diff --git a/configure.py b/configure.py index ffdd538bf71834..27ccb365bec088 100755 --- a/configure.py +++ b/configure.py @@ -1059,6 +1059,12 @@ default=None, help='build without FFI (Foreign Function Interface) support') +parser.add_argument('--without-fast-ffi', + action='store_true', + dest='without_fast_ffi', + default=None, + help='build without fast FFI support') + parser.add_argument('--experimental-quic', action='store_true', dest='experimental_quic', @@ -2330,6 +2336,7 @@ def bundled_ffi_supported(os_name, target_arch): def configure_ffi(o): use_ffi = not options.without_ffi + use_fast_ffi = False if use_ffi and not options.shared_ffi: target_arch = o['variables']['target_arch'] @@ -2341,6 +2348,7 @@ def configure_ffi(o): use_ffi = False o['variables']['node_use_ffi'] = b(use_ffi) + o['variables']['node_use_fast_ffi'] = b(use_fast_ffi) if options.without_ffi: if options.shared_ffi: @@ -2352,6 +2360,9 @@ def configure_ffi(o): configure_library('ffi', o, pkgname='libffi') + use_fast_ffi = not options.without_fast_ffi and not options.shared_ffi + o['variables']['node_use_fast_ffi'] = b(use_fast_ffi) + def configure_quic(o): o['variables']['node_use_quic'] = b(options.experimental_quic and not options.without_ssl) diff --git a/deps/crates/Cargo.lock b/deps/crates/Cargo.lock index b8586e1b704145..83d1fcf4d98bf6 100644 --- a/deps/crates/Cargo.lock +++ b/deps/crates/Cargo.lock @@ -2,12 +2,39 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "allocator-api2", +] + [[package]] name = "calendrical_calculations" version = "0.2.3" @@ -27,6 +54,129 @@ dependencies = [ "libm", ] +[[package]] +name = "cranelift" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a71de5e59f616d79d14d2c71aa2799ce898241d7f10f7e64a4997014b4000a28" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", + "cranelift-module", +] + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.5", + "log", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", +] + +[[package]] +name = "cranelift-frontend" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" + +[[package]] +name = "cranelift-module" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", +] + +[[package]] +name = "cranelift-native" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + [[package]] name = "diplomat" version = "0.13.0" @@ -70,6 +220,47 @@ dependencies = [ "syn", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "icu_calendar" version = "2.0.6" @@ -159,6 +350,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", +] + [[package]] name = "ixdtf" version = "0.5.0" @@ -174,6 +375,12 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + [[package]] name = "libm" version = "0.2.15" @@ -186,15 +393,33 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + [[package]] name = "node_crates" version = "0.1.0" dependencies = [ + "cranelift", + "cranelift-native", "icu_calendar", "icu_collections", "icu_locale", "icu_locale_core", "icu_provider", + "memmap2", "temporal_capi", "temporal_rs", "timezone_provider", @@ -238,6 +463,20 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regalloc2" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc06e6b318142614e4a48bc725abbf08ff166694835c43c9dae5a9009704639a" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", + "log", + "rustc-hash", + "smallvec", +] + [[package]] name = "resb" version = "0.1.1" @@ -246,6 +485,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "serde" version = "1.0.228" @@ -319,6 +564,12 @@ dependencies = [ "syn", ] +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + [[package]] name = "temporal_capi" version = "0.1.0" diff --git a/deps/crates/Cargo.toml b/deps/crates/Cargo.toml index 7c67cc30e31944..f56d3b3e6863a0 100644 --- a/deps/crates/Cargo.toml +++ b/deps/crates/Cargo.toml @@ -10,11 +10,17 @@ rust-version = "1.82" [lib] crate-type = ["staticlib"] +[features] +fast_ffi = ["dep:cranelift", "dep:cranelift-native", "dep:memmap2"] + [dependencies] +cranelift = { version = "0.116.1", optional = true } +cranelift-native = { version = "0.116.1", optional = true } # Pin all temporal dependencies to the last version support rustc 1.82 icu_collections = "~2.0.0" icu_locale_core = "~2.0.0" icu_provider = "~2.0.0" +memmap2 = { version = "0.9.9", optional = true } timezone_provider = "=0.1.0" [dependencies.temporal_capi] diff --git a/deps/crates/crates.gyp b/deps/crates/crates.gyp index 5c1dc9d782cbfe..dcd309dd0a7227 100644 --- a/deps/crates/crates.gyp +++ b/deps/crates/crates.gyp @@ -3,8 +3,15 @@ 'cargo%': 'cargo', 'cargo_vendor_dir': './vendor', 'cargo_rust_target%': '', + 'node_use_fast_ffi%': 'false', + 'cargo_fast_ffi_flags': [], }, 'conditions': [ + ['node_use_fast_ffi=="true"', { + 'variables': { + 'cargo_fast_ffi_flags': ['--features', 'fast_ffi'], + }, + }], ['build_type == "Release"', { 'variables': { 'cargo_build_flags': ['--release'], @@ -52,6 +59,7 @@ 'Cargo.toml', 'Cargo.lock', 'src/lib.rs', + 'src/node_fast_ffi.rs', ], 'link_settings': { 'libraries': [ @@ -83,6 +91,7 @@ '$(Platform)', '<(SHARED_INTERMEDIATE_DIR)', '<@(cargo_build_flags)', + '<@(cargo_fast_ffi_flags)', '--frozen', ], } @@ -101,6 +110,7 @@ '<(cargo)', 'rustc', '<@(cargo_build_flags)', + '<@(cargo_fast_ffi_flags)', '--frozen', '--target-dir', '<(SHARED_INTERMEDIATE_DIR)' diff --git a/deps/crates/src/lib.rs b/deps/crates/src/lib.rs index d2705806664fc9..ff52f4f7b9a182 100644 --- a/deps/crates/src/lib.rs +++ b/deps/crates/src/lib.rs @@ -5,3 +5,6 @@ #[allow(unused_imports)] use temporal_capi; + +#[cfg(feature = "fast_ffi")] +pub mod node_fast_ffi; diff --git a/deps/crates/src/node_fast_ffi.rs b/deps/crates/src/node_fast_ffi.rs new file mode 100644 index 00000000000000..9554d42fff77b3 --- /dev/null +++ b/deps/crates/src/node_fast_ffi.rs @@ -0,0 +1,349 @@ +use cranelift::codegen::ir::UserFuncName; +use cranelift::prelude::*; +use std::ffi::c_void; + +#[repr(C)] +pub struct FastFFIFunction { + pub code: *const c_void, + pub handle: *mut c_void, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +#[repr(u8)] +enum FastFFIType { + Void = 0, + I8 = 1, + U8 = 2, + I16 = 3, + U16 = 4, + I32 = 5, + U32 = 6, + I64 = 7, + U64 = 8, + F32 = 9, + F64 = 10, + Pointer = 11, + Buffer = 12, +} + +impl FastFFIType { + fn from_raw(raw: u8) -> Option { + match raw { + 0 => Some(Self::Void), + 1 => Some(Self::I8), + 2 => Some(Self::U8), + 3 => Some(Self::I16), + 4 => Some(Self::U16), + 5 => Some(Self::I32), + 6 => Some(Self::U32), + 7 => Some(Self::I64), + 8 => Some(Self::U64), + 9 => Some(Self::F32), + 10 => Some(Self::F64), + 11 => Some(Self::Pointer), + 12 => Some(Self::Buffer), + _ => None, + } + } +} + +fn convert(ty: FastFFIType, wrapper: bool, isize_ty: Type) -> AbiParam { + match ty { + FastFFIType::Void => AbiParam::new(types::INVALID), + FastFFIType::I8 => { + if wrapper { + AbiParam::new(types::I32) + } else { + AbiParam::new(types::I8).sext() + } + } + FastFFIType::U8 => { + if wrapper { + AbiParam::new(types::I32) + } else { + AbiParam::new(types::I8).uext() + } + } + FastFFIType::I16 => { + if wrapper { + AbiParam::new(types::I32) + } else { + AbiParam::new(types::I16).sext() + } + } + FastFFIType::U16 => { + if wrapper { + AbiParam::new(types::I32) + } else { + AbiParam::new(types::I16).uext() + } + } + FastFFIType::I32 | FastFFIType::U32 => AbiParam::new(types::I32), + FastFFIType::I64 | FastFFIType::U64 => AbiParam::new(types::I64), + FastFFIType::F32 => AbiParam::new(types::F32), + FastFFIType::F64 => AbiParam::new(types::F64), + FastFFIType::Pointer => AbiParam::new(isize_ty), + FastFFIType::Buffer => { + if wrapper { + AbiParam::new(isize_ty) + } else { + AbiParam::new(isize_ty) + } + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn node_fast_ffi_compile( + target_slot: *const c_void, + result_type: u8, + parameter_types: *const u8, + parameter_count: usize, + buffer_data: *const c_void, + raise_invalid_buffer: *const c_void, + raise_library_closed: *const c_void, + out: *mut FastFFIFunction, +) -> bool { + if target_slot.is_null() || out.is_null() || parameter_types.is_null() { + return false; + } + + let result_type = match FastFFIType::from_raw(result_type) { + Some(value) => value, + None => return false, + }; + + let parameter_types = unsafe { std::slice::from_raw_parts(parameter_types, parameter_count) }; + let mut params = Vec::with_capacity(parameter_count); + for raw in parameter_types { + let Some(param) = FastFFIType::from_raw(*raw) else { + return false; + }; + params.push(param); + } + + let Ok(compiled) = compile( + target_slot, + result_type, + ¶ms, + buffer_data, + raise_invalid_buffer, + raise_library_closed, + ) else { + return false; + }; + + unsafe { + *out = compiled; + } + true +} + +#[no_mangle] +pub unsafe extern "C" fn node_fast_ffi_free(handle: *mut c_void) { + if handle.is_null() { + return; + } + unsafe { + drop(Box::from_raw(handle as *mut memmap2::Mmap)); + } +} + +fn compile( + target_slot: *const c_void, + result_type: FastFFIType, + parameter_types: &[FastFFIType], + buffer_data: *const c_void, + raise_invalid_buffer: *const c_void, + raise_library_closed: *const c_void, +) -> Result> { + let mut flag_builder = settings::builder(); + flag_builder.set("is_pic", "true")?; + flag_builder.set("opt_level", "speed_and_size")?; + let flags = settings::Flags::new(flag_builder); + let isa = cranelift_native::builder() + .map_err(|err| format!("Cranelift native ISA error: {err}"))? + .finish(flags)?; + + #[cfg(target_pointer_width = "32")] + let isize_ty = types::I32; + #[cfg(target_pointer_width = "64")] + let isize_ty = types::I64; + + let mut wrapper_sig = cranelift::codegen::ir::Signature::new(isa.default_call_conv()); + let mut target_sig = cranelift::codegen::ir::Signature::new(isa.default_call_conv()); + let mut buffer_sig = cranelift::codegen::ir::Signature::new(isa.default_call_conv()); + let mut raise_sig = cranelift::codegen::ir::Signature::new(isa.default_call_conv()); + let mut raise_closed_sig = cranelift::codegen::ir::Signature::new(isa.default_call_conv()); + + // V8 receiver. + wrapper_sig.params.push(AbiParam::new(isize_ty)); + for param in parameter_types { + wrapper_sig.params.push(convert(*param, true, isize_ty)); + target_sig.params.push(convert(*param, false, isize_ty)); + } + // FastApiCallbackOptions&. + wrapper_sig.params.push(AbiParam::new(isize_ty)); + + if result_type != FastFFIType::Void { + wrapper_sig + .returns + .push(convert(result_type, true, isize_ty)); + target_sig + .returns + .push(convert(result_type, false, isize_ty)); + } + + buffer_sig.params.push(AbiParam::new(isize_ty)); + buffer_sig.returns.push(AbiParam::new(isize_ty)); + + raise_sig.params.push(AbiParam::new(isize_ty)); + raise_sig.params.push(AbiParam::new(types::I32)); + + raise_closed_sig.params.push(AbiParam::new(isize_ty)); + + let mut ctx = cranelift::codegen::Context::new(); + let mut fn_builder_ctx = FunctionBuilderContext::new(); + ctx.func = cranelift::codegen::ir::Function::with_name_signature( + UserFuncName::testcase("node_fast_ffi_wrapper".to_string()), + wrapper_sig, + ); + + let mut f = FunctionBuilder::new(&mut ctx.func, &mut fn_builder_ctx); + let target_sig = f.import_signature(target_sig); + let buffer_sig = f.import_signature(buffer_sig); + let raise_sig = f.import_signature(raise_sig); + let raise_closed_sig = f.import_signature(raise_closed_sig); + + let entry = f.create_block(); + let error = f.create_block(); + let closed_error = f.create_block(); + f.append_block_param(error, types::I32); + f.set_cold_block(error); + f.set_cold_block(closed_error); + f.append_block_params_for_function_params(entry); + f.switch_to_block(entry); + f.seal_block(entry); + + let wrapper_args = f.block_params(entry).to_owned(); + let options = wrapper_args[parameter_types.len() + 1]; + let mut native_args = Vec::with_capacity(parameter_types.len()); + let mut next = f.create_block(); + + for (index, param) in parameter_types.iter().enumerate() { + let arg = wrapper_args[index + 1]; + match param { + FastFFIType::I8 | FastFFIType::U8 => { + native_args.push(f.ins().ireduce(types::I8, arg)); + } + FastFFIType::I16 | FastFFIType::U16 => { + native_args.push(f.ins().ireduce(types::I16, arg)); + } + FastFFIType::Buffer => { + if buffer_data.is_null() { + return Err("missing buffer helper".into()); + } + let callee = f.ins().iconst(isize_ty, buffer_data as i64); + let call = f.ins().call_indirect(buffer_sig, callee, &[arg]); + let ptr = f.inst_results(call)[0]; + native_args.push(ptr); + + let sentinel = f.ins().iconst(isize_ty, -1); + let invalid = f.ins().icmp(IntCC::Equal, ptr, sentinel); + let index = f.ins().iconst(types::I32, index as i64); + f.ins().brif(invalid, error, &[index], next, &[]); + f.switch_to_block(next); + f.seal_block(next); + next = f.create_block(); + } + _ => native_args.push(arg), + } + } + + let target_slot = f.ins().iconst(isize_ty, target_slot as i64); + let callee = f.ins().load(isize_ty, MemFlags::trusted(), target_slot, 0); + let null = f.ins().iconst(isize_ty, 0); + let is_closed = f.ins().icmp(IntCC::Equal, callee, null); + let call_target = f.create_block(); + f.ins().brif(is_closed, closed_error, &[], call_target, &[]); + f.switch_to_block(call_target); + f.seal_block(call_target); + + let call = f.ins().call_indirect(target_sig, callee, &native_args); + let mut results = f.inst_results(call).to_owned(); + match result_type { + FastFFIType::I8 | FastFFIType::I16 => { + results[0] = f.ins().sextend(types::I32, results[0]); + } + FastFFIType::U8 | FastFFIType::U16 => { + results[0] = f.ins().uextend(types::I32, results[0]); + } + _ => {} + } + f.ins().return_(&results); + + f.switch_to_block(closed_error); + f.seal_block(closed_error); + if !raise_library_closed.is_null() { + let callee = f.ins().iconst(isize_ty, raise_library_closed as i64); + f.ins().call_indirect(raise_closed_sig, callee, &[options]); + } + if result_type == FastFFIType::Void { + f.ins().return_(&[]); + } else { + let ret = convert(result_type, true, isize_ty).value_type; + let zero = if ret == types::F32 { + f.ins().f32const(0.0) + } else if ret == types::F64 { + f.ins().f64const(0.0) + } else { + f.ins().iconst(ret, 0) + }; + f.ins().return_(&[zero]); + } + + f.switch_to_block(error); + f.seal_block(error); + let error_index = f.block_params(error)[0]; + if result_type == FastFFIType::Void { + if !raise_invalid_buffer.is_null() { + let callee = f.ins().iconst(isize_ty, raise_invalid_buffer as i64); + f.ins() + .call_indirect(raise_sig, callee, &[options, error_index]); + } + f.ins().return_(&[]); + } else { + if !raise_invalid_buffer.is_null() { + let callee = f.ins().iconst(isize_ty, raise_invalid_buffer as i64); + f.ins() + .call_indirect(raise_sig, callee, &[options, error_index]); + } + let ret = convert(result_type, true, isize_ty).value_type; + let zero = if ret == types::F32 { + f.ins().f32const(0.0) + } else if ret == types::F64 { + f.ins().f64const(0.0) + } else { + f.ins().iconst(ret, 0) + }; + f.ins().return_(&[zero]); + } + + f.finalize(); + + cranelift::codegen::verifier::verify_function(&ctx.func, isa.flags())?; + let mut ctrl_plane = Default::default(); + ctx.optimize(&*isa, &mut ctrl_plane)?; + let code_info = ctx + .compile(&*isa, &mut ctrl_plane) + .map_err(|err| format!("Cranelift compile error: {err:?}"))?; + + let data = code_info.buffer.data(); + let mut mutable = memmap2::MmapMut::map_anon(data.len())?; + mutable.copy_from_slice(data); + let executable = mutable.make_exec()?; + let code = executable.as_ptr() as *const c_void; + let handle = Box::into_raw(Box::new(executable)) as *mut c_void; + + Ok(FastFFIFunction { code, handle }) +} diff --git a/deps/crates/vendor/allocator-api2/.cargo-checksum.json b/deps/crates/vendor/allocator-api2/.cargo-checksum.json new file mode 100644 index 00000000000000..8abee443cfe75e --- /dev/null +++ b/deps/crates/vendor/allocator-api2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"f44a14175e1995bd4b75ea0c74654a53b7073fedcb37c92c41841126e6f40f17","CHANGELOG.md":"886f8c688db0c22d24b650df0dc30a39d05d54d0e562c00d9574bf31cbf73251","Cargo.toml":"ddaa434cc54a30a33bbe0096e72479d71ba5deffa2ad9bee39419d4e50b75275","Cargo.toml.orig":"c1688fbd2be36f529a6eebbbf62fcf612c86b6f824738a44f6caa8875f57279b","LICENSE-APACHE":"20fe7b00e904ed690e3b9fd6073784d3fc428141dbd10b81c01fd143d0797f58","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"8b8c45a89f9d61688fd32516ca24ea11cc6be4994757bd01bd9d02d96cd49337","src/lib.rs":"56a7344026bf5be503ca8b3fe208b74550956e82be7806a229951e80ebb3c249","src/nightly.rs":"c12152b6721216174c9a3cec90e612d5571a5d2c0a94ad54900cb814414519c3","src/stable/alloc/global.rs":"14836ad7d73a364474fc153b24a1f17ad0e60a69b90a8721dc1059eada8bf869","src/stable/alloc/mod.rs":"866dafd3984dd246e381d8ad1c2b3e02a60c3421b598ca493aa83f9b6422608d","src/stable/alloc/system.rs":"db5d5bf088eecac3fc5ff1281e1bf26ca36dd38f13cd52c49d95ff1bab064254","src/stable/boxed.rs":"fb664ab68a599b7fc5acbae1c634c2007ba2bda9a24fea2212b8202bb537f7a0","src/stable/macros.rs":"74490796a766338d0163f40a37612cd9ea2de58ae3d8e9abf6c7bcf81d9be4a6","src/stable/mod.rs":"474dce5f150456a98fa7c4debc24f03ec2db4ebf0d54011ae19c8b575feb5712","src/stable/raw_vec.rs":"9a56ce1bab4562000285e80837da7b7bd2bbbc63850c83ab5d8df9888b65f5db","src/stable/slice.rs":"089263b058e6c185467bad7ad14908479e5675408fc70a8291e5dddaef36035a","src/stable/unique.rs":"6ed3678beed7fa6bd18b694f7357e638d83e3f1f895f9988a465dc5afebfbac9","src/stable/vec/drain.rs":"740cd2e0f31eeb0146bbd0f645a14fe12bacd3912f003db433ddc6b3a178461f","src/stable/vec/into_iter.rs":"da72ce52344ea2e263ddf7776356cc012bbafc51f48499955c1771729448754d","src/stable/vec/mod.rs":"dd3ddca02747686ed2064397dd17068b64f28c6f42b55e9e2ce129cd573fe44c","src/stable/vec/partial_eq.rs":"9f1b18605164a62b58d9e17914d573698735de31c51ceb8bd3666e83d32df370","src/stable/vec/set_len_on_drop.rs":"561342e22a194e515cc25c9a1bcd827ca24c4db033e9e2c4266fbdd2fb16e5bc","src/stable/vec/splice.rs":"95a460b3a7b4af60fdc9ba04d3a719b61a0c11786cd2d8823d022e22c397f9c9"},"package":"683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"} \ No newline at end of file diff --git a/deps/crates/vendor/allocator-api2/.cargo_vcs_info.json b/deps/crates/vendor/allocator-api2/.cargo_vcs_info.json new file mode 100644 index 00000000000000..3ec5f17b72994b --- /dev/null +++ b/deps/crates/vendor/allocator-api2/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "63cd7fcc2f8854b5821c7054d026e8a4647acde1" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/allocator-api2/CHANGELOG.md b/deps/crates/vendor/allocator-api2/CHANGELOG.md new file mode 100644 index 00000000000000..1d8f11d32d784f --- /dev/null +++ b/deps/crates/vendor/allocator-api2/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] diff --git a/deps/crates/vendor/allocator-api2/Cargo.toml b/deps/crates/vendor/allocator-api2/Cargo.toml new file mode 100644 index 00000000000000..541b4e97e9e651 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.63" +name = "allocator-api2" +version = "0.2.21" +authors = ["Zakarum "] +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Mirror of Rust's allocator API" +homepage = "https://github.com/zakarumych/allocator-api2" +documentation = "https://docs.rs/allocator-api2" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/zakarumych/allocator-api2" + +[lib] +name = "allocator_api2" +path = "src/lib.rs" + +[dependencies.serde] +version = "1.0" +optional = true + +[features] +alloc = [] +default = ["std"] +fresh-rust = [] +nightly = [] +std = ["alloc"] + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(no_global_oom_handling)"] diff --git a/deps/crates/vendor/allocator-api2/Cargo.toml.orig b/deps/crates/vendor/allocator-api2/Cargo.toml.orig new file mode 100644 index 00000000000000..c57a2d9807adda --- /dev/null +++ b/deps/crates/vendor/allocator-api2/Cargo.toml.orig @@ -0,0 +1,30 @@ +[package] +name = "allocator-api2" +version = "0.2.21" +edition = "2018" +authors = ["Zakarum "] +license = "MIT OR Apache-2.0" +documentation = "https://docs.rs/allocator-api2" +homepage = "https://github.com/zakarumych/allocator-api2" +repository = "https://github.com/zakarumych/allocator-api2" +readme = "README.md" +description = "Mirror of Rust's allocator API" +rust-version = "1.63" + +[features] +alloc = [] +std = ["alloc"] +default = ["std"] +nightly = [] +fresh-rust = [] + +[dependencies] +serde = { version = "1.0", optional = true } + +[workspace] +members = ["tests"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(no_global_oom_handling)', +] } diff --git a/deps/crates/vendor/allocator-api2/LICENSE-APACHE b/deps/crates/vendor/allocator-api2/LICENSE-APACHE new file mode 100644 index 00000000000000..a2ce4d97c149d9 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/deps/crates/vendor/allocator-api2/LICENSE-MIT b/deps/crates/vendor/allocator-api2/LICENSE-MIT new file mode 100644 index 00000000000000..458723b374585a --- /dev/null +++ b/deps/crates/vendor/allocator-api2/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/allocator-api2/README.md b/deps/crates/vendor/allocator-api2/README.md new file mode 100644 index 00000000000000..68e9b36c6b34c8 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/README.md @@ -0,0 +1,61 @@ +# allocator-api2 + +[![crates](https://img.shields.io/crates/v/allocator-api2.svg?style=for-the-badge&label=allocator-api2)](https://crates.io/crates/allocator-api2) +[![docs](https://img.shields.io/badge/docs.rs-allocator--api2-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white)](https://docs.rs/allocator-api2) +[![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/allocator-api2/badge.yml?branch=main&style=for-the-badge)](https://github.com/zakarumych/allocator-api2/actions/workflows/badge.yml) +[![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING) +![loc](https://img.shields.io/tokei/lines/github/zakarumych/allocator-api2?style=for-the-badge) + +This crate mirrors types and traits from Rust's unstable [`allocator_api`] +The intention of this crate is to serve as substitution for actual thing +for libs when build on stable and beta channels. +The target users are library authors who implement allocators or collection types +that use allocators, or anyone else who wants using [`allocator_api`] + +The crate should be frequently updated with minor version bump. +When [`allocator_api`] is stable this crate will get version `1.0` and simply +re-export from `core`, `alloc` and `std`. + +The code is mostly verbatim copy from rust repository. +Mostly attributes are removed. + +## Usage + +This paragraph describes how to use this crate correctly to ensure +compatibility and interoperability on both stable and nightly channels. + +If you are writing a library that interacts with allocators API, you can +add this crate as a dependency and use the types and traits from this +crate instead of the ones in `core` or `alloc`. +This will allow your library to compile on stable and beta channels. + +Your library *MAY* provide a feature that will enable "allocator-api2/nightly". +When this feature is enabled, your library *MUST* enable +unstable `#![feature(allocator_api)]` or it may not compile. +If feature is not provided, your library may not be compatible with the +rest of the users and cause compilation errors on nightly channel +when some other crate enables "allocator-api2/nightly" feature. + +# Minimal Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.63 and up. +A feature "fresh-rust" bumps the MSRV to unspecified higher version, but should be compatible with +at least few latest stable releases. The feature enables some additional functionality: + +* `CStr` without "std" feature + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contributions + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + + +[`allocator_api`]: https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html diff --git a/deps/crates/vendor/allocator-api2/src/lib.rs b/deps/crates/vendor/allocator-api2/src/lib.rs new file mode 100644 index 00000000000000..f0974db827083c --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/lib.rs @@ -0,0 +1,20 @@ +//! +//! allocator-api2 crate. +//! +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc as alloc_crate; + +#[cfg(not(feature = "nightly"))] +#[macro_use] +mod stable; + +#[cfg(feature = "nightly")] +mod nightly; + +#[cfg(not(feature = "nightly"))] +pub use self::stable::*; + +#[cfg(feature = "nightly")] +pub use self::nightly::*; diff --git a/deps/crates/vendor/allocator-api2/src/nightly.rs b/deps/crates/vendor/allocator-api2/src/nightly.rs new file mode 100644 index 00000000000000..61f1cafb409226 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/nightly.rs @@ -0,0 +1,5 @@ +#[cfg(not(feature = "alloc"))] +pub use core::alloc; + +#[cfg(feature = "alloc")] +pub use alloc_crate::{alloc, boxed, vec, collections}; diff --git a/deps/crates/vendor/allocator-api2/src/stable/alloc/global.rs b/deps/crates/vendor/allocator-api2/src/stable/alloc/global.rs new file mode 100644 index 00000000000000..161f3c2c372f21 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/alloc/global.rs @@ -0,0 +1,187 @@ +use core::ptr::NonNull; + +use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; + +use crate::stable::{assume, invalid_mut}; + +use super::{AllocError, Allocator, Layout}; + +/// The global memory allocator. +/// +/// This type implements the [`Allocator`] trait by forwarding calls +/// to the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// Note: while this type is unstable, the functionality it provides can be +/// accessed through the [free functions in `alloc`](crate#functions). +#[derive(Copy, Clone, Default, Debug)] +pub struct Global; + +impl Global { + #[inline(always)] + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + match layout.size() { + 0 => Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + invalid_mut(layout.align()), + 0, + )) + }), + // SAFETY: `layout` is non-zero in size, + size => unsafe { + let raw_ptr = if zeroed { + alloc_zeroed(layout) + } else { + alloc(layout) + }; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + size, + ))) + }, + } + } + + // SAFETY: Same as `Allocator::grow` + #[inline(always)] + unsafe fn grow_impl( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), + + // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` + // as required by safety conditions. Other conditions must be upheld by the caller + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); + + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + assume(new_size >= old_layout.size()); + + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + if zeroed { + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + new_size, + ))) + }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); + self.deallocate(ptr, old_layout); + Ok(new_ptr) + }, + } + } +} + +unsafe impl Allocator for Global { + #[inline(always)] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, false) + } + + #[inline(always)] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, true) + } + + #[inline(always)] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: `layout` is non-zero in size, + // other conditions must be upheld by the caller + unsafe { dealloc(ptr.as_ptr(), layout) } + } + } + + #[inline(always)] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } + } + + #[inline(always)] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } + } + + #[inline(always)] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + match new_layout.size() { + // SAFETY: conditions must be upheld by the caller + 0 => unsafe { + self.deallocate(ptr, old_layout); + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + invalid_mut(new_layout.align()), + 0, + ))) + }, + + // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + assume(new_size <= old_layout.size()); + + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + new_size, + ))) + }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.allocate(new_layout)?; + core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); + self.deallocate(ptr, old_layout); + Ok(new_ptr) + }, + } + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/alloc/mod.rs b/deps/crates/vendor/allocator-api2/src/stable/alloc/mod.rs new file mode 100644 index 00000000000000..35b389b9ae8b3f --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/alloc/mod.rs @@ -0,0 +1,416 @@ +//! Memory allocation APIs + +use core::{ + fmt, + ptr::{self, NonNull}, +}; + +#[cfg(feature = "alloc")] +mod global; + +#[cfg(feature = "std")] +mod system; + +pub use core::alloc::{GlobalAlloc, Layout, LayoutError}; + +#[cfg(feature = "alloc")] +pub use self::global::Global; + +#[cfg(feature = "std")] +pub use self::system::System; + +#[cfg(feature = "alloc")] +pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; + +#[cfg(all(feature = "alloc", not(no_global_oom_handling)))] +pub use alloc_crate::alloc::handle_alloc_error; + +/// The `AllocError` error indicates an allocation failure +/// that may be due to resource exhaustion or to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct AllocError; + +#[cfg(feature = "std")] +impl std::error::Error for AllocError {} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("memory allocation failed") + } +} + +/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of +/// data described via [`Layout`][]. +/// +/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having +/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the +/// allocated memory. +/// +/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying +/// allocator does not support this (like jemalloc) or return a null pointer (such as +/// `libc::malloc`), this must be caught by the implementation. +/// +/// ### Currently allocated memory +/// +/// Some of the methods require that a memory block be *currently allocated* via an allocator. This +/// means that: +/// +/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or +/// [`shrink`], and +/// +/// * the memory block has not been subsequently deallocated, where blocks are either deallocated +/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or +/// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer +/// remains valid. +/// +/// [`allocate`]: Allocator::allocate +/// [`grow`]: Allocator::grow +/// [`shrink`]: Allocator::shrink +/// [`deallocate`]: Allocator::deallocate +/// +/// ### Memory fitting +/// +/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to +/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the +/// following conditions must hold: +/// +/// * The block must be allocated with the same alignment as [`layout.align()`], and +/// +/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: +/// - `min` is the size of the layout most recently used to allocate the block, and +/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. +/// +/// [`layout.align()`]: Layout::align +/// [`layout.size()`]: Layout::size +/// +/// # Safety +/// +/// * Memory blocks returned from an allocator must point to valid memory and retain their validity +/// until the instance and all of its clones are dropped, +/// +/// * cloning or moving the allocator must not invalidate memory blocks returned from this +/// allocator. A cloned allocator must behave like the same allocator, and +/// +/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other +/// method of the allocator. +/// +/// [*currently allocated*]: #currently-allocated-memory +pub unsafe trait Allocator { + /// Attempts to allocate a block of memory. + /// + /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. + /// + /// The returned block may have a larger size than specified by `layout.size()`, and may or may + /// not have its contents initialized. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet + /// allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + fn allocate(&self, layout: Layout) -> Result, AllocError>; + + /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet + /// allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[inline(always)] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; + // SAFETY: `alloc` returns a valid memory block + unsafe { ptr.cast::().as_ptr().write_bytes(0, ptr.len()) } + Ok(ptr) + } + + /// Deallocates the memory referenced by `ptr`. + /// + /// # Safety + /// + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and + /// * `layout` must [*fit*] that block of memory. + /// + /// [*currently allocated*]: #currently-allocated-memory + /// [*fit*]: #memory-fitting + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + + /// Attempts to extend the memory block. + /// + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. + /// + /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been + /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the + /// allocation was grown in-place. The newly returned pointer is the only valid pointer + /// for accessing this memory now. + /// + /// If this method returns `Err`, then ownership of the memory block has not been transferred to + /// this allocator, and the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. + /// + /// Note that `new_layout.align()` need not be the same as `old_layout.align()`. + /// + /// [*currently allocated*]: #currently-allocated-memory + /// [*fit*]: #memory-fitting + /// + /// # Errors + /// + /// Returns `Err` if the new layout does not meet the allocator's size and alignment + /// constraints of the allocator, or if growing otherwise fails. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[inline(always)] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); + self.deallocate(ptr, old_layout); + } + + Ok(new_ptr) + } + + /// Behaves like `grow`, but also ensures that the new contents are set to zero before being + /// returned. + /// + /// The memory block will contain the following contents after a successful call to + /// `grow_zeroed`: + /// * Bytes `0..old_layout.size()` are preserved from the original allocation. + /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on + /// the allocator implementation. `old_size` refers to the size of the memory block prior + /// to the `grow_zeroed` call, which may be larger than the size that was originally + /// requested when it was allocated. + /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory + /// block returned by the `grow_zeroed` call. + /// + /// # Safety + /// + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. + /// + /// Note that `new_layout.align()` need not be the same as `old_layout.align()`. + /// + /// [*currently allocated*]: #currently-allocated-memory + /// [*fit*]: #memory-fitting + /// + /// # Errors + /// + /// Returns `Err` if the new layout does not meet the allocator's size and alignment + /// constraints of the allocator, or if growing otherwise fails. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[inline(always)] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate_zeroed(new_layout)?; + + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); + self.deallocate(ptr, old_layout); + } + + Ok(new_ptr) + } + + /// Attempts to shrink the memory block. + /// + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. + /// + /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been + /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the + /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer + /// for accessing this memory now. + /// + /// If this method returns `Err`, then ownership of the memory block has not been transferred to + /// this allocator, and the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. + /// + /// Note that `new_layout.align()` need not be the same as `old_layout.align()`. + /// + /// [*currently allocated*]: #currently-allocated-memory + /// [*fit*]: #memory-fitting + /// + /// # Errors + /// + /// Returns `Err` if the new layout does not meet the allocator's size and alignment + /// constraints of the allocator, or if shrinking otherwise fails. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[inline(always)] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + + // SAFETY: because `new_layout.size()` must be lower than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_layout.size()); + self.deallocate(ptr, old_layout); + } + + Ok(new_ptr) + } + + /// Creates a "by reference" adapter for this instance of `Allocator`. + /// + /// The returned adapter also implements `Allocator` and will simply borrow this. + #[inline(always)] + fn by_ref(&self) -> &Self + where + Self: Sized, + { + self + } +} + +unsafe impl Allocator for &A +where + A: Allocator + ?Sized, +{ + #[inline(always)] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline(always)] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline(always)] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline(always)] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline(always)] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline(always)] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/alloc/system.rs b/deps/crates/vendor/allocator-api2/src/stable/alloc/system.rs new file mode 100644 index 00000000000000..3a0fe4c8514169 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/alloc/system.rs @@ -0,0 +1,172 @@ +use core::ptr::NonNull; +pub use std::alloc::System; + +use crate::stable::{assume, invalid_mut}; + +use super::{AllocError, Allocator, GlobalAlloc as _, Layout}; + +unsafe impl Allocator for System { + #[inline(always)] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + alloc_impl(layout, false) + } + + #[inline(always)] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + alloc_impl(layout, true) + } + + #[inline(always)] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: `layout` is non-zero in size, + // other conditions must be upheld by the caller + unsafe { System.dealloc(ptr.as_ptr(), layout) } + } + } + + #[inline(always)] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { grow_impl(ptr, old_layout, new_layout, false) } + } + + #[inline(always)] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { grow_impl(ptr, old_layout, new_layout, true) } + } + + #[inline(always)] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + match new_layout.size() { + // SAFETY: conditions must be upheld by the caller + 0 => unsafe { + self.deallocate(ptr, old_layout); + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + invalid_mut(new_layout.align()), + 0, + ))) + }, + + // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + assume(new_size <= old_layout.size()); + + let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + new_size, + ))) + }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.allocate(new_layout)?; + core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); + self.deallocate(ptr, old_layout); + Ok(new_ptr) + }, + } + } +} + +#[inline(always)] +fn alloc_impl(layout: Layout, zeroed: bool) -> Result, AllocError> { + match layout.size() { + 0 => Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + invalid_mut(layout.align()), + 0, + )) + }), + // SAFETY: `layout` is non-zero in size, + size => unsafe { + let raw_ptr = if zeroed { + System.alloc_zeroed(layout) + } else { + System.alloc(layout) + }; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + size, + ))) + }, + } +} + +// SAFETY: Same as `Allocator::grow` +#[inline(always)] +unsafe fn grow_impl( + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, +) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + match old_layout.size() { + 0 => alloc_impl(new_layout, zeroed), + + // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` + // as required by safety conditions. Other conditions must be upheld by the caller + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); + + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + assume(new_size >= old_layout.size()); + + let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + if zeroed { + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + ptr.as_ptr(), + new_size, + ))) + }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = alloc_impl(new_layout, zeroed)?; + core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); + System.deallocate(ptr, old_layout); + Ok(new_ptr) + }, + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/boxed.rs b/deps/crates/vendor/allocator-api2/src/stable/boxed.rs new file mode 100644 index 00000000000000..8f9633823c4a3f --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/boxed.rs @@ -0,0 +1,2272 @@ +//! The `Box` type for heap allocation. +//! +//! [`Box`], casually referred to as a 'box', provides the simplest form of +//! heap allocation in Rust. Boxes provide ownership for this allocation, and +//! drop their contents when they go out of scope. Boxes also ensure that they +//! never allocate more than `isize::MAX` bytes. +//! +//! # Examples +//! +//! Move a value from the stack to the heap by creating a [`Box`]: +//! +//! ``` +//! let val: u8 = 5; +//! let boxed: Box = Box::new(val); +//! ``` +//! +//! Move a value from a [`Box`] back to the stack by [dereferencing]: +//! +//! ``` +//! let boxed: Box = Box::new(5); +//! let val: u8 = *boxed; +//! ``` +//! +//! Creating a recursive data structure: +//! +//! ``` +//! #[derive(Debug)] +//! enum List { +//! Cons(T, Box>), +//! Nil, +//! } +//! +//! let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); +//! println!("{list:?}"); +//! ``` +//! +//! This will print `Cons(1, Cons(2, Nil))`. +//! +//! Recursive structures must be boxed, because if the definition of `Cons` +//! looked like this: +//! +//! ```compile_fail,E0072 +//! # enum List { +//! Cons(T, List), +//! # } +//! ``` +//! +//! It wouldn't work. This is because the size of a `List` depends on how many +//! elements are in the list, and so we don't know how much memory to allocate +//! for a `Cons`. By introducing a [`Box`], which has a defined size, we know how +//! big `Cons` needs to be. +//! +//! # Memory layout +//! +//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for +//! its allocation. It is valid to convert both ways between a [`Box`] and a +//! raw pointer allocated with the [`Global`] allocator, given that the +//! [`Layout`] used with the allocator is correct for the type. More precisely, +//! a `value: *mut T` that has been allocated with the [`Global`] allocator +//! with `Layout::for_value(&*value)` may be converted into a box using +//! [`Box::::from_raw(value)`]. Conversely, the memory backing a `value: *mut +//! T` obtained from [`Box::::into_raw`] may be deallocated using the +//! [`Global`] allocator with [`Layout::for_value(&*value)`]. +//! +//! For zero-sized values, the `Box` pointer still has to be [valid] for reads +//! and writes and sufficiently aligned. In particular, casting any aligned +//! non-zero integer literal to a raw pointer produces a valid pointer, but a +//! pointer pointing into previously allocated memory that since got freed is +//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot +//! be used is to use [`ptr::NonNull::dangling`]. +//! +//! So long as `T: Sized`, a `Box` is guaranteed to be represented +//! as a single pointer and is also ABI-compatible with C pointers +//! (i.e. the C type `T*`). This means that if you have extern "C" +//! Rust functions that will be called from C, you can define those +//! Rust functions using `Box` types, and use `T*` as corresponding +//! type on the C side. As an example, consider this C header which +//! declares functions that create and destroy some kind of `Foo` +//! value: +//! +//! ```c +//! /* C header */ +//! +//! /* Returns ownership to the caller */ +//! struct Foo* foo_new(void); +//! +//! /* Takes ownership from the caller; no-op when invoked with null */ +//! void foo_delete(struct Foo*); +//! ``` +//! +//! These two functions might be implemented in Rust as follows. Here, the +//! `struct Foo*` type from C is translated to `Box`, which captures +//! the ownership constraints. Note also that the nullable argument to +//! `foo_delete` is represented in Rust as `Option>`, since `Box` +//! cannot be null. +//! +//! ``` +//! #[repr(C)] +//! pub struct Foo; +//! +//! #[no_mangle] +//! pub extern "C" fn foo_new() -> Box { +//! Box::new(Foo) +//! } +//! +//! #[no_mangle] +//! pub extern "C" fn foo_delete(_: Option>) {} +//! ``` +//! +//! Even though `Box` has the same representation and C ABI as a C pointer, +//! this does not mean that you can convert an arbitrary `T*` into a `Box` +//! and expect things to work. `Box` values will always be fully aligned, +//! non-null pointers. Moreover, the destructor for `Box` will attempt to +//! free the value with the global allocator. In general, the best practice +//! is to only use `Box` for pointers that originated from the global +//! allocator. +//! +//! **Important.** At least at present, you should avoid using +//! `Box` types for functions that are defined in C but invoked +//! from Rust. In those cases, you should directly mirror the C types +//! as closely as possible. Using types like `Box` where the C +//! definition is just using `T*` can lead to undefined behavior, as +//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198]. +//! +//! # Considerations for unsafe code +//! +//! **Warning: This section is not normative and is subject to change, possibly +//! being relaxed in the future! It is a simplified summary of the rules +//! currently implemented in the compiler.** +//! +//! The aliasing rules for `Box` are the same as for `&mut T`. `Box` +//! asserts uniqueness over its content. Using raw pointers derived from a box +//! after that box has been mutated through, moved or borrowed as `&mut T` +//! is not allowed. For more guidance on working with box from unsafe code, see +//! [rust-lang/unsafe-code-guidelines#326][ucg#326]. +//! +//! +//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 +//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326 +//! [dereferencing]: core::ops::Deref +//! [`Box::::from_raw(value)`]: Box::from_raw +//! [`Global`]: crate::alloc::Global +//! [`Layout`]: crate::alloc::Layout +//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value +//! [valid]: ptr#safety + +use core::any::Any; +use core::borrow; +use core::cmp::Ordering; +use core::convert::{From, TryFrom}; + +// use core::error::Error; +use core::fmt; +use core::future::Future; +use core::hash::{Hash, Hasher}; +#[cfg(not(no_global_oom_handling))] +use core::iter::FromIterator; +use core::iter::{FusedIterator, Iterator}; +use core::marker::Unpin; +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr::{self, NonNull}; +use core::task::{Context, Poll}; + +use super::alloc::{AllocError, Allocator, Global, Layout}; +use super::raw_vec::RawVec; +use super::unique::Unique; +#[cfg(not(no_global_oom_handling))] +use super::vec::Vec; +#[cfg(not(no_global_oom_handling))] +use alloc_crate::alloc::handle_alloc_error; + +/// A pointer type for heap allocation. +/// +/// See the [module-level documentation](../../std/boxed/index.html) for more. +pub struct Box(Unique, A); + +// Safety: Box owns both T and A, so sending is safe if +// sending is safe for T and A. +unsafe impl Send for Box +where + T: Send, + A: Send, +{ +} + +// Safety: Box owns both T and A, so sharing is safe if +// sharing is safe for T and A. +unsafe impl Sync for Box +where + T: Sync, + A: Sync, +{ +} + +impl Box { + /// Allocates memory on the heap and then places `x` into it. + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// let five = Box::new(5); + /// ``` + #[cfg(all(not(no_global_oom_handling)))] + #[inline(always)] + #[must_use] + pub fn new(x: T) -> Self { + Self::new_in(x, Global) + } + + /// Constructs a new box with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut five = Box::::new_uninit(); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_uninit() -> Box> { + Self::new_uninit_in(Global) + } + + /// Constructs a new `Box` with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let zero = Box::::new_zeroed(); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_zeroed() -> Box> { + Self::new_zeroed_in(Global) + } + + /// Constructs a new `Pin>`. If `T` does not implement [`Unpin`], then + /// `x` will be pinned in memory and unable to be moved. + /// + /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin(x)` + /// does the same as [Box::into_pin]\([Box::new]\(x)). Consider using + /// [`into_pin`](Box::into_pin) if you already have a `Box`, or if you want to + /// construct a (pinned) `Box` in a different way than with [`Box::new`]. + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn pin(x: T) -> Pin> { + Box::new(x).into() + } + + /// Allocates memory on the heap then places `x` into it, + /// returning an error if the allocation fails + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// let five = Box::try_new(5)?; + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline(always)] + pub fn try_new(x: T) -> Result { + Self::try_new_in(x, Global) + } + + /// Constructs a new box with uninitialized contents on the heap, + /// returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let mut five = Box::::try_new_uninit()?; + /// + /// let five = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline(always)] + pub fn try_new_uninit() -> Result>, AllocError> { + Box::try_new_uninit_in(Global) + } + + /// Constructs a new `Box` with uninitialized contents, with the memory + /// being filled with `0` bytes on the heap + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let zero = Box::::try_new_zeroed()?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[inline(always)] + pub fn try_new_zeroed() -> Result>, AllocError> { + Box::try_new_zeroed_in(Global) + } +} + +impl Box { + /// Allocates memory in the given allocator then places `x` into it. + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let five = Box::new_in(5, System); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_in(x: T, alloc: A) -> Self + where + A: Allocator, + { + let mut boxed = Self::new_uninit_in(alloc); + unsafe { + boxed.as_mut_ptr().write(x); + boxed.assume_init() + } + } + + /// Allocates memory in the given allocator then places `x` into it, + /// returning an error if the allocation fails + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let five = Box::try_new_in(5, System)?; + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline(always)] + pub fn try_new_in(x: T, alloc: A) -> Result + where + A: Allocator, + { + let mut boxed = Self::try_new_uninit_in(alloc)?; + unsafe { + boxed.as_mut_ptr().write(x); + Ok(boxed.assume_init()) + } + } + + /// Constructs a new box with uninitialized contents in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut five = Box::::new_uninit_in(System); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[must_use] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline(always)] + pub fn new_uninit_in(alloc: A) -> Box, A> + where + A: Allocator, + { + let layout = Layout::new::>(); + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Box::try_new_uninit_in(alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(layout), + } + } + + /// Constructs a new box with uninitialized contents in the provided allocator, + /// returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut five = Box::::try_new_uninit_in(System)?; + /// + /// let five = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline(always)] + pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> + where + A: Allocator, + { + let ptr = if mem::size_of::() == 0 { + NonNull::dangling() + } else { + let layout = Layout::new::>(); + alloc.allocate(layout)?.cast() + }; + + unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } + } + + /// Constructs a new `Box` with uninitialized contents, with the memory + /// being filled with `0` bytes in the provided allocator. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let zero = Box::::new_zeroed_in(System); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] + #[inline(always)] + pub fn new_zeroed_in(alloc: A) -> Box, A> + where + A: Allocator, + { + let layout = Layout::new::>(); + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Box::try_new_zeroed_in(alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(layout), + } + } + + /// Constructs a new `Box` with uninitialized contents, with the memory + /// being filled with `0` bytes in the provided allocator, + /// returning an error if the allocation fails, + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let zero = Box::::try_new_zeroed_in(System)?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[inline(always)] + pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> + where + A: Allocator, + { + let ptr = if mem::size_of::() == 0 { + NonNull::dangling() + } else { + let layout = Layout::new::>(); + alloc.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } + } + + /// Constructs a new `Pin>`. If `T` does not implement [`Unpin`], then + /// `x` will be pinned in memory and unable to be moved. + /// + /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin_in(x, alloc)` + /// does the same as [Box::into_pin]\([Box::new_in]\(x, alloc)). Consider using + /// [`into_pin`](Box::into_pin) if you already have a `Box`, or if you want to + /// construct a (pinned) `Box` in a different way than with [`Box::new_in`]. + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn pin_in(x: T, alloc: A) -> Pin + where + A: 'static + Allocator, + { + Self::into_pin(Self::new_in(x, alloc)) + } + + /// Converts a `Box` into a `Box<[T]>` + /// + /// This conversion does not allocate on the heap and happens in place. + #[inline(always)] + pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { + let (raw, alloc) = Box::into_raw_with_allocator(boxed); + unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } + } + + /// Consumes the `Box`, returning the wrapped value. + /// + /// # Examples + /// + /// ``` + /// #![feature(box_into_inner)] + /// + /// let c = Box::new(5); + /// + /// assert_eq!(Box::into_inner(c), 5); + /// ``` + #[inline(always)] + pub fn into_inner(boxed: Self) -> T { + // Override our default `Drop` implementation. + // Though the default `Drop` implementation drops the both the pointer and the allocator, + // here we only want to drop the allocator. + let boxed = mem::ManuallyDrop::new(boxed); + let alloc = unsafe { ptr::read(&boxed.1) }; + + let ptr = boxed.0; + let unboxed = unsafe { ptr.as_ptr().read() }; + unsafe { alloc.deallocate(ptr.as_non_null_ptr().cast(), Layout::new::()) }; + + unboxed + } +} + +impl Box<[T]> { + /// Constructs a new boxed slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut values = Box::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit]> { + unsafe { RawVec::with_capacity(len).into_box(len) } + } + + /// Constructs a new boxed slice with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let values = Box::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { + unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } + } + + /// Constructs a new boxed slice with uninitialized contents. Returns an error if + /// the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let mut values = Box::<[u32]>::try_new_uninit_slice(3)?; + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline(always)] + pub fn try_new_uninit_slice(len: usize) -> Result]>, AllocError> { + Self::try_new_uninit_slice_in(len, Global) + } + + /// Constructs a new boxed slice with uninitialized contents, with the memory + /// being filled with `0` bytes. Returns an error if the allocation fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let values = Box::<[u32]>::try_new_zeroed_slice(3)?; + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[inline(always)] + pub fn try_new_zeroed_slice(len: usize) -> Result]>, AllocError> { + Self::try_new_zeroed_slice_in(len, Global) + } +} + +impl Box<[T], A> { + /// Constructs a new boxed slice with uninitialized contents in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut values = Box::<[u32], _>::new_uninit_slice_in(3, System); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { + unsafe { RawVec::with_capacity_in(len, alloc).into_box(len) } + } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator, + /// with the memory being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let values = Box::<[u32], _>::new_zeroed_slice_in(3, System); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { + unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) } + } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator. Returns an error if + /// the allocation fails. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut values = Box::<[u32], _>::try_new_uninit_slice_in(3, System)?; + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[inline] + pub fn try_new_uninit_slice_in( + len: usize, + alloc: A, + ) -> Result], A>, AllocError> { + let ptr = if mem::size_of::() == 0 || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + alloc.allocate(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator, with the memory + /// being filled with `0` bytes. Returns an error if the allocation fails. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let values = Box::<[u32], _>::try_new_zeroed_slice_in(3, System)?; + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[inline] + pub fn try_new_zeroed_slice_in( + len: usize, + alloc: A, + ) -> Result], A>, AllocError> { + let ptr = if mem::size_of::() == 0 || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + alloc.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } + + /// Converts `self` into a vector without clones or allocation. + /// + /// The resulting vector can be converted back into a box via + /// `Vec`'s `into_boxed_slice` method. + /// + /// # Examples + /// + /// ``` + /// let s: Box<[i32]> = Box::new([10, 40, 30]); + /// let x = s.into_vec(); + /// // `s` cannot be used anymore because it has been converted into `x`. + /// + /// assert_eq!(x, vec![10, 40, 30]); + /// ``` + #[inline] + pub fn into_vec(self) -> Vec + where + A: Allocator, + { + unsafe { + let len = self.len(); + let (b, alloc) = Box::into_raw_with_allocator(self); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) + } + } +} + +impl Box, A> { + /// Converts to `Box`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut five = Box::::new_uninit(); + /// + /// let five: Box = unsafe { + /// // Deferred initialization: + /// five.as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[inline(always)] + pub unsafe fn assume_init(self) -> Box { + let (raw, alloc) = Self::into_raw_with_allocator(self); + unsafe { Box::::from_raw_in(raw as *mut T, alloc) } + } + + /// Writes the value and converts to `Box`. + /// + /// This method converts the box similarly to [`Box::assume_init`] but + /// writes `value` into it before conversion thus guaranteeing safety. + /// In some scenarios use of this method may improve performance because + /// the compiler may be able to optimize copying from stack. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let big_box = Box::<[usize; 1024]>::new_uninit(); + /// + /// let mut array = [0; 1024]; + /// for (i, place) in array.iter_mut().enumerate() { + /// *place = i; + /// } + /// + /// // The optimizer may be able to elide this copy, so previous code writes + /// // to heap directly. + /// let big_box = Box::write(big_box, array); + /// + /// for (i, x) in big_box.iter().enumerate() { + /// assert_eq!(*x, i); + /// } + /// ``` + #[inline(always)] + pub fn write(mut boxed: Self, value: T) -> Box { + unsafe { + (*boxed).write(value); + boxed.assume_init() + } + } +} + +impl Box<[mem::MaybeUninit], A> { + /// Converts to `Box<[T], A>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the values + /// really are in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut values = Box::<[u32]>::new_uninit_slice(3); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[inline(always)] + pub unsafe fn assume_init(self) -> Box<[T], A> { + let (raw, alloc) = Self::into_raw_with_allocator(self); + unsafe { Box::<[T], A>::from_raw_in(raw as *mut [T], alloc) } + } +} + +impl Box { + /// Constructs a box from a raw pointer. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// The safety conditions are described in the [memory layout] section. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw`]: + /// ``` + /// let x = Box::new(5); + /// let ptr = Box::into_raw(x); + /// let x = unsafe { Box::from_raw(ptr) }; + /// ``` + /// Manually create a `Box` from scratch by using the global allocator: + /// ``` + /// use std::alloc::{alloc, Layout}; + /// + /// unsafe { + /// let ptr = alloc(Layout::new::()) as *mut i32; + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); + /// let x = Box::from_raw(ptr); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + /// [`Layout`]: crate::Layout + #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"] + #[inline(always)] + pub unsafe fn from_raw(raw: *mut T) -> Self { + unsafe { Self::from_raw_in(raw, Global) } + } +} + +impl Box { + /// Constructs a box from a raw pointer in the given allocator. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw_with_allocator`]: + /// ``` + /// use std::alloc::System; + /// # use allocator_api2::boxed::Box; + /// + /// let x = Box::new_in(5, System); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); + /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// use allocator_api2::alloc::{Allocator, Layout, System}; + /// # use allocator_api2::boxed::Box; + /// + /// unsafe { + /// let ptr = System.allocate(Layout::new::())?.as_ptr().cast::(); + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); + /// let x = Box::from_raw_in(ptr, System); + /// } + /// # Ok::<(), allocator_api2::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + /// [`Layout`]: crate::Layout + #[inline(always)] + pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + Box(unsafe { Unique::new_unchecked(raw) }, alloc) + } + + /// Consumes the `Box`, returning a wrapped raw pointer. + /// + /// The pointer will be properly aligned and non-null. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Box`. In particular, the + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the raw pointer back into a `Box` with the + /// [`Box::from_raw`] function, allowing the `Box` destructor to perform + /// the cleanup. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] + /// for automatic cleanup: + /// ``` + /// let x = Box::new(String::from("Hello")); + /// let ptr = Box::into_raw(x); + /// let x = unsafe { Box::from_raw(ptr) }; + /// ``` + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: + /// ``` + /// use std::alloc::{dealloc, Layout}; + /// use std::ptr; + /// + /// let x = Box::new(String::from("Hello")); + /// let p = Box::into_raw(x); + /// unsafe { + /// ptr::drop_in_place(p); + /// dealloc(p as *mut u8, Layout::new::()); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + #[inline(always)] + pub fn into_raw(b: Self) -> *mut T { + Self::into_raw_with_allocator(b).0 + } + + /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. + /// + /// The pointer will be properly aligned and non-null. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Box`. In particular, the + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the raw pointer back into a `Box` with the + /// [`Box::from_raw_in`] function, allowing the `Box` destructor to perform + /// the cleanup. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_raw_with_allocator(b)` instead of `b.into_raw_with_allocator()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// Converting the raw pointer back into a `Box` with [`Box::from_raw_in`] + /// for automatic cleanup: + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(String::from("Hello"), System); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); + /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; + /// ``` + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// use std::ptr::{self, NonNull}; + /// + /// let x = Box::new_in(String::from("Hello"), System); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); + /// unsafe { + /// ptr::drop_in_place(ptr); + /// let non_null = NonNull::new_unchecked(ptr); + /// alloc.deallocate(non_null.cast(), Layout::new::()); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + #[inline(always)] + pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { + let (leaked, alloc) = Box::into_non_null(b); + (leaked.as_ptr(), alloc) + } + + #[inline(always)] + pub fn into_non_null(b: Self) -> (NonNull, A) { + // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a + // raw pointer for the type system. Turning it directly into a raw pointer would not be + // recognized as "releasing" the unique pointer to permit aliased raw accesses, + // so all raw pointer methods have to go through `Box::leak`. Turning *that* to a raw pointer + // behaves correctly. + let alloc = unsafe { ptr::read(&b.1) }; + (NonNull::from(Box::leak(b)), alloc) + } + + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline(always)] + pub const fn allocator(b: &Self) -> &A { + &b.1 + } + + /// Consumes and leaks the `Box`, returning a mutable reference, + /// `&'a mut T`. Note that the type `T` must outlive the chosen lifetime + /// `'a`. If the type has only static references, or none at all, then this + /// may be chosen to be `'static`. + /// + /// This function is mainly useful for data that lives for the remainder of + /// the program's life. Dropping the returned reference will cause a memory + /// leak. If this is not acceptable, the reference should first be wrapped + /// with the [`Box::from_raw`] function producing a `Box`. This `Box` can + /// then be dropped which will properly destroy `T` and release the + /// allocated memory. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::leak(b)` instead of `b.leak()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// + /// Simple usage: + /// + /// ``` + /// let x = Box::new(41); + /// let static_ref: &'static mut usize = Box::leak(x); + /// *static_ref += 1; + /// assert_eq!(*static_ref, 42); + /// ``` + /// + /// Unsized data: + /// + /// ``` + /// let x = vec![1, 2, 3].into_boxed_slice(); + /// let static_ref = Box::leak(x); + /// static_ref[0] = 4; + /// assert_eq!(*static_ref, [4, 2, 3]); + /// ``` + #[inline(always)] + pub fn leak<'a>(b: Self) -> &'a mut T + where + A: 'a, + { + unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() } + } + + /// Converts a `Box` into a `Pin>`. If `T` does not implement [`Unpin`], then + /// `*boxed` will be pinned in memory and unable to be moved. + /// + /// This conversion does not allocate on the heap and happens in place. + /// + /// This is also available via [`From`]. + /// + /// Constructing and pinning a `Box` with Box::into_pin([Box::new]\(x)) + /// can also be written more concisely using [Box::pin]\(x). + /// This `into_pin` method is useful if you already have a `Box`, or you are + /// constructing a (pinned) `Box` in a different way than with [`Box::new`]. + /// + /// # Notes + /// + /// It's not recommended that crates add an impl like `From> for Pin`, + /// as it'll introduce an ambiguity when calling `Pin::from`. + /// A demonstration of such a poor impl is shown below. + /// + /// ```compile_fail + /// # use std::pin::Pin; + /// struct Foo; // A type defined in this crate. + /// impl From> for Pin { + /// fn from(_: Box<()>) -> Pin { + /// Pin::new(Foo) + /// } + /// } + /// + /// let foo = Box::new(()); + /// let bar = Pin::from(foo); + /// ``` + #[inline(always)] + pub fn into_pin(boxed: Self) -> Pin + where + A: 'static, + { + // It's not possible to move or replace the insides of a `Pin>` + // when `T: !Unpin`, so it's safe to pin it directly without any + // additional requirements. + unsafe { Pin::new_unchecked(boxed) } + } +} + +impl Drop for Box { + #[inline(always)] + fn drop(&mut self) { + let layout = Layout::for_value::(&**self); + unsafe { + ptr::drop_in_place(self.0.as_mut()); + self.1.deallocate(self.0.as_non_null_ptr().cast(), layout); + } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Default for Box { + /// Creates a `Box`, with the `Default` value for T. + #[inline(always)] + fn default() -> Self { + Box::new(T::default()) + } +} + +impl Default for Box<[T], A> { + #[inline(always)] + fn default() -> Self { + let ptr: NonNull<[T]> = NonNull::<[T; 0]>::dangling(); + Box(unsafe { Unique::new_unchecked(ptr.as_ptr()) }, A::default()) + } +} + +impl Default for Box { + #[inline(always)] + fn default() -> Self { + // SAFETY: This is the same as `Unique::cast` but with an unsized `U = str`. + let ptr: Unique = unsafe { + let bytes: NonNull<[u8]> = NonNull::<[u8; 0]>::dangling(); + Unique::new_unchecked(bytes.as_ptr() as *mut str) + }; + Box(ptr, A::default()) + } +} + +#[cfg(not(no_global_oom_handling))] +impl Clone for Box { + /// Returns a new box with a `clone()` of this box's contents. + /// + /// # Examples + /// + /// ``` + /// let x = Box::new(5); + /// let y = x.clone(); + /// + /// // The value is the same + /// assert_eq!(x, y); + /// + /// // But they are unique objects + /// assert_ne!(&*x as *const i32, &*y as *const i32); + /// ``` + #[inline(always)] + fn clone(&self) -> Self { + // Pre-allocate memory to allow writing the cloned value directly. + let mut boxed = Self::new_uninit_in(self.1.clone()); + unsafe { + boxed.write((**self).clone()); + boxed.assume_init() + } + } + + /// Copies `source`'s contents into `self` without creating a new allocation. + /// + /// # Examples + /// + /// ``` + /// let x = Box::new(5); + /// let mut y = Box::new(10); + /// let yp: *const i32 = &*y; + /// + /// y.clone_from(&x); + /// + /// // The value is the same + /// assert_eq!(x, y); + /// + /// // And no allocation occurred + /// assert_eq!(yp, &*y); + /// ``` + #[inline(always)] + fn clone_from(&mut self, source: &Self) { + (**self).clone_from(&(**source)); + } +} + +#[cfg(not(no_global_oom_handling))] +impl Clone for Box { + #[inline(always)] + fn clone(&self) -> Self { + // this makes a copy of the data + let buf: Box<[u8]> = self.as_bytes().into(); + unsafe { Box::from_raw(Box::into_raw(buf) as *mut str) } + } +} + +impl PartialEq for Box { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + #[inline(always)] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +impl PartialOrd for Box { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } + #[inline(always)] + fn lt(&self, other: &Self) -> bool { + PartialOrd::lt(&**self, &**other) + } + #[inline(always)] + fn le(&self, other: &Self) -> bool { + PartialOrd::le(&**self, &**other) + } + #[inline(always)] + fn ge(&self, other: &Self) -> bool { + PartialOrd::ge(&**self, &**other) + } + #[inline(always)] + fn gt(&self, other: &Self) -> bool { + PartialOrd::gt(&**self, &**other) + } +} + +impl Ord for Box { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl Eq for Box {} + +impl Hash for Box { + #[inline(always)] + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +impl Hasher for Box { + #[inline(always)] + fn finish(&self) -> u64 { + (**self).finish() + } + #[inline(always)] + fn write(&mut self, bytes: &[u8]) { + (**self).write(bytes) + } + #[inline(always)] + fn write_u8(&mut self, i: u8) { + (**self).write_u8(i) + } + #[inline(always)] + fn write_u16(&mut self, i: u16) { + (**self).write_u16(i) + } + #[inline(always)] + fn write_u32(&mut self, i: u32) { + (**self).write_u32(i) + } + #[inline(always)] + fn write_u64(&mut self, i: u64) { + (**self).write_u64(i) + } + #[inline(always)] + fn write_u128(&mut self, i: u128) { + (**self).write_u128(i) + } + #[inline(always)] + fn write_usize(&mut self, i: usize) { + (**self).write_usize(i) + } + #[inline(always)] + fn write_i8(&mut self, i: i8) { + (**self).write_i8(i) + } + #[inline(always)] + fn write_i16(&mut self, i: i16) { + (**self).write_i16(i) + } + #[inline(always)] + fn write_i32(&mut self, i: i32) { + (**self).write_i32(i) + } + #[inline(always)] + fn write_i64(&mut self, i: i64) { + (**self).write_i64(i) + } + #[inline(always)] + fn write_i128(&mut self, i: i128) { + (**self).write_i128(i) + } + #[inline(always)] + fn write_isize(&mut self, i: isize) { + (**self).write_isize(i) + } +} + +#[cfg(not(no_global_oom_handling))] +impl From for Box { + /// Converts a `T` into a `Box` + /// + /// The conversion allocates on the heap and moves `t` + /// from the stack into it. + /// + /// # Examples + /// + /// ```rust + /// let x = 5; + /// let boxed = Box::new(5); + /// + /// assert_eq!(Box::from(x), boxed); + /// ``` + #[inline(always)] + fn from(t: T) -> Self { + Box::new(t) + } +} + +impl From> for Pin> +where + A: 'static, +{ + /// Converts a `Box` into a `Pin>`. If `T` does not implement [`Unpin`], then + /// `*boxed` will be pinned in memory and unable to be moved. + /// + /// This conversion does not allocate on the heap and happens in place. + /// + /// This is also available via [`Box::into_pin`]. + /// + /// Constructing and pinning a `Box` with >>::from([Box::new]\(x)) + /// can also be written more concisely using [Box::pin]\(x). + /// This `From` implementation is useful if you already have a `Box`, or you are + /// constructing a (pinned) `Box` in a different way than with [`Box::new`]. + #[inline(always)] + fn from(boxed: Box) -> Self { + Box::into_pin(boxed) + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<&[T]> for Box<[T], A> { + /// Converts a `&[T]` into a `Box<[T]>` + /// + /// This conversion allocates on the heap + /// and performs a copy of `slice` and its contents. + /// + /// # Examples + /// ```rust + /// // create a &[u8] which will be used to create a Box<[u8]> + /// let slice: &[u8] = &[104, 101, 108, 108, 111]; + /// let boxed_slice: Box<[u8]> = Box::from(slice); + /// + /// println!("{boxed_slice:?}"); + /// ``` + #[inline(always)] + fn from(slice: &[T]) -> Box<[T], A> { + let len = slice.len(); + let buf = RawVec::with_capacity_in(len, A::default()); + unsafe { + ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); + buf.into_box(slice.len()).assume_init() + } + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<&str> for Box { + /// Converts a `&str` into a `Box` + /// + /// This conversion allocates on the heap + /// and performs a copy of `s`. + /// + /// # Examples + /// + /// ```rust + /// let boxed: Box = Box::from("hello"); + /// println!("{boxed}"); + /// ``` + #[inline(always)] + fn from(s: &str) -> Box { + let (raw, alloc) = Box::into_raw_with_allocator(Box::<[u8], A>::from(s.as_bytes())); + unsafe { Box::from_raw_in(raw as *mut str, alloc) } + } +} + +impl From> for Box<[u8], A> { + /// Converts a `Box` into a `Box<[u8]>` + /// + /// This conversion does not allocate on the heap and happens in place. + /// + /// # Examples + /// ```rust + /// // create a Box which will be used to create a Box<[u8]> + /// let boxed: Box = Box::from("hello"); + /// let boxed_str: Box<[u8]> = Box::from(boxed); + /// + /// // create a &[u8] which will be used to create a Box<[u8]> + /// let slice: &[u8] = &[104, 101, 108, 108, 111]; + /// let boxed_slice = Box::from(slice); + /// + /// assert_eq!(boxed_slice, boxed_str); + /// ``` + #[inline(always)] + fn from(s: Box) -> Self { + let (raw, alloc) = Box::into_raw_with_allocator(s); + unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } + } +} + +impl Box<[T; N], A> { + #[inline(always)] + pub fn slice(b: Self) -> Box<[T], A> { + let (ptr, alloc) = Box::into_raw_with_allocator(b); + unsafe { Box::from_raw_in(ptr, alloc) } + } + + pub fn into_vec(self) -> Vec + where + A: Allocator, + { + unsafe { + let (b, alloc) = Box::into_raw_with_allocator(self); + Vec::from_raw_parts_in(b as *mut T, N, N, alloc) + } + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<[T; N]> for Box<[T]> { + /// Converts a `[T; N]` into a `Box<[T]>` + /// + /// This conversion moves the array to newly heap-allocated memory. + /// + /// # Examples + /// + /// ```rust + /// let boxed: Box<[u8]> = Box::from([4, 2]); + /// println!("{boxed:?}"); + /// ``` + #[inline(always)] + fn from(array: [T; N]) -> Box<[T]> { + Box::slice(Box::new(array)) + } +} + +impl TryFrom> for Box<[T; N], A> { + type Error = Box<[T], A>; + + /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`. + /// + /// The conversion occurs in-place and does not require a + /// new memory allocation. + /// + /// # Errors + /// + /// Returns the old `Box<[T]>` in the `Err` variant if + /// `boxed_slice.len()` does not equal `N`. + #[inline(always)] + fn try_from(boxed_slice: Box<[T], A>) -> Result { + if boxed_slice.len() == N { + let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice); + Ok(unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }) + } else { + Err(boxed_slice) + } + } +} + +impl Box { + /// Attempt to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline(always)] + pub fn downcast(self) -> Result, Self> { + if self.is::() { + unsafe { Ok(self.downcast_unchecked::()) } + } else { + Err(self) + } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline(always)] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + unsafe { + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +impl Box { + /// Attempt to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline(always)] + pub fn downcast(self) -> Result, Self> { + if self.is::() { + unsafe { Ok(self.downcast_unchecked::()) } + } else { + Err(self) + } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline(always)] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +impl Box { + /// Attempt to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline(always)] + pub fn downcast(self) -> Result, Self> { + if self.is::() { + unsafe { Ok(self.downcast_unchecked::()) } + } else { + Err(self) + } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline(always)] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = + Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +impl fmt::Display for Box { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl fmt::Debug for Box { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl fmt::Pointer for Box { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // It's not possible to extract the inner Uniq directly from the Box, + // instead we cast it to a *const which aliases the Unique + let ptr: *const T = &**self; + fmt::Pointer::fmt(&ptr, f) + } +} + +impl Deref for Box { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + unsafe { self.0.as_ref() } + } +} + +impl DerefMut for Box { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + unsafe { self.0.as_mut() } + } +} + +impl Iterator for Box { + type Item = I::Item; + + #[inline(always)] + fn next(&mut self) -> Option { + (**self).next() + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } + + #[inline(always)] + fn nth(&mut self, n: usize) -> Option { + (**self).nth(n) + } + + #[inline(always)] + fn last(self) -> Option { + BoxIter::last(self) + } +} + +trait BoxIter { + type Item; + fn last(self) -> Option; +} + +impl BoxIter for Box { + type Item = I::Item; + + #[inline(always)] + fn last(self) -> Option { + #[inline(always)] + fn some(_: Option, x: T) -> Option { + Some(x) + } + + self.fold(None, some) + } +} + +impl DoubleEndedIterator for Box { + #[inline(always)] + fn next_back(&mut self) -> Option { + (**self).next_back() + } + #[inline(always)] + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } +} + +impl ExactSizeIterator for Box { + #[inline(always)] + fn len(&self) -> usize { + (**self).len() + } +} + +impl FusedIterator for Box {} + +#[cfg(not(no_global_oom_handling))] +impl FromIterator for Box<[I]> { + #[inline(always)] + fn from_iter>(iter: T) -> Self { + iter.into_iter().collect::>().into_boxed_slice() + } +} + +#[cfg(not(no_global_oom_handling))] +impl Clone for Box<[T], A> { + #[inline(always)] + fn clone(&self) -> Self { + let alloc = Box::allocator(self).clone(); + let mut vec = Vec::with_capacity_in(self.len(), alloc); + vec.extend_from_slice(self); + vec.into_boxed_slice() + } + + #[inline(always)] + fn clone_from(&mut self, other: &Self) { + if self.len() == other.len() { + self.clone_from_slice(other); + } else { + *self = other.clone(); + } + } +} + +impl borrow::Borrow for Box { + #[inline(always)] + fn borrow(&self) -> &T { + self + } +} + +impl borrow::BorrowMut for Box { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut T { + self + } +} + +impl AsRef for Box { + #[inline(always)] + fn as_ref(&self) -> &T { + self + } +} + +impl AsMut for Box { + #[inline(always)] + fn as_mut(&mut self) -> &mut T { + self + } +} + +/* Nota bene + * + * We could have chosen not to add this impl, and instead have written a + * function of Pin> to Pin. Such a function would not be sound, + * because Box implements Unpin even when T does not, as a result of + * this impl. + * + * We chose this API instead of the alternative for a few reasons: + * - Logically, it is helpful to understand pinning in regard to the + * memory region being pointed to. For this reason none of the + * standard library pointer types support projecting through a pin + * (Box is the only pointer type in std for which this would be + * safe.) + * - It is in practice very useful to have Box be unconditionally + * Unpin because of trait objects, for which the structural auto + * trait functionality does not apply (e.g., Box would + * otherwise not be Unpin). + * + * Another type with the same semantics as Box but only a conditional + * implementation of `Unpin` (where `T: Unpin`) would be valid/safe, and + * could have a method to project a Pin from it. + */ +impl Unpin for Box where A: 'static {} + +impl Future for Box +where + A: 'static, +{ + type Output = F::Output; + + #[inline(always)] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut *self), cx) + } +} + +#[cfg(feature = "std")] +mod error { + use std::error::Error; + + use super::Box; + + #[cfg(not(no_global_oom_handling))] + impl<'a, E: Error + 'a> From for Box { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline(always)] + fn from(err: E) -> Box { + unsafe { Box::from_raw(Box::leak(Box::new(err))) } + } + } + + #[cfg(not(no_global_oom_handling))] + impl<'a, E: Error + Send + Sync + 'a> From for Box { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline(always)] + fn from(err: E) -> Box { + unsafe { Box::from_raw(Box::leak(Box::new(err))) } + } + } + + impl Error for Box { + #[inline(always)] + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + } +} + +#[cfg(feature = "std")] +impl std::io::Read for Box { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + (**self).read(buf) + } + + #[inline] + fn read_to_end(&mut self, buf: &mut std::vec::Vec) -> std::io::Result { + (**self).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> std::io::Result { + (**self).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + (**self).read_exact(buf) + } +} + +#[cfg(feature = "std")] +impl std::io::Write for Box { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + (**self).write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + (**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + (**self).write_all(buf) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> std::io::Result<()> { + (**self).write_fmt(fmt) + } +} + +#[cfg(feature = "std")] +impl std::io::Seek for Box { + #[inline] + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + (**self).seek(pos) + } + + #[inline] + fn stream_position(&mut self) -> std::io::Result { + (**self).stream_position() + } +} + +#[cfg(feature = "std")] +impl std::io::BufRead for Box { + #[inline] + fn fill_buf(&mut self) -> std::io::Result<&[u8]> { + (**self).fill_buf() + } + + #[inline] + fn consume(&mut self, amt: usize) { + (**self).consume(amt) + } + + #[inline] + fn read_until(&mut self, byte: u8, buf: &mut std::vec::Vec) -> std::io::Result { + (**self).read_until(byte, buf) + } + + #[inline] + fn read_line(&mut self, buf: &mut std::string::String) -> std::io::Result { + (**self).read_line(buf) + } +} + +#[cfg(feature = "alloc")] +impl Extend> for alloc_crate::string::String { + fn extend>>(&mut self, iter: I) { + iter.into_iter().for_each(move |s| self.push_str(&s)); + } +} + +#[cfg(not(no_global_oom_handling))] +#[cfg(feature = "std")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + (**self).into() + } +} + +#[cfg(not(no_global_oom_handling))] +#[cfg(feature = "std")] +impl From<&std::ffi::CStr> for Box { + /// Converts a `&CStr` into a `Box`, + /// by copying the contents into a newly allocated [`Box`]. + fn from(s: &std::ffi::CStr) -> Box { + let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut std::ffi::CStr) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[cfg(feature = "fresh-rust")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + (**self).into() + } +} + +#[cfg(not(no_global_oom_handling))] +#[cfg(feature = "fresh-rust")] +impl From<&core::ffi::CStr> for Box { + /// Converts a `&CStr` into a `Box`, + /// by copying the contents into a newly allocated [`Box`]. + fn from(s: &core::ffi::CStr) -> Box { + let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut core::ffi::CStr) } + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Box +where + T: serde::Serialize, + A: Allocator, +{ + #[inline(always)] + fn serialize(&self, serializer: S) -> Result { + (**self).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, T, A> serde::Deserialize<'de> for Box +where + T: serde::Deserialize<'de>, + A: Allocator + Default, +{ + #[inline(always)] + fn deserialize>(deserializer: D) -> Result { + let value = T::deserialize(deserializer)?; + Ok(Box::new_in(value, A::default())) + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/macros.rs b/deps/crates/vendor/allocator-api2/src/stable/macros.rs new file mode 100644 index 00000000000000..f67c58756c8239 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/macros.rs @@ -0,0 +1,83 @@ +/// Creates a [`Vec`] containing the arguments. +/// +/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a [`Vec`] containing a given list of elements: +/// +/// ``` +/// use allocator_api2::vec; +/// let v = vec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// ``` +/// +/// +/// ``` +/// use allocator_api2::{vec, alloc::Global}; +/// let v = vec![in Global; 1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// ``` +/// +/// - Create a [`Vec`] from a given element and size: +/// +/// ``` +/// use allocator_api2::vec; +/// let v = vec![1; 3]; +/// assert_eq!(v, [1, 1, 1]); +/// ``` +/// +/// ``` +/// use allocator_api2::{vec, alloc::Global}; +/// let v = vec![in Global; 1; 3]; +/// assert_eq!(v, [1, 1, 1]); +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement [`Clone`] and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone` to duplicate an expression, so one should be careful +/// using this with types having a nonstandard `Clone` implementation. For +/// example, `vec![Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. +/// +/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. +/// +/// [`Vec`]: crate::vec::Vec +#[cfg(not(no_global_oom_handling))] +#[macro_export] +macro_rules! vec { + (in $alloc:expr $(;)?) => ( + $crate::vec::Vec::new_in($alloc) + ); + (in $alloc:expr; $elem:expr; $n:expr) => ( + $crate::vec::from_elem_in($elem, $n, $alloc) + ); + (in $alloc:expr; $($x:expr),+ $(,)?) => ( + $crate::boxed::Box::<[_]>::into_vec( + $crate::boxed::Box::slice( + $crate::boxed::Box::new_in([$($x),+], $alloc) + ) + ) + ); + () => ( + $crate::vec::Vec::new() + ); + ($elem:expr; $n:expr) => ( + $crate::vec::from_elem($elem, $n) + ); + ($($x:expr),+ $(,)?) => ( + $crate::boxed::Box::<[_]>::into_vec( + $crate::boxed::Box::slice( + $crate::boxed::Box::new([$($x),+]) + ) + ) + ); +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/mod.rs b/deps/crates/vendor/allocator-api2/src/stable/mod.rs new file mode 100644 index 00000000000000..0f2c9cea8f991d --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/mod.rs @@ -0,0 +1,105 @@ +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(clippy::needless_doctest_main, clippy::partialeq_ne_impl)] + +#[cfg(feature = "alloc")] +pub use self::slice::SliceExt; + +pub mod alloc; + +#[cfg(feature = "alloc")] +pub mod boxed; + +#[cfg(feature = "alloc")] +mod raw_vec; + +#[cfg(feature = "alloc")] +pub mod vec; + +#[cfg(feature = "alloc")] +mod macros; + +#[cfg(feature = "alloc")] +mod slice; + +#[cfg(feature = "alloc")] +mod unique; + +/// Allows turning a [`Box`][boxed::Box] into a [`Box`][boxed::Box] where `T` can be unsizing-coerced into a `U`. +/// +/// This is the only way to create an `allocator_api2::boxed::Box` of an unsized type on stable. +/// +/// With the standard library's `alloc::boxed::Box`, this is done automatically using the unstable unsize traits, but this crate's Box +/// can't take advantage of that machinery on stable. So, we need to use type inference and the fact that you *can* +/// still coerce the inner pointer of a box to get the compiler to help us unsize it using this macro. +/// +/// # Example +/// +/// ``` +/// use allocator_api2::unsize_box; +/// use allocator_api2::boxed::Box; +/// use core::any::Any; +/// +/// let sized_box: Box = Box::new(0); +/// let unsized_box: Box = unsize_box!(sized_box); +/// ``` +#[macro_export] +#[cfg(feature = "alloc")] +macro_rules! unsize_box {( $boxed:expr $(,)? ) => ({ + let (ptr, allocator) = ::allocator_api2::boxed::Box::into_raw_with_allocator($boxed); + // we don't want to allow casting to arbitrary type U, but we do want to allow unsize coercion to happen. + // that's exactly what's happening here -- this is *not* a pointer cast ptr as *mut _, but the compiler + // *will* allow an unsizing coercion to happen into the `ptr` place, if one is available. And we use _ so that the user can + // fill in what they want the unsized type to be by annotating the type of the variable this macro will + // assign its result to. + let ptr: *mut _ = ptr; + // SAFETY: see above for why ptr's type can only be something that can be safely coerced. + // also, ptr just came from a properly allocated box in the same allocator. + unsafe { + ::allocator_api2::boxed::Box::from_raw_in(ptr, allocator) + } +})} + +#[cfg(feature = "alloc")] +pub mod collections { + pub use super::raw_vec::{TryReserveError, TryReserveErrorKind}; +} + +#[cfg(feature = "alloc")] +#[track_caller] +#[inline(always)] +#[cfg(debug_assertions)] +unsafe fn assume(v: bool) { + if !v { + core::unreachable!() + } +} + +#[cfg(feature = "alloc")] +#[track_caller] +#[inline(always)] +#[cfg(not(debug_assertions))] +unsafe fn assume(v: bool) { + if !v { + unsafe { + core::hint::unreachable_unchecked(); + } + } +} + +#[cfg(feature = "alloc")] +#[inline(always)] +fn addr(x: *const T) -> usize { + #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] + unsafe { + core::mem::transmute(x) + } +} + +#[cfg(feature = "alloc")] +#[inline(always)] +fn invalid_mut(addr: usize) -> *mut T { + #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] + unsafe { + core::mem::transmute(addr) + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/raw_vec.rs b/deps/crates/vendor/allocator-api2/src/stable/raw_vec.rs new file mode 100644 index 00000000000000..938c28b0c0034d --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/raw_vec.rs @@ -0,0 +1,642 @@ +use core::alloc::LayoutError; +use core::mem::{self, ManuallyDrop, MaybeUninit}; +use core::ops::Drop; +use core::ptr::{self, NonNull}; +use core::slice; +use core::{cmp, fmt}; + +use super::{ + alloc::{Allocator, Global, Layout}, + assume, + boxed::Box, +}; + +#[cfg(not(no_global_oom_handling))] +use super::alloc::handle_alloc_error; + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct TryReserveError { + kind: TryReserveErrorKind, +} + +impl TryReserveError { + /// Details about the allocation that caused the error + pub fn kind(&self) -> TryReserveErrorKind { + self.kind.clone() + } +} + +/// Details of the allocation that caused a `TryReserveError` +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveErrorKind { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of allocation request that failed + layout: Layout, + + #[doc(hidden)] + non_exhaustive: (), + }, +} + +use TryReserveErrorKind::*; + +impl From for TryReserveError { + #[inline(always)] + fn from(kind: TryReserveErrorKind) -> Self { + Self { kind } + } +} + +impl From for TryReserveErrorKind { + /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. + #[inline(always)] + fn from(_: LayoutError) -> Self { + TryReserveErrorKind::CapacityOverflow + } +} + +impl fmt::Display for TryReserveError { + fn fmt( + &self, + fmt: &mut core::fmt::Formatter<'_>, + ) -> core::result::Result<(), core::fmt::Error> { + fmt.write_str("memory allocation failed")?; + let reason = match self.kind { + TryReserveErrorKind::CapacityOverflow => { + " because the computed capacity exceeded the collection's maximum" + } + TryReserveErrorKind::AllocError { .. } => { + " because the memory allocator returned an error" + } + }; + fmt.write_str(reason) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TryReserveError {} + +#[cfg(not(no_global_oom_handling))] +enum AllocInit { + /// The contents of the new memory are uninitialized. + Uninitialized, + /// The new memory is guaranteed to be zeroed. + Zeroed, +} + +/// A low-level utility for more ergonomically allocating, reallocating, and deallocating +/// a buffer of memory on the heap without having to worry about all the corner cases +/// involved. This type is excellent for building your own data structures like Vec and VecDeque. +/// In particular: +/// +/// * Produces `NonNull::dangling()` on zero-sized types. +/// * Produces `NonNull::dangling()` on zero-length allocations. +/// * Avoids freeing `NonNull::dangling()`. +/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). +/// * Guards against 32-bit systems allocating more than isize::MAX bytes. +/// * Guards against overflowing your length. +/// * Calls `handle_alloc_error` for fallible allocations. +/// * Contains a `ptr::NonNull` and thus endows the user with all related benefits. +/// * Uses the excess returned from the allocator to use the largest available capacity. +/// +/// This type does not in anyway inspect the memory that it manages. When dropped it *will* +/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` +/// to handle the actual things *stored* inside of a `RawVec`. +/// +/// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns +/// `usize::MAX`. This means that you need to be careful when round-tripping this type with a +/// `Box<[T]>`, since `capacity()` won't yield the length. +#[allow(missing_debug_implementations)] +pub(crate) struct RawVec { + ptr: NonNull, + cap: usize, + alloc: A, +} + +// Safety: RawVec owns both T and A, so sending is safe if +// sending is safe for T and A. +unsafe impl Send for RawVec +where + T: Send, + A: Send, +{ +} + +// Safety: RawVec owns both T and A, so sharing is safe if +// sharing is safe for T and A. +unsafe impl Sync for RawVec +where + T: Sync, + A: Sync, +{ +} + +impl RawVec { + /// Creates the biggest possible `RawVec` (on the system heap) + /// without allocating. If `T` has positive size, then this makes a + /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a + /// `RawVec` with capacity `usize::MAX`. Useful for implementing + /// delayed allocation. + #[must_use] + pub const fn new() -> Self { + Self::new_in(Global) + } + + /// Creates a `RawVec` (on the system heap) with exactly the + /// capacity and alignment requirements for a `[T; capacity]`. This is + /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is + /// zero-sized. Note that if `T` is zero-sized this means you will + /// *not* get a `RawVec` with the requested capacity. + /// + /// # Panics + /// + /// Panics if the requested capacity exceeds `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } + + /// Like `with_capacity`, but guarantees the buffer is zeroed. + #[cfg(not(no_global_oom_handling))] + #[must_use] + #[inline(always)] + pub fn with_capacity_zeroed(capacity: usize) -> Self { + Self::with_capacity_zeroed_in(capacity, Global) + } +} + +impl RawVec { + // Tiny Vecs are dumb. Skip to: + // - 8 if the element size is 1, because any heap allocators is likely + // to round up a request of less than 8 bytes to at least 8 bytes. + // - 4 if elements are moderate-sized (<= 1 KiB). + // - 1 otherwise, to avoid wasting too much space for very short Vecs. + pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::() == 1 { + 8 + } else if mem::size_of::() <= 1024 { + 4 + } else { + 1 + }; + + /// Like `new`, but parameterized over the choice of allocator for + /// the returned `RawVec`. + #[inline(always)] + pub const fn new_in(alloc: A) -> Self { + // `cap: 0` means "unallocated". zero-sized types are ignored. + Self { + ptr: NonNull::dangling(), + cap: 0, + alloc, + } + } + + /// Like `with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) + } + + /// Like `with_capacity_zeroed`, but parameterized over the choice + /// of allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { + Self::allocate_in(capacity, AllocInit::Zeroed, alloc) + } + + /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (See description of type for details.) + /// + /// # Safety + /// + /// * `len` must be greater than or equal to the most recently requested capacity, and + /// * `len` must be less than or equal to `self.capacity()`. + /// + /// Note, that the requested capacity and `self.capacity()` could differ, as + /// an allocator could overallocate and return a greater memory block than requested. + #[inline(always)] + pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { + // Sanity-check one half of the safety requirement (we cannot check the other half). + debug_assert!( + len <= self.capacity(), + "`len` must be smaller than or equal to `self.capacity()`" + ); + + let me = ManuallyDrop::new(self); + unsafe { + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + Box::<[MaybeUninit], A>::from_raw_in(slice, ptr::read(&me.alloc)) + } + } + + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { + // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if mem::size_of::() == 0 || capacity == 0 { + Self::new_in(alloc) + } else { + // We avoid `unwrap_or_else` here because it bloats the amount of + // LLVM IR generated. + let layout = match Layout::array::(capacity) { + Ok(layout) => layout, + Err(_) => capacity_overflow(), + }; + match alloc_guard(layout.size()) { + Ok(_) => {} + Err(_) => capacity_overflow(), + } + let result = match init { + AllocInit::Uninitialized => alloc.allocate(layout), + AllocInit::Zeroed => alloc.allocate_zeroed(layout), + }; + let ptr = match result { + Ok(ptr) => ptr, + Err(_) => handle_alloc_error(layout), + }; + + // Allocators currently return a `NonNull<[u8]>` whose length + // matches the size requested. If that ever changes, the capacity + // here should change to `ptr.len() / mem::size_of::()`. + Self { + ptr: unsafe { NonNull::new_unchecked(ptr.cast().as_ptr()) }, + cap: capacity, + alloc, + } + } + } + + /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. + /// + /// # Safety + /// + /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given + /// `capacity`. + /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit + /// systems). ZST vectors may have a capacity up to `usize::MAX`. + /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is + /// guaranteed. + #[inline(always)] + pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { + Self { + ptr: unsafe { NonNull::new_unchecked(ptr) }, + cap: capacity, + alloc, + } + } + + /// Gets a raw pointer to the start of the allocation. Note that this is + /// `NonNull::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must + /// be careful. + #[inline(always)] + pub fn ptr(&self) -> *mut T { + self.ptr.as_ptr() + } + + /// Gets the capacity of the allocation. + /// + /// This will always be `usize::MAX` if `T` is zero-sized. + #[inline(always)] + pub fn capacity(&self) -> usize { + if mem::size_of::() == 0 { + usize::MAX + } else { + self.cap + } + } + + /// Returns a shared reference to the allocator backing this `RawVec`. + #[inline(always)] + pub fn allocator(&self) -> &A { + &self.alloc + } + + #[inline(always)] + fn current_memory(&self) -> Option<(NonNull, Layout)> { + if mem::size_of::() == 0 || self.cap == 0 { + None + } else { + // We have an allocated chunk of memory, so we can bypass runtime + // checks to get our current layout. + unsafe { + let layout = Layout::array::(self.cap).unwrap_unchecked(); + Some((self.ptr.cast(), layout)) + } + } + } + + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already have enough capacity, will + /// reallocate enough space plus comfortable slack space to get amortized + /// *O*(1) behavior. Will limit this behavior if it would needlessly cause + /// itself to panic. + /// + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// This is ideal for implementing a bulk-push operation like `extend`. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn reserve(&mut self, len: usize, additional: usize) { + // Callers expect this function to be very cheap when there is already sufficient capacity. + // Therefore, we move all the resizing and error-handling logic from grow_amortized and + // handle_reserve behind a call, while making sure that this function is likely to be + // inlined as just a comparison and a call if the comparison fails. + #[cold] + #[inline(always)] + fn do_reserve_and_handle( + slf: &mut RawVec, + len: usize, + additional: usize, + ) { + handle_reserve(slf.grow_amortized(len, additional)); + } + + if self.needs_to_grow(len, additional) { + do_reserve_and_handle(self, len, additional); + } + } + + /// A specialized version of `reserve()` used only by the hot and + /// oft-instantiated `Vec::push()`, which does its own capacity check. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn reserve_for_push(&mut self, len: usize) { + handle_reserve(self.grow_amortized(len, 1)); + } + + /// The same as `reserve`, but returns on errors instead of panicking or aborting. + #[inline(always)] + pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + if self.needs_to_grow(len, additional) { + self.grow_amortized(len, additional) + } else { + Ok(()) + } + } + + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already, will reallocate the + /// minimum possible amount of memory necessary. Generally this will be + /// exactly the amount of memory necessary, but in principle the allocator + /// is free to give back more than we asked for. + /// + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe code + /// *you* write that relies on the behavior of this function may break. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn reserve_exact(&mut self, len: usize, additional: usize) { + handle_reserve(self.try_reserve_exact(len, additional)); + } + + /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. + #[inline(always)] + pub fn try_reserve_exact( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TryReserveError> { + if self.needs_to_grow(len, additional) { + self.grow_exact(len, additional) + } else { + Ok(()) + } + } + + /// Shrinks the buffer down to the specified capacity. If the given amount + /// is 0, actually completely deallocates. + /// + /// # Panics + /// + /// Panics if the given amount is *larger* than the current capacity. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn shrink_to_fit(&mut self, cap: usize) { + handle_reserve(self.shrink(cap)); + } +} + +impl RawVec { + /// Returns if the buffer needs to grow to fulfill the needed extra capacity. + /// Mainly used to make inlining reserve-calls possible without inlining `grow`. + #[inline(always)] + fn needs_to_grow(&self, len: usize, additional: usize) -> bool { + additional > self.capacity().wrapping_sub(len) + } + + #[inline(always)] + fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { + // Allocators currently return a `NonNull<[u8]>` whose length matches + // the size requested. If that ever changes, the capacity here should + // change to `ptr.len() / mem::size_of::()`. + self.ptr = unsafe { NonNull::new_unchecked(ptr.cast().as_ptr()) }; + self.cap = cap; + } + + // This method is usually instantiated many times. So we want it to be as + // small as possible, to improve compile times. But we also want as much of + // its contents to be statically computable as possible, to make the + // generated code run faster. Therefore, this method is carefully written + // so that all of the code that depends on `T` is within it, while as much + // of the code that doesn't depend on `T` as possible is in functions that + // are non-generic over `T`. + #[inline(always)] + fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + // This is ensured by the calling contexts. + debug_assert!(additional > 0); + + if mem::size_of::() == 0 { + // Since we return a capacity of `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + // Nothing we can really do about these checks, sadly. + let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + + // This guarantees exponential growth. The doubling cannot overflow + // because `cap <= isize::MAX` and the type of `cap` is `usize`. + let cap = cmp::max(self.cap * 2, required_cap); + let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap); + + let new_layout = Layout::array::(cap); + + // `finish_grow` is non-generic over `T`. + let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + self.set_ptr_and_cap(ptr, cap); + Ok(()) + } + + // The constraints on this method are much the same as those on + // `grow_amortized`, but this method is usually instantiated less often so + // it's less critical. + #[inline(always)] + fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + if mem::size_of::() == 0 { + // Since we return a capacity of `usize::MAX` when the type size is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(cap); + + // `finish_grow` is non-generic over `T`. + let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + self.set_ptr_and_cap(ptr, cap); + Ok(()) + } + + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { + assert!( + cap <= self.capacity(), + "Tried to shrink to a larger capacity" + ); + + let (ptr, layout) = if let Some(mem) = self.current_memory() { + mem + } else { + return Ok(()); + }; + + let ptr = unsafe { + // `Layout::array` cannot overflow here because it would have + // overflowed earlier when capacity was larger. + let new_layout = Layout::array::(cap).unwrap_unchecked(); + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { + layout: new_layout, + non_exhaustive: (), + })? + }; + self.set_ptr_and_cap(ptr, cap); + Ok(()) + } +} + +// This function is outside `RawVec` to minimize compile times. See the comment +// above `RawVec::grow_amortized` for details. (The `A` parameter isn't +// significant, because the number of different `A` types seen in practice is +// much smaller than the number of `T` types.) +#[inline(always)] +fn finish_grow( + new_layout: Result, + current_memory: Option<(NonNull, Layout)>, + alloc: &mut A, +) -> Result, TryReserveError> +where + A: Allocator, +{ + // Check for the error here to minimize the size of `RawVec::grow_*`. + let new_layout = new_layout.map_err(|_| CapacityOverflow)?; + + alloc_guard(new_layout.size())?; + + let memory = if let Some((ptr, old_layout)) = current_memory { + debug_assert_eq!(old_layout.align(), new_layout.align()); + unsafe { + // The allocator checks for alignment equality + assume(old_layout.align() == new_layout.align()); + alloc.grow(ptr, old_layout, new_layout) + } + } else { + alloc.allocate(new_layout) + }; + + memory.map_err(|_| { + AllocError { + layout: new_layout, + non_exhaustive: (), + } + .into() + }) +} + +impl Drop for RawVec { + /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. + #[inline(always)] + fn drop(&mut self) { + if let Some((ptr, layout)) = self.current_memory() { + unsafe { self.alloc.deallocate(ptr, layout) } + } + } +} + +// Central function for reserve error handling. +#[cfg(not(no_global_oom_handling))] +#[inline(always)] +fn handle_reserve(result: Result<(), TryReserveError>) { + match result.map_err(|e| e.kind()) { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocError { layout, .. }) => handle_alloc_error(layout), + Ok(()) => { /* yay */ } + } +} + +// We need to guarantee the following: +// * We don't ever allocate `> isize::MAX` byte-size objects. +// * We don't overflow `usize::MAX` and actually allocate too little. +// +// On 64-bit we just need to check for overflow since trying to allocate +// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add +// an extra guard for this in case we're running on a platform which can use +// all 4GB in user-space, e.g., PAE or x32. + +#[inline(always)] +fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { + Err(CapacityOverflow.into()) + } else { + Ok(()) + } +} + +// One central function responsible for reporting capacity overflows. This'll +// ensure that the code generation related to these panics is minimal as there's +// only one location which panics rather than a bunch throughout the module. +#[cfg(not(no_global_oom_handling))] +fn capacity_overflow() -> ! { + panic!("capacity overflow"); +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/slice.rs b/deps/crates/vendor/allocator-api2/src/stable/slice.rs new file mode 100644 index 00000000000000..82b2d80d791335 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/slice.rs @@ -0,0 +1,171 @@ +use crate::{ + alloc::{Allocator, Global}, + vec::Vec, +}; + +/// Slice methods that use `Box` and `Vec` from this crate. +pub trait SliceExt { + /// Copies `self` into a new `Vec`. + /// + /// # Examples + /// + /// ``` + /// let s = [10, 40, 30]; + /// let x = s.to_vec(); + /// // Here, `s` and `x` can be modified independently. + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + fn to_vec(&self) -> Vec + where + T: Clone, + { + self.to_vec_in(Global) + } + + /// Copies `self` into a new `Vec` with an allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let s = [10, 40, 30]; + /// let x = s.to_vec_in(System); + /// // Here, `s` and `x` can be modified independently. + /// ``` + #[cfg(not(no_global_oom_handling))] + fn to_vec_in(&self, alloc: A) -> Vec + where + T: Clone; + + /// Creates a vector by copying a slice `n` times. + /// + /// # Panics + /// + /// This function will panic if the capacity would overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); + /// ``` + /// + /// A panic upon overflow: + /// + /// ```should_panic + /// // this will panic at runtime + /// b"0123456789abcdef".repeat(usize::MAX); + /// ``` + fn repeat(&self, n: usize) -> Vec + where + T: Copy; +} + +impl SliceExt for [T] { + #[cfg(not(no_global_oom_handling))] + #[inline] + fn to_vec_in(&self, alloc: A) -> Vec + where + T: Clone, + { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + + let mut vec = Vec::with_capacity_in(self.len(), alloc); + let mut guard = DropGuard { + vec: &mut vec, + num_init: 0, + }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in self.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(self.len()); + } + vec + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + fn repeat(&self, n: usize) -> Vec + where + T: Copy, + { + if n == 0 { + return Vec::new(); + } + + // If `n` is larger than zero, it can be split as + // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. + // `2^expn` is the number represented by the leftmost '1' bit of `n`, + // and `rem` is the remaining part of `n`. + + // Using `Vec` to access `set_len()`. + let capacity = self.len().checked_mul(n).expect("capacity overflow"); + let mut buf = Vec::with_capacity(capacity); + + // `2^expn` repetition is done by doubling `buf` `expn`-times. + buf.extend(self); + { + let mut m = n >> 1; + // If `m > 0`, there are remaining bits up to the leftmost '1'. + while m > 0 { + // `buf.extend(buf)`: + unsafe { + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut T).add(buf.len()), + buf.len(), + ); + // `buf` has capacity of `self.len() * n`. + let buf_len = buf.len(); + buf.set_len(buf_len * 2); + } + + m >>= 1; + } + } + + // `rem` (`= n - 2^expn`) repetition is done by copying + // first `rem` repetitions from `buf` itself. + let rem_len = capacity - buf.len(); // `self.len() * rem` + if rem_len > 0 { + // `buf.extend(buf[0 .. rem_len])`: + unsafe { + // This is non-overlapping since `2^expn > rem`. + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut T).add(buf.len()), + rem_len, + ); + // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). + buf.set_len(capacity); + } + } + buf + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/unique.rs b/deps/crates/vendor/allocator-api2/src/stable/unique.rs new file mode 100644 index 00000000000000..6768a3d9b56239 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/unique.rs @@ -0,0 +1,106 @@ +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor +/// of this wrapper owns the referent. Useful for building abstractions like +/// `Box`, `Vec`, `String`, and `HashMap`. +/// +/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies +/// the kind of strong aliasing guarantees an instance of `T` can expect: +/// the referent of the pointer should not be modified without a unique path to +/// its owning Unique. +/// +/// If you're uncertain of whether it's correct to use `Unique` for your purposes, +/// consider using `NonNull`, which has weaker semantics. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Unique`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct +/// for any type which upholds Unique's aliasing requirements. +#[repr(transparent)] +pub(crate) struct Unique { + pointer: NonNull, + _marker: PhantomData, +} + +/// `Unique` pointers are `Send` if `T` is `Send` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Send for Unique {} + +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Sync for Unique {} + +impl Unique { + /// Creates a new `Unique`. + /// + /// # Safety + /// + /// `ptr` must be non-null. + #[inline] + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + // SAFETY: the caller must guarantee that `ptr` is non-null. + unsafe { + Unique { + pointer: NonNull::new_unchecked(ptr), + _marker: PhantomData, + } + } + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_ptr(self) -> *mut T { + self.pointer.as_ptr() + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_non_null_ptr(self) -> NonNull { + self.pointer + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + #[must_use] + #[inline] + pub const unsafe fn as_ref(&self) -> &T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a reference. + unsafe { &*(self.as_ptr() as *const T) } + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + #[must_use] + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a mutable reference. + unsafe { self.pointer.as_mut() } + } +} + +impl Clone for Unique { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Unique {} + +use core::{marker::PhantomData, ptr::NonNull}; diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/drain.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/drain.rs new file mode 100644 index 00000000000000..d3b962f7398e24 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/drain.rs @@ -0,0 +1,242 @@ +use core::fmt; +use core::iter::FusedIterator; +use core::mem::{self, size_of, ManuallyDrop}; +use core::ptr::{self, NonNull}; +use core::slice::{self}; + +use crate::stable::alloc::{Allocator, Global}; + +use super::Vec; + +/// A draining iterator for `Vec`. +/// +/// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::Drain<_> = v.drain(..); +/// ``` +pub struct Drain<'a, T: 'a, A: Allocator + 'a = Global> { + /// Index of tail to preserve + pub(super) tail_start: usize, + /// Length of tail + pub(super) tail_len: usize, + /// Current remaining range to remove + pub(super) iter: slice::Iter<'a, T>, + pub(super) vec: NonNull>, +} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() + } +} + +impl<'a, T, A: Allocator> Drain<'a, T, A> { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain(..); + /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_slice(), &['b', 'c']); + /// ``` + #[must_use] + #[inline(always)] + pub fn as_slice(&self) -> &[T] { + self.iter.as_slice() + } + + /// Returns a reference to the underlying allocator. + #[must_use] + #[inline(always)] + pub fn allocator(&self) -> &A { + unsafe { self.vec.as_ref().allocator() } + } + + /// Keep unyielded elements in the source `Vec`. + /// + /// # Examples + /// + /// ``` + /// #![feature(drain_keep_rest)] + /// + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain(..); + /// + /// assert_eq!(drain.next().unwrap(), 'a'); + /// + /// // This call keeps 'b' and 'c' in the vec. + /// drain.keep_rest(); + /// + /// // If we wouldn't call `keep_rest()`, + /// // `vec` would be empty. + /// assert_eq!(vec, ['b', 'c']); + /// ``` + #[inline(always)] + pub fn keep_rest(self) { + // At this moment layout looks like this: + // + // [head] [yielded by next] [unyielded] [yielded by next_back] [tail] + // ^-- start \_________/-- unyielded_len \____/-- self.tail_len + // ^-- unyielded_ptr ^-- tail + // + // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`. + // Here we want to + // 1. Move [unyielded] to `start` + // 2. Move [tail] to a new start at `start + len(unyielded)` + // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)` + // a. In case of ZST, this is the only thing we want to do + // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do + let mut this = ManuallyDrop::new(self); + + unsafe { + let source_vec = this.vec.as_mut(); + + let start = source_vec.len(); + let tail = this.tail_start; + + let unyielded_len = this.iter.len(); + let unyielded_ptr = this.iter.as_slice().as_ptr(); + + // ZSTs have no identity, so we don't need to move them around. + let needs_move = mem::size_of::() != 0; + + if needs_move { + let start_ptr = source_vec.as_mut_ptr().add(start); + + // memmove back unyielded elements + if unyielded_ptr != start_ptr { + let src = unyielded_ptr; + let dst = start_ptr; + + ptr::copy(src, dst, unyielded_len); + } + + // memmove back untouched tail + if tail != (start + unyielded_len) { + let src = source_vec.as_ptr().add(tail); + let dst = start_ptr.add(unyielded_len); + ptr::copy(src, dst, this.tail_len); + } + } + + source_vec.set_len(start + unyielded_len + this.tail_len); + } + } +} + +impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { + #[inline(always)] + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +unsafe impl Sync for Drain<'_, T, A> {} + +unsafe impl Send for Drain<'_, T, A> {} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option { + self.iter + .next() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for Drain<'_, T, A> { + #[inline(always)] + fn next_back(&mut self) -> Option { + self.iter + .next_back() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } +} + +impl Drop for Drain<'_, T, A> { + #[inline] + fn drop(&mut self) { + /// Moves back the un-`Drain`ed elements to restore the original `Vec`. + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); + + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { + fn drop(&mut self) { + if self.0.tail_len > 0 { + unsafe { + let source_vec = self.0.vec.as_mut(); + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.0.tail_start; + if tail != start { + let src = source_vec.as_ptr().add(tail); + let dst = source_vec.as_mut_ptr().add(start); + ptr::copy(src, dst, self.0.tail_len); + } + source_vec.set_len(start + self.0.tail_len); + } + } + } + } + + let iter = mem::replace(&mut self.iter, [].iter()); + let drop_len = iter.len(); + + let mut vec = self.vec; + + if size_of::() == 0 { + // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. + // this can be achieved by manipulating the Vec length instead of moving values out from `iter`. + unsafe { + let vec = vec.as_mut(); + let old_len = vec.len(); + vec.set_len(old_len + drop_len + self.tail_len); + vec.truncate(old_len + self.tail_len); + } + + return; + } + + // ensure elements are moved back into their appropriate places, even when drop_in_place panics + let _guard = DropGuard(self); + + if drop_len == 0 { + return; + } + + // as_slice() must only be called when iter.len() is > 0 because + // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate + // the iterator's internal pointers. Creating a reference to deallocated memory + // is invalid even when it is zero-length + let drop_ptr = iter.as_slice().as_ptr(); + + unsafe { + // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place + // a pointer with mutable provenance is necessary. Therefore we must reconstruct + // it from the original vec but also avoid creating a &mut to the front since that could + // invalidate raw pointers to it which some unsafe code might rely on. + let vec_ptr = vec.as_mut().as_mut_ptr(); + let drop_offset = drop_ptr.offset_from(vec_ptr) as usize; + let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); + ptr::drop_in_place(to_drop); + } + } +} + +impl ExactSizeIterator for Drain<'_, T, A> {} + +impl FusedIterator for Drain<'_, T, A> {} diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/into_iter.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/into_iter.rs new file mode 100644 index 00000000000000..653ccdbf8b26b6 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/into_iter.rs @@ -0,0 +1,191 @@ +use core::fmt; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem::{self, size_of, ManuallyDrop}; + +use core::ptr::{self, NonNull}; +use core::slice::{self}; + +use crate::stable::addr; + +use super::{Allocator, Global, RawVec}; + +#[cfg(not(no_global_oom_handling))] +use super::Vec; + +/// An iterator that moves out of a vector. +/// +/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) +/// (provided by the [`IntoIterator`] trait). +/// +/// # Example +/// +/// ``` +/// let v = vec![0, 1, 2]; +/// let iter: std::vec::IntoIter<_> = v.into_iter(); +/// ``` +pub struct IntoIter { + pub(super) buf: NonNull, + pub(super) phantom: PhantomData, + pub(super) cap: usize, + // the drop impl reconstructs a RawVec from buf, cap and alloc + // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop + pub(super) alloc: ManuallyDrop, + pub(super) ptr: *const T, + pub(super) end: *const T, +} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +impl IntoIter { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// let _ = into_iter.next().unwrap(); + /// assert_eq!(into_iter.as_slice(), &['b', 'c']); + /// ``` + pub fn as_slice(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.ptr, self.len()) } + } + + /// Returns the remaining items of this iterator as a mutable slice. + /// + /// # Examples + /// + /// ``` + /// let vec = vec!['a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// into_iter.as_mut_slice()[2] = 'z'; + /// assert_eq!(into_iter.next().unwrap(), 'a'); + /// assert_eq!(into_iter.next().unwrap(), 'b'); + /// assert_eq!(into_iter.next().unwrap(), 'z'); + /// ``` + pub fn as_mut_slice(&mut self) -> &mut [T] { + unsafe { &mut *self.as_raw_mut_slice() } + } + + /// Returns a reference to the underlying allocator. + #[inline(always)] + pub fn allocator(&self) -> &A { + &self.alloc + } + + fn as_raw_mut_slice(&mut self) -> *mut [T] { + ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) + } +} + +impl AsRef<[T]> for IntoIter { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +unsafe impl Send for IntoIter {} + +unsafe impl Sync for IntoIter {} + +impl Iterator for IntoIter { + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option { + if self.ptr == self.end { + None + } else if size_of::() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = self.ptr.cast::().wrapping_add(1).cast(); + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + let old = self.ptr; + self.ptr = unsafe { self.ptr.add(1) }; + + Some(unsafe { ptr::read(old) }) + } + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + let exact = if size_of::() == 0 { + addr(self.end).wrapping_sub(addr(self.ptr)) + } else { + unsafe { self.end.offset_from(self.ptr) as usize } + }; + (exact, Some(exact)) + } + + #[inline(always)] + fn count(self) -> usize { + self.len() + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline(always)] + fn next_back(&mut self) -> Option { + if self.end == self.ptr { + None + } else if size_of::() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = self.end.cast::().wrapping_add(1).cast(); + + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + self.end = unsafe { self.end.sub(1) }; + + Some(unsafe { ptr::read(self.end) }) + } + } +} + +impl ExactSizeIterator for IntoIter {} + +impl FusedIterator for IntoIter {} + +#[cfg(not(no_global_oom_handling))] +impl Clone for IntoIter { + fn clone(&self) -> Self { + let mut vec = Vec::::with_capacity_in(self.len(), (*self.alloc).clone()); + vec.extend(self.as_slice().iter().cloned()); + vec.into_iter() + } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); + + impl Drop for DropGuard<'_, T, A> { + fn drop(&mut self) { + unsafe { + // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec + let alloc = ManuallyDrop::take(&mut self.0.alloc); + // RawVec handles deallocation + let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); + } + } + } + + let guard = DropGuard(self); + // destroy the remaining elements + unsafe { + ptr::drop_in_place(guard.0.as_raw_mut_slice()); + } + // now `guard` will be dropped and do the rest + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/mod.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/mod.rs new file mode 100644 index 00000000000000..0366e5e8882d9c --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/mod.rs @@ -0,0 +1,3232 @@ +//! A contiguous growable array type with heap-allocated contents, written +//! `Vec`. +//! +//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and +//! *O*(1) pop (from the end). +//! +//! Vectors ensure they never allocate more than `isize::MAX` bytes. +//! +//! # Examples +//! +//! You can explicitly create a [`Vec`] with [`Vec::new`]: +//! +//! ``` +//! let v: Vec = Vec::new(); +//! ``` +//! +//! ...or by using the [`vec!`] macro: +//! +//! ``` +//! let v: Vec = vec![]; +//! +//! let v = vec![1, 2, 3, 4, 5]; +//! +//! let v = vec![0; 10]; // ten zeroes +//! ``` +//! +//! You can [`push`] values onto the end of a vector (which will grow the vector +//! as needed): +//! +//! ``` +//! let mut v = vec![1, 2]; +//! +//! v.push(3); +//! ``` +//! +//! Popping values works in much the same way: +//! +//! ``` +//! let mut v = vec![1, 2]; +//! +//! let two = v.pop(); +//! ``` +//! +//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits): +//! +//! ``` +//! let mut v = vec![1, 2, 3]; +//! let three = v[2]; +//! v[1] = v[1] + 5; +//! ``` +//! +//! [`push`]: Vec::push + +#[cfg(not(no_global_oom_handling))] +use core::cmp; +use core::cmp::Ordering; +use core::convert::TryFrom; +use core::fmt; +use core::hash::{Hash, Hasher}; +#[cfg(not(no_global_oom_handling))] +use core::iter; +#[cfg(not(no_global_oom_handling))] +use core::iter::FromIterator; +use core::marker::PhantomData; +use core::mem::{self, size_of, ManuallyDrop, MaybeUninit}; +use core::ops::{self, Bound, Index, IndexMut, RangeBounds}; +use core::ptr::{self, NonNull}; +use core::slice::{self, SliceIndex}; + +#[cfg(feature = "std")] +use std::io; + +use super::{ + alloc::{Allocator, Global}, + assume, + boxed::Box, + raw_vec::{RawVec, TryReserveError}, +}; + +#[cfg(not(no_global_oom_handling))] +pub use self::splice::Splice; + +#[cfg(not(no_global_oom_handling))] +mod splice; + +pub use self::drain::Drain; + +mod drain; + +pub use self::into_iter::IntoIter; + +mod into_iter; + +mod partial_eq; + +#[cfg(not(no_global_oom_handling))] +mod set_len_on_drop; + +#[cfg(not(no_global_oom_handling))] +use self::set_len_on_drop::SetLenOnDrop; + +/// A contiguous growable array type, written as `Vec`, short for 'vector'. +/// +/// # Examples +/// +/// ``` +/// let mut vec = Vec::new(); +/// vec.push(1); +/// vec.push(2); +/// +/// assert_eq!(vec.len(), 2); +/// assert_eq!(vec[0], 1); +/// +/// assert_eq!(vec.pop(), Some(2)); +/// assert_eq!(vec.len(), 1); +/// +/// vec[0] = 7; +/// assert_eq!(vec[0], 7); +/// +/// vec.extend([1, 2, 3].iter().copied()); +/// +/// for x in &vec { +/// println!("{x}"); +/// } +/// assert_eq!(vec, [7, 1, 2, 3]); +/// ``` +/// +/// The [`vec!`] macro is provided for convenient initialization: +/// +/// ``` +/// let mut vec1 = vec![1, 2, 3]; +/// vec1.push(4); +/// let vec2 = Vec::from([1, 2, 3, 4]); +/// assert_eq!(vec1, vec2); +/// ``` +/// +/// It can also initialize each element of a `Vec` with a given value. +/// This may be more efficient than performing allocation and initialization +/// in separate steps, especially when initializing a vector of zeros: +/// +/// ``` +/// let vec = vec![0; 5]; +/// assert_eq!(vec, [0, 0, 0, 0, 0]); +/// +/// // The following is equivalent, but potentially slower: +/// let mut vec = Vec::with_capacity(5); +/// vec.resize(5, 0); +/// assert_eq!(vec, [0, 0, 0, 0, 0]); +/// ``` +/// +/// For more information, see +/// [Capacity and Reallocation](#capacity-and-reallocation). +/// +/// Use a `Vec` as an efficient stack: +/// +/// ``` +/// let mut stack = Vec::new(); +/// +/// stack.push(1); +/// stack.push(2); +/// stack.push(3); +/// +/// while let Some(top) = stack.pop() { +/// // Prints 3, 2, 1 +/// println!("{top}"); +/// } +/// ``` +/// +/// # Indexing +/// +/// The `Vec` type allows to access values by index, because it implements the +/// [`Index`] trait. An example will be more explicit: +/// +/// ``` +/// let v = vec![0, 2, 4, 6]; +/// println!("{}", v[1]); // it will display '2' +/// ``` +/// +/// However be careful: if you try to access an index which isn't in the `Vec`, +/// your software will panic! You cannot do this: +/// +/// ```should_panic +/// let v = vec![0, 2, 4, 6]; +/// println!("{}", v[6]); // it will panic! +/// ``` +/// +/// Use [`get`] and [`get_mut`] if you want to check whether the index is in +/// the `Vec`. +/// +/// # Slicing +/// +/// A `Vec` can be mutable. On the other hand, slices are read-only objects. +/// To get a [slice][prim@slice], use [`&`]. Example: +/// +/// ``` +/// fn read_slice(slice: &[usize]) { +/// // ... +/// } +/// +/// let v = vec![0, 1]; +/// read_slice(&v); +/// +/// // ... and that's all! +/// // you can also do it like this: +/// let u: &[usize] = &v; +/// // or like this: +/// let u: &[_] = &v; +/// ``` +/// +/// In Rust, it's more common to pass slices as arguments rather than vectors +/// when you just want to provide read access. The same goes for [`String`] and +/// [`&str`]. +/// +/// # Capacity and reallocation +/// +/// The capacity of a vector is the amount of space allocated for any future +/// elements that will be added onto the vector. This is not to be confused with +/// the *length* of a vector, which specifies the number of actual elements +/// within the vector. If a vector's length exceeds its capacity, its capacity +/// will automatically be increased, but its elements will have to be +/// reallocated. +/// +/// For example, a vector with capacity 10 and length 0 would be an empty vector +/// with space for 10 more elements. Pushing 10 or fewer elements onto the +/// vector will not change its capacity or cause reallocation to occur. However, +/// if the vector's length is increased to 11, it will have to reallocate, which +/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`] +/// whenever possible to specify how big the vector is expected to get. +/// +/// # Guarantees +/// +/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees +/// about its design. This ensures that it's as low-overhead as possible in +/// the general case, and can be correctly manipulated in primitive ways +/// by unsafe code. Note that these guarantees refer to an unqualified `Vec`. +/// If additional type parameters are added (e.g., to support custom allocators), +/// overriding their defaults may change the behavior. +/// +/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length) +/// triplet. No more, no less. The order of these fields is completely +/// unspecified, and you should use the appropriate methods to modify these. +/// The pointer will never be null, so this type is null-pointer-optimized. +/// +/// However, the pointer might not actually point to allocated memory. In particular, +/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`], +/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`] +/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized +/// types inside a `Vec`, it will not allocate space for them. *Note that in this case +/// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only +/// if [mem::size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation +/// details are very subtle --- if you intend to allocate memory using a `Vec` +/// and use it for something else (either to pass to unsafe code, or to build your +/// own memory-backed collection), be sure to deallocate this memory by using +/// `from_raw_parts` to recover the `Vec` and then dropping it. +/// +/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap +/// (as defined by the allocator Rust is configured to use by default), and its +/// pointer points to [`len`] initialized, contiguous elements in order (what +/// you would see if you coerced it to a slice), followed by [capacity] - [len] +/// logically uninitialized, contiguous elements. +/// +/// A vector containing the elements `'a'` and `'b'` with capacity 4 can be +/// visualized as below. The top part is the `Vec` struct, it contains a +/// pointer to the head of the allocation in the heap, length and capacity. +/// The bottom part is the allocation on the heap, a contiguous memory block. +/// +/// ```text +/// ptr len capacity +/// +--------+--------+--------+ +/// | 0x0123 | 2 | 4 | +/// +--------+--------+--------+ +/// | +/// v +/// Heap +--------+--------+--------+--------+ +/// | 'a' | 'b' | uninit | uninit | +/// +--------+--------+--------+--------+ +/// ``` +/// +/// - **uninit** represents memory that is not initialized, see [`MaybeUninit`]. +/// - Note: the ABI is not stable and `Vec` makes no guarantees about its memory +/// layout (including the order of fields). +/// +/// `Vec` will never perform a "small optimization" where elements are actually +/// stored on the stack for two reasons: +/// +/// * It would make it more difficult for unsafe code to correctly manipulate +/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were +/// only moved, and it would be more difficult to determine if a `Vec` had +/// actually allocated memory. +/// +/// * It would penalize the general case, incurring an additional branch +/// on every access. +/// +/// `Vec` will never automatically shrink itself, even if completely empty. This +/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` +/// and then filling it back up to the same [`len`] should incur no calls to +/// the allocator. If you wish to free up unused memory, use +/// [`shrink_to_fit`] or [`shrink_to`]. +/// +/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is +/// sufficient. [`push`] and [`insert`] *will* (re)allocate if +/// [len] == [capacity]. That is, the reported capacity is completely +/// accurate, and can be relied on. It can even be used to manually free the memory +/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even +/// when not necessary. +/// +/// `Vec` does not guarantee any particular growth strategy when reallocating +/// when full, nor when [`reserve`] is called. The current strategy is basic +/// and it may prove desirable to use a non-constant growth factor. Whatever +/// strategy is used will of course guarantee *O*(1) amortized [`push`]. +/// +/// `vec![x; n]`, `vec![a, b, c, d]`, and +/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` +/// with exactly the requested capacity. If [len] == [capacity], +/// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to +/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. +/// +/// `Vec` will not specifically overwrite any data that is removed from it, +/// but also won't specifically preserve it. Its uninitialized memory is +/// scratch space that it may use however it wants. It will generally just do +/// whatever is most efficient or otherwise easy to implement. Do not rely on +/// removed data to be erased for security purposes. Even if you drop a `Vec`, its +/// buffer may simply be reused by another allocation. Even if you zero a `Vec`'s memory +/// first, that might not actually happen because the optimizer does not consider +/// this a side-effect that must be preserved. There is one case which we will +/// not break, however: using `unsafe` code to write to the excess capacity, +/// and then increasing the length to match, is always valid. +/// +/// Currently, `Vec` does not guarantee the order in which elements are dropped. +/// The order has changed in the past and may change again. +/// +/// [`get`]: ../../std/vec/struct.Vec.html#method.get +/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut +/// [`String`]: alloc_crate::string::String +/// [`&str`]: type@str +/// [`shrink_to_fit`]: Vec::shrink_to_fit +/// [`shrink_to`]: Vec::shrink_to +/// [capacity]: Vec::capacity +/// [`capacity`]: Vec::capacity +/// [mem::size_of::\]: core::mem::size_of +/// [len]: Vec::len +/// [`len`]: Vec::len +/// [`push`]: Vec::push +/// [`insert`]: Vec::insert +/// [`reserve`]: Vec::reserve +/// [`MaybeUninit`]: core::mem::MaybeUninit +/// [owned slice]: Box +pub struct Vec { + buf: RawVec, + len: usize, +} + +//////////////////////////////////////////////////////////////////////////////// +// Inherent methods +//////////////////////////////////////////////////////////////////////////////// + +impl Vec { + /// Constructs a new, empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// # #![allow(unused_mut)] + /// let mut vec: Vec = Vec::new(); + /// ``` + #[inline(always)] + #[must_use] + pub const fn new() -> Self { + Vec { + buf: RawVec::new(), + len: 0, + } + } + + /// Constructs a new, empty `Vec` with at least the specified capacity. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// minimum *capacity* specified, the vector will have a zero *length*. For + /// an explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// If it is important to know the exact allocated capacity of a `Vec`, + /// always use the [`capacity`] method after construction. + /// + /// For `Vec` where `T` is a zero-sized type, there will be no allocation + /// and the capacity will always be `usize::MAX`. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// [`capacity`]: Vec::capacity + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert!(vec.capacity() >= 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 10); + /// assert!(vec.capacity() >= 10); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// + /// // A vector of a zero-sized type will always over-allocate, since no + /// // allocation is necessary + /// let vec_units = Vec::<()>::with_capacity(10); + /// assert_eq!(vec_units.capacity(), usize::MAX); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + #[must_use] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } + + /// Creates a `Vec` directly from a pointer, a capacity, and a length. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `T` needs to have the same alignment as what `ptr` was allocated with. + /// (`T` having a less strict alignment is not sufficient, the alignment really + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be + /// allocated and deallocated with the same layout.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// to be the same size as the pointer was allocated with. (Because similar to + /// alignment, [`dealloc`] must be called with the same layout `size`.) + /// * `length` needs to be less than or equal to `capacity`. + /// * The first `length` values must be properly initialized values of type `T`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset). + /// + /// These requirements are always upheld by any `ptr` that has been allocated + /// via `Vec`. Other allocation sources are allowed if the invariants are + /// upheld. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is normally **not** safe + /// to build a `Vec` from a pointer to a C `char` array with length + /// `size_t`, doing so is only safe if the array was initially allocated by + /// a `Vec` or `String`. + /// It's also not safe to build one from a `Vec` and its length, because + /// the allocator cares about the alignment, and these two types have different + /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after + /// turning it into a `Vec` it'll be deallocated with alignment 1. To avoid + /// these issues, it is often preferable to do casting/transmuting using + /// [`slice::from_raw_parts`] instead. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: alloc_crate::string::String + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc + /// + /// # Examples + /// + /// ``` + /// use std::ptr; + /// use std::mem; + /// + /// let v = vec![1, 2, 3]; + /// + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); + /// + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// + /// unsafe { + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len { + /// ptr::write(p.add(i), 4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts(p, len, cap); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } + /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// #![feature(allocator_api)] + /// + /// use std::alloc::{AllocError, Allocator, Global, Layout}; + /// + /// fn main() { + /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// + /// let vec = unsafe { + /// let mem = match Global.allocate(layout) { + /// Ok(mem) => mem.cast::().as_ptr(), + /// Err(AllocError) => return, + /// }; + /// + /// mem.write(1_000_000); + /// + /// Vec::from_raw_parts_in(mem, 1, 16, Global) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` + #[inline(always)] + pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { + unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) } + } +} + +impl Vec { + /// Constructs a new, empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// use std::alloc::System; + /// + /// # #[allow(unused_mut)] + /// let mut vec: Vec = Vec::new_in(System); + /// ``` + #[inline(always)] + pub const fn new_in(alloc: A) -> Self { + Vec { + buf: RawVec::new_in(alloc), + len: 0, + } + } + + /// Constructs a new, empty `Vec` with at least the specified capacity + /// with the provided allocator. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// minimum *capacity* specified, the vector will have a zero *length*. For + /// an explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// If it is important to know the exact allocated capacity of a `Vec`, + /// always use the [`capacity`] method after construction. + /// + /// For `Vec` where `T` is a zero-sized type, there will be no allocation + /// and the capacity will always be `usize::MAX`. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// [`capacity`]: Vec::capacity + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// use std::alloc::System; + /// + /// let mut vec = Vec::with_capacity_in(10, System); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// + /// // A vector of a zero-sized type will always over-allocate, since no + /// // allocation is necessary + /// let vec_units = Vec::<(), System>::with_capacity_in(10, System); + /// assert_eq!(vec_units.capacity(), usize::MAX); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Vec { + buf: RawVec::with_capacity_in(capacity, alloc), + len: 0, + } + } + + /// Creates a `Vec` directly from a pointer, a capacity, a length, + /// and an allocator. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `T` needs to have the same alignment as what `ptr` was allocated with. + /// (`T` having a less strict alignment is not sufficient, the alignment really + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be + /// allocated and deallocated with the same layout.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// to be the same size as the pointer was allocated with. (Because similar to + /// alignment, [`dealloc`] must be called with the same layout `size`.) + /// * `length` needs to be less than or equal to `capacity`. + /// * The first `length` values must be properly initialized values of type `T`. + /// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset). + /// + /// These requirements are always upheld by any `ptr` that has been allocated + /// via `Vec`. Other allocation sources are allowed if the invariants are + /// upheld. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is **not** safe + /// to build a `Vec` from a pointer to a C `char` array with length `size_t`. + /// It's also not safe to build one from a `Vec` and its length, because + /// the allocator cares about the alignment, and these two types have different + /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after + /// turning it into a `Vec` it'll be deallocated with alignment 1. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: alloc_crate::string::String + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc + /// [*fit*]: crate::alloc::Allocator#memory-fitting + /// + /// # Examples + /// + /// ``` + /// use std::alloc::System; + /// + /// use std::ptr; + /// use std::mem; + /// + /// + /// # use allocator_api2::vec::Vec; + /// let mut v = Vec::with_capacity_in(3, System); + /// v.push(1); + /// v.push(2); + /// v.push(3); + /// + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); + /// + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// let alloc = v.allocator(); + /// + /// unsafe { + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len { + /// ptr::write(p.add(i), 4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone()); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } + /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// use std::alloc::{alloc, Layout}; + /// + /// fn main() { + /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// let vec = unsafe { + /// let mem = alloc(layout).cast::(); + /// if mem.is_null() { + /// return; + /// } + /// + /// mem.write(1_000_000); + /// + /// Vec::from_raw_parts(mem, 1, 16) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` + #[inline(always)] + pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + unsafe { + Vec { + buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), + len: length, + } + } + } + + /// Decomposes a `Vec` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: Vec::from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let v: Vec = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } + + /// Decomposes a `Vec` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of the vector (in elements), + /// the allocated capacity of the data (in elements), and the allocator. These are the same + /// arguments in the same order as the arguments to [`from_raw_parts_in`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts_in`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts_in`]: Vec::from_raw_parts_in + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, vec_into_raw_parts)] + /// + /// use std::alloc::System; + /// + /// let mut v: Vec = Vec::new_in(System); + /// v.push(-1); + /// v.push(0); + /// v.push(1); + /// + /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts_in(ptr, len, cap, alloc) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) { + let mut me = ManuallyDrop::new(self); + let len = me.len(); + let capacity = me.capacity(); + let ptr = me.as_mut_ptr(); + let alloc = unsafe { ptr::read(me.allocator()) }; + (ptr, len, capacity, alloc) + } + + /// Returns the total number of elements the vector can hold without + /// reallocating. + /// + /// # Examples + /// + /// ``` + /// let mut vec: Vec = Vec::with_capacity(10); + /// vec.push(42); + /// assert_eq!(vec.capacity(), 10); + /// ``` + #[inline(always)] + pub fn capacity(&self) -> usize { + self.buf.capacity() + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the given `Vec`. The collection may reserve more space to + /// speculatively avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1]; + /// vec.reserve(10); + /// assert!(vec.capacity() >= 11); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn reserve(&mut self, additional: usize) { + self.buf.reserve(self.len, additional); + } + + /// Reserves the minimum capacity for at least `additional` more elements to + /// be inserted in the given `Vec`. Unlike [`reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: Vec::reserve + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1]; + /// vec.reserve_exact(10); + /// assert!(vec.capacity() >= 11); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn reserve_exact(&mut self, additional: usize) { + self.buf.reserve_exact(self.len, additional); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `Vec`. The collection may reserve more space to speculatively avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional` if it returns + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use allocator_api2::collections::TryReserveError; + /// + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { + /// let mut output = Vec::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[inline(always)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.buf.try_reserve(self.len, additional) + } + + /// Tries to reserve the minimum capacity for at least `additional` + /// elements to be inserted in the given `Vec`. Unlike [`try_reserve`], + /// this will not deliberately over-allocate to speculatively avoid frequent + /// allocations. After calling `try_reserve_exact`, capacity will be greater + /// than or equal to `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: Vec::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use allocator_api2::collections::TryReserveError; + /// + /// fn process_data(data: &[u32]) -> Result, TryReserveError> { + /// let mut output = Vec::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve_exact(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[inline(always)] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.buf.try_reserve_exact(self.len, additional) + } + + /// Shrinks the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator + /// may still inform the vector that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// assert_eq!(vec.capacity(), 10); + /// vec.shrink_to_fit(); + /// assert!(vec.capacity() >= 3); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn shrink_to_fit(&mut self) { + // The capacity is never less than the length, and there's nothing to do when + // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit` + // by only calling it with a greater capacity. + if self.capacity() > self.len { + self.buf.shrink_to_fit(self.len); + } + } + + /// Shrinks the capacity of the vector with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// # Examples + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// assert_eq!(vec.capacity(), 10); + /// vec.shrink_to(4); + /// assert!(vec.capacity() >= 4); + /// vec.shrink_to(0); + /// assert!(vec.capacity() >= 3); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn shrink_to(&mut self, min_capacity: usize) { + if self.capacity() > min_capacity { + self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); + } + } + + /// Converts the vector into [`Box<[T]>`][owned slice]. + /// + /// If the vector has excess capacity, its items will be moved into a + /// newly-allocated buffer with exactly the right capacity. + /// + /// [owned slice]: Box + /// + /// # Examples + /// + /// ``` + /// let v = vec![1, 2, 3]; + /// + /// let slice = v.into_boxed_slice(); + /// ``` + /// + /// Any excess capacity is removed: + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// + /// assert_eq!(vec.capacity(), 10); + /// let slice = vec.into_boxed_slice(); + /// assert_eq!(slice.into_vec().capacity(), 3); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn into_boxed_slice(mut self) -> Box<[T], A> { + unsafe { + self.shrink_to_fit(); + let me = ManuallyDrop::new(self); + let buf = ptr::read(&me.buf); + let len = me.len(); + Box::<[mem::MaybeUninit], A>::assume_init(buf.into_box(len)) + } + } + + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. + /// + /// If `len` is greater than the vector's current length, this has no + /// effect. + /// + /// The [`drain`] method can emulate `truncate`, but causes the excess + /// elements to be returned instead of dropped. + /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// + /// # Examples + /// + /// Truncating a five element vector to two elements: + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4, 5]; + /// vec.truncate(2); + /// assert_eq!(vec, [1, 2]); + /// ``` + /// + /// No truncation occurs when `len` is greater than the vector's current + /// length: + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(8); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// Truncating when `len == 0` is equivalent to calling the [`clear`] + /// method. + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(0); + /// assert_eq!(vec, []); + /// ``` + /// + /// [`clear`]: Vec::clear + /// [`drain`]: Vec::drain + #[inline(always)] + pub fn truncate(&mut self, len: usize) { + // This is safe because: + // + // * the slice passed to `drop_in_place` is valid; the `len > self.len` + // case avoids creating an invalid slice, and + // * the `len` of the vector is shrunk before calling `drop_in_place`, + // such that no value will be dropped twice in case `drop_in_place` + // were to panic once (if it panics twice, the program aborts). + unsafe { + // Note: It's intentional that this is `>` and not `>=`. + // Changing it to `>=` has negative performance + // implications in some cases. See #78884 for more. + if len > self.len { + return; + } + let remaining_len = self.len - len; + let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); + self.len = len; + ptr::drop_in_place(s); + } + } + + /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// let buffer = vec![1, 2, 3, 5, 8]; + /// io::sink().write(buffer.as_slice()).unwrap(); + /// ``` + #[inline(always)] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Read}; + /// let mut buffer = vec![0; 3]; + /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); + /// ``` + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer + /// valid for zero sized reads if the vector didn't allocate. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// # Examples + /// + /// ``` + /// let x = vec![1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(*x_ptr.add(i), 1 << i); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: Vec::as_mut_ptr + #[inline(always)] + pub fn as_ptr(&self) -> *const T { + // We shadow the slice method of the same name to avoid going through + // `deref`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { + assume(!ptr.is_null()); + } + ptr + } + + /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling + /// raw pointer valid for zero sized reads if the vector didn't allocate. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// // Allocate vector big enough for 4 elements. + /// let size = 4; + /// let mut x: Vec = Vec::with_capacity(size); + /// let x_ptr = x.as_mut_ptr(); + /// + /// // Initialize elements via raw pointer writes, then set length. + /// unsafe { + /// for i in 0..size { + /// *x_ptr.add(i) = i as i32; + /// } + /// x.set_len(size); + /// } + /// assert_eq!(&*x, &[0, 1, 2, 3]); + /// ``` + #[inline(always)] + pub fn as_mut_ptr(&mut self) -> *mut T { + // We shadow the slice method of the same name to avoid going through + // `deref_mut`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { + assume(!ptr.is_null()); + } + ptr + } + + /// Returns a reference to the underlying allocator. + #[inline(always)] + pub fn allocator(&self) -> &A { + self.buf.allocator() + } + + /// Forces the length of the vector to `new_len`. + /// + /// This is a low-level operation that maintains none of the normal + /// invariants of the type. Normally changing the length of a vector + /// is done using one of the safe operations instead, such as + /// [`truncate`], [`resize`], [`extend`], or [`clear`]. + /// + /// [`truncate`]: Vec::truncate + /// [`resize`]: Vec::resize + /// [`extend`]: Extend::extend + /// [`clear`]: Vec::clear + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to [`capacity()`]. + /// - The elements at `old_len..new_len` must be initialized. + /// + /// [`capacity()`]: Vec::capacity + /// + /// # Examples + /// + /// This method can be useful for situations in which the vector + /// is serving as a buffer for other code, particularly over FFI: + /// + /// ```no_run + /// # #![allow(dead_code)] + /// # // This is just a minimal skeleton for the doc example; + /// # // don't use this as a starting point for a real library. + /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void } + /// # const Z_OK: i32 = 0; + /// # extern "C" { + /// # fn deflateGetDictionary( + /// # strm: *mut std::ffi::c_void, + /// # dictionary: *mut u8, + /// # dictLength: *mut usize, + /// # ) -> i32; + /// # } + /// # impl StreamWrapper { + /// pub fn get_dictionary(&self) -> Option> { + /// // Per the FFI method's docs, "32768 bytes is always enough". + /// let mut dict = Vec::with_capacity(32_768); + /// let mut dict_length = 0; + /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that: + /// // 1. `dict_length` elements were initialized. + /// // 2. `dict_length` <= the capacity (32_768) + /// // which makes `set_len` safe to call. + /// unsafe { + /// // Make the FFI call... + /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); + /// if r == Z_OK { + /// // ...and update the length to what was initialized. + /// dict.set_len(dict_length); + /// Some(dict) + /// } else { + /// None + /// } + /// } + /// } + /// # } + /// ``` + /// + /// While the following example is sound, there is a memory leak since + /// the inner vectors were not freed prior to the `set_len` call: + /// + /// ``` + /// let mut vec = vec![vec![1, 0, 0], + /// vec![0, 1, 0], + /// vec![0, 0, 1]]; + /// // SAFETY: + /// // 1. `old_len..0` is empty so no elements need to be initialized. + /// // 2. `0 <= capacity` always holds whatever `capacity` is. + /// unsafe { + /// vec.set_len(0); + /// } + /// ``` + /// + /// Normally, here, one would use [`clear`] instead to correctly drop + /// the contents and thus not leak memory. + #[inline(always)] + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + + self.len = new_len; + } + + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. + /// + /// This does not preserve ordering, but is *O*(1). + /// If you need to preserve the element order, use [`remove`] instead. + /// + /// [`remove`]: Vec::remove + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = vec!["foo", "bar", "baz", "qux"]; + /// + /// assert_eq!(v.swap_remove(1), "bar"); + /// assert_eq!(v, ["foo", "qux", "baz"]); + /// + /// assert_eq!(v.swap_remove(0), "foo"); + /// assert_eq!(v, ["baz", "qux"]); + /// ``` + #[inline(always)] + pub fn swap_remove(&mut self, index: usize) -> T { + #[cold] + #[inline(never)] + fn assert_failed(index: usize, len: usize) -> ! { + panic!( + "swap_remove index (is {}) should be < len (is {})", + index, len + ); + } + + let len = self.len(); + if index >= len { + assert_failed(index, len); + } + unsafe { + // We replace self[index] with the last element. Note that if the + // bounds check above succeeds there must be a last element (which + // can be self[index] itself). + let value = ptr::read(self.as_ptr().add(index)); + let base_ptr = self.as_mut_ptr(); + ptr::copy(base_ptr.add(len - 1), base_ptr.add(index), 1); + self.set_len(len - 1); + value + } + } + + /// Inserts an element at position `index` within the vector, shifting all + /// elements after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.insert(1, 4); + /// assert_eq!(vec, [1, 4, 2, 3]); + /// vec.insert(4, 5); + /// assert_eq!(vec, [1, 4, 2, 3, 5]); + /// ``` + #[cfg(not(no_global_oom_handling))] + pub fn insert(&mut self, index: usize, element: T) { + #[cold] + #[inline(never)] + fn assert_failed(index: usize, len: usize) -> ! { + panic!( + "insertion index (is {}) should be <= len (is {})", + index, len + ); + } + + let len = self.len(); + + // space for the new element + if len == self.buf.capacity() { + self.reserve(1); + } + + unsafe { + // infallible + // The spot to put the new value + { + let p = self.as_mut_ptr().add(index); + match cmp::Ord::cmp(&index, &len) { + Ordering::Less => { + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.add(1), len - index); + } + Ordering::Equal => { + // No elements need shifting. + } + Ordering::Greater => { + assert_failed(index, len); + } + } + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + } + + /// Removes and returns the element at position `index` within the vector, + /// shifting all elements after it to the left. + /// + /// Note: Because this shifts over the remaining elements, it has a + /// worst-case performance of *O*(*n*). If you don't need the order of elements + /// to be preserved, use [`swap_remove`] instead. If you'd like to remove + /// elements from the beginning of the `Vec`, consider using + /// [`VecDeque::pop_front`] instead. + /// + /// [`swap_remove`]: Vec::swap_remove + /// [`VecDeque::pop_front`]: alloc_crate::collections::VecDeque::pop_front + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = vec![1, 2, 3]; + /// assert_eq!(v.remove(1), 2); + /// assert_eq!(v, [1, 3]); + /// ``` + #[track_caller] + #[inline(always)] + pub fn remove(&mut self, index: usize) -> T { + #[cold] + #[inline(never)] + #[track_caller] + fn assert_failed(index: usize, len: usize) -> ! { + panic!("removal index (is {}) should be < len (is {})", index, len); + } + + let len = self.len(); + if index >= len { + assert_failed(index, len); + } + unsafe { + // infallible + let ret; + { + // the place we are taking from. + let ptr = self.as_mut_ptr().add(index); + // copy it out, unsafely having a copy of the value on + // the stack and in the vector at the same time. + ret = ptr::read(ptr); + + // Shift everything down to fill in that spot. + ptr::copy(ptr.add(1), ptr, len - index - 1); + } + self.set_len(len - 1); + ret + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns `false`. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4]; + /// vec.retain(|&x| x % 2 == 0); + /// assert_eq!(vec, [2, 4]); + /// ``` + /// + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4, 5]; + /// let keep = [false, true, true, false, true]; + /// let mut iter = keep.iter(); + /// vec.retain(|_| *iter.next().unwrap()); + /// assert_eq!(vec, [2, 3, 5]); + /// ``` + #[inline(always)] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.retain_mut(|elem| f(elem)); + } + + /// Retains only the elements specified by the predicate, passing a mutable reference to it. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4]; + /// vec.retain_mut(|x| if *x <= 3 { + /// *x += 1; + /// true + /// } else { + /// false + /// }); + /// assert_eq!(vec, [2, 3, 4]); + /// ``` + #[inline] + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let original_len = self.len(); + // Avoid double drop if the drop guard is not executed, + // since we may make some holes during the process. + unsafe { self.set_len(0) }; + + // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] + // |<- processed len ->| ^- next to check + // |<- deleted cnt ->| + // |<- original_len ->| + // Kept: Elements which predicate returns true on. + // Hole: Moved or dropped element slot. + // Unchecked: Unchecked valid elements. + // + // This drop guard will be invoked when predicate or `drop` of element panicked. + // It shifts unchecked elements to cover holes and `set_len` to the correct length. + // In cases when predicate and `drop` never panick, it will be optimized out. + struct BackshiftOnDrop<'a, T, A: Allocator> { + v: &'a mut Vec, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, T, A> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + // SAFETY: Trailing unchecked items must be valid since we never touch them. + unsafe { + ptr::copy( + self.v.as_ptr().add(self.processed_len), + self.v + .as_mut_ptr() + .add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len, + ); + } + } + // SAFETY: After filling holes, all items are in contiguous memory. + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); + } + } + } + + let mut g = BackshiftOnDrop { + v: self, + processed_len: 0, + deleted_cnt: 0, + original_len, + }; + + fn process_loop( + original_len: usize, + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, A>, + ) where + F: FnMut(&mut T) -> bool, + { + while g.processed_len != original_len { + // SAFETY: Unchecked element must be valid. + let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; + if !f(cur) { + // Advance early to avoid double drop if `drop_in_place` panicked. + g.processed_len += 1; + g.deleted_cnt += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + // We already advanced the counter. + if DELETED { + continue; + } else { + break; + } + } + if DELETED { + // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. + // We use copy for move, and never touch this element again. + unsafe { + let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + } + } + + // Stage 1: Nothing was deleted. + process_loop::(original_len, &mut f, &mut g); + + // Stage 2: Some elements were deleted. + process_loop::(original_len, &mut f, &mut g); + + // All item are processed. This can be optimized to `set_len` by LLVM. + drop(g); + } + + /// Removes all but the first of consecutive elements in the vector that resolve to the same + /// key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![10, 20, 21, 30, 20]; + /// + /// vec.dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(vec, [10, 20, 30, 20]); + /// ``` + #[inline(always)] + pub fn dedup_by_key(&mut self, mut key: F) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.dedup_by(|a, b| key(a) == key(b)) + } + + /// Removes all but the first of consecutive elements in the vector satisfying a given equality + /// relation. + /// + /// The `same_bucket` function is passed references to two elements from the vector and + /// must determine if the elements compare equal. The elements are passed in opposite order + /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + /// + /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// + /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` + #[inline] + pub fn dedup_by(&mut self, mut same_bucket: F) + where + F: FnMut(&mut T, &mut T) -> bool, + { + let len = self.len(); + if len <= 1 { + return; + } + + /* INVARIANT: vec.len() > read >= write > write-1 >= 0 */ + struct FillGapOnDrop<'a, T, A: Allocator> { + /* Offset of the element we want to check if it is duplicate */ + read: usize, + + /* Offset of the place where we want to place the non-duplicate + * when we find it. */ + write: usize, + + /* The Vec that would need correction if `same_bucket` panicked */ + vec: &'a mut Vec, + } + + impl<'a, T, A: Allocator> Drop for FillGapOnDrop<'a, T, A> { + fn drop(&mut self) { + /* This code gets executed when `same_bucket` panics */ + + /* SAFETY: invariant guarantees that `read - write` + * and `len - read` never overflow and that the copy is always + * in-bounds. */ + unsafe { + let ptr = self.vec.as_mut_ptr(); + let len = self.vec.len(); + + /* How many items were left when `same_bucket` panicked. + * Basically vec[read..].len() */ + let items_left = len.wrapping_sub(self.read); + + /* Pointer to first item in vec[write..write+items_left] slice */ + let dropped_ptr = ptr.add(self.write); + /* Pointer to first item in vec[read..] slice */ + let valid_ptr = ptr.add(self.read); + + /* Copy `vec[read..]` to `vec[write..write+items_left]`. + * The slices can overlap, so `copy_nonoverlapping` cannot be used */ + ptr::copy(valid_ptr, dropped_ptr, items_left); + + /* How many items have been already dropped + * Basically vec[read..write].len() */ + let dropped = self.read.wrapping_sub(self.write); + + self.vec.set_len(len - dropped); + } + } + } + + let mut gap = FillGapOnDrop { + read: 1, + write: 1, + vec: self, + }; + let ptr = gap.vec.as_mut_ptr(); + + /* Drop items while going through Vec, it should be more efficient than + * doing slice partition_dedup + truncate */ + + /* SAFETY: Because of the invariant, read_ptr, prev_ptr and write_ptr + * are always in-bounds and read_ptr never aliases prev_ptr */ + unsafe { + while gap.read < len { + let read_ptr = ptr.add(gap.read); + let prev_ptr = ptr.add(gap.write.wrapping_sub(1)); + + if same_bucket(&mut *read_ptr, &mut *prev_ptr) { + // Increase `gap.read` now since the drop may panic. + gap.read += 1; + /* We have found duplicate, drop it in-place */ + ptr::drop_in_place(read_ptr); + } else { + let write_ptr = ptr.add(gap.write); + + /* Because `read_ptr` can be equal to `write_ptr`, we either + * have to use `copy` or conditional `copy_nonoverlapping`. + * Looks like the first option is faster. */ + ptr::copy(read_ptr, write_ptr, 1); + + /* We have filled that place, so go further */ + gap.write += 1; + gap.read += 1; + } + } + + /* Technically we could let `gap` clean up with its Drop, but + * when `same_bucket` is guaranteed to not panic, this bloats a little + * the codegen, so we just do it manually */ + gap.vec.set_len(gap.write); + mem::forget(gap); + } + } + + /// Appends an element to the back of a collection. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2]; + /// vec.push(3); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn push(&mut self, value: T) { + // This will panic or abort if we would allocate > isize::MAX bytes + // or if the length increment would overflow for zero-sized types. + if self.len == self.buf.capacity() { + self.buf.reserve_for_push(self.len); + } + unsafe { + let end = self.as_mut_ptr().add(self.len); + ptr::write(end, value); + self.len += 1; + } + } + + /// Appends an element if there is sufficient spare capacity, otherwise an error is returned + /// with the element. + /// + /// Unlike [`push`] this method will not reallocate when there's insufficient capacity. + /// The caller should use [`reserve`] or [`try_reserve`] to ensure that there is enough capacity. + /// + /// [`push`]: Vec::push + /// [`reserve`]: Vec::reserve + /// [`try_reserve`]: Vec::try_reserve + /// + /// # Examples + /// + /// A manual, panic-free alternative to [`FromIterator`]: + /// + /// ``` + /// #![feature(vec_push_within_capacity)] + /// + /// use std::collections::TryReserveError; + /// fn from_iter_fallible(iter: impl Iterator) -> Result, TryReserveError> { + /// let mut vec = Vec::new(); + /// for value in iter { + /// if let Err(value) = vec.push_within_capacity(value) { + /// vec.try_reserve(1)?; + /// // this cannot fail, the previous line either returned or added at least 1 free slot + /// let _ = vec.push_within_capacity(value); + /// } + /// } + /// Ok(vec) + /// } + /// assert_eq!(from_iter_fallible(0..100), Ok(Vec::from_iter(0..100))); + /// ``` + #[inline(always)] + pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> { + if self.len == self.buf.capacity() { + return Err(value); + } + unsafe { + let end = self.as_mut_ptr().add(self.len); + ptr::write(end, value); + self.len += 1; + } + Ok(()) + } + + /// Removes the last element from a vector and returns it, or [`None`] if it + /// is empty. + /// + /// If you'd like to pop the first element, consider using + /// [`VecDeque::pop_front`] instead. + /// + /// [`VecDeque::pop_front`]: alloc_crate::collections::VecDeque::pop_front + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// assert_eq!(vec.pop(), Some(3)); + /// assert_eq!(vec, [1, 2]); + /// ``` + #[inline(always)] + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + unsafe { + self.len -= 1; + Some(ptr::read(self.as_ptr().add(self.len()))) + } + } + } + + /// Moves all the elements of `other` into `self`, leaving `other` empty. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// let mut vec2 = vec![4, 5, 6]; + /// vec.append(&mut vec2); + /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(vec2, []); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn append(&mut self, other: &mut Self) { + unsafe { + self.append_elements(other.as_slice() as _); + other.set_len(0); + } + } + + /// Appends elements to `self` from other buffer. + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + unsafe fn append_elements(&mut self, other: *const [T]) { + let count = unsafe { (*other).len() }; + self.reserve(count); + let len = self.len(); + unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; + self.len += count; + } + + /// Removes the specified range from the vector in bulk, returning all + /// removed elements as an iterator. If the iterator is dropped before + /// being fully consumed, it drops the remaining removed elements. + /// + /// The returned iterator keeps a mutable borrow on the vector to optimize + /// its implementation. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (due to + /// [`mem::forget`], for example), the vector may have lost and leaked + /// elements arbitrarily, including elements outside the range. + /// + /// # Examples + /// + /// ``` + /// let mut v = vec![1, 2, 3]; + /// let u: Vec<_> = v.drain(1..).collect(); + /// assert_eq!(v, &[1]); + /// assert_eq!(u, &[2, 3]); + /// + /// // A full range clears the vector, like `clear()` does + /// v.drain(..); + /// assert_eq!(v, &[]); + /// ``` + #[inline(always)] + pub fn drain(&mut self, range: R) -> Drain<'_, T, A> + where + R: RangeBounds, + { + // Memory safety + // + // When the Drain is first created, it shortens the length of + // the source vector to make sure no uninitialized or moved-from elements + // are accessible at all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, remaining tail of the vec is copied back to cover + // the hole, and the vector length is restored to the new length. + // + let len = self.len(); + + // Replaced by code below + // let Range { start, end } = slice::range(range, ..len); + + // Panics if range is out of bounds + let _ = &self.as_slice()[(range.start_bound().cloned(), range.end_bound().cloned())]; + + let start = match range.start_bound() { + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + Bound::Unbounded => 0, + }; + let end = match range.end_bound() { + Bound::Included(&n) => n + 1, + Bound::Excluded(&n) => n, + Bound::Unbounded => len, + }; + + unsafe { + // set self.vec length's to start, to be safe in case Drain is leaked + self.set_len(start); + let range_slice = slice::from_raw_parts(self.as_ptr().add(start), end - start); + Drain { + tail_start: end, + tail_len: len - end, + iter: range_slice.iter(), + vec: NonNull::from(self), + } + } + } + + /// Clears the vector, removing all values. + /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// + /// # Examples + /// + /// ``` + /// let mut v = vec![1, 2, 3]; + /// + /// v.clear(); + /// + /// assert!(v.is_empty()); + /// ``` + #[inline(always)] + pub fn clear(&mut self) { + let elems: *mut [T] = self.as_mut_slice(); + + // SAFETY: + // - `elems` comes directly from `as_mut_slice` and is therefore valid. + // - Setting `self.len` before calling `drop_in_place` means that, + // if an element's `Drop` impl panics, the vector's `Drop` impl will + // do nothing (leaking the rest of the elements) instead of dropping + // some twice. + unsafe { + self.len = 0; + ptr::drop_in_place(elems); + } + } + + /// Returns the number of elements in the vector, also referred to + /// as its 'length'. + /// + /// # Examples + /// + /// ``` + /// let a = vec![1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[inline(always)] + pub fn len(&self) -> usize { + self.len + } + + /// Returns `true` if the vector contains no elements. + /// + /// # Examples + /// + /// ``` + /// let mut v = Vec::new(); + /// assert!(v.is_empty()); + /// + /// v.push(1); + /// assert!(!v.is_empty()); + /// ``` + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated vector containing the elements in the range + /// `[at, len)`. After the call, the original vector will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// let vec2 = vec.split_off(1); + /// assert_eq!(vec, [1]); + /// assert_eq!(vec2, [2, 3]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + #[must_use = "use `.truncate()` if you don't need the other half"] + pub fn split_off(&mut self, at: usize) -> Self + where + A: Clone, + { + #[cold] + #[inline(never)] + fn assert_failed(at: usize, len: usize) -> ! { + panic!("`at` split index (is {}) should be <= len (is {})", at, len); + } + + if at > self.len() { + assert_failed(at, self.len()); + } + + if at == 0 { + // the new vector can take over the original buffer and avoid the copy + return mem::replace( + self, + Vec::with_capacity_in(self.capacity(), self.allocator().clone()), + ); + } + + let other_len = self.len - at; + let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); + + // Unsafely `set_len` and copy items to `other`. + unsafe { + self.set_len(at); + other.set_len(other_len); + + ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len()); + } + other + } + + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with the result of + /// calling the closure `f`. The return values from `f` will end up + /// in the `Vec` in the order they have been generated. + /// + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method uses a closure to create new values on every push. If + /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you + /// want to use the [`Default`] trait to generate values, you can + /// pass [`Default::default`] as the second argument. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.resize_with(5, Default::default); + /// assert_eq!(vec, [1, 2, 3, 0, 0]); + /// + /// let mut vec = vec![]; + /// let mut p = 1; + /// vec.resize_with(4, || { p *= 2; p }); + /// assert_eq!(vec, [2, 4, 8, 16]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn resize_with(&mut self, new_len: usize, f: F) + where + F: FnMut() -> T, + { + let len = self.len(); + if new_len > len { + self.extend(iter::repeat_with(f).take(new_len - len)); + } else { + self.truncate(new_len); + } + } + + /// Consumes and leaks the `Vec`, returning a mutable reference to the contents, + /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime + /// `'a`. If the type has only static references, or none at all, then this + /// may be chosen to be `'static`. + /// + /// As of Rust 1.57, this method does not reallocate or shrink the `Vec`, + /// so the leaked allocation may include unused capacity that is not part + /// of the returned slice. + /// + /// This function is mainly useful for data that lives for the remainder of + /// the program's life. Dropping the returned reference will cause a memory + /// leak. + /// + /// # Examples + /// + /// Simple usage: + /// + /// ``` + /// let x = vec![1, 2, 3]; + /// let static_ref: &'static mut [usize] = x.leak(); + /// static_ref[0] += 1; + /// assert_eq!(static_ref, &[2, 2, 3]); + /// ``` + #[inline(always)] + pub fn leak<'a>(self) -> &'a mut [T] + where + A: 'a, + { + let mut me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts_mut(me.as_mut_ptr(), me.len) } + } + + /// Returns the remaining spare capacity of the vector as a slice of + /// `MaybeUninit`. + /// + /// The returned slice can be used to fill the vector with data (e.g. by + /// reading from a file) before marking the data as initialized using the + /// [`set_len`] method. + /// + /// [`set_len`]: Vec::set_len + /// + /// # Examples + /// + /// ``` + /// // Allocate vector big enough for 10 elements. + /// let mut v = Vec::with_capacity(10); + /// + /// // Fill in the first 3 elements. + /// let uninit = v.spare_capacity_mut(); + /// uninit[0].write(0); + /// uninit[1].write(1); + /// uninit[2].write(2); + /// + /// // Mark the first 3 elements of the vector as being initialized. + /// unsafe { + /// v.set_len(3); + /// } + /// + /// assert_eq!(&v, &[0, 1, 2]); + /// ``` + #[inline(always)] + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + // Note: + // This method is not implemented in terms of `split_at_spare_mut`, + // to prevent invalidation of pointers to the buffer. + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr().add(self.len) as *mut MaybeUninit, + self.buf.capacity() - self.len, + ) + } + } + + /// Returns vector content as a slice of `T`, along with the remaining spare + /// capacity of the vector as a slice of `MaybeUninit`. + /// + /// The returned spare capacity slice can be used to fill the vector with data + /// (e.g. by reading from a file) before marking the data as initialized using + /// the [`set_len`] method. + /// + /// [`set_len`]: Vec::set_len + /// + /// Note that this is a low-level API, which should be used with care for + /// optimization purposes. If you need to append data to a `Vec` + /// you can use [`push`], [`extend`], [`extend_from_slice`], + /// [`extend_from_within`], [`insert`], [`append`], [`resize`] or + /// [`resize_with`], depending on your exact needs. + /// + /// [`push`]: Vec::push + /// [`extend`]: Vec::extend + /// [`extend_from_slice`]: Vec::extend_from_slice + /// [`extend_from_within`]: Vec::extend_from_within + /// [`insert`]: Vec::insert + /// [`append`]: Vec::append + /// [`resize`]: Vec::resize + /// [`resize_with`]: Vec::resize_with + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_split_at_spare)] + /// + /// let mut v = vec![1, 1, 2]; + /// + /// // Reserve additional space big enough for 10 elements. + /// v.reserve(10); + /// + /// let (init, uninit) = v.split_at_spare_mut(); + /// let sum = init.iter().copied().sum::(); + /// + /// // Fill in the next 4 elements. + /// uninit[0].write(sum); + /// uninit[1].write(sum * 2); + /// uninit[2].write(sum * 3); + /// uninit[3].write(sum * 4); + /// + /// // Mark the 4 elements of the vector as being initialized. + /// unsafe { + /// let len = v.len(); + /// v.set_len(len + 4); + /// } + /// + /// assert_eq!(&v, &[1, 1, 2, 4, 8, 12, 16]); + /// ``` + #[inline(always)] + pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [MaybeUninit]) { + // SAFETY: + // - len is ignored and so never changed + let (init, spare, _) = unsafe { self.split_at_spare_mut_with_len() }; + (init, spare) + } + + /// Safety: changing returned .2 (&mut usize) is considered the same as calling `.set_len(_)`. + /// + /// This method provides unique access to all vec parts at once in `extend_from_within`. + unsafe fn split_at_spare_mut_with_len( + &mut self, + ) -> (&mut [T], &mut [MaybeUninit], &mut usize) { + let ptr = self.as_mut_ptr(); + // SAFETY: + // - `ptr` is guaranteed to be valid for `self.len` elements + // - but the allocation extends out to `self.buf.capacity()` elements, possibly + // uninitialized + let spare_ptr = unsafe { ptr.add(self.len) }; + let spare_ptr = spare_ptr.cast::>(); + let spare_len = self.buf.capacity() - self.len; + + // SAFETY: + // - `ptr` is guaranteed to be valid for `self.len` elements + // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized` + unsafe { + let initialized = slice::from_raw_parts_mut(ptr, self.len); + let spare = slice::from_raw_parts_mut(spare_ptr, spare_len); + + (initialized, spare, &mut self.len) + } + } +} + +impl Vec { + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with `value`. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method requires `T` to implement [`Clone`], + /// in order to be able to clone the passed value. + /// If you need more flexibility (or want to rely on [`Default`] instead of + /// [`Clone`]), use [`Vec::resize_with`]. + /// If you only need to resize to a smaller size, use [`Vec::truncate`]. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec!["hello"]; + /// vec.resize(3, "world"); + /// assert_eq!(vec, ["hello", "world", "world"]); + /// + /// let mut vec = vec![1, 2, 3, 4]; + /// vec.resize(2, 0); + /// assert_eq!(vec, [1, 2]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn resize(&mut self, new_len: usize, value: T) { + let len = self.len(); + + if new_len > len { + self.extend_with(new_len - len, ExtendElement(value)) + } else { + self.truncate(new_len); + } + } + + /// Clones and appends all elements in a slice to the `Vec`. + /// + /// Iterates over the slice `other`, clones each element, and then appends + /// it to this `Vec`. The `other` slice is traversed in-order. + /// + /// Note that this function is same as [`extend`] except that it is + /// specialized to work with slices instead. If and when Rust gets + /// specialization this function will likely be deprecated (but still + /// available). + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1]; + /// vec.extend_from_slice(&[2, 3, 4]); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// [`extend`]: Vec::extend + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn extend_from_slice(&mut self, other: &[T]) { + self.extend(other.iter().cloned()) + } + + /// Copies elements from `src` range to the end of the vector. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![0, 1, 2, 3, 4]; + /// + /// vec.extend_from_within(2..); + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]); + /// + /// vec.extend_from_within(..2); + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]); + /// + /// vec.extend_from_within(4..8); + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn extend_from_within(&mut self, src: R) + where + R: RangeBounds, + { + // let range = slice::range(src, ..self.len()); + + let _ = &self.as_slice()[(src.start_bound().cloned(), src.end_bound().cloned())]; + + let len = self.len(); + + let start: ops::Bound<&usize> = src.start_bound(); + let start = match start { + ops::Bound::Included(&start) => start, + ops::Bound::Excluded(start) => start + 1, + ops::Bound::Unbounded => 0, + }; + + let end: ops::Bound<&usize> = src.end_bound(); + let end = match end { + ops::Bound::Included(end) => end + 1, + ops::Bound::Excluded(&end) => end, + ops::Bound::Unbounded => len, + }; + + let range = start..end; + + self.reserve(range.len()); + + // SAFETY: + // - len is increased only after initializing elements + let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() }; + + // SAFETY: + // - caller guarantees that src is a valid index + let to_clone = unsafe { this.get_unchecked(range) }; + + iter::zip(to_clone, spare) + .map(|(src, dst)| dst.write(src.clone())) + // Note: + // - Element was just initialized with `MaybeUninit::write`, so it's ok to increase len + // - len is increased after each element to prevent leaks (see issue #82533) + .for_each(|_| *len += 1); + } +} + +impl Vec<[T; N], A> { + /// Takes a `Vec<[T; N]>` and flattens it into a `Vec`. + /// + /// # Panics + /// + /// Panics if the length of the resulting vector would overflow a `usize`. + /// + /// This is only possible when flattening a vector of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_flatten)] + /// + /// let mut vec = vec![[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// assert_eq!(vec.pop(), Some([7, 8, 9])); + /// + /// let mut flattened = vec.into_flattened(); + /// assert_eq!(flattened.pop(), Some(6)); + /// ``` + #[inline(always)] + pub fn into_flattened(self) -> Vec { + let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc(); + let (new_len, new_cap) = if size_of::() == 0 { + (len.checked_mul(N).expect("vec len overflow"), usize::MAX) + } else { + // SAFETY: + // - `cap * N` cannot overflow because the allocation is already in + // the address space. + // - Each `[T; N]` has `N` valid elements, so there are `len * N` + // valid elements in the allocation. + (len * N, cap * N) + }; + // SAFETY: + // - `ptr` was allocated by `self` + // - `ptr` is well-aligned because `[T; N]` has the same alignment as `T`. + // - `new_cap` refers to the same sized allocation as `cap` because + // `new_cap * size_of::()` == `cap * size_of::<[T; N]>()` + // - `len` <= `cap`, so `len * N` <= `cap * N`. + unsafe { Vec::::from_raw_parts_in(ptr.cast(), new_len, new_cap, alloc) } + } +} + +// This code generalizes `extend_with_{element,default}`. +trait ExtendWith { + fn next(&mut self) -> T; + fn last(self) -> T; +} + +struct ExtendElement(T); +impl ExtendWith for ExtendElement { + #[inline(always)] + fn next(&mut self) -> T { + self.0.clone() + } + + #[inline(always)] + fn last(self) -> T { + self.0 + } +} + +impl Vec { + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + /// Extend the vector by `n` values, using the given generator. + fn extend_with>(&mut self, n: usize, mut value: E) { + self.reserve(n); + + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + // Use SetLenOnDrop to work around bug where compiler + // might not realize the store through `ptr` through self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + + // Write all elements except the last one + for _ in 1..n { + ptr::write(ptr, value.next()); + ptr = ptr.add(1); + // Increment the length in every step in case next() panics + local_len.increment_len(1); + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, value.last()); + local_len.increment_len(1); + } + + // len set by scope guard + } + } +} + +impl Vec { + /// Removes consecutive repeated elements in the vector according to the + /// [`PartialEq`] trait implementation. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2, 2, 3, 2]; + /// + /// vec.dedup(); + /// + /// assert_eq!(vec, [1, 2, 3, 2]); + /// ``` + #[inline(always)] + pub fn dedup(&mut self) { + self.dedup_by(|a, b| a == b) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Common trait implementations for Vec +//////////////////////////////////////////////////////////////////////////////// + +impl ops::Deref for Vec { + type Target = [T]; + + #[inline(always)] + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + } +} + +impl ops::DerefMut for Vec { + #[inline(always)] + fn deref_mut(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Clone for Vec { + #[inline(always)] + fn clone(&self) -> Self { + let alloc = self.allocator().clone(); + let mut vec = Vec::with_capacity_in(self.len(), alloc); + vec.extend_from_slice(self); + vec + } + + #[inline(always)] + fn clone_from(&mut self, other: &Self) { + // drop anything that will not be overwritten + self.truncate(other.len()); + + // self.len <= other.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = other.split_at(self.len()); + + // reuse the contained values' allocations/resources. + self.clone_from_slice(init); + self.extend_from_slice(tail); + } +} + +/// The hash of a vector is the same as that of the corresponding slice, +/// as required by the `core::borrow::Borrow` implementation. +/// +/// ``` +/// #![feature(build_hasher_simple_hash_one)] +/// use std::hash::BuildHasher; +/// +/// let b = std::collections::hash_map::RandomState::new(); +/// let v: Vec = vec![0xa8, 0x3c, 0x09]; +/// let s: &[u8] = &[0xa8, 0x3c, 0x09]; +/// assert_eq!(b.hash_one(v), b.hash_one(s)); +/// ``` +impl Hash for Vec { + #[inline(always)] + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} + +impl, A: Allocator> Index for Vec { + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + Index::index(&**self, index) + } +} + +impl, A: Allocator> IndexMut for Vec { + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut **self, index) + } +} + +#[cfg(not(no_global_oom_handling))] +impl FromIterator for Vec { + #[inline(always)] + fn from_iter>(iter: I) -> Vec { + let mut vec = Vec::new(); + vec.extend(iter); + vec + } +} + +impl IntoIterator for Vec { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out of + /// the vector (from start to end). The vector cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// let v = vec!["a".to_string(), "b".to_string()]; + /// let mut v_iter = v.into_iter(); + /// + /// let first_element: Option = v_iter.next(); + /// + /// assert_eq!(first_element, Some("a".to_string())); + /// assert_eq!(v_iter.next(), Some("b".to_string())); + /// assert_eq!(v_iter.next(), None); + /// ``` + #[inline(always)] + fn into_iter(self) -> Self::IntoIter { + unsafe { + let mut me = ManuallyDrop::new(self); + let alloc = ManuallyDrop::new(ptr::read(me.allocator())); + let begin = me.as_mut_ptr(); + let end = if size_of::() == 0 { + begin.cast::().wrapping_add(me.len()).cast() + } else { + begin.add(me.len()) as *const T + }; + let cap = me.buf.capacity(); + IntoIter { + buf: NonNull::new_unchecked(begin), + phantom: PhantomData, + cap, + alloc, + ptr: begin, + end, + } + } + } +} + +impl<'a, T, A: Allocator> IntoIterator for &'a Vec { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + #[inline(always)] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +#[cfg(not(no_global_oom_handling))] +impl Extend for Vec { + #[inline(always)] + fn extend>(&mut self, iter: I) { + // This is the case for a general iter. + // + // This function should be the moral equivalent of: + // + // for item in iter { + // self.push(item); + // } + + let mut iter = iter.into_iter(); + while let Some(element) = iter.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iter.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.as_mut_ptr().add(len), element); + // Since next() executes user code which can panic we have to bump the length + // after each step. + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); + } + } + } +} + +impl Vec { + /// Creates a splicing iterator that replaces the specified range in the vector + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// `range` is removed even if the iterator is not consumed until the end. + /// + /// It is unspecified how many elements are removed from the vector + /// if the `Splice` value is leaked. + /// + /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped. + /// + /// This is optimal if: + /// + /// * The tail (elements in the vector after `range`) is empty, + /// * or `replace_with` yields fewer or equal elements than `range`’s length + /// * or the lower bound of its `size_hint()` is exact. + /// + /// Otherwise, a temporary vector is allocated and the tail is moved twice. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// let mut v = vec![1, 2, 3, 4]; + /// let new = [7, 8, 9]; + /// let u: Vec<_> = v.splice(1..3, new).collect(); + /// assert_eq!(v, &[1, 7, 8, 9, 4]); + /// assert_eq!(u, &[2, 3]); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[inline(always)] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A> + where + R: RangeBounds, + I: IntoIterator, + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } + } +} + +/// Extend implementation that copies elements out of references before pushing them onto the Vec. +/// +/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to +/// append the entire slice at once. +/// +/// [`copy_from_slice`]: slice::copy_from_slice +#[cfg(not(no_global_oom_handling))] +impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { + #[inline(always)] + fn extend>(&mut self, iter: I) { + let mut iter = iter.into_iter(); + while let Some(element) = iter.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iter.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.as_mut_ptr().add(len), *element); + // Since next() executes user code which can panic we have to bump the length + // after each step. + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); + } + } + } +} + +/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). +impl PartialOrd for Vec { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +impl Eq for Vec {} + +/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). +impl Ord for Vec { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl Drop for Vec { + #[inline(always)] + fn drop(&mut self) { + unsafe { + // use drop for [T] + // use a raw slice to refer to the elements of the vector as weakest necessary type; + // could avoid questions of validity in certain cases + ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len)) + } + // RawVec handles deallocation + } +} + +impl Default for Vec { + /// Creates an empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + #[inline(always)] + fn default() -> Vec { + Vec::new() + } +} + +impl fmt::Debug for Vec { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl AsRef> for Vec { + #[inline(always)] + fn as_ref(&self) -> &Vec { + self + } +} + +impl AsMut> for Vec { + #[inline(always)] + fn as_mut(&mut self) -> &mut Vec { + self + } +} + +impl AsRef<[T]> for Vec { + #[inline(always)] + fn as_ref(&self) -> &[T] { + self + } +} + +impl AsMut<[T]> for Vec { + #[inline(always)] + fn as_mut(&mut self) -> &mut [T] { + self + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<&[T]> for Vec { + /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); + /// ``` + #[inline(always)] + fn from(s: &[T]) -> Vec { + let mut vec = Vec::with_capacity(s.len()); + vec.extend_from_slice(s); + vec + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<&mut [T]> for Vec { + /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); + /// ``` + #[inline(always)] + fn from(s: &mut [T]) -> Vec { + let mut vec = Vec::with_capacity(s.len()); + vec.extend_from_slice(s); + vec + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<[T; N]> for Vec { + #[inline(always)] + fn from(s: [T; N]) -> Vec { + Box::slice(Box::new(s)).into_vec() + } +} + +impl From> for Vec { + /// Convert a boxed slice into a vector by transferring ownership of + /// the existing heap allocation. + /// + /// # Examples + /// + /// ``` + /// let b: Box<[i32]> = vec![1, 2, 3].into_boxed_slice(); + /// assert_eq!(Vec::from(b), vec![1, 2, 3]); + /// ``` + #[inline(always)] + fn from(s: Box<[T], A>) -> Self { + s.into_vec() + } +} + +impl From> for Vec { + /// Convert a boxed array into a vector by transferring ownership of + /// the existing heap allocation. + /// + /// # Examples + /// + /// ``` + /// let b: Box<[i32; 3]> = Box::new([1, 2, 3]); + /// assert_eq!(Vec::from(b), vec![1, 2, 3]); + /// ``` + #[inline(always)] + fn from(s: Box<[T; N], A>) -> Self { + s.into_vec() + } +} + +// note: test pulls in libstd, which causes errors here +#[cfg(not(no_global_oom_handling))] +impl From> for Box<[T], A> { + /// Convert a vector into a boxed slice. + /// + /// If `v` has excess capacity, its items will be moved into a + /// newly-allocated buffer with exactly the right capacity. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(Box::from(vec![1, 2, 3]), vec![1, 2, 3].into_boxed_slice()); + /// ``` + /// + /// Any excess capacity is removed: + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// + /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice()); + /// ``` + #[inline(always)] + fn from(v: Vec) -> Self { + v.into_boxed_slice() + } +} + +#[cfg(not(no_global_oom_handling))] +impl From<&str> for Vec { + /// Allocate a `Vec` and fill it with a UTF-8 string. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']); + /// ``` + #[inline(always)] + fn from(s: &str) -> Vec { + From::from(s.as_bytes()) + } +} + +impl TryFrom> for [T; N] { + type Error = Vec; + + /// Gets the entire contents of the `Vec` as an array, + /// if its size exactly matches that of the requested array. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3])); + /// assert_eq!(>::new().try_into(), Ok([])); + /// ``` + /// + /// If the length doesn't match, the input comes back in `Err`: + /// ``` + /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); + /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + /// ``` + /// + /// If you're fine with just getting a prefix of the `Vec`, + /// you can call [`.truncate(N)`](Vec::truncate) first. + /// ``` + /// let mut v = String::from("hello world").into_bytes(); + /// v.sort(); + /// v.truncate(2); + /// let [a, b]: [_; 2] = v.try_into().unwrap(); + /// assert_eq!(a, b' '); + /// assert_eq!(b, b'd'); + /// ``` + #[inline(always)] + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + if vec.len() != N { + return Err(vec); + } + + // SAFETY: `.set_len(0)` is always sound. + unsafe { vec.set_len(0) }; + + // SAFETY: A `Vec`'s pointer is always aligned properly, and + // the alignment the array needs is the same as the items. + // We checked earlier that we have sufficient items. + // The items will not double-drop as the `set_len` + // tells the `Vec` not to also drop them. + let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) }; + Ok(array) + } +} + +#[inline(always)] +#[cfg(not(no_global_oom_handling))] +#[doc(hidden)] +pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(n, alloc); + v.extend_with(n, ExtendElement(elem)); + v +} + +#[inline(always)] +#[cfg(not(no_global_oom_handling))] +#[doc(hidden)] +pub fn from_elem(elem: T, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + v.extend_with(n, ExtendElement(elem)); + v +} + +/// Write is implemented for `Vec` by appending to the vector. +/// The vector will grow as needed. +#[cfg(feature = "std")] +impl io::Write for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + let len = bufs.iter().map(|b| b.len()).sum(); + self.reserve(len); + for buf in bufs { + self.extend_from_slice(buf); + } + Ok(len) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Vec +where + T: serde::Serialize, + A: Allocator, +{ + #[inline(always)] + fn serialize(&self, serializer: S) -> Result + where + S: serde::ser::Serializer, + { + serializer.collect_seq(self) + } +} + +#[cfg(feature = "serde")] +impl<'de, T, A> serde::de::Deserialize<'de> for Vec +where + T: serde::de::Deserialize<'de>, + A: Allocator + Default, +{ + #[inline(always)] + fn deserialize(deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + struct VecVisitor { + marker: PhantomData<(T, A)>, + } + + impl<'de, T, A> serde::de::Visitor<'de> for VecVisitor + where + T: serde::de::Deserialize<'de>, + A: Allocator + Default, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let mut values = Vec::with_capacity_in(cautious(seq.size_hint()), A::default()); + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } + } + + let visitor = VecVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + #[inline(always)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: serde::de::Deserializer<'de>, + { + struct VecInPlaceVisitor<'a, T: 'a, A: Allocator + 'a>(&'a mut Vec); + + impl<'a, 'de, T, A> serde::de::Visitor<'de> for VecInPlaceVisitor<'a, T, A> + where + T: serde::de::Deserialize<'de>, + A: Allocator + Default, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let hint = cautious(seq.size_hint()); + if let Some(additional) = hint.checked_sub(self.0.len()) { + self.0.reserve(additional); + } + + for i in 0..self.0.len() { + let next = { + let next_place = InPlaceSeed(&mut self.0[i]); + seq.next_element_seed(next_place)? + }; + if next.is_none() { + self.0.truncate(i); + return Ok(()); + } + } + + while let Some(value) = seq.next_element()? { + self.0.push(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(VecInPlaceVisitor(place)) + } +} + +#[cfg(feature = "serde")] +pub fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) +} + +/// A DeserializeSeed helper for implementing deserialize_in_place Visitors. +/// +/// Wraps a mutable reference and calls deserialize_in_place on it. + +#[cfg(feature = "serde")] +pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T); + +#[cfg(feature = "serde")] +impl<'a, 'de, T> serde::de::DeserializeSeed<'de> for InPlaceSeed<'a, T> +where + T: serde::de::Deserialize<'de>, +{ + type Value = (); + fn deserialize(self, deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + T::deserialize_in_place(deserializer, self.0) + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/partial_eq.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/partial_eq.rs new file mode 100644 index 00000000000000..a2e64fcd12af6e --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/partial_eq.rs @@ -0,0 +1,43 @@ +#[cfg(not(no_global_oom_handling))] +use alloc_crate::borrow::Cow; + +use crate::stable::alloc::Allocator; + +use super::Vec; + +macro_rules! __impl_slice_eq1 { + ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => { + impl PartialEq<$rhs> for $lhs + where + T: PartialEq, + $($ty: $bound)? + { + #[inline(always)] + fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } + #[inline(always)] + fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } + } + } +} + +__impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec, Vec } +__impl_slice_eq1! { [A: Allocator] Vec, &[U] } +__impl_slice_eq1! { [A: Allocator] Vec, &mut [U] } +__impl_slice_eq1! { [A: Allocator] &[T], Vec } +__impl_slice_eq1! { [A: Allocator] &mut [T], Vec } +__impl_slice_eq1! { [A: Allocator] Vec, [U] } +__impl_slice_eq1! { [A: Allocator] [T], Vec } +#[cfg(not(no_global_oom_handling))] +__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N] } + +// NOTE: some less important impls are omitted to reduce code bloat +// FIXME(Centril): Reconsider this? +//__impl_slice_eq1! { [const N: usize] Vec, &mut [B; N], } +//__impl_slice_eq1! { [const N: usize] [A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] &[A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec, } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } +//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/set_len_on_drop.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/set_len_on_drop.rs new file mode 100644 index 00000000000000..bf08507f1cf526 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/set_len_on_drop.rs @@ -0,0 +1,31 @@ +// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +// +// The idea is: The length field in SetLenOnDrop is a local variable +// that the optimizer will see does not alias with any stores through the Vec's data +// pointer. This is a workaround for alias analysis issue #32155 +pub(super) struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline(always)] + pub(super) fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { + local_len: *len, + len, + } + } + + #[inline(always)] + pub(super) fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl Drop for SetLenOnDrop<'_> { + #[inline(always)] + fn drop(&mut self) { + *self.len = self.local_len; + } +} diff --git a/deps/crates/vendor/allocator-api2/src/stable/vec/splice.rs b/deps/crates/vendor/allocator-api2/src/stable/vec/splice.rs new file mode 100644 index 00000000000000..06a712b844a2a9 --- /dev/null +++ b/deps/crates/vendor/allocator-api2/src/stable/vec/splice.rs @@ -0,0 +1,135 @@ +use core::ptr::{self}; +use core::slice::{self}; + +use crate::stable::alloc::{Allocator, Global}; + +use super::{Drain, Vec}; + +/// A splicing iterator for `Vec`. +/// +/// This struct is created by [`Vec::splice()`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let new = [7, 8]; +/// let iter: std::vec::Splice<_> = v.splice(1.., new); +/// ``` +#[derive(Debug)] +pub struct Splice<'a, I: Iterator + 'a, A: Allocator + 'a = Global> { + pub(super) drain: Drain<'a, I::Item, A>, + pub(super) replace_with: I, +} + +impl Iterator for Splice<'_, I, A> { + type Item = I::Item; + + #[inline(always)] + fn next(&mut self) -> Option { + self.drain.next() + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, A> { + #[inline(always)] + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +impl ExactSizeIterator for Splice<'_, I, A> {} + +impl Drop for Splice<'_, I, A> { + #[inline] + fn drop(&mut self) { + self.drain.by_ref().for_each(drop); + + unsafe { + if self.drain.tail_len == 0 { + self.drain.vec.as_mut().extend(self.replace_with.by_ref()); + return; + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return; + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return; + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = self + .replace_with + .by_ref() + .collect::>() + .into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl Drain<'_, T, A> { + /// The range from `self.vec.len` to `self.tail_start` contains elements + /// that have been moved out. + /// Fill that range as much as possible with new elements from the `replace_with` iterator. + /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) + #[inline(always)] + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = unsafe { self.vec.as_mut() }; + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = unsafe { + slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) + }; + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + unsafe { ptr::write(place, new_item) }; + vec.len += 1; + } else { + return false; + } + } + true + } + + /// Makes room for inserting more elements before the tail. + #[inline(always)] + unsafe fn move_tail(&mut self, additional: usize) { + let vec = unsafe { self.vec.as_mut() }; + let len = self.tail_start + self.tail_len; + vec.buf.reserve(len, additional); + + let new_tail_start = self.tail_start + additional; + unsafe { + let src = vec.as_ptr().add(self.tail_start); + let dst = vec.as_mut_ptr().add(new_tail_start); + ptr::copy(src, dst, self.tail_len); + } + self.tail_start = new_tail_start; + } +} diff --git a/deps/crates/vendor/anyhow/.cargo-checksum.json b/deps/crates/vendor/anyhow/.cargo-checksum.json new file mode 100644 index 00000000000000..52e90b2aba06ea --- /dev/null +++ b/deps/crates/vendor/anyhow/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"f5e9f49ba26ab09e3432ae424ecb09eeb39bf0dcbe8e2bdc2335db4dee8eb7df",".github/FUNDING.yml":"b017158736b3c9751a2d21edfce7fe61c8954e2fced8da8dd3013c2f3e295bd9",".github/workflows/ci.yml":"3906e0b1d66cd99e62f9a1d1455ff0c5181dd7ce6abd07f5f9d392d93e6d66c2","Cargo.lock":"f03ce351fa726aa6a443c0e8e20e2aac653a95dbc8225dcd497390106584b5ae","Cargo.toml":"a89e4444e863507cfd9d4df741a9512b5db220aefe75311bd402c787a22a0bfc","Cargo.toml.orig":"9dd604a6cb912032e6ccd873385b2f3339c46c8ece69f876af4ce535dc20d612","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"86f5b88c45b2b9b7eefa0ad66c11918a607319cad683f01123ff38db68b4a49b","build.rs":"89d1baedcff59822ed692d3a33f131c211a213bdec33c83f68b54110d9c64223","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"621ec5d9e2f31883d0384ae00fc536d1ea359da989d2e0d1be1ba03482c8f920","src/chain.rs":"85af447405f075633fab186b7f1c94d7f33a36474f239c50a961b2d6197d5426","src/context.rs":"8b106e43df7a66fbc3e85b87a4d7f8a780d43d3ee0cd1ae86c571950ecf07d13","src/ensure.rs":"709524741c8f9365e01cb36fc2349a8724513de02cf9e253809a93af8d6a7b6e","src/error.rs":"38aaae2c0067c25137d6528bb1e32dc60122efe285559d50bbca854a0656d8fc","src/fmt.rs":"2cca8c7f3cab636fdb17433ca2b1fda0e8d28bb20d4647b87c991dacd8f06cdf","src/kind.rs":"ddcabf15b3b47a4ef16ed361c45cc0cc82e7be90622995ff6c04b3fec78bb04f","src/lib.rs":"d03bbd1141aac19f344606daa73eb389d54dd26ee27cd13143d1eddb1a045297","src/macros.rs":"696e6a8aac614525a29697aedc7561e98beccf3d43aed3ada1cc93daa99da8ba","src/nightly.rs":"1c0aeadfcdbe22f8f807b185dec1a7448c378bddb37689714944b60473b58049","src/ptr.rs":"a114639d26f4feca7e186106342334cdf2e2176f892149aa331ace72e5d81410","src/wrapper.rs":"079218e1d8c9374f52311b1c7971f7fbdeba4d7af1b0749c0d535010f1232697","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"4e381aa8ca3eabb7ac14d1e0c3700b3223e47640547a6988cfa13ad68255f60f","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ba9bc18416115cb48fd08675a3e7fc89584de7926dad6b2be6645dc13d5931df","tests/test_backtrace.rs":"60afdd7ee5850dc22625ff486fe41c47fd322db874a93c4871ddfed2bf603930","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"6ef8823153d6aba31dda8438b9e51984e6b7377d585addbaf87162b39d733cd9","tests/test_ffi.rs":"c6e6bf39e6b2cf9aacea12e3e4da4e1e1edb7fc906d231e5baf45812a08de3c4","tests/test_fmt.rs":"0e49b48f08e4faaf03e2f202e1efc5250018876c4e1b01b8379d7a38ae8df870","tests/test_macros.rs":"3eb6ec9024cf8812da48de35b733d5a69ed942907fb4e6c67ec471cd4bcef562","tests/test_repr.rs":"034dee888abd08741e11ac2e95ef4fcb2ab3943d0a76e8e976db404658e1a252","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/ensure-nonbool.rs":"7e57cb93fbcd82959b36586ed6bd2ad978b051fe5facd5274651fde6b1600905","tests/ui/ensure-nonbool.stderr":"e3dfbaedd66fdfc524f8462305760c7978c4268ca7e1cd872d7ecde5d3b455bd","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"8b1cb7fca632396a22bb3a642f2df3ab62b3e9a87951e20fa40bdd548d002162","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"c472de95483aa234728c7f57039c88fc3456892838329976a75cd167c3c172c9","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"7f99cd914d2d423d77274e1b859b5ad151cde8224e42687e50622c26118fd47f","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"} \ No newline at end of file diff --git a/deps/crates/vendor/anyhow/.cargo_vcs_info.json b/deps/crates/vendor/anyhow/.cargo_vcs_info.json new file mode 100644 index 00000000000000..bf102082793200 --- /dev/null +++ b/deps/crates/vendor/anyhow/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "5c657b32522023a9f7ef883fb08582fd8e656b1a" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/anyhow/.github/FUNDING.yml b/deps/crates/vendor/anyhow/.github/FUNDING.yml new file mode 100644 index 00000000000000..750707701cdae9 --- /dev/null +++ b/deps/crates/vendor/anyhow/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/deps/crates/vendor/anyhow/.github/workflows/ci.yml b/deps/crates/vendor/anyhow/.github/workflows/ci.yml new file mode 100644 index 00000000000000..74f1fa1c9509ea --- /dev/null +++ b/deps/crates/vendor/anyhow/.github/workflows/ci.yml @@ -0,0 +1,146 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + test: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, beta, stable, 1.82.0, 1.80.0, 1.76.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + components: rust-src + - name: Enable type layout randomization + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV + if: matrix.rust == 'nightly' + - name: Enable nightly-only tests + run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=anyhow_nightly_testing >> $GITHUB_ENV + if: matrix.rust == 'nightly' + - run: cargo test + - run: cargo check --no-default-features + - run: cargo check + - uses: actions/upload-artifact@v6 + if: matrix.rust == 'nightly' && always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true + + build: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [1.68.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + components: rust-src + - run: cargo check --manifest-path tests/crate/Cargo.toml + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features + + minimal: + name: Minimal versions + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked + + windows: + name: Windows + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: windows-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + with: + components: rust-src + - run: cargo check + + doc: + name: Documentation + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy, rust-src + - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic + + miri: + name: Miri + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test + env: + MIRIFLAGS: -Zmiri-strict-provenance + + outdated: + name: Outdated + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --workspace --exit-code 1 diff --git a/deps/crates/vendor/anyhow/Cargo.lock b/deps/crates/vendor/anyhow/Cargo.lock new file mode 100644 index 00000000000000..90091b44d0c2bd --- /dev/null +++ b/deps/crates/vendor/anyhow/Cargo.lock @@ -0,0 +1,344 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.102" +dependencies = [ + "futures", + "rustversion", + "syn", + "thiserror", + "trybuild", +] + +[[package]] +name = "dissimilar" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] +name = "syn" +version = "2.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-triple" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "1.0.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + +[[package]] +name = "trybuild" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c635f0191bd3a2941013e5062667100969f8c4e9cd787c14f977265d73616e" +dependencies = [ + "dissimilar", + "glob", + "serde", + "serde_derive", + "serde_json", + "target-triple", + "termcolor", + "toml", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/deps/crates/vendor/anyhow/Cargo.toml b/deps/crates/vendor/anyhow/Cargo.toml new file mode 100644 index 00000000000000..e1012e60f1bca7 --- /dev/null +++ b/deps/crates/vendor/anyhow/Cargo.toml @@ -0,0 +1,129 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.68" +name = "anyhow" +version = "1.0.102" +authors = ["David Tolnay "] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Flexible concrete Error type built on std::error::Error" +documentation = "https://docs.rs/anyhow" +readme = "README.md" +keywords = [ + "error", + "error-handling", +] +categories = [ + "rust-patterns", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/anyhow" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] + +[features] +backtrace = [] +default = ["std"] +std = [] + +[lib] +name = "anyhow" +path = "src/lib.rs" + +[[test]] +name = "compiletest" +path = "tests/compiletest.rs" + +[[test]] +name = "test_autotrait" +path = "tests/test_autotrait.rs" + +[[test]] +name = "test_backtrace" +path = "tests/test_backtrace.rs" + +[[test]] +name = "test_boxed" +path = "tests/test_boxed.rs" + +[[test]] +name = "test_chain" +path = "tests/test_chain.rs" + +[[test]] +name = "test_context" +path = "tests/test_context.rs" + +[[test]] +name = "test_convert" +path = "tests/test_convert.rs" + +[[test]] +name = "test_downcast" +path = "tests/test_downcast.rs" + +[[test]] +name = "test_ensure" +path = "tests/test_ensure.rs" + +[[test]] +name = "test_ffi" +path = "tests/test_ffi.rs" + +[[test]] +name = "test_fmt" +path = "tests/test_fmt.rs" + +[[test]] +name = "test_macros" +path = "tests/test_macros.rs" + +[[test]] +name = "test_repr" +path = "tests/test_repr.rs" + +[[test]] +name = "test_source" +path = "tests/test_source.rs" + +[dev-dependencies.futures] +version = "0.3" +default-features = false + +[dev-dependencies.rustversion] +version = "1.0.6" + +[dev-dependencies.syn] +version = "2.0" +features = ["full"] + +[dev-dependencies.thiserror] +version = "2" + +[dev-dependencies.trybuild] +version = "1.0.108" +features = ["diff"] diff --git a/deps/crates/vendor/anyhow/Cargo.toml.orig b/deps/crates/vendor/anyhow/Cargo.toml.orig new file mode 100644 index 00000000000000..e4d2ca8fa51a71 --- /dev/null +++ b/deps/crates/vendor/anyhow/Cargo.toml.orig @@ -0,0 +1,36 @@ +[package] +name = "anyhow" +version = "1.0.102" +authors = ["David Tolnay "] +categories = ["rust-patterns", "no-std"] +description = "Flexible concrete Error type built on std::error::Error" +documentation = "https://docs.rs/anyhow" +edition = "2021" +keywords = ["error", "error-handling"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/anyhow" +rust-version = "1.68" + +[features] +default = ["std"] +std = [] +# THIS HAS NO EFFECT. This feature remains to preserve compatibility with the +# old `backtrace` optional dependency that this crate used to have. +backtrace = [] + +[dev-dependencies] +futures = { version = "0.3", default-features = false } +rustversion = "1.0.6" +syn = { version = "2.0", features = ["full"] } +thiserror = "2" +trybuild = { version = "1.0.108", features = ["diff"] } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] diff --git a/deps/crates/vendor/anyhow/LICENSE-APACHE b/deps/crates/vendor/anyhow/LICENSE-APACHE new file mode 100644 index 00000000000000..1b5ec8b78e237b --- /dev/null +++ b/deps/crates/vendor/anyhow/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/deps/crates/vendor/anyhow/LICENSE-MIT b/deps/crates/vendor/anyhow/LICENSE-MIT new file mode 100644 index 00000000000000..31aa79387f27e7 --- /dev/null +++ b/deps/crates/vendor/anyhow/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/anyhow/README.md b/deps/crates/vendor/anyhow/README.md new file mode 100644 index 00000000000000..78225bb6603f14 --- /dev/null +++ b/deps/crates/vendor/anyhow/README.md @@ -0,0 +1,179 @@ +Anyhow ¯\\\_(°ペ)\_/¯ +========================== + +[github](https://github.com/dtolnay/anyhow) +[crates.io](https://crates.io/crates/anyhow) +[docs.rs](https://docs.rs/anyhow) +[build status](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster) + +This library provides [`anyhow::Error`][Error], a trait object based error type +for easy idiomatic error handling in Rust applications. + +[Error]: https://docs.rs/anyhow/1.0/anyhow/struct.Error.html + +```toml +[dependencies] +anyhow = "1.0" +``` + +
+ +## Details + +- Use `Result`, or equivalently `anyhow::Result`, as the + return type of any fallible function. + + Within the function, use `?` to easily propagate any error that implements the + [`std::error::Error`] trait. + + ```rust + use anyhow::Result; + + fn get_cluster_info() -> Result { + let config = std::fs::read_to_string("cluster.json")?; + let map: ClusterMap = serde_json::from_str(&config)?; + Ok(map) + } + ``` + + [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html + +- Attach context to help the person troubleshooting the error understand where + things went wrong. A low-level error like "No such file or directory" can be + annoying to debug without more context about what higher level step the + application was in the middle of. + + ```rust + use anyhow::{Context, Result}; + + fn main() -> Result<()> { + ... + it.detach().context("Failed to detach the important thing")?; + + let content = std::fs::read(path) + .with_context(|| format!("Failed to read instrs from {}", path))?; + ... + } + ``` + + ```console + Error: Failed to read instrs from ./path/to/instrs.json + + Caused by: + No such file or directory (os error 2) + ``` + +- Downcasting is supported and can be by value, by shared reference, or by + mutable reference as needed. + + ```rust + // If the error was caused by redaction, then return a + // tombstone instead of the content. + match root_cause.downcast_ref::() { + Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), + None => Err(error), + } + ``` + +- If using Rust ≥ 1.65, a backtrace is captured and printed with the error if + the underlying error type does not already provide its own. In order to see + backtraces, they must be enabled through the environment variables described + in [`std::backtrace`]: + + - If you want panics and errors to both have backtraces, set + `RUST_BACKTRACE=1`; + - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; + - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and + `RUST_LIB_BACKTRACE=0`. + + [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables + +- Anyhow works with any error type that has an impl of `std::error::Error`, + including ones defined in your crate. We do not bundle a `derive(Error)` macro + but you can write the impls yourself or use a standalone macro like + [thiserror]. + + ```rust + use thiserror::Error; + + #[derive(Error, Debug)] + pub enum FormatError { + #[error("Invalid header (expected {expected:?}, got {found:?})")] + InvalidHeader { + expected: String, + found: String, + }, + #[error("Missing attribute: {0}")] + MissingAttribute(String), + } + ``` + +- One-off error messages can be constructed using the `anyhow!` macro, which + supports string interpolation and produces an `anyhow::Error`. + + ```rust + return Err(anyhow!("Missing attribute: {}", missing)); + ``` + + A `bail!` macro is provided as a shorthand for the same early return. + + ```rust + bail!("Missing attribute: {}", missing); + ``` + +
+ +## No-std support + +In no_std mode, almost all of the same API is available and works the same way. +To depend on Anyhow in no_std mode, disable our default enabled "std" feature in +Cargo.toml. A global allocator is required. + +```toml +[dependencies] +anyhow = { version = "1.0", default-features = false } +``` + +With versions of Rust older than 1.81, no_std mode may require an additional +`.map_err(Error::msg)` when working with a non-Anyhow error type inside a +function that returns Anyhow's error type, as the trait that `?`-based error +conversions are defined by is only available in std in those old versions. + +
+ +## Comparison to failure + +The `anyhow::Error` type works something like `failure::Error`, but unlike +failure ours is built around the standard library's `std::error::Error` trait +rather than a separate trait `failure::Fail`. The standard library has adopted +the necessary improvements for this to be possible as part of [RFC 2504]. + +[RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md + +
+ +## Comparison to thiserror + +Use Anyhow if you don't care what error type your functions return, you just +want it to be easy. This is common in application code. Use [thiserror] if you +are a library that wants to design your own dedicated error type(s) so that on +failures the caller gets exactly the information that you choose. + +[thiserror]: https://github.com/dtolnay/thiserror + +
+ +#### License + + +Licensed under either of
Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/deps/crates/vendor/anyhow/build.rs b/deps/crates/vendor/anyhow/build.rs new file mode 100644 index 00000000000000..f4fbc94d5f9ce5 --- /dev/null +++ b/deps/crates/vendor/anyhow/build.rs @@ -0,0 +1,194 @@ +#![allow(clippy::uninlined_format_args)] + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::ErrorKind; +use std::iter; +use std::path::Path; +use std::process::{self, Command, Stdio}; +use std::str; + +fn main() { + if cfg!(feature = "std") { + println!("cargo:rerun-if-changed=src/nightly.rs"); + + let error_generic_member_access; + let consider_rustc_bootstrap; + if compile_probe(false) { + // This is a nightly or dev compiler, so it supports unstable + // features regardless of RUSTC_BOOTSTRAP. No need to rerun build + // script if RUSTC_BOOTSTRAP is changed. + error_generic_member_access = true; + consider_rustc_bootstrap = false; + } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") { + if compile_probe(true) { + // This is a stable or beta compiler for which the user has set + // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build + // script if they change it. + error_generic_member_access = true; + consider_rustc_bootstrap = true; + } else if rustc_bootstrap == "1" { + // This compiler does not support the generic member access API + // in the form that anyhow expects. No need to pay attention to + // RUSTC_BOOTSTRAP. + error_generic_member_access = false; + consider_rustc_bootstrap = false; + } else { + // This is a stable or beta compiler for which RUSTC_BOOTSTRAP + // is set to restrict the use of unstable features by this + // crate. + error_generic_member_access = false; + consider_rustc_bootstrap = true; + } + } else { + // Without RUSTC_BOOTSTRAP, this compiler does not support the + // generic member access API in the form that anyhow expects, but + // try again if the user turns on unstable features. + error_generic_member_access = false; + consider_rustc_bootstrap = true; + } + + if error_generic_member_access { + println!("cargo:rustc-cfg=error_generic_member_access"); + } + + if consider_rustc_bootstrap { + println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); + } + } + + let Some(rustc) = rustc_minor_version() else { + return; + }; + + if rustc >= 80 { + println!("cargo:rustc-check-cfg=cfg(anyhow_build_probe)"); + println!("cargo:rustc-check-cfg=cfg(anyhow_nightly_testing)"); + println!("cargo:rustc-check-cfg=cfg(anyhow_no_clippy_format_args)"); + println!("cargo:rustc-check-cfg=cfg(anyhow_no_core_error)"); + println!("cargo:rustc-check-cfg=cfg(error_generic_member_access)"); + } + + if rustc < 81 { + // core::error::Error + // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror + println!("cargo:rustc-cfg=anyhow_no_core_error"); + } + + if rustc < 85 { + // #[clippy::format_args] + // https://doc.rust-lang.org/1.85.1/clippy/attribs.html#clippyformat_args + println!("cargo:rustc-cfg=anyhow_no_clippy_format_args"); + } +} + +fn compile_probe(rustc_bootstrap: bool) -> bool { + if env::var_os("RUSTC_STAGE").is_some() { + // We are running inside rustc bootstrap. This is a highly non-standard + // environment with issues such as: + // + // https://github.com/rust-lang/cargo/issues/11138 + // https://github.com/rust-lang/rust/issues/114839 + // + // Let's just not use nightly features here. + return false; + } + + let rustc = cargo_env_var("RUSTC"); + let out_dir = cargo_env_var("OUT_DIR"); + let out_subdir = Path::new(&out_dir).join("probe"); + let probefile = Path::new("src").join("nightly.rs"); + + if let Err(err) = fs::create_dir(&out_subdir) { + if err.kind() != ErrorKind::AlreadyExists { + eprintln!("Failed to create {}: {}", out_subdir.display(), err); + process::exit(1); + } + } + + let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let rustc_workspace_wrapper = + env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let mut rustc = rustc_wrapper + .into_iter() + .chain(rustc_workspace_wrapper) + .chain(iter::once(rustc)); + let mut cmd = Command::new(rustc.next().unwrap()); + cmd.args(rustc); + + if !rustc_bootstrap { + cmd.env_remove("RUSTC_BOOTSTRAP"); + } + + cmd.stderr(Stdio::null()) + .arg("--cfg=anyhow_build_probe") + .arg("--edition=2018") + .arg("--crate-name=anyhow") + .arg("--crate-type=lib") + .arg("--cap-lints=allow") + .arg("--emit=dep-info,metadata") + .arg("--out-dir") + .arg(&out_subdir) + .arg(probefile); + + if let Some(target) = env::var_os("TARGET") { + cmd.arg("--target").arg(target); + } + + // If Cargo wants to set RUSTFLAGS, use that. + if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { + if !rustflags.is_empty() { + for arg in rustflags.split('\x1f') { + cmd.arg(arg); + } + } + } + + let success = match cmd.status() { + Ok(status) => status.success(), + Err(_) => false, + }; + + // Clean up to avoid leaving nondeterministic absolute paths in the dep-info + // file in OUT_DIR, which causes nonreproducible builds in build systems + // that treat the entire OUT_DIR as an artifact. + if let Err(err) = fs::remove_dir_all(&out_subdir) { + // libc::ENOTEMPTY + // Some filesystems (NFSv3) have timing issues under load where '.nfs*' + // dummy files can continue to get created for a short period after the + // probe command completes, breaking remove_dir_all. + // To be replaced with ErrorKind::DirectoryNotEmpty (Rust 1.83+). + const ENOTEMPTY: i32 = 39; + + if !(err.kind() == ErrorKind::NotFound + || (cfg!(target_os = "linux") && err.raw_os_error() == Some(ENOTEMPTY))) + { + eprintln!("Failed to clean up {}: {}", out_subdir.display(), err); + process::exit(1); + } + } + + success +} + +fn rustc_minor_version() -> Option { + let rustc = cargo_env_var("RUSTC"); + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + pieces.next()?.parse().ok() +} + +fn cargo_env_var(key: &str) -> OsString { + env::var_os(key).unwrap_or_else(|| { + eprintln!( + "Environment variable ${} is not set during execution of build script", + key, + ); + process::exit(1); + }) +} diff --git a/deps/crates/vendor/anyhow/rust-toolchain.toml b/deps/crates/vendor/anyhow/rust-toolchain.toml new file mode 100644 index 00000000000000..20fe888c30ab44 --- /dev/null +++ b/deps/crates/vendor/anyhow/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +components = ["rust-src"] diff --git a/deps/crates/vendor/anyhow/src/backtrace.rs b/deps/crates/vendor/anyhow/src/backtrace.rs new file mode 100644 index 00000000000000..d9ae520a9c74ad --- /dev/null +++ b/deps/crates/vendor/anyhow/src/backtrace.rs @@ -0,0 +1,48 @@ +#[cfg(feature = "std")] +pub(crate) use std::backtrace::Backtrace; + +#[cfg(not(feature = "std"))] +pub(crate) enum Backtrace {} + +#[cfg(feature = "std")] +macro_rules! backtrace { + () => { + Some(std::backtrace::Backtrace::capture()) + }; +} + +#[cfg(not(feature = "std"))] +macro_rules! backtrace { + () => { + None + }; +} + +#[cfg(error_generic_member_access)] +macro_rules! backtrace_if_absent { + ($err:expr) => { + match $crate::nightly::request_ref_backtrace($err as &dyn core::error::Error) { + Some(_) => None, + None => backtrace!(), + } + }; +} + +#[cfg(all(not(error_generic_member_access), feature = "std"))] +macro_rules! backtrace_if_absent { + ($err:expr) => { + backtrace!() + }; +} + +#[cfg(all(not(anyhow_no_core_error), not(feature = "std")))] +macro_rules! backtrace_if_absent { + ($err:expr) => { + None + }; +} + +fn _assert_send_sync() { + fn assert() {} + assert::(); +} diff --git a/deps/crates/vendor/anyhow/src/chain.rs b/deps/crates/vendor/anyhow/src/chain.rs new file mode 100644 index 00000000000000..e56bc6696280ef --- /dev/null +++ b/deps/crates/vendor/anyhow/src/chain.rs @@ -0,0 +1,102 @@ +use self::ChainState::*; +use crate::StdError; + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use alloc::vec::{self, Vec}; + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +pub(crate) use crate::Chain; + +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] +pub(crate) struct Chain<'a> { + state: ChainState<'a>, +} + +#[derive(Clone)] +pub(crate) enum ChainState<'a> { + Linked { + next: Option<&'a (dyn StdError + 'static)>, + }, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + Buffered { + rest: vec::IntoIter<&'a (dyn StdError + 'static)>, + }, +} + +impl<'a> Chain<'a> { + #[cold] + pub fn new(head: &'a (dyn StdError + 'static)) -> Self { + Chain { + state: ChainState::Linked { next: Some(head) }, + } + } +} + +impl<'a> Iterator for Chain<'a> { + type Item = &'a (dyn StdError + 'static); + + fn next(&mut self) -> Option { + match &mut self.state { + Linked { next } => { + let error = (*next)?; + *next = error.source(); + Some(error) + } + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + Buffered { rest } => rest.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl DoubleEndedIterator for Chain<'_> { + fn next_back(&mut self) -> Option { + match &mut self.state { + Linked { mut next } => { + let mut rest = Vec::new(); + while let Some(cause) = next { + next = cause.source(); + rest.push(cause); + } + let mut rest = rest.into_iter(); + let last = rest.next_back(); + self.state = Buffered { rest }; + last + } + Buffered { rest } => rest.next_back(), + } + } +} + +impl ExactSizeIterator for Chain<'_> { + fn len(&self) -> usize { + match &self.state { + Linked { mut next } => { + let mut len = 0; + while let Some(cause) = next { + next = cause.source(); + len += 1; + } + len + } + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + Buffered { rest } => rest.len(), + } + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl Default for Chain<'_> { + fn default() -> Self { + Chain { + state: ChainState::Buffered { + rest: Vec::new().into_iter(), + }, + } + } +} diff --git a/deps/crates/vendor/anyhow/src/context.rs b/deps/crates/vendor/anyhow/src/context.rs new file mode 100644 index 00000000000000..52e6ab6fdb315e --- /dev/null +++ b/deps/crates/vendor/anyhow/src/context.rs @@ -0,0 +1,193 @@ +use crate::error::ContextError; +use crate::{Context, Error, StdError}; +use core::convert::Infallible; +use core::fmt::{self, Debug, Display, Write}; + +#[cfg(error_generic_member_access)] +use crate::nightly::{self, Request}; + +mod ext { + use super::*; + + pub trait StdError { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static; + } + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + impl StdError for E + where + E: crate::StdError + Send + Sync + 'static, + { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static, + { + let backtrace = backtrace_if_absent!(&self); + Error::construct_from_context(context, self, backtrace) + } + } + + impl StdError for Error { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static, + { + self.context(context) + } + } +} + +impl Context for Result +where + E: ext::StdError + Send + Sync + 'static, +{ + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static, + { + // Not using map_err to save 2 useless frames off the captured backtrace + // in ext_context. + match self { + Ok(ok) => Ok(ok), + Err(error) => Err(error.ext_context(context)), + } + } + + fn with_context(self, context: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + match self { + Ok(ok) => Ok(ok), + Err(error) => Err(error.ext_context(context())), + } + } +} + +/// ``` +/// # type T = (); +/// # +/// use anyhow::{Context, Result}; +/// +/// fn maybe_get() -> Option { +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unimplemented!() +/// } +/// +/// fn demo() -> Result<()> { +/// let t = maybe_get().context("there is no T")?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unimplemented!() +/// } +/// ``` +impl Context for Option { + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static, + { + // Not using ok_or_else to save 2 useless frames off the captured + // backtrace. + match self { + Some(ok) => Ok(ok), + None => Err(Error::construct_from_display(context, backtrace!())), + } + } + + fn with_context(self, context: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + match self { + Some(ok) => Ok(ok), + None => Err(Error::construct_from_display(context(), backtrace!())), + } + } +} + +impl Debug for ContextError +where + C: Display, + E: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Error") + .field("context", &Quoted(&self.context)) + .field("source", &self.error) + .finish() + } +} + +impl Display for ContextError +where + C: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.context, f) + } +} + +impl StdError for ContextError +where + C: Display, + E: StdError + 'static, +{ + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.error) + } + + #[cfg(error_generic_member_access)] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + nightly::provide(&self.error, request); + } +} + +impl StdError for ContextError +where + C: Display, +{ + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) }) + } + + #[cfg(error_generic_member_access)] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + Error::provide(&self.error, request); + } +} + +struct Quoted(C); + +impl Debug for Quoted +where + C: Display, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_char('"')?; + Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; + formatter.write_char('"')?; + Ok(()) + } +} + +impl Write for Quoted<&mut fmt::Formatter<'_>> { + fn write_str(&mut self, s: &str) -> fmt::Result { + Display::fmt(&s.escape_debug(), self.0) + } +} + +pub(crate) mod private { + use super::*; + + pub trait Sealed {} + + impl Sealed for Result where E: ext::StdError {} + impl Sealed for Option {} +} diff --git a/deps/crates/vendor/anyhow/src/ensure.rs b/deps/crates/vendor/anyhow/src/ensure.rs new file mode 100644 index 00000000000000..795757d4b77561 --- /dev/null +++ b/deps/crates/vendor/anyhow/src/ensure.rs @@ -0,0 +1,935 @@ +use crate::Error; +use alloc::string::String; +use core::fmt::{self, Debug, Write}; +use core::mem::MaybeUninit; +use core::ptr; +use core::slice; +use core::str; + +#[doc(hidden)] +pub trait BothDebug { + fn __dispatch_ensure(self, msg: &'static str) -> Error; +} + +impl BothDebug for (A, B) +where + A: Debug, + B: Debug, +{ + fn __dispatch_ensure(self, msg: &'static str) -> Error { + render(msg, &self.0, &self.1) + } +} + +#[doc(hidden)] +pub trait NotBothDebug { + fn __dispatch_ensure(self, msg: &'static str) -> Error; +} + +impl NotBothDebug for &(A, B) { + fn __dispatch_ensure(self, msg: &'static str) -> Error { + Error::msg(msg) + } +} + +struct Buf { + bytes: [MaybeUninit; 40], + written: usize, +} + +impl Buf { + fn new() -> Self { + Buf { + bytes: [MaybeUninit::uninit(); 40], + written: 0, + } + } + + fn as_str(&self) -> &str { + unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + self.bytes.as_ptr().cast::(), + self.written, + )) + } + } +} + +impl Write for Buf { + fn write_str(&mut self, s: &str) -> fmt::Result { + if s.bytes().any(|b| b == b' ' || b == b'\n') { + return Err(fmt::Error); + } + + let remaining = self.bytes.len() - self.written; + if s.len() > remaining { + return Err(fmt::Error); + } + + unsafe { + ptr::copy_nonoverlapping( + s.as_ptr(), + self.bytes.as_mut_ptr().add(self.written).cast::(), + s.len(), + ); + } + self.written += s.len(); + Ok(()) + } +} + +fn render(msg: &'static str, lhs: &dyn Debug, rhs: &dyn Debug) -> Error { + let mut lhs_buf = Buf::new(); + if fmt::write(&mut lhs_buf, format_args!("{:?}", lhs)).is_ok() { + let mut rhs_buf = Buf::new(); + if fmt::write(&mut rhs_buf, format_args!("{:?}", rhs)).is_ok() { + let lhs_str = lhs_buf.as_str(); + let rhs_str = rhs_buf.as_str(); + // "{msg} ({lhs} vs {rhs})" + let len = msg.len() + 2 + lhs_str.len() + 4 + rhs_str.len() + 1; + let mut string = String::with_capacity(len); + string.push_str(msg); + string.push_str(" ("); + string.push_str(lhs_str); + string.push_str(" vs "); + string.push_str(rhs_str); + string.push(')'); + return Error::msg(string); + } + } + Error::msg(msg) +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __parse_ensure { + (atom () $bail:tt $fuel:tt {($($rhs:tt)+) ($($lhs:tt)+) $op:tt} $dup:tt $(,)?) => { + $crate::__fancy_ensure!($($lhs)+, $op, $($rhs)+) + }; + + // low precedence control flow constructs + + (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt $dup:tt return $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt $dup:tt break $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt $dup:tt continue $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt $dup:tt yield $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt $dup:tt move $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + // unary operators + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($deref:tt $($dup:tt)*) * $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $deref) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($not:tt $($dup:tt)*) ! $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $not) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($neg:tt $($dup:tt)*) - $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $neg) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($let:tt $($dup:tt)*) let $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $let) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($lifetime:tt $colon:tt $($dup:tt)*) $label:lifetime : $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $lifetime $colon) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) &mut $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $raw:tt $mut:tt $($dup:tt)*) &raw mut $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $and $raw $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $raw:tt $const:tt $($dup:tt)*) &raw const $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $and $raw $const) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) & $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($andand:tt $mut:tt $($dup:tt)*) &&mut $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $andand $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($andand:tt $raw:tt $mut:tt $($dup:tt)*) &&raw mut $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $andand $raw $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($andand:tt $raw:tt $const:tt $($dup:tt)*) &&raw const $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $andand $raw $const) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($andand:tt $($dup:tt)*) && $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $andand) $($parse)*} ($($rest)*) $($rest)*) + }; + + // control flow constructs + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($if:tt $($dup:tt)*) if $($rest:tt)*) => { + $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* $if) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($match:tt $($dup:tt)*) match $($rest:tt)*) => { + $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* $match) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($while:tt $($dup:tt)*) while $($rest:tt)*) => { + $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* $while) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($for:tt $($dup:tt)*) for $($rest:tt)*) => { + $crate::__parse_ensure!(pat (cond $stack) $bail ($($fuel)*) {($($buf)* $for) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom (cond $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($block:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(cond $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (cond $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($else:tt $if:tt $($dup:tt)*) else if $($rest:tt)*) => { + $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* $else $if) $($parse)*} ($($rest)*) $($rest)*) + }; + + (cond $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($else:tt $brace:tt $($dup:tt)*) else {$($block:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $else $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (cond $stack:tt $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + // atomic expressions + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $($dup:tt)*) ($($content:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bracket:tt $($dup:tt)*) [$($array:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $bracket) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($block:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($loop:tt $block:tt $($dup:tt)*) loop {$($body:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $loop $block) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($async:tt $block:tt $($dup:tt)*) async {$($body:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $async $block) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($async:tt $move:tt $block:tt $($dup:tt)*) async move {$($body:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $async $move $block) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($unsafe:tt $block:tt $($dup:tt)*) unsafe {$($body:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $unsafe $block) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($const:tt $block:tt $($dup:tt)*) const {$($body:tt)*} $($rest:tt)*) => { + // TODO: this is mostly useless due to https://github.com/rust-lang/rust/issues/86730 + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $const $block) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*) + }; + + // path expressions + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (epath (atom $stack))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => { + $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: << $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (tpath (arglist (epath $stack)))) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt :: <- - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $larrow:tt $($dup:tt)*) :: <- $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $larrow) $($parse)*} ($($dup)*) $($dup)*) + }; + + (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(epath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! ($($mac:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! [$($mac:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! {$($mac:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (epath (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + // trailer expressions + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $($dup:tt)*) ($($call:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bracket:tt $($dup:tt)*) [$($index:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $bracket) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($init:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($question:tt $($dup:tt)*) ? $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $question) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $langle:tt $($dup:tt)*) . $i:ident :: < $($rest:tt)*) => { + $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $langle:tt $($dup:tt)*) . $i:ident :: << $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (tpath (arglist (atom $stack)))) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt . $i:ident :: <- - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $larrow:tt $($dup:tt)*) . $i:ident :: <- $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $larrow) $($parse)*} ($($dup)*) $($dup)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $field:tt $($dup:tt)*) . $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $field) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt . - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $index:tt $($dup:tt)*) . $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $index) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($as:tt $($dup:tt)*) as $($rest:tt)*) => { + $crate::__parse_ensure!(type (atom $stack) $bail ($($fuel)*) {($($buf)* $as) $($parse)*} ($($rest)*) $($rest)*) + }; + + // types + + (type ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bracket:tt $($dup:tt)*) [$($content:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bracket) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $($dup:tt)*) ($($content:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($star:tt $const:tt $($dup:tt)*) *const $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $star $const) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($star:tt $mut:tt $($dup:tt)*) *mut $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $star $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $mut:tt $($dup:tt)*) & $l:lifetime mut $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) & mut $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $($dup:tt)*) & $l:lifetime $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) & $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $mut:tt $($dup:tt)*) && $l:lifetime mut $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) && mut $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $($dup:tt)*) && $l:lifetime $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt unsafe extern - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($unsafe:tt $(extern $($abi:literal)?)? fn $($dup:tt)*) unsafe $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $unsafe) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt extern - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($extern:tt $abi:tt fn $($dup:tt)*) extern $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $extern $abi) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($extern:tt fn $($dup:tt)*) extern $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $extern) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($fn:tt $paren:tt $arrow:tt $($dup:tt)*) fn ($($args:tt)*) -> $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $fn $paren $arrow) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($fn:tt $paren:tt $($dup:tt)*) fn ($($args:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $fn $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($impl:tt $($dup:tt)*) impl $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $impl) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dyn:tt $($dup:tt)*) dyn $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $dyn) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($wild:tt $($dup:tt)*) _ $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $wild) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($never:tt $($dup:tt)*) ! $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $never) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($for:tt $langle:tt $($dup:tt)*) for < $($rest:tt)*) => { + $crate::__parse_ensure!(generic (type $stack) $bail ($($fuel)*) {($($buf)* $for $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + // path types + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (tpath $stack)) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) << $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (tpath (arglist (tpath $stack)))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt <- - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($larrow:tt $($dup:tt)*) <- $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $larrow) $($parse)*} ($($dup)*) $($dup)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => { + $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: << $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (tpath (arglist (tpath $stack)))) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt :: <- - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $larrow:tt $($dup:tt)*) :: <- $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $larrow) $($parse)*} ($($dup)*) $($dup)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $arrow:tt $($dup:tt)*) ($($args:tt)*) -> $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $paren $arrow) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $($dup:tt)*) ($($args:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!(object $stack $bail ($($fuel)*) {($($buf)* $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $paren:tt $arrow:tt $($dup:tt)*) :: ($($args:tt)*) -> $($rest:tt)*) => { + $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $colons $paren $arrow) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $paren:tt $($dup:tt)*) :: ($($args:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!(object $stack $bail ($($fuel)*) {($($buf)* $colons $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! ($($mac:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! [$($mac:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! {$($mac:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) + }; + + (tpath $stack:tt $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!(object $stack $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + // qualified paths + + (qpath (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $colons:tt $ident:tt $($dup:tt)*) >> :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (qpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $colons:tt $ident:tt $($dup:tt)*) > :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (qpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($as:tt $($dup:tt)*) as $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath $stack) $bail ($($fuel)*) {($($buf)* $as) $($parse)*} ($($rest)*) $($rest)*) + }; + + // trait objects + + (object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $colons:tt $ident:tt $($dup:tt)*) + :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $ident:tt $($dup:tt)*) + $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (object (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + (object ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + // angle bracketed generic arguments + + (generic (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) {($($buf)*) $($parse)*} ($rangle $($rest)*) $rangle $($rest)*) + }; + + (generic $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($neg:tt $($dup:tt)*) - $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $neg) $($parse)*} ($($dup)*) $($dup)*) + }; + + (generic $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($block:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($lifetime:tt $($dup:tt)*) $l:lifetime $($rest:tt)*) => { + $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $lifetime) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($assoc:tt $eq:tt $($dup:tt)*) $ident:ident = $($rest:tt)*) => { + $crate::__parse_ensure!(type (arglist $stack) $bail ($($fuel)*) {($($buf)* $assoc $eq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (generic $stack:tt $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { + $crate::__parse_ensure!(type (arglist $stack) $bail ($($fuel)*) $parse $dup $($rest)*) + }; + + (arglist $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($comma:tt $($dup:tt)*) , $($rest:tt)*) => { + $crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $comma) $($parse)*} ($($rest)*) $($rest)*) + }; + + (arglist (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)*) $rangle $($parse)*} ($($rest)*) $($rest)*) + }; + + (arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => { + $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) {($($buf)*) $($parse)*} ($rangle $($rest)*) $rangle $($rest)*) + }; + + // patterns + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($pipe:tt $($dup:tt)*) | $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $pipe) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($eq:tt $($dup:tt)*) = $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $eq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($in:tt $($dup:tt)*) in $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $in) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ref:tt $($dup:tt)*) ref $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $ref) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($mut:tt $($dup:tt)*) mut $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $mut) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($at:tt $($dup:tt)*) @ $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $at) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($neg:tt $($dup:tt)*) - $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $neg) $($parse)*} ($($dup)*) $($dup)*) + }; + + (pat $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($range:tt $($dup:tt)*) .. $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $range) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($range:tt $($dup:tt)*) ..= $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $range) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) & $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($andand:tt $($dup:tt)*) && $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $andand) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $($dup:tt)*) ($($content:tt)*) $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $paren) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bracket:tt $($dup:tt)*) [$($content:tt)*] $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $bracket) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($content:tt)*} $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($wild:tt $($dup:tt)*) _ $($rest:tt)*) => { + $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $wild) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => { + $crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) + }; + + (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(type (qpath (epath (pat $stack))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) + }; + + // comparison binary operators + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($eq:tt $($dup:tt)*) == $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $eq} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($eq:tt $($dup:tt)*) == $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $eq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($le:tt $($dup:tt)*) <= $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $le} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($le:tt $($dup:tt)*) <= $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $le) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($lt:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $lt} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($lt:tt $($dup:tt)*) < $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $lt) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ne:tt $($dup:tt)*) != $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $ne} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($ne:tt $($dup:tt)*) != $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $ne) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ge:tt $($dup:tt)*) >= $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $ge} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($ge:tt $($dup:tt)*) >= $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $ge) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom (split ()) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt >> $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)* > ) > } ($($rest)*) $($rest)*) + }; + + (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => { + $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $gt} ($($rest)*) $($rest)*) + }; + + (atom (split $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $gt) $($parse)*} ($($rest)*) $($rest)*) + }; + + // high precedence binary operators + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($add:tt $($dup:tt)*) + $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $add) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($sub:tt $($dup:tt)*) - $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $sub) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($mul:tt $($dup:tt)*) * $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $mul) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($div:tt $($dup:tt)*) / $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $div) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rem:tt $($dup:tt)*) % $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $rem) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitxor:tt $($dup:tt)*) ^ $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitxor) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitand:tt $($dup:tt)*) & $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitand) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitor:tt $($dup:tt)*) | $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitor) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shl:tt $($dup:tt)*) << $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shl) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shr:tt $($dup:tt)*) >> $($rest:tt)*) => { + $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shr) $($parse)*} ($($rest)*) $($rest)*) + }; + + // low precedence binary operators + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($or:tt $($dup:tt)*) || $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $or) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($assign:tt $($dup:tt)*) = $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $assign) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($addeq:tt $($dup:tt)*) += $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $addeq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($subeq:tt $($dup:tt)*) -= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $subeq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($muleq:tt $($dup:tt)*) *= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $muleq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($diveq:tt $($dup:tt)*) /= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $diveq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($remeq:tt $($dup:tt)*) %= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $remeq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitxoreq:tt $($dup:tt)*) ^= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $bitxoreq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitandeq:tt $($dup:tt)*) &= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $bitandeq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitoreq:tt $($dup:tt)*) |= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $bitoreq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shleq:tt $($dup:tt)*) <<= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $shleq) $($parse)*} ($($rest)*) $($rest)*) + }; + + (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shreq:tt $($dup:tt)*) >>= $($rest:tt)*) => { + $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* $shreq) $($parse)*} ($($rest)*) $($rest)*) + }; + + // unrecognized expression + + ($state:tt $stack:tt ($($bail:tt)*) $($rest:tt)*) => { + $crate::__fallback_ensure!($($bail)*) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __fancy_ensure { + ($lhs:expr, $op:tt, $rhs:expr) => { + match (&$lhs, &$rhs) { + (lhs, rhs) => { + if !(lhs $op rhs) { + #[allow(unused_imports)] + use $crate::__private::{BothDebug, NotBothDebug}; + return Err((lhs, rhs).__dispatch_ensure( + $crate::__private::concat!( + "Condition failed: `", + $crate::__private::stringify!($lhs), + " ", + $crate::__private::stringify!($op), + " ", + $crate::__private::stringify!($rhs), + "`", + ), + )); + } + } + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __fallback_ensure { + ($cond:expr $(,)?) => { + if $crate::__private::not($cond) { + return $crate::__private::Err($crate::Error::msg( + $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") + )); + } + }; + ($cond:expr, $msg:literal $(,)?) => { + if $crate::__private::not($cond) { + return $crate::__private::Err($crate::__anyhow!($msg)); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if $crate::__private::not($cond) { + return $crate::__private::Err($crate::__anyhow!($err)); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if $crate::__private::not($cond) { + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); + } + }; +} diff --git a/deps/crates/vendor/anyhow/src/error.rs b/deps/crates/vendor/anyhow/src/error.rs new file mode 100644 index 00000000000000..a70d6ecc980bd1 --- /dev/null +++ b/deps/crates/vendor/anyhow/src/error.rs @@ -0,0 +1,1059 @@ +use crate::backtrace::Backtrace; +use crate::chain::Chain; +#[cfg(error_generic_member_access)] +use crate::nightly::{self, Request}; +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use crate::ptr::Mut; +use crate::ptr::{Own, Ref}; +use crate::{Error, StdError}; +use alloc::boxed::Box; +use core::any::TypeId; +use core::fmt::{self, Debug, Display}; +use core::mem::ManuallyDrop; +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use core::ops::{Deref, DerefMut}; +use core::panic::{RefUnwindSafe, UnwindSafe}; +use core::ptr; +use core::ptr::NonNull; + +impl Error { + /// Create a new error object from any error type. + /// + /// The error type must be threadsafe and `'static`, so that the `Error` + /// will be as well. + /// + /// If the error type does not provide a backtrace, a backtrace will be + /// created here to ensure that a backtrace exists. + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + #[must_use] + pub fn new(error: E) -> Self + where + E: StdError + Send + Sync + 'static, + { + let backtrace = backtrace_if_absent!(&error); + Error::construct_from_std(error, backtrace) + } + + /// Create a new error object from a printable error message. + /// + /// If the argument implements std::error::Error, prefer `Error::new` + /// instead which preserves the underlying error's cause chain and + /// backtrace. If the argument may or may not implement std::error::Error + /// now or in the future, use `anyhow!(err)` which handles either way + /// correctly. + /// + /// `Error::msg("...")` is equivalent to `anyhow!("...")` but occasionally + /// convenient in places where a function is preferable over a macro, such + /// as iterator or stream combinators: + /// + /// ``` + /// # mod ffi { + /// # pub struct Input; + /// # pub struct Output; + /// # pub async fn do_some_work(_: Input) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # use ffi::{Input, Output}; + /// # + /// use anyhow::{Error, Result}; + /// use futures::stream::{Stream, StreamExt, TryStreamExt}; + /// + /// async fn demo(stream: S) -> Result> + /// where + /// S: Stream, + /// { + /// stream + /// .then(ffi::do_some_work) // returns Result + /// .map_err(Error::msg) + /// .try_collect() + /// .await + /// } + /// ``` + #[cold] + #[must_use] + pub fn msg(message: M) -> Self + where + M: Display + Debug + Send + Sync + 'static, + { + Error::construct_from_adhoc(message, backtrace!()) + } + + /// Construct an error object from a type-erased standard library error. + /// + /// This is mostly useful for interop with other error libraries. + /// + /// # Example + /// + /// Here is a skeleton of a library that provides its own error abstraction. + /// The pair of `From` impls provide bidirectional support for `?` + /// conversion between `Report` and `anyhow::Error`. + /// + /// ``` + /// use std::error::Error as StdError; + /// + /// pub struct Report {/* ... */} + /// + /// impl From for Report + /// where + /// E: Into, + /// Result<(), E>: anyhow::Context<(), E>, + /// { + /// fn from(error: E) -> Self { + /// let anyhow_error: anyhow::Error = error.into(); + /// let boxed_error: Box = anyhow_error.into(); + /// Report::from_boxed(boxed_error) + /// } + /// } + /// + /// impl From for anyhow::Error { + /// fn from(report: Report) -> Self { + /// let boxed_error: Box = report.into_boxed(); + /// anyhow::Error::from_boxed(boxed_error) + /// } + /// } + /// + /// impl Report { + /// fn from_boxed(boxed_error: Box) -> Self { + /// todo!() + /// } + /// fn into_boxed(self) -> Box { + /// todo!() + /// } + /// } + /// + /// // Example usage: can use `?` in both directions. + /// fn a() -> anyhow::Result<()> { + /// b()?; + /// Ok(()) + /// } + /// fn b() -> Result<(), Report> { + /// a()?; + /// Ok(()) + /// } + /// ``` + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + #[must_use] + pub fn from_boxed(boxed_error: Box) -> Self { + let backtrace = backtrace_if_absent!(&*boxed_error); + Error::construct_from_boxed(boxed_error, backtrace) + } + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + pub(crate) fn construct_from_std(error: E, backtrace: Option) -> Self + where + E: StdError + Send + Sync + 'static, + { + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + object_boxed: object_boxed::, + object_reallocate_boxed: object_reallocate_boxed::, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: no_backtrace, + }; + + // Safety: passing vtable that operates on the right type E. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cold] + pub(crate) fn construct_from_adhoc(message: M, backtrace: Option) -> Self + where + M: Display + Debug + Send + Sync + 'static, + { + use crate::wrapper::MessageError; + let error: MessageError = MessageError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: object_boxed::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: object_reallocate_boxed::>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: no_backtrace, + }; + + // Safety: MessageError is repr(transparent) so it is okay for the + // vtable to allow casting the MessageError to M. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cold] + pub(crate) fn construct_from_display(message: M, backtrace: Option) -> Self + where + M: Display + Send + Sync + 'static, + { + use crate::wrapper::DisplayError; + let error: DisplayError = DisplayError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: object_boxed::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: object_reallocate_boxed::>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: no_backtrace, + }; + + // Safety: DisplayError is repr(transparent) so it is okay for the + // vtable to allow casting the DisplayError to M. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + pub(crate) fn construct_from_context( + context: C, + error: E, + backtrace: Option, + ) -> Self + where + C: Display + Send + Sync + 'static, + E: StdError + Send + Sync + 'static, + { + let error: ContextError = ContextError { context, error }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: object_boxed::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: object_reallocate_boxed::>, + object_downcast: context_downcast::, + object_drop_rest: context_drop_rest::, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: no_backtrace, + }; + + // Safety: passing vtable that operates on the right type. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + pub(crate) fn construct_from_boxed( + error: Box, + backtrace: Option, + ) -> Self { + use crate::wrapper::BoxedError; + let error = BoxedError(error); + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: object_boxed::, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: object_reallocate_boxed::, + object_downcast: object_downcast::>, + object_drop_rest: object_drop_front::>, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: no_backtrace, + }; + + // Safety: BoxedError is repr(transparent) so it is okay for the vtable + // to allow casting to Box. + unsafe { Error::construct(error, vtable, backtrace) } + } + + // Takes backtrace as argument rather than capturing it here so that the + // user sees one fewer layer of wrapping noise in the backtrace. + // + // Unsafe because the given vtable must have sensible behavior on the error + // value of type E. + #[cold] + unsafe fn construct( + error: E, + vtable: &'static ErrorVTable, + backtrace: Option, + ) -> Self + where + E: StdError + Send + Sync + 'static, + { + let inner: Box> = Box::new(ErrorImpl { + vtable, + backtrace, + _object: error, + }); + // Erase the concrete type of E from the compile-time type system. This + // is equivalent to the safe unsize coercion from Box> to + // Box> except that the + // result is a thin pointer. The necessary behavior for manipulating the + // underlying ErrorImpl is preserved in the vtable provided by the + // caller rather than a builtin fat pointer vtable. + let inner = Own::new(inner).cast::(); + Error { inner } + } + + /// Wrap the error value with additional context. + /// + /// For attaching context to a `Result` as it is propagated, the + /// [`Context`][crate::Context] extension trait may be more convenient than + /// this function. + /// + /// The primary reason to use `error.context(...)` instead of + /// `result.context(...)` via the `Context` trait would be if the context + /// needs to depend on some data held by the underlying error: + /// + /// ``` + /// # use std::fmt::{self, Debug, Display}; + /// # + /// # type T = (); + /// # + /// # impl std::error::Error for ParseError {} + /// # impl Debug for ParseError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # impl Display for ParseError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use anyhow::Result; + /// use std::fs::File; + /// use std::path::Path; + /// + /// struct ParseError { + /// line: usize, + /// column: usize, + /// } + /// + /// fn parse_impl(file: File) -> Result { + /// # const IGNORE: &str = stringify! { + /// ... + /// # }; + /// # unimplemented!() + /// } + /// + /// pub fn parse(path: impl AsRef) -> Result { + /// let file = File::open(&path)?; + /// parse_impl(file).map_err(|error| { + /// let context = format!( + /// "only the first {} lines of {} are valid", + /// error.line, path.as_ref().display(), + /// ); + /// anyhow::Error::new(error).context(context) + /// }) + /// } + /// ``` + #[cold] + #[must_use] + pub fn context(self, context: C) -> Self + where + C: Display + Send + Sync + 'static, + { + let error: ContextError = ContextError { + context, + error: self, + }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: object_boxed::>, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: object_reallocate_boxed::>, + object_downcast: context_chain_downcast::, + object_drop_rest: context_chain_drop_rest::, + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: context_backtrace::, + }; + + // As the cause is anyhow::Error, we already have a backtrace for it. + let backtrace = None; + + // Safety: passing vtable that operates on the right type. + unsafe { Error::construct(error, vtable, backtrace) } + } + + /// Get the backtrace for this Error. + /// + /// In order for the backtrace to be meaningful, one of the two environment + /// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined + /// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat + /// expensive to capture in Rust, so we don't necessarily want to be + /// capturing them all over the place all the time. + /// + /// - If you want panics and errors to both have backtraces, set + /// `RUST_BACKTRACE=1`; + /// - If you want only errors to have backtraces, set + /// `RUST_LIB_BACKTRACE=1`; + /// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and + /// `RUST_LIB_BACKTRACE=0`. + /// + /// # Stability + /// + /// Standard library backtraces are only available when using Rust ≥ + /// 1.65. On older compilers, this function is only available if the crate's + /// "backtrace" feature is enabled, and will use the `backtrace` crate as + /// the underlying backtrace implementation. The return type of this + /// function on old compilers is `&(impl Debug + Display)`. + /// + /// ```toml + /// [dependencies] + /// anyhow = { version = "1.0", features = ["backtrace"] } + /// ``` + #[cfg(feature = "std")] + pub fn backtrace(&self) -> &Backtrace { + unsafe { ErrorImpl::backtrace(self.inner.by_ref()) } + } + + /// An iterator of the chain of source errors contained by this Error. + /// + /// This iterator will visit every error in the cause chain of this error + /// object, beginning with the error that this error object was created + /// from. + /// + /// # Example + /// + /// ``` + /// use anyhow::Error; + /// use std::io; + /// + /// pub fn underlying_io_error_kind(error: &Error) -> Option { + /// for cause in error.chain() { + /// if let Some(io_error) = cause.downcast_ref::() { + /// return Some(io_error.kind()); + /// } + /// } + /// None + /// } + /// ``` + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + pub fn chain(&self) -> Chain { + unsafe { ErrorImpl::chain(self.inner.by_ref()) } + } + + /// The lowest level cause of this error — this error's cause's + /// cause's cause etc. + /// + /// The root cause is the last error in the iterator produced by + /// [`chain()`][Error::chain]. + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[allow(clippy::double_ended_iterator_last)] + pub fn root_cause(&self) -> &(dyn StdError + 'static) { + self.chain().last().unwrap() + } + + /// Returns true if `E` is the type held by this error object. + /// + /// For errors with context, this method returns true if `E` matches the + /// type of the context `C` **or** the type of the error on which the + /// context has been attached. For details about the interaction between + /// context and downcasting, [see here]. + /// + /// [see here]: crate::Context#effect-on-downcasting + pub fn is(&self) -> bool + where + E: Display + Debug + Send + Sync + 'static, + { + self.downcast_ref::().is_some() + } + + /// Attempt to downcast the error object to a concrete type. + pub fn downcast(mut self) -> Result + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + let inner = self.inner.by_mut(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) { + Some(addr) => addr.by_mut().extend(), + None => return Err(self), + }; + + // Prepare to read E out of the data structure. We'll drop the rest + // of the data structure separately so that E is not dropped. + let outer = ManuallyDrop::new(self); + + // Read E from where the vtable found it. + let error = addr.cast::().read(); + + // Drop rest of the data structure outside of E. + (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target); + + Ok(error) + } + } + + /// Downcast this error object by reference. + /// + /// # Example + /// + /// ``` + /// # use anyhow::anyhow; + /// # use std::fmt::{self, Display}; + /// # use std::task::Poll; + /// # + /// # #[derive(Debug)] + /// # enum DataStoreError { + /// # Censored(()), + /// # } + /// # + /// # impl Display for DataStoreError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl std::error::Error for DataStoreError {} + /// # + /// # const REDACTED_CONTENT: () = (); + /// # + /// # let error = anyhow!("..."); + /// # let root_cause = &error; + /// # + /// # let ret = + /// // If the error was caused by redaction, then return a tombstone instead + /// // of the content. + /// match root_cause.downcast_ref::() { + /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), + /// None => Err(error), + /// } + /// # ; + /// ``` + pub fn downcast_ref(&self) -> Option<&E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?; + Some(addr.cast::().deref()) + } + } + + /// Downcast this error object by mutable reference. + pub fn downcast_mut(&mut self) -> Option<&mut E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = + (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut(); + Some(addr.cast::().deref_mut()) + } + } + + /// Convert to a standard library error trait object. + /// + /// This is implemented as a cheap pointer cast that does not allocate or + /// deallocate memory. Like [`anyhow::Error::from_boxed`], it's useful for + /// interop with other error libraries. + /// + /// The same conversion is also available as + /// impl From<anyhow::Error> + /// for Box<dyn Error + Send + Sync + 'static>. + /// + /// If a backtrace was collected during construction of the `anyhow::Error`, + /// that backtrace remains accessible using the standard library `Error` + /// trait's provider API, but as a consequence, the resulting boxed error + /// can no longer be downcast to its original underlying type. + /// + /// ``` + #[cfg_attr(not(error_generic_member_access), doc = "# _ = stringify! {")] + /// #![feature(error_generic_member_access)] + /// + /// use anyhow::anyhow; + /// use std::backtrace::Backtrace; + /// use thiserror::Error; + /// + /// #[derive(Error, Debug)] + /// #[error("...")] + /// struct MyError; + /// + /// let anyhow_error = anyhow!(MyError); + /// println!("{}", anyhow_error.backtrace()); // has Backtrace + /// assert!(anyhow_error.downcast_ref::().is_some()); // can downcast + /// + /// let boxed_dyn_error = anyhow_error.into_boxed_dyn_error(); + /// assert!(std::error::request_ref::(&*boxed_dyn_error).is_some()); // has Backtrace + /// assert!(boxed_dyn_error.downcast_ref::().is_none()); // can no longer downcast + #[cfg_attr(not(error_generic_member_access), doc = "# };")] + /// ``` + /// + /// [`anyhow::Error::from_boxed`]: Self::from_boxed + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[must_use] + pub fn into_boxed_dyn_error(self) -> Box { + let outer = ManuallyDrop::new(self); + unsafe { + // Use vtable to attach ErrorImpl's native StdError vtable for + // the right original type E. + (vtable(outer.inner.ptr).object_boxed)(outer.inner) + } + } + + /// Convert to a standard library error trait object. + /// + /// Unlike `self.into_boxed_dyn_error()`, this method relocates the + /// underlying error into a new allocation in order to make it downcastable + /// to `&E` or `Box` for its original underlying error type. Any + /// backtrace collected during construction of the `anyhow::Error` is + /// discarded. + /// + /// ``` + #[cfg_attr(not(error_generic_member_access), doc = "# _ = stringify!{")] + /// #![feature(error_generic_member_access)] + /// + /// use anyhow::anyhow; + /// use std::backtrace::Backtrace; + /// use thiserror::Error; + /// + /// #[derive(Error, Debug)] + /// #[error("...")] + /// struct MyError; + /// + /// let anyhow_error = anyhow!(MyError); + /// println!("{}", anyhow_error.backtrace()); // has Backtrace + /// assert!(anyhow_error.downcast_ref::().is_some()); // can downcast + /// + /// let boxed_dyn_error = anyhow_error.reallocate_into_boxed_dyn_error_without_backtrace(); + /// assert!(std::error::request_ref::(&*boxed_dyn_error).is_none()); // Backtrace lost + /// assert!(boxed_dyn_error.downcast_ref::().is_some()); // can downcast to &MyError + /// assert!(boxed_dyn_error.downcast::().is_ok()); // can downcast to Box + #[cfg_attr(not(error_generic_member_access), doc = "# };")] + /// ``` + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[must_use] + pub fn reallocate_into_boxed_dyn_error_without_backtrace( + self, + ) -> Box { + let outer = ManuallyDrop::new(self); + unsafe { + // Use vtable to attach E's native StdError vtable for the right + // original type E. + (vtable(outer.inner.ptr).object_reallocate_boxed)(outer.inner) + } + } + + #[cfg(error_generic_member_access)] + pub(crate) fn provide<'a>(&'a self, request: &mut Request<'a>) { + unsafe { ErrorImpl::provide(self.inner.by_ref(), request) } + } + + // Called by thiserror when you have `#[source] anyhow::Error`. This provide + // implementation includes the anyhow::Error's Backtrace if any, unlike + // deref'ing to dyn Error where the provide implementation would include + // only the original error's Backtrace from before it got wrapped into an + // anyhow::Error. + #[cfg(error_generic_member_access)] + #[doc(hidden)] + pub fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) { + Self::provide(self, request); + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl From for Error +where + E: StdError + Send + Sync + 'static, +{ + #[cold] + fn from(error: E) -> Self { + let backtrace = backtrace_if_absent!(&error); + Error::construct_from_std(error, backtrace) + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl Deref for Error { + type Target = dyn StdError + Send + Sync + 'static; + + fn deref(&self) -> &Self::Target { + unsafe { ErrorImpl::error(self.inner.by_ref()) } + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl DerefMut for Error { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { ErrorImpl::error_mut(self.inner.by_mut()) } + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) } + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) } + } +} + +impl Drop for Error { + fn drop(&mut self) { + unsafe { + // Invoke the vtable's drop behavior. + (vtable(self.inner.ptr).object_drop)(self.inner); + } + } +} + +struct ErrorVTable { + object_drop: unsafe fn(Own), + object_ref: unsafe fn(Ref) -> Ref, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_boxed: unsafe fn(Own) -> Box, + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + object_reallocate_boxed: unsafe fn(Own) -> Box, + object_downcast: unsafe fn(Ref, TypeId) -> Option>, + object_drop_rest: unsafe fn(Own, TypeId), + #[cfg(all(not(error_generic_member_access), feature = "std"))] + object_backtrace: unsafe fn(Ref) -> Option<&Backtrace>, +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop(e: Own) { + // Cast back to ErrorImpl so that the allocator receives the correct + // Layout to deallocate the Box's memory. + let unerased_own = e.cast::>(); + drop(unsafe { unerased_own.boxed() }); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop_front(e: Own, target: TypeId) { + // Drop the fields of ErrorImpl other than E as well as the Box allocation, + // without dropping E itself. This is used by downcast after doing a + // ptr::read to take ownership of the E. + let _ = target; + let unerased_own = e.cast::>>(); + drop(unsafe { unerased_own.boxed() }); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_ref(e: Ref) -> Ref +where + E: StdError + Send + Sync + 'static, +{ + // Attach E's native StdError vtable onto a pointer to self._object. + let unerased_ref = e.cast::>(); + Ref::from_raw(unsafe { + NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object).cast_mut()) + }) +} + +// Safety: requires layout of *e to match ErrorImpl. +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +unsafe fn object_boxed(e: Own) -> Box +where + E: StdError + Send + Sync + 'static, +{ + // Attach ErrorImpl's native StdError vtable. The StdError impl is below. + let unerased_own = e.cast::>(); + unsafe { unerased_own.boxed() } +} + +// Safety: requires layout of *e to match ErrorImpl. +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +unsafe fn object_reallocate_boxed(e: Own) -> Box +where + E: StdError + Send + Sync + 'static, +{ + // Attach E's native StdError vtable. + let unerased_own = e.cast::>(); + Box::new(unsafe { unerased_own.boxed() }._object) +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_downcast(e: Ref, target: TypeId) -> Option> +where + E: 'static, +{ + if TypeId::of::() == target { + // Caller is looking for an E pointer and e is ErrorImpl, take a + // pointer to its E field. + let unerased_ref = e.cast::>(); + Some( + Ref::from_raw(unsafe { + NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object).cast_mut()) + }) + .cast::<()>(), + ) + } else { + None + } +} + +#[cfg(all(not(error_generic_member_access), feature = "std"))] +fn no_backtrace(e: Ref) -> Option<&Backtrace> { + let _ = e; + None +} + +// Safety: requires layout of *e to match ErrorImpl>. +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +unsafe fn context_downcast(e: Ref, target: TypeId) -> Option> +where + C: 'static, + E: 'static, +{ + if TypeId::of::() == target { + let unerased_ref = e.cast::>>(); + let unerased = unsafe { unerased_ref.deref() }; + Some(Ref::new(&unerased._object.context).cast::<()>()) + } else if TypeId::of::() == target { + let unerased_ref = e.cast::>>(); + let unerased = unsafe { unerased_ref.deref() }; + Some(Ref::new(&unerased._object.error).cast::<()>()) + } else { + None + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +unsafe fn context_drop_rest(e: Own, target: TypeId) +where + C: 'static, + E: 'static, +{ + // Called after downcasting by value to either the C or the E and doing a + // ptr::read to take ownership of that value. + if TypeId::of::() == target { + let unerased_own = e.cast::, E>>>(); + drop(unsafe { unerased_own.boxed() }); + } else { + let unerased_own = e.cast::>>>(); + drop(unsafe { unerased_own.boxed() }); + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_chain_downcast(e: Ref, target: TypeId) -> Option> +where + C: 'static, +{ + let unerased_ref = e.cast::>>(); + let unerased = unsafe { unerased_ref.deref() }; + if TypeId::of::() == target { + Some(Ref::new(&unerased._object.context).cast::<()>()) + } else { + // Recurse down the context chain per the inner error's vtable. + let source = &unerased._object.error; + unsafe { (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) } + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_chain_drop_rest(e: Own, target: TypeId) +where + C: 'static, +{ + // Called after downcasting by value to either the C or one of the causes + // and doing a ptr::read to take ownership of that value. + if TypeId::of::() == target { + let unerased_own = e.cast::, Error>>>(); + // Drop the entire rest of the data structure rooted in the next Error. + drop(unsafe { unerased_own.boxed() }); + } else { + let unerased_own = e.cast::>>>(); + let unerased = unsafe { unerased_own.boxed() }; + // Read the Own from the next error. + let inner = unerased._object.error.inner; + drop(unerased); + let vtable = unsafe { vtable(inner.ptr) }; + // Recursively drop the next error using the same target typeid. + unsafe { (vtable.object_drop_rest)(inner, target) }; + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +#[cfg(all(not(error_generic_member_access), feature = "std"))] +#[allow(clippy::unnecessary_wraps)] +unsafe fn context_backtrace(e: Ref) -> Option<&Backtrace> +where + C: 'static, +{ + let unerased_ref = e.cast::>>(); + let unerased = unsafe { unerased_ref.deref() }; + let backtrace = unsafe { ErrorImpl::backtrace(unerased._object.error.inner.by_ref()) }; + Some(backtrace) +} + +// NOTE: If working with `ErrorImpl<()>`, references should be avoided in favor +// of raw pointers and `NonNull`. +// repr C to ensure that E remains in the final position. +#[repr(C)] +pub(crate) struct ErrorImpl { + vtable: &'static ErrorVTable, + backtrace: Option, + // NOTE: Don't use directly. Use only through vtable. Erased type may have + // different alignment. + _object: E, +} + +// Reads the vtable out of `p`. This is the same as `p.as_ref().vtable`, but +// avoids converting `p` into a reference. +unsafe fn vtable(p: NonNull) -> &'static ErrorVTable { + // NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl. + unsafe { *(p.as_ptr() as *const &'static ErrorVTable) } +} + +// repr C to ensure that ContextError has the same layout as +// ContextError, E> and ContextError>. +#[repr(C)] +pub(crate) struct ContextError { + pub context: C, + pub error: E, +} + +impl ErrorImpl { + fn erase(&self) -> Ref { + // Erase the concrete type of E but preserve the vtable in self.vtable + // for manipulating the resulting thin pointer. This is analogous to an + // unsize coercion. + Ref::new(self).cast::() + } +} + +impl ErrorImpl { + pub(crate) unsafe fn error(this: Ref) -> &(dyn StdError + Send + Sync + 'static) { + // Use vtable to attach E's native StdError vtable for the right + // original type E. + unsafe { (vtable(this.ptr).object_ref)(this).deref() } + } + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + pub(crate) unsafe fn error_mut(this: Mut) -> &mut (dyn StdError + Send + Sync + 'static) { + // Use vtable to attach E's native StdError vtable for the right + // original type E. + unsafe { + (vtable(this.ptr).object_ref)(this.by_ref()) + .by_mut() + .deref_mut() + } + } + + #[cfg(feature = "std")] + pub(crate) unsafe fn backtrace(this: Ref) -> &Backtrace { + // This unwrap can only panic if the underlying error's backtrace method + // is nondeterministic, which would only happen in maliciously + // constructed code. + unsafe { this.deref() } + .backtrace + .as_ref() + .or_else(|| { + #[cfg(error_generic_member_access)] + return nightly::request_ref_backtrace(unsafe { Self::error(this) }); + #[cfg(not(error_generic_member_access))] + return unsafe { (vtable(this.ptr).object_backtrace)(this) }; + }) + .expect("backtrace capture failed") + } + + #[cfg(error_generic_member_access)] + unsafe fn provide<'a>(this: Ref<'a, Self>, request: &mut Request<'a>) { + if let Some(backtrace) = unsafe { &this.deref().backtrace } { + nightly::provide_ref_backtrace(request, backtrace); + } + nightly::provide(unsafe { Self::error(this) }, request); + } + + #[cold] + pub(crate) unsafe fn chain(this: Ref) -> Chain { + Chain::new(unsafe { Self::error(this) }) + } +} + +impl StdError for ErrorImpl +where + E: StdError, +{ + fn source(&self) -> Option<&(dyn StdError + 'static)> { + unsafe { ErrorImpl::error(self.erase()).source() } + } + + #[cfg(error_generic_member_access)] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + unsafe { ErrorImpl::provide(self.erase(), request) } + } +} + +impl Debug for ErrorImpl +where + E: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + unsafe { ErrorImpl::debug(self.erase(), formatter) } + } +} + +impl Display for ErrorImpl +where + E: Display, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + unsafe { Display::fmt(ErrorImpl::error(self.erase()), formatter) } + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl From for Box { + #[cold] + fn from(error: Error) -> Self { + error.into_boxed_dyn_error() + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl From for Box { + #[cold] + fn from(error: Error) -> Self { + error.into_boxed_dyn_error() + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl From for Box { + #[cold] + fn from(error: Error) -> Self { + error.into_boxed_dyn_error() + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl AsRef for Error { + fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { + &**self + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl AsRef for Error { + fn as_ref(&self) -> &(dyn StdError + 'static) { + &**self + } +} + +impl UnwindSafe for Error {} +impl RefUnwindSafe for Error {} diff --git a/deps/crates/vendor/anyhow/src/fmt.rs b/deps/crates/vendor/anyhow/src/fmt.rs new file mode 100644 index 00000000000000..9a108cba0a9936 --- /dev/null +++ b/deps/crates/vendor/anyhow/src/fmt.rs @@ -0,0 +1,158 @@ +use crate::chain::Chain; +use crate::error::ErrorImpl; +use crate::ptr::Ref; +use core::fmt::{self, Debug, Write}; + +impl ErrorImpl { + pub(crate) unsafe fn display(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", unsafe { Self::error(this) })?; + + if f.alternate() { + let chain = unsafe { Self::chain(this) }; + for cause in chain.skip(1) { + write!(f, ": {}", cause)?; + } + } + + Ok(()) + } + + pub(crate) unsafe fn debug(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { + let error = unsafe { Self::error(this) }; + + if f.alternate() { + return Debug::fmt(error, f); + } + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + let multiple = cause.source().is_some(); + for (n, error) in Chain::new(cause).enumerate() { + writeln!(f)?; + let mut indented = Indented { + inner: f, + number: if multiple { Some(n) } else { None }, + started: false, + }; + write!(indented, "{}", error)?; + } + } + + #[cfg(feature = "std")] + { + use alloc::string::ToString; + use std::backtrace::BacktraceStatus; + + let backtrace = unsafe { Self::backtrace(this) }; + if let BacktraceStatus::Captured = backtrace.status() { + let mut backtrace = backtrace.to_string(); + write!(f, "\n\n")?; + if backtrace.starts_with("stack backtrace:") { + // Capitalize to match "Caused by:" + backtrace.replace_range(0..1, "S"); + } else { + // "stack backtrace:" prefix was removed in + // https://github.com/rust-lang/backtrace-rs/pull/286 + writeln!(f, "Stack backtrace:")?; + } + backtrace.truncate(backtrace.trim_end().len()); + write!(f, "{}", backtrace)?; + } + } + + Ok(()) + } +} + +struct Indented<'a, D> { + inner: &'a mut D, + number: Option, + started: bool, +} + +impl Write for Indented<'_, T> +where + T: Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if !self.started { + self.started = true; + match self.number { + Some(number) => write!(self.inner, "{: >5}: ", number)?, + None => self.inner.write_str(" ")?, + } + } else if i > 0 { + self.inner.write_char('\n')?; + if self.number.is_some() { + self.inner.write_str(" ")?; + } else { + self.inner.write_str(" ")?; + } + } + + self.inner.write_str(line)?; + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::String; + + #[test] + fn one_digit() { + let input = "verify\nthis"; + let expected = " 2: verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: Some(2), + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } + + #[test] + fn two_digits() { + let input = "verify\nthis"; + let expected = " 12: verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: Some(12), + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } + + #[test] + fn no_digits() { + let input = "verify\nthis"; + let expected = " verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: None, + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } +} diff --git a/deps/crates/vendor/anyhow/src/kind.rs b/deps/crates/vendor/anyhow/src/kind.rs new file mode 100644 index 00000000000000..a9f40c33d42970 --- /dev/null +++ b/deps/crates/vendor/anyhow/src/kind.rs @@ -0,0 +1,121 @@ +// Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`. +// +// When anyhow! is given a single expr argument to turn into anyhow::Error, we +// want the resulting Error to pick up the input's implementation of source() +// and backtrace() if it has a std::error::Error impl, otherwise require nothing +// more than Display and Debug. +// +// Expressed in terms of specialization, we want something like: +// +// trait AnyhowNew { +// fn new(self) -> Error; +// } +// +// impl AnyhowNew for T +// where +// T: Display + Debug + Send + Sync + 'static, +// { +// default fn new(self) -> Error { +// /* no std error impl */ +// } +// } +// +// impl AnyhowNew for T +// where +// T: std::error::Error + Send + Sync + 'static, +// { +// fn new(self) -> Error { +// /* use std error's source() and backtrace() */ +// } +// } +// +// Since specialization is not stable yet, instead we rely on autoref behavior +// of method resolution to perform tagged dispatch. Here we have two traits +// AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is +// implemented whether or not the caller's type has a std error impl, while +// TraitKind is implemented only when a std error impl does exist. The ambiguity +// is resolved by AdhocKind requiring an extra autoref so that it has lower +// precedence. +// +// The anyhow! macro will set up the call in this form: +// +// #[allow(unused_imports)] +// use $crate::__private::{AdhocKind, TraitKind}; +// let error = $msg; +// (&error).anyhow_kind().new(error) + +use crate::Error; +use core::fmt::{Debug, Display}; + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use crate::StdError; +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use alloc::boxed::Box; + +pub struct Adhoc; + +#[doc(hidden)] +pub trait AdhocKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Adhoc { + Adhoc + } +} + +impl AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} + +impl Adhoc { + #[cold] + pub fn new(self, message: M) -> Error + where + M: Display + Debug + Send + Sync + 'static, + { + Error::construct_from_adhoc(message, backtrace!()) + } +} + +pub struct Trait; + +#[doc(hidden)] +pub trait TraitKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Trait { + Trait + } +} + +impl TraitKind for E where E: Into {} + +impl Trait { + #[cold] + pub fn new(self, error: E) -> Error + where + E: Into, + { + error.into() + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +pub struct Boxed; + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +#[doc(hidden)] +pub trait BoxedKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Boxed { + Boxed + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl BoxedKind for Box {} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl Boxed { + #[cold] + pub fn new(self, error: Box) -> Error { + let backtrace = backtrace_if_absent!(&*error); + Error::construct_from_boxed(error, backtrace) + } +} diff --git a/deps/crates/vendor/anyhow/src/lib.rs b/deps/crates/vendor/anyhow/src/lib.rs new file mode 100644 index 00000000000000..0b5f69fb03c57f --- /dev/null +++ b/deps/crates/vendor/anyhow/src/lib.rs @@ -0,0 +1,728 @@ +//! [![github]](https://github.com/dtolnay/anyhow) [![crates-io]](https://crates.io/crates/anyhow) [![docs-rs]](https://docs.rs/anyhow) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! This library provides [`anyhow::Error`][Error], a trait object based error +//! type for easy idiomatic error handling in Rust applications. +//! +//!
+//! +//! # Details +//! +//! - Use `Result`, or equivalently `anyhow::Result`, as +//! the return type of any fallible function. +//! +//! Within the function, use `?` to easily propagate any error that implements +//! the [`std::error::Error`] trait. +//! +//! ``` +//! # pub trait Deserialize {} +//! # +//! # mod serde_json { +//! # use super::Deserialize; +//! # use std::io; +//! # +//! # pub fn from_str(json: &str) -> io::Result { +//! # unimplemented!() +//! # } +//! # } +//! # +//! # struct ClusterMap; +//! # +//! # impl Deserialize for ClusterMap {} +//! # +//! use anyhow::Result; +//! +//! fn get_cluster_info() -> Result { +//! let config = std::fs::read_to_string("cluster.json")?; +//! let map: ClusterMap = serde_json::from_str(&config)?; +//! Ok(map) +//! } +//! # +//! # fn main() {} +//! ``` +//! +//! - Attach context to help the person troubleshooting the error understand +//! where things went wrong. A low-level error like "No such file or +//! directory" can be annoying to debug without more context about what higher +//! level step the application was in the middle of. +//! +//! ``` +//! # struct It; +//! # +//! # impl It { +//! # fn detach(&self) -> Result<()> { +//! # unimplemented!() +//! # } +//! # } +//! # +//! use anyhow::{Context, Result}; +//! +//! fn main() -> Result<()> { +//! # return Ok(()); +//! # +//! # const _: &str = stringify! { +//! ... +//! # }; +//! # +//! # let it = It; +//! # let path = "./path/to/instrs.json"; +//! # +//! it.detach().context("Failed to detach the important thing")?; +//! +//! let content = std::fs::read(path) +//! .with_context(|| format!("Failed to read instrs from {}", path))?; +//! # +//! # const _: &str = stringify! { +//! ... +//! # }; +//! # +//! # Ok(()) +//! } +//! ``` +//! +//! ```console +//! Error: Failed to read instrs from ./path/to/instrs.json +//! +//! Caused by: +//! No such file or directory (os error 2) +//! ``` +//! +//! - Downcasting is supported and can be by value, by shared reference, or by +//! mutable reference as needed. +//! +//! ``` +//! # use anyhow::anyhow; +//! # use std::fmt::{self, Display}; +//! # use std::task::Poll; +//! # +//! # #[derive(Debug)] +//! # enum DataStoreError { +//! # Censored(()), +//! # } +//! # +//! # impl Display for DataStoreError { +//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +//! # unimplemented!() +//! # } +//! # } +//! # +//! # impl std::error::Error for DataStoreError {} +//! # +//! # const REDACTED_CONTENT: () = (); +//! # +//! # let error = anyhow!("..."); +//! # let root_cause = &error; +//! # +//! # let ret = +//! // If the error was caused by redaction, then return a +//! // tombstone instead of the content. +//! match root_cause.downcast_ref::() { +//! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), +//! None => Err(error), +//! } +//! # ; +//! ``` +//! +//! - If using Rust ≥ 1.65, a backtrace is captured and printed with the +//! error if the underlying error type does not already provide its own. In +//! order to see backtraces, they must be enabled through the environment +//! variables described in [`std::backtrace`]: +//! +//! - If you want panics and errors to both have backtraces, set +//! `RUST_BACKTRACE=1`; +//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; +//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and +//! `RUST_LIB_BACKTRACE=0`. +//! +//! [`std::backtrace`]: std::backtrace#environment-variables +//! +//! - Anyhow works with any error type that has an impl of `std::error::Error`, +//! including ones defined in your crate. We do not bundle a `derive(Error)` +//! macro but you can write the impls yourself or use a standalone macro like +//! [thiserror]. +//! +//! [thiserror]: https://github.com/dtolnay/thiserror +//! +//! ``` +//! use thiserror::Error; +//! +//! #[derive(Error, Debug)] +//! pub enum FormatError { +//! #[error("Invalid header (expected {expected:?}, got {found:?})")] +//! InvalidHeader { +//! expected: String, +//! found: String, +//! }, +//! #[error("Missing attribute: {0}")] +//! MissingAttribute(String), +//! } +//! ``` +//! +//! - One-off error messages can be constructed using the `anyhow!` macro, which +//! supports string interpolation and produces an `anyhow::Error`. +//! +//! ``` +//! # use anyhow::{anyhow, Result}; +//! # +//! # fn demo() -> Result<()> { +//! # let missing = "..."; +//! return Err(anyhow!("Missing attribute: {}", missing)); +//! # Ok(()) +//! # } +//! ``` +//! +//! A `bail!` macro is provided as a shorthand for the same early return. +//! +//! ``` +//! # use anyhow::{bail, Result}; +//! # +//! # fn demo() -> Result<()> { +//! # let missing = "..."; +//! bail!("Missing attribute: {}", missing); +//! # Ok(()) +//! # } +//! ``` +//! +//!
+//! +//! # No-std support +//! +//! In no_std mode, almost all of the same API is available and works the same +//! way. To depend on Anyhow in no_std mode, disable our default enabled "std" +//! feature in Cargo.toml. A global allocator is required. +//! +//! ```toml +//! [dependencies] +//! anyhow = { version = "1.0", default-features = false } +//! ``` +//! +//! With versions of Rust older than 1.81, no_std mode may require an additional +//! `.map_err(Error::msg)` when working with a non-Anyhow error type inside a +//! function that returns Anyhow's error type, as the trait that `?`-based error +//! conversions are defined by is only available in std in those old versions. + +#![doc(html_root_url = "https://docs.rs/anyhow/1.0.102")] +#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] +#![no_std] +#![deny(dead_code, unsafe_op_in_unsafe_fn, unused_imports, unused_mut)] +#![allow( + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::enum_glob_use, + clippy::explicit_auto_deref, + clippy::extra_unused_type_parameters, + clippy::incompatible_msrv, + clippy::let_underscore_untyped, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::needless_doctest_main, + clippy::needless_lifetimes, + clippy::new_ret_no_self, + clippy::redundant_else, + clippy::return_self_not_must_use, + clippy::struct_field_names, + clippy::uninlined_format_args, + clippy::unused_self, + clippy::used_underscore_binding, + clippy::wildcard_imports, + clippy::wrong_self_convention +)] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] + +#[cfg(all( + anyhow_nightly_testing, + feature = "std", + not(error_generic_member_access) +))] +compile_error!("Build script probe failed to compile."); + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +#[macro_use] +mod backtrace; +mod chain; +mod context; +mod ensure; +mod error; +mod fmt; +mod kind; +mod macros; +#[cfg(error_generic_member_access)] +mod nightly; +mod ptr; +mod wrapper; + +use crate::error::ErrorImpl; +use crate::ptr::Own; +use core::fmt::Display; + +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] +use core::fmt::Debug; + +#[cfg(feature = "std")] +use std::error::Error as StdError; + +#[cfg(not(any(feature = "std", anyhow_no_core_error)))] +use core::error::Error as StdError; + +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] +trait StdError: Debug + Display { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } +} + +#[doc(no_inline)] +pub use anyhow as format_err; + +/// The `Error` type, a wrapper around a dynamic error type. +/// +/// `Error` works a lot like `Box`, but with these +/// differences: +/// +/// - `Error` requires that the error is `Send`, `Sync`, and `'static`. +/// - `Error` guarantees that a backtrace is available, even if the underlying +/// error type does not provide one. +/// - `Error` is represented as a narrow pointer — exactly one word in +/// size instead of two. +/// +///
+/// +/// # Display representations +/// +/// When you print an error object using "{}" or to_string(), only the outermost +/// underlying error or context is printed, not any of the lower level causes. +/// This is exactly as if you had called the Display impl of the error from +/// which you constructed your anyhow::Error. +/// +/// ```console +/// Failed to read instrs from ./path/to/instrs.json +/// ``` +/// +/// To print causes as well using anyhow's default formatting of causes, use the +/// alternate selector "{:#}". +/// +/// ```console +/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2) +/// ``` +/// +/// The Debug format "{:?}" includes your backtrace if one was captured. Note +/// that this is the representation you get by default if you return an error +/// from `fn main` instead of printing it explicitly yourself. +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// ``` +/// +/// and if there is a backtrace available: +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// +/// Stack backtrace: +/// 0: ::ext_context +/// at /git/anyhow/src/backtrace.rs:26 +/// 1: core::result::Result::map_err +/// at /git/rustc/src/libcore/result.rs:596 +/// 2: anyhow::context:: for core::result::Result>::with_context +/// at /git/anyhow/src/context.rs:58 +/// 3: testing::main +/// at src/main.rs:5 +/// 4: std::rt::lang_start +/// at /git/rustc/src/libstd/rt.rs:61 +/// 5: main +/// 6: __libc_start_main +/// 7: _start +/// ``` +/// +/// To see a conventional struct-style Debug representation, use "{:#?}". +/// +/// ```console +/// Error { +/// context: "Failed to read instrs from ./path/to/instrs.json", +/// source: Os { +/// code: 2, +/// kind: NotFound, +/// message: "No such file or directory", +/// }, +/// } +/// ``` +/// +/// If none of the built-in representations are appropriate and you would prefer +/// to render the error and its cause chain yourself, it can be done something +/// like this: +/// +/// ``` +/// use anyhow::{Context, Result}; +/// +/// fn main() { +/// if let Err(err) = try_main() { +/// eprintln!("ERROR: {}", err); +/// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause)); +/// std::process::exit(1); +/// } +/// } +/// +/// fn try_main() -> Result<()> { +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # Ok(()) +/// } +/// ``` +#[repr(transparent)] +pub struct Error { + inner: Own, +} + +/// Iterator of a chain of source errors. +/// +/// This type is the iterator returned by [`Error::chain`]. +/// +/// # Example +/// +/// ``` +/// use anyhow::Error; +/// use std::io; +/// +/// pub fn underlying_io_error_kind(error: &Error) -> Option { +/// for cause in error.chain() { +/// if let Some(io_error) = cause.downcast_ref::() { +/// return Some(io_error.kind()); +/// } +/// } +/// None +/// } +/// ``` +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +#[derive(Clone)] +pub struct Chain<'a> { + state: crate::chain::ChainState<'a>, +} + +/// `Result` +/// +/// This is a reasonable return type to use throughout your application but also +/// for `fn main`; if you do, failures will be printed along with any +/// [context][Context] and a backtrace if one was captured. +/// +/// `anyhow::Result` may be used with one *or* two type parameters. +/// +/// ```rust +/// use anyhow::Result; +/// +/// # const IGNORE: &str = stringify! { +/// fn demo1() -> Result {...} +/// // ^ equivalent to std::result::Result +/// +/// fn demo2() -> Result {...} +/// // ^ equivalent to std::result::Result +/// # }; +/// ``` +/// +/// # Example +/// +/// ``` +/// # pub trait Deserialize {} +/// # +/// # mod serde_json { +/// # use super::Deserialize; +/// # use std::io; +/// # +/// # pub fn from_str(json: &str) -> io::Result { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # #[derive(Debug)] +/// # struct ClusterMap; +/// # +/// # impl Deserialize for ClusterMap {} +/// # +/// use anyhow::Result; +/// +/// fn main() -> Result<()> { +/// # return Ok(()); +/// let config = std::fs::read_to_string("cluster.json")?; +/// let map: ClusterMap = serde_json::from_str(&config)?; +/// println!("cluster info: {:#?}", map); +/// Ok(()) +/// } +/// ``` +pub type Result = core::result::Result; + +/// Provides the `context` method for `Result`. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `anyhow`. +/// +///
+/// +/// # Example +/// +/// ``` +/// use anyhow::{Context, Result}; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// pub struct ImportantThing { +/// path: PathBuf, +/// } +/// +/// impl ImportantThing { +/// # const IGNORE: &'static str = stringify! { +/// pub fn detach(&mut self) -> Result<()> {...} +/// # }; +/// # fn detach(&mut self) -> Result<()> { +/// # unimplemented!() +/// # } +/// } +/// +/// pub fn do_it(mut it: ImportantThing) -> Result> { +/// it.detach().context("Failed to detach the important thing")?; +/// +/// let path = &it.path; +/// let content = fs::read(path) +/// .with_context(|| format!("Failed to read instrs from {}", path.display()))?; +/// +/// Ok(content) +/// } +/// ``` +/// +/// When printed, the outermost context would be printed first and the lower +/// level underlying causes would be enumerated below. +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// ``` +/// +/// Refer to the [Display representations] documentation for other forms in +/// which this context chain can be rendered. +/// +/// [Display representations]: Error#display-representations +/// +///
+/// +/// # Effect on downcasting +/// +/// After attaching context of type `C` onto an error of type `E`, the resulting +/// `anyhow::Error` may be downcast to `C` **or** to `E`. +/// +/// That is, in codebases that rely on downcasting, Anyhow's context supports +/// both of the following use cases: +/// +/// - **Attaching context whose type is insignificant onto errors whose type +/// is used in downcasts.** +/// +/// In other error libraries whose context is not designed this way, it can +/// be risky to introduce context to existing code because new context might +/// break existing working downcasts. In Anyhow, any downcast that worked +/// before adding context will continue to work after you add a context, so +/// you should freely add human-readable context to errors wherever it would +/// be helpful. +/// +/// ``` +/// # use anyhow::bail; +/// # use thiserror::Error; +/// # +/// # #[derive(Error, Debug)] +/// # #[error("???")] +/// # struct SuspiciousError; +/// # +/// # fn helper() -> Result<()> { +/// # bail!(SuspiciousError); +/// # } +/// # +/// use anyhow::{Context, Result}; +/// +/// fn do_it() -> Result<()> { +/// helper().context("Failed to complete the work")?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unreachable!() +/// } +/// +/// fn main() { +/// let err = do_it().unwrap_err(); +/// if let Some(e) = err.downcast_ref::() { +/// // If helper() returned SuspiciousError, this downcast will +/// // correctly succeed even with the context in between. +/// # return; +/// } +/// # panic!("expected downcast to succeed"); +/// } +/// ``` +/// +/// - **Attaching context whose type is used in downcasts onto errors whose +/// type is insignificant.** +/// +/// Some codebases prefer to use machine-readable context to categorize +/// lower level errors in a way that will be actionable to higher levels of +/// the application. +/// +/// ``` +/// # use anyhow::bail; +/// # use thiserror::Error; +/// # +/// # #[derive(Error, Debug)] +/// # #[error("???")] +/// # struct HelperFailed; +/// # +/// # fn helper() -> Result<()> { +/// # bail!("no such file or directory"); +/// # } +/// # +/// use anyhow::{Context, Result}; +/// +/// fn do_it() -> Result<()> { +/// helper().context(HelperFailed)?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unreachable!() +/// } +/// +/// fn main() { +/// let err = do_it().unwrap_err(); +/// if let Some(e) = err.downcast_ref::() { +/// // If helper failed, this downcast will succeed because +/// // HelperFailed is the context that has been attached to +/// // that error. +/// # return; +/// } +/// # panic!("expected downcast to succeed"); +/// } +/// ``` +pub trait Context: context::private::Sealed { + /// Wrap the error value with additional context. + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static; + + /// Wrap the error value with additional context that is evaluated lazily + /// only once an error does occur. + fn with_context(self, f: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C; +} + +/// Equivalent to `Ok::<_, anyhow::Error>(value)`. +/// +/// This simplifies creation of an `anyhow::Result` in places where type +/// inference cannot deduce the `E` type of the result — without needing +/// to write `Ok::<_, anyhow::Error>(value)`. +/// +/// One might think that `anyhow::Result::Ok(value)` would work in such cases +/// but it does not. +/// +/// ```console +/// error[E0282]: type annotations needed for `std::result::Result` +/// --> src/main.rs:11:13 +/// | +/// 11 | let _ = anyhow::Result::Ok(1); +/// | - ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result` +/// | | +/// | consider giving this pattern the explicit type `std::result::Result`, where the type parameter `E` is specified +/// ``` +#[allow(non_snake_case)] +#[inline] +pub fn Ok(value: T) -> Result { + Result::Ok(value) +} + +// Not public API. Referenced by macro-generated code. +#[doc(hidden)] +pub mod __private { + use self::not::Bool; + use crate::Error; + use alloc::fmt; + use core::fmt::Arguments; + + #[doc(hidden)] + pub use crate::ensure::{BothDebug, NotBothDebug}; + #[doc(hidden)] + pub use alloc::format; + #[doc(hidden)] + pub use core::result::Result::Err; + #[doc(hidden)] + pub use core::{concat, format_args, stringify}; + + #[doc(hidden)] + pub mod kind { + #[doc(hidden)] + pub use crate::kind::{AdhocKind, TraitKind}; + + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[doc(hidden)] + pub use crate::kind::BoxedKind; + } + + #[doc(hidden)] + #[inline] + #[cold] + pub fn format_err(args: Arguments) -> Error { + if let Some(message) = args.as_str() { + // anyhow!("literal"), can downcast to &'static str + Error::msg(message) + } else { + // anyhow!("interpolate {var}"), can downcast to String + Error::msg(fmt::format(args)) + } + } + + #[doc(hidden)] + #[inline] + #[cold] + #[must_use] + pub fn must_use(error: Error) -> Error { + error + } + + #[doc(hidden)] + #[inline] + pub fn not(cond: impl Bool) -> bool { + cond.not() + } + + mod not { + #[doc(hidden)] + pub trait Bool { + fn not(self) -> bool; + } + + impl Bool for bool { + #[inline] + fn not(self) -> bool { + !self + } + } + + impl Bool for &bool { + #[inline] + fn not(self) -> bool { + !*self + } + } + } +} diff --git a/deps/crates/vendor/anyhow/src/macros.rs b/deps/crates/vendor/anyhow/src/macros.rs new file mode 100644 index 00000000000000..1558de56a25236 --- /dev/null +++ b/deps/crates/vendor/anyhow/src/macros.rs @@ -0,0 +1,245 @@ +/// Return early with an error. +/// +/// This macro is equivalent to +/// return Err([anyhow!($args\...)][anyhow!]). +/// +/// The surrounding function's or closure's return value is required to be +/// Result<_, [anyhow::Error][crate::Error]>. +/// +/// [anyhow!]: crate::anyhow +/// +/// # Example +/// +/// ``` +/// # use anyhow::{bail, Result}; +/// # +/// # fn has_permission(user: usize, resource: usize) -> bool { +/// # true +/// # } +/// # +/// # fn main() -> Result<()> { +/// # let user = 0; +/// # let resource = 0; +/// # +/// if !has_permission(user, resource) { +/// bail!("permission denied for accessing {}", resource); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use anyhow::{bail, Result}; +/// # use thiserror::Error; +/// # +/// # const MAX_DEPTH: usize = 1; +/// # +/// #[derive(Error, Debug)] +/// enum ScienceError { +/// #[error("recursion limit exceeded")] +/// RecursionLimitExceeded, +/// # #[error("...")] +/// # More = (stringify! { +/// ... +/// # }, 1).1, +/// } +/// +/// # fn main() -> Result<()> { +/// # let depth = 0; +/// # +/// if depth > MAX_DEPTH { +/// bail!(ScienceError::RecursionLimitExceeded); +/// } +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +#[cfg_attr(not(anyhow_no_clippy_format_args), clippy::format_args)] +macro_rules! bail { + ($msg:literal $(,)?) => { + return $crate::__private::Err($crate::__anyhow!($msg)) + }; + ($err:expr $(,)?) => { + return $crate::__private::Err($crate::__anyhow!($err)) + }; + ($fmt:expr, $($arg:tt)*) => { + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)) + }; +} + +macro_rules! __ensure { + ($ensure:item) => { + /// Return early with an error if a condition is not satisfied. + /// + /// This macro is equivalent to + /// if !$cond { return Err([anyhow!($args\...)][anyhow!]); }. + /// + /// The surrounding function's or closure's return value is required to be + /// Result<_, [anyhow::Error][crate::Error]>. + /// + /// Analogously to `assert!`, `ensure!` takes a condition and exits the function + /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` + /// rather than panicking. + /// + /// [anyhow!]: crate::anyhow + /// + /// # Example + /// + /// ``` + /// # use anyhow::{ensure, Result}; + /// # + /// # fn main() -> Result<()> { + /// # let user = 0; + /// # + /// ensure!(user == 0, "only user 0 is allowed"); + /// # Ok(()) + /// # } + /// ``` + /// + /// ``` + /// # use anyhow::{ensure, Result}; + /// # use thiserror::Error; + /// # + /// # const MAX_DEPTH: usize = 1; + /// # + /// #[derive(Error, Debug)] + /// enum ScienceError { + /// #[error("recursion limit exceeded")] + /// RecursionLimitExceeded, + /// # #[error("...")] + /// # More = (stringify! { + /// ... + /// # }, 1).1, + /// } + /// + /// # fn main() -> Result<()> { + /// # let depth = 0; + /// # + /// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); + /// # Ok(()) + /// # } + /// ``` + $ensure + }; +} + +#[cfg(doc)] +__ensure![ + #[macro_export] + macro_rules! ensure { + ($cond:expr $(,)?) => { + if !$cond { + return $crate::__private::Err($crate::Error::msg( + $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") + )); + } + }; + ($cond:expr, $msg:literal $(,)?) => { + if !$cond { + return $crate::__private::Err($crate::__anyhow!($msg)); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if !$cond { + return $crate::__private::Err($crate::__anyhow!($err)); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if !$cond { + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); + } + }; + } +]; + +#[cfg(not(doc))] +__ensure![ + #[macro_export] + #[cfg_attr(not(anyhow_no_clippy_format_args), clippy::format_args)] + macro_rules! ensure { + ($($tt:tt)*) => { + $crate::__parse_ensure!( + /* state */ 0 + /* stack */ () + /* bail */ ($($tt)*) + /* fuel */ (~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~) + /* parse */ {()} + /* dup */ ($($tt)*) + /* rest */ $($tt)* + ) + }; + } +]; + +/// Construct an ad-hoc error from a string or existing non-`anyhow` error +/// value. +/// +/// This evaluates to an [`Error`][crate::Error]. It can take either just a +/// string, or a format string with arguments. It also can take any custom type +/// which implements `Debug` and `Display`. +/// +/// If called with a single argument whose type implements `std::error::Error` +/// (in addition to `Debug` and `Display`, which are always required), then that +/// Error impl's `source` is preserved as the `source` of the resulting +/// `anyhow::Error`. +/// +/// # Example +/// +/// ``` +/// # type V = (); +/// # +/// use anyhow::{anyhow, Result}; +/// +/// fn lookup(key: &str) -> Result { +/// if key.len() != 16 { +/// return Err(anyhow!("key length must be 16 characters, got {:?}", key)); +/// } +/// +/// // ... +/// # Ok(()) +/// } +/// ``` +#[macro_export] +#[cfg_attr(not(anyhow_no_clippy_format_args), clippy::format_args)] +macro_rules! anyhow { + ($msg:literal $(,)?) => { + $crate::__private::must_use({ + let error = $crate::__private::format_err($crate::__private::format_args!($msg)); + error + }) + }; + ($err:expr $(,)?) => { + $crate::__private::must_use({ + use $crate::__private::kind::*; + let error = match $err { + error => (&error).anyhow_kind().new(error), + }; + error + }) + }; + ($fmt:expr, $($arg:tt)*) => { + $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) + }; +} + +// Not public API. This is used in the implementation of some of the other +// macros, in which the must_use call is not needed because the value is known +// to be used. +#[doc(hidden)] +#[macro_export] +macro_rules! __anyhow { + ($msg:literal $(,)?) => ({ + let error = $crate::__private::format_err($crate::__private::format_args!($msg)); + error + }); + ($err:expr $(,)?) => ({ + use $crate::__private::kind::*; + let error = match $err { + error => (&error).anyhow_kind().new(error), + }; + error + }); + ($fmt:expr, $($arg:tt)*) => { + $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) + }; +} diff --git a/deps/crates/vendor/anyhow/src/nightly.rs b/deps/crates/vendor/anyhow/src/nightly.rs new file mode 100644 index 00000000000000..125fe36ad7a12e --- /dev/null +++ b/deps/crates/vendor/anyhow/src/nightly.rs @@ -0,0 +1,58 @@ +// This code exercises the surface area that we expect of the Error generic +// member access API. If the current toolchain is able to compile it, then +// anyhow is able to provide backtrace support. + +#![cfg_attr(anyhow_build_probe, feature(error_generic_member_access))] + +use core::error::{self, Error}; +use std::backtrace::Backtrace; + +pub use core::error::Request; + +#[cfg(anyhow_build_probe)] +const _: () = { + use core::fmt::{self, Debug, Display}; + + struct MyError(Backtrace); + + impl Debug for MyError { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + } + + impl Display for MyError { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + } + + impl Error for MyError { + fn provide<'a>(&'a self, request: &mut Request<'a>) { + provide_ref_backtrace(request, &self.0); + } + } +}; + +// Include in sccache cache key. +#[cfg(anyhow_build_probe)] +const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP"); + +pub fn request_ref_backtrace(err: &dyn Error) -> Option<&Backtrace> { + request_ref::(err) +} + +fn request_ref<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<&'a T> +where + T: 'static + ?Sized, +{ + error::request_ref::(err) +} + +pub fn provide_ref_backtrace<'a>(request: &mut Request<'a>, backtrace: &'a Backtrace) { + Request::provide_ref(request, backtrace); +} + +pub fn provide<'a>(err: &'a (impl Error + ?Sized), request: &mut Request<'a>) { + Error::provide(err, request); +} diff --git a/deps/crates/vendor/anyhow/src/ptr.rs b/deps/crates/vendor/anyhow/src/ptr.rs new file mode 100644 index 00000000000000..4d6b3ab322937a --- /dev/null +++ b/deps/crates/vendor/anyhow/src/ptr.rs @@ -0,0 +1,187 @@ +use alloc::boxed::Box; +use core::marker::PhantomData; +use core::ptr::NonNull; + +#[repr(transparent)] +pub struct Own +where + T: ?Sized, +{ + pub ptr: NonNull, +} + +unsafe impl Send for Own where T: ?Sized {} + +unsafe impl Sync for Own where T: ?Sized {} + +impl Copy for Own where T: ?Sized {} + +impl Clone for Own +where + T: ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Own +where + T: ?Sized, +{ + pub fn new(ptr: Box) -> Self { + Own { + ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) }, + } + } + + pub fn cast(self) -> Own { + Own { + ptr: self.ptr.cast(), + } + } + + pub unsafe fn boxed(self) -> Box { + unsafe { Box::from_raw(self.ptr.as_ptr()) } + } + + pub fn by_ref(&self) -> Ref { + Ref { + ptr: self.ptr, + lifetime: PhantomData, + } + } + + pub fn by_mut(&mut self) -> Mut { + Mut { + ptr: self.ptr, + lifetime: PhantomData, + } + } +} + +#[repr(transparent)] +pub struct Ref<'a, T> +where + T: ?Sized, +{ + pub ptr: NonNull, + lifetime: PhantomData<&'a T>, +} + +impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {} + +impl<'a, T> Clone for Ref<'a, T> +where + T: ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Ref<'a, T> +where + T: ?Sized, +{ + pub fn new(ptr: &'a T) -> Self { + Ref { + ptr: NonNull::from(ptr), + lifetime: PhantomData, + } + } + + pub fn from_raw(ptr: NonNull) -> Self { + Ref { + ptr, + lifetime: PhantomData, + } + } + + pub fn cast(self) -> Ref<'a, U::Target> { + Ref { + ptr: self.ptr.cast(), + lifetime: PhantomData, + } + } + + pub fn by_mut(self) -> Mut<'a, T> { + Mut { + ptr: self.ptr, + lifetime: PhantomData, + } + } + + pub fn as_ptr(self) -> *const T { + self.ptr.as_ptr().cast_const() + } + + pub unsafe fn deref(self) -> &'a T { + unsafe { &*self.ptr.as_ptr() } + } +} + +#[repr(transparent)] +pub struct Mut<'a, T> +where + T: ?Sized, +{ + pub ptr: NonNull, + lifetime: PhantomData<&'a mut T>, +} + +impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {} + +impl<'a, T> Clone for Mut<'a, T> +where + T: ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Mut<'a, T> +where + T: ?Sized, +{ + pub fn cast(self) -> Mut<'a, U::Target> { + Mut { + ptr: self.ptr.cast(), + lifetime: PhantomData, + } + } + + pub fn by_ref(self) -> Ref<'a, T> { + Ref { + ptr: self.ptr, + lifetime: PhantomData, + } + } + + pub fn extend<'b>(self) -> Mut<'b, T> { + Mut { + ptr: self.ptr, + lifetime: PhantomData, + } + } + + pub unsafe fn deref_mut(self) -> &'a mut T { + unsafe { &mut *self.ptr.as_ptr() } + } +} + +impl<'a, T> Mut<'a, T> { + pub unsafe fn read(self) -> T { + unsafe { self.ptr.as_ptr().read() } + } +} + +// Force turbofish on all calls of `.cast::()`. +pub trait CastTo { + type Target; +} + +impl CastTo for T { + type Target = T; +} diff --git a/deps/crates/vendor/anyhow/src/wrapper.rs b/deps/crates/vendor/anyhow/src/wrapper.rs new file mode 100644 index 00000000000000..bad3ddda4fcd1d --- /dev/null +++ b/deps/crates/vendor/anyhow/src/wrapper.rs @@ -0,0 +1,84 @@ +use crate::StdError; +use core::fmt::{self, Debug, Display}; + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use alloc::boxed::Box; + +#[cfg(error_generic_member_access)] +use crate::nightly::{self, Request}; + +#[repr(transparent)] +pub struct MessageError(pub M); + +impl Debug for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +impl Display for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for MessageError where M: Display + Debug + 'static {} + +#[repr(transparent)] +pub struct DisplayError(pub M); + +impl Debug for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl Display for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for DisplayError where M: Display + 'static {} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +#[repr(transparent)] +pub struct BoxedError(pub Box); + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl Debug for BoxedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl Display for BoxedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +impl StdError for BoxedError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.0.source() + } + + #[cfg(error_generic_member_access)] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + nightly::provide(&*self.0, request); + } +} diff --git a/deps/crates/vendor/anyhow/tests/common/mod.rs b/deps/crates/vendor/anyhow/tests/common/mod.rs new file mode 100644 index 00000000000000..fc165a5be90c76 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/common/mod.rs @@ -0,0 +1,14 @@ +use anyhow::{bail, Result}; +use std::io; + +pub fn bail_literal() -> Result<()> { + bail!("oh no!"); +} + +pub fn bail_fmt() -> Result<()> { + bail!("{} {}!", "oh", "no"); +} + +pub fn bail_error() -> Result<()> { + bail!(io::Error::new(io::ErrorKind::Other, "oh no!")); +} diff --git a/deps/crates/vendor/anyhow/tests/compiletest.rs b/deps/crates/vendor/anyhow/tests/compiletest.rs new file mode 100644 index 00000000000000..23a6a065ec960a --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/compiletest.rs @@ -0,0 +1,7 @@ +#[rustversion::attr(not(nightly), ignore = "requires nightly")] +#[cfg_attr(miri, ignore = "incompatible with miri")] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/deps/crates/vendor/anyhow/tests/drop/mod.rs b/deps/crates/vendor/anyhow/tests/drop/mod.rs new file mode 100644 index 00000000000000..7da4bf55a1042f --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/drop/mod.rs @@ -0,0 +1,53 @@ +#![allow(clippy::module_name_repetitions)] + +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Flag { + atomic: Arc, +} + +impl Flag { + pub fn new() -> Self { + Flag { + atomic: Arc::new(AtomicBool::new(false)), + } + } + + pub fn get(&self) -> bool { + self.atomic.load(Ordering::Relaxed) + } +} + +#[derive(Debug)] +pub struct DetectDrop { + has_dropped: Flag, +} + +impl DetectDrop { + pub fn new(has_dropped: &Flag) -> Self { + DetectDrop { + has_dropped: Flag { + atomic: Arc::clone(&has_dropped.atomic), + }, + } + } +} + +impl StdError for DetectDrop {} + +impl Display for DetectDrop { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "oh no!") + } +} + +impl Drop for DetectDrop { + fn drop(&mut self) { + let already_dropped = self.has_dropped.atomic.swap(true, Ordering::Relaxed); + assert!(!already_dropped); + } +} diff --git a/deps/crates/vendor/anyhow/tests/test_autotrait.rs b/deps/crates/vendor/anyhow/tests/test_autotrait.rs new file mode 100644 index 00000000000000..080b3b9e00e3c9 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_autotrait.rs @@ -0,0 +1,34 @@ +#![allow(clippy::extra_unused_type_parameters)] + +use anyhow::Error; +use std::panic::{RefUnwindSafe, UnwindSafe}; + +#[test] +fn test_send() { + fn assert_send() {} + assert_send::(); +} + +#[test] +fn test_sync() { + fn assert_sync() {} + assert_sync::(); +} + +#[test] +fn test_unwind_safe() { + fn assert_unwind_safe() {} + assert_unwind_safe::(); +} + +#[test] +fn test_ref_unwind_safe() { + fn assert_ref_unwind_safe() {} + assert_ref_unwind_safe::(); +} + +#[test] +fn test_unpin() { + fn assert_unpin() {} + assert_unpin::(); +} diff --git a/deps/crates/vendor/anyhow/tests/test_backtrace.rs b/deps/crates/vendor/anyhow/tests/test_backtrace.rs new file mode 100644 index 00000000000000..938c1c24ee3215 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_backtrace.rs @@ -0,0 +1,15 @@ +#![allow(clippy::let_underscore_untyped)] + +#[rustversion::not(nightly)] +#[ignore = "requires nightly"] +#[test] +fn test_backtrace() {} + +#[rustversion::nightly] +#[test] +fn test_backtrace() { + use anyhow::anyhow; + + let error = anyhow!("oh no!"); + let _ = error.backtrace(); +} diff --git a/deps/crates/vendor/anyhow/tests/test_boxed.rs b/deps/crates/vendor/anyhow/tests/test_boxed.rs new file mode 100644 index 00000000000000..fb1fb132d50c8e --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_boxed.rs @@ -0,0 +1,45 @@ +#![allow( + // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 + clippy::nonstandard_macro_braces, +)] + +use anyhow::anyhow; +use std::error::Error as StdError; +use std::io; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("outer")] +struct MyError { + source: io::Error, +} + +#[test] +fn test_boxed_str() { + let error = Box::::from("oh no!"); + let error = anyhow!(error); + assert_eq!("oh no!", error.to_string()); + assert_eq!( + "oh no!", + error + .downcast_ref::>() + .unwrap() + .to_string() + ); +} + +#[test] +fn test_boxed_thiserror() { + let error = MyError { + source: io::Error::new(io::ErrorKind::Other, "oh no!"), + }; + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} + +#[test] +fn test_boxed_anyhow() { + let error = anyhow!("oh no!").context("it failed"); + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} diff --git a/deps/crates/vendor/anyhow/tests/test_chain.rs b/deps/crates/vendor/anyhow/tests/test_chain.rs new file mode 100644 index 00000000000000..c8b901ab41d8f5 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_chain.rs @@ -0,0 +1,69 @@ +use anyhow::{anyhow, Chain, Error}; + +fn error() -> Error { + anyhow!({ 0 }).context(1).context(2).context(3) +} + +#[test] +fn test_iter() { + let e = error(); + let mut chain = e.chain(); + assert_eq!("3", chain.next().unwrap().to_string()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!("1", chain.next().unwrap().to_string()); + assert_eq!("0", chain.next().unwrap().to_string()); + assert!(chain.next().is_none()); + assert!(chain.next_back().is_none()); +} + +#[test] +fn test_rev() { + let e = error(); + let mut chain = e.chain().rev(); + assert_eq!("0", chain.next().unwrap().to_string()); + assert_eq!("1", chain.next().unwrap().to_string()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!("3", chain.next().unwrap().to_string()); + assert!(chain.next().is_none()); + assert!(chain.next_back().is_none()); +} + +#[test] +fn test_len() { + let e = error(); + let mut chain = e.chain(); + assert_eq!(4, chain.len()); + assert_eq!((4, Some(4)), chain.size_hint()); + assert_eq!("3", chain.next().unwrap().to_string()); + assert_eq!(3, chain.len()); + assert_eq!((3, Some(3)), chain.size_hint()); + assert_eq!("0", chain.next_back().unwrap().to_string()); + assert_eq!(2, chain.len()); + assert_eq!((2, Some(2)), chain.size_hint()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!(1, chain.len()); + assert_eq!((1, Some(1)), chain.size_hint()); + assert_eq!("1", chain.next_back().unwrap().to_string()); + assert_eq!(0, chain.len()); + assert_eq!((0, Some(0)), chain.size_hint()); + assert!(chain.next().is_none()); +} + +#[test] +fn test_default() { + let mut c = Chain::default(); + assert!(c.next().is_none()); +} + +#[test] +#[allow(clippy::redundant_clone)] +fn test_clone() { + let e = error(); + let mut chain = e.chain().clone(); + assert_eq!("3", chain.next().unwrap().to_string()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!("1", chain.next().unwrap().to_string()); + assert_eq!("0", chain.next().unwrap().to_string()); + assert!(chain.next().is_none()); + assert!(chain.next_back().is_none()); +} diff --git a/deps/crates/vendor/anyhow/tests/test_context.rs b/deps/crates/vendor/anyhow/tests/test_context.rs new file mode 100644 index 00000000000000..2053fc9e571449 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_context.rs @@ -0,0 +1,172 @@ +#![allow( + // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 + clippy::nonstandard_macro_braces, +)] + +mod drop; + +use crate::drop::{DetectDrop, Flag}; +use anyhow::{Context, Error, Result}; +use std::fmt::{self, Display}; +use thiserror::Error; + +// https://github.com/dtolnay/anyhow/issues/18 +#[test] +fn test_inference() -> Result<()> { + let x = "1"; + let y: u32 = x.parse().context("...")?; + assert_eq!(y, 1); + Ok(()) +} + +macro_rules! context_type { + ($name:ident) => { + #[derive(Debug)] + struct $name { + message: &'static str, + #[allow(dead_code)] + drop: DetectDrop, + } + + impl Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.message) + } + } + }; +} + +context_type!(HighLevel); +context_type!(MidLevel); + +#[derive(Error, Debug)] +#[error("{message}")] +struct LowLevel { + message: &'static str, + drop: DetectDrop, +} + +struct Dropped { + low: Flag, + mid: Flag, + high: Flag, +} + +impl Dropped { + fn none(&self) -> bool { + !self.low.get() && !self.mid.get() && !self.high.get() + } + + fn all(&self) -> bool { + self.low.get() && self.mid.get() && self.high.get() + } +} + +fn make_chain() -> (Error, Dropped) { + let dropped = Dropped { + low: Flag::new(), + mid: Flag::new(), + high: Flag::new(), + }; + + let low = LowLevel { + message: "no such file or directory", + drop: DetectDrop::new(&dropped.low), + }; + + // impl Context for Result + let mid = Err::<(), LowLevel>(low) + .context(MidLevel { + message: "failed to load config", + drop: DetectDrop::new(&dropped.mid), + }) + .unwrap_err(); + + // impl Context for Result + let high = Err::<(), Error>(mid) + .context(HighLevel { + message: "failed to start server", + drop: DetectDrop::new(&dropped.high), + }) + .unwrap_err(); + + (high, dropped) +} + +#[test] +fn test_downcast_ref() { + let (err, dropped) = make_chain(); + + assert!(!err.is::()); + assert!(err.downcast_ref::().is_none()); + + assert!(err.is::()); + let high = err.downcast_ref::().unwrap(); + assert_eq!(high.to_string(), "failed to start server"); + + assert!(err.is::()); + let mid = err.downcast_ref::().unwrap(); + assert_eq!(mid.to_string(), "failed to load config"); + + assert!(err.is::()); + let low = err.downcast_ref::().unwrap(); + assert_eq!(low.to_string(), "no such file or directory"); + + assert!(dropped.none()); + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_high() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.high.get()); + assert!(dropped.low.get() && dropped.mid.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_mid() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.mid.get()); + assert!(dropped.low.get() && dropped.high.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_low() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.low.get()); + assert!(dropped.mid.get() && dropped.high.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_unsuccessful_downcast() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap_err(); + assert!(dropped.none()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_root_cause() { + let (err, _) = make_chain(); + + assert_eq!(err.root_cause().to_string(), "no such file or directory"); +} diff --git a/deps/crates/vendor/anyhow/tests/test_convert.rs b/deps/crates/vendor/anyhow/tests/test_convert.rs new file mode 100644 index 00000000000000..6da171d1b89066 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_convert.rs @@ -0,0 +1,46 @@ +#![allow(clippy::unnecessary_wraps)] + +mod drop; + +use self::drop::{DetectDrop, Flag}; +use anyhow::{Error, Result}; +use std::error::Error as StdError; + +#[test] +fn test_convert() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + let box_dyn = Box::::from(error); + assert_eq!("oh no!", box_dyn.to_string()); + drop(box_dyn); + assert!(has_dropped.get()); +} + +#[test] +fn test_convert_send() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + let box_dyn = Box::::from(error); + assert_eq!("oh no!", box_dyn.to_string()); + drop(box_dyn); + assert!(has_dropped.get()); +} + +#[test] +fn test_convert_send_sync() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + let box_dyn = Box::::from(error); + assert_eq!("oh no!", box_dyn.to_string()); + drop(box_dyn); + assert!(has_dropped.get()); +} + +#[test] +fn test_question_mark() -> Result<(), Box> { + fn f() -> Result<()> { + Ok(()) + } + f()?; + Ok(()) +} diff --git a/deps/crates/vendor/anyhow/tests/test_downcast.rs b/deps/crates/vendor/anyhow/tests/test_downcast.rs new file mode 100644 index 00000000000000..b4470d551ab497 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_downcast.rs @@ -0,0 +1,123 @@ +#![allow(clippy::assertions_on_result_states, clippy::wildcard_imports)] + +mod common; +mod drop; + +use self::common::*; +use self::drop::{DetectDrop, Flag}; +use anyhow::Error; +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::io; + +#[test] +fn test_downcast() { + assert_eq!( + "oh no!", + bail_literal().unwrap_err().downcast::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + ); +} + +#[test] +fn test_downcast_ref() { + assert_eq!( + "oh no!", + *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast_ref::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast_ref::() + .unwrap() + .to_string(), + ); +} + +#[test] +fn test_downcast_mut() { + assert_eq!( + "oh no!", + *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast_mut::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast_mut::() + .unwrap() + .to_string(), + ); + + let mut bailed = bail_fmt().unwrap_err(); + *bailed.downcast_mut::().unwrap() = "clobber".to_string(); + assert_eq!(bailed.downcast_ref::().unwrap(), "clobber"); + assert_eq!(bailed.downcast_mut::().unwrap(), "clobber"); + assert_eq!(bailed.downcast::().unwrap(), "clobber"); +} + +#[test] +fn test_drop() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + drop(error.downcast::().unwrap()); + assert!(has_dropped.get()); +} + +#[test] +fn test_as_ref() { + let error = bail_error().unwrap_err(); + let ref_dyn: &dyn StdError = error.as_ref(); + assert_eq!("oh no!", ref_dyn.to_string()); + let ref_dyn_send_sync: &(dyn StdError + Send + Sync) = error.as_ref(); + assert_eq!("oh no!", ref_dyn_send_sync.to_string()); +} + +#[test] +fn test_large_alignment() { + #[repr(align(64))] + #[derive(Debug)] + struct LargeAlignedError(&'static str); + + impl Display for LargeAlignedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.0) + } + } + + impl StdError for LargeAlignedError {} + + let error = Error::new(LargeAlignedError("oh no!")); + assert_eq!( + "oh no!", + error.downcast_ref::().unwrap().0 + ); +} + +#[test] +fn test_unsuccessful_downcast() { + let mut error = bail_error().unwrap_err(); + assert!(error.downcast_ref::<&str>().is_none()); + assert!(error.downcast_mut::<&str>().is_none()); + assert!(error.downcast::<&str>().is_err()); +} diff --git a/deps/crates/vendor/anyhow/tests/test_ensure.rs b/deps/crates/vendor/anyhow/tests/test_ensure.rs new file mode 100644 index 00000000000000..dc95160609a6eb --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_ensure.rs @@ -0,0 +1,756 @@ +#![allow( + clippy::bool_to_int_with_if, + clippy::char_lit_as_u8, + clippy::deref_addrof, + clippy::diverging_sub_expression, + clippy::erasing_op, + clippy::extra_unused_type_parameters, + clippy::if_same_then_else, + clippy::ifs_same_cond, + clippy::ignored_unit_patterns, + clippy::items_after_statements, + clippy::let_and_return, + clippy::let_underscore_untyped, + clippy::literal_string_with_formatting_args, + clippy::match_bool, + clippy::needless_else, + clippy::never_loop, + clippy::overly_complex_bool_expr, + clippy::ptr_cast_constness, + clippy::redundant_closure_call, + clippy::redundant_pattern_matching, + clippy::too_many_lines, + clippy::uninlined_format_args, + clippy::unit_arg, + clippy::unnecessary_cast, + clippy::while_immutable_condition, + clippy::zero_ptr, + irrefutable_let_patterns +)] + +use self::Enum::Generic; +use anyhow::{anyhow, ensure, Chain, Error, Result}; +use std::fmt::{self, Debug}; +use std::iter; +use std::marker::{PhantomData, PhantomData as P}; +use std::mem; +use std::ops::Add; +use std::ptr; + +struct S; + +impl Add for S { + type Output = bool; + fn add(self, rhs: T) -> Self::Output { + let _ = rhs; + false + } +} + +trait Trait: Sized { + const V: usize = 0; + fn t(self, i: i32) -> i32 { + i + } +} + +impl Trait for T {} + +enum Enum { + #[allow(dead_code)] + Thing(PhantomData), + Generic, +} + +impl PartialEq for Enum { + fn eq(&self, rhs: &Self) -> bool { + mem::discriminant(self) == mem::discriminant(rhs) + } +} + +impl Debug for Enum { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Generic") + } +} + +#[track_caller] +fn assert_err(result: impl FnOnce() -> Result, expected: &'static str) { + let actual = result().unwrap_err().to_string(); + + // In general different rustc versions will format the interpolated lhs and + // rhs $:expr fragment with insignificant differences in whitespace or + // punctuation, so we check the message in full against nightly and do just + // a cursory test on older toolchains. + if rustversion::cfg!(nightly) && !cfg!(miri) { + assert_eq!(actual, expected); + } else { + assert_eq!(actual.contains(" vs "), expected.contains(" vs ")); + } +} + +#[test] +fn test_recursion() { + // Must not blow the default #[recursion_limit], which is 128. + #[rustfmt::skip] + let test = || Ok(ensure!( + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false | + false | false | false | false | false | false | false | false | false + )); + + test().unwrap_err(); +} + +#[test] +fn test_low_precedence_control_flow() { + #[allow(unreachable_code)] + let test = || { + let val = loop { + // Break has lower precedence than the comparison operators so the + // expression here is `S + (break (1 == 1))`. It would be bad if the + // ensure macro partitioned this input into `(S + break 1) == (1)` + // because that means a different thing than what was written. + ensure!(S + break 1 == 1); + }; + Ok(val) + }; + + assert!(test().unwrap()); +} + +#[test] +fn test_low_precedence_binary_operator() { + // Must not partition as `false == (true && false)`. + let test = || Ok(ensure!(false == true && false)); + assert_err(test, "Condition failed: `false == true && false`"); + + // But outside the root level, it is fine. + let test = || Ok(ensure!(while false == true && false {} < ())); + assert_err( + test, + "Condition failed: `while false == true && false {} < ()` (() vs ())", + ); + + let a = 15; + let b = 3; + let test = || Ok(ensure!(a <= b || a - b <= 10)); + assert_err(test, "Condition failed: `a <= b || a - b <= 10`"); +} + +#[test] +fn test_high_precedence_binary_operator() { + let a = 15; + let b = 3; + let test = || Ok(ensure!(a - b <= 10)); + assert_err(test, "Condition failed: `a - b <= 10` (12 vs 10)"); +} + +#[test] +fn test_closure() { + // Must not partition as `(S + move) || (1 == 1)` by treating move as an + // identifier, nor as `(S + move || 1) == (1)` by misinterpreting the + // closure precedence. + let test = || Ok(ensure!(S + move || 1 == 1)); + assert_err(test, "Condition failed: `S + move || 1 == 1`"); + + let test = || Ok(ensure!(S + || 1 == 1)); + assert_err(test, "Condition failed: `S + || 1 == 1`"); + + // Must not partition as `S + ((move | ()) | 1) == 1` by treating those + // pipes as bitwise-or. + let test = || Ok(ensure!(S + move |()| 1 == 1)); + assert_err(test, "Condition failed: `S + move |()| 1 == 1`"); + + let test = || Ok(ensure!(S + |()| 1 == 1)); + assert_err(test, "Condition failed: `S + |()| 1 == 1`"); +} + +#[test] +fn test_unary() { + let mut x = &1; + let test = || Ok(ensure!(*x == 2)); + assert_err(test, "Condition failed: `*x == 2` (1 vs 2)"); + + let test = || Ok(ensure!(!x == 1)); + assert_err(test, "Condition failed: `!x == 1` (-2 vs 1)"); + + let test = || Ok(ensure!(-x == 1)); + assert_err(test, "Condition failed: `-x == 1` (-1 vs 1)"); + + let test = || Ok(ensure!(&x == &&2)); + assert_err(test, "Condition failed: `&x == &&2` (1 vs 2)"); + + let test = || Ok(ensure!(&mut x == *&&mut &2)); + assert_err(test, "Condition failed: `&mut x == *&&mut &2` (1 vs 2)"); +} + +#[rustversion::since(1.82)] +#[test] +fn test_raw_addr() { + let mut x = 1; + let test = || Ok(ensure!(S + &raw const x != S + &raw mut x)); + assert_err( + test, + "Condition failed: `S + &raw const x != S + &raw mut x` (false vs false)", + ); +} + +#[test] +fn test_if() { + #[rustfmt::skip] + let test = || Ok(ensure!(if false {}.t(1) == 2)); + assert_err(test, "Condition failed: `if false {}.t(1) == 2` (1 vs 2)"); + + #[rustfmt::skip] + let test = || Ok(ensure!(if false {} else {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `if false {} else {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(if false {} else if false {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `if false {} else if false {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(if let 1 = 2 {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `if let 1 = 2 {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(if let 1 | 2 = 2 {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `if let 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(if let | 1 | 2 = 2 {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `if let | 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)", + ); +} + +#[test] +fn test_loop() { + #[rustfmt::skip] + let test = || Ok(ensure!(1 + loop { break 1 } == 1)); + assert_err( + test, + "Condition failed: `1 + loop { break 1 } == 1` (2 vs 1)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(1 + 'a: loop { break 'a 1 } == 1)); + assert_err( + test, + "Condition failed: `1 + 'a: loop { break 'a 1 } == 1` (2 vs 1)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(while false {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `while false {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(while let None = Some(1) {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `while let None = Some(1) {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(for _x in iter::once(0) {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `for _x in iter::once(0) {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(for | _x in iter::once(0) {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `for | _x in iter::once(0) {}.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(for true | false in iter::empty() {}.t(1) == 2)); + assert_err( + test, + "Condition failed: `for true | false in iter::empty() {}.t(1) == 2` (1 vs 2)", + ); +} + +#[test] +fn test_match() { + #[rustfmt::skip] + let test = || Ok(ensure!(match 1 == 1 { true => 1, false => 0 } == 2)); + assert_err( + test, + "Condition failed: `match 1 == 1 { true => 1, false => 0 } == 2` (1 vs 2)", + ); +} + +#[test] +fn test_atom() { + let test = || Ok(ensure!([false, false].len() > 3)); + assert_err( + test, + "Condition failed: `[false, false].len() > 3` (2 vs 3)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!({ let x = 1; x } >= 3)); + assert_err(test, "Condition failed: `{ let x = 1; x } >= 3` (1 vs 3)"); + + let test = || Ok(ensure!(S + async { 1 } == true)); + assert_err( + test, + "Condition failed: `S + async { 1 } == true` (false vs true)", + ); + + let test = || Ok(ensure!(S + async move { 1 } == true)); + assert_err( + test, + "Condition failed: `S + async move { 1 } == true` (false vs true)", + ); + + let x = &1; + let test = || Ok(ensure!(S + unsafe { ptr::read(x) } == true)); + assert_err( + test, + "Condition failed: `S + unsafe { ptr::read(x) } == true` (false vs true)", + ); +} + +#[test] +fn test_path() { + let test = || Ok(ensure!(crate::S.t(1) == 2)); + assert_err(test, "Condition failed: `crate::S.t(1) == 2` (1 vs 2)"); + + let test = || Ok(ensure!(::anyhow::Error::root_cause.t(1) == 2)); + assert_err( + test, + "Condition failed: `::anyhow::Error::root_cause.t(1) == 2` (1 vs 2)", + ); + + let test = || Ok(ensure!(Error::msg::<&str>.t(1) == 2)); + assert_err( + test, + "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(Error::msg::<&str,>.t(1) == 2)); + assert_err( + test, + "Condition failed: `Error::msg::<&str,>.t(1) == 2` (1 vs 2)", + ); + + let test = || Ok(ensure!(Error::msg::<::Owned>.t(1) == 2)); + assert_err( + test, + "Condition failed: `Error::msg::<::Owned>.t(1) == 2` (1 vs 2)", + ); + + let test = || Ok(ensure!(Chain::<'static>::new.t(1) == 2)); + assert_err( + test, + "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2)); + assert_err( + test, + "Condition failed: `Chain::<'static,>::new.t(1) == 2` (1 vs 2)", + ); + + fn f() {} + let test = || Ok(ensure!(f::<1>() != ())); + assert_err(test, "Condition failed: `f::<1>() != ()` (() vs ())"); + let test = || Ok(ensure!(f::<-1>() != ())); + assert_err(test, "Condition failed: `f::<-1>() != ()` (() vs ())"); + + fn g() {} + let test = || Ok(ensure!(g::() != ())); + assert_err(test, "Condition failed: `g::() != ()` (() vs ())"); + let test = || Ok(ensure!(g::() != ())); + assert_err(test, "Condition failed: `g::() != ()` (() vs ())"); + + #[derive(PartialOrd, PartialEq, Debug)] + enum E<'a, T> { + #[allow(dead_code)] + T(&'a T), + U, + } + + #[rustfmt::skip] + let test = || Ok(ensure!(E::U::<>>E::U::)); + assert_err(test, "Condition failed: `E::U::<> > E::U::` (U vs U)"); + + #[rustfmt::skip] + let test = || Ok(ensure!(E::U::>E::U)); + assert_err(test, "Condition failed: `E::U:: > E::U` (U vs U)"); + + #[rustfmt::skip] + let test = || Ok(ensure!(E::U::>E::U)); + assert_err(test, "Condition failed: `E::U:: > E::U` (U vs U)"); + + let test = || Ok(ensure!(Generic:: != Generic)); + assert_err( + test, + "Condition failed: `Generic:: != Generic` (Generic vs Generic)", + ); + + let test = || Ok(ensure!(Generic:: != Generic)); + assert_err( + test, + "Condition failed: `Generic:: != Generic` (Generic vs Generic)", + ); + + #[rustfmt::skip] + let test = || { + Ok(ensure!( + Generic:: != Generic + )) + }; + assert_err( + test, + "Condition failed: `Generic:: != Generic` (Generic vs Generic)", + ); +} + +#[test] +fn test_macro() { + let test = || Ok(ensure!(anyhow!("...").to_string().len() <= 1)); + assert_err( + test, + "Condition failed: `anyhow!(\"...\").to_string().len() <= 1` (3 vs 1)", + ); + + let test = || Ok(ensure!(vec![1].len() < 1)); + assert_err(test, "Condition failed: `vec![1].len() < 1` (1 vs 1)"); + + let test = || Ok(ensure!(stringify! {} != "")); + assert_err( + test, + "Condition failed: `stringify! {} != \"\"` (\"\" vs \"\")", + ); +} + +#[test] +fn test_trailer() { + let test = || Ok(ensure!((|| 1)() == 2)); + assert_err(test, "Condition failed: `(|| 1)() == 2` (1 vs 2)"); + + let test = || Ok(ensure!(b"hmm"[1] == b'c')); + assert_err(test, "Condition failed: `b\"hmm\"[1] == b'c'` (109 vs 99)"); + + let test = || Ok(ensure!(PhantomData:: {} != PhantomData)); + assert_err( + test, + "Condition failed: `PhantomData:: {} != PhantomData` (PhantomData vs PhantomData)", + ); + + let result = Ok::<_, Error>(1); + let test = || Ok(ensure!(result? == 2)); + assert_err(test, "Condition failed: `result? == 2` (1 vs 2)"); + + let test = || Ok(ensure!((2, 3).1 == 2)); + assert_err(test, "Condition failed: `(2, 3).1 == 2` (3 vs 2)"); + + #[rustfmt::skip] + let test = || Ok(ensure!((2, (3, 4)). 1.1 == 2)); + assert_err(test, "Condition failed: `(2, (3, 4)).1.1 == 2` (4 vs 2)"); + + let err = anyhow!(""); + let test = || Ok(ensure!(err.is::<&str>() == false)); + assert_err( + test, + "Condition failed: `err.is::<&str>() == false` (true vs false)", + ); + + let test = || Ok(ensure!(err.is::<::Owned>() == true)); + assert_err( + test, + "Condition failed: `err.is::<::Owned>() == true` (false vs true)", + ); +} + +#[test] +fn test_whitespace() { + #[derive(Debug)] + pub struct Point { + #[allow(dead_code)] + pub x: i32, + #[allow(dead_code)] + pub y: i32, + } + + let point = Point { x: 0, y: 0 }; + let test = || Ok(ensure!("" == format!("{:#?}", point))); + assert_err( + test, + "Condition failed: `\"\" == format!(\"{:#?}\", point)`", + ); +} + +#[test] +fn test_too_long() { + let test = || Ok(ensure!("" == "x".repeat(10))); + assert_err( + test, + "Condition failed: `\"\" == \"x\".repeat(10)` (\"\" vs \"xxxxxxxxxx\")", + ); + + let test = || Ok(ensure!("" == "x".repeat(80))); + assert_err(test, "Condition failed: `\"\" == \"x\".repeat(80)`"); +} + +#[test] +fn test_as() { + let test = || Ok(ensure!('\0' as u8 > 1)); + assert_err(test, "Condition failed: `'\\0' as u8 > 1` (0 vs 1)"); + + let test = || Ok(ensure!('\0' as ::std::primitive::u8 > 1)); + assert_err( + test, + "Condition failed: `'\\0' as ::std::primitive::u8 > 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(&[0] as &[i32] == [1])); + assert_err( + test, + "Condition failed: `&[0] as &[i32] == [1]` ([0] vs [1])", + ); + + let test = || Ok(ensure!(0 as *const () as *mut _ == 1 as *mut ())); + assert_err( + test, + "Condition failed: `0 as *const () as *mut _ == 1 as *mut ()` (0x0 vs 0x1)", + ); + + let s = ""; + let test = || Ok(ensure!(s as &str != s)); + assert_err(test, "Condition failed: `s as &str != s` (\"\" vs \"\")"); + + let test = || Ok(ensure!(&s as &&str != &s)); + assert_err(test, "Condition failed: `&s as &&str != &s` (\"\" vs \"\")"); + + let test = || Ok(ensure!(s as &'static str != s)); + assert_err( + test, + "Condition failed: `s as &'static str != s` (\"\" vs \"\")", + ); + + let test = || Ok(ensure!(&s as &&'static str != &s)); + assert_err( + test, + "Condition failed: `&s as &&'static str != &s` (\"\" vs \"\")", + ); + + let m: &mut str = Default::default(); + let test = || Ok(ensure!(m as &mut str != s)); + assert_err( + test, + "Condition failed: `m as &mut str != s` (\"\" vs \"\")", + ); + + let test = || Ok(ensure!(&m as &&mut str != &s)); + assert_err( + test, + "Condition failed: `&m as &&mut str != &s` (\"\" vs \"\")", + ); + + let test = || Ok(ensure!(&m as &&'static mut str != &s)); + assert_err( + test, + "Condition failed: `&m as &&'static mut str != &s` (\"\" vs \"\")", + ); + + let f = || {}; + let test = || Ok(ensure!(f as fn() as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as fn() as usize * 0 != 0` (0 vs 0)", + ); + + let test = || Ok(ensure!(f as fn() -> () as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as fn() -> () as usize * 0 != 0` (0 vs 0)", + ); + + let test = || Ok(ensure!(f as for<'a> fn() as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as for<'a> fn() as usize * 0 != 0` (0 vs 0)", + ); + + let test = || Ok(ensure!(f as unsafe fn() as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as unsafe fn() as usize * 0 != 0` (0 vs 0)", + ); + + #[rustfmt::skip] + let test = || Ok(ensure!(f as extern "Rust" fn() as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as extern \"Rust\" fn() as usize * 0 != 0` (0 vs 0)", + ); + + extern "C" fn extern_fn() {} + #[rustfmt::skip] + #[allow(missing_abi)] + let test = || Ok(ensure!(extern_fn as extern fn() as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `extern_fn as extern fn() as usize * 0 != 0` (0 vs 0)", + ); + + let f = || -> ! { panic!() }; + let test = || Ok(ensure!(f as fn() -> ! as usize * 0 != 0)); + assert_err( + test, + "Condition failed: `f as fn() -> ! as usize * 0 != 0` (0 vs 0)", + ); + + trait EqDebug: PartialEq + Debug { + type Assoc; + } + + impl EqDebug for S + where + S: PartialEq + Debug, + { + type Assoc = bool; + } + + let test = || Ok(ensure!(&0 as &dyn EqDebug != &0)); + assert_err( + test, + "Condition failed: `&0 as &dyn EqDebug != &0` (0 vs 0)", + ); + + let test = || { + Ok(ensure!( + PhantomData as PhantomData<::Owned> != PhantomData + )) + }; + assert_err( + test, + "Condition failed: `PhantomData as PhantomData<::Owned> != PhantomData` (PhantomData vs PhantomData)", + ); + + macro_rules! int { + (...) => { + u8 + }; + } + + let test = || Ok(ensure!(0 as int!(...) != 0)); + assert_err(test, "Condition failed: `0 as int!(...) != 0` (0 vs 0)"); + + let test = || Ok(ensure!(0 as int![...] != 0)); + assert_err(test, "Condition failed: `0 as int![...] != 0` (0 vs 0)"); + + let test = || Ok(ensure!(0 as int! {...} != 0)); + assert_err(test, "Condition failed: `0 as int! {...} != 0` (0 vs 0)"); +} + +#[test] +fn test_pat() { + let test = || Ok(ensure!(if let ref mut _x @ 0 = 0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let ref mut _x @ 0 = 0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let -1..=1 = 0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let -1..=1 = 0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let &0 = &0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let &0 = &0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let &&0 = &&0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let &&0 = &&0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let &mut 0 = &mut 0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let &mut 0 = &mut 0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let &&mut 0 = &&mut 0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let &&mut 0 = &&mut 0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let (0, 1) = (0, 1) { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let (0, 1) = (0, 1) { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let [0] = b"\0" { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let [0] = b\"\\0\" { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let p = PhantomData::; + let test = || Ok(ensure!(if let P:: {} = p { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let P:: {} = p { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(if let ::std::marker::PhantomData = p {} != ())); + assert_err( + test, + "Condition failed: `if let ::std::marker::PhantomData = p {} != ()` (() vs ())", + ); + + let test = || Ok(ensure!(if let ::V = 0 { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let ::V = 0 { 0 } else { 1 } == 1` (0 vs 1)", + ); + + let test = || Ok(ensure!(for _ in iter::once(()) {} != ())); + assert_err( + test, + "Condition failed: `for _ in iter::once(()) {} != ()` (() vs ())", + ); + + let test = || Ok(ensure!(if let stringify!(x) = "x" { 0 } else { 1 } == 1)); + assert_err( + test, + "Condition failed: `if let stringify!(x) = \"x\" { 0 } else { 1 } == 1` (0 vs 1)", + ); +} diff --git a/deps/crates/vendor/anyhow/tests/test_ffi.rs b/deps/crates/vendor/anyhow/tests/test_ffi.rs new file mode 100644 index 00000000000000..59578af91a666d --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_ffi.rs @@ -0,0 +1,19 @@ +#![deny(improper_ctypes, improper_ctypes_definitions)] +#![allow(clippy::uninlined_format_args)] + +use anyhow::anyhow; + +#[no_mangle] +pub extern "C" fn anyhow1(err: anyhow::Error) { + println!("{:?}", err); +} + +#[no_mangle] +pub extern "C" fn anyhow2(err: &mut Option) { + *err = Some(anyhow!("ffi error")); +} + +#[no_mangle] +pub extern "C" fn anyhow3() -> Option { + Some(anyhow!("ffi error")) +} diff --git a/deps/crates/vendor/anyhow/tests/test_fmt.rs b/deps/crates/vendor/anyhow/tests/test_fmt.rs new file mode 100644 index 00000000000000..8206f22c41dd71 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_fmt.rs @@ -0,0 +1,93 @@ +use anyhow::{bail, Context, Result}; +use std::io; + +fn f() -> Result<()> { + bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); +} + +fn g() -> Result<()> { + f().context("f failed") +} + +fn h() -> Result<()> { + g().context("g failed") +} + +const EXPECTED_ALTDISPLAY_F: &str = "oh no!"; + +const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!"; + +const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!"; + +const EXPECTED_DEBUG_F: &str = "oh no!"; + +const EXPECTED_DEBUG_G: &str = "\ +f failed + +Caused by: + oh no!\ +"; + +const EXPECTED_DEBUG_H: &str = "\ +g failed + +Caused by: + 0: f failed + 1: oh no!\ +"; + +const EXPECTED_ALTDEBUG_F: &str = "\ +Custom { + kind: PermissionDenied, + error: \"oh no!\", +}\ +"; + +const EXPECTED_ALTDEBUG_G: &str = "\ +Error { + context: \"f failed\", + source: Custom { + kind: PermissionDenied, + error: \"oh no!\", + }, +}\ +"; + +const EXPECTED_ALTDEBUG_H: &str = "\ +Error { + context: \"g failed\", + source: Error { + context: \"f failed\", + source: Custom { + kind: PermissionDenied, + error: \"oh no!\", + }, + }, +}\ +"; + +#[test] +fn test_display() { + assert_eq!("g failed", h().unwrap_err().to_string()); +} + +#[test] +fn test_altdisplay() { + assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err())); + assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err())); + assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err())); +} + +#[test] +fn test_debug() { + assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err())); + assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err())); + assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err())); +} + +#[test] +fn test_altdebug() { + assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err())); + assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err())); + assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err())); +} diff --git a/deps/crates/vendor/anyhow/tests/test_macros.rs b/deps/crates/vendor/anyhow/tests/test_macros.rs new file mode 100644 index 00000000000000..0689506965430f --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_macros.rs @@ -0,0 +1,97 @@ +#![allow( + clippy::assertions_on_result_states, + clippy::eq_op, + clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 + clippy::items_after_statements, + clippy::match_single_binding, + clippy::needless_pass_by_value, + clippy::shadow_unrelated, + clippy::uninlined_format_args, + clippy::wildcard_imports +)] + +mod common; + +use self::common::*; +use anyhow::{anyhow, ensure, Result}; +use std::cell::Cell; +use std::future; + +#[test] +fn test_messages() { + assert_eq!("oh no!", bail_literal().unwrap_err().to_string()); + assert_eq!("oh no!", bail_fmt().unwrap_err().to_string()); + assert_eq!("oh no!", bail_error().unwrap_err().to_string()); +} + +#[test] +fn test_ensure() { + let f = || { + ensure!(1 + 1 == 2, "This is correct"); + Ok(()) + }; + assert!(f().is_ok()); + + let v = 1; + let f = || { + ensure!(v + v == 2, "This is correct, v: {}", v); + Ok(()) + }; + assert!(f().is_ok()); + + let f = || { + ensure!(v + v == 1, "This is not correct, v: {}", v); + Ok(()) + }; + assert!(f().is_err()); + + let f = || { + ensure!(v + v == 1); + Ok(()) + }; + assert_eq!( + f().unwrap_err().to_string(), + "Condition failed: `v + v == 1` (2 vs 1)", + ); +} + +#[test] +fn test_ensure_nonbool() -> Result<()> { + struct Struct { + condition: bool, + } + + let s = Struct { condition: true }; + match &s { + Struct { condition } => ensure!(condition), // &bool + } + + Ok(()) +} + +#[test] +fn test_temporaries() { + fn require_send_sync(_: impl Send + Sync) {} + + require_send_sync(async { + // If anyhow hasn't dropped any temporary format_args it creates by the + // time it's done evaluating, those will stick around until the + // semicolon, which is on the other side of the await point, making the + // enclosing future non-Send. + future::ready(anyhow!("...")).await; + }); + + fn message(cell: Cell<&str>) -> &str { + cell.get() + } + + require_send_sync(async { + future::ready(anyhow!(message(Cell::new("...")))).await; + }); +} + +#[test] +fn test_brace_escape() { + let err = anyhow!("unterminated ${{..}} expression"); + assert_eq!("unterminated ${..} expression", err.to_string()); +} diff --git a/deps/crates/vendor/anyhow/tests/test_repr.rs b/deps/crates/vendor/anyhow/tests/test_repr.rs new file mode 100644 index 00000000000000..2976cd86204a54 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_repr.rs @@ -0,0 +1,30 @@ +#![allow(clippy::extra_unused_type_parameters)] + +mod drop; + +use self::drop::{DetectDrop, Flag}; +use anyhow::Error; +use std::mem; + +#[test] +fn test_error_size() { + assert_eq!(mem::size_of::(), mem::size_of::()); +} + +#[test] +fn test_null_pointer_optimization() { + assert_eq!(mem::size_of::>(), mem::size_of::()); +} + +#[test] +fn test_autotraits() { + fn assert() {} + assert::(); +} + +#[test] +fn test_drop() { + let has_dropped = Flag::new(); + drop(Error::new(DetectDrop::new(&has_dropped))); + assert!(has_dropped.get()); +} diff --git a/deps/crates/vendor/anyhow/tests/test_source.rs b/deps/crates/vendor/anyhow/tests/test_source.rs new file mode 100644 index 00000000000000..018267d315fa7c --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/test_source.rs @@ -0,0 +1,62 @@ +use anyhow::anyhow; +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::io; + +#[derive(Debug)] +enum TestError { + Io(io::Error), +} + +impl Display for TestError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TestError::Io(e) => Display::fmt(e, formatter), + } + } +} + +impl StdError for TestError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + TestError::Io(io) => Some(io), + } + } +} + +#[test] +fn test_literal_source() { + let error = anyhow!("oh no!"); + assert!(error.source().is_none()); +} + +#[test] +fn test_variable_source() { + let msg = "oh no!"; + let error = anyhow!(msg); + assert!(error.source().is_none()); + + let msg = msg.to_owned(); + let error = anyhow!(msg); + assert!(error.source().is_none()); +} + +#[test] +fn test_fmt_source() { + let error = anyhow!("{} {}!", "oh", "no"); + assert!(error.source().is_none()); +} + +#[test] +fn test_io_source() { + let io = io::Error::new(io::ErrorKind::Other, "oh no!"); + let error = anyhow!(TestError::Io(io)); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} + +#[test] +fn test_anyhow_from_anyhow() { + let error = anyhow!("oh no!").context("context"); + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} diff --git a/deps/crates/vendor/anyhow/tests/ui/chained-comparison.rs b/deps/crates/vendor/anyhow/tests/ui/chained-comparison.rs new file mode 100644 index 00000000000000..4521b51c8ca216 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/chained-comparison.rs @@ -0,0 +1,8 @@ +use anyhow::{ensure, Result}; + +fn main() -> Result<()> { + // `ensure!` must not partition this into `(false) == (false == true)` + // because Rust doesn't ordinarily allow this form of expression. + ensure!(false == false == true); + Ok(()) +} diff --git a/deps/crates/vendor/anyhow/tests/ui/chained-comparison.stderr b/deps/crates/vendor/anyhow/tests/ui/chained-comparison.stderr new file mode 100644 index 00000000000000..2a4c66508a0a65 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/chained-comparison.stderr @@ -0,0 +1,10 @@ +error: comparison operators cannot be chained + --> tests/ui/chained-comparison.rs:6:19 + | +6 | ensure!(false == false == true); + | ^^ ^^ + | +help: split the comparison into two + | +6 | ensure!(false == false && false == true); + | ++++++++ diff --git a/deps/crates/vendor/anyhow/tests/ui/empty-ensure.rs b/deps/crates/vendor/anyhow/tests/ui/empty-ensure.rs new file mode 100644 index 00000000000000..139b743bbf9bdf --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/empty-ensure.rs @@ -0,0 +1,6 @@ +use anyhow::{ensure, Result}; + +fn main() -> Result<()> { + ensure!(); + Ok(()) +} diff --git a/deps/crates/vendor/anyhow/tests/ui/empty-ensure.stderr b/deps/crates/vendor/anyhow/tests/ui/empty-ensure.stderr new file mode 100644 index 00000000000000..bf0229a2b238b3 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/empty-ensure.stderr @@ -0,0 +1,12 @@ +error: unexpected end of macro invocation + --> tests/ui/empty-ensure.rs:4:5 + | +4 | ensure!(); + | ^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$cond:expr` + --> src/ensure.rs + | + | ($cond:expr $(,)?) => { + | ^^^^^^^^^^ + = note: this error originates in the macro `$crate::__parse_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.rs b/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.rs new file mode 100644 index 00000000000000..c7df4e17c2f3dd --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.rs @@ -0,0 +1,40 @@ +use anyhow::{ensure, Result}; +use std::ops::{Deref, Not}; + +struct Bool(bool); + +struct DerefBool(bool); + +struct NotBool(bool); + +impl Deref for DerefBool { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Not for NotBool { + type Output = bool; + fn not(self) -> Self::Output { + !self.0 + } +} + +fn main() -> Result<()> { + ensure!("..."); + + let mut s = Bool(true); + match &mut s { + Bool(cond) => ensure!(cond), + } + + let db = DerefBool(true); + ensure!(db); + ensure!(&db); + + let nb = NotBool(true); + ensure!(nb); + + Ok(()) +} diff --git a/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.stderr b/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.stderr new file mode 100644 index 00000000000000..5a4e0eccd5a33a --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/ensure-nonbool.stderr @@ -0,0 +1,113 @@ +error[E0277]: the trait bound `&str: anyhow::__private::not::Bool` is not satisfied + --> tests/ui/ensure-nonbool.rs:25:13 + | +25 | ensure!("..."); + | --------^^^^^- + | | | + | | the trait `anyhow::__private::not::Bool` is not implemented for `&str` + | required by a bound introduced by this call + | +help: the following other types implement trait `anyhow::__private::not::Bool` + --> src/lib.rs + | + | impl Bool for bool { + | ^^^^^^^^^^^^^^^^^^ `bool` +... + | impl Bool for &bool { + | ^^^^^^^^^^^^^^^^^^^ `&bool` +note: required by a bound in `anyhow::__private::not` + --> src/lib.rs + | + | pub fn not(cond: impl Bool) -> bool { + | ^^^^ required by this bound in `not` + +error[E0277]: the trait bound `&mut bool: anyhow::__private::not::Bool` is not satisfied + --> tests/ui/ensure-nonbool.rs:29:31 + | +29 | Bool(cond) => ensure!(cond), + | --------^^^^- + | | | + | | the trait `anyhow::__private::not::Bool` is not implemented for `&mut bool` + | required by a bound introduced by this call + | + = note: `anyhow::__private::not::Bool` is implemented for `&bool`, but not for `&mut bool` +note: required by a bound in `anyhow::__private::not` + --> src/lib.rs + | + | pub fn not(cond: impl Bool) -> bool { + | ^^^^ required by this bound in `not` +help: consider dereferencing here + | +29 | Bool(cond) => ensure!(*cond), + | + + +error[E0277]: the trait bound `DerefBool: anyhow::__private::not::Bool` is not satisfied + --> tests/ui/ensure-nonbool.rs:33:13 + | +33 | ensure!(db); + | --------^^- + | | | + | | unsatisfied trait bound + | required by a bound introduced by this call + | +help: the trait `anyhow::__private::not::Bool` is not implemented for `DerefBool` + --> tests/ui/ensure-nonbool.rs:6:1 + | + 6 | struct DerefBool(bool); + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `anyhow::__private::not` + --> src/lib.rs + | + | pub fn not(cond: impl Bool) -> bool { + | ^^^^ required by this bound in `not` +help: consider dereferencing here + | +33 | ensure!(*db); + | + + +error[E0277]: the trait bound `&DerefBool: anyhow::__private::not::Bool` is not satisfied + --> tests/ui/ensure-nonbool.rs:34:13 + | +34 | ensure!(&db); + | --------^^^- + | | | + | | the trait `anyhow::__private::not::Bool` is not implemented for `&DerefBool` + | required by a bound introduced by this call + | +note: required by a bound in `anyhow::__private::not` + --> src/lib.rs + | + | pub fn not(cond: impl Bool) -> bool { + | ^^^^ required by this bound in `not` +help: consider dereferencing here + | +34 | ensure!(&*db); + | + + +error[E0277]: the trait bound `NotBool: anyhow::__private::not::Bool` is not satisfied + --> tests/ui/ensure-nonbool.rs:37:13 + | +37 | ensure!(nb); + | --------^^- + | | | + | | unsatisfied trait bound + | required by a bound introduced by this call + | +help: the trait `anyhow::__private::not::Bool` is not implemented for `NotBool` + --> tests/ui/ensure-nonbool.rs:8:1 + | + 8 | struct NotBool(bool); + | ^^^^^^^^^^^^^^ +help: the following other types implement trait `anyhow::__private::not::Bool` + --> src/lib.rs + | + | impl Bool for bool { + | ^^^^^^^^^^^^^^^^^^ `bool` +... + | impl Bool for &bool { + | ^^^^^^^^^^^^^^^^^^^ `&bool` +note: required by a bound in `anyhow::__private::not` + --> src/lib.rs + | + | pub fn not(cond: impl Bool) -> bool { + | ^^^^ required by this bound in `not` diff --git a/deps/crates/vendor/anyhow/tests/ui/must-use.rs b/deps/crates/vendor/anyhow/tests/ui/must-use.rs new file mode 100644 index 00000000000000..ea4e58f55ee43c --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/must-use.rs @@ -0,0 +1,11 @@ +#![deny(unused_must_use)] + +use anyhow::anyhow; + +fn main() -> anyhow::Result<()> { + if true { + // meant to write bail! + anyhow!("it failed"); + } + Ok(()) +} diff --git a/deps/crates/vendor/anyhow/tests/ui/must-use.stderr b/deps/crates/vendor/anyhow/tests/ui/must-use.stderr new file mode 100644 index 00000000000000..b2a3f3146a448a --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/must-use.stderr @@ -0,0 +1,15 @@ +error: unused return value of `anyhow::__private::must_use` that must be used + --> tests/ui/must-use.rs:8:9 + | +8 | anyhow!("it failed"); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/must-use.rs:1:9 + | +1 | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +8 | let _ = anyhow!("it failed"); + | +++++++ diff --git a/deps/crates/vendor/anyhow/tests/ui/no-impl.rs b/deps/crates/vendor/anyhow/tests/ui/no-impl.rs new file mode 100644 index 00000000000000..d2e89afc1b36e2 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/no-impl.rs @@ -0,0 +1,8 @@ +use anyhow::anyhow; + +#[derive(Debug)] +struct Error; + +fn main() { + let _ = anyhow!(Error); +} diff --git a/deps/crates/vendor/anyhow/tests/ui/no-impl.stderr b/deps/crates/vendor/anyhow/tests/ui/no-impl.stderr new file mode 100644 index 00000000000000..9b584df412c208 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/no-impl.stderr @@ -0,0 +1,32 @@ +error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its trait bounds were not satisfied + --> tests/ui/no-impl.rs:7:13 + | +4 | struct Error; + | ------------ doesn't satisfy `Error: Into`, `Error: anyhow::kind::TraitKind` or `Error: std::fmt::Display` +... +7 | let _ = anyhow!(Error); + | ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Error: Into` + which is required by `Error: anyhow::kind::TraitKind` + `Error: std::fmt::Display` + which is required by `&Error: anyhow::kind::AdhocKind` + `&Error: Into` + which is required by `&Error: anyhow::kind::TraitKind` +note: the traits `Into` and `std::fmt::Display` must be implemented + --> $RUST/core/src/fmt/mod.rs + | + | pub trait Display: PointeeSized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: $RUST/core/src/convert/mod.rs + | + | pub const trait Into: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `anyhow_kind`, perhaps you need to implement one of them: + candidate #1: `anyhow::kind::AdhocKind` + candidate #2: `anyhow::kind::BoxedKind` + candidate #3: `anyhow::kind::TraitKind` + = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/deps/crates/vendor/anyhow/tests/ui/temporary-value.rs b/deps/crates/vendor/anyhow/tests/ui/temporary-value.rs new file mode 100644 index 00000000000000..803809b238f0d2 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/temporary-value.rs @@ -0,0 +1,5 @@ +use anyhow::anyhow; + +fn main() { + let _ = anyhow!(&String::new()); +} diff --git a/deps/crates/vendor/anyhow/tests/ui/temporary-value.stderr b/deps/crates/vendor/anyhow/tests/ui/temporary-value.stderr new file mode 100644 index 00000000000000..c92ec92d461f36 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/temporary-value.stderr @@ -0,0 +1,15 @@ +error[E0716]: temporary value dropped while borrowed + --> tests/ui/temporary-value.rs:4:22 + | +4 | let _ = anyhow!(&String::new()); + | ---------^^^^^^^^^^^^^- + | | | + | | creates a temporary value which is freed while still in use + | temporary value is freed at the end of this statement + | argument requires that borrow lasts for `'static` + | +note: requirement that the value outlives `'static` introduced here + --> src/kind.rs + | + | M: Display + Debug + Send + Sync + 'static, + | ^^^^^^^ diff --git a/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.rs b/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.rs new file mode 100644 index 00000000000000..b870ca713d4adf --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.rs @@ -0,0 +1,5 @@ +use anyhow::{bail, Result}; + +fn main() -> Result<()> { + bail!("{} not found"); +} diff --git a/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.stderr b/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.stderr new file mode 100644 index 00000000000000..55a29641136719 --- /dev/null +++ b/deps/crates/vendor/anyhow/tests/ui/wrong-interpolation.stderr @@ -0,0 +1,5 @@ +error: 1 positional argument in format string, but no arguments were given + --> tests/ui/wrong-interpolation.rs:4:12 + | +4 | bail!("{} not found"); + | ^^ diff --git a/deps/crates/vendor/arbitrary/.cargo-checksum.json b/deps/crates/vendor/arbitrary/.cargo-checksum.json new file mode 100644 index 00000000000000..b0e329a6a93a65 --- /dev/null +++ b/deps/crates/vendor/arbitrary/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"4ccfce7ed08cd9e4c7c6dde4ba7150998c79fe9e2bea9789a67db2e11826ca0f",".github/workflows/rust.yml":"547c39288b203a13a0067413953d28d9f40f12c3cabe3e93b497addc97243b93","CHANGELOG.md":"0635d44ea4dd7af870a570661568dfff09175dafa88f999b1904d8dc81024262","Cargo.lock":"dc6ed543396cf073d2b0e045f09505a77b80a54e1b4a7ec71b8edde4f3454d65","Cargo.toml":"18431fa35c62df4019339b0b105a0ee12e8db49ca178e68f0fb3b9b7e5e8ec01","Cargo.toml.orig":"4c37498742093f3ae1e828f2f9a3678e16fb599cae3c7d8ac6f2816d9c28f851","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"15656cc11a8331f28c0986b8ab97220d3e76f98e60ed388b5ffad37dfac4710c","README.md":"480774d6a0bedd284549aac8ce7757d8e7cdcc4713fd64214742088975f58f7d","examples/derive_enum.rs":"45d11d8cd0461716b276e2df4a5b31e7ae7ece36f05d42a0d4c055a5e4f02ab1","publish.sh":"752e221bdd960666b127df15effddd3d789ff3f1762498961fc79ae99f9a27f1","src/error.rs":"9340da1575e92d57169798bc23f5356d9e97963497fdc6b2d6f8b8c2d7fd5be6","src/foreign/alloc/borrow.rs":"2741eea43a139e7c83b92ab237a60f421224c539ef90ae3125be34b1e6943e54","src/foreign/alloc/boxed.rs":"2ea6fe8795b644de7785ff5373ab6728399de531c2bf50b8f501d48e15dc92db","src/foreign/alloc/collections/binary_heap.rs":"69e648323514313a6f9b6e24b1dbe03d3b24830608f04ad8acac043e6eb44a2b","src/foreign/alloc/collections/btree_map.rs":"158e9e611cb7b03b3190ee8bbebe855cf2291bf14c2adc774d4e6edf5ec47650","src/foreign/alloc/collections/btree_set.rs":"16ad32b9edaa871c046a2543614eb18513801fd880f8926343c2cc74ee7251a4","src/foreign/alloc/collections/linked_list.rs":"cad35cd65f824ef4f0931fa6c200d737b2ac56c3940321a7c7c7b7d9b2d86f1f","src/foreign/alloc/collections/mod.rs":"e81c20370de8903f79d53dd89552c00d3ce6ff12280b379a5ab8d8d1adcecaa5","src/foreign/alloc/collections/vec_deque.rs":"0821db085c8303f8f9e4a316a6dbb5529330488ed06c19284a22a6ef72313270","src/foreign/alloc/ffi/c_str.rs":"16228949035611dfa6522fdc8f25f5afc188eef74febbf06769e9edb88a8430f","src/foreign/alloc/ffi/mod.rs":"9e612467614f7a53369b11278d624bca71f1f44156fcb58d891c7d06f6f1425f","src/foreign/alloc/mod.rs":"27e0cdebd51ee3626ac7ae0b6926c25fdacc9c74b337318d35573d33cc9996b9","src/foreign/alloc/rc.rs":"d17102fc5573461b33b995b5e69553f4d1115f40d70a500c6b86cdf1af766e48","src/foreign/alloc/string.rs":"4c67871b59fb0ce1c13c54b2df2e2054cf02986152bcead7a701fc272ded3cbd","src/foreign/alloc/sync.rs":"e95b2d61962247a03524583aa5ecd1ad5abeb2cfe6590b3ccf7f26649f1287ac","src/foreign/alloc/vec.rs":"57ca9806b9381d6b53e46a0b15fa97c1c698ef950686a1502d0b034656a3f23e","src/foreign/core/array.rs":"1d8c7d794f9990ea43166744a7b25937d43f5f438d0a2c0ab086d88ea07258bd","src/foreign/core/bool.rs":"0f8eff3a2520c85d4bf0ea72895c45e809bf99e45cc10b3e6d3f571ada05de52","src/foreign/core/cell.rs":"b594f71084136f441d49340c74e5df734df9f6d91a3fd9945d96595c440f0a2b","src/foreign/core/char.rs":"a4ce48e71e3acd09c5b42259455c131522d1d21534324cd62f34027d3db5336a","src/foreign/core/cmp.rs":"55cceee1523a0cefbcd7fa2bbe4b6661b473bf950115f41c64e9fffd77276dce","src/foreign/core/iter.rs":"8e5ea3c9885db203cdfb55585c7f6d46f70aa626188abf80af58f2c96df38f53","src/foreign/core/marker.rs":"67386fd457adfabcca6c6fdfbc6883782f6ee3bdd8c344e316adc4587de886af","src/foreign/core/mod.rs":"f5c98383dc33e4a45bc32136ca26c985f2b45771573ac7152a9335992456bc24","src/foreign/core/num.rs":"294b4977e7707d274461d3029fc7b3225fe2dc4d21e0b86f01bed16b24f901b6","src/foreign/core/ops.rs":"f9bfaef1d11aac50dbefbcd2122b912999401a5a1a165caadc7c3e7aa844d61a","src/foreign/core/option.rs":"173f8a9193b075f2c7fe754177912432d8b4f06fdeeca55cab8ebce332a8ccaa","src/foreign/core/result.rs":"13ea4aab756af7de3e1cc1e38aa0a68045c213636809862193a047c36f13f0a7","src/foreign/core/slice.rs":"f42caa49d1a55461c9d515d386fc2b7b2bfc5f0ac8a229d5ca465af5573a453f","src/foreign/core/str.rs":"add0bc52fcc06adcf294f16bf95f3c513ce07a2fd614d8474976cbf743922e2a","src/foreign/core/sync/atomic.rs":"541583cb54d26c65b99254e788e1d4a6a14e4fdba351f14e700fdbc0416e8326","src/foreign/core/sync/mod.rs":"a5ae8ce1fc6b462b1f57993f94bd8cf014d5375728e67dd9c24a21b66cba95c8","src/foreign/core/time.rs":"fa0f1383c65e44c185f2f5112c22a6ca58f9688c5bac1b130c5d91d11c0fa7a4","src/foreign/core/tuple.rs":"66e9361bec0d62d2f4214ddab266fee2258cbf52c1243f8882612861b2bd98f1","src/foreign/core/unit.rs":"1035c63c6a7757bae8940bf0fbdcc8c49a2ca2ea004d8c39666c5d0b22d921e1","src/foreign/mod.rs":"9ab162a3dc28ad93acf2a8fc2942d0f409de349a4282f42538e09669aec4aaa5","src/foreign/std/collections/hash_map.rs":"aa6c7e6e7cf4afcb207fa43f1edf95dd3ec4d78cc5fe86bf40a8b98b116d5f0f","src/foreign/std/collections/hash_set.rs":"4b36b1e6f096c8690c7c6b106505c53cd58370f9fb9b4683cd753fa7f393bda4","src/foreign/std/collections/mod.rs":"54399ce5574fd1d84b7b0cb4238fa3e898575e89a6724299be009d2172bda02e","src/foreign/std/ffi/c_str.rs":"80c4bcd6e3d79999503b50c9b82c234539cd63905c0745f9f755b91e1fe54f9a","src/foreign/std/ffi/mod.rs":"7b6b2f64278961fb440787161924427fb6f4ebc376243932ecab9409e1dab755","src/foreign/std/ffi/os_str.rs":"e20cce997e2139d51dc345375e3ad8da3385de7d46e3dc288fc4963835fcb0e6","src/foreign/std/mod.rs":"f304d0482650833ce7f3a785add71590019c3e00ce39f68740b98a966100acf3","src/foreign/std/net.rs":"e391211150bd94fc6fd7f8dac0e1e7e0454b6421f69790996efd93fcd5e277a8","src/foreign/std/path.rs":"8ef7a801595763c99a1342eeaa222a08a46e5c5770bc4a167d36cfd933ad9649","src/foreign/std/sync.rs":"bfbde00300424956e7f06df3194547c0cf2a463ec60df47b0ec90d920e063f8b","src/lib.rs":"62eb6dfc34cc0e97e4be4c43de1071e698d2848349871395a2c3b13dd5883f7c","src/size_hint.rs":"2e409df461eabb90c4b3e6788e99cb9469a134bb28b95bb7faf1ca5061a6be91","src/tests.rs":"9044f1cf9fbf4879c4e91181376b52700d4dacbcdd1c792743c8abd69281d59a","src/unstructured.rs":"b775c04198c786ebc1a022ffbcf4c6f8d3a0406e4900d8829577b59268759dc0","tests/bound.rs":"32b8ce8083419ecadd66e1fde4da427b437ac9e007ed9d6b5229a4ef24a5d772","tests/derive.rs":"ea65d058a28fce8b54c0b707027907547a1e512038d621b778b1e2987f1a8755","tests/path.rs":"7e3e5fa26d5671ac19e99ba010a2fa0894fafe996c5d28ee587919e486d7c7c1"},"package":"c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"} \ No newline at end of file diff --git a/deps/crates/vendor/arbitrary/.cargo_vcs_info.json b/deps/crates/vendor/arbitrary/.cargo_vcs_info.json new file mode 100644 index 00000000000000..25f2bce8116a39 --- /dev/null +++ b/deps/crates/vendor/arbitrary/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "dc22fdefd5456a0f4d2f190c6d3e017e3c7ddd8e" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/arbitrary/.github/workflows/rust.yml b/deps/crates/vendor/arbitrary/.github/workflows/rust.yml new file mode 100644 index 00000000000000..1dbac58722adad --- /dev/null +++ b/deps/crates/vendor/arbitrary/.github/workflows/rust.yml @@ -0,0 +1,63 @@ +name: Rust + +on: [push, pull_request] + +jobs: + vanilla_build: + name: Vanilla Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - name: Build + run: cargo build --verbose --all + - name: Run tests + run: cargo test --verbose --all + all_features_build: + name: All Features Enabled Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - name: Build + run: cargo build --verbose --all-features --all + - name: Run tests + run: cargo test --verbose --all-features --all + - name: Build Examples + run: cargo build --examples --all-features --all + msrv: + name: Minimum Supported Rust Version + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup toolchain add 1.63 + - name: Build + run: cargo +1.63 check --lib --all-features + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - run: rustup component add clippy + - run: cargo clippy --all-features --workspace -- -Dclippy::all + rustfmt: + name: Check rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - run: rustup component add rustfmt --toolchain stable + - run: cargo +stable fmt --all -- --check + fuzz: + name: Run `int_in_range` fuzz target + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - name: "Install nightly" + run: rustup toolchain install nightly && rustup default nightly + - name: "Install `cargo-fuzz`" + run: cargo install cargo-fuzz + - name: "Fuzz for 3 minutes" + run: cargo fuzz run int_in_range -- -max_total_time=$((3 * 60)) diff --git a/deps/crates/vendor/arbitrary/CHANGELOG.md b/deps/crates/vendor/arbitrary/CHANGELOG.md new file mode 100644 index 00000000000000..bce7faf4ea26e5 --- /dev/null +++ b/deps/crates/vendor/arbitrary/CHANGELOG.md @@ -0,0 +1,553 @@ +## Unreleased + +Released YYYY-MM-DD. + +### Added + +* TODO (or remove section if none) + +### Changed + +* TODO (or remove section if none) + +### Deprecated + +* TODO (or remove section if none) + +### Removed + +* TODO (or remove section if none) + +### Fixed + +* TODO (or remove section if none) + +### Security + +* TODO (or remove section if none) + +-------------------------------------------------------------------------------- + +## 1.4.2 + +Released 2025-08-13. + +### Added + +* Added formal MSRV policy: "We reserve the right to increment the MSRV on minor + releases, however we will strive to only do it deliberately and for good + reasons." The current MSRV is 1.63.0. +* Added an `Arbitrary` implementation for `core::cmp::Reverse`. + +### Changed + +* Landed a handful of changes to the code generated by `#[derive(Arbitrary)]` + that speed up compilation. + +### Fixed + +* Better documented bias and behavior when running out of entropy, fixed some + outdated and incorrect docs related to this. + +-------------------------------------------------------------------------------- + +## 1.4.1 + +Released 2024-11-05. + +-------------------------------------------------------------------------------- + +## 1.4.0 + +Released 2024-10-30. + +### Added + +* Added an `Arbitrary` implementation for `PhantomPinned`. +* Added the `Unstructured::choose_iter` helper method. +* Added `#[arbitrary(skip)]` for `enum` variants in the derive macro. +* Added the `Arbitrary::try_size_hint` trait method. + +### Changed + +* Implement `Arbitrary` for `PhantomData` even when `A` does not implement + `Arbitrary` and when `A` is `?Sized`. +* Make `usize`'s underlying encoding independent of machine word size so that + corpora are more portable. + +### Fixed + +* Make `derive(Arbitrary)` work for local definitions of `struct Option`. + +-------------------------------------------------------------------------------- + +## 1.3.2 + +Released 2023-10-30. + +### Added + +* Added `Arbitrary` implementations for `Arc<[T]>` and + `Rc<[T]>`. [#160](https://github.com/rust-fuzz/arbitrary/pull/160) + +-------------------------------------------------------------------------------- + +## 1.3.1 + +Released 2023-10-11. + +### Fixed + +* Fixed an issue with generating collections of collections in + `arbitrary_take_rest` where `>>::arbitrary_take_rest` would never + generate `vec![vec![]]` for example. See + [#159](https://github.com/rust-fuzz/arbitrary/pull/159) for details. + +-------------------------------------------------------------------------------- + +## 1.3.0 + +Released 2023-03-13. + +### Added + +* Added the ability to manually specify derived trait bounds for + `Arbitrary`. See [#138](https://github.com/rust-fuzz/arbitrary/pull/138) for + details. + +### Fixed + +* Fixed minimal versions correctness for `syn`. + +-------------------------------------------------------------------------------- + +## 1.2.3 + +Released 2023-01-20. + +### Fixed + +* The `derive(Arbitrary)` will now annotate the generated `impl`s with a `#[automatically_derived]` + attribute to indicate to e.g. clippy that lints should not fire for the code within the derived + implementation. + +## 1.2.2 + +Released 2023-01-03. + +### Fixed + +* Ensured that `arbitrary` and `derive_arbitrary` versions are synced up so that + they don't, e.g., emit generated code that depends on newer versions of + `arbitrary` than the one currently in + use. [#134](https://github.com/rust-fuzz/arbitrary/issues/134) + +## 1.2.1 + +### Fixed + +* Fixed an issue where `std::thread_local!` macro invocations in derive code + were not fully prefixed, causing confusing build errors in certain situations. + +## 1.2.0 + +Released 2022-10-20. + +### Added + +* Support custom arbitrary implementation for fields on + derive. [#129](https://github.com/rust-fuzz/arbitrary/pull/129) + +-------------------------------------------------------------------------------- + +## 1.1.6 + +Released 2022-09-20. + +### Fixed + +* Fixed a potential panic due to an off-by-one error in the `Arbitrary` + implementation for `std::ops::Bound`. + +-------------------------------------------------------------------------------- + +## 1.1.5 + +Released 2022-09-08. + +### Added + +* Implemented `Arbitrary` for `std::ops::Bound`. + +### Fixed + +* Fixed a bug where `Unstructured::int_in_range` could return out-of-range + integers when generating arbitrary signed integers. + +-------------------------------------------------------------------------------- + +## 1.1.4 + +Released 2022-08-29. + +### Added + +* Implemented `Arbitrary` for `Rc` and `Arc` + +### Changed + +* Allow overriding the error type in `arbitrary::Result` +* The `Unstructured::arbitrary_loop` method will consume fewer bytes of input + now. + +### Fixed + +* Fixed a bug where `Unstructured::int_in_range` could return out-of-range + integers. + +-------------------------------------------------------------------------------- + +## 1.1.3 + +Released 2022-06-23. + +### Fixed + +* Fixed some potential (but highly unlikely) name-clashes inside + `derive(Arbitrary)`'s generated + code. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) +* Fixed an edge case where `derive(Arbitrary)` for recursive types that detected + an overflow would not reset the overflow + detection. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) + +-------------------------------------------------------------------------------- + +## 1.1.2 + +Released 2022-06-16. + +### Fixed + +* Fixed a warning inside `derive(Arbitrary)`-generated + code. [#110](https://github.com/rust-fuzz/arbitrary/pull/110) + +-------------------------------------------------------------------------------- + +## 1.1.1 + +Released 2022-06-14. + +### Fixed + +* Fixed a stack overflow when using `derive(Arbitrary)` with recursive types and + empty inputs. [#109](https://github.com/rust-fuzz/arbitrary/pull/109) + +-------------------------------------------------------------------------------- + +## 1.1.0 + +Released 2022-02-09. + +### Added + +* Added the `Unstructured::ratio` method to generate a boolean that is `true` at + the given rate. + +* Added the `Unstructured::arbitrary_loop` method to call a function an + arbitrary number of times. + +-------------------------------------------------------------------------------- + +## 1.0.3 + +Released 2021-11-20. + +### Fixed + +* Fixed documentation for `Unstructured::fill_bytes`. We forgot to update this + way back in [#53](https://github.com/rust-fuzz/arbitrary/pull/53) when the + behavior changed. + +-------------------------------------------------------------------------------- + +## 1.0.2 + +Released 2021-08-25. + +### Added + +* `Arbitrary` impls for `HashMap`s and `HashSet`s with custom `Hasher`s + [#87](https://github.com/rust-fuzz/arbitrary/pull/87) + +-------------------------------------------------------------------------------- + +## 1.0.1 + +Released 2021-05-20. + +### Added + +* `Arbitrary` impls for `NonZeroX` types [#79](https://github.com/rust-fuzz/arbitrary/pull/79) +* `Arbitrary` impls for all arrays using const generics [#55](https://github.com/rust-fuzz/arbitrary/pull/55) +* `Arbitrary` impls for `Ipv4Addr` and `Ipv6Addr` [#84](https://github.com/rust-fuzz/arbitrary/pull/84) + +### Fixed + +* Use fewer bytes for `Unstructured::int_in_range()` [#80](https://github.com/rust-fuzz/arbitrary/pull/80) +* Use correct range for `char` generation [#83](https://github.com/rust-fuzz/arbitrary/pull/83) + +-------------------------------------------------------------------------------- + +## 1.0.0 + +Released 2020-02-24. + +See 1.0.0-rc1 and 1.0.0-rc2 for changes since 0.4.7, which was the last main +line release. + +-------------------------------------------------------------------------------- + +## 1.0.0-rc2 + +Released 2021-02-09. + +### Added + +* The `Arbitrary` trait is now implemented for `&[u8]`. [#67](https://github.com/rust-fuzz/arbitrary/pull/67) + +### Changed + +* Rename `Unstructured#get_bytes` to `Unstructured#bytes`. [#70](https://github.com/rust-fuzz/arbitrary/pull/70) +* Passing an empty slice of choices to `Unstructured#choose` returns an error. Previously it would panic. [71](https://github.com/rust-fuzz/arbitrary/pull/71) + +-------------------------------------------------------------------------------- + +## 1.0.0-rc1 + +Released 2020-11-25. + +### Added + +* The `Arbitrary` trait is now implemented for `&str`. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) + +### Changed + +* The `Arbitrary` trait now has a lifetime parameter, allowing `Arbitrary` implementations that borrow from the raw input (e.g. the new `&str` implementaton). The `derive(Arbitrary)` macro also supports deriving `Arbitrary` on types with lifetimes now. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) + +### Removed + +* The `shrink` method on the `Arbitrary` trait has been removed. + + We have found that, in practice, using [internal reduction](https://drmaciver.github.io/papers/reduction-via-generation-preview.pdf) via approaches like `cargo fuzz tmin`, where the raw input bytes are reduced rather than the `T: Arbitrary` type constructed from those raw bytes, has the best efficiency-to-maintenance ratio. To the best of our knowledge, no one is relying on or using the `Arbitrary::shrink` method. If you *are* using and relying on the `Arbitrary::shrink` method, please reach out by [dropping a comment here](https://github.com/rust-fuzz/arbitrary/issues/62) and explaining how you're using it and what your use case is. We'll figure out what the best solution is, including potentially adding shrinking functionality back to the `arbitrary` crate. + +-------------------------------------------------------------------------------- + +## 0.4.7 + +Released 2020-10-14. + +### Added + +* Added an optimization to avoid unnecessarily consuming bytes from the + underlying data when there is only one possible choice in + `Unstructured::{int_in_range, choose, etc..}`. + +* Added license files to the derive crate. + +### Changed + +* The `Arbitrary` implementation for `std::time::Duration` should now be faster + and produce durations with a more-uniform distribution of nanoseconds. + +-------------------------------------------------------------------------------- + +## 0.4.6 + +Released 2020-08-22. + +### Added + +* Added the `Unstructured::peek_bytes` method. + +### Changed + +* Test case reduction via `cargo fuzz tmin` should be much more effective at + reducing the sizes of collections now. (See + [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit messages + for details.) + +* Fuzzing with mutation-based fuzzers (like libFuzzer) should be more efficient + now. (See [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit + messages for details) + +-------------------------------------------------------------------------------- + +## 0.4.5 + +Released 2020-06-18. + +### Added + +* Implement `Arbitrary` for zero length arrays. +* Implement `Arbitrary` for `Range` and `RangeInclusive`. + +-------------------------------------------------------------------------------- + +## 0.4.4 + +Released 2020-04-29. + +### Fixed + +* Fixed the custom derive for enums when used via its full path (like + `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). + + +## 0.4.3 + +Released 2020-04-28. + +### Fixed + +* Fixed the custom derive when used via its full path (like + `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). + +-------------------------------------------------------------------------------- + +## 0.4.2 + +Released 2020-04-17. + +### Changed + +* We forgot to release a new version of the `derive_arbitrary` crate last + release. This release fixes that and so the `synstructure` dependency is + finally actually removed in the cargo releases. + +-------------------------------------------------------------------------------- + +## 0.4.1 + +Released 2020-03-18. + +### Removed + +* Removed an internal dependency on the `synstructure` crate when the `derive` + feature is enabled. This should not have any visible downstream effects other + than faster build times! + +-------------------------------------------------------------------------------- + +## 0.4.0 + +Released 2020-01-22. + +This is technically a breaking change, but we expect that nearly everyone should +be able to upgrade without any compilation errors. The only exception is if you +were implementing the `Arbitrary::size_hint` method by hand. If so, see the +"changed" section below and the [API docs for +`Arbitrary::shrink`](https://docs.rs/arbitrary/0.4.0/arbitrary/trait.Arbitrary.html#method.size_hint) +for details. + +### Added + +* Added [the `arbitary::size_hint::recursion_guard` helper + function][recursion_guard] for guarding against infinite recursion in + `size_hint` implementations for recursive types. + +### Changed + +* The `Arbitrary::size_hint` signature now takes a `depth: usize` + parameter. This should be passed along unmodified to any nested calls of other + `size_hint` methods. If you're implementing `size_hint` for a recursive type + (like a linked list or tree) or a generic type with type parameters, you + should use [the new `arbitrary::size_hint::recursion_guard` helper + function][recursion_guard]. + +### Fixed + +* Fixed infinite recursion in generated `size_hint` implementations + from `#[derive(Arbitrary)]` for recursive types. + +[recursion_guard]: https://docs.rs/arbitrary/0.4.0/arbitrary/size_hint/fn.recursion_guard.html + +-------------------------------------------------------------------------------- + +## 0.3.2 + +Released 2020-01-16. + +### Changed + +* Updated the custom derive's dependencies. + +-------------------------------------------------------------------------------- + +## 0.3.2 + +Released 2020-01-15. + +### Fixed + +* Fixed an over-eager assertion condition in `Unstructured::int_in_range` that + would incorrectly trigger when given valid ranges of length one. + +-------------------------------------------------------------------------------- + +## 0.3.1 + +Released 2020-01-14. + +### Fixed + +* Fixed some links and version numbers in README. + +-------------------------------------------------------------------------------- + +## 0.3.0 + +Released 2020-01-14. + +### Added + +* Added the `"derive"` cargo feature, to enable `#[derive(Arbitrary)]` for + custom types. Enabling this feature re-exports functionality from the + `derive_arbitrary` crate. +* The custom derive for `Arbitrary` implements the shrink method for you now. +* All implementations of `Arbitrary` for `std` types implement shrinking now. +* Added the `Arbitrary::arbitrary_take_rest` method allows an `Arbitrary` + implementation to consume all of the rest of the remaining raw input. It has a + default implementation that forwards to `Arbitrary::arbitrary` and the custom + derive creates a smart implementation for your custom types. +* Added the `Arbitrary::size_hint` method for hinting how many raw bytes an + implementation needs to construct itself. This has a default implementation, + but the custom derive creates a smart implementation for your custom types. +* Added the `Unstructured::choose` method to choose one thing among a set of + choices. +* Added the `Unstructured::arbitrary_len` method to get an arbitrary length for + a collection of some arbitrary type. +* Added the `Unstructured::arbitrary_iter` method to create an iterator of + arbitrary instance of some type. + +### Changed + +* The `Arbitrary` trait was simplified a bit. +* `Unstructured` is a concrete type now, not a trait. +* Switched to Rust 2018 edition. + +### Removed + +* `RingBuffer` and `FiniteBuffer` are removed. Use `Unstructured` instead. + +### Fixed + +* Better `Arbitrary` implementation for `char`. +* Better `Arbitrary` implementation for `String`. + +-------------------------------------------------------------------------------- + +## 0.2.0 + +-------------------------------------------------------------------------------- + +## 0.1.0 diff --git a/deps/crates/vendor/arbitrary/Cargo.lock b/deps/crates/vendor/arbitrary/Cargo.lock new file mode 100644 index 00000000000000..d4fad7007d3dc9 --- /dev/null +++ b/deps/crates/vendor/arbitrary/Cargo.lock @@ -0,0 +1,63 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.4.2" +dependencies = [ + "derive_arbitrary", + "exhaustigen", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "exhaustigen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d88f747710a968a0a32ce4c4ae90ead21dc36a06aceabbb4367452679a95eb6" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/deps/crates/vendor/arbitrary/Cargo.toml b/deps/crates/vendor/arbitrary/Cargo.toml new file mode 100644 index 00000000000000..f9f1f745876d72 --- /dev/null +++ b/deps/crates/vendor/arbitrary/Cargo.toml @@ -0,0 +1,72 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.63.0" +name = "arbitrary" +version = "1.4.2" +authors = [ + "The Rust-Fuzz Project Developers", + "Nick Fitzgerald ", + "Manish Goregaokar ", + "Simonas Kazlauskas ", + "Brian L. Troutwine ", + "Corey Farwell ", +] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "The trait for generating structured data from unstructured data" +documentation = "https://docs.rs/arbitrary/" +readme = "README.md" +keywords = [ + "arbitrary", + "testing", +] +categories = ["development-tools::testing"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-fuzz/arbitrary/" + +[features] +derive = ["derive_arbitrary"] + +[lib] +name = "arbitrary" +path = "src/lib.rs" + +[[example]] +name = "derive_enum" +path = "examples/derive_enum.rs" +required-features = ["derive"] + +[[test]] +name = "bound" +path = "tests/bound.rs" + +[[test]] +name = "derive" +path = "tests/derive.rs" +required-features = ["derive"] + +[[test]] +name = "path" +path = "tests/path.rs" + +[dependencies.derive_arbitrary] +version = "~1.4.0" +optional = true + +[dev-dependencies.exhaustigen] +version = "0.1.0" diff --git a/deps/crates/vendor/arbitrary/Cargo.toml.orig b/deps/crates/vendor/arbitrary/Cargo.toml.orig new file mode 100644 index 00000000000000..a060234ecd5dc2 --- /dev/null +++ b/deps/crates/vendor/arbitrary/Cargo.toml.orig @@ -0,0 +1,42 @@ +[package] +name = "arbitrary" +version = "1.4.2" # Make sure this matches the derive crate version (not including the patch version) +authors = [ + "The Rust-Fuzz Project Developers", + "Nick Fitzgerald ", + "Manish Goregaokar ", + "Simonas Kazlauskas ", + "Brian L. Troutwine ", + "Corey Farwell ", +] +categories = ["development-tools::testing"] +edition = "2021" +keywords = ["arbitrary", "testing"] +readme = "README.md" +description = "The trait for generating structured data from unstructured data" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-fuzz/arbitrary/" +documentation = "https://docs.rs/arbitrary/" +rust-version = "1.63.0" # Keep in sync with version documented in the README.md + +[dependencies] +derive_arbitrary = { version = "~1.4.0", path = "./derive", optional = true } + +[features] +# Turn this feature on to enable support for `#[derive(Arbitrary)]`. +derive = ["derive_arbitrary"] + +[[example]] +name = "derive_enum" +required-features = ["derive"] + +[[test]] +name = "derive" +path = "./tests/derive.rs" +required-features = ["derive"] + +[workspace] +members = ["./fuzz"] + +[dev-dependencies] +exhaustigen = "0.1.0" diff --git a/deps/crates/vendor/arbitrary/LICENSE-APACHE b/deps/crates/vendor/arbitrary/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/arbitrary/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/arbitrary/LICENSE-MIT b/deps/crates/vendor/arbitrary/LICENSE-MIT new file mode 100644 index 00000000000000..d74f9e93d4c0f2 --- /dev/null +++ b/deps/crates/vendor/arbitrary/LICENSE-MIT @@ -0,0 +1,27 @@ +MIT License + +Copyright (c) 2019 Manish Goregaokar + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/arbitrary/README.md b/deps/crates/vendor/arbitrary/README.md new file mode 100644 index 00000000000000..5d75f315793de1 --- /dev/null +++ b/deps/crates/vendor/arbitrary/README.md @@ -0,0 +1,139 @@ +
+ +

Arbitrary

+ +

The trait for generating structured data from arbitrary, unstructured input.

+ + GitHub Actions Status + +
+ +## About + +The `Arbitrary` crate lets you construct arbitrary instances of a type. + +This crate is primarily intended to be combined with a fuzzer like [libFuzzer +and `cargo-fuzz`](https://github.com/rust-fuzz/cargo-fuzz) or +[AFL](https://github.com/rust-fuzz/afl.rs), and to help you turn the raw, +untyped byte buffers that they produce into well-typed, valid, structured +values. This allows you to combine structure-aware test case generation with +coverage-guided, mutation-based fuzzers. + +## Documentation + +[**Read the API documentation on `docs.rs`!**](https://docs.rs/arbitrary) + +## Example + +Say you're writing a color conversion library, and you have an `Rgb` struct to +represent RGB colors. You might want to implement `Arbitrary` for `Rgb` so that +you could take arbitrary `Rgb` instances in a test function that asserts some +property (for example, asserting that RGB converted to HSL and converted back to +RGB always ends up exactly where we started). + +### Automatically Deriving `Arbitrary` + +Automatically deriving the `Arbitrary` trait is the recommended way to implement +`Arbitrary` for your types. + +Automatically deriving `Arbitrary` requires you to enable the `"derive"` cargo +feature: + +```toml +# Cargo.toml + +[dependencies] +arbitrary = { version = "1", features = ["derive"] } +``` + +And then you can simply add `#[derive(Arbitrary)]` annotations to your types: + +```rust +// rgb.rs + +use arbitrary::Arbitrary; + +#[derive(Arbitrary)] +pub struct Rgb { + pub r: u8, + pub g: u8, + pub b: u8, +} +``` + +#### Customizing single fields + +This can be particular handy if your structure uses a type that does not implement `Arbitrary` or you want to have more customization for particular fields. + +```rust +#[derive(Arbitrary)] +pub struct Rgba { + // set `r` to Default::default() + #[arbitrary(default)] + pub r: u8, + + // set `g` to 255 + #[arbitrary(value = 255)] + pub g: u8, + + // Generate `b` with a custom function of type + // + // fn(&mut Unstructured) -> arbitrary::Result + // + // where `T` is the field's type. + #[arbitrary(with = arbitrary_b)] + pub b: u8, + + // Generate `a` with a custom closure (shortcut to avoid a custom function) + #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=64))] + pub a: u8, +} + +fn arbitrary_b(u: &mut Unstructured) -> arbitrary::Result { + u.int_in_range(64..=128) +} +``` + +### Implementing `Arbitrary` By Hand + +Alternatively, you can write an `Arbitrary` implementation by hand: + +```rust +// rgb.rs + +use arbitrary::{Arbitrary, Result, Unstructured}; + +#[derive(Copy, Clone, Debug)] +pub struct Rgb { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl<'a> Arbitrary<'a> for Rgb { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let r = u8::arbitrary(u)?; + let g = u8::arbitrary(u)?; + let b = u8::arbitrary(u)?; + Ok(Rgb { r, g, b }) + } +} +``` + +## Minimum Supported Rust Version (MSRV) + + + +This crate is guaranteed to compile on stable Rust **1.63.0** and up. It might +compile with older versions but that may change in any new patch release. + +We reserve the right to increment the MSRV on minor releases, however we will +strive to only do it deliberately and for good reasons. + +## License + +Licensed under dual MIT or Apache-2.0 at your choice. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/deps/crates/vendor/arbitrary/examples/derive_enum.rs b/deps/crates/vendor/arbitrary/examples/derive_enum.rs new file mode 100644 index 00000000000000..3009f06ba53805 --- /dev/null +++ b/deps/crates/vendor/arbitrary/examples/derive_enum.rs @@ -0,0 +1,33 @@ +//! A simple example of deriving the `Arbitrary` trait for an `enum`. +//! +//! Note that this requires enabling the "derive" cargo feature. + +// Various enums/fields that we are deriving `Arbitrary` for aren't actually +// used except to show off the derive. +#![allow(dead_code)] + +use arbitrary::{Arbitrary, Unstructured}; + +#[derive(Arbitrary, Debug)] +enum MyEnum { + Unit, + Tuple(bool, u32), + Struct { + x: i8, + y: (u8, i32), + }, + + #[arbitrary(skip)] + Skipped(usize), +} + +fn main() { + let raw = b"This is some raw, unstructured data!"; + + let mut unstructured = Unstructured::new(raw); + + let instance = MyEnum::arbitrary(&mut unstructured) + .expect("`unstructured` has enough underlying data to create all variants of `MyEnum`"); + + println!("Here is an arbitrary enum: {:?}", instance); +} diff --git a/deps/crates/vendor/arbitrary/publish.sh b/deps/crates/vendor/arbitrary/publish.sh new file mode 100755 index 00000000000000..24db2bd779297e --- /dev/null +++ b/deps/crates/vendor/arbitrary/publish.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -eux + +cd $(dirname $0)/derive + +cargo publish + +cd .. + +# Let the crates.io index figure out we've published `derive_arbitrary` already. +sleep 5 + +cargo publish diff --git a/deps/crates/vendor/arbitrary/src/error.rs b/deps/crates/vendor/arbitrary/src/error.rs new file mode 100644 index 00000000000000..8cdf39bbd6d9a1 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/error.rs @@ -0,0 +1,57 @@ +use std::{error, fmt}; + +/// An enumeration of buffer creation errors +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum Error { + /// No choices were provided to the Unstructured::choose call + EmptyChoose, + /// There was not enough underlying data to fulfill some request for raw + /// bytes. + /// + /// Note that outside of [`Unstructured::bytes`][crate::Unstructured::bytes], + /// most APIs do *not* return this error when running out of underlying arbitrary bytes + /// but silently return some default value instead. + NotEnoughData, + /// The input bytes were not of the right format + IncorrectFormat, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::EmptyChoose => write!( + f, + "`arbitrary::Unstructured::choose` must be given a non-empty set of choices" + ), + Error::NotEnoughData => write!( + f, + "There is not enough underlying raw data to construct an `Arbitrary` instance" + ), + Error::IncorrectFormat => write!( + f, + "The raw data is not of the correct format to construct this type" + ), + } + } +} + +impl error::Error for Error {} + +/// A `Result` with the error type fixed as `arbitrary::Error`. +/// +/// Either an `Ok(T)` or `Err(arbitrary::Error)`. +pub type Result = std::result::Result; + +#[cfg(test)] +mod tests { + // Often people will import our custom `Result` type because 99.9% of + // results in a file will be `arbitrary::Result` but then have that one last + // 0.1% that want to have a custom error type. Don't make them prefix that + // 0.1% as `std::result::Result`; instead, let `arbitrary::Result` have an + // overridable error type. + #[test] + fn can_use_custom_error_types_with_result() -> super::Result<(), String> { + Ok(()) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/borrow.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/borrow.rs new file mode 100644 index 00000000000000..b5b1e22b82369e --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/borrow.rs @@ -0,0 +1,26 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::borrow::{Cow, ToOwned}, +}; + +impl<'a, A> Arbitrary<'a> for Cow<'a, A> +where + A: ToOwned + ?Sized + 'a, +
::Owned: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Cow::Owned) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + size_hint::try_recursion_guard(depth, |depth| { + <::Owned as Arbitrary>::try_size_hint(depth) + }) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/boxed.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/boxed.rs new file mode 100644 index 00000000000000..c3014a378dc541 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/boxed.rs @@ -0,0 +1,52 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::boxed::Box, +}; + +impl<'a, A> Arbitrary<'a> for Box +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + size_hint::try_recursion_guard(depth, ::try_size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Box<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Box { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(|x| x.into_boxed_str()) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/binary_heap.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/binary_heap.rs new file mode 100644 index 00000000000000..25a0384ded6e66 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/binary_heap.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::binary_heap::BinaryHeap, +}; + +impl<'a, A> Arbitrary<'a> for BinaryHeap +where + A: Arbitrary<'a> + Ord, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_map.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_map.rs new file mode 100644 index 00000000000000..21b93a4828f155 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_map.rs @@ -0,0 +1,23 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::btree_map::BTreeMap, +}; + +impl<'a, K, V> Arbitrary<'a> for BTreeMap +where + K: Arbitrary<'a> + Ord, + V: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_set.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_set.rs new file mode 100644 index 00000000000000..8c6e92fd697864 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/btree_set.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::btree_set::BTreeSet, +}; + +impl<'a, A> Arbitrary<'a> for BTreeSet +where + A: Arbitrary<'a> + Ord, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/linked_list.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/linked_list.rs new file mode 100644 index 00000000000000..6bf2e988140bf9 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/linked_list.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::linked_list::LinkedList, +}; + +impl<'a, A> Arbitrary<'a> for LinkedList +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/mod.rs new file mode 100644 index 00000000000000..67ca9085d1d287 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/mod.rs @@ -0,0 +1,5 @@ +mod binary_heap; +mod btree_map; +mod btree_set; +mod linked_list; +mod vec_deque; diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/vec_deque.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/vec_deque.rs new file mode 100644 index 00000000000000..40e04132f095ea --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/collections/vec_deque.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::vec_deque::VecDeque, +}; + +impl<'a, A> Arbitrary<'a> for VecDeque +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/c_str.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/c_str.rs new file mode 100644 index 00000000000000..a1b2383334663b --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/c_str.rs @@ -0,0 +1,19 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::ffi::CString, +}; + +impl<'a> Arbitrary<'a> for CString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + as Arbitrary>::arbitrary(u).map(|mut x| { + x.retain(|&c| c != 0); + // SAFETY: all zero bytes have been removed + unsafe { Self::from_vec_unchecked(x) } + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + as Arbitrary>::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/mod.rs new file mode 100644 index 00000000000000..9238cfccb4e682 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/ffi/mod.rs @@ -0,0 +1 @@ +mod c_str; diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/mod.rs new file mode 100644 index 00000000000000..a04b62c0b41cf4 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/mod.rs @@ -0,0 +1,13 @@ +//! Implementations of [`Arbitrary`] for [`alloc`] types, +//! excluding those in [`core`]. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod borrow; +mod boxed; +mod collections; +mod ffi; +mod rc; +mod string; +mod sync; +mod vec; diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/rc.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/rc.rs new file mode 100644 index 00000000000000..6d581679404871 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/rc.rs @@ -0,0 +1,52 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::rc::Rc, +}; + +impl<'a, A> Arbitrary<'a> for Rc +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + size_hint::try_recursion_guard(depth, ::try_size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Rc<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Rc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/string.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/string.rs new file mode 100644 index 00000000000000..a5797847b3ca14 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/string.rs @@ -0,0 +1,19 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::string::String, +}; + +impl<'a> Arbitrary<'a> for String { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/sync.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/sync.rs new file mode 100644 index 00000000000000..c8ca1db46a6451 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/sync.rs @@ -0,0 +1,52 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::sync::Arc, +}; + +impl<'a, A> Arbitrary<'a> for Arc +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + size_hint::try_recursion_guard(depth, ::try_size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Arc<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Arc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/alloc/vec.rs b/deps/crates/vendor/arbitrary/src/foreign/alloc/vec.rs new file mode 100644 index 00000000000000..63313ba8afc04f --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/alloc/vec.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::vec::Vec, +}; + +impl<'a, A> Arbitrary<'a> for Vec +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/array.rs b/deps/crates/vendor/arbitrary/src/foreign/core/array.rs new file mode 100644 index 00000000000000..39075be3e3bf1d --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/array.rs @@ -0,0 +1,76 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::{ + array, + mem::{self, MaybeUninit}, + ptr, + }, +}; + +/// Helper to safely create arrays since the standard library doesn't +/// provide one yet. Shouldn't be necessary in the future. +struct ArrayGuard { + dst: *mut T, + initialized: usize, +} + +impl Drop for ArrayGuard { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + let initialized_part = ptr::slice_from_raw_parts_mut(self.dst, self.initialized); + unsafe { + ptr::drop_in_place(initialized_part); + } + } +} + +fn try_create_array(mut cb: F) -> Result<[T; N]> +where + F: FnMut(usize) -> Result, +{ + let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit(); + let array_ptr = array.as_mut_ptr(); + let dst = array_ptr as _; + let mut guard: ArrayGuard = ArrayGuard { + dst, + initialized: 0, + }; + unsafe { + for (idx, value_ptr) in (*array.as_mut_ptr()).iter_mut().enumerate() { + ptr::write(value_ptr, cb(idx)?); + guard.initialized += 1; + } + mem::forget(guard); + Ok(array.assume_init()) + } +} + +impl<'a, T, const N: usize> Arbitrary<'a> for [T; N] +where + T: Arbitrary<'a>, +{ + #[inline] + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + try_create_array(|_| >::arbitrary(u)) + } + + #[inline] + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + let mut array = Self::arbitrary(&mut u)?; + if let Some(last) = array.last_mut() { + *last = Arbitrary::arbitrary_take_rest(u)?; + } + Ok(array) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + let hint = ::try_size_hint(depth)?; + Ok(size_hint::and_all(&array::from_fn::<_, N, _>(|_| hint))) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/bool.rs b/deps/crates/vendor/arbitrary/src/foreign/core/bool.rs new file mode 100644 index 00000000000000..bad6d1b5ff0bbd --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/bool.rs @@ -0,0 +1,13 @@ +use crate::{Arbitrary, Result, Unstructured}; + +/// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for bool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(>::arbitrary(u)? & 1 == 1) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/cell.rs b/deps/crates/vendor/arbitrary/src/foreign/core/cell.rs new file mode 100644 index 00000000000000..ad0db385b88dd2 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/cell.rs @@ -0,0 +1,61 @@ +use { + crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, + core::cell::{Cell, RefCell, UnsafeCell}, +}; + +impl<'a, A> Arbitrary<'a> for Cell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + >::try_size_hint(depth) + } +} + +impl<'a, A> Arbitrary<'a> for RefCell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + >::try_size_hint(depth) + } +} + +impl<'a, A> Arbitrary<'a> for UnsafeCell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + >::try_size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/char.rs b/deps/crates/vendor/arbitrary/src/foreign/core/char.rs new file mode 100644 index 00000000000000..30d26ea02643e4 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/char.rs @@ -0,0 +1,25 @@ +use crate::{Arbitrary, Result, Unstructured}; + +/// Returns '\0', not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for char { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + // The highest unicode code point is 0x11_FFFF + const CHAR_END: u32 = 0x11_0000; + // The size of the surrogate blocks + const SURROGATES_START: u32 = 0xD800; + let mut c = >::arbitrary(u)? % CHAR_END; + if let Some(c) = char::from_u32(c) { + Ok(c) + } else { + // We found a surrogate, wrap and try again + c -= SURROGATES_START; + Ok(char::from_u32(c) + .expect("Generated character should be valid! This is a bug in arbitrary-rs")) + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/cmp.rs b/deps/crates/vendor/arbitrary/src/foreign/core/cmp.rs new file mode 100644 index 00000000000000..17bb029b958ae6 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/cmp.rs @@ -0,0 +1,23 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::cmp::Reverse, +}; + +impl<'a, A> Arbitrary<'a> for Reverse +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { + size_hint::try_recursion_guard(depth, ::try_size_hint) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/iter.rs b/deps/crates/vendor/arbitrary/src/foreign/core/iter.rs new file mode 100644 index 00000000000000..8a56f2a0c47ad1 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/iter.rs @@ -0,0 +1,18 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::iter::{empty, Empty}, +}; + +impl<'a, A> Arbitrary<'a> for Empty +where + A: Arbitrary<'a>, +{ + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(empty()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/marker.rs b/deps/crates/vendor/arbitrary/src/foreign/core/marker.rs new file mode 100644 index 00000000000000..aa0afbed0ba35c --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/marker.rs @@ -0,0 +1,29 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::marker::{PhantomData, PhantomPinned}, +}; + +impl<'a, A> Arbitrary<'a> for PhantomData +where + A: ?Sized, +{ + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(PhantomData) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} + +impl<'a> Arbitrary<'a> for PhantomPinned { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(PhantomPinned) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/core/mod.rs new file mode 100644 index 00000000000000..60089e948ba06e --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/mod.rs @@ -0,0 +1,21 @@ +//! Implementations of [`Arbitrary`] for [`core`] types. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod array; +mod bool; +mod cell; +mod char; +mod cmp; +mod iter; +mod marker; +mod num; +mod ops; +mod option; +mod result; +mod slice; +mod str; +mod sync; +mod time; +mod tuple; +mod unit; diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/num.rs b/deps/crates/vendor/arbitrary/src/foreign/core/num.rs new file mode 100644 index 00000000000000..f0d5b33caa1326 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/num.rs @@ -0,0 +1,141 @@ +use { + crate::{Arbitrary, Error, MaxRecursionReached, Result, Unstructured}, + core::{ + mem, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, + }, + }, +}; + +macro_rules! impl_arbitrary_for_integers { + ( $( $ty:ty; )* ) => { + $( + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let mut buf = [0; mem::size_of::<$ty>()]; + u.fill_buffer(&mut buf)?; + Ok(Self::from_le_bytes(buf)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + let n = mem::size_of::<$ty>(); + (n, Some(n)) + } + + } + )* + } +} + +impl_arbitrary_for_integers! { + u8; + u16; + u32; + u64; + u128; + i8; + i16; + i32; + i64; + i128; +} + +// Note: We forward Arbitrary for i/usize to i/u64 in order to simplify corpus +// compatibility between 32-bit and 64-bit builds. This introduces dead space in +// 32-bit builds but keeps the input layout independent of the build platform. +impl<'a> Arbitrary<'a> for usize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary::().map(|x| x as usize) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +impl<'a> Arbitrary<'a> for isize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary::().map(|x| x as isize) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +macro_rules! impl_arbitrary_for_floats { + ( $( $ty:ident : $unsigned:ty; )* ) => { + $( + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <$unsigned as Arbitrary<'a>>::size_hint(depth) + } + } + )* + } +} + +impl_arbitrary_for_floats! { + f32: u32; + f64: u64; +} + +macro_rules! implement_nonzero_int { + ($nonzero:ty, $int:ty) => { + impl<'a> Arbitrary<'a> for $nonzero { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) { + Some(n) => Ok(n), + None => Err(Error::IncorrectFormat), + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <$int as Arbitrary<'a>>::size_hint(depth) + } + } + }; +} + +implement_nonzero_int! { NonZeroI8, i8 } +implement_nonzero_int! { NonZeroI16, i16 } +implement_nonzero_int! { NonZeroI32, i32 } +implement_nonzero_int! { NonZeroI64, i64 } +implement_nonzero_int! { NonZeroI128, i128 } +implement_nonzero_int! { NonZeroIsize, isize } +implement_nonzero_int! { NonZeroU8, u8 } +implement_nonzero_int! { NonZeroU16, u16 } +implement_nonzero_int! { NonZeroU32, u32 } +implement_nonzero_int! { NonZeroU64, u64 } +implement_nonzero_int! { NonZeroU128, u128 } +implement_nonzero_int! { NonZeroUsize, usize } + +impl<'a, A> Arbitrary<'a> for Wrapping +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Wrapping) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + >::try_size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/ops.rs b/deps/crates/vendor/arbitrary/src/foreign/core/ops.rs new file mode 100644 index 00000000000000..8c247354fe034e --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/ops.rs @@ -0,0 +1,127 @@ +use { + crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}, + core::{ + mem, + ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}, + }, +}; + +macro_rules! impl_range { + ( + $range:ty, + $value_closure:expr, + $value_ty:ty, + $fun:ident($fun_closure:expr), + $size_hint_closure:expr + ) => { + impl<'a, A> Arbitrary<'a> for $range + where + A: Arbitrary<'a> + Clone + PartialOrd, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let value: $value_ty = Arbitrary::arbitrary(u)?; + Ok($fun(value, $fun_closure)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + #[allow(clippy::redundant_closure_call)] + $size_hint_closure(depth) + } + } + }; +} +impl_range!( + Range, + |r: &Range| (r.start.clone(), r.end.clone()), + (A, A), + bounded_range(|(a, b)| a..b), + |depth| Ok(crate::size_hint::and( + ::try_size_hint(depth)?, + ::try_size_hint(depth)?, + )) +); +impl_range!( + RangeFrom, + |r: &RangeFrom| r.start.clone(), + A, + unbounded_range(|a| a..), + |depth| ::try_size_hint(depth) +); +impl_range!( + RangeInclusive, + |r: &RangeInclusive| (r.start().clone(), r.end().clone()), + (A, A), + bounded_range(|(a, b)| a..=b), + |depth| Ok(crate::size_hint::and( + ::try_size_hint(depth)?, + ::try_size_hint(depth)?, + )) +); +impl_range!( + RangeTo, + |r: &RangeTo| r.end.clone(), + A, + unbounded_range(|b| ..b), + |depth| ::try_size_hint(depth) +); +impl_range!( + RangeToInclusive, + |r: &RangeToInclusive| r.end.clone(), + A, + unbounded_range(|b| ..=b), + |depth| ::try_size_hint(depth) +); + +pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R +where + CB: Fn((I, I)) -> R, + I: PartialOrd, + R: RangeBounds, +{ + let (mut start, mut end) = bounds; + if start > end { + mem::swap(&mut start, &mut end); + } + cb((start, end)) +} + +pub(crate) fn unbounded_range(bound: I, cb: CB) -> R +where + CB: Fn(I) -> R, + R: RangeBounds, +{ + cb(bound) +} + +impl<'a, A> Arbitrary<'a> for Bound +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + match u.int_in_range::(0..=2)? { + 0 => Ok(Bound::Included(A::arbitrary(u)?)), + 1 => Ok(Bound::Excluded(A::arbitrary(u)?)), + 2 => Ok(Bound::Unbounded), + _ => unreachable!(), + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + Ok(size_hint::or( + size_hint::and((1, Some(1)), A::try_size_hint(depth)?), + (1, Some(1)), + )) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/option.rs b/deps/crates/vendor/arbitrary/src/foreign/core/option.rs new file mode 100644 index 00000000000000..586a939ded641e --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/option.rs @@ -0,0 +1,28 @@ +use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; + +/// Returns `None`, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a, A> Arbitrary<'a> for Option +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { + Some(Arbitrary::arbitrary(u)?) + } else { + None + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + Ok(size_hint::and( + ::try_size_hint(depth)?, + size_hint::or((0, Some(0)), ::try_size_hint(depth)?), + )) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/result.rs b/deps/crates/vendor/arbitrary/src/foreign/core/result.rs new file mode 100644 index 00000000000000..65ad50a17776eb --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/result.rs @@ -0,0 +1,31 @@ +use crate::{size_hint, Arbitrary, Error, MaxRecursionReached, Unstructured}; + +impl<'a, T, E> Arbitrary<'a> for Result +where + T: Arbitrary<'a>, + E: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { + Ok(::arbitrary(u)?) + } else { + Err(::arbitrary(u)?) + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + Ok(size_hint::and( + ::size_hint(depth), + size_hint::or( + ::try_size_hint(depth)?, + ::try_size_hint(depth)?, + ), + )) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/slice.rs b/deps/crates/vendor/arbitrary/src/foreign/core/slice.rs new file mode 100644 index 00000000000000..296d474aac4716 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/slice.rs @@ -0,0 +1,17 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for &'a [u8] { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let len = u.arbitrary_len::()?; + u.bytes(len) + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + Ok(u.take_rest()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/str.rs b/deps/crates/vendor/arbitrary/src/foreign/core/str.rs new file mode 100644 index 00000000000000..cfca8adb68af70 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/str.rs @@ -0,0 +1,39 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::str, +}; + +fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> { + match str::from_utf8(u.peek_bytes(size).unwrap()) { + Ok(s) => { + u.bytes(size).unwrap(); + Ok(s) + } + Err(e) => { + let i = e.valid_up_to(); + let valid = u.bytes(i).unwrap(); + let s = unsafe { + debug_assert!(str::from_utf8(valid).is_ok()); + str::from_utf8_unchecked(valid) + }; + Ok(s) + } + } +} + +impl<'a> Arbitrary<'a> for &'a str { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let size = u.arbitrary_len::()?; + arbitrary_str(u, size) + } + + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + let size = u.len(); + arbitrary_str(&mut u, size) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/sync/atomic.rs b/deps/crates/vendor/arbitrary/src/foreign/core/sync/atomic.rs new file mode 100644 index 00000000000000..3f5f3588175318 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/sync/atomic.rs @@ -0,0 +1,40 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}, +}; + +/// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for AtomicBool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +/// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for AtomicIsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +/// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for AtomicUsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/sync/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/core/sync/mod.rs new file mode 100644 index 00000000000000..f7b1416e395379 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/sync/mod.rs @@ -0,0 +1 @@ +mod atomic; diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/time.rs b/deps/crates/vendor/arbitrary/src/foreign/core/time.rs new file mode 100644 index 00000000000000..994a875af7fbe0 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/time.rs @@ -0,0 +1,22 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::time::Duration, +}; + +/// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. +impl<'a> Arbitrary<'a> for Duration { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Self::new( + ::arbitrary(u)?, + u.int_in_range(0..=999_999_999)?, + )) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + ::size_hint(depth), + ::size_hint(depth), + ) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/tuple.rs b/deps/crates/vendor/arbitrary/src/foreign/core/tuple.rs new file mode 100644 index 00000000000000..dfdd469a73e060 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/tuple.rs @@ -0,0 +1,38 @@ +use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; + +macro_rules! arbitrary_tuple { + () => {}; + ($last: ident $($xs: ident)*) => { + arbitrary_tuple!($($xs)*); + + impl<'a, $($xs,)* $last> Arbitrary<'a> for ($($xs,)* $last,) + where + $($xs: Arbitrary<'a>,)* + $last: Arbitrary<'a>, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) + } + + #[allow(unused_mut, non_snake_case)] + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + $(let $xs = $xs::arbitrary(&mut u)?;)* + let $last = $last::arbitrary_take_rest(u)?; + Ok(($($xs,)* $last,)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + Ok(size_hint::and_all(&[ + <$last as Arbitrary>::try_size_hint(depth)?, + $( <$xs as Arbitrary>::try_size_hint(depth)?),* + ])) + } + } + }; +} +arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); diff --git a/deps/crates/vendor/arbitrary/src/foreign/core/unit.rs b/deps/crates/vendor/arbitrary/src/foreign/core/unit.rs new file mode 100644 index 00000000000000..20523a6b6596ca --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/core/unit.rs @@ -0,0 +1,12 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for () { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/mod.rs new file mode 100644 index 00000000000000..b1c42be610f254 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/mod.rs @@ -0,0 +1,7 @@ +//! Implementations of [`Arbitrary`] for foreign types. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod alloc; +mod core; +mod std; diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_map.rs b/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_map.rs new file mode 100644 index 00000000000000..d2e77afce66fcf --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_map.rs @@ -0,0 +1,27 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ + collections::hash_map::HashMap, + hash::{BuildHasher, Hash}, + }, +}; + +impl<'a, K, V, S> Arbitrary<'a> for HashMap +where + K: Arbitrary<'a> + Eq + Hash, + V: Arbitrary<'a>, + S: BuildHasher + Default, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_set.rs b/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_set.rs new file mode 100644 index 00000000000000..5cb63d217594d8 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/collections/hash_set.rs @@ -0,0 +1,26 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ + collections::hash_set::HashSet, + hash::{BuildHasher, Hash}, + }, +}; + +impl<'a, A, S> Arbitrary<'a> for HashSet +where + A: Arbitrary<'a> + Eq + Hash, + S: BuildHasher + Default, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/collections/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/std/collections/mod.rs new file mode 100644 index 00000000000000..2bde6a06538c12 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/collections/mod.rs @@ -0,0 +1,2 @@ +mod hash_map; +mod hash_set; diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/ffi/c_str.rs b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/c_str.rs new file mode 100644 index 00000000000000..7a1dc299984cdc --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/c_str.rs @@ -0,0 +1,5 @@ +// impl Arbitrary for Box { +// fn arbitrary(u: &mut Unstructured<'_>) -> Result { +// ::arbitrary(u).map(|x| x.into_boxed_c_str()) +// } +// } diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/ffi/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/mod.rs new file mode 100644 index 00000000000000..f5d739fb95b360 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/mod.rs @@ -0,0 +1,2 @@ +mod c_str; +mod os_str; diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/ffi/os_str.rs b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/os_str.rs new file mode 100644 index 00000000000000..9fa0cb387421a9 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/ffi/os_str.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::ffi::OsString, +}; + +impl<'a> Arbitrary<'a> for OsString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(From::from) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +// impl Arbitrary for Box { +// fn arbitrary(u: &mut Unstructured<'_>) -> Result { +// ::arbitrary(u).map(|x| x.into_boxed_osstr()) +// +// } +// } diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/mod.rs b/deps/crates/vendor/arbitrary/src/foreign/std/mod.rs new file mode 100644 index 00000000000000..bc85aa2342872a --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/mod.rs @@ -0,0 +1,10 @@ +//! Implementations of [`Arbitrary`] for [`std`] types, +//! excluding those in [`core`] and [`alloc`]. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod collections; +mod ffi; +mod net; +mod path; +mod sync; diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/net.rs b/deps/crates/vendor/arbitrary/src/foreign/std/net.rs new file mode 100644 index 00000000000000..41e1f8a8c089e7 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/net.rs @@ -0,0 +1,96 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, +}; + +impl<'a> Arbitrary<'a> for Ipv4Addr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Ipv4Addr::from(u32::arbitrary(u)?)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (4, Some(4)) + } +} + +impl<'a> Arbitrary<'a> for Ipv6Addr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Ipv6Addr::from(u128::arbitrary(u)?)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (16, Some(16)) + } +} + +impl<'a> Arbitrary<'a> for IpAddr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + if u.arbitrary()? { + Ok(IpAddr::V4(u.arbitrary()?)) + } else { + Ok(IpAddr::V6(u.arbitrary()?)) + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + bool::size_hint(depth), + size_hint::or(Ipv4Addr::size_hint(depth), Ipv6Addr::size_hint(depth)), + ) + } +} + +impl<'a> Arbitrary<'a> for SocketAddrV4 { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(SocketAddrV4::new(u.arbitrary()?, u.arbitrary()?)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and(Ipv4Addr::size_hint(depth), u16::size_hint(depth)) + } +} + +impl<'a> Arbitrary<'a> for SocketAddrV6 { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(SocketAddrV6::new( + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + )) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + Ipv6Addr::size_hint(depth), + size_hint::and( + u16::size_hint(depth), + size_hint::and(u32::size_hint(depth), u32::size_hint(depth)), + ), + ) + } +} + +impl<'a> Arbitrary<'a> for SocketAddr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + if u.arbitrary()? { + Ok(SocketAddr::V4(u.arbitrary()?)) + } else { + Ok(SocketAddr::V6(u.arbitrary()?)) + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + bool::size_hint(depth), + size_hint::or( + SocketAddrV4::size_hint(depth), + SocketAddrV6::size_hint(depth), + ), + ) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/path.rs b/deps/crates/vendor/arbitrary/src/foreign/std/path.rs new file mode 100644 index 00000000000000..c94797b737429e --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/path.rs @@ -0,0 +1,15 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ffi::OsString, path::PathBuf}, +}; + +impl<'a> Arbitrary<'a> for PathBuf { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(From::from) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/foreign/std/sync.rs b/deps/crates/vendor/arbitrary/src/foreign/std/sync.rs new file mode 100644 index 00000000000000..312b37e107d80d --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/foreign/std/sync.rs @@ -0,0 +1,23 @@ +use { + crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, + std::sync::Mutex, +}; + +impl<'a, A> Arbitrary<'a> for Mutex +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + Self::try_size_hint(depth).unwrap_or_default() + } + + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + A::try_size_hint(depth) + } +} diff --git a/deps/crates/vendor/arbitrary/src/lib.rs b/deps/crates/vendor/arbitrary/src/lib.rs new file mode 100644 index 00000000000000..8b28c69a78fc36 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/lib.rs @@ -0,0 +1,608 @@ +// Copyright © 2019 The Rust Fuzz Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `Arbitrary` trait crate. +//! +//! This trait provides an [`Arbitrary`] trait to +//! produce well-typed, structured values, from raw, byte buffers. It is +//! generally intended to be used with fuzzers like AFL or libFuzzer. See the +//! [`Arbitrary`] trait's documentation for details on +//! automatically deriving, implementing, and/or using the trait. + +#![deny(bad_style)] +#![deny(missing_docs)] +#![deny(future_incompatible)] +#![deny(nonstandard_style)] +#![deny(rust_2018_compatibility)] +#![deny(rust_2018_idioms)] +#![deny(unused)] + +mod error; +mod foreign; +pub mod size_hint; +pub mod unstructured; + +#[cfg(test)] +mod tests; + +pub use error::*; + +#[cfg(feature = "derive_arbitrary")] +pub use derive_arbitrary::*; + +#[doc(inline)] +pub use unstructured::Unstructured; + +/// Error indicating that the maximum recursion depth has been reached while calculating [`Arbitrary::size_hint`]() +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct MaxRecursionReached {} + +impl core::fmt::Display for MaxRecursionReached { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("Maximum recursion depth has been reached") + } +} + +impl std::error::Error for MaxRecursionReached {} + +/// Generate arbitrary structured values from raw, unstructured data. +/// +/// The `Arbitrary` trait allows you to generate valid structured values, like +/// `HashMap`s, or ASTs, or `MyTomlConfig`, or any other data structure from +/// raw, unstructured bytes provided by a fuzzer. +/// +/// # Deriving `Arbitrary` +/// +/// Automatically deriving the `Arbitrary` trait is the recommended way to +/// implement `Arbitrary` for your types. +/// +/// Using the custom derive requires that you enable the `"derive"` cargo +/// feature in your `Cargo.toml`: +/// +/// ```toml +/// [dependencies] +/// arbitrary = { version = "1", features = ["derive"] } +/// ``` +/// +/// Then, you add the `#[derive(Arbitrary)]` annotation to your `struct` or +/// `enum` type definition: +/// +/// ``` +/// # #[cfg(feature = "derive")] mod foo { +/// use arbitrary::Arbitrary; +/// use std::collections::HashSet; +/// +/// #[derive(Arbitrary)] +/// pub struct AddressBook { +/// friends: HashSet, +/// } +/// +/// #[derive(Arbitrary, Hash, Eq, PartialEq)] +/// pub enum Friend { +/// Buddy { name: String }, +/// Pal { age: usize }, +/// } +/// # } +/// ``` +/// +/// Every member of the `struct` or `enum` must also implement `Arbitrary`. +/// +/// It is also possible to change the default bounds added by the derive: +/// +/// ``` +/// # #[cfg(feature = "derive")] mod foo { +/// use arbitrary::Arbitrary; +/// +/// trait Trait { +/// type Assoc: for<'a> Arbitrary<'a>; +/// } +/// +/// #[derive(Arbitrary)] +/// // The bounds are used verbatim, so any existing trait bounds will need to be repeated. +/// #[arbitrary(bound = "T: Trait")] +/// struct Point { +/// x: T::Assoc, +/// } +/// # } +/// ``` +/// +/// # Implementing `Arbitrary` By Hand +/// +/// Implementing `Arbitrary` mostly involves nested calls to other `Arbitrary` +/// arbitrary implementations for each of your `struct` or `enum`'s members. But +/// sometimes you need some amount of raw data, or you need to generate a +/// variably-sized collection type, or something of that sort. The +/// [`Unstructured`] type helps you with these tasks. +/// +/// ``` +/// # #[cfg(feature = "derive")] mod foo { +/// # pub struct MyCollection { _t: std::marker::PhantomData } +/// # impl MyCollection { +/// # pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } } +/// # pub fn insert(&mut self, element: T) {} +/// # } +/// use arbitrary::{Arbitrary, Result, Unstructured}; +/// +/// impl<'a, T> Arbitrary<'a> for MyCollection +/// where +/// T: Arbitrary<'a>, +/// { +/// fn arbitrary(u: &mut Unstructured<'a>) -> Result { +/// // Get an iterator of arbitrary `T`s. +/// let iter = u.arbitrary_iter::()?; +/// +/// // And then create a collection! +/// let mut my_collection = MyCollection::new(); +/// for elem_result in iter { +/// let elem = elem_result?; +/// my_collection.insert(elem); +/// } +/// +/// Ok(my_collection) +/// } +/// } +/// # } +/// ``` +/// +/// # A Note On Output Distributions +/// +/// There is no requirement for a particular distribution of the values. For +/// example, it is not required that every value appears with the same +/// probability. That being said, the main use for `Arbitrary` is for fuzzing, +/// so in many cases a uniform distribution will make the most sense in order to +/// provide the best coverage of the domain. In other cases this is not +/// desirable or even possible, for example when sampling from a uniform +/// distribution is computationally expensive or in the case of collections that +/// may grow indefinitely. +pub trait Arbitrary<'a>: Sized { + /// Generate an arbitrary value of `Self` from the given unstructured data. + /// + /// Calling `Arbitrary::arbitrary` requires that you have some raw data, + /// perhaps given to you by a fuzzer like AFL or libFuzzer. You wrap this + /// raw data in an `Unstructured`, and then you can call `::arbitrary` to construct an arbitrary instance of `MyType` + /// from that unstructured data. + /// + /// Implementations may return an error if there is not enough data to + /// construct a full instance of `Self`, or they may fill out the rest of + /// `Self` with dummy values. Using dummy values when the underlying data is + /// exhausted can help avoid accidentally "defeating" some of the fuzzer's + /// mutations to the underlying byte stream that might otherwise lead to + /// interesting runtime behavior or new code coverage if only we had just a + /// few more bytes. However, it also requires that implementations for + /// recursive types (e.g. `struct Foo(Option>)`) avoid infinite + /// recursion when the underlying data is exhausted. + /// + /// ``` + /// # #[cfg(feature = "derive")] fn foo() { + /// use arbitrary::{Arbitrary, Unstructured}; + /// + /// #[derive(Arbitrary)] + /// pub struct MyType { + /// // ... + /// } + /// + /// // Get the raw data from the fuzzer or wherever else. + /// # let get_raw_data_from_fuzzer = || &[]; + /// let raw_data: &[u8] = get_raw_data_from_fuzzer(); + /// + /// // Wrap that raw data in an `Unstructured`. + /// let mut unstructured = Unstructured::new(raw_data); + /// + /// // Generate an arbitrary instance of `MyType` and do stuff with it. + /// if let Ok(value) = MyType::arbitrary(&mut unstructured) { + /// # let do_stuff = |_| {}; + /// do_stuff(value); + /// } + /// # } + /// ``` + /// + /// See also the documentation for [`Unstructured`]. + fn arbitrary(u: &mut Unstructured<'a>) -> Result; + + /// Generate an arbitrary value of `Self` from the entirety of the given + /// unstructured data. + /// + /// This is similar to Arbitrary::arbitrary, however it assumes that it is + /// the last consumer of the given data, and is thus able to consume it all + /// if it needs. See also the documentation for + /// [`Unstructured`]. + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + Self::arbitrary(&mut u) + } + + /// Get a size hint for how many bytes out of an `Unstructured` this type + /// needs to construct itself. + /// + /// This is useful for determining how many elements we should insert when + /// creating an arbitrary collection. + /// + /// The return value is similar to [`Iterator::size_hint`]: it returns a + /// tuple where the first element is a lower bound on the number of bytes + /// required, and the second element is an optional upper bound. + /// + /// The default implementation return `(0, None)` which is correct for any + /// type, but not ultimately that useful. Using `#[derive(Arbitrary)]` will + /// create a better implementation. If you are writing an `Arbitrary` + /// implementation by hand, and your type can be part of a dynamically sized + /// collection (such as `Vec`), you are strongly encouraged to override this + /// default with a better implementation, and also override + /// [`try_size_hint`]. + /// + /// ## How to implement this + /// + /// If the size hint calculation is a trivial constant and does not recurse + /// into any other `size_hint` call, you should implement it in `size_hint`: + /// + /// ``` + /// use arbitrary::{size_hint, Arbitrary, Result, Unstructured}; + /// + /// struct SomeStruct(u8); + /// + /// impl<'a> Arbitrary<'a> for SomeStruct { + /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { + /// let buf = &mut [0]; + /// u.fill_buffer(buf)?; + /// Ok(SomeStruct(buf[0])) + /// } + /// + /// #[inline] + /// fn size_hint(depth: usize) -> (usize, Option) { + /// let _ = depth; + /// (1, Some(1)) + /// } + /// } + /// ``` + /// + /// Otherwise, it should instead be implemented in [`try_size_hint`], + /// and the `size_hint` implementation should forward to it: + /// + /// ``` + /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; + /// + /// struct SomeStruct { + /// a: A, + /// b: B, + /// } + /// + /// impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for SomeStruct { + /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { + /// // ... + /// # todo!() + /// } + /// + /// fn size_hint(depth: usize) -> (usize, Option) { + /// // Return the value of try_size_hint + /// // + /// // If the recursion fails, return the default, always valid `(0, None)` + /// Self::try_size_hint(depth).unwrap_or_default() + /// } + /// + /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + /// // Protect against potential infinite recursion with + /// // `try_recursion_guard`. + /// size_hint::try_recursion_guard(depth, |depth| { + /// // If we aren't too deep, then `recursion_guard` calls + /// // this closure, which implements the natural size hint. + /// // Don't forget to use the new `depth` in all nested + /// // `try_size_hint` calls! We recommend shadowing the + /// // parameter, like what is done here, so that you can't + /// // accidentally use the wrong depth. + /// Ok(size_hint::and( + /// ::try_size_hint(depth)?, + /// ::try_size_hint(depth)?, + /// )) + /// }) + /// } + /// } + /// ``` + /// + /// ## Invariant + /// + /// It must be possible to construct every possible output using only inputs + /// of lengths bounded by these parameters. This applies to both + /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. + /// + /// This is trivially true for `(0, None)`. To restrict this further, it + /// must be proven that all inputs that are now excluded produced redundant + /// outputs which are still possible to produce using the reduced input + /// space. + /// + /// [iterator-size-hint]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.size_hint + /// [`try_size_hint`]: Arbitrary::try_size_hint + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + let _ = depth; + (0, None) + } + + /// Get a size hint for how many bytes out of an `Unstructured` this type + /// needs to construct itself. + /// + /// Unlike [`size_hint`], this function keeps the information that the + /// recursion limit was reached. This is required to "short circuit" the + /// calculation and avoid exponential blowup with recursive structures. + /// + /// If you are implementing [`size_hint`] for a struct that could be + /// recursive, you should implement `try_size_hint` and call the + /// `try_size_hint` when recursing + /// + /// + /// The return value is similar to [`core::iter::Iterator::size_hint`]: it + /// returns a tuple where the first element is a lower bound on the number + /// of bytes required, and the second element is an optional upper bound. + /// + /// The default implementation returns the value of [`size_hint`] which is + /// correct for any type, but might lead to exponential blowup when dealing + /// with recursive types. + /// + /// ## Invariant + /// + /// It must be possible to construct every possible output using only inputs + /// of lengths bounded by these parameters. This applies to both + /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. + /// + /// This is trivially true for `(0, None)`. To restrict this further, it + /// must be proven that all inputs that are now excluded produced redundant + /// outputs which are still possible to produce using the reduced input + /// space. + /// + /// ## When to implement `try_size_hint` + /// + /// If you 100% know that the type you are implementing `Arbitrary` for is + /// not a recursive type, or your implementation is not transitively calling + /// any other `size_hint` methods, you may implement [`size_hint`], and the + /// default `try_size_hint` implementation will use it. + /// + /// Note that if you are implementing `Arbitrary` for a generic type, you + /// cannot guarantee the lack of type recursion! + /// + /// Otherwise, when there is possible type recursion, you should implement + /// `try_size_hint` instead. + /// + /// ## The `depth` parameter + /// + /// When implementing `try_size_hint`, you need to use + /// [`arbitrary::size_hint::try_recursion_guard(depth)`][crate::size_hint::try_recursion_guard] + /// to prevent potential infinite recursion when calculating size hints for + /// potentially recursive types: + /// + /// ``` + /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Unstructured}; + /// + /// // This can potentially be a recursive type if `L` or `R` contain + /// // something like `Box>>`! + /// enum MyEither { + /// Left(L), + /// Right(R), + /// } + /// + /// impl<'a, L, R> Arbitrary<'a> for MyEither + /// where + /// L: Arbitrary<'a>, + /// R: Arbitrary<'a>, + /// { + /// fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { + /// // ... + /// # unimplemented!() + /// } + /// + /// fn size_hint(depth: usize) -> (usize, Option) { + /// // Return the value of `try_size_hint` + /// // + /// // If the recursion fails, return the default `(0, None)` range, + /// // which is always valid. + /// Self::try_size_hint(depth).unwrap_or_default() + /// } + /// + /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + /// // Protect against potential infinite recursion with + /// // `try_recursion_guard`. + /// size_hint::try_recursion_guard(depth, |depth| { + /// // If we aren't too deep, then `recursion_guard` calls + /// // this closure, which implements the natural size hint. + /// // Don't forget to use the new `depth` in all nested + /// // `try_size_hint` calls! We recommend shadowing the + /// // parameter, like what is done here, so that you can't + /// // accidentally use the wrong depth. + /// Ok(size_hint::or( + /// ::try_size_hint(depth)?, + /// ::try_size_hint(depth)?, + /// )) + /// }) + /// } + /// } + /// ``` + #[inline] + fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { + Ok(Self::size_hint(depth)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn exhausted_entropy() { + let mut u = Unstructured::new(&[]); + assert_eq!(u.arbitrary::().unwrap(), false); + assert_eq!(u.arbitrary::().unwrap(), 0); + assert_eq!(u.arbitrary::().unwrap(), 0); + assert_eq!(u.arbitrary::().unwrap(), 0.0); + assert_eq!(u.arbitrary::().unwrap(), 0.0); + assert_eq!(u.arbitrary::>().unwrap(), None); + assert_eq!(u.int_in_range(4..=100).unwrap(), 4); + assert_eq!(u.choose_index(10).unwrap(), 0); + assert_eq!(u.ratio(5, 7).unwrap(), true); + } +} + +/// Multiple conflicting arbitrary attributes are used on the same field: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// struct Point { +/// #[arbitrary(value = 2)] +/// #[arbitrary(value = 2)] +/// x: i32, +/// } +/// ``` +/// +/// An unknown attribute: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// struct Point { +/// #[arbitrary(unknown_attr)] +/// x: i32, +/// } +/// ``` +/// +/// An unknown attribute with a value: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// struct Point { +/// #[arbitrary(unknown_attr = 13)] +/// x: i32, +/// } +/// ``` +/// +/// `value` without RHS: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// struct Point { +/// #[arbitrary(value)] +/// x: i32, +/// } +/// ``` +/// +/// `with` without RHS: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// struct Point { +/// #[arbitrary(with)] +/// x: i32, +/// } +/// ``` +/// +/// Multiple conflicting bounds at the container-level: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// #[arbitrary(bound = "T: Default")] +/// #[arbitrary(bound = "T: Default")] +/// struct Point { +/// #[arbitrary(default)] +/// x: T, +/// } +/// ``` +/// +/// Multiple conflicting bounds in a single bound attribute: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// #[arbitrary(bound = "T: Default, T: Default")] +/// struct Point { +/// #[arbitrary(default)] +/// x: T, +/// } +/// ``` +/// +/// Multiple conflicting bounds in multiple bound attributes: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// #[arbitrary(bound = "T: Default", bound = "T: Default")] +/// struct Point { +/// #[arbitrary(default)] +/// x: T, +/// } +/// ``` +/// +/// Too many bounds supplied: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// #[arbitrary(bound = "T: Default")] +/// struct Point { +/// x: i32, +/// } +/// ``` +/// +/// Too many bounds supplied across multiple attributes: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// #[arbitrary(bound = "T: Default")] +/// #[arbitrary(bound = "U: Default")] +/// struct Point { +/// #[arbitrary(default)] +/// x: T, +/// } +/// ``` +/// +/// Attempt to use the derive attribute on an enum variant: +/// ```compile_fail +/// #[derive(::arbitrary::Arbitrary)] +/// enum Enum { +/// #[arbitrary(default)] +/// Variant(T), +/// } +/// ``` +#[cfg(all(doctest, feature = "derive"))] +pub struct CompileFailTests; + +// Support for `#[derive(Arbitrary)]`. +#[doc(hidden)] +#[cfg(feature = "derive")] +pub mod details { + use super::*; + + // Hidden trait that papers over the difference between `&mut Unstructured` and + // `Unstructured` arguments so that `with_recursive_count` can be used for both + // `arbitrary` and `arbitrary_take_rest`. + pub trait IsEmpty { + fn is_empty(&self) -> bool; + } + + impl IsEmpty for Unstructured<'_> { + fn is_empty(&self) -> bool { + Unstructured::is_empty(self) + } + } + + impl IsEmpty for &mut Unstructured<'_> { + fn is_empty(&self) -> bool { + Unstructured::is_empty(self) + } + } + + // Calls `f` with a recursive count guard. + #[inline] + pub fn with_recursive_count( + u: U, + recursive_count: &'static std::thread::LocalKey>, + f: impl FnOnce(U) -> Result, + ) -> Result { + let guard_against_recursion = u.is_empty(); + if guard_against_recursion { + recursive_count.with(|count| { + if count.get() > 0 { + return Err(Error::NotEnoughData); + } + count.set(count.get() + 1); + Ok(()) + })?; + } + + let result = f(u); + + if guard_against_recursion { + recursive_count.with(|count| { + count.set(count.get() - 1); + }); + } + + result + } +} diff --git a/deps/crates/vendor/arbitrary/src/size_hint.rs b/deps/crates/vendor/arbitrary/src/size_hint.rs new file mode 100644 index 00000000000000..95707ee369f345 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/size_hint.rs @@ -0,0 +1,149 @@ +//! Utilities for working with and combining the results of +//! [`Arbitrary::size_hint`][crate::Arbitrary::size_hint]. + +pub(crate) const MAX_DEPTH: usize = 20; + +/// Protects against potential infinite recursion when calculating size hints +/// due to indirect type recursion. +/// +/// When the depth is not too deep, calls `f` with `depth + 1` to calculate the +/// size hint. +/// +/// Otherwise, returns the default size hint: `(0, None)`. +/// +/// +#[inline] +#[deprecated(note = "use `try_recursion_guard` instead")] +pub fn recursion_guard( + depth: usize, + f: impl FnOnce(usize) -> (usize, Option), +) -> (usize, Option) { + if depth > MAX_DEPTH { + (0, None) + } else { + f(depth + 1) + } +} + +/// Protects against potential infinite recursion when calculating size hints +/// due to indirect type recursion. +/// +/// When the depth is not too deep, calls `f` with `depth + 1` to calculate the +/// size hint. +/// +/// Otherwise, returns an error. +/// +/// This should be used when implementing [`try_size_hint`](crate::Arbitrary::try_size_hint) +#[inline] +pub fn try_recursion_guard( + depth: usize, + f: impl FnOnce(usize) -> Result<(usize, Option), crate::MaxRecursionReached>, +) -> Result<(usize, Option), crate::MaxRecursionReached> { + if depth > MAX_DEPTH { + Err(crate::MaxRecursionReached {}) + } else { + f(depth + 1) + } +} + +/// Take the sum of the `lhs` and `rhs` size hints. +#[inline] +pub fn and(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { + let lower = lhs.0 + rhs.0; + let upper = lhs.1.and_then(|lhs| rhs.1.map(|rhs| lhs + rhs)); + (lower, upper) +} + +/// Take the sum of all of the given size hints. +/// +/// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming +/// nothing. +#[inline] +pub fn and_all(hints: &[(usize, Option)]) -> (usize, Option) { + hints.iter().copied().fold((0, Some(0)), and) +} + +/// Take the minimum of the lower bounds and maximum of the upper bounds in the +/// `lhs` and `rhs` size hints. +#[inline] +pub fn or(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { + let lower = std::cmp::min(lhs.0, rhs.0); + let upper = lhs + .1 + .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs))); + (lower, upper) +} + +/// Take the maximum of the `lhs` and `rhs` size hints. +/// +/// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming +/// nothing. +#[inline] +pub fn or_all(hints: &[(usize, Option)]) -> (usize, Option) { + if let Some(head) = hints.first().copied() { + hints[1..].iter().copied().fold(head, or) + } else { + (0, Some(0)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn and() { + assert_eq!((5, Some(5)), super::and((2, Some(2)), (3, Some(3)))); + assert_eq!((5, None), super::and((2, Some(2)), (3, None))); + assert_eq!((5, None), super::and((2, None), (3, Some(3)))); + assert_eq!((5, None), super::and((2, None), (3, None))); + } + + #[test] + fn or() { + assert_eq!((2, Some(3)), super::or((2, Some(2)), (3, Some(3)))); + assert_eq!((2, None), super::or((2, Some(2)), (3, None))); + assert_eq!((2, None), super::or((2, None), (3, Some(3)))); + assert_eq!((2, None), super::or((2, None), (3, None))); + } + + #[test] + fn and_all() { + assert_eq!((0, Some(0)), super::and_all(&[])); + assert_eq!( + (7, Some(7)), + super::and_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) + ); + assert_eq!( + (7, None), + super::and_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) + ); + assert_eq!( + (7, None), + super::and_all(&[(1, Some(1)), (2, None), (4, Some(4))]) + ); + assert_eq!( + (7, None), + super::and_all(&[(1, None), (2, Some(2)), (4, Some(4))]) + ); + } + + #[test] + fn or_all() { + assert_eq!((0, Some(0)), super::or_all(&[])); + assert_eq!( + (1, Some(4)), + super::or_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) + ); + assert_eq!( + (1, None), + super::or_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) + ); + assert_eq!( + (1, None), + super::or_all(&[(1, Some(1)), (2, None), (4, Some(4))]) + ); + assert_eq!( + (1, None), + super::or_all(&[(1, None), (2, Some(2)), (4, Some(4))]) + ); + } +} diff --git a/deps/crates/vendor/arbitrary/src/tests.rs b/deps/crates/vendor/arbitrary/src/tests.rs new file mode 100644 index 00000000000000..7746715a9f3aa6 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/tests.rs @@ -0,0 +1,316 @@ +use { + super::{Arbitrary, Result, Unstructured}, + std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, +}; + +/// Assert that the given expected values are all generated. +/// +/// Exhaustively enumerates all buffers up to length 10 containing the +/// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` +fn assert_generates(expected_values: impl IntoIterator) +where + T: Clone + Debug + Hash + Eq + for<'a> Arbitrary<'a>, +{ + let expected_values: HashSet<_> = expected_values.into_iter().collect(); + let mut arbitrary_expected = expected_values.clone(); + let mut arbitrary_take_rest_expected = expected_values; + + let bytes = [0, 1, b'a', 0xff]; + let max_len = 10; + + let mut buf = Vec::with_capacity(max_len); + + let mut g = exhaustigen::Gen::new(); + while !g.done() { + let len = g.gen(max_len); + + buf.clear(); + buf.extend( + std::iter::repeat_with(|| { + let index = g.gen(bytes.len() - 1); + bytes[index] + }) + .take(len), + ); + + let mut u = Unstructured::new(&buf); + let val = T::arbitrary(&mut u).unwrap(); + arbitrary_expected.remove(&val); + + let u = Unstructured::new(&buf); + let val = T::arbitrary_take_rest(u).unwrap(); + arbitrary_take_rest_expected.remove(&val); + + if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { + return; + } + } + + panic!( + "failed to generate all expected values!\n\n\ + T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ + T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" + ) +} + +/// Generates an arbitrary `T`, and checks that the result is consistent with the +/// `size_hint()` reported by `T`. +fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { + let (min, max) = T::size_hint(0); + + let len_before = u.len(); + let result = T::arbitrary(u); + + let consumed = len_before - u.len(); + + if let Some(max) = max { + assert!( + consumed <= max, + "incorrect maximum size: indicated {}, actually consumed {}", + max, + consumed + ); + } + + if result.is_ok() { + assert!( + consumed >= min, + "incorrect minimum size: indicated {}, actually consumed {}", + min, + consumed + ); + } + + result +} + +/// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. +fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { + let (min, _) = T::size_hint(0); + + let len_before = u.len(); + let result = T::arbitrary_take_rest(u); + + if result.is_ok() { + assert!( + len_before >= min, + "incorrect minimum size: indicated {}, worked with {}", + min, + len_before + ); + } + + result +} + +#[test] +fn finite_buffer_fill_buffer() { + let x = [1, 2, 3, 4]; + let mut rb = Unstructured::new(&x); + let mut z = [0; 2]; + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [1, 2]); + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [3, 4]); + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [0, 0]); +} + +#[test] +fn arbitrary_for_integers() { + let x = [1, 2, 3, 4]; + let mut buf = Unstructured::new(&x); + let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); + let actual = checked_arbitrary::(&mut buf).unwrap(); + assert_eq!(expected, actual); + + assert_generates([ + i32::from_ne_bytes([0, 0, 0, 0]), + i32::from_ne_bytes([0, 0, 0, 1]), + i32::from_ne_bytes([0, 0, 1, 0]), + i32::from_ne_bytes([0, 1, 0, 0]), + i32::from_ne_bytes([1, 0, 0, 0]), + i32::from_ne_bytes([1, 1, 1, 1]), + i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), + ]); +} + +#[test] +fn arbitrary_for_bytes() { + let x = [1, 2, 3, 4, 4]; + let mut buf = Unstructured::new(&x); + let expected = &[1, 2, 3, 4]; + let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); + assert_eq!(expected, actual); +} + +#[test] +fn arbitrary_take_rest_for_bytes() { + let x = [1, 2, 3, 4]; + let buf = Unstructured::new(&x); + let expected = &[1, 2, 3, 4]; + let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); + assert_eq!(expected, actual); +} + +#[test] +fn arbitrary_for_vec_u8() { + assert_generates::>([ + vec![], + vec![0], + vec![1], + vec![0, 0], + vec![0, 1], + vec![1, 0], + vec![1, 1], + vec![0, 0, 0], + vec![0, 0, 1], + vec![0, 1, 0], + vec![0, 1, 1], + vec![1, 0, 0], + vec![1, 0, 1], + vec![1, 1, 0], + vec![1, 1, 1], + ]); +} + +#[test] +fn arbitrary_for_vec_vec_u8() { + assert_generates::>>([ + vec![], + vec![vec![]], + vec![vec![0]], + vec![vec![1]], + vec![vec![0, 1]], + vec![vec![], vec![]], + vec![vec![0], vec![]], + vec![vec![], vec![1]], + vec![vec![0], vec![1]], + vec![vec![0, 1], vec![]], + vec![vec![], vec![1, 0]], + vec![vec![], vec![], vec![]], + ]); +} + +#[test] +fn arbitrary_for_vec_vec_vec_u8() { + assert_generates::>>>([ + vec![], + vec![vec![]], + vec![vec![vec![0]]], + vec![vec![vec![1]]], + vec![vec![vec![0, 1]]], + vec![vec![], vec![]], + vec![vec![], vec![vec![]]], + vec![vec![vec![]], vec![]], + vec![vec![vec![]], vec![vec![]]], + vec![vec![vec![0]], vec![]], + vec![vec![], vec![vec![1]]], + vec![vec![vec![0]], vec![vec![1]]], + vec![vec![vec![0, 1]], vec![]], + vec![vec![], vec![vec![0, 1]]], + vec![vec![], vec![], vec![]], + vec![vec![vec![]], vec![], vec![]], + vec![vec![], vec![vec![]], vec![]], + vec![vec![], vec![], vec![vec![]]], + ]); +} + +#[test] +fn arbitrary_for_string() { + assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); +} + +#[test] +fn arbitrary_collection() { + let x = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 12, + ]; + assert_eq!( + checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] + ); + assert_eq!( + checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[84148994] + ); + assert_eq!( + checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" + ); +} + +#[test] +fn arbitrary_take_rest() { + // Basic examples + let x = [1, 2, 3, 4]; + assert_eq!( + checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), + &[1, 2, 3, 4] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[0x040302] + ); + assert_eq!( + checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), + "\x01\x02\x03\x04" + ); + + // Empty remainder + assert_eq!( + checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), + &[] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), + &[] + ); + + // Cannot consume all but can consume part of the input + assert_eq!( + checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), + "\x01" + ); +} + +#[test] +fn size_hint_for_tuples() { + assert_eq!( + (7, Some(7)), + <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) + ); + assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); +} diff --git a/deps/crates/vendor/arbitrary/src/unstructured.rs b/deps/crates/vendor/arbitrary/src/unstructured.rs new file mode 100644 index 00000000000000..2b5e04388f6e28 --- /dev/null +++ b/deps/crates/vendor/arbitrary/src/unstructured.rs @@ -0,0 +1,1071 @@ +// Copyright © 2019 The Rust Fuzz Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Wrappers around raw, unstructured bytes. + +use crate::{Arbitrary, Error, Result}; +use std::marker::PhantomData; +use std::ops::ControlFlow; +use std::{mem, ops}; + +/// A source of unstructured data. +/// +/// An `Unstructured` helps `Arbitrary` implementations interpret raw data +/// (typically provided by a fuzzer) as a "DNA string" that describes how to +/// construct the `Arbitrary` type. The goal is that a small change to the "DNA +/// string" (the raw data wrapped by an `Unstructured`) results in a small +/// change to the generated `Arbitrary` instance. This helps a fuzzer +/// efficiently explore the `Arbitrary`'s input space. +/// +/// `Unstructured` is deterministic: given the same raw data, the same series of +/// API calls will return the same results (modulo system resource constraints, +/// like running out of memory). However, `Unstructured` does not guarantee +/// anything beyond that: it makes not guarantee that it will yield bytes from +/// the underlying data in any particular order. +/// +/// You shouldn't generally need to use an `Unstructured` unless you are writing +/// a custom `Arbitrary` implementation by hand, instead of deriving it. Mostly, +/// you should just be passing it through to nested `Arbitrary::arbitrary` +/// calls. +/// +/// # Example +/// +/// Imagine you were writing a color conversion crate. You might want to write +/// fuzz tests that take a random RGB color and assert various properties, run +/// functions and make sure nothing panics, etc. +/// +/// Below is what translating the fuzzer's raw input into an `Unstructured` and +/// using that to generate an arbitrary RGB color might look like: +/// +/// ``` +/// # #[cfg(feature = "derive")] fn foo() { +/// use arbitrary::{Arbitrary, Unstructured}; +/// +/// /// An RGB color. +/// #[derive(Arbitrary)] +/// pub struct Rgb { +/// r: u8, +/// g: u8, +/// b: u8, +/// } +/// +/// // Get the raw bytes from the fuzzer. +/// # let get_input_from_fuzzer = || &[]; +/// let raw_data: &[u8] = get_input_from_fuzzer(); +/// +/// // Wrap it in an `Unstructured`. +/// let mut unstructured = Unstructured::new(raw_data); +/// +/// // Generate an `Rgb` color and run our checks. +/// if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) { +/// # let run_my_color_conversion_checks = |_| {}; +/// run_my_color_conversion_checks(rgb); +/// } +/// # } +/// ``` +#[derive(Debug)] +pub struct Unstructured<'a> { + data: &'a [u8], +} + +impl<'a> Unstructured<'a> { + /// Create a new `Unstructured` from the given raw data. + /// + /// # Example + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let u = Unstructured::new(&[1, 2, 3, 4]); + /// ``` + pub fn new(data: &'a [u8]) -> Self { + Unstructured { data } + } + + /// Get the number of remaining bytes of underlying data that are still + /// available. + /// + /// # Example + /// + /// ``` + /// use arbitrary::{Arbitrary, Unstructured}; + /// + /// let mut u = Unstructured::new(&[1, 2, 3]); + /// + /// // Initially have three bytes of data. + /// assert_eq!(u.len(), 3); + /// + /// // Generating a `bool` consumes one byte from the underlying data, so + /// // we are left with two bytes afterwards. + /// let _ = bool::arbitrary(&mut u); + /// assert_eq!(u.len(), 2); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.data.len() + } + + /// Is the underlying unstructured data exhausted? + /// + /// `unstructured.is_empty()` is the same as `unstructured.len() == 0`. + /// + /// # Example + /// + /// ``` + /// use arbitrary::{Arbitrary, Unstructured}; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4]); + /// + /// // Initially, we are not empty. + /// assert!(!u.is_empty()); + /// + /// // Generating a `u32` consumes all four bytes of the underlying data, so + /// // we become empty afterwards. + /// let _ = u32::arbitrary(&mut u); + /// assert!(u.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Generate an arbitrary instance of `A`. + /// + /// This is simply a helper method that is equivalent to `::arbitrary(self)`. This helper is a little bit more concise, + /// and can be used in situations where Rust's type inference will figure + /// out what `A` should be. + /// + /// # Example + /// + /// ``` + /// # #[cfg(feature="derive")] fn foo() -> arbitrary::Result<()> { + /// use arbitrary::{Arbitrary, Unstructured}; + /// + /// #[derive(Arbitrary)] + /// struct MyType { + /// // ... + /// } + /// + /// fn do_stuff(value: MyType) { + /// # let _ = value; + /// // ... + /// } + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4]); + /// + /// // Rust's type inference can figure out that `value` should be of type + /// // `MyType` here: + /// let value = u.arbitrary()?; + /// do_stuff(value); + /// # Ok(()) } + /// ``` + pub fn arbitrary(&mut self) -> Result + where + A: Arbitrary<'a>, + { + >::arbitrary(self) + } + + /// Get the number of elements to insert when building up a collection of + /// arbitrary `ElementType`s. + /// + /// This uses the [`::size_hint`][crate::Arbitrary::size_hint] method to smartly + /// choose a length such that we most likely have enough underlying bytes to + /// construct that many arbitrary `ElementType`s. + /// + /// This should only be called within an `Arbitrary` implementation. + /// + /// # Example + /// + /// ``` + /// use arbitrary::{Arbitrary, Result, Unstructured}; + /// # pub struct MyCollection { _t: std::marker::PhantomData } + /// # impl MyCollection { + /// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } } + /// # pub fn insert(&mut self, element: T) {} + /// # } + /// + /// impl<'a, T> Arbitrary<'a> for MyCollection + /// where + /// T: Arbitrary<'a>, + /// { + /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { + /// // Get the number of `T`s we should insert into our collection. + /// let len = u.arbitrary_len::()?; + /// + /// // And then create a collection of that length! + /// let mut my_collection = MyCollection::with_capacity(len); + /// for _ in 0..len { + /// let element = T::arbitrary(u)?; + /// my_collection.insert(element); + /// } + /// + /// Ok(my_collection) + /// } + /// } + /// ``` + pub fn arbitrary_len(&mut self) -> Result + where + ElementType: Arbitrary<'a>, + { + let byte_size = self.arbitrary_byte_size()?; + let (lower, upper) = ::size_hint(0); + let elem_size = upper.unwrap_or(lower * 2); + let elem_size = std::cmp::max(1, elem_size); + Ok(byte_size / elem_size) + } + + fn arbitrary_byte_size(&mut self) -> Result { + if self.data.is_empty() { + Ok(0) + } else if self.data.len() == 1 { + self.data = &[]; + Ok(0) + } else { + // Take lengths from the end of the data, since the `libFuzzer` folks + // found that this lets fuzzers more efficiently explore the input + // space. + // + // https://github.com/rust-fuzz/libfuzzer-sys/blob/0c450753/libfuzzer/utils/FuzzedDataProvider.h#L92-L97 + + // We only consume as many bytes as necessary to cover the entire + // range of the byte string. + // Note: We cast to u64 so we don't overflow when checking u32::MAX + 4 on 32-bit archs + let len = if self.data.len() as u64 <= u8::MAX as u64 + 1 { + let bytes = 1; + let max_size = self.data.len() - bytes; + let (rest, for_size) = self.data.split_at(max_size); + self.data = rest; + Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0 as usize + } else if self.data.len() as u64 <= u16::MAX as u64 + 2 { + let bytes = 2; + let max_size = self.data.len() - bytes; + let (rest, for_size) = self.data.split_at(max_size); + self.data = rest; + Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0 as usize + } else if self.data.len() as u64 <= u32::MAX as u64 + 4 { + let bytes = 4; + let max_size = self.data.len() - bytes; + let (rest, for_size) = self.data.split_at(max_size); + self.data = rest; + Self::int_in_range_impl(0..=max_size as u32, for_size.iter().copied())?.0 as usize + } else { + let bytes = 8; + let max_size = self.data.len() - bytes; + let (rest, for_size) = self.data.split_at(max_size); + self.data = rest; + Self::int_in_range_impl(0..=max_size as u64, for_size.iter().copied())?.0 as usize + }; + + Ok(len) + } + } + + /// Generate an integer within the given range. + /// + /// Do not use this to generate the size of a collection. Use + /// `arbitrary_len` instead. + /// + /// The probability distribution of the return value is not necessarily uniform. + /// + /// Returns `range.start()`, not an error, + /// if this `Unstructured` [is empty][Unstructured::is_empty]. + /// + /// # Panics + /// + /// Panics if `range.start > range.end`. That is, the given range must be + /// non-empty. + /// + /// # Example + /// + /// ``` + /// # fn foo() -> arbitrary::Result<()> { + /// use arbitrary::{Arbitrary, Unstructured}; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4]); + /// + /// let x: i32 = u.int_in_range(-5_000..=-1_000)?; + /// + /// assert!(-5_000 <= x); + /// assert!(x <= -1_000); + /// # Ok(()) } + /// ``` + pub fn int_in_range(&mut self, range: ops::RangeInclusive) -> Result + where + T: Int, + { + let (result, bytes_consumed) = Self::int_in_range_impl(range, self.data.iter().cloned())?; + self.data = &self.data[bytes_consumed..]; + Ok(result) + } + + fn int_in_range_impl( + range: ops::RangeInclusive, + mut bytes: impl Iterator, + ) -> Result<(T, usize)> + where + T: Int, + { + let start = *range.start(); + let end = *range.end(); + assert!( + start <= end, + "`arbitrary::Unstructured::int_in_range` requires a non-empty range" + ); + + // When there is only one possible choice, don't waste any entropy from + // the underlying data. + if start == end { + return Ok((start, 0)); + } + + // From here on out we work with the unsigned representation. All of the + // operations performed below work out just as well whether or not `T` + // is a signed or unsigned integer. + let start = start.to_unsigned(); + let end = end.to_unsigned(); + + let delta = end.wrapping_sub(start); + debug_assert_ne!(delta, T::Unsigned::ZERO); + + // Compute an arbitrary integer offset from the start of the range. We + // do this by consuming `size_of(T)` bytes from the input to create an + // arbitrary integer and then clamping that int into our range bounds + // with a modulo operation. + let mut arbitrary_int = T::Unsigned::ZERO; + let mut bytes_consumed: usize = 0; + + while (bytes_consumed < mem::size_of::()) + && (delta >> T::Unsigned::from_usize(bytes_consumed * 8)) > T::Unsigned::ZERO + { + let byte = match bytes.next() { + None => break, + Some(b) => b, + }; + bytes_consumed += 1; + + // Combine this byte into our arbitrary integer, but avoid + // overflowing the shift for `u8` and `i8`. + arbitrary_int = if mem::size_of::() == 1 { + T::Unsigned::from_u8(byte) + } else { + (arbitrary_int << 8) | T::Unsigned::from_u8(byte) + }; + } + + let offset = if delta == T::Unsigned::MAX { + arbitrary_int + } else { + arbitrary_int % (delta.checked_add(T::Unsigned::ONE).unwrap()) + }; + + // Finally, we add `start` to our offset from `start` to get the result + // actual value within the range. + let result = start.wrapping_add(offset); + + // And convert back to our maybe-signed representation. + let result = T::from_unsigned(result); + debug_assert!(*range.start() <= result); + debug_assert!(result <= *range.end()); + + Ok((result, bytes_consumed)) + } + + /// Choose one of the given choices. + /// + /// This should only be used inside of `Arbitrary` implementations. + /// + /// The probability distribution of choices is not necessarily uniform. + /// + /// Returns the first choice, not an error, + /// if this `Unstructured` [is empty][Unstructured::is_empty]. + /// + /// Returns an error if no choices are provided. + /// + /// # Examples + /// + /// Selecting from an array of choices: + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + /// let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + /// + /// let choice = u.choose(&choices).unwrap(); + /// + /// println!("chose {}", choice); + /// ``` + /// + /// An error is returned if no choices are provided: + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + /// let choices: [char; 0] = []; + /// + /// let result = u.choose(&choices); + /// + /// assert!(result.is_err()); + /// ``` + pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> { + let idx = self.choose_index(choices.len())?; + Ok(&choices[idx]) + } + + /// Choose one of the given iterator choices. + /// + /// This should only be used inside of `Arbitrary` implementations. + /// + /// The probability distribution of choices is not necessarily uniform. + /// + /// Returns the first choice, not an error, + /// if this `Unstructured` [is empty][Unstructured::is_empty]. + /// + /// Returns an error if no choices are provided. + /// + /// # Examples + /// + /// Selecting a random item from a set: + /// + /// ``` + /// use std::collections::BTreeSet; + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + /// let set = BTreeSet::from(['a', 'b', 'c']); + /// + /// let choice = u.choose_iter(set.iter()).unwrap(); + /// + /// println!("chose {}", choice); + /// ``` + pub fn choose_iter(&mut self, choices: I) -> Result + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let mut choices = choices.into_iter(); + let idx = self.choose_index(choices.len())?; + let choice = choices + .nth(idx) + .expect("ExactSizeIterator should have correct len"); + Ok(choice) + } + + /// Choose a value in `0..len`. + /// + /// The probability distribution of return values is not necessarily uniform. + /// + /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. + /// + /// Returns an error if the `len` is zero. + /// + /// # Examples + /// + /// Using Fisher–Yates shuffle shuffle to generate an arbitrary permutation. + /// + /// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + /// let mut permutation = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + /// let mut to_permute = &mut permutation[..]; + /// while to_permute.len() > 1 { + /// let idx = u.choose_index(to_permute.len()).unwrap(); + /// to_permute.swap(0, idx); + /// to_permute = &mut to_permute[1..]; + /// } + /// + /// println!("permutation: {:?}", permutation); + /// ``` + /// + /// An error is returned if the length is zero: + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + /// let array: [i32; 0] = []; + /// + /// let result = u.choose_index(array.len()); + /// + /// assert!(result.is_err()); + /// ``` + pub fn choose_index(&mut self, len: usize) -> Result { + if len == 0 { + return Err(Error::EmptyChoose); + } + let idx = self.int_in_range(0..=len - 1)?; + Ok(idx) + } + + /// Generate a boolean which is true with probability approximately the given ratio. + /// + /// Returns true, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. + /// + /// # Panics + /// + /// Panics when the numerator and denominator do not meet these constraints: + /// + /// * `0 < numerator <= denominator` + /// + /// # Example + /// + /// Generate a boolean that is `true` five sevenths of the time: + /// + /// ``` + /// # fn foo() -> arbitrary::Result<()> { + /// use arbitrary::Unstructured; + /// + /// # let my_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + /// let mut u = Unstructured::new(&my_data); + /// + /// if u.ratio(5, 7)? { + /// // Take this branch approximately 5/7 of the time. + /// } + /// # Ok(()) + /// # } + /// ``` + pub fn ratio(&mut self, numerator: T, denominator: T) -> Result + where + T: Int, + { + assert!(T::ZERO < numerator); + assert!(numerator <= denominator); + let x = self.int_in_range(T::ONE..=denominator)?; + Ok(x <= numerator) + } + + /// Fill a `buffer` with bytes from the underlying raw data. + /// + /// This should only be called within an `Arbitrary` implementation. This is + /// a very low-level operation. You should generally prefer calling nested + /// `Arbitrary` implementations like `>::arbitrary` and + /// `String::arbitrary` over using this method directly. + /// + /// If this `Unstructured` does not have enough underlying data to fill the + /// whole `buffer`, it pads the buffer out with zeros. + /// + /// # Example + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4]); + /// + /// let mut buf = [0; 2]; + /// + /// assert!(u.fill_buffer(&mut buf).is_ok()); + /// assert_eq!(buf, [1, 2]); + /// + /// assert!(u.fill_buffer(&mut buf).is_ok()); + /// assert_eq!(buf, [3, 4]); + /// + /// assert!(u.fill_buffer(&mut buf).is_ok()); + /// assert_eq!(buf, [0, 0]); + /// ``` + pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> { + let n = std::cmp::min(buffer.len(), self.data.len()); + buffer[..n].copy_from_slice(&self.data[..n]); + for byte in buffer[n..].iter_mut() { + *byte = 0; + } + self.data = &self.data[n..]; + Ok(()) + } + + /// Provide `size` bytes from the underlying raw data. + /// + /// This should only be called within an `Arbitrary` implementation. This is + /// a very low-level operation. You should generally prefer calling nested + /// `Arbitrary` implementations like `>::arbitrary` and + /// `String::arbitrary` over using this method directly. + /// + /// # Example + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3, 4]); + /// + /// assert!(u.bytes(2).unwrap() == &[1, 2]); + /// assert!(u.bytes(2).unwrap() == &[3, 4]); + /// ``` + pub fn bytes(&mut self, size: usize) -> Result<&'a [u8]> { + if self.data.len() < size { + return Err(Error::NotEnoughData); + } + + let (for_buf, rest) = self.data.split_at(size); + self.data = rest; + Ok(for_buf) + } + + /// Peek at `size` number of bytes of the underlying raw input. + /// + /// Does not consume the bytes, only peeks at them. + /// + /// Returns `None` if there are not `size` bytes left in the underlying raw + /// input. + /// + /// # Example + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let u = Unstructured::new(&[1, 2, 3]); + /// + /// assert_eq!(u.peek_bytes(0).unwrap(), []); + /// assert_eq!(u.peek_bytes(1).unwrap(), [1]); + /// assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]); + /// assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]); + /// + /// assert!(u.peek_bytes(4).is_none()); + /// ``` + pub fn peek_bytes(&self, size: usize) -> Option<&'a [u8]> { + self.data.get(..size) + } + + /// Consume all of the rest of the remaining underlying bytes. + /// + /// Returns a slice of all the remaining, unconsumed bytes. + /// + /// # Example + /// + /// ``` + /// use arbitrary::Unstructured; + /// + /// let mut u = Unstructured::new(&[1, 2, 3]); + /// + /// let mut remaining = u.take_rest(); + /// + /// assert_eq!(remaining, [1, 2, 3]); + /// ``` + pub fn take_rest(mut self) -> &'a [u8] { + mem::take(&mut self.data) + } + + /// Provide an iterator over elements for constructing a collection + /// + /// This is useful for implementing [`Arbitrary::arbitrary`] on collections + /// since the implementation is simply `u.arbitrary_iter()?.collect()` + pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>( + &'b mut self, + ) -> Result> { + Ok(ArbitraryIter { + u: &mut *self, + _marker: PhantomData, + }) + } + + /// Provide an iterator over elements for constructing a collection from + /// all the remaining bytes. + /// + /// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections + /// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()` + pub fn arbitrary_take_rest_iter>( + self, + ) -> Result> { + Ok(ArbitraryTakeRestIter { + u: self, + _marker: PhantomData, + }) + } + + /// Call the given function an arbitrary number of times. + /// + /// The function is given this `Unstructured` so that it can continue to + /// generate arbitrary data and structures. + /// + /// You may optionaly specify minimum and maximum bounds on the number of + /// times the function is called. + /// + /// You may break out of the loop early by returning + /// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return + /// `Ok(std::ops::ControlFlow::Continue)`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Example + /// + /// Call a closure that generates an arbitrary type inside a context an + /// arbitrary number of times: + /// + /// ``` + /// use arbitrary::{Result, Unstructured}; + /// use std::ops::ControlFlow; + /// + /// enum Type { + /// /// A boolean type. + /// Bool, + /// + /// /// An integer type. + /// Int, + /// + /// /// A list of the `i`th type in this type's context. + /// List(usize), + /// } + /// + /// fn arbitrary_types_context(u: &mut Unstructured) -> Result> { + /// let mut context = vec![]; + /// + /// u.arbitrary_loop(Some(10), Some(20), |u| { + /// let num_choices = if context.is_empty() { + /// 2 + /// } else { + /// 3 + /// }; + /// let ty = match u.int_in_range::(1..=num_choices)? { + /// 1 => Type::Bool, + /// 2 => Type::Int, + /// 3 => Type::List(u.int_in_range(0..=context.len() - 1)?), + /// _ => unreachable!(), + /// }; + /// context.push(ty); + /// Ok(ControlFlow::Continue(())) + /// })?; + /// + /// // The number of loop iterations are constrained by the min/max + /// // bounds that we provided. + /// assert!(context.len() >= 10); + /// assert!(context.len() <= 20); + /// + /// Ok(context) + /// } + /// ``` + pub fn arbitrary_loop( + &mut self, + min: Option, + max: Option, + mut f: impl FnMut(&mut Self) -> Result>, + ) -> Result<()> { + let min = min.unwrap_or(0); + let max = max.unwrap_or(u32::MAX); + + for _ in 0..self.int_in_range(min..=max)? { + match f(self)? { + ControlFlow::Continue(_) => continue, + ControlFlow::Break(_) => break, + } + } + + Ok(()) + } +} + +/// Utility iterator produced by [`Unstructured::arbitrary_iter`] +pub struct ArbitraryIter<'a, 'b, ElementType> { + u: &'b mut Unstructured<'a>, + _marker: PhantomData, +} + +impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, '_, ElementType> { + type Item = Result; + fn next(&mut self) -> Option> { + let keep_going = self.u.arbitrary().unwrap_or(false); + if keep_going { + Some(Arbitrary::arbitrary(self.u)) + } else { + None + } + } +} + +/// Utility iterator produced by [`Unstructured::arbitrary_take_rest_iter`] +pub struct ArbitraryTakeRestIter<'a, ElementType> { + u: Unstructured<'a>, + _marker: PhantomData, +} + +impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> { + type Item = Result; + fn next(&mut self) -> Option> { + let keep_going = self.u.arbitrary().unwrap_or(false); + if keep_going { + Some(Arbitrary::arbitrary(&mut self.u)) + } else { + None + } + } +} + +/// A trait that is implemented for all of the primitive integers: +/// +/// * `u8` +/// * `u16` +/// * `u32` +/// * `u64` +/// * `u128` +/// * `usize` +/// * `i8` +/// * `i16` +/// * `i32` +/// * `i64` +/// * `i128` +/// * `isize` +/// +/// Don't implement this trait yourself. +pub trait Int: + Copy + + std::fmt::Debug + + PartialOrd + + Ord + + ops::Sub + + ops::Rem + + ops::Shr + + ops::Shl + + ops::BitOr +{ + #[doc(hidden)] + type Unsigned: Int; + + #[doc(hidden)] + const ZERO: Self; + + #[doc(hidden)] + const ONE: Self; + + #[doc(hidden)] + const MAX: Self; + + #[doc(hidden)] + fn from_u8(b: u8) -> Self; + + #[doc(hidden)] + fn from_usize(u: usize) -> Self; + + #[doc(hidden)] + fn checked_add(self, rhs: Self) -> Option; + + #[doc(hidden)] + fn wrapping_add(self, rhs: Self) -> Self; + + #[doc(hidden)] + fn wrapping_sub(self, rhs: Self) -> Self; + + #[doc(hidden)] + fn to_unsigned(self) -> Self::Unsigned; + + #[doc(hidden)] + fn from_unsigned(unsigned: Self::Unsigned) -> Self; +} + +macro_rules! impl_int { + ( $( $ty:ty : $unsigned_ty: ty ; )* ) => { + $( + impl Int for $ty { + type Unsigned = $unsigned_ty; + + const ZERO: Self = 0; + + const ONE: Self = 1; + + const MAX: Self = Self::MAX; + + fn from_u8(b: u8) -> Self { + b as Self + } + + fn from_usize(u: usize) -> Self { + u as Self + } + + fn checked_add(self, rhs: Self) -> Option { + <$ty>::checked_add(self, rhs) + } + + fn wrapping_add(self, rhs: Self) -> Self { + <$ty>::wrapping_add(self, rhs) + } + + fn wrapping_sub(self, rhs: Self) -> Self { + <$ty>::wrapping_sub(self, rhs) + } + + fn to_unsigned(self) -> Self::Unsigned { + self as $unsigned_ty + } + + fn from_unsigned(unsigned: $unsigned_ty) -> Self { + unsigned as Self + } + } + )* + } +} + +impl_int! { + u8: u8; + u16: u16; + u32: u32; + u64: u64; + u128: u128; + usize: usize; + i8: u8; + i16: u16; + i32: u32; + i64: u64; + i128: u128; + isize: usize; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_byte_size() { + let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); + // Should take one byte off the end + assert_eq!(u.arbitrary_byte_size().unwrap(), 6); + assert_eq!(u.len(), 9); + let mut v = vec![0; 260]; + v.push(1); + v.push(4); + let mut u = Unstructured::new(&v); + // Should read two bytes off the end + assert_eq!(u.arbitrary_byte_size().unwrap(), 0x104); + assert_eq!(u.len(), 260); + } + + #[test] + fn int_in_range_of_one() { + let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); + let x = u.int_in_range(0..=0).unwrap(); + assert_eq!(x, 0); + let choice = *u.choose(&[42]).unwrap(); + assert_eq!(choice, 42) + } + + #[test] + fn int_in_range_uses_minimal_amount_of_bytes() { + let mut u = Unstructured::new(&[1, 2]); + assert_eq!(1, u.int_in_range::(0..=u8::MAX).unwrap()); + assert_eq!(u.len(), 1); + + let mut u = Unstructured::new(&[1, 2]); + assert_eq!(1, u.int_in_range::(0..=u8::MAX as u32).unwrap()); + assert_eq!(u.len(), 1); + + let mut u = Unstructured::new(&[1]); + assert_eq!(1, u.int_in_range::(0..=u8::MAX as u32 + 1).unwrap()); + assert!(u.is_empty()); + } + + #[test] + fn int_in_range_in_bounds() { + for input in u8::MIN..=u8::MAX { + let input = [input]; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(1..=u8::MAX).unwrap(); + assert_ne!(x, 0); + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(0..=u8::MAX - 1).unwrap(); + assert_ne!(x, u8::MAX); + } + } + + #[test] + fn int_in_range_covers_unsigned_range() { + // Test that we generate all values within the range given to + // `int_in_range`. + + let mut full = [false; u8::MAX as usize + 1]; + let mut no_zero = [false; u8::MAX as usize]; + let mut no_max = [false; u8::MAX as usize]; + let mut narrow = [false; 10]; + + for input in u8::MIN..=u8::MAX { + let input = [input]; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(0..=u8::MAX).unwrap(); + full[x as usize] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(1..=u8::MAX).unwrap(); + no_zero[x as usize - 1] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(0..=u8::MAX - 1).unwrap(); + no_max[x as usize] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(100..=109).unwrap(); + narrow[x as usize - 100] = true; + } + + for (i, covered) in full.iter().enumerate() { + assert!(covered, "full[{}] should have been generated", i); + } + for (i, covered) in no_zero.iter().enumerate() { + assert!(covered, "no_zero[{}] should have been generated", i); + } + for (i, covered) in no_max.iter().enumerate() { + assert!(covered, "no_max[{}] should have been generated", i); + } + for (i, covered) in narrow.iter().enumerate() { + assert!(covered, "narrow[{}] should have been generated", i); + } + } + + #[test] + fn int_in_range_covers_signed_range() { + // Test that we generate all values within the range given to + // `int_in_range`. + + let mut full = [false; u8::MAX as usize + 1]; + let mut no_min = [false; u8::MAX as usize]; + let mut no_max = [false; u8::MAX as usize]; + let mut narrow = [false; 21]; + + let abs_i8_min: isize = 128; + + for input in 0..=u8::MAX { + let input = [input]; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(i8::MIN..=i8::MAX).unwrap(); + full[(x as isize + abs_i8_min) as usize] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(i8::MIN + 1..=i8::MAX).unwrap(); + no_min[(x as isize + abs_i8_min - 1) as usize] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(i8::MIN..=i8::MAX - 1).unwrap(); + no_max[(x as isize + abs_i8_min) as usize] = true; + + let mut u = Unstructured::new(&input); + let x = u.int_in_range(-10..=10).unwrap(); + narrow[(x as isize + 10) as usize] = true; + } + + for (i, covered) in full.iter().enumerate() { + assert!(covered, "full[{}] should have been generated", i); + } + for (i, covered) in no_min.iter().enumerate() { + assert!(covered, "no_min[{}] should have been generated", i); + } + for (i, covered) in no_max.iter().enumerate() { + assert!(covered, "no_max[{}] should have been generated", i); + } + for (i, covered) in narrow.iter().enumerate() { + assert!(covered, "narrow[{}] should have been generated", i); + } + } +} diff --git a/deps/crates/vendor/arbitrary/tests/bound.rs b/deps/crates/vendor/arbitrary/tests/bound.rs new file mode 100644 index 00000000000000..7a772ac71561c6 --- /dev/null +++ b/deps/crates/vendor/arbitrary/tests/bound.rs @@ -0,0 +1,142 @@ +#![cfg(feature = "derive")] + +use arbitrary::{Arbitrary, Unstructured}; + +fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { + let mut buf = Unstructured::new(input); + T::arbitrary(&mut buf).expect("can create arbitrary instance OK") +} + +/// This wrapper trait *implies* `Arbitrary`, but the compiler isn't smart enough to work that out +/// so when using this wrapper we *must* opt-out of the auto-generated `T: Arbitrary` bounds. +pub trait WrapperTrait: for<'a> Arbitrary<'a> {} + +impl WrapperTrait for u32 {} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: WrapperTrait")] +struct GenericSingleBound { + t: T, +} + +#[test] +fn single_bound() { + let v: GenericSingleBound = arbitrary_from(&[0, 0, 0, 0]); + assert_eq!(v.t, 0); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: WrapperTrait, U: WrapperTrait")] +struct GenericMultipleBoundsSingleAttribute { + t: T, + u: U, +} + +#[test] +fn multiple_bounds_single_attribute() { + let v: GenericMultipleBoundsSingleAttribute = + arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); + assert_eq!(v.t, 1); + assert_eq!(v.u, 2); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: WrapperTrait")] +#[arbitrary(bound = "U: Default")] +struct GenericMultipleArbitraryAttributes { + t: T, + #[arbitrary(default)] + u: U, +} + +#[test] +fn multiple_arbitrary_attributes() { + let v: GenericMultipleArbitraryAttributes = arbitrary_from(&[1, 0, 0, 0]); + assert_eq!(v.t, 1); + assert_eq!(v.u, 0); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] +struct GenericMultipleBoundAttributes { + t: T, + #[arbitrary(default)] + u: U, +} + +#[test] +fn multiple_bound_attributes() { + let v: GenericMultipleBoundAttributes = arbitrary_from(&[1, 0, 0, 0]); + assert_eq!(v.t, 1); + assert_eq!(v.u, 0); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] +#[arbitrary(bound = "V: WrapperTrait, W: Default")] +struct GenericMultipleArbitraryAndBoundAttributes< + T: WrapperTrait, + U: Default, + V: WrapperTrait, + W: Default, +> { + t: T, + #[arbitrary(default)] + u: U, + v: V, + #[arbitrary(default)] + w: W, +} + +#[test] +fn multiple_arbitrary_and_bound_attributes() { + let v: GenericMultipleArbitraryAndBoundAttributes = + arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); + assert_eq!(v.t, 1); + assert_eq!(v.u, 0); + assert_eq!(v.v, 2); + assert_eq!(v.w, 0); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "T: Default")] +struct GenericDefault { + #[arbitrary(default)] + x: T, +} + +#[test] +fn default_bound() { + // We can write a generic func without any `Arbitrary` bound. + fn generic_default() -> GenericDefault { + arbitrary_from(&[]) + } + + assert_eq!(generic_default::().x, 0); + assert_eq!(generic_default::().x, String::new()); + assert_eq!(generic_default::>().x, Vec::new()); +} + +#[derive(Arbitrary)] +#[arbitrary()] +struct EmptyArbitraryAttribute { + t: u32, +} + +#[test] +fn empty_arbitrary_attribute() { + let v: EmptyArbitraryAttribute = arbitrary_from(&[1, 0, 0, 0]); + assert_eq!(v.t, 1); +} + +#[derive(Arbitrary)] +#[arbitrary(bound = "")] +struct EmptyBoundAttribute { + t: u32, +} + +#[test] +fn empty_bound_attribute() { + let v: EmptyBoundAttribute = arbitrary_from(&[1, 0, 0, 0]); + assert_eq!(v.t, 1); +} diff --git a/deps/crates/vendor/arbitrary/tests/derive.rs b/deps/crates/vendor/arbitrary/tests/derive.rs new file mode 100644 index 00000000000000..c45cc24b7b99e0 --- /dev/null +++ b/deps/crates/vendor/arbitrary/tests/derive.rs @@ -0,0 +1,402 @@ +#![cfg(feature = "derive")] +// Various structs/fields that we are deriving `Arbitrary` for aren't actually +// used except to exercise the derive. +#![allow(dead_code)] +// Various assert_eq! are used to compare result of bool amongst other data types +// In this case, using assert! is less explicit and readable +#![allow(clippy::bool_assert_comparison)] + +use arbitrary::*; + +fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { + let mut buf = Unstructured::new(input); + T::arbitrary(&mut buf).expect("can create arbitrary instance OK") +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary)] +pub struct Rgb { + pub r: u8, + pub g: u8, + pub b: u8, +} + +#[test] +fn struct_with_named_fields() { + let rgb: Rgb = arbitrary_from(&[4, 5, 6]); + assert_eq!(rgb.r, 4); + assert_eq!(rgb.g, 5); + assert_eq!(rgb.b, 6); + + assert_eq!((3, Some(3)), ::size_hint(0)); +} + +#[derive(Copy, Clone, Debug, Arbitrary)] +struct MyTupleStruct(u8, bool); + +#[test] +fn tuple_struct() { + let s: MyTupleStruct = arbitrary_from(&[43, 42]); + assert_eq!(s.0, 43); + assert_eq!(s.1, false); + + let s: MyTupleStruct = arbitrary_from(&[42, 43]); + assert_eq!(s.0, 42); + assert_eq!(s.1, true); + + assert_eq!((2, Some(2)), ::size_hint(0)); +} + +#[derive(Clone, Debug, Arbitrary)] +struct EndingInVec(u8, bool, u32, Vec); +#[derive(Clone, Debug, Arbitrary)] +struct EndingInString(u8, bool, u32, String); + +#[test] +fn test_take_rest() { + let bytes = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8]; + let s1 = EndingInVec::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); + let s2 = EndingInString::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); + assert_eq!(s1.0, 1); + assert_eq!(s2.0, 1); + assert_eq!(s1.1, true); + assert_eq!(s2.1, true); + assert_eq!(s1.2, 0x4030201); + assert_eq!(s2.2, 0x4030201); + assert_eq!(s1.3, vec![0x0706]); + assert_eq!(s2.3, "\x05\x06\x07\x08"); +} + +#[derive(Copy, Clone, Debug, Arbitrary)] +enum MyEnum { + Unit, + Tuple(u8, u16), + Struct { a: u32, b: (bool, u64) }, +} + +#[test] +fn derive_enum() { + let mut raw = vec![ + // The choice of which enum variant takes 4 bytes. + 1, 2, 3, 4, + // And then we need up to 13 bytes for creating `MyEnum::Struct`, the + // largest variant. + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + ]; + + let mut saw_unit = false; + let mut saw_tuple = false; + let mut saw_struct = false; + + for i in 0..=255 { + // Choose different variants each iteration. + for el in &mut raw[..4] { + *el = i; + } + + let e: MyEnum = arbitrary_from(&raw); + + match e { + MyEnum::Unit => { + saw_unit = true; + } + MyEnum::Tuple(a, b) => { + saw_tuple = true; + assert_eq!(a, arbitrary_from(&raw[4..5])); + assert_eq!(b, arbitrary_from(&raw[5..])); + } + MyEnum::Struct { a, b } => { + saw_struct = true; + assert_eq!(a, arbitrary_from(&raw[4..8])); + assert_eq!(b, arbitrary_from(&raw[8..])); + } + } + } + + assert!(saw_unit); + assert!(saw_tuple); + assert!(saw_struct); + + assert_eq!((4, Some(17)), ::size_hint(0)); +} + +// This should result in a compiler-error: +// #[derive(Arbitrary, Debug)] +// enum Never { +// #[arbitrary(skip)] +// Nope, +// } + +#[derive(Arbitrary, Debug)] +enum SkipVariant { + Always, + #[arbitrary(skip)] + Never, +} + +#[test] +fn test_skip_variant() { + (0..=u8::MAX).for_each(|byte| { + let buffer = [byte]; + let unstructured = Unstructured::new(&buffer); + let skip_variant = SkipVariant::arbitrary_take_rest(unstructured).unwrap(); + assert!(!matches!(skip_variant, SkipVariant::Never)); + }) +} + +#[derive(Arbitrary, Debug)] +enum RecursiveTree { + Leaf, + Node { + left: Box, + right: Box, + }, +} + +#[derive(Arbitrary, Debug)] +struct WideRecursiveStruct { + a: Option>, + b: Option>, + c: Option>, + d: Option>, + e: Option>, + f: Option>, + g: Option>, + h: Option>, + i: Option>, + k: Option>, +} + +#[derive(Arbitrary, Debug)] +enum WideRecursiveEnum { + None, + A(Box), + B(Box), + C(Box), + D(Box), + E(Box), + F(Box), + G(Box), + H(Box), + I(Box), + K(Box), +} + +#[derive(Arbitrary, Debug)] +enum WideRecursiveMixedEnum { + None, + A(Box), + B(Box), + C(Box), + D(Box), + E(Box), + F(Box), + G(Box), + H(Box), + I(Box), + K(Box), +} + +#[derive(Arbitrary, Debug)] +struct WideRecursiveMixedStruct { + a: Option>, + b: Option>, + c: Option>, + d: Option>, + e: Option>, + f: Option>, + g: Option>, + h: Option>, + i: Option>, + k: Option>, +} + +#[test] +fn recursive() { + let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + let _rec: RecursiveTree = arbitrary_from(&raw); + let _rec: WideRecursiveStruct = arbitrary_from(&raw); + let _rec: WideRecursiveEnum = arbitrary_from(&raw); + let _rec: WideRecursiveMixedStruct = arbitrary_from(&raw); + let _rec: WideRecursiveMixedEnum = arbitrary_from(&raw); + + assert_eq!((0, None), ::size_hint(0)); + assert_eq!((0, None), ::size_hint(0)); + assert_eq!( + (0, None), + ::size_hint(0) + ); + assert_eq!( + (0, None), + ::size_hint(0) + ); + + let (lower, upper) = ::size_hint(0); + assert_eq!(lower, 0, "Cannot compute size hint of recursive structure"); + assert!( + upper.is_none(), + "potentially infinitely recursive, so no upper bound" + ); +} + +#[derive(Arbitrary, Debug)] +struct Generic { + inner: T, +} + +#[test] +fn generics() { + let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + let gen: Generic = arbitrary_from(&raw); + assert!(gen.inner); + + let (lower, upper) = as Arbitrary>::size_hint(0); + assert_eq!(lower, 4); + assert_eq!(upper, Some(4)); +} + +#[derive(Arbitrary, Debug)] +struct OneLifetime<'a> { + alpha: &'a str, +} + +#[test] +fn one_lifetime() { + // Last byte is used for length + let raw: Vec = vec![97, 98, 99, 100, 3]; + let lifetime: OneLifetime = arbitrary_from(&raw); + assert_eq!("abc", lifetime.alpha); + + let (lower, upper) = ::size_hint(0); + assert_eq!(lower, 0); + assert_eq!(upper, None); +} + +#[derive(Arbitrary, Debug)] +struct TwoLifetimes<'a, 'b> { + alpha: &'a str, + beta: &'b str, +} + +#[test] +fn two_lifetimes() { + // Last byte is used for length + let raw: Vec = vec![97, 98, 99, 100, 101, 102, 103, 3]; + let lifetime: TwoLifetimes = arbitrary_from(&raw); + assert_eq!("abc", lifetime.alpha); + assert_eq!("def", lifetime.beta); + + let (lower, upper) = ::size_hint(0); + assert_eq!(lower, 0); + assert_eq!(upper, None); +} + +#[test] +fn recursive_and_empty_input() { + // None of the following derives should result in a stack overflow. See + // https://github.com/rust-fuzz/arbitrary/issues/107 for details. + + #[derive(Debug, Arbitrary)] + enum Nat { + Succ(Box), + Zero, + } + + let _ = Nat::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Arbitrary)] + enum Nat2 { + Zero, + Succ(Box), + } + + let _ = Nat2::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Arbitrary)] + struct Nat3 { + f: Option>, + } + + let _ = Nat3::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Arbitrary)] + struct Nat4(Option>); + + let _ = Nat4::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Arbitrary)] + enum Nat5 { + Zero, + Succ { f: Box }, + } + + let _ = Nat5::arbitrary(&mut Unstructured::new(&[])); +} + +#[test] +fn test_field_attributes() { + // A type that DOES NOT implement Arbitrary + #[derive(Debug)] + struct Weight(u8); + + #[derive(Debug, Arbitrary)] + struct Parcel { + #[arbitrary(with = arbitrary_weight)] + weight: Weight, + + #[arbitrary(default)] + width: u8, + + #[arbitrary(value = 2 + 2)] + length: u8, + + height: u8, + + #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=100))] + price: u8, + } + + fn arbitrary_weight(u: &mut Unstructured) -> arbitrary::Result { + u.int_in_range(45..=56).map(Weight) + } + + let parcel: Parcel = arbitrary_from(&[6, 199, 17]); + + // 45 + 6 = 51 + assert_eq!(parcel.weight.0, 51); + + // u8::default() + assert_eq!(parcel.width, 0); + + // 2 + 2 = 4 + assert_eq!(parcel.length, 4); + + // 199 is the 2nd byte used by arbitrary + assert_eq!(parcel.height, 199); + + // 17 is the 3rd byte used by arbitrary + assert_eq!(parcel.price, 17); +} + +#[test] +fn derive_structs_named_same_as_core() { + #[derive(Debug, Arbitrary)] + struct Option { + f: core::option::Option, + } + + let _ = Option::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Default, Arbitrary)] + struct Default { + f: u32, + } + + let _ = Default::arbitrary(&mut Unstructured::new(&[])); + + #[derive(Debug, Arbitrary)] + struct Result { + f: core::result::Result, + } + + let _ = Result::arbitrary(&mut Unstructured::new(&[])); +} diff --git a/deps/crates/vendor/arbitrary/tests/path.rs b/deps/crates/vendor/arbitrary/tests/path.rs new file mode 100644 index 00000000000000..c42ec0a1134674 --- /dev/null +++ b/deps/crates/vendor/arbitrary/tests/path.rs @@ -0,0 +1,32 @@ +#![cfg(feature = "derive")] +// Various structs/fields that we are deriving `Arbitrary` for aren't actually +// used except to show off the derive. +#![allow(dead_code)] + +// Regression test for ensuring the derives work without Arbitrary being imported + +#[derive(arbitrary::Arbitrary, Clone, Debug)] +pub struct Struct { + x: u8, + y: u8, +} + +#[derive(arbitrary::Arbitrary, Clone, Debug)] +pub struct Tuple(u8); + +#[derive(arbitrary::Arbitrary, Clone, Debug)] +pub struct Unit(u8); + +#[derive(arbitrary::Arbitrary, Clone, Debug)] +pub enum Enum { + X(u8), + Y(u8), +} + +#[derive(arbitrary::Arbitrary, Clone, Debug)] +struct EndingInVec(u8, bool, u32, Vec); + +#[derive(arbitrary::Arbitrary, Debug)] +struct Generic { + inner: T, +} diff --git a/deps/crates/vendor/bumpalo/.cargo-checksum.json b/deps/crates/vendor/bumpalo/.cargo-checksum.json new file mode 100644 index 00000000000000..81dee15b5061f5 --- /dev/null +++ b/deps/crates/vendor/bumpalo/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"a09ad0e25c850897890eb7b83f903d5ae8b8bed0f1277e5a3f93175bfe57790e","CHANGELOG.md":"6b4984917b525372cc892936e1d44d2461965c3fa2a1a6a3d4472550422921b8","Cargo.lock":"b1c1f605c396e79aa3f2c3f2f992665503fd0cc5c93d45e2cedf95749d0e1cd9","Cargo.toml":"c7928795a1899a69c3e06fe5bd8628c73a34e19f558d7a9a67bd7dfabf58f632","Cargo.toml.orig":"c8debab96114f172dbb09e0a4e1f319066ba7eca09b3f72e42c6803615ad79e3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee","README.md":"050b1853333be74aa06088e47f5d53bc18840319d4dd256760d3d860e5e52879","src/alloc.rs":"3a9645d9e8db1f2a8549ee928cafa5263a828f25c88ce4d2b07996ecc14bfa81","src/boxed.rs":"ad0ead49343b0eb66464d8c7ec645e145d00558e6a2507d7d7a8c777fc9f5c68","src/collections/collect_in.rs":"0588a4ff3967a4323abb4218bbd615af4b123639ab4fae9130c6590c258b3d15","src/collections/mod.rs":"d58dc46eb4f9fcdde574f09bc5b8646f53e42d49c169561d98e0c23e5b36848a","src/collections/raw_vec.rs":"c045b13f3ac191f1c597f87a7385f59078a3d091f7888d8449d65b9e6f67e315","src/collections/str/lossy.rs":"c5d62b16e01071e2a574ae41ef6693ad12f1e6c786c5d38f7a13ebd6cb23c088","src/collections/str/mod.rs":"d82a8bd417fbf52a589d89a16ea2a0ac4f6ac920c3976ab1f5b6ac0c8493c4f2","src/collections/string.rs":"9cbca6a0c6ae8b9c961d7a140d5146ba4c1f2e7a317c33e2e693911f2848044d","src/collections/vec.rs":"7f00d01cdc328064e8bf36a3e4ea490a10ece4bd5f5b29a107edc85a5bd70dae","src/lib.rs":"b17a8a9e525ab8599050f2cb50b158a6e883db9e64f893bd31d02f19a75920bc"},"package":"5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"} \ No newline at end of file diff --git a/deps/crates/vendor/bumpalo/.cargo_vcs_info.json b/deps/crates/vendor/bumpalo/.cargo_vcs_info.json new file mode 100644 index 00000000000000..32a7c3c75c11a6 --- /dev/null +++ b/deps/crates/vendor/bumpalo/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "1aad072f93d8a4cf5885446ead554927c7c94f9c" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/bumpalo/CHANGELOG.md b/deps/crates/vendor/bumpalo/CHANGELOG.md new file mode 100644 index 00000000000000..48a72372f544e1 --- /dev/null +++ b/deps/crates/vendor/bumpalo/CHANGELOG.md @@ -0,0 +1,915 @@ +## Unreleased + +Released YYYY-MM-DD. + +### Added + +* TODO (or remove section if none) + +### Changed + +* TODO (or remove section if none) + +### Deprecated + +* TODO (or remove section if none) + +### Removed + +* TODO (or remove section if none) + +### Fixed + +* TODO (or remove section if none) + +### Security + +* TODO (or remove section if none) + +-------------------------------------------------------------------------------- + +## 3.20.2 + +Released 2026-02-19. + +### Fixed + +* Restored `Send` and `Sync` implementations for `Box` for `T: ?Sized` types + as well. + +-------------------------------------------------------------------------------- + +## 3.20.1 + +Released 2026-02-18. + +### Fixed + +* Restored `Send` and `Sync` implementations for `Box` when `T: Send` and `T: + Sync` respectively. + +-------------------------------------------------------------------------------- + +## 3.20.0 + +Released 2026-02-18. + +### Added + +* Added the `bumpalo::collections::Vec::pop_if` method. + +### Fixed + +* Fixed a bug in the `bumpalo::collections::String::retain` method in the face + of panics. +* Made `bumpalo::collections::Box` covariant with `T` (just like + `std::boxed::Box`). + +-------------------------------------------------------------------------------- + +## 3.19.1 + +Released 2025-12-16. + +### Changed + +* Annotated `bumpalo::collections::String::from_str_in` as `#[inline]`. + +### Fixed + +* Fixed compilation failures with the latest nightly Rust when enabling the + unstable `allocator_api` feature. + +-------------------------------------------------------------------------------- + +## 3.19.0 + +Released 2025-06-24. + +### Added + +* Added `bumpalo::collections::Vec::retain_mut`, similar to + `std::vec::Vec::retain_mut`. + +-------------------------------------------------------------------------------- + +## 3.18.1 + +Released 2025-06-05. + +### Removed + +* Removed the `allocator-api2` version bump from 3.18.0, as it was not actually + semver compatible. + +-------------------------------------------------------------------------------- + +## 3.18.0 (yanked) + +Released 2025-06-05. + +### Added + +* Added support for enforcing a minimum alignment on all allocations inside a + `Bump` arena, which can provide speed ups when allocating objects whose + alignment is less than or equal to that minimum. +* Added `serde` serialization support for `bumpalo::collections::String`. +* Added some missing fallible slice allocation function variants. + +### Changed + +* Replaced `extend_from_slice` implementation with a formally-verified version + that is also faster and more-optimizable for LLVM. +* Updated `allocator-api2` support to version `0.3.*`. + +### Fixed + +* Fixed a bug where the `allocated_bytes` metrics helper was accidentally + including the size of `bumpalo`'s footer, rather than just reporting the + user-allocated bytes. + +-------------------------------------------------------------------------------- + +## 3.17.0 + +Released 2025-01-28. + +### Added + +* Added a bunch of `try_` allocation methods for slices and `str`: + * `try_alloc_slice_fill_default` + * `try_alloc_slice_fill_iter` + * `try_alloc_slice_fill_clone` + * `try_alloc_slice_fill_copy` + * `try_alloc_slice_fill_with` + * `try_alloc_str` + * `try_alloc_slice_clone` + * `try_alloc_slice_copy` + +### Changed + +* Minimum supported Rust version reduced to 1.71.1 + +### Fixed + +* Fixed a stacked-borrows MIRI bug in `dealloc` + +-------------------------------------------------------------------------------- + +## 3.16.0 + +Released 2024-04-08. + +### Added + +* Added an optional, off-by-default dependency on the `serde` crate. Enabling + this dependency allows you to serialize Bumpalo's collection and box + types. Deserialization is not implemented, due to constraints of the + deserialization trait. + +-------------------------------------------------------------------------------- + +## 3.15.4 + +Released 2024-03-07. + +### Added + +* Added the `bumpalo::collections::Vec::extend_from_slices_copy` method, which + is a faster way to extend a vec from multiple slices when the element is + `Copy` than calling `extend_from_slice_copy` N times. + +-------------------------------------------------------------------------------- + +## 3.15.3 + +Released 2024-02-22. + +### Added + +* Added additional performance improvements to `bumpalo::collections::Vec` + related to reserving capacity. + +-------------------------------------------------------------------------------- + +## 3.15.2 + +Released 2024-02-21. + +### Added + +* Add a `bumpalo::collections::Vec::extend_from_slice_copy` method. This doesn't + exist on the standard library's `Vec` but they have access to specialization, + so their regular `extend_from_slice` has a specialization for `Copy` + types. Using this new method for `Copy` types is a ~80x performance + improvement over the plain `extend_from_slice` method. + +-------------------------------------------------------------------------------- + +## 3.15.1 + +Released 2024-02-20. + +### Fixed + +* Fixed the MSRV listed in `Cargo.toml`, whose update was forgotten when the + MSRV bumped in release 3.15.0. + +-------------------------------------------------------------------------------- + +## 3.15.0 + +Released 2024-02-15. + +### Changed + +* The minimum supported Rust version (MSRV) is now 1.73.0. +* `bumpalo::collections::String::push_str` and + `bumpalo::collections::String::from_str_in` received significant performance + improvements. +* Allocator trait methods are now marked `#[inline]`, increasing performance for + some callers. + +### Fixed + +* Fixed an edge-case bug in the `Allocator::shrink` method. + +-------------------------------------------------------------------------------- + +## 3.14.0 + +Released 2023-09-14. + +### Added + +* Added the `std` cargo feature, which enables implementations of `std` traits + for various things. Right now that is just `std::io::Write` for + `bumpalo::collections::Vec`, but could be more in the future. + +-------------------------------------------------------------------------------- + +## 3.13.0 + +Released 2023-05-22. + +### Added + +* New `"allocator-api2"` feature enables the use of the allocator API on + stable. This feature uses a crate that mirrors the API of the unstable Rust + `allocator_api` feature. If the feature is enabled, references to `Bump` will + implement `allocator_api2::Allocator`. This allows `Bump` to be used as an + allocator for collection types from `allocator-api2` and any other crates that + support `allocator-api2`. + +### Changed + +* The minimum supported Rust version (MSRV) is now 1.63.0. + +-------------------------------------------------------------------------------- + +## 3.12.2 + +Released 2023-05-09. + +### Changed + +* Added `rust-version` metadata to `Cargo.toml` which helps `cargo` with version + resolution. + +-------------------------------------------------------------------------------- + +## 3.12.1 + +Released 2023-04-21. + +### Fixed + +* Fixed a bug where `Bump::try_with_capacity(n)` where `n > isize::MAX` could + lead to attempts to create invalid `Layout`s. + +-------------------------------------------------------------------------------- + +## 3.12.0 + +Released 2023-01-17. + +### Added + +* Added the `bumpalo::boxed::Box::bump` and `bumpalo::collections::String::bump` + getters to get the underlying `Bump` that a string or box was allocated into. + +### Changed + +* Some uses of `Box` that MIRI did not previously consider as UB are now + reported as UB, and `bumpalo`'s internals have been adjusted to avoid the new + UB. + +-------------------------------------------------------------------------------- + +## 3.11.1 + +Released 2022-10-18. + +### Security + +* Fixed a bug where when `std::vec::IntoIter` was ported to + `bumpalo::collections::vec::IntoIter`, it didn't get its underlying `Bump`'s + lifetime threaded through. This meant that `rustc` was not checking the + borrows for `bumpalo::collections::IntoIter` and this could result in + use-after-free bugs. + +-------------------------------------------------------------------------------- + +## 3.11.0 + +Released 2022-08-17. + +### Added + +* Added support for per-`Bump` allocation limits. These are enforced only in the + slow path when allocating new chunks in the `Bump`, not in the bump allocation + hot path, and therefore impose near zero overhead. +* Added the `bumpalo::boxed::Box::into_inner` method. + +### Changed + +* Updated to Rust 2021 edition. +* The minimum supported Rust version (MSRV) is now 1.56.0. + +-------------------------------------------------------------------------------- + +## 3.10.0 + +Released 2022-06-01. + +### Added + +* Implement `bumpalo::collections::FromIteratorIn` for `Option` and `Result`, + just like `core` does for `FromIterator`. +* Implement `bumpalo::collections::FromIteratorIn` for `bumpalo::boxed::Box<'a, + [T]>`. +* Added running tests under MIRI in CI for additional confidence in unsafe code. +* Publicly exposed `bumpalo::collections::Vec::drain_filter` since the + corresponding `std::vec::Vec` method has stabilized. + +### Changed + +* `Bump::new` will not allocate a backing chunk until the first allocation + inside the bump arena now. + +### Fixed + +* Properly account for alignment changes when growing or shrinking an existing + allocation. +* Removed all internal integer-to-pointer casts, to play better with UB checkers + like MIRI. + +-------------------------------------------------------------------------------- + +## 3.9.1 + +Released 2022-01-06. + +### Fixed + +* Fixed link to logo in docs and README.md + +-------------------------------------------------------------------------------- + +## 3.9.0 + +Released 2022-01-05. + +### Changed + +* The minimum supported Rust version (MSRV) has been raised to Rust 1.54.0. + +* `bumpalo::collections::Vec` implements relevant traits for all arrays of + any size `N` via const generics. Previously, it was just arrays up to length + 32. Similar for `bumpalo::boxed::Box<[T; N]>`. + +-------------------------------------------------------------------------------- + +## 3.8.0 + +Released 2021-10-19. + +### Added + +* Added the `CollectIn` and `FromIteratorIn` traits to make building a + collection from an iterator easier. These new traits live in the + `bumpalo::collections` module and are implemented by + `bumpalo::collections::{String,Vec}`. + +* Added the `Bump::iter_allocated_chunks_raw` method, which is an `unsafe`, raw + version of `Bump::iter_allocated_chunks`. The new method does not take an + exclusive borrow of the `Bump` and yields raw pointer-and-length pairs for + each chunk in the bump. It is the caller's responsibility to ensure that no + allocation happens in the `Bump` while iterating over chunks and that there + are no active borrows of allocated data if they want to turn any + pointer-and-length pairs into slices. + +-------------------------------------------------------------------------------- + +## 3.7.1 + +Released 2021-09-17. + +### Changed + +* The packaged crate uploaded to crates.io when `bumpalo` is published is now + smaller, thanks to excluding unnecessary files. + +-------------------------------------------------------------------------------- + +## 3.7.0 + +Released 2020-05-28. + +### Added + +* Added `Borrow` and `BorrowMut` trait implementations for + `bumpalo::collections::Vec` and + `bumpalo::collections::String`. [#108](https://github.com/fitzgen/bumpalo/pull/108) + +### Changed + +* When allocating a new chunk fails, don't immediately give up. Instead, try + allocating a chunk that is half that size, and if that fails, then try half of + *that* size, etc until either we successfully allocate a chunk or we fail to + allocate the minimum chunk size and then finally give + up. [#111](https://github.com/fitzgen/bumpalo/pull/111) + +-------------------------------------------------------------------------------- + +## 3.6.1 + +Released 2020-02-18. + +### Added + +* Improved performance of `Bump`'s `Allocator::grow_zeroed` trait method + implementation. [#99](https://github.com/fitzgen/bumpalo/pull/99) + +-------------------------------------------------------------------------------- + +## 3.6.0 + +Released 2020-01-29. + +### Added + +* Added a few new flavors of allocation: + + * `try_alloc` for fallible, by-value allocation + + * `try_alloc_with` for fallible allocation with an infallible initializer + function + + * `alloc_try_with` for infallible allocation with a fallible initializer + function + + * `try_alloc_try_with` method for fallible allocation with a fallible + initializer function + + We already have infallible, by-value allocation (`alloc`) and infallible + allocation with an infallible initializer (`alloc_with`). With these new + methods, we now have every combination covered. + + Thanks to [Tamme Schichler](https://github.com/Tamschi) for contributing these + methods! + +-------------------------------------------------------------------------------- + +## 3.5.0 + +Released 2020-01-22. + +### Added + +* Added experimental, unstable support for the unstable, nightly Rust + `allocator_api` feature. + + The `allocator_api` feature defines an `Allocator` trait and exposes custom + allocators for `std` types. Bumpalo has a matching `allocator_api` cargo + feature to enable implementing `Allocator` and using `Bump` with `std` + collections. + + First, enable the `allocator_api` feature in your `Cargo.toml`: + + ```toml + [dependencies] + bumpalo = { version = "3.5", features = ["allocator_api"] } + ``` + + Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or `src/main.rs`: + + ```rust + # #[cfg(feature = "allocator_api")] + # { + #![feature(allocator_api)] + # } + ``` + + Finally, use `std` collections with `Bump`, so that their internal heap + allocations are made within the given bump arena: + + ``` + # #![cfg_attr(feature = "allocator_api", feature(allocator_api))] + # #[cfg(feature = "allocator_api")] + # { + #![feature(allocator_api)] + use bumpalo::Bump; + + // Create a new bump arena. + let bump = Bump::new(); + + // Create a `Vec` whose elements are allocated within the bump arena. + let mut v = Vec::new_in(&bump); + v.push(0); + v.push(1); + v.push(2); + # } + ``` + + I'm very excited to see custom allocators in `std` coming along! Thanks to + Arthur Gautier for implementing support for the `allocator_api` feature for + Bumpalo. + +-------------------------------------------------------------------------------- + +## 3.4.0 + +Released 2020-06-01. + +### Added + +* Added the `bumpalo::boxed::Box` type. It is an owned pointer referencing a + bump-allocated value, and it runs `T`'s `Drop` implementation on the + referenced value when dropped. This type can be used by enabling the `"boxed"` + cargo feature flag. + +-------------------------------------------------------------------------------- + +## 3.3.0 + +Released 2020-05-13. + +### Added + +* Added fallible allocation methods to `Bump`: `try_new`, `try_with_capacity`, + and `try_alloc_layout`. + +* Added `Bump::chunk_capacity` + +* Added `bumpalo::collections::Vec::try_reserve[_exact]` + +-------------------------------------------------------------------------------- + +## 3.2.1 + +Released 2020-03-24. + +### Security + +* When `realloc`ing, if we allocate new space, we need to copy the old + allocation's bytes into the new space. There are `old_size` number of bytes in + the old allocation, but we were accidentally copying `new_size` number of + bytes, which could lead to copying bytes into the realloc'd space from past + the chunk that we're bump allocating out of, from unknown memory. + + If an attacker can cause `realloc`s, and can read the `realoc`ed data back, + this could allow them to read things from other regions of memory that they + shouldn't be able to. For example, if some crypto keys happened to live in + memory right after a chunk we were bump allocating out of, this could allow + the attacker to read the crypto keys. + + Beyond just fixing the bug and adding a regression test, I've also taken two + additional steps: + + 1. While we were already running the testsuite under `valgrind` in CI, because + `valgrind` exits with the same code that the program did, if there are + invalid reads/writes that happen not to trigger a segfault, the program can + still exit OK and we will be none the wiser. I've enabled the + `--error-exitcode=1` flag for `valgrind` in CI so that tests eagerly fail + in these scenarios. + + 2. I've written a quickcheck test to exercise `realloc`. Without the bug fix + in this patch, this quickcheck immediately triggers invalid reads when run + under `valgrind`. We didn't previously have quickchecks that exercised + `realloc` because `realloc` isn't publicly exposed directly, and instead + can only be indirectly called. This new quickcheck test exercises `realloc` + via `bumpalo::collections::Vec::resize` and + `bumpalo::collections::Vec::shrink_to_fit` calls. + + This bug was introduced in version 3.0.0. + + See [#69](https://github.com/fitzgen/bumpalo/issues/69) for details. + +-------------------------------------------------------------------------------- + +## 3.2.0 + +Released 2020-02-07. + +### Added + +* Added the `bumpalo::collections::Vec::into_bump_slice_mut` method to turn a + `bumpalo::collections::Vec<'bump, T>` into a `&'bump mut [T]`. + +-------------------------------------------------------------------------------- + +## 3.1.2 + +Released 2020-01-07. + +### Fixed + +* The `bumpalo::collections::format!` macro did not used to accept a trailing + comma like `format!(in bump; "{}", 1,)`, but it does now. + +-------------------------------------------------------------------------------- + +## 3.1.1 + +Released 2020-01-03. + +### Fixed + +* The `bumpalo::collections::vec!` macro did not used to accept a trailing + comma like `vec![in bump; 1, 2,]`, but it does now. + +-------------------------------------------------------------------------------- + +## 3.1.0 + +Released 2019-12-27. + +### Added + +* Added the `Bump::allocated_bytes` diagnostic method for counting the total + number of bytes a `Bump` has allocated. + +-------------------------------------------------------------------------------- + +# 3.0.0 + +Released 2019-12-20. + +## Added + +* Added `Bump::alloc_str` for copying string slices into a `Bump`. + +* Added `Bump::alloc_slice_copy` and `Bump::alloc_slice_clone` for copying or + cloning slices into a `Bump`. + +* Added `Bump::alloc_slice_fill_iter` for allocating a slice in the `Bump` from + an iterator. + +* Added `Bump::alloc_slice_fill_copy` and `Bump::alloc_slice_fill_clone` for + creating slices of length `n` that are filled with copies or clones of an + initial element. + +* Added `Bump::alloc_slice_fill_default` for creating slices of length `n` with + the element type's default instance. + +* Added `Bump::alloc_slice_fill_with` for creating slices of length `n` whose + elements are initialized with a function or closure. + +* Added `Bump::iter_allocated_chunks` as a replacement for the old + `Bump::each_allocated_chunk`. The `iter_allocated_chunks` version returns an + iterator, which is more idiomatic than its old, callback-taking counterpart. + Additionally, `iter_allocated_chunks` exposes the chunks as `MaybeUninit`s + instead of slices, which makes it usable in more situations without triggering + undefined behavior. See also the note about bump direction in the "changed" + section; if you're iterating chunks, you're likely affected by that change! + +* Added `Bump::with_capacity` so that you can pre-allocate a chunk with the + requested space. + +### Changed + +* **BREAKING:** The direction we allocate within a chunk has changed. It used to + be "upwards", from low addresses within a chunk towards high addresses. It is + now "downwards", from high addresses towards lower addresses. + + Additionally, the order in which we iterate over allocated chunks has changed! + We used to iterate over chunks from oldest chunk to youngest chunk, and now we + do the opposite: the youngest chunks are iterated over first, and the oldest + chunks are iterated over last. + + If you were using `Bump::each_allocated_chunk` to iterate over data that you + had previously allocated, and *you want to iterate in order of + oldest-to-youngest allocation*, you need to reverse the chunks iterator and + also reverse the order in which you loop through the data within a chunk! + + For example, if you had this code: + + ```rust + unsafe { + bump.each_allocated_chunk(|chunk| { + for byte in chunk { + // Touch each byte in oldest-to-youngest allocation order... + } + }); + } + ``` + + It should become this code: + + ```rust + let mut chunks: Vec<_> = bump.iter_allocated_chunks().collect(); + chunks.reverse(); + for chunk in chunks { + for byte in chunk.iter().rev() { + let byte = unsafe { byte.assume_init() }; + // Touch each byte in oldest-to-youngest allocation order... + } + } + ``` + + The good news is that this change yielded a *speed up in allocation throughput + of 3-19%!* + + See https://github.com/fitzgen/bumpalo/pull/37 and + https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html for details. + +* **BREAKING:** The `collections` cargo feature is no longer on by default. You + must explicitly turn it on if you intend to use the `bumpalo::collections` + module. + +* `Bump::reset` will now retain only the last allocated chunk (the biggest), + rather than only the first allocated chunk (the smallest). This should enable + `Bump` to better adapt to workload sizes and quickly reach a steady state + where new chunks are not requested from the global allocator. + +### Removed + +* The `Bump::each_allocated_chunk` method is removed in favor of + `Bump::iter_allocated_chunks`. Note that its safety requirements for reading + from the allocated chunks are slightly different from the old + `each_allocated_chunk`: only up to 16-byte alignment is supported now. If you + allocate anything with greater alignment than that into the bump arena, there + might be uninitialized padding inserted in the chunks, and therefore it is no + longer safe to read them via `MaybeUninit::assume_init`. See also the note + about bump direction in the "changed" section; if you're iterating chunks, + you're likely affected by that change! + +* The `std` cargo feature has been removed, since this crate is now always + no-std. + +## Fixed + +* Fixed a bug involving potential integer overflows with large requested + allocation sizes. + +-------------------------------------------------------------------------------- + +# 2.6.0 + +Released 2019-08-19. + +* Implement `Send` for `Bump`. + +-------------------------------------------------------------------------------- + +# 2.5.0 + +Released 2019-07-01. + +* Add `alloc_slice_copy` and `alloc_slice_clone` methods that allocate space for + slices and either copy (with bound `T: Copy`) or clone (with bound `T: Clone`) + the provided slice's data into the newly allocated space. + +-------------------------------------------------------------------------------- + +# 2.4.3 + +Released 2019-05-20. + +* Fixed a bug where chunks were always deallocated with the default chunk + layout, not the layout that the chunk was actually allocated with (i.e. if we + started growing larger chunks with larger layouts, we would deallocate those + chunks with an incorrect layout). + +-------------------------------------------------------------------------------- + +# 2.4.2 + +Released 2019-05-17. + +* Added an implementation `Default` for `Bump`. +* Made it so that if bump allocation within a chunk overflows, we still try to + allocate a new chunk to bump out of for the requested allocation. This can + avoid some OOMs in scenarios where the chunk we are currently allocating out + of is very near the high end of the address space, and there is still + available address space lower down for new chunks. + +-------------------------------------------------------------------------------- + +# 2.4.1 + +Released 2019-04-19. + +* Added readme metadata to Cargo.toml so it shows up on crates.io + +-------------------------------------------------------------------------------- + +# 2.4.0 + +Released 2019-04-19. + +* Added support for `realloc`ing in-place when the pointer being `realloc`ed is + the last allocation made from the bump arena. This should speed up various + `String`, `Vec`, and `format!` operations in many cases. + +-------------------------------------------------------------------------------- + +# 2.3.0 + +Released 2019-03-26. + +* Add the `alloc_with` method, that (usually) avoids stack-allocating the + allocated value and then moving it into the bump arena. This avoids potential + stack overflows in release mode when allocating very large objects, and also + some `memcpy` calls. This is similar to the `copyless` crate. Read [the + `alloc_with` doc comments][alloc-with-doc-comments] and [the original issue + proposing this API][issue-proposing-alloc-with] for more. + +[alloc-with-doc-comments]: https://github.com/fitzgen/bumpalo/blob/9f47aee8a6839ba65c073b9ad5372aacbbd02352/src/lib.rs#L436-L475 +[issue-proposing-alloc-with]: https://github.com/fitzgen/bumpalo/issues/10 + +-------------------------------------------------------------------------------- + +# 2.2.2 + +Released 2019-03-18. + +* Fix a regression from 2.2.1 where chunks were not always aligned to the chunk + footer's alignment. + +-------------------------------------------------------------------------------- + +# 2.2.1 + +Released 2019-03-18. + +* Fix a regression in 2.2.0 where newly allocated bump chunks could fail to have + capacity for a large requested bump allocation in some corner cases. + +-------------------------------------------------------------------------------- + +# 2.2.0 + +Released 2019-03-15. + +* Chunks in an arena now start out small, and double in size as more chunks are + requested. + +-------------------------------------------------------------------------------- + +# 2.1.0 + +Released 2019-02-12. + +* Added the `into_bump_slice` method on `bumpalo::collections::Vec`. + +-------------------------------------------------------------------------------- + +# 2.0.0 + +Released 2019-02-11. + +* Removed the `BumpAllocSafe` trait. +* Correctly detect overflows from large allocations and panic. + +-------------------------------------------------------------------------------- + +# 1.2.0 + +Released 2019-01-15. + +* Fixed an overly-aggressive `debug_assert!` that had false positives. +* Ported to Rust 2018 edition. + +-------------------------------------------------------------------------------- + +# 1.1.0 + +Released 2018-11-28. + +* Added the `collections` module, which contains ports of `std`'s collection + types that are compatible with backing their storage in `Bump` arenas. +* Lifted the limits on size and alignment of allocations. + +-------------------------------------------------------------------------------- + +# 1.0.2 + +-------------------------------------------------------------------------------- + +# 1.0.1 + +-------------------------------------------------------------------------------- + +# 1.0.0 diff --git a/deps/crates/vendor/bumpalo/Cargo.lock b/deps/crates/vendor/bumpalo/Cargo.lock new file mode 100644 index 00000000000000..c4620635aa8b39 --- /dev/null +++ b/deps/crates/vendor/bumpalo/Cargo.lock @@ -0,0 +1,697 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e" + +[[package]] +name = "allocator-api2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c880a97d28a3681c0267bd29cff89621202715b065127cd445fa0f0fe0aa2880" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blink-alloc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce4c15bad517bc0fb4a44523adf470e2c3eb3a365769327acdba849948ea3705" +dependencies = [ + "allocator-api2 0.4.0", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "bumpalo" +version = "3.20.2" +dependencies = [ + "allocator-api2 0.2.14", + "blink-alloc", + "criterion", + "quickcheck", + "rand", + "rayon", + "rayon-core", + "serde", + "serde_json", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa 0.4.8", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "plotters" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger", + "log", + "rand", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa 1.0.3", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo 3.11.0", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.99", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.99", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + +[[package]] +name = "web-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/deps/crates/vendor/bumpalo/Cargo.toml b/deps/crates/vendor/bumpalo/Cargo.toml new file mode 100644 index 00000000000000..94cc1c6e42f0e7 --- /dev/null +++ b/deps/crates/vendor/bumpalo/Cargo.toml @@ -0,0 +1,94 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71.1" +name = "bumpalo" +version = "3.20.2" +authors = ["Nick Fitzgerald "] +build = false +exclude = [ + "/.github/*", + "/benches", + "/tests", + "valgrind.supp", + "bumpalo.png", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A fast bump allocation arena for Rust." +documentation = "https://docs.rs/bumpalo" +readme = "README.md" +categories = [ + "memory-management", + "rust-patterns", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/fitzgen/bumpalo" + +[package.metadata.docs.rs] +all-features = true + +[features] +allocator_api = [] +bench_allocator_api = [ + "allocator_api", + "blink-alloc/nightly", +] +boxed = [] +collections = [] +default = [] +serde = ["dep:serde"] +std = [] + +[lib] +name = "bumpalo" +path = "src/lib.rs" +bench = false + +[dependencies.allocator-api2] +version = "0.2.8" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.171" +optional = true + +[dev-dependencies.blink-alloc] +version = "=0.4.0" + +[dev-dependencies.criterion] +version = "0.3.6" + +[dev-dependencies.quickcheck] +version = "=1.0.3" + +[dev-dependencies.rand] +version = "0.8.5" + +[dev-dependencies.rayon] +version = "=1.10.0" + +[dev-dependencies.rayon-core] +version = "=1.12.1" + +[dev-dependencies.serde] +version = "1.0.197" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1.0.115" diff --git a/deps/crates/vendor/bumpalo/Cargo.toml.orig b/deps/crates/vendor/bumpalo/Cargo.toml.orig new file mode 100644 index 00000000000000..61852984f0c2c0 --- /dev/null +++ b/deps/crates/vendor/bumpalo/Cargo.toml.orig @@ -0,0 +1,72 @@ +[package] +authors = ["Nick Fitzgerald "] +categories = ["memory-management", "rust-patterns", "no-std"] +description = "A fast bump allocation arena for Rust." +documentation = "https://docs.rs/bumpalo" +edition = "2021" +exclude = ["/.github/*", "/benches", "/tests", "valgrind.supp", "bumpalo.png"] +license = "MIT OR Apache-2.0" +name = "bumpalo" +readme = "README.md" +repository = "https://github.com/fitzgen/bumpalo" +rust-version = "1.71.1" +version = "3.20.2" + +[package.metadata.docs.rs] +all-features = true + +[lib] +path = "src/lib.rs" +bench = false + +[[bench]] +name = "benches" +path = "benches/benches.rs" +harness = false +required-features = ["collections"] + +[[bench]] +name = "allocator_api" +path = "benches/allocator_api.rs" +harness = false +required-features = ["bench_allocator_api"] + +[[test]] +name = "try_alloc" +path = "tests/try_alloc.rs" +harness = false + +[dependencies] +# This dependency provides a version of the unstable nightly Rust `Allocator` +# trait on stable Rust. Enabling this feature means that `bumpalo` will +# implement its `Allocator` trait. +allocator-api2 = { version = "0.2.8", default-features = false, optional = true } + +# This dependency is here to allow integration with Serde, if the `serde` feature is enabled +serde = { version = "1.0.171", optional = true } + +[dev-dependencies] +quickcheck = "=1.0.3" +criterion = "0.3.6" +rand = "0.8.5" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" +blink-alloc = { version = "=0.4.0" } + +# Make sure that criterion pulls in a rayon that supports our MSRV. +rayon = { version = "=1.10.0" } +rayon-core = { version = "=1.12.1" } + +[features] +default = [] +collections = [] +boxed = [] +allocator_api = [] +std = [] +serde = ["dep:serde"] + +# Feature for bumpalo's internal development only. Do not use! +bench_allocator_api = ["allocator_api", "blink-alloc/nightly"] + +# [profile.bench] +# debug = true diff --git a/deps/crates/vendor/bumpalo/LICENSE-APACHE b/deps/crates/vendor/bumpalo/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/bumpalo/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/bumpalo/LICENSE-MIT b/deps/crates/vendor/bumpalo/LICENSE-MIT new file mode 100644 index 00000000000000..bac6fb98de263c --- /dev/null +++ b/deps/crates/vendor/bumpalo/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2019 Nick Fitzgerald + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/bumpalo/README.md b/deps/crates/vendor/bumpalo/README.md new file mode 100644 index 00000000000000..9c80b3037eef54 --- /dev/null +++ b/deps/crates/vendor/bumpalo/README.md @@ -0,0 +1,261 @@ +# `bumpalo` + +**A fast bump allocation arena for Rust.** + +[![](https://docs.rs/bumpalo/badge.svg)](https://docs.rs/bumpalo/) +[![](https://img.shields.io/crates/v/bumpalo.svg)](https://crates.io/crates/bumpalo) +[![](https://img.shields.io/crates/d/bumpalo.svg)](https://crates.io/crates/bumpalo) +[![Build Status](https://github.com/fitzgen/bumpalo/workflows/Rust/badge.svg)](https://github.com/fitzgen/bumpalo/actions?query=workflow%3ARust) + +![](https://github.com/fitzgen/bumpalo/raw/main/bumpalo.png) + +### Bump Allocation + +Bump allocation is a fast, but limited approach to allocation. We have a chunk +of memory, and we maintain a pointer within that memory. Whenever we allocate an +object, we do a quick check that we have enough capacity left in our chunk to +allocate the object and then update the pointer by the object's size. *That's +it!* + +The disadvantage of bump allocation is that there is no general way to +deallocate individual objects or reclaim the memory region for a +no-longer-in-use object. + +These trade offs make bump allocation well-suited for *phase-oriented* +allocations. That is, a group of objects that will all be allocated during the +same program phase, used, and then can all be deallocated together as a group. + +### Deallocation en Masse, but no `Drop` + +To deallocate all the objects in the arena at once, we can simply reset the bump +pointer back to the start of the arena's memory chunk. This makes mass +deallocation *extremely* fast, but allocated objects' [`Drop`] implementations are +not invoked. + +> **However:** [`bumpalo::boxed::Box`][box] can be used to wrap +> `T` values allocated in the `Bump` arena, and calls `T`'s `Drop` +> implementation when the `Box` wrapper goes out of scope. This is similar to +> how [`std::boxed::Box`] works, except without deallocating its backing memory. + +[`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html +[box]: https://docs.rs/bumpalo/latest/bumpalo/boxed/struct.Box.html +[`std::boxed::Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html + +### What happens when the memory chunk is full? + +This implementation will allocate a new memory chunk from the global allocator +and then start bump allocating into this new memory chunk. + +### Example + +```rust +use bumpalo::Bump; + +struct Doggo { + cuteness: u64, + age: u8, + scritches_required: bool, +} + +// Create a new arena to bump allocate into. +let bump = Bump::new(); + +// Allocate values into the arena. +let scooter = bump.alloc(Doggo { + cuteness: u64::MAX, + age: 8, + scritches_required: true, +}); + +// Exclusive, mutable references to the just-allocated value are returned. +assert!(scooter.scritches_required); +scooter.age += 1; +``` + +### Collections + +When the `"collections"` cargo feature is enabled, a fork of some of the `std` +library's collections are available in the [`collections`] module. These +collection types are modified to allocate their space inside `bumpalo::Bump` +arenas. + +[`collections`]: https://docs.rs/bumpalo/latest/bumpalo/collections/index.html + +```rust +#[cfg(feature = "collections")] +{ + use bumpalo::{Bump, collections::Vec}; + + // Create a new bump arena. + let bump = Bump::new(); + + // Create a vector of integers whose storage is backed by the bump arena. The + // vector cannot outlive its backing arena, and this property is enforced with + // Rust's lifetime rules. + let mut v = Vec::new_in(&bump); + + // Push a bunch of integers onto `v`! + for i in 0..100 { + v.push(i); + } +} +``` + +Eventually [all `std` collection types will be parameterized by an +allocator](https://github.com/rust-lang/rust/issues/42774) and we can remove +this `collections` module and use the `std` versions. + +For unstable, nightly-only support for custom allocators in `std`, see the +`allocator_api` section below. + +### `bumpalo::boxed::Box` + +When the `"boxed"` cargo feature is enabled, a fork of `std::boxed::Box` +is available in the `boxed` module. This `Box` type is modified to allocate its +space inside `bumpalo::Bump` arenas. + +**A `Box` runs `T`'s drop implementation when the `Box` is dropped.** You +can use this to work around the fact that `Bump` does not drop values allocated +in its space itself. + +```rust +#[cfg(feature = "boxed")] +{ + use bumpalo::{Bump, boxed::Box}; + use std::sync::atomic::{AtomicUsize, Ordering}; + + static NUM_DROPPED: AtomicUsize = AtomicUsize::new(0); + + struct CountDrops; + + impl Drop for CountDrops { + fn drop(&mut self) { + NUM_DROPPED.fetch_add(1, Ordering::SeqCst); + } + } + + // Create a new bump arena. + let bump = Bump::new(); + + // Create a `CountDrops` inside the bump arena. + let mut c = Box::new_in(CountDrops, &bump); + + // No `CountDrops` have been dropped yet. + assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 0); + + // Drop our `Box`. + drop(c); + + // Its `Drop` implementation was run, and so `NUM_DROPS` has been + // incremented. + assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1); +} +``` + +#### Serde + +Adding the `serde` feature flag will enable transparent serialization of `Vec`s, `String`s +and boxed values. + +```toml +[dependencies] +bumpalo = { version = "3.18", features = ["collections", "boxed", "serde"] } +``` + +```rust,ignore +use bumpalo::{Bump, boxed::Box, collections::Vec}; + +// Create a new bump arena. +let bump = Bump::new(); + +// Create a `Box` +let box = Box::new_in("hello", &bump); + +// Serialize with serde_json +assert_eq!(serde_json::to_string(&box).unwrap(), "\"hello\""); + +// Create a `Vec` +let vec = Vec::new_in( &bump); +vec.push(1); +vec.push(2); + +// Serialize with serde_json +assert_eq!(serde_json::to_string(&vec).unwrap(), "[1, 2]"); +``` + +### `#![no_std]` Support + +Bumpalo is a `no_std` crate by default. It depends only on the `alloc` and `core` crates. + +### `std` Support + +You can optionally decide to enable the `std` feature in order to enable some +std only trait implementations for some collections: + +* `std::io::Write` for `Vec<'bump, u8>` + +### Thread support + +The `Bump` is `!Sync`, which makes it hard to use in certain situations around +threads ‒ for example in `rayon`. + +The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a +pool of `Bump` allocators for use in such situations. + +### Nightly Rust `allocator_api` Support + +The unstable, nightly-only Rust `allocator_api` feature defines an [`Allocator`] +trait and exposes custom allocators for `std` types. Bumpalo has a matching +`allocator_api` cargo feature to enable implementing `Allocator` and using +`Bump` with `std` collections. Note that, as `feature(allocator_api)` is +unstable and only in nightly Rust, Bumpalo's matching `allocator_api` cargo +feature should be considered unstable, and will not follow the semver +conventions that the rest of the crate does. + +First, enable the `allocator_api` feature in your `Cargo.toml`: + +```toml +[dependencies] +bumpalo = { version = "3", features = ["allocator_api"] } +``` + +Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or +`src/main.rs`: + +```rust,ignore +#![feature(allocator_api)] +``` + +Finally, use `std` collections with `Bump`, so that their internal heap +allocations are made within the given bump arena: + +```rust,ignore +use bumpalo::Bump; + +// Create a new bump arena. +let bump = Bump::new(); + +// Create a `Vec` whose elements are allocated within the bump arena. +let mut v = Vec::new_in(&bump); +v.push(0); +v.push(1); +v.push(2); +``` + +[`Allocator`]: https://doc.rust-lang.org/std/alloc/trait.Allocator.html + +### Using the `Allocator` API on Stable Rust + +You can enable the `allocator-api2` Cargo feature and `bumpalo` will use [the +`allocator-api2` crate](https://crates.io/crates/allocator-api2) to implement +the unstable nightly`Allocator` API on stable Rust. This means that +`bumpalo::Bump` will be usable with any collection that is generic over +`allocator_api2::Allocator`. + +### Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust **1.71.1** and up. It might +compile with older versions but that may change in any new patch release. + +We reserve the right to increment the MSRV on minor releases, however we will +strive to only do it deliberately and for good reasons. diff --git a/deps/crates/vendor/bumpalo/src/alloc.rs b/deps/crates/vendor/bumpalo/src/alloc.rs new file mode 100644 index 00000000000000..6947e2a6cf59a2 --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/alloc.rs @@ -0,0 +1,794 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unstable_name_collisions)] +#![allow(dead_code)] +#![allow(deprecated)] + +//! Memory allocation APIs + +use core::cmp; +use core::fmt; +use core::mem; +use core::ptr::{self, NonNull}; +use core::usize; + +pub use core::alloc::{Layout, LayoutErr}; + +fn new_layout_err() -> LayoutErr { + Layout::from_size_align(1, 3).unwrap_err() +} + +pub fn handle_alloc_error(layout: Layout) -> ! { + panic!("encountered allocation error: {:?}", layout) +} + +pub trait UnstableLayoutMethods { + fn padding_needed_for(&self, align: usize) -> usize; + fn repeat(&self, n: usize) -> Result<(Layout, usize), LayoutErr>; + fn array(n: usize) -> Result; +} + +impl UnstableLayoutMethods for Layout { + fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask with `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + len_rounded_up.wrapping_sub(len) + } + + fn repeat(&self, n: usize) -> Result<(Layout, usize), LayoutErr> { + let padded_size = self + .size() + .checked_add(self.padding_needed_for(self.align())) + .ok_or_else(new_layout_err)?; + let alloc_size = padded_size.checked_mul(n).ok_or_else(new_layout_err)?; + + unsafe { + // self.align is already known to be valid and alloc_size has been + // padded already. + Ok(( + Layout::from_size_align_unchecked(alloc_size, self.align()), + padded_size, + )) + } + } + + fn array(n: usize) -> Result { + Layout::new::().repeat(n).map(|(k, offs)| { + debug_assert!(offs == mem::size_of::()); + k + }) + } +} + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +// #[unstable(feature = "allocator_api", issue = "32838")] +#[derive(Debug)] +pub struct Excess(pub NonNull, pub usize); + +fn size_align() -> (usize, usize) { + (mem::size_of::(), mem::align_of::()) +} + +/// The `AllocErr` error indicates an allocation failure +/// that may be due to resource exhaustion or to +/// something wrong when combining the given input arguments with this +/// allocator. +// #[unstable(feature = "allocator_api", issue = "32838")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AllocErr; + +// (we need this for downstream impl of trait Error) +// #[unstable(feature = "allocator_api", issue = "32838")] +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("memory allocation failed") + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +// #[unstable(feature = "allocator_api", issue = "32838")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +// #[unstable(feature = "allocator_api", issue = "32838")] +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +// #[unstable(feature = "allocator_api", issue = "32838")] +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. +// #[unstable(feature = "allocator_api", issue = "32838")] +pub unsafe trait Alloc { + // (Note: some existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. + // However in jemalloc for example, + // `mallocx(0)` is documented as undefined behavior.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// a new layout with `layout`’s alignment and a size given + /// by `new_size`. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit the new layout. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_size` + /// argument need not fit it.) + /// + /// * `new_size` must be greater than zero. + /// + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if the new layout + /// does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn realloc( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { + let old_size = layout.size(); + + if new_size >= old_size { + if let Ok(()) = self.grow_in_place(ptr, layout, new_size) { + return Ok(ptr); + } + } else if new_size < old_size { + if let Ok(()) = self.shrink_in_place(ptr, layout, new_size) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p.as_ptr(), 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn realloc_excess( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_size) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_size`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_size`, and thus can + /// be used to carry data of a layout of that size and same alignment as + /// `layout`. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_size` argument need not fit it, + /// + /// * `new_size` must not be less than `layout.size()`, + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` + /// function; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_size >= layout.size()); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_size <= u { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_size`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_size` argument need not fit it, + /// + /// * `new_size` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` + /// function; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_size <= layout.size()); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_size { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + fn alloc_one(&mut self) -> Result, AllocErr> + where + Self: Sized, + { + let k = Layout::new::(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| p.cast()) } + } else { + Err(AllocErr) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one(&mut self, ptr: NonNull) + where + Self: Sized, + { + let k = Layout::new::(); + if k.size() > 0 { + self.dealloc(ptr.cast(), k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + where + Self: Sized, + { + match Layout::array::(n) { + Ok(layout) if layout.size() > 0 => unsafe { self.alloc(layout).map(|p| p.cast()) }, + _ => Err(AllocErr), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn realloc_array( + &mut self, + ptr: NonNull, + n_old: usize, + n_new: usize, + ) -> Result, AllocErr> + where + Self: Sized, + { + match (Layout::array::(n_old), Layout::array::(n_new)) { + (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { + debug_assert!(k_old.align() == k_new.align()); + self.realloc(ptr.cast(), *k_old, k_new.size()) + .map(NonNull::cast) + } + _ => Err(AllocErr), + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> + where + Self: Sized, + { + match Layout::array::(n) { + Ok(k) if k.size() > 0 => { + self.dealloc(ptr.cast(), k); + Ok(()) + } + _ => Err(AllocErr), + } + } +} diff --git a/deps/crates/vendor/bumpalo/src/boxed.rs b/deps/crates/vendor/bumpalo/src/boxed.rs new file mode 100644 index 00000000000000..40f8108a7700ce --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/boxed.rs @@ -0,0 +1,747 @@ +//! A pointer type for bump allocation. +//! +//! [`Box<'a, T>`] provides the simplest form of +//! bump allocation in `bumpalo`. Boxes provide ownership for this allocation, and +//! drop their contents when they go out of scope. +//! +//! # Examples +//! +//! Move a value from the stack to the heap by creating a [`Box`]: +//! +//! ``` +//! use bumpalo::{Bump, boxed::Box}; +//! +//! let b = Bump::new(); +//! +//! let val: u8 = 5; +//! let boxed: Box = Box::new_in(val, &b); +//! ``` +//! +//! Move a value from a [`Box`] back to the stack by [dereferencing]: +//! +//! ``` +//! use bumpalo::{Bump, boxed::Box}; +//! +//! let b = Bump::new(); +//! +//! let boxed: Box = Box::new_in(5, &b); +//! let val: u8 = *boxed; +//! ``` +//! +//! Running [`Drop`] implementations on bump-allocated values: +//! +//! ``` +//! use bumpalo::{Bump, boxed::Box}; +//! use std::sync::atomic::{AtomicUsize, Ordering}; +//! +//! static NUM_DROPPED: AtomicUsize = AtomicUsize::new(0); +//! +//! struct CountDrops; +//! +//! impl Drop for CountDrops { +//! fn drop(&mut self) { +//! NUM_DROPPED.fetch_add(1, Ordering::SeqCst); +//! } +//! } +//! +//! // Create a new bump arena. +//! let bump = Bump::new(); +//! +//! // Create a `CountDrops` inside the bump arena. +//! let mut c = Box::new_in(CountDrops, &bump); +//! +//! // No `CountDrops` have been dropped yet. +//! assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 0); +//! +//! // Drop our `Box`. +//! drop(c); +//! +//! // Its `Drop` implementation was run, and so `NUM_DROPS` has been incremented. +//! assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1); +//! ``` +//! +//! Creating a recursive data structure: +//! +//! ``` +//! use bumpalo::{Bump, boxed::Box}; +//! +//! let b = Bump::new(); +//! +//! #[derive(Debug)] +//! enum List<'a, T> { +//! Cons(T, Box<'a, List<'a, T>>), +//! Nil, +//! } +//! +//! let list: List = List::Cons(1, Box::new_in(List::Cons(2, Box::new_in(List::Nil, &b)), &b)); +//! println!("{:?}", list); +//! ``` +//! +//! This will print `Cons(1, Cons(2, Nil))`. +//! +//! Recursive structures must be boxed, because if the definition of `Cons` +//! looked like this: +//! +//! ```compile_fail,E0072 +//! # enum List { +//! Cons(T, List), +//! # } +//! ``` +//! +//! It wouldn't work. This is because the size of a `List` depends on how many +//! elements are in the list, and so we don't know how much memory to allocate +//! for a `Cons`. By introducing a [`Box<'a, T>`], which has a defined size, we know how +//! big `Cons` needs to be. +//! +//! # Memory layout +//! +//! For non-zero-sized values, a [`Box`] will use the provided [`Bump`] allocator for +//! its allocation. It is valid to convert both ways between a [`Box`] and a +//! pointer allocated with the [`Bump`] allocator, given that the +//! [`Layout`] used with the allocator is correct for the type. More precisely, +//! a `value: *mut T` that has been allocated with the [`Bump`] allocator +//! with `Layout::for_value(&*value)` may be converted into a box using +//! [`Box::::from_raw(value)`]. Conversely, the memory backing a `value: *mut +//! T` obtained from [`Box::::into_raw`] will be deallocated by the +//! [`Bump`] allocator with [`Layout::for_value(&*value)`]. +//! +//! Note that roundtrip `Box::from_raw(Box::into_raw(b))` looses the lifetime bound to the +//! [`Bump`] immutable borrow which guarantees that the allocator will not be reset +//! and memory will not be freed. +//! +//! [dereferencing]: https://doc.rust-lang.org/std/ops/trait.Deref.html +//! [`Box`]: struct.Box.html +//! [`Box<'a, T>`]: struct.Box.html +//! [`Box::::from_raw(value)`]: struct.Box.html#method.from_raw +//! [`Box::::into_raw`]: struct.Box.html#method.into_raw +//! [`Bump`]: ../struct.Bump.html +//! [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html +//! [`Layout`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html +//! [`Layout::for_value(&*value)`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value + +use { + crate::Bump, + core::{ + any::Any, + borrow, + cmp::Ordering, + convert::TryFrom, + future::Future, + hash::{Hash, Hasher}, + iter::FusedIterator, + marker::PhantomData, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + pin::Pin, + ptr::NonNull, + task::{Context, Poll}, + }, + core_alloc::fmt, +}; + +/// An owned pointer to a bump-allocated `T` value, that runs `Drop` +/// implementations. +/// +/// See the [module-level documentation][crate::boxed] for more details. +#[repr(transparent)] +pub struct Box<'a, T: ?Sized>(NonNull, PhantomData<&'a T>); + +impl<'a, T> Box<'a, T> { + /// Allocates memory on the heap and then places `x` into it. + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let five = Box::new_in(5, &b); + /// ``` + #[inline(always)] + pub fn new_in(x: T, a: &'a Bump) -> Box<'a, T> { + Box(a.alloc(x).into(), PhantomData) + } + + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `x` will be pinned in memory and unable to be moved. + #[inline(always)] + pub fn pin_in(x: T, a: &'a Bump) -> Pin> { + Box(a.alloc(x).into(), PhantomData).into() + } + + /// Consumes the `Box`, returning the wrapped value. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let hello = Box::new_in("hello".to_owned(), &b); + /// assert_eq!(Box::into_inner(hello), "hello"); + /// ``` + pub fn into_inner(b: Box<'a, T>) -> T { + // `Box::into_raw` returns a pointer that is properly aligned and non-null. + // The underlying `Bump` only frees the memory, but won't call the destructor. + unsafe { core::ptr::read(Box::into_raw(b)) } + } +} + +impl<'a, T: ?Sized> Box<'a, T> { + /// Constructs a box from a raw pointer. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the memory layout used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw`]: + /// ``` + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let x = Box::new_in(5, &b); + /// let ptr = Box::into_raw(x); + /// let x = unsafe { Box::from_raw(ptr) }; // Note that new `x`'s lifetime is unbound. It must be bound to the `b` immutable borrow before `b` is reset. + /// ``` + /// Manually create a `Box` from scratch by using the bump allocator: + /// ``` + /// use std::alloc::{alloc, Layout}; + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// unsafe { + /// let ptr = b.alloc_layout(Layout::new::()).as_ptr() as *mut i32; + /// *ptr = 5; + /// let x = Box::from_raw(ptr); // Note that `x`'s lifetime is unbound. It must be bound to the `b` immutable borrow before `b` is reset. + /// } + /// ``` + #[inline] + pub unsafe fn from_raw(raw: *mut T) -> Self { + // Safety: part of this function's unsafe contract is that the raw + // pointer be non-null. + Box(unsafe { NonNull::new_unchecked(raw) }, PhantomData) + } + + /// Consumes the `Box`, returning a wrapped raw pointer. + /// + /// The pointer will be properly aligned and non-null. + /// + /// After calling this function, the caller is responsible for the + /// value previously managed by the `Box`. In particular, the + /// caller should properly destroy `T`. The easiest way to + /// do this is to convert the raw pointer back into a `Box` with the + /// [`Box::from_raw`] function, allowing the `Box` destructor to perform + /// the cleanup. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// + /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] + /// for automatic cleanup: + /// ``` + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let x = Box::new_in(String::from("Hello"), &b); + /// let ptr = Box::into_raw(x); + /// let x = unsafe { Box::from_raw(ptr) }; // Note that new `x`'s lifetime is unbound. It must be bound to the `b` immutable borrow before `b` is reset. + /// ``` + /// Manual cleanup by explicitly running the destructor: + /// ``` + /// use std::ptr; + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let mut x = Box::new_in(String::from("Hello"), &b); + /// let p = Box::into_raw(x); + /// unsafe { + /// ptr::drop_in_place(p); + /// } + /// ``` + #[inline] + pub fn into_raw(b: Box<'a, T>) -> *mut T { + let b = ManuallyDrop::new(b); + b.0.as_ptr() + } + + /// Consumes and leaks the `Box`, returning a mutable reference, + /// `&'a mut T`. Note that the type `T` must outlive the chosen lifetime + /// `'a`. If the type has only static references, or none at all, then this + /// may be chosen to be `'static`. + /// + /// This function is mainly useful for data that lives for the remainder of + /// the program's life. Dropping the returned reference will cause a memory + /// leak. If this is not acceptable, the reference should first be wrapped + /// with the [`Box::from_raw`] function producing a `Box`. This `Box` can + /// then be dropped which will properly destroy `T` and release the + /// allocated memory. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::leak(b)` instead of `b.leak()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// + /// Simple usage: + /// + /// ``` + /// use bumpalo::{Bump, boxed::Box}; + /// + /// let b = Bump::new(); + /// + /// let x = Box::new_in(41, &b); + /// let reference: &mut usize = Box::leak(x); + /// *reference += 1; + /// assert_eq!(*reference, 42); + /// ``` + /// + ///``` + /// # #[cfg(feature = "collections")] + /// # { + /// use bumpalo::{Bump, boxed::Box, vec}; + /// + /// let b = Bump::new(); + /// + /// let x = vec![in &b; 1, 2, 3].into_boxed_slice(); + /// let reference = Box::leak(x); + /// reference[0] = 4; + /// assert_eq!(*reference, [4, 2, 3]); + /// # } + ///``` + #[inline] + pub fn leak(b: Box<'a, T>) -> &'a mut T { + unsafe { &mut *Box::into_raw(b) } + } +} + +impl<'a, T: ?Sized> Drop for Box<'a, T> { + fn drop(&mut self) { + unsafe { + // `Box` owns value of `T`, but not memory behind it. + core::ptr::drop_in_place(self.0.as_ptr()); + } + } +} + +impl<'a, T> Default for Box<'a, [T]> { + fn default() -> Box<'a, [T]> { + // It should be OK to `drop_in_place` empty slice of anything. + Box( + NonNull::new(&mut []).expect("Reference to empty list is NonNull"), + PhantomData, + ) + } +} + +impl<'a> Default for Box<'a, str> { + fn default() -> Box<'a, str> { + // Empty slice is valid string. + // It should be OK to `drop_in_place` empty str. + unsafe { Box::from_raw(Box::into_raw(Box::<[u8]>::default()) as *mut str) } + } +} + +impl<'a, 'b, T: ?Sized + PartialEq> PartialEq> for Box<'a, T> { + #[inline] + fn eq(&self, other: &Box<'b, T>) -> bool { + PartialEq::eq(&**self, &**other) + } + #[inline] + fn ne(&self, other: &Box<'b, T>) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +impl<'a, 'b, T: ?Sized + PartialOrd> PartialOrd> for Box<'a, T> { + #[inline] + fn partial_cmp(&self, other: &Box<'b, T>) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } + #[inline] + fn lt(&self, other: &Box<'b, T>) -> bool { + PartialOrd::lt(&**self, &**other) + } + #[inline] + fn le(&self, other: &Box<'b, T>) -> bool { + PartialOrd::le(&**self, &**other) + } + #[inline] + fn ge(&self, other: &Box<'b, T>) -> bool { + PartialOrd::ge(&**self, &**other) + } + #[inline] + fn gt(&self, other: &Box<'b, T>) -> bool { + PartialOrd::gt(&**self, &**other) + } +} + +impl<'a, T: ?Sized + Ord> Ord for Box<'a, T> { + #[inline] + fn cmp(&self, other: &Box<'a, T>) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl<'a, T: ?Sized + Eq> Eq for Box<'a, T> {} + +impl<'a, T: ?Sized + Hash> Hash for Box<'a, T> { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +impl<'a, T: ?Sized + Hasher> Hasher for Box<'a, T> { + fn finish(&self) -> u64 { + (**self).finish() + } + fn write(&mut self, bytes: &[u8]) { + (**self).write(bytes) + } + fn write_u8(&mut self, i: u8) { + (**self).write_u8(i) + } + fn write_u16(&mut self, i: u16) { + (**self).write_u16(i) + } + fn write_u32(&mut self, i: u32) { + (**self).write_u32(i) + } + fn write_u64(&mut self, i: u64) { + (**self).write_u64(i) + } + fn write_u128(&mut self, i: u128) { + (**self).write_u128(i) + } + fn write_usize(&mut self, i: usize) { + (**self).write_usize(i) + } + fn write_i8(&mut self, i: i8) { + (**self).write_i8(i) + } + fn write_i16(&mut self, i: i16) { + (**self).write_i16(i) + } + fn write_i32(&mut self, i: i32) { + (**self).write_i32(i) + } + fn write_i64(&mut self, i: i64) { + (**self).write_i64(i) + } + fn write_i128(&mut self, i: i128) { + (**self).write_i128(i) + } + fn write_isize(&mut self, i: isize) { + (**self).write_isize(i) + } +} + +impl<'a, T: ?Sized> From> for Pin> { + /// Converts a `Box` into a `Pin>`. + /// + /// This conversion does not allocate on the heap and happens in place. + fn from(boxed: Box<'a, T>) -> Self { + // It's not possible to move or replace the insides of a `Pin>` + // when `T: !Unpin`, so it's safe to pin it directly without any + // additional requirements. + unsafe { Pin::new_unchecked(boxed) } + } +} + +impl<'a> Box<'a, dyn Any> { + #[inline] + /// Attempt to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + pub fn downcast(self) -> Result, Box<'a, dyn Any>> { + if self.is::() { + unsafe { + let raw: *mut dyn Any = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +impl<'a> Box<'a, dyn Any + Send> { + #[inline] + /// Attempt to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + pub fn downcast(self) -> Result, Box<'a, dyn Any + Send>> { + if self.is::() { + unsafe { + let raw: *mut (dyn Any + Send) = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +impl<'a, T: fmt::Display + ?Sized> fmt::Display for Box<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Box<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T: ?Sized> fmt::Pointer for Box<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // It's not possible to extract the inner Uniq directly from the Box, + // instead we cast it to a *const which aliases the Unique + let ptr: *const T = &**self; + fmt::Pointer::fmt(&ptr, f) + } +} + +/// This function tests that box isn't contravariant. +/// +/// ```compile_fail +/// fn _box_is_not_contravariant<'sub, 'sup :'sub>( +/// a: Box<&'sup u32>, +/// b: Box<&'sub u32>, +/// f: impl Fn(Box<&'sup u32>), +/// ) { +/// f(a); +/// f(b); +/// } +/// ``` +/// +/// This function tests that `Box` isn't Send when the inner type isn't Send. +/// ```compile_fail +/// fn _requires_send(_value: T) {} +/// fn _box_inherets_send_not_send(a: Box>) { +/// _requires_send(a); +/// } +/// ``` +/// +/// This function tests that `Box` isn't Sync when the inner type isn't Sync. +/// ```compile_fail +/// fn _requires_sync(_value: T) {} +/// fn _box_inherets_sync_not_sync(a: Box>) { +/// _requires_sync(a); +/// } +/// ``` +#[cfg(doctest)] +fn _doctest_only() {} + +impl<'a, T: ?Sized> Deref for Box<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + // Safety: Our pointer always points to a valid instance of `T` + // allocated within a `Bump` and the `&self` borrow ensures that there + // are no active exclusive borrows. + unsafe { self.0.as_ref() } + } +} + +impl<'a, T: ?Sized> DerefMut for Box<'a, T> { + fn deref_mut(&mut self) -> &mut T { + // Safety: Our pointer always points to a valid instance of `T` + // allocated within a `Bump` and the `&mut self` borrow ensures that + // there are no other active borrows. + unsafe { self.0.as_mut() } + } +} + +impl<'a, I: Iterator + ?Sized> Iterator for Box<'a, I> { + type Item = I::Item; + fn next(&mut self) -> Option { + (**self).next() + } + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } + fn nth(&mut self, n: usize) -> Option { + (**self).nth(n) + } + fn last(self) -> Option { + #[inline] + fn some(_: Option, x: T) -> Option { + Some(x) + } + self.fold(None, some) + } +} + +impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<'a, I> { + fn next_back(&mut self) -> Option { + (**self).next_back() + } + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } +} +impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<'a, I> { + fn len(&self) -> usize { + (**self).len() + } +} + +impl<'a, I: FusedIterator + ?Sized> FusedIterator for Box<'a, I> {} + +#[cfg(feature = "collections")] +impl<'a, A> Box<'a, [A]> { + /// Creates a value from an iterator. + /// This method is an adapted version of [`FromIterator::from_iter`][from_iter]. + /// It cannot be made as that trait implementation given different signature. + /// + /// [from_iter]: https://doc.rust-lang.org/std/iter/trait.FromIterator.html#tymethod.from_iter + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// use bumpalo::{Bump, boxed::Box, vec}; + /// + /// let b = Bump::new(); + /// + /// let five_fives = std::iter::repeat(5).take(5); + /// let slice = Box::from_iter_in(five_fives, &b); + /// assert_eq!(vec![in &b; 5, 5, 5, 5, 5], &*slice); + /// ``` + pub fn from_iter_in>(iter: T, a: &'a Bump) -> Self { + use crate::collections::Vec; + let mut vec = Vec::new_in(a); + vec.extend(iter); + vec.into_boxed_slice() + } +} + +impl<'a, T: ?Sized> borrow::Borrow for Box<'a, T> { + fn borrow(&self) -> &T { + &**self + } +} + +impl<'a, T: ?Sized> borrow::BorrowMut for Box<'a, T> { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +impl<'a, T: ?Sized> AsRef for Box<'a, T> { + fn as_ref(&self) -> &T { + &**self + } +} + +impl<'a, T: ?Sized> AsMut for Box<'a, T> { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +impl<'a, T: ?Sized> Unpin for Box<'a, T> {} + +// Safety: If T is Send the box is too because Box has exclusive access to its wrapped T. +unsafe impl<'a, T: ?Sized + Send> Send for Box<'a, T> {} + +// Safety: If T is Sync the box is too because Box has exclusive access to its wrapped T. +unsafe impl<'a, T: ?Sized + Sync> Sync for Box<'a, T> {} + +impl<'a, F: ?Sized + Future + Unpin> Future for Box<'a, F> { + type Output = F::Output; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut *self), cx) + } +} + +/// This impl replaces unsize coercion. +impl<'a, T, const N: usize> From> for Box<'a, [T]> { + fn from(arr: Box<'a, [T; N]>) -> Box<'a, [T]> { + let mut arr = ManuallyDrop::new(arr); + let ptr = core::ptr::slice_from_raw_parts_mut(arr.as_mut_ptr(), N); + unsafe { Box::from_raw(ptr) } + } +} + +/// This impl replaces unsize coercion. +impl<'a, T, const N: usize> TryFrom> for Box<'a, [T; N]> { + type Error = Box<'a, [T]>; + fn try_from(slice: Box<'a, [T]>) -> Result, Box<'a, [T]>> { + if slice.len() == N { + let mut slice = ManuallyDrop::new(slice); + let ptr = slice.as_mut_ptr() as *mut [T; N]; + Ok(unsafe { Box::from_raw(ptr) }) + } else { + Err(slice) + } + } +} + +#[cfg(feature = "serde")] +mod serialize { + use super::*; + + use serde::{Serialize, Serializer}; + + impl<'a, T> Serialize for Box<'a, T> + where + T: Serialize, + { + fn serialize(&self, serializer: S) -> Result { + T::serialize(self, serializer) + } + } +} diff --git a/deps/crates/vendor/bumpalo/src/collections/collect_in.rs b/deps/crates/vendor/bumpalo/src/collections/collect_in.rs new file mode 100644 index 00000000000000..3e1adeaeaa12d0 --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/collect_in.rs @@ -0,0 +1,152 @@ +#[cfg(feature = "boxed")] +use crate::boxed::Box; +use crate::collections::{String, Vec}; +use crate::Bump; + +/// A trait for types that support being constructed from an iterator, parameterized by an allocator. +pub trait FromIteratorIn { + /// The allocator type + type Alloc; + + /// Similar to [`FromIterator::from_iter`][from_iter], but with a given allocator. + /// + /// [from_iter]: https://doc.rust-lang.org/std/iter/trait.FromIterator.html#tymethod.from_iter + /// + /// ``` + /// # use bumpalo::collections::{FromIteratorIn, Vec}; + /// # use bumpalo::Bump; + /// # + /// let five_fives = std::iter::repeat(5).take(5); + /// let bump = Bump::new(); + /// + /// let v = Vec::from_iter_in(five_fives, &bump); + /// + /// assert_eq!(v, [5, 5, 5, 5, 5]); + /// ``` + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator; +} + +#[cfg(feature = "boxed")] +impl<'bump, T> FromIteratorIn for Box<'bump, [T]> { + type Alloc = &'bump Bump; + + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator, + { + Box::from_iter_in(iter, alloc) + } +} + +impl<'bump, T> FromIteratorIn for Vec<'bump, T> { + type Alloc = &'bump Bump; + + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator, + { + Vec::from_iter_in(iter, alloc) + } +} + +impl> FromIteratorIn> for Option { + type Alloc = V::Alloc; + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator>, + { + iter.into_iter() + .map(|x| x.ok_or(())) + .collect_in::>(alloc) + .ok() + } +} + +impl> FromIteratorIn> for Result { + type Alloc = V::Alloc; + /// Takes each element in the `Iterator`: if it is an `Err`, no further + /// elements are taken, and the `Err` is returned. Should no `Err` occur, a + /// container with the values of each `Result` is returned. + /// + /// Here is an example which increments every integer in a vector, + /// checking for overflow: + /// + /// ``` + /// # use bumpalo::collections::{FromIteratorIn, CollectIn, Vec, String}; + /// # use bumpalo::Bump; + /// # + /// let bump = Bump::new(); + /// + /// let v = vec![1, 2, u32::MAX]; + /// let res: Result, &'static str> = v.iter().take(2).map(|x: &u32| + /// x.checked_add(1).ok_or("Overflow!") + /// ).collect_in(&bump); + /// assert_eq!(res, Ok(bumpalo::vec![in ≎ 2, 3])); + /// + /// let res: Result, &'static str> = v.iter().map(|x: &u32| + /// x.checked_add(1).ok_or("Overflow!") + /// ).collect_in(&bump); + /// assert_eq!(res, Err("Overflow!")); + /// ``` + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator>, + { + let mut iter = iter.into_iter(); + let mut error = None; + let container = core::iter::from_fn(|| match iter.next() { + Some(Ok(x)) => Some(x), + Some(Err(e)) => { + error = Some(e); + None + } + None => None, + }) + .collect_in(alloc); + + match error { + Some(e) => Err(e), + None => Ok(container), + } + } +} + +impl<'bump> FromIteratorIn for String<'bump> { + type Alloc = &'bump Bump; + + fn from_iter_in(iter: I, alloc: Self::Alloc) -> Self + where + I: IntoIterator, + { + String::from_iter_in(iter, alloc) + } +} + +/// Extension trait for iterators, in order to allow allocator-parameterized collections to be constructed more easily. +pub trait CollectIn: Iterator + Sized { + /// Collect all items from an iterator, into a collection parameterized by an allocator. + /// Similar to [`Iterator::collect`][collect]. + /// + /// [collect]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect + /// + /// ``` + /// # use bumpalo::collections::{FromIteratorIn, CollectIn, Vec, String}; + /// # use bumpalo::Bump; + /// # + /// let bump = Bump::new(); + /// + /// let str = "hello, world!".to_owned(); + /// let bump_str: String = str.chars().collect_in(&bump); + /// assert_eq!(&bump_str, &str); + /// + /// let nums: Vec = (0..=3).collect_in::>(&bump); + /// assert_eq!(&nums, &[0,1,2,3]); + /// ``` + fn collect_in>(self, alloc: C::Alloc) -> C { + C::from_iter_in(self, alloc) + } +} + +impl CollectIn for I {} diff --git a/deps/crates/vendor/bumpalo/src/collections/mod.rs b/deps/crates/vendor/bumpalo/src/collections/mod.rs new file mode 100644 index 00000000000000..218636c320ac85 --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/mod.rs @@ -0,0 +1,93 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Collection types that allocate inside a [`Bump`] arena. +//! +//! [`Bump`]: ../struct.Bump.html + +#![allow(deprecated)] + +mod raw_vec; + +pub mod vec; +pub use self::vec::Vec; + +mod str; +pub mod string; +pub use self::string::String; + +mod collect_in; +pub use collect_in::{CollectIn, FromIteratorIn}; + +// pub mod binary_heap; +// mod btree; +// pub mod linked_list; +// pub mod vec_deque; + +// pub mod btree_map { +// //! A map based on a B-Tree. +// pub use super::btree::map::*; +// } + +// pub mod btree_set { +// //! A set based on a B-Tree. +// pub use super::btree::set::*; +// } + +// #[doc(no_inline)] +// pub use self::binary_heap::BinaryHeap; + +// #[doc(no_inline)] +// pub use self::btree_map::BTreeMap; + +// #[doc(no_inline)] +// pub use self::btree_set::BTreeSet; + +// #[doc(no_inline)] +// pub use self::linked_list::LinkedList; + +// #[doc(no_inline)] +// pub use self::vec_deque::VecDeque; + +use crate::alloc::{AllocErr, LayoutErr}; + +/// Augments `AllocErr` with a `CapacityOverflow` variant. +#[derive(Clone, PartialEq, Eq, Debug)] +// #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the documentation for the [`AllocErr`] type). + AllocErr, +} + +// #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr + } +} + +// #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + +// /// An intermediate trait for specialization of `Extend`. +// #[doc(hidden)] +// trait SpecExtend { +// /// Extends `self` with the contents of the given iterator. +// fn spec_extend(&mut self, iter: I); +// } diff --git a/deps/crates/vendor/bumpalo/src/collections/raw_vec.rs b/deps/crates/vendor/bumpalo/src/collections/raw_vec.rs new file mode 100644 index 00000000000000..3977ba9a48867e --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/raw_vec.rs @@ -0,0 +1,781 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unstable_name_collisions)] +#![allow(dead_code)] + +use crate::Bump; + +use core::cmp; +use core::mem; +use core::ptr::{self, NonNull}; + +use crate::alloc::{handle_alloc_error, Alloc, Layout, UnstableLayoutMethods}; +use crate::collections::CollectionAllocErr; +use crate::collections::CollectionAllocErr::*; +// use boxed::Box; + +/// A low-level utility for more ergonomically allocating, reallocating, and deallocating +/// a buffer of memory on the heap without having to worry about all the corner cases +/// involved. This type is excellent for building your own data structures like Vec and VecDeque. +/// In particular: +/// +/// * Produces Unique::empty() on zero-sized types +/// * Produces Unique::empty() on zero-length allocations +/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics) +/// * Guards against 32-bit systems allocating more than isize::MAX bytes +/// * Guards against overflowing your length +/// * Aborts on OOM +/// * Avoids freeing Unique::empty() +/// * Contains a ptr::Unique and thus endows the user with all related benefits +/// +/// This type does not in anyway inspect the memory that it manages. When dropped it *will* +/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec +/// to handle the actual things *stored* inside of a RawVec. +/// +/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types. +/// This enables you to use capacity growing logic catch the overflows in your length +/// that might occur with zero-sized types. +/// +/// However this means that you need to be careful when round-tripping this type +/// with a `Box<[T]>`: `cap()` won't yield the len. However `with_capacity`, +/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity +/// field. This allows zero-sized types to not be special-cased by consumers of +/// this type. +#[allow(missing_debug_implementations)] +pub struct RawVec<'a, T> { + ptr: NonNull, + cap: usize, + a: &'a Bump, +} + +impl<'a, T> RawVec<'a, T> { + /// Like `new` but parameterized over the choice of allocator for + /// the returned RawVec. + pub fn new_in(a: &'a Bump) -> Self { + // `cap: 0` means "unallocated". zero-sized types are ignored. + RawVec { + ptr: NonNull::dangling(), + cap: 0, + a, + } + } + + /// Like `with_capacity` but parameterized over the choice of + /// allocator for the returned RawVec. + #[inline] + pub fn with_capacity_in(cap: usize, a: &'a Bump) -> Self { + RawVec::allocate_in(cap, false, a) + } + + /// Like `with_capacity_zeroed` but parameterized over the choice + /// of allocator for the returned RawVec. + #[inline] + pub fn with_capacity_zeroed_in(cap: usize, a: &'a Bump) -> Self { + RawVec::allocate_in(cap, true, a) + } + + fn allocate_in(cap: usize, zeroed: bool, mut a: &'a Bump) -> Self { + unsafe { + let elem_size = mem::size_of::(); + + let alloc_size = cap + .checked_mul(elem_size) + .unwrap_or_else(|| capacity_overflow()); + alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow()); + + // handles ZSTs and `cap = 0` alike + let ptr = if alloc_size == 0 { + NonNull::::dangling() + } else { + let align = mem::align_of::(); + let layout = Layout::from_size_align(alloc_size, align).unwrap(); + let result = if zeroed { + a.alloc_zeroed(layout) + } else { + Alloc::alloc(&mut a, layout) + }; + match result { + Ok(ptr) => ptr.cast(), + Err(_) => handle_alloc_error(layout), + } + }; + + RawVec { ptr, cap, a } + } + } +} + +impl<'a, T> RawVec<'a, T> { + /// Reconstitutes a RawVec from a pointer, capacity, and allocator. + /// + /// # Undefined Behavior + /// + /// The ptr must be allocated (via the given allocator `a`), and with the given capacity. The + /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems). + /// If the ptr and capacity come from a RawVec created via `a`, then this is guaranteed. + pub unsafe fn from_raw_parts_in(ptr: *mut T, cap: usize, a: &'a Bump) -> Self { + RawVec { + ptr: NonNull::new_unchecked(ptr), + cap, + a, + } + } +} + +impl<'a, T> RawVec<'a, T> { + /// Gets a raw pointer to the start of the allocation. Note that this is + /// Unique::empty() if `cap = 0` or T is zero-sized. In the former case, you must + /// be careful. + pub fn ptr(&self) -> *mut T { + self.ptr.as_ptr() + } + + /// Gets the capacity of the allocation. + /// + /// This will always be `usize::MAX` if `T` is zero-sized. + #[inline(always)] + pub fn cap(&self) -> usize { + if mem::size_of::() == 0 { + !0 + } else { + self.cap + } + } + + /// Returns a shared reference to the allocator backing this RawVec. + pub fn bump(&self) -> &'a Bump { + self.a + } + + fn current_layout(&self) -> Option { + if self.cap == 0 { + None + } else { + // We have an allocated chunk of memory, so we can bypass runtime + // checks to get our current layout. + unsafe { + let align = mem::align_of::(); + let size = mem::size_of::() * self.cap; + Some(Layout::from_size_align_unchecked(size, align)) + } + } + } + + /// Doubles the size of the type's backing allocation. This is common enough + /// to want to do that it's easiest to just have a dedicated method. Slightly + /// more efficient logic can be provided for this than the general case. + /// + /// This function is ideal for when pushing elements one-at-a-time because + /// you don't need to incur the costs of the more general computations + /// reserve needs to do to guard against overflow. You do however need to + /// manually check if your `len == cap`. + /// + /// # Panics + /// + /// * Panics if T is zero-sized on the assumption that you managed to exhaust + /// all `usize::MAX` slots in your imaginary buffer. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + /// + /// # Examples + /// + /// ```ignore + /// # #![feature(alloc, raw_vec_internals)] + /// # extern crate alloc; + /// # use std::ptr; + /// # use alloc::raw_vec::RawVec; + /// struct MyVec { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// pub fn push(&mut self, elem: T) { + /// if self.len == self.buf.cap() { self.buf.double(); } + /// // double would have aborted or panicked if the len exceeded + /// // `isize::MAX` so this is safe to do unchecked now. + /// unsafe { + /// ptr::write(self.buf.ptr().add(self.len), elem); + /// } + /// self.len += 1; + /// } + /// } + /// # fn main() { + /// # let mut vec = MyVec { buf: RawVec::new(), len: 0 }; + /// # vec.push(1); + /// # } + /// ``` + #[inline(never)] + #[cold] + pub fn double(&mut self) { + unsafe { + let elem_size = mem::size_of::(); + + // since we set the capacity to usize::MAX when elem_size is + // 0, getting to here necessarily means the RawVec is overfull. + assert!(elem_size != 0, "capacity overflow"); + + let (new_cap, uniq) = match self.current_layout() { + Some(cur) => { + // Since we guarantee that we never allocate more than + // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as + // a precondition, so this can't overflow. Additionally the + // alignment will never be too large as to "not be + // satisfiable", so `Layout::from_size_align` will always + // return `Some`. + // + // tl;dr; we bypass runtime checks due to dynamic assertions + // in this module, allowing us to use + // `from_size_align_unchecked`. + let new_cap = 2 * self.cap; + let new_size = new_cap * elem_size; + alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); + let ptr_res = self.a.realloc(self.ptr.cast(), cur, new_size); + match ptr_res { + Ok(ptr) => (new_cap, ptr.cast()), + Err(_) => handle_alloc_error(Layout::from_size_align_unchecked( + new_size, + cur.align(), + )), + } + } + None => { + // skip to 4 because tiny Vec's are dumb; but not if that + // would cause overflow + let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; + match self.a.alloc_array::(new_cap) { + Ok(ptr) => (new_cap, ptr), + Err(_) => handle_alloc_error(Layout::array::(new_cap).unwrap()), + } + } + }; + self.ptr = uniq; + self.cap = new_cap; + } + } + + /// Attempts to double the size of the type's backing allocation in place. This is common + /// enough to want to do that it's easiest to just have a dedicated method. Slightly + /// more efficient logic can be provided for this than the general case. + /// + /// Returns true if the reallocation attempt has succeeded, or false otherwise. + /// + /// # Panics + /// + /// * Panics if T is zero-sized on the assumption that you managed to exhaust + /// all `usize::MAX` slots in your imaginary buffer. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + #[inline(never)] + #[cold] + pub fn double_in_place(&mut self) -> bool { + unsafe { + let elem_size = mem::size_of::(); + let old_layout = match self.current_layout() { + Some(layout) => layout, + None => return false, // nothing to double + }; + + // since we set the capacity to usize::MAX when elem_size is + // 0, getting to here necessarily means the RawVec is overfull. + assert!(elem_size != 0, "capacity overflow"); + + // Since we guarantee that we never allocate more than isize::MAX + // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so + // this can't overflow. + // + // Similarly like with `double` above we can go straight to + // `Layout::from_size_align_unchecked` as we know this won't + // overflow and the alignment is sufficiently small. + let new_cap = 2 * self.cap; + let new_size = new_cap * elem_size; + alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); + match self.a.grow_in_place(self.ptr.cast(), old_layout, new_size) { + Ok(_) => { + // We can't directly divide `size`. + self.cap = new_cap; + true + } + Err(_) => false, + } + } + } + + /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. + pub fn try_reserve_exact( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + ) -> Result<(), CollectionAllocErr> { + self.fallible_reserve_internal(used_cap, needed_extra_cap, Exact) + } + + /// Ensures that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already, + /// will reallocate the minimum possible amount of memory necessary. + /// Generally this will be exactly the amount of memory necessary, + /// but in principle the allocator is free to give back more than + /// we asked for. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { + self.infallible_reserve_internal(used_cap, needed_extra_cap, Exact) + } + + /// Calculates the buffer's new size given that it'll hold `used_cap + + /// needed_extra_cap` elements. This logic is used in amortized reserve methods. + /// Returns `(new_capacity, new_alloc_size)`. + fn amortized_new_size( + &self, + used_cap: usize, + needed_extra_cap: usize, + ) -> Result { + // Nothing we can really do about these checks :( + let required_cap = used_cap + .checked_add(needed_extra_cap) + .ok_or(CapacityOverflow)?; + // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. + let double_cap = self.cap * 2; + // `double_cap` guarantees exponential growth. + Ok(cmp::max(double_cap, required_cap)) + } + + /// The same as `reserve`, but returns on errors instead of panicking or aborting. + pub fn try_reserve( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + ) -> Result<(), CollectionAllocErr> { + self.fallible_reserve_internal(used_cap, needed_extra_cap, Amortized) + } + + /// Ensures that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already have + /// enough capacity, will reallocate enough space plus comfortable slack + /// space to get amortized `O(1)` behavior. Will limit this behavior + /// if it would needlessly cause itself to panic. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// This is ideal for implementing a bulk-push operation like `extend`. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + /// + /// # Examples + /// + /// ```ignore + /// # #![feature(alloc, raw_vec_internals)] + /// # extern crate alloc; + /// # use std::ptr; + /// # use alloc::raw_vec::RawVec; + /// struct MyVec { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// pub fn push_all(&mut self, elems: &[T]) { + /// self.buf.reserve(self.len, elems.len()); + /// // reserve would have aborted or panicked if the len exceeded + /// // `isize::MAX` so this is safe to do unchecked now. + /// for x in elems { + /// unsafe { + /// ptr::write(self.buf.ptr().add(self.len), x.clone()); + /// } + /// self.len += 1; + /// } + /// } + /// } + /// # fn main() { + /// # let mut vector = MyVec { buf: RawVec::new(), len: 0 }; + /// # vector.push_all(&[1, 3, 5, 7, 9]); + /// # } + /// ``` + #[inline(always)] + pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { + self.infallible_reserve_internal(used_cap, needed_extra_cap, Amortized) + } + + /// Attempts to ensure that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already have + /// enough capacity, will reallocate in place enough space plus comfortable slack + /// space to get amortized `O(1)` behavior. Will limit this behaviour + /// if it would needlessly cause itself to panic. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// Returns true if the reallocation attempt has succeeded, or false otherwise. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + pub fn reserve_in_place(&mut self, used_cap: usize, needed_extra_cap: usize) -> bool { + unsafe { + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. If the current `cap` is 0, we can't + // reallocate in place. + // Wrapping in case they give a bad `used_cap` + let old_layout = match self.current_layout() { + Some(layout) => layout, + None => return false, + }; + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return false; + } + + let new_cap = self + .amortized_new_size(used_cap, needed_extra_cap) + .unwrap_or_else(|_| capacity_overflow()); + + // Here, `cap < used_cap + needed_extra_cap <= new_cap` + // (regardless of whether `self.cap - used_cap` wrapped). + // Therefore we can safely call grow_in_place. + + let new_layout = Layout::new::().repeat(new_cap).unwrap().0; + // FIXME: may crash and burn on over-reserve + alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow()); + match self + .a + .grow_in_place(self.ptr.cast(), old_layout, new_layout.size()) + { + Ok(_) => { + self.cap = new_cap; + true + } + Err(_) => false, + } + } + } + + /// Shrinks the allocation down to the specified amount. If the given amount + /// is 0, actually completely deallocates. + /// + /// # Panics + /// + /// Panics if the given amount is *larger* than the current capacity. + /// + /// # Aborts + /// + /// Aborts on OOM. + pub fn shrink_to_fit(&mut self, amount: usize) { + let elem_size = mem::size_of::(); + + // Set the `cap` because they might be about to promote to a `Box<[T]>` + if elem_size == 0 { + self.cap = amount; + return; + } + + // This check is my waterloo; it's the only thing Vec wouldn't have to do. + assert!(self.cap >= amount, "Tried to shrink to a larger capacity"); + + if amount == 0 { + // We want to create a new zero-length vector within the + // same allocator. We use ptr::write to avoid an + // erroneous attempt to drop the contents, and we use + // ptr::read to sidestep condition against destructuring + // types that implement Drop. + + unsafe { + let a = self.a; + self.dealloc_buffer(); + ptr::write(self, RawVec::new_in(a)); + } + } else if self.cap != amount { + unsafe { + // We know here that our `amount` is greater than zero. This + // implies, via the assert above, that capacity is also greater + // than zero, which means that we've got a current layout that + // "fits" + // + // We also know that `self.cap` is greater than `amount`, and + // consequently we don't need runtime checks for creating either + // layout + let old_size = elem_size * self.cap; + let new_size = elem_size * amount; + let align = mem::align_of::(); + let old_layout = Layout::from_size_align_unchecked(old_size, align); + match self.a.realloc(self.ptr.cast(), old_layout, new_size) { + Ok(p) => self.ptr = p.cast(), + Err(_) => { + handle_alloc_error(Layout::from_size_align_unchecked(new_size, align)) + } + } + } + self.cap = amount; + } + } +} + +#[cfg(feature = "boxed")] +impl<'a, T> RawVec<'a, T> { + /// Converts the entire buffer into `Box<[T]>`. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (See description of type for details.) + /// + /// # Undefined Behavior + /// + /// All elements of `RawVec` must be initialized. Notice that + /// the rules around uninitialized boxed values are not finalized yet, + /// but until they are, it is advisable to avoid them. + pub unsafe fn into_box(self) -> crate::boxed::Box<'a, [T]> { + use crate::boxed::Box; + + // NOTE: not calling `cap()` here; actually using the real `cap` field! + let slice = core::slice::from_raw_parts_mut(self.ptr(), self.cap); + let output: Box<'a, [T]> = Box::from_raw(slice); + mem::forget(self); + output + } +} + +enum Fallibility { + Fallible, + Infallible, +} + +use self::Fallibility::*; + +enum ReserveStrategy { + Exact, + Amortized, +} + +use self::ReserveStrategy::*; + +impl<'a, T> RawVec<'a, T> { + #[inline(always)] + fn fallible_reserve_internal( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + strategy: ReserveStrategy, + ) -> Result<(), CollectionAllocErr> { + // This portion of the method should always be inlined. + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return Ok(()); + } + // This portion of the method should never be inlined, and will only be called when + // the check above has confirmed that it is necessary. + self.reserve_internal_or_error(used_cap, needed_extra_cap, Fallible, strategy) + } + + #[inline(always)] + fn infallible_reserve_internal( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + strategy: ReserveStrategy, + ) { + // This portion of the method should always be inlined. + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return; + } + // This portion of the method should never be inlined, and will only be called when + // the check above has confirmed that it is necessary. + self.reserve_internal_or_panic(used_cap, needed_extra_cap, strategy) + } + + #[inline(never)] + fn reserve_internal_or_panic( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + strategy: ReserveStrategy, + ) { + // Delegates the call to `reserve_internal_or_error` and panics in the event of an error. + // This allows the method to have a return type of `()`, simplifying the assembly at the + // call site. + match self.reserve_internal(used_cap, needed_extra_cap, Infallible, strategy) { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocErr) => unreachable!(), + Ok(()) => { /* yay */ } + } + } + + #[inline(never)] + fn reserve_internal_or_error( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + fallibility: Fallibility, + strategy: ReserveStrategy, + ) -> Result<(), CollectionAllocErr> { + // Delegates the call to `reserve_internal`, which can be inlined. + self.reserve_internal(used_cap, needed_extra_cap, fallibility, strategy) + } + + /// Helper method to reserve additional space, reallocating the backing memory. + /// The caller is responsible for confirming that there is not already enough space available. + fn reserve_internal( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + fallibility: Fallibility, + strategy: ReserveStrategy, + ) -> Result<(), CollectionAllocErr> { + unsafe { + use crate::AllocErr; + + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Nothing we can really do about these checks :( + let new_cap = match strategy { + Exact => used_cap + .checked_add(needed_extra_cap) + .ok_or(CapacityOverflow)?, + Amortized => self.amortized_new_size(used_cap, needed_extra_cap)?, + }; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; + + alloc_guard(new_layout.size())?; + + let res = match self.current_layout() { + Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(self.ptr.cast(), layout, new_layout.size()) + } + None => Alloc::alloc(&mut self.a, new_layout), + }; + + if let (Err(AllocErr), Infallible) = (&res, fallibility) { + handle_alloc_error(new_layout); + } + + self.ptr = res?.cast(); + self.cap = new_cap; + + Ok(()) + } + } +} + +impl<'a, T> RawVec<'a, T> { + /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + pub unsafe fn dealloc_buffer(&mut self) { + let elem_size = mem::size_of::(); + if elem_size != 0 { + if let Some(layout) = self.current_layout() { + self.a.dealloc(self.ptr.cast(), layout); + } + } + } +} + +impl<'a, T> Drop for RawVec<'a, T> { + /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + fn drop(&mut self) { + unsafe { + self.dealloc_buffer(); + } + } +} + +// We need to guarantee the following: +// * We don't ever allocate `> isize::MAX` byte-size objects +// * We don't overflow `usize::MAX` and actually allocate too little +// +// On 64-bit we just need to check for overflow since trying to allocate +// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add +// an extra guard for this in case we're running on a platform which can use +// all 4GB in user-space. e.g. PAE or x32 + +#[inline] +fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { + if mem::size_of::() < 8 && alloc_size > ::core::isize::MAX as usize { + Err(CapacityOverflow) + } else { + Ok(()) + } +} + +// One central function responsible for reporting capacity overflows. This'll +// ensure that the code generation related to these panics is minimal as there's +// only one location which panics rather than a bunch throughout the module. +fn capacity_overflow() -> ! { + panic!("capacity overflow") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reserve_does_not_overallocate() { + let bump = Bump::new(); + { + let mut v: RawVec = RawVec::new_in(&bump); + // First `reserve` allocates like `reserve_exact` + v.reserve(0, 9); + assert_eq!(9, v.cap()); + } + + { + let mut v: RawVec = RawVec::new_in(&bump); + v.reserve(0, 7); + assert_eq!(7, v.cap()); + // 97 if more than double of 7, so `reserve` should work + // like `reserve_exact`. + v.reserve(7, 90); + assert_eq!(97, v.cap()); + } + + { + let mut v: RawVec = RawVec::new_in(&bump); + v.reserve(0, 12); + assert_eq!(12, v.cap()); + v.reserve(12, 3); + // 3 is less than half of 12, so `reserve` must grow + // exponentially. At the time of writing this test grow + // factor is 2, so new capacity is 24, however, grow factor + // of 1.5 is OK too. Hence `>= 18` in assert. + assert!(v.cap() >= 12 + 12 / 2); + } + } +} diff --git a/deps/crates/vendor/bumpalo/src/collections/str/lossy.rs b/deps/crates/vendor/bumpalo/src/collections/str/lossy.rs new file mode 100644 index 00000000000000..b1012a412989ad --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/str/lossy.rs @@ -0,0 +1,209 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::collections::str as core_str; +use core::char; +use core::fmt; +use core::fmt::Write; +use core::str; + +/// Lossy UTF-8 string. +pub struct Utf8Lossy<'a> { + bytes: &'a [u8], +} + +impl<'a> Utf8Lossy<'a> { + pub fn from_bytes(bytes: &'a [u8]) -> Utf8Lossy<'a> { + Utf8Lossy { bytes } + } + + pub fn chunks(&self) -> Utf8LossyChunksIter<'a> { + Utf8LossyChunksIter { + source: &self.bytes, + } + } +} + +/// Iterator over lossy UTF-8 string +#[allow(missing_debug_implementations)] +pub struct Utf8LossyChunksIter<'a> { + source: &'a [u8], +} + +#[derive(PartialEq, Eq, Debug)] +pub struct Utf8LossyChunk<'a> { + /// Sequence of valid chars. + /// Can be empty between broken UTF-8 chars. + pub valid: &'a str, + /// Single broken char, empty if none. + /// Empty iff iterator item is last. + pub broken: &'a [u8], +} + +impl<'a> Iterator for Utf8LossyChunksIter<'a> { + type Item = Utf8LossyChunk<'a>; + + fn next(&mut self) -> Option> { + if self.source.is_empty() { + return None; + } + + const TAG_CONT_U8: u8 = 128; + fn unsafe_get(xs: &[u8], i: usize) -> u8 { + unsafe { *xs.get_unchecked(i) } + } + fn safe_get(xs: &[u8], i: usize) -> u8 { + if i >= xs.len() { + 0 + } else { + unsafe_get(xs, i) + } + } + + let mut i = 0; + while i < self.source.len() { + let i_ = i; + + let byte = unsafe_get(self.source, i); + i += 1; + + if byte < 128 { + } else { + let w = core_str::utf8_char_width(byte); + + macro_rules! error { + () => {{ + unsafe { + let r = Utf8LossyChunk { + valid: str::from_utf8_unchecked(&self.source[0..i_]), + broken: &self.source[i_..i], + }; + self.source = &self.source[i..]; + return Some(r); + } + }}; + } + + match w { + 2 => { + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 3 => { + match (byte, safe_get(self.source, i)) { + (0xE0, 0xA0..=0xBF) => (), + (0xE1..=0xEC, 0x80..=0xBF) => (), + (0xED, 0x80..=0x9F) => (), + (0xEE..=0xEF, 0x80..=0xBF) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 4 => { + match (byte, safe_get(self.source, i)) { + (0xF0, 0x90..=0xBF) => (), + (0xF1..=0xF3, 0x80..=0xBF) => (), + (0xF4, 0x80..=0x8F) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + _ => { + error!(); + } + } + } + } + + let r = Utf8LossyChunk { + valid: unsafe { str::from_utf8_unchecked(self.source) }, + broken: &[], + }; + self.source = &[]; + Some(r) + } +} + +impl<'a> fmt::Display for Utf8Lossy<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // If we're the empty string then our iterator won't actually yield + // anything, so perform the formatting manually + if self.bytes.is_empty() { + return "".fmt(f); + } + + for Utf8LossyChunk { valid, broken } in self.chunks() { + // If we successfully decoded the whole chunk as a valid string then + // we can return a direct formatting of the string which will also + // respect various formatting flags if possible. + if valid.len() == self.bytes.len() { + assert!(broken.is_empty()); + return valid.fmt(f); + } + + f.write_str(valid)?; + if !broken.is_empty() { + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + } + Ok(()) + } +} + +impl<'a> fmt::Debug for Utf8Lossy<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_char('"')?; + + for Utf8LossyChunk { valid, broken } in self.chunks() { + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in broken { + write!(f, "\\x{:02x}", b)?; + } + } + + f.write_char('"') + } +} diff --git a/deps/crates/vendor/bumpalo/src/collections/str/mod.rs b/deps/crates/vendor/bumpalo/src/collections/str/mod.rs new file mode 100644 index 00000000000000..29f4c6be06993f --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/str/mod.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! String manipulation +//! +//! For more details, see std::str + +#[allow(missing_docs)] +pub mod lossy; + +// https://tools.ietf.org/html/rfc3629 +#[rustfmt::skip] +static UTF8_CHAR_WIDTH: [u8; 256] = [ +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF +0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF +4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF +]; + +/// Given a first byte, determines how many bytes are in this UTF-8 character. +#[inline] +pub fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} diff --git a/deps/crates/vendor/bumpalo/src/collections/string.rs b/deps/crates/vendor/bumpalo/src/collections/string.rs new file mode 100644 index 00000000000000..bbc8050fa7c65c --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/string.rs @@ -0,0 +1,2191 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A UTF-8 encoded, growable string. +//! +//! This module contains the [`String`] type and several error types that may +//! result from working with [`String`]s. +//! +//! This module is a fork of the [`std::string`] module, that uses a bump allocator. +//! +//! [`std::string`]: https://doc.rust-lang.org/std/string/index.html +//! +//! # Examples +//! +//! You can create a new [`String`] from a string literal with [`String::from_str_in`]: +//! +//! ``` +//! use bumpalo::{Bump, collections::String}; +//! +//! let b = Bump::new(); +//! +//! let s = String::from_str_in("world", &b); +//! ``` +//! +//! [`String`]: struct.String.html +//! [`String::from_str_in`]: struct.String.html#method.from_str_in +//! +//! If you have a vector of valid UTF-8 bytes, you can make a [`String`] out of +//! it. You can do the reverse too. +//! +//! ``` +//! use bumpalo::{Bump, collections::String}; +//! +//! let b = Bump::new(); +//! +//! let sparkle_heart = bumpalo::vec![in &b; 240, 159, 146, 150]; +//! +//! // We know these bytes are valid, so we'll use `unwrap()`. +//! let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); +//! +//! assert_eq!("💖", sparkle_heart); +//! +//! let bytes = sparkle_heart.into_bytes(); +//! +//! assert_eq!(bytes, [240, 159, 146, 150]); +//! ``` + +use crate::collections::str::lossy; +use crate::collections::vec::Vec; +use crate::Bump; +use core::borrow::{Borrow, BorrowMut}; +use core::char::decode_utf16; +use core::fmt; +use core::hash; +use core::iter::FusedIterator; +use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; +use core::ptr; +use core::str::{self, Chars, Utf8Error}; +use core_alloc::borrow::Cow; + +/// Like the [`format!`] macro, but for creating [`bumpalo::collections::String`]s. +/// +/// [`format!`]: https://doc.rust-lang.org/std/macro.format.html +/// [`bumpalo::collections::String`]: collections/string/struct.String.html +/// +/// # Examples +/// +/// ``` +/// use bumpalo::Bump; +/// +/// let b = Bump::new(); +/// +/// let who = "World"; +/// let s = bumpalo::format!(in &b, "Hello, {}!", who); +/// assert_eq!(s, "Hello, World!") +/// ``` +#[macro_export] +macro_rules! format { + ( in $bump:expr, $fmt:expr, $($args:expr),* ) => {{ + use $crate::core_alloc::fmt::Write; + let bump = $bump; + let mut s = $crate::collections::String::new_in(bump); + let _ = write!(&mut s, $fmt, $($args),*); + s + }}; + + ( in $bump:expr, $fmt:expr, $($args:expr,)* ) => { + $crate::format!(in $bump, $fmt, $($args),*) + }; +} + +/// A UTF-8 encoded, growable string. +/// +/// The `String` type is the most common string type that has ownership over the +/// contents of the string. It has a close relationship with its borrowed +/// counterpart, the primitive [`str`]. +/// +/// [`str`]: https://doc.rust-lang.org/std/primitive.str.html +/// +/// # Examples +/// +/// You can create a `String` from a literal string with [`String::from_str_in`]: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// let hello = String::from_str_in("Hello, world!", &b); +/// ``` +/// +/// You can append a [`char`] to a `String` with the [`push`] method, and +/// append a [`&str`] with the [`push_str`] method: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// let mut hello = String::from_str_in("Hello, ", &b); +/// +/// hello.push('w'); +/// hello.push_str("orld!"); +/// ``` +/// +/// [`char`]: https://doc.rust-lang.org/std/primitive.char.html +/// [`push`]: #method.push +/// [`push_str`]: #method.push_str +/// +/// If you have a vector of UTF-8 bytes, you can create a `String` from it with +/// the [`from_utf8`] method: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// // some bytes, in a vector +/// let sparkle_heart = bumpalo::vec![in &b; 240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so we'll use `unwrap()`. +/// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +/// +/// [`from_utf8`]: #method.from_utf8 +/// +/// # Deref +/// +/// `String`s implement [`Deref`], and so inherit all of [`str`]'s +/// methods. In addition, this means that you can pass a `String` to a +/// function which takes a [`&str`] by using an ampersand (`&`): +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// fn takes_str(s: &str) { } +/// +/// let s = String::from_str_in("Hello", &b); +/// +/// takes_str(&s); +/// ``` +/// +/// This will create a [`&str`] from the `String` and pass it in. This +/// conversion is very inexpensive, and so generally, functions will accept +/// [`&str`]s as arguments unless they need a `String` for some specific +/// reason. +/// +/// In certain cases Rust doesn't have enough information to make this +/// conversion, known as [`Deref`] coercion. In the following example a string +/// slice [`&'a str`][`&str`] implements the trait `TraitExample`, and the function +/// `example_func` takes anything that implements the trait. In this case Rust +/// would need to make two implicit conversions, which Rust doesn't have the +/// means to do. For that reason, the following example will not compile. +/// +/// ```compile_fail,E0277 +/// use bumpalo::{Bump, collections::String}; +/// +/// trait TraitExample {} +/// +/// impl<'a> TraitExample for &'a str {} +/// +/// fn example_func(example_arg: A) {} +/// +/// let b = Bump::new(); +/// let example_string = String::from_str_in("example_string", &b); +/// example_func(&example_string); +/// ``` +/// +/// There are two options that would work instead. The first would be to +/// change the line `example_func(&example_string);` to +/// `example_func(example_string.as_str());`, using the method [`as_str()`] +/// to explicitly extract the string slice containing the string. The second +/// way changes `example_func(&example_string);` to +/// `example_func(&*example_string);`. In this case we are dereferencing a +/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to +/// [`&str`]. The second way is more idiomatic, however both work to do the +/// conversion explicitly rather than relying on the implicit conversion. +/// +/// # Representation +/// +/// A `String` is made up of three components: a pointer to some bytes, a +/// length, and a capacity. The pointer points to an internal buffer `String` +/// uses to store its data. The length is the number of bytes currently stored +/// in the buffer, and the capacity is the size of the buffer in bytes. As such, +/// the length will always be less than or equal to the capacity. +/// +/// This buffer is always stored on the heap. +/// +/// You can look at these with the [`as_ptr`], [`len`], and [`capacity`] +/// methods: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// use std::mem; +/// +/// let b = Bump::new(); +/// +/// let mut story = String::from_str_in("Once upon a time...", &b); +/// +/// let ptr = story.as_mut_ptr(); +/// let len = story.len(); +/// let capacity = story.capacity(); +/// +/// // story has nineteen bytes +/// assert_eq!(19, len); +/// +/// // Now that we have our parts, we throw the story away. +/// mem::forget(story); +/// +/// // We can re-build a String out of ptr, len, and capacity. This is all +/// // unsafe because we are responsible for making sure the components are +/// // valid: +/// let s = unsafe { String::from_raw_parts_in(ptr, len, capacity, &b) } ; +/// +/// assert_eq!(String::from_str_in("Once upon a time...", &b), s); +/// ``` +/// +/// [`as_ptr`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_ptr +/// [`len`]: #method.len +/// [`capacity`]: #method.capacity +/// +/// If a `String` has enough capacity, adding elements to it will not +/// re-allocate. For example, consider this program: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// let mut s = String::new_in(&b); +/// +/// println!("{}", s.capacity()); +/// +/// for _ in 0..5 { +/// s.push_str("hello"); +/// println!("{}", s.capacity()); +/// } +/// ``` +/// +/// This will output the following: +/// +/// ```text +/// 0 +/// 5 +/// 10 +/// 20 +/// 20 +/// 40 +/// ``` +/// +/// At first, we have no memory allocated at all, but as we append to the +/// string, it increases its capacity appropriately. If we instead use the +/// [`with_capacity_in`] method to allocate the correct capacity initially: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// let mut s = String::with_capacity_in(25, &b); +/// +/// println!("{}", s.capacity()); +/// +/// for _ in 0..5 { +/// s.push_str("hello"); +/// println!("{}", s.capacity()); +/// } +/// ``` +/// +/// [`with_capacity_in`]: #method.with_capacity_in +/// +/// We end up with a different output: +/// +/// ```text +/// 25 +/// 25 +/// 25 +/// 25 +/// 25 +/// 25 +/// ``` +/// +/// Here, there's no need to allocate more memory inside the loop. +/// +/// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html +/// [`Deref`]: https://doc.rust-lang.org/std/ops/trait.Deref.html +/// [`as_str()`]: struct.String.html#method.as_str +#[derive(PartialOrd, Eq, Ord)] +pub struct String<'bump> { + vec: Vec<'bump, u8>, +} + +/// A possible error value when converting a `String` from a UTF-8 byte vector. +/// +/// This type is the error type for the [`from_utf8`] method on [`String`]. It +/// is designed in such a way to carefully avoid reallocations: the +/// [`into_bytes`] method will give back the byte vector that was used in the +/// conversion attempt. +/// +/// [`from_utf8`]: struct.String.html#method.from_utf8 +/// [`String`]: struct.String.html +/// [`into_bytes`]: struct.FromUtf8Error.html#method.into_bytes +/// +/// The [`Utf8Error`] type provided by [`std::str`] represents an error that may +/// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's +/// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` +/// through the [`utf8_error`] method. +/// +/// [`Utf8Error`]: https://doc.rust-lang.org/std/str/struct.Utf8Error.html +/// [`std::str`]: https://doc.rust-lang.org/std/str/index.html +/// [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html +/// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html +/// [`utf8_error`]: #method.utf8_error +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// // some invalid bytes, in a vector +/// let bytes = bumpalo::vec![in &b; 0, 159]; +/// +/// let value = String::from_utf8(bytes); +/// +/// assert!(value.is_err()); +/// assert_eq!(bumpalo::vec![in &b; 0, 159], value.unwrap_err().into_bytes()); +/// ``` +#[derive(Debug)] +pub struct FromUtf8Error<'bump> { + bytes: Vec<'bump, u8>, + error: Utf8Error, +} + +/// A possible error value when converting a `String` from a UTF-16 byte slice. +/// +/// This type is the error type for the [`from_utf16_in`] method on [`String`]. +/// +/// [`from_utf16_in`]: struct.String.html#method.from_utf16_in +/// [`String`]: struct.String.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let b = Bump::new(); +/// +/// // 𝄞muic +/// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063]; +/// +/// assert!(String::from_utf16_in(v, &b).is_err()); +/// ``` +#[derive(Debug)] +pub struct FromUtf16Error(()); + +impl<'bump> String<'bump> { + /// Creates a new empty `String`. + /// + /// Given that the `String` is empty, this will not allocate any initial + /// buffer. While that means that this initial operation is very + /// inexpensive, it may cause excessive allocation later when you add + /// data. If you have an idea of how much data the `String` will hold, + /// consider the [`with_capacity_in`] method to prevent excessive + /// re-allocation. + /// + /// [`with_capacity_in`]: #method.with_capacity_in + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::new_in(&b); + /// ``` + #[inline] + pub fn new_in(bump: &'bump Bump) -> String<'bump> { + String { + vec: Vec::new_in(bump), + } + } + + /// Creates a new empty `String` with a particular capacity. + /// + /// `String`s have an internal buffer to hold their data. The capacity is + /// the length of that buffer, and can be queried with the [`capacity`] + /// method. This method creates an empty `String`, but one with an initial + /// buffer that can hold `capacity` bytes. This is useful when you may be + /// appending a bunch of data to the `String`, reducing the number of + /// reallocations it needs to do. + /// + /// [`capacity`]: #method.capacity + /// + /// If the given capacity is `0`, no allocation will occur, and this method + /// is identical to the [`new_in`] method. + /// + /// [`new_in`]: #method.new + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::with_capacity_in(10, &b); + /// + /// // The String contains no chars, even though it has capacity for more + /// assert_eq!(s.len(), 0); + /// + /// // These are all done without reallocating... + /// let cap = s.capacity(); + /// for _ in 0..10 { + /// s.push('a'); + /// } + /// + /// assert_eq!(s.capacity(), cap); + /// + /// // ...but this may make the vector reallocate + /// s.push('a'); + /// ``` + #[inline] + pub fn with_capacity_in(capacity: usize, bump: &'bump Bump) -> String<'bump> { + String { + vec: Vec::with_capacity_in(capacity, bump), + } + } + + /// Converts a vector of bytes to a `String`. + /// + /// A string (`String`) is made of bytes ([`u8`]), and a vector of bytes + /// ([`Vec`]) is made of bytes, so this function converts between the + /// two. Not all byte slices are valid `String`s, however: `String` + /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that + /// the bytes are valid UTF-8, and then does the conversion. + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want + /// to incur the overhead of the validity check, there is an unsafe version + /// of this function, [`from_utf8_unchecked`], which has the same behavior + /// but skips the check. + /// + /// This method will take care to not copy the vector, for efficiency's + /// sake. + /// + /// If you need a [`&str`] instead of a `String`, consider + /// [`str::from_utf8`]. + /// + /// The inverse of this method is [`into_bytes`]. + /// + /// # Errors + /// + /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the + /// provided bytes are not UTF-8. The vector you moved in is also included. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some bytes, in a vector + /// let sparkle_heart = bumpalo::vec![in &b; 240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so we'll use `unwrap()`. + /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some invalid bytes, in a vector + /// let sparkle_heart = bumpalo::vec![in &b; 0, 159, 146, 150]; + /// + /// assert!(String::from_utf8(sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`FromUtf8Error`] for more details on what you can do + /// with this error. + /// + /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked + /// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html + /// [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html + /// [`Vec`]: ../vec/struct.Vec.html + /// [`str::from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html + /// [`into_bytes`]: struct.String.html#method.into_bytes + /// [`FromUtf8Error`]: struct.FromUtf8Error.html + /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + #[inline] + pub fn from_utf8(vec: Vec<'bump, u8>) -> Result, FromUtf8Error<'bump>> { + match str::from_utf8(&vec) { + Ok(..) => Ok(String { vec }), + Err(e) => Err(FromUtf8Error { + bytes: vec, + error: e, + }), + } + } + + /// Converts a slice of bytes to a string, including invalid characters. + /// + /// Strings are made of bytes ([`u8`]), and a slice of bytes + /// ([`&[u8]`][slice]) is made of bytes, so this function converts + /// between the two. Not all byte slices are valid strings, however: strings + /// are required to be valid UTF-8. During this conversion, + /// `from_utf8_lossy_in()` will replace any invalid UTF-8 sequences with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], which looks like this: � + /// + /// [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html + /// [slice]: https://doc.rust-lang.org/std/primitive.slice.html + /// [U+FFFD]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want + /// to incur the overhead of the conversion, there is an unsafe version + /// of this function, [`from_utf8_unchecked`], which has the same behavior + /// but skips the checks. + /// + /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{collections::String, Bump, vec}; + /// + /// let b = Bump::new(); + /// + /// // some bytes, in a vector + /// let sparkle_heart = bumpalo::vec![in &b; 240, 159, 146, 150]; + /// + /// let sparkle_heart = String::from_utf8_lossy_in(&sparkle_heart, &b); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use bumpalo::{collections::String, Bump, vec}; + /// + /// let b = Bump::new(); + /// + /// // some invalid bytes + /// let input = b"Hello \xF0\x90\x80World"; + /// let output = String::from_utf8_lossy_in(input, &b); + /// + /// assert_eq!("Hello �World", output); + /// ``` + pub fn from_utf8_lossy_in(v: &[u8], bump: &'bump Bump) -> String<'bump> { + let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks(); + + let (first_valid, first_broken) = if let Some(chunk) = iter.next() { + let lossy::Utf8LossyChunk { valid, broken } = chunk; + if valid.len() == v.len() { + debug_assert!(broken.is_empty()); + unsafe { + return String::from_utf8_unchecked(Vec::from_iter_in(v.iter().cloned(), bump)); + } + } + (valid, broken) + } else { + return String::from_str_in("", bump); + }; + + const REPLACEMENT: &str = "\u{FFFD}"; + + let mut res = String::with_capacity_in(v.len(), bump); + res.push_str(first_valid); + if !first_broken.is_empty() { + res.push_str(REPLACEMENT); + } + + for lossy::Utf8LossyChunk { valid, broken } in iter { + res.push_str(valid); + if !broken.is_empty() { + res.push_str(REPLACEMENT); + } + } + + res + } + + /// Decode a UTF-16 encoded slice `v` into a `String`, returning [`Err`] + /// if `v` contains any invalid data. + /// + /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // 𝄞music + /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063]; + /// assert_eq!(String::from_str_in("𝄞music", &b), String::from_utf16_in(v, &b).unwrap()); + /// + /// // 𝄞muic + /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063]; + /// assert!(String::from_utf16_in(v, &b).is_err()); + /// ``` + pub fn from_utf16_in(v: &[u16], bump: &'bump Bump) -> Result, FromUtf16Error> { + let mut ret = String::with_capacity_in(v.len(), bump); + for c in decode_utf16(v.iter().cloned()) { + if let Ok(c) = c { + ret.push(c); + } else { + return Err(FromUtf16Error(())); + } + } + Ok(ret) + } + + /// Construct a new `String<'bump>` from a string slice. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_str_in("hello", &b); + /// assert_eq!(s, "hello"); + /// ``` + #[inline] + pub fn from_str_in(s: &str, bump: &'bump Bump) -> String<'bump> { + let len = s.len(); + let mut t = String::with_capacity_in(len, bump); + // SAFETY: + // * `src` is valid for reads of `s.len()` bytes by virtue of being an allocated `&str`. + // * `dst` is valid for writes of `s.len()` bytes as `String::with_capacity_in(s.len(), bump)` + // above guarantees that. + // * Alignment is not relevant as `u8` has no alignment requirements. + // * Source and destination ranges cannot overlap as we just reserved the destination + // range from the bump. + unsafe { ptr::copy_nonoverlapping(s.as_ptr(), t.vec.as_mut_ptr(), len) }; + // SAFETY: We reserved sufficent capacity for the string above. + // The elements at `0..len` were initialized by `copy_nonoverlapping` above. + unsafe { t.vec.set_len(len) }; + t + } + + /// Construct a new `String<'bump>` from an iterator of `char`s. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_iter_in(['h', 'e', 'l', 'l', 'o'].iter().cloned(), &b); + /// assert_eq!(s, "hello"); + /// ``` + pub fn from_iter_in>(iter: I, bump: &'bump Bump) -> String<'bump> { + let mut s = String::new_in(bump); + for c in iter { + s.push(c); + } + s + } + + /// Creates a new `String` from a length, capacity, and pointer. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * The memory at `ptr` needs to have been previously allocated by the + /// same allocator the standard library uses. + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the correct value. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `String` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// use std::mem; + /// + /// let b = Bump::new(); + /// + /// unsafe { + /// let mut s = String::from_str_in("hello", &b); + /// let ptr = s.as_mut_ptr(); + /// let len = s.len(); + /// let capacity = s.capacity(); + /// + /// mem::forget(s); + /// + /// let s = String::from_raw_parts_in(ptr, len, capacity, &b); + /// + /// assert_eq!(s, "hello"); + /// } + /// ``` + #[inline] + pub unsafe fn from_raw_parts_in( + buf: *mut u8, + length: usize, + capacity: usize, + bump: &'bump Bump, + ) -> String<'bump> { + String { + vec: Vec::from_raw_parts_in(buf, length, capacity, bump), + } + } + + /// Converts a vector of bytes to a `String` without checking that the + /// string contains valid UTF-8. + /// + /// See the safe version, [`from_utf8`], for more details. + /// + /// [`from_utf8`]: struct.String.html#method.from_utf8 + /// + /// # Safety + /// + /// This function is unsafe because it does not check that the bytes passed + /// to it are valid UTF-8. If this constraint is violated, it may cause + /// memory unsafety issues with future users of the `String`, + /// as it is assumed that `String`s are valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some bytes, in a vector + /// let sparkle_heart = bumpalo::vec![in &b; 240, 159, 146, 150]; + /// + /// let sparkle_heart = unsafe { + /// String::from_utf8_unchecked(sparkle_heart) + /// }; + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[inline] + pub unsafe fn from_utf8_unchecked(bytes: Vec<'bump, u8>) -> String<'bump> { + String { vec: bytes } + } + + /// Returns a shared reference to the allocator backing this `String`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// // uses the same allocator as the provided `String` + /// fn copy_string<'bump>(s: &String<'bump>) -> &'bump str { + /// s.bump().alloc_str(s.as_str()) + /// } + /// ``` + #[inline] + #[must_use] + pub fn bump(&self) -> &'bump Bump { + self.vec.bump() + } + + /// Converts a `String` into a byte vector. + /// + /// This consumes the `String`, so we do not need to copy its contents. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_str_in("hello", &b); + /// + /// assert_eq!(s.into_bytes(), [104, 101, 108, 108, 111]); + /// ``` + #[inline] + pub fn into_bytes(self) -> Vec<'bump, u8> { + self.vec + } + + /// Convert this `String<'bump>` into a `&'bump str`. This is analogous to + /// [`std::string::String::into_boxed_str`][into_boxed_str]. + /// + /// [into_boxed_str]: https://doc.rust-lang.org/std/string/struct.String.html#method.into_boxed_str + /// + /// # Example + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_str_in("foo", &b); + /// + /// assert_eq!(s.into_bump_str(), "foo"); + /// ``` + pub fn into_bump_str(self) -> &'bump str { + let s = unsafe { + let s = self.as_str(); + mem::transmute(s) + }; + mem::forget(self); + s + } + + /// Extracts a string slice containing the entire `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_str_in("foo", &b); + /// + /// assert_eq!("foo", s.as_str()); + /// ``` + #[inline] + pub fn as_str(&self) -> &str { + self + } + + /// Converts a `String` into a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foobar", &b); + /// let s_mut_str = s.as_mut_str(); + /// + /// s_mut_str.make_ascii_uppercase(); + /// + /// assert_eq!("FOOBAR", s_mut_str); + /// ``` + #[inline] + pub fn as_mut_str(&mut self) -> &mut str { + self + } + + /// Appends a given string slice onto the end of this `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foo", &b); + /// + /// s.push_str("bar"); + /// + /// assert_eq!("foobar", s); + /// ``` + #[inline] + pub fn push_str(&mut self, string: &str) { + self.vec.extend_from_slice_copy(string.as_bytes()) + } + + /// Returns this `String`'s capacity, in bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::with_capacity_in(10, &b); + /// + /// assert!(s.capacity() >= 10); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.vec.capacity() + } + + /// Ensures that this `String`'s capacity is at least `additional` bytes + /// larger than its length. + /// + /// The capacity may be increased by more than `additional` bytes if it + /// chooses, to prevent frequent reallocations. + /// + /// If you do not want this "at least" behavior, see the [`reserve_exact`] + /// method. + /// + /// # Panics + /// + /// Panics if the new capacity overflows [`usize`]. + /// + /// [`reserve_exact`]: struct.String.html#method.reserve_exact + /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::new_in(&b); + /// + /// s.reserve(10); + /// + /// assert!(s.capacity() >= 10); + /// ``` + /// + /// This may not actually increase the capacity: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::with_capacity_in(10, &b); + /// s.push('a'); + /// s.push('b'); + /// + /// // s now has a length of 2 and a capacity of 10 + /// assert_eq!(2, s.len()); + /// assert_eq!(10, s.capacity()); + /// + /// // Since we already have an extra 8 capacity, calling this... + /// s.reserve(8); + /// + /// // ... doesn't actually increase. + /// assert_eq!(10, s.capacity()); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.vec.reserve(additional) + } + + /// Ensures that this `String`'s capacity is `additional` bytes + /// larger than its length. + /// + /// Consider using the [`reserve`] method unless you absolutely know + /// better than the allocator. + /// + /// [`reserve`]: #method.reserve + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::new_in(&b); + /// + /// s.reserve_exact(10); + /// + /// assert!(s.capacity() >= 10); + /// ``` + /// + /// This may not actually increase the capacity: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::with_capacity_in(10, &b); + /// s.push('a'); + /// s.push('b'); + /// + /// // s now has a length of 2 and a capacity of 10 + /// assert_eq!(2, s.len()); + /// assert_eq!(10, s.capacity()); + /// + /// // Since we already have an extra 8 capacity, calling this... + /// s.reserve_exact(8); + /// + /// // ... doesn't actually increase. + /// assert_eq!(10, s.capacity()); + /// ``` + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.vec.reserve_exact(additional) + } + + /// Shrinks the capacity of this `String` to match its length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foo", &b); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to_fit(); + /// assert_eq!(3, s.capacity()); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + self.vec.shrink_to_fit() + } + + /// Appends the given [`char`] to the end of this `String`. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("abc", &b); + /// + /// s.push('1'); + /// s.push('2'); + /// s.push('3'); + /// + /// assert_eq!("abc123", s); + /// ``` + #[inline] + pub fn push(&mut self, ch: char) { + match ch.len_utf8() { + 1 => self.vec.push(ch as u8), + _ => self + .vec + .extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()), + } + } + + /// Returns a byte slice of this `String`'s contents. + /// + /// The inverse of this method is [`from_utf8`]. + /// + /// [`from_utf8`]: #method.from_utf8 + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let s = String::from_str_in("hello", &b); + /// + /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.vec + } + + /// Shortens this `String` to the specified length. + /// + /// If `new_len` is greater than the string's current length, this has no + /// effect. + /// + /// Note that this method has no effect on the allocated capacity + /// of the string. + /// + /// # Panics + /// + /// Panics if `new_len` does not lie on a [`char`] boundary. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("hello", &b); + /// + /// s.truncate(2); + /// + /// assert_eq!("he", s); + /// ``` + #[inline] + pub fn truncate(&mut self, new_len: usize) { + if new_len <= self.len() { + assert!(self.is_char_boundary(new_len)); + self.vec.truncate(new_len) + } + } + + /// Removes the last character from the string buffer and returns it. + /// + /// Returns [`None`] if this `String` is empty. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foo", &b); + /// + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('f')); + /// + /// assert_eq!(s.pop(), None); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + let ch = self.chars().rev().next()?; + let newlen = self.len() - ch.len_utf8(); + unsafe { + self.vec.set_len(newlen); + } + Some(ch) + } + + /// Removes a [`char`] from this `String` at a byte position and returns it. + /// + /// This is an `O(n)` operation, as it requires copying every element in the + /// buffer. + /// + /// # Panics + /// + /// Panics if `idx` is larger than or equal to the `String`'s length, + /// or if it does not lie on a [`char`] boundary. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foo", &b); + /// + /// assert_eq!(s.remove(0), 'f'); + /// assert_eq!(s.remove(1), 'o'); + /// assert_eq!(s.remove(0), 'o'); + /// ``` + #[inline] + pub fn remove(&mut self, idx: usize) -> char { + let ch = match self[idx..].chars().next() { + Some(ch) => ch, + None => panic!("cannot remove a char from the end of a string"), + }; + + let next = idx + ch.len_utf8(); + let len = self.len(); + unsafe { + ptr::copy( + self.vec.as_ptr().add(next), + self.vec.as_mut_ptr().add(idx), + len - next, + ); + self.vec.set_len(len - (next - idx)); + } + ch + } + + /// Retains only the characters specified by the predicate. + /// + /// In other words, remove all characters `c` such that `f(c)` returns `false`. + /// This method operates in place and preserves the order of the retained + /// characters. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("f_o_ob_ar", &b); + /// + /// s.retain(|c| c != '_'); + /// + /// assert_eq!(s, "foobar"); + /// ``` + #[inline] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(char) -> bool, + { + struct SetLenOnDrop<'a, 'bump> { + s: &'a mut String<'bump>, + idx: usize, + del_bytes: usize, + } + + impl<'a, 'bump> Drop for SetLenOnDrop<'a, 'bump> { + fn drop(&mut self) { + let new_len = self.idx - self.del_bytes; + debug_assert!(new_len <= self.s.len()); + unsafe { self.s.vec.set_len(new_len) }; + } + } + + let len = self.len(); + let mut guard = SetLenOnDrop { + s: self, + idx: 0, + del_bytes: 0, + }; + + while guard.idx < len { + let ch = + // SAFETY: `guard.idx` is positive-or-zero and less that len so the `get_unchecked` + // is in bound. `self` is valid UTF-8 like string and the returned slice starts at + // a unicode code point so the `Chars` always return one character. + unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() }; + let ch_len = ch.len_utf8(); + + if !f(ch) { + guard.del_bytes += ch_len; + } else if guard.del_bytes > 0 { + // SAFETY: `guard.idx` is in bound and `guard.del_bytes` represent the number of + // bytes that are erased from the string so the resulting `guard.idx - + // guard.del_bytes` always represent a valid unicode code point. + // + // `guard.del_bytes` >= `ch.len_utf8()`, so taking a slice with `ch.len_utf8()` len + // is safe. + ch.encode_utf8(unsafe { + core::slice::from_raw_parts_mut( + guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes), + ch.len_utf8(), + ) + }); + } + + // Point idx to the next char + guard.idx += ch_len; + } + + drop(guard); + } + + /// Inserts a character into this `String` at a byte position. + /// + /// This is an `O(n)` operation as it requires copying every element in the + /// buffer. + /// + /// # Panics + /// + /// Panics if `idx` is larger than the `String`'s length, or if it does not + /// lie on a [`char`] boundary. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::with_capacity_in(3, &b); + /// + /// s.insert(0, 'f'); + /// s.insert(1, 'o'); + /// s.insert(2, 'o'); + /// + /// assert_eq!("foo", s); + /// ``` + #[inline] + pub fn insert(&mut self, idx: usize, ch: char) { + assert!(self.is_char_boundary(idx)); + let mut bits = [0; 4]; + let bits = ch.encode_utf8(&mut bits).as_bytes(); + + unsafe { + self.insert_bytes(idx, bits); + } + } + + unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { + let len = self.len(); + let amt = bytes.len(); + self.vec.reserve(amt); + + ptr::copy( + self.vec.as_ptr().add(idx), + self.vec.as_mut_ptr().add(idx + amt), + len - idx, + ); + ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + self.vec.set_len(len + amt); + } + + /// Inserts a string slice into this `String` at a byte position. + /// + /// This is an `O(n)` operation as it requires copying every element in the + /// buffer. + /// + /// # Panics + /// + /// Panics if `idx` is larger than the `String`'s length, or if it does not + /// lie on a [`char`] boundary. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("bar", &b); + /// + /// s.insert_str(0, "foo"); + /// + /// assert_eq!("foobar", s); + /// ``` + #[inline] + pub fn insert_str(&mut self, idx: usize, string: &str) { + assert!(self.is_char_boundary(idx)); + + unsafe { + self.insert_bytes(idx, string.as_bytes()); + } + } + + /// Returns a mutable reference to the contents of this `String`. + /// + /// # Safety + /// + /// This function is unsafe because the returned `&mut Vec` allows writing + /// bytes which are not valid UTF-8. If this constraint is violated, using + /// the original `String` after dropping the `&mut Vec` may violate memory + /// safety, as it is assumed that `String`s are valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("hello", &b); + /// + /// unsafe { + /// let vec = s.as_mut_vec(); + /// assert_eq!(vec, &[104, 101, 108, 108, 111]); + /// + /// vec.reverse(); + /// } + /// assert_eq!(s, "olleh"); + /// ``` + #[inline] + pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<'bump, u8> { + &mut self.vec + } + + /// Returns the length of this `String`, in bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let a = String::from_str_in("foo", &b); + /// + /// assert_eq!(a.len(), 3); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.vec.len() + } + + /// Returns `true` if this `String` has a length of zero. + /// + /// Returns `false` otherwise. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut v = String::new_in(&b); + /// assert!(v.is_empty()); + /// + /// v.push('a'); + /// assert!(!v.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Splits the string into two at the given index. + /// + /// Returns a newly allocated `String`. `self` contains bytes `[0, at)`, and + /// the returned `String` contains bytes `[at, len)`. `at` must be on the + /// boundary of a UTF-8 code point. + /// + /// Note that the capacity of `self` does not change. + /// + /// # Panics + /// + /// Panics if `at` is not on a UTF-8 code point boundary, or if it is beyond the last + /// code point of the string. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut hello = String::from_str_in("Hello, World!", &b); + /// let world = hello.split_off(7); + /// assert_eq!(hello, "Hello, "); + /// assert_eq!(world, "World!"); + /// ``` + #[inline] + pub fn split_off(&mut self, at: usize) -> String<'bump> { + assert!(self.is_char_boundary(at)); + let other = self.vec.split_off(at); + unsafe { String::from_utf8_unchecked(other) } + } + + /// Truncates this `String`, removing all contents. + /// + /// While this means the `String` will have a length of zero, it does not + /// touch its capacity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("foo", &b); + /// + /// s.clear(); + /// + /// assert!(s.is_empty()); + /// assert_eq!(0, s.len()); + /// assert_eq!(3, s.capacity()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.vec.clear() + } + + /// Creates a draining iterator that removes the specified range in the `String` + /// and yields the removed `chars`. + /// + /// Note: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// # Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("α is alpha, β is beta", &b); + /// let beta_offset = s.find('β').unwrap_or(s.len()); + /// + /// // Remove the range up until the β from the string + /// let t = String::from_iter_in(s.drain(..beta_offset), &b); + /// assert_eq!(t, "α is alpha, "); + /// assert_eq!(s, "β is beta"); + /// + /// // A full range clears the string + /// drop(s.drain(..)); + /// assert_eq!(s, ""); + /// ``` + pub fn drain<'a, R>(&'a mut self, range: R) -> Drain<'a, 'bump> + where + R: RangeBounds, + { + // Memory safety + // + // The String version of Drain does not have the memory safety issues + // of the vector version. The data is just plain bytes. + // Because the range removal happens in Drop, if the Drain iterator is leaked, + // the removal will not happen. + let len = self.len(); + let start = match range.start_bound() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end_bound() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + + // Take out two simultaneous borrows. The &mut String won't be accessed + // until iteration is over, in Drop. + let self_ptr = self as *mut _; + // slicing does the appropriate bounds checks + let chars_iter = self[start..end].chars(); + + Drain { + start, + end, + iter: chars_iter, + string: self_ptr, + } + } + + /// Removes the specified range in the string, + /// and replaces it with the given string. + /// The given string doesn't need to be the same length as the range. + /// + /// # Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// [`char`]: https://doc.rust-lang.org/std/primitive.char.html + /// [`Vec::splice`]: ../vec/struct.Vec.html#method.splice + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// let mut s = String::from_str_in("α is alpha, β is beta", &b); + /// let beta_offset = s.find('β').unwrap_or(s.len()); + /// + /// // Replace the range up until the β from the string + /// s.replace_range(..beta_offset, "Α is capital alpha; "); + /// assert_eq!(s, "Α is capital alpha; β is beta"); + /// ``` + pub fn replace_range(&mut self, range: R, replace_with: &str) + where + R: RangeBounds, + { + // Memory safety + // + // Replace_range does not have the memory safety issues of a vector Splice. + // of the vector version. The data is just plain bytes. + + match range.start_bound() { + Included(&n) => assert!(self.is_char_boundary(n)), + Excluded(&n) => assert!(self.is_char_boundary(n + 1)), + Unbounded => {} + }; + match range.end_bound() { + Included(&n) => assert!(self.is_char_boundary(n + 1)), + Excluded(&n) => assert!(self.is_char_boundary(n)), + Unbounded => {} + }; + + unsafe { self.as_mut_vec() }.splice(range, replace_with.bytes()); + } +} + +impl<'bump> FromUtf8Error<'bump> { + /// Returns a slice of bytes that were attempted to convert to a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some invalid bytes, in a vector + /// let bytes = bumpalo::vec![in &b; 0, 159]; + /// + /// let value = String::from_utf8(bytes); + /// + /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); + /// ``` + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..] + } + + /// Returns the bytes that were attempted to convert to a `String`. + /// + /// This method is carefully constructed to avoid allocation. It will + /// consume the error, moving out the bytes, so that a copy of the bytes + /// does not need to be made. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some invalid bytes, in a vector + /// let bytes = bumpalo::vec![in &b; 0, 159]; + /// + /// let value = String::from_utf8(bytes); + /// + /// assert_eq!(bumpalo::vec![in &b; 0, 159], value.unwrap_err().into_bytes()); + /// ``` + pub fn into_bytes(self) -> Vec<'bump, u8> { + self.bytes + } + + /// Fetch a `Utf8Error` to get more details about the conversion failure. + /// + /// The [`Utf8Error`] type provided by [`std::str`] represents an error that may + /// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's + /// an analogue to `FromUtf8Error`. See its documentation for more details + /// on using it. + /// + /// [`Utf8Error`]: https://doc.rust-lang.org/std/str/struct.Utf8Error.html + /// [`std::str`]: https://doc.rust-lang.org/std/str/index.html + /// [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html + /// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bumpalo::{Bump, collections::String}; + /// + /// let b = Bump::new(); + /// + /// // some invalid bytes, in a vector + /// let bytes = bumpalo::vec![in &b; 0, 159]; + /// + /// let error = String::from_utf8(bytes).unwrap_err().utf8_error(); + /// + /// // the first byte is invalid here + /// assert_eq!(1, error.valid_up_to()); + /// ``` + pub fn utf8_error(&self) -> Utf8Error { + self.error + } +} + +impl<'bump> fmt::Display for FromUtf8Error<'bump> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.error, f) + } +} + +impl fmt::Display for FromUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt("invalid utf-16: lone surrogate found", f) + } +} + +impl<'bump> Clone for String<'bump> { + fn clone(&self) -> Self { + String { + vec: self.vec.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.vec.clone_from(&source.vec); + } +} + +impl<'bump> Extend for String<'bump> { + fn extend>(&mut self, iter: I) { + let iterator = iter.into_iter(); + let (lower_bound, _) = iterator.size_hint(); + self.reserve(lower_bound); + for ch in iterator { + self.push(ch) + } + } +} + +impl<'a, 'bump> Extend<&'a char> for String<'bump> { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } +} + +impl<'a, 'bump> Extend<&'a str> for String<'bump> { + fn extend>(&mut self, iter: I) { + for s in iter { + self.push_str(s) + } + } +} + +impl<'bump> Extend> for String<'bump> { + fn extend>>(&mut self, iter: I) { + for s in iter { + self.push_str(&s) + } + } +} + +impl<'bump> Extend for String<'bump> { + fn extend>(&mut self, iter: I) { + for s in iter { + self.push_str(&s) + } + } +} + +impl<'a, 'bump> Extend> for String<'bump> { + fn extend>>(&mut self, iter: I) { + for s in iter { + self.push_str(&s) + } + } +} + +impl<'bump> PartialEq for String<'bump> { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(&self[..], &other[..]) + } +} + +macro_rules! impl_eq { + ($lhs:ty, $rhs: ty) => { + impl<'a, 'bump> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + PartialEq::eq(&self[..], &other[..]) + } + } + + impl<'a, 'b, 'bump> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + PartialEq::eq(&self[..], &other[..]) + } + } + }; +} + +impl_eq! { String<'bump>, str } +impl_eq! { String<'bump>, &'a str } +impl_eq! { Cow<'a, str>, String<'bump> } +impl_eq! { core_alloc::string::String, String<'bump> } + +impl<'bump> fmt::Display for String<'bump> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl<'bump> fmt::Debug for String<'bump> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'bump> hash::Hash for String<'bump> { + #[inline] + fn hash(&self, hasher: &mut H) { + (**self).hash(hasher) + } +} + +/// Implements the `+` operator for concatenating two strings. +/// +/// This consumes the `String<'bump>` on the left-hand side and re-uses its buffer (growing it if +/// necessary). This is done to avoid allocating a new `String<'bump>` and copying the entire contents on +/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// repeated concatenation. +/// +/// The string on the right-hand side is only borrowed; its contents are copied into the returned +/// `String<'bump>`. +/// +/// # Examples +/// +/// Concatenating two `String<'bump>`s takes the first by value and borrows the second: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let bump = Bump::new(); +/// +/// let a = String::from_str_in("hello", &bump); +/// let b = String::from_str_in(" world", &bump); +/// let c = a + &b; +/// // `a` is moved and can no longer be used here. +/// ``` +/// +/// If you want to keep using the first `String`, you can clone it and append to the clone instead: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let bump = Bump::new(); +/// +/// let a = String::from_str_in("hello", &bump); +/// let b = String::from_str_in(" world", &bump); +/// let c = a.clone() + &b; +/// // `a` is still valid here. +/// ``` +/// +/// Concatenating `&str` slices can be done by converting the first to a `String`: +/// +/// ``` +/// use bumpalo::{Bump, collections::String}; +/// +/// let bump = Bump::new(); +/// +/// let a = "hello"; +/// let b = " world"; +/// let c = String::from_str_in(a, &bump) + b; +/// ``` +impl<'a, 'bump> Add<&'a str> for String<'bump> { + type Output = String<'bump>; + + #[inline] + fn add(mut self, other: &str) -> String<'bump> { + self.push_str(other); + self + } +} + +/// Implements the `+=` operator for appending to a `String<'bump>`. +/// +/// This has the same behavior as the [`push_str`][String::push_str] method. +impl<'a, 'bump> AddAssign<&'a str> for String<'bump> { + #[inline] + fn add_assign(&mut self, other: &str) { + self.push_str(other); + } +} + +impl<'bump> ops::Index> for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, index: ops::Range) -> &str { + &self[..][index] + } +} +impl<'bump> ops::Index> for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeTo) -> &str { + &self[..][index] + } +} +impl<'bump> ops::Index> for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeFrom) -> &str { + &self[..][index] + } +} +impl<'bump> ops::Index for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &str { + unsafe { str::from_utf8_unchecked(&self.vec) } + } +} +impl<'bump> ops::Index> for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeInclusive) -> &str { + Index::index(&**self, index) + } +} +impl<'bump> ops::Index> for String<'bump> { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeToInclusive) -> &str { + Index::index(&**self, index) + } +} + +impl<'bump> ops::IndexMut> for String<'bump> { + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut str { + &mut self[..][index] + } +} +impl<'bump> ops::IndexMut> for String<'bump> { + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { + &mut self[..][index] + } +} +impl<'bump> ops::IndexMut> for String<'bump> { + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { + &mut self[..][index] + } +} +impl<'bump> ops::IndexMut for String<'bump> { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } + } +} +impl<'bump> ops::IndexMut> for String<'bump> { + #[inline] + fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { + IndexMut::index_mut(&mut **self, index) + } +} +impl<'bump> ops::IndexMut> for String<'bump> { + #[inline] + fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { + IndexMut::index_mut(&mut **self, index) + } +} + +impl<'bump> ops::Deref for String<'bump> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + unsafe { str::from_utf8_unchecked(&self.vec) } + } +} + +impl<'bump> ops::DerefMut for String<'bump> { + #[inline] + fn deref_mut(&mut self) -> &mut str { + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } + } +} + +impl<'bump> AsRef for String<'bump> { + #[inline] + fn as_ref(&self) -> &str { + self + } +} + +impl<'bump> AsRef<[u8]> for String<'bump> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'bump> fmt::Write for String<'bump> { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + self.push_str(s); + Ok(()) + } + + #[inline] + fn write_char(&mut self, c: char) -> fmt::Result { + self.push(c); + Ok(()) + } +} + +impl<'bump> Borrow for String<'bump> { + #[inline] + fn borrow(&self) -> &str { + &self[..] + } +} + +impl<'bump> BorrowMut for String<'bump> { + #[inline] + fn borrow_mut(&mut self) -> &mut str { + &mut self[..] + } +} + +/// A draining iterator for `String`. +/// +/// This struct is created by the [`String::drain`] method. See its +/// documentation for more information. +pub struct Drain<'a, 'bump> { + /// Will be used as &'a mut String in the destructor + string: *mut String<'bump>, + /// Start of part to remove + start: usize, + /// End of part to remove + end: usize, + /// Current remaining range to remove + iter: Chars<'a>, +} + +impl<'a, 'bump> fmt::Debug for Drain<'a, 'bump> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Drain { .. }") + } +} + +unsafe impl<'a, 'bump> Sync for Drain<'a, 'bump> {} +unsafe impl<'a, 'bump> Send for Drain<'a, 'bump> {} + +impl<'a, 'bump> Drop for Drain<'a, 'bump> { + fn drop(&mut self) { + unsafe { + // Use Vec::drain. "Reaffirm" the bounds checks to avoid + // panic code being inserted again. + let self_vec = (*self.string).as_mut_vec(); + if self.start <= self.end && self.end <= self_vec.len() { + self_vec.drain(self.start..self.end); + } + } + } +} + +// TODO: implement `AsRef` and `as_str` + +impl<'a, 'bump> Iterator for Drain<'a, 'bump> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, 'bump> DoubleEndedIterator for Drain<'a, 'bump> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +impl<'a, 'bump> FusedIterator for Drain<'a, 'bump> {} + +#[cfg(feature = "serde")] +mod serialize { + use super::*; + + use serde::{Serialize, Serializer}; + + impl<'bump> Serialize for String<'bump> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self) + } + } +} diff --git a/deps/crates/vendor/bumpalo/src/collections/vec.rs b/deps/crates/vendor/bumpalo/src/collections/vec.rs new file mode 100644 index 00000000000000..c2b8892df915d9 --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/collections/vec.rs @@ -0,0 +1,3004 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! A contiguous growable array type with heap-allocated contents, written +//! [`Vec<'bump, T>`]. +//! +//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and +//! `O(1)` pop (from the end). +//! +//! This module is a fork of the [`std::vec`] module, that uses a bump allocator. +//! +//! [`std::vec`]: https://doc.rust-lang.org/std/vec/index.html +//! +//! # Examples +//! +//! You can explicitly create a [`Vec<'bump, T>`] with [`new_in`]: +//! +//! ``` +//! use bumpalo::{Bump, collections::Vec}; +//! +//! let b = Bump::new(); +//! let v: Vec = Vec::new_in(&b); +//! ``` +//! +//! ... or by using the [`vec!`] macro: +//! +//! ``` +//! use bumpalo::{Bump, collections::Vec}; +//! +//! let b = Bump::new(); +//! +//! let v: Vec = bumpalo::vec![in &b]; +//! +//! let v = bumpalo::vec![in &b; 1, 2, 3, 4, 5]; +//! +//! let v = bumpalo::vec![in &b; 0; 10]; // ten zeroes +//! ``` +//! +//! You can [`push`] values onto the end of a vector (which will grow the vector +//! as needed): +//! +//! ``` +//! use bumpalo::{Bump, collections::Vec}; +//! +//! let b = Bump::new(); +//! +//! let mut v = bumpalo::vec![in &b; 1, 2]; +//! +//! v.push(3); +//! ``` +//! +//! Popping values works in much the same way: +//! +//! ``` +//! use bumpalo::{Bump, collections::Vec}; +//! +//! let b = Bump::new(); +//! +//! let mut v = bumpalo::vec![in &b; 1, 2]; +//! +//! assert_eq!(v.pop(), Some(2)); +//! ``` +//! +//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits): +//! +//! ``` +//! use bumpalo::{Bump, collections::Vec}; +//! +//! let b = Bump::new(); +//! +//! let mut v = bumpalo::vec![in &b; 1, 2, 3]; +//! assert_eq!(v[2], 3); +//! v[1] += 5; +//! assert_eq!(v, [1, 7, 3]); +//! ``` +//! +//! [`Vec<'bump, T>`]: struct.Vec.html +//! [`new_in`]: struct.Vec.html#method.new_in +//! [`push`]: struct.Vec.html#method.push +//! [`Index`]: https://doc.rust-lang.org/std/ops/trait.Index.html +//! [`IndexMut`]: https://doc.rust-lang.org/std/ops/trait.IndexMut.html +//! [`vec!`]: ../../macro.vec.html + +use super::raw_vec::RawVec; +use crate::collections::CollectionAllocErr; +use crate::Bump; +use core::borrow::{Borrow, BorrowMut}; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{self, Hash}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ops; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::{Index, IndexMut, RangeBounds}; +use core::ptr; +use core::ptr::NonNull; +use core::slice; +#[cfg(feature = "std")] +use std::io; + +unsafe fn arith_offset(p: *const T, offset: isize) -> *const T { + p.offset(offset) +} + +fn partition_dedup_by(s: &mut [T], mut same_bucket: F) -> (&mut [T], &mut [T]) +where + F: FnMut(&mut T, &mut T) -> bool, +{ + // Although we have a mutable reference to `s`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the slice is in a valid state at all times. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then split the slice. + // This operation is still O(n). + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write`. + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing s[r] against s[w-1], this is not a duplicate, so + // we swap s[r] and s[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing s[r] against s[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing s[r] against s[w-1], this is not a duplicate, + // so swap s[r] and s[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of slice. Split at w. + + let len = s.len(); + if len <= 1 { + return (s, &mut []); + } + + let ptr = s.as_mut_ptr(); + let mut next_read: usize = 1; + let mut next_write: usize = 1; + + unsafe { + // Avoid bounds checks by using raw pointers. + while next_read < len { + let ptr_read = ptr.add(next_read); + let prev_ptr_write = ptr.add(next_write - 1); + if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) { + if next_read != next_write { + let ptr_write = prev_ptr_write.offset(1); + mem::swap(&mut *ptr_read, &mut *ptr_write); + } + next_write += 1; + } + next_read += 1; + } + } + + s.split_at_mut(next_write) +} + +unsafe fn offset_from(p: *const T, origin: *const T) -> isize +where + T: Sized, +{ + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let d = isize::wrapping_sub(p as _, origin as _); + d / (pointee_size as isize) +} + +/// Creates a [`Vec`] containing the arguments. +/// +/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a [`Vec`] containing a given list of elements: +/// +/// ``` +/// use bumpalo::Bump; +/// +/// let b = Bump::new(); +/// let v = bumpalo::vec![in &b; 1, 2, 3]; +/// assert_eq!(v, [1, 2, 3]); +/// ``` +/// +/// - Create a [`Vec`] from a given element and size: +/// +/// ``` +/// use bumpalo::Bump; +/// +/// let b = Bump::new(); +/// let v = bumpalo::vec![in &b; 1; 3]; +/// assert_eq!(v, [1, 1, 1]); +/// ``` +/// +/// Note that unlike array expressions, this syntax supports all elements +/// which implement [`Clone`] and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone` to duplicate an expression, so one should be careful +/// using this with types having a non-standard `Clone` implementation. For +/// example, `bumpalo::vec![in ≎ Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. +/// +/// [`Vec`]: collections/vec/struct.Vec.html +/// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html +#[macro_export] +macro_rules! vec { + (in $bump:expr; $elem:expr; $n:expr) => {{ + let n = $n; + let mut v = $crate::collections::Vec::with_capacity_in(n, $bump); + if n > 0 { + let elem = $elem; + for _ in 0..n - 1 { + v.push(elem.clone()); + } + v.push(elem); + } + v + }}; + (in $bump:expr) => { $crate::collections::Vec::new_in($bump) }; + (in $bump:expr; $($x:expr),*) => {{ + let mut v = $crate::collections::Vec::new_in($bump); + $( v.push($x); )* + v + }}; + (in $bump:expr; $($x:expr,)*) => (bumpalo::vec![in $bump; $($x),*]) +} + +/// A contiguous growable array type, written `Vec<'bump, T>` but pronounced 'vector'. +/// +/// # Examples +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let mut vec = Vec::new_in(&b); +/// vec.push(1); +/// vec.push(2); +/// +/// assert_eq!(vec.len(), 2); +/// assert_eq!(vec[0], 1); +/// +/// assert_eq!(vec.pop(), Some(2)); +/// assert_eq!(vec.len(), 1); +/// +/// vec[0] = 7; +/// assert_eq!(vec[0], 7); +/// +/// vec.extend([1, 2, 3].iter().cloned()); +/// +/// for x in &vec { +/// println!("{}", x); +/// } +/// assert_eq!(vec, [7, 1, 2, 3]); +/// ``` +/// +/// The [`vec!`] macro is provided to make initialization more convenient: +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; +/// vec.push(4); +/// assert_eq!(vec, [1, 2, 3, 4]); +/// ``` +/// +/// It can also initialize each element of a `Vec<'bump, T>` with a given value. +/// This may be more efficient than performing allocation and initialization +/// in separate steps, especially when initializing a vector of zeros: +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let vec = bumpalo::vec![in &b; 0; 5]; +/// assert_eq!(vec, [0, 0, 0, 0, 0]); +/// +/// // The following is equivalent, but potentially slower: +/// let mut vec1 = Vec::with_capacity_in(5, &b); +/// vec1.resize(5, 0); +/// ``` +/// +/// Use a `Vec<'bump, T>` as an efficient stack: +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let mut stack = Vec::new_in(&b); +/// +/// stack.push(1); +/// stack.push(2); +/// stack.push(3); +/// +/// while let Some(top) = stack.pop() { +/// // Prints 3, 2, 1 +/// println!("{}", top); +/// } +/// ``` +/// +/// # Indexing +/// +/// The `Vec` type allows to access values by index, because it implements the +/// [`Index`] trait. An example will be more explicit: +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let v = bumpalo::vec![in &b; 0, 2, 4, 6]; +/// println!("{}", v[1]); // it will display '2' +/// ``` +/// +/// However be careful: if you try to access an index which isn't in the `Vec`, +/// your software will panic! You cannot do this: +/// +/// ```should_panic +/// use bumpalo::{Bump, collections::Vec}; +/// +/// let b = Bump::new(); +/// +/// let v = bumpalo::vec![in &b; 0, 2, 4, 6]; +/// println!("{}", v[6]); // it will panic! +/// ``` +/// +/// In conclusion: always check if the index you want to get really exists +/// before doing it. +/// +/// # Slicing +/// +/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects. +/// To get a slice, use `&`. Example: +/// +/// ``` +/// use bumpalo::{Bump, collections::Vec}; +/// +/// fn read_slice(slice: &[usize]) { +/// // ... +/// } +/// +/// let b = Bump::new(); +/// +/// let v = bumpalo::vec![in &b; 0, 1]; +/// read_slice(&v); +/// +/// // ... and that's all! +/// // you can also do it like this: +/// let x : &[usize] = &v; +/// ``` +/// +/// In Rust, it's more common to pass slices as arguments rather than vectors +/// when you just want to provide a read access. The same goes for [`String`] and +/// [`&str`]. +/// +/// # Capacity and reallocation +/// +/// The capacity of a vector is the amount of space allocated for any future +/// elements that will be added onto the vector. This is not to be confused with +/// the *length* of a vector, which specifies the number of actual elements +/// within the vector. If a vector's length exceeds its capacity, its capacity +/// will automatically be increased, but its elements will have to be +/// reallocated. +/// +/// For example, a vector with capacity 10 and length 0 would be an empty vector +/// with space for 10 more elements. Pushing 10 or fewer elements onto the +/// vector will not change its capacity or cause reallocation to occur. However, +/// if the vector's length is increased to 11, it will have to reallocate, which +/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity_in`] +/// whenever possible to specify how big the vector is expected to get. +/// +/// # Guarantees +/// +/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees +/// about its design. This ensures that it's as low-overhead as possible in +/// the general case, and can be correctly manipulated in primitive ways +/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<'bump, T>`. +/// If additional type parameters are added (e.g. to support custom allocators), +/// overriding their defaults may change the behavior. +/// +/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length) +/// triplet. No more, no less. The order of these fields is completely +/// unspecified, and you should use the appropriate methods to modify these. +/// The pointer will never be null, so this type is null-pointer-optimized. +/// +/// However, the pointer may not actually point to allocated memory. In particular, +/// if you construct a `Vec` with capacity 0 via [`Vec::new_in`], [`bumpalo::vec![in bump]`][`vec!`], +/// [`Vec::with_capacity_in(0)`][`Vec::with_capacity_in`], or by calling [`shrink_to_fit`] +/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized +/// types inside a `Vec`, it will not allocate space for them. *Note that in this case +/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only +/// if [`mem::size_of::`]\() * capacity() > 0. In general, `Vec`'s allocation +/// details are very subtle — if you intend to allocate memory using a `Vec` +/// and use it for something else (either to pass to unsafe code, or to build your +/// own memory-backed collection), be sure to deallocate this memory by using +/// `from_raw_parts` to recover the `Vec` and then dropping it. +/// +/// If a `Vec` *has* allocated memory, then the memory it points to is +/// in the [`Bump`] arena used to construct it, and its +/// pointer points to [`len`] initialized, contiguous elements in order (what +/// you would see if you coerced it to a slice), followed by [`capacity`] - +/// [`len`] logically uninitialized, contiguous elements. +/// +/// `Vec` will never perform a "small optimization" where elements are actually +/// stored on the stack for two reasons: +/// +/// * It would make it more difficult for unsafe code to correctly manipulate +/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were +/// only moved, and it would be more difficult to determine if a `Vec` had +/// actually allocated memory. +/// +/// * It would penalize the general case, incurring an additional branch +/// on every access. +/// +/// `Vec` will never automatically shrink itself, even if completely empty. This +/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` +/// and then filling it back up to the same [`len`] should incur no calls to +/// the allocator. If you wish to free up unused memory, use +/// [`shrink_to_fit`][`shrink_to_fit`]. +/// +/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is +/// sufficient. [`push`] and [`insert`] *will* (re)allocate if +/// [`len`] == [`capacity`]. That is, the reported capacity is completely +/// accurate, and can be relied on. It can even be used to manually free the memory +/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even +/// when not necessary. +/// +/// `Vec` does not guarantee any particular growth strategy when reallocating +/// when full, nor when [`reserve`] is called. The current strategy is basic +/// and it may prove desirable to use a non-constant growth factor. Whatever +/// strategy is used will of course guarantee `O(1)` amortized [`push`]. +/// +/// `bumpalo::vec![in bump; x; n]`, `bumpalo::vec![in bump; a, b, c, d]`, and +/// [`Vec::with_capacity_in(n)`][`Vec::with_capacity_in`], will all produce a +/// `Vec` with exactly the requested capacity. If [`len`] == [`capacity`], (as +/// is the case for the [`vec!`] macro), then a `Vec<'bump, T>` can be converted +/// to and from a [`Box<[T]>`][owned slice] without reallocating or moving the +/// elements. +/// +/// `Vec` will not specifically overwrite any data that is removed from it, +/// but also won't specifically preserve it. Its uninitialized memory is +/// scratch space that it may use however it wants. It will generally just do +/// whatever is most efficient or otherwise easy to implement. Do not rely on +/// removed data to be erased for security purposes. Even if you drop a `Vec`, its +/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory +/// first, that may not actually happen because the optimizer does not consider +/// this a side-effect that must be preserved. There is one case which we will +/// not break, however: using `unsafe` code to write to the excess capacity, +/// and then increasing the length to match, is always valid. +/// +/// `Vec` does not currently guarantee the order in which elements are dropped. +/// The order has changed in the past and may change again. +/// +/// [`vec!`]: ../../macro.vec.html +/// [`Index`]: https://doc.rust-lang.org/std/ops/trait.Index.html +/// [`String`]: ../string/struct.String.html +/// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html +/// [`Vec::with_capacity_in`]: struct.Vec.html#method.with_capacity_in +/// [`Vec::new_in`]: struct.Vec.html#method.new_in +/// [`shrink_to_fit`]: struct.Vec.html#method.shrink_to_fit +/// [`capacity`]: struct.Vec.html#method.capacity +/// [`mem::size_of::`]: https://doc.rust-lang.org/std/mem/fn.size_of.html +/// [`len`]: struct.Vec.html#method.len +/// [`push`]: struct.Vec.html#method.push +/// [`insert`]: struct.Vec.html#method.insert +/// [`reserve`]: struct.Vec.html#method.reserve +/// [owned slice]: https://doc.rust-lang.org/std/boxed/struct.Box.html +pub struct Vec<'bump, T: 'bump> { + buf: RawVec<'bump, T>, + len: usize, +} + +//////////////////////////////////////////////////////////////////////////////// +// Inherent methods +//////////////////////////////////////////////////////////////////////////////// + +impl<'bump, T: 'bump> Vec<'bump, T> { + /// Constructs a new, empty `Vec<'bump, T>`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// # #![allow(unused_mut)] + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec: Vec = Vec::new_in(&b); + /// ``` + #[inline] + pub fn new_in(bump: &'bump Bump) -> Vec<'bump, T> { + Vec { + buf: RawVec::new_in(bump), + len: 0, + } + } + + /// Constructs a new, empty `Vec<'bump, T>` with the specified capacity. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = Vec::with_capacity_in(10, &b); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// ``` + #[inline] + pub fn with_capacity_in(capacity: usize, bump: &'bump Bump) -> Vec<'bump, T> { + Vec { + buf: RawVec::with_capacity_in(capacity, bump), + len: 0, + } + } + + /// Construct a new `Vec` from the given iterator's items. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// use std::iter; + /// + /// let b = Bump::new(); + /// let v = Vec::from_iter_in(iter::repeat(7).take(3), &b); + /// assert_eq!(v, [7, 7, 7]); + /// ``` + pub fn from_iter_in>(iter: I, bump: &'bump Bump) -> Vec<'bump, T> { + let mut v = Vec::new_in(bump); + v.extend(iter); + v + } + + /// Creates a `Vec<'bump, T>` directly from the raw components of another vector. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<'bump, T>` + /// (at least, it's highly likely to be incorrect if it wasn't). + /// * `ptr`'s `T` needs to have the same size and alignment as it was allocated with. + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is **not** safe + /// to build a `Vec` from a pointer to a C `char` array and a `size_t`. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec<'bump, T>` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: ../string/struct.String.html + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// use std::ptr; + /// use std::mem; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; 1, 2, 3]; + /// + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// + /// unsafe { + /// // Cast `v` into the void: no destructor run, so we are in + /// // complete control of the allocation to which `p` points. + /// mem::forget(v); + /// + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, &b); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } + /// ``` + pub unsafe fn from_raw_parts_in( + ptr: *mut T, + length: usize, + capacity: usize, + bump: &'bump Bump, + ) -> Vec<'bump, T> { + Vec { + buf: RawVec::from_raw_parts_in(ptr, capacity, bump), + len: length, + } + } + + /// Returns a shared reference to the allocator backing this `Vec`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// // uses the same allocator as the provided `Vec` + /// fn add_strings<'bump>(vec: &mut Vec<'bump, &'bump str>) { + /// for string in ["foo", "bar", "baz"] { + /// vec.push(vec.bump().alloc_str(string)); + /// } + /// } + /// ``` + #[inline] + #[must_use] + pub fn bump(&self) -> &'bump Bump { + self.buf.bump() + } + + /// Returns the number of elements the vector can hold without + /// reallocating. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let vec: Vec = Vec::with_capacity_in(10, &b); + /// assert_eq!(vec.capacity(), 10); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.buf.cap() + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the given `Vec<'bump, T>`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.reserve(10); + /// assert!(vec.capacity() >= 11); + /// ``` + pub fn reserve(&mut self, additional: usize) { + self.buf.reserve(self.len, additional); + } + + /// Reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `Vec<'bump, T>`. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.reserve_exact(10); + /// assert!(vec.capacity() >= 11); + /// ``` + pub fn reserve_exact(&mut self, additional: usize) { + self.buf.reserve_exact(self.len, additional); + } + + /// Attempts to reserve capacity for at least `additional` more elements to be inserted + /// in the given `Vec<'bump, T>`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.try_reserve(10).unwrap(); + /// assert!(vec.capacity() >= 11); + /// ``` + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.buf.try_reserve(self.len, additional) + } + + /// Attempts to reserve the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `Vec<'bump, T>`. After calling `try_reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `try_reserve` if future insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.try_reserve_exact(10).unwrap(); + /// assert!(vec.capacity() >= 11); + /// ``` + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.buf.try_reserve_exact(self.len, additional) + } + + /// Shrinks the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator + /// may still inform the vector that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = Vec::with_capacity_in(10, &b); + /// vec.extend([1, 2, 3].iter().cloned()); + /// assert_eq!(vec.capacity(), 10); + /// vec.shrink_to_fit(); + /// assert!(vec.capacity() >= 3); + /// ``` + pub fn shrink_to_fit(&mut self) { + if self.capacity() != self.len { + self.buf.shrink_to_fit(self.len); + } + } + + /// Converts the vector into `&'bump [T]`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let v = bumpalo::vec![in &b; 1, 2, 3]; + /// + /// let slice = v.into_bump_slice(); + /// assert_eq!(slice, [1, 2, 3]); + /// ``` + pub fn into_bump_slice(self) -> &'bump [T] { + unsafe { + let ptr = self.as_ptr(); + let len = self.len(); + mem::forget(self); + slice::from_raw_parts(ptr, len) + } + } + + /// Converts the vector into `&'bump mut [T]`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let v = bumpalo::vec![in &b; 1, 2, 3]; + /// + /// let mut slice = v.into_bump_slice_mut(); + /// + /// slice[0] = 3; + /// slice[2] = 1; + /// + /// assert_eq!(slice, [3, 2, 1]); + /// ``` + pub fn into_bump_slice_mut(mut self) -> &'bump mut [T] { + let ptr = self.as_mut_ptr(); + let len = self.len(); + mem::forget(self); + + unsafe { slice::from_raw_parts_mut(ptr, len) } + } + + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. + /// + /// If `len` is greater than the vector's current length, this has no + /// effect. + /// + /// The [`drain`] method can emulate `truncate`, but causes the excess + /// elements to be returned instead of dropped. + /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// + /// # Examples + /// + /// Truncating a five element vector to two elements: + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3, 4, 5]; + /// vec.truncate(2); + /// assert_eq!(vec, [1, 2]); + /// ``` + /// + /// No truncation occurs when `len` is greater than the vector's current + /// length: + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// vec.truncate(8); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// Truncating when `len == 0` is equivalent to calling the [`clear`] + /// method. + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// vec.truncate(0); + /// assert_eq!(vec, []); + /// ``` + /// + /// [`clear`]: #method.clear + /// [`drain`]: #method.drain + pub fn truncate(&mut self, len: usize) { + let current_len = self.len; + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len); + // Set the final length at the end, keeping in mind that + // dropping an element might panic. Works around a missed + // optimization, as seen in the following issue: + // https://github.com/rust-lang/rust/issues/51802 + let mut local_len = SetLenOnDrop::new(&mut self.len); + + // drop any extra elements + for _ in len..current_len { + local_len.decrement_len(1); + ptr = ptr.offset(-1); + ptr::drop_in_place(ptr); + } + } + } + + /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// use std::io::{self, Write}; + /// + /// let b = Bump::new(); + /// + /// let buffer = bumpalo::vec![in &b; 1, 2, 3, 5, 8]; + /// io::sink().write(buffer.as_slice()).unwrap(); + /// ``` + #[inline] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// use std::io::{self, Read}; + /// + /// let b = Bump::new(); + /// let mut buffer = bumpalo::vec![in &b; 0; 3]; + /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); + /// ``` + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer + /// valid for zero sized reads if the vector didn't allocate. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let bump = Bump::new(); + /// + /// let x = bumpalo::vec![in ≎ 1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(*x_ptr.add(i), 1 << i); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: Vec::as_mut_ptr + #[inline] + pub fn as_ptr(&self) -> *const T { + // We shadow the slice method of the same name to avoid going through + // `deref`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { + if ptr.is_null() { + core::hint::unreachable_unchecked(); + } + } + ptr + } + + /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling + /// raw pointer valid for zero sized reads if the vector didn't allocate. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let bump = Bump::new(); + /// + /// // Allocate vector big enough for 4 elements. + /// let size = 4; + /// let mut x: Vec = Vec::with_capacity_in(size, &bump); + /// let x_ptr = x.as_mut_ptr(); + /// + /// // Initialize elements via raw pointer writes, then set length. + /// unsafe { + /// for i in 0..size { + /// x_ptr.add(i).write(i as i32); + /// } + /// x.set_len(size); + /// } + /// assert_eq!(&*x, &[0, 1, 2, 3]); + /// ``` + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + // We shadow the slice method of the same name to avoid going through + // `deref_mut`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { + if ptr.is_null() { + core::hint::unreachable_unchecked(); + } + } + ptr + } + + /// Sets the length of a vector. + /// + /// This will explicitly set the size of the vector, without actually + /// modifying its buffers, so it is up to the caller to ensure that the + /// vector is actually the specified size. + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to [`capacity()`]. + /// - The elements at `old_len..new_len` must be initialized. + /// + /// [`capacity()`]: struct.Vec.html#method.capacity + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// use std::ptr; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 'r', 'u', 's', 't']; + /// + /// unsafe { + /// ptr::drop_in_place(&mut vec[3]); + /// vec.set_len(3); + /// } + /// assert_eq!(vec, ['r', 'u', 's']); + /// ``` + /// + /// In this example, there is a memory leak since the memory locations + /// owned by the inner vectors were not freed prior to the `set_len` call: + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; + /// bumpalo::vec![in &b; 1, 0, 0], + /// bumpalo::vec![in &b; 0, 1, 0], + /// bumpalo::vec![in &b; 0, 0, 1]]; + /// unsafe { + /// vec.set_len(0); + /// } + /// ``` + /// + /// In this example, the vector gets expanded from zero to four items + /// but we directly initialize uninitialized memory: + /// + // TODO: rely upon `spare_capacity_mut` + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let len = 4; + /// let b = Bump::new(); + /// + /// let mut vec: Vec = Vec::with_capacity_in(len, &b); + /// + /// for i in 0..len { + /// // SAFETY: we initialize memory via `pointer::write` + /// unsafe { vec.as_mut_ptr().add(i).write(b'a') } + /// } + /// + /// unsafe { + /// vec.set_len(len); + /// } + /// + /// assert_eq!(b"aaaa", &*vec); + /// ``` + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + self.len = new_len; + } + + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. + /// + /// This does not preserve ordering, but is O(1). + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; "foo", "bar", "baz", "qux"]; + /// + /// assert_eq!(v.swap_remove(1), "bar"); + /// assert_eq!(v, ["foo", "qux", "baz"]); + /// + /// assert_eq!(v.swap_remove(0), "foo"); + /// assert_eq!(v, ["baz", "qux"]); + /// ``` + #[inline] + pub fn swap_remove(&mut self, index: usize) -> T { + unsafe { + // We replace self[index] with the last element. Note that if the + // bounds check on hole succeeds there must be a last element (which + // can be self[index] itself). + let hole: *mut T = &mut self[index]; + let last = ptr::read(self.get_unchecked(self.len - 1)); + self.len -= 1; + ptr::replace(hole, last) + } + } + + /// Inserts an element at position `index` within the vector, shifting all + /// elements after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// vec.insert(1, 4); + /// assert_eq!(vec, [1, 4, 2, 3]); + /// vec.insert(4, 5); + /// assert_eq!(vec, [1, 4, 2, 3, 5]); + /// ``` + pub fn insert(&mut self, index: usize, element: T) { + let len = self.len(); + assert!(index <= len); + + // space for the new element + if len == self.buf.cap() { + self.reserve(1); + } + + unsafe { + // infallible + // The spot to put the new value + { + let p = self.as_mut_ptr().add(index); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + } + + /// Removes and returns the element at position `index` within the vector, + /// shifting all elements after it to the left. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; 1, 2, 3]; + /// assert_eq!(v.remove(1), 2); + /// assert_eq!(v, [1, 3]); + /// ``` + pub fn remove(&mut self, index: usize) -> T { + let len = self.len(); + assert!(index < len); + unsafe { + // infallible + let ret; + { + // the place we are taking from. + let ptr = self.as_mut_ptr().add(index); + // copy it out, unsafely having a copy of the value on + // the stack and in the vector at the same time. + ret = ptr::read(ptr); + + // Shift everything down to fill in that spot. + ptr::copy(ptr.offset(1), ptr, len - index - 1); + } + self.set_len(len - 1); + ret + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// This method operates in place and preserves the order of the retained + /// elements. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3, 4]; + /// vec.retain(|x: &i32| *x % 2 == 0); + /// assert_eq!(vec, [2, 4]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.drain_filter(|x| !f(x)); + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. + /// This method operates in place and preserves the order of the retained + /// elements. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3, 4]; + /// vec.retain_mut(|x: &mut i32| *x % 2 == 0); + /// assert_eq!(vec, [2, 4]); + /// ``` + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + self.drain_filter(|x| !f(x)); + } + + /// Creates an iterator that removes the elements in the vector + /// for which the predicate returns `true` and yields the removed items. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::Bump; + /// use bumpalo::collections::{CollectIn, Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut numbers = bumpalo::vec![in &b; 1, 2, 3, 4, 5]; + /// + /// let evens: Vec<_> = numbers.drain_filter(|x| *x % 2 == 0).collect_in(&b); + /// + /// assert_eq!(numbers, &[1, 3, 5]); + /// assert_eq!(evens, &[2, 4]); + /// ``` + pub fn drain_filter<'a, F>(&'a mut self, filter: F) -> DrainFilter<'a, 'bump, T, F> + where + F: FnMut(&mut T) -> bool, + { + let old_len = self.len(); + + // Guard against us getting leaked (leak amplification) + unsafe { + self.set_len(0); + } + + DrainFilter { + vec: self, + idx: 0, + del: 0, + old_len, + pred: filter, + } + } + + /// Removes all but the first of consecutive elements in the vector that resolve to the same + /// key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 10, 20, 21, 30, 20]; + /// + /// vec.dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(vec, [10, 20, 30, 20]); + /// ``` + #[inline] + pub fn dedup_by_key(&mut self, mut key: F) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.dedup_by(|a, b| key(a) == key(b)) + } + + /// Removes all but the first of consecutive elements in the vector satisfying a given equality + /// relation. + /// + /// The `same_bucket` function is passed references to two elements from the vector and + /// must determine if the elements compare equal. The elements are passed in opposite order + /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; "foo", "bar", "Bar", "baz", "bar"]; + /// + /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// + /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` + pub fn dedup_by(&mut self, same_bucket: F) + where + F: FnMut(&mut T, &mut T) -> bool, + { + let len = { + let (dedup, _) = partition_dedup_by(self.as_mut_slice(), same_bucket); + dedup.len() + }; + self.truncate(len); + } + + // Proven specification with verus, converted to comments. + /// # Preconditions + /// + /// - old(self).len() < old(self).capacity(), + /// + /// # Postconditions + /// + /// - self.get_unchecked(old(self).len()) == value, + /// - self.len() == old(self).len() + 1, + /// - self.capacity() == old(self).capacity(), + /// - forall|i: usize| implies( + /// i < old(self).len(), + /// self.get_unchecked(i) == old(self).get_unchecked(i) + /// ) + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn push_unchecked(&mut self, value: T) { + debug_assert!(self.len() < self.capacity()); + + // Divergence from verified impl: + // Verified implementation has special handling for ZSTs + // as ZSTs do not play nicely with separation logic. + ptr::write(self.buf.ptr().add(self.len), value); + + self.len = self.len + 1; + } + + /// Appends an element to the back of a vector. + /// + /// # Panics + /// + /// Panics if the number of elements in the vector overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2]; + /// vec.push(3); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + pub fn push(&mut self, value: T) { + // This will panic or abort if we would allocate > isize::MAX bytes + // or if the length increment would overflow for zero-sized types. + if self.len == self.buf.cap() { + self.reserve(1); + } + unsafe { + self.push_unchecked(value); + } + } + + /// Removes the last element from a vector and returns it, or [`None`] if it + /// is empty. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// assert_eq!(vec.pop(), Some(3)); + /// assert_eq!(vec, [1, 2]); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + unsafe { + self.len -= 1; + Some(ptr::read(self.as_ptr().add(self.len()))) + } + } + } + + /// Removes and returns the last element from a vector if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the vector + /// is empty (the predicate will not be called in that case). + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3, 4]; + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(vec.pop_if(pred), Some(4)); + /// assert_eq!(vec, [1, 2, 3]); + /// assert_eq!(vec.pop_if(pred), None); + /// ``` + #[inline] + pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { + let last = self.last_mut()?; + if predicate(last) { + self.pop() + } else { + None + } + } + + /// Moves all the elements of `other` into `Self`, leaving `other` empty. + /// + /// # Panics + /// + /// Panics if the number of elements in the vector overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// let mut vec2 = bumpalo::vec![in &b; 4, 5, 6]; + /// vec.append(&mut vec2); + /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(vec2, []); + /// ``` + #[inline] + pub fn append(&mut self, other: &mut Self) { + unsafe { + self.append_elements(other.as_slice() as _); + other.set_len(0); + } + } + + /// Appends elements to `Self` from other buffer. + #[inline] + unsafe fn append_elements(&mut self, other: *const [T]) { + let count = (&(*other)).len(); + self.reserve(count); + let len = self.len(); + ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count); + self.len += count; + } + + /// Creates a draining iterator that removes the specified range in the vector + /// and yields the removed items. + /// + /// Note 1: The element range is removed even if the iterator is only + /// partially consumed or not consumed at all. + /// + /// Note 2: It is unspecified how many elements are removed from the vector + /// if the `Drain` value is leaked. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::Bump; + /// use bumpalo::collections::{CollectIn, Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; 1, 2, 3]; + /// + /// let u: Vec<_> = v.drain(1..).collect_in(&b); + /// + /// assert_eq!(v, &[1]); + /// assert_eq!(u, &[2, 3]); + /// + /// // A full range clears the vector + /// v.drain(..); + /// assert_eq!(v, &[]); + /// ``` + pub fn drain<'a, R>(&'a mut self, range: R) -> Drain<'a, 'bump, T> + where + R: RangeBounds, + { + // Memory safety + // + // When the Drain is first created, it shortens the length of + // the source vector to make sure no uninitialized or moved-from elements + // are accessible at all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, remaining tail of the vec is copied back to cover + // the hole, and the vector length is restored to the new length. + // + let len = self.len(); + let start = match range.start_bound() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end_bound() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + assert!(start <= end); + assert!(end <= len); + + unsafe { + // set self.vec length's to start, to be safe in case Drain is leaked + self.set_len(start); + // Use the borrow in the IterMut to indicate borrowing behavior of the + // whole Drain iterator (like &mut T). + let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start); + Drain { + tail_start: end, + tail_len: len - end, + iter: range_slice.iter(), + vec: NonNull::from(self), + } + } + } + + /// Clears the vector, removing all values. + /// + /// Note that this method has no effect on the allocated capacity + /// of the vector. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; 1, 2, 3]; + /// + /// v.clear(); + /// + /// assert!(v.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.truncate(0) + } + + /// Returns the number of elements in the vector, also referred to + /// as its 'length'. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let a = bumpalo::vec![in &b; 1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns `true` if the vector contains no elements. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = Vec::new_in(&b); + /// assert!(v.is_empty()); + /// + /// v.push(1); + /// assert!(!v.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated vector. `self` contains elements `[0, at)`, + /// and the returned vector contains elements `[at, len)`. + /// + /// Note that the capacity of `self` does not change. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3]; + /// let vec2 = vec.split_off(1); + /// assert_eq!(vec, [1]); + /// assert_eq!(vec2, [2, 3]); + /// ``` + #[inline] + pub fn split_off(&mut self, at: usize) -> Self { + assert!(at <= self.len(), "`at` out of bounds"); + + let other_len = self.len - at; + let mut other = Vec::with_capacity_in(other_len, self.buf.bump()); + + // Unsafely `set_len` and copy items to `other`. + unsafe { + self.set_len(at); + other.set_len(other_len); + + ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len()); + } + other + } +} + +#[cfg(feature = "boxed")] +impl<'bump, T> Vec<'bump, T> { + /// Converts the vector into [`Box<[T]>`][owned slice]. + /// + /// Note that this will drop any excess capacity. + /// + /// [owned slice]: ../../boxed/struct.Box.html + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec, vec}; + /// + /// let b = Bump::new(); + /// + /// let v = vec![in &b; 1, 2, 3]; + /// + /// let slice = v.into_boxed_slice(); + /// ``` + pub fn into_boxed_slice(mut self) -> crate::boxed::Box<'bump, [T]> { + use crate::boxed::Box; + + // Unlike `alloc::vec::Vec` shrinking here isn't necessary as `bumpalo::boxed::Box` doesn't own memory. + unsafe { + let slice = slice::from_raw_parts_mut(self.as_mut_ptr(), self.len); + let output: Box<'bump, [T]> = Box::from_raw(slice); + mem::forget(self); + output + } + } +} + +impl<'bump, T: 'bump + Clone> Vec<'bump, T> { + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with `value`. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method requires [`Clone`] to be able clone the passed value. If + /// you need more flexibility (or want to rely on [`Default`] instead of + /// [`Clone`]), use [`resize_with`]. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; "hello"]; + /// vec.resize(3, "world"); + /// assert_eq!(vec, ["hello", "world", "world"]); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 3, 4]; + /// vec.resize(2, 0); + /// assert_eq!(vec, [1, 2]); + /// ``` + /// + /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html + /// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html + /// [`resize_with`]: #method.resize_with + pub fn resize(&mut self, new_len: usize, value: T) { + let len = self.len(); + + if new_len > len { + self.extend_with(new_len - len, ExtendElement(value)) + } else { + self.truncate(new_len); + } + } + + // Proven specification with verus, converted to comments. + /// # Preconditions + /// + /// - old(self).len() + slice.len() <= old(self).capacity(), + /// + /// # Postconditions + /// + /// - forall|i: usize| implies( + /// i < old(self).len(), + /// self.get_unchecked(i) == old(self).get_unchecked(i) + /// ), + /// - forall|i: usize| implies( + /// i < slice.len(), + /// self.get_unchecked((old(self).len() + i) as usize) + /// == clone(slice.get_unchecked(i)) + /// ), + /// - self.len() == old(self).len() + slice.len(), + /// - self.capacity() == old(self).capacity(), + #[inline] + unsafe fn extend_from_slice_unchecked(&mut self, slice: &[T]) { + // Guaranteed never to overflow for non ZSTs + // size_of::() <= isize::MAX - (isize::MAX % align_of::())) + // isize::MAX + isize::MAX < usize::MAX + debug_assert!( + core::mem::size_of::() == 0 || self.capacity() >= self.len() + slice.len() + ); + debug_assert!( + // is_zst::() ==> capacity >= slen + slice.len() + core::mem::size_of::() != 0 + // Capacity is usize::MAX for ZSTs + || self.len() <= usize::MAX - slice.len() + ); + + let mut pos = 0usize; + + loop + /* + invariants + pos <= slice.len(), + self.len() + (slice.len() - pos) <= old(self).capacity(), + old(self).capacity() == self.capacity(), + + self.len() == old(self).len() + pos, + + forall|i: usize| implies( + i < old(self).len(), + self.get_unchecked(i) == old(self).get_unchecked(i) + ), + forall|i: usize| implies( + i < pos, + self.get_unchecked((old(self).len() + i) as usize) + == clone(slice.get_unchecked(i)) + ) + */ + { + if pos == slice.len() { + /* + pos = slice.len(), + self.len() = old(self).len() + slice.len(), + + forall|i: usize| i < slice.len() implies { + self.get_unchecked((old(self).len() + i) as usize) + == clone(slice.get_unchecked(i)) + } + by { + i < pos + } + */ + return; + } + + /* + pos < slice.len(), + self.len() < self.capacity() + */ + + let elem = slice.get_unchecked(pos); + self.push_unchecked(elem.clone()); + + /* + ghost prev_pos = pos + */ + + pos = pos + 1; + + /* + forall|i: usize| i < pos implies { + self.get_unchecked((old(self).len() + i) as usize) + == clone(slice.get_unchecked(i)) + } + by { + if i < pos - 1 { + // By invariant + } + else { + i == prev_pos + } + } + */ + } + } + + /// Clones and appends all elements in a slice to the `Vec`. + /// + /// Iterates over the slice `other`, clones each element, and then appends + /// it to this `Vec`. The `other` vector is traversed in-order. + /// + /// Note that this function is same as [`extend`] except that it is + /// specialized to work with slices instead. If and when Rust gets + /// specialization this function will likely be deprecated (but still + /// available). + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.extend_from_slice(&[2, 3, 4]); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// [`extend`]: #method.extend + pub fn extend_from_slice(&mut self, other: &[T]) { + let capacity = self.capacity(); + + /* + Cannot underflow via invariant of the Vec (capacity >= length). + + This also holds for ZSTs, as capacity is usize::MAX + */ + let remaining_cap = capacity - self.len; + + /* + self.len() + other.len() <= self.capacity(), + <==> + other.len() <= self.capacity() - self.len() + */ + + if other.len() > remaining_cap { + /* + Divergence from verified impl: + Verified implementation's reserve is not the same + as bumpalo's. Verified implementation reserves with + respect to capacity, not length. Thus this is equivalent + to the verified implementation's: + + self.buf.reserve(other.len() - remaining_cap) + + */ + self.reserve(other.len()); + } + + /* + self.capacity() >= self.len() + other.len() + */ + + unsafe { + self.extend_from_slice_unchecked(other); + } + } +} + +impl<'bump, T: 'bump + Copy> Vec<'bump, T> { + /// Helper method to copy all of the items in `other` and append them to the end of `self`. + /// + /// SAFETY: + /// * The caller is responsible for: + /// * calling [`reserve`](Self::reserve) beforehand to guarantee that there is enough + /// capacity to store `other.len()` more items. + /// * guaranteeing that `self` and `other` do not overlap. + unsafe fn extend_from_slice_copy_unchecked(&mut self, other: &[T]) { + let old_len = self.len(); + debug_assert!(old_len + other.len() <= self.capacity()); + + // SAFETY: + // * `src` is valid for reads of `other.len()` values by virtue of being a `&[T]`. + // * `dst` is valid for writes of `other.len()` bytes because the caller of this + // method is required to `reserve` capacity to store at least `other.len()` items + // beforehand. + // * Because `src` is a `&[T]` and dst is a `&[T]` within the `Vec`, + // `copy_nonoverlapping`'s alignment requirements are met. + // * Caller is required to guarantee that the source and destination ranges cannot overlap + unsafe { + let src = other.as_ptr(); + let dst = self.as_mut_ptr().add(old_len); + ptr::copy_nonoverlapping(src, dst, other.len()); + self.set_len(old_len + other.len()); + } + } + + /// Copies all elements in the slice `other` and appends them to the `Vec`. + /// + /// Note that this function is same as [`extend_from_slice`] except that it is optimized for + /// slices of types that implement the `Copy` trait. If and when Rust gets specialization + /// this function will likely be deprecated (but still available). + /// + /// To copy and append the data from multiple source slices at once, see + /// [`extend_from_slices_copy`]. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.extend_from_slice_copy(&[2, 3, 4]); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 'H' as u8]; + /// vec.extend_from_slice_copy("ello, world!".as_bytes()); + /// assert_eq!(vec, "Hello, world!".as_bytes()); + /// ``` + /// + /// [`extend_from_slice`]: #method.extend_from_slice + /// [`extend_from_slices`]: #method.extend_from_slices + pub fn extend_from_slice_copy(&mut self, other: &[T]) { + // Reserve space in the Vec for the values to be added + self.reserve(other.len()); + + // Copy values into the space that was just reserved + // SAFETY: + // * `self` has enough capacity to store `other.len()` more items as `self.reserve(other.len())` + // above guarantees that. + // * Source and destination data ranges cannot overlap as we just reserved the destination + // range from the bump. + unsafe { + self.extend_from_slice_copy_unchecked(other); + } + } + + /// For each slice in `slices`, copies all elements in the slice and appends them to the `Vec`. + /// + /// This method is equivalent to calling [`extend_from_slice_copy`] in a loop, but is able + /// to precompute the total amount of space to reserve in advance. This reduces the potential + /// maximum number of reallocations needed from one-per-slice to just one. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1]; + /// vec.extend_from_slices_copy(&[&[2, 3], &[], &[4]]); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 'H' as u8]; + /// vec.extend_from_slices_copy(&["ello,".as_bytes(), &[], " world!".as_bytes()]); + /// assert_eq!(vec, "Hello, world!".as_bytes()); + /// ``` + /// + /// [`extend_from_slice_copy`]: #method.extend_from_slice_copy + pub fn extend_from_slices_copy(&mut self, slices: &[&[T]]) { + // Reserve the total amount of capacity we'll need to safely append the aggregated contents + // of each slice in `slices`. + let capacity_to_reserve: usize = slices.iter().map(|slice| slice.len()).sum(); + self.reserve(capacity_to_reserve); + + // SAFETY: + // * `dst` is valid for writes of `capacity_to_reserve` items as + // `self.reserve(capacity_to_reserve)` above guarantees that. + // * Source and destination ranges cannot overlap as we just reserved the destination + // range from the bump. + unsafe { + // Copy the contents of each slice onto the end of `self` + slices.iter().for_each(|slice| { + self.extend_from_slice_copy_unchecked(slice); + }); + } + } +} + +// This code generalises `extend_with_{element,default}`. +trait ExtendWith { + fn next(&mut self) -> T; + fn last(self) -> T; +} + +struct ExtendElement(T); +impl ExtendWith for ExtendElement { + fn next(&mut self) -> T { + self.0.clone() + } + fn last(self) -> T { + self.0 + } +} + +impl<'bump, T: 'bump> Vec<'bump, T> { + /// Extend the vector by `n` values, using the given generator. + fn extend_with>(&mut self, n: usize, mut value: E) { + self.reserve(n); + + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + // Use SetLenOnDrop to work around bug where compiler + // may not realize the store through `ptr` through self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + + // Write all elements except the last one + for _ in 1..n { + ptr::write(ptr, value.next()); + ptr = ptr.offset(1); + // Increment the length in every step in case next() panics + local_len.increment_len(1); + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, value.last()); + local_len.increment_len(1); + } + + // len set by scope guard + } + } +} + +// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +// +// The idea is: The length field in SetLenOnDrop is a local variable +// that the optimizer will see does not alias with any stores through the Vec's data +// pointer. This is a workaround for alias analysis issue #32155 +struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { + local_len: *len, + len, + } + } + + #[inline] + fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } + + #[inline] + fn decrement_len(&mut self, decrement: usize) { + self.local_len -= decrement; + } +} + +impl<'a> Drop for SetLenOnDrop<'a> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} + +impl<'bump, T: 'bump + PartialEq> Vec<'bump, T> { + /// Removes consecutive repeated elements in the vector according to the + /// [`PartialEq`] trait implementation. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut vec = bumpalo::vec![in &b; 1, 2, 2, 3, 2]; + /// + /// vec.dedup(); + /// + /// assert_eq!(vec, [1, 2, 3, 2]); + /// ``` + #[inline] + pub fn dedup(&mut self) { + self.dedup_by(|a, b| a == b) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Common trait implementations for Vec +//////////////////////////////////////////////////////////////////////////////// + +impl<'bump, T: 'bump + Clone> Clone for Vec<'bump, T> { + #[cfg(not(test))] + fn clone(&self) -> Vec<'bump, T> { + let mut v = Vec::with_capacity_in(self.len(), self.buf.bump()); + v.extend(self.iter().cloned()); + v + } + + // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is + // required for this method definition, is not available. Instead use the + // `slice::to_vec` function which is only available with cfg(test) + // NB see the slice::hack module in slice.rs for more information + #[cfg(test)] + fn clone(&self) -> Vec<'bump, T> { + let mut v = Vec::new_in(self.buf.bump()); + v.extend(self.iter().cloned()); + v + } +} + +impl<'bump, T: 'bump + Hash> Hash for Vec<'bump, T> { + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} + +impl<'bump, T, I> Index for Vec<'bump, T> +where + I: ::core::slice::SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(&**self, index) + } +} + +impl<'bump, T, I> IndexMut for Vec<'bump, T> +where + I: ::core::slice::SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut **self, index) + } +} + +impl<'bump, T: 'bump> ops::Deref for Vec<'bump, T> { + type Target = [T]; + + fn deref(&self) -> &[T] { + unsafe { + let p = self.buf.ptr(); + // assume(!p.is_null()); + slice::from_raw_parts(p, self.len) + } + } +} + +impl<'bump, T: 'bump> ops::DerefMut for Vec<'bump, T> { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { + let ptr = self.buf.ptr(); + // assume(!ptr.is_null()); + slice::from_raw_parts_mut(ptr, self.len) + } + } +} + +impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> { + type Item = T; + type IntoIter = IntoIter<'bump, T>; + + /// Creates a consuming iterator, that is, one that moves each value out of + /// the vector (from start to end). The vector cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let v = bumpalo::vec![in &b; "a".to_string(), "b".to_string()]; + /// for s in v.into_iter() { + /// // s has type String, not &String + /// println!("{}", s); + /// } + /// ``` + #[inline] + fn into_iter(mut self) -> IntoIter<'bump, T> { + unsafe { + let begin = self.as_mut_ptr(); + // assume(!begin.is_null()); + let end = if mem::size_of::() == 0 { + arith_offset(begin as *const i8, self.len() as isize) as *const T + } else { + begin.add(self.len()) as *const T + }; + mem::forget(self); + IntoIter { + phantom: PhantomData, + ptr: begin, + end, + } + } + } +} + +impl<'a, 'bump, T> IntoIterator for &'a Vec<'bump, T> { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + fn into_iter(self) -> slice::Iter<'a, T> { + self.iter() + } +} + +impl<'a, 'bump, T> IntoIterator for &'a mut Vec<'bump, T> { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + fn into_iter(self) -> slice::IterMut<'a, T> { + self.iter_mut() + } +} + +impl<'bump, T: 'bump> Extend for Vec<'bump, T> { + #[inline] + fn extend>(&mut self, iter: I) { + let iter = iter.into_iter(); + self.reserve(iter.size_hint().0); + + for t in iter { + self.push(t); + } + } +} + +impl<'bump, T: 'bump> Vec<'bump, T> { + /// Creates a splicing iterator that replaces the specified range in the vector + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// Note 1: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// Note 2: It is unspecified how many elements are removed from the vector, + /// if the `Splice` value is leaked. + /// + /// Note 3: The input iterator `replace_with` is only consumed + /// when the `Splice` value is dropped. + /// + /// Note 4: This is optimal if: + /// + /// * The tail (elements in the vector after `range`) is empty, + /// * or `replace_with` yields fewer elements than `range`’s length + /// * or the lower bound of its `size_hint()` is exact. + /// + /// Otherwise, a temporary vector is allocated and the tail is moved twice. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let mut v = bumpalo::vec![in &b; 1, 2, 3]; + /// let new = [7, 8]; + /// let u: Vec<_> = Vec::from_iter_in(v.splice(..2, new.iter().cloned()), &b); + /// assert_eq!(v, &[7, 8, 3]); + /// assert_eq!(u, &[1, 2]); + /// ``` + #[inline] + pub fn splice<'a, R, I>( + &'a mut self, + range: R, + replace_with: I, + ) -> Splice<'a, 'bump, I::IntoIter> + where + R: RangeBounds, + I: IntoIterator, + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } + } +} + +/// Extend implementation that copies elements out of references before pushing them onto the Vec. +/// +/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to +/// append the entire slice at once. +/// +/// [`copy_from_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice +impl<'a, 'bump, T: 'a + Copy> Extend<&'a T> for Vec<'bump, T> { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()) + } +} + +macro_rules! __impl_slice_eq1 { + ($Lhs: ty, $Rhs: ty) => { + __impl_slice_eq1! { $Lhs, $Rhs, Sized } + }; + ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs + where + A: PartialEq, + { + #[inline] + fn eq(&self, other: &$Rhs) -> bool { + self[..] == other[..] + } + } + }; +} + +__impl_slice_eq1! { Vec<'a, A>, Vec<'b, B> } +__impl_slice_eq1! { Vec<'a, A>, &'b [B] } +__impl_slice_eq1! { Vec<'a, A>, &'b mut [B] } +// __impl_slice_eq1! { Cow<'a, [A]>, Vec<'b, B>, Clone } + +macro_rules! __impl_slice_eq1_array { + ($Lhs: ty, $Rhs: ty) => { + impl<'a, 'b, A, B, const N: usize> PartialEq<$Rhs> for $Lhs + where + A: PartialEq, + { + #[inline] + fn eq(&self, other: &$Rhs) -> bool { + self[..] == other[..] + } + } + }; +} + +__impl_slice_eq1_array! { Vec<'a, A>, [B; N] } +__impl_slice_eq1_array! { Vec<'a, A>, &'b [B; N] } +__impl_slice_eq1_array! { Vec<'a, A>, &'b mut [B; N] } + +/// Implements comparison of vectors, lexicographically. +impl<'bump, T: 'bump + PartialOrd> PartialOrd for Vec<'bump, T> { + #[inline] + fn partial_cmp(&self, other: &Vec<'bump, T>) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +impl<'bump, T: 'bump + Eq> Eq for Vec<'bump, T> {} + +/// Implements ordering of vectors, lexicographically. +impl<'bump, T: 'bump + Ord> Ord for Vec<'bump, T> { + #[inline] + fn cmp(&self, other: &Vec<'bump, T>) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl<'bump, T: 'bump + fmt::Debug> fmt::Debug for Vec<'bump, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'bump, T: 'bump> AsRef> for Vec<'bump, T> { + fn as_ref(&self) -> &Vec<'bump, T> { + self + } +} + +impl<'bump, T: 'bump> AsMut> for Vec<'bump, T> { + fn as_mut(&mut self) -> &mut Vec<'bump, T> { + self + } +} + +impl<'bump, T: 'bump> AsRef<[T]> for Vec<'bump, T> { + fn as_ref(&self) -> &[T] { + self + } +} + +impl<'bump, T: 'bump> AsMut<[T]> for Vec<'bump, T> { + fn as_mut(&mut self) -> &mut [T] { + self + } +} + +#[cfg(feature = "boxed")] +impl<'bump, T: 'bump> From> for crate::boxed::Box<'bump, [T]> { + fn from(v: Vec<'bump, T>) -> crate::boxed::Box<'bump, [T]> { + v.into_boxed_slice() + } +} + +impl<'bump, T: 'bump> Borrow<[T]> for Vec<'bump, T> { + #[inline] + fn borrow(&self) -> &[T] { + &self[..] + } +} + +impl<'bump, T: 'bump> BorrowMut<[T]> for Vec<'bump, T> { + #[inline] + fn borrow_mut(&mut self) -> &mut [T] { + &mut self[..] + } +} + +impl<'bump, T> Drop for Vec<'bump, T> { + fn drop(&mut self) { + unsafe { + // use drop for [T] + // use a raw slice to refer to the elements of the vector as weakest necessary type; + // could avoid questions of validity in certain cases + ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len)) + } + // RawVec handles deallocation + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Clone-on-write +//////////////////////////////////////////////////////////////////////////////// + +// impl<'a, 'bump, T: Clone> From> for Cow<'a, [T]> { +// fn from(v: Vec<'bump, T>) -> Cow<'a, [T]> { +// Cow::Owned(v) +// } +// } + +// impl<'a, 'bump, T: Clone> From<&'a Vec<'bump, T>> for Cow<'a, [T]> { +// fn from(v: &'a Vec<'bump, T>) -> Cow<'a, [T]> { +// Cow::Borrowed(v.as_slice()) +// } +// } + +//////////////////////////////////////////////////////////////////////////////// +// Iterators +//////////////////////////////////////////////////////////////////////////////// + +/// An iterator that moves out of a vector. +/// +/// This `struct` is created by the [`Vec::into_iter`] method +/// (provided by the [`IntoIterator`] trait). +/// +/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html +pub struct IntoIter<'bump, T> { + phantom: PhantomData<&'bump [T]>, + ptr: *const T, + end: *const T, +} + +impl<'bump, T: fmt::Debug> fmt::Debug for IntoIter<'bump, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +impl<'bump, T: 'bump> IntoIter<'bump, T> { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let vec = bumpalo::vec![in &b; 'a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// let _ = into_iter.next().unwrap(); + /// assert_eq!(into_iter.as_slice(), &['b', 'c']); + /// ``` + pub fn as_slice(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.ptr, self.len()) } + } + + /// Returns the remaining items of this iterator as a mutable slice. + /// + /// # Examples + /// + /// ``` + /// use bumpalo::{Bump, collections::Vec}; + /// + /// let b = Bump::new(); + /// + /// let vec = bumpalo::vec![in &b; 'a', 'b', 'c']; + /// let mut into_iter = vec.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// into_iter.as_mut_slice()[2] = 'z'; + /// assert_eq!(into_iter.next().unwrap(), 'a'); + /// assert_eq!(into_iter.next().unwrap(), 'b'); + /// assert_eq!(into_iter.next().unwrap(), 'z'); + /// ``` + pub fn as_mut_slice(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self.ptr as *mut T, self.len()) } + } +} + +unsafe impl<'bump, T: Send> Send for IntoIter<'bump, T> {} +unsafe impl<'bump, T: Sync> Sync for IntoIter<'bump, T> {} + +impl<'bump, T: 'bump> Iterator for IntoIter<'bump, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + unsafe { + if self.ptr as *const _ == self.end { + None + } else if mem::size_of::() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T; + + // Make up a value of this ZST. + Some(mem::zeroed()) + } else { + let old = self.ptr; + self.ptr = self.ptr.offset(1); + + Some(ptr::read(old)) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let exact = if mem::size_of::() == 0 { + (self.end as usize).wrapping_sub(self.ptr as usize) + } else { + unsafe { offset_from(self.end, self.ptr) as usize } + }; + (exact, Some(exact)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } +} + +impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<'bump, T> { + #[inline] + fn next_back(&mut self) -> Option { + unsafe { + if self.end == self.ptr { + None + } else if mem::size_of::() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = arith_offset(self.end as *const i8, -1) as *mut T; + + // Make up a value of this ZST. + Some(mem::zeroed()) + } else { + self.end = self.end.offset(-1); + + Some(ptr::read(self.end)) + } + } + } +} + +impl<'bump, T: 'bump> ExactSizeIterator for IntoIter<'bump, T> {} + +impl<'bump, T: 'bump> FusedIterator for IntoIter<'bump, T> {} + +impl<'bump, T> Drop for IntoIter<'bump, T> { + fn drop(&mut self) { + // drop all remaining elements + self.for_each(drop); + } +} + +/// A draining iterator for `Vec<'bump, T>`. +/// +/// This `struct` is created by the [`Vec::drain`] method. +pub struct Drain<'a, 'bump, T: 'a + 'bump> { + /// Index of tail to preserve + tail_start: usize, + /// Length of tail + tail_len: usize, + /// Current remaining range to remove + iter: slice::Iter<'a, T>, + vec: NonNull>, +} + +impl<'a, 'bump, T: 'a + 'bump + fmt::Debug> fmt::Debug for Drain<'a, 'bump, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() + } +} + +unsafe impl<'a, 'bump, T: Sync> Sync for Drain<'a, 'bump, T> {} +unsafe impl<'a, 'bump, T: Send> Send for Drain<'a, 'bump, T> {} + +impl<'a, 'bump, T> Iterator for Drain<'a, 'bump, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter + .next() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, 'bump, T> DoubleEndedIterator for Drain<'a, 'bump, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter + .next_back() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } +} + +impl<'a, 'bump, T> Drop for Drain<'a, 'bump, T> { + fn drop(&mut self) { + // exhaust self first + self.for_each(drop); + + if self.tail_len > 0 { + unsafe { + let source_vec = self.vec.as_mut(); + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.tail_start; + if tail != start { + let src = source_vec.as_ptr().add(tail); + let dst = source_vec.as_mut_ptr().add(start); + ptr::copy(src, dst, self.tail_len); + } + source_vec.set_len(start + self.tail_len); + } + } + } +} + +impl<'a, 'bump, T> ExactSizeIterator for Drain<'a, 'bump, T> {} + +impl<'a, 'bump, T> FusedIterator for Drain<'a, 'bump, T> {} + +/// A splicing iterator for `Vec`. +/// +/// This struct is created by the [`Vec::splice`] method. See its +/// documentation for more information. +#[derive(Debug)] +pub struct Splice<'a, 'bump, I> +where + I: Iterator, + I::Item: 'a + 'bump, +{ + drain: Drain<'a, 'bump, I::Item>, + replace_with: I, +} + +impl<'a, 'bump, I: Iterator> Iterator for Splice<'a, 'bump, I> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl<'a, 'bump, I: Iterator> DoubleEndedIterator for Splice<'a, 'bump, I> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +impl<'a, 'bump, I: Iterator> ExactSizeIterator for Splice<'a, 'bump, I> {} + +impl<'a, 'bump, I: Iterator> Drop for Splice<'a, 'bump, I> { + fn drop(&mut self) { + self.drain.by_ref().for_each(drop); + + unsafe { + if self.drain.tail_len == 0 { + self.drain.vec.as_mut().extend(self.replace_with.by_ref()); + return; + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return; + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return; + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = Vec::new_in(self.drain.vec.as_ref().buf.bump()); + collected.extend(self.replace_with.by_ref()); + let mut collected = collected.into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl<'a, 'bump, T> Drain<'a, 'bump, T> { + /// The range from `self.vec.len` to `self.tail_start` contains elements + /// that have been moved out. + /// Fill that range as much as possible with new elements from the `replace_with` iterator. + /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.) + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = self.vec.as_mut(); + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = + slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start); + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + ptr::write(place, new_item); + vec.len += 1; + } else { + return false; + } + } + true + } + + /// Make room for inserting more elements before the tail. + unsafe fn move_tail(&mut self, extra_capacity: usize) { + let vec = self.vec.as_mut(); + let used_capacity = self.tail_start + self.tail_len; + vec.buf.reserve(used_capacity, extra_capacity); + + let new_tail_start = self.tail_start + extra_capacity; + let src = vec.as_ptr().add(self.tail_start); + let dst = vec.as_mut_ptr().add(new_tail_start); + ptr::copy(src, dst, self.tail_len); + self.tail_start = new_tail_start; + } +} + +/// An iterator produced by calling [`Vec::drain_filter`]. +#[derive(Debug)] +pub struct DrainFilter<'a, 'bump: 'a, T: 'a + 'bump, F> +where + F: FnMut(&mut T) -> bool, +{ + vec: &'a mut Vec<'bump, T>, + idx: usize, + del: usize, + old_len: usize, + pred: F, +} + +impl<'a, 'bump, T, F> Iterator for DrainFilter<'a, 'bump, T, F> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + while self.idx != self.old_len { + let i = self.idx; + self.idx += 1; + let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); + if (self.pred)(&mut v[i]) { + self.del += 1; + return Some(ptr::read(&v[i])); + } else if self.del > 0 { + let del = self.del; + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + // This is safe because self.vec has length 0 + // thus its elements will not have Drop::drop + // called on them in the event of a panic. + ptr::copy_nonoverlapping(src, dst, 1); + } + } + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +impl<'a, 'bump, T, F> Drop for DrainFilter<'a, 'bump, T, F> +where + F: FnMut(&mut T) -> bool, +{ + fn drop(&mut self) { + self.for_each(drop); + unsafe { + self.vec.set_len(self.old_len - self.del); + } + } +} + +#[cfg(feature = "std")] +impl<'bump> io::Write for Vec<'bump, u8> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice_copy(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice_copy(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "serde")] +mod serialize { + use super::*; + + use serde::{ser::SerializeSeq, Serialize, Serializer}; + + impl<'a, T> Serialize for Vec<'a, T> + where + T: Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.len))?; + for e in self.iter() { + seq.serialize_element(e)?; + } + seq.end() + } + } +} diff --git a/deps/crates/vendor/bumpalo/src/lib.rs b/deps/crates/vendor/bumpalo/src/lib.rs new file mode 100644 index 00000000000000..49050129d732a7 --- /dev/null +++ b/deps/crates/vendor/bumpalo/src/lib.rs @@ -0,0 +1,2650 @@ +#![doc = include_str!("../README.md")] +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "allocator_api", feature(allocator_api))] + +#[doc(hidden)] +pub extern crate alloc as core_alloc; + +#[cfg(feature = "boxed")] +pub mod boxed; +#[cfg(feature = "collections")] +pub mod collections; + +mod alloc; + +use core::cell::Cell; +use core::cmp::Ordering; +use core::fmt::Display; +use core::iter; +use core::marker::PhantomData; +use core::mem; +use core::ptr::{self, NonNull}; +use core::slice; +use core::str; +use core_alloc::alloc::{alloc, dealloc, Layout}; + +#[cfg(feature = "allocator_api")] +use core_alloc::alloc::{AllocError, Allocator}; + +#[cfg(all(feature = "allocator-api2", not(feature = "allocator_api")))] +use allocator_api2::alloc::{AllocError, Allocator}; + +pub use alloc::AllocErr; + +/// An error returned from [`Bump::try_alloc_try_with`]. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocOrInitError { + /// Indicates that the initial allocation failed. + Alloc(AllocErr), + /// Indicates that the initializer failed with the contained error after + /// allocation. + /// + /// It is possible but not guaranteed that the allocated memory has been + /// released back to the allocator at this point. + Init(E), +} +impl From for AllocOrInitError { + fn from(e: AllocErr) -> Self { + Self::Alloc(e) + } +} +impl Display for AllocOrInitError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + AllocOrInitError::Alloc(err) => err.fmt(f), + AllocOrInitError::Init(err) => write!(f, "initialization failed: {}", err), + } + } +} + +/// An arena to bump allocate into. +/// +/// ## No `Drop`s +/// +/// Objects that are bump-allocated will never have their [`Drop`] implementation +/// called — unless you do it manually yourself. This makes it relatively +/// easy to leak memory or other resources. +/// +/// If you have a type which internally manages +/// +/// * an allocation from the global heap (e.g. [`Vec`]), +/// * open file descriptors (e.g. [`std::fs::File`]), or +/// * any other resource that must be cleaned up (e.g. an `mmap`) +/// +/// and relies on its `Drop` implementation to clean up the internal resource, +/// then if you allocate that type with a `Bump`, you need to find a new way to +/// clean up after it yourself. +/// +/// Potential solutions are: +/// +/// * Using [`bumpalo::boxed::Box::new_in`] instead of [`Bump::alloc`], that +/// will drop wrapped values similarly to [`std::boxed::Box`]. Note that this +/// requires enabling the `"boxed"` Cargo feature for this crate. **This is +/// often the easiest solution.** +/// +/// * Calling [`drop_in_place`][drop_in_place] or using +/// [`std::mem::ManuallyDrop`][manuallydrop] to manually drop these types. +/// +/// * Using [`bumpalo::collections::Vec`] instead of [`std::vec::Vec`]. +/// +/// * Avoiding allocating these problematic types within a `Bump`. +/// +/// Note that not calling `Drop` is memory safe! Destructors are never +/// guaranteed to run in Rust, you can't rely on them for enforcing memory +/// safety. +/// +/// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html +/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +/// [`std::fs::File`]: https://doc.rust-lang.org/std/fs/struct.File.html +/// [drop_in_place]: https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html +/// [manuallydrop]: https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html +/// [`bumpalo::collections::Vec`]: collections/vec/struct.Vec.html +/// [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +/// [`bumpalo::boxed::Box::new_in`]: boxed/struct.Box.html#method.new_in +/// [`std::boxed::Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html +/// +/// ## Example +/// +/// ``` +/// use bumpalo::Bump; +/// +/// // Create a new bump arena. +/// let bump = Bump::new(); +/// +/// // Allocate values into the arena. +/// let forty_two = bump.alloc(42); +/// assert_eq!(*forty_two, 42); +/// +/// // Mutable references are returned from allocation. +/// let mut s = bump.alloc("bumpalo"); +/// *s = "the bump allocator; and also is a buffalo"; +/// ``` +/// +/// ## Allocation Methods Come in Many Flavors +/// +/// There are various allocation methods on `Bump`, the simplest being +/// [`alloc`][Bump::alloc]. The others exist to satisfy some combination of +/// fallible allocation and initialization. The allocation methods are +/// summarized in the following table: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
Infallible AllocationFallible Allocation
By Valuealloctry_alloc
Infallible Initializer Functionalloc_withtry_alloc_with
Fallible Initializer Functionalloc_try_withtry_alloc_try_with
+/// +/// ### Fallible Allocation: The `try_alloc_` Method Prefix +/// +/// These allocation methods let you recover from out-of-memory (OOM) +/// scenarios, rather than raising a panic on OOM. +/// +/// ``` +/// use bumpalo::Bump; +/// +/// let bump = Bump::new(); +/// +/// match bump.try_alloc(MyStruct { +/// // ... +/// }) { +/// Ok(my_struct) => { +/// // Allocation succeeded. +/// } +/// Err(e) => { +/// // Out of memory. +/// } +/// } +/// +/// struct MyStruct { +/// // ... +/// } +/// ``` +/// +/// ### Initializer Functions: The `_with` Method Suffix +/// +/// Calling one of the generic `…alloc(x)` methods is essentially equivalent to +/// the matching [`…alloc_with(|| x)`](?search=alloc_with). However if you use +/// `…alloc_with`, then the closure will not be invoked until after allocating +/// space for storing `x` on the heap. +/// +/// This can be useful in certain edge-cases related to compiler optimizations. +/// When evaluating for example `bump.alloc(x)`, semantically `x` is first put +/// on the stack and then moved onto the heap. In some cases, the compiler is +/// able to optimize this into constructing `x` directly on the heap, however +/// in many cases it does not. +/// +/// The `…alloc_with` functions try to help the compiler be smarter. In most +/// cases doing for example `bump.try_alloc_with(|| x)` on release mode will be +/// enough to help the compiler realize that this optimization is valid and +/// to construct `x` directly onto the heap. +/// +/// #### Warning +/// +/// These functions critically depend on compiler optimizations to achieve their +/// desired effect. This means that it is not an effective tool when compiling +/// without optimizations on. +/// +/// Even when optimizations are on, these functions do not **guarantee** that +/// the value is constructed on the heap. To the best of our knowledge no such +/// guarantee can be made in stable Rust as of 1.54. +/// +/// ### Fallible Initialization: The `_try_with` Method Suffix +/// +/// The generic [`…alloc_try_with(|| x)`](?search=_try_with) methods behave +/// like the purely `_with` suffixed methods explained above. However, they +/// allow for fallible initialization by accepting a closure that returns a +/// [`Result`] and will attempt to undo the initial allocation if this closure +/// returns [`Err`]. +/// +/// #### Warning +/// +/// If the inner closure returns [`Ok`], space for the entire [`Result`] remains +/// allocated inside `self`. This can be a problem especially if the [`Err`] +/// variant is larger, but even otherwise there may be overhead for the +/// [`Result`]'s discriminant. +/// +///

Undoing the allocation in the Err case +/// always fails if f successfully made any additional allocations +/// in self. +/// +/// For example, the following will always leak also space for the [`Result`] +/// into this `Bump`, even though the inner reference isn't kept and the [`Err`] +/// payload is returned semantically by value: +/// +/// ```rust +/// let bump = bumpalo::Bump::new(); +/// +/// let r: Result<&mut [u8; 1000], ()> = bump.alloc_try_with(|| { +/// let _ = bump.alloc(0_u8); +/// Err(()) +/// }); +/// +/// assert!(r.is_err()); +/// ``` +/// +///

+/// +/// Since [`Err`] payloads are first placed on the heap and then moved to the +/// stack, `bump.…alloc_try_with(|| x)?` is likely to execute more slowly than +/// the matching `bump.…alloc(x?)` in case of initialization failure. If this +/// happens frequently, using the plain un-suffixed method may perform better. +/// +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +/// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok +/// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err +/// +/// ### `Bump` Allocation Limits +/// +/// `bumpalo` supports setting a limit on the maximum bytes of memory that can +/// be allocated for use in a particular `Bump` arena. This limit can be set and removed with +/// [`set_allocation_limit`][Bump::set_allocation_limit]. +/// The allocation limit is only enforced when allocating new backing chunks for +/// a `Bump`. Updating the allocation limit will not affect existing allocations +/// or any future allocations within the `Bump`'s current chunk. +/// +/// #### Example +/// +/// ``` +/// let bump = bumpalo::Bump::new(); +/// +/// assert_eq!(bump.allocation_limit(), None); +/// bump.set_allocation_limit(Some(0)); +/// +/// assert!(bump.try_alloc(5).is_err()); +/// +/// bump.set_allocation_limit(Some(6)); +/// +/// assert_eq!(bump.allocation_limit(), Some(6)); +/// +/// bump.set_allocation_limit(None); +/// +/// assert_eq!(bump.allocation_limit(), None); +/// ``` +/// +/// #### Warning +/// +/// Because of backwards compatibility, allocations that fail +/// due to allocation limits will not present differently than +/// errors due to resource exhaustion. +#[derive(Debug)] +pub struct Bump { + // The current chunk we are bump allocating within. + current_chunk_footer: Cell>, + allocation_limit: Cell>, +} + +#[repr(C)] +#[derive(Debug)] +struct ChunkFooter { + // Pointer to the start of this chunk allocation. This footer is always at + // the end of the chunk. + data: NonNull, + + // The layout of this chunk's allocation. + layout: Layout, + + // Link to the previous chunk. + // + // Note that the last node in the `prev` linked list is the canonical empty + // chunk, whose `prev` link points to itself. + prev: Cell>, + + // Bump allocation finger that is always in the range `self.data..=self`. + ptr: Cell>, + + // The bytes allocated in all chunks so far, the canonical empty chunk has + // a size of 0 and for all other chunks, `allocated_bytes` will be + // the allocated_bytes of the current chunk plus the allocated bytes + // of the `prev` chunk. + allocated_bytes: usize, +} + +/// A wrapper type for the canonical, statically allocated empty chunk. +/// +/// For the canonical empty chunk to be `static`, its type must be `Sync`, which +/// is the purpose of this wrapper type. This is safe because the empty chunk is +/// immutable and never actually modified. +#[repr(transparent)] +struct EmptyChunkFooter(ChunkFooter); + +unsafe impl Sync for EmptyChunkFooter {} + +static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter { + // This chunk is empty (except the foot itself). + layout: Layout::new::(), + + // The start of the (empty) allocatable region for this chunk is itself. + data: unsafe { NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut u8) }, + + // The end of the (empty) allocatable region for this chunk is also itself. + ptr: Cell::new(unsafe { + NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut u8) + }), + + // Invariant: the last chunk footer in all `ChunkFooter::prev` linked lists + // is the empty chunk footer, whose `prev` points to itself. + prev: Cell::new(unsafe { + NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter) + }), + + // Empty chunks count as 0 allocated bytes in an arena. + allocated_bytes: 0, +}); + +impl EmptyChunkFooter { + fn get(&'static self) -> NonNull { + NonNull::from(&self.0) + } +} + +impl ChunkFooter { + // Returns the start and length of the currently allocated region of this + // chunk. + fn as_raw_parts(&self) -> (*const u8, usize) { + let data = self.data.as_ptr() as *const u8; + let ptr = self.ptr.get().as_ptr() as *const u8; + debug_assert!(data <= ptr); + debug_assert!(ptr <= self as *const ChunkFooter as *const u8); + let len = unsafe { (self as *const ChunkFooter as *const u8).offset_from(ptr) as usize }; + (ptr, len) + } + + /// Is this chunk the last empty chunk? + fn is_empty(&self) -> bool { + ptr::eq(self, EMPTY_CHUNK.get().as_ptr()) + } +} + +impl Default for Bump { + fn default() -> Self { + Self::with_min_align() + } +} + +impl Drop for Bump { + fn drop(&mut self) { + unsafe { + dealloc_chunk_list(self.current_chunk_footer.get()); + } + } +} + +#[inline] +unsafe fn dealloc_chunk_list(mut footer: NonNull) { + while !footer.as_ref().is_empty() { + let f = footer; + footer = f.as_ref().prev.get(); + dealloc(f.as_ref().data.as_ptr(), f.as_ref().layout); + } +} + +// `Bump`s are safe to send between threads because nothing aliases its owned +// chunks until you start allocating from it. But by the time you allocate from +// it, the returned references to allocations borrow the `Bump` and therefore +// prevent sending the `Bump` across threads until the borrows end. +unsafe impl Send for Bump {} + +#[inline] +fn is_pointer_aligned_to(pointer: *mut T, align: usize) -> bool { + debug_assert!(align.is_power_of_two()); + + let pointer = pointer as usize; + let pointer_aligned = round_down_to(pointer, align); + pointer == pointer_aligned +} + +#[inline] +pub(crate) const fn round_up_to(n: usize, divisor: usize) -> Option { + debug_assert!(divisor > 0); + debug_assert!(divisor.is_power_of_two()); + match n.checked_add(divisor - 1) { + Some(x) => Some(x & !(divisor - 1)), + None => None, + } +} + +/// Like `round_up_to` but turns overflow into undefined behavior rather than +/// returning `None`. +#[inline] +pub(crate) unsafe fn round_up_to_unchecked(n: usize, divisor: usize) -> usize { + match round_up_to(n, divisor) { + Some(x) => x, + None => { + debug_assert!(false, "round_up_to_unchecked failed"); + core::hint::unreachable_unchecked() + } + } +} + +#[inline] +pub(crate) fn round_down_to(n: usize, divisor: usize) -> usize { + debug_assert!(divisor > 0); + debug_assert!(divisor.is_power_of_two()); + n & !(divisor - 1) +} + +/// Same as `round_down_to` but preserves pointer provenance. +#[inline] +pub(crate) fn round_mut_ptr_down_to(ptr: *mut u8, divisor: usize) -> *mut u8 { + debug_assert!(divisor > 0); + debug_assert!(divisor.is_power_of_two()); + ptr.wrapping_sub(ptr as usize & (divisor - 1)) +} + +#[inline] +pub(crate) unsafe fn round_mut_ptr_up_to_unchecked(ptr: *mut u8, divisor: usize) -> *mut u8 { + debug_assert!(divisor > 0); + debug_assert!(divisor.is_power_of_two()); + let aligned = round_up_to_unchecked(ptr as usize, divisor); + let delta = aligned - (ptr as usize); + ptr.add(delta) +} + +// The typical page size these days. +// +// Note that we don't need to exactly match page size for correctness, and it is +// okay if this is smaller than the real page size in practice. It isn't worth +// the portability concerns and lack of const propagation that dynamically +// looking up the actual page size implies. +const TYPICAL_PAGE_SIZE: usize = 0x1000; + +// We only support alignments of up to 16 bytes for iter_allocated_chunks. +const SUPPORTED_ITER_ALIGNMENT: usize = 16; +const CHUNK_ALIGN: usize = SUPPORTED_ITER_ALIGNMENT; +const FOOTER_SIZE: usize = mem::size_of::(); + +// Assert that `ChunkFooter` is at most the supported alignment. This will give a +// compile time error if it is not the case +const _FOOTER_ALIGN_ASSERTION: () = { + assert!(mem::align_of::() <= CHUNK_ALIGN); +}; + +// Maximum typical overhead per allocation imposed by allocators. +const MALLOC_OVERHEAD: usize = 16; + +// This is the overhead from malloc, footer and alignment. For instance, if +// we want to request a chunk of memory that has at least X bytes usable for +// allocations (where X is aligned to CHUNK_ALIGN), then we expect that the +// after adding a footer, malloc overhead and alignment, the chunk of memory +// the allocator actually sets aside for us is X+OVERHEAD rounded up to the +// nearest suitable size boundary. +const OVERHEAD: usize = match round_up_to(MALLOC_OVERHEAD + FOOTER_SIZE, CHUNK_ALIGN) { + Some(x) => x, + None => panic!(), +}; + +// The target size of our first allocation, including our overhead. The +// available bump capacity will be smaller. +const FIRST_ALLOCATION_GOAL: usize = 1 << 9; + +// The actual size of the first allocation is going to be a bit smaller than the +// goal. We need to make room for the footer, and we also need take the +// alignment into account. We're trying to avoid this kind of situation: +// https://blog.mozilla.org/nnethercote/2011/08/05/clownshoes-available-in-sizes-2101-and-up/ +const DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER: usize = FIRST_ALLOCATION_GOAL - OVERHEAD; + +/// The memory size and alignment details for a potential new chunk +/// allocation. +#[derive(Debug, Clone, Copy)] +struct NewChunkMemoryDetails { + new_size_without_footer: usize, + align: usize, + size: usize, +} + +/// Wrapper around `Layout::from_size_align` that adds debug assertions. +#[inline] +fn layout_from_size_align(size: usize, align: usize) -> Result { + Layout::from_size_align(size, align).map_err(|_| AllocErr) +} + +#[cold] +#[inline(never)] +fn allocation_size_overflow() -> T { + panic!("requested allocation size overflowed") +} + +// NB: We don't have constructors as methods on `impl Bump` that return +// `Self` because then `rustc` can't infer the `N` if it isn't explicitly +// provided, even though it has a default value. There doesn't seem to be a good +// workaround, other than putting constructors on the `Bump`; even +// `std` does this same thing with `HashMap`, for example. +impl Bump<1> { + /// Construct a new arena to bump allocate into. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// # let _ = bump; + /// ``` + pub fn new() -> Self { + Self::with_capacity(0) + } + + /// Attempt to construct a new arena to bump allocate into. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::try_new(); + /// # let _ = bump.unwrap(); + /// ``` + pub fn try_new() -> Result { + Bump::try_with_capacity(0) + } + + /// Construct a new arena with the specified byte capacity to bump allocate + /// into. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::with_capacity(100); + /// # let _ = bump; + /// ``` + /// + /// ## Panics + /// + /// Panics if allocating the initial capacity fails. + pub fn with_capacity(capacity: usize) -> Self { + Self::try_with_capacity(capacity).unwrap_or_else(|_| oom()) + } + + /// Attempt to construct a new arena with the specified byte capacity to + /// bump allocate into. + /// + /// Propagates errors when allocating the initial capacity. + /// + /// ## Example + /// + /// ``` + /// # fn _foo() -> Result<(), bumpalo::AllocErr> { + /// let bump = bumpalo::Bump::try_with_capacity(100)?; + /// # let _ = bump; + /// # Ok(()) + /// # } + /// ``` + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_min_align_and_capacity(capacity) + } +} + +impl Bump { + /// Create a new `Bump` that enforces a minimum alignment. + /// + /// The minimum alignment must be a power of two and no larger than `16`. + /// + /// Enforcing a minimum alignment can speed up allocation of objects with + /// alignment less than or equal to the minimum alignment. This comes at the + /// cost of introducing otherwise-unnecessary padding between allocations of + /// objects with alignment less than the minimum. + /// + /// # Example + /// + /// ``` + /// type BumpAlign8 = bumpalo::Bump<8>; + /// let bump = BumpAlign8::with_min_align(); + /// for x in 0..u8::MAX { + /// let x = bump.alloc(x); + /// assert_eq!((x as *mut _ as usize) % 8, 0, "x is aligned to 8"); + /// } + /// ``` + /// + /// # Panics + /// + /// Panics on invalid minimum alignments. + // + // Because of `rustc`'s poor type inference for default type/const + // parameters (see the comment above the `impl Bump` block with no const + // `MIN_ALIGN` parameter) and because we don't want to force everyone to + // specify a minimum alignment with `Bump::new()` et al, we have a separate + // constructor for specifying the minimum alignment. + pub fn with_min_align() -> Self { + assert!( + MIN_ALIGN.is_power_of_two(), + "MIN_ALIGN must be a power of two; found {MIN_ALIGN}" + ); + assert!( + MIN_ALIGN <= CHUNK_ALIGN, + "MIN_ALIGN may not be larger than {CHUNK_ALIGN}; found {MIN_ALIGN}" + ); + + Bump { + current_chunk_footer: Cell::new(EMPTY_CHUNK.get()), + allocation_limit: Cell::new(None), + } + } + + /// Create a new `Bump` that enforces a minimum alignment and starts with + /// room for at least `capacity` bytes. + /// + /// The minimum alignment must be a power of two and no larger than `16`. + /// + /// Enforcing a minimum alignment can speed up allocation of objects with + /// alignment less than or equal to the minimum alignment. This comes at the + /// cost of introducing otherwise-unnecessary padding between allocations of + /// objects with alignment less than the minimum. + /// + /// # Example + /// + /// ``` + /// type BumpAlign8 = bumpalo::Bump<8>; + /// let mut bump = BumpAlign8::with_min_align_and_capacity(8 * 100); + /// for x in 0..100_u64 { + /// let x = bump.alloc(x); + /// assert_eq!((x as *mut _ as usize) % 8, 0, "x is aligned to 8"); + /// } + /// assert_eq!( + /// bump.iter_allocated_chunks().count(), 1, + /// "initial chunk had capacity for all allocations", + /// ); + /// ``` + /// + /// # Panics + /// + /// Panics on invalid minimum alignments. + /// + /// Panics if allocating the initial capacity fails. + pub fn with_min_align_and_capacity(capacity: usize) -> Self { + Self::try_with_min_align_and_capacity(capacity).unwrap_or_else(|_| oom()) + } + + /// Create a new `Bump` that enforces a minimum alignment and starts with + /// room for at least `capacity` bytes. + /// + /// The minimum alignment must be a power of two and no larger than `16`. + /// + /// Enforcing a minimum alignment can speed up allocation of objects with + /// alignment less than or equal to the minimum alignment. This comes at the + /// cost of introducing otherwise-unnecessary padding between allocations of + /// objects with alignment less than the minimum. + /// + /// # Example + /// + /// ``` + /// # fn _foo() -> Result<(), bumpalo::AllocErr> { + /// type BumpAlign8 = bumpalo::Bump<8>; + /// let mut bump = BumpAlign8::try_with_min_align_and_capacity(8 * 100)?; + /// for x in 0..100_u64 { + /// let x = bump.alloc(x); + /// assert_eq!((x as *mut _ as usize) % 8, 0, "x is aligned to 8"); + /// } + /// assert_eq!( + /// bump.iter_allocated_chunks().count(), 1, + /// "initial chunk had capacity for all allocations", + /// ); + /// # Ok(()) + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics on invalid minimum alignments. + /// + /// Panics if allocating the initial capacity fails. + pub fn try_with_min_align_and_capacity(capacity: usize) -> Result { + assert!( + MIN_ALIGN.is_power_of_two(), + "MIN_ALIGN must be a power of two; found {MIN_ALIGN}" + ); + assert!( + MIN_ALIGN <= CHUNK_ALIGN, + "MIN_ALIGN may not be larger than {CHUNK_ALIGN}; found {MIN_ALIGN}" + ); + + if capacity == 0 { + return Ok(Bump { + current_chunk_footer: Cell::new(EMPTY_CHUNK.get()), + allocation_limit: Cell::new(None), + }); + } + + let layout = layout_from_size_align(capacity, MIN_ALIGN)?; + + let chunk_footer = unsafe { + Self::new_chunk( + Self::new_chunk_memory_details(None, layout).ok_or(AllocErr)?, + layout, + EMPTY_CHUNK.get(), + ) + .ok_or(AllocErr)? + }; + + Ok(Bump { + current_chunk_footer: Cell::new(chunk_footer), + allocation_limit: Cell::new(None), + }) + } + + /// Get this bump arena's minimum alignment. + /// + /// All objects allocated in this arena get aligned to this value. + /// + /// ## Example + /// + /// ``` + /// let bump2 = bumpalo::Bump::<2>::with_min_align(); + /// assert_eq!(bump2.min_align(), 2); + /// + /// let bump4 = bumpalo::Bump::<4>::with_min_align(); + /// assert_eq!(bump4.min_align(), 4); + /// ``` + #[inline] + pub fn min_align(&self) -> usize { + MIN_ALIGN + } + + /// The allocation limit for this arena in bytes. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::with_capacity(0); + /// + /// assert_eq!(bump.allocation_limit(), None); + /// + /// bump.set_allocation_limit(Some(6)); + /// + /// assert_eq!(bump.allocation_limit(), Some(6)); + /// + /// bump.set_allocation_limit(None); + /// + /// assert_eq!(bump.allocation_limit(), None); + /// ``` + pub fn allocation_limit(&self) -> Option { + self.allocation_limit.get() + } + + /// Set the allocation limit in bytes for this arena. + /// + /// The allocation limit is only enforced when allocating new backing chunks for + /// a `Bump`. Updating the allocation limit will not affect existing allocations + /// or any future allocations within the `Bump`'s current chunk. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::with_capacity(0); + /// + /// bump.set_allocation_limit(Some(0)); + /// + /// assert!(bump.try_alloc(5).is_err()); + /// ``` + pub fn set_allocation_limit(&self, limit: Option) { + self.allocation_limit.set(limit); + } + + /// How much headroom an arena has before it hits its allocation + /// limit. + fn allocation_limit_remaining(&self) -> Option { + self.allocation_limit.get().and_then(|allocation_limit| { + let allocated_bytes = self.allocated_bytes(); + if allocated_bytes > allocation_limit { + None + } else { + Some(usize::abs_diff(allocation_limit, allocated_bytes)) + } + }) + } + + /// Whether a request to allocate a new chunk with a given size for a given + /// requested layout will fit under the allocation limit set on a `Bump`. + fn chunk_fits_under_limit( + allocation_limit_remaining: Option, + new_chunk_memory_details: NewChunkMemoryDetails, + ) -> bool { + allocation_limit_remaining + .map(|allocation_limit_left| { + allocation_limit_left >= new_chunk_memory_details.new_size_without_footer + }) + .unwrap_or(true) + } + + /// Determine the memory details including final size, alignment and final + /// size without footer for a new chunk that would be allocated to fulfill + /// an allocation request. + fn new_chunk_memory_details( + new_size_without_footer: Option, + requested_layout: Layout, + ) -> Option { + // We must have `CHUNK_ALIGN` or better alignment... + let align = CHUNK_ALIGN + // and we have to have at least our configured minimum alignment... + .max(MIN_ALIGN) + // and make sure we satisfy the requested allocation's alignment. + .max(requested_layout.align()); + + let mut new_size_without_footer = + new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER); + + let requested_size = + round_up_to(requested_layout.size(), align).unwrap_or_else(allocation_size_overflow); + new_size_without_footer = new_size_without_footer.max(requested_size); + + // We want our allocations to play nice with the memory allocator, and + // waste as little memory as possible. For small allocations, this means + // that the entire allocation including the chunk footer and mallocs + // internal overhead is as close to a power of two as we can go without + // going over. For larger allocations, we only need to get close to a + // page boundary without going over. + if new_size_without_footer < TYPICAL_PAGE_SIZE { + new_size_without_footer = + (new_size_without_footer + OVERHEAD).next_power_of_two() - OVERHEAD; + } else { + new_size_without_footer = + round_up_to(new_size_without_footer + OVERHEAD, TYPICAL_PAGE_SIZE)? - OVERHEAD; + } + + debug_assert_eq!(align % CHUNK_ALIGN, 0); + debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0); + let size = new_size_without_footer + .checked_add(FOOTER_SIZE) + .unwrap_or_else(allocation_size_overflow); + + Some(NewChunkMemoryDetails { + new_size_without_footer, + size, + align, + }) + } + + /// Allocate a new chunk and return its initialized footer. + /// + /// If given, `layouts` is a tuple of the current chunk size and the + /// layout of the allocation request that triggered us to fall back to + /// allocating a new chunk of memory. + unsafe fn new_chunk( + new_chunk_memory_details: NewChunkMemoryDetails, + requested_layout: Layout, + prev: NonNull, + ) -> Option> { + let NewChunkMemoryDetails { + new_size_without_footer, + align, + size, + } = new_chunk_memory_details; + + let layout = layout_from_size_align(size, align).ok()?; + + debug_assert!(size >= requested_layout.size()); + + let data = alloc(layout); + let data = NonNull::new(data)?; + + // The `ChunkFooter` is at the end of the chunk. + let footer_ptr = data.as_ptr().add(new_size_without_footer); + debug_assert_eq!((data.as_ptr() as usize) % align, 0); + debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0); + let footer_ptr = footer_ptr as *mut ChunkFooter; + + // The bump pointer is initialized to the end of the range we will bump + // out of, rounded down to the minimum alignment. It is the + // `NewChunkMemoryDetails` constructor's responsibility to ensure that + // even after this rounding we have enough non-zero capacity in the + // chunk. + let ptr = round_mut_ptr_down_to(footer_ptr.cast::(), MIN_ALIGN); + debug_assert_eq!(ptr as usize % MIN_ALIGN, 0); + debug_assert!( + data.as_ptr() < ptr, + "bump pointer {ptr:#p} should still be greater than or equal to the \ + start of the bump chunk {data:#p}" + ); + debug_assert_eq!( + (ptr as usize) - (data.as_ptr() as usize), + new_size_without_footer + ); + + let ptr = Cell::new(NonNull::new_unchecked(ptr)); + + // The `allocated_bytes` of a new chunk counts the total size + // of the chunks, not how much of the chunks are used. + let allocated_bytes = prev.as_ref().allocated_bytes + new_size_without_footer; + + ptr::write( + footer_ptr, + ChunkFooter { + data, + layout, + prev: Cell::new(prev), + ptr, + allocated_bytes, + }, + ); + + Some(NonNull::new_unchecked(footer_ptr)) + } + + /// Reset this bump allocator. + /// + /// Performs mass deallocation on everything allocated in this arena by + /// resetting the pointer into the underlying chunk of memory to the start + /// of the chunk. Does not run any `Drop` implementations on deallocated + /// objects; see [the top-level documentation](struct.Bump.html) for details. + /// + /// If this arena has allocated multiple chunks to bump allocate into, then + /// the excess chunks are returned to the global allocator. + /// + /// ## Example + /// + /// ``` + /// let mut bump = bumpalo::Bump::new(); + /// + /// // Allocate a bunch of things. + /// { + /// for i in 0..100 { + /// bump.alloc(i); + /// } + /// } + /// + /// // Reset the arena. + /// bump.reset(); + /// + /// // Allocate some new things in the space previously occupied by the + /// // original things. + /// for j in 200..400 { + /// bump.alloc(j); + /// } + ///``` + pub fn reset(&mut self) { + // Takes `&mut self` so `self` must be unique and there can't be any + // borrows active that would get invalidated by resetting. + unsafe { + if self.current_chunk_footer.get().as_ref().is_empty() { + return; + } + + let mut cur_chunk = self.current_chunk_footer.get(); + + // Deallocate all chunks except the current one + let prev_chunk = cur_chunk.as_ref().prev.replace(EMPTY_CHUNK.get()); + dealloc_chunk_list(prev_chunk); + + // Reset the bump finger to the end of the chunk. + debug_assert!( + is_pointer_aligned_to(cur_chunk.as_ptr(), MIN_ALIGN), + "bump pointer {cur_chunk:#p} should be aligned to the minimum alignment of {MIN_ALIGN:#x}" + ); + cur_chunk.as_ref().ptr.set(cur_chunk.cast()); + + // Reset the allocated size of the chunk. + cur_chunk.as_mut().allocated_bytes = cur_chunk.as_ref().layout.size() - FOOTER_SIZE; + + debug_assert!( + self.current_chunk_footer + .get() + .as_ref() + .prev + .get() + .as_ref() + .is_empty(), + "We should only have a single chunk" + ); + debug_assert_eq!( + self.current_chunk_footer.get().as_ref().ptr.get(), + self.current_chunk_footer.get().cast(), + "Our chunk's bump finger should be reset to the start of its allocation" + ); + } + } + + /// Allocate an object in this `Bump` and return an exclusive reference to + /// it. + /// + /// ## Panics + /// + /// Panics if reserving space for `T` fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc("hello"); + /// assert_eq!(*x, "hello"); + /// ``` + #[inline(always)] + pub fn alloc(&self, val: T) -> &mut T { + self.alloc_with(|| val) + } + + /// Try to allocate an object in this `Bump` and return an exclusive + /// reference to it. + /// + /// ## Errors + /// + /// Errors if reserving space for `T` fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.try_alloc("hello"); + /// assert_eq!(x, Ok(&mut "hello")); + /// ``` + #[inline(always)] + pub fn try_alloc(&self, val: T) -> Result<&mut T, AllocErr> { + self.try_alloc_with(|| val) + } + + /// Pre-allocate space for an object in this `Bump`, initializes it using + /// the closure, then returns an exclusive reference to it. + /// + /// See [The `_with` Method Suffix](#initializer-functions-the-_with-method-suffix) for a + /// discussion on the differences between the `_with` suffixed methods and + /// those methods without it, their performance characteristics, and when + /// you might or might not choose a `_with` suffixed method. + /// + /// ## Panics + /// + /// Panics if reserving space for `T` fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_with(|| "hello"); + /// assert_eq!(*x, "hello"); + /// ``` + #[inline(always)] + pub fn alloc_with(&self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + #[inline(always)] + unsafe fn inner_writer(ptr: *mut T, f: F) + where + F: FnOnce() -> T, + { + // This function is translated as: + // - allocate space for a T on the stack + // - call f() with the return value being put onto this stack space + // - memcpy from the stack to the heap + // + // Ideally we want LLVM to always realize that doing a stack + // allocation is unnecessary and optimize the code so it writes + // directly into the heap instead. It seems we get it to realize + // this most consistently if we put this critical line into it's + // own function instead of inlining it into the surrounding code. + ptr::write(ptr, f()); + } + + let layout = Layout::new::(); + + unsafe { + let p = self.alloc_layout(layout); + let p = p.as_ptr() as *mut T; + inner_writer(p, f); + &mut *p + } + } + + /// Tries to pre-allocate space for an object in this `Bump`, initializes + /// it using the closure, then returns an exclusive reference to it. + /// + /// See [The `_with` Method Suffix](#initializer-functions-the-_with-method-suffix) for a + /// discussion on the differences between the `_with` suffixed methods and + /// those methods without it, their performance characteristics, and when + /// you might or might not choose a `_with` suffixed method. + /// + /// ## Errors + /// + /// Errors if reserving space for `T` fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.try_alloc_with(|| "hello"); + /// assert_eq!(x, Ok(&mut "hello")); + /// ``` + #[inline(always)] + pub fn try_alloc_with(&self, f: F) -> Result<&mut T, AllocErr> + where + F: FnOnce() -> T, + { + #[inline(always)] + unsafe fn inner_writer(ptr: *mut T, f: F) + where + F: FnOnce() -> T, + { + // This function is translated as: + // - allocate space for a T on the stack + // - call f() with the return value being put onto this stack space + // - memcpy from the stack to the heap + // + // Ideally we want LLVM to always realize that doing a stack + // allocation is unnecessary and optimize the code so it writes + // directly into the heap instead. It seems we get it to realize + // this most consistently if we put this critical line into it's + // own function instead of inlining it into the surrounding code. + ptr::write(ptr, f()); + } + + //SAFETY: Self-contained: + // `p` is allocated for `T` and then a `T` is written. + let layout = Layout::new::(); + let p = self.try_alloc_layout(layout)?; + let p = p.as_ptr() as *mut T; + + unsafe { + inner_writer(p, f); + Ok(&mut *p) + } + } + + /// Pre-allocates space for a [`Result`] in this `Bump`, initializes it using + /// the closure, then returns an exclusive reference to its `T` if [`Ok`]. + /// + /// Iff the allocation fails, the closure is not run. + /// + /// Iff [`Err`], an allocator rewind is *attempted* and the `E` instance is + /// moved out of the allocator to be consumed or dropped as normal. + /// + /// See [The `_with` Method Suffix](#initializer-functions-the-_with-method-suffix) for a + /// discussion on the differences between the `_with` suffixed methods and + /// those methods without it, their performance characteristics, and when + /// you might or might not choose a `_with` suffixed method. + /// + /// For caveats specific to fallible initialization, see + /// [The `_try_with` Method Suffix](#fallible-initialization-the-_try_with-method-suffix). + /// + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok + /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// + /// ## Errors + /// + /// Iff the allocation succeeds but `f` fails, that error is forwarded by value. + /// + /// ## Panics + /// + /// Panics if reserving space for `Result` fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_try_with(|| Ok("hello"))?; + /// assert_eq!(*x, "hello"); + /// # Result::<_, ()>::Ok(()) + /// ``` + #[inline(always)] + pub fn alloc_try_with(&self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result, + { + let rewind_footer = self.current_chunk_footer.get(); + let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get(); + let mut inner_result_ptr = NonNull::from(self.alloc_with(f)); + match unsafe { inner_result_ptr.as_mut() } { + Ok(t) => Ok(unsafe { + //SAFETY: + // The `&mut Result` returned by `alloc_with` may be + // lifetime-limited by `E`, but the derived `&mut T` still has + // the same validity as in `alloc_with` since the error variant + // is already ruled out here. + + // We could conditionally truncate the allocation here, but + // since it grows backwards, it seems unlikely that we'd get + // any more than the `Result`'s discriminant this way, if + // anything at all. + &mut *(t as *mut _) + }), + Err(e) => unsafe { + // If this result was the last allocation in this arena, we can + // reclaim its space. In fact, sometimes we can do even better + // than simply calling `dealloc` on the result pointer: we can + // reclaim any alignment padding we might have added (which + // `dealloc` cannot do) if we didn't allocate a new chunk for + // this result. + if self.is_last_allocation(inner_result_ptr.cast()) { + let current_footer_p = self.current_chunk_footer.get(); + let current_ptr = ¤t_footer_p.as_ref().ptr; + if current_footer_p == rewind_footer { + // It's still the same chunk, so reset the bump pointer + // to its original value upon entry to this method + // (reclaiming any alignment padding we may have + // added). + current_ptr.set(rewind_ptr); + } else { + // We allocated a new chunk for this result. + // + // We know the result is the only allocation in this + // chunk: Any additional allocations since the start of + // this method could only have happened when running + // the initializer function, which is called *after* + // reserving space for this result. Therefore, since we + // already determined via the check above that this + // result was the last allocation, there must not have + // been any other allocations, and this result is the + // only allocation in this chunk. + // + // Because this is the only allocation in this chunk, + // we can reset the chunk's bump finger to the start of + // the chunk. + current_ptr.set(current_footer_p.as_ref().data); + } + } + //SAFETY: + // As we received `E` semantically by value from `f`, we can + // just copy that value here as long as we avoid a double-drop + // (which can't happen as any specific references to the `E`'s + // data in `self` are destroyed when this function returns). + // + // The order between this and the deallocation doesn't matter + // because `Self: !Sync`. + Err(ptr::read(e as *const _)) + }, + } + } + + /// Tries to pre-allocates space for a [`Result`] in this `Bump`, + /// initializes it using the closure, then returns an exclusive reference + /// to its `T` if all [`Ok`]. + /// + /// Iff the allocation fails, the closure is not run. + /// + /// Iff the closure returns [`Err`], an allocator rewind is *attempted* and + /// the `E` instance is moved out of the allocator to be consumed or dropped + /// as normal. + /// + /// See [The `_with` Method Suffix](#initializer-functions-the-_with-method-suffix) for a + /// discussion on the differences between the `_with` suffixed methods and + /// those methods without it, their performance characteristics, and when + /// you might or might not choose a `_with` suffixed method. + /// + /// For caveats specific to fallible initialization, see + /// [The `_try_with` Method Suffix](#fallible-initialization-the-_try_with-method-suffix). + /// + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok + /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// + /// ## Errors + /// + /// Errors with the [`Alloc`](`AllocOrInitError::Alloc`) variant iff + /// reserving space for `Result` fails. + /// + /// Iff the allocation succeeds but `f` fails, that error is forwarded by + /// value inside the [`Init`](`AllocOrInitError::Init`) variant. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.try_alloc_try_with(|| Ok("hello"))?; + /// assert_eq!(*x, "hello"); + /// # Result::<_, bumpalo::AllocOrInitError<()>>::Ok(()) + /// ``` + #[inline(always)] + pub fn try_alloc_try_with(&self, f: F) -> Result<&mut T, AllocOrInitError> + where + F: FnOnce() -> Result, + { + let rewind_footer = self.current_chunk_footer.get(); + let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get(); + let mut inner_result_ptr = NonNull::from(self.try_alloc_with(f)?); + match unsafe { inner_result_ptr.as_mut() } { + Ok(t) => Ok(unsafe { + //SAFETY: + // The `&mut Result` returned by `alloc_with` may be + // lifetime-limited by `E`, but the derived `&mut T` still has + // the same validity as in `alloc_with` since the error variant + // is already ruled out here. + + // We could conditionally truncate the allocation here, but + // since it grows backwards, it seems unlikely that we'd get + // any more than the `Result`'s discriminant this way, if + // anything at all. + &mut *(t as *mut _) + }), + Err(e) => unsafe { + // If this result was the last allocation in this arena, we can + // reclaim its space. In fact, sometimes we can do even better + // than simply calling `dealloc` on the result pointer: we can + // reclaim any alignment padding we might have added (which + // `dealloc` cannot do) if we didn't allocate a new chunk for + // this result. + if self.is_last_allocation(inner_result_ptr.cast()) { + let current_footer_p = self.current_chunk_footer.get(); + let current_ptr = ¤t_footer_p.as_ref().ptr; + if current_footer_p == rewind_footer { + // It's still the same chunk, so reset the bump pointer + // to its original value upon entry to this method + // (reclaiming any alignment padding we may have + // added). + current_ptr.set(rewind_ptr); + } else { + // We allocated a new chunk for this result. + // + // We know the result is the only allocation in this + // chunk: Any additional allocations since the start of + // this method could only have happened when running + // the initializer function, which is called *after* + // reserving space for this result. Therefore, since we + // already determined via the check above that this + // result was the last allocation, there must not have + // been any other allocations, and this result is the + // only allocation in this chunk. + // + // Because this is the only allocation in this chunk, + // we can reset the chunk's bump finger to the start of + // the chunk. + current_ptr.set(current_footer_p.as_ref().data); + } + } + //SAFETY: + // As we received `E` semantically by value from `f`, we can + // just copy that value here as long as we avoid a double-drop + // (which can't happen as any specific references to the `E`'s + // data in `self` are destroyed when this function returns). + // + // The order between this and the deallocation doesn't matter + // because `Self: !Sync`. + Err(AllocOrInitError::Init(ptr::read(e as *const _))) + }, + } + } + + /// `Copy` a slice into this `Bump` and return an exclusive reference to + /// the copy. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_slice_copy(&[1, 2, 3]); + /// assert_eq!(x, &[1, 2, 3]); + /// ``` + #[inline(always)] + pub fn alloc_slice_copy(&self, src: &[T]) -> &mut [T] + where + T: Copy, + { + let layout = Layout::for_value(src); + let dst = self.alloc_layout(layout).cast::(); + + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), dst.as_ptr(), src.len()); + slice::from_raw_parts_mut(dst.as_ptr(), src.len()) + } + } + + /// Like `alloc_slice_copy`, but does not panic in case of allocation failure. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.try_alloc_slice_copy(&[1, 2, 3]); + /// assert_eq!(x, Ok(&mut[1, 2, 3] as &mut [_])); + /// + /// + /// let bump = bumpalo::Bump::new(); + /// bump.set_allocation_limit(Some(4)); + /// let x = bump.try_alloc_slice_copy(&[1, 2, 3, 4, 5, 6]); + /// assert_eq!(x, Err(bumpalo::AllocErr)); // too big + /// ``` + #[inline(always)] + pub fn try_alloc_slice_copy(&self, src: &[T]) -> Result<&mut [T], AllocErr> + where + T: Copy, + { + let layout = Layout::for_value(src); + let dst = self.try_alloc_layout(layout)?.cast::(); + let result = unsafe { + core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_ptr(), src.len()); + slice::from_raw_parts_mut(dst.as_ptr(), src.len()) + }; + Ok(result) + } + + /// `Clone` a slice into this `Bump` and return an exclusive reference to + /// the clone. Prefer [`alloc_slice_copy`](#method.alloc_slice_copy) if `T` is `Copy`. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// #[derive(Clone, Debug, Eq, PartialEq)] + /// struct Sheep { + /// name: String, + /// } + /// + /// let originals = [ + /// Sheep { name: "Alice".into() }, + /// Sheep { name: "Bob".into() }, + /// Sheep { name: "Cathy".into() }, + /// ]; + /// + /// let bump = bumpalo::Bump::new(); + /// let clones = bump.alloc_slice_clone(&originals); + /// assert_eq!(originals, clones); + /// ``` + #[inline(always)] + pub fn alloc_slice_clone(&self, src: &[T]) -> &mut [T] + where + T: Clone, + { + let layout = Layout::for_value(src); + let dst = self.alloc_layout(layout).cast::(); + + unsafe { + for (i, val) in src.iter().cloned().enumerate() { + ptr::write(dst.as_ptr().add(i), val); + } + + slice::from_raw_parts_mut(dst.as_ptr(), src.len()) + } + } + + /// Like `alloc_slice_clone` but does not panic on failure. + #[inline(always)] + pub fn try_alloc_slice_clone(&self, src: &[T]) -> Result<&mut [T], AllocErr> + where + T: Clone, + { + let layout = Layout::for_value(src); + let dst = self.try_alloc_layout(layout)?.cast::(); + + unsafe { + for (i, val) in src.iter().cloned().enumerate() { + ptr::write(dst.as_ptr().add(i), val); + } + + Ok(slice::from_raw_parts_mut(dst.as_ptr(), src.len())) + } + } + + /// `Copy` a string slice into this `Bump` and return an exclusive reference to it. + /// + /// ## Panics + /// + /// Panics if reserving space for the string fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let hello = bump.alloc_str("hello world"); + /// assert_eq!("hello world", hello); + /// ``` + #[inline(always)] + pub fn alloc_str(&self, src: &str) -> &mut str { + let buffer = self.alloc_slice_copy(src.as_bytes()); + unsafe { + // This is OK, because it already came in as str, so it is guaranteed to be utf8 + str::from_utf8_unchecked_mut(buffer) + } + } + + /// Same as `alloc_str` but does not panic on failure. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let hello = bump.try_alloc_str("hello world").unwrap(); + /// assert_eq!("hello world", hello); + /// + /// + /// let bump = bumpalo::Bump::new(); + /// bump.set_allocation_limit(Some(5)); + /// let hello = bump.try_alloc_str("hello world"); + /// assert_eq!(Err(bumpalo::AllocErr), hello); + /// ``` + #[inline(always)] + pub fn try_alloc_str(&self, src: &str) -> Result<&mut str, AllocErr> { + let buffer = self.try_alloc_slice_copy(src.as_bytes())?; + unsafe { + // This is OK, because it already came in as str, so it is guaranteed to be utf8 + Ok(str::from_utf8_unchecked_mut(buffer)) + } + } + + /// Allocates a new slice of size `len` into this `Bump` and returns an + /// exclusive reference to the copy. + /// + /// The elements of the slice are initialized using the supplied closure. + /// The closure argument is the position in the slice. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_slice_fill_with(5, |i| 5 * (i + 1)); + /// assert_eq!(x, &[5, 10, 15, 20, 25]); + /// ``` + #[inline(always)] + pub fn alloc_slice_fill_with(&self, len: usize, mut f: F) -> &mut [T] + where + F: FnMut(usize) -> T, + { + let layout = Layout::array::(len).unwrap_or_else(|_| oom()); + let dst = self.alloc_layout(layout).cast::(); + + unsafe { + for i in 0..len { + ptr::write(dst.as_ptr().add(i), f(i)); + } + + let result = slice::from_raw_parts_mut(dst.as_ptr(), len); + debug_assert_eq!(Layout::for_value(result), layout); + result + } + } + + /// Allocates a new slice of size `len` into this `Bump` and returns an + /// exclusive reference to the copy, failing if the closure return an Err. + /// + /// The elements of the slice are initialized using the supplied closure. + /// The closure argument is the position in the slice. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: Result<&mut [usize], ()> = bump.alloc_slice_try_fill_with(5, |i| Ok(5 * i)); + /// assert_eq!(x, Ok(bump.alloc_slice_copy(&[0, 5, 10, 15, 20]))); + /// ``` + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: Result<&mut [usize], ()> = bump.alloc_slice_try_fill_with( + /// 5, + /// |n| if n == 2 { Err(()) } else { Ok(n) } + /// ); + /// assert_eq!(x, Err(())); + /// ``` + #[inline(always)] + pub fn alloc_slice_try_fill_with(&self, len: usize, mut f: F) -> Result<&mut [T], E> + where + F: FnMut(usize) -> Result, + { + let layout = Layout::array::(len).unwrap_or_else(|_| oom()); + let base_ptr = self.alloc_layout(layout); + let dst = base_ptr.cast::(); + + unsafe { + for i in 0..len { + match f(i) { + Ok(el) => ptr::write(dst.as_ptr().add(i), el), + Err(e) => { + self.dealloc(base_ptr, layout); + return Err(e); + } + } + } + + let result = slice::from_raw_parts_mut(dst.as_ptr(), len); + debug_assert_eq!(Layout::for_value(result), layout); + Ok(result) + } + } + + /// Allocates a new slice of size `len` into this `Bump` and returns an + /// exclusive reference to the copy. + /// + /// The elements of the slice are initialized using the supplied closure. + /// The closure argument is the position in the slice. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.try_alloc_slice_fill_with(5, |i| 5 * (i + 1)); + /// assert_eq!(x, Ok(&mut[5usize, 10, 15, 20, 25] as &mut [_])); + /// + /// + /// let bump = bumpalo::Bump::new(); + /// bump.set_allocation_limit(Some(4)); + /// let x = bump.try_alloc_slice_fill_with(10, |i| 5 * (i + 1)); + /// assert_eq!(x, Err(bumpalo::AllocErr)); + /// ``` + #[inline(always)] + pub fn try_alloc_slice_fill_with( + &self, + len: usize, + mut f: F, + ) -> Result<&mut [T], AllocErr> + where + F: FnMut(usize) -> T, + { + let layout = Layout::array::(len).map_err(|_| AllocErr)?; + let dst = self.try_alloc_layout(layout)?.cast::(); + + unsafe { + for i in 0..len { + ptr::write(dst.as_ptr().add(i), f(i)); + } + + let result = slice::from_raw_parts_mut(dst.as_ptr(), len); + debug_assert_eq!(Layout::for_value(result), layout); + Ok(result) + } + } + + /// Allocates a new slice of size `len` into this `Bump` and returns an + /// exclusive reference to the copy. + /// + /// All elements of the slice are initialized to `value`. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_slice_fill_copy(5, 42); + /// assert_eq!(x, &[42, 42, 42, 42, 42]); + /// ``` + #[inline(always)] + pub fn alloc_slice_fill_copy(&self, len: usize, value: T) -> &mut [T] { + self.alloc_slice_fill_with(len, |_| value) + } + + /// Same as `alloc_slice_fill_copy` but does not panic on failure. + #[inline(always)] + pub fn try_alloc_slice_fill_copy( + &self, + len: usize, + value: T, + ) -> Result<&mut [T], AllocErr> { + self.try_alloc_slice_fill_with(len, |_| value) + } + + /// Allocates a new slice of size `len` slice into this `Bump` and return an + /// exclusive reference to the copy. + /// + /// All elements of the slice are initialized to `value.clone()`. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let s: String = "Hello Bump!".to_string(); + /// let x: &[String] = bump.alloc_slice_fill_clone(2, &s); + /// assert_eq!(x.len(), 2); + /// assert_eq!(&x[0], &s); + /// assert_eq!(&x[1], &s); + /// ``` + #[inline(always)] + pub fn alloc_slice_fill_clone(&self, len: usize, value: &T) -> &mut [T] { + self.alloc_slice_fill_with(len, |_| value.clone()) + } + + /// Like `alloc_slice_fill_clone` but does not panic on failure. + #[inline(always)] + pub fn try_alloc_slice_fill_clone( + &self, + len: usize, + value: &T, + ) -> Result<&mut [T], AllocErr> { + self.try_alloc_slice_fill_with(len, |_| value.clone()) + } + + /// Allocates a new slice of size `len` slice into this `Bump` and return an + /// exclusive reference to the copy. + /// + /// The elements are initialized using the supplied iterator. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails, or if the supplied + /// iterator returns fewer elements than it promised. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: &[i32] = bump.alloc_slice_fill_iter([2, 3, 5].iter().cloned().map(|i| i * i)); + /// assert_eq!(x, [4, 9, 25]); + /// ``` + #[inline(always)] + pub fn alloc_slice_fill_iter(&self, iter: I) -> &mut [T] + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let mut iter = iter.into_iter(); + self.alloc_slice_fill_with(iter.len(), |_| { + iter.next().expect("Iterator supplied too few elements") + }) + } + + /// Allocates a new slice of size `len` slice into this `Bump` and return an + /// exclusive reference to the copy, failing if the iterator returns an Err. + /// + /// The elements are initialized using the supplied iterator. + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails, or if the supplied + /// iterator returns fewer elements than it promised. + /// + /// ## Examples + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: Result<&mut [i32], ()> = bump.alloc_slice_try_fill_iter( + /// [2, 3, 5].iter().cloned().map(|i| Ok(i * i)) + /// ); + /// assert_eq!(x, Ok(bump.alloc_slice_copy(&[4, 9, 25]))); + /// ``` + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: Result<&mut [i32], ()> = bump.alloc_slice_try_fill_iter( + /// [Ok(2), Err(()), Ok(5)].iter().cloned() + /// ); + /// assert_eq!(x, Err(())); + /// ``` + #[inline(always)] + pub fn alloc_slice_try_fill_iter(&self, iter: I) -> Result<&mut [T], E> + where + I: IntoIterator>, + I::IntoIter: ExactSizeIterator, + { + let mut iter = iter.into_iter(); + self.alloc_slice_try_fill_with(iter.len(), |_| { + iter.next().expect("Iterator supplied too few elements") + }) + } + + /// Allocates a new slice of size `iter.len()` slice into this `Bump` and return an + /// exclusive reference to the copy. Does not panic on failure. + /// + /// The elements are initialized using the supplied iterator. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x: &[i32] = bump.try_alloc_slice_fill_iter([2, 3, 5] + /// .iter().cloned().map(|i| i * i)).unwrap(); + /// assert_eq!(x, [4, 9, 25]); + /// ``` + #[inline(always)] + pub fn try_alloc_slice_fill_iter(&self, iter: I) -> Result<&mut [T], AllocErr> + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let mut iter = iter.into_iter(); + self.try_alloc_slice_fill_with(iter.len(), |_| { + iter.next().expect("Iterator supplied too few elements") + }) + } + + /// Allocates a new slice of size `len` slice into this `Bump` and return an + /// exclusive reference to the copy. + /// + /// All elements of the slice are initialized to [`T::default()`]. + /// + /// [`T::default()`]: https://doc.rust-lang.org/std/default/trait.Default.html#tymethod.default + /// + /// ## Panics + /// + /// Panics if reserving space for the slice fails. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let x = bump.alloc_slice_fill_default::(5); + /// assert_eq!(x, &[0, 0, 0, 0, 0]); + /// ``` + #[inline(always)] + pub fn alloc_slice_fill_default(&self, len: usize) -> &mut [T] { + self.alloc_slice_fill_with(len, |_| T::default()) + } + + /// Like `alloc_slice_fill_default` but does not panic on failure. + #[inline(always)] + pub fn try_alloc_slice_fill_default( + &self, + len: usize, + ) -> Result<&mut [T], AllocErr> { + self.try_alloc_slice_fill_with(len, |_| T::default()) + } + + /// Allocate space for an object with the given `Layout`. + /// + /// The returned pointer points at uninitialized memory, and should be + /// initialized with + /// [`std::ptr::write`](https://doc.rust-lang.org/std/ptr/fn.write.html). + /// + /// # Panics + /// + /// Panics if reserving space matching `layout` fails. + #[inline(always)] + pub fn alloc_layout(&self, layout: Layout) -> NonNull { + self.try_alloc_layout(layout).unwrap_or_else(|_| oom()) + } + + /// Attempts to allocate space for an object with the given `Layout` or else returns + /// an `Err`. + /// + /// The returned pointer points at uninitialized memory, and should be + /// initialized with + /// [`std::ptr::write`](https://doc.rust-lang.org/std/ptr/fn.write.html). + /// + /// # Errors + /// + /// Errors if reserving space matching `layout` fails. + #[inline(always)] + pub fn try_alloc_layout(&self, layout: Layout) -> Result, AllocErr> { + if let Some(p) = self.try_alloc_layout_fast(layout) { + Ok(p) + } else { + self.alloc_layout_slow(layout).ok_or(AllocErr) + } + } + + #[inline(always)] + fn try_alloc_layout_fast(&self, layout: Layout) -> Option> { + // We don't need to check for ZSTs here since they will automatically + // be handled properly: the pointer will be bumped by zero bytes, + // modulo alignment. This keeps the fast path optimized for non-ZSTs, + // which are much more common. + unsafe { + let footer_ptr = self.current_chunk_footer.get(); + let footer = footer_ptr.as_ref(); + + let ptr = footer.ptr.get().as_ptr(); + let start = footer.data.as_ptr(); + debug_assert!( + start <= ptr, + "start pointer {start:#p} should be less than or equal to bump pointer {ptr:#p}" + ); + debug_assert!( + ptr <= footer_ptr.cast::().as_ptr(), + "bump pointer {ptr:#p} should be less than or equal to footer pointer {footer_ptr:#p}" + ); + debug_assert!( + is_pointer_aligned_to(ptr, MIN_ALIGN), + "bump pointer {ptr:#p} should be aligned to the minimum alignment of {MIN_ALIGN:#x}" + ); + + // This `match` should be boiled away by LLVM: `MIN_ALIGN` is a + // constant and the layout's alignment is also constant in practice + // after inlining. + let aligned_ptr = match layout.align().cmp(&MIN_ALIGN) { + Ordering::Less => { + // We need to round the size up to a multiple of `MIN_ALIGN` + // to preserve the minimum alignment. This might overflow + // since we cannot rely on `Layout`'s guarantees. + let aligned_size = round_up_to(layout.size(), MIN_ALIGN)?; + + let capacity = (ptr as usize) - (start as usize); + if aligned_size > capacity { + return None; + } + + ptr.wrapping_sub(aligned_size) + } + Ordering::Equal => { + // `Layout` guarantees that rounding the size up to its + // align cannot overflow (but does not guarantee that the + // size is initially a multiple of the alignment, which is + // why we need to do this rounding). + let aligned_size = round_up_to_unchecked(layout.size(), layout.align()); + + let capacity = (ptr as usize) - (start as usize); + if aligned_size > capacity { + return None; + } + + ptr.wrapping_sub(aligned_size) + } + Ordering::Greater => { + // `Layout` guarantees that rounding the size up to its + // align cannot overflow (but does not guarantee that the + // size is initially a multiple of the alignment, which is + // why we need to do this rounding). + let aligned_size = round_up_to_unchecked(layout.size(), layout.align()); + + let aligned_ptr = round_mut_ptr_down_to(ptr, layout.align()); + let capacity = (aligned_ptr as usize).wrapping_sub(start as usize); + if aligned_ptr < start || aligned_size > capacity { + return None; + } + + aligned_ptr.wrapping_sub(aligned_size) + } + }; + + debug_assert!( + is_pointer_aligned_to(aligned_ptr, layout.align()), + "pointer {aligned_ptr:#p} should be aligned to layout alignment of {:#}", + layout.align() + ); + debug_assert!( + is_pointer_aligned_to(aligned_ptr, MIN_ALIGN), + "pointer {aligned_ptr:#p} should be aligned to minimum alignment of {:#}", + MIN_ALIGN + ); + debug_assert!( + start <= aligned_ptr && aligned_ptr <= ptr, + "pointer {aligned_ptr:#p} should be in range {start:#p}..{ptr:#p}" + ); + + debug_assert!(!aligned_ptr.is_null()); + let aligned_ptr = NonNull::new_unchecked(aligned_ptr); + + footer.ptr.set(aligned_ptr); + Some(aligned_ptr) + } + } + + /// Gets the remaining capacity in the current chunk (in bytes). + /// + /// ## Example + /// + /// ``` + /// use bumpalo::Bump; + /// + /// let bump = Bump::with_capacity(100); + /// + /// let capacity = bump.chunk_capacity(); + /// assert!(capacity >= 100); + /// ``` + pub fn chunk_capacity(&self) -> usize { + let current_footer = self.current_chunk_footer.get(); + let current_footer = unsafe { current_footer.as_ref() }; + + current_footer.ptr.get().as_ptr() as usize - current_footer.data.as_ptr() as usize + } + + /// Slow path allocation for when we need to allocate a new chunk from the + /// parent bump set because there isn't enough room in our current chunk. + #[inline(never)] + #[cold] + fn alloc_layout_slow(&self, layout: Layout) -> Option> { + unsafe { + let allocation_limit_remaining = self.allocation_limit_remaining(); + + // Get a new chunk from the global allocator. + let current_footer = self.current_chunk_footer.get(); + let current_layout = current_footer.as_ref().layout; + + // By default, we want our new chunk to be about twice as big + // as the previous chunk. If the global allocator refuses it, + // we try to divide it by half until it works or the requested + // size is smaller than the default footer size. + let min_new_chunk_size = layout.size().max(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER); + let mut base_size = (current_layout.size() - FOOTER_SIZE) + .checked_mul(2)? + .max(min_new_chunk_size); + let chunk_memory_details = iter::from_fn(|| { + let bypass_min_chunk_size_for_small_limits = matches!(self.allocation_limit(), Some(limit) if layout.size() < limit + && base_size >= layout.size() + && limit < DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER + && self.allocated_bytes() == 0); + + if base_size >= min_new_chunk_size || bypass_min_chunk_size_for_small_limits { + let size = base_size; + base_size /= 2; + Self::new_chunk_memory_details(Some(size), layout) + } else { + None + } + }); + + let new_footer = chunk_memory_details + .filter_map(|chunk_memory_details| { + if Self::chunk_fits_under_limit( + allocation_limit_remaining, + chunk_memory_details, + ) { + Self::new_chunk(chunk_memory_details, layout, current_footer) + } else { + None + } + }) + .next()?; + + debug_assert_eq!( + new_footer.as_ref().data.as_ptr() as usize % layout.align(), + 0 + ); + + // Set the new chunk as our new current chunk. + self.current_chunk_footer.set(new_footer); + + // And then we can rely on `tray_alloc_layout_fast` to allocate + // space within this chunk. + let ptr = self.try_alloc_layout_fast(layout); + debug_assert!(ptr.is_some()); + ptr + } + } + + /// Returns an iterator over each chunk of allocated memory that + /// this arena has bump allocated into. + /// + /// The chunks are returned ordered by allocation time, with the most + /// recently allocated chunk being returned first, and the least recently + /// allocated chunk being returned last. + /// + /// The values inside each chunk are also ordered by allocation time, with + /// the most recent allocation being earlier in the slice, and the least + /// recent allocation being towards the end of the slice. + /// + /// ## Safety + /// + /// Because this method takes `&mut self`, we know that the bump arena + /// reference is unique and therefore there aren't any active references to + /// any of the objects we've allocated in it either. This potential aliasing + /// of exclusive references is one common footgun for unsafe code that we + /// don't need to worry about here. + /// + /// However, there could be regions of uninitialized memory used as padding + /// between allocations, which is why this iterator has items of type + /// `[MaybeUninit]`, instead of simply `[u8]`. + /// + /// The only way to guarantee that there is no padding between allocations + /// or within allocated objects is if all of these properties hold: + /// + /// 1. Every object allocated in this arena has the same alignment, + /// and that alignment is at most 16. + /// 2. Every object's size is a multiple of its alignment. + /// 3. None of the objects allocated in this arena contain any internal + /// padding. + /// + /// If you want to use this `iter_allocated_chunks` method, it is *your* + /// responsibility to ensure that these properties hold before calling + /// `MaybeUninit::assume_init` or otherwise reading the returned values. + /// + /// Finally, you must also ensure that any values allocated into the bump + /// arena have not had their `Drop` implementations called on them, + /// e.g. after dropping a [`bumpalo::boxed::Box`][crate::boxed::Box]. + /// + /// ## Example + /// + /// ``` + /// let mut bump = bumpalo::Bump::new(); + /// + /// // Allocate a bunch of `i32`s in this bump arena, potentially causing + /// // additional memory chunks to be reserved. + /// for i in 0..10000 { + /// bump.alloc(i); + /// } + /// + /// // Iterate over each chunk we've bump allocated into. This is safe + /// // because we have only allocated `i32`s in this arena, which fulfills + /// // the above requirements. + /// for ch in bump.iter_allocated_chunks() { + /// println!("Used a chunk that is {} bytes long", ch.len()); + /// println!("The first byte is {:?}", unsafe { + /// ch[0].assume_init() + /// }); + /// } + /// + /// // Within a chunk, allocations are ordered from most recent to least + /// // recent. If we allocated 'a', then 'b', then 'c', when we iterate + /// // through the chunk's data, we get them in the order 'c', then 'b', + /// // then 'a'. + /// + /// bump.reset(); + /// bump.alloc(b'a'); + /// bump.alloc(b'b'); + /// bump.alloc(b'c'); + /// + /// assert_eq!(bump.iter_allocated_chunks().count(), 1); + /// let chunk = bump.iter_allocated_chunks().nth(0).unwrap(); + /// assert_eq!(chunk.len(), 3); + /// + /// // Safe because we've only allocated `u8`s in this arena, which + /// // fulfills the above requirements. + /// unsafe { + /// assert_eq!(chunk[0].assume_init(), b'c'); + /// assert_eq!(chunk[1].assume_init(), b'b'); + /// assert_eq!(chunk[2].assume_init(), b'a'); + /// } + /// ``` + pub fn iter_allocated_chunks(&mut self) -> ChunkIter<'_, MIN_ALIGN> { + // Safety: Ensured by mutable borrow of `self`. + let raw = unsafe { self.iter_allocated_chunks_raw() }; + ChunkIter { + raw, + bump: PhantomData, + } + } + + /// Returns an iterator over raw pointers to chunks of allocated memory that + /// this arena has bump allocated into. + /// + /// This is an unsafe version of [`iter_allocated_chunks()`](Bump::iter_allocated_chunks), + /// with the caller responsible for safe usage of the returned pointers as + /// well as ensuring that the iterator is not invalidated by new + /// allocations. + /// + /// ## Safety + /// + /// Allocations from this arena must not be performed while the returned + /// iterator is alive. If reading the chunk data (or casting to a reference) + /// the caller must ensure that there exist no mutable references to + /// previously allocated data. + /// + /// In addition, all of the caveats when reading the chunk data from + /// [`iter_allocated_chunks()`](Bump::iter_allocated_chunks) still apply. + pub unsafe fn iter_allocated_chunks_raw(&self) -> ChunkRawIter<'_, MIN_ALIGN> { + ChunkRawIter { + footer: self.current_chunk_footer.get(), + bump: PhantomData, + } + } + + /// Calculates the number of bytes currently allocated across all chunks in + /// this bump arena. + /// + /// If you allocate types of different alignments or types with + /// larger-than-typical alignment in the same arena, some padding + /// bytes might get allocated in the bump arena. Note that those padding + /// bytes will add to this method's resulting sum, so you cannot rely + /// on it only counting the sum of the sizes of the things + /// you've allocated in the arena. + /// + /// The allocated bytes do not include the size of bumpalo's metadata, + /// so the amount of memory requested from the Rust allocator is higher + /// than the returned value. + /// + /// ## Example + /// + /// ``` + /// let bump = bumpalo::Bump::new(); + /// let _x = bump.alloc_slice_fill_default::(5); + /// let bytes = bump.allocated_bytes(); + /// assert!(bytes >= core::mem::size_of::() * 5); + /// ``` + pub fn allocated_bytes(&self) -> usize { + let footer = self.current_chunk_footer.get(); + + unsafe { footer.as_ref().allocated_bytes } + } + + /// Calculates the number of bytes requested from the Rust allocator for this `Bump`. + /// + /// This number is equal to the [`allocated_bytes()`](Self::allocated_bytes) plus + /// the size of the bump metadata. + pub fn allocated_bytes_including_metadata(&self) -> usize { + let metadata_size = + unsafe { self.iter_allocated_chunks_raw().count() * mem::size_of::() }; + self.allocated_bytes() + metadata_size + } + + #[inline] + unsafe fn is_last_allocation(&self, ptr: NonNull) -> bool { + let footer = self.current_chunk_footer.get(); + let footer = footer.as_ref(); + footer.ptr.get() == ptr + } + + #[inline] + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + // If the pointer is the last allocation we made, we can reuse the bytes, + // otherwise they are simply leaked -- at least until somebody calls reset(). + if self.is_last_allocation(ptr) { + let ptr = self.current_chunk_footer.get().as_ref().ptr.get(); + let ptr = ptr.as_ptr().add(layout.size()); + + let ptr = round_mut_ptr_up_to_unchecked(ptr, MIN_ALIGN); + debug_assert!( + is_pointer_aligned_to(ptr, MIN_ALIGN), + "bump pointer {ptr:#p} should be aligned to the minimum alignment of {MIN_ALIGN:#x}" + ); + let ptr = NonNull::new_unchecked(ptr); + self.current_chunk_footer.get().as_ref().ptr.set(ptr); + } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocErr> { + // If the new layout demands greater alignment than the old layout has, + // then either + // + // 1. the pointer happens to satisfy the new layout's alignment, so we + // got lucky and can return the pointer as-is, or + // + // 2. the pointer is not aligned to the new layout's demanded alignment, + // and we are unlucky. + // + // In the case of (2), to successfully "shrink" the allocation, we have + // to allocate a whole new region for the new layout. + if old_layout.align() < new_layout.align() { + return if is_pointer_aligned_to(ptr.as_ptr(), new_layout.align()) { + Ok(ptr) + } else { + let new_ptr = self.try_alloc_layout(new_layout)?; + + // We know that these regions are nonoverlapping because + // `new_ptr` is a fresh allocation. + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), new_layout.size()); + + Ok(new_ptr) + }; + } + + debug_assert!(is_pointer_aligned_to(ptr.as_ptr(), new_layout.align())); + + let old_size = old_layout.size(); + let new_size = new_layout.size(); + + // This is how much space we would *actually* reclaim while satisfying + // the requested alignment. + let delta = round_down_to(old_size - new_size, new_layout.align().max(MIN_ALIGN)); + + if self.is_last_allocation(ptr) + // Only reclaim the excess space (which requires a copy) if it + // is worth it: we are actually going to recover "enough" space + // and we can do a non-overlapping copy. + // + // We do `(old_size + 1) / 2` so division rounds up rather than + // down. Consider when: + // + // old_size = 5 + // new_size = 3 + // + // If we do not take care to round up, this will result in: + // + // delta = 2 + // (old_size / 2) = (5 / 2) = 2 + // + // And the the check will succeed even though we are have + // overlapping ranges: + // + // |--------old-allocation-------| + // |------from-------| + // |-------to--------| + // +-----+-----+-----+-----+-----+ + // | a | b | c | . | . | + // +-----+-----+-----+-----+-----+ + // + // But we MUST NOT have overlapping ranges because we use + // `copy_nonoverlapping` below! Therefore, we round the division + // up to avoid this issue. + && delta >= (old_size + 1) / 2 + { + let footer = self.current_chunk_footer.get(); + let footer = footer.as_ref(); + + // NB: new_ptr is aligned, because ptr *has to* be aligned, and we + // made sure delta is aligned. + let new_ptr = NonNull::new_unchecked(footer.ptr.get().as_ptr().add(delta)); + debug_assert!( + is_pointer_aligned_to(new_ptr.as_ptr(), MIN_ALIGN), + "bump pointer {new_ptr:#p} should be aligned to the minimum alignment of {MIN_ALIGN:#x}" + ); + footer.ptr.set(new_ptr); + + // NB: we know it is non-overlapping because of the size check + // in the `if` condition. + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), new_size); + + return Ok(new_ptr); + } + + // If this wasn't the last allocation, or shrinking wasn't worth it, + // simply return the old pointer as-is. + Ok(ptr) + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocErr> { + let old_size = old_layout.size(); + + let new_size = new_layout.size(); + let new_size = round_up_to(new_size, MIN_ALIGN).ok_or(AllocErr)?; + + let align_is_compatible = old_layout.align() >= new_layout.align(); + + if align_is_compatible && self.is_last_allocation(ptr) { + // Try to allocate the delta size within this same block so we can + // reuse the currently allocated space. + let delta = new_size - old_size; + if let Some(p) = + self.try_alloc_layout_fast(layout_from_size_align(delta, old_layout.align())?) + { + ptr::copy(ptr.as_ptr(), p.as_ptr(), old_size); + return Ok(p); + } + } + + // Fallback: do a fresh allocation and copy the existing data into it. + let new_ptr = self.try_alloc_layout(new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size); + Ok(new_ptr) + } +} + +/// An iterator over each chunk of allocated memory that +/// an arena has bump allocated into. +/// +/// The chunks are returned ordered by allocation time, with the most recently +/// allocated chunk being returned first. +/// +/// The values inside each chunk are also ordered by allocation time, with the most +/// recent allocation being earlier in the slice. +/// +/// This struct is created by the [`iter_allocated_chunks`] method on +/// [`Bump`]. See that function for a safety description regarding reading from the returned items. +/// +/// [`Bump`]: struct.Bump.html +/// [`iter_allocated_chunks`]: struct.Bump.html#method.iter_allocated_chunks +#[derive(Debug)] +pub struct ChunkIter<'a, const MIN_ALIGN: usize = 1> { + raw: ChunkRawIter<'a, MIN_ALIGN>, + bump: PhantomData<&'a mut Bump>, +} + +impl<'a, const MIN_ALIGN: usize> Iterator for ChunkIter<'a, MIN_ALIGN> { + type Item = &'a [mem::MaybeUninit]; + + fn next(&mut self) -> Option { + unsafe { + let (ptr, len) = self.raw.next()?; + let slice = slice::from_raw_parts(ptr as *const mem::MaybeUninit, len); + Some(slice) + } + } +} + +impl<'a, const MIN_ALIGN: usize> iter::FusedIterator for ChunkIter<'a, MIN_ALIGN> {} + +/// An iterator over raw pointers to chunks of allocated memory that this +/// arena has bump allocated into. +/// +/// See [`ChunkIter`] for details regarding the returned chunks. +/// +/// This struct is created by the [`iter_allocated_chunks_raw`] method on +/// [`Bump`]. See that function for a safety description regarding reading from +/// the returned items. +/// +/// [`Bump`]: struct.Bump.html +/// [`iter_allocated_chunks_raw`]: struct.Bump.html#method.iter_allocated_chunks_raw +#[derive(Debug)] +pub struct ChunkRawIter<'a, const MIN_ALIGN: usize = 1> { + footer: NonNull, + bump: PhantomData<&'a Bump>, +} + +impl Iterator for ChunkRawIter<'_, MIN_ALIGN> { + type Item = (*mut u8, usize); + fn next(&mut self) -> Option<(*mut u8, usize)> { + unsafe { + let foot = self.footer.as_ref(); + if foot.is_empty() { + return None; + } + let (ptr, len) = foot.as_raw_parts(); + self.footer = foot.prev.get(); + Some((ptr as *mut u8, len)) + } + } +} + +impl iter::FusedIterator for ChunkRawIter<'_, MIN_ALIGN> {} + +#[inline(never)] +#[cold] +fn oom() -> ! { + panic!("out of memory") +} + +unsafe impl<'a, const MIN_ALIGN: usize> alloc::Alloc for &'a Bump { + #[inline(always)] + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + self.try_alloc_layout(layout) + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + Bump::::dealloc(self, ptr, layout); + } + + #[inline] + unsafe fn realloc( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { + let old_size = layout.size(); + + if old_size == 0 { + return self.try_alloc_layout(layout); + } + + let new_layout = layout_from_size_align(new_size, layout.align())?; + if new_size <= old_size { + Bump::shrink(self, ptr, layout, new_layout) + } else { + Bump::grow(self, ptr, layout, new_layout) + } + } +} + +/// This function tests that Bump isn't Sync. +/// ```compile_fail +/// use bumpalo::Bump; +/// fn _requires_sync(_value: T) {} +/// fn _bump_not_sync(b: Bump) { +/// _requires_sync(b); +/// } +/// ``` +#[cfg(doctest)] +fn _doctest_only() {} + +#[cfg(any(feature = "allocator_api", feature = "allocator-api2"))] +unsafe impl<'a, const MIN_ALIGN: usize> Allocator for &'a Bump { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.try_alloc_layout(layout) + .map(|p| unsafe { + NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(p.as_ptr(), layout.size())) + }) + .map_err(|_| AllocError) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + Bump::::dealloc(self, ptr, layout) + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + Bump::::shrink(self, ptr, old_layout, new_layout) + .map(|p| unsafe { + NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(p.as_ptr(), new_layout.size())) + }) + .map_err(|_| AllocError) + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + Bump::::grow(self, ptr, old_layout, new_layout) + .map(|p| unsafe { + NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(p.as_ptr(), new_layout.size())) + }) + .map_err(|_| AllocError) + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + let mut ptr = self.grow(ptr, old_layout, new_layout)?; + ptr.as_mut()[old_layout.size()..].fill(0); + Ok(ptr) + } +} + +// NB: Only tests which require private types, fields, or methods should be in +// here. Anything that can just be tested via public API surface should be in +// `bumpalo/tests/all/*`. +#[cfg(test)] +mod tests { + use super::*; + + // Uses private type `ChunkFooter`. + #[test] + fn chunk_footer_is_five_words() { + assert_eq!(mem::size_of::(), mem::size_of::() * 6); + } + + // Uses private `DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER` and `FOOTER_SIZE`. + #[test] + fn allocated_bytes() { + let mut b = Bump::with_capacity(1); + + assert_eq!(b.allocated_bytes(), DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER); + assert_eq!( + b.allocated_bytes_including_metadata(), + DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER + FOOTER_SIZE + ); + + b.reset(); + + assert_eq!(b.allocated_bytes(), DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER); + assert_eq!( + b.allocated_bytes_including_metadata(), + DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER + FOOTER_SIZE + ); + } + + // Uses private `alloc` module. + #[test] + fn test_realloc() { + use crate::alloc::Alloc; + + unsafe { + const CAPACITY: usize = DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER; + let mut b = Bump::<1>::with_min_align_and_capacity(CAPACITY); + + // `realloc` doesn't shrink allocations that aren't "worth it". + let layout = Layout::from_size_align(100, 1).unwrap(); + let p = b.alloc_layout(layout); + let q = (&b).realloc(p, layout, 51).unwrap(); + assert_eq!(p, q); + b.reset(); + + // `realloc` will shrink allocations that are "worth it". + let layout = Layout::from_size_align(100, 1).unwrap(); + let p = b.alloc_layout(layout); + let q = (&b).realloc(p, layout, 50).unwrap(); + assert!(p != q); + b.reset(); + + // `realloc` will reuse the last allocation when growing. + let layout = Layout::from_size_align(10, 1).unwrap(); + let p = b.alloc_layout(layout); + let q = (&b).realloc(p, layout, 11).unwrap(); + assert_eq!(q.as_ptr() as usize, p.as_ptr() as usize - 1); + b.reset(); + + // `realloc` will allocate a new chunk when growing the last + // allocation, if need be. + let layout = Layout::from_size_align(1, 1).unwrap(); + let p = b.alloc_layout(layout); + let q = (&b).realloc(p, layout, CAPACITY + 1).unwrap(); + assert_ne!(q.as_ptr() as usize, p.as_ptr() as usize - CAPACITY); + b.reset(); + + // `realloc` will allocate and copy when reallocating anything that + // wasn't the last allocation. + let layout = Layout::from_size_align(1, 1).unwrap(); + let p = b.alloc_layout(layout); + let _ = b.alloc_layout(layout); + let q = (&b).realloc(p, layout, 2).unwrap(); + assert!(q.as_ptr() as usize != p.as_ptr() as usize - 1); + b.reset(); + } + } + + // Uses our private `alloc` module. + #[test] + fn invalid_read() { + use alloc::Alloc; + + let mut b = &Bump::new(); + + unsafe { + let l1 = Layout::from_size_align(12000, 4).unwrap(); + let p1 = Alloc::alloc(&mut b, l1).unwrap(); + + let l2 = Layout::from_size_align(1000, 4).unwrap(); + Alloc::alloc(&mut b, l2).unwrap(); + + let p1 = b.realloc(p1, l1, 24000).unwrap(); + let l3 = Layout::from_size_align(24000, 4).unwrap(); + b.realloc(p1, l3, 48000).unwrap(); + } + } +} diff --git a/deps/crates/vendor/cranelift-bforest/.cargo-checksum.json b/deps/crates/vendor/cranelift-bforest/.cargo-checksum.json new file mode 100644 index 00000000000000..b38709d581376e --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"3445b7f209285aa48dd62759f5fabff2f4f5d19ef4e9b0eef4b77e4983a4006e","Cargo.lock":"d5865c6bfbfe56f34d08599c1e089e287ce67a1d776c437056b012bb084c05ab","Cargo.toml":"e20c293edefcaa26132d550445c03c73c1ad065edd923bffa7d9aa6f50e9b804","Cargo.toml.orig":"e08fdc7ebcd752ba045cb5d18f61ca3a82c7f366053fb14891b5125bb1df0c37","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"f813243589cbf47418dc966a863bb8efeee9f9c7a03b44c04890faf3b50ca065","src/map.rs":"f2f7db1a0daa60249d426580ecc7dc913228f7dee1aa8437680fa78e353c448f","src/node.rs":"48acd09f300223dec183cb22bc3ee9634f9ae09b4a0dcf31fa6e749ef4829770","src/path.rs":"db258cfb525afdc7b4433996439e4da6dfb090649180f35f34c0ce0df6588364","src/pool.rs":"5907efaadd76261727f07c06e16644d8742d497f53f2e2c4cc8bf3eeca99ffd1","src/set.rs":"08b984f3ba810b2baffa6f915e305ff88427569340dfaffbaea6b7b5363ae606"},"package":"e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-bforest/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-bforest/.cargo_vcs_info.json new file mode 100644 index 00000000000000..31e8a33685448e --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/bforest" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-bforest/Cargo.lock b/deps/crates/vendor/cranelift-bforest/Cargo.lock new file mode 100644 index 00000000000000..fd45c1ece02a4b --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", +] diff --git a/deps/crates/vendor/cranelift-bforest/Cargo.toml b/deps/crates/vendor/cranelift-bforest/Cargo.toml new file mode 100644 index 00000000000000..aca7e92cdc38de --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/Cargo.toml @@ -0,0 +1,73 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-bforest" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A forest of B+-trees" +documentation = "https://docs.rs/cranelift-bforest" +readme = "README.md" +keywords = [ + "btree", + "forest", + "set", + "map", +] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_bforest" +path = "src/lib.rs" + +[dependencies.cranelift-entity] +version = "0.116.1" + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-bforest/Cargo.toml.orig b/deps/crates/vendor/cranelift-bforest/Cargo.toml.orig new file mode 100644 index 00000000000000..e1b58625d35b92 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/Cargo.toml.orig @@ -0,0 +1,19 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-bforest" +version = "0.116.1" +description = "A forest of B+-trees" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift-bforest" +repository = "https://github.com/bytecodealliance/wasmtime" +categories = ["no-std"] +readme = "README.md" +keywords = ["btree", "forest", "set", "map"] +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +cranelift-entity = { workspace = true } diff --git a/deps/crates/vendor/cranelift-bforest/LICENSE b/deps/crates/vendor/cranelift-bforest/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-bforest/README.md b/deps/crates/vendor/cranelift-bforest/README.md new file mode 100644 index 00000000000000..391d6287d290d9 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/README.md @@ -0,0 +1,12 @@ +This crate contains array-based data structures used by the core Cranelift code +generator which represent a set of small ordered sets or maps. + +**These are not general purpose data structures that are somehow magically faster that the +standard library's `BTreeSet` and `BTreeMap` types.** + +The tradeoffs are different: + +- Keys and values are expected to be small and copyable. We optimize for 32-bit types. +- A comparator object is used to compare keys, allowing smaller "context free" keys. +- Empty trees have a very small 32-bit footprint. +- All the trees in a forest can be cleared in constant time. diff --git a/deps/crates/vendor/cranelift-bforest/src/lib.rs b/deps/crates/vendor/cranelift-bforest/src/lib.rs new file mode 100644 index 00000000000000..90eda03d85f6de --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/lib.rs @@ -0,0 +1,183 @@ +//! A forest of B+-trees. +//! +//! This crate provides a data structures representing a set of small ordered sets or maps. +//! It is implemented as a forest of B+-trees all allocating nodes out of the same pool. +//! +//! **These are not general purpose data structures that are somehow magically faster that the +//! standard library's `BTreeSet` and `BTreeMap` types.** +//! +//! The tradeoffs are different: +//! +//! - Keys and values are expected to be small and copyable. We optimize for 32-bit types. +//! - A comparator object is used to compare keys, allowing smaller "context free" keys. +//! - Empty trees have a very small 32-bit footprint. +//! - All the trees in a forest can be cleared in constant time. + +#![deny(missing_docs)] +#![no_std] + +#[cfg(test)] +extern crate alloc; + +#[macro_use] +extern crate cranelift_entity as entity; +use crate::entity::packed_option; + +use core::borrow::BorrowMut; +use core::cmp::Ordering; + +mod map; +mod node; +mod path; +mod pool; +mod set; + +pub use self::map::{Map, MapCursor, MapForest, MapIter}; +pub use self::set::{Set, SetCursor, SetForest, SetIter}; + +use self::node::NodeData; +use self::path::Path; +use self::pool::NodePool; + +/// The maximum branching factor of an inner node in a B+-tree. +/// The minimum number of outgoing edges is `INNER_SIZE/2`. +const INNER_SIZE: usize = 8; + +/// Given the worst case branching factor of `INNER_SIZE/2` = 4, this is the +/// worst case path length from the root node to a leaf node in a tree with 2^32 +/// entries. We would run out of node references before we hit `MAX_PATH`. +const MAX_PATH: usize = 16; + +/// Key comparator. +/// +/// Keys don't need to implement `Ord`. They are compared using a comparator object which +/// provides a context for comparison. +pub trait Comparator +where + K: Copy, +{ + /// Compare keys `a` and `b`. + /// + /// This relation must provide a total ordering or the key space. + fn cmp(&self, a: K, b: K) -> Ordering; + + /// Binary search for `k` in an ordered slice. + /// + /// Assume that `s` is already sorted according to this ordering, search for the key `k`. + /// + /// Returns `Ok(idx)` if `k` was found in the slice or `Err(idx)` with the position where it + /// should be inserted to preserve the ordering. + fn search(&self, k: K, s: &[K]) -> Result { + s.binary_search_by(|x| self.cmp(*x, k)) + } +} + +/// Trivial comparator that doesn't actually provide any context. +impl Comparator for () +where + K: Copy + Ord, +{ + fn cmp(&self, a: K, b: K) -> Ordering { + a.cmp(&b) + } +} + +/// Family of types shared by the map and set forest implementations. +trait Forest { + /// The key type is present for both sets and maps. + type Key: Copy; + + /// The value type is `()` for sets. + type Value: Copy; + + /// An array of keys for the leaf nodes. + type LeafKeys: Copy + BorrowMut<[Self::Key]>; + + /// An array of values for the leaf nodes. + type LeafValues: Copy + BorrowMut<[Self::Value]>; + + /// Splat a single key into a whole array. + fn splat_key(key: Self::Key) -> Self::LeafKeys; + + /// Splat a single value inst a whole array + fn splat_value(value: Self::Value) -> Self::LeafValues; +} + +/// A reference to a B+-tree node. +#[derive(Clone, Copy, PartialEq, Eq)] +struct Node(u32); +entity_impl!(Node, "node"); + +/// Empty type to be used as the "value" in B-trees representing sets. +#[derive(Clone, Copy)] +struct SetValue(); + +/// Insert `x` into `s` at position `i`, pushing out the last element. +fn slice_insert(s: &mut [T], i: usize, x: T) { + for j in (i + 1..s.len()).rev() { + s[j] = s[j - 1]; + } + s[i] = x; +} + +/// Shift elements in `s` to the left by `n` positions. +fn slice_shift(s: &mut [T], n: usize) { + for j in 0..s.len() - n { + s[j] = s[j + n]; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::entity::EntityRef; + + /// An opaque reference to a basic block in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Block(u32); + entity_impl!(Block, "block"); + + #[test] + fn comparator() { + let block1 = Block::new(1); + let block2 = Block::new(2); + let block3 = Block::new(3); + let block4 = Block::new(4); + let vals = [block1, block2, block4]; + let comp = (); + assert_eq!(comp.search(block1, &vals), Ok(0)); + assert_eq!(comp.search(block3, &vals), Err(2)); + assert_eq!(comp.search(block4, &vals), Ok(2)); + } + + #[test] + fn slice_insertion() { + let mut a = ['a', 'b', 'c', 'd']; + + slice_insert(&mut a[0..1], 0, 'e'); + assert_eq!(a, ['e', 'b', 'c', 'd']); + + slice_insert(&mut a, 0, 'a'); + assert_eq!(a, ['a', 'e', 'b', 'c']); + + slice_insert(&mut a, 3, 'g'); + assert_eq!(a, ['a', 'e', 'b', 'g']); + + slice_insert(&mut a, 1, 'h'); + assert_eq!(a, ['a', 'h', 'e', 'b']); + } + + #[test] + fn slice_shifting() { + let mut a = ['a', 'b', 'c', 'd']; + + slice_shift(&mut a[0..1], 1); + assert_eq!(a, ['a', 'b', 'c', 'd']); + + slice_shift(&mut a[1..], 1); + assert_eq!(a, ['a', 'c', 'd', 'd']); + + slice_shift(&mut a, 2); + assert_eq!(a, ['d', 'd', 'd', 'd']); + } +} diff --git a/deps/crates/vendor/cranelift-bforest/src/map.rs b/deps/crates/vendor/cranelift-bforest/src/map.rs new file mode 100644 index 00000000000000..d539e1d8cc4eb9 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/map.rs @@ -0,0 +1,921 @@ +//! Forest of maps. + +use super::{Comparator, Forest, Node, NodeData, NodePool, Path, INNER_SIZE}; +use crate::packed_option::PackedOption; +#[cfg(test)] +use alloc::string::String; +#[cfg(test)] +use core::fmt; +use core::marker::PhantomData; + +/// Tag type defining forest types for a map. +struct MapTypes(PhantomData<(K, V)>); + +impl Forest for MapTypes +where + K: Copy, + V: Copy, +{ + type Key = K; + type Value = V; + type LeafKeys = [K; INNER_SIZE - 1]; + type LeafValues = [V; INNER_SIZE - 1]; + + fn splat_key(key: Self::Key) -> Self::LeafKeys { + [key; INNER_SIZE - 1] + } + + fn splat_value(value: Self::Value) -> Self::LeafValues { + [value; INNER_SIZE - 1] + } +} + +/// Memory pool for a forest of `Map` instances. +pub struct MapForest +where + K: Copy, + V: Copy, +{ + nodes: NodePool>, +} + +impl MapForest +where + K: Copy, + V: Copy, +{ + /// Create a new empty forest. + pub fn new() -> Self { + Self { + nodes: NodePool::new(), + } + } + + /// Clear all maps in the forest. + /// + /// All `Map` instances belong to this forest are invalidated and should no longer be used. + pub fn clear(&mut self) { + self.nodes.clear(); + } +} + +/// B-tree mapping from `K` to `V`. +/// +/// This is not a general-purpose replacement for `BTreeMap`. See the [module +/// documentation](index.html) for more information about design tradeoffs. +/// +/// Maps can be cloned, but that operation should only be used as part of cloning the whole forest +/// they belong to. *Cloning a map does not allocate new memory for the clone*. It creates an alias +/// of the same memory. +#[derive(Clone)] +pub struct Map +where + K: Copy, + V: Copy, +{ + root: PackedOption, + unused: PhantomData<(K, V)>, +} + +impl Map +where + K: Copy, + V: Copy, +{ + /// Make an empty map. + pub fn new() -> Self { + Self { + root: None.into(), + unused: PhantomData, + } + } + + /// Is this an empty map? + pub fn is_empty(&self) -> bool { + self.root.is_none() + } + + /// Get the value stored for `key`. + pub fn get>(&self, key: K, forest: &MapForest, comp: &C) -> Option { + self.root + .expand() + .and_then(|root| Path::default().find(key, root, &forest.nodes, comp)) + } + + /// Look up the value stored for `key`. + /// + /// If it exists, return the stored key-value pair. + /// + /// Otherwise, return the last key-value pair with a key that is less than or equal to `key`. + /// + /// If no stored keys are less than or equal to `key`, return `None`. + pub fn get_or_less>( + &self, + key: K, + forest: &MapForest, + comp: &C, + ) -> Option<(K, V)> { + self.root.expand().and_then(|root| { + let mut path = Path::default(); + match path.find(key, root, &forest.nodes, comp) { + Some(v) => Some((key, v)), + None => path.prev(root, &forest.nodes), + } + }) + } + + /// Insert `key, value` into the map and return the old value stored for `key`, if any. + pub fn insert>( + &mut self, + key: K, + value: V, + forest: &mut MapForest, + comp: &C, + ) -> Option { + self.cursor(forest, comp).insert(key, value) + } + + /// Remove `key` from the map and return the removed value for `key`, if any. + pub fn remove>( + &mut self, + key: K, + forest: &mut MapForest, + comp: &C, + ) -> Option { + let mut c = self.cursor(forest, comp); + if c.goto(key).is_some() { + c.remove() + } else { + None + } + } + + /// Remove all entries. + pub fn clear(&mut self, forest: &mut MapForest) { + if let Some(root) = self.root.take() { + forest.nodes.free_tree(root); + } + } + + /// Retains only the elements specified by the predicate. + /// + /// Remove all key-value pairs where the predicate returns false. + /// + /// The predicate is allowed to update the values stored in the map. + pub fn retain(&mut self, forest: &mut MapForest, mut predicate: F) + where + F: FnMut(K, &mut V) -> bool, + { + let mut path = Path::default(); + if let Some(root) = self.root.expand() { + path.first(root, &forest.nodes); + } + while let Some((node, entry)) = path.leaf_pos() { + let keep = { + let (ks, vs) = forest.nodes[node].unwrap_leaf_mut(); + predicate(ks[entry], &mut vs[entry]) + }; + if keep { + path.next(&forest.nodes); + } else { + self.root = path.remove(&mut forest.nodes).into(); + } + } + } + + /// Create a cursor for navigating this map. The cursor is initially positioned off the end of + /// the map. + pub fn cursor<'a, C: Comparator>( + &'a mut self, + forest: &'a mut MapForest, + comp: &'a C, + ) -> MapCursor<'a, K, V, C> { + MapCursor::new(self, forest, comp) + } + + /// Create an iterator traversing this map. The iterator type is `(K, V)`. + pub fn iter<'a>(&'a self, forest: &'a MapForest) -> MapIter<'a, K, V> { + MapIter { + root: self.root, + pool: &forest.nodes, + path: Path::default(), + } + } +} + +impl Default for Map +where + K: Copy, + V: Copy, +{ + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +impl Map +where + K: Copy + fmt::Display, + V: Copy, +{ + /// Verify consistency. + fn verify>(&self, forest: &MapForest, comp: &C) + where + NodeData>: fmt::Display, + { + if let Some(root) = self.root.expand() { + forest.nodes.verify_tree(root, comp); + } + } + + /// Get a text version of the path to `key`. + fn tpath>(&self, key: K, forest: &MapForest, comp: &C) -> String { + use alloc::string::ToString; + match self.root.expand() { + None => "map(empty)".to_string(), + Some(root) => { + let mut path = Path::default(); + path.find(key, root, &forest.nodes, comp); + path.to_string() + } + } + } +} + +/// A position in a `Map` used to navigate and modify the ordered map. +/// +/// A cursor always points at a key-value pair in the map, or "off the end" which is a position +/// after the last entry in the map. +pub struct MapCursor<'a, K, V, C> +where + K: 'a + Copy, + V: 'a + Copy, + C: 'a + Comparator, +{ + root: &'a mut PackedOption, + pool: &'a mut NodePool>, + comp: &'a C, + path: Path>, +} + +impl<'a, K, V, C> MapCursor<'a, K, V, C> +where + K: Copy, + V: Copy, + C: Comparator, +{ + /// Create a cursor with a default (off-the-end) location. + fn new(container: &'a mut Map, forest: &'a mut MapForest, comp: &'a C) -> Self { + Self { + root: &mut container.root, + pool: &mut forest.nodes, + comp, + path: Path::default(), + } + } + + /// Is this cursor pointing to an empty map? + pub fn is_empty(&self) -> bool { + self.root.is_none() + } + + /// Move cursor to the next key-value pair and return it. + /// + /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end + /// position. + pub fn next(&mut self) -> Option<(K, V)> { + self.path.next(self.pool) + } + + /// Move cursor to the previous key-value pair and return it. + /// + /// If the cursor is already pointing at the first entry, leave it there and return `None`. + pub fn prev(&mut self) -> Option<(K, V)> { + self.root + .expand() + .and_then(|root| self.path.prev(root, self.pool)) + } + + /// Get the current key, or `None` if the cursor is at the end. + pub fn key(&self) -> Option { + self.path + .leaf_pos() + .and_then(|(node, entry)| self.pool[node].unwrap_leaf().0.get(entry).cloned()) + } + + /// Get the current value, or `None` if the cursor is at the end. + pub fn value(&self) -> Option { + self.path + .leaf_pos() + .and_then(|(node, entry)| self.pool[node].unwrap_leaf().1.get(entry).cloned()) + } + + /// Get a mutable reference to the current value, or `None` if the cursor is at the end. + pub fn value_mut(&mut self) -> Option<&mut V> { + self.path + .leaf_pos() + .and_then(move |(node, entry)| self.pool[node].unwrap_leaf_mut().1.get_mut(entry)) + } + + /// Move this cursor to `key`. + /// + /// If `key` is in the map, place the cursor at `key` and return the corresponding value. + /// + /// If `key` is not in the set, place the cursor at the next larger element (or the end) and + /// return `None`. + pub fn goto(&mut self, elem: K) -> Option { + self.root.expand().and_then(|root| { + let v = self.path.find(elem, root, self.pool, self.comp); + if v.is_none() { + self.path.normalize(self.pool); + } + v + }) + } + + /// Move this cursor to the first element. + pub fn goto_first(&mut self) -> Option { + self.root.map(|root| self.path.first(root, self.pool).1) + } + + /// Insert `(key, value))` into the map and leave the cursor at the inserted pair. + /// + /// If the map did not contain `key`, return `None`. + /// + /// If `key` is already present, replace the existing with `value` and return the old value. + pub fn insert(&mut self, key: K, value: V) -> Option { + match self.root.expand() { + None => { + let root = self.pool.alloc_node(NodeData::leaf(key, value)); + *self.root = root.into(); + self.path.set_root_node(root); + None + } + Some(root) => { + // TODO: Optimize the case where `self.path` is already at the correct insert pos. + let old = self.path.find(key, root, self.pool, self.comp); + if old.is_some() { + *self.path.value_mut(self.pool) = value; + } else { + *self.root = self.path.insert(key, value, self.pool).into(); + } + old + } + } + } + + /// Remove the current entry (if any) and return the mapped value. + /// This advances the cursor to the next entry after the removed one. + pub fn remove(&mut self) -> Option { + let value = self.value(); + if value.is_some() { + *self.root = self.path.remove(self.pool).into(); + } + value + } +} + +/// An iterator visiting the key-value pairs of a `Map`. +pub struct MapIter<'a, K, V> +where + K: 'a + Copy, + V: 'a + Copy, +{ + root: PackedOption, + pool: &'a NodePool>, + path: Path>, +} + +impl<'a, K, V> Iterator for MapIter<'a, K, V> +where + K: 'a + Copy, + V: 'a + Copy, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + // We use `self.root` to indicate if we need to go to the first element. Reset to `None` + // once we've returned the first element. This also works for an empty tree since the + // `path.next()` call returns `None` when the path is empty. This also fuses the iterator. + match self.root.take() { + Some(root) => Some(self.path.first(root, self.pool)), + None => self.path.next(self.pool), + } + } +} + +#[cfg(test)] +impl<'a, K, V, C> MapCursor<'a, K, V, C> +where + K: Copy + fmt::Display, + V: Copy + fmt::Display, + C: Comparator, +{ + fn verify(&self) { + self.path.verify(self.pool); + self.root.map(|root| self.pool.verify_tree(root, self.comp)); + } + + /// Get a text version of the path to the current position. + fn tpath(&self) -> String { + use alloc::string::ToString; + self.path.to_string() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec::Vec; + use core::mem; + + #[test] + fn node_size() { + // check that nodes are cache line sized when keys and values are 32 bits. + type F = MapTypes; + assert_eq!(mem::size_of::>(), 64); + } + + #[test] + fn empty() { + let mut f = MapForest::::new(); + f.clear(); + + let mut m = Map::::new(); + assert!(m.is_empty()); + m.clear(&mut f); + + assert_eq!(m.get(7, &f, &()), None); + assert_eq!(m.iter(&f).next(), None); + assert_eq!(m.get_or_less(7, &f, &()), None); + m.retain(&mut f, |_, _| unreachable!()); + + let mut c = m.cursor(&mut f, &()); + assert!(c.is_empty()); + assert_eq!(c.key(), None); + assert_eq!(c.value(), None); + assert_eq!(c.next(), None); + assert_eq!(c.prev(), None); + c.verify(); + assert_eq!(c.tpath(), ""); + assert_eq!(c.goto_first(), None); + assert_eq!(c.tpath(), ""); + } + + #[test] + fn inserting() { + let f = &mut MapForest::::new(); + let mut m = Map::::new(); + + // The first seven values stay in a single leaf node. + assert_eq!(m.insert(50, 5.0, f, &()), None); + assert_eq!(m.insert(50, 5.5, f, &()), Some(5.0)); + assert_eq!(m.insert(20, 2.0, f, &()), None); + assert_eq!(m.insert(80, 8.0, f, &()), None); + assert_eq!(m.insert(40, 4.0, f, &()), None); + assert_eq!(m.insert(60, 6.0, f, &()), None); + assert_eq!(m.insert(90, 9.0, f, &()), None); + assert_eq!(m.insert(200, 20.0, f, &()), None); + + m.verify(f, &()); + + assert_eq!( + m.iter(f).collect::>(), + [ + (20, 2.0), + (40, 4.0), + (50, 5.5), + (60, 6.0), + (80, 8.0), + (90, 9.0), + (200, 20.0), + ] + ); + + assert_eq!(m.get(0, f, &()), None); + assert_eq!(m.get(20, f, &()), Some(2.0)); + assert_eq!(m.get(30, f, &()), None); + assert_eq!(m.get(40, f, &()), Some(4.0)); + assert_eq!(m.get(50, f, &()), Some(5.5)); + assert_eq!(m.get(60, f, &()), Some(6.0)); + assert_eq!(m.get(70, f, &()), None); + assert_eq!(m.get(80, f, &()), Some(8.0)); + assert_eq!(m.get(100, f, &()), None); + + assert_eq!(m.get_or_less(0, f, &()), None); + assert_eq!(m.get_or_less(20, f, &()), Some((20, 2.0))); + assert_eq!(m.get_or_less(30, f, &()), Some((20, 2.0))); + assert_eq!(m.get_or_less(40, f, &()), Some((40, 4.0))); + assert_eq!(m.get_or_less(200, f, &()), Some((200, 20.0))); + assert_eq!(m.get_or_less(201, f, &()), Some((200, 20.0))); + + { + let mut c = m.cursor(f, &()); + assert_eq!(c.prev(), Some((200, 20.0))); + assert_eq!(c.prev(), Some((90, 9.0))); + assert_eq!(c.prev(), Some((80, 8.0))); + assert_eq!(c.prev(), Some((60, 6.0))); + assert_eq!(c.prev(), Some((50, 5.5))); + assert_eq!(c.prev(), Some((40, 4.0))); + assert_eq!(c.prev(), Some((20, 2.0))); + assert_eq!(c.prev(), None); + } + + // Test some removals where the node stays healthy. + assert_eq!(m.tpath(50, f, &()), "node0[2]"); + assert_eq!(m.tpath(80, f, &()), "node0[4]"); + assert_eq!(m.tpath(200, f, &()), "node0[6]"); + + assert_eq!(m.remove(80, f, &()), Some(8.0)); + assert_eq!(m.tpath(50, f, &()), "node0[2]"); + assert_eq!(m.tpath(80, f, &()), "node0[4]"); + assert_eq!(m.tpath(200, f, &()), "node0[5]"); + assert_eq!(m.remove(80, f, &()), None); + m.verify(f, &()); + + assert_eq!(m.remove(20, f, &()), Some(2.0)); + assert_eq!(m.tpath(50, f, &()), "node0[1]"); + assert_eq!(m.tpath(80, f, &()), "node0[3]"); + assert_eq!(m.tpath(200, f, &()), "node0[4]"); + assert_eq!(m.remove(20, f, &()), None); + m.verify(f, &()); + + // [ 40 50 60 90 200 ] + + { + let mut c = m.cursor(f, &()); + assert_eq!(c.goto_first(), Some(4.0)); + assert_eq!(c.key(), Some(40)); + assert_eq!(c.value(), Some(4.0)); + assert_eq!(c.next(), Some((50, 5.5))); + assert_eq!(c.next(), Some((60, 6.0))); + assert_eq!(c.next(), Some((90, 9.0))); + assert_eq!(c.next(), Some((200, 20.0))); + c.verify(); + assert_eq!(c.next(), None); + c.verify(); + } + + // Removals from the root leaf node beyond underflow. + assert_eq!(m.remove(200, f, &()), Some(20.0)); + assert_eq!(m.remove(40, f, &()), Some(4.0)); + assert_eq!(m.remove(60, f, &()), Some(6.0)); + m.verify(f, &()); + assert_eq!(m.remove(50, f, &()), Some(5.5)); + m.verify(f, &()); + assert_eq!(m.remove(90, f, &()), Some(9.0)); + m.verify(f, &()); + assert!(m.is_empty()); + } + + #[test] + fn split_level0_leaf() { + // Various ways of splitting a full leaf node at level 0. + let f = &mut MapForest::::new(); + + fn full_leaf(f: &mut MapForest) -> Map { + let mut m = Map::new(); + for n in 1..8 { + m.insert(n * 10, n as f32 * 1.1, f, &()); + } + m + } + + // Insert at front of leaf. + let mut m = full_leaf(f); + m.insert(5, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(5, f, &()), Some(4.2)); + + // Retain even entries, with altered values. + m.retain(f, |k, v| { + *v = (k / 10) as f32; + (k % 20) == 0 + }); + assert_eq!( + m.iter(f).collect::>(), + [(20, 2.0), (40, 4.0), (60, 6.0)] + ); + + // Insert at back of leaf. + let mut m = full_leaf(f); + m.insert(80, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(80, f, &()), Some(4.2)); + + // Insert before middle (40). + let mut m = full_leaf(f); + m.insert(35, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(35, f, &()), Some(4.2)); + + // Insert after middle (40). + let mut m = full_leaf(f); + m.insert(45, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(45, f, &()), Some(4.2)); + + m.clear(f); + assert!(m.is_empty()); + } + + #[test] + fn split_level1_leaf() { + // Various ways of splitting a full leaf node at level 1. + let f = &mut MapForest::::new(); + + // Return a map whose root node is a full inner node, and the leaf nodes are all full + // containing: + // + // 110, 120, ..., 170 + // 210, 220, ..., 270 + // ... + // 810, 820, ..., 870 + fn full(f: &mut MapForest) -> Map { + let mut m = Map::new(); + + // Start by inserting elements in order. + // This should leave 8 leaf nodes with 4 elements in each. + for row in 1..9 { + for col in 1..5 { + m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &()); + } + } + + // Then top up the leaf nodes without splitting them. + for row in 1..9 { + for col in 5..8 { + m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &()); + } + } + + m + } + + let mut m = full(f); + // Verify geometry. Get get node2 as the root and leaves node0, 1, 3, ... + m.verify(f, &()); + assert_eq!(m.tpath(110, f, &()), "node2[0]--node0[0]"); + assert_eq!(m.tpath(140, f, &()), "node2[0]--node0[3]"); + assert_eq!(m.tpath(210, f, &()), "node2[1]--node1[0]"); + assert_eq!(m.tpath(270, f, &()), "node2[1]--node1[6]"); + assert_eq!(m.tpath(310, f, &()), "node2[2]--node3[0]"); + assert_eq!(m.tpath(810, f, &()), "node2[7]--node8[0]"); + assert_eq!(m.tpath(870, f, &()), "node2[7]--node8[6]"); + + { + let mut c = m.cursor(f, &()); + assert_eq!(c.goto_first(), Some(1.1)); + assert_eq!(c.key(), Some(110)); + } + + // Front of first leaf. + m.insert(0, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(0, f, &()), Some(4.2)); + + // First leaf split 4-4 after appending to LHS. + f.clear(); + m = full(f); + m.insert(135, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(135, f, &()), Some(4.2)); + + // First leaf split 4-4 after prepending to RHS. + f.clear(); + m = full(f); + m.insert(145, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(145, f, &()), Some(4.2)); + + // First leaf split 4-4 after appending to RHS. + f.clear(); + m = full(f); + m.insert(175, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(175, f, &()), Some(4.2)); + + // Left-middle leaf split, ins LHS. + f.clear(); + m = full(f); + m.insert(435, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(435, f, &()), Some(4.2)); + + // Left-middle leaf split, ins RHS. + f.clear(); + m = full(f); + m.insert(445, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(445, f, &()), Some(4.2)); + + // Right-middle leaf split, ins LHS. + f.clear(); + m = full(f); + m.insert(535, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(535, f, &()), Some(4.2)); + + // Right-middle leaf split, ins RHS. + f.clear(); + m = full(f); + m.insert(545, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(545, f, &()), Some(4.2)); + + // Last leaf split, ins LHS. + f.clear(); + m = full(f); + m.insert(835, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(835, f, &()), Some(4.2)); + + // Last leaf split, ins RHS. + f.clear(); + m = full(f); + m.insert(845, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(845, f, &()), Some(4.2)); + + // Front of last leaf. + f.clear(); + m = full(f); + m.insert(805, 4.2, f, &()); + m.verify(f, &()); + assert_eq!(m.get(805, f, &()), Some(4.2)); + + m.clear(f); + m.verify(f, &()); + } + + // Make a tree with two barely healthy leaf nodes: + // [ 10 20 30 40 ] [ 50 60 70 80 ] + fn two_leaf(f: &mut MapForest) -> Map { + f.clear(); + let mut m = Map::new(); + for n in 1..9 { + m.insert(n * 10, n as f32, f, &()); + } + m + } + + #[test] + fn remove_level1() { + let f = &mut MapForest::::new(); + let mut m = two_leaf(f); + + // Verify geometry. + m.verify(f, &()); + assert_eq!(m.tpath(10, f, &()), "node2[0]--node0[0]"); + assert_eq!(m.tpath(40, f, &()), "node2[0]--node0[3]"); + assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(50, f, &()), "node2[1]--node1[0]"); + assert_eq!(m.tpath(80, f, &()), "node2[1]--node1[3]"); + + // Remove the front entry from a node that stays healthy. + assert_eq!(m.insert(55, 5.5, f, &()), None); + assert_eq!(m.remove(50, f, &()), Some(5.0)); + m.verify(f, &()); + assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(55, f, &()), "node2[1]--node1[0]"); + + // Remove the front entry from the first leaf node: No critical key to update. + assert_eq!(m.insert(15, 1.5, f, &()), None); + assert_eq!(m.remove(10, f, &()), Some(1.0)); + m.verify(f, &()); + + // [ 15 20 30 40 ] [ 55 60 70 80 ] + + // Remove the front entry from a right-most node that underflows. + // No rebalancing for the right-most node. Still need critical key update. + assert_eq!(m.remove(55, f, &()), Some(5.5)); + m.verify(f, &()); + assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]"); + + // [ 15 20 30 40 ] [ 60 70 80 ] + + // Replenish the right leaf. + assert_eq!(m.insert(90, 9.0, f, &()), None); + assert_eq!(m.insert(100, 10.0, f, &()), None); + m.verify(f, &()); + assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]"); + + // [ 15 20 30 40 ] [ 60 70 80 90 100 ] + + // Removing one entry from the left leaf should trigger a rebalancing from the right + // sibling. + assert_eq!(m.remove(20, f, &()), Some(2.0)); + m.verify(f, &()); + + // [ 15 30 40 60 ] [ 70 80 90 100 ] + // Check that the critical key was updated correctly. + assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[3]"); + assert_eq!(m.tpath(60, f, &()), "node2[0]--node0[3]"); + assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]"); + + // Remove front entry from the left-most leaf node, underflowing. + // This should cause two leaf nodes to be merged and the root node to go away. + assert_eq!(m.remove(15, f, &()), Some(1.5)); + m.verify(f, &()); + } + + #[test] + fn remove_level1_rightmost() { + let f = &mut MapForest::::new(); + let mut m = two_leaf(f); + + // [ 10 20 30 40 ] [ 50 60 70 80 ] + + // Remove entries from the right leaf. This doesn't trigger a rebalancing. + assert_eq!(m.remove(60, f, &()), Some(6.0)); + assert_eq!(m.remove(80, f, &()), Some(8.0)); + assert_eq!(m.remove(50, f, &()), Some(5.0)); + m.verify(f, &()); + + // [ 10 20 30 40 ] [ 70 ] + assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]"); + assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]"); + + // Removing the last entry from the right leaf should cause a collapse. + assert_eq!(m.remove(70, f, &()), Some(7.0)); + m.verify(f, &()); + } + + // Make a 3-level tree with barely healthy nodes. + // 1 root, 8 inner nodes, 7*4+5=33 leaf nodes, 4 entries each. + fn level3_sparse(f: &mut MapForest) -> Map { + f.clear(); + let mut m = Map::new(); + for n in 1..133 { + m.insert(n * 10, n as f32, f, &()); + } + m + } + + #[test] + fn level3_removes() { + let f = &mut MapForest::::new(); + let mut m = level3_sparse(f); + m.verify(f, &()); + + // Check geometry. + // Root: node11 + // [ node2 170 node10 330 node16 490 node21 650 node26 810 node31 970 node36 1130 node41 ] + // L1: node11 + assert_eq!(m.tpath(0, f, &()), "node11[0]--node2[0]--node0[0]"); + assert_eq!(m.tpath(10000, f, &()), "node11[7]--node41[4]--node40[4]"); + + // 650 is a critical key in the middle of the root. + assert_eq!(m.tpath(640, f, &()), "node11[3]--node21[3]--node19[3]"); + assert_eq!(m.tpath(650, f, &()), "node11[4]--node26[0]--node20[0]"); + + // Deleting 640 triggers a rebalance from node19 to node 20, cascading to n21 -> n26. + assert_eq!(m.remove(640, f, &()), Some(64.0)); + m.verify(f, &()); + assert_eq!(m.tpath(650, f, &()), "node11[3]--node26[3]--node20[3]"); + + // 1130 is in the first leaf of the last L1 node. Deleting it triggers a rebalance node35 + // -> node37, but no rebalance above where there is no right sibling. + assert_eq!(m.tpath(1130, f, &()), "node11[6]--node41[0]--node35[0]"); + assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node35[1]"); + assert_eq!(m.remove(1130, f, &()), Some(113.0)); + m.verify(f, &()); + assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node37[0]"); + } + + #[test] + fn insert_many() { + let f = &mut MapForest::::new(); + let mut m = Map::::new(); + + let mm = 4096; + let mut x = 0; + + for n in 0..mm { + assert_eq!(m.insert(x, n as f32, f, &()), None); + m.verify(f, &()); + + x = (x + n + 1) % mm; + } + + x = 0; + for n in 0..mm { + assert_eq!(m.get(x, f, &()), Some(n as f32)); + x = (x + n + 1) % mm; + } + + x = 0; + for n in 0..mm { + assert_eq!(m.remove(x, f, &()), Some(n as f32)); + m.verify(f, &()); + + x = (x + n + 1) % mm; + } + + assert!(m.is_empty()); + } +} diff --git a/deps/crates/vendor/cranelift-bforest/src/node.rs b/deps/crates/vendor/cranelift-bforest/src/node.rs new file mode 100644 index 00000000000000..848c657e82c812 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/node.rs @@ -0,0 +1,805 @@ +//! B+-tree nodes. + +use super::{slice_insert, slice_shift, Forest, Node, SetValue, INNER_SIZE}; +use core::borrow::{Borrow, BorrowMut}; +use core::fmt; + +/// B+-tree node. +/// +/// A B+-tree has different node types for inner nodes and leaf nodes. Inner nodes contain M node +/// references and M-1 keys while leaf nodes contain N keys and values. Values for M and N are +/// chosen such that a node is exactly 64 bytes (a cache line) when keys and values are 32 bits +/// each. +/// +/// An inner node contains at least M/2 node references unless it is the right-most node at its +/// level. A leaf node contains at least N/2 keys unless it is the right-most leaf. +pub(super) enum NodeData { + Inner { + /// The number of keys in this node. + /// The number of node references is always one more. + size: u8, + + /// Keys discriminating sub-trees. + /// + /// The key in `keys[i]` is greater than all keys in `tree[i]` and less than or equal to + /// all keys in `tree[i+1]`. + keys: [F::Key; INNER_SIZE - 1], + + /// Sub-trees. + tree: [Node; INNER_SIZE], + }, + Leaf { + /// Number of key-value pairs in this node. + size: u8, + + // Key array. + keys: F::LeafKeys, + + // Value array. + vals: F::LeafValues, + }, + /// An unused node on the free list. + Free { next: Option }, +} + +// Implement `Clone` and `Copy` manually, because deriving them would also require `Forest` to +// implement `Clone`. +impl Copy for NodeData {} +impl Clone for NodeData { + fn clone(&self) -> Self { + *self + } +} + +impl NodeData { + /// Is this a free/unused node? + pub fn is_free(&self) -> bool { + match *self { + Self::Free { .. } => true, + _ => false, + } + } + + /// Get the number of entries in this node. + /// + /// This is the number of outgoing edges in an inner node, or the number of key-value pairs in + /// a leaf node. + pub fn entries(&self) -> usize { + match *self { + Self::Inner { size, .. } => usize::from(size) + 1, + Self::Leaf { size, .. } => usize::from(size), + Self::Free { .. } => panic!("freed node"), + } + } + + /// Create an inner node with a single key and two sub-trees. + pub fn inner(left: Node, key: F::Key, right: Node) -> Self { + // Splat the key and right node to the whole array. + // Saves us from inventing a default/reserved value. + let mut tree = [right; INNER_SIZE]; + tree[0] = left; + Self::Inner { + size: 1, + keys: [key; INNER_SIZE - 1], + tree, + } + } + + /// Create a leaf node with a single key-value pair. + pub fn leaf(key: F::Key, value: F::Value) -> Self { + Self::Leaf { + size: 1, + keys: F::splat_key(key), + vals: F::splat_value(value), + } + } + + /// Unwrap an inner node into two slices (keys, trees). + pub fn unwrap_inner(&self) -> (&[F::Key], &[Node]) { + match *self { + Self::Inner { + size, + ref keys, + ref tree, + } => { + let size = usize::from(size); + // TODO: We could probably use `get_unchecked()` here since `size` is always in + // range. + (&keys[0..size], &tree[0..=size]) + } + _ => panic!("Expected inner node"), + } + } + + /// Unwrap a leaf node into two slices (keys, values) of the same length. + pub fn unwrap_leaf(&self) -> (&[F::Key], &[F::Value]) { + match *self { + Self::Leaf { + size, + ref keys, + ref vals, + } => { + let size = usize::from(size); + let keys = keys.borrow(); + let vals = vals.borrow(); + // TODO: We could probably use `get_unchecked()` here since `size` is always in + // range. + (&keys[0..size], &vals[0..size]) + } + _ => panic!("Expected leaf node"), + } + } + + /// Unwrap a mutable leaf node into two slices (keys, values) of the same length. + pub fn unwrap_leaf_mut(&mut self) -> (&mut [F::Key], &mut [F::Value]) { + match *self { + Self::Leaf { + size, + ref mut keys, + ref mut vals, + } => { + let size = usize::from(size); + let keys = keys.borrow_mut(); + let vals = vals.borrow_mut(); + // TODO: We could probably use `get_unchecked_mut()` here since `size` is always in + // range. + (&mut keys[0..size], &mut vals[0..size]) + } + _ => panic!("Expected leaf node"), + } + } + + /// Get the critical key for a leaf node. + /// This is simply the first key. + pub fn leaf_crit_key(&self) -> F::Key { + match *self { + Self::Leaf { size, ref keys, .. } => { + debug_assert!(size > 0, "Empty leaf node"); + keys.borrow()[0] + } + _ => panic!("Expected leaf node"), + } + } + + /// Try to insert `(key, node)` at key-position `index` in an inner node. + /// This means that `key` is inserted at `keys[i]` and `node` is inserted at `tree[i + 1]`. + /// If the node is full, this leaves the node unchanged and returns false. + pub fn try_inner_insert(&mut self, index: usize, key: F::Key, node: Node) -> bool { + match *self { + Self::Inner { + ref mut size, + ref mut keys, + ref mut tree, + } => { + let sz = usize::from(*size); + debug_assert!(sz <= keys.len()); + debug_assert!(index <= sz, "Can't insert at {index} with {sz} keys"); + + if let Some(ks) = keys.get_mut(0..=sz) { + *size = (sz + 1) as u8; + slice_insert(ks, index, key); + slice_insert(&mut tree[1..=sz + 1], index, node); + true + } else { + false + } + } + _ => panic!("Expected inner node"), + } + } + + /// Try to insert `key, value` at `index` in a leaf node, but fail and return false if the node + /// is full. + pub fn try_leaf_insert(&mut self, index: usize, key: F::Key, value: F::Value) -> bool { + match *self { + Self::Leaf { + ref mut size, + ref mut keys, + ref mut vals, + } => { + let sz = usize::from(*size); + let keys = keys.borrow_mut(); + let vals = vals.borrow_mut(); + debug_assert!(sz <= keys.len()); + debug_assert!(index <= sz); + + if let Some(ks) = keys.get_mut(0..=sz) { + *size = (sz + 1) as u8; + slice_insert(ks, index, key); + slice_insert(&mut vals[0..=sz], index, value); + true + } else { + false + } + } + _ => panic!("Expected leaf node"), + } + } + + /// Split off the second half of this node. + /// It is assumed that this a completely full inner or leaf node. + /// + /// The `insert_index` parameter is the position where an insertion was tried and failed. The + /// node will be split in half with a bias towards an even split after the insertion is retried. + pub fn split(&mut self, insert_index: usize) -> SplitOff { + match *self { + Self::Inner { + ref mut size, + ref keys, + ref tree, + } => { + debug_assert_eq!(usize::from(*size), keys.len(), "Node not full"); + + // Number of tree entries in the lhs node. + let l_ents = split_pos(tree.len(), insert_index + 1); + let r_ents = tree.len() - l_ents; + + // With INNER_SIZE=8, we get l_ents=4 and: + // + // self: [ n0 k0 n1 k1 n2 k2 n3 k3 n4 k4 n5 k5 n6 k6 n7 ] + // lhs: [ n0 k0 n1 k1 n2 k2 n3 ] + // crit_key = k3 (not present in either node) + // rhs: [ n4 k4 n5 k5 n6 k6 n7 ] + + // 1. Truncate the LHS. + *size = (l_ents - 1) as u8; + + // 2. Copy second half to `rhs_data`. + let mut r_keys = *keys; + r_keys[0..r_ents - 1].copy_from_slice(&keys[l_ents..]); + + let mut r_tree = *tree; + r_tree[0..r_ents].copy_from_slice(&tree[l_ents..]); + + SplitOff { + lhs_entries: l_ents, + rhs_entries: r_ents, + crit_key: keys[l_ents - 1], + rhs_data: Self::Inner { + size: (r_ents - 1) as u8, + keys: r_keys, + tree: r_tree, + }, + } + } + Self::Leaf { + ref mut size, + ref keys, + ref vals, + } => { + let o_keys = keys.borrow(); + let o_vals = vals.borrow(); + debug_assert_eq!(usize::from(*size), o_keys.len(), "Node not full"); + + let l_size = split_pos(o_keys.len(), insert_index); + let r_size = o_keys.len() - l_size; + + // 1. Truncate the LHS node at `l_size`. + *size = l_size as u8; + + // 2. Copy second half to `rhs_data`. + let mut r_keys = *keys; + r_keys.borrow_mut()[0..r_size].copy_from_slice(&o_keys[l_size..]); + + let mut r_vals = *vals; + r_vals.borrow_mut()[0..r_size].copy_from_slice(&o_vals[l_size..]); + + SplitOff { + lhs_entries: l_size, + rhs_entries: r_size, + crit_key: o_keys[l_size], + rhs_data: Self::Leaf { + size: r_size as u8, + keys: r_keys, + vals: r_vals, + }, + } + } + _ => panic!("Expected leaf node"), + } + } + + /// Remove the sub-tree at `index` from this inner node. + /// + /// Note that `index` refers to a sub-tree entry and not a key entry as it does for + /// `try_inner_insert()`. It is possible to remove the first sub-tree (which can't be inserted + /// by `try_inner_insert()`). + /// + /// Return an indication of the node's health (i.e. below half capacity). + pub fn inner_remove(&mut self, index: usize) -> Removed { + match *self { + Self::Inner { + ref mut size, + ref mut keys, + ref mut tree, + } => { + let ents = usize::from(*size) + 1; + debug_assert!(ents <= tree.len()); + debug_assert!(index < ents); + // Leave an invalid 0xff size when node becomes empty. + *size = ents.wrapping_sub(2) as u8; + if ents > 1 { + slice_shift(&mut keys[index.saturating_sub(1)..ents - 1], 1); + } + slice_shift(&mut tree[index..ents], 1); + Removed::new(index, ents - 1, tree.len()) + } + _ => panic!("Expected inner node"), + } + } + + /// Remove the key-value pair at `index` from this leaf node. + /// + /// Return an indication of the node's health (i.e. below half capacity). + pub fn leaf_remove(&mut self, index: usize) -> Removed { + match *self { + Self::Leaf { + ref mut size, + ref mut keys, + ref mut vals, + } => { + let sz = usize::from(*size); + let keys = keys.borrow_mut(); + let vals = vals.borrow_mut(); + *size -= 1; + slice_shift(&mut keys[index..sz], 1); + slice_shift(&mut vals[index..sz], 1); + Removed::new(index, sz - 1, keys.len()) + } + _ => panic!("Expected leaf node"), + } + } + + /// Balance this node with its right sibling. + /// + /// It is assumed that the current node has underflowed. Look at the right sibling node and do + /// one of two things: + /// + /// 1. Move all entries to the right node, leaving this node empty, or + /// 2. Distribute entries evenly between the two nodes. + /// + /// In the first case, `None` is returned. In the second case, the new critical key for the + /// right sibling node is returned. + pub fn balance(&mut self, crit_key: F::Key, rhs: &mut Self) -> Option { + match (self, rhs) { + ( + &mut Self::Inner { + size: ref mut l_size, + keys: ref mut l_keys, + tree: ref mut l_tree, + }, + &mut Self::Inner { + size: ref mut r_size, + keys: ref mut r_keys, + tree: ref mut r_tree, + }, + ) => { + let l_ents = usize::from(*l_size) + 1; + let r_ents = usize::from(*r_size) + 1; + let ents = l_ents + r_ents; + + if ents <= r_tree.len() { + // All entries will fit in the RHS node. + // We'll leave the LHS node empty, but first use it as a scratch space. + *l_size = 0; + // Insert `crit_key` between the two nodes. + l_keys[l_ents - 1] = crit_key; + l_keys[l_ents..ents - 1].copy_from_slice(&r_keys[0..r_ents - 1]); + r_keys[0..ents - 1].copy_from_slice(&l_keys[0..ents - 1]); + l_tree[l_ents..ents].copy_from_slice(&r_tree[0..r_ents]); + r_tree[0..ents].copy_from_slice(&l_tree[0..ents]); + *r_size = (ents - 1) as u8; + None + } else { + // The entries don't all fit in one node. Distribute some from RHS -> LHS. + // Split evenly with a bias to putting one entry in LHS. + let r_goal = ents / 2; + let l_goal = ents - r_goal; + debug_assert!(l_goal > l_ents, "Node must be underflowed"); + + l_keys[l_ents - 1] = crit_key; + l_keys[l_ents..l_goal - 1].copy_from_slice(&r_keys[0..l_goal - 1 - l_ents]); + l_tree[l_ents..l_goal].copy_from_slice(&r_tree[0..l_goal - l_ents]); + *l_size = (l_goal - 1) as u8; + + let new_crit = r_keys[r_ents - r_goal - 1]; + slice_shift(&mut r_keys[0..r_ents - 1], r_ents - r_goal); + slice_shift(&mut r_tree[0..r_ents], r_ents - r_goal); + *r_size = (r_goal - 1) as u8; + + Some(new_crit) + } + } + ( + &mut Self::Leaf { + size: ref mut l_size, + keys: ref mut l_keys, + vals: ref mut l_vals, + }, + &mut Self::Leaf { + size: ref mut r_size, + keys: ref mut r_keys, + vals: ref mut r_vals, + }, + ) => { + let l_ents = usize::from(*l_size); + let l_keys = l_keys.borrow_mut(); + let l_vals = l_vals.borrow_mut(); + let r_ents = usize::from(*r_size); + let r_keys = r_keys.borrow_mut(); + let r_vals = r_vals.borrow_mut(); + let ents = l_ents + r_ents; + + if ents <= r_vals.len() { + // We can fit all entries in the RHS node. + // We'll leave the LHS node empty, but first use it as a scratch space. + *l_size = 0; + l_keys[l_ents..ents].copy_from_slice(&r_keys[0..r_ents]); + r_keys[0..ents].copy_from_slice(&l_keys[0..ents]); + l_vals[l_ents..ents].copy_from_slice(&r_vals[0..r_ents]); + r_vals[0..ents].copy_from_slice(&l_vals[0..ents]); + *r_size = ents as u8; + None + } else { + // The entries don't all fit in one node. Distribute some from RHS -> LHS. + // Split evenly with a bias to putting one entry in LHS. + let r_goal = ents / 2; + let l_goal = ents - r_goal; + debug_assert!(l_goal > l_ents, "Node must be underflowed"); + + l_keys[l_ents..l_goal].copy_from_slice(&r_keys[0..l_goal - l_ents]); + l_vals[l_ents..l_goal].copy_from_slice(&r_vals[0..l_goal - l_ents]); + *l_size = l_goal as u8; + + slice_shift(&mut r_keys[0..r_ents], r_ents - r_goal); + slice_shift(&mut r_vals[0..r_ents], r_ents - r_goal); + *r_size = r_goal as u8; + + Some(r_keys[0]) + } + } + _ => panic!("Mismatched nodes"), + } + } +} + +/// Find the right split position for halving a full node with `len` entries to recover from a +/// failed insertion at `ins`. +/// +/// If `len` is even, we should split straight down the middle regardless of `len`. +/// +/// If `len` is odd, we should split the node such that the two halves are the same size after the +/// insertion is retried. +fn split_pos(len: usize, ins: usize) -> usize { + // Anticipate `len` being a compile time constant, so this all folds away when `len` is even. + if ins <= len / 2 { + len / 2 + } else { + (len + 1) / 2 + } +} + +/// The result of splitting off the second half of a node. +pub(super) struct SplitOff { + /// The number of entries left in the original node which becomes the left-hand-side of the + /// pair. This is the number of outgoing node edges for an inner node, and the number of + /// key-value pairs for a leaf node. + pub lhs_entries: usize, + + /// The number of entries in the new RHS node. + pub rhs_entries: usize, + + /// The critical key separating the LHS and RHS nodes. All keys in the LHS sub-tree are less + /// than the critical key, and all entries in the RHS sub-tree are greater or equal to the + /// critical key. + pub crit_key: F::Key, + + /// The RHS node data containing the elements that were removed from the original node (now the + /// LHS). + pub rhs_data: NodeData, +} + +/// The result of removing an entry from a node. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(super) enum Removed { + /// An entry was removed, and the node is still in good shape. + Healthy, + + /// The node is in good shape after removing the rightmost element. + Rightmost, + + /// The node has too few entries now, and it should be balanced with a sibling node. + Underflow, + + /// The last entry was removed. For an inner node, this means that the `keys` array is empty + /// and there is just a single sub-tree left. + Empty, +} + +impl Removed { + /// Create a `Removed` status from a size and capacity. + fn new(removed: usize, new_size: usize, capacity: usize) -> Self { + if 2 * new_size >= capacity { + if removed == new_size { + Self::Rightmost + } else { + Self::Healthy + } + } else if new_size > 0 { + Self::Underflow + } else { + Self::Empty + } + } +} + +// Display ": value" or nothing at all for `()`. +pub(super) trait ValDisp { + fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result; +} + +impl ValDisp for SetValue { + fn valfmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +impl ValDisp for T { + fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, ":{self}") + } +} + +impl fmt::Display for NodeData +where + F: Forest, + F::Key: fmt::Display, + F::Value: ValDisp, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Inner { size, keys, tree } => { + write!(f, "[ {}", tree[0])?; + for i in 0..usize::from(size) { + write!(f, " {} {}", keys[i], tree[i + 1])?; + } + write!(f, " ]") + } + Self::Leaf { size, keys, vals } => { + let keys = keys.borrow(); + let vals = vals.borrow(); + write!(f, "[")?; + for i in 0..usize::from(size) { + write!(f, " {}", keys[i])?; + vals[i].valfmt(f)?; + } + write!(f, " ]") + } + Self::Free { next: Some(n) } => write!(f, "[ free -> {n} ]"), + Self::Free { next: None } => write!(f, "[ free ]"), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + use core::mem; + + // Forest impl for a set implementation. + struct TF(); + + impl Forest for TF { + type Key = char; + type Value = SetValue; + type LeafKeys = [char; 15]; + type LeafValues = [SetValue; 15]; + + fn splat_key(key: Self::Key) -> Self::LeafKeys { + [key; 15] + } + + fn splat_value(value: Self::Value) -> Self::LeafValues { + [value; 15] + } + } + + #[test] + fn inner() { + let n1 = Node(1); + let n2 = Node(2); + let n3 = Node(3); + let n4 = Node(4); + let mut inner = NodeData::::inner(n1, 'c', n4); + assert_eq!(mem::size_of_val(&inner), 64); + assert_eq!(inner.to_string(), "[ node1 c node4 ]"); + + assert!(inner.try_inner_insert(0, 'a', n2)); + assert_eq!(inner.to_string(), "[ node1 a node2 c node4 ]"); + + assert!(inner.try_inner_insert(1, 'b', n3)); + assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]"); + + for i in 3..7 { + assert!(inner.try_inner_insert( + usize::from(i), + ('a' as u8 + i) as char, + Node(i as u32 + 2), + )); + } + assert_eq!( + inner.to_string(), + "[ node1 a node2 b node3 c node4 d node5 e node6 f node7 g node8 ]" + ); + + // Now the node is full and insertion should fail anywhere. + assert!(!inner.try_inner_insert(0, 'x', n3)); + assert!(!inner.try_inner_insert(4, 'x', n3)); + assert!(!inner.try_inner_insert(7, 'x', n3)); + + // Splitting should be independent of the hint because we have an even number of node + // references. + let saved = inner; + let sp = inner.split(1); + assert_eq!(sp.lhs_entries, 4); + assert_eq!(sp.rhs_entries, 4); + assert_eq!(sp.crit_key, 'd'); + // The critical key is not present in either of the resulting nodes. + assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]"); + assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]"); + + assert_eq!(inner.inner_remove(0), Removed::Underflow); + assert_eq!(inner.to_string(), "[ node2 b node3 c node4 ]"); + + assert_eq!(inner.inner_remove(1), Removed::Underflow); + assert_eq!(inner.to_string(), "[ node2 c node4 ]"); + + assert_eq!(inner.inner_remove(1), Removed::Underflow); + assert_eq!(inner.to_string(), "[ node2 ]"); + + assert_eq!(inner.inner_remove(0), Removed::Empty); + + inner = saved; + let sp = inner.split(6); + assert_eq!(sp.lhs_entries, 4); + assert_eq!(sp.rhs_entries, 4); + assert_eq!(sp.crit_key, 'd'); + assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]"); + assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]"); + } + + #[test] + fn leaf() { + let mut leaf = NodeData::::leaf('d', SetValue()); + assert_eq!(leaf.to_string(), "[ d ]"); + + assert!(leaf.try_leaf_insert(0, 'a', SetValue())); + assert_eq!(leaf.to_string(), "[ a d ]"); + assert!(leaf.try_leaf_insert(1, 'b', SetValue())); + assert!(leaf.try_leaf_insert(2, 'c', SetValue())); + assert_eq!(leaf.to_string(), "[ a b c d ]"); + for i in 4..15 { + assert!(leaf.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue())); + } + assert_eq!(leaf.to_string(), "[ a b c d e f g h i j k l m n o ]"); + + // Now the node is full and insertion should fail anywhere. + assert!(!leaf.try_leaf_insert(0, 'x', SetValue())); + assert!(!leaf.try_leaf_insert(8, 'x', SetValue())); + assert!(!leaf.try_leaf_insert(15, 'x', SetValue())); + + // The index given to `split` is not the split position, it's a hint for balancing the node. + let saved = leaf; + let sp = leaf.split(12); + assert_eq!(sp.lhs_entries, 8); + assert_eq!(sp.rhs_entries, 7); + assert_eq!(sp.crit_key, 'i'); + assert_eq!(leaf.to_string(), "[ a b c d e f g h ]"); + assert_eq!(sp.rhs_data.to_string(), "[ i j k l m n o ]"); + + assert!(leaf.try_leaf_insert(8, 'i', SetValue())); + assert_eq!(leaf.leaf_remove(2), Removed::Healthy); + assert_eq!(leaf.to_string(), "[ a b d e f g h i ]"); + assert_eq!(leaf.leaf_remove(7), Removed::Underflow); + assert_eq!(leaf.to_string(), "[ a b d e f g h ]"); + + leaf = saved; + let sp = leaf.split(7); + assert_eq!(sp.lhs_entries, 7); + assert_eq!(sp.rhs_entries, 8); + assert_eq!(sp.crit_key, 'h'); + assert_eq!(leaf.to_string(), "[ a b c d e f g ]"); + assert_eq!(sp.rhs_data.to_string(), "[ h i j k l m n o ]"); + } + + #[test] + fn optimal_split_pos() { + // An even split is easy. + assert_eq!(split_pos(8, 0), 4); + assert_eq!(split_pos(8, 8), 4); + + // Easy cases for odd splits. + assert_eq!(split_pos(7, 0), 3); + assert_eq!(split_pos(7, 7), 4); + + // If the insertion point is the same as the split position, we + // will append to the lhs node. + assert_eq!(split_pos(7, 3), 3); + assert_eq!(split_pos(7, 4), 4); + } + + #[test] + fn inner_balance() { + let n1 = Node(1); + let n2 = Node(2); + let n3 = Node(3); + let mut lhs = NodeData::::inner(n1, 'a', n2); + assert!(lhs.try_inner_insert(1, 'b', n3)); + assert_eq!(lhs.to_string(), "[ node1 a node2 b node3 ]"); + + let n11 = Node(11); + let n12 = Node(12); + let mut rhs = NodeData::::inner(n11, 'p', n12); + + for i in 1..4 { + assert!(rhs.try_inner_insert( + usize::from(i), + ('p' as u8 + i) as char, + Node(i as u32 + 12), + )); + } + assert_eq!( + rhs.to_string(), + "[ node11 p node12 q node13 r node14 s node15 ]" + ); + + // 3+5 elements fit in RHS. + assert_eq!(lhs.balance('o', &mut rhs), None); + assert_eq!( + rhs.to_string(), + "[ node1 a node2 b node3 o node11 p node12 q node13 r node14 s node15 ]" + ); + + // 2+8 elements are redistributed. + lhs = NodeData::::inner(Node(20), 'x', Node(21)); + assert_eq!(lhs.balance('y', &mut rhs), Some('o')); + assert_eq!( + lhs.to_string(), + "[ node20 x node21 y node1 a node2 b node3 ]" + ); + assert_eq!( + rhs.to_string(), + "[ node11 p node12 q node13 r node14 s node15 ]" + ); + } + + #[test] + fn leaf_balance() { + let mut lhs = NodeData::::leaf('a', SetValue()); + for i in 1..6 { + assert!(lhs.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue())); + } + assert_eq!(lhs.to_string(), "[ a b c d e f ]"); + + let mut rhs = NodeData::::leaf('0', SetValue()); + for i in 1..8 { + assert!(rhs.try_leaf_insert(usize::from(i), ('0' as u8 + i) as char, SetValue())); + } + assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]"); + + // 6+8 elements all fits in rhs. + assert_eq!(lhs.balance('0', &mut rhs), None); + assert_eq!(rhs.to_string(), "[ a b c d e f 0 1 2 3 4 5 6 7 ]"); + + assert!(lhs.try_leaf_insert(0, 'x', SetValue())); + assert!(lhs.try_leaf_insert(1, 'y', SetValue())); + assert!(lhs.try_leaf_insert(2, 'z', SetValue())); + assert_eq!(lhs.to_string(), "[ x y z ]"); + + // 3+14 elements need redistribution. + assert_eq!(lhs.balance('a', &mut rhs), Some('0')); + assert_eq!(lhs.to_string(), "[ x y z a b c d e f ]"); + assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]"); + } +} diff --git a/deps/crates/vendor/cranelift-bforest/src/path.rs b/deps/crates/vendor/cranelift-bforest/src/path.rs new file mode 100644 index 00000000000000..896bd0e23db215 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/path.rs @@ -0,0 +1,830 @@ +//! A path from the root of a B+-tree to a leaf node. + +use super::node::Removed; +use super::{slice_insert, slice_shift, Comparator, Forest, Node, NodeData, NodePool, MAX_PATH}; +use core::borrow::Borrow; +use core::marker::PhantomData; + +#[cfg(test)] +use core::fmt; + +pub(super) struct Path { + /// Number of path entries including the root and leaf nodes. + size: usize, + + /// Path of node references from the root to a leaf node. + node: [Node; MAX_PATH], + + /// Entry number in each node. + entry: [u8; MAX_PATH], + + unused: PhantomData, +} + +impl Default for Path { + fn default() -> Self { + Self { + size: 0, + node: [Node(0); MAX_PATH], + entry: [0; MAX_PATH], + unused: PhantomData, + } + } +} + +impl Path { + /// Reset path by searching for `key` starting from `root`. + /// + /// If `key` is in the tree, returns the corresponding value and leaved the path pointing at + /// the entry. Otherwise returns `None` and: + /// + /// - A key smaller than all stored keys returns a path to the first entry of the first leaf. + /// - A key larger than all stored keys returns a path to one beyond the last element of the + /// last leaf. + /// - A key between the stored keys of adjacent leaf nodes returns a path to one beyond the + /// last entry of the first of the leaf nodes. + /// + pub fn find( + &mut self, + key: F::Key, + root: Node, + pool: &NodePool, + comp: &dyn Comparator, + ) -> Option { + let mut node = root; + for level in 0.. { + self.size = level + 1; + self.node[level] = node; + match pool[node] { + NodeData::Inner { size, keys, tree } => { + // Invariant: `tree[i]` contains keys smaller than + // `keys[i]`, greater or equal to `keys[i-1]`. + let i = match comp.search(key, &keys[0..size.into()]) { + // We hit an existing key, so follow the >= branch. + Ok(i) => i + 1, + // Key is less than `keys[i]`, so follow the < branch. + Err(i) => i, + }; + self.entry[level] = i as u8; + node = tree[i]; + } + NodeData::Leaf { size, keys, vals } => { + // For a leaf we want either the found key or an insert position. + return match comp.search(key, &keys.borrow()[0..size.into()]) { + Ok(i) => { + self.entry[level] = i as u8; + Some(vals.borrow()[i]) + } + Err(i) => { + self.entry[level] = i as u8; + None + } + }; + } + NodeData::Free { .. } => panic!("Free {} reached from {}", node, root), + } + } + unreachable!(); + } + + /// Move path to the first entry of the tree starting at `root` and return it. + pub fn first(&mut self, root: Node, pool: &NodePool) -> (F::Key, F::Value) { + let mut node = root; + for level in 0.. { + self.size = level + 1; + self.node[level] = node; + self.entry[level] = 0; + match pool[node] { + NodeData::Inner { tree, .. } => node = tree[0], + NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]), + NodeData::Free { .. } => panic!("Free {} reached from {}", node, root), + } + } + unreachable!(); + } + + /// Move this path to the next key-value pair and return it. + pub fn next(&mut self, pool: &NodePool) -> Option<(F::Key, F::Value)> { + match self.leaf_pos() { + None => return None, + Some((node, entry)) => { + let (keys, vals) = pool[node].unwrap_leaf(); + if entry + 1 < keys.len() { + self.entry[self.size - 1] += 1; + return Some((keys[entry + 1], vals[entry + 1])); + } + } + } + + // The current leaf node is exhausted. Move to the next one. + let leaf_level = self.size - 1; + self.next_node(leaf_level, pool).map(|node| { + let (keys, vals) = pool[node].unwrap_leaf(); + (keys[0], vals[0]) + }) + } + + /// Move this path to the previous key-value pair and return it. + /// + /// If the path is at the off-the-end position, go to the last key-value pair. + /// + /// If the path is already at the first key-value pair, leave it there and return `None`. + pub fn prev(&mut self, root: Node, pool: &NodePool) -> Option<(F::Key, F::Value)> { + // We use `size == 0` as a generic off-the-end position. + if self.size == 0 { + self.goto_subtree_last(0, root, pool); + let (node, entry) = self.leaf_pos().unwrap(); + let (keys, vals) = pool[node].unwrap_leaf(); + return Some((keys[entry], vals[entry])); + } + + match self.leaf_pos() { + None => return None, + Some((node, entry)) => { + if entry > 0 { + self.entry[self.size - 1] -= 1; + let (keys, vals) = pool[node].unwrap_leaf(); + return Some((keys[entry - 1], vals[entry - 1])); + } + } + } + + // The current leaf node is exhausted. Move to the previous one. + self.prev_leaf(pool).map(|node| { + let (keys, vals) = pool[node].unwrap_leaf(); + let e = self.leaf_entry(); + (keys[e], vals[e]) + }) + } + + /// Move path to the first entry of the next node at level, if one exists. + /// + /// Returns the new node if it exists. + /// + /// Reset the path to `size = 0` and return `None` if there is no next node. + fn next_node(&mut self, level: usize, pool: &NodePool) -> Option { + match self.right_sibling_branch_level(level, pool) { + None => { + self.size = 0; + None + } + Some(bl) => { + let (_, bnodes) = pool[self.node[bl]].unwrap_inner(); + self.entry[bl] += 1; + let mut node = bnodes[usize::from(self.entry[bl])]; + + for l in bl + 1..level { + self.node[l] = node; + self.entry[l] = 0; + node = pool[node].unwrap_inner().1[0]; + } + + self.node[level] = node; + self.entry[level] = 0; + Some(node) + } + } + } + + /// Move the path to the last entry of the previous leaf node, if one exists. + /// + /// Returns the new leaf node if it exists. + /// + /// Leave the path unchanged and returns `None` if we are already at the first leaf node. + fn prev_leaf(&mut self, pool: &NodePool) -> Option { + self.left_sibling_branch_level(self.size - 1).map(|bl| { + let entry = self.entry[bl] - 1; + self.entry[bl] = entry; + let (_, bnodes) = pool[self.node[bl]].unwrap_inner(); + self.goto_subtree_last(bl + 1, bnodes[usize::from(entry)], pool) + }) + } + + /// Move this path to the last position for the sub-tree at `level, root`. + fn goto_subtree_last(&mut self, level: usize, root: Node, pool: &NodePool) -> Node { + let mut node = root; + for l in level.. { + self.node[l] = node; + match pool[node] { + NodeData::Inner { size, ref tree, .. } => { + self.entry[l] = size; + node = tree[usize::from(size)]; + } + NodeData::Leaf { size, .. } => { + self.entry[l] = size - 1; + self.size = l + 1; + break; + } + NodeData::Free { .. } => panic!("Free {} reached from {}", node, root), + } + } + node + } + + /// Set the root node and point the path at the first entry of the node. + pub fn set_root_node(&mut self, root: Node) { + self.size = 1; + self.node[0] = root; + self.entry[0] = 0; + } + + /// Get the current leaf node and entry, if any. + pub fn leaf_pos(&self) -> Option<(Node, usize)> { + let i = self.size.wrapping_sub(1); + self.node.get(i).map(|&n| (n, self.entry[i].into())) + } + + /// Get the current leaf node. + fn leaf_node(&self) -> Node { + self.node[self.size - 1] + } + + /// Get the current entry in the leaf node. + fn leaf_entry(&self) -> usize { + self.entry[self.size - 1].into() + } + + /// Is this path pointing to the first entry in the tree? + /// This corresponds to the smallest key. + fn at_first_entry(&self) -> bool { + self.entry[0..self.size].iter().all(|&i| i == 0) + } + + /// Get a mutable reference to the current value. + /// This assumes that there is a current value. + pub fn value_mut<'a>(&self, pool: &'a mut NodePool) -> &'a mut F::Value { + &mut pool[self.leaf_node()].unwrap_leaf_mut().1[self.leaf_entry()] + } + + /// Insert the key-value pair at the current position. + /// The current position must be the correct insertion location for the key. + /// This function does not check for duplicate keys. Use `find` or similar for that. + /// Returns the new root node. + pub fn insert(&mut self, key: F::Key, value: F::Value, pool: &mut NodePool) -> Node { + if !self.try_leaf_insert(key, value, pool) { + self.split_and_insert(key, value, pool); + } + self.node[0] + } + + /// Try to insert `key, value` at the current position, but fail and return false if the leaf + /// node is full. + fn try_leaf_insert(&self, key: F::Key, value: F::Value, pool: &mut NodePool) -> bool { + let index = self.leaf_entry(); + + // The case `index == 0` should only ever happen when there are no earlier leaf nodes, + // otherwise we should have appended to the previous leaf node instead. This invariant + // means that we don't need to update keys stored in inner nodes here. + debug_assert!(index > 0 || self.at_first_entry()); + + pool[self.leaf_node()].try_leaf_insert(index, key, value) + } + + /// Split the current leaf node and then insert `key, value`. + /// This should only be used if `try_leaf_insert()` fails. + fn split_and_insert(&mut self, mut key: F::Key, value: F::Value, pool: &mut NodePool) { + let orig_root = self.node[0]; + + // Loop invariant: We need to split the node at `level` and then retry a failed insertion. + // The items to insert are either `(key, ins_node)` or `(key, value)`. + let mut ins_node = None; + let mut split; + for level in (0..self.size).rev() { + // Split the current node. + let mut node = self.node[level]; + let mut entry = self.entry[level].into(); + split = pool[node].split(entry); + let rhs_node = pool.alloc_node(split.rhs_data); + + // Should the path be moved to the new RHS node? + // Prefer the smaller node if we're right in the middle. + // Prefer to append to LHS all other things being equal. + // + // When inserting into an inner node (`ins_node.is_some()`), we must point to a valid + // entry in the current node since the new entry is inserted *after* the insert + // location. + if entry > split.lhs_entries + || (entry == split.lhs_entries + && (split.lhs_entries > split.rhs_entries || ins_node.is_some())) + { + node = rhs_node; + entry -= split.lhs_entries; + self.node[level] = node; + self.entry[level] = entry as u8; + } + + // Now that we have a not-full node, it must be possible to insert. + match ins_node { + None => { + let inserted = pool[node].try_leaf_insert(entry, key, value); + debug_assert!(inserted); + // If we inserted at the front of the new rhs_node leaf, we need to propagate + // the inserted key as the critical key instead of the previous front key. + if entry == 0 && node == rhs_node { + split.crit_key = key; + } + } + Some(n) => { + let inserted = pool[node].try_inner_insert(entry, key, n); + debug_assert!(inserted); + // The lower level was moved to the new RHS node, so make sure that is + // reflected here. + if n == self.node[level + 1] { + self.entry[level] += 1; + } + } + } + + // We are now done with the current level, but `rhs_node` must be inserted in the inner + // node above us. If we're already at level 0, the root node needs to be split. + key = split.crit_key; + ins_node = Some(rhs_node); + if level > 0 { + let pnode = &mut pool[self.node[level - 1]]; + let pentry = self.entry[level - 1].into(); + if pnode.try_inner_insert(pentry, key, rhs_node) { + // If this level level was moved to the new RHS node, update parent entry. + if node == rhs_node { + self.entry[level - 1] += 1; + } + return; + } + } + } + + // If we get here we have split the original root node and need to add an extra level. + let rhs_node = ins_node.expect("empty path"); + let root = pool.alloc_node(NodeData::inner(orig_root, key, rhs_node)); + let entry = if self.node[0] == rhs_node { 1 } else { 0 }; + self.size += 1; + slice_insert(&mut self.node[0..self.size], 0, root); + slice_insert(&mut self.entry[0..self.size], 0, entry); + } + + /// Remove the key-value pair at the current position and advance the path to the next + /// key-value pair, leaving the path in a normalized state. + /// + /// Return the new root node. + pub fn remove(&mut self, pool: &mut NodePool) -> Option { + let e = self.leaf_entry(); + match pool[self.leaf_node()].leaf_remove(e) { + Removed::Healthy => { + if e == 0 { + self.update_crit_key(pool) + } + Some(self.node[0]) + } + status => self.balance_nodes(status, pool), + } + } + + /// Get the critical key for the current node at `level`. + /// + /// The critical key is less than or equal to all keys in the sub-tree at `level` and greater + /// than all keys to the left of the current node at `level`. + /// + /// The left-most node at any level does not have a critical key. + fn current_crit_key(&self, level: usize, pool: &NodePool) -> Option { + // Find the level containing the critical key for the current node. + self.left_sibling_branch_level(level).map(|bl| { + let (keys, _) = pool[self.node[bl]].unwrap_inner(); + keys[usize::from(self.entry[bl]) - 1] + }) + } + + /// Update the critical key after removing the front entry of the leaf node. + fn update_crit_key(&mut self, pool: &mut NodePool) { + // Find the inner level containing the critical key for the current leaf node. + let crit_level = match self.left_sibling_branch_level(self.size - 1) { + None => return, + Some(l) => l, + }; + let crit_kidx = self.entry[crit_level] - 1; + + // Extract the new critical key from the leaf node. + let crit_key = pool[self.leaf_node()].leaf_crit_key(); + let crit_node = self.node[crit_level]; + + match pool[crit_node] { + NodeData::Inner { + size, ref mut keys, .. + } => { + debug_assert!(crit_kidx < size); + keys[usize::from(crit_kidx)] = crit_key; + } + _ => panic!("Expected inner node"), + } + } + + /// Given that the current leaf node is in an unhealthy (underflowed or even empty) status, + /// balance it with sibling nodes. + /// + /// Return the new root node. + fn balance_nodes(&mut self, status: Removed, pool: &mut NodePool) -> Option { + // The current leaf node is not in a healthy state, and its critical key may have changed + // too. + // + // Start by dealing with a changed critical key for the leaf level. + if status != Removed::Empty && self.leaf_entry() == 0 { + self.update_crit_key(pool); + } + + let leaf_level = self.size - 1; + if self.heal_level(status, leaf_level, pool) { + // Tree has become empty. + self.size = 0; + return None; + } + + // Discard the root node if it has shrunk to a single sub-tree. + let mut ns = 0; + while let NodeData::Inner { + size: 0, ref tree, .. + } = pool[self.node[ns]] + { + ns += 1; + self.node[ns] = tree[0]; + } + + if ns > 0 { + for l in 0..ns { + pool.free_node(self.node[l]); + } + + // Shift the whole array instead of just 0..size because `self.size` may be cleared + // here if the path is pointing off-the-end. + slice_shift(&mut self.node, ns); + slice_shift(&mut self.entry, ns); + + if self.size > 0 { + self.size -= ns; + } + } + + // Return the root node, even when `size=0` indicating that we're at the off-the-end + // position. + Some(self.node[0]) + } + + /// After removing an entry from the node at `level`, check its health and rebalance as needed. + /// + /// Leave the path up to and including `level` in a normalized state where all entries are in + /// bounds. + /// + /// Returns true if the tree becomes empty. + fn heal_level(&mut self, status: Removed, level: usize, pool: &mut NodePool) -> bool { + match status { + Removed::Healthy => {} + Removed::Rightmost => { + // The rightmost entry was removed from the current node, so move the path so it + // points at the first entry of the next node at this level. + debug_assert_eq!( + usize::from(self.entry[level]), + pool[self.node[level]].entries() + ); + self.next_node(level, pool); + } + Removed::Underflow => self.underflowed_node(level, pool), + Removed::Empty => return self.empty_node(level, pool), + } + false + } + + /// The current node at `level` has underflowed, meaning that it is below half capacity but + /// not completely empty. + /// + /// Handle this by balancing entries with the right sibling node. + /// + /// Leave the path up to and including `level` in a valid state that points to the same entry. + fn underflowed_node(&mut self, level: usize, pool: &mut NodePool) { + // Look for a right sibling node at this level. If none exists, we allow the underflowed + // node to persist as the right-most node at its level. + if let Some((crit_key, rhs_node)) = self.right_sibling(level, pool) { + // New critical key for the updated right sibling node. + let new_ck: Option; + let empty; + // Make a COPY of the sibling node to avoid fighting the borrow checker. + let mut rhs = pool[rhs_node]; + match pool[self.node[level]].balance(crit_key, &mut rhs) { + None => { + // Everything got moved to the RHS node. + new_ck = self.current_crit_key(level, pool); + empty = true; + } + Some(key) => { + // Entries moved from RHS node. + new_ck = Some(key); + empty = false; + } + } + // Put back the updated RHS node data. + pool[rhs_node] = rhs; + // Update the critical key for the RHS node unless it has become a left-most + // node. + if let Some(ck) = new_ck { + self.update_right_crit_key(level, ck, pool); + } + if empty { + let empty_tree = self.empty_node(level, pool); + debug_assert!(!empty_tree); + } + + // Any Removed::Rightmost state must have been cleared above by merging nodes. If the + // current entry[level] was one off the end of the node, it will now point at a proper + // entry. + debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries()); + } else if usize::from(self.entry[level]) >= pool[self.node[level]].entries() { + // There's no right sibling at this level, so the node can't be rebalanced. + // Check if we are in an off-the-end position. + self.size = 0; + } + } + + /// The current node at `level` has become empty. + /// + /// Remove the node from its parent node and leave the path in a normalized state. This means + /// that the path at this level will go through the right sibling of this node. + /// + /// If the current node has no right sibling, set `self.size = 0`. + /// + /// Returns true if the tree becomes empty. + fn empty_node(&mut self, level: usize, pool: &mut NodePool) -> bool { + pool.free_node(self.node[level]); + if level == 0 { + // We just deleted the root node, so the tree is now empty. + return true; + } + + // Get the right sibling node before recursively removing nodes. + let rhs_node = self.right_sibling(level, pool).map(|(_, n)| n); + + // Remove the current sub-tree from the parent node. + let pl = level - 1; + let pe = self.entry[pl].into(); + let status = pool[self.node[pl]].inner_remove(pe); + self.heal_level(status, pl, pool); + + // Finally update the path at this level. + match rhs_node { + // We'll leave `self.entry[level]` unchanged. It can be non-zero after moving node + // entries to the right sibling node. + Some(rhs) => self.node[level] = rhs, + // We have no right sibling, so we must have deleted the right-most + // entry. The path should be moved to the "off-the-end" position. + None => self.size = 0, + } + false + } + + /// Find the level where the right sibling to the current node at `level` branches off. + /// + /// This will be an inner node with two adjacent sub-trees: In one the current node at level is + /// a right-most node, in the other, the right sibling is a left-most node. + /// + /// Returns `None` if the current node is a right-most node so no right sibling exists. + fn right_sibling_branch_level(&self, level: usize, pool: &NodePool) -> Option { + (0..level).rposition(|l| match pool[self.node[l]] { + NodeData::Inner { size, .. } => self.entry[l] < size, + _ => panic!("Expected inner node"), + }) + } + + /// Find the level where the left sibling to the current node at `level` branches off. + fn left_sibling_branch_level(&self, level: usize) -> Option { + self.entry[0..level].iter().rposition(|&e| e != 0) + } + + /// Get the right sibling node to the current node at `level`. + /// Also return the critical key between the current node and the right sibling. + fn right_sibling(&self, level: usize, pool: &NodePool) -> Option<(F::Key, Node)> { + // Find the critical level: The deepest level where two sibling subtrees contain the + // current node and its right sibling. + self.right_sibling_branch_level(level, pool).map(|bl| { + // Extract the critical key and the `bl+1` node. + let be = usize::from(self.entry[bl]); + let crit_key; + let mut node; + { + let (keys, tree) = pool[self.node[bl]].unwrap_inner(); + crit_key = keys[be]; + node = tree[be + 1]; + } + + // Follow left-most links back down to `level`. + for _ in bl + 1..level { + node = pool[node].unwrap_inner().1[0]; + } + + (crit_key, node) + }) + } + + /// Update the critical key for the right sibling node at `level`. + fn update_right_crit_key(&self, level: usize, crit_key: F::Key, pool: &mut NodePool) { + let bl = self + .right_sibling_branch_level(level, pool) + .expect("No right sibling exists"); + match pool[self.node[bl]] { + NodeData::Inner { ref mut keys, .. } => { + keys[usize::from(self.entry[bl])] = crit_key; + } + _ => panic!("Expected inner node"), + } + } + + /// Normalize the path position such that it is either pointing at a real entry or `size=0` + /// indicating "off-the-end". + pub fn normalize(&mut self, pool: &mut NodePool) { + if let Some((leaf, entry)) = self.leaf_pos() { + if entry >= pool[leaf].entries() { + let leaf_level = self.size - 1; + self.next_node(leaf_level, pool); + } + } + } +} + +#[cfg(test)] +impl Path { + /// Check the internal consistency of this path. + pub fn verify(&self, pool: &NodePool) { + for level in 0..self.size { + match pool[self.node[level]] { + NodeData::Inner { size, tree, .. } => { + assert!(level < self.size - 1, "Expected leaf node at level {level}"); + assert!( + self.entry[level] <= size, + "OOB inner entry {}/{} at level {}", + self.entry[level], + size, + level + ); + assert_eq!( + self.node[level + 1], + tree[usize::from(self.entry[level])], + "Node mismatch at level {level}" + ); + } + NodeData::Leaf { size, .. } => { + assert_eq!(level, self.size - 1, "Expected inner node"); + assert!( + self.entry[level] <= size, + "OOB leaf entry {}/{}", + self.entry[level], + size, + ); + } + NodeData::Free { .. } => { + panic!("Free {} in path", self.node[level]); + } + } + } + } +} + +#[cfg(test)] +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.size == 0 { + write!(f, "") + } else { + write!(f, "{}[{}]", self.node[0], self.entry[0])?; + for i in 1..self.size { + write!(f, "--{}[{}]", self.node[i], self.entry[i])?; + } + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::cmp::Ordering; + + struct TC(); + + impl Comparator for TC { + fn cmp(&self, a: i32, b: i32) -> Ordering { + a.cmp(&b) + } + } + + struct TF(); + + impl Forest for TF { + type Key = i32; + type Value = char; + type LeafKeys = [i32; 7]; + type LeafValues = [char; 7]; + + fn splat_key(key: Self::Key) -> Self::LeafKeys { + [key; 7] + } + + fn splat_value(value: Self::Value) -> Self::LeafValues { + [value; 7] + } + } + + #[test] + fn search_single_leaf() { + // Testing Path::new() for trees with a single leaf node. + let mut pool = NodePool::::new(); + let root = pool.alloc_node(NodeData::leaf(10, 'a')); + let mut p = Path::default(); + let comp = TC(); + + // Search for key less than stored key. + assert_eq!(p.find(5, root, &pool, &comp), None); + assert_eq!(p.size, 1); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 0); + + // Search for stored key. + assert_eq!(p.find(10, root, &pool, &comp), Some('a')); + assert_eq!(p.size, 1); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 0); + + // Search for key greater than stored key. + assert_eq!(p.find(15, root, &pool, &comp), None); + assert_eq!(p.size, 1); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 1); + + // Modify leaf node to contain two values. + match pool[root] { + NodeData::Leaf { + ref mut size, + ref mut keys, + ref mut vals, + } => { + *size = 2; + keys[1] = 20; + vals[1] = 'b'; + } + _ => unreachable!(), + } + + // Search for key between stored keys. + assert_eq!(p.find(15, root, &pool, &comp), None); + assert_eq!(p.size, 1); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 1); + + // Search for key greater than stored keys. + assert_eq!(p.find(25, root, &pool, &comp), None); + assert_eq!(p.size, 1); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 2); + } + + #[test] + fn search_single_inner() { + // Testing Path::new() for trees with a single inner node and two leaves. + let mut pool = NodePool::::new(); + let leaf1 = pool.alloc_node(NodeData::leaf(10, 'a')); + let leaf2 = pool.alloc_node(NodeData::leaf(20, 'b')); + let root = pool.alloc_node(NodeData::inner(leaf1, 20, leaf2)); + let mut p = Path::default(); + let comp = TC(); + + // Search for key less than stored keys. + assert_eq!(p.find(5, root, &pool, &comp), None); + assert_eq!(p.size, 2); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 0); + assert_eq!(p.node[1], leaf1); + assert_eq!(p.entry[1], 0); + + assert_eq!(p.find(10, root, &pool, &comp), Some('a')); + assert_eq!(p.size, 2); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 0); + assert_eq!(p.node[1], leaf1); + assert_eq!(p.entry[1], 0); + + // Midway between the two leaf nodes. + assert_eq!(p.find(15, root, &pool, &comp), None); + assert_eq!(p.size, 2); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 0); + assert_eq!(p.node[1], leaf1); + assert_eq!(p.entry[1], 1); + + assert_eq!(p.find(20, root, &pool, &comp), Some('b')); + assert_eq!(p.size, 2); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 1); + assert_eq!(p.node[1], leaf2); + assert_eq!(p.entry[1], 0); + + assert_eq!(p.find(25, root, &pool, &comp), None); + assert_eq!(p.size, 2); + assert_eq!(p.node[0], root); + assert_eq!(p.entry[0], 1); + assert_eq!(p.node[1], leaf2); + assert_eq!(p.entry[1], 1); + } +} diff --git a/deps/crates/vendor/cranelift-bforest/src/pool.rs b/deps/crates/vendor/cranelift-bforest/src/pool.rs new file mode 100644 index 00000000000000..9e3f57fcceddba --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/pool.rs @@ -0,0 +1,219 @@ +//! B+-tree node pool. + +#[cfg(test)] +use super::Comparator; +use super::{Forest, Node, NodeData}; +use crate::entity::PrimaryMap; +#[cfg(test)] +use core::fmt; +use core::ops::{Index, IndexMut}; + +/// A pool of nodes, including a free list. +pub(super) struct NodePool { + nodes: PrimaryMap>, + freelist: Option, +} + +impl NodePool { + /// Allocate a new empty pool of nodes. + pub fn new() -> Self { + Self { + nodes: PrimaryMap::new(), + freelist: None, + } + } + + /// Free all nodes. + pub fn clear(&mut self) { + self.nodes.clear(); + self.freelist = None; + } + + /// Allocate a new node containing `data`. + pub fn alloc_node(&mut self, data: NodeData) -> Node { + debug_assert!(!data.is_free(), "can't allocate free node"); + match self.freelist { + Some(node) => { + // Remove this node from the free list. + match self.nodes[node] { + NodeData::Free { next } => self.freelist = next, + _ => panic!("Invalid {} on free list", node), + } + self.nodes[node] = data; + node + } + None => { + // The free list is empty. Allocate a new node. + self.nodes.push(data) + } + } + } + + /// Free a node. + pub fn free_node(&mut self, node: Node) { + // Quick check for a double free. + debug_assert!(!self.nodes[node].is_free(), "{node} is already free"); + self.nodes[node] = NodeData::Free { + next: self.freelist, + }; + self.freelist = Some(node); + } + + /// Free the entire tree rooted at `node`. + pub fn free_tree(&mut self, node: Node) { + if let NodeData::Inner { size, tree, .. } = self[node] { + // Note that we have to capture `tree` by value to avoid borrow checker trouble. + for i in 0..usize::from(size + 1) { + // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`, + // and since most trees have less than a handful of nodes, it is worthwhile to + // avoid the heap allocation for an iterative tree traversal. + self.free_tree(tree[i]); + } + } + self.free_node(node); + } +} + +#[cfg(test)] +impl NodePool { + /// Verify the consistency of the tree rooted at `node`. + pub fn verify_tree>(&self, node: Node, comp: &C) + where + NodeData: fmt::Display, + F::Key: fmt::Display, + { + use crate::entity::EntitySet; + use alloc::vec::Vec; + use core::borrow::Borrow; + use core::cmp::Ordering; + + // The root node can't be an inner node with just a single sub-tree. It should have been + // pruned. + if let NodeData::Inner { size, .. } = self[node] { + assert!(size > 0, "Root must have more than one sub-tree"); + } + + let mut done = match self[node] { + NodeData::Inner { size, .. } | NodeData::Leaf { size, .. } => { + EntitySet::with_capacity(size.into()) + } + _ => EntitySet::new(), + }; + + let mut todo = Vec::new(); + + // Todo-list entries are: + // 1. Optional LHS key which must be <= all node entries. + // 2. The node reference. + // 3. Optional RHS key which must be > all node entries. + todo.push((None, node, None)); + + while let Some((lkey, node, rkey)) = todo.pop() { + assert!(done.insert(node), "Node appears more than once in tree"); + let mut lower = lkey; + + match self[node] { + NodeData::Inner { size, keys, tree } => { + let size = size as usize; + let capacity = tree.len(); + let keys = &keys[0..size]; + + // Verify occupancy. + // Right-most nodes can be small, but others must be at least half full. + assert!( + rkey.is_none() || (size + 1) * 2 >= capacity, + "Only {}/{} entries in {}:{}, upper={}", + size + 1, + capacity, + node, + self[node], + rkey.unwrap() + ); + + // Queue up the sub-trees, checking for duplicates. + for i in 0..size + 1 { + // Get an upper bound for node[i]. + let upper = keys.get(i).cloned().or(rkey); + + // Check that keys are strictly monotonic. + if let (Some(a), Some(b)) = (lower, upper) { + assert_eq!( + comp.cmp(a, b), + Ordering::Less, + "Key order {} < {} failed in {}: {}", + a, + b, + node, + self[node] + ); + } + + // Queue up the sub-tree. + todo.push((lower, tree[i], upper)); + + // Set a lower bound for the next tree. + lower = upper; + } + } + NodeData::Leaf { size, keys, .. } => { + let size = size as usize; + let capacity = keys.borrow().len(); + let keys = &keys.borrow()[0..size]; + + // Verify occupancy. + // Right-most nodes can be small, but others must be at least half full. + assert!(size > 0, "Leaf {node} is empty"); + assert!( + rkey.is_none() || size * 2 >= capacity, + "Only {}/{} entries in {}:{}, upper={}", + size, + capacity, + node, + self[node], + rkey.unwrap() + ); + + for i in 0..size + 1 { + let upper = keys.get(i).cloned().or(rkey); + + // Check that keys are strictly monotonic. + if let (Some(a), Some(b)) = (lower, upper) { + let wanted = if i == 0 { + Ordering::Equal + } else { + Ordering::Less + }; + assert_eq!( + comp.cmp(a, b), + wanted, + "Key order for {} - {} failed in {}: {}", + a, + b, + node, + self[node] + ); + } + + // Set a lower bound for the next key. + lower = upper; + } + } + NodeData::Free { .. } => panic!("Free {} reached", node), + } + } + } +} + +impl Index for NodePool { + type Output = NodeData; + + fn index(&self, index: Node) -> &Self::Output { + self.nodes.index(index) + } +} + +impl IndexMut for NodePool { + fn index_mut(&mut self, index: Node) -> &mut Self::Output { + self.nodes.index_mut(index) + } +} diff --git a/deps/crates/vendor/cranelift-bforest/src/set.rs b/deps/crates/vendor/cranelift-bforest/src/set.rs new file mode 100644 index 00000000000000..34a3063c2f3de8 --- /dev/null +++ b/deps/crates/vendor/cranelift-bforest/src/set.rs @@ -0,0 +1,596 @@ +//! Forest of sets. + +use super::{Comparator, Forest, Node, NodeData, NodePool, Path, SetValue, INNER_SIZE}; +use crate::packed_option::PackedOption; +#[cfg(test)] +use alloc::string::String; +#[cfg(test)] +use core::fmt; +use core::marker::PhantomData; + +/// Tag type defining forest types for a set. +struct SetTypes(PhantomData); + +impl Forest for SetTypes +where + K: Copy, +{ + type Key = K; + type Value = SetValue; + type LeafKeys = [K; 2 * INNER_SIZE - 1]; + type LeafValues = [SetValue; 2 * INNER_SIZE - 1]; + + fn splat_key(key: Self::Key) -> Self::LeafKeys { + [key; 2 * INNER_SIZE - 1] + } + + fn splat_value(value: Self::Value) -> Self::LeafValues { + [value; 2 * INNER_SIZE - 1] + } +} + +/// Memory pool for a forest of `Set` instances. +pub struct SetForest +where + K: Copy, +{ + nodes: NodePool>, +} + +impl SetForest +where + K: Copy, +{ + /// Create a new empty forest. + pub fn new() -> Self { + Self { + nodes: NodePool::new(), + } + } + + /// Clear all sets in the forest. + /// + /// All `Set` instances belong to this forest are invalidated and should no longer be used. + pub fn clear(&mut self) { + self.nodes.clear(); + } +} + +/// B-tree representing an ordered set of `K`s using `C` for comparing elements. +/// +/// This is not a general-purpose replacement for `BTreeSet`. See the [module +/// documentation](index.html) for more information about design tradeoffs. +/// +/// Sets can be cloned, but that operation should only be used as part of cloning the whole forest +/// they belong to. *Cloning a set does not allocate new memory for the clone*. It creates an alias +/// of the same memory. +#[derive(Clone)] +pub struct Set +where + K: Copy, +{ + root: PackedOption, + unused: PhantomData, +} + +impl Set +where + K: Copy, +{ + /// Make an empty set. + pub fn new() -> Self { + Self { + root: None.into(), + unused: PhantomData, + } + } + + /// Is this an empty set? + pub fn is_empty(&self) -> bool { + self.root.is_none() + } + + /// Does the set contain `key`?. + pub fn contains>(&self, key: K, forest: &SetForest, comp: &C) -> bool { + self.root + .expand() + .and_then(|root| Path::default().find(key, root, &forest.nodes, comp)) + .is_some() + } + + /// Try to insert `key` into the set. + /// + /// If the set did not contain `key`, insert it and return true. + /// + /// If `key` is already present, don't change the set and return false. + pub fn insert>( + &mut self, + key: K, + forest: &mut SetForest, + comp: &C, + ) -> bool { + self.cursor(forest, comp).insert(key) + } + + /// Remove `key` from the set and return true. + /// + /// If `key` was not present in the set, return false. + pub fn remove>( + &mut self, + key: K, + forest: &mut SetForest, + comp: &C, + ) -> bool { + let mut c = self.cursor(forest, comp); + if c.goto(key) { + c.remove(); + true + } else { + false + } + } + + /// Remove all entries. + pub fn clear(&mut self, forest: &mut SetForest) { + if let Some(root) = self.root.take() { + forest.nodes.free_tree(root); + } + } + + /// Retains only the elements specified by the predicate. + /// + /// Remove all elements where the predicate returns false. + pub fn retain(&mut self, forest: &mut SetForest, mut predicate: F) + where + F: FnMut(K) -> bool, + { + let mut path = Path::default(); + if let Some(root) = self.root.expand() { + path.first(root, &forest.nodes); + } + while let Some((node, entry)) = path.leaf_pos() { + if predicate(forest.nodes[node].unwrap_leaf().0[entry]) { + path.next(&forest.nodes); + } else { + self.root = path.remove(&mut forest.nodes).into(); + } + } + } + + /// Create a cursor for navigating this set. The cursor is initially positioned off the end of + /// the set. + pub fn cursor<'a, C: Comparator>( + &'a mut self, + forest: &'a mut SetForest, + comp: &'a C, + ) -> SetCursor<'a, K, C> { + SetCursor::new(self, forest, comp) + } + + /// Create an iterator traversing this set. The iterator type is `K`. + pub fn iter<'a>(&'a self, forest: &'a SetForest) -> SetIter<'a, K> { + SetIter { + root: self.root, + pool: &forest.nodes, + path: Path::default(), + } + } +} + +impl Default for Set +where + K: Copy, +{ + fn default() -> Self { + Self::new() + } +} + +/// A position in a `Set` used to navigate and modify the ordered set. +/// +/// A cursor always points at an element in the set, or "off the end" which is a position after the +/// last element in the set. +pub struct SetCursor<'a, K, C> +where + K: 'a + Copy, + C: 'a + Comparator, +{ + root: &'a mut PackedOption, + pool: &'a mut NodePool>, + comp: &'a C, + path: Path>, +} + +impl<'a, K, C> SetCursor<'a, K, C> +where + K: Copy, + C: Comparator, +{ + /// Create a cursor with a default (invalid) location. + fn new(container: &'a mut Set, forest: &'a mut SetForest, comp: &'a C) -> Self { + Self { + root: &mut container.root, + pool: &mut forest.nodes, + comp, + path: Path::default(), + } + } + + /// Is this cursor pointing to an empty set? + pub fn is_empty(&self) -> bool { + self.root.is_none() + } + + /// Move cursor to the next element and return it. + /// + /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end + /// position. + pub fn next(&mut self) -> Option { + self.path.next(self.pool).map(|(k, _)| k) + } + + /// Move cursor to the previous element and return it. + /// + /// If the cursor is already pointing at the first element, leave it there and return `None`. + pub fn prev(&mut self) -> Option { + self.root + .expand() + .and_then(|root| self.path.prev(root, self.pool).map(|(k, _)| k)) + } + + /// Get the current element, or `None` if the cursor is at the end. + pub fn elem(&self) -> Option { + self.path + .leaf_pos() + .and_then(|(node, entry)| self.pool[node].unwrap_leaf().0.get(entry).cloned()) + } + + /// Move this cursor to `elem`. + /// + /// If `elem` is in the set, place the cursor at `elem` and return true. + /// + /// If `elem` is not in the set, place the cursor at the next larger element (or the end) and + /// return false. + pub fn goto(&mut self, elem: K) -> bool { + match self.root.expand() { + None => false, + Some(root) => { + if self.path.find(elem, root, self.pool, self.comp).is_some() { + true + } else { + self.path.normalize(self.pool); + false + } + } + } + } + + /// Move this cursor to the first element. + pub fn goto_first(&mut self) -> Option { + self.root.map(|root| self.path.first(root, self.pool).0) + } + + /// Try to insert `elem` into the set and leave the cursor at the inserted element. + /// + /// If the set did not contain `elem`, insert it and return true. + /// + /// If `elem` is already present, don't change the set, place the cursor at `goto(elem)`, and + /// return false. + pub fn insert(&mut self, elem: K) -> bool { + match self.root.expand() { + None => { + let root = self.pool.alloc_node(NodeData::leaf(elem, SetValue())); + *self.root = root.into(); + self.path.set_root_node(root); + true + } + Some(root) => { + // TODO: Optimize the case where `self.path` is already at the correct insert pos. + if self.path.find(elem, root, self.pool, self.comp).is_none() { + *self.root = self.path.insert(elem, SetValue(), self.pool).into(); + true + } else { + false + } + } + } + } + + /// Remove the current element (if any) and return it. + /// This advances the cursor to the next element after the removed one. + pub fn remove(&mut self) -> Option { + let elem = self.elem(); + if elem.is_some() { + *self.root = self.path.remove(self.pool).into(); + } + elem + } +} + +#[cfg(test)] +impl<'a, K, C> SetCursor<'a, K, C> +where + K: Copy + fmt::Display, + C: Comparator, +{ + fn verify(&self) { + self.path.verify(self.pool); + self.root.map(|root| self.pool.verify_tree(root, self.comp)); + } + + /// Get a text version of the path to the current position. + fn tpath(&self) -> String { + use alloc::string::ToString; + self.path.to_string() + } +} + +/// An iterator visiting the elements of a `Set`. +pub struct SetIter<'a, K> +where + K: 'a + Copy, +{ + root: PackedOption, + pool: &'a NodePool>, + path: Path>, +} + +impl<'a, K> Iterator for SetIter<'a, K> +where + K: 'a + Copy, +{ + type Item = K; + + fn next(&mut self) -> Option { + // We use `self.root` to indicate if we need to go to the first element. Reset to `None` + // once we've returned the first element. This also works for an empty tree since the + // `path.next()` call returns `None` when the path is empty. This also fuses the iterator. + match self.root.take() { + Some(root) => Some(self.path.first(root, self.pool).0), + None => self.path.next(self.pool).map(|(k, _)| k), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec::Vec; + use core::mem; + + #[test] + fn node_size() { + // check that nodes are cache line sized when keys are 32 bits. + type F = SetTypes; + assert_eq!(mem::size_of::>(), 64); + } + + #[test] + fn empty() { + let mut f = SetForest::::new(); + f.clear(); + + let mut s = Set::::new(); + assert!(s.is_empty()); + s.clear(&mut f); + assert!(!s.contains(7, &f, &())); + + // Iterator for an empty set. + assert_eq!(s.iter(&f).next(), None); + + s.retain(&mut f, |_| unreachable!()); + + let mut c = SetCursor::new(&mut s, &mut f, &()); + c.verify(); + assert_eq!(c.elem(), None); + + assert_eq!(c.goto_first(), None); + assert_eq!(c.tpath(), ""); + } + + #[test] + fn simple_cursor() { + let mut f = SetForest::::new(); + let mut s = Set::::new(); + let mut c = SetCursor::new(&mut s, &mut f, &()); + + assert!(c.insert(50)); + c.verify(); + assert_eq!(c.elem(), Some(50)); + + assert!(c.insert(100)); + c.verify(); + assert_eq!(c.elem(), Some(100)); + + assert!(c.insert(10)); + c.verify(); + assert_eq!(c.elem(), Some(10)); + + // Basic movement. + assert_eq!(c.next(), Some(50)); + assert_eq!(c.next(), Some(100)); + assert_eq!(c.next(), None); + assert_eq!(c.next(), None); + assert_eq!(c.prev(), Some(100)); + assert_eq!(c.prev(), Some(50)); + assert_eq!(c.prev(), Some(10)); + assert_eq!(c.prev(), None); + assert_eq!(c.prev(), None); + + assert!(c.goto(50)); + assert_eq!(c.elem(), Some(50)); + assert_eq!(c.remove(), Some(50)); + c.verify(); + + assert_eq!(c.elem(), Some(100)); + assert_eq!(c.remove(), Some(100)); + c.verify(); + assert_eq!(c.elem(), None); + assert_eq!(c.remove(), None); + c.verify(); + } + + #[test] + fn two_level_sparse_tree() { + let mut f = SetForest::::new(); + let mut s = Set::::new(); + let mut c = SetCursor::new(&mut s, &mut f, &()); + + // Insert enough elements that we get a two-level tree. + // Each leaf node holds 8 elements + assert!(c.is_empty()); + for i in 0..50 { + assert!(c.insert(i)); + assert_eq!(c.elem(), Some(i)); + } + assert!(!c.is_empty()); + + assert_eq!(c.goto_first(), Some(0)); + assert_eq!(c.tpath(), "node2[0]--node0[0]"); + + assert_eq!(c.prev(), None); + for i in 1..50 { + assert_eq!(c.next(), Some(i)); + } + assert_eq!(c.next(), None); + for i in (0..50).rev() { + assert_eq!(c.prev(), Some(i)); + } + assert_eq!(c.prev(), None); + + assert!(c.goto(25)); + for i in 25..50 { + assert_eq!(c.remove(), Some(i)); + assert!(!c.is_empty()); + c.verify(); + } + + for i in (0..25).rev() { + assert!(!c.is_empty()); + assert_eq!(c.elem(), None); + assert_eq!(c.prev(), Some(i)); + assert_eq!(c.remove(), Some(i)); + c.verify(); + } + assert_eq!(c.elem(), None); + assert!(c.is_empty()); + } + + #[test] + fn three_level_sparse_tree() { + let mut f = SetForest::::new(); + let mut s = Set::::new(); + let mut c = SetCursor::new(&mut s, &mut f, &()); + + // Insert enough elements that we get a 3-level tree. + // Each leaf node holds 8 elements when filled up sequentially. + // Inner nodes hold 8 node pointers. + assert!(c.is_empty()); + for i in 0..150 { + assert!(c.insert(i)); + assert_eq!(c.elem(), Some(i)); + } + assert!(!c.is_empty()); + + assert!(c.goto(0)); + assert_eq!(c.tpath(), "node11[0]--node2[0]--node0[0]"); + + assert_eq!(c.prev(), None); + for i in 1..150 { + assert_eq!(c.next(), Some(i)); + } + assert_eq!(c.next(), None); + for i in (0..150).rev() { + assert_eq!(c.prev(), Some(i)); + } + assert_eq!(c.prev(), None); + + assert!(c.goto(125)); + for i in 125..150 { + assert_eq!(c.remove(), Some(i)); + assert!(!c.is_empty()); + c.verify(); + } + + for i in (0..125).rev() { + assert!(!c.is_empty()); + assert_eq!(c.elem(), None); + assert_eq!(c.prev(), Some(i)); + assert_eq!(c.remove(), Some(i)); + c.verify(); + } + assert_eq!(c.elem(), None); + assert!(c.is_empty()); + } + + // Generate a densely populated 4-level tree. + // + // Level 1: 1 root + // Level 2: 8 inner + // Level 3: 64 inner + // Level 4: 512 leafs, up to 7680 elements + // + // A 3-level tree can hold at most 960 elements. + fn dense4l(f: &mut SetForest) -> Set { + f.clear(); + let mut s = Set::new(); + + // Insert 400 elements in 7 passes over the range to avoid the half-full leaf node pattern + // that comes from sequential insertion. This will generate a normal leaf layer. + for n in 0..4000 { + assert!(s.insert((n * 7) % 4000, f, &())); + } + s + } + + #[test] + fn four_level() { + let mut f = SetForest::::new(); + let mut s = dense4l(&mut f); + + assert_eq!( + s.iter(&f).collect::>()[0..10], + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ); + + let mut c = s.cursor(&mut f, &()); + + c.verify(); + + // Peel off a whole sub-tree of the root by deleting from the front. + // The 900 element is near the front of the second sub-tree. + assert!(c.goto(900)); + assert_eq!(c.tpath(), "node48[1]--node47[0]--node26[0]--node20[4]"); + assert!(c.goto(0)); + for i in 0..900 { + assert!(!c.is_empty()); + assert_eq!(c.remove(), Some(i)); + } + c.verify(); + assert_eq!(c.elem(), Some(900)); + + // Delete backwards from somewhere in the middle. + assert!(c.goto(3000)); + for i in (2000..3000).rev() { + assert_eq!(c.prev(), Some(i)); + assert_eq!(c.remove(), Some(i)); + assert_eq!(c.elem(), Some(3000)); + } + c.verify(); + + // Remove everything in a scattered manner, triggering many collapsing patterns. + for i in 0..4000 { + if c.goto((i * 7) % 4000) { + c.remove(); + } + } + assert!(c.is_empty()); + } + + #[test] + fn four_level_clear() { + let mut f = SetForest::::new(); + let mut s = dense4l(&mut f); + s.clear(&mut f); + } +} diff --git a/deps/crates/vendor/cranelift-bitset/.cargo-checksum.json b/deps/crates/vendor/cranelift-bitset/.cargo-checksum.json new file mode 100644 index 00000000000000..a5eefb269560eb --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"33175b499605eeabaf11eeaa670151ef1fabc4b6e2c4994320cec92021c5da0d","Cargo.lock":"29379f2fdcbcf716211a028a4b7db1da826ec22f1662b0718954477fe82589a3","Cargo.toml":"b01e729b0303dbd74069359f37d037d9b4c6e9716596d2fa5872a4a171c7b341","Cargo.toml.orig":"14ca0f5c48dbf15c28b9252f1d8880ab4c9545479926310ece50587c0bf02d45","src/compound.rs":"10fc436a90c313f2c51a2fca563ef502fa4276d66d8b6d3a5502be0f426ab23c","src/lib.rs":"f8df4142218c08cda5e38bb5087a8e2869e694acdec228a4a163d1eb1156d6b1","src/scalar.rs":"c9f0b45f299fdfa9e6f6b24517df2e2b942d15d35fecfcee9972ab9deab82c7b","tests/bitset.rs":"a6328a130b8a6c6b1b5f9415e706b89a16a04fcc91f739b386371fe66b540b5d"},"package":"7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-bitset/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-bitset/.cargo_vcs_info.json new file mode 100644 index 00000000000000..a1e4d0682f7546 --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/bitset" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-bitset/Cargo.lock b/deps/crates/vendor/cranelift-bitset/Cargo.lock new file mode 100644 index 00000000000000..b1ba3dc058d328 --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/Cargo.lock @@ -0,0 +1,73 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +dependencies = [ + "arbitrary", + "serde", + "serde_derive", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/deps/crates/vendor/cranelift-bitset/Cargo.toml b/deps/crates/vendor/cranelift-bitset/Cargo.toml new file mode 100644 index 00000000000000..c2376e373e2863 --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/Cargo.toml @@ -0,0 +1,88 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-bitset" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Various bitset stuff for use inside Cranelift" +documentation = "https://docs.rs/cranelift-bitset" +readme = false +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_bitset" +path = "src/lib.rs" + +[[test]] +name = "bitset" +path = "tests/bitset.rs" + +[dependencies.arbitrary] +version = "1.4.0" +optional = true + +[dependencies.serde] +version = "1.0.215" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde_derive] +version = "1.0.188" +optional = true + +[features] +arbitrary = ["dep:arbitrary"] +enable-serde = [ + "dep:serde", + "dep:serde_derive", +] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-bitset/Cargo.toml.orig b/deps/crates/vendor/cranelift-bitset/Cargo.toml.orig new file mode 100644 index 00000000000000..2037a633a2ac3b --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/Cargo.toml.orig @@ -0,0 +1,22 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-bitset" +version = "0.116.1" +description = "Various bitset stuff for use inside Cranelift" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift-bitset" +repository = "https://github.com/bytecodealliance/wasmtime" +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +arbitrary = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } + +[features] +enable-serde = ["dep:serde", "dep:serde_derive"] +arbitrary = ["dep:arbitrary"] diff --git a/deps/crates/vendor/cranelift-bitset/src/compound.rs b/deps/crates/vendor/cranelift-bitset/src/compound.rs new file mode 100644 index 00000000000000..ebb9b4e7d703c8 --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/src/compound.rs @@ -0,0 +1,508 @@ +//! Compound bit sets. + +use crate::scalar::{self, ScalarBitSet}; +use alloc::boxed::Box; +use core::{cmp, iter, mem}; + +/// A large bit set backed by dynamically-sized storage. +/// +/// # Example +/// +/// ``` +/// use cranelift_bitset::CompoundBitSet; +/// +/// // Create a new bitset. +/// let mut bitset = CompoundBitSet::new(); +/// +/// // Bitsets are initially empty. +/// assert!(bitset.is_empty()); +/// assert_eq!(bitset.len(), 0); +/// +/// // Insert into the bitset. +/// bitset.insert(444); +/// bitset.insert(555); +/// bitset.insert(666); +/// +/// // Now the bitset is not empty. +/// assert_eq!(bitset.len(), 3); +/// assert!(!bitset.is_empty()); +/// assert!(bitset.contains(444)); +/// assert!(bitset.contains(555)); +/// assert!(bitset.contains(666)); +/// +/// // Remove an element from the bitset. +/// let was_present = bitset.remove(666); +/// assert!(was_present); +/// assert!(!bitset.contains(666)); +/// assert_eq!(bitset.len(), 2); +/// +/// // Can iterate over the elements in the set. +/// let elems: Vec<_> = bitset.iter().collect(); +/// assert_eq!(elems, [444, 555]); +/// ``` +#[derive(Clone, Default, PartialEq, Eq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct CompoundBitSet { + elems: Box<[ScalarBitSet]>, + max: Option, +} + +impl core::fmt::Debug for CompoundBitSet { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "CompoundBitSet ")?; + f.debug_set().entries(self.iter()).finish() + } +} + +const BITS_PER_WORD: usize = mem::size_of::() * 8; + +impl CompoundBitSet { + /// Construct a new, empty bit set. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let bitset = CompoundBitSet::new(); + /// + /// assert!(bitset.is_empty()); + /// ``` + #[inline] + pub fn new() -> Self { + CompoundBitSet::default() + } + + /// Construct a new, empty bit set with space reserved to store any element + /// `x` such that `x < capacity`. + /// + /// The actual capacity reserved may be greater than that requested. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let bitset = CompoundBitSet::with_capacity(4096); + /// + /// assert!(bitset.is_empty()); + /// assert!(bitset.capacity() >= 4096); + /// ``` + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + let mut bitset = Self::new(); + bitset.ensure_capacity(capacity); + bitset + } + + /// Get the number of elements in this bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// assert_eq!(bitset.len(), 0); + /// + /// bitset.insert(24); + /// bitset.insert(130); + /// bitset.insert(3600); + /// + /// assert_eq!(bitset.len(), 3); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.elems.iter().map(|sub| usize::from(sub.len())).sum() + } + + /// Get `n + 1` where `n` is the largest value that can be stored inside + /// this set without growing the backing storage. + /// + /// That is, this set can store any value `x` such that `x < + /// bitset.capacity()` without growing the backing storage. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// // New bitsets have zero capacity -- they allocate lazily. + /// assert_eq!(bitset.capacity(), 0); + /// + /// // Insert into the bitset, growing its capacity. + /// bitset.insert(999); + /// + /// // The bitset must now have capacity for at least `999` elements, + /// // perhaps more. + /// assert!(bitset.capacity() >= 999); + ///``` + pub fn capacity(&self) -> usize { + self.elems.len() * BITS_PER_WORD + } + + /// Is this bitset empty? + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// assert!(bitset.is_empty()); + /// + /// bitset.insert(1234); + /// + /// assert!(!bitset.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Convert an element `i` into the `word` that can be used to index into + /// `self.elems` and the `bit` that can be tested in the + /// `ScalarBitSet` at `self.elems[word]`. + #[inline] + fn word_and_bit(i: usize) -> (usize, u8) { + let word = i / BITS_PER_WORD; + let bit = i % BITS_PER_WORD; + let bit = u8::try_from(bit).unwrap(); + (word, bit) + } + + /// The opposite of `word_and_bit`: convert the pair of an index into + /// `self.elems` and associated bit index into a set element. + #[inline] + fn elem(word: usize, bit: u8) -> usize { + let bit = usize::from(bit); + debug_assert!(bit < BITS_PER_WORD); + word * BITS_PER_WORD + bit + } + + /// Is `i` contained in this bitset? + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// assert!(!bitset.contains(666)); + /// + /// bitset.insert(666); + /// + /// assert!(bitset.contains(666)); + /// ``` + #[inline] + pub fn contains(&self, i: usize) -> bool { + let (word, bit) = Self::word_and_bit(i); + if word < self.elems.len() { + self.elems[word].contains(bit) + } else { + false + } + } + + /// Ensure there is space in this bitset for the values `0..n`, growing the + /// backing storage if necessary. + /// + /// After calling `bitset.ensure_capacity(n)`, inserting any element `i` + /// where `i < n` is guaranteed to succeed without growing the bitset's + /// backing storage. + /// + /// # Example + /// + /// ``` + /// # use cranelift_bitset::CompoundBitSet; + /// # let mut bitset = CompoundBitSet::new(); + /// // We are going to do a series of inserts where `1000` will be the + /// // maximum value inserted. Make sure that our bitset has capacity for + /// // these elements once up front, to avoid growing the backing storage + /// // multiple times incrementally. + /// bitset.ensure_capacity(1001); + /// + /// for i in 0..=1000 { + /// if i % 2 == 0 { + /// // Inserting this value should not require growing the backing + /// // storage. + /// assert!(bitset.capacity() > i); + /// bitset.insert(i); + /// } + /// } + /// ``` + #[inline] + pub fn ensure_capacity(&mut self, n: usize) { + let (word, _bit) = Self::word_and_bit(n); + if word >= self.elems.len() { + assert!(word < usize::try_from(isize::MAX).unwrap()); + + let delta = word - self.elems.len(); + let to_grow = delta + 1; + + // Amortize the cost of growing. + let to_grow = cmp::max(to_grow, self.elems.len() * 2); + // Don't make ridiculously small allocations. + let to_grow = cmp::max(to_grow, 4); + + let new_elems = self + .elems + .iter() + .copied() + .chain(iter::repeat(ScalarBitSet::new()).take(to_grow)) + .collect::>(); + self.elems = new_elems; + } + } + + /// Insert `i` into this bitset. + /// + /// Returns whether the value was newly inserted. That is: + /// + /// * If the set did not previously contain `i` then `true` is returned. + /// + /// * If the set already contained `i` then `false` is returned. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// // When an element is inserted that was not already present in the set, + /// // then `true` is returned. + /// let is_new = bitset.insert(1234); + /// assert!(is_new); + /// + /// // The element is now present in the set. + /// assert!(bitset.contains(1234)); + /// + /// // And when the element is already in the set, `false` is returned from + /// // `insert`. + /// let is_new = bitset.insert(1234); + /// assert!(!is_new); + /// ``` + #[inline] + pub fn insert(&mut self, i: usize) -> bool { + self.ensure_capacity(i + 1); + + let (word, bit) = Self::word_and_bit(i); + let is_new = self.elems[word].insert(bit); + + let i = u32::try_from(i).unwrap(); + self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i)); + + is_new + } + + /// Remove `i` from this bitset. + /// + /// Returns whether `i` was previously in this set or not. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// // Removing an element that was not present in the set returns `false`. + /// let was_present = bitset.remove(456); + /// assert!(!was_present); + /// + /// // And when the element was in the set, `true` is returned. + /// bitset.insert(456); + /// let was_present = bitset.remove(456); + /// assert!(was_present); + /// ``` + #[inline] + pub fn remove(&mut self, i: usize) -> bool { + let (word, bit) = Self::word_and_bit(i); + if word < self.elems.len() { + let sub = &mut self.elems[word]; + let was_present = sub.remove(bit); + if was_present && self.max() == Some(i) { + self.update_max(word); + } + was_present + } else { + false + } + } + + /// Update the `self.max` field, based on the old word index of `self.max`. + fn update_max(&mut self, word_of_old_max: usize) { + self.max = self.elems[0..word_of_old_max + 1] + .iter() + .enumerate() + .rev() + .filter_map(|(word, sub)| { + let bit = sub.max()?; + Some(u32::try_from(Self::elem(word, bit)).unwrap()) + }) + .next(); + } + + /// Get the largest value in this set, or `None` if this set is empty. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// // Returns `None` if the bitset is empty. + /// assert!(bitset.max().is_none()); + /// + /// bitset.insert(123); + /// bitset.insert(987); + /// bitset.insert(999); + /// + /// // Otherwise, it returns the largest value in the set. + /// assert_eq!(bitset.max(), Some(999)); + /// ``` + #[inline] + pub fn max(&self) -> Option { + self.max.map(|m| usize::try_from(m).unwrap()) + } + + /// Removes and returns the largest value in this set. + /// + /// Returns `None` if this set is empty. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// bitset.insert(111); + /// bitset.insert(222); + /// bitset.insert(333); + /// bitset.insert(444); + /// bitset.insert(555); + /// + /// assert_eq!(bitset.pop(), Some(555)); + /// assert_eq!(bitset.pop(), Some(444)); + /// assert_eq!(bitset.pop(), Some(333)); + /// assert_eq!(bitset.pop(), Some(222)); + /// assert_eq!(bitset.pop(), Some(111)); + /// assert_eq!(bitset.pop(), None); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + let max = self.max()?; + self.remove(max); + Some(max) + } + + /// Remove all elements from this bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// bitset.insert(100); + /// bitset.insert(200); + /// bitset.insert(300); + /// + /// bitset.clear(); + /// + /// assert!(bitset.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + let max = match self.max() { + Some(max) => max, + None => return, + }; + let (word, _bit) = Self::word_and_bit(max); + debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty())); + for sub in &mut self.elems[..=word] { + *sub = ScalarBitSet::new(); + } + self.max = None; + } + + /// Iterate over the elements in this bitset. + /// + /// The elements are always yielded in sorted order. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::CompoundBitSet; + /// + /// let mut bitset = CompoundBitSet::new(); + /// + /// bitset.insert(0); + /// bitset.insert(4096); + /// bitset.insert(123); + /// bitset.insert(456); + /// bitset.insert(789); + /// + /// assert_eq!( + /// bitset.iter().collect::>(), + /// [0, 123, 456, 789, 4096], + /// ); + /// ``` + #[inline] + pub fn iter(&self) -> Iter<'_> { + Iter { + bitset: self, + word: 0, + sub: None, + } + } +} + +impl<'a> IntoIterator for &'a CompoundBitSet { + type Item = usize; + + type IntoIter = Iter<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// An iterator over the elements in a [`CompoundBitSet`]. +pub struct Iter<'a> { + bitset: &'a CompoundBitSet, + word: usize, + sub: Option>, +} + +impl Iterator for Iter<'_> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + loop { + if let Some(sub) = &mut self.sub { + if let Some(bit) = sub.next() { + return Some(CompoundBitSet::elem(self.word, bit)); + } else { + self.word += 1; + } + } + + self.sub = Some(self.bitset.elems.get(self.word)?.iter()); + } + } +} diff --git a/deps/crates/vendor/cranelift-bitset/src/lib.rs b/deps/crates/vendor/cranelift-bitset/src/lib.rs new file mode 100644 index 00000000000000..5a9fd354aa157d --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/src/lib.rs @@ -0,0 +1,19 @@ +//! Bitsets for Cranelift. +//! +//! This module provides two bitset implementations: +//! +//! 1. [`ScalarBitSet`]: A small bitset built on top of a single integer. +//! +//! 2. [`CompoundBitSet`]: A bitset that can store more bits than fit in a +//! single integer, but which internally has heap allocations. + +#![deny(missing_docs)] +#![no_std] + +extern crate alloc; + +pub mod compound; +pub mod scalar; + +pub use compound::CompoundBitSet; +pub use scalar::ScalarBitSet; diff --git a/deps/crates/vendor/cranelift-bitset/src/scalar.rs b/deps/crates/vendor/cranelift-bitset/src/scalar.rs new file mode 100644 index 00000000000000..6d05338adbef5d --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/src/scalar.rs @@ -0,0 +1,629 @@ +//! Scalar bitsets. + +use core::mem::size_of; +use core::ops::{Add, BitAnd, BitOr, Not, Shl, Shr, Sub}; + +/// A small bitset built on top of a single primitive integer type. +/// +/// # Example +/// +/// ``` +/// use cranelift_bitset::ScalarBitSet; +/// +/// // Create a new bitset backed with a `u32`. +/// let mut bitset = ScalarBitSet::::new(); +/// +/// // Bitsets are initially empty. +/// assert!(bitset.is_empty()); +/// assert_eq!(bitset.len(), 0); +/// +/// // Insert into the bitset. +/// bitset.insert(4); +/// bitset.insert(5); +/// bitset.insert(6); +/// +/// // Now the bitset is not empty. +/// assert_eq!(bitset.len(), 3); +/// assert!(!bitset.is_empty()); +/// assert!(bitset.contains(4)); +/// assert!(bitset.contains(5)); +/// assert!(bitset.contains(6)); +/// +/// // Remove an element from the bitset. +/// let was_present = bitset.remove(6); +/// assert!(was_present); +/// assert!(!bitset.contains(6)); +/// assert_eq!(bitset.len(), 2); +/// +/// // Can iterate over the elements in the set. +/// let elems: Vec<_> = bitset.iter().collect(); +/// assert_eq!(elems, [4, 5]); +/// ``` +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct ScalarBitSet(pub T); + +impl core::fmt::Debug for ScalarBitSet +where + T: ScalarBitSetStorage, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut s = f.debug_struct(core::any::type_name::()); + for i in 0..Self::capacity() { + use alloc::string::ToString; + let i = u8::try_from(i).unwrap(); + s.field(&i.to_string(), &self.contains(i)); + } + s.finish() + } +} + +impl Default for ScalarBitSet +where + T: ScalarBitSetStorage, +{ + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl ScalarBitSet +where + T: ScalarBitSetStorage, +{ + /// Create a new, empty bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let bitset = ScalarBitSet::::new(); + /// + /// assert!(bitset.is_empty()); + /// ``` + #[inline] + pub fn new() -> Self { + Self(T::from(0)) + } + + /// Construct a bitset with the half-open range `[lo, hi)` inserted. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let bitset = ScalarBitSet::::from_range(3, 6); + /// + /// assert_eq!(bitset.len(), 3); + /// + /// assert!(bitset.contains(3)); + /// assert!(bitset.contains(4)); + /// assert!(bitset.contains(5)); + /// ``` + /// + /// # Panics + /// + /// Panics if `lo > hi` or if `hi > Self::capacity()`. + /// + /// ```should_panic + /// use cranelift_bitset::ScalarBitSet; + /// + /// // The lower bound may not be larger than the upper bound. + /// let bitset = ScalarBitSet::::from_range(6, 3); + /// ``` + /// + /// ```should_panic + /// use cranelift_bitset::ScalarBitSet; + /// + /// // The bounds must fit within the backing scalar type. + /// let bitset = ScalarBitSet::::from_range(3, 69); + /// ``` + #[inline] + pub fn from_range(lo: u8, hi: u8) -> Self { + assert!(lo <= hi); + assert!(hi <= Self::capacity()); + + let one = T::from(1); + + // We can't just do (one << hi) - one here as the shift may overflow + let hi_rng = if hi >= 1 { + (one << (hi - 1)) + ((one << (hi - 1)) - one) + } else { + T::from(0) + }; + + let lo_rng = (one << lo) - one; + + Self(hi_rng - lo_rng) + } + + /// The maximum number of bits that can be stored in this bitset. + /// + /// If you need more bits than this, use a + /// [`CompoundBitSet`][crate::CompoundBitSet] instead of a `ScalarBitSet`. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// assert_eq!(ScalarBitSet::::capacity(), 8); + /// assert_eq!(ScalarBitSet::::capacity(), 64); + /// ``` + #[inline] + pub fn capacity() -> u8 { + u8::try_from(size_of::()).unwrap() * 8 + } + + /// Get the number of elements in this set. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// assert_eq!(bitset.len(), 0); + /// + /// bitset.insert(24); + /// bitset.insert(13); + /// bitset.insert(36); + /// + /// assert_eq!(bitset.len(), 3); + /// ``` + #[inline] + pub fn len(&self) -> u8 { + self.0.count_ones() + } + + /// Is this bitset empty? + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// assert!(bitset.is_empty()); + /// + /// bitset.insert(10); + /// + /// assert!(!bitset.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.0 == T::from(0) + } + + /// Check whether this bitset contains `i`. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// assert!(!bitset.contains(7)); + /// + /// bitset.insert(7); + /// + /// assert!(bitset.contains(7)); + /// ``` + /// + /// # Panics + /// + /// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity]. + /// + /// ```should_panic + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // A `ScalarBitSet` can only hold the elements `0..=7`, so `8` is + /// // out of bounds and will trigger a panic. + /// bitset.contains(8); + /// ``` + #[inline] + pub fn contains(&self, i: u8) -> bool { + assert!(i < Self::capacity()); + self.0 & (T::from(1) << i) != T::from(0) + } + + /// Insert `i` into this bitset. + /// + /// Returns whether the value was newly inserted. That is: + /// + /// * If the set did not previously contain `i` then `true` is returned. + /// + /// * If the set already contained `i` then `false` is returned. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // When an element is inserted that was not already present in the set, + /// // then `true` is returned. + /// let is_new = bitset.insert(7); + /// assert!(is_new); + /// + /// // The element is now present in the set. + /// assert!(bitset.contains(7)); + /// + /// // And when the element is already in the set, `false` is returned from + /// // `insert`. + /// let is_new = bitset.insert(7); + /// assert!(!is_new); + /// ``` + /// + /// # Panics + /// + /// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity]. + /// + /// ```should_panic + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // A `ScalarBitSet` can only hold the elements `0..=31`, so `42` is + /// // out of bounds and will trigger a panic. + /// bitset.insert(42); + /// ``` + #[inline] + pub fn insert(&mut self, i: u8) -> bool { + let is_new = !self.contains(i); + self.0 = self.0 | (T::from(1) << i); + is_new + } + + /// Remove `i` from this bitset. + /// + /// Returns whether `i` was previously in this set or not. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // Removing an element that was not present in the set returns `false`. + /// let was_present = bitset.remove(100); + /// assert!(!was_present); + /// + /// // And when the element was in the set, `true` is returned. + /// bitset.insert(100); + /// let was_present = bitset.remove(100); + /// assert!(was_present); + /// ``` + /// + /// # Panics + /// + /// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity]. + /// + /// ```should_panic + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // A `ScalarBitSet` can only hold the elements `0..=15`, so `20` is + /// // out of bounds and will trigger a panic. + /// bitset.remove(20); + /// ``` + #[inline] + pub fn remove(&mut self, i: u8) -> bool { + let was_present = self.contains(i); + self.0 = self.0 & !(T::from(1) << i); + was_present + } + + /// Remove all entries from this bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// bitset.insert(10); + /// bitset.insert(20); + /// bitset.insert(30); + /// + /// bitset.clear(); + /// + /// assert!(bitset.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.0 = T::from(0); + } + + /// Remove and return the smallest value in the bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// bitset.insert(0); + /// bitset.insert(24); + /// bitset.insert(13); + /// bitset.insert(36); + /// + /// assert_eq!(bitset.pop_min(), Some(0)); + /// assert_eq!(bitset.pop_min(), Some(13)); + /// assert_eq!(bitset.pop_min(), Some(24)); + /// assert_eq!(bitset.pop_min(), Some(36)); + /// assert_eq!(bitset.pop_min(), None); + /// ``` + #[inline] + pub fn pop_min(&mut self) -> Option { + let min = self.min()?; + self.remove(min); + Some(min) + } + + /// Remove and return the largest value in the bitset. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// bitset.insert(0); + /// bitset.insert(24); + /// bitset.insert(13); + /// bitset.insert(36); + /// + /// assert_eq!(bitset.pop_max(), Some(36)); + /// assert_eq!(bitset.pop_max(), Some(24)); + /// assert_eq!(bitset.pop_max(), Some(13)); + /// assert_eq!(bitset.pop_max(), Some(0)); + /// assert_eq!(bitset.pop_max(), None); + /// ``` + #[inline] + pub fn pop_max(&mut self) -> Option { + let max = self.max()?; + self.remove(max); + Some(max) + } + + /// Return the smallest number contained in this bitset or `None` if this + /// bitset is empty. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // When the bitset is empty, `min` returns `None`. + /// assert_eq!(bitset.min(), None); + /// + /// bitset.insert(28); + /// bitset.insert(1); + /// bitset.insert(63); + /// + /// // When the bitset is not empty, it returns the smallest element. + /// assert_eq!(bitset.min(), Some(1)); + /// ``` + #[inline] + pub fn min(&self) -> Option { + if self.0 == T::from(0) { + None + } else { + Some(self.0.trailing_zeros()) + } + } + + /// Return the largest number contained in the bitset or None if this bitset + /// is empty + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// // When the bitset is empty, `max` returns `None`. + /// assert_eq!(bitset.max(), None); + /// + /// bitset.insert(0); + /// bitset.insert(36); + /// bitset.insert(49); + /// + /// // When the bitset is not empty, it returns the smallest element. + /// assert_eq!(bitset.max(), Some(49)); + /// ``` + #[inline] + pub fn max(&self) -> Option { + if self.0 == T::from(0) { + None + } else { + let leading_zeroes = self.0.leading_zeros(); + Some(Self::capacity() - leading_zeroes - 1) + } + } + + /// Iterate over the items in this set. + /// + /// Items are always yielded in sorted order. + /// + /// # Example + /// + /// ``` + /// use cranelift_bitset::ScalarBitSet; + /// + /// let mut bitset = ScalarBitSet::::new(); + /// + /// bitset.insert(19); + /// bitset.insert(3); + /// bitset.insert(63); + /// bitset.insert(0); + /// + /// assert_eq!( + /// bitset.iter().collect::>(), + /// [0, 3, 19, 63], + /// ); + /// ``` + #[inline] + pub fn iter(self) -> Iter { + Iter { bitset: self } + } +} + +impl IntoIterator for ScalarBitSet +where + T: ScalarBitSetStorage, +{ + type Item = u8; + + type IntoIter = Iter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a ScalarBitSet +where + T: ScalarBitSetStorage, +{ + type Item = u8; + + type IntoIter = Iter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl From for ScalarBitSet { + fn from(bits: T) -> Self { + Self(bits) + } +} + +/// A trait implemented by all integers that can be used as the backing storage +/// for a [`ScalarBitSet`]. +/// +/// You shouldn't have to implement this yourself, it is already implemented for +/// `u{8,16,32,64,128}` and if you need more bits than that, then use +/// [`CompoundBitSet`][crate::CompoundBitSet] instead. +pub trait ScalarBitSetStorage: + Default + + From + + Shl + + Shr + + BitAnd + + BitOr + + Not + + Sub + + Add + + PartialEq + + Copy +{ + /// Count the number of leading zeros. + fn leading_zeros(self) -> u8; + + /// Count the number of trailing zeros. + fn trailing_zeros(self) -> u8; + + /// Count the number of bits set in this integer. + fn count_ones(self) -> u8; +} + +macro_rules! impl_storage { + ( $int:ty ) => { + impl ScalarBitSetStorage for $int { + #[inline] + fn leading_zeros(self) -> u8 { + u8::try_from(self.leading_zeros()).unwrap() + } + + #[inline] + fn trailing_zeros(self) -> u8 { + u8::try_from(self.trailing_zeros()).unwrap() + } + + #[inline] + fn count_ones(self) -> u8 { + u8::try_from(self.count_ones()).unwrap() + } + } + }; +} + +impl_storage!(u8); +impl_storage!(u16); +impl_storage!(u32); +impl_storage!(u64); +impl_storage!(u128); +impl_storage!(usize); + +/// An iterator over the elements in a [`ScalarBitSet`]. +pub struct Iter { + bitset: ScalarBitSet, +} + +impl Iterator for Iter +where + T: ScalarBitSetStorage, +{ + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.bitset.pop_min() + } +} + +impl DoubleEndedIterator for Iter +where + T: ScalarBitSetStorage, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.bitset.pop_max() + } +} + +impl ExactSizeIterator for Iter +where + T: ScalarBitSetStorage, +{ + #[inline] + fn len(&self) -> usize { + usize::from(self.bitset.len()) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a, T> arbitrary::Arbitrary<'a> for ScalarBitSet +where + T: ScalarBitSetStorage + arbitrary::Arbitrary<'a>, +{ + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + T::arbitrary(u).map(Self) + } +} diff --git a/deps/crates/vendor/cranelift-bitset/tests/bitset.rs b/deps/crates/vendor/cranelift-bitset/tests/bitset.rs new file mode 100644 index 00000000000000..d0f5aedd64280a --- /dev/null +++ b/deps/crates/vendor/cranelift-bitset/tests/bitset.rs @@ -0,0 +1,78 @@ +use cranelift_bitset::*; + +#[test] +fn contains() { + let s = ScalarBitSet::(255); + for i in 0..7 { + assert!(s.contains(i)); + } + + let s1 = ScalarBitSet::(0); + for i in 0..7 { + assert!(!s1.contains(i)); + } + + let s2 = ScalarBitSet::(127); + for i in 0..6 { + assert!(s2.contains(i)); + } + assert!(!s2.contains(7)); + + let s3 = ScalarBitSet::(2 | 4 | 64); + assert!(!s3.contains(0) && !s3.contains(3) && !s3.contains(4)); + assert!(!s3.contains(5) && !s3.contains(7)); + assert!(s3.contains(1) && s3.contains(2) && s3.contains(6)); + + let s4 = ScalarBitSet::(4 | 8 | 256 | 1024); + assert!( + !s4.contains(0) + && !s4.contains(1) + && !s4.contains(4) + && !s4.contains(5) + && !s4.contains(6) + && !s4.contains(7) + && !s4.contains(9) + && !s4.contains(11) + ); + assert!(s4.contains(2) && s4.contains(3) && s4.contains(8) && s4.contains(10)); +} + +#[test] +fn minmax() { + let s = ScalarBitSet::(255); + assert_eq!(s.min(), Some(0)); + assert_eq!(s.max(), Some(7)); + assert!(s.min() == Some(0) && s.max() == Some(7)); + let s1 = ScalarBitSet::(0); + assert!(s1.min() == None && s1.max() == None); + let s2 = ScalarBitSet::(127); + assert!(s2.min() == Some(0) && s2.max() == Some(6)); + let s3 = ScalarBitSet::(2 | 4 | 64); + assert!(s3.min() == Some(1) && s3.max() == Some(6)); + let s4 = ScalarBitSet::(4 | 8 | 256 | 1024); + assert!(s4.min() == Some(2) && s4.max() == Some(10)); +} + +#[test] +fn from_range() { + let s = ScalarBitSet::::from_range(5, 5); + assert!(s.0 == 0); + + let s = ScalarBitSet::::from_range(0, 8); + assert!(s.0 == 255); + + let s = ScalarBitSet::::from_range(0, 8); + assert!(s.0 == 255u16); + + let s = ScalarBitSet::::from_range(0, 16); + assert!(s.0 == 65535u16); + + let s = ScalarBitSet::::from_range(5, 6); + assert!(s.0 == 32u8); + + let s = ScalarBitSet::::from_range(3, 7); + assert!(s.0 == 8 | 16 | 32 | 64); + + let s = ScalarBitSet::::from_range(5, 11); + assert!(s.0 == 32 | 64 | 128 | 256 | 512 | 1024); +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/.cargo-checksum.json b/deps/crates/vendor/cranelift-codegen-meta/.cargo-checksum.json new file mode 100644 index 00000000000000..6143c652d591b6 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"21425b20b75f9336c04d05b54aff3e4a84e84180bd0fe0d2470b350782fa1e55","Cargo.lock":"013f473aef3993819585b44a092ff68e526bad1f5565ab847dc5bc2de5ba7b16","Cargo.toml":"e0809d1f9357a0ef6164f78d2079703b9a58de323c8992b145126bcc68dc793b","Cargo.toml.orig":"ff80394918070ad2b6af8c6a970b9beada150d2b994009f593ebb53060feac8b","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/formats.rs":"3dbbbe2b05ac1df9d88ce8cfafba5a41c485566a6ba9dc6dfcfd71b1b85e85f2","src/cdsl/instructions.rs":"d0ead1013b5fb9a119c0ec27e8b4f040bd0f070f9d0ec95c609da6f4fb5b2c43","src/cdsl/isa.rs":"fbb5848baea534584ec113fab8d13015b80b125392e86cad0c91e14f746c038c","src/cdsl/mod.rs":"7faf3c1159b05a11aba71bd791dba544423a3e765f5d016f9bb225263edb039d","src/cdsl/operands.rs":"f531120b794e9a79e24a24212ad55a999f02be41af4cea788042ba562c109ecf","src/cdsl/settings.rs":"ba021285b6797e14609c46763d3d47ed762f277a5b86e6f4907279a8fe9368cb","src/cdsl/types.rs":"8477f2a3731a2c777ecbe2b00826e95cd927c19c304c4505d24d30447c26b53e","src/cdsl/typevar.rs":"6517e3238c5e148d288cdce5b9269a7c9fdfb5db15122c474918443298193339","src/constant_hash.rs":"7f21c124e58286bf5239bba064c3f1bdd76ba95f27c2f6c82ffff1ec54f46274","src/error.rs":"0dbd1942f756b76498223d815a3ab82e3e0ab3ef2680387dd89ad5d2f41b6d56","src/gen_inst.rs":"60d3116951aefe45d34cff20e8be2320f65d6f11dd785b84de05d3af9c80e85f","src/gen_isle.rs":"55805cb52e46e2d131c527c9b340a794508dbdc8c25d2cae3889ccf00b5da60c","src/gen_settings.rs":"11bb543d52bf97c07101ace74939b3ebb4b3107106922f575f531898ab8e15e4","src/gen_types.rs":"91b5f3574975758f713c4963467d1d4a8bd70986aebde57ee35dcbe6ebc9b302","src/isa/arm64.rs":"5142712e4f6c7fdb3c68295cb1d29c9784bc270edf610fd2075ee747eef5004f","src/isa/mod.rs":"c618456a675f2ba29c8b5c91d136eb4b18dbecab567d35b4d236f798c50637ad","src/isa/pulley.rs":"a8460cb4345b6cbe5089f014510e34338f9a9613e62a97dd2d293a3ed0893210","src/isa/riscv64.rs":"0139e7ddebd39d3bb9a91a0d2f922dc7d6c5ff6be4aa65decd53f1a251592ba5","src/isa/s390x.rs":"54ed76179d0696d6244720666685336b90e318be848dc32217ccc16a28a40490","src/isa/x86.rs":"07b670111565c15432b08698b05580025fc2634f7d67146a5dbd0cee5ab3c766","src/isle.rs":"9cbc9987d6791721238b71b2859e37ad2dd0c34db906544247d52cea60bed20c","src/lib.rs":"26334518b82ee417f178bf49acf29611a57fdc7cd8b027a6f1930cef47c38a89","src/pulley.rs":"a1c9320dfe0dbff19635131534988cdd8bce370032525fe49af63ca8d97f51cd","src/shared/entities.rs":"b93ccbec3531fe3ad002eeb400214f84439b46c64f4c1b6e06f641fbffed334c","src/shared/formats.rs":"48457f8aee7ff0ff14454d4ce51ab16104e0b64a8b71cba14fed0b23f2cb715a","src/shared/immediates.rs":"d98aeefd50ee80da66ff661313c79d4bfabb34b352d747f527d0b6f77db3d4a5","src/shared/instructions.rs":"0b9f4adbd7a2a3cc5496b7616e8d332a43a2b4488e19bc1187da64e5e42f6197","src/shared/mod.rs":"9bcbec640951baa85b2db0c69d4f4e65d4d4ffb49c75d5f34c01c6520030ec80","src/shared/settings.rs":"206c905e7b4b03a198c968ddaa3a0446d463d68d65385bbee7d9ea26554a93e9","src/shared/types.rs":"796326a9b00368c8d7dd0b49ac1e30d2d71c78d8444a3265b4a7ca68c50322bc","src/srcgen.rs":"6daf723b9c8183bec8460b57394386edb153b01705ac19a6a23fec4e427e7189","src/unique_table.rs":"d804720d23d3db4cc8630fd3975dbde13dcd111137e98513c950ad3618ce1168"},"package":"c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen-meta/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-codegen-meta/.cargo_vcs_info.json new file mode 100644 index 00000000000000..266179bac89b33 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/codegen/meta" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen-meta/Cargo.lock b/deps/crates/vendor/cranelift-codegen-meta/Cargo.lock new file mode 100644 index 00000000000000..67273b9a38f9fb --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +dependencies = [ + "cranelift-codegen-shared", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "pulley-interpreter" +version = "29.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d95f8575df49a2708398182f49a888cf9dc30210fb1fd2df87c889edcee75d" +dependencies = [ + "cranelift-bitset", + "log", + "sptr", +] + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" diff --git a/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml b/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml new file mode 100644 index 00000000000000..4841a5941be522 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml @@ -0,0 +1,75 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-codegen-meta" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Metaprogram for cranelift-codegen code generator library" +readme = "README.md" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[package.metadata.docs.rs] +rustdoc-args = ["--document-private-items"] + +[lib] +name = "cranelift_codegen_meta" +path = "src/lib.rs" + +[dependencies.cranelift-codegen-shared] +version = "0.116.1" + +[dependencies.pulley-interpreter] +version = "=29.0.1" +optional = true + +[features] +pulley = ["dep:pulley-interpreter"] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml.orig b/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml.orig new file mode 100644 index 00000000000000..80a60e0b1863cc --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/Cargo.toml.orig @@ -0,0 +1,23 @@ +[package] +name = "cranelift-codegen-meta" +authors = ["The Cranelift Project Developers"] +version = "0.116.1" +description = "Metaprogram for cranelift-codegen code generator library" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[package.metadata.docs.rs] +rustdoc-args = [ "--document-private-items" ] + +[dependencies] +cranelift-codegen-shared = { path = "../shared", version = "0.116.1" } +pulley-interpreter = { workspace = true, optional = true } + +[features] +pulley = ['dep:pulley-interpreter'] diff --git a/deps/crates/vendor/cranelift-codegen-meta/LICENSE b/deps/crates/vendor/cranelift-codegen-meta/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-codegen-meta/README.md b/deps/crates/vendor/cranelift-codegen-meta/README.md new file mode 100644 index 00000000000000..c0c8648b298a17 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/README.md @@ -0,0 +1,2 @@ +This crate contains the metaprogram used by cranelift-codegen. It's not +useful on its own. diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/formats.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/formats.rs new file mode 100644 index 00000000000000..10d804a98aa34a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/formats.rs @@ -0,0 +1,144 @@ +use crate::cdsl::operands::OperandKind; +use std::fmt; +use std::rc::Rc; + +/// An immediate field in an instruction format. +/// +/// This corresponds to a single member of a variant of the `InstructionData` +/// data type. +#[derive(Debug)] +pub(crate) struct FormatField { + /// Immediate operand kind. + pub kind: OperandKind, + + /// Member name in InstructionData variant. + pub member: &'static str, +} + +/// Every instruction opcode has a corresponding instruction format which determines the number of +/// operands and their kinds. Instruction formats are identified structurally, i.e., the format of +/// an instruction is derived from the kinds of operands used in its declaration. +/// +/// The instruction format stores two separate lists of operands: Immediates and values. Immediate +/// operands (including entity references) are represented as explicit members in the +/// `InstructionData` variants. The value operands are stored differently, depending on how many +/// there are. Beyond a certain point, instruction formats switch to an external value list for +/// storing value arguments. Value lists can hold an arbitrary number of values. +/// +/// All instruction formats must be predefined in the meta shared/formats.rs module. +#[derive(Debug)] +pub(crate) struct InstructionFormat { + /// Instruction format name in CamelCase. This is used as a Rust variant name in both the + /// `InstructionData` and `InstructionFormat` enums. + pub name: &'static str, + + pub num_value_operands: usize, + + pub has_value_list: bool, + + pub imm_fields: Vec, + + pub num_block_operands: usize, + + /// Index of the value input operand that is used to infer the controlling type variable. By + /// default, this is `0`, the first `value` operand. The index is relative to the values only, + /// ignoring immediate operands. + pub typevar_operand: Option, +} + +/// A tuple serving as a key to deduplicate InstructionFormat. +#[derive(Hash, PartialEq, Eq)] +pub(crate) struct FormatStructure { + pub num_value_operands: usize, + pub has_value_list: bool, + pub num_block_operands: usize, + /// Tuples of (Rust field name / Rust type) for each immediate field. + pub imm_field_names: Vec<(&'static str, &'static str)>, +} + +impl fmt::Display for InstructionFormat { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let imm_args = self + .imm_fields + .iter() + .map(|field| format!("{}: {}", field.member, field.kind.rust_type)) + .collect::>() + .join(", "); + fmt.write_fmt(format_args!( + "{}(imms=({}), vals={}, blocks={})", + self.name, imm_args, self.num_value_operands, self.num_block_operands, + ))?; + Ok(()) + } +} + +impl InstructionFormat { + /// Returns a tuple that uniquely identifies the structure. + pub fn structure(&self) -> FormatStructure { + FormatStructure { + num_value_operands: self.num_value_operands, + has_value_list: self.has_value_list, + num_block_operands: self.num_block_operands, + imm_field_names: self + .imm_fields + .iter() + .map(|field| (field.kind.rust_field_name, field.kind.rust_type)) + .collect::>(), + } + } +} + +pub(crate) struct InstructionFormatBuilder(InstructionFormat); + +impl InstructionFormatBuilder { + pub fn new(name: &'static str) -> Self { + Self(InstructionFormat { + name, + num_value_operands: 0, + has_value_list: false, + num_block_operands: 0, + imm_fields: Vec::new(), + typevar_operand: None, + }) + } + + pub fn value(mut self) -> Self { + self.0.num_value_operands += 1; + self + } + + pub fn varargs(mut self) -> Self { + self.0.has_value_list = true; + self + } + + pub fn block(mut self) -> Self { + self.0.num_block_operands += 1; + self + } + + pub fn imm(mut self, operand_kind: &OperandKind) -> Self { + let field = FormatField { + kind: operand_kind.clone(), + member: operand_kind.rust_field_name, + }; + self.0.imm_fields.push(field); + self + } + + pub fn typevar_operand(mut self, operand_index: usize) -> Self { + assert!(self.0.typevar_operand.is_none()); + assert!(operand_index < self.0.num_value_operands); + self.0.typevar_operand = Some(operand_index); + self + } + + pub fn build(mut self) -> Rc { + if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 { + // Default to the first value operand, if there's one. + self.0.typevar_operand = Some(0); + }; + + Rc::new(self.0) + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/instructions.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/instructions.rs new file mode 100644 index 00000000000000..b944255149fc12 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/instructions.rs @@ -0,0 +1,494 @@ +use std::fmt; +use std::rc::Rc; + +use crate::cdsl::camel_case; +use crate::cdsl::formats::InstructionFormat; +use crate::cdsl::operands::Operand; +use crate::cdsl::typevar::TypeVar; + +pub(crate) type AllInstructions = Vec; + +pub(crate) struct InstructionGroupBuilder<'all_inst> { + all_instructions: &'all_inst mut AllInstructions, +} + +impl<'all_inst> InstructionGroupBuilder<'all_inst> { + pub fn new(all_instructions: &'all_inst mut AllInstructions) -> Self { + Self { all_instructions } + } + + pub fn push(&mut self, builder: InstructionBuilder) { + let inst = builder.build(); + self.all_instructions.push(inst); + } +} + +#[derive(Debug)] +pub(crate) struct PolymorphicInfo { + pub use_typevar_operand: bool, + pub ctrl_typevar: TypeVar, +} + +#[derive(Debug)] +pub(crate) struct InstructionContent { + /// Instruction mnemonic, also becomes opcode name. + pub name: String, + pub camel_name: String, + + /// Documentation string. + pub doc: String, + + /// Input operands. This can be a mix of SSA value operands and other operand kinds. + pub operands_in: Vec, + /// Output operands. The output operands must be SSA values or `variable_args`. + pub operands_out: Vec, + + /// Instruction format. + pub format: Rc, + + /// One of the input or output operands is a free type variable. None if the instruction is not + /// polymorphic, set otherwise. + pub polymorphic_info: Option, + + /// Indices in operands_in of input operands that are values. + pub value_opnums: Vec, + /// Indices in operands_in of input operands that are immediates or entities. + pub imm_opnums: Vec, + /// Indices in operands_out of output operands that are values. + pub value_results: Vec, + + /// True for instructions that terminate the block. + pub is_terminator: bool, + /// True for all branch or jump instructions. + pub is_branch: bool, + /// Is this a call instruction? + pub is_call: bool, + /// Is this a return instruction? + pub is_return: bool, + /// Can this instruction read from memory? + pub can_load: bool, + /// Can this instruction write to memory? + pub can_store: bool, + /// Can this instruction cause a trap? + pub can_trap: bool, + /// Does this instruction have other side effects besides can_* flags? + pub other_side_effects: bool, + /// Despite having other side effects, is this instruction okay to GVN? + pub side_effects_idempotent: bool, +} + +impl InstructionContent { + pub fn snake_name(&self) -> &str { + if &self.name == "return" { + "return_" + } else { + &self.name + } + } +} + +pub(crate) type Instruction = Rc; + +impl fmt::Display for InstructionContent { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + if !self.operands_out.is_empty() { + let operands_out = self + .operands_out + .iter() + .map(|op| op.name) + .collect::>() + .join(", "); + fmt.write_str(&operands_out)?; + fmt.write_str(" = ")?; + } + + fmt.write_str(&self.name)?; + + if !self.operands_in.is_empty() { + let operands_in = self + .operands_in + .iter() + .map(|op| op.name) + .collect::>() + .join(", "); + fmt.write_str(" ")?; + fmt.write_str(&operands_in)?; + } + + Ok(()) + } +} + +pub(crate) struct InstructionBuilder { + name: String, + doc: String, + format: Rc, + operands_in: Option>, + operands_out: Option>, + + // See Instruction comments for the meaning of these fields. + is_terminator: bool, + is_branch: bool, + is_call: bool, + is_return: bool, + can_load: bool, + can_store: bool, + can_trap: bool, + other_side_effects: bool, + side_effects_idempotent: bool, +} + +impl InstructionBuilder { + pub fn new>(name: S, doc: S, format: &Rc) -> Self { + Self { + name: name.into(), + doc: doc.into(), + format: format.clone(), + operands_in: None, + operands_out: None, + + is_terminator: false, + is_branch: false, + is_call: false, + is_return: false, + can_load: false, + can_store: false, + can_trap: false, + other_side_effects: false, + side_effects_idempotent: false, + } + } + + pub fn operands_in(mut self, operands: Vec) -> Self { + assert!(self.operands_in.is_none()); + self.operands_in = Some(operands); + self + } + + pub fn operands_out(mut self, operands: Vec) -> Self { + assert!(self.operands_out.is_none()); + self.operands_out = Some(operands); + self + } + + /// Mark this instruction as a block terminator. + pub fn terminates_block(mut self) -> Self { + self.is_terminator = true; + self + } + + /// Mark this instruction as a branch instruction. This also implies that the instruction is a + /// block terminator. + pub fn branches(mut self) -> Self { + self.is_branch = true; + self.terminates_block() + } + + /// Mark this instruction as a call instruction. + pub fn call(mut self) -> Self { + self.is_call = true; + self + } + + /// Mark this instruction as a return instruction. This also implies that the instruction is a + /// block terminator. + pub fn returns(mut self) -> Self { + self.is_return = true; + self.terminates_block() + } + + /// Mark this instruction as one that can load from memory. + pub fn can_load(mut self) -> Self { + self.can_load = true; + self + } + + /// Mark this instruction as one that can store to memory. + pub fn can_store(mut self) -> Self { + self.can_store = true; + self + } + + /// Mark this instruction as possibly trapping. + pub fn can_trap(mut self) -> Self { + self.can_trap = true; + self + } + + /// Mark this instruction as one that has side-effects. + pub fn other_side_effects(mut self) -> Self { + self.other_side_effects = true; + self + } + + /// Mark this instruction as one whose side-effects may be de-duplicated. + pub fn side_effects_idempotent(mut self) -> Self { + self.side_effects_idempotent = true; + self + } + + fn build(self) -> Instruction { + let operands_in = self.operands_in.unwrap_or_default(); + let operands_out = self.operands_out.unwrap_or_default(); + + let mut value_opnums = Vec::new(); + let mut imm_opnums = Vec::new(); + for (i, op) in operands_in.iter().enumerate() { + if op.is_value() { + value_opnums.push(i); + } else if op.is_immediate_or_entityref() { + imm_opnums.push(i); + } else { + assert!(op.is_varargs()); + } + } + + let value_results = operands_out + .iter() + .enumerate() + .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None }) + .collect(); + + verify_format(&self.name, &operands_in, &self.format); + + let polymorphic_info = + verify_polymorphic(&operands_in, &operands_out, &self.format, &value_opnums); + + let camel_name = camel_case(&self.name); + + Rc::new(InstructionContent { + name: self.name, + camel_name, + doc: self.doc, + operands_in, + operands_out, + format: self.format, + polymorphic_info, + value_opnums, + value_results, + imm_opnums, + is_terminator: self.is_terminator, + is_branch: self.is_branch, + is_call: self.is_call, + is_return: self.is_return, + can_load: self.can_load, + can_store: self.can_store, + can_trap: self.can_trap, + other_side_effects: self.other_side_effects, + side_effects_idempotent: self.side_effects_idempotent, + }) + } +} + +/// Checks that the input operands actually match the given format. +fn verify_format(inst_name: &str, operands_in: &[Operand], format: &InstructionFormat) { + // A format is defined by: + // - its number of input value operands, + // - its number and names of input immediate operands, + // - whether it has a value list or not. + let mut num_values = 0; + let mut num_blocks = 0; + let mut num_immediates = 0; + + for operand in operands_in.iter() { + if operand.is_varargs() { + assert!( + format.has_value_list, + "instruction {} has varargs, but its format {} doesn't have a value list; you may \ + need to use a different format.", + inst_name, format.name + ); + } + if operand.is_value() { + num_values += 1; + } + if operand.kind.is_block() { + num_blocks += 1; + } else if operand.is_immediate_or_entityref() { + if let Some(format_field) = format.imm_fields.get(num_immediates) { + assert_eq!( + format_field.kind.rust_field_name, + operand.kind.rust_field_name, + "{}th operand of {} should be {} (according to format), not {} (according to \ + inst definition). You may need to use a different format.", + num_immediates, + inst_name, + format_field.kind.rust_field_name, + operand.kind.rust_field_name + ); + num_immediates += 1; + } + } + } + + assert_eq!( + num_values, format.num_value_operands, + "inst {} doesn't have as many value input operands as its format {} declares; you may need \ + to use a different format.", + inst_name, format.name + ); + + assert_eq!( + num_blocks, format.num_block_operands, + "inst {} doesn't have as many block input operands as its format {} declares; you may need \ + to use a different format.", + inst_name, format.name, + ); + + assert_eq!( + num_immediates, + format.imm_fields.len(), + "inst {} doesn't have as many immediate input \ + operands as its format {} declares; you may need to use a different format.", + inst_name, + format.name + ); +} + +/// Check if this instruction is polymorphic, and verify its use of type variables. +fn verify_polymorphic( + operands_in: &[Operand], + operands_out: &[Operand], + format: &InstructionFormat, + value_opnums: &[usize], +) -> Option { + // The instruction is polymorphic if it has one free input or output operand. + let is_polymorphic = operands_in + .iter() + .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()) + || operands_out + .iter() + .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()); + + if !is_polymorphic { + return None; + } + + // Verify the use of type variables. + let tv_op = format.typevar_operand; + let mut maybe_error_message = None; + if let Some(tv_op) = tv_op { + if tv_op < value_opnums.len() { + let op_num = value_opnums[tv_op]; + let tv = operands_in[op_num].type_var().unwrap(); + let free_typevar = tv.free_typevar(); + if (free_typevar.is_some() && tv == &free_typevar.unwrap()) + || tv.singleton_type().is_some() + { + match is_ctrl_typevar_candidate(tv, operands_in, operands_out) { + Ok(_other_typevars) => { + return Some(PolymorphicInfo { + use_typevar_operand: true, + ctrl_typevar: tv.clone(), + }); + } + Err(error_message) => { + maybe_error_message = Some(error_message); + } + } + } + } + }; + + // If we reached here, it means the type variable indicated as the typevar operand couldn't + // control every other input and output type variable. We need to look at the result type + // variables. + if operands_out.is_empty() { + // No result means no other possible type variable, so it's a type inference failure. + match maybe_error_message { + Some(msg) => panic!("{}", msg), + None => panic!("typevar_operand must be a free type variable"), + } + } + + // Otherwise, try to infer the controlling type variable by looking at the first result. + let tv = operands_out[0].type_var().unwrap(); + let free_typevar = tv.free_typevar(); + if free_typevar.is_some() && tv != &free_typevar.unwrap() { + panic!("first result must be a free type variable"); + } + + // At this point, if the next unwrap() fails, it means the output type couldn't be used as a + // controlling type variable either; panicking is the right behavior. + is_ctrl_typevar_candidate(tv, operands_in, operands_out).unwrap(); + + Some(PolymorphicInfo { + use_typevar_operand: false, + ctrl_typevar: tv.clone(), + }) +} + +/// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type +/// variable. +/// +/// All polymorphic inputs must either be derived from `ctrl_typevar` or be independent free type +/// variables only used once. +/// +/// All polymorphic results must be derived from `ctrl_typevar`. +/// +/// Return a vector of other type variables used, or a string explaining what went wrong. +fn is_ctrl_typevar_candidate( + ctrl_typevar: &TypeVar, + operands_in: &[Operand], + operands_out: &[Operand], +) -> Result, String> { + let mut other_typevars = Vec::new(); + + // Check value inputs. + for input in operands_in { + if !input.is_value() { + continue; + } + + let typ = input.type_var().unwrap(); + let free_typevar = typ.free_typevar(); + + // Non-polymorphic or derived from ctrl_typevar is OK. + if free_typevar.is_none() { + continue; + } + let free_typevar = free_typevar.unwrap(); + if &free_typevar == ctrl_typevar { + continue; + } + + // No other derived typevars allowed. + if typ != &free_typevar { + return Err(format!( + "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}", + input, typ.name, ctrl_typevar, free_typevar + )); + } + + // Other free type variables can only be used once each. + for other_tv in &other_typevars { + if &free_typevar == other_tv { + return Err(format!( + "non-controlling type variable {} can't be used more than once", + free_typevar.name + )); + } + } + + other_typevars.push(free_typevar); + } + + // Check outputs. + for result in operands_out { + if !result.is_value() { + continue; + } + + let typ = result.type_var().unwrap(); + let free_typevar = typ.free_typevar(); + + // Non-polymorphic or derived from ctrl_typevar is OK. + if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar { + continue; + } + + return Err("type variable in output not derived from ctrl_typevar".into()); + } + + Ok(other_typevars) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/isa.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/isa.rs new file mode 100644 index 00000000000000..b595ffa99f08a4 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/isa.rs @@ -0,0 +1,12 @@ +use crate::cdsl::settings::SettingGroup; + +pub(crate) struct TargetIsa { + pub name: &'static str, + pub settings: SettingGroup, +} + +impl TargetIsa { + pub fn new(name: &'static str, settings: SettingGroup) -> Self { + Self { name, settings } + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/mod.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/mod.rs new file mode 100644 index 00000000000000..4bde7d3e4a1a0c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/mod.rs @@ -0,0 +1,72 @@ +//! Cranelift DSL classes. +//! +//! This module defines the classes that are used to define Cranelift +//! instructions and other entities. + +pub mod formats; +pub mod instructions; +pub mod isa; +pub mod operands; +pub mod settings; +pub mod types; +pub mod typevar; + +/// A macro that converts boolean settings into predicates to look more natural. +#[macro_export] +macro_rules! predicate { + ($a:ident && $($b:tt)*) => { + PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*))) + }; + ($a:ident) => { + $a.into() + }; +} + +/// A macro that joins boolean settings into a list (e.g. `preset!(feature_a && feature_b)`). +#[macro_export] +macro_rules! preset { + () => { + vec![] + }; + ($($x:tt)&&*) => { + { + let mut v = Vec::new(); + $( + v.push($x.into()); + )* + v + } + }; +} + +/// Convert the string `s` to CamelCase. +pub fn camel_case(s: &str) -> String { + let mut output_chars = String::with_capacity(s.len()); + + let mut capitalize = true; + for curr_char in s.chars() { + if curr_char == '_' { + capitalize = true; + } else { + if capitalize { + output_chars.extend(curr_char.to_uppercase()); + } else { + output_chars.push(curr_char); + } + capitalize = false; + } + } + + output_chars +} + +#[cfg(test)] +mod tests { + use super::camel_case; + + #[test] + fn camel_case_works() { + assert_eq!(camel_case("x"), "X"); + assert_eq!(camel_case("camel_case"), "CamelCase"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/operands.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/operands.rs new file mode 100644 index 00000000000000..f2ec8f9d479c5b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/operands.rs @@ -0,0 +1,169 @@ +use std::collections::HashMap; + +use crate::cdsl::typevar::TypeVar; + +/// An instruction operand can be an *immediate*, an *SSA value*, or an *entity reference*. The +/// type of the operand is one of: +/// +/// 1. A `ValueType` instance indicates an SSA value operand with a concrete type. +/// +/// 2. A `TypeVar` instance indicates an SSA value operand, and the instruction is polymorphic over +/// the possible concrete types that the type variable can assume. +/// +/// 3. An `ImmediateKind` instance indicates an immediate operand whose value is encoded in the +/// instruction itself rather than being passed as an SSA value. +/// +/// 4. An `EntityRefKind` instance indicates an operand that references another entity in the +/// function, typically something declared in the function preamble. +#[derive(Clone, Debug)] +pub(crate) struct Operand { + /// Name of the operand variable, as it appears in function parameters, legalizations, etc. + pub name: &'static str, + + /// Type of the operand. + pub kind: OperandKind, + + doc: Option<&'static str>, +} + +impl Operand { + pub fn new(name: &'static str, kind: impl Into) -> Self { + Self { + name, + doc: None, + kind: kind.into(), + } + } + pub fn with_doc(mut self, doc: &'static str) -> Self { + self.doc = Some(doc); + self + } + + pub fn doc(&self) -> &str { + if let Some(doc) = &self.doc { + return doc; + } + match &self.kind.fields { + OperandKindFields::TypeVar(tvar) => &tvar.doc, + _ => self.kind.doc(), + } + } + + pub fn is_value(&self) -> bool { + matches!(self.kind.fields, OperandKindFields::TypeVar(_)) + } + + pub fn type_var(&self) -> Option<&TypeVar> { + match &self.kind.fields { + OperandKindFields::TypeVar(typevar) => Some(typevar), + _ => None, + } + } + + pub fn is_varargs(&self) -> bool { + matches!(self.kind.fields, OperandKindFields::VariableArgs) + } + + /// Returns true if the operand has an immediate kind or is an EntityRef. + pub fn is_immediate_or_entityref(&self) -> bool { + matches!( + self.kind.fields, + OperandKindFields::ImmEnum(_) + | OperandKindFields::ImmValue + | OperandKindFields::EntityRef + ) + } + + /// Returns true if the operand has an immediate kind. + pub fn is_immediate(&self) -> bool { + matches!( + self.kind.fields, + OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue + ) + } +} + +pub type EnumValues = HashMap<&'static str, &'static str>; + +#[derive(Clone, Debug)] +pub(crate) enum OperandKindFields { + EntityRef, + VariableArgs, + ImmValue, + ImmEnum(EnumValues), + TypeVar(TypeVar), +} + +impl OperandKindFields { + /// Return the [EnumValues] for this field if it is an `enum`. + pub(crate) fn enum_values(&self) -> Option<&EnumValues> { + match self { + OperandKindFields::ImmEnum(map) => Some(map), + _ => None, + } + } +} + +#[derive(Clone, Debug)] +pub(crate) struct OperandKind { + /// String representation of the Rust type mapping to this OperandKind. + pub rust_type: &'static str, + + /// Name of this OperandKind in the format's member field. + pub rust_field_name: &'static str, + + /// Type-specific fields for this OperandKind. + pub fields: OperandKindFields, + + doc: Option<&'static str>, +} + +impl OperandKind { + pub fn new( + rust_field_name: &'static str, + rust_type: &'static str, + fields: OperandKindFields, + doc: &'static str, + ) -> Self { + Self { + rust_field_name, + rust_type, + fields, + doc: Some(doc), + } + } + fn doc(&self) -> &str { + if let Some(doc) = &self.doc { + return doc; + } + match &self.fields { + OperandKindFields::TypeVar(type_var) => &type_var.doc, + // The only method to create an OperandKind with `doc` set to None is using a TypeVar, + // so all other options are unreachable here. + OperandKindFields::ImmEnum(_) + | OperandKindFields::ImmValue + | OperandKindFields::EntityRef + | OperandKindFields::VariableArgs => unreachable!(), + } + } + + pub(crate) fn is_block(&self) -> bool { + self.rust_type == "ir::BlockCall" + } +} + +impl From<&TypeVar> for OperandKind { + fn from(type_var: &TypeVar) -> Self { + OperandKind { + rust_field_name: "value", + rust_type: "ir::Value", + fields: OperandKindFields::TypeVar(type_var.into()), + doc: None, + } + } +} +impl From<&OperandKind> for OperandKind { + fn from(kind: &OperandKind) -> Self { + kind.clone() + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/settings.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/settings.rs new file mode 100644 index 00000000000000..6ed68d24a2aa40 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/settings.rs @@ -0,0 +1,429 @@ +use std::iter; + +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +pub(crate) struct BoolSettingIndex(usize); + +#[derive(Hash, PartialEq, Eq)] +pub(crate) struct BoolSetting { + pub default: bool, + pub bit_offset: u8, + pub predicate_number: u8, +} + +#[derive(Hash, PartialEq, Eq)] +pub(crate) enum SpecificSetting { + Bool(BoolSetting), + Enum(Vec<&'static str>), + Num(u8), +} + +#[derive(Hash, PartialEq, Eq)] +pub(crate) struct Setting { + pub name: &'static str, + pub description: &'static str, + pub comment: &'static str, + pub specific: SpecificSetting, + pub byte_offset: u8, +} + +impl Setting { + pub fn default_byte(&self) -> u8 { + match self.specific { + SpecificSetting::Bool(BoolSetting { + default, + bit_offset, + .. + }) => { + if default { + 1 << bit_offset + } else { + 0 + } + } + SpecificSetting::Enum(_) => 0, + SpecificSetting::Num(default) => default, + } + } + + fn byte_for_value(&self, v: bool) -> u8 { + match self.specific { + SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => { + if v { + 1 << bit_offset + } else { + 0 + } + } + _ => panic!("byte_for_value shouldn't be used for non-boolean settings."), + } + } + + fn byte_mask(&self) -> u8 { + match self.specific { + SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset, + _ => panic!("byte_for_value shouldn't be used for non-boolean settings."), + } + } +} + +#[derive(Hash, PartialEq, Eq, Copy, Clone)] +pub(crate) struct PresetIndex(usize); + +#[derive(Hash, PartialEq, Eq)] +pub(crate) enum PresetType { + BoolSetting(BoolSettingIndex), + OtherPreset(PresetIndex), +} + +impl From for PresetType { + fn from(bool_setting_index: BoolSettingIndex) -> Self { + PresetType::BoolSetting(bool_setting_index) + } +} +impl From for PresetType { + fn from(value: PresetIndex) -> Self { + PresetType::OtherPreset(value) + } +} + +#[derive(Hash, PartialEq, Eq)] +pub(crate) struct Preset { + pub name: &'static str, + pub description: &'static str, + values: Vec, +} + +impl Preset { + pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> { + let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0)) + .take(group.settings_size as usize) + .collect(); + for bool_index in &self.values { + let setting = &group.settings[bool_index.0]; + let mask = setting.byte_mask(); + let val = setting.byte_for_value(true); + assert!((val & !mask) == 0); + let (ref mut l_mask, ref mut l_val) = + *layout.get_mut(setting.byte_offset as usize).unwrap(); + *l_mask |= mask; + *l_val = (*l_val & !mask) | val; + } + layout + } + + pub fn setting_names<'a>( + &'a self, + group: &'a SettingGroup, + ) -> impl Iterator + 'a { + self.values + .iter() + .map(|bool_index| group.settings[bool_index.0].name) + } +} + +pub(crate) struct SettingGroup { + pub name: &'static str, + pub settings: Vec, + pub bool_start_byte_offset: u8, + pub settings_size: u8, + pub presets: Vec, + pub predicates: Vec, +} + +impl SettingGroup { + fn num_bool_settings(&self) -> u8 { + self.settings + .iter() + .filter(|s| matches!(s.specific, SpecificSetting::Bool(_))) + .count() as u8 + } + + pub fn byte_size(&self) -> u8 { + let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8); + self.bool_start_byte_offset + (num_predicates + 7) / 8 + } +} + +/// This is the basic information needed to track the specific parts of a setting when building +/// them. +pub(crate) enum ProtoSpecificSetting { + Bool(bool), + Enum(Vec<&'static str>), + Num(u8), +} + +/// This is the information provided during building for a setting. +struct ProtoSetting { + name: &'static str, + description: &'static str, + comment: &'static str, + specific: ProtoSpecificSetting, +} + +#[derive(Hash, PartialEq, Eq)] +pub(crate) enum PredicateNode { + OwnedBool(BoolSettingIndex), + SharedBool(&'static str, &'static str), + And(Box, Box), +} + +impl From for PredicateNode { + fn from(bool_setting_index: BoolSettingIndex) -> Self { + PredicateNode::OwnedBool(bool_setting_index) + } +} + +impl<'a> From<(BoolSettingIndex, &'a SettingGroup)> for PredicateNode { + fn from(val: (BoolSettingIndex, &'a SettingGroup)) -> Self { + let (index, group) = (val.0, val.1); + let setting = &group.settings[index.0]; + PredicateNode::SharedBool(group.name, setting.name) + } +} + +impl PredicateNode { + fn render(&self, group: &SettingGroup) -> String { + match *self { + PredicateNode::OwnedBool(bool_setting_index) => format!( + "{}.{}()", + group.name, group.settings[bool_setting_index.0].name + ), + PredicateNode::SharedBool(ref group_name, ref bool_name) => { + format!("{group_name}.{bool_name}()") + } + PredicateNode::And(ref lhs, ref rhs) => { + format!("{} && {}", lhs.render(group), rhs.render(group)) + } + } + } +} + +struct ProtoPredicate { + pub name: &'static str, + node: PredicateNode, +} + +pub(crate) type SettingPredicateNumber = u8; + +pub(crate) struct Predicate { + pub name: &'static str, + node: PredicateNode, + pub number: SettingPredicateNumber, +} + +impl Predicate { + pub fn render(&self, group: &SettingGroup) -> String { + self.node.render(group) + } +} + +pub(crate) struct SettingGroupBuilder { + name: &'static str, + settings: Vec, + presets: Vec, + predicates: Vec, +} + +impl SettingGroupBuilder { + pub fn new(name: &'static str) -> Self { + Self { + name, + settings: Vec::new(), + presets: Vec::new(), + predicates: Vec::new(), + } + } + + fn add_setting( + &mut self, + name: &'static str, + description: &'static str, + comment: &'static str, + specific: ProtoSpecificSetting, + ) { + self.settings.push(ProtoSetting { + name, + description, + comment, + specific, + }) + } + + pub fn add_bool( + &mut self, + name: &'static str, + description: &'static str, + comment: &'static str, + default: bool, + ) -> BoolSettingIndex { + assert!( + self.predicates.is_empty(), + "predicates must be added after the boolean settings" + ); + self.add_setting( + name, + description, + comment, + ProtoSpecificSetting::Bool(default), + ); + BoolSettingIndex(self.settings.len() - 1) + } + + pub fn add_enum( + &mut self, + name: &'static str, + description: &'static str, + comment: &'static str, + values: Vec<&'static str>, + ) { + self.add_setting( + name, + description, + comment, + ProtoSpecificSetting::Enum(values), + ); + } + + pub fn add_num( + &mut self, + name: &'static str, + description: &'static str, + comment: &'static str, + default: u8, + ) { + self.add_setting( + name, + description, + comment, + ProtoSpecificSetting::Num(default), + ); + } + + pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) { + self.predicates.push(ProtoPredicate { name, node }); + } + + pub fn add_preset( + &mut self, + name: &'static str, + description: &'static str, + args: Vec, + ) -> PresetIndex { + let mut values = Vec::new(); + for arg in args { + match arg { + PresetType::OtherPreset(index) => { + values.extend(self.presets[index.0].values.iter()); + } + PresetType::BoolSetting(index) => values.push(index), + } + } + self.presets.push(Preset { + name, + description, + values, + }); + PresetIndex(self.presets.len() - 1) + } + + /// Compute the layout of the byte vector used to represent this settings + /// group. + /// + /// The byte vector contains the following entries in order: + /// + /// 1. Byte-sized settings like `NumSetting` and `EnumSetting`. + /// 2. `BoolSetting` settings. + /// 3. Precomputed named predicates. + /// 4. Other numbered predicates, including parent predicates that need to be accessible by + /// number. + /// + /// Set `self.settings_size` to the length of the byte vector prefix that + /// contains the settings. All bytes after that are computed, not + /// configured. + /// + /// Set `self.boolean_offset` to the beginning of the numbered predicates, + /// 2. in the list above. + /// + /// Assign `byte_offset` and `bit_offset` fields in all settings. + pub fn build(self) -> SettingGroup { + let mut group = SettingGroup { + name: self.name, + settings: Vec::new(), + bool_start_byte_offset: 0, + settings_size: 0, + presets: Vec::new(), + predicates: Vec::new(), + }; + + let mut byte_offset = 0; + + // Assign the non-boolean settings first. + for s in &self.settings { + let specific = match s.specific { + ProtoSpecificSetting::Bool(..) => continue, + ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()), + ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default), + }; + + group.settings.push(Setting { + name: s.name, + description: s.description, + comment: s.comment, + byte_offset, + specific, + }); + + byte_offset += 1; + } + + group.bool_start_byte_offset = byte_offset; + + let mut predicate_number = 0; + + // Then the boolean settings. + for s in &self.settings { + let default = match s.specific { + ProtoSpecificSetting::Bool(default) => default, + ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue, + }; + group.settings.push(Setting { + name: s.name, + description: s.description, + comment: s.comment, + byte_offset: byte_offset + predicate_number / 8, + specific: SpecificSetting::Bool(BoolSetting { + default, + bit_offset: predicate_number % 8, + predicate_number, + }), + }); + predicate_number += 1; + } + + assert!( + group.predicates.is_empty(), + "settings_size is the byte size before adding predicates" + ); + group.settings_size = group.byte_size(); + + // Sort predicates by name to ensure the same order as the Python code. + let mut predicates = self.predicates; + predicates.sort_by_key(|predicate| predicate.name); + + group + .predicates + .extend(predicates.into_iter().map(|predicate| { + let number = predicate_number; + predicate_number += 1; + Predicate { + name: predicate.name, + node: predicate.node, + number, + } + })); + + group.presets.extend(self.presets); + + group + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/types.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/types.rs new file mode 100644 index 00000000000000..ce3c2e5825532a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/types.rs @@ -0,0 +1,420 @@ +//! Cranelift ValueType hierarchy + +use std::fmt; + +use crate::shared::types as shared_types; +use cranelift_codegen_shared::constants; + +// Rust name prefix used for the `rust_name` method. +static RUST_NAME_PREFIX: &str = "ir::types::"; + +// ValueType variants (i8, i32, ...) are provided in `shared::types.rs`. + +/// A concrete SSA value type. +/// +/// All SSA values have a type that is described by an instance of `ValueType` +/// or one of its subclasses. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) enum ValueType { + Lane(LaneType), + Vector(VectorType), + DynamicVector(DynamicVectorType), +} + +impl ValueType { + /// Iterate through all of the lane types. + pub fn all_lane_types() -> LaneTypeIterator { + LaneTypeIterator::new() + } + + /// Return a string containing the documentation comment for this type. + pub fn doc(&self) -> String { + match *self { + ValueType::Lane(l) => l.doc(), + ValueType::Vector(ref v) => v.doc(), + ValueType::DynamicVector(ref v) => v.doc(), + } + } + + /// Return the number of bits in a lane. + pub fn lane_bits(&self) -> u64 { + match *self { + ValueType::Lane(l) => l.lane_bits(), + ValueType::Vector(ref v) => v.lane_bits(), + ValueType::DynamicVector(ref v) => v.lane_bits(), + } + } + + /// Return the number of lanes. + pub fn lane_count(&self) -> u64 { + match *self { + ValueType::Vector(ref v) => v.lane_count(), + _ => 1, + } + } + + /// Find the number of bytes that this type occupies in memory. + pub fn membytes(&self) -> u64 { + self.width() / 8 + } + + /// Find the unique number associated with this type. + pub fn number(&self) -> u16 { + match *self { + ValueType::Lane(l) => l.number(), + ValueType::Vector(ref v) => v.number(), + ValueType::DynamicVector(ref v) => v.number(), + } + } + + /// Return the name of this type for generated Rust source files. + pub fn rust_name(&self) -> String { + format!("{}{}", RUST_NAME_PREFIX, self.to_string().to_uppercase()) + } + + /// Return the total number of bits of an instance of this type. + pub fn width(&self) -> u64 { + self.lane_count() * self.lane_bits() + } +} + +impl fmt::Display for ValueType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ValueType::Lane(l) => l.fmt(f), + ValueType::Vector(ref v) => v.fmt(f), + ValueType::DynamicVector(ref v) => v.fmt(f), + } + } +} + +/// Create a ValueType from a given lane type. +impl From for ValueType { + fn from(lane: LaneType) -> Self { + ValueType::Lane(lane) + } +} + +/// Create a ValueType from a given vector type. +impl From for ValueType { + fn from(vector: VectorType) -> Self { + ValueType::Vector(vector) + } +} + +/// Create a ValueType from a given dynamic vector type. +impl From for ValueType { + fn from(vector: DynamicVectorType) -> Self { + ValueType::DynamicVector(vector) + } +} + +/// A concrete scalar type that can appear as a vector lane too. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) enum LaneType { + Float(shared_types::Float), + Int(shared_types::Int), +} + +impl LaneType { + /// Return a string containing the documentation comment for this lane type. + pub fn doc(self) -> String { + match self { + LaneType::Float(shared_types::Float::F16) => String::from( + "A 16-bit floating point type represented in the IEEE 754-2008 + *binary16* interchange format. This corresponds to the :c:type:`_Float16` + type in most C implementations. + WARNING: f16 support is a work-in-progress and is incomplete", + ), + LaneType::Float(shared_types::Float::F32) => String::from( + "A 32-bit floating point type represented in the IEEE 754-2008 + *binary32* interchange format. This corresponds to the :c:type:`float` + type in most C implementations.", + ), + LaneType::Float(shared_types::Float::F64) => String::from( + "A 64-bit floating point type represented in the IEEE 754-2008 + *binary64* interchange format. This corresponds to the :c:type:`double` + type in most C implementations.", + ), + LaneType::Float(shared_types::Float::F128) => String::from( + "A 128-bit floating point type represented in the IEEE 754-2008 + *binary128* interchange format. This corresponds to the :c:type:`_Float128` + type in most C implementations. + WARNING: f128 support is a work-in-progress and is incomplete", + ), + LaneType::Int(_) if self.lane_bits() < 32 => format!( + "An integer type with {} bits. + WARNING: arithmetic on {}bit integers is incomplete", + self.lane_bits(), + self.lane_bits() + ), + LaneType::Int(_) => format!("An integer type with {} bits.", self.lane_bits()), + } + } + + /// Return the number of bits in a lane. + pub fn lane_bits(self) -> u64 { + match self { + LaneType::Float(ref f) => *f as u64, + LaneType::Int(ref i) => *i as u64, + } + } + + /// Find the unique number associated with this lane type. + pub fn number(self) -> u16 { + constants::LANE_BASE + + match self { + LaneType::Int(shared_types::Int::I8) => 4, + LaneType::Int(shared_types::Int::I16) => 5, + LaneType::Int(shared_types::Int::I32) => 6, + LaneType::Int(shared_types::Int::I64) => 7, + LaneType::Int(shared_types::Int::I128) => 8, + LaneType::Float(shared_types::Float::F16) => 9, + LaneType::Float(shared_types::Float::F32) => 10, + LaneType::Float(shared_types::Float::F64) => 11, + LaneType::Float(shared_types::Float::F128) => 12, + } + } + + pub fn int_from_bits(num_bits: u16) -> LaneType { + LaneType::Int(match num_bits { + 8 => shared_types::Int::I8, + 16 => shared_types::Int::I16, + 32 => shared_types::Int::I32, + 64 => shared_types::Int::I64, + 128 => shared_types::Int::I128, + _ => unreachable!("unexpected num bits for int"), + }) + } + + pub fn float_from_bits(num_bits: u16) -> LaneType { + LaneType::Float(match num_bits { + 16 => shared_types::Float::F16, + 32 => shared_types::Float::F32, + 64 => shared_types::Float::F64, + 128 => shared_types::Float::F128, + _ => unreachable!("unexpected num bits for float"), + }) + } + + pub fn by(self, lanes: u16) -> ValueType { + if lanes == 1 { + self.into() + } else { + ValueType::Vector(VectorType::new(self, lanes.into())) + } + } + + pub fn to_dynamic(self, lanes: u16) -> ValueType { + ValueType::DynamicVector(DynamicVectorType::new(self, lanes.into())) + } +} + +impl fmt::Display for LaneType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LaneType::Float(_) => write!(f, "f{}", self.lane_bits()), + LaneType::Int(_) => write!(f, "i{}", self.lane_bits()), + } + } +} + +impl fmt::Debug for LaneType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let inner_msg = format!("bits={}", self.lane_bits()); + write!( + f, + "{}", + match *self { + LaneType::Float(_) => format!("FloatType({inner_msg})"), + LaneType::Int(_) => format!("IntType({inner_msg})"), + } + ) + } +} + +/// Create a LaneType from a given float variant. +impl From for LaneType { + fn from(f: shared_types::Float) -> Self { + LaneType::Float(f) + } +} + +/// Create a LaneType from a given int variant. +impl From for LaneType { + fn from(i: shared_types::Int) -> Self { + LaneType::Int(i) + } +} + +/// An iterator for different lane types. +pub(crate) struct LaneTypeIterator { + int_iter: shared_types::IntIterator, + float_iter: shared_types::FloatIterator, +} + +impl LaneTypeIterator { + /// Create a new lane type iterator. + fn new() -> Self { + Self { + int_iter: shared_types::IntIterator::new(), + float_iter: shared_types::FloatIterator::new(), + } + } +} + +impl Iterator for LaneTypeIterator { + type Item = LaneType; + fn next(&mut self) -> Option { + if let Some(i) = self.int_iter.next() { + Some(LaneType::from(i)) + } else if let Some(f) = self.float_iter.next() { + Some(LaneType::from(f)) + } else { + None + } + } +} + +/// A concrete SIMD vector type. +/// +/// A vector type has a lane type which is an instance of `LaneType`, +/// and a positive number of lanes. +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct VectorType { + base: LaneType, + lanes: u64, +} + +impl VectorType { + /// Initialize a new integer type with `n` bits. + pub fn new(base: LaneType, lanes: u64) -> Self { + Self { base, lanes } + } + + /// Return a string containing the documentation comment for this vector type. + pub fn doc(&self) -> String { + format!( + "A SIMD vector with {} lanes containing a `{}` each.", + self.lane_count(), + self.base + ) + } + + /// Return the number of bits in a lane. + pub fn lane_bits(&self) -> u64 { + self.base.lane_bits() + } + + /// Return the number of lanes. + pub fn lane_count(&self) -> u64 { + self.lanes + } + + /// Return the lane type. + pub fn lane_type(&self) -> LaneType { + self.base + } + + /// Find the unique number associated with this vector type. + /// + /// Vector types are encoded with the lane type in the low 4 bits and + /// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes. + pub fn number(&self) -> u16 { + let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros(); + let base_num = u32::from(self.base.number()); + let num = (lanes_log_2 << 4) + base_num; + num as u16 + } +} + +impl fmt::Display for VectorType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}x{}", self.base, self.lane_count()) + } +} + +impl fmt::Debug for VectorType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "VectorType(base={}, lanes={})", + self.base, + self.lane_count() + ) + } +} + +/// A concrete dynamic SIMD vector type. +/// +/// A vector type has a lane type which is an instance of `LaneType`, +/// and a positive number of lanes. +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct DynamicVectorType { + base: LaneType, + unscaled_lanes: u64, +} + +impl DynamicVectorType { + /// Initialize a new type with `base` lane type and a minimum number of lanes. + pub fn new(base: LaneType, unscaled_lanes: u64) -> Self { + Self { + base, + unscaled_lanes, + } + } + + /// Return a string containing the documentation comment for this vector type. + pub fn doc(&self) -> String { + format!( + "A dynamically-scaled SIMD vector with a minimum of {} lanes containing `{}` bits each.", + self.unscaled_lanes, + self.base + ) + } + + /// Return the number of bits in a lane. + pub fn lane_bits(&self) -> u64 { + self.base.lane_bits() + } + + /// Return the number of lanes. + pub fn minimum_lane_count(&self) -> u64 { + self.unscaled_lanes + } + + /// Return the lane type. + pub fn lane_type(&self) -> LaneType { + self.base + } + + /// Find the unique number associated with this vector type. + /// + /// Dynamic vector types are encoded in the same manner as `VectorType`, + /// with lane type in the low 4 bits and the log2(lane_count). We add the + /// `VECTOR_BASE` to move these numbers into the range beyond the fixed + /// SIMD types. + pub fn number(&self) -> u16 { + let base_num = u32::from(self.base.number()); + let lanes_log_2: u32 = 63 - self.minimum_lane_count().leading_zeros(); + let num = 0x80 + (lanes_log_2 << 4) + base_num; + num as u16 + } +} + +impl fmt::Display for DynamicVectorType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}x{}xN", self.base, self.minimum_lane_count()) + } +} + +impl fmt::Debug for DynamicVectorType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "DynamicVectorType(base={}, lanes={})", + self.base, + self.minimum_lane_count(), + ) + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/typevar.rs b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/typevar.rs new file mode 100644 index 00000000000000..61f31d9dbf5076 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/cdsl/typevar.rs @@ -0,0 +1,946 @@ +use std::cell::RefCell; +use std::collections::BTreeSet; +use std::fmt; +use std::hash; +use std::ops; +use std::rc::Rc; + +use crate::cdsl::types::{LaneType, ValueType}; + +const MAX_LANES: u16 = 256; +const MAX_BITS: u16 = 128; +const MAX_FLOAT_BITS: u16 = 128; + +/// Type variables can be used in place of concrete types when defining +/// instructions. This makes the instructions *polymorphic*. +/// +/// A type variable is restricted to vary over a subset of the value types. +/// This subset is specified by a set of flags that control the permitted base +/// types and whether the type variable can assume scalar or vector types, or +/// both. +#[derive(Debug)] +pub(crate) struct TypeVarContent { + /// Short name of type variable used in instruction descriptions. + pub name: String, + + /// Documentation string. + pub doc: String, + + /// Type set associated to the type variable. + /// This field must remain private; use `get_typeset()` or `get_raw_typeset()` to get the + /// information you want. + type_set: TypeSet, + + pub base: Option, +} + +#[derive(Clone, Debug)] +pub(crate) struct TypeVar { + content: Rc>, +} + +impl TypeVar { + pub fn new(name: impl Into, doc: impl Into, type_set: TypeSet) -> Self { + Self { + content: Rc::new(RefCell::new(TypeVarContent { + name: name.into(), + doc: doc.into(), + type_set, + base: None, + })), + } + } + + pub fn new_singleton(value_type: ValueType) -> Self { + let (name, doc) = (value_type.to_string(), value_type.doc()); + let mut builder = TypeSetBuilder::new(); + + let (scalar_type, num_lanes) = match value_type { + ValueType::Lane(lane_type) => (lane_type, 1), + ValueType::Vector(vec_type) => { + (vec_type.lane_type(), vec_type.lane_count() as RangeBound) + } + ValueType::DynamicVector(vec_type) => ( + vec_type.lane_type(), + vec_type.minimum_lane_count() as RangeBound, + ), + }; + + builder = builder.simd_lanes(num_lanes..num_lanes); + + // Only generate dynamic types for multiple lanes. + if num_lanes > 1 { + builder = builder.dynamic_simd_lanes(num_lanes..num_lanes); + } + + let builder = match scalar_type { + LaneType::Int(int_type) => { + let bits = int_type as RangeBound; + builder.ints(bits..bits) + } + LaneType::Float(float_type) => { + let bits = float_type as RangeBound; + builder.floats(bits..bits) + } + }; + TypeVar::new(name, doc, builder.build()) + } + + /// Get a fresh copy of self, named after `name`. Can only be called on non-derived typevars. + pub fn copy_from(other: &TypeVar, name: String) -> TypeVar { + assert!( + other.base.is_none(), + "copy_from() can only be called on non-derived type variables" + ); + TypeVar { + content: Rc::new(RefCell::new(TypeVarContent { + name, + doc: "".into(), + type_set: other.type_set.clone(), + base: None, + })), + } + } + + /// Returns the typeset for this TV. If the TV is derived, computes it recursively from the + /// derived function and the base's typeset. + /// Note this can't be done non-lazily in the constructor, because the TypeSet of the base may + /// change over time. + pub fn get_typeset(&self) -> TypeSet { + match &self.base { + Some(base) => base.type_var.get_typeset().image(base.derived_func), + None => self.type_set.clone(), + } + } + + /// Returns this typevar's type set, assuming this type var has no parent. + pub fn get_raw_typeset(&self) -> &TypeSet { + assert_eq!(self.type_set, self.get_typeset()); + &self.type_set + } + + /// If the associated typeset has a single type return it. Otherwise return None. + pub fn singleton_type(&self) -> Option { + let type_set = self.get_typeset(); + if type_set.size() == 1 { + Some(type_set.get_singleton()) + } else { + None + } + } + + /// Get the free type variable controlling this one. + pub fn free_typevar(&self) -> Option { + match &self.base { + Some(base) => base.type_var.free_typevar(), + None => { + match self.singleton_type() { + // A singleton type isn't a proper free variable. + Some(_) => None, + None => Some(self.clone()), + } + } + } + } + + /// Create a type variable that is a function of another. + pub fn derived(&self, derived_func: DerivedFunc) -> TypeVar { + let ts = self.get_typeset(); + + // Safety checks to avoid over/underflows. + match derived_func { + DerivedFunc::HalfWidth => { + assert!( + ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8, + "can't halve all integer types" + ); + assert!( + ts.floats.is_empty() || *ts.floats.iter().min().unwrap() > 16, + "can't halve all float types" + ); + } + DerivedFunc::DoubleWidth => { + assert!( + ts.ints.is_empty() || *ts.ints.iter().max().unwrap() < MAX_BITS, + "can't double all integer types" + ); + assert!( + ts.floats.is_empty() || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS, + "can't double all float types" + ); + } + DerivedFunc::SplitLanes => { + assert!( + ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8, + "can't halve all integer types" + ); + assert!( + ts.floats.is_empty() || *ts.floats.iter().min().unwrap() > 16, + "can't halve all float types" + ); + assert!( + *ts.lanes.iter().max().unwrap() < MAX_LANES, + "can't double 256 lanes" + ); + } + DerivedFunc::MergeLanes => { + assert!( + ts.ints.is_empty() || *ts.ints.iter().max().unwrap() < MAX_BITS, + "can't double all integer types" + ); + assert!( + ts.floats.is_empty() || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS, + "can't double all float types" + ); + assert!( + *ts.lanes.iter().min().unwrap() > 1, + "can't halve a scalar type" + ); + } + DerivedFunc::Narrower => { + assert_eq!( + *ts.lanes.iter().max().unwrap(), + 1, + "The `narrower` constraint does not apply to vectors" + ); + assert!( + (!ts.ints.is_empty() || !ts.floats.is_empty()) && ts.dynamic_lanes.is_empty(), + "The `narrower` constraint only applies to scalar ints or floats" + ); + } + DerivedFunc::Wider => { + assert_eq!( + *ts.lanes.iter().max().unwrap(), + 1, + "The `wider` constraint does not apply to vectors" + ); + assert!( + (!ts.ints.is_empty() || !ts.floats.is_empty()) && ts.dynamic_lanes.is_empty(), + "The `wider` constraint only applies to scalar ints or floats" + ); + } + DerivedFunc::LaneOf | DerivedFunc::AsTruthy | DerivedFunc::DynamicToVector => { + /* no particular assertions */ + } + } + + TypeVar { + content: Rc::new(RefCell::new(TypeVarContent { + name: format!("{}({})", derived_func.name(), self.name), + doc: "".into(), + type_set: ts, + base: Some(TypeVarParent { + type_var: self.clone(), + derived_func, + }), + })), + } + } + + pub fn lane_of(&self) -> TypeVar { + self.derived(DerivedFunc::LaneOf) + } + pub fn as_truthy(&self) -> TypeVar { + self.derived(DerivedFunc::AsTruthy) + } + pub fn half_width(&self) -> TypeVar { + self.derived(DerivedFunc::HalfWidth) + } + pub fn double_width(&self) -> TypeVar { + self.derived(DerivedFunc::DoubleWidth) + } + pub fn split_lanes(&self) -> TypeVar { + self.derived(DerivedFunc::SplitLanes) + } + pub fn merge_lanes(&self) -> TypeVar { + self.derived(DerivedFunc::MergeLanes) + } + pub fn dynamic_to_vector(&self) -> TypeVar { + self.derived(DerivedFunc::DynamicToVector) + } + + /// Make a new [TypeVar] that includes all types narrower than self. + pub fn narrower(&self) -> TypeVar { + self.derived(DerivedFunc::Narrower) + } + + /// Make a new [TypeVar] that includes all types wider than self. + pub fn wider(&self) -> TypeVar { + self.derived(DerivedFunc::Wider) + } +} + +impl From<&TypeVar> for TypeVar { + fn from(type_var: &TypeVar) -> Self { + type_var.clone() + } +} +impl From for TypeVar { + fn from(value_type: ValueType) -> Self { + TypeVar::new_singleton(value_type) + } +} + +// Hash TypeVars by pointers. +// There might be a better way to do this, but since TypeVar's content (namely TypeSet) can be +// mutated, it makes sense to use pointer equality/hashing here. +impl hash::Hash for TypeVar { + fn hash(&self, h: &mut H) { + match &self.base { + Some(base) => { + base.type_var.hash(h); + base.derived_func.hash(h); + } + None => { + (&**self as *const TypeVarContent).hash(h); + } + } + } +} + +impl PartialEq for TypeVar { + fn eq(&self, other: &TypeVar) -> bool { + match (&self.base, &other.base) { + (Some(base1), Some(base2)) => { + base1.type_var.eq(&base2.type_var) && base1.derived_func == base2.derived_func + } + (None, None) => Rc::ptr_eq(&self.content, &other.content), + _ => false, + } + } +} + +// Allow TypeVar as map keys, based on pointer equality (see also above PartialEq impl). +impl Eq for TypeVar {} + +impl ops::Deref for TypeVar { + type Target = TypeVarContent; + fn deref(&self) -> &Self::Target { + unsafe { self.content.as_ptr().as_ref().unwrap() } + } +} + +#[derive(Clone, Copy, Debug, Hash, PartialEq)] +pub(crate) enum DerivedFunc { + LaneOf, + AsTruthy, + HalfWidth, + DoubleWidth, + SplitLanes, + MergeLanes, + DynamicToVector, + Narrower, + Wider, +} + +impl DerivedFunc { + pub fn name(self) -> &'static str { + match self { + DerivedFunc::LaneOf => "lane_of", + DerivedFunc::AsTruthy => "as_truthy", + DerivedFunc::HalfWidth => "half_width", + DerivedFunc::DoubleWidth => "double_width", + DerivedFunc::SplitLanes => "split_lanes", + DerivedFunc::MergeLanes => "merge_lanes", + DerivedFunc::DynamicToVector => "dynamic_to_vector", + DerivedFunc::Narrower => "narrower", + DerivedFunc::Wider => "wider", + } + } +} + +#[derive(Debug, Hash)] +pub(crate) struct TypeVarParent { + pub type_var: TypeVar, + pub derived_func: DerivedFunc, +} + +/// A set of types. +/// +/// We don't allow arbitrary subsets of types, but use a parametrized approach +/// instead. +/// +/// Objects of this class can be used as dictionary keys. +/// +/// Parametrized type sets are specified in terms of ranges: +/// - The permitted range of vector lanes, where 1 indicates a scalar type. +/// - The permitted range of integer types. +/// - The permitted range of floating point types, and +/// - The permitted range of boolean types. +/// +/// The ranges are inclusive from smallest bit-width to largest bit-width. + +type RangeBound = u16; +type Range = ops::Range; +type NumSet = BTreeSet; + +macro_rules! num_set { + ($($expr:expr),*) => { + NumSet::from_iter(vec![$($expr),*]) + }; +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct TypeSet { + pub lanes: NumSet, + pub dynamic_lanes: NumSet, + pub ints: NumSet, + pub floats: NumSet, +} + +impl TypeSet { + fn new(lanes: NumSet, dynamic_lanes: NumSet, ints: NumSet, floats: NumSet) -> Self { + Self { + lanes, + dynamic_lanes, + ints, + floats, + } + } + + /// Return the number of concrete types represented by this typeset. + pub fn size(&self) -> usize { + self.lanes.len() * (self.ints.len() + self.floats.len()) + + self.dynamic_lanes.len() * (self.ints.len() + self.floats.len()) + } + + /// Return the image of self across the derived function func. + fn image(&self, derived_func: DerivedFunc) -> TypeSet { + match derived_func { + DerivedFunc::LaneOf => self.lane_of(), + DerivedFunc::AsTruthy => self.as_truthy(), + DerivedFunc::HalfWidth => self.half_width(), + DerivedFunc::DoubleWidth => self.double_width(), + DerivedFunc::SplitLanes => self.half_width().double_vector(), + DerivedFunc::MergeLanes => self.double_width().half_vector(), + DerivedFunc::DynamicToVector => self.dynamic_to_vector(), + DerivedFunc::Narrower => self.clone(), + DerivedFunc::Wider => self.clone(), + } + } + + /// Return a TypeSet describing the image of self across lane_of. + fn lane_of(&self) -> TypeSet { + let mut copy = self.clone(); + copy.lanes = num_set![1]; + copy + } + + /// Return a TypeSet describing the image of self across as_truthy. + fn as_truthy(&self) -> TypeSet { + let mut copy = self.clone(); + + // If this type set represents a scalar, `as_truthy` produces an I8, otherwise it returns a + // vector of the same number of lanes, whose elements are integers of the same width. For + // example, F32X4 gets turned into I32X4, while I32 gets turned into I8. + if self.lanes.len() == 1 && self.lanes.contains(&1) { + copy.ints = NumSet::from([8]); + } else { + copy.ints.extend(&self.floats) + } + + copy.floats = NumSet::new(); + copy + } + + /// Return a TypeSet describing the image of self across halfwidth. + fn half_width(&self) -> TypeSet { + let mut copy = self.clone(); + copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x > 8).map(|&x| x / 2)); + copy.floats = NumSet::from_iter(self.floats.iter().filter(|&&x| x > 16).map(|&x| x / 2)); + copy + } + + /// Return a TypeSet describing the image of self across doublewidth. + fn double_width(&self) -> TypeSet { + let mut copy = self.clone(); + copy.ints = NumSet::from_iter(self.ints.iter().filter(|&&x| x < MAX_BITS).map(|&x| x * 2)); + copy.floats = NumSet::from_iter( + self.floats + .iter() + .filter(|&&x| x < MAX_FLOAT_BITS) + .map(|&x| x * 2), + ); + copy + } + + /// Return a TypeSet describing the image of self across halfvector. + fn half_vector(&self) -> TypeSet { + let mut copy = self.clone(); + copy.lanes = NumSet::from_iter(self.lanes.iter().filter(|&&x| x > 1).map(|&x| x / 2)); + copy + } + + /// Return a TypeSet describing the image of self across doublevector. + fn double_vector(&self) -> TypeSet { + let mut copy = self.clone(); + copy.lanes = NumSet::from_iter( + self.lanes + .iter() + .filter(|&&x| x < MAX_LANES) + .map(|&x| x * 2), + ); + copy + } + + fn dynamic_to_vector(&self) -> TypeSet { + let mut copy = self.clone(); + copy.lanes = NumSet::from_iter( + self.dynamic_lanes + .iter() + .filter(|&&x| x < MAX_LANES) + .copied(), + ); + copy.dynamic_lanes = NumSet::new(); + copy + } + + fn concrete_types(&self) -> Vec { + let mut ret = Vec::new(); + for &num_lanes in &self.lanes { + for &bits in &self.ints { + ret.push(LaneType::int_from_bits(bits).by(num_lanes)); + } + for &bits in &self.floats { + ret.push(LaneType::float_from_bits(bits).by(num_lanes)); + } + } + for &num_lanes in &self.dynamic_lanes { + for &bits in &self.ints { + ret.push(LaneType::int_from_bits(bits).to_dynamic(num_lanes)); + } + for &bits in &self.floats { + ret.push(LaneType::float_from_bits(bits).to_dynamic(num_lanes)); + } + } + ret + } + + /// Return the singleton type represented by self. Can only call on typesets containing 1 type. + fn get_singleton(&self) -> ValueType { + let mut types = self.concrete_types(); + assert_eq!(types.len(), 1); + types.remove(0) + } +} + +impl fmt::Debug for TypeSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "TypeSet(")?; + + let mut subsets = Vec::new(); + if !self.lanes.is_empty() { + subsets.push(format!( + "lanes={{{}}}", + Vec::from_iter(self.lanes.iter().map(|x| x.to_string())).join(", ") + )); + } + if !self.dynamic_lanes.is_empty() { + subsets.push(format!( + "dynamic_lanes={{{}}}", + Vec::from_iter(self.dynamic_lanes.iter().map(|x| x.to_string())).join(", ") + )); + } + if !self.ints.is_empty() { + subsets.push(format!( + "ints={{{}}}", + Vec::from_iter(self.ints.iter().map(|x| x.to_string())).join(", ") + )); + } + if !self.floats.is_empty() { + subsets.push(format!( + "floats={{{}}}", + Vec::from_iter(self.floats.iter().map(|x| x.to_string())).join(", ") + )); + } + + write!(fmt, "{})", subsets.join(", "))?; + Ok(()) + } +} + +pub(crate) struct TypeSetBuilder { + ints: Interval, + floats: Interval, + includes_scalars: bool, + simd_lanes: Interval, + dynamic_simd_lanes: Interval, +} + +impl TypeSetBuilder { + pub fn new() -> Self { + Self { + ints: Interval::None, + floats: Interval::None, + includes_scalars: true, + simd_lanes: Interval::None, + dynamic_simd_lanes: Interval::None, + } + } + + pub fn ints(mut self, interval: impl Into) -> Self { + assert!(self.ints == Interval::None); + self.ints = interval.into(); + self + } + pub fn floats(mut self, interval: impl Into) -> Self { + assert!(self.floats == Interval::None); + self.floats = interval.into(); + self + } + pub fn includes_scalars(mut self, includes_scalars: bool) -> Self { + self.includes_scalars = includes_scalars; + self + } + pub fn simd_lanes(mut self, interval: impl Into) -> Self { + assert!(self.simd_lanes == Interval::None); + self.simd_lanes = interval.into(); + self + } + pub fn dynamic_simd_lanes(mut self, interval: impl Into) -> Self { + assert!(self.dynamic_simd_lanes == Interval::None); + self.dynamic_simd_lanes = interval.into(); + self + } + + pub fn build(self) -> TypeSet { + let min_lanes = if self.includes_scalars { 1 } else { 2 }; + + TypeSet::new( + range_to_set(self.simd_lanes.to_range(min_lanes..MAX_LANES, Some(1))), + range_to_set(self.dynamic_simd_lanes.to_range(2..MAX_LANES, None)), + range_to_set(self.ints.to_range(8..MAX_BITS, None)), + range_to_set(self.floats.to_range(16..MAX_FLOAT_BITS, None)), + ) + } +} + +#[derive(PartialEq)] +pub(crate) enum Interval { + None, + All, + Range(Range), +} + +impl Interval { + fn to_range(&self, full_range: Range, default: Option) -> Option { + match self { + Interval::None => default.map(|default_val| default_val..default_val), + + Interval::All => Some(full_range), + + Interval::Range(range) => { + let (low, high) = (range.start, range.end); + assert!(low.is_power_of_two()); + assert!(high.is_power_of_two()); + assert!(low <= high); + assert!(low >= full_range.start); + assert!(high <= full_range.end); + Some(low..high) + } + } + } +} + +impl From for Interval { + fn from(range: Range) -> Self { + Interval::Range(range) + } +} + +/// Generates a set with all the powers of two included in the range. +fn range_to_set(range: Option) -> NumSet { + let mut set = NumSet::new(); + + let (low, high) = match range { + Some(range) => (range.start, range.end), + None => return set, + }; + + assert!(low.is_power_of_two()); + assert!(high.is_power_of_two()); + assert!(low <= high); + + for i in low.trailing_zeros()..=high.trailing_zeros() { + assert!(1 << i <= RangeBound::max_value()); + set.insert(1 << i); + } + set +} + +#[test] +fn test_typevar_builder() { + let type_set = TypeSetBuilder::new().ints(Interval::All).build(); + assert_eq!(type_set.lanes, num_set![1]); + assert!(type_set.floats.is_empty()); + assert_eq!(type_set.ints, num_set![8, 16, 32, 64, 128]); + + let type_set = TypeSetBuilder::new().floats(Interval::All).build(); + assert_eq!(type_set.lanes, num_set![1]); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert!(type_set.ints.is_empty()); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(); + assert_eq!(type_set.lanes, num_set![2, 4, 8, 16, 32, 64, 128, 256]); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert!(type_set.ints.is_empty()); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .build(); + assert_eq!(type_set.lanes, num_set![1, 2, 4, 8, 16, 32, 64, 128, 256]); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert!(type_set.ints.is_empty()); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(); + assert_eq!(type_set.lanes, num_set![2, 4, 8, 16, 32, 64, 128, 256]); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert!(type_set.dynamic_lanes.is_empty()); + assert!(type_set.ints.is_empty()); + + let type_set = TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .dynamic_simd_lanes(Interval::All) + .includes_scalars(false) + .build(); + assert_eq!( + type_set.dynamic_lanes, + num_set![2, 4, 8, 16, 32, 64, 128, 256] + ); + assert_eq!(type_set.ints, num_set![8, 16, 32, 64, 128]); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert_eq!(type_set.lanes, num_set![1]); + + let type_set = TypeSetBuilder::new() + .floats(Interval::All) + .dynamic_simd_lanes(Interval::All) + .includes_scalars(false) + .build(); + assert_eq!( + type_set.dynamic_lanes, + num_set![2, 4, 8, 16, 32, 64, 128, 256] + ); + assert_eq!(type_set.floats, num_set![16, 32, 64, 128]); + assert_eq!(type_set.lanes, num_set![1]); + assert!(type_set.ints.is_empty()); + + let type_set = TypeSetBuilder::new().ints(16..64).build(); + assert_eq!(type_set.lanes, num_set![1]); + assert_eq!(type_set.ints, num_set![16, 32, 64]); + assert!(type_set.floats.is_empty()); +} + +#[test] +fn test_dynamic_to_vector() { + // We don't generate single lane dynamic types, so the maximum number of + // lanes we support is 128, as MAX_BITS is 256. + assert_eq!( + TypeSetBuilder::new() + .dynamic_simd_lanes(Interval::All) + .ints(Interval::All) + .build() + .dynamic_to_vector(), + TypeSetBuilder::new() + .simd_lanes(2..128) + .ints(Interval::All) + .build() + ); + assert_eq!( + TypeSetBuilder::new() + .dynamic_simd_lanes(Interval::All) + .floats(Interval::All) + .build() + .dynamic_to_vector(), + TypeSetBuilder::new() + .simd_lanes(2..128) + .floats(Interval::All) + .build() + ); +} + +#[test] +#[should_panic] +fn test_typevar_builder_too_high_bound_panic() { + TypeSetBuilder::new().ints(16..2 * MAX_BITS).build(); +} + +#[test] +#[should_panic] +fn test_typevar_builder_inverted_bounds_panic() { + TypeSetBuilder::new().ints(32..16).build(); +} + +#[test] +fn test_as_truthy() { + let a = TypeSetBuilder::new() + .simd_lanes(2..8) + .ints(8..8) + .floats(32..32) + .build(); + assert_eq!( + a.lane_of(), + TypeSetBuilder::new().ints(8..8).floats(32..32).build() + ); + + let mut a_as_truthy = TypeSetBuilder::new().simd_lanes(2..8).build(); + a_as_truthy.ints = num_set![8, 32]; + assert_eq!(a.as_truthy(), a_as_truthy); + + let a = TypeSetBuilder::new().ints(8..32).floats(32..64).build(); + let a_as_truthy = TypeSetBuilder::new().ints(8..8).build(); + assert_eq!(a.as_truthy(), a_as_truthy); +} + +#[test] +fn test_forward_images() { + let empty_set = TypeSetBuilder::new().build(); + + // Half vector. + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(1..32) + .build() + .half_vector(), + TypeSetBuilder::new().simd_lanes(1..16).build() + ); + + // Double vector. + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(1..32) + .build() + .double_vector(), + TypeSetBuilder::new().simd_lanes(2..64).build() + ); + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(128..256) + .build() + .double_vector(), + TypeSetBuilder::new().simd_lanes(256..256).build() + ); + + // Half width. + assert_eq!( + TypeSetBuilder::new().ints(8..32).build().half_width(), + TypeSetBuilder::new().ints(8..16).build() + ); + assert_eq!( + TypeSetBuilder::new().floats(16..16).build().half_width(), + empty_set + ); + assert_eq!( + TypeSetBuilder::new().floats(32..128).build().half_width(), + TypeSetBuilder::new().floats(16..64).build() + ); + + // Double width. + assert_eq!( + TypeSetBuilder::new().ints(8..32).build().double_width(), + TypeSetBuilder::new().ints(16..64).build() + ); + assert_eq!( + TypeSetBuilder::new().ints(32..64).build().double_width(), + TypeSetBuilder::new().ints(64..128).build() + ); + assert_eq!( + TypeSetBuilder::new().floats(32..32).build().double_width(), + TypeSetBuilder::new().floats(64..64).build() + ); + assert_eq!( + TypeSetBuilder::new().floats(16..64).build().double_width(), + TypeSetBuilder::new().floats(32..128).build() + ); +} + +#[test] +#[should_panic] +fn test_typeset_singleton_panic_nonsingleton_types() { + TypeSetBuilder::new() + .ints(8..8) + .floats(32..32) + .build() + .get_singleton(); +} + +#[test] +#[should_panic] +fn test_typeset_singleton_panic_nonsingleton_lanes() { + TypeSetBuilder::new() + .simd_lanes(1..2) + .floats(32..32) + .build() + .get_singleton(); +} + +#[test] +fn test_typeset_singleton() { + use crate::shared::types as shared_types; + assert_eq!( + TypeSetBuilder::new().ints(16..16).build().get_singleton(), + ValueType::Lane(shared_types::Int::I16.into()) + ); + assert_eq!( + TypeSetBuilder::new().floats(64..64).build().get_singleton(), + ValueType::Lane(shared_types::Float::F64.into()) + ); + assert_eq!( + TypeSetBuilder::new() + .simd_lanes(4..4) + .ints(32..32) + .build() + .get_singleton(), + LaneType::from(shared_types::Int::I32).by(4) + ); +} + +#[test] +fn test_typevar_functions() { + let x = TypeVar::new( + "x", + "i16 and up", + TypeSetBuilder::new().ints(16..64).build(), + ); + assert_eq!(x.half_width().name, "half_width(x)"); + assert_eq!( + x.half_width().double_width().name, + "double_width(half_width(x))" + ); + + let x = TypeVar::new("x", "up to i32", TypeSetBuilder::new().ints(8..32).build()); + assert_eq!(x.double_width().name, "double_width(x)"); +} + +#[test] +fn test_typevar_singleton() { + use crate::cdsl::types::VectorType; + use crate::shared::types as shared_types; + + // Test i32. + let typevar = TypeVar::new_singleton(ValueType::Lane(LaneType::Int(shared_types::Int::I32))); + assert_eq!(typevar.name, "i32"); + assert_eq!(typevar.type_set.ints, num_set![32]); + assert!(typevar.type_set.floats.is_empty()); + assert_eq!(typevar.type_set.lanes, num_set![1]); + + // Test f32x4. + let typevar = TypeVar::new_singleton(ValueType::Vector(VectorType::new( + LaneType::Float(shared_types::Float::F32), + 4, + ))); + assert_eq!(typevar.name, "f32x4"); + assert!(typevar.type_set.ints.is_empty()); + assert_eq!(typevar.type_set.floats, num_set![32]); + assert_eq!(typevar.type_set.lanes, num_set![4]); +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/constant_hash.rs b/deps/crates/vendor/cranelift-codegen-meta/src/constant_hash.rs new file mode 100644 index 00000000000000..044e1b706e345f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/constant_hash.rs @@ -0,0 +1,63 @@ +//! Build support for precomputed constant hash tables. +//! +//! This module can generate constant hash tables using open addressing and quadratic probing. +//! +//! The hash tables are arrays that are guaranteed to: +//! +//! - Have a power-of-two size. +//! - Contain at least one empty slot. + +use std::iter; + +/// Compute an open addressed, quadratically probed hash table containing +/// `items`. The returned table is a list containing the elements of the +/// iterable `items` and `None` in unused slots. +pub fn generate_table<'cont, T, I: iter::Iterator, H: Fn(&T) -> usize>( + items: I, + num_items: usize, + hash_function: H, +) -> Vec> { + let size = (1.20 * num_items as f64) as usize; + + // Probing code's stop condition relies on the table having one vacant entry at least. + let size = if size.is_power_of_two() { + size * 2 + } else { + size.next_power_of_two() + }; + + let mut table = vec![None; size]; + + for i in items { + let mut h = hash_function(i) % size; + let mut s = 0; + while table[h].is_some() { + s += 1; + h = (h + s) % size; + } + table[h] = Some(i); + } + + table +} + +#[cfg(test)] +mod tests { + use super::generate_table; + use cranelift_codegen_shared::constant_hash::simple_hash; + + #[test] + fn test_generate_table() { + let v = vec!["Hello".to_string(), "world".to_string()]; + let table = generate_table(v.iter(), v.len(), |s| simple_hash(&s)); + assert_eq!( + table, + vec![ + None, + Some(&"Hello".to_string()), + Some(&"world".to_string()), + None + ] + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/error.rs b/deps/crates/vendor/cranelift-codegen-meta/src/error.rs new file mode 100644 index 00000000000000..e898dea4e296fd --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/error.rs @@ -0,0 +1,50 @@ +//! Error returned during meta code-generation. +use std::fmt; +use std::io; + +/// An error that occurred when the cranelift_codegen_meta crate was generating +/// source files for the cranelift_codegen crate. +#[derive(Debug)] +pub struct Error { + inner: Box, +} + +impl Error { + /// Create a new error object with the given message. + pub fn with_msg>(msg: S) -> Error { + Error { + inner: Box::new(ErrorInner::Msg(msg.into())), + } + } +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.inner) + } +} + +impl From for Error { + fn from(e: io::Error) -> Self { + Error { + inner: Box::new(ErrorInner::IoError(e)), + } + } +} + +#[derive(Debug)] +enum ErrorInner { + Msg(String), + IoError(io::Error), +} + +impl fmt::Display for ErrorInner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ErrorInner::Msg(ref s) => write!(f, "{s}"), + ErrorInner::IoError(ref e) => write!(f, "{e}"), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/gen_inst.rs b/deps/crates/vendor/cranelift-codegen-meta/src/gen_inst.rs new file mode 100644 index 00000000000000..e9a505933219a2 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/gen_inst.rs @@ -0,0 +1,1274 @@ +//! Generate instruction data (including opcodes, formats, builders, etc.). +use std::fmt; +use std::rc::Rc; + +use cranelift_codegen_shared::constant_hash; + +use crate::cdsl::camel_case; +use crate::cdsl::formats::InstructionFormat; +use crate::cdsl::instructions::{AllInstructions, Instruction}; +use crate::cdsl::operands::Operand; +use crate::cdsl::typevar::{TypeSet, TypeVar}; + +use crate::error; +use crate::srcgen::{Formatter, Match}; +use crate::unique_table::{UniqueSeqTable, UniqueTable}; + +// TypeSet indexes are encoded in 8 bits, with `0xff` reserved. +const TYPESET_LIMIT: usize = 0xff; + +/// Generate an instruction format enumeration. +fn gen_formats(formats: &[Rc], fmt: &mut Formatter) { + fmt.doc_comment( + r#" + An instruction format + + Every opcode has a corresponding instruction format + which is represented by both the `InstructionFormat` + and the `InstructionData` enums. + "#, + ); + fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug)]"); + fmt.line("pub enum InstructionFormat {"); + fmt.indent(|fmt| { + for format in formats { + fmt.doc_comment(format.to_string()); + fmtln!(fmt, "{},", format.name); + } + }); + fmt.line("}"); + fmt.empty_line(); + + // Emit a From which also serves to verify that + // InstructionFormat and InstructionData are in sync. + fmt.line("impl<'a> From<&'a InstructionData> for InstructionFormat {"); + fmt.indent(|fmt| { + fmt.line("fn from(inst: &'a InstructionData) -> Self {"); + fmt.indent(|fmt| { + let mut m = Match::new("*inst"); + for format in formats { + m.arm( + format!("InstructionData::{}", format.name), + vec![".."], + format!("Self::{}", format.name), + ); + } + fmt.add_match(m); + }); + fmt.line("}"); + }); + fmt.line("}"); + fmt.empty_line(); +} + +/// Generate the InstructionData enum. +/// +/// Every variant must contain an `opcode` field. The size of `InstructionData` should be kept at +/// 16 bytes on 64-bit architectures. If more space is needed to represent an instruction, use a +/// `ValueList` to store the additional information out of line. +fn gen_instruction_data(formats: &[Rc], fmt: &mut Formatter) { + fmt.line("#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]"); + fmt.line(r#"#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]"#); + fmt.line("#[allow(missing_docs)]"); + fmtln!(fmt, "pub enum InstructionData {"); + fmt.indent(|fmt| { + for format in formats { + fmtln!(fmt, "{} {{", format.name); + fmt.indent(|fmt| { + fmt.line("opcode: Opcode,"); + if format.has_value_list { + fmt.line("args: ValueList,"); + } else if format.num_value_operands == 1 { + fmt.line("arg: Value,"); + } else if format.num_value_operands > 0 { + fmtln!(fmt, "args: [Value; {}],", format.num_value_operands); + } + + match format.num_block_operands { + 0 => (), + 1 => fmt.line("destination: ir::BlockCall,"), + 2 => fmtln!( + fmt, + "blocks: [ir::BlockCall; {}],", + format.num_block_operands + ), + n => panic!("Too many block operands in instruction: {n}"), + } + + for field in &format.imm_fields { + fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type); + } + }); + fmtln!(fmt, "},"); + } + }); + fmt.line("}"); +} + +fn gen_arguments_method(formats: &[Rc], fmt: &mut Formatter, is_mut: bool) { + let (method, mut_, rslice, as_slice) = if is_mut { + ( + "arguments_mut", + "mut ", + "core::slice::from_mut", + "as_mut_slice", + ) + } else { + ("arguments", "", "core::slice::from_ref", "as_slice") + }; + + fmtln!( + fmt, + "pub fn {}<'a>(&'a {}self, pool: &'a {}ir::ValueListPool) -> &'a {}[Value] {{", + method, + mut_, + mut_, + mut_ + ); + fmt.indent(|fmt| { + let mut m = Match::new("*self"); + for format in formats { + let name = format!("Self::{}", format.name); + + // Formats with a value list put all of their arguments in the list. We don't split + // them up, just return it all as variable arguments. (I expect the distinction to go + // away). + if format.has_value_list { + m.arm( + name, + vec![format!("ref {}args", mut_), "..".to_string()], + format!("args.{as_slice}(pool)"), + ); + continue; + } + + // Fixed args. + let mut fields = Vec::new(); + let arg = if format.num_value_operands == 0 { + format!("&{mut_}[]") + } else if format.num_value_operands == 1 { + fields.push(format!("ref {mut_}arg")); + format!("{rslice}(arg)") + } else { + let arg = format!("args_arity{}", format.num_value_operands); + fields.push(format!("args: ref {mut_}{arg}")); + arg + }; + fields.push("..".into()); + + m.arm(name, fields, arg); + } + fmt.add_match(m); + }); + fmtln!(fmt, "}"); +} + +/// Generate the boring parts of the InstructionData implementation. +/// +/// These methods in `impl InstructionData` can be generated automatically from the instruction +/// formats: +/// +/// - `pub fn opcode(&self) -> Opcode` +/// - `pub fn arguments(&self, &pool) -> &[Value]` +/// - `pub fn arguments_mut(&mut self, &pool) -> &mut [Value]` +/// - `pub fn eq(&self, &other: Self, &pool) -> bool` +/// - `pub fn hash(&self, state: &mut H, &pool)` +fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Formatter) { + fmt.line("impl InstructionData {"); + fmt.indent(|fmt| { + fmt.doc_comment("Get the opcode of this instruction."); + fmt.line("pub fn opcode(&self) -> Opcode {"); + fmt.indent(|fmt| { + let mut m = Match::new("*self"); + for format in formats { + m.arm(format!("Self::{}", format.name), vec!["opcode", ".."], + "opcode".to_string()); + } + fmt.add_match(m); + }); + fmt.line("}"); + fmt.empty_line(); + + fmt.doc_comment("Get the controlling type variable operand."); + fmt.line("pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> Option {"); + fmt.indent(|fmt| { + let mut m = Match::new("*self"); + for format in formats { + let name = format!("Self::{}", format.name); + if format.typevar_operand.is_none() { + m.arm(name, vec![".."], "None".to_string()); + } else if format.has_value_list { + // We keep all arguments in a value list. + m.arm(name, vec!["ref args", ".."], format!("args.get({}, pool)", format.typevar_operand.unwrap())); + } else if format.num_value_operands == 1 { + m.arm(name, vec!["arg", ".."], "Some(arg)".to_string()); + } else { + // We have multiple value operands and an array `args`. + // Which `args` index to use? + let args = format!("args_arity{}", format.num_value_operands); + m.arm(name, vec![format!("args: ref {}", args), "..".to_string()], + format!("Some({}[{}])", args, format.typevar_operand.unwrap())); + } + } + fmt.add_match(m); + }); + fmt.line("}"); + fmt.empty_line(); + + fmt.doc_comment("Get the value arguments to this instruction."); + gen_arguments_method(formats, fmt, false); + fmt.empty_line(); + + fmt.doc_comment(r#"Get mutable references to the value arguments to this + instruction."#); + gen_arguments_method(formats, fmt, true); + fmt.empty_line(); + + fmt.doc_comment(r#" + Compare two `InstructionData` for equality. + + This operation requires a reference to a `ValueListPool` to + determine if the contents of any `ValueLists` are equal. + + This operation takes a closure that is allowed to map each + argument value to some other value before the instructions + are compared. This allows various forms of canonicalization. + "#); + fmt.line("pub fn eq Value>(&self, other: &Self, pool: &ir::ValueListPool, mapper: F) -> bool {"); + fmt.indent(|fmt| { + fmt.line("if ::core::mem::discriminant(self) != ::core::mem::discriminant(other) {"); + fmt.indent(|fmt| { + fmt.line("return false;"); + }); + fmt.line("}"); + + fmt.line("match (self, other) {"); + fmt.indent(|fmt| { + for format in formats { + let name = format!("&Self::{}", format.name); + let mut members = vec!["opcode"]; + + let args_eq = if format.has_value_list { + members.push("args"); + Some("args1.as_slice(pool).iter().zip(args2.as_slice(pool).iter()).all(|(a, b)| mapper(*a) == mapper(*b))") + } else if format.num_value_operands == 1 { + members.push("arg"); + Some("mapper(*arg1) == mapper(*arg2)") + } else if format.num_value_operands > 0 { + members.push("args"); + Some("args1.iter().zip(args2.iter()).all(|(a, b)| mapper(*a) == mapper(*b))") + } else { + None + }; + + let blocks_eq = match format.num_block_operands { + 0 => None, + 1 => { + members.push("destination"); + Some("destination1 == destination2") + }, + _ => { + members.push("blocks"); + Some("blocks1.iter().zip(blocks2.iter()).all(|(a, b)| a.block(pool) == b.block(pool))") + } + }; + + for field in &format.imm_fields { + members.push(field.member); + } + + let pat1 = members.iter().map(|x| format!("{x}: ref {x}1")).collect::>().join(", "); + let pat2 = members.iter().map(|x| format!("{x}: ref {x}2")).collect::>().join(", "); + fmtln!(fmt, "({} {{ {} }}, {} {{ {} }}) => {{", name, pat1, name, pat2); + fmt.indent(|fmt| { + fmt.line("opcode1 == opcode2"); + for field in &format.imm_fields { + fmtln!(fmt, "&& {}1 == {}2", field.member, field.member); + } + if let Some(args_eq) = args_eq { + fmtln!(fmt, "&& {}", args_eq); + } + if let Some(blocks_eq) = blocks_eq { + fmtln!(fmt, "&& {}", blocks_eq); + } + }); + fmtln!(fmt, "}"); + } + fmt.line("_ => unreachable!()"); + }); + fmt.line("}"); + }); + fmt.line("}"); + fmt.empty_line(); + + fmt.doc_comment(r#" + Hash an `InstructionData`. + + This operation requires a reference to a `ValueListPool` to + hash the contents of any `ValueLists`. + + This operation takes a closure that is allowed to map each + argument value to some other value before it is hashed. This + allows various forms of canonicalization. + "#); + fmt.line("pub fn hash Value>(&self, state: &mut H, pool: &ir::ValueListPool, mapper: F) {"); + fmt.indent(|fmt| { + fmt.line("match *self {"); + fmt.indent(|fmt| { + for format in formats { + let name = format!("Self::{}", format.name); + let mut members = vec!["opcode"]; + + let (args, len) = if format.has_value_list { + members.push("ref args"); + ("args.as_slice(pool)", "args.len(pool)") + } else if format.num_value_operands == 1 { + members.push("ref arg"); + ("std::slice::from_ref(arg)", "1") + } else if format.num_value_operands > 0 { + members.push("ref args"); + ("args", "args.len()") + } else { + ("&[]", "0") + }; + + let blocks = match format.num_block_operands { + 0 => None, + 1 => { + members.push("ref destination"); + Some(("std::slice::from_ref(destination)", "1")) + } + _ => { + members.push("ref blocks"); + Some(("blocks", "blocks.len()")) + } + }; + + for field in &format.imm_fields { + members.push(field.member); + } + let members = members.join(", "); + + fmtln!(fmt, "{}{{{}}} => {{", name, members ); // beware the moustaches + fmt.indent(|fmt| { + fmt.line("::core::hash::Hash::hash( &::core::mem::discriminant(self), state);"); + fmt.line("::core::hash::Hash::hash(&opcode, state);"); + for field in &format.imm_fields { + fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", field.member); + } + fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", len); + fmtln!(fmt, "for &arg in {} {{", args); + fmt.indent(|fmt| { + fmtln!(fmt, "let arg = mapper(arg);"); + fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);"); + }); + fmtln!(fmt, "}"); + + if let Some((blocks, len)) = blocks { + fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", len); + fmtln!(fmt, "for &block in {} {{", blocks); + fmt.indent(|fmt| { + fmtln!(fmt, "::core::hash::Hash::hash(&block.block(pool), state);"); + fmtln!(fmt, "for &arg in block.args_slice(pool) {"); + fmt.indent(|fmt| { + fmtln!(fmt, "let arg = mapper(arg);"); + fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); + } + }); + fmtln!(fmt, "}"); + } + }); + fmt.line("}"); + }); + fmt.line("}"); + + fmt.empty_line(); + + fmt.doc_comment(r#" + Deep-clone an `InstructionData`, including any referenced lists. + + This operation requires a reference to a `ValueListPool` to + clone the `ValueLists`. + "#); + fmt.line("pub fn deep_clone(&self, pool: &mut ir::ValueListPool) -> Self {"); + fmt.indent(|fmt| { + fmt.line("match *self {"); + fmt.indent(|fmt| { + for format in formats { + let name = format!("Self::{}", format.name); + let mut members = vec!["opcode"]; + + if format.has_value_list { + members.push("ref args"); + } else if format.num_value_operands == 1 { + members.push("arg"); + } else if format.num_value_operands > 0 { + members.push("args"); + } + + match format.num_block_operands { + 0 => {} + 1 => { + members.push("destination"); + } + _ => { + members.push("blocks"); + } + }; + + for field in &format.imm_fields { + members.push(field.member); + } + let members = members.join(", "); + + fmtln!(fmt, "{}{{{}}} => {{", name, members ); // beware the moustaches + fmt.indent(|fmt| { + fmtln!(fmt, "Self::{} {{", format.name); + fmt.indent(|fmt| { + fmtln!(fmt, "opcode,"); + + if format.has_value_list { + fmtln!(fmt, "args: args.deep_clone(pool),"); + } else if format.num_value_operands == 1 { + fmtln!(fmt, "arg,"); + } else if format.num_value_operands > 0 { + fmtln!(fmt, "args,"); + } + + match format.num_block_operands { + 0 => {} + 1 => { + fmtln!(fmt, "destination: destination.deep_clone(pool),"); + } + 2 => { + fmtln!(fmt, "blocks: [blocks[0].deep_clone(pool), blocks[1].deep_clone(pool)],"); + } + _ => panic!("Too many block targets in instruction"), + } + + for field in &format.imm_fields { + fmtln!(fmt, "{},", field.member); + } + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); + } + }); + fmt.line("}"); + }); + fmt.line("}"); + }); + fmt.line("}"); +} + +fn gen_bool_accessor bool>( + all_inst: &AllInstructions, + get_attr: T, + name: &'static str, + doc: &'static str, + fmt: &mut Formatter, +) { + fmt.doc_comment(doc); + fmtln!(fmt, "pub fn {}(self) -> bool {{", name); + fmt.indent(|fmt| { + let mut m = Match::new("self"); + for inst in all_inst.iter() { + if get_attr(inst) { + m.arm_no_fields(format!("Self::{}", inst.camel_name), "true"); + } + } + m.arm_no_fields("_", "false"); + fmt.add_match(m); + }); + fmtln!(fmt, "}"); + fmt.empty_line(); +} + +fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) { + fmt.doc_comment( + r#" + An instruction opcode. + + All instructions from all supported ISAs are present. + "#, + ); + fmt.line("#[repr(u8)]"); + fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]"); + fmt.line( + r#"#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) + )]"#, + ); + + // We explicitly set the discriminant of the first variant to 1, which allows us to take + // advantage of the NonZero optimization, meaning that wrapping enums can use the 0 + // discriminant instead of increasing the size of the whole type, and so the size of + // Option is the same as Opcode's. + fmt.line("pub enum Opcode {"); + fmt.indent(|fmt| { + let mut is_first_opcode = true; + for inst in all_inst.iter() { + fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name)); + + // Document polymorphism. + if let Some(poly) = &inst.polymorphic_info { + if poly.use_typevar_operand { + let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()]; + fmt.doc_comment(format!( + "Type inferred from `{}`.", + inst.operands_in[op_num].name + )); + } + } + + // Enum variant itself. + if is_first_opcode { + fmtln!(fmt, "{} = 1,", inst.camel_name); + is_first_opcode = false; + } else { + fmtln!(fmt, "{},", inst.camel_name) + } + } + }); + fmt.line("}"); + fmt.empty_line(); + + fmt.line("impl Opcode {"); + fmt.indent(|fmt| { + gen_bool_accessor( + all_inst, + |inst| inst.is_terminator, + "is_terminator", + "True for instructions that terminate the block", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.is_branch, + "is_branch", + "True for all branch or jump instructions.", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.is_call, + "is_call", + "Is this a call instruction?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.is_return, + "is_return", + "Is this a return instruction?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.can_load, + "can_load", + "Can this instruction read from memory?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.can_store, + "can_store", + "Can this instruction write to memory?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.can_trap, + "can_trap", + "Can this instruction cause a trap?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.other_side_effects, + "other_side_effects", + "Does this instruction have other side effects besides can_* flags?", + fmt, + ); + gen_bool_accessor( + all_inst, + |inst| inst.side_effects_idempotent, + "side_effects_idempotent", + "Despite having side effects, is this instruction okay to GVN?", + fmt, + ); + + // Generate an opcode list, for iterating over all known opcodes. + fmt.doc_comment("All cranelift opcodes."); + fmt.line("pub fn all() -> &'static [Opcode] {"); + fmt.indent(|fmt| { + fmt.line("return &["); + for inst in all_inst { + fmt.indent(|fmt| { + fmtln!(fmt, "Opcode::{},", inst.camel_name); + }); + } + fmt.line("];"); + }); + fmt.line("}"); + fmt.empty_line(); + }); + fmt.line("}"); + fmt.empty_line(); + + // Generate a private opcode_format table. + fmtln!( + fmt, + "const OPCODE_FORMAT: [InstructionFormat; {}] = [", + all_inst.len() + ); + fmt.indent(|fmt| { + for inst in all_inst.iter() { + fmtln!( + fmt, + "InstructionFormat::{}, // {}", + inst.format.name, + inst.name + ); + } + }); + fmtln!(fmt, "];"); + fmt.empty_line(); + + // Generate a private opcode_name function. + fmt.line("fn opcode_name(opc: Opcode) -> &\'static str {"); + fmt.indent(|fmt| { + let mut m = Match::new("opc"); + for inst in all_inst.iter() { + m.arm_no_fields( + format!("Opcode::{}", inst.camel_name), + format!("\"{}\"", inst.name), + ); + } + fmt.add_match(m); + }); + fmt.line("}"); + fmt.empty_line(); + + // Generate an opcode hash table for looking up opcodes by name. + let hash_table = + crate::constant_hash::generate_table(all_inst.iter(), all_inst.len(), |inst| { + constant_hash::simple_hash(&inst.name) + }); + fmtln!( + fmt, + "const OPCODE_HASH_TABLE: [Option; {}] = [", + hash_table.len() + ); + fmt.indent(|fmt| { + for i in hash_table { + match i { + Some(i) => fmtln!(fmt, "Some(Opcode::{}),", i.camel_name), + None => fmtln!(fmt, "None,"), + } + } + }); + fmtln!(fmt, "];"); + fmt.empty_line(); +} + +/// Get the value type constraint for an SSA value operand, where +/// `ctrl_typevar` is the controlling type variable. +/// +/// Each operand constraint is represented as a string, one of: +/// - `Concrete(vt)`, where `vt` is a value type name. +/// - `Free(idx)` where `idx` is an index into `type_sets`. +/// - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints. +fn get_constraint<'entries, 'table>( + operand: &'entries Operand, + ctrl_typevar: Option<&TypeVar>, + type_sets: &'table mut UniqueTable<'entries, TypeSet>, +) -> String { + assert!(operand.is_value()); + let type_var = operand.type_var().unwrap(); + + if let Some(typ) = type_var.singleton_type() { + return format!("Concrete({})", typ.rust_name()); + } + + if let Some(free_typevar) = type_var.free_typevar() { + if ctrl_typevar.is_some() && free_typevar != *ctrl_typevar.unwrap() { + assert!(type_var.base.is_none()); + return format!("Free({})", type_sets.add(type_var.get_raw_typeset())); + } + } + + if let Some(base) = &type_var.base { + assert!(base.type_var == *ctrl_typevar.unwrap()); + return camel_case(base.derived_func.name()); + } + + assert!(type_var == ctrl_typevar.unwrap()); + "Same".into() +} + +fn gen_bitset<'a, T: IntoIterator>( + iterable: T, + name: &'static str, + field_size: u8, + fmt: &mut Formatter, +) { + let bits = iterable.into_iter().fold(0, |acc, x| { + assert!(x.is_power_of_two()); + assert!(u32::from(*x) < (1 << u32::from(field_size))); + acc | x + }); + fmtln!(fmt, "{}: ScalarBitSet::({}),", name, field_size, bits); +} + +fn iterable_to_string>(iterable: T) -> String { + let elems = iterable + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(", "); + format!("{{{elems}}}") +} + +fn typeset_to_string(ts: &TypeSet) -> String { + let mut result = format!("TypeSet(lanes={}", iterable_to_string(&ts.lanes)); + if !ts.ints.is_empty() { + result += &format!(", ints={}", iterable_to_string(&ts.ints)); + } + if !ts.floats.is_empty() { + result += &format!(", floats={}", iterable_to_string(&ts.floats)); + } + result += ")"; + result +} + +/// Generate the table of ValueTypeSets described by type_sets. +pub(crate) fn gen_typesets_table(type_sets: &UniqueTable, fmt: &mut Formatter) { + if type_sets.len() == 0 { + return; + } + + fmt.comment("Table of value type sets."); + assert!(type_sets.len() <= TYPESET_LIMIT, "Too many type sets!"); + fmtln!( + fmt, + "const TYPE_SETS: [ir::instructions::ValueTypeSet; {}] = [", + type_sets.len() + ); + fmt.indent(|fmt| { + for ts in type_sets.iter() { + fmt.line("ir::instructions::ValueTypeSet {"); + fmt.indent(|fmt| { + fmt.comment(typeset_to_string(ts)); + gen_bitset(&ts.lanes, "lanes", 16, fmt); + gen_bitset(&ts.dynamic_lanes, "dynamic_lanes", 16, fmt); + gen_bitset(&ts.ints, "ints", 8, fmt); + gen_bitset(&ts.floats, "floats", 8, fmt); + }); + fmt.line("},"); + } + }); + fmtln!(fmt, "];"); +} + +/// Generate value type constraints for all instructions. +/// - Emit a compact constant table of ValueTypeSet objects. +/// - Emit a compact constant table of OperandConstraint objects. +/// - Emit an opcode-indexed table of instruction constraints. +fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) { + // Table of TypeSet instances. + let mut type_sets = UniqueTable::new(); + + // Table of operand constraint sequences (as tuples). Each operand + // constraint is represented as a string, one of: + // - `Concrete(vt)`, where `vt` is a value type name. + // - `Free(idx)` where `idx` is an index into `type_sets`. + // - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints. + let mut operand_seqs = UniqueSeqTable::new(); + + // Preload table with constraints for typical binops. + operand_seqs.add(&vec!["Same".to_string(); 3]); + + fmt.comment("Table of opcode constraints."); + fmtln!( + fmt, + "const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [", + all_inst.len() + ); + fmt.indent(|fmt| { + for inst in all_inst.iter() { + let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info { + let index = type_sets.add(poly.ctrl_typevar.get_raw_typeset()); + (Some(&poly.ctrl_typevar), index) + } else { + (None, TYPESET_LIMIT) + }; + + // Collect constraints for the value results, not including `variable_args` results + // which are always special cased. + let mut constraints = Vec::new(); + for &index in &inst.value_results { + constraints.push(get_constraint(&inst.operands_out[index], ctrl_typevar, &mut type_sets)); + } + for &index in &inst.value_opnums { + constraints.push(get_constraint(&inst.operands_in[index], ctrl_typevar, &mut type_sets)); + } + + let constraint_offset = operand_seqs.add(&constraints); + + let fixed_results = inst.value_results.len(); + let fixed_values = inst.value_opnums.len(); + + // Can the controlling type variable be inferred from the designated operand? + let use_typevar_operand = if let Some(poly) = &inst.polymorphic_info { + poly.use_typevar_operand + } else { + false + }; + + // Can the controlling type variable be inferred from the result? + let use_result = fixed_results > 0 && inst.operands_out[inst.value_results[0]].type_var() == ctrl_typevar; + + // Are we required to use the designated operand instead of the result? + let requires_typevar_operand = use_typevar_operand && !use_result; + + fmt.comment( + format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}", + inst.camel_name, + fixed_results, + use_typevar_operand, + requires_typevar_operand, + fixed_values) + ); + fmt.comment(format!("Constraints=[{}]", constraints + .iter() + .map(|x| format!("'{x}'")) + .collect::>() + .join(", "))); + if let Some(poly) = &inst.polymorphic_info { + fmt.comment(format!("Polymorphic over {}", typeset_to_string(poly.ctrl_typevar.get_raw_typeset()))); + } + + // Compute the bit field encoding, c.f. instructions.rs. + assert!(fixed_results < 8 && fixed_values < 8, "Bit field encoding too tight"); + let mut flags = fixed_results; // 3 bits + if use_typevar_operand { + flags |= 1<<3; // 4th bit + } + if requires_typevar_operand { + flags |= 1<<4; // 5th bit + } + flags |= fixed_values << 5; // 6th bit and more + + fmt.line("OpcodeConstraints {"); + fmt.indent(|fmt| { + fmtln!(fmt, "flags: {:#04x},", flags); + fmtln!(fmt, "typeset_offset: {},", ctrl_typeset); + fmtln!(fmt, "constraint_offset: {},", constraint_offset); + }); + fmt.line("},"); + } + }); + fmtln!(fmt, "];"); + fmt.empty_line(); + + gen_typesets_table(&type_sets, fmt); + fmt.empty_line(); + + fmt.comment("Table of operand constraint sequences."); + fmtln!( + fmt, + "const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [", + operand_seqs.len() + ); + fmt.indent(|fmt| { + for constraint in operand_seqs.iter() { + fmtln!(fmt, "OperandConstraint::{},", constraint); + } + }); + fmtln!(fmt, "];"); +} + +/// Emit member initializers for an instruction format. +fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) { + // Immediate operands. + // We have local variables with the same names as the members. + for f in &format.imm_fields { + fmtln!(fmt, "{},", f.member); + } + + // Value operands. + if format.has_value_list { + fmt.line("args,"); + } else if format.num_value_operands == 1 { + fmt.line("arg: arg0,"); + } else if format.num_value_operands > 1 { + let mut args = Vec::new(); + for i in 0..format.num_value_operands { + args.push(format!("arg{i}")); + } + fmtln!(fmt, "args: [{}],", args.join(", ")); + } + + // Block operands + match format.num_block_operands { + 0 => (), + 1 => fmt.line("destination: block0"), + n => { + let mut blocks = Vec::new(); + for i in 0..n { + blocks.push(format!("block{i}")); + } + fmtln!(fmt, "blocks: [{}],", blocks.join(", ")); + } + } +} + +/// Emit a method for creating and inserting an instruction format. +/// +/// All instruction formats take an `opcode` argument and a `ctrl_typevar` argument for deducing +/// the result types. +fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) { + // Construct method arguments. + let mut args = vec![ + "self".to_string(), + "opcode: Opcode".into(), + "ctrl_typevar: Type".into(), + ]; + + // Normal operand arguments. Start with the immediate operands. + for f in &format.imm_fields { + args.push(format!("{}: {}", f.member, f.kind.rust_type)); + } + + // Then the block operands. + args.extend((0..format.num_block_operands).map(|i| format!("block{i}: ir::BlockCall"))); + + // Then the value operands. + if format.has_value_list { + // Take all value arguments as a finished value list. The value lists + // are created by the individual instruction constructors. + args.push("args: ir::ValueList".into()); + } else { + // Take a fixed number of value operands. + for i in 0..format.num_value_operands { + args.push(format!("arg{i}: Value")); + } + } + + let proto = format!( + "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)", + format.name, + args.join(", ") + ); + + let imms_need_masking = format + .imm_fields + .iter() + .any(|f| f.kind.rust_type == "ir::immediates::Imm64"); + + fmt.doc_comment(format.to_string()); + fmt.line("#[allow(non_snake_case)]"); + fmtln!(fmt, "fn {} {{", proto); + fmt.indent(|fmt| { + // Generate the instruction data. + fmtln!( + fmt, + "let{} data = ir::InstructionData::{} {{", + if imms_need_masking { " mut" } else { "" }, + format.name + ); + fmt.indent(|fmt| { + fmt.line("opcode,"); + gen_member_inits(format, fmt); + }); + fmtln!(fmt, "};"); + + if imms_need_masking { + fmtln!(fmt, "data.mask_immediates(ctrl_typevar);"); + } + + // Assert that this opcode belongs to this format + fmtln!(fmt, "debug_assert_eq!(opcode.format(), InstructionFormat::from(&data), \"Wrong InstructionFormat for Opcode: {opcode}\");"); + + fmt.line("self.build(data, ctrl_typevar)"); + }); + fmtln!(fmt, "}"); +} + +/// Emit a method for generating the instruction `inst`. +/// +/// The method will create and insert an instruction, then return the result values, or the +/// instruction reference itself for instructions that don't have results. +fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter) { + // Construct method arguments. + let mut args = vec![String::new()]; + + let mut args_doc = Vec::new(); + let mut rets_doc = Vec::new(); + + // The controlling type variable will be inferred from the input values if + // possible. Otherwise, it is the first method argument. + if let Some(poly) = &inst.polymorphic_info { + if !poly.use_typevar_operand { + args.push(format!("{}: crate::ir::Type", poly.ctrl_typevar.name)); + args_doc.push(format!( + "- {} (controlling type variable): {}", + poly.ctrl_typevar.name, poly.ctrl_typevar.doc + )); + } + } + + let mut tmpl_types = Vec::new(); + let mut into_args = Vec::new(); + let mut block_args = Vec::new(); + for op in &inst.operands_in { + if op.kind.is_block() { + args.push(format!("{}_label: {}", op.name, "ir::Block")); + args_doc.push(format!( + "- {}_label: {}", + op.name, "Destination basic block" + )); + + args.push(format!("{}_args: {}", op.name, "&[Value]")); + args_doc.push(format!("- {}_args: {}", op.name, "Block arguments")); + + block_args.push(op); + } else { + let t = if op.is_immediate() { + let t = format!("T{}", tmpl_types.len() + 1); + tmpl_types.push(format!("{}: Into<{}>", t, op.kind.rust_type)); + into_args.push(op.name); + t + } else { + op.kind.rust_type.to_string() + }; + args.push(format!("{}: {}", op.name, t)); + args_doc.push(format!("- {}: {}", op.name, op.doc())); + } + } + + // We need to mutate `self` if this instruction accepts a value list, or will construct + // BlockCall values. + if format.has_value_list || !block_args.is_empty() { + args[0].push_str("mut self"); + } else { + args[0].push_str("self"); + } + + for op in &inst.operands_out { + rets_doc.push(format!("- {}: {}", op.name, op.doc())); + } + + let rtype = match inst.value_results.len() { + 0 => "Inst".into(), + 1 => "Value".into(), + _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")), + }; + + let tmpl = if !tmpl_types.is_empty() { + format!("<{}>", tmpl_types.join(", ")) + } else { + "".into() + }; + + let proto = format!( + "{}{}({}) -> {}", + inst.snake_name(), + tmpl, + args.join(", "), + rtype + ); + + fmt.doc_comment(&inst.doc); + if !args_doc.is_empty() { + fmt.line("///"); + fmt.doc_comment("Inputs:"); + fmt.line("///"); + for doc_line in args_doc { + fmt.doc_comment(doc_line); + } + } + if !rets_doc.is_empty() { + fmt.line("///"); + fmt.doc_comment("Outputs:"); + fmt.line("///"); + for doc_line in rets_doc { + fmt.doc_comment(doc_line); + } + } + + fmt.line("#[allow(non_snake_case)]"); + fmtln!(fmt, "fn {} {{", proto); + fmt.indent(|fmt| { + // Convert all of the `Into<>` arguments. + for arg in into_args { + fmtln!(fmt, "let {} = {}.into();", arg, arg); + } + + // Convert block references + for op in block_args { + fmtln!( + fmt, + "let {0} = self.data_flow_graph_mut().block_call({0}_label, {0}_args);", + op.name + ); + } + + // Arguments for instruction constructor. + let first_arg = format!("Opcode::{}", inst.camel_name); + let mut args = vec![first_arg.as_str()]; + if let Some(poly) = &inst.polymorphic_info { + if poly.use_typevar_operand { + // Infer the controlling type variable from the input operands. + let op_num = inst.value_opnums[format.typevar_operand.unwrap()]; + fmtln!( + fmt, + "let ctrl_typevar = self.data_flow_graph().value_type({});", + inst.operands_in[op_num].name + ); + + // The format constructor will resolve the result types from the type var. + args.push("ctrl_typevar"); + } else { + // This was an explicit method argument. + args.push(&poly.ctrl_typevar.name); + } + } else { + // No controlling type variable needed. + args.push("types::INVALID"); + } + + // Now add all of the immediate operands to the constructor arguments. + for &op_num in &inst.imm_opnums { + args.push(inst.operands_in[op_num].name); + } + + // Finally, the value operands. + if format.has_value_list { + // We need to build a value list with all the arguments. + fmt.line("let mut vlist = ir::ValueList::default();"); + args.push("vlist"); + fmt.line("{"); + fmt.indent(|fmt| { + fmt.line("let pool = &mut self.data_flow_graph_mut().value_lists;"); + for op in &inst.operands_in { + if op.is_value() { + fmtln!(fmt, "vlist.push({}, pool);", op.name); + } else if op.is_varargs() { + fmtln!(fmt, "vlist.extend({}.iter().cloned(), pool);", op.name); + } + } + }); + fmt.line("}"); + } else { + // With no value list, we're guaranteed to just have a set of fixed value operands. + for &op_num in &inst.value_opnums { + args.push(inst.operands_in[op_num].name); + } + } + + // Call to the format constructor, + let fcall = format!("self.{}({})", format.name, args.join(", ")); + + if inst.value_results.is_empty() { + fmtln!(fmt, "{}.0", fcall); + return; + } + + fmtln!(fmt, "let (inst, dfg) = {};", fcall); + if inst.value_results.len() == 1 { + fmt.line("dfg.first_result(inst)"); + } else { + fmtln!( + fmt, + "let results = &dfg.inst_results(inst)[0..{}];", + inst.value_results.len() + ); + fmtln!( + fmt, + "({})", + inst.value_results + .iter() + .enumerate() + .map(|(i, _)| format!("results[{i}]")) + .collect::>() + .join(", ") + ); + } + }); + fmtln!(fmt, "}") +} + +/// Generate a Builder trait with methods for all instructions. +fn gen_builder( + instructions: &AllInstructions, + formats: &[Rc], + fmt: &mut Formatter, +) { + fmt.doc_comment( + r#" + Convenience methods for building instructions. + + The `InstBuilder` trait has one method per instruction opcode for + conveniently constructing the instruction with minimum arguments. + Polymorphic instructions infer their result types from the input + arguments when possible. In some cases, an explicit `ctrl_typevar` + argument is required. + + The opcode methods return the new instruction's result values, or + the `Inst` itself for instructions that don't have any results. + + There is also a method per instruction format. These methods all + return an `Inst`. + "#, + ); + fmt.line("pub trait InstBuilder<'f>: InstBuilderBase<'f> {"); + fmt.indent(|fmt| { + for inst in instructions.iter() { + gen_inst_builder(inst, &inst.format, fmt); + fmt.empty_line(); + } + for (i, format) in formats.iter().enumerate() { + gen_format_constructor(format, fmt); + if i + 1 != formats.len() { + fmt.empty_line(); + } + } + }); + fmt.line("}"); +} + +pub(crate) fn generate( + formats: &[Rc], + all_inst: &AllInstructions, + opcode_filename: &str, + inst_builder_filename: &str, + out_dir: &std::path::Path, +) -> Result<(), error::Error> { + // Opcodes. + let mut fmt = Formatter::new(); + gen_formats(&formats, &mut fmt); + gen_instruction_data(&formats, &mut fmt); + fmt.empty_line(); + gen_instruction_data_impl(&formats, &mut fmt); + fmt.empty_line(); + gen_opcodes(all_inst, &mut fmt); + fmt.empty_line(); + gen_type_constraints(all_inst, &mut fmt); + fmt.update_file(opcode_filename, out_dir)?; + + // Instruction builder. + let mut fmt = Formatter::new(); + gen_builder(all_inst, &formats, &mut fmt); + fmt.update_file(inst_builder_filename, out_dir)?; + + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/gen_isle.rs b/deps/crates/vendor/cranelift-codegen-meta/src/gen_isle.rs new file mode 100644 index 00000000000000..e48285bfeeb0da --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/gen_isle.rs @@ -0,0 +1,519 @@ +use std::rc::Rc; + +use crate::cdsl::formats::InstructionFormat; +use crate::cdsl::instructions::AllInstructions; +use crate::error; +use crate::srcgen::Formatter; + +/// Which ISLE target are we generating code for? +#[derive(Clone, Copy, PartialEq, Eq)] +enum IsleTarget { + /// Generating code for instruction selection and lowering. + Lower, + /// Generating code for CLIF to CLIF optimizations. + Opt, +} + +fn gen_common_isle( + formats: &[Rc], + instructions: &AllInstructions, + fmt: &mut Formatter, + isle_target: IsleTarget, +) { + use std::collections::{BTreeMap, BTreeSet}; + use std::fmt::Write; + + use crate::cdsl::formats::FormatField; + + fmt.multi_line( + r#" +;; GENERATED BY `gen_isle`. DO NOT EDIT!!! +;; +;; This ISLE file defines all the external type declarations for Cranelift's +;; data structures that ISLE will process, such as `InstructionData` and +;; `Opcode`. + "#, + ); + fmt.empty_line(); + + // Collect and deduplicate the immediate types from the instruction fields. + let rust_name = |f: &FormatField| f.kind.rust_type.rsplit("::").next().unwrap(); + let fields = |f: &FormatField| f.kind.fields.clone(); + let immediate_types: BTreeMap<_, _> = formats + .iter() + .flat_map(|f| { + f.imm_fields + .iter() + .map(|i| (rust_name(i), fields(i))) + .collect::>() + }) + .collect(); + + // Separate the `enum` immediates (e.g., `FloatCC`) from other kinds of + // immediates. + let (enums, others): (BTreeMap<_, _>, BTreeMap<_, _>) = immediate_types + .iter() + .partition(|(_, field)| field.enum_values().is_some()); + + // Generate all the extern type declarations we need for the non-`enum` + // immediates. + fmt.line(";;;; Extern type declarations for immediates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + fmt.empty_line(); + for ty in others.keys() { + fmtln!(fmt, "(type {} (primitive {}))", ty, ty); + } + fmt.empty_line(); + + // Generate the `enum` immediates, expanding all of the available variants + // into ISLE. + for (name, field) in enums { + let field = field.enum_values().expect("only enums considered here"); + let variants = field.values().cloned().collect(); + gen_isle_enum(name, variants, fmt) + } + + // Generate all of the value arrays we need for `InstructionData` as well as + // the constructors and extractors for them. + fmt.line(";;;; Value Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + fmt.empty_line(); + let value_array_arities: BTreeSet<_> = formats + .iter() + .filter(|f| f.typevar_operand.is_some() && !f.has_value_list && f.num_value_operands != 1) + .map(|f| f.num_value_operands) + .collect(); + for n in value_array_arities { + fmtln!(fmt, ";; ISLE representation of `[Value; {}]`.", n); + fmtln!(fmt, "(type ValueArray{} extern (enum))", n); + fmt.empty_line(); + + fmtln!( + fmt, + "(decl value_array_{} ({}) ValueArray{})", + n, + (0..n).map(|_| "Value").collect::>().join(" "), + n + ); + fmtln!( + fmt, + "(extern constructor value_array_{} pack_value_array_{})", + n, + n + ); + fmtln!( + fmt, + "(extern extractor infallible value_array_{} unpack_value_array_{})", + n, + n + ); + fmt.empty_line(); + } + + // Generate all of the block arrays we need for `InstructionData` as well as + // the constructors and extractors for them. + fmt.line(";;;; Block Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + fmt.empty_line(); + let block_array_arities: BTreeSet<_> = formats + .iter() + .filter(|f| f.num_block_operands > 1) + .map(|f| f.num_block_operands) + .collect(); + for n in block_array_arities { + fmtln!(fmt, ";; ISLE representation of `[BlockCall; {}]`.", n); + fmtln!(fmt, "(type BlockArray{} extern (enum))", n); + fmt.empty_line(); + + fmtln!( + fmt, + "(decl block_array_{0} ({1}) BlockArray{0})", + n, + (0..n).map(|_| "BlockCall").collect::>().join(" ") + ); + + fmtln!( + fmt, + "(extern constructor block_array_{0} pack_block_array_{0})", + n + ); + + fmtln!( + fmt, + "(extern extractor infallible block_array_{0} unpack_block_array_{0})", + n + ); + fmt.empty_line(); + } + + // Generate the extern type declaration for `Opcode`. + fmt.line(";;;; `Opcode` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + fmt.empty_line(); + fmt.line("(type Opcode extern"); + fmt.indent(|fmt| { + fmt.line("(enum"); + fmt.indent(|fmt| { + for inst in instructions { + fmtln!(fmt, "{}", inst.camel_name); + } + }); + fmt.line(")"); + }); + fmt.line(")"); + fmt.empty_line(); + + // Generate the extern type declaration for `InstructionData`. + fmtln!( + fmt, + ";;;; `InstructionData` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", + ); + fmt.empty_line(); + fmtln!(fmt, "(type InstructionData extern"); + fmt.indent(|fmt| { + fmt.line("(enum"); + fmt.indent(|fmt| { + for format in formats { + let mut s = format!("({} (opcode Opcode)", format.name); + if format.has_value_list { + s.push_str(" (args ValueList)"); + } else if format.num_value_operands == 1 { + s.push_str(" (arg Value)"); + } else if format.num_value_operands > 1 { + write!(&mut s, " (args ValueArray{})", format.num_value_operands).unwrap(); + } + + match format.num_block_operands { + 0 => (), + 1 => write!(&mut s, " (destination BlockCall)").unwrap(), + n => write!(&mut s, " (blocks BlockArray{n})").unwrap(), + } + + for field in &format.imm_fields { + write!( + &mut s, + " ({} {})", + field.member, + field.kind.rust_type.rsplit("::").next().unwrap() + ) + .unwrap(); + } + s.push(')'); + fmt.line(&s); + } + }); + fmt.line(")"); + }); + fmt.line(")"); + fmt.empty_line(); + + // Generate the helper extractors for each opcode's full instruction. + fmtln!( + fmt, + ";;;; Extracting Opcode, Operands, and Immediates from `InstructionData` ;;;;;;;;", + ); + fmt.empty_line(); + let ret_ty = match isle_target { + IsleTarget::Lower => "Inst", + IsleTarget::Opt => "Value", + }; + for inst in instructions { + if isle_target == IsleTarget::Opt + && (inst.format.has_value_list || inst.value_results.len() != 1) + { + continue; + } + + fmtln!( + fmt, + "(decl {} ({}{}) {})", + inst.name, + match isle_target { + IsleTarget::Lower => "", + IsleTarget::Opt => "Type ", + }, + inst.operands_in + .iter() + .map(|o| { + let ty = o.kind.rust_type; + if ty == "&[Value]" { + "ValueSlice" + } else { + ty.rsplit("::").next().unwrap() + } + }) + .collect::>() + .join(" "), + ret_ty + ); + fmtln!(fmt, "(extractor"); + fmt.indent(|fmt| { + fmtln!( + fmt, + "({} {}{})", + inst.name, + match isle_target { + IsleTarget::Lower => "", + IsleTarget::Opt => "ty ", + }, + inst.operands_in + .iter() + .map(|o| { o.name }) + .collect::>() + .join(" ") + ); + + let mut s = format!( + "(inst_data{} (InstructionData.{} (Opcode.{})", + match isle_target { + IsleTarget::Lower => "", + IsleTarget::Opt => " ty", + }, + inst.format.name, + inst.camel_name + ); + + // Value and varargs operands. + if inst.format.has_value_list { + // The instruction format uses a value list, but the + // instruction itself might have not only a `&[Value]` + // varargs operand, but also one or more `Value` operands as + // well. If this is the case, then we need to read them off + // the front of the `ValueList`. + let values: Vec<_> = inst + .operands_in + .iter() + .filter(|o| o.is_value()) + .map(|o| o.name) + .collect(); + let varargs = inst + .operands_in + .iter() + .find(|o| o.is_varargs()) + .unwrap() + .name; + if values.is_empty() { + write!(&mut s, " (value_list_slice {varargs})").unwrap(); + } else { + write!( + &mut s, + " (unwrap_head_value_list_{} {} {})", + values.len(), + values.join(" "), + varargs + ) + .unwrap(); + } + } else if inst.format.num_value_operands == 1 { + write!( + &mut s, + " {}", + inst.operands_in.iter().find(|o| o.is_value()).unwrap().name + ) + .unwrap(); + } else if inst.format.num_value_operands > 1 { + let values = inst + .operands_in + .iter() + .filter(|o| o.is_value()) + .map(|o| o.name) + .collect::>(); + assert_eq!(values.len(), inst.format.num_value_operands); + let values = values.join(" "); + write!( + &mut s, + " (value_array_{} {})", + inst.format.num_value_operands, values, + ) + .unwrap(); + } + + // Immediates. + let imm_operands: Vec<_> = inst + .operands_in + .iter() + .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block()) + .collect(); + assert_eq!(imm_operands.len(), inst.format.imm_fields.len(),); + for op in imm_operands { + write!(&mut s, " {}", op.name).unwrap(); + } + + // Blocks. + let block_operands: Vec<_> = inst + .operands_in + .iter() + .filter(|o| o.kind.is_block()) + .collect(); + assert_eq!(block_operands.len(), inst.format.num_block_operands); + assert!(block_operands.len() <= 2); + + if !block_operands.is_empty() { + if block_operands.len() == 1 { + write!(&mut s, " {}", block_operands[0].name).unwrap(); + } else { + let blocks: Vec<_> = block_operands.iter().map(|o| o.name).collect(); + let blocks = blocks.join(" "); + write!( + &mut s, + " (block_array_{} {})", + inst.format.num_block_operands, blocks, + ) + .unwrap(); + } + } + + s.push_str("))"); + fmt.line(&s); + }); + fmt.line(")"); + + // Generate a constructor if this is the mid-end prelude. + if isle_target == IsleTarget::Opt { + fmtln!( + fmt, + "(rule ({} ty {})", + inst.name, + inst.operands_in + .iter() + .map(|o| o.name) + .collect::>() + .join(" ") + ); + fmt.indent(|fmt| { + let mut s = format!( + "(make_inst ty (InstructionData.{} (Opcode.{})", + inst.format.name, inst.camel_name + ); + + // Handle values. Note that we skip generating + // constructors for any instructions with variadic + // value lists. This is fine for the mid-end because + // in practice only calls and branches (for branch + // args) use this functionality, and neither can + // really be optimized or rewritten in the mid-end + // (currently). + // + // As a consequence, we only have to handle the + // one-`Value` case, in which the `Value` is directly + // in the `InstructionData`, and the multiple-`Value` + // case, in which the `Value`s are in a + // statically-sized array (e.g. `[Value; 2]` for a + // binary op). + assert!(!inst.format.has_value_list); + if inst.format.num_value_operands == 1 { + write!( + &mut s, + " {}", + inst.operands_in.iter().find(|o| o.is_value()).unwrap().name + ) + .unwrap(); + } else if inst.format.num_value_operands > 1 { + // As above, get all bindings together, and pass + // to a sub-term; here we use a constructor to + // build the value array. + let values = inst + .operands_in + .iter() + .filter(|o| o.is_value()) + .map(|o| o.name) + .collect::>(); + assert_eq!(values.len(), inst.format.num_value_operands); + let values = values.join(" "); + write!( + &mut s, + " (value_array_{}_ctor {})", + inst.format.num_value_operands, values + ) + .unwrap(); + } + + if inst.format.num_block_operands > 0 { + let blocks: Vec<_> = inst + .operands_in + .iter() + .filter(|o| o.kind.is_block()) + .map(|o| o.name) + .collect(); + if inst.format.num_block_operands == 1 { + write!(&mut s, " {}", blocks.first().unwrap(),).unwrap(); + } else { + write!( + &mut s, + " (block_array_{} {})", + inst.format.num_block_operands, + blocks.join(" ") + ) + .unwrap(); + } + } + + // Immediates (non-value args). + for o in inst + .operands_in + .iter() + .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block()) + { + write!(&mut s, " {}", o.name).unwrap(); + } + s.push_str("))"); + fmt.line(&s); + }); + fmt.line(")"); + } + + fmt.empty_line(); + } +} + +fn gen_opt_isle( + formats: &[Rc], + instructions: &AllInstructions, + fmt: &mut Formatter, +) { + gen_common_isle(formats, instructions, fmt, IsleTarget::Opt); +} + +fn gen_lower_isle( + formats: &[Rc], + instructions: &AllInstructions, + fmt: &mut Formatter, +) { + gen_common_isle(formats, instructions, fmt, IsleTarget::Lower); +} + +/// Generate an `enum` immediate in ISLE. +fn gen_isle_enum(name: &str, mut variants: Vec<&str>, fmt: &mut Formatter) { + variants.sort(); + let prefix = format!(";;;; Enumerated Immediate: {name} "); + fmtln!(fmt, "{:;<80}", prefix); + fmt.empty_line(); + fmtln!(fmt, "(type {} extern", name); + fmt.indent(|fmt| { + fmt.line("(enum"); + fmt.indent(|fmt| { + for variant in variants { + fmtln!(fmt, "{}", variant); + } + }); + fmt.line(")"); + }); + fmt.line(")"); + fmt.empty_line(); +} + +pub(crate) fn generate( + formats: &[Rc], + all_inst: &AllInstructions, + isle_opt_filename: &str, + isle_lower_filename: &str, + isle_dir: &std::path::Path, +) -> Result<(), error::Error> { + // ISLE DSL: mid-end ("opt") generated bindings. + let mut fmt = Formatter::new(); + gen_opt_isle(&formats, all_inst, &mut fmt); + fmt.update_file(isle_opt_filename, isle_dir)?; + + // ISLE DSL: lowering generated bindings. + let mut fmt = Formatter::new(); + gen_lower_isle(&formats, all_inst, &mut fmt); + fmt.update_file(isle_lower_filename, isle_dir)?; + + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/gen_settings.rs b/deps/crates/vendor/cranelift-codegen-meta/src/gen_settings.rs new file mode 100644 index 00000000000000..3d9a4e00cff58b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/gen_settings.rs @@ -0,0 +1,505 @@ +//! Generate the ISA-specific settings. +use std::collections::HashMap; + +use crate::constant_hash::generate_table; +use cranelift_codegen_shared::constant_hash::simple_hash; + +use crate::cdsl::camel_case; +use crate::cdsl::settings::{ + BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting, +}; +use crate::error; +use crate::srcgen::{Formatter, Match}; +use crate::unique_table::UniqueSeqTable; + +pub(crate) enum ParentGroup { + None, + Shared, +} + +/// Emits the constructor of the Flags structure. +fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) { + let args = match parent { + ParentGroup::None => "builder: Builder", + ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder", + }; + fmtln!(fmt, "impl Flags {"); + fmt.indent(|fmt| { + fmt.doc_comment(format!("Create flags {} settings group.", group.name)); + fmtln!(fmt, "#[allow(unused_variables)]"); + fmtln!(fmt, "pub fn new({}) -> Self {{", args); + fmt.indent(|fmt| { + fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name); + fmtln!( + fmt, + "let mut {} = Self {{ bytes: [0; {}] }};", + group.name, + group.byte_size() + ); + fmtln!( + fmt, + "debug_assert_eq!(bvec.len(), {});", + group.settings_size + ); + fmtln!( + fmt, + "{}.bytes[0..{}].copy_from_slice(&bvec);", + group.name, + group.settings_size + ); + + // Now compute the predicates. + for p in &group.predicates { + fmt.comment(format!("Precompute #{}.", p.number)); + fmtln!(fmt, "if {} {{", p.render(group)); + fmt.indent(|fmt| { + fmtln!( + fmt, + "{}.bytes[{}] |= 1 << {};", + group.name, + group.bool_start_byte_offset + p.number / 8, + p.number % 8 + ); + }); + fmtln!(fmt, "}"); + } + + fmtln!(fmt, group.name); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); +} + +/// Generates the `iter` function. +fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) { + fmtln!(fmt, "impl Flags {"); + fmt.indent(|fmt| { + fmt.doc_comment("Iterates the setting values."); + fmtln!(fmt, "pub fn iter(&self) -> impl Iterator {"); + fmt.indent(|fmt| { + fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size); + fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size); + fmtln!(fmt, "DESCRIPTORS.iter().filter_map(move |d| {"); + fmt.indent(|fmt| { + fmtln!(fmt, "let values = match &d.detail {"); + fmt.indent(|fmt| { + fmtln!(fmt, "detail::Detail::Preset => return None,"); + fmtln!(fmt, "detail::Detail::Enum { last, enumerators } => Some(TEMPLATE.enums(*last, *enumerators)),"); + fmtln!(fmt, "_ => None"); + }); + fmtln!(fmt, "};"); + fmtln!(fmt, "Some(Value{ name: d.name, detail: d.detail, values, value: bytes[d.offset as usize] })"); + }); + fmtln!(fmt, "})"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); +} + +/// Generates a `all()` function with all options for this enum +fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) { + fmtln!( + fmt, + "/// Returns a slice with all possible [{}] values.", + name + ); + fmtln!(fmt, "pub fn all() -> &'static [{}] {{", name); + fmt.indent(|fmt| { + fmtln!(fmt, "&["); + fmt.indent(|fmt| { + for v in values.iter() { + fmtln!(fmt, "Self::{},", camel_case(v)); + } + }); + fmtln!(fmt, "]"); + }); + fmtln!(fmt, "}"); +} + +/// Emit Display and FromStr implementations for enum settings. +fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) { + fmtln!(fmt, "impl fmt::Display for {} {{", name); + fmt.indent(|fmt| { + fmtln!( + fmt, + "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {" + ); + fmt.indent(|fmt| { + fmtln!(fmt, "f.write_str(match *self {"); + fmt.indent(|fmt| { + for v in values.iter() { + fmtln!(fmt, "Self::{} => \"{}\",", camel_case(v), v); + } + }); + fmtln!(fmt, "})"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); + + fmtln!(fmt, "impl core::str::FromStr for {} {{", name); + fmt.indent(|fmt| { + fmtln!(fmt, "type Err = ();"); + fmtln!(fmt, "fn from_str(s: &str) -> Result {"); + fmt.indent(|fmt| { + fmtln!(fmt, "match s {"); + fmt.indent(|fmt| { + for v in values.iter() { + fmtln!(fmt, "\"{}\" => Ok(Self::{}),", v, camel_case(v)); + } + fmtln!(fmt, "_ => Err(()),"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); +} + +/// Emit real enum for the Enum settings. +fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) { + for setting in group.settings.iter() { + let values = match setting.specific { + SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue, + SpecificSetting::Enum(ref values) => values, + }; + let name = camel_case(setting.name); + + fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name)); + fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]"); + fmtln!(fmt, "pub enum {} {{", name); + fmt.indent(|fmt| { + for v in values.iter() { + fmt.doc_comment(format!("`{v}`.")); + fmtln!(fmt, "{},", camel_case(v)); + } + }); + fmtln!(fmt, "}"); + + fmtln!(fmt, "impl {} {{", name); + fmt.indent(|fmt| { + gen_enum_all(&name, values, fmt); + }); + fmtln!(fmt, "}"); + + gen_to_and_from_str(&name, values, fmt); + } +} + +/// Emit a getter function for `setting`. +fn gen_getter(setting: &Setting, fmt: &mut Formatter) { + fmt.doc_comment(format!("{}\n{}", setting.description, setting.comment)); + match setting.specific { + SpecificSetting::Bool(BoolSetting { + predicate_number, .. + }) => { + fmtln!(fmt, "pub fn {}(&self) -> bool {{", setting.name); + fmt.indent(|fmt| { + fmtln!(fmt, "self.numbered_predicate({})", predicate_number); + }); + fmtln!(fmt, "}"); + } + SpecificSetting::Enum(ref values) => { + let ty = camel_case(setting.name); + fmtln!(fmt, "pub fn {}(&self) -> {} {{", setting.name, ty); + fmt.indent(|fmt| { + let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset)); + for (i, v) in values.iter().enumerate() { + m.arm_no_fields(format!("{i}"), format!("{}::{}", ty, camel_case(v))); + } + m.arm_no_fields("_", "panic!(\"Invalid enum value\")"); + fmt.add_match(m); + }); + fmtln!(fmt, "}"); + } + SpecificSetting::Num(_) => { + fmtln!(fmt, "pub fn {}(&self) -> u8 {{", setting.name); + fmt.indent(|fmt| { + fmtln!(fmt, "self.bytes[{}]", setting.byte_offset); + }); + fmtln!(fmt, "}"); + } + } +} + +fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) { + fmt.doc_comment(format!("Computed predicate `{}`.", predicate.render(group))); + fmtln!(fmt, "pub fn {}(&self) -> bool {{", predicate.name); + fmt.indent(|fmt| { + fmtln!(fmt, "self.numbered_predicate({})", predicate.number); + }); + fmtln!(fmt, "}"); +} + +/// Emits getters for each setting value. +fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) { + fmt.doc_comment("User-defined settings."); + fmtln!(fmt, "#[allow(dead_code)]"); + fmtln!(fmt, "impl Flags {"); + fmt.indent(|fmt| { + fmt.doc_comment("Get a view of the boolean predicates."); + fmtln!( + fmt, + "pub fn predicate_view(&self) -> crate::settings::PredicateView {" + ); + fmt.indent(|fmt| { + fmtln!( + fmt, + "crate::settings::PredicateView::new(&self.bytes[{}..])", + group.bool_start_byte_offset + ); + }); + fmtln!(fmt, "}"); + + if !group.settings.is_empty() { + fmt.doc_comment("Dynamic numbered predicate getter."); + fmtln!(fmt, "fn numbered_predicate(&self, p: usize) -> bool {"); + fmt.indent(|fmt| { + fmtln!( + fmt, + "self.bytes[{} + p / 8] & (1 << (p % 8)) != 0", + group.bool_start_byte_offset + ); + }); + fmtln!(fmt, "}"); + } + + for setting in &group.settings { + gen_getter(setting, fmt); + } + for predicate in &group.predicates { + gen_pred_getter(predicate, group, fmt); + } + }); + fmtln!(fmt, "}"); +} + +#[derive(Hash, PartialEq, Eq)] +enum SettingOrPreset<'a> { + Setting(&'a Setting), + Preset(&'a Preset), +} + +impl<'a> SettingOrPreset<'a> { + fn name(&self) -> &str { + match *self { + SettingOrPreset::Setting(s) => s.name, + SettingOrPreset::Preset(p) => p.name, + } + } +} + +/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS. +fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) { + let mut enum_table = UniqueSeqTable::new(); + + let mut descriptor_index_map: HashMap = HashMap::new(); + + // Generate descriptors. + fmtln!( + fmt, + "static DESCRIPTORS: [detail::Descriptor; {}] = [", + group.settings.len() + group.presets.len() + ); + fmt.indent(|fmt| { + for (idx, setting) in group.settings.iter().enumerate() { + fmtln!(fmt, "detail::Descriptor {"); + fmt.indent(|fmt| { + fmtln!(fmt, "name: \"{}\",", setting.name); + fmtln!(fmt, "description: \"{}\",", setting.description); + fmtln!(fmt, "offset: {},", setting.byte_offset); + match setting.specific { + SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => { + fmtln!( + fmt, + "detail: detail::Detail::Bool {{ bit: {} }},", + bit_offset + ); + } + SpecificSetting::Enum(ref values) => { + let offset = enum_table.add(values); + fmtln!( + fmt, + "detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},", + values.len() - 1, + offset + ); + } + SpecificSetting::Num(_) => { + fmtln!(fmt, "detail: detail::Detail::Num,"); + } + } + + descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx); + }); + fmtln!(fmt, "},"); + } + + for (idx, preset) in group.presets.iter().enumerate() { + fmtln!(fmt, "detail::Descriptor {"); + fmt.indent(|fmt| { + fmtln!(fmt, "name: \"{}\",", preset.name); + fmtln!(fmt, "description: \"{}\",", preset.description); + fmtln!(fmt, "offset: {},", (idx as u8) * group.settings_size); + fmtln!(fmt, "detail: detail::Detail::Preset,"); + }); + fmtln!(fmt, "},"); + + let whole_idx = idx + group.settings.len(); + descriptor_index_map.insert(SettingOrPreset::Preset(preset), whole_idx); + } + }); + fmtln!(fmt, "];"); + + // Generate enumerators. + fmtln!(fmt, "static ENUMERATORS: [&str; {}] = [", enum_table.len()); + fmt.indent(|fmt| { + for enum_val in enum_table.iter() { + fmtln!(fmt, "\"{}\",", enum_val); + } + }); + fmtln!(fmt, "];"); + + // Generate hash table. + let mut hash_entries: Vec = Vec::new(); + hash_entries.extend(group.settings.iter().map(SettingOrPreset::Setting)); + hash_entries.extend(group.presets.iter().map(SettingOrPreset::Preset)); + + let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| { + simple_hash(entry.name()) + }); + fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len()); + fmt.indent(|fmt| { + for h in &hash_table { + match *h { + Some(setting_or_preset) => fmtln!( + fmt, + "{},", + &descriptor_index_map + .get(setting_or_preset) + .unwrap() + .to_string() + ), + None => fmtln!(fmt, "0xffff,"), + } + } + }); + fmtln!(fmt, "];"); + + // Generate presets. + fmtln!( + fmt, + "static PRESETS: [(u8, u8); {}] = [", + group.presets.len() * (group.settings_size as usize) + ); + fmt.indent(|fmt| { + for preset in &group.presets { + fmt.comment(format!( + "{}: {}", + preset.name, + preset.setting_names(group).collect::>().join(", ") + )); + for (mask, value) in preset.layout(group) { + fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value); + } + } + }); + fmtln!(fmt, "];"); +} + +fn gen_template(group: &SettingGroup, fmt: &mut Formatter) { + let mut default_bytes: Vec = vec![0; group.settings_size as usize]; + for setting in &group.settings { + *default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte(); + } + + let default_bytes: Vec = default_bytes.iter().map(|x| format!("{x:#04x}")).collect(); + let default_bytes_str = default_bytes.join(", "); + + fmtln!( + fmt, + "static TEMPLATE: detail::Template = detail::Template {" + ); + fmt.indent(|fmt| { + fmtln!(fmt, "name: \"{}\",", group.name); + fmtln!(fmt, "descriptors: &DESCRIPTORS,"); + fmtln!(fmt, "enumerators: &ENUMERATORS,"); + fmtln!(fmt, "hash_table: &HASH_TABLE,"); + fmtln!(fmt, "defaults: &[{}],", default_bytes_str); + fmtln!(fmt, "presets: &PRESETS,"); + }); + fmtln!(fmt, "};"); + + fmt.doc_comment(format!( + "Create a `settings::Builder` for the {} settings group.", + group.name + )); + fmtln!(fmt, "pub fn builder() -> Builder {"); + fmt.indent(|fmt| { + fmtln!(fmt, "Builder::new(&TEMPLATE)"); + }); + fmtln!(fmt, "}"); +} + +fn gen_display(group: &SettingGroup, fmt: &mut Formatter) { + fmtln!(fmt, "impl fmt::Display for Flags {"); + fmt.indent(|fmt| { + fmtln!( + fmt, + "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {" + ); + fmt.indent(|fmt| { + fmtln!(fmt, "writeln!(f, \"[{}]\")?;", group.name); + fmtln!(fmt, "for d in &DESCRIPTORS {"); + fmt.indent(|fmt| { + fmtln!(fmt, "if !d.detail.is_preset() {"); + fmt.indent(|fmt| { + fmtln!(fmt, "write!(f, \"{} = \", d.name)?;"); + fmtln!( + fmt, + "TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;", + ); + fmtln!(fmt, "writeln!(f)?;"); + }); + fmtln!(fmt, "}"); + }); + fmtln!(fmt, "}"); + fmtln!(fmt, "Ok(())"); + }); + fmtln!(fmt, "}") + }); + fmtln!(fmt, "}"); +} + +fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) { + // Generate struct. + fmtln!(fmt, "#[derive(Clone, Hash)]"); + fmt.doc_comment(format!("Flags group `{}`.", group.name)); + fmtln!(fmt, "pub struct Flags {"); + fmt.indent(|fmt| { + fmtln!(fmt, "bytes: [u8; {}],", group.byte_size()); + }); + fmtln!(fmt, "}"); + + gen_constructor(group, parent, fmt); + gen_iterator(group, fmt); + gen_enum_types(group, fmt); + gen_getters(group, fmt); + gen_descriptors(group, fmt); + gen_template(group, fmt); + gen_display(group, fmt); +} + +pub(crate) fn generate( + settings: &SettingGroup, + parent_group: ParentGroup, + filename: &str, + out_dir: &std::path::Path, +) -> Result<(), error::Error> { + let mut fmt = Formatter::new(); + gen_group(settings, parent_group, &mut fmt); + fmt.update_file(filename, out_dir)?; + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/gen_types.rs b/deps/crates/vendor/cranelift-codegen-meta/src/gen_types.rs new file mode 100644 index 00000000000000..e0e66a3de9be3d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/gen_types.rs @@ -0,0 +1,70 @@ +//! Generate sources with type info. +//! +//! This generates a `types.rs` file which is included in +//! `cranelift-codegen/ir/types.rs`. The file provides constant definitions for the +//! most commonly used types, including all of the scalar types. +//! +//! This ensures that the metaprogram and the generated program see the same +//! type numbering. + +use crate::cdsl::types as cdsl_types; +use crate::error; +use crate::srcgen; + +/// Emit a constant definition of a single value type. +fn emit_type(ty: &cdsl_types::ValueType, fmt: &mut srcgen::Formatter) { + let name = ty.to_string().to_uppercase(); + let number = ty.number(); + + fmt.doc_comment(&ty.doc()); + fmtln!(fmt, "pub const {}: Type = Type({:#x});\n", name, number); +} + +/// Emit definition for all vector types with `bits` total size. +fn emit_vectors(bits: u64, fmt: &mut srcgen::Formatter) { + let vec_size: u64 = bits / 8; + for vec in cdsl_types::ValueType::all_lane_types() + .map(|ty| (ty, cdsl_types::ValueType::from(ty).membytes())) + .filter(|&(_, lane_size)| lane_size != 0 && lane_size < vec_size) + .map(|(ty, lane_size)| (ty, vec_size / lane_size)) + .map(|(ty, lanes)| cdsl_types::VectorType::new(ty, lanes)) + { + emit_type(&cdsl_types::ValueType::from(vec), fmt); + } +} + +/// Emit definition for all dynamic vector types with `bits` total size. +fn emit_dynamic_vectors(bits: u64, fmt: &mut srcgen::Formatter) { + let vec_size: u64 = bits / 8; + for vec in cdsl_types::ValueType::all_lane_types() + .map(|ty| (ty, cdsl_types::ValueType::from(ty).membytes())) + .filter(|&(_, lane_size)| lane_size != 0 && lane_size < vec_size) + .map(|(ty, lane_size)| (ty, vec_size / lane_size)) + .map(|(ty, lanes)| cdsl_types::DynamicVectorType::new(ty, lanes)) + { + emit_type(&cdsl_types::ValueType::from(vec), fmt); + } +} + +/// Emit types using the given formatter object. +fn emit_types(fmt: &mut srcgen::Formatter) { + // Emit all of the lane types, such integers, floats, and booleans. + for ty in cdsl_types::ValueType::all_lane_types().map(cdsl_types::ValueType::from) { + emit_type(&ty, fmt); + } + + // Emit vector definitions for common SIMD sizes. + // Emit dynamic vector definitions. + for vec_size in &[16_u64, 32, 64, 128, 256, 512] { + emit_vectors(*vec_size, fmt); + emit_dynamic_vectors(*vec_size, fmt); + } +} + +/// Generate the types file. +pub(crate) fn generate(filename: &str, out_dir: &std::path::Path) -> Result<(), error::Error> { + let mut fmt = srcgen::Formatter::new(); + emit_types(&mut fmt); + fmt.update_file(filename, out_dir)?; + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/arm64.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/arm64.rs new file mode 100644 index 00000000000000..afad7d15468f7f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/arm64.rs @@ -0,0 +1,59 @@ +use crate::cdsl::isa::TargetIsa; +use crate::cdsl::settings::SettingGroupBuilder; + +pub(crate) fn define() -> TargetIsa { + let mut settings = SettingGroupBuilder::new("arm64"); + + settings.add_bool( + "has_lse", + "Has Large System Extensions (FEAT_LSE) support.", + "", + false, + ); + settings.add_bool( + "has_pauth", + "Has Pointer authentication (FEAT_PAuth) support; enables the use of \ + non-HINT instructions, but does not have an effect on code generation \ + by itself.", + "", + false, + ); + settings.add_bool( + "has_fp16", + "Use half-precision floating point (FEAT_FP16) instructions.", + "", + false, + ); + settings.add_bool( + "sign_return_address_all", + "If function return address signing is enabled, then apply it to all \ + functions; does not have an effect on code generation by itself.", + "", + false, + ); + settings.add_bool( + "sign_return_address", + "Use pointer authentication instructions to sign function return \ + addresses; HINT-space instructions using the A key are generated \ + and simple functions that do not use the stack are not affected \ + unless overridden by other settings.", + "", + false, + ); + settings.add_bool( + "sign_return_address_with_bkey", + "Use the B key with pointer authentication instructions instead of \ + the default A key; does not have an effect on code generation by \ + itself. Some platform ABIs may require this, for example.", + "", + false, + ); + settings.add_bool( + "use_bti", + "Use Branch Target Identification (FEAT_BTI) instructions.", + "", + false, + ); + + TargetIsa::new("arm64", settings.build()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/mod.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/mod.rs new file mode 100644 index 00000000000000..655b14a9c5a15f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/mod.rs @@ -0,0 +1,81 @@ +//! Define supported ISAs; includes ISA-specific instructions, encodings, registers, settings, etc. +use crate::cdsl::isa::TargetIsa; +use std::fmt; + +mod arm64; +mod pulley; +mod riscv64; +mod s390x; +pub(crate) mod x86; + +/// Represents known ISA target. +#[derive(PartialEq, Copy, Clone)] +pub enum Isa { + X86, + Arm64, + S390x, + Riscv64, + Pulley32, + Pulley64, +} + +impl Isa { + /// Creates isa target using name. + pub fn from_name(name: &str) -> Option { + Isa::all() + .iter() + .cloned() + .find(|isa| isa.to_string() == name) + } + + /// Creates isa target from arch. + pub fn from_arch(arch: &str) -> Option { + match arch { + "aarch64" => Some(Isa::Arm64), + "s390x" => Some(Isa::S390x), + x if ["x86_64", "i386", "i586", "i686"].contains(&x) => Some(Isa::X86), + "riscv64" | "riscv64gc" | "riscv64imac" => Some(Isa::Riscv64), + "pulley32" => Some(Isa::Pulley32), + "pulley64" => Some(Isa::Pulley64), + _ => None, + } + } + + /// Returns all supported isa targets. + pub fn all() -> &'static [Isa] { + &[ + Isa::X86, + Isa::Arm64, + Isa::S390x, + Isa::Riscv64, + Isa::Pulley32, + Isa::Pulley64, + ] + } +} + +impl fmt::Display for Isa { + // These names should be kept in sync with the crate features. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Isa::X86 => write!(f, "x86"), + Isa::Arm64 => write!(f, "arm64"), + Isa::S390x => write!(f, "s390x"), + Isa::Riscv64 => write!(f, "riscv64"), + Isa::Pulley32 => write!(f, "pulley32"), + Isa::Pulley64 => write!(f, "pulley64"), + } + } +} + +pub(crate) fn define(isas: &[Isa]) -> Vec { + isas.iter() + .map(|isa| match isa { + Isa::X86 => x86::define(), + Isa::Arm64 => arm64::define(), + Isa::S390x => s390x::define(), + Isa::Riscv64 => riscv64::define(), + Isa::Pulley32 | Isa::Pulley64 => pulley::define(), + }) + .collect() +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/pulley.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/pulley.rs new file mode 100644 index 00000000000000..a0ab5c203f8aa9 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/pulley.rs @@ -0,0 +1,20 @@ +use crate::cdsl::{isa::TargetIsa, settings::SettingGroupBuilder}; + +pub(crate) fn define() -> TargetIsa { + let mut settings = SettingGroupBuilder::new("pulley"); + settings.add_enum( + "pointer_width", + "The width of pointers for this Pulley target", + "Supported values:\n\ + * 'pointer32'\n\ + * 'pointer64'\n", + vec!["pointer32", "pointer64"], + ); + settings.add_bool( + "big_endian", + "Whether this is a big-endian target", + "Whether this is a big-endian target", + false, + ); + TargetIsa::new("pulley", settings.build()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/riscv64.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/riscv64.rs new file mode 100644 index 00000000000000..355a9125abfb9d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/riscv64.rs @@ -0,0 +1,181 @@ +use crate::cdsl::isa::TargetIsa; +use crate::cdsl::settings::{PredicateNode, SettingGroupBuilder}; + +macro_rules! define_zvl_ext { + (DEF: $settings:expr, $size:expr) => {{ + let name = concat!("has_zvl", $size, "b"); + let desc = concat!("has extension Zvl", $size, "b?"); + let comment = concat!( + "Zvl", + $size, + "b: Vector register has a minimum of ", + $size, + " bits" + ); + $settings.add_bool(&name, &desc, &comment, false) + }}; + ($settings:expr, $size:expr $(, $implies:expr)*) => {{ + let has_feature = define_zvl_ext!(DEF: $settings, $size); + + let name = concat!("zvl", $size, "b"); + let desc = concat!("Has a vector register size of at least ", $size, " bits"); + + let preset = $settings.add_preset(&name, &desc, preset!(has_feature $( && $implies )*)); + (has_feature, preset) + }}; +} + +pub(crate) fn define() -> TargetIsa { + let mut setting = SettingGroupBuilder::new("riscv64"); + + // We target a minimum of riscv64g. That means that we have the following extensions by default: + // + // * M (integer multiplication and division) + // * A (atomic instructions) + // * F (single-precision floating point) + // * D (double-precision floating point) + // * Zicsr (control and status register instructions) + // * Zifencei (instruction-fetch fence) + + let has_m = setting.add_bool( + "has_m", + "has extension M?", + "Integer multiplication and division", + true, + ); + let has_a = setting.add_bool("has_a", "has extension A?", "Atomic instructions", true); + let has_f = setting.add_bool( + "has_f", + "has extension F?", + "Single-precision floating point", + true, + ); + let has_d = setting.add_bool( + "has_d", + "has extension D?", + "Double-precision floating point", + true, + ); + + let _has_zfa = setting.add_bool( + "has_zfa", + "has extension Zfa?", + "Zfa: Extension for Additional Floating-Point Instructions", + false, + ); + + let _has_zfh = setting.add_bool( + "has_zfh", + "has extension Zfh?", + "Zfh: Half-Precision Floating-Point Instructions", + false, + ); + + let _has_v = setting.add_bool( + "has_v", + "has extension V?", + "Vector instruction support", + false, + ); + + let has_zca = setting.add_bool( + "has_zca", + "has extension Zca?", + "Zca is the C extension without floating point loads", + false, + ); + let has_zcd = setting.add_bool( + "has_zcd", + "has extension Zcd?", + "Zcd contains only the double precision floating point loads from the C extension", + false, + ); + setting.add_preset( + "has_c", + "Support for compressed instructions", + preset!(has_zca && has_zcd), + ); + + let _has_zcb = setting.add_bool( + "has_zcb", + "has extension Zcb?", + "Zcb: Extra compressed instructions", + false, + ); + + let _has_zbkb = setting.add_bool( + "has_zbkb", + "has extension zbkb?", + "Zbkb: Bit-manipulation for Cryptography", + false, + ); + let _has_zba = setting.add_bool( + "has_zba", + "has extension zba?", + "Zba: Address Generation", + false, + ); + let _has_zbb = setting.add_bool( + "has_zbb", + "has extension zbb?", + "Zbb: Basic bit-manipulation", + false, + ); + let _has_zbc = setting.add_bool( + "has_zbc", + "has extension zbc?", + "Zbc: Carry-less multiplication", + false, + ); + let _has_zbs = setting.add_bool( + "has_zbs", + "has extension zbs?", + "Zbs: Single-bit instructions", + false, + ); + let _has_zicond = setting.add_bool( + "has_zicond", + "has extension zicond?", + "ZiCond: Integer Conditional Operations", + false, + ); + + let has_zicsr = setting.add_bool( + "has_zicsr", + "has extension zicsr?", + "Zicsr: Control and Status Register (CSR) Instructions", + true, + ); + let has_zifencei = setting.add_bool( + "has_zifencei", + "has extension zifencei?", + "Zifencei: Instruction-Fetch Fence", + true, + ); + + // Zvl*: Minimum Vector Length Standard Extensions + // These extension specify the minimum number of bits in a vector register. + // Since it is a minimum, Zvl64b implies Zvl32b, Zvl128b implies Zvl64b, etc. + // The V extension supports a maximum of 64K bits in a single register. + // + // See: https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#181-zvl-minimum-vector-length-standard-extensions + let (_, zvl32b) = define_zvl_ext!(setting, 32); + let (_, zvl64b) = define_zvl_ext!(setting, 64, zvl32b); + let (_, zvl128b) = define_zvl_ext!(setting, 128, zvl64b); + let (_, zvl256b) = define_zvl_ext!(setting, 256, zvl128b); + let (_, zvl512b) = define_zvl_ext!(setting, 512, zvl256b); + let (_, zvl1024b) = define_zvl_ext!(setting, 1024, zvl512b); + let (_, zvl2048b) = define_zvl_ext!(setting, 2048, zvl1024b); + let (_, zvl4096b) = define_zvl_ext!(setting, 4096, zvl2048b); + let (_, zvl8192b) = define_zvl_ext!(setting, 8192, zvl4096b); + let (_, zvl16384b) = define_zvl_ext!(setting, 16384, zvl8192b); + let (_, zvl32768b) = define_zvl_ext!(setting, 32768, zvl16384b); + let (_, _zvl65536b) = define_zvl_ext!(setting, 65536, zvl32768b); + + setting.add_predicate( + "has_g", + predicate!(has_m && has_a && has_f && has_d && has_zicsr && has_zifencei), + ); + + TargetIsa::new("riscv64", setting.build()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/s390x.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/s390x.rs new file mode 100644 index 00000000000000..7a404d3d33fefc --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/s390x.rs @@ -0,0 +1,39 @@ +use crate::cdsl::isa::TargetIsa; +use crate::cdsl::settings::SettingGroupBuilder; + +pub(crate) fn define() -> TargetIsa { + let mut settings = SettingGroupBuilder::new("s390x"); + + // The baseline architecture for cranelift is z14 (arch12), + // so we list only facilities of later processors here. + + // z15 (arch13) facilities + let has_mie2 = settings.add_bool( + "has_mie2", + "Has Miscellaneous-Instruction-Extensions Facility 2 support.", + "", + false, + ); + let has_vxrs_ext2 = settings.add_bool( + "has_vxrs_ext2", + "Has Vector-Enhancements Facility 2 support.", + "", + false, + ); + + // Architecture level presets + settings.add_preset( + "arch13", + "Thirteenth Edition of the z/Architecture.", + preset!(has_mie2 && has_vxrs_ext2), + ); + + // Processor presets + settings.add_preset( + "z15", + "IBM z15 processor.", + preset!(has_mie2 && has_vxrs_ext2), + ); + + TargetIsa::new("s390x", settings.build()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isa/x86.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isa/x86.rs new file mode 100644 index 00000000000000..053d15c8f35704 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isa/x86.rs @@ -0,0 +1,447 @@ +use crate::cdsl::isa::TargetIsa; +use crate::cdsl::settings::{PredicateNode, SettingGroupBuilder}; + +pub(crate) fn define() -> TargetIsa { + let mut settings = SettingGroupBuilder::new("x86"); + + // CPUID.01H:ECX + let has_sse3 = settings.add_bool( + "has_sse3", + "Has support for SSE3.", + "SSE3: CPUID.01H:ECX.SSE3[bit 0]", + false, + ); + let has_ssse3 = settings.add_bool( + "has_ssse3", + "Has support for SSSE3.", + "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", + false, + ); + let has_cmpxchg16b = settings.add_bool( + "has_cmpxchg16b", + "Has support for CMPXCHG16b.", + "CMPXCHG16b: CPUID.01H:ECX.CMPXCHG16B[bit 13]", + false, + ); + let has_sse41 = settings.add_bool( + "has_sse41", + "Has support for SSE4.1.", + "SSE4.1: CPUID.01H:ECX.SSE4_1[bit 19]", + false, + ); + let has_sse42 = settings.add_bool( + "has_sse42", + "Has support for SSE4.2.", + "SSE4.2: CPUID.01H:ECX.SSE4_2[bit 20]", + false, + ); + let has_avx = settings.add_bool( + "has_avx", + "Has support for AVX.", + "AVX: CPUID.01H:ECX.AVX[bit 28]", + false, + ); + let has_avx2 = settings.add_bool( + "has_avx2", + "Has support for AVX2.", + "AVX2: CPUID.07H:EBX.AVX2[bit 5]", + false, + ); + let has_fma = settings.add_bool( + "has_fma", + "Has support for FMA.", + "FMA: CPUID.01H:ECX.FMA[bit 12]", + false, + ); + let has_avx512bitalg = settings.add_bool( + "has_avx512bitalg", + "Has support for AVX512BITALG.", + "AVX512BITALG: CPUID.07H:ECX.AVX512BITALG[bit 12]", + false, + ); + let has_avx512dq = settings.add_bool( + "has_avx512dq", + "Has support for AVX512DQ.", + "AVX512DQ: CPUID.07H:EBX.AVX512DQ[bit 17]", + false, + ); + let has_avx512vl = settings.add_bool( + "has_avx512vl", + "Has support for AVX512VL.", + "AVX512VL: CPUID.07H:EBX.AVX512VL[bit 31]", + false, + ); + let has_avx512vbmi = settings.add_bool( + "has_avx512vbmi", + "Has support for AVX512VMBI.", + "AVX512VBMI: CPUID.07H:ECX.AVX512VBMI[bit 1]", + false, + ); + let has_avx512f = settings.add_bool( + "has_avx512f", + "Has support for AVX512F.", + "AVX512F: CPUID.07H:EBX.AVX512F[bit 16]", + false, + ); + let has_popcnt = settings.add_bool( + "has_popcnt", + "Has support for POPCNT.", + "POPCNT: CPUID.01H:ECX.POPCNT[bit 23]", + false, + ); + + // CPUID.(EAX=07H, ECX=0H):EBX + let has_bmi1 = settings.add_bool( + "has_bmi1", + "Has support for BMI1.", + "BMI1: CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]", + false, + ); + let has_bmi2 = settings.add_bool( + "has_bmi2", + "Has support for BMI2.", + "BMI2: CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]", + false, + ); + + // CPUID.EAX=80000001H:ECX + let has_lzcnt = settings.add_bool( + "has_lzcnt", + "Has support for LZCNT.", + "LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]", + false, + ); + + settings.add_predicate("use_cmpxchg16b", predicate!(has_cmpxchg16b)); + settings.add_predicate("use_ssse3", predicate!(has_ssse3)); + settings.add_predicate("use_sse41", predicate!(has_sse41)); + settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42)); + settings.add_predicate("use_fma", predicate!(has_avx && has_fma)); + + settings.add_predicate("use_avx", predicate!(has_avx)); + settings.add_predicate("use_avx2", predicate!(has_avx && has_avx2)); + settings.add_predicate("use_avx512bitalg", predicate!(has_avx512bitalg)); + settings.add_predicate("use_avx512dq", predicate!(has_avx512dq)); + settings.add_predicate("use_avx512vl", predicate!(has_avx512vl)); + settings.add_predicate("use_avx512vbmi", predicate!(has_avx512vbmi)); + settings.add_predicate("use_avx512f", predicate!(has_avx512f)); + + settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42)); + settings.add_predicate("use_bmi1", predicate!(has_bmi1)); + settings.add_predicate("use_bmi2", predicate!(has_bmi2)); + settings.add_predicate("use_lzcnt", predicate!(has_lzcnt)); + + let sse3 = settings.add_preset("sse3", "SSE3 and earlier.", preset!(has_sse3)); + let ssse3 = settings.add_preset("ssse3", "SSSE3 and earlier.", preset!(sse3 && has_ssse3)); + let sse41 = settings.add_preset("sse41", "SSE4.1 and earlier.", preset!(ssse3 && has_sse41)); + let sse42 = settings.add_preset("sse42", "SSE4.2 and earlier.", preset!(sse41 && has_sse42)); + + // Presets corresponding to x86 CPUs. + // Features and architecture names are from LLVM's x86 presets: + // https://github.com/llvm/llvm-project/blob/d4493dd1ed58ac3f1eab0c4ca6e363e2b15bfd1c/llvm/lib/Target/X86/X86.td#L1300-L1643 + settings.add_preset( + "baseline", + "A baseline preset with no extensions enabled.", + preset!(), + ); + + // Intel CPUs + + // Netburst + settings.add_preset( + "nocona", + "Nocona microarchitecture.", + preset!(sse3 && has_cmpxchg16b), + ); + + // Intel Core 2 Solo/Duo + settings.add_preset( + "core2", + "Core 2 microarchitecture.", + preset!(sse3 && has_cmpxchg16b), + ); + settings.add_preset( + "penryn", + "Penryn microarchitecture.", + preset!(sse41 && has_cmpxchg16b), + ); + + // Intel Atom CPUs + let atom = settings.add_preset( + "atom", + "Atom microarchitecture.", + preset!(ssse3 && has_cmpxchg16b), + ); + settings.add_preset("bonnell", "Bonnell microarchitecture.", preset!(atom)); + let silvermont = settings.add_preset( + "silvermont", + "Silvermont microarchitecture.", + preset!(atom && sse42 && has_popcnt), + ); + settings.add_preset("slm", "Silvermont microarchitecture.", preset!(silvermont)); + let goldmont = settings.add_preset( + "goldmont", + "Goldmont microarchitecture.", + preset!(silvermont), + ); + settings.add_preset( + "goldmont-plus", + "Goldmont Plus microarchitecture.", + preset!(goldmont), + ); + let tremont = settings.add_preset("tremont", "Tremont microarchitecture.", preset!(goldmont)); + + let alderlake = settings.add_preset( + "alderlake", + "Alderlake microarchitecture.", + preset!(tremont && has_bmi1 && has_bmi2 && has_lzcnt && has_fma), + ); + let sierra_forest = settings.add_preset( + "sierraforest", + "Sierra Forest microarchitecture.", + preset!(alderlake), + ); + settings.add_preset( + "grandridge", + "Grandridge microarchitecture.", + preset!(sierra_forest), + ); + let nehalem = settings.add_preset( + "nehalem", + "Nehalem microarchitecture.", + preset!(sse42 && has_popcnt && has_cmpxchg16b), + ); + settings.add_preset("corei7", "Core i7 microarchitecture.", preset!(nehalem)); + let westmere = settings.add_preset("westmere", "Westmere microarchitecture.", preset!(nehalem)); + let sandy_bridge = settings.add_preset( + "sandybridge", + "Sandy Bridge microarchitecture.", + preset!(westmere && has_avx), + ); + settings.add_preset( + "corei7-avx", + "Core i7 AVX microarchitecture.", + preset!(sandy_bridge), + ); + let ivy_bridge = settings.add_preset( + "ivybridge", + "Ivy Bridge microarchitecture.", + preset!(sandy_bridge), + ); + settings.add_preset( + "core-avx-i", + "Intel Core CPU with 64-bit extensions.", + preset!(ivy_bridge), + ); + let haswell = settings.add_preset( + "haswell", + "Haswell microarchitecture.", + preset!(ivy_bridge && has_avx2 && has_bmi1 && has_bmi2 && has_fma && has_lzcnt), + ); + settings.add_preset( + "core-avx2", + "Intel Core CPU with AVX2 extensions.", + preset!(haswell), + ); + let broadwell = settings.add_preset( + "broadwell", + "Broadwell microarchitecture.", + preset!(haswell), + ); + let skylake = settings.add_preset("skylake", "Skylake microarchitecture.", preset!(broadwell)); + let knights_landing = settings.add_preset( + "knl", + "Knights Landing microarchitecture.", + preset!( + has_popcnt + && has_avx512f + && has_fma + && has_bmi1 + && has_bmi2 + && has_lzcnt + && has_cmpxchg16b + ), + ); + settings.add_preset( + "knm", + "Knights Mill microarchitecture.", + preset!(knights_landing), + ); + let skylake_avx512 = settings.add_preset( + "skylake-avx512", + "Skylake AVX512 microarchitecture.", + preset!(broadwell && has_avx512f && has_avx512dq && has_avx512vl), + ); + settings.add_preset( + "skx", + "Skylake AVX512 microarchitecture.", + preset!(skylake_avx512), + ); + let cascadelake = settings.add_preset( + "cascadelake", + "Cascade Lake microarchitecture.", + preset!(skylake_avx512), + ); + settings.add_preset( + "cooperlake", + "Cooper Lake microarchitecture.", + preset!(cascadelake), + ); + let cannonlake = settings.add_preset( + "cannonlake", + "Canon Lake microarchitecture.", + preset!(skylake && has_avx512f && has_avx512dq && has_avx512vl && has_avx512vbmi), + ); + let icelake_client = settings.add_preset( + "icelake-client", + "Ice Lake microarchitecture.", + preset!(cannonlake && has_avx512bitalg), + ); + // LLVM doesn't use the name "icelake" but Cranelift did in the past; alias it + settings.add_preset( + "icelake", + "Ice Lake microarchitecture", + preset!(icelake_client), + ); + let icelake_server = settings.add_preset( + "icelake-server", + "Ice Lake (server) microarchitecture.", + preset!(icelake_client), + ); + settings.add_preset( + "tigerlake", + "Tiger Lake microarchitecture.", + preset!(icelake_client), + ); + let sapphire_rapids = settings.add_preset( + "sapphirerapids", + "Sapphire Rapids microarchitecture.", + preset!(icelake_server), + ); + settings.add_preset( + "raptorlake", + "Raptor Lake microarchitecture.", + preset!(alderlake), + ); + settings.add_preset( + "meteorlake", + "Meteor Lake microarchitecture.", + preset!(alderlake), + ); + settings.add_preset( + "graniterapids", + "Granite Rapids microarchitecture.", + preset!(sapphire_rapids), + ); + + // AMD CPUs + + settings.add_preset("opteron", "Opteron microarchitecture.", preset!()); + settings.add_preset("k8", "K8 Hammer microarchitecture.", preset!()); + settings.add_preset("athlon64", "Athlon64 microarchitecture.", preset!()); + settings.add_preset("athlon-fx", "Athlon FX microarchitecture.", preset!()); + settings.add_preset( + "opteron-sse3", + "Opteron microarchitecture with support for SSE3 instructions.", + preset!(sse3 && has_cmpxchg16b), + ); + settings.add_preset( + "k8-sse3", + "K8 Hammer microarchitecture with support for SSE3 instructions.", + preset!(sse3 && has_cmpxchg16b), + ); + settings.add_preset( + "athlon64-sse3", + "Athlon 64 microarchitecture with support for SSE3 instructions.", + preset!(sse3 && has_cmpxchg16b), + ); + let barcelona = settings.add_preset( + "barcelona", + "Barcelona microarchitecture.", + preset!(has_popcnt && has_lzcnt && has_cmpxchg16b), + ); + settings.add_preset( + "amdfam10", + "AMD Family 10h microarchitecture", + preset!(barcelona), + ); + + let btver1 = settings.add_preset( + "btver1", + "Bobcat microarchitecture.", + preset!(ssse3 && has_lzcnt && has_popcnt && has_cmpxchg16b), + ); + settings.add_preset( + "btver2", + "Jaguar microarchitecture.", + preset!(btver1 && has_avx && has_bmi1), + ); + + let bdver1 = settings.add_preset( + "bdver1", + "Bulldozer microarchitecture", + preset!(has_lzcnt && has_popcnt && ssse3 && has_cmpxchg16b), + ); + let bdver2 = settings.add_preset( + "bdver2", + "Piledriver microarchitecture.", + preset!(bdver1 && has_bmi1), + ); + let bdver3 = settings.add_preset("bdver3", "Steamroller microarchitecture.", preset!(bdver2)); + settings.add_preset( + "bdver4", + "Excavator microarchitecture.", + preset!(bdver3 && has_avx2 && has_bmi2), + ); + + let znver1 = settings.add_preset( + "znver1", + "Zen (first generation) microarchitecture.", + preset!( + sse42 && has_popcnt && has_bmi1 && has_bmi2 && has_lzcnt && has_fma && has_cmpxchg16b + ), + ); + let znver2 = settings.add_preset( + "znver2", + "Zen (second generation) microarchitecture.", + preset!(znver1), + ); + let znver3 = settings.add_preset( + "znver3", + "Zen (third generation) microarchitecture.", + preset!(znver2), + ); + settings.add_preset( + "znver4", + "Zen (fourth generation) microarchitecture.", + preset!( + znver3 + && has_avx512bitalg + && has_avx512dq + && has_avx512f + && has_avx512vbmi + && has_avx512vl + ), + ); + + // Generic + + settings.add_preset("x86-64", "Generic x86-64 microarchitecture.", preset!()); + let x86_64_v2 = settings.add_preset( + "x86-64-v2", + "Generic x86-64 (V2) microarchitecture.", + preset!(sse42 && has_popcnt && has_cmpxchg16b), + ); + let x86_64_v3 = settings.add_preset( + "x84_64_v3", + "Generic x86_64 (V3) microarchitecture.", + preset!(x86_64_v2 && has_bmi1 && has_bmi2 && has_fma && has_lzcnt && has_avx2), + ); + settings.add_preset( + "x86_64_v4", + "Generic x86_64 (V4) microarchitecture.", + preset!(x86_64_v3 && has_avx512dq && has_avx512vl), + ); + + TargetIsa::new("x86", settings.build()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/isle.rs b/deps/crates/vendor/cranelift-codegen-meta/src/isle.rs new file mode 100644 index 00000000000000..e2210df3a31d3e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/isle.rs @@ -0,0 +1,186 @@ +/// A list of compilations (transformations from ISLE source to +/// generated Rust source) that exist in the repository. +/// +/// This list is used either to regenerate the Rust source in-tree (if +/// the `rebuild-isle` feature is enabled), or to verify that the ISLE +/// source in-tree corresponds to the ISLE source that was last used +/// to rebuild the Rust source (if the `rebuild-isle` feature is not +/// enabled). +#[derive(Clone, Debug)] +pub struct IsleCompilations { + pub items: Vec, +} + +impl IsleCompilations { + pub fn lookup(&self, name: &str) -> Option<&IsleCompilation> { + for compilation in &self.items { + if compilation.name == name { + return Some(compilation); + } + } + None + } +} + +#[derive(Clone, Debug)] +pub struct IsleCompilation { + pub name: String, + pub output: std::path::PathBuf, + pub inputs: Vec, + pub untracked_inputs: Vec, +} + +impl IsleCompilation { + pub fn inputs(&self) -> Vec { + self.inputs + .iter() + .chain(self.untracked_inputs.iter()) + .cloned() + .collect() + } +} + +pub fn shared_isle_lower_paths(codegen_crate_dir: &std::path::Path) -> Vec { + let inst_specs_isle = codegen_crate_dir.join("src").join("inst_specs.isle"); + let prelude_isle = codegen_crate_dir.join("src").join("prelude.isle"); + let prelude_lower_isle = codegen_crate_dir.join("src").join("prelude_lower.isle"); + // The shared instruction selector logic. + vec![ + inst_specs_isle.clone(), + prelude_isle.clone(), + prelude_lower_isle.clone(), + ] +} + +/// Construct the list of compilations (transformations from ISLE +/// source to generated Rust source) that exist in the repository. +pub fn get_isle_compilations( + codegen_crate_dir: &std::path::Path, + gen_dir: &std::path::Path, +) -> IsleCompilations { + // Preludes. + let clif_lower_isle = gen_dir.join("clif_lower.isle"); + let clif_opt_isle = gen_dir.join("clif_opt.isle"); + let prelude_isle = codegen_crate_dir.join("src").join("prelude.isle"); + let prelude_opt_isle = codegen_crate_dir.join("src").join("prelude_opt.isle"); + let prelude_lower_isle = codegen_crate_dir.join("src").join("prelude_lower.isle"); + #[cfg(feature = "pulley")] + let pulley_gen = gen_dir.join("pulley_gen.isle"); + + // Directory for mid-end optimizations. + let src_opts = codegen_crate_dir.join("src").join("opts"); + + // Directories for lowering backends. + let src_isa_x64 = codegen_crate_dir.join("src").join("isa").join("x64"); + let src_isa_aarch64 = codegen_crate_dir.join("src").join("isa").join("aarch64"); + let src_isa_s390x = codegen_crate_dir.join("src").join("isa").join("s390x"); + let src_isa_risc_v = codegen_crate_dir.join("src").join("isa").join("riscv64"); + #[cfg(feature = "pulley")] + let src_isa_pulley_shared = codegen_crate_dir + .join("src") + .join("isa") + .join("pulley_shared"); + + // This is a set of ISLE compilation units. + // + // The format of each entry is: + // + // (output Rust code file, input ISLE source files) + // + // There should be one entry for each backend that uses ISLE for lowering, + // and if/when we replace our peephole optimization passes with ISLE, there + // should be an entry for each of those as well. + // + // N.B.: add any new compilation outputs to + // `scripts/force-rebuild-isle.sh` if they do not fit the pattern + // `cranelift/codegen/src/isa/*/lower/isle/generated_code.rs`! + IsleCompilations { + items: vec![ + // The mid-end optimization rules. + IsleCompilation { + name: "opt".to_string(), + output: gen_dir.join("isle_opt.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_opt_isle, + src_opts.join("arithmetic.isle"), + src_opts.join("bitops.isle"), + src_opts.join("cprop.isle"), + src_opts.join("extends.isle"), + src_opts.join("icmp.isle"), + src_opts.join("remat.isle"), + src_opts.join("selects.isle"), + src_opts.join("shifts.isle"), + src_opts.join("spaceship.isle"), + src_opts.join("spectre.isle"), + src_opts.join("vector.isle"), + ], + untracked_inputs: vec![clif_opt_isle], + }, + // The x86-64 instruction selector. + IsleCompilation { + name: "x64".to_string(), + output: gen_dir.join("isle_x64.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_lower_isle.clone(), + src_isa_x64.join("inst.isle"), + src_isa_x64.join("lower.isle"), + ], + untracked_inputs: vec![clif_lower_isle.clone()], + }, + // The aarch64 instruction selector. + IsleCompilation { + name: "aarch64".to_string(), + output: gen_dir.join("isle_aarch64.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_lower_isle.clone(), + src_isa_aarch64.join("inst.isle"), + src_isa_aarch64.join("inst_neon.isle"), + src_isa_aarch64.join("lower.isle"), + src_isa_aarch64.join("lower_dynamic_neon.isle"), + ], + untracked_inputs: vec![clif_lower_isle.clone()], + }, + // The s390x instruction selector. + IsleCompilation { + name: "s390x".to_string(), + output: gen_dir.join("isle_s390x.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_lower_isle.clone(), + src_isa_s390x.join("inst.isle"), + src_isa_s390x.join("lower.isle"), + ], + untracked_inputs: vec![clif_lower_isle.clone()], + }, + // The risc-v instruction selector. + IsleCompilation { + name: "riscv64".to_string(), + output: gen_dir.join("isle_riscv64.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_lower_isle.clone(), + src_isa_risc_v.join("inst.isle"), + src_isa_risc_v.join("inst_vector.isle"), + src_isa_risc_v.join("lower.isle"), + ], + untracked_inputs: vec![clif_lower_isle.clone()], + }, + // The Pulley instruction selector. + #[cfg(feature = "pulley")] + IsleCompilation { + name: "pulley".to_string(), + output: gen_dir.join("isle_pulley_shared.rs"), + inputs: vec![ + prelude_isle.clone(), + prelude_lower_isle.clone(), + src_isa_pulley_shared.join("inst.isle"), + src_isa_pulley_shared.join("lower.isle"), + ], + untracked_inputs: vec![pulley_gen.clone(), clif_lower_isle.clone()], + }, + ], + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/lib.rs b/deps/crates/vendor/cranelift-codegen-meta/src/lib.rs new file mode 100644 index 00000000000000..188e7e7ffbfb94 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/lib.rs @@ -0,0 +1,111 @@ +//! This crate generates Rust sources for use by +//! [`cranelift_codegen`](../cranelift_codegen/index.html). + +use shared::Definitions; + +#[macro_use] +mod cdsl; +mod srcgen; + +pub mod error; +pub mod isa; +pub mod isle; + +mod gen_inst; +mod gen_isle; +mod gen_settings; +mod gen_types; + +mod constant_hash; +mod shared; +mod unique_table; + +#[cfg(feature = "pulley")] +mod pulley; + +/// Generate an ISA from an architecture string (e.g. "x86_64"). +pub fn isa_from_arch(arch: &str) -> Result { + isa::Isa::from_arch(arch).ok_or_else(|| format!("no supported isa found for arch `{arch}`")) +} + +/// Generates all the Rust source files used in Cranelift from the meta-language. +pub fn generate_rust(isas: &[isa::Isa], out_dir: &std::path::Path) -> Result<(), error::Error> { + let shared_defs = shared::define(); + generate_rust_for_shared_defs(&shared_defs, isas, out_dir) +} + +fn generate_rust_for_shared_defs( + shared_defs: &Definitions, + isas: &[isa::Isa], + out_dir: &std::path::Path, +) -> Result<(), error::Error> { + gen_settings::generate( + &shared_defs.settings, + gen_settings::ParentGroup::None, + "settings.rs", + out_dir, + )?; + + gen_types::generate("types.rs", out_dir)?; + + gen_inst::generate( + &shared_defs.all_formats, + &shared_defs.all_instructions, + "opcodes.rs", + "inst_builder.rs", + out_dir, + )?; + + // Per ISA definitions. + for isa in isa::define(isas) { + gen_settings::generate( + &isa.settings, + gen_settings::ParentGroup::Shared, + &format!("settings-{}.rs", isa.name), + out_dir, + )?; + } + + #[cfg(feature = "pulley")] + if isas.contains(&isa::Isa::Pulley32) || isas.contains(&isa::Isa::Pulley64) { + pulley::generate_rust("pulley_inst_gen.rs", out_dir)?; + } + + Ok(()) +} + +/// Generates all the ISLE source files used in Cranelift from the meta-language. +pub fn generate_isle(isle_dir: &std::path::Path) -> Result<(), error::Error> { + let shared_defs = shared::define(); + generate_isle_for_shared_defs(&shared_defs, isle_dir) +} + +fn generate_isle_for_shared_defs( + shared_defs: &Definitions, + isle_dir: &std::path::Path, +) -> Result<(), error::Error> { + gen_isle::generate( + &shared_defs.all_formats, + &shared_defs.all_instructions, + "clif_opt.isle", + "clif_lower.isle", + isle_dir, + )?; + + #[cfg(feature = "pulley")] + pulley::generate_isle("pulley_gen.isle", isle_dir)?; + + Ok(()) +} + +/// Generates all the source files used in Cranelift from the meta-language. +pub fn generate( + isas: &[isa::Isa], + out_dir: &std::path::Path, + isle_dir: &std::path::Path, +) -> Result<(), error::Error> { + let shared_defs = shared::define(); + generate_rust_for_shared_defs(&shared_defs, isas, out_dir)?; + generate_isle_for_shared_defs(&shared_defs, isle_dir)?; + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/pulley.rs b/deps/crates/vendor/cranelift-codegen-meta/src/pulley.rs new file mode 100644 index 00000000000000..6fb8316b9270a6 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/pulley.rs @@ -0,0 +1,401 @@ +use crate::error::Error; +use std::path::Path; + +struct Inst<'a> { + snake_name: &'a str, + name: &'a str, + fields: &'a [(&'a str, &'a str)], +} + +macro_rules! define { + ( + $( + $( #[$attr:meta] )* + $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; + )* + ) => { + &[$(Inst { + snake_name: stringify!($snake_name), + name: stringify!($name), + fields: &[$($( (stringify!($field), stringify!($field_ty)), )*)?], + }),*] + // helpers.push_str(concat!("(define pulley_", stringify!($snake_name), " (")); + }; +} + +const OPS: &[Inst<'_>] = pulley_interpreter::for_each_op!(define); +const EXTENDED_OPS: &[Inst<'_>] = pulley_interpreter::for_each_extended_op!(define); + +enum Operand<'a> { + Normal { + name: &'a str, + ty: &'a str, + }, + Writable { + name: &'a str, + ty: &'a str, + }, + TrapCode { + name: &'a str, + ty: &'a str, + }, + Binop { + dst: &'a str, + src1: &'a str, + src2: &'a str, + }, +} + +impl Inst<'_> { + fn operands(&self) -> impl Iterator> { + self.fields + .iter() + .map(|(name, ty)| match (*name, *ty) { + ("operands", binop) => { + // Parse "BinaryOperands < A >"` as A/A/A + // Parse "BinaryOperands < A, B >"` as A/B/A + // Parse "BinaryOperands < A, B, C >"` as A/B/C + let mut parts = binop + .strip_prefix("BinaryOperands <") + .unwrap() + .strip_suffix(">") + .unwrap() + .trim() + .split(',') + .map(|x| x.trim()); + let dst = parts.next().unwrap(); + let src1 = parts.next().unwrap_or(dst); + let src2 = parts.next().unwrap_or(dst); + Operand::Binop { dst, src1, src2 } + } + ("dst", ty) => Operand::Writable { name, ty }, + (name, "RegSet < XReg >") => Operand::Normal { + name, + ty: "XRegSet", + }, + (name, ty) => Operand::Normal { name, ty }, + }) + .chain(if self.name.contains("Trap") { + Some(Operand::TrapCode { + name: "code", + ty: "TrapCode", + }) + } else { + None + }) + } + + fn skip(&self) -> bool { + match self.name { + // Skip instructions related to control-flow as those require + // special handling with `MachBuffer`. + "Jump" => true, + n if n.starts_with("Call") => true, + + // Skip special instructions not used in Cranelift. + "XPush32Many" | "XPush64Many" | "XPop32Many" | "XPop64Many" => true, + + // Skip more branching-related instructions. + n => n.starts_with("Br"), + } + } +} + +pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { + let mut rust = String::new(); + + // Generate a pretty-printing method for debugging. + rust.push_str("pub fn print(inst: &RawInst) -> String {\n"); + rust.push_str("match inst {\n"); + for inst @ Inst { name, .. } in OPS.iter().chain(EXTENDED_OPS) { + if inst.skip() { + continue; + } + + let mut pat = String::new(); + let mut locals = String::new(); + let mut format_string = String::new(); + format_string.push_str(inst.snake_name); + for (i, op) in inst.operands().enumerate() { + match op { + Operand::Normal { name, ty } | Operand::Writable { name, ty } => { + pat.push_str(name); + pat.push_str(","); + + if i > 0 { + format_string.push_str(","); + } + + if ty == "XRegSet" { + format_string.push_str(" {"); + format_string.push_str(name); + format_string.push_str(":?}"); + continue; + } + + format_string.push_str(" {"); + format_string.push_str(name); + format_string.push_str("}"); + if ty.contains("Reg") { + if name == "dst" { + locals.push_str(&format!("let {name} = reg_name(*{name}.to_reg());\n")); + } else { + locals.push_str(&format!("let {name} = reg_name(**{name});\n")); + } + } + } + Operand::TrapCode { name, ty: _ } => { + pat.push_str(name); + pat.push_str(","); + format_string.push_str(&format!(" // trap={{{name}:?}}")); + } + Operand::Binop { src2, .. } => { + pat.push_str("dst, src1, src2,"); + format_string.push_str(" {dst}, {src1}, {src2}"); + locals.push_str(&format!("let dst = reg_name(*dst.to_reg());\n")); + locals.push_str(&format!("let src1 = reg_name(**src1);\n")); + if src2.contains("Reg") { + locals.push_str(&format!("let src2 = reg_name(**src2);\n")); + } + } + } + } + + rust.push_str(&format!( + " + RawInst::{name} {{ {pat} }} => {{ + {locals} + format!(\"{format_string}\") + }} + " + )); + } + rust.push_str("}\n"); + rust.push_str("}\n"); + + // Generate `get_operands` to feed information to regalloc + rust.push_str( + "pub fn get_operands(inst: &mut RawInst, collector: &mut impl OperandVisitor) {\n", + ); + rust.push_str("match inst {\n"); + for inst @ Inst { name, .. } in OPS.iter().chain(EXTENDED_OPS) { + if inst.skip() { + continue; + } + + let mut pat = String::new(); + let mut uses = Vec::new(); + let mut defs = Vec::new(); + for op in inst.operands() { + match op { + // `{Push,Pop}Frame{Save,Restore}` doesn't participate in + // register allocation. + Operand::Normal { + name: _, + ty: "XRegSet", + } if *name == "PushFrameSave" || *name == "PopFrameRestore" => {} + + Operand::Normal { name, ty } => { + if ty.contains("Reg") { + uses.push(name); + pat.push_str(name); + pat.push_str(","); + } + } + Operand::Writable { name, ty } => { + if ty.contains("Reg") { + defs.push(name); + pat.push_str(name); + pat.push_str(","); + } + } + Operand::TrapCode { .. } => {} + Operand::Binop { src2, .. } => { + pat.push_str("dst, src1,"); + uses.push("src1"); + defs.push("dst"); + if src2.contains("Reg") { + pat.push_str("src2,"); + uses.push("src2"); + } + } + } + } + + let uses = uses + .iter() + .map(|u| format!("collector.reg_use({u});\n")) + .collect::(); + let defs = defs + .iter() + .map(|u| format!("collector.reg_def({u});\n")) + .collect::(); + + rust.push_str(&format!( + " + RawInst::{name} {{ {pat} .. }} => {{ + {uses} + {defs} + }} + " + )); + } + rust.push_str("}\n"); + rust.push_str("}\n"); + + // Generate an emission method + rust.push_str("pub fn emit

(inst: &RawInst, sink: &mut MachBuffer>)\n"); + rust.push_str(" where P: PulleyTargetKind,\n"); + rust.push_str("{\n"); + rust.push_str("match *inst {\n"); + for inst @ Inst { + name, snake_name, .. + } in OPS.iter().chain(EXTENDED_OPS) + { + if inst.skip() { + continue; + } + + let mut pat = String::new(); + let mut args = String::new(); + let mut trap = String::new(); + for op in inst.operands() { + match op { + Operand::Normal { name, ty: _ } | Operand::Writable { name, ty: _ } => { + pat.push_str(name); + pat.push_str(","); + + args.push_str(name); + args.push_str(","); + } + Operand::TrapCode { name, ty: _ } => { + pat.push_str(name); + pat.push_str(","); + trap.push_str(&format!("sink.add_trap({name});\n")); + } + Operand::Binop { .. } => { + pat.push_str("dst, src1, src2,"); + args.push_str( + "pulley_interpreter::regs::BinaryOperands::new(dst, src1, src2),", + ); + } + } + } + + rust.push_str(&format!( + " + RawInst::{name} {{ {pat} }} => {{ + {trap} + pulley_interpreter::encode::{snake_name}(sink, {args}) + }} + " + )); + } + rust.push_str("}\n"); + rust.push_str("}\n"); + + std::fs::write(out_dir.join(filename), rust)?; + Ok(()) +} + +pub fn generate_isle(filename: &str, out_dir: &Path) -> Result<(), Error> { + let mut isle = String::new(); + + // Generate the `RawInst` enum + isle.push_str("(type RawInst (enum\n"); + for inst in OPS.iter().chain(EXTENDED_OPS) { + if inst.skip() { + continue; + } + isle.push_str(" ("); + isle.push_str(inst.name); + for op in inst.operands() { + match op { + Operand::Normal { name, ty } | Operand::TrapCode { name, ty } => { + isle.push_str(&format!("\n ({name} {ty})")); + } + Operand::Writable { name, ty } => { + isle.push_str(&format!("\n ({name} Writable{ty})")); + } + Operand::Binop { dst, src1, src2 } => { + isle.push_str(&format!("\n (dst Writable{dst})")); + isle.push_str(&format!("\n (src1 {src1})")); + isle.push_str(&format!("\n (src2 {src2})")); + } + } + } + isle.push_str(")\n"); + } + isle.push_str("))\n"); + + // Generate the `pulley_*` constructors with a `decl` and a `rule`. + for inst @ Inst { + name, snake_name, .. + } in OPS.iter().chain(EXTENDED_OPS) + { + if inst.skip() { + continue; + } + // generate `decl` and `rule` at the same time, placing the `rule` in + // temporary storage on the side. Makes generation a bit easier to read + // as opposed to doing the decl first then the rule. + let mut rule = String::new(); + isle.push_str(&format!("(decl pulley_{snake_name} (")); + rule.push_str(&format!("(rule (pulley_{snake_name} ")); + let mut result = None; + let mut ops = Vec::new(); + for op in inst.operands() { + match op { + Operand::Normal { name, ty } | Operand::TrapCode { name, ty } => { + isle.push_str(ty); + rule.push_str(name); + ops.push(name); + } + Operand::Writable { name: _, ty } => { + assert!(result.is_none(), "{} has >1 result", inst.snake_name); + result = Some(ty); + } + Operand::Binop { dst, src1, src2 } => { + isle.push_str(&format!("{src1} {src2}")); + rule.push_str("src1 src2"); + ops.push("src1"); + ops.push("src2"); + assert!(result.is_none(), "{} has >1 result", inst.snake_name); + result = Some(dst); + } + } + isle.push_str(" "); + rule.push_str(" "); + } + isle.push_str(") "); + rule.push_str(")"); + let ops = ops.join(" "); + match result { + Some(result) => { + isle.push_str(result); + rule.push_str(&format!( + " + (let ( + (dst Writable{result} (temp_writable_{})) + (_ Unit (emit (RawInst.{name} dst {ops}))) + ) + dst))\ +\n", + result.to_lowercase() + )); + } + None => { + isle.push_str("SideEffectNoResult"); + rule.push_str(&format!( + " (SideEffectNoResult.Inst (RawInst.{name} {ops})))\n", + )); + } + } + isle.push_str(")\n"); + + isle.push_str(&rule); + } + + std::fs::write(out_dir.join(filename), isle)?; + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/entities.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/entities.rs new file mode 100644 index 00000000000000..3df9ecaa171fad --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/entities.rs @@ -0,0 +1,101 @@ +use crate::cdsl::operands::{OperandKind, OperandKindFields}; + +/// Small helper to initialize an OperandBuilder with the right kind, for a given name and doc. +fn new(format_field_name: &'static str, rust_type: &'static str, doc: &'static str) -> OperandKind { + OperandKind::new( + format_field_name, + rust_type, + OperandKindFields::EntityRef, + doc, + ) +} + +pub(crate) struct EntityRefs { + /// A reference to a basic block in the same function, with its arguments provided. + /// This is primarily used in control flow instructions. + pub(crate) block_call: OperandKind, + + /// A reference to a basic block in the same function, with its arguments provided. + /// This is primarily used in control flow instructions. + pub(crate) block_then: OperandKind, + + /// A reference to a basic block in the same function, with its arguments provided. + /// This is primarily used in control flow instructions. + pub(crate) block_else: OperandKind, + + /// A reference to a stack slot declared in the function preamble. + pub(crate) stack_slot: OperandKind, + + /// A reference to a dynamic_stack slot declared in the function preamble. + pub(crate) dynamic_stack_slot: OperandKind, + + /// A reference to a global value. + pub(crate) global_value: OperandKind, + + /// A reference to a function signature declared in the function preamble. + /// This is used to provide the call signature in a call_indirect instruction. + pub(crate) sig_ref: OperandKind, + + /// A reference to an external function declared in the function preamble. + /// This is used to provide the callee and signature in a call instruction. + pub(crate) func_ref: OperandKind, + + /// A reference to a jump table declared in the function preamble. + pub(crate) jump_table: OperandKind, + + /// A variable-sized list of value operands. Use for Block and function call arguments. + pub(crate) varargs: OperandKind, +} + +impl EntityRefs { + pub fn new() -> Self { + Self { + block_call: new( + "destination", + "ir::BlockCall", + "a basic block in the same function, with its arguments provided.", + ), + + block_then: new( + "block_then", + "ir::BlockCall", + "a basic block in the same function, with its arguments provided.", + ), + + block_else: new( + "block_else", + "ir::BlockCall", + "a basic block in the same function, with its arguments provided.", + ), + + stack_slot: new("stack_slot", "ir::StackSlot", "A stack slot"), + + dynamic_stack_slot: new( + "dynamic_stack_slot", + "ir::DynamicStackSlot", + "A dynamic stack slot", + ), + + global_value: new("global_value", "ir::GlobalValue", "A global value."), + + sig_ref: new("sig_ref", "ir::SigRef", "A function signature."), + + func_ref: new("func_ref", "ir::FuncRef", "An external function."), + + jump_table: new("table", "ir::JumpTable", "A jump table."), + + varargs: OperandKind::new( + "", + "&[Value]", + OperandKindFields::VariableArgs, + r#" + A variable size list of `value` operands. + + Use this to represent arguments passed to a function call, arguments + passed to a basic block, or a variable number of results + returned from an instruction. + "#, + ), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/formats.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/formats.rs new file mode 100644 index 00000000000000..86d54338d63dad --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/formats.rs @@ -0,0 +1,208 @@ +use crate::cdsl::formats::{InstructionFormat, InstructionFormatBuilder as Builder}; +use crate::shared::{entities::EntityRefs, immediates::Immediates}; +use std::rc::Rc; + +pub(crate) struct Formats { + pub(crate) atomic_cas: Rc, + pub(crate) atomic_rmw: Rc, + pub(crate) binary: Rc, + pub(crate) binary_imm8: Rc, + pub(crate) binary_imm64: Rc, + pub(crate) branch_table: Rc, + pub(crate) brif: Rc, + pub(crate) call: Rc, + pub(crate) call_indirect: Rc, + pub(crate) cond_trap: Rc, + pub(crate) float_compare: Rc, + pub(crate) func_addr: Rc, + pub(crate) int_compare: Rc, + pub(crate) int_compare_imm: Rc, + pub(crate) int_add_trap: Rc, + pub(crate) jump: Rc, + pub(crate) load: Rc, + pub(crate) load_no_offset: Rc, + pub(crate) multiary: Rc, + pub(crate) nullary: Rc, + pub(crate) shuffle: Rc, + pub(crate) stack_load: Rc, + pub(crate) stack_store: Rc, + pub(crate) dynamic_stack_load: Rc, + pub(crate) dynamic_stack_store: Rc, + pub(crate) store: Rc, + pub(crate) store_no_offset: Rc, + pub(crate) ternary: Rc, + pub(crate) ternary_imm8: Rc, + pub(crate) trap: Rc, + pub(crate) unary: Rc, + pub(crate) unary_const: Rc, + pub(crate) unary_global_value: Rc, + pub(crate) unary_ieee16: Rc, + pub(crate) unary_ieee32: Rc, + pub(crate) unary_ieee64: Rc, + pub(crate) unary_imm: Rc, +} + +impl Formats { + pub fn new(imm: &Immediates, entities: &EntityRefs) -> Self { + Self { + unary: Builder::new("Unary").value().build(), + + unary_imm: Builder::new("UnaryImm").imm(&imm.imm64).build(), + + unary_ieee16: Builder::new("UnaryIeee16").imm(&imm.ieee16).build(), + + unary_ieee32: Builder::new("UnaryIeee32").imm(&imm.ieee32).build(), + + unary_ieee64: Builder::new("UnaryIeee64").imm(&imm.ieee64).build(), + + unary_const: Builder::new("UnaryConst").imm(&imm.pool_constant).build(), + + unary_global_value: Builder::new("UnaryGlobalValue") + .imm(&entities.global_value) + .build(), + + binary: Builder::new("Binary").value().value().build(), + + binary_imm8: Builder::new("BinaryImm8").value().imm(&imm.uimm8).build(), + + binary_imm64: Builder::new("BinaryImm64").value().imm(&imm.imm64).build(), + + // The select instructions are controlled by the second VALUE operand. + // The first VALUE operand is the controlling flag which has a derived type. + // The fma instruction has the same constraint on all inputs. + ternary: Builder::new("Ternary") + .value() + .value() + .value() + .typevar_operand(1) + .build(), + + ternary_imm8: Builder::new("TernaryImm8") + .value() + .imm(&imm.uimm8) + .value() + .build(), + + // Catch-all for instructions with many outputs and inputs and no immediate + // operands. + multiary: Builder::new("MultiAry").varargs().build(), + + nullary: Builder::new("NullAry").build(), + + shuffle: Builder::new("Shuffle") + .value() + .value() + .imm(&imm.uimm128) + .build(), + + int_compare: Builder::new("IntCompare") + .imm(&imm.intcc) + .value() + .value() + .build(), + + int_compare_imm: Builder::new("IntCompareImm") + .imm(&imm.intcc) + .value() + .imm(&imm.imm64) + .build(), + + float_compare: Builder::new("FloatCompare") + .imm(&imm.floatcc) + .value() + .value() + .build(), + + jump: Builder::new("Jump").block().build(), + + brif: Builder::new("Brif").value().block().block().build(), + + branch_table: Builder::new("BranchTable") + .value() + .imm(&entities.jump_table) + .build(), + + call: Builder::new("Call") + .imm(&entities.func_ref) + .varargs() + .build(), + + call_indirect: Builder::new("CallIndirect") + .imm(&entities.sig_ref) + .value() + .varargs() + .build(), + + func_addr: Builder::new("FuncAddr").imm(&entities.func_ref).build(), + + atomic_rmw: Builder::new("AtomicRmw") + .imm(&imm.memflags) + .imm(&imm.atomic_rmw_op) + .value() + .value() + .build(), + + atomic_cas: Builder::new("AtomicCas") + .imm(&imm.memflags) + .value() + .value() + .value() + .typevar_operand(2) + .build(), + + load: Builder::new("Load") + .imm(&imm.memflags) + .value() + .imm(&imm.offset32) + .build(), + + load_no_offset: Builder::new("LoadNoOffset") + .imm(&imm.memflags) + .value() + .build(), + + store: Builder::new("Store") + .imm(&imm.memflags) + .value() + .value() + .imm(&imm.offset32) + .build(), + + store_no_offset: Builder::new("StoreNoOffset") + .imm(&imm.memflags) + .value() + .value() + .build(), + + stack_load: Builder::new("StackLoad") + .imm(&entities.stack_slot) + .imm(&imm.offset32) + .build(), + + stack_store: Builder::new("StackStore") + .value() + .imm(&entities.stack_slot) + .imm(&imm.offset32) + .build(), + + dynamic_stack_load: Builder::new("DynamicStackLoad") + .imm(&entities.dynamic_stack_slot) + .build(), + + dynamic_stack_store: Builder::new("DynamicStackStore") + .value() + .imm(&entities.dynamic_stack_slot) + .build(), + + trap: Builder::new("Trap").imm(&imm.trapcode).build(), + + cond_trap: Builder::new("CondTrap").value().imm(&imm.trapcode).build(), + + int_add_trap: Builder::new("IntAddTrap") + .value() + .value() + .imm(&imm.trapcode) + .build(), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/immediates.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/immediates.rs new file mode 100644 index 00000000000000..21f4a117c720d2 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/immediates.rs @@ -0,0 +1,224 @@ +use crate::cdsl::operands::{EnumValues, OperandKind, OperandKindFields}; + +use std::collections::HashMap; + +pub(crate) struct Immediates { + /// A 64-bit immediate integer operand. + /// + /// This type of immediate integer can interact with SSA values with any IntType type. + pub imm64: OperandKind, + + /// An unsigned 8-bit immediate integer operand. + /// + /// This small operand is used to indicate lane indexes in SIMD vectors and immediate bit + /// counts on shift instructions. + pub uimm8: OperandKind, + + /// An unsigned 128-bit immediate integer operand. + /// + /// This operand is used to pass entire 128-bit vectors as immediates to instructions like + /// const. + pub uimm128: OperandKind, + + /// A constant stored in the constant pool. + /// + /// This operand is used to pass constants to instructions like vconst while storing the + /// actual bytes in the constant pool. + pub pool_constant: OperandKind, + + /// A 32-bit immediate signed offset. + /// + /// This is used to represent an immediate address offset in load/store instructions. + pub offset32: OperandKind, + + /// A 16-bit immediate floating point operand. + /// + /// IEEE 754-2008 binary16 interchange format. + pub ieee16: OperandKind, + + /// A 32-bit immediate floating point operand. + /// + /// IEEE 754-2008 binary32 interchange format. + pub ieee32: OperandKind, + + /// A 64-bit immediate floating point operand. + /// + /// IEEE 754-2008 binary64 interchange format. + pub ieee64: OperandKind, + + /// A condition code for comparing integer values. + /// + /// This enumerated operand kind is used for the `icmp` instruction and corresponds to the + /// condcodes::IntCC` Rust type. + pub intcc: OperandKind, + + /// A condition code for comparing floating point values. + /// + /// This enumerated operand kind is used for the `fcmp` instruction and corresponds to the + /// `condcodes::FloatCC` Rust type. + pub floatcc: OperandKind, + + /// Flags for memory operations like `load` and `store`. + pub memflags: OperandKind, + + /// A trap code indicating the reason for trapping. + /// + /// The Rust enum type also has a `User(u16)` variant for user-provided trap codes. + pub trapcode: OperandKind, + + /// A code indicating the arithmetic operation to perform in an atomic_rmw memory access. + pub atomic_rmw_op: OperandKind, +} + +fn new_imm( + format_field_name: &'static str, + rust_type: &'static str, + doc: &'static str, +) -> OperandKind { + OperandKind::new( + format_field_name, + rust_type, + OperandKindFields::ImmValue, + doc, + ) +} +fn new_enum( + format_field_name: &'static str, + rust_type: &'static str, + values: EnumValues, + doc: &'static str, +) -> OperandKind { + OperandKind::new( + format_field_name, + rust_type, + OperandKindFields::ImmEnum(values), + doc, + ) +} + +impl Immediates { + pub fn new() -> Self { + Self { + imm64: new_imm( + "imm", + "ir::immediates::Imm64", + "A 64-bit immediate integer.", + ), + uimm8: new_imm( + "imm", + "ir::immediates::Uimm8", + "An 8-bit immediate unsigned integer.", + ), + uimm128: new_imm( + "imm", + "ir::Immediate", + "A 128-bit immediate unsigned integer.", + ), + pool_constant: new_imm( + "constant_handle", + "ir::Constant", + "A constant stored in the constant pool.", + ), + offset32: new_imm( + "offset", + "ir::immediates::Offset32", + "A 32-bit immediate signed offset.", + ), + ieee16: new_imm( + "imm", + "ir::immediates::Ieee16", + "A 16-bit immediate floating point number.", + ), + ieee32: new_imm( + "imm", + "ir::immediates::Ieee32", + "A 32-bit immediate floating point number.", + ), + ieee64: new_imm( + "imm", + "ir::immediates::Ieee64", + "A 64-bit immediate floating point number.", + ), + intcc: { + let mut intcc_values = HashMap::new(); + intcc_values.insert("eq", "Equal"); + intcc_values.insert("ne", "NotEqual"); + intcc_values.insert("sge", "SignedGreaterThanOrEqual"); + intcc_values.insert("sgt", "SignedGreaterThan"); + intcc_values.insert("sle", "SignedLessThanOrEqual"); + intcc_values.insert("slt", "SignedLessThan"); + intcc_values.insert("uge", "UnsignedGreaterThanOrEqual"); + intcc_values.insert("ugt", "UnsignedGreaterThan"); + intcc_values.insert("ule", "UnsignedLessThanOrEqual"); + intcc_values.insert("ult", "UnsignedLessThan"); + new_enum( + "cond", + "ir::condcodes::IntCC", + intcc_values, + "An integer comparison condition code.", + ) + }, + + floatcc: { + let mut floatcc_values = HashMap::new(); + floatcc_values.insert("ord", "Ordered"); + floatcc_values.insert("uno", "Unordered"); + floatcc_values.insert("eq", "Equal"); + floatcc_values.insert("ne", "NotEqual"); + floatcc_values.insert("one", "OrderedNotEqual"); + floatcc_values.insert("ueq", "UnorderedOrEqual"); + floatcc_values.insert("lt", "LessThan"); + floatcc_values.insert("le", "LessThanOrEqual"); + floatcc_values.insert("gt", "GreaterThan"); + floatcc_values.insert("ge", "GreaterThanOrEqual"); + floatcc_values.insert("ult", "UnorderedOrLessThan"); + floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual"); + floatcc_values.insert("ugt", "UnorderedOrGreaterThan"); + floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual"); + new_enum( + "cond", + "ir::condcodes::FloatCC", + floatcc_values, + "A floating point comparison condition code", + ) + }, + + memflags: new_imm("flags", "ir::MemFlags", "Memory operation flags"), + + trapcode: { + let mut trapcode_values = HashMap::new(); + trapcode_values.insert("stk_ovf", "STACK_OVERFLOW"); + trapcode_values.insert("heap_oob", "HEAP_OUT_OF_BOUNDS"); + trapcode_values.insert("int_ovf", "INTEGER_OVERFLOW"); + trapcode_values.insert("int_divz", "INTEGER_DIVISION_BY_ZERO"); + trapcode_values.insert("bad_toint", "BAD_CONVERSION_TO_INTEGER"); + new_enum( + "code", + "ir::TrapCode", + trapcode_values, + "A trap reason code.", + ) + }, + atomic_rmw_op: { + let mut atomic_rmw_op_values = HashMap::new(); + atomic_rmw_op_values.insert("add", "Add"); + atomic_rmw_op_values.insert("sub", "Sub"); + atomic_rmw_op_values.insert("and", "And"); + atomic_rmw_op_values.insert("nand", "Nand"); + atomic_rmw_op_values.insert("or", "Or"); + atomic_rmw_op_values.insert("xor", "Xor"); + atomic_rmw_op_values.insert("xchg", "Xchg"); + atomic_rmw_op_values.insert("umin", "Umin"); + atomic_rmw_op_values.insert("umax", "Umax"); + atomic_rmw_op_values.insert("smin", "Smin"); + atomic_rmw_op_values.insert("smax", "Smax"); + new_enum( + "op", + "ir::AtomicRmwOp", + atomic_rmw_op_values, + "Atomic Read-Modify-Write Ops", + ) + }, + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/instructions.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/instructions.rs new file mode 100644 index 00000000000000..2611f5d714f165 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/instructions.rs @@ -0,0 +1,3786 @@ +#![expect(non_snake_case, reason = "DSL style here")] + +use crate::cdsl::instructions::{ + AllInstructions, InstructionBuilder as Inst, InstructionGroupBuilder, +}; +use crate::cdsl::operands::Operand; +use crate::cdsl::types::{LaneType, ValueType}; +use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar}; +use crate::shared::formats::Formats; +use crate::shared::types; +use crate::shared::{entities::EntityRefs, immediates::Immediates}; + +#[inline(never)] +fn define_control_flow( + ig: &mut InstructionGroupBuilder, + formats: &Formats, + imm: &Immediates, + entities: &EntityRefs, +) { + ig.push( + Inst::new( + "jump", + r#" + Jump. + + Unconditionally jump to a basic block, passing the specified + block arguments. The number and types of arguments must match the + destination block. + "#, + &formats.jump, + ) + .operands_in(vec![Operand::new("block_call", &entities.block_call) + .with_doc("Destination basic block, with its arguments provided")]) + .branches(), + ); + + let ScalarTruthy = &TypeVar::new( + "ScalarTruthy", + "A scalar truthy type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + ig.push( + Inst::new( + "brif", + r#" + Conditional branch when cond is non-zero. + + Take the ``then`` branch when ``c != 0``, and the ``else`` branch otherwise. + "#, + &formats.brif, + ) + .operands_in(vec![ + Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), + Operand::new("block_then", &entities.block_then).with_doc("Then block"), + Operand::new("block_else", &entities.block_else).with_doc("Else block"), + ]) + .branches(), + ); + + { + let _i32 = &TypeVar::new( + "i32", + "A 32 bit scalar integer type", + TypeSetBuilder::new().ints(32..32).build(), + ); + + ig.push( + Inst::new( + "br_table", + r#" + Indirect branch via jump table. + + Use ``x`` as an unsigned index into the jump table ``JT``. If a jump + table entry is found, branch to the corresponding block. If no entry was + found or the index is out-of-bounds, branch to the default block of the + table. + + Note that this branch instruction can't pass arguments to the targeted + blocks. Split critical edges as needed to work around this. + + Do not confuse this with "tables" in WebAssembly. ``br_table`` is for + jump tables with destinations within the current function only -- think + of a ``match`` in Rust or a ``switch`` in C. If you want to call a + function in a dynamic library, that will typically use + ``call_indirect``. + "#, + &formats.branch_table, + ) + .operands_in(vec![ + Operand::new("x", _i32).with_doc("i32 index into jump table"), + Operand::new("JT", &entities.jump_table), + ]) + .branches(), + ); + } + + let iAddr = &TypeVar::new( + "iAddr", + "An integer address type", + TypeSetBuilder::new().ints(32..64).build(), + ); + + ig.push( + Inst::new( + "debugtrap", + r#" + Encodes an assembly debug trap. + "#, + &formats.nullary, + ) + .other_side_effects() + .can_load() + .can_store(), + ); + + ig.push( + Inst::new( + "trap", + r#" + Terminate execution unconditionally. + "#, + &formats.trap, + ) + .operands_in(vec![Operand::new("code", &imm.trapcode)]) + .can_trap() + .terminates_block(), + ); + + ig.push( + Inst::new( + "trapz", + r#" + Trap when zero. + + if ``c`` is non-zero, execution continues at the following instruction. + "#, + &formats.cond_trap, + ) + .operands_in(vec![ + Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), + Operand::new("code", &imm.trapcode), + ]) + .can_trap(), + ); + + ig.push( + Inst::new( + "trapnz", + r#" + Trap when non-zero. + + If ``c`` is zero, execution continues at the following instruction. + "#, + &formats.cond_trap, + ) + .operands_in(vec![ + Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), + Operand::new("code", &imm.trapcode), + ]) + .can_trap(), + ); + + ig.push( + Inst::new( + "return", + r#" + Return from the function. + + Unconditionally transfer control to the calling function, passing the + provided return values. The list of return values must match the + function signature's return types. + "#, + &formats.multiary, + ) + .operands_in(vec![ + Operand::new("rvals", &entities.varargs).with_doc("return values") + ]) + .returns(), + ); + + ig.push( + Inst::new( + "call", + r#" + Direct function call. + + Call a function which has been declared in the preamble. The argument + types must match the function's signature. + "#, + &formats.call, + ) + .operands_in(vec![ + Operand::new("FN", &entities.func_ref) + .with_doc("function to call, declared by `function`"), + Operand::new("args", &entities.varargs).with_doc("call arguments"), + ]) + .operands_out(vec![ + Operand::new("rvals", &entities.varargs).with_doc("return values") + ]) + .call(), + ); + + ig.push( + Inst::new( + "call_indirect", + r#" + Indirect function call. + + Call the function pointed to by `callee` with the given arguments. The + called function must match the specified signature. + + Note that this is different from WebAssembly's ``call_indirect``; the + callee is a native address, rather than a table index. For WebAssembly, + `table_addr` and `load` are used to obtain a native address + from a table. + "#, + &formats.call_indirect, + ) + .operands_in(vec![ + Operand::new("SIG", &entities.sig_ref).with_doc("function signature"), + Operand::new("callee", iAddr).with_doc("address of function to call"), + Operand::new("args", &entities.varargs).with_doc("call arguments"), + ]) + .operands_out(vec![ + Operand::new("rvals", &entities.varargs).with_doc("return values") + ]) + .call(), + ); + + ig.push( + Inst::new( + "return_call", + r#" + Direct tail call. + + Tail call a function which has been declared in the preamble. The + argument types must match the function's signature, the caller and + callee calling conventions must be the same, and must be a calling + convention that supports tail calls. + + This instruction is a block terminator. + "#, + &formats.call, + ) + .operands_in(vec![ + Operand::new("FN", &entities.func_ref) + .with_doc("function to call, declared by `function`"), + Operand::new("args", &entities.varargs).with_doc("call arguments"), + ]) + .returns() + .call(), + ); + + ig.push( + Inst::new( + "return_call_indirect", + r#" + Indirect tail call. + + Call the function pointed to by `callee` with the given arguments. The + argument types must match the function's signature, the caller and + callee calling conventions must be the same, and must be a calling + convention that supports tail calls. + + This instruction is a block terminator. + + Note that this is different from WebAssembly's ``tail_call_indirect``; + the callee is a native address, rather than a table index. For + WebAssembly, `table_addr` and `load` are used to obtain a native address + from a table. + "#, + &formats.call_indirect, + ) + .operands_in(vec![ + Operand::new("SIG", &entities.sig_ref).with_doc("function signature"), + Operand::new("callee", iAddr).with_doc("address of function to call"), + Operand::new("args", &entities.varargs).with_doc("call arguments"), + ]) + .returns() + .call(), + ); + + ig.push( + Inst::new( + "func_addr", + r#" + Get the address of a function. + + Compute the absolute address of a function declared in the preamble. + The returned address can be used as a ``callee`` argument to + `call_indirect`. This is also a method for calling functions that + are too far away to be addressable by a direct `call` + instruction. + "#, + &formats.func_addr, + ) + .operands_in(vec![Operand::new("FN", &entities.func_ref) + .with_doc("function to call, declared by `function`")]) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); +} + +#[inline(never)] +fn define_simd_lane_access( + ig: &mut InstructionGroupBuilder, + formats: &Formats, + imm: &Immediates, + _: &EntityRefs, +) { + let TxN = &TypeVar::new( + "TxN", + "A SIMD vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .dynamic_simd_lanes(Interval::All) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "splat", + r#" + Vector splat. + + Return a vector whose lanes are all ``x``. + "#, + &formats.unary, + ) + .operands_in(vec![ + Operand::new("x", &TxN.lane_of()).with_doc("Value to splat to all lanes") + ]) + .operands_out(vec![Operand::new("a", TxN)]), + ); + + let I8x16 = &TypeVar::new( + "I8x16", + "A SIMD vector type consisting of 16 lanes of 8-bit integers", + TypeSetBuilder::new() + .ints(8..8) + .simd_lanes(16..16) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "swizzle", + r#" + Vector swizzle. + + Returns a new vector with byte-width lanes selected from the lanes of the first input + vector ``x`` specified in the second input vector ``s``. The indices ``i`` in range + ``[0, 15]`` select the ``i``-th element of ``x``. For indices outside of the range the + resulting lane is 0. Note that this operates on byte-width lanes. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes"), + Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes"), + ]) + .operands_out(vec![Operand::new("a", I8x16)]), + ); + + ig.push( + Inst::new( + "x86_pshufb", + r#" + A vector swizzle lookalike which has the semantics of `pshufb` on x64. + + This instruction will permute the 8-bit lanes of `x` with the indices + specified in `y`. Each lane in the mask, `y`, uses the bottom four + bits for selecting the lane from `x` unless the most significant bit + is set, in which case the lane is zeroed. The output vector will have + the following contents when the element of `y` is in these ranges: + + * `[0, 127]` -> `x[y[i] % 16]` + * `[128, 255]` -> 0 + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes"), + Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes"), + ]) + .operands_out(vec![Operand::new("a", I8x16)]), + ); + + ig.push( + Inst::new( + "insertlane", + r#" + Insert ``y`` as lane ``Idx`` in x. + + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. + "#, + &formats.ternary_imm8, + ) + .operands_in(vec![ + Operand::new("x", TxN).with_doc("The vector to modify"), + Operand::new("y", &TxN.lane_of()).with_doc("New lane value"), + Operand::new("Idx", &imm.uimm8).with_doc("Lane index"), + ]) + .operands_out(vec![Operand::new("a", TxN)]), + ); + + ig.push( + Inst::new( + "extractlane", + r#" + Extract lane ``Idx`` from ``x``. + + The lane index, ``Idx``, is an immediate value, not an SSA value. It + must indicate a valid lane index for the type of ``x``. Note that the upper bits of ``a`` + may or may not be zeroed depending on the ISA but the type system should prevent using + ``a`` as anything other than the extracted value. + "#, + &formats.binary_imm8, + ) + .operands_in(vec![ + Operand::new("x", TxN), + Operand::new("Idx", &imm.uimm8).with_doc("Lane index"), + ]) + .operands_out(vec![Operand::new("a", &TxN.lane_of())]), + ); +} + +#[inline(never)] +fn define_simd_arithmetic( + ig: &mut InstructionGroupBuilder, + formats: &Formats, + _: &Immediates, + _: &EntityRefs, +) { + let Int = &TypeVar::new( + "Int", + "A scalar or vector integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .build(), + ); + + ig.push( + Inst::new( + "smin", + r#" + Signed integer minimum. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "umin", + r#" + Unsigned integer minimum. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "smax", + r#" + Signed integer maximum. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "umax", + r#" + Unsigned integer maximum. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + let IxN = &TypeVar::new( + "IxN", + "A SIMD vector type containing integers", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "avg_round", + r#" + Unsigned average with rounding: `a := (x + y + 1) // 2` + + The addition does not lose any information (such as from overflow). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)]) + .operands_out(vec![Operand::new("a", IxN)]), + ); + + ig.push( + Inst::new( + "uadd_sat", + r#" + Add with unsigned saturation. + + This is similar to `iadd` but the operands are interpreted as unsigned integers and their + summed result, instead of wrapping, will be saturated to the highest unsigned integer for + the controlling type (e.g. `0xFF` for i8). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)]) + .operands_out(vec![Operand::new("a", IxN)]), + ); + + ig.push( + Inst::new( + "sadd_sat", + r#" + Add with signed saturation. + + This is similar to `iadd` but the operands are interpreted as signed integers and their + summed result, instead of wrapping, will be saturated to the lowest or highest + signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). For example, + since an `sadd_sat.i8` of `0x70` and `0x70` is greater than `0x7F`, the result will be + clamped to `0x7F`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)]) + .operands_out(vec![Operand::new("a", IxN)]), + ); + + ig.push( + Inst::new( + "usub_sat", + r#" + Subtract with unsigned saturation. + + This is similar to `isub` but the operands are interpreted as unsigned integers and their + difference, instead of wrapping, will be saturated to the lowest unsigned integer for + the controlling type (e.g. `0x00` for i8). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)]) + .operands_out(vec![Operand::new("a", IxN)]), + ); + + ig.push( + Inst::new( + "ssub_sat", + r#" + Subtract with signed saturation. + + This is similar to `isub` but the operands are interpreted as signed integers and their + difference, instead of wrapping, will be saturated to the lowest or highest + signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)]) + .operands_out(vec![Operand::new("a", IxN)]), + ); +} + +pub(crate) fn define( + all_instructions: &mut AllInstructions, + formats: &Formats, + imm: &Immediates, + entities: &EntityRefs, +) { + let mut ig = InstructionGroupBuilder::new(all_instructions); + + define_control_flow(&mut ig, formats, imm, entities); + define_simd_lane_access(&mut ig, formats, imm, entities); + define_simd_arithmetic(&mut ig, formats, imm, entities); + + // Operand kind shorthands. + let i8: &TypeVar = &ValueType::from(LaneType::from(types::Int::I8)).into(); + let f16_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F16)).into(); + let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into(); + let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into(); + let f128_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F128)).into(); + + // Starting definitions. + let Int = &TypeVar::new( + "Int", + "A scalar or vector integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .dynamic_simd_lanes(Interval::All) + .build(), + ); + + let NarrowInt = &TypeVar::new( + "NarrowInt", + "An integer type of width up to `i64`", + TypeSetBuilder::new().ints(8..64).build(), + ); + + let ScalarTruthy = &TypeVar::new( + "ScalarTruthy", + "A scalar truthy type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + let iB = &TypeVar::new( + "iB", + "A scalar integer type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + let iSwappable = &TypeVar::new( + "iSwappable", + "A multi byte scalar integer type", + TypeSetBuilder::new().ints(16..128).build(), + ); + + let iAddr = &TypeVar::new( + "iAddr", + "An integer address type", + TypeSetBuilder::new().ints(32..64).build(), + ); + + let TxN = &TypeVar::new( + "TxN", + "A SIMD vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(false) + .build(), + ); + let Any = &TypeVar::new( + "Any", + "Any integer, float, or reference scalar or vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .build(), + ); + + let Mem = &TypeVar::new( + "Mem", + "Any type that can be stored in memory", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .dynamic_simd_lanes(Interval::All) + .build(), + ); + + let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string()); + + ig.push( + Inst::new( + "load", + r#" + Load from memory at ``p + Offset``. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "store", + r#" + Store ``x`` to memory at ``p + Offset``. + + This is a polymorphic instruction that can store any value type with a + memory representation. + "#, + &formats.store, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", Mem).with_doc("Value to be stored"), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .can_store(), + ); + + let iExt8 = &TypeVar::new( + "iExt8", + "An integer type with more than 8 bits", + TypeSetBuilder::new().ints(16..64).build(), + ); + + ig.push( + Inst::new( + "uload8", + r#" + Load 8 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i8`` followed by ``uextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt8)]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload8", + r#" + Load 8 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i8`` followed by ``sextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt8)]) + .can_load(), + ); + + ig.push( + Inst::new( + "istore8", + r#" + Store the low 8 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i8`` followed by ``store.i8``. + "#, + &formats.store, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", iExt8), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .can_store(), + ); + + let iExt16 = &TypeVar::new( + "iExt16", + "An integer type with more than 16 bits", + TypeSetBuilder::new().ints(32..64).build(), + ); + + ig.push( + Inst::new( + "uload16", + r#" + Load 16 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i16`` followed by ``uextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt16)]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload16", + r#" + Load 16 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i16`` followed by ``sextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt16)]) + .can_load(), + ); + + ig.push( + Inst::new( + "istore16", + r#" + Store the low 16 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i16`` followed by ``store.i16``. + "#, + &formats.store, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", iExt16), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .can_store(), + ); + + let iExt32 = &TypeVar::new( + "iExt32", + "An integer type with more than 32 bits", + TypeSetBuilder::new().ints(64..64).build(), + ); + + ig.push( + Inst::new( + "uload32", + r#" + Load 32 bits from memory at ``p + Offset`` and zero-extend. + + This is equivalent to ``load.i32`` followed by ``uextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt32)]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload32", + r#" + Load 32 bits from memory at ``p + Offset`` and sign-extend. + + This is equivalent to ``load.i32`` followed by ``sextend``. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", iExt32)]) + .can_load(), + ); + + ig.push( + Inst::new( + "istore32", + r#" + Store the low 32 bits of ``x`` to memory at ``p + Offset``. + + This is equivalent to ``ireduce.i32`` followed by ``store.i32``. + "#, + &formats.store, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", iExt32), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .can_store(), + ); + ig.push( + Inst::new( + "stack_switch", + r#" + Suspends execution of the current stack and resumes execution of another + one. + + The target stack to switch to is identified by the data stored at + ``load_context_ptr``. Before switching, this instruction stores + analogous information about the + current (i.e., original) stack at ``store_context_ptr``, to + enabled switching back to the original stack at a later point. + + The size, alignment and layout of the information stored at + ``load_context_ptr`` and ``store_context_ptr`` is platform-dependent. + The instruction assumes that ``load_context_ptr`` and + ``store_context_ptr`` are valid pointers to memory with said layout and + alignment, and does not perform any checks on these pointers or the data + stored there. + + The instruction is experimental and only supported on x64 Linux at the + moment. + + When switching from a stack A to a stack B, one of the following cases + must apply: + 1. Stack B was previously suspended using a ``stack_switch`` instruction. + 2. Stack B is a newly initialized stack. The necessary initialization is + platform-dependent and will generally involve running some kind of + trampoline to start execution of a function on the new stack. + + In both cases, the ``in_payload`` argument of the ``stack_switch`` + instruction executed on A is passed to stack B. In the first case above, + it will be the result value of the earlier ``stack_switch`` instruction + executed on stack B. In the second case, the value will be accessible to + the trampoline in a platform-dependent register. + + The pointers ``load_context_ptr`` and ``store_context_ptr`` are allowed + to be equal; the instruction ensures that all data is loaded from the + former before writing to the latter. + + Stack switching is one-shot in the sense that each ``stack_switch`` + operation effectively consumes the context identified by + ``load_context_ptr``. In other words, performing two ``stack_switches`` + using the same ``load_context_ptr`` causes undefined behavior, unless + the context at ``load_context_ptr`` is overwritten by another + `stack_switch` in between. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("store_context_ptr", iAddr), + Operand::new("load_context_ptr", iAddr), + Operand::new("in_payload0", iAddr), + ]) + .operands_out(vec![Operand::new("out_payload0", iAddr)]) + .other_side_effects() + .can_load() + .can_store() + .call(), + ); + + let I16x8 = &TypeVar::new( + "I16x8", + "A SIMD vector with exactly 8 lanes of 16-bit values", + TypeSetBuilder::new() + .ints(16..16) + .simd_lanes(8..8) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "uload8x8", + r#" + Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i16x8 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I16x8).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload8x8", + r#" + Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i16x8 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I16x8).with_doc("Value loaded")]) + .can_load(), + ); + + let I32x4 = &TypeVar::new( + "I32x4", + "A SIMD vector with exactly 4 lanes of 32-bit values", + TypeSetBuilder::new() + .ints(32..32) + .simd_lanes(4..4) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "uload16x4", + r#" + Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i32x4 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I32x4).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload16x4", + r#" + Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i32x4 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I32x4).with_doc("Value loaded")]) + .can_load(), + ); + + let I64x2 = &TypeVar::new( + "I64x2", + "A SIMD vector with exactly 2 lanes of 64-bit values", + TypeSetBuilder::new() + .ints(64..64) + .simd_lanes(2..2) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "uload32x2", + r#" + Load an 32x2 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i64x2 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I64x2).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "sload32x2", + r#" + Load a 32x2 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i64x2 + vector. + "#, + &formats.load, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"), + ]) + .operands_out(vec![Operand::new("a", I64x2).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "stack_load", + r#" + Load a value from a stack slot at the constant offset. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + + The offset is an immediate constant, not an SSA value. The memory + access cannot go out of bounds, i.e. + `sizeof(a) + Offset <= sizeof(SS)`. + "#, + &formats.stack_load, + ) + .operands_in(vec![ + Operand::new("SS", &entities.stack_slot), + Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"), + ]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "stack_store", + r#" + Store a value to a stack slot at a constant offset. + + This is a polymorphic instruction that can store any value type with a + memory representation. + + The offset is an immediate constant, not an SSA value. The memory + access cannot go out of bounds, i.e. + `sizeof(a) + Offset <= sizeof(SS)`. + "#, + &formats.stack_store, + ) + .operands_in(vec![ + Operand::new("x", Mem).with_doc("Value to be stored"), + Operand::new("SS", &entities.stack_slot), + Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"), + ]) + .can_store(), + ); + + ig.push( + Inst::new( + "stack_addr", + r#" + Get the address of a stack slot. + + Compute the absolute address of a byte in a stack slot. The offset must + refer to a byte inside the stack slot: + `0 <= Offset < sizeof(SS)`. + "#, + &formats.stack_load, + ) + .operands_in(vec![ + Operand::new("SS", &entities.stack_slot), + Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"), + ]) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); + + ig.push( + Inst::new( + "dynamic_stack_load", + r#" + Load a value from a dynamic stack slot. + + This is a polymorphic instruction that can load any value type which + has a memory representation. + "#, + &formats.dynamic_stack_load, + ) + .operands_in(vec![Operand::new("DSS", &entities.dynamic_stack_slot)]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]) + .can_load(), + ); + + ig.push( + Inst::new( + "dynamic_stack_store", + r#" + Store a value to a dynamic stack slot. + + This is a polymorphic instruction that can store any dynamic value type with a + memory representation. + "#, + &formats.dynamic_stack_store, + ) + .operands_in(vec![ + Operand::new("x", Mem).with_doc("Value to be stored"), + Operand::new("DSS", &entities.dynamic_stack_slot), + ]) + .can_store(), + ); + + ig.push( + Inst::new( + "dynamic_stack_addr", + r#" + Get the address of a dynamic stack slot. + + Compute the absolute address of the first byte of a dynamic stack slot. + "#, + &formats.dynamic_stack_load, + ) + .operands_in(vec![Operand::new("DSS", &entities.dynamic_stack_slot)]) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); + + ig.push( + Inst::new( + "global_value", + r#" + Compute the value of global GV. + "#, + &formats.unary_global_value, + ) + .operands_in(vec![Operand::new("GV", &entities.global_value)]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]), + ); + + ig.push( + Inst::new( + "symbol_value", + r#" + Compute the value of global GV, which is a symbolic value. + "#, + &formats.unary_global_value, + ) + .operands_in(vec![Operand::new("GV", &entities.global_value)]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]), + ); + + ig.push( + Inst::new( + "tls_value", + r#" + Compute the value of global GV, which is a TLS (thread local storage) value. + "#, + &formats.unary_global_value, + ) + .operands_in(vec![Operand::new("GV", &entities.global_value)]) + .operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]), + ); + + // Note this instruction is marked as having other side-effects, so GVN won't try to hoist it, + // which would result in it being subject to spilling. While not hoisting would generally hurt + // performance, since a computed value used many times may need to be regenerated before each + // use, it is not the case here: this instruction doesn't generate any code. That's because, + // by definition the pinned register is never used by the register allocator, but is written to + // and read explicitly and exclusively by set_pinned_reg and get_pinned_reg. + ig.push( + Inst::new( + "get_pinned_reg", + r#" + Gets the content of the pinned register, when it's enabled. + "#, + &formats.nullary, + ) + .operands_out(vec![Operand::new("addr", iAddr)]) + .other_side_effects(), + ); + + ig.push( + Inst::new( + "set_pinned_reg", + r#" + Sets the content of the pinned register, when it's enabled. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("addr", iAddr)]) + .other_side_effects(), + ); + + ig.push( + Inst::new( + "get_frame_pointer", + r#" + Get the address in the frame pointer register. + + Usage of this instruction requires setting `preserve_frame_pointers` to `true`. + "#, + &formats.nullary, + ) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); + + ig.push( + Inst::new( + "get_stack_pointer", + r#" + Get the address in the stack pointer register. + "#, + &formats.nullary, + ) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); + + ig.push( + Inst::new( + "get_return_address", + r#" + Get the PC where this function will transfer control to when it returns. + + Usage of this instruction requires setting `preserve_frame_pointers` to `true`. + "#, + &formats.nullary, + ) + .operands_out(vec![Operand::new("addr", iAddr)]), + ); + + ig.push( + Inst::new( + "iconst", + r#" + Integer constant. + + Create a scalar integer SSA value with an immediate constant value, or + an integer vector where all the lanes have the same value. + "#, + &formats.unary_imm, + ) + .operands_in(vec![Operand::new("N", &imm.imm64)]) + .operands_out(vec![ + Operand::new("a", NarrowInt).with_doc("A constant integer scalar or vector value") + ]), + ); + + ig.push( + Inst::new( + "f16const", + r#" + Floating point constant. + + Create a `f16` SSA value with an immediate constant value. + "#, + &formats.unary_ieee16, + ) + .operands_in(vec![Operand::new("N", &imm.ieee16)]) + .operands_out(vec![ + Operand::new("a", f16_).with_doc("A constant f16 scalar value") + ]), + ); + + ig.push( + Inst::new( + "f32const", + r#" + Floating point constant. + + Create a `f32` SSA value with an immediate constant value. + "#, + &formats.unary_ieee32, + ) + .operands_in(vec![Operand::new("N", &imm.ieee32)]) + .operands_out(vec![ + Operand::new("a", f32_).with_doc("A constant f32 scalar value") + ]), + ); + + ig.push( + Inst::new( + "f64const", + r#" + Floating point constant. + + Create a `f64` SSA value with an immediate constant value. + "#, + &formats.unary_ieee64, + ) + .operands_in(vec![Operand::new("N", &imm.ieee64)]) + .operands_out(vec![ + Operand::new("a", f64_).with_doc("A constant f64 scalar value") + ]), + ); + + ig.push( + Inst::new( + "f128const", + r#" + Floating point constant. + + Create a `f128` SSA value with an immediate constant value. + "#, + &formats.unary_const, + ) + .operands_in(vec![Operand::new("N", &imm.pool_constant)]) + .operands_out(vec![ + Operand::new("a", f128_).with_doc("A constant f128 scalar value") + ]), + ); + + ig.push( + Inst::new( + "vconst", + r#" + SIMD vector constant. + + Construct a vector with the given immediate bytes. + "#, + &formats.unary_const, + ) + .operands_in(vec![Operand::new("N", &imm.pool_constant) + .with_doc("The 16 immediate bytes of a 128-bit vector")]) + .operands_out(vec![ + Operand::new("a", TxN).with_doc("A constant vector value") + ]), + ); + + let Tx16 = &TypeVar::new( + "Tx16", + "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \ + lane counts and widths", + TypeSetBuilder::new() + .ints(8..8) + .simd_lanes(16..16) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "shuffle", + r#" + SIMD vector shuffle. + + Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the + immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of + 16-31 selects the (i-16)th element of the second vector. Immediate values outside of the + 0-31 range are not valid. + "#, + &formats.shuffle, + ) + .operands_in(vec![ + Operand::new("a", Tx16).with_doc("A vector value"), + Operand::new("b", Tx16).with_doc("A vector value"), + Operand::new("mask", &imm.uimm128) + .with_doc("The 16 immediate bytes used for selecting the elements to shuffle"), + ]) + .operands_out(vec![Operand::new("a", Tx16).with_doc("A vector value")]), + ); + + ig.push(Inst::new( + "nop", + r#" + Just a dummy instruction. + + Note: this doesn't compile to a machine code nop. + "#, + &formats.nullary, + )); + + ig.push( + Inst::new( + "select", + r#" + Conditional select. + + This instruction selects whole values. Use `bitselect` to choose each + bit according to a mask. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), + Operand::new("x", Any).with_doc("Value to use when `c` is true"), + Operand::new("y", Any).with_doc("Value to use when `c` is false"), + ]) + .operands_out(vec![Operand::new("a", Any)]), + ); + + ig.push( + Inst::new( + "select_spectre_guard", + r#" + Conditional select intended for Spectre guards. + + This operation is semantically equivalent to a select instruction. + However, this instruction prohibits all speculation on the + controlling value when determining which input to use as the result. + As such, it is suitable for use in Spectre guards. + + For example, on a target which may speculatively execute branches, + the lowering of this instruction is guaranteed to not conditionally + branch. Instead it will typically lower to a conditional move + instruction. (No Spectre-vulnerable processors are known to perform + value speculation on conditional move instructions.) + + Ensure that the instruction you're trying to protect from Spectre + attacks has a data dependency on the result of this instruction. + That prevents an out-of-order CPU from evaluating that instruction + until the result of this one is known, which in turn will be blocked + until the controlling value is known. + + Typical usage is to use a bounds-check as the controlling value, + and select between either a null pointer if the bounds-check + fails, or an in-bounds address otherwise, so that dereferencing + the resulting address with a load or store instruction will trap if + the bounds-check failed. When this instruction is used in this way, + any microarchitectural side effects of the memory access will only + occur after the bounds-check finishes, which ensures that no Spectre + vulnerability will exist. + + Optimization opportunities for this instruction are limited compared + to a normal select instruction, but it is allowed to be replaced + by other values which are functionally equivalent as long as doing + so does not introduce any new opportunities to speculate on the + controlling value. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), + Operand::new("x", Any).with_doc("Value to use when `c` is true"), + Operand::new("y", Any).with_doc("Value to use when `c` is false"), + ]) + .operands_out(vec![Operand::new("a", Any)]), + ); + + ig.push( + Inst::new( + "bitselect", + r#" + Conditional select of bits. + + For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit + in `x` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also: + `select`. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("c", Any).with_doc("Controlling value to test"), + Operand::new("x", Any).with_doc("Value to use when `c` is true"), + Operand::new("y", Any).with_doc("Value to use when `c` is false"), + ]) + .operands_out(vec![Operand::new("a", Any)]), + ); + + ig.push( + Inst::new( + "x86_blendv", + r#" + A bitselect-lookalike instruction except with the semantics of + `blendv`-related instructions on x86. + + This instruction will use the top bit of each lane in `c`, the condition + mask. If the bit is 1 then the corresponding lane from `x` is chosen. + Otherwise the corresponding lane from `y` is chosen. + + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("c", Any).with_doc("Controlling value to test"), + Operand::new("x", Any).with_doc("Value to use when `c` is true"), + Operand::new("y", Any).with_doc("Value to use when `c` is false"), + ]) + .operands_out(vec![Operand::new("a", Any)]), + ); + + ig.push( + Inst::new( + "vany_true", + r#" + Reduce a vector to a scalar boolean. + + Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("a", TxN)]) + .operands_out(vec![Operand::new("s", i8)]), + ); + + ig.push( + Inst::new( + "vall_true", + r#" + Reduce a vector to a scalar boolean. + + Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("a", TxN)]) + .operands_out(vec![Operand::new("s", i8)]), + ); + + ig.push( + Inst::new( + "vhigh_bits", + r#" + Reduce a vector to a scalar integer. + + Return a scalar integer, consisting of the concatenation of the most significant bit + of each lane of ``a``. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("a", TxN)]) + .operands_out(vec![Operand::new("x", NarrowInt)]), + ); + + ig.push( + Inst::new( + "icmp", + r#" + Integer comparison. + + The condition code determines if the operands are interpreted as signed + or unsigned integers. + + | Signed | Unsigned | Condition | + |--------|----------|-----------------------| + | eq | eq | Equal | + | ne | ne | Not equal | + | slt | ult | Less than | + | sge | uge | Greater than or equal | + | sgt | ugt | Greater than | + | sle | ule | Less than or equal | + + When this instruction compares integer vectors, it returns a vector of + lane-wise comparisons. + + When comparing scalars, the result is: + - `1` if the condition holds. + - `0` if the condition does not hold. + + When comparing vectors, the result is: + - `-1` (i.e. all ones) in each lane where the condition holds. + - `0` in each lane where the condition does not hold. + "#, + &formats.int_compare, + ) + .operands_in(vec![ + Operand::new("Cond", &imm.intcc), + Operand::new("x", Int), + Operand::new("y", Int), + ]) + .operands_out(vec![Operand::new("a", &Int.as_truthy())]), + ); + + ig.push( + Inst::new( + "icmp_imm", + r#" + Compare scalar integer to a constant. + + This is the same as the `icmp` instruction, except one operand is + a sign extended 64 bit immediate constant. + + This instruction can only compare scalars. Use `icmp` for + lane-wise vector comparisons. + "#, + &formats.int_compare_imm, + ) + .operands_in(vec![ + Operand::new("Cond", &imm.intcc), + Operand::new("x", iB), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", i8)]), + ); + + ig.push( + Inst::new( + "iadd", + r#" + Wrapping integer addition: `a := x + y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the operands. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "isub", + r#" + Wrapping integer subtraction: `a := x - y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the operands. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "ineg", + r#" + Integer negation: `a := -x \pmod{2^B}`. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "iabs", + r#" + Integer absolute value with wrapping: `a := |x|`. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "imul", + r#" + Wrapping integer multiplication: `a := x y \pmod{2^B}`. + + This instruction does not depend on the signed/unsigned interpretation + of the operands. + + Polymorphic over all integer types (vector and scalar). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "umulhi", + r#" + Unsigned integer multiplication, producing the high half of a + double-length result. + + Polymorphic over all integer types (vector and scalar). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "smulhi", + r#" + Signed integer multiplication, producing the high half of a + double-length result. + + Polymorphic over all integer types (vector and scalar). + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + let I16or32 = &TypeVar::new( + "I16or32", + "A vector integer type with 16- or 32-bit numbers", + TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(), + ); + + ig.push( + Inst::new( + "sqmul_round_sat", + r#" + Fixed-point multiplication of numbers in the QN format, where N + 1 + is the number bitwidth: + `a := signed_saturate((x * y + (1 << (Q - 1))) >> Q)` + + Polymorphic over all integer vector types with 16- or 32-bit numbers. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)]) + .operands_out(vec![Operand::new("a", I16or32)]), + ); + + ig.push( + Inst::new( + "x86_pmulhrsw", + r#" + A similar instruction to `sqmul_round_sat` except with the semantics + of x86's `pmulhrsw` instruction. + + This is the same as `sqmul_round_sat` except when both input lanes are + `i16::MIN`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)]) + .operands_out(vec![Operand::new("a", I16or32)]), + ); + + // Integer division and remainder are scalar-only; most + // hardware does not directly support vector integer division. + + ig.push( + Inst::new( + "udiv", + r#" + Unsigned integer division: `a := \lfloor {x \over y} \rfloor`. + + This operation traps if the divisor is zero. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "sdiv", + r#" + Signed integer division rounded toward zero: `a := sign(xy) + \lfloor {|x| \over |y|}\rfloor`. + + This operation traps if the divisor is zero, or if the result is not + representable in `B` bits two's complement. This only happens + when `x = -2^{B-1}, y = -1`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "urem", + r#" + Unsigned integer remainder. + + This operation traps if the divisor is zero. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "srem", + r#" + Signed integer remainder. The result has the sign of the dividend. + + This operation traps if the divisor is zero. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "iadd_imm", + r#" + Add immediate integer. + + Same as `iadd`, but one operand is a sign extended 64 bit immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "imul_imm", + r#" + Integer multiplication by immediate constant. + + Same as `imul`, but one operand is a sign extended 64 bit immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "udiv_imm", + r#" + Unsigned integer division by an immediate constant. + + Same as `udiv`, but one operand is a zero extended 64 bit immediate constant. + + This operation traps if the divisor is zero. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "sdiv_imm", + r#" + Signed integer division by an immediate constant. + + Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant. + + This operation traps if the divisor is zero, or if the result is not + representable in `B` bits two's complement. This only happens + when `x = -2^{B-1}, Y = -1`. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "urem_imm", + r#" + Unsigned integer remainder with immediate divisor. + + Same as `urem`, but one operand is a zero extended 64 bit immediate constant. + + This operation traps if the divisor is zero. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "srem_imm", + r#" + Signed integer remainder with immediate divisor. + + Same as `srem`, but one operand is a sign extended 64 bit immediate constant. + + This operation traps if the divisor is zero. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "irsub_imm", + r#" + Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`. + + The immediate operand is a sign extended 64 bit constant. + + Also works as integer negation when `Y = 0`. Use `iadd_imm` + with a negative immediate operand for the reverse immediate + subtraction. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "sadd_overflow_cin", + r#" + Add signed integers with carry in and overflow out. + + Same as `sadd_overflow` with an additional carry input. The `c_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("x", iB), + Operand::new("y", iB), + Operand::new("c_in", i8).with_doc("Input carry flag"), + ]) + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("c_out", i8).with_doc("Output carry flag"), + ]), + ); + + ig.push( + Inst::new( + "uadd_overflow_cin", + r#" + Add unsigned integers with carry in and overflow out. + + Same as `uadd_overflow` with an additional carry input. The `c_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("x", iB), + Operand::new("y", iB), + Operand::new("c_in", i8).with_doc("Input carry flag"), + ]) + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("c_out", i8).with_doc("Output carry flag"), + ]), + ); + + { + let of_out = Operand::new("of", i8).with_doc("Overflow flag"); + ig.push( + Inst::new( + "uadd_overflow", + r#" + Add integers unsigned with overflow out. + ``of`` is set when the addition overflowed. + ```text + a &= x + y \pmod 2^B \\ + of &= x+y >= 2^B + ``` + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB), of_out.clone()]), + ); + + ig.push( + Inst::new( + "sadd_overflow", + r#" + Add integers signed with overflow out. + ``of`` is set when the addition over- or underflowed. + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB), of_out.clone()]), + ); + + ig.push( + Inst::new( + "usub_overflow", + r#" + Subtract integers unsigned with overflow out. + ``of`` is set when the subtraction underflowed. + ```text + a &= x - y \pmod 2^B \\ + of &= x - y < 0 + ``` + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB), of_out.clone()]), + ); + + ig.push( + Inst::new( + "ssub_overflow", + r#" + Subtract integers signed with overflow out. + ``of`` is set when the subtraction over- or underflowed. + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) + .operands_out(vec![Operand::new("a", iB), of_out.clone()]), + ); + + { + let NarrowScalar = &TypeVar::new( + "NarrowScalar", + "A scalar integer type up to 64 bits", + TypeSetBuilder::new().ints(8..64).build(), + ); + + ig.push( + Inst::new( + "umul_overflow", + r#" + Multiply integers unsigned with overflow out. + ``of`` is set when the multiplication overflowed. + ```text + a &= x * y \pmod 2^B \\ + of &= x * y > 2^B + ``` + Polymorphic over all scalar integer types except i128, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", NarrowScalar), + Operand::new("y", NarrowScalar), + ]) + .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]), + ); + + ig.push( + Inst::new( + "smul_overflow", + r#" + Multiply integers signed with overflow out. + ``of`` is set when the multiplication over- or underflowed. + Polymorphic over all scalar integer types except i128, but does not support vector + types. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", NarrowScalar), + Operand::new("y", NarrowScalar), + ]) + .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]), + ); + } + } + + let i32_64 = &TypeVar::new( + "i32_64", + "A 32 or 64-bit scalar integer type", + TypeSetBuilder::new().ints(32..64).build(), + ); + + ig.push( + Inst::new( + "uadd_overflow_trap", + r#" + Unsigned addition of x and y, trapping if the result overflows. + + Accepts 32 or 64-bit integers, and does not support vector types. + "#, + &formats.int_add_trap, + ) + .operands_in(vec![ + Operand::new("x", i32_64), + Operand::new("y", i32_64), + Operand::new("code", &imm.trapcode), + ]) + .operands_out(vec![Operand::new("a", i32_64)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "ssub_overflow_bin", + r#" + Subtract signed integers with borrow in and overflow out. + + Same as `ssub_overflow` with an additional borrow input. The `b_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. The computation + performed here is `x - (y + (b_in != 0))`. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("x", iB), + Operand::new("y", iB), + Operand::new("b_in", i8).with_doc("Input borrow flag"), + ]) + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("b_out", i8).with_doc("Output borrow flag"), + ]), + ); + + ig.push( + Inst::new( + "usub_overflow_bin", + r#" + Subtract unsigned integers with borrow in and overflow out. + + Same as `usub_overflow` with an additional borrow input. The `b_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. The computation + performed here is `x - (y + (b_in != 0))`. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("x", iB), + Operand::new("y", iB), + Operand::new("b_in", i8).with_doc("Input borrow flag"), + ]) + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("b_out", i8).with_doc("Output borrow flag"), + ]), + ); + + let bits = &TypeVar::new( + "bits", + "Any integer, float, or vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .simd_lanes(Interval::All) + .includes_scalars(true) + .build(), + ); + + ig.push( + Inst::new( + "band", + r#" + Bitwise and. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "bor", + r#" + Bitwise or. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "bxor", + r#" + Bitwise xor. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "bnot", + r#" + Bitwise not. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "band_not", + r#" + Bitwise and not. + + Computes `x & ~y`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "bor_not", + r#" + Bitwise or not. + + Computes `x | ~y`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "bxor_not", + r#" + Bitwise xor not. + + Computes `x ^ ~y`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) + .operands_out(vec![Operand::new("a", bits)]), + ); + + ig.push( + Inst::new( + "band_imm", + r#" + Bitwise and with immediate. + + Same as `band`, but one operand is a zero extended 64 bit immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "bor_imm", + r#" + Bitwise or with immediate. + + Same as `bor`, but one operand is a zero extended 64 bit immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "bxor_imm", + r#" + Bitwise xor with immediate. + + Same as `bxor`, but one operand is a zero extended 64 bit immediate constant. + + Polymorphic over all scalar integer types, but does not support vector + types. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "rotl", + r#" + Rotate left. + + Rotate the bits in ``x`` by ``y`` places. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("y", iB).with_doc("Number of bits to shift"), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "rotr", + r#" + Rotate right. + + Rotate the bits in ``x`` by ``y`` places. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("y", iB).with_doc("Number of bits to shift"), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "rotl_imm", + r#" + Rotate left by immediate. + + Same as `rotl`, but one operand is a zero extended 64 bit immediate constant. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "rotr_imm", + r#" + Rotate right by immediate. + + Same as `rotr`, but one operand is a zero extended 64 bit immediate constant. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "ishl", + r#" + Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` + places. Shift in zero bits to the LSB. + + The shift amount is masked to the size of ``x``. + + When shifting a B-bits integer type, this instruction computes: + + ```text + s &:= y \pmod B, + a &:= x \cdot 2^s \pmod{2^B}. + ``` + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("y", iB).with_doc("Number of bits to shift"), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "ushr", + r#" + Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` + places, shifting in zero bits to the MSB. Also called a *logical + shift*. + + The shift amount is masked to the size of ``x``. + + When shifting a B-bits integer type, this instruction computes: + + ```text + s &:= y \pmod B, + a &:= \lfloor x \cdot 2^{-s} \rfloor. + ``` + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("y", iB).with_doc("Number of bits to shift"), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "sshr", + r#" + Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` + places, shifting in sign bits to the MSB. Also called an *arithmetic + shift*. + + The shift amount is masked to the size of ``x``. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("y", iB).with_doc("Number of bits to shift"), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "ishl_imm", + r#" + Integer shift left by immediate. + + The shift amount is masked to the size of ``x``. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "ushr_imm", + r#" + Unsigned shift right by immediate. + + The shift amount is masked to the size of ``x``. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "sshr_imm", + r#" + Signed shift right by immediate. + + The shift amount is masked to the size of ``x``. + "#, + &formats.binary_imm64, + ) + .operands_in(vec![ + Operand::new("x", Int).with_doc("Scalar or vector value to shift"), + Operand::new("Y", &imm.imm64), + ]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "bitrev", + r#" + Reverse the bits of a integer. + + Reverses the bits in ``x``. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", iB)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "clz", + r#" + Count leading zero bits. + + Starting from the MSB in ``x``, count the number of zero bits before + reaching the first one bit. When ``x`` is zero, returns the size of x + in bits. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", iB)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "cls", + r#" + Count leading sign bits. + + Starting from the MSB after the sign bit in ``x``, count the number of + consecutive bits identical to the sign bit. When ``x`` is 0 or -1, + returns one less than the size of x in bits. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", iB)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "ctz", + r#" + Count trailing zeros. + + Starting from the LSB in ``x``, count the number of zero bits before + reaching the first one bit. When ``x`` is zero, returns the size of x + in bits. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", iB)]) + .operands_out(vec![Operand::new("a", iB)]), + ); + + ig.push( + Inst::new( + "bswap", + r#" + Reverse the byte order of an integer. + + Reverses the bytes in ``x``. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", iSwappable)]) + .operands_out(vec![Operand::new("a", iSwappable)]), + ); + + ig.push( + Inst::new( + "popcnt", + r#" + Population count + + Count the number of one bits in ``x``. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Int)]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + let Float = &TypeVar::new( + "Float", + "A scalar or vector floating point number", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .dynamic_simd_lanes(Interval::All) + .build(), + ); + + ig.push( + Inst::new( + "fcmp", + r#" + Floating point comparison. + + Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each + other in exactly one of four ways: + + ```text + == ========================================== + UN Unordered when one or both numbers is NaN. + EQ When `x = y`. (And `0.0 = -0.0`). + LT When `x < y`. + GT When `x > y`. + == ========================================== + ``` + + The 14 `floatcc` condition codes each correspond to a subset of + the four relations, except for the empty set which would always be + false, and the full set which would always be true. + + The condition codes are divided into 7 'ordered' conditions which don't + include UN, and 7 unordered conditions which all include UN. + + ```text + +-------+------------+---------+------------+-------------------------+ + |Ordered |Unordered |Condition | + +=======+============+=========+============+=========================+ + |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | + +-------+------------+---------+------------+-------------------------+ + |eq |EQ |ueq |UN | EQ |Equal | + +-------+------------+---------+------------+-------------------------+ + |one |LT | GT |ne |UN | LT | GT|Not equal | + +-------+------------+---------+------------+-------------------------+ + |lt |LT |ult |UN | LT |Less than | + +-------+------------+---------+------------+-------------------------+ + |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | + +-------+------------+---------+------------+-------------------------+ + |gt |GT |ugt |UN | GT |Greater than | + +-------+------------+---------+------------+-------------------------+ + |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | + +-------+------------+---------+------------+-------------------------+ + ``` + + The standard C comparison operators, `<, <=, >, >=`, are all ordered, + so they are false if either operand is NaN. The C equality operator, + `==`, is ordered, and since inequality is defined as the logical + inverse it is *unordered*. They map to the `floatcc` condition + codes as follows: + + ```text + ==== ====== ============ + C `Cond` Subset + ==== ====== ============ + `==` eq EQ + `!=` ne UN | LT | GT + `<` lt LT + `<=` le LT | EQ + `>` gt GT + `>=` ge GT | EQ + ==== ====== ============ + ``` + + This subset of condition codes also corresponds to the WebAssembly + floating point comparisons of the same name. + + When this instruction compares floating point vectors, it returns a + vector with the results of lane-wise comparisons. + + When comparing scalars, the result is: + - `1` if the condition holds. + - `0` if the condition does not hold. + + When comparing vectors, the result is: + - `-1` (i.e. all ones) in each lane where the condition holds. + - `0` in each lane where the condition does not hold. + "#, + &formats.float_compare, + ) + .operands_in(vec![ + Operand::new("Cond", &imm.floatcc), + Operand::new("x", Float), + Operand::new("y", Float), + ]) + .operands_out(vec![Operand::new("a", &Float.as_truthy())]), + ); + + ig.push( + Inst::new( + "fadd", + r#" + Floating point addition. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "fsub", + r#" + Floating point subtraction. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "fmul", + r#" + Floating point multiplication. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "fdiv", + r#" + Floating point division. + + Unlike the integer division instructions ` and + `udiv`, this can't trap. Division by zero is infinity or + NaN, depending on the dividend. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "sqrt", + r#" + Floating point square root. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "fma", + r#" + Floating point fused multiply-and-add. + + Computes `a := xy+z` without any intermediate rounding of the + product. + "#, + &formats.ternary, + ) + .operands_in(vec![ + Operand::new("x", Float), + Operand::new("y", Float), + Operand::new("z", Float), + ]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("Result of applying operator to each lane") + ]), + ); + + ig.push( + Inst::new( + "fneg", + r#" + Floating point negation. + + Note that this is a pure bitwise operation. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` with its sign bit inverted") + ]), + ); + + ig.push( + Inst::new( + "fabs", + r#" + Floating point absolute value. + + Note that this is a pure bitwise operation. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` with its sign bit cleared") + ]), + ); + + ig.push( + Inst::new( + "fcopysign", + r#" + Floating point copy sign. + + Note that this is a pure bitwise operation. The sign bit from ``y`` is + copied to the sign bit of ``x``. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``") + ]), + ); + + ig.push( + Inst::new( + "fmin", + r#" + Floating point minimum, propagating NaNs using the WebAssembly rules. + + If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if + each input NaN consists of a mantissa whose most significant bit is 1 and the rest is + 0, then the output has the same form. Otherwise, the output mantissa's most significant + bit is 1 and the rest is unspecified. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``") + ]), + ); + + ig.push( + Inst::new( + "fmax", + r#" + Floating point maximum, propagating NaNs using the WebAssembly rules. + + If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if + each input NaN consists of a mantissa whose most significant bit is 1 and the rest is + 0, then the output has the same form. Otherwise, the output mantissa's most significant + bit is 1 and the rest is unspecified. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``") + ]), + ); + + ig.push( + Inst::new( + "ceil", + r#" + Round floating point round to integral, towards positive infinity. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` rounded to integral value") + ]), + ); + + ig.push( + Inst::new( + "floor", + r#" + Round floating point round to integral, towards negative infinity. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` rounded to integral value") + ]), + ); + + ig.push( + Inst::new( + "trunc", + r#" + Round floating point round to integral, towards zero. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` rounded to integral value") + ]), + ); + + ig.push( + Inst::new( + "nearest", + r#" + Round floating point round to integral, towards nearest with ties to + even. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![ + Operand::new("a", Float).with_doc("``x`` rounded to integral value") + ]), + ); + + ig.push( + Inst::new( + "bitcast", + r#" + Reinterpret the bits in `x` as a different type. + + The input and output types must be storable to memory and of the same + size. A bitcast is equivalent to storing one type and loading the other + type from the same address, both using the specified MemFlags. + + Note that this operation only supports the `big` or `little` MemFlags. + The specified byte order only affects the result in the case where + input and output types differ in lane count/size. In this case, the + operation is only valid if a byte order specifier is provided. + "#, + &formats.load_no_offset, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", Mem), + ]) + .operands_out(vec![ + Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted") + ]), + ); + + ig.push( + Inst::new( + "scalar_to_vector", + r#" + Copies a scalar value to a vector value. The scalar is copied into the + least significant lane of the vector, and all other lanes will be zero. + "#, + &formats.unary, + ) + .operands_in(vec![ + Operand::new("s", &TxN.lane_of()).with_doc("A scalar value") + ]) + .operands_out(vec![Operand::new("a", TxN).with_doc("A vector value")]), + ); + + let Truthy = &TypeVar::new( + "Truthy", + "A scalar whose values are truthy", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + let IntTo = &TypeVar::new( + "IntTo", + "An integer type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + ig.push( + Inst::new( + "bmask", + r#" + Convert `x` to an integer mask. + + Non-zero maps to all 1s and zero maps to all 0s. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Truthy)]) + .operands_out(vec![Operand::new("a", IntTo)]), + ); + + let Int = &TypeVar::new( + "Int", + "A scalar integer type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + ig.push( + Inst::new( + "ireduce", + r#" + Convert `x` to a smaller integer type by discarding + the most significant bits. + + This is the same as reducing modulo `2^n`. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", &Int.wider()) + .with_doc("A scalar integer type, wider than the controlling type")]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + let I16or32or64xN = &TypeVar::new( + "I16or32or64xN", + "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", + TypeSetBuilder::new() + .ints(16..64) + .simd_lanes(2..8) + .dynamic_simd_lanes(2..8) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "snarrow", + r#" + Combine `x` and `y` into a vector with twice the lanes but half the integer width while + saturating overflowing values to the signed maximum and minimum. + + The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` + and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value + returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", I16or32or64xN), + Operand::new("y", I16or32or64xN), + ]) + .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), + ); + + ig.push( + Inst::new( + "unarrow", + r#" + Combine `x` and `y` into a vector with twice the lanes but half the integer width while + saturating overflowing values to the unsigned maximum and minimum. + + Note that all input lanes are considered signed: any negative lanes will overflow and be + replaced with the unsigned minimum, `0x00`. + + The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` + and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value + returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", I16or32or64xN), + Operand::new("y", I16or32or64xN), + ]) + .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), + ); + + ig.push( + Inst::new( + "uunarrow", + r#" + Combine `x` and `y` into a vector with twice the lanes but half the integer width while + saturating overflowing values to the unsigned maximum and minimum. + + Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. + + The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` + and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value + returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", I16or32or64xN), Operand::new("y", I16or32or64xN)]) + .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), + ); + + let I8or16or32xN = &TypeVar::new( + "I8or16or32xN", + "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", + TypeSetBuilder::new() + .ints(8..32) + .simd_lanes(2..16) + .dynamic_simd_lanes(2..16) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "swiden_low", + r#" + Widen the low lanes of `x` using signed extension. + + This will double the lane width and halve the number of lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", I8or16or32xN)]) + .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), + ); + + ig.push( + Inst::new( + "swiden_high", + r#" + Widen the high lanes of `x` using signed extension. + + This will double the lane width and halve the number of lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", I8or16or32xN)]) + .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), + ); + + ig.push( + Inst::new( + "uwiden_low", + r#" + Widen the low lanes of `x` using unsigned extension. + + This will double the lane width and halve the number of lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", I8or16or32xN)]) + .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), + ); + + ig.push( + Inst::new( + "uwiden_high", + r#" + Widen the high lanes of `x` using unsigned extension. + + This will double the lane width and halve the number of lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", I8or16or32xN)]) + .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), + ); + + ig.push( + Inst::new( + "iadd_pairwise", + r#" + Does lane-wise integer pairwise addition on two operands, putting the + combined results into a single vector result. Here a pair refers to adjacent + lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand + pairwise add results will make up the low half of the resulting vector while + the second operand pairwise add results will make up the upper half of the + resulting vector. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("x", I8or16or32xN), + Operand::new("y", I8or16or32xN), + ]) + .operands_out(vec![Operand::new("a", I8or16or32xN)]), + ); + + let I8x16 = &TypeVar::new( + "I8x16", + "A SIMD vector type consisting of 16 lanes of 8-bit integers", + TypeSetBuilder::new() + .ints(8..8) + .simd_lanes(16..16) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "x86_pmaddubsw", + r#" + An instruction with equivalent semantics to `pmaddubsw` on x86. + + This instruction will take signed bytes from the first argument and + multiply them against unsigned bytes in the second argument. Adjacent + pairs are then added, with saturating, to a 16-bit value and are packed + into the result. + "#, + &formats.binary, + ) + .operands_in(vec![Operand::new("x", I8x16), Operand::new("y", I8x16)]) + .operands_out(vec![Operand::new("a", I16x8)]), + ); + + ig.push( + Inst::new( + "uextend", + r#" + Convert `x` to a larger integer type by zero-extending. + + Each lane in `x` is converted to a larger integer type by adding + zeroes. The result has the same numerical value as `x` when both are + interpreted as unsigned integers. + + The result type must have the same number of vector lanes as the input, + and each lane must not have fewer bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc( + "A scalar integer type, narrower than the controlling type", + )]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + ig.push( + Inst::new( + "sextend", + r#" + Convert `x` to a larger integer type by sign-extending. + + Each lane in `x` is converted to a larger integer type by replicating + the sign bit. The result has the same numerical value as `x` when both + are interpreted as signed integers. + + The result type must have the same number of vector lanes as the input, + and each lane must not have fewer bits that the input lanes. If the + input and output types are the same, this is a no-op. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc( + "A scalar integer type, narrower than the controlling type", + )]) + .operands_out(vec![Operand::new("a", Int)]), + ); + + let FloatScalar = &TypeVar::new( + "FloatScalar", + "A scalar only floating point number", + TypeSetBuilder::new().floats(Interval::All).build(), + ); + + ig.push( + Inst::new( + "fpromote", + r#" + Convert `x` to a larger floating point format. + + Each lane in `x` is converted to the destination floating point format. + This is an exact operation. + + Cranelift currently only supports two floating point formats + - `f32` and `f64`. This may change in the future. + + The result type must have the same number of vector lanes as the input, + and the result lanes must not have fewer bits than the input lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", &FloatScalar.narrower()).with_doc( + "A scalar only floating point number, narrower than the controlling type", + )]) + .operands_out(vec![Operand::new("a", FloatScalar)]), + ); + + ig.push( + Inst::new( + "fdemote", + r#" + Convert `x` to a smaller floating point format. + + Each lane in `x` is converted to the destination floating point format + by rounding to nearest, ties to even. + + Cranelift currently only supports two floating point formats + - `f32` and `f64`. This may change in the future. + + The result type must have the same number of vector lanes as the input, + and the result lanes must not have more bits than the input lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", &FloatScalar.wider()).with_doc( + "A scalar only floating point number, wider than the controlling type", + )]) + .operands_out(vec![Operand::new("a", FloatScalar)]), + ); + + let F64x2 = &TypeVar::new( + "F64x2", + "A SIMD vector type consisting of 2 lanes of 64-bit floats", + TypeSetBuilder::new() + .floats(64..64) + .simd_lanes(2..2) + .includes_scalars(false) + .build(), + ); + let F32x4 = &TypeVar::new( + "F32x4", + "A SIMD vector type consisting of 4 lanes of 32-bit floats", + TypeSetBuilder::new() + .floats(32..32) + .simd_lanes(4..4) + .includes_scalars(false) + .build(), + ); + + ig.push( + Inst::new( + "fvdemote", + r#" + Convert `x` to a smaller floating point format. + + Each lane in `x` is converted to the destination floating point format + by rounding to nearest, ties to even. + + Cranelift currently only supports two floating point formats + - `f32` and `f64`. This may change in the future. + + Fvdemote differs from fdemote in that with fvdemote it targets vectors. + Fvdemote is constrained to having the input type being F64x2 and the result + type being F32x4. The result lane that was the upper half of the input lane + is initialized to zero. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", F64x2)]) + .operands_out(vec![Operand::new("a", F32x4)]), + ); + + ig.push( + Inst::new( + "fvpromote_low", + r#" + Converts packed single precision floating point to packed double precision floating point. + + Considering only the lower half of the register, the low lanes in `x` are interpreted as + single precision floats that are then converted to a double precision floats. + + The result type will have half the number of vector lanes as the input. Fvpromote_low is + constrained to input F32x4 with a result type of F64x2. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("a", F32x4)]) + .operands_out(vec![Operand::new("x", F64x2)]), + ); + + let IntTo = &TypeVar::new( + "IntTo", + "An scalar only integer type", + TypeSetBuilder::new().ints(Interval::All).build(), + ); + + ig.push( + Inst::new( + "fcvt_to_uint", + r#" + Converts floating point scalars to unsigned integer. + + Only operates on `x` if it is a scalar. If `x` is NaN or if + the unsigned integral value cannot be represented in the result + type, this instruction traps. + + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", FloatScalar)]) + .operands_out(vec![Operand::new("a", IntTo)]) + .can_trap() + .side_effects_idempotent(), + ); + + ig.push( + Inst::new( + "fcvt_to_sint", + r#" + Converts floating point scalars to signed integer. + + Only operates on `x` if it is a scalar. If `x` is NaN or if + the unsigned integral value cannot be represented in the result + type, this instruction traps. + + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", FloatScalar)]) + .operands_out(vec![Operand::new("a", IntTo)]) + .can_trap() + .side_effects_idempotent(), + ); + + let IntTo = &TypeVar::new( + "IntTo", + "A larger integer type with the same number of lanes", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .build(), + ); + + ig.push( + Inst::new( + "fcvt_to_uint_sat", + r#" + Convert floating point to unsigned integer as fcvt_to_uint does, but + saturates the input instead of trapping. NaN and negative values are + converted to 0. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![Operand::new("a", IntTo)]), + ); + + ig.push( + Inst::new( + "fcvt_to_sint_sat", + r#" + Convert floating point to signed integer as fcvt_to_sint does, but + saturates the input instead of trapping. NaN values are converted to 0. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![Operand::new("a", IntTo)]), + ); + + ig.push( + Inst::new( + "x86_cvtt2dq", + r#" + A float-to-integer conversion instruction for vectors-of-floats which + has the same semantics as `cvttp{s,d}2dq` on x86. This specifically + returns `INT_MIN` for NaN or out-of-bounds lanes. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Float)]) + .operands_out(vec![Operand::new("a", IntTo)]), + ); + + let Int = &TypeVar::new( + "Int", + "A scalar or vector integer type", + TypeSetBuilder::new() + .ints(Interval::All) + .simd_lanes(Interval::All) + .build(), + ); + + let FloatTo = &TypeVar::new( + "FloatTo", + "A scalar or vector floating point number", + TypeSetBuilder::new() + .floats(Interval::All) + .simd_lanes(Interval::All) + .build(), + ); + + ig.push( + Inst::new( + "fcvt_from_uint", + r#" + Convert unsigned integer to floating point. + + Each lane in `x` is interpreted as an unsigned integer and converted to + floating point using round to nearest, ties to even. + + The result type must have the same number of vector lanes as the input. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Int)]) + .operands_out(vec![Operand::new("a", FloatTo)]), + ); + + ig.push( + Inst::new( + "fcvt_from_sint", + r#" + Convert signed integer to floating point. + + Each lane in `x` is interpreted as a signed integer and converted to + floating point using round to nearest, ties to even. + + The result type must have the same number of vector lanes as the input. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", Int)]) + .operands_out(vec![Operand::new("a", FloatTo)]), + ); + + let WideInt = &TypeVar::new( + "WideInt", + "An integer type of width `i16` upwards", + TypeSetBuilder::new().ints(16..128).build(), + ); + + ig.push( + Inst::new( + "isplit", + r#" + Split an integer into low and high parts. + + Vectors of integers are split lane-wise, so the results have the same + number of lanes as the input, but the lanes are half the size. + + Returns the low half of `x` and the high half of `x` as two independent + values. + "#, + &formats.unary, + ) + .operands_in(vec![Operand::new("x", WideInt)]) + .operands_out(vec![ + Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"), + Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"), + ]), + ); + + ig.push( + Inst::new( + "iconcat", + r#" + Concatenate low and high bits to form a larger integer type. + + Vectors of integers are concatenated lane-wise such that the result has + the same number of lanes as the inputs, but the lanes are twice the + size. + "#, + &formats.binary, + ) + .operands_in(vec![ + Operand::new("lo", NarrowInt), + Operand::new("hi", NarrowInt), + ]) + .operands_out(vec![Operand::new("a", &NarrowInt.double_width()) + .with_doc("The concatenation of `lo` and `hi`")]), + ); + + // Instructions relating to atomic memory accesses and fences + let AtomicMem = &TypeVar::new( + "AtomicMem", + "Any type that can be stored in memory, which can be used in an atomic operation", + TypeSetBuilder::new().ints(8..128).build(), + ); + + ig.push( + Inst::new( + "atomic_rmw", + r#" + Atomically read-modify-write memory at `p`, with second operand `x`. The old value is + returned. `p` has the type of the target word size, and `x` may be any integer type; note + that some targets require specific target features to be enabled in order to support 128-bit + integer atomics. The type of the returned value is the same as the type of `x`. This + operation is sequentially consistent and creates happens-before edges that order normal + (non-atomic) loads and stores. + "#, + &formats.atomic_rmw, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("AtomicRmwOp", &imm.atomic_rmw_op), + Operand::new("p", iAddr), + Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), + ]) + .operands_out(vec![ + Operand::new("a", AtomicMem).with_doc("Value atomically loaded") + ]) + .can_load() + .can_store() + .other_side_effects(), + ); + + ig.push( + Inst::new( + "atomic_cas", + r#" + Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, + storing `x` if the value at `p` equals `e`. The old value at `p` is returned, + regardless of whether the operation succeeds or fails. `p` has the type of the target + word size, and `x` and `e` must have the same type and the same size, which may be any + integer type; note that some targets require specific target features to be enabled in order + to support 128-bit integer atomics. The type of the returned value is the same as the type + of `x` and `e`. This operation is sequentially consistent and creates happens-before edges + that order normal (non-atomic) loads and stores. + "#, + &formats.atomic_cas, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + Operand::new("e", AtomicMem).with_doc("Expected value in CAS"), + Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), + ]) + .operands_out(vec![ + Operand::new("a", AtomicMem).with_doc("Value atomically loaded") + ]) + .can_load() + .can_store() + .other_side_effects(), + ); + + ig.push( + Inst::new( + "atomic_load", + r#" + Atomically load from memory at `p`. + + This is a polymorphic instruction that can load any value type which has a memory + representation. It can only be used for integer types; note that some targets require + specific target features to be enabled in order to support 128-bit integer atomics. This + operation is sequentially consistent and creates happens-before edges that order normal + (non-atomic) loads and stores. + "#, + &formats.load_no_offset, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("p", iAddr), + ]) + .operands_out(vec![ + Operand::new("a", AtomicMem).with_doc("Value atomically loaded") + ]) + .can_load() + .other_side_effects(), + ); + + ig.push( + Inst::new( + "atomic_store", + r#" + Atomically store `x` to memory at `p`. + + This is a polymorphic instruction that can store any value type with a memory + representation. It can only be used for integer types; note that some targets require + specific target features to be enabled in order to support 128-bit integer atomics This + operation is sequentially consistent and creates happens-before edges that order normal + (non-atomic) loads and stores. + "#, + &formats.store_no_offset, + ) + .operands_in(vec![ + Operand::new("MemFlags", &imm.memflags), + Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), + Operand::new("p", iAddr), + ]) + .can_store() + .other_side_effects(), + ); + + ig.push( + Inst::new( + "fence", + r#" + A memory fence. This must provide ordering to ensure that, at a minimum, neither loads + nor stores of any kind may move forwards or backwards across the fence. This operation + is sequentially consistent. + "#, + &formats.nullary, + ) + .other_side_effects(), + ); + + let TxN = &TypeVar::new( + "TxN", + "A dynamic vector type", + TypeSetBuilder::new() + .ints(Interval::All) + .floats(Interval::All) + .dynamic_simd_lanes(Interval::All) + .build(), + ); + + ig.push( + Inst::new( + "extract_vector", + r#" + Return a fixed length sub vector, extracted from a dynamic vector. + "#, + &formats.binary_imm8, + ) + .operands_in(vec![ + Operand::new("x", TxN).with_doc("The dynamic vector to extract from"), + Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"), + ]) + .operands_out(vec![ + Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector") + ]), + ); +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/mod.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/mod.rs new file mode 100644 index 00000000000000..77b248ec55f9e1 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/mod.rs @@ -0,0 +1,87 @@ +//! Shared definitions for the Cranelift intermediate language. + +pub mod entities; +pub mod formats; +pub mod immediates; +pub mod instructions; +pub mod settings; +pub mod types; + +use crate::cdsl::formats::{FormatStructure, InstructionFormat}; +use crate::cdsl::instructions::AllInstructions; +use crate::cdsl::settings::SettingGroup; + +use crate::shared::entities::EntityRefs; +use crate::shared::formats::Formats; +use crate::shared::immediates::Immediates; + +use std::collections::HashMap; +use std::rc::Rc; + +pub(crate) struct Definitions { + pub settings: SettingGroup, + pub all_instructions: AllInstructions, + pub all_formats: Vec>, +} + +pub(crate) fn define() -> Definitions { + let mut all_instructions = AllInstructions::new(); + + let immediates = Immediates::new(); + let entities = EntityRefs::new(); + let formats = Formats::new(&immediates, &entities); + instructions::define(&mut all_instructions, &formats, &immediates, &entities); + let all_formats = verify_instruction_formats(&all_instructions); + + Definitions { + settings: settings::define(), + all_instructions, + all_formats, + } +} + +/// Verifies certain properties of formats. +/// +/// - Formats must be uniquely named: if two formats have the same name, they must refer to the +/// same data. Otherwise, two format variants in the codegen crate would have the same name. +/// - Formats must be structurally different from each other. Otherwise, this would lead to +/// code duplicate in the codegen crate. +/// +/// Returns a list of all the instruction formats effectively used. +fn verify_instruction_formats(all_instructions: &AllInstructions) -> Vec> { + let mut format_names: HashMap<&'static str, &Rc> = HashMap::new(); + + // A structure is: number of input value operands / whether there's varargs or not / names + // of immediate fields. + let mut format_structures: HashMap> = HashMap::new(); + + for inst in all_instructions { + // Check name. + if let Some(existing_format) = format_names.get(&inst.format.name) { + assert!( + Rc::ptr_eq(existing_format, &inst.format), + "formats must uniquely named; there's a\ + conflict on the name '{}', please make sure it is used only once.", + existing_format.name + ); + } else { + format_names.insert(inst.format.name, &inst.format); + } + + // Check structure. + let key = inst.format.structure(); + if let Some(existing_format) = format_structures.get(&key) { + assert_eq!( + existing_format.name, inst.format.name, + "duplicate instruction formats {} and {}; please remove one.", + existing_format.name, inst.format.name + ); + } else { + format_structures.insert(key, inst.format.clone()); + } + } + + let mut result = Vec::from_iter(format_structures.into_values()); + result.sort_by_key(|format| format.name); + result +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/settings.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/settings.rs new file mode 100644 index 00000000000000..43b5c54c5ec6db --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/settings.rs @@ -0,0 +1,404 @@ +use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; + +pub(crate) fn define() -> SettingGroup { + let mut settings = SettingGroupBuilder::new("shared"); + + settings.add_bool( + "regalloc_checker", + "Enable the symbolic checker for register allocation.", + r#" + This performs a verification that the register allocator preserves + equivalent dataflow with respect to the original (pre-regalloc) + program. This analysis is somewhat expensive. However, if it succeeds, + it provides independent evidence (by a carefully-reviewed, from-first-principles + analysis) that no regalloc bugs were triggered for the particular compilations + performed. This is a valuable assurance to have as regalloc bugs can be + very dangerous and difficult to debug. + "#, + false, + ); + + settings.add_bool( + "regalloc_verbose_logs", + "Enable verbose debug logs for regalloc2.", + r#" + This adds extra logging for regalloc2 output, that is quite valuable to understand + decisions taken by the register allocator as well as debugging it. It is disabled by + default, as it can cause many log calls which can slow down compilation by a large + amount. + "#, + false, + ); + + settings.add_enum( + "regalloc_algorithm", + "Algorithm to use in register allocator.", + r#" + Supported options: + + - `backtracking`: A backtracking allocator with range splitting; more expensive + but generates better code. + - `single_pass`: A single-pass algorithm that yields quick compilation but + results in code with more register spills and moves. + "#, + vec!["backtracking", "single_pass"], + ); + + settings.add_enum( + "opt_level", + "Optimization level for generated code.", + r#" + Supported levels: + + - `none`: Minimise compile time by disabling most optimizations. + - `speed`: Generate the fastest possible code + - `speed_and_size`: like "speed", but also perform transformations aimed at reducing code size. + "#, + vec!["none", "speed", "speed_and_size"], + ); + + settings.add_bool( + "enable_alias_analysis", + "Do redundant-load optimizations with alias analysis.", + r#" + This enables the use of a simple alias analysis to optimize away redundant loads. + Only effective when `opt_level` is `speed` or `speed_and_size`. + "#, + true, + ); + + settings.add_bool( + "enable_verifier", + "Run the Cranelift IR verifier at strategic times during compilation.", + r#" + This makes compilation slower but catches many bugs. The verifier is always enabled by + default, which is useful during development. + "#, + true, + ); + + settings.add_bool( + "enable_pcc", + "Enable proof-carrying code translation validation.", + r#" + This adds a proof-carrying-code mode. Proof-carrying code (PCC) is a strategy to verify + that the compiler preserves certain properties or invariants in the compiled code. + For example, a frontend that translates WebAssembly to CLIF can embed PCC facts in + the CLIF, and Cranelift will verify that the final machine code satisfies the stated + facts at each intermediate computed value. Loads and stores can be marked as "checked" + and their memory effects can be verified as safe. + "#, + false, + ); + + // Note that Cranelift doesn't currently need an is_pie flag, because PIE is + // just PIC where symbols can't be pre-empted, which can be expressed with the + // `colocated` flag on external functions and global values. + settings.add_bool( + "is_pic", + "Enable Position-Independent Code generation.", + "", + false, + ); + + settings.add_bool( + "use_colocated_libcalls", + "Use colocated libcalls.", + r#" + Generate code that assumes that libcalls can be declared "colocated", + meaning they will be defined along with the current function, such that + they can use more efficient addressing. + "#, + false, + ); + + settings.add_bool( + "enable_float", + "Enable the use of floating-point instructions.", + r#" + Disabling use of floating-point instructions is not yet implemented. + "#, + true, + ); + + settings.add_bool( + "enable_nan_canonicalization", + "Enable NaN canonicalization.", + r#" + This replaces NaNs with a single canonical value, for users requiring + entirely deterministic WebAssembly computation. This is not required + by the WebAssembly spec, so it is not enabled by default. + "#, + false, + ); + + settings.add_bool( + "enable_pinned_reg", + "Enable the use of the pinned register.", + r#" + This register is excluded from register allocation, and is completely under the control of + the end-user. It is possible to read it via the get_pinned_reg instruction, and to set it + with the set_pinned_reg instruction. + "#, + false, + ); + + settings.add_bool( + "enable_atomics", + "Enable the use of atomic instructions", + "", + true, + ); + + settings.add_bool( + "enable_safepoints", + "Enable safepoint instruction insertions.", + r#" + This will allow the emit_stack_maps() function to insert the safepoint + instruction on top of calls and interrupt traps in order to display the + live reference values at that point in the program. + "#, + false, + ); + + settings.add_enum( + "tls_model", + "Defines the model used to perform TLS accesses.", + "", + vec!["none", "elf_gd", "macho", "coff"], + ); + + settings.add_enum( + "stack_switch_model", + "Defines the model used to performing stack switching.", + r#" + This determines the compilation of `stack_switch` instructions. If + set to `basic`, we simply save all registers, update stack pointer + and frame pointer (if needed), and jump to the target IP. + If set to `update_windows_tib`, we *additionally* update information + about the active stack in Windows' Thread Information Block. + "#, + vec!["none", "basic", "update_windows_tib"], + ); + + settings.add_enum( + "libcall_call_conv", + "Defines the calling convention to use for LibCalls call expansion.", + r#" + This may be different from the ISA default calling convention. + + The default value is to use the same calling convention as the ISA + default calling convention. + + This list should be kept in sync with the list of calling + conventions available in isa/call_conv.rs. + "#, + vec![ + "isa_default", + "fast", + "cold", + "system_v", + "windows_fastcall", + "apple_aarch64", + "probestack", + ], + ); + + settings.add_bool( + "enable_llvm_abi_extensions", + "Enable various ABI extensions defined by LLVM's behavior.", + r#" + In some cases, LLVM's implementation of an ABI (calling convention) + goes beyond a standard and supports additional argument types or + behavior. This option instructs Cranelift codegen to follow LLVM's + behavior where applicable. + + Currently, this applies only to Windows Fastcall on x86-64, and + allows an `i128` argument to be spread across two 64-bit integer + registers. The Fastcall implementation otherwise does not support + `i128` arguments, and will panic if they are present and this + option is not set. + "#, + false, + ); + + settings.add_bool( + "enable_multi_ret_implicit_sret", + "Enable support for sret arg introduction when there are too many ret vals.", + r#" + When there are more returns than available return registers, the + return value has to be returned through the introduction of a + return area pointer. Normally this return area pointer has to be + introduced as `ArgumentPurpose::StructReturn` parameter, but for + backward compatibility reasons Cranelift also supports implicitly + introducing this parameter and writing the return values through it. + + **This option currently does not conform to platform ABIs and the + used ABI should not be assumed to remain the same between Cranelift + versions.** + + This option is **deprecated** and will be removed in the future. + + Because of the above issues, and complexities of native ABI support + for the concept in general, Cranelift's support for multiple return + values may also be removed in the future (#9510). For the most + robust solution, it is recommended to build a convention on top of + Cranelift's primitives for passing multiple return values, for + example by allocating a stackslot in the caller, passing it as an + explicit StructReturn argument, storing return values in the callee, + and loading results in the caller. + "#, + false, + ); + + settings.add_bool( + "unwind_info", + "Generate unwind information.", + r#" + This increases metadata size and compile time, but allows for the + debugger to trace frames, is needed for GC tracing that relies on + libunwind (such as in Wasmtime), and is unconditionally needed on + certain platforms (such as Windows) that must always be able to unwind. + "#, + true, + ); + + settings.add_bool( + "preserve_frame_pointers", + "Preserve frame pointers", + r#" + Preserving frame pointers -- even inside leaf functions -- makes it + easy to capture the stack of a running program, without requiring any + side tables or metadata (like `.eh_frame` sections). Many sampling + profilers and similar tools walk frame pointers to capture stacks. + Enabling this option will play nice with those tools. + "#, + false, + ); + + settings.add_bool( + "machine_code_cfg_info", + "Generate CFG metadata for machine code.", + r#" + This increases metadata size and compile time, but allows for the + embedder to more easily post-process or analyze the generated + machine code. It provides code offsets for the start of each + basic block in the generated machine code, and a list of CFG + edges (with blocks identified by start offsets) between them. + This is useful for, e.g., machine-code analyses that verify certain + properties of the generated code. + "#, + false, + ); + + // Stack probing options. + + settings.add_bool( + "enable_probestack", + "Enable the use of stack probes for supported calling conventions.", + "", + false, + ); + + settings.add_num( + "probestack_size_log2", + "The log2 of the size of the stack guard region.", + r#" + Stack frames larger than this size will have stack overflow checked + by calling the probestack function. + + The default is 12, which translates to a size of 4096. + "#, + 12, + ); + + settings.add_enum( + "probestack_strategy", + "Controls what kinds of stack probes are emitted.", + r#" + Supported strategies: + + - `outline`: Always emits stack probes as calls to a probe stack function. + - `inline`: Always emits inline stack probes. + "#, + vec!["outline", "inline"], + ); + + // Jump table options. + + settings.add_bool( + "enable_jump_tables", + "Enable the use of jump tables in generated machine code.", + "", + true, + ); + + // Spectre options. + + settings.add_bool( + "enable_heap_access_spectre_mitigation", + "Enable Spectre mitigation on heap bounds checks.", + r#" + This is a no-op for any heap that needs no bounds checks; e.g., + if the limit is static and the guard region is large enough that + the index cannot reach past it. + + This option is enabled by default because it is highly + recommended for secure sandboxing. The embedder should consider + the security implications carefully before disabling this option. + "#, + true, + ); + + settings.add_bool( + "enable_table_access_spectre_mitigation", + "Enable Spectre mitigation on table bounds checks.", + r#" + This option uses a conditional move to ensure that when a table + access index is bounds-checked and a conditional branch is used + for the out-of-bounds case, a misspeculation of that conditional + branch (falsely predicted in-bounds) will select an in-bounds + index to load on the speculative path. + + This option is enabled by default because it is highly + recommended for secure sandboxing. The embedder should consider + the security implications carefully before disabling this option. + "#, + true, + ); + + settings.add_bool( + "enable_incremental_compilation_cache_checks", + "Enable additional checks for debugging the incremental compilation cache.", + r#" + Enables additional checks that are useful during development of the incremental + compilation cache. This should be mostly useful for Cranelift hackers, as well as for + helping to debug false incremental cache positives for embedders. + + This option is disabled by default and requires enabling the "incremental-cache" Cargo + feature in cranelift-codegen. + "#, + false, + ); + + settings.add_num( + "bb_padding_log2_minus_one", + "The log2 of the size to insert dummy padding between basic blocks", + r#" + This is a debugging option for stressing various cases during code + generation without requiring large functions. This will insert + 0-byte padding between basic blocks of the specified size. + + The amount of padding inserted two raised to the power of this value + minus one. If this value is 0 then no padding is inserted. + + The default for this option is 0 to insert no padding as it's only + intended for testing and development. + "#, + 0, + ); + + // When adding new settings please check if they can also be added + // in cranelift/fuzzgen/src/lib.rs for fuzzing. + settings.build() +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/shared/types.rs b/deps/crates/vendor/cranelift-codegen-meta/src/shared/types.rs new file mode 100644 index 00000000000000..d09abe179ddec5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/shared/types.rs @@ -0,0 +1,103 @@ +//! This module predefines all the Cranelift scalar types. + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub(crate) enum Int { + /// 8-bit int. + I8 = 8, + /// 16-bit int. + I16 = 16, + /// 32-bit int. + I32 = 32, + /// 64-bit int. + I64 = 64, + /// 128-bit int. + I128 = 128, +} + +/// This provides an iterator through all of the supported int variants. +pub(crate) struct IntIterator { + index: u8, +} + +impl IntIterator { + pub fn new() -> Self { + Self { index: 0 } + } +} + +impl Iterator for IntIterator { + type Item = Int; + fn next(&mut self) -> Option { + let res = match self.index { + 0 => Some(Int::I8), + 1 => Some(Int::I16), + 2 => Some(Int::I32), + 3 => Some(Int::I64), + 4 => Some(Int::I128), + _ => return None, + }; + self.index += 1; + res + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub(crate) enum Float { + F16 = 16, + F32 = 32, + F64 = 64, + F128 = 128, +} + +/// Iterator through the variants of the Float enum. +pub(crate) struct FloatIterator { + index: u8, +} + +impl FloatIterator { + pub fn new() -> Self { + Self { index: 0 } + } +} + +/// This provides an iterator through all of the supported float variants. +impl Iterator for FloatIterator { + type Item = Float; + fn next(&mut self) -> Option { + let res = match self.index { + 0 => Some(Float::F16), + 1 => Some(Float::F32), + 2 => Some(Float::F64), + 3 => Some(Float::F128), + _ => return None, + }; + self.index += 1; + res + } +} + +#[cfg(test)] +mod iter_tests { + use super::*; + + #[test] + fn int_iter_works() { + let mut int_iter = IntIterator::new(); + assert_eq!(int_iter.next(), Some(Int::I8)); + assert_eq!(int_iter.next(), Some(Int::I16)); + assert_eq!(int_iter.next(), Some(Int::I32)); + assert_eq!(int_iter.next(), Some(Int::I64)); + assert_eq!(int_iter.next(), Some(Int::I128)); + assert_eq!(int_iter.next(), None); + } + + #[test] + fn float_iter_works() { + let mut float_iter = FloatIterator::new(); + assert_eq!(float_iter.next(), Some(Float::F16)); + assert_eq!(float_iter.next(), Some(Float::F32)); + assert_eq!(float_iter.next(), Some(Float::F64)); + assert_eq!(float_iter.next(), Some(Float::F128)); + assert_eq!(float_iter.next(), None); + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/srcgen.rs b/deps/crates/vendor/cranelift-codegen-meta/src/srcgen.rs new file mode 100644 index 00000000000000..d3c321e5bc5177 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/srcgen.rs @@ -0,0 +1,464 @@ +//! Source code generator. +//! +//! The `srcgen` module contains generic helper routines and classes for +//! generating source code. + +#![macro_use] + +use std::cmp; +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; +use std::io::Write; + +use crate::error; + +static SHIFTWIDTH: usize = 4; + +/// A macro that simplifies the usage of the Formatter by allowing format +/// strings. +macro_rules! fmtln { + ($fmt:ident, $fmtstring:expr, $($fmtargs:expr),*) => { + $fmt.line(format!($fmtstring, $($fmtargs),*)) + }; + + ($fmt:ident, $arg:expr) => { + $fmt.line($arg) + }; + + ($_:tt, $($args:expr),+) => { + compile_error!("This macro requires at least two arguments: the Formatter instance and a format string.") + }; + + ($_:tt) => { + compile_error!("This macro requires at least two arguments: the Formatter instance and a format string.") + }; +} + +pub(crate) struct Formatter { + indent: usize, + lines: Vec, +} + +impl Formatter { + /// Source code formatter class. Used to collect source code to be written + /// to a file, and keep track of indentation. + pub fn new() -> Self { + Self { + indent: 0, + lines: Vec::new(), + } + } + + /// Increase current indentation level by one. + pub fn indent_push(&mut self) { + self.indent += 1; + } + + /// Decrease indentation by one level. + pub fn indent_pop(&mut self) { + assert!(self.indent > 0, "Already at top level indentation"); + self.indent -= 1; + } + + pub fn indent T>(&mut self, f: F) -> T { + self.indent_push(); + let ret = f(self); + self.indent_pop(); + ret + } + + /// Get the current whitespace indentation in the form of a String. + fn get_indent(&self) -> String { + if self.indent == 0 { + String::new() + } else { + format!("{:-1$}", " ", self.indent * SHIFTWIDTH) + } + } + + /// Add an indented line. + pub fn line(&mut self, contents: impl AsRef) { + let indented_line = format!("{}{}\n", self.get_indent(), contents.as_ref()); + self.lines.push(indented_line); + } + + /// Pushes an empty line. + pub fn empty_line(&mut self) { + self.lines.push("\n".to_string()); + } + + /// Write `self.lines` to a file. + pub fn update_file( + &self, + filename: impl AsRef, + directory: &std::path::Path, + ) -> Result<(), error::Error> { + let path = directory.join(&filename); + eprintln!("Writing generated file: {}", path.display()); + let mut f = fs::File::create(path)?; + + for l in self.lines.iter().map(|l| l.as_bytes()) { + f.write_all(l)?; + } + + Ok(()) + } + + /// Add one or more lines after stripping common indentation. + pub fn multi_line(&mut self, s: &str) { + parse_multiline(s).into_iter().for_each(|l| self.line(&l)); + } + + /// Add a comment line. + pub fn comment(&mut self, s: impl AsRef) { + fmtln!(self, "// {}", s.as_ref()); + } + + /// Add a (multi-line) documentation comment. + pub fn doc_comment(&mut self, contents: impl AsRef) { + parse_multiline(contents.as_ref()) + .iter() + .map(|l| { + if l.is_empty() { + "///".into() + } else { + format!("/// {l}") + } + }) + .for_each(|s| self.line(s.as_str())); + } + + /// Add a match expression. + pub fn add_match(&mut self, m: Match) { + fmtln!(self, "match {} {{", m.expr); + self.indent(|fmt| { + for (&(ref fields, ref body), ref names) in m.arms.iter() { + // name { fields } | name { fields } => { body } + let conditions = names + .iter() + .map(|name| { + if !fields.is_empty() { + format!("{} {{ {} }}", name, fields.join(", ")) + } else { + name.clone() + } + }) + .collect::>() + .join(" |\n") + + " => {"; + + fmt.multi_line(&conditions); + fmt.indent(|fmt| { + fmt.line(body); + }); + fmt.line("}"); + } + + // Make sure to include the catch all clause last. + if let Some(body) = m.catch_all { + fmt.line("_ => {"); + fmt.indent(|fmt| { + fmt.line(body); + }); + fmt.line("}"); + } + }); + self.line("}"); + } +} + +/// Compute the indentation of s, or None of an empty line. +fn _indent(s: &str) -> Option { + if s.is_empty() { + None + } else { + let t = s.trim_start(); + Some(s.len() - t.len()) + } +} + +/// Given a multi-line string, split it into a sequence of lines after +/// stripping a common indentation. This is useful for strings defined with +/// doc strings. +fn parse_multiline(s: &str) -> Vec { + // Convert tabs into spaces. + let expanded_tab = format!("{:-1$}", " ", SHIFTWIDTH); + let lines: Vec = s.lines().map(|l| l.replace('\t', &expanded_tab)).collect(); + + // Determine minimum indentation, ignoring the first line and empty lines. + let indent = lines + .iter() + .skip(1) + .filter(|l| !l.trim().is_empty()) + .map(|l| l.len() - l.trim_start().len()) + .min(); + + // Strip off leading blank lines. + let mut lines_iter = lines.iter().skip_while(|l| l.is_empty()); + let mut trimmed = Vec::with_capacity(lines.len()); + + // Remove indentation (first line is special) + if let Some(s) = lines_iter.next().map(|l| l.trim()).map(|l| l.to_string()) { + trimmed.push(s); + } + + // Remove trailing whitespace from other lines. + let mut other_lines = if let Some(indent) = indent { + // Note that empty lines may have fewer than `indent` chars. + lines_iter + .map(|l| &l[cmp::min(indent, l.len())..]) + .map(|l| l.trim_end()) + .map(|l| l.to_string()) + .collect::>() + } else { + lines_iter + .map(|l| l.trim_end()) + .map(|l| l.to_string()) + .collect::>() + }; + + trimmed.append(&mut other_lines); + + // Strip off trailing blank lines. + while let Some(s) = trimmed.pop() { + if s.is_empty() { + continue; + } else { + trimmed.push(s); + break; + } + } + + trimmed +} + +/// Match formatting class. +/// +/// Match objects collect all the information needed to emit a Rust `match` +/// expression, automatically deduplicating overlapping identical arms. +/// +/// Note that this class is ignorant of Rust types, and considers two fields +/// with the same name to be equivalent. BTreeMap/BTreeSet are used to +/// represent the arms in order to make the order deterministic. +pub(crate) struct Match { + expr: String, + arms: BTreeMap<(Vec, String), BTreeSet>, + /// The clause for the placeholder pattern _. + catch_all: Option, +} + +impl Match { + /// Create a new match statement on `expr`. + pub fn new(expr: impl Into) -> Self { + Self { + expr: expr.into(), + arms: BTreeMap::new(), + catch_all: None, + } + } + + fn set_catch_all(&mut self, clause: String) { + assert!(self.catch_all.is_none()); + self.catch_all = Some(clause); + } + + /// Add an arm that reads fields to the Match statement. + pub fn arm, S: Into>(&mut self, name: T, fields: Vec, body: T) { + let name = name.into(); + assert!( + name != "_", + "catch all clause can't extract fields, use arm_no_fields instead." + ); + + let body = body.into(); + let fields = fields.into_iter().map(|x| x.into()).collect(); + let match_arm = self + .arms + .entry((fields, body)) + .or_insert_with(BTreeSet::new); + match_arm.insert(name); + } + + /// Adds an arm that doesn't read anythings from the fields to the Match statement. + pub fn arm_no_fields(&mut self, name: impl Into, body: impl Into) { + let body = body.into(); + + let name = name.into(); + if name == "_" { + self.set_catch_all(body); + return; + } + + let match_arm = self + .arms + .entry((Vec::new(), body)) + .or_insert_with(BTreeSet::new); + match_arm.insert(name); + } +} + +#[cfg(test)] +mod srcgen_tests { + use super::parse_multiline; + use super::Formatter; + use super::Match; + + fn from_raw_string>(s: S) -> Vec { + s.into() + .trim() + .split("\n") + .into_iter() + .map(|x| format!("{x}\n")) + .collect() + } + + #[test] + fn adding_arms_works() { + let mut m = Match::new("x"); + m.arm("Orange", vec!["a", "b"], "some body"); + m.arm("Yellow", vec!["a", "b"], "some body"); + m.arm("Green", vec!["a", "b"], "different body"); + m.arm("Blue", vec!["x", "y"], "some body"); + assert_eq!(m.arms.len(), 3); + + let mut fmt = Formatter::new(); + fmt.add_match(m); + + let expected_lines = from_raw_string( + r#" +match x { + Green { a, b } => { + different body + } + Orange { a, b } | + Yellow { a, b } => { + some body + } + Blue { x, y } => { + some body + } +} + "#, + ); + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn match_with_catchall_order() { + // The catchall placeholder must be placed after other clauses. + let mut m = Match::new("x"); + m.arm("Orange", vec!["a", "b"], "some body"); + m.arm("Green", vec!["a", "b"], "different body"); + m.arm_no_fields("_", "unreachable!()"); + assert_eq!(m.arms.len(), 2); // catchall is not counted + + let mut fmt = Formatter::new(); + fmt.add_match(m); + + let expected_lines = from_raw_string( + r#" +match x { + Green { a, b } => { + different body + } + Orange { a, b } => { + some body + } + _ => { + unreachable!() + } +} + "#, + ); + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn parse_multiline_works() { + let input = "\n hello\n world\n"; + let expected = vec!["hello", "world"]; + let output = parse_multiline(input); + assert_eq!(output, expected); + } + + #[test] + fn formatter_basic_example_works() { + let mut fmt = Formatter::new(); + fmt.line("Hello line 1"); + fmt.indent_push(); + fmt.comment("Nested comment"); + fmt.indent_pop(); + fmt.line("Back home again"); + let expected_lines = vec![ + "Hello line 1\n", + " // Nested comment\n", + "Back home again\n", + ]; + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn get_indent_works() { + let mut fmt = Formatter::new(); + let expected_results = vec!["", " ", " ", ""]; + + let actual_results = Vec::with_capacity(4); + (0..3).for_each(|_| { + fmt.get_indent(); + fmt.indent_push(); + }); + (0..3).for_each(|_| fmt.indent_pop()); + fmt.get_indent(); + + actual_results + .into_iter() + .zip(expected_results.into_iter()) + .for_each(|(actual, expected): (String, &str)| assert_eq!(&actual, expected)); + } + + #[test] + fn fmt_can_add_type_to_lines() { + let mut fmt = Formatter::new(); + fmt.line(format!("pub const {}: Type = Type({:#x});", "example", 0,)); + let expected_lines = vec!["pub const example: Type = Type(0x0);\n"]; + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn fmt_can_add_indented_line() { + let mut fmt = Formatter::new(); + fmt.line("hello"); + fmt.indent_push(); + fmt.line("world"); + let expected_lines = vec!["hello\n", " world\n"]; + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn fmt_can_add_doc_comments() { + let mut fmt = Formatter::new(); + fmt.doc_comment("documentation\nis\ngood"); + let expected_lines = vec!["/// documentation\n", "/// is\n", "/// good\n"]; + assert_eq!(fmt.lines, expected_lines); + } + + #[test] + fn fmt_can_add_doc_comments_with_empty_lines() { + let mut fmt = Formatter::new(); + fmt.doc_comment( + r#"documentation + can be really good. + + If you stick to writing it. +"#, + ); + let expected_lines = from_raw_string( + r#" +/// documentation +/// can be really good. +/// +/// If you stick to writing it."#, + ); + assert_eq!(fmt.lines, expected_lines); + } +} diff --git a/deps/crates/vendor/cranelift-codegen-meta/src/unique_table.rs b/deps/crates/vendor/cranelift-codegen-meta/src/unique_table.rs new file mode 100644 index 00000000000000..50c664e4dfb63b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-meta/src/unique_table.rs @@ -0,0 +1,138 @@ +//! An index-accessed table implementation that avoids duplicate entries. +use std::collections::HashMap; +use std::hash::Hash; +use std::slice; + +/// Collect items into the `table` list, removing duplicates. +pub(crate) struct UniqueTable<'entries, T: Eq + Hash> { + table: Vec<&'entries T>, + map: HashMap<&'entries T, usize>, +} + +impl<'entries, T: Eq + Hash> UniqueTable<'entries, T> { + pub fn new() -> Self { + Self { + table: Vec::new(), + map: HashMap::new(), + } + } + + pub fn add(&mut self, entry: &'entries T) -> usize { + match self.map.get(&entry) { + None => { + let i = self.table.len(); + self.table.push(entry); + self.map.insert(entry, i); + i + } + Some(&i) => i, + } + } + + pub fn len(&self) -> usize { + self.table.len() + } + pub fn iter(&self) -> slice::Iter<&'entries T> { + self.table.iter() + } +} + +/// A table of sequences which tries to avoid common subsequences. +pub(crate) struct UniqueSeqTable { + table: Vec, +} + +impl UniqueSeqTable { + pub fn new() -> Self { + Self { table: Vec::new() } + } + pub fn add(&mut self, values: &[T]) -> usize { + if values.is_empty() { + return 0; + } + if let Some(offset) = find_subsequence(values, &self.table) { + offset + } else { + let table_len = self.table.len(); + + // Try to put in common the last elements of the table if they're a prefix of the new + // sequence. + // + // We know there wasn't a full match, so the best prefix we can hope to find contains + // all the values but the last one. + let mut start_from = usize::min(table_len, values.len() - 1); + while start_from != 0 { + // Loop invariant: start_from <= table_len, so table_len - start_from >= 0. + if values[0..start_from] == self.table[table_len - start_from..table_len] { + break; + } + start_from -= 1; + } + + self.table + .extend(values[start_from..values.len()].iter().cloned()); + table_len - start_from + } + } + pub fn len(&self) -> usize { + self.table.len() + } + pub fn iter(&self) -> slice::Iter { + self.table.iter() + } +} + +/// Try to find the subsequence `sub` in the `whole` sequence. Returns None if +/// it's not been found, or Some(index) if it has been. Naive implementation +/// until proven we need something better. +fn find_subsequence(sub: &[T], whole: &[T]) -> Option { + assert!(!sub.is_empty()); + // We want i + sub.len() <= whole.len(), i.e. i < whole.len() + 1 - sub.len(). + if whole.len() < sub.len() { + return None; + } + let max = whole.len() - sub.len(); + for i in 0..=max { + if whole[i..i + sub.len()] == sub[..] { + return Some(i); + } + } + None +} + +#[test] +fn test_find_subsequence() { + assert_eq!(find_subsequence(&vec![1], &vec![4]), None); + assert_eq!(find_subsequence(&vec![1], &vec![1]), Some(0)); + assert_eq!(find_subsequence(&vec![1, 2], &vec![1]), None); + assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 2]), Some(0)); + assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 3]), None); + assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 2]), Some(1)); + assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1]), None); + assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1, 2]), Some(3)); + assert_eq!( + find_subsequence(&vec![1, 1, 3], &vec![1, 1, 1, 3, 3]), + Some(1) + ); +} + +#[test] +fn test_optimal_add() { + let mut seq_table = UniqueSeqTable::new(); + // [0, 1, 2, 3] + assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0); + assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0); + assert_eq!(seq_table.add(&vec![1, 2, 3]), 1); + assert_eq!(seq_table.add(&vec![2, 3]), 2); + assert_eq!(seq_table.len(), 4); + // [0, 1, 2, 3, 4] + assert_eq!(seq_table.add(&vec![2, 3, 4]), 2); + assert_eq!(seq_table.len(), 5); + // [0, 1, 2, 3, 4, 6, 5, 7] + assert_eq!(seq_table.add(&vec![4, 6, 5, 7]), 4); + assert_eq!(seq_table.len(), 8); + // [0, 1, 2, 3, 4, 6, 5, 7, 8, 2, 3, 4] + assert_eq!(seq_table.add(&vec![8, 2, 3, 4]), 8); + assert_eq!(seq_table.add(&vec![8]), 8); + assert_eq!(seq_table.len(), 12); +} diff --git a/deps/crates/vendor/cranelift-codegen-shared/.cargo-checksum.json b/deps/crates/vendor/cranelift-codegen-shared/.cargo-checksum.json new file mode 100644 index 00000000000000..a77aef55371921 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"79a706004b88aff1389b447f300cf3ce2a966faf0c5c39bb684d4007e33f27e6","Cargo.lock":"2e70446b06407b58dcaf779ffade0f703e982cd5a9a904fac55f955f0bb330b6","Cargo.toml":"a2dc775b00c71091b2737ebe2ee63bb708253b0be0bbac8264e2f1158cbb2305","Cargo.toml.orig":"615bf9d1ea275a6acffe603a10b3852e6c280cd0763b8abea408246bd8e1061d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/constant_hash.rs":"4dc1a4e6f31a2f25d41fc7ee4ed2ae94563a090cdc77d7bbd972aa4098bd4f01","src/constants.rs":"930ecd722ef9cef5e3a807bcab310034b1b6d17e6153e5c69a53858865b11c51","src/lib.rs":"317c5fad6b13ad2ef5b4fe5ac45a45e776dda246f293fe9f7f1248096ddfaedd"},"package":"40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen-shared/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-codegen-shared/.cargo_vcs_info.json new file mode 100644 index 00000000000000..36a9df30dfe7fd --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/codegen/shared" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen-shared/Cargo.lock b/deps/crates/vendor/cranelift-codegen-shared/Cargo.lock new file mode 100644 index 00000000000000..788361d2b565b8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" diff --git a/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml b/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml new file mode 100644 index 00000000000000..3c3e708f17a782 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-codegen-shared" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "For code shared between cranelift-codegen-meta and cranelift-codegen" +readme = "README.md" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_codegen_shared" +path = "src/lib.rs" + +[dependencies] diff --git a/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml.orig b/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml.orig new file mode 100644 index 00000000000000..921d2397e8fd38 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/Cargo.toml.orig @@ -0,0 +1,14 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-codegen-shared" +version = "0.116.1" +description = "For code shared between cranelift-codegen-meta and cranelift-codegen" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +edition.workspace = true +rust-version.workspace = true + +[dependencies] +# Since this is a shared dependency of several packages, please strive to keep this dependency-free +# when no features are enabled. diff --git a/deps/crates/vendor/cranelift-codegen-shared/LICENSE b/deps/crates/vendor/cranelift-codegen-shared/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-codegen-shared/README.md b/deps/crates/vendor/cranelift-codegen-shared/README.md new file mode 100644 index 00000000000000..54f9f5d6d29d61 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/README.md @@ -0,0 +1,2 @@ +This crate contains shared definitions for use in both `cranelift-codegen-meta` and `cranelift +-codegen`. diff --git a/deps/crates/vendor/cranelift-codegen-shared/src/constant_hash.rs b/deps/crates/vendor/cranelift-codegen-shared/src/constant_hash.rs new file mode 100644 index 00000000000000..2929319656ba3d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/src/constant_hash.rs @@ -0,0 +1,21 @@ +//! This module provides a primitive hash function. + +/// A primitive hash function for matching opcodes. +pub fn simple_hash(s: &str) -> usize { + let mut h: u32 = 5381; + for c in s.chars() { + h = (h ^ c as u32).wrapping_add(h.rotate_right(6)); + } + h as usize +} + +#[cfg(test)] +mod tests { + use super::simple_hash; + + #[test] + fn basic() { + assert_eq!(simple_hash("Hello"), 0x2fa70c01); + assert_eq!(simple_hash("world"), 0x5b0c31d5); + } +} diff --git a/deps/crates/vendor/cranelift-codegen-shared/src/constants.rs b/deps/crates/vendor/cranelift-codegen-shared/src/constants.rs new file mode 100644 index 00000000000000..4fa5897dca96ee --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/src/constants.rs @@ -0,0 +1,28 @@ +//! This module contains constants that are shared between the codegen and the meta crate, so they +//! are kept in sync. + +// Numbering scheme for value types: +// +// 0: Void +// 0x01-0x6f: Special types +// 0x70-0x7d: Lane types +// 0x7e-0x7f: Reference types +// 0x80-0xff: Vector types +// 0x100-0x17f: Dynamic Vector types +// +// Vector types are encoded with the lane type in the low 4 bits and log2(lanes) +// in the next highest 4 bits, giving a range of 2-256 lanes. + +// Dynamic vector types are encoded similarly. + +/// Start of the lane types. +pub const LANE_BASE: u16 = 0x70; + +/// Base for reference types. +pub const REFERENCE_BASE: u16 = 0x7E; + +/// Start of the 2-lane vector types. +pub const VECTOR_BASE: u16 = 0x80; + +/// Start of the dynamic vector types. +pub const DYNAMIC_VECTOR_BASE: u16 = 0x100; diff --git a/deps/crates/vendor/cranelift-codegen-shared/src/lib.rs b/deps/crates/vendor/cranelift-codegen-shared/src/lib.rs new file mode 100644 index 00000000000000..2a03a8323439eb --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen-shared/src/lib.rs @@ -0,0 +1,10 @@ +//! This library contains code that is common to both the `cranelift-codegen` and +//! `cranelift-codegen-meta` libraries. + +#![deny(missing_docs)] + +pub mod constant_hash; +pub mod constants; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/deps/crates/vendor/cranelift-codegen/.cargo-checksum.json b/deps/crates/vendor/cranelift-codegen/.cargo-checksum.json new file mode 100644 index 00000000000000..04aaeeb42d781a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"e66f5f111fdc6762c78b37c67a7f5a777c9ef19422c2880d0190ec2db6f301ba","Cargo.lock":"e1fee98e07fc5a4a4fc1fc8bbe3392e42588ceae30657cb206510426915eded9","Cargo.toml":"92db82524721309a0d3330b5c21aea0e565f75275519091b9170ab486d667510","Cargo.toml.orig":"bcafe8a328760dda5bf664225c018e7ef591ee55859d1a359bb5b14d8480ea11","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","benches/x64-evex-encoding.rs":"d44fe0567d4a2b8a9dd2e1daf0994601918f4853dcd073c8c99c15e40d6297c9","build.rs":"ea0735d325e25dda38c2fec051e56e48a45397a564c7bbb47751dcf101d03d2d","src/alias_analysis.rs":"3f46da1f44e31e8e06e2b963ed36efb5bad422d51ce312a130ba2dfa9dad9338","src/binemit/mod.rs":"3ce81efcdc2952db9ff58d8711bb49abfb2daa3789906ad796acae7693f1ef2c","src/cfg_printer.rs":"7aeee3150cf32695ef3ff658142e08921ee90bd8bf526c9cabd28dc7acd318d0","src/constant_hash.rs":"8f53afb38891fbdab8553c7a89e61f0ce30947a22fb24ae84523c9a1ab025c3f","src/context.rs":"bb41ecd2af1890ccfe2223267ef5084e5cc73a8eb0d33771bfa6c98b2255d08e","src/ctxhash.rs":"2ce7282cd3f7a99effa7090a9d5937e6699cc2901b59c32aa6a1ca644ee14c27","src/cursor.rs":"babf745cbf4785cd310c2848661315f5de2ee1da24220145c7839b637a57094f","src/data_value.rs":"a921966558d95baf975f12004667526949b0b9503937a2d13c9646a89ff7cf23","src/dbg.rs":"333ebc4fd0ac5ade2b129eef44a64a9c554718431dc78f22c9e11ffbd8eea342","src/dominator_tree.rs":"5e46df574071ed3778d356e7f6777fbaea5738e1e24efeaea3d7fe5e58902589","src/egraph.rs":"3072479d9536dd031d39aa44377c8e4d040bb3681f78347070bc7592cb8f9e21","src/egraph/cost.rs":"19ad392d4f7a93dd8d2763a8c78c0c696939377185096e62029d164bf34a4e46","src/egraph/elaborate.rs":"dfce1b2bc4aadc4c8de108c539796319c79e3e21877f223e4c4283d6947d70b4","src/flowgraph.rs":"779c1710dc6055cc311471c1955bd975ea08b16bbfb73d46e2880e0655a20e02","src/incremental_cache.rs":"79fa916cc8841912e22b95fdb38cb4d8dd4670898812d8a79a8fc699b3149f34","src/inst_predicates.rs":"cc2799beafa460397cb3c03b3e80263a317d5adfba0d658e0cfb4a043b4d9887","src/inst_specs.isle":"b986c37cf353cf0c544fe21df8246b48ee84ad10d030d97cd8d2ad1d5832b241","src/ir/atomic_rmw_op.rs":"f4bb1aba71533f50a27e0da76e22d06bf02e0a6af5bf77401576b5598b7d2725","src/ir/builder.rs":"5c29c6bce5e202fb1c0f465781cb1abf7d9f97ee8c4cfa5e98bb0b2888393d8a","src/ir/condcodes.rs":"a03c9c208bb42e91c8f913c1ca556a7aeed17f1f99d40d68776c7680aa3af440","src/ir/constant.rs":"6dd36b8e2e2738c88bb5295677473eccd03cdc23bf8134641104ccee4028042c","src/ir/dfg.rs":"9b13f4e9741bdfbb3f45e45192eb4d8a8443f1c1ae950f20ce15024f00a8ac41","src/ir/dynamic_type.rs":"d9414af46a4f8bf598786948d33f53bd87b0cf0c01185a2774302c2fd2bb5376","src/ir/entities.rs":"02d15550bc6b045beefbca4ba8c374924a23f4754a6e44a707788b8b1c9ced2f","src/ir/extfunc.rs":"2e6b3fe09c137853a7df64ee5d7d6e7d2a9fb55ff0e3d06955e4c8c797c22793","src/ir/extname.rs":"cc07a1baf6dd4c584b25b329e5213e9805a7e8529e07caa4b326dee0a97e845a","src/ir/function.rs":"f426a19e7d5a023cba6ffab935d47261f2e9977aa0c34d776811f63559dc2b2d","src/ir/globalvalue.rs":"5b8827bda454a61bbdb891914fefb9e0a430d7fa91585a9920492561e9a66391","src/ir/immediates.rs":"b837a63069ccf2b2429ac2d8f42026b819b1fdd3dd2c50fc310e5c48ec1ecc82","src/ir/instructions.rs":"f6950e7f6a8b7361089a1b7e8cf3dc10bda92088df3b678358afb658cca4aac1","src/ir/jumptable.rs":"80a27e75d620215482664a44d622c99ffd555af689e5886534421abf157caf46","src/ir/known_symbol.rs":"daad9ff92b224fae0ab3553e7366675830556b146933fec6946c697d635bf48a","src/ir/layout.rs":"39171d349225d413c00965ad3104052bb0204583e7fbefe79c9e06ec9c632451","src/ir/libcall.rs":"7e3a55e8cf7401630f9818ea3dfa845f1af1c3e8f1d8dcb587f5df15fb996b4c","src/ir/memflags.rs":"33007bfe5c9c7309601eebd619553bf005fab4f37976586fb34ad99c23e0af0b","src/ir/memtype.rs":"44153dd83b66caf2a9bfca9d1fc60719aa50685f318c997859293691d6697b5e","src/ir/mod.rs":"18beb1b78ea05588fc9af12324437bfa46c93511b7d1fc52eeb4af3ab25b10ad","src/ir/pcc.rs":"3c805442b8a7f56ffe125c43ee423eb539925c0b808748e03d88c4bb824944e3","src/ir/progpoint.rs":"4c03b2fbebcb8d5af8ff8effd353b9ca66fb5551eaf2434376617390c66047a8","src/ir/sourceloc.rs":"a4f2d0e51c50d9caab15f493999cb12916d525600de638b43e6f0b785b856404","src/ir/stackslot.rs":"4255305e0521a6afb73f6189ce0e0c971df745d6a9e411172bb9b5a5fc29e0b9","src/ir/trapcode.rs":"fe5a0b09e35a87308acc57b3de03d61e5607061e9734862799e95437907fdb3a","src/ir/types.rs":"b5e3bc6e1be08d33ccdb348bc0144f77db07b1db6a8d331341e0a8714cbf4953","src/ir/user_stack_maps.rs":"f8eae1999d149d07cdea97e4a538e43b75a5cd68786dbc3ec453c9b41feb1a3e","src/isa/aarch64/abi.rs":"b28efd7116d446cc1ddc48b0e131e77fa1afcf28295be39345a18d73ea59c77d","src/isa/aarch64/inst.isle":"ac891c58c4bba08d1d275ccd6455ff43d9b4e9266348bc1bd58b42f64b30edf5","src/isa/aarch64/inst/args.rs":"77f263c71b32c25874ae8487dcb6b1dd5ce64dd857876e424c7353db44cd57e0","src/isa/aarch64/inst/emit.rs":"770bff96c91e8382258894286e05fa02ab73cce4a989f792073ceaee68feb4ae","src/isa/aarch64/inst/emit_tests.rs":"1c1611d184866f84f8707caf993d7058a9d92fcaa4264d5d48e7ee9eeafdd7b7","src/isa/aarch64/inst/imms.rs":"6cf991147f681433921718f9c9f6b70fe940678300235e8230923204be27c1db","src/isa/aarch64/inst/mod.rs":"39868a4c60ef946d797026ef55332b501b2d1b1b8e0794a3ab591c340d50f9b4","src/isa/aarch64/inst/regs.rs":"b059ce795a6f59740f74dd061dc8dc1a9a0d0c9e703c8e901c6b432161bec69b","src/isa/aarch64/inst/unwind.rs":"0d06a94e614794057f224554060c8d6e0da0a01e021b92c33a1dbb3854b414f6","src/isa/aarch64/inst/unwind/systemv.rs":"77edc0d8964a54b4eaa6413c84dfa5f1d748c58c089adf6810b89aa13a7a6d76","src/isa/aarch64/inst_neon.isle":"7c41eccc1808a0daecb5d1406a1ec3292904341cfacc4dd40bb1da7e3d932159","src/isa/aarch64/lower.isle":"53db4a131f7c13d59a2653bd62d82e073974cb08f677e372d5a1256d686daf55","src/isa/aarch64/lower.rs":"093ff5c1b1a44575a93d3d2fea45b5cfbb0d2e388805517d0ed9c9675201a5f0","src/isa/aarch64/lower/isle.rs":"b3515e01b863e324bf226cd07dd4bf0d8a6626535784dc43e370fb7adbdb5434","src/isa/aarch64/lower/isle/generated_code.rs":"14eb64ead3efe928bea2d25438afe938f234b8202f912e11800a8c5687e3335d","src/isa/aarch64/lower_dynamic_neon.isle":"3e112cb6c3b3a3ce014b9556ca1742172dad063c0c883b3dbeda2b3cbdaf88bd","src/isa/aarch64/mod.rs":"8a8eabd2fd5054217af7bfb7be01dde1853e7c9328797599f7f1e9c529d2a127","src/isa/aarch64/pcc.rs":"734a6ef1d32c9b9816fbe9aa7607f20d4a143f57f899cd38622fbd2c0d68ba34","src/isa/aarch64/settings.rs":"e0a1decd458bb18bb49051058c76f226786effb2ac28df1eb77a4f51baf8a491","src/isa/call_conv.rs":"a9b949c9077c05d525f40a5646b5d30eeb34241dfc831ad12872050b7c74b2fd","src/isa/mod.rs":"188080feec61a7d92789782b2d14ea79440f2091b4f30fe450d9fd94b09c32c7","src/isa/pulley32.rs":"2f3c4118f59478ab67ce0ada7466d61cb6abbc6335056b4b9749b642210d4ca0","src/isa/pulley64.rs":"add7db7131a8078bee82171487d9136f94b7c6493992d03e86edac16a98f9a3c","src/isa/pulley_shared/abi.rs":"1a545128ee2004a6775795c55aaefdf4dd3df1e4b981f7cda9b716c9beb311ec","src/isa/pulley_shared/inst.isle":"3a150ad0b35e610b04418fc8ce4fb25a505050d4d36e603fdc838b8fe5a37206","src/isa/pulley_shared/inst/args.rs":"8465bbe54da864fb3e80a554654a621c825303a9f0072524d276aa9ddf6c520d","src/isa/pulley_shared/inst/emit.rs":"ac7192b01da7d882e308602ce61ec08aec00b6fa8871fbe52eab5871c0342a7d","src/isa/pulley_shared/inst/mod.rs":"d69f0719b1232653044075c096d5bb3b7eb9315e0c2f6231e92ab59bec73e681","src/isa/pulley_shared/inst/regs.rs":"7f2b68b172516056a76632d506dfc4113e889d345fe648caaaa93f304dd64c56","src/isa/pulley_shared/lower.isle":"995d88ae33263ec4e99451c8cf3706b8b0623bf028d391f811d794c4ef2d78eb","src/isa/pulley_shared/lower.rs":"e3965bcf3c351f6be17099b5fb9e9214a611120ed1262ec1fab9dd0174da0bf8","src/isa/pulley_shared/lower/isle.rs":"589068b961e954601c710bc4cb258840277413d8a271bc2e4d45a93b50268f03","src/isa/pulley_shared/lower/isle/generated_code.rs":"42f8a5a915246fcd9824aed029f790d9d1d8a1e1a4f0d0c8a2160d0ab05b5230","src/isa/pulley_shared/mod.rs":"f00e19f006e392263a811b464e30e3a70a477684d8fbd029409623269737388b","src/isa/pulley_shared/settings.rs":"df3bfa05363825fb9ce1809cbf77a450e0fb9f95a464ac2d8eed96d7c070bc93","src/isa/riscv64/abi.rs":"197a2e8f9340a01b3bc1298e596d12be1780e48b4883f7b4d3933e8be1a0a496","src/isa/riscv64/inst.isle":"73c755a94c369c8963d629c77b299a69bacaec8a8e471e443a84f21cf075428b","src/isa/riscv64/inst/args.rs":"bd503d3478a55ebc90737feaab4c2720bdb7a87ea4f86b8fc5bbb6be477459cb","src/isa/riscv64/inst/emit.rs":"faa08557d8b6f7aa65e630d9be733666a18003f3c5a6163de3e562f1bca7617e","src/isa/riscv64/inst/emit_tests.rs":"fb22535c0c28f6f5dfdb087fbbc8ba557df4d6477ba3108e68647b00979c8861","src/isa/riscv64/inst/encode.rs":"b2a633299da54b9afa1b1d6e3f9b27425dc1d378eabf8b457cd1716019de3fba","src/isa/riscv64/inst/imms.rs":"47c4c97f8b799e6e3c69b8d968de290dcc2daa76c6b9aa4e83a785037a79ae45","src/isa/riscv64/inst/mod.rs":"af365d6fb8174a67db47f9723770ddf4ad55db4f4f253d091ca4eef8f49986eb","src/isa/riscv64/inst/regs.rs":"ff1007c76a73ed4d35fe83959bddd82e7ebd086ea6fee30109dbf2e092448b5f","src/isa/riscv64/inst/unwind.rs":"0d06a94e614794057f224554060c8d6e0da0a01e021b92c33a1dbb3854b414f6","src/isa/riscv64/inst/unwind/systemv.rs":"5563b6088f091d2750c3999ae03b7f23d92faffa905e90f06cc9a9e8d18fc4a9","src/isa/riscv64/inst/vector.rs":"c80826d19b42208fc1b705fb6df8dc728b806a073afb8be3017d188f7ed95b3d","src/isa/riscv64/inst_vector.isle":"5ea53b582f58e531192d199e976e0e9c3b34f1eb4497ee50f993a45ebcd0075b","src/isa/riscv64/lower.isle":"c46aca90b8f54a93fc28038bdb445b7eaadf873c59e1540e48bf08c63c35d578","src/isa/riscv64/lower.rs":"544fca9dfc125ed05d6eed4b87f654c7a74533b83049b3a5d8f7cec3a695196d","src/isa/riscv64/lower/isle.rs":"add3a3f37866bec2ea856f179536a46fcfe36a2ad03ba18b3a8a9fb9c7a8fe91","src/isa/riscv64/lower/isle/generated_code.rs":"64b1255e1543a6f27a18409d6cb788f45872a3e8c23f1a1cd8f6bebf3de86b46","src/isa/riscv64/mod.rs":"edc53ebb4b9bef333fa545eb57d808f5ef1f3391fc6314f6085c2a4ba6f34ccd","src/isa/riscv64/settings.rs":"39c26a31ffa46e524859fef756ad7ea523b9609acd16b0748655cc58f2fe0ad3","src/isa/s390x/abi.rs":"5774e66c53b0f6ba79aaeb7d54ce66a92fd2f0cd6fdc54d4a053e09ca7c34ecd","src/isa/s390x/inst.isle":"e24d5081d1c4fab88d3c84044e19bdfb3f83d75c4f092d5e8627acf318d3bf5e","src/isa/s390x/inst/args.rs":"ed71f8c9f849a1faa87511f82022c7b47d62d2dc309752bcb3edb5114eec7d59","src/isa/s390x/inst/emit.rs":"3e1135012dae987acedd3fcf5bcba373785787fa47f20a7ea3432bc3909e564f","src/isa/s390x/inst/emit_tests.rs":"3f71d804441d2e299690f9814de026c456fa567904931e6ca5f4f6dab78154d2","src/isa/s390x/inst/imms.rs":"de587bbdba3115eb2f54f374943ff82d9c5e9cbba44cca50088bcf40eda47a12","src/isa/s390x/inst/mod.rs":"b516db6954f9bfd97c2e08fb3ae0634b6dc721e66effe08b6d9b3736b31ff343","src/isa/s390x/inst/regs.rs":"1c11ec3c09b65c1557ae51f520222479aed3abf300b456df58824b32fb5bc9d0","src/isa/s390x/inst/unwind.rs":"0d06a94e614794057f224554060c8d6e0da0a01e021b92c33a1dbb3854b414f6","src/isa/s390x/inst/unwind/systemv.rs":"963a5d0c7bcd1a4441da501151213f5135719f10f389884bc273dc1a3321d746","src/isa/s390x/lower.isle":"c98e13076e01d13a79c763672ef28006e29f89dadb22e03e964187ee82de57a3","src/isa/s390x/lower.rs":"a19eebe83a12f247110bdabb398769050a333e45e9f4babf8b197a3ec9aa4088","src/isa/s390x/lower/isle.rs":"4271a61924d57a300f5a34e585446f3decf022edb069f8645df2071197164eb2","src/isa/s390x/lower/isle/generated_code.rs":"f3f544cd7e3abf337fcecf0c5e259325beb88ecda3b7f5c5efa87ed5e392eacd","src/isa/s390x/mod.rs":"15f5f4eea0cb5bdd6ef6d3c0018fee88783127cf4253528db3153c370cf7257d","src/isa/s390x/settings.rs":"064f84148f1bbffe440792c8b0337899b3f5bb1fd8c72b4b8d7c56faa5b93517","src/isa/unwind.rs":"c7d44abeb0cadc547663359f4c2a9600896ba4295d9bb9c70cd03abc2a30a1b0","src/isa/unwind/systemv.rs":"93affbf82faf637b2b3c84b966c18bee2603f15ec925899e023bed97dd9cc33c","src/isa/unwind/winarm64.rs":"f9419335200c3ab959d9bf27d2e402df4421dd427d9e8bf21bc3e7bb9a2c8a52","src/isa/unwind/winx64.rs":"05a7fb3adc5c99e6c6da589cf411e28bb05fe68fc5a41ea4fce3cddd22dfdbe8","src/isa/winch.rs":"e8098d0cf3e3bda6312ed8232b24744ddbbed643baa71306caa4b5a7e585378d","src/isa/x64/abi.rs":"eab84729a6c3574fd45e09bf1d2e892ecb73502af2effe10bb918da403d4e4e9","src/isa/x64/encoding/evex.rs":"e482baa91b6d62235ef6bac98704f37d4324738725e08b60e41aaa0f738904db","src/isa/x64/encoding/mod.rs":"0a0b63345f26e355b1a3e8f25d22e444dd32f53b6cf8978208d1bd3c33418876","src/isa/x64/encoding/rex.rs":"3e4698e53d3445135fbc786ad4c88b25ca873a2519d95902fd8e0e01c2483ede","src/isa/x64/encoding/vex.rs":"7df5c330cab063649f484b487da3341cab8697a41be7a999b7dc9ebafc811476","src/isa/x64/inst.isle":"d866a7b49ab92de62ac1061d2a293e1b5bbf9a8c3dbbf17c6518d99e61b2d7e1","src/isa/x64/inst/args.rs":"9896bcc8e20edac09c63a10c8759a34005170727c38ebdc140042ca7ffb5b337","src/isa/x64/inst/emit.rs":"081a9a6b379146b2d3afca9f9e6f2a5bc8317e8152ae939c5aa458eebaaeebf4","src/isa/x64/inst/emit_state.rs":"a6dbd1f8b704e39f9252a236f62a89c85e34fac3f4141724a5db536b35d73d68","src/isa/x64/inst/emit_tests.rs":"1da26f80261fc41103bf3b650759250efc821a33bf50698e785f5e3f2b4628e4","src/isa/x64/inst/mod.rs":"95bb71ecfa6e0eda810e7b32fa8057143c258411b641cf5e199b0fd407cb39d8","src/isa/x64/inst/regs.rs":"94a97f06d3cd14d74bd5f3ea01a8af4780d5de087dada68646c15e11c67f1b8f","src/isa/x64/inst/stack_switch.rs":"f4b7f1d6d27d4ae2f5629c00b992da5342e357467fa7b3ff964078a66f5f64a2","src/isa/x64/inst/unwind.rs":"3ef395c2108a0a3b5e48e52453276e212ea92f644a5007c427ed60f12c8daf1b","src/isa/x64/inst/unwind/systemv.rs":"5be5e4892917b884c7b99c7e14c980128032cb285c57ad39c29ff0ddecbff3a3","src/isa/x64/inst/unwind/winx64.rs":"e71e9dde687b85cdddfacad0f6000d18b24fdc29664cc208c244eb56a9d5b7c9","src/isa/x64/lower.isle":"915b7a785c663c66ba914b3facfc27375b564175f4690d35c65f548d3f92e99c","src/isa/x64/lower.rs":"2a82dc5bd1d2cade9b82c5c76310631630e258e6930c2c65ccd129a77f84203a","src/isa/x64/lower/isle.rs":"d5cbfc3a1e00f38a505c603b30cab0a5cf7e46092c0737993d2e6da9b47a3d41","src/isa/x64/lower/isle/generated_code.rs":"ec40e694d6924fd48839bee93939813e4a1e0a9fa3474c0c3b7a7524565f14f9","src/isa/x64/mod.rs":"04ddce806675a55ee3b31288e4f2f9f8d892ac852fc69e98cfbe96cb881c1bbb","src/isa/x64/pcc.rs":"098e72838d6ba08a977d49050714941e6d8b109551d902e4e10a932ea99b3fcc","src/isa/x64/settings.rs":"0e8cf4bbd126bce457045a4a51504f31188d95aaaa2ec9f896010443bc382fc4","src/isle_prelude.rs":"82004427625236846516fbf745d08334d528a729a40f29b3d3c645c47b000bb1","src/iterators.rs":"d399a80bc65b97f7d650978e19086dcc1d280ac96d60628eac3d17eb363b0d71","src/legalizer/globalvalue.rs":"32e771a49eee11edf67b7583571eba50d309f9b7a020790481720fc1bc92ee08","src/legalizer/mod.rs":"8ed2537bac41763c3d52b592b1bbff78537a4d27dd7c348703846ea3872eb692","src/lib.rs":"419f52bfed4029b4ea4d1697ed19f69631007583fbae3e1ec91544470905e448","src/loop_analysis.rs":"db38e668da56f1e719c8be9db4ae63b8752c1563c985fd9a53d77bb5e8754c59","src/machinst/abi.rs":"8315285743e5c2c78ad89be10152c0981dee3138aec8b76cc699e95d20f1420b","src/machinst/blockorder.rs":"6b945ba2d672e3b439058203788cc5e7a59b8a65345b171b2f14c7ee15499c7e","src/machinst/buffer.rs":"450492524dbf55028a7390b5d1926b5d51370a31ee6fcc9d17d358de4f87ed6f","src/machinst/compile.rs":"ba6822a449af747ff957fa095fd684807b4745e8002969e73a5779827de7a2dd","src/machinst/helpers.rs":"2e39db285fbc02c6e389dd85807697759c926ec6607597d30d46025f868a9c78","src/machinst/inst_common.rs":"0e63e1100ee2652ded93d375078c23cc704a46efb5bd4f9e5362345e71780424","src/machinst/isle.rs":"911359dbb0a8493e370a6b0f540d1bfa06e838763f57d100fb3aecf7ed56cb91","src/machinst/lower.rs":"216243f3da6d89477d31b6341230481e818022bfd3aa58ce83b28dab2331704f","src/machinst/mod.rs":"fa298a04ec446eb32079a0fe54ec5e28a990c5c09545dedabfc708d5624e0c4a","src/machinst/pcc.rs":"8e6ad20c61cb1945c90be6d7e51319062abe422fc2f131693c8d8a63d0368990","src/machinst/reg.rs":"441869d600766449f1497aa4f0e943186ad9b7756adf264420e82ec7bd99f7e9","src/machinst/valueregs.rs":"46d22cb5dd0f3a145113745dc4f6502343c6e51b95be4de244f164c00b0ced0c","src/machinst/vcode.rs":"48e34a48e517bdcb570915b70727c55843b3cf90308fae065a29b6c911469bea","src/nan_canonicalization.rs":"886672f28c04caa52df495b9f164e1d658be54f1e1445934c9146f1a951fb831","src/opts.rs":"16bcc2d256f0904e08831662a6ecd2b96d7dea4ba105f156833dbe1dfb53d430","src/opts/README.md":"9afe9a86535cd8657949daa060b17ce6c362ea23bd50b34bf59cfe647b745097","src/opts/arithmetic.isle":"1045f04f4c5f9ef117639afb3921ec3c8986db4e48ca07e8821305c22484e5c9","src/opts/bitops.isle":"20384674384605179cdd60a69fa0a8d7454114fd56ea8a2606f7d6edbcdb07da","src/opts/cprop.isle":"650599f3f73fb3e2430810ff9d861ad3cd961a70d4e506dfe0af13d3febc2b96","src/opts/extends.isle":"484deed3ae552ec5c18db96e9c07e8bef4cce92a740887e10e55b7617987a4d4","src/opts/generated_code.rs":"a1f736ddafaaa475e3483547eaba80b7d68595a5ef701139bb0652599fdb2139","src/opts/icmp.isle":"c7bd0acbb4096a5cb8403d97aa1da9e4dc1de0bc1b66de0be12e2ea07e62bbd9","src/opts/remat.isle":"f996f00c2b2d8607a32305b8665b7088779de0fb6fd23cabb38a2c8a2c9accc3","src/opts/selects.isle":"f6231ceb205851a0750417805f5d74bc31a0217390f4ad957bedbf4bf00bb099","src/opts/shifts.isle":"8d1f596ab9e6a00b50810de898def196733256023c8aa0684dc6e63c74ca8615","src/opts/spaceship.isle":"c3e6fe70d31d11994260eb96bdd11da73621c6884b953f55f1011d9e8c9ae4f3","src/opts/spectre.isle":"c5f389770ad42c81dd681c4ca2b001608ba0219c175ffa1748819d87841295b9","src/opts/vector.isle":"c565199aab0f157b6d3adc99fdc15e9fd028073591faee392e337611065f887e","src/prelude.isle":"280110a7ccde9bb8b679976649fb09409e37ad98b088d13ebe66625542bf7b55","src/prelude_lower.isle":"4816f98a127fd934fc0dbf1223540d6843d86a6b0f0787bdfd385ed39ef57f2d","src/prelude_opt.isle":"e7a43732d8abe3eebbbcd2722e30fc4416a0b78d54280d52382eee3d41578619","src/print_errors.rs":"5fb555c4036a3193da7a7b9820f94d171a68b51965fe9aca297fb2563a42b608","src/ranges.rs":"a9fc274561b2536750ec0c5ec2dff02073e547a9a8d55876d344378f5cd5d1ea","src/remove_constant_phis.rs":"ed3e9c8930d85ccc6540fe569a9dbfc944c957f70e9678497f6143f14c8774fe","src/result.rs":"1cf49ba5c2f1c213954e2ee4dba1719d71c7f6d1bee16d6d96431041be39beeb","src/scoped_hash_map.rs":"f2e682485abc7643c4417fc9a236ca166d788724b68e8fffcfff356682b691f4","src/settings.rs":"67fe94fcd7a07b280d45a995d82226f9d775f49aa234848e8d60b4244aa9acb5","src/souper_harvest.rs":"a101686d3d5e23ec617ddbce222e0d1058b136e4d6dd8a2cbfb44be15aa3dbae","src/timing.rs":"a4e67bbcbda1a7168192214e91e16b233ec536e8f627dfb6b73f1871bd6b1a06","src/traversals.rs":"f52e4980cdabb0e2af92577781992551db3fce4bcc82a584b489aa124e34274d","src/unionfind.rs":"ee962db114bc364b9a4cda8b20cdc14e8589ae36e419cc148529a2f5d1fe4cc5","src/unreachable_code.rs":"607dd0f78067ed69da6c8fa1dde915b2fed1f71a39195086531ed6617e819544","src/value_label.rs":"c7684e75ef035aa0d6e79d74be5c93142b7d5800ef4b05c3a8198cf8e5761cca","src/verifier/mod.rs":"83f47938508090385159d419b7ae2c1acdcd29e978b9a494d40545c013b8dc52","src/write.rs":"f3b1fa8b95f5e3e9ed133cdbaefda5d5b78d5b6d916faa05796729bf4a0d759d"},"package":"2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-codegen/.cargo_vcs_info.json new file mode 100644 index 00000000000000..8f552106a91bb6 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/codegen" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-codegen/Cargo.lock b/deps/crates/vendor/cranelift-codegen/Cargo.lock new file mode 100644 index 00000000000000..8c871d62883271 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/Cargo.lock @@ -0,0 +1,1078 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "capstone" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08ca438d9585a2b216b0c2e88ea51e096286c5f197f7be2526bb515ef775b6c" +dependencies = [ + "capstone-sys", + "libc", +] + +[[package]] +name = "capstone-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7183271711ffb7c63a6480e4baf480e0140da59eeba9b18fcc8bf3478950e3" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +dependencies = [ + "anyhow", + "bumpalo", + "capstone", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "criterion", + "env_logger", + "gimli", + "hashbrown 0.14.3", + "log", + "postcard", + "pulley-interpreter", + "regalloc2", + "rustc-hash", + "serde", + "serde_derive", + "sha2", + "similar", + "smallvec", + "souper-ir", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" +dependencies = [ + "codespan-reporting", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulley-interpreter" +version = "29.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d95f8575df49a2708398182f49a888cf9dc30210fb1fd2df87c889edcee75d" +dependencies = [ + "cranelift-bitset", + "log", + "sptr", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regalloc2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", + "log", + "rustc-hash", + "serde", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustix" +version = "0.38.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "similar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] + +[[package]] +name = "souper-ir" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50c18ce33988e1973003afbaa66e6a465ad7a614dc33f246879ccc209c2c044" +dependencies = [ + "id-arena", +] + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/deps/crates/vendor/cranelift-codegen/Cargo.toml b/deps/crates/vendor/cranelift-codegen/Cargo.toml new file mode 100644 index 00000000000000..9fc32c3b52bfb0 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/Cargo.toml @@ -0,0 +1,242 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-codegen" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Low-level code generator library" +documentation = "https://docs.rs/cranelift-codegen" +readme = "README.md" +keywords = [ + "compile", + "compiler", + "jit", +] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[package.metadata.docs.rs] +features = ["all-arch"] + +[lib] +name = "cranelift_codegen" +path = "src/lib.rs" + +[[bench]] +name = "x64-evex-encoding" +path = "benches/x64-evex-encoding.rs" +harness = false + +[dependencies.anyhow] +version = "1.0.93" +features = ["std"] +optional = true +default-features = false + +[dependencies.bumpalo] +version = "3" + +[dependencies.capstone] +version = "0.12.0" +optional = true + +[dependencies.cranelift-bforest] +version = "0.116.1" + +[dependencies.cranelift-bitset] +version = "0.116.1" + +[dependencies.cranelift-codegen-shared] +version = "0.116.1" + +[dependencies.cranelift-control] +version = "0.116.1" + +[dependencies.cranelift-entity] +version = "0.116.1" + +[dependencies.gimli] +version = "0.31.0" +features = [ + "read", + "write", + "std", +] +optional = true +default-features = false + +[dependencies.hashbrown] +version = "0.14" +features = ["raw"] +default-features = false + +[dependencies.log] +version = "0.4.8" +default-features = false + +[dependencies.postcard] +version = "1.0.8" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.pulley-interpreter] +version = "=29.0.1" +optional = true + +[dependencies.regalloc2] +version = "0.11.1" +features = ["checker"] + +[dependencies.rustc-hash] +version = "2.0.0" + +[dependencies.serde] +version = "1.0.215" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde_derive] +version = "1.0.188" +optional = true + +[dependencies.sha2] +version = "0.10.2" +optional = true + +[dependencies.smallvec] +version = "1.6.1" +features = ["union"] + +[dependencies.souper-ir] +version = "2.1.0" +optional = true + +[dependencies.target-lexicon] +version = "0.13.0" + +[dev-dependencies.criterion] +version = "0.5.0" +features = [ + "html_reports", + "rayon", +] +default-features = false + +[dev-dependencies.env_logger] +version = "0.11.5" + +[dev-dependencies.similar] +version = "2.1.0" + +[build-dependencies.cranelift-codegen-meta] +version = "0.116.1" + +[build-dependencies.cranelift-isle] +version = "=0.116.1" + +[features] +all-arch = [ + "all-native-arch", + "pulley", +] +all-native-arch = [ + "x86", + "arm64", + "s390x", + "riscv64", +] +arm64 = [] +core = [] +default = [ + "std", + "unwind", + "host-arch", + "timing", +] +disas = [ + "anyhow", + "capstone", +] +enable-serde = [ + "serde", + "serde_derive", + "cranelift-entity/enable-serde", + "cranelift-bitset/enable-serde", + "regalloc2/enable-serde", + "smallvec/serde", +] +host-arch = [] +incremental-cache = [ + "enable-serde", + "postcard", + "sha2", +] +isle-errors = ["cranelift-isle/fancy-errors"] +pulley = [ + "dep:pulley-interpreter", + "pulley-interpreter/encode", + "pulley-interpreter/disas", + "cranelift-codegen-meta/pulley", +] +riscv64 = [] +s390x = [] +souper-harvest = [ + "souper-ir", + "souper-ir/stringify", +] +std = ["serde?/std"] +timing = [] +trace-log = ["regalloc2/trace-log"] +unwind = ["gimli"] +x86 = [] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-codegen/Cargo.toml.orig b/deps/crates/vendor/cranelift-codegen/Cargo.toml.orig new file mode 100644 index 00000000000000..9a1c4779cfb14f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/Cargo.toml.orig @@ -0,0 +1,143 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-codegen" +version = "0.116.1" +description = "Low-level code generator library" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift-codegen" +repository = "https://github.com/bytecodealliance/wasmtime" +categories = ["no-std"] +readme = "README.md" +keywords = ["compile", "compiler", "jit"] +build = "build.rs" +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[package.metadata.docs.rs] +# Ask Cargo to build docs with the feature `all-arch` +features = ["all-arch"] + +[dependencies] +anyhow = { workspace = true, optional = true, features = ['std'] } +bumpalo = "3" +capstone = { workspace = true, optional = true } +cranelift-codegen-shared = { path = "./shared", version = "0.116.1" } +cranelift-entity = { workspace = true } +cranelift-bforest = { workspace = true } +cranelift-bitset = { workspace = true } +cranelift-control = { workspace = true } +hashbrown = { workspace = true, features = ["raw"] } +target-lexicon = { workspace = true } +log = { workspace = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +pulley-interpreter = { workspace = true, optional = true } +postcard = { workspace = true, optional = true } +gimli = { workspace = true, features = ["write", "std"], optional = true } +smallvec = { workspace = true } +regalloc2 = { workspace = true, features = ["checker"] } +souper-ir = { version = "2.1.0", optional = true } +sha2 = { version = "0.10.2", optional = true } +rustc-hash = { workspace = true } +# It is a goal of the cranelift-codegen crate to have minimal external dependencies. +# Please don't add any unless they are essential to the task of creating binary +# machine code. Integration tests that need external dependencies can be +# accommodated in `tests`. + +[dev-dependencies] +criterion = { workspace = true } +similar = "2.1.0" +env_logger = { workspace = true } + +[build-dependencies] +cranelift-codegen-meta = { path = "meta", version = "0.116.1" } +cranelift-isle = { path = "../isle/isle", version = "=0.116.1" } + +[features] +default = ["std", "unwind", "host-arch", "timing"] + +# The "std" feature enables use of libstd. The "core" feature enables use +# of some minimal std-like replacement libraries. At least one of these two +# features need to be enabled. +std = ["serde?/std"] + +# The "core" feature used to enable a hashmap workaround, but is now +# deprecated (we (i) always use hashbrown, and (ii) don't support a +# no_std build anymore). The feature remains for backward +# compatibility as a no-op. +core = [] + +# Enable the `to_capstone` method on TargetIsa, for constructing a Capstone +# context, and the `disassemble` method on `MachBufferFinalized`. +disas = ["anyhow", "capstone"] + +# Enables detailed logging which can be somewhat expensive. +trace-log = ["regalloc2/trace-log"] + +# This enables unwind info generation functionality. +unwind = ["gimli"] + +# ISA targets for which we should build. +# If no ISA targets are explicitly enabled, the ISA target for the host machine is enabled. +x86 = [] +arm64 = [] +s390x = [] +riscv64 = [] +pulley = [ + "dep:pulley-interpreter", + "pulley-interpreter/encode", + "pulley-interpreter/disas", + "cranelift-codegen-meta/pulley", +] +# Enable the ISA target for the host machine +host-arch = [] + +# Option to enable all architectures. +all-arch = [ + "all-native-arch", + "pulley", +] + +# Option to enable all architectures that correspond to an actual native target +# (that is, exclude Pulley). +all-native-arch = [ + "x86", + "arm64", + "s390x", + "riscv64", +] + +# For dependent crates that want to serialize some parts of cranelift +enable-serde = [ + "serde", + "serde_derive", + "cranelift-entity/enable-serde", + "cranelift-bitset/enable-serde", + "regalloc2/enable-serde", + "smallvec/serde" +] + +# Enable the incremental compilation cache for hot-reload use cases. +incremental-cache = [ + "enable-serde", + "postcard", + "sha2" +] + +# Enable support for the Souper harvester. +souper-harvest = ["souper-ir", "souper-ir/stringify"] + +# Report any ISLE errors in pretty-printed style. +isle-errors = ["cranelift-isle/fancy-errors"] + +# Enable tracking how long passes take in Cranelift. +# +# Enabled by default. +timing = [] + +[[bench]] +name = "x64-evex-encoding" +harness = false diff --git a/deps/crates/vendor/cranelift-codegen/LICENSE b/deps/crates/vendor/cranelift-codegen/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-codegen/README.md b/deps/crates/vendor/cranelift-codegen/README.md new file mode 100644 index 00000000000000..18b9756aad97fa --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/README.md @@ -0,0 +1,2 @@ +This crate contains the core Cranelift code generator. It translates code from an +intermediate representation into executable machine code. diff --git a/deps/crates/vendor/cranelift-codegen/benches/x64-evex-encoding.rs b/deps/crates/vendor/cranelift-codegen/benches/x64-evex-encoding.rs new file mode 100644 index 00000000000000..dd280212c59840 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/benches/x64-evex-encoding.rs @@ -0,0 +1,52 @@ +//! Measure instruction encoding latency using various approaches; the +//! benchmarking is feature-gated on `x86` since it only measures the encoding +//! mechanism of that backend. + +#[cfg(feature = "x86")] +mod x86 { + use cranelift_codegen::isa::x64::encoding::{ + evex::{EvexInstruction, EvexVectorLength, Register}, + rex::{LegacyPrefixes, OpcodeMap}, + }; + use criterion::{criterion_group, Criterion}; + + // Define the benchmarks. + fn x64_evex_encoding_benchmarks(c: &mut Criterion) { + let mut group = c.benchmark_group("x64 EVEX encoding"); + let rax = Register::from(0); + let rdx = 2; + + group.bench_function("EvexInstruction (builder pattern)", |b| { + b.iter(|| { + let mut sink = cranelift_codegen::MachBuffer::new(); + EvexInstruction::new() + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F38) + .w(true) + .opcode(0x1F) + .reg(rax) + .rm(rdx) + .length(EvexVectorLength::V128) + .encode(&mut sink); + }); + }); + } + criterion_group!(benches, x64_evex_encoding_benchmarks); + + /// Using an inner module to feature-gate the benchmarks means that we must + /// manually specify how to run the benchmarks (see `criterion_main!`). + pub fn run_benchmarks() { + benches(); + Criterion::default().configure_from_args().final_summary(); + } +} + +fn main() { + #[cfg(feature = "x86")] + x86::run_benchmarks(); + + #[cfg(not(feature = "x86"))] + println!( + "Unable to run the x64-evex-encoding benchmark; the `x86` feature must be enabled in Cargo.", + ); +} diff --git a/deps/crates/vendor/cranelift-codegen/build.rs b/deps/crates/vendor/cranelift-codegen/build.rs new file mode 100644 index 00000000000000..72ea49bbb88679 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/build.rs @@ -0,0 +1,223 @@ +// Build script. +// +// This program is run by Cargo when building cranelift-codegen. It is used to generate Rust code from +// the language definitions in the cranelift-codegen/meta directory. +// +// Environment: +// +// OUT_DIR +// Directory where generated files should be placed. +// +// TARGET +// Target triple provided by Cargo. +// +// The build script expects to be run from the directory where this build.rs file lives. The +// current directory is used to find the sources. + +use cranelift_codegen_meta as meta; +use cranelift_isle::error::Errors; +use meta::isle::IsleCompilation; + +use std::env; +use std::io::Read; +use std::process; +use std::time::Instant; + +fn main() { + let start_time = Instant::now(); + + let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"); + let out_dir = std::path::Path::new(&out_dir); + let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set"); + + let all_arch = env::var("CARGO_FEATURE_ALL_ARCH").is_ok(); + let all_native_arch = env::var("CARGO_FEATURE_ALL_NATIVE_ARCH").is_ok(); + + let mut isas = meta::isa::Isa::all() + .iter() + .cloned() + .filter(|isa| { + let env_key = match isa { + meta::isa::Isa::Pulley32 | meta::isa::Isa::Pulley64 => { + "CARGO_FEATURE_PULLEY".to_string() + } + _ => format!("CARGO_FEATURE_{}", isa.to_string().to_uppercase()), + }; + all_arch || env::var(env_key).is_ok() + }) + .collect::>(); + + // Don't require host isa if under 'all-arch' feature. + let host_isa = env::var("CARGO_FEATURE_HOST_ARCH").is_ok() && !all_native_arch; + + if isas.is_empty() || host_isa { + // Try to match native target. + let target_name = target_triple.split('-').next().unwrap(); + let isa = meta::isa_from_arch(&target_name).expect("error when identifying target"); + println!("cargo:rustc-cfg=feature=\"{isa}\""); + isas.push(isa); + } + + let cur_dir = env::current_dir().expect("Can't access current working directory"); + let crate_dir = cur_dir.as_path(); + + println!("cargo:rerun-if-changed=build.rs"); + + let isle_dir = if let Ok(path) = std::env::var("ISLE_SOURCE_DIR") { + // This will canonicalize any relative path in terms of the + // crate root, and will take any absolute path as overriding the + // `crate_dir`. + crate_dir.join(&path) + } else { + out_dir.into() + }; + + std::fs::create_dir_all(&isle_dir).expect("Could not create ISLE source directory"); + + if let Err(err) = meta::generate(&isas, &out_dir, &isle_dir) { + eprintln!("Error: {err}"); + process::exit(1); + } + + if &std::env::var("SKIP_ISLE").unwrap_or("0".to_string()) != "1" { + if let Err(err) = build_isle(crate_dir, &isle_dir) { + eprintln!("Error: {err}"); + process::exit(1); + } + } + + if env::var("CRANELIFT_VERBOSE").is_ok() { + for isa in &isas { + println!("cargo:warning=Includes support for {} ISA", isa.to_string()); + } + println!( + "cargo:warning=Build step took {:?}.", + Instant::now() - start_time + ); + println!("cargo:warning=Generated files are in {}", out_dir.display()); + } + + let pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); + let mut cmd = std::process::Command::new("git"); + cmd.arg("rev-parse") + .arg("HEAD") + .stdout(std::process::Stdio::piped()) + .current_dir(env::var("CARGO_MANIFEST_DIR").unwrap()); + let version = if let Ok(mut child) = cmd.spawn() { + let mut git_rev = String::new(); + child + .stdout + .as_mut() + .unwrap() + .read_to_string(&mut git_rev) + .unwrap(); + let status = child.wait().unwrap(); + if status.success() { + let git_rev = git_rev.trim().chars().take(9).collect::(); + format!("{pkg_version}-{git_rev}") + } else { + // not a git repo + pkg_version + } + } else { + // git not available + pkg_version + }; + std::fs::write( + std::path::Path::new(&out_dir).join("version.rs"), + format!( + "/// Version number of this crate. \n\ + pub const VERSION: &str = \"{version}\";" + ), + ) + .unwrap(); +} + +/// Strip the current directory from the file paths, because `islec` +/// includes them in the generated source, and this helps us maintain +/// deterministic builds that don't include those local file paths. +fn make_isle_source_path_relative( + cur_dir: &std::path::Path, + filename: &std::path::Path, +) -> std::path::PathBuf { + if let Ok(suffix) = filename.strip_prefix(&cur_dir) { + suffix.to_path_buf() + } else { + filename.to_path_buf() + } +} + +fn build_isle( + crate_dir: &std::path::Path, + isle_dir: &std::path::Path, +) -> Result<(), Box> { + let cur_dir = std::env::current_dir()?; + let isle_compilations = meta::isle::get_isle_compilations( + &make_isle_source_path_relative(&cur_dir, &crate_dir), + &make_isle_source_path_relative(&cur_dir, &isle_dir), + ); + + let mut had_error = false; + for compilation in &isle_compilations.items { + for file in &compilation.inputs { + println!("cargo:rerun-if-changed={}", file.display()); + } + + if let Err(e) = run_compilation(compilation) { + had_error = true; + eprintln!("Error building ISLE files:"); + eprintln!("{e:?}"); + #[cfg(not(feature = "isle-errors"))] + { + eprintln!("To see a more detailed error report, run: "); + eprintln!(); + eprintln!(" $ cargo check -p cranelift-codegen --features isle-errors"); + eprintln!(); + } + } + } + + if had_error { + std::process::exit(1); + } + + println!("cargo:rustc-env=ISLE_DIR={}", isle_dir.to_str().unwrap()); + + Ok(()) +} + +/// Build ISLE DSL source text into generated Rust code. +/// +/// NB: This must happen *after* the `cranelift-codegen-meta` functions, since +/// it consumes files generated by them. +fn run_compilation(compilation: &IsleCompilation) -> Result<(), Errors> { + use cranelift_isle as isle; + + eprintln!("Rebuilding {}", compilation.output.display()); + + let code = { + let file_paths = compilation + .inputs + .iter() + .chain(compilation.untracked_inputs.iter()); + + let mut options = isle::codegen::CodegenOptions::default(); + // Because we include!() the generated ISLE source, we cannot + // put the global pragmas (`#![allow(...)]`) in the ISLE + // source itself; we have to put them in the source that + // include!()s it. (See + // https://github.com/rust-lang/rust/issues/47995.) + options.exclude_global_allow_pragmas = true; + + isle::compile::from_files(file_paths, &options)? + }; + + eprintln!( + "Writing ISLE-generated Rust code to {}", + compilation.output.display() + ); + std::fs::write(&compilation.output, code) + .map_err(|e| Errors::from_io(e, "failed writing output"))?; + + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/alias_analysis.rs b/deps/crates/vendor/cranelift-codegen/src/alias_analysis.rs new file mode 100644 index 00000000000000..6a6e9f2748ba9b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/alias_analysis.rs @@ -0,0 +1,402 @@ +//! Alias analysis, consisting of a "last store" pass and a "memory +//! values" pass. These two passes operate as one fused pass, and so +//! are implemented together here. +//! +//! We partition memory state into several *disjoint pieces* of +//! "abstract state". There are a finite number of such pieces: +//! currently, we call them "heap", "table", "vmctx", and "other".Any +//! given address in memory belongs to exactly one disjoint piece. +//! +//! One never tracks which piece a concrete address belongs to at +//! runtime; this is a purely static concept. Instead, all +//! memory-accessing instructions (loads and stores) are labeled with +//! one of these four categories in the `MemFlags`. It is forbidden +//! for a load or store to access memory under one category and a +//! later load or store to access the same memory under a different +//! category. This is ensured to be true by construction during +//! frontend translation into CLIF and during legalization. +//! +//! Given that this non-aliasing property is ensured by the producer +//! of CLIF, we can compute a *may-alias* property: one load or store +//! may-alias another load or store if both access the same category +//! of abstract state. +//! +//! The "last store" pass helps to compute this aliasing: it scans the +//! code, finding at each program point the last instruction that +//! *might have* written to a given part of abstract state. +//! +//! We can't say for sure that the "last store" *did* actually write +//! that state, but we know for sure that no instruction *later* than +//! it (up to the current instruction) did. However, we can get a +//! must-alias property from this: if at a given load or store, we +//! look backward to the "last store", *AND* we find that it has +//! exactly the same address expression and type, then we know that +//! the current instruction's access *must* be to the same memory +//! location. +//! +//! To get this must-alias property, we compute a sparse table of +//! "memory values": these are known equivalences between SSA `Value`s +//! and particular locations in memory. The memory-values table is a +//! mapping from (last store, address expression, type) to SSA +//! value. At a store, we can insert into this table directly. At a +//! load, we can also insert, if we don't already have a value (from +//! the store that produced the load's value). +//! +//! Then we can do two optimizations at once given this table. If a +//! load accesses a location identified by a (last store, address, +//! type) key already in the table, we replace it with the SSA value +//! for that memory location. This is usually known as "redundant load +//! elimination" if the value came from an earlier load of the same +//! location, or "store-to-load forwarding" if the value came from an +//! earlier store to the same location. +//! +//! In theory we could also do *dead-store elimination*, where if a +//! store overwrites a key in the table, *and* if no other load/store +//! to the abstract state category occurred, *and* no other trapping +//! instruction occurred (at which point we need an up-to-date memory +//! state because post-trap-termination memory state can be observed), +//! *and* we can prove the original store could not have trapped, then +//! we can eliminate the original store. Because this is so complex, +//! and the conditions for doing it correctly when post-trap state +//! must be correct likely reduce the potential benefit, we don't yet +//! do this. + +use crate::{ + cursor::{Cursor, FuncCursor}, + dominator_tree::DominatorTree, + inst_predicates::{ + has_memory_fence_semantics, inst_addr_offset_type, inst_store_data, visit_block_succs, + }, + ir::{immediates::Offset32, AliasRegion, Block, Function, Inst, Opcode, Type, Value}, + trace, +}; +use cranelift_entity::{packed_option::PackedOption, EntityRef}; +use rustc_hash::{FxHashMap, FxHashSet}; + +/// For a given program point, the vector of last-store instruction +/// indices for each disjoint category of abstract state. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct LastStores { + heap: PackedOption, + table: PackedOption, + vmctx: PackedOption, + other: PackedOption, +} + +impl LastStores { + fn update(&mut self, func: &Function, inst: Inst) { + let opcode = func.dfg.insts[inst].opcode(); + if has_memory_fence_semantics(opcode) { + self.heap = inst.into(); + self.table = inst.into(); + self.vmctx = inst.into(); + self.other = inst.into(); + } else if opcode.can_store() { + if let Some(memflags) = func.dfg.insts[inst].memflags() { + match memflags.alias_region() { + None => self.other = inst.into(), + Some(AliasRegion::Heap) => self.heap = inst.into(), + Some(AliasRegion::Table) => self.table = inst.into(), + Some(AliasRegion::Vmctx) => self.vmctx = inst.into(), + } + } else { + self.heap = inst.into(); + self.table = inst.into(); + self.vmctx = inst.into(); + self.other = inst.into(); + } + } + } + + fn get_last_store(&self, func: &Function, inst: Inst) -> PackedOption { + if let Some(memflags) = func.dfg.insts[inst].memflags() { + match memflags.alias_region() { + None => self.other, + Some(AliasRegion::Heap) => self.heap, + Some(AliasRegion::Table) => self.table, + Some(AliasRegion::Vmctx) => self.vmctx, + } + } else if func.dfg.insts[inst].opcode().can_load() + || func.dfg.insts[inst].opcode().can_store() + { + inst.into() + } else { + PackedOption::default() + } + } + + fn meet_from(&mut self, other: &LastStores, loc: Inst) { + let meet = |a: PackedOption, b: PackedOption| -> PackedOption { + match (a.into(), b.into()) { + (None, None) => None.into(), + (Some(a), None) => a, + (None, Some(b)) => b, + (Some(a), Some(b)) if a == b => a, + _ => loc.into(), + } + }; + + self.heap = meet(self.heap, other.heap); + self.table = meet(self.table, other.table); + self.vmctx = meet(self.vmctx, other.vmctx); + self.other = meet(self.other, other.other); + } +} + +/// A key identifying a unique memory location. +/// +/// For the result of a load to be equivalent to the result of another +/// load, or the store data from a store, we need for (i) the +/// "version" of memory (here ensured by having the same last store +/// instruction to touch the disjoint category of abstract state we're +/// accessing); (ii) the address must be the same (here ensured by +/// having the same SSA value, which doesn't change after computed); +/// (iii) the offset must be the same; and (iv) the accessed type and +/// extension mode (e.g., 8-to-32, signed) must be the same. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct MemoryLoc { + last_store: PackedOption, + address: Value, + offset: Offset32, + ty: Type, + /// We keep the *opcode* of the instruction that produced the + /// value we record at this key if the opcode is anything other + /// than an ordinary load or store. This is needed when we + /// consider loads that extend the value: e.g., an 8-to-32 + /// sign-extending load will produce a 32-bit value from an 8-bit + /// value in memory, so we can only reuse that (as part of RLE) + /// for another load with the same extending opcode. + /// + /// We could improve the transform to insert explicit extend ops + /// in place of extending loads when we know the memory value, but + /// we haven't yet done this. + extending_opcode: Option, +} + +/// An alias-analysis pass. +pub struct AliasAnalysis<'a> { + /// The domtree for the function. + domtree: &'a DominatorTree, + + /// Input state to a basic block. + block_input: FxHashMap, + + /// Known memory-value equivalences. This is the result of the + /// analysis. This is a mapping from (last store, address + /// expression, offset, type) to SSA `Value`. + /// + /// We keep the defining inst around for quick dominance checks. + mem_values: FxHashMap, +} + +impl<'a> AliasAnalysis<'a> { + /// Perform an alias analysis pass. + pub fn new(func: &Function, domtree: &'a DominatorTree) -> AliasAnalysis<'a> { + trace!("alias analysis: input is:\n{:?}", func); + let mut analysis = AliasAnalysis { + domtree, + block_input: FxHashMap::default(), + mem_values: FxHashMap::default(), + }; + + analysis.compute_block_input_states(func); + analysis + } + + fn compute_block_input_states(&mut self, func: &Function) { + let mut queue = vec![]; + let mut queue_set = FxHashSet::default(); + let entry = func.layout.entry_block().unwrap(); + queue.push(entry); + queue_set.insert(entry); + + while let Some(block) = queue.pop() { + queue_set.remove(&block); + let mut state = *self + .block_input + .entry(block) + .or_insert_with(|| LastStores::default()); + + trace!( + "alias analysis: input to block{} is {:?}", + block.index(), + state + ); + + for inst in func.layout.block_insts(block) { + state.update(func, inst); + trace!("after inst{}: state is {:?}", inst.index(), state); + } + + visit_block_succs(func, block, |_inst, succ, _from_table| { + let succ_first_inst = func.layout.block_insts(succ).into_iter().next().unwrap(); + let updated = match self.block_input.get_mut(&succ) { + Some(succ_state) => { + let old = *succ_state; + succ_state.meet_from(&state, succ_first_inst); + *succ_state != old + } + None => { + self.block_input.insert(succ, state); + true + } + }; + + if updated && queue_set.insert(succ) { + queue.push(succ); + } + }); + } + } + + /// Get the starting state for a block. + pub fn block_starting_state(&self, block: Block) -> LastStores { + self.block_input + .get(&block) + .cloned() + .unwrap_or_else(|| LastStores::default()) + } + + /// Process one instruction. Meant to be invoked in program order + /// within a block, and ideally in RPO or at least some domtree + /// preorder for maximal reuse. + /// + /// Returns `true` if instruction was removed. + pub fn process_inst( + &mut self, + func: &mut Function, + state: &mut LastStores, + inst: Inst, + ) -> Option { + trace!( + "alias analysis: scanning at inst{} with state {:?} ({:?})", + inst.index(), + state, + func.dfg.insts[inst], + ); + + let replacing_value = if let Some((address, offset, ty)) = inst_addr_offset_type(func, inst) + { + let address = func.dfg.resolve_aliases(address); + let opcode = func.dfg.insts[inst].opcode(); + + if opcode.can_store() { + let store_data = inst_store_data(func, inst).unwrap(); + let store_data = func.dfg.resolve_aliases(store_data); + let mem_loc = MemoryLoc { + last_store: inst.into(), + address, + offset, + ty, + extending_opcode: get_ext_opcode(opcode), + }; + trace!( + "alias analysis: at inst{}: store with data v{} at loc {:?}", + inst.index(), + store_data.index(), + mem_loc + ); + self.mem_values.insert(mem_loc, (inst, store_data)); + + None + } else if opcode.can_load() { + let last_store = state.get_last_store(func, inst); + let load_result = func.dfg.inst_results(inst)[0]; + let mem_loc = MemoryLoc { + last_store, + address, + offset, + ty, + extending_opcode: get_ext_opcode(opcode), + }; + trace!( + "alias analysis: at inst{}: load with last_store inst{} at loc {:?}", + inst.index(), + last_store.map(|inst| inst.index()).unwrap_or(usize::MAX), + mem_loc + ); + + // Is there a Value already known to be stored + // at this specific memory location? If so, + // we can alias the load result to this + // already-known Value. + // + // Check if the definition dominates this + // location; it might not, if it comes from a + // load (stores will always dominate though if + // their `last_store` survives through + // meet-points to this use-site). + let aliased = + if let Some((def_inst, value)) = self.mem_values.get(&mem_loc).cloned() { + trace!( + " -> sees known value v{} from inst{}", + value.index(), + def_inst.index() + ); + if self.domtree.dominates(def_inst, inst, &func.layout) { + trace!( + " -> dominates; value equiv from v{} to v{} inserted", + load_result.index(), + value.index() + ); + Some(value) + } else { + None + } + } else { + None + }; + + // Otherwise, we can keep *this* load around + // as a new equivalent value. + if aliased.is_none() { + trace!( + " -> inserting load result v{} at loc {:?}", + load_result.index(), + mem_loc + ); + self.mem_values.insert(mem_loc, (inst, load_result)); + } + + aliased + } else { + None + } + } else { + None + }; + + state.update(func, inst); + + replacing_value + } + + /// Make a pass and update known-redundant loads to aliased + /// values. We interleave the updates with the memory-location + /// tracking because resolving some aliases may expose others + /// (e.g. in cases of double-indirection with two separate chains + /// of loads). + pub fn compute_and_update_aliases(&mut self, func: &mut Function) { + let mut pos = FuncCursor::new(func); + + while let Some(block) = pos.next_block() { + let mut state = self.block_starting_state(block); + while let Some(inst) = pos.next_inst() { + if let Some(replaced_result) = self.process_inst(pos.func, &mut state, inst) { + let result = pos.func.dfg.inst_results(inst)[0]; + pos.func.dfg.clear_results(inst); + pos.func.dfg.change_to_alias(result, replaced_result); + pos.remove_inst_and_step_back(); + } + } + } + } +} + +fn get_ext_opcode(op: Opcode) -> Option { + debug_assert!(op.can_load() || op.can_store()); + match op { + Opcode::Load | Opcode::Store => None, + _ => Some(op), + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/binemit/mod.rs b/deps/crates/vendor/cranelift-codegen/src/binemit/mod.rs new file mode 100644 index 00000000000000..39490849a87734 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/binemit/mod.rs @@ -0,0 +1,174 @@ +//! Binary machine code emission. +//! +//! The `binemit` module contains code for translating Cranelift's intermediate representation into +//! binary machine code. + +use core::fmt; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Offset in bytes from the beginning of the function. +/// +/// Cranelift can be used as a cross compiler, so we don't want to use a type like `usize` which +/// depends on the *host* platform, not the *target* platform. +pub type CodeOffset = u32; + +/// Addend to add to the symbol value. +pub type Addend = i64; + +/// Relocation kinds for every ISA +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum Reloc { + /// absolute 4-byte + Abs4, + /// absolute 8-byte + Abs8, + /// x86 PC-relative 4-byte + X86PCRel4, + /// x86 call to PC-relative 4-byte + X86CallPCRel4, + /// x86 call to PLT-relative 4-byte + X86CallPLTRel4, + /// x86 GOT PC-relative 4-byte + X86GOTPCRel4, + /// The 32-bit offset of the target from the beginning of its section. + /// Equivalent to `IMAGE_REL_AMD64_SECREL`. + /// See: [PE Format](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format) + X86SecRel, + /// Arm32 call target + Arm32Call, + /// Arm64 call target. Encoded as bottom 26 bits of instruction. This + /// value is sign-extended, multiplied by 4, and added to the PC of + /// the call instruction to form the destination address. + Arm64Call, + /// s390x PC-relative 4-byte offset + S390xPCRel32Dbl, + /// s390x PC-relative 4-byte offset to PLT + S390xPLTRel32Dbl, + + /// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol. + ElfX86_64TlsGd, + + /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry. + MachOX86_64Tlv, + + /// Mach-O Aarch64 TLS + /// PC-relative distance to the page of the TLVP slot. + MachOAarch64TlsAdrPage21, + + /// Mach-O Aarch64 TLS + /// Offset within page of TLVP slot. + MachOAarch64TlsAdrPageOff12, + + /// Aarch64 TLSDESC Adr Page21 + /// This is equivalent to `R_AARCH64_TLSDESC_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescAdrPage21, + + /// Aarch64 TLSDESC Ld64 Lo12 + /// This is equivalent to `R_AARCH64_TLSDESC_LD64_LO12` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescLd64Lo12, + + /// Aarch64 TLSDESC Add Lo12 + /// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescAddLo12, + + /// Aarch64 TLSDESC Call + /// This is equivalent to `R_AARCH64_TLSDESC_CALL` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescCall, + + /// AArch64 GOT Page + /// Set the immediate value of an ADRP to bits 32:12 of X; check that –2^32 <= X < 2^32 + /// This is equivalent to `R_AARCH64_ADR_GOT_PAGE` (311) in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#static-aarch64-relocations) + Aarch64AdrGotPage21, + + /// AArch64 GOT Low bits + + /// Set the LD/ST immediate field to bits 11:3 of X. No overflow check; check that X&7 = 0 + /// This is equivalent to `R_AARCH64_LD64_GOT_LO12_NC` (312) in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#static-aarch64-relocations) + Aarch64Ld64GotLo12Nc, + + /// RISC-V Call PLT: 32-bit PC-relative function call, macros call, tail (PIC) + /// + /// Despite having PLT in the name, this relocation is also used for normal calls. + /// The non-PLT version of this relocation has been deprecated. + /// + /// This is the `R_RISCV_CALL_PLT` relocation from the RISC-V ELF psABI document. + /// + RiscvCallPlt, + + /// RISC-V TLS GD: High 20 bits of 32-bit PC-relative TLS GD GOT reference, + /// + /// This is the `R_RISCV_TLS_GD_HI20` relocation from the RISC-V ELF psABI document. + /// + RiscvTlsGdHi20, + + /// Low 12 bits of a 32-bit PC-relative relocation (I-Type instruction) + /// + /// This is the `R_RISCV_PCREL_LO12_I` relocation from the RISC-V ELF psABI document. + /// + RiscvPCRelLo12I, + + /// High 20 bits of a 32-bit PC-relative GOT offset relocation + /// + /// This is the `R_RISCV_GOT_HI20` relocation from the RISC-V ELF psABI document. + /// + RiscvGotHi20, + + /// s390x TLS GD64 - 64-bit offset of tls_index for GD symbol in GOT + S390xTlsGd64, + /// s390x TLS GDCall - marker to enable optimization of TLS calls + S390xTlsGdCall, + + /// Pulley - call a host function indirectly where the embedder resolving + /// this relocation needs to fill the 8-bit immediate that's part of the + /// `call_indirect_host` opcode (an opaque identifier used by the host). + PulleyCallIndirectHost, +} + +impl fmt::Display for Reloc { + /// Display trait implementation drops the arch, since its used in contexts where the arch is + /// already unambiguous, e.g. clif syntax with isa specified. In other contexts, use Debug. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Abs4 => write!(f, "Abs4"), + Self::Abs8 => write!(f, "Abs8"), + Self::S390xPCRel32Dbl => write!(f, "PCRel32Dbl"), + Self::S390xPLTRel32Dbl => write!(f, "PLTRel32Dbl"), + Self::X86PCRel4 => write!(f, "PCRel4"), + Self::X86CallPCRel4 => write!(f, "CallPCRel4"), + Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"), + Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"), + Self::X86SecRel => write!(f, "SecRel"), + Self::Arm32Call | Self::Arm64Call => write!(f, "Call"), + Self::RiscvCallPlt => write!(f, "RiscvCallPlt"), + Self::RiscvTlsGdHi20 => write!(f, "RiscvTlsGdHi20"), + Self::RiscvGotHi20 => write!(f, "RiscvGotHi20"), + Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"), + Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), + Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), + Self::MachOAarch64TlsAdrPage21 => write!(f, "MachOAarch64TlsAdrPage21"), + Self::MachOAarch64TlsAdrPageOff12 => write!(f, "MachOAarch64TlsAdrPageOff12"), + Self::Aarch64TlsDescAdrPage21 => write!(f, "Aarch64TlsDescAdrPage21"), + Self::Aarch64TlsDescLd64Lo12 => write!(f, "Aarch64TlsDescLd64Lo12"), + Self::Aarch64TlsDescAddLo12 => write!(f, "Aarch64TlsDescAddLo12"), + Self::Aarch64TlsDescCall => write!(f, "Aarch64TlsDescCall"), + Self::Aarch64AdrGotPage21 => write!(f, "Aarch64AdrGotPage21"), + Self::Aarch64Ld64GotLo12Nc => write!(f, "Aarch64AdrGotLo12Nc"), + Self::S390xTlsGd64 => write!(f, "TlsGd64"), + Self::S390xTlsGdCall => write!(f, "TlsGdCall"), + Self::PulleyCallIndirectHost => write!(f, "PulleyCallIndirectHost"), + } + } +} + +/// Container for information about a vector of compiled code and its supporting read-only data. +/// +/// The code starts at offset 0 and is followed optionally by relocatable jump tables and copyable +/// (raw binary) read-only data. Any padding between sections is always part of the section that +/// precedes the boundary between the sections. +#[derive(Debug, PartialEq)] +pub struct CodeInfo { + /// Number of bytes in total. + pub total_size: CodeOffset, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/cfg_printer.rs b/deps/crates/vendor/cranelift-codegen/src/cfg_printer.rs new file mode 100644 index 00000000000000..ef71b63ca71286 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/cfg_printer.rs @@ -0,0 +1,83 @@ +//! The `CFGPrinter` utility. + +use alloc::vec::Vec; +use core::fmt::{Display, Formatter, Result, Write}; + +use crate::entity::SecondaryMap; +use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; +use crate::ir::Function; +use crate::write::{FuncWriter, PlainWriter}; + +/// A utility for pretty-printing the CFG of a `Function`. +pub struct CFGPrinter<'a> { + func: &'a Function, + cfg: ControlFlowGraph, +} + +/// A utility for pretty-printing the CFG of a `Function`. +impl<'a> CFGPrinter<'a> { + /// Create a new CFGPrinter. + pub fn new(func: &'a Function) -> Self { + Self { + func, + cfg: ControlFlowGraph::with_function(func), + } + } + + /// Write the CFG for this function to `w`. + pub fn write(&self, w: &mut dyn Write) -> Result { + self.header(w)?; + self.block_nodes(w)?; + self.cfg_connections(w)?; + writeln!(w, "}}") + } + + fn header(&self, w: &mut dyn Write) -> Result { + writeln!(w, "digraph \"{}\" {{", self.func.name)?; + if let Some(entry) = self.func.layout.entry_block() { + writeln!(w, " {{rank=min; {entry}}}")?; + } + Ok(()) + } + + fn block_nodes(&self, w: &mut dyn Write) -> Result { + let mut aliases = SecondaryMap::<_, Vec<_>>::new(); + for v in self.func.dfg.values() { + // VADFS returns the immediate target of an alias + if let Some(k) = self.func.dfg.value_alias_dest_for_serialization(v) { + aliases[k].push(v); + } + } + + for block in &self.func.layout { + write!(w, " {block} [shape=record, label=\"{{")?; + crate::write::write_block_header(w, self.func, block, 4)?; + // Add all outgoing branch instructions to the label. + if let Some(inst) = self.func.layout.last_inst(block) { + write!(w, " | <{inst}>")?; + PlainWriter.write_instruction(w, self.func, &aliases, inst, 0)?; + } + writeln!(w, "}}\"]")? + } + Ok(()) + } + + fn cfg_connections(&self, w: &mut dyn Write) -> Result { + for block in &self.func.layout { + for BlockPredecessor { + block: parent, + inst, + } in self.cfg.pred_iter(block) + { + writeln!(w, " {parent}:{inst} -> {block}")?; + } + } + Ok(()) + } +} + +impl<'a> Display for CFGPrinter<'a> { + fn fmt(&self, f: &mut Formatter) -> Result { + self.write(f) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/constant_hash.rs b/deps/crates/vendor/cranelift-codegen/src/constant_hash.rs new file mode 100644 index 00000000000000..1de2a2edb43e42 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/constant_hash.rs @@ -0,0 +1,62 @@ +//! Runtime support for precomputed constant hash tables. +//! +//! The shared module with the same name can generate constant hash tables using open addressing +//! and quadratic probing. +//! +//! The hash tables are arrays that are guaranteed to: +//! +//! - Have a power-of-two size. +//! - Contain at least one empty slot. +//! +//! This module provides runtime support for lookups in these tables. + +// Re-export entities from constant_hash for simplicity of use. +pub use cranelift_codegen_shared::constant_hash::*; + +/// Trait that must be implemented by the entries in a constant hash table. +pub trait Table { + /// Get the number of entries in this table which must be a power of two. + fn len(&self) -> usize; + + /// Get the key corresponding to the entry at `idx`, or `None` if the entry is empty. + /// The `idx` must be in range. + fn key(&self, idx: usize) -> Option; +} + +/// Look for `key` in `table`. +/// +/// The provided `hash` value must have been computed from `key` using the same hash function that +/// was used to construct the table. +/// +/// Returns `Ok(idx)` with the table index containing the found entry, or `Err(idx)` with the empty +/// sentinel entry if no entry could be found. +pub fn probe + ?Sized>( + table: &T, + key: K, + hash: usize, +) -> Result { + debug_assert!(table.len().is_power_of_two()); + let mask = table.len() - 1; + + let mut idx = hash; + let mut step = 0; + + loop { + idx &= mask; + + match table.key(idx) { + None => return Err(idx), + Some(k) if k == key => return Ok(idx), + _ => {} + } + + // Quadratic probing. + step += 1; + + // When `table.len()` is a power of two, it can be proven that `idx` will visit all + // entries. This means that this loop will always terminate if the hash table has even + // one unused entry. + debug_assert!(step < table.len()); + idx += step; + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/context.rs b/deps/crates/vendor/cranelift-codegen/src/context.rs new file mode 100644 index 00000000000000..9cc7b7140d1ef4 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/context.rs @@ -0,0 +1,381 @@ +//! Cranelift compilation context and main entry point. +//! +//! When compiling many small functions, it is important to avoid repeatedly allocating and +//! deallocating the data structures needed for compilation. The `Context` struct is used to hold +//! on to memory allocations between function compilations. +//! +//! The context does not hold a `TargetIsa` instance which has to be provided as an argument +//! instead. This is because an ISA instance is immutable and can be used by multiple compilation +//! contexts concurrently. Typically, you would have one context per compilation thread and only a +//! single ISA instance. + +use crate::alias_analysis::AliasAnalysis; +use crate::dominator_tree::DominatorTree; +use crate::egraph::EgraphPass; +use crate::flowgraph::ControlFlowGraph; +use crate::ir::Function; +use crate::isa::TargetIsa; +use crate::legalizer::simple_legalize; +use crate::loop_analysis::LoopAnalysis; +use crate::machinst::{CompiledCode, CompiledCodeStencil}; +use crate::nan_canonicalization::do_nan_canonicalization; +use crate::remove_constant_phis::do_remove_constant_phis; +use crate::result::{CodegenResult, CompileResult}; +use crate::settings::{FlagsOrIsa, OptLevel}; +use crate::trace; +use crate::unreachable_code::eliminate_unreachable_code; +use crate::verifier::{verify_context, VerifierErrors, VerifierResult}; +use crate::{timing, CompileError}; +#[cfg(feature = "souper-harvest")] +use alloc::string::String; +use alloc::vec::Vec; +use cranelift_control::ControlPlane; +use target_lexicon::Architecture; + +#[cfg(feature = "souper-harvest")] +use crate::souper_harvest::do_souper_harvest; + +/// Persistent data structures and compilation pipeline. +pub struct Context { + /// The function we're compiling. + pub func: Function, + + /// The control flow graph of `func`. + pub cfg: ControlFlowGraph, + + /// Dominator tree for `func`. + pub domtree: DominatorTree, + + /// Loop analysis of `func`. + pub loop_analysis: LoopAnalysis, + + /// Result of MachBackend compilation, if computed. + pub(crate) compiled_code: Option, + + /// Flag: do we want a disassembly with the CompiledCode? + pub want_disasm: bool, +} + +impl Context { + /// Allocate a new compilation context. + /// + /// The returned instance should be reused for compiling multiple functions in order to avoid + /// needless allocator thrashing. + pub fn new() -> Self { + Self::for_function(Function::new()) + } + + /// Allocate a new compilation context with an existing Function. + /// + /// The returned instance should be reused for compiling multiple functions in order to avoid + /// needless allocator thrashing. + pub fn for_function(func: Function) -> Self { + Self { + func, + cfg: ControlFlowGraph::new(), + domtree: DominatorTree::new(), + loop_analysis: LoopAnalysis::new(), + compiled_code: None, + want_disasm: false, + } + } + + /// Clear all data structures in this context. + pub fn clear(&mut self) { + self.func.clear(); + self.cfg.clear(); + self.domtree.clear(); + self.loop_analysis.clear(); + self.compiled_code = None; + self.want_disasm = false; + } + + /// Returns the compilation result for this function, available after any `compile` function + /// has been called. + pub fn compiled_code(&self) -> Option<&CompiledCode> { + self.compiled_code.as_ref() + } + + /// Returns the compilation result for this function, available after any `compile` function + /// has been called. + pub fn take_compiled_code(&mut self) -> Option { + self.compiled_code.take() + } + + /// Set the flag to request a disassembly when compiling with a + /// `MachBackend` backend. + pub fn set_disasm(&mut self, val: bool) { + self.want_disasm = val; + } + + /// Compile the function, and emit machine code into a `Vec`. + #[deprecated = "use Context::compile"] + pub fn compile_and_emit( + &mut self, + isa: &dyn TargetIsa, + mem: &mut Vec, + ctrl_plane: &mut ControlPlane, + ) -> CompileResult<&CompiledCode> { + let compiled_code = self.compile(isa, ctrl_plane)?; + mem.extend_from_slice(compiled_code.code_buffer()); + Ok(compiled_code) + } + + /// Internally compiles the function into a stencil. + /// + /// Public only for testing and fuzzing purposes. + pub fn compile_stencil( + &mut self, + isa: &dyn TargetIsa, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult { + let _tt = timing::compile(); + + self.verify_if(isa)?; + + self.optimize(isa, ctrl_plane)?; + + isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane) + } + + /// Optimize the function, performing all compilation steps up to + /// but not including machine-code lowering and register + /// allocation. + /// + /// Public only for testing purposes. + pub fn optimize( + &mut self, + isa: &dyn TargetIsa, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<()> { + log::debug!( + "Number of CLIF instructions to optimize: {}", + self.func.dfg.num_insts() + ); + log::debug!( + "Number of CLIF blocks to optimize: {}", + self.func.dfg.num_blocks() + ); + + let opt_level = isa.flags().opt_level(); + crate::trace!( + "Optimizing (opt level {:?}):\n{}", + opt_level, + self.func.display() + ); + + self.compute_cfg(); + if isa.flags().enable_nan_canonicalization() { + self.canonicalize_nans(isa)?; + } + + self.legalize(isa)?; + + self.compute_domtree(); + self.eliminate_unreachable_code(isa)?; + self.remove_constant_phis(isa)?; + + self.func.dfg.resolve_all_aliases(); + + if opt_level != OptLevel::None { + self.egraph_pass(isa, ctrl_plane)?; + } + + Ok(()) + } + + /// Compile the function, + /// + /// Run the function through all the passes necessary to generate + /// code for the target ISA represented by `isa`. The generated + /// machine code is not relocated. Instead, any relocations can be + /// obtained from `compiled_code.buffer.relocs()`. + /// + /// Performs any optimizations that are enabled, unless + /// `optimize()` was already invoked. + /// + /// Returns the generated machine code as well as information about + /// the function's code and read-only data. + pub fn compile( + &mut self, + isa: &dyn TargetIsa, + ctrl_plane: &mut ControlPlane, + ) -> CompileResult<&CompiledCode> { + let stencil = self + .compile_stencil(isa, ctrl_plane) + .map_err(|error| CompileError { + inner: error, + func: &self.func, + })?; + Ok(self + .compiled_code + .insert(stencil.apply_params(&self.func.params))) + } + + /// If available, return information about the code layout in the + /// final machine code: the offsets (in bytes) of each basic-block + /// start, and all basic-block edges. + #[deprecated = "use CompiledCode::get_code_bb_layout"] + pub fn get_code_bb_layout(&self) -> Option<(Vec, Vec<(usize, usize)>)> { + self.compiled_code().map(CompiledCode::get_code_bb_layout) + } + + /// Creates unwind information for the function. + /// + /// Returns `None` if the function has no unwind information. + #[cfg(feature = "unwind")] + #[deprecated = "use CompiledCode::create_unwind_info"] + pub fn create_unwind_info( + &self, + isa: &dyn TargetIsa, + ) -> CodegenResult> { + self.compiled_code().unwrap().create_unwind_info(isa) + } + + /// Run the verifier on the function. + /// + /// Also check that the dominator tree and control flow graph are consistent with the function. + /// + /// TODO: rename to "CLIF validate" or similar. + pub fn verify<'a, FOI: Into>>(&self, fisa: FOI) -> VerifierResult<()> { + let mut errors = VerifierErrors::default(); + let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + /// Run the verifier only if the `enable_verifier` setting is true. + pub fn verify_if<'a, FOI: Into>>(&self, fisa: FOI) -> CodegenResult<()> { + let fisa = fisa.into(); + if fisa.flags.enable_verifier() { + self.verify(fisa)?; + } + Ok(()) + } + + /// Perform constant-phi removal on the function. + pub fn remove_constant_phis<'a, FOI: Into>>( + &mut self, + fisa: FOI, + ) -> CodegenResult<()> { + do_remove_constant_phis(&mut self.func, &mut self.domtree); + self.verify_if(fisa)?; + Ok(()) + } + + /// Perform NaN canonicalizing rewrites on the function. + pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { + // Currently only RiscV64 is the only arch that may not have vector support. + let has_vector_support = match isa.triple().architecture { + Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") { + Some(value) => value.as_bool().unwrap_or(false), + None => false, + }, + _ => true, + }; + do_nan_canonicalization(&mut self.func, has_vector_support); + self.verify_if(isa) + } + + /// Run the legalizer for `isa` on the function. + pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { + // Legalization invalidates the domtree and loop_analysis by mutating the CFG. + // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. + self.domtree.clear(); + self.loop_analysis.clear(); + + // Run some specific legalizations only. + simple_legalize(&mut self.func, isa); + self.verify_if(isa) + } + + /// Compute the control flow graph. + pub fn compute_cfg(&mut self) { + self.cfg.compute(&self.func) + } + + /// Compute dominator tree. + pub fn compute_domtree(&mut self) { + self.domtree.compute(&self.func, &self.cfg) + } + + /// Compute the loop analysis. + pub fn compute_loop_analysis(&mut self) { + self.loop_analysis + .compute(&self.func, &self.cfg, &self.domtree) + } + + /// Compute the control flow graph and dominator tree. + pub fn flowgraph(&mut self) { + self.compute_cfg(); + self.compute_domtree() + } + + /// Perform unreachable code elimination. + pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> + where + FOI: Into>, + { + eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); + self.verify_if(fisa) + } + + /// Replace all redundant loads with the known values in + /// memory. These are loads whose values were already loaded by + /// other loads earlier, as well as loads whose values were stored + /// by a store instruction to the same instruction (so-called + /// "store-to-load forwarding"). + pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> { + let mut analysis = AliasAnalysis::new(&self.func, &self.domtree); + analysis.compute_and_update_aliases(&mut self.func); + Ok(()) + } + + /// Harvest candidate left-hand sides for superoptimization with Souper. + #[cfg(feature = "souper-harvest")] + pub fn souper_harvest( + &mut self, + out: &mut std::sync::mpsc::Sender, + ) -> CodegenResult<()> { + do_souper_harvest(&self.func, out); + Ok(()) + } + + /// Run optimizations via the egraph infrastructure. + pub fn egraph_pass<'a, FOI>( + &mut self, + fisa: FOI, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<()> + where + FOI: Into>, + { + let _tt = timing::egraph(); + + trace!( + "About to optimize with egraph phase:\n{}", + self.func.display() + ); + let fisa = fisa.into(); + self.compute_loop_analysis(); + let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree); + let mut pass = EgraphPass::new( + &mut self.func, + &self.domtree, + &self.loop_analysis, + &mut alias_analysis, + &fisa.flags, + ctrl_plane, + ); + pass.run(); + log::debug!("egraph stats: {:?}", pass.stats); + trace!("pinned_union_count: {}", pass.eclasses.pinned_union_count); + trace!("After egraph optimization:\n{}", self.func.display()); + + self.verify_if(fisa) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ctxhash.rs b/deps/crates/vendor/cranelift-codegen/src/ctxhash.rs new file mode 100644 index 00000000000000..74290877bbcfb6 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ctxhash.rs @@ -0,0 +1,167 @@ +//! A hashmap with "external hashing": nodes are hashed or compared for +//! equality only with some external context provided on lookup/insert. +//! This allows very memory-efficient data structures where +//! node-internal data references some other storage (e.g., offsets into +//! an array or pool of shared data). + +use hashbrown::raw::RawTable; +use std::hash::{Hash, Hasher}; + +/// Trait that allows for equality comparison given some external +/// context. +/// +/// Note that this trait is implemented by the *context*, rather than +/// the item type, for somewhat complex lifetime reasons (lack of GATs +/// to allow `for<'ctx> Ctx<'ctx>`-like associated types in traits on +/// the value type). +pub trait CtxEq { + /// Determine whether `a` and `b` are equal, given the context in + /// `self` and the union-find data structure `uf`. + fn ctx_eq(&self, a: &V1, b: &V2) -> bool; +} + +/// Trait that allows for hashing given some external context. +pub trait CtxHash: CtxEq { + /// Compute the hash of `value`, given the context in `self` and + /// the union-find data structure `uf`. + fn ctx_hash(&self, state: &mut H, value: &Value); +} + +/// A null-comparator context type for underlying value types that +/// already have `Eq` and `Hash`. +#[derive(Default)] +pub struct NullCtx; + +impl CtxEq for NullCtx { + fn ctx_eq(&self, a: &V, b: &V) -> bool { + a.eq(b) + } +} +impl CtxHash for NullCtx { + fn ctx_hash(&self, state: &mut H, value: &V) { + value.hash(state); + } +} + +/// A bucket in the hash table. +/// +/// Some performance-related design notes: we cache the hashcode for +/// speed, as this often buys a few percent speed in +/// interning-table-heavy workloads. We only keep the low 32 bits of +/// the hashcode, for memory efficiency: in common use, `K` and `V` +/// are often 32 bits also, and a 12-byte bucket is measurably better +/// than a 16-byte bucket. +struct BucketData { + hash: u32, + k: K, + v: V, +} + +/// A HashMap that takes external context for all operations. +pub struct CtxHashMap { + raw: RawTable>, +} + +impl CtxHashMap { + /// Create an empty hashmap with pre-allocated space for the given + /// capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +fn compute_hash(ctx: &Ctx, k: &K) -> u32 +where + Ctx: CtxHash, +{ + let mut hasher = rustc_hash::FxHasher::default(); + ctx.ctx_hash(&mut hasher, k); + hasher.finish() as u32 +} + +impl CtxHashMap { + /// Insert a new key-value pair, returning the old value associated + /// with this key (if any). + pub fn insert(&mut self, k: K, v: V, ctx: &Ctx) -> Option + where + Ctx: CtxEq + CtxHash, + { + let hash = compute_hash(ctx, &k); + match self.raw.find(hash as u64, |bucket| { + hash == bucket.hash && ctx.ctx_eq(&bucket.k, &k) + }) { + Some(bucket) => { + let data = unsafe { bucket.as_mut() }; + Some(std::mem::replace(&mut data.v, v)) + } + None => { + let data = BucketData { hash, k, v }; + self.raw + .insert_entry(hash as u64, data, |bucket| bucket.hash as u64); + None + } + } + } + + /// Look up a key, returning a borrow of the value if present. + pub fn get<'a, Q, Ctx>(&'a self, k: &Q, ctx: &Ctx) -> Option<&'a V> + where + Ctx: CtxEq + CtxHash + CtxHash, + { + let hash = compute_hash(ctx, k); + self.raw + .find(hash as u64, |bucket| { + hash == bucket.hash && ctx.ctx_eq(&bucket.k, k) + }) + .map(|bucket| { + let data = unsafe { bucket.as_ref() }; + &data.v + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[derive(Clone, Copy, Debug)] + struct Key { + index: u32, + } + struct Ctx { + vals: &'static [&'static str], + } + impl CtxEq for Ctx { + fn ctx_eq(&self, a: &Key, b: &Key) -> bool { + self.vals[a.index as usize].eq(self.vals[b.index as usize]) + } + } + impl CtxHash for Ctx { + fn ctx_hash(&self, state: &mut H, value: &Key) { + self.vals[value.index as usize].hash(state); + } + } + + #[test] + fn test_basic() { + let ctx = Ctx { + vals: &["a", "b", "a"], + }; + + let k0 = Key { index: 0 }; + let k1 = Key { index: 1 }; + let k2 = Key { index: 2 }; + + assert!(ctx.ctx_eq(&k0, &k2)); + assert!(!ctx.ctx_eq(&k0, &k1)); + assert!(!ctx.ctx_eq(&k2, &k1)); + + let mut map: CtxHashMap = CtxHashMap::with_capacity(4); + assert_eq!(map.insert(k0, 42, &ctx), None); + assert_eq!(map.insert(k2, 84, &ctx), Some(42)); + assert_eq!(map.get(&k1, &ctx), None); + assert_eq!(*map.get(&k0, &ctx).unwrap(), 84); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/cursor.rs b/deps/crates/vendor/cranelift-codegen/src/cursor.rs new file mode 100644 index 00000000000000..a0176e6296f500 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/cursor.rs @@ -0,0 +1,644 @@ +//! Cursor library. +//! +//! This module defines cursor data types that can be used for inserting instructions. + +use crate::ir; + +/// The possible positions of a cursor. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CursorPosition { + /// Cursor is not pointing anywhere. No instructions can be inserted. + Nowhere, + /// Cursor is pointing at an existing instruction. + /// New instructions will be inserted *before* the current instruction. + At(ir::Inst), + /// Cursor is before the beginning of a block. No instructions can be inserted. Calling + /// `next_inst()` will move to the first instruction in the block. + Before(ir::Block), + /// Cursor is pointing after the end of a block. + /// New instructions will be appended to the block. + After(ir::Block), +} + +/// All cursor types implement the `Cursor` which provides common navigation operations. +pub trait Cursor { + /// Get the current cursor position. + fn position(&self) -> CursorPosition; + + /// Set the current position. + fn set_position(&mut self, pos: CursorPosition); + + /// Get the source location that should be assigned to new instructions. + fn srcloc(&self) -> ir::SourceLoc; + + /// Set the source location that should be assigned to new instructions. + fn set_srcloc(&mut self, srcloc: ir::SourceLoc); + + /// Borrow a reference to the function layout that this cursor is navigating. + fn layout(&self) -> &ir::Layout; + + /// Borrow a mutable reference to the function layout that this cursor is navigating. + fn layout_mut(&mut self) -> &mut ir::Layout; + + /// Exchange this cursor for one with a set source location. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, SourceLoc}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, srcloc: SourceLoc) { + /// let mut pos = FuncCursor::new(func).with_srcloc(srcloc); + /// + /// // Use `pos`... + /// } + /// ``` + fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self + where + Self: Sized, + { + self.set_srcloc(srcloc); + self + } + + /// Rebuild this cursor positioned at `pos`. + fn at_position(mut self, pos: CursorPosition) -> Self + where + Self: Sized, + { + self.set_position(pos); + self + } + + /// Rebuild this cursor positioned at `inst`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, inst: Inst) { + /// let mut pos = FuncCursor::new(func).at_inst(inst); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_inst(mut self, inst: ir::Inst) -> Self + where + Self: Sized, + { + self.goto_inst(inst); + self + } + + /// Rebuild this cursor positioned at the first insertion point for `block`. + /// This differs from `at_first_inst` in that it doesn't assume that any + /// instructions have been inserted into `block` yet. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, block: Block) { + /// let mut pos = FuncCursor::new(func).at_first_insertion_point(block); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_first_insertion_point(mut self, block: ir::Block) -> Self + where + Self: Sized, + { + self.goto_first_insertion_point(block); + self + } + + /// Rebuild this cursor positioned at the first instruction in `block`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, block: Block) { + /// let mut pos = FuncCursor::new(func).at_first_inst(block); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_first_inst(mut self, block: ir::Block) -> Self + where + Self: Sized, + { + self.goto_first_inst(block); + self + } + + /// Rebuild this cursor positioned at the last instruction in `block`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, block: Block) { + /// let mut pos = FuncCursor::new(func).at_last_inst(block); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_last_inst(mut self, block: ir::Block) -> Self + where + Self: Sized, + { + self.goto_last_inst(block); + self + } + + /// Rebuild this cursor positioned after `inst`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, inst: Inst) { + /// let mut pos = FuncCursor::new(func).after_inst(inst); + /// + /// // Use `pos`... + /// } + /// ``` + fn after_inst(mut self, inst: ir::Inst) -> Self + where + Self: Sized, + { + self.goto_after_inst(inst); + self + } + + /// Rebuild this cursor positioned at the top of `block`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, block: Block) { + /// let mut pos = FuncCursor::new(func).at_top(block); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_top(mut self, block: ir::Block) -> Self + where + Self: Sized, + { + self.goto_top(block); + self + } + + /// Rebuild this cursor positioned at the bottom of `block`. + /// + /// This is intended to be used as a builder method: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block, Inst}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function, block: Block) { + /// let mut pos = FuncCursor::new(func).at_bottom(block); + /// + /// // Use `pos`... + /// } + /// ``` + fn at_bottom(mut self, block: ir::Block) -> Self + where + Self: Sized, + { + self.goto_bottom(block); + self + } + + /// Get the block corresponding to the current position. + fn current_block(&self) -> Option { + use self::CursorPosition::*; + match self.position() { + Nowhere => None, + At(inst) => self.layout().inst_block(inst), + Before(block) | After(block) => Some(block), + } + } + + /// Get the instruction corresponding to the current position, if any. + fn current_inst(&self) -> Option { + use self::CursorPosition::*; + match self.position() { + At(inst) => Some(inst), + _ => None, + } + } + + /// Go to the position after a specific instruction, which must be inserted + /// in the layout. New instructions will be inserted after `inst`. + fn goto_after_inst(&mut self, inst: ir::Inst) { + debug_assert!(self.layout().inst_block(inst).is_some()); + let new_pos = if let Some(next) = self.layout().next_inst(inst) { + CursorPosition::At(next) + } else { + CursorPosition::After( + self.layout() + .inst_block(inst) + .expect("current instruction removed?"), + ) + }; + self.set_position(new_pos); + } + + /// Go to a specific instruction which must be inserted in the layout. + /// New instructions will be inserted before `inst`. + fn goto_inst(&mut self, inst: ir::Inst) { + debug_assert!(self.layout().inst_block(inst).is_some()); + self.set_position(CursorPosition::At(inst)); + } + + /// Go to the position for inserting instructions at the beginning of `block`, + /// which unlike `goto_first_inst` doesn't assume that any instructions have + /// been inserted into `block` yet. + fn goto_first_insertion_point(&mut self, block: ir::Block) { + if let Some(inst) = self.layout().first_inst(block) { + self.goto_inst(inst); + } else { + self.goto_bottom(block); + } + } + + /// Go to the first instruction in `block`. + fn goto_first_inst(&mut self, block: ir::Block) { + let inst = self.layout().first_inst(block).expect("Empty block"); + self.goto_inst(inst); + } + + /// Go to the last instruction in `block`. + fn goto_last_inst(&mut self, block: ir::Block) { + let inst = self.layout().last_inst(block).expect("Empty block"); + self.goto_inst(inst); + } + + /// Go to the top of `block` which must be inserted into the layout. + /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first + /// instruction in `block`. + fn goto_top(&mut self, block: ir::Block) { + debug_assert!(self.layout().is_block_inserted(block)); + self.set_position(CursorPosition::Before(block)); + } + + /// Go to the bottom of `block` which must be inserted into the layout. + /// At this position, inserted instructions will be appended to `block`. + fn goto_bottom(&mut self, block: ir::Block) { + debug_assert!(self.layout().is_block_inserted(block)); + self.set_position(CursorPosition::After(block)); + } + + /// Go to the top of the next block in layout order and return it. + /// + /// - If the cursor wasn't pointing at anything, go to the top of the first block in the + /// function. + /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. + /// + /// # Examples + /// + /// The `next_block()` method is intended for iterating over the blocks in layout order: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function) { + /// let mut cursor = FuncCursor::new(func); + /// while let Some(block) = cursor.next_block() { + /// // Edit block. + /// } + /// } + /// ``` + fn next_block(&mut self) -> Option { + let next = if let Some(block) = self.current_block() { + self.layout().next_block(block) + } else { + self.layout().entry_block() + }; + self.set_position(match next { + Some(block) => CursorPosition::Before(block), + None => CursorPosition::Nowhere, + }); + next + } + + /// Go to the bottom of the previous block in layout order and return it. + /// + /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the + /// function. + /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. + /// + /// # Examples + /// + /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function) { + /// let mut cursor = FuncCursor::new(func); + /// while let Some(block) = cursor.prev_block() { + /// // Edit block. + /// } + /// } + /// ``` + fn prev_block(&mut self) -> Option { + let prev = if let Some(block) = self.current_block() { + self.layout().prev_block(block) + } else { + self.layout().last_block() + }; + self.set_position(match prev { + Some(block) => CursorPosition::After(block), + None => CursorPosition::Nowhere, + }); + prev + } + + /// Move to the next instruction in the same block and return it. + /// + /// - If the cursor was positioned before a block, go to the first instruction in that block. + /// - If there are no more instructions in the block, go to the `After(block)` position and return + /// `None`. + /// - If the cursor wasn't pointing anywhere, keep doing that. + /// + /// This method will never move the cursor to a different block. + /// + /// # Examples + /// + /// The `next_inst()` method is intended for iterating over the instructions in a block like + /// this: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_block(func: &mut Function, block: Block) { + /// let mut cursor = FuncCursor::new(func).at_top(block); + /// while let Some(inst) = cursor.next_inst() { + /// // Edit instructions... + /// } + /// } + /// ``` + /// The loop body can insert and remove instructions via the cursor. + /// + /// Iterating over all the instructions in a function looks like this: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_func(func: &mut Function) { + /// let mut cursor = FuncCursor::new(func); + /// while let Some(block) = cursor.next_block() { + /// while let Some(inst) = cursor.next_inst() { + /// // Edit instructions... + /// } + /// } + /// } + /// ``` + fn next_inst(&mut self) -> Option { + use self::CursorPosition::*; + match self.position() { + Nowhere | After(..) => None, + At(inst) => { + if let Some(next) = self.layout().next_inst(inst) { + self.set_position(At(next)); + Some(next) + } else { + let pos = After( + self.layout() + .inst_block(inst) + .expect("current instruction removed?"), + ); + self.set_position(pos); + None + } + } + Before(block) => { + if let Some(next) = self.layout().first_inst(block) { + self.set_position(At(next)); + Some(next) + } else { + self.set_position(After(block)); + None + } + } + } + } + + /// Move to the previous instruction in the same block and return it. + /// + /// - If the cursor was positioned after a block, go to the last instruction in that block. + /// - If there are no more instructions in the block, go to the `Before(block)` position and return + /// `None`. + /// - If the cursor wasn't pointing anywhere, keep doing that. + /// + /// This method will never move the cursor to a different block. + /// + /// # Examples + /// + /// The `prev_inst()` method is intended for iterating backwards over the instructions in an + /// block like this: + /// + /// ``` + /// # use cranelift_codegen::ir::{Function, Block}; + /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; + /// fn edit_block(func: &mut Function, block: Block) { + /// let mut cursor = FuncCursor::new(func).at_bottom(block); + /// while let Some(inst) = cursor.prev_inst() { + /// // Edit instructions... + /// } + /// } + /// ``` + fn prev_inst(&mut self) -> Option { + use self::CursorPosition::*; + match self.position() { + Nowhere | Before(..) => None, + At(inst) => { + if let Some(prev) = self.layout().prev_inst(inst) { + self.set_position(At(prev)); + Some(prev) + } else { + let pos = Before( + self.layout() + .inst_block(inst) + .expect("current instruction removed?"), + ); + self.set_position(pos); + None + } + } + After(block) => { + if let Some(prev) = self.layout().last_inst(block) { + self.set_position(At(prev)); + Some(prev) + } else { + self.set_position(Before(block)); + None + } + } + } + } + + /// Insert an instruction at the current position. + /// + /// - If pointing at an instruction, the new instruction is inserted before the current + /// instruction. + /// - If pointing at the bottom of a block, the new instruction is appended to the block. + /// - Otherwise panic. + /// + /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes + /// instructions to appear in insertion order in the block. + fn insert_inst(&mut self, inst: ir::Inst) { + use self::CursorPosition::*; + match self.position() { + Nowhere | Before(..) => panic!("Invalid insert_inst position"), + At(cur) => self.layout_mut().insert_inst(inst, cur), + After(block) => self.layout_mut().append_inst(inst, block), + } + } + + /// Remove the instruction under the cursor. + /// + /// The cursor is left pointing at the position following the current instruction. + /// + /// Return the instruction that was removed. + fn remove_inst(&mut self) -> ir::Inst { + let inst = self.current_inst().expect("No instruction to remove"); + self.next_inst(); + self.layout_mut().remove_inst(inst); + inst + } + + /// Remove the instruction under the cursor. + /// + /// The cursor is left pointing at the position preceding the current instruction. + /// + /// Return the instruction that was removed. + fn remove_inst_and_step_back(&mut self) -> ir::Inst { + let inst = self.current_inst().expect("No instruction to remove"); + self.prev_inst(); + self.layout_mut().remove_inst(inst); + inst + } + + /// Insert a block at the current position and switch to it. + /// + /// As far as possible, this method behaves as if the block header were an instruction inserted + /// at the current position. + /// + /// - If the cursor is pointing at an existing instruction, *the current block is split in two* + /// and the current instruction becomes the first instruction in the inserted block. + /// - If the cursor points at the bottom of a block, the new block is inserted after the current + /// one, and moved to the bottom of the new block where instructions can be appended. + /// - If the cursor points to the top of a block, the new block is inserted above the current one. + /// - If the cursor is not pointing at anything, the new block is placed last in the layout. + /// + /// This means that it is always valid to call this method, and it always leaves the cursor in + /// a state that will insert instructions into the new block. + fn insert_block(&mut self, new_block: ir::Block) { + use self::CursorPosition::*; + match self.position() { + At(inst) => { + self.layout_mut().split_block(new_block, inst); + // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`. + return; + } + Nowhere => self.layout_mut().append_block(new_block), + Before(block) => self.layout_mut().insert_block(new_block, block), + After(block) => self.layout_mut().insert_block_after(new_block, block), + } + // For everything but `At(inst)` we end up appending to the new block. + self.set_position(After(new_block)); + } +} + +/// Function cursor. +/// +/// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position +/// too. The function can be re-borrowed by accessing the public `cur.func` member. +/// +/// This cursor is for use before legalization. The inserted instructions are not given an +/// encoding. +pub struct FuncCursor<'f> { + pos: CursorPosition, + srcloc: ir::SourceLoc, + + /// The referenced function. + pub func: &'f mut ir::Function, +} + +impl<'f> FuncCursor<'f> { + /// Create a new `FuncCursor` pointing nowhere. + pub fn new(func: &'f mut ir::Function) -> Self { + Self { + pos: CursorPosition::Nowhere, + srcloc: Default::default(), + func, + } + } + + /// Use the source location of `inst` for future instructions. + pub fn use_srcloc(&mut self, inst: ir::Inst) { + self.srcloc = self.func.srcloc(inst); + } + + /// Create an instruction builder that inserts an instruction at the current position. + pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> { + ir::InsertBuilder::new(self) + } +} + +impl<'f> Cursor for FuncCursor<'f> { + fn position(&self) -> CursorPosition { + self.pos + } + + fn set_position(&mut self, pos: CursorPosition) { + self.pos = pos + } + + fn srcloc(&self) -> ir::SourceLoc { + self.srcloc + } + + fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { + self.func.params.ensure_base_srcloc(srcloc); + self.srcloc = srcloc; + } + + fn layout(&self) -> &ir::Layout { + &self.func.layout + } + + fn layout_mut(&mut self) -> &mut ir::Layout { + &mut self.func.layout + } +} + +impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> { + fn data_flow_graph(&self) -> &ir::DataFlowGraph { + &self.func.dfg + } + + fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { + &mut self.func.dfg + } + + fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph { + self.insert_inst(inst); + if !self.srcloc.is_default() { + self.func.set_srcloc(inst, self.srcloc); + } + &mut self.func.dfg + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/data_value.rs b/deps/crates/vendor/cranelift-codegen/src/data_value.rs new file mode 100644 index 00000000000000..523182f07d9eec --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/data_value.rs @@ -0,0 +1,402 @@ +//! This module gives users to instantiate values that Cranelift understands. These values are used, +//! for example, during interpretation and for wrapping immediates. +use crate::ir::immediates::{Ieee128, Ieee16, Ieee32, Ieee64, Offset32}; +use crate::ir::{types, ConstantData, Type}; +use core::cmp::Ordering; +use core::fmt::{self, Display, Formatter}; + +/// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value +/// that would be referred to by a [Value]. +/// +/// [Value]: crate::ir::Value +#[allow(missing_docs)] +#[derive(Clone, Debug, PartialOrd)] +pub enum DataValue { + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + F16(Ieee16), + F32(Ieee32), + F64(Ieee64), + F128(Ieee128), + V128([u8; 16]), + V64([u8; 8]), +} + +impl PartialEq for DataValue { + fn eq(&self, other: &Self) -> bool { + use DataValue::*; + match (self, other) { + (I8(l), I8(r)) => l == r, + (I8(_), _) => false, + (I16(l), I16(r)) => l == r, + (I16(_), _) => false, + (I32(l), I32(r)) => l == r, + (I32(_), _) => false, + (I64(l), I64(r)) => l == r, + (I64(_), _) => false, + (I128(l), I128(r)) => l == r, + (I128(_), _) => false, + (F16(l), F16(r)) => l.partial_cmp(&r) == Some(Ordering::Equal), + (F16(_), _) => false, + (F32(l), F32(r)) => l.as_f32() == r.as_f32(), + (F32(_), _) => false, + (F64(l), F64(r)) => l.as_f64() == r.as_f64(), + (F64(_), _) => false, + (F128(l), F128(r)) => l.partial_cmp(&r) == Some(Ordering::Equal), + (F128(_), _) => false, + (V128(l), V128(r)) => l == r, + (V128(_), _) => false, + (V64(l), V64(r)) => l == r, + (V64(_), _) => false, + } + } +} + +impl DataValue { + /// Try to cast an immediate integer (a wrapped `i64` on most Cranelift instructions) to the + /// given Cranelift [Type]. + pub fn from_integer(imm: i128, ty: Type) -> Result { + match ty { + types::I8 => Ok(DataValue::I8(imm as i8)), + types::I16 => Ok(DataValue::I16(imm as i16)), + types::I32 => Ok(DataValue::I32(imm as i32)), + types::I64 => Ok(DataValue::I64(imm as i64)), + types::I128 => Ok(DataValue::I128(imm)), + _ => Err(DataValueCastFailure::FromInteger(imm, ty)), + } + } + + /// Return the Cranelift IR [Type] for this [DataValue]. + pub fn ty(&self) -> Type { + match self { + DataValue::I8(_) => types::I8, + DataValue::I16(_) => types::I16, + DataValue::I32(_) => types::I32, + DataValue::I64(_) => types::I64, + DataValue::I128(_) => types::I128, + DataValue::F16(_) => types::F16, + DataValue::F32(_) => types::F32, + DataValue::F64(_) => types::F64, + DataValue::F128(_) => types::F128, + DataValue::V128(_) => types::I8X16, // A default type. + DataValue::V64(_) => types::I8X8, // A default type. + } + } + + /// Return true if the value is a vector (i.e. `DataValue::V128`). + pub fn is_vector(&self) -> bool { + match self { + DataValue::V128(_) | DataValue::V64(_) => true, + _ => false, + } + } + + fn swap_bytes(self) -> Self { + match self { + DataValue::I8(i) => DataValue::I8(i.swap_bytes()), + DataValue::I16(i) => DataValue::I16(i.swap_bytes()), + DataValue::I32(i) => DataValue::I32(i.swap_bytes()), + DataValue::I64(i) => DataValue::I64(i.swap_bytes()), + DataValue::I128(i) => DataValue::I128(i.swap_bytes()), + DataValue::F16(f) => DataValue::F16(Ieee16::with_bits(f.bits().swap_bytes())), + DataValue::F32(f) => DataValue::F32(Ieee32::with_bits(f.bits().swap_bytes())), + DataValue::F64(f) => DataValue::F64(Ieee64::with_bits(f.bits().swap_bytes())), + DataValue::F128(f) => DataValue::F128(Ieee128::with_bits(f.bits().swap_bytes())), + DataValue::V128(mut v) => { + v.reverse(); + DataValue::V128(v) + } + DataValue::V64(mut v) => { + v.reverse(); + DataValue::V64(v) + } + } + } + + /// Converts `self` to big endian from target's endianness. + pub fn to_be(self) -> Self { + if cfg!(target_endian = "big") { + self + } else { + self.swap_bytes() + } + } + + /// Converts `self` to little endian from target's endianness. + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { + self + } else { + self.swap_bytes() + } + } + + /// Write a [DataValue] to a slice in native-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn write_to_slice_ne(&self, dst: &mut [u8]) { + match self { + DataValue::I8(i) => dst[..1].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::I16(i) => dst[..2].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::I32(i) => dst[..4].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::I64(i) => dst[..8].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::I128(i) => dst[..16].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::F16(f) => dst[..2].copy_from_slice(&f.bits().to_ne_bytes()[..]), + DataValue::F32(f) => dst[..4].copy_from_slice(&f.bits().to_ne_bytes()[..]), + DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]), + DataValue::F128(f) => dst[..16].copy_from_slice(&f.bits().to_ne_bytes()[..]), + DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]), + DataValue::V64(v) => dst[..8].copy_from_slice(&v[..]), + }; + } + + /// Write a [DataValue] to a slice in big-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn write_to_slice_be(&self, dst: &mut [u8]) { + self.clone().to_be().write_to_slice_ne(dst); + } + + /// Write a [DataValue] to a slice in little-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn write_to_slice_le(&self, dst: &mut [u8]) { + self.clone().to_le().write_to_slice_ne(dst); + } + + /// Read a [DataValue] from a slice using a given [Type] with native-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn read_from_slice_ne(src: &[u8], ty: Type) -> Self { + match ty { + types::I8 => DataValue::I8(i8::from_ne_bytes(src[..1].try_into().unwrap())), + types::I16 => DataValue::I16(i16::from_ne_bytes(src[..2].try_into().unwrap())), + types::I32 => DataValue::I32(i32::from_ne_bytes(src[..4].try_into().unwrap())), + types::I64 => DataValue::I64(i64::from_ne_bytes(src[..8].try_into().unwrap())), + types::I128 => DataValue::I128(i128::from_ne_bytes(src[..16].try_into().unwrap())), + types::F16 => DataValue::F16(Ieee16::with_bits(u16::from_ne_bytes( + src[..2].try_into().unwrap(), + ))), + types::F32 => DataValue::F32(Ieee32::with_bits(u32::from_ne_bytes( + src[..4].try_into().unwrap(), + ))), + types::F64 => DataValue::F64(Ieee64::with_bits(u64::from_ne_bytes( + src[..8].try_into().unwrap(), + ))), + types::F128 => DataValue::F128(Ieee128::with_bits(u128::from_ne_bytes( + src[..16].try_into().unwrap(), + ))), + _ if ty.is_vector() => { + if ty.bytes() == 16 { + DataValue::V128(src[..16].try_into().unwrap()) + } else if ty.bytes() == 8 { + DataValue::V64(src[..8].try_into().unwrap()) + } else { + unimplemented!() + } + } + _ => unimplemented!(), + } + } + + /// Read a [DataValue] from a slice using a given [Type] in big-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn read_from_slice_be(src: &[u8], ty: Type) -> Self { + DataValue::read_from_slice_ne(src, ty).to_be() + } + + /// Read a [DataValue] from a slice using a given [Type] in little-endian byte order. + /// + /// # Panics: + /// + /// Panics if the slice does not have enough space to accommodate the [DataValue] + pub fn read_from_slice_le(src: &[u8], ty: Type) -> Self { + DataValue::read_from_slice_ne(src, ty).to_le() + } + + /// Write a [DataValue] to a memory location in native-endian byte order. + pub unsafe fn write_value_to(&self, p: *mut u128) { + let size = self.ty().bytes() as usize; + self.write_to_slice_ne(std::slice::from_raw_parts_mut(p as *mut u8, size)); + } + + /// Read a [DataValue] from a memory location using a given [Type] in native-endian byte order. + pub unsafe fn read_value_from(p: *const u128, ty: Type) -> Self { + DataValue::read_from_slice_ne( + std::slice::from_raw_parts(p as *const u8, ty.bytes() as usize), + ty, + ) + } + + /// Performs a bitwise comparison over the contents of [DataValue]. + /// + /// Returns true if all bits are equal. + /// + /// This behaviour is different from PartialEq for NaN floats. + pub fn bitwise_eq(&self, other: &DataValue) -> bool { + match (self, other) { + // We need to bit compare the floats to ensure that we produce the correct values + // on NaN's. The test suite expects to assert the precise bit pattern on NaN's or + // works around it in the tests themselves. + (DataValue::F16(a), DataValue::F16(b)) => a.bits() == b.bits(), + (DataValue::F32(a), DataValue::F32(b)) => a.bits() == b.bits(), + (DataValue::F64(a), DataValue::F64(b)) => a.bits() == b.bits(), + (DataValue::F128(a), DataValue::F128(b)) => a.bits() == b.bits(), + + // We don't need to worry about F32x4 / F64x2 Since we compare V128 which is already the + // raw bytes anyway + (a, b) => a == b, + } + } +} + +/// Record failures to cast [DataValue]. +#[derive(Debug, PartialEq)] +#[allow(missing_docs)] +pub enum DataValueCastFailure { + TryInto(Type, Type), + FromInteger(i128, Type), +} + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for DataValueCastFailure {} + +impl Display for DataValueCastFailure { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + DataValueCastFailure::TryInto(from, to) => { + write!(f, "unable to cast data value of type {from} to type {to}") + } + DataValueCastFailure::FromInteger(val, to) => { + write!(f, "unable to cast i64({val}) to a data value of type {to}") + } + } + } +} + +/// Helper for creating conversion implementations for [DataValue]. +macro_rules! build_conversion_impl { + ( $rust_ty:ty, $data_value_ty:ident, $cranelift_ty:ident ) => { + impl From<$rust_ty> for DataValue { + fn from(data: $rust_ty) -> Self { + DataValue::$data_value_ty(data) + } + } + + impl TryInto<$rust_ty> for DataValue { + type Error = DataValueCastFailure; + fn try_into(self) -> Result<$rust_ty, Self::Error> { + if let DataValue::$data_value_ty(v) = self { + Ok(v) + } else { + Err(DataValueCastFailure::TryInto( + self.ty(), + types::$cranelift_ty, + )) + } + } + } + }; +} +build_conversion_impl!(i8, I8, I8); +build_conversion_impl!(i16, I16, I16); +build_conversion_impl!(i32, I32, I32); +build_conversion_impl!(i64, I64, I64); +build_conversion_impl!(i128, I128, I128); +build_conversion_impl!(Ieee16, F16, F16); +build_conversion_impl!(Ieee32, F32, F32); +build_conversion_impl!(Ieee64, F64, F64); +build_conversion_impl!(Ieee128, F128, F128); +build_conversion_impl!([u8; 16], V128, I8X16); +build_conversion_impl!([u8; 8], V64, I8X8); +impl From for DataValue { + fn from(o: Offset32) -> Self { + DataValue::from(Into::::into(o)) + } +} + +impl Display for DataValue { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + DataValue::I8(dv) => write!(f, "{dv}"), + DataValue::I16(dv) => write!(f, "{dv}"), + DataValue::I32(dv) => write!(f, "{dv}"), + DataValue::I64(dv) => write!(f, "{dv}"), + DataValue::I128(dv) => write!(f, "{dv}"), + // The Ieee* wrappers here print the expected syntax. + DataValue::F16(dv) => write!(f, "{dv}"), + DataValue::F32(dv) => write!(f, "{dv}"), + DataValue::F64(dv) => write!(f, "{dv}"), + DataValue::F128(dv) => write!(f, "{dv}"), + // Again, for syntax consistency, use ConstantData, which in this case displays as hex. + DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])), + DataValue::V64(dv) => write!(f, "{}", ConstantData::from(&dv[..])), + } + } +} + +/// Helper structure for printing bracket-enclosed vectors of [DataValue]s. +/// - for empty vectors, display `[]` +/// - for single item vectors, display `42`, e.g. +/// - for multiple item vectors, display `[42, 43, 44]`, e.g. +pub struct DisplayDataValues<'a>(pub &'a [DataValue]); + +impl<'a> Display for DisplayDataValues<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if self.0.len() == 1 { + write!(f, "{}", self.0[0]) + } else { + write!(f, "[")?; + write_data_value_list(f, &self.0)?; + write!(f, "]") + } + } +} + +/// Helper function for displaying `Vec`. +pub fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result { + match list.len() { + 0 => Ok(()), + 1 => write!(f, "{}", list[0]), + _ => { + write!(f, "{}", list[0])?; + for dv in list.iter().skip(1) { + write!(f, ", {dv}")?; + } + Ok(()) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn type_conversions() { + assert_eq!(DataValue::V128([0; 16]).ty(), types::I8X16); + assert_eq!( + TryInto::<[u8; 16]>::try_into(DataValue::V128([0; 16])).unwrap(), + [0; 16] + ); + assert_eq!( + TryInto::::try_into(DataValue::V128([0; 16])).unwrap_err(), + DataValueCastFailure::TryInto(types::I8X16, types::I32) + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/dbg.rs b/deps/crates/vendor/cranelift-codegen/src/dbg.rs new file mode 100644 index 00000000000000..4796f3967b91cc --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/dbg.rs @@ -0,0 +1,28 @@ +//! Debug tracing helpers. +use core::fmt; + +/// Prefix added to the log file names, just before the thread name or id. +pub static LOG_FILENAME_PREFIX: &str = "cranelift.dbg."; + +/// Helper for printing lists. +pub struct DisplayList<'a, T>(pub &'a [T]) +where + T: 'a + fmt::Display; + +impl<'a, T> fmt::Display for DisplayList<'a, T> +where + T: 'a + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0.split_first() { + None => write!(f, "[]"), + Some((first, rest)) => { + write!(f, "[{first}")?; + for x in rest { + write!(f, ", {x}")?; + } + write!(f, "]") + } + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/dominator_tree.rs b/deps/crates/vendor/cranelift-codegen/src/dominator_tree.rs new file mode 100644 index 00000000000000..03a0368028c68e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/dominator_tree.rs @@ -0,0 +1,752 @@ +//! A Dominator Tree represented as mappings of Blocks to their immediate dominator. + +use crate::entity::SecondaryMap; +use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; +use crate::ir::{Block, Function, Layout, ProgramPoint}; +use crate::packed_option::PackedOption; +use crate::timing; +use crate::traversals::Dfs; +use alloc::vec::Vec; +use core::cmp; +use core::cmp::Ordering; +use core::mem; + +/// RPO numbers are not first assigned in a contiguous way but as multiples of STRIDE, to leave +/// room for modifications of the dominator tree. +const STRIDE: u32 = 4; + +/// Dominator tree node. We keep one of these per block. +#[derive(Clone, Default)] +struct DomNode { + /// Number of this node in a reverse post-order traversal of the CFG, starting from 1. + /// This number is monotonic in the reverse postorder but not contiguous, since we leave + /// holes for later localized modifications of the dominator tree. + /// Unreachable nodes get number 0, all others are positive. + rpo_number: u32, + + /// The immediate dominator of this block. + /// + /// This is `None` for unreachable blocks and the entry block which doesn't have an immediate + /// dominator. + idom: PackedOption, +} + +/// The dominator tree for a single function. +pub struct DominatorTree { + nodes: SecondaryMap, + + /// CFG post-order of all reachable blocks. + postorder: Vec, + + /// Scratch traversal state used by `compute_postorder()`. + dfs: Dfs, + + valid: bool, +} + +/// Methods for querying the dominator tree. +impl DominatorTree { + /// Is `block` reachable from the entry block? + pub fn is_reachable(&self, block: Block) -> bool { + self.nodes[block].rpo_number != 0 + } + + /// Get the CFG post-order of blocks that was used to compute the dominator tree. + /// + /// Note that this post-order is not updated automatically when the CFG is modified. It is + /// computed from scratch and cached by `compute()`. + pub fn cfg_postorder(&self) -> &[Block] { + debug_assert!(self.is_valid()); + &self.postorder + } + + /// Get an iterator over CFG reverse post-order of blocks used to compute the dominator tree. + /// + /// Note that the post-order is not updated automatically when the CFG is modified. It is + /// computed from scratch and cached by `compute()`. + pub fn cfg_rpo(&self) -> impl Iterator { + debug_assert!(self.is_valid()); + self.postorder.iter().rev() + } + + /// Returns the immediate dominator of `block`. + /// + /// `block_a` is said to *dominate* `block_b` if all control flow paths from the function + /// entry to `block_b` must go through `block_a`. + /// + /// The *immediate dominator* is the dominator that is closest to `block`. All other dominators + /// also dominate the immediate dominator. + /// + /// This returns `None` if `block` is not reachable from the entry block, or if it is the entry block + /// which has no dominators. + pub fn idom(&self, block: Block) -> Option { + self.nodes[block].idom.into() + } + + /// Compare two blocks relative to the reverse post-order. + pub fn rpo_cmp_block(&self, a: Block, b: Block) -> Ordering { + self.nodes[a].rpo_number.cmp(&self.nodes[b].rpo_number) + } + + /// Compare two program points relative to a reverse post-order traversal of the control-flow + /// graph. + /// + /// Return `Ordering::Less` if `a` comes before `b` in the RPO. + /// + /// If `a` and `b` belong to the same block, compare their relative position in the block. + pub fn rpo_cmp(&self, a: A, b: B, layout: &Layout) -> Ordering + where + A: Into, + B: Into, + { + let a = a.into(); + let b = b.into(); + self.rpo_cmp_block(layout.pp_block(a), layout.pp_block(b)) + .then_with(|| layout.pp_cmp(a, b)) + } + + /// Returns `true` if `a` dominates `b`. + /// + /// This means that every control-flow path from the function entry to `b` must go through `a`. + /// + /// Dominance is ill defined for unreachable blocks. This function can always determine + /// dominance for instructions in the same block, but otherwise returns `false` if either block + /// is unreachable. + /// + /// An instruction is considered to dominate itself. + /// A block is also considered to dominate itself. + pub fn dominates(&self, a: A, b: B, layout: &Layout) -> bool + where + A: Into, + B: Into, + { + let a = a.into(); + let b = b.into(); + match a { + ProgramPoint::Block(block_a) => match b { + ProgramPoint::Block(block_b) => self.block_dominates(block_a, block_b), + ProgramPoint::Inst(inst_b) => { + let block_b = layout + .inst_block(inst_b) + .expect("Instruction not in layout."); + self.block_dominates(block_a, block_b) + } + }, + ProgramPoint::Inst(inst_a) => { + let block_a: Block = layout + .inst_block(inst_a) + .expect("Instruction not in layout."); + match b { + ProgramPoint::Block(block_b) => { + block_a != block_b && self.block_dominates(block_a, block_b) + } + ProgramPoint::Inst(inst_b) => { + let block_b = layout + .inst_block(inst_b) + .expect("Instruction not in layout."); + if block_a == block_b { + layout.pp_cmp(a, b) != Ordering::Greater + } else { + self.block_dominates(block_a, block_b) + } + } + } + } + } + } + + /// Returns `true` if `block_a` dominates `block_b`. + /// + /// A block is considered to dominate itself. + fn block_dominates(&self, block_a: Block, mut block_b: Block) -> bool { + let rpo_a = self.nodes[block_a].rpo_number; + + // Run a finger up the dominator tree from b until we see a. + // Do nothing if b is unreachable. + while rpo_a < self.nodes[block_b].rpo_number { + let idom = match self.idom(block_b) { + Some(idom) => idom, + None => return false, // a is unreachable, so we climbed past the entry + }; + block_b = idom; + } + + block_a == block_b + } + + /// Compute the common dominator of two basic blocks. + /// + /// Both basic blocks are assumed to be reachable. + fn common_dominator(&self, mut a: Block, mut b: Block) -> Block { + loop { + match self.rpo_cmp_block(a, b) { + Ordering::Less => { + // `a` comes before `b` in the RPO. Move `b` up. + let idom = self.nodes[b].idom.expect("Unreachable basic block?"); + b = idom; + } + Ordering::Greater => { + // `b` comes before `a` in the RPO. Move `a` up. + let idom = self.nodes[a].idom.expect("Unreachable basic block?"); + a = idom; + } + Ordering::Equal => break, + } + } + + debug_assert_eq!(a, b, "Unreachable block passed to common_dominator?"); + + a + } +} + +impl DominatorTree { + /// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a + /// function. + pub fn new() -> Self { + Self { + nodes: SecondaryMap::new(), + postorder: Vec::new(), + dfs: Dfs::new(), + valid: false, + } + } + + /// Allocate and compute a dominator tree. + pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self { + let block_capacity = func.layout.block_capacity(); + let mut domtree = Self { + nodes: SecondaryMap::with_capacity(block_capacity), + postorder: Vec::with_capacity(block_capacity), + dfs: Dfs::new(), + valid: false, + }; + domtree.compute(func, cfg); + domtree + } + + /// Reset and compute a CFG post-order and dominator tree. + pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) { + let _tt = timing::domtree(); + debug_assert!(cfg.is_valid()); + self.compute_postorder(func); + self.compute_domtree(func, cfg); + self.valid = true; + } + + /// Clear the data structures used to represent the dominator tree. This will leave the tree in + /// a state where `is_valid()` returns false. + pub fn clear(&mut self) { + self.nodes.clear(); + self.postorder.clear(); + self.valid = false; + } + + /// Check if the dominator tree is in a valid state. + /// + /// Note that this doesn't perform any kind of validity checks. It simply checks if the + /// `compute()` method has been called since the last `clear()`. It does not check that the + /// dominator tree is consistent with the CFG. + pub fn is_valid(&self) -> bool { + self.valid + } + + /// Reset all internal data structures and compute a post-order of the control flow graph. + /// + /// This leaves `rpo_number == 1` for all reachable blocks, 0 for unreachable ones. + fn compute_postorder(&mut self, func: &Function) { + self.clear(); + self.nodes.resize(func.dfg.num_blocks()); + self.postorder.extend(self.dfs.post_order_iter(func)); + } + + /// Build a dominator tree from a control flow graph using Keith D. Cooper's + /// "Simple, Fast Dominator Algorithm." + fn compute_domtree(&mut self, func: &Function, cfg: &ControlFlowGraph) { + // During this algorithm, `rpo_number` has the following values: + // + // 0: block is not reachable. + // 1: block is reachable, but has not yet been visited during the first pass. This is set by + // `compute_postorder`. + // 2+: block is reachable and has an assigned RPO number. + + // We'll be iterating over a reverse post-order of the CFG, skipping the entry block. + let (entry_block, postorder) = match self.postorder.as_slice().split_last() { + Some((&eb, rest)) => (eb, rest), + None => return, + }; + debug_assert_eq!(Some(entry_block), func.layout.entry_block()); + + // Do a first pass where we assign RPO numbers to all reachable nodes. + self.nodes[entry_block].rpo_number = 2 * STRIDE; + for (rpo_idx, &block) in postorder.iter().rev().enumerate() { + // Update the current node and give it an RPO number. + // The entry block got 2, the rest start at 3 by multiples of STRIDE to leave + // room for future dominator tree modifications. + // + // Since `compute_idom` will only look at nodes with an assigned RPO number, the + // function will never see an uninitialized predecessor. + // + // Due to the nature of the post-order traversal, every node we visit will have at + // least one predecessor that has previously been visited during this RPO. + self.nodes[block] = DomNode { + idom: self.compute_idom(block, cfg).into(), + rpo_number: (rpo_idx as u32 + 3) * STRIDE, + } + } + + // Now that we have RPO numbers for everything and initial immediate dominator estimates, + // iterate until convergence. + // + // If the function is free of irreducible control flow, this will exit after one iteration. + let mut changed = true; + while changed { + changed = false; + for &block in postorder.iter().rev() { + let idom = self.compute_idom(block, cfg).into(); + if self.nodes[block].idom != idom { + self.nodes[block].idom = idom; + changed = true; + } + } + } + } + + // Compute the immediate dominator for `block` using the current `idom` states for the reachable + // nodes. + fn compute_idom(&self, block: Block, cfg: &ControlFlowGraph) -> Block { + // Get an iterator with just the reachable, already visited predecessors to `block`. + // Note that during the first pass, `rpo_number` is 1 for reachable blocks that haven't + // been visited yet, 0 for unreachable blocks. + let mut reachable_preds = cfg + .pred_iter(block) + .filter(|&BlockPredecessor { block: pred, .. }| self.nodes[pred].rpo_number > 1) + .map(|pred| pred.block); + + // The RPO must visit at least one predecessor before this node. + let mut idom = reachable_preds + .next() + .expect("block node must have one reachable predecessor"); + + for pred in reachable_preds { + idom = self.common_dominator(idom, pred); + } + + idom + } +} + +/// Optional pre-order information that can be computed for a dominator tree. +/// +/// This data structure is computed from a `DominatorTree` and provides: +/// +/// - A forward traversable dominator tree through the `children()` iterator. +/// - An ordering of blocks according to a dominator tree pre-order. +/// - Constant time dominance checks at the block granularity. +/// +/// The information in this auxiliary data structure is not easy to update when the control flow +/// graph changes, which is why it is kept separate. +pub struct DominatorTreePreorder { + nodes: SecondaryMap, + + // Scratch memory used by `compute_postorder()`. + stack: Vec, +} + +#[derive(Default, Clone)] +struct ExtraNode { + /// First child node in the domtree. + child: PackedOption, + + /// Next sibling node in the domtree. This linked list is ordered according to the CFG RPO. + sibling: PackedOption, + + /// Sequence number for this node in a pre-order traversal of the dominator tree. + /// Unreachable blocks have number 0, the entry block is 1. + pre_number: u32, + + /// Maximum `pre_number` for the sub-tree of the dominator tree that is rooted at this node. + /// This is always >= `pre_number`. + pre_max: u32, +} + +/// Creating and computing the dominator tree pre-order. +impl DominatorTreePreorder { + /// Create a new blank `DominatorTreePreorder`. + pub fn new() -> Self { + Self { + nodes: SecondaryMap::new(), + stack: Vec::new(), + } + } + + /// Recompute this data structure to match `domtree`. + pub fn compute(&mut self, domtree: &DominatorTree) { + self.nodes.clear(); + + // Step 1: Populate the child and sibling links. + // + // By following the CFG post-order and pushing to the front of the lists, we make sure that + // sibling lists are ordered according to the CFG reverse post-order. + for &block in domtree.cfg_postorder() { + if let Some(idom) = domtree.idom(block) { + let sib = mem::replace(&mut self.nodes[idom].child, block.into()); + self.nodes[block].sibling = sib; + } else { + // The only block without an immediate dominator is the entry. + self.stack.push(block); + } + } + + // Step 2. Assign pre-order numbers from a DFS of the dominator tree. + debug_assert!(self.stack.len() <= 1); + let mut n = 0; + while let Some(block) = self.stack.pop() { + n += 1; + let node = &mut self.nodes[block]; + node.pre_number = n; + node.pre_max = n; + if let Some(n) = node.sibling.expand() { + self.stack.push(n); + } + if let Some(n) = node.child.expand() { + self.stack.push(n); + } + } + + // Step 3. Propagate the `pre_max` numbers up the tree. + // The CFG post-order is topologically ordered w.r.t. dominance so a node comes after all + // its dominator tree children. + for &block in domtree.cfg_postorder() { + if let Some(idom) = domtree.idom(block) { + let pre_max = cmp::max(self.nodes[block].pre_max, self.nodes[idom].pre_max); + self.nodes[idom].pre_max = pre_max; + } + } + } +} + +/// An iterator that enumerates the direct children of a block in the dominator tree. +pub struct ChildIter<'a> { + dtpo: &'a DominatorTreePreorder, + next: PackedOption, +} + +impl<'a> Iterator for ChildIter<'a> { + type Item = Block; + + fn next(&mut self) -> Option { + let n = self.next.expand(); + if let Some(block) = n { + self.next = self.dtpo.nodes[block].sibling; + } + n + } +} + +/// Query interface for the dominator tree pre-order. +impl DominatorTreePreorder { + /// Get an iterator over the direct children of `block` in the dominator tree. + /// + /// These are the block's whose immediate dominator is an instruction in `block`, ordered according + /// to the CFG reverse post-order. + pub fn children(&self, block: Block) -> ChildIter { + ChildIter { + dtpo: self, + next: self.nodes[block].child, + } + } + + /// Fast, constant time dominance check with block granularity. + /// + /// This computes the same result as `domtree.dominates(a, b)`, but in guaranteed fast constant + /// time. This is less general than the `DominatorTree` method because it only works with block + /// program points. + /// + /// A block is considered to dominate itself. + pub fn dominates(&self, a: Block, b: Block) -> bool { + let na = &self.nodes[a]; + let nb = &self.nodes[b]; + na.pre_number <= nb.pre_number && na.pre_max >= nb.pre_max + } + + /// Compare two blocks according to the dominator pre-order. + pub fn pre_cmp_block(&self, a: Block, b: Block) -> Ordering { + self.nodes[a].pre_number.cmp(&self.nodes[b].pre_number) + } + + /// Compare two program points according to the dominator tree pre-order. + /// + /// This ordering of program points have the property that given a program point, pp, all the + /// program points dominated by pp follow immediately and contiguously after pp in the order. + pub fn pre_cmp(&self, a: A, b: B, layout: &Layout) -> Ordering + where + A: Into, + B: Into, + { + let a = a.into(); + let b = b.into(); + self.pre_cmp_block(layout.pp_block(a), layout.pp_block(b)) + .then_with(|| layout.pp_cmp(a, b)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::types::*; + use crate::ir::{InstBuilder, TrapCode}; + + #[test] + fn empty() { + let func = Function::new(); + let cfg = ControlFlowGraph::with_function(&func); + debug_assert!(cfg.is_valid()); + let dtree = DominatorTree::with_function(&func, &cfg); + assert_eq!(0, dtree.nodes.keys().count()); + assert_eq!(dtree.cfg_postorder(), &[]); + + let mut dtpo = DominatorTreePreorder::new(); + dtpo.compute(&dtree); + } + + #[test] + fn unreachable_node() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let v0 = func.dfg.append_block_param(block0, I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let trap_block = func.dfg.make_block(); + + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + cur.ins().brif(v0, block2, &[], trap_block, &[]); + + cur.insert_block(trap_block); + cur.ins().trap(TrapCode::unwrap_user(1)); + + cur.insert_block(block1); + let v1 = cur.ins().iconst(I32, 1); + let v2 = cur.ins().iadd(v0, v1); + cur.ins().jump(block0, &[v2]); + + cur.insert_block(block2); + cur.ins().return_(&[v0]); + + let cfg = ControlFlowGraph::with_function(cur.func); + let dt = DominatorTree::with_function(cur.func, &cfg); + + // Fall-through-first, prune-at-source DFT: + // + // block0 { + // brif block2 { + // trap + // block2 { + // return + // } block2 + // } block0 + assert_eq!(dt.cfg_postorder(), &[block2, trap_block, block0]); + + let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); + assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); + assert!(!dt.dominates(block0, v2_def, &cur.func.layout)); + + let mut dtpo = DominatorTreePreorder::new(); + dtpo.compute(&dt); + assert!(dtpo.dominates(block0, block0)); + assert!(!dtpo.dominates(block0, block1)); + assert!(dtpo.dominates(block0, block2)); + assert!(!dtpo.dominates(block1, block0)); + assert!(dtpo.dominates(block1, block1)); + assert!(!dtpo.dominates(block1, block2)); + assert!(!dtpo.dominates(block2, block0)); + assert!(!dtpo.dominates(block2, block1)); + assert!(dtpo.dominates(block2, block2)); + } + + #[test] + fn non_zero_entry_block() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let block3 = func.dfg.make_block(); + let cond = func.dfg.append_block_param(block3, I32); + + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block3); + let jmp_block3_block1 = cur.ins().jump(block1, &[]); + + cur.insert_block(block1); + let br_block1_block0_block2 = cur.ins().brif(cond, block0, &[], block2, &[]); + + cur.insert_block(block2); + cur.ins().jump(block0, &[]); + + cur.insert_block(block0); + + let cfg = ControlFlowGraph::with_function(cur.func); + let dt = DominatorTree::with_function(cur.func, &cfg); + + // Fall-through-first, prune-at-source DFT: + // + // block3 { + // block3:jump block1 { + // block1 { + // block1:brif block0 { + // block1:jump block2 { + // block2 { + // block2:jump block0 (seen) + // } block2 + // } block1:jump block2 + // block0 { + // } block0 + // } block1:brif block0 + // } block1 + // } block3:jump block1 + // } block3 + + assert_eq!(dt.cfg_postorder(), &[block0, block2, block1, block3]); + + assert_eq!(cur.func.layout.entry_block().unwrap(), block3); + assert_eq!(dt.idom(block3), None); + assert_eq!(dt.idom(block1).unwrap(), block3); + assert_eq!(dt.idom(block2).unwrap(), block1); + assert_eq!(dt.idom(block0).unwrap(), block1); + + assert!(dt.dominates( + br_block1_block0_block2, + br_block1_block0_block2, + &cur.func.layout + )); + assert!(!dt.dominates(br_block1_block0_block2, jmp_block3_block1, &cur.func.layout)); + assert!(dt.dominates(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout)); + + assert_eq!( + dt.rpo_cmp(block3, block3, &cur.func.layout), + Ordering::Equal + ); + assert_eq!(dt.rpo_cmp(block3, block1, &cur.func.layout), Ordering::Less); + assert_eq!( + dt.rpo_cmp(block3, jmp_block3_block1, &cur.func.layout), + Ordering::Less + ); + assert_eq!( + dt.rpo_cmp(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout), + Ordering::Less + ); + } + + #[test] + fn backwards_layout() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + let jmp02 = cur.ins().jump(block2, &[]); + + cur.insert_block(block1); + let trap = cur.ins().trap(TrapCode::unwrap_user(5)); + + cur.insert_block(block2); + let jmp21 = cur.ins().jump(block1, &[]); + + let cfg = ControlFlowGraph::with_function(cur.func); + let dt = DominatorTree::with_function(cur.func, &cfg); + + assert_eq!(cur.func.layout.entry_block(), Some(block0)); + assert_eq!(dt.idom(block0), None); + assert_eq!(dt.idom(block1), Some(block2)); + assert_eq!(dt.idom(block2), Some(block0)); + + assert!(dt.dominates(block0, block0, &cur.func.layout)); + assert!(dt.dominates(block0, jmp02, &cur.func.layout)); + assert!(dt.dominates(block0, block1, &cur.func.layout)); + assert!(dt.dominates(block0, trap, &cur.func.layout)); + assert!(dt.dominates(block0, block2, &cur.func.layout)); + assert!(dt.dominates(block0, jmp21, &cur.func.layout)); + + assert!(!dt.dominates(jmp02, block0, &cur.func.layout)); + assert!(dt.dominates(jmp02, jmp02, &cur.func.layout)); + assert!(dt.dominates(jmp02, block1, &cur.func.layout)); + assert!(dt.dominates(jmp02, trap, &cur.func.layout)); + assert!(dt.dominates(jmp02, block2, &cur.func.layout)); + assert!(dt.dominates(jmp02, jmp21, &cur.func.layout)); + + assert!(!dt.dominates(block1, block0, &cur.func.layout)); + assert!(!dt.dominates(block1, jmp02, &cur.func.layout)); + assert!(dt.dominates(block1, block1, &cur.func.layout)); + assert!(dt.dominates(block1, trap, &cur.func.layout)); + assert!(!dt.dominates(block1, block2, &cur.func.layout)); + assert!(!dt.dominates(block1, jmp21, &cur.func.layout)); + + assert!(!dt.dominates(trap, block0, &cur.func.layout)); + assert!(!dt.dominates(trap, jmp02, &cur.func.layout)); + assert!(!dt.dominates(trap, block1, &cur.func.layout)); + assert!(dt.dominates(trap, trap, &cur.func.layout)); + assert!(!dt.dominates(trap, block2, &cur.func.layout)); + assert!(!dt.dominates(trap, jmp21, &cur.func.layout)); + + assert!(!dt.dominates(block2, block0, &cur.func.layout)); + assert!(!dt.dominates(block2, jmp02, &cur.func.layout)); + assert!(dt.dominates(block2, block1, &cur.func.layout)); + assert!(dt.dominates(block2, trap, &cur.func.layout)); + assert!(dt.dominates(block2, block2, &cur.func.layout)); + assert!(dt.dominates(block2, jmp21, &cur.func.layout)); + + assert!(!dt.dominates(jmp21, block0, &cur.func.layout)); + assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout)); + assert!(dt.dominates(jmp21, block1, &cur.func.layout)); + assert!(dt.dominates(jmp21, trap, &cur.func.layout)); + assert!(!dt.dominates(jmp21, block2, &cur.func.layout)); + assert!(dt.dominates(jmp21, jmp21, &cur.func.layout)); + } + + #[test] + fn insts_same_block() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + let v1 = cur.ins().iconst(I32, 1); + let v2 = cur.ins().iadd(v1, v1); + let v3 = cur.ins().iadd(v2, v2); + cur.ins().return_(&[]); + + let cfg = ControlFlowGraph::with_function(cur.func); + let dt = DominatorTree::with_function(cur.func, &cfg); + + let v1_def = cur.func.dfg.value_def(v1).unwrap_inst(); + let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); + let v3_def = cur.func.dfg.value_def(v3).unwrap_inst(); + + assert!(dt.dominates(v1_def, v2_def, &cur.func.layout)); + assert!(dt.dominates(v2_def, v3_def, &cur.func.layout)); + assert!(dt.dominates(v1_def, v3_def, &cur.func.layout)); + + assert!(!dt.dominates(v2_def, v1_def, &cur.func.layout)); + assert!(!dt.dominates(v3_def, v2_def, &cur.func.layout)); + assert!(!dt.dominates(v3_def, v1_def, &cur.func.layout)); + + assert!(dt.dominates(v2_def, v2_def, &cur.func.layout)); + assert!(dt.dominates(block0, block0, &cur.func.layout)); + + assert!(dt.dominates(block0, v1_def, &cur.func.layout)); + assert!(dt.dominates(block0, v2_def, &cur.func.layout)); + assert!(dt.dominates(block0, v3_def, &cur.func.layout)); + + assert!(!dt.dominates(v1_def, block0, &cur.func.layout)); + assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); + assert!(!dt.dominates(v3_def, block0, &cur.func.layout)); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/egraph.rs b/deps/crates/vendor/cranelift-codegen/src/egraph.rs new file mode 100644 index 00000000000000..eef19a6007171d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/egraph.rs @@ -0,0 +1,835 @@ +//! Support for egraphs represented in the DataFlowGraph. + +use crate::alias_analysis::{AliasAnalysis, LastStores}; +use crate::ctxhash::{CtxEq, CtxHash, CtxHashMap}; +use crate::cursor::{Cursor, CursorPosition, FuncCursor}; +use crate::dominator_tree::{DominatorTree, DominatorTreePreorder}; +use crate::egraph::elaborate::Elaborator; +use crate::inst_predicates::{is_mergeable_for_egraph, is_pure_for_egraph}; +use crate::ir::pcc::Fact; +use crate::ir::{ + Block, DataFlowGraph, Function, Inst, InstructionData, Opcode, Type, Value, ValueDef, + ValueListPool, +}; +use crate::loop_analysis::LoopAnalysis; +use crate::opts::IsleContext; +use crate::scoped_hash_map::{Entry as ScopedEntry, ScopedHashMap}; +use crate::settings::Flags; +use crate::trace; +use crate::unionfind::UnionFind; +use core::cmp::Ordering; +use cranelift_control::ControlPlane; +use cranelift_entity::packed_option::ReservedValue; +use cranelift_entity::SecondaryMap; +use rustc_hash::FxHashSet; +use smallvec::SmallVec; +use std::hash::Hasher; + +mod cost; +mod elaborate; + +/// Pass over a Function that does the whole aegraph thing. +/// +/// - Removes non-skeleton nodes from the Layout. +/// - Performs a GVN-and-rule-application pass over all Values +/// reachable from the skeleton, potentially creating new Union +/// nodes (i.e., an aegraph) so that some values have multiple +/// representations. +/// - Does "extraction" on the aegraph: selects the best value out of +/// the tree-of-Union nodes for each used value. +/// - Does "scoped elaboration" on the aegraph: chooses one or more +/// locations for pure nodes to become instructions again in the +/// layout, as forced by the skeleton. +/// +/// At the beginning and end of this pass, the CLIF should be in a +/// state that passes the verifier and, additionally, has no Union +/// nodes. During the pass, Union nodes may exist, and instructions in +/// the layout may refer to results of instructions that are not +/// placed in the layout. +pub struct EgraphPass<'a> { + /// The function we're operating on. + func: &'a mut Function, + /// Dominator tree for the CFG, used to visit blocks in pre-order + /// so we see value definitions before their uses, and also used for + /// O(1) dominance checks. + domtree: DominatorTreePreorder, + /// Alias analysis, used during optimization. + alias_analysis: &'a mut AliasAnalysis<'a>, + /// Loop analysis results, used for built-in LICM during + /// elaboration. + loop_analysis: &'a LoopAnalysis, + /// Compiler flags. + flags: &'a Flags, + /// Chaos-mode control-plane so we can test that we still get + /// correct results when our heuristics make bad decisions. + ctrl_plane: &'a mut ControlPlane, + /// Which canonical Values do we want to rematerialize in each + /// block where they're used? + /// + /// (A canonical Value is the *oldest* Value in an eclass, + /// i.e. tree of union value-nodes). + remat_values: FxHashSet, + /// Stats collected while we run this pass. + pub(crate) stats: Stats, + /// Union-find that maps all members of a Union tree (eclass) back + /// to the *oldest* (lowest-numbered) `Value`. + pub(crate) eclasses: UnionFind, +} + +// The maximum number of rewrites we will take from a single call into ISLE. +const MATCHES_LIMIT: usize = 5; + +/// Context passed through node insertion and optimization. +pub(crate) struct OptimizeCtx<'opt, 'analysis> +where + 'analysis: 'opt, +{ + // Borrowed from EgraphPass: + pub(crate) func: &'opt mut Function, + pub(crate) value_to_opt_value: &'opt mut SecondaryMap, + pub(crate) gvn_map: &'opt mut CtxHashMap<(Type, InstructionData), Value>, + pub(crate) effectful_gvn_map: &'opt mut ScopedHashMap<(Type, InstructionData), Value>, + available_block: &'opt mut SecondaryMap, + pub(crate) eclasses: &'opt mut UnionFind, + pub(crate) remat_values: &'opt mut FxHashSet, + pub(crate) stats: &'opt mut Stats, + domtree: &'opt DominatorTreePreorder, + pub(crate) alias_analysis: &'opt mut AliasAnalysis<'analysis>, + pub(crate) alias_analysis_state: &'opt mut LastStores, + flags: &'opt Flags, + ctrl_plane: &'opt mut ControlPlane, + // Held locally during optimization of one node (recursively): + pub(crate) rewrite_depth: usize, + pub(crate) subsume_values: FxHashSet, + optimized_values: SmallVec<[Value; MATCHES_LIMIT]>, +} + +/// For passing to `insert_pure_enode`. Sometimes the enode already +/// exists as an Inst (from the original CLIF), and sometimes we're in +/// the middle of creating it and want to avoid inserting it if +/// possible until we know we need it. +pub(crate) enum NewOrExistingInst { + New(InstructionData, Type), + Existing(Inst), +} + +impl NewOrExistingInst { + fn get_inst_key<'a>(&'a self, dfg: &'a DataFlowGraph) -> (Type, InstructionData) { + match self { + NewOrExistingInst::New(data, ty) => (*ty, *data), + NewOrExistingInst::Existing(inst) => { + let ty = dfg.ctrl_typevar(*inst); + (ty, dfg.insts[*inst]) + } + } + } +} + +impl<'opt, 'analysis> OptimizeCtx<'opt, 'analysis> +where + 'analysis: 'opt, +{ + /// Optimization of a single instruction. + /// + /// This does a few things: + /// - Looks up the instruction in the GVN deduplication map. If we + /// already have the same instruction somewhere else, with the + /// same args, then we can alias the original instruction's + /// results and omit this instruction entirely. + /// - Note that we do this canonicalization based on the + /// instruction with its arguments as *canonical* eclass IDs, + /// that is, the oldest (smallest index) `Value` reachable in + /// the tree-of-unions (whole eclass). This ensures that we + /// properly canonicalize newer nodes that use newer "versions" + /// of a value that are still equal to the older versions. + /// - If the instruction is "new" (not deduplicated), then apply + /// optimization rules: + /// - All of the mid-end rules written in ISLE. + /// - Store-to-load forwarding. + /// - Update the value-to-opt-value map, and update the eclass + /// union-find, if we rewrote the value to different form(s). + pub(crate) fn insert_pure_enode(&mut self, inst: NewOrExistingInst) -> Value { + // Create the external context for looking up and updating the + // GVN map. This is necessary so that instructions themselves + // do not have to carry all the references or data for a full + // `Eq` or `Hash` impl. + let gvn_context = GVNContext { + union_find: self.eclasses, + value_lists: &self.func.dfg.value_lists, + }; + + self.stats.pure_inst += 1; + if let NewOrExistingInst::New(..) = inst { + self.stats.new_inst += 1; + } + + // Does this instruction already exist? If so, add entries to + // the value-map to rewrite uses of its results to the results + // of the original (existing) instruction. If not, optimize + // the new instruction. + if let Some(&orig_result) = self + .gvn_map + .get(&inst.get_inst_key(&self.func.dfg), &gvn_context) + { + self.stats.pure_inst_deduped += 1; + if let NewOrExistingInst::Existing(inst) = inst { + debug_assert_eq!(self.func.dfg.inst_results(inst).len(), 1); + let result = self.func.dfg.first_result(inst); + debug_assert!( + self.domtree.dominates( + self.available_block[orig_result], + self.get_available_block(inst) + ), + "GVN shouldn't replace {result} (available in {}) with non-dominating {orig_result} (available in {})", + self.get_available_block(inst), + self.available_block[orig_result], + ); + self.value_to_opt_value[result] = orig_result; + self.func.dfg.merge_facts(result, orig_result); + } + orig_result + } else { + // Now actually insert the InstructionData and attach + // result value (exactly one). + let (inst, result, ty) = match inst { + NewOrExistingInst::New(data, typevar) => { + let inst = self.func.dfg.make_inst(data); + // TODO: reuse return value? + self.func.dfg.make_inst_results(inst, typevar); + let result = self.func.dfg.first_result(inst); + // Add to eclass unionfind. + self.eclasses.add(result); + // New inst. We need to do the analysis of its result. + (inst, result, typevar) + } + NewOrExistingInst::Existing(inst) => { + let result = self.func.dfg.first_result(inst); + let ty = self.func.dfg.ctrl_typevar(inst); + (inst, result, ty) + } + }; + + self.attach_constant_fact(inst, result, ty); + + self.available_block[result] = self.get_available_block(inst); + let opt_value = self.optimize_pure_enode(inst); + + for &argument in self.func.dfg.inst_args(inst) { + self.eclasses.pin_index(argument); + } + + let gvn_context = GVNContext { + union_find: self.eclasses, + value_lists: &self.func.dfg.value_lists, + }; + self.gvn_map + .insert((ty, self.func.dfg.insts[inst]), opt_value, &gvn_context); + self.value_to_opt_value[result] = opt_value; + opt_value + } + } + + /// Find the block where a pure instruction first becomes available, + /// defined as the block that is closest to the root where all of + /// its arguments are available. In the unusual case where a pure + /// instruction has no arguments (e.g. get_return_address), we can + /// place it anywhere, so it is available in the entry block. + /// + /// This function does not compute available blocks recursively. + /// All of the instruction's arguments must have had their available + /// blocks assigned already. + fn get_available_block(&self, inst: Inst) -> Block { + // Side-effecting instructions have different rules for where + // they become available, so this function does not apply. + debug_assert!(is_pure_for_egraph(self.func, inst)); + + // Note that the def-point of all arguments to an instruction + // in SSA lie on a line of direct ancestors in the domtree, and + // so do their available-blocks. This means that for any pair of + // arguments, their available blocks are either the same or one + // strictly dominates the other. We just need to find any argument + // whose available block is deepest in the domtree. + self.func.dfg.insts[inst] + .arguments(&self.func.dfg.value_lists) + .iter() + .map(|&v| { + let block = self.available_block[v]; + debug_assert!(!block.is_reserved_value()); + block + }) + .max_by(|&x, &y| { + if self.domtree.dominates(x, y) { + Ordering::Less + } else { + debug_assert!(self.domtree.dominates(y, x)); + Ordering::Greater + } + }) + .unwrap_or(self.func.layout.entry_block().unwrap()) + } + + /// Optimizes an enode by applying any matching mid-end rewrite + /// rules (or store-to-load forwarding, which is a special case), + /// unioning together all possible optimized (or rewritten) forms + /// of this expression into an eclass and returning the `Value` + /// that represents that eclass. + fn optimize_pure_enode(&mut self, inst: Inst) -> Value { + // A pure node always has exactly one result. + let orig_value = self.func.dfg.first_result(inst); + + let mut optimized_values = std::mem::take(&mut self.optimized_values); + + // Limit rewrite depth. When we apply optimization rules, they + // may create new nodes (values) and those are, recursively, + // optimized eagerly as soon as they are created. So we may + // have more than one ISLE invocation on the stack. (This is + // necessary so that as the toplevel builds the + // right-hand-side expression bottom-up, it uses the "latest" + // optimized values for all the constituent parts.) To avoid + // infinite or problematic recursion, we bound the rewrite + // depth to a small constant here. + const REWRITE_LIMIT: usize = 5; + if self.rewrite_depth > REWRITE_LIMIT { + self.stats.rewrite_depth_limit += 1; + return orig_value; + } + self.rewrite_depth += 1; + trace!("Incrementing rewrite depth; now {}", self.rewrite_depth); + + // Invoke the ISLE toplevel constructor, getting all new + // values produced as equivalents to this value. + trace!("Calling into ISLE with original value {}", orig_value); + self.stats.rewrite_rule_invoked += 1; + debug_assert!(optimized_values.is_empty()); + crate::opts::generated_code::constructor_simplify( + &mut IsleContext { ctx: self }, + orig_value, + &mut optimized_values, + ); + + optimized_values.push(orig_value); + + // Remove any values from optimized_values that do not have + // the highest possible available block in the domtree, in + // O(n) time. This loop scans in reverse, establishing the + // loop invariant that all values at indices >= idx have the + // same available block, which is the best available block + // seen so far. Note that orig_value must also be removed if + // it isn't in the best block, so we push it above, which means + // optimized_values is never empty: there's always at least one + // value in best_block. + let mut best_block = self.available_block[*optimized_values.last().unwrap()]; + for idx in (0..optimized_values.len() - 1).rev() { + // At the beginning of each iteration, there is a non-empty + // collection of values after idx, which are all available + // at best_block. + let this_block = self.available_block[optimized_values[idx]]; + if this_block != best_block { + if self.domtree.dominates(this_block, best_block) { + // If the available block for this value dominates + // the best block we've seen so far, discard all + // the values we already checked and leave only this + // value in the tail of the vector. + optimized_values.truncate(idx + 1); + best_block = this_block; + } else { + // Otherwise the tail of the vector contains values + // which are all better than this value, so we can + // swap any of them in place of this value to delete + // this one in O(1) time. + debug_assert!(self.domtree.dominates(best_block, this_block)); + optimized_values.swap_remove(idx); + debug_assert!(optimized_values.len() > idx); + } + } + } + + // It's not supposed to matter what order `simplify` returns values in. + self.ctrl_plane.shuffle(&mut optimized_values); + + let num_matches = optimized_values.len(); + if num_matches > MATCHES_LIMIT { + trace!( + "Reached maximum matches limit; too many optimized values \ + ({num_matches} > {MATCHES_LIMIT}); ignoring rest.", + ); + optimized_values.truncate(MATCHES_LIMIT); + } + + trace!(" -> returned from ISLE: {orig_value} -> {optimized_values:?}"); + + // Create a union of all new values with the original (or + // maybe just one new value marked as "subsuming" the + // original, if present.) + let mut union_value = optimized_values.pop().unwrap(); + for optimized_value in optimized_values.drain(..) { + trace!( + "Returned from ISLE for {}, got {:?}", + orig_value, + optimized_value + ); + if optimized_value == orig_value { + trace!(" -> same as orig value; skipping"); + continue; + } + if self.subsume_values.contains(&optimized_value) { + // Merge in the unionfind so canonicalization + // still works, but take *only* the subsuming + // value, and break now. + self.eclasses.union(optimized_value, union_value); + self.func.dfg.merge_facts(optimized_value, union_value); + union_value = optimized_value; + break; + } + + let old_union_value = union_value; + union_value = self.func.dfg.union(old_union_value, optimized_value); + self.available_block[union_value] = best_block; + self.stats.union += 1; + trace!(" -> union: now {}", union_value); + self.eclasses.add(union_value); + self.eclasses.union(old_union_value, optimized_value); + self.func.dfg.merge_facts(old_union_value, optimized_value); + self.eclasses.union(old_union_value, union_value); + } + + self.rewrite_depth -= 1; + trace!("Decrementing rewrite depth; now {}", self.rewrite_depth); + + debug_assert!(self.optimized_values.is_empty()); + self.optimized_values = optimized_values; + + union_value + } + + /// Optimize a "skeleton" instruction, possibly removing + /// it. Returns `true` if the instruction should be removed from + /// the layout. + fn optimize_skeleton_inst(&mut self, inst: Inst) -> bool { + self.stats.skeleton_inst += 1; + + for &result in self.func.dfg.inst_results(inst) { + self.available_block[result] = self.func.layout.inst_block(inst).unwrap(); + } + + // First, can we try to deduplicate? We need to keep some copy + // of the instruction around because it's side-effecting, but + // we may be able to reuse an earlier instance of it. + if is_mergeable_for_egraph(self.func, inst) { + let result = self.func.dfg.inst_results(inst)[0]; + trace!(" -> mergeable side-effecting op {}", inst); + + // Does this instruction already exist? If so, add entries to + // the value-map to rewrite uses of its results to the results + // of the original (existing) instruction. If not, optimize + // the new instruction. + // + // Note that we use the "effectful GVN map", which is + // scoped: because effectful ops are not removed from the + // skeleton (`Layout`), we need to be mindful of whether + // our current position is dominated by an instance of the + // instruction. (See #5796 for details.) + let ty = self.func.dfg.ctrl_typevar(inst); + match self + .effectful_gvn_map + .entry((ty, self.func.dfg.insts[inst])) + { + ScopedEntry::Occupied(o) => { + let orig_result = *o.get(); + // Hit in GVN map -- reuse value. + self.value_to_opt_value[result] = orig_result; + trace!(" -> merges result {} to {}", result, orig_result); + true + } + ScopedEntry::Vacant(v) => { + // Otherwise, insert it into the value-map. + self.value_to_opt_value[result] = result; + v.insert(result); + trace!(" -> inserts as new (no GVN)"); + false + } + } + } + // Otherwise, if a load or store, process it with the alias + // analysis to see if we can optimize it (rewrite in terms of + // an earlier load or stored value). + else if let Some(new_result) = + self.alias_analysis + .process_inst(self.func, self.alias_analysis_state, inst) + { + self.stats.alias_analysis_removed += 1; + let result = self.func.dfg.first_result(inst); + trace!( + " -> inst {} has result {} replaced with {}", + inst, + result, + new_result + ); + self.value_to_opt_value[result] = new_result; + self.func.dfg.merge_facts(result, new_result); + true + } + // Otherwise, generic side-effecting op -- always keep it, and + // set its results to identity-map to original values. + else { + // Set all results to identity-map to themselves + // in the value-to-opt-value map. + for &result in self.func.dfg.inst_results(inst) { + self.value_to_opt_value[result] = result; + self.eclasses.add(result); + } + false + } + } + + /// Helper to propagate facts on constant values: if PCC is + /// enabled, then unconditionally add a fact attesting to the + /// Value's concrete value. + fn attach_constant_fact(&mut self, inst: Inst, value: Value, ty: Type) { + if self.flags.enable_pcc() { + if let InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm, + } = self.func.dfg.insts[inst] + { + let imm: i64 = imm.into(); + self.func.dfg.facts[value] = + Some(Fact::constant(ty.bits().try_into().unwrap(), imm as u64)); + } + } + } +} + +impl<'a> EgraphPass<'a> { + /// Create a new EgraphPass. + pub fn new( + func: &'a mut Function, + raw_domtree: &'a DominatorTree, + loop_analysis: &'a LoopAnalysis, + alias_analysis: &'a mut AliasAnalysis<'a>, + flags: &'a Flags, + ctrl_plane: &'a mut ControlPlane, + ) -> Self { + let num_values = func.dfg.num_values(); + let mut domtree = DominatorTreePreorder::new(); + domtree.compute(raw_domtree); + Self { + func, + domtree, + loop_analysis, + alias_analysis, + flags, + ctrl_plane, + stats: Stats::default(), + eclasses: UnionFind::with_capacity(num_values), + remat_values: FxHashSet::default(), + } + } + + /// Run the process. + pub fn run(&mut self) { + self.remove_pure_and_optimize(); + + trace!("egraph built:\n{}\n", self.func.display()); + if cfg!(feature = "trace-log") { + for (value, def) in self.func.dfg.values_and_defs() { + trace!(" -> {} = {:?}", value, def); + match def { + ValueDef::Result(i, 0) => { + trace!(" -> {} = {:?}", i, self.func.dfg.insts[i]); + } + _ => {} + } + } + } + trace!("stats: {:#?}", self.stats); + trace!("pinned_union_count: {}", self.eclasses.pinned_union_count); + self.elaborate(); + } + + /// Remove pure nodes from the `Layout` of the function, ensuring + /// that only the "side-effect skeleton" remains, and also + /// optimize the pure nodes. This is the first step of + /// egraph-based processing and turns the pure CFG-based CLIF into + /// a CFG skeleton with a sea of (optimized) nodes tying it + /// together. + /// + /// As we walk through the code, we eagerly apply optimization + /// rules; at any given point we have a "latest version" of an + /// eclass of possible representations for a `Value` in the + /// original program, which is itself a `Value` at the root of a + /// union-tree. We keep a map from the original values to these + /// optimized values. When we encounter any instruction (pure or + /// side-effecting skeleton) we rewrite its arguments to capture + /// the "latest" optimized forms of these values. (We need to do + /// this as part of this pass, and not later using a finished map, + /// because the eclass can continue to be updated and we need to + /// only refer to its subset that exists at this stage, to + /// maintain acyclicity.) + fn remove_pure_and_optimize(&mut self) { + let mut cursor = FuncCursor::new(self.func); + let mut value_to_opt_value: SecondaryMap = + SecondaryMap::with_default(Value::reserved_value()); + // Map from instruction to value for hash-consing of pure ops + // into the egraph. This can be a standard (non-scoped) + // hashmap because pure ops have no location: they are + // "outside of" control flow. + // + // Note also that we keep the controlling typevar (the `Type` + // in the tuple below) because it may disambiguate + // instructions that are identical except for type. + let mut gvn_map: CtxHashMap<(Type, InstructionData), Value> = + CtxHashMap::with_capacity(cursor.func.dfg.num_values()); + // Map from instruction to value for GVN'ing of effectful but + // idempotent ops, which remain in the side-effecting + // skeleton. This needs to be scoped because we cannot + // deduplicate one instruction to another that is in a + // non-dominating block. + // + // Note that we can use a ScopedHashMap here without the + // "context" (as needed by CtxHashMap) because in practice the + // ops we want to GVN have all their args inline. Equality on + // the InstructionData itself is conservative: two insts whose + // struct contents compare shallowly equal are definitely + // identical, but identical insts in a deep-equality sense may + // not compare shallowly equal, due to list indirection. This + // is fine for GVN, because it is still sound to skip any + // given GVN opportunity (and keep the original instructions). + // + // As above, we keep the controlling typevar here as part of + // the key: effectful instructions may (as for pure + // instructions) be differentiated only on the type. + let mut effectful_gvn_map: ScopedHashMap<(Type, InstructionData), Value> = + ScopedHashMap::new(); + + // We assign an "available block" to every value. Values tied to + // the side-effecting skeleton are available in the block where + // they're defined. Results from pure instructions could legally + // float up the domtree so they are available as soon as all + // their arguments are available. Values which identify union + // nodes are available in the same block as all values in the + // eclass, enforced by optimize_pure_enode. + let mut available_block: SecondaryMap = + SecondaryMap::with_default(Block::reserved_value()); + // This is an initial guess at the size we'll need, but we add + // more values as we build simplified alternative expressions so + // this is likely to realloc again later. + available_block.resize(cursor.func.dfg.num_values()); + + // In domtree preorder, visit blocks. (TODO: factor out an + // iterator from this and elaborator.) + let root = cursor.layout().entry_block().unwrap(); + enum StackEntry { + Visit(Block), + Pop, + } + let mut block_stack = vec![StackEntry::Visit(root)]; + while let Some(entry) = block_stack.pop() { + match entry { + StackEntry::Visit(block) => { + // We popped this block; push children + // immediately, then process this block. + block_stack.push(StackEntry::Pop); + block_stack.extend( + self.ctrl_plane + .shuffled(self.domtree.children(block)) + .map(StackEntry::Visit), + ); + effectful_gvn_map.increment_depth(); + + trace!("Processing block {}", block); + cursor.set_position(CursorPosition::Before(block)); + + let mut alias_analysis_state = self.alias_analysis.block_starting_state(block); + + for ¶m in cursor.func.dfg.block_params(block) { + trace!("creating initial singleton eclass for blockparam {}", param); + self.eclasses.add(param); + value_to_opt_value[param] = param; + available_block[param] = block; + } + while let Some(inst) = cursor.next_inst() { + trace!("Processing inst {}", inst); + + // While we're passing over all insts, create initial + // singleton eclasses for all result and blockparam + // values. Also do initial analysis of all inst + // results. + for &result in cursor.func.dfg.inst_results(inst) { + trace!("creating initial singleton eclass for {}", result); + self.eclasses.add(result); + } + + // Rewrite args of *all* instructions using the + // value-to-opt-value map. + cursor.func.dfg.map_inst_values(inst, |arg| { + let new_value = value_to_opt_value[arg]; + trace!("rewriting arg {} of inst {} to {}", arg, inst, new_value); + debug_assert_ne!(new_value, Value::reserved_value()); + new_value + }); + + // Build a context for optimization, with borrows of + // state. We can't invoke a method on `self` because + // we've borrowed `self.func` mutably (as + // `cursor.func`) so we pull apart the pieces instead + // here. + let mut ctx = OptimizeCtx { + func: cursor.func, + value_to_opt_value: &mut value_to_opt_value, + gvn_map: &mut gvn_map, + effectful_gvn_map: &mut effectful_gvn_map, + available_block: &mut available_block, + eclasses: &mut self.eclasses, + rewrite_depth: 0, + subsume_values: FxHashSet::default(), + remat_values: &mut self.remat_values, + stats: &mut self.stats, + domtree: &self.domtree, + alias_analysis: self.alias_analysis, + alias_analysis_state: &mut alias_analysis_state, + flags: self.flags, + ctrl_plane: self.ctrl_plane, + optimized_values: Default::default(), + }; + + if is_pure_for_egraph(ctx.func, inst) { + // Insert into GVN map and optimize any new nodes + // inserted (recursively performing this work for + // any nodes the optimization rules produce). + let inst = NewOrExistingInst::Existing(inst); + ctx.insert_pure_enode(inst); + // We've now rewritten all uses, or will when we + // see them, and the instruction exists as a pure + // enode in the eclass, so we can remove it. + cursor.remove_inst_and_step_back(); + } else { + if ctx.optimize_skeleton_inst(inst) { + cursor.remove_inst_and_step_back(); + } + } + } + } + StackEntry::Pop => { + effectful_gvn_map.decrement_depth(); + } + } + } + } + + /// Scoped elaboration: compute a final ordering of op computation + /// for each block and update the given Func body. After this + /// runs, the function body is back into the state where every + /// Inst with an used result is placed in the layout (possibly + /// duplicated, if our code-motion logic decides this is the best + /// option). + /// + /// This works in concert with the domtree. We do a preorder + /// traversal of the domtree, tracking a scoped map from Id to + /// (new) Value. The map's scopes correspond to levels in the + /// domtree. + /// + /// At each block, we iterate forward over the side-effecting + /// eclasses, and recursively generate their arg eclasses, then + /// emit the ops themselves. + /// + /// To use an eclass in a given block, we first look it up in the + /// scoped map, and get the Value if already present. If not, we + /// need to generate it. We emit the extracted enode for this + /// eclass after recursively generating its args. Eclasses are + /// thus computed "as late as possible", but then memoized into + /// the Id-to-Value map and available to all dominated blocks and + /// for the rest of this block. (This subsumes GVN.) + fn elaborate(&mut self) { + let mut elaborator = Elaborator::new( + self.func, + &self.domtree, + self.loop_analysis, + &self.remat_values, + &mut self.stats, + self.ctrl_plane, + ); + elaborator.elaborate(); + + self.check_post_egraph(); + } + + #[cfg(debug_assertions)] + fn check_post_egraph(&self) { + // Verify that no union nodes are reachable from inst args, + // and that all inst args' defining instructions are in the + // layout. + for block in self.func.layout.blocks() { + for inst in self.func.layout.block_insts(block) { + self.func + .dfg + .inst_values(inst) + .for_each(|arg| match self.func.dfg.value_def(arg) { + ValueDef::Result(i, _) => { + debug_assert!(self.func.layout.inst_block(i).is_some()); + } + ValueDef::Union(..) => { + panic!("egraph union node {arg} still reachable at {inst}!"); + } + _ => {} + }) + } + } + } + + #[cfg(not(debug_assertions))] + fn check_post_egraph(&self) {} +} + +/// Implementation of external-context equality and hashing on +/// InstructionData. This allows us to deduplicate instructions given +/// some context that lets us see its value lists and the mapping from +/// any value to "canonical value" (in an eclass). +struct GVNContext<'a> { + value_lists: &'a ValueListPool, + union_find: &'a UnionFind, +} + +impl<'a> CtxEq<(Type, InstructionData), (Type, InstructionData)> for GVNContext<'a> { + fn ctx_eq( + &self, + (a_ty, a_inst): &(Type, InstructionData), + (b_ty, b_inst): &(Type, InstructionData), + ) -> bool { + a_ty == b_ty + && a_inst.eq(b_inst, self.value_lists, |value| { + self.union_find.find(value) + }) + } +} + +impl<'a> CtxHash<(Type, InstructionData)> for GVNContext<'a> { + fn ctx_hash(&self, state: &mut H, (ty, inst): &(Type, InstructionData)) { + std::hash::Hash::hash(&ty, state); + inst.hash(state, self.value_lists, |value| self.union_find.find(value)); + } +} + +/// Statistics collected during egraph-based processing. +#[derive(Clone, Debug, Default)] +pub(crate) struct Stats { + pub(crate) pure_inst: u64, + pub(crate) pure_inst_deduped: u64, + pub(crate) skeleton_inst: u64, + pub(crate) alias_analysis_removed: u64, + pub(crate) new_inst: u64, + pub(crate) union: u64, + pub(crate) subsume: u64, + pub(crate) remat: u64, + pub(crate) rewrite_rule_invoked: u64, + pub(crate) rewrite_depth_limit: u64, + pub(crate) elaborate_visit_node: u64, + pub(crate) elaborate_memoize_hit: u64, + pub(crate) elaborate_memoize_miss: u64, + pub(crate) elaborate_remat: u64, + pub(crate) elaborate_licm_hoist: u64, + pub(crate) elaborate_func: u64, + pub(crate) elaborate_func_pre_insts: u64, + pub(crate) elaborate_func_post_insts: u64, + pub(crate) elaborate_best_cost_fixpoint_iters: u64, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/egraph/cost.rs b/deps/crates/vendor/cranelift-codegen/src/egraph/cost.rs new file mode 100644 index 00000000000000..28aab40e97405d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/egraph/cost.rs @@ -0,0 +1,213 @@ +//! Cost functions for egraph representation. + +use crate::ir::Opcode; + +/// A cost of computing some value in the program. +/// +/// Costs are measured in an arbitrary union that we represent in a +/// `u32`. The ordering is meant to be meaningful, but the value of a +/// single unit is arbitrary (and "not to scale"). We use a collection +/// of heuristics to try to make this approximation at least usable. +/// +/// We start by defining costs for each opcode (see `pure_op_cost` +/// below). The cost of computing some value, initially, is the cost +/// of its opcode, plus the cost of computing its inputs. +/// +/// We then adjust the cost according to loop nests: for each +/// loop-nest level, we multiply by 1024. Because we only have 32 +/// bits, we limit this scaling to a loop-level of two (i.e., multiply +/// by 2^20 ~= 1M). +/// +/// Arithmetic on costs is always saturating: we don't want to wrap +/// around and return to a tiny cost when adding the costs of two very +/// expensive operations. It is better to approximate and lose some +/// precision than to lose the ordering by wrapping. +/// +/// Finally, we reserve the highest value, `u32::MAX`, as a sentinel +/// that means "infinite". This is separate from the finite costs and +/// not reachable by doing arithmetic on them (even when overflowing) +/// -- we saturate just *below* infinity. (This is done by the +/// `finite()` method.) An infinite cost is used to represent a value +/// that cannot be computed, or otherwise serve as a sentinel when +/// performing search for the lowest-cost representation of a value. +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) struct Cost(u32); + +impl core::fmt::Debug for Cost { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if *self == Cost::infinity() { + write!(f, "Cost::Infinite") + } else { + f.debug_struct("Cost::Finite") + .field("op_cost", &self.op_cost()) + .field("depth", &self.depth()) + .finish() + } + } +} + +impl Ord for Cost { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + // We make sure that the high bits are the op cost and the low bits are + // the depth. This means that we can use normal integer comparison to + // order by op cost and then depth. + // + // We want to break op cost ties with depth (rather than the other way + // around). When the op cost is the same, we prefer shallow and wide + // expressions to narrow and deep expressions and breaking ties with + // `depth` gives us that. For example, `(a + b) + (c + d)` is preferred + // to `((a + b) + c) + d`. This is beneficial because it exposes more + // instruction-level parallelism and shortens live ranges. + self.0.cmp(&other.0) + } +} + +impl PartialOrd for Cost { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Cost { + const DEPTH_BITS: u8 = 8; + const DEPTH_MASK: u32 = (1 << Self::DEPTH_BITS) - 1; + const OP_COST_MASK: u32 = !Self::DEPTH_MASK; + const MAX_OP_COST: u32 = Self::OP_COST_MASK >> Self::DEPTH_BITS; + + pub(crate) fn infinity() -> Cost { + // 2^32 - 1 is, uh, pretty close to infinite... (we use `Cost` + // only for heuristics and always saturate so this suffices!) + Cost(u32::MAX) + } + + pub(crate) fn zero() -> Cost { + Cost(0) + } + + /// Construct a new `Cost` from the given parts. + /// + /// If the opcode cost is greater than or equal to the maximum representable + /// opcode cost, then the resulting `Cost` saturates to infinity. + fn new(opcode_cost: u32, depth: u8) -> Cost { + if opcode_cost >= Self::MAX_OP_COST { + Self::infinity() + } else { + Cost(opcode_cost << Self::DEPTH_BITS | u32::from(depth)) + } + } + + fn depth(&self) -> u8 { + let depth = self.0 & Self::DEPTH_MASK; + u8::try_from(depth).unwrap() + } + + fn op_cost(&self) -> u32 { + (self.0 & Self::OP_COST_MASK) >> Self::DEPTH_BITS + } + + /// Compute the cost of the operation and its given operands. + /// + /// Caller is responsible for checking that the opcode came from an instruction + /// that satisfies `inst_predicates::is_pure_for_egraph()`. + pub(crate) fn of_pure_op(op: Opcode, operand_costs: impl IntoIterator) -> Self { + let c = pure_op_cost(op) + operand_costs.into_iter().sum(); + Cost::new(c.op_cost(), c.depth().saturating_add(1)) + } +} + +impl std::iter::Sum for Cost { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), |a, b| a + b) + } +} + +impl std::default::Default for Cost { + fn default() -> Cost { + Cost::zero() + } +} + +impl std::ops::Add for Cost { + type Output = Cost; + + fn add(self, other: Cost) -> Cost { + let op_cost = self.op_cost().saturating_add(other.op_cost()); + let depth = std::cmp::max(self.depth(), other.depth()); + Cost::new(op_cost, depth) + } +} + +/// Return the cost of a *pure* opcode. +/// +/// Caller is responsible for checking that the opcode came from an instruction +/// that satisfies `inst_predicates::is_pure_for_egraph()`. +fn pure_op_cost(op: Opcode) -> Cost { + match op { + // Constants. + Opcode::Iconst | Opcode::F32const | Opcode::F64const => Cost::new(1, 0), + + // Extends/reduces. + Opcode::Uextend | Opcode::Sextend | Opcode::Ireduce | Opcode::Iconcat | Opcode::Isplit => { + Cost::new(2, 0) + } + + // "Simple" arithmetic. + Opcode::Iadd + | Opcode::Isub + | Opcode::Band + | Opcode::Bor + | Opcode::Bxor + | Opcode::Bnot + | Opcode::Ishl + | Opcode::Ushr + | Opcode::Sshr => Cost::new(3, 0), + + // Everything else (pure.) + _ => Cost::new(4, 0), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_cost() { + let a = Cost::new(5, 2); + let b = Cost::new(37, 3); + assert_eq!(a + b, Cost::new(42, 3)); + assert_eq!(b + a, Cost::new(42, 3)); + } + + #[test] + fn add_infinity() { + let a = Cost::new(5, 2); + let b = Cost::infinity(); + assert_eq!(a + b, Cost::infinity()); + assert_eq!(b + a, Cost::infinity()); + } + + #[test] + fn op_cost_saturates_to_infinity() { + let a = Cost::new(Cost::MAX_OP_COST - 10, 2); + let b = Cost::new(11, 2); + assert_eq!(a + b, Cost::infinity()); + assert_eq!(b + a, Cost::infinity()); + } + + #[test] + fn depth_saturates_to_max_depth() { + let a = Cost::new(10, u8::MAX); + let b = Cost::new(10, 1); + assert_eq!( + Cost::of_pure_op(Opcode::Iconst, [a, b]), + Cost::new(21, u8::MAX) + ); + assert_eq!( + Cost::of_pure_op(Opcode::Iconst, [b, a]), + Cost::new(21, u8::MAX) + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/egraph/elaborate.rs b/deps/crates/vendor/cranelift-codegen/src/egraph/elaborate.rs new file mode 100644 index 00000000000000..a35c2ac25734cb --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/egraph/elaborate.rs @@ -0,0 +1,835 @@ +//! Elaboration phase: lowers EGraph back to sequences of operations +//! in CFG nodes. + +use super::cost::Cost; +use super::Stats; +use crate::dominator_tree::DominatorTreePreorder; +use crate::hash_map::Entry as HashEntry; +use crate::inst_predicates::is_pure_for_egraph; +use crate::ir::{Block, Function, Inst, Value, ValueDef}; +use crate::loop_analysis::{Loop, LoopAnalysis}; +use crate::scoped_hash_map::ScopedHashMap; +use crate::trace; +use alloc::vec::Vec; +use cranelift_control::ControlPlane; +use cranelift_entity::{packed_option::ReservedValue, SecondaryMap}; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::{smallvec, SmallVec}; + +pub(crate) struct Elaborator<'a> { + func: &'a mut Function, + domtree: &'a DominatorTreePreorder, + loop_analysis: &'a LoopAnalysis, + /// Map from Value that is produced by a pure Inst (and was thus + /// not in the side-effecting skeleton) to the value produced by + /// an elaborated inst (placed in the layout) to whose results we + /// refer in the final code. + /// + /// The first time we use some result of an instruction during + /// elaboration, we can place it and insert an identity map (inst + /// results to that same inst's results) in this scoped + /// map. Within that block and its dom-tree children, that mapping + /// is visible and we can continue to use it. This allows us to + /// avoid cloning the instruction. However, if we pop that scope + /// and use it somewhere else as well, we will need to + /// duplicate. We detect this case by checking, when a value that + /// we want is not present in this map, whether the producing inst + /// is already placed in the Layout. If so, we duplicate, and + /// insert non-identity mappings from the original inst's results + /// to the cloned inst's results. + /// + /// Note that as values may refer to unions that represent a subset + /// of a larger eclass, it's not valid to walk towards the root of a + /// union tree: doing so would potentially equate values that fall + /// on different branches of the dominator tree. + value_to_elaborated_value: ScopedHashMap, + /// Map from Value to the best (lowest-cost) Value in its eclass + /// (tree of union value-nodes). + value_to_best_value: SecondaryMap, + /// Stack of blocks and loops in current elaboration path. + loop_stack: SmallVec<[LoopStackEntry; 8]>, + /// The current block into which we are elaborating. + cur_block: Block, + /// Values that opt rules have indicated should be rematerialized + /// in every block they are used (e.g., immediates or other + /// "cheap-to-compute" ops). + remat_values: &'a FxHashSet, + /// Explicitly-unrolled value elaboration stack. + elab_stack: Vec, + /// Results from the elab stack. + elab_result_stack: Vec, + /// Explicitly-unrolled block elaboration stack. + block_stack: Vec, + /// Copies of values that have been rematerialized. + remat_copies: FxHashMap<(Block, Value), Value>, + /// Stats for various events during egraph processing, to help + /// with optimization of this infrastructure. + stats: &'a mut Stats, + /// Chaos-mode control-plane so we can test that we still get + /// correct results when our heuristics make bad decisions. + ctrl_plane: &'a mut ControlPlane, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct BestEntry(Cost, Value); + +impl PartialOrd for BestEntry { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BestEntry { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0).then_with(|| { + // Note that this comparison is reversed. When costs are equal, + // prefer the value with the bigger index. This is a heuristic that + // prefers results of rewrites to the original value, since we + // expect that our rewrites are generally improvements. + self.1.cmp(&other.1).reverse() + }) + } +} + +#[derive(Clone, Copy, Debug)] +struct ElaboratedValue { + in_block: Block, + value: Value, +} + +#[derive(Clone, Debug)] +struct LoopStackEntry { + /// The loop identifier. + lp: Loop, + /// The hoist point: a block that immediately dominates this + /// loop. May not be an immediate predecessor, but will be a valid + /// point to place all loop-invariant ops: they must depend only + /// on inputs that dominate the loop, so are available at (the end + /// of) this block. + hoist_block: Block, + /// The depth in the scope map. + scope_depth: u32, +} + +#[derive(Clone, Debug)] +enum ElabStackEntry { + /// Next action is to resolve this value into an elaborated inst + /// (placed into the layout) that produces the value, and + /// recursively elaborate the insts that produce its args. + /// + /// Any inserted ops should be inserted before `before`, which is + /// the instruction demanding this value. + Start { value: Value, before: Inst }, + /// Args have been pushed; waiting for results. + PendingInst { + inst: Inst, + result_idx: usize, + num_args: usize, + before: Inst, + }, +} + +#[derive(Clone, Debug)] +enum BlockStackEntry { + Elaborate { block: Block, idom: Option }, + Pop, +} + +impl<'a> Elaborator<'a> { + pub(crate) fn new( + func: &'a mut Function, + domtree: &'a DominatorTreePreorder, + loop_analysis: &'a LoopAnalysis, + remat_values: &'a FxHashSet, + stats: &'a mut Stats, + ctrl_plane: &'a mut ControlPlane, + ) -> Self { + let num_values = func.dfg.num_values(); + let mut value_to_best_value = + SecondaryMap::with_default(BestEntry(Cost::infinity(), Value::reserved_value())); + value_to_best_value.resize(num_values); + Self { + func, + domtree, + loop_analysis, + value_to_elaborated_value: ScopedHashMap::with_capacity(num_values), + value_to_best_value, + loop_stack: smallvec![], + cur_block: Block::reserved_value(), + remat_values, + elab_stack: vec![], + elab_result_stack: vec![], + block_stack: vec![], + remat_copies: FxHashMap::default(), + stats, + ctrl_plane, + } + } + + fn start_block(&mut self, idom: Option, block: Block) { + trace!( + "start_block: block {:?} with idom {:?} at loop depth {:?} scope depth {}", + block, + idom, + self.loop_stack.len(), + self.value_to_elaborated_value.depth() + ); + + // Pop any loop levels we're no longer in. + while let Some(inner_loop) = self.loop_stack.last() { + if self.loop_analysis.is_in_loop(block, inner_loop.lp) { + break; + } + self.loop_stack.pop(); + } + + // Note that if the *entry* block is a loop header, we will + // not make note of the loop here because it will not have an + // immediate dominator. We must disallow this case because we + // will skip adding the `LoopStackEntry` here but our + // `LoopAnalysis` will otherwise still make note of this loop + // and loop depths will not match. + if let Some(idom) = idom { + if let Some(lp) = self.loop_analysis.is_loop_header(block) { + self.loop_stack.push(LoopStackEntry { + lp, + // Any code hoisted out of this loop will have code + // placed in `idom`, and will have def mappings + // inserted in to the scoped hashmap at that block's + // level. + hoist_block: idom, + scope_depth: (self.value_to_elaborated_value.depth() - 1) as u32, + }); + trace!( + " -> loop header, pushing; depth now {}", + self.loop_stack.len() + ); + } + } else { + debug_assert!( + self.loop_analysis.is_loop_header(block).is_none(), + "Entry block (domtree root) cannot be a loop header!" + ); + } + + trace!("block {}: loop stack is {:?}", block, self.loop_stack); + + self.cur_block = block; + } + + fn compute_best_values(&mut self) { + let best = &mut self.value_to_best_value; + + // We can't make random decisions inside the fixpoint loop below because + // that could cause values to change on every iteration of the loop, + // which would make the loop never terminate. So in chaos testing + // mode we need a form of making suboptimal decisions that is fully + // deterministic. We choose to simply make the worst decision we know + // how to do instead of the best. + let use_worst = self.ctrl_plane.get_decision(); + + // Do a fixpoint loop to compute the best value for each eclass. + // + // The maximum number of iterations is the length of the longest chain + // of `vNN -> vMM` edges in the dataflow graph where `NN < MM`, so this + // is *technically* quadratic, but `cranelift-frontend` won't construct + // any such edges. NaN canonicalization will introduce some of these + // edges, but they are chains of only two or three edges. So in + // practice, we *never* do more than a handful of iterations here unless + // (a) we parsed the CLIF from text and the text was funkily numbered, + // which we don't really care about, or (b) the CLIF producer did + // something weird, in which case it is their responsibility to stop + // doing that. + trace!( + "Entering fixpoint loop to compute the {} values for each eclass", + if use_worst { + "worst (chaos mode)" + } else { + "best" + } + ); + let mut keep_going = true; + while keep_going { + keep_going = false; + trace!( + "fixpoint iteration {}", + self.stats.elaborate_best_cost_fixpoint_iters + ); + self.stats.elaborate_best_cost_fixpoint_iters += 1; + + for (value, def) in self.func.dfg.values_and_defs() { + trace!("computing best for value {:?} def {:?}", value, def); + let orig_best_value = best[value]; + + match def { + ValueDef::Union(x, y) => { + // Pick the best of the two options based on + // min-cost. This works because each element of `best` + // is a `(cost, value)` tuple; `cost` comes first so + // the natural comparison works based on cost, and + // breaks ties based on value number. + best[value] = if use_worst { + if best[x].1.is_reserved_value() { + best[y] + } else if best[y].1.is_reserved_value() { + best[x] + } else { + std::cmp::max(best[x], best[y]) + } + } else { + std::cmp::min(best[x], best[y]) + }; + trace!( + " -> best of union({:?}, {:?}) = {:?}", + best[x], + best[y], + best[value] + ); + } + ValueDef::Param(_, _) => { + best[value] = BestEntry(Cost::zero(), value); + } + // If the Inst is inserted into the layout (which is, + // at this point, only the side-effecting skeleton), + // then it must be computed and thus we give it zero + // cost. + ValueDef::Result(inst, _) => { + if let Some(_) = self.func.layout.inst_block(inst) { + best[value] = BestEntry(Cost::zero(), value); + } else { + let inst_data = &self.func.dfg.insts[inst]; + // N.B.: at this point we know that the opcode is + // pure, so `pure_op_cost`'s precondition is + // satisfied. + let cost = Cost::of_pure_op( + inst_data.opcode(), + self.func.dfg.inst_values(inst).map(|value| best[value].0), + ); + best[value] = BestEntry(cost, value); + trace!(" -> cost of value {} = {:?}", value, cost); + } + } + }; + + // Keep on iterating the fixpoint loop while we are finding new + // best values. + keep_going |= orig_best_value != best[value]; + } + } + + if cfg!(any(feature = "trace-log", debug_assertions)) { + trace!("finished fixpoint loop to compute best value for each eclass"); + for value in self.func.dfg.values() { + trace!("-> best for eclass {:?}: {:?}", value, best[value]); + debug_assert_ne!(best[value].1, Value::reserved_value()); + // You might additionally be expecting an assert that the best + // cost is not infinity, however infinite cost *can* happen in + // practice. First, note that our cost function doesn't know + // about any shared structure in the dataflow graph, it only + // sums operand costs. (And trying to avoid that by deduping a + // single operation's operands is a losing game because you can + // always just add one indirection and go from `add(x, x)` to + // `add(foo(x), bar(x))` to hide the shared structure.) Given + // that blindness to sharing, we can make cost grow + // exponentially with a linear sequence of operations: + // + // v0 = iconst.i32 1 ;; cost = 1 + // v1 = iadd v0, v0 ;; cost = 3 + 1 + 1 + // v2 = iadd v1, v1 ;; cost = 3 + 5 + 5 + // v3 = iadd v2, v2 ;; cost = 3 + 13 + 13 + // v4 = iadd v3, v3 ;; cost = 3 + 29 + 29 + // v5 = iadd v4, v4 ;; cost = 3 + 61 + 61 + // v6 = iadd v5, v5 ;; cost = 3 + 125 + 125 + // ;; etc... + // + // Such a chain can cause cost to saturate to infinity. How do + // we choose which e-node is best when there are multiple that + // have saturated to infinity? It doesn't matter. As long as + // invariant (2) for optimization rules is upheld by our rule + // set (see `cranelift/codegen/src/opts/README.md`) it is safe + // to choose *any* e-node in the e-class. At worst we will + // produce suboptimal code, but never an incorrectness. + } + } + } + + /// Elaborate use of an eclass, inserting any needed new + /// instructions before the given inst `before`. Should only be + /// given values corresponding to results of instructions or + /// blockparams. + fn elaborate_eclass_use(&mut self, value: Value, before: Inst) -> ElaboratedValue { + debug_assert_ne!(value, Value::reserved_value()); + + // Kick off the process by requesting this result + // value. + self.elab_stack + .push(ElabStackEntry::Start { value, before }); + + // Now run the explicit-stack recursion until we reach + // the root. + self.process_elab_stack(); + debug_assert_eq!(self.elab_result_stack.len(), 1); + self.elab_result_stack.pop().unwrap() + } + + /// Possibly rematerialize the instruction producing the value in + /// `arg` and rewrite `arg` to refer to it, if needed. Returns + /// `true` if a rewrite occurred. + fn maybe_remat_arg( + remat_values: &FxHashSet, + func: &mut Function, + remat_copies: &mut FxHashMap<(Block, Value), Value>, + insert_block: Block, + before: Inst, + arg: &mut ElaboratedValue, + stats: &mut Stats, + ) -> bool { + // TODO (#7313): we may want to consider recursive + // rematerialization as well. We could process the arguments of + // the rematerialized instruction up to a certain depth. This + // would affect, e.g., adds-with-one-constant-arg, which are + // currently rematerialized. Right now we don't do this, to + // avoid the need for another fixpoint loop here. + if arg.in_block != insert_block && remat_values.contains(&arg.value) { + let new_value = match remat_copies.entry((insert_block, arg.value)) { + HashEntry::Occupied(o) => *o.get(), + HashEntry::Vacant(v) => { + let inst = func.dfg.value_def(arg.value).inst().unwrap(); + debug_assert_eq!(func.dfg.inst_results(inst).len(), 1); + let new_inst = func.dfg.clone_inst(inst); + func.layout.insert_inst(new_inst, before); + let new_result = func.dfg.inst_results(new_inst)[0]; + *v.insert(new_result) + } + }; + trace!("rematerialized {} as {}", arg.value, new_value); + arg.value = new_value; + stats.elaborate_remat += 1; + true + } else { + false + } + } + + fn process_elab_stack(&mut self) { + while let Some(entry) = self.elab_stack.pop() { + match entry { + ElabStackEntry::Start { value, before } => { + debug_assert!(self.func.dfg.value_is_real(value)); + + self.stats.elaborate_visit_node += 1; + + // Get the best option; we use `value` (latest + // value) here so we have a full view of the + // eclass. + trace!("looking up best value for {}", value); + let BestEntry(_, best_value) = self.value_to_best_value[value]; + trace!("elaborate: value {} -> best {}", value, best_value); + debug_assert_ne!(best_value, Value::reserved_value()); + + if let Some(elab_val) = self.value_to_elaborated_value.get(&best_value) { + // Value is available; use it. + trace!("elaborate: value {} -> {:?}", value, elab_val); + self.stats.elaborate_memoize_hit += 1; + self.elab_result_stack.push(*elab_val); + continue; + } + + self.stats.elaborate_memoize_miss += 1; + + // Now resolve the value to its definition to see + // how we can compute it. + let (inst, result_idx) = match self.func.dfg.value_def(best_value) { + ValueDef::Result(inst, result_idx) => { + trace!( + " -> value {} is result {} of {}", + best_value, + result_idx, + inst + ); + (inst, result_idx) + } + ValueDef::Param(in_block, _) => { + // We don't need to do anything to compute + // this value; just push its result on the + // result stack (blockparams are already + // available). + trace!(" -> value {} is a blockparam", best_value); + self.elab_result_stack.push(ElaboratedValue { + in_block, + value: best_value, + }); + continue; + } + ValueDef::Union(_, _) => { + panic!("Should never have a Union value as the best value"); + } + }; + + trace!( + " -> result {} of inst {:?}", + result_idx, + self.func.dfg.insts[inst] + ); + + // We're going to need to use this instruction + // result, placing the instruction into the + // layout. First, enqueue all args to be + // elaborated. Push state to receive the results + // and later elab this inst. + let num_args = self.func.dfg.inst_values(inst).count(); + self.elab_stack.push(ElabStackEntry::PendingInst { + inst, + result_idx, + num_args, + before, + }); + + // Push args in reverse order so we process the + // first arg first. + for arg in self.func.dfg.inst_values(inst).rev() { + debug_assert_ne!(arg, Value::reserved_value()); + self.elab_stack + .push(ElabStackEntry::Start { value: arg, before }); + } + } + + ElabStackEntry::PendingInst { + inst, + result_idx, + num_args, + before, + } => { + trace!( + "PendingInst: {} result {} args {} before {}", + inst, + result_idx, + num_args, + before + ); + + // We should have all args resolved at this + // point. Grab them and drain them out, removing + // them. + let arg_idx = self.elab_result_stack.len() - num_args; + let arg_values = &mut self.elab_result_stack[arg_idx..]; + + // Compute max loop depth. + // + // Note that if there are no arguments then this instruction + // is allowed to get hoisted up one loop. This is not + // usually used since no-argument values are things like + // constants which are typically rematerialized, but for the + // `vconst` instruction 128-bit constants aren't as easily + // rematerialized. They're hoisted out of inner loops but + // not to the function entry which may run the risk of + // placing too much register pressure on the entire + // function. This is modeled with the `.saturating_sub(1)` + // as the default if there's otherwise no maximum. + let loop_hoist_level = arg_values + .iter() + .map(|&value| { + // Find the outermost loop level at which + // the value's defining block *is not* a + // member. This is the loop-nest level + // whose hoist-block we hoist to. + let hoist_level = self + .loop_stack + .iter() + .position(|loop_entry| { + !self.loop_analysis.is_in_loop(value.in_block, loop_entry.lp) + }) + .unwrap_or(self.loop_stack.len()); + trace!( + " -> arg: elab_value {:?} hoist level {:?}", + value, + hoist_level + ); + hoist_level + }) + .max() + .unwrap_or(self.loop_stack.len().saturating_sub(1)); + trace!( + " -> loop hoist level: {:?}; cur loop depth: {:?}, loop_stack: {:?}", + loop_hoist_level, + self.loop_stack.len(), + self.loop_stack, + ); + + // We know that this is a pure inst, because + // non-pure roots have already been placed in the + // value-to-elab'd-value map, so they will not + // reach this stage of processing. + // + // We now must determine the location at which we + // place the instruction. This is the current + // block *unless* we hoist above a loop when all + // args are loop-invariant (and this op is pure). + let (scope_depth, before, insert_block) = + if loop_hoist_level == self.loop_stack.len() { + // Depends on some value at the current + // loop depth, or remat forces it here: + // place it at the current location. + ( + self.value_to_elaborated_value.depth(), + before, + self.func.layout.inst_block(before).unwrap(), + ) + } else { + // Does not depend on any args at current + // loop depth: hoist out of loop. + self.stats.elaborate_licm_hoist += 1; + let data = &self.loop_stack[loop_hoist_level]; + // `data.hoist_block` should dominate `before`'s block. + let before_block = self.func.layout.inst_block(before).unwrap(); + debug_assert!(self.domtree.dominates(data.hoist_block, before_block)); + // Determine the instruction at which we + // insert in `data.hoist_block`. + let before = self.func.layout.last_inst(data.hoist_block).unwrap(); + (data.scope_depth as usize, before, data.hoist_block) + }; + + trace!( + " -> decided to place: before {} insert_block {}", + before, + insert_block + ); + + // Now that we have the location for the + // instruction, check if any of its args are remat + // values. If so, and if we don't have a copy of + // the rematerializing instruction for this block + // yet, create one. + let mut remat_arg = false; + for arg_value in arg_values.iter_mut() { + if Self::maybe_remat_arg( + &self.remat_values, + &mut self.func, + &mut self.remat_copies, + insert_block, + before, + arg_value, + &mut self.stats, + ) { + remat_arg = true; + } + } + + // Now we need to place `inst` at the computed + // location (just before `before`). Note that + // `inst` may already have been placed somewhere + // else, because a pure node may be elaborated at + // more than one place. In this case, we need to + // duplicate the instruction (and return the + // `Value`s for that duplicated instance instead). + // + // Also clone if we rematerialized, because we + // don't want to rewrite the args in the original + // copy. + trace!("need inst {} before {}", inst, before); + let inst = if self.func.layout.inst_block(inst).is_some() || remat_arg { + // Clone the inst! + let new_inst = self.func.dfg.clone_inst(inst); + trace!( + " -> inst {} already has a location; cloned to {}", + inst, + new_inst + ); + // Create mappings in the + // value-to-elab'd-value map from original + // results to cloned results. + for (&result, &new_result) in self + .func + .dfg + .inst_results(inst) + .iter() + .zip(self.func.dfg.inst_results(new_inst).iter()) + { + let elab_value = ElaboratedValue { + value: new_result, + in_block: insert_block, + }; + let best_result = self.value_to_best_value[result]; + self.value_to_elaborated_value.insert_if_absent_with_depth( + best_result.1, + elab_value, + scope_depth, + ); + + self.value_to_best_value[new_result] = best_result; + + trace!( + " -> cloned inst has new result {} for orig {}", + new_result, + result + ); + } + new_inst + } else { + trace!(" -> no location; using original inst"); + // Create identity mappings from result values + // to themselves in this scope, since we're + // using the original inst. + for &result in self.func.dfg.inst_results(inst) { + let elab_value = ElaboratedValue { + value: result, + in_block: insert_block, + }; + let best_result = self.value_to_best_value[result]; + self.value_to_elaborated_value.insert_if_absent_with_depth( + best_result.1, + elab_value, + scope_depth, + ); + trace!(" -> inserting identity mapping for {}", result); + } + inst + }; + + // Place the inst just before `before`. + assert!( + is_pure_for_egraph(self.func, inst), + "something has gone very wrong if we are elaborating effectful \ + instructions, they should have remained in the skeleton" + ); + self.func.layout.insert_inst(inst, before); + + // Update the inst's arguments. + self.func + .dfg + .overwrite_inst_values(inst, arg_values.into_iter().map(|ev| ev.value)); + + // Now that we've consumed the arg values, pop + // them off the stack. + self.elab_result_stack.truncate(arg_idx); + + // Push the requested result index of the + // instruction onto the elab-results stack. + self.elab_result_stack.push(ElaboratedValue { + in_block: insert_block, + value: self.func.dfg.inst_results(inst)[result_idx], + }); + } + } + } + } + + fn elaborate_block(&mut self, elab_values: &mut Vec, idom: Option, block: Block) { + trace!("elaborate_block: block {}", block); + self.start_block(idom, block); + + // Iterate over the side-effecting skeleton using the linked + // list in Layout. We will insert instructions that are + // elaborated *before* `inst`, so we can always use its + // next-link to continue the iteration. + let mut next_inst = self.func.layout.first_inst(block); + let mut first_branch = None; + while let Some(inst) = next_inst { + trace!( + "elaborating inst {} with results {:?}", + inst, + self.func.dfg.inst_results(inst) + ); + // Record the first branch we see in the block; all + // elaboration for args of *any* branch must be inserted + // before the *first* branch, because the branch group + // must remain contiguous at the end of the block. + if self.func.dfg.insts[inst].opcode().is_branch() && first_branch == None { + first_branch = Some(inst); + } + + // Determine where elaboration inserts insts. + let before = first_branch.unwrap_or(inst); + trace!(" -> inserting before {}", before); + + elab_values.extend(self.func.dfg.inst_values(inst)); + for arg in elab_values.iter_mut() { + trace!(" -> arg {}", *arg); + // Elaborate the arg, placing any newly-inserted insts + // before `before`. Get the updated value, which may + // be different than the original. + let mut new_arg = self.elaborate_eclass_use(*arg, before); + Self::maybe_remat_arg( + &self.remat_values, + &mut self.func, + &mut self.remat_copies, + block, + inst, + &mut new_arg, + &mut self.stats, + ); + trace!(" -> rewrote arg to {:?}", new_arg); + *arg = new_arg.value; + } + self.func + .dfg + .overwrite_inst_values(inst, elab_values.drain(..)); + + // We need to put the results of this instruction in the + // map now. + for &result in self.func.dfg.inst_results(inst) { + trace!(" -> result {}", result); + let best_result = self.value_to_best_value[result]; + self.value_to_elaborated_value.insert_if_absent( + best_result.1, + ElaboratedValue { + in_block: block, + value: result, + }, + ); + } + + next_inst = self.func.layout.next_inst(inst); + } + } + + fn elaborate_domtree(&mut self, domtree: &DominatorTreePreorder) { + self.block_stack.push(BlockStackEntry::Elaborate { + block: self.func.layout.entry_block().unwrap(), + idom: None, + }); + + // A temporary workspace for elaborate_block, allocated here to maximize the use of the + // allocation. + let mut elab_values = Vec::new(); + + while let Some(top) = self.block_stack.pop() { + match top { + BlockStackEntry::Elaborate { block, idom } => { + self.block_stack.push(BlockStackEntry::Pop); + self.value_to_elaborated_value.increment_depth(); + + self.elaborate_block(&mut elab_values, idom, block); + + // Push children. We are doing a preorder + // traversal so we do this after processing this + // block above. + let block_stack_end = self.block_stack.len(); + for child in self.ctrl_plane.shuffled(domtree.children(block)) { + self.block_stack.push(BlockStackEntry::Elaborate { + block: child, + idom: Some(block), + }); + } + // Reverse what we just pushed so we elaborate in + // original block order. (The domtree iter is a + // single-ended iter over a singly-linked list so + // we can't `.rev()` above.) + self.block_stack[block_stack_end..].reverse(); + } + BlockStackEntry::Pop => { + self.value_to_elaborated_value.decrement_depth(); + } + } + } + } + + pub(crate) fn elaborate(&mut self) { + self.stats.elaborate_func += 1; + self.stats.elaborate_func_pre_insts += self.func.dfg.num_insts() as u64; + self.compute_best_values(); + self.elaborate_domtree(&self.domtree); + self.stats.elaborate_func_post_insts += self.func.dfg.num_insts() as u64; + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/flowgraph.rs b/deps/crates/vendor/cranelift-codegen/src/flowgraph.rs new file mode 100644 index 00000000000000..b57af31055d00b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/flowgraph.rs @@ -0,0 +1,349 @@ +//! A control flow graph represented as mappings of basic blocks to their predecessors +//! and successors. +//! +//! Successors are represented as basic blocks while predecessors are represented by basic +//! blocks. Basic blocks are denoted by tuples of block and branch/jump instructions. Each +//! predecessor tuple corresponds to the end of a basic block. +//! +//! ```c +//! Block0: +//! ... ; beginning of basic block +//! +//! ... +//! +//! brif vx, Block1, Block2 ; end of basic block +//! +//! Block1: +//! jump block3 +//! ``` +//! +//! Here `Block1` and `Block2` would each have a single predecessor denoted as `(Block0, brif)`, +//! while `Block3` would have a single predecessor denoted as `(Block1, jump block3)`. + +use crate::bforest; +use crate::entity::SecondaryMap; +use crate::inst_predicates; +use crate::ir::{Block, Function, Inst}; +use crate::timing; +use core::mem; + +/// A basic block denoted by its enclosing Block and last instruction. +#[derive(Debug, PartialEq, Eq)] +pub struct BlockPredecessor { + /// Enclosing Block key. + pub block: Block, + /// Last instruction in the basic block. + pub inst: Inst, +} + +impl BlockPredecessor { + /// Convenient method to construct new BlockPredecessor. + pub fn new(block: Block, inst: Inst) -> Self { + Self { block, inst } + } +} + +/// A container for the successors and predecessors of some Block. +#[derive(Clone, Default)] +struct CFGNode { + /// Instructions that can branch or jump to this block. + /// + /// This maps branch instruction -> predecessor block which is redundant since the block containing + /// the branch instruction is available from the `layout.inst_block()` method. We store the + /// redundant information because: + /// + /// 1. Many `pred_iter()` consumers want the block anyway, so it is handily available. + /// 2. The `invalidate_block_successors()` may be called *after* branches have been removed from + /// their block, but we still need to remove them form the old block predecessor map. + /// + /// The redundant block stored here is always consistent with the CFG successor lists, even after + /// the IR has been edited. + pub predecessors: bforest::Map, + + /// Set of blocks that are the targets of branches and jumps in this block. + /// The set is ordered by block number, indicated by the `()` comparator type. + pub successors: bforest::Set, +} + +/// The Control Flow Graph maintains a mapping of blocks to their predecessors +/// and successors where predecessors are basic blocks and successors are +/// basic blocks. +pub struct ControlFlowGraph { + data: SecondaryMap, + pred_forest: bforest::MapForest, + succ_forest: bforest::SetForest, + valid: bool, +} + +impl ControlFlowGraph { + /// Allocate a new blank control flow graph. + pub fn new() -> Self { + Self { + data: SecondaryMap::new(), + valid: false, + pred_forest: bforest::MapForest::new(), + succ_forest: bforest::SetForest::new(), + } + } + + /// Clear all data structures in this control flow graph. + pub fn clear(&mut self) { + self.data.clear(); + self.pred_forest.clear(); + self.succ_forest.clear(); + self.valid = false; + } + + /// Allocate and compute the control flow graph for `func`. + pub fn with_function(func: &Function) -> Self { + let mut cfg = Self::new(); + cfg.compute(func); + cfg + } + + /// Compute the control flow graph of `func`. + /// + /// This will clear and overwrite any information already stored in this data structure. + pub fn compute(&mut self, func: &Function) { + let _tt = timing::flowgraph(); + self.clear(); + self.data.resize(func.dfg.num_blocks()); + + for block in &func.layout { + self.compute_block(func, block); + } + + self.valid = true; + } + + fn compute_block(&mut self, func: &Function, block: Block) { + inst_predicates::visit_block_succs(func, block, |inst, dest, _| { + self.add_edge(block, inst, dest); + }); + } + + fn invalidate_block_successors(&mut self, block: Block) { + // Temporarily take ownership because we need mutable access to self.data inside the loop. + // Unfortunately borrowck cannot see that our mut accesses to predecessors don't alias + // our iteration over successors. + let mut successors = mem::replace(&mut self.data[block].successors, Default::default()); + for succ in successors.iter(&self.succ_forest) { + self.data[succ] + .predecessors + .retain(&mut self.pred_forest, |_, &mut e| e != block); + } + successors.clear(&mut self.succ_forest); + } + + /// Recompute the control flow graph of `block`. + /// + /// This is for use after modifying instructions within a specific block. It recomputes all edges + /// from `block` while leaving edges to `block` intact. Its functionality a subset of that of the + /// more expensive `compute`, and should be used when we know we don't need to recompute the CFG + /// from scratch, but rather that our changes have been restricted to specific blocks. + pub fn recompute_block(&mut self, func: &Function, block: Block) { + debug_assert!(self.is_valid()); + self.invalidate_block_successors(block); + self.compute_block(func, block); + } + + fn add_edge(&mut self, from: Block, from_inst: Inst, to: Block) { + self.data[from] + .successors + .insert(to, &mut self.succ_forest, &()); + self.data[to] + .predecessors + .insert(from_inst, from, &mut self.pred_forest, &()); + } + + /// Get an iterator over the CFG predecessors to `block`. + pub fn pred_iter(&self, block: Block) -> PredIter { + PredIter(self.data[block].predecessors.iter(&self.pred_forest)) + } + + /// Get an iterator over the CFG successors to `block`. + pub fn succ_iter(&self, block: Block) -> SuccIter { + debug_assert!(self.is_valid()); + self.data[block].successors.iter(&self.succ_forest) + } + + /// Check if the CFG is in a valid state. + /// + /// Note that this doesn't perform any kind of validity checks. It simply checks if the + /// `compute()` method has been called since the last `clear()`. It does not check that the + /// CFG is consistent with the function. + pub fn is_valid(&self) -> bool { + self.valid + } +} + +/// An iterator over block predecessors. The iterator type is `BlockPredecessor`. +/// +/// Each predecessor is an instruction that branches to the block. +pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Block>); + +impl<'a> Iterator for PredIter<'a> { + type Item = BlockPredecessor; + + fn next(&mut self) -> Option { + self.0.next().map(|(i, e)| BlockPredecessor::new(e, i)) + } +} + +/// An iterator over block successors. The iterator type is `Block`. +pub type SuccIter<'a> = bforest::SetIter<'a, Block>; + +#[cfg(test)] +mod tests { + use super::*; + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::{types, InstBuilder}; + use alloc::vec::Vec; + + #[test] + fn empty() { + let func = Function::new(); + ControlFlowGraph::with_function(&func); + } + + #[test] + fn no_predecessors() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + func.layout.append_block(block0); + func.layout.append_block(block1); + func.layout.append_block(block2); + + let cfg = ControlFlowGraph::with_function(&func); + + let mut fun_blocks = func.layout.blocks(); + for block in func.layout.blocks() { + assert_eq!(block, fun_blocks.next().unwrap()); + assert_eq!(cfg.pred_iter(block).count(), 0); + assert_eq!(cfg.succ_iter(block).count(), 0); + } + } + + #[test] + fn branches_and_jumps() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let cond = func.dfg.append_block_param(block0, types::I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + + let br_block0_block2_block1; + let br_block1_block1_block2; + + { + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + br_block0_block2_block1 = cur.ins().brif(cond, block2, &[], block1, &[]); + + cur.insert_block(block1); + br_block1_block1_block2 = cur.ins().brif(cond, block1, &[], block2, &[]); + + cur.insert_block(block2); + } + + let mut cfg = ControlFlowGraph::with_function(&func); + + { + let block0_predecessors = cfg.pred_iter(block0).collect::>(); + let block1_predecessors = cfg.pred_iter(block1).collect::>(); + let block2_predecessors = cfg.pred_iter(block2).collect::>(); + + let block0_successors = cfg.succ_iter(block0).collect::>(); + let block1_successors = cfg.succ_iter(block1).collect::>(); + let block2_successors = cfg.succ_iter(block2).collect::>(); + + assert_eq!(block0_predecessors.len(), 0); + assert_eq!(block1_predecessors.len(), 2); + assert_eq!(block2_predecessors.len(), 2); + + assert_eq!( + block1_predecessors + .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)), + true + ); + assert_eq!( + block1_predecessors + .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), + true + ); + assert_eq!( + block2_predecessors + .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)), + true + ); + assert_eq!( + block2_predecessors + .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), + true + ); + + assert_eq!(block0_successors, [block1, block2]); + assert_eq!(block1_successors, [block1, block2]); + assert_eq!(block2_successors, []); + } + + // Add a new block to hold a return instruction + let ret_block = func.dfg.make_block(); + + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(ret_block); + cur.ins().return_(&[]); + } + + // Change some instructions and recompute block0 and ret_block + func.dfg + .replace(br_block0_block2_block1) + .brif(cond, block1, &[], ret_block, &[]); + cfg.recompute_block(&func, block0); + cfg.recompute_block(&func, ret_block); + let br_block0_block1_ret_block = br_block0_block2_block1; + + { + let block0_predecessors = cfg.pred_iter(block0).collect::>(); + let block1_predecessors = cfg.pred_iter(block1).collect::>(); + let block2_predecessors = cfg.pred_iter(block2).collect::>(); + + let block0_successors = cfg.succ_iter(block0); + let block1_successors = cfg.succ_iter(block1); + let block2_successors = cfg.succ_iter(block2); + + assert_eq!(block0_predecessors.len(), 0); + assert_eq!(block1_predecessors.len(), 2); + assert_eq!(block2_predecessors.len(), 1); + + assert_eq!( + block1_predecessors + .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)), + true + ); + assert_eq!( + block1_predecessors + .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), + true + ); + assert_eq!( + block2_predecessors + .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)), + false + ); + assert_eq!( + block2_predecessors + .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), + true + ); + + assert_eq!(block0_successors.collect::>(), [block1, ret_block]); + assert_eq!(block1_successors.collect::>(), [block1, block2]); + assert_eq!(block2_successors.collect::>(), []); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/incremental_cache.rs b/deps/crates/vendor/cranelift-codegen/src/incremental_cache.rs new file mode 100644 index 00000000000000..89e42cf242a010 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/incremental_cache.rs @@ -0,0 +1,256 @@ +//! This module provides a set of primitives that allow implementing an incremental cache on top of +//! Cranelift, making it possible to reuse previous compiled artifacts for functions that have been +//! compiled previously. +//! +//! This set of operation is experimental and can be enabled using the Cargo feature +//! `incremental-cache`. +//! +//! This can bring speedups in different cases: change-code-and-immediately-recompile iterations +//! get faster, modules sharing lots of code can reuse each other's artifacts, etc. +//! +//! The three main primitives are the following: +//! - `compute_cache_key` is used to compute the cache key associated to a `Function`. This is +//! basically the content of the function, modulo a few things the caching system is resilient to. +//! - `serialize_compiled` is used to serialize the result of a compilation, so it can be reused +//! later on by... +//! - `try_finish_recompile`, which reads binary blobs serialized with `serialize_compiled`, +//! re-creating the compilation artifact from those. +//! +//! The `CacheStore` trait and `Context::compile_with_cache` method are provided as +//! high-level, easy-to-use facilities to make use of that cache, and show an example of how to use +//! the above three primitives to form a full incremental caching system. + +use core::fmt; + +use crate::alloc::string::String; +use crate::alloc::vec::Vec; +use crate::ir::function::{FunctionStencil, VersionMarker}; +use crate::ir::Function; +use crate::machinst::{CompiledCode, CompiledCodeStencil}; +use crate::result::CompileResult; +use crate::{isa::TargetIsa, timing}; +use crate::{trace, CompileError, Context}; +use alloc::borrow::{Cow, ToOwned as _}; +use alloc::string::ToString as _; +use cranelift_control::ControlPlane; + +impl Context { + /// Compile the function, as in `compile`, but tries to reuse compiled artifacts from former + /// compilations using the provided cache store. + pub fn compile_with_cache( + &mut self, + isa: &dyn TargetIsa, + cache_store: &mut dyn CacheKvStore, + ctrl_plane: &mut ControlPlane, + ) -> CompileResult<(&CompiledCode, bool)> { + let cache_key_hash = { + let _tt = timing::try_incremental_cache(); + + let cache_key_hash = compute_cache_key(isa, &self.func); + + if let Some(blob) = cache_store.get(&cache_key_hash.0) { + match try_finish_recompile(&self.func, &blob) { + Ok(compiled_code) => { + let info = compiled_code.code_info(); + + if isa.flags().enable_incremental_compilation_cache_checks() { + let actual_result = self.compile(isa, ctrl_plane)?; + assert_eq!(*actual_result, compiled_code); + assert_eq!(actual_result.code_info(), info); + // no need to set `compiled_code` here, it's set by `compile()`. + return Ok((actual_result, true)); + } + + let compiled_code = self.compiled_code.insert(compiled_code); + return Ok((compiled_code, true)); + } + Err(err) => { + trace!("error when finishing recompilation: {err}"); + } + } + } + + cache_key_hash + }; + + let stencil = self + .compile_stencil(isa, ctrl_plane) + .map_err(|err| CompileError { + inner: err, + func: &self.func, + })?; + + let stencil = { + let _tt = timing::store_incremental_cache(); + let (stencil, res) = serialize_compiled(stencil); + if let Ok(blob) = res { + cache_store.insert(&cache_key_hash.0, blob); + } + stencil + }; + + let compiled_code = self + .compiled_code + .insert(stencil.apply_params(&self.func.params)); + + Ok((compiled_code, false)) + } +} + +/// Backing storage for an incremental compilation cache, when enabled. +pub trait CacheKvStore { + /// Given a cache key hash, retrieves the associated opaque serialized data. + fn get(&self, key: &[u8]) -> Option>; + + /// Given a new cache key and a serialized blob obtained from `serialize_compiled`, stores it + /// in the cache store. + fn insert(&mut self, key: &[u8], val: Vec); +} + +/// Hashed `CachedKey`, to use as an identifier when looking up whether a function has already been +/// compiled or not. +#[derive(Clone, Hash, PartialEq, Eq)] +pub struct CacheKeyHash([u8; 32]); + +impl std::fmt::Display for CacheKeyHash { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "CacheKeyHash:{:?}", self.0) + } +} + +#[derive(serde_derive::Serialize, serde_derive::Deserialize)] +struct CachedFunc { + // Note: The version marker must be first to ensure deserialization stops in case of a version + // mismatch before attempting to deserialize the actual compiled code. + version_marker: VersionMarker, + stencil: CompiledCodeStencil, +} + +/// Key for caching a single function's compilation. +/// +/// If two functions get the same `CacheKey`, then we can reuse the compiled artifacts, modulo some +/// fixups. +/// +/// Note: the key will be invalidated across different versions of cranelift, as the +/// `FunctionStencil` contains a `VersionMarker` itself. +#[derive(Hash)] +struct CacheKey<'a> { + stencil: &'a FunctionStencil, + parameters: CompileParameters, +} + +#[derive(Clone, PartialEq, Hash, serde_derive::Serialize, serde_derive::Deserialize)] +struct CompileParameters { + isa: String, + triple: String, + flags: String, + isa_flags: Vec, +} + +impl CompileParameters { + fn from_isa(isa: &dyn TargetIsa) -> Self { + Self { + isa: isa.name().to_owned(), + triple: isa.triple().to_string(), + flags: isa.flags().to_string(), + isa_flags: isa + .isa_flags() + .into_iter() + .map(|v| v.value_string()) + .collect(), + } + } +} + +impl<'a> CacheKey<'a> { + /// Creates a new cache store key for a function. + /// + /// This is a bit expensive to compute, so it should be cached and reused as much as possible. + fn new(isa: &dyn TargetIsa, f: &'a Function) -> Self { + CacheKey { + stencil: &f.stencil, + parameters: CompileParameters::from_isa(isa), + } + } +} + +/// Compute a cache key, and hash it on your behalf. +/// +/// Since computing the `CacheKey` is a bit expensive, it should be done as least as possible. +pub fn compute_cache_key(isa: &dyn TargetIsa, func: &Function) -> CacheKeyHash { + use core::hash::{Hash as _, Hasher}; + use sha2::Digest as _; + + struct Sha256Hasher(sha2::Sha256); + + impl Hasher for Sha256Hasher { + fn finish(&self) -> u64 { + panic!("Sha256Hasher doesn't support finish!"); + } + fn write(&mut self, bytes: &[u8]) { + self.0.update(bytes); + } + } + + let cache_key = CacheKey::new(isa, func); + + let mut hasher = Sha256Hasher(sha2::Sha256::new()); + cache_key.hash(&mut hasher); + let hash: [u8; 32] = hasher.0.finalize().into(); + + CacheKeyHash(hash) +} + +/// Given a function that's been successfully compiled, serialize it to a blob that the caller may +/// store somewhere for future use by `try_finish_recompile`. +/// +/// As this function requires ownership on the `CompiledCodeStencil`, it gives it back at the end +/// of the function call. The value is left untouched. +pub fn serialize_compiled( + result: CompiledCodeStencil, +) -> (CompiledCodeStencil, Result, postcard::Error>) { + let cached = CachedFunc { + version_marker: VersionMarker, + stencil: result, + }; + let result = postcard::to_allocvec(&cached); + (cached.stencil, result) +} + +/// An error returned when recompiling failed. +#[derive(Debug)] +pub enum RecompileError { + /// The version embedded in the cache entry isn't the same as cranelift's current version. + VersionMismatch, + /// An error occurred while deserializing the cache entry. + Deserialize(postcard::Error), +} + +impl fmt::Display for RecompileError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RecompileError::VersionMismatch => write!(f, "cranelift version mismatch",), + RecompileError::Deserialize(err) => { + write!(f, "postcard failed during deserialization: {err}") + } + } + } +} + +/// Given a function that's been precompiled and its entry in the caching storage, try to shortcut +/// compilation of the given function. +/// +/// Precondition: the bytes must have retrieved from a cache store entry which hash value +/// is strictly the same as the `Function`'s computed hash retrieved from `compute_cache_key`. +pub fn try_finish_recompile(func: &Function, bytes: &[u8]) -> Result { + match postcard::from_bytes::(bytes) { + Ok(result) => { + if result.version_marker != func.stencil.version_marker { + Err(RecompileError::VersionMismatch) + } else { + Ok(result.stencil.apply_params(&func.params)) + } + } + Err(err) => Err(RecompileError::Deserialize(err)), + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/inst_predicates.rs b/deps/crates/vendor/cranelift-codegen/src/inst_predicates.rs new file mode 100644 index 00000000000000..e0000b726ee555 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/inst_predicates.rs @@ -0,0 +1,207 @@ +//! Instruction predicates/properties, shared by various analyses. +use crate::ir::immediates::Offset32; +use crate::ir::{self, Block, Function, Inst, InstructionData, Opcode, Type, Value}; + +/// Test whether the given opcode is unsafe to even consider as side-effect-free. +#[inline(always)] +fn trivially_has_side_effects(opcode: Opcode) -> bool { + opcode.is_call() + || opcode.is_branch() + || opcode.is_terminator() + || opcode.is_return() + || opcode.can_trap() + || opcode.other_side_effects() + || opcode.can_store() +} + +/// Load instructions without the `notrap` flag are defined to trap when +/// operating on inaccessible memory, so we can't treat them as side-effect-free even if the loaded +/// value is unused. +#[inline(always)] +fn is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool { + if !opcode.can_load() { + return false; + } + match *data { + InstructionData::StackLoad { .. } => false, + InstructionData::Load { flags, .. } => !flags.notrap(), + _ => true, + } +} + +/// Does the given instruction have any side-effect that would preclude it from being removed when +/// its value is unused? +#[inline(always)] +fn has_side_effect(func: &Function, inst: Inst) -> bool { + let data = &func.dfg.insts[inst]; + let opcode = data.opcode(); + trivially_has_side_effects(opcode) || is_load_with_defined_trapping(opcode, data) +} + +/// Does the given instruction behave as a "pure" node with respect to +/// aegraph semantics? +/// +/// - Actual pure nodes (arithmetic, etc) +/// - Loads with the `readonly` flag set +pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool { + let is_readonly_load = match func.dfg.insts[inst] { + InstructionData::Load { + opcode: Opcode::Load, + flags, + .. + } => flags.readonly() && flags.notrap(), + _ => false, + }; + + // Multi-value results do not play nicely with much of the egraph + // infrastructure. They are in practice used only for multi-return + // calls and some other odd instructions (e.g. uadd_overflow) which, + // for now, we can afford to leave in place as opaque + // side-effecting ops. So if more than one result, then the inst + // is "not pure". Similarly, ops with zero results can be used + // only for their side-effects, so are never pure. (Or if they + // are, we can always trivially eliminate them with no effect.) + let has_one_result = func.dfg.inst_results(inst).len() == 1; + + let op = func.dfg.insts[inst].opcode(); + + has_one_result && (is_readonly_load || (!op.can_load() && !trivially_has_side_effects(op))) +} + +/// Can the given instruction be merged into another copy of itself? +/// These instructions may have side-effects, but as long as we retain +/// the first instance of the instruction, the second and further +/// instances are redundant if they would produce the same trap or +/// result. +pub fn is_mergeable_for_egraph(func: &Function, inst: Inst) -> bool { + let op = func.dfg.insts[inst].opcode(); + // We can only merge one-result operators due to the way that GVN + // is structured in the egraph implementation. + let has_one_result = func.dfg.inst_results(inst).len() == 1; + has_one_result + // Loads/stores are handled by alias analysis and not + // otherwise mergeable. + && !op.can_load() + && !op.can_store() + // Can only have idempotent side-effects. + && (!has_side_effect(func, inst) || op.side_effects_idempotent()) +} + +/// Does the given instruction have any side-effect as per [has_side_effect], or else is a load, +/// but not the get_pinned_reg opcode? +pub fn has_lowering_side_effect(func: &Function, inst: Inst) -> bool { + let op = func.dfg.insts[inst].opcode(); + op != Opcode::GetPinnedReg && (has_side_effect(func, inst) || op.can_load()) +} + +/// Is the given instruction a constant value (`iconst`, `fconst`) that can be +/// represented in 64 bits? +pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option { + match &func.dfg.insts[inst] { + &InstructionData::UnaryImm { imm, .. } => Some(imm.bits() as u64), + &InstructionData::UnaryIeee16 { imm, .. } => Some(imm.bits() as u64), + &InstructionData::UnaryIeee32 { imm, .. } => Some(imm.bits() as u64), + &InstructionData::UnaryIeee64 { imm, .. } => Some(imm.bits()), + _ => None, + } +} + +/// Get the address, offset, and access type from the given instruction, if any. +pub fn inst_addr_offset_type(func: &Function, inst: Inst) -> Option<(Value, Offset32, Type)> { + match &func.dfg.insts[inst] { + InstructionData::Load { arg, offset, .. } => { + let ty = func.dfg.value_type(func.dfg.inst_results(inst)[0]); + Some((*arg, *offset, ty)) + } + InstructionData::LoadNoOffset { arg, .. } => { + let ty = func.dfg.value_type(func.dfg.inst_results(inst)[0]); + Some((*arg, 0.into(), ty)) + } + InstructionData::Store { args, offset, .. } => { + let ty = func.dfg.value_type(args[0]); + Some((args[1], *offset, ty)) + } + InstructionData::StoreNoOffset { args, .. } => { + let ty = func.dfg.value_type(args[0]); + Some((args[1], 0.into(), ty)) + } + _ => None, + } +} + +/// Get the store data, if any, from an instruction. +pub fn inst_store_data(func: &Function, inst: Inst) -> Option { + match &func.dfg.insts[inst] { + InstructionData::Store { args, .. } | InstructionData::StoreNoOffset { args, .. } => { + Some(args[0]) + } + _ => None, + } +} + +/// Determine whether this opcode behaves as a memory fence, i.e., +/// prohibits any moving of memory accesses across it. +pub fn has_memory_fence_semantics(op: Opcode) -> bool { + match op { + Opcode::AtomicRmw + | Opcode::AtomicCas + | Opcode::AtomicLoad + | Opcode::AtomicStore + | Opcode::Fence + | Opcode::Debugtrap => true, + Opcode::Call | Opcode::CallIndirect => true, + op if op.can_trap() => true, + _ => false, + } +} + +/// Visit all successors of a block with a given visitor closure. The closure +/// arguments are the branch instruction that is used to reach the successor, +/// the successor block itself, and a flag indicating whether the block is +/// branched to via a table entry. +pub(crate) fn visit_block_succs( + f: &Function, + block: Block, + mut visit: F, +) { + if let Some(inst) = f.layout.last_inst(block) { + match &f.dfg.insts[inst] { + ir::InstructionData::Jump { + destination: dest, .. + } => { + visit(inst, dest.block(&f.dfg.value_lists), false); + } + + ir::InstructionData::Brif { + blocks: [block_then, block_else], + .. + } => { + visit(inst, block_then.block(&f.dfg.value_lists), false); + visit(inst, block_else.block(&f.dfg.value_lists), false); + } + + ir::InstructionData::BranchTable { table, .. } => { + let pool = &f.dfg.value_lists; + let table = &f.stencil.dfg.jump_tables[*table]; + + // The default block is reached via a direct conditional branch, + // so it is not part of the table. We visit the default block + // first explicitly, to mirror the traversal order of + // `JumpTableData::all_branches`, and transitively the order of + // `InstructionData::branch_destination`. + // + // Additionally, this case is why we are unable to replace this + // whole function with a loop over `branch_destination`: we need + // to report which branch targets come from the table vs the + // default. + visit(inst, table.default_block().block(pool), false); + + for dest in table.as_slice() { + visit(inst, dest.block(pool), true); + } + } + + inst => debug_assert!(!inst.opcode().is_branch()), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/inst_specs.isle b/deps/crates/vendor/cranelift-codegen/src/inst_specs.isle new file mode 100644 index 00000000000000..83f703e4510ce3 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/inst_specs.isle @@ -0,0 +1,242 @@ +(model Imm64 (type (bv 64))) + +(model IntCC (enum + (Equal #x00) + (NotEqual #x01) + (SignedGreaterThan #x02) + (SignedGreaterThanOrEqual #x03) + (SignedLessThan #x04) + (SignedLessThanOrEqual #x05) + (UnsignedGreaterThan #x06) + (UnsignedGreaterThanOrEqual #x07) + (UnsignedLessThan #x08) + (UnsignedLessThanOrEqual #x09))) + +(spec (smin x y) + (provide (= result (if (bvsle x y) x y)))) +(instantiate smin bv_binary_8_to_64) + +(spec (umin x y) + (provide (= result (if (bvule x y) x y)))) +(instantiate umin bv_binary_8_to_64) + +(spec (smax x y) + (provide (= result (if (bvsge x y) x y)))) +(instantiate smax bv_binary_8_to_64) + +(spec (umax x y) + (provide (= result (if (bvuge x y) x y)))) +(instantiate umax bv_binary_8_to_64) + +(spec (iconst arg) + (provide (= arg (zero_ext 64 result)))) +(instantiate iconst + ((args (bv 64)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 64)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 64)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) +) + +(spec (bitselect c x y) + (provide (= result (bvor (bvand c x) (bvand (bvnot c) y))))) +(instantiate bitselect bv_ternary_8_to_64) + +(spec (icmp c x y) + (provide + (= result + (switch c + ((IntCC.Equal) (if (= x y) #x01 #x00)) + ((IntCC.NotEqual) (if (not (= x y)) #x01 #x00)) + ((IntCC.SignedGreaterThan) (if (bvsgt x y) #x01 #x00)) + ((IntCC.SignedGreaterThanOrEqual) (if (bvsge x y) #x01 #x00)) + ((IntCC.SignedLessThan) (if (bvslt x y) #x01 #x00)) + ((IntCC.SignedLessThanOrEqual) (if (bvsle x y) #x01 #x00)) + ((IntCC.UnsignedGreaterThan) (if (bvugt x y) #x01 #x00)) + ((IntCC.UnsignedGreaterThanOrEqual) (if (bvuge x y) #x01 #x00)) + ((IntCC.UnsignedLessThan) (if (bvult x y) #x01 #x00)) + ((IntCC.UnsignedLessThanOrEqual) (if (bvule x y) #x01 #x00))))) + (require + ;; AVH TODO: if we understand enums semantically, we can generate this + (or + (= c (IntCC.Equal)) + (= c (IntCC.NotEqual)) + (= c (IntCC.UnsignedGreaterThanOrEqual)) + (= c (IntCC.UnsignedGreaterThan)) + (= c (IntCC.UnsignedLessThanOrEqual)) + (= c (IntCC.UnsignedLessThan)) + (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))))) +(instantiate icmp + ((args (bv 8) (bv 8) (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 8) (bv 16) (bv 16)) (ret (bv 8)) (canon (bv 16))) + ((args (bv 8) (bv 32) (bv 32)) (ret (bv 8)) (canon (bv 32))) + ((args (bv 8) (bv 64) (bv 64)) (ret (bv 8)) (canon (bv 64))) +) + +(spec (iadd x y) + (provide (= result (bvadd x y)))) +(instantiate iadd bv_binary_8_to_64) + +(spec (isub x y) + (provide (= result (bvsub x y)))) +(instantiate isub bv_binary_8_to_64) + +(spec (ineg x) + (provide (= result (bvneg x)))) +(instantiate ineg bv_unary_8_to_64) + +(spec (iabs x) + (provide (= result + (if (bvsge x (conv_to (widthof x) #x0000000000000000)) + x + (bvneg x))))) +(instantiate iabs bv_unary_8_to_64) + +(spec (imul x y) + (provide (= result (bvmul x y)))) +(instantiate imul bv_binary_8_to_64) + +(spec (udiv x y) + (provide (= result (bvudiv x y))) + (require (not (= y (zero_ext (widthof y) #b0))))) +(instantiate udiv bv_binary_8_to_64) + +(spec (sdiv x y) + (provide (= result (bvsdiv x y))) + (require (not (= y (zero_ext (widthof y) #b0))))) +(instantiate sdiv bv_binary_8_to_64) + +(spec (urem x y) + (provide (= result (bvurem x y))) + (require (not (= y (zero_ext (widthof y) #b0))))) +(instantiate urem bv_binary_8_to_64) + +(spec (srem x y) + (provide (= result (bvsrem x y))) + (require (not (= y (zero_ext (widthof y) #b0))))) +(instantiate srem bv_binary_8_to_64) + +(spec (imul_imm x y) + (provide (= result (bvmul (sign_ext 64 x) y)))) + +(spec (band x y) + (provide (= result (bvand x y)))) +(instantiate band bv_binary_8_to_64) + +(spec (bor x y) + (provide (= result (bvor x y)))) +(instantiate bor bv_binary_8_to_64) + +(spec (bxor x y) + (provide (= result (bvxor x y)))) +(instantiate bxor bv_binary_8_to_64) + +(spec (bnot x) + (provide (= result (bvnot x))) + (require (or (= (widthof x) 8) (= (widthof x) 16) (= (widthof x) 32) (= (widthof x) 64)))) +(instantiate bnot bv_unary_8_to_64) + +(spec (band_not x y) + (provide (= result (bvand x (bvnot y))))) +(instantiate band_not bv_binary_8_to_64) + +(spec (rotl x y) + (provide (= result (rotl x y)))) +(instantiate rotl bv_binary_8_to_64) + +(spec (rotr x y) + (provide (= result (rotr x y)))) +(instantiate rotr bv_binary_8_to_64) + +;; fn shift_mask(&mut self, ty: Type) -> ImmLogic { +;; let mask = (ty.lane_bits() - 1) as u64; +;; ImmLogic::maybe_from_u64(mask, I32).unwrap() +;; } +(spec (ishl x y) + (provide + (= result + (bvshl x + (bvand (conv_to (widthof y) (bvsub (int2bv 64 (widthof y)) + #x0000000000000001)) + y))))) +(instantiate ishl bv_binary_8_to_64) + +(spec (ushr x y) + (provide + (= result + (bvlshr x + (bvand (conv_to (widthof y) (bvsub (int2bv 64 (widthof y)) + #x0000000000000001)) + y))))) +(instantiate ushr bv_binary_8_to_64) + +(spec (sshr x y) + (provide + (= result + (bvashr x + (bvand (conv_to (widthof y) (bvsub (int2bv 64 (widthof y)) + #x0000000000000001)) + y))))) +(instantiate sshr bv_binary_8_to_64) + +(spec (clz x) + (provide (= result (clz x)))) +(instantiate clz bv_unary_8_to_64) + +(spec (cls x) + (provide (= result (cls x)))) +(instantiate cls bv_unary_8_to_64) + +(spec (ctz x) + (provide (= result (clz (rev x))))) +(instantiate ctz bv_unary_8_to_64) + +(spec (popcnt x) + (provide (= result (popcnt x)))) +(instantiate popcnt bv_unary_8_to_64) + +(form extend + ((args (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 8)) (ret (bv 16)) (canon (bv 8))) + ((args (bv 8)) (ret (bv 32)) (canon (bv 8))) + ((args (bv 8)) (ret (bv 64)) (canon (bv 8))) + ((args (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 16)) (ret (bv 32)) (canon (bv 16))) + ((args (bv 16)) (ret (bv 64)) (canon (bv 16))) + ((args (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 32)) (ret (bv 64)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) +) + +(spec (uextend x) + (provide (= result (zero_ext (widthof result) x)))) +(instantiate uextend extend) + +(spec (sextend x) + (provide (= result (sign_ext (widthof result) x)))) +(instantiate sextend extend) + + +(form load + ((args (bv 16) (bv 64) (bv 32)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16) (bv 64) (bv 32)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 16) (bv 64) (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 16) (bv 64) (bv 32)) (ret (bv 64)) (canon (bv 64))) +) +(spec (load flags val offset) + (provide + (= result (load_effect flags (widthof result) (bvadd val (sign_ext 64 offset)))))) +(instantiate load load) + +(form store + ((args (bv 16) (bv 8) (bv 64) (bv 32)) (ret Unit) (canon (bv 8))) + ((args (bv 16) (bv 16) (bv 64) (bv 32)) (ret Unit) (canon (bv 16))) + ((args (bv 16) (bv 32) (bv 64) (bv 32)) (ret Unit) (canon (bv 32))) + ((args (bv 16) (bv 64) (bv 64) (bv 32)) (ret Unit) (canon (bv 64))) +) +(spec (store flags val_to_store addr offset) + (provide + (= result (store_effect flags (widthof val_to_store) val_to_store (bvadd (zero_ext 64 addr) (sign_ext 64 offset)))))) +(instantiate store store) diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/atomic_rmw_op.rs b/deps/crates/vendor/cranelift-codegen/src/ir/atomic_rmw_op.rs new file mode 100644 index 00000000000000..0317fc00d2c119 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/atomic_rmw_op.rs @@ -0,0 +1,104 @@ +/// Describes the arithmetic operation in an atomic memory read-modify-write operation. +use core::fmt::{self, Display, Formatter}; +use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +/// Describes the arithmetic operation in an atomic memory read-modify-write operation. +pub enum AtomicRmwOp { + /// Add + Add, + /// Sub + Sub, + /// And + And, + /// Nand + Nand, + /// Or + Or, + /// Xor + Xor, + /// Exchange + Xchg, + /// Unsigned min + Umin, + /// Unsigned max + Umax, + /// Signed min + Smin, + /// Signed max + Smax, +} + +impl AtomicRmwOp { + /// Returns a slice with all supported [AtomicRmwOp]'s. + pub fn all() -> &'static [AtomicRmwOp] { + &[ + AtomicRmwOp::Add, + AtomicRmwOp::Sub, + AtomicRmwOp::And, + AtomicRmwOp::Nand, + AtomicRmwOp::Or, + AtomicRmwOp::Xor, + AtomicRmwOp::Xchg, + AtomicRmwOp::Umin, + AtomicRmwOp::Umax, + AtomicRmwOp::Smin, + AtomicRmwOp::Smax, + ] + } +} + +impl Display for AtomicRmwOp { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let s = match self { + AtomicRmwOp::Add => "add", + AtomicRmwOp::Sub => "sub", + AtomicRmwOp::And => "and", + AtomicRmwOp::Nand => "nand", + AtomicRmwOp::Or => "or", + AtomicRmwOp::Xor => "xor", + AtomicRmwOp::Xchg => "xchg", + AtomicRmwOp::Umin => "umin", + AtomicRmwOp::Umax => "umax", + AtomicRmwOp::Smin => "smin", + AtomicRmwOp::Smax => "smax", + }; + f.write_str(s) + } +} + +impl FromStr for AtomicRmwOp { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "add" => Ok(AtomicRmwOp::Add), + "sub" => Ok(AtomicRmwOp::Sub), + "and" => Ok(AtomicRmwOp::And), + "nand" => Ok(AtomicRmwOp::Nand), + "or" => Ok(AtomicRmwOp::Or), + "xor" => Ok(AtomicRmwOp::Xor), + "xchg" => Ok(AtomicRmwOp::Xchg), + "umin" => Ok(AtomicRmwOp::Umin), + "umax" => Ok(AtomicRmwOp::Umax), + "smin" => Ok(AtomicRmwOp::Smin), + "smax" => Ok(AtomicRmwOp::Smax), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip_parse() { + for op in AtomicRmwOp::all() { + let roundtripped = format!("{op}").parse::().unwrap(); + assert_eq!(*op, roundtripped); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/builder.rs b/deps/crates/vendor/cranelift-codegen/src/ir/builder.rs new file mode 100644 index 00000000000000..6032f07f52125b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/builder.rs @@ -0,0 +1,282 @@ +//! Cranelift instruction builder. +//! +//! A `Builder` provides a convenient interface for inserting instructions into a Cranelift +//! function. Many of its methods are generated from the meta language instruction definitions. + +use crate::ir; +use crate::ir::instructions::InstructionFormat; +use crate::ir::types; +use crate::ir::{DataFlowGraph, InstructionData}; +use crate::ir::{Inst, Opcode, Type, Value}; + +/// Base trait for instruction builders. +/// +/// The `InstBuilderBase` trait provides the basic functionality required by the methods of the +/// generated `InstBuilder` trait. These methods should not normally be used directly. Use the +/// methods in the `InstBuilder` trait instead. +/// +/// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder` +/// trait. +pub trait InstBuilderBase<'f>: Sized { + /// Get an immutable reference to the data flow graph that will hold the constructed + /// instructions. + fn data_flow_graph(&self) -> &DataFlowGraph; + /// Get a mutable reference to the data flow graph that will hold the constructed + /// instructions. + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; + + /// Insert an instruction and return a reference to it, consuming the builder. + /// + /// The result types may depend on a controlling type variable. For non-polymorphic + /// instructions with multiple results, pass `INVALID` for the `ctrl_typevar` argument. + fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph); +} + +// Include trait code generated by `cranelift-codegen/meta/src/gen_inst.rs`. +// +// This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per +// instruction format and per opcode. +include!(concat!(env!("OUT_DIR"), "/inst_builder.rs")); + +/// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. +impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {} + +/// Base trait for instruction inserters. +/// +/// This is an alternative base trait for an instruction builder to implement. +/// +/// An instruction inserter can be adapted into an instruction builder by wrapping it in an +/// `InsertBuilder`. This provides some common functionality for instruction builders that insert +/// new instructions, as opposed to the `ReplaceBuilder` which overwrites existing instructions. +pub trait InstInserterBase<'f>: Sized { + /// Get an immutable reference to the data flow graph. + fn data_flow_graph(&self) -> &DataFlowGraph; + + /// Get a mutable reference to the data flow graph. + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; + + /// Insert a new instruction which belongs to the DFG. + fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph; +} + +use core::marker::PhantomData; + +/// Builder that inserts an instruction at the current position. +/// +/// An `InsertBuilder` is a wrapper for an `InstInserterBase` that turns it into an instruction +/// builder with some additional facilities for creating instructions that reuse existing values as +/// their results. +pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> { + inserter: IIB, + unused: PhantomData<&'f u32>, +} + +impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> { + /// Create a new builder which inserts instructions at `pos`. + /// The `dfg` and `pos.layout` references should be from the same `Function`. + pub fn new(inserter: IIB) -> Self { + Self { + inserter, + unused: PhantomData, + } + } + + /// Reuse result values in `reuse`. + /// + /// Convert this builder into one that will reuse the provided result values instead of + /// allocating new ones. The provided values for reuse must not be attached to anything. Any + /// missing result values will be allocated as normal. + /// + /// The `reuse` argument is expected to be an array of `Option`. + pub fn with_results(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array> + where + Array: AsRef<[Option]>, + { + InsertReuseBuilder { + inserter: self.inserter, + reuse, + unused: PhantomData, + } + } + + /// Reuse a single result value. + /// + /// Convert this into a builder that will reuse `v` as the single result value. The reused + /// result value `v` must not be attached to anything. + /// + /// This method should only be used when building an instruction with exactly one result. Use + /// `with_results()` for the more general case. + pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option; 1]> { + // TODO: Specialize this to return a different builder that just attaches `v` instead of + // calling `make_inst_results_reusing()`. + self.with_results([Some(v)]) + } +} + +impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> { + fn data_flow_graph(&self) -> &DataFlowGraph { + self.inserter.data_flow_graph() + } + + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { + self.inserter.data_flow_graph_mut() + } + + fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { + let inst; + { + let dfg = self.inserter.data_flow_graph_mut(); + inst = dfg.make_inst(data); + dfg.make_inst_results(inst, ctrl_typevar); + } + (inst, self.inserter.insert_built_inst(inst)) + } +} + +/// Builder that inserts a new instruction like `InsertBuilder`, but reusing result values. +pub struct InsertReuseBuilder<'f, IIB, Array> +where + IIB: InstInserterBase<'f>, + Array: AsRef<[Option]>, +{ + inserter: IIB, + reuse: Array, + unused: PhantomData<&'f u32>, +} + +impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array> +where + IIB: InstInserterBase<'f>, + Array: AsRef<[Option]>, +{ + fn data_flow_graph(&self) -> &DataFlowGraph { + self.inserter.data_flow_graph() + } + + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { + self.inserter.data_flow_graph_mut() + } + + fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { + let inst; + { + let dfg = self.inserter.data_flow_graph_mut(); + inst = dfg.make_inst(data); + // Make an `Iterator>`. + let ru = self.reuse.as_ref().iter().cloned(); + dfg.make_inst_results_reusing(inst, ctrl_typevar, ru); + } + (inst, self.inserter.insert_built_inst(inst)) + } +} + +/// Instruction builder that replaces an existing instruction. +/// +/// The inserted instruction will have the same `Inst` number as the old one. +/// +/// If the old instruction still has result values attached, it is assumed that the new instruction +/// produces the same number and types of results. The old result values are preserved. If the +/// replacement instruction format does not support multiple results, the builder panics. It is a +/// bug to leave result values dangling. +pub struct ReplaceBuilder<'f> { + dfg: &'f mut DataFlowGraph, + inst: Inst, +} + +impl<'f> ReplaceBuilder<'f> { + /// Create a `ReplaceBuilder` that will overwrite `inst`. + pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self { + Self { dfg, inst } + } +} + +impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> { + fn data_flow_graph(&self) -> &DataFlowGraph { + self.dfg + } + + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { + self.dfg + } + + fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { + // Splat the new instruction on top of the old one. + self.dfg.insts[self.inst] = data; + + if !self.dfg.has_results(self.inst) { + // The old result values were either detached or non-existent. + // Construct new ones. + self.dfg.make_inst_results(self.inst, ctrl_typevar); + } + + (self.inst, self.dfg) + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::condcodes::*; + use crate::ir::types::*; + use crate::ir::{Function, InstBuilder, ValueDef}; + + #[test] + fn types() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let arg0 = func.dfg.append_block_param(block0, I32); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + + // Explicit types. + let v0 = pos.ins().iconst(I32, 3); + assert_eq!(pos.func.dfg.value_type(v0), I32); + + // Inferred from inputs. + let v1 = pos.ins().iadd(arg0, v0); + assert_eq!(pos.func.dfg.value_type(v1), I32); + + // Formula. + let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0); + assert_eq!(pos.func.dfg.value_type(cmp), I8); + } + + #[test] + fn reuse_results() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let arg0 = func.dfg.append_block_param(block0, I32); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + + let v0 = pos.ins().iadd_imm(arg0, 17); + assert_eq!(pos.func.dfg.value_type(v0), I32); + let iadd = pos.prev_inst().unwrap(); + assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0)); + + // Detach v0 and reuse it for a different instruction. + pos.func.dfg.clear_results(iadd); + let v0b = pos.ins().with_result(v0).iconst(I32, 3); + assert_eq!(v0, v0b); + assert_eq!(pos.current_inst(), Some(iadd)); + let iconst = pos.prev_inst().unwrap(); + assert!(iadd != iconst); + assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn panics_when_inserting_wrong_opcode() { + use crate::ir::{Opcode, TrapCode}; + + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + + // We are trying to create a Opcode::Return with the InstData::Trap, which is obviously wrong + pos.ins() + .Trap(Opcode::Return, I32, TrapCode::BAD_CONVERSION_TO_INTEGER); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/condcodes.rs b/deps/crates/vendor/cranelift-codegen/src/ir/condcodes.rs new file mode 100644 index 00000000000000..e791649bb69cca --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/condcodes.rs @@ -0,0 +1,404 @@ +//! Condition codes for the Cranelift code generator. +//! +//! A condition code here is an enumerated type that determined how to compare two numbers. There +//! are different rules for comparing integers and floating point numbers, so they use different +//! condition codes. + +use core::fmt::{self, Display, Formatter}; +use core::str::FromStr; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Common traits of condition codes. +pub trait CondCode: Copy { + /// Get the complemented condition code of `self`. + /// + /// The complemented condition code produces the opposite result for all comparisons. + /// That is, `cmp CC, x, y` is true if and only if `cmp CC.complement(), x, y` is false. + #[must_use] + fn complement(self) -> Self; + + /// Get the swapped args condition code for `self`. + /// + /// The swapped args condition code produces the same result as swapping `x` and `y` in the + /// comparison. That is, `cmp CC, x, y` is the same as `cmp CC.swap_args(), y, x`. + #[must_use] + fn swap_args(self) -> Self; +} + +/// Condition code for comparing integers. +/// +/// This condition code is used by the `icmp` instruction to compare integer values. There are +/// separate codes for comparing the integers as signed or unsigned numbers where it makes a +/// difference. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum IntCC { + /// `==`. + Equal, + /// `!=`. + NotEqual, + /// Signed `<`. + SignedLessThan, + /// Signed `>=`. + SignedGreaterThanOrEqual, + /// Signed `>`. + SignedGreaterThan, + /// Signed `<=`. + SignedLessThanOrEqual, + /// Unsigned `<`. + UnsignedLessThan, + /// Unsigned `>=`. + UnsignedGreaterThanOrEqual, + /// Unsigned `>`. + UnsignedGreaterThan, + /// Unsigned `<=`. + UnsignedLessThanOrEqual, +} + +impl CondCode for IntCC { + fn complement(self) -> Self { + use self::IntCC::*; + match self { + Equal => NotEqual, + NotEqual => Equal, + SignedLessThan => SignedGreaterThanOrEqual, + SignedGreaterThanOrEqual => SignedLessThan, + SignedGreaterThan => SignedLessThanOrEqual, + SignedLessThanOrEqual => SignedGreaterThan, + UnsignedLessThan => UnsignedGreaterThanOrEqual, + UnsignedGreaterThanOrEqual => UnsignedLessThan, + UnsignedGreaterThan => UnsignedLessThanOrEqual, + UnsignedLessThanOrEqual => UnsignedGreaterThan, + } + } + + fn swap_args(self) -> Self { + use self::IntCC::*; + match self { + Equal => Equal, + NotEqual => NotEqual, + SignedGreaterThan => SignedLessThan, + SignedGreaterThanOrEqual => SignedLessThanOrEqual, + SignedLessThan => SignedGreaterThan, + SignedLessThanOrEqual => SignedGreaterThanOrEqual, + UnsignedGreaterThan => UnsignedLessThan, + UnsignedGreaterThanOrEqual => UnsignedLessThanOrEqual, + UnsignedLessThan => UnsignedGreaterThan, + UnsignedLessThanOrEqual => UnsignedGreaterThanOrEqual, + } + } +} + +impl IntCC { + /// Returns a slice with all possible [IntCC] values. + pub fn all() -> &'static [IntCC] { + &[ + IntCC::Equal, + IntCC::NotEqual, + IntCC::SignedLessThan, + IntCC::SignedGreaterThanOrEqual, + IntCC::SignedGreaterThan, + IntCC::SignedLessThanOrEqual, + IntCC::UnsignedLessThan, + IntCC::UnsignedGreaterThanOrEqual, + IntCC::UnsignedGreaterThan, + IntCC::UnsignedLessThanOrEqual, + ] + } + + /// Get the corresponding IntCC with the equal component removed. + /// For conditions without a zero component, this is a no-op. + pub fn without_equal(self) -> Self { + use self::IntCC::*; + match self { + SignedGreaterThan | SignedGreaterThanOrEqual => SignedGreaterThan, + SignedLessThan | SignedLessThanOrEqual => SignedLessThan, + UnsignedGreaterThan | UnsignedGreaterThanOrEqual => UnsignedGreaterThan, + UnsignedLessThan | UnsignedLessThanOrEqual => UnsignedLessThan, + _ => self, + } + } + + /// Get the corresponding IntCC with the signed component removed. + /// For conditions without a signed component, this is a no-op. + pub fn unsigned(self) -> Self { + use self::IntCC::*; + match self { + SignedGreaterThan | UnsignedGreaterThan => UnsignedGreaterThan, + SignedGreaterThanOrEqual | UnsignedGreaterThanOrEqual => UnsignedGreaterThanOrEqual, + SignedLessThan | UnsignedLessThan => UnsignedLessThan, + SignedLessThanOrEqual | UnsignedLessThanOrEqual => UnsignedLessThanOrEqual, + _ => self, + } + } + + /// Get the corresponding string condition code for the IntCC object. + pub fn to_static_str(self) -> &'static str { + use self::IntCC::*; + match self { + Equal => "eq", + NotEqual => "ne", + SignedGreaterThan => "sgt", + SignedGreaterThanOrEqual => "sge", + SignedLessThan => "slt", + SignedLessThanOrEqual => "sle", + UnsignedGreaterThan => "ugt", + UnsignedGreaterThanOrEqual => "uge", + UnsignedLessThan => "ult", + UnsignedLessThanOrEqual => "ule", + } + } +} + +impl Display for IntCC { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str(self.to_static_str()) + } +} + +impl FromStr for IntCC { + type Err = (); + + fn from_str(s: &str) -> Result { + use self::IntCC::*; + match s { + "eq" => Ok(Equal), + "ne" => Ok(NotEqual), + "sge" => Ok(SignedGreaterThanOrEqual), + "sgt" => Ok(SignedGreaterThan), + "sle" => Ok(SignedLessThanOrEqual), + "slt" => Ok(SignedLessThan), + "uge" => Ok(UnsignedGreaterThanOrEqual), + "ugt" => Ok(UnsignedGreaterThan), + "ule" => Ok(UnsignedLessThanOrEqual), + "ult" => Ok(UnsignedLessThan), + _ => Err(()), + } + } +} + +/// Condition code for comparing floating point numbers. +/// +/// This condition code is used by the `fcmp` instruction to compare floating point values. Two +/// IEEE floating point values relate in exactly one of four ways: +/// +/// 1. `UN` - unordered when either value is NaN. +/// 2. `EQ` - equal numerical value. +/// 3. `LT` - `x` is less than `y`. +/// 4. `GT` - `x` is greater than `y`. +/// +/// Note that `0.0` and `-0.0` relate as `EQ` because they both represent the number 0. +/// +/// The condition codes described here are used to produce a single boolean value from the +/// comparison. The 14 condition codes here cover every possible combination of the relation above +/// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum FloatCC { + /// EQ | LT | GT + Ordered, + /// UN + Unordered, + + /// EQ + Equal, + /// The C '!=' operator is the inverse of '==': `NotEqual`. + /// UN | LT | GT + NotEqual, + /// LT | GT + OrderedNotEqual, + /// UN | EQ + UnorderedOrEqual, + + /// LT + LessThan, + /// LT | EQ + LessThanOrEqual, + /// GT + GreaterThan, + /// GT | EQ + GreaterThanOrEqual, + + /// UN | LT + UnorderedOrLessThan, + /// UN | LT | EQ + UnorderedOrLessThanOrEqual, + /// UN | GT + UnorderedOrGreaterThan, + /// UN | GT | EQ + UnorderedOrGreaterThanOrEqual, +} + +impl FloatCC { + /// Returns a slice with all possible [FloatCC] values. + pub fn all() -> &'static [FloatCC] { + &[ + FloatCC::Ordered, + FloatCC::Unordered, + FloatCC::Equal, + FloatCC::NotEqual, + FloatCC::OrderedNotEqual, + FloatCC::UnorderedOrEqual, + FloatCC::LessThan, + FloatCC::LessThanOrEqual, + FloatCC::GreaterThan, + FloatCC::GreaterThanOrEqual, + FloatCC::UnorderedOrLessThan, + FloatCC::UnorderedOrLessThanOrEqual, + FloatCC::UnorderedOrGreaterThan, + FloatCC::UnorderedOrGreaterThanOrEqual, + ] + } +} + +impl CondCode for FloatCC { + fn complement(self) -> Self { + use self::FloatCC::*; + match self { + Ordered => Unordered, + Unordered => Ordered, + Equal => NotEqual, + NotEqual => Equal, + OrderedNotEqual => UnorderedOrEqual, + UnorderedOrEqual => OrderedNotEqual, + LessThan => UnorderedOrGreaterThanOrEqual, + LessThanOrEqual => UnorderedOrGreaterThan, + GreaterThan => UnorderedOrLessThanOrEqual, + GreaterThanOrEqual => UnorderedOrLessThan, + UnorderedOrLessThan => GreaterThanOrEqual, + UnorderedOrLessThanOrEqual => GreaterThan, + UnorderedOrGreaterThan => LessThanOrEqual, + UnorderedOrGreaterThanOrEqual => LessThan, + } + } + fn swap_args(self) -> Self { + use self::FloatCC::*; + match self { + Ordered => Ordered, + Unordered => Unordered, + Equal => Equal, + NotEqual => NotEqual, + OrderedNotEqual => OrderedNotEqual, + UnorderedOrEqual => UnorderedOrEqual, + LessThan => GreaterThan, + LessThanOrEqual => GreaterThanOrEqual, + GreaterThan => LessThan, + GreaterThanOrEqual => LessThanOrEqual, + UnorderedOrLessThan => UnorderedOrGreaterThan, + UnorderedOrLessThanOrEqual => UnorderedOrGreaterThanOrEqual, + UnorderedOrGreaterThan => UnorderedOrLessThan, + UnorderedOrGreaterThanOrEqual => UnorderedOrLessThanOrEqual, + } + } +} + +impl Display for FloatCC { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + use self::FloatCC::*; + f.write_str(match *self { + Ordered => "ord", + Unordered => "uno", + Equal => "eq", + NotEqual => "ne", + OrderedNotEqual => "one", + UnorderedOrEqual => "ueq", + LessThan => "lt", + LessThanOrEqual => "le", + GreaterThan => "gt", + GreaterThanOrEqual => "ge", + UnorderedOrLessThan => "ult", + UnorderedOrLessThanOrEqual => "ule", + UnorderedOrGreaterThan => "ugt", + UnorderedOrGreaterThanOrEqual => "uge", + }) + } +} + +impl FromStr for FloatCC { + type Err = (); + + fn from_str(s: &str) -> Result { + use self::FloatCC::*; + match s { + "ord" => Ok(Ordered), + "uno" => Ok(Unordered), + "eq" => Ok(Equal), + "ne" => Ok(NotEqual), + "one" => Ok(OrderedNotEqual), + "ueq" => Ok(UnorderedOrEqual), + "lt" => Ok(LessThan), + "le" => Ok(LessThanOrEqual), + "gt" => Ok(GreaterThan), + "ge" => Ok(GreaterThanOrEqual), + "ult" => Ok(UnorderedOrLessThan), + "ule" => Ok(UnorderedOrLessThanOrEqual), + "ugt" => Ok(UnorderedOrGreaterThan), + "uge" => Ok(UnorderedOrGreaterThanOrEqual), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::ToString; + + #[test] + fn int_complement() { + for r in IntCC::all() { + let cc = *r; + let inv = cc.complement(); + assert!(cc != inv); + assert_eq!(inv.complement(), cc); + } + } + + #[test] + fn int_swap_args() { + for r in IntCC::all() { + let cc = *r; + let rev = cc.swap_args(); + assert_eq!(rev.swap_args(), cc); + } + } + + #[test] + fn int_display() { + for r in IntCC::all() { + let cc = *r; + assert_eq!(cc.to_string().parse(), Ok(cc)); + } + assert_eq!("bogus".parse::(), Err(())); + } + + #[test] + fn float_complement() { + for r in FloatCC::all() { + let cc = *r; + let inv = cc.complement(); + assert!(cc != inv); + assert_eq!(inv.complement(), cc); + } + } + + #[test] + fn float_swap_args() { + for r in FloatCC::all() { + let cc = *r; + let rev = cc.swap_args(); + assert_eq!(rev.swap_args(), cc); + } + } + + #[test] + fn float_display() { + for r in FloatCC::all() { + let cc = *r; + assert_eq!(cc.to_string().parse(), Ok(cc)); + } + assert_eq!("bogus".parse::(), Err(())); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/constant.rs b/deps/crates/vendor/cranelift-codegen/src/ir/constant.rs new file mode 100644 index 00000000000000..0db31628cca2ca --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/constant.rs @@ -0,0 +1,485 @@ +//! Constants +//! +//! The constant pool defined here allows Cranelift to avoid emitting the same constant multiple +//! times. As constants are inserted in the pool, a handle is returned; the handle is a Cranelift +//! Entity. Inserting the same data multiple times will always return the same handle. +//! +//! Future work could include: +//! - ensuring alignment of constants within the pool, +//! - bucketing constants by size. + +use crate::ir::immediates::{Ieee128, IntoBytes, V128Imm}; +use crate::ir::Constant; +use alloc::collections::BTreeMap; +use alloc::vec::Vec; +use core::fmt; +use core::slice::Iter; +use core::str::{from_utf8, FromStr}; +use cranelift_entity::EntityRef; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// This type describes the actual constant data. Note that the bytes stored in this structure are +/// expected to be in little-endian order; this is due to ease-of-use when interacting with +/// WebAssembly values, which are [little-endian by design]. +/// +/// [little-endian by design]: https://github.com/WebAssembly/design/blob/master/Portability.md +#[derive(Clone, Hash, Eq, PartialEq, Debug, Default, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ConstantData(Vec); + +impl FromIterator for ConstantData { + fn from_iter>(iter: T) -> Self { + let v = iter.into_iter().collect(); + Self(v) + } +} + +impl From> for ConstantData { + fn from(v: Vec) -> Self { + Self(v) + } +} + +impl From<&[u8]> for ConstantData { + fn from(v: &[u8]) -> Self { + Self(v.to_vec()) + } +} + +impl From for ConstantData { + fn from(v: V128Imm) -> Self { + Self(v.to_vec()) + } +} + +impl From for ConstantData { + fn from(v: Ieee128) -> Self { + Self(v.into_bytes()) + } +} + +impl TryFrom<&ConstantData> for Ieee128 { + type Error = <[u8; 16] as TryFrom<&'static [u8]>>::Error; + + fn try_from(value: &ConstantData) -> Result { + Ok(Ieee128::with_bits(u128::from_le_bytes( + value.as_slice().try_into()?, + ))) + } +} + +impl ConstantData { + /// Return the number of bytes in the constant. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Check if the constant contains any bytes. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Return the data as a slice. + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + /// Convert the data to a vector. + pub fn into_vec(self) -> Vec { + self.0 + } + + /// Iterate over the constant's bytes. + pub fn iter(&self) -> Iter { + self.0.iter() + } + + /// Add new bytes to the constant data. + pub fn append(mut self, bytes: impl IntoBytes) -> Self { + let mut to_add = bytes.into_bytes(); + self.0.append(&mut to_add); + self + } + + /// Expand the size of the constant data to `expected_size` number of bytes by adding zeroes + /// in the high-order byte slots. + pub fn expand_to(mut self, expected_size: usize) -> Self { + if self.len() > expected_size { + panic!("The constant data is already expanded beyond {expected_size} bytes") + } + self.0.resize(expected_size, 0); + self + } +} + +impl fmt::Display for ConstantData { + /// Print the constant data in hexadecimal format, e.g. 0x000102030405060708090a0b0c0d0e0f. + /// This function will flip the stored order of bytes--little-endian--to the more readable + /// big-endian ordering. + /// + /// ``` + /// use cranelift_codegen::ir::ConstantData; + /// let data = ConstantData::from([3, 2, 1, 0, 0].as_ref()); // note the little-endian order + /// assert_eq!(data.to_string(), "0x0000010203"); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if !self.is_empty() { + write!(f, "0x")?; + for b in self.0.iter().rev() { + write!(f, "{b:02x}")?; + } + } + Ok(()) + } +} + +impl FromStr for ConstantData { + type Err = &'static str; + + /// Parse a hexadecimal string to `ConstantData`. This is the inverse of `Display::fmt`. + /// + /// ``` + /// use cranelift_codegen::ir::ConstantData; + /// let c: ConstantData = "0x000102".parse().unwrap(); + /// assert_eq!(c.into_vec(), [2, 1, 0]); + /// ``` + fn from_str(s: &str) -> Result { + if s.len() <= 2 || &s[0..2] != "0x" { + return Err("Expected a hexadecimal string, e.g. 0x1234"); + } + + // clean and check the string + let cleaned: Vec = s[2..] + .as_bytes() + .iter() + .filter(|&&b| b as char != '_') + .cloned() + .collect(); // remove 0x prefix and any intervening _ characters + + if cleaned.is_empty() { + Err("Hexadecimal string must have some digits") + } else if cleaned.len() % 2 != 0 { + Err("Hexadecimal string must have an even number of digits") + } else if cleaned.len() > 32 { + Err("Hexadecimal string has too many digits to fit in a 128-bit vector") + } else { + let mut buffer = Vec::with_capacity((s.len() - 2) / 2); + for i in (0..cleaned.len()).step_by(2) { + let pair = from_utf8(&cleaned[i..i + 2]) + .or_else(|_| Err("Unable to parse hexadecimal pair as UTF-8"))?; + let byte = u8::from_str_radix(pair, 16) + .or_else(|_| Err("Unable to parse as hexadecimal"))?; + buffer.insert(0, byte); + } + Ok(Self(buffer)) + } + } +} + +/// Maintains the mapping between a constant handle (i.e. [`Constant`]) and +/// its constant data (i.e. [`ConstantData`]). +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ConstantPool { + /// This mapping maintains the insertion order as long as Constants are created with + /// sequentially increasing integers. + /// + /// It is important that, by construction, no entry in that list gets removed. If that ever + /// need to happen, don't forget to update the `Constant` generation scheme. + handles_to_values: BTreeMap, + + /// Mapping of hashed `ConstantData` to the index into the other hashmap. + /// + /// This allows for deduplication of entries into the `handles_to_values` mapping. + values_to_handles: BTreeMap, +} + +impl ConstantPool { + /// Create a new constant pool instance. + pub fn new() -> Self { + Self { + handles_to_values: BTreeMap::new(), + values_to_handles: BTreeMap::new(), + } + } + + /// Empty the constant pool of all data. + pub fn clear(&mut self) { + self.handles_to_values.clear(); + self.values_to_handles.clear(); + } + + /// Insert constant data into the pool, returning a handle for later referencing; when constant + /// data is inserted that is a duplicate of previous constant data, the existing handle will be + /// returned. + pub fn insert(&mut self, constant_value: ConstantData) -> Constant { + if let Some(cst) = self.values_to_handles.get(&constant_value) { + return *cst; + } + + let constant_handle = Constant::new(self.len()); + self.set(constant_handle, constant_value); + constant_handle + } + + /// Retrieve the constant data given a handle. + pub fn get(&self, constant_handle: Constant) -> &ConstantData { + assert!(self.handles_to_values.contains_key(&constant_handle)); + self.handles_to_values.get(&constant_handle).unwrap() + } + + /// Link a constant handle to its value. This does not de-duplicate data but does avoid + /// replacing any existing constant values. use `set` to tie a specific `const42` to its value; + /// use `insert` to add a value and return the next available `const` entity. + pub fn set(&mut self, constant_handle: Constant, constant_value: ConstantData) { + let replaced = self + .handles_to_values + .insert(constant_handle, constant_value.clone()); + assert!( + replaced.is_none(), + "attempted to overwrite an existing constant {:?}: {:?} => {:?}", + constant_handle, + &constant_value, + replaced.unwrap() + ); + self.values_to_handles + .insert(constant_value, constant_handle); + } + + /// Iterate over the constants in insertion order. + pub fn iter(&self) -> impl Iterator { + self.handles_to_values.iter() + } + + /// Iterate over mutable entries in the constant pool in insertion order. + pub fn entries_mut(&mut self) -> impl Iterator { + self.handles_to_values.values_mut() + } + + /// Return the number of constants in the pool. + pub fn len(&self) -> usize { + self.handles_to_values.len() + } + + /// Return the combined size of all of the constant values in the pool. + pub fn byte_size(&self) -> usize { + self.handles_to_values.values().map(|c| c.len()).sum() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::ToString; + + #[test] + fn empty() { + let sut = ConstantPool::new(); + assert_eq!(sut.len(), 0); + } + + #[test] + fn insert() { + let mut sut = ConstantPool::new(); + sut.insert(vec![1, 2, 3].into()); + sut.insert(vec![4, 5, 6].into()); + assert_eq!(sut.len(), 2); + } + + #[test] + fn insert_duplicate() { + let mut sut = ConstantPool::new(); + let a = sut.insert(vec![1, 2, 3].into()); + sut.insert(vec![4, 5, 6].into()); + let b = sut.insert(vec![1, 2, 3].into()); + assert_eq!(a, b); + } + + #[test] + fn clear() { + let mut sut = ConstantPool::new(); + sut.insert(vec![1, 2, 3].into()); + assert_eq!(sut.len(), 1); + + sut.clear(); + assert_eq!(sut.len(), 0); + } + + #[test] + fn iteration_order() { + let mut sut = ConstantPool::new(); + sut.insert(vec![1, 2, 3].into()); + sut.insert(vec![4, 5, 6].into()); + sut.insert(vec![1, 2, 3].into()); + let data = sut.iter().map(|(_, v)| v).collect::>(); + assert_eq!(data, vec![&vec![1, 2, 3].into(), &vec![4, 5, 6].into()]); + } + + #[test] + fn get() { + let mut sut = ConstantPool::new(); + let data = vec![1, 2, 3]; + let handle = sut.insert(data.clone().into()); + assert_eq!(sut.get(handle), &data.into()); + } + + #[test] + fn set() { + let mut sut = ConstantPool::new(); + let handle = Constant::with_number(42).unwrap(); + let data = vec![1, 2, 3]; + sut.set(handle, data.clone().into()); + assert_eq!(sut.get(handle), &data.into()); + } + + #[test] + #[should_panic] + fn disallow_overwriting_constant() { + let mut sut = ConstantPool::new(); + let handle = Constant::with_number(42).unwrap(); + sut.set(handle, vec![].into()); + sut.set(handle, vec![1].into()); + } + + #[test] + #[should_panic] + fn get_nonexistent_constant() { + let sut = ConstantPool::new(); + let a = Constant::with_number(42).unwrap(); + sut.get(a); // panics, only use constants returned by ConstantPool + } + + #[test] + fn display_constant_data() { + assert_eq!(ConstantData::from([0].as_ref()).to_string(), "0x00"); + assert_eq!(ConstantData::from([42].as_ref()).to_string(), "0x2a"); + assert_eq!( + ConstantData::from([3, 2, 1, 0].as_ref()).to_string(), + "0x00010203" + ); + assert_eq!( + ConstantData::from(3735928559u32.to_le_bytes().as_ref()).to_string(), + "0xdeadbeef" + ); + assert_eq!( + ConstantData::from(0x0102030405060708u64.to_le_bytes().as_ref()).to_string(), + "0x0102030405060708" + ); + } + + #[test] + fn iterate_over_constant_data() { + let c = ConstantData::from([1, 2, 3].as_ref()); + let mut iter = c.iter(); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), None); + } + + #[test] + fn add_to_constant_data() { + let d = ConstantData::from([1, 2].as_ref()); + let e = d.append(i16::from(3u8)); + assert_eq!(e.into_vec(), vec![1, 2, 3, 0]) + } + + #[test] + fn extend_constant_data() { + let d = ConstantData::from([1, 2].as_ref()); + assert_eq!(d.expand_to(4).into_vec(), vec![1, 2, 0, 0]) + } + + #[test] + #[should_panic] + fn extend_constant_data_to_invalid_length() { + ConstantData::from([1, 2].as_ref()).expand_to(1); + } + + #[test] + fn parse_constant_data_and_restringify() { + // Verify that parsing of `from` succeeds and stringifies to `to`. + fn parse_ok(from: &str, to: &str) { + let parsed = from.parse::().unwrap(); + assert_eq!(parsed.to_string(), to); + } + + // Verify that parsing of `from` fails with `error_msg`. + fn parse_err(from: &str, error_msg: &str) { + let parsed = from.parse::(); + assert!( + parsed.is_err(), + "Expected a parse error but parsing succeeded: {from}" + ); + assert_eq!(parsed.err().unwrap(), error_msg); + } + + parse_ok("0x00", "0x00"); + parse_ok("0x00000042", "0x00000042"); + parse_ok( + "0x0102030405060708090a0b0c0d0e0f00", + "0x0102030405060708090a0b0c0d0e0f00", + ); + parse_ok("0x_0000_0043_21", "0x0000004321"); + + parse_err("", "Expected a hexadecimal string, e.g. 0x1234"); + parse_err("0x", "Expected a hexadecimal string, e.g. 0x1234"); + parse_err( + "0x042", + "Hexadecimal string must have an even number of digits", + ); + parse_err( + "0x00000000000000000000000000000000000000000000000000", + "Hexadecimal string has too many digits to fit in a 128-bit vector", + ); + parse_err("0xrstu", "Unable to parse as hexadecimal"); + parse_err("0x__", "Hexadecimal string must have some digits"); + } + + #[test] + fn verify_stored_bytes_in_constant_data() { + assert_eq!("0x01".parse::().unwrap().into_vec(), [1]); + assert_eq!(ConstantData::from([1, 0].as_ref()).0, [1, 0]); + assert_eq!(ConstantData::from(vec![1, 0, 0, 0]).0, [1, 0, 0, 0]); + } + + #[test] + fn check_constant_data_endianness_as_uimm128() { + fn parse_to_uimm128(from: &str) -> Vec { + from.parse::() + .unwrap() + .expand_to(16) + .into_vec() + } + + assert_eq!( + parse_to_uimm128("0x42"), + [0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + parse_to_uimm128("0x00"), + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + parse_to_uimm128("0x12345678"), + [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!( + parse_to_uimm128("0x1234_5678"), + [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + } + + #[test] + fn constant_ieee128() { + let value = Ieee128::with_bits(0x000102030405060708090a0b0c0d0e0f); + let constant = ConstantData::from(value); + assert_eq!( + constant.as_slice(), + &[0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0] + ); + assert_eq!(Ieee128::try_from(&constant).unwrap().bits(), value.bits()); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/dfg.rs b/deps/crates/vendor/cranelift-codegen/src/ir/dfg.rs new file mode 100644 index 00000000000000..152259697fb97e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/dfg.rs @@ -0,0 +1,1802 @@ +//! Data flow graph tracking Instructions, Values, and blocks. + +use crate::entity::{self, PrimaryMap, SecondaryMap}; +use crate::ir; +use crate::ir::builder::ReplaceBuilder; +use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes}; +use crate::ir::instructions::{CallInfo, InstructionData}; +use crate::ir::pcc::Fact; +use crate::ir::user_stack_maps::{UserStackMapEntry, UserStackMapEntryVec}; +use crate::ir::{ + types, Block, BlockCall, ConstantData, ConstantPool, DynamicType, ExtFuncData, FuncRef, + Immediate, Inst, JumpTables, RelSourceLoc, SigRef, Signature, Type, Value, + ValueLabelAssignments, ValueList, ValueListPool, +}; +use crate::packed_option::ReservedValue; +use crate::write::write_operands; +use core::fmt; +use core::iter; +use core::mem; +use core::ops::{Index, IndexMut}; +use core::u16; + +use alloc::collections::BTreeMap; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; +use smallvec::SmallVec; + +/// Storage for instructions within the DFG. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Insts(PrimaryMap); + +/// Allow immutable access to instructions via indexing. +impl Index for Insts { + type Output = InstructionData; + + fn index(&self, inst: Inst) -> &InstructionData { + self.0.index(inst) + } +} + +/// Allow mutable access to instructions via indexing. +impl IndexMut for Insts { + fn index_mut(&mut self, inst: Inst) -> &mut InstructionData { + self.0.index_mut(inst) + } +} + +/// Storage for basic blocks within the DFG. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Blocks(PrimaryMap); + +impl Blocks { + /// Create a new basic block. + pub fn add(&mut self) -> Block { + self.0.push(BlockData::new()) + } + + /// Get the total number of basic blocks created in this function, whether they are + /// currently inserted in the layout or not. + /// + /// This is intended for use with `SecondaryMap::with_capacity`. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns `true` if the given block reference is valid. + pub fn is_valid(&self, block: Block) -> bool { + self.0.is_valid(block) + } +} + +impl Index for Blocks { + type Output = BlockData; + + fn index(&self, block: Block) -> &BlockData { + &self.0[block] + } +} + +impl IndexMut for Blocks { + fn index_mut(&mut self, block: Block) -> &mut BlockData { + &mut self.0[block] + } +} + +/// A data flow graph defines all instructions and basic blocks in a function as well as +/// the data flow dependencies between them. The DFG also tracks values which can be either +/// instruction results or block parameters. +/// +/// The layout of blocks in the function and of instructions in each block is recorded by the +/// `Layout` data structure which forms the other half of the function representation. +/// +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct DataFlowGraph { + /// Data about all of the instructions in the function, including opcodes and operands. + /// The instructions in this map are not in program order. That is tracked by `Layout`, along + /// with the block containing each instruction. + pub insts: Insts, + + /// List of result values for each instruction. + /// + /// This map gets resized automatically by `make_inst()` so it is always in sync with the + /// primary `insts` map. + results: SecondaryMap, + + /// User-defined stack maps. + /// + /// Not to be confused with the stack maps that `regalloc2` produces. These + /// are defined by the user in `cranelift-frontend`. These will eventually + /// replace the stack maps support in `regalloc2`, but in the name of + /// incrementalism and avoiding gigantic PRs that completely overhaul + /// Cranelift and Wasmtime at the same time, we are allowing them to live in + /// parallel for the time being. + user_stack_maps: alloc::collections::BTreeMap, + + /// basic blocks in the function and their parameters. + /// + /// This map is not in program order. That is handled by `Layout`, and so is the sequence of + /// instructions contained in each block. + pub blocks: Blocks, + + /// Dynamic types created. + pub dynamic_types: DynamicTypes, + + /// Memory pool of value lists. + /// + /// The `ValueList` references into this pool appear in many places: + /// + /// - Instructions in `insts` that don't have room for their entire argument list inline. + /// - Instruction result values in `results`. + /// - block parameters in `blocks`. + pub value_lists: ValueListPool, + + /// Primary value table with entries for all values. + values: PrimaryMap, + + /// Facts: proof-carrying-code assertions about values. + pub facts: SecondaryMap>, + + /// Function signature table. These signatures are referenced by indirect call instructions as + /// well as the external function references. + pub signatures: PrimaryMap, + + /// External function references. These are functions that can be called directly. + pub ext_funcs: PrimaryMap, + + /// Saves Value labels. + pub values_labels: Option>, + + /// Constants used within the function. + pub constants: ConstantPool, + + /// Stores large immediates that otherwise will not fit on InstructionData. + pub immediates: PrimaryMap, + + /// Jump tables used in this function. + pub jump_tables: JumpTables, +} + +impl DataFlowGraph { + /// Create a new empty `DataFlowGraph`. + pub fn new() -> Self { + Self { + insts: Insts(PrimaryMap::new()), + results: SecondaryMap::new(), + user_stack_maps: alloc::collections::BTreeMap::new(), + blocks: Blocks(PrimaryMap::new()), + dynamic_types: DynamicTypes::new(), + value_lists: ValueListPool::new(), + values: PrimaryMap::new(), + facts: SecondaryMap::new(), + signatures: PrimaryMap::new(), + ext_funcs: PrimaryMap::new(), + values_labels: None, + constants: ConstantPool::new(), + immediates: PrimaryMap::new(), + jump_tables: JumpTables::new(), + } + } + + /// Clear everything. + pub fn clear(&mut self) { + self.insts.0.clear(); + self.results.clear(); + self.user_stack_maps.clear(); + self.blocks.0.clear(); + self.dynamic_types.clear(); + self.value_lists.clear(); + self.values.clear(); + self.signatures.clear(); + self.ext_funcs.clear(); + self.values_labels = None; + self.constants.clear(); + self.immediates.clear(); + self.jump_tables.clear(); + self.facts.clear(); + } + + /// Get the total number of instructions created in this function, whether they are currently + /// inserted in the layout or not. + /// + /// This is intended for use with `SecondaryMap::with_capacity`. + pub fn num_insts(&self) -> usize { + self.insts.0.len() + } + + /// Returns `true` if the given instruction reference is valid. + pub fn inst_is_valid(&self, inst: Inst) -> bool { + self.insts.0.is_valid(inst) + } + + /// Get the total number of basic blocks created in this function, whether they are + /// currently inserted in the layout or not. + /// + /// This is intended for use with `SecondaryMap::with_capacity`. + pub fn num_blocks(&self) -> usize { + self.blocks.len() + } + + /// Returns `true` if the given block reference is valid. + pub fn block_is_valid(&self, block: Block) -> bool { + self.blocks.is_valid(block) + } + + /// Make a BlockCall, bundling together the block and its arguments. + pub fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall { + BlockCall::new(block, args, &mut self.value_lists) + } + + /// Get the total number of values. + pub fn num_values(&self) -> usize { + self.values.len() + } + + /// Get an iterator over all values and their definitions. + pub fn values_and_defs(&self) -> impl Iterator + '_ { + self.values().map(|value| (value, self.value_def(value))) + } + + /// Starts collection of debug information. + pub fn collect_debug_info(&mut self) { + if self.values_labels.is_none() { + self.values_labels = Some(Default::default()); + } + } + + /// Inserts a `ValueLabelAssignments::Alias` for `to_alias` if debug info + /// collection is enabled. + pub fn add_value_label_alias(&mut self, to_alias: Value, from: RelSourceLoc, value: Value) { + if let Some(values_labels) = self.values_labels.as_mut() { + values_labels.insert(to_alias, ir::ValueLabelAssignments::Alias { from, value }); + } + } +} + +/// Resolve value aliases. +/// +/// Find the original SSA value that `value` aliases, or None if an +/// alias cycle is detected. +fn maybe_resolve_aliases( + values: &PrimaryMap, + value: Value, +) -> Option { + let mut v = value; + + // Note that values may be empty here. + for _ in 0..=values.len() { + if let ValueData::Alias { original, .. } = ValueData::from(values[v]) { + v = original; + } else { + return Some(v); + } + } + + None +} + +/// Resolve value aliases. +/// +/// Find the original SSA value that `value` aliases. +fn resolve_aliases(values: &PrimaryMap, value: Value) -> Value { + if let Some(v) = maybe_resolve_aliases(values, value) { + v + } else { + panic!("Value alias loop detected for {value}"); + } +} + +/// Iterator over all Values in a DFG. +pub struct Values<'a> { + inner: entity::Iter<'a, Value, ValueDataPacked>, +} + +/// Check for non-values. +fn valid_valuedata(data: ValueDataPacked) -> bool { + let data = ValueData::from(data); + if let ValueData::Alias { + ty: types::INVALID, + original, + } = ValueData::from(data) + { + if original == Value::reserved_value() { + return false; + } + } + true +} + +impl<'a> Iterator for Values<'a> { + type Item = Value; + + fn next(&mut self) -> Option { + self.inner + .by_ref() + .find(|kv| valid_valuedata(*kv.1)) + .map(|kv| kv.0) + } +} + +/// Handling values. +/// +/// Values are either block parameters or instruction results. +impl DataFlowGraph { + /// Allocate an extended value entry. + fn make_value(&mut self, data: ValueData) -> Value { + self.values.push(data.into()) + } + + /// Get an iterator over all values. + pub fn values<'a>(&'a self) -> Values<'a> { + Values { + inner: self.values.iter(), + } + } + + /// Check if a value reference is valid. + pub fn value_is_valid(&self, v: Value) -> bool { + self.values.is_valid(v) + } + + /// Check whether a value is valid and not an alias. + pub fn value_is_real(&self, value: Value) -> bool { + // Deleted or unused values are also stored as aliases so this excludes + // those as well. + self.value_is_valid(value) && !matches!(self.values[value].into(), ValueData::Alias { .. }) + } + + /// Get the type of a value. + pub fn value_type(&self, v: Value) -> Type { + self.values[v].ty() + } + + /// Get the definition of a value. + /// + /// This is either the instruction that defined it or the Block that has the value as an + /// parameter. + pub fn value_def(&self, v: Value) -> ValueDef { + match ValueData::from(self.values[v]) { + ValueData::Inst { inst, num, .. } => ValueDef::Result(inst, num as usize), + ValueData::Param { block, num, .. } => ValueDef::Param(block, num as usize), + ValueData::Alias { original, .. } => { + // Make sure we only recurse one level. `resolve_aliases` has safeguards to + // detect alias loops without overrunning the stack. + self.value_def(self.resolve_aliases(original)) + } + ValueData::Union { x, y, .. } => ValueDef::Union(x, y), + } + } + + /// Determine if `v` is an attached instruction result / block parameter. + /// + /// An attached value can't be attached to something else without first being detached. + /// + /// Value aliases are not considered to be attached to anything. Use `resolve_aliases()` to + /// determine if the original aliased value is attached. + pub fn value_is_attached(&self, v: Value) -> bool { + use self::ValueData::*; + match ValueData::from(self.values[v]) { + Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize), + Param { block, num, .. } => Some(&v) == self.block_params(block).get(num as usize), + Alias { .. } => false, + Union { .. } => false, + } + } + + /// Resolve value aliases. + /// + /// Find the original SSA value that `value` aliases. + pub fn resolve_aliases(&self, value: Value) -> Value { + resolve_aliases(&self.values, value) + } + + /// Replace all uses of value aliases with their resolved values, and delete + /// the aliases. + pub fn resolve_all_aliases(&mut self) { + let invalid_value = ValueDataPacked::from(ValueData::Alias { + ty: types::INVALID, + original: Value::reserved_value(), + }); + + // Rewrite each chain of aliases. Update every alias along the chain + // into an alias directly to the final value. Due to updating every + // alias that it looks at, this loop runs in time linear in the number + // of values. + for mut src in self.values.keys() { + let value_data = self.values[src]; + if value_data == invalid_value { + continue; + } + if let ValueData::Alias { mut original, .. } = value_data.into() { + // We don't use the type after this, we just need some place to + // store the resolved aliases temporarily. + let resolved = ValueDataPacked::from(ValueData::Alias { + ty: types::INVALID, + original: resolve_aliases(&self.values, original), + }); + // Walk the chain again, splatting the new alias everywhere. + // resolve_aliases panics if there's an alias cycle, so we don't + // need to guard against cycles here. + loop { + self.values[src] = resolved; + src = original; + if let ValueData::Alias { original: next, .. } = self.values[src].into() { + original = next; + } else { + break; + } + } + } + } + + // Now aliases don't point to other aliases, so we can replace any use + // of an alias with the final value in constant time. + + // Rewrite InstructionData in `self.insts`. + for inst in self.insts.0.values_mut() { + inst.map_values(&mut self.value_lists, &mut self.jump_tables, |arg| { + if let ValueData::Alias { original, .. } = self.values[arg].into() { + original + } else { + arg + } + }); + } + + // - `results` and block-params in `blocks` are not aliases, by + // definition. + // - `dynamic_types` has no values. + // - `value_lists` can only be accessed via references from elsewhere. + // - `values` only has value references in aliases (which we've + // removed), and unions (but the egraph pass ensures there are no + // aliases before creating unions). + + // Merge `facts` from any alias onto the aliased value. Note that if + // there was a chain of aliases, at this point every alias that was in + // the chain points to the same final value, so their facts will all be + // merged together. + for value in self.facts.keys() { + if let ValueData::Alias { original, .. } = self.values[value].into() { + if let Some(new_fact) = self.facts[value].take() { + match &mut self.facts[original] { + Some(old_fact) => *old_fact = Fact::intersect(old_fact, &new_fact), + old_fact => *old_fact = Some(new_fact), + } + } + } + } + + // - `signatures` and `ext_funcs` have no values. + + if let Some(values_labels) = &mut self.values_labels { + // Debug info is best-effort. If any is attached to value aliases, + // just discard it. + values_labels.retain(|&k, _| !matches!(self.values[k].into(), ValueData::Alias { .. })); + + // If debug-info says a value should have the same labels as another + // value, then make sure that target is not a value alias. + for value_label in values_labels.values_mut() { + if let ValueLabelAssignments::Alias { value, .. } = value_label { + if let ValueData::Alias { original, .. } = self.values[*value].into() { + *value = original; + } + } + } + } + + // - `constants` and `immediates` have no values. + // - `jump_tables` is updated together with instruction-data above. + + // Delete all aliases now that there are no uses left. + for value in self.values.values_mut() { + if let ValueData::Alias { .. } = ValueData::from(*value) { + *value = invalid_value; + } + } + } + + /// Turn a value into an alias of another. + /// + /// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest` + /// will behave as if they used that value `src`. + /// + /// The `dest` value can't be attached to an instruction or block. + pub fn change_to_alias(&mut self, dest: Value, src: Value) { + debug_assert!(!self.value_is_attached(dest)); + // Try to create short alias chains by finding the original source value. + // This also avoids the creation of loops. + let original = self.resolve_aliases(src); + debug_assert_ne!( + dest, original, + "Aliasing {dest} to {src} would create a loop" + ); + let ty = self.value_type(original); + debug_assert_eq!( + self.value_type(dest), + ty, + "Aliasing {} to {} would change its type {} to {}", + dest, + src, + self.value_type(dest), + ty + ); + debug_assert_ne!(ty, types::INVALID); + + self.values[dest] = ValueData::Alias { ty, original }.into(); + } + + /// Replace the results of one instruction with aliases to the results of another. + /// + /// Change all the results of `dest_inst` to behave as aliases of + /// corresponding results of `src_inst`, as if calling change_to_alias for + /// each. + /// + /// After calling this instruction, `dest_inst` will have had its results + /// cleared, so it likely needs to be removed from the graph. + /// + pub fn replace_with_aliases(&mut self, dest_inst: Inst, original_inst: Inst) { + debug_assert_ne!( + dest_inst, original_inst, + "Replacing {dest_inst} with itself would create a loop" + ); + + let dest_results = self.results[dest_inst].as_slice(&self.value_lists); + let original_results = self.results[original_inst].as_slice(&self.value_lists); + + debug_assert_eq!( + dest_results.len(), + original_results.len(), + "Replacing {dest_inst} with {original_inst} would produce a different number of results." + ); + + for (&dest, &original) in dest_results.iter().zip(original_results) { + let ty = self.value_type(original); + debug_assert_eq!( + self.value_type(dest), + ty, + "Aliasing {} to {} would change its type {} to {}", + dest, + original, + self.value_type(dest), + ty + ); + debug_assert_ne!(ty, types::INVALID); + + self.values[dest] = ValueData::Alias { ty, original }.into(); + } + + self.clear_results(dest_inst); + } + + /// Get the stack map entries associated with the given instruction. + pub fn user_stack_map_entries(&self, inst: Inst) -> Option<&[UserStackMapEntry]> { + self.user_stack_maps.get(&inst).map(|es| &**es) + } + + /// Append a new stack map entry for the given call instruction. + /// + /// # Panics + /// + /// Panics if the given instruction is not a (non-tail) call instruction. + pub fn append_user_stack_map_entry(&mut self, inst: Inst, entry: UserStackMapEntry) { + let opcode = self.insts[inst].opcode(); + assert!(opcode.is_safepoint()); + self.user_stack_maps.entry(inst).or_default().push(entry); + } +} + +/// Where did a value come from? +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ValueDef { + /// Value is the n'th result of an instruction. + Result(Inst, usize), + /// Value is the n'th parameter to a block. + Param(Block, usize), + /// Value is a union of two other values. + Union(Value, Value), +} + +impl ValueDef { + /// Unwrap the instruction where the value was defined, or panic. + pub fn unwrap_inst(&self) -> Inst { + self.inst().expect("Value is not an instruction result") + } + + /// Get the instruction where the value was defined, if any. + pub fn inst(&self) -> Option { + match *self { + Self::Result(inst, _) => Some(inst), + _ => None, + } + } + + /// Unwrap the block there the parameter is defined, or panic. + pub fn unwrap_block(&self) -> Block { + match *self { + Self::Param(block, _) => block, + _ => panic!("Value is not a block parameter"), + } + } + + /// Get the number component of this definition. + /// + /// When multiple values are defined at the same program point, this indicates the index of + /// this value. + pub fn num(self) -> usize { + match self { + Self::Result(_, n) | Self::Param(_, n) => n, + Self::Union(_, _) => 0, + } + } +} + +/// Internal table storage for extended values. +#[derive(Clone, Debug, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +enum ValueData { + /// Value is defined by an instruction. + Inst { ty: Type, num: u16, inst: Inst }, + + /// Value is a block parameter. + Param { ty: Type, num: u16, block: Block }, + + /// Value is an alias of another value. + /// An alias value can't be linked as an instruction result or block parameter. It is used as a + /// placeholder when the original instruction or block has been rewritten or modified. + Alias { ty: Type, original: Value }, + + /// Union is a "fork" in representation: the value can be + /// represented as either of the values named here. This is used + /// for aegraph (acyclic egraph) representation in the DFG. + Union { ty: Type, x: Value, y: Value }, +} + +/// Bit-packed version of ValueData, for efficiency. +/// +/// Layout: +/// +/// ```plain +/// | tag:2 | type:14 | x:24 | y:24 | +/// +/// Inst 00 ty inst output inst index +/// Param 01 ty blockparam num block index +/// Alias 10 ty 0 value index +/// Union 11 ty first value second value +/// ``` +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +struct ValueDataPacked(u64); + +/// Encodes a value in 0..2^32 into 0..2^n, where n is less than 32 +/// (and is implied by `mask`), by translating 2^32-1 (0xffffffff) +/// into 2^n-1 and panic'ing on 2^n..2^32-1. +fn encode_narrow_field(x: u32, bits: u8) -> u32 { + let max = (1 << bits) - 1; + if x == 0xffff_ffff { + max + } else { + debug_assert!( + x < max, + "{x} does not fit into {bits} bits (must be less than {max} to \ + allow for a 0xffffffff sentinel)" + ); + x + } +} + +/// The inverse of the above `encode_narrow_field`: unpacks 2^n-1 into +/// 2^32-1. +fn decode_narrow_field(x: u32, bits: u8) -> u32 { + if x == (1 << bits) - 1 { + 0xffff_ffff + } else { + x + } +} + +impl ValueDataPacked { + const Y_SHIFT: u8 = 0; + const Y_BITS: u8 = 24; + const X_SHIFT: u8 = Self::Y_SHIFT + Self::Y_BITS; + const X_BITS: u8 = 24; + const TYPE_SHIFT: u8 = Self::X_SHIFT + Self::X_BITS; + const TYPE_BITS: u8 = 14; + const TAG_SHIFT: u8 = Self::TYPE_SHIFT + Self::TYPE_BITS; + const TAG_BITS: u8 = 2; + + const TAG_INST: u64 = 0; + const TAG_PARAM: u64 = 1; + const TAG_ALIAS: u64 = 2; + const TAG_UNION: u64 = 3; + + fn make(tag: u64, ty: Type, x: u32, y: u32) -> ValueDataPacked { + debug_assert!(tag < (1 << Self::TAG_BITS)); + debug_assert!(ty.repr() < (1 << Self::TYPE_BITS)); + + let x = encode_narrow_field(x, Self::X_BITS); + let y = encode_narrow_field(y, Self::Y_BITS); + + ValueDataPacked( + (tag << Self::TAG_SHIFT) + | ((ty.repr() as u64) << Self::TYPE_SHIFT) + | ((x as u64) << Self::X_SHIFT) + | ((y as u64) << Self::Y_SHIFT), + ) + } + + #[inline(always)] + fn field(self, shift: u8, bits: u8) -> u64 { + (self.0 >> shift) & ((1 << bits) - 1) + } + + #[inline(always)] + fn ty(self) -> Type { + let ty = self.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS) as u16; + Type::from_repr(ty) + } + + #[inline(always)] + fn set_type(&mut self, ty: Type) { + self.0 &= !(((1 << Self::TYPE_BITS) - 1) << Self::TYPE_SHIFT); + self.0 |= (ty.repr() as u64) << Self::TYPE_SHIFT; + } +} + +impl From for ValueDataPacked { + fn from(data: ValueData) -> Self { + match data { + ValueData::Inst { ty, num, inst } => { + Self::make(Self::TAG_INST, ty, num.into(), inst.as_bits()) + } + ValueData::Param { ty, num, block } => { + Self::make(Self::TAG_PARAM, ty, num.into(), block.as_bits()) + } + ValueData::Alias { ty, original } => { + Self::make(Self::TAG_ALIAS, ty, 0, original.as_bits()) + } + ValueData::Union { ty, x, y } => { + Self::make(Self::TAG_UNION, ty, x.as_bits(), y.as_bits()) + } + } + } +} + +impl From for ValueData { + fn from(data: ValueDataPacked) -> Self { + let tag = data.field(ValueDataPacked::TAG_SHIFT, ValueDataPacked::TAG_BITS); + let ty = u16::try_from(data.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS)) + .expect("Mask should ensure result fits in a u16"); + let x = u32::try_from(data.field(ValueDataPacked::X_SHIFT, ValueDataPacked::X_BITS)) + .expect("Mask should ensure result fits in a u32"); + let y = u32::try_from(data.field(ValueDataPacked::Y_SHIFT, ValueDataPacked::Y_BITS)) + .expect("Mask should ensure result fits in a u32"); + + let ty = Type::from_repr(ty); + match tag { + ValueDataPacked::TAG_INST => ValueData::Inst { + ty, + num: u16::try_from(x).expect("Inst result num should fit in u16"), + inst: Inst::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)), + }, + ValueDataPacked::TAG_PARAM => ValueData::Param { + ty, + num: u16::try_from(x).expect("Blockparam index should fit in u16"), + block: Block::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)), + }, + ValueDataPacked::TAG_ALIAS => ValueData::Alias { + ty, + original: Value::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)), + }, + ValueDataPacked::TAG_UNION => ValueData::Union { + ty, + x: Value::from_bits(decode_narrow_field(x, ValueDataPacked::X_BITS)), + y: Value::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)), + }, + _ => panic!("Invalid tag {} in ValueDataPacked 0x{:x}", tag, data.0), + } + } +} + +/// Instructions. +/// +impl DataFlowGraph { + /// Create a new instruction. + /// + /// The type of the first result is indicated by `data.ty`. If the + /// instruction produces multiple results, also call + /// `make_inst_results` to allocate value table entries. (It is + /// always safe to call `make_inst_results`, regardless of how + /// many results the instruction has.) + pub fn make_inst(&mut self, data: InstructionData) -> Inst { + let n = self.num_insts() + 1; + self.results.resize(n); + self.insts.0.push(data) + } + + /// Declares a dynamic vector type + pub fn make_dynamic_ty(&mut self, data: DynamicTypeData) -> DynamicType { + self.dynamic_types.push(data) + } + + /// Returns an object that displays `inst`. + pub fn display_inst<'a>(&'a self, inst: Inst) -> DisplayInst<'a> { + DisplayInst(self, inst) + } + + /// Returns an object that displays the given `value`'s defining instruction. + /// + /// Panics if the value is not defined by an instruction (i.e. it is a basic + /// block argument). + pub fn display_value_inst(&self, value: Value) -> DisplayInst<'_> { + match self.value_def(value) { + ir::ValueDef::Result(inst, _) => self.display_inst(inst), + ir::ValueDef::Param(_, _) => panic!("value is not defined by an instruction"), + ir::ValueDef::Union(_, _) => panic!("value is a union of two other values"), + } + } + + /// Construct a read-only visitor context for the values of this instruction. + pub fn inst_values<'dfg>( + &'dfg self, + inst: Inst, + ) -> impl DoubleEndedIterator + 'dfg { + self.inst_args(inst) + .iter() + .chain( + self.insts[inst] + .branch_destination(&self.jump_tables) + .into_iter() + .flat_map(|branch| branch.args_slice(&self.value_lists).iter()), + ) + .copied() + } + + /// Map a function over the values of the instruction. + pub fn map_inst_values(&mut self, inst: Inst, body: F) + where + F: FnMut(Value) -> Value, + { + self.insts[inst].map_values(&mut self.value_lists, &mut self.jump_tables, body); + } + + /// Overwrite the instruction's value references with values from the iterator. + /// NOTE: the iterator provided is expected to yield at least as many values as the instruction + /// currently has. + pub fn overwrite_inst_values(&mut self, inst: Inst, mut values: I) + where + I: Iterator, + { + self.insts[inst].map_values(&mut self.value_lists, &mut self.jump_tables, |_| { + values.next().unwrap() + }); + } + + /// Get all value arguments on `inst` as a slice. + pub fn inst_args(&self, inst: Inst) -> &[Value] { + self.insts[inst].arguments(&self.value_lists) + } + + /// Get all value arguments on `inst` as a mutable slice. + pub fn inst_args_mut(&mut self, inst: Inst) -> &mut [Value] { + self.insts[inst].arguments_mut(&mut self.value_lists) + } + + /// Get the fixed value arguments on `inst` as a slice. + pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] { + let num_fixed_args = self.insts[inst] + .opcode() + .constraints() + .num_fixed_value_arguments(); + &self.inst_args(inst)[..num_fixed_args] + } + + /// Get the fixed value arguments on `inst` as a mutable slice. + pub fn inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value] { + let num_fixed_args = self.insts[inst] + .opcode() + .constraints() + .num_fixed_value_arguments(); + &mut self.inst_args_mut(inst)[..num_fixed_args] + } + + /// Get the variable value arguments on `inst` as a slice. + pub fn inst_variable_args(&self, inst: Inst) -> &[Value] { + let num_fixed_args = self.insts[inst] + .opcode() + .constraints() + .num_fixed_value_arguments(); + &self.inst_args(inst)[num_fixed_args..] + } + + /// Get the variable value arguments on `inst` as a mutable slice. + pub fn inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value] { + let num_fixed_args = self.insts[inst] + .opcode() + .constraints() + .num_fixed_value_arguments(); + &mut self.inst_args_mut(inst)[num_fixed_args..] + } + + /// Create result values for an instruction that produces multiple results. + /// + /// Instructions that produce no result values only need to be created with `make_inst`, + /// otherwise call `make_inst_results` to allocate value table entries for the results. + /// + /// The result value types are determined from the instruction's value type constraints and the + /// provided `ctrl_typevar` type for polymorphic instructions. For non-polymorphic + /// instructions, `ctrl_typevar` is ignored, and `INVALID` can be used. + /// + /// The type of the first result value is also set, even if it was already set in the + /// `InstructionData` passed to `make_inst`. If this function is called with a single-result + /// instruction, that is the only effect. + pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize { + self.make_inst_results_reusing(inst, ctrl_typevar, iter::empty()) + } + + /// Create result values for `inst`, reusing the provided detached values. + /// + /// Create a new set of result values for `inst` using `ctrl_typevar` to determine the result + /// types. Any values provided by `reuse` will be reused. When `reuse` is exhausted or when it + /// produces `None`, a new value is created. + pub fn make_inst_results_reusing( + &mut self, + inst: Inst, + ctrl_typevar: Type, + reuse: I, + ) -> usize + where + I: Iterator>, + { + self.clear_results(inst); + + let mut reuse = reuse.fuse(); + let result_tys: SmallVec<[_; 16]> = self.inst_result_types(inst, ctrl_typevar).collect(); + + for (expected, &ty) in result_tys.iter().enumerate() { + let num = u16::try_from(expected).expect("Result value index should fit in u16"); + let value_data = ValueData::Inst { ty, num, inst }; + let v = if let Some(Some(v)) = reuse.next() { + debug_assert_eq!(self.value_type(v), ty, "Reused {ty} is wrong type"); + debug_assert!(!self.value_is_attached(v)); + self.values[v] = value_data.into(); + v + } else { + self.make_value(value_data) + }; + let actual = self.results[inst].push(v, &mut self.value_lists); + debug_assert_eq!(expected, actual); + } + + result_tys.len() + } + + /// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place. + pub fn replace(&mut self, inst: Inst) -> ReplaceBuilder { + ReplaceBuilder::new(self, inst) + } + + /// Clear the list of result values from `inst`. + /// + /// This leaves `inst` without any result values. New result values can be created by calling + /// `make_inst_results` or by using a `replace(inst)` builder. + pub fn clear_results(&mut self, inst: Inst) { + self.results[inst].clear(&mut self.value_lists) + } + + /// Replace an instruction result with a new value of type `new_type`. + /// + /// The `old_value` must be an attached instruction result. + /// + /// The old value is left detached, so it should probably be changed into something else. + /// + /// Returns the new value. + pub fn replace_result(&mut self, old_value: Value, new_type: Type) -> Value { + let (num, inst) = match ValueData::from(self.values[old_value]) { + ValueData::Inst { num, inst, .. } => (num, inst), + _ => panic!("{old_value} is not an instruction result value"), + }; + let new_value = self.make_value(ValueData::Inst { + ty: new_type, + num, + inst, + }); + let num = num as usize; + let attached = mem::replace( + self.results[inst] + .get_mut(num, &mut self.value_lists) + .expect("Replacing detached result"), + new_value, + ); + debug_assert_eq!( + attached, + old_value, + "{} wasn't detached from {}", + old_value, + self.display_inst(inst) + ); + new_value + } + + /// Clone an instruction, attaching new result `Value`s and + /// returning them. + pub fn clone_inst(&mut self, inst: Inst) -> Inst { + // First, add a clone of the InstructionData. + let inst_data = self.insts[inst]; + // If the `inst_data` has a reference to a ValueList, clone it + // as well, because we can't share these (otherwise mutating + // one would affect the other). + let inst_data = inst_data.deep_clone(&mut self.value_lists); + let new_inst = self.make_inst(inst_data); + // Get the controlling type variable. + let ctrl_typevar = self.ctrl_typevar(inst); + // Create new result values. + let num_results = self.make_inst_results(new_inst, ctrl_typevar); + // Copy over PCC facts, if any. + for i in 0..num_results { + let old_result = self.inst_results(inst)[i]; + let new_result = self.inst_results(new_inst)[i]; + self.facts[new_result] = self.facts[old_result].clone(); + } + new_inst + } + + /// Get the first result of an instruction. + /// + /// This function panics if the instruction doesn't have any result. + pub fn first_result(&self, inst: Inst) -> Value { + self.results[inst] + .first(&self.value_lists) + .expect("Instruction has no results") + } + + /// Test if `inst` has any result values currently. + pub fn has_results(&self, inst: Inst) -> bool { + !self.results[inst].is_empty() + } + + /// Return all the results of an instruction. + pub fn inst_results(&self, inst: Inst) -> &[Value] { + self.results[inst].as_slice(&self.value_lists) + } + + /// Return all the results of an instruction as ValueList. + pub fn inst_results_list(&self, inst: Inst) -> ValueList { + self.results[inst] + } + + /// Create a union of two values. + pub fn union(&mut self, x: Value, y: Value) -> Value { + // Get the type. + let ty = self.value_type(x); + debug_assert_eq!(ty, self.value_type(y)); + self.make_value(ValueData::Union { ty, x, y }) + } + + /// Get the call signature of a direct or indirect call instruction. + /// Returns `None` if `inst` is not a call instruction. + pub fn call_signature(&self, inst: Inst) -> Option { + match self.insts[inst].analyze_call(&self.value_lists) { + CallInfo::NotACall => None, + CallInfo::Direct(f, _) => Some(self.ext_funcs[f].signature), + CallInfo::Indirect(s, _) => Some(s), + } + } + + /// Like `call_signature` but returns none for tail call instructions. + fn non_tail_call_signature(&self, inst: Inst) -> Option { + let sig = self.call_signature(inst)?; + match self.insts[inst].opcode() { + ir::Opcode::ReturnCall | ir::Opcode::ReturnCallIndirect => None, + _ => Some(sig), + } + } + + // Only for use by the verifier. Everyone else should just use + // `dfg.inst_results(inst).len()`. + pub(crate) fn num_expected_results_for_verifier(&self, inst: Inst) -> usize { + match self.non_tail_call_signature(inst) { + Some(sig) => self.signatures[sig].returns.len(), + None => { + let constraints = self.insts[inst].opcode().constraints(); + constraints.num_fixed_results() + } + } + } + + /// Get the result types of the given instruction. + pub fn inst_result_types<'a>( + &'a self, + inst: Inst, + ctrl_typevar: Type, + ) -> impl iter::ExactSizeIterator + 'a { + return match self.non_tail_call_signature(inst) { + Some(sig) => InstResultTypes::Signature(self, sig, 0), + None => { + let constraints = self.insts[inst].opcode().constraints(); + InstResultTypes::Constraints(constraints, ctrl_typevar, 0) + } + }; + + enum InstResultTypes<'a> { + Signature(&'a DataFlowGraph, SigRef, usize), + Constraints(ir::instructions::OpcodeConstraints, Type, usize), + } + + impl Iterator for InstResultTypes<'_> { + type Item = Type; + + fn next(&mut self) -> Option { + match self { + InstResultTypes::Signature(dfg, sig, i) => { + let param = dfg.signatures[*sig].returns.get(*i)?; + *i += 1; + Some(param.value_type) + } + InstResultTypes::Constraints(constraints, ctrl_ty, i) => { + if *i < constraints.num_fixed_results() { + let ty = constraints.result_type(*i, *ctrl_ty); + *i += 1; + Some(ty) + } else { + None + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = match self { + InstResultTypes::Signature(dfg, sig, i) => { + dfg.signatures[*sig].returns.len() - *i + } + InstResultTypes::Constraints(constraints, _, i) => { + constraints.num_fixed_results() - *i + } + }; + (len, Some(len)) + } + } + + impl ExactSizeIterator for InstResultTypes<'_> {} + } + + /// Compute the type of an instruction result from opcode constraints and call signatures. + /// + /// This computes the same sequence of result types that `make_inst_results()` above would + /// assign to the created result values, but it does not depend on `make_inst_results()` being + /// called first. + /// + /// Returns `None` if asked about a result index that is too large. + pub fn compute_result_type( + &self, + inst: Inst, + result_idx: usize, + ctrl_typevar: Type, + ) -> Option { + self.inst_result_types(inst, ctrl_typevar).nth(result_idx) + } + + /// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic. + pub fn ctrl_typevar(&self, inst: Inst) -> Type { + let constraints = self.insts[inst].opcode().constraints(); + + if !constraints.is_polymorphic() { + types::INVALID + } else if constraints.requires_typevar_operand() { + // Not all instruction formats have a designated operand, but in that case + // `requires_typevar_operand()` should never be true. + self.value_type( + self.insts[inst] + .typevar_operand(&self.value_lists) + .unwrap_or_else(|| { + panic!( + "Instruction format for {:?} doesn't have a designated operand", + self.insts[inst] + ) + }), + ) + } else { + self.value_type(self.first_result(inst)) + } + } +} + +/// basic blocks. +impl DataFlowGraph { + /// Create a new basic block. + pub fn make_block(&mut self) -> Block { + self.blocks.add() + } + + /// Get the number of parameters on `block`. + pub fn num_block_params(&self, block: Block) -> usize { + self.blocks[block].params(&self.value_lists).len() + } + + /// Get the parameters on `block`. + pub fn block_params(&self, block: Block) -> &[Value] { + self.blocks[block].params(&self.value_lists) + } + + /// Get the types of the parameters on `block`. + pub fn block_param_types(&self, block: Block) -> impl Iterator + '_ { + self.block_params(block).iter().map(|&v| self.value_type(v)) + } + + /// Append a parameter with type `ty` to `block`. + pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value { + let param = self.values.next_key(); + let num = self.blocks[block].params.push(param, &mut self.value_lists); + debug_assert!(num <= u16::MAX as usize, "Too many parameters on block"); + self.make_value(ValueData::Param { + ty, + num: num as u16, + block, + }) + } + + /// Removes `val` from `block`'s parameters by swapping it with the last parameter on `block`. + /// Returns the position of `val` before removal. + /// + /// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the + /// last `block` parameter. This can disrupt all the branch instructions jumping to this + /// `block` for which you have to change the branch argument order if necessary. + /// + /// Panics if `val` is not a block parameter. + pub fn swap_remove_block_param(&mut self, val: Value) -> usize { + let (block, num) = + if let ValueData::Param { num, block, .. } = ValueData::from(self.values[val]) { + (block, num) + } else { + panic!("{val} must be a block parameter"); + }; + self.blocks[block] + .params + .swap_remove(num as usize, &mut self.value_lists); + if let Some(last_arg_val) = self.blocks[block] + .params + .get(num as usize, &self.value_lists) + { + // We update the position of the old last arg. + let mut last_arg_data = ValueData::from(self.values[last_arg_val]); + if let ValueData::Param { + num: ref mut old_num, + .. + } = &mut last_arg_data + { + *old_num = num; + self.values[last_arg_val] = last_arg_data.into(); + } else { + panic!("{last_arg_val} should be a Block parameter"); + } + } + num as usize + } + + /// Removes `val` from `block`'s parameters by a standard linear time list removal which + /// preserves ordering. Also updates the values' data. + pub fn remove_block_param(&mut self, val: Value) { + let (block, num) = + if let ValueData::Param { num, block, .. } = ValueData::from(self.values[val]) { + (block, num) + } else { + panic!("{val} must be a block parameter"); + }; + self.blocks[block] + .params + .remove(num as usize, &mut self.value_lists); + for index in num..(self.num_block_params(block) as u16) { + let packed = &mut self.values[self.blocks[block] + .params + .get(index as usize, &self.value_lists) + .unwrap()]; + let mut data = ValueData::from(*packed); + match &mut data { + ValueData::Param { ref mut num, .. } => { + *num -= 1; + *packed = data.into(); + } + _ => panic!( + "{} must be a block parameter", + self.blocks[block] + .params + .get(index as usize, &self.value_lists) + .unwrap() + ), + } + } + } + + /// Append an existing value to `block`'s parameters. + /// + /// The appended value can't already be attached to something else. + /// + /// In almost all cases, you should be using `append_block_param()` instead of this method. + pub fn attach_block_param(&mut self, block: Block, param: Value) { + debug_assert!(!self.value_is_attached(param)); + let num = self.blocks[block].params.push(param, &mut self.value_lists); + debug_assert!(num <= u16::MAX as usize, "Too many parameters on block"); + let ty = self.value_type(param); + self.values[param] = ValueData::Param { + ty, + num: num as u16, + block, + } + .into(); + } + + /// Replace a block parameter with a new value of type `ty`. + /// + /// The `old_value` must be an attached block parameter. It is removed from its place in the list + /// of parameters and replaced by a new value of type `new_type`. The new value gets the same + /// position in the list, and other parameters are not disturbed. + /// + /// The old value is left detached, so it should probably be changed into something else. + /// + /// Returns the new value. + pub fn replace_block_param(&mut self, old_value: Value, new_type: Type) -> Value { + // Create new value identical to the old one except for the type. + let (block, num) = + if let ValueData::Param { num, block, .. } = ValueData::from(self.values[old_value]) { + (block, num) + } else { + panic!("{old_value} must be a block parameter"); + }; + let new_arg = self.make_value(ValueData::Param { + ty: new_type, + num, + block, + }); + + self.blocks[block] + .params + .as_mut_slice(&mut self.value_lists)[num as usize] = new_arg; + new_arg + } + + /// Detach all the parameters from `block` and return them as a `ValueList`. + /// + /// This is a quite low-level operation. Sensible things to do with the detached block parameters + /// is to put them back on the same block with `attach_block_param()` or change them into aliases + /// with `change_to_alias()`. + pub fn detach_block_params(&mut self, block: Block) -> ValueList { + self.blocks[block].params.take() + } + + /// Merge the facts for two values. If both values have facts and + /// they differ, both values get a special "conflict" fact that is + /// never satisfied. + pub fn merge_facts(&mut self, a: Value, b: Value) { + let a = self.resolve_aliases(a); + let b = self.resolve_aliases(b); + match (&self.facts[a], &self.facts[b]) { + (Some(a), Some(b)) if a == b => { /* nothing */ } + (None, None) => { /* nothing */ } + (Some(a), None) => { + self.facts[b] = Some(a.clone()); + } + (None, Some(b)) => { + self.facts[a] = Some(b.clone()); + } + (Some(a_fact), Some(b_fact)) => { + assert_eq!(self.value_type(a), self.value_type(b)); + let merged = Fact::intersect(a_fact, b_fact); + crate::trace!( + "facts merge on {} and {}: {:?}, {:?} -> {:?}", + a, + b, + a_fact, + b_fact, + merged, + ); + self.facts[a] = Some(merged.clone()); + self.facts[b] = Some(merged); + } + } + } +} + +/// Contents of a basic block. +/// +/// Parameters on a basic block are values that dominate everything in the block. All +/// branches to this block must provide matching arguments, and the arguments to the entry block must +/// match the function arguments. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct BlockData { + /// List of parameters to this block. + params: ValueList, +} + +impl BlockData { + fn new() -> Self { + Self { + params: ValueList::new(), + } + } + + /// Get the parameters on `block`. + pub fn params<'a>(&self, pool: &'a ValueListPool) -> &'a [Value] { + self.params.as_slice(pool) + } +} + +/// Object that can display an instruction. +pub struct DisplayInst<'a>(&'a DataFlowGraph, Inst); + +impl<'a> fmt::Display for DisplayInst<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let dfg = self.0; + let inst = self.1; + + if let Some((first, rest)) = dfg.inst_results(inst).split_first() { + write!(f, "{first}")?; + for v in rest { + write!(f, ", {v}")?; + } + write!(f, " = ")?; + } + + let typevar = dfg.ctrl_typevar(inst); + if typevar.is_invalid() { + write!(f, "{}", dfg.insts[inst].opcode())?; + } else { + write!(f, "{}.{}", dfg.insts[inst].opcode(), typevar)?; + } + write_operands(f, dfg, inst) + } +} + +/// Parser routines. These routines should not be used outside the parser. +impl DataFlowGraph { + /// Set the type of a value. This is only for use in the parser, which needs + /// to create invalid values for index padding which may be reassigned later. + #[cold] + fn set_value_type_for_parser(&mut self, v: Value, t: Type) { + assert_eq!( + self.value_type(v), + types::INVALID, + "this function is only for assigning types to previously invalid values" + ); + self.values[v].set_type(t); + } + + /// Check that the given concrete `Type` has been defined in the function. + pub fn check_dynamic_type(&mut self, ty: Type) -> Option { + debug_assert!(ty.is_dynamic_vector()); + if self + .dynamic_types + .values() + .any(|dyn_ty_data| dyn_ty_data.concrete().unwrap() == ty) + { + Some(ty) + } else { + None + } + } + + /// Create result values for `inst`, reusing the provided detached values. + /// This is similar to `make_inst_results_reusing` except it's only for use + /// in the parser, which needs to reuse previously invalid values. + #[cold] + pub fn make_inst_results_for_parser( + &mut self, + inst: Inst, + ctrl_typevar: Type, + reuse: &[Value], + ) -> usize { + let mut reuse_iter = reuse.iter().copied(); + let result_tys: SmallVec<[_; 16]> = self.inst_result_types(inst, ctrl_typevar).collect(); + for ty in result_tys { + if ty.is_dynamic_vector() { + self.check_dynamic_type(ty) + .unwrap_or_else(|| panic!("Use of undeclared dynamic type: {ty}")); + } + if let Some(v) = reuse_iter.next() { + self.set_value_type_for_parser(v, ty); + } + } + + self.make_inst_results_reusing(inst, ctrl_typevar, reuse.iter().map(|x| Some(*x))) + } + + /// Similar to `append_block_param`, append a parameter with type `ty` to + /// `block`, but using value `val`. This is only for use by the parser to + /// create parameters with specific values. + #[cold] + pub fn append_block_param_for_parser(&mut self, block: Block, ty: Type, val: Value) { + let num = self.blocks[block].params.push(val, &mut self.value_lists); + assert!(num <= u16::MAX as usize, "Too many parameters on block"); + self.values[val] = ValueData::Param { + ty, + num: num as u16, + block, + } + .into(); + } + + /// Create a new value alias. This is only for use by the parser to create + /// aliases with specific values, and the printer for testing. + #[cold] + pub fn make_value_alias_for_serialization(&mut self, src: Value, dest: Value) { + assert_ne!(src, Value::reserved_value()); + assert_ne!(dest, Value::reserved_value()); + + let ty = if self.values.is_valid(src) { + self.value_type(src) + } else { + // As a special case, if we can't resolve the aliasee yet, use INVALID + // temporarily. It will be resolved later in parsing. + types::INVALID + }; + let data = ValueData::Alias { ty, original: src }; + self.values[dest] = data.into(); + } + + /// If `v` is already defined as an alias, return its destination value. + /// Otherwise return None. This allows the parser to coalesce identical + /// alias definitions, and the printer to identify an alias's immediate target. + #[cold] + pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option { + if let ValueData::Alias { original, .. } = ValueData::from(self.values[v]) { + Some(original) + } else { + None + } + } + + /// Compute the type of an alias. This is only for use in the parser. + /// Returns false if an alias cycle was encountered. + #[cold] + pub fn set_alias_type_for_parser(&mut self, v: Value) -> bool { + if let Some(resolved) = maybe_resolve_aliases(&self.values, v) { + let old_ty = self.value_type(v); + let new_ty = self.value_type(resolved); + if old_ty == types::INVALID { + self.set_value_type_for_parser(v, new_ty); + } else { + assert_eq!(old_ty, new_ty); + } + true + } else { + false + } + } + + /// Create an invalid value, to pad the index space. This is only for use by + /// the parser to pad out the value index space. + #[cold] + pub fn make_invalid_value_for_parser(&mut self) { + let data = ValueData::Alias { + ty: types::INVALID, + original: Value::reserved_value(), + }; + self.make_value(data); + } + + /// Check if a value reference is valid, while being aware of aliases which + /// may be unresolved while parsing. + #[cold] + pub fn value_is_valid_for_parser(&self, v: Value) -> bool { + if !self.value_is_valid(v) { + return false; + } + if let ValueData::Alias { ty, .. } = ValueData::from(self.values[v]) { + ty != types::INVALID + } else { + true + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::{Function, Opcode, TrapCode}; + use alloc::string::ToString; + + #[test] + fn make_inst() { + let mut dfg = DataFlowGraph::new(); + + let idata = InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm: 0.into(), + }; + let inst = dfg.make_inst(idata); + + dfg.make_inst_results(inst, types::I32); + assert_eq!(inst.to_string(), "inst0"); + assert_eq!(dfg.display_inst(inst).to_string(), "v0 = iconst.i32 0"); + + // Immutable reference resolution. + { + let immdfg = &dfg; + let ins = &immdfg.insts[inst]; + assert_eq!(ins.opcode(), Opcode::Iconst); + } + + // Results. + let val = dfg.first_result(inst); + assert_eq!(dfg.inst_results(inst), &[val]); + + assert_eq!(dfg.value_def(val), ValueDef::Result(inst, 0)); + assert_eq!(dfg.value_type(val), types::I32); + + // Replacing results. + assert!(dfg.value_is_attached(val)); + let v2 = dfg.replace_result(val, types::F64); + assert!(!dfg.value_is_attached(val)); + assert!(dfg.value_is_attached(v2)); + assert_eq!(dfg.inst_results(inst), &[v2]); + assert_eq!(dfg.value_def(v2), ValueDef::Result(inst, 0)); + assert_eq!(dfg.value_type(v2), types::F64); + } + + #[test] + fn no_results() { + let mut dfg = DataFlowGraph::new(); + + let idata = InstructionData::Trap { + opcode: Opcode::Trap, + code: TrapCode::unwrap_user(1), + }; + let inst = dfg.make_inst(idata); + assert_eq!(dfg.display_inst(inst).to_string(), "trap user1"); + + // Result slice should be empty. + assert_eq!(dfg.inst_results(inst), &[]); + } + + #[test] + fn block() { + let mut dfg = DataFlowGraph::new(); + + let block = dfg.make_block(); + assert_eq!(block.to_string(), "block0"); + assert_eq!(dfg.num_block_params(block), 0); + assert_eq!(dfg.block_params(block), &[]); + assert!(dfg.detach_block_params(block).is_empty()); + assert_eq!(dfg.num_block_params(block), 0); + assert_eq!(dfg.block_params(block), &[]); + + let arg1 = dfg.append_block_param(block, types::F32); + assert_eq!(arg1.to_string(), "v0"); + assert_eq!(dfg.num_block_params(block), 1); + assert_eq!(dfg.block_params(block), &[arg1]); + + let arg2 = dfg.append_block_param(block, types::I16); + assert_eq!(arg2.to_string(), "v1"); + assert_eq!(dfg.num_block_params(block), 2); + assert_eq!(dfg.block_params(block), &[arg1, arg2]); + + assert_eq!(dfg.value_def(arg1), ValueDef::Param(block, 0)); + assert_eq!(dfg.value_def(arg2), ValueDef::Param(block, 1)); + assert_eq!(dfg.value_type(arg1), types::F32); + assert_eq!(dfg.value_type(arg2), types::I16); + + // Swap the two block parameters. + let vlist = dfg.detach_block_params(block); + assert_eq!(dfg.num_block_params(block), 0); + assert_eq!(dfg.block_params(block), &[]); + assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]); + dfg.attach_block_param(block, arg2); + let arg3 = dfg.append_block_param(block, types::I32); + dfg.attach_block_param(block, arg1); + assert_eq!(dfg.block_params(block), &[arg2, arg3, arg1]); + } + + #[test] + fn replace_block_params() { + let mut dfg = DataFlowGraph::new(); + + let block = dfg.make_block(); + let arg1 = dfg.append_block_param(block, types::F32); + + let new1 = dfg.replace_block_param(arg1, types::I64); + assert_eq!(dfg.value_type(arg1), types::F32); + assert_eq!(dfg.value_type(new1), types::I64); + assert_eq!(dfg.block_params(block), &[new1]); + + dfg.attach_block_param(block, arg1); + assert_eq!(dfg.block_params(block), &[new1, arg1]); + + let new2 = dfg.replace_block_param(arg1, types::I8); + assert_eq!(dfg.value_type(arg1), types::F32); + assert_eq!(dfg.value_type(new2), types::I8); + assert_eq!(dfg.block_params(block), &[new1, new2]); + + dfg.attach_block_param(block, arg1); + assert_eq!(dfg.block_params(block), &[new1, new2, arg1]); + + let new3 = dfg.replace_block_param(new2, types::I16); + assert_eq!(dfg.value_type(new1), types::I64); + assert_eq!(dfg.value_type(new2), types::I8); + assert_eq!(dfg.value_type(new3), types::I16); + assert_eq!(dfg.block_params(block), &[new1, new3, arg1]); + } + + #[test] + fn swap_remove_block_params() { + let mut dfg = DataFlowGraph::new(); + + let block = dfg.make_block(); + let arg1 = dfg.append_block_param(block, types::F32); + let arg2 = dfg.append_block_param(block, types::F32); + let arg3 = dfg.append_block_param(block, types::F32); + assert_eq!(dfg.block_params(block), &[arg1, arg2, arg3]); + + dfg.swap_remove_block_param(arg1); + assert_eq!(dfg.value_is_attached(arg1), false); + assert_eq!(dfg.value_is_attached(arg2), true); + assert_eq!(dfg.value_is_attached(arg3), true); + assert_eq!(dfg.block_params(block), &[arg3, arg2]); + dfg.swap_remove_block_param(arg2); + assert_eq!(dfg.value_is_attached(arg2), false); + assert_eq!(dfg.value_is_attached(arg3), true); + assert_eq!(dfg.block_params(block), &[arg3]); + dfg.swap_remove_block_param(arg3); + assert_eq!(dfg.value_is_attached(arg3), false); + assert_eq!(dfg.block_params(block), &[]); + } + + #[test] + fn aliases() { + use crate::ir::condcodes::IntCC; + use crate::ir::InstBuilder; + + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + + // Build a little test program. + let v1 = pos.ins().iconst(types::I32, 42); + + // Make sure we can resolve value aliases even when values is empty. + assert_eq!(pos.func.dfg.resolve_aliases(v1), v1); + + let arg0 = pos.func.dfg.append_block_param(block0, types::I32); + let (s, c) = pos.ins().uadd_overflow(v1, arg0); + let iadd = match pos.func.dfg.value_def(s) { + ValueDef::Result(i, 0) => i, + _ => panic!(), + }; + + // Remove `c` from the result list. + pos.func.stencil.dfg.results[iadd].remove(1, &mut pos.func.stencil.dfg.value_lists); + + // Replace `uadd_overflow` with a normal `iadd` and an `icmp`. + pos.func.dfg.replace(iadd).iadd(v1, arg0); + let c2 = pos.ins().icmp(IntCC::Equal, s, v1); + pos.func.dfg.change_to_alias(c, c2); + + assert_eq!(pos.func.dfg.resolve_aliases(c2), c2); + assert_eq!(pos.func.dfg.resolve_aliases(c), c2); + } + + #[test] + fn cloning() { + use crate::ir::InstBuilder; + + let mut func = Function::new(); + let mut sig = Signature::new(crate::isa::CallConv::SystemV); + sig.params.push(ir::AbiParam::new(types::I32)); + let sig = func.import_signature(sig); + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + let v1 = pos.ins().iconst(types::I32, 0); + let v2 = pos.ins().iconst(types::I32, 1); + let call_inst = pos.ins().call_indirect(sig, v1, &[v1]); + let func = pos.func; + + let call_inst_dup = func.dfg.clone_inst(call_inst); + func.dfg.inst_args_mut(call_inst)[0] = v2; + assert_eq!(v1, func.dfg.inst_args(call_inst_dup)[0]); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/dynamic_type.rs b/deps/crates/vendor/cranelift-codegen/src/ir/dynamic_type.rs new file mode 100644 index 00000000000000..d98ced809ef63a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/dynamic_type.rs @@ -0,0 +1,54 @@ +//! Dynamic IR types + +use crate::ir::entities::DynamicType; +use crate::ir::types::*; +use crate::ir::GlobalValue; +use crate::ir::PrimaryMap; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A dynamic type object which has a base vector type and a scaling factor. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct DynamicTypeData { + /// Base vector type, this is the minimum size of the type. + pub base_vector_ty: Type, + /// The dynamic scaling factor of the base vector type. + pub dynamic_scale: GlobalValue, +} + +impl DynamicTypeData { + /// Create a new dynamic type. + pub fn new(base_vector_ty: Type, dynamic_scale: GlobalValue) -> Self { + assert!(base_vector_ty.is_vector()); + Self { + base_vector_ty, + dynamic_scale, + } + } + + /// Convert 'base_vector_ty' into a concrete dynamic vector type. + pub fn concrete(&self) -> Option { + self.base_vector_ty.vector_to_dynamic() + } +} + +/// All allocated dynamic types. +pub type DynamicTypes = PrimaryMap; + +/// Convert a dynamic-vector type to a fixed-vector type. +pub fn dynamic_to_fixed(ty: Type) -> Type { + match ty { + I8X8XN => I8X8, + I8X16XN => I8X16, + I16X4XN => I16X4, + I16X8XN => I16X8, + I32X2XN => I32X2, + I32X4XN => I32X4, + I64X2XN => I64X2, + F32X4XN => F32X4, + F64X2XN => F64X2, + _ => unreachable!("unhandled type: {}", ty), + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/entities.rs b/deps/crates/vendor/cranelift-codegen/src/ir/entities.rs new file mode 100644 index 00000000000000..005007471b35e3 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/entities.rs @@ -0,0 +1,558 @@ +//! Cranelift IR entity references. +//! +//! Instructions in Cranelift IR need to reference other entities in the function. This can be other +//! parts of the function like basic blocks or stack slots, or it can be external entities +//! that are declared in the function preamble in the text format. +//! +//! These entity references in instruction operands are not implemented as Rust references both +//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers +//! take up a lot of space, and we want a compact in-memory representation. Instead, entity +//! references are structs wrapping a `u32` index into a table in the `Function` main data +//! structure. There is a separate index type for each entity type, so we don't lose type safety. +//! +//! The `entities` module defines public types for the entity references along with constants +//! representing an invalid reference. We prefer to use `Option` whenever possible, but +//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact +//! data structures use the `PackedOption` representation, while function arguments and +//! return values prefer the more Rust-like `Option` variant. +//! +//! The entity references all implement the `Display` trait in a way that matches the textual IR +//! format. + +use crate::entity::entity_impl; +use core::fmt; +use core::u32; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// An opaque reference to a [basic block](https://en.wikipedia.org/wiki/Basic_block) in a +/// [`Function`](super::function::Function). +/// +/// You can get a `Block` using +/// [`FunctionBuilder::create_block`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_block) +/// +/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Block(u32); +entity_impl!(Block, "block"); + +impl Block { + /// Create a new block reference from its number. This corresponds to the `blockNN` representation. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to an SSA value. +/// +/// You can get a constant `Value` from the following +/// [`InstBuilder`](super::InstBuilder) instructions: +/// +/// - [`iconst`](super::InstBuilder::iconst) for integer constants +/// - [`f16const`](super::InstBuilder::f16const) for 16-bit float constants +/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants +/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants +/// - [`f128const`](super::InstBuilder::f128const) for 128-bit float constants +/// - [`vconst`](super::InstBuilder::vconst) for vector constants +/// - [`null`](super::InstBuilder::null) for null reference constants +/// +/// Any `InstBuilder` instruction that has an output will also return a `Value`. +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Value(u32); +entity_impl!(Value, "v"); + +impl Value { + /// Create a value from its number representation. + /// This is the number in the `vNN` notation. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX / 2 { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to an instruction in a [`Function`](super::Function). +/// +/// Most usage of `Inst` is internal. `Inst`ructions are returned by +/// [`InstBuilder`](super::InstBuilder) instructions that do not return a +/// [`Value`], such as control flow and trap instructions, as well as instructions that return a +/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get +/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or +/// its analogue in `cranelift_frontend::FuncBuilder`. +/// +/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs +/// +/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Inst(u32); +entity_impl!(Inst, "inst"); + +/// An opaque reference to a stack slot. +/// +/// Stack slots represent an address on the +/// [call stack](https://en.wikipedia.org/wiki/Call_stack). +/// +/// `StackSlot`s can be created with +/// [`FunctionBuilder::create_sized_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_sized_stack_slot) +/// or +/// [`FunctionBuilder::create_dynamic_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_dynamic_stack_slot). +/// +/// `StackSlot`s are most often used with +/// [`stack_addr`](super::InstBuilder::stack_addr), +/// [`stack_load`](super::InstBuilder::stack_load), and +/// [`stack_store`](super::InstBuilder::stack_store). +/// +/// While the order is stable, it is arbitrary and does not necessarily resemble the stack order. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct StackSlot(u32); +entity_impl!(StackSlot, "ss"); + +impl StackSlot { + /// Create a new stack slot reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a dynamic stack slot. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct DynamicStackSlot(u32); +entity_impl!(DynamicStackSlot, "dss"); + +impl DynamicStackSlot { + /// Create a new stack slot reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a dynamic type. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct DynamicType(u32); +entity_impl!(DynamicType, "dt"); + +impl DynamicType { + /// Create a new dynamic type reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a global value. +/// +/// A `GlobalValue` is a [`Value`] that will be live across the entire +/// function lifetime. It can be preloaded from other global values. +/// +/// You can create a `GlobalValue` in the following ways: +/// +/// - When compiling to native code, you can use it for objects in static memory with +/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_data_in_func). +/// - For any compilation target, it can be registered with +/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value). +/// +/// `GlobalValue`s can be retrieved with +/// [`InstBuilder:global_value`](super::InstBuilder::global_value). +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct GlobalValue(u32); +entity_impl!(GlobalValue, "gv"); + +impl GlobalValue { + /// Create a new global value reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a memory type. +/// +/// A `MemoryType` is a descriptor of a struct layout in memory, with +/// types and proof-carrying-code facts optionally attached to the +/// fields. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MemoryType(u32); +entity_impl!(MemoryType, "mt"); + +impl MemoryType { + /// Create a new memory type reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a constant. +/// +/// You can store [`ConstantData`](super::ConstantData) in a +/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval. +/// See [`ConstantPool::insert`](super::ConstantPool::insert). +/// +/// While the order is stable, it is arbitrary and does not necessarily resemble the order in which +/// the constants are written in the constant pool. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Constant(u32); +entity_impl!(Constant, "const"); + +impl Constant { + /// Create a const reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to an immediate. +/// +/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the +/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be +/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate` +/// provides a way to reference values stored there. +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Immediate(u32); +entity_impl!(Immediate, "imm"); + +impl Immediate { + /// Create an immediate reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table). +/// +/// `JumpTable`s are used for indirect branching and are specialized for dense, +/// 0-based jump offsets. If you want a jump table which doesn't start at 0, +/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead. +/// +/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table). +/// +/// `JumpTable`s can be created with +/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table). +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct JumpTable(u32); +entity_impl!(JumpTable, "jt"); + +impl JumpTable { + /// Create a new jump table reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to another [`Function`](super::Function). +/// +/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls +/// and by [`func_addr`](super::InstBuilder::func_addr) for use in +/// [indirect](super::InstBuilder::call_indirect) function calls. +/// +/// `FuncRef`s can be created with +/// +/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function) +/// for external functions +/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func) +/// for functions declared elsewhere in the same native +/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html) +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct FuncRef(u32); +entity_impl!(FuncRef, "fn"); + +impl FuncRef { + /// Create a new external function reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UserExternalNameRef(u32); +entity_impl!(UserExternalNameRef, "userextname"); + +/// An opaque reference to a function [`Signature`](super::Signature). +/// +/// `SigRef`s are used to declare a function with +/// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function) +/// as well as to make an [indirect function call](super::InstBuilder::call_indirect). +/// +/// `SigRef`s can be created with +/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature). +/// +/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with +/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or +/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures). +/// +/// While the order is stable, it is arbitrary. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct SigRef(u32); +entity_impl!(SigRef, "sig"); + +impl SigRef { + /// Create a new function signature reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + +/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum AnyEntity { + /// The whole function. + Function, + /// a basic block. + Block(Block), + /// An instruction. + Inst(Inst), + /// An SSA value. + Value(Value), + /// A stack slot. + StackSlot(StackSlot), + /// A dynamic stack slot. + DynamicStackSlot(DynamicStackSlot), + /// A dynamic type + DynamicType(DynamicType), + /// A Global value. + GlobalValue(GlobalValue), + /// A memory type. + MemoryType(MemoryType), + /// A jump table. + JumpTable(JumpTable), + /// A constant. + Constant(Constant), + /// An external function. + FuncRef(FuncRef), + /// A function call signature. + SigRef(SigRef), + /// A function's stack limit + StackLimit, +} + +impl fmt::Display for AnyEntity { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Function => write!(f, "function"), + Self::Block(r) => r.fmt(f), + Self::Inst(r) => r.fmt(f), + Self::Value(r) => r.fmt(f), + Self::StackSlot(r) => r.fmt(f), + Self::DynamicStackSlot(r) => r.fmt(f), + Self::DynamicType(r) => r.fmt(f), + Self::GlobalValue(r) => r.fmt(f), + Self::MemoryType(r) => r.fmt(f), + Self::JumpTable(r) => r.fmt(f), + Self::Constant(r) => r.fmt(f), + Self::FuncRef(r) => r.fmt(f), + Self::SigRef(r) => r.fmt(f), + Self::StackLimit => write!(f, "stack_limit"), + } + } +} + +impl fmt::Debug for AnyEntity { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (self as &dyn fmt::Display).fmt(f) + } +} + +impl From for AnyEntity { + fn from(r: Block) -> Self { + Self::Block(r) + } +} + +impl From for AnyEntity { + fn from(r: Inst) -> Self { + Self::Inst(r) + } +} + +impl From for AnyEntity { + fn from(r: Value) -> Self { + Self::Value(r) + } +} + +impl From for AnyEntity { + fn from(r: StackSlot) -> Self { + Self::StackSlot(r) + } +} + +impl From for AnyEntity { + fn from(r: DynamicStackSlot) -> Self { + Self::DynamicStackSlot(r) + } +} + +impl From for AnyEntity { + fn from(r: DynamicType) -> Self { + Self::DynamicType(r) + } +} + +impl From for AnyEntity { + fn from(r: GlobalValue) -> Self { + Self::GlobalValue(r) + } +} + +impl From for AnyEntity { + fn from(r: MemoryType) -> Self { + Self::MemoryType(r) + } +} + +impl From for AnyEntity { + fn from(r: JumpTable) -> Self { + Self::JumpTable(r) + } +} + +impl From for AnyEntity { + fn from(r: Constant) -> Self { + Self::Constant(r) + } +} + +impl From for AnyEntity { + fn from(r: FuncRef) -> Self { + Self::FuncRef(r) + } +} + +impl From for AnyEntity { + fn from(r: SigRef) -> Self { + Self::SigRef(r) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn value_with_number() { + assert_eq!(Value::with_number(0).unwrap().to_string(), "v0"); + assert_eq!(Value::with_number(1).unwrap().to_string(), "v1"); + + assert_eq!(Value::with_number(u32::MAX / 2), None); + assert!(Value::with_number(u32::MAX / 2 - 1).is_some()); + } + + #[test] + fn memory() { + use crate::packed_option::PackedOption; + use core::mem; + // This is the whole point of `PackedOption`. + assert_eq!( + mem::size_of::(), + mem::size_of::>() + ); + } + + #[test] + fn memory_option() { + use core::mem; + // PackedOption is used because Option is twice as large + // as EntityRef. If this ever fails to be the case, this test will fail. + assert_eq!(mem::size_of::() * 2, mem::size_of::>()); + } + + #[test] + fn constant_with_number() { + assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0"); + assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/extfunc.rs b/deps/crates/vendor/cranelift-codegen/src/ir/extfunc.rs new file mode 100644 index 00000000000000..319ec4038243f4 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/extfunc.rs @@ -0,0 +1,408 @@ +//! External function calls. +//! +//! To a Cranelift function, all functions are "external". Directly called functions must be +//! declared in the preamble, and all function calls must have a signature. +//! +//! This module declares the data types used to represent external functions and call signatures. + +use crate::ir::{ExternalName, SigRef, Type}; +use crate::isa::CallConv; +use alloc::vec::Vec; +use core::fmt; +use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +use super::function::FunctionParameters; + +/// Function signature. +/// +/// The function signature describes the types of formal parameters and return values along with +/// other details that are needed to call a function correctly. +/// +/// A signature can optionally include ISA-specific ABI information which specifies exactly how +/// arguments and return values are passed. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Signature { + /// The arguments passed to the function. + pub params: Vec, + /// Values returned from the function. + pub returns: Vec, + + /// Calling convention. + pub call_conv: CallConv, +} + +impl Signature { + /// Create a new blank signature. + pub fn new(call_conv: CallConv) -> Self { + Self { + params: Vec::new(), + returns: Vec::new(), + call_conv, + } + } + + /// Clear the signature so it is identical to a fresh one returned by `new()`. + pub fn clear(&mut self, call_conv: CallConv) { + self.params.clear(); + self.returns.clear(); + self.call_conv = call_conv; + } + + /// Find the index of a presumed unique special-purpose parameter. + pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option { + self.params.iter().rposition(|arg| arg.purpose == purpose) + } + + /// Find the index of a presumed unique special-purpose parameter. + pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option { + self.returns.iter().rposition(|arg| arg.purpose == purpose) + } + + /// Does this signature have a parameter whose `ArgumentPurpose` is + /// `purpose`? + pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool { + self.special_param_index(purpose).is_some() + } + + /// Does this signature have a return whose `ArgumentPurpose` is `purpose`? + pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool { + self.special_return_index(purpose).is_some() + } + + /// How many special parameters does this function have? + pub fn num_special_params(&self) -> usize { + self.params + .iter() + .filter(|p| p.purpose != ArgumentPurpose::Normal) + .count() + } + + /// How many special returns does this function have? + pub fn num_special_returns(&self) -> usize { + self.returns + .iter() + .filter(|r| r.purpose != ArgumentPurpose::Normal) + .count() + } + + /// Does this signature take an struct return pointer parameter? + pub fn uses_struct_return_param(&self) -> bool { + self.uses_special_param(ArgumentPurpose::StructReturn) + } + + /// Does this return more than one normal value? (Pre-struct return + /// legalization) + pub fn is_multi_return(&self) -> bool { + self.returns + .iter() + .filter(|r| r.purpose == ArgumentPurpose::Normal) + .count() + > 1 + } +} + +fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result { + match args.split_first() { + None => {} + Some((first, rest)) => { + write!(f, "{first}")?; + for arg in rest { + write!(f, ", {arg}")?; + } + } + } + Ok(()) +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(")?; + write_list(f, &self.params)?; + write!(f, ")")?; + if !self.returns.is_empty() { + write!(f, " -> ")?; + write_list(f, &self.returns)?; + } + write!(f, " {}", self.call_conv) + } +} + +/// Function parameter or return value descriptor. +/// +/// This describes the value type being passed to or from a function along with flags that affect +/// how the argument is passed. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct AbiParam { + /// Type of the argument value. + pub value_type: Type, + /// Special purpose of argument, or `Normal`. + pub purpose: ArgumentPurpose, + /// Method for extending argument to a full register. + pub extension: ArgumentExtension, +} + +impl AbiParam { + /// Create a parameter with default flags. + pub fn new(vt: Type) -> Self { + Self { + value_type: vt, + extension: ArgumentExtension::None, + purpose: ArgumentPurpose::Normal, + } + } + + /// Create a special-purpose parameter that is not (yet) bound to a specific register. + pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self { + Self { + value_type: vt, + extension: ArgumentExtension::None, + purpose, + } + } + + /// Convert `self` to a parameter with the `uext` flag set. + pub fn uext(self) -> Self { + debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type); + Self { + extension: ArgumentExtension::Uext, + ..self + } + } + + /// Convert `self` to a parameter type with the `sext` flag set. + pub fn sext(self) -> Self { + debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type); + Self { + extension: ArgumentExtension::Sext, + ..self + } + } +} + +impl fmt::Display for AbiParam { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.value_type)?; + match self.extension { + ArgumentExtension::None => {} + ArgumentExtension::Uext => write!(f, " uext")?, + ArgumentExtension::Sext => write!(f, " sext")?, + } + if self.purpose != ArgumentPurpose::Normal { + write!(f, " {}", self.purpose)?; + } + Ok(()) + } +} + +/// Function argument extension options. +/// +/// On some architectures, small integer function arguments and/or return values are extended to +/// the width of a general-purpose register. +/// +/// This attribute specifies how an argument or return value should be extended *if the platform +/// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the +/// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes +/// specify *how* to extend (according to the signedness of the original program) rather than +/// *whether* to extend. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum ArgumentExtension { + /// No extension, high bits are indeterminate. + None, + /// Unsigned extension: high bits in register are 0. + Uext, + /// Signed extension: high bits in register replicate sign bit. + Sext, +} + +/// The special purpose of a function argument. +/// +/// Function arguments and return values are used to pass user program values between functions, +/// but they are also used to represent special registers with significance to the ABI such as +/// frame pointers and callee-saved registers. +/// +/// The argument purpose is used to indicate any special meaning of an argument or return value. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum ArgumentPurpose { + /// A normal user program value passed to or from a function. + Normal, + + /// A C struct passed as argument. + /// + /// Note that this should only be used when interacting with code following + /// a C ABI which is expecting a struct passed *by value*. + StructArgument( + /// The size, in bytes, of the struct. + u32, + ), + + /// Struct return pointer. + /// + /// When a function needs to return more data than will fit in registers, the caller passes a + /// pointer to a memory location where the return value can be written. In some ABIs, this + /// struct return pointer is passed in a specific register. + /// + /// This argument kind can also appear as a return value for ABIs that require a function with + /// a `StructReturn` pointer argument to also return that pointer in a register. + StructReturn, + + /// A VM context pointer. + /// + /// This is a pointer to a context struct containing details about the current sandbox. It is + /// used as a base pointer for `vmctx` global values. + VMContext, +} + +impl fmt::Display for ArgumentPurpose { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Self::Normal => "normal", + Self::StructArgument(size) => return write!(f, "sarg({size})"), + Self::StructReturn => "sret", + Self::VMContext => "vmctx", + }) + } +} + +impl FromStr for ArgumentPurpose { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "normal" => Ok(Self::Normal), + "sret" => Ok(Self::StructReturn), + "vmctx" => Ok(Self::VMContext), + _ if s.starts_with("sarg(") => { + if !s.ends_with(")") { + return Err(()); + } + // Parse 'sarg(size)' + let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?; + Ok(Self::StructArgument(size)) + } + _ => Err(()), + } + } +} + +/// An external function. +/// +/// Information about a function that can be called directly with a direct `call` instruction. +#[derive(Clone, Debug, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ExtFuncData { + /// Name of the external function. + pub name: ExternalName, + /// Call signature of function. + pub signature: SigRef, + /// Will this function be defined nearby, such that it will always be a certain distance away, + /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that + /// symbols meant to be preemptible cannot be considered colocated. + /// + /// If `true`, some backends may use relocation forms that have limited range. The exact + /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift + /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how + /// far away the target will be, it is best not to set the `colocated` flag; in general, this + /// flag is best used when the target is known to be in the same unit of code generation, such + /// as a Wasm module. + /// + /// See the documentation for `RelocDistance` for more details. A `colocated` flag value of + /// `true` implies `RelocDistance::Near`. + pub colocated: bool, +} + +impl ExtFuncData { + /// Returns a displayable version of the `ExtFuncData`, with or without extra context to + /// prettify the output. + pub fn display<'a>( + &'a self, + params: Option<&'a FunctionParameters>, + ) -> DisplayableExtFuncData<'a> { + DisplayableExtFuncData { + ext_func: self, + params, + } + } +} + +/// A displayable `ExtFuncData`, with extra context to prettify the output. +pub struct DisplayableExtFuncData<'a> { + ext_func: &'a ExtFuncData, + params: Option<&'a FunctionParameters>, +} + +impl<'a> fmt::Display for DisplayableExtFuncData<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.ext_func.colocated { + write!(f, "colocated ")?; + } + write!( + f, + "{} {}", + self.ext_func.name.display(self.params), + self.ext_func.signature + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::types::{F32, I32, I8}; + use alloc::string::ToString; + + #[test] + fn argument_type() { + let t = AbiParam::new(I32); + assert_eq!(t.to_string(), "i32"); + let mut t = t.uext(); + assert_eq!(t.to_string(), "i32 uext"); + assert_eq!(t.sext().to_string(), "i32 sext"); + t.purpose = ArgumentPurpose::StructReturn; + assert_eq!(t.to_string(), "i32 uext sret"); + } + + #[test] + fn argument_purpose() { + let all_purpose = [ + (ArgumentPurpose::Normal, "normal"), + (ArgumentPurpose::StructReturn, "sret"), + (ArgumentPurpose::VMContext, "vmctx"), + (ArgumentPurpose::StructArgument(42), "sarg(42)"), + ]; + for &(e, n) in &all_purpose { + assert_eq!(e.to_string(), n); + assert_eq!(Ok(e), n.parse()); + } + } + + #[test] + fn call_conv() { + for &cc in &[ + CallConv::Fast, + CallConv::Cold, + CallConv::SystemV, + CallConv::WindowsFastcall, + ] { + assert_eq!(Ok(cc), cc.to_string().parse()) + } + } + + #[test] + fn signatures() { + let mut sig = Signature::new(CallConv::WindowsFastcall); + assert_eq!(sig.to_string(), "() windows_fastcall"); + sig.params.push(AbiParam::new(I32)); + assert_eq!(sig.to_string(), "(i32) windows_fastcall"); + sig.returns.push(AbiParam::new(F32)); + assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall"); + sig.params.push(AbiParam::new(I32.by(4).unwrap())); + assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall"); + sig.returns.push(AbiParam::new(I8)); + assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, i8 windows_fastcall"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/extname.rs b/deps/crates/vendor/cranelift-codegen/src/ir/extname.rs new file mode 100644 index 00000000000000..8484376b5a8794 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/extname.rs @@ -0,0 +1,333 @@ +//! External names. +//! +//! These are identifiers for declaring entities defined outside the current +//! function. The name of an external declaration doesn't have any meaning to +//! Cranelift, which compiles functions independently. + +use crate::ir::{KnownSymbol, LibCall}; +use alloc::boxed::Box; +use core::fmt::{self, Write}; +use core::str::FromStr; + +use cranelift_entity::EntityRef as _; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +use super::entities::UserExternalNameRef; +use super::function::FunctionParameters; + +/// An explicit name for a user-defined function, be it defined in code or in CLIF text. +/// +/// This is used both for naming a function (for debugging purposes) and for declaring external +/// functions. In the latter case, this becomes an `ExternalName`, which gets embedded in +/// relocations later, etc. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum UserFuncName { + /// A user-defined name, with semantics left to the user. + User(UserExternalName), + /// A name for a test case, mostly intended for Cranelift testing. + Testcase(TestcaseName), +} + +impl UserFuncName { + /// Creates a new external name from a sequence of bytes. Caller is expected + /// to guarantee bytes are only ascii alphanumeric or `_`. + pub fn testcase>(v: T) -> Self { + Self::Testcase(TestcaseName::new(v)) + } + + /// Create a new external name from a user-defined external function reference. + pub fn user(namespace: u32, index: u32) -> Self { + Self::User(UserExternalName::new(namespace, index)) + } + + /// Get a `UserExternalName` if this is a user-defined name. + pub fn get_user(&self) -> Option<&UserExternalName> { + match self { + UserFuncName::User(user) => Some(user), + UserFuncName::Testcase(_) => None, + } + } +} + +impl Default for UserFuncName { + fn default() -> Self { + UserFuncName::User(UserExternalName::default()) + } +} + +impl fmt::Display for UserFuncName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UserFuncName::User(user) => user.fmt(f), + UserFuncName::Testcase(testcase) => testcase.fmt(f), + } + } +} + +/// An external name in a user-defined symbol table. +/// +/// Cranelift does not interpret these numbers in any way, so they can represent arbitrary values. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UserExternalName { + /// Arbitrary. + pub namespace: u32, + /// Arbitrary. + pub index: u32, +} + +impl UserExternalName { + /// Creates a new [UserExternalName]. + pub fn new(namespace: u32, index: u32) -> Self { + Self { namespace, index } + } +} + +impl fmt::Display for UserExternalName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "u{}:{}", self.namespace, self.index) + } +} + +/// A name for a test case. +#[derive(Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct TestcaseName(Box<[u8]>); + +impl fmt::Display for TestcaseName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_char('%')?; + f.write_str(std::str::from_utf8(&self.0).unwrap()) + } +} + +impl fmt::Debug for TestcaseName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl TestcaseName { + pub(crate) fn new>(v: T) -> Self { + Self(v.as_ref().into()) + } +} + +/// The name of an external is either a reference to a user-defined symbol +/// table, or a short sequence of ascii bytes so that test cases do not have +/// to keep track of a symbol table. +/// +/// External names are primarily used as keys by code using Cranelift to map +/// from a `cranelift_codegen::ir::FuncRef` or similar to additional associated +/// data. +/// +/// External names can also serve as a primitive testing and debugging tool. +/// In particular, many `.clif` test files use function names to identify +/// functions. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum ExternalName { + /// A reference to a name in a user-defined symbol table. + User(UserExternalNameRef), + /// A test case function name of up to a hardcoded amount of ascii + /// characters. This is not intended to be used outside test cases. + TestCase(TestcaseName), + /// A well-known runtime library function. + LibCall(LibCall), + /// A well-known symbol. + KnownSymbol(KnownSymbol), +} + +impl Default for ExternalName { + fn default() -> Self { + Self::User(UserExternalNameRef::new(0)) + } +} + +impl ExternalName { + /// Creates a new external name from a sequence of bytes. Caller is expected + /// to guarantee bytes are only ascii alphanumeric or `_`. + /// + /// # Examples + /// + /// ```rust + /// # use cranelift_codegen::ir::ExternalName; + /// // Create `ExternalName` from a string. + /// let name = ExternalName::testcase("hello"); + /// assert_eq!(name.display(None).to_string(), "%hello"); + /// ``` + pub fn testcase>(v: T) -> Self { + Self::TestCase(TestcaseName::new(v)) + } + + /// Create a new external name from a user-defined external function reference. + /// + /// # Examples + /// ```rust + /// # use cranelift_codegen::ir::{ExternalName, UserExternalNameRef}; + /// let user_func_ref: UserExternalNameRef = Default::default(); // usually obtained with `Function::declare_imported_user_function()` + /// let name = ExternalName::user(user_func_ref); + /// assert_eq!(name.display(None).to_string(), "userextname0"); + /// ``` + pub fn user(func_ref: UserExternalNameRef) -> Self { + Self::User(func_ref) + } + + /// Returns a display for the current `ExternalName`, with extra context to prettify the + /// output. + pub fn display<'a>( + &'a self, + params: Option<&'a FunctionParameters>, + ) -> DisplayableExternalName<'a> { + DisplayableExternalName { name: self, params } + } +} + +/// An `ExternalName` that has enough context to be displayed. +pub struct DisplayableExternalName<'a> { + name: &'a ExternalName, + params: Option<&'a FunctionParameters>, +} + +impl<'a> fmt::Display for DisplayableExternalName<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.name { + ExternalName::User(func_ref) => { + if let Some(params) = self.params { + let name = ¶ms.user_named_funcs()[*func_ref]; + write!(f, "u{}:{}", name.namespace, name.index) + } else { + // Best effort. + write!(f, "{}", *func_ref) + } + } + ExternalName::TestCase(testcase) => testcase.fmt(f), + ExternalName::LibCall(lc) => write!(f, "%{lc}"), + ExternalName::KnownSymbol(ks) => write!(f, "%{ks}"), + } + } +} + +impl FromStr for ExternalName { + type Err = (); + + fn from_str(s: &str) -> Result { + // Try to parse as a known symbol + if let Ok(ks) = s.parse() { + return Ok(Self::KnownSymbol(ks)); + } + + // Try to parse as a libcall name + if let Ok(lc) = s.parse() { + return Ok(Self::LibCall(lc)); + } + + // Otherwise its a test case name + Ok(Self::testcase(s.as_bytes())) + } +} + +#[cfg(test)] +mod tests { + use super::ExternalName; + use crate::ir::{ + entities::UserExternalNameRef, function::FunctionParameters, LibCall, UserExternalName, + }; + use alloc::string::ToString; + use core::u32; + use cranelift_entity::EntityRef as _; + + #[cfg(target_pointer_width = "64")] + #[test] + fn externalname_size() { + assert_eq!(core::mem::size_of::(), 24); + } + + #[test] + fn display_testcase() { + assert_eq!(ExternalName::testcase("").display(None).to_string(), "%"); + assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x"); + assert_eq!( + ExternalName::testcase("x_1").display(None).to_string(), + "%x_1" + ); + assert_eq!( + ExternalName::testcase("longname12345678") + .display(None) + .to_string(), + "%longname12345678" + ); + assert_eq!( + ExternalName::testcase("longname123456789") + .display(None) + .to_string(), + "%longname123456789" + ); + } + + #[test] + fn display_user() { + assert_eq!( + ExternalName::user(UserExternalNameRef::new(0)) + .display(None) + .to_string(), + "userextname0" + ); + assert_eq!( + ExternalName::user(UserExternalNameRef::new(1)) + .display(None) + .to_string(), + "userextname1" + ); + assert_eq!( + ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _)) + .display(None) + .to_string(), + "userextname4294967294" + ); + + let mut func_params = FunctionParameters::new(); + + // ref 0 + func_params.ensure_user_func_name(UserExternalName { + namespace: 13, + index: 37, + }); + + // ref 1 + func_params.ensure_user_func_name(UserExternalName { + namespace: 2, + index: 4, + }); + + assert_eq!( + ExternalName::user(UserExternalNameRef::new(0)) + .display(Some(&func_params)) + .to_string(), + "u13:37" + ); + + assert_eq!( + ExternalName::user(UserExternalNameRef::new(1)) + .display(Some(&func_params)) + .to_string(), + "u2:4" + ); + } + + #[test] + fn parsing() { + assert_eq!( + "FloorF32".parse(), + Ok(ExternalName::LibCall(LibCall::FloorF32)) + ); + assert_eq!( + ExternalName::LibCall(LibCall::FloorF32) + .display(None) + .to_string(), + "%FloorF32" + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/function.rs b/deps/crates/vendor/cranelift-codegen/src/ir/function.rs new file mode 100644 index 00000000000000..ebf7f08cb85c14 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/function.rs @@ -0,0 +1,495 @@ +//! Intermediate representation of a function. +//! +//! The `Function` struct defined in this module owns all of its basic blocks and +//! instructions. + +use crate::entity::{PrimaryMap, SecondaryMap}; +use crate::ir::{ + self, pcc::Fact, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, + DynamicStackSlots, DynamicType, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, + JumpTable, JumpTableData, Layout, MemoryType, MemoryTypeData, SigRef, Signature, SourceLocs, + StackSlot, StackSlotData, StackSlots, Type, +}; +use crate::isa::CallConv; +use crate::write::write_function; +use crate::HashMap; +#[cfg(feature = "enable-serde")] +use alloc::string::String; +use core::fmt; + +#[cfg(feature = "enable-serde")] +use serde::de::{Deserializer, Error}; +#[cfg(feature = "enable-serde")] +use serde::ser::Serializer; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +use super::entities::UserExternalNameRef; +use super::extname::UserFuncName; +use super::{RelSourceLoc, SourceLoc, UserExternalName}; + +/// A version marker used to ensure that serialized clif ir is never deserialized with a +/// different version of Cranelift. +#[derive(Default, Copy, Clone, Debug, PartialEq, Hash)] +pub struct VersionMarker; + +#[cfg(feature = "enable-serde")] +impl Serialize for VersionMarker { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + crate::VERSION.serialize(serializer) + } +} + +#[cfg(feature = "enable-serde")] +impl<'de> Deserialize<'de> for VersionMarker { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let version = String::deserialize(deserializer)?; + if version != crate::VERSION { + return Err(D::Error::custom(&format!( + "Expected a clif ir function for version {}, found one for version {}", + crate::VERSION, + version, + ))); + } + Ok(VersionMarker) + } +} + +/// Function parameters used when creating this function, and that will become applied after +/// compilation to materialize the final `CompiledCode`. +#[derive(Clone, PartialEq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct FunctionParameters { + /// The first `SourceLoc` appearing in the function, serving as a base for every relative + /// source loc in the function. + base_srcloc: Option, + + /// External user-defined function references. + user_named_funcs: PrimaryMap, + + /// Inverted mapping of `user_named_funcs`, to deduplicate internally. + user_ext_name_to_ref: HashMap, +} + +impl FunctionParameters { + /// Creates a new `FunctionParameters` with the given name. + pub fn new() -> Self { + Self { + base_srcloc: None, + user_named_funcs: Default::default(), + user_ext_name_to_ref: Default::default(), + } + } + + /// Returns the base `SourceLoc`. + /// + /// If it was never explicitly set with `ensure_base_srcloc`, will return an invalid + /// `SourceLoc`. + pub fn base_srcloc(&self) -> SourceLoc { + self.base_srcloc.unwrap_or_default() + } + + /// Sets the base `SourceLoc`, if not set yet, and returns the base value. + pub fn ensure_base_srcloc(&mut self, srcloc: SourceLoc) -> SourceLoc { + match self.base_srcloc { + Some(val) => val, + None => { + self.base_srcloc = Some(srcloc); + srcloc + } + } + } + + /// Retrieve a `UserExternalNameRef` for the given name, or add a new one. + /// + /// This method internally deduplicates same `UserExternalName` so they map to the same + /// reference. + pub fn ensure_user_func_name(&mut self, name: UserExternalName) -> UserExternalNameRef { + if let Some(reff) = self.user_ext_name_to_ref.get(&name) { + *reff + } else { + let reff = self.user_named_funcs.push(name.clone()); + self.user_ext_name_to_ref.insert(name, reff); + reff + } + } + + /// Resets an already existing user function name to a new value. + pub fn reset_user_func_name(&mut self, index: UserExternalNameRef, name: UserExternalName) { + if let Some(prev_name) = self.user_named_funcs.get_mut(index) { + self.user_ext_name_to_ref.remove(prev_name); + *prev_name = name.clone(); + self.user_ext_name_to_ref.insert(name, index); + } + } + + /// Returns the internal mapping of `UserExternalNameRef` to `UserExternalName`. + pub fn user_named_funcs(&self) -> &PrimaryMap { + &self.user_named_funcs + } + + fn clear(&mut self) { + self.base_srcloc = None; + self.user_named_funcs.clear(); + self.user_ext_name_to_ref.clear(); + } +} + +/// Function fields needed when compiling a function. +/// +/// Additionally, these fields can be the same for two functions that would be compiled the same +/// way, and finalized by applying `FunctionParameters` onto their `CompiledCodeStencil`. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct FunctionStencil { + /// A version marker used to ensure that serialized clif ir is never deserialized with a + /// different version of Cranelift. + // Note: This must be the first field to ensure that Serde will deserialize it before + // attempting to deserialize other fields that are potentially changed between versions. + pub version_marker: VersionMarker, + + /// Signature of this function. + pub signature: Signature, + + /// Sized stack slots allocated in this function. + pub sized_stack_slots: StackSlots, + + /// Dynamic stack slots allocated in this function. + pub dynamic_stack_slots: DynamicStackSlots, + + /// Global values referenced. + pub global_values: PrimaryMap, + + /// Global value proof-carrying-code facts. + pub global_value_facts: SecondaryMap>, + + /// Memory types for proof-carrying code. + pub memory_types: PrimaryMap, + + /// Data flow graph containing the primary definition of all instructions, blocks and values. + pub dfg: DataFlowGraph, + + /// Layout of blocks and instructions in the function body. + pub layout: Layout, + + /// Source locations. + /// + /// Track the original source location for each instruction. The source locations are not + /// interpreted by Cranelift, only preserved. + pub srclocs: SourceLocs, + + /// An optional global value which represents an expression evaluating to + /// the stack limit for this function. This `GlobalValue` will be + /// interpreted in the prologue, if necessary, to insert a stack check to + /// ensure that a trap happens if the stack pointer goes below the + /// threshold specified here. + pub stack_limit: Option, +} + +impl FunctionStencil { + fn clear(&mut self) { + self.signature.clear(CallConv::Fast); + self.sized_stack_slots.clear(); + self.dynamic_stack_slots.clear(); + self.global_values.clear(); + self.global_value_facts.clear(); + self.memory_types.clear(); + self.dfg.clear(); + self.layout.clear(); + self.srclocs.clear(); + self.stack_limit = None; + } + + /// Creates a jump table in the function, to be used by `br_table` instructions. + pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { + self.dfg.jump_tables.push(data) + } + + /// Creates a sized stack slot in the function, to be used by `stack_load`, `stack_store` + /// and `stack_addr` instructions. + pub fn create_sized_stack_slot(&mut self, data: StackSlotData) -> StackSlot { + self.sized_stack_slots.push(data) + } + + /// Creates a dynamic stack slot in the function, to be used by `dynamic_stack_load`, + /// `dynamic_stack_store` and `dynamic_stack_addr` instructions. + pub fn create_dynamic_stack_slot(&mut self, data: DynamicStackSlotData) -> DynamicStackSlot { + self.dynamic_stack_slots.push(data) + } + + /// Adds a signature which can later be used to declare an external function import. + pub fn import_signature(&mut self, signature: Signature) -> SigRef { + self.dfg.signatures.push(signature) + } + + /// Declares a global value accessible to the function. + pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { + self.global_values.push(data) + } + + /// Declares a memory type for use by the function. + pub fn create_memory_type(&mut self, data: MemoryTypeData) -> MemoryType { + self.memory_types.push(data) + } + + /// Find the global dyn_scale value associated with given DynamicType. + pub fn get_dyn_scale(&self, ty: DynamicType) -> GlobalValue { + self.dfg.dynamic_types.get(ty).unwrap().dynamic_scale + } + + /// Find the global dyn_scale for the given stack slot. + pub fn get_dynamic_slot_scale(&self, dss: DynamicStackSlot) -> GlobalValue { + let dyn_ty = self.dynamic_stack_slots.get(dss).unwrap().dyn_ty; + self.get_dyn_scale(dyn_ty) + } + + /// Get a concrete `Type` from a user defined `DynamicType`. + pub fn get_concrete_dynamic_ty(&self, ty: DynamicType) -> Option { + self.dfg + .dynamic_types + .get(ty) + .unwrap_or_else(|| panic!("Undeclared dynamic vector type: {ty}")) + .concrete() + } + + /// Find a presumed unique special-purpose function parameter value. + /// + /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists. + pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option { + let entry = self.layout.entry_block().expect("Function is empty"); + self.signature + .special_param_index(purpose) + .map(|i| self.dfg.block_params(entry)[i]) + } + + /// Starts collection of debug information. + pub fn collect_debug_info(&mut self) { + self.dfg.collect_debug_info(); + } + + /// Rewrite the branch destination to `new_dest` if the destination matches `old_dest`. + /// Does nothing if called with a non-jump or non-branch instruction. + pub fn rewrite_branch_destination(&mut self, inst: Inst, old_dest: Block, new_dest: Block) { + for dest in self.dfg.insts[inst].branch_destination_mut(&mut self.dfg.jump_tables) { + if dest.block(&self.dfg.value_lists) == old_dest { + dest.set_block(new_dest, &mut self.dfg.value_lists) + } + } + } + + /// Checks that the specified block can be encoded as a basic block. + /// + /// On error, returns the first invalid instruction and an error message. + pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { + let dfg = &self.dfg; + let inst_iter = self.layout.block_insts(block); + + // Ignore all instructions prior to the first branch. + let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); + + if let Some(_branch) = inst_iter.next() { + if let Some(next) = inst_iter.next() { + return Err((next, "post-terminator instruction")); + } + } + + Ok(()) + } + + /// Returns an iterator over the blocks succeeding the given block. + pub fn block_successors(&self, block: Block) -> impl DoubleEndedIterator + '_ { + self.layout.last_inst(block).into_iter().flat_map(|inst| { + self.dfg.insts[inst] + .branch_destination(&self.dfg.jump_tables) + .iter() + .map(|block| block.block(&self.dfg.value_lists)) + }) + } + + /// Returns true if the function is function that doesn't call any other functions. This is not + /// to be confused with a "leaf function" in Windows terminology. + pub fn is_leaf(&self) -> bool { + // Conservative result: if there's at least one function signature referenced in this + // function, assume it is not a leaf. + let has_signatures = !self.dfg.signatures.is_empty(); + + // Under some TLS models, retrieving the address of a TLS variable requires calling a + // function. Conservatively assume that any function that references a tls global value + // is not a leaf. + let has_tls = self.global_values.values().any(|gv| match gv { + GlobalValueData::Symbol { tls, .. } => *tls, + _ => false, + }); + + !has_signatures && !has_tls + } + + /// Replace the `dst` instruction's data with the `src` instruction's data + /// and then remove `src`. + /// + /// `src` and its result values should not be used at all, as any uses would + /// be left dangling after calling this method. + /// + /// `src` and `dst` must have the same number of resulting values, and + /// `src`'s i^th value must have the same type as `dst`'s i^th value. + pub fn transplant_inst(&mut self, dst: Inst, src: Inst) { + debug_assert_eq!( + self.dfg.inst_results(dst).len(), + self.dfg.inst_results(src).len() + ); + debug_assert!(self + .dfg + .inst_results(dst) + .iter() + .zip(self.dfg.inst_results(src)) + .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b))); + + self.dfg.insts[dst] = self.dfg.insts[src]; + self.layout.remove_inst(src); + } + + /// Size occupied by all stack slots associated with this function. + /// + /// Does not include any padding necessary due to offsets + pub fn fixed_stack_size(&self) -> u32 { + self.sized_stack_slots.values().map(|ss| ss.size).sum() + } + + /// Returns the list of relative source locations for this function. + pub(crate) fn rel_srclocs(&self) -> &SecondaryMap { + &self.srclocs + } +} + +/// Functions can be cloned, but it is not a very fast operation. +/// The clone will have all the same entity numbers as the original. +#[derive(Clone, PartialEq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Function { + /// Name of this function. + /// + /// Mostly used by `.clif` files, only there for debugging / naming purposes. + pub name: UserFuncName, + + /// All the fields required for compiling a function, independently of details irrelevant to + /// compilation and that are stored in the `FunctionParameters` `params` field instead. + pub stencil: FunctionStencil, + + /// All the parameters that can be applied onto the function stencil, that is, that don't + /// matter when caching compilation artifacts. + pub params: FunctionParameters, +} + +impl core::ops::Deref for Function { + type Target = FunctionStencil; + + fn deref(&self) -> &Self::Target { + &self.stencil + } +} + +impl core::ops::DerefMut for Function { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.stencil + } +} + +impl Function { + /// Create a function with the given name and signature. + pub fn with_name_signature(name: UserFuncName, sig: Signature) -> Self { + Self { + name, + stencil: FunctionStencil { + version_marker: VersionMarker, + signature: sig, + sized_stack_slots: StackSlots::new(), + dynamic_stack_slots: DynamicStackSlots::new(), + global_values: PrimaryMap::new(), + global_value_facts: SecondaryMap::new(), + memory_types: PrimaryMap::new(), + dfg: DataFlowGraph::new(), + layout: Layout::new(), + srclocs: SecondaryMap::new(), + stack_limit: None, + }, + params: FunctionParameters::new(), + } + } + + /// Clear all data structures in this function. + pub fn clear(&mut self) { + self.stencil.clear(); + self.params.clear(); + self.name = UserFuncName::default(); + } + + /// Create a new empty, anonymous function with a Fast calling convention. + pub fn new() -> Self { + Self::with_name_signature(Default::default(), Signature::new(CallConv::Fast)) + } + + /// Return an object that can display this function with correct ISA-specific annotations. + pub fn display(&self) -> DisplayFunction<'_> { + DisplayFunction(self) + } + + /// Sets an absolute source location for the given instruction. + /// + /// If no base source location has been set yet, records it at the same time. + pub fn set_srcloc(&mut self, inst: Inst, srcloc: SourceLoc) { + let base = self.params.ensure_base_srcloc(srcloc); + self.stencil.srclocs[inst] = RelSourceLoc::from_base_offset(base, srcloc); + } + + /// Returns an absolute source location for the given instruction. + pub fn srcloc(&self, inst: Inst) -> SourceLoc { + let base = self.params.base_srcloc(); + self.stencil.srclocs[inst].expand(base) + } + + /// Declare a user-defined external function import, to be referenced in `ExtFuncData::User` later. + pub fn declare_imported_user_function( + &mut self, + name: UserExternalName, + ) -> UserExternalNameRef { + self.params.ensure_user_func_name(name) + } + + /// Declare an external function import. + pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { + self.stencil.dfg.ext_funcs.push(data) + } +} + +/// Wrapper type capable of displaying a `Function`. +pub struct DisplayFunction<'a>(&'a Function); + +impl<'a> fmt::Display for DisplayFunction<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write_function(fmt, self.0) + } +} + +impl fmt::Display for Function { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write_function(fmt, self) + } +} + +impl fmt::Debug for Function { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write_function(fmt, self) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/globalvalue.rs b/deps/crates/vendor/cranelift-codegen/src/ir/globalvalue.rs new file mode 100644 index 00000000000000..89120c8b8364fa --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/globalvalue.rs @@ -0,0 +1,147 @@ +//! Global values. + +use crate::ir::immediates::{Imm64, Offset32}; +use crate::ir::{ExternalName, GlobalValue, MemFlags, Type}; +use crate::isa::TargetIsa; +use core::fmt; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Information about a global value declaration. +#[derive(Debug, Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum GlobalValueData { + /// Value is the address of the VM context struct. + VMContext, + + /// Value is pointed to by another global value. + /// + /// The `base` global value is assumed to contain a pointer. This global value is computed + /// by loading from memory at that pointer value. The memory must be accessible, and + /// naturally aligned to hold a value of the type. The data at this address is assumed + /// to never change while the current function is executing. + Load { + /// The base pointer global value. + base: GlobalValue, + + /// Offset added to the base pointer before doing the load. + offset: Offset32, + + /// Type of the loaded value. + global_type: Type, + + /// Specifies the memory flags to be used by the load. Guaranteed to be notrap and aligned. + flags: MemFlags, + }, + + /// Value is an offset from another global value. + IAddImm { + /// The base pointer global value. + base: GlobalValue, + + /// Byte offset to be added to the value. + offset: Imm64, + + /// Type of the iadd. + global_type: Type, + }, + + /// Value is symbolic, meaning it's a name which will be resolved to an + /// actual value later (eg. by linking). Cranelift itself does not interpret + /// this name; it's used by embedders to link with other data structures. + /// + /// For now, symbolic values always have pointer type, and represent + /// addresses, however in the future they could be used to represent other + /// things as well. + Symbol { + /// The symbolic name. + name: ExternalName, + + /// Offset from the symbol. This can be used instead of IAddImm to represent folding an + /// offset into a symbol. + offset: Imm64, + + /// Will this symbol be defined nearby, such that it will always be a certain distance + /// away, after linking? If so, references to it can avoid going through a GOT. Note that + /// symbols meant to be preemptible cannot be colocated. + /// + /// If `true`, some backends may use relocation forms that have limited range: for example, + /// a +/- 2^27-byte range on AArch64. See the documentation for + /// `RelocDistance` for more details. + colocated: bool, + + /// Does this symbol refer to a thread local storage value? + tls: bool, + }, + + /// Value is a multiple of how many instances of `vector_type` will fit in + /// a target vector register. + DynScaleTargetConst { + /// Base vector type. + vector_type: Type, + }, +} + +impl GlobalValueData { + /// Assume that `self` is an `GlobalValueData::Symbol` and return its name. + pub fn symbol_name(&self) -> &ExternalName { + match *self { + Self::Symbol { ref name, .. } => name, + _ => panic!("only symbols have names"), + } + } + + /// Return the type of this global. + pub fn global_type(&self, isa: &dyn TargetIsa) -> Type { + match *self { + Self::VMContext { .. } | Self::Symbol { .. } => isa.pointer_type(), + Self::IAddImm { global_type, .. } | Self::Load { global_type, .. } => global_type, + Self::DynScaleTargetConst { .. } => isa.pointer_type(), + } + } +} + +impl fmt::Display for GlobalValueData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::VMContext => write!(f, "vmctx"), + Self::Load { + base, + offset, + global_type, + flags, + } => write!(f, "load.{global_type}{flags} {base}{offset}"), + Self::IAddImm { + global_type, + base, + offset, + } => write!(f, "iadd_imm.{global_type} {base}, {offset}"), + Self::Symbol { + ref name, + offset, + colocated, + tls, + } => { + write!( + f, + "symbol {}{}{}", + if colocated { "colocated " } else { "" }, + if tls { "tls " } else { "" }, + name.display(None) + )?; + let offset_val: i64 = offset.into(); + if offset_val > 0 { + write!(f, "+")?; + } + if offset_val != 0 { + write!(f, "{offset}")?; + } + Ok(()) + } + Self::DynScaleTargetConst { vector_type } => { + write!(f, "dyn_scale_target_const.{vector_type}") + } + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/immediates.rs b/deps/crates/vendor/cranelift-codegen/src/ir/immediates.rs new file mode 100644 index 00000000000000..82ca114bee4bbf --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/immediates.rs @@ -0,0 +1,1961 @@ +//! Immediate operands for Cranelift instructions +//! +//! This module defines the types of immediate operands that can appear on Cranelift instructions. +//! Each type here should have a corresponding definition in the +//! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language. + +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt::{self, Display, Formatter}; +use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub}; +use core::str::FromStr; +use core::{i32, u32}; +use cranelift_entity::{Signed, Unsigned}; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Convert a type into a vector of bytes; all implementors in this file must use little-endian +/// orderings of bytes to match WebAssembly's little-endianness. +pub trait IntoBytes { + /// Return the little-endian byte representation of the implementing type. + fn into_bytes(self) -> Vec; +} + +impl IntoBytes for u8 { + fn into_bytes(self) -> Vec { + vec![self] + } +} + +impl IntoBytes for i8 { + fn into_bytes(self) -> Vec { + vec![self as u8] + } +} + +impl IntoBytes for i16 { + fn into_bytes(self) -> Vec { + self.to_le_bytes().to_vec() + } +} + +impl IntoBytes for i32 { + fn into_bytes(self) -> Vec { + self.to_le_bytes().to_vec() + } +} + +impl IntoBytes for Vec { + fn into_bytes(self) -> Vec { + self + } +} + +/// 64-bit immediate signed integer operand. +/// +/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by +/// sign-extending to `i64`. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Imm64(i64); + +impl Imm64 { + /// Create a new `Imm64` representing the signed number `x`. + pub fn new(x: i64) -> Self { + Self(x) + } + + /// Return self negated. + pub fn wrapping_neg(self) -> Self { + Self(self.0.wrapping_neg()) + } + + /// Returns the value of this immediate. + pub fn bits(&self) -> i64 { + self.0 + } + + /// Mask this immediate to the given power-of-two bit width. + #[must_use] + pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self { + debug_assert!(bit_width.is_power_of_two()); + + if bit_width >= 64 { + return *self; + } + + let bit_width = i64::from(bit_width); + let mask = (1 << bit_width) - 1; + let masked = self.0 & mask; + Imm64(masked) + } + + /// Sign extend this immediate as if it were a signed integer of the given + /// power-of-two width. + #[must_use] + pub fn sign_extend_from_width(&self, bit_width: u32) -> Self { + debug_assert!( + bit_width.is_power_of_two(), + "{bit_width} is not a power of two" + ); + + if bit_width >= 64 { + return *self; + } + + let bit_width = i64::from(bit_width); + let delta = 64 - bit_width; + let sign_extended = (self.0 << delta) >> delta; + Imm64(sign_extended) + } + + /// Zero extend this immediate as if it were an unsigned integer of the + /// given power-of-two width. + #[must_use] + pub fn zero_extend_from_width(&self, bit_width: u32) -> Self { + debug_assert!( + bit_width.is_power_of_two(), + "{bit_width} is not a power of two" + ); + + if bit_width >= 64 { + return *self; + } + + let bit_width = u64::from(bit_width); + let delta = 64 - bit_width; + let zero_extended = (self.0.unsigned() << delta) >> delta; + Imm64(zero_extended.signed()) + } +} + +impl From for i64 { + fn from(val: Imm64) -> i64 { + val.0 + } +} + +impl IntoBytes for Imm64 { + fn into_bytes(self) -> Vec { + self.0.to_le_bytes().to_vec() + } +} + +impl From for Imm64 { + fn from(x: i64) -> Self { + Self(x) + } +} + +impl Display for Imm64 { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let x = self.0; + if x < 10_000 { + // Use decimal for small and negative numbers. + write!(f, "{x}") + } else { + write_hex(x as u64, f) + } + } +} + +/// Parse a 64-bit signed number. +fn parse_i64(s: &str) -> Result { + let negative = s.starts_with('-'); + let s2 = if negative || s.starts_with('+') { + &s[1..] + } else { + s + }; + + let mut value = parse_u64(s2)?; + + // We support the range-and-a-half from -2^63 .. 2^64-1. + if negative { + value = value.wrapping_neg(); + // Don't allow large negative values to wrap around and become positive. + if value as i64 > 0 { + return Err("Negative number too small"); + } + } + Ok(value as i64) +} + +impl FromStr for Imm64 { + type Err = &'static str; + + // Parse a decimal or hexadecimal `Imm64`, formatted as above. + fn from_str(s: &str) -> Result { + parse_i64(s).map(Self::new) + } +} + +/// 64-bit immediate unsigned integer operand. +/// +/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by +/// zero-extending to `i64`. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Uimm64(u64); + +impl Uimm64 { + /// Create a new `Uimm64` representing the unsigned number `x`. + pub fn new(x: u64) -> Self { + Self(x) + } + + /// Return self negated. + pub fn wrapping_neg(self) -> Self { + Self(self.0.wrapping_neg()) + } +} + +impl From for u64 { + fn from(val: Uimm64) -> u64 { + val.0 + } +} + +impl From for Uimm64 { + fn from(x: u64) -> Self { + Self(x) + } +} + +/// Hexadecimal with a multiple of 4 digits and group separators: +/// +/// 0xfff0 +/// 0x0001_ffff +/// 0xffff_ffff_fff8_4400 +/// +fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result { + let mut pos = (64 - x.leading_zeros() - 1) & 0xf0; + write!(f, "0x{:04x}", (x >> pos) & 0xffff)?; + while pos > 0 { + pos -= 16; + write!(f, "_{:04x}", (x >> pos) & 0xffff)?; + } + Ok(()) +} + +impl Display for Uimm64 { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let x = self.0; + if x < 10_000 { + // Use decimal for small numbers. + write!(f, "{x}") + } else { + write_hex(x, f) + } + } +} + +/// Parse a 64-bit unsigned number. +fn parse_u64(s: &str) -> Result { + let mut value: u64 = 0; + let mut digits = 0; + + if s.starts_with("-0x") { + return Err("Invalid character in hexadecimal number"); + } else if let Some(num) = s.strip_prefix("0x") { + // Hexadecimal. + for ch in num.chars() { + match ch.to_digit(16) { + Some(digit) => { + digits += 1; + if digits > 16 { + return Err("Too many hexadecimal digits"); + } + // This can't overflow given the digit limit. + value = (value << 4) | u64::from(digit); + } + None => { + // Allow embedded underscores, but fail on anything else. + if ch != '_' { + return Err("Invalid character in hexadecimal number"); + } + } + } + } + } else { + // Decimal number, possibly negative. + for ch in s.chars() { + match ch.to_digit(10) { + Some(digit) => { + digits += 1; + match value.checked_mul(10) { + None => return Err("Too large decimal number"), + Some(v) => value = v, + } + match value.checked_add(u64::from(digit)) { + None => return Err("Too large decimal number"), + Some(v) => value = v, + } + } + None => { + // Allow embedded underscores, but fail on anything else. + if ch != '_' { + return Err("Invalid character in decimal number"); + } + } + } + } + } + + if digits == 0 { + return Err("No digits in number"); + } + + Ok(value) +} + +impl FromStr for Uimm64 { + type Err = &'static str; + + // Parse a decimal or hexadecimal `Uimm64`, formatted as above. + fn from_str(s: &str) -> Result { + parse_u64(s).map(Self::new) + } +} + +/// 8-bit unsigned integer immediate operand. +/// +/// This is used to indicate lane indexes typically. +pub type Uimm8 = u8; + +/// A 32-bit unsigned integer immediate operand. +/// +/// This is used to represent sizes of memory objects. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Uimm32(u32); + +impl From for u32 { + fn from(val: Uimm32) -> u32 { + val.0 + } +} + +impl From for u64 { + fn from(val: Uimm32) -> u64 { + val.0.into() + } +} + +impl From for i64 { + fn from(val: Uimm32) -> i64 { + i64::from(val.0) + } +} + +impl From for Uimm32 { + fn from(x: u32) -> Self { + Self(x) + } +} + +impl Display for Uimm32 { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.0 < 10_000 { + write!(f, "{}", self.0) + } else { + write_hex(u64::from(self.0), f) + } + } +} + +impl FromStr for Uimm32 { + type Err = &'static str; + + // Parse a decimal or hexadecimal `Uimm32`, formatted as above. + fn from_str(s: &str) -> Result { + parse_i64(s).and_then(|x| { + if 0 <= x && x <= i64::from(u32::MAX) { + Ok(Self(x as u32)) + } else { + Err("Uimm32 out of range") + } + }) + } +} + +/// A 128-bit immediate operand. +/// +/// This is used as an immediate value in SIMD instructions. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct V128Imm(pub [u8; 16]); + +impl V128Imm { + /// Iterate over the bytes in the constant. + pub fn bytes(&self) -> impl Iterator { + self.0.iter() + } + + /// Convert the immediate into a vector. + pub fn to_vec(self) -> Vec { + self.0.to_vec() + } + + /// Convert the immediate into a slice. + pub fn as_slice(&self) -> &[u8] { + &self.0[..] + } +} + +impl From<&[u8]> for V128Imm { + fn from(slice: &[u8]) -> Self { + assert_eq!(slice.len(), 16); + let mut buffer = [0; 16]; + buffer.copy_from_slice(slice); + Self(buffer) + } +} + +impl From for V128Imm { + fn from(val: u128) -> Self { + V128Imm(val.to_le_bytes()) + } +} + +/// 32-bit signed immediate offset. +/// +/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have +/// a maximum load/store offset that fits in an `i32`. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Offset32(i32); + +impl Offset32 { + /// Create a new `Offset32` representing the signed number `x`. + pub fn new(x: i32) -> Self { + Self(x) + } + + /// Create a new `Offset32` representing the signed number `x` if possible. + pub fn try_from_i64(x: i64) -> Option { + let x = i32::try_from(x).ok()?; + Some(Self::new(x)) + } + + /// Add in the signed number `x` if possible. + pub fn try_add_i64(self, x: i64) -> Option { + let x = i32::try_from(x).ok()?; + let ret = self.0.checked_add(x)?; + Some(Self::new(ret)) + } +} + +impl From for i32 { + fn from(val: Offset32) -> i32 { + val.0 + } +} + +impl From for i64 { + fn from(val: Offset32) -> i64 { + i64::from(val.0) + } +} + +impl From for Offset32 { + fn from(x: i32) -> Self { + Self(x) + } +} + +impl From for Offset32 { + fn from(val: u8) -> Offset32 { + Self(val.into()) + } +} + +impl Display for Offset32 { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + // 0 displays as an empty offset. + if self.0 == 0 { + return Ok(()); + } + + // Always include a sign. + write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?; + + let val = i64::from(self.0).abs(); + if val < 10_000 { + write!(f, "{val}") + } else { + write_hex(val as u64, f) + } + } +} + +impl FromStr for Offset32 { + type Err = &'static str; + + // Parse a decimal or hexadecimal `Offset32`, formatted as above. + fn from_str(s: &str) -> Result { + if !(s.starts_with('-') || s.starts_with('+')) { + return Err("Offset must begin with sign"); + } + parse_i64(s).and_then(|x| { + if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) { + Ok(Self::new(x as i32)) + } else { + Err("Offset out of range") + } + }) + } +} + +// FIXME(rust-lang/rust#83527): Replace with `${ignore()}` once it is stabilised. +macro_rules! ignore { + ($($t:tt)*) => {}; +} + +macro_rules! ieee_float { + ( + name = $name:ident, + bits = $bits:literal, + significand_bits = $significand_bits:literal, + bits_ty = $bits_ty:ident, + float_ty = $float_ty:ident, + $(as_float = $as_float:ident,)? + $(rust_type_not_stable = $rust_type_not_stable:ident,)? + ) => { + /// An IEEE + #[doc = concat!("binary", stringify!($bits))] + /// immediate floating point value, represented as a + #[doc = stringify!($bits_ty)] + /// containing the bit pattern. + /// + /// We specifically avoid using a + #[doc = stringify!($float_ty)] + /// here since some architectures may silently alter floats. + /// See: + /// + /// The [PartialEq] and [Hash] implementations are over the underlying bit pattern, but + /// [PartialOrd] respects IEEE754 semantics. + /// + /// All bit patterns are allowed. + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] + #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] + #[repr(C)] + pub struct $name { + bits: $bits_ty + } + + impl $name { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + const EXPONENT_BITS: u8 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + const SIGN_MASK: $bits_ty = 1 << (Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS); + const SIGNIFICAND_MASK: $bits_ty = $bits_ty::MAX >> (Self::EXPONENT_BITS + 1); + const EXPONENT_MASK: $bits_ty = !Self::SIGN_MASK & !Self::SIGNIFICAND_MASK; + /// The positive WebAssembly canonical NaN. + pub const NAN: Self = Self::with_bits(Self::EXPONENT_MASK | (1 << (Self::SIGNIFICAND_BITS - 1))); + + /// Create a new + #[doc = concat!("`", stringify!($name), "`")] + /// containing the bits of `bits`. + pub const fn with_bits(bits: $bits_ty) -> Self { + Self { bits } + } + + /// Get the bitwise representation. + pub fn bits(self) -> $bits_ty { + self.bits + } + + $( + /// Create a new + #[doc = concat!("`", stringify!($name), "`")] + /// representing the number `x`. + pub fn with_float(x: $float_ty) -> Self { + Self::with_bits(x.to_bits()) + } + + /// Converts `self` to a Rust + #[doc = concat!("`", stringify!($float_ty), "`.")] + pub fn $as_float(self) -> $float_ty { + $float_ty::from_bits(self.bits()) + } + )? + + /// Computes the absolute value of `self`. + pub fn abs(self) -> Self { + Self::with_bits(self.bits() & !Self::SIGN_MASK) + } + + /// Returns a number composed of the magnitude of `self` and the sign of `sign`. + pub fn copysign(self, sign: Self) -> Self { + Self::with_bits((self.bits() & !Self::SIGN_MASK) | (sign.bits() & Self::SIGN_MASK)) + } + + /// Returns the minimum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition. + pub fn minimum(self, other: Self) -> Self { + // FIXME: Replace with Rust float method once it is stabilised. + if self.is_nan() || other.is_nan() { + Self::NAN + } else if self.is_zero() && other.is_zero() { + if self.is_negative() { + self + } else { + other + } + } else if self <= other { + self + } else { + other + } + } + + /// Returns the maximum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition. + pub fn maximum(self, other: Self) -> Self { + // FIXME: Replace with Rust float method once it is stabilised. + if self.is_nan() || other.is_nan() { + Self::NAN + } else if self.is_zero() && other.is_zero() { + if self.is_positive() { + self + } else { + other + } + } else if self >= other { + self + } else { + other + } + } + + /// Create an + #[doc = concat!("`", stringify!($name), "`")] + /// number representing `2.0^n`. + pub fn pow2>(n: I) -> Self { + let n = n.into(); + let w = Self::EXPONENT_BITS; + let t = Self::SIGNIFICAND_BITS; + let bias = (1 << (w - 1)) - 1; + let exponent = n + bias; + assert!(exponent > 0, "Underflow n={}", n); + assert!(exponent < (1 << w) + 1, "Overflow n={}", n); + Self::with_bits((exponent as $bits_ty) << t) + } + + /// Create an + #[doc = concat!("`", stringify!($name), "`")] + /// number representing the greatest negative value not convertible from + #[doc = concat!("`", stringify!($float_ty), "`")] + /// to a signed integer with width n. + pub fn fcvt_to_sint_negative_overflow>(n: I) -> Self { + let n = n.into(); + debug_assert!(n < i32::from(Self::BITS)); + debug_assert!(i32::from(Self::SIGNIFICAND_BITS) + 1 - n < i32::from(Self::BITS)); + Self::with_bits((1 << (Self::BITS - 1)) | Self::pow2(n - 1).bits() | (1 << (i32::from(Self::SIGNIFICAND_BITS) + 1 - n))) + } + + /// Check if the value is a NaN. For + #[doc = concat!("`", stringify!($name), "`,")] + /// this means checking that all the exponent bits are set and the significand is non-zero. + pub fn is_nan(self) -> bool { + self.abs().bits() > Self::EXPONENT_MASK + } + + /// Returns true if `self` has a negative sign, including 0.0, NaNs with positive sign bit and positive infinity. + pub fn is_positive(self) -> bool { + !self.is_negative() + } + + /// Returns true if `self` has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity. + pub fn is_negative(self) -> bool { + self.bits() & Self::SIGN_MASK == Self::SIGN_MASK + } + + /// Returns `true` if `self` is positive or negative zero. + pub fn is_zero(self) -> bool { + self.abs().bits() == 0 + } + + /// Returns `None` if `self` is a NaN and `Some(self)` otherwise. + pub fn non_nan(self) -> Option { + Some(self).filter(|f| !f.is_nan()) + } + + $( + /// Returns the square root of `self`. + pub fn sqrt(self) -> Self { + Self::with_float(self.$as_float().sqrt()) + } + + /// Returns the smallest integer greater than or equal to `self`. + pub fn ceil(self) -> Self { + Self::with_float(self.$as_float().ceil()) + } + + /// Returns the largest integer less than or equal to `self`. + pub fn floor(self) -> Self { + Self::with_float(self.$as_float().floor()) + } + + /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero. + pub fn trunc(self) -> Self { + Self::with_float(self.$as_float().trunc()) + } + + /// Returns the nearest integer to `self`. Rounds half-way cases to the number + /// with an even least significant digit. + pub fn round_ties_even(self) -> Self { + Self::with_float(self.$as_float().round_ties_even()) + } + )? + } + + impl PartialOrd for $name { + fn partial_cmp(&self, rhs: &Self) -> Option { + $(self.$as_float().partial_cmp(&rhs.$as_float()))? + $( + ignore!($rust_type_not_stable); + // FIXME(#8312): Use builtin Rust comparisons once `f16` and `f128` support is stabalised. + if self.is_nan() || rhs.is_nan() { + // One of the floats is a NaN. + return None; + } + if self.is_zero() || rhs.is_zero() { + // Zeros are always equal regardless of sign. + return Some(Ordering::Equal); + } + let lhs_positive = self.is_positive(); + let rhs_positive = rhs.is_positive(); + if lhs_positive != rhs_positive { + // Different signs: negative < positive + return lhs_positive.partial_cmp(&rhs_positive); + } + // Finite or infinity will order correctly with an integer comparison of the bits. + if lhs_positive { + self.bits().partial_cmp(&rhs.bits()) + } else { + // Reverse the comparison when both floats are negative. + rhs.bits().partial_cmp(&self.bits()) + } + )? + } + } + + impl Display for $name { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + format_float(u128::from(self.bits()), Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS, f) + } + } + + impl FromStr for $name { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match parse_float(s, Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS) { + Ok(b) => Ok(Self::with_bits(b.try_into().unwrap())), + Err(s) => Err(s), + } + } + } + + impl IntoBytes for $name { + fn into_bytes(self) -> Vec { + self.bits().to_le_bytes().to_vec() + } + } + + impl Neg for $name { + type Output = Self; + + fn neg(self) -> Self { + Self::with_bits(self.bits() ^ Self::SIGN_MASK) + } + } + + + + $( + impl From<$float_ty> for $name { + fn from(x: $float_ty) -> Self { + Self::with_float(x) + } + } + + impl Add for $name { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self::with_float(self.$as_float() + rhs.$as_float()) + } + } + + impl Sub for $name { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + Self::with_float(self.$as_float() - rhs.$as_float()) + } + } + + impl Mul for $name { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + Self::with_float(self.$as_float() * rhs.$as_float()) + } + } + + impl Div for $name { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self::with_float(self.$as_float() / rhs.$as_float()) + } + } + )? + + impl BitAnd for $name { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self { + Self::with_bits(self.bits() & rhs.bits()) + } + } + + impl BitOr for $name { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Self::with_bits(self.bits() | rhs.bits()) + } + } + + impl BitXor for $name { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Self { + Self::with_bits(self.bits() ^ rhs.bits()) + } + } + + impl Not for $name { + type Output = Self; + + fn not(self) -> Self { + Self::with_bits(!self.bits()) + } + } + }; +} + +ieee_float! { + name = Ieee16, + bits = 16, + significand_bits = 10, + bits_ty = u16, + float_ty = f16, + rust_type_not_stable = rust_type_not_stable, +} + +ieee_float! { + name = Ieee32, + bits = 32, + significand_bits = 23, + bits_ty = u32, + float_ty = f32, + as_float = as_f32, +} + +ieee_float! { + name = Ieee64, + bits = 64, + significand_bits = 52, + bits_ty = u64, + float_ty = f64, + as_float = as_f64, +} + +ieee_float! { + name = Ieee128, + bits = 128, + significand_bits = 112, + bits_ty = u128, + float_ty = f128, + rust_type_not_stable = rust_type_not_stable, +} + +/// Format a floating point number in a way that is reasonably human-readable, and that can be +/// converted back to binary without any rounding issues. The hexadecimal formatting of normal and +/// subnormal numbers is compatible with C99 and the `printf "%a"` format specifier. The NaN and Inf +/// formats are not supported by C99. +/// +/// The encoding parameters are: +/// +/// w - exponent field width in bits +/// t - trailing significand field width in bits +/// +fn format_float(bits: u128, w: u8, t: u8, f: &mut Formatter) -> fmt::Result { + debug_assert!(w > 0 && w <= 16, "Invalid exponent range"); + debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128"); + debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size"); + + let max_e_bits = (1u128 << w) - 1; + let t_bits = bits & ((1u128 << t) - 1); // Trailing significand. + let e_bits = (bits >> t) & max_e_bits; // Biased exponent. + let sign_bit = (bits >> (w + t)) & 1; + + let bias: i32 = (1 << (w - 1)) - 1; + let e = e_bits as i32 - bias; // Unbiased exponent. + let emin = 1 - bias; // Minimum exponent. + + // How many hexadecimal digits are needed for the trailing significand? + let digits = (t + 3) / 4; + // Trailing significand left-aligned in `digits` hexadecimal digits. + let left_t_bits = t_bits << (4 * digits - t); + + // All formats share the leading sign. + if sign_bit != 0 { + write!(f, "-")?; + } + + if e_bits == 0 { + if t_bits == 0 { + // Zero. + write!(f, "0.0") + } else { + // Subnormal. + write!( + f, + "0x0.{0:01$x}p{2}", + left_t_bits, + usize::from(digits), + emin + ) + } + } else if e_bits == max_e_bits { + // Always print a `+` or `-` sign for these special values. + // This makes them easier to parse as they can't be confused as identifiers. + if sign_bit == 0 { + write!(f, "+")?; + } + if t_bits == 0 { + // Infinity. + write!(f, "Inf") + } else { + // NaN. + let payload = t_bits & ((1 << (t - 1)) - 1); + if t_bits & (1 << (t - 1)) != 0 { + // Quiet NaN. + if payload != 0 { + write!(f, "NaN:0x{payload:x}") + } else { + write!(f, "NaN") + } + } else { + // Signaling NaN. + write!(f, "sNaN:0x{payload:x}") + } + } + } else { + // Normal number. + write!(f, "0x1.{0:01$x}p{2}", left_t_bits, usize::from(digits), e) + } +} + +/// Parse a float using the same format as `format_float` above. +/// +/// The encoding parameters are: +/// +/// w - exponent field width in bits +/// t - trailing significand field width in bits +/// +fn parse_float(s: &str, w: u8, t: u8) -> Result { + debug_assert!(w > 0 && w <= 16, "Invalid exponent range"); + debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128"); + debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size"); + + let (sign_bit, s2) = if let Some(num) = s.strip_prefix('-') { + (1u128 << (t + w), num) + } else if let Some(num) = s.strip_prefix('+') { + (0, num) + } else { + (0, s) + }; + + if !s2.starts_with("0x") { + let max_e_bits = ((1u128 << w) - 1) << t; + let quiet_bit = 1u128 << (t - 1); + + // The only decimal encoding allowed is 0. + if s2 == "0.0" { + return Ok(sign_bit); + } + + if s2 == "Inf" { + // +/- infinity: e = max, t = 0. + return Ok(sign_bit | max_e_bits); + } + if s2 == "NaN" { + // Canonical quiet NaN: e = max, t = quiet. + return Ok(sign_bit | max_e_bits | quiet_bit); + } + if let Some(nan) = s2.strip_prefix("NaN:0x") { + // Quiet NaN with payload. + return match u128::from_str_radix(nan, 16) { + Ok(payload) if payload < quiet_bit => { + Ok(sign_bit | max_e_bits | quiet_bit | payload) + } + _ => Err("Invalid NaN payload"), + }; + } + if let Some(nan) = s2.strip_prefix("sNaN:0x") { + // Signaling NaN with payload. + return match u128::from_str_radix(nan, 16) { + Ok(payload) if 0 < payload && payload < quiet_bit => { + Ok(sign_bit | max_e_bits | payload) + } + _ => Err("Invalid sNaN payload"), + }; + } + + return Err("Float must be hexadecimal"); + } + let s3 = &s2[2..]; + + let mut digits = 0u8; + let mut digits_before_period: Option = None; + let mut significand = 0u128; + let mut exponent = 0i32; + + for (idx, ch) in s3.char_indices() { + match ch { + '.' => { + // This is the radix point. There can only be one. + if digits_before_period != None { + return Err("Multiple radix points"); + } else { + digits_before_period = Some(digits); + } + } + 'p' => { + // The following exponent is a decimal number. + let exp_str = &s3[1 + idx..]; + match exp_str.parse::() { + Ok(e) => { + exponent = i32::from(e); + break; + } + Err(_) => return Err("Bad exponent"), + } + } + _ => match ch.to_digit(16) { + Some(digit) => { + digits += 1; + if digits > 32 { + return Err("Too many digits"); + } + significand = (significand << 4) | u128::from(digit); + } + None => return Err("Invalid character"), + }, + } + } + + if digits == 0 { + return Err("No digits"); + } + + if significand == 0 { + // This is +/- 0.0. + return Ok(sign_bit); + } + + // Number of bits appearing after the radix point. + match digits_before_period { + None => {} // No radix point present. + Some(d) => exponent -= 4 * i32::from(digits - d), + }; + + // Normalize the significand and exponent. + let significant_bits = (128 - significand.leading_zeros()) as u8; + if significant_bits > t + 1 { + let adjust = significant_bits - (t + 1); + if significand & ((1u128 << adjust) - 1) != 0 { + return Err("Too many significant bits"); + } + // Adjust significand down. + significand >>= adjust; + exponent += i32::from(adjust); + } else { + let adjust = t + 1 - significant_bits; + significand <<= adjust; + exponent -= i32::from(adjust); + } + debug_assert_eq!(significand >> t, 1); + + // Trailing significand excludes the high bit. + let t_bits = significand & ((1 << t) - 1); + + let max_exp = (1i32 << w) - 2; + let bias: i32 = (1 << (w - 1)) - 1; + exponent += bias + i32::from(t); + + if exponent > max_exp { + Err("Magnitude too large") + } else if exponent > 0 { + // This is a normal number. + let e_bits = (exponent as u128) << t; + Ok(sign_bit | e_bits | t_bits) + } else if 1 - exponent <= i32::from(t) { + // This is a subnormal number: e = 0, t = significand bits. + // Renormalize significand for exponent = 1. + let adjust = 1 - exponent; + if significand & ((1u128 << adjust) - 1) != 0 { + Err("Subnormal underflow") + } else { + significand >>= adjust; + Ok(sign_bit | significand) + } + } else { + Err("Magnitude too small") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + use core::{f32, f64}; + + #[test] + fn format_imm64() { + assert_eq!(Imm64(0).to_string(), "0"); + assert_eq!(Imm64(9999).to_string(), "9999"); + assert_eq!(Imm64(10000).to_string(), "0x2710"); + assert_eq!(Imm64(-9999).to_string(), "-9999"); + assert_eq!(Imm64(-10000).to_string(), "-10000"); + assert_eq!(Imm64(0xffff).to_string(), "0xffff"); + assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000"); + } + + #[test] + fn format_uimm64() { + assert_eq!(Uimm64(0).to_string(), "0"); + assert_eq!(Uimm64(9999).to_string(), "9999"); + assert_eq!(Uimm64(10000).to_string(), "0x2710"); + assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1"); + assert_eq!( + Uimm64(-10000i64 as u64).to_string(), + "0xffff_ffff_ffff_d8f0" + ); + assert_eq!(Uimm64(0xffff).to_string(), "0xffff"); + assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000"); + } + + // Verify that `text` can be parsed as a `T` into a value that displays as `want`. + #[track_caller] + fn parse_ok(text: &str, want: &str) + where + ::Err: Display, + { + match text.parse::() { + Err(s) => panic!("\"{text}\".parse() error: {s}"), + Ok(x) => assert_eq!(x.to_string(), want), + } + } + + // Verify that `text` fails to parse as `T` with the error `msg`. + fn parse_err(text: &str, msg: &str) + where + ::Err: Display, + { + match text.parse::() { + Err(s) => assert_eq!(s.to_string(), msg), + Ok(x) => panic!("Wanted Err({msg}), but got {x}"), + } + } + + #[test] + fn parse_imm64() { + parse_ok::("0", "0"); + parse_ok::("1", "1"); + parse_ok::("-0", "0"); + parse_ok::("-1", "-1"); + parse_ok::("0x0", "0"); + parse_ok::("0xf", "15"); + parse_ok::("-0x9", "-9"); + + // Probe limits. + parse_ok::("0xffffffff_ffffffff", "-1"); + parse_ok::("0x80000000_00000000", "-9223372036854775808"); + parse_ok::("-0x80000000_00000000", "-9223372036854775808"); + parse_err::("-0x80000000_00000001", "Negative number too small"); + parse_ok::("18446744073709551615", "-1"); + parse_ok::("-9223372036854775808", "-9223372036854775808"); + // Overflow both the `checked_add` and `checked_mul`. + parse_err::("18446744073709551616", "Too large decimal number"); + parse_err::("184467440737095516100", "Too large decimal number"); + parse_err::("-9223372036854775809", "Negative number too small"); + + // Underscores are allowed where digits go. + parse_ok::("0_0", "0"); + parse_ok::("-_10_0", "-100"); + parse_ok::("_10_", "10"); + parse_ok::("0x97_88_bb", "0x0097_88bb"); + parse_ok::("0x_97_", "151"); + + parse_err::("", "No digits in number"); + parse_err::("-", "No digits in number"); + parse_err::("_", "No digits in number"); + parse_err::("0x", "No digits in number"); + parse_err::("0x_", "No digits in number"); + parse_err::("-0x", "No digits in number"); + parse_err::(" ", "Invalid character in decimal number"); + parse_err::("0 ", "Invalid character in decimal number"); + parse_err::(" 0", "Invalid character in decimal number"); + parse_err::("--", "Invalid character in decimal number"); + parse_err::("-0x-", "Invalid character in hexadecimal number"); + parse_err::("abc", "Invalid character in decimal number"); + parse_err::("-abc", "Invalid character in decimal number"); + + // Hex count overflow. + parse_err::("0x0_0000_0000_0000_0000", "Too many hexadecimal digits"); + } + + #[test] + fn parse_uimm64() { + parse_ok::("0", "0"); + parse_ok::("1", "1"); + parse_ok::("0x0", "0"); + parse_ok::("0xf", "15"); + parse_ok::("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7"); + + // Probe limits. + parse_ok::("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff"); + parse_ok::("0x80000000_00000000", "0x8000_0000_0000_0000"); + parse_ok::("18446744073709551615", "0xffff_ffff_ffff_ffff"); + // Overflow both the `checked_add` and `checked_mul`. + parse_err::("18446744073709551616", "Too large decimal number"); + parse_err::("184467440737095516100", "Too large decimal number"); + + // Underscores are allowed where digits go. + parse_ok::("0_0", "0"); + parse_ok::("_10_", "10"); + parse_ok::("0x97_88_bb", "0x0097_88bb"); + parse_ok::("0x_97_", "151"); + + parse_err::("", "No digits in number"); + parse_err::("_", "No digits in number"); + parse_err::("0x", "No digits in number"); + parse_err::("0x_", "No digits in number"); + parse_err::("-", "Invalid character in decimal number"); + parse_err::("-0x", "Invalid character in hexadecimal number"); + parse_err::(" ", "Invalid character in decimal number"); + parse_err::("0 ", "Invalid character in decimal number"); + parse_err::(" 0", "Invalid character in decimal number"); + parse_err::("--", "Invalid character in decimal number"); + parse_err::("-0x-", "Invalid character in hexadecimal number"); + parse_err::("-0", "Invalid character in decimal number"); + parse_err::("-1", "Invalid character in decimal number"); + parse_err::("abc", "Invalid character in decimal number"); + parse_err::("-abc", "Invalid character in decimal number"); + + // Hex count overflow. + parse_err::("0x0_0000_0000_0000_0000", "Too many hexadecimal digits"); + } + + #[test] + fn format_offset32() { + assert_eq!(Offset32(0).to_string(), ""); + assert_eq!(Offset32(1).to_string(), "+1"); + assert_eq!(Offset32(-1).to_string(), "-1"); + assert_eq!(Offset32(9999).to_string(), "+9999"); + assert_eq!(Offset32(10000).to_string(), "+0x2710"); + assert_eq!(Offset32(-9999).to_string(), "-9999"); + assert_eq!(Offset32(-10000).to_string(), "-0x2710"); + assert_eq!(Offset32(0xffff).to_string(), "+0xffff"); + assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000"); + } + + #[test] + fn parse_offset32() { + parse_ok::("+0", ""); + parse_ok::("+1", "+1"); + parse_ok::("-0", ""); + parse_ok::("-1", "-1"); + parse_ok::("+0x0", ""); + parse_ok::("+0xf", "+15"); + parse_ok::("-0x9", "-9"); + parse_ok::("-0x8000_0000", "-0x8000_0000"); + + parse_err::("+0x8000_0000", "Offset out of range"); + } + + #[test] + fn format_ieee16() { + assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.0 + assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.0 + assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.0 + assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.5 + assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.5 + assert_eq!( + Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON` + "0x1.000p-10" + ); + assert_eq!( + Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN` + "-0x1.ffcp15" + ); + assert_eq!( + Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX` + "0x1.ffcp15" + ); + // Smallest positive normal number. + assert_eq!( + Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE` + "0x1.000p-14" + ); + // Subnormals. + assert_eq!( + Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0` + "0x0.800p-14" + ); + assert_eq!( + Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON` + "0x0.004p-14" + ); + assert_eq!( + Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY` + "+Inf" + ); + assert_eq!( + Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY` + "-Inf" + ); + assert_eq!( + Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN` + "+NaN" + ); + assert_eq!( + Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN` + "-NaN" + ); + // Construct some qNaNs with payloads. + assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1"); + assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101"); + // Signaling NaNs. + assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1"); + assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101"); + } + + #[test] + fn parse_ieee16() { + parse_ok::("0.0", "0.0"); + parse_ok::("+0.0", "0.0"); + parse_ok::("-0.0", "-0.0"); + parse_ok::("0x0", "0.0"); + parse_ok::("0x0.0", "0.0"); + parse_ok::("0x.0", "0.0"); + parse_ok::("0x0.", "0.0"); + parse_ok::("0x1", "0x1.000p0"); + parse_ok::("+0x1", "0x1.000p0"); + parse_ok::("-0x1", "-0x1.000p0"); + parse_ok::("0x10", "0x1.000p4"); + parse_ok::("0x10.0", "0x1.000p4"); + parse_err::("0.", "Float must be hexadecimal"); + parse_err::(".0", "Float must be hexadecimal"); + parse_err::("0", "Float must be hexadecimal"); + parse_err::("-0", "Float must be hexadecimal"); + parse_err::(".", "Float must be hexadecimal"); + parse_err::("", "Float must be hexadecimal"); + parse_err::("-", "Float must be hexadecimal"); + parse_err::("0x", "No digits"); + parse_err::("0x..", "Multiple radix points"); + + // Check significant bits. + parse_ok::("0x0.ffe", "0x1.ffcp-1"); + parse_ok::("0x1.ffc", "0x1.ffcp0"); + parse_ok::("0x3.ff8", "0x1.ffcp1"); + parse_ok::("0x7.ff", "0x1.ffcp2"); + parse_ok::("0xf.fe", "0x1.ffcp3"); + parse_err::("0x1.ffe", "Too many significant bits"); + parse_err::("0x1.ffc00000000000000000000000000000", "Too many digits"); + + // Exponents. + parse_ok::("0x1p3", "0x1.000p3"); + parse_ok::("0x1p-3", "0x1.000p-3"); + parse_ok::("0x1.0p3", "0x1.000p3"); + parse_ok::("0x2.0p3", "0x1.000p4"); + parse_ok::("0x1.0p15", "0x1.000p15"); + parse_ok::("0x1.0p-14", "0x1.000p-14"); + parse_ok::("0x0.1p-10", "0x1.000p-14"); + parse_err::("0x2.0p15", "Magnitude too large"); + + // Subnormals. + parse_ok::("0x1.0p-15", "0x0.800p-14"); + parse_ok::("0x1.0p-24", "0x0.004p-14"); + parse_ok::("0x0.004p-14", "0x0.004p-14"); + parse_err::("0x0.102p-14", "Subnormal underflow"); + parse_err::("0x1.8p-24", "Subnormal underflow"); + parse_err::("0x1.0p-25", "Magnitude too small"); + + // NaNs and Infs. + parse_ok::("Inf", "+Inf"); + parse_ok::("+Inf", "+Inf"); + parse_ok::("-Inf", "-Inf"); + parse_ok::("NaN", "+NaN"); + parse_ok::("+NaN", "+NaN"); + parse_ok::("-NaN", "-NaN"); + parse_ok::("NaN:0x0", "+NaN"); + parse_err::("NaN:", "Float must be hexadecimal"); + parse_err::("NaN:0", "Float must be hexadecimal"); + parse_err::("NaN:0x", "Invalid NaN payload"); + parse_ok::("NaN:0x001", "+NaN:0x1"); + parse_ok::("NaN:0x101", "+NaN:0x101"); + parse_err::("NaN:0x301", "Invalid NaN payload"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); + parse_err::("sNaN:0x0", "Invalid sNaN payload"); + parse_ok::("sNaN:0x101", "+sNaN:0x101"); + parse_err::("sNaN:0x301", "Invalid sNaN payload"); + } + + #[test] + fn pow2_ieee16() { + assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0"); + assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1"); + assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1"); + assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15"); + assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14"); + + assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1"); + } + + #[test] + fn fcvt_to_sint_negative_overflow_ieee16() { + // FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised. + // let n = 8; + // assert_eq!( + // -((1u16 << (n - 1)) as f16) - 1.0, + // Ieee16::fcvt_to_sint_negative_overflow(n).as_f16() + // ); + let n = 8; + assert_eq!( + "-0x1.020p7", + Ieee16::fcvt_to_sint_negative_overflow(n).to_string() + ); + } + + #[test] + fn format_ieee32() { + assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0"); + assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0"); + assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0"); + assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0"); + assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1"); + assert_eq!( + Ieee32::with_float(f32::EPSILON).to_string(), + "0x1.000000p-23" + ); + assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127"); + assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127"); + // Smallest positive normal number. + assert_eq!( + Ieee32::with_float(f32::MIN_POSITIVE).to_string(), + "0x1.000000p-126" + ); + // Subnormals. + assert_eq!( + Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(), + "0x0.800000p-126" + ); + assert_eq!( + Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(), + "0x0.000002p-126" + ); + assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf"); + assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf"); + assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN"); + assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN"); + // Construct some qNaNs with payloads. + assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1"); + assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001"); + // Signaling NaNs. + assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1"); + assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001"); + } + + #[test] + fn parse_ieee32() { + parse_ok::("0.0", "0.0"); + parse_ok::("+0.0", "0.0"); + parse_ok::("-0.0", "-0.0"); + parse_ok::("0x0", "0.0"); + parse_ok::("0x0.0", "0.0"); + parse_ok::("0x.0", "0.0"); + parse_ok::("0x0.", "0.0"); + parse_ok::("0x1", "0x1.000000p0"); + parse_ok::("+0x1", "0x1.000000p0"); + parse_ok::("-0x1", "-0x1.000000p0"); + parse_ok::("0x10", "0x1.000000p4"); + parse_ok::("0x10.0", "0x1.000000p4"); + parse_err::("0.", "Float must be hexadecimal"); + parse_err::(".0", "Float must be hexadecimal"); + parse_err::("0", "Float must be hexadecimal"); + parse_err::("-0", "Float must be hexadecimal"); + parse_err::(".", "Float must be hexadecimal"); + parse_err::("", "Float must be hexadecimal"); + parse_err::("-", "Float must be hexadecimal"); + parse_err::("0x", "No digits"); + parse_err::("0x..", "Multiple radix points"); + + // Check significant bits. + parse_ok::("0x0.ffffff", "0x1.fffffep-1"); + parse_ok::("0x1.fffffe", "0x1.fffffep0"); + parse_ok::("0x3.fffffc", "0x1.fffffep1"); + parse_ok::("0x7.fffff8", "0x1.fffffep2"); + parse_ok::("0xf.fffff0", "0x1.fffffep3"); + parse_err::("0x1.ffffff", "Too many significant bits"); + parse_err::("0x1.fffffe00000000000000000000000000", "Too many digits"); + + // Exponents. + parse_ok::("0x1p3", "0x1.000000p3"); + parse_ok::("0x1p-3", "0x1.000000p-3"); + parse_ok::("0x1.0p3", "0x1.000000p3"); + parse_ok::("0x2.0p3", "0x1.000000p4"); + parse_ok::("0x1.0p127", "0x1.000000p127"); + parse_ok::("0x1.0p-126", "0x1.000000p-126"); + parse_ok::("0x0.1p-122", "0x1.000000p-126"); + parse_err::("0x2.0p127", "Magnitude too large"); + + // Subnormals. + parse_ok::("0x1.0p-127", "0x0.800000p-126"); + parse_ok::("0x1.0p-149", "0x0.000002p-126"); + parse_ok::("0x0.000002p-126", "0x0.000002p-126"); + parse_err::("0x0.100001p-126", "Subnormal underflow"); + parse_err::("0x1.8p-149", "Subnormal underflow"); + parse_err::("0x1.0p-150", "Magnitude too small"); + + // NaNs and Infs. + parse_ok::("Inf", "+Inf"); + parse_ok::("+Inf", "+Inf"); + parse_ok::("-Inf", "-Inf"); + parse_ok::("NaN", "+NaN"); + parse_ok::("+NaN", "+NaN"); + parse_ok::("-NaN", "-NaN"); + parse_ok::("NaN:0x0", "+NaN"); + parse_err::("NaN:", "Float must be hexadecimal"); + parse_err::("NaN:0", "Float must be hexadecimal"); + parse_err::("NaN:0x", "Invalid NaN payload"); + parse_ok::("NaN:0x000001", "+NaN:0x1"); + parse_ok::("NaN:0x300001", "+NaN:0x300001"); + parse_err::("NaN:0x400001", "Invalid NaN payload"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); + parse_err::("sNaN:0x0", "Invalid sNaN payload"); + parse_ok::("sNaN:0x200001", "+sNaN:0x200001"); + parse_err::("sNaN:0x400001", "Invalid sNaN payload"); + } + + #[test] + fn pow2_ieee32() { + assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0"); + assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1"); + assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1"); + assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127"); + assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126"); + + assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1"); + } + + #[test] + fn fcvt_to_sint_negative_overflow_ieee32() { + for n in [8, 16] { + assert_eq!( + -((1u32 << (n - 1)) as f32) - 1.0, + Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(), + "n = {n}" + ); + } + } + + #[test] + fn format_ieee64() { + assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0"); + assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0"); + assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0"); + assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0"); + assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1"); + assert_eq!( + Ieee64::with_float(f64::EPSILON).to_string(), + "0x1.0000000000000p-52" + ); + assert_eq!( + Ieee64::with_float(f64::MIN).to_string(), + "-0x1.fffffffffffffp1023" + ); + assert_eq!( + Ieee64::with_float(f64::MAX).to_string(), + "0x1.fffffffffffffp1023" + ); + // Smallest positive normal number. + assert_eq!( + Ieee64::with_float(f64::MIN_POSITIVE).to_string(), + "0x1.0000000000000p-1022" + ); + // Subnormals. + assert_eq!( + Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(), + "0x0.8000000000000p-1022" + ); + assert_eq!( + Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(), + "0x0.0000000000001p-1022" + ); + assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf"); + assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf"); + assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN"); + assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN"); + // Construct some qNaNs with payloads. + assert_eq!( + Ieee64::with_bits(0x7ff8000000000001).to_string(), + "+NaN:0x1" + ); + assert_eq!( + Ieee64::with_bits(0x7ffc000000000001).to_string(), + "+NaN:0x4000000000001" + ); + // Signaling NaNs. + assert_eq!( + Ieee64::with_bits(0x7ff0000000000001).to_string(), + "+sNaN:0x1" + ); + assert_eq!( + Ieee64::with_bits(0x7ff4000000000001).to_string(), + "+sNaN:0x4000000000001" + ); + } + + #[test] + fn parse_ieee64() { + parse_ok::("0.0", "0.0"); + parse_ok::("-0.0", "-0.0"); + parse_ok::("0x0", "0.0"); + parse_ok::("0x0.0", "0.0"); + parse_ok::("0x.0", "0.0"); + parse_ok::("0x0.", "0.0"); + parse_ok::("0x1", "0x1.0000000000000p0"); + parse_ok::("-0x1", "-0x1.0000000000000p0"); + parse_ok::("0x10", "0x1.0000000000000p4"); + parse_ok::("0x10.0", "0x1.0000000000000p4"); + parse_err::("0.", "Float must be hexadecimal"); + parse_err::(".0", "Float must be hexadecimal"); + parse_err::("0", "Float must be hexadecimal"); + parse_err::("-0", "Float must be hexadecimal"); + parse_err::(".", "Float must be hexadecimal"); + parse_err::("", "Float must be hexadecimal"); + parse_err::("-", "Float must be hexadecimal"); + parse_err::("0x", "No digits"); + parse_err::("0x..", "Multiple radix points"); + + // Check significant bits. + parse_ok::("0x0.fffffffffffff8", "0x1.fffffffffffffp-1"); + parse_ok::("0x1.fffffffffffff", "0x1.fffffffffffffp0"); + parse_ok::("0x3.ffffffffffffe", "0x1.fffffffffffffp1"); + parse_ok::("0x7.ffffffffffffc", "0x1.fffffffffffffp2"); + parse_ok::("0xf.ffffffffffff8", "0x1.fffffffffffffp3"); + parse_err::("0x3.fffffffffffff", "Too many significant bits"); + parse_err::("0x001.fffffe000000000000000000000000", "Too many digits"); + + // Exponents. + parse_ok::("0x1p3", "0x1.0000000000000p3"); + parse_ok::("0x1p-3", "0x1.0000000000000p-3"); + parse_ok::("0x1.0p3", "0x1.0000000000000p3"); + parse_ok::("0x2.0p3", "0x1.0000000000000p4"); + parse_ok::("0x1.0p1023", "0x1.0000000000000p1023"); + parse_ok::("0x1.0p-1022", "0x1.0000000000000p-1022"); + parse_ok::("0x0.1p-1018", "0x1.0000000000000p-1022"); + parse_err::("0x2.0p1023", "Magnitude too large"); + + // Subnormals. + parse_ok::("0x1.0p-1023", "0x0.8000000000000p-1022"); + parse_ok::("0x1.0p-1074", "0x0.0000000000001p-1022"); + parse_ok::("0x0.0000000000001p-1022", "0x0.0000000000001p-1022"); + parse_err::("0x0.10000000000008p-1022", "Subnormal underflow"); + parse_err::("0x1.8p-1074", "Subnormal underflow"); + parse_err::("0x1.0p-1075", "Magnitude too small"); + + // NaNs and Infs. + parse_ok::("Inf", "+Inf"); + parse_ok::("-Inf", "-Inf"); + parse_ok::("NaN", "+NaN"); + parse_ok::("-NaN", "-NaN"); + parse_ok::("NaN:0x0", "+NaN"); + parse_err::("NaN:", "Float must be hexadecimal"); + parse_err::("NaN:0", "Float must be hexadecimal"); + parse_err::("NaN:0x", "Invalid NaN payload"); + parse_ok::("NaN:0x000001", "+NaN:0x1"); + parse_ok::("NaN:0x4000000000001", "+NaN:0x4000000000001"); + parse_err::("NaN:0x8000000000001", "Invalid NaN payload"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); + parse_err::("sNaN:0x0", "Invalid sNaN payload"); + parse_ok::("sNaN:0x4000000000001", "+sNaN:0x4000000000001"); + parse_err::("sNaN:0x8000000000001", "Invalid sNaN payload"); + } + + #[test] + fn pow2_ieee64() { + assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0"); + assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1"); + assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1"); + assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023"); + assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022"); + + assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1"); + } + + #[test] + fn fcvt_to_sint_negative_overflow_ieee64() { + for n in [8, 16, 32] { + assert_eq!( + -((1u64 << (n - 1)) as f64) - 1.0, + Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(), + "n = {n}" + ); + } + } + + #[test] + fn format_ieee128() { + assert_eq!( + Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.0 + "0.0" + ); + assert_eq!( + Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.0 + "-0.0" + ); + assert_eq!( + Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.0 + "0x1.0000000000000000000000000000p0" + ); + assert_eq!( + Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.5 + "0x1.8000000000000000000000000000p0" + ); + assert_eq!( + Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.5 + "0x1.0000000000000000000000000000p-1" + ); + assert_eq!( + Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON` + "0x1.0000000000000000000000000000p-112" + ); + assert_eq!( + Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN` + "-0x1.ffffffffffffffffffffffffffffp16383" + ); + assert_eq!( + Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX` + "0x1.ffffffffffffffffffffffffffffp16383" + ); + // Smallest positive normal number. + assert_eq!( + Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE` + "0x1.0000000000000000000000000000p-16382" + ); + // Subnormals. + assert_eq!( + Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0` + "0x0.8000000000000000000000000000p-16382" + ); + assert_eq!( + Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON` + "0x0.0000000000000000000000000001p-16382" + ); + assert_eq!( + Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY` + "+Inf" + ); + assert_eq!( + Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY` + "-Inf" + ); + assert_eq!( + Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN` + "+NaN" + ); + assert_eq!( + Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN` + "-NaN" + ); + // Construct some qNaNs with payloads. + assert_eq!( + Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(), + "+NaN:0x1" + ); + assert_eq!( + Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(), + "+NaN:0x4000000000000000000000000001" + ); + // Signaling NaNs. + assert_eq!( + Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(), + "+sNaN:0x1" + ); + assert_eq!( + Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(), + "+sNaN:0x4000000000000000000000000001" + ); + } + + #[test] + fn parse_ieee128() { + parse_ok::("0.0", "0.0"); + parse_ok::("-0.0", "-0.0"); + parse_ok::("0x0", "0.0"); + parse_ok::("0x0.0", "0.0"); + parse_ok::("0x.0", "0.0"); + parse_ok::("0x0.", "0.0"); + parse_ok::("0x1", "0x1.0000000000000000000000000000p0"); + parse_ok::("-0x1", "-0x1.0000000000000000000000000000p0"); + parse_ok::("0x10", "0x1.0000000000000000000000000000p4"); + parse_ok::("0x10.0", "0x1.0000000000000000000000000000p4"); + parse_err::("0.", "Float must be hexadecimal"); + parse_err::(".0", "Float must be hexadecimal"); + parse_err::("0", "Float must be hexadecimal"); + parse_err::("-0", "Float must be hexadecimal"); + parse_err::(".", "Float must be hexadecimal"); + parse_err::("", "Float must be hexadecimal"); + parse_err::("-", "Float must be hexadecimal"); + parse_err::("0x", "No digits"); + parse_err::("0x..", "Multiple radix points"); + + // Check significant bits. + parse_ok::( + "0x0.ffffffffffffffffffffffffffff8", + "0x1.ffffffffffffffffffffffffffffp-1", + ); + parse_ok::( + "0x1.ffffffffffffffffffffffffffff", + "0x1.ffffffffffffffffffffffffffffp0", + ); + parse_ok::( + "0x3.fffffffffffffffffffffffffffe", + "0x1.ffffffffffffffffffffffffffffp1", + ); + parse_ok::( + "0x7.fffffffffffffffffffffffffffc", + "0x1.ffffffffffffffffffffffffffffp2", + ); + parse_ok::( + "0xf.fffffffffffffffffffffffffff8", + "0x1.ffffffffffffffffffffffffffffp3", + ); + parse_err::( + "0x3.ffffffffffffffffffffffffffff", + "Too many significant bits", + ); + parse_err::("0x001.fffffe000000000000000000000000", "Too many digits"); + + // Exponents. + parse_ok::("0x1p3", "0x1.0000000000000000000000000000p3"); + parse_ok::("0x1p-3", "0x1.0000000000000000000000000000p-3"); + parse_ok::("0x1.0p3", "0x1.0000000000000000000000000000p3"); + parse_ok::("0x2.0p3", "0x1.0000000000000000000000000000p4"); + parse_ok::("0x1.0p16383", "0x1.0000000000000000000000000000p16383"); + parse_ok::("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382"); + parse_ok::("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382"); + parse_err::("0x2.0p16383", "Magnitude too large"); + + // Subnormals. + parse_ok::("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382"); + parse_ok::("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382"); + parse_ok::( + "0x0.0000000000000000000000000001p-16382", + "0x0.0000000000000000000000000001p-16382", + ); + parse_err::( + "0x0.10000000000000000000000000008p-16382", + "Subnormal underflow", + ); + parse_err::("0x1.8p-16494", "Subnormal underflow"); + parse_err::("0x1.0p-16495", "Magnitude too small"); + + // NaNs and Infs. + parse_ok::("Inf", "+Inf"); + parse_ok::("-Inf", "-Inf"); + parse_ok::("NaN", "+NaN"); + parse_ok::("-NaN", "-NaN"); + parse_ok::("NaN:0x0", "+NaN"); + parse_err::("NaN:", "Float must be hexadecimal"); + parse_err::("NaN:0", "Float must be hexadecimal"); + parse_err::("NaN:0x", "Invalid NaN payload"); + parse_ok::("NaN:0x000001", "+NaN:0x1"); + parse_ok::( + "NaN:0x4000000000000000000000000001", + "+NaN:0x4000000000000000000000000001", + ); + parse_err::("NaN:0x8000000000000000000000000001", "Invalid NaN payload"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); + parse_err::("sNaN:0x0", "Invalid sNaN payload"); + parse_ok::( + "sNaN:0x4000000000000000000000000001", + "+sNaN:0x4000000000000000000000000001", + ); + parse_err::( + "sNaN:0x8000000000000000000000000001", + "Invalid sNaN payload", + ); + } + + #[test] + fn pow2_ieee128() { + assert_eq!( + Ieee128::pow2(0).to_string(), + "0x1.0000000000000000000000000000p0" + ); + assert_eq!( + Ieee128::pow2(1).to_string(), + "0x1.0000000000000000000000000000p1" + ); + assert_eq!( + Ieee128::pow2(-1).to_string(), + "0x1.0000000000000000000000000000p-1" + ); + assert_eq!( + Ieee128::pow2(16383).to_string(), + "0x1.0000000000000000000000000000p16383" + ); + assert_eq!( + Ieee128::pow2(-16382).to_string(), + "0x1.0000000000000000000000000000p-16382" + ); + + assert_eq!( + (-Ieee128::pow2(1)).to_string(), + "-0x1.0000000000000000000000000000p1" + ); + } + + #[test] + fn fcvt_to_sint_negative_overflow_ieee128() { + // FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised. + // for n in [8, 16, 32, 64] { + // assert_eq!( + // -((1u128 << (n - 1)) as f128) - 1.0, + // Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(), + // "n = {n}" + // ); + // } + for (n, expected) in [ + (8, "-0x1.0200000000000000000000000000p7"), + (16, "-0x1.0002000000000000000000000000p15"), + (32, "-0x1.0000000200000000000000000000p31"), + (64, "-0x1.0000000000000002000000000000p63"), + ] { + assert_eq!( + expected, + Ieee128::fcvt_to_sint_negative_overflow(n).to_string(), + "n = {n}" + ); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/instructions.rs b/deps/crates/vendor/cranelift-codegen/src/ir/instructions.rs new file mode 100644 index 00000000000000..f885083cc1bb39 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/instructions.rs @@ -0,0 +1,1021 @@ +//! Instruction formats and opcodes. +//! +//! The `instructions` module contains definitions for instruction formats, opcodes, and the +//! in-memory representation of IR instructions. +//! +//! A large part of this module is auto-generated from the instruction descriptions in the meta +//! directory. + +use crate::constant_hash::Table; +use alloc::vec::Vec; +use core::fmt::{self, Display, Formatter}; +use core::ops::{Deref, DerefMut}; +use core::str::FromStr; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +use crate::bitset::ScalarBitSet; +use crate::entity; +use crate::ir::{ + self, + condcodes::{FloatCC, IntCC}, + trapcode::TrapCode, + types, Block, FuncRef, MemFlags, SigRef, StackSlot, Type, Value, +}; + +/// Some instructions use an external list of argument values because there is not enough space in +/// the 16-byte `InstructionData` struct. These value lists are stored in a memory pool in +/// `dfg.value_lists`. +pub type ValueList = entity::EntityList; + +/// Memory pool for holding value lists. See `ValueList`. +pub type ValueListPool = entity::ListPool; + +/// A pair of a Block and its arguments, stored in a single EntityList internally. +/// +/// NOTE: We don't expose either value_to_block or block_to_value outside of this module because +/// this operation is not generally safe. However, as the two share the same underlying layout, +/// they can be stored in the same value pool. +/// +/// BlockCall makes use of this shared layout by storing all of its contents (a block and its +/// argument) in a single EntityList. This is a bit better than introducing a new entity type for +/// the pair of a block name and the arguments entity list, as we don't pay any indirection penalty +/// to get to the argument values -- they're stored in-line with the block in the same list. +/// +/// The BlockCall::new function guarantees this layout by requiring a block argument that's written +/// in as the first element of the EntityList. Any subsequent entries are always assumed to be real +/// Values. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct BlockCall { + /// The underlying storage for the BlockCall. The first element of the values EntityList is + /// guaranteed to always be a Block encoded as a Value via BlockCall::block_to_value. + /// Consequently, the values entity list is never empty. + values: entity::EntityList, +} + +impl BlockCall { + // NOTE: the only uses of this function should be internal to BlockCall. See the block comment + // on BlockCall for more context. + fn value_to_block(val: Value) -> Block { + Block::from_u32(val.as_u32()) + } + + // NOTE: the only uses of this function should be internal to BlockCall. See the block comment + // on BlockCall for more context. + fn block_to_value(block: Block) -> Value { + Value::from_u32(block.as_u32()) + } + + /// Construct a BlockCall with the given block and arguments. + pub fn new(block: Block, args: &[Value], pool: &mut ValueListPool) -> Self { + let mut values = ValueList::default(); + values.push(Self::block_to_value(block), pool); + values.extend(args.iter().copied(), pool); + Self { values } + } + + /// Return the block for this BlockCall. + pub fn block(&self, pool: &ValueListPool) -> Block { + let val = self.values.first(pool).unwrap(); + Self::value_to_block(val) + } + + /// Replace the block for this BlockCall. + pub fn set_block(&mut self, block: Block, pool: &mut ValueListPool) { + *self.values.get_mut(0, pool).unwrap() = Self::block_to_value(block); + } + + /// Append an argument to the block args. + pub fn append_argument(&mut self, arg: Value, pool: &mut ValueListPool) { + self.values.push(arg, pool); + } + + /// Return a slice for the arguments of this block. + pub fn args_slice<'a>(&self, pool: &'a ValueListPool) -> &'a [Value] { + &self.values.as_slice(pool)[1..] + } + + /// Return a slice for the arguments of this block. + pub fn args_slice_mut<'a>(&'a mut self, pool: &'a mut ValueListPool) -> &'a mut [Value] { + &mut self.values.as_mut_slice(pool)[1..] + } + + /// Remove the argument at ix from the argument list. + pub fn remove(&mut self, ix: usize, pool: &mut ValueListPool) { + self.values.remove(1 + ix, pool) + } + + /// Clear out the arguments list. + pub fn clear(&mut self, pool: &mut ValueListPool) { + self.values.truncate(1, pool) + } + + /// Appends multiple elements to the arguments. + pub fn extend(&mut self, elements: I, pool: &mut ValueListPool) + where + I: IntoIterator, + { + self.values.extend(elements, pool) + } + + /// Return a value that can display this block call. + pub fn display<'a>(&self, pool: &'a ValueListPool) -> DisplayBlockCall<'a> { + DisplayBlockCall { block: *self, pool } + } + + /// Deep-clone the underlying list in the same pool. The returned + /// list will have identical contents but changes to this list + /// will not change its contents or vice-versa. + pub fn deep_clone(&self, pool: &mut ValueListPool) -> Self { + Self { + values: self.values.deep_clone(pool), + } + } +} + +/// Wrapper for the context needed to display a [BlockCall] value. +pub struct DisplayBlockCall<'a> { + block: BlockCall, + pool: &'a ValueListPool, +} + +impl<'a> Display for DisplayBlockCall<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.block.block(&self.pool))?; + let args = self.block.args_slice(&self.pool); + if !args.is_empty() { + write!(f, "(")?; + for (ix, arg) in args.iter().enumerate() { + if ix > 0 { + write!(f, ", ")?; + } + write!(f, "{arg}")?; + } + write!(f, ")")?; + } + Ok(()) + } +} + +// Include code generated by `cranelift-codegen/meta/src/gen_inst.rs`. This file contains: +// +// - The `pub enum InstructionFormat` enum with all the instruction formats. +// - The `pub enum InstructionData` enum with all the instruction data fields. +// - The `pub enum Opcode` definition with all known opcodes, +// - The `const OPCODE_FORMAT: [InstructionFormat; N]` table. +// - The private `fn opcode_name(Opcode) -> &'static str` function, and +// - The hash table `const OPCODE_HASH_TABLE: [Opcode; N]`. +// +// For value type constraints: +// +// - The `const OPCODE_CONSTRAINTS : [OpcodeConstraints; N]` table. +// - The `const TYPE_SETS : [ValueTypeSet; N]` table. +// - The `const OPERAND_CONSTRAINTS : [OperandConstraint; N]` table. +// +include!(concat!(env!("OUT_DIR"), "/opcodes.rs")); + +impl Display for Opcode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", opcode_name(*self)) + } +} + +impl Opcode { + /// Get the instruction format for this opcode. + pub fn format(self) -> InstructionFormat { + OPCODE_FORMAT[self as usize - 1] + } + + /// Get the constraint descriptor for this opcode. + /// Panic if this is called on `NotAnOpcode`. + pub fn constraints(self) -> OpcodeConstraints { + OPCODE_CONSTRAINTS[self as usize - 1] + } + + /// Is this instruction a GC safepoint? + /// + /// Safepoints are all kinds of calls, except for tail calls. + #[inline] + pub fn is_safepoint(self) -> bool { + self.is_call() && !self.is_return() + } +} + +// This trait really belongs in cranelift-reader where it is used by the `.clif` file parser, but since +// it critically depends on the `opcode_name()` function which is needed here anyway, it lives in +// this module. This also saves us from running the build script twice to generate code for the two +// separate crates. +impl FromStr for Opcode { + type Err = &'static str; + + /// Parse an Opcode name from a string. + fn from_str(s: &str) -> Result { + use crate::constant_hash::{probe, simple_hash}; + + match probe::<&str, [Option]>(&OPCODE_HASH_TABLE, s, simple_hash(s)) { + Err(_) => Err("Unknown opcode"), + // We unwrap here because probe() should have ensured that the entry + // at this index is not None. + Ok(i) => Ok(OPCODE_HASH_TABLE[i].unwrap()), + } + } +} + +impl<'a> Table<&'a str> for [Option] { + fn len(&self) -> usize { + self.len() + } + + fn key(&self, idx: usize) -> Option<&'a str> { + self[idx].map(opcode_name) + } +} + +/// A variable list of `Value` operands used for function call arguments and passing arguments to +/// basic blocks. +#[derive(Clone, Debug)] +pub struct VariableArgs(Vec); + +impl VariableArgs { + /// Create an empty argument list. + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Add an argument to the end. + pub fn push(&mut self, v: Value) { + self.0.push(v) + } + + /// Check if the list is empty. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Convert this to a value list in `pool` with `fixed` prepended. + pub fn into_value_list(self, fixed: &[Value], pool: &mut ValueListPool) -> ValueList { + let mut vlist = ValueList::default(); + vlist.extend(fixed.iter().cloned(), pool); + vlist.extend(self.0, pool); + vlist + } +} + +// Coerce `VariableArgs` into a `&[Value]` slice. +impl Deref for VariableArgs { + type Target = [Value]; + + fn deref(&self) -> &[Value] { + &self.0 + } +} + +impl DerefMut for VariableArgs { + fn deref_mut(&mut self) -> &mut [Value] { + &mut self.0 + } +} + +impl Display for VariableArgs { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + for (i, val) in self.0.iter().enumerate() { + if i == 0 { + write!(fmt, "{val}")?; + } else { + write!(fmt, ", {val}")?; + } + } + Ok(()) + } +} + +impl Default for VariableArgs { + fn default() -> Self { + Self::new() + } +} + +/// Analyzing an instruction. +/// +/// Avoid large matches on instruction formats by using the methods defined here to examine +/// instructions. +impl InstructionData { + /// Get the destinations of this instruction, if it's a branch. + /// + /// `br_table` returns the empty slice. + pub fn branch_destination<'a>(&'a self, jump_tables: &'a ir::JumpTables) -> &'a [BlockCall] { + match self { + Self::Jump { + ref destination, .. + } => std::slice::from_ref(destination), + Self::Brif { blocks, .. } => blocks.as_slice(), + Self::BranchTable { table, .. } => jump_tables.get(*table).unwrap().all_branches(), + _ => { + debug_assert!(!self.opcode().is_branch()); + &[] + } + } + } + + /// Get a mutable slice of the destinations of this instruction, if it's a branch. + /// + /// `br_table` returns the empty slice. + pub fn branch_destination_mut<'a>( + &'a mut self, + jump_tables: &'a mut ir::JumpTables, + ) -> &'a mut [BlockCall] { + match self { + Self::Jump { + ref mut destination, + .. + } => std::slice::from_mut(destination), + Self::Brif { blocks, .. } => blocks.as_mut_slice(), + Self::BranchTable { table, .. } => { + jump_tables.get_mut(*table).unwrap().all_branches_mut() + } + _ => { + debug_assert!(!self.opcode().is_branch()); + &mut [] + } + } + } + + /// Replace the values used in this instruction according to the given + /// function. + pub fn map_values( + &mut self, + pool: &mut ValueListPool, + jump_tables: &mut ir::JumpTables, + mut f: impl FnMut(Value) -> Value, + ) { + for arg in self.arguments_mut(pool) { + *arg = f(*arg); + } + + for block in self.branch_destination_mut(jump_tables) { + for arg in block.args_slice_mut(pool) { + *arg = f(*arg); + } + } + } + + /// If this is a trapping instruction, get its trap code. Otherwise, return + /// `None`. + pub fn trap_code(&self) -> Option { + match *self { + Self::CondTrap { code, .. } | Self::Trap { code, .. } => Some(code), + _ => None, + } + } + + /// If this is a control-flow instruction depending on an integer condition, gets its + /// condition. Otherwise, return `None`. + pub fn cond_code(&self) -> Option { + match self { + &InstructionData::IntCompare { cond, .. } + | &InstructionData::IntCompareImm { cond, .. } => Some(cond), + _ => None, + } + } + + /// If this is a control-flow instruction depending on a floating-point condition, gets its + /// condition. Otherwise, return `None`. + pub fn fp_cond_code(&self) -> Option { + match self { + &InstructionData::FloatCompare { cond, .. } => Some(cond), + _ => None, + } + } + + /// If this is a trapping instruction, get an exclusive reference to its + /// trap code. Otherwise, return `None`. + pub fn trap_code_mut(&mut self) -> Option<&mut TrapCode> { + match self { + Self::CondTrap { code, .. } | Self::Trap { code, .. } => Some(code), + _ => None, + } + } + + /// If this is an atomic read/modify/write instruction, return its subopcode. + pub fn atomic_rmw_op(&self) -> Option { + match self { + &InstructionData::AtomicRmw { op, .. } => Some(op), + _ => None, + } + } + + /// If this is a load/store instruction, returns its immediate offset. + pub fn load_store_offset(&self) -> Option { + match self { + &InstructionData::Load { offset, .. } + | &InstructionData::StackLoad { offset, .. } + | &InstructionData::Store { offset, .. } + | &InstructionData::StackStore { offset, .. } => Some(offset.into()), + _ => None, + } + } + + /// If this is a load/store instruction, return its memory flags. + pub fn memflags(&self) -> Option { + match self { + &InstructionData::Load { flags, .. } + | &InstructionData::LoadNoOffset { flags, .. } + | &InstructionData::Store { flags, .. } + | &InstructionData::StoreNoOffset { flags, .. } + | &InstructionData::AtomicCas { flags, .. } + | &InstructionData::AtomicRmw { flags, .. } => Some(flags), + _ => None, + } + } + + /// If this instruction references a stack slot, return it + pub fn stack_slot(&self) -> Option { + match self { + &InstructionData::StackStore { stack_slot, .. } + | &InstructionData::StackLoad { stack_slot, .. } => Some(stack_slot), + _ => None, + } + } + + /// Return information about a call instruction. + /// + /// Any instruction that can call another function reveals its call signature here. + pub fn analyze_call<'a>(&'a self, pool: &'a ValueListPool) -> CallInfo<'a> { + match *self { + Self::Call { + func_ref, ref args, .. + } => CallInfo::Direct(func_ref, args.as_slice(pool)), + Self::CallIndirect { + sig_ref, ref args, .. + } => CallInfo::Indirect(sig_ref, &args.as_slice(pool)[1..]), + Self::Ternary { + opcode: Opcode::StackSwitch, + .. + } => { + // `StackSwitch` is not actually a call, but has the .call() side + // effect as it continues execution elsewhere. + CallInfo::NotACall + } + _ => { + debug_assert!(!self.opcode().is_call()); + CallInfo::NotACall + } + } + } + + #[inline] + pub(crate) fn mask_immediates(&mut self, ctrl_typevar: Type) { + if ctrl_typevar.is_invalid() { + return; + } + + let bit_width = ctrl_typevar.bits(); + + match self { + Self::UnaryImm { opcode: _, imm } => { + *imm = imm.mask_to_width(bit_width); + } + Self::BinaryImm64 { + opcode, + arg: _, + imm, + } => { + if *opcode == Opcode::SdivImm || *opcode == Opcode::SremImm { + *imm = imm.mask_to_width(bit_width); + } + } + Self::IntCompareImm { + opcode, + arg: _, + cond, + imm, + } => { + debug_assert_eq!(*opcode, Opcode::IcmpImm); + if cond.unsigned() != *cond { + *imm = imm.mask_to_width(bit_width); + } + } + _ => {} + } + } +} + +/// Information about call instructions. +pub enum CallInfo<'a> { + /// This is not a call instruction. + NotACall, + + /// This is a direct call to an external function declared in the preamble. See + /// `DataFlowGraph.ext_funcs`. + Direct(FuncRef, &'a [Value]), + + /// This is an indirect call with the specified signature. See `DataFlowGraph.signatures`. + Indirect(SigRef, &'a [Value]), +} + +/// Value type constraints for a given opcode. +/// +/// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and +/// results are not determined by the format. Every `Opcode` has an associated +/// `OpcodeConstraints` object that provides the missing details. +#[derive(Clone, Copy)] +pub struct OpcodeConstraints { + /// Flags for this opcode encoded as a bit field: + /// + /// Bits 0-2: + /// Number of fixed result values. This does not include `variable_args` results as are + /// produced by call instructions. + /// + /// Bit 3: + /// This opcode is polymorphic and the controlling type variable can be inferred from the + /// designated input operand. This is the `typevar_operand` index given to the + /// `InstructionFormat` meta language object. When this bit is not set, the controlling + /// type variable must be the first output value instead. + /// + /// Bit 4: + /// This opcode is polymorphic and the controlling type variable does *not* appear as the + /// first result type. + /// + /// Bits 5-7: + /// Number of fixed value arguments. The minimum required number of value operands. + flags: u8, + + /// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`. + typeset_offset: u8, + + /// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first + /// `num_fixed_results()` entries describe the result constraints, then follows constraints for + /// the fixed `Value` input operands. (`num_fixed_value_arguments()` of them). + constraint_offset: u16, +} + +impl OpcodeConstraints { + /// Can the controlling type variable for this opcode be inferred from the designated value + /// input operand? + /// This also implies that this opcode is polymorphic. + pub fn use_typevar_operand(self) -> bool { + (self.flags & 0x8) != 0 + } + + /// Is it necessary to look at the designated value input operand in order to determine the + /// controlling type variable, or is it good enough to use the first return type? + /// + /// Most polymorphic instructions produce a single result with the type of the controlling type + /// variable. A few polymorphic instructions either don't produce any results, or produce + /// results with a fixed type. These instructions return `true`. + pub fn requires_typevar_operand(self) -> bool { + (self.flags & 0x10) != 0 + } + + /// Get the number of *fixed* result values produced by this opcode. + /// This does not include `variable_args` produced by calls. + pub fn num_fixed_results(self) -> usize { + (self.flags & 0x7) as usize + } + + /// Get the number of *fixed* input values required by this opcode. + /// + /// This does not include `variable_args` arguments on call and branch instructions. + /// + /// The number of fixed input values is usually implied by the instruction format, but + /// instruction formats that use a `ValueList` put both fixed and variable arguments in the + /// list. This method returns the *minimum* number of values required in the value list. + pub fn num_fixed_value_arguments(self) -> usize { + ((self.flags >> 5) & 0x7) as usize + } + + /// Get the offset into `TYPE_SETS` for the controlling type variable. + /// Returns `None` if the instruction is not polymorphic. + fn typeset_offset(self) -> Option { + let offset = usize::from(self.typeset_offset); + if offset < TYPE_SETS.len() { + Some(offset) + } else { + None + } + } + + /// Get the offset into OPERAND_CONSTRAINTS where the descriptors for this opcode begin. + fn constraint_offset(self) -> usize { + self.constraint_offset as usize + } + + /// Get the value type of result number `n`, having resolved the controlling type variable to + /// `ctrl_type`. + pub fn result_type(self, n: usize, ctrl_type: Type) -> Type { + debug_assert!(n < self.num_fixed_results(), "Invalid result index"); + match OPERAND_CONSTRAINTS[self.constraint_offset() + n].resolve(ctrl_type) { + ResolvedConstraint::Bound(t) => t, + ResolvedConstraint::Free(ts) => panic!("Result constraints can't be free: {ts:?}"), + } + } + + /// Get the value type of input value number `n`, having resolved the controlling type variable + /// to `ctrl_type`. + /// + /// Unlike results, it is possible for some input values to vary freely within a specific + /// `ValueTypeSet`. This is represented with the `ArgumentConstraint::Free` variant. + pub fn value_argument_constraint(self, n: usize, ctrl_type: Type) -> ResolvedConstraint { + debug_assert!( + n < self.num_fixed_value_arguments(), + "Invalid value argument index" + ); + let offset = self.constraint_offset() + self.num_fixed_results(); + OPERAND_CONSTRAINTS[offset + n].resolve(ctrl_type) + } + + /// Get the typeset of allowed types for the controlling type variable in a polymorphic + /// instruction. + pub fn ctrl_typeset(self) -> Option { + self.typeset_offset().map(|offset| TYPE_SETS[offset]) + } + + /// Is this instruction polymorphic? + pub fn is_polymorphic(self) -> bool { + self.ctrl_typeset().is_some() + } +} + +type BitSet8 = ScalarBitSet; +type BitSet16 = ScalarBitSet; + +/// A value type set describes the permitted set of types for a type variable. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct ValueTypeSet { + /// Allowed lane sizes + pub lanes: BitSet16, + /// Allowed int widths + pub ints: BitSet8, + /// Allowed float widths + pub floats: BitSet8, + /// Allowed dynamic vectors minimum lane sizes + pub dynamic_lanes: BitSet16, +} + +impl ValueTypeSet { + /// Is `scalar` part of the base type set? + /// + /// Note that the base type set does not have to be included in the type set proper. + fn is_base_type(self, scalar: Type) -> bool { + let l2b = u8::try_from(scalar.log2_lane_bits()).unwrap(); + if scalar.is_int() { + self.ints.contains(l2b) + } else if scalar.is_float() { + self.floats.contains(l2b) + } else { + false + } + } + + /// Does `typ` belong to this set? + pub fn contains(self, typ: Type) -> bool { + if typ.is_dynamic_vector() { + let l2l = u8::try_from(typ.log2_min_lane_count()).unwrap(); + self.dynamic_lanes.contains(l2l) && self.is_base_type(typ.lane_type()) + } else { + let l2l = u8::try_from(typ.log2_lane_count()).unwrap(); + self.lanes.contains(l2l) && self.is_base_type(typ.lane_type()) + } + } + + /// Get an example member of this type set. + /// + /// This is used for error messages to avoid suggesting invalid types. + pub fn example(self) -> Type { + let t = if self.ints.max().unwrap_or(0) > 5 { + types::I32 + } else if self.floats.max().unwrap_or(0) > 5 { + types::F32 + } else { + types::I8 + }; + t.by(1 << self.lanes.min().unwrap()).unwrap() + } +} + +/// Operand constraints. This describes the value type constraints on a single `Value` operand. +enum OperandConstraint { + /// This operand has a concrete value type. + Concrete(Type), + + /// This operand can vary freely within the given type set. + /// The type set is identified by its index into the TYPE_SETS constant table. + Free(u8), + + /// This operand is the same type as the controlling type variable. + Same, + + /// This operand is `ctrlType.lane_of()`. + LaneOf, + + /// This operand is `ctrlType.as_truthy()`. + AsTruthy, + + /// This operand is `ctrlType.half_width()`. + HalfWidth, + + /// This operand is `ctrlType.double_width()`. + DoubleWidth, + + /// This operand is `ctrlType.split_lanes()`. + SplitLanes, + + /// This operand is `ctrlType.merge_lanes()`. + MergeLanes, + + /// This operands is `ctrlType.dynamic_to_vector()`. + DynamicToVector, + + /// This operand is `ctrlType.narrower()`. + Narrower, + + /// This operand is `ctrlType.wider()`. + Wider, +} + +impl OperandConstraint { + /// Resolve this operand constraint into a concrete value type, given the value of the + /// controlling type variable. + pub fn resolve(&self, ctrl_type: Type) -> ResolvedConstraint { + use self::OperandConstraint::*; + use self::ResolvedConstraint::Bound; + match *self { + Concrete(t) => Bound(t), + Free(vts) => ResolvedConstraint::Free(TYPE_SETS[vts as usize]), + Same => Bound(ctrl_type), + LaneOf => Bound(ctrl_type.lane_of()), + AsTruthy => Bound(ctrl_type.as_truthy()), + HalfWidth => Bound(ctrl_type.half_width().expect("invalid type for half_width")), + DoubleWidth => Bound( + ctrl_type + .double_width() + .expect("invalid type for double_width"), + ), + SplitLanes => { + if ctrl_type.is_dynamic_vector() { + Bound( + ctrl_type + .dynamic_to_vector() + .expect("invalid type for dynamic_to_vector") + .split_lanes() + .expect("invalid type for split_lanes") + .vector_to_dynamic() + .expect("invalid dynamic type"), + ) + } else { + Bound( + ctrl_type + .split_lanes() + .expect("invalid type for split_lanes"), + ) + } + } + MergeLanes => { + if ctrl_type.is_dynamic_vector() { + Bound( + ctrl_type + .dynamic_to_vector() + .expect("invalid type for dynamic_to_vector") + .merge_lanes() + .expect("invalid type for merge_lanes") + .vector_to_dynamic() + .expect("invalid dynamic type"), + ) + } else { + Bound( + ctrl_type + .merge_lanes() + .expect("invalid type for merge_lanes"), + ) + } + } + DynamicToVector => Bound( + ctrl_type + .dynamic_to_vector() + .expect("invalid type for dynamic_to_vector"), + ), + Narrower => { + let ctrl_type_bits = ctrl_type.log2_lane_bits(); + let mut tys = ValueTypeSet::default(); + + // We're testing scalar values, only. + tys.lanes = ScalarBitSet::from_range(0, 1); + + if ctrl_type.is_int() { + // The upper bound in from_range is exclusive, and we want to exclude the + // control type to construct the interval of [I8, ctrl_type). + tys.ints = BitSet8::from_range(3, ctrl_type_bits as u8); + } else if ctrl_type.is_float() { + // The upper bound in from_range is exclusive, and we want to exclude the + // control type to construct the interval of [F16, ctrl_type). + tys.floats = BitSet8::from_range(4, ctrl_type_bits as u8); + } else { + panic!("The Narrower constraint only operates on floats or ints"); + } + ResolvedConstraint::Free(tys) + } + Wider => { + let ctrl_type_bits = ctrl_type.log2_lane_bits(); + let mut tys = ValueTypeSet::default(); + + // We're testing scalar values, only. + tys.lanes = ScalarBitSet::from_range(0, 1); + + if ctrl_type.is_int() { + let lower_bound = ctrl_type_bits as u8 + 1; + // The largest integer type we can represent in `BitSet8` is I128, which is + // represented by bit 7 in the bit set. Adding one to exclude I128 from the + // lower bound would overflow as 2^8 doesn't fit in a u8, but this would + // already describe the empty set so instead we leave `ints` in its default + // empty state. + if lower_bound < BitSet8::capacity() { + // The interval should include all types wider than `ctrl_type`, so we use + // `2^8` as the upper bound, and add one to the bits of `ctrl_type` to define + // the interval `(ctrl_type, I128]`. + tys.ints = BitSet8::from_range(lower_bound, 8); + } + } else if ctrl_type.is_float() { + // Same as above but for `tys.floats`, as the largest float type is F128. + let lower_bound = ctrl_type_bits as u8 + 1; + if lower_bound < BitSet8::capacity() { + tys.floats = BitSet8::from_range(lower_bound, 8); + } + } else { + panic!("The Wider constraint only operates on floats or ints"); + } + + ResolvedConstraint::Free(tys) + } + } + } +} + +/// The type constraint on a value argument once the controlling type variable is known. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ResolvedConstraint { + /// The operand is bound to a known type. + Bound(Type), + /// The operand type can vary freely within the given set. + Free(ValueTypeSet), +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn inst_data_is_copy() { + fn is_copy() {} + is_copy::(); + } + + #[test] + fn inst_data_size() { + // The size of `InstructionData` is performance sensitive, so make sure + // we don't regress it unintentionally. + assert_eq!(std::mem::size_of::(), 16); + } + + #[test] + fn opcodes() { + use core::mem; + + let x = Opcode::Iadd; + let mut y = Opcode::Isub; + + assert!(x != y); + y = Opcode::Iadd; + assert_eq!(x, y); + assert_eq!(x.format(), InstructionFormat::Binary); + + assert_eq!(format!("{:?}", Opcode::IaddImm), "IaddImm"); + assert_eq!(Opcode::IaddImm.to_string(), "iadd_imm"); + + // Check the matcher. + assert_eq!("iadd".parse::(), Ok(Opcode::Iadd)); + assert_eq!("iadd_imm".parse::(), Ok(Opcode::IaddImm)); + assert_eq!("iadd\0".parse::(), Err("Unknown opcode")); + assert_eq!("".parse::(), Err("Unknown opcode")); + assert_eq!("\0".parse::(), Err("Unknown opcode")); + + // Opcode is a single byte, and because Option originally came to 2 bytes, early on + // Opcode included a variant NotAnOpcode to avoid the unnecessary bloat. Since then the Rust + // compiler has brought in NonZero optimization, meaning that an enum not using the 0 value + // can be optional for no size cost. We want to ensure Option remains small. + assert_eq!(mem::size_of::(), mem::size_of::>()); + } + + #[test] + fn instruction_data() { + use core::mem; + // The size of the `InstructionData` enum is important for performance. It should not + // exceed 16 bytes. Use `Box` out-of-line payloads for instruction formats that + // require more space than that. It would be fine with a data structure smaller than 16 + // bytes, but what are the odds of that? + assert_eq!(mem::size_of::(), 16); + } + + #[test] + fn constraints() { + let a = Opcode::Iadd.constraints(); + assert!(a.use_typevar_operand()); + assert!(!a.requires_typevar_operand()); + assert_eq!(a.num_fixed_results(), 1); + assert_eq!(a.num_fixed_value_arguments(), 2); + assert_eq!(a.result_type(0, types::I32), types::I32); + assert_eq!(a.result_type(0, types::I8), types::I8); + assert_eq!( + a.value_argument_constraint(0, types::I32), + ResolvedConstraint::Bound(types::I32) + ); + assert_eq!( + a.value_argument_constraint(1, types::I32), + ResolvedConstraint::Bound(types::I32) + ); + + let b = Opcode::Bitcast.constraints(); + assert!(!b.use_typevar_operand()); + assert!(!b.requires_typevar_operand()); + assert_eq!(b.num_fixed_results(), 1); + assert_eq!(b.num_fixed_value_arguments(), 1); + assert_eq!(b.result_type(0, types::I32), types::I32); + assert_eq!(b.result_type(0, types::I8), types::I8); + match b.value_argument_constraint(0, types::I32) { + ResolvedConstraint::Free(vts) => assert!(vts.contains(types::F32)), + _ => panic!("Unexpected constraint from value_argument_constraint"), + } + + let c = Opcode::Call.constraints(); + assert_eq!(c.num_fixed_results(), 0); + assert_eq!(c.num_fixed_value_arguments(), 0); + + let i = Opcode::CallIndirect.constraints(); + assert_eq!(i.num_fixed_results(), 0); + assert_eq!(i.num_fixed_value_arguments(), 1); + + let cmp = Opcode::Icmp.constraints(); + assert!(cmp.use_typevar_operand()); + assert!(cmp.requires_typevar_operand()); + assert_eq!(cmp.num_fixed_results(), 1); + assert_eq!(cmp.num_fixed_value_arguments(), 2); + assert_eq!(cmp.result_type(0, types::I64), types::I8); + } + + #[test] + fn value_set() { + use crate::ir::types::*; + + let vts = ValueTypeSet { + lanes: BitSet16::from_range(0, 8), + ints: BitSet8::from_range(4, 7), + floats: BitSet8::from_range(0, 0), + dynamic_lanes: BitSet16::from_range(0, 4), + }; + assert!(!vts.contains(I8)); + assert!(vts.contains(I32)); + assert!(vts.contains(I64)); + assert!(vts.contains(I32X4)); + assert!(vts.contains(I32X4XN)); + assert!(!vts.contains(F16)); + assert!(!vts.contains(F32)); + assert!(!vts.contains(F128)); + assert_eq!(vts.example().to_string(), "i32"); + + let vts = ValueTypeSet { + lanes: BitSet16::from_range(0, 8), + ints: BitSet8::from_range(0, 0), + floats: BitSet8::from_range(5, 7), + dynamic_lanes: BitSet16::from_range(0, 8), + }; + assert_eq!(vts.example().to_string(), "f32"); + + let vts = ValueTypeSet { + lanes: BitSet16::from_range(1, 8), + ints: BitSet8::from_range(0, 0), + floats: BitSet8::from_range(5, 7), + dynamic_lanes: BitSet16::from_range(0, 8), + }; + assert_eq!(vts.example().to_string(), "f32x2"); + + let vts = ValueTypeSet { + lanes: BitSet16::from_range(2, 8), + ints: BitSet8::from_range(3, 7), + floats: BitSet8::from_range(0, 0), + dynamic_lanes: BitSet16::from_range(0, 8), + }; + assert_eq!(vts.example().to_string(), "i32x4"); + + let vts = ValueTypeSet { + // TypeSet(lanes=(1, 256), ints=(8, 64)) + lanes: BitSet16::from_range(0, 9), + ints: BitSet8::from_range(3, 7), + floats: BitSet8::from_range(0, 0), + dynamic_lanes: BitSet16::from_range(0, 8), + }; + assert!(vts.contains(I32)); + assert!(vts.contains(I32X4)); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/jumptable.rs b/deps/crates/vendor/cranelift-codegen/src/ir/jumptable.rs new file mode 100644 index 00000000000000..8e1e15c7d62114 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/jumptable.rs @@ -0,0 +1,168 @@ +//! Jump table representation. +//! +//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference. +//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module. + +use crate::ir::instructions::ValueListPool; +use crate::ir::BlockCall; +use alloc::vec::Vec; +use core::fmt::{self, Display, Formatter}; +use core::slice::{Iter, IterMut}; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Contents of a jump table. +/// +/// All jump tables use 0-based indexing and are densely populated. +/// +/// The default block for the jump table is stored as the first element of the underlying vector. +/// It can be accessed through the `default_block` and `default_block_mut` functions. All blocks +/// may be iterated using the `all_branches` and `all_branches_mut` functions, which will both +/// iterate over the default block first. +#[derive(Debug, Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct JumpTableData { + // Table entries. + table: Vec, +} + +impl JumpTableData { + /// Create a new jump table with the provided blocks. + pub fn new(def: BlockCall, table: &[BlockCall]) -> Self { + Self { + table: std::iter::once(def).chain(table.iter().copied()).collect(), + } + } + + /// Fetch the default block for this jump table. + pub fn default_block(&self) -> BlockCall { + *self.table.first().unwrap() + } + + /// Mutable access to the default block of this jump table. + pub fn default_block_mut(&mut self) -> &mut BlockCall { + self.table.first_mut().unwrap() + } + + /// The jump table and default block as a single slice. The default block will always be first. + pub fn all_branches(&self) -> &[BlockCall] { + self.table.as_slice() + } + + /// The jump table and default block as a single mutable slice. The default block will always + /// be first. + pub fn all_branches_mut(&mut self) -> &mut [BlockCall] { + self.table.as_mut_slice() + } + + /// Access the jump table as a slice. This excludes the default block. + pub fn as_slice(&self) -> &[BlockCall] { + &self.table.as_slice()[1..] + } + + /// Access the jump table as a mutable slice. This excludes the default block. + pub fn as_mut_slice(&mut self) -> &mut [BlockCall] { + &mut self.table.as_mut_slice()[1..] + } + + /// Returns an iterator to the jump table, excluding the default block. + #[deprecated(since = "7.0.0", note = "please use `.as_slice()` instead")] + pub fn iter(&self) -> Iter { + self.as_slice().iter() + } + + /// Returns an iterator that allows modifying each value, excluding the default block. + #[deprecated(since = "7.0.0", note = "please use `.as_mut_slice()` instead")] + pub fn iter_mut(&mut self) -> IterMut { + self.as_mut_slice().iter_mut() + } + + /// Clears all entries in this jump table, except for the default block. + pub fn clear(&mut self) { + self.table.drain(1..); + } + + /// Return a value that can display the contents of this jump table. + pub fn display<'a>(&'a self, pool: &'a ValueListPool) -> DisplayJumpTable<'a> { + DisplayJumpTable { jt: self, pool } + } +} + +/// A wrapper for the context required to display a [JumpTableData]. +pub struct DisplayJumpTable<'a> { + jt: &'a JumpTableData, + pool: &'a ValueListPool, +} + +impl<'a> Display for DisplayJumpTable<'a> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + write!(fmt, "{}, [", self.jt.default_block().display(self.pool))?; + if let Some((first, rest)) = self.jt.as_slice().split_first() { + write!(fmt, "{}", first.display(self.pool))?; + for block in rest { + write!(fmt, ", {}", block.display(self.pool))?; + } + } + write!(fmt, "]") + } +} + +#[cfg(test)] +mod tests { + use super::JumpTableData; + use crate::entity::EntityRef; + use crate::ir::instructions::ValueListPool; + use crate::ir::{Block, BlockCall, Value}; + use std::string::ToString; + + #[test] + fn empty() { + let mut pool = ValueListPool::default(); + let def = BlockCall::new(Block::new(0), &[], &mut pool); + + let jt = JumpTableData::new(def, &[]); + + assert_eq!(jt.all_branches().get(0), Some(&def)); + + assert_eq!(jt.as_slice().get(0), None); + assert_eq!(jt.as_slice().get(10), None); + + assert_eq!(jt.display(&pool).to_string(), "block0, []"); + + assert_eq!(jt.all_branches(), [def]); + assert_eq!(jt.as_slice(), []); + } + + #[test] + fn insert() { + let mut pool = ValueListPool::default(); + + let v0 = Value::new(0); + let v1 = Value::new(1); + + let e0 = Block::new(0); + let e1 = Block::new(1); + let e2 = Block::new(2); + + let def = BlockCall::new(e0, &[], &mut pool); + let b1 = BlockCall::new(e1, &[v0], &mut pool); + let b2 = BlockCall::new(e2, &[], &mut pool); + let b3 = BlockCall::new(e1, &[v1], &mut pool); + + let jt = JumpTableData::new(def, &[b1, b2, b3]); + + assert_eq!(jt.default_block(), def); + assert_eq!( + jt.display(&pool).to_string(), + "block0, [block1(v0), block2, block1(v1)]" + ); + + assert_eq!(jt.all_branches(), [def, b1, b2, b3]); + assert_eq!(jt.as_slice(), [b1, b2, b3]); + + assert_eq!(jt.as_slice()[0].args_slice(&pool), [v0]); + assert_eq!(jt.as_slice()[1].args_slice(&pool), []); + assert_eq!(jt.as_slice()[2].args_slice(&pool), [v1]); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/known_symbol.rs b/deps/crates/vendor/cranelift-codegen/src/ir/known_symbol.rs new file mode 100644 index 00000000000000..c3d17501a39b56 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/known_symbol.rs @@ -0,0 +1,47 @@ +use core::fmt; +use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A well-known symbol. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum KnownSymbol { + /// ELF well-known linker symbol _GLOBAL_OFFSET_TABLE_ + ElfGlobalOffsetTable, + /// TLS index symbol for the current thread. + /// Used in COFF/PE file formats. + CoffTlsIndex, +} + +impl fmt::Display for KnownSymbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +impl FromStr for KnownSymbol { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "ElfGlobalOffsetTable" => Ok(Self::ElfGlobalOffsetTable), + "CoffTlsIndex" => Ok(Self::CoffTlsIndex), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parsing() { + assert_eq!( + "ElfGlobalOffsetTable".parse(), + Ok(KnownSymbol::ElfGlobalOffsetTable) + ); + assert_eq!("CoffTlsIndex".parse(), Ok(KnownSymbol::CoffTlsIndex)); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/layout.rs b/deps/crates/vendor/cranelift-codegen/src/ir/layout.rs new file mode 100644 index 00000000000000..4e6ca774cc26ec --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/layout.rs @@ -0,0 +1,1193 @@ +//! Function layout. +//! +//! The order of basic blocks in a function and the order of instructions in a block is +//! determined by the `Layout` data structure defined in this module. + +use crate::entity::SecondaryMap; +use crate::ir::progpoint::ProgramPoint; +use crate::ir::{Block, Inst}; +use crate::packed_option::PackedOption; +use crate::{timing, trace}; +use core::cmp; + +/// The `Layout` struct determines the layout of blocks and instructions in a function. It does not +/// contain definitions of instructions or blocks, but depends on `Inst` and `Block` entity references +/// being defined elsewhere. +/// +/// This data structure determines: +/// +/// - The order of blocks in the function. +/// - Which block contains a given instruction. +/// - The order of instructions with a block. +/// +/// While data dependencies are not recorded, instruction ordering does affect control +/// dependencies, so part of the semantics of the program are determined by the layout. +/// +#[derive(Debug, Clone, PartialEq, Hash)] +pub struct Layout { + /// Linked list nodes for the layout order of blocks Forms a doubly linked list, terminated in + /// both ends by `None`. + blocks: SecondaryMap, + + /// Linked list nodes for the layout order of instructions. Forms a double linked list per block, + /// terminated in both ends by `None`. + insts: SecondaryMap, + + /// First block in the layout order, or `None` when no blocks have been laid out. + first_block: Option, + + /// Last block in the layout order, or `None` when no blocks have been laid out. + last_block: Option, +} + +impl Layout { + /// Create a new empty `Layout`. + pub fn new() -> Self { + Self { + blocks: SecondaryMap::new(), + insts: SecondaryMap::new(), + first_block: None, + last_block: None, + } + } + + /// Clear the layout. + pub fn clear(&mut self) { + self.blocks.clear(); + self.insts.clear(); + self.first_block = None; + self.last_block = None; + } + + /// Returns the capacity of the `BlockData` map. + pub fn block_capacity(&self) -> usize { + self.blocks.capacity() + } +} + +/// Sequence numbers. +/// +/// All instructions are given a sequence number that can be used to quickly determine +/// their relative position in a block. The sequence numbers are not contiguous, but are assigned +/// like line numbers in BASIC: 10, 20, 30, ... +/// +/// Sequence numbers are strictly increasing within a block, but are reset between blocks. +/// +/// The result is that sequence numbers work like BASIC line numbers for the textual form of the IR. +type SequenceNumber = u32; + +/// Initial stride assigned to new sequence numbers. +const MAJOR_STRIDE: SequenceNumber = 10; + +/// Secondary stride used when renumbering locally. +const MINOR_STRIDE: SequenceNumber = 2; + +/// Limit on the sequence number range we'll renumber locally. If this limit is exceeded, we'll +/// switch to a full block renumbering. +const LOCAL_LIMIT: SequenceNumber = 100 * MINOR_STRIDE; + +/// Compute the midpoint between `a` and `b`. +/// Return `None` if the midpoint would be equal to either. +fn midpoint(a: SequenceNumber, b: SequenceNumber) -> Option { + debug_assert!(a < b); + // Avoid integer overflow. + let m = a + (b - a) / 2; + if m > a { + Some(m) + } else { + None + } +} + +impl Layout { + /// Compare the program points `a` and `b` in the same block relative to this program order. + /// + /// Return `Less` if `a` appears in the program before `b`. + /// + /// This is declared as a generic such that it can be called with `Inst` and `Block` arguments + /// directly. Depending on the implementation, there is a good chance performance will be + /// improved for those cases where the type of either argument is known statically. + pub fn pp_cmp(&self, a: A, b: B) -> cmp::Ordering + where + A: Into, + B: Into, + { + let a = a.into(); + let b = b.into(); + debug_assert_eq!(self.pp_block(a), self.pp_block(b)); + let a_seq = match a { + ProgramPoint::Block(_block) => 0, + ProgramPoint::Inst(inst) => self.insts[inst].seq, + }; + let b_seq = match b { + ProgramPoint::Block(_block) => 0, + ProgramPoint::Inst(inst) => self.insts[inst].seq, + }; + a_seq.cmp(&b_seq) + } +} + +// Private methods for dealing with sequence numbers. +impl Layout { + /// Assign a valid sequence number to `inst` such that the numbers are still monotonic. This may + /// require renumbering. + fn assign_inst_seq(&mut self, inst: Inst) { + // Get the sequence number immediately before `inst`. + let prev_seq = match self.insts[inst].prev.expand() { + Some(prev_inst) => self.insts[prev_inst].seq, + None => 0, + }; + + // Get the sequence number immediately following `inst`. + let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() { + self.insts[next_inst].seq + } else { + // There is nothing after `inst`. We can just use a major stride. + self.insts[inst].seq = prev_seq + MAJOR_STRIDE; + return; + }; + + // Check if there is room between these sequence numbers. + if let Some(seq) = midpoint(prev_seq, next_seq) { + self.insts[inst].seq = seq; + } else { + // No available integers between `prev_seq` and `next_seq`. We have to renumber. + self.renumber_insts(inst, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT); + } + } + + /// Renumber instructions starting from `inst` until the end of the block or until numbers catch + /// up. + /// + /// If sequence numbers exceed `limit`, switch to a full block renumbering. + fn renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber) { + let mut inst = inst; + let mut seq = seq; + + loop { + self.insts[inst].seq = seq; + + // Next instruction. + inst = match self.insts[inst].next.expand() { + None => return, + Some(next) => next, + }; + + if seq < self.insts[inst].seq { + // Sequence caught up. + return; + } + + if seq > limit { + // We're pushing too many instructions in front of us. + // Switch to a full block renumbering to make some space. + self.full_block_renumber( + self.inst_block(inst) + .expect("inst must be inserted before assigning an seq"), + ); + return; + } + + seq += MINOR_STRIDE; + } + } + + /// Renumber all instructions in a block. + /// + /// This doesn't affect the position of anything, but it gives more room in the internal + /// sequence numbers for inserting instructions later. + fn full_block_renumber(&mut self, block: Block) { + let _tt = timing::layout_renumber(); + // Avoid 0 as this is reserved for the program point indicating the block itself + let mut seq = MAJOR_STRIDE; + let mut next_inst = self.blocks[block].first_inst.expand(); + while let Some(inst) = next_inst { + self.insts[inst].seq = seq; + seq += MAJOR_STRIDE; + next_inst = self.insts[inst].next.expand(); + } + + trace!("Renumbered {} program points", seq / MAJOR_STRIDE); + } +} + +/// Methods for laying out blocks. +/// +/// An unknown block starts out as *not inserted* in the block layout. The layout is a linear order of +/// inserted blocks. Once a block has been inserted in the layout, instructions can be added. A block +/// can only be removed from the layout when it is empty. +/// +/// Since every block must end with a terminator instruction which cannot fall through, the layout of +/// blocks do not affect the semantics of the program. +/// +impl Layout { + /// Is `block` currently part of the layout? + pub fn is_block_inserted(&self, block: Block) -> bool { + Some(block) == self.first_block || self.blocks[block].prev.is_some() + } + + /// Insert `block` as the last block in the layout. + pub fn append_block(&mut self, block: Block) { + debug_assert!( + !self.is_block_inserted(block), + "Cannot append block that is already in the layout" + ); + { + let node = &mut self.blocks[block]; + debug_assert!(node.first_inst.is_none() && node.last_inst.is_none()); + node.prev = self.last_block.into(); + node.next = None.into(); + } + if let Some(last) = self.last_block { + self.blocks[last].next = block.into(); + } else { + self.first_block = Some(block); + } + self.last_block = Some(block); + } + + /// Insert `block` in the layout before the existing block `before`. + pub fn insert_block(&mut self, block: Block, before: Block) { + debug_assert!( + !self.is_block_inserted(block), + "Cannot insert block that is already in the layout" + ); + debug_assert!( + self.is_block_inserted(before), + "block Insertion point not in the layout" + ); + let after = self.blocks[before].prev; + { + let node = &mut self.blocks[block]; + node.next = before.into(); + node.prev = after; + } + self.blocks[before].prev = block.into(); + match after.expand() { + None => self.first_block = Some(block), + Some(a) => self.blocks[a].next = block.into(), + } + } + + /// Insert `block` in the layout *after* the existing block `after`. + pub fn insert_block_after(&mut self, block: Block, after: Block) { + debug_assert!( + !self.is_block_inserted(block), + "Cannot insert block that is already in the layout" + ); + debug_assert!( + self.is_block_inserted(after), + "block Insertion point not in the layout" + ); + let before = self.blocks[after].next; + { + let node = &mut self.blocks[block]; + node.next = before; + node.prev = after.into(); + } + self.blocks[after].next = block.into(); + match before.expand() { + None => self.last_block = Some(block), + Some(b) => self.blocks[b].prev = block.into(), + } + } + + /// Remove `block` from the layout. + pub fn remove_block(&mut self, block: Block) { + debug_assert!(self.is_block_inserted(block), "block not in the layout"); + debug_assert!(self.first_inst(block).is_none(), "block must be empty."); + + // Clear the `block` node and extract links. + let prev; + let next; + { + let n = &mut self.blocks[block]; + prev = n.prev; + next = n.next; + n.prev = None.into(); + n.next = None.into(); + } + // Fix up links to `block`. + match prev.expand() { + None => self.first_block = next.expand(), + Some(p) => self.blocks[p].next = next, + } + match next.expand() { + None => self.last_block = prev.expand(), + Some(n) => self.blocks[n].prev = prev, + } + } + + /// Return an iterator over all blocks in layout order. + pub fn blocks(&self) -> Blocks { + Blocks { + layout: self, + next: self.first_block, + } + } + + /// Get the function's entry block. + /// This is simply the first block in the layout order. + pub fn entry_block(&self) -> Option { + self.first_block + } + + /// Get the last block in the layout. + pub fn last_block(&self) -> Option { + self.last_block + } + + /// Get the block preceding `block` in the layout order. + pub fn prev_block(&self, block: Block) -> Option { + self.blocks[block].prev.expand() + } + + /// Get the block following `block` in the layout order. + pub fn next_block(&self, block: Block) -> Option { + self.blocks[block].next.expand() + } + + /// Mark a block as "cold". + /// + /// This will try to move it out of the ordinary path of execution + /// when lowered to machine code. + pub fn set_cold(&mut self, block: Block) { + self.blocks[block].cold = true; + } + + /// Is the given block cold? + pub fn is_cold(&self, block: Block) -> bool { + self.blocks[block].cold + } +} + +/// A single node in the linked-list of blocks. +// **Note:** Whenever you add new fields here, don't forget to update the custom serializer for `Layout` too. +#[derive(Clone, Debug, Default, PartialEq, Hash)] +struct BlockNode { + prev: PackedOption, + next: PackedOption, + first_inst: PackedOption, + last_inst: PackedOption, + cold: bool, +} + +/// Iterate over blocks in layout order. See [crate::ir::layout::Layout::blocks]. +pub struct Blocks<'f> { + layout: &'f Layout, + next: Option, +} + +impl<'f> Iterator for Blocks<'f> { + type Item = Block; + + fn next(&mut self) -> Option { + match self.next { + Some(block) => { + self.next = self.layout.next_block(block); + Some(block) + } + None => None, + } + } +} + +/// Use a layout reference in a for loop. +impl<'f> IntoIterator for &'f Layout { + type Item = Block; + type IntoIter = Blocks<'f>; + + fn into_iter(self) -> Blocks<'f> { + self.blocks() + } +} + +/// Methods for arranging instructions. +/// +/// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into +/// a block at a given position. +impl Layout { + /// Get the block containing `inst`, or `None` if `inst` is not inserted in the layout. + pub fn inst_block(&self, inst: Inst) -> Option { + self.insts[inst].block.into() + } + + /// Get the block containing the program point `pp`. Panic if `pp` is not in the layout. + pub fn pp_block(&self, pp: ProgramPoint) -> Block { + match pp { + ProgramPoint::Block(block) => block, + ProgramPoint::Inst(inst) => self.inst_block(inst).expect("Program point not in layout"), + } + } + + /// Append `inst` to the end of `block`. + pub fn append_inst(&mut self, inst: Inst, block: Block) { + debug_assert_eq!(self.inst_block(inst), None); + debug_assert!( + self.is_block_inserted(block), + "Cannot append instructions to block not in layout" + ); + { + let block_node = &mut self.blocks[block]; + { + let inst_node = &mut self.insts[inst]; + inst_node.block = block.into(); + inst_node.prev = block_node.last_inst; + debug_assert!(inst_node.next.is_none()); + } + if block_node.first_inst.is_none() { + block_node.first_inst = inst.into(); + } else { + self.insts[block_node.last_inst.unwrap()].next = inst.into(); + } + block_node.last_inst = inst.into(); + } + self.assign_inst_seq(inst); + } + + /// Fetch a block's first instruction. + pub fn first_inst(&self, block: Block) -> Option { + self.blocks[block].first_inst.into() + } + + /// Fetch a block's last instruction. + pub fn last_inst(&self, block: Block) -> Option { + self.blocks[block].last_inst.into() + } + + /// Fetch the instruction following `inst`. + pub fn next_inst(&self, inst: Inst) -> Option { + self.insts[inst].next.expand() + } + + /// Fetch the instruction preceding `inst`. + pub fn prev_inst(&self, inst: Inst) -> Option { + self.insts[inst].prev.expand() + } + + /// Insert `inst` before the instruction `before` in the same block. + pub fn insert_inst(&mut self, inst: Inst, before: Inst) { + debug_assert_eq!(self.inst_block(inst), None); + let block = self + .inst_block(before) + .expect("Instruction before insertion point not in the layout"); + let after = self.insts[before].prev; + { + let inst_node = &mut self.insts[inst]; + inst_node.block = block.into(); + inst_node.next = before.into(); + inst_node.prev = after; + } + self.insts[before].prev = inst.into(); + match after.expand() { + None => self.blocks[block].first_inst = inst.into(), + Some(a) => self.insts[a].next = inst.into(), + } + self.assign_inst_seq(inst); + } + + /// Remove `inst` from the layout. + pub fn remove_inst(&mut self, inst: Inst) { + let block = self.inst_block(inst).expect("Instruction already removed."); + // Clear the `inst` node and extract links. + let prev; + let next; + { + let n = &mut self.insts[inst]; + prev = n.prev; + next = n.next; + n.block = None.into(); + n.prev = None.into(); + n.next = None.into(); + } + // Fix up links to `inst`. + match prev.expand() { + None => self.blocks[block].first_inst = next, + Some(p) => self.insts[p].next = next, + } + match next.expand() { + None => self.blocks[block].last_inst = prev, + Some(n) => self.insts[n].prev = prev, + } + } + + /// Iterate over the instructions in `block` in layout order. + pub fn block_insts(&self, block: Block) -> Insts { + Insts { + layout: self, + head: self.blocks[block].first_inst.into(), + tail: self.blocks[block].last_inst.into(), + } + } + + /// Split the block containing `before` in two. + /// + /// Insert `new_block` after the old block and move `before` and the following instructions to + /// `new_block`: + /// + /// ```text + /// old_block: + /// i1 + /// i2 + /// i3 << before + /// i4 + /// ``` + /// becomes: + /// + /// ```text + /// old_block: + /// i1 + /// i2 + /// new_block: + /// i3 << before + /// i4 + /// ``` + pub fn split_block(&mut self, new_block: Block, before: Inst) { + let old_block = self + .inst_block(before) + .expect("The `before` instruction must be in the layout"); + debug_assert!(!self.is_block_inserted(new_block)); + + // Insert new_block after old_block. + let next_block = self.blocks[old_block].next; + let last_inst = self.blocks[old_block].last_inst; + { + let node = &mut self.blocks[new_block]; + node.prev = old_block.into(); + node.next = next_block; + node.first_inst = before.into(); + node.last_inst = last_inst; + } + self.blocks[old_block].next = new_block.into(); + + // Fix backwards link. + if Some(old_block) == self.last_block { + self.last_block = Some(new_block); + } else { + self.blocks[next_block.unwrap()].prev = new_block.into(); + } + + // Disconnect the instruction links. + let prev_inst = self.insts[before].prev; + self.insts[before].prev = None.into(); + self.blocks[old_block].last_inst = prev_inst; + match prev_inst.expand() { + None => self.blocks[old_block].first_inst = None.into(), + Some(pi) => self.insts[pi].next = None.into(), + } + + // Fix the instruction -> block pointers. + let mut opt_i = Some(before); + while let Some(i) = opt_i { + debug_assert_eq!(self.insts[i].block.expand(), Some(old_block)); + self.insts[i].block = new_block.into(); + opt_i = self.insts[i].next.into(); + } + } +} + +#[derive(Clone, Debug, Default)] +struct InstNode { + /// The Block containing this instruction, or `None` if the instruction is not yet inserted. + block: PackedOption, + prev: PackedOption, + next: PackedOption, + seq: SequenceNumber, +} + +impl PartialEq for InstNode { + fn eq(&self, other: &Self) -> bool { + // Ignore the sequence number as it is an optimization used by pp_cmp and may be different + // even for equivalent layouts. + self.block == other.block && self.prev == other.prev && self.next == other.next + } +} + +impl core::hash::Hash for InstNode { + fn hash(&self, state: &mut H) { + // Ignore the sequence number as it is an optimization used by pp_cmp and may be different + // even for equivalent layouts. + self.block.hash(state); + self.prev.hash(state); + self.next.hash(state); + } +} + +/// Iterate over instructions in a block in layout order. See `Layout::block_insts()`. +pub struct Insts<'f> { + layout: &'f Layout, + head: Option, + tail: Option, +} + +impl<'f> Iterator for Insts<'f> { + type Item = Inst; + + fn next(&mut self) -> Option { + let rval = self.head; + if let Some(inst) = rval { + if self.head == self.tail { + self.head = None; + self.tail = None; + } else { + self.head = self.layout.insts[inst].next.into(); + } + } + rval + } +} + +impl<'f> DoubleEndedIterator for Insts<'f> { + fn next_back(&mut self) -> Option { + let rval = self.tail; + if let Some(inst) = rval { + if self.head == self.tail { + self.head = None; + self.tail = None; + } else { + self.tail = self.layout.insts[inst].prev.into(); + } + } + rval + } +} + +/// A custom serialize and deserialize implementation for [`Layout`]. +/// +/// This doesn't use a derived implementation as [`Layout`] is a manual implementation of a linked +/// list. Storing it directly as a regular list saves a lot of space. +/// +/// The following format is used. (notated in EBNF form) +/// +/// ```plain +/// data = block_data * ; +/// block_data = "block_id" , "cold" , "inst_count" , ( "inst_id" * ) ; +/// ``` +#[cfg(feature = "enable-serde")] +mod serde { + use ::serde::de::{Deserializer, Error, SeqAccess, Visitor}; + use ::serde::ser::{SerializeSeq, Serializer}; + use ::serde::{Deserialize, Serialize}; + use core::fmt; + use core::marker::PhantomData; + + use super::*; + + impl Serialize for Layout { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let size = self.blocks().count() * 3 + + self + .blocks() + .map(|block| self.block_insts(block).count()) + .sum::(); + let mut seq = serializer.serialize_seq(Some(size))?; + for block in self.blocks() { + seq.serialize_element(&block)?; + seq.serialize_element(&self.blocks[block].cold)?; + seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?; + for inst in self.block_insts(block) { + seq.serialize_element(&inst)?; + } + } + seq.end() + } + } + + impl<'de> Deserialize<'de> for Layout { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(LayoutVisitor { + marker: PhantomData, + }) + } + } + + struct LayoutVisitor { + marker: PhantomData Layout>, + } + + impl<'de> Visitor<'de> for LayoutVisitor { + type Value = Layout; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a `cranelift_codegen::ir::Layout`") + } + + fn visit_seq(self, mut access: M) -> Result + where + M: SeqAccess<'de>, + { + let mut layout = Layout::new(); + + while let Some(block) = access.next_element::()? { + layout.append_block(block); + + let cold = access + .next_element::()? + .ok_or_else(|| Error::missing_field("cold"))?; + layout.blocks[block].cold = cold; + + let count = access + .next_element::()? + .ok_or_else(|| Error::missing_field("count"))?; + + for _ in 0..count { + let inst = access + .next_element::()? + .ok_or_else(|| Error::missing_field("inst"))?; + layout.append_inst(inst, block); + } + } + + Ok(layout) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cursor::{Cursor, CursorPosition}; + use crate::entity::EntityRef; + use crate::ir::{Block, Inst, SourceLoc}; + use alloc::vec::Vec; + use core::cmp::Ordering; + + #[test] + fn test_midpoint() { + assert_eq!(midpoint(0, 1), None); + assert_eq!(midpoint(0, 2), Some(1)); + assert_eq!(midpoint(0, 3), Some(1)); + assert_eq!(midpoint(0, 4), Some(2)); + assert_eq!(midpoint(1, 4), Some(2)); + assert_eq!(midpoint(2, 4), Some(3)); + assert_eq!(midpoint(3, 4), None); + assert_eq!(midpoint(3, 4), None); + } + + struct LayoutCursor<'f> { + /// Borrowed function layout. Public so it can be re-borrowed from this cursor. + pub layout: &'f mut Layout, + pos: CursorPosition, + } + + impl<'f> Cursor for LayoutCursor<'f> { + fn position(&self) -> CursorPosition { + self.pos + } + + fn set_position(&mut self, pos: CursorPosition) { + self.pos = pos; + } + + fn srcloc(&self) -> SourceLoc { + unimplemented!() + } + + fn set_srcloc(&mut self, _srcloc: SourceLoc) { + unimplemented!() + } + + fn layout(&self) -> &Layout { + self.layout + } + + fn layout_mut(&mut self) -> &mut Layout { + self.layout + } + } + + impl<'f> LayoutCursor<'f> { + /// Create a new `LayoutCursor` for `layout`. + /// The cursor holds a mutable reference to `layout` for its entire lifetime. + pub fn new(layout: &'f mut Layout) -> Self { + Self { + layout, + pos: CursorPosition::Nowhere, + } + } + } + + fn verify(layout: &mut Layout, blocks: &[(Block, &[Inst])]) { + // Check that blocks are inserted and instructions belong the right places. + // Check forward linkage with iterators. + // Check that layout sequence numbers are strictly monotonic. + { + let mut block_iter = layout.blocks(); + for &(block, insts) in blocks { + assert!(layout.is_block_inserted(block)); + assert_eq!(block_iter.next(), Some(block)); + + let mut seq = 0; + let mut inst_iter = layout.block_insts(block); + for &inst in insts { + assert_eq!(layout.inst_block(inst), Some(block)); + assert_eq!(inst_iter.next(), Some(inst)); + assert!(layout.insts[inst].seq > seq); + seq = layout.insts[inst].seq; + } + assert_eq!(inst_iter.next(), None); + } + assert_eq!(block_iter.next(), None); + } + + // Check backwards linkage with a cursor. + let mut cur = LayoutCursor::new(layout); + for &(block, insts) in blocks.into_iter().rev() { + assert_eq!(cur.prev_block(), Some(block)); + for &inst in insts.into_iter().rev() { + assert_eq!(cur.prev_inst(), Some(inst)); + } + assert_eq!(cur.prev_inst(), None); + } + assert_eq!(cur.prev_block(), None); + } + + #[test] + fn append_block() { + let mut layout = Layout::new(); + let e0 = Block::new(0); + let e1 = Block::new(1); + let e2 = Block::new(2); + + { + let imm = &layout; + assert!(!imm.is_block_inserted(e0)); + assert!(!imm.is_block_inserted(e1)); + } + verify(&mut layout, &[]); + + layout.append_block(e1); + assert!(!layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(!layout.is_block_inserted(e2)); + let v: Vec = layout.blocks().collect(); + assert_eq!(v, [e1]); + + layout.append_block(e2); + assert!(!layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(layout.is_block_inserted(e2)); + let v: Vec = layout.blocks().collect(); + assert_eq!(v, [e1, e2]); + + layout.append_block(e0); + assert!(layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(layout.is_block_inserted(e2)); + let v: Vec = layout.blocks().collect(); + assert_eq!(v, [e1, e2, e0]); + + { + let imm = &layout; + let mut v = Vec::new(); + for e in imm { + v.push(e); + } + assert_eq!(v, [e1, e2, e0]); + } + + // Test cursor positioning. + let mut cur = LayoutCursor::new(&mut layout); + assert_eq!(cur.position(), CursorPosition::Nowhere); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.position(), CursorPosition::Nowhere); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.position(), CursorPosition::Nowhere); + + assert_eq!(cur.next_block(), Some(e1)); + assert_eq!(cur.position(), CursorPosition::Before(e1)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.position(), CursorPosition::After(e1)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.position(), CursorPosition::After(e1)); + assert_eq!(cur.next_block(), Some(e2)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.position(), CursorPosition::Before(e2)); + assert_eq!(cur.next_block(), Some(e0)); + assert_eq!(cur.next_block(), None); + assert_eq!(cur.position(), CursorPosition::Nowhere); + + // Backwards through the blocks. + assert_eq!(cur.prev_block(), Some(e0)); + assert_eq!(cur.position(), CursorPosition::After(e0)); + assert_eq!(cur.prev_block(), Some(e2)); + assert_eq!(cur.prev_block(), Some(e1)); + assert_eq!(cur.prev_block(), None); + assert_eq!(cur.position(), CursorPosition::Nowhere); + } + + #[test] + fn insert_block() { + let mut layout = Layout::new(); + let e0 = Block::new(0); + let e1 = Block::new(1); + let e2 = Block::new(2); + + { + let imm = &layout; + assert!(!imm.is_block_inserted(e0)); + assert!(!imm.is_block_inserted(e1)); + + let v: Vec = layout.blocks().collect(); + assert_eq!(v, []); + } + + layout.append_block(e1); + assert!(!layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(!layout.is_block_inserted(e2)); + verify(&mut layout, &[(e1, &[])]); + + layout.insert_block(e2, e1); + assert!(!layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(layout.is_block_inserted(e2)); + verify(&mut layout, &[(e2, &[]), (e1, &[])]); + + layout.insert_block(e0, e1); + assert!(layout.is_block_inserted(e0)); + assert!(layout.is_block_inserted(e1)); + assert!(layout.is_block_inserted(e2)); + verify(&mut layout, &[(e2, &[]), (e0, &[]), (e1, &[])]); + } + + #[test] + fn insert_block_after() { + let mut layout = Layout::new(); + let e0 = Block::new(0); + let e1 = Block::new(1); + let e2 = Block::new(2); + + layout.append_block(e1); + layout.insert_block_after(e2, e1); + verify(&mut layout, &[(e1, &[]), (e2, &[])]); + + layout.insert_block_after(e0, e1); + verify(&mut layout, &[(e1, &[]), (e0, &[]), (e2, &[])]); + } + + #[test] + fn append_inst() { + let mut layout = Layout::new(); + let e1 = Block::new(1); + + layout.append_block(e1); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, []); + + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), None); + assert_eq!(layout.inst_block(i2), None); + + layout.append_inst(i1, e1); + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), Some(e1)); + assert_eq!(layout.inst_block(i2), None); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, [i1]); + + layout.append_inst(i2, e1); + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), Some(e1)); + assert_eq!(layout.inst_block(i2), Some(e1)); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, [i1, i2]); + + // Test double-ended instruction iterator. + let v: Vec = layout.block_insts(e1).rev().collect(); + assert_eq!(v, [i2, i1]); + + layout.append_inst(i0, e1); + verify(&mut layout, &[(e1, &[i1, i2, i0])]); + + // Test cursor positioning. + let mut cur = LayoutCursor::new(&mut layout).at_top(e1); + assert_eq!(cur.position(), CursorPosition::Before(e1)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.position(), CursorPosition::Before(e1)); + assert_eq!(cur.next_inst(), Some(i1)); + assert_eq!(cur.position(), CursorPosition::At(i1)); + assert_eq!(cur.next_inst(), Some(i2)); + assert_eq!(cur.next_inst(), Some(i0)); + assert_eq!(cur.prev_inst(), Some(i2)); + assert_eq!(cur.position(), CursorPosition::At(i2)); + assert_eq!(cur.next_inst(), Some(i0)); + assert_eq!(cur.position(), CursorPosition::At(i0)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.position(), CursorPosition::After(e1)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.position(), CursorPosition::After(e1)); + assert_eq!(cur.prev_inst(), Some(i0)); + assert_eq!(cur.prev_inst(), Some(i2)); + assert_eq!(cur.prev_inst(), Some(i1)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.position(), CursorPosition::Before(e1)); + + // Test remove_inst. + cur.goto_inst(i2); + assert_eq!(cur.remove_inst(), i2); + verify(cur.layout, &[(e1, &[i1, i0])]); + assert_eq!(cur.layout.inst_block(i2), None); + assert_eq!(cur.remove_inst(), i0); + verify(cur.layout, &[(e1, &[i1])]); + assert_eq!(cur.layout.inst_block(i0), None); + assert_eq!(cur.position(), CursorPosition::After(e1)); + cur.layout.remove_inst(i1); + verify(cur.layout, &[(e1, &[])]); + assert_eq!(cur.layout.inst_block(i1), None); + } + + #[test] + fn insert_inst() { + let mut layout = Layout::new(); + let e1 = Block::new(1); + + layout.append_block(e1); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, []); + + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), None); + assert_eq!(layout.inst_block(i2), None); + + layout.append_inst(i1, e1); + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), Some(e1)); + assert_eq!(layout.inst_block(i2), None); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, [i1]); + + layout.insert_inst(i2, i1); + assert_eq!(layout.inst_block(i0), None); + assert_eq!(layout.inst_block(i1), Some(e1)); + assert_eq!(layout.inst_block(i2), Some(e1)); + let v: Vec = layout.block_insts(e1).collect(); + assert_eq!(v, [i2, i1]); + + layout.insert_inst(i0, i1); + verify(&mut layout, &[(e1, &[i2, i0, i1])]); + } + + #[test] + fn multiple_blocks() { + let mut layout = Layout::new(); + + let e0 = Block::new(0); + let e1 = Block::new(1); + + assert_eq!(layout.entry_block(), None); + layout.append_block(e0); + assert_eq!(layout.entry_block(), Some(e0)); + layout.append_block(e1); + assert_eq!(layout.entry_block(), Some(e0)); + + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + + layout.append_inst(i0, e0); + layout.append_inst(i1, e0); + layout.append_inst(i2, e1); + layout.append_inst(i3, e1); + + let v0: Vec = layout.block_insts(e0).collect(); + let v1: Vec = layout.block_insts(e1).collect(); + assert_eq!(v0, [i0, i1]); + assert_eq!(v1, [i2, i3]); + } + + #[test] + fn split_block() { + let mut layout = Layout::new(); + + let e0 = Block::new(0); + let e1 = Block::new(1); + let e2 = Block::new(2); + + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + + layout.append_block(e0); + layout.append_inst(i0, e0); + assert_eq!(layout.inst_block(i0), Some(e0)); + layout.split_block(e1, i0); + assert_eq!(layout.inst_block(i0), Some(e1)); + + { + let mut cur = LayoutCursor::new(&mut layout); + assert_eq!(cur.next_block(), Some(e0)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.next_block(), Some(e1)); + assert_eq!(cur.next_inst(), Some(i0)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.next_block(), None); + + // Check backwards links. + assert_eq!(cur.prev_block(), Some(e1)); + assert_eq!(cur.prev_inst(), Some(i0)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.prev_block(), Some(e0)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.prev_block(), None); + } + + layout.append_inst(i1, e0); + layout.append_inst(i2, e0); + layout.append_inst(i3, e0); + layout.split_block(e2, i2); + + assert_eq!(layout.inst_block(i0), Some(e1)); + assert_eq!(layout.inst_block(i1), Some(e0)); + assert_eq!(layout.inst_block(i2), Some(e2)); + assert_eq!(layout.inst_block(i3), Some(e2)); + + { + let mut cur = LayoutCursor::new(&mut layout); + assert_eq!(cur.next_block(), Some(e0)); + assert_eq!(cur.next_inst(), Some(i1)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.next_block(), Some(e2)); + assert_eq!(cur.next_inst(), Some(i2)); + assert_eq!(cur.next_inst(), Some(i3)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.next_block(), Some(e1)); + assert_eq!(cur.next_inst(), Some(i0)); + assert_eq!(cur.next_inst(), None); + assert_eq!(cur.next_block(), None); + + assert_eq!(cur.prev_block(), Some(e1)); + assert_eq!(cur.prev_inst(), Some(i0)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.prev_block(), Some(e2)); + assert_eq!(cur.prev_inst(), Some(i3)); + assert_eq!(cur.prev_inst(), Some(i2)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.prev_block(), Some(e0)); + assert_eq!(cur.prev_inst(), Some(i1)); + assert_eq!(cur.prev_inst(), None); + assert_eq!(cur.prev_block(), None); + } + + // Check `ProgramOrder`. + assert_eq!(layout.pp_cmp(e2, e2), Ordering::Equal); + assert_eq!(layout.pp_cmp(e2, i2), Ordering::Less); + assert_eq!(layout.pp_cmp(i3, i2), Ordering::Greater) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/libcall.rs b/deps/crates/vendor/cranelift-codegen/src/ir/libcall.rs new file mode 100644 index 00000000000000..1e05adcc5d5f66 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/libcall.rs @@ -0,0 +1,232 @@ +//! Naming well-known routines in the runtime library. + +use crate::{ + ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature, Type}, + isa::CallConv, +}; +use core::fmt; +use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// The name of a runtime library routine. +/// +/// Runtime library calls are generated for Cranelift IR instructions that don't have an equivalent +/// ISA instruction or an easy macro expansion. A `LibCall` is used as a well-known name to refer to +/// the runtime library routine. This way, Cranelift doesn't have to know about the naming +/// convention in the embedding VM's runtime library. +/// +/// This list is likely to grow over time. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum LibCall { + /// probe for stack overflow. These are emitted for functions which need + /// when the `enable_probestack` setting is true. + Probestack, + /// ceil.f32 + CeilF32, + /// ceil.f64 + CeilF64, + /// floor.f32 + FloorF32, + /// floor.f64 + FloorF64, + /// trunc.f32 + TruncF32, + /// frunc.f64 + TruncF64, + /// nearest.f32 + NearestF32, + /// nearest.f64 + NearestF64, + /// fma.f32 + FmaF32, + /// fma.f64 + FmaF64, + /// libc.memcpy + Memcpy, + /// libc.memset + Memset, + /// libc.memmove + Memmove, + /// libc.memcmp + Memcmp, + + /// Elf __tls_get_addr + ElfTlsGetAddr, + /// Elf __tls_get_offset + ElfTlsGetOffset, + + /// The `pshufb` on x86 when SSSE3 isn't available. + X86Pshufb, + // When adding a new variant make sure to add it to `all_libcalls` too. +} + +impl fmt::Display for LibCall { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +impl FromStr for LibCall { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "Probestack" => Ok(Self::Probestack), + "CeilF32" => Ok(Self::CeilF32), + "CeilF64" => Ok(Self::CeilF64), + "FloorF32" => Ok(Self::FloorF32), + "FloorF64" => Ok(Self::FloorF64), + "TruncF32" => Ok(Self::TruncF32), + "TruncF64" => Ok(Self::TruncF64), + "NearestF32" => Ok(Self::NearestF32), + "NearestF64" => Ok(Self::NearestF64), + "FmaF32" => Ok(Self::FmaF32), + "FmaF64" => Ok(Self::FmaF64), + "Memcpy" => Ok(Self::Memcpy), + "Memset" => Ok(Self::Memset), + "Memmove" => Ok(Self::Memmove), + "Memcmp" => Ok(Self::Memcmp), + + "ElfTlsGetAddr" => Ok(Self::ElfTlsGetAddr), + "ElfTlsGetOffset" => Ok(Self::ElfTlsGetOffset), + + "X86Pshufb" => Ok(Self::X86Pshufb), + _ => Err(()), + } + } +} + +impl LibCall { + /// Get a list of all known `LibCall`'s. + pub fn all_libcalls() -> &'static [LibCall] { + use LibCall::*; + &[ + Probestack, + CeilF32, + CeilF64, + FloorF32, + FloorF64, + TruncF32, + TruncF64, + NearestF32, + NearestF64, + FmaF32, + FmaF64, + Memcpy, + Memset, + Memmove, + Memcmp, + ElfTlsGetAddr, + ElfTlsGetOffset, + X86Pshufb, + ] + } + + /// Get a [Signature] for the function targeted by this [LibCall]. + pub fn signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature { + use types::*; + let mut sig = Signature::new(call_conv); + + match self { + LibCall::CeilF32 | LibCall::FloorF32 | LibCall::TruncF32 | LibCall::NearestF32 => { + sig.params.push(AbiParam::new(F32)); + sig.returns.push(AbiParam::new(F32)); + } + LibCall::TruncF64 | LibCall::FloorF64 | LibCall::CeilF64 | LibCall::NearestF64 => { + sig.params.push(AbiParam::new(F64)); + sig.returns.push(AbiParam::new(F64)); + } + LibCall::FmaF32 | LibCall::FmaF64 => { + let ty = if *self == LibCall::FmaF32 { F32 } else { F64 }; + + sig.params.push(AbiParam::new(ty)); + sig.params.push(AbiParam::new(ty)); + sig.params.push(AbiParam::new(ty)); + sig.returns.push(AbiParam::new(ty)); + } + LibCall::Memcpy | LibCall::Memmove => { + // void* memcpy(void *dest, const void *src, size_t count); + // void* memmove(void* dest, const void* src, size_t count); + sig.params.push(AbiParam::new(pointer_type)); + sig.params.push(AbiParam::new(pointer_type)); + sig.params.push(AbiParam::new(pointer_type)); + sig.returns.push(AbiParam::new(pointer_type)); + } + LibCall::Memset => { + // void *memset(void *dest, int ch, size_t count); + sig.params.push(AbiParam::new(pointer_type)); + sig.params.push(AbiParam::new(I32)); + sig.params.push(AbiParam::new(pointer_type)); + sig.returns.push(AbiParam::new(pointer_type)); + } + LibCall::Memcmp => { + // void* memcpy(void *dest, const void *src, size_t count); + sig.params.push(AbiParam::new(pointer_type)); + sig.params.push(AbiParam::new(pointer_type)); + sig.params.push(AbiParam::new(pointer_type)); + sig.returns.push(AbiParam::new(I32)) + } + + LibCall::Probestack | LibCall::ElfTlsGetAddr | LibCall::ElfTlsGetOffset => { + unimplemented!() + } + LibCall::X86Pshufb => { + sig.params.push(AbiParam::new(I8X16)); + sig.params.push(AbiParam::new(I8X16)); + sig.returns.push(AbiParam::new(I8X16)); + } + } + + sig + } +} + +/// Get a function reference for the probestack function in `func`. +/// +/// If there is an existing reference, use it, otherwise make a new one. +pub fn get_probestack_funcref(func: &mut Function) -> Option { + find_funcref(LibCall::Probestack, func) +} + +/// Get the existing function reference for `libcall` in `func` if it exists. +fn find_funcref(libcall: LibCall, func: &Function) -> Option { + // We're assuming that all libcall function decls are at the end. + // If we get this wrong, worst case we'll have duplicate libcall decls which is harmless. + for (fref, func_data) in func.dfg.ext_funcs.iter().rev() { + match func_data.name { + ExternalName::LibCall(lc) => { + if lc == libcall { + return Some(fref); + } + } + _ => break, + } + } + None +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn display() { + assert_eq!(LibCall::CeilF32.to_string(), "CeilF32"); + assert_eq!(LibCall::NearestF64.to_string(), "NearestF64"); + } + + #[test] + fn parsing() { + assert_eq!("FloorF32".parse(), Ok(LibCall::FloorF32)); + } + + #[test] + fn all_libcalls_to_from_string() { + for &libcall in LibCall::all_libcalls() { + assert_eq!(libcall.to_string().parse(), Ok(libcall)); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/memflags.rs b/deps/crates/vendor/cranelift-codegen/src/ir/memflags.rs new file mode 100644 index 00000000000000..e83466f814dc60 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/memflags.rs @@ -0,0 +1,441 @@ +//! Memory operation flags. + +use super::TrapCode; +use core::fmt; +use core::num::NonZeroU8; +use core::str::FromStr; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Endianness of a memory access. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum Endianness { + /// Little-endian + Little, + /// Big-endian + Big, +} + +/// Which disjoint region of aliasing memory is accessed in this memory +/// operation. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[repr(u8)] +#[allow(missing_docs)] +#[rustfmt::skip] +pub enum AliasRegion { + // None = 0b00; + Heap = 0b01, + Table = 0b10, + Vmctx = 0b11, +} + +impl AliasRegion { + const fn from_bits(bits: u8) -> Option { + match bits { + 0b00 => None, + 0b01 => Some(Self::Heap), + 0b10 => Some(Self::Table), + 0b11 => Some(Self::Vmctx), + _ => panic!("invalid alias region bits"), + } + } + + const fn to_bits(region: Option) -> u8 { + match region { + None => 0b00, + Some(r) => r as u8, + } + } +} + +/// Flags for memory operations like load/store. +/// +/// Each of these flags introduce a limited form of undefined behavior. The flags each enable +/// certain optimizations that need to make additional assumptions. Generally, the semantics of a +/// program does not change when a flag is removed, but adding a flag will. +/// +/// In addition, the flags determine the endianness of the memory access. By default, +/// any memory access uses the native endianness determined by the target ISA. This can +/// be overridden for individual accesses by explicitly specifying little- or big-endian +/// semantics via the flags. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MemFlags { + // Initialized to all zeros to have all flags have their default value. + // This is interpreted through various methods below. Currently the bits of + // this are defined as: + // + // * 0 - aligned flag + // * 1 - readonly flag + // * 2 - little endian flag + // * 3 - big endian flag + // * 4 - checked flag + // * 5/6 - alias region + // * 7/8/9/10/11/12/13/14 - trap code + // * 15 - unallocated + // + // Current properties upheld are: + // + // * only one of little/big endian is set + // * only one alias region can be set - once set it cannot be changed + bits: u16, +} + +/// Guaranteed to use "natural alignment" for the given type. This +/// may enable better instruction selection. +const BIT_ALIGNED: u16 = 1 << 0; + +/// A load that reads data in memory that does not change for the +/// duration of the function's execution. This may enable +/// additional optimizations to be performed. +const BIT_READONLY: u16 = 1 << 1; + +/// Load multi-byte values from memory in a little-endian format. +const BIT_LITTLE_ENDIAN: u16 = 1 << 2; + +/// Load multi-byte values from memory in a big-endian format. +const BIT_BIG_ENDIAN: u16 = 1 << 3; + +/// Check this load or store for safety when using the +/// proof-carrying-code framework. The address must have a +/// `PointsTo` fact attached with a sufficiently large valid range +/// for the accessed size. +const BIT_CHECKED: u16 = 1 << 4; + +/// Used for alias analysis, indicates which disjoint part of the abstract state +/// is being accessed. +const MASK_ALIAS_REGION: u16 = 0b11 << ALIAS_REGION_OFFSET; +const ALIAS_REGION_OFFSET: u16 = 5; + +/// Trap code, if any, for this memory operation. +const MASK_TRAP_CODE: u16 = 0b1111_1111 << TRAP_CODE_OFFSET; +const TRAP_CODE_OFFSET: u16 = 7; + +impl MemFlags { + /// Create a new empty set of flags. + pub const fn new() -> Self { + Self { bits: 0 }.with_trap_code(Some(TrapCode::HEAP_OUT_OF_BOUNDS)) + } + + /// Create a set of flags representing an access from a "trusted" address, meaning it's + /// known to be aligned and non-trapping. + pub const fn trusted() -> Self { + Self::new().with_notrap().with_aligned() + } + + /// Read a flag bit. + const fn read_bit(self, bit: u16) -> bool { + self.bits & bit != 0 + } + + /// Return a new `MemFlags` with this flag bit set. + const fn with_bit(mut self, bit: u16) -> Self { + self.bits |= bit; + self + } + + /// Reads the alias region that this memory operation works with. + pub const fn alias_region(self) -> Option { + AliasRegion::from_bits(((self.bits & MASK_ALIAS_REGION) >> ALIAS_REGION_OFFSET) as u8) + } + + /// Sets the alias region that this works on to the specified `region`. + pub const fn with_alias_region(mut self, region: Option) -> Self { + let bits = AliasRegion::to_bits(region); + self.bits &= !MASK_ALIAS_REGION; + self.bits |= (bits as u16) << ALIAS_REGION_OFFSET; + self + } + + /// Sets the alias region that this works on to the specified `region`. + pub fn set_alias_region(&mut self, region: Option) { + *self = self.with_alias_region(region); + } + + /// Set a flag bit by name. + /// + /// Returns true if the flag was found and set, false for an unknown flag + /// name. + /// + /// # Errors + /// + /// Returns an error message if the `name` is known but couldn't be applied + /// due to it being a semantic error. + pub fn set_by_name(&mut self, name: &str) -> Result { + *self = match name { + "notrap" => self.with_trap_code(None), + "aligned" => self.with_aligned(), + "readonly" => self.with_readonly(), + "little" => { + if self.read_bit(BIT_BIG_ENDIAN) { + return Err("cannot set both big and little endian bits"); + } + self.with_endianness(Endianness::Little) + } + "big" => { + if self.read_bit(BIT_LITTLE_ENDIAN) { + return Err("cannot set both big and little endian bits"); + } + self.with_endianness(Endianness::Big) + } + "heap" => { + if self.alias_region().is_some() { + return Err("cannot set more than one alias region"); + } + self.with_alias_region(Some(AliasRegion::Heap)) + } + "table" => { + if self.alias_region().is_some() { + return Err("cannot set more than one alias region"); + } + self.with_alias_region(Some(AliasRegion::Table)) + } + "vmctx" => { + if self.alias_region().is_some() { + return Err("cannot set more than one alias region"); + } + self.with_alias_region(Some(AliasRegion::Vmctx)) + } + "checked" => self.with_checked(), + + other => match TrapCode::from_str(other) { + Ok(code) => self.with_trap_code(Some(code)), + Err(()) => return Ok(false), + }, + }; + Ok(true) + } + + /// Return endianness of the memory access. This will return the endianness + /// explicitly specified by the flags if any, and will default to the native + /// endianness otherwise. The native endianness has to be provided by the + /// caller since it is not explicitly encoded in CLIF IR -- this allows a + /// front end to create IR without having to know the target endianness. + pub const fn endianness(self, native_endianness: Endianness) -> Endianness { + if self.read_bit(BIT_LITTLE_ENDIAN) { + Endianness::Little + } else if self.read_bit(BIT_BIG_ENDIAN) { + Endianness::Big + } else { + native_endianness + } + } + + /// Return endianness of the memory access, if explicitly specified. + /// + /// If the endianness is not explicitly specified, this will return `None`, + /// which means "native endianness". + pub const fn explicit_endianness(self) -> Option { + if self.read_bit(BIT_LITTLE_ENDIAN) { + Some(Endianness::Little) + } else if self.read_bit(BIT_BIG_ENDIAN) { + Some(Endianness::Big) + } else { + None + } + } + + /// Set endianness of the memory access. + pub fn set_endianness(&mut self, endianness: Endianness) { + *self = self.with_endianness(endianness); + } + + /// Set endianness of the memory access, returning new flags. + pub const fn with_endianness(self, endianness: Endianness) -> Self { + let res = match endianness { + Endianness::Little => self.with_bit(BIT_LITTLE_ENDIAN), + Endianness::Big => self.with_bit(BIT_BIG_ENDIAN), + }; + assert!(!(res.read_bit(BIT_LITTLE_ENDIAN) && res.read_bit(BIT_BIG_ENDIAN))); + res + } + + /// Test if this memory operation cannot trap. + /// + /// By default `MemFlags` will assume that any load/store can trap and is + /// associated with a `TrapCode::HeapOutOfBounds` code. If the trap code is + /// configured to `None` though then this method will return `true` and + /// indicates that the memory operation will not trap. + /// + /// If this returns `true` then the memory is *accessible*, which means + /// that accesses will not trap. This makes it possible to delete an unused + /// load or a dead store instruction. + pub const fn notrap(self) -> bool { + self.trap_code().is_none() + } + + /// Sets the trap code for this `MemFlags` to `None`. + pub fn set_notrap(&mut self) { + *self = self.with_notrap(); + } + + /// Sets the trap code for this `MemFlags` to `None`, returning the new + /// flags. + pub const fn with_notrap(self) -> Self { + self.with_trap_code(None) + } + + /// Test if the `aligned` flag is set. + /// + /// By default, Cranelift memory instructions work with any unaligned effective address. If the + /// `aligned` flag is set, the instruction is permitted to trap or return a wrong result if the + /// effective address is misaligned. + pub const fn aligned(self) -> bool { + self.read_bit(BIT_ALIGNED) + } + + /// Set the `aligned` flag. + pub fn set_aligned(&mut self) { + *self = self.with_aligned(); + } + + /// Set the `aligned` flag, returning new flags. + pub const fn with_aligned(self) -> Self { + self.with_bit(BIT_ALIGNED) + } + + /// Test if the `readonly` flag is set. + /// + /// Loads with this flag have no memory dependencies. + /// This results in undefined behavior if the dereferenced memory is mutated at any time + /// between when the function is called and when it is exited. + pub const fn readonly(self) -> bool { + self.read_bit(BIT_READONLY) + } + + /// Set the `readonly` flag. + pub fn set_readonly(&mut self) { + *self = self.with_readonly(); + } + + /// Set the `readonly` flag, returning new flags. + pub const fn with_readonly(self) -> Self { + self.with_bit(BIT_READONLY) + } + + /// Test if the `checked` bit is set. + /// + /// Loads and stores with this flag are verified to access + /// pointers only with a validated `PointsTo` fact attached, and + /// with that fact validated, when using the proof-carrying-code + /// framework. If initial facts on program inputs are correct + /// (i.e., correctly denote the shape and types of data structures + /// in memory), and if PCC validates the compiled output, then all + /// `checked`-marked memory accesses are guaranteed (up to the + /// checker's correctness) to access valid memory. This can be + /// used to ensure memory safety and sandboxing. + pub const fn checked(self) -> bool { + self.read_bit(BIT_CHECKED) + } + + /// Set the `checked` bit. + pub fn set_checked(&mut self) { + *self = self.with_checked(); + } + + /// Set the `checked` bit, returning new flags. + pub const fn with_checked(self) -> Self { + self.with_bit(BIT_CHECKED) + } + + /// Get the trap code to report if this memory access traps. + /// + /// A `None` trap code indicates that this memory access does not trap. + pub const fn trap_code(self) -> Option { + let byte = ((self.bits & MASK_TRAP_CODE) >> TRAP_CODE_OFFSET) as u8; + match NonZeroU8::new(byte) { + Some(code) => Some(TrapCode::from_raw(code)), + None => None, + } + } + + /// Configures these flags with the specified trap code `code`. + /// + /// A trap code indicates that this memory operation cannot be optimized + /// away and it must "stay where it is" in the programs. Traps are + /// considered side effects, for example, and have meaning through the trap + /// code that is communicated and which instruction trapped. + pub const fn with_trap_code(mut self, code: Option) -> Self { + let bits = match code { + Some(code) => code.as_raw().get() as u16, + None => 0, + }; + self.bits &= !MASK_TRAP_CODE; + self.bits |= bits << TRAP_CODE_OFFSET; + self + } +} + +impl fmt::Display for MemFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.trap_code() { + None => write!(f, " notrap")?, + // This is the default trap code, so don't print anything extra + // for this. + Some(TrapCode::HEAP_OUT_OF_BOUNDS) => {} + Some(t) => write!(f, " {t}")?, + } + if self.aligned() { + write!(f, " aligned")?; + } + if self.readonly() { + write!(f, " readonly")?; + } + if self.read_bit(BIT_BIG_ENDIAN) { + write!(f, " big")?; + } + if self.read_bit(BIT_LITTLE_ENDIAN) { + write!(f, " little")?; + } + if self.checked() { + write!(f, " checked")?; + } + match self.alias_region() { + None => {} + Some(AliasRegion::Heap) => write!(f, " heap")?, + Some(AliasRegion::Table) => write!(f, " table")?, + Some(AliasRegion::Vmctx) => write!(f, " vmctx")?, + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip_traps() { + for trap in TrapCode::non_user_traps().iter().copied() { + let flags = MemFlags::new().with_trap_code(Some(trap)); + assert_eq!(flags.trap_code(), Some(trap)); + } + let flags = MemFlags::new().with_trap_code(None); + assert_eq!(flags.trap_code(), None); + } + + #[test] + fn cannot_set_big_and_little() { + let mut big = MemFlags::new().with_endianness(Endianness::Big); + assert!(big.set_by_name("little").is_err()); + + let mut little = MemFlags::new().with_endianness(Endianness::Little); + assert!(little.set_by_name("big").is_err()); + } + + #[test] + fn only_one_region() { + let mut big = MemFlags::new().with_alias_region(Some(AliasRegion::Heap)); + assert!(big.set_by_name("table").is_err()); + assert!(big.set_by_name("vmctx").is_err()); + + let mut big = MemFlags::new().with_alias_region(Some(AliasRegion::Table)); + assert!(big.set_by_name("heap").is_err()); + assert!(big.set_by_name("vmctx").is_err()); + + let mut big = MemFlags::new().with_alias_region(Some(AliasRegion::Vmctx)); + assert!(big.set_by_name("heap").is_err()); + assert!(big.set_by_name("table").is_err()); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/memtype.rs b/deps/crates/vendor/cranelift-codegen/src/ir/memtype.rs new file mode 100644 index 00000000000000..4df26f1647e54c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/memtype.rs @@ -0,0 +1,190 @@ +//! Definitions for "memory types" in CLIF. +//! +//! A memory type is a struct-like definition -- fields with offsets, +//! each field having a type and possibly an attached fact -- that we +//! can use in proof-carrying code to validate accesses to structs and +//! propagate facts onto the loaded values as well. +//! +//! Memory types are meant to be rich enough to describe the *layout* +//! of values in memory, but do not necessarily need to embody +//! higher-level features such as subtyping directly. Rather, they +//! should encode an implementation of a type or object system. +//! +//! Note also that it is a non-goal for now for this type system to be +//! "complete" or fully orthogonal: we have some restrictions now +//! (e.g., struct fields are only primitives) because this is all we +//! need for existing PCC applications, and it keeps the +//! implementation simpler. +//! +//! There are a few basic kinds of types: +//! +//! - A struct is an aggregate of fields and an overall size. Each +//! field has a *primitive Cranelift type*. This is for simplicity's +//! sake: we do not allow nested memory types because to do so +//! invites cycles, requires recursive computation of sizes, creates +//! complicated questions when field types are dynamically-sized, +//! and in general is more complexity than we need. +//! +//! The expectation (validated by PCC) is that when a checked load +//! or store accesses memory typed by a memory type, accesses will +//! only be to fields at offsets named in the type, and will be via +//! the given Cranelift type -- i.e., no type-punning occurs in +//! memory. +//! +//! The overall size of the struct may be larger than that implied +//! by the fields because (i) we may not want or need to name all +//! the actually-existing fields in the memory type, and (ii) there +//! may be alignment padding that we also don't want or need to +//! represent explicitly. +//! +//! - A static memory is an untyped blob of storage with a static +//! size. This is memory that can be accessed with any type of load +//! or store at any valid offset. +//! +//! Note that this is *distinct* from an "array of u8" kind of +//! representation of memory, if/when we can represent such a thing, +//! because the expectation with memory types' fields (including +//! array elements) is that they are strongly typed, only accessed +//! via that type, and not type-punned. We don't want to imply any +//! restriction on load/store size, or any actual structure, with +//! untyped memory; it's just a blob. +//! +//! Eventually we plan to also have: +//! +//! - A dynamic array is a sequence of struct memory types, with a +//! length given by a global value (GV). This is useful to model, +//! e.g., tables. +//! +//! - A discriminated union is a union of several memory types +//! together with a tag field. This will be useful to model and +//! verify subtyping/downcasting for Wasm GC, among other uses. +//! +//! - Nullability on pointer fields: the fact will hold only if the +//! field is not null (all zero bits). + +use crate::ir::pcc::Fact; +use crate::ir::{GlobalValue, Type}; +use alloc::vec::Vec; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Data defining a memory type. +/// +/// A memory type corresponds to a layout of data in memory. It may +/// have a statically-known or dynamically-known size. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum MemoryTypeData { + /// An aggregate consisting of certain fields at certain offsets. + /// + /// Fields must be sorted by offset, must be within the struct's + /// overall size, and must not overlap. These conditions are + /// checked by the CLIF verifier. + Struct { + /// Size of this type. + size: u64, + + /// Fields in this type. Sorted by offset. + fields: Vec, + }, + + /// A statically-sized untyped blob of memory. + Memory { + /// Accessible size. + size: u64, + }, + + /// A dynamically-sized untyped blob of memory, with bound given + /// by a global value plus some static amount. + DynamicMemory { + /// Static part of size. + size: u64, + /// Dynamic part of size. + gv: GlobalValue, + }, + + /// A type with no size. + Empty, +} + +impl std::default::Default for MemoryTypeData { + fn default() -> Self { + Self::Empty + } +} + +impl std::fmt::Display for MemoryTypeData { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Struct { size, fields } => { + write!(f, "struct {size} {{")?; + let mut first = true; + for field in fields { + if first { + first = false; + } else { + write!(f, ",")?; + } + write!(f, " {}: {}", field.offset, field.ty)?; + if field.readonly { + write!(f, " readonly")?; + } + if let Some(fact) = &field.fact { + write!(f, " ! {fact}")?; + } + } + write!(f, " }}")?; + Ok(()) + } + Self::Memory { size } => { + write!(f, "memory {size:#x}") + } + Self::DynamicMemory { size, gv } => { + write!(f, "dynamic_memory {gv}+{size:#x}") + } + Self::Empty => { + write!(f, "empty") + } + } + } +} + +/// One field in a memory type. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MemoryTypeField { + /// The offset of this field in the memory type. + pub offset: u64, + /// The primitive type of the value in this field. Accesses to the + /// field must use this type (i.e., cannot bitcast/type-pun in + /// memory). + pub ty: Type, + /// A proof-carrying-code fact about this value, if any. + pub fact: Option, + /// Whether this field is read-only, i.e., stores should be + /// disallowed. + pub readonly: bool, +} + +impl MemoryTypeField { + /// Get the fact, if any, on a field. + pub fn fact(&self) -> Option<&Fact> { + self.fact.as_ref() + } +} + +impl MemoryTypeData { + /// Provide the static size of this type, if known. + /// + /// (The size may not be known for dynamically-sized arrays or + /// memories, when those memtype kinds are added.) + pub fn static_size(&self) -> Option { + match self { + Self::Struct { size, .. } => Some(*size), + Self::Memory { size } => Some(*size), + Self::DynamicMemory { .. } => None, + Self::Empty => Some(0), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/mod.rs b/deps/crates/vendor/cranelift-codegen/src/ir/mod.rs new file mode 100644 index 00000000000000..e6f082d70a8d9d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/mod.rs @@ -0,0 +1,110 @@ +//! Representation of Cranelift IR functions. + +mod atomic_rmw_op; +mod builder; +pub mod condcodes; +pub mod constant; +pub mod dfg; +pub mod dynamic_type; +pub mod entities; +mod extfunc; +mod extname; +pub mod function; +mod globalvalue; +pub mod immediates; +pub mod instructions; +pub mod jumptable; +pub(crate) mod known_symbol; +pub mod layout; +pub(crate) mod libcall; +mod memflags; +mod memtype; +pub mod pcc; +mod progpoint; +mod sourceloc; +pub mod stackslot; +mod trapcode; +pub mod types; +mod user_stack_maps; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +pub use crate::ir::atomic_rmw_op::AtomicRmwOp; +pub use crate::ir::builder::{ + InsertBuilder, InstBuilder, InstBuilderBase, InstInserterBase, ReplaceBuilder, +}; +pub use crate::ir::constant::{ConstantData, ConstantPool}; +pub use crate::ir::dfg::{BlockData, DataFlowGraph, ValueDef}; +pub use crate::ir::dynamic_type::{dynamic_to_fixed, DynamicTypeData, DynamicTypes}; +pub use crate::ir::entities::{ + Block, Constant, DynamicStackSlot, DynamicType, FuncRef, GlobalValue, Immediate, Inst, + JumpTable, MemoryType, SigRef, StackSlot, UserExternalNameRef, Value, +}; +pub use crate::ir::extfunc::{ + AbiParam, ArgumentExtension, ArgumentPurpose, ExtFuncData, Signature, +}; +pub use crate::ir::extname::{ExternalName, UserExternalName, UserFuncName}; +pub use crate::ir::function::Function; +pub use crate::ir::globalvalue::GlobalValueData; +pub use crate::ir::instructions::{ + BlockCall, InstructionData, Opcode, ValueList, ValueListPool, VariableArgs, +}; +pub use crate::ir::jumptable::JumpTableData; +pub use crate::ir::known_symbol::KnownSymbol; +pub use crate::ir::layout::Layout; +pub use crate::ir::libcall::{get_probestack_funcref, LibCall}; +pub use crate::ir::memflags::{AliasRegion, Endianness, MemFlags}; +pub use crate::ir::memtype::{MemoryTypeData, MemoryTypeField}; +pub use crate::ir::pcc::{BaseExpr, Expr, Fact, FactContext, PccError, PccResult}; +pub use crate::ir::progpoint::ProgramPoint; +pub use crate::ir::sourceloc::RelSourceLoc; +pub use crate::ir::sourceloc::SourceLoc; +pub use crate::ir::stackslot::{ + DynamicStackSlotData, DynamicStackSlots, StackSlotData, StackSlotKind, StackSlots, +}; +pub use crate::ir::trapcode::TrapCode; +pub use crate::ir::types::Type; +pub use crate::ir::user_stack_maps::{UserStackMap, UserStackMapEntry}; + +use crate::entity::{entity_impl, PrimaryMap, SecondaryMap}; + +/// Map of jump tables. +pub type JumpTables = PrimaryMap; + +/// Source locations for instructions. +pub(crate) type SourceLocs = SecondaryMap; + +/// Marked with a label value. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ValueLabel(u32); +entity_impl!(ValueLabel, "val"); + +/// A label of a Value. +#[derive(Debug, Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ValueLabelStart { + /// Source location when it is in effect + pub from: RelSourceLoc, + + /// The label index. + pub label: ValueLabel, +} + +/// Value label assignments: label starts or value aliases. +#[derive(Debug, Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum ValueLabelAssignments { + /// Original value labels assigned at transform. + Starts(alloc::vec::Vec), + + /// A value alias to original value. + Alias { + /// Source location when it is in effect + from: RelSourceLoc, + + /// The label index. + value: Value, + }, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/pcc.rs b/deps/crates/vendor/cranelift-codegen/src/ir/pcc.rs new file mode 100644 index 00000000000000..5ebfbbb503d1e2 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/pcc.rs @@ -0,0 +1,1682 @@ +//! Proof-carrying code. We attach "facts" to values and then check +//! that they remain true after compilation. +//! +//! A few key design principle of this approach are: +//! +//! - The producer of the IR provides the axioms. All "ground truth", +//! such as what memory is accessible -- is meant to come by way of +//! facts on the function arguments and global values. In some +//! sense, all we are doing here is validating the "internal +//! consistency" of the facts that are provided on values, and the +//! actions performed on those values. +//! +//! - We do not derive and forward-propagate facts eagerly. Rather, +//! the producer needs to provide breadcrumbs -- a "proof witness" +//! of sorts -- to allow the checking to complete. That means that +//! as an address is computed, or pointer chains are dereferenced, +//! each intermediate value will likely have some fact attached. +//! +//! This does create more verbose IR, but a significant positive +//! benefit is that it avoids unnecessary work: we do not build up a +//! knowledge base that effectively encodes the integer ranges of +//! many or most values in the program. Rather, we only check +//! specifically the memory-access sequences. In practice, each such +//! sequence is likely to be a carefully-controlled sequence of IR +//! operations from, e.g., a sandboxing compiler (such as +//! Wasmtime) so adding annotations here to communicate +//! intent (ranges, bounds-checks, and the like) is no problem. +//! +//! Facts are attached to SSA values in CLIF, and are maintained +//! through optimizations and through lowering. They are thus also +//! present on VRegs in the VCode. In theory, facts could be checked +//! at either level, though in practice it is most useful to check +//! them at the VCode level if the goal is an end-to-end verification +//! of certain properties (e.g., memory sandboxing). +//! +//! Checking facts entails visiting each instruction that defines a +//! value with a fact, and checking the result's fact against the +//! facts on arguments and the operand. For VCode, this is +//! fundamentally a question of the target ISA's semantics, so we call +//! into the `LowerBackend` for this. Note that during checking there +//! is also limited forward propagation / inference, but only within +//! an instruction: for example, an addressing mode commonly can +//! include an addition, multiplication/shift, or extend operation, +//! and there is no way to attach facts to the intermediate values +//! "inside" the instruction, so instead the backend can use +//! `FactContext::add()` and friends to forward-propagate facts. +//! +//! TODO: +//! +//! Deployment: +//! - Add to fuzzing +//! - Turn on during wasm spec-tests +//! +//! More checks: +//! - Check that facts on `vmctx` GVs are subsumed by the actual facts +//! on the vmctx arg in block0 (function arg). +//! +//! Generality: +//! - facts on outputs (in func signature)? +//! - Implement checking at the CLIF level as well. +//! - Check instructions that can trap as well? +//! +//! Nicer errors: +//! - attach instruction index or some other identifier to errors +//! +//! Text format cleanup: +//! - make the bitwidth on `max` facts optional in the CLIF text +//! format? +//! - make offset in `mem` fact optional in the text format? +//! +//! Bikeshed colors (syntax): +//! - Put fact bang-annotations after types? +//! `v0: i64 ! fact(..)` vs. `v0 ! fact(..): i64` + +use crate::ir; +use crate::ir::types::*; +use crate::isa::TargetIsa; +use crate::machinst::{BlockIndex, LowerBackend, VCode}; +use crate::trace; +use regalloc2::Function as _; +use std::fmt; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// The result of checking proof-carrying-code facts. +pub type PccResult = std::result::Result; + +/// An error or inconsistency discovered when checking proof-carrying +/// code. +#[derive(Debug, Clone)] +pub enum PccError { + /// An operation wraps around, invalidating the stated value + /// range. + Overflow, + /// An input to an operator that produces a fact-annotated value + /// does not have a fact describing it, and one is needed. + MissingFact, + /// A derivation of an output fact is unsupported (incorrect or + /// not derivable). + UnsupportedFact, + /// A block parameter claims a fact that one of its predecessors + /// does not support. + UnsupportedBlockparam, + /// A memory access is out of bounds. + OutOfBounds, + /// Proof-carrying-code checking is not implemented for a + /// particular compiler backend. + UnimplementedBackend, + /// Proof-carrying-code checking is not implemented for a + /// particular instruction that instruction-selection chose. This + /// is an internal compiler error. + UnimplementedInst, + /// Access to an invalid or undefined field offset in a struct. + InvalidFieldOffset, + /// Access to a field via the wrong type. + BadFieldType, + /// Store to a read-only field. + WriteToReadOnlyField, + /// Store of data to a field with a fact that does not subsume the + /// field's fact. + InvalidStoredFact, +} + +/// A fact on a value. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum Fact { + /// A bitslice of a value (up to a bitwidth) is within the given + /// integer range. + /// + /// The slicing behavior is needed because this fact can describe + /// both an SSA `Value`, whose entire value is well-defined, and a + /// `VReg` in VCode, whose bits beyond the type stored in that + /// register are don't-care (undefined). + Range { + /// The bitwidth of bits we care about, from the LSB upward. + bit_width: u16, + /// The minimum value that the bitslice can take + /// (inclusive). The range is unsigned: the specified bits of + /// the actual value will be greater than or equal to this + /// value, as evaluated by an unsigned integer comparison. + min: u64, + /// The maximum value that the bitslice can take + /// (inclusive). The range is unsigned: the specified bits of + /// the actual value will be less than or equal to this value, + /// as evaluated by an unsigned integer comparison. + max: u64, + }, + + /// A value bounded by a global value. + /// + /// The range is in `(min_GV + min_offset)..(max_GV + + /// max_offset)`, inclusive on the lower and upper bound. + DynamicRange { + /// The bitwidth of bits we care about, from the LSB upward. + bit_width: u16, + /// The lower bound, inclusive. + min: Expr, + /// The upper bound, inclusive. + max: Expr, + }, + + /// A pointer to a memory type. + Mem { + /// The memory type. + ty: ir::MemoryType, + /// The minimum offset into the memory type, inclusive. + min_offset: u64, + /// The maximum offset into the memory type, inclusive. + max_offset: u64, + /// This pointer can also be null. + nullable: bool, + }, + + /// A pointer to a memory type, dynamically bounded. The pointer + /// is within `(GV_min+offset_min)..(GV_max+offset_max)` + /// (inclusive on both ends) in the memory type. + DynamicMem { + /// The memory type. + ty: ir::MemoryType, + /// The lower bound, inclusive. + min: Expr, + /// The upper bound, inclusive. + max: Expr, + /// This pointer can also be null. + nullable: bool, + }, + + /// A definition of a value to be used as a symbol in + /// BaseExprs. There can only be one of these per value number. + /// + /// Note that this differs from a `DynamicRange` specifying that + /// some value in the program is the same as `value`. A `def(v1)` + /// fact is propagated to machine code and serves as a source of + /// truth: the value or location labeled with this fact *defines* + /// what `v1` is, and any `dynamic_range(64, v1, v1)`-labeled + /// values elsewhere are claiming to be equal to this value. + /// + /// This is necessary because we don't propagate SSA value labels + /// down to machine code otherwise; so when referring symbolically + /// to addresses and expressions derived from addresses, we need + /// to introduce the symbol first. + Def { + /// The SSA value this value defines. + value: ir::Value, + }, + + /// A comparison result between two dynamic values with a + /// comparison of a certain kind. + Compare { + /// The kind of comparison. + kind: ir::condcodes::IntCC, + /// The left-hand side of the comparison. + lhs: Expr, + /// The right-hand side of the comparison. + rhs: Expr, + }, + + /// A "conflict fact": this fact results from merging two other + /// facts, and it can never be satisfied -- checking any value + /// against this fact will fail. + Conflict, +} + +/// A bound expression. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Expr { + /// The dynamic (base) part. + pub base: BaseExpr, + /// The static (offset) part. + pub offset: i64, +} + +/// The base part of a bound expression. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum BaseExpr { + /// No dynamic part (i.e., zero). + None, + /// A global value. + GlobalValue(ir::GlobalValue), + /// An SSA Value as a symbolic value. This can be referenced in + /// facts even after we've lowered out of SSA: it becomes simply + /// some symbolic value. + Value(ir::Value), + /// Top of the address space. This is "saturating": the offset + /// doesn't matter. + Max, +} + +impl BaseExpr { + /// Is one base less than or equal to another? (We can't always + /// know; in such cases, returns `false`.) + fn le(lhs: &BaseExpr, rhs: &BaseExpr) -> bool { + // (i) reflexivity; (ii) 0 <= x for all (unsigned) x; (iii) x <= max for all x. + lhs == rhs || *lhs == BaseExpr::None || *rhs == BaseExpr::Max + } + + /// Compute some BaseExpr that will be less than or equal to both + /// inputs. This is a generalization of `min` (but looser). + fn min(lhs: &BaseExpr, rhs: &BaseExpr) -> BaseExpr { + if lhs == rhs { + lhs.clone() + } else if *lhs == BaseExpr::Max { + rhs.clone() + } else if *rhs == BaseExpr::Max { + lhs.clone() + } else { + BaseExpr::None // zero is <= x for all (unsigned) x. + } + } + + /// Compute some BaseExpr that will be greater than or equal to + /// both inputs. + fn max(lhs: &BaseExpr, rhs: &BaseExpr) -> BaseExpr { + if lhs == rhs { + lhs.clone() + } else if *lhs == BaseExpr::None { + rhs.clone() + } else if *rhs == BaseExpr::None { + lhs.clone() + } else { + BaseExpr::Max + } + } +} + +impl Expr { + /// Constant value. + pub fn constant(offset: i64) -> Self { + Expr { + base: BaseExpr::None, + offset, + } + } + + /// The value of an SSA value. + pub fn value(value: ir::Value) -> Self { + Expr { + base: BaseExpr::Value(value), + offset: 0, + } + } + + /// The value of a global value. + pub fn global_value(gv: ir::GlobalValue) -> Self { + Expr { + base: BaseExpr::GlobalValue(gv), + offset: 0, + } + } + + /// Is one expression definitely less than or equal to another? + /// (We can't always know; in such cases, returns `false`.) + fn le(lhs: &Expr, rhs: &Expr) -> bool { + if rhs.base == BaseExpr::Max { + true + } else { + BaseExpr::le(&lhs.base, &rhs.base) && lhs.offset <= rhs.offset + } + } + + /// Generalization of `min`: compute some Expr that is less than + /// or equal to both inputs. + fn min(lhs: &Expr, rhs: &Expr) -> Expr { + if lhs.base == BaseExpr::None && lhs.offset == 0 { + lhs.clone() + } else if rhs.base == BaseExpr::None && rhs.offset == 0 { + rhs.clone() + } else { + Expr { + base: BaseExpr::min(&lhs.base, &rhs.base), + offset: std::cmp::min(lhs.offset, rhs.offset), + } + } + } + + /// Generalization of `max`: compute some Expr that is greater + /// than or equal to both inputs. + fn max(lhs: &Expr, rhs: &Expr) -> Expr { + if lhs.base == BaseExpr::None && lhs.offset == 0 { + rhs.clone() + } else if rhs.base == BaseExpr::None && rhs.offset == 0 { + lhs.clone() + } else { + Expr { + base: BaseExpr::max(&lhs.base, &rhs.base), + offset: std::cmp::max(lhs.offset, rhs.offset), + } + } + } + + /// Add one expression to another. + fn add(lhs: &Expr, rhs: &Expr) -> Option { + if lhs.base == rhs.base { + Some(Expr { + base: lhs.base.clone(), + offset: lhs.offset.checked_add(rhs.offset)?, + }) + } else if lhs.base == BaseExpr::None { + Some(Expr { + base: rhs.base.clone(), + offset: lhs.offset.checked_add(rhs.offset)?, + }) + } else if rhs.base == BaseExpr::None { + Some(Expr { + base: lhs.base.clone(), + offset: lhs.offset.checked_add(rhs.offset)?, + }) + } else { + Some(Expr { + base: BaseExpr::Max, + offset: 0, + }) + } + } + + /// Add a static offset to an expression. + pub fn offset(lhs: &Expr, rhs: i64) -> Option { + let offset = lhs.offset.checked_add(rhs)?; + Some(Expr { + base: lhs.base.clone(), + offset, + }) + } + + /// Is this Expr a BaseExpr with no offset? Return it if so. + pub fn without_offset(&self) -> Option<&BaseExpr> { + if self.offset == 0 { + Some(&self.base) + } else { + None + } + } +} + +impl fmt::Display for BaseExpr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + BaseExpr::None => Ok(()), + BaseExpr::Max => write!(f, "max"), + BaseExpr::GlobalValue(gv) => write!(f, "{gv}"), + BaseExpr::Value(value) => write!(f, "{value}"), + } + } +} + +impl BaseExpr { + /// Does this dynamic_expression take an offset? + pub fn is_some(&self) -> bool { + match self { + BaseExpr::None => false, + _ => true, + } + } +} + +impl fmt::Display for Expr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.base)?; + match self.offset { + offset if offset > 0 && self.base.is_some() => write!(f, "+{offset:#x}"), + offset if offset > 0 => write!(f, "{offset:#x}"), + offset if offset < 0 => { + let negative_offset = -i128::from(offset); // upcast to support i64::MIN. + write!(f, "-{negative_offset:#x}") + } + 0 if self.base.is_some() => Ok(()), + 0 => write!(f, "0"), + _ => unreachable!(), + } + } +} + +impl fmt::Display for Fact { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Fact::Range { + bit_width, + min, + max, + } => write!(f, "range({bit_width}, {min:#x}, {max:#x})"), + Fact::DynamicRange { + bit_width, + min, + max, + } => { + write!(f, "dynamic_range({bit_width}, {min}, {max})") + } + Fact::Mem { + ty, + min_offset, + max_offset, + nullable, + } => { + let nullable_flag = if *nullable { ", nullable" } else { "" }; + write!( + f, + "mem({ty}, {min_offset:#x}, {max_offset:#x}{nullable_flag})" + ) + } + Fact::DynamicMem { + ty, + min, + max, + nullable, + } => { + let nullable_flag = if *nullable { ", nullable" } else { "" }; + write!(f, "dynamic_mem({ty}, {min}, {max}{nullable_flag})") + } + Fact::Def { value } => write!(f, "def({value})"), + Fact::Compare { kind, lhs, rhs } => { + write!(f, "compare({kind}, {lhs}, {rhs})") + } + Fact::Conflict => write!(f, "conflict"), + } + } +} + +impl Fact { + /// Create a range fact that specifies a single known constant value. + pub fn constant(bit_width: u16, value: u64) -> Self { + debug_assert!(value <= max_value_for_width(bit_width)); + // `min` and `max` are inclusive, so this specifies a range of + // exactly one value. + Fact::Range { + bit_width, + min: value, + max: value, + } + } + + /// Create a dynamic range fact that points to the base of a dynamic memory. + pub fn dynamic_base_ptr(ty: ir::MemoryType) -> Self { + Fact::DynamicMem { + ty, + min: Expr::constant(0), + max: Expr::constant(0), + nullable: false, + } + } + + /// Create a fact that specifies the value is exactly an SSA value. + /// + /// Note that this differs from a `def` fact: it is not *defining* + /// a symbol to have the value that this fact is attached to; + /// rather it is claiming that this value is the same as whatever + /// that symbol is. (In other words, the def should be elsewhere, + /// and we are tying ourselves to it.) + pub fn value(bit_width: u16, value: ir::Value) -> Self { + Fact::DynamicRange { + bit_width, + min: Expr::value(value), + max: Expr::value(value), + } + } + + /// Create a fact that specifies the value is exactly an SSA value plus some offset. + pub fn value_offset(bit_width: u16, value: ir::Value, offset: i64) -> Self { + Fact::DynamicRange { + bit_width, + min: Expr::offset(&Expr::value(value), offset).unwrap(), + max: Expr::offset(&Expr::value(value), offset).unwrap(), + } + } + + /// Create a fact that specifies the value is exactly the value of a GV. + pub fn global_value(bit_width: u16, gv: ir::GlobalValue) -> Self { + Fact::DynamicRange { + bit_width, + min: Expr::global_value(gv), + max: Expr::global_value(gv), + } + } + + /// Create a fact that specifies the value is exactly the value of a GV plus some offset. + pub fn global_value_offset(bit_width: u16, gv: ir::GlobalValue, offset: i64) -> Self { + Fact::DynamicRange { + bit_width, + min: Expr::offset(&Expr::global_value(gv), offset).unwrap(), + max: Expr::offset(&Expr::global_value(gv), offset).unwrap(), + } + } + + /// Create a range fact that specifies the maximum range for a + /// value of the given bit-width. + pub const fn max_range_for_width(bit_width: u16) -> Self { + match bit_width { + bit_width if bit_width < 64 => Fact::Range { + bit_width, + min: 0, + max: (1u64 << bit_width) - 1, + }, + 64 => Fact::Range { + bit_width: 64, + min: 0, + max: u64::MAX, + }, + _ => panic!("bit width too large!"), + } + } + + /// Create a range fact that specifies the maximum range for a + /// value of the given bit-width, zero-extended into a wider + /// width. + pub const fn max_range_for_width_extended(from_width: u16, to_width: u16) -> Self { + debug_assert!(from_width <= to_width); + match from_width { + from_width if from_width < 64 => Fact::Range { + bit_width: to_width, + min: 0, + max: (1u64 << from_width) - 1, + }, + 64 => Fact::Range { + bit_width: to_width, + min: 0, + max: u64::MAX, + }, + _ => panic!("bit width too large!"), + } + } + + /// Try to infer a minimal fact for a value of the given IR type. + pub fn infer_from_type(ty: ir::Type) -> Option<&'static Self> { + static FACTS: [Fact; 4] = [ + Fact::max_range_for_width(8), + Fact::max_range_for_width(16), + Fact::max_range_for_width(32), + Fact::max_range_for_width(64), + ]; + match ty { + I8 => Some(&FACTS[0]), + I16 => Some(&FACTS[1]), + I32 => Some(&FACTS[2]), + I64 => Some(&FACTS[3]), + _ => None, + } + } + + /// Does this fact "propagate" automatically, i.e., cause + /// instructions that process it to infer their own output facts? + /// Not all facts propagate automatically; otherwise, verification + /// would be much slower. + pub fn propagates(&self) -> bool { + match self { + Fact::Mem { .. } => true, + _ => false, + } + } + + /// Is this a constant value of the given bitwidth? Return it as a + /// `Some(value)` if so. + pub fn as_const(&self, bits: u16) -> Option { + match self { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == bits && min == max => Some(*min), + _ => None, + } + } + + /// Is this fact a single-value range with a symbolic Expr? + pub fn as_symbol(&self) -> Option<&Expr> { + match self { + Fact::DynamicRange { min, max, .. } if min == max => Some(min), + _ => None, + } + } + + /// Merge two facts. We take the *intersection*: that is, we know + /// both facts to be true, so we can intersect ranges. (This + /// differs from the usual static analysis approach, where we are + /// merging multiple possibilities into a generalized / widened + /// fact. We want to narrow here.) + pub fn intersect(a: &Fact, b: &Fact) -> Fact { + match (a, b) { + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) if bw_lhs == bw_rhs && max_lhs >= min_rhs && max_rhs >= min_lhs => Fact::Range { + bit_width: *bw_lhs, + min: std::cmp::max(*min_lhs, *min_rhs), + max: std::cmp::min(*max_lhs, *max_rhs), + }, + + ( + Fact::DynamicRange { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::DynamicRange { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) if bw_lhs == bw_rhs && Expr::le(min_rhs, max_lhs) && Expr::le(min_lhs, max_rhs) => { + Fact::DynamicRange { + bit_width: *bw_lhs, + min: Expr::max(min_lhs, min_rhs), + max: Expr::min(max_lhs, max_rhs), + } + } + + ( + Fact::Mem { + ty: ty_lhs, + min_offset: min_offset_lhs, + max_offset: max_offset_lhs, + nullable: nullable_lhs, + }, + Fact::Mem { + ty: ty_rhs, + min_offset: min_offset_rhs, + max_offset: max_offset_rhs, + nullable: nullable_rhs, + }, + ) if ty_lhs == ty_rhs + && max_offset_lhs >= min_offset_rhs + && max_offset_rhs >= min_offset_lhs => + { + Fact::Mem { + ty: *ty_lhs, + min_offset: std::cmp::max(*min_offset_lhs, *min_offset_rhs), + max_offset: std::cmp::min(*max_offset_lhs, *max_offset_rhs), + nullable: *nullable_lhs && *nullable_rhs, + } + } + + ( + Fact::DynamicMem { + ty: ty_lhs, + min: min_lhs, + max: max_lhs, + nullable: null_lhs, + }, + Fact::DynamicMem { + ty: ty_rhs, + min: min_rhs, + max: max_rhs, + nullable: null_rhs, + }, + ) if ty_lhs == ty_rhs && Expr::le(min_rhs, max_lhs) && Expr::le(min_lhs, max_rhs) => { + Fact::DynamicMem { + ty: *ty_lhs, + min: Expr::max(min_lhs, min_rhs), + max: Expr::min(max_lhs, max_rhs), + nullable: *null_lhs && *null_rhs, + } + } + + _ => Fact::Conflict, + } + } +} + +macro_rules! ensure { + ( $condition:expr, $err:tt $(,)? ) => { + if !$condition { + return Err(PccError::$err); + } + }; +} + +macro_rules! bail { + ( $err:tt ) => {{ + return Err(PccError::$err); + }}; +} + +/// The two kinds of inequalities: "strict" (`<`, `>`) and "loose" +/// (`<=`, `>=`), the latter of which admit equality. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum InequalityKind { + /// Strict inequality: {less,greater}-than. + Strict, + /// Loose inequality: {less,greater}-than-or-equal. + Loose, +} + +/// A "context" in which we can evaluate and derive facts. This +/// context carries environment/global properties, such as the machine +/// pointer width. +pub struct FactContext<'a> { + function: &'a ir::Function, + pointer_width: u16, +} + +impl<'a> FactContext<'a> { + /// Create a new "fact context" in which to evaluate facts. + pub fn new(function: &'a ir::Function, pointer_width: u16) -> Self { + FactContext { + function, + pointer_width, + } + } + + /// Computes whether `lhs` "subsumes" (implies) `rhs`. + pub fn subsumes(&self, lhs: &Fact, rhs: &Fact) -> bool { + match (lhs, rhs) { + // Reflexivity. + (l, r) if l == r => true, + + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) => { + // If the bitwidths we're claiming facts about are the + // same, or the left-hand-side makes a claim about a + // wider bitwidth, and if the right-hand-side range is + // larger than the left-hand-side range, than the LHS + // subsumes the RHS. + // + // In other words, we can always expand the claimed + // possible value range. + bw_lhs >= bw_rhs && max_lhs <= max_rhs && min_lhs >= min_rhs + } + + ( + Fact::DynamicRange { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::DynamicRange { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) => { + // Nearly same as above, but with dynamic-expression + // comparisons. Note that we require equal bitwidths + // here: unlike in the static case, we don't have + // fixed values for min and max, so we can't lean on + // the well-formedness requirements of the static + // ranges fitting within the bit-width max. + bw_lhs == bw_rhs && Expr::le(max_lhs, max_rhs) && Expr::le(min_rhs, min_lhs) + } + + ( + Fact::Mem { + ty: ty_lhs, + min_offset: min_offset_lhs, + max_offset: max_offset_lhs, + nullable: nullable_lhs, + }, + Fact::Mem { + ty: ty_rhs, + min_offset: min_offset_rhs, + max_offset: max_offset_rhs, + nullable: nullable_rhs, + }, + ) => { + ty_lhs == ty_rhs + && max_offset_lhs <= max_offset_rhs + && min_offset_lhs >= min_offset_rhs + && (*nullable_lhs || !*nullable_rhs) + } + + ( + Fact::DynamicMem { + ty: ty_lhs, + min: min_lhs, + max: max_lhs, + nullable: nullable_lhs, + }, + Fact::DynamicMem { + ty: ty_rhs, + min: min_rhs, + max: max_rhs, + nullable: nullable_rhs, + }, + ) => { + ty_lhs == ty_rhs + && Expr::le(max_lhs, max_rhs) + && Expr::le(min_rhs, min_lhs) + && (*nullable_lhs || !*nullable_rhs) + } + + // Constant zero subsumes nullable DynamicMem pointers. + ( + Fact::Range { + bit_width, + min: 0, + max: 0, + }, + Fact::DynamicMem { nullable: true, .. }, + ) if *bit_width == self.pointer_width => true, + + // Any fact subsumes a Def, because the Def makes no + // claims about the actual value (it ties a symbol to that + // value, but the value is fed to the symbol, not the + // other way around). + (_, Fact::Def { .. }) => true, + + _ => false, + } + } + + /// Computes whether the optional fact `lhs` subsumes (implies) + /// the optional fact `lhs`. A `None` never subsumes any fact, and + /// is always subsumed by any fact at all (or no fact). + pub fn subsumes_fact_optionals(&self, lhs: Option<&Fact>, rhs: Option<&Fact>) -> bool { + match (lhs, rhs) { + (None, None) => true, + (Some(_), None) => true, + (None, Some(_)) => false, + (Some(lhs), Some(rhs)) => self.subsumes(lhs, rhs), + } + } + + /// Computes whatever fact can be known about the sum of two + /// values with attached facts. The add is performed to the given + /// bit-width. Note that this is distinct from the machine or + /// pointer width: e.g., many 64-bit machines can still do 32-bit + /// adds that wrap at 2^32. + pub fn add(&self, lhs: &Fact, rhs: &Fact, add_width: u16) -> Option { + let result = match (lhs, rhs) { + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) if bw_lhs == bw_rhs && add_width >= *bw_lhs => { + let computed_min = min_lhs.checked_add(*min_rhs)?; + let computed_max = max_lhs.checked_add(*max_rhs)?; + let computed_max = std::cmp::min(max_value_for_width(add_width), computed_max); + Some(Fact::Range { + bit_width: *bw_lhs, + min: computed_min, + max: computed_max, + }) + } + + ( + Fact::Range { + bit_width: bw_max, + min, + max, + }, + Fact::Mem { + ty, + min_offset, + max_offset, + nullable, + }, + ) + | ( + Fact::Mem { + ty, + min_offset, + max_offset, + nullable, + }, + Fact::Range { + bit_width: bw_max, + min, + max, + }, + ) if *bw_max >= self.pointer_width + && add_width >= *bw_max + && (!*nullable || *max == 0) => + { + let min_offset = min_offset.checked_add(*min)?; + let max_offset = max_offset.checked_add(*max)?; + Some(Fact::Mem { + ty: *ty, + min_offset, + max_offset, + nullable: false, + }) + } + + ( + Fact::Range { + bit_width: bw_static, + min: min_static, + max: max_static, + }, + Fact::DynamicRange { + bit_width: bw_dynamic, + min: ref min_dynamic, + max: ref max_dynamic, + }, + ) + | ( + Fact::DynamicRange { + bit_width: bw_dynamic, + min: ref min_dynamic, + max: ref max_dynamic, + }, + Fact::Range { + bit_width: bw_static, + min: min_static, + max: max_static, + }, + ) if bw_static == bw_dynamic => { + let min = Expr::offset(min_dynamic, i64::try_from(*min_static).ok()?)?; + let max = Expr::offset(max_dynamic, i64::try_from(*max_static).ok()?)?; + Some(Fact::DynamicRange { + bit_width: *bw_dynamic, + min, + max, + }) + } + + ( + Fact::DynamicMem { + ty, + min: min_mem, + max: max_mem, + nullable: false, + }, + Fact::DynamicRange { + bit_width, + min: min_range, + max: max_range, + }, + ) + | ( + Fact::DynamicRange { + bit_width, + min: min_range, + max: max_range, + }, + Fact::DynamicMem { + ty, + min: min_mem, + max: max_mem, + nullable: false, + }, + ) if *bit_width == self.pointer_width => { + let min = Expr::add(min_mem, min_range)?; + let max = Expr::add(max_mem, max_range)?; + Some(Fact::DynamicMem { + ty: *ty, + min, + max, + nullable: false, + }) + } + + ( + Fact::Mem { + ty, + min_offset, + max_offset, + nullable: false, + }, + Fact::DynamicRange { + bit_width, + min: min_range, + max: max_range, + }, + ) + | ( + Fact::DynamicRange { + bit_width, + min: min_range, + max: max_range, + }, + Fact::Mem { + ty, + min_offset, + max_offset, + nullable: false, + }, + ) if *bit_width == self.pointer_width => { + let min = Expr::offset(min_range, i64::try_from(*min_offset).ok()?)?; + let max = Expr::offset(max_range, i64::try_from(*max_offset).ok()?)?; + Some(Fact::DynamicMem { + ty: *ty, + min, + max, + nullable: false, + }) + } + + ( + Fact::Range { + bit_width: bw_static, + min: min_static, + max: max_static, + }, + Fact::DynamicMem { + ty, + min: ref min_dynamic, + max: ref max_dynamic, + nullable, + }, + ) + | ( + Fact::DynamicMem { + ty, + min: ref min_dynamic, + max: ref max_dynamic, + nullable, + }, + Fact::Range { + bit_width: bw_static, + min: min_static, + max: max_static, + }, + ) if *bw_static == self.pointer_width && (!*nullable || *max_static == 0) => { + let min = Expr::offset(min_dynamic, i64::try_from(*min_static).ok()?)?; + let max = Expr::offset(max_dynamic, i64::try_from(*max_static).ok()?)?; + Some(Fact::DynamicMem { + ty: *ty, + min, + max, + nullable: false, + }) + } + + _ => None, + }; + + trace!("add: {lhs:?} + {rhs:?} -> {result:?}"); + result + } + + /// Computes the `uextend` of a value with the given facts. + pub fn uextend(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + if from_width == to_width { + return Some(fact.clone()); + } + + let result = match fact { + // If the claim is already for a same-or-wider value and the min + // and max are within range of the narrower value, we can + // claim the same range. + Fact::Range { + bit_width, + min, + max, + } if *bit_width >= from_width + && *min <= max_value_for_width(from_width) + && *max <= max_value_for_width(from_width) => + { + Some(Fact::Range { + bit_width: to_width, + min: *min, + max: *max, + }) + } + + // If the claim is a dynamic range for the from-width, we + // can extend to the to-width. + Fact::DynamicRange { + bit_width, + min, + max, + } if *bit_width == from_width => Some(Fact::DynamicRange { + bit_width: to_width, + min: min.clone(), + max: max.clone(), + }), + + // If the claim is a definition of a value, we can say + // that the output has a range of exactly that value. + Fact::Def { value } => Some(Fact::value(to_width, *value)), + + // Otherwise, we can at least claim that the value is + // within the range of `from_width`. + Fact::Range { .. } => Some(Fact::max_range_for_width_extended(from_width, to_width)), + + _ => None, + }; + trace!("uextend: fact {fact:?} from {from_width} to {to_width} -> {result:?}"); + result + } + + /// Computes the `sextend` of a value with the given facts. + pub fn sextend(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + match fact { + // If we have a defined value in bits 0..bit_width, and + // the MSB w.r.t. `from_width` is *not* set, then we can + // do the same as `uextend`. + Fact::Range { + bit_width, + // We can ignore `min`: it is always <= max in + // unsigned terms, and we check max's LSB below. + min: _, + max, + } if *bit_width == from_width && (*max & (1 << (*bit_width - 1)) == 0) => { + self.uextend(fact, from_width, to_width) + } + _ => None, + } + } + + /// Computes the bit-truncation of a value with the given fact. + pub fn truncate(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + if from_width == to_width { + return Some(fact.clone()); + } + + trace!( + "truncate: fact {:?} from {} to {}", + fact, + from_width, + to_width + ); + + match fact { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == from_width => { + let max_val = (1u64 << to_width) - 1; + if *min <= max_val && *max <= max_val { + Some(Fact::Range { + bit_width: to_width, + min: *min, + max: *max, + }) + } else { + Some(Fact::Range { + bit_width: to_width, + min: 0, + max: max_val, + }) + } + } + _ => None, + } + } + + /// Scales a value with a fact by a known constant. + pub fn scale(&self, fact: &Fact, width: u16, factor: u32) -> Option { + let result = match fact { + x if factor == 1 => Some(x.clone()), + + Fact::Range { + bit_width, + min, + max, + } if *bit_width == width => { + let min = min.checked_mul(u64::from(factor))?; + let max = max.checked_mul(u64::from(factor))?; + if *bit_width < 64 && max > max_value_for_width(width) { + return None; + } + Some(Fact::Range { + bit_width: *bit_width, + min, + max, + }) + } + _ => None, + }; + trace!("scale: {fact:?} * {factor} at width {width} -> {result:?}"); + result + } + + /// Left-shifts a value with a fact by a known constant. + pub fn shl(&self, fact: &Fact, width: u16, amount: u16) -> Option { + if amount >= 32 { + return None; + } + let factor: u32 = 1 << amount; + self.scale(fact, width, factor) + } + + /// Offsets a value with a fact by a known amount. + pub fn offset(&self, fact: &Fact, width: u16, offset: i64) -> Option { + if offset == 0 { + return Some(fact.clone()); + } + + let compute_offset = |base: u64| -> Option { + if offset >= 0 { + base.checked_add(u64::try_from(offset).unwrap()) + } else { + base.checked_sub(u64::try_from(-offset).unwrap()) + } + }; + + let result = match fact { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == width => { + let min = compute_offset(*min)?; + let max = compute_offset(*max)?; + Some(Fact::Range { + bit_width: *bit_width, + min, + max, + }) + } + Fact::DynamicRange { + bit_width, + min, + max, + } if *bit_width == width => { + let min = Expr::offset(min, offset)?; + let max = Expr::offset(max, offset)?; + Some(Fact::DynamicRange { + bit_width: *bit_width, + min, + max, + }) + } + Fact::Mem { + ty, + min_offset: mem_min_offset, + max_offset: mem_max_offset, + nullable: false, + } => { + let min_offset = compute_offset(*mem_min_offset)?; + let max_offset = compute_offset(*mem_max_offset)?; + Some(Fact::Mem { + ty: *ty, + min_offset, + max_offset, + nullable: false, + }) + } + Fact::DynamicMem { + ty, + min, + max, + nullable: false, + } => { + let min = Expr::offset(min, offset)?; + let max = Expr::offset(max, offset)?; + Some(Fact::DynamicMem { + ty: *ty, + min, + max, + nullable: false, + }) + } + _ => None, + }; + trace!("offset: {fact:?} + {offset} in width {width} -> {result:?}"); + result + } + + /// Check that accessing memory via a pointer with this fact, with + /// a memory access of the given size, is valid. + /// + /// If valid, returns the memory type and offset into that type + /// that this address accesses, if known, or `None` if the range + /// doesn't constrain the access to exactly one location. + fn check_address(&self, fact: &Fact, size: u32) -> PccResult> { + trace!("check_address: fact {:?} size {}", fact, size); + match fact { + Fact::Mem { + ty, + min_offset, + max_offset, + nullable: _, + } => { + let end_offset: u64 = max_offset + .checked_add(u64::from(size)) + .ok_or(PccError::Overflow)?; + match &self.function.memory_types[*ty] { + ir::MemoryTypeData::Struct { size, .. } + | ir::MemoryTypeData::Memory { size } => { + ensure!(end_offset <= *size, OutOfBounds) + } + ir::MemoryTypeData::DynamicMemory { .. } => bail!(OutOfBounds), + ir::MemoryTypeData::Empty => bail!(OutOfBounds), + } + let specific_ty_and_offset = if min_offset == max_offset { + Some((*ty, *min_offset)) + } else { + None + }; + Ok(specific_ty_and_offset) + } + Fact::DynamicMem { + ty, + min: _, + max: + Expr { + base: BaseExpr::GlobalValue(max_gv), + offset: max_offset, + }, + nullable: _, + } => match &self.function.memory_types[*ty] { + ir::MemoryTypeData::DynamicMemory { + gv, + size: mem_static_size, + } if gv == max_gv => { + let end_offset = max_offset + .checked_add(i64::from(size)) + .ok_or(PccError::Overflow)?; + let mem_static_size = + i64::try_from(*mem_static_size).map_err(|_| PccError::Overflow)?; + ensure!(end_offset <= mem_static_size, OutOfBounds); + Ok(None) + } + _ => bail!(OutOfBounds), + }, + _ => bail!(OutOfBounds), + } + } + + /// Get the access struct field, if any, by a pointer with the + /// given fact and an access of the given type. + pub fn struct_field<'b>( + &'b self, + fact: &Fact, + access_ty: ir::Type, + ) -> PccResult> { + let (ty, offset) = match self.check_address(fact, access_ty.bytes())? { + Some((ty, offset)) => (ty, offset), + None => return Ok(None), + }; + + if let ir::MemoryTypeData::Struct { fields, .. } = &self.function.memory_types[ty] { + let field = fields + .iter() + .find(|field| field.offset == offset) + .ok_or(PccError::InvalidFieldOffset)?; + if field.ty != access_ty { + bail!(BadFieldType); + } + Ok(Some(field)) + } else { + // Access to valid memory, but not a struct: no facts can be attached to the result. + Ok(None) + } + } + + /// Check a load, and determine what fact, if any, the result of the load might have. + pub fn load<'b>(&'b self, fact: &Fact, access_ty: ir::Type) -> PccResult> { + Ok(self + .struct_field(fact, access_ty)? + .and_then(|field| field.fact())) + } + + /// Check a store. + pub fn store( + &self, + fact: &Fact, + access_ty: ir::Type, + data_fact: Option<&Fact>, + ) -> PccResult<()> { + if let Some(field) = self.struct_field(fact, access_ty)? { + // If it's a read-only field, disallow. + if field.readonly { + bail!(WriteToReadOnlyField); + } + // Check that the fact on the stored data subsumes the field's fact. + if !self.subsumes_fact_optionals(data_fact, field.fact()) { + bail!(InvalidStoredFact); + } + } + Ok(()) + } + + /// Apply a known inequality to rewrite dynamic bounds using transitivity, if possible. + /// + /// Given that `lhs >= rhs` (if not `strict`) or `lhs > rhs` (if + /// `strict`), update `fact`. + pub fn apply_inequality( + &self, + fact: &Fact, + lhs: &Fact, + rhs: &Fact, + kind: InequalityKind, + ) -> Fact { + let result = match ( + lhs.as_symbol(), + lhs.as_const(self.pointer_width) + .and_then(|k| i64::try_from(k).ok()), + rhs.as_symbol(), + fact, + ) { + ( + Some(lhs), + None, + Some(rhs), + Fact::DynamicMem { + ty, + min, + max, + nullable, + }, + ) if rhs.base == max.base => { + let strict_offset = match kind { + InequalityKind::Strict => 1, + InequalityKind::Loose => 0, + }; + if let Some(offset) = max + .offset + .checked_add(lhs.offset) + .and_then(|x| x.checked_sub(rhs.offset)) + .and_then(|x| x.checked_sub(strict_offset)) + { + let new_max = Expr { + base: lhs.base.clone(), + offset, + }; + Fact::DynamicMem { + ty: *ty, + min: min.clone(), + max: new_max, + nullable: *nullable, + } + } else { + fact.clone() + } + } + + ( + None, + Some(lhs_const), + Some(rhs), + Fact::DynamicMem { + ty, + min: _, + max, + nullable, + }, + ) if rhs.base == max.base => { + let strict_offset = match kind { + InequalityKind::Strict => 1, + InequalityKind::Loose => 0, + }; + if let Some(offset) = max + .offset + .checked_add(lhs_const) + .and_then(|x| x.checked_sub(rhs.offset)) + .and_then(|x| x.checked_sub(strict_offset)) + { + Fact::Mem { + ty: *ty, + min_offset: 0, + max_offset: u64::try_from(offset).unwrap_or(0), + nullable: *nullable, + } + } else { + fact.clone() + } + } + + _ => fact.clone(), + }; + trace!("apply_inequality({fact:?}, {lhs:?}, {rhs:?}, {kind:?} -> {result:?}"); + result + } + + /// Compute the union of two facts, if possible. + pub fn union(&self, lhs: &Fact, rhs: &Fact) -> Option { + let result = match (lhs, rhs) { + (lhs, rhs) if lhs == rhs => Some(lhs.clone()), + + ( + Fact::DynamicMem { + ty: ty_lhs, + min: min_lhs, + max: max_lhs, + nullable: nullable_lhs, + }, + Fact::DynamicMem { + ty: ty_rhs, + min: min_rhs, + max: max_rhs, + nullable: nullable_rhs, + }, + ) if ty_lhs == ty_rhs => Some(Fact::DynamicMem { + ty: *ty_lhs, + min: Expr::min(min_lhs, min_rhs), + max: Expr::max(max_lhs, max_rhs), + nullable: *nullable_lhs || *nullable_rhs, + }), + + ( + Fact::Range { + bit_width: bw_const, + min: 0, + max: 0, + }, + Fact::DynamicMem { + ty, + min, + max, + nullable: _, + }, + ) + | ( + Fact::DynamicMem { + ty, + min, + max, + nullable: _, + }, + Fact::Range { + bit_width: bw_const, + min: 0, + max: 0, + }, + ) if *bw_const == self.pointer_width => Some(Fact::DynamicMem { + ty: *ty, + min: min.clone(), + max: max.clone(), + nullable: true, + }), + + ( + Fact::Range { + bit_width: bw_const, + min: 0, + max: 0, + }, + Fact::Mem { + ty, + min_offset, + max_offset, + nullable: _, + }, + ) + | ( + Fact::Mem { + ty, + min_offset, + max_offset, + nullable: _, + }, + Fact::Range { + bit_width: bw_const, + min: 0, + max: 0, + }, + ) if *bw_const == self.pointer_width => Some(Fact::Mem { + ty: *ty, + min_offset: *min_offset, + max_offset: *max_offset, + nullable: true, + }), + + _ => None, + }; + trace!("union({lhs:?}, {rhs:?}) -> {result:?}"); + result + } +} + +fn max_value_for_width(bits: u16) -> u64 { + assert!(bits <= 64); + if bits == 64 { + u64::MAX + } else { + (1u64 << bits) - 1 + } +} + +/// Top-level entry point after compilation: this checks the facts in +/// VCode. +pub fn check_vcode_facts( + f: &ir::Function, + vcode: &mut VCode, + backend: &B, +) -> PccResult<()> { + let ctx = FactContext::new(f, backend.triple().pointer_width().unwrap().bits().into()); + + // Check that individual instructions are valid according to input + // facts, and support the stated output facts. + for block in 0..vcode.num_blocks() { + let block = BlockIndex::new(block); + let mut flow_state = B::FactFlowState::default(); + for inst in vcode.block_insns(block).iter() { + // Check any output facts on this inst. + if let Err(e) = backend.check_fact(&ctx, vcode, inst, &mut flow_state) { + log::info!("Error checking instruction: {:?}", vcode[inst]); + return Err(e); + } + + // If this is a branch, check that all block arguments subsume + // the assumed facts on the blockparams of successors. + if vcode.is_branch(inst) { + for (succ_idx, succ) in vcode.block_succs(block).iter().enumerate() { + for (arg, param) in vcode + .branch_blockparams(block, inst, succ_idx) + .iter() + .zip(vcode.block_params(*succ).iter()) + { + let arg_fact = vcode.vreg_fact(*arg); + let param_fact = vcode.vreg_fact(*param); + if !ctx.subsumes_fact_optionals(arg_fact, param_fact) { + return Err(PccError::UnsupportedBlockparam); + } + } + } + } + } + } + Ok(()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/progpoint.rs b/deps/crates/vendor/cranelift-codegen/src/ir/progpoint.rs new file mode 100644 index 00000000000000..84d394276f6702 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/progpoint.rs @@ -0,0 +1,75 @@ +//! Program points. + +use crate::ir::{Block, Inst}; +use core::fmt; + +/// A `ProgramPoint` represents a position in a function where the live range of an SSA value can +/// begin or end. It can be either: +/// +/// 1. An instruction or +/// 2. A block header. +/// +/// This corresponds more or less to the lines in the textual form of Cranelift IR. +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum ProgramPoint { + /// An instruction in the function. + Inst(Inst), + /// A block header. + Block(Block), +} + +impl ProgramPoint { + /// Get the instruction we know is inside. + pub fn unwrap_inst(self) -> Inst { + match self { + Self::Inst(x) => x, + Self::Block(x) => panic!("expected inst: {x}"), + } + } +} + +impl From for ProgramPoint { + fn from(inst: Inst) -> Self { + Self::Inst(inst) + } +} + +impl From for ProgramPoint { + fn from(block: Block) -> Self { + Self::Block(block) + } +} + +impl fmt::Display for ProgramPoint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Inst(x) => write!(f, "{x}"), + Self::Block(x) => write!(f, "{x}"), + } + } +} + +impl fmt::Debug for ProgramPoint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ProgramPoint({self})") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::entity::EntityRef; + use alloc::string::ToString; + + #[test] + fn convert() { + let i5 = Inst::new(5); + let b3 = Block::new(3); + + let pp1: ProgramPoint = i5.into(); + let pp2: ProgramPoint = b3.into(); + + assert_eq!(pp1.to_string(), "inst5"); + assert_eq!(pp2.to_string(), "block3"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/sourceloc.rs b/deps/crates/vendor/cranelift-codegen/src/ir/sourceloc.rs new file mode 100644 index 00000000000000..6704574d0d09b0 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/sourceloc.rs @@ -0,0 +1,117 @@ +//! Source locations. +//! +//! Cranelift tracks the original source location of each instruction, and preserves the source +//! location when instructions are transformed. + +use core::fmt; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A source location. +/// +/// This is an opaque 32-bit number attached to each Cranelift IR instruction. Cranelift does not +/// interpret source locations in any way, they are simply preserved from the input to the output. +/// +/// The default source location uses the all-ones bit pattern `!0`. It is used for instructions +/// that can't be given a real source location. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct SourceLoc(u32); + +impl SourceLoc { + /// Create a new source location with the given bits. + pub fn new(bits: u32) -> Self { + Self(bits) + } + + /// Is this the default source location? + pub fn is_default(self) -> bool { + self == Default::default() + } + + /// Read the bits of this source location. + pub fn bits(self) -> u32 { + self.0 + } +} + +impl Default for SourceLoc { + fn default() -> Self { + Self(!0) + } +} + +impl fmt::Display for SourceLoc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_default() { + write!(f, "@-") + } else { + write!(f, "@{:04x}", self.0) + } + } +} + +/// Source location relative to another base source location. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct RelSourceLoc(u32); + +impl RelSourceLoc { + /// Create a new relative source location with the given bits. + pub fn new(bits: u32) -> Self { + Self(bits) + } + + /// Creates a new `RelSourceLoc` based on the given base and offset. + pub fn from_base_offset(base: SourceLoc, offset: SourceLoc) -> Self { + if base.is_default() || offset.is_default() { + Self::default() + } else { + Self(offset.bits().wrapping_sub(base.bits())) + } + } + + /// Expands the relative source location into an absolute one, using the given base. + pub fn expand(&self, base: SourceLoc) -> SourceLoc { + if self.is_default() || base.is_default() { + Default::default() + } else { + SourceLoc::new(self.0.wrapping_add(base.bits())) + } + } + + /// Is this the default relative source location? + pub fn is_default(self) -> bool { + self == Default::default() + } +} + +impl Default for RelSourceLoc { + fn default() -> Self { + Self(!0) + } +} + +impl fmt::Display for RelSourceLoc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_default() { + write!(f, "@-") + } else { + write!(f, "@+{:04x}", self.0) + } + } +} + +#[cfg(test)] +mod tests { + use crate::ir::SourceLoc; + use alloc::string::ToString; + + #[test] + fn display() { + assert_eq!(SourceLoc::default().to_string(), "@-"); + assert_eq!(SourceLoc::new(0).to_string(), "@0000"); + assert_eq!(SourceLoc::new(16).to_string(), "@0010"); + assert_eq!(SourceLoc::new(0xabcdef).to_string(), "@abcdef"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/stackslot.rs b/deps/crates/vendor/cranelift-codegen/src/ir/stackslot.rs new file mode 100644 index 00000000000000..d906fb29132472 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/stackslot.rs @@ -0,0 +1,208 @@ +//! Stack slots. +//! +//! The `StackSlotData` struct keeps track of a single stack slot in a function. +//! + +use crate::entity::PrimaryMap; +use crate::ir::entities::{DynamicStackSlot, DynamicType}; +use crate::ir::StackSlot; +use core::fmt; +use core::str::FromStr; + +/// imports only needed for testing. +#[allow(unused_imports)] +use crate::ir::{DynamicTypeData, GlobalValueData}; + +#[allow(unused_imports)] +use crate::ir::types::*; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// The size of an object on the stack, or the size of a stack frame. +/// +/// We don't use `usize` to represent object sizes on the target platform because Cranelift supports +/// cross-compilation, and `usize` is a type that depends on the host platform, not the target +/// platform. +pub type StackSize = u32; + +/// The kind of a stack slot. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum StackSlotKind { + /// An explicit stack slot. This is a chunk of stack memory for use by the `stack_load` + /// and `stack_store` instructions. + ExplicitSlot, + /// An explicit stack slot for dynamic vector types. This is a chunk of stack memory + /// for use by the `dynamic_stack_load` and `dynamic_stack_store` instructions. + ExplicitDynamicSlot, +} + +impl FromStr for StackSlotKind { + type Err = (); + + fn from_str(s: &str) -> Result { + use self::StackSlotKind::*; + match s { + "explicit_slot" => Ok(ExplicitSlot), + "explicit_dynamic_slot" => Ok(ExplicitDynamicSlot), + _ => Err(()), + } + } +} + +impl fmt::Display for StackSlotKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::StackSlotKind::*; + f.write_str(match *self { + ExplicitSlot => "explicit_slot", + ExplicitDynamicSlot => "explicit_dynamic_slot", + }) + } +} + +/// Contents of a stack slot. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct StackSlotData { + /// The kind of stack slot. + pub kind: StackSlotKind, + + /// Size of stack slot in bytes. + pub size: StackSize, + + /// Alignment of stack slot as a power-of-two exponent (log2 + /// value). The stack slot will be at least this aligned; it may + /// be aligned according to other considerations, such as minimum + /// stack slot size or machine word size, as well. + pub align_shift: u8, +} + +impl StackSlotData { + /// Create a stack slot with the specified byte size and alignment. + pub fn new(kind: StackSlotKind, size: StackSize, align_shift: u8) -> Self { + Self { + kind, + size, + align_shift, + } + } +} + +impl fmt::Display for StackSlotData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.align_shift != 0 { + write!( + f, + "{} {}, align = {}", + self.kind, + self.size, + 1u32 << self.align_shift + ) + } else { + write!(f, "{} {}", self.kind, self.size) + } + } +} + +/// Contents of a dynamic stack slot. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct DynamicStackSlotData { + /// The kind of stack slot. + pub kind: StackSlotKind, + + /// The type of this slot. + pub dyn_ty: DynamicType, +} + +impl DynamicStackSlotData { + /// Create a stack slot with the specified byte size. + pub fn new(kind: StackSlotKind, dyn_ty: DynamicType) -> Self { + assert!(kind == StackSlotKind::ExplicitDynamicSlot); + Self { kind, dyn_ty } + } + + /// Get the alignment in bytes of this stack slot given the stack pointer alignment. + pub fn alignment(&self, max_align: StackSize) -> StackSize { + debug_assert!(max_align.is_power_of_two()); + max_align + } +} + +impl fmt::Display for DynamicStackSlotData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.kind, self.dyn_ty) + } +} + +/// All allocated stack slots. +pub type StackSlots = PrimaryMap; + +/// All allocated dynamic stack slots. +pub type DynamicStackSlots = PrimaryMap; + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::Function; + use alloc::string::ToString; + + #[test] + fn stack_slot() { + let mut func = Function::new(); + + let ss0 = + func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0)); + let ss1 = + func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 8, 0)); + assert_eq!(ss0.to_string(), "ss0"); + assert_eq!(ss1.to_string(), "ss1"); + + assert_eq!(func.sized_stack_slots[ss0].size, 4); + assert_eq!(func.sized_stack_slots[ss1].size, 8); + + assert_eq!(func.sized_stack_slots[ss0].to_string(), "explicit_slot 4"); + assert_eq!(func.sized_stack_slots[ss1].to_string(), "explicit_slot 8"); + } + + #[test] + fn dynamic_stack_slot() { + let mut func = Function::new(); + + let int_vector_ty = I32X4; + let fp_vector_ty = F64X2; + let scale0 = GlobalValueData::DynScaleTargetConst { + vector_type: int_vector_ty, + }; + let scale1 = GlobalValueData::DynScaleTargetConst { + vector_type: fp_vector_ty, + }; + let gv0 = func.create_global_value(scale0); + let gv1 = func.create_global_value(scale1); + let dtd0 = DynamicTypeData::new(int_vector_ty, gv0); + let dtd1 = DynamicTypeData::new(fp_vector_ty, gv1); + let dt0 = func.dfg.make_dynamic_ty(dtd0); + let dt1 = func.dfg.make_dynamic_ty(dtd1); + + let dss0 = func.create_dynamic_stack_slot(DynamicStackSlotData::new( + StackSlotKind::ExplicitDynamicSlot, + dt0, + )); + let dss1 = func.create_dynamic_stack_slot(DynamicStackSlotData::new( + StackSlotKind::ExplicitDynamicSlot, + dt1, + )); + assert_eq!(dss0.to_string(), "dss0"); + assert_eq!(dss1.to_string(), "dss1"); + + assert_eq!( + func.dynamic_stack_slots[dss0].to_string(), + "explicit_dynamic_slot dt0" + ); + assert_eq!( + func.dynamic_stack_slots[dss1].to_string(), + "explicit_dynamic_slot dt1" + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/trapcode.rs b/deps/crates/vendor/cranelift-codegen/src/ir/trapcode.rs new file mode 100644 index 00000000000000..e3fbcfbb4a5009 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/trapcode.rs @@ -0,0 +1,147 @@ +//! Trap codes describing the reason for a trap. + +use core::fmt::{self, Display, Formatter}; +use core::num::NonZeroU8; +use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A trap code describing the reason for a trap. +/// +/// All trap instructions have an explicit trap code. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct TrapCode(NonZeroU8); + +impl TrapCode { + /// Number of reserved opcodes for Cranelift itself. This number of traps are + /// defined below starting at the high end of the byte space (e.g. 255, 254, + /// ...) + const RESERVED: u8 = 5; + const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1; + + /// Internal helper to create new reserved trap codes. + const fn reserved(byte: u8) -> TrapCode { + if let Some(code) = byte.checked_add(Self::RESERVED_START) { + if let Some(nz) = NonZeroU8::new(code) { + return TrapCode(nz); + } + } + panic!("invalid reserved opcode") + } + + /// The current stack space was exhausted. + pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0); + /// An integer arithmetic operation caused an overflow. + pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1); + /// A `heap_addr` instruction detected an out-of-bounds error. + /// + /// Note that not all out-of-bounds heap accesses are reported this way; + /// some are detected by a segmentation fault on the heap unmapped or + /// offset-guard pages. + pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2); + + /// An integer division by zero. + pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3); + + /// Failed float-to-int conversion. + pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4); + + /// Create a user-defined trap code. + /// + /// Returns `None` if `code` is zero or too large and is reserved by + /// Cranelift. + pub const fn user(code: u8) -> Option { + if code >= Self::RESERVED_START { + return None; + } + match NonZeroU8::new(code) { + Some(nz) => Some(TrapCode(nz)), + None => None, + } + } + + /// Alias for [`TrapCode::user`] with a panic built-in. + pub const fn unwrap_user(code: u8) -> TrapCode { + match TrapCode::user(code) { + Some(code) => code, + None => panic!("invalid user trap code"), + } + } + + /// Returns the raw byte representing this trap. + pub const fn as_raw(&self) -> NonZeroU8 { + self.0 + } + + /// Creates a trap code from its raw byte, likely returned by + /// [`TrapCode::as_raw`] previously. + pub const fn from_raw(byte: NonZeroU8) -> TrapCode { + TrapCode(byte) + } + + /// Returns a slice of all traps except `TrapCode::User` traps + pub const fn non_user_traps() -> &'static [TrapCode] { + &[ + TrapCode::STACK_OVERFLOW, + TrapCode::HEAP_OUT_OF_BOUNDS, + TrapCode::INTEGER_OVERFLOW, + TrapCode::INTEGER_DIVISION_BY_ZERO, + TrapCode::BAD_CONVERSION_TO_INTEGER, + ] + } +} + +impl Display for TrapCode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let identifier = match *self { + Self::STACK_OVERFLOW => "stk_ovf", + Self::HEAP_OUT_OF_BOUNDS => "heap_oob", + Self::INTEGER_OVERFLOW => "int_ovf", + Self::INTEGER_DIVISION_BY_ZERO => "int_divz", + Self::BAD_CONVERSION_TO_INTEGER => "bad_toint", + TrapCode(x) => return write!(f, "user{x}"), + }; + f.write_str(identifier) + } +} + +impl FromStr for TrapCode { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "stk_ovf" => Ok(Self::STACK_OVERFLOW), + "heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS), + "int_ovf" => Ok(Self::INTEGER_OVERFLOW), + "int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO), + "bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER), + _ if s.starts_with("user") => { + let num = s[4..].parse().map_err(|_| ())?; + TrapCode::user(num).ok_or(()) + } + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn display() { + for r in TrapCode::non_user_traps() { + let tc = *r; + assert_eq!(tc.to_string().parse(), Ok(tc)); + } + assert_eq!("bogus".parse::(), Err(())); + + assert_eq!(TrapCode::unwrap_user(17).to_string(), "user17"); + assert_eq!("user22".parse(), Ok(TrapCode::unwrap_user(22))); + assert_eq!("user".parse::(), Err(())); + assert_eq!("user-1".parse::(), Err(())); + assert_eq!("users".parse::(), Err(())); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/types.rs b/deps/crates/vendor/cranelift-codegen/src/ir/types.rs new file mode 100644 index 00000000000000..bc7704cf06621b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/types.rs @@ -0,0 +1,624 @@ +//! Common types for the Cranelift code generator. + +use core::fmt::{self, Debug, Display, Formatter}; +use cranelift_codegen_shared::constants; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; +use target_lexicon::{PointerWidth, Triple}; + +/// The type of an SSA value. +/// +/// The `INVALID` type isn't a real type, and is used as a placeholder in the IR where a type +/// field is present put no type is needed, such as the controlling type variable for a +/// non-polymorphic instruction. +/// +/// Basic integer types: `I8`, `I16`, `I32`, `I64`, and `I128`. These types are sign-agnostic. +/// +/// Basic floating point types: `F16`, `F32`, `F64`, and `F128`. IEEE half, single, double, and quadruple precision. +/// +/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float type. +/// +/// Note that this is encoded in a `u16` currently for extensibility, +/// but allows only 14 bits to be used due to some bitpacking tricks +/// in the CLIF data structures. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Type(u16); + +/// Not a valid type. Can't be loaded or stored. Can't be part of a SIMD vector. +pub const INVALID: Type = Type(0); + +// Include code generated by `cranelift-codegen/meta/gen_types.rs`. This file contains constant +// definitions for all the scalar types as well as common vector types for 64, 128, 256, and +// 512-bit SIMD vectors. +include!(concat!(env!("OUT_DIR"), "/types.rs")); + +impl Type { + /// Get the lane type of this SIMD vector type. + /// + /// A lane type is the same as a SIMD vector type with one lane, so it returns itself. + pub fn lane_type(self) -> Self { + if self.0 < constants::VECTOR_BASE { + self + } else { + Self(constants::LANE_BASE | (self.0 & 0x0f)) + } + } + + /// The type transformation that returns the lane type of a type variable; it is just a + /// renaming of lane_type() to be used in context where we think in terms of type variable + /// transformations. + pub fn lane_of(self) -> Self { + self.lane_type() + } + + /// Get log_2 of the number of bits in a lane. + pub fn log2_lane_bits(self) -> u32 { + match self.lane_type() { + I8 => 3, + I16 | F16 => 4, + I32 | F32 => 5, + I64 | F64 => 6, + I128 | F128 => 7, + _ => 0, + } + } + + /// Get the number of bits in a lane. + pub fn lane_bits(self) -> u32 { + match self.lane_type() { + I8 => 8, + I16 | F16 => 16, + I32 | F32 => 32, + I64 | F64 => 64, + I128 | F128 => 128, + _ => 0, + } + } + + /// Get the (minimum, maximum) values represented by each lane in the type. + /// Note that these are returned as unsigned 'bit patterns'. + pub fn bounds(self, signed: bool) -> (u128, u128) { + if signed { + match self.lane_type() { + I8 => (i8::MIN as u128, i8::MAX as u128), + I16 => (i16::MIN as u128, i16::MAX as u128), + I32 => (i32::MIN as u128, i32::MAX as u128), + I64 => (i64::MIN as u128, i64::MAX as u128), + I128 => (i128::MIN as u128, i128::MAX as u128), + _ => unimplemented!(), + } + } else { + match self.lane_type() { + I8 => (u8::MIN as u128, u8::MAX as u128), + I16 => (u16::MIN as u128, u16::MAX as u128), + I32 => (u32::MIN as u128, u32::MAX as u128), + I64 => (u64::MIN as u128, u64::MAX as u128), + I128 => (u128::MIN, u128::MAX), + _ => unimplemented!(), + } + } + } + + /// Get an integer type with the requested number of bits. + /// + /// For the same thing but in *bytes*, use [`Self::int_with_byte_size`]. + pub fn int(bits: u16) -> Option { + match bits { + 8 => Some(I8), + 16 => Some(I16), + 32 => Some(I32), + 64 => Some(I64), + 128 => Some(I128), + _ => None, + } + } + + /// Get an integer type with the requested number of bytes. + /// + /// For the same thing but in *bits*, use [`Self::int`]. + pub fn int_with_byte_size(bytes: u16) -> Option { + Self::int(bytes.checked_mul(8)?) + } + + /// Get a type with the same number of lanes as `self`, but using `lane` as the lane type. + fn replace_lanes(self, lane: Self) -> Self { + debug_assert!(lane.is_lane() && !self.is_special()); + Self((lane.0 & 0x0f) | (self.0 & 0xf0)) + } + + /// Get a type with the same number of lanes as this type, but with the lanes replaced by + /// booleans of the same size. + /// + /// Lane types are treated as vectors with one lane, so they are converted to the multi-bit + /// boolean types. + pub fn as_truthy_pedantic(self) -> Self { + // Replace the low 4 bits with the boolean version, preserve the high 4 bits. + self.replace_lanes(match self.lane_type() { + I8 => I8, + I16 | F16 => I16, + I32 | F32 => I32, + I64 | F64 => I64, + I128 | F128 => I128, + _ => I8, + }) + } + + /// Get the type of a comparison result for the given type. For vectors this will be a vector + /// with the same number of lanes and integer elements, and for scalar types this will be `i8`, + /// which is the result type of comparisons. + pub fn as_truthy(self) -> Self { + if !self.is_vector() { + I8 + } else { + self.as_truthy_pedantic() + } + } + + /// Get a type with the same number of lanes as this type, but with the lanes replaced by + /// integers of the same size. + pub fn as_int(self) -> Self { + self.replace_lanes(match self.lane_type() { + I8 => I8, + I16 | F16 => I16, + I32 | F32 => I32, + I64 | F64 => I64, + I128 | F128 => I128, + _ => unimplemented!(), + }) + } + + /// Get a type with the same number of lanes as this type, but with lanes that are half the + /// number of bits. + pub fn half_width(self) -> Option { + Some(self.replace_lanes(match self.lane_type() { + I16 => I8, + I32 => I16, + I64 => I32, + I128 => I64, + F32 => F16, + F64 => F32, + F128 => F64, + _ => return None, + })) + } + + /// Get a type with the same number of lanes as this type, but with lanes that are twice the + /// number of bits. + pub fn double_width(self) -> Option { + Some(self.replace_lanes(match self.lane_type() { + I8 => I16, + I16 => I32, + I32 => I64, + I64 => I128, + F16 => F32, + F32 => F64, + F64 => F128, + _ => return None, + })) + } + + /// Is this the INVALID type? + pub fn is_invalid(self) -> bool { + self == INVALID + } + + /// Is this a special type? + pub fn is_special(self) -> bool { + self.0 < constants::LANE_BASE + } + + /// Is this a lane type? + /// + /// This is a scalar type that can also appear as the lane type of a SIMD vector. + pub fn is_lane(self) -> bool { + constants::LANE_BASE <= self.0 && self.0 < constants::VECTOR_BASE + } + + /// Is this a SIMD vector type? + /// + /// A vector type has 2 or more lanes. + pub fn is_vector(self) -> bool { + self.0 >= constants::VECTOR_BASE && !self.is_dynamic_vector() + } + + /// Is this a SIMD vector type with a runtime number of lanes? + pub fn is_dynamic_vector(self) -> bool { + self.0 >= constants::DYNAMIC_VECTOR_BASE + } + + /// Is this a scalar integer type? + pub fn is_int(self) -> bool { + match self { + I8 | I16 | I32 | I64 | I128 => true, + _ => false, + } + } + + /// Is this a scalar floating point type? + pub fn is_float(self) -> bool { + match self { + F16 | F32 | F64 | F128 => true, + _ => false, + } + } + + /// Get log_2 of the number of lanes in this SIMD vector type. + /// + /// All SIMD types have a lane count that is a power of two and no larger than 256, so this + /// will be a number in the range 0-8. + /// + /// A scalar type is the same as a SIMD vector type with one lane, so it returns 0. + pub fn log2_lane_count(self) -> u32 { + if self.is_dynamic_vector() { + 0 + } else { + (self.0.saturating_sub(constants::LANE_BASE) >> 4) as u32 + } + } + + /// Get log_2 of the number of lanes in this vector/dynamic type. + pub fn log2_min_lane_count(self) -> u32 { + if self.is_dynamic_vector() { + (self + .0 + .saturating_sub(constants::VECTOR_BASE + constants::LANE_BASE) + >> 4) as u32 + } else { + self.log2_lane_count() + } + } + + /// Get the number of lanes in this SIMD vector type. + /// + /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1. + pub fn lane_count(self) -> u32 { + if self.is_dynamic_vector() { + 0 + } else { + 1 << self.log2_lane_count() + } + } + + /// Get the total number of bits used to represent this type. + pub fn bits(self) -> u32 { + if self.is_dynamic_vector() { + 0 + } else { + self.lane_bits() * self.lane_count() + } + } + + /// Get the minimum of lanes in this SIMD vector type, this supports both fixed and + /// dynamic types. + pub fn min_lane_count(self) -> u32 { + if self.is_dynamic_vector() { + 1 << self.log2_min_lane_count() + } else { + 1 << self.log2_lane_count() + } + } + + /// Get the minimum number of bits used to represent this type. + pub fn min_bits(self) -> u32 { + if self.is_dynamic_vector() { + self.lane_bits() * self.min_lane_count() + } else { + self.bits() + } + } + + /// Get the number of bytes used to store this type in memory. + pub fn bytes(self) -> u32 { + (self.bits() + 7) / 8 + } + + /// Get a SIMD vector type with `n` times more lanes than this one. + /// + /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes. + /// + /// If this is already a SIMD vector type, this produces a SIMD vector type with `n * + /// self.lane_count()` lanes. + pub fn by(self, n: u32) -> Option { + if self.is_dynamic_vector() { + return None; + } + if self.lane_bits() == 0 || !n.is_power_of_two() { + return None; + } + let log2_lanes: u32 = n.trailing_zeros(); + let new_type = u32::from(self.0) + (log2_lanes << 4); + if new_type < constants::DYNAMIC_VECTOR_BASE as u32 + && (new_type as u16) < constants::DYNAMIC_VECTOR_BASE + { + Some(Self(new_type as u16)) + } else { + None + } + } + + /// Convert a fixed vector type to a dynamic one. + pub fn vector_to_dynamic(self) -> Option { + assert!(self.is_vector()); + if self.bits() > 256 { + return None; + } + let new_ty = self.0 + constants::VECTOR_BASE; + let ty = Some(Self(new_ty)); + assert!(ty.unwrap().is_dynamic_vector()); + return ty; + } + + /// Convert a dynamic vector type to a fixed one. + pub fn dynamic_to_vector(self) -> Option { + assert!(self.is_dynamic_vector()); + Some(Self(self.0 - constants::VECTOR_BASE)) + } + + /// Split the lane width in half and double the number of lanes to maintain the same bit-width. + /// + /// If this is a scalar type of `n` bits, it produces a SIMD vector type of `(n/2)x2`. + pub fn split_lanes(self) -> Option { + match self.half_width() { + Some(half_width) => half_width.by(2), + None => None, + } + } + + /// Merge lanes to half the number of lanes and double the lane width to maintain the same + /// bit-width. + /// + /// If this is a scalar type, it will return `None`. + pub fn merge_lanes(self) -> Option { + match self.double_width() { + Some(double_width) => { + if double_width.is_vector() && !double_width.is_dynamic_vector() { + Some(Self(double_width.0 - 0x10)) + } else { + None + } + } + None => None, + } + } + + /// Index of this type, for use with hash tables etc. + pub fn index(self) -> usize { + usize::from(self.0) + } + + /// True iff: + /// + /// 1. `self.lane_count() == other.lane_count()` and + /// 2. `self.lane_bits() >= other.lane_bits()` + pub fn wider_or_equal(self, other: Self) -> bool { + self.lane_count() == other.lane_count() && self.lane_bits() >= other.lane_bits() + } + + /// Return the pointer type for the given target triple. + pub fn triple_pointer_type(triple: &Triple) -> Self { + match triple.pointer_width() { + Ok(PointerWidth::U16) => I16, + Ok(PointerWidth::U32) => I32, + Ok(PointerWidth::U64) => I64, + Err(()) => panic!("unable to determine architecture pointer width"), + } + } + + /// Gets a bit-level representation of the type. Used only + /// internally for efficiently storing types. + pub(crate) fn repr(self) -> u16 { + self.0 + } + + /// Converts from a bit-level representation of the type back to a + /// `Type`. + pub(crate) fn from_repr(bits: u16) -> Type { + Type(bits) + } +} + +impl Display for Type { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.is_int() { + write!(f, "i{}", self.lane_bits()) + } else if self.is_float() { + write!(f, "f{}", self.lane_bits()) + } else if self.is_vector() { + write!(f, "{}x{}", self.lane_type(), self.lane_count()) + } else if self.is_dynamic_vector() { + write!(f, "{:?}x{}xN", self.lane_type(), self.min_lane_count()) + } else { + match *self { + INVALID => panic!("INVALID encountered"), + _ => panic!("Unknown Type(0x{:x})", self.0), + } + } + } +} + +impl Debug for Type { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.is_int() { + write!(f, "types::I{}", self.lane_bits()) + } else if self.is_float() { + write!(f, "types::F{}", self.lane_bits()) + } else if self.is_vector() { + write!(f, "{:?}X{}", self.lane_type(), self.lane_count()) + } else if self.is_dynamic_vector() { + write!(f, "{:?}X{}XN", self.lane_type(), self.min_lane_count()) + } else { + match *self { + INVALID => write!(f, "types::INVALID"), + _ => write!(f, "Type(0x{:x})", self.0), + } + } + } +} + +impl Default for Type { + fn default() -> Self { + INVALID + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn basic_scalars() { + assert_eq!(INVALID, INVALID.lane_type()); + assert_eq!(0, INVALID.bits()); + assert_eq!(I8, I8.lane_type()); + assert_eq!(I16, I16.lane_type()); + assert_eq!(I32, I32.lane_type()); + assert_eq!(I64, I64.lane_type()); + assert_eq!(I128, I128.lane_type()); + assert_eq!(F32, F32.lane_type()); + assert_eq!(F16, F16.lane_type()); + assert_eq!(F64, F64.lane_type()); + assert_eq!(F128, F128.lane_type()); + assert_eq!(I32, I32X4.lane_type()); + assert_eq!(F64, F64X2.lane_type()); + + assert_eq!(INVALID.lane_bits(), 0); + assert_eq!(I8.lane_bits(), 8); + assert_eq!(I16.lane_bits(), 16); + assert_eq!(I32.lane_bits(), 32); + assert_eq!(I64.lane_bits(), 64); + assert_eq!(I128.lane_bits(), 128); + assert_eq!(F16.lane_bits(), 16); + assert_eq!(F32.lane_bits(), 32); + assert_eq!(F64.lane_bits(), 64); + assert_eq!(F128.lane_bits(), 128); + } + + #[test] + fn typevar_functions() { + assert_eq!(INVALID.half_width(), None); + assert_eq!(INVALID.half_width(), None); + assert_eq!(I8.half_width(), None); + assert_eq!(I16.half_width(), Some(I8)); + assert_eq!(I32.half_width(), Some(I16)); + assert_eq!(I32X4.half_width(), Some(I16X4)); + assert_eq!(I64.half_width(), Some(I32)); + assert_eq!(I128.half_width(), Some(I64)); + assert_eq!(F16.half_width(), None); + assert_eq!(F32.half_width(), Some(F16)); + assert_eq!(F64.half_width(), Some(F32)); + assert_eq!(F128.half_width(), Some(F64)); + + assert_eq!(INVALID.double_width(), None); + assert_eq!(I8.double_width(), Some(I16)); + assert_eq!(I16.double_width(), Some(I32)); + assert_eq!(I32.double_width(), Some(I64)); + assert_eq!(I32X4.double_width(), Some(I64X4)); + assert_eq!(I64.double_width(), Some(I128)); + assert_eq!(I128.double_width(), None); + assert_eq!(F16.double_width(), Some(F32)); + assert_eq!(F32.double_width(), Some(F64)); + assert_eq!(F64.double_width(), Some(F128)); + assert_eq!(F128.double_width(), None); + } + + #[test] + fn vectors() { + let big = F64.by(256).unwrap(); + assert_eq!(big.lane_bits(), 64); + assert_eq!(big.lane_count(), 256); + assert_eq!(big.bits(), 64 * 256); + + // Check that the generated constants match the computed vector types. + assert_eq!(I32.by(4), Some(I32X4)); + assert_eq!(F64.by(8), Some(F64X8)); + } + + #[test] + fn dynamic_vectors() { + // Identification. + assert_eq!(I8X16XN.is_dynamic_vector(), true); + assert_eq!(F32X8XN.is_dynamic_vector(), true); + assert_eq!(F64X4XN.is_dynamic_vector(), true); + assert_eq!(I128X2XN.is_dynamic_vector(), true); + + // Lane counts. + assert_eq!(I16X8XN.lane_count(), 0); + assert_eq!(I16X8XN.min_lane_count(), 8); + + // Change lane counts + assert_eq!(I8X8XN.by(2), None); + + // Conversions to and from vectors. + assert_eq!(I8.by(16).unwrap().vector_to_dynamic(), Some(I8X16XN)); + assert_eq!(I16.by(8).unwrap().vector_to_dynamic(), Some(I16X8XN)); + assert_eq!(F16.by(8).unwrap().vector_to_dynamic(), Some(F16X8XN)); + assert_eq!(I32.by(4).unwrap().vector_to_dynamic(), Some(I32X4XN)); + assert_eq!(F32.by(4).unwrap().vector_to_dynamic(), Some(F32X4XN)); + assert_eq!(F64.by(2).unwrap().vector_to_dynamic(), Some(F64X2XN)); + assert_eq!(I128.by(2).unwrap().vector_to_dynamic(), Some(I128X2XN)); + assert_eq!(F128.by(2).unwrap().vector_to_dynamic(), Some(F128X2XN)); + + assert_eq!(I128X2XN.dynamic_to_vector(), Some(I128X2)); + assert_eq!(F16X4XN.dynamic_to_vector(), Some(F16X4)); + assert_eq!(F32X4XN.dynamic_to_vector(), Some(F32X4)); + assert_eq!(F64X4XN.dynamic_to_vector(), Some(F64X4)); + assert_eq!(F128X4XN.dynamic_to_vector(), Some(F128X4)); + assert_eq!(I32X2XN.dynamic_to_vector(), Some(I32X2)); + assert_eq!(I32X8XN.dynamic_to_vector(), Some(I32X8)); + assert_eq!(I16X16XN.dynamic_to_vector(), Some(I16X16)); + assert_eq!(I8X32XN.dynamic_to_vector(), Some(I8X32)); + + assert_eq!(I8X64.vector_to_dynamic(), None); + assert_eq!(F32X16.vector_to_dynamic(), None); + assert_eq!(I64X8.vector_to_dynamic(), None); + assert_eq!(I128X4.vector_to_dynamic(), None); + } + + #[test] + fn format_scalars() { + assert_eq!(I8.to_string(), "i8"); + assert_eq!(I16.to_string(), "i16"); + assert_eq!(I32.to_string(), "i32"); + assert_eq!(I64.to_string(), "i64"); + assert_eq!(I128.to_string(), "i128"); + assert_eq!(F32.to_string(), "f32"); + assert_eq!(F64.to_string(), "f64"); + } + + #[test] + fn format_vectors() { + assert_eq!(I8.by(64).unwrap().to_string(), "i8x64"); + assert_eq!(F64.by(2).unwrap().to_string(), "f64x2"); + assert_eq!(I8.by(3), None); + assert_eq!(I8.by(512), None); + assert_eq!(INVALID.by(4), None); + } + + #[test] + fn as_truthy() { + assert_eq!(I32X4.as_truthy(), I32X4); + assert_eq!(I32.as_truthy(), I8); + assert_eq!(I32X4.as_truthy_pedantic(), I32X4); + assert_eq!(I32.as_truthy_pedantic(), I32); + } + + #[test] + fn int_from_size() { + assert_eq!(Type::int(0), None); + assert_eq!(Type::int(8), Some(I8)); + assert_eq!(Type::int(33), None); + assert_eq!(Type::int(64), Some(I64)); + + assert_eq!(Type::int_with_byte_size(0), None); + assert_eq!(Type::int_with_byte_size(2), Some(I16)); + assert_eq!(Type::int_with_byte_size(6), None); + assert_eq!(Type::int_with_byte_size(16), Some(I128)); + + // Ensure `int_with_byte_size` handles overflow properly + let evil = 0xE001_u16; + assert_eq!(evil.wrapping_mul(8), 8, "check the constant is correct"); + assert_eq!(Type::int_with_byte_size(evil), None); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ir/user_stack_maps.rs b/deps/crates/vendor/cranelift-codegen/src/ir/user_stack_maps.rs new file mode 100644 index 00000000000000..6ad9b697cd0203 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ir/user_stack_maps.rs @@ -0,0 +1,199 @@ +//! User-defined stack maps. +//! +//! This module provides types allowing users to define stack maps and associate +//! them with safepoints. +//! +//! A **safepoint** is a program point (i.e. CLIF instruction) where it must be +//! safe to run GC. Currently all non-tail call instructions are considered +//! safepoints. (This does *not* allow, for example, skipping safepoints for +//! calls that are statically known not to trigger collections, or to have a +//! safepoint on a volatile load to a page that gets protected when it is time +//! to GC, triggering a fault that pauses the mutator and lets the collector do +//! its work before resuming the mutator. We can lift this restriction in the +//! future, if necessary.) +//! +//! A **stack map** is a description of where to find all the GC-managed values +//! that are live at a particular safepoint. Stack maps let the collector find +//! on-stack roots. Each stack map is logically a set of offsets into the stack +//! frame and the type of value at that associated offset. However, because the +//! stack layout isn't defined until much later in the compiler's pipeline, each +//! stack map entry instead includes both an `ir::StackSlot` and an offset +//! within that slot. +//! +//! These stack maps are **user-defined** in that it is the CLIF producer's +//! responsibility to identify and spill the live GC-managed values and attach +//! the associated stack map entries to each safepoint themselves (see +//! `cranelift_frontend::Function::declare_needs_stack_map` and +//! `cranelift_codegen::ir::DataFlowGraph::append_user_stack_map_entry`). Cranelift +//! will not insert spills and record these stack map entries automatically. +//! +//! Logically, a set of stack maps for a function record a table of the form: +//! +//! ```text +//! +---------------------+-------------------------------------------+ +//! | Instruction Pointer | SP-Relative Offsets of Live GC References | +//! +---------------------+-------------------------------------------+ +//! | 0x12345678 | 2, 6, 12 | +//! | 0x1234abcd | 2, 6 | +//! | ... | ... | +//! +---------------------+-------------------------------------------+ +//! ``` +//! +//! Where "instruction pointer" is an instruction pointer within the function, +//! and "offsets of live GC references" contains the offsets (in units of words) +//! from the frame's stack pointer where live GC references are stored on the +//! stack. Instruction pointers within the function that do not have an entry in +//! this table are not GC safepoints. +//! +//! Because +//! +//! * offsets of live GC references are relative from the stack pointer, and +//! * stack frames grow down from higher addresses to lower addresses, +//! +//! to get a pointer to a live reference at offset `x` within a stack frame, you +//! add `x` to the frame's stack pointer. +//! +//! For example, to calculate the pointer to the live GC reference inside "frame +//! 1" below, you would do `frame_1_sp + x`: +//! +//! ```text +//! Stack +//! +-------------------+ +//! | Frame 0 | +//! | | +//! | | | +//! | +-------------------+ <--- Frame 0's SP +//! | | Frame 1 | +//! Grows | | +//! down | | +//! | | Live GC reference | --+-- +//! | | | | +//! | | | | +//! V | | x = offset of live GC reference +//! | | | +//! | | | +//! +-------------------+ --+-- <--- Frame 1's SP +//! | Frame 2 | +//! | ... | +//! ``` +//! +//! An individual `UserStackMap` is associated with just one instruction pointer +//! within the function, contains the size of the stack frame, and represents +//! the stack frame as a bitmap. There is one bit per word in the stack frame, +//! and if the bit is set, then the word contains a live GC reference. +//! +//! Note that a caller's outgoing argument stack slots (if any) and callee's +//! incoming argument stack slots (if any) overlap, so we must choose which +//! function's stack maps record live GC references in these slots. We record +//! the incoming arguments in the callee's stack map. This choice plays nice +//! with tail calls, where by the time we transfer control to the callee, the +//! caller no longer exists. + +use crate::ir; +use cranelift_bitset::CompoundBitSet; +use cranelift_entity::PrimaryMap; +use smallvec::SmallVec; + +pub(crate) type UserStackMapEntryVec = SmallVec<[UserStackMapEntry; 4]>; + +/// A stack map entry describes a single GC-managed value and its location on +/// the stack. +/// +/// A stack map entry is associated with a particular instruction, and that +/// instruction must be a safepoint. The GC-managed value must be stored in the +/// described location across this entry's instruction. +#[derive(Clone, Debug, PartialEq, Hash)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct UserStackMapEntry { + /// The type of the value stored in this stack map entry. + pub ty: ir::Type, + + /// The stack slot that this stack map entry is within. + pub slot: ir::StackSlot, + + /// The offset within the stack slot where this entry's value can be found. + pub offset: u32, +} + +/// A compiled stack map, describing the location of many GC-managed values. +/// +/// A stack map is associated with a particular instruction, and that +/// instruction is a safepoint. +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] +pub struct UserStackMap { + // Offsets into the frame's sized stack slots that are GC references, by type. + by_type: SmallVec<[(ir::Type, CompoundBitSet); 1]>, + + // The offset of the sized stack slots, from SP, for this stack map's + // associated PC. + // + // This is initially `None` upon construction during lowering, but filled in + // after regalloc during emission when we have the precise frame layout. + sp_to_sized_stack_slots: Option, +} + +impl UserStackMap { + /// Coalesce the given entries into a new `UserStackMap`. + pub(crate) fn new( + entries: &[UserStackMapEntry], + stack_slot_offsets: &PrimaryMap, + ) -> Self { + let mut by_type = SmallVec::<[(ir::Type, CompoundBitSet); 1]>::default(); + + for entry in entries { + let offset = stack_slot_offsets[entry.slot] + entry.offset; + let offset = usize::try_from(offset).unwrap(); + + // Don't bother trying to avoid an `O(n)` search here: `n` is + // basically always one in practice; even if it isn't, there aren't + // that many different CLIF types. + let index = by_type + .iter() + .position(|(ty, _)| *ty == entry.ty) + .unwrap_or_else(|| { + by_type.push((entry.ty, CompoundBitSet::with_capacity(offset + 1))); + by_type.len() - 1 + }); + + by_type[index].1.insert(offset); + } + + UserStackMap { + by_type, + sp_to_sized_stack_slots: None, + } + } + + /// Finalize this stack map by filling in the SP-to-stack-slots offset. + pub(crate) fn finalize(&mut self, sp_to_sized_stack_slots: u32) { + debug_assert!(self.sp_to_sized_stack_slots.is_none()); + self.sp_to_sized_stack_slots = Some(sp_to_sized_stack_slots); + } + + /// Iterate over the entries in this stack map. + /// + /// Yields pairs of the type of GC reference that is at the offset, and the + /// offset from SP. If a pair `(i64, 0x42)` is yielded, for example, then + /// when execution is at this stack map's associated PC, `SP + 0x42` is a + /// pointer to an `i64`, and that `i64` is a live GC reference. + pub fn entries(&self) -> impl Iterator + '_ { + let sp_to_sized_stack_slots = self.sp_to_sized_stack_slots.expect( + "`sp_to_sized_stack_slots` should have been filled in before this stack map was used", + ); + self.by_type.iter().flat_map(move |(ty, bitset)| { + bitset.iter().map(move |slot_offset| { + ( + *ty, + sp_to_sized_stack_slots + u32::try_from(slot_offset).unwrap(), + ) + }) + }) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/abi.rs b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/abi.rs new file mode 100644 index 00000000000000..4233078b779a4a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/abi.rs @@ -0,0 +1,1540 @@ +//! Implementation of a standard AArch64 ABI. + +use crate::ir; +use crate::ir::types; +use crate::ir::types::*; +use crate::ir::MemFlags; +use crate::ir::{dynamic_to_fixed, ExternalName, LibCall, Signature}; +use crate::isa; +use crate::isa::aarch64::{inst::*, settings as aarch64_settings, AArch64Backend}; +use crate::isa::unwind::UnwindInst; +use crate::isa::winch; +use crate::machinst::*; +use crate::settings; +use crate::CodegenResult; +use alloc::boxed::Box; +use alloc::vec::Vec; +use regalloc2::{MachineEnv, PReg, PRegSet}; +use smallvec::{smallvec, SmallVec}; +use std::borrow::ToOwned; +use std::sync::OnceLock; + +// We use a generic implementation that factors out AArch64 and x64 ABI commonalities, because +// these ABIs are very similar. + +/// Support for the AArch64 ABI from the callee side (within a function body). +pub(crate) type AArch64Callee = Callee; + +/// Support for the AArch64 ABI from the caller side (at a callsite). +pub(crate) type AArch64CallSite = CallSite; + +impl Into for StackAMode { + fn into(self) -> AMode { + match self { + StackAMode::IncomingArg(off, stack_args_size) => AMode::IncomingArg { + off: i64::from(stack_args_size) - off, + }, + StackAMode::Slot(off) => AMode::SlotOffset { off }, + StackAMode::OutgoingArg(off) => AMode::SPOffset { off }, + } + } +} + +// Returns the size of stack space needed to store the +// `clobbered_callee_saved` registers. +fn compute_clobber_size(clobbered_callee_saves: &[Writable]) -> u32 { + let mut int_regs = 0; + let mut vec_regs = 0; + for ® in clobbered_callee_saves { + match reg.to_reg().class() { + RegClass::Int => { + int_regs += 1; + } + RegClass::Float => { + vec_regs += 1; + } + RegClass::Vector => unreachable!(), + } + } + + // Round up to multiple of 2, to keep 16-byte stack alignment. + let int_save_bytes = (int_regs + (int_regs & 1)) * 8; + // The Procedure Call Standard for the Arm 64-bit Architecture + // (AAPCS64, including several related ABIs such as the one used by + // Windows) mandates saving only the bottom 8 bytes of the vector + // registers, so we round up the number of registers to ensure + // proper stack alignment (similarly to the situation with + // `int_reg`). + let vec_reg_size = 8; + let vec_save_padding = vec_regs & 1; + // FIXME: SVE: ABI is different to Neon, so do we treat all vec regs as Z-regs? + let vec_save_bytes = (vec_regs + vec_save_padding) * vec_reg_size; + + int_save_bytes + vec_save_bytes +} + +/// AArch64-specific ABI behavior. This struct just serves as an implementation +/// point for the trait; it is never actually instantiated. +pub struct AArch64MachineDeps; + +impl IsaFlags for aarch64_settings::Flags { + fn is_forward_edge_cfi_enabled(&self) -> bool { + self.use_bti() + } +} + +impl ABIMachineSpec for AArch64MachineDeps { + type I = Inst; + + type F = aarch64_settings::Flags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic: for now, 128 MB. + const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024; + + fn word_bits() -> u32 { + 64 + } + + /// Return required stack alignment in bytes. + fn stack_align(_call_conv: isa::CallConv) -> u32 { + 16 + } + + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + mut args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)> { + let is_apple_cc = call_conv == isa::CallConv::AppleAarch64; + let is_winch_return = call_conv == isa::CallConv::Winch && args_or_rets == ArgsOrRets::Rets; + + // See AArch64 ABI (https://github.com/ARM-software/abi-aa/blob/2021Q1/aapcs64/aapcs64.rst#64parameter-passing), sections 6.4. + // + // MacOS aarch64 is slightly different, see also + // https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms. + // We are diverging from the MacOS aarch64 implementation in the + // following ways: + // - sign- and zero- extensions of data types less than 32 bits are not + // implemented yet. + // - we align the arguments stack space to a 16-bytes boundary, while + // the MacOS allows aligning only on 8 bytes. In practice it means we're + // slightly overallocating when calling, which is fine, and doesn't + // break our other invariants that the stack is always allocated in + // 16-bytes chunks. + + let mut next_xreg = if call_conv == isa::CallConv::Tail { + // We reserve `x0` for the return area pointer. For simplicity, we + // reserve it even when there is no return area pointer needed. This + // also means that identity functions don't have to shuffle arguments to + // different return registers because we shifted all argument register + // numbers down by one to make space for the return area pointer. + // + // Also, we cannot use all allocatable GPRs as arguments because we need + // at least one allocatable register for holding the callee address in + // indirect calls. So skip `x1` also, reserving it for that role. + 2 + } else { + 0 + }; + let mut next_vreg = 0; + let mut next_stack: u32 = 0; + + // Note on return values: on the regular ABI, we may return values + // in 8 registers for V128 and I64 registers independently of the + // number of register values returned in the other class. That is, + // we can return values in up to 8 integer and + // 8 vector registers at once. + let max_per_class_reg_vals = 8; // x0-x7 and v0-v7 + let mut remaining_reg_vals = 16; + + let ret_area_ptr = if add_ret_area_ptr { + debug_assert_eq!(args_or_rets, ArgsOrRets::Args); + if call_conv != isa::CallConv::Winch { + // In the AAPCS64 calling convention the return area pointer is + // stored in x8. + Some(ABIArg::reg( + xreg(8).to_real_reg().unwrap(), + I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } else { + // Use x0 for the return area pointer in the Winch calling convention + // to simplify the ABI handling code in Winch by avoiding an AArch64 + // special case to assign it to x8. + next_xreg += 1; + Some(ABIArg::reg( + xreg(0).to_real_reg().unwrap(), + I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } + } else { + None + }; + + for (i, param) in params.into_iter().enumerate() { + if is_apple_cc && param.value_type == types::F128 && !flags.enable_llvm_abi_extensions() + { + panic!( + "f128 args/return values not supported for apple_aarch64 unless LLVM ABI extensions are enabled" + ); + } + + let (rcs, reg_types) = Inst::rc_for_type(param.value_type)?; + + if let ir::ArgumentPurpose::StructReturn = param.purpose { + assert!( + call_conv != isa::CallConv::Tail, + "support for StructReturn parameters is not implemented for the `tail` \ + calling convention yet", + ); + } + + if let ir::ArgumentPurpose::StructArgument(_) = param.purpose { + panic!( + "StructArgument parameters are not supported on arm64. \ + Use regular pointer arguments instead." + ); + } + + if let ir::ArgumentPurpose::StructReturn = param.purpose { + // FIXME add assert_eq!(args_or_rets, ArgsOrRets::Args); once + // ensure_struct_return_ptr_is_returned is gone. + assert!( + param.value_type == types::I64, + "StructReturn must be a pointer sized integer" + ); + args.push(ABIArg::Slots { + slots: smallvec![ABIArgSlot::Reg { + reg: xreg(8).to_real_reg().unwrap(), + ty: types::I64, + extension: param.extension, + },], + purpose: ir::ArgumentPurpose::StructReturn, + }); + continue; + } + + // Handle multi register params + // + // See AArch64 ABI (https://github.com/ARM-software/abi-aa/blob/2021Q1/aapcs64/aapcs64.rst#642parameter-passing-rules), (Section 6.4.2 Stage C). + // + // For arguments with alignment of 16 we round up the register number + // to the next even value. So we can never allocate for example an i128 + // to X1 and X2, we have to skip one register and do X2, X3 + // (Stage C.8) + // Note: The Apple ABI deviates a bit here. They don't respect Stage C.8 + // and will happily allocate a i128 to X1 and X2 + // + // For integer types with alignment of 16 we also have the additional + // restriction of passing the lower half in Xn and the upper half in Xn+1 + // (Stage C.9) + // + // For examples of how LLVM handles this: https://godbolt.org/z/bhd3vvEfh + // + // On the Apple ABI it is unspecified if we can spill half the value into the stack + // i.e load the lower half into x7 and the upper half into the stack + // LLVM does not seem to do this, so we are going to replicate that behaviour + let is_multi_reg = rcs.len() >= 2; + if is_multi_reg { + assert!( + rcs.len() == 2, + "Unable to handle multi reg params with more than 2 regs" + ); + assert!( + rcs == &[RegClass::Int, RegClass::Int], + "Unable to handle non i64 regs" + ); + + let reg_class_space = max_per_class_reg_vals - next_xreg; + let reg_space = remaining_reg_vals; + + if reg_space >= 2 && reg_class_space >= 2 { + // The aarch64 ABI does not allow us to start a split argument + // at an odd numbered register. So we need to skip one register + // + // TODO: The Fast ABI should probably not skip the register + if !is_apple_cc && next_xreg % 2 != 0 { + next_xreg += 1; + } + + let lower_reg = xreg(next_xreg); + let upper_reg = xreg(next_xreg + 1); + + args.push(ABIArg::Slots { + slots: smallvec![ + ABIArgSlot::Reg { + reg: lower_reg.to_real_reg().unwrap(), + ty: reg_types[0], + extension: param.extension, + }, + ABIArgSlot::Reg { + reg: upper_reg.to_real_reg().unwrap(), + ty: reg_types[1], + extension: param.extension, + }, + ], + purpose: param.purpose, + }); + + next_xreg += 2; + remaining_reg_vals -= 2; + continue; + } + } else { + // Single Register parameters + let rc = rcs[0]; + let next_reg = match rc { + RegClass::Int => &mut next_xreg, + RegClass::Float => &mut next_vreg, + RegClass::Vector => unreachable!(), + }; + + let push_to_reg = if is_winch_return { + // Winch uses the first register to return the last result + i == params.len() - 1 + } else { + // Use max_per_class_reg_vals & remaining_reg_vals otherwise + *next_reg < max_per_class_reg_vals && remaining_reg_vals > 0 + }; + + if push_to_reg { + let reg = match rc { + RegClass::Int => xreg(*next_reg), + RegClass::Float => vreg(*next_reg), + RegClass::Vector => unreachable!(), + }; + // Overlay Z-regs on V-regs for parameter passing. + let ty = if param.value_type.is_dynamic_vector() { + dynamic_to_fixed(param.value_type) + } else { + param.value_type + }; + args.push(ABIArg::reg( + reg.to_real_reg().unwrap(), + ty, + param.extension, + param.purpose, + )); + *next_reg += 1; + remaining_reg_vals -= 1; + continue; + } + } + + // Spill to the stack + + if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() { + return Err(crate::CodegenError::Unsupported( + "Too many return values to fit in registers. \ + Use a StructReturn argument instead. (#9510)" + .to_owned(), + )); + } + + // Compute the stack slot's size. + let size = (ty_bits(param.value_type) / 8) as u32; + + let size = if is_apple_cc || is_winch_return { + // MacOS and Winch aarch64 allows stack slots with + // sizes less than 8 bytes. They still need to be + // properly aligned on their natural data alignment, + // though. + size + } else { + // Every arg takes a minimum slot of 8 bytes. (16-byte stack + // alignment happens separately after all args.) + std::cmp::max(size, 8) + }; + + if !is_winch_return { + // Align the stack slot. + debug_assert!(size.is_power_of_two()); + next_stack = align_to(next_stack, size); + } + + let slots = reg_types + .iter() + .copied() + // Build the stack locations from each slot + .scan(next_stack, |next_stack, ty| { + let slot_offset = *next_stack as i64; + *next_stack += (ty_bits(ty) / 8) as u32; + + Some((ty, slot_offset)) + }) + .map(|(ty, offset)| ABIArgSlot::Stack { + offset, + ty, + extension: param.extension, + }) + .collect(); + + args.push(ABIArg::Slots { + slots, + purpose: param.purpose, + }); + + next_stack += size; + } + + let extra_arg = if let Some(ret_area_ptr) = ret_area_ptr { + args.push_non_formal(ret_area_ptr); + Some(args.args().len() - 1) + } else { + None + }; + + if is_winch_return { + winch::reverse_stack(args, next_stack, false); + } + + next_stack = align_to(next_stack, 16); + + Ok((next_stack, extra_arg)) + } + + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Inst { + Inst::gen_load(into_reg, mem.into(), ty, MemFlags::trusted()) + } + + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_store(mem.into(), from_reg, ty, MemFlags::trusted()) + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_move(to_reg, from_reg, ty) + } + + fn gen_extend( + to_reg: Writable, + from_reg: Reg, + signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Inst { + assert!(from_bits < to_bits); + Inst::Extend { + rd: to_reg, + rn: from_reg, + signed, + from_bits, + to_bits, + } + } + + fn gen_args(args: Vec) -> Inst { + Inst::Args { args } + } + + fn gen_rets(rets: Vec) -> Inst { + Inst::Rets { rets } + } + + fn gen_add_imm( + _call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec { + let imm = imm as u64; + let mut insts = SmallVec::new(); + if let Some(imm12) = Imm12::maybe_from_u64(imm) { + insts.push(Inst::AluRRImm12 { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: into_reg, + rn: from_reg, + imm12, + }); + } else { + let scratch2 = writable_tmp2_reg(); + assert_ne!(scratch2.to_reg(), from_reg); + // `gen_add_imm` is only ever called after register allocation has taken place, and as a + // result it's ok to reuse the scratch2 register here. If that changes, we'll need to + // plumb through a way to allocate temporary virtual registers + insts.extend(Inst::load_constant(scratch2, imm.into(), &mut |_| scratch2)); + insts.push(Inst::AluRRRExtend { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: into_reg, + rn: from_reg, + rm: scratch2.to_reg(), + extendop: ExtendOp::UXTX, + }); + } + insts + } + + fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { + let mut insts = SmallVec::new(); + insts.push(Inst::AluRRRExtend { + alu_op: ALUOp::SubS, + size: OperandSize::Size64, + rd: writable_zero_reg(), + rn: stack_reg(), + rm: limit_reg, + extendop: ExtendOp::UXTX, + }); + insts.push(Inst::TrapIf { + trap_code: ir::TrapCode::STACK_OVERFLOW, + // Here `Lo` == "less than" when interpreting the two + // operands as unsigned integers. + kind: CondBrKind::Cond(Cond::Lo), + }); + insts + } + + fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable) -> Inst { + // FIXME: Do something different for dynamic types? + let mem = mem.into(); + Inst::LoadAddr { rd: into_reg, mem } + } + + fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg { + spilltmp_reg() + } + + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Inst { + let mem = AMode::RegOffset { + rn: base, + off: offset as i64, + }; + Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()) + } + + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst { + let mem = AMode::RegOffset { + rn: base, + off: offset as i64, + }; + Inst::gen_store(mem, from_reg, ty, MemFlags::trusted()) + } + + fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { + if amount == 0 { + return SmallVec::new(); + } + + let (amount, is_sub) = if amount > 0 { + (amount as u64, false) + } else { + (-amount as u64, true) + }; + + let alu_op = if is_sub { ALUOp::Sub } else { ALUOp::Add }; + + let mut ret = SmallVec::new(); + if let Some(imm12) = Imm12::maybe_from_u64(amount) { + let adj_inst = Inst::AluRRImm12 { + alu_op, + size: OperandSize::Size64, + rd: writable_stack_reg(), + rn: stack_reg(), + imm12, + }; + ret.push(adj_inst); + } else { + let tmp = writable_spilltmp_reg(); + // `gen_sp_reg_adjust` is called after regalloc2, so it's acceptable to reuse `tmp` for + // intermediates in `load_constant`. + let const_inst = Inst::load_constant(tmp, amount, &mut |_| tmp); + let adj_inst = Inst::AluRRRExtend { + alu_op, + size: OperandSize::Size64, + rd: writable_stack_reg(), + rn: stack_reg(), + rm: tmp.to_reg(), + extendop: ExtendOp::UXTX, + }; + ret.extend(const_inst); + ret.push(adj_inst); + } + ret + } + + fn gen_prologue_frame_setup( + call_conv: isa::CallConv, + flags: &settings::Flags, + isa_flags: &aarch64_settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let setup_frame = frame_layout.setup_area_size > 0; + let mut insts = SmallVec::new(); + + match select_api_key(isa_flags, call_conv, setup_frame) { + Some(key) => { + insts.push(Inst::Paci { key }); + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::Aarch64SetPointerAuth { + return_addresses: true, + }, + }); + } + } + None => { + if isa_flags.use_bti() { + insts.push(Inst::Bti { + targets: BranchTargetType::C, + }); + } + + if flags.unwind_info() && call_conv == isa::CallConv::AppleAarch64 { + // The macOS unwinder seems to require this. + insts.push(Inst::Unwind { + inst: UnwindInst::Aarch64SetPointerAuth { + return_addresses: false, + }, + }); + } + } + } + + if setup_frame { + // stp fp (x29), lr (x30), [sp, #-16]! + insts.push(Inst::StoreP64 { + rt: fp_reg(), + rt2: link_reg(), + mem: PairAMode::SPPreIndexed { + simm7: SImm7Scaled::maybe_from_i64(-16, types::I64).unwrap(), + }, + flags: MemFlags::trusted(), + }); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::PushFrameRegs { + offset_upward_to_caller_sp: frame_layout.setup_area_size, + }, + }); + } + + // mov fp (x29), sp. This uses the ADDI rd, rs, 0 form of `MOV` because + // the usual encoding (`ORR`) does not work with SP. + insts.push(Inst::AluRRImm12 { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: writable_fp_reg(), + rn: stack_reg(), + imm12: Imm12 { + bits: 0, + shift12: false, + }, + }); + } + + insts + } + + fn gen_epilogue_frame_restore( + call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &aarch64_settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let setup_frame = frame_layout.setup_area_size > 0; + let mut insts = SmallVec::new(); + + if setup_frame { + // N.B.: sp is already adjusted to the appropriate place by the + // clobber-restore code (which also frees the fixed frame). Hence, there + // is no need for the usual `mov sp, fp` here. + + // `ldp fp, lr, [sp], #16` + insts.push(Inst::LoadP64 { + rt: writable_fp_reg(), + rt2: writable_link_reg(), + mem: PairAMode::SPPostIndexed { + simm7: SImm7Scaled::maybe_from_i64(16, types::I64).unwrap(), + }, + flags: MemFlags::trusted(), + }); + } + + if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 { + insts.extend(Self::gen_sp_reg_adjust( + frame_layout.tail_args_size.try_into().unwrap(), + )); + } + + insts + } + + fn gen_return( + call_conv: isa::CallConv, + isa_flags: &aarch64_settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let setup_frame = frame_layout.setup_area_size > 0; + + match select_api_key(isa_flags, call_conv, setup_frame) { + Some(key) => { + smallvec![Inst::AuthenticatedRet { + key, + is_hint: !isa_flags.has_pauth(), + }] + } + None => { + smallvec![Inst::Ret {}] + } + } + } + + fn gen_probestack(_insts: &mut SmallInstVec, _: u32) { + // TODO: implement if we ever require stack probes on an AArch64 host + // (unlikely unless Lucet is ported) + unimplemented!("Stack probing is unimplemented on AArch64"); + } + + fn gen_inline_probestack( + insts: &mut SmallInstVec, + _call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ) { + // The stack probe loop currently takes 6 instructions and each inline + // probe takes 2 (ish, these numbers sort of depend on the constants). + // Set this to 3 to keep the max size of the probe to 6 instructions. + const PROBE_MAX_UNROLL: u32 = 3; + + // Calculate how many probes we need to perform. Round down, as we only + // need to probe whole guard_size regions we'd otherwise skip over. + let probe_count = frame_size / guard_size; + if probe_count == 0 { + // No probe necessary + } else if probe_count <= PROBE_MAX_UNROLL { + Self::gen_probestack_unroll(insts, guard_size, probe_count) + } else { + Self::gen_probestack_loop(insts, frame_size, guard_size) + } + } + + fn gen_clobber_save( + _call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class(); + + let mut insts = SmallVec::new(); + let setup_frame = frame_layout.setup_area_size > 0; + + // When a return_call within this function required more stack arguments than we have + // present, resize the incoming argument area of the frame to accommodate those arguments. + let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size; + if incoming_args_diff > 0 { + // Decrement SP to account for the additional space required by a tail call. + insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32))); + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::StackAlloc { + size: incoming_args_diff, + }, + }); + } + + // Move fp and lr down. + if setup_frame { + // Reload the frame pointer from the stack. + insts.push(Inst::ULoad64 { + rd: regs::writable_fp_reg(), + mem: AMode::SPOffset { + off: i64::from(incoming_args_diff), + }, + flags: MemFlags::trusted(), + }); + + // Store the frame pointer and link register again at the new SP + insts.push(Inst::StoreP64 { + rt: fp_reg(), + rt2: link_reg(), + mem: PairAMode::SignedOffset { + reg: regs::stack_reg(), + simm7: SImm7Scaled::maybe_from_i64(0, types::I64).unwrap(), + }, + flags: MemFlags::trusted(), + }); + + // Keep the frame pointer in sync + insts.push(Self::gen_move( + regs::writable_fp_reg(), + regs::stack_reg(), + types::I64, + )); + } + } + + if flags.unwind_info() && setup_frame { + // The *unwind* frame (but not the actual frame) starts at the + // clobbers, just below the saved FP/LR pair. + insts.push(Inst::Unwind { + inst: UnwindInst::DefineNewFrame { + offset_downward_to_clobbers: frame_layout.clobber_size, + offset_upward_to_caller_sp: frame_layout.setup_area_size, + }, + }); + } + + // We use pre-indexed addressing modes here, rather than the possibly + // more efficient "subtract sp once then used fixed offsets" scheme, + // because (i) we cannot necessarily guarantee that the offset of a + // clobber-save slot will be within a SImm7Scaled (+504-byte) offset + // range of the whole frame including other slots, it is more complex to + // conditionally generate a two-stage SP adjustment (clobbers then fixed + // frame) otherwise, and generally we just want to maintain simplicity + // here for maintainability. Because clobbers are at the top of the + // frame, just below FP, all that is necessary is to use the pre-indexed + // "push" `[sp, #-16]!` addressing mode. + // + // `frame_offset` tracks offset above start-of-clobbers for unwind-info + // purposes. + let mut clobber_offset = frame_layout.clobber_size; + let clobber_offset_change = 16; + let iter = clobbered_int.chunks_exact(2); + + if let [rd] = iter.remainder() { + let rd: Reg = rd.to_reg().into(); + + debug_assert_eq!(rd.class(), RegClass::Int); + // str rd, [sp, #-16]! + insts.push(Inst::Store64 { + rd, + mem: AMode::SPPreIndexed { + simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(), + }, + flags: MemFlags::trusted(), + }); + + if flags.unwind_info() { + clobber_offset -= clobber_offset_change as u32; + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset, + reg: rd.to_real_reg().unwrap(), + }, + }); + } + } + + let mut iter = iter.rev(); + + while let Some([rt, rt2]) = iter.next() { + // .to_reg().into(): Writable --> RealReg --> Reg + let rt: Reg = rt.to_reg().into(); + let rt2: Reg = rt2.to_reg().into(); + + debug_assert!(rt.class() == RegClass::Int); + debug_assert!(rt2.class() == RegClass::Int); + + // stp rt, rt2, [sp, #-16]! + insts.push(Inst::StoreP64 { + rt, + rt2, + mem: PairAMode::SPPreIndexed { + simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, types::I64).unwrap(), + }, + flags: MemFlags::trusted(), + }); + + if flags.unwind_info() { + clobber_offset -= clobber_offset_change as u32; + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset, + reg: rt.to_real_reg().unwrap(), + }, + }); + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: clobber_offset + (clobber_offset_change / 2) as u32, + reg: rt2.to_real_reg().unwrap(), + }, + }); + } + } + + let store_vec_reg = |rd| Inst::FpuStore64 { + rd, + mem: AMode::SPPreIndexed { + simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(), + }, + flags: MemFlags::trusted(), + }; + let iter = clobbered_vec.chunks_exact(2); + + if let [rd] = iter.remainder() { + let rd: Reg = rd.to_reg().into(); + + debug_assert_eq!(rd.class(), RegClass::Float); + insts.push(store_vec_reg(rd)); + + if flags.unwind_info() { + clobber_offset -= clobber_offset_change as u32; + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset, + reg: rd.to_real_reg().unwrap(), + }, + }); + } + } + + let store_vec_reg_pair = |rt, rt2| { + let clobber_offset_change = 16; + + ( + Inst::FpuStoreP64 { + rt, + rt2, + mem: PairAMode::SPPreIndexed { + simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, F64).unwrap(), + }, + flags: MemFlags::trusted(), + }, + clobber_offset_change as u32, + ) + }; + let mut iter = iter.rev(); + + while let Some([rt, rt2]) = iter.next() { + let rt: Reg = rt.to_reg().into(); + let rt2: Reg = rt2.to_reg().into(); + + debug_assert_eq!(rt.class(), RegClass::Float); + debug_assert_eq!(rt2.class(), RegClass::Float); + + let (inst, clobber_offset_change) = store_vec_reg_pair(rt, rt2); + + insts.push(inst); + + if flags.unwind_info() { + clobber_offset -= clobber_offset_change; + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset, + reg: rt.to_real_reg().unwrap(), + }, + }); + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: clobber_offset + clobber_offset_change / 2, + reg: rt2.to_real_reg().unwrap(), + }, + }); + } + } + + // Allocate the fixed frame below the clobbers if necessary. + let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size; + if stack_size > 0 { + insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32))); + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::StackAlloc { size: stack_size }, + }); + } + } + + insts + } + + fn gen_clobber_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class(); + + // Free the fixed frame if necessary. + let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size; + if stack_size > 0 { + insts.extend(Self::gen_sp_reg_adjust(stack_size as i32)); + } + + let load_vec_reg = |rd| Inst::FpuLoad64 { + rd, + mem: AMode::SPPostIndexed { + simm9: SImm9::maybe_from_i64(16).unwrap(), + }, + flags: MemFlags::trusted(), + }; + let load_vec_reg_pair = |rt, rt2| Inst::FpuLoadP64 { + rt, + rt2, + mem: PairAMode::SPPostIndexed { + simm7: SImm7Scaled::maybe_from_i64(16, F64).unwrap(), + }, + flags: MemFlags::trusted(), + }; + + let mut iter = clobbered_vec.chunks_exact(2); + + while let Some([rt, rt2]) = iter.next() { + let rt: Writable = rt.map(|r| r.into()); + let rt2: Writable = rt2.map(|r| r.into()); + + debug_assert_eq!(rt.to_reg().class(), RegClass::Float); + debug_assert_eq!(rt2.to_reg().class(), RegClass::Float); + insts.push(load_vec_reg_pair(rt, rt2)); + } + + debug_assert!(iter.remainder().len() <= 1); + + if let [rd] = iter.remainder() { + let rd: Writable = rd.map(|r| r.into()); + + debug_assert_eq!(rd.to_reg().class(), RegClass::Float); + insts.push(load_vec_reg(rd)); + } + + let mut iter = clobbered_int.chunks_exact(2); + + while let Some([rt, rt2]) = iter.next() { + let rt: Writable = rt.map(|r| r.into()); + let rt2: Writable = rt2.map(|r| r.into()); + + debug_assert_eq!(rt.to_reg().class(), RegClass::Int); + debug_assert_eq!(rt2.to_reg().class(), RegClass::Int); + // ldp rt, rt2, [sp], #16 + insts.push(Inst::LoadP64 { + rt, + rt2, + mem: PairAMode::SPPostIndexed { + simm7: SImm7Scaled::maybe_from_i64(16, I64).unwrap(), + }, + flags: MemFlags::trusted(), + }); + } + + debug_assert!(iter.remainder().len() <= 1); + + if let [rd] = iter.remainder() { + let rd: Writable = rd.map(|r| r.into()); + + debug_assert_eq!(rd.to_reg().class(), RegClass::Int); + // ldr rd, [sp], #16 + insts.push(Inst::ULoad64 { + rd, + mem: AMode::SPPostIndexed { + simm9: SImm9::maybe_from_i64(16).unwrap(), + }, + flags: MemFlags::trusted(), + }); + } + + insts + } + + fn gen_call(dest: &CallDest, tmp: Writable, info: CallInfo<()>) -> SmallVec<[Inst; 2]> { + let mut insts = SmallVec::new(); + match &dest { + &CallDest::ExtName(ref name, RelocDistance::Near) => { + let info = Box::new(info.map(|()| name.clone())); + insts.push(Inst::Call { info }); + } + &CallDest::ExtName(ref name, RelocDistance::Far) => { + insts.push(Inst::LoadExtName { + rd: tmp, + name: Box::new(name.clone()), + offset: 0, + }); + let info = Box::new(info.map(|()| tmp.to_reg())); + insts.push(Inst::CallInd { info }); + } + &CallDest::Reg(reg) => { + let info = Box::new(info.map(|()| *reg)); + insts.push(Inst::CallInd { info }); + } + } + + insts + } + + fn gen_memcpy Writable>( + call_conv: isa::CallConv, + dst: Reg, + src: Reg, + size: usize, + mut alloc_tmp: F, + ) -> SmallVec<[Self::I; 8]> { + let mut insts = SmallVec::new(); + let arg0 = writable_xreg(0); + let arg1 = writable_xreg(1); + let arg2 = writable_xreg(2); + let tmp = alloc_tmp(Self::word_type()); + insts.extend(Inst::load_constant(tmp, size as u64, &mut alloc_tmp)); + insts.push(Inst::Call { + info: Box::new(CallInfo { + dest: ExternalName::LibCall(LibCall::Memcpy), + uses: smallvec![ + CallArgPair { + vreg: dst, + preg: arg0.to_reg() + }, + CallArgPair { + vreg: src, + preg: arg1.to_reg() + }, + CallArgPair { + vreg: tmp.to_reg(), + preg: arg2.to_reg() + } + ], + defs: smallvec![], + clobbers: Self::get_regs_clobbered_by_call(call_conv), + caller_conv: call_conv, + callee_conv: call_conv, + callee_pop_size: 0, + }), + }); + insts + } + + fn get_number_of_spillslots_for_value( + rc: RegClass, + vector_size: u32, + _isa_flags: &Self::F, + ) -> u32 { + assert_eq!(vector_size % 8, 0); + // We allocate in terms of 8-byte slots. + match rc { + RegClass::Int => 1, + RegClass::Float => vector_size / 8, + RegClass::Vector => unreachable!(), + } + } + + fn get_machine_env(flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv { + if flags.enable_pinned_reg() { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(|| create_reg_env(true)) + } else { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(|| create_reg_env(false)) + } + } + + fn get_regs_clobbered_by_call(_call_conv: isa::CallConv) -> PRegSet { + DEFAULT_AAPCS_CLOBBERS + } + + fn get_ext_mode( + call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension { + if call_conv == isa::CallConv::AppleAarch64 { + specified + } else { + ir::ArgumentExtension::None + } + } + + fn compute_frame_layout( + call_conv: isa::CallConv, + flags: &settings::Flags, + sig: &Signature, + regs: &[Writable], + is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + outgoing_args_size: u32, + ) -> FrameLayout { + let mut regs: Vec> = regs + .iter() + .cloned() + .filter(|r| { + is_reg_saved_in_prologue(call_conv, flags.enable_pinned_reg(), sig, r.to_reg()) + }) + .collect(); + + // Sort registers for deterministic code output. We can do an unstable + // sort because the registers will be unique (there are no dups). + regs.sort_unstable(); + + // Compute clobber size. + let clobber_size = compute_clobber_size(®s); + + // Compute linkage frame size. + let setup_area_size = if flags.preserve_frame_pointers() + || !is_leaf + // The function arguments that are passed on the stack are addressed + // relative to the Frame Pointer. + || incoming_args_size > 0 + || clobber_size > 0 + || fixed_frame_storage_size > 0 + { + 16 // FP, LR + } else { + 0 + }; + + // Return FrameLayout structure. + FrameLayout { + incoming_args_size, + tail_args_size, + setup_area_size, + clobber_size, + fixed_frame_storage_size, + outgoing_args_size, + clobbered_callee_saves: regs, + } + } +} + +impl AArch64MachineDeps { + fn gen_probestack_unroll(insts: &mut SmallInstVec, guard_size: u32, probe_count: u32) { + // When manually unrolling adjust the stack pointer and then write a zero + // to the stack at that offset. This generates something like + // `sub sp, sp, #1, lsl #12` followed by `stur wzr, [sp]`. + // + // We do this because valgrind expects us to never write beyond the stack + // pointer and associated redzone. + // See: https://github.com/bytecodealliance/wasmtime/issues/7454 + for _ in 0..probe_count { + insts.extend(Self::gen_sp_reg_adjust(-(guard_size as i32))); + + insts.push(Inst::gen_store( + AMode::SPOffset { off: 0 }, + zero_reg(), + I32, + MemFlags::trusted(), + )); + } + + // Restore the stack pointer to its original value + insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32)); + } + + fn gen_probestack_loop(insts: &mut SmallInstVec, frame_size: u32, guard_size: u32) { + // The non-unrolled version uses two temporary registers. The + // `start` contains the current offset from sp and counts downwards + // during the loop by increments of `guard_size`. The `end` is + // the size of the frame and where we stop. + // + // Note that this emission is all post-regalloc so it should be ok + // to use the temporary registers here as input/output as the loop + // itself is not allowed to use the registers. + let start = writable_spilltmp_reg(); + let end = writable_tmp2_reg(); + // `gen_inline_probestack` is called after regalloc2, so it's acceptable to reuse + // `start` and `end` as temporaries in load_constant. + insts.extend(Inst::load_constant(start, 0, &mut |_| start)); + insts.extend(Inst::load_constant(end, frame_size.into(), &mut |_| end)); + insts.push(Inst::StackProbeLoop { + start, + end: end.to_reg(), + step: Imm12::maybe_from_u64(guard_size.into()).unwrap(), + }); + } +} + +fn select_api_key( + isa_flags: &aarch64_settings::Flags, + call_conv: isa::CallConv, + setup_frame: bool, +) -> Option { + if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) { + // The `tail` calling convention uses a zero modifier rather than SP + // because tail calls may happen with a different stack pointer than + // when the function was entered, meaning that it won't be the same when + // the return address is decrypted. + Some(if isa_flags.sign_return_address_with_bkey() { + match call_conv { + isa::CallConv::Tail => APIKey::BZ, + _ => APIKey::BSP, + } + } else { + match call_conv { + isa::CallConv::Tail => APIKey::AZ, + _ => APIKey::ASP, + } + }) + } else { + None + } +} + +impl AArch64CallSite { + pub fn emit_return_call( + mut self, + ctx: &mut Lower, + args: isle::ValueSlice, + backend: &AArch64Backend, + ) { + let new_stack_arg_size = + u32::try_from(self.sig(ctx.sigs()).sized_stack_arg_space()).unwrap(); + + ctx.abi_mut().accumulate_tail_args_size(new_stack_arg_size); + + // Put all arguments in registers and stack slots (within that newly + // allocated stack space). + self.emit_args(ctx, args); + self.emit_stack_ret_arg_for_tail_call(ctx); + + let dest = self.dest().clone(); + let uses = self.take_uses(); + let key = select_api_key(&backend.isa_flags, isa::CallConv::Tail, true); + + match dest { + CallDest::ExtName(callee, RelocDistance::Near) => { + let info = Box::new(ReturnCallInfo { + dest: callee, + uses, + key, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCall { info }); + } + CallDest::ExtName(name, RelocDistance::Far) => { + let callee = ctx.alloc_tmp(types::I64).only_reg().unwrap(); + ctx.emit(Inst::LoadExtName { + rd: callee, + name: Box::new(name), + offset: 0, + }); + let info = Box::new(ReturnCallInfo { + dest: callee.to_reg(), + uses, + key, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallInd { info }); + } + CallDest::Reg(callee) => { + let info = Box::new(ReturnCallInfo { + dest: callee, + uses, + key, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallInd { info }); + } + } + } +} + +/// Is the given register saved in the prologue if clobbered, i.e., is it a +/// callee-save? +fn is_reg_saved_in_prologue( + _call_conv: isa::CallConv, + enable_pinned_reg: bool, + sig: &Signature, + r: RealReg, +) -> bool { + // FIXME: We need to inspect whether a function is returning Z or P regs too. + let save_z_regs = sig + .params + .iter() + .filter(|p| p.value_type.is_dynamic_vector()) + .count() + != 0; + + match r.class() { + RegClass::Int => { + // x19 - x28 inclusive are callee-saves. + // However, x21 is the pinned reg if `enable_pinned_reg` + // is set, and is implicitly globally-allocated, hence not + // callee-saved in prologues. + if enable_pinned_reg && r.hw_enc() == PINNED_REG { + false + } else { + r.hw_enc() >= 19 && r.hw_enc() <= 28 + } + } + RegClass::Float => { + // If a subroutine takes at least one argument in scalable vector registers + // or scalable predicate registers, or if it is a function that returns + // results in such registers, it must ensure that the entire contents of + // z8-z23 are preserved across the call. In other cases it need only + // preserve the low 64 bits of z8-z15. + if save_z_regs { + r.hw_enc() >= 8 && r.hw_enc() <= 23 + } else { + // v8 - v15 inclusive are callee-saves. + r.hw_enc() >= 8 && r.hw_enc() <= 15 + } + } + RegClass::Vector => unreachable!(), + } +} + +const fn default_aapcs_clobbers() -> PRegSet { + PRegSet::empty() + // x0 - x17 inclusive are caller-saves. + .with(xreg_preg(0)) + .with(xreg_preg(1)) + .with(xreg_preg(2)) + .with(xreg_preg(3)) + .with(xreg_preg(4)) + .with(xreg_preg(5)) + .with(xreg_preg(6)) + .with(xreg_preg(7)) + .with(xreg_preg(8)) + .with(xreg_preg(9)) + .with(xreg_preg(10)) + .with(xreg_preg(11)) + .with(xreg_preg(12)) + .with(xreg_preg(13)) + .with(xreg_preg(14)) + .with(xreg_preg(15)) + .with(xreg_preg(16)) + .with(xreg_preg(17)) + // v0 - v7 inclusive and v16 - v31 inclusive are + // caller-saves. The upper 64 bits of v8 - v15 inclusive are + // also caller-saves. However, because we cannot currently + // represent partial registers to regalloc2, we indicate here + // that every vector register is caller-save. Because this + // function is used at *callsites*, approximating in this + // direction (save more than necessary) is conservative and + // thus safe. + // + // Note that we exclude clobbers from a call instruction when + // a call instruction's callee has the same ABI as the caller + // (the current function body); this is safe (anything + // clobbered by callee can be clobbered by caller as well) and + // avoids unnecessary saves of v8-v15 in the prologue even + // though we include them as defs here. + .with(vreg_preg(0)) + .with(vreg_preg(1)) + .with(vreg_preg(2)) + .with(vreg_preg(3)) + .with(vreg_preg(4)) + .with(vreg_preg(5)) + .with(vreg_preg(6)) + .with(vreg_preg(7)) + .with(vreg_preg(8)) + .with(vreg_preg(9)) + .with(vreg_preg(10)) + .with(vreg_preg(11)) + .with(vreg_preg(12)) + .with(vreg_preg(13)) + .with(vreg_preg(14)) + .with(vreg_preg(15)) + .with(vreg_preg(16)) + .with(vreg_preg(17)) + .with(vreg_preg(18)) + .with(vreg_preg(19)) + .with(vreg_preg(20)) + .with(vreg_preg(21)) + .with(vreg_preg(22)) + .with(vreg_preg(23)) + .with(vreg_preg(24)) + .with(vreg_preg(25)) + .with(vreg_preg(26)) + .with(vreg_preg(27)) + .with(vreg_preg(28)) + .with(vreg_preg(29)) + .with(vreg_preg(30)) + .with(vreg_preg(31)) +} + +const DEFAULT_AAPCS_CLOBBERS: PRegSet = default_aapcs_clobbers(); + +fn create_reg_env(enable_pinned_reg: bool) -> MachineEnv { + fn preg(r: Reg) -> PReg { + r.to_real_reg().unwrap().into() + } + + let mut env = MachineEnv { + preferred_regs_by_class: [ + vec![ + preg(xreg(0)), + preg(xreg(1)), + preg(xreg(2)), + preg(xreg(3)), + preg(xreg(4)), + preg(xreg(5)), + preg(xreg(6)), + preg(xreg(7)), + preg(xreg(8)), + preg(xreg(9)), + preg(xreg(10)), + preg(xreg(11)), + preg(xreg(12)), + preg(xreg(13)), + preg(xreg(14)), + preg(xreg(15)), + // x16 and x17 are spilltmp and tmp2 (see above). + // x18 could be used by the platform to carry inter-procedural state; + // conservatively assume so and make it not allocatable. + // x19-28 are callee-saved and so not preferred. + // x21 is the pinned register (if enabled) and not allocatable if so. + // x29 is FP, x30 is LR, x31 is SP/ZR. + ], + vec![ + preg(vreg(0)), + preg(vreg(1)), + preg(vreg(2)), + preg(vreg(3)), + preg(vreg(4)), + preg(vreg(5)), + preg(vreg(6)), + preg(vreg(7)), + // v8-15 are callee-saved and so not preferred. + preg(vreg(16)), + preg(vreg(17)), + preg(vreg(18)), + preg(vreg(19)), + preg(vreg(20)), + preg(vreg(21)), + preg(vreg(22)), + preg(vreg(23)), + preg(vreg(24)), + preg(vreg(25)), + preg(vreg(26)), + preg(vreg(27)), + preg(vreg(28)), + preg(vreg(29)), + preg(vreg(30)), + preg(vreg(31)), + ], + // Vector Regclass is unused + vec![], + ], + non_preferred_regs_by_class: [ + vec![ + preg(xreg(19)), + preg(xreg(20)), + // x21 is pinned reg if enabled; we add to this list below if not. + preg(xreg(22)), + preg(xreg(23)), + preg(xreg(24)), + preg(xreg(25)), + preg(xreg(26)), + preg(xreg(27)), + preg(xreg(28)), + ], + vec![ + preg(vreg(8)), + preg(vreg(9)), + preg(vreg(10)), + preg(vreg(11)), + preg(vreg(12)), + preg(vreg(13)), + preg(vreg(14)), + preg(vreg(15)), + ], + // Vector Regclass is unused + vec![], + ], + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + }; + + if !enable_pinned_reg { + debug_assert_eq!(PINNED_REG, 21); // We assumed this above in hardcoded reg list. + env.non_preferred_regs_by_class[0].push(preg(xreg(PINNED_REG))); + } + + env +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst.isle b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst.isle new file mode 100644 index 00000000000000..465e729af5c57c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst.isle @@ -0,0 +1,5102 @@ +;; Instruction formats. +(type MInst + (enum + ;; A no-op of zero size. + (Nop0) + + ;; A no-op that is one instruction large. + (Nop4) + + ;; An ALU operation with two register sources and a register destination. + (AluRRR + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; An ALU operation with three register sources and a register destination. + (AluRRRR + (alu_op ALUOp3) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (rm Reg) + (ra Reg)) + + ;; An ALU operation with a register source and an immediate-12 source, and a register + ;; destination. + (AluRRImm12 + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (imm12 Imm12)) + + ;; An ALU operation with a register source and an immediate-logic source, and a register destination. + (AluRRImmLogic + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (imml ImmLogic)) + + ;; An ALU operation with a register source and an immediate-shiftamt source, and a register destination. + (AluRRImmShift + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (immshift ImmShift)) + + ;; An ALU operation with two register sources, one of which can be shifted, and a register + ;; destination. + (AluRRRShift + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (rm Reg) + (shiftop ShiftOpAndAmt)) + + ;; An ALU operation with two register sources, one of which can be {zero,sign}-extended and + ;; shifted, and a register destination. + (AluRRRExtend + (alu_op ALUOp) + (size OperandSize) + (rd WritableReg) + (rn Reg) + (rm Reg) + (extendop ExtendOp)) + + ;; A bit op instruction with a single register source. + (BitRR + (op BitOp) + (size OperandSize) + (rd WritableReg) + (rn Reg)) + + ;; An unsigned (zero-extending) 8-bit load. + (ULoad8 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; A signed (sign-extending) 8-bit load. + (SLoad8 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; An unsigned (zero-extending) 16-bit load. + (ULoad16 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; A signed (sign-extending) 16-bit load. + (SLoad16 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; An unsigned (zero-extending) 32-bit load. + (ULoad32 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; A signed (sign-extending) 32-bit load. + (SLoad32 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; A 64-bit load. + (ULoad64 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; An 8-bit store. + (Store8 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; A 16-bit store. + (Store16 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; A 32-bit store. + (Store32 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; A 64-bit store. + (Store64 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; A store of a pair of registers. + (StoreP64 + (rt Reg) + (rt2 Reg) + (mem PairAMode) + (flags MemFlags)) + + ;; A load of a pair of registers. + (LoadP64 + (rt WritableReg) + (rt2 WritableReg) + (mem PairAMode) + (flags MemFlags)) + + ;; A MOV instruction. These are encoded as ORR's (AluRRR form). + ;; The 32-bit version zeroes the top 32 bits of the + ;; destination, which is effectively an alias for an unsigned + ;; 32-to-64-bit extension. + (Mov + (size OperandSize) + (rd WritableReg) + (rm Reg)) + + ;; Like `Move` but with a particular `PReg` source (for implementing CLIF + ;; instructions like `get_stack_pointer`). + (MovFromPReg + (rd WritableReg) + (rm PReg)) + + ;; Like `Move` but with a particular `PReg` destination (for + ;; implementing CLIF instructions like `set_pinned_reg`). + (MovToPReg + (rd PReg) + (rm Reg)) + + ;; A MOV[Z,N] with a 16-bit immediate. + (MovWide + (op MoveWideOp) + (rd WritableReg) + (imm MoveWideConst) + (size OperandSize)) + + ;; A MOVK with a 16-bit immediate. Modifies its register; we + ;; model this with a separate input `rn` and output `rd` virtual + ;; register, with a regalloc constraint to tie them together. + (MovK + (rd WritableReg) + (rn Reg) + (imm MoveWideConst) + (size OperandSize)) + + + ;; A sign- or zero-extend operation. + (Extend + (rd WritableReg) + (rn Reg) + (signed bool) + (from_bits u8) + (to_bits u8)) + + ;; A conditional-select operation. + (CSel + (rd WritableReg) + (cond Cond) + (rn Reg) + (rm Reg)) + + ;; A conditional-select negation operation. + (CSNeg + (rd WritableReg) + (cond Cond) + (rn Reg) + (rm Reg)) + + ;; A conditional-set operation. + (CSet + (rd WritableReg) + (cond Cond)) + + ;; A conditional-set-mask operation. + (CSetm + (rd WritableReg) + (cond Cond)) + + ;; A conditional comparison with a second register. + (CCmp + (size OperandSize) + (rn Reg) + (rm Reg) + (nzcv NZCV) + (cond Cond)) + + ;; A conditional comparison with an immediate. + (CCmpImm + (size OperandSize) + (rn Reg) + (imm UImm5) + (nzcv NZCV) + (cond Cond)) + + ;; A synthetic insn, which is a load-linked store-conditional loop, that has the overall + ;; effect of atomically modifying a memory location in a particular way. Because we have + ;; no way to explain to the regalloc about earlyclobber registers, this instruction has + ;; completely fixed operand registers, and we rely on the RA's coalescing to remove copies + ;; in the surrounding code to the extent it can. Load- and store-exclusive instructions, + ;; with acquire-release semantics, are used to access memory. The operand conventions are: + ;; + ;; x25 (rd) address + ;; x26 (rd) second operand for `op` + ;; x27 (wr) old value + ;; x24 (wr) scratch reg; value afterwards has no meaning + ;; x28 (wr) scratch reg; value afterwards has no meaning + (AtomicRMWLoop + (ty Type) ;; I8, I16, I32 or I64 + (op AtomicRMWLoopOp) + (flags MemFlags) + (addr Reg) + (operand Reg) + (oldval WritableReg) + (scratch1 WritableReg) + (scratch2 WritableReg)) + + ;; Similar to AtomicRMWLoop, a compare-and-swap operation implemented using a load-linked + ;; store-conditional loop, with acquire-release semantics. + ;; Note that the operand conventions, although very similar to AtomicRMWLoop, are different: + ;; + ;; x25 (rd) address + ;; x26 (rd) expected value + ;; x28 (rd) replacement value + ;; x27 (wr) old value + ;; x24 (wr) scratch reg; value afterwards has no meaning + (AtomicCASLoop + (ty Type) ;; I8, I16, I32 or I64 + (flags MemFlags) + (addr Reg) + (expected Reg) + (replacement Reg) + (oldval WritableReg) + (scratch WritableReg)) + + ;; An atomic read-modify-write operation. These instructions require the + ;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have + ;; acquire-release semantics. + (AtomicRMW + (op AtomicRMWOp) + (rs Reg) + (rt WritableReg) + (rn Reg) + (ty Type) + (flags MemFlags)) + + ;; An atomic compare-and-swap operation. These instructions require the + ;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have + ;; acquire-release semantics. + (AtomicCAS + ;; `rd` is really `rs` in the encoded instruction (so `rd` == `rs`); we separate + ;; them here to have separate use and def vregs for regalloc. + (rd WritableReg) + (rs Reg) + (rt Reg) + (rn Reg) + (ty Type) + (flags MemFlags)) + + ;; Read `access_ty` bits from address `rt`, either 8, 16, 32 or 64-bits, and put + ;; it in `rn`, optionally zero-extending to fill a word or double word result. + ;; This instruction is sequentially consistent. + (LoadAcquire + (access_ty Type) ;; I8, I16, I32 or I64 + (rt WritableReg) + (rn Reg) + (flags MemFlags)) + + ;; Write the lowest `ty` bits of `rt` to address `rn`. + ;; This instruction is sequentially consistent. + (StoreRelease + (access_ty Type) ;; I8, I16, I32 or I64 + (rt Reg) + (rn Reg) + (flags MemFlags)) + + ;; A memory fence. This must provide ordering to ensure that, at a minimum, neither loads + ;; nor stores may move forwards or backwards across the fence. Currently emitted as "dmb + ;; ish". This instruction is sequentially consistent. + (Fence) + + ;; Consumption of speculative data barrier. + (Csdb) + + ;; FPU 32-bit move. + (FpuMove32 + (rd WritableReg) + (rn Reg)) + + ;; FPU move. Note that this is distinct from a vector-register + ;; move; moving just 64 bits seems to be significantly faster. + (FpuMove64 + (rd WritableReg) + (rn Reg)) + + ;; Vector register move. + (FpuMove128 + (rd WritableReg) + (rn Reg)) + + ;; Move to scalar from a vector element. + (FpuMoveFromVec + (rd WritableReg) + (rn Reg) + (idx u8) + (size VectorSize)) + + ;; Zero-extend a SIMD & FP scalar to the full width of a vector register. + ;; 16-bit scalars require half-precision floating-point support (FEAT_FP16). + (FpuExtend + (rd WritableReg) + (rn Reg) + (size ScalarSize)) + + ;; 1-op FPU instruction. + (FpuRR + (fpu_op FPUOp1) + (size ScalarSize) + (rd WritableReg) + (rn Reg)) + + ;; 2-op FPU instruction. + (FpuRRR + (fpu_op FPUOp2) + (size ScalarSize) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + (FpuRRI + (fpu_op FPUOpRI) + (rd WritableReg) + (rn Reg)) + + ;; Variant of FpuRRI that modifies its `rd`, and so we name the + ;; input state `ri` (for "input") and constrain the two + ;; together. + (FpuRRIMod + (fpu_op FPUOpRIMod) + (rd WritableReg) + (ri Reg) + (rn Reg)) + + + ;; 3-op FPU instruction. + ;; 16-bit scalars require half-precision floating-point support (FEAT_FP16). + (FpuRRRR + (fpu_op FPUOp3) + (size ScalarSize) + (rd WritableReg) + (rn Reg) + (rm Reg) + (ra Reg)) + + ;; FPU comparison. + (FpuCmp + (size ScalarSize) + (rn Reg) + (rm Reg)) + + ;; Floating-point load, half-precision (16 bit). + (FpuLoad16 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point store, half-precision (16 bit). + (FpuStore16 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point load, single-precision (32 bit). + (FpuLoad32 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point store, single-precision (32 bit). + (FpuStore32 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point load, double-precision (64 bit). + (FpuLoad64 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point store, double-precision (64 bit). + (FpuStore64 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point/vector load, 128 bit. + (FpuLoad128 + (rd WritableReg) + (mem AMode) + (flags MemFlags)) + + ;; Floating-point/vector store, 128 bit. + (FpuStore128 + (rd Reg) + (mem AMode) + (flags MemFlags)) + + ;; A load of a pair of floating-point registers, double precision (64-bit). + (FpuLoadP64 + (rt WritableReg) + (rt2 WritableReg) + (mem PairAMode) + (flags MemFlags)) + + ;; A store of a pair of floating-point registers, double precision (64-bit). + (FpuStoreP64 + (rt Reg) + (rt2 Reg) + (mem PairAMode) + (flags MemFlags)) + + ;; A load of a pair of floating-point registers, 128-bit. + (FpuLoadP128 + (rt WritableReg) + (rt2 WritableReg) + (mem PairAMode) + (flags MemFlags)) + + ;; A store of a pair of floating-point registers, 128-bit. + (FpuStoreP128 + (rt Reg) + (rt2 Reg) + (mem PairAMode) + (flags MemFlags)) + + ;; Conversion: FP -> integer. + (FpuToInt + (op FpuToIntOp) + (rd WritableReg) + (rn Reg)) + + ;; Conversion: integer -> FP. + (IntToFpu + (op IntToFpuOp) + (rd WritableReg) + (rn Reg)) + + ;; FP conditional select, 16 bit. + ;; Requires FEAT_FP16. + (FpuCSel16 + (rd WritableReg) + (rn Reg) + (rm Reg) + (cond Cond)) + + ;; FP conditional select, 32 bit. + (FpuCSel32 + (rd WritableReg) + (rn Reg) + (rm Reg) + (cond Cond)) + + ;; FP conditional select, 64 bit. + (FpuCSel64 + (rd WritableReg) + (rn Reg) + (rm Reg) + (cond Cond)) + + ;; Round to integer. + (FpuRound + (op FpuRoundMode) + (rd WritableReg) + (rn Reg)) + + ;; Move from a GPR to a vector register. The scalar value is parked in the lowest lane + ;; of the destination, and all other lanes are zeroed out. Currently 16-, 32- and 64-bit + ;; transactions are supported. 16-bit moves require FEAT_FP16. + (MovToFpu + (rd WritableReg) + (rn Reg) + (size ScalarSize)) + + ;; Loads a floating-point immediate. + (FpuMoveFPImm + (rd WritableReg) + (imm ASIMDFPModImm) + (size ScalarSize)) + + ;; Move to a vector element from a GPR. + (MovToVec + (rd WritableReg) + (ri Reg) + (rn Reg) + (idx u8) + (size VectorSize)) + + ;; Unsigned move from a vector element to a GPR. + (MovFromVec + (rd WritableReg) + (rn Reg) + (idx u8) + (size ScalarSize)) + + ;; Signed move from a vector element to a GPR. + (MovFromVecSigned + (rd WritableReg) + (rn Reg) + (idx u8) + (size VectorSize) + (scalar_size OperandSize)) + + ;; Duplicate general-purpose register to vector. + (VecDup + (rd WritableReg) + (rn Reg) + (size VectorSize)) + + ;; Duplicate scalar to vector. + (VecDupFromFpu + (rd WritableReg) + (rn Reg) + (size VectorSize) + (lane u8)) + + ;; Duplicate FP immediate to vector. + (VecDupFPImm + (rd WritableReg) + (imm ASIMDFPModImm) + (size VectorSize)) + + ;; Duplicate immediate to vector. + (VecDupImm + (rd WritableReg) + (imm ASIMDMovModImm) + (invert bool) + (size VectorSize)) + + ;; Vector extend. + (VecExtend + (t VecExtendOp) + (rd WritableReg) + (rn Reg) + (high_half bool) + (lane_size ScalarSize)) + + ;; Move vector element to another vector element. + (VecMovElement + (rd WritableReg) + (ri Reg) + (rn Reg) + (dest_idx u8) + (src_idx u8) + (size VectorSize)) + + ;; Vector widening operation. + (VecRRLong + (op VecRRLongOp) + (rd WritableReg) + (rn Reg) + (high_half bool)) + + ;; Vector narrowing operation -- low half. + (VecRRNarrowLow + (op VecRRNarrowOp) + (rd WritableReg) + (rn Reg) + (lane_size ScalarSize)) + + ;; Vector narrowing operation -- high half. + (VecRRNarrowHigh + (op VecRRNarrowOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (lane_size ScalarSize)) + + ;; 1-operand vector instruction that operates on a pair of elements. + (VecRRPair + (op VecPairOp) + (rd WritableReg) + (rn Reg)) + + ;; 2-operand vector instruction that produces a result with twice the + ;; lane width and half the number of lanes. + (VecRRRLong + (alu_op VecRRRLongOp) + (rd WritableReg) + (rn Reg) + (rm Reg) + (high_half bool)) + + ;; 2-operand vector instruction that produces a result with + ;; twice the lane width and half the number of lanes. Variant + ;; that modifies `rd` (so takes its initial state as `ri`). + (VecRRRLongMod + (alu_op VecRRRLongModOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (rm Reg) + (high_half bool)) + + ;; 1-operand vector instruction that extends elements of the input + ;; register and operates on a pair of elements. The output lane width + ;; is double that of the input. + (VecRRPairLong + (op VecRRPairLongOp) + (rd WritableReg) + (rn Reg)) + + ;; A vector ALU op. + (VecRRR + (alu_op VecALUOp) + (rd WritableReg) + (rn Reg) + (rm Reg) + (size VectorSize)) + + ;; A vector ALU op modifying a source register. + (VecRRRMod + (alu_op VecALUModOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (rm Reg) + (size VectorSize)) + + ;; A vector ALU op modifying a source register. + (VecFmlaElem + (alu_op VecALUModOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (rm Reg) + (size VectorSize) + (idx u8)) + + ;; Vector two register miscellaneous instruction. + (VecMisc + (op VecMisc2) + (rd WritableReg) + (rn Reg) + (size VectorSize)) + + ;; Vector instruction across lanes. + (VecLanes + (op VecLanesOp) + (rd WritableReg) + (rn Reg) + (size VectorSize)) + + ;; Vector shift by immediate Shift Left (immediate), Unsigned Shift Right (immediate) + ;; Signed Shift Right (immediate). These are somewhat unusual in that, for right shifts, + ;; the allowed range of `imm` values is 1 to lane-size-in-bits, inclusive. A zero + ;; right-shift cannot be encoded. Left shifts are "normal", though, having valid `imm` + ;; values from 0 to lane-size-in-bits - 1 inclusive. + (VecShiftImm + (op VecShiftImmOp) + (rd WritableReg) + (rn Reg) + (size VectorSize) + (imm u8)) + + ;; Destructive vector shift by immediate. + (VecShiftImmMod + (op VecShiftImmModOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (size VectorSize) + (imm u8)) + + ;; Vector extract - create a new vector, being the concatenation of the lowest `imm4` bytes + ;; of `rm` followed by the uppermost `16 - imm4` bytes of `rn`. + (VecExtract + (rd WritableReg) + (rn Reg) + (rm Reg) + (imm4 u8)) + + ;; Table vector lookup - single register table. The table + ;; consists of 8-bit elements and is stored in `rn`, while `rm` + ;; contains 8-bit element indices. This variant emits `TBL`, + ;; which sets elements that correspond to out-of-range indices + ;; (greater than 15) to 0. + (VecTbl + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Table vector lookup - single register table. The table + ;; consists of 8-bit elements and is stored in `rn`, while `rm` + ;; contains 8-bit element indices. This variant emits `TBX`, + ;; which leaves elements that correspond to out-of-range indices + ;; (greater than 15) unmodified. Hence, it takes an input vreg in + ;; `ri` that is constrained to the same allocation as `rd`. + (VecTblExt + (rd WritableReg) + (ri Reg) + (rn Reg) + (rm Reg)) + + ;; Table vector lookup - two register table. The table consists + ;; of 8-bit elements and is stored in `rn` and `rn2`, while + ;; `rm` contains 8-bit element indices. The table registers + ;; `rn` and `rn2` must have consecutive numbers modulo 32, that + ;; is v31 and v0 (in that order) are consecutive registers. + ;; This variant emits `TBL`, which sets out-of-range results to + ;; 0. + (VecTbl2 + (rd WritableReg) + (rn Reg) + (rn2 Reg) + (rm Reg)) + + ;; Table vector lookup - two register table. The table consists + ;; of 8-bit elements and is stored in `rn` and `rn2`, while + ;; `rm` contains 8-bit element indices. The table registers + ;; `rn` and `rn2` must have consecutive numbers modulo 32, that + ;; is v31 and v0 (in that order) are consecutive registers. + ;; This variant emits `TBX`, which leaves out-of-range results + ;; unmodified, hence takes the initial state of the result + ;; register in vreg `ri`. + (VecTbl2Ext + (rd WritableReg) + (ri Reg) + (rn Reg) + (rn2 Reg) + (rm Reg)) + + ;; Load an element and replicate to all lanes of a vector. + (VecLoadReplicate + (rd WritableReg) + (rn Reg) + (size VectorSize) + (flags MemFlags)) + + ;; Vector conditional select, 128 bit. A synthetic instruction, which generates a 4-insn + ;; control-flow diamond. + (VecCSel + (rd WritableReg) + (rn Reg) + (rm Reg) + (cond Cond)) + + ;; Move to the NZCV flags (actually a `MSR NZCV, Xn` insn). + (MovToNZCV + (rn Reg)) + + ;; Move from the NZCV flags (actually a `MRS Xn, NZCV` insn). + (MovFromNZCV + (rd WritableReg)) + + ;; A machine call instruction. N.B.: this allows only a +/- 128MB offset (it uses a relocation + ;; of type `Reloc::Arm64Call`); if the destination distance is not `RelocDistance::Near`, the + ;; code should use a `LoadExtName` / `CallInd` sequence instead, allowing an arbitrary 64-bit + ;; target. + (Call (info BoxCallInfo)) + + ;; A machine indirect-call instruction. + (CallInd (info BoxCallIndInfo)) + + ;; A return-call macro instruction. + (ReturnCall (info BoxReturnCallInfo)) + + ;; An indirect return-call macro instruction. + (ReturnCallInd (info BoxReturnCallIndInfo)) + + ;; A pseudo-instruction that captures register arguments in vregs. + (Args + (args VecArgPair)) + + ;; A pseudo-instruction that moves vregs to return registers. + (Rets + (rets VecRetPair)) + + ;; ---- branches (exactly one must appear at end of BB) ---- + + ;; A machine return instruction. + (Ret) + + ;; A machine return instruction with pointer authentication using SP as the + ;; modifier. This instruction requires pointer authentication support + ;; (FEAT_PAuth) unless `is_hint` is true, in which case it is equivalent to + ;; the combination of a no-op and a return instruction on platforms without + ;; the relevant support. + (AuthenticatedRet + (key APIKey) + (is_hint bool)) + + ;; An unconditional branch. + (Jump + (dest BranchTarget)) + + ;; A conditional branch. Contains two targets; at emission time, both are emitted, but + ;; the MachBuffer knows to truncate the trailing branch if fallthrough. We optimize the + ;; choice of taken/not_taken (inverting the branch polarity as needed) based on the + ;; fallthrough at the time of lowering. + (CondBr + (taken BranchTarget) + (not_taken BranchTarget) + (kind CondBrKind)) + + ;; A conditional branch which tests the `bit` of `rn` and branches + ;; depending on `kind`. + (TestBitAndBranch + (kind TestBitAndBranchKind) + (taken BranchTarget) + (not_taken BranchTarget) + (rn Reg) + (bit u8)) + + ;; A conditional trap: execute a `udf` if the condition is true. This is + ;; one VCode instruction because it uses embedded control flow; it is + ;; logically a single-in, single-out region, but needs to appear as one + ;; unit to the register allocator. + ;; + ;; The `CondBrKind` gives the conditional-branch condition that will + ;; *execute* the embedded `Inst`. (In the emitted code, we use the inverse + ;; of this condition in a branch that skips the trap instruction.) + (TrapIf + (kind CondBrKind) + (trap_code TrapCode)) + + ;; An indirect branch through a register, augmented with set of all + ;; possible successors. + (IndirectBr + (rn Reg) + (targets VecMachLabel)) + + ;; A "break" instruction, used for e.g. traps and debug breakpoints. + (Brk) + + ;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at + ;; runtime. + (Udf + (trap_code TrapCode)) + + ;; Compute the address (using a PC-relative offset) of a memory location, using the `ADR` + ;; instruction. Note that we take a simple offset, not a `MemLabel`, here, because `Adr` is + ;; only used for now in fixed lowering sequences with hardcoded offsets. In the future we may + ;; need full `MemLabel` support. + (Adr + (rd WritableReg) + ;; Offset in range -2^20 .. 2^20. + (off i32)) + + ;; Compute the address (using a PC-relative offset) of a 4KB page. + (Adrp + (rd WritableReg) + (off i32)) + + ;; Raw 32-bit word, used for inline constants and jump-table entries. + (Word4 + (data u32)) + + ;; Raw 64-bit word, used for inline constants. + (Word8 + (data u64)) + + ;; Jump-table sequence, as one compound instruction (see note in lower_inst.rs for rationale). + (JTSequence + (default MachLabel) + (targets BoxVecMachLabel) + (ridx Reg) + (rtmp1 WritableReg) + (rtmp2 WritableReg)) + + ;; Load an inline symbol reference. + (LoadExtName + (rd WritableReg) + (name BoxExternalName) + (offset i64)) + + ;; Load address referenced by `mem` into `rd`. + (LoadAddr + (rd WritableReg) + (mem AMode)) + + ;; Pointer authentication code for instruction address with modifier in SP; + ;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not + ;; supported. + (Paci + (key APIKey)) + + ;; Strip pointer authentication code from instruction address in LR; + ;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not + ;; supported. + (Xpaclri) + + ;; Branch target identification; equivalent to a no-op if Branch Target + ;; Identification (FEAT_BTI) is not supported. + (Bti + (targets BranchTargetType)) + + ;; Meta-insn, no-op in generated code: emit constant/branch veneer island + ;; at this point (with a guard jump around it) if less than the needed + ;; space is available before the next branch deadline. See the `MachBuffer` + ;; implementation in `machinst/buffer.rs` for the overall algorithm. In + ;; brief, we retain a set of "pending/unresolved label references" from + ;; branches as we scan forward through instructions to emit machine code; + ;; if we notice we're about to go out of range on an unresolved reference, + ;; we stop, emit a bunch of "veneers" (branches in a form that has a longer + ;; range, e.g. a 26-bit-offset unconditional jump), and point the original + ;; label references to those. This is an "island" because it comes in the + ;; middle of the code. + ;; + ;; This meta-instruction is a necessary part of the logic that determines + ;; where to place islands. Ordinarily, we want to place them between basic + ;; blocks, so we compute the worst-case size of each block, and emit the + ;; island before starting a block if we would exceed a deadline before the + ;; end of the block. However, some sequences (such as an inline jumptable) + ;; are variable-length and not accounted for by this logic; so these + ;; lowered sequences include an `EmitIsland` to trigger island generation + ;; where necessary. + (EmitIsland + ;; The needed space before the next deadline. + (needed_space CodeOffset)) + + ;; A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol in x0. + (ElfTlsGetAddr + (symbol BoxExternalName) + (rd WritableReg) + (tmp WritableReg)) + + (MachOTlsGetAddr + (symbol ExternalName) + (rd WritableReg)) + + ;; An unwind pseudo-instruction. + (Unwind + (inst UnwindInst)) + + ;; A dummy use, useful to keep a value alive. + (DummyUse + (reg Reg)) + + ;; Emits an inline stack probe loop. + ;; + ;; Note that this is emitted post-regalloc so `start` and `end` can be + ;; temporary registers such as the spilltmp and tmp2 registers. This also + ;; means that the internal codegen can't use these registers. + (StackProbeLoop (start WritableReg) + (end Reg) + (step Imm12)))) + +(model ALUOp (enum + (Add #x00) ;; 0 + (Sub #x01) + (Orr #x02) + (OrrNot #x03) + (And #x04) + (AndNot #x05) + (Eor #x06) + (EorNot #x07) + (SubS #x08) + (SDiv #x09) + (UDiv #x0a) + (RotR #x0b) + (Lsr #x0c) + (Asr #x0d) + (Lsl #x0e))) + +;; An ALU operation. This can be paired with several instruction formats +;; below (see `Inst`) in any combination. +(type ALUOp + (enum + (Add) + (Sub) + (Orr) + (OrrNot) + (And) + (AndS) + (AndNot) + ;; XOR (AArch64 calls this "EOR") + (Eor) + ;; XNOR (AArch64 calls this "EOR-NOT") + (EorNot) + ;; Add, setting flags + (AddS) + ;; Sub, setting flags + (SubS) + ;; Signed multiply, high-word result + (SMulH) + ;; Unsigned multiply, high-word result + (UMulH) + (SDiv) + (UDiv) + (RotR) + (Lsr) + (Asr) + (Lsl) + ;; Add with carry + (Adc) + ;; Add with carry, settings flags + (AdcS) + ;; Subtract with carry + (Sbc) + ;; Subtract with carry, settings flags + (SbcS) +)) + +;; An ALU operation with three arguments. +(type ALUOp3 + (enum + ;; Multiply-add + (MAdd) + ;; Multiply-sub + (MSub) + ;; Unsigned-Multiply-add + (UMAddL) + ;; Signed-Multiply-add + (SMAddL) +)) + +(type MoveWideOp + (enum + (MovZ) + (MovN) +)) + +(type UImm5 (primitive UImm5)) +(model Imm12 (type (bv 24))) +(type Imm12 (primitive Imm12)) +(model ImmLogic (type (bv 64))) +(type ImmLogic (primitive ImmLogic)) +(model ImmShift (type (bv 6))) +(type ImmShift (primitive ImmShift)) +(model ShiftOpAndAmt (type (bv 16))) +(type ShiftOpAndAmt (primitive ShiftOpAndAmt)) +(model MoveWideConst (type (bv 16))) +(type MoveWideConst (primitive MoveWideConst)) +(type NZCV (primitive NZCV)) +(type ASIMDFPModImm (primitive ASIMDFPModImm)) +(type ASIMDMovModImm (primitive ASIMDMovModImm)) +(type SImm7Scaled (primitive SImm7Scaled)) + +(type BoxCallInfo (primitive BoxCallInfo)) +(type BoxCallIndInfo (primitive BoxCallIndInfo)) +(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) +(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) +(type CondBrKind (primitive CondBrKind)) +(type BranchTarget (primitive BranchTarget)) +(type BoxJTSequenceInfo (primitive BoxJTSequenceInfo)) +(type CodeOffset (primitive CodeOffset)) +(type VecMachLabel extern (enum)) + +(model ExtendOp (enum + (UXTB #b000) + (UXTH #b001) + (UXTW #b010) + (UXTX #b011) + (SXTB #b100) + (SXTH #b101) + (SXTW #b110) + (SXTX #b111) +)) + +(type ExtendOp extern + (enum + (UXTB) + (UXTH) + (UXTW) + (UXTX) + (SXTB) + (SXTH) + (SXTW) + (SXTX) +)) + +;; An operation on the bits of a register. This can be paired with several instruction formats +;; below (see `Inst`) in any combination. +(type BitOp + (enum + ;; Bit reverse + (RBit) + (Clz) + (Cls) + ;; Byte reverse + (Rev16) + (Rev32) + (Rev64) +)) + +(type MemLabel extern (enum)) +(type SImm9 extern (enum)) +(type UImm12Scaled extern (enum)) + +;; An addressing mode specified for a load/store operation. +(type AMode + (enum + ;; + ;; Real ARM64 addressing modes: + ;; + ;; "post-indexed" mode as per AArch64 docs: postincrement reg after + ;; address computation. + ;; Specialized here to SP so we don't have to emit regalloc metadata. + (SPPostIndexed + (simm9 SImm9)) + + ;; "pre-indexed" mode as per AArch64 docs: preincrement reg before + ;; address computation. + ;; Specialized here to SP so we don't have to emit regalloc metadata. + (SPPreIndexed + (simm9 SImm9)) + + ;; N.B.: RegReg, RegScaled, and RegScaledExtended all correspond to + ;; what the ISA calls the "register offset" addressing mode. We split + ;; out several options here for more ergonomic codegen. + ;; + ;; Register plus register offset. + (RegReg + (rn Reg) + (rm Reg)) + + ;; Register plus register offset, scaled by type's size. + (RegScaled + (rn Reg) + (rm Reg)) + + ;; Register plus register offset, scaled by type's size, with index + ;; sign- or zero-extended first. + (RegScaledExtended + (rn Reg) + (rm Reg) + (extendop ExtendOp)) + + ;; Register plus register offset, with index sign- or zero-extended + ;; first. + (RegExtended + (rn Reg) + (rm Reg) + (extendop ExtendOp)) + + ;; Unscaled signed 9-bit immediate offset from reg. + (Unscaled + (rn Reg) + (simm9 SImm9)) + + ;; Scaled (by size of a type) unsigned 12-bit immediate offset from reg. + (UnsignedOffset + (rn Reg) + (uimm12 UImm12Scaled)) + + ;; virtual addressing modes that are lowered at emission time: + ;; + ;; Reference to a "label": e.g., a symbol. + (Label + (label MemLabel)) + + ;; Arbitrary offset from a register. Converted to generation of large + ;; offsets with multiple instructions as necessary during code emission. + (RegOffset + (rn Reg) + (off i64)) + + ;; Offset from the stack pointer. + (SPOffset + (off i64)) + + ;; Offset from the frame pointer. + (FPOffset + (off i64)) + + ;; A reference to a constant which is placed outside of the function's + ;; body, typically at the end. + (Const + (addr VCodeConstant)) + + ;; Offset from the beginning of the argument area to the argument + ;; referenced. This can only be determined when the function has been + ;; processed fully, as the size of the argument area after the prologue + ;; is only known once all return_call instructions in the function body + ;; have been processed. + (IncomingArg + (off i64)) + + ;; Offset into the slot area of the stack, which lies just above the + ;; outgoing argument area that's setup by the function prologue. + ;; At emission time, this is converted to `SPOffset` with a fixup added to + ;; the offset constant. The fixup is a running value that is tracked as + ;; emission iterates through instructions in linear order, and can be + ;; adjusted up and down with [Inst::VirtualSPOffsetAdj]. + ;; + ;; The standard ABI is in charge of handling this (by emitting the + ;; adjustment meta-instructions). See the diagram in the documentation + ;; for [crate::isa::aarch64::abi](the ABI module) for more details. + (SlotOffset + (off i64)))) + +;; A memory argument to a load/store-pair. +(type PairAMode (enum + ;; Signed, scaled 7-bit offset from a register. + (SignedOffset + (reg Reg) + (simm7 SImm7Scaled)) + + ;; Pre-increment register before address computation. + (SPPreIndexed (simm7 SImm7Scaled)) + + ;; Post-increment register after address computation. + (SPPostIndexed (simm7 SImm7Scaled)) +)) + +(type FPUOpRI extern (enum)) +(type FPUOpRIMod extern (enum)) + +(model OperandSize + (enum (Size32 32) + (Size64 64))) + +(type OperandSize extern + (enum Size32 + Size64)) + +(type TestBitAndBranchKind (enum (Z) (NZ))) + +;; Helper for calculating the `OperandSize` corresponding to a type +(spec (operand_size ty) + (provide + (= result (if (<= ty 32) 32 64))) + (require + (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(instantiate operand_size + ((args Int) (ret Int) (canon (bv 8))) + ((args Int) (ret Int) (canon (bv 16))) + ((args Int) (ret Int) (canon (bv 32))) + ((args Int) (ret Int) (canon (bv 64))) +) +(decl operand_size (Type) OperandSize) +(rule operand_size_32 1 (operand_size (fits_in_32 _ty)) (OperandSize.Size32)) +(rule operand_size_64 (operand_size (fits_in_64 _ty)) (OperandSize.Size64)) + +(model ScalarSize + (enum (Size8 8) + (Size16 16) + (Size32 32) + (Size64 64) + (Size128 128))) + +;; Difference (32 - ty), useful for narrow calculations with 32-bit +;; instructions. +(decl diff_from_32 (Type) u8) +(rule (diff_from_32 $I8) 24) +(rule (diff_from_32 $I16) 16) + +(type ScalarSize extern + (enum Size8 + Size16 + Size32 + Size64 + Size128)) + +;; Helper for calculating the `ScalarSize` corresponding to a type +(decl scalar_size (Type) ScalarSize) + +(rule (scalar_size $I8) (ScalarSize.Size8)) +(rule (scalar_size $I16) (ScalarSize.Size16)) +(rule (scalar_size $I32) (ScalarSize.Size32)) +(rule (scalar_size $I64) (ScalarSize.Size64)) +(rule (scalar_size $I128) (ScalarSize.Size128)) + +(rule (scalar_size $F32) (ScalarSize.Size32)) +(rule (scalar_size $F64) (ScalarSize.Size64)) + +;; Helper for calculating the `ScalarSize` lane type from vector type +(decl lane_size (Type) ScalarSize) +(rule 1 (lane_size (multi_lane 8 _)) (ScalarSize.Size8)) +(rule 1 (lane_size (multi_lane 16 _)) (ScalarSize.Size16)) +(rule 1 (lane_size (multi_lane 32 _)) (ScalarSize.Size32)) +(rule 1 (lane_size (multi_lane 64 _)) (ScalarSize.Size64)) +(rule (lane_size (dynamic_lane 8 _)) (ScalarSize.Size8)) +(rule (lane_size (dynamic_lane 16 _)) (ScalarSize.Size16)) +(rule (lane_size (dynamic_lane 32 _)) (ScalarSize.Size32)) +(rule (lane_size (dynamic_lane 64 _)) (ScalarSize.Size64)) + +;; Helper for extracting the size of a lane from the input `VectorSize` +(decl pure vector_lane_size (VectorSize) ScalarSize) +(rule (vector_lane_size (VectorSize.Size8x16)) (ScalarSize.Size8)) +(rule (vector_lane_size (VectorSize.Size8x8)) (ScalarSize.Size8)) +(rule (vector_lane_size (VectorSize.Size16x8)) (ScalarSize.Size16)) +(rule (vector_lane_size (VectorSize.Size16x4)) (ScalarSize.Size16)) +(rule (vector_lane_size (VectorSize.Size32x4)) (ScalarSize.Size32)) +(rule (vector_lane_size (VectorSize.Size32x2)) (ScalarSize.Size32)) +(rule (vector_lane_size (VectorSize.Size64x2)) (ScalarSize.Size64)) + +(model Cond + (enum (Lo #x03) + (Hi #x08) + (Lt #x0b) + (Gt #x0c))) + +(type Cond extern + (enum + (Eq) + (Ne) + (Hs) + (Lo) + (Mi) + (Pl) + (Vs) + (Vc) + (Hi) + (Ls) + (Ge) + (Lt) + (Gt) + (Le) + (Al) + (Nv) +)) + +(model VectorSize + (enum + (Size8x8 #x00) + (Size8x16 #x01) + (Size16x4 #x02) + (Size16x8 #x03) + (Size32x2 #x04) + (Size32x4 #x05) + (Size64x2 #x06))) + +(type VectorSize extern + (enum + (Size8x8) + (Size8x16) + (Size16x4) + (Size16x8) + (Size32x2) + (Size32x4) + (Size64x2) +)) + +;; Helper for calculating the `VectorSize` corresponding to a type +(decl vector_size (Type) VectorSize) +(rule 1 (vector_size (multi_lane 8 8)) (VectorSize.Size8x8)) +(rule 1 (vector_size (multi_lane 8 16)) (VectorSize.Size8x16)) +(rule 1 (vector_size (multi_lane 16 4)) (VectorSize.Size16x4)) +(rule 1 (vector_size (multi_lane 16 8)) (VectorSize.Size16x8)) +(rule 1 (vector_size (multi_lane 32 2)) (VectorSize.Size32x2)) +(rule 1 (vector_size (multi_lane 32 4)) (VectorSize.Size32x4)) +(rule 1 (vector_size (multi_lane 64 2)) (VectorSize.Size64x2)) +(rule (vector_size (dynamic_lane 8 8)) (VectorSize.Size8x8)) +(rule (vector_size (dynamic_lane 8 16)) (VectorSize.Size8x16)) +(rule (vector_size (dynamic_lane 16 4)) (VectorSize.Size16x4)) +(rule (vector_size (dynamic_lane 16 8)) (VectorSize.Size16x8)) +(rule (vector_size (dynamic_lane 32 2)) (VectorSize.Size32x2)) +(rule (vector_size (dynamic_lane 32 4)) (VectorSize.Size32x4)) +(rule (vector_size (dynamic_lane 64 2)) (VectorSize.Size64x2)) + +;; A floating-point unit (FPU) operation with one arg. +(type FPUOp1 + (enum + (Abs) + (Neg) + (Sqrt) + (Cvt32To64) + (Cvt64To32) +)) + +;; A floating-point unit (FPU) operation with two args. +(type FPUOp2 + (enum + (Add) + (Sub) + (Mul) + (Div) + (Max) + (Min) +)) + +;; A floating-point unit (FPU) operation with three args. +(type FPUOp3 + (enum + ;; Multiply-add + (MAdd) + ;; Multiply-sub + (MSub) + ;; Negated fused Multiply-add + (NMAdd) + ;; Negated fused Multiply-sub + (NMSub) +)) + +;; A conversion from an FP to an integer value. +(type FpuToIntOp + (enum + (F32ToU32) + (F32ToI32) + (F32ToU64) + (F32ToI64) + (F64ToU32) + (F64ToI32) + (F64ToU64) + (F64ToI64) +)) + +;; A conversion from an integer to an FP value. +(type IntToFpuOp + (enum + (U32ToF32) + (I32ToF32) + (U32ToF64) + (I32ToF64) + (U64ToF32) + (I64ToF32) + (U64ToF64) + (I64ToF64) +)) + +;; Modes for FP rounding ops: round down (floor) or up (ceil), or toward zero (trunc), or to +;; nearest, and for 32- or 64-bit FP values. +(type FpuRoundMode + (enum + (Minus32) + (Minus64) + (Plus32) + (Plus64) + (Zero32) + (Zero64) + (Nearest32) + (Nearest64) +)) + +;; Type of vector element extensions. +(type VecExtendOp + (enum + ;; Signed extension + (Sxtl) + ;; Unsigned extension + (Uxtl) +)) + +;; A vector ALU operation. +(type VecALUOp + (enum + ;; Signed saturating add + (Sqadd) + ;; Unsigned saturating add + (Uqadd) + ;; Signed saturating subtract + (Sqsub) + ;; Unsigned saturating subtract + (Uqsub) + ;; Compare bitwise equal + (Cmeq) + ;; Compare signed greater than or equal + (Cmge) + ;; Compare signed greater than + (Cmgt) + ;; Compare unsigned higher + (Cmhs) + ;; Compare unsigned higher or same + (Cmhi) + ;; Floating-point compare equal + (Fcmeq) + ;; Floating-point compare greater than + (Fcmgt) + ;; Floating-point compare greater than or equal + (Fcmge) + ;; Bitwise and + (And) + ;; Bitwise bit clear + (Bic) + ;; Bitwise inclusive or + (Orr) + ;; Bitwise exclusive or + (Eor) + ;; Unsigned maximum pairwise + (Umaxp) + ;; Add + (Add) + ;; Subtract + (Sub) + ;; Multiply + (Mul) + ;; Signed shift left + (Sshl) + ;; Unsigned shift left + (Ushl) + ;; Unsigned minimum + (Umin) + ;; Signed minimum + (Smin) + ;; Unsigned maximum + (Umax) + ;; Signed maximum + (Smax) + ;; Unsigned rounding halving add + (Urhadd) + ;; Floating-point add + (Fadd) + ;; Floating-point subtract + (Fsub) + ;; Floating-point divide + (Fdiv) + ;; Floating-point maximum + (Fmax) + ;; Floating-point minimum + (Fmin) + ;; Floating-point multiply + (Fmul) + ;; Add pairwise + (Addp) + ;; Zip vectors (primary) [meaning, high halves] + (Zip1) + ;; Zip vectors (secondary) + (Zip2) + ;; Signed saturating rounding doubling multiply returning high half + (Sqrdmulh) + ;; Unzip vectors (primary) + (Uzp1) + ;; Unzip vectors (secondary) + (Uzp2) + ;; Transpose vectors (primary) + (Trn1) + ;; Transpose vectors (secondary) + (Trn2) +)) + +;; A Vector ALU operation which modifies a source register. +(type VecALUModOp + (enum + ;; Bitwise select + (Bsl) + ;; Floating-point fused multiply-add vectors + (Fmla) + ;; Floating-point fused multiply-subtract vectors + (Fmls) +)) + +;; A Vector miscellaneous operation with two registers. +(type VecMisc2 + (enum + ;; Bitwise NOT + (Not) + ;; Negate + (Neg) + ;; Absolute value + (Abs) + ;; Floating-point absolute value + (Fabs) + ;; Floating-point negate + (Fneg) + ;; Floating-point square root + (Fsqrt) + ;; Reverse elements in 16-bit lanes + (Rev16) + ;; Reverse elements in 32-bit lanes + (Rev32) + ;; Reverse elements in 64-bit doublewords + (Rev64) + ;; Floating-point convert to signed integer, rounding toward zero + (Fcvtzs) + ;; Floating-point convert to unsigned integer, rounding toward zero + (Fcvtzu) + ;; Signed integer convert to floating-point + (Scvtf) + ;; Unsigned integer convert to floating-point + (Ucvtf) + ;; Floating point round to integral, rounding towards nearest + (Frintn) + ;; Floating point round to integral, rounding towards zero + (Frintz) + ;; Floating point round to integral, rounding towards minus infinity + (Frintm) + ;; Floating point round to integral, rounding towards plus infinity + (Frintp) + ;; Population count per byte + (Cnt) + ;; Compare bitwise equal to 0 + (Cmeq0) + ;; Compare signed greater than or equal to 0 + (Cmge0) + ;; Compare signed greater than 0 + (Cmgt0) + ;; Compare signed less than or equal to 0 + (Cmle0) + ;; Compare signed less than 0 + (Cmlt0) + ;; Floating point compare equal to 0 + (Fcmeq0) + ;; Floating point compare greater than or equal to 0 + (Fcmge0) + ;; Floating point compare greater than 0 + (Fcmgt0) + ;; Floating point compare less than or equal to 0 + (Fcmle0) + ;; Floating point compare less than 0 + (Fcmlt0) +)) + +;; A vector widening operation with one argument. +(type VecRRLongOp + (enum + ;; Floating-point convert to higher precision long, 16-bit elements + (Fcvtl16) + ;; Floating-point convert to higher precision long, 32-bit elements + (Fcvtl32) + ;; Shift left long (by element size), 8-bit elements + (Shll8) + ;; Shift left long (by element size), 16-bit elements + (Shll16) + ;; Shift left long (by element size), 32-bit elements + (Shll32) +)) + +;; A vector narrowing operation with one argument. +(type VecRRNarrowOp + (enum + ;; Extract narrow. + (Xtn) + ;; Signed saturating extract narrow. + (Sqxtn) + ;; Signed saturating extract unsigned narrow. + (Sqxtun) + ;; Unsigned saturating extract narrow. + (Uqxtn) + ;; Floating-point convert to lower precision narrow. + (Fcvtn) +)) + +(type VecRRRLongOp + (enum + ;; Signed multiply long. + (Smull8) + (Smull16) + (Smull32) + ;; Unsigned multiply long. + (Umull8) + (Umull16) + (Umull32) +)) + +(type VecRRRLongModOp + (enum + ;; Unsigned multiply add long + (Umlal8) + (Umlal16) + (Umlal32) +)) + +;; A vector operation on a pair of elements with one register. +(type VecPairOp + (enum + ;; Add pair of elements + (Addp) +)) + +;; 1-operand vector instruction that extends elements of the input register +;; and operates on a pair of elements. +(type VecRRPairLongOp + (enum + ;; Sign extend and add pair of elements + (Saddlp8) + (Saddlp16) + ;; Unsigned extend and add pair of elements + (Uaddlp8) + (Uaddlp16) +)) + +;; An operation across the lanes of vectors. +(type VecLanesOp + (enum + ;; Integer addition across a vector + (Addv) + ;; Unsigned minimum across a vector + (Uminv) +)) + +;; A shift-by-immediate operation on each lane of a vector. +(type VecShiftImmOp + (enum + ;; Unsigned shift left + (Shl) + ;; Unsigned shift right + (Ushr) + ;; Signed shift right + (Sshr) +)) + +;; Destructive shift-by-immediate operation on each lane of a vector. +(type VecShiftImmModOp + (enum + ;; Shift left and insert + (Sli) +)) + +;; Atomic read-modify-write operations with acquire-release semantics +(type AtomicRMWOp + (enum + (Add) + (Clr) + (Eor) + (Set) + (Smax) + (Smin) + (Umax) + (Umin) + (Swp) +)) + +;; Atomic read-modify-write operations, with acquire-release semantics, +;; implemented with a loop. +(type AtomicRMWLoopOp + (enum + (Add) + (Sub) + (And) + (Nand) + (Eor) + (Orr) + (Smax) + (Smin) + (Umax) + (Umin) + (Xchg) +)) + +;; Keys for instruction address PACs +(type APIKey + (enum + ;; API key A with the modifier of SP + (ASP) + ;; API key B with the modifier of SP + (BSP) + ;; API key A with the modifier of zero + (AZ) + ;; API key B with the modifier of zero + (BZ) +)) + +;; Branch target types +(type BranchTargetType + (enum + (None) + (C) + (J) + (JC) +)) + +;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(decl pure partial sign_return_address_disabled () Unit) +(extern constructor sign_return_address_disabled sign_return_address_disabled) + +(decl use_lse () Inst) +(extern extractor use_lse use_lse) + +(decl pure use_fp16 () bool) +(extern constructor use_fp16 use_fp16) + +;; Extractor helpers for various immediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pure partial move_wide_const_from_u64 (Type u64) MoveWideConst) +(extern constructor move_wide_const_from_u64 move_wide_const_from_u64) + +(decl pure partial move_wide_const_from_inverted_u64 (Type u64) MoveWideConst) +(extern constructor move_wide_const_from_inverted_u64 move_wide_const_from_inverted_u64) + +(decl pure partial imm_logic_from_u64 (Type u64) ImmLogic) +(extern constructor imm_logic_from_u64 imm_logic_from_u64) + +(decl pure partial imm_size_from_type (Type) u16) +(extern constructor imm_size_from_type imm_size_from_type) + +(decl pure partial imm_logic_from_imm64 (Type Imm64) ImmLogic) +(extern constructor imm_logic_from_imm64 imm_logic_from_imm64) + +(spec (imm_shift_from_imm64 ty x) + (provide (= result (extract 5 0 (bvand x (bvsub (int2bv 64 ty) #x0000000000000001))))) + (require (bvult (bvand x (bvsub (int2bv 64 ty) #x0000000000000001)) #x0000000000000040))) + +(decl pure partial imm_shift_from_imm64 (Type Imm64) ImmShift) +(extern constructor imm_shift_from_imm64 imm_shift_from_imm64) + +(decl imm_shift_from_u8 (u8) ImmShift) +(extern constructor imm_shift_from_u8 imm_shift_from_u8) + +(spec (imm12_from_u64 imm12) + (provide (= result (zero_ext 64 imm12))) + (require + ; REVIEW(mbm): correct formulation of imm12? + (or + (= imm12 (bvand imm12 #x000fff)) + (= imm12 (bvand imm12 #xfff000)) + ) + ) +) +(decl imm12_from_u64 (Imm12) u64) +(extern extractor imm12_from_u64 imm12_from_u64) + +(decl u8_into_uimm5 (u8) UImm5) +(extern constructor u8_into_uimm5 u8_into_uimm5) + +(spec (u8_into_imm12 arg) + (provide (= result (zero_ext 24 arg)))) +(decl u8_into_imm12 (u8) Imm12) +(extern constructor u8_into_imm12 u8_into_imm12) + +(spec (u64_into_imm_logic ty a) + (provide (= result a)) + (require (or (= ty 32) (= ty 64)))) +(decl u64_into_imm_logic (Type u64) ImmLogic) +(extern constructor u64_into_imm_logic u64_into_imm_logic) + +(decl branch_target (MachLabel) BranchTarget) +(extern constructor branch_target branch_target) +(convert MachLabel BranchTarget branch_target) + +(decl targets_jt_space (BoxVecMachLabel) CodeOffset) +(extern constructor targets_jt_space targets_jt_space) + +;; Calculate the minimum floating-point bound for a conversion to floating +;; point from an integer type. +;; Accepts whether the output is signed, the size of the input +;; floating point type in bits, and the size of the output integer type +;; in bits. +(decl min_fp_value (bool u8 u8) Reg) +(extern constructor min_fp_value min_fp_value) + +;; Calculate the maximum floating-point bound for a conversion to floating +;; point from an integer type. +;; Accepts whether the output is signed, the size of the input +;; floating point type in bits, and the size of the output integer type +;; in bits. +(decl max_fp_value (bool u8 u8) Reg) +(extern constructor max_fp_value max_fp_value) + +;; Constructs an FPUOpRI.Ushr* given the size in bits of the value (or lane) +;; and the amount to shift by. +(decl fpu_op_ri_ushr (u8 u8) FPUOpRI) +(extern constructor fpu_op_ri_ushr fpu_op_ri_ushr) + +;; Constructs an FPUOpRIMod.Sli* given the size in bits of the value (or lane) +;; and the amount to shift by. +(decl fpu_op_ri_sli (u8 u8) FPUOpRIMod) +(extern constructor fpu_op_ri_sli fpu_op_ri_sli) + +(decl pure partial lshr_from_u64 (Type u64) ShiftOpAndAmt) +(extern constructor lshr_from_u64 lshr_from_u64) + +(spec (lshl_from_imm64 ty a) + (provide (= result (concat #x0e (extract 7 0 a)))) + (require (= (extract 63 8 a) #b00000000000000000000000000000000000000000000000000000000))) +(decl pure partial lshl_from_imm64 (Type Imm64) ShiftOpAndAmt) +(extern constructor lshl_from_imm64 lshl_from_imm64) + +(decl pure partial lshl_from_u64 (Type u64) ShiftOpAndAmt) +(extern constructor lshl_from_u64 lshl_from_u64) + +(decl pure partial ashr_from_u64 (Type u64) ShiftOpAndAmt) +(extern constructor ashr_from_u64 ashr_from_u64) + +(decl integral_ty (Type) Type) +(extern extractor integral_ty integral_ty) + +(decl valid_atomic_transaction (Type) Type) +(extern extractor valid_atomic_transaction valid_atomic_transaction) + +(decl pure partial is_zero_simm9 (SImm9) Unit) +(extern constructor is_zero_simm9 is_zero_simm9) + +(decl pure partial is_zero_uimm12 (UImm12Scaled) Unit) +(extern constructor is_zero_uimm12 is_zero_uimm12) + +;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`. +; REVIEW(mbm): is imm12_from_value spec correct? +; NOTE(mbm): compare with https://github.com/avanhatt/wasmtime/blob/94ccb9d4d55a479893cb04bc796ec620ed24cee2/cranelift/codegen/src/isa/aarch64/inst.isle#L1867-L1874 +(spec (imm12_from_value imm12) + (provide + ; REVIEW(mbm): zero_ext vs conv_to? + (= result (conv_to (widthof result) (zero_ext 64 imm12))) + (= imm12 (conv_to (widthof imm12) (zero_ext 64 result))) + ) + (require + ; REVIEW(mbm): correct formulation of imm12? + (or + (= imm12 (bvand imm12 #x000fff)) + (= imm12 (bvand imm12 #xfff000)) + ) + ) +) +(decl imm12_from_value (Imm12) Value) +(extractor + (imm12_from_value n) + (iconst (u64_from_imm64 (imm12_from_u64 n)))) +;; Conceptually the same as `imm12_from_value`, but tries negating the constant +;; value (first sign-extending to handle narrow widths). +(spec (imm12_from_negated_value arg) + (provide + (= (bvneg (sign_ext 64 arg)) (zero_ext 64 result)) + ) + (require + ; REVIEW(mbm): correct formulation of imm12? + (or + (= result (bvand result #x000fff)) + (= result (bvand result #xfff000)) + ) + ) +) + +(instantiate imm12_from_negated_value + ((args (bv 8)) (ret (bv 24)) (canon (bv 8))) + ((args (bv 16)) (ret (bv 24)) (canon (bv 16))) + ((args (bv 32)) (ret (bv 24)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 24)) (canon (bv 64))) +) +(decl pure partial imm12_from_negated_value (Value) Imm12) +(rule imm12_from_negated_value + (imm12_from_negated_value (has_type ty (iconst n))) + (if-let (imm12_from_u64 imm) (i64_as_u64 (i64_neg (i64_sextend_imm64 ty n)))) + imm) + +;; Helper type to represent a value and an extend operation fused together. +(model ExtendedValue (type (bv 67))) +(type ExtendedValue extern (enum)) +;; Only including the i8 to i32 opcodes, based on the impl of extended_value_from_value +(spec (extended_value_from_value x) + (provide + (switch (extract 66 64 x) + ((ExtendOp.UXTB) (= (extract 63 0 x) (zero_ext 64 (extract 7 0 (zero_ext 64 result))))) + ((ExtendOp.UXTH) (= (extract 63 0 x) (zero_ext 64 (extract 15 0 (zero_ext 64 result))))) + ((ExtendOp.UXTW) (= (extract 63 0 x) (zero_ext 64 (extract 31 0 (zero_ext 64 result))))) + ((ExtendOp.SXTB) (= (extract 63 0 x) (sign_ext 64 (extract 7 0 (zero_ext 64 result))))) + ((ExtendOp.SXTH) (= (extract 63 0 x) (sign_ext 64 (extract 15 0 (zero_ext 64 result))))) + ((ExtendOp.SXTW) (= (extract 63 0 x) (sign_ext 64 (extract 31 0 (zero_ext 64 result))))))) + (require + (bvult (extract 66 64 x) #b110) + (not (= (extract 66 64 x) #b011)) + (= result (conv_to (widthof result) x)) + (or (= 8 (widthof result)) (= 16 (widthof result)) (= 32 (widthof result))))) +(decl extended_value_from_value (ExtendedValue) Value) +(extern extractor extended_value_from_value extended_value_from_value) + +;; Constructors used to poke at the fields of an `ExtendedValue`. +(decl put_extended_in_reg (ExtendedValue) Reg) +(extern constructor put_extended_in_reg put_extended_in_reg) +(decl get_extended_op (ExtendedValue) ExtendOp) +(extern constructor get_extended_op get_extended_op) + +(decl nzcv (bool bool bool bool) NZCV) +(extern constructor nzcv nzcv) + +(decl cond_br_zero (Reg OperandSize) CondBrKind) +(extern constructor cond_br_zero cond_br_zero) + +(decl cond_br_not_zero (Reg OperandSize) CondBrKind) +(extern constructor cond_br_not_zero cond_br_not_zero) + +(decl cond_br_cond (Cond) CondBrKind) +(extern constructor cond_br_cond cond_br_cond) + +;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper for creating the zero register. +(spec (zero_reg) (provide (= result #x0000000000000000))) +(decl zero_reg () Reg) +(extern constructor zero_reg zero_reg) + +(decl fp_reg () Reg) +(extern constructor fp_reg fp_reg) + +(decl stack_reg () Reg) +(extern constructor stack_reg stack_reg) + +(decl writable_link_reg () WritableReg) +(extern constructor writable_link_reg writable_link_reg) + +(decl writable_zero_reg () WritableReg) +(extern constructor writable_zero_reg writable_zero_reg) + +(decl value_regs_zero () ValueRegs) +(rule (value_regs_zero) + (value_regs + (imm $I64 (ImmExtend.Zero) 0) + (imm $I64 (ImmExtend.Zero) 0))) + + +;; Helper for emitting `MInst.Mov` instructions. +(decl mov (Reg Type) Reg) +(rule (mov src ty) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Mov (operand_size ty) dst src)))) + dst)) + +;; Helper for emitting `MInst.MovZ` instructions. +(decl movz (MoveWideConst OperandSize) Reg) +(rule (movz imm size) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovWide (MoveWideOp.MovZ) dst imm size)))) + dst)) + +;; Helper for emitting `MInst.MovN` instructions. +(decl movn (MoveWideConst OperandSize) Reg) +(rule (movn imm size) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovWide (MoveWideOp.MovN) dst imm size)))) + dst)) + +;; Helper for emitting `MInst.AluRRImmLogic` instructions. +(decl alu_rr_imm_logic (ALUOp Type Reg ImmLogic) Reg) +(rule (alu_rr_imm_logic op ty src imm) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRImmLogic op (operand_size ty) dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRRImmShift` instructions. +(spec (alu_rr_imm_shift op t a b) + (provide + (= result (switch op + ((ALUOp.Lsr) + (if (<= t 32) + (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) + (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b))))) + ((ALUOp.Asr) + (if (<= t 32) + (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) + (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b))))) + ((ALUOp.Lsl) + (if (<= t 32) + (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) + (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b)))))))) + (require + (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) + (or (= t 8) (= t 16) (= t 32) (= t 64)))) +(decl alu_rr_imm_shift (ALUOp Type Reg ImmShift) Reg) +(rule (alu_rr_imm_shift op ty src imm) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRImmShift op (operand_size ty) dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRRR` instructions. +(spec (alu_rrr op t a b) + (provide + (= result (switch op + ((ALUOp.Lsr) + (if (<= t 32) + (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ((ALUOp.Asr) + (if (<= t 32) + (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ((ALUOp.Lsl) + (if (<= t 32) + (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) + (require + (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) + (or (= t 8) (= t 16) (= t 32) (= t 64)))) +(decl alu_rrr (ALUOp Type Reg Reg) Reg) +(rule (alu_rrr op ty src1 src2) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRR op (operand_size ty) dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.VecRRR` instructions. +(decl vec_rrr (VecALUOp Reg Reg VectorSize) Reg) +(rule (vec_rrr op src1 src2 size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRR op dst src1 src2 size)))) + dst)) + +;; Helper for emitting `MInst.FpuRR` instructions. +(decl fpu_rr (FPUOp1 Reg ScalarSize) Reg) +(rule (fpu_rr op src size) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRR op size dst src)))) + dst)) + +;; Helper for emitting `MInst.VecRRRMod` instructions which use three registers, +;; one of which is both source and output. +(decl vec_rrr_mod (VecALUModOp Reg Reg Reg VectorSize) Reg) +(rule (vec_rrr_mod op src1 src2 src3 size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_1 Unit (emit (MInst.VecRRRMod op dst src1 src2 src3 size)))) + dst)) + +;; Helper for emitting `MInst.VecFmlaElem` instructions which use three registers, +;; one of which is both source and output. +(decl vec_fmla_elem (VecALUModOp Reg Reg Reg VectorSize u8) Reg) +(rule (vec_fmla_elem op src1 src2 src3 size idx) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_1 Unit (emit (MInst.VecFmlaElem op dst src1 src2 src3 size idx)))) + dst)) + +(decl fpu_rri (FPUOpRI Reg) Reg) +(rule (fpu_rri op src) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRRI op dst src)))) + dst)) + +(decl fpu_rri_mod (FPUOpRIMod Reg Reg) Reg) +(rule (fpu_rri_mod op dst_src src) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRRIMod op dst dst_src src)))) + dst)) + +;; Helper for emitting `MInst.FpuRRR` instructions. +(decl fpu_rrr (FPUOp2 Reg Reg ScalarSize) Reg) +(rule (fpu_rrr op src1 src2 size) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRRR op size dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.FpuRRRR` instructions. +(decl fpu_rrrr (FPUOp3 ScalarSize Reg Reg Reg) Reg) +(rule (fpu_rrrr size op src1 src2 src3) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRRRR size op dst src1 src2 src3)))) + dst)) + +;; Helper for emitting `MInst.FpuCmp` instructions. +(decl fpu_cmp (ScalarSize Reg Reg) ProducesFlags) +(rule (fpu_cmp size rn rm) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.FpuCmp size rn rm))) + +;; Helper for emitting `MInst.VecLanes` instructions. +(decl vec_lanes (VecLanesOp Reg VectorSize) Reg) +(rule (vec_lanes op src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecLanes op dst src size)))) + dst)) + +;; Helper for emitting `MInst.VecShiftImm` instructions. +(decl vec_shift_imm (VecShiftImmOp u8 Reg VectorSize) Reg) +(rule (vec_shift_imm op imm src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecShiftImm op dst src size imm)))) + dst)) + +;; Helper for emitting `MInst.VecDup` instructions. +(decl vec_dup (Reg VectorSize) Reg) +(rule (vec_dup src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecDup dst src size)))) + dst)) + +;; Helper for emitting `MInst.VecDupFromFpu` instructions. +(decl vec_dup_from_fpu (Reg VectorSize u8) Reg) +(rule (vec_dup_from_fpu src size lane) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecDupFromFpu dst src size lane)))) + dst)) + +;; Helper for emitting `MInst.VecDupImm` instructions. +(decl vec_dup_imm (ASIMDMovModImm bool VectorSize) Reg) +(rule (vec_dup_imm imm invert size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecDupImm dst imm invert size)))) + dst)) + +;; Helper for emitting `MInst.AluRRImm12` instructions. +(decl alu_rr_imm12 (ALUOp Type Reg Imm12) Reg) +(rule (alu_rr_imm12 op ty src imm) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRImm12 op (operand_size ty) dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRRRShift` instructions. +(decl alu_rrr_shift (ALUOp Type Reg Reg ShiftOpAndAmt) Reg) +(rule (alu_rrr_shift op ty src1 src2 shift) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRRShift op (operand_size ty) dst src1 src2 shift)))) + dst)) + +;; Helper for emitting `cmp` instructions, setting flags, with a right-shifted +;; second operand register. +(decl cmp_rr_shift (OperandSize Reg Reg u64) ProducesFlags) +(rule (cmp_rr_shift size src1 src2 shift_amount) + (if-let shift (lshr_from_u64 $I64 shift_amount)) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRRShift (ALUOp.SubS) size (writable_zero_reg) + src1 src2 shift))) + +;; Helper for emitting `cmp` instructions, setting flags, with an arithmetic right-shifted +;; second operand register. +(decl cmp_rr_shift_asr (OperandSize Reg Reg u64) ProducesFlags) +(rule (cmp_rr_shift_asr size src1 src2 shift_amount) + (if-let shift (ashr_from_u64 $I64 shift_amount)) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRRShift (ALUOp.SubS) size (writable_zero_reg) + src1 src2 shift))) + +;; Helper for emitting `MInst.AluRRRExtend` instructions. +(decl alu_rrr_extend (ALUOp Type Reg Reg ExtendOp) Reg) +(rule (alu_rrr_extend op ty src1 src2 extend) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRRExtend op (operand_size ty) dst src1 src2 extend)))) + dst)) + +;; Same as `alu_rrr_extend`, but takes an `ExtendedValue` packed "pair" instead +;; of a `Reg` and an `ExtendOp`. +(decl alu_rr_extend_reg (ALUOp Type Reg ExtendedValue) Reg) +(rule (alu_rr_extend_reg op ty src1 extended_reg) + (let ((src2 Reg (put_extended_in_reg extended_reg)) + (extend ExtendOp (get_extended_op extended_reg))) + (alu_rrr_extend op ty src1 src2 extend))) + +;; Helper for emitting `MInst.AluRRRR` instructions. +(decl alu_rrrr (ALUOp3 Type Reg Reg Reg) Reg) +(rule (alu_rrrr op ty src1 src2 src3) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AluRRRR op (operand_size ty) dst src1 src2 src3)))) + dst)) + +;; Helper for emitting paired `MInst.AluRRR` instructions +(decl alu_rrr_with_flags_paired (Type Reg Reg ALUOp) ProducesFlags) +(rule (alu_rrr_with_flags_paired ty src1 src2 alu_op) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRRR alu_op (operand_size ty) dst src1 src2) + dst))) + +;; Should only be used for AdcS and SbcS +(decl alu_rrr_with_flags_chained (Type Reg Reg ALUOp) ConsumesAndProducesFlags) +(rule (alu_rrr_with_flags_chained ty src1 src2 alu_op) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesAndProducesFlags.ReturnsReg + (MInst.AluRRR alu_op (operand_size ty) dst src1 src2) + dst))) + +;; Helper for emitting `MInst.BitRR` instructions. +(decl bit_rr (BitOp Type Reg) Reg) +(rule (bit_rr op ty src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.BitRR op (operand_size ty) dst src)))) + dst)) + +;; Helper for emitting `adds` instructions. +(decl add_with_flags_paired (Type Reg Reg) ProducesFlags) +(rule (add_with_flags_paired ty src1 src2) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRRR (ALUOp.AddS) (operand_size ty) dst src1 src2) + dst))) + +;; Helper for emitting `adc` instructions. +(decl adc_paired (Type Reg Reg) ConsumesFlags) +(rule (adc_paired ty src1 src2) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer + (MInst.AluRRR (ALUOp.Adc) (operand_size ty) dst src1 src2) + dst))) + +;; Helper for emitting `subs` instructions. +(decl sub_with_flags_paired (Type Reg Reg) ProducesFlags) +(rule (sub_with_flags_paired ty src1 src2) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRRR (ALUOp.SubS) (operand_size ty) dst src1 src2) + dst))) + +;; Helper for materializing a boolean value into a register from +;; flags. +(decl materialize_bool_result (Cond) ConsumesFlags) +(rule (materialize_bool_result cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.CSet dst cond) + dst))) + +(decl cmn_imm (OperandSize Reg Imm12) ProducesFlags) +(rule (cmn_imm size src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRImm12 (ALUOp.AddS) size (writable_zero_reg) + src1 src2))) + +(spec (cmp ty x y) + (provide (= result (subs ty x y))) + (require + (or (= ty 32) (= ty 64)))) +(decl cmp (OperandSize Reg Reg) ProducesFlags) +(rule (cmp size src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRR (ALUOp.SubS) size (writable_zero_reg) + src1 src2))) + +(spec (cmp_imm ty x y) + (provide (= result (subs ty x (zero_ext 64 y)))) + (require (or (= ty 32) (= ty 64)))) +(decl cmp_imm (OperandSize Reg Imm12) ProducesFlags) +(rule (cmp_imm size src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRImm12 (ALUOp.SubS) size (writable_zero_reg) + src1 src2))) + +(decl cmp64_imm (Reg Imm12) ProducesFlags) +(rule (cmp64_imm src1 src2) + (cmp_imm (OperandSize.Size64) src1 src2)) + +(spec (cmp_extend ty x y extend) + (provide + (= result + (subs ty x + (switch extend + ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) + ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) + ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) + ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) + ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) + ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) + ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) + ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))) + (require (or (= ty 32) (= ty 64)))) +(decl cmp_extend (OperandSize Reg Reg ExtendOp) ProducesFlags) +(rule (cmp_extend size src1 src2 extend) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRRExtend (ALUOp.SubS) size (writable_zero_reg) + src1 src2 extend))) + +;; Helper for emitting `sbc` instructions. +(decl sbc_paired (Type Reg Reg) ConsumesFlags) +(rule (sbc_paired ty src1 src2) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer + (MInst.AluRRR (ALUOp.Sbc) (operand_size ty) dst src1 src2) + dst))) + +;; Helper for emitting `MInst.VecMisc` instructions. +(decl vec_misc (VecMisc2 Reg VectorSize) Reg) +(rule (vec_misc op src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecMisc op dst src size)))) + dst)) + +;; Helper for emitting `MInst.VecTbl` instructions. +(decl vec_tbl (Reg Reg) Reg) +(rule (vec_tbl rn rm) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecTbl dst rn rm)))) + dst)) + +(decl vec_tbl_ext (Reg Reg Reg) Reg) +(rule (vec_tbl_ext ri rn rm) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecTblExt dst ri rn rm)))) + dst)) + +;; Helper for emitting `MInst.VecTbl2` instructions. +(decl vec_tbl2 (Reg Reg Reg Type) Reg) +(rule (vec_tbl2 rn rn2 rm ty) + (let ( + (dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecTbl2 dst rn rn2 rm))) + ) + dst)) + +;; Helper for emitting `MInst.VecTbl2Ext` instructions. +(decl vec_tbl2_ext (Reg Reg Reg Reg Type) Reg) +(rule (vec_tbl2_ext ri rn rn2 rm ty) + (let ( + (dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecTbl2Ext dst ri rn rn2 rm))) + ) + dst)) + +;; Helper for emitting `MInst.VecRRRLong` instructions. +(decl vec_rrr_long (VecRRRLongOp Reg Reg bool) Reg) +(rule (vec_rrr_long op src1 src2 high_half) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRRLong op dst src1 src2 high_half)))) + dst)) + +;; Helper for emitting `MInst.VecRRPairLong` instructions. +(decl vec_rr_pair_long (VecRRPairLongOp Reg) Reg) +(rule (vec_rr_pair_long op src) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRPairLong op dst src)))) + dst)) + +;; Helper for emitting `MInst.VecRRRLongMod` instructions. +(decl vec_rrrr_long (VecRRRLongModOp Reg Reg Reg bool) Reg) +(rule (vec_rrrr_long op src1 src2 src3 high_half) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRRLongMod op dst src1 src2 src3 high_half)))) + dst)) + +;; Helper for emitting `MInst.VecRRNarrow` instructions. +(decl vec_rr_narrow_low (VecRRNarrowOp Reg ScalarSize) Reg) +(rule (vec_rr_narrow_low op src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRNarrowLow op dst src size)))) + dst)) + +;; Helper for emitting `MInst.VecRRNarrow` instructions which update the +;; high half of the destination register. +(decl vec_rr_narrow_high (VecRRNarrowOp Reg Reg ScalarSize) Reg) +(rule (vec_rr_narrow_high op mod src size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRNarrowHigh op dst mod src size)))) + dst)) + +;; Helper for emitting `MInst.VecRRLong` instructions. +(decl vec_rr_long (VecRRLongOp Reg bool) Reg) +(rule (vec_rr_long op src high_half) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecRRLong op dst src high_half)))) + dst)) + +;; Helper for emitting `MInst.FpuCSel16` / `MInst.FpuCSel32` / `MInst.FpuCSel64` +;; instructions. +(decl fpu_csel (Type Cond Reg Reg) ConsumesFlags) +(rule (fpu_csel $F16 cond if_true if_false) + (fpu_csel $F32 cond if_true if_false)) + +(rule 1 (fpu_csel $F16 cond if_true if_false) + (if-let true (use_fp16)) + (let ((dst WritableReg (temp_writable_reg $F16))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.FpuCSel16 dst if_true if_false cond) + dst))) + +(rule (fpu_csel $F32 cond if_true if_false) + (let ((dst WritableReg (temp_writable_reg $F32))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.FpuCSel32 dst if_true if_false cond) + dst))) + +(rule (fpu_csel $F64 cond if_true if_false) + (let ((dst WritableReg (temp_writable_reg $F64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.FpuCSel64 dst if_true if_false cond) + dst))) + +;; Helper for emitting `MInst.VecCSel` instructions. +(decl vec_csel (Cond Reg Reg) ConsumesFlags) +(rule (vec_csel cond if_true if_false) + (let ((dst WritableReg (temp_writable_reg $I8X16))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.VecCSel dst if_true if_false cond) + dst))) + +;; Helper for emitting `MInst.FpuRound` instructions. +(decl fpu_round (FpuRoundMode Reg) Reg) +(rule (fpu_round op rn) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuRound op dst rn)))) + dst)) + +;; Helper for emitting `MInst.FpuMove64` and `MInst.FpuMove128` instructions. +(decl fpu_move (Type Reg) Reg) +(rule (fpu_move _ src) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.FpuMove128 dst src)))) + dst)) +(rule 1 (fpu_move (fits_in_64 _) src) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuMove64 dst src)))) + dst)) + +;; Helper for emitting `MInst.MovToFpu` instructions. +(spec (mov_to_fpu x s) + (provide (= result (zero_ext 64 (conv_to s x))))) +(decl mov_to_fpu (Reg ScalarSize) Reg) +(rule (mov_to_fpu x size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.MovToFpu dst x size)))) + dst)) +(rule 1 (mov_to_fpu x (ScalarSize.Size16)) + (if-let false (use_fp16)) + (mov_to_fpu x (ScalarSize.Size32))) + +;; Helper for emitting `MInst.FpuMoveFPImm` instructions. +(decl fpu_move_fp_imm (ASIMDFPModImm ScalarSize) Reg) +(rule (fpu_move_fp_imm imm size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.FpuMoveFPImm dst imm size)))) + dst)) + +;; Helper for emitting `MInst.MovToVec` instructions. +(decl mov_to_vec (Reg Reg u8 VectorSize) Reg) +(rule (mov_to_vec src1 src2 lane size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.MovToVec dst src1 src2 lane size)))) + dst)) + +;; Helper for emitting `MInst.VecMovElement` instructions. +(decl mov_vec_elem (Reg Reg u8 u8 VectorSize) Reg) +(rule (mov_vec_elem src1 src2 dst_idx src_idx size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecMovElement dst src1 src2 dst_idx src_idx size)))) + dst)) + +;; Helper for emitting `MInst.MovFromVec` instructions. +(spec (mov_from_vec x i s) + (provide + (= result + (switch s + (8 + (switch i + (#x00 (zero_ext 64 (extract 7 0 x))) + (#x01 (zero_ext 64 (extract 15 8 x))) + (#x02 (zero_ext 64 (extract 23 16 x))) + (#x03 (zero_ext 64 (extract 31 24 x))) + (#x04 (zero_ext 64 (extract 39 32 x))) + (#x05 (zero_ext 64 (extract 47 40 x))) + (#x06 (zero_ext 64 (extract 55 48 x))) + (#x07 (zero_ext 64 (extract 63 56 x))))) + (16 + (switch i + (#x00 (zero_ext 64 (extract 15 0 x))) + (#x01 (zero_ext 64 (extract 31 16 x))) + (#x03 (zero_ext 64 (extract 47 32 x))) + (#x04 (zero_ext 64 (extract 63 48 x))))) + (32 + (switch i + (#x00 (zero_ext 64 (extract 31 0 x))) + (#x01 (zero_ext 64 (extract 63 32 x))))))))) +(decl mov_from_vec (Reg u8 ScalarSize) Reg) +(rule (mov_from_vec rn idx size) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovFromVec dst rn idx size)))) + dst)) + +;; Helper for emitting `MInst.MovFromVecSigned` instructions. +(decl mov_from_vec_signed (Reg u8 VectorSize OperandSize) Reg) +(rule (mov_from_vec_signed rn idx size scalar_size) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovFromVecSigned dst rn idx size scalar_size)))) + dst)) + +(decl fpu_move_from_vec (Reg u8 VectorSize) Reg) +(rule (fpu_move_from_vec rn idx size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.FpuMoveFromVec dst rn idx size)))) + dst)) + +;; Helper for emitting `MInst.Extend` instructions. +(spec (extend a b c d) + (provide + (if b + (= result (sign_ext (bv2int d) (conv_to (bv2int c) a))) + (= result (zero_ext (bv2int d) (conv_to (bv2int c) a)))))) +(decl extend (Reg bool u8 u8) Reg) +(rule (extend rn signed from_bits to_bits) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Extend dst rn signed from_bits to_bits)))) + dst)) + +;; Helper for emitting `MInst.FpuExtend` instructions. +(decl fpu_extend (Reg ScalarSize) Reg) +(rule (fpu_extend src size) + (let ((dst WritableReg (temp_writable_reg $F32X4)) + (_ Unit (emit (MInst.FpuExtend dst src size)))) + dst)) + +;; Helper for emitting `MInst.VecExtend` instructions. +(decl vec_extend (VecExtendOp Reg bool ScalarSize) Reg) +(rule (vec_extend op src high_half size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecExtend op dst src high_half size)))) + dst)) + +;; Helper for emitting `MInst.VecExtract` instructions. +(decl vec_extract (Reg Reg u8) Reg) +(rule (vec_extract src1 src2 idx) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecExtract dst src1 src2 idx)))) + dst)) + +;; Helper for emitting `MInst.LoadAcquire` instructions. +(decl load_acquire (Type MemFlags Reg) Reg) +(rule (load_acquire ty flags addr) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadAcquire ty dst addr flags)))) + dst)) + +;; Helper for emitting `MInst.StoreRelease` instructions. +(decl store_release (Type MemFlags Reg Reg) SideEffectNoResult) +(rule (store_release ty flags src addr) + (SideEffectNoResult.Inst (MInst.StoreRelease ty src addr flags))) + +;; Helper for generating a `tst` instruction. +;; +;; Produces a `ProducesFlags` rather than a register or emitted instruction +;; which must be paired with `with_flags*` helpers. +(decl tst_imm (Type Reg ImmLogic) ProducesFlags) +(rule (tst_imm ty reg imm) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRRImmLogic (ALUOp.AndS) + (operand_size ty) + (writable_zero_reg) + reg + imm))) + +;; Helper for generating a `CSel` instruction. +;; +;; Note that this doesn't actually emit anything, instead it produces a +;; `ConsumesFlags` instruction which must be consumed with `with_flags*` +;; helpers. +(decl csel (Cond Reg Reg) ConsumesFlags) +(rule (csel cond if_true if_false) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.CSel dst cond if_true if_false) + dst))) + +;; Helper for constructing `cset` instructions. +(decl cset (Cond) ConsumesFlags) +(rule (cset cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg (MInst.CSet dst cond) dst))) + +;; Helper for constructing `cset` instructions, when the flags producer will +;; also return a value. +(decl cset_paired (Cond) ConsumesFlags) +(rule (cset_paired cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer (MInst.CSet dst cond) dst))) + +;; Helper for constructing `csetm` instructions. +(decl csetm (Cond) ConsumesFlags) +(rule (csetm cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg (MInst.CSetm dst cond) dst))) + +;; Helper for generating a `CSNeg` instruction. +;; +;; Note that this doesn't actually emit anything, instead it produces a +;; `ConsumesFlags` instruction which must be consumed with `with_flags*` +;; helpers. +(decl csneg (Cond Reg Reg) ConsumesFlags) +(rule (csneg cond if_true if_false) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.CSNeg dst cond if_true if_false) + dst))) + +;; Helper for generating `MInst.CCmp` instructions. +;; Creates a new `ProducesFlags` from the supplied `ProducesFlags` followed +;; immediately by the `MInst.CCmp` instruction. +(decl ccmp (OperandSize Reg Reg NZCV Cond ProducesFlags) ProducesFlags) +(rule (ccmp size rn rm nzcv cond inst_input) + (produces_flags_concat inst_input (ProducesFlags.ProducesFlagsSideEffect (MInst.CCmp size rn rm nzcv cond)))) + +;; Helper for generating `MInst.CCmpImm` instructions. +(decl ccmp_imm (OperandSize Reg UImm5 NZCV Cond) ConsumesFlags) +(rule 1 (ccmp_imm size rn imm nzcv cond) + (let ((dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + (MInst.CCmpImm size rn imm nzcv cond) + (MInst.CSet dst cond) + (value_reg dst)))) + +;; Helpers for generating `add` instructions. +(spec (add ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b))))) +(decl add (Type Reg Reg) Reg) +(rule (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) + +(spec (add_imm ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) (zero_ext 32 b))) + (bvadd a (zero_ext 64 b))))) + (require + (or + (= b (bvand b #x000fff)) + (= b (bvand b #xfff000))))) +(decl add_imm (Type Reg Imm12) Reg) +(rule (add_imm ty x y) (alu_rr_imm12 (ALUOp.Add) ty x y)) + +(spec (add_extend ty x y) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 x) + (switch (extract 66 64 y) + ((ExtendOp.UXTB) (zero_ext 32 (extract 7 0 y))) + ((ExtendOp.UXTH) (zero_ext 32 (extract 15 0 y))) + ((ExtendOp.UXTW) (zero_ext 32 (extract 31 0 y))) + ((ExtendOp.UXTX) (zero_ext 32 (extract 31 0 y))) + ((ExtendOp.SXTB) (sign_ext 32 (extract 7 0 y))) + ((ExtendOp.SXTH) (sign_ext 32 (extract 15 0 y))) + ((ExtendOp.SXTW) (sign_ext 32 (extract 31 0 y))) + ((ExtendOp.SXTX) (sign_ext 32 (extract 31 0 y)))))) + (bvadd x + (switch (extract 66 64 y) + ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) + ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) + ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) + ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) + ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) + ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) + ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) + ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))))) +(decl add_extend (Type Reg ExtendedValue) Reg) +(rule (add_extend ty x y) (alu_rr_extend_reg (ALUOp.Add) ty x y)) + +(decl add_extend_op (Type Reg Reg ExtendOp) Reg) +(rule (add_extend_op ty x y extend) (alu_rrr_extend (ALUOp.Add) ty x y extend)) + +(spec (add_shift ty a b shift) + (provide + (= result (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) + (switch (extract 15 8 shift) + ((ALUOp.Lsl) (bvshl (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Lsr) (bvlshr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Asr) (bvashr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))) + (bvadd a + (switch (extract 15 8 shift) + ((ALUOp.Lsl) (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Lsr) (bvlshr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Asr) (bvashr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))))))) +(decl add_shift (Type Reg Reg ShiftOpAndAmt) Reg) +(rule (add_shift ty x y z) (alu_rrr_shift (ALUOp.Add) ty x y z)) + +(decl add_vec (Reg Reg VectorSize) Reg) +(rule (add_vec x y size) (vec_rrr (VecALUOp.Add) x y size)) + +;; Helpers for generating `sub` instructions. +(spec (sub ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvsub (extract 31 0 a) (extract 31 0 b))) + (bvsub a b))))) +(decl sub (Type Reg Reg) Reg) +(rule (sub ty x y) (alu_rrr (ALUOp.Sub) ty x y)) + +(spec (sub_imm ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvsub (extract 31 0 a) (zero_ext 32 b))) + (bvsub a (zero_ext 64 b))))) + (require + (or + (= b (bvand b #x000fff)) + (= b (bvand b #xfff000))))) +(decl sub_imm (Type Reg Imm12) Reg) +(rule (sub_imm ty x y) (alu_rr_imm12 (ALUOp.Sub) ty x y)) + +(spec (sub_extend ty x y) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvsub (extract 31 0 x) + (switch (extract 66 64 y) + ((ExtendOp.UXTB) (zero_ext 32 (extract 7 0 y))) + ((ExtendOp.UXTH) (zero_ext 32 (extract 15 0 y))) + ((ExtendOp.UXTW) (zero_ext 32 (extract 31 0 y))) + ((ExtendOp.UXTX) (zero_ext 32 (extract 31 0 y))) + ((ExtendOp.SXTB) (sign_ext 32 (extract 7 0 y))) + ((ExtendOp.SXTH) (sign_ext 32 (extract 15 0 y))) + ((ExtendOp.SXTW) (sign_ext 32 (extract 31 0 y))) + ((ExtendOp.SXTX) (sign_ext 32 (extract 31 0 y)))))) + (bvsub x + (switch (extract 66 64 y) + ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) + ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) + ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) + ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) + ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) + ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) + ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) + ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))))) +(decl sub_extend (Type Reg ExtendedValue) Reg) +(rule (sub_extend ty x y) (alu_rr_extend_reg (ALUOp.Sub) ty x y)) + +(spec (sub_shift ty a b shift) + (provide + (= result (if (<= ty 32) + (conv_to 64 (bvsub (extract 31 0 a) (switch (extract 15 8 shift) + ((ALUOp.Lsl) (bvshl (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Lsr) (bvlshr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Asr) (bvashr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))) + (bvsub a (switch (extract 15 8 shift) + ((ALUOp.Lsl) (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Lsr) (bvlshr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) + ((ALUOp.Asr) (bvashr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))))))) +(decl sub_shift (Type Reg Reg ShiftOpAndAmt) Reg) +(rule (sub_shift ty x y z) (alu_rrr_shift (ALUOp.Sub) ty x y z)) + +(decl sub_vec (Reg Reg VectorSize) Reg) +(rule (sub_vec x y size) (vec_rrr (VecALUOp.Sub) x y size)) + +(decl sub_i128 (ValueRegs ValueRegs) ValueRegs) +(rule (sub_i128 x y) + (let + ;; Get the high/low registers for `x`. + ((x_regs ValueRegs x) + (x_lo Reg (value_regs_get x_regs 0)) + (x_hi Reg (value_regs_get x_regs 1)) + + ;; Get the high/low registers for `y`. + (y_regs ValueRegs y) + (y_lo Reg (value_regs_get y_regs 0)) + (y_hi Reg (value_regs_get y_regs 1))) + ;; the actual subtraction is `subs` followed by `sbc` which comprises + ;; the low/high bits of the result + (with_flags + (sub_with_flags_paired $I64 x_lo y_lo) + (sbc_paired $I64 x_hi y_hi)))) + +;; Helpers for generating `madd` instructions. +(spec (madd ty a b c) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 c) (bvmul (extract 31 0 a) (extract 31 0 b)))) + (bvadd c (bvmul a b)))))) +(decl madd (Type Reg Reg Reg) Reg) +(rule (madd ty x y z) (alu_rrrr (ALUOp3.MAdd) ty x y z)) + +;; Helpers for generating `msub` instructions. +(spec (msub ty a b c) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvsub (extract 31 0 c) (bvmul (extract 31 0 a) (extract 31 0 b)))) + (bvsub c (bvmul a b)))))) +(decl msub (Type Reg Reg Reg) Reg) +(rule (msub ty x y z) (alu_rrrr (ALUOp3.MSub) ty x y z)) + +;; Helpers for generating `umaddl` instructions +(decl umaddl (Reg Reg Reg) Reg) +(rule (umaddl x y z) (alu_rrrr (ALUOp3.UMAddL) $I32 x y z)) + +;; Helpers for generating `smaddl` instructions +(decl smaddl (Reg Reg Reg) Reg) +(rule (smaddl x y z) (alu_rrrr (ALUOp3.SMAddL) $I32 x y z)) + +;; Helper for generating `uqadd` instructions. +(decl uqadd (Reg Reg VectorSize) Reg) +(rule (uqadd x y size) (vec_rrr (VecALUOp.Uqadd) x y size)) + +;; Helper for generating `sqadd` instructions. +(decl sqadd (Reg Reg VectorSize) Reg) +(rule (sqadd x y size) (vec_rrr (VecALUOp.Sqadd) x y size)) + +;; Helper for generating `uqsub` instructions. +(decl uqsub (Reg Reg VectorSize) Reg) +(rule (uqsub x y size) (vec_rrr (VecALUOp.Uqsub) x y size)) + +;; Helper for generating `sqsub` instructions. +(decl sqsub (Reg Reg VectorSize) Reg) +(rule (sqsub x y size) (vec_rrr (VecALUOp.Sqsub) x y size)) + +;; Helper for generating `umulh` instructions. +(decl umulh (Type Reg Reg) Reg) +(rule (umulh ty x y) (alu_rrr (ALUOp.UMulH) ty x y)) + +;; Helper for generating `smulh` instructions. +(decl smulh (Type Reg Reg) Reg) +(rule (smulh ty x y) (alu_rrr (ALUOp.SMulH) ty x y)) + +;; Helper for generating `mul` instructions. +(decl mul (Reg Reg VectorSize) Reg) +(rule (mul x y size) (vec_rrr (VecALUOp.Mul) x y size)) + +;; Helper for generating `neg` instructions. +(decl neg (Reg VectorSize) Reg) +(rule (neg x size) (vec_misc (VecMisc2.Neg) x size)) + +;; Helper for generating `rev16` instructions. +(decl rev16 (Reg VectorSize) Reg) +(rule (rev16 x size) (vec_misc (VecMisc2.Rev16) x size)) + +;; Helper for generating `rev32` instructions. +(decl rev32 (Reg VectorSize) Reg) +(rule (rev32 x size) (vec_misc (VecMisc2.Rev32) x size)) + +;; Helper for generating `rev64` instructions. +(decl rev64 (Reg VectorSize) Reg) +(rule (rev64 x size) (vec_misc (VecMisc2.Rev64) x size)) + +;; Helper for generating `xtn` instructions. +(decl xtn (Reg ScalarSize) Reg) +(rule (xtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Xtn) x size)) + +;; Helper for generating `fcvtn` instructions. +(decl fcvtn (Reg ScalarSize) Reg) +(rule (fcvtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Fcvtn) x size)) + +;; Helper for generating `sqxtn` instructions. +(decl sqxtn (Reg ScalarSize) Reg) +(rule (sqxtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Sqxtn) x size)) + +;; Helper for generating `sqxtn2` instructions. +(decl sqxtn2 (Reg Reg ScalarSize) Reg) +(rule (sqxtn2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Sqxtn) x y size)) + +;; Helper for generating `sqxtun` instructions. +(decl sqxtun (Reg ScalarSize) Reg) +(rule (sqxtun x size) (vec_rr_narrow_low (VecRRNarrowOp.Sqxtun) x size)) + +;; Helper for generating `sqxtun2` instructions. +(decl sqxtun2 (Reg Reg ScalarSize) Reg) +(rule (sqxtun2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Sqxtun) x y size)) + +;; Helper for generating `uqxtn` instructions. +(decl uqxtn (Reg ScalarSize) Reg) +(rule (uqxtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Uqxtn) x size)) + +;; Helper for generating `uqxtn2` instructions. +(decl uqxtn2 (Reg Reg ScalarSize) Reg) +(rule (uqxtn2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Uqxtn) x y size)) + +;; Helper for generating `fence` instructions. +(decl aarch64_fence () SideEffectNoResult) +(rule (aarch64_fence) + (SideEffectNoResult.Inst (MInst.Fence))) + +;; Helper for generating `csdb` instructions. +(decl csdb () SideEffectNoResult) +(rule (csdb) + (SideEffectNoResult.Inst (MInst.Csdb))) + +;; Helper for generating `brk` instructions. +(decl brk () SideEffectNoResult) +(rule (brk) + (SideEffectNoResult.Inst (MInst.Brk))) + +;; Helper for generating `addp` instructions. +(spec (addp x y s) + (provide + (= result + (switch s + (#x00 (concat + (bvadd (extract 55 48 x) (extract 63 56 x)) + (bvadd (extract 39 32 x) (extract 47 40 x)) + (bvadd (extract 23 16 x) (extract 31 24 x)) + (bvadd (extract 7 0 x) (extract 15 8 x)) + (bvadd (extract 55 48 y) (extract 63 56 y)) + (bvadd (extract 39 32 y) (extract 47 40 y)) + (bvadd (extract 23 16 y) (extract 31 24 y)) + (bvadd (extract 7 0 y) (extract 15 8 y)))) + (#x01 (concat + (bvadd (extract 47 32 x) (extract 63 48 x)) + (bvadd (extract 15 0 x) (extract 31 16 x)) + (bvadd (extract 47 32 y) (extract 63 48 y)) + (bvadd (extract 15 0 y) (extract 31 16 y)))) + (#x02 (concat + (bvadd (extract 31 0 x) (extract 63 32 x)) + (bvadd (extract 31 0 y) (extract 63 32 y))))))) + (require (or (= s #x00) (= s #x01) (= s #x02)))) +(decl addp (Reg Reg VectorSize) Reg) +(rule (addp x y size) (vec_rrr (VecALUOp.Addp) x y size)) + +;; Helper for generating `zip1` instructions. +(decl zip1 (Reg Reg VectorSize) Reg) +(rule (zip1 x y size) (vec_rrr (VecALUOp.Zip1) x y size)) + +;; Helper for generating vector `abs` instructions. +(decl vec_abs (Reg VectorSize) Reg) +(rule (vec_abs x size) (vec_misc (VecMisc2.Abs) x size)) + +;; Helper for generating instruction sequences to calculate a scalar absolute +;; value. +(spec (abs s x) + (provide + (= result + (if (= s 32) + (conv_to 64 + (if (bvsge (extract 31 0 x) #x00000000) + (extract 31 0 x) + (bvneg (extract 31 0 x)))) + (if (bvsge x #x0000000000000000) x (bvneg x))))) + (require (or (= s 32) (= s 64)))) +(decl abs (OperandSize Reg) Reg) +(rule (abs size x) + (value_regs_get (with_flags (cmp_imm size x (u8_into_imm12 0)) + (csneg (Cond.Gt) x x)) 0)) + +;; Helper for generating `addv` instructions. +(spec (addv x s) + (provide + (= result + (switch s + (#x00 (zero_ext 64 + (bvadd (extract 7 0 x) + (bvadd (extract 15 8 x) + (bvadd (extract 23 16 x) + (bvadd (extract 31 24 x) + (bvadd (extract 39 32 x) + (bvadd (extract 47 40 x) + (bvadd (extract 55 48 x) + (extract 63 56 x)))))))))) + (#x01 (zero_ext 64 + (bvadd (extract 15 0 x) + (bvadd (extract 31 16 x) + (bvadd (extract 47 32 x) + (extract 63 48 x)))))) + (#x02 (zero_ext 64 + (bvadd (extract 31 0 x) + (extract 63 32 x))))))) + (require (or (= s #x00) (or (= s #x01) (= s #x02))))) +(decl addv (Reg VectorSize) Reg) +(rule (addv x size) (vec_lanes (VecLanesOp.Addv) x size)) + +;; Helper for generating `shll32` instructions. +(decl shll32 (Reg bool) Reg) +(rule (shll32 x high_half) (vec_rr_long (VecRRLongOp.Shll32) x high_half)) + +;; Helpers for generating `addlp` instructions. + +(decl saddlp8 (Reg) Reg) +(rule (saddlp8 x) (vec_rr_pair_long (VecRRPairLongOp.Saddlp8) x)) + +(decl saddlp16 (Reg) Reg) +(rule (saddlp16 x) (vec_rr_pair_long (VecRRPairLongOp.Saddlp16) x)) + +(decl uaddlp8 (Reg) Reg) +(rule (uaddlp8 x) (vec_rr_pair_long (VecRRPairLongOp.Uaddlp8) x)) + +(decl uaddlp16 (Reg) Reg) +(rule (uaddlp16 x) (vec_rr_pair_long (VecRRPairLongOp.Uaddlp16) x)) + +;; Helper for generating `umlal32` instructions. +(decl umlal32 (Reg Reg Reg bool) Reg) +(rule (umlal32 x y z high_half) (vec_rrrr_long (VecRRRLongModOp.Umlal32) x y z high_half)) + +;; Helper for generating `smull8` instructions. +(decl smull8 (Reg Reg bool) Reg) +(rule (smull8 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull8) x y high_half)) + +;; Helper for generating `umull8` instructions. +(decl umull8 (Reg Reg bool) Reg) +(rule (umull8 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull8) x y high_half)) + +;; Helper for generating `smull16` instructions. +(decl smull16 (Reg Reg bool) Reg) +(rule (smull16 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull16) x y high_half)) + +;; Helper for generating `umull16` instructions. +(decl umull16 (Reg Reg bool) Reg) +(rule (umull16 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull16) x y high_half)) + +;; Helper for generating `smull32` instructions. +(decl smull32 (Reg Reg bool) Reg) +(rule (smull32 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull32) x y high_half)) + +;; Helper for generating `umull32` instructions. +(decl umull32 (Reg Reg bool) Reg) +(rule (umull32 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull32) x y high_half)) + +;; Helper for generating `asr` instructions. +(decl asr (Type Reg Reg) Reg) +(rule (asr ty x y) (alu_rrr (ALUOp.Asr) ty x y)) + +(decl asr_imm (Type Reg ImmShift) Reg) +(rule (asr_imm ty x imm) (alu_rr_imm_shift (ALUOp.Asr) ty x imm)) + +;; Helper for generating `lsr` instructions. +(spec (lsr ty a b) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvlshr (extract 31 0 a) (extract 31 0 b)))) + (64 (bvlshr a b)))))) +(decl lsr (Type Reg Reg) Reg) +(rule (lsr ty x y) (alu_rrr (ALUOp.Lsr) ty x y)) + +(spec (lsr_imm ty a b) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvlshr (extract 31 0 a) (zero_ext 32 b)))) + (64 (bvlshr a (zero_ext 64 b))))))) +(decl lsr_imm (Type Reg ImmShift) Reg) +(rule (lsr_imm ty x imm) (alu_rr_imm_shift (ALUOp.Lsr) ty x imm)) + +;; Helper for generating `lsl` instructions. +(spec (lsl ty a b) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvshl (extract 31 0 a) (extract 31 0 b)))) + (64 (bvshl a b)))))) +(decl lsl (Type Reg Reg) Reg) +(rule (lsl ty x y) (alu_rrr (ALUOp.Lsl) ty x y)) + +(spec (lsl_imm ty a b) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvshl (extract 31 0 a) (zero_ext 32 b)))) + (64 (bvshl a (zero_ext 64 b))))))) +(decl lsl_imm (Type Reg ImmShift) Reg) +(rule (lsl_imm ty x imm) (alu_rr_imm_shift (ALUOp.Lsl) ty x imm)) + +;; Helper for generating `udiv` instructions. +(spec (a64_udiv ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvudiv (extract 31 0 a) (extract 31 0 b))) + (bvudiv a b))))) +(decl a64_udiv (Type Reg Reg) Reg) +(rule (a64_udiv ty x y) (alu_rrr (ALUOp.UDiv) ty x y)) + +;; Helper for generating `sdiv` instructions. +(spec (a64_sdiv ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvsdiv (extract 31 0 a) (extract 31 0 b))) + (bvsdiv a b))))) +(decl a64_sdiv (Type Reg Reg) Reg) +(rule (a64_sdiv ty x y) (alu_rrr (ALUOp.SDiv) ty x y)) + +;; Helper for generating `not` instructions. +(decl not (Reg VectorSize) Reg) +(rule (not x size) (vec_misc (VecMisc2.Not) x size)) + +;; Helpers for generating `orr_not` instructions. +(spec (orr_not ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvor (extract 31 0 a) (bvnot (extract 31 0 b)))) + (bvor a (bvnot b)))))) +(decl orr_not (Type Reg Reg) Reg) +(rule (orr_not ty x y) (alu_rrr (ALUOp.OrrNot) ty x y)) + +(spec (orr_not_shift ty a b shift) + (provide + (= result (if (<= ty 32) + (conv_to 64 (bvor a (bvnot (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))) + (bvor a (bvnot (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))))) +(decl orr_not_shift (Type Reg Reg ShiftOpAndAmt) Reg) +(rule (orr_not_shift ty x y shift) (alu_rrr_shift (ALUOp.OrrNot) ty x y shift)) + +;; Helpers for generating `orr` instructions. +(spec (orr ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvor (extract 31 0 a) (extract 31 0 b))) + (bvor a b)))) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(decl orr (Type Reg Reg) Reg) +(rule (orr ty x y) (alu_rrr (ALUOp.Orr) ty x y)) + +(spec (orr_imm ty x y) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvor (extract 31 0 x) (extract 31 0 y)))) + (64 (bvor x (zero_ext 64 y)))))) + (require + (or + (= y (bvand y #x0000000000000fff)) + (= y (bvand y #x0000000000fff000))))) +(decl orr_imm (Type Reg ImmLogic) Reg) +(rule (orr_imm ty x y) (alu_rr_imm_logic (ALUOp.Orr) ty x y)) + +(decl orr_shift (Type Reg Reg ShiftOpAndAmt) Reg) +(rule (orr_shift ty x y shift) (alu_rrr_shift (ALUOp.Orr) ty x y shift)) + +(decl orr_vec (Reg Reg VectorSize) Reg) +(rule (orr_vec x y size) (vec_rrr (VecALUOp.Orr) x y size)) + +;; Helpers for generating `and` instructions. +(spec (and_reg ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) + (bvand a b)))) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(decl and_reg (Type Reg Reg) Reg) +(rule (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) + +(spec (and_imm ty x y) + (provide + (= result + (switch ty + (32 (conv_to 64 (bvand (extract 31 0 x) (extract 31 0 y)))) + (64 (bvand x (zero_ext 64 y)))))) + (require + (or + (= y (bvand y #x0000000000000fff)) + (= y (bvand y #x0000000000fff000))))) +(decl and_imm (Type Reg ImmLogic) Reg) +(rule (and_imm ty x y) (alu_rr_imm_logic (ALUOp.And) ty x y)) + +(decl and_vec (Reg Reg VectorSize) Reg) +(rule (and_vec x y size) (vec_rrr (VecALUOp.And) x y size)) + +;; Helpers for generating `eor` instructions. +(decl eor (Type Reg Reg) Reg) +(rule (eor ty x y) (alu_rrr (ALUOp.Eor) ty x y)) + +(decl eor_vec (Reg Reg VectorSize) Reg) +(rule (eor_vec x y size) (vec_rrr (VecALUOp.Eor) x y size)) + +;; Helpers for generating `bic` instructions. +(spec (bic ty a b) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvand (extract 31 0 a) (bvnot (extract 31 0 b)))) + (bvand a (bvnot b)) + ) + )) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(decl bic (Type Reg Reg) Reg) +(rule (bic ty x y) (alu_rrr (ALUOp.AndNot) ty x y)) + +(decl bic_vec (Reg Reg VectorSize) Reg) +(rule (bic_vec x y size) (vec_rrr (VecALUOp.Bic) x y size)) + +;; Helpers for generating `sshl` instructions. +(decl sshl (Reg Reg VectorSize) Reg) +(rule (sshl x y size) (vec_rrr (VecALUOp.Sshl) x y size)) + +;; Helpers for generating `ushl` instructions. +(decl ushl (Reg Reg VectorSize) Reg) +(rule (ushl x y size) (vec_rrr (VecALUOp.Ushl) x y size)) + +;; Helpers for generating `ushl` instructions. +(decl ushl_vec_imm (Reg u8 VectorSize) Reg) +(rule (ushl_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Shl) amt x size)) + +;; Helpers for generating `ushr` instructions. +(decl ushr_vec_imm (Reg u8 VectorSize) Reg) +(rule (ushr_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Ushr) amt x size)) + +;; Helpers for generating `sshr` instructions. +(decl sshr_vec_imm (Reg u8 VectorSize) Reg) +(rule (sshr_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Sshr) amt x size)) + +;; Helpers for generating `rotr` instructions. +(spec (a64_rotr ty x y) + (provide + (= result + (if (= ty 32) + (zero_ext 64 (rotr (extract 31 0 x) (extract 31 0 y))) + (rotr x y)))) + (require (or (= ty 32) (= ty 64)))) +(decl a64_rotr (Type Reg Reg) Reg) +(rule (a64_rotr ty x y) (alu_rrr (ALUOp.RotR) ty x y)) + +(spec (a64_rotr_imm ty x y) + (provide + (= result + (if (= ty 32) + (zero_ext 64 (rotr (extract 31 0 x) (zero_ext 32 y))) + (rotr x (zero_ext 64 y))))) + (require (or (= ty 32) (= ty 64)))) +(decl a64_rotr_imm (Type Reg ImmShift) Reg) +(rule (a64_rotr_imm ty x y) (alu_rr_imm_shift (ALUOp.RotR) ty x y)) + +;; Helpers for generating `rbit` instructions. +(spec (rbit ty a) + (provide + (= result + (if (= ty 32) + (conv_to 64 (rev (extract 31 0 a))) + (rev a)))) + (require (or (= ty 32) (= ty 64)))) +(decl rbit (Type Reg) Reg) +(rule (rbit ty x) (bit_rr (BitOp.RBit) ty x)) + +;; Helpers for generating `clz` instructions. +(spec (a64_clz ty a) + (provide + (= result + (if (= ty 32) + (conv_to 64 (clz (extract 31 0 a))) + (clz a)))) + (require (or (= ty 32) (= ty 64)))) +(decl a64_clz (Type Reg) Reg) +(rule (a64_clz ty x) (bit_rr (BitOp.Clz) ty x)) + +;; Helpers for generating `cls` instructions. +(spec (a64_cls ty a) + (provide + (= result + (if (= ty 32) + (conv_to 64 (cls (extract 31 0 a))) + (cls a)))) + (require (or (= ty 32) (= ty 64)))) +(decl a64_cls (Type Reg) Reg) +(rule (a64_cls ty x) (bit_rr (BitOp.Cls) ty x)) + +;; Helpers for generating `rev` instructions + +(decl a64_rev16 (Type Reg) Reg) +(rule (a64_rev16 ty x) (bit_rr (BitOp.Rev16) ty x)) + +(decl a64_rev32 (Type Reg) Reg) +(rule (a64_rev32 ty x) (bit_rr (BitOp.Rev32) ty x)) + +(decl a64_rev64 (Type Reg) Reg) +(rule (a64_rev64 ty x) (bit_rr (BitOp.Rev64) ty x)) + +;; Helpers for generating `eon` instructions. + +(decl eon (Type Reg Reg) Reg) +(rule (eon ty x y) (alu_rrr (ALUOp.EorNot) ty x y)) + +;; Helpers for generating `cnt` instructions. +(spec (vec_cnt x s) + (provide + (= result + (switch s + ((VectorSize.Size8x8) + (concat + (popcnt (extract 63 56 x)) + (popcnt (extract 55 48 x)) + (popcnt (extract 47 40 x)) + (popcnt (extract 39 32 x)) + (popcnt (extract 31 24 x)) + (popcnt (extract 23 16 x)) + (popcnt (extract 15 8 x)) + (popcnt (extract 7 0 x)))) + ((VectorSize.Size16x4) result) + ((VectorSize.Size32x2) result)))) + (require + (or (= s (VectorSize.Size8x8)) (= s (VectorSize.Size16x4)) (= s (VectorSize.Size32x2))))) +(decl vec_cnt (Reg VectorSize) Reg) +(rule (vec_cnt x size) (vec_misc (VecMisc2.Cnt) x size)) + +;; Helpers for generating a `bsl` instruction. + +(decl bsl (Type Reg Reg Reg) Reg) +(rule (bsl ty c x y) + (vec_rrr_mod (VecALUModOp.Bsl) c x y (vector_size ty))) + +;; Helper for generating a `udf` instruction. + +(decl udf (TrapCode) SideEffectNoResult) +(rule (udf trap_code) + (SideEffectNoResult.Inst (MInst.Udf trap_code))) + +;; Helpers for generating various load instructions, with varying +;; widths and sign/zero-extending properties. +(decl aarch64_uload8 (AMode MemFlags) Reg) +(spec (aarch64_uload8 amode flags) + (provide (= result (zero_ext 32 (load_effect flags 8 amode)))) + (require (= 32 (widthof result)))) +(rule (aarch64_uload8 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ULoad8 dst amode flags)))) + dst)) +(decl aarch64_sload8 (AMode MemFlags) Reg) +(rule (aarch64_sload8 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.SLoad8 dst amode flags)))) + dst)) +(decl aarch64_uload16 (AMode MemFlags) Reg) +(spec (aarch64_uload16 amode flags) + (provide (= result (zero_ext 32 (load_effect flags 16 amode)))) + (require (= 32 (widthof result)))) +(rule (aarch64_uload16 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ULoad16 dst amode flags)))) + dst)) +(decl aarch64_sload16 (AMode MemFlags) Reg) +(rule (aarch64_sload16 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.SLoad16 dst amode flags)))) + dst)) +(decl aarch64_uload32 (AMode MemFlags) Reg) +(spec (aarch64_uload32 amode flags) + (provide (= result (load_effect flags 32 amode))) + (require (= 32 (widthof result)))) +(rule (aarch64_uload32 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ULoad32 dst amode flags)))) + dst)) +(decl aarch64_sload32 (AMode MemFlags) Reg) +(rule (aarch64_sload32 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.SLoad32 dst amode flags)))) + dst)) +(decl aarch64_uload64 (AMode MemFlags) Reg) +(spec (aarch64_uload64 amode flags) + (provide (= result (load_effect flags 64 amode))) + (require (= 64 (widthof result)))) +(rule (aarch64_uload64 amode flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ULoad64 dst amode flags)))) + dst)) +(decl aarch64_fpuload16 (AMode MemFlags) Reg) +(rule (aarch64_fpuload16 amode flags) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuLoad16 dst amode flags)))) + dst)) +(decl aarch64_fpuload32 (AMode MemFlags) Reg) +(rule (aarch64_fpuload32 amode flags) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuLoad32 dst amode flags)))) + dst)) +(decl aarch64_fpuload64 (AMode MemFlags) Reg) +(rule (aarch64_fpuload64 amode flags) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.FpuLoad64 dst amode flags)))) + dst)) +(decl aarch64_fpuload128 (AMode MemFlags) Reg) +(rule (aarch64_fpuload128 amode flags) + (let ((dst WritableReg (temp_writable_reg $F64X2)) + (_ Unit (emit (MInst.FpuLoad128 dst amode flags)))) + dst)) +(decl aarch64_loadp64 (PairAMode MemFlags) ValueRegs) +(rule (aarch64_loadp64 amode flags) + (let ((dst1 WritableReg (temp_writable_reg $I64)) + (dst2 WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadP64 dst1 dst2 amode flags)))) + (value_regs dst1 dst2))) + +;; Helpers for generating various store instructions with varying +;; widths. +(decl aarch64_store8 (AMode MemFlags Reg) SideEffectNoResult) +(spec (aarch64_store8 amode flags val) + (provide (= result (store_effect flags 8 (extract 7 0 val) amode)))) +(rule (aarch64_store8 amode flags val) + (SideEffectNoResult.Inst (MInst.Store8 val amode flags))) +(decl aarch64_store16 (AMode MemFlags Reg) SideEffectNoResult) +(spec (aarch64_store16 amode flags val) + (provide (= result (store_effect flags 16 (extract 15 0 val) amode)))) +(rule (aarch64_store16 amode flags val) + (SideEffectNoResult.Inst (MInst.Store16 val amode flags))) +(decl aarch64_store32 (AMode MemFlags Reg) SideEffectNoResult) +(spec (aarch64_store32 amode flags val) + (provide (= result (store_effect flags 32 (extract 31 0 val) amode)))) +(rule (aarch64_store32 amode flags val) + (SideEffectNoResult.Inst (MInst.Store32 val amode flags))) +(decl aarch64_store64 (AMode MemFlags Reg) SideEffectNoResult) +(spec (aarch64_store64 amode flags val) + (provide (= result (store_effect flags 64 val amode)))) +(rule (aarch64_store64 amode flags val) + (SideEffectNoResult.Inst (MInst.Store64 val amode flags))) +(decl aarch64_fpustore16 (AMode MemFlags Reg) SideEffectNoResult) +(rule (aarch64_fpustore16 amode flags val) + (SideEffectNoResult.Inst (MInst.FpuStore16 val amode flags))) +(decl aarch64_fpustore32 (AMode MemFlags Reg) SideEffectNoResult) +(rule (aarch64_fpustore32 amode flags val) + (SideEffectNoResult.Inst (MInst.FpuStore32 val amode flags))) +(decl aarch64_fpustore64 (AMode MemFlags Reg) SideEffectNoResult) +(rule (aarch64_fpustore64 amode flags val) + (SideEffectNoResult.Inst (MInst.FpuStore64 val amode flags))) +(decl aarch64_fpustore128 (AMode MemFlags Reg) SideEffectNoResult) +(rule (aarch64_fpustore128 amode flags val) + (SideEffectNoResult.Inst (MInst.FpuStore128 val amode flags))) +(decl aarch64_storep64 (PairAMode MemFlags Reg Reg) SideEffectNoResult) +(rule (aarch64_storep64 amode flags val1 val2) + (SideEffectNoResult.Inst (MInst.StoreP64 val1 val2 amode flags))) + +;; Helper for generating a `trapif` instruction. + +(decl trap_if (ProducesFlags TrapCode Cond) InstOutput) +(rule (trap_if flags trap_code cond) + (side_effect + (with_flags_side_effect flags + (ConsumesFlags.ConsumesFlagsSideEffect + (MInst.TrapIf (cond_br_cond cond) trap_code))))) + +;; Helpers for lowering `trapz` and `trapnz`. +(type ZeroCond + (enum + Zero + NonZero)) + +(decl zero_cond_to_cond_br (ZeroCond Reg OperandSize) CondBrKind) +(rule (zero_cond_to_cond_br (ZeroCond.Zero) reg size) + (cond_br_zero reg size)) + +(rule (zero_cond_to_cond_br (ZeroCond.NonZero) reg size) + (cond_br_not_zero reg size)) + +(decl trap_if_val (ZeroCond Value TrapCode) InstOutput) +(rule (trap_if_val zero_cond val @ (value_type (fits_in_64 _)) trap_code) + (let ((reg Reg (put_in_reg_zext64 val))) + (side_effect + (SideEffectNoResult.Inst + (MInst.TrapIf (zero_cond_to_cond_br zero_cond reg (operand_size $I64)) trap_code))))) + +(rule -1 (trap_if_val zero_cond val @ (value_type $I128) trap_code) + (let ((c ValueRegs (put_in_regs val)) + (c_lo Reg (value_regs_get c 0)) + (c_hi Reg (value_regs_get c 1)) + (c_test Reg (orr $I64 c_lo c_hi))) + (side_effect + (SideEffectNoResult.Inst + (MInst.TrapIf (zero_cond_to_cond_br zero_cond c_test (operand_size $I64)) trap_code))))) + +;; Immediate value helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Type of extension performed by an immediate helper +(model ImmExtend + (enum + (Sign #b0) + (Zero #b1))) +(type ImmExtend + (enum + (Sign) + (Zero))) + +;; Arguments: +;; * Immediate type +;; * Way to extend the immediate value to the full width of the destination +;; register +;; * Immediate value - only the bits that fit within the type are used and +;; extended, while the rest are ignored +;; +;; Note that, unlike the convention in the AArch64 backend, this helper leaves +;; all bits in the destination register in a defined state, i.e. smaller types +;; such as `I8` are either sign- or zero-extended. +(spec (imm ty ext x) + (provide + (= result + (switch ty + (8 (if (= ext #b1) (zero_ext 64 (extract 7 0 x)) (sign_ext 64 (extract 7 0 x)))) + (16 (if (= ext #b1) (zero_ext 64 (extract 15 0 x)) (sign_ext 64 (extract 15 0 x)))) + (32 (if (= ext #b1) (zero_ext 64 (extract 32 0 x)) (sign_ext 64 (extract 32 0 x)))) + (64 x)))) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(instantiate imm + ((args Int (bv 64)) (ret (bv 64)) (canon (bv 8))) + ((args Int (bv 64)) (ret (bv 64)) (canon (bv 16))) + ((args Int (bv 64)) (ret (bv 64)) (canon (bv 32))) + ((args Int (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(decl imm (Type ImmExtend u64) Reg) + +;; Move wide immediate instructions; to simplify, we only match when we +;; are zero-extending the value. +(rule 3 (imm (integral_ty ty) (ImmExtend.Zero) k) + (if-let n (move_wide_const_from_u64 ty k)) + (add_range_fact + (movz n (operand_size ty)) + 64 k k)) +(rule 2 (imm (integral_ty (ty_32_or_64 ty)) (ImmExtend.Zero) k) + (if-let n (move_wide_const_from_inverted_u64 ty k)) + (add_range_fact + (movn n (operand_size ty)) + 64 k k)) + +;; Weird logical-instruction immediate in ORI using zero register; to simplify, +;; we only match when we are zero-extending the value. +(rule 1 (imm (integral_ty ty) (ImmExtend.Zero) k) + (if-let n (imm_logic_from_u64 ty k)) + (if-let m (imm_size_from_type ty)) + (add_range_fact + (orr_imm ty (zero_reg) n) + m k k)) + +(decl load_constant_full (Type ImmExtend OperandSize u64) Reg) +(extern constructor load_constant_full load_constant_full) + +;; Fallback for integral 32-bit constants +(rule (imm (fits_in_32 (integral_ty ty)) extend n) + (load_constant_full ty extend (operand_size $I32) n)) + +;; Fallback for integral 64-bit constants +(rule -1 (imm (integral_ty $I64) extend n) + (load_constant_full $I64 extend (operand_size $I64) n)) + + +;; Sign extension helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Place a `Value` into a register, sign extending it to 32-bits +(spec (put_in_reg_sext32 arg) + (provide + (= result + (if (<= (widthof arg) 32) + (conv_to 64 (sign_ext 32 arg)) + (conv_to 64 arg))))) +(decl put_in_reg_sext32 (Value) Reg) +(rule -1 (put_in_reg_sext32 val @ (value_type (fits_in_32 ty))) + (extend val true (ty_bits ty) 32)) + +;; 32/64-bit passthrough. +(rule (put_in_reg_sext32 val @ (value_type $I32)) val) +(rule (put_in_reg_sext32 val @ (value_type $I64)) val) + +;; Place a `Value` into a register, zero extending it to 32-bits +(spec (put_in_reg_zext32 arg) + (provide + (= result + (if (<= (widthof arg) 32) + (conv_to 64 (zero_ext 32 arg)) + (conv_to 64 arg))))) +(decl put_in_reg_zext32 (Value) Reg) +(rule -1 (put_in_reg_zext32 val @ (value_type (fits_in_32 ty))) + (extend val false (ty_bits ty) 32)) + +;; 32/64-bit passthrough. +(rule (put_in_reg_zext32 val @ (value_type $I32)) val) +(rule (put_in_reg_zext32 val @ (value_type $I64)) val) + +;; Place a `Value` into a register, sign extending it to 64-bits +(spec (put_in_reg_sext64 x) + (provide (= (sign_ext 64 x) result))) +(decl put_in_reg_sext64 (Value) Reg) +(rule 1 (put_in_reg_sext64 val @ (value_type (fits_in_32 ty))) + (extend val true (ty_bits ty) 64)) + +;; 64-bit passthrough. +(rule (put_in_reg_sext64 val @ (value_type $I64)) val) + +;; Place a `Value` into a register, zero extending it to 64-bits +(spec (put_in_reg_zext64 x) + (provide (= result (zero_ext 64 x)))) +(decl put_in_reg_zext64 (Value) Reg) +(rule 1 (put_in_reg_zext64 val @ (value_type (fits_in_32 ty))) + (extend val false (ty_bits ty) 64)) + +;; 64-bit passthrough. +(rule (put_in_reg_zext64 val @ (value_type $I64)) val) + +;; Misc instruction helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl trap_if_zero_divisor (Reg OperandSize) Reg) +(rule (trap_if_zero_divisor reg size) + (let ((_ Unit (emit (MInst.TrapIf (cond_br_zero reg size ) (trap_code_division_by_zero))))) + reg)) + +(decl size_from_ty (Type) OperandSize) +(rule 1 (size_from_ty (fits_in_32 _ty)) (OperandSize.Size32)) +(rule (size_from_ty $I64) (OperandSize.Size64)) + +;; Check for signed overflow. The only case is min_value / -1. +;; The following checks must be done in 32-bit or 64-bit, depending +;; on the input type. For 8- and 16- bit, the check for x == min_value +;; must use a possibly-shifted value, xcheck, to overflow as expected. +(decl trap_if_div_overflow (Type Reg Reg Reg) Reg) +(rule (trap_if_div_overflow ty xcheck x y) + (let ( + ;; Check RHS is -1. + (_ Unit (emit (MInst.AluRRImm12 (ALUOp.AddS) (operand_size ty) (writable_zero_reg) y (u8_into_imm12 1)))) + + ;; Check LHS is min_value, by subtracting 1 from the possibly-shifted + ;; value and branching if there is overflow. + (_ Unit (emit (MInst.CCmpImm (size_from_ty ty) + xcheck + (u8_into_uimm5 1) + (nzcv false false false false) + (Cond.Eq)))) + (_ Unit (emit (MInst.TrapIf (cond_br_cond (Cond.Vs)) + (trap_code_integer_overflow)))) + ) + x)) + +;; In the cases narrower than a register width, subtracting 1 from the +;; min_value will not cause overflow (e.g., I8's min_value of -128 stored in +;; a 32-bit register produces -129 with no overflow). However, if we left shift +;; x by (32 - ty), we then produce the 32-bit min_value for the respective min +;; values of I8 and I16. +;; E.g., I8's 0x00000080 left-shifted by 24 is 0x80000000, which overflows. +(decl intmin_check (Type Reg) Reg) +(rule intmin_check_fits_in_16 (intmin_check (fits_in_16 ty) x) + (alu_rr_imm_shift (ALUOp.Lsl) ty x (imm_shift_from_u8 (diff_from_32 ty)))) + +;; In the I32 or I64 case, checking x itself against the min_value is fine. +(rule -1 (intmin_check ty x) x) + +;; Check for unsigned overflow. +(decl trap_if_overflow (ProducesFlags TrapCode) Reg) +(rule (trap_if_overflow producer tc) + (with_flags_reg + producer + (ConsumesFlags.ConsumesFlagsSideEffect + (MInst.TrapIf (cond_br_cond (Cond.Hs)) tc)))) + +(decl sink_atomic_load (Inst) Reg) +(rule (sink_atomic_load x @ (atomic_load _ addr)) + (let ((_ Unit (sink_inst x))) + (put_in_reg addr))) + +;; Helper for generating either an `AluRRR`, `AluRRRShift`, or `AluRRImmLogic` +;; instruction depending on the input. Note that this requires that the `ALUOp` +;; specified is commutative. +(spec (alu_rs_imm_logic_commutative op t a b) + (provide + (= result + (conv_to 64 + (switch op + ((ALUOp.Orr) (bvor a b)) + ((ALUOp.And) (bvand a b)) + ((ALUOp.Eor) (bvxor a b))))))) +(decl alu_rs_imm_logic_commutative (ALUOp Type Value Value) Reg) + +;; Base case of operating on registers. +(rule -1 (alu_rs_imm_logic_commutative op ty x y) + (alu_rrr op ty x y)) + +;; Special cases for when one operand is a constant. +(rule (alu_rs_imm_logic_commutative op ty x (iconst k)) + (if-let imm (imm_logic_from_imm64 ty k)) + (alu_rr_imm_logic op ty x imm)) +(rule 1 (alu_rs_imm_logic_commutative op ty (iconst k) x) + (if-let imm (imm_logic_from_imm64 ty k)) + (alu_rr_imm_logic op ty x imm)) + +;; Special cases for when one operand is shifted left by a constant. +(rule (alu_rs_imm_logic_commutative op ty x (ishl y (iconst k))) + (if-let amt (lshl_from_imm64 ty k)) + (alu_rrr_shift op ty x y amt)) +(rule 1 (alu_rs_imm_logic_commutative op ty (ishl x (iconst k)) y) + (if-let amt (lshl_from_imm64 ty k)) + (alu_rrr_shift op ty y x amt)) + +;; Same as `alu_rs_imm_logic_commutative` above, except that it doesn't require +;; that the operation is commutative. +(spec (alu_rs_imm_logic op t a b) + (provide + (= result + (conv_to 64 + (switch op + ((ALUOp.OrrNot) (bvor a (bvnot b))) + ((ALUOp.EorNot) (bvxor a (bvnot b))) + ((ALUOp.AndNot) (bvand a (bvnot b)))))))) +(decl alu_rs_imm_logic (ALUOp Type Value Value) Reg) +(rule -1 (alu_rs_imm_logic op ty x y) + (alu_rrr op ty x y)) +(rule (alu_rs_imm_logic op ty x (iconst k)) + (if-let imm (imm_logic_from_imm64 ty k)) + (alu_rr_imm_logic op ty x imm)) +(rule (alu_rs_imm_logic op ty x (ishl y (iconst k))) + (if-let amt (lshl_from_imm64 ty k)) + (alu_rrr_shift op ty x y amt)) + +;; Helper for generating i128 bitops which simply do the same operation to the +;; hi/lo registers. +;; +;; TODO: Support immlogic here +(decl i128_alu_bitop (ALUOp Type Value Value) ValueRegs) +(rule (i128_alu_bitop op ty x y) + (let ( + (x_regs ValueRegs (put_in_regs x)) + (x_lo Reg (value_regs_get x_regs 0)) + (x_hi Reg (value_regs_get x_regs 1)) + (y_regs ValueRegs (put_in_regs y)) + (y_lo Reg (value_regs_get y_regs 0)) + (y_hi Reg (value_regs_get y_regs 1)) + ) + (value_regs + (alu_rrr op ty x_lo y_lo) + (alu_rrr op ty x_hi y_hi)))) + +;; Helper for emitting `MInst.VecLoadReplicate` instructions. +(decl ld1r (Reg VectorSize MemFlags) Reg) +(rule (ld1r src size flags) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecLoadReplicate dst src size flags)))) + dst)) + +;; Helper for emitting `MInst.LoadExtName` instructions. +(decl load_ext_name (BoxExternalName i64) Reg) +(rule (load_ext_name extname offset) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadExtName dst extname offset)))) + dst)) + +;; Lower the address of a load or a store. +;; +;; This will create an `AMode` representing the address of the `Value` provided +;; at runtime plus the immediate offset `i32` provided. The `Type` here is used +;; to represent the size of the value being loaded or stored for offset scaling +;; if necessary. +;; +;; Note that this is broken up into two phases. In the first phase this attempts +;; to find constants within the `val` provided and fold them in to the `offset` +;; provided. Afterwards though the `amode_no_more_iconst` helper is used at +;; which pointer constants are no longer pattern-matched and instead only +;; various modes are generated. This in theory would not be necessary with +;; mid-end optimizations that fold constants into load/store immediate offsets +;; instead, but for now each backend needs to do this. +(decl amode (Type Value i32) AMode) +(spec (amode ty val offset) + (provide (= result (bvadd val (sign_ext 64 offset)))) + (require (= 64 (widthof val)))) + +(rule 0 (amode ty val offset) + (amode_no_more_iconst ty val offset)) +(rule 1 (amode ty (iadd x (i32_from_iconst y)) offset) + (if-let new_offset (s32_add_fallible y offset)) + (amode_no_more_iconst ty x new_offset)) +(rule 2 (amode ty (iadd (i32_from_iconst x) y) offset) + (if-let new_offset (s32_add_fallible x offset)) + (amode_no_more_iconst ty y new_offset)) + +(decl amode_no_more_iconst (Type Value i32) AMode) +;; Base case: move the `offset` into a register and add it to `val` via the +;; amode +(rule 0 (amode_no_more_iconst ty val offset) + (AMode.RegReg val (imm $I64 (ImmExtend.Zero) (i64_as_u64 offset)))) + +;; Optimize cases where the `offset` provided fits into a immediates of +;; various kinds of addressing modes. +(rule 1 (amode_no_more_iconst ty val offset) + (if-let simm9 (simm9_from_i64 offset)) + (AMode.Unscaled val simm9)) +(rule 2 (amode_no_more_iconst ty val offset) + (if-let uimm12 (uimm12_scaled_from_i64 offset ty)) + (AMode.UnsignedOffset val uimm12)) + +;; Optimizations where addition can fold some operations into the `amode`. +;; +;; Note that here these take higher priority than constants because an +;; add-of-extend can be folded into an amode, representing 2 otherwise emitted +;; instructions. Constants on the other hand added to the amode represent only +;; a single instruction folded in, so fewer instructions should be generated +;; with these higher priority than the rules above. +(rule 3 (amode_no_more_iconst ty (iadd x y) offset) + (AMode.RegReg (amode_add x offset) y)) +(rule 4 (amode_no_more_iconst ty (iadd x (uextend y @ (value_type $I32))) offset) + (AMode.RegExtended (amode_add x offset) y (ExtendOp.UXTW))) +(rule 4 (amode_no_more_iconst ty (iadd x (sextend y @ (value_type $I32))) offset) + (AMode.RegExtended (amode_add x offset) y (ExtendOp.SXTW))) +(rule 5 (amode_no_more_iconst ty (iadd (uextend x @ (value_type $I32)) y) offset) + (AMode.RegExtended (amode_add y offset) x (ExtendOp.UXTW))) +(rule 5 (amode_no_more_iconst ty (iadd (sextend x @ (value_type $I32)) y) offset) + (AMode.RegExtended (amode_add y offset) x (ExtendOp.SXTW))) + +;; `RegScaled*` rules where this matches an addition of an "index register" to a +;; base register. The index register is shifted by the size of the type loaded +;; in bytes to enable this mode matching. +;; +;; Note that this can additionally bundle an extending operation but the +;; extension must happen before the shift. This will pattern-match the shift +;; first and then if that succeeds afterwards try to find an extend. +(rule 6 (amode_no_more_iconst ty (iadd x (ishl y (iconst (u64_from_imm64 n)))) offset) + (if-let true (u64_eq (ty_bytes ty) (u64_shl 1 n))) + (amode_reg_scaled (amode_add x offset) y)) +(rule 7 (amode_no_more_iconst ty (iadd (ishl y (iconst (u64_from_imm64 n))) x) offset) + (if-let true (u64_eq (ty_bytes ty) (u64_shl 1 n))) + (amode_reg_scaled (amode_add x offset) y)) + +(decl amode_reg_scaled (Reg Value) AMode) +(rule 0 (amode_reg_scaled base index) + (AMode.RegScaled base index)) +(rule 1 (amode_reg_scaled base (uextend index @ (value_type $I32))) + (AMode.RegScaledExtended base index (ExtendOp.UXTW))) +(rule 1 (amode_reg_scaled base (sextend index @ (value_type $I32))) + (AMode.RegScaledExtended base index (ExtendOp.SXTW))) + +;; Helper to add a 32-bit signed immediate to the register provided. This will +;; select an appropriate `add` instruction to use. +(decl amode_add (Reg i32) Reg) +(rule 0 (amode_add x y) + (add $I64 x (imm $I64 (ImmExtend.Zero) (i64_as_u64 y)))) +(rule 1 (amode_add x y) + (if-let (imm12_from_u64 imm12) (i64_as_u64 y)) + (add_imm $I64 x imm12)) +(rule 2 (amode_add x 0) x) + +;; Creates a `PairAMode` for the `Value` provided plus the `i32` constant +;; offset provided. +(decl pair_amode (Value i32) PairAMode) + +;; Base case where `val` and `offset` are combined with an `add` +(rule 0 (pair_amode val offset) + (if-let simm7 (simm7_scaled_from_i64 0 $I64)) + (PairAMode.SignedOffset (amode_add val offset) simm7)) + +;; Optimization when `offset` can fit into a `SImm7Scaled`. +(rule 1 (pair_amode val offset) + (if-let simm7 (simm7_scaled_from_i64 offset $I64)) + (PairAMode.SignedOffset val simm7)) + +(decl pure partial simm7_scaled_from_i64 (i64 Type) SImm7Scaled) +(extern constructor simm7_scaled_from_i64 simm7_scaled_from_i64) + +(decl pure partial uimm12_scaled_from_i64 (i64 Type) UImm12Scaled) +(extern constructor uimm12_scaled_from_i64 uimm12_scaled_from_i64) + +(decl pure partial simm9_from_i64 (i64) SImm9) +(extern constructor simm9_from_i64 simm9_from_i64) + + +(decl sink_load_into_addr (Type Inst) Reg) +(rule (sink_load_into_addr ty x @ (load _ addr (offset32 offset))) + (let ((_ Unit (sink_inst x))) + (add_imm_to_addr addr (i64_as_u64 offset)))) + +(decl add_imm_to_addr (Reg u64) Reg) +(rule 2 (add_imm_to_addr val 0) val) +(rule 1 (add_imm_to_addr val (imm12_from_u64 imm)) (add_imm $I64 val imm)) +(rule 0 (add_imm_to_addr val offset) (add $I64 val (imm $I64 (ImmExtend.Zero) offset))) + +;; Lower a constant f16. +;; +;; Note that we must make sure that all bits outside the lowest 16 are set to 0 +;; because this function is also used to load wider constants (that have zeros +;; in their most significant bits). +(decl constant_f16 (u16) Reg) +(rule 3 (constant_f16 n) + (if-let false (use_fp16)) + (constant_f32 n)) +(rule 2 (constant_f16 0) + (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) + false + (VectorSize.Size32x2))) +(rule 1 (constant_f16 n) + (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size16))) + (fpu_move_fp_imm imm (ScalarSize.Size16))) +(rule (constant_f16 n) + (mov_to_fpu (imm $I16 (ImmExtend.Zero) n) (ScalarSize.Size16))) + +;; Lower a constant f32. +;; +;; Note that we must make sure that all bits outside the lowest 32 are set to 0 +;; because this function is also used to load wider constants (that have zeros +;; in their most significant bits). +(decl constant_f32 (u32) Reg) +(rule 3 (constant_f32 0) + (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) + false + (VectorSize.Size32x2))) +(rule 2 (constant_f32 n) + (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size32))) + (fpu_move_fp_imm imm (ScalarSize.Size32))) +(rule 1 (constant_f32 (u32_as_u16 n)) + (if-let true (use_fp16)) + (constant_f16 n)) +(rule (constant_f32 n) + (mov_to_fpu (imm $I32 (ImmExtend.Zero) n) (ScalarSize.Size32))) + +;; Lower a constant f64. +;; +;; Note that we must make sure that all bits outside the lowest 64 are set to 0 +;; because this function is also used to load wider constants (that have zeros +;; in their most significant bits). +;; TODO: Treat as half of a 128 bit vector and consider replicated patterns. +;; Scalar MOVI might also be an option. +(decl constant_f64 (u64) Reg) +(rule 4 (constant_f64 0) + (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) + false + (VectorSize.Size32x2))) +(rule 3 (constant_f64 n) + (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size64))) + (fpu_move_fp_imm imm (ScalarSize.Size64))) +(rule 2 (constant_f64 (u64_as_u32 n)) + (constant_f32 n)) +(rule 1 (constant_f64 (u64_low32_bits_unset n)) + (mov_to_fpu (imm $I64 (ImmExtend.Zero) n) (ScalarSize.Size64))) +(rule (constant_f64 n) + (fpu_load64 (AMode.Const (emit_u64_le_const n)) (mem_flags_trusted))) + +;; Tests whether the low 32 bits in the input are all zero. +(decl u64_low32_bits_unset (u64) u64) +(extern extractor u64_low32_bits_unset u64_low32_bits_unset) + +;; Lower a constant f128. +(decl constant_f128 (u128) Reg) +(rule 3 (constant_f128 0) + (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size8)) + false + (VectorSize.Size8x16))) + +;; If the upper 64-bits are all zero then defer to `constant_f64`. +(rule 2 (constant_f128 (u128_as_u64 n)) (constant_f64 n)) + +;; If the low half of the u128 equals the high half then delegate to the splat +;; logic as a splat of a 64-bit value. +(rule 1 (constant_f128 (u128_replicated_u64 n)) + (splat_const n (VectorSize.Size64x2))) + +;; Base case is to load the constant from memory. +(rule (constant_f128 n) + (fpu_load128 (AMode.Const (emit_u128_le_const n)) (mem_flags_trusted))) + +;; Lower a vector splat with a constant parameter. +;; +;; The 64-bit input here only uses the low bits for the lane size in +;; `VectorSize` and all other bits are ignored. +(decl splat_const (u64 VectorSize) Reg) + +;; If the splat'd constant can itself be reduced in size then attempt to do so +;; as it will make it easier to create the immediates in the instructions below. +(rule 5 (splat_const (u64_replicated_u32 n) (VectorSize.Size64x2)) + (splat_const n (VectorSize.Size32x4))) +(rule 5 (splat_const (u32_replicated_u16 n) (VectorSize.Size32x4)) + (splat_const n (VectorSize.Size16x8))) +(rule 5 (splat_const (u32_replicated_u16 n) (VectorSize.Size32x2)) + (splat_const n (VectorSize.Size16x4))) +(rule 5 (splat_const (u16_replicated_u8 n) (VectorSize.Size16x8)) + (splat_const n (VectorSize.Size8x16))) +(rule 5 (splat_const (u16_replicated_u8 n) (VectorSize.Size16x4)) + (splat_const n (VectorSize.Size8x8))) + +;; Special cases for `vec_dup_imm` instructions where the input is either +;; negated or not. +(rule 4 (splat_const n size) + (if-let imm (asimd_mov_mod_imm_from_u64 n (vector_lane_size size))) + (vec_dup_imm imm false size)) +(rule 3 (splat_const n size) + (if-let imm (asimd_mov_mod_imm_from_u64 (u64_not n) (vector_lane_size size))) + (vec_dup_imm imm true size)) + +;; Special case a 32-bit splat where an immediate can be created by +;; concatenating the 32-bit constant into a 64-bit value +(rule 2 (splat_const n (VectorSize.Size32x4)) + (if-let imm (asimd_mov_mod_imm_from_u64 (u64_or n (u64_shl n 32)) (ScalarSize.Size64))) + (vec_dup_imm imm false (VectorSize.Size64x2))) +(rule 2 (splat_const n (VectorSize.Size32x2)) + (if-let imm (asimd_mov_mod_imm_from_u64 (u64_or n (u64_shl n 32)) (ScalarSize.Size64))) + (fpu_extend (vec_dup_imm imm false (VectorSize.Size64x2)) (ScalarSize.Size64))) + +(rule 1 (splat_const n size) + (if-let true (vec_dup_fp_imm_supports_lane_size (vector_lane_size size))) + (if-let imm (asimd_fp_mod_imm_from_u64 n (vector_lane_size size))) + (vec_dup_fp_imm imm size)) + +(decl pure vec_dup_fp_imm_supports_lane_size (ScalarSize) bool) +(rule 1 (vec_dup_fp_imm_supports_lane_size (ScalarSize.Size32)) true) +(rule 1 (vec_dup_fp_imm_supports_lane_size (ScalarSize.Size64)) true) +(rule (vec_dup_fp_imm_supports_lane_size _) false) + +;; The base case for splat is to use `vec_dup` with the immediate loaded into a +;; register. +(rule (splat_const n size) + (vec_dup (imm $I64 (ImmExtend.Zero) n) size)) + +;; Lower a FloatCC to a Cond. +(decl fp_cond_code (FloatCC) Cond) +;; TODO: Port lower_fp_condcode() to ISLE. +(extern constructor fp_cond_code fp_cond_code) + +;; Lower an integer cond code. +(spec (cond_code a) (provide (= a result))) +(decl cond_code (IntCC) Cond) +;; TODO: Port lower_condcode() to ISLE. +(extern constructor cond_code cond_code) + +;; Invert a condition code. +(decl invert_cond (Cond) Cond) +;; TODO: Port cond.invert() to ISLE. +(extern constructor invert_cond invert_cond) + +;; Generate comparison to zero operator from input condition code +(decl float_cc_cmp_zero_to_vec_misc_op (FloatCC) VecMisc2) +(extern constructor float_cc_cmp_zero_to_vec_misc_op float_cc_cmp_zero_to_vec_misc_op) + +(decl float_cc_cmp_zero_to_vec_misc_op_swap (FloatCC) VecMisc2) +(extern constructor float_cc_cmp_zero_to_vec_misc_op_swap float_cc_cmp_zero_to_vec_misc_op_swap) + +;; Match valid generic compare to zero cases +(decl fcmp_zero_cond (FloatCC) FloatCC) +(extern extractor fcmp_zero_cond fcmp_zero_cond) + +;; Match not equal compare to zero separately as it requires two output instructions +(decl fcmp_zero_cond_not_eq (FloatCC) FloatCC) +(extern extractor fcmp_zero_cond_not_eq fcmp_zero_cond_not_eq) + +;; Helper for generating float compare to zero instructions where 2nd argument is zero +(decl float_cmp_zero (FloatCC Reg VectorSize) Reg) +(rule (float_cmp_zero cond rn size) + (vec_misc (float_cc_cmp_zero_to_vec_misc_op cond) rn size)) + +;; Helper for generating float compare to zero instructions in case where 1st argument is zero +(decl float_cmp_zero_swap (FloatCC Reg VectorSize) Reg) +(rule (float_cmp_zero_swap cond rn size) + (vec_misc (float_cc_cmp_zero_to_vec_misc_op_swap cond) rn size)) + +;; Helper for generating float compare equal to zero instruction +(decl fcmeq0 (Reg VectorSize) Reg) +(rule (fcmeq0 rn size) + (vec_misc (VecMisc2.Fcmeq0) rn size)) + +;; Generate comparison to zero operator from input condition code +(decl int_cc_cmp_zero_to_vec_misc_op (IntCC) VecMisc2) +(extern constructor int_cc_cmp_zero_to_vec_misc_op int_cc_cmp_zero_to_vec_misc_op) + +(decl int_cc_cmp_zero_to_vec_misc_op_swap (IntCC) VecMisc2) +(extern constructor int_cc_cmp_zero_to_vec_misc_op_swap int_cc_cmp_zero_to_vec_misc_op_swap) + +;; Match valid generic compare to zero cases +(decl icmp_zero_cond (IntCC) IntCC) +(extern extractor icmp_zero_cond icmp_zero_cond) + +;; Match not equal compare to zero separately as it requires two output instructions +(decl icmp_zero_cond_not_eq (IntCC) IntCC) +(extern extractor icmp_zero_cond_not_eq icmp_zero_cond_not_eq) + +;; Helper for generating int compare to zero instructions where 2nd argument is zero +(decl int_cmp_zero (IntCC Reg VectorSize) Reg) +(rule (int_cmp_zero cond rn size) + (vec_misc (int_cc_cmp_zero_to_vec_misc_op cond) rn size)) + +;; Helper for generating int compare to zero instructions in case where 1st argument is zero +(decl int_cmp_zero_swap (IntCC Reg VectorSize) Reg) +(rule (int_cmp_zero_swap cond rn size) + (vec_misc (int_cc_cmp_zero_to_vec_misc_op_swap cond) rn size)) + +;; Helper for generating int compare equal to zero instruction +(decl cmeq0 (Reg VectorSize) Reg) +(rule (cmeq0 rn size) + (vec_misc (VecMisc2.Cmeq0) rn size)) + +;; Helper for emitting `MInst.AtomicRMW` instructions. +(decl lse_atomic_rmw (AtomicRMWOp Value Reg Type MemFlags) Reg) +(rule (lse_atomic_rmw op p r_arg2 ty flags) + (let ( + (r_addr Reg p) + (dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AtomicRMW op r_arg2 dst r_addr ty flags))) + ) + dst)) + +;; Helper for emitting `MInst.AtomicCAS` instructions. +(decl lse_atomic_cas (Reg Reg Reg Type MemFlags) Reg) +(rule (lse_atomic_cas addr expect replace ty flags) + (let ( + (dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AtomicCAS dst expect replace addr ty flags))) + ) + dst)) + +;; Helper for emitting `MInst.AtomicRMWLoop` instructions. +;; - Make sure that both args are in virtual regs, since in effect +;; we have to do a parallel copy to get them safely to the AtomicRMW input +;; regs, and that's not guaranteed safe if either is in a real reg. +;; - Move the args to the preordained AtomicRMW input regs +;; - And finally, copy the preordained AtomicRMW output reg to its destination. +(decl atomic_rmw_loop (AtomicRMWLoopOp Reg Reg Type MemFlags) Reg) +(rule (atomic_rmw_loop op addr operand ty flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (scratch1 WritableReg (temp_writable_reg $I64)) + (scratch2 WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AtomicRMWLoop ty op flags addr operand dst scratch1 scratch2)))) + dst)) + +;; Helper for emitting `MInst.AtomicCASLoop` instructions. +;; This is very similar to, but not identical to, the AtomicRmw case. Note +;; that the AtomicCASLoop sequence does its own masking, so we don't need to worry +;; about zero-extending narrow (I8/I16/I32) values here. +;; Make sure that all three args are in virtual regs. See corresponding comment +;; for `atomic_rmw_loop` above. +(decl atomic_cas_loop (Reg Reg Reg Type MemFlags) Reg) +(rule (atomic_cas_loop addr expect replace ty flags) + (let ((dst WritableReg (temp_writable_reg $I64)) + (scratch WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AtomicCASLoop ty flags addr expect replace dst scratch)))) + dst)) + +;; Helper for emitting `MInst.MovPReg` instructions. +(decl mov_from_preg (PReg) Reg) +(rule (mov_from_preg src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovFromPReg dst src)))) + dst)) + +(decl mov_to_preg (PReg Reg) SideEffectNoResult) +(rule (mov_to_preg dst src) + (SideEffectNoResult.Inst (MInst.MovToPReg dst src))) + +(decl preg_sp () PReg) +(extern constructor preg_sp preg_sp) + +(decl preg_fp () PReg) +(extern constructor preg_fp preg_fp) + +(decl preg_link () PReg) +(extern constructor preg_link preg_link) + +(decl preg_pinned () PReg) +(extern constructor preg_pinned preg_pinned) + +(decl aarch64_sp () Reg) +(rule (aarch64_sp) + (mov_from_preg (preg_sp))) + +(decl aarch64_fp () Reg) +(rule (aarch64_fp) + (mov_from_preg (preg_fp))) + +(decl aarch64_link () Reg) +(rule 1 (aarch64_link) + (if (preserve_frame_pointers)) + (if (sign_return_address_disabled)) + (let ((dst WritableReg (temp_writable_reg $I64)) + ;; Even though LR is not an allocatable register, whether it + ;; contains the return address for the current function is + ;; unknown at this point. For example, this operation may come + ;; immediately after a call, in which case LR would not have a + ;; valid value. That's why we must obtain the return address from + ;; the frame record that corresponds to the current subroutine on + ;; the stack; the presence of the record is guaranteed by the + ;; `preserve_frame_pointers` setting. + (addr AMode (AMode.FPOffset 8)) + (_ Unit (emit (MInst.ULoad64 dst addr (mem_flags_trusted))))) + dst)) + +(rule (aarch64_link) + (if (preserve_frame_pointers)) + ;; Similarly to the rule above, we must load the return address from the + ;; the frame record. Furthermore, we can use LR as a scratch register + ;; because the function will set it to the return address immediately + ;; before returning. + (let ((addr AMode (AMode.FPOffset 8)) + (lr WritableReg (writable_link_reg)) + (_ Unit (emit (MInst.ULoad64 lr addr (mem_flags_trusted)))) + (_ Unit (emit (MInst.Xpaclri)))) + (mov_from_preg (preg_link)))) + +;; Helper for getting the maximum shift amount for a type. + +(decl max_shift (Type) u8) +(rule (max_shift $F64) 63) +(rule (max_shift $F32) 31) + +;; Helper for generating `fcopysign` instruction sequences. + +(decl fcopy_sign (Reg Reg Type) Reg) +(rule 1 (fcopy_sign x y (ty_scalar_float ty)) + (let ((dst WritableReg (temp_writable_reg $F64)) + (tmp Reg (fpu_rri (fpu_op_ri_ushr (ty_bits ty) (max_shift ty)) y)) + (_ Unit (emit (MInst.FpuRRIMod (fpu_op_ri_sli (ty_bits ty) (max_shift ty)) dst x tmp)))) + dst)) +(rule (fcopy_sign x y ty @ (multi_lane _ _)) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (tmp Reg (ushr_vec_imm y (max_shift (lane_type ty)) (vector_size ty))) + (_ Unit (emit (MInst.VecShiftImmMod (VecShiftImmModOp.Sli) dst x tmp (vector_size ty) (max_shift (lane_type ty)))))) + dst)) + +;; Helpers for generating `MInst.FpuToInt` instructions. + +(decl fpu_to_int_nan_check (ScalarSize Reg) Reg) +(rule (fpu_to_int_nan_check size src) + (let ((r ValueRegs + (with_flags (fpu_cmp size src src) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Vs)) + (trap_code_bad_conversion_to_integer)) + src)))) + (value_regs_get r 0))) + +;; Checks that the value is not less than the minimum bound, +;; accepting a boolean (whether the type is signed), input type, +;; output type, and registers containing the source and minimum bound. +(decl fpu_to_int_underflow_check (bool Type Type Reg Reg) Reg) +(rule (fpu_to_int_underflow_check true $F32 (fits_in_16 out_ty) src min) + (let ((r ValueRegs + (with_flags (fpu_cmp (ScalarSize.Size32) src min) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Le)) + (trap_code_integer_overflow)) + src)))) + (value_regs_get r 0))) +(rule (fpu_to_int_underflow_check true $F64 (fits_in_32 out_ty) src min) + (let ((r ValueRegs + (with_flags (fpu_cmp (ScalarSize.Size64) src min) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Le)) + (trap_code_integer_overflow)) + src)))) + (value_regs_get r 0))) +(rule -1 (fpu_to_int_underflow_check true in_ty _out_ty src min) + (let ((r ValueRegs + (with_flags (fpu_cmp (scalar_size in_ty) src min) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Lt)) + (trap_code_integer_overflow)) + src)))) + (value_regs_get r 0))) +(rule (fpu_to_int_underflow_check false in_ty _out_ty src min) + (let ((r ValueRegs + (with_flags (fpu_cmp (scalar_size in_ty) src min) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Le)) + (trap_code_integer_overflow)) + src)))) + (value_regs_get r 0))) + +(decl fpu_to_int_overflow_check (ScalarSize Reg Reg) Reg) +(rule (fpu_to_int_overflow_check size src max) + (let ((r ValueRegs + (with_flags (fpu_cmp size src max) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.TrapIf (cond_br_cond (Cond.Ge)) + (trap_code_integer_overflow)) + src)))) + (value_regs_get r 0))) + +;; Emits the appropriate instruction sequence to convert a +;; floating-point value to an integer, trapping if the value +;; is a NaN or does not fit in the target type. +;; Accepts the specific conversion op, the source register, +;; whether the input is signed, and finally the input and output +;; types. +(decl fpu_to_int_cvt (FpuToIntOp Reg bool Type Type) Reg) +(rule (fpu_to_int_cvt op src signed in_ty out_ty) + (let ((size ScalarSize (scalar_size in_ty)) + (in_bits u8 (ty_bits in_ty)) + (out_bits u8 (ty_bits out_ty)) + (src Reg (fpu_to_int_nan_check size src)) + (min Reg (min_fp_value signed in_bits out_bits)) + (src Reg (fpu_to_int_underflow_check signed in_ty out_ty src min)) + (max Reg (max_fp_value signed in_bits out_bits)) + (src Reg (fpu_to_int_overflow_check size src max))) + (fpu_to_int op src))) + +;; Emits the appropriate instruction sequence to convert a +;; floating-point value to an integer, saturating if the value +;; does not fit in the target type. +;; Accepts the specific conversion op, the source register, +;; whether the input is signed, and finally the output type. +(decl fpu_to_int_cvt_sat (FpuToIntOp Reg bool Type) Reg) +(rule 1 (fpu_to_int_cvt_sat op src _ $I64) + (fpu_to_int op src)) +(rule 1 (fpu_to_int_cvt_sat op src _ $I32) + (fpu_to_int op src)) +(rule (fpu_to_int_cvt_sat op src false (fits_in_16 out_ty)) + (let ((result Reg (fpu_to_int op src)) + (max Reg (imm out_ty (ImmExtend.Zero) (ty_mask out_ty)))) + (with_flags_reg + (cmp (OperandSize.Size32) result max) + (csel (Cond.Hi) max result)))) +(rule (fpu_to_int_cvt_sat op src true (fits_in_16 out_ty)) + (let ((result Reg (fpu_to_int op src)) + (max Reg (signed_max out_ty)) + (min Reg (signed_min out_ty)) + (result Reg (with_flags_reg + (cmp (operand_size out_ty) result max) + (csel (Cond.Gt) max result))) + (result Reg (with_flags_reg + (cmp (operand_size out_ty) result min) + (csel (Cond.Lt) min result)))) + result)) + +(decl signed_min (Type) Reg) +(rule (signed_min $I8) (imm $I8 (ImmExtend.Sign) 0x80)) +(rule (signed_min $I16) (imm $I16 (ImmExtend.Sign) 0x8000)) + +(decl signed_max (Type) Reg) +(rule (signed_max $I8) (imm $I8 (ImmExtend.Sign) 0x7F)) +(rule (signed_max $I16) (imm $I16 (ImmExtend.Sign) 0x7FFF)) + +(decl fpu_to_int (FpuToIntOp Reg) Reg) +(rule (fpu_to_int op src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.FpuToInt op dst src)))) + dst)) + +;; Helper for generating `MInst.IntToFpu` instructions. + +(decl int_to_fpu (IntToFpuOp Reg) Reg) +(rule (int_to_fpu op src) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.IntToFpu op dst src)))) + dst)) + +;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_call (SigRef ExternalName RelocDistance ValueSlice) InstOutput) +(extern constructor gen_call gen_call) + +(decl gen_call_indirect (SigRef Value ValueSlice) InstOutput) +(extern constructor gen_call_indirect gen_call_indirect) + +;; Helpers for pinned register manipulation. + +(decl write_pinned_reg (Reg) SideEffectNoResult) +(rule (write_pinned_reg val) + (mov_to_preg (preg_pinned) val)) + +;; Helpers for stackslot effective address generation. + +(decl compute_stack_addr (StackSlot Offset32) Reg) +(rule (compute_stack_addr stack_slot offset) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (abi_stackslot_addr dst stack_slot offset)))) + dst)) + +;; Helper for emitting instruction sequences to perform a vector comparison. + +(decl vec_cmp_vc (Reg Reg VectorSize) Reg) +(rule (vec_cmp_vc rn rm size) + (let ((dst Reg (vec_rrr (VecALUOp.Fcmeq) rn rn size)) + (tmp Reg (vec_rrr (VecALUOp.Fcmeq) rm rm size)) + (dst Reg (vec_rrr (VecALUOp.And) dst tmp size))) + dst)) + +(decl vec_cmp (Reg Reg Type Cond) Reg) + +;; Floating point Vs / Vc +(rule (vec_cmp rn rm ty (Cond.Vc)) + (if (ty_vector_float ty)) + (vec_cmp_vc rn rm (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Vs)) + (if (ty_vector_float ty)) + (let ((tmp Reg (vec_cmp_vc rn rm (vector_size ty)))) + (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) + +;; 'Less than' operations are implemented by swapping the order of +;; operands and using the 'greater than' instructions. +;; 'Not equal' is implemented with 'equal' and inverting the result. + +;; Floating-point +(rule (vec_cmp rn rm ty (Cond.Eq)) + (if (ty_vector_float ty)) + (vec_rrr (VecALUOp.Fcmeq) rn rm (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Ne)) + (if (ty_vector_float ty)) + (let ((tmp Reg (vec_rrr (VecALUOp.Fcmeq) rn rm (vector_size ty)))) + (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) +(rule (vec_cmp rn rm ty (Cond.Ge)) + (if (ty_vector_float ty)) + (vec_rrr (VecALUOp.Fcmge) rn rm (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Gt)) + (if (ty_vector_float ty)) + (vec_rrr (VecALUOp.Fcmgt) rn rm (vector_size ty))) +;; Floating-point swapped-operands +(rule (vec_cmp rn rm ty (Cond.Mi)) + (if (ty_vector_float ty)) + (vec_rrr (VecALUOp.Fcmgt) rm rn (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Ls)) + (if (ty_vector_float ty)) + (vec_rrr (VecALUOp.Fcmge) rm rn (vector_size ty))) + +;; Integer +(rule 1 (vec_cmp rn rm ty (Cond.Eq)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmeq) rn rm (vector_size ty))) +(rule 1 (vec_cmp rn rm ty (Cond.Ne)) + (if (ty_vector_not_float ty)) + (let ((tmp Reg (vec_rrr (VecALUOp.Cmeq) rn rm (vector_size ty)))) + (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) +(rule 1 (vec_cmp rn rm ty (Cond.Ge)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmge) rn rm (vector_size ty))) +(rule 1 (vec_cmp rn rm ty (Cond.Gt)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmgt) rn rm (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Hs)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmhs) rn rm (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Hi)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmhi) rn rm (vector_size ty))) +;; Integer swapped-operands +(rule (vec_cmp rn rm ty (Cond.Le)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmge) rm rn (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Lt)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmgt) rm rn (vector_size ty))) +(rule 1 (vec_cmp rn rm ty (Cond.Ls)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmhs) rm rn (vector_size ty))) +(rule (vec_cmp rn rm ty (Cond.Lo)) + (if (ty_vector_not_float ty)) + (vec_rrr (VecALUOp.Cmhi) rm rn (vector_size ty))) + +;; Helper for determining if any value in a vector is true. +;; This operation is implemented by using umaxp to create a scalar value, which +;; is then compared against zero. +;; +;; umaxp vn.4s, vm.4s, vm.4s +;; mov xm, vn.d[0] +;; cmp xm, #0 +(decl vanytrue (Reg Type) ProducesFlags) +(rule 1 (vanytrue src (ty_vec128 ty)) + (let ((src Reg (vec_rrr (VecALUOp.Umaxp) src src (VectorSize.Size32x4))) + (src Reg (mov_from_vec src 0 (ScalarSize.Size64)))) + (cmp_imm (OperandSize.Size64) src (u8_into_imm12 0)))) +(rule (vanytrue src ty) + (if (ty_vec64 ty)) + (let ((src Reg (mov_from_vec src 0 (ScalarSize.Size64)))) + (cmp_imm (OperandSize.Size64) src (u8_into_imm12 0)))) + +;;;; TLS Values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper for emitting ElfTlsGetAddr. +(decl elf_tls_get_addr (ExternalName) Reg) +(rule (elf_tls_get_addr name) + (let ((dst WritableReg (temp_writable_reg $I64)) + (tmp WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ElfTlsGetAddr (box_external_name name) dst tmp)))) + dst)) + +(decl macho_tls_get_addr (ExternalName) Reg) +(rule (macho_tls_get_addr name) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MachOTlsGetAddr name dst)))) + dst)) + +;; A tuple of `ProducesFlags` and `IntCC`. +(type FlagsAndCC (enum (FlagsAndCC (flags ProducesFlags) + (cc IntCC)))) + +(spec (flags_and_cc flags cc) + (provide + (= result (concat (extract 67 64 flags) cc))) + (require + (or + (= cc (IntCC.Equal)) + (= cc (IntCC.NotEqual)) + (= cc (IntCC.UnsignedGreaterThanOrEqual)) + (= cc (IntCC.UnsignedGreaterThan)) + (= cc (IntCC.UnsignedLessThanOrEqual)) + (= cc (IntCC.UnsignedLessThan)) + (= cc (IntCC.SignedGreaterThanOrEqual)) + (= cc (IntCC.SignedGreaterThan)) + (= cc (IntCC.SignedLessThanOrEqual)) + (= cc (IntCC.SignedLessThan))))) +;; Helper constructor for `FlagsAndCC`. +(decl flags_and_cc (ProducesFlags IntCC) FlagsAndCC) +(rule (flags_and_cc flags cc) (FlagsAndCC.FlagsAndCC flags cc)) + +(spec (flags_and_cc_to_bool a) + (provide + (= result + (switch (extract 7 0 a) + ((IntCC.Equal) (if (= (extract 10 10 a) #b1) #x01 #x00)) + ((IntCC.NotEqual) (if (= (extract 10 10 a) #b0) #x01 #x00)) + ((IntCC.SignedGreaterThan) (if (and (= (extract 10 10 a) #b0) (= (extract 11 11 a) (extract 8 8 a))) #x01 #x00)) + ((IntCC.SignedGreaterThanOrEqual) (if (= (extract 11 11 a) (extract 8 8 a)) #x01 #x00)) + ((IntCC.SignedLessThan) (if (not (= (extract 11 11 a) (extract 8 8 a))) #x01 #x00)) + ((IntCC.SignedLessThanOrEqual) (if (or (= (extract 10 10 a) #b1) (not (= (extract 11 11 a) (extract 8 8 a)))) #x01 #x00)) + ((IntCC.UnsignedGreaterThan) (if (and (= (extract 9 9 a) #b1) (= (extract 10 10 a) #b0)) #x01 #x00)) + ((IntCC.UnsignedGreaterThanOrEqual) (if (= (extract 9 9 a) #b1) #x01 #x00)) + ((IntCC.UnsignedLessThan) (if (= (extract 9 9 a) #b0) #x01 #x00)) + ((IntCC.UnsignedLessThanOrEqual) (if (or (= (extract 9 9 a) #b0) (= (extract 10 10 a) #b1)) #x01 #x00))))) + (require + (or + (= (extract 7 0 a) (IntCC.Equal)) + (= (extract 7 0 a) (IntCC.NotEqual)) + (= (extract 7 0 a) (IntCC.UnsignedGreaterThanOrEqual)) + (= (extract 7 0 a) (IntCC.UnsignedGreaterThan)) + (= (extract 7 0 a) (IntCC.UnsignedLessThanOrEqual)) + (= (extract 7 0 a) (IntCC.UnsignedLessThan)) + (= (extract 7 0 a) (IntCC.SignedGreaterThanOrEqual)) + (= (extract 7 0 a) (IntCC.SignedGreaterThan)) + (= (extract 7 0 a) (IntCC.SignedLessThanOrEqual)) + (= (extract 7 0 a) (IntCC.SignedLessThan))))) +;; Materialize a `FlagsAndCC` into a boolean `ValueRegs`. +(decl flags_and_cc_to_bool (FlagsAndCC) ValueRegs) +(rule (flags_and_cc_to_bool (FlagsAndCC.FlagsAndCC flags cc)) + (with_flags flags (materialize_bool_result (cond_code cc)))) + +;; Get the `ProducesFlags` out of a `FlagsAndCC`. +(decl flags_and_cc_flags (FlagsAndCC) ProducesFlags) +(rule (flags_and_cc_flags (FlagsAndCC.FlagsAndCC flags _cc)) flags) + +;; Get the `IntCC` out of a `FlagsAndCC`. +(decl flags_and_cc_cc (FlagsAndCC) IntCC) +(rule (flags_and_cc_cc (FlagsAndCC.FlagsAndCC _flags cc)) cc) + +;; Helpers for lowering `icmp` sequences. +;; `lower_icmp` contains shared functionality for lowering `icmp` +;; sequences, which `lower_icmp_into_{reg,flags}` extend from. +(spec (lower_icmp c x y in_ty) + (provide + (= result + (concat + (extract 67 64 + (if (or (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))) + (if (<= in_ty 32) + (subs 32 (sign_ext 64 x) (sign_ext 64 y)) + (subs 64 (sign_ext 64 x) (sign_ext 64 y))) + (if (<= in_ty 32) + (subs 32 (zero_ext 64 x) (zero_ext 64 y)) + (subs 64 (zero_ext 64 x) (zero_ext 64 y))))) + c))) + (require + (or + (= c (IntCC.Equal)) + (= c (IntCC.NotEqual)) + (= c (IntCC.UnsignedGreaterThanOrEqual)) + (= c (IntCC.UnsignedGreaterThan)) + (= c (IntCC.UnsignedLessThanOrEqual)) + (= c (IntCC.UnsignedLessThan)) + (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))) + (or (= in_ty 8) + (= in_ty 16) + (= in_ty 32) + (= in_ty 64)) + (= in_ty (widthof x)) + (= in_ty (widthof y)))) +(instantiate lower_icmp + ((args (bv 8) (bv 8) (bv 8) Int) (ret (bv 12)) (canon (bv 8))) + ((args (bv 8) (bv 16) (bv 16) Int) (ret (bv 12)) (canon (bv 16))) + ((args (bv 8) (bv 32) (bv 32) Int) (ret (bv 12)) (canon (bv 32))) + ((args (bv 8) (bv 64) (bv 64) Int) (ret (bv 12)) (canon (bv 64))) +) +(decl lower_icmp (IntCC Value Value Type) FlagsAndCC) + +(spec (lower_icmp_into_reg c x y in_ty out_ty) + (provide + (= result + (switch c + ((IntCC.Equal) (if (= x y) #x01 #x00)) + ((IntCC.NotEqual) (if (not (= x y)) #x01 #x00)) + ((IntCC.SignedGreaterThan) (if (bvsgt x y) #x01 #x00)) + ((IntCC.SignedGreaterThanOrEqual) (if (bvsge x y) #x01 #x00)) + ((IntCC.SignedLessThan) (if (bvslt x y) #x01 #x00)) + ((IntCC.SignedLessThanOrEqual) (if (bvsle x y) #x01 #x00)) + ((IntCC.UnsignedGreaterThan) (if (bvugt x y) #x01 #x00)) + ((IntCC.UnsignedGreaterThanOrEqual) (if (bvuge x y) #x01 #x00)) + ((IntCC.UnsignedLessThan) (if (bvult x y) #x01 #x00)) + ((IntCC.UnsignedLessThanOrEqual) (if (bvule x y) #x01 #x00))))) + (require + (or + (= c (IntCC.Equal)) + (= c (IntCC.NotEqual)) + (= c (IntCC.UnsignedGreaterThanOrEqual)) + (= c (IntCC.UnsignedGreaterThan)) + (= c (IntCC.UnsignedLessThanOrEqual)) + (= c (IntCC.UnsignedLessThan)) + (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))) + (or (= in_ty 8) + (= in_ty 16) + (= in_ty 32) + (= in_ty 64)) + (= in_ty (widthof x)) + (= in_ty (widthof y)) + (= out_ty 8))) +(instantiate lower_icmp_into_reg + ((args (bv 8) (bv 8) (bv 8) Int Int) (ret (bv 8)) (canon (bv 8))) + ((args (bv 8) (bv 16) (bv 16) Int Int) (ret (bv 8)) (canon (bv 16))) + ((args (bv 8) (bv 32) (bv 32) Int Int) (ret (bv 8)) (canon (bv 32))) + ((args (bv 8) (bv 64) (bv 64) Int Int) (ret (bv 8)) (canon (bv 64))) +) +(decl lower_icmp_into_reg (IntCC Value Value Type Type) ValueRegs) +(decl lower_icmp_into_flags (IntCC Value Value Type) FlagsAndCC) + +(spec (lower_icmp_const c x y in_ty) + (provide + (= result + (concat (extract 67 64 + (if (or (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))) + (if (<= in_ty 32) + (subs 32 (sign_ext 64 x) y) + (subs 64 (sign_ext 64 x) y)) + (if (<= in_ty 32) + (subs 32 (zero_ext 64 x) y) + (subs 64 (zero_ext 64 x) y)))) + c))) + (require + (or + (= c (IntCC.Equal)) + (= c (IntCC.NotEqual)) + (= c (IntCC.UnsignedGreaterThanOrEqual)) + (= c (IntCC.UnsignedGreaterThan)) + (= c (IntCC.UnsignedLessThanOrEqual)) + (= c (IntCC.UnsignedLessThan)) + (= c (IntCC.SignedGreaterThanOrEqual)) + (= c (IntCC.SignedGreaterThan)) + (= c (IntCC.SignedLessThanOrEqual)) + (= c (IntCC.SignedLessThan))) + (or (= in_ty 32) (= in_ty 64)) + (= in_ty (widthof x)))) +(instantiate lower_icmp_const + ((args (bv 8) (bv 8) (bv 64) Int) (ret (bv 12)) (canon (bv 8))) + ((args (bv 8) (bv 16) (bv 64) Int) (ret (bv 12)) (canon (bv 16))) + ((args (bv 8) (bv 32) (bv 64) Int) (ret (bv 12)) (canon (bv 32))) + ((args (bv 8) (bv 64) (bv 64) Int) (ret (bv 12)) (canon (bv 64))) +) +(decl lower_icmp_const (IntCC Value u64 Type) FlagsAndCC) +;; For most cases, `lower_icmp_into_flags` is the same as `lower_icmp`, +;; except for some I128 cases (see below). +(rule -1 (lower_icmp_into_flags cond x y ty) (lower_icmp cond x y ty)) + +;; Vectors. +;; `icmp` into flags for vectors is invalid. +(rule 1 (lower_icmp_into_reg cond x y in_ty @ (multi_lane _ _) _out_ty) + (let ((cond Cond (cond_code cond)) + (rn Reg (put_in_reg x)) + (rm Reg (put_in_reg y))) + (vec_cmp rn rm in_ty cond))) + +;; Determines the appropriate extend op given the value type and the given ArgumentExtension. +(spec (lower_extend_op ty b) + (provide + (= result + (switch ty + (8 (switch b ((ArgumentExtension.Sext) (ExtendOp.SXTB)) + ((ArgumentExtension.Uext) (ExtendOp.UXTB)))) + (16 (switch b ((ArgumentExtension.Sext) (ExtendOp.SXTH)) + ((ArgumentExtension.Uext) (ExtendOp.UXTH))))))) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) +(decl lower_extend_op (Type ArgumentExtension) ExtendOp) +(rule (lower_extend_op $I8 (ArgumentExtension.Sext)) (ExtendOp.SXTB)) +(rule (lower_extend_op $I16 (ArgumentExtension.Sext)) (ExtendOp.SXTH)) +(rule (lower_extend_op $I8 (ArgumentExtension.Uext)) (ExtendOp.UXTB)) +(rule (lower_extend_op $I16 (ArgumentExtension.Uext)) (ExtendOp.UXTH)) + +;; Integers <= 64-bits. +(rule lower_icmp_into_reg_8_16_32_64 -2 (lower_icmp_into_reg cond rn rm in_ty out_ty) + (if (ty_int_ref_scalar_64 in_ty)) + (let ((cc Cond (cond_code cond))) + (flags_and_cc_to_bool (lower_icmp cond rn rm in_ty)))) + +(rule lower_icmp_8_16_signed 1 (lower_icmp cond rn rm (fits_in_16 ty)) + (if (signed_cond_code cond)) + (let ((rn Reg (put_in_reg_sext32 rn))) + (flags_and_cc (cmp_extend (operand_size ty) rn rm (lower_extend_op ty (ArgumentExtension.Sext))) cond))) +(rule lower_icmp_8_16_unsigned_imm -1 (lower_icmp cond rn (imm12_from_value rm) (fits_in_16 ty)) + (let ((rn Reg (put_in_reg_zext32 rn))) + (flags_and_cc (cmp_imm (operand_size ty) rn rm) cond))) +(rule lower_icmp_8_16_unsigned -2 (lower_icmp cond rn rm (fits_in_16 ty)) + (let ((rn Reg (put_in_reg_zext32 rn))) + (flags_and_cc (cmp_extend (operand_size ty) rn rm (lower_extend_op ty (ArgumentExtension.Uext))) cond))) +(rule lower_icmp_32_64_const -3 (lower_icmp cond rn (u64_from_iconst c) ty) + (if (ty_int_ref_scalar_64 ty)) + (lower_icmp_const cond rn c ty)) +(rule lower_icmp_32_64 -4 (lower_icmp cond rn rm ty) + (if (ty_int_ref_scalar_64 ty)) + (flags_and_cc (cmp (operand_size ty) rn rm) cond)) + +;; We get better encodings when testing against an immediate that's even instead +;; of odd, so rewrite comparisons to use even immediates: +;; +;; A >= B + 1 +;; ==> A - 1 >= B +;; ==> A > B +(rule lower_icmp_const_32_64_ugte (lower_icmp_const (IntCC.UnsignedGreaterThanOrEqual) a b ty) + (if (ty_int_ref_scalar_64 ty)) + (if-let true (u64_is_odd b)) + (if-let (imm12_from_u64 imm) (u64_sub b 1)) + (flags_and_cc (cmp_imm (operand_size ty) a imm) (IntCC.UnsignedGreaterThan))) + +(rule lower_icmp_const_32_64_sgte (lower_icmp_const (IntCC.SignedGreaterThanOrEqual) a b ty) + (if (ty_int_ref_scalar_64 ty)) + (if-let true (u64_is_odd b)) + (if-let (imm12_from_u64 imm) (u64_sub b 1)) + (flags_and_cc (cmp_imm (operand_size ty) a imm) (IntCC.SignedGreaterThan))) + +(rule lower_icmp_const_32_64_imm -1 (lower_icmp_const cond rn (imm12_from_u64 c) ty) + (if (ty_int_ref_scalar_64 ty)) + (flags_and_cc (cmp_imm (operand_size ty) rn c) cond)) +(rule lower_icmp_const_32_64 -2 (lower_icmp_const cond rn c ty) + (if (ty_int_ref_scalar_64 ty)) + (flags_and_cc (cmp (operand_size ty) rn (imm ty (ImmExtend.Zero) c)) cond)) + + +;; 128-bit integers. +(rule (lower_icmp_into_reg cond @ (IntCC.Equal) rn rm $I128 $I8) + (let ((cc Cond (cond_code cond))) + (flags_and_cc_to_bool + (lower_icmp cond rn rm $I128)))) +(rule (lower_icmp_into_reg cond @ (IntCC.NotEqual) rn rm $I128 $I8) + (let ((cc Cond (cond_code cond))) + (flags_and_cc_to_bool + (lower_icmp cond rn rm $I128)))) + +;; cmp lhs_lo, rhs_lo +;; ccmp lhs_hi, rhs_hi, #0, eq +(decl lower_icmp_i128_eq_ne (Value Value) ProducesFlags) +(rule (lower_icmp_i128_eq_ne lhs rhs) + (let ((lhs ValueRegs (put_in_regs lhs)) + (rhs ValueRegs (put_in_regs rhs)) + (lhs_lo Reg (value_regs_get lhs 0)) + (lhs_hi Reg (value_regs_get lhs 1)) + (rhs_lo Reg (value_regs_get rhs 0)) + (rhs_hi Reg (value_regs_get rhs 1)) + (cmp_inst ProducesFlags (cmp (OperandSize.Size64) lhs_lo rhs_lo))) + (ccmp (OperandSize.Size64) lhs_hi rhs_hi + (nzcv false false false false) (Cond.Eq) cmp_inst))) + +(rule (lower_icmp (IntCC.Equal) lhs rhs $I128) + (flags_and_cc (lower_icmp_i128_eq_ne lhs rhs) (IntCC.Equal))) +(rule (lower_icmp (IntCC.NotEqual) lhs rhs $I128) + (flags_and_cc (lower_icmp_i128_eq_ne lhs rhs) (IntCC.NotEqual))) + +;; cmp lhs_lo, rhs_lo +;; cset tmp1, unsigned_cond +;; cmp lhs_hi, rhs_hi +;; cset tmp2, cond +;; csel dst, tmp1, tmp2, eq +(rule -1 (lower_icmp_into_reg cond lhs rhs $I128 $I8) + (let ((unsigned_cond Cond (cond_code (intcc_unsigned cond))) + (cond Cond (cond_code cond)) + (lhs ValueRegs (put_in_regs lhs)) + (rhs ValueRegs (put_in_regs rhs)) + (lhs_lo Reg (value_regs_get lhs 0)) + (lhs_hi Reg (value_regs_get lhs 1)) + (rhs_lo Reg (value_regs_get rhs 0)) + (rhs_hi Reg (value_regs_get rhs 1)) + (tmp1 Reg (with_flags_reg (cmp (OperandSize.Size64) lhs_lo rhs_lo) + (materialize_bool_result unsigned_cond)))) + (with_flags (cmp (OperandSize.Size64) lhs_hi rhs_hi) + (lower_icmp_i128_consumer cond tmp1)))) + +(decl lower_icmp_i128_consumer (Cond Reg) ConsumesFlags) +(rule (lower_icmp_i128_consumer cond tmp1) + (let ((tmp2 WritableReg (temp_writable_reg $I64)) + (dst WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + (MInst.CSet tmp2 cond) + (MInst.CSel dst (Cond.Eq) tmp1 tmp2) + (value_reg dst)))) + +(decl lower_bmask (Type Type ValueRegs) ValueRegs) + + +;; For conversions that exactly fit a register, we can use csetm. +;; +;; cmp val, #0 +;; csetm res, ne +(rule 0 + (lower_bmask (fits_in_64 _) (ty_32_or_64 in_ty) val) + (with_flags_reg + (cmp_imm (operand_size in_ty) (value_regs_get val 0) (u8_into_imm12 0)) + (csetm (Cond.Ne)))) + +;; For conversions from a 128-bit value into a 64-bit or smaller one, we or the +;; two registers of the 128-bit value together, and then recurse with the +;; combined value as a 64-bit test. +;; +;; orr val, lo, hi +;; cmp val, #0 +;; csetm res, ne +(rule 1 + (lower_bmask (fits_in_64 ty) $I128 val) + (let ((lo Reg (value_regs_get val 0)) + (hi Reg (value_regs_get val 1)) + (combined Reg (orr $I64 lo hi))) + (lower_bmask ty $I64 (value_reg combined)))) + +;; For converting from any type into i128, duplicate the result of +;; converting to i64. +(rule 2 + (lower_bmask $I128 in_ty val) + (let ((res ValueRegs (lower_bmask $I64 in_ty val)) + (res Reg (value_regs_get res 0))) + (value_regs res res))) + +;; For conversions smaller than a register, we need to mask off the high bits, and then +;; we can recurse into the general case. +;; +;; and tmp, val, #ty_mask +;; cmp tmp, #0 +;; csetm res, ne +(rule 3 + (lower_bmask out_ty (fits_in_16 in_ty) val) + ; This if-let can't fail due to ty_mask always producing 8/16 consecutive 1s. + (if-let mask_bits (imm_logic_from_u64 $I32 (ty_mask in_ty))) + (let ((masked Reg (and_imm $I32 (value_regs_get val 0) mask_bits))) + (lower_bmask out_ty $I32 masked))) + +;; Exceptional `lower_icmp_into_flags` rules. +;; We need to guarantee that the flags for `cond` are correct, so we +;; compare `dst` with 1. +(rule (lower_icmp_into_flags cond @ (IntCC.SignedGreaterThanOrEqual) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0)) + (tmp Reg (imm $I64 (ImmExtend.Sign) 1))) ;; mov tmp, #1 + (flags_and_cc (cmp (OperandSize.Size64) dst tmp) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedGreaterThanOrEqual) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0)) + (tmp Reg (imm $I64 (ImmExtend.Zero) 1))) + (flags_and_cc (cmp (OperandSize.Size64) dst tmp) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.SignedLessThanOrEqual) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0)) + (tmp Reg (imm $I64 (ImmExtend.Sign) 1))) + (flags_and_cc (cmp (OperandSize.Size64) tmp dst) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedLessThanOrEqual) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0)) + (tmp Reg (imm $I64 (ImmExtend.Zero) 1))) + (flags_and_cc (cmp (OperandSize.Size64) tmp dst) cond))) +;; For strict comparisons, we compare with 0. +(rule (lower_icmp_into_flags cond @ (IntCC.SignedGreaterThan) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0))) + (flags_and_cc (cmp (OperandSize.Size64) dst (zero_reg)) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedGreaterThan) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0))) + (flags_and_cc (cmp (OperandSize.Size64) dst (zero_reg)) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.SignedLessThan) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0))) + (flags_and_cc (cmp (OperandSize.Size64) (zero_reg) dst) cond))) +(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedLessThan) lhs rhs $I128) + (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) + (dst Reg (value_regs_get dst 0))) + (flags_and_cc (cmp (OperandSize.Size64) (zero_reg) dst) cond))) + +;; Helpers for generating select instruction sequences. +(decl lower_select (ProducesFlags Cond Type Value Value) ValueRegs) +(rule 2 (lower_select flags cond (ty_scalar_float (fits_in_64 ty)) rn rm) + (with_flags flags (fpu_csel ty cond rn rm))) +(rule 4 (lower_select flags cond $F128 rn rm) + (with_flags flags (vec_csel cond rn rm))) +(rule 3 (lower_select flags cond (ty_vec128 ty) rn rm) + (with_flags flags (vec_csel cond rn rm))) +(rule (lower_select flags cond ty rn rm) + (if (ty_vec64 ty)) + (with_flags flags (fpu_csel $F64 cond rn rm))) +(rule 4 (lower_select flags cond $I128 rn rm) + (let ((dst_lo WritableReg (temp_writable_reg $I64)) + (dst_hi WritableReg (temp_writable_reg $I64)) + (rn ValueRegs (put_in_regs rn)) + (rm ValueRegs (put_in_regs rm)) + (rn_lo Reg (value_regs_get rn 0)) + (rn_hi Reg (value_regs_get rn 1)) + (rm_lo Reg (value_regs_get rm 0)) + (rm_hi Reg (value_regs_get rm 1))) + (with_flags flags + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + (MInst.CSel dst_lo cond rn_lo rm_lo) + (MInst.CSel dst_hi cond rn_hi rm_hi) + (value_regs dst_lo dst_hi))))) +(rule 1 (lower_select flags cond ty rn rm) + (if (ty_int_ref_scalar_64 ty)) + (with_flags flags (csel cond rn rm))) + +;; Helper for emitting `MInst.Jump` instructions. +(decl aarch64_jump (BranchTarget) SideEffectNoResult) +(rule (aarch64_jump target) + (SideEffectNoResult.Inst (MInst.Jump target))) + +;; Helper for emitting `MInst.JTSequence` instructions. +;; Emit the compound instruction that does: +;; +;; b.hs default +;; csel rB, xzr, rIndex, hs +;; csdb +;; adr rA, jt +;; ldrsw rB, [rA, rB, uxtw #2] +;; add rA, rA, rB +;; br rA +;; [jt entries] +;; +;; This must be *one* instruction in the vcode because +;; we cannot allow regalloc to insert any spills/fills +;; in the middle of the sequence; otherwise, the ADR's +;; PC-rel offset to the jumptable would be incorrect. +;; (The alternative is to introduce a relocation pass +;; for inlined jumptables, which is much worse, IMHO.) +(decl jt_sequence (Reg MachLabel BoxVecMachLabel) ConsumesFlags) +(rule (jt_sequence ridx default targets) + (let ((rtmp1 WritableReg (temp_writable_reg $I64)) + (rtmp2 WritableReg (temp_writable_reg $I64))) + (ConsumesFlags.ConsumesFlagsSideEffect + (MInst.JTSequence default targets ridx rtmp1 rtmp2)))) + +;; Helper for emitting `MInst.CondBr` instructions. +(decl cond_br (BranchTarget BranchTarget CondBrKind) ConsumesFlags) +(rule (cond_br taken not_taken kind) + (ConsumesFlags.ConsumesFlagsSideEffect + (MInst.CondBr taken not_taken kind))) + +;; Helper for emitting `MInst.TestBitAndBranch` instructions. +(decl test_branch (TestBitAndBranchKind BranchTarget BranchTarget Reg u8) SideEffectNoResult) +(rule (test_branch kind taken not_taken rn bit) + (SideEffectNoResult.Inst (MInst.TestBitAndBranch kind taken not_taken rn bit))) + +;; Helper for emitting `tbnz` instructions. +(decl tbnz (BranchTarget BranchTarget Reg u8) SideEffectNoResult) +(rule (tbnz taken not_taken rn bit) + (test_branch (TestBitAndBranchKind.NZ) taken not_taken rn bit)) + +;; Helper for emitting `tbz` instructions. +(decl tbz (BranchTarget BranchTarget Reg u8) SideEffectNoResult) +(rule (tbz taken not_taken rn bit) + (test_branch (TestBitAndBranchKind.Z) taken not_taken rn bit)) + +;; Helper for emitting `MInst.MovToNZCV` instructions. +(decl mov_to_nzcv (Reg) ProducesFlags) +(rule (mov_to_nzcv rn) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.MovToNZCV rn))) + +;; Helper for emitting `MInst.EmitIsland` instructions. +(decl emit_island (CodeOffset) SideEffectNoResult) +(rule (emit_island needed_space) + (SideEffectNoResult.Inst + (MInst.EmitIsland needed_space))) + +;; Helper for emitting `br_table` sequences. +(decl br_table_impl (u64 Reg MachLabel BoxVecMachLabel) Unit) +(rule (br_table_impl (imm12_from_u64 jt_size) ridx default targets) + (emit_side_effect (with_flags_side_effect + (cmp_imm (OperandSize.Size32) ridx jt_size) + (jt_sequence ridx default targets)))) +(rule -1 (br_table_impl jt_size ridx default targets) + (let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size))) + (emit_side_effect (with_flags_side_effect + (cmp (OperandSize.Size32) ridx jt_size) + (jt_sequence ridx default targets))))) + +;; Helper for emitting the `uzp1` instruction +(decl vec_uzp1 (Reg Reg VectorSize) Reg) +(rule (vec_uzp1 rn rm size) (vec_rrr (VecALUOp.Uzp1) rn rm size)) + +;; Helper for emitting the `uzp2` instruction +(decl vec_uzp2 (Reg Reg VectorSize) Reg) +(rule (vec_uzp2 rn rm size) (vec_rrr (VecALUOp.Uzp2) rn rm size)) + +;; Helper for emitting the `zip1` instruction +(decl vec_zip1 (Reg Reg VectorSize) Reg) +(rule (vec_zip1 rn rm size) (vec_rrr (VecALUOp.Zip1) rn rm size)) + +;; Helper for emitting the `zip2` instruction +(decl vec_zip2 (Reg Reg VectorSize) Reg) +(rule (vec_zip2 rn rm size) (vec_rrr (VecALUOp.Zip2) rn rm size)) + +;; Helper for emitting the `trn1` instruction +(decl vec_trn1 (Reg Reg VectorSize) Reg) +(rule (vec_trn1 rn rm size) (vec_rrr (VecALUOp.Trn1) rn rm size)) + +;; Helper for emitting the `trn2` instruction +(decl vec_trn2 (Reg Reg VectorSize) Reg) +(rule (vec_trn2 rn rm size) (vec_rrr (VecALUOp.Trn2) rn rm size)) + +;; Helper for creating a zero value `ASIMDMovModImm` immediate. +(decl asimd_mov_mod_imm_zero (ScalarSize) ASIMDMovModImm) +(extern constructor asimd_mov_mod_imm_zero asimd_mov_mod_imm_zero) + +;; Helper for fallibly creating an `ASIMDMovModImm` immediate from its parts. +(decl pure partial asimd_mov_mod_imm_from_u64 (u64 ScalarSize) ASIMDMovModImm) +(extern constructor asimd_mov_mod_imm_from_u64 asimd_mov_mod_imm_from_u64) + +;; Helper for fallibly creating an `ASIMDFPModImm` immediate from its parts. +(decl pure partial asimd_fp_mod_imm_from_u64 (u64 ScalarSize) ASIMDFPModImm) +(extern constructor asimd_fp_mod_imm_from_u64 asimd_fp_mod_imm_from_u64) + +;; Helper for creating a `VecDupFPImm` instruction +(decl vec_dup_fp_imm (ASIMDFPModImm VectorSize) Reg) +(rule (vec_dup_fp_imm imm size) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.VecDupFPImm dst imm size)))) + dst)) + +;; Helper for creating a `FpuLoad64` instruction +(decl fpu_load64 (AMode MemFlags) Reg) +(rule (fpu_load64 amode flags) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.FpuLoad64 dst amode flags)))) + dst)) + +;; Helper for creating a `FpuLoad128` instruction +(decl fpu_load128 (AMode MemFlags) Reg) +(rule (fpu_load128 amode flags) + (let ((dst WritableReg (temp_writable_reg $I8X16)) + (_ Unit (emit (MInst.FpuLoad128 dst amode flags)))) + dst)) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/args.rs b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/args.rs new file mode 100644 index 00000000000000..5ad617ca2bed48 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/args.rs @@ -0,0 +1,711 @@ +//! AArch64 ISA definitions: instruction arguments. + +use crate::ir::types::*; +use crate::isa::aarch64::inst::*; + +//============================================================================= +// Instruction sub-components: shift and extend descriptors + +/// A shift operator for a register or immediate. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum ShiftOp { + /// Logical shift left. + LSL = 0b00, + /// Logical shift right. + LSR = 0b01, + /// Arithmetic shift right. + ASR = 0b10, + /// Rotate right. + ROR = 0b11, +} + +impl ShiftOp { + /// Get the encoding of this shift op. + pub fn bits(self) -> u8 { + self as u8 + } +} + +/// A shift operator amount. +#[derive(Clone, Copy, Debug)] +pub struct ShiftOpShiftImm(u8); + +impl ShiftOpShiftImm { + /// Maximum shift for shifted-register operands. + pub const MAX_SHIFT: u64 = 63; + + /// Create a new shiftop shift amount, if possible. + pub fn maybe_from_shift(shift: u64) -> Option { + if shift <= Self::MAX_SHIFT { + Some(ShiftOpShiftImm(shift as u8)) + } else { + None + } + } + + /// Return the shift amount. + pub fn value(self) -> u8 { + self.0 + } + + /// Mask down to a given number of bits. + pub fn mask(self, bits: u8) -> ShiftOpShiftImm { + ShiftOpShiftImm(self.0 & (bits - 1)) + } +} + +/// A shift operator with an amount, guaranteed to be within range. +#[derive(Copy, Clone, Debug)] +pub struct ShiftOpAndAmt { + /// The shift operator. + op: ShiftOp, + /// The shift operator amount. + shift: ShiftOpShiftImm, +} + +impl ShiftOpAndAmt { + /// Create a new shift operator with an amount. + pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt { + ShiftOpAndAmt { op, shift } + } + + /// Get the shift op. + pub fn op(&self) -> ShiftOp { + self.op + } + + /// Get the shift amount. + pub fn amt(&self) -> ShiftOpShiftImm { + self.shift + } +} + +/// An extend operator for a register. +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum ExtendOp { + /// Unsigned extend byte. + UXTB = 0b000, + /// Unsigned extend halfword. + UXTH = 0b001, + /// Unsigned extend word. + UXTW = 0b010, + /// Unsigned extend doubleword. + UXTX = 0b011, + /// Signed extend byte. + SXTB = 0b100, + /// Signed extend halfword. + SXTH = 0b101, + /// Signed extend word. + SXTW = 0b110, + /// Signed extend doubleword. + SXTX = 0b111, +} + +impl ExtendOp { + /// Encoding of this op. + pub fn bits(self) -> u8 { + self as u8 + } +} + +//============================================================================= +// Instruction sub-components (memory addresses): definitions + +/// A reference to some memory address. +#[derive(Clone, Debug)] +pub enum MemLabel { + /// An address in the code, a constant pool or jumptable, with relative + /// offset from this instruction. This form must be used at emission time; + /// see `memlabel_finalize()` for how other forms are lowered to this one. + PCRel(i32), + /// An address that refers to a label within a `MachBuffer`, for example a + /// constant that lives in the pool at the end of the function. + Mach(MachLabel), +} + +impl AMode { + /// Memory reference using an address in a register. + pub fn reg(reg: Reg) -> AMode { + // Use UnsignedOffset rather than Unscaled to use ldr rather than ldur. + // This also does not use PostIndexed / PreIndexed as they update the register. + AMode::UnsignedOffset { + rn: reg, + uimm12: UImm12Scaled::zero(I64), + } + } + + /// Memory reference using `reg1 + sizeof(ty) * reg2` as an address, with `reg2` sign- or + /// zero-extended as per `op`. + pub fn reg_plus_reg_scaled_extended(reg1: Reg, reg2: Reg, op: ExtendOp) -> AMode { + AMode::RegScaledExtended { + rn: reg1, + rm: reg2, + extendop: op, + } + } +} + +pub use crate::isa::aarch64::lower::isle::generated_code::PairAMode; + +//============================================================================= +// Instruction sub-components (conditions, branches and branch targets): +// definitions + +/// Condition for conditional branches. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Cond { + /// Equal. + Eq = 0, + /// Not equal. + Ne = 1, + /// Unsigned greater than or equal to. + Hs = 2, + /// Unsigned less than. + Lo = 3, + /// Minus, negative. + Mi = 4, + /// Positive or zero. + Pl = 5, + /// Signed overflow. + Vs = 6, + /// No signed overflow. + Vc = 7, + /// Unsigned greater than. + Hi = 8, + /// Unsigned less than or equal to. + Ls = 9, + /// Signed greater or equal to. + Ge = 10, + /// Signed less than. + Lt = 11, + /// Signed greater than. + Gt = 12, + /// Signed less than or equal. + Le = 13, + /// Always executed. + Al = 14, + /// Always executed. + Nv = 15, +} + +impl Cond { + /// Return the inverted condition. + pub fn invert(self) -> Cond { + match self { + Cond::Eq => Cond::Ne, + Cond::Ne => Cond::Eq, + + Cond::Hs => Cond::Lo, + Cond::Lo => Cond::Hs, + + Cond::Mi => Cond::Pl, + Cond::Pl => Cond::Mi, + + Cond::Vs => Cond::Vc, + Cond::Vc => Cond::Vs, + + Cond::Hi => Cond::Ls, + Cond::Ls => Cond::Hi, + + Cond::Ge => Cond::Lt, + Cond::Lt => Cond::Ge, + + Cond::Gt => Cond::Le, + Cond::Le => Cond::Gt, + + Cond::Al => Cond::Nv, + Cond::Nv => Cond::Al, + } + } + + /// Return the machine encoding of this condition. + pub fn bits(self) -> u32 { + self as u32 + } +} + +/// The kind of conditional branch: the common-case-optimized "reg-is-zero" / +/// "reg-is-nonzero" variants, or the generic one that tests the machine +/// condition codes. +#[derive(Clone, Copy, Debug)] +pub enum CondBrKind { + /// Condition: given register is zero. + Zero(Reg, OperandSize), + /// Condition: given register is nonzero. + NotZero(Reg, OperandSize), + /// Condition: the given condition-code test is true. + Cond(Cond), +} + +impl CondBrKind { + /// Return the inverted branch condition. + pub fn invert(self) -> CondBrKind { + match self { + CondBrKind::Zero(reg, size) => CondBrKind::NotZero(reg, size), + CondBrKind::NotZero(reg, size) => CondBrKind::Zero(reg, size), + CondBrKind::Cond(c) => CondBrKind::Cond(c.invert()), + } + } +} + +/// A branch target. Either unresolved (basic-block index) or resolved (offset +/// from end of current instruction). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BranchTarget { + /// An unresolved reference to a Label, as passed into + /// `lower_branch_group()`. + Label(MachLabel), + /// A fixed PC offset. + ResolvedOffset(i32), +} + +impl BranchTarget { + /// Return the target's label, if it is a label-based target. + pub fn as_label(self) -> Option { + match self { + BranchTarget::Label(l) => Some(l), + _ => None, + } + } + + /// Return the target's offset, if specified, or zero if label-based. + pub fn as_offset14_or_zero(self) -> u32 { + self.as_offset_bounded(14) + } + + /// Return the target's offset, if specified, or zero if label-based. + pub fn as_offset19_or_zero(self) -> u32 { + self.as_offset_bounded(19) + } + + /// Return the target's offset, if specified, or zero if label-based. + pub fn as_offset26_or_zero(self) -> u32 { + self.as_offset_bounded(26) + } + + fn as_offset_bounded(self, bits: u32) -> u32 { + let off = match self { + BranchTarget::ResolvedOffset(off) => off >> 2, + _ => 0, + }; + let hi = (1 << (bits - 1)) - 1; + let lo = -(1 << bits - 1); + assert!(off <= hi); + assert!(off >= lo); + (off as u32) & ((1 << bits) - 1) + } +} + +impl PrettyPrint for ShiftOpAndAmt { + fn pretty_print(&self, _: u8) -> String { + format!("{:?} {}", self.op(), self.amt().value()) + } +} + +impl PrettyPrint for ExtendOp { + fn pretty_print(&self, _: u8) -> String { + format!("{self:?}") + } +} + +impl PrettyPrint for MemLabel { + fn pretty_print(&self, _: u8) -> String { + match self { + MemLabel::PCRel(off) => format!("pc+{off}"), + MemLabel::Mach(off) => format!("label({})", off.get()), + } + } +} + +fn shift_for_type(size_bytes: u8) -> usize { + match size_bytes { + 1 => 0, + 2 => 1, + 4 => 2, + 8 => 3, + 16 => 4, + _ => panic!("unknown type size: {size_bytes}"), + } +} + +impl PrettyPrint for AMode { + fn pretty_print(&self, size_bytes: u8) -> String { + debug_assert!(size_bytes != 0); + match self { + &AMode::Unscaled { rn, simm9 } => { + let reg = pretty_print_reg(rn); + if simm9.value != 0 { + let simm9 = simm9.pretty_print(8); + format!("[{reg}, {simm9}]") + } else { + format!("[{reg}]") + } + } + &AMode::UnsignedOffset { rn, uimm12 } => { + let reg = pretty_print_reg(rn); + if uimm12.value() != 0 { + let uimm12 = uimm12.pretty_print(8); + format!("[{reg}, {uimm12}]") + } else { + format!("[{reg}]") + } + } + &AMode::RegReg { rn, rm } => { + let r1 = pretty_print_reg(rn); + let r2 = pretty_print_reg(rm); + format!("[{r1}, {r2}]") + } + &AMode::RegScaled { rn, rm } => { + let r1 = pretty_print_reg(rn); + let r2 = pretty_print_reg(rm); + let shift = shift_for_type(size_bytes); + format!("[{r1}, {r2}, LSL #{shift}]") + } + &AMode::RegScaledExtended { rn, rm, extendop } => { + let shift = shift_for_type(size_bytes); + let size = match extendop { + ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32, + _ => OperandSize::Size64, + }; + let r1 = pretty_print_reg(rn); + let r2 = pretty_print_ireg(rm, size); + let op = extendop.pretty_print(0); + format!("[{r1}, {r2}, {op} #{shift}]") + } + &AMode::RegExtended { rn, rm, extendop } => { + let size = match extendop { + ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32, + _ => OperandSize::Size64, + }; + let r1 = pretty_print_reg(rn); + let r2 = pretty_print_ireg(rm, size); + let op = extendop.pretty_print(0); + format!("[{r1}, {r2}, {op}]") + } + &AMode::Label { ref label } => label.pretty_print(0), + &AMode::SPPreIndexed { simm9 } => { + let simm9 = simm9.pretty_print(8); + format!("[sp, {simm9}]!") + } + &AMode::SPPostIndexed { simm9 } => { + let simm9 = simm9.pretty_print(8); + format!("[sp], {simm9}") + } + AMode::Const { addr } => format!("[const({})]", addr.as_u32()), + + // Eliminated by `mem_finalize()`. + &AMode::SPOffset { .. } + | &AMode::FPOffset { .. } + | &AMode::IncomingArg { .. } + | &AMode::SlotOffset { .. } + | &AMode::RegOffset { .. } => { + panic!("Unexpected pseudo mem-arg mode: {self:?}") + } + } + } +} + +impl PrettyPrint for PairAMode { + fn pretty_print(&self, _: u8) -> String { + match self { + &PairAMode::SignedOffset { reg, simm7 } => { + let reg = pretty_print_reg(reg); + if simm7.value != 0 { + let simm7 = simm7.pretty_print(8); + format!("[{reg}, {simm7}]") + } else { + format!("[{reg}]") + } + } + &PairAMode::SPPreIndexed { simm7 } => { + let simm7 = simm7.pretty_print(8); + format!("[sp, {simm7}]!") + } + &PairAMode::SPPostIndexed { simm7 } => { + let simm7 = simm7.pretty_print(8); + format!("[sp], {simm7}") + } + } + } +} + +impl PrettyPrint for Cond { + fn pretty_print(&self, _: u8) -> String { + let mut s = format!("{self:?}"); + s.make_ascii_lowercase(); + s + } +} + +impl PrettyPrint for BranchTarget { + fn pretty_print(&self, _: u8) -> String { + match self { + &BranchTarget::Label(label) => format!("label{:?}", label.get()), + &BranchTarget::ResolvedOffset(off) => format!("{off}"), + } + } +} + +/// Type used to communicate the operand size of a machine instruction, as AArch64 has 32- and +/// 64-bit variants of many instructions (and integer registers). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OperandSize { + /// 32-bit. + Size32, + /// 64-bit. + Size64, +} + +impl OperandSize { + /// 32-bit case? + pub fn is32(self) -> bool { + self == OperandSize::Size32 + } + + /// 64-bit case? + pub fn is64(self) -> bool { + self == OperandSize::Size64 + } + + /// Convert from a needed width to the smallest size that fits. + pub fn from_bits>(bits: I) -> OperandSize { + let bits: usize = bits.into(); + assert!(bits <= 64); + if bits <= 32 { + OperandSize::Size32 + } else { + OperandSize::Size64 + } + } + + /// Return the operand size in bits. + pub fn bits(&self) -> u8 { + match self { + OperandSize::Size32 => 32, + OperandSize::Size64 => 64, + } + } + + /// Convert from an integer type into the smallest size that fits. + pub fn from_ty(ty: Type) -> OperandSize { + debug_assert!(!ty.is_vector()); + + Self::from_bits(ty_bits(ty)) + } + + /// Convert to I32, I64, or I128. + pub fn to_ty(self) -> Type { + match self { + OperandSize::Size32 => I32, + OperandSize::Size64 => I64, + } + } + + /// Register interpretation bit. + /// When 0, the register is interpreted as the 32-bit version. + /// When 1, the register is interpreted as the 64-bit version. + pub fn sf_bit(&self) -> u32 { + match self { + OperandSize::Size32 => 0, + OperandSize::Size64 => 1, + } + } + + /// The maximum unsigned value representable in a value of this size. + pub fn max_value(&self) -> u64 { + match self { + OperandSize::Size32 => u32::MAX as u64, + OperandSize::Size64 => u64::MAX, + } + } +} + +/// Type used to communicate the size of a scalar SIMD & FP operand. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ScalarSize { + /// 8-bit. + Size8, + /// 16-bit. + Size16, + /// 32-bit. + Size32, + /// 64-bit. + Size64, + /// 128-bit. + Size128, +} + +impl ScalarSize { + /// Convert to an integer operand size. + pub fn operand_size(&self) -> OperandSize { + match self { + ScalarSize::Size8 | ScalarSize::Size16 | ScalarSize::Size32 => OperandSize::Size32, + ScalarSize::Size64 => OperandSize::Size64, + _ => panic!("Unexpected operand_size request for: {self:?}"), + } + } + + /// Return the encoding bits that are used by some scalar FP instructions + /// for a particular operand size. + pub fn ftype(&self) -> u32 { + match self { + ScalarSize::Size16 => 0b11, + ScalarSize::Size32 => 0b00, + ScalarSize::Size64 => 0b01, + _ => panic!("Unexpected scalar FP operand size: {self:?}"), + } + } + + /// Return the widened version of the scalar size. + pub fn widen(&self) -> ScalarSize { + match self { + ScalarSize::Size8 => ScalarSize::Size16, + ScalarSize::Size16 => ScalarSize::Size32, + ScalarSize::Size32 => ScalarSize::Size64, + ScalarSize::Size64 => ScalarSize::Size128, + ScalarSize::Size128 => panic!("can't widen 128-bits"), + } + } + + /// Return the narrowed version of the scalar size. + pub fn narrow(&self) -> ScalarSize { + match self { + ScalarSize::Size8 => panic!("can't narrow 8-bits"), + ScalarSize::Size16 => ScalarSize::Size8, + ScalarSize::Size32 => ScalarSize::Size16, + ScalarSize::Size64 => ScalarSize::Size32, + ScalarSize::Size128 => ScalarSize::Size64, + } + } + + /// Return a type with the same size as this scalar. + pub fn ty(&self) -> Type { + match self { + ScalarSize::Size8 => I8, + ScalarSize::Size16 => I16, + ScalarSize::Size32 => I32, + ScalarSize::Size64 => I64, + ScalarSize::Size128 => I128, + } + } +} + +/// Type used to communicate the size of a vector operand. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum VectorSize { + /// 8-bit, 8 lanes. + Size8x8, + /// 8 bit, 16 lanes. + Size8x16, + /// 16-bit, 4 lanes. + Size16x4, + /// 16-bit, 8 lanes. + Size16x8, + /// 32-bit, 2 lanes. + Size32x2, + /// 32-bit, 4 lanes. + Size32x4, + /// 64-bit, 2 lanes. + Size64x2, +} + +impl VectorSize { + /// Get the vector operand size with the given scalar size as lane size. + pub fn from_lane_size(size: ScalarSize, is_128bit: bool) -> VectorSize { + match (size, is_128bit) { + (ScalarSize::Size8, false) => VectorSize::Size8x8, + (ScalarSize::Size8, true) => VectorSize::Size8x16, + (ScalarSize::Size16, false) => VectorSize::Size16x4, + (ScalarSize::Size16, true) => VectorSize::Size16x8, + (ScalarSize::Size32, false) => VectorSize::Size32x2, + (ScalarSize::Size32, true) => VectorSize::Size32x4, + (ScalarSize::Size64, true) => VectorSize::Size64x2, + _ => panic!("Unexpected scalar FP operand size: {size:?}"), + } + } + + /// Get the integer operand size that corresponds to a lane of a vector with a certain size. + pub fn operand_size(&self) -> OperandSize { + match self { + VectorSize::Size64x2 => OperandSize::Size64, + _ => OperandSize::Size32, + } + } + + /// Get the scalar operand size that corresponds to a lane of a vector with a certain size. + pub fn lane_size(&self) -> ScalarSize { + match self { + VectorSize::Size8x8 | VectorSize::Size8x16 => ScalarSize::Size8, + VectorSize::Size16x4 | VectorSize::Size16x8 => ScalarSize::Size16, + VectorSize::Size32x2 | VectorSize::Size32x4 => ScalarSize::Size32, + VectorSize::Size64x2 => ScalarSize::Size64, + } + } + + /// Returns true if the VectorSize is 128-bits. + pub fn is_128bits(&self) -> bool { + match self { + VectorSize::Size8x8 => false, + VectorSize::Size8x16 => true, + VectorSize::Size16x4 => false, + VectorSize::Size16x8 => true, + VectorSize::Size32x2 => false, + VectorSize::Size32x4 => true, + VectorSize::Size64x2 => true, + } + } + + /// Return the encoding bits that are used by some SIMD instructions + /// for a particular operand size. + pub fn enc_size(&self) -> (u32, u32) { + let q = self.is_128bits() as u32; + let size = match self.lane_size() { + ScalarSize::Size8 => 0b00, + ScalarSize::Size16 => 0b01, + ScalarSize::Size32 => 0b10, + ScalarSize::Size64 => 0b11, + _ => unreachable!(), + }; + + (q, size) + } + + /// Return the encoding bit that is used by some floating-point SIMD + /// instructions for a particular operand size. + pub fn enc_float_size(&self) -> u32 { + match self.lane_size() { + ScalarSize::Size32 => 0b0, + ScalarSize::Size64 => 0b1, + size => panic!("Unsupported floating-point size for vector op: {size:?}"), + } + } +} + +impl APIKey { + /// Returns the encoding of the `auti{key}` instruction used to decrypt the + /// `lr` register. + pub fn enc_auti_hint(&self) -> u32 { + let (crm, op2) = match self { + APIKey::AZ => (0b0011, 0b100), + APIKey::ASP => (0b0011, 0b101), + APIKey::BZ => (0b0011, 0b110), + APIKey::BSP => (0b0011, 0b111), + }; + 0xd503201f | (crm << 8) | (op2 << 5) + } +} + +pub use crate::isa::aarch64::lower::isle::generated_code::TestBitAndBranchKind; + +impl TestBitAndBranchKind { + /// Complements this branch condition to act on the opposite result. + pub fn complement(&self) -> TestBitAndBranchKind { + match self { + TestBitAndBranchKind::Z => TestBitAndBranchKind::NZ, + TestBitAndBranchKind::NZ => TestBitAndBranchKind::Z, + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/emit.rs b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/emit.rs new file mode 100644 index 00000000000000..d31e08fcedb8e2 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/aarch64/inst/emit.rs @@ -0,0 +1,3577 @@ +//! AArch64 ISA: binary code emission. + +use cranelift_control::ControlPlane; + +use crate::ir::{self, types::*}; +use crate::isa::aarch64::inst::*; +use crate::trace; + +/// Memory addressing mode finalization: convert "special" modes (e.g., +/// generic arbitrary stack offset) into real addressing modes, possibly by +/// emitting some helper instructions that come immediately before the use +/// of this amode. +pub fn mem_finalize( + sink: Option<&mut MachBuffer>, + mem: &AMode, + access_ty: Type, + state: &EmitState, +) -> (SmallVec<[Inst; 4]>, AMode) { + match mem { + &AMode::RegOffset { off, .. } + | &AMode::SPOffset { off } + | &AMode::FPOffset { off } + | &AMode::IncomingArg { off } + | &AMode::SlotOffset { off } => { + let basereg = match mem { + &AMode::RegOffset { rn, .. } => rn, + &AMode::SPOffset { .. } + | &AMode::SlotOffset { .. } + | &AMode::IncomingArg { .. } => stack_reg(), + &AMode::FPOffset { .. } => fp_reg(), + _ => unreachable!(), + }; + let off = match mem { + &AMode::IncomingArg { .. } => { + let frame_layout = state.frame_layout(); + i64::from( + frame_layout.setup_area_size + + frame_layout.tail_args_size + + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size, + ) - off + } + &AMode::SlotOffset { .. } => { + let adj = i64::from(state.frame_layout().outgoing_args_size); + trace!( + "mem_finalize: slot offset {} + adj {} -> {}", + off, + adj, + off + adj + ); + off + adj + } + _ => off, + }; + + if let Some(simm9) = SImm9::maybe_from_i64(off) { + let mem = AMode::Unscaled { rn: basereg, simm9 }; + (smallvec![], mem) + } else if let Some(uimm12) = UImm12Scaled::maybe_from_i64(off, access_ty) { + let mem = AMode::UnsignedOffset { + rn: basereg, + uimm12, + }; + (smallvec![], mem) + } else { + let tmp = writable_spilltmp_reg(); + ( + Inst::load_constant(tmp, off as u64, &mut |_| tmp), + AMode::RegExtended { + rn: basereg, + rm: tmp.to_reg(), + extendop: ExtendOp::SXTX, + }, + ) + } + } + + AMode::Const { addr } => { + let sink = match sink { + Some(sink) => sink, + None => return (smallvec![], mem.clone()), + }; + let label = sink.get_label_for_constant(*addr); + let label = MemLabel::Mach(label); + (smallvec![], AMode::Label { label }) + } + + _ => (smallvec![], mem.clone()), + } +} + +//============================================================================= +// Instructions and subcomponents: emission + +pub(crate) fn machreg_to_gpr(m: Reg) -> u32 { + assert_eq!(m.class(), RegClass::Int); + u32::from(m.to_real_reg().unwrap().hw_enc() & 31) +} + +pub(crate) fn machreg_to_vec(m: Reg) -> u32 { + assert_eq!(m.class(), RegClass::Float); + u32::from(m.to_real_reg().unwrap().hw_enc()) +} + +fn machreg_to_gpr_or_vec(m: Reg) -> u32 { + u32::from(m.to_real_reg().unwrap().hw_enc() & 31) +} + +pub(crate) fn enc_arith_rrr( + bits_31_21: u32, + bits_15_10: u32, + rd: Writable, + rn: Reg, + rm: Reg, +) -> u32 { + (bits_31_21 << 21) + | (bits_15_10 << 10) + | machreg_to_gpr(rd.to_reg()) + | (machreg_to_gpr(rn) << 5) + | (machreg_to_gpr(rm) << 16) +} + +fn enc_arith_rr_imm12( + bits_31_24: u32, + immshift: u32, + imm12: u32, + rn: Reg, + rd: Writable, +) -> u32 { + (bits_31_24 << 24) + | (immshift << 22) + | (imm12 << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_arith_rr_imml(bits_31_23: u32, imm_bits: u32, rn: Reg, rd: Writable) -> u32 { + (bits_31_23 << 23) | (imm_bits << 10) | (machreg_to_gpr(rn) << 5) | machreg_to_gpr(rd.to_reg()) +} + +fn enc_arith_rrrr(top11: u32, rm: Reg, bit15: u32, ra: Reg, rn: Reg, rd: Writable) -> u32 { + (top11 << 21) + | (machreg_to_gpr(rm) << 16) + | (bit15 << 15) + | (machreg_to_gpr(ra) << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_jump26(op_31_26: u32, off_26_0: u32) -> u32 { + assert!(off_26_0 < (1 << 26)); + (op_31_26 << 26) | off_26_0 +} + +fn enc_cmpbr(op_31_24: u32, off_18_0: u32, reg: Reg) -> u32 { + assert!(off_18_0 < (1 << 19)); + (op_31_24 << 24) | (off_18_0 << 5) | machreg_to_gpr(reg) +} + +fn enc_cbr(op_31_24: u32, off_18_0: u32, op_4: u32, cond: u32) -> u32 { + assert!(off_18_0 < (1 << 19)); + assert!(cond < (1 << 4)); + (op_31_24 << 24) | (off_18_0 << 5) | (op_4 << 4) | cond +} + +/// Set the size bit of an instruction. +fn enc_op_size(op: u32, size: OperandSize) -> u32 { + (op & !(1 << 31)) | (size.sf_bit() << 31) +} + +fn enc_conditional_br(taken: BranchTarget, kind: CondBrKind) -> u32 { + match kind { + CondBrKind::Zero(reg, size) => enc_op_size( + enc_cmpbr(0b0_011010_0, taken.as_offset19_or_zero(), reg), + size, + ), + CondBrKind::NotZero(reg, size) => enc_op_size( + enc_cmpbr(0b0_011010_1, taken.as_offset19_or_zero(), reg), + size, + ), + CondBrKind::Cond(c) => enc_cbr(0b01010100, taken.as_offset19_or_zero(), 0b0, c.bits()), + } +} + +fn enc_test_bit_and_branch( + kind: TestBitAndBranchKind, + taken: BranchTarget, + reg: Reg, + bit: u8, +) -> u32 { + assert!(bit < 64); + let op_31 = u32::from(bit >> 5); + let op_23_19 = u32::from(bit & 0b11111); + let op_30_24 = 0b0110110 + | match kind { + TestBitAndBranchKind::Z => 0, + TestBitAndBranchKind::NZ => 1, + }; + (op_31 << 31) + | (op_30_24 << 24) + | (op_23_19 << 19) + | (taken.as_offset14_or_zero() << 5) + | machreg_to_gpr(reg) +} + +fn enc_move_wide(op: MoveWideOp, rd: Writable, imm: MoveWideConst, size: OperandSize) -> u32 { + assert!(imm.shift <= 0b11); + let op = match op { + MoveWideOp::MovN => 0b00, + MoveWideOp::MovZ => 0b10, + }; + 0x12800000 + | size.sf_bit() << 31 + | op << 29 + | u32::from(imm.shift) << 21 + | u32::from(imm.bits) << 5 + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_movk(rd: Writable, imm: MoveWideConst, size: OperandSize) -> u32 { + assert!(imm.shift <= 0b11); + 0x72800000 + | size.sf_bit() << 31 + | u32::from(imm.shift) << 21 + | u32::from(imm.bits) << 5 + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_ldst_pair(op_31_22: u32, simm7: SImm7Scaled, rn: Reg, rt: Reg, rt2: Reg) -> u32 { + (op_31_22 << 22) + | (simm7.bits() << 15) + | (machreg_to_gpr(rt2) << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt) +} + +fn enc_ldst_simm9(op_31_22: u32, simm9: SImm9, op_11_10: u32, rn: Reg, rd: Reg) -> u32 { + (op_31_22 << 22) + | (simm9.bits() << 12) + | (op_11_10 << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr_or_vec(rd) +} + +fn enc_ldst_uimm12(op_31_22: u32, uimm12: UImm12Scaled, rn: Reg, rd: Reg) -> u32 { + (op_31_22 << 22) + | (0b1 << 24) + | (uimm12.bits() << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr_or_vec(rd) +} + +fn enc_ldst_reg( + op_31_22: u32, + rn: Reg, + rm: Reg, + s_bit: bool, + extendop: Option, + rd: Reg, +) -> u32 { + let s_bit = if s_bit { 1 } else { 0 }; + let extend_bits = match extendop { + Some(ExtendOp::UXTW) => 0b010, + Some(ExtendOp::SXTW) => 0b110, + Some(ExtendOp::SXTX) => 0b111, + None => 0b011, // LSL + _ => panic!("bad extend mode for ld/st AMode"), + }; + (op_31_22 << 22) + | (1 << 21) + | (machreg_to_gpr(rm) << 16) + | (extend_bits << 13) + | (s_bit << 12) + | (0b10 << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr_or_vec(rd) +} + +pub(crate) fn enc_ldst_imm19(op_31_24: u32, imm19: u32, rd: Reg) -> u32 { + (op_31_24 << 24) | (imm19 << 5) | machreg_to_gpr_or_vec(rd) +} + +fn enc_ldst_vec(q: u32, size: u32, rn: Reg, rt: Writable) -> u32 { + debug_assert_eq!(q & 0b1, q); + debug_assert_eq!(size & 0b11, size); + 0b0_0_0011010_10_00000_110_0_00_00000_00000 + | q << 30 + | size << 10 + | machreg_to_gpr(rn) << 5 + | machreg_to_vec(rt.to_reg()) +} + +fn enc_ldst_vec_pair( + opc: u32, + amode: u32, + is_load: bool, + simm7: SImm7Scaled, + rn: Reg, + rt: Reg, + rt2: Reg, +) -> u32 { + debug_assert_eq!(opc & 0b11, opc); + debug_assert_eq!(amode & 0b11, amode); + + 0b00_10110_00_0_0000000_00000_00000_00000 + | opc << 30 + | amode << 23 + | (is_load as u32) << 22 + | simm7.bits() << 15 + | machreg_to_vec(rt2) << 10 + | machreg_to_gpr(rn) << 5 + | machreg_to_vec(rt) +} + +fn enc_vec_rrr(top11: u32, rm: Reg, bit15_10: u32, rn: Reg, rd: Writable) -> u32 { + (top11 << 21) + | (machreg_to_vec(rm) << 16) + | (bit15_10 << 10) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) +} + +fn enc_vec_rrr_long( + q: u32, + u: u32, + size: u32, + bit14: u32, + rm: Reg, + rn: Reg, + rd: Writable, +) -> u32 { + debug_assert_eq!(q & 0b1, q); + debug_assert_eq!(u & 0b1, u); + debug_assert_eq!(size & 0b11, size); + debug_assert_eq!(bit14 & 0b1, bit14); + + 0b0_0_0_01110_00_1_00000_100000_00000_00000 + | q << 30 + | u << 29 + | size << 22 + | bit14 << 14 + | (machreg_to_vec(rm) << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) +} + +fn enc_bit_rr(size: u32, opcode2: u32, opcode1: u32, rn: Reg, rd: Writable) -> u32 { + (0b01011010110 << 21) + | size << 31 + | opcode2 << 16 + | opcode1 << 10 + | machreg_to_gpr(rn) << 5 + | machreg_to_gpr(rd.to_reg()) +} + +pub(crate) fn enc_br(rn: Reg) -> u32 { + 0b1101011_0000_11111_000000_00000_00000 | (machreg_to_gpr(rn) << 5) +} + +pub(crate) fn enc_adr_inst(opcode: u32, off: i32, rd: Writable) -> u32 { + let off = u32::try_from(off).unwrap(); + let immlo = off & 3; + let immhi = (off >> 2) & ((1 << 19) - 1); + opcode | (immlo << 29) | (immhi << 5) | machreg_to_gpr(rd.to_reg()) +} + +pub(crate) fn enc_adr(off: i32, rd: Writable) -> u32 { + let opcode = 0b00010000 << 24; + enc_adr_inst(opcode, off, rd) +} + +pub(crate) fn enc_adrp(off: i32, rd: Writable) -> u32 { + let opcode = 0b10010000 << 24; + enc_adr_inst(opcode, off, rd) +} + +fn enc_csel(rd: Writable, rn: Reg, rm: Reg, cond: Cond, op: u32, o2: u32) -> u32 { + debug_assert_eq!(op & 0b1, op); + debug_assert_eq!(o2 & 0b1, o2); + 0b100_11010100_00000_0000_00_00000_00000 + | (op << 30) + | (machreg_to_gpr(rm) << 16) + | (cond.bits() << 12) + | (o2 << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_fcsel(rd: Writable, rn: Reg, rm: Reg, cond: Cond, size: ScalarSize) -> u32 { + 0b000_11110_00_1_00000_0000_11_00000_00000 + | (size.ftype() << 22) + | (machreg_to_vec(rm) << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) + | (cond.bits() << 12) +} + +fn enc_ccmp(size: OperandSize, rn: Reg, rm: Reg, nzcv: NZCV, cond: Cond) -> u32 { + 0b0_1_1_11010010_00000_0000_00_00000_0_0000 + | size.sf_bit() << 31 + | machreg_to_gpr(rm) << 16 + | cond.bits() << 12 + | machreg_to_gpr(rn) << 5 + | nzcv.bits() +} + +fn enc_ccmp_imm(size: OperandSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) -> u32 { + 0b0_1_1_11010010_00000_0000_10_00000_0_0000 + | size.sf_bit() << 31 + | imm.bits() << 16 + | cond.bits() << 12 + | machreg_to_gpr(rn) << 5 + | nzcv.bits() +} + +fn enc_bfm(opc: u8, size: OperandSize, rd: Writable, rn: Reg, immr: u8, imms: u8) -> u32 { + match size { + OperandSize::Size64 => { + debug_assert!(immr <= 63); + debug_assert!(imms <= 63); + } + OperandSize::Size32 => { + debug_assert!(immr <= 31); + debug_assert!(imms <= 31); + } + } + debug_assert_eq!(opc & 0b11, opc); + let n_bit = size.sf_bit(); + 0b0_00_100110_0_000000_000000_00000_00000 + | size.sf_bit() << 31 + | u32::from(opc) << 29 + | n_bit << 22 + | u32::from(immr) << 16 + | u32::from(imms) << 10 + | machreg_to_gpr(rn) << 5 + | machreg_to_gpr(rd.to_reg()) +} + +fn enc_vecmov(is_16b: bool, rd: Writable, rn: Reg) -> u32 { + 0b00001110_101_00000_00011_1_00000_00000 + | ((is_16b as u32) << 30) + | machreg_to_vec(rd.to_reg()) + | (machreg_to_vec(rn) << 16) + | (machreg_to_vec(rn) << 5) +} + +fn enc_fpurr(top22: u32, rd: Writable, rn: Reg) -> u32 { + (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg()) +} + +fn enc_fpurrr(top22: u32, rd: Writable, rn: Reg, rm: Reg) -> u32 { + (top22 << 10) + | (machreg_to_vec(rm) << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) +} + +fn enc_fpurrrr(top17: u32, rd: Writable, rn: Reg, rm: Reg, ra: Reg) -> u32 { + (top17 << 15) + | (machreg_to_vec(rm) << 16) + | (machreg_to_vec(ra) << 10) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) +} + +fn enc_fcmp(size: ScalarSize, rn: Reg, rm: Reg) -> u32 { + 0b000_11110_00_1_00000_00_1000_00000_00000 + | (size.ftype() << 22) + | (machreg_to_vec(rm) << 16) + | (machreg_to_vec(rn) << 5) +} + +fn enc_fputoint(top16: u32, rd: Writable, rn: Reg) -> u32 { + (top16 << 16) | (machreg_to_vec(rn) << 5) | machreg_to_gpr(rd.to_reg()) +} + +fn enc_inttofpu(top16: u32, rd: Writable, rn: Reg) -> u32 { + (top16 << 16) | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg()) +} + +fn enc_fround(top22: u32, rd: Writable, rn: Reg) -> u32 { + (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg()) +} + +fn enc_vec_rr_misc(qu: u32, size: u32, bits_12_16: u32, rd: Writable, rn: Reg) -> u32 { + debug_assert_eq!(qu & 0b11, qu); + debug_assert_eq!(size & 0b11, size); + debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16); + let bits = 0b0_00_01110_00_10000_00000_10_00000_00000; + bits | qu << 29 + | size << 22 + | bits_12_16 << 12 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()) +} + +fn enc_vec_rr_pair(bits_12_16: u32, rd: Writable, rn: Reg) -> u32 { + debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16); + + 0b010_11110_11_11000_11011_10_00000_00000 + | bits_12_16 << 12 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()) +} + +fn enc_vec_rr_pair_long(u: u32, enc_size: u32, rd: Writable, rn: Reg) -> u32 { + debug_assert_eq!(u & 0b1, u); + debug_assert_eq!(enc_size & 0b1, enc_size); + + 0b0_1_0_01110_00_10000_00_0_10_10_00000_00000 + | u << 29 + | enc_size << 22 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()) +} + +fn enc_vec_lanes(q: u32, u: u32, size: u32, opcode: u32, rd: Writable, rn: Reg) -> u32 { + debug_assert_eq!(q & 0b1, q); + debug_assert_eq!(u & 0b1, u); + debug_assert_eq!(size & 0b11, size); + debug_assert_eq!(opcode & 0b11111, opcode); + 0b0_0_0_01110_00_11000_0_0000_10_00000_00000 + | q << 30 + | u << 29 + | size << 22 + | opcode << 12 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()) +} + +fn enc_tbl(is_extension: bool, len: u32, rd: Writable, rn: Reg, rm: Reg) -> u32 { + debug_assert_eq!(len & 0b11, len); + 0b0_1_001110_000_00000_0_00_0_00_00000_00000 + | (machreg_to_vec(rm) << 16) + | len << 13 + | (is_extension as u32) << 12 + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()) +} + +fn enc_dmb_ish() -> u32 { + 0xD5033BBF +} + +fn enc_acq_rel(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable, rn: Reg) -> u32 { + assert!(machreg_to_gpr(rt.to_reg()) != 31); + let sz = match ty { + I64 => 0b11, + I32 => 0b10, + I16 => 0b01, + I8 => 0b00, + _ => unreachable!(), + }; + let bit15 = match op { + AtomicRMWOp::Swp => 0b1, + _ => 0b0, + }; + let op = match op { + AtomicRMWOp::Add => 0b000, + AtomicRMWOp::Clr => 0b001, + AtomicRMWOp::Eor => 0b010, + AtomicRMWOp::Set => 0b011, + AtomicRMWOp::Smax => 0b100, + AtomicRMWOp::Smin => 0b101, + AtomicRMWOp::Umax => 0b110, + AtomicRMWOp::Umin => 0b111, + AtomicRMWOp::Swp => 0b000, + }; + 0b00_111_000_111_00000_0_000_00_00000_00000 + | (sz << 30) + | (machreg_to_gpr(rs) << 16) + | bit15 << 15 + | (op << 12) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt.to_reg()) +} + +fn enc_ldar(ty: Type, rt: Writable, rn: Reg) -> u32 { + let sz = match ty { + I64 => 0b11, + I32 => 0b10, + I16 => 0b01, + I8 => 0b00, + _ => unreachable!(), + }; + 0b00_001000_1_1_0_11111_1_11111_00000_00000 + | (sz << 30) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt.to_reg()) +} + +fn enc_stlr(ty: Type, rt: Reg, rn: Reg) -> u32 { + let sz = match ty { + I64 => 0b11, + I32 => 0b10, + I16 => 0b01, + I8 => 0b00, + _ => unreachable!(), + }; + 0b00_001000_100_11111_1_11111_00000_00000 + | (sz << 30) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt) +} + +fn enc_ldaxr(ty: Type, rt: Writable, rn: Reg) -> u32 { + let sz = match ty { + I64 => 0b11, + I32 => 0b10, + I16 => 0b01, + I8 => 0b00, + _ => unreachable!(), + }; + 0b00_001000_0_1_0_11111_1_11111_00000_00000 + | (sz << 30) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt.to_reg()) +} + +fn enc_stlxr(ty: Type, rs: Writable, rt: Reg, rn: Reg) -> u32 { + let sz = match ty { + I64 => 0b11, + I32 => 0b10, + I16 => 0b01, + I8 => 0b00, + _ => unreachable!(), + }; + 0b00_001000_000_00000_1_11111_00000_00000 + | (sz << 30) + | (machreg_to_gpr(rs.to_reg()) << 16) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rt) +} + +fn enc_cas(size: u32, rs: Writable, rt: Reg, rn: Reg) -> u32 { + debug_assert_eq!(size & 0b11, size); + + 0b00_0010001_1_1_00000_1_11111_00000_00000 + | size << 30 + | machreg_to_gpr(rs.to_reg()) << 16 + | machreg_to_gpr(rn) << 5 + | machreg_to_gpr(rt) +} + +fn enc_asimd_mod_imm(rd: Writable, q_op: u32, cmode: u32, imm: u8) -> u32 { + let abc = (imm >> 5) as u32; + let defgh = (imm & 0b11111) as u32; + + debug_assert_eq!(cmode & 0b1111, cmode); + debug_assert_eq!(q_op & 0b11, q_op); + + 0b0_0_0_0111100000_000_0000_01_00000_00000 + | (q_op << 29) + | (abc << 16) + | (cmode << 12) + | (defgh << 5) + | machreg_to_vec(rd.to_reg()) +} + +/// State carried between emissions of a sequence of instructions. +#[derive(Default, Clone, Debug)] +pub struct EmitState { + /// The user stack map for the upcoming instruction, as provided to + /// `pre_safepoint()`. + user_stack_map: Option, + + /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and + /// optimized away at compiletime. See [cranelift_control]. + ctrl_plane: ControlPlane, + + frame_layout: FrameLayout, +} + +impl MachInstEmitState for EmitState { + fn new(abi: &Callee, ctrl_plane: ControlPlane) -> Self { + EmitState { + user_stack_map: None, + ctrl_plane, + frame_layout: abi.frame_layout().clone(), + } + } + + fn pre_safepoint(&mut self, user_stack_map: Option) { + self.user_stack_map = user_stack_map; + } + + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane { + &mut self.ctrl_plane + } + + fn take_ctrl_plane(self) -> ControlPlane { + self.ctrl_plane + } + + fn frame_layout(&self) -> &FrameLayout { + &self.frame_layout + } +} + +impl EmitState { + fn take_stack_map(&mut self) -> Option { + self.user_stack_map.take() + } + + fn clear_post_insn(&mut self) { + self.user_stack_map = None; + } +} + +/// Constant state used during function compilation. +pub struct EmitInfo(settings::Flags); + +impl EmitInfo { + /// Create a constant state for emission of instructions. + pub fn new(flags: settings::Flags) -> Self { + Self(flags) + } +} + +impl MachInstEmit for Inst { + type State = EmitState; + type Info = EmitInfo; + + fn emit(&self, sink: &mut MachBuffer, emit_info: &Self::Info, state: &mut EmitState) { + // N.B.: we *must* not exceed the "worst-case size" used to compute + // where to insert islands, except when islands are explicitly triggered + // (with an `EmitIsland`). We check this in debug builds. This is `mut` + // to allow disabling the check for `JTSequence`, which is always + // emitted following an `EmitIsland`. + let mut start_off = sink.cur_offset(); + + match self { + &Inst::AluRRR { + alu_op, + size, + rd, + rn, + rm, + } => { + debug_assert!(match alu_op { + ALUOp::SMulH | ALUOp::UMulH => size == OperandSize::Size64, + _ => true, + }); + let top11 = match alu_op { + ALUOp::Add => 0b00001011_000, + ALUOp::Adc => 0b00011010_000, + ALUOp::AdcS => 0b00111010_000, + ALUOp::Sub => 0b01001011_000, + ALUOp::Sbc => 0b01011010_000, + ALUOp::SbcS => 0b01111010_000, + ALUOp::Orr => 0b00101010_000, + ALUOp::And => 0b00001010_000, + ALUOp::AndS => 0b01101010_000, + ALUOp::Eor => 0b01001010_000, + ALUOp::OrrNot => 0b00101010_001, + ALUOp::AndNot => 0b00001010_001, + ALUOp::EorNot => 0b01001010_001, + ALUOp::AddS => 0b00101011_000, + ALUOp::SubS => 0b01101011_000, + ALUOp::SDiv | ALUOp::UDiv => 0b00011010_110, + ALUOp::RotR | ALUOp::Lsr | ALUOp::Asr | ALUOp::Lsl => 0b00011010_110, + ALUOp::SMulH => 0b10011011_010, + ALUOp::UMulH => 0b10011011_110, + }; + + let top11 = top11 | size.sf_bit() << 10; + let bit15_10 = match alu_op { + ALUOp::SDiv => 0b000011, + ALUOp::UDiv => 0b000010, + ALUOp::RotR => 0b001011, + ALUOp::Lsr => 0b001001, + ALUOp::Asr => 0b001010, + ALUOp::Lsl => 0b001000, + ALUOp::SMulH | ALUOp::UMulH => 0b011111, + _ => 0b000000, + }; + debug_assert_ne!(writable_stack_reg(), rd); + // The stack pointer is the zero register in this context, so this might be an + // indication that something is wrong. + debug_assert_ne!(stack_reg(), rn); + debug_assert_ne!(stack_reg(), rm); + sink.put4(enc_arith_rrr(top11, bit15_10, rd, rn, rm)); + } + &Inst::AluRRRR { + alu_op, + size, + rd, + rm, + rn, + ra, + } => { + let (top11, bit15) = match alu_op { + ALUOp3::MAdd => (0b0_00_11011_000, 0), + ALUOp3::MSub => (0b0_00_11011_000, 1), + ALUOp3::UMAddL => { + debug_assert!(size == OperandSize::Size32); + (0b1_00_11011_1_01, 0) + } + ALUOp3::SMAddL => { + debug_assert!(size == OperandSize::Size32); + (0b1_00_11011_0_01, 0) + } + }; + let top11 = top11 | size.sf_bit() << 10; + sink.put4(enc_arith_rrrr(top11, rm, bit15, ra, rn, rd)); + } + &Inst::AluRRImm12 { + alu_op, + size, + rd, + rn, + ref imm12, + } => { + let top8 = match alu_op { + ALUOp::Add => 0b000_10001, + ALUOp::Sub => 0b010_10001, + ALUOp::AddS => 0b001_10001, + ALUOp::SubS => 0b011_10001, + _ => unimplemented!("{:?}", alu_op), + }; + let top8 = top8 | size.sf_bit() << 7; + sink.put4(enc_arith_rr_imm12( + top8, + imm12.shift_bits(), + imm12.imm_bits(), + rn, + rd, + )); + } + &Inst::AluRRImmLogic { + alu_op, + size, + rd, + rn, + ref imml, + } => { + let (top9, inv) = match alu_op { + ALUOp::Orr => (0b001_100100, false), + ALUOp::And => (0b000_100100, false), + ALUOp::AndS => (0b011_100100, false), + ALUOp::Eor => (0b010_100100, false), + ALUOp::OrrNot => (0b001_100100, true), + ALUOp::AndNot => (0b000_100100, true), + ALUOp::EorNot => (0b010_100100, true), + _ => unimplemented!("{:?}", alu_op), + }; + let top9 = top9 | size.sf_bit() << 8; + let imml = if inv { imml.invert() } else { *imml }; + sink.put4(enc_arith_rr_imml(top9, imml.enc_bits(), rn, rd)); + } + + &Inst::AluRRImmShift { + alu_op, + size, + rd, + rn, + ref immshift, + } => { + let amt = immshift.value(); + let (top10, immr, imms) = match alu_op { + ALUOp::RotR => (0b0001001110, machreg_to_gpr(rn), u32::from(amt)), + ALUOp::Lsr => (0b0101001100, u32::from(amt), 0b011111), + ALUOp::Asr => (0b0001001100, u32::from(amt), 0b011111), + ALUOp::Lsl => { + let bits = if size.is64() { 64 } else { 32 }; + ( + 0b0101001100, + u32::from((bits - amt) % bits), + u32::from(bits - 1 - amt), + ) + } + _ => unimplemented!("{:?}", alu_op), + }; + let top10 = top10 | size.sf_bit() << 9 | size.sf_bit(); + let imms = match alu_op { + ALUOp::Lsr | ALUOp::Asr => imms | size.sf_bit() << 5, + _ => imms, + }; + sink.put4( + (top10 << 22) + | (immr << 16) + | (imms << 10) + | (machreg_to_gpr(rn) << 5) + | machreg_to_gpr(rd.to_reg()), + ); + } + + &Inst::AluRRRShift { + alu_op, + size, + rd, + rn, + rm, + ref shiftop, + } => { + let top11: u32 = match alu_op { + ALUOp::Add => 0b000_01011000, + ALUOp::AddS => 0b001_01011000, + ALUOp::Sub => 0b010_01011000, + ALUOp::SubS => 0b011_01011000, + ALUOp::Orr => 0b001_01010000, + ALUOp::And => 0b000_01010000, + ALUOp::AndS => 0b011_01010000, + ALUOp::Eor => 0b010_01010000, + ALUOp::OrrNot => 0b001_01010001, + ALUOp::EorNot => 0b010_01010001, + ALUOp::AndNot => 0b000_01010001, + _ => unimplemented!("{:?}", alu_op), + }; + let top11 = top11 | size.sf_bit() << 10; + let top11 = top11 | (u32::from(shiftop.op().bits()) << 1); + let bits_15_10 = u32::from(shiftop.amt().value()); + sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm)); + } + + &Inst::AluRRRExtend { + alu_op, + size, + rd, + rn, + rm, + extendop, + } => { + let top11: u32 = match alu_op { + ALUOp::Add => 0b00001011001, + ALUOp::Sub => 0b01001011001, + ALUOp::AddS => 0b00101011001, + ALUOp::SubS => 0b01101011001, + _ => unimplemented!("{:?}", alu_op), + }; + let top11 = top11 | size.sf_bit() << 10; + let bits_15_10 = u32::from(extendop.bits()) << 3; + sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm)); + } + + &Inst::BitRR { + op, size, rd, rn, .. + } => { + let (op1, op2) = match op { + BitOp::RBit => (0b00000, 0b000000), + BitOp::Clz => (0b00000, 0b000100), + BitOp::Cls => (0b00000, 0b000101), + BitOp::Rev16 => (0b00000, 0b000001), + BitOp::Rev32 => (0b00000, 0b000010), + BitOp::Rev64 => (0b00000, 0b000011), + }; + sink.put4(enc_bit_rr(size.sf_bit(), op1, op2, rn, rd)) + } + + &Inst::ULoad8 { rd, ref mem, flags } + | &Inst::SLoad8 { rd, ref mem, flags } + | &Inst::ULoad16 { rd, ref mem, flags } + | &Inst::SLoad16 { rd, ref mem, flags } + | &Inst::ULoad32 { rd, ref mem, flags } + | &Inst::SLoad32 { rd, ref mem, flags } + | &Inst::ULoad64 { + rd, ref mem, flags, .. + } + | &Inst::FpuLoad16 { rd, ref mem, flags } + | &Inst::FpuLoad32 { rd, ref mem, flags } + | &Inst::FpuLoad64 { rd, ref mem, flags } + | &Inst::FpuLoad128 { rd, ref mem, flags } => { + let mem = mem.clone(); + let access_ty = self.mem_type().unwrap(); + let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state); + + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + // ldst encoding helpers take Reg, not Writable. + let rd = rd.to_reg(); + + // This is the base opcode (top 10 bits) for the "unscaled + // immediate" form (Unscaled). Other addressing modes will OR in + // other values for bits 24/25 (bits 1/2 of this constant). + let op = match self { + Inst::ULoad8 { .. } => 0b0011100001, + Inst::SLoad8 { .. } => 0b0011100010, + Inst::ULoad16 { .. } => 0b0111100001, + Inst::SLoad16 { .. } => 0b0111100010, + Inst::ULoad32 { .. } => 0b1011100001, + Inst::SLoad32 { .. } => 0b1011100010, + Inst::ULoad64 { .. } => 0b1111100001, + Inst::FpuLoad16 { .. } => 0b0111110001, + Inst::FpuLoad32 { .. } => 0b1011110001, + Inst::FpuLoad64 { .. } => 0b1111110001, + Inst::FpuLoad128 { .. } => 0b0011110011, + _ => unreachable!(), + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + match &mem { + &AMode::Unscaled { rn, simm9 } => { + let reg = rn; + sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd)); + } + &AMode::UnsignedOffset { rn, uimm12 } => { + let reg = rn; + sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd)); + } + &AMode::RegReg { rn, rm } => { + let r1 = rn; + let r2 = rm; + sink.put4(enc_ldst_reg( + op, r1, r2, /* scaled = */ false, /* extendop = */ None, rd, + )); + } + &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => { + let r1 = rn; + let r2 = rm; + let extendop = match &mem { + &AMode::RegScaled { .. } => None, + &AMode::RegScaledExtended { extendop, .. } => Some(extendop), + _ => unreachable!(), + }; + sink.put4(enc_ldst_reg( + op, r1, r2, /* scaled = */ true, extendop, rd, + )); + } + &AMode::RegExtended { rn, rm, extendop } => { + let r1 = rn; + let r2 = rm; + sink.put4(enc_ldst_reg( + op, + r1, + r2, + /* scaled = */ false, + Some(extendop), + rd, + )); + } + &AMode::Label { ref label } => { + let offset = match label { + // cast i32 to u32 (two's-complement) + MemLabel::PCRel(off) => *off as u32, + // Emit a relocation into the `MachBuffer` + // for the label that's being loaded from and + // encode an address of 0 in its place which will + // get filled in by relocation resolution later on. + MemLabel::Mach(label) => { + sink.use_label_at_offset( + sink.cur_offset(), + *label, + LabelUse::Ldr19, + ); + 0 + } + } / 4; + assert!(offset < (1 << 19)); + match self { + &Inst::ULoad32 { .. } => { + sink.put4(enc_ldst_imm19(0b00011000, offset, rd)); + } + &Inst::SLoad32 { .. } => { + sink.put4(enc_ldst_imm19(0b10011000, offset, rd)); + } + &Inst::FpuLoad32 { .. } => { + sink.put4(enc_ldst_imm19(0b00011100, offset, rd)); + } + &Inst::ULoad64 { .. } => { + sink.put4(enc_ldst_imm19(0b01011000, offset, rd)); + } + &Inst::FpuLoad64 { .. } => { + sink.put4(enc_ldst_imm19(0b01011100, offset, rd)); + } + &Inst::FpuLoad128 { .. } => { + sink.put4(enc_ldst_imm19(0b10011100, offset, rd)); + } + _ => panic!("Unsupported size for LDR from constant pool!"), + } + } + &AMode::SPPreIndexed { simm9 } => { + let reg = stack_reg(); + sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd)); + } + &AMode::SPPostIndexed { simm9 } => { + let reg = stack_reg(); + sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd)); + } + // Eliminated by `mem_finalize()` above. + &AMode::SPOffset { .. } + | &AMode::FPOffset { .. } + | &AMode::IncomingArg { .. } + | &AMode::SlotOffset { .. } + | &AMode::Const { .. } + | &AMode::RegOffset { .. } => { + panic!("Should not see {mem:?} here!") + } + } + } + + &Inst::Store8 { rd, ref mem, flags } + | &Inst::Store16 { rd, ref mem, flags } + | &Inst::Store32 { rd, ref mem, flags } + | &Inst::Store64 { rd, ref mem, flags } + | &Inst::FpuStore16 { rd, ref mem, flags } + | &Inst::FpuStore32 { rd, ref mem, flags } + | &Inst::FpuStore64 { rd, ref mem, flags } + | &Inst::FpuStore128 { rd, ref mem, flags } => { + let mem = mem.clone(); + let access_ty = self.mem_type().unwrap(); + let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state); + + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + let op = match self { + Inst::Store8 { .. } => 0b0011100000, + Inst::Store16 { .. } => 0b0111100000, + Inst::Store32 { .. } => 0b1011100000, + Inst::Store64 { .. } => 0b1111100000, + Inst::FpuStore16 { .. } => 0b0111110000, + Inst::FpuStore32 { .. } => 0b1011110000, + Inst::FpuStore64 { .. } => 0b1111110000, + Inst::FpuStore128 { .. } => 0b0011110010, + _ => unreachable!(), + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual store instruction starts. + sink.add_trap(trap_code); + } + + match &mem { + &AMode::Unscaled { rn, simm9 } => { + let reg = rn; + sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd)); + } + &AMode::UnsignedOffset { rn, uimm12 } => { + let reg = rn; + sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd)); + } + &AMode::RegReg { rn, rm } => { + let r1 = rn; + let r2 = rm; + sink.put4(enc_ldst_reg( + op, r1, r2, /* scaled = */ false, /* extendop = */ None, rd, + )); + } + &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => { + let r1 = rn; + let r2 = rm; + let extendop = match &mem { + &AMode::RegScaled { .. } => None, + &AMode::RegScaledExtended { extendop, .. } => Some(extendop), + _ => unreachable!(), + }; + sink.put4(enc_ldst_reg( + op, r1, r2, /* scaled = */ true, extendop, rd, + )); + } + &AMode::RegExtended { rn, rm, extendop } => { + let r1 = rn; + let r2 = rm; + sink.put4(enc_ldst_reg( + op, + r1, + r2, + /* scaled = */ false, + Some(extendop), + rd, + )); + } + &AMode::Label { .. } => { + panic!("Store to a MemLabel not implemented!"); + } + &AMode::SPPreIndexed { simm9 } => { + let reg = stack_reg(); + sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd)); + } + &AMode::SPPostIndexed { simm9 } => { + let reg = stack_reg(); + sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd)); + } + // Eliminated by `mem_finalize()` above. + &AMode::SPOffset { .. } + | &AMode::FPOffset { .. } + | &AMode::IncomingArg { .. } + | &AMode::SlotOffset { .. } + | &AMode::Const { .. } + | &AMode::RegOffset { .. } => { + panic!("Should not see {mem:?} here!") + } + } + } + + &Inst::StoreP64 { + rt, + rt2, + ref mem, + flags, + } => { + let mem = mem.clone(); + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual store instruction starts. + sink.add_trap(trap_code); + } + match &mem { + &PairAMode::SignedOffset { reg, simm7 } => { + assert_eq!(simm7.scale_ty, I64); + sink.put4(enc_ldst_pair(0b1010100100, simm7, reg, rt, rt2)); + } + &PairAMode::SPPreIndexed { simm7 } => { + assert_eq!(simm7.scale_ty, I64); + let reg = stack_reg(); + sink.put4(enc_ldst_pair(0b1010100110, simm7, reg, rt, rt2)); + } + &PairAMode::SPPostIndexed { simm7 } => { + assert_eq!(simm7.scale_ty, I64); + let reg = stack_reg(); + sink.put4(enc_ldst_pair(0b1010100010, simm7, reg, rt, rt2)); + } + } + } + &Inst::LoadP64 { + rt, + rt2, + ref mem, + flags, + } => { + let rt = rt.to_reg(); + let rt2 = rt2.to_reg(); + let mem = mem.clone(); + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + match &mem { + &PairAMode::SignedOffset { reg, simm7 } => { + assert_eq!(simm7.scale_ty, I64); + sink.put4(enc_ldst_pair(0b1010100101, simm7, reg, rt, rt2)); + } + &PairAMode::SPPreIndexed { simm7 } => { + assert_eq!(simm7.scale_ty, I64); + let reg = stack_reg(); + sink.put4(enc_ldst_pair(0b1010100111, simm7, reg, rt, rt2)); + } + &PairAMode::SPPostIndexed { simm7 } => { + assert_eq!(simm7.scale_ty, I64); + let reg = stack_reg(); + sink.put4(enc_ldst_pair(0b1010100011, simm7, reg, rt, rt2)); + } + } + } + &Inst::FpuLoadP64 { + rt, + rt2, + ref mem, + flags, + } + | &Inst::FpuLoadP128 { + rt, + rt2, + ref mem, + flags, + } => { + let rt = rt.to_reg(); + let rt2 = rt2.to_reg(); + let mem = mem.clone(); + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + let opc = match self { + &Inst::FpuLoadP64 { .. } => 0b01, + &Inst::FpuLoadP128 { .. } => 0b10, + _ => unreachable!(), + }; + + match &mem { + &PairAMode::SignedOffset { reg, simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + sink.put4(enc_ldst_vec_pair(opc, 0b10, true, simm7, reg, rt, rt2)); + } + &PairAMode::SPPreIndexed { simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + let reg = stack_reg(); + sink.put4(enc_ldst_vec_pair(opc, 0b11, true, simm7, reg, rt, rt2)); + } + &PairAMode::SPPostIndexed { simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + let reg = stack_reg(); + sink.put4(enc_ldst_vec_pair(opc, 0b01, true, simm7, reg, rt, rt2)); + } + } + } + &Inst::FpuStoreP64 { + rt, + rt2, + ref mem, + flags, + } + | &Inst::FpuStoreP128 { + rt, + rt2, + ref mem, + flags, + } => { + let mem = mem.clone(); + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual store instruction starts. + sink.add_trap(trap_code); + } + + let opc = match self { + &Inst::FpuStoreP64 { .. } => 0b01, + &Inst::FpuStoreP128 { .. } => 0b10, + _ => unreachable!(), + }; + + match &mem { + &PairAMode::SignedOffset { reg, simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + sink.put4(enc_ldst_vec_pair(opc, 0b10, false, simm7, reg, rt, rt2)); + } + &PairAMode::SPPreIndexed { simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + let reg = stack_reg(); + sink.put4(enc_ldst_vec_pair(opc, 0b11, false, simm7, reg, rt, rt2)); + } + &PairAMode::SPPostIndexed { simm7 } => { + assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16); + let reg = stack_reg(); + sink.put4(enc_ldst_vec_pair(opc, 0b01, false, simm7, reg, rt, rt2)); + } + } + } + &Inst::Mov { size, rd, rm } => { + assert!(rd.to_reg().class() == rm.class()); + assert!(rm.class() == RegClass::Int); + + match size { + OperandSize::Size64 => { + // MOV to SP is interpreted as MOV to XZR instead. And our codegen + // should never MOV to XZR. + assert!(rd.to_reg() != stack_reg()); + + if rm == stack_reg() { + // We can't use ORR here, so use an `add rd, sp, #0` instead. + let imm12 = Imm12::maybe_from_u64(0).unwrap(); + sink.put4(enc_arith_rr_imm12( + 0b100_10001, + imm12.shift_bits(), + imm12.imm_bits(), + rm, + rd, + )); + } else { + // Encoded as ORR rd, rm, zero. + sink.put4(enc_arith_rrr(0b10101010_000, 0b000_000, rd, zero_reg(), rm)); + } + } + OperandSize::Size32 => { + // MOV to SP is interpreted as MOV to XZR instead. And our codegen + // should never MOV to XZR. + assert!(machreg_to_gpr(rd.to_reg()) != 31); + // Encoded as ORR rd, rm, zero. + sink.put4(enc_arith_rrr(0b00101010_000, 0b000_000, rd, zero_reg(), rm)); + } + } + } + &Inst::MovFromPReg { rd, rm } => { + let rm: Reg = rm.into(); + debug_assert!([ + regs::fp_reg(), + regs::stack_reg(), + regs::link_reg(), + regs::pinned_reg() + ] + .contains(&rm)); + assert!(rm.class() == RegClass::Int); + assert!(rd.to_reg().class() == rm.class()); + let size = OperandSize::Size64; + Inst::Mov { size, rd, rm }.emit(sink, emit_info, state); + } + &Inst::MovToPReg { rd, rm } => { + let rd: Writable = Writable::from_reg(rd.into()); + debug_assert!([ + regs::fp_reg(), + regs::stack_reg(), + regs::link_reg(), + regs::pinned_reg() + ] + .contains(&rd.to_reg())); + assert!(rd.to_reg().class() == RegClass::Int); + assert!(rm.class() == rd.to_reg().class()); + let size = OperandSize::Size64; + Inst::Mov { size, rd, rm }.emit(sink, emit_info, state); + } + &Inst::MovWide { op, rd, imm, size } => { + sink.put4(enc_move_wide(op, rd, imm, size)); + } + &Inst::MovK { rd, rn, imm, size } => { + debug_assert_eq!(rn, rd.to_reg()); + sink.put4(enc_movk(rd, imm, size)); + } + &Inst::CSel { rd, rn, rm, cond } => { + sink.put4(enc_csel(rd, rn, rm, cond, 0, 0)); + } + &Inst::CSNeg { rd, rn, rm, cond } => { + sink.put4(enc_csel(rd, rn, rm, cond, 1, 1)); + } + &Inst::CSet { rd, cond } => { + sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 0, 1)); + } + &Inst::CSetm { rd, cond } => { + sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 1, 0)); + } + &Inst::CCmp { + size, + rn, + rm, + nzcv, + cond, + } => { + sink.put4(enc_ccmp(size, rn, rm, nzcv, cond)); + } + &Inst::CCmpImm { + size, + rn, + imm, + nzcv, + cond, + } => { + sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond)); + } + &Inst::AtomicRMW { + ty, + op, + rs, + rt, + rn, + flags, + } => { + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_acq_rel(ty, op, rs, rt, rn)); + } + &Inst::AtomicRMWLoop { ty, op, flags, .. } => { + /* Emit this: + again: + ldaxr{,b,h} x/w27, [x25] + // maybe sign extend + op x28, x27, x26 // op is add,sub,and,orr,eor + stlxr{,b,h} w24, x/w28, [x25] + cbnz x24, again + + Operand conventions: + IN: x25 (addr), x26 (2nd arg for op) + OUT: x27 (old value), x24 (trashed), x28 (trashed) + + It is unfortunate that, per the ARM documentation, x28 cannot be used for + both the store-data and success-flag operands of stlxr. This causes the + instruction's behaviour to be "CONSTRAINED UNPREDICTABLE", so we use x24 + instead for the success-flag. + */ + // TODO: We should not hardcode registers here, a better idea would be to + // pass some scratch registers in the AtomicRMWLoop pseudo-instruction, and use those + let xzr = zero_reg(); + let x24 = xreg(24); + let x25 = xreg(25); + let x26 = xreg(26); + let x27 = xreg(27); + let x28 = xreg(28); + let x24wr = writable_xreg(24); + let x27wr = writable_xreg(27); + let x28wr = writable_xreg(28); + let again_label = sink.get_label(); + + // again: + sink.bind_label(again_label, &mut state.ctrl_plane); + + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_ldaxr(ty, x27wr, x25)); // ldaxr x27, [x25] + let size = OperandSize::from_ty(ty); + let sign_ext = match op { + AtomicRMWLoopOp::Smin | AtomicRMWLoopOp::Smax => match ty { + I16 => Some((ExtendOp::SXTH, 16)), + I8 => Some((ExtendOp::SXTB, 8)), + _ => None, + }, + _ => None, + }; + + // sxt{b|h} the loaded result if necessary. + if sign_ext.is_some() { + let (_, from_bits) = sign_ext.unwrap(); + Inst::Extend { + rd: x27wr, + rn: x27, + signed: true, + from_bits, + to_bits: size.bits(), + } + .emit(sink, emit_info, state); + } + + match op { + AtomicRMWLoopOp::Xchg => {} // do nothing + AtomicRMWLoopOp::Nand => { + // and x28, x27, x26 + // mvn x28, x28 + + Inst::AluRRR { + alu_op: ALUOp::And, + size, + rd: x28wr, + rn: x27, + rm: x26, + } + .emit(sink, emit_info, state); + + Inst::AluRRR { + alu_op: ALUOp::OrrNot, + size, + rd: x28wr, + rn: xzr, + rm: x28, + } + .emit(sink, emit_info, state); + } + AtomicRMWLoopOp::Umin + | AtomicRMWLoopOp::Umax + | AtomicRMWLoopOp::Smin + | AtomicRMWLoopOp::Smax => { + // cmp x27, x26 {?sxt} + // csel.op x28, x27, x26 + + let cond = match op { + AtomicRMWLoopOp::Umin => Cond::Lo, + AtomicRMWLoopOp::Umax => Cond::Hi, + AtomicRMWLoopOp::Smin => Cond::Lt, + AtomicRMWLoopOp::Smax => Cond::Gt, + _ => unreachable!(), + }; + + if sign_ext.is_some() { + let (extendop, _) = sign_ext.unwrap(); + Inst::AluRRRExtend { + alu_op: ALUOp::SubS, + size, + rd: writable_zero_reg(), + rn: x27, + rm: x26, + extendop, + } + .emit(sink, emit_info, state); + } else { + Inst::AluRRR { + alu_op: ALUOp::SubS, + size, + rd: writable_zero_reg(), + rn: x27, + rm: x26, + } + .emit(sink, emit_info, state); + } + + Inst::CSel { + cond, + rd: x28wr, + rn: x27, + rm: x26, + } + .emit(sink, emit_info, state); + } + _ => { + // add/sub/and/orr/eor x28, x27, x26 + let alu_op = match op { + AtomicRMWLoopOp::Add => ALUOp::Add, + AtomicRMWLoopOp::Sub => ALUOp::Sub, + AtomicRMWLoopOp::And => ALUOp::And, + AtomicRMWLoopOp::Orr => ALUOp::Orr, + AtomicRMWLoopOp::Eor => ALUOp::Eor, + AtomicRMWLoopOp::Nand + | AtomicRMWLoopOp::Umin + | AtomicRMWLoopOp::Umax + | AtomicRMWLoopOp::Smin + | AtomicRMWLoopOp::Smax + | AtomicRMWLoopOp::Xchg => unreachable!(), + }; + + Inst::AluRRR { + alu_op, + size, + rd: x28wr, + rn: x27, + rm: x26, + } + .emit(sink, emit_info, state); + } + } + + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + if op == AtomicRMWLoopOp::Xchg { + sink.put4(enc_stlxr(ty, x24wr, x26, x25)); // stlxr w24, x26, [x25] + } else { + sink.put4(enc_stlxr(ty, x24wr, x28, x25)); // stlxr w24, x28, [x25] + } + + // cbnz w24, again + // Note, we're actually testing x24, and relying on the default zero-high-half + // rule in the assignment that `stlxr` does. + let br_offset = sink.cur_offset(); + sink.put4(enc_conditional_br( + BranchTarget::Label(again_label), + CondBrKind::NotZero(x24, OperandSize::Size64), + )); + sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19); + } + &Inst::AtomicCAS { + rd, + rs, + rt, + rn, + ty, + flags, + } => { + debug_assert_eq!(rd.to_reg(), rs); + let size = match ty { + I8 => 0b00, + I16 => 0b01, + I32 => 0b10, + I64 => 0b11, + _ => panic!("Unsupported type: {ty}"), + }; + + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_cas(size, rd, rt, rn)); + } + &Inst::AtomicCASLoop { ty, flags, .. } => { + /* Emit this: + again: + ldaxr{,b,h} x/w27, [x25] + cmp x27, x/w26 uxt{b,h} + b.ne out + stlxr{,b,h} w24, x/w28, [x25] + cbnz x24, again + out: + + Operand conventions: + IN: x25 (addr), x26 (expected value), x28 (replacement value) + OUT: x27 (old value), x24 (trashed) + */ + let x24 = xreg(24); + let x25 = xreg(25); + let x26 = xreg(26); + let x27 = xreg(27); + let x28 = xreg(28); + let xzrwr = writable_zero_reg(); + let x24wr = writable_xreg(24); + let x27wr = writable_xreg(27); + let again_label = sink.get_label(); + let out_label = sink.get_label(); + + // again: + sink.bind_label(again_label, &mut state.ctrl_plane); + + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + // ldaxr x27, [x25] + sink.put4(enc_ldaxr(ty, x27wr, x25)); + + // The top 32-bits are zero-extended by the ldaxr so we don't + // have to use UXTW, just the x-form of the register. + let (bit21, extend_op) = match ty { + I8 => (0b1, 0b000000), + I16 => (0b1, 0b001000), + _ => (0b0, 0b000000), + }; + let bits_31_21 = 0b111_01011_000 | bit21; + // cmp x27, x26 (== subs xzr, x27, x26) + sink.put4(enc_arith_rrr(bits_31_21, extend_op, xzrwr, x27, x26)); + + // b.ne out + let br_out_offset = sink.cur_offset(); + sink.put4(enc_conditional_br( + BranchTarget::Label(out_label), + CondBrKind::Cond(Cond::Ne), + )); + sink.use_label_at_offset(br_out_offset, out_label, LabelUse::Branch19); + + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_stlxr(ty, x24wr, x28, x25)); // stlxr w24, x28, [x25] + + // cbnz w24, again. + // Note, we're actually testing x24, and relying on the default zero-high-half + // rule in the assignment that `stlxr` does. + let br_again_offset = sink.cur_offset(); + sink.put4(enc_conditional_br( + BranchTarget::Label(again_label), + CondBrKind::NotZero(x24, OperandSize::Size64), + )); + sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19); + + // out: + sink.bind_label(out_label, &mut state.ctrl_plane); + } + &Inst::LoadAcquire { + access_ty, + rt, + rn, + flags, + } => { + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_ldar(access_ty, rt, rn)); + } + &Inst::StoreRelease { + access_ty, + rt, + rn, + flags, + } => { + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + + sink.put4(enc_stlr(access_ty, rt, rn)); + } + &Inst::Fence {} => { + sink.put4(enc_dmb_ish()); // dmb ish + } + &Inst::Csdb {} => { + sink.put4(0xd503229f); + } + &Inst::FpuMove32 { rd, rn } => { + sink.put4(enc_fpurr(0b000_11110_00_1_000000_10000, rd, rn)); + } + &Inst::FpuMove64 { rd, rn } => { + sink.put4(enc_fpurr(0b000_11110_01_1_000000_10000, rd, rn)); + } + &Inst::FpuMove128 { rd, rn } => { + sink.put4(enc_vecmov(/* 16b = */ true, rd, rn)); + } + &Inst::FpuMoveFromVec { rd, rn, idx, size } => { + let (imm5, shift, mask) = match size.lane_size() { + ScalarSize::Size32 => (0b00100, 3, 0b011), + ScalarSize::Size64 => (0b01000, 4, 0b001), + _ => unimplemented!(), + }; + debug_assert_eq!(idx & mask, idx); + let imm5 = imm5 | ((idx as u32) << shift); + sink.put4( + 0b010_11110000_00000_000001_00000_00000 + | (imm5 << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::FpuExtend { rd, rn, size } => { + sink.put4(enc_fpurr( + 0b000_11110_00_1_000000_10000 | (size.ftype() << 12), + rd, + rn, + )); + } + &Inst::FpuRR { + fpu_op, + size, + rd, + rn, + } => { + let top22 = match fpu_op { + FPUOp1::Abs => 0b000_11110_00_1_000001_10000, + FPUOp1::Neg => 0b000_11110_00_1_000010_10000, + FPUOp1::Sqrt => 0b000_11110_00_1_000011_10000, + FPUOp1::Cvt32To64 => { + debug_assert_eq!(size, ScalarSize::Size32); + 0b000_11110_00_1_000101_10000 + } + FPUOp1::Cvt64To32 => { + debug_assert_eq!(size, ScalarSize::Size64); + 0b000_11110_01_1_000100_10000 + } + }; + let top22 = top22 | size.ftype() << 12; + sink.put4(enc_fpurr(top22, rd, rn)); + } + &Inst::FpuRRR { + fpu_op, + size, + rd, + rn, + rm, + } => { + let top22 = match fpu_op { + FPUOp2::Add => 0b000_11110_00_1_00000_001010, + FPUOp2::Sub => 0b000_11110_00_1_00000_001110, + FPUOp2::Mul => 0b000_11110_00_1_00000_000010, + FPUOp2::Div => 0b000_11110_00_1_00000_000110, + FPUOp2::Max => 0b000_11110_00_1_00000_010010, + FPUOp2::Min => 0b000_11110_00_1_00000_010110, + }; + let top22 = top22 | size.ftype() << 12; + sink.put4(enc_fpurrr(top22, rd, rn, rm)); + } + &Inst::FpuRRI { fpu_op, rd, rn } => match fpu_op { + FPUOpRI::UShr32(imm) => { + debug_assert_eq!(32, imm.lane_size_in_bits); + sink.put4( + 0b0_0_1_011110_0000000_00_0_0_0_1_00000_00000 + | imm.enc() << 16 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()), + ) + } + FPUOpRI::UShr64(imm) => { + debug_assert_eq!(64, imm.lane_size_in_bits); + sink.put4( + 0b01_1_111110_0000000_00_0_0_0_1_00000_00000 + | imm.enc() << 16 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()), + ) + } + }, + &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => { + debug_assert_eq!(rd.to_reg(), ri); + match fpu_op { + FPUOpRIMod::Sli64(imm) => { + debug_assert_eq!(64, imm.lane_size_in_bits); + sink.put4( + 0b01_1_111110_0000000_010101_00000_00000 + | imm.enc() << 16 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()), + ) + } + FPUOpRIMod::Sli32(imm) => { + debug_assert_eq!(32, imm.lane_size_in_bits); + sink.put4( + 0b0_0_1_011110_0000000_010101_00000_00000 + | imm.enc() << 16 + | machreg_to_vec(rn) << 5 + | machreg_to_vec(rd.to_reg()), + ) + } + } + } + &Inst::FpuRRRR { + fpu_op, + size, + rd, + rn, + rm, + ra, + } => { + let top17 = match fpu_op { + FPUOp3::MAdd => 0b000_11111_00_0_00000_0, + FPUOp3::MSub => 0b000_11111_00_0_00000_1, + FPUOp3::NMAdd => 0b000_11111_00_1_00000_0, + FPUOp3::NMSub => 0b000_11111_00_1_00000_1, + }; + let top17 = top17 | size.ftype() << 7; + sink.put4(enc_fpurrrr(top17, rd, rn, rm, ra)); + } + &Inst::VecMisc { op, rd, rn, size } => { + let (q, enc_size) = size.enc_size(); + let (u, bits_12_16, size) = match op { + VecMisc2::Not => (0b1, 0b00101, 0b00), + VecMisc2::Neg => (0b1, 0b01011, enc_size), + VecMisc2::Abs => (0b0, 0b01011, enc_size), + VecMisc2::Fabs => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b01111, enc_size) + } + VecMisc2::Fneg => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b1, 0b01111, enc_size) + } + VecMisc2::Fsqrt => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b1, 0b11111, enc_size) + } + VecMisc2::Rev16 => { + debug_assert_eq!(size, VectorSize::Size8x16); + (0b0, 0b00001, enc_size) + } + VecMisc2::Rev32 => { + debug_assert!(size == VectorSize::Size8x16 || size == VectorSize::Size16x8); + (0b1, 0b00000, enc_size) + } + VecMisc2::Rev64 => { + debug_assert!( + size == VectorSize::Size8x16 + || size == VectorSize::Size16x8 + || size == VectorSize::Size32x4 + ); + (0b0, 0b00000, enc_size) + } + VecMisc2::Fcvtzs => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b11011, enc_size) + } + VecMisc2::Fcvtzu => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b1, 0b11011, enc_size) + } + VecMisc2::Scvtf => { + debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2); + (0b0, 0b11101, enc_size & 0b1) + } + VecMisc2::Ucvtf => { + debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2); + (0b1, 0b11101, enc_size & 0b1) + } + VecMisc2::Frintn => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b11000, enc_size & 0b01) + } + VecMisc2::Frintz => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b11001, enc_size) + } + VecMisc2::Frintm => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b11001, enc_size & 0b01) + } + VecMisc2::Frintp => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b11000, enc_size) + } + VecMisc2::Cnt => { + debug_assert!(size == VectorSize::Size8x8 || size == VectorSize::Size8x16); + (0b0, 0b00101, enc_size) + } + VecMisc2::Cmeq0 => (0b0, 0b01001, enc_size), + VecMisc2::Cmge0 => (0b1, 0b01000, enc_size), + VecMisc2::Cmgt0 => (0b0, 0b01000, enc_size), + VecMisc2::Cmle0 => (0b1, 0b01001, enc_size), + VecMisc2::Cmlt0 => (0b0, 0b01010, enc_size), + VecMisc2::Fcmeq0 => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b01101, enc_size) + } + VecMisc2::Fcmge0 => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b1, 0b01100, enc_size) + } + VecMisc2::Fcmgt0 => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b01100, enc_size) + } + VecMisc2::Fcmle0 => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b1, 0b01101, enc_size) + } + VecMisc2::Fcmlt0 => { + debug_assert!( + size == VectorSize::Size32x2 + || size == VectorSize::Size32x4 + || size == VectorSize::Size64x2 + ); + (0b0, 0b01110, enc_size) + } + }; + sink.put4(enc_vec_rr_misc((q << 1) | u, size, bits_12_16, rd, rn)); + } + &Inst::VecLanes { op, rd, rn, size } => { + let (q, size) = match size { + VectorSize::Size8x8 => (0b0, 0b00), + VectorSize::Size8x16 => (0b1, 0b00), + VectorSize::Size16x4 => (0b0, 0b01), + VectorSize::Size16x8 => (0b1, 0b01), + VectorSize::Size32x4 => (0b1, 0b10), + _ => unreachable!(), + }; + let (u, opcode) = match op { + VecLanesOp::Uminv => (0b1, 0b11010), + VecLanesOp::Addv => (0b0, 0b11011), + }; + sink.put4(enc_vec_lanes(q, u, size, opcode, rd, rn)); + } + &Inst::VecShiftImm { + op, + rd, + rn, + size, + imm, + } => { + let (is_shr, mut template) = match op { + VecShiftImmOp::Ushr => (true, 0b_001_011110_0000_000_000001_00000_00000_u32), + VecShiftImmOp::Sshr => (true, 0b_000_011110_0000_000_000001_00000_00000_u32), + VecShiftImmOp::Shl => (false, 0b_000_011110_0000_000_010101_00000_00000_u32), + }; + if size.is_128bits() { + template |= 0b1 << 30; + } + let imm = imm as u32; + // Deal with the somewhat strange encoding scheme for, and limits on, + // the shift amount. + let immh_immb = match (size.lane_size(), is_shr) { + (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => { + 0b_1000_000_u32 | (64 - imm) + } + (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => { + 0b_0100_000_u32 | (32 - imm) + } + (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => { + 0b_0010_000_u32 | (16 - imm) + } + (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => { + 0b_0001_000_u32 | (8 - imm) + } + (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm, + (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm, + (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm, + (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm, + _ => panic!( + "aarch64: Inst::VecShiftImm: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}" + ), + }; + let rn_enc = machreg_to_vec(rn); + let rd_enc = machreg_to_vec(rd.to_reg()); + sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc); + } + &Inst::VecShiftImmMod { + op, + rd, + ri, + rn, + size, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let (is_shr, mut template) = match op { + VecShiftImmModOp::Sli => (false, 0b_001_011110_0000_000_010101_00000_00000_u32), + }; + if size.is_128bits() { + template |= 0b1 << 30; + } + let imm = imm as u32; + // Deal with the somewhat strange encoding scheme for, and limits on, + // the shift amount. + let immh_immb = match (size.lane_size(), is_shr) { + (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => { + 0b_1000_000_u32 | (64 - imm) + } + (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => { + 0b_0100_000_u32 | (32 - imm) + } + (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => { + 0b_0010_000_u32 | (16 - imm) + } + (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => { + 0b_0001_000_u32 | (8 - imm) + } + (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm, + (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm, + (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm, + (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm, + _ => panic!( + "aarch64: Inst::VecShiftImmMod: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}" + ), + }; + let rn_enc = machreg_to_vec(rn); + let rd_enc = machreg_to_vec(rd.to_reg()); + sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc); + } + &Inst::VecExtract { rd, rn, rm, imm4 } => { + if imm4 < 16 { + let template = 0b_01_101110_000_00000_0_0000_0_00000_00000_u32; + let rm_enc = machreg_to_vec(rm); + let rn_enc = machreg_to_vec(rn); + let rd_enc = machreg_to_vec(rd.to_reg()); + sink.put4( + template | (rm_enc << 16) | ((imm4 as u32) << 11) | (rn_enc << 5) | rd_enc, + ); + } else { + panic!("aarch64: Inst::VecExtract: emit: invalid extract index {imm4}"); + } + } + &Inst::VecTbl { rd, rn, rm } => { + sink.put4(enc_tbl(/* is_extension = */ false, 0b00, rd, rn, rm)); + } + &Inst::VecTblExt { rd, ri, rn, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + sink.put4(enc_tbl(/* is_extension = */ true, 0b00, rd, rn, rm)); + } + &Inst::VecTbl2 { rd, rn, rn2, rm } => { + assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32); + sink.put4(enc_tbl(/* is_extension = */ false, 0b01, rd, rn, rm)); + } + &Inst::VecTbl2Ext { + rd, + ri, + rn, + rn2, + rm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32); + sink.put4(enc_tbl(/* is_extension = */ true, 0b01, rd, rn, rm)); + } + &Inst::FpuCmp { size, rn, rm } => { + sink.put4(enc_fcmp(size, rn, rm)); + } + &Inst::FpuToInt { op, rd, rn } => { + let top16 = match op { + // FCVTZS (32/32-bit) + FpuToIntOp::F32ToI32 => 0b000_11110_00_1_11_000, + // FCVTZU (32/32-bit) + FpuToIntOp::F32ToU32 => 0b000_11110_00_1_11_001, + // FCVTZS (32/64-bit) + FpuToIntOp::F32ToI64 => 0b100_11110_00_1_11_000, + // FCVTZU (32/64-bit) + FpuToIntOp::F32ToU64 => 0b100_11110_00_1_11_001, + // FCVTZS (64/32-bit) + FpuToIntOp::F64ToI32 => 0b000_11110_01_1_11_000, + // FCVTZU (64/32-bit) + FpuToIntOp::F64ToU32 => 0b000_11110_01_1_11_001, + // FCVTZS (64/64-bit) + FpuToIntOp::F64ToI64 => 0b100_11110_01_1_11_000, + // FCVTZU (64/64-bit) + FpuToIntOp::F64ToU64 => 0b100_11110_01_1_11_001, + }; + sink.put4(enc_fputoint(top16, rd, rn)); + } + &Inst::IntToFpu { op, rd, rn } => { + let top16 = match op { + // SCVTF (32/32-bit) + IntToFpuOp::I32ToF32 => 0b000_11110_00_1_00_010, + // UCVTF (32/32-bit) + IntToFpuOp::U32ToF32 => 0b000_11110_00_1_00_011, + // SCVTF (64/32-bit) + IntToFpuOp::I64ToF32 => 0b100_11110_00_1_00_010, + // UCVTF (64/32-bit) + IntToFpuOp::U64ToF32 => 0b100_11110_00_1_00_011, + // SCVTF (32/64-bit) + IntToFpuOp::I32ToF64 => 0b000_11110_01_1_00_010, + // UCVTF (32/64-bit) + IntToFpuOp::U32ToF64 => 0b000_11110_01_1_00_011, + // SCVTF (64/64-bit) + IntToFpuOp::I64ToF64 => 0b100_11110_01_1_00_010, + // UCVTF (64/64-bit) + IntToFpuOp::U64ToF64 => 0b100_11110_01_1_00_011, + }; + sink.put4(enc_inttofpu(top16, rd, rn)); + } + &Inst::FpuCSel16 { rd, rn, rm, cond } => { + sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size16)); + } + &Inst::FpuCSel32 { rd, rn, rm, cond } => { + sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size32)); + } + &Inst::FpuCSel64 { rd, rn, rm, cond } => { + sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size64)); + } + &Inst::FpuRound { op, rd, rn } => { + let top22 = match op { + FpuRoundMode::Minus32 => 0b000_11110_00_1_001_010_10000, + FpuRoundMode::Minus64 => 0b000_11110_01_1_001_010_10000, + FpuRoundMode::Plus32 => 0b000_11110_00_1_001_001_10000, + FpuRoundMode::Plus64 => 0b000_11110_01_1_001_001_10000, + FpuRoundMode::Zero32 => 0b000_11110_00_1_001_011_10000, + FpuRoundMode::Zero64 => 0b000_11110_01_1_001_011_10000, + FpuRoundMode::Nearest32 => 0b000_11110_00_1_001_000_10000, + FpuRoundMode::Nearest64 => 0b000_11110_01_1_001_000_10000, + }; + sink.put4(enc_fround(top22, rd, rn)); + } + &Inst::MovToFpu { rd, rn, size } => { + let template = match size { + ScalarSize::Size16 => 0b000_11110_11_1_00_111_000000_00000_00000, + ScalarSize::Size32 => 0b000_11110_00_1_00_111_000000_00000_00000, + ScalarSize::Size64 => 0b100_11110_01_1_00_111_000000_00000_00000, + _ => unreachable!(), + }; + sink.put4(template | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg())); + } + &Inst::FpuMoveFPImm { rd, imm, size } => { + sink.put4( + 0b000_11110_00_1_00_000_000100_00000_00000 + | size.ftype() << 22 + | ((imm.enc_bits() as u32) << 13) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::MovToVec { + rd, + ri, + rn, + idx, + size, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let (imm5, shift) = match size.lane_size() { + ScalarSize::Size8 => (0b00001, 1), + ScalarSize::Size16 => (0b00010, 2), + ScalarSize::Size32 => (0b00100, 3), + ScalarSize::Size64 => (0b01000, 4), + _ => unreachable!(), + }; + debug_assert_eq!(idx & (0b11111 >> shift), idx); + let imm5 = imm5 | ((idx as u32) << shift); + sink.put4( + 0b010_01110000_00000_0_0011_1_00000_00000 + | (imm5 << 16) + | (machreg_to_gpr(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::MovFromVec { rd, rn, idx, size } => { + let (q, imm5, shift, mask) = match size { + ScalarSize::Size8 => (0b0, 0b00001, 1, 0b1111), + ScalarSize::Size16 => (0b0, 0b00010, 2, 0b0111), + ScalarSize::Size32 => (0b0, 0b00100, 3, 0b0011), + ScalarSize::Size64 => (0b1, 0b01000, 4, 0b0001), + _ => panic!("Unexpected scalar FP operand size: {size:?}"), + }; + debug_assert_eq!(idx & mask, idx); + let imm5 = imm5 | ((idx as u32) << shift); + sink.put4( + 0b000_01110000_00000_0_0111_1_00000_00000 + | (q << 30) + | (imm5 << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_gpr(rd.to_reg()), + ); + } + &Inst::MovFromVecSigned { + rd, + rn, + idx, + size, + scalar_size, + } => { + let (imm5, shift, half) = match size { + VectorSize::Size8x8 => (0b00001, 1, true), + VectorSize::Size8x16 => (0b00001, 1, false), + VectorSize::Size16x4 => (0b00010, 2, true), + VectorSize::Size16x8 => (0b00010, 2, false), + VectorSize::Size32x2 => { + debug_assert_ne!(scalar_size, OperandSize::Size32); + (0b00100, 3, true) + } + VectorSize::Size32x4 => { + debug_assert_ne!(scalar_size, OperandSize::Size32); + (0b00100, 3, false) + } + _ => panic!("Unexpected vector operand size"), + }; + debug_assert_eq!(idx & (0b11111 >> (half as u32 + shift)), idx); + let imm5 = imm5 | ((idx as u32) << shift); + sink.put4( + 0b000_01110000_00000_0_0101_1_00000_00000 + | (scalar_size.is64() as u32) << 30 + | (imm5 << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_gpr(rd.to_reg()), + ); + } + &Inst::VecDup { rd, rn, size } => { + let q = size.is_128bits() as u32; + let imm5 = match size.lane_size() { + ScalarSize::Size8 => 0b00001, + ScalarSize::Size16 => 0b00010, + ScalarSize::Size32 => 0b00100, + ScalarSize::Size64 => 0b01000, + _ => unreachable!(), + }; + sink.put4( + 0b0_0_0_01110000_00000_000011_00000_00000 + | (q << 30) + | (imm5 << 16) + | (machreg_to_gpr(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::VecDupFromFpu { rd, rn, size, lane } => { + let q = size.is_128bits() as u32; + let imm5 = match size.lane_size() { + ScalarSize::Size8 => { + assert!(lane < 16); + 0b00001 | (u32::from(lane) << 1) + } + ScalarSize::Size16 => { + assert!(lane < 8); + 0b00010 | (u32::from(lane) << 2) + } + ScalarSize::Size32 => { + assert!(lane < 4); + 0b00100 | (u32::from(lane) << 3) + } + ScalarSize::Size64 => { + assert!(lane < 2); + 0b01000 | (u32::from(lane) << 4) + } + _ => unimplemented!(), + }; + sink.put4( + 0b000_01110000_00000_000001_00000_00000 + | (q << 30) + | (imm5 << 16) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::VecDupFPImm { rd, imm, size } => { + let imm = imm.enc_bits(); + let op = match size.lane_size() { + ScalarSize::Size32 => 0, + ScalarSize::Size64 => 1, + _ => unimplemented!(), + }; + let q_op = op | ((size.is_128bits() as u32) << 1); + + sink.put4(enc_asimd_mod_imm(rd, q_op, 0b1111, imm)); + } + &Inst::VecDupImm { + rd, + imm, + invert, + size, + } => { + let (imm, shift, shift_ones) = imm.value(); + let (op, cmode) = match size.lane_size() { + ScalarSize::Size8 => { + assert!(!invert); + assert_eq!(shift, 0); + + (0, 0b1110) + } + ScalarSize::Size16 => { + let s = shift & 8; + + assert!(!shift_ones); + assert_eq!(s, shift); + + (invert as u32, 0b1000 | (s >> 2)) + } + ScalarSize::Size32 => { + if shift_ones { + assert!(shift == 8 || shift == 16); + + (invert as u32, 0b1100 | (shift >> 4)) + } else { + let s = shift & 24; + + assert_eq!(s, shift); + + (invert as u32, 0b0000 | (s >> 2)) + } + } + ScalarSize::Size64 => { + assert!(!invert); + assert_eq!(shift, 0); + + (1, 0b1110) + } + _ => unreachable!(), + }; + let q_op = op | ((size.is_128bits() as u32) << 1); + + sink.put4(enc_asimd_mod_imm(rd, q_op, cmode, imm)); + } + &Inst::VecExtend { + t, + rd, + rn, + high_half, + lane_size, + } => { + let immh = match lane_size { + ScalarSize::Size16 => 0b001, + ScalarSize::Size32 => 0b010, + ScalarSize::Size64 => 0b100, + _ => panic!("Unexpected VecExtend to lane size of {lane_size:?}"), + }; + let u = match t { + VecExtendOp::Sxtl => 0b0, + VecExtendOp::Uxtl => 0b1, + }; + sink.put4( + 0b000_011110_0000_000_101001_00000_00000 + | ((high_half as u32) << 30) + | (u << 29) + | (immh << 19) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::VecRRLong { + op, + rd, + rn, + high_half, + } => { + let (u, size, bits_12_16) = match op { + VecRRLongOp::Fcvtl16 => (0b0, 0b00, 0b10111), + VecRRLongOp::Fcvtl32 => (0b0, 0b01, 0b10111), + VecRRLongOp::Shll8 => (0b1, 0b00, 0b10011), + VecRRLongOp::Shll16 => (0b1, 0b01, 0b10011), + VecRRLongOp::Shll32 => (0b1, 0b10, 0b10011), + }; + + sink.put4(enc_vec_rr_misc( + ((high_half as u32) << 1) | u, + size, + bits_12_16, + rd, + rn, + )); + } + &Inst::VecRRNarrowLow { + op, + rd, + rn, + lane_size, + } + | &Inst::VecRRNarrowHigh { + op, + rd, + rn, + lane_size, + .. + } => { + let high_half = match self { + &Inst::VecRRNarrowLow { .. } => false, + &Inst::VecRRNarrowHigh { .. } => true, + _ => unreachable!(), + }; + + let size = match lane_size { + ScalarSize::Size8 => 0b00, + ScalarSize::Size16 => 0b01, + ScalarSize::Size32 => 0b10, + _ => panic!("unsupported size: {lane_size:?}"), + }; + + // Floats use a single bit, to encode either half or single. + let size = match op { + VecRRNarrowOp::Fcvtn => size >> 1, + _ => size, + }; + + let (u, bits_12_16) = match op { + VecRRNarrowOp::Xtn => (0b0, 0b10010), + VecRRNarrowOp::Sqxtn => (0b0, 0b10100), + VecRRNarrowOp::Sqxtun => (0b1, 0b10010), + VecRRNarrowOp::Uqxtn => (0b1, 0b10100), + VecRRNarrowOp::Fcvtn => (0b0, 0b10110), + }; + + sink.put4(enc_vec_rr_misc( + ((high_half as u32) << 1) | u, + size, + bits_12_16, + rd, + rn, + )); + } + &Inst::VecMovElement { + rd, + ri, + rn, + dest_idx, + src_idx, + size, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let (imm5, shift) = match size.lane_size() { + ScalarSize::Size8 => (0b00001, 1), + ScalarSize::Size16 => (0b00010, 2), + ScalarSize::Size32 => (0b00100, 3), + ScalarSize::Size64 => (0b01000, 4), + _ => unreachable!(), + }; + let mask = 0b11111 >> shift; + debug_assert_eq!(dest_idx & mask, dest_idx); + debug_assert_eq!(src_idx & mask, src_idx); + let imm4 = (src_idx as u32) << (shift - 1); + let imm5 = imm5 | ((dest_idx as u32) << shift); + sink.put4( + 0b011_01110000_00000_0_0000_1_00000_00000 + | (imm5 << 16) + | (imm4 << 11) + | (machreg_to_vec(rn) << 5) + | machreg_to_vec(rd.to_reg()), + ); + } + &Inst::VecRRPair { op, rd, rn } => { + let bits_12_16 = match op { + VecPairOp::Addp => 0b11011, + }; + + sink.put4(enc_vec_rr_pair(bits_12_16, rd, rn)); + } + &Inst::VecRRRLong { + rd, + rn, + rm, + alu_op, + high_half, + } => { + let (u, size, bit14) = match alu_op { + VecRRRLongOp::Smull8 => (0b0, 0b00, 0b1), + VecRRRLongOp::Smull16 => (0b0, 0b01, 0b1), + VecRRRLongOp::Smull32 => (0b0, 0b10, 0b1), + VecRRRLongOp::Umull8 => (0b1, 0b00, 0b1), + VecRRRLongOp::Umull16 => (0b1, 0b01, 0b1), + VecRRRLongOp::Umull32 => (0b1, 0b10, 0b1), + }; + sink.put4(enc_vec_rrr_long( + high_half as u32, + u, + size, + bit14, + rm, + rn, + rd, + )); + } + &Inst::VecRRRLongMod { + rd, + ri, + rn, + rm, + alu_op, + high_half, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let (u, size, bit14) = match alu_op { + VecRRRLongModOp::Umlal8 => (0b1, 0b00, 0b0), + VecRRRLongModOp::Umlal16 => (0b1, 0b01, 0b0), + VecRRRLongModOp::Umlal32 => (0b1, 0b10, 0b0), + }; + sink.put4(enc_vec_rrr_long( + high_half as u32, + u, + size, + bit14, + rm, + rn, + rd, + )); + } + &Inst::VecRRPairLong { op, rd, rn } => { + let (u, size) = match op { + VecRRPairLongOp::Saddlp8 => (0b0, 0b0), + VecRRPairLongOp::Uaddlp8 => (0b1, 0b0), + VecRRPairLongOp::Saddlp16 => (0b0, 0b1), + VecRRPairLongOp::Uaddlp16 => (0b1, 0b1), + }; + + sink.put4(enc_vec_rr_pair_long(u, size, rd, rn)); + } + &Inst::VecRRR { + rd, + rn, + rm, + alu_op, + size, + } => { + let (q, enc_size) = size.enc_size(); + let is_float = match alu_op { + VecALUOp::Fcmeq + | VecALUOp::Fcmgt + | VecALUOp::Fcmge + | VecALUOp::Fadd + | VecALUOp::Fsub + | VecALUOp::Fdiv + | VecALUOp::Fmax + | VecALUOp::Fmin + | VecALUOp::Fmul => true, + _ => false, + }; + + let (top11, bit15_10) = match alu_op { + VecALUOp::Sqadd => (0b000_01110_00_1 | enc_size << 1, 0b000011), + VecALUOp::Sqsub => (0b000_01110_00_1 | enc_size << 1, 0b001011), + VecALUOp::Uqadd => (0b001_01110_00_1 | enc_size << 1, 0b000011), + VecALUOp::Uqsub => (0b001_01110_00_1 | enc_size << 1, 0b001011), + VecALUOp::Cmeq => (0b001_01110_00_1 | enc_size << 1, 0b100011), + VecALUOp::Cmge => (0b000_01110_00_1 | enc_size << 1, 0b001111), + VecALUOp::Cmgt => (0b000_01110_00_1 | enc_size << 1, 0b001101), + VecALUOp::Cmhi => (0b001_01110_00_1 | enc_size << 1, 0b001101), + VecALUOp::Cmhs => (0b001_01110_00_1 | enc_size << 1, 0b001111), + VecALUOp::Fcmeq => (0b000_01110_00_1, 0b111001), + VecALUOp::Fcmgt => (0b001_01110_10_1, 0b111001), + VecALUOp::Fcmge => (0b001_01110_00_1, 0b111001), + // The following logical instructions operate on bytes, so are not encoded differently + // for the different vector types. + VecALUOp::And => (0b000_01110_00_1, 0b000111), + VecALUOp::Bic => (0b000_01110_01_1, 0b000111), + VecALUOp::Orr => (0b000_01110_10_1, 0b000111), + VecALUOp::Eor => (0b001_01110_00_1, 0b000111), + VecALUOp::Umaxp => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b001_01110_00_1 | enc_size << 1, 0b101001) + } + VecALUOp::Add => (0b000_01110_00_1 | enc_size << 1, 0b100001), + VecALUOp::Sub => (0b001_01110_00_1 | enc_size << 1, 0b100001), + VecALUOp::Mul => { + debug_assert_ne!(size, VectorSize::Size64x2); + (0b000_01110_00_1 | enc_size << 1, 0b100111) + } + VecALUOp::Sshl => (0b000_01110_00_1 | enc_size << 1, 0b010001), + VecALUOp::Ushl => (0b001_01110_00_1 | enc_size << 1, 0b010001), + VecALUOp::Umin => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b001_01110_00_1 | enc_size << 1, 0b011011) + } + VecALUOp::Smin => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b000_01110_00_1 | enc_size << 1, 0b011011) + } + VecALUOp::Umax => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b001_01110_00_1 | enc_size << 1, 0b011001) + } + VecALUOp::Smax => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b000_01110_00_1 | enc_size << 1, 0b011001) + } + VecALUOp::Urhadd => { + debug_assert_ne!(size, VectorSize::Size64x2); + + (0b001_01110_00_1 | enc_size << 1, 0b000101) + } + VecALUOp::Fadd => (0b000_01110_00_1, 0b110101), + VecALUOp::Fsub => (0b000_01110_10_1, 0b110101), + VecALUOp::Fdiv => (0b001_01110_00_1, 0b111111), + VecALUOp::Fmax => (0b000_01110_00_1, 0b111101), + VecALUOp::Fmin => (0b000_01110_10_1, 0b111101), + VecALUOp::Fmul => (0b001_01110_00_1, 0b110111), + VecALUOp::Addp => (0b000_01110_00_1 | enc_size << 1, 0b101111), + VecALUOp::Zip1 => (0b01001110_00_0 | enc_size << 1, 0b001110), + VecALUOp::Zip2 => (0b01001110_00_0 | enc_size << 1, 0b011110), + VecALUOp::Sqrdmulh => { + debug_assert!( + size.lane_size() == ScalarSize::Size16 + || size.lane_size() == ScalarSize::Size32 + ); + + (0b001_01110_00_1 | enc_size << 1, 0b101101) + } + VecALUOp::Uzp1 => (0b01001110_00_0 | enc_size << 1, 0b000110), + VecALUOp::Uzp2 => (0b01001110_00_0 | enc_size << 1, 0b010110), + VecALUOp::Trn1 => (0b01001110_00_0 | enc_size << 1, 0b001010), + VecALUOp::Trn2 => (0b01001110_00_0 | enc_size << 1, 0b011010), + }; + let top11 = if is_float { + top11 | size.enc_float_size() << 1 + } else { + top11 + }; + sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd)); + } + &Inst::VecRRRMod { + rd, + ri, + rn, + rm, + alu_op, + size, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let (q, _enc_size) = size.enc_size(); + + let (top11, bit15_10) = match alu_op { + VecALUModOp::Bsl => (0b001_01110_01_1, 0b000111), + VecALUModOp::Fmla => { + (0b000_01110_00_1 | (size.enc_float_size() << 1), 0b110011) + } + VecALUModOp::Fmls => { + (0b000_01110_10_1 | (size.enc_float_size() << 1), 0b110011) + } + }; + sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd)); + } + &Inst::VecFmlaElem { + rd, + ri, + rn, + rm, + alu_op, + size, + idx, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let idx = u32::from(idx); + + let (q, _size) = size.enc_size(); + let o2 = match alu_op { + VecALUModOp::Fmla => 0b0, + VecALUModOp::Fmls => 0b1, + _ => unreachable!(), + }; + + let (h, l) = match size { + VectorSize::Size32x4 => { + assert!(idx < 4); + (idx >> 1, idx & 1) + } + VectorSize::Size64x2 => { + assert!(idx < 2); + (idx, 0) + } + _ => unreachable!(), + }; + + let top11 = 0b000_011111_00 | (q << 9) | (size.enc_float_size() << 1) | l; + let bit15_10 = 0b000100 | (o2 << 4) | (h << 1); + sink.put4(enc_vec_rrr(top11, rm, bit15_10, rn, rd)); + } + &Inst::VecLoadReplicate { + rd, + rn, + size, + flags, + } => { + let (q, size) = size.enc_size(); + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + sink.put4(enc_ldst_vec(q, size, rn, rd)); + } + &Inst::VecCSel { rd, rn, rm, cond } => { + /* Emit this: + b.cond else + mov rd, rm + b out + else: + mov rd, rn + out: + + Note, we could do better in the cases where rd == rn or rd == rm. + */ + let else_label = sink.get_label(); + let out_label = sink.get_label(); + + // b.cond else + let br_else_offset = sink.cur_offset(); + sink.put4(enc_conditional_br( + BranchTarget::Label(else_label), + CondBrKind::Cond(cond), + )); + sink.use_label_at_offset(br_else_offset, else_label, LabelUse::Branch19); + + // mov rd, rm + sink.put4(enc_vecmov(/* 16b = */ true, rd, rm)); + + // b out + let b_out_offset = sink.cur_offset(); + sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26); + sink.add_uncond_branch(b_out_offset, b_out_offset + 4, out_label); + sink.put4(enc_jump26(0b000101, 0 /* will be fixed up later */)); + + // else: + sink.bind_label(else_label, &mut state.ctrl_plane); + + // mov rd, rn + sink.put4(enc_vecmov(/* 16b = */ true, rd, rn)); + + // out: + sink.bind_label(out_label, &mut state.ctrl_plane); + } + &Inst::MovToNZCV { rn } => { + sink.put4(0xd51b4200 | machreg_to_gpr(rn)); + } + &Inst::MovFromNZCV { rd } => { + sink.put4(0xd53b4200 | machreg_to_gpr(rd.to_reg())); + } + &Inst::Extend { + rd, + rn, + signed: false, + from_bits: 1, + to_bits, + } => { + assert!(to_bits <= 64); + // Reduce zero-extend-from-1-bit to: + // - and rd, rn, #1 + // Note: This is special cased as UBFX may take more cycles + // than AND on smaller cores. + let imml = ImmLogic::maybe_from_u64(1, I32).unwrap(); + Inst::AluRRImmLogic { + alu_op: ALUOp::And, + size: OperandSize::Size32, + rd, + rn, + imml, + } + .emit(sink, emit_info, state); + } + &Inst::Extend { + rd, + rn, + signed: false, + from_bits: 32, + to_bits: 64, + } => { + let mov = Inst::Mov { + size: OperandSize::Size32, + rd, + rm: rn, + }; + mov.emit(sink, emit_info, state); + } + &Inst::Extend { + rd, + rn, + signed, + from_bits, + to_bits, + } => { + let (opc, size) = if signed { + (0b00, OperandSize::from_bits(to_bits)) + } else { + (0b10, OperandSize::Size32) + }; + sink.put4(enc_bfm(opc, size, rd, rn, 0, from_bits - 1)); + } + &Inst::Jump { ref dest } => { + let off = sink.cur_offset(); + // Indicate that the jump uses a label, if so, so that a fixup can occur later. + if let Some(l) = dest.as_label() { + sink.use_label_at_offset(off, l, LabelUse::Branch26); + sink.add_uncond_branch(off, off + 4, l); + } + // Emit the jump itself. + sink.put4(enc_jump26(0b000101, dest.as_offset26_or_zero())); + } + &Inst::Args { .. } | &Inst::Rets { .. } => { + // Nothing: this is a pseudoinstruction that serves + // only to constrain registers at a certain point. + } + &Inst::Ret {} => { + sink.put4(0xd65f03c0); + } + &Inst::AuthenticatedRet { key, is_hint } => { + let (op2, is_hint) = match key { + APIKey::AZ => (0b100, true), + APIKey::ASP => (0b101, is_hint), + APIKey::BZ => (0b110, true), + APIKey::BSP => (0b111, is_hint), + }; + + if is_hint { + sink.put4(key.enc_auti_hint()); + Inst::Ret {}.emit(sink, emit_info, state); + } else { + sink.put4(0xd65f0bff | (op2 << 9)); // reta{key} + } + } + &Inst::Call { ref info } => { + let user_stack_map = state.take_stack_map(); + sink.add_reloc(Reloc::Arm64Call, &info.dest, 0); + sink.put4(enc_jump26(0b100101, 0)); + if let Some(s) = user_stack_map { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + sink.add_call_site(); + + if info.callee_pop_size > 0 { + let callee_pop_size = + i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB"); + for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) { + inst.emit(sink, emit_info, state); + } + } + } + &Inst::CallInd { ref info } => { + let user_stack_map = state.take_stack_map(); + sink.put4( + 0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.dest) << 5), + ); + if let Some(s) = user_stack_map { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + sink.add_call_site(); + + if info.callee_pop_size > 0 { + let callee_pop_size = + i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB"); + for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) { + inst.emit(sink, emit_info, state); + } + } + } + &Inst::ReturnCall { ref info } => { + emit_return_call_common_sequence(sink, emit_info, state, info); + + // Note: this is not `Inst::Jump { .. }.emit(..)` because we + // have different metadata in this case: we don't have a label + // for the target, but rather a function relocation. + sink.add_reloc(Reloc::Arm64Call, &info.dest, 0); + sink.put4(enc_jump26(0b000101, 0)); + sink.add_call_site(); + + // `emit_return_call_common_sequence` emits an island if + // necessary, so we can safely disable the worst-case-size check + // in this case. + start_off = sink.cur_offset(); + } + &Inst::ReturnCallInd { ref info } => { + emit_return_call_common_sequence(sink, emit_info, state, info); + + Inst::IndirectBr { + rn: info.dest, + targets: vec![], + } + .emit(sink, emit_info, state); + sink.add_call_site(); + + // `emit_return_call_common_sequence` emits an island if + // necessary, so we can safely disable the worst-case-size check + // in this case. + start_off = sink.cur_offset(); + } + &Inst::CondBr { + taken, + not_taken, + kind, + } => { + // Conditional part first. + let cond_off = sink.cur_offset(); + if let Some(l) = taken.as_label() { + sink.use_label_at_offset(cond_off, l, LabelUse::Branch19); + let inverted = enc_conditional_br(taken, kind.invert()).to_le_bytes(); + sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]); + } + sink.put4(enc_conditional_br(taken, kind)); + + // Unconditional part next. + let uncond_off = sink.cur_offset(); + if let Some(l) = not_taken.as_label() { + sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26); + sink.add_uncond_branch(uncond_off, uncond_off + 4, l); + } + sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero())); + } + &Inst::TestBitAndBranch { + taken, + not_taken, + kind, + rn, + bit, + } => { + // Emit the conditional branch first + let cond_off = sink.cur_offset(); + if let Some(l) = taken.as_label() { + sink.use_label_at_offset(cond_off, l, LabelUse::Branch14); + let inverted = + enc_test_bit_and_branch(kind.complement(), taken, rn, bit).to_le_bytes(); + sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]); + } + sink.put4(enc_test_bit_and_branch(kind, taken, rn, bit)); + + // Unconditional part next. + let uncond_off = sink.cur_offset(); + if let Some(l) = not_taken.as_label() { + sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26); + sink.add_uncond_branch(uncond_off, uncond_off + 4, l); + } + sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero())); + } + &Inst::TrapIf { kind, trap_code } => { + let label = sink.defer_trap(trap_code); + // condbr KIND, LABEL + let off = sink.cur_offset(); + sink.put4(enc_conditional_br(BranchTarget::Label(label), kind)); + sink.use_label_at_offset(off, label, LabelUse::Branch19); + } + &Inst::IndirectBr { rn, .. } => { + sink.put4(enc_br(rn)); + } + &Inst::Nop0 => {} + &Inst::Nop4 => { + sink.put4(0xd503201f); + } + &Inst::Brk => { + sink.put4(0xd4200000); + } + &Inst::Udf { trap_code } => { + sink.add_trap(trap_code); + sink.put_data(Inst::TRAP_OPCODE); + } + &Inst::Adr { rd, off } => { + assert!(off > -(1 << 20)); + assert!(off < (1 << 20)); + sink.put4(enc_adr(off, rd)); + } + &Inst::Adrp { rd, off } => { + assert!(off > -(1 << 20)); + assert!(off < (1 << 20)); + sink.put4(enc_adrp(off, rd)); + } + &Inst::Word4 { data } => { + sink.put4(data); + } + &Inst::Word8 { data } => { + sink.put8(data); + } + &Inst::JTSequence { + ridx, + rtmp1, + rtmp2, + default, + ref targets, + .. + } => { + // This sequence is *one* instruction in the vcode, and is expanded only here at + // emission time, because we cannot allow the regalloc to insert spills/reloads in + // the middle; we depend on hardcoded PC-rel addressing below. + + // Branch to default when condition code from prior comparison indicates. + let br = + enc_conditional_br(BranchTarget::Label(default), CondBrKind::Cond(Cond::Hs)); + + // No need to inform the sink's branch folding logic about this branch, because it + // will not be merged with any other branch, flipped, or elided (it is not preceded + // or succeeded by any other branch). Just emit it with the label use. + let default_br_offset = sink.cur_offset(); + sink.use_label_at_offset(default_br_offset, default, LabelUse::Branch19); + sink.put4(br); + + // Overwrite the index with a zero when the above + // branch misspeculates (Spectre mitigation). Save the + // resulting index in rtmp2. + let inst = Inst::CSel { + rd: rtmp2, + cond: Cond::Hs, + rn: zero_reg(), + rm: ridx, + }; + inst.emit(sink, emit_info, state); + // Prevent any data value speculation. + Inst::Csdb.emit(sink, emit_info, state); + + // Load address of jump table + let inst = Inst::Adr { rd: rtmp1, off: 16 }; + inst.emit(sink, emit_info, state); + // Load value out of jump table + let inst = Inst::SLoad32 { + rd: rtmp2, + mem: AMode::reg_plus_reg_scaled_extended( + rtmp1.to_reg(), + rtmp2.to_reg(), + ExtendOp::UXTW, + ), + flags: MemFlags::trusted(), + }; + inst.emit(sink, emit_info, state); + // Add base of jump table to jump-table-sourced block offset + let inst = Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: rtmp1, + rn: rtmp1.to_reg(), + rm: rtmp2.to_reg(), + }; + inst.emit(sink, emit_info, state); + // Branch to computed address. (`targets` here is only used for successor queries + // and is not needed for emission.) + let inst = Inst::IndirectBr { + rn: rtmp1.to_reg(), + targets: vec![], + }; + inst.emit(sink, emit_info, state); + // Emit jump table (table of 32-bit offsets). + let jt_off = sink.cur_offset(); + for &target in targets.iter() { + let word_off = sink.cur_offset(); + // off_into_table is an addend here embedded in the label to be later patched + // at the end of codegen. The offset is initially relative to this jump table + // entry; with the extra addend, it'll be relative to the jump table's start, + // after patching. + let off_into_table = word_off - jt_off; + sink.use_label_at_offset(word_off, target, LabelUse::PCRel32); + sink.put4(off_into_table); + } + + // Lowering produces an EmitIsland before using a JTSequence, so we can safely + // disable the worst-case-size check in this case. + start_off = sink.cur_offset(); + } + &Inst::LoadExtName { + rd, + ref name, + offset, + } => { + if emit_info.0.is_pic() { + // See this CE Example for the variations of this with and without BTI & PAUTH + // https://godbolt.org/z/ncqjbbvvn + // + // Emit the following code: + // adrp rd, :got:X + // ldr rd, [rd, :got_lo12:X] + + // adrp rd, symbol + sink.add_reloc(Reloc::Aarch64AdrGotPage21, &**name, 0); + let inst = Inst::Adrp { rd, off: 0 }; + inst.emit(sink, emit_info, state); + + // ldr rd, [rd, :got_lo12:X] + sink.add_reloc(Reloc::Aarch64Ld64GotLo12Nc, &**name, 0); + let inst = Inst::ULoad64 { + rd, + mem: AMode::reg(rd.to_reg()), + flags: MemFlags::trusted(), + }; + inst.emit(sink, emit_info, state); + } else { + // With absolute offsets we set up a load from a preallocated space, and then jump + // over it. + // + // Emit the following code: + // ldr rd, #8 + // b #0x10 + // <8 byte space> + + let inst = Inst::ULoad64 { + rd, + mem: AMode::Label { + label: MemLabel::PCRel(8), + }, + flags: MemFlags::trusted(), + }; + inst.emit(sink, emit_info, state); + let inst = Inst::Jump { + dest: BranchTarget::ResolvedOffset(12), + }; + inst.emit(sink, emit_info, state); + sink.add_reloc(Reloc::Abs8, &**name, offset); + sink.put8(0); + } + } + &Inst::LoadAddr { rd, ref mem } => { + let mem = mem.clone(); + let (mem_insts, mem) = mem_finalize(Some(sink), &mem, I8, state); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + let (reg, index_reg, offset) = match mem { + AMode::RegExtended { rn, rm, extendop } => { + let r = rn; + (r, Some((rm, extendop)), 0) + } + AMode::Unscaled { rn, simm9 } => { + let r = rn; + (r, None, simm9.value()) + } + AMode::UnsignedOffset { rn, uimm12 } => { + let r = rn; + (r, None, uimm12.value() as i32) + } + _ => panic!("Unsupported case for LoadAddr: {mem:?}"), + }; + let abs_offset = if offset < 0 { + -offset as u64 + } else { + offset as u64 + }; + let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add }; + + if let Some((idx, extendop)) = index_reg { + let add = Inst::AluRRRExtend { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd, + rn: reg, + rm: idx, + extendop, + }; + + add.emit(sink, emit_info, state); + } else if offset == 0 { + if reg != rd.to_reg() { + let mov = Inst::Mov { + size: OperandSize::Size64, + rd, + rm: reg, + }; + + mov.emit(sink, emit_info, state); + } + } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) { + let add = Inst::AluRRImm12 { + alu_op, + size: OperandSize::Size64, + rd, + rn: reg, + imm12, + }; + add.emit(sink, emit_info, state); + } else { + // Use `tmp2` here: `reg` may be `spilltmp` if the `AMode` on this instruction + // was initially an `SPOffset`. Assert that `tmp2` is truly free to use. Note + // that no other instructions will be inserted here (we're emitting directly), + // and a live range of `tmp2` should not span this instruction, so this use + // should otherwise be correct. + debug_assert!(rd.to_reg() != tmp2_reg()); + debug_assert!(reg != tmp2_reg()); + let tmp = writable_tmp2_reg(); + for insn in Inst::load_constant(tmp, abs_offset, &mut |_| tmp).into_iter() { + insn.emit(sink, emit_info, state); + } + let add = Inst::AluRRR { + alu_op, + size: OperandSize::Size64, + rd, + rn: reg, + rm: tmp.to_reg(), + }; + add.emit(sink, emit_info, state); + } + } + &Inst::Paci { key } => { + let (crm, op2) = match key { + APIKey::AZ => (0b0011, 0b000), + APIKey::ASP => (0b0011, 0b001), + APIKey::BZ => (0b0011, 0b010), + APIKey::BSP => (0b0011, 0b011), + }; + + sink.put4(0xd503211f | (crm << 8) | (op2 << 5)); + } + &Inst::Xpaclri => sink.put4(0xd50320ff), + &Inst::Bti { targets } => { + let targets = match targets { + BranchTargetType::None => 0b00, + BranchTargetType::C => 0b01, + BranchTargetType::J => 0b10, + BranchTargetType::JC => 0b11, + }; + + sink.put4(0xd503241f | targets << 6); + } + &Inst::EmitIsland { needed_space } => { + if sink.island_needed(needed_space + 4) { + let jump_around_label = sink.get_label(); + let jmp = Inst::Jump { + dest: BranchTarget::Label(jump_around_label), + }; + jmp.emit(sink, emit_info, state); + sink.emit_island(needed_space + 4, &mut state.ctrl_plane); + sink.bind_label(jump_around_label, &mut state.ctrl_plane); + } + } + + &Inst::ElfTlsGetAddr { + ref symbol, + rd, + tmp, + } => { + assert_eq!(xreg(0), rd.to_reg()); + + // See the original proposal for TLSDESC. + // http://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf + // + // Implement the TLSDESC instruction sequence: + // adrp x0, :tlsdesc:tlsvar + // ldr tmp, [x0, :tlsdesc_lo12:tlsvar] + // add x0, x0, :tlsdesc_lo12:tlsvar + // blr tmp + // mrs tmp, tpidr_el0 + // add x0, x0, tmp + // + // This is the instruction sequence that GCC emits for ELF GD TLS Relocations in aarch64 + // See: https://gcc.godbolt.org/z/e4j7MdErh + + // adrp x0, :tlsdesc:tlsvar + sink.add_reloc(Reloc::Aarch64TlsDescAdrPage21, &**symbol, 0); + Inst::Adrp { rd, off: 0 }.emit(sink, emit_info, state); + + // ldr tmp, [x0, :tlsdesc_lo12:tlsvar] + sink.add_reloc(Reloc::Aarch64TlsDescLd64Lo12, &**symbol, 0); + Inst::ULoad64 { + rd: tmp, + mem: AMode::reg(rd.to_reg()), + flags: MemFlags::trusted(), + } + .emit(sink, emit_info, state); + + // add x0, x0, :tlsdesc_lo12:tlsvar + sink.add_reloc(Reloc::Aarch64TlsDescAddLo12, &**symbol, 0); + Inst::AluRRImm12 { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd, + rn: rd.to_reg(), + imm12: Imm12::maybe_from_u64(0).unwrap(), + } + .emit(sink, emit_info, state); + + // blr tmp + sink.add_reloc(Reloc::Aarch64TlsDescCall, &**symbol, 0); + Inst::CallInd { + info: crate::isa::Box::new(CallInfo::empty(tmp.to_reg(), CallConv::SystemV)), + } + .emit(sink, emit_info, state); + + // mrs tmp, tpidr_el0 + sink.put4(0xd53bd040 | machreg_to_gpr(tmp.to_reg())); + + // add x0, x0, tmp + Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd, + rn: rd.to_reg(), + rm: tmp.to_reg(), + } + .emit(sink, emit_info, state); + } + + &Inst::MachOTlsGetAddr { ref symbol, rd } => { + // Each thread local variable gets a descriptor, where the first xword of the descriptor is a pointer + // to a function that takes the descriptor address in x0, and after the function returns x0 + // contains the address for the thread local variable + // + // what we want to emit is basically: + // + // adrp x0,

= Callee>; + +/// Support for the Pulley ABI from the caller side (at a callsite). +pub(crate) type PulleyABICallSite

= CallSite>; + +/// Pulley-specific ABI behavior. This struct just serves as an implementation +/// point for the trait; it is never actually instantiated. +pub struct PulleyMachineDeps

+where + P: PulleyTargetKind, +{ + _phantom: PhantomData

, +} + +impl

ABIMachineSpec for PulleyMachineDeps

+where + P: PulleyTargetKind, +{ + type I = InstAndKind

; + type F = PulleyFlags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic: for now, 128 MB. + const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024; + + fn word_bits() -> u32 { + P::pointer_width().bits().into() + } + + /// Return required stack alignment in bytes. + fn stack_align(_call_conv: isa::CallConv) -> u32 { + 16 + } + + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + mut args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)> { + // NB: make sure this method stays in sync with + // `cranelift_pulley::interp::Vm::call`. + + let x_end = 15; + let f_end = 15; + let v_end = 15; + + let mut next_x_reg = 0; + let mut next_f_reg = 0; + let mut next_v_reg = 0; + let mut next_stack: u32 = 0; + + let ret_area_ptr = if add_ret_area_ptr { + debug_assert_eq!(args_or_rets, ArgsOrRets::Args); + next_x_reg += 1; + Some(ABIArg::reg( + x_reg(next_x_reg - 1).to_real_reg().unwrap(), + I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } else { + None + }; + + for param in params { + // Find the regclass(es) of the register(s) used to store a value of + // this type. + let (rcs, reg_tys) = Self::I::rc_for_type(param.value_type)?; + + let mut slots = ABIArgSlotVec::new(); + for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) { + let next_reg = if (next_x_reg <= x_end) && *rc == RegClass::Int { + let x = Some(x_reg(next_x_reg)); + next_x_reg += 1; + x + } else if (next_f_reg <= f_end) && *rc == RegClass::Float { + let f = Some(f_reg(next_f_reg)); + next_f_reg += 1; + f + } else if (next_v_reg <= v_end) && *rc == RegClass::Vector { + let v = Some(v_reg(next_v_reg)); + next_v_reg += 1; + v + } else { + None + }; + + if let Some(reg) = next_reg { + slots.push(ABIArgSlot::Reg { + reg: reg.to_real_reg().unwrap(), + ty: *reg_ty, + extension: param.extension, + }); + } else { + if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() { + return Err(crate::CodegenError::Unsupported( + "Too many return values to fit in registers. \ + Use a StructReturn argument instead. (#9510)" + .to_owned(), + )); + } + + // Compute size and 16-byte stack alignment happens + // separately after all args. + let size = reg_ty.bits() / 8; + let size = std::cmp::max(size, 8); + + // Align. + debug_assert!(size.is_power_of_two()); + next_stack = align_to(next_stack, size); + + slots.push(ABIArgSlot::Stack { + offset: i64::from(next_stack), + ty: *reg_ty, + extension: param.extension, + }); + + next_stack += size; + } + } + + args.push(ABIArg::Slots { + slots, + purpose: param.purpose, + }); + } + + let pos = if let Some(ret_area_ptr) = ret_area_ptr { + args.push_non_formal(ret_area_ptr); + Some(args.args().len() - 1) + } else { + None + }; + + next_stack = align_to(next_stack, Self::stack_align(call_conv)); + + Ok((next_stack, pos)) + } + + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Self::I { + let mut flags = MemFlags::trusted(); + // Stack loads/stores of vectors always use little-endianess to avoid + // implementing a byte-swap of vectors on big-endian platforms. + if ty.is_vector() { + flags.set_endianness(ir::Endianness::Little); + } + Inst::gen_load(into_reg, mem.into(), ty, flags).into() + } + + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I { + let mut flags = MemFlags::trusted(); + // Stack loads/stores of vectors always use little-endianess to avoid + // implementing a byte-swap of vectors on big-endian platforms. + if ty.is_vector() { + flags.set_endianness(ir::Endianness::Little); + } + Inst::gen_store(mem.into(), from_reg, ty, flags).into() + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self::I { + Self::I::gen_move(to_reg, from_reg, ty) + } + + fn gen_extend( + dst: Writable, + src: Reg, + signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Self::I { + assert!(from_bits < to_bits); + let src = XReg::new(src).unwrap(); + let dst = dst.try_into().unwrap(); + match (signed, from_bits) { + (true, 8) => RawInst::Sext8 { dst, src }.into(), + (true, 16) => RawInst::Sext16 { dst, src }.into(), + (true, 32) => RawInst::Sext32 { dst, src }.into(), + (false, 8) => RawInst::Zext8 { dst, src }.into(), + (false, 16) => RawInst::Zext16 { dst, src }.into(), + (false, 32) => RawInst::Zext32 { dst, src }.into(), + _ => unimplemented!("extend {from_bits} to {to_bits} as signed? {signed}"), + } + } + + fn get_ext_mode( + _call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension { + specified + } + + fn gen_args(args: Vec) -> Self::I { + Inst::Args { args }.into() + } + + fn gen_rets(rets: Vec) -> Self::I { + Inst::Rets { rets }.into() + } + + fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg { + spilltmp_reg() + } + + fn gen_add_imm( + _call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec { + let dst = into_reg.try_into().unwrap(); + let imm = imm as i32; + smallvec![ + RawInst::Xconst32 { dst, imm }.into(), + RawInst::Xadd32 { + dst, + src1: from_reg.try_into().unwrap(), + src2: dst.to_reg(), + } + .into() + ] + } + + fn gen_stack_lower_bound_trap(_limit_reg: Reg) -> SmallInstVec { + unimplemented!("pulley shouldn't need stack bound checks") + } + + fn gen_get_stack_addr(mem: StackAMode, dst: Writable) -> Self::I { + let dst = dst.to_reg(); + let dst = XReg::new(dst).unwrap(); + let dst = WritableXReg::from_reg(dst); + let mem = mem.into(); + Inst::LoadAddr { dst, mem }.into() + } + + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Self::I { + let base = XReg::try_from(base).unwrap(); + let mem = Amode::RegOffset { base, offset }; + Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()).into() + } + + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Self::I { + let base = XReg::try_from(base).unwrap(); + let mem = Amode::RegOffset { base, offset }; + Inst::gen_store(mem, from_reg, ty, MemFlags::trusted()).into() + } + + fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { + if amount == 0 { + return smallvec![]; + } + + let inst = if amount < 0 { + let amount = amount.checked_neg().unwrap(); + if let Ok(amt) = u32::try_from(amount) { + RawInst::StackAlloc32 { amt } + } else { + unreachable!() + } + } else { + if let Ok(amt) = u32::try_from(amount) { + RawInst::StackFree32 { amt } + } else { + unreachable!() + } + }; + smallvec![inst.into()] + } + + /// Generates the entire prologue for the function. + /// + /// Note that this is different from other backends where it's not spread + /// out among a few individual functions. That's because the goal here is to + /// generate a single macro-instruction for the entire prologue in the most + /// common cases and we don't want to spread the logic over multiple + /// functions. + /// + /// The general machinst methods are split to accommodate stack checks and + /// things like stack probes, all of which are empty on Pulley because + /// Pulley has its own stack check mechanism. + fn gen_prologue_frame_setup( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &PulleyFlags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + + let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size; + if incoming_args_diff > 0 { + // Decrement SP by the amount of additional incoming argument space + // we need + insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32))); + } + + let style = frame_layout.pulley_frame_style(); + + match &style { + FrameStyle::None => {} + FrameStyle::PulleySetupNoClobbers => insts.push(RawInst::PushFrame.into()), + FrameStyle::PulleySetupAndSaveClobbers { + frame_size, + saved_by_pulley, + } => insts.push( + RawInst::PushFrameSave { + amt: *frame_size, + regs: pulley_interpreter::RegSet::from_bitset(*saved_by_pulley), + } + .into(), + ), + FrameStyle::Manual { frame_size } => insts.extend(Self::gen_sp_reg_adjust( + -i32::try_from(*frame_size).unwrap(), + )), + } + + for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) { + insts.push( + Inst::gen_store(Amode::SpOffset { offset }, reg, ty, MemFlags::trusted()).into(), + ); + } + + insts + } + + /// Reverse of `gen_prologue_frame_setup`. + fn gen_epilogue_frame_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &PulleyFlags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + // Note that this is intentionally empty as `gen_return` does + // everything. + SmallVec::new() + } + + fn gen_return( + _call_conv: isa::CallConv, + _isa_flags: &PulleyFlags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + + let style = frame_layout.pulley_frame_style(); + + // Restore clobbered registers that are manually managed in Cranelift. + for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) { + insts.push( + Inst::gen_load( + Writable::from_reg(reg), + Amode::SpOffset { offset }, + ty, + MemFlags::trusted(), + ) + .into(), + ); + } + + // Perform the inverse of `gen_prologue_frame_setup`. + match &style { + FrameStyle::None => {} + FrameStyle::PulleySetupNoClobbers => insts.push(RawInst::PopFrame.into()), + FrameStyle::PulleySetupAndSaveClobbers { + frame_size, + saved_by_pulley, + } => insts.push( + RawInst::PopFrameRestore { + amt: *frame_size, + regs: pulley_interpreter::RegSet::from_bitset(*saved_by_pulley), + } + .into(), + ), + FrameStyle::Manual { frame_size } => { + insts.extend(Self::gen_sp_reg_adjust(i32::try_from(*frame_size).unwrap())) + } + } + + // Handle final stack adjustments for the tail-call ABI. + if frame_layout.tail_args_size > 0 { + insts.extend(Self::gen_sp_reg_adjust( + frame_layout.tail_args_size.try_into().unwrap(), + )); + } + + // And finally, return. + // + // FIXME: if `frame_layout.tail_args_size` is zero this instruction + // should get folded into the macro-instructions above. No need to have + // all functions do `pop_frame; ret`, that could be `pop_frame_and_ret`. + // Should benchmark whether this is worth it though. + insts.push(RawInst::Ret {}.into()); + insts + } + + fn gen_probestack(_insts: &mut SmallInstVec, _frame_size: u32) { + // Pulley doesn't implement stack probes since all stack pointer + // decrements are checked already. + } + + fn gen_clobber_save( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]> { + // Note that this is intentionally empty because everything necessary + // was already done in `gen_prologue_frame_setup`. + SmallVec::new() + } + + fn gen_clobber_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]> { + // Intentionally empty as restores happen for Pulley in `gen_return`. + SmallVec::new() + } + + fn gen_call( + dest: &CallDest, + _tmp: Writable, + mut info: CallInfo<()>, + ) -> SmallVec<[Self::I; 2]> { + match dest { + // "near" calls are pulley->pulley calls so they use a normal "call" + // opcode + CallDest::ExtName(name, RelocDistance::Near) => { + // The first four integer arguments to a call can be handled via + // special pulley call instructions. Assert here that + // `info.uses` is sorted in order and then take out x0-x3 if + // they're present and move them from `info.uses` to + // `info.dest.args` to be handled differently during register + // allocation. + let mut args = SmallVec::new(); + if cfg!(debug_assertions) { + let xargs = info + .uses + .iter() + .filter_map(|a| XReg::new(a.preg)) + .collect::>(); + for window in xargs.windows(2) { + assert!(window[0] < window[1]); + } + } + info.uses.retain(|arg| { + if arg.preg != x0() && arg.preg != x1() && arg.preg != x2() && arg.preg != x3() + { + return true; + } + args.push(XReg::new(arg.vreg).unwrap()); + false + }); + smallvec![Inst::Call { + info: Box::new(info.map(|()| PulleyCall { + name: name.clone(), + args, + })) + } + .into()] + } + // "far" calls are pulley->host calls so they use a different opcode + // which is lowered with a special relocation in the backend. + CallDest::ExtName(name, RelocDistance::Far) => smallvec![Inst::IndirectCallHost { + info: Box::new(info.map(|()| name.clone())) + } + .into()], + // Indirect calls are all assumed to be pulley->pulley calls + CallDest::Reg(reg) => smallvec![Inst::IndirectCall { + info: Box::new(info.map(|()| XReg::new(*reg).unwrap())) + } + .into()], + } + } + + fn gen_memcpy Writable>( + _call_conv: isa::CallConv, + _dst: Reg, + _src: Reg, + _size: usize, + _alloc_tmp: F, + ) -> SmallVec<[Self::I; 8]> { + todo!() + } + + fn get_number_of_spillslots_for_value( + rc: RegClass, + _target_vector_bytes: u32, + _isa_flags: &PulleyFlags, + ) -> u32 { + // Spill slots are the size of a "word" or a pointer, but Pulley + // registers are 8-byte for integers/floats regardless of pointer size. + // Calculate the number of slots necessary to store 8 bytes. + let slots_for_8bytes = match P::pointer_width() { + PointerWidth::PointerWidth32 => 2, + PointerWidth::PointerWidth64 => 1, + }; + match rc { + // Int/float registers are 8-bytes + RegClass::Int | RegClass::Float => slots_for_8bytes, + // Vector registers are 16 bytes + RegClass::Vector => 2 * slots_for_8bytes, + } + } + + fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(create_reg_environment) + } + + fn get_regs_clobbered_by_call(_call_conv_of_callee: isa::CallConv) -> PRegSet { + DEFAULT_CLOBBERS + } + + fn compute_frame_layout( + _call_conv: isa::CallConv, + flags: &settings::Flags, + _sig: &Signature, + regs: &[Writable], + is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + outgoing_args_size: u32, + ) -> FrameLayout { + let mut regs: Vec> = regs + .iter() + .cloned() + .filter(|r| DEFAULT_CALLEE_SAVES.contains(r.to_reg().into())) + .collect(); + + regs.sort_unstable(); + + // Compute clobber size. + let clobber_size = compute_clobber_size(®s); + + // Compute linkage frame size. + let setup_area_size = if flags.preserve_frame_pointers() + || !is_leaf + // The function arguments that are passed on the stack are addressed + // relative to the Frame Pointer. + || incoming_args_size > 0 + || clobber_size > 0 + || fixed_frame_storage_size > 0 + { + P::pointer_width().bytes() * 2 // FP, LR + } else { + 0 + }; + + FrameLayout { + incoming_args_size, + tail_args_size, + setup_area_size: setup_area_size.into(), + clobber_size, + fixed_frame_storage_size, + outgoing_args_size, + clobbered_callee_saves: regs, + } + } + + fn gen_inline_probestack( + _insts: &mut SmallInstVec, + _call_conv: isa::CallConv, + _frame_size: u32, + _guard_size: u32, + ) { + // Pulley doesn't need inline probestacks because it always checks stack + // decrements. + } +} + +/// Different styles of management of fp/lr and clobbered registers. +/// +/// This helps decide, depending on Cranelift settings and frame layout, what +/// macro instruction is used to setup the pulley frame. +enum FrameStyle { + /// No management is happening, fp/lr aren't saved by Pulley or Cranelift. + /// No stack is being allocated either. + None, + + /// No stack is being allocated and nothing is clobbered, but Pulley should + /// save the fp/lr combo. + PulleySetupNoClobbers, + + /// Pulley is managing the fp/lr combo, the stack size, and clobbered + /// X-class registers. + /// + /// Note that `saved_by_pulley` is not the exhaustive set of clobbered + /// registers. It's only those that are part of the `PushFrameSave` + /// instruction. + PulleySetupAndSaveClobbers { + /// The size of the frame, including clobbers, that's being allocated. + frame_size: u32, + /// Registers that pulley is saving/restoring. + saved_by_pulley: ScalarBitSet, + }, + + /// Cranelift is manually managing everything, both clobbers and stack + /// increments/decrements. + /// + /// Note that fp/lr are not saved in this mode. + Manual { + /// The size of the stack being allocated. + frame_size: u32, + }, +} + +/// Pulley-specific helpers when dealing with ABI code. +impl FrameLayout { + /// Whether or not this frame saves fp/lr. + fn setup_frame(&self) -> bool { + self.setup_area_size > 0 + } + + /// Returns the stack size allocated by this function, excluding incoming + /// tail args or the optional "setup area" of fp/lr. + fn stack_size(&self) -> u32 { + self.clobber_size + self.fixed_frame_storage_size + self.outgoing_args_size + } + + /// Returns the style of frame being used for this function. + /// + /// See `FrameStyle` for more information. + fn pulley_frame_style(&self) -> FrameStyle { + let saved_by_pulley = self.clobbered_xregs_saved_by_pulley(); + match ( + self.stack_size(), + self.setup_frame(), + saved_by_pulley.is_empty(), + ) { + // No stack allocated, not saving fp/lr, no clobbers, nothing to do + (0, false, true) => FrameStyle::None, + + // No stack allocated, saving fp/lr, no clobbers, so this is + // pulley-managed via push/pop_frame. + (0, true, true) => FrameStyle::PulleySetupNoClobbers, + + // Some stack is being allocated and pulley is managing fp/lr. Let + // pulley manage clobbered registers as well, regardless if they're + // present or not. + (frame_size, true, _) => FrameStyle::PulleySetupAndSaveClobbers { + frame_size, + saved_by_pulley, + }, + + // Some stack is being allocated, but pulley isn't managing fp/lr, + // so we're manually doing everything. + (frame_size, false, true) => FrameStyle::Manual { frame_size }, + + // If there's no frame setup and there's clobbered registers this + // technically should have already hit a case above, so panic here. + (_, false, false) => unreachable!(), + } + } + + /// Returns the set of clobbered registers that Pulley is managing via its + /// macro instructions rather than the generated code. + fn clobbered_xregs_saved_by_pulley(&self) -> ScalarBitSet { + let mut clobbered: ScalarBitSet = ScalarBitSet::new(); + // Pulley only manages clobbers if it's also managing fp/lr. + if !self.setup_frame() { + return clobbered; + } + let mut found_manual_clobber = false; + for reg in self.clobbered_callee_saves.iter() { + let r_reg = reg.to_reg(); + // Pulley can only manage clobbers of integer registers at this + // time, float registers are managed manually. + // + // Also assert that all pulley-managed clobbers come first, + // otherwise the loop below in `manually_managed_clobbers` is + // incorrect. + if r_reg.class() == RegClass::Int { + assert!(!found_manual_clobber); + clobbered.insert(r_reg.hw_enc()); + } else { + found_manual_clobber = true; + } + } + clobbered + } + + /// Returns an iterator over the clobbers that Cranelift is managing, not + /// Pulley. + /// + /// If this frame has clobbers then they're either saved by Pulley with + /// `FrameStyle::PulleySetupAndSaveClobbers`. Cranelift might need to manage + /// these registers depending on Cranelift settings. Cranelift also always + /// manages floating-point registers. + fn manually_managed_clobbers<'a>( + &'a self, + style: &'a FrameStyle, + ) -> impl Iterator + 'a { + let mut offset = self.stack_size(); + self.clobbered_callee_saves.iter().filter_map(move |reg| { + // Allocate space for this clobber no matter what. If pulley is + // managing this then we're just accounting for the pulley-saved + // registers as well. Note that all pulley-managed registers come + // first in the list here. + offset -= 8; + let r_reg = reg.to_reg(); + let ty = match r_reg.class() { + RegClass::Int => { + // If this register is saved by pulley, skip this clobber. + if let FrameStyle::PulleySetupAndSaveClobbers { + saved_by_pulley, .. + } = style + { + if saved_by_pulley.contains(r_reg.hw_enc()) { + return None; + } + } + I64 + } + RegClass::Float => F64, + RegClass::Vector => unreachable!("no vector registers are callee-save"), + }; + let offset = i32::try_from(offset).unwrap(); + Some((offset, ty, Reg::from(reg.to_reg()))) + }) + } +} + +impl

PulleyABICallSite

+where + P: PulleyTargetKind, +{ + pub fn emit_return_call( + mut self, + ctx: &mut Lower>, + args: isle::ValueSlice, + _backend: &PulleyBackend

, + ) { + let new_stack_arg_size = + u32::try_from(self.sig(ctx.sigs()).sized_stack_arg_space()).unwrap(); + + ctx.abi_mut().accumulate_tail_args_size(new_stack_arg_size); + + // Put all arguments in registers and stack slots (within that newly + // allocated stack space). + self.emit_args(ctx, args); + self.emit_stack_ret_arg_for_tail_call(ctx); + + let dest = self.dest().clone(); + let uses = self.take_uses(); + + match dest { + CallDest::ExtName(name, RelocDistance::Near) => { + let info = Box::new(ReturnCallInfo { + dest: name, + uses, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCall { info }.into()); + } + CallDest::ExtName(_name, RelocDistance::Far) => { + unimplemented!("return-call of a host function") + } + CallDest::Reg(callee) => { + let info = Box::new(ReturnCallInfo { + dest: XReg::new(callee).unwrap(), + uses, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnIndirectCall { info }.into()); + } + } + } +} + +const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty() + // Integer registers. + .with(px_reg(16)) + .with(px_reg(17)) + .with(px_reg(18)) + .with(px_reg(19)) + .with(px_reg(20)) + .with(px_reg(21)) + .with(px_reg(22)) + .with(px_reg(23)) + .with(px_reg(24)) + .with(px_reg(25)) + .with(px_reg(26)) + .with(px_reg(27)) + .with(px_reg(28)) + .with(px_reg(29)) + .with(px_reg(30)) + .with(px_reg(31)) + // Float registers. + .with(pf_reg(16)) + .with(pf_reg(17)) + .with(pf_reg(18)) + .with(pf_reg(19)) + .with(pf_reg(20)) + .with(pf_reg(21)) + .with(pf_reg(22)) + .with(pf_reg(23)) + .with(pf_reg(24)) + .with(pf_reg(25)) + .with(pf_reg(26)) + .with(pf_reg(27)) + .with(pf_reg(28)) + .with(pf_reg(29)) + .with(pf_reg(30)) + .with(pf_reg(31)) + // Note: no vector registers are callee-saved. +; + +fn compute_clobber_size(clobbers: &[Writable]) -> u32 { + let mut clobbered_size = 0; + for reg in clobbers { + match reg.to_reg().class() { + RegClass::Int => { + clobbered_size += 8; + } + RegClass::Float => { + clobbered_size += 8; + } + RegClass::Vector => unimplemented!("Vector Size Clobbered"), + } + } + align_to(clobbered_size, 16) +} + +const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty() + // Integer registers: the first 16 get clobbered. + .with(px_reg(0)) + .with(px_reg(1)) + .with(px_reg(2)) + .with(px_reg(3)) + .with(px_reg(4)) + .with(px_reg(5)) + .with(px_reg(6)) + .with(px_reg(7)) + .with(px_reg(8)) + .with(px_reg(9)) + .with(px_reg(10)) + .with(px_reg(11)) + .with(px_reg(12)) + .with(px_reg(13)) + .with(px_reg(14)) + .with(px_reg(15)) + // Float registers: the first 16 get clobbered. + .with(pf_reg(0)) + .with(pf_reg(1)) + .with(pf_reg(2)) + .with(pf_reg(3)) + .with(pf_reg(4)) + .with(pf_reg(5)) + .with(pf_reg(6)) + .with(pf_reg(7)) + .with(pf_reg(8)) + .with(pf_reg(9)) + .with(pf_reg(10)) + .with(pf_reg(11)) + .with(pf_reg(12)) + .with(pf_reg(13)) + .with(pf_reg(14)) + .with(pf_reg(15)) + // All vector registers get clobbered. + .with(pv_reg(0)) + .with(pv_reg(1)) + .with(pv_reg(2)) + .with(pv_reg(3)) + .with(pv_reg(4)) + .with(pv_reg(5)) + .with(pv_reg(6)) + .with(pv_reg(7)) + .with(pv_reg(8)) + .with(pv_reg(9)) + .with(pv_reg(10)) + .with(pv_reg(11)) + .with(pv_reg(12)) + .with(pv_reg(13)) + .with(pv_reg(14)) + .with(pv_reg(15)) + .with(pv_reg(16)) + .with(pv_reg(17)) + .with(pv_reg(18)) + .with(pv_reg(19)) + .with(pv_reg(20)) + .with(pv_reg(21)) + .with(pv_reg(22)) + .with(pv_reg(23)) + .with(pv_reg(24)) + .with(pv_reg(25)) + .with(pv_reg(26)) + .with(pv_reg(27)) + .with(pv_reg(28)) + .with(pv_reg(29)) + .with(pv_reg(30)) + .with(pv_reg(31)); + +fn create_reg_environment() -> MachineEnv { + // Prefer caller-saved registers over callee-saved registers, because that + // way we don't need to emit code to save and restore them if we don't + // mutate them. + + let preferred_regs_by_class: [Vec; 3] = { + let x_registers: Vec = (0..16).map(|x| px_reg(x)).collect(); + let f_registers: Vec = (0..16).map(|x| pf_reg(x)).collect(); + let v_registers: Vec = (0..32).map(|x| pv_reg(x)).collect(); + [x_registers, f_registers, v_registers] + }; + + let non_preferred_regs_by_class: [Vec; 3] = { + let x_registers: Vec = (16..XReg::SPECIAL_START) + .map(|x| px_reg(x.into())) + .collect(); + let f_registers: Vec = (16..32).map(|x| pf_reg(x)).collect(); + let v_registers: Vec = vec![]; + [x_registers, f_registers, v_registers] + }; + + MachineEnv { + preferred_regs_by_class, + non_preferred_regs_by_class, + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst.isle b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst.isle new file mode 100644 index 00000000000000..ffb72c24abf5b6 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst.isle @@ -0,0 +1,489 @@ +;;;; Instruction definition ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type OperandSize extern (enum Size32 Size64)) + +(decl ty_to_operand_size (Type) OperandSize) +(rule (ty_to_operand_size $I32) (OperandSize.Size32)) +(rule (ty_to_operand_size $I64) (OperandSize.Size64)) + +;; Note: in the instructions below, we order destination registers first and +;; then source registers afterwards. +(type MInst + (enum + ;;;; Pseudo-Instructions ;;;; + + ;; A pseudo-instruction that captures register arguments in vregs. + (Args (args VecArgPair)) + + ;; A pseudo-instruction that moves vregs to return registers. + (Rets (rets VecRetPair)) + + ;; Implementation of `br_table`, uses `idx` to jump to one of `targets` or + ;; jumps to `default` if it's out-of-bounds. + (BrTable + (idx XReg) + (default MachLabel) + (targets BoxVecMachLabel)) + + ;;;; Actual Instructions ;;;; + + ;; Trap if `cond` is true. + (TrapIf (cond Cond) (code TrapCode)) + + ;; Nothing. + (Nop) + + ;; Move a special register (e.g. sp, fp, lr, etc) in to a general-purpose + ;; register. + (GetSpecial + (dst WritableXReg) + (reg XReg)) + + ;; Load an external symbol's address into a register. + (LoadExtName (dst WritableXReg) + (name BoxExternalName) + (offset i64)) + + ;; A direct call to a known callee. + (Call (info BoxCallInfo)) + + ;; An indirect call to an unknown callee. + (IndirectCall (info BoxCallIndInfo)) + + ;; A direct return-call macro instruction. + (ReturnCall (info BoxReturnCallInfo)) + + ;; An indirect return-call macro instruction. + (ReturnIndirectCall (info BoxReturnCallIndInfo)) + + ;; An indirect call out to a host-defined function. The host function + ;; pointer is the first "argument" of this function call. + (IndirectCallHost (info BoxCallIndirectHostInfo)) + + ;; Unconditional jumps. + (Jump (label MachLabel)) + + ;; Jump to `then` if `c` is true, otherwise to `else`. + (BrIf (cond Cond) (taken MachLabel) (not_taken MachLabel)) + + ;; Load the memory address referenced by `mem` into `dst`. + (LoadAddr (dst WritableXReg) (mem Amode)) + + ;; Load `ty` bytes from memory pointed to by `mem` and store in `dst`. + ;; + ;; How much is written to the register is defined by `ExtKind`. The `flags` + ;; control behavior such as endianness. + (XLoad (dst WritableXReg) (mem Amode) (ty Type) (flags MemFlags) (ext ExtKind)) + (FLoad (dst WritableFReg) (mem Amode) (ty Type) (flags MemFlags)) + (VLoad (dst WritableVReg) (mem Amode) (ty Type) (flags MemFlags) (ext VExtKind)) + + ;; Stores. + (XStore (mem Amode) (src XReg) (ty Type) (flags MemFlags)) + (FStore (mem Amode) (src FReg) (ty Type) (flags MemFlags)) + (VStore (mem Amode) (src VReg) (ty Type) (flags MemFlags)) + + ;; A raw pulley instruction generated at compile-time via Pulley's + ;; `for_each_op!` macro. This variant has `pulley_*` constructors to + ;; emit this instruction and auto-generated methods for other various + ;; bits and pieces of boilerplate in the backend. + (Raw (raw RawInst)) + ) +) + +;; Helper type on conditional branches and traps to represent what the +;; condition that is being performed is. +;; +;; Used in `BrIf` and `TrapIf` above for example. +(type Cond + (enum + ;; True if `reg` contains a nonzero value in the low 32-bits. + (If32 (reg XReg)) + ;; True if `reg` contains a zero in the low 32-bits. + (IfNot32 (reg XReg)) + + ;; Conditionals for comparing the low 32-bits of two registers. + (IfXeq32 (src1 XReg) (src2 XReg)) + (IfXneq32 (src1 XReg) (src2 XReg)) + (IfXslt32 (src1 XReg) (src2 XReg)) + (IfXslteq32 (src1 XReg) (src2 XReg)) + (IfXult32 (src1 XReg) (src2 XReg)) + (IfXulteq32 (src1 XReg) (src2 XReg)) + + (IfXeq32I32 (src1 XReg) (src2 i32)) + (IfXneq32I32 (src1 XReg) (src2 i32)) + (IfXslt32I32 (src1 XReg) (src2 i32)) + (IfXslteq32I32 (src1 XReg) (src2 i32)) + (IfXult32I32 (src1 XReg) (src2 u32)) + (IfXulteq32I32 (src1 XReg) (src2 u32)) + (IfXsgt32I32 (src1 XReg) (src2 i32)) + (IfXsgteq32I32 (src1 XReg) (src2 i32)) + (IfXugt32I32 (src1 XReg) (src2 u32)) + (IfXugteq32I32 (src1 XReg) (src2 u32)) + + ;; Conditionals for comparing two 64-bit registers. + (IfXeq64 (src1 XReg) (src2 XReg)) + (IfXneq64 (src1 XReg) (src2 XReg)) + (IfXslt64 (src1 XReg) (src2 XReg)) + (IfXslteq64 (src1 XReg) (src2 XReg)) + (IfXult64 (src1 XReg) (src2 XReg)) + (IfXulteq64 (src1 XReg) (src2 XReg)) + + (IfXeq64I32 (src1 XReg) (src2 i32)) + (IfXneq64I32 (src1 XReg) (src2 i32)) + (IfXslt64I32 (src1 XReg) (src2 i32)) + (IfXslteq64I32 (src1 XReg) (src2 i32)) + (IfXult64I32 (src1 XReg) (src2 u32)) + (IfXulteq64I32 (src1 XReg) (src2 u32)) + (IfXsgt64I32 (src1 XReg) (src2 i32)) + (IfXsgteq64I32 (src1 XReg) (src2 i32)) + (IfXugt64I32 (src1 XReg) (src2 u32)) + (IfXugteq64I32 (src1 XReg) (src2 u32)) + ) +) + +(decl cond_invert (Cond) Cond) +(extern constructor cond_invert cond_invert) + +(decl raw_inst_to_inst (RawInst) MInst) +(rule (raw_inst_to_inst inst) (MInst.Raw inst)) +(convert RawInst MInst raw_inst_to_inst) + +(type U6 (primitive U6)) +(type BoxCallInfo (primitive BoxCallInfo)) +(type BoxCallIndInfo (primitive BoxCallIndInfo)) +(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) +(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) +(type XRegSet (primitive XRegSet)) +(type BoxCallIndirectHostInfo (primitive BoxCallIndirectHostInfo)) + +;;;; Address Modes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type StackAMode extern (enum)) + +(type Amode + (enum + (SpOffset (offset i32)) + (RegOffset (base XReg) (offset i32)) + (Stack (amode StackAMode)) + ) +) + +(type ExtKind (enum None Sign32 Sign64 Zero32 Zero64)) + +(type VExtKind (enum None S8x8 U8x8 S16x4 U16x4 S32x2 U32x2)) + +;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type XReg (primitive XReg)) +(type WritableXReg (primitive WritableXReg)) + +(type FReg (primitive FReg)) +(type WritableFReg (primitive WritableFReg)) + +(type VReg (primitive VReg)) +(type WritableVReg (primitive WritableVReg)) + +;; Construct a new `XReg` from a `Reg`. +;; +;; Asserts that the register has an integer RegClass. +(decl xreg_new (Reg) XReg) +(extern constructor xreg_new xreg_new) +(convert Reg XReg xreg_new) + +;; Construct a new `WritableXReg` from a `WritableReg`. +;; +;; Asserts that the register has an integer RegClass. +(decl writable_xreg_new (WritableReg) WritableXReg) +(extern constructor writable_xreg_new writable_xreg_new) +(convert WritableReg WritableXReg writable_xreg_new) + +;; Put a value into a XReg. +;; +;; Asserts that the value goes into a XReg. +(decl put_in_xreg (Value) XReg) +(rule (put_in_xreg val) (xreg_new (put_in_reg val))) +(convert Value XReg put_in_xreg) + +;; Construct an `InstOutput` out of a single XReg register. +(decl output_xreg (XReg) InstOutput) +(rule (output_xreg x) (output_reg x)) +(convert XReg InstOutput output_xreg) + +;; Convert a `WritableXReg` to an `XReg`. +(decl pure writable_xreg_to_xreg (WritableXReg) XReg) +(extern constructor writable_xreg_to_xreg writable_xreg_to_xreg) +(convert WritableXReg XReg writable_xreg_to_xreg) + +;; Convert a `WritableXReg` to an `WritableReg`. +(decl pure writable_xreg_to_writable_reg (WritableXReg) WritableReg) +(extern constructor writable_xreg_to_writable_reg writable_xreg_to_writable_reg) +(convert WritableXReg WritableReg writable_xreg_to_writable_reg) + +;; Convert a `WritableXReg` to an `Reg`. +(decl pure writable_xreg_to_reg (WritableXReg) Reg) +(rule (writable_xreg_to_reg x) (writable_xreg_to_writable_reg x)) +(convert WritableXReg Reg writable_xreg_to_reg) + +;; Convert an `XReg` to a `Reg`. +(decl pure xreg_to_reg (XReg) Reg) +(extern constructor xreg_to_reg xreg_to_reg) +(convert XReg Reg xreg_to_reg) + +;; Convert a `XReg` to a `ValueRegs`. +(decl xreg_to_value_regs (XReg) ValueRegs) +(rule (xreg_to_value_regs x) (value_reg x)) +(convert XReg ValueRegs xreg_to_reg) + +;; Convert a `WritableXReg` to a `ValueRegs`. +(decl writable_xreg_to_value_regs (WritableXReg) ValueRegs) +(rule (writable_xreg_to_value_regs x) (value_reg x)) +(convert WritableXReg ValueRegs writable_xreg_to_value_regs) + +;; Allocates a new `WritableXReg`. +(decl temp_writable_xreg () WritableXReg) +(rule (temp_writable_xreg) (temp_writable_reg $I64)) + +;; Construct a new `FReg` from a `Reg`. +;; +;; Asserts that the register has a Float RegClass. +(decl freg_new (Reg) FReg) +(extern constructor freg_new freg_new) +(convert Reg FReg freg_new) + +;; Construct a new `WritableFReg` from a `WritableReg`. +;; +;; Asserts that the register has a Float RegClass. +(decl writable_freg_new (WritableReg) WritableFReg) +(extern constructor writable_freg_new writable_freg_new) +(convert WritableReg WritableFReg writable_freg_new) + +;; Put a value into a FReg. +;; +;; Asserts that the value goes into a FReg. +(decl put_in_freg (Value) FReg) +(rule (put_in_freg val) (freg_new (put_in_reg val))) +(convert Value FReg put_in_freg) + +;; Construct an `InstOutput` out of a single FReg register. +(decl output_freg (FReg) InstOutput) +(rule (output_freg x) (output_reg x)) +(convert FReg InstOutput output_freg) + +;; Convert a `WritableFReg` to an `FReg`. +(decl pure writable_freg_to_freg (WritableFReg) FReg) +(extern constructor writable_freg_to_freg writable_freg_to_freg) +(convert WritableFReg FReg writable_freg_to_freg) + +;; Convert a `WritableFReg` to an `WritableReg`. +(decl pure writable_freg_to_writable_reg (WritableFReg) WritableReg) +(extern constructor writable_freg_to_writable_reg writable_freg_to_writable_reg) +(convert WritableFReg WritableReg writable_freg_to_writable_reg) + +;; Convert a `WritableFReg` to an `Reg`. +(decl pure writable_freg_to_reg (WritableFReg) Reg) +(rule (writable_freg_to_reg x) (writable_freg_to_writable_reg x)) +(convert WritableFReg Reg writable_freg_to_reg) + +;; Convert an `FReg` to a `Reg`. +(decl pure freg_to_reg (FReg) Reg) +(extern constructor freg_to_reg freg_to_reg) +(convert FReg Reg freg_to_reg) + +;; Convert a `FReg` to a `ValueRegs`. +(decl freg_to_value_regs (FReg) ValueRegs) +(rule (freg_to_value_regs x) (value_reg x)) +(convert FReg ValueRegs xreg_to_reg) + +;; Convert a `WritableFReg` to a `ValueRegs`. +(decl writable_freg_to_value_regs (WritableFReg) ValueRegs) +(rule (writable_freg_to_value_regs x) (value_reg x)) +(convert WritableFReg ValueRegs writable_freg_to_value_regs) + +;; Allocates a new `WritableFReg`. +(decl temp_writable_freg () WritableFReg) +(rule (temp_writable_freg) (temp_writable_reg $F64)) + +;; Construct a new `VReg` from a `Reg`. +;; +;; Asserts that the register has a Vector RegClass. +(decl vreg_new (Reg) VReg) +(extern constructor vreg_new vreg_new) +(convert Reg VReg vreg_new) + +;; Construct a new `WritableVReg` from a `WritableReg`. +;; +;; Asserts that the register has a Vector RegClass. +(decl writable_vreg_new (WritableReg) WritableVReg) +(extern constructor writable_vreg_new writable_vreg_new) +(convert WritableReg WritableVReg writable_vreg_new) + +;; Put a value into a VReg. +;; +;; Asserts that the value goes into a VReg. +(decl put_in_vreg (Value) VReg) +(rule (put_in_vreg val) (vreg_new (put_in_reg val))) +(convert Value VReg put_in_vreg) + +;; Construct an `InstOutput` out of a single VReg register. +(decl output_vreg (VReg) InstOutput) +(rule (output_vreg x) (output_reg x)) +(convert VReg InstOutput output_vreg) + +;; Convert a `WritableVReg` to an `VReg`. +(decl pure writable_vreg_to_vreg (WritableVReg) VReg) +(extern constructor writable_vreg_to_vreg writable_vreg_to_vreg) +(convert WritableVReg VReg writable_vreg_to_vreg) + +;; Convert a `WritableVReg` to an `WritableReg`. +(decl pure writable_vreg_to_writable_reg (WritableVReg) WritableReg) +(extern constructor writable_vreg_to_writable_reg writable_vreg_to_writable_reg) +(convert WritableVReg WritableReg writable_vreg_to_writable_reg) + +;; Convert a `WritableVReg` to an `Reg`. +(decl pure writable_vreg_to_reg (WritableVReg) Reg) +(rule (writable_vreg_to_reg x) (writable_vreg_to_writable_reg x)) +(convert WritableVReg Reg writable_vreg_to_reg) + +;; Convert an `VReg` to a `Reg`. +(decl pure vreg_to_reg (VReg) Reg) +(extern constructor vreg_to_reg vreg_to_reg) +(convert VReg Reg vreg_to_reg) + +;; Convert a `VReg` to a `ValueRegs`. +(decl vreg_to_value_regs (VReg) ValueRegs) +(rule (vreg_to_value_regs x) (value_reg x)) +(convert VReg ValueRegs xreg_to_reg) + +;; Convert a `WritableVReg` to a `ValueRegs`. +(decl writable_vreg_to_value_regs (WritableVReg) ValueRegs) +(rule (writable_vreg_to_value_regs x) (value_reg x)) +(convert WritableVReg ValueRegs writable_vreg_to_value_regs) + +;; Allocates a new `WritableVReg`. +(decl temp_writable_vreg () WritableVReg) +(rule (temp_writable_vreg) (temp_writable_reg $I8X16)) + +;;;; Materializing Constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Lower a constant into a register. +(decl imm (Type u64) Reg) + +;; If a value can fit into 8 bits, then prioritize that. +(rule 3 (imm (ty_int _) x) + (if-let y (i8_try_from_u64 x)) + (pulley_xconst8 y)) + +;; If a value can fit into 16 bits, then prioritize that. +(rule 2 (imm (ty_int _) x) + (if-let y (i16_try_from_u64 x)) + (pulley_xconst16 y)) + +;; If a value can fit into 32 bits, then prioritize that. +(rule 1 (imm (ty_int _) x) + (if-let y (i32_try_from_u64 x)) + (pulley_xconst32 y)) + +;; Base cases for integers. +(rule 0 (imm $I8 x) (pulley_xconst8 (u8_as_i8 (u64_as_u8 x)))) +(rule 0 (imm $I16 x) (pulley_xconst16 (u16_as_i16 (u64_as_u16 x)))) +(rule 0 (imm $I32 x) (pulley_xconst32 (u64_as_i32 x))) +(rule 0 (imm $I64 x) (pulley_xconst64 (u64_as_i64 x))) + +;; Base cases for floats. +(rule 0 (imm $F32 (u64_as_u32 c)) (pulley_fconst32 c)) +(rule 0 (imm $F64 c) (pulley_fconst64 c)) + +;;;; Instruction Constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pulley_trap_if (Cond TrapCode) SideEffectNoResult) +(rule (pulley_trap_if cond code) + (SideEffectNoResult.Inst (MInst.TrapIf cond code))) + +(decl sp_reg () XReg) +(extern constructor sp_reg sp_reg) + +(decl pulley_get_special (XReg) XReg) +(rule (pulley_get_special reg) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.GetSpecial dst reg)))) + dst)) + +(decl pulley_jump (MachLabel) SideEffectNoResult) +(rule (pulley_jump label) + (SideEffectNoResult.Inst (MInst.Jump label))) + +(decl pulley_br_if (Cond MachLabel MachLabel) SideEffectNoResult) +(rule (pulley_br_if cond taken not_taken) + (SideEffectNoResult.Inst (MInst.BrIf cond taken not_taken))) + +(decl pulley_xload (Amode Type MemFlags ExtKind) XReg) +(rule (pulley_xload amode ty flags ext) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.XLoad dst amode ty flags ext)))) + dst)) + +(decl pulley_xstore (Amode XReg Type MemFlags) SideEffectNoResult) +(rule (pulley_xstore amode src ty flags) + (SideEffectNoResult.Inst (MInst.XStore amode src ty flags))) + +(decl pulley_fload (Amode Type MemFlags) FReg) +(rule (pulley_fload amode ty flags) + (let ((dst WritableFReg (temp_writable_freg)) + (_ Unit (emit (MInst.FLoad dst amode ty flags)))) + dst)) + +(decl pulley_fstore (Amode FReg Type MemFlags) SideEffectNoResult) +(rule (pulley_fstore amode src ty flags) + (SideEffectNoResult.Inst (MInst.FStore amode src ty flags))) + +(decl pulley_vload (Amode Type MemFlags VExtKind) VReg) +(rule (pulley_vload amode ty flags ext) + (let ((dst WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VLoad dst amode ty flags ext)))) + dst)) + +(decl pulley_vstore (Amode VReg Type MemFlags) SideEffectNoResult) +(rule (pulley_vstore amode src ty flags) + (SideEffectNoResult.Inst (MInst.VStore amode src ty flags))) + +(decl gen_br_table (XReg MachLabel BoxVecMachLabel) Unit) +(rule (gen_br_table idx default labels) + (emit (MInst.BrTable idx default labels))) + +;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_call (SigRef ExternalName RelocDistance ValueSlice) InstOutput) +(extern constructor gen_call gen_call) + +(decl gen_call_indirect (SigRef Value ValueSlice) InstOutput) +(extern constructor gen_call_indirect gen_call_indirect) + +;;;; Helpers for Sign extension ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Sign extend a `Value` to at least 32-bit +(decl zext32 (Value) XReg) +(rule (zext32 val @ (value_type $I8)) (pulley_zext8 val)) +(rule (zext32 val @ (value_type $I16)) (pulley_zext16 val)) +(rule (zext32 val @ (value_type $I32)) val) +(rule (zext32 val @ (value_type $I64)) val) + +;; Same as `zext32` but for sign-extension +(decl sext32 (Value) XReg) +(rule (sext32 val @ (value_type $I8)) (pulley_sext8 val)) +(rule (sext32 val @ (value_type $I16)) (pulley_sext16 val)) +(rule (sext32 val @ (value_type $I32)) val) +(rule (sext32 val @ (value_type $I64)) val) + +;; Sign extend a `Value` to at least 64-bit +(decl zext64 (Value) XReg) +(rule (zext64 val @ (value_type $I8)) (pulley_zext8 val)) +(rule (zext64 val @ (value_type $I16)) (pulley_zext16 val)) +(rule (zext64 val @ (value_type $I32)) (pulley_zext32 val)) +(rule (zext64 val @ (value_type $I64)) val) + +;; Same as `zext64` but for sign-extension +(decl sext64 (Value) XReg) +(rule (sext64 val @ (value_type $I8)) (pulley_sext8 val)) +(rule (sext64 val @ (value_type $I16)) (pulley_sext16 val)) +(rule (sext64 val @ (value_type $I32)) (pulley_sext32 val)) +(rule (sext64 val @ (value_type $I64)) val) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/args.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/args.rs new file mode 100644 index 00000000000000..48bb791538e317 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/args.rs @@ -0,0 +1,580 @@ +//! Pulley instruction arguments. + +use super::*; +use crate::ir::ExternalName; +use crate::machinst::abi::StackAMode; +use pulley_interpreter::encode; +use pulley_interpreter::regs::Reg as _; +use std::fmt; + +/// A macro for defining a newtype of `Reg` that enforces some invariant about +/// the wrapped `Reg` (such as that it is of a particular register class). +macro_rules! newtype_of_reg { + ( + $newtype_reg:ident, + $newtype_writable_reg:ident, + $class:expr + ) => { + /// A newtype wrapper around `Reg`. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $newtype_reg(Reg); + + impl PartialEq for $newtype_reg { + fn eq(&self, other: &Reg) -> bool { + self.0 == *other + } + } + + impl From<$newtype_reg> for Reg { + fn from(r: $newtype_reg) -> Self { + r.0 + } + } + + impl TryFrom for $newtype_reg { + type Error = (); + fn try_from(r: Reg) -> Result { + Self::new(r).ok_or(()) + } + } + + impl $newtype_reg { + /// Create this newtype from the given register, or return `None` if the register + /// is not a valid instance of this newtype. + pub fn new(reg: Reg) -> Option { + if reg.class() == $class { + Some(Self(reg)) + } else { + None + } + } + + /// Get this newtype's underlying `Reg`. + pub fn to_reg(self) -> Reg { + self.0 + } + } + + // Convenience impl so that people working with this newtype can use it + // "just like" a plain `Reg`. + // + // NB: We cannot implement `DerefMut` because that would let people do + // nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the + // invariants that `XReg` provides. + impl std::ops::Deref for $newtype_reg { + type Target = Reg; + + fn deref(&self) -> &Reg { + &self.0 + } + } + + /// If you know what you're doing, you can explicitly mutably borrow the + /// underlying `Reg`. Don't make it point to the wrong type of register + /// please. + impl AsMut for $newtype_reg { + fn as_mut(&mut self) -> &mut Reg { + &mut self.0 + } + } + + /// Writable Reg. + pub type $newtype_writable_reg = Writable<$newtype_reg>; + + impl From for $newtype_reg { + fn from(r: pulley_interpreter::regs::$newtype_reg) -> Self { + Self::new(regalloc2::PReg::new(usize::from(r as u8), $class).into()).unwrap() + } + } + impl From<$newtype_reg> for pulley_interpreter::regs::$newtype_reg { + fn from(r: $newtype_reg) -> Self { + Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap() + } + } + impl<'a> From<&'a $newtype_reg> for pulley_interpreter::regs::$newtype_reg { + fn from(r: &'a $newtype_reg) -> Self { + Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap() + } + } + impl From<$newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg { + fn from(r: $newtype_writable_reg) -> Self { + Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap() + } + } + impl<'a> From<&'a $newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg { + fn from(r: &'a $newtype_writable_reg) -> Self { + Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap() + } + } + + impl TryFrom> for $newtype_writable_reg { + type Error = (); + fn try_from(r: Writable) -> Result { + let r = r.to_reg(); + match $newtype_reg::new(r) { + Some(r) => Ok(Writable::from_reg(r)), + None => Err(()), + } + } + } + }; +} + +// Newtypes for registers classes. +newtype_of_reg!(XReg, WritableXReg, RegClass::Int); +newtype_of_reg!(FReg, WritableFReg, RegClass::Float); +newtype_of_reg!(VReg, WritableVReg, RegClass::Vector); + +impl XReg { + /// Index of the first "special" register, or the end of which registers + /// regalloc is allowed to use. + pub const SPECIAL_START: u8 = pulley_interpreter::regs::XReg::SPECIAL_START; + + /// Returns whether this is a "special" physical register for pulley. + pub fn is_special(&self) -> bool { + match self.as_pulley() { + Some(reg) => reg.is_special(), + None => false, + } + } + + /// Returns the pulley-typed register, if this is a physical register. + pub fn as_pulley(&self) -> Option { + let enc = self.to_real_reg()?.hw_enc(); + Some(pulley_interpreter::XReg::new(enc).unwrap()) + } +} + +pub use super::super::lower::isle::generated_code::ExtKind; + +pub use super::super::lower::isle::generated_code::Amode; + +impl Amode { + /// Add the registers referenced by this Amode to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + Amode::RegOffset { base, offset: _ } => collector.reg_use(base), + // Registers used in these modes aren't allocatable. + Amode::SpOffset { .. } | Amode::Stack { .. } => {} + } + } + + pub(crate) fn get_base_register(&self) -> Option { + match self { + Amode::RegOffset { base, offset: _ } => Some((*base).into()), + Amode::SpOffset { .. } | Amode::Stack { .. } => Some(XReg::new(stack_reg()).unwrap()), + } + } + + pub(crate) fn get_offset_with_state

(&self, state: &EmitState

) -> i32 + where + P: PulleyTargetKind, + { + match self { + Amode::RegOffset { base: _, offset } | Amode::SpOffset { offset } => *offset, + Amode::Stack { amode } => { + let offset64 = match amode { + StackAMode::IncomingArg(offset, stack_args_size) => { + let offset = i64::from(*stack_args_size) - *offset; + let frame_layout = state.frame_layout(); + let sp_offset = frame_layout.tail_args_size + + frame_layout.setup_area_size + + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size; + i64::from(sp_offset) - offset + } + StackAMode::Slot(offset) => { + offset + i64::from(state.frame_layout().outgoing_args_size) + } + StackAMode::OutgoingArg(offset) => *offset, + }; + i32::try_from(offset64).unwrap() + } + } + } +} + +impl core::fmt::Display for Amode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Amode::SpOffset { offset } => { + if *offset >= 0 { + write!(f, "sp+{offset}") + } else { + write!(f, "sp{offset}") + } + } + Amode::RegOffset { base, offset } => { + let name = reg_name(**base); + if *offset >= 0 { + write!(f, "{name}+{offset}") + } else { + write!(f, "{name}{offset}") + } + } + Amode::Stack { amode } => core::fmt::Debug::fmt(amode, f), + } + } +} + +impl From for Amode { + fn from(amode: StackAMode) -> Self { + Amode::Stack { amode } + } +} + +/// The size of an operand or operation. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OperandSize { + /// 32 bits. + Size32, + /// 64 bits. + Size64, +} + +pub use crate::isa::pulley_shared::lower::isle::generated_code::Cond; + +impl Cond { + /// Collect register operands within `collector` for register allocation. + pub fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + Cond::If32 { reg } | Cond::IfNot32 { reg } => collector.reg_use(reg), + + Cond::IfXeq32 { src1, src2 } + | Cond::IfXneq32 { src1, src2 } + | Cond::IfXslt32 { src1, src2 } + | Cond::IfXslteq32 { src1, src2 } + | Cond::IfXult32 { src1, src2 } + | Cond::IfXulteq32 { src1, src2 } + | Cond::IfXeq64 { src1, src2 } + | Cond::IfXneq64 { src1, src2 } + | Cond::IfXslt64 { src1, src2 } + | Cond::IfXslteq64 { src1, src2 } + | Cond::IfXult64 { src1, src2 } + | Cond::IfXulteq64 { src1, src2 } => { + collector.reg_use(src1); + collector.reg_use(src2); + } + + Cond::IfXeq32I32 { src1, src2 } + | Cond::IfXneq32I32 { src1, src2 } + | Cond::IfXslt32I32 { src1, src2 } + | Cond::IfXslteq32I32 { src1, src2 } + | Cond::IfXsgt32I32 { src1, src2 } + | Cond::IfXsgteq32I32 { src1, src2 } + | Cond::IfXeq64I32 { src1, src2 } + | Cond::IfXneq64I32 { src1, src2 } + | Cond::IfXslt64I32 { src1, src2 } + | Cond::IfXslteq64I32 { src1, src2 } + | Cond::IfXsgt64I32 { src1, src2 } + | Cond::IfXsgteq64I32 { src1, src2 } => { + collector.reg_use(src1); + let _: &mut i32 = src2; + } + + Cond::IfXult32I32 { src1, src2 } + | Cond::IfXulteq32I32 { src1, src2 } + | Cond::IfXugt32I32 { src1, src2 } + | Cond::IfXugteq32I32 { src1, src2 } + | Cond::IfXult64I32 { src1, src2 } + | Cond::IfXulteq64I32 { src1, src2 } + | Cond::IfXugt64I32 { src1, src2 } + | Cond::IfXugteq64I32 { src1, src2 } => { + collector.reg_use(src1); + let _: &mut u32 = src2; + } + } + } + + /// Encode this condition as a branch into `sink`. + /// + /// Note that the offset encoded to jump by is filled in as 0 and it's + /// assumed `MachBuffer` will come back and clean it up. + pub fn encode(&self, sink: &mut impl Extend) { + match *self { + Cond::If32 { reg } => encode::br_if32(sink, reg, 0), + Cond::IfNot32 { reg } => encode::br_if_not32(sink, reg, 0), + Cond::IfXeq32 { src1, src2 } => encode::br_if_xeq32(sink, src1, src2, 0), + Cond::IfXneq32 { src1, src2 } => encode::br_if_xneq32(sink, src1, src2, 0), + Cond::IfXslt32 { src1, src2 } => encode::br_if_xslt32(sink, src1, src2, 0), + Cond::IfXslteq32 { src1, src2 } => encode::br_if_xslteq32(sink, src1, src2, 0), + Cond::IfXult32 { src1, src2 } => encode::br_if_xult32(sink, src1, src2, 0), + Cond::IfXulteq32 { src1, src2 } => encode::br_if_xulteq32(sink, src1, src2, 0), + Cond::IfXeq64 { src1, src2 } => encode::br_if_xeq64(sink, src1, src2, 0), + Cond::IfXneq64 { src1, src2 } => encode::br_if_xneq64(sink, src1, src2, 0), + Cond::IfXslt64 { src1, src2 } => encode::br_if_xslt64(sink, src1, src2, 0), + Cond::IfXslteq64 { src1, src2 } => encode::br_if_xslteq64(sink, src1, src2, 0), + Cond::IfXult64 { src1, src2 } => encode::br_if_xult64(sink, src1, src2, 0), + Cond::IfXulteq64 { src1, src2 } => encode::br_if_xulteq64(sink, src1, src2, 0), + + Cond::IfXeq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xeq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xeq32_i32(sink, src1, src2, 0), + }, + Cond::IfXneq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xneq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xneq32_i32(sink, src1, src2, 0), + }, + Cond::IfXslt32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslt32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslt32_i32(sink, src1, src2, 0), + }, + Cond::IfXslteq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslteq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslteq32_i32(sink, src1, src2, 0), + }, + Cond::IfXsgt32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgt32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgt32_i32(sink, src1, src2, 0), + }, + Cond::IfXsgteq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgteq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgteq32_i32(sink, src1, src2, 0), + }, + Cond::IfXult32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xult32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xult32_u32(sink, src1, src2, 0), + }, + Cond::IfXulteq32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xulteq32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xulteq32_u32(sink, src1, src2, 0), + }, + Cond::IfXugt32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugt32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugt32_u32(sink, src1, src2, 0), + }, + Cond::IfXugteq32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugteq32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugteq32_u32(sink, src1, src2, 0), + }, + + Cond::IfXeq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xeq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xeq64_i32(sink, src1, src2, 0), + }, + Cond::IfXneq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xneq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xneq64_i32(sink, src1, src2, 0), + }, + Cond::IfXslt64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslt64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslt64_i32(sink, src1, src2, 0), + }, + Cond::IfXslteq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslteq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslteq64_i32(sink, src1, src2, 0), + }, + Cond::IfXsgt64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgt64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgt64_i32(sink, src1, src2, 0), + }, + Cond::IfXsgteq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgteq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgteq64_i32(sink, src1, src2, 0), + }, + Cond::IfXult64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xult64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xult64_u32(sink, src1, src2, 0), + }, + Cond::IfXulteq64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xulteq64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xulteq64_u32(sink, src1, src2, 0), + }, + Cond::IfXugt64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugt64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugt64_u32(sink, src1, src2, 0), + }, + Cond::IfXugteq64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugteq64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugteq64_u32(sink, src1, src2, 0), + }, + } + } + + /// Inverts this conditional. + pub fn invert(&self) -> Cond { + match *self { + Cond::If32 { reg } => Cond::IfNot32 { reg }, + Cond::IfNot32 { reg } => Cond::If32 { reg }, + Cond::IfXeq32 { src1, src2 } => Cond::IfXneq32 { src1, src2 }, + Cond::IfXneq32 { src1, src2 } => Cond::IfXeq32 { src1, src2 }, + Cond::IfXeq64 { src1, src2 } => Cond::IfXneq64 { src1, src2 }, + Cond::IfXneq64 { src1, src2 } => Cond::IfXeq64 { src1, src2 }, + + // Note that for below the condition changes but the operands are + // also swapped. + Cond::IfXslt32 { src1, src2 } => Cond::IfXslteq32 { + src1: src2, + src2: src1, + }, + Cond::IfXslteq32 { src1, src2 } => Cond::IfXslt32 { + src1: src2, + src2: src1, + }, + Cond::IfXult32 { src1, src2 } => Cond::IfXulteq32 { + src1: src2, + src2: src1, + }, + Cond::IfXulteq32 { src1, src2 } => Cond::IfXult32 { + src1: src2, + src2: src1, + }, + Cond::IfXslt64 { src1, src2 } => Cond::IfXslteq64 { + src1: src2, + src2: src1, + }, + Cond::IfXslteq64 { src1, src2 } => Cond::IfXslt64 { + src1: src2, + src2: src1, + }, + Cond::IfXult64 { src1, src2 } => Cond::IfXulteq64 { + src1: src2, + src2: src1, + }, + Cond::IfXulteq64 { src1, src2 } => Cond::IfXult64 { + src1: src2, + src2: src1, + }, + + Cond::IfXeq32I32 { src1, src2 } => Cond::IfXneq32I32 { src1, src2 }, + Cond::IfXneq32I32 { src1, src2 } => Cond::IfXeq32I32 { src1, src2 }, + Cond::IfXslt32I32 { src1, src2 } => Cond::IfXsgteq32I32 { src1, src2 }, + Cond::IfXslteq32I32 { src1, src2 } => Cond::IfXsgt32I32 { src1, src2 }, + Cond::IfXult32I32 { src1, src2 } => Cond::IfXugteq32I32 { src1, src2 }, + Cond::IfXulteq32I32 { src1, src2 } => Cond::IfXugt32I32 { src1, src2 }, + Cond::IfXsgt32I32 { src1, src2 } => Cond::IfXslteq32I32 { src1, src2 }, + Cond::IfXsgteq32I32 { src1, src2 } => Cond::IfXslt32I32 { src1, src2 }, + Cond::IfXugt32I32 { src1, src2 } => Cond::IfXulteq32I32 { src1, src2 }, + Cond::IfXugteq32I32 { src1, src2 } => Cond::IfXult32I32 { src1, src2 }, + + Cond::IfXeq64I32 { src1, src2 } => Cond::IfXneq64I32 { src1, src2 }, + Cond::IfXneq64I32 { src1, src2 } => Cond::IfXeq64I32 { src1, src2 }, + Cond::IfXslt64I32 { src1, src2 } => Cond::IfXsgteq64I32 { src1, src2 }, + Cond::IfXslteq64I32 { src1, src2 } => Cond::IfXsgt64I32 { src1, src2 }, + Cond::IfXult64I32 { src1, src2 } => Cond::IfXugteq64I32 { src1, src2 }, + Cond::IfXulteq64I32 { src1, src2 } => Cond::IfXugt64I32 { src1, src2 }, + Cond::IfXsgt64I32 { src1, src2 } => Cond::IfXslteq64I32 { src1, src2 }, + Cond::IfXsgteq64I32 { src1, src2 } => Cond::IfXslt64I32 { src1, src2 }, + Cond::IfXugt64I32 { src1, src2 } => Cond::IfXulteq64I32 { src1, src2 }, + Cond::IfXugteq64I32 { src1, src2 } => Cond::IfXult64I32 { src1, src2 }, + } + } +} + +impl fmt::Display for Cond { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Cond::If32 { reg } => write!(f, "if32 {}", reg_name(**reg)), + Cond::IfNot32 { reg } => write!(f, "if_not32 {}", reg_name(**reg)), + Cond::IfXeq32 { src1, src2 } => { + write!(f, "if_xeq32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXneq32 { src1, src2 } => { + write!(f, "if_xneq32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXslt32 { src1, src2 } => { + write!(f, "if_xslt32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXslteq32 { src1, src2 } => { + write!(f, "if_xslteq32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXult32 { src1, src2 } => { + write!(f, "if_xult32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXulteq32 { src1, src2 } => { + write!(f, "if_xulteq32 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXeq64 { src1, src2 } => { + write!(f, "if_xeq64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXneq64 { src1, src2 } => { + write!(f, "if_xneq64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXslt64 { src1, src2 } => { + write!(f, "if_xslt64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXslteq64 { src1, src2 } => { + write!(f, "if_xslteq64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXult64 { src1, src2 } => { + write!(f, "if_xult64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXulteq64 { src1, src2 } => { + write!(f, "if_xulteq64 {}, {}", reg_name(**src1), reg_name(**src2)) + } + Cond::IfXeq32I32 { src1, src2 } => { + write!(f, "if_xeq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXneq32I32 { src1, src2 } => { + write!(f, "if_xneq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslt32I32 { src1, src2 } => { + write!(f, "if_xslt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslteq32I32 { src1, src2 } => { + write!(f, "if_xslteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgt32I32 { src1, src2 } => { + write!(f, "if_xsgt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgteq32I32 { src1, src2 } => { + write!(f, "if_xsgteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXult32I32 { src1, src2 } => { + write!(f, "if_xult32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXulteq32I32 { src1, src2 } => { + write!(f, "if_xulteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugt32I32 { src1, src2 } => { + write!(f, "if_xugt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugteq32I32 { src1, src2 } => { + write!(f, "if_xugteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXeq64I32 { src1, src2 } => { + write!(f, "if_xeq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXneq64I32 { src1, src2 } => { + write!(f, "if_xneq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslt64I32 { src1, src2 } => { + write!(f, "if_xslt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslteq64I32 { src1, src2 } => { + write!(f, "if_xslteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgt64I32 { src1, src2 } => { + write!(f, "if_xsgt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgteq64I32 { src1, src2 } => { + write!(f, "if_xsgteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXult64I32 { src1, src2 } => { + write!(f, "if_xult64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXulteq64I32 { src1, src2 } => { + write!(f, "if_xulteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugt64I32 { src1, src2 } => { + write!(f, "if_xugt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugteq64I32 { src1, src2 } => { + write!(f, "if_xugteq64_i32 {}, {src2}", reg_name(**src1)) + } + } + } +} + +/// Payload of `CallInfo` for call instructions +#[derive(Clone, Debug)] +pub struct PulleyCall { + /// The external name that's being called, or the Cranelift-generated + /// function that's being invoked. + pub name: ExternalName, + /// Arguments tracked in this call invocation which aren't assigned fixed + /// registers. This tracks up to 4 registers and all remaining registers + /// will be present and tracked in `CallInfo` fields. + pub args: SmallVec<[XReg; 4]>, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/emit.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/emit.rs new file mode 100644 index 00000000000000..9090e3585f2ec1 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/emit.rs @@ -0,0 +1,710 @@ +//! Pulley binary code emission. + +use super::*; +use crate::ir::{self, Endianness}; +use crate::isa::pulley_shared::abi::PulleyMachineDeps; +use crate::isa::pulley_shared::PointerWidth; +use core::marker::PhantomData; +use cranelift_control::ControlPlane; +use pulley_interpreter::encode as enc; +use pulley_interpreter::regs::BinaryOperands; + +pub struct EmitInfo { + #[allow(dead_code)] // Will get used as we fill out this backend. + shared_flags: settings::Flags, + + #[allow(dead_code)] // Will get used as we fill out this backend. + isa_flags: crate::isa::pulley_shared::settings::Flags, +} + +impl EmitInfo { + pub(crate) fn new( + shared_flags: settings::Flags, + isa_flags: crate::isa::pulley_shared::settings::Flags, + ) -> Self { + Self { + shared_flags, + isa_flags, + } + } + + fn endianness(&self, flags: MemFlags) -> Endianness { + let target_endianness = if self.isa_flags.big_endian() { + Endianness::Big + } else { + Endianness::Little + }; + flags.endianness(target_endianness) + } +} + +/// State carried between emissions of a sequence of instructions. +#[derive(Default, Clone, Debug)] +pub struct EmitState

+where + P: PulleyTargetKind, +{ + _phantom: PhantomData

, + ctrl_plane: ControlPlane, + user_stack_map: Option, + frame_layout: FrameLayout, +} + +impl

EmitState

+where + P: PulleyTargetKind, +{ + fn take_stack_map(&mut self) -> Option { + self.user_stack_map.take() + } +} + +impl

MachInstEmitState> for EmitState

+where + P: PulleyTargetKind, +{ + fn new(abi: &Callee>, ctrl_plane: ControlPlane) -> Self { + EmitState { + _phantom: PhantomData, + ctrl_plane, + user_stack_map: None, + frame_layout: abi.frame_layout().clone(), + } + } + + fn pre_safepoint(&mut self, user_stack_map: Option) { + self.user_stack_map = user_stack_map; + } + + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane { + &mut self.ctrl_plane + } + + fn take_ctrl_plane(self) -> ControlPlane { + self.ctrl_plane + } + + fn frame_layout(&self) -> &FrameLayout { + &self.frame_layout + } +} + +impl

MachInstEmit for InstAndKind

+where + P: PulleyTargetKind, +{ + type State = EmitState

; + type Info = EmitInfo; + + fn emit(&self, sink: &mut MachBuffer, emit_info: &Self::Info, state: &mut Self::State) { + // N.B.: we *must* not exceed the "worst-case size" used to compute + // where to insert islands, except when islands are explicitly triggered + // (with an `EmitIsland`). We check this in debug builds. This is `mut` + // to allow disabling the check for `JTSequence`, which is always + // emitted following an `EmitIsland`. + let mut start = sink.cur_offset(); + pulley_emit(self, sink, emit_info, state, &mut start); + + let end = sink.cur_offset(); + assert!( + (end - start) <= InstAndKind::

::worst_case_size(), + "encoded inst {self:?} longer than worst-case size: length: {}, Inst::worst_case_size() = {}", + end - start, + InstAndKind::

::worst_case_size() + ); + } + + fn pretty_print_inst(&self, state: &mut Self::State) -> String { + self.print_with_state(state) + } +} + +/// Representation of a static offset from a pointer. +/// +/// In VCode this is always represented as an `i32` and then just before +/// lowering this is used to determine which instruction to emit. +enum Offset { + /// An unsigned 8-bit offset. + U8(u8), + /// A signed 32-bit offset. + I32(i32), +} + +impl From for Offset { + fn from(i: i32) -> Offset { + if let Ok(i) = i.try_into() { + return Offset::U8(i); + } + Offset::I32(i) + } +} + +fn pulley_emit

( + inst: &Inst, + sink: &mut MachBuffer>, + emit_info: &EmitInfo, + state: &mut EmitState

, + start_offset: &mut u32, +) where + P: PulleyTargetKind, +{ + match inst { + // Pseduo-instructions that don't actually encode to anything. + Inst::Args { .. } | Inst::Rets { .. } => {} + + Inst::TrapIf { cond, code } => { + let trap = sink.defer_trap(*code); + let not_trap = sink.get_label(); + + >::from(Inst::BrIf { + cond: cond.clone(), + taken: trap, + not_taken: not_trap, + }) + .emit(sink, emit_info, state); + sink.bind_label(not_trap, &mut state.ctrl_plane); + } + + Inst::Nop => todo!(), + + Inst::GetSpecial { dst, reg } => enc::xmov(sink, dst, reg), + + Inst::LoadExtName { .. } => todo!(), + + Inst::Call { info } => { + let offset = sink.cur_offset(); + + // If arguments happen to already be in the right register for the + // ABI then remove them from this list. Otherwise emit the + // appropriate `Call` instruction depending on how many arguments we + // have that aren't already in their correct register according to + // ABI conventions. + let mut args = &info.dest.args[..]; + while !args.is_empty() && args.last().copied() == XReg::new(x_reg(args.len() - 1)) { + args = &args[..args.len() - 1]; + } + match args { + [] => enc::call(sink, 0), + [x0] => enc::call1(sink, x0, 0), + [x0, x1] => enc::call2(sink, x0, x1, 0), + [x0, x1, x2] => enc::call3(sink, x0, x1, x2, 0), + [x0, x1, x2, x3] => enc::call4(sink, x0, x1, x2, x3, 0), + _ => unreachable!(), + } + let end = sink.cur_offset(); + sink.add_reloc_at_offset( + end - 4, + // TODO: is it actually okay to reuse this reloc here? + Reloc::X86CallPCRel4, + &info.dest.name, + // This addend adjusts for the difference between the start of + // the instruction and the beginning of the immediate offset + // field which is always the final 4 bytes of the instruction. + -i64::from(end - offset - 4), + ); + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + sink.add_call_site(); + + let adjust = -i32::try_from(info.callee_pop_size).unwrap(); + for i in PulleyMachineDeps::

::gen_sp_reg_adjust(adjust) { + >::from(i).emit(sink, emit_info, state); + } + } + + Inst::IndirectCall { info } => { + enc::call_indirect(sink, info.dest); + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + + sink.add_call_site(); + + let adjust = -i32::try_from(info.callee_pop_size).unwrap(); + for i in PulleyMachineDeps::

::gen_sp_reg_adjust(adjust) { + >::from(i).emit(sink, emit_info, state); + } + } + + Inst::ReturnCall { info } => { + emit_return_call_common_sequence(sink, emit_info, state, &info); + + // Emit an unconditional jump which is quite similar to `Inst::Call` + // except that a `jump` opcode is used instead of a `call` opcode. + sink.put1(pulley_interpreter::Opcode::Jump as u8); + sink.add_reloc(Reloc::X86CallPCRel4, &info.dest, -1); + sink.put4(0); + + // Islands were manually handled in + // `emit_return_call_common_sequence`. + *start_offset = sink.cur_offset(); + } + + Inst::ReturnIndirectCall { info } => { + emit_return_call_common_sequence(sink, emit_info, state, &info); + enc::xjump(sink, info.dest); + + // Islands were manually handled in + // `emit_return_call_common_sequence`. + *start_offset = sink.cur_offset(); + } + + Inst::IndirectCallHost { info } => { + // Emit a relocation to fill in the actual immediate argument here + // in `call_indirect_host`. + sink.add_reloc(Reloc::PulleyCallIndirectHost, &info.dest, 0); + enc::call_indirect_host(sink, 0_u8); + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + sink.add_call_site(); + + // If a callee pop is happening here that means that something has + // messed up, these are expected to be "very simple" signatures. + assert!(info.callee_pop_size == 0); + } + + Inst::Jump { label } => { + sink.use_label_at_offset(*start_offset + 1, *label, LabelUse::Jump(1)); + sink.add_uncond_branch(*start_offset, *start_offset + 5, *label); + enc::jump(sink, 0x00000000); + } + + Inst::BrIf { + cond, + taken, + not_taken, + } => { + // Encode the inverted form of the branch. Branches always have + // their trailing 4 bytes as the relative offset which is what we're + // going to target here within the `MachBuffer`. + let mut inverted = SmallVec::<[u8; 16]>::new(); + cond.invert().encode(&mut inverted); + let len = inverted.len() as u32; + debug_assert!(len > 4); + + // Use the `taken` label 4 bytes before the end of the instruction + // we're about to emit as that's the base of `PcRelOffset`. Note + // that the `Jump` here factors in the offset from the start of the + // instruction to the start of the relative offset, hence `len - 4` + // as the factor to adjust by. + let taken_end = *start_offset + len; + sink.use_label_at_offset(taken_end - 4, *taken, LabelUse::Jump(len - 4)); + sink.add_cond_branch(*start_offset, taken_end, *taken, &inverted); + cond.encode(sink); + debug_assert_eq!(sink.cur_offset(), taken_end); + + // For the not-taken branch use an unconditional jump to the + // relevant label, and we know that the jump instruction is 5 bytes + // long where the final 4 bytes are the offset to jump by. + let not_taken_start = taken_end + 1; + let not_taken_end = not_taken_start + 4; + sink.use_label_at_offset(not_taken_start, *not_taken, LabelUse::Jump(1)); + sink.add_uncond_branch(taken_end, not_taken_end, *not_taken); + enc::jump(sink, 0x00000000); + assert_eq!(sink.cur_offset(), not_taken_end); + } + + Inst::LoadAddr { dst, mem } => { + let base = mem.get_base_register(); + let offset = mem.get_offset_with_state(state); + + if let Some(base) = base { + if offset == 0 { + enc::xmov(sink, dst, base); + } else { + if let Ok(offset) = i8::try_from(offset) { + enc::xconst8(sink, dst, offset); + } else if let Ok(offset) = i16::try_from(offset) { + enc::xconst16(sink, dst, offset); + } else { + enc::xconst32(sink, dst, offset); + } + + match P::pointer_width() { + PointerWidth::PointerWidth32 => { + enc::xadd32(sink, BinaryOperands::new(dst, base, dst)) + } + PointerWidth::PointerWidth64 => { + enc::xadd64(sink, BinaryOperands::new(dst, base, dst)) + } + } + } + } else { + unreachable!("all pulley amodes have a base register right now") + } + } + + Inst::XLoad { + dst, + mem, + ty, + flags, + ext, + } => { + use Endianness as E; + use ExtKind as X; + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + match *ty { + I8 => match ext { + X::None | X::Zero32 => match x.into() { + Offset::I32(x) => enc::xload8_u32_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload8_u32_offset8(sink, dst, r, x), + }, + X::Zero64 => match x.into() { + Offset::I32(x) => enc::xload8_u64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload8_u64_offset8(sink, dst, r, x), + }, + X::Sign32 => match x.into() { + Offset::I32(x) => enc::xload8_s32_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload8_s32_offset8(sink, dst, r, x), + }, + X::Sign64 => match x.into() { + Offset::I32(x) => enc::xload8_s64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload8_s64_offset8(sink, dst, r, x), + }, + }, + I16 => match (ext, endian) { + (X::None | X::Zero32, E::Little) => match x.into() { + Offset::I32(x) => enc::xload16le_u32_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload16le_u32_offset8(sink, dst, r, x), + }, + (X::Sign32, E::Little) => match x.into() { + Offset::I32(x) => enc::xload16le_s32_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload16le_s32_offset8(sink, dst, r, x), + }, + (X::Zero64, E::Little) => match x.into() { + Offset::I32(x) => enc::xload16le_u64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload16le_u64_offset8(sink, dst, r, x), + }, + (X::Sign64, E::Little) => match x.into() { + Offset::I32(x) => enc::xload16le_s64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload16le_s64_offset8(sink, dst, r, x), + }, + (X::None | X::Zero32 | X::Zero64, E::Big) => { + enc::xload16be_u64_offset32(sink, dst, r, x); + } + (X::Sign32 | X::Sign64, E::Big) => { + enc::xload16be_s64_offset32(sink, dst, r, x); + } + }, + I32 => match (ext, endian) { + (X::None | X::Zero32 | X::Sign32, E::Little) => match x.into() { + Offset::I32(x) => enc::xload32le_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload32le_offset8(sink, dst, r, x), + }, + (X::Zero64, E::Little) => match x.into() { + Offset::I32(x) => enc::xload32le_u64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload32le_u64_offset8(sink, dst, r, x), + }, + (X::Sign64, E::Little) => match x.into() { + Offset::I32(x) => enc::xload32le_s64_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload32le_s64_offset8(sink, dst, r, x), + }, + (X::None | X::Zero32 | X::Zero64, E::Big) => { + enc::xload32be_u64_offset32(sink, dst, r, x); + } + (X::Sign32 | X::Sign64, E::Big) => { + enc::xload32be_s64_offset32(sink, dst, r, x); + } + }, + I64 => match endian { + E::Little => match x.into() { + Offset::I32(x) => enc::xload64le_offset32(sink, dst, r, x), + Offset::U8(x) => enc::xload64le_offset8(sink, dst, r, x), + }, + E::Big => enc::xload64be_offset32(sink, dst, r, x), + }, + _ => unimplemented!("xload ty={ty:?}"), + } + } + + Inst::FLoad { + dst, + mem, + ty, + flags, + } => { + use Endianness as E; + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + match *ty { + F32 => match endian { + E::Little => enc::fload32le_offset32(sink, dst, r, x), + E::Big => enc::fload32be_offset32(sink, dst, r, x), + }, + F64 => match endian { + E::Little => enc::fload64le_offset32(sink, dst, r, x), + E::Big => enc::fload64be_offset32(sink, dst, r, x), + }, + _ => unimplemented!("fload ty={ty:?}"), + } + } + + Inst::VLoad { + dst, + mem, + ty, + flags, + ext, + } => { + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + assert_eq!(endian, Endianness::Little); + assert_eq!(ty.bytes(), 16); + match ext { + VExtKind::None => enc::vload128le_offset32(sink, dst, r, x), + VExtKind::S8x8 => enc::vload8x8_s_offset32(sink, dst, r, x), + VExtKind::U8x8 => enc::vload8x8_u_offset32(sink, dst, r, x), + VExtKind::S16x4 => enc::vload16x4le_s_offset32(sink, dst, r, x), + VExtKind::U16x4 => enc::vload16x4le_u_offset32(sink, dst, r, x), + VExtKind::S32x2 => enc::vload32x2le_s_offset32(sink, dst, r, x), + VExtKind::U32x2 => enc::vload32x2le_u_offset32(sink, dst, r, x), + } + } + + Inst::XStore { + mem, + src, + ty, + flags, + } => { + use Endianness as E; + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + match *ty { + I8 => match x.into() { + Offset::I32(x) => enc::xstore8_offset32(sink, r, x, src), + Offset::U8(x) => enc::xstore8_offset8(sink, r, x, src), + }, + I16 => match endian { + E::Little => match x.into() { + Offset::I32(x) => enc::xstore16le_offset32(sink, r, x, src), + Offset::U8(x) => enc::xstore16le_offset8(sink, r, x, src), + }, + E::Big => enc::xstore16be_offset32(sink, r, x, src), + }, + I32 => match endian { + E::Little => match x.into() { + Offset::I32(x) => enc::xstore32le_offset32(sink, r, x, src), + Offset::U8(x) => enc::xstore32le_offset8(sink, r, x, src), + }, + E::Big => enc::xstore32be_offset32(sink, r, x, src), + }, + I64 => match endian { + E::Little => match x.into() { + Offset::I32(x) => enc::xstore64le_offset32(sink, r, x, src), + Offset::U8(x) => enc::xstore64le_offset8(sink, r, x, src), + }, + E::Big => enc::xstore64be_offset32(sink, r, x, src), + }, + _ => unimplemented!("xstore ty={ty:?}"), + } + } + + Inst::FStore { + mem, + src, + ty, + flags, + } => { + use Endianness as E; + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + match *ty { + F32 => match endian { + E::Little => enc::fstore32le_offset32(sink, r, x, src), + E::Big => enc::fstore32be_offset32(sink, r, x, src), + }, + F64 => match endian { + E::Little => enc::fstore64le_offset32(sink, r, x, src), + E::Big => enc::fstore64be_offset32(sink, r, x, src), + }, + _ => unimplemented!("fstore ty={ty:?}"), + } + } + + Inst::VStore { + mem, + src, + ty, + flags, + } => { + let r = mem.get_base_register().unwrap(); + let x = mem.get_offset_with_state(state); + let endian = emit_info.endianness(*flags); + assert_eq!(endian, Endianness::Little); + assert_eq!(ty.bytes(), 16); + enc::vstore128le_offset32(sink, r, x, src); + } + + Inst::BrTable { + idx, + default, + targets, + } => { + // Encode the `br_table32` instruction directly which expects the + // next `amt` 4-byte integers to all be relative offsets. Each + // offset is the pc-relative offset of the branch destination. + // + // Pulley clamps the branch targets to the `amt` specified so the + // final branch target is the default jump target. + // + // Note that this instruction may have many branch targets so it + // manually checks to see if an island is needed. If so we emit a + // jump around the island before the `br_table32` itself gets + // emitted. + let amt = u32::try_from(targets.len() + 1).expect("too many branch targets"); + let br_table_size = amt * 4 + 6; + if sink.island_needed(br_table_size) { + let label = sink.get_label(); + >::from(Inst::Jump { label }).emit(sink, emit_info, state); + sink.emit_island(br_table_size, &mut state.ctrl_plane); + sink.bind_label(label, &mut state.ctrl_plane); + } + enc::br_table32(sink, *idx, amt); + for target in targets.iter() { + let offset = sink.cur_offset(); + sink.use_label_at_offset(offset, *target, LabelUse::Jump(0)); + sink.put4(0); + } + let offset = sink.cur_offset(); + sink.use_label_at_offset(offset, *default, LabelUse::Jump(0)); + sink.put4(0); + + // We manually handled `emit_island` above when dealing with + // `island_needed` so update the starting offset to the current + // offset so this instruction doesn't accidentally trigger + // the assertion that we're always under worst-case-size. + *start_offset = sink.cur_offset(); + } + + Inst::Raw { raw } => { + match raw { + RawInst::PushFrame + | RawInst::StackAlloc32 { .. } + | RawInst::PushFrameSave { .. } => { + sink.add_trap(ir::TrapCode::STACK_OVERFLOW); + } + _ => {} + } + super::generated::emit(raw, sink) + } + } +} + +fn emit_return_call_common_sequence( + sink: &mut MachBuffer>, + emit_info: &EmitInfo, + state: &mut EmitState

, + info: &ReturnCallInfo, +) where + P: PulleyTargetKind, +{ + // The return call sequence can potentially emit a lot of instructions, so + // lets emit an island here if we need it. + // + // It is difficult to calculate exactly how many instructions are going to + // be emitted, so we calculate it by emitting it into a disposable buffer, + // and then checking how many instructions were actually emitted. + let mut buffer = MachBuffer::new(); + let mut fake_emit_state = state.clone(); + + return_call_emit_impl(&mut buffer, emit_info, &mut fake_emit_state, info); + + // Finalize the buffer and get the number of bytes emitted. + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + let length = buffer.data().len() as u32; + + // And now emit the island inline with this instruction. + if sink.island_needed(length) { + let jump_around_label = sink.get_label(); + >::gen_jump(jump_around_label).emit(sink, emit_info, state); + sink.emit_island(length + 4, &mut state.ctrl_plane); + sink.bind_label(jump_around_label, &mut state.ctrl_plane); + } + + // Now that we're done, emit the *actual* return sequence. + return_call_emit_impl(sink, emit_info, state, info); +} + +/// This should not be called directly, Instead prefer to call [emit_return_call_common_sequence]. +fn return_call_emit_impl( + sink: &mut MachBuffer>, + emit_info: &EmitInfo, + state: &mut EmitState

, + info: &ReturnCallInfo, +) where + P: PulleyTargetKind, +{ + let sp_to_fp_offset = { + let frame_layout = state.frame_layout(); + i64::from( + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size, + ) + }; + + // Restore all clobbered registers before leaving the function. + let mut clobber_offset = sp_to_fp_offset - 8; + for reg in state.frame_layout().clobbered_callee_saves.clone() { + let rreg = reg.to_reg(); + let ty = match rreg.class() { + RegClass::Int => I64, + RegClass::Float => F64, + RegClass::Vector => unimplemented!("Vector Clobber Restores"), + }; + + >::from(Inst::gen_load( + reg.map(Reg::from), + Amode::SpOffset { + offset: clobber_offset.try_into().unwrap(), + }, + ty, + MemFlags::trusted(), + )) + .emit(sink, emit_info, state); + + clobber_offset -= 8 + } + + // Restore the link register and frame pointer using a `pop_frame` + // instruction. This will move `sp` to the current frame pointer and then + // restore the old lr/fp, so this restores all of sp/fp/lr in one + // instruction. + let setup_area_size = i64::from(state.frame_layout().setup_area_size); + assert!(setup_area_size > 0, "must have frame pointers enabled"); + >::from(RawInst::PopFrame).emit(sink, emit_info, state); + + // Now that `sp` is restored to what it was on function entry it may need to + // be adjusted if the stack arguments of our own function differ from the + // stack arguments of the callee. Perform any necessary adjustment here. + // + // Note that this means that there's a brief window where stack arguments + // might be below `sp` in the case that the callee has more stack arguments + // than ourselves. That's in theory ok though as we're inventing the pulley + // ABI and nothing like async signals are happening that we have to worry + // about. + let incoming_args_diff = + i64::from(state.frame_layout().tail_args_size - info.new_stack_arg_size); + + if incoming_args_diff != 0 { + let amt = i32::try_from(incoming_args_diff).unwrap(); + for inst in PulleyMachineDeps::

::gen_sp_reg_adjust(amt) { + >::from(inst).emit(sink, emit_info, state); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/mod.rs new file mode 100644 index 00000000000000..6b77be3d8e3fae --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/mod.rs @@ -0,0 +1,846 @@ +//! This module defines Pulley-specific machine instruction types. + +use core::marker::PhantomData; + +use crate::binemit::{Addend, CodeOffset, Reloc}; +use crate::ir::types::{self, F32, F64, I128, I16, I32, I64, I8, I8X16}; +use crate::ir::{self, MemFlags, Type}; +use crate::isa::pulley_shared::abi::PulleyMachineDeps; +use crate::isa::FunctionAlignment; +use crate::{machinst::*, trace}; +use crate::{settings, CodegenError, CodegenResult}; +use alloc::string::{String, ToString}; +use regalloc2::RegClass; +use smallvec::SmallVec; + +pub mod regs; +pub use self::regs::*; +pub mod args; +pub use self::args::*; +pub mod emit; +pub use self::emit::*; + +//============================================================================= +// Instructions (top level): definition + +pub use crate::isa::pulley_shared::lower::isle::generated_code::MInst as Inst; +pub use crate::isa::pulley_shared::lower::isle::generated_code::RawInst; +pub use crate::isa::pulley_shared::lower::isle::generated_code::VExtKind; + +impl From for Inst { + fn from(raw: RawInst) -> Inst { + Inst::Raw { raw } + } +} + +use super::PulleyTargetKind; + +mod generated { + use super::*; + use crate::isa::pulley_shared::lower::isle::generated_code::RawInst; + + include!(concat!(env!("OUT_DIR"), "/pulley_inst_gen.rs")); +} + +/// Out-of-line data for return-calls, to keep the size of `Inst` down. +#[derive(Clone, Debug)] +pub struct ReturnCallInfo { + /// Where this call is going. + pub dest: T, + + /// The size of the argument area for this return-call, potentially smaller + /// than that of the caller, but never larger. + pub new_stack_arg_size: u32, + + /// The in-register arguments and their constraints. + pub uses: CallArgList, +} + +impl Inst { + /// Generic constructor for a load (zero-extending where appropriate). + pub fn gen_load(dst: Writable, mem: Amode, ty: Type, flags: MemFlags) -> Inst { + if ty.is_vector() { + assert_eq!(ty.bytes(), 16); + Inst::VLoad { + dst: dst.map(|r| VReg::new(r).unwrap()), + mem, + ty, + flags, + ext: VExtKind::None, + } + } else if ty.is_int() { + assert!(ty.bytes() <= 8); + Inst::XLoad { + dst: dst.map(|r| XReg::new(r).unwrap()), + mem, + ty, + flags, + ext: ExtKind::None, + } + } else { + Inst::FLoad { + dst: dst.map(|r| FReg::new(r).unwrap()), + mem, + ty, + flags, + } + } + } + + /// Generic constructor for a store. + pub fn gen_store(mem: Amode, from_reg: Reg, ty: Type, flags: MemFlags) -> Inst { + if ty.is_vector() { + assert_eq!(ty.bytes(), 16); + Inst::VStore { + mem, + src: VReg::new(from_reg).unwrap(), + ty, + flags, + } + } else if ty.is_int() { + assert!(ty.bytes() <= 8); + Inst::XStore { + mem, + src: XReg::new(from_reg).unwrap(), + ty, + flags, + } + } else { + Inst::FStore { + mem, + src: FReg::new(from_reg).unwrap(), + ty, + flags, + } + } + } +} + +fn pulley_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { + match inst { + Inst::Args { args } => { + for ArgPair { vreg, preg } in args { + collector.reg_fixed_def(vreg, *preg); + } + } + Inst::Rets { rets } => { + for RetPair { vreg, preg } in rets { + collector.reg_fixed_use(vreg, *preg); + } + } + + Inst::Nop => {} + + Inst::TrapIf { cond, code: _ } => { + cond.get_operands(collector); + } + + Inst::GetSpecial { dst, reg } => { + collector.reg_def(dst); + // Note that this is explicitly ignored as this is only used for + // special registers that don't participate in register allocation + // such as the stack pointer, frame pointer, etc. + assert!(reg.is_special()); + } + + Inst::LoadExtName { + dst, + name: _, + offset: _, + } => { + collector.reg_def(dst); + } + + Inst::Call { info } => { + let CallInfo { + uses, defs, dest, .. + } = &mut **info; + + // Pulley supports having the first few integer arguments in any + // register, so flag that with `reg_use` here. + let PulleyCall { args, .. } = dest; + for arg in args { + collector.reg_use(arg); + } + + // Remaining arguments (and return values) are all in fixed + // registers according to Pulley's ABI, however. + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(info.clobbers); + } + Inst::IndirectCallHost { info } => { + let CallInfo { uses, defs, .. } = &mut **info; + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(info.clobbers); + } + Inst::IndirectCall { info } => { + collector.reg_use(&mut info.dest); + let CallInfo { uses, defs, .. } = &mut **info; + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(info.clobbers); + } + Inst::ReturnCall { info } => { + for CallArgPair { vreg, preg } in &mut info.uses { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::ReturnIndirectCall { info } => { + collector.reg_use(&mut info.dest); + + for CallArgPair { vreg, preg } in &mut info.uses { + collector.reg_fixed_use(vreg, *preg); + } + } + + Inst::Jump { .. } => {} + + Inst::BrIf { + cond, + taken: _, + not_taken: _, + } => { + cond.get_operands(collector); + } + + Inst::LoadAddr { dst, mem } => { + collector.reg_def(dst); + mem.get_operands(collector); + } + + Inst::XLoad { + dst, + mem, + ty: _, + flags: _, + ext: _, + } => { + collector.reg_def(dst); + mem.get_operands(collector); + } + + Inst::XStore { + mem, + src, + ty: _, + flags: _, + } => { + mem.get_operands(collector); + collector.reg_use(src); + } + + Inst::FLoad { + dst, + mem, + ty: _, + flags: _, + } => { + collector.reg_def(dst); + mem.get_operands(collector); + } + + Inst::FStore { + mem, + src, + ty: _, + flags: _, + } => { + mem.get_operands(collector); + collector.reg_use(src); + } + + Inst::VLoad { + dst, + mem, + ty: _, + flags: _, + ext: _, + } => { + collector.reg_def(dst); + mem.get_operands(collector); + } + + Inst::VStore { + mem, + src, + ty: _, + flags: _, + } => { + mem.get_operands(collector); + collector.reg_use(src); + } + + Inst::BrTable { idx, .. } => { + collector.reg_use(idx); + } + + Inst::Raw { raw } => generated::get_operands(raw, collector), + } +} + +/// A newtype over a Pulley instruction that also carries a phantom type +/// parameter describing whether we are targeting 32- or 64-bit Pulley bytecode. +/// +/// Implements `Deref`, `DerefMut`, and `From`/`Into` for `Inst` to allow for +/// seamless conversion between `Inst` and `InstAndKind`. +#[derive(Clone, Debug)] +pub struct InstAndKind

+where + P: PulleyTargetKind, +{ + inst: Inst, + kind: PhantomData

, +} + +impl

From for InstAndKind

+where + P: PulleyTargetKind, +{ + fn from(inst: Inst) -> Self { + Self { + inst, + kind: PhantomData, + } + } +} + +impl

From for InstAndKind

+where + P: PulleyTargetKind, +{ + fn from(inst: RawInst) -> Self { + Self { + inst: inst.into(), + kind: PhantomData, + } + } +} + +impl

From> for Inst +where + P: PulleyTargetKind, +{ + fn from(inst: InstAndKind

) -> Self { + inst.inst + } +} + +impl

core::ops::Deref for InstAndKind

+where + P: PulleyTargetKind, +{ + type Target = Inst; + + fn deref(&self) -> &Self::Target { + &self.inst + } +} + +impl

core::ops::DerefMut for InstAndKind

+where + P: PulleyTargetKind, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inst + } +} + +impl

MachInst for InstAndKind

+where + P: PulleyTargetKind, +{ + type LabelUse = LabelUse; + type ABIMachineSpec = PulleyMachineDeps

; + + const TRAP_OPCODE: &'static [u8] = TRAP_OPCODE; + + fn gen_dummy_use(_reg: Reg) -> Self { + todo!() + } + + fn canonical_type_for_rc(rc: RegClass) -> Type { + match rc { + regalloc2::RegClass::Int => I64, + regalloc2::RegClass::Float => F64, + regalloc2::RegClass::Vector => I8X16, + } + } + + fn is_safepoint(&self) -> bool { + match self.inst { + Inst::Raw { + raw: RawInst::Trap { .. }, + } + | Inst::Call { .. } + | Inst::IndirectCall { .. } + | Inst::IndirectCallHost { .. } => true, + _ => false, + } + } + + fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + pulley_get_operands(self, collector); + } + + fn is_move(&self) -> Option<(Writable, Reg)> { + match self.inst { + Inst::Raw { + raw: RawInst::Xmov { dst, src }, + } => Some((Writable::from_reg(*dst.to_reg()), *src)), + _ => None, + } + } + + fn is_included_in_clobbers(&self) -> bool { + !self.is_args() + } + + fn is_trap(&self) -> bool { + match self.inst { + Inst::Raw { + raw: RawInst::Trap { .. }, + } => true, + _ => false, + } + } + + fn is_args(&self) -> bool { + match self.inst { + Inst::Args { .. } => true, + _ => false, + } + } + + fn is_term(&self) -> MachTerminator { + match self.inst { + Inst::Raw { + raw: RawInst::Ret { .. }, + } + | Inst::Rets { .. } => MachTerminator::Ret, + Inst::Jump { .. } => MachTerminator::Uncond, + Inst::BrIf { .. } => MachTerminator::Cond, + Inst::BrTable { .. } => MachTerminator::Indirect, + Inst::ReturnCall { .. } | Inst::ReturnIndirectCall { .. } => MachTerminator::Indirect, + _ => MachTerminator::None, + } + } + + fn is_mem_access(&self) -> bool { + todo!() + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self { + match ty { + ir::types::I8 | ir::types::I16 | ir::types::I32 | ir::types::I64 => RawInst::Xmov { + dst: WritableXReg::try_from(to_reg).unwrap(), + src: XReg::new(from_reg).unwrap(), + } + .into(), + ir::types::F32 | ir::types::F64 => RawInst::Fmov { + dst: WritableFReg::try_from(to_reg).unwrap(), + src: FReg::new(from_reg).unwrap(), + } + .into(), + _ if ty.is_vector() => RawInst::Vmov { + dst: WritableVReg::try_from(to_reg).unwrap(), + src: VReg::new(from_reg).unwrap(), + } + .into(), + _ => panic!("don't know how to generate a move for type {ty}"), + } + } + + fn gen_nop(_preferred_size: usize) -> Self { + todo!() + } + + fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> { + match ty { + I8 => Ok((&[RegClass::Int], &[I8])), + I16 => Ok((&[RegClass::Int], &[I16])), + I32 => Ok((&[RegClass::Int], &[I32])), + I64 => Ok((&[RegClass::Int], &[I64])), + F32 => Ok((&[RegClass::Float], &[F32])), + F64 => Ok((&[RegClass::Float], &[F64])), + I128 => Ok((&[RegClass::Int, RegClass::Int], &[I64, I64])), + _ if ty.is_vector() => { + debug_assert!(ty.bits() <= 512); + + // Here we only need to return a SIMD type with the same size as `ty`. + // We use these types for spills and reloads, so prefer types with lanes <= 31 + // since that fits in the immediate field of `vsetivli`. + const SIMD_TYPES: [[Type; 1]; 6] = [ + [types::I8X2], + [types::I8X4], + [types::I8X8], + [types::I8X16], + [types::I16X16], + [types::I32X16], + ]; + let idx = (ty.bytes().ilog2() - 1) as usize; + let ty = &SIMD_TYPES[idx][..]; + + Ok((&[RegClass::Vector], ty)) + } + _ => Err(CodegenError::Unsupported(format!( + "Unexpected SSA-value type: {ty}" + ))), + } + } + + fn gen_jump(label: MachLabel) -> Self { + Inst::Jump { label }.into() + } + + fn worst_case_size() -> CodeOffset { + // `VShuffle { dst, src1, src2, imm }` is 22 bytes: + // 3-byte opcode + // dst, src1, src2 + // 16-byte immediate + 22 + } + + fn ref_type_regclass(_settings: &settings::Flags) -> RegClass { + RegClass::Int + } + + fn function_alignment() -> FunctionAlignment { + FunctionAlignment { + minimum: 1, + preferred: 1, + } + } +} + +const TRAP_OPCODE: &'static [u8] = &[ + pulley_interpreter::opcode::Opcode::ExtendedOp as u8, + ((pulley_interpreter::opcode::ExtendedOpcode::Trap as u16) >> 0) as u8, + ((pulley_interpreter::opcode::ExtendedOpcode::Trap as u16) >> 8) as u8, +]; + +#[test] +fn test_trap_encoding() { + let mut dst = std::vec::Vec::new(); + pulley_interpreter::encode::trap(&mut dst); + assert_eq!(dst, TRAP_OPCODE); +} + +//============================================================================= +// Pretty-printing of instructions. + +pub fn reg_name(reg: Reg) -> String { + match reg.to_real_reg() { + Some(real) => { + let n = real.hw_enc(); + match (real.class(), n) { + (RegClass::Int, 63) => format!("sp"), + (RegClass::Int, 62) => format!("lr"), + (RegClass::Int, 61) => format!("fp"), + (RegClass::Int, 60) => format!("tmp0"), + (RegClass::Int, 59) => format!("tmp1"), + + (RegClass::Int, _) => format!("x{n}"), + (RegClass::Float, _) => format!("f{n}"), + (RegClass::Vector, _) => format!("v{n}"), + } + } + None => { + format!("{reg:?}") + } + } +} + +impl Inst { + fn print_with_state

(&self, _state: &mut EmitState

) -> String + where + P: PulleyTargetKind, + { + use core::fmt::Write; + + let format_reg = |reg: Reg| -> String { reg_name(reg) }; + + let format_ext = |ext: ExtKind| -> &'static str { + match ext { + ExtKind::None => "", + ExtKind::Sign32 => "_s32", + ExtKind::Sign64 => "_s64", + ExtKind::Zero32 => "_u32", + ExtKind::Zero64 => "_u64", + } + }; + + match self { + Inst::Args { args } => { + let mut s = "args".to_string(); + for arg in args { + let preg = format_reg(arg.preg); + let def = format_reg(arg.vreg.to_reg()); + write!(&mut s, " {def}={preg}").unwrap(); + } + s + } + Inst::Rets { rets } => { + let mut s = "rets".to_string(); + for ret in rets { + let preg = format_reg(ret.preg); + let vreg = format_reg(ret.vreg); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + + Inst::TrapIf { cond, code } => { + format!("trap_{cond} // code = {code:?}") + } + + Inst::Nop => format!("nop"), + + Inst::GetSpecial { dst, reg } => { + let dst = format_reg(*dst.to_reg()); + let reg = format_reg(**reg); + format!("xmov {dst}, {reg}") + } + + Inst::LoadExtName { dst, name, offset } => { + let dst = format_reg(*dst.to_reg()); + format!("{dst} = load_ext_name {name:?}, {offset}") + } + + Inst::Call { info } => { + format!("call {info:?}") + } + + Inst::IndirectCall { info } => { + let callee = format_reg(*info.dest); + format!("indirect_call {callee}, {info:?}") + } + + Inst::ReturnCall { info } => { + format!("return_call {info:?}") + } + + Inst::ReturnIndirectCall { info } => { + let callee = format_reg(*info.dest); + format!("return_indirect_call {callee}, {info:?}") + } + + Inst::IndirectCallHost { info } => { + format!("indirect_call_host {info:?}") + } + + Inst::Jump { label } => format!("jump {}", label.to_string()), + + Inst::BrIf { + cond, + taken, + not_taken, + } => { + let taken = taken.to_string(); + let not_taken = not_taken.to_string(); + format!("br_{cond}, {taken}; jump {not_taken}") + } + + Inst::LoadAddr { dst, mem } => { + let dst = format_reg(*dst.to_reg()); + let mem = mem.to_string(); + format!("{dst} = load_addr {mem}") + } + + Inst::XLoad { + dst, + mem, + ty, + flags, + ext, + } => { + let dst = format_reg(*dst.to_reg()); + let ty = ty.bits(); + let ext = format_ext(*ext); + let mem = mem.to_string(); + format!("{dst} = xload{ty}{ext} {mem} // flags ={flags}") + } + + Inst::XStore { + mem, + src, + ty, + flags, + } => { + let ty = ty.bits(); + let mem = mem.to_string(); + let src = format_reg(**src); + format!("xstore{ty} {mem}, {src} // flags = {flags}") + } + + Inst::FLoad { + dst, + mem, + ty, + flags, + } => { + let dst = format_reg(*dst.to_reg()); + let ty = ty.bits(); + let mem = mem.to_string(); + format!("{dst} = fload{ty} {mem} // flags ={flags}") + } + + Inst::FStore { + mem, + src, + ty, + flags, + } => { + let ty = ty.bits(); + let mem = mem.to_string(); + let src = format_reg(**src); + format!("fstore{ty} {mem}, {src} // flags = {flags}") + } + + Inst::VLoad { + dst, + mem, + ty, + flags, + ext, + } => { + let dst = format_reg(*dst.to_reg()); + let ty = ty.bits(); + let mem = mem.to_string(); + format!("{dst} = vload{ty}_{ext:?} {mem} // flags ={flags}") + } + + Inst::VStore { + mem, + src, + ty, + flags, + } => { + let ty = ty.bits(); + let mem = mem.to_string(); + let src = format_reg(**src); + format!("vstore{ty} {mem}, {src} // flags = {flags}") + } + + Inst::BrTable { + idx, + default, + targets, + } => { + let idx = format_reg(**idx); + format!("br_table {idx} {default:?} {targets:?}") + } + Inst::Raw { raw } => generated::print(raw), + } + } +} + +/// Different forms of label references for different instruction formats. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LabelUse { + /// A PC-relative `jump`/`call`/etc... instruction with an `i32` relative + /// target. The payload value is an addend that describes the positive + /// offset from the start of the instruction to the offset being relocated. + Jump(u32), +} + +impl MachInstLabelUse for LabelUse { + /// Alignment for veneer code. Pulley instructions don't require any + /// particular alignment. + const ALIGN: CodeOffset = 1; + + /// Maximum PC-relative range (positive), inclusive. + fn max_pos_range(self) -> CodeOffset { + match self { + Self::Jump(_) => 0x7fff_ffff, + } + } + + /// Maximum PC-relative range (negative). + fn max_neg_range(self) -> CodeOffset { + match self { + Self::Jump(_) => 0x8000_0000, + } + } + + /// Size of window into code needed to do the patch. + fn patch_size(self) -> CodeOffset { + match self { + Self::Jump(_) => 4, + } + } + + /// Perform the patch. + fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) { + let use_relative = (label_offset as i64) - (use_offset as i64); + debug_assert!(use_relative <= self.max_pos_range() as i64); + debug_assert!(use_relative >= -(self.max_neg_range() as i64)); + let pc_rel = i32::try_from(use_relative).unwrap() as u32; + match self { + Self::Jump(addend) => { + let value = pc_rel.wrapping_add(addend); + trace!( + "patching label use @ {use_offset:#x} to label {label_offset:#x} via \ + PC-relative offset {pc_rel:#x}" + ); + buffer.copy_from_slice(&value.to_le_bytes()[..]); + } + } + } + + /// Is a veneer supported for this label reference type? + fn supports_veneer(self) -> bool { + match self { + Self::Jump(_) => false, + } + } + + /// How large is the veneer, if supported? + fn veneer_size(self) -> CodeOffset { + match self { + Self::Jump(_) => 0, + } + } + + fn worst_case_veneer_size() -> CodeOffset { + 0 + } + + /// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return + /// an offset and label-use for the veneer's use of the original label. + fn generate_veneer( + self, + _buffer: &mut [u8], + _veneer_offset: CodeOffset, + ) -> (CodeOffset, LabelUse) { + match self { + Self::Jump(_) => panic!("veneer not supported for {self:?}"), + } + } + + fn from_reloc(reloc: Reloc, addend: Addend) -> Option { + match reloc { + Reloc::X86CallPCRel4 if addend < 0 => { + // We are always relocating some offset that is within an + // instruction, but pulley adds the offset relative to the PC + // pointing to the *start* of the instruction. Therefore, adjust + // back to the beginning of the instruction. + Some(LabelUse::Jump(i32::try_from(-addend).unwrap() as u32)) + } + _ => None, + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/regs.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/regs.rs new file mode 100644 index 00000000000000..434abecaebcf99 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/inst/regs.rs @@ -0,0 +1,164 @@ +//! Pulley registers. + +use crate::machinst::{Reg, Writable}; +use regalloc2::{PReg, RegClass, VReg}; + +#[inline] +pub fn x_reg(enc: usize) -> Reg { + let p = PReg::new(enc, RegClass::Int); + let v = VReg::new(p.index(), p.class()); + Reg::from(v) +} + +#[inline] +pub const fn px_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Int) +} + +#[inline] +pub fn f_reg(enc: usize) -> Reg { + let p = PReg::new(enc, RegClass::Float); + let v = VReg::new(p.index(), p.class()); + Reg::from(v) +} + +#[inline] +pub const fn pf_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Float) +} + +#[inline] +pub fn v_reg(enc: usize) -> Reg { + let p = PReg::new(enc, RegClass::Vector); + let v = VReg::new(p.index(), p.class()); + Reg::from(v) +} + +#[inline] +pub const fn pv_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Vector) +} + +macro_rules! define_registers { + ( + $( + $reg:expr => $readable:ident, $writable:ident; + )* + ) => { + $( + #[inline] + #[allow(dead_code)] + pub fn $readable() -> Reg { + $reg + } + + #[inline] + #[allow(dead_code)] + pub fn $writable() -> Writable { + Writable::from_reg($readable()) + } + )* + }; +} + +define_registers! { + x_reg(0) => x0, writable_x0; + x_reg(1) => x1, writable_x1; + x_reg(2) => x2, writable_x2; + x_reg(3) => x3, writable_x3; + x_reg(4) => x4, writable_x4; + x_reg(5) => x5, writable_x5; + x_reg(6) => x6, writable_x6; + x_reg(7) => x7, writable_x7; + x_reg(8) => x8, writable_x8; + x_reg(9) => x9, writable_x9; + x_reg(10) => x10, writable_x10; + x_reg(11) => x11, writable_x11; + x_reg(12) => x12, writable_x12; + x_reg(13) => x13, writable_x13; + x_reg(14) => x14, writable_x14; + x_reg(15) => x15, writable_x15; + x_reg(16) => x16, writable_x16; + x_reg(17) => x17, writable_x17; + x_reg(18) => x18, writable_x18; + x_reg(19) => x19, writable_x19; + x_reg(20) => x20, writable_x20; + x_reg(21) => x21, writable_x21; + x_reg(22) => x22, writable_x22; + x_reg(23) => x23, writable_x23; + x_reg(24) => x24, writable_x24; + x_reg(25) => x25, writable_x25; + x_reg(26) => x26, writable_x26; + x_reg(27) => x27, writable_x27; + x_reg(28) => x28, writable_x28; + x_reg(29) => x29, writable_x29; + + x_reg(30) => stack_reg, writable_stack_reg; + x_reg(31) => spilltmp_reg, writable_spilltmp_reg; + + f_reg(0) => f0, writable_f0; + f_reg(1) => f1, writable_f1; + f_reg(2) => f2, writable_f2; + f_reg(3) => f3, writable_f3; + f_reg(4) => f4, writable_f4; + f_reg(5) => f5, writable_f5; + f_reg(6) => f6, writable_f6; + f_reg(7) => f7, writable_f7; + f_reg(8) => f8, writable_f8; + f_reg(9) => f9, writable_f9; + f_reg(10) => f10, writable_f10; + f_reg(11) => f11, writable_f11; + f_reg(12) => f12, writable_f12; + f_reg(13) => f13, writable_f13; + f_reg(14) => f14, writable_f14; + f_reg(15) => f15, writable_f15; + f_reg(16) => f16, writable_f16; + f_reg(17) => f17, writable_f17; + f_reg(18) => f18, writable_f18; + f_reg(19) => f19, writable_f19; + f_reg(20) => f20, writable_f20; + f_reg(21) => f21, writable_f21; + f_reg(22) => f22, writable_f22; + f_reg(23) => f23, writable_f23; + f_reg(24) => f24, writable_f24; + f_reg(25) => f25, writable_f25; + f_reg(26) => f26, writable_f26; + f_reg(27) => f27, writable_f27; + f_reg(28) => f28, writable_f28; + f_reg(29) => f29, writable_f29; + f_reg(30) => f30, writable_f30; + f_reg(31) => f31, writable_f31; + + v_reg(0) => v0, writable_v0; + v_reg(1) => v1, writable_v1; + v_reg(2) => v2, writable_v2; + v_reg(3) => v3, writable_v3; + v_reg(4) => v4, writable_v4; + v_reg(5) => v5, writable_v5; + v_reg(6) => v6, writable_v6; + v_reg(7) => v7, writable_v7; + v_reg(8) => v8, writable_v8; + v_reg(9) => v9, writable_v9; + v_reg(10) => v10, writable_v10; + v_reg(11) => v11, writable_v11; + v_reg(12) => v12, writable_v12; + v_reg(13) => v13, writable_v13; + v_reg(14) => v14, writable_v14; + v_reg(15) => v15, writable_v15; + v_reg(16) => v16, writable_v16; + v_reg(17) => v17, writable_v17; + v_reg(18) => v18, writable_v18; + v_reg(19) => v19, writable_v19; + v_reg(20) => v20, writable_v20; + v_reg(21) => v21, writable_v21; + v_reg(22) => v22, writable_v22; + v_reg(23) => v23, writable_v23; + v_reg(24) => v24, writable_v24; + v_reg(25) => v25, writable_v25; + v_reg(26) => v26, writable_v26; + v_reg(27) => v27, writable_v27; + v_reg(28) => v28, writable_v28; + v_reg(29) => v29, writable_v29; + v_reg(30) => v30, writable_v30; + v_reg(31) => v31, writable_v31; +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.isle b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.isle new file mode 100644 index 00000000000000..b62d44810eb10b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.isle @@ -0,0 +1,1414 @@ +;; Pulley instruction selection and CLIF-to-MachInst lowering. + +;; The main lowering constructor term: takes a clif `Inst` and returns the +;; register(s) within which the lowered instruction's result values live. +(decl partial lower (Inst) InstOutput) + +;;;; Rules for Control Flow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper to place a conditional `Value` provided into a register. Pulley +;; conditional values occupy the full low 32-bits of a register and so this +;; needs to handle situations such as when the `Value` is 64-bits an explicit +;; comparison must be made. Additionally if `Value` is smaller than 32-bits +;; then it must be sign-extended up to at least 32 bits. +(decl lower_cond (Value) Cond) +(rule 0 (lower_cond val @ (value_type (fits_in_32 _))) (Cond.If32 (zext32 val))) +(rule 1 (lower_cond val @ (value_type $I64)) + (Cond.IfXneq64I32 val 0)) + +;; Peel away explicit `uextend` values to take a look at the inner value. +(rule 2 (lower_cond (uextend val)) (lower_cond val)) +;; Conditional branches on `icmp`s. +(rule 2 (lower_cond (icmp cc a b @ (value_type $I32))) (lower_cond_icmp32 cc a b)) +(rule 2 (lower_cond (icmp cc a b @ (value_type $I64))) (lower_cond_icmp64 cc a b)) + +(decl lower_cond_icmp32 (IntCC Value Value) Cond) +(rule (lower_cond_icmp32 (IntCC.Equal) a b) (Cond.IfXeq32 a b)) +(rule (lower_cond_icmp32 (IntCC.NotEqual) a b) (Cond.IfXneq32 a b)) +(rule (lower_cond_icmp32 (IntCC.SignedLessThan) a b) (Cond.IfXslt32 a b)) +(rule (lower_cond_icmp32 (IntCC.SignedLessThanOrEqual) a b) (Cond.IfXslteq32 a b)) +(rule (lower_cond_icmp32 (IntCC.UnsignedLessThan) a b) (Cond.IfXult32 a b)) +(rule (lower_cond_icmp32 (IntCC.UnsignedLessThanOrEqual) a b) (Cond.IfXulteq32 a b)) +;; Swap args for conditions pulley doesn't have +(rule (lower_cond_icmp32 (IntCC.SignedGreaterThan) a b) (Cond.IfXslt32 b a)) +(rule (lower_cond_icmp32 (IntCC.SignedGreaterThanOrEqual) a b) (Cond.IfXslteq32 b a)) +(rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult32 b a)) +(rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq32 b a)) + +(rule 1 (lower_cond_icmp32 (IntCC.Equal) a (i32_from_iconst b)) + (Cond.IfXeq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.NotEqual) a (i32_from_iconst b)) + (Cond.IfXneq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThan) a (i32_from_iconst b)) + (Cond.IfXslt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXslteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThan) a (i32_from_iconst b)) + (Cond.IfXsgt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXsgteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThan) a (u32_from_iconst b)) + (Cond.IfXult32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXulteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b)) + (Cond.IfXugt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXugteq32I32 a b)) + +(decl lower_cond_icmp64 (IntCC Value Value) Cond) +(rule (lower_cond_icmp64 (IntCC.Equal) a b) (Cond.IfXeq64 a b)) +(rule (lower_cond_icmp64 (IntCC.NotEqual) a b) (Cond.IfXneq64 a b)) +(rule (lower_cond_icmp64 (IntCC.SignedLessThan) a b) (Cond.IfXslt64 a b)) +(rule (lower_cond_icmp64 (IntCC.SignedLessThanOrEqual) a b) (Cond.IfXslteq64 a b)) +(rule (lower_cond_icmp64 (IntCC.UnsignedLessThan) a b) (Cond.IfXult64 a b)) +(rule (lower_cond_icmp64 (IntCC.UnsignedLessThanOrEqual) a b) (Cond.IfXulteq64 a b)) +;; Swap args for conditions pulley doesn't have +(rule (lower_cond_icmp64 (IntCC.SignedGreaterThan) a b) (Cond.IfXslt64 b a)) +(rule (lower_cond_icmp64 (IntCC.SignedGreaterThanOrEqual) a b) (Cond.IfXslteq64 b a)) +(rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult64 b a)) +(rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq64 b a)) + +(rule 1 (lower_cond_icmp64 (IntCC.Equal) a (i32_from_iconst b)) + (Cond.IfXeq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.NotEqual) a (i32_from_iconst b)) + (Cond.IfXneq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThan) a (i32_from_iconst b)) + (Cond.IfXslt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXslteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThan) a (i32_from_iconst b)) + (Cond.IfXsgt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXsgteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThan) a (u32_from_iconst b)) + (Cond.IfXult64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXulteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b)) + (Cond.IfXugt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXugteq64I32 a b)) + +;; The main control-flow-lowering term: takes a control-flow instruction and +;; target(s) and emits the necessary instructions. +(decl partial lower_branch (Inst MachLabelSlice) Unit) + +;; Unconditional jumps. +(rule (lower_branch (jump _) (single_target label)) + (emit_side_effect (pulley_jump label))) + +;; Generic case for conditional branches. +(rule -1 (lower_branch (brif c _ _) (two_targets then else)) + (emit_side_effect (pulley_br_if (lower_cond c) then else))) + +;; Branch tables. +(rule (lower_branch (br_table index _) (jump_table_targets default targets)) + (gen_br_table index default targets)) + +;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trap code)) + (side_effect (pulley_trap code))) + +;;;; Rules for `trapz` and `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trapz cond code)) + (side_effect (pulley_trap_if (cond_invert (lower_cond cond)) code))) + +(rule (lower (trapnz cond code)) + (side_effect (pulley_trap_if (lower_cond cond) code))) + +;;;; Rules for `get_stack_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_stack_pointer)) + (pulley_get_special (sp_reg))) + +;;;; Rules for `get_frame_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_frame_pointer)) (pulley_xmov_fp)) + +;;;; Rules for `get_return_address` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_return_address)) (pulley_xmov_lr)) + +;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; N.B.: the `ret` itself is generated by the ABI. +(rule (lower (return args)) + (lower_return args)) + +;;;; Rules for calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (call (func_ref_data sig_ref extname dist) inputs)) + (gen_call sig_ref extname dist inputs)) + +(rule (lower (call_indirect sig_ref val inputs)) + (gen_call_indirect sig_ref val inputs)) + +;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (return_call (func_ref_data sig_ref extname dist) args)) + (gen_return_call sig_ref extname dist args)) + +(rule (lower (return_call_indirect sig_ref callee args)) + (gen_return_call_indirect sig_ref callee args)) + +;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (iconst (u64_from_imm64 n)))) + (imm ty n)) + +;;;; Rules for `f32const`;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f32const (u32_from_ieee32 x))) (imm $F32 x)) + +;;;; Rules for `f64const`;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f64const (u64_from_ieee64 x))) (imm $F64 x)) + +;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_64 ty)) (iadd a b))) (pulley_xadd32 a b)) +(rule 1 (lower (has_type $I64 (iadd a b))) (pulley_xadd64 a b)) + +;; Fold constants into the instruction if possible +(rule 2 (lower (has_type (ty_int (fits_in_32 _)) (iadd a (u32_from_iconst b)))) + (pulley_xadd32_u32 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (iadd a (u8_from_iconst b)))) + (pulley_xadd32_u8 a b)) +(rule 4 (lower (has_type $I64 (iadd a (u32_from_iconst b)))) + (pulley_xadd64_u32 a b)) +(rule 5 (lower (has_type $I64 (iadd a (u8_from_iconst b)))) + (pulley_xadd64_u8 a b)) + +;; If the rhs is a constant and the negated version can fit within a smaller +;; constant then switch this to a subtraction with the negated constant. +(rule 6 (lower (has_type (ty_int (fits_in_32 _)) (iadd a b))) + (if-let c (u32_from_negated_iconst b)) + (pulley_xsub32_u32 a c)) +(rule 7 (lower (has_type $I64 (iadd a b))) + (if-let c (u32_from_negated_iconst b)) + (pulley_xsub64_u32 a c)) +(rule 8 (lower (has_type (ty_int (fits_in_32 _)) (iadd a b))) + (if-let c (u8_from_negated_iconst b)) + (pulley_xsub32_u8 a c)) +(rule 9 (lower (has_type $I64 (iadd a b))) + (if-let c (u8_from_negated_iconst b)) + (pulley_xsub64_u8 a c)) + +;; Helper extract a constant from a `Value`, negate it, and fit it within a +;; `u8`. +(decl pure partial u8_from_negated_iconst (Value) u8) +(rule (u8_from_negated_iconst (i32_from_iconst i)) + (if-let neg_i64 (i64_neg (i32_as_i64 i))) + (if-let neg_u64 (u64_try_from_i64 neg_i64)) + (if-let neg_u8 (u8_try_from_u64 neg_u64)) + neg_u8) + +;; Helper extract a constant from a `Value`, negate it, and fit it within a +;; `u32`. +(decl pure partial u32_from_negated_iconst (Value) u32) +(rule (u32_from_negated_iconst (i32_from_iconst i)) + (if-let neg_i64 (i64_neg (i32_as_i64 i))) + (if-let neg_u64 (u64_try_from_i64 neg_i64)) + (if-let neg_u32 (u32_try_from_u64 neg_u64)) + neg_u32) + +(rule 1 (lower (has_type $I8X16 (iadd a b))) (pulley_vaddi8x16 a b)) +(rule 1 (lower (has_type $I16X8 (iadd a b))) (pulley_vaddi16x8 a b)) +(rule 1 (lower (has_type $I32X4 (iadd a b))) (pulley_vaddi32x4 a b)) +(rule 1 (lower (has_type $I64X2 (iadd a b))) (pulley_vaddi64x2 a b)) + +(rule 1 (lower (has_type $I8X16 (sadd_sat a b))) (pulley_vaddi8x16_sat a b)) +(rule 1 (lower (has_type $I8X16 (uadd_sat a b))) (pulley_vaddu8x16_sat a b)) +(rule 1 (lower (has_type $I16X8 (sadd_sat a b))) (pulley_vaddi16x8_sat a b)) +(rule 1 (lower (has_type $I16X8 (uadd_sat a b))) (pulley_vaddu16x8_sat a b)) + +;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I16X8 (iadd_pairwise a b))) (pulley_vaddpairwisei16x8_s a b)) +(rule (lower (has_type $I32X4 (iadd_pairwise a b))) (pulley_vaddpairwisei32x4_s a b)) + +;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (isub a b))) (pulley_xsub32 a b)) +(rule 1 (lower (has_type $I64 (isub a b))) (pulley_xsub64 a b)) + +;; Fold a rhs constant into the instruction if possible. +(rule 2 (lower (has_type (ty_int (fits_in_32 _)) (isub a (u32_from_iconst b)))) + (pulley_xsub32_u32 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (isub a (u8_from_iconst b)))) + (pulley_xsub32_u8 a b)) +(rule 4 (lower (has_type $I64 (isub a (u32_from_iconst b)))) + (pulley_xsub64_u32 a b)) +(rule 5 (lower (has_type $I64 (isub a (u8_from_iconst b)))) + (pulley_xsub64_u8 a b)) + +;; If the rhs is a constant and the negated version can fit within a smaller +;; constant then switch this to an addition with the negated constant. +(rule 6 (lower (has_type (ty_int (fits_in_32 _)) (isub a b))) + (if-let c (u32_from_negated_iconst b)) + (pulley_xadd32_u32 a c)) +(rule 7 (lower (has_type $I64 (isub a b))) + (if-let c (u32_from_negated_iconst b)) + (pulley_xadd64_u32 a c)) +(rule 8 (lower (has_type (ty_int (fits_in_32 _)) (isub a b))) + (if-let c (u8_from_negated_iconst b)) + (pulley_xadd32_u8 a c)) +(rule 9 (lower (has_type $I64 (isub a b))) + (if-let c (u8_from_negated_iconst b)) + (pulley_xadd64_u8 a c)) + +(rule 1 (lower (has_type $I8X16 (isub a b))) (pulley_vsubi8x16 a b)) +(rule 1 (lower (has_type $I16X8 (isub a b))) (pulley_vsubi16x8 a b)) +(rule 1 (lower (has_type $I32X4 (isub a b))) (pulley_vsubi32x4 a b)) +(rule 1 (lower (has_type $I64X2 (isub a b))) (pulley_vsubi64x2 a b)) + +(rule 1 (lower (has_type $I8X16 (ssub_sat a b))) (pulley_vsubi8x16_sat a b)) +(rule 1 (lower (has_type $I8X16 (usub_sat a b))) (pulley_vsubu8x16_sat a b)) +(rule 1 (lower (has_type $I16X8 (ssub_sat a b))) (pulley_vsubi16x8_sat a b)) +(rule 1 (lower (has_type $I16X8 (usub_sat a b))) (pulley_vsubu16x8_sat a b)) + +;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (imul a b))) (pulley_xmul32 a b)) +(rule (lower (has_type $I16 (imul a b))) (pulley_xmul32 a b)) +(rule (lower (has_type $I32 (imul a b))) (pulley_xmul32 a b)) +(rule (lower (has_type $I64 (imul a b))) (pulley_xmul64 a b)) + +(rule 1 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i32_from_iconst b)))) + (pulley_xmul32_s32 a b)) +(rule 2 (lower (has_type $I64 (imul a (i32_from_iconst b)))) + (pulley_xmul64_s32 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i8_from_iconst b)))) + (pulley_xmul32_s8 a b)) +(rule 4 (lower (has_type $I64 (imul a (i8_from_iconst b)))) + (pulley_xmul64_s8 a b)) + +(rule (lower (has_type $I8X16 (imul a b))) (pulley_vmuli8x16 a b)) +(rule (lower (has_type $I16X8 (imul a b))) (pulley_vmuli16x8 a b)) +(rule (lower (has_type $I32X4 (imul a b))) (pulley_vmuli32x4 a b)) +(rule (lower (has_type $I64X2 (imul a b))) (pulley_vmuli64x2 a b)) + +;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (umulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 8)) + (pulley_xshr32_u_u6 (pulley_xmul32 (zext32 a) (zext32 b)) shift)) + +(rule (lower (has_type $I16 (umulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 16)) + (pulley_xshr32_u_u6 (pulley_xmul32 (zext32 a) (zext32 b)) shift)) + +(rule (lower (has_type $I32 (umulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 32)) + (pulley_xshr64_u_u6 (pulley_xmul64 (zext64 a) (zext64 b)) shift)) + +(rule (lower (has_type $I64 (umulhi a b))) + (pulley_xmulhi64_u a b)) + +;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (smulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 8)) + (pulley_xshr32_s_u6 (pulley_xmul32 (sext32 a) (sext32 b)) shift)) + +(rule (lower (has_type $I16 (smulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 16)) + (pulley_xshr32_s_u6 (pulley_xmul32 (sext32 a) (sext32 b)) shift)) + +(rule (lower (has_type $I32 (smulhi a b))) + (if-let (u6_from_u8 shift) (u64_as_u8 32)) + (pulley_xshr64_s_u6 (pulley_xmul64 (sext64 a) (sext64 b)) shift)) + +(rule (lower (has_type $I64 (smulhi a b))) + (pulley_xmulhi64_s a b)) + +;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I16X8 (sqmul_round_sat a b))) (pulley_vqmulrsi16x8 a b)) + +;;;; Rules for `sdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (sdiv a b))) + (pulley_xdiv32_s (sext32 a) (sext32 b))) +(rule 1 (lower (has_type $I64 (sdiv a b))) (pulley_xdiv64_s a b)) + +;;;; Rules for `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (srem a b))) + (pulley_xrem32_s (sext32 a) (sext32 b))) +(rule 1 (lower (has_type $I64 (srem a b))) (pulley_xrem64_s a b)) + +;;;; Rules for `udiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (udiv a b))) + (pulley_xdiv32_u (zext32 a) (zext32 b))) +(rule 1 (lower (has_type $I64 (udiv a b))) (pulley_xdiv64_u a b)) + +;;;; Rules for `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (urem a b))) + (pulley_xrem32_u (zext32 a) (zext32 b))) +(rule 1 (lower (has_type $I64 (urem a b))) (pulley_xrem64_u a b)) + +;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (avg_round a b))) (pulley_vavground8x16 a b)) +(rule (lower (has_type $I16X8 (avg_round a b))) (pulley_vavground16x8 a b)) + +;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (ishl a b))) + (pulley_xshl32 a (pulley_xband32_s8 b 7))) + +(rule (lower (has_type $I16 (ishl a b))) + (pulley_xshl32 a (pulley_xband32_s8 b 15))) + +(rule (lower (has_type $I32 (ishl a b))) + (pulley_xshl32 a b)) + +(rule (lower (has_type $I64 (ishl a b))) + (pulley_xshl64 a b)) + +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (ishl a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshl32_u6 a n)) +(rule 1 (lower (has_type $I64 (ishl a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshl64_u6 a n)) + +;; vector shifts + +(rule (lower (has_type $I8X16 (ishl a b))) (pulley_vshli8x16 a b)) +(rule (lower (has_type $I16X8 (ishl a b))) (pulley_vshli16x8 a b)) +(rule (lower (has_type $I32X4 (ishl a b))) (pulley_vshli32x4 a b)) +(rule (lower (has_type $I64X2 (ishl a b))) (pulley_vshli64x2 a b)) + +;; Helper to extract a constant from `Value`, mask it to 6 bits, and then make a +;; `U6`. +(decl pure partial u6_shift_from_iconst (Value) U6) +(rule (u6_shift_from_iconst (u64_from_iconst val)) + (if-let (u6_from_u8 x) (u64_as_u8 (u64_and val 0x3f))) + x) + +(decl u6_from_u8 (U6) u8) +(extern extractor u6_from_u8 u6_from_u8) + +;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (ushr a b))) + (pulley_xshr32_u (zext32 a) (pulley_xband32_s8 b 7))) + +(rule (lower (has_type $I16 (ushr a b))) + (pulley_xshr32_u (zext32 a) (pulley_xband32_s8 b 15))) + +(rule (lower (has_type $I32 (ushr a b))) + (pulley_xshr32_u a b)) + +(rule (lower (has_type $I64 (ushr a b))) + (pulley_xshr64_u a b)) + +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (ushr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr32_u_u6 a n)) +(rule 1 (lower (has_type $I64 (ushr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr64_u_u6 a n)) + +;; vector shifts + +(rule (lower (has_type $I8X16 (ushr a b))) (pulley_vshri8x16_u a b)) +(rule (lower (has_type $I16X8 (ushr a b))) (pulley_vshri16x8_u a b)) +(rule (lower (has_type $I32X4 (ushr a b))) (pulley_vshri32x4_u a b)) +(rule (lower (has_type $I64X2 (ushr a b))) (pulley_vshri64x2_u a b)) + +;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (sshr a b))) + (pulley_xshr32_u (sext32 a) (pulley_xband32_s8 b 7))) + +(rule (lower (has_type $I16 (sshr a b))) + (pulley_xshr32_u (sext32 a) (pulley_xband32_s8 b 15))) + +(rule (lower (has_type $I32 (sshr a b))) + (pulley_xshr32_s a b)) + +(rule (lower (has_type $I64 (sshr a b))) + (pulley_xshr64_s a b)) + +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (sshr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr32_s_u6 a n)) +(rule 1 (lower (has_type $I64 (sshr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr64_s_u6 a n)) + +;; vector shifts + +(rule (lower (has_type $I8X16 (sshr a b))) (pulley_vshri8x16_s a b)) +(rule (lower (has_type $I16X8 (sshr a b))) (pulley_vshri16x8_s a b)) +(rule (lower (has_type $I32X4 (sshr a b))) (pulley_vshri32x4_s a b)) +(rule (lower (has_type $I64X2 (sshr a b))) (pulley_vshri64x2_s a b)) + +;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (band a b))) (pulley_xband32 a b)) +(rule 1 (lower (has_type $I64 (band a b))) (pulley_xband64 a b)) + +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (band a (i32_from_iconst b)))) + (pulley_xband32_s32 a b)) +(rule 4 (lower (has_type $I64 (band a (i32_from_iconst b)))) + (pulley_xband64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (band a (i8_from_iconst b)))) + (pulley_xband32_s8 a b)) +(rule 6 (lower (has_type $I64 (band a (i8_from_iconst b)))) + (pulley_xband64_s8 a b)) + +(rule 2 (lower (has_type (ty_vec128 _) (band a b))) + (pulley_vband128 a b)) + +;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (bor a b))) (pulley_xbor32 a b)) +(rule 1 (lower (has_type $I64 (bor a b))) (pulley_xbor64 a b)) + +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i32_from_iconst b)))) + (pulley_xbor32_s32 a b)) +(rule 4 (lower (has_type $I64 (bor a (i32_from_iconst b)))) + (pulley_xbor64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i8_from_iconst b)))) + (pulley_xbor32_s8 a b)) +(rule 6 (lower (has_type $I64 (bor a (i8_from_iconst b)))) + (pulley_xbor64_s8 a b)) + +(rule 2 (lower (has_type (ty_vec128 _) (bor a b))) + (pulley_vbor128 a b)) + +;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (bxor a b))) (pulley_xbxor32 a b)) +(rule 1 (lower (has_type $I64 (bxor a b))) (pulley_xbxor64 a b)) + +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i32_from_iconst b)))) + (pulley_xbxor32_s32 a b)) +(rule 4 (lower (has_type $I64 (bxor a (i32_from_iconst b)))) + (pulley_xbxor64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i8_from_iconst b)))) + (pulley_xbxor32_s8 a b)) +(rule 6 (lower (has_type $I64 (bxor a (i8_from_iconst b)))) + (pulley_xbxor64_s8 a b)) + +(rule 2 (lower (has_type (ty_vec128 _) (bxor a b))) + (pulley_vbxor128 a b)) + +;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (bnot a))) + (pulley_xbnot32 a)) + +(rule 1 (lower (has_type $I64 (bnot a))) + (pulley_xbnot64 a)) + +(rule 2 (lower (has_type (ty_vec128 _) (bnot a))) + (pulley_vbnot128 a)) + +;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_vec128 _) (bitselect c x y))) + (pulley_vbitselect128 c x y)) + +;;;; Rules for `umin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (umin a b))) + (pulley_xmin32_u (zext32 a) (zext32 b))) +(rule 1 (lower (has_type $I64 (umin a b))) (pulley_xmin64_u a b)) +(rule 1 (lower (has_type $I8X16 (umin a b))) (pulley_vmin8x16_u a b)) +(rule 1 (lower (has_type $I16X8 (umin a b))) (pulley_vmin16x8_u a b)) +(rule 1 (lower (has_type $I32X4 (umin a b))) (pulley_vmin32x4_u a b)) + +;;;; Rules for `smin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (smin a b))) + (pulley_xmin32_s (sext32 a) (sext32 b))) +(rule 1 (lower (has_type $I64 (smin a b))) (pulley_xmin64_s a b)) +(rule 1 (lower (has_type $I8X16 (smin a b))) (pulley_vmin8x16_s a b)) +(rule 1 (lower (has_type $I16X8 (smin a b))) (pulley_vmin16x8_s a b)) +(rule 1 (lower (has_type $I32X4 (smin a b))) (pulley_vmin32x4_s a b)) + +;;;; Rules for `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (umax a b))) + (pulley_xmax32_u (zext32 a) (zext32 b))) +(rule 1 (lower (has_type $I64 (umax a b))) (pulley_xmax64_u a b)) +(rule 1 (lower (has_type $I8X16 (umax a b))) (pulley_vmax8x16_u a b)) +(rule 1 (lower (has_type $I16X8 (umax a b))) (pulley_vmax16x8_u a b)) +(rule 1 (lower (has_type $I32X4 (umax a b))) (pulley_vmax32x4_u a b)) + +;;;; Rules for `smax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (smax a b))) + (pulley_xmax32_s (sext32 a) (sext32 b))) +(rule 1 (lower (has_type $I64 (smax a b))) (pulley_xmax64_s a b)) +(rule 1 (lower (has_type $I8X16 (smax a b))) (pulley_vmax8x16_s a b)) +(rule 1 (lower (has_type $I16X8 (smax a b))) (pulley_vmax16x8_s a b)) +(rule 1 (lower (has_type $I32X4 (smax a b))) (pulley_vmax32x4_s a b)) + +;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (bmask a @ (value_type (fits_in_32 _))))) + (pulley_xbmask32 (zext32 a))) +(rule 1 (lower (has_type $I64 (bmask a))) + (pulley_xbmask64 (zext64 a))) +(rule 2 (lower (bmask a @ (value_type $I64))) + (pulley_xbmask64 a)) + +;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (ctz a))) + (pulley_xctz32 (pulley_xbor32_s32 a 0x100))) +(rule (lower (has_type $I16 (ctz a))) + (pulley_xctz32 (pulley_xbor32_s32 a 0x10000))) +(rule (lower (has_type $I32 (ctz a))) (pulley_xctz32 a)) +(rule (lower (has_type $I64 (ctz a))) (pulley_xctz64 a)) + +;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (clz a))) + (pulley_xsub32_u8 (pulley_xclz32 (zext32 a)) 24)) +(rule (lower (has_type $I16 (clz a))) + (pulley_xsub32_u8 (pulley_xclz32 (zext32 a)) 16)) +(rule (lower (has_type $I32 (clz a))) (pulley_xclz32 a)) +(rule (lower (has_type $I64 (clz a))) (pulley_xclz64 a)) + +;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (popcnt a))) (pulley_xpopcnt32 (zext32 a))) +(rule 1 (lower (has_type $I64 (popcnt a))) (pulley_xpopcnt64 a)) +(rule 1 (lower (has_type $I8X16 (popcnt a))) (pulley_vpopcnt8x16 a)) + +;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32 (rotl a b))) (pulley_xrotl32 a b)) +(rule (lower (has_type $I64 (rotl a b))) (pulley_xrotl64 a b)) + +;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32 (rotr a b))) (pulley_xrotr32 a b)) +(rule (lower (has_type $I64 (rotr a b))) (pulley_xrotr64 a b)) + +;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (icmp cc a b @ (value_type (ty_int ty)))) + (lower_icmp ty cc a b)) + +(decl lower_icmp (Type IntCC Value Value) XReg) + +(rule (lower_icmp $I64 (IntCC.Equal) a b) + (pulley_xeq64 a b)) + +(rule (lower_icmp $I64 (IntCC.NotEqual) a b) + (pulley_xneq64 a b)) + +(rule (lower_icmp $I64 (IntCC.SignedLessThan) a b) + (pulley_xslt64 a b)) + +(rule (lower_icmp $I64 (IntCC.SignedLessThanOrEqual) a b) + (pulley_xslteq64 a b)) + +(rule (lower_icmp $I64 (IntCC.UnsignedLessThan) a b) + (pulley_xult64 a b)) + +(rule (lower_icmp $I64 (IntCC.UnsignedLessThanOrEqual) a b) + (pulley_xulteq64 a b)) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.Equal) a b) + (pulley_xeq32 (zext32 a) (zext32 b))) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.NotEqual) a b) + (pulley_xneq32 (zext32 a) (zext32 b))) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.SignedLessThan) a b) + (pulley_xslt32 (sext32 a) (sext32 b))) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.SignedLessThanOrEqual) a b) + (pulley_xslteq32 (sext32 a) (sext32 b))) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.UnsignedLessThan) a b) + (pulley_xult32 (zext32 a) (zext32 b))) + +(rule 1 (lower_icmp (fits_in_32 _) (IntCC.UnsignedLessThanOrEqual) a b) + (pulley_xulteq32 (zext32 a) (zext32 b))) + +;; Pulley doesn't have instructions for `>` and `>=`, so we have to reverse the +;; operation. +(rule (lower_icmp ty (IntCC.SignedGreaterThan) a b) + (lower_icmp ty (IntCC.SignedLessThan) b a)) +(rule (lower_icmp ty (IntCC.SignedGreaterThanOrEqual) a b) + (lower_icmp ty (IntCC.SignedLessThanOrEqual) b a)) +(rule (lower_icmp ty (IntCC.UnsignedGreaterThan) a b) + (lower_icmp ty (IntCC.UnsignedLessThan) b a)) +(rule (lower_icmp ty (IntCC.UnsignedGreaterThanOrEqual) a b) + (lower_icmp ty (IntCC.UnsignedLessThanOrEqual) b a)) + +;; `i128` comparisons +;; +;; While we could pretty easily add 128-bit comparisons to the interpreter it's +;; currently predicted that it's relatively niche to need this and that it's +;; not performance-sensitive in an interpreter context. In lieu of adding more +;; opcodes this is an adaptation of riscv64's lowering rules for 128-bit +;; integers. In the future if this is a performance bottleneck it should be +;; possible to add new opcodes to pulley for 128-bit comparisons. + +(rule (lower_icmp $I128 (IntCC.Equal) x y) + (let ((lo XReg (pulley_xbxor64 (value_regs_get x 0) (value_regs_get y 0))) + (hi XReg (pulley_xbxor64 (value_regs_get x 1) (value_regs_get y 1)))) + (pulley_xeq64 (pulley_xbor64 lo hi) (pulley_xconst8 0)))) +(rule (lower_icmp $I128 (IntCC.NotEqual) x y) + (let ((lo XReg (pulley_xbxor64 (value_regs_get x 0) (value_regs_get y 0))) + (hi XReg (pulley_xbxor64 (value_regs_get x 1) (value_regs_get y 1)))) + (pulley_xneq64 (pulley_xbor64 lo hi) (pulley_xconst8 0)))) + +;; swap args for `>` to use `<` instead +;;(rule 1 (lower_icmp $I128 cc @ (IntCC.SignedGreaterThan) x y) +;; (lower_icmp $I128 (intcc_swap_args cc) y x)) +;;(rule 1 (lower_icmp $I128 cc @ (IntCC.UnsignedGreaterThan) x y) +;; (lower_icmp $I128 (intcc_swap_args cc) y x)) + +;; complement `=`-related conditions to get ones that don't use `=`. +(rule 2 (lower_icmp $I128 cc @ (IntCC.SignedLessThanOrEqual) x y) + (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1)) +(rule 2 (lower_icmp $I128 cc @ (IntCC.SignedGreaterThanOrEqual) x y) + (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1)) +(rule 2 (lower_icmp $I128 cc @ (IntCC.UnsignedLessThanOrEqual) x y) + (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1)) +(rule 2 (lower_icmp $I128 cc @ (IntCC.UnsignedGreaterThanOrEqual) x y) + (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1)) + +;; Compare both the bottom and upper halves of the 128-bit values. If +;; the top half is equal use the bottom comparison, otherwise use the upper +;; comparison. Note that the lower comparison is always unsigned since if it's +;; used the top halves are all zeros and the semantic values are positive. +(rule 3 (lower_icmp $I128 cc x y) + (if-let (IntCC.UnsignedLessThan) (intcc_unsigned cc)) + (let ((x_lo XReg (value_regs_get x 0)) + (x_hi XReg (value_regs_get x 1)) + (y_lo XReg (value_regs_get y 0)) + (y_hi XReg (value_regs_get y 1)) + (top_cmp XReg (lower_icmp128_hi cc x_hi y_hi)) + (bottom_cmp XReg (pulley_xult64 x_lo y_lo))) + (pulley_xselect32 + (pulley_xeq64 (pulley_xbxor64 x_hi y_hi) (pulley_xconst8 0)) + bottom_cmp + top_cmp))) + +(decl lower_icmp128_hi (IntCC XReg XReg) XReg) +(rule (lower_icmp128_hi (IntCC.SignedLessThan) a b) (pulley_xslt64 a b)) +(rule (lower_icmp128_hi (IntCC.UnsignedLessThan) a b) (pulley_xult64 a b)) + +;; vector comparisons + +(rule 1 (lower (icmp cc a @ (value_type (ty_vec128 ty)) b)) + (lower_vcmp ty cc a b)) + +(decl lower_vcmp (Type IntCC Value Value) VReg) +(rule (lower_vcmp $I8X16 (IntCC.Equal) a b) (pulley_veq8x16 a b)) +(rule (lower_vcmp $I8X16 (IntCC.NotEqual) a b) (pulley_vneq8x16 a b)) +(rule (lower_vcmp $I8X16 (IntCC.SignedLessThan) a b) (pulley_vslt8x16 a b)) +(rule (lower_vcmp $I8X16 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq8x16 a b)) +(rule (lower_vcmp $I8X16 (IntCC.UnsignedLessThan) a b) (pulley_vult8x16 a b)) +(rule (lower_vcmp $I8X16 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq8x16 a b)) +(rule (lower_vcmp $I16X8 (IntCC.Equal) a b) (pulley_veq16x8 a b)) +(rule (lower_vcmp $I16X8 (IntCC.NotEqual) a b) (pulley_vneq16x8 a b)) +(rule (lower_vcmp $I16X8 (IntCC.SignedLessThan) a b) (pulley_vslt16x8 a b)) +(rule (lower_vcmp $I16X8 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq16x8 a b)) +(rule (lower_vcmp $I16X8 (IntCC.UnsignedLessThan) a b) (pulley_vult16x8 a b)) +(rule (lower_vcmp $I16X8 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq16x8 a b)) +(rule (lower_vcmp $I32X4 (IntCC.Equal) a b) (pulley_veq32x4 a b)) +(rule (lower_vcmp $I32X4 (IntCC.NotEqual) a b) (pulley_vneq32x4 a b)) +(rule (lower_vcmp $I32X4 (IntCC.SignedLessThan) a b) (pulley_vslt32x4 a b)) +(rule (lower_vcmp $I32X4 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq32x4 a b)) +(rule (lower_vcmp $I32X4 (IntCC.UnsignedLessThan) a b) (pulley_vult32x4 a b)) +(rule (lower_vcmp $I32X4 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq32x4 a b)) +(rule (lower_vcmp $I64X2 (IntCC.Equal) a b) (pulley_veq64x2 a b)) +(rule (lower_vcmp $I64X2 (IntCC.NotEqual) a b) (pulley_vneq64x2 a b)) +(rule (lower_vcmp $I64X2 (IntCC.SignedLessThan) a b) (pulley_vslt64x2 a b)) +(rule (lower_vcmp $I64X2 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq64x2 a b)) +(rule (lower_vcmp $I64X2 (IntCC.UnsignedLessThan) a b) (pulley_vult64x2 a b)) +(rule (lower_vcmp $I64X2 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq64x2 a b)) + +;; Sweap operand order of ops pulley doesn't support +(rule (lower_vcmp ty cc @ (IntCC.SignedGreaterThan) a b) + (lower_vcmp ty (intcc_swap_args cc) b a)) +(rule (lower_vcmp ty cc @ (IntCC.SignedGreaterThanOrEqual) a b) + (lower_vcmp ty (intcc_swap_args cc) b a)) +(rule (lower_vcmp ty cc @ (IntCC.UnsignedGreaterThan) a b) + (lower_vcmp ty (intcc_swap_args cc) b a)) +(rule (lower_vcmp ty cc @ (IntCC.UnsignedGreaterThanOrEqual) a b) + (lower_vcmp ty (intcc_swap_args cc) b a)) + +;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (fcmp cc a b @ (value_type (ty_scalar_float ty)))) + (lower_fcmp ty cc a b)) + +(decl lower_fcmp (Type FloatCC Value Value) XReg) + +(rule (lower_fcmp $F32 (FloatCC.Equal) a b) (pulley_feq32 a b)) +(rule (lower_fcmp $F64 (FloatCC.Equal) a b) (pulley_feq64 a b)) +(rule (lower_fcmp $F32 (FloatCC.NotEqual) a b) (pulley_fneq32 a b)) +(rule (lower_fcmp $F64 (FloatCC.NotEqual) a b) (pulley_fneq64 a b)) +(rule (lower_fcmp $F32 (FloatCC.LessThan) a b) (pulley_flt32 a b)) +(rule (lower_fcmp $F64 (FloatCC.LessThan) a b) (pulley_flt64 a b)) +(rule (lower_fcmp $F32 (FloatCC.LessThanOrEqual) a b) (pulley_flteq32 a b)) +(rule (lower_fcmp $F64 (FloatCC.LessThanOrEqual) a b) (pulley_flteq64 a b)) + +;; Ordered == !a.is_nan() && !b.is_nan() +(rule (lower_fcmp ty (FloatCC.Ordered) a b) + (pulley_xband32 (lower_fcmp ty (FloatCC.Equal) a a) (lower_fcmp ty (FloatCC.Equal) b b))) + +;; OrderedNotEqual == a < b || a > b +(rule (lower_fcmp ty (FloatCC.OrderedNotEqual) a b) + (pulley_xbor32 (lower_fcmp ty (FloatCC.LessThan) a b) (lower_fcmp ty (FloatCC.GreaterThan) a b))) + +;; Pulley doesn't have instructions for `>` and `>=`, so we have to reverse the +;; operation. +(rule (lower_fcmp ty (FloatCC.GreaterThan) a b) + (lower_fcmp ty (FloatCC.LessThan) b a)) +(rule (lower_fcmp ty (FloatCC.GreaterThanOrEqual) a b) + (lower_fcmp ty (FloatCC.LessThanOrEqual) b a)) + +;; For other `Unordered*` comparisons generate its complement and invert the result. +(rule -1 (lower_fcmp ty cc a b) + (if-let true (floatcc_unordered cc)) + (pulley_xbxor32_s8 (lower_fcmp ty (floatcc_complement cc) a b) 1)) + +;;;; Rules for `load` and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl amode (Value Offset32) Amode) +(rule (amode addr (offset32 offset)) (Amode.RegOffset addr offset)) +(rule 1 (amode (iadd addr (i32_from_iconst b)) (offset32 offset)) + (if-let new_offset (s32_add_fallible b offset)) + (Amode.RegOffset addr new_offset)) + +(rule (lower (has_type (ty_int (fits_in_64 ty)) (load flags addr offset))) + (pulley_xload (amode addr offset) ty flags (ExtKind.None))) + +(rule 1 (lower (has_type (ty_scalar_float ty) (load flags addr offset))) + (pulley_fload (amode addr offset) ty flags)) + +(rule 3 (lower (has_type $I128 (load flags addr offset))) + (if-let offsetp8 (s32_add_fallible offset 8)) + (let ((lo XReg (pulley_xload (amode addr offset) $I64 flags (ExtKind.None))) + (hi XReg (pulley_xload (amode addr offsetp8) $I64 flags (ExtKind.None)))) + (value_regs lo hi))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload8 flags addr offset))) + (pulley_xload (amode addr offset) $I8 flags (ExtKind.Zero32))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload16 flags addr offset))) + (pulley_xload (amode addr offset) $I16 flags (ExtKind.Zero32))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload32 flags addr offset))) + (pulley_xload (amode addr offset) $I32 flags (ExtKind.None))) + +(rule 1 (lower (has_type $I64 (uload8 flags addr offset))) + (pulley_xload (amode addr offset) $I8 flags (ExtKind.Zero64))) + +(rule 1 (lower (has_type $I64 (uload16 flags addr offset))) + (pulley_xload (amode addr offset) $I16 flags (ExtKind.Zero64))) + +(rule 1 (lower (has_type $I64 (uload32 flags addr offset))) + (pulley_xload (amode addr offset) $I32 flags (ExtKind.Zero64))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload8 flags addr offset))) + (pulley_xload (amode addr offset) $I8 flags (ExtKind.Sign32))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload16 flags addr offset))) + (pulley_xload (amode addr offset) $I16 flags (ExtKind.Sign32))) + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload32 flags addr offset))) + (pulley_xload (amode addr offset) $I32 flags (ExtKind.None))) + +(rule 1 (lower (has_type $I64 (sload8 flags addr offset))) + (pulley_xload (amode addr offset) $I8 flags (ExtKind.Sign64))) + +(rule 1 (lower (has_type $I64 (sload16 flags addr offset))) + (pulley_xload (amode addr offset) $I16 flags (ExtKind.Sign64))) + +(rule 1 (lower (has_type $I64 (sload32 flags addr offset))) + (pulley_xload (amode addr offset) $I32 flags (ExtKind.Sign64))) + +(rule 2 (lower (has_type (ty_vec128 ty) (load flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.None))) + +(rule (lower (has_type ty (sload8x8 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.S8x8))) + +(rule (lower (has_type ty (uload8x8 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.U8x8))) + +(rule (lower (has_type ty (sload16x4 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.S16x4))) + +(rule (lower (has_type ty (uload16x4 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.U16x4))) + +(rule (lower (has_type ty (sload32x2 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.S32x2))) + +(rule (lower (has_type ty (uload32x2 flags addr offset))) + (pulley_vload (amode addr offset) ty flags (VExtKind.U32x2))) + +;;;; Rules for `store` and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (store flags src @ (value_type (ty_int (fits_in_64 ty))) addr offset)) + (side_effect (pulley_xstore (amode addr offset) src ty flags))) + +(rule 1 (lower (store flags src @ (value_type (ty_scalar_float ty)) addr offset)) + (side_effect (pulley_fstore (amode addr offset) src ty flags))) + +(rule (lower (istore8 flags src addr offset)) + (side_effect (pulley_xstore (amode addr offset) src $I8 flags))) + +(rule (lower (istore16 flags src addr offset)) + (side_effect (pulley_xstore (amode addr offset) src $I16 flags))) + +(rule (lower (istore32 flags src addr offset)) + (side_effect (pulley_xstore (amode addr offset) src $I32 flags))) + +(rule 2 (lower (store flags src @ (value_type (ty_vec128 ty)) addr offset)) + (side_effect (pulley_vstore (amode addr offset) src ty flags))) + +;;;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (stack_addr stack_slot offset)) + (lower_stack_addr stack_slot offset)) + +(decl lower_stack_addr (StackSlot Offset32) XReg) +(rule (lower_stack_addr stack_slot offset) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (abi_stackslot_addr dst stack_slot offset)))) + dst)) + +;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (uextend val))) + (zext32 val)) + +(rule 1 (lower (has_type $I64 (uextend val))) + (zext64 val)) + +;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (sextend val))) + (sext32 val)) + +(rule 1 (lower (has_type $I64 (sextend val))) + (sext64 val)) + +(rule 1 (lower (has_type $I128 (sextend val))) + (if-let (u6_from_u8 shift) (u64_as_u8 63)) + (let ((lo XReg (sext64 val)) + (hi XReg (pulley_xshr64_s_u6 lo shift))) + (value_regs lo hi))) + +;;;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (fits_in_64 _ty) (ireduce src))) + src) + +;;;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I128 (iconcat a b))) + (value_regs a b)) + +;;;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (isplit x @ (value_type $I128))) + (let ((lo XReg (value_regs_get x 0)) + (hi XReg (value_regs_get x 1))) + (output_pair lo hi))) + +;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32 (uadd_overflow_trap a b tc))) + (pulley_xadd32_uoverflow_trap a b tc)) + +(rule (lower (has_type $I64 (uadd_overflow_trap a b tc))) + (pulley_xadd64_uoverflow_trap a b tc)) + +;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (select c a b))) + (pulley_xselect32 (emit_cond (lower_cond c)) a b)) + +(rule 1 (lower (has_type $I64 (select c a b))) + (pulley_xselect64 (emit_cond (lower_cond c)) a b)) + +(rule 1 (lower (has_type $F32 (select c a b))) + (pulley_fselect32 (emit_cond (lower_cond c)) a b)) + +(rule 1 (lower (has_type $F64 (select c a b))) + (pulley_fselect64 (emit_cond (lower_cond c)) a b)) + +;; Helper to emit a conditional into a register itself. +(decl emit_cond (Cond) XReg) +(rule (emit_cond (Cond.If32 reg)) reg) +(rule (emit_cond (Cond.IfNot32 reg)) (pulley_xeq32 reg (pulley_xconst8 0))) +(rule (emit_cond (Cond.IfXeq32 src1 src2)) (pulley_xeq32 src1 src2)) +(rule (emit_cond (Cond.IfXneq32 src1 src2)) (pulley_xneq32 src1 src2)) +(rule (emit_cond (Cond.IfXslt32 src1 src2)) (pulley_xslt32 src1 src2)) +(rule (emit_cond (Cond.IfXslteq32 src1 src2)) (pulley_xslteq32 src1 src2)) +(rule (emit_cond (Cond.IfXult32 src1 src2)) (pulley_xult32 src1 src2)) +(rule (emit_cond (Cond.IfXulteq32 src1 src2)) (pulley_xulteq32 src1 src2)) +(rule (emit_cond (Cond.IfXeq64 src1 src2)) (pulley_xeq64 src1 src2)) +(rule (emit_cond (Cond.IfXneq64 src1 src2)) (pulley_xneq64 src1 src2)) +(rule (emit_cond (Cond.IfXslt64 src1 src2)) (pulley_xslt64 src1 src2)) +(rule (emit_cond (Cond.IfXslteq64 src1 src2)) (pulley_xslteq64 src1 src2)) +(rule (emit_cond (Cond.IfXult64 src1 src2)) (pulley_xult64 src1 src2)) +(rule (emit_cond (Cond.IfXulteq64 src1 src2)) (pulley_xulteq64 src1 src2)) + +(rule (emit_cond (Cond.IfXeq32I32 src1 src2)) + (pulley_xeq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXneq32I32 src1 src2)) + (pulley_xneq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslt32I32 src1 src2)) + (pulley_xslt32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslteq32I32 src1 src2)) + (pulley_xslteq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXult32I32 src1 src2)) + (pulley_xult32 src1 (imm $I32 (u32_as_u64 src2)))) +(rule (emit_cond (Cond.IfXulteq32I32 src1 src2)) + (pulley_xulteq32 src1 (imm $I32 (u32_as_u64 src2)))) + +;; Note the operand swaps here +(rule (emit_cond (Cond.IfXsgt32I32 src1 src2)) + (pulley_xslt32 (imm $I32 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXsgteq32I32 src1 src2)) + (pulley_xslteq32 (imm $I32 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXugt32I32 src1 src2)) + (pulley_xult32 (imm $I32 (u32_as_u64 src2)) src1)) +(rule (emit_cond (Cond.IfXugteq32I32 src1 src2)) + (pulley_xulteq32 (imm $I32 (u32_as_u64 src2)) src1)) + +(rule (emit_cond (Cond.IfXeq64I32 src1 src2)) + (pulley_xeq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXneq64I32 src1 src2)) + (pulley_xneq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslt64I32 src1 src2)) + (pulley_xslt64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslteq64I32 src1 src2)) + (pulley_xslteq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXult64I32 src1 src2)) + (pulley_xult64 src1 (imm $I64 (u32_as_u64 src2)))) +(rule (emit_cond (Cond.IfXulteq64I32 src1 src2)) + (pulley_xulteq64 src1 (imm $I64 (u32_as_u64 src2)))) + +;; Note the operand swaps here +(rule (emit_cond (Cond.IfXsgt64I32 src1 src2)) + (pulley_xslt64 (imm $I64 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXsgteq64I32 src1 src2)) + (pulley_xslteq64 (imm $I64 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXugt64I32 src1 src2)) + (pulley_xult64 (imm $I64 (u32_as_u64 src2)) src1)) +(rule (emit_cond (Cond.IfXugteq64I32 src1 src2)) + (pulley_xulteq64 (imm $I64 (u32_as_u64 src2)) src1)) + +;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (bitcast _flags val @ (value_type $I32)))) + (pulley_bitcast_float_from_int_32 val)) + +(rule (lower (has_type $F64 (bitcast _flags val @ (value_type $I64)))) + (pulley_bitcast_float_from_int_64 val)) + +(rule (lower (has_type $I32 (bitcast _flags val @ (value_type $F32)))) + (pulley_bitcast_int_from_float_32 val)) + +(rule (lower (has_type $I64 (bitcast _flags val @ (value_type $F64)))) + (pulley_bitcast_int_from_float_64 val)) + +(rule 1 (lower (has_type (ty_vec128 _) (bitcast _flags val @ (value_type (ty_vec128 _))))) + val) + +(rule 2 (lower (has_type ty (bitcast _flags a @ (value_type ty)))) a) + +;;;; Rules for `fcvt_to_{u,s}int` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32 (fcvt_to_uint val @ (value_type $F32)))) + (pulley_x32_from_f32_u val)) + +(rule (lower (has_type $I32 (fcvt_to_uint val @ (value_type $F64)))) + (pulley_x32_from_f64_u val)) + +(rule (lower (has_type $I64 (fcvt_to_uint val @ (value_type $F32)))) + (pulley_x64_from_f32_u val)) + +(rule (lower (has_type $I64 (fcvt_to_uint val @ (value_type $F64)))) + (pulley_x64_from_f64_u val)) + +(rule (lower (has_type $I32 (fcvt_to_sint val @ (value_type $F32)))) + (pulley_x32_from_f32_s val)) + +(rule (lower (has_type $I32 (fcvt_to_sint val @ (value_type $F64)))) + (pulley_x32_from_f64_s val)) + +(rule (lower (has_type $I64 (fcvt_to_sint val @ (value_type $F32)))) + (pulley_x64_from_f32_s val)) + +(rule (lower (has_type $I64 (fcvt_to_sint val @ (value_type $F64)))) + (pulley_x64_from_f64_s val)) + +;;;; Rules for `fcvt_from_{u,s}int` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fcvt_from_uint val @ (value_type $I32)))) + (pulley_f32_from_x32_u val)) + +(rule (lower (has_type $F32 (fcvt_from_uint val @ (value_type $I64)))) + (pulley_f32_from_x64_u val)) + +(rule (lower (has_type $F64 (fcvt_from_uint val @ (value_type $I32)))) + (pulley_f64_from_x32_u val)) + +(rule (lower (has_type $F64 (fcvt_from_uint val @ (value_type $I64)))) + (pulley_f64_from_x64_u val)) + +(rule (lower (has_type $F32 (fcvt_from_sint val @ (value_type $I32)))) + (pulley_f32_from_x32_s val)) + +(rule (lower (has_type $F32 (fcvt_from_sint val @ (value_type $I64)))) + (pulley_f32_from_x64_s val)) + +(rule (lower (has_type $F64 (fcvt_from_sint val @ (value_type $I32)))) + (pulley_f64_from_x32_s val)) + +(rule (lower (has_type $F64 (fcvt_from_sint val @ (value_type $I64)))) + (pulley_f64_from_x64_s val)) + +(rule (lower (has_type $F32X4 (fcvt_from_sint val @ (value_type $I32X4)))) + (pulley_vf32x4_from_i32x4_s val)) + +(rule (lower (has_type $F32X4 (fcvt_from_uint val @ (value_type $I32X4)))) + (pulley_vf32x4_from_i32x4_u val)) + +(rule (lower (has_type $F64X2 (fcvt_from_sint val @ (value_type $I64X2)))) + (pulley_vf64x2_from_i64x2_s val)) + +(rule (lower (has_type $F64X2 (fcvt_from_uint val @ (value_type $I64X2)))) + (pulley_vf64x2_from_i64x2_u val)) + +;;;; Rules for `fcvt_to_{u,s}int_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32 (fcvt_to_uint_sat val @ (value_type $F32)))) + (pulley_x32_from_f32_u_sat val)) + +(rule (lower (has_type $I32 (fcvt_to_uint_sat val @ (value_type $F64)))) + (pulley_x32_from_f64_u_sat val)) + +(rule (lower (has_type $I64 (fcvt_to_uint_sat val @ (value_type $F32)))) + (pulley_x64_from_f32_u_sat val)) + +(rule (lower (has_type $I64 (fcvt_to_uint_sat val @ (value_type $F64)))) + (pulley_x64_from_f64_u_sat val)) + +(rule (lower (has_type $I32 (fcvt_to_sint_sat val @ (value_type $F32)))) + (pulley_x32_from_f32_s_sat val)) + +(rule (lower (has_type $I32 (fcvt_to_sint_sat val @ (value_type $F64)))) + (pulley_x32_from_f64_s_sat val)) + +(rule (lower (has_type $I64 (fcvt_to_sint_sat val @ (value_type $F32)))) + (pulley_x64_from_f32_s_sat val)) + +(rule (lower (has_type $I64 (fcvt_to_sint_sat val @ (value_type $F64)))) + (pulley_x64_from_f64_s_sat val)) + +;;;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fdemote val @ (value_type $F64)))) + (pulley_f32_from_f64 val)) + +;;;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F64 (fpromote val @ (value_type $F32)))) + (pulley_f64_from_f32 val)) + +;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fcopysign a b))) + (pulley_fcopysign32 a b)) + +(rule (lower (has_type $F64 (fcopysign a b))) + (pulley_fcopysign64 a b)) + +;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fadd a b))) (pulley_fadd32 a b)) +(rule (lower (has_type $F64 (fadd a b))) (pulley_fadd64 a b)) +(rule (lower (has_type $F32X4 (fadd a b))) (pulley_vaddf32x4 a b)) +(rule (lower (has_type $F64X2 (fadd a b))) (pulley_vaddf64x2 a b)) + +;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fsub a b))) (pulley_fsub32 a b)) +(rule (lower (has_type $F64 (fsub a b))) (pulley_fsub64 a b)) +(rule (lower (has_type $F64X2 (fsub a b))) (pulley_vsubf64x2 a b)) + +;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmul a b))) (pulley_fmul32 a b)) +(rule (lower (has_type $F64 (fmul a b))) (pulley_fmul64 a b)) +(rule (lower (has_type $F64X2 (fmul a b))) (pulley_vmulf64x2 a b)) + +;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fdiv a b))) (pulley_fdiv32 a b)) +(rule (lower (has_type $F64 (fdiv a b))) (pulley_fdiv64 a b)) +(rule (lower (has_type $F32X4 (fdiv a b))) (pulley_vdivf32x4 a b)) +(rule (lower (has_type $F64X2 (fdiv a b))) (pulley_vdivf64x2 a b)) + +;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmax a b))) (pulley_fmaximum32 a b)) +(rule (lower (has_type $F64 (fmax a b))) (pulley_fmaximum64 a b)) +(rule (lower (has_type $F32X4 (fmax a b))) (pulley_vmaximumf32x4 a b)) +(rule (lower (has_type $F64X2 (fmax a b))) (pulley_vmaximumf64x2 a b)) + +;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmin a b))) (pulley_fminimum32 a b)) +(rule (lower (has_type $F64 (fmin a b))) (pulley_fminimum64 a b)) +(rule (lower (has_type $F32X4 (fmin a b))) (pulley_vminimumf32x4 a b)) +(rule (lower (has_type $F64X2 (fmin a b))) (pulley_vminimumf64x2 a b)) + +;;;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (trunc a))) (pulley_ftrunc32 a)) +(rule (lower (has_type $F64 (trunc a))) (pulley_ftrunc64 a)) +(rule (lower (has_type $F32X4 (trunc a))) (pulley_vtrunc32x4 a)) +(rule (lower (has_type $F64X2 (trunc a))) (pulley_vtrunc64x2 a)) + +;;;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (floor a))) (pulley_ffloor32 a)) +(rule (lower (has_type $F64 (floor a))) (pulley_ffloor64 a)) +(rule (lower (has_type $F32X4 (floor a))) + (pulley_vfloor32x4 a)) +(rule (lower (has_type $F64X2 (floor a))) + (pulley_vfloor64x2 a)) +;;;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (ceil a))) (pulley_fceil32 a)) +(rule (lower (has_type $F64 (ceil a))) (pulley_fceil64 a)) +(rule (lower (has_type $F64X2 (ceil a))) + (pulley_vceil64x2 a)) +(rule (lower (has_type $F32X4 (ceil a))) + (pulley_vceil32x4 a)) + +;;;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (nearest a))) (pulley_fnearest32 a)) +(rule (lower (has_type $F64 (nearest a))) (pulley_fnearest64 a)) +(rule (lower (has_type $F32X4 (nearest a))) + (pulley_vnearest32x4 a)) +(rule (lower (has_type $F64X2 (nearest a))) + (pulley_vnearest64x2 a)) + +;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (sqrt a))) (pulley_fsqrt32 a)) +(rule (lower (has_type $F64 (sqrt a))) (pulley_fsqrt64 a)) +(rule (lower (has_type $F32X4 (sqrt a))) + (pulley_vsqrt32x4 a)) +(rule (lower (has_type $F64X2 (sqrt a))) + (pulley_vsqrt64x2 a)) + + +;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fneg a))) (pulley_fneg32 a)) +(rule (lower (has_type $F64 (fneg a))) (pulley_fneg64 a)) +(rule (lower (has_type $F64X2 (fneg a))) (pulley_vnegf64x2 a)) + +;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (ineg a))) (pulley_xneg32 (sext32 a))) +(rule 1 (lower (has_type $I64 (ineg a))) (pulley_xneg64 a)) + +;; vector negation + +(rule 1 (lower (has_type $I8X16 (ineg a))) (pulley_vneg8x16 a)) +(rule 1 (lower (has_type $I16X8 (ineg a))) (pulley_vneg16x8 a)) +(rule 1 (lower (has_type $I32X4 (ineg a))) (pulley_vneg32x4 a)) +(rule 1 (lower (has_type $I64X2 (ineg a))) (pulley_vneg64x2 a)) + +;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fabs a))) (pulley_fabs32 a)) +(rule (lower (has_type $F64 (fabs a))) (pulley_fabs64 a)) +(rule (lower (has_type $F32X4 (fabs a))) (pulley_vabsf32x4 a)) +(rule (lower (has_type $F64X2 (fabs a))) (pulley_vabsf64x2 a)) + +;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_vec128 _) (vconst (u128_from_constant a)))) (pulley_vconst128 a)) + +;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I16 (bswap a))) + (if-let (u6_from_u8 shift) (u64_as_u8 16)) + (pulley_xshr32_u_u6 (pulley_bswap32 a) shift)) +(rule (lower (has_type $I32 (bswap a))) (pulley_bswap32 a)) +(rule (lower (has_type $I64 (bswap a))) (pulley_bswap64 a)) + +;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_32 _) (iabs a))) (pulley_xabs32 (sext32 a))) +(rule 1 (lower (has_type $I64 (iabs a))) (pulley_xabs64 a)) +(rule 1 (lower (has_type $I8X16 (iabs a))) (pulley_vabs8x16 a)) +(rule 1 (lower (has_type $I16X8 (iabs a))) (pulley_vabs16x8 a)) +(rule 1 (lower (has_type $I32X4 (iabs a))) (pulley_vabs32x4 a)) +(rule 1 (lower (has_type $I64X2 (iabs a))) (pulley_vabs64x2 a)) + +;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (splat a))) (pulley_vsplatx8 a)) +(rule (lower (has_type $I16X8 (splat a))) (pulley_vsplatx16 a)) +(rule (lower (has_type $I32X4 (splat a))) (pulley_vsplatx32 a)) +(rule (lower (has_type $I64X2 (splat a))) (pulley_vsplatx64 a)) +(rule (lower (has_type $F32X4 (splat a))) (pulley_vsplatf32 a)) +(rule (lower (has_type $F64X2 (splat a))) (pulley_vsplatf64 a)) + +;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I8X16)))) + (pulley_vbitmask8x16 a)) +(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I16X8)))) + (pulley_vbitmask16x8 a)) +(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I32X4)))) + (pulley_vbitmask32x4 a)) +(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I64X2)))) + (pulley_vbitmask64x2 a)) + +;;;; Rules for `vall_true`; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (vall_true a @ (value_type $I8X16))) (pulley_valltrue8x16 a)) +(rule (lower (vall_true a @ (value_type $I16X8))) (pulley_valltrue16x8 a)) +(rule (lower (vall_true a @ (value_type $I32X4))) (pulley_valltrue32x4 a)) +(rule (lower (vall_true a @ (value_type $I64X2))) (pulley_valltrue64x2 a)) +(rule (lower (vall_true a @ (value_type $F32X4))) (pulley_valltrue32x4 a)) +(rule (lower (vall_true a @ (value_type $F64X2))) (pulley_valltrue64x2 a)) + +;;;; Rules for `vany_true`; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (vany_true a @ (value_type $I8X16))) (pulley_vanytrue8x16 a)) +(rule (lower (vany_true a @ (value_type $I16X8))) (pulley_vanytrue16x8 a)) +(rule (lower (vany_true a @ (value_type $I32X4))) (pulley_vanytrue32x4 a)) +(rule (lower (vany_true a @ (value_type $I64X2))) (pulley_vanytrue64x2 a)) +(rule (lower (vany_true a @ (value_type $F32X4))) (pulley_vanytrue32x4 a)) +(rule (lower (vany_true a @ (value_type $F64X2))) (pulley_vanytrue64x2 a)) + +;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (swiden_low a @ (value_type $I8X16))) (pulley_vwidenlow8x16_s a)) +(rule (lower (swiden_low a @ (value_type $I16X8))) (pulley_vwidenlow16x8_s a)) +(rule (lower (swiden_low a @ (value_type $I32X4))) (pulley_vwidenlow32x4_s a)) + +;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (swiden_high a @ (value_type $I8X16))) (pulley_vwidenhigh8x16_s a)) +(rule (lower (swiden_high a @ (value_type $I16X8))) (pulley_vwidenhigh16x8_s a)) +(rule (lower (swiden_high a @ (value_type $I32X4))) (pulley_vwidenhigh32x4_s a)) + +;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (uwiden_low a @ (value_type $I8X16))) (pulley_vwidenlow8x16_u a)) +(rule (lower (uwiden_low a @ (value_type $I16X8))) (pulley_vwidenlow16x8_u a)) +(rule (lower (uwiden_low a @ (value_type $I32X4))) (pulley_vwidenlow32x4_u a)) + +;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (uwiden_high a @ (value_type $I8X16))) (pulley_vwidenhigh8x16_u a)) +(rule (lower (uwiden_high a @ (value_type $I16X8))) (pulley_vwidenhigh16x8_u a)) +(rule (lower (uwiden_high a @ (value_type $I32X4))) (pulley_vwidenhigh32x4_u a)) + +;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (snarrow a @ (value_type $I16X8) b)) (pulley_vnarrow16x8_s a b)) +(rule (lower (snarrow a @ (value_type $I32X4) b)) (pulley_vnarrow32x4_s a b)) + +;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (unarrow a @ (value_type $I16X8) b)) (pulley_vnarrow16x8_u a b)) +(rule (lower (unarrow a @ (value_type $I32X4) b)) (pulley_vnarrow32x4_u a b)) + +;;;; Rules for `fvpromote_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (fvpromote_low a @ (value_type $F32X4))) (pulley_vfpromotelow a)) + +;;;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (fvdemote a @ (value_type $F64X2))) (pulley_vfdemote a)) + +;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (extractlane a @ (value_type $I8X16) (u8_from_uimm8 lane))) + (pulley_xextractv8x16 a lane)) +(rule (lower (extractlane a @ (value_type $I16X8) (u8_from_uimm8 lane))) + (pulley_xextractv16x8 a lane)) +(rule (lower (extractlane a @ (value_type $I32X4) (u8_from_uimm8 lane))) + (pulley_xextractv32x4 a lane)) +(rule (lower (extractlane a @ (value_type $I64X2) (u8_from_uimm8 lane))) + (pulley_xextractv64x2 a lane)) +(rule (lower (extractlane a @ (value_type $F32X4) (u8_from_uimm8 lane))) + (pulley_fextractv32x4 a lane)) +(rule (lower (extractlane a @ (value_type $F64X2) (u8_from_uimm8 lane))) + (pulley_fextractv64x2 a lane)) + +;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (insertlane a @ (value_type $I8X16) b (u8_from_uimm8 lane))) + (pulley_vinsertx8 a b lane)) +(rule (lower (insertlane a @ (value_type $I16X8) b (u8_from_uimm8 lane))) + (pulley_vinsertx16 a b lane)) +(rule (lower (insertlane a @ (value_type $I32X4) b (u8_from_uimm8 lane))) + (pulley_vinsertx32 a b lane)) +(rule (lower (insertlane a @ (value_type $I64X2) b (u8_from_uimm8 lane))) + (pulley_vinsertx64 a b lane)) +(rule (lower (insertlane a @ (value_type $F32X4) b (u8_from_uimm8 lane))) + (pulley_vinsertf32 a b lane)) +(rule (lower (insertlane a @ (value_type $F64X2) b (u8_from_uimm8 lane))) + (pulley_vinsertf64 a b lane)) + +;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Note that this doesn't use special pulley instructions at this time and +;; generates a bytecode-wise relatively inefficient lowering. Should be +;; relatively easy to optimize if necessary in the future. + +(rule (lower (scalar_to_vector a @ (value_type $I8))) + (pulley_vinsertx8 (pulley_vconst128 0) a 0)) +(rule (lower (scalar_to_vector a @ (value_type $I16))) + (pulley_vinsertx16 (pulley_vconst128 0) a 0)) +(rule (lower (scalar_to_vector a @ (value_type $I32))) + (pulley_vinsertx32 (pulley_vconst128 0) a 0)) +(rule (lower (scalar_to_vector a @ (value_type $I64))) + (pulley_vinsertx64 (pulley_vconst128 0) a 0)) +(rule (lower (scalar_to_vector a @ (value_type $F32))) + (pulley_vinsertf32 (pulley_vconst128 0) a 0)) +(rule (lower (scalar_to_vector a @ (value_type $F64))) + (pulley_vinsertf64 (pulley_vconst128 0) a 0)) + +;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (shuffle a b (u128_from_immediate mask)))) + (pulley_vshuffle a b mask)) + +;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (has_type $I8X16 (swizzle a b))) (pulley_vswizzlei8x16 a b)) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.rs new file mode 100644 index 00000000000000..9f8754d513d3bb --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower.rs @@ -0,0 +1,36 @@ +//! Lowering backend for Pulley. + +pub mod isle; + +use super::{inst::*, PulleyBackend, PulleyTargetKind}; +use crate::{ + ir, + machinst::{lower::*, *}, +}; + +impl

LowerBackend for PulleyBackend

+where + P: PulleyTargetKind, +{ + type MInst = InstAndKind

; + + fn lower(&self, ctx: &mut Lower, ir_inst: ir::Inst) -> Option { + isle::lower(ctx, self, ir_inst) + } + + fn lower_branch( + &self, + ctx: &mut Lower, + ir_inst: ir::Inst, + targets: &[MachLabel], + ) -> Option<()> { + isle::lower_branch(ctx, self, ir_inst, targets) + } + + fn maybe_pinned_reg(&self) -> Option { + // Pulley does not support this feature right now. + None + } + + type FactFlowState = (); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle.rs new file mode 100644 index 00000000000000..f344d33436dfc9 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle.rs @@ -0,0 +1,162 @@ +//! ISLE integration glue code for Pulley lowering. + +// Pull in the ISLE generated code. +pub mod generated_code; +use generated_code::MInst; +use inst::InstAndKind; + +// Types that the generated ISLE code uses via `use super::*`. +use crate::ir::{condcodes::*, immediates::*, types::*, *}; +use crate::isa::pulley_shared::{ + abi::*, + inst::{ + FReg, OperandSize, PulleyCall, ReturnCallInfo, VReg, WritableFReg, WritableVReg, + WritableXReg, XReg, + }, + lower::{regs, Cond}, + *, +}; +use crate::machinst::{ + abi::{ArgPair, RetPair, StackAMode}, + isle::*, + CallInfo, IsTailCall, MachInst, Reg, VCodeConstant, VCodeConstantData, +}; +use alloc::boxed::Box; +use pulley_interpreter::U6; +use regalloc2::PReg; +type Unit = (); +type VecArgPair = Vec; +type VecRetPair = Vec; +type BoxCallInfo = Box>; +type BoxCallIndInfo = Box>; +type BoxCallIndirectHostInfo = Box>; +type BoxReturnCallInfo = Box>; +type BoxReturnCallIndInfo = Box>; +type BoxExternalName = Box; +type XRegSet = pulley_interpreter::RegSet; + +#[expect( + unused_imports, + reason = "used on other backends, used here to suppress warning elsewhere" +)] +use crate::machinst::isle::UnwindInst as _; + +pub(crate) struct PulleyIsleContext<'a, 'b, I, B> +where + I: VCodeInst, + B: LowerBackend, +{ + pub lower_ctx: &'a mut Lower<'b, I>, + pub backend: &'a B, +} + +impl<'a, 'b, P> PulleyIsleContext<'a, 'b, InstAndKind

, PulleyBackend

> +where + P: PulleyTargetKind, +{ + fn new(lower_ctx: &'a mut Lower<'b, InstAndKind

>, backend: &'a PulleyBackend

) -> Self { + Self { lower_ctx, backend } + } +} + +impl

generated_code::Context for PulleyIsleContext<'_, '_, InstAndKind

, PulleyBackend

> +where + P: PulleyTargetKind, +{ + crate::isle_lower_prelude_methods!(InstAndKind

); + crate::isle_prelude_caller_methods!(PulleyABICallSite

); + + fn vreg_new(&mut self, r: Reg) -> VReg { + VReg::new(r).unwrap() + } + fn writable_vreg_new(&mut self, r: WritableReg) -> WritableVReg { + r.map(|wr| VReg::new(wr).unwrap()) + } + fn writable_vreg_to_vreg(&mut self, arg0: WritableVReg) -> VReg { + arg0.to_reg() + } + fn writable_vreg_to_writable_reg(&mut self, arg0: WritableVReg) -> WritableReg { + arg0.map(|vr| vr.to_reg()) + } + fn vreg_to_reg(&mut self, arg0: VReg) -> Reg { + *arg0 + } + fn xreg_new(&mut self, r: Reg) -> XReg { + XReg::new(r).unwrap() + } + fn writable_xreg_new(&mut self, r: WritableReg) -> WritableXReg { + r.map(|wr| XReg::new(wr).unwrap()) + } + fn writable_xreg_to_xreg(&mut self, arg0: WritableXReg) -> XReg { + arg0.to_reg() + } + fn writable_xreg_to_writable_reg(&mut self, arg0: WritableXReg) -> WritableReg { + arg0.map(|xr| xr.to_reg()) + } + fn xreg_to_reg(&mut self, arg0: XReg) -> Reg { + *arg0 + } + fn freg_new(&mut self, r: Reg) -> FReg { + FReg::new(r).unwrap() + } + fn writable_freg_new(&mut self, r: WritableReg) -> WritableFReg { + r.map(|wr| FReg::new(wr).unwrap()) + } + fn writable_freg_to_freg(&mut self, arg0: WritableFReg) -> FReg { + arg0.to_reg() + } + fn writable_freg_to_writable_reg(&mut self, arg0: WritableFReg) -> WritableReg { + arg0.map(|fr| fr.to_reg()) + } + fn freg_to_reg(&mut self, arg0: FReg) -> Reg { + *arg0 + } + + #[inline] + fn emit(&mut self, arg0: &MInst) -> Unit { + self.lower_ctx.emit(arg0.clone().into()); + } + + fn sp_reg(&mut self) -> XReg { + XReg::new(regs::stack_reg()).unwrap() + } + + fn cond_invert(&mut self, cond: &Cond) -> Cond { + cond.invert() + } + + fn u6_from_u8(&mut self, imm: u8) -> Option { + U6::new(imm) + } +} + +/// The main entry point for lowering with ISLE. +pub(crate) fn lower

( + lower_ctx: &mut Lower>, + backend: &PulleyBackend

, + inst: Inst, +) -> Option +where + P: PulleyTargetKind, +{ + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = PulleyIsleContext::new(lower_ctx, backend); + generated_code::constructor_lower(&mut isle_ctx, inst) +} + +/// The main entry point for branch lowering with ISLE. +pub(crate) fn lower_branch

( + lower_ctx: &mut Lower>, + backend: &PulleyBackend

, + branch: Inst, + targets: &[MachLabel], +) -> Option<()> +where + P: PulleyTargetKind, +{ + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = PulleyIsleContext::new(lower_ctx, backend); + generated_code::constructor_lower_branch(&mut isle_ctx, branch, targets) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle/generated_code.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle/generated_code.rs new file mode 100644 index 00000000000000..5467fc5ea6369d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/lower/isle/generated_code.rs @@ -0,0 +1,17 @@ +// See https://github.com/rust-lang/rust/issues/47995: we cannot use `#![...]` attributes inside of +// the generated ISLE source below because we include!() it. We must include!() it because its path +// depends on an environment variable; and also because of this, we can't do the `#[path = "..."] +// mod generated_code;` trick either. +#![allow( + dead_code, + unreachable_code, + unreachable_patterns, + unused_imports, + unused_variables, + non_snake_case, + unused_mut, + irrefutable_let_patterns, + clippy::all +)] + +include!(concat!(env!("ISLE_DIR"), "/isle_pulley_shared.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/mod.rs new file mode 100644 index 00000000000000..16aba8304e7223 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/mod.rs @@ -0,0 +1,287 @@ +//! Common support compiling to either 32- or 64-bit Pulley bytecode. + +mod abi; +mod inst; +mod lower; +mod settings; + +use self::inst::EmitInfo; +use super::{Builder as IsaBuilder, FunctionAlignment}; +use crate::{ + dominator_tree::DominatorTree, + ir, + isa::{self, OwnedTargetIsa, TargetIsa}, + machinst::{self, CompiledCodeStencil, MachInst, SigSet, VCode}, + result::CodegenResult, + settings::{self as shared_settings, Flags}, + MachTextSectionBuilder, TextSectionBuilder, +}; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::fmt::Debug; +use core::marker::PhantomData; +use cranelift_control::ControlPlane; +use target_lexicon::{Architecture, Triple}; + +pub use settings::Flags as PulleyFlags; + +/// A trait to abstract over the different kinds of Pulley targets that exist +/// (32- vs 64-bit). +pub trait PulleyTargetKind: 'static + Clone + Debug + Default + Send + Sync { + // Required types and methods. + + fn pointer_width() -> PointerWidth; + + // Provided methods. Don't overwrite. + + fn name() -> &'static str { + match Self::pointer_width() { + PointerWidth::PointerWidth32 => "pulley32", + PointerWidth::PointerWidth64 => "pulley64", + } + } +} + +pub enum PointerWidth { + PointerWidth32, + PointerWidth64, +} + +impl PointerWidth { + pub fn bits(self) -> u8 { + match self { + PointerWidth::PointerWidth32 => 32, + PointerWidth::PointerWidth64 => 64, + } + } + + pub fn bytes(self) -> u8 { + self.bits() / 8 + } +} + +/// A Pulley backend. +pub struct PulleyBackend

+where + P: PulleyTargetKind, +{ + pulley_target: PhantomData

, + triple: Triple, + flags: Flags, + isa_flags: PulleyFlags, +} + +impl

core::fmt::Debug for PulleyBackend

+where + P: PulleyTargetKind, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let PulleyBackend { + pulley_target: _, + triple, + flags: _, + isa_flags: _, + } = self; + f.debug_struct("PulleyBackend") + .field("triple", triple) + .finish_non_exhaustive() + } +} + +impl

core::fmt::Display for PulleyBackend

+where + P: PulleyTargetKind, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(self, f) + } +} + +impl

PulleyBackend

+where + P: PulleyTargetKind, +{ + /// Create a new pulley backend with the given (shared) flags. + pub fn new_with_flags( + triple: Triple, + flags: shared_settings::Flags, + isa_flags: PulleyFlags, + ) -> Self { + PulleyBackend { + pulley_target: PhantomData, + triple, + flags, + isa_flags, + } + } + + /// This performs lowering to VCode, register-allocates the code, computes block layout and + /// finalizes branches. The result is ready for binary emission. + fn compile_vcode( + &self, + func: &ir::Function, + domtree: &DominatorTree, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<(VCode>, regalloc2::Output)> { + let emit_info = EmitInfo::new(self.flags.clone(), self.isa_flags.clone()); + let sigs = SigSet::new::>(func, &self.flags)?; + let abi = abi::PulleyCallee::new(func, self, &self.isa_flags, &sigs)?; + machinst::compile::(func, domtree, self, abi, emit_info, sigs, ctrl_plane) + } +} + +impl

TargetIsa for PulleyBackend

+where + P: PulleyTargetKind, +{ + fn name(&self) -> &'static str { + P::name() + } + + fn triple(&self) -> &Triple { + &self.triple + } + + fn flags(&self) -> &Flags { + &self.flags + } + + fn isa_flags(&self) -> Vec { + self.isa_flags.iter().collect() + } + + fn dynamic_vector_bytes(&self, _dynamic_ty: ir::Type) -> u32 { + 512 + } + + fn page_size_align_log2(&self) -> u8 { + // Claim 64KiB pages to be conservative. + 16 + } + + fn compile_function( + &self, + func: &ir::Function, + domtree: &DominatorTree, + want_disasm: bool, + ctrl_plane: &mut cranelift_control::ControlPlane, + ) -> CodegenResult { + let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; + + let want_disasm = + want_disasm || (cfg!(feature = "trace-log") && log::log_enabled!(log::Level::Debug)); + let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane); + let frame_size = emit_result.frame_size; + let value_labels_ranges = emit_result.value_labels_ranges; + let buffer = emit_result.buffer; + let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; + let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; + + if let Some(disasm) = emit_result.disasm.as_ref() { + log::debug!("disassembly:\n{}", disasm); + } + + Ok(CompiledCodeStencil { + buffer, + frame_size, + vcode: emit_result.disasm, + value_labels_ranges, + sized_stackslot_offsets, + dynamic_stackslot_offsets, + bb_starts: emit_result.bb_offsets, + bb_edges: emit_result.bb_edges, + }) + } + + fn emit_unwind_info( + &self, + _result: &crate::CompiledCode, + _kind: super::unwind::UnwindInfoKind, + ) -> CodegenResult> { + // TODO: actually support unwind info? + Ok(None) + } + + fn text_section_builder( + &self, + num_labeled_funcs: usize, + ) -> alloc::boxed::Box { + Box::new(MachTextSectionBuilder::>::new( + num_labeled_funcs, + )) + } + + fn function_alignment(&self) -> FunctionAlignment { + inst::InstAndKind::

{ + let pos = self.pos(); + let name = self.parse_ident()?; + let signatures = self.parse_signatures()?; + Ok(Form { + name, + signatures, + pos, + }) + } + + fn parse_signatures(&mut self) -> Result> { + let mut signatures = vec![]; + while !self.is_rparen() { + signatures.push(self.parse_signature()?); + } + Ok(signatures) + } + + fn parse_signature(&mut self) -> Result { + self.expect_lparen()?; + let pos = self.pos(); + let args = self.parse_tagged_types("args")?; + let ret = self.parse_tagged_type("ret")?; + let canonical = self.parse_tagged_type("canon")?; + self.expect_rparen()?; + Ok(Signature { + args, + ret, + canonical, + pos, + }) + } + + fn parse_tagged_types(&mut self, tag: &str) -> Result> { + self.expect_lparen()?; + let pos = self.pos(); + if !self.eat_sym_str(tag)? { + return Err(self.error(pos, format!("Invalid {tag}: expected ({tag} ...)"))); + }; + let mut params = vec![]; + while !self.is_rparen() { + params.push(self.parse_model_type()?); + } + self.expect_rparen()?; + Ok(params) + } + + fn parse_tagged_type(&mut self, tag: &str) -> Result { + self.expect_lparen()?; + let pos = self.pos(); + if !self.eat_sym_str(tag)? { + return Err(self.error(pos, format!("Invalid {tag}: expected ({tag} )"))); + }; + let ty = self.parse_model_type()?; + self.expect_rparen()?; + Ok(ty) + } + + fn parse_instantiation(&mut self) -> Result { + let pos = self.pos(); + let term = self.parse_ident()?; + // Instantiation either has an explicit signatures list, which would + // open with a left paren. Or it has an identifier referencing a + // predefined set of signatures. + if self.is_lparen() { + let signatures = self.parse_signatures()?; + Ok(Instantiation { + term, + form: None, + signatures, + pos, + }) + } else { + let form = self.parse_ident()?; + Ok(Instantiation { + term, + form: Some(form), + signatures: vec![], + pos, + }) + } + } + + fn parse_extern(&mut self) -> Result { + let pos = self.pos(); + if self.eat_sym_str("constructor")? { + let term = self.parse_ident()?; + let func = self.parse_ident()?; + Ok(Extern::Constructor { term, func, pos }) + } else if self.eat_sym_str("extractor")? { + let infallible = self.eat_sym_str("infallible")?; + + let term = self.parse_ident()?; + let func = self.parse_ident()?; + + Ok(Extern::Extractor { + term, + func, + pos, + infallible, + }) + } else if self.eat_sym_str("const")? { + let pos = self.pos(); + let name = self.parse_const()?; + let ty = self.parse_ident()?; + Ok(Extern::Const { name, ty, pos }) + } else { + Err(self.error( + pos, + "Invalid extern: must be (extern constructor ...), (extern extractor ...) or (extern const ...)" + .to_string(), + )) + } + } + + fn parse_etor(&mut self) -> Result { + let pos = self.pos(); + self.expect_lparen()?; + let term = self.parse_ident()?; + let mut args = vec![]; + while !self.is_rparen() { + args.push(self.parse_ident()?); + } + self.expect_rparen()?; + let template = self.parse_pattern()?; + Ok(Extractor { + term, + args, + template, + pos, + }) + } + + fn parse_rule(&mut self) -> Result { + let pos = self.pos(); + let name = if self.is_sym() { + Some( + self.parse_ident() + .map_err(|err| self.error(pos, format!("Invalid rule name: {err:?}")))?, + ) + } else { + None + }; + let prio = if self.is_int() { + Some( + i64::try_from(self.expect_int()?) + .map_err(|err| self.error(pos, format!("Invalid rule priority: {err}")))?, + ) + } else { + None + }; + let pattern = self.parse_pattern()?; + let mut iflets = vec![]; + loop { + match self.parse_iflet_or_expr()? { + IfLetOrExpr::IfLet(iflet) => { + iflets.push(iflet); + } + IfLetOrExpr::Expr(expr) => { + return Ok(Rule { + pattern, + iflets, + expr, + pos, + prio, + name, + }); + } + } + } + } + + fn parse_pattern(&mut self) -> Result { + let pos = self.pos(); + if self.is_int() { + Ok(Pattern::ConstInt { + val: self.expect_int()?, + pos, + }) + } else if self.is_const() { + let val = self.parse_const()?; + Ok(Pattern::ConstPrim { val, pos }) + } else if self.eat_sym_str("_")? { + Ok(Pattern::Wildcard { pos }) + } else if self.eat_sym_str("true")? { + Ok(Pattern::ConstBool { val: true, pos }) + } else if self.eat_sym_str("false")? { + Ok(Pattern::ConstBool { val: false, pos }) + } else if self.is_sym() { + let var = self.parse_ident()?; + if self.is_at() { + self.expect_at()?; + let subpat = Box::new(self.parse_pattern()?); + Ok(Pattern::BindPattern { var, subpat, pos }) + } else { + Ok(Pattern::Var { var, pos }) + } + } else if self.is_lparen() { + self.expect_lparen()?; + if self.eat_sym_str("and")? { + let mut subpats = vec![]; + while !self.is_rparen() { + subpats.push(self.parse_pattern()?); + } + self.expect_rparen()?; + Ok(Pattern::And { subpats, pos }) + } else { + let sym = self.parse_ident()?; + let mut args = vec![]; + while !self.is_rparen() { + args.push(self.parse_pattern()?); + } + self.expect_rparen()?; + Ok(Pattern::Term { sym, args, pos }) + } + } else { + Err(self.error(pos, "Unexpected pattern".into())) + } + } + + fn parse_iflet_or_expr(&mut self) -> Result { + let pos = self.pos(); + if self.is_lparen() { + self.expect_lparen()?; + let ret = if self.eat_sym_str("if-let")? { + IfLetOrExpr::IfLet(self.parse_iflet()?) + } else if self.eat_sym_str("if")? { + // Shorthand form: `(if (x))` desugars to `(if-let _ + // (x))`. + IfLetOrExpr::IfLet(self.parse_iflet_if()?) + } else { + IfLetOrExpr::Expr(self.parse_expr_inner_parens(pos)?) + }; + self.expect_rparen()?; + Ok(ret) + } else { + self.parse_expr().map(IfLetOrExpr::Expr) + } + } + + fn parse_iflet(&mut self) -> Result { + let pos = self.pos(); + let pattern = self.parse_pattern()?; + let expr = self.parse_expr()?; + Ok(IfLet { pattern, expr, pos }) + } + + fn parse_iflet_if(&mut self) -> Result { + let pos = self.pos(); + let expr = self.parse_expr()?; + Ok(IfLet { + pattern: Pattern::Wildcard { pos }, + expr, + pos, + }) + } + + fn parse_expr(&mut self) -> Result { + let pos = self.pos(); + if self.is_lparen() { + self.expect_lparen()?; + let ret = self.parse_expr_inner_parens(pos)?; + self.expect_rparen()?; + Ok(ret) + } else if self.is_const() { + let val = self.parse_const()?; + Ok(Expr::ConstPrim { val, pos }) + } else if self.eat_sym_str("true")? { + Ok(Expr::ConstBool { val: true, pos }) + } else if self.eat_sym_str("false")? { + Ok(Expr::ConstBool { val: false, pos }) + } else if self.is_sym() { + let name = self.parse_ident()?; + Ok(Expr::Var { name, pos }) + } else if self.is_int() { + let val = self.expect_int()?; + Ok(Expr::ConstInt { val, pos }) + } else { + Err(self.error(pos, "Invalid expression".into())) + } + } + + fn parse_expr_inner_parens(&mut self, pos: Pos) -> Result { + if self.eat_sym_str("let")? { + self.expect_lparen()?; + let mut defs = vec![]; + while !self.is_rparen() { + let def = self.parse_letdef()?; + defs.push(def); + } + self.expect_rparen()?; + let body = Box::new(self.parse_expr()?); + Ok(Expr::Let { defs, body, pos }) + } else { + let sym = self.parse_ident()?; + let mut args = vec![]; + while !self.is_rparen() { + args.push(self.parse_expr()?); + } + Ok(Expr::Term { sym, args, pos }) + } + } + + fn parse_letdef(&mut self) -> Result { + let pos = self.pos(); + self.expect_lparen()?; + let var = self.parse_ident()?; + let ty = self.parse_ident()?; + let val = Box::new(self.parse_expr()?); + self.expect_rparen()?; + Ok(LetDef { var, ty, val, pos }) + } + + fn parse_converter(&mut self) -> Result { + let pos = self.pos(); + let inner_ty = self.parse_ident()?; + let outer_ty = self.parse_ident()?; + let term = self.parse_ident()?; + Ok(Converter { + term, + inner_ty, + outer_ty, + pos, + }) + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/sema.rs b/deps/crates/vendor/cranelift-isle/src/sema.rs new file mode 100644 index 00000000000000..0e8f27780a308d --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/sema.rs @@ -0,0 +1,2734 @@ +//! Semantic analysis. +//! +//! This module primarily contains the type environment and term environment. +//! +//! The type environment is constructed by analyzing an input AST. The type +//! environment records the types used in the input source and the types of our +//! various rules and symbols. ISLE's type system is intentionally easy to +//! check, only requires a single pass over the AST, and doesn't require any +//! unification or anything like that. +//! +//! The term environment is constructed from both the AST and type +//! environment. It is sort of a typed and reorganized AST that more directly +//! reflects ISLE semantics than the input ISLE source code (where as the AST is +//! the opposite). + +use crate::ast; +use crate::error::*; +use crate::lexer::Pos; +use crate::log; +use crate::stablemapset::{StableMap, StableSet}; +use std::collections::hash_map::Entry; +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::fmt; + +declare_id!( + /// The id of an interned symbol. + Sym +); +declare_id!( + /// The id of an interned type inside the `TypeEnv`. + TypeId +); +declare_id!( + /// The id of a variant inside an enum. + VariantId +); +declare_id!( + /// The id of a field inside a variant. + FieldId +); +declare_id!( + /// The id of an interned term inside the `TermEnv`. + TermId +); +declare_id!( + /// The id of an interned rule inside the `TermEnv`. + RuleId +); +declare_id!( + /// The id of a bound variable inside a `Bindings`. + VarId +); + +/// The type environment. +/// +/// Keeps track of which symbols and rules have which types. +#[derive(Debug)] +pub struct TypeEnv { + /// Arena of interned symbol names. + /// + /// Referred to indirectly via `Sym` indices. + pub syms: Vec, + + /// Map of already-interned symbol names to their `Sym` ids. + pub sym_map: StableMap, + + /// Arena of type definitions. + /// + /// Referred to indirectly via `TypeId`s. + pub types: Vec, + + /// A map from a type name symbol to its `TypeId`. + pub type_map: StableMap, + + /// The types of constant symbols. + pub const_types: StableMap, + + /// Type errors that we've found so far during type checking. + pub errors: Vec, +} + +/// A built-in type. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum BuiltinType { + /// The type of booleans, with values `true` and `false`. + Bool, + /// The types of fixed-width integers. + Int(IntType), +} + +/// A built-in fixed-width integer type. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum IntType { + /// Unsigned, 8 bits. + U8, + /// Unsigned, 16 bits. + U16, + /// Unsigned, 32 bits. + U32, + /// Unsigned, 64 bits. + U64, + /// Unsigned, 128 bits. + U128, + /// Unsigned, enough bits to hold a pointer. + USize, + /// Signed, 8 bits. + I8, + /// Signed, 16 bits. + I16, + /// Signed, 32 bits. + I32, + /// Signed, 64 bits. + I64, + /// Signed, 128 bits. + I128, + /// Unsigned, enough bits to hold a pointer. + ISize, +} + +impl IntType { + /// Get the integer type's name. + pub fn name(&self) -> &'static str { + match self { + IntType::U8 => "u8", + IntType::U16 => "u16", + IntType::U32 => "u32", + IntType::U64 => "u64", + IntType::U128 => "u128", + IntType::USize => "usize", + IntType::I8 => "i8", + IntType::I16 => "i16", + IntType::I32 => "i32", + IntType::I64 => "i64", + IntType::I128 => "i128", + IntType::ISize => "isize", + } + } + + /// Is this integer type signed? + pub fn is_signed(&self) -> bool { + match self { + IntType::U8 + | IntType::U16 + | IntType::U32 + | IntType::U64 + | IntType::U128 + | IntType::USize => false, + + IntType::I8 + | IntType::I16 + | IntType::I32 + | IntType::I64 + | IntType::I128 + | IntType::ISize => true, + } + } +} + +impl fmt::Display for IntType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl BuiltinType { + /// All the built-in types. + pub const ALL: &'static [Self] = &[ + Self::Bool, + Self::Int(IntType::U8), + Self::Int(IntType::U16), + Self::Int(IntType::U32), + Self::Int(IntType::U64), + Self::Int(IntType::U128), + Self::Int(IntType::USize), + Self::Int(IntType::I8), + Self::Int(IntType::I16), + Self::Int(IntType::I32), + Self::Int(IntType::I64), + Self::Int(IntType::I128), + Self::Int(IntType::ISize), + ]; + + /// Get the built-in type's name. + pub fn name(&self) -> &'static str { + match self { + BuiltinType::Bool => "bool", + BuiltinType::Int(it) => it.name(), + } + } + + const fn to_usize(&self) -> usize { + match self { + Self::Bool => 0, + Self::Int(ty) => *ty as usize + 1, + } + } +} + +impl TypeId { + const fn builtin(builtin: BuiltinType) -> Self { + Self(builtin.to_usize()) + } + + /// TypeId for `bool`. + pub const BOOL: Self = Self::builtin(BuiltinType::Bool); + + /// TypeId for `u8`. + pub const U8: Self = Self::builtin(BuiltinType::Int(IntType::U8)); + /// TypeId for `u16`. + pub const U16: Self = Self::builtin(BuiltinType::Int(IntType::U16)); + /// TypeId for `u32`. + pub const U32: Self = Self::builtin(BuiltinType::Int(IntType::U32)); + /// TypeId for `u64`. + pub const U64: Self = Self::builtin(BuiltinType::Int(IntType::U64)); + /// TypeId for `u128`. + pub const U128: Self = Self::builtin(BuiltinType::Int(IntType::U128)); + /// TypeId for `usize`. + pub const USIZE: Self = Self::builtin(BuiltinType::Int(IntType::USize)); + + /// TypeId for `i8`. + pub const I8: Self = Self::builtin(BuiltinType::Int(IntType::I8)); + /// TypeId for `i16`. + pub const I16: Self = Self::builtin(BuiltinType::Int(IntType::I16)); + /// TypeId for `i32`. + pub const I32: Self = Self::builtin(BuiltinType::Int(IntType::I32)); + /// TypeId for `i64`. + pub const I64: Self = Self::builtin(BuiltinType::Int(IntType::I64)); + /// TypeId for `i128`. + pub const I128: Self = Self::builtin(BuiltinType::Int(IntType::I128)); + /// TypeId for `isize`. + pub const ISIZE: Self = Self::builtin(BuiltinType::Int(IntType::ISize)); +} + +/// A type. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Type { + /// Built-in types. Always in scope, not defined anywhere in source. + Builtin(BuiltinType), + + /// A primitive, `Copy` type. + /// + /// These are always defined externally, and we allow literals of these + /// types to pass through from ISLE source code to the emitted Rust code. + Primitive(TypeId, Sym, Pos), + + /// A sum type. + /// + /// Note that enums with only one variant are equivalent to a "struct". + Enum { + /// The name of this enum. + name: Sym, + /// This `enum`'s type id. + id: TypeId, + /// Is this `enum` defined in external Rust code? + /// + /// If so, ISLE will not emit a definition for it. If not, then it will + /// emit a Rust definition for it. + is_extern: bool, + /// Whether this type should *not* derive `Debug`. + /// + /// Incompatible with `is_extern`. + is_nodebug: bool, + /// The different variants for this enum. + variants: Vec, + /// The ISLE source position where this `enum` is defined. + pos: Pos, + }, +} + +impl Type { + /// Get the name of this `Type`. + pub fn name<'a>(&self, tyenv: &'a TypeEnv) -> &'a str { + match self { + Self::Builtin(ty) => ty.name(), + Self::Primitive(_, name, _) | Self::Enum { name, .. } => &tyenv.syms[name.index()], + } + } + + /// Get the position where this type was defined. + pub fn pos(&self) -> Option { + match self { + Self::Builtin(..) => None, + Self::Primitive(_, _, pos) | Self::Enum { pos, .. } => Some(*pos), + } + } + + /// Is this a primitive type? + pub fn is_prim(&self) -> bool { + matches!(self, Type::Primitive(..)) + } + + /// Is this a built-in integer type? + pub fn is_int(&self) -> bool { + matches!(self, Self::Builtin(BuiltinType::Int(_))) + } +} + +/// A variant of an enum. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Variant { + /// The name of this variant. + pub name: Sym, + + /// The full, prefixed-with-the-enum's-name name of this variant. + /// + /// E.g. if the enum is `Foo` and this variant is `Bar`, then the + /// `fullname` is `Foo.Bar`. + pub fullname: Sym, + + /// The id of this variant, i.e. the index of this variant within its + /// enum's `Type::Enum::variants`. + pub id: VariantId, + + /// The data fields of this enum variant. + pub fields: Vec, +} + +/// A field of a `Variant`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Field { + /// The name of this field. + pub name: Sym, + /// This field's id. + pub id: FieldId, + /// The type of this field. + pub ty: TypeId, +} + +/// The term environment. +/// +/// This is sort of a typed and reorganized AST that more directly reflects ISLE +/// semantics than the input ISLE source code (where as the AST is the +/// opposite). +#[derive(Clone, Debug)] +pub struct TermEnv { + /// Arena of interned terms defined in this ISLE program. + /// + /// This is indexed by `TermId`. + pub terms: Vec, + + /// A map from am interned `Term`'s name to its `TermId`. + pub term_map: StableMap, + + /// Arena of interned rules defined in this ISLE program. + /// + /// This is indexed by `RuleId`. + pub rules: Vec, + + /// Map from (inner_ty, outer_ty) pairs to term IDs, giving the + /// defined implicit type-converter terms we can try to use to fit + /// types together. + pub converters: StableMap<(TypeId, TypeId), TermId>, + + /// Flag for whether to expand internal extractors in the + /// translation from the AST to sema. + pub expand_internal_extractors: bool, +} + +/// A term. +/// +/// Maps parameter types to result types if this is a constructor term, or +/// result types to parameter types if this is an extractor term. Or both if +/// this term can be either a constructor or an extractor. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Term { + /// This term's id. + pub id: TermId, + /// The source position where this term was declared. + pub decl_pos: Pos, + /// The name of this term. + pub name: Sym, + /// The parameter types to this term. + pub arg_tys: Vec, + /// The result types of this term. + pub ret_ty: TypeId, + /// The kind of this term. + pub kind: TermKind, +} + +/// Flags from a term's declaration with `(decl ...)`. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TermFlags { + /// Whether the term is marked as `pure`. + pub pure: bool, + /// Whether the term is marked as `multi`. + pub multi: bool, + /// Whether the term is marked as `partial`. + pub partial: bool, +} + +impl TermFlags { + /// Return a new `TermFlags` suitable for a term on the LHS of a rule. + pub fn on_lhs(mut self) -> Self { + self.pure = true; + self.partial = true; + self + } +} + +/// The kind of a term. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum TermKind { + /// An enum variant constructor or extractor. + EnumVariant { + /// Which variant of the enum: e.g. for enum type `A` if a term is + /// `(A.A1 ...)` then the variant ID corresponds to `A1`. + variant: VariantId, + }, + /// A term declared via a `(decl ...)` form. + Decl { + /// Flags from the term's declaration. + flags: TermFlags, + /// The kind of this term's constructor, if any. + constructor_kind: Option, + /// The kind of this term's extractor, if any. + extractor_kind: Option, + }, +} + +/// The kind of a constructor for a term. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ConstructorKind { + /// A term with "internal" rules that work in the forward direction. Becomes + /// a compiled Rust function in the generated code. + InternalConstructor, + /// A term defined solely by an external constructor function. + ExternalConstructor { + /// The external name of the constructor function. + name: Sym, + }, +} + +/// The kind of an extractor for a term. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ExtractorKind { + /// A term that defines an "extractor macro" in the LHS of a pattern. Its + /// arguments take patterns and are simply substituted with the given + /// patterns when used. + InternalExtractor { + /// This extractor's pattern. + template: ast::Pattern, + }, + /// A term defined solely by an external extractor function. + ExternalExtractor { + /// The external name of the extractor function. + name: Sym, + /// Is the external extractor infallible? + infallible: bool, + /// The position where this external extractor was declared. + pos: Pos, + }, +} + +/// How many values a function can return. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ReturnKind { + /// Exactly one return value. + Plain, + /// Zero or one return values. + Option, + /// Zero or more return values. + Iterator, +} + +/// An external function signature. +#[derive(Clone, Debug)] +pub struct ExternalSig { + /// The name of the external function. + pub func_name: String, + /// The name of the external function, prefixed with the context trait. + pub full_name: String, + /// The types of this function signature's parameters. + pub param_tys: Vec, + /// The types of this function signature's results. + pub ret_tys: Vec, + /// How many values can this function return? + pub ret_kind: ReturnKind, +} + +impl Term { + /// Get this term's type. + pub fn ty(&self) -> TypeId { + self.ret_ty + } + + fn check_args_count(&self, args: &[T], tyenv: &mut TypeEnv, pos: Pos, sym: &ast::Ident) { + if self.arg_tys.len() != args.len() { + tyenv.report_error( + pos, + format!( + "Incorrect argument count for term '{}': got {}, expect {}", + sym.0, + args.len(), + self.arg_tys.len() + ), + ); + } + } + + /// Is this term an enum variant? + pub fn is_enum_variant(&self) -> bool { + matches!(self.kind, TermKind::EnumVariant { .. }) + } + + /// Is this term partial? + pub fn is_partial(&self) -> bool { + matches!( + self.kind, + TermKind::Decl { + flags: TermFlags { partial: true, .. }, + .. + } + ) + } + + /// Does this term have a constructor? + pub fn has_constructor(&self) -> bool { + matches!( + self.kind, + TermKind::EnumVariant { .. } + | TermKind::Decl { + constructor_kind: Some(_), + .. + } + ) + } + + /// Does this term have an extractor? + pub fn has_extractor(&self) -> bool { + matches!( + self.kind, + TermKind::EnumVariant { .. } + | TermKind::Decl { + extractor_kind: Some(_), + .. + } + ) + } + + /// Is this term's extractor external? + pub fn has_external_extractor(&self) -> bool { + matches!( + self.kind, + TermKind::Decl { + extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }), + .. + } + ) + } + + /// Is this term's constructor external? + pub fn has_external_constructor(&self) -> bool { + matches!( + self.kind, + TermKind::Decl { + constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }), + .. + } + ) + } + + /// Get this term's extractor's external function signature, if any. + pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option { + match &self.kind { + TermKind::Decl { + flags, + extractor_kind: + Some(ExtractorKind::ExternalExtractor { + name, infallible, .. + }), + .. + } => { + let ret_kind = if flags.multi { + ReturnKind::Iterator + } else if *infallible { + ReturnKind::Plain + } else { + ReturnKind::Option + }; + Some(ExternalSig { + func_name: tyenv.syms[name.index()].clone(), + full_name: format!("C::{}", tyenv.syms[name.index()]), + param_tys: vec![self.ret_ty], + ret_tys: self.arg_tys.clone(), + ret_kind, + }) + } + _ => None, + } + } + + /// Get this term's constructor's external function signature, if any. + pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option { + match &self.kind { + TermKind::Decl { + constructor_kind: Some(kind), + flags, + .. + } => { + let (func_name, full_name) = match kind { + ConstructorKind::InternalConstructor => { + let name = format!("constructor_{}", tyenv.syms[self.name.index()]); + (name.clone(), name) + } + ConstructorKind::ExternalConstructor { name } => ( + tyenv.syms[name.index()].clone(), + format!("C::{}", tyenv.syms[name.index()]), + ), + }; + let ret_kind = if flags.multi { + ReturnKind::Iterator + } else if flags.partial { + ReturnKind::Option + } else { + ReturnKind::Plain + }; + Some(ExternalSig { + func_name, + full_name, + param_tys: self.arg_tys.clone(), + ret_tys: vec![self.ret_ty], + ret_kind, + }) + } + _ => None, + } + } +} + +/// A term rewrite rule. +#[derive(Clone, Debug)] +pub struct Rule { + /// This rule's id. + pub id: RuleId, + /// The left-hand side pattern that this rule matches. + pub root_term: TermId, + /// Patterns to test against the root term's arguments. + pub args: Vec, + /// Any subpattern "if-let" clauses. + pub iflets: Vec, + /// The right-hand side expression that this rule evaluates upon successful + /// match. + pub rhs: Expr, + /// Variable names used in this rule, indexed by [VarId]. + pub vars: Vec, + /// The priority of this rule, defaulted to 0 if it was missing in the source. + pub prio: i64, + /// The source position where this rule is defined. + pub pos: Pos, + /// The optional name for this rule. + pub name: Option, +} + +/// A name bound in a pattern or let-expression. +#[derive(Clone, Debug)] +pub struct BoundVar { + /// The identifier used for this variable within the scope of the current [Rule]. + pub id: VarId, + /// The variable's name. + pub name: Sym, + /// The type of the value this variable is bound to. + pub ty: TypeId, + /// A counter used to check whether this variable is still in scope during + /// semantic analysis. Not meaningful afterward. + scope: usize, +} + +/// An `if-let` clause with a subpattern match on an expr after the +/// main LHS matches. +#[derive(Clone, Debug)] +pub struct IfLet { + /// The left-hand side pattern that this `if-let` clause matches + /// against the expression below. + pub lhs: Pattern, + /// The right-hand side expression that this pattern + /// evaluates. Must be pure. + pub rhs: Expr, +} + +/// A left-hand side pattern of some rule. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Pattern { + /// Bind a variable of the given type from the current value. + /// + /// Keep matching on the value with the subpattern. + BindPattern(TypeId, VarId, Box), + + /// Match the current value against an already bound variable with the given + /// type. + Var(TypeId, VarId), + + /// Match the current value against a constant boolean. + ConstBool(TypeId, bool), + + /// Match the current value against a constant integer of the given integer + /// type. + ConstInt(TypeId, i128), + + /// Match the current value against a constant primitive value of the given + /// primitive type. + ConstPrim(TypeId, Sym), + + /// Match the current value against the given extractor term with the given + /// arguments. + Term(TypeId, TermId, Vec), + + /// Match anything of the given type successfully. + Wildcard(TypeId), + + /// Match all of the following patterns of the given type. + And(TypeId, Vec), +} + +/// A right-hand side expression of some rule. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Expr { + /// Invoke this term constructor with the given arguments. + Term(TypeId, TermId, Vec), + /// Get the value of a variable that was bound in the left-hand side. + Var(TypeId, VarId), + /// Get a constant boolean. + ConstBool(TypeId, bool), + /// Get a constant integer. + ConstInt(TypeId, i128), + /// Get a constant primitive. + ConstPrim(TypeId, Sym), + /// Evaluate the nested expressions and bind their results to the given + /// variables, then evaluate the body expression. + Let { + /// The type of the result of this let expression. + ty: TypeId, + /// The expressions that are evaluated and bound to the given variables. + bindings: Vec<(VarId, TypeId, Box)>, + /// The body expression that is evaluated after the bindings. + body: Box, + }, +} + +/// Visitor interface for [Pattern]s. Visitors can assign an arbitrary identifier to each +/// subpattern, which is threaded through to subsequent calls into the visitor. +pub trait PatternVisitor { + /// The type of subpattern identifiers. + type PatternId: Copy; + + /// Match if `a` and `b` have equal values. + fn add_match_equal(&mut self, a: Self::PatternId, b: Self::PatternId, ty: TypeId); + /// Match if `input` is the given boolean constant. + fn add_match_bool(&mut self, input: Self::PatternId, ty: TypeId, bool_val: bool); + /// Match if `input` is the given integer constant. + fn add_match_int(&mut self, input: Self::PatternId, ty: TypeId, int_val: i128); + /// Match if `input` is the given primitive constant. + fn add_match_prim(&mut self, input: Self::PatternId, ty: TypeId, val: Sym); + + /// Match if `input` is the given enum variant. Returns an identifier for each field within the + /// enum variant. The length of the return list must equal the length of `arg_tys`. + fn add_match_variant( + &mut self, + input: Self::PatternId, + input_ty: TypeId, + arg_tys: &[TypeId], + variant: VariantId, + ) -> Vec; + + /// Match if the given external extractor succeeds on `input`. Returns an identifier for each + /// return value from the external extractor. The length of the return list must equal the + /// length of `output_tys`. + fn add_extract( + &mut self, + input: Self::PatternId, + input_ty: TypeId, + output_tys: Vec, + term: TermId, + infallible: bool, + multi: bool, + ) -> Vec; +} + +impl Pattern { + /// Get this pattern's type. + pub fn ty(&self) -> TypeId { + match *self { + Self::BindPattern(t, ..) => t, + Self::Var(t, ..) => t, + Self::ConstBool(t, ..) => t, + Self::ConstInt(t, ..) => t, + Self::ConstPrim(t, ..) => t, + Self::Term(t, ..) => t, + Self::Wildcard(t, ..) => t, + Self::And(t, ..) => t, + } + } + + /// Recursively visit every sub-pattern. + pub fn visit( + &self, + visitor: &mut V, + input: V::PatternId, + termenv: &TermEnv, + vars: &mut HashMap, + ) { + match *self { + Pattern::BindPattern(_ty, var, ref subpat) => { + // Bind the appropriate variable and recurse. + assert!(!vars.contains_key(&var)); + vars.insert(var, input); + subpat.visit(visitor, input, termenv, vars); + } + Pattern::Var(ty, var) => { + // Assert that the value matches the existing bound var. + let var_val = vars + .get(&var) + .copied() + .expect("Variable should already be bound"); + visitor.add_match_equal(input, var_val, ty); + } + Pattern::ConstBool(ty, value) => visitor.add_match_bool(input, ty, value), + Pattern::ConstInt(ty, value) => visitor.add_match_int(input, ty, value), + Pattern::ConstPrim(ty, value) => visitor.add_match_prim(input, ty, value), + Pattern::Term(ty, term, ref args) => { + // Determine whether the term has an external extractor or not. + let termdata = &termenv.terms[term.index()]; + let arg_values = match &termdata.kind { + TermKind::EnumVariant { variant } => { + visitor.add_match_variant(input, ty, &termdata.arg_tys, *variant) + } + TermKind::Decl { + extractor_kind: None, + .. + } => { + panic!("Pattern invocation of undefined term body") + } + TermKind::Decl { + extractor_kind: Some(ExtractorKind::InternalExtractor { .. }), + .. + } => { + panic!("Should have been expanded away") + } + TermKind::Decl { + flags, + extractor_kind: Some(ExtractorKind::ExternalExtractor { infallible, .. }), + .. + } => { + // Evaluate all `input` args. + let output_tys = args.iter().map(|arg| arg.ty()).collect(); + + // Invoke the extractor. + visitor.add_extract( + input, + termdata.ret_ty, + output_tys, + term, + *infallible && !flags.multi, + flags.multi, + ) + } + }; + for (pat, val) in args.iter().zip(arg_values) { + pat.visit(visitor, val, termenv, vars); + } + } + Pattern::And(_ty, ref children) => { + for child in children { + child.visit(visitor, input, termenv, vars); + } + } + Pattern::Wildcard(_ty) => { + // Nothing! + } + } + } +} + +/// Visitor interface for [Expr]s. Visitors can return an arbitrary identifier for each +/// subexpression, which is threaded through to subsequent calls into the visitor. +pub trait ExprVisitor { + /// The type of subexpression identifiers. + type ExprId: Copy; + + /// Construct a constant boolean. + fn add_const_bool(&mut self, ty: TypeId, val: bool) -> Self::ExprId; + /// Construct a constant integer. + fn add_const_int(&mut self, ty: TypeId, val: i128) -> Self::ExprId; + /// Construct a primitive constant. + fn add_const_prim(&mut self, ty: TypeId, val: Sym) -> Self::ExprId; + + /// Construct an enum variant with the given `inputs` assigned to the variant's fields in order. + fn add_create_variant( + &mut self, + inputs: Vec<(Self::ExprId, TypeId)>, + ty: TypeId, + variant: VariantId, + ) -> Self::ExprId; + + /// Call an external constructor with the given `inputs` as arguments. + fn add_construct( + &mut self, + inputs: Vec<(Self::ExprId, TypeId)>, + ty: TypeId, + term: TermId, + pure: bool, + infallible: bool, + multi: bool, + ) -> Self::ExprId; +} + +impl Expr { + /// Get this expression's type. + pub fn ty(&self) -> TypeId { + match *self { + Self::Term(t, ..) => t, + Self::Var(t, ..) => t, + Self::ConstBool(t, ..) => t, + Self::ConstInt(t, ..) => t, + Self::ConstPrim(t, ..) => t, + Self::Let { ty: t, .. } => t, + } + } + + /// Recursively visit every subexpression. + pub fn visit( + &self, + visitor: &mut V, + termenv: &TermEnv, + vars: &HashMap, + ) -> V::ExprId { + log!("Expr::visit: expr {:?}", self); + match *self { + Expr::ConstBool(ty, val) => visitor.add_const_bool(ty, val), + Expr::ConstInt(ty, val) => visitor.add_const_int(ty, val), + Expr::ConstPrim(ty, val) => visitor.add_const_prim(ty, val), + Expr::Let { + ty: _ty, + ref bindings, + ref body, + } => { + let mut vars = vars.clone(); + for &(var, _var_ty, ref var_expr) in bindings { + let var_value = var_expr.visit(visitor, termenv, &vars); + vars.insert(var, var_value); + } + body.visit(visitor, termenv, &vars) + } + Expr::Var(_ty, var_id) => *vars.get(&var_id).unwrap(), + Expr::Term(ty, term, ref arg_exprs) => { + let termdata = &termenv.terms[term.index()]; + let arg_values_tys = arg_exprs + .iter() + .map(|arg_expr| arg_expr.visit(visitor, termenv, vars)) + .zip(termdata.arg_tys.iter().copied()) + .collect(); + match &termdata.kind { + TermKind::EnumVariant { variant } => { + visitor.add_create_variant(arg_values_tys, ty, *variant) + } + TermKind::Decl { + constructor_kind: Some(_), + flags, + .. + } => { + visitor.add_construct( + arg_values_tys, + ty, + term, + flags.pure, + /* infallible = */ !flags.partial, + flags.multi, + ) + } + TermKind::Decl { + constructor_kind: None, + .. + } => panic!("Should have been caught by typechecking"), + } + } + } + } + + fn visit_in_rule( + &self, + visitor: &mut V, + termenv: &TermEnv, + vars: &HashMap::PatternId>, + ) -> V::Expr { + let var_exprs = vars + .iter() + .map(|(&var, &val)| (var, visitor.pattern_as_expr(val))) + .collect(); + visitor.add_expr(|visitor| VisitedExpr { + ty: self.ty(), + value: self.visit(visitor, termenv, &var_exprs), + }) + } +} + +/// Information about an expression after it has been fully visited in [RuleVisitor::add_expr]. +#[derive(Clone, Copy)] +pub struct VisitedExpr { + /// The type of the top-level expression. + pub ty: TypeId, + /// The identifier returned by the visitor for the top-level expression. + pub value: V::ExprId, +} + +/// Visitor interface for [Rule]s. Visitors must be able to visit patterns by implementing +/// [PatternVisitor], and to visit expressions by providing a type that implements [ExprVisitor]. +pub trait RuleVisitor { + /// The type of pattern visitors constructed by [RuleVisitor::add_pattern]. + type PatternVisitor: PatternVisitor; + /// The type of expression visitors constructed by [RuleVisitor::add_expr]. + type ExprVisitor: ExprVisitor; + /// The type returned from [RuleVisitor::add_expr], which may be exchanged for a subpattern + /// identifier using [RuleVisitor::expr_as_pattern]. + type Expr; + + /// Visit one of the arguments to the top-level pattern. + fn add_arg( + &mut self, + index: usize, + ty: TypeId, + ) -> ::PatternId; + + /// Visit a pattern, used once for the rule's left-hand side and once for each if-let. You can + /// determine which part of the rule the pattern comes from based on whether the `PatternId` + /// passed to the first call to this visitor came from `add_arg` or `expr_as_pattern`. + fn add_pattern(&mut self, visitor: F) + where + F: FnOnce(&mut Self::PatternVisitor); + + /// Visit an expression, used once for each if-let and once for the rule's right-hand side. + fn add_expr(&mut self, visitor: F) -> Self::Expr + where + F: FnOnce(&mut Self::ExprVisitor) -> VisitedExpr; + + /// Given an expression from [RuleVisitor::add_expr], return an identifier that can be used with + /// a pattern visitor in [RuleVisitor::add_pattern]. + fn expr_as_pattern( + &mut self, + expr: Self::Expr, + ) -> ::PatternId; + + /// Given an identifier from the pattern visitor, return an identifier that can be used with + /// the expression visitor. + fn pattern_as_expr( + &mut self, + pattern: ::PatternId, + ) -> ::ExprId; +} + +impl Rule { + /// Recursively visit every pattern and expression in this rule. Returns the [RuleVisitor::Expr] + /// that was returned from [RuleVisitor::add_expr] when that function was called on the rule's + /// right-hand side. + pub fn visit(&self, visitor: &mut V, termenv: &TermEnv) -> V::Expr { + let mut vars = HashMap::new(); + + // Visit the pattern, starting from the root input value. + let termdata = &termenv.terms[self.root_term.index()]; + for (i, (subpat, &arg_ty)) in self.args.iter().zip(termdata.arg_tys.iter()).enumerate() { + let value = visitor.add_arg(i, arg_ty); + visitor.add_pattern(|visitor| subpat.visit(visitor, value, termenv, &mut vars)); + } + + // Visit the `if-let` clauses, using `V::ExprVisitor` for the sub-exprs (right-hand sides). + for iflet in self.iflets.iter() { + let subexpr = iflet.rhs.visit_in_rule(visitor, termenv, &vars); + let value = visitor.expr_as_pattern(subexpr); + visitor.add_pattern(|visitor| iflet.lhs.visit(visitor, value, termenv, &mut vars)); + } + + // Visit the rule's right-hand side, making use of the bound variables from the pattern. + self.rhs.visit_in_rule(visitor, termenv, &vars) + } +} + +/// Given an `Option`, unwrap the inner `T` value, or `continue` if it is +/// `None`. +/// +/// Useful for when we encountered an error earlier in our analysis but kept +/// going to find more errors, and now we've run into some missing data that +/// would have been filled in if we didn't hit that original error, but we want +/// to keep going to find more errors. +macro_rules! unwrap_or_continue { + ($e:expr) => { + match $e { + Some(x) => x, + None => continue, + } + }; +} + +impl Default for TypeEnv { + fn default() -> Self { + Self { + syms: BuiltinType::ALL + .iter() + .map(|bt| String::from(bt.name())) + .collect(), + sym_map: BuiltinType::ALL + .iter() + .enumerate() + .map(|(idx, bt)| (String::from(bt.name()), Sym(idx))) + .collect(), + types: BuiltinType::ALL + .iter() + .map(|bt| Type::Builtin(*bt)) + .collect(), + type_map: BuiltinType::ALL + .iter() + .enumerate() + .map(|(idx, _)| (Sym(idx), TypeId(idx))) + .collect(), + const_types: StableMap::new(), + errors: vec![], + } + } +} + +impl TypeEnv { + /// Construct the type environment from the AST. + pub fn from_ast(defs: &[ast::Def]) -> Result> { + let mut tyenv = TypeEnv::default(); + + // Traverse defs, assigning type IDs to type names. We'll fill + // in types on a second pass. + for def in defs { + match def { + &ast::Def::Type(ref td) => { + let tid = TypeId(tyenv.type_map.len()); + let name = tyenv.intern_mut(&td.name); + + if let Some(existing) = tyenv.type_map.get(&name).copied() { + tyenv.report_error( + td.pos, + format!("Type with name '{}' defined more than once", td.name.0), + ); + let pos = unwrap_or_continue!(tyenv.types.get(existing.index())).pos(); + match pos { + Some(pos) => tyenv.report_error( + pos, + format!("Type with name '{}' already defined here", td.name.0), + ), + None => tyenv.report_error( + td.pos, + format!("Type with name '{}' is a built-in type", td.name.0), + ), + } + continue; + } + + tyenv.type_map.insert(name, tid); + } + _ => {} + } + } + + // Now lower AST nodes to type definitions, raising errors + // where typenames of fields are undefined or field names are + // duplicated. + for def in defs { + match def { + &ast::Def::Type(ref td) => { + let tid = tyenv.types.len(); + if let Some(ty) = tyenv.type_from_ast(TypeId(tid), td) { + tyenv.types.push(ty); + } + } + _ => {} + } + } + + // Now collect types for extern constants. + for def in defs { + if let &ast::Def::Extern(ast::Extern::Const { + ref name, + ref ty, + pos, + }) = def + { + let ty = match tyenv.get_type_by_name(ty) { + Some(ty) => ty, + None => { + tyenv.report_error(pos, "Unknown type for constant"); + continue; + } + }; + let name = tyenv.intern_mut(name); + tyenv.const_types.insert(name, ty); + } + } + + tyenv.return_errors()?; + + Ok(tyenv) + } + + fn return_errors(&mut self) -> Result<(), Vec> { + if self.errors.is_empty() { + Ok(()) + } else { + Err(std::mem::take(&mut self.errors)) + } + } + + fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> Option { + let name = self.intern(&ty.name).unwrap(); + match &ty.ty { + &ast::TypeValue::Primitive(ref id, ..) => { + if ty.is_nodebug { + self.report_error(ty.pos, "primitive types cannot be marked `nodebug`"); + return None; + } + if ty.is_extern { + self.report_error(ty.pos, "primitive types cannot be marked `extern`"); + return None; + } + Some(Type::Primitive(tid, self.intern_mut(id), ty.pos)) + } + &ast::TypeValue::Enum(ref ty_variants, ..) => { + if ty.is_extern && ty.is_nodebug { + self.report_error(ty.pos, "external types cannot be marked `nodebug`"); + return None; + } + + let mut variants = vec![]; + for variant in ty_variants { + let combined_ident = + ast::Ident(format!("{}.{}", ty.name.0, variant.name.0), variant.name.1); + let fullname = self.intern_mut(&combined_ident); + let name = self.intern_mut(&variant.name); + let id = VariantId(variants.len()); + if variants.iter().any(|v: &Variant| v.name == name) { + self.report_error( + variant.pos, + format!("Duplicate variant name in type: '{}'", variant.name.0), + ); + return None; + } + let mut fields = vec![]; + for field in &variant.fields { + let field_name = self.intern_mut(&field.name); + if fields.iter().any(|f: &Field| f.name == field_name) { + self.report_error( + field.pos, + format!( + "Duplicate field name '{}' in variant '{}' of type", + field.name.0, variant.name.0 + ), + ); + return None; + } + let field_tid = match self.get_type_by_name(&field.ty) { + Some(tid) => tid, + None => { + self.report_error( + field.ty.1, + format!( + "Unknown type '{}' for field '{}' in variant '{}'", + field.ty.0, field.name.0, variant.name.0 + ), + ); + return None; + } + }; + fields.push(Field { + name: field_name, + id: FieldId(fields.len()), + ty: field_tid, + }); + } + variants.push(Variant { + name, + fullname, + id, + fields, + }); + } + Some(Type::Enum { + name, + id: tid, + is_extern: ty.is_extern, + is_nodebug: ty.is_nodebug, + variants, + pos: ty.pos, + }) + } + } + } + + fn error(&self, pos: Pos, msg: impl Into) -> Error { + Error::TypeError { + msg: msg.into(), + span: Span::new_single(pos), + } + } + + fn report_error(&mut self, pos: Pos, msg: impl Into) { + let err = self.error(pos, msg); + self.errors.push(err); + } + + fn intern_mut(&mut self, ident: &ast::Ident) -> Sym { + if let Some(s) = self.sym_map.get(&ident.0).copied() { + s + } else { + let s = Sym(self.syms.len()); + self.syms.push(ident.0.clone()); + self.sym_map.insert(ident.0.clone(), s); + s + } + } + + fn intern(&self, ident: &ast::Ident) -> Option { + self.sym_map.get(&ident.0).copied() + } + + /// Lookup type by name. + pub fn get_type_by_name(&self, sym: &ast::Ident) -> Option { + self.intern(sym) + .and_then(|sym| self.type_map.get(&sym)) + .copied() + } +} + +#[derive(Clone, Debug, Default)] +struct Bindings { + /// All bindings accumulated so far within the current rule, including let- + /// bindings which have gone out of scope. + seen: Vec, + /// Counter for unique scope IDs within this set of bindings. + next_scope: usize, + /// Stack of the scope IDs for bindings which are currently in scope. + in_scope: Vec, +} + +impl Bindings { + fn enter_scope(&mut self) { + self.in_scope.push(self.next_scope); + self.next_scope += 1; + } + + fn exit_scope(&mut self) { + self.in_scope.pop(); + } + + fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId { + let id = VarId(self.seen.len()); + let var = BoundVar { + id, + name, + ty, + scope: *self + .in_scope + .last() + .expect("enter_scope should be called before add_var"), + }; + log!("binding var {:?}", var); + self.seen.push(var); + id + } + + fn lookup(&self, name: Sym) -> Option<&BoundVar> { + self.seen + .iter() + .rev() + .find(|binding| binding.name == name && self.in_scope.contains(&binding.scope)) + } +} + +impl TermEnv { + /// Construct the term environment from the AST and the type environment. + pub fn from_ast( + tyenv: &mut TypeEnv, + defs: &[ast::Def], + expand_internal_extractors: bool, + ) -> Result> { + let mut env = TermEnv { + terms: vec![], + term_map: StableMap::new(), + rules: vec![], + converters: StableMap::new(), + expand_internal_extractors, + }; + + env.collect_pragmas(defs); + env.collect_term_sigs(tyenv, defs); + env.collect_enum_variant_terms(tyenv); + tyenv.return_errors()?; + env.collect_constructors(tyenv, defs); + env.collect_extractor_templates(tyenv, defs); + tyenv.return_errors()?; + env.collect_converters(tyenv, defs); + tyenv.return_errors()?; + env.collect_externs(tyenv, defs); + tyenv.return_errors()?; + env.collect_rules(tyenv, defs); + env.check_for_undefined_decls(tyenv, defs); + env.check_for_expr_terms_without_constructors(tyenv, defs); + tyenv.return_errors()?; + + Ok(env) + } + + fn collect_pragmas(&mut self, _: &[ast::Def]) { + // currently, no pragmas are defined, but the infrastructure is useful to keep around + return; + } + + fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + match def { + &ast::Def::Decl(ref decl) => { + let name = tyenv.intern_mut(&decl.term); + if let Some(tid) = self.term_map.get(&name) { + tyenv.report_error( + decl.pos, + format!("Duplicate decl for '{}'", decl.term.0), + ); + tyenv.report_error( + self.terms[tid.index()].decl_pos, + format!("Duplicate decl for '{}'", decl.term.0), + ); + } + + if decl.multi && decl.partial { + tyenv.report_error( + decl.pos, + format!("Term '{}' can't be both multi and partial", decl.term.0), + ); + } + + let arg_tys = decl + .arg_tys + .iter() + .map(|id| { + tyenv.get_type_by_name(id).ok_or_else(|| { + tyenv.report_error(id.1, format!("Unknown arg type: '{}'", id.0)); + }) + }) + .collect::, _>>(); + let arg_tys = match arg_tys { + Ok(a) => a, + Err(_) => { + continue; + } + }; + let ret_ty = match tyenv.get_type_by_name(&decl.ret_ty) { + Some(t) => t, + None => { + tyenv.report_error( + decl.ret_ty.1, + format!("Unknown return type: '{}'", decl.ret_ty.0), + ); + continue; + } + }; + + let tid = TermId(self.terms.len()); + self.term_map.insert(name, tid); + let flags = TermFlags { + pure: decl.pure, + multi: decl.multi, + partial: decl.partial, + }; + self.terms.push(Term { + id: tid, + decl_pos: decl.pos, + name, + arg_tys, + ret_ty, + kind: TermKind::Decl { + flags, + constructor_kind: None, + extractor_kind: None, + }, + }); + } + _ => {} + } + } + } + + fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) { + 'types: for i in 0..tyenv.types.len() { + let ty = &tyenv.types[i]; + match ty { + &Type::Enum { + pos, + id, + ref variants, + .. + } => { + for variant in variants { + if self.term_map.contains_key(&variant.fullname) { + let variant_name = tyenv.syms[variant.fullname.index()].clone(); + tyenv.report_error( + pos, + format!("Duplicate enum variant constructor: '{variant_name}'",), + ); + continue 'types; + } + let tid = TermId(self.terms.len()); + let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::>(); + let ret_ty = id; + self.terms.push(Term { + id: tid, + decl_pos: pos, + name: variant.fullname, + arg_tys, + ret_ty, + kind: TermKind::EnumVariant { + variant: variant.id, + }, + }); + self.term_map.insert(variant.fullname, tid); + } + } + _ => {} + } + } + } + + fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + log!("collect_constructors from def: {:?}", def); + match def { + &ast::Def::Rule(ref rule) => { + let pos = rule.pos; + let term = match rule.pattern.root_term() { + Some(t) => t, + None => { + tyenv.report_error( + pos, + "Rule does not have a term at the LHS root".to_string(), + ); + continue; + } + }; + let term = match self.get_term_by_name(tyenv, &term) { + Some(tid) => tid, + None => { + tyenv + .report_error(pos, "Rule LHS root term is not defined".to_string()); + continue; + } + }; + let termdata = &mut self.terms[term.index()]; + match &mut termdata.kind { + TermKind::Decl { + constructor_kind, .. + } => { + match constructor_kind { + None => { + *constructor_kind = Some(ConstructorKind::InternalConstructor); + } + Some(ConstructorKind::InternalConstructor) => { + // OK, no error; multiple rules can apply to + // one internal constructor term. + } + Some(ConstructorKind::ExternalConstructor { .. }) => { + tyenv.report_error( + pos, + "Rule LHS root term is incorrect kind; cannot \ + be external constructor" + .to_string(), + ); + continue; + } + } + } + TermKind::EnumVariant { .. } => { + tyenv.report_error( + pos, + "Rule LHS root term is incorrect kind; cannot be enum variant" + .to_string(), + ); + continue; + } + } + } + _ => {} + } + } + } + + fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + let mut extractor_call_graph = BTreeMap::new(); + + for def in defs { + if let &ast::Def::Extractor(ref ext) = def { + let term = match self.get_term_by_name(tyenv, &ext.term) { + Some(x) => x, + None => { + tyenv.report_error( + ext.pos, + "Extractor macro body definition on a non-existent term".to_string(), + ); + return; + } + }; + + let template = ext.template.make_macro_template(&ext.args[..]); + log!("extractor def: {:?} becomes template {:?}", def, template); + + let mut callees = BTreeSet::new(); + template.terms(&mut |pos, t| { + if let Some(term) = self.get_term_by_name(tyenv, t) { + callees.insert(term); + } else { + tyenv.report_error( + pos, + format!( + "`{}` extractor definition references unknown term `{}`", + ext.term.0, t.0 + ), + ); + } + }); + extractor_call_graph.insert(term, callees); + + let termdata = &mut self.terms[term.index()]; + match &mut termdata.kind { + TermKind::EnumVariant { .. } => { + tyenv.report_error( + ext.pos, + "Extractor macro body defined on term of incorrect kind; cannot be an \ + enum variant", + ); + continue; + } + TermKind::Decl { + flags, + extractor_kind, + .. + } => match extractor_kind { + None => { + if flags.multi { + tyenv.report_error( + ext.pos, + "A term declared with `multi` cannot have an internal extractor.".to_string()); + continue; + } + *extractor_kind = Some(ExtractorKind::InternalExtractor { template }); + } + Some(ext_kind) => { + tyenv.report_error( + ext.pos, + "Duplicate extractor definition".to_string(), + ); + let pos = match ext_kind { + ExtractorKind::InternalExtractor { template } => template.pos(), + ExtractorKind::ExternalExtractor { pos, .. } => *pos, + }; + tyenv.report_error( + pos, + "Extractor was already defined here".to_string(), + ); + continue; + } + }, + } + } + } + + // Check for cycles in the extractor call graph. + let mut stack = vec![]; + 'outer: for root in extractor_call_graph.keys().copied() { + stack.clear(); + stack.push((root, vec![root], StableSet::new())); + + while let Some((caller, path, mut seen)) = stack.pop() { + let is_new = seen.insert(caller); + if is_new { + if let Some(callees) = extractor_call_graph.get(&caller) { + stack.extend(callees.iter().map(|callee| { + let mut path = path.clone(); + path.push(*callee); + (*callee, path, seen.clone()) + })); + } + } else { + let pos = match &self.terms[caller.index()].kind { + TermKind::Decl { + extractor_kind: Some(ExtractorKind::InternalExtractor { template }), + .. + } => template.pos(), + _ => { + // There must have already been errors recorded. + assert!(!tyenv.errors.is_empty()); + continue 'outer; + } + }; + + let path: Vec<_> = path + .iter() + .map(|sym| tyenv.syms[sym.index()].as_str()) + .collect(); + let msg = format!( + "`{}` extractor definition is recursive: {}", + tyenv.syms[root.index()], + path.join(" -> ") + ); + tyenv.report_error(pos, msg); + continue 'outer; + } + } + } + } + + fn collect_converters(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + match def { + &ast::Def::Converter(ast::Converter { + ref term, + ref inner_ty, + ref outer_ty, + pos, + }) => { + let inner_ty_id = match tyenv.get_type_by_name(inner_ty) { + Some(ty) => ty, + None => { + tyenv.report_error( + inner_ty.1, + format!("Unknown inner type for converter: '{}'", inner_ty.0), + ); + continue; + } + }; + + let outer_ty_id = match tyenv.get_type_by_name(outer_ty) { + Some(ty) => ty, + None => { + tyenv.report_error( + outer_ty.1, + format!("Unknown outer type for converter: '{}'", outer_ty.0), + ); + continue; + } + }; + + let term_id = match self.get_term_by_name(tyenv, term) { + Some(term_id) => term_id, + None => { + tyenv.report_error( + term.1, + format!("Unknown term for converter: '{}'", term.0), + ); + continue; + } + }; + + match self.converters.entry((inner_ty_id, outer_ty_id)) { + Entry::Vacant(v) => { + v.insert(term_id); + } + Entry::Occupied(_) => { + tyenv.report_error( + pos, + format!( + "Converter already exists for this type pair: '{}', '{}'", + inner_ty.0, outer_ty.0 + ), + ); + continue; + } + } + } + _ => {} + } + } + } + + fn collect_externs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + match def { + &ast::Def::Extern(ast::Extern::Constructor { + ref term, + ref func, + pos, + }) => { + let func_sym = tyenv.intern_mut(func); + let term_id = match self.get_term_by_name(tyenv, term) { + Some(term) => term, + None => { + tyenv.report_error( + pos, + format!("Constructor declared on undefined term '{}'", term.0), + ); + continue; + } + }; + let termdata = &mut self.terms[term_id.index()]; + match &mut termdata.kind { + TermKind::Decl { + constructor_kind, .. + } => match constructor_kind { + None => { + *constructor_kind = + Some(ConstructorKind::ExternalConstructor { name: func_sym }); + } + Some(ConstructorKind::InternalConstructor) => { + tyenv.report_error( + pos, + format!( + "External constructor declared on term that already has rules: {}", + term.0, + ), + ); + } + Some(ConstructorKind::ExternalConstructor { .. }) => { + tyenv.report_error( + pos, + "Duplicate external constructor definition".to_string(), + ); + } + }, + TermKind::EnumVariant { .. } => { + tyenv.report_error( + pos, + format!( + "External constructor cannot be defined on enum variant: {}", + term.0, + ), + ); + } + } + } + &ast::Def::Extern(ast::Extern::Extractor { + ref term, + ref func, + pos, + infallible, + }) => { + let func_sym = tyenv.intern_mut(func); + let term_id = match self.get_term_by_name(tyenv, term) { + Some(term) => term, + None => { + tyenv.report_error( + pos, + format!("Extractor declared on undefined term '{}'", term.0), + ); + continue; + } + }; + + let termdata = &mut self.terms[term_id.index()]; + + match &mut termdata.kind { + TermKind::Decl { extractor_kind, .. } => match extractor_kind { + None => { + *extractor_kind = Some(ExtractorKind::ExternalExtractor { + name: func_sym, + infallible, + pos, + }); + } + Some(ExtractorKind::ExternalExtractor { pos: pos2, .. }) => { + tyenv.report_error( + pos, + "Duplicate external extractor definition".to_string(), + ); + tyenv.report_error( + *pos2, + "External extractor already defined".to_string(), + ); + continue; + } + Some(ExtractorKind::InternalExtractor { template }) => { + tyenv.report_error( + pos, + "Cannot define external extractor for term that already has an \ + internal extractor macro body defined" + .to_string(), + ); + tyenv.report_error( + template.pos(), + "Internal extractor macro body already defined".to_string(), + ); + continue; + } + }, + TermKind::EnumVariant { .. } => { + tyenv.report_error( + pos, + format!("Cannot define extractor for enum variant '{}'", term.0), + ); + continue; + } + } + } + _ => {} + } + } + } + + fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + match def { + &ast::Def::Rule(ref rule) => { + let pos = rule.pos; + let mut bindings = Bindings::default(); + bindings.enter_scope(); + + let (sym, args) = if let ast::Pattern::Term { sym, args, .. } = &rule.pattern { + (sym, args) + } else { + tyenv.report_error( + pos, + "Rule does not have a term at the root of its left-hand side" + .to_string(), + ); + continue; + }; + + let root_term = if let Some(term) = self.get_term_by_name(tyenv, sym) { + term + } else { + tyenv.report_error( + pos, + "Cannot define a rule for an unknown term".to_string(), + ); + continue; + }; + + let termdata = &self.terms[root_term.index()]; + + let flags = match &termdata.kind { + TermKind::Decl { flags, .. } => *flags, + _ => { + tyenv.report_error( + pos, + "Cannot define a rule on a left-hand-side that is an enum variant" + .to_string(), + ); + continue; + } + }; + + termdata.check_args_count(args, tyenv, pos, sym); + let args = self.translate_args(args, termdata, tyenv, &mut bindings); + + let iflets = rule + .iflets + .iter() + .filter_map(|iflet| { + self.translate_iflet(tyenv, iflet, &mut bindings, flags) + }) + .collect(); + let rhs = unwrap_or_continue!(self.translate_expr( + tyenv, + &rule.expr, + Some(termdata.ret_ty), + &mut bindings, + flags, + )); + + bindings.exit_scope(); + + let prio = if let Some(prio) = rule.prio { + if flags.multi { + tyenv.report_error( + pos, + "Cannot set rule priorities in multi-terms".to_string(), + ); + } + prio + } else { + 0 + }; + + let rid = RuleId(self.rules.len()); + self.rules.push(Rule { + id: rid, + root_term, + args, + iflets, + rhs, + vars: bindings.seen, + prio, + pos, + name: rule.name.as_ref().map(|i| tyenv.intern_mut(i)), + }); + } + _ => {} + } + } + } + + fn check_for_undefined_decls(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + if let ast::Def::Decl(decl) = def { + let term = self.get_term_by_name(tyenv, &decl.term).unwrap(); + let term = &self.terms[term.index()]; + if !term.has_constructor() && !term.has_extractor() { + tyenv.report_error( + decl.pos, + format!( + "no rules, extractor, or external definition for declaration '{}'", + decl.term.0 + ), + ); + } + } + } + } + + fn check_for_expr_terms_without_constructors(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) { + for def in defs { + if let ast::Def::Rule(rule) = def { + rule.expr.terms(&mut |pos, ident| { + let term = match self.get_term_by_name(tyenv, ident) { + None => { + debug_assert!(!tyenv.errors.is_empty()); + return; + } + Some(t) => t, + }; + let term = &self.terms[term.index()]; + if !term.has_constructor() { + tyenv.report_error( + pos, + format!( + "term `{}` cannot be used in an expression because \ + it does not have a constructor", + ident.0 + ), + ) + } + }); + } + } + } + + fn maybe_implicit_convert_pattern( + &self, + tyenv: &mut TypeEnv, + pattern: &ast::Pattern, + inner_ty: TypeId, + outer_ty: TypeId, + ) -> Option { + if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) { + if self.terms[converter_term.index()].has_extractor() { + // This is a little awkward: we have to + // convert back to an Ident, to be + // re-resolved. The pos doesn't matter + // as it shouldn't result in a lookup + // failure. + let converter_term_ident = ast::Ident( + tyenv.syms[self.terms[converter_term.index()].name.index()].clone(), + pattern.pos(), + ); + let expanded_pattern = ast::Pattern::Term { + sym: converter_term_ident, + pos: pattern.pos(), + args: vec![pattern.clone()], + }; + + return Some(expanded_pattern); + } + } + None + } + + fn translate_pattern( + &self, + tyenv: &mut TypeEnv, + pat: &ast::Pattern, + expected_ty: TypeId, + bindings: &mut Bindings, + ) -> Option { + log!("translate_pattern: {:?}", pat); + log!("translate_pattern: bindings = {:?}", bindings); + match pat { + // TODO: flag on primitive type decl indicating it's an integer type? + &ast::Pattern::ConstInt { val, pos } => { + let ty = &tyenv.types[expected_ty.index()]; + if !ty.is_int() && !ty.is_prim() { + tyenv.report_error( + pos, + format!( + "expected non-integer type {}, but found integer literal '{}'", + ty.name(tyenv), + val, + ), + ); + } + Some(Pattern::ConstInt(expected_ty, val)) + } + &ast::Pattern::ConstBool { val, pos } => { + if expected_ty != TypeId::BOOL { + tyenv.report_error( + pos, + format!( + "Boolean literal '{val}' has type {} but we need {} in context", + BuiltinType::Bool.name(), + tyenv.types[expected_ty.index()].name(tyenv) + ), + ) + } + Some(Pattern::ConstBool(TypeId::BOOL, val)) + } + &ast::Pattern::ConstPrim { ref val, pos } => { + let val = tyenv.intern_mut(val); + let const_ty = match tyenv.const_types.get(&val) { + Some(ty) => *ty, + None => { + tyenv.report_error(pos, "Unknown constant"); + return None; + } + }; + if expected_ty != const_ty { + tyenv.report_error(pos, "Type mismatch for constant"); + } + Some(Pattern::ConstPrim(const_ty, val)) + } + &ast::Pattern::Wildcard { .. } => Some(Pattern::Wildcard(expected_ty)), + &ast::Pattern::And { ref subpats, .. } => { + // If any of the subpatterns fails to type-check, we'll report + // an error at that point. Here, just skip it and keep looking + // for more errors. + let children = subpats + .iter() + .filter_map(|subpat| { + self.translate_pattern(tyenv, subpat, expected_ty, bindings) + }) + .collect(); + Some(Pattern::And(expected_ty, children)) + } + &ast::Pattern::BindPattern { + ref var, + ref subpat, + pos, + } => { + let subpat = self.translate_pattern(tyenv, subpat, expected_ty, bindings)?; + + // The sub-pattern's type should be `expected_ty`. If it isn't, + // we've already reported a type error about it, but continue + // using the type we actually found in hopes that we'll + // generate fewer follow-on error messages. + let ty = subpat.ty(); + + let name = tyenv.intern_mut(var); + if bindings.lookup(name).is_some() { + tyenv.report_error( + pos, + format!("Re-bound variable name in LHS pattern: '{}'", var.0), + ); + // Try to keep going. + } + let id = bindings.add_var(name, ty); + Some(Pattern::BindPattern(ty, id, Box::new(subpat))) + } + &ast::Pattern::Var { ref var, pos } => { + // Look up the variable; if it has already been bound, + // then this becomes a `Var` node (which matches the + // existing bound value), otherwise it becomes a + // `BindPattern` with a wildcard subpattern to capture + // at this location. + let name = tyenv.intern_mut(var); + match bindings.lookup(name) { + None => { + let id = bindings.add_var(name, expected_ty); + Some(Pattern::BindPattern( + expected_ty, + id, + Box::new(Pattern::Wildcard(expected_ty)), + )) + } + Some(bv) => { + if expected_ty != bv.ty { + tyenv.report_error( + pos, + format!( + "Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'", + tyenv.types[expected_ty.index()].name(tyenv), + var.0, + tyenv.types[bv.ty.index()].name(tyenv), + ), + ); + // Try to keep going for more errors. + } + Some(Pattern::Var(bv.ty, bv.id)) + } + } + } + &ast::Pattern::Term { + ref sym, + ref args, + pos, + } => { + // Look up the term. + let tid = match self.get_term_by_name(tyenv, sym) { + Some(t) => t, + None => { + tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0)); + return None; + } + }; + + let termdata = &self.terms[tid.index()]; + + // Get the return type and arg types. Verify the + // expected type of this pattern, if any, against the + // return type of the term. Insert an implicit + // converter if needed. + let ret_ty = termdata.ret_ty; + if expected_ty != ret_ty { + // Can we do an implicit type conversion? Look + // up the converter term, if any. If one has + // been registered, and the term has an + // extractor, then build an expanded AST node + // right here and recurse on it. + if let Some(expanded_pattern) = + self.maybe_implicit_convert_pattern(tyenv, pat, ret_ty, expected_ty) + { + return self.translate_pattern( + tyenv, + &expanded_pattern, + expected_ty, + bindings, + ); + } + + tyenv.report_error( + pos, + format!( + "Mismatched types: pattern expects type '{}' but term has return type '{}'", + tyenv.types[expected_ty.index()].name(tyenv), + tyenv.types[ret_ty.index()].name(tyenv), + ), + ); + // Try to keep going for more errors. + } + + termdata.check_args_count(args, tyenv, pos, sym); + + // TODO: check that multi-extractors are only used in terms declared `multi` + + match &termdata.kind { + TermKind::EnumVariant { .. } => {} + TermKind::Decl { + extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }), + .. + } => {} + TermKind::Decl { + extractor_kind: Some(ExtractorKind::InternalExtractor { ref template }), + .. + } => { + if self.expand_internal_extractors { + // Expand the extractor macro! We create a map + // from macro args to AST pattern trees and + // then evaluate the template with these + // substitutions. + log!("internal extractor macro args = {:?}", args); + let pat = template.subst_macro_args(&args)?; + return self.translate_pattern(tyenv, &pat, expected_ty, bindings); + } + } + TermKind::Decl { + extractor_kind: None, + .. + } => { + tyenv.report_error( + pos, + format!( + "Cannot use term '{}' that does not have a defined extractor in a \ + left-hand side pattern", + sym.0 + ), + ); + } + } + + let subpats = self.translate_args(args, termdata, tyenv, bindings); + Some(Pattern::Term(ret_ty, tid, subpats)) + } + &ast::Pattern::MacroArg { .. } => unreachable!(), + } + } + + fn translate_args( + &self, + args: &Vec, + termdata: &Term, + tyenv: &mut TypeEnv, + bindings: &mut Bindings, + ) -> Vec { + args.iter() + .zip(termdata.arg_tys.iter()) + .filter_map(|(arg, &arg_ty)| self.translate_pattern(tyenv, arg, arg_ty, bindings)) + .collect() + } + + fn maybe_implicit_convert_expr( + &self, + tyenv: &mut TypeEnv, + expr: &ast::Expr, + inner_ty: TypeId, + outer_ty: TypeId, + ) -> Option { + // Is there a converter for this type mismatch? + if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) { + if self.terms[converter_term.index()].has_constructor() { + let converter_ident = ast::Ident( + tyenv.syms[self.terms[converter_term.index()].name.index()].clone(), + expr.pos(), + ); + return Some(ast::Expr::Term { + sym: converter_ident, + pos: expr.pos(), + args: vec![expr.clone()], + }); + } + } + None + } + + fn translate_expr( + &self, + tyenv: &mut TypeEnv, + expr: &ast::Expr, + ty: Option, + bindings: &mut Bindings, + root_flags: TermFlags, + ) -> Option { + log!("translate_expr: {:?}", expr); + match expr { + &ast::Expr::Term { + ref sym, + ref args, + pos, + } => { + // Look up the term. + let name = tyenv.intern_mut(&sym); + let tid = match self.term_map.get(&name) { + Some(&t) => t, + None => { + // Maybe this was actually a variable binding and the user has placed + // parens around it by mistake? (See #4775.) + if bindings.lookup(name).is_some() { + tyenv.report_error( + pos, + format!( + "Unknown term in expression: '{}'. Variable binding under this name exists; try removing the parens?", sym.0)); + } else { + tyenv.report_error( + pos, + format!("Unknown term in expression: '{}'", sym.0), + ); + } + return None; + } + }; + let termdata = &self.terms[tid.index()]; + + // Get the return type and arg types. Verify the + // expected type of this pattern, if any, against the + // return type of the term, and determine whether we + // are doing an implicit conversion. Report an error + // if types don't match and no conversion is possible. + let ret_ty = termdata.ret_ty; + let ty = if ty.is_some() && ret_ty != ty.unwrap() { + // Is there a converter for this type mismatch? + if let Some(expanded_expr) = + self.maybe_implicit_convert_expr(tyenv, expr, ret_ty, ty.unwrap()) + { + return self.translate_expr( + tyenv, + &expanded_expr, + ty, + bindings, + root_flags, + ); + } + + tyenv.report_error( + pos, + format!("Mismatched types: expression expects type '{}' but term has return type '{}'", + tyenv.types[ty.unwrap().index()].name(tyenv), + tyenv.types[ret_ty.index()].name(tyenv))); + + // Keep going, to discover more errors. + ret_ty + } else { + ret_ty + }; + + if let TermKind::Decl { flags, .. } = &termdata.kind { + // On the left-hand side of a rule or in a pure term, only pure terms may be + // used. + let pure_required = root_flags.pure; + if pure_required && !flags.pure { + tyenv.report_error( + pos, + format!( + "Used non-pure constructor '{}' in pure expression context", + sym.0 + ), + ); + } + + // Multi-terms may only be used inside other multi-terms. + if !root_flags.multi && flags.multi { + tyenv.report_error( + pos, + format!( + "Used multi-constructor '{}' but this rule is not in a multi-term", + sym.0 + ), + ); + } + + // Partial terms may always be used on the left-hand side of a rule. On the + // right-hand side they may only be used inside other partial terms. + let partial_allowed = root_flags.partial; + if !partial_allowed && flags.partial { + tyenv.report_error( + pos, + format!( + "Rule can't use partial constructor '{}' on RHS; \ + try moving it to if-let{}", + sym.0, + if root_flags.multi { + "" + } else { + " or make this rule's term partial too" + } + ), + ); + } + } + + termdata.check_args_count(args, tyenv, pos, sym); + + // Resolve subexpressions. + let subexprs = args + .iter() + .zip(termdata.arg_tys.iter()) + .filter_map(|(arg, &arg_ty)| { + self.translate_expr(tyenv, arg, Some(arg_ty), bindings, root_flags) + }) + .collect(); + + Some(Expr::Term(ty, tid, subexprs)) + } + &ast::Expr::Var { ref name, pos } => { + let sym = tyenv.intern_mut(name); + // Look through bindings, innermost (most recent) first. + let bv = match bindings.lookup(sym) { + None => { + tyenv.report_error(pos, format!("Unknown variable '{}'", name.0)); + return None; + } + Some(bv) => bv, + }; + + // Verify type. Maybe do an implicit conversion. + if ty.is_some() && bv.ty != ty.unwrap() { + // Is there a converter for this type mismatch? + if let Some(expanded_expr) = + self.maybe_implicit_convert_expr(tyenv, expr, bv.ty, ty.unwrap()) + { + return self.translate_expr( + tyenv, + &expanded_expr, + ty, + bindings, + root_flags, + ); + } + + tyenv.report_error( + pos, + format!( + "Variable '{}' has type {} but we need {} in context", + name.0, + tyenv.types[bv.ty.index()].name(tyenv), + tyenv.types[ty.unwrap().index()].name(tyenv) + ), + ); + } + + Some(Expr::Var(bv.ty, bv.id)) + } + &ast::Expr::ConstBool { val, pos } => { + match ty { + Some(ty) if ty != TypeId::BOOL => tyenv.report_error( + pos, + format!( + "Boolean literal '{val}' has type {} but we need {} in context", + BuiltinType::Bool.name(), + tyenv.types[ty.index()].name(tyenv) + ), + ), + Some(..) | None => {} + }; + Some(Expr::ConstBool(TypeId::BOOL, val)) + } + &ast::Expr::ConstInt { val, pos } => { + let Some(ty) = ty else { + tyenv.report_error( + pos, + "integer literal in a context that needs an explicit type".to_string(), + ); + return None; + }; + + let typ = &tyenv.types[ty.index()]; + + if !typ.is_int() && !typ.is_prim() { + tyenv.report_error( + pos, + format!( + "expected non-integer type {}, but found integer literal '{}'", + tyenv.types[ty.index()].name(tyenv), + val, + ), + ); + } + Some(Expr::ConstInt(ty, val)) + } + &ast::Expr::ConstPrim { ref val, pos } => { + let val = tyenv.intern_mut(val); + let const_ty = match tyenv.const_types.get(&val) { + Some(ty) => *ty, + None => { + tyenv.report_error(pos, "Unknown constant"); + return None; + } + }; + if ty.is_some() && const_ty != ty.unwrap() { + tyenv.report_error( + pos, + format!( + "Constant '{}' has wrong type: expected {}, but is actually {}", + tyenv.syms[val.index()], + tyenv.types[ty.unwrap().index()].name(tyenv), + tyenv.types[const_ty.index()].name(tyenv) + ), + ); + return None; + } + Some(Expr::ConstPrim(const_ty, val)) + } + &ast::Expr::Let { + ref defs, + ref body, + pos, + } => { + bindings.enter_scope(); + + // For each new binding... + let mut let_defs = vec![]; + for def in defs { + // Check that the given variable name does not already exist. + let name = tyenv.intern_mut(&def.var); + + // Look up the type. + let tid = match tyenv.get_type_by_name(&def.ty) { + Some(tid) => tid, + None => { + tyenv.report_error( + pos, + format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0), + ); + continue; + } + }; + + // Evaluate the variable's value. + let val = Box::new(unwrap_or_continue!(self.translate_expr( + tyenv, + &def.val, + Some(tid), + bindings, + root_flags, + ))); + + // Bind the var with the given type. + let id = bindings.add_var(name, tid); + let_defs.push((id, tid, val)); + } + + // Evaluate the body, expecting the type of the overall let-expr. + let body = Box::new(self.translate_expr(tyenv, body, ty, bindings, root_flags)?); + let body_ty = body.ty(); + + // Pop the bindings. + bindings.exit_scope(); + + Some(Expr::Let { + ty: body_ty, + bindings: let_defs, + body, + }) + } + } + } + + fn translate_iflet( + &self, + tyenv: &mut TypeEnv, + iflet: &ast::IfLet, + bindings: &mut Bindings, + root_flags: TermFlags, + ) -> Option { + // Translate the expr first. The `if-let` and `if` forms are part of the left-hand side of + // the rule. + let rhs = self.translate_expr(tyenv, &iflet.expr, None, bindings, root_flags.on_lhs())?; + let lhs = self.translate_pattern(tyenv, &iflet.pattern, rhs.ty(), bindings)?; + + Some(IfLet { lhs, rhs }) + } + + /// Lookup term by name. + pub fn get_term_by_name(&self, tyenv: &TypeEnv, sym: &ast::Ident) -> Option { + tyenv + .intern(sym) + .and_then(|sym| self.term_map.get(&sym)) + .copied() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::ast::Ident; + use crate::lexer::Lexer; + use crate::parser::parse; + + #[test] + fn build_type_env() { + let text = r" + (type UImm8 (primitive UImm8)) + (type A extern (enum (B (f1 u32) (f2 u32)) (C (f1 u32)))) + "; + let ast = parse(Lexer::new(0, text).unwrap()).expect("should parse"); + let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors"); + + let sym_a = tyenv + .intern(&Ident("A".to_string(), Default::default())) + .unwrap(); + let sym_b = tyenv + .intern(&Ident("B".to_string(), Default::default())) + .unwrap(); + let sym_c = tyenv + .intern(&Ident("C".to_string(), Default::default())) + .unwrap(); + let sym_a_b = tyenv + .intern(&Ident("A.B".to_string(), Default::default())) + .unwrap(); + let sym_a_c = tyenv + .intern(&Ident("A.C".to_string(), Default::default())) + .unwrap(); + let sym_uimm8 = tyenv + .intern(&Ident("UImm8".to_string(), Default::default())) + .unwrap(); + let sym_f1 = tyenv + .intern(&Ident("f1".to_string(), Default::default())) + .unwrap(); + let sym_f2 = tyenv + .intern(&Ident("f2".to_string(), Default::default())) + .unwrap(); + + assert_eq!(tyenv.type_map.get(&sym_uimm8).unwrap(), &TypeId(13)); + assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(14)); + + let expected_types = vec![ + Type::Primitive( + TypeId(13), + sym_uimm8, + Pos { + file: 0, + offset: 19, + }, + ), + Type::Enum { + name: sym_a, + id: TypeId(14), + is_extern: true, + is_nodebug: false, + variants: vec![ + Variant { + name: sym_b, + fullname: sym_a_b, + id: VariantId(0), + fields: vec![ + Field { + name: sym_f1, + id: FieldId(0), + ty: TypeId::U32, + }, + Field { + name: sym_f2, + id: FieldId(1), + ty: TypeId::U32, + }, + ], + }, + Variant { + name: sym_c, + fullname: sym_a_c, + id: VariantId(1), + fields: vec![Field { + name: sym_f1, + id: FieldId(0), + ty: TypeId::U32, + }], + }, + ], + pos: Pos { + file: 0, + offset: 62, + }, + }, + ]; + + assert_eq!( + tyenv.types.len(), + expected_types.len() + BuiltinType::ALL.len() + ); + for (i, (actual, expected)) in tyenv + .types + .iter() + .skip(BuiltinType::ALL.len()) + .zip(&expected_types) + .enumerate() + { + assert_eq!(expected, actual, "`{i}`th type is not equal!"); + } + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/serialize.rs b/deps/crates/vendor/cranelift-isle/src/serialize.rs new file mode 100644 index 00000000000000..a05a6cd22b2fc6 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/serialize.rs @@ -0,0 +1,851 @@ +//! Put "sea of nodes" representation of a `RuleSet` into a sequential order. +//! +//! We're trying to satisfy two key constraints on generated code: +//! +//! First, we must produce the same result as if we tested the left-hand side +//! of every rule in descending priority order and picked the first match. +//! But that would mean a lot of duplicated work since many rules have similar +//! patterns. We want to evaluate in an order that gets the same answer but +//! does as little work as possible. +//! +//! Second, some ISLE patterns can only be implemented in Rust using a `match` +//! expression (or various choices of syntactic sugar). Others can only +//! be implemented as expressions, which can't be evaluated while matching +//! patterns in Rust. So we need to alternate between pattern matching and +//! expression evaluation. +//! +//! To meet both requirements, we repeatedly partition the set of rules for a +//! term and build a tree of Rust control-flow constructs corresponding to each +//! partition. The root of such a tree is a [Block], and [serialize] constructs +//! it. + +use crate::disjointsets::DisjointSets; +use crate::lexer::Pos; +use crate::trie_again::{Binding, BindingId, Constraint, Rule, RuleSet}; +use std::cmp::Reverse; + +/// Decomposes the rule-set into a tree of [Block]s. +pub fn serialize(rules: &RuleSet) -> Block { + // While building the tree, we need temporary storage to keep track of + // different subsets of the rules as we partition them into ever smaller + // sets. As long as we're allowed to re-order the rules, we can ensure + // that every partition is contiguous; but since we plan to re-order them, + // we actually just store indexes into the `RuleSet` to minimize data + // movement. The algorithm in this module never duplicates or discards + // rules, so the total size of all partitions is exactly the number of + // rules. For all the above reasons, we can pre-allocate all the space + // we'll need to hold those partitions up front and share it throughout the + // tree. + // + // As an interesting side effect, when the algorithm finishes, this vector + // records the order in which rule bodies will be emitted in the generated + // Rust. We don't care because we could get the same information from the + // built tree, but it may be helpful to think about the intermediate steps + // as recursively sorting the rules. It may not be possible to produce the + // same order using a comparison sort, and the asymptotic complexity is + // probably worse than the O(n log n) of a comparison sort, but it's still + // doing sorting of some kind. + let mut order = Vec::from_iter(0..rules.rules.len()); + Decomposition::new(rules).sort(&mut order) +} + +/// A sequence of steps to evaluate in order. Any step may return early, so +/// steps ordered later can assume the negation of the conditions evaluated in +/// earlier steps. +#[derive(Default)] +pub struct Block { + /// Steps to evaluate. + pub steps: Vec, +} + +/// A step to evaluate involves possibly let-binding some expressions, then +/// executing some control flow construct. +pub struct EvalStep { + /// Before evaluating this case, emit let-bindings in this order. + pub bind_order: Vec, + /// The control-flow construct to execute at this point. + pub check: ControlFlow, +} + +/// What kind of control-flow structure do we need to emit here? +pub enum ControlFlow { + /// Test a binding site against one or more mutually-exclusive patterns and + /// branch to the appropriate block if a pattern matches. + Match { + /// Which binding site are we examining at this point? + source: BindingId, + /// What patterns do we care about? + arms: Vec, + }, + /// Test whether two binding sites have values which are equal when + /// evaluated on the current input. + Equal { + /// One binding site. + a: BindingId, + /// The other binding site. To ensure we always generate the same code + /// given the same set of ISLE rules, `b` should be strictly greater + /// than `a`. + b: BindingId, + /// If the test succeeds, evaluate this block. + body: Block, + }, + /// Evaluate a block once with each value of the given binding site. + Loop { + /// A binding site of type [Binding::Iterator]. Its source binding site + /// must be a multi-extractor or multi-constructor call. + result: BindingId, + /// What to evaluate with each binding. + body: Block, + }, + /// Return a result from the right-hand side of a rule. If we're building a + /// multi-constructor then this doesn't actually return, but adds to a list + /// of results instead. Otherwise this return stops evaluation before any + /// later steps. + Return { + /// Where was the rule defined that had this right-hand side? + pos: Pos, + /// What is the result expression which should be returned if this + /// rule matched? + result: BindingId, + }, +} + +/// One concrete pattern and the block to evaluate if the pattern matches. +pub struct MatchArm { + /// The pattern to match. + pub constraint: Constraint, + /// If this pattern matches, it brings these bindings into scope. If a + /// binding is unused in this block, then the corresponding position in the + /// pattern's bindings may be `None`. + pub bindings: Vec>, + /// Steps to evaluate if the pattern matched. + pub body: Block, +} + +/// Given a set of rules that's been partitioned into two groups, move rules +/// from the first partition to the second if there are higher-priority rules +/// in the second group. In the final generated code, we'll check the rules +/// in the first ("selected") group before any in the second ("deferred") +/// group. But we need the result to be _as if_ we checked the rules in strict +/// descending priority order. +/// +/// When evaluating the relationship between one rule in the selected set and +/// one rule in the deferred set, there are two cases where we can keep a rule +/// in the selected set: +/// 1. The deferred rule is lower priority than the selected rule; or +/// 2. The two rules don't overlap, so they can't match on the same inputs. +/// +/// In either case, if the selected rule matches then we know the deferred rule +/// would not have been the one we wanted anyway; and if it doesn't match then +/// the fall-through semantics of the code we generate will let us go on to +/// check the deferred rule. +/// +/// So a rule can stay in the selected set as long as it's in one of the above +/// relationships with every rule in the deferred set. +/// +/// Due to the overlap checking pass which occurs before codegen, we know that +/// if two rules have the same priority, they do not overlap. So case 1 above +/// can be expanded to when the deferred rule is lower _or equal_ priority +/// to the selected rule. This much overlap checking is absolutely necessary: +/// There are terms where codegen is impossible if we use only the unmodified +/// case 1 and don't also check case 2. +/// +/// Aside from the equal-priority case, though, case 2 does not seem to matter +/// in practice. On the current backends, doing a full overlap check here does +/// not change the generated code at all. So we don't bother. +/// +/// Since this function never moves rules from the deferred set to the selected +/// set, the returned partition-point is always less than or equal to the +/// initial partition-point. +fn respect_priority(rules: &RuleSet, order: &mut [usize], partition_point: usize) -> usize { + let (selected, deferred) = order.split_at_mut(partition_point); + + if let Some(max_deferred_prio) = deferred.iter().map(|&idx| rules.rules[idx].prio).max() { + partition_in_place(selected, |&idx| rules.rules[idx].prio >= max_deferred_prio) + } else { + // If the deferred set is empty, all selected rules are fine where + // they are. + partition_point + } +} + +/// A query which can be tested against a [Rule] to see if that rule requires +/// the given kind of control flow around the given binding sites. These +/// choices correspond to the identically-named variants of [ControlFlow]. +/// +/// The order of these variants is significant, because it's used as a tie- +/// breaker in the heuristic that picks which control flow to generate next. +/// +/// - Loops should always be chosen last. If a rule needs to run once for each +/// value from an iterator, but only if some other condition is true, we +/// should check the other condition first. +/// +/// - Sorting concrete [HasControlFlow::Match] constraints first has the effect +/// of clustering such constraints together, which is not important but means +/// codegen could theoretically merge the cluster of matches into a single +/// Rust `match` statement. +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +enum HasControlFlow { + /// Find rules which have a concrete pattern constraint on the given + /// binding site. + Match(BindingId), + + /// Find rules which require both given binding sites to be in the same + /// equivalence class. + Equal(BindingId, BindingId), + + /// Find rules which must loop over the multiple values of the given + /// binding site. + Loop(BindingId), +} + +struct PartitionResults { + any_matched: bool, + valid: usize, +} + +impl HasControlFlow { + /// Identify which rules both satisfy this query, and are safe to evaluate + /// before all rules that don't satisfy the query, considering rules' + /// relative priorities like [respect_priority]. Partition matching rules + /// first in `order`. Return the number of rules which are valid with + /// respect to priority, as well as whether any rules matched the query at + /// all. No ordering is guaranteed within either partition, which allows + /// this function to run in linear time. That's fine because later we'll + /// recursively sort both partitions. + fn partition(self, rules: &RuleSet, order: &mut [usize]) -> PartitionResults { + let matching = partition_in_place(order, |&idx| { + let rule = &rules.rules[idx]; + match self { + HasControlFlow::Match(binding_id) => rule.get_constraint(binding_id).is_some(), + HasControlFlow::Equal(x, y) => rule.equals.in_same_set(x, y), + HasControlFlow::Loop(binding_id) => rule.iterators.contains(&binding_id), + } + }); + PartitionResults { + any_matched: matching > 0, + valid: respect_priority(rules, order, matching), + } + } +} + +/// As we proceed through sorting a term's rules, the term's binding sites move +/// through this sequence of states. This state machine helps us avoid doing +/// the same thing with a binding site more than once in any subtree. +#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] +enum BindingState { + /// Initially, all binding sites are unavailable for evaluation except for + /// top-level arguments, constants, and similar. + #[default] + Unavailable, + /// As more binding sites become available, it becomes possible to evaluate + /// bindings which depend on those sites. + Available, + /// Once we've decided a binding is needed in order to make progress in + /// matching, we emit a let-binding for it. We shouldn't evaluate it a + /// second time, if possible. + Emitted, + /// We can only match a constraint against a binding site if we can emit it + /// first. Afterward, we should not try to match a constraint against that + /// site again in the same subtree. + Matched, +} + +/// A sort key used to order control-flow candidates in `best_control_flow`. +#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] +struct Score { + // We prefer to match as many rules at once as possible. + count: usize, + // Break ties by preferring bindings we've already emitted. + state: BindingState, +} + +impl Score { + /// Recompute this score. Returns whether this is a valid candidate; if + /// not, the score may not have been updated and the candidate should + /// be removed from further consideration. The `partition` callback is + /// evaluated lazily. + fn update( + &mut self, + state: BindingState, + partition: impl FnOnce() -> PartitionResults, + ) -> bool { + // Candidates which have already been matched in this partition must + // not be matched again. There's never anything to be gained from + // matching a binding site when you're in an evaluation path where you + // already know exactly what pattern that binding site matches. And + // without this check, we could go into an infinite loop: all rules in + // the current partition match the same pattern for this binding site, + // so matching on it doesn't reduce the number of rules to check and it + // doesn't make more binding sites available. + // + // Note that equality constraints never make a binding site `Matched` + // and are de-duplicated using more complicated equivalence-class + // checks instead. + if state == BindingState::Matched { + return false; + } + self.state = state; + + // The score is not based solely on how many rules have this + // constraint, but on how many such rules can go into the same block + // without violating rule priority. This number can grow as higher- + // priority rules are removed from the partition, so we can't drop + // candidates just because this is zero. If some rule has this + // constraint, it will become viable in some later partition. + let partition = partition(); + self.count = partition.valid; + + // Only consider constraints that are present in some rule in the + // current partition. Note that as we partition the rule set into + // smaller groups, the number of rules which have a particular kind of + // constraint can never grow, so a candidate removed here doesn't need + // to be examined again in this partition. + partition.any_matched + } +} + +/// A rule filter ([HasControlFlow]), plus temporary storage for the sort +/// key used in `best_control_flow` to order these candidates. Keeping the +/// temporary storage here lets us avoid repeated heap allocations. +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct Candidate { + score: Score, + // Last resort tie-breaker: defer to HasControlFlow order, but prefer + // control-flow that sorts earlier. + kind: Reverse, +} + +impl Candidate { + /// Construct a candidate where the score is not set. The score will need + /// to be reset by [Score::update] before use. + fn new(kind: HasControlFlow) -> Self { + Candidate { + score: Score::default(), + kind: Reverse(kind), + } + } +} + +/// A single binding site to check for participation in equality constraints, +/// plus temporary storage for the score used in `best_control_flow` to order +/// these candidates. Keeping the temporary storage here lets us avoid repeated +/// heap allocations. +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct EqualCandidate { + score: Score, + // Last resort tie-breaker: prefer earlier binding sites. + source: Reverse, +} + +impl EqualCandidate { + /// Construct a candidate where the score is not set. The score will need + /// to be reset by [Score::update] before use. + fn new(source: BindingId) -> Self { + EqualCandidate { + score: Score::default(), + source: Reverse(source), + } + } +} + +/// State for a [Decomposition] that needs to be cloned when entering a nested +/// scope, so that changes in that scope don't affect this one. +#[derive(Clone, Default)] +struct ScopedState { + /// The state of all binding sites at this point in the tree, indexed by + /// [BindingId]. Bindings which become available in nested scopes don't + /// magically become available in outer scopes too. + ready: Vec, + /// The current set of candidates for control flow to add at this point in + /// the tree. We can't rely on any match results that might be computed in + /// a nested scope, so if we still care about a candidate in the fallback + /// case then we need to emit the correct control flow for it again. + candidates: Vec, + /// The current set of binding sites which participate in equality + /// constraints at this point in the tree. We can't rely on any match + /// results that might be computed in a nested scope, so if we still care + /// about a candidate in the fallback case then we need to emit the correct + /// control flow for it again. + equal_candidates: Vec, + /// Equivalence classes that we've established on the current path from + /// the root. + equal: DisjointSets, +} + +/// Builder for one [Block] in the tree. +struct Decomposition<'a> { + /// The complete RuleSet, shared across the whole tree. + rules: &'a RuleSet, + /// Decomposition state that is scoped to the current subtree. + scope: ScopedState, + /// Accumulator for bindings that should be emitted before the next + /// control-flow construct. + bind_order: Vec, + /// Accumulator for the final Block that we'll return as this subtree. + block: Block, +} + +impl<'a> Decomposition<'a> { + /// Create a builder for the root [Block]. + fn new(rules: &'a RuleSet) -> Decomposition<'a> { + let mut scope = ScopedState::default(); + scope.ready.resize(rules.bindings.len(), Default::default()); + let mut result = Decomposition { + rules, + scope, + bind_order: Default::default(), + block: Default::default(), + }; + result.add_bindings(); + result + } + + /// Create a builder for a nested [Block]. + fn new_block(&mut self) -> Decomposition { + Decomposition { + rules: self.rules, + scope: self.scope.clone(), + bind_order: Default::default(), + block: Default::default(), + } + } + + /// Ensure that every binding site's state reflects its dependencies' + /// states. This takes time linear in the number of bindings. Because + /// `trie_again` only hash-conses a binding after all its dependencies have + /// already been hash-consed, a single in-order pass visits a binding's + /// dependencies before visiting the binding itself. + fn add_bindings(&mut self) { + for (idx, binding) in self.rules.bindings.iter().enumerate() { + // We only add these bindings when matching a corresponding + // type of control flow, in `make_control_flow`. + if matches!( + binding, + Binding::Iterator { .. } | Binding::MatchVariant { .. } | Binding::MatchSome { .. } + ) { + continue; + } + + // TODO: proactively put some bindings in `Emitted` state + // That makes them visible to the best-binding heuristic, which + // prefers to match on already-emitted bindings first. This helps + // to sort cheap computations before expensive ones. + + let idx: BindingId = idx.try_into().unwrap(); + if self.scope.ready[idx.index()] < BindingState::Available { + if binding + .sources() + .iter() + .all(|&source| self.scope.ready[source.index()] >= BindingState::Available) + { + self.set_ready(idx, BindingState::Available); + } + } + } + } + + /// Determines the final evaluation order for the given subset of rules, and + /// builds a [Block] representing that order. + fn sort(mut self, mut order: &mut [usize]) -> Block { + while let Some(best) = self.best_control_flow(order) { + // Peel off all rules that have this particular control flow, and + // save the rest for the next iteration of the loop. + let partition_point = best.partition(self.rules, order).valid; + debug_assert!(partition_point > 0); + let (this, rest) = order.split_at_mut(partition_point); + order = rest; + + // Recursively build the control-flow tree for these rules. + let check = self.make_control_flow(best, this); + // Note that `make_control_flow` may have added more let-bindings. + let bind_order = std::mem::take(&mut self.bind_order); + self.block.steps.push(EvalStep { bind_order, check }); + } + + // At this point, `best_control_flow` says the remaining rules don't + // have any control flow left to emit. That could be because there are + // no unhandled rules left, or because every candidate for control flow + // for the remaining rules has already been matched by some ancestor in + // the tree. + debug_assert_eq!(self.scope.candidates.len(), 0); + // TODO: assert something about self.equal_candidates? + + // If we're building a multi-constructor, then there could be multiple + // rules with the same left-hand side. We'll evaluate them all, but + // to keep the output consistent, first sort by descending priority + // and break ties with the order the rules were declared. In non-multi + // constructors, there should be at most one rule remaining here. + order.sort_unstable_by_key(|&idx| (Reverse(self.rules.rules[idx].prio), idx)); + for &idx in order.iter() { + let &Rule { + pos, + result, + ref impure, + .. + } = &self.rules.rules[idx]; + + // Ensure that any impure constructors are called, even if their + // results aren't used. + for &impure in impure.iter() { + self.use_expr(impure); + } + self.use_expr(result); + + let check = ControlFlow::Return { pos, result }; + let bind_order = std::mem::take(&mut self.bind_order); + self.block.steps.push(EvalStep { bind_order, check }); + } + + self.block + } + + /// Let-bind this binding site and all its dependencies, skipping any + /// which are already let-bound. Also skip let-bindings for certain trivial + /// expressions which are safe and cheap to evaluate multiple times, + /// because that reduces clutter in the generated code. + fn use_expr(&mut self, name: BindingId) { + if self.scope.ready[name.index()] < BindingState::Emitted { + self.set_ready(name, BindingState::Emitted); + let binding = &self.rules.bindings[name.index()]; + for &source in binding.sources() { + self.use_expr(source); + } + + let should_let_bind = match binding { + Binding::ConstInt { .. } => false, + Binding::ConstPrim { .. } => false, + Binding::Argument { .. } => false, + Binding::MatchTuple { .. } => false, + + // Only let-bind variant constructors if they have some fields. + // Building a variant with no fields is cheap, but don't + // duplicate more complex expressions. + Binding::MakeVariant { fields, .. } => !fields.is_empty(), + + // By default, do let-bind: that's always safe. + _ => true, + }; + if should_let_bind { + self.bind_order.push(name); + } + } + } + + /// Build one control-flow construct and its subtree for the specified rules. + /// The rules in `order` must all have the kind of control-flow named in `best`. + fn make_control_flow(&mut self, best: HasControlFlow, order: &mut [usize]) -> ControlFlow { + match best { + HasControlFlow::Match(source) => { + self.use_expr(source); + self.add_bindings(); + let mut arms = Vec::new(); + + let get_constraint = + |idx: usize| self.rules.rules[idx].get_constraint(source).unwrap(); + + // Ensure that identical constraints are grouped together, then + // loop over each group. + order.sort_unstable_by_key(|&idx| get_constraint(idx)); + for g in group_by_mut(order, |&a, &b| get_constraint(a) == get_constraint(b)) { + // Applying a constraint moves the discriminant from + // Emitted to Matched, but only within the constraint's + // match arm; later fallthrough cases may need to match + // this discriminant again. Since `source` is in the + // `Emitted` state in the parent due to the above call + // to `use_expr`, calling `add_bindings` again after this + // wouldn't change anything. + let mut child = self.new_block(); + child.set_ready(source, BindingState::Matched); + + // Get the constraint for this group, and all of the + // binding sites that it introduces. + let constraint = get_constraint(g[0]); + let bindings = Vec::from_iter( + constraint + .bindings_for(source) + .into_iter() + .map(|b| child.rules.find_binding(&b)), + ); + + let mut changed = false; + for &binding in bindings.iter() { + if let Some(binding) = binding { + // Matching a pattern makes its bindings + // available, and also emits code to bind + // them. + child.set_ready(binding, BindingState::Emitted); + changed = true; + } + } + + // As an optimization, only propagate availability + // if we changed any binding's readiness. + if changed { + child.add_bindings(); + } + + // Recursively construct a Block for this group of rules. + let body = child.sort(g); + arms.push(MatchArm { + constraint, + bindings, + body, + }); + } + + ControlFlow::Match { source, arms } + } + + HasControlFlow::Equal(a, b) => { + // Both sides of the equality test must be evaluated before + // the condition can be tested. Go ahead and let-bind them + // so they're available without re-evaluation in fall-through + // cases. + self.use_expr(a); + self.use_expr(b); + self.add_bindings(); + + let mut child = self.new_block(); + // Never mark binding sites used in equality constraints as + // "matched", because either might need to be used again in + // a later equality check. Instead record that they're in the + // same equivalence class on this path. + child.scope.equal.merge(a, b); + let body = child.sort(order); + ControlFlow::Equal { a, b, body } + } + + HasControlFlow::Loop(source) => { + // Consuming a multi-term involves two binding sites: + // calling the multi-term to get an iterator (the `source`), + // and looping over the iterator to get a binding for each + // `result`. + let result = self + .rules + .find_binding(&Binding::Iterator { source }) + .unwrap(); + + // We must not let-bind the iterator until we're ready to + // consume it, because it can only be consumed once. This also + // means that the let-binding for `source` is not actually + // reusable after this point, so even though we need to emit + // its let-binding here, we pretend we haven't. + let base_state = self.scope.ready[source.index()]; + debug_assert_eq!(base_state, BindingState::Available); + self.use_expr(source); + self.scope.ready[source.index()] = base_state; + self.add_bindings(); + + let mut child = self.new_block(); + child.set_ready(source, BindingState::Matched); + child.set_ready(result, BindingState::Emitted); + child.add_bindings(); + let body = child.sort(order); + ControlFlow::Loop { result, body } + } + } + } + + /// Advance the given binding to a new state. The new state usually should + /// be greater than the existing state; but at the least it must never + /// go backward. + fn set_ready(&mut self, source: BindingId, state: BindingState) { + let old = &mut self.scope.ready[source.index()]; + debug_assert!(*old <= state); + + // Add candidates for this binding, but only when it first becomes + // available. + if let BindingState::Unavailable = old { + // A binding site can't have all of these kinds of constraint, + // and many have none. But `best_control_flow` has to check all + // candidates anyway, so let it figure out which (if any) of these + // are applicable. It will only check false candidates once on any + // partition, removing them from this list immediately. + self.scope.candidates.extend([ + Candidate::new(HasControlFlow::Match(source)), + Candidate::new(HasControlFlow::Loop(source)), + ]); + self.scope + .equal_candidates + .push(EqualCandidate::new(source)); + } + + *old = state; + } + + /// For the specified set of rules, heuristically choose which control-flow + /// will minimize redundant work when the generated code is running. + fn best_control_flow(&mut self, order: &mut [usize]) -> Option { + // If there are no rules left, none of the candidates will match + // anything in the `retain_mut` call below, so short-circuit it. + if order.is_empty() { + // This is only read in a debug-assert but it's fast so just do it + self.scope.candidates.clear(); + return None; + } + + // Remove false candidates, and recompute the candidate score for the + // current set of rules in `order`. + self.scope.candidates.retain_mut(|candidate| { + let kind = candidate.kind.0; + let source = match kind { + HasControlFlow::Match(source) => source, + HasControlFlow::Loop(source) => source, + HasControlFlow::Equal(..) => unreachable!(), + }; + let state = self.scope.ready[source.index()]; + candidate + .score + .update(state, || kind.partition(self.rules, order)) + }); + + // Find the best normal candidate. + let mut best = self.scope.candidates.iter().max().cloned(); + + // Equality constraints are more complicated. We need to identify + // some pair of binding sites which are constrained to be equal in at + // least one rule in the current partition. We do this in two steps. + // First, find each single binding site which participates in any + // equality constraint in some rule. We compute the best-case `Score` + // we could get, if there were another binding site where all the rules + // constraining this binding site require it to be equal to that one. + self.scope.equal_candidates.retain_mut(|candidate| { + let source = candidate.source.0; + let state = self.scope.ready[source.index()]; + candidate.score.update(state, || { + let matching = partition_in_place(order, |&idx| { + self.rules.rules[idx].equals.find(source).is_some() + }); + PartitionResults { + any_matched: matching > 0, + valid: respect_priority(self.rules, order, matching), + } + }) + }); + + // Now that we know which single binding sites participate in any + // equality constraints, we need to find the best pair of binding + // sites. Rules that require binding sites `x` and `y` to be equal are + // a subset of the intersection of rules constraining `x` and those + // constraining `y`. So the upper bound on the number of matching rules + // is whichever candidate is smaller. + // + // Do an O(n log n) sort to put the best single binding sites first. + // Then the O(n^2) all-pairs loop can do branch-and-bound style + // pruning, breaking out of a loop as soon as the remaining candidates + // must all produce worse results than our current best candidate. + // + // Note that `x` and `y` are reversed, to sort in descending order. + self.scope + .equal_candidates + .sort_unstable_by(|x, y| y.cmp(x)); + + let mut equals = self.scope.equal_candidates.iter(); + while let Some(x) = equals.next() { + if Some(&x.score) < best.as_ref().map(|best| &best.score) { + break; + } + let x_id = x.source.0; + for y in equals.as_slice().iter() { + if Some(&y.score) < best.as_ref().map(|best| &best.score) { + break; + } + let y_id = y.source.0; + // If x and y are already in the same path-scoped equivalence + // class, then skip this pair because we already emitted this + // check or a combination of equivalent checks on this path. + if !self.scope.equal.in_same_set(x_id, y_id) { + // Sort arguments for consistency. + let kind = if x_id < y_id { + HasControlFlow::Equal(x_id, y_id) + } else { + HasControlFlow::Equal(y_id, x_id) + }; + let pair = Candidate { + kind: Reverse(kind), + score: Score { + count: kind.partition(self.rules, order).valid, + // Only treat this as already-emitted if + // both bindings are. + state: x.score.state.min(y.score.state), + }, + }; + if best.as_ref() < Some(&pair) { + best = Some(pair); + } + } + } + } + + best.filter(|candidate| candidate.score.count > 0) + .map(|candidate| candidate.kind.0) + } +} + +/// Places all elements which satisfy the predicate at the beginning of the +/// slice, and all elements which don't at the end. Returns the number of +/// elements in the first partition. +/// +/// This function runs in time linear in the number of elements, and calls +/// the predicate exactly once per element. If either partition is empty, no +/// writes will occur in the slice, so it's okay to call this frequently with +/// predicates that we expect won't match anything. +fn partition_in_place(xs: &mut [T], mut pred: impl FnMut(&T) -> bool) -> usize { + let mut iter = xs.iter_mut(); + let mut partition_point = 0; + while let Some(a) = iter.next() { + if pred(a) { + partition_point += 1; + } else { + // `a` belongs in the partition at the end. If there's some later + // element `b` that belongs in the partition at the beginning, + // swap them. Working backwards from the end establishes the loop + // invariant that both ends of the array are partitioned correctly, + // and only the middle needs to be checked. + while let Some(b) = iter.next_back() { + if pred(b) { + std::mem::swap(a, b); + partition_point += 1; + break; + } + } + } + } + partition_point +} + +fn group_by_mut( + mut xs: &mut [T], + mut pred: impl FnMut(&T, &T) -> bool, +) -> impl Iterator { + std::iter::from_fn(move || { + if xs.is_empty() { + None + } else { + let mid = xs + .windows(2) + .position(|w| !pred(&w[0], &w[1])) + .map_or(xs.len(), |x| x + 1); + let slice = std::mem::take(&mut xs); + let (group, rest) = slice.split_at_mut(mid); + xs = rest; + Some(group) + } + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_group_mut() { + let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + let mut iter = group_by_mut(slice, |a, b| a == b); + assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next(), None); + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/stablemapset.rs b/deps/crates/vendor/cranelift-isle/src/stablemapset.rs new file mode 100644 index 00000000000000..6b2c283cf3c9ee --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/stablemapset.rs @@ -0,0 +1,91 @@ +//! Implementations of hashmap and hashset that asvoid observing non-determinism +//! in iteration order. In a separate module so the compiler can prevent access to the internal +//! implementation details. + +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; +use std::hash::Hash; +use std::ops::Index; + +/// A wrapper around a [HashSet] which prevents accidentally observing the non-deterministic +/// iteration order. +#[derive(Clone, Debug, Default)] +pub struct StableSet(HashSet); + +impl StableSet { + pub(crate) fn new() -> Self { + StableSet(HashSet::new()) + } +} + +impl StableSet { + /// Adds a value to the set. Returns whether the value was newly inserted. + pub fn insert(&mut self, val: T) -> bool { + self.0.insert(val) + } + + /// Returns true if the set contains a value. + pub fn contains(&self, val: &T) -> bool { + self.0.contains(val) + } +} + +/// A wrapper around a [HashMap] which prevents accidentally observing the non-deterministic +/// iteration order. +#[derive(Clone, Debug)] +pub struct StableMap(HashMap); + +impl StableMap { + pub(crate) fn new() -> Self { + StableMap(HashMap::new()) + } + + pub(crate) fn len(&self) -> usize { + self.0.len() + } +} + +// NOTE: Can't auto-derive this +impl Default for StableMap { + fn default() -> Self { + StableMap(HashMap::new()) + } +} + +impl StableMap { + pub(crate) fn insert(&mut self, k: K, v: V) -> Option { + self.0.insert(k, v) + } + + pub(crate) fn contains_key(&self, k: &K) -> bool { + self.0.contains_key(k) + } + + pub(crate) fn get(&self, k: &K) -> Option<&V> { + self.0.get(k) + } + + pub(crate) fn entry(&mut self, k: K) -> Entry { + self.0.entry(k) + } +} + +impl Index<&K> for StableMap { + type Output = V; + + fn index(&self, index: &K) -> &Self::Output { + self.0.index(index) + } +} + +impl From> for StableMap { + fn from(map: HashMap) -> Self { + StableMap(map) + } +} + +impl FromIterator<(K, V)> for StableMap { + fn from_iter>(iter: T) -> Self { + StableMap(HashMap::from_iter(iter)) + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/trie_again.rs b/deps/crates/vendor/cranelift-isle/src/trie_again.rs new file mode 100644 index 00000000000000..8db8d0ea67496f --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/trie_again.rs @@ -0,0 +1,722 @@ +//! A strongly-normalizing intermediate representation for ISLE rules. This representation is chosen +//! to closely reflect the operations we can implement in Rust, to make code generation easy. +use crate::disjointsets::DisjointSets; +use crate::error::{Error, Span}; +use crate::lexer::Pos; +use crate::sema; +use crate::stablemapset::StableSet; +use std::collections::{hash_map::Entry, HashMap}; + +/// A field index in a tuple or an enum variant. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct TupleIndex(u8); +/// A hash-consed identifier for a binding, stored in a [RuleSet]. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct BindingId(u16); + +impl std::convert::TryFrom for TupleIndex { + type Error = >::Error; + + fn try_from(value: usize) -> Result { + Ok(TupleIndex(value.try_into()?)) + } +} + +impl std::convert::TryFrom for BindingId { + type Error = >::Error; + + fn try_from(value: usize) -> Result { + Ok(BindingId(value.try_into()?)) + } +} + +impl TupleIndex { + /// Get the index of this field. + pub fn index(self) -> usize { + self.0.into() + } +} + +impl BindingId { + /// Get the index of this id. + pub fn index(self) -> usize { + self.0.into() + } +} + +/// Bindings are anything which can be bound to a variable name in Rust. This includes expressions, +/// such as constants or function calls; but it also includes names bound in pattern matches. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum Binding { + /// Evaluates to the given boolean literal. + ConstBool { + /// The constant value. + val: bool, + /// The constant's type. + ty: sema::TypeId, + }, + /// Evaluates to the given integer literal. + ConstInt { + /// The constant value. + val: i128, + /// The constant's type. Unsigned types preserve the representation of `val`, not its value. + ty: sema::TypeId, + }, + /// Evaluates to the given primitive Rust value. + ConstPrim { + /// The constant value. + val: sema::Sym, + }, + /// One of the arguments to the top-level function. + Argument { + /// Which of the function's arguments is this? + index: TupleIndex, + }, + /// The result of calling an external extractor. + Extractor { + /// Which extractor should be called? + term: sema::TermId, + /// What expression should be passed to the extractor? + parameter: BindingId, + }, + /// The result of calling an external constructor. + Constructor { + /// Which constructor should be called? + term: sema::TermId, + /// What expressions should be passed to the constructor? + parameters: Box<[BindingId]>, + /// For impure constructors, a unique number for each use of this term. Always 0 for pure + /// constructors. + instance: u32, + }, + /// The result of getting one value from a multi-constructor or multi-extractor. + Iterator { + /// Which expression produced the iterator that this consumes? + source: BindingId, + }, + /// The result of constructing an enum variant. + MakeVariant { + /// Which enum type should be constructed? + ty: sema::TypeId, + /// Which variant of that enum should be constructed? + variant: sema::VariantId, + /// What expressions should be provided for this variant's fields? + fields: Box<[BindingId]>, + }, + /// Pattern-match one of the previous bindings against an enum variant and produce a new binding + /// from one of its fields. There must be a corresponding [Constraint::Variant] for each + /// `source`/`variant` pair that appears in some `MatchVariant` binding. + MatchVariant { + /// Which binding is being matched? + source: BindingId, + /// Which enum variant are we pulling binding sites from? This is somewhat redundant with + /// information in a corresponding [Constraint]. However, it must be here so that different + /// enum variants aren't hash-consed into the same binding site. + variant: sema::VariantId, + /// Which field of this enum variant are we projecting out? Although ISLE uses named fields, + /// we track them by index for constant-time comparisons. The [sema::TypeEnv] can be used to + /// get the field names. + field: TupleIndex, + }, + /// The result of constructing an Option::Some variant. + MakeSome { + /// Contained expression. + inner: BindingId, + }, + /// Pattern-match one of the previous bindings against `Option::Some` and produce a new binding + /// from its contents. There must be a corresponding [Constraint::Some] for each `source` that + /// appears in a `MatchSome` binding. (This currently only happens with external extractors.) + MatchSome { + /// Which binding is being matched? + source: BindingId, + }, + /// Pattern-match one of the previous bindings against a tuple and produce a new binding from + /// one of its fields. This is an irrefutable pattern match so there is no corresponding + /// [Constraint]. (This currently only happens with external extractors.) + MatchTuple { + /// Which binding is being matched? + source: BindingId, + /// Which tuple field are we projecting out? + field: TupleIndex, + }, +} + +/// Pattern matches which can fail. Some binding sites are the result of successfully matching a +/// constraint. A rule applies constraints to binding sites to determine whether the rule matches. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Constraint { + /// The value must match this enum variant. + Variant { + /// Which enum type is being matched? This is implied by the binding where the constraint is + /// applied, but recorded here for convenience. + ty: sema::TypeId, + /// Which enum variant must this binding site match to satisfy the rule? + variant: sema::VariantId, + /// Number of fields in this variant of this enum. This is recorded in the constraint for + /// convenience, to avoid needing to look up the variant in a [sema::TypeEnv]. + fields: TupleIndex, + }, + /// The value must equal this boolean literal. + ConstBool { + /// The constant value. + val: bool, + /// The constant's type. + ty: sema::TypeId, + }, + /// The value must equal this integer literal. + ConstInt { + /// The constant value. + val: i128, + /// The constant's type. Unsigned types preserve the representation of `val`, not its value. + ty: sema::TypeId, + }, + /// The value must equal this Rust primitive value. + ConstPrim { + /// The constant value. + val: sema::Sym, + }, + /// The value must be an `Option::Some`, from a fallible extractor. + Some, +} + +/// A term-rewriting rule. All [BindingId]s are only meaningful in the context of the [RuleSet] that +/// contains this rule. +#[derive(Debug, Default)] +pub struct Rule { + /// Where was this rule defined? + pub pos: Pos, + /// All of these bindings must match the given constraints for this rule to apply. Note that + /// within a single rule, if a binding site must match two different constraints, then the rule + /// can never match. + constraints: HashMap, + /// Sets of bindings which must be equal for this rule to match. + pub equals: DisjointSets, + /// These bindings are from multi-terms which need to be evaluated in this rule. + pub iterators: StableSet, + /// If other rules apply along with this one, the one with the highest numeric priority is + /// evaluated. If multiple applicable rules have the same priority, that's an overlap error. + pub prio: i64, + /// If this rule applies, these side effects should be evaluated before returning. + pub impure: Vec, + /// If this rule applies, the top-level term should evaluate to this expression. + pub result: BindingId, +} + +/// Records whether a given pair of rules can both match on some input. +#[derive(Debug, Eq, PartialEq)] +pub enum Overlap { + /// There is no input on which this pair of rules can both match. + No, + /// There is at least one input on which this pair of rules can both match. + Yes { + /// True if every input accepted by one rule is also accepted by the other. This does not + /// indicate which rule is more general and in fact the rules could match exactly the same + /// set of inputs. You can work out which by comparing `total_constraints()` in both rules: + /// The more general rule has fewer constraints. + subset: bool, + }, +} + +/// A collection of [Rule]s, along with hash-consed [Binding]s for all of them. +#[derive(Debug, Default)] +pub struct RuleSet { + /// The [Rule]s for a single [sema::Term]. + pub rules: Vec, + /// The bindings identified by [BindingId]s within rules. + pub bindings: Vec, + /// Intern table for de-duplicating [Binding]s. + binding_map: HashMap, +} + +/// Construct a [RuleSet] for each term in `termenv` that has rules. +pub fn build(termenv: &sema::TermEnv) -> (Vec<(sema::TermId, RuleSet)>, Vec) { + let mut errors = Vec::new(); + let mut term = HashMap::new(); + for rule in termenv.rules.iter() { + term.entry(rule.root_term) + .or_insert_with(RuleSetBuilder::default) + .add_rule(rule, termenv, &mut errors); + } + + // The `term` hash map may return terms in any order. Sort them to ensure that we produce the + // same output every time when given the same ISLE source. Rules are added to terms in `RuleId` + // order, so it's not necessary to sort within a `RuleSet`. + let mut result: Vec<_> = term + .into_iter() + .map(|(term, builder)| (term, builder.rules)) + .collect(); + result.sort_unstable_by_key(|(term, _)| *term); + + (result, errors) +} + +impl RuleSet { + /// Returns the [BindingId] corresponding to the given [Binding] within this rule-set, if any. + pub fn find_binding(&self, binding: &Binding) -> Option { + self.binding_map.get(binding).copied() + } +} + +impl Binding { + /// Returns the binding sites which must be evaluated before this binding. + pub fn sources(&self) -> &[BindingId] { + match self { + Binding::ConstBool { .. } => &[][..], + Binding::ConstInt { .. } => &[][..], + Binding::ConstPrim { .. } => &[][..], + Binding::Argument { .. } => &[][..], + Binding::Extractor { parameter, .. } => std::slice::from_ref(parameter), + Binding::Constructor { parameters, .. } => ¶meters[..], + Binding::Iterator { source } => std::slice::from_ref(source), + Binding::MakeVariant { fields, .. } => &fields[..], + Binding::MatchVariant { source, .. } => std::slice::from_ref(source), + Binding::MakeSome { inner } => std::slice::from_ref(inner), + Binding::MatchSome { source } => std::slice::from_ref(source), + Binding::MatchTuple { source, .. } => std::slice::from_ref(source), + } + } +} + +impl Constraint { + /// Return the nested [Binding]s from matching the given [Constraint] against the given [BindingId]. + pub fn bindings_for(self, source: BindingId) -> Vec { + match self { + // These constraints never introduce any bindings. + Constraint::ConstBool { .. } + | Constraint::ConstInt { .. } + | Constraint::ConstPrim { .. } => vec![], + Constraint::Some => vec![Binding::MatchSome { source }], + Constraint::Variant { + variant, fields, .. + } => (0..fields.0) + .map(TupleIndex) + .map(|field| Binding::MatchVariant { + source, + variant, + field, + }) + .collect(), + } + } +} + +impl Rule { + /// Returns whether a given pair of rules can both match on some input, and if so, whether + /// either matches a subset of the other's inputs. If this function returns `No`, then the two + /// rules definitely do not overlap. However, it may return `Yes` in cases where the rules can't + /// overlap in practice, or where this analysis is not yet precise enough to decide. + pub fn may_overlap(&self, other: &Rule) -> Overlap { + // Two rules can't overlap if, for some binding site in the intersection of their + // constraints, the rules have different constraints: an input can't possibly match both + // rules then. If the rules do overlap, and one has a subset of the constraints of the + // other, then the less-constrained rule matches every input that the more-constrained rule + // matches, and possibly more. We test for both conditions at once, with the observation + // that if the intersection of two sets is equal to the smaller set, then it's a subset. So + // the outer loop needs to go over the rule with fewer constraints in order to correctly + // identify if it's a subset of the other rule. Also, that way around is faster. + let (small, big) = if self.constraints.len() <= other.constraints.len() { + (self, other) + } else { + (other, self) + }; + + // TODO: nonlinear constraints complicate the subset check + // For the purpose of overlap checking, equality constraints act like other constraints, in + // that they can cause rules to not overlap. However, because we don't have a concrete + // pattern to compare, the analysis to prove that is complicated. For now, we approximate + // the result. If either rule has nonlinear constraints, conservatively report that neither + // is a subset of the other. Note that this does not disagree with the doc comment for + // `Overlap::Yes { subset }` which says to use `total_constraints` to disambiguate, since if + // we return `subset: true` here, `equals` is empty for both rules, so `total_constraints()` + // equals `constraints.len()`. + let mut subset = small.equals.is_empty() && big.equals.is_empty(); + + for (binding, a) in small.constraints.iter() { + if let Some(b) = big.constraints.get(binding) { + if a != b { + // If any binding site is constrained differently by both rules then there is + // no input where both rules can match. + return Overlap::No; + } + // Otherwise both are constrained in the same way at this binding site. That doesn't + // rule out any possibilities for what inputs the rules accept. + } else { + // The `big` rule's inputs are a subset of the `small` rule's inputs if every + // constraint in `small` is exactly matched in `big`. But we found a counterexample. + subset = false; + } + } + Overlap::Yes { subset } + } + + /// Returns the total number of binding sites which this rule constrains, with either a concrete + /// pattern or an equality constraint. + pub fn total_constraints(&self) -> usize { + // Because of `normalize_equivalence_classes`, these two sets don't overlap, so the size of + // the union is the sum of their sizes. + self.constraints.len() + self.equals.len() + } + + /// Returns the constraint that the given binding site must satisfy for this rule to match, if + /// there is one. + pub fn get_constraint(&self, source: BindingId) -> Option { + self.constraints.get(&source).copied() + } + + fn set_constraint( + &mut self, + source: BindingId, + constraint: Constraint, + ) -> Result<(), UnreachableError> { + match self.constraints.entry(source) { + Entry::Occupied(entry) => { + if entry.get() != &constraint { + return Err(UnreachableError { + pos: self.pos, + constraint_a: *entry.get(), + constraint_b: constraint, + }); + } + } + Entry::Vacant(entry) => { + entry.insert(constraint); + } + } + Ok(()) + } +} + +#[derive(Debug)] +struct UnreachableError { + pos: Pos, + constraint_a: Constraint, + constraint_b: Constraint, +} + +#[derive(Debug, Default)] +struct RuleSetBuilder { + current_rule: Rule, + impure_instance: u32, + unreachable: Vec, + rules: RuleSet, +} + +impl RuleSetBuilder { + fn add_rule(&mut self, rule: &sema::Rule, termenv: &sema::TermEnv, errors: &mut Vec) { + self.impure_instance = 0; + self.current_rule.pos = rule.pos; + self.current_rule.prio = rule.prio; + self.current_rule.result = rule.visit(self, termenv); + if termenv.terms[rule.root_term.index()].is_partial() { + self.current_rule.result = self.dedup_binding(Binding::MakeSome { + inner: self.current_rule.result, + }); + } + self.normalize_equivalence_classes(); + let rule = std::mem::take(&mut self.current_rule); + + if self.unreachable.is_empty() { + self.rules.rules.push(rule); + } else { + // If this rule can never match, drop it so it doesn't affect overlap checking. + errors.extend( + self.unreachable + .drain(..) + .map(|err| Error::UnreachableError { + msg: format!( + "rule requires binding to match both {:?} and {:?}", + err.constraint_a, err.constraint_b + ), + span: Span::new_single(err.pos), + }), + ) + } + } + + /// Establish the invariant that a binding site can have a concrete constraint in `constraints`, + /// or an equality constraint in `equals`, but not both. This is useful because overlap checking + /// is most effective on concrete constraints, and also because it exposes more rule structure + /// for codegen. + /// + /// If a binding site is constrained and also required to be equal to another binding site, then + /// copy the constraint and push the equality inside it. For example: + /// - `(term x @ 2 x)` is rewritten to `(term 2 2)` + /// - `(term x @ (T.A _ _) x)` is rewritten to `(term (T.A y z) (T.A y z))` + /// + /// In the latter case, note that every field of `T.A` has been replaced with a fresh variable + /// and each of the copies are set equal. + /// + /// If several binding sites are supposed to be equal but they each have conflicting constraints + /// then this rule is unreachable. For example, `(term x @ 2 (and x 3))` requires both arguments + /// to be equal but also requires them to match both 2 and 3, which can't happen for any input. + /// + /// We could do this incrementally, while building the rule. The implementation is nearly + /// identical but, having tried both ways, it's slightly easier to think about this as a + /// separate pass. Also, batching up this work should be slightly faster if there are multiple + /// binding sites set equal to each other. + fn normalize_equivalence_classes(&mut self) { + // First, find all the constraints that need to be copied to other binding sites in their + // respective equivalence classes. Note: do not remove these constraints here! Yes, we'll + // put them back later, but we rely on still having them around so that + // `set_constraint` can detect conflicting constraints. + let mut deferred_constraints = Vec::new(); + for (&binding, &constraint) in self.current_rule.constraints.iter() { + if let Some(root) = self.current_rule.equals.find_mut(binding) { + deferred_constraints.push((root, constraint)); + } + } + + // Pick one constraint and propagate it through its equivalence class. If there are no + // errors then it doesn't matter what order we do this in, because that means that any + // redundant constraints on an equivalence class were equal. We can write equal values into + // the constraint map in any order and get the same result. If there were errors, we aren't + // going to generate code from this rule, so order only affects how conflicts are reported. + while let Some((current, constraint)) = deferred_constraints.pop() { + // Remove the entire equivalence class and instead add copies of this constraint to + // every binding site in the class. If there are constraints on other binding sites in + // this class, then when we try to copy this constraint to those binding sites, + // `set_constraint` will check that the constraints are equal and record an appropriate + // error otherwise. + // + // Later, we'll re-visit those other binding sites because they're still in + // `deferred_constraints`, but `set` will be empty because we already deleted the + // equivalence class the first time we encountered it. + let set = self.current_rule.equals.remove_set_of(current); + if let Some((&base, rest)) = set.split_first() { + let mut defer = |this: &Self, binding| { + // We're adding equality constraints to binding sites that may not have had + // one already. If that binding site already had a concrete constraint, then + // we need to "recursively" propagate that constraint through the new + // equivalence class too. + if let Some(constraint) = this.current_rule.get_constraint(binding) { + deferred_constraints.push((binding, constraint)); + } + }; + + // If this constraint introduces nested binding sites, make the fields of those + // binding sites equal instead. Arbitrarily pick one member of `set` to set all the + // others equal to. If there are existing constraints on the new binding sites, copy + // those around the new equivalence classes too. + let base_fields = self.set_constraint(base, constraint); + base_fields.iter().for_each(|&x| defer(self, x)); + for &b in rest { + for (&x, y) in base_fields.iter().zip(self.set_constraint(b, constraint)) { + defer(self, y); + self.current_rule.equals.merge(x, y); + } + } + } + } + } + + fn dedup_binding(&mut self, binding: Binding) -> BindingId { + if let Some(binding) = self.rules.binding_map.get(&binding) { + *binding + } else { + let id = BindingId(self.rules.bindings.len().try_into().unwrap()); + self.rules.bindings.push(binding.clone()); + self.rules.binding_map.insert(binding, id); + id + } + } + + fn set_constraint(&mut self, input: BindingId, constraint: Constraint) -> Vec { + if let Err(e) = self.current_rule.set_constraint(input, constraint) { + self.unreachable.push(e); + } + constraint + .bindings_for(input) + .into_iter() + .map(|binding| self.dedup_binding(binding)) + .collect() + } +} + +impl sema::PatternVisitor for RuleSetBuilder { + type PatternId = BindingId; + + fn add_match_equal(&mut self, a: BindingId, b: BindingId, _ty: sema::TypeId) { + // If both bindings represent the same binding site, they're implicitly equal. + if a != b { + self.current_rule.equals.merge(a, b); + } + } + + fn add_match_bool(&mut self, input: BindingId, ty: sema::TypeId, val: bool) { + let bindings = self.set_constraint(input, Constraint::ConstBool { val, ty }); + debug_assert_eq!(bindings, &[]); + } + + fn add_match_int(&mut self, input: BindingId, ty: sema::TypeId, val: i128) { + let bindings = self.set_constraint(input, Constraint::ConstInt { val, ty }); + debug_assert_eq!(bindings, &[]); + } + + fn add_match_prim(&mut self, input: BindingId, _ty: sema::TypeId, val: sema::Sym) { + let bindings = self.set_constraint(input, Constraint::ConstPrim { val }); + debug_assert_eq!(bindings, &[]); + } + + fn add_match_variant( + &mut self, + input: BindingId, + input_ty: sema::TypeId, + arg_tys: &[sema::TypeId], + variant: sema::VariantId, + ) -> Vec { + let fields = TupleIndex(arg_tys.len().try_into().unwrap()); + self.set_constraint( + input, + Constraint::Variant { + fields, + ty: input_ty, + variant, + }, + ) + } + + fn add_extract( + &mut self, + input: BindingId, + _input_ty: sema::TypeId, + output_tys: Vec, + term: sema::TermId, + infallible: bool, + multi: bool, + ) -> Vec { + let source = self.dedup_binding(Binding::Extractor { + term, + parameter: input, + }); + + // If the extractor is fallible, build a pattern and constraint for `Some` + let source = if multi { + self.current_rule.iterators.insert(source); + self.dedup_binding(Binding::Iterator { source }) + } else if infallible { + source + } else { + let bindings = self.set_constraint(source, Constraint::Some); + debug_assert_eq!(bindings.len(), 1); + bindings[0] + }; + + // If the extractor has multiple outputs, create a separate binding for each + match output_tys.len().try_into().unwrap() { + 0 => vec![], + 1 => vec![source], + outputs => (0..outputs) + .map(TupleIndex) + .map(|field| self.dedup_binding(Binding::MatchTuple { source, field })) + .collect(), + } + } +} + +impl sema::ExprVisitor for RuleSetBuilder { + type ExprId = BindingId; + + fn add_const_bool(&mut self, ty: sema::TypeId, val: bool) -> BindingId { + self.dedup_binding(Binding::ConstBool { val, ty }) + } + + fn add_const_int(&mut self, ty: sema::TypeId, val: i128) -> BindingId { + self.dedup_binding(Binding::ConstInt { val, ty }) + } + + fn add_const_prim(&mut self, _ty: sema::TypeId, val: sema::Sym) -> BindingId { + self.dedup_binding(Binding::ConstPrim { val }) + } + + fn add_create_variant( + &mut self, + inputs: Vec<(BindingId, sema::TypeId)>, + ty: sema::TypeId, + variant: sema::VariantId, + ) -> BindingId { + self.dedup_binding(Binding::MakeVariant { + ty, + variant, + fields: inputs.into_iter().map(|(expr, _)| expr).collect(), + }) + } + + fn add_construct( + &mut self, + inputs: Vec<(BindingId, sema::TypeId)>, + _ty: sema::TypeId, + term: sema::TermId, + pure: bool, + infallible: bool, + multi: bool, + ) -> BindingId { + let instance = if pure { + 0 + } else { + self.impure_instance += 1; + self.impure_instance + }; + let source = self.dedup_binding(Binding::Constructor { + term, + parameters: inputs.into_iter().map(|(expr, _)| expr).collect(), + instance, + }); + + // If the constructor is fallible, build a pattern for `Some`, but not a constraint. If the + // constructor is on the right-hand side of a rule then its failure is not considered when + // deciding which rule to evaluate. Corresponding constraints are only added if this + // expression is subsequently used as a pattern; see `expr_as_pattern`. + let source = if multi { + self.current_rule.iterators.insert(source); + self.dedup_binding(Binding::Iterator { source }) + } else if infallible { + source + } else { + self.dedup_binding(Binding::MatchSome { source }) + }; + + if !pure { + self.current_rule.impure.push(source); + } + + source + } +} + +impl sema::RuleVisitor for RuleSetBuilder { + type PatternVisitor = Self; + type ExprVisitor = Self; + type Expr = BindingId; + + fn add_arg(&mut self, index: usize, _ty: sema::TypeId) -> BindingId { + let index = TupleIndex(index.try_into().unwrap()); + self.dedup_binding(Binding::Argument { index }) + } + + fn add_pattern(&mut self, visitor: F) { + visitor(self) + } + + fn add_expr(&mut self, visitor: F) -> BindingId + where + F: FnOnce(&mut Self) -> sema::VisitedExpr, + { + visitor(self).value + } + + fn expr_as_pattern(&mut self, expr: BindingId) -> BindingId { + let mut todo = vec![expr]; + while let Some(expr) = todo.pop() { + let expr = &self.rules.bindings[expr.index()]; + todo.extend_from_slice(expr.sources()); + if let &Binding::MatchSome { source } = expr { + let _ = self.set_constraint(source, Constraint::Some); + } + } + expr + } + + fn pattern_as_expr(&mut self, pattern: BindingId) -> BindingId { + pattern + } +} diff --git a/deps/crates/vendor/cranelift-isle/tests/run_tests.rs b/deps/crates/vendor/cranelift-isle/tests/run_tests.rs new file mode 100644 index 00000000000000..5fbabdca75ed4e --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/tests/run_tests.rs @@ -0,0 +1,77 @@ +//! Helper for autogenerated unit tests. + +use cranelift_isle::compile; +use cranelift_isle::error::Errors; + +fn build(filename: &str) -> Result { + compile::from_files(&[filename], &Default::default()) +} + +pub fn run_pass(filename: &str) { + if let Err(err) = build(filename) { + panic!("pass test failed:\n{err:?}"); + } +} + +pub fn run_fail(filename: &str) { + match build(filename) { + Ok(_) => panic!("test {filename} passed unexpectedly"), + Err(err) => { + // Log the actual errors for use with `cargo test -- --nocapture` + println!("failed, as expected:\n{err:?}"); + } + } +} + +fn build_and_link_isle(isle_filename: &str) -> (tempfile::TempDir, std::path::PathBuf) { + let tempdir = tempfile::tempdir().unwrap(); + let code = build(isle_filename).unwrap(); + + let isle_filename_base = std::path::Path::new(isle_filename) + .file_stem() + .unwrap() + .to_str() + .unwrap() + .to_string(); + let isle_generated_code = tempdir + .path() + .to_path_buf() + .join(isle_filename_base.clone() + ".rs"); + std::fs::write(isle_generated_code, code).unwrap(); + + let rust_filename = isle_filename.replace(".isle", "").to_string() + "_main.rs"; + let rust_filename_base = std::path::Path::new(&rust_filename).file_name().unwrap(); + let rust_driver = tempdir.path().to_path_buf().join(&rust_filename_base); + println!("copying {rust_filename} to {rust_driver:?}"); + std::fs::copy(&rust_filename, &rust_driver).unwrap(); + + let output = tempdir.path().to_path_buf().join("out"); + + let mut rustc = std::process::Command::new("rustc") + .arg(&rust_driver) + .arg("-o") + .arg(output.clone()) + .spawn() + .unwrap(); + assert!(rustc.wait().unwrap().success()); + + (tempdir, output) +} + +pub fn run_link(isle_filename: &str) { + build_and_link_isle(isle_filename); +} + +pub fn run_run(isle_filename: &str) { + let (_tempdir, exe) = build_and_link_isle(isle_filename); + + assert!(std::process::Command::new(exe) + .spawn() + .unwrap() + .wait() + .unwrap() + .success()); +} + +// Generated by build.rs. +include!(concat!(env!("OUT_DIR"), "/isle_tests.rs")); diff --git a/deps/crates/vendor/cranelift-module/.cargo-checksum.json b/deps/crates/vendor/cranelift-module/.cargo-checksum.json new file mode 100644 index 00000000000000..4bc9aaec001d4a --- /dev/null +++ b/deps/crates/vendor/cranelift-module/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"e75595825d6c3427218a4573b7969b3d29ed6032483c4448c8fc2edd1571ab9d","Cargo.lock":"3568bcc716cd669ae1bace73085f431367b1769f1cc5a560f416c5a205ec43f7","Cargo.toml":"39ec980310144c54903a1b8fb12702361718bdf27940e035916c7bae52d0a9f5","Cargo.toml.orig":"34b1eeb78642d8979b5440cca91d7ddda8c665854acfa556880540c41168527e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"f3fe085fc51ff25ef00fb460dca785e431629aee5b178a392c61699348f81ca9","src/data_context.rs":"62aac34913b32556f75838d0041b144c51d4e323b4ab1490b8e1cfbc2df10c43","src/lib.rs":"a990e5ff02d5f2770d6a49723551ad8aec722137e75b1738ce44af9bffc483df","src/module.rs":"2b62846fb4c7bf3aad021bb914f8d48ebcd4e1548cf551c29b3d8cd7ddcddffe","src/traps.rs":"74a12f48fed59d700da8046705250403279b1276cb4f1c517557f06aae8d7b00"},"package":"4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-module/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-module/.cargo_vcs_info.json new file mode 100644 index 00000000000000..5a32e5925e39e1 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/module" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-module/Cargo.lock b/deps/crates/vendor/cranelift-module/Cargo.lock new file mode 100644 index 00000000000000..b2765e27e0d44f --- /dev/null +++ b/deps/crates/vendor/cranelift-module/Cargo.lock @@ -0,0 +1,275 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "rustc-hash", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" + +[[package]] +name = "cranelift-module" +version = "0.116.1" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "hashbrown 0.14.3", + "serde", + "serde_derive", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regalloc2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", + "log", + "rustc-hash", + "serde", + "smallvec", +] + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/deps/crates/vendor/cranelift-module/Cargo.toml b/deps/crates/vendor/cranelift-module/Cargo.toml new file mode 100644 index 00000000000000..db176715206d8e --- /dev/null +++ b/deps/crates/vendor/cranelift-module/Cargo.toml @@ -0,0 +1,108 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-module" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Support for linking functions and data with Cranelift" +documentation = "https://docs.rs/cranelift-module" +readme = "README.md" +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_module" +path = "src/lib.rs" + +[dependencies.anyhow] +version = "1.0.93" +features = ["std"] +default-features = false + +[dependencies.cranelift-codegen] +version = "0.116.1" +features = [ + "std", + "unwind", +] +default-features = false + +[dependencies.cranelift-control] +version = "0.116.1" + +[dependencies.hashbrown] +version = "0.14" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.215" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde_derive] +version = "1.0.188" +optional = true + +[features] +core = [ + "hashbrown", + "cranelift-codegen/core", +] +default = ["std"] +enable-serde = [ + "serde", + "serde_derive", + "cranelift-codegen/enable-serde", +] +std = ["cranelift-codegen/std"] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-module/Cargo.toml.orig b/deps/crates/vendor/cranelift-module/Cargo.toml.orig new file mode 100644 index 00000000000000..cf79b1f5746118 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/Cargo.toml.orig @@ -0,0 +1,31 @@ +[package] +name = "cranelift-module" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +description = "Support for linking functions and data with Cranelift" +repository = "https://github.com/bytecodealliance/wasmtime" +documentation = "https://docs.rs/cranelift-module" +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +cranelift-codegen = { workspace = true } +cranelift-control = { workspace = true } +hashbrown = { workspace = true, optional = true } +anyhow = { workspace = true, features = ['std'] } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } + +[features] +default = ["std"] +std = ["cranelift-codegen/std"] +core = ["hashbrown", "cranelift-codegen/core"] + +# For dependent crates that want to serialize some parts of cranelift +enable-serde = ["serde", "serde_derive", "cranelift-codegen/enable-serde"] diff --git a/deps/crates/vendor/cranelift-module/LICENSE b/deps/crates/vendor/cranelift-module/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-module/README.md b/deps/crates/vendor/cranelift-module/README.md new file mode 100644 index 00000000000000..09caf7e2705ed8 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/README.md @@ -0,0 +1,17 @@ +This crate provides module-level functionality, which allow multiple +functions and data to be emitted with +[Cranelift](https://crates.io/crates/cranelift) and then linked together. + +This crate is structured as an optional layer on top of cranelift-codegen. +It provides additional functionality, such as linking, however users that +require greater flexibility don't need to use it. + +A module is a collection of functions and data objects that are linked +together. The `Module` trait that defines a common interface for various kinds +of modules. Most users will use one of the following `Module` implementations: + + - `JITModule`, provided by [cranelift-jit], which JITs code to memory for direct execution. + - `ObjectModule`, provided by [cranelift-object], which emits native object files. + +[cranelift-jit]: https://crates.io/crates/cranelift-jit +[cranelift-object]: https://crates.io/crates/cranelift-object diff --git a/deps/crates/vendor/cranelift-module/src/data_context.rs b/deps/crates/vendor/cranelift-module/src/data_context.rs new file mode 100644 index 00000000000000..b55f96fcd3c5ee --- /dev/null +++ b/deps/crates/vendor/cranelift-module/src/data_context.rs @@ -0,0 +1,233 @@ +//! Defines `DataContext`. + +use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc}; +use cranelift_codegen::entity::PrimaryMap; +use cranelift_codegen::ir; +use std::borrow::ToOwned; +use std::boxed::Box; +use std::string::String; +use std::vec::Vec; + +use crate::module::ModuleReloc; +use crate::ModuleRelocTarget; + +/// This specifies how data is to be initialized. +#[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub enum Init { + /// This indicates that no initialization has been specified yet. + Uninitialized, + /// Initialize the data with all zeros. + Zeros { + /// The size of the data. + size: usize, + }, + /// Initialize the data with the specified contents. + Bytes { + /// The contents, which also implies the size of the data. + contents: Box<[u8]>, + }, +} + +impl Init { + /// Return the size of the data to be initialized. + pub fn size(&self) -> usize { + match *self { + Self::Uninitialized => panic!("data size not initialized yet"), + Self::Zeros { size } => size, + Self::Bytes { ref contents } => contents.len(), + } + } +} + +/// A description of a data object. +#[derive(Clone, Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct DataDescription { + /// How the data should be initialized. + pub init: Init, + /// External function declarations. + pub function_decls: PrimaryMap, + /// External data object declarations. + pub data_decls: PrimaryMap, + /// Function addresses to write at specified offsets. + pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>, + /// Data addresses to write at specified offsets. + pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>, + /// Object file section + pub custom_segment_section: Option<(String, String)>, + /// Alignment in bytes. `None` means that the default alignment of the respective module should + /// be used. + pub align: Option, +} + +impl DataDescription { + /// Allocate a new `DataDescription`. + pub fn new() -> Self { + Self { + init: Init::Uninitialized, + function_decls: PrimaryMap::new(), + data_decls: PrimaryMap::new(), + function_relocs: vec![], + data_relocs: vec![], + custom_segment_section: None, + align: None, + } + } + + /// Clear all data structures in this `DataDescription`. + pub fn clear(&mut self) { + self.init = Init::Uninitialized; + self.function_decls.clear(); + self.data_decls.clear(); + self.function_relocs.clear(); + self.data_relocs.clear(); + self.custom_segment_section = None; + self.align = None; + } + + /// Define a zero-initialized object with the given size. + pub fn define_zeroinit(&mut self, size: usize) { + debug_assert_eq!(self.init, Init::Uninitialized); + self.init = Init::Zeros { size }; + } + + /// Define an object initialized with the given contents. + /// + /// TODO: Can we avoid a Box here? + pub fn define(&mut self, contents: Box<[u8]>) { + debug_assert_eq!(self.init, Init::Uninitialized); + self.init = Init::Bytes { contents }; + } + + /// Override the segment/section for data, only supported on Object backend + pub fn set_segment_section(&mut self, seg: &str, sec: &str) { + self.custom_segment_section = Some((seg.to_owned(), sec.to_owned())) + } + + /// Set the alignment for data. The alignment must be a power of two. + pub fn set_align(&mut self, align: u64) { + assert!(align.is_power_of_two()); + self.align = Some(align); + } + + /// Declare an external function import. + /// + /// Users of the `Module` API generally should call + /// `Module::declare_func_in_data` instead, as it takes care of generating + /// the appropriate `ExternalName`. + pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef { + self.function_decls.push(name) + } + + /// Declares a global value import. + /// + /// TODO: Rename to import_data? + /// + /// Users of the `Module` API generally should call + /// `Module::declare_data_in_data` instead, as it takes care of generating + /// the appropriate `ExternalName`. + pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue { + self.data_decls.push(name) + } + + /// Write the address of `func` into the data at offset `offset`. + pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) { + self.function_relocs.push((offset, func)) + } + + /// Write the address of `data` into the data at offset `offset`. + pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) { + self.data_relocs.push((offset, data, addend)) + } + + /// An iterator over all relocations of the data object. + pub fn all_relocs<'a>( + &'a self, + pointer_reloc: Reloc, + ) -> impl Iterator + 'a { + let func_relocs = self + .function_relocs + .iter() + .map(move |&(offset, id)| ModuleReloc { + kind: pointer_reloc, + offset, + name: self.function_decls[id].clone(), + addend: 0, + }); + let data_relocs = self + .data_relocs + .iter() + .map(move |&(offset, id, addend)| ModuleReloc { + kind: pointer_reloc, + offset, + name: self.data_decls[id].clone(), + addend, + }); + func_relocs.chain(data_relocs) + } +} + +#[cfg(test)] +mod tests { + use crate::ModuleRelocTarget; + + use super::{DataDescription, Init}; + + #[test] + fn basic_data_context() { + let mut data = DataDescription::new(); + assert_eq!(data.init, Init::Uninitialized); + assert!(data.function_decls.is_empty()); + assert!(data.data_decls.is_empty()); + assert!(data.function_relocs.is_empty()); + assert!(data.data_relocs.is_empty()); + + data.define_zeroinit(256); + + let _func_a = data.import_function(ModuleRelocTarget::user(0, 0)); + let func_b = data.import_function(ModuleRelocTarget::user(0, 1)); + let func_c = data.import_function(ModuleRelocTarget::user(0, 2)); + let _data_a = data.import_global_value(ModuleRelocTarget::user(0, 3)); + let data_b = data.import_global_value(ModuleRelocTarget::user(0, 4)); + + data.write_function_addr(8, func_b); + data.write_function_addr(16, func_c); + data.write_data_addr(32, data_b, 27); + + assert_eq!(data.init, Init::Zeros { size: 256 }); + assert_eq!(data.function_decls.len(), 3); + assert_eq!(data.data_decls.len(), 2); + assert_eq!(data.function_relocs.len(), 2); + assert_eq!(data.data_relocs.len(), 1); + + data.clear(); + + assert_eq!(data.init, Init::Uninitialized); + assert!(data.function_decls.is_empty()); + assert!(data.data_decls.is_empty()); + assert!(data.function_relocs.is_empty()); + assert!(data.data_relocs.is_empty()); + + let contents = vec![33, 34, 35, 36]; + let contents_clone = contents.clone(); + data.define(contents.into_boxed_slice()); + + assert_eq!( + data.init, + Init::Bytes { + contents: contents_clone.into_boxed_slice() + } + ); + assert_eq!(data.function_decls.len(), 0); + assert_eq!(data.data_decls.len(), 0); + assert_eq!(data.function_relocs.len(), 0); + assert_eq!(data.data_relocs.len(), 0); + } +} diff --git a/deps/crates/vendor/cranelift-module/src/lib.rs b/deps/crates/vendor/cranelift-module/src/lib.rs new file mode 100644 index 00000000000000..7528ad67caad32 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/src/lib.rs @@ -0,0 +1,61 @@ +//! Top-level lib.rs for `cranelift_module`. + +#![deny(missing_docs)] +#![no_std] + +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc as std; +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(not(feature = "std"))] +use hashbrown::{hash_map, HashMap}; +use std::borrow::ToOwned; +use std::boxed::Box; +#[cfg(feature = "std")] +use std::collections::{hash_map, HashMap}; +use std::string::String; + +use cranelift_codegen::ir; + +mod data_context; +mod module; +mod traps; + +pub use crate::data_context::{DataDescription, Init}; +pub use crate::module::{ + DataDeclaration, DataId, FuncId, FuncOrDataId, FunctionDeclaration, Linkage, Module, + ModuleDeclarations, ModuleError, ModuleReloc, ModuleRelocTarget, ModuleResult, +}; +pub use crate::traps::TrapSite; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Default names for [ir::LibCall]s. A function by this name is imported into the object as +/// part of the translation of a [ir::ExternalName::LibCall] variant. +pub fn default_libcall_names() -> Box String + Send + Sync> { + Box::new(move |libcall| match libcall { + ir::LibCall::Probestack => "__cranelift_probestack".to_owned(), + ir::LibCall::CeilF32 => "ceilf".to_owned(), + ir::LibCall::CeilF64 => "ceil".to_owned(), + ir::LibCall::FloorF32 => "floorf".to_owned(), + ir::LibCall::FloorF64 => "floor".to_owned(), + ir::LibCall::TruncF32 => "truncf".to_owned(), + ir::LibCall::TruncF64 => "trunc".to_owned(), + ir::LibCall::NearestF32 => "nearbyintf".to_owned(), + ir::LibCall::NearestF64 => "nearbyint".to_owned(), + ir::LibCall::FmaF32 => "fmaf".to_owned(), + ir::LibCall::FmaF64 => "fma".to_owned(), + ir::LibCall::Memcpy => "memcpy".to_owned(), + ir::LibCall::Memset => "memset".to_owned(), + ir::LibCall::Memmove => "memmove".to_owned(), + ir::LibCall::Memcmp => "memcmp".to_owned(), + + ir::LibCall::ElfTlsGetAddr => "__tls_get_addr".to_owned(), + ir::LibCall::ElfTlsGetOffset => "__tls_get_offset".to_owned(), + ir::LibCall::X86Pshufb => "__cranelift_x86_pshufb".to_owned(), + }) +} diff --git a/deps/crates/vendor/cranelift-module/src/module.rs b/deps/crates/vendor/cranelift-module/src/module.rs new file mode 100644 index 00000000000000..4a32837787ca60 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/src/module.rs @@ -0,0 +1,1195 @@ +//! Defines `Module` and related types. + +// TODO: Should `ir::Function` really have a `name`? + +// TODO: Factor out `ir::Function`'s `ext_funcs` and `global_values` into a struct +// shared with `DataDescription`? + +use super::HashMap; +use crate::data_context::DataDescription; +use core::fmt::Display; +use cranelift_codegen::binemit::{CodeOffset, Reloc}; +use cranelift_codegen::entity::{entity_impl, PrimaryMap}; +use cranelift_codegen::ir::function::{Function, VersionMarker}; +use cranelift_codegen::ir::ExternalName; +use cranelift_codegen::settings::SetError; +use cranelift_codegen::{ + ir, isa, CodegenError, CompileError, Context, FinalizedMachReloc, FinalizedRelocTarget, +}; +use cranelift_control::ControlPlane; +use std::borrow::{Cow, ToOwned}; +use std::boxed::Box; +use std::string::String; + +/// A module relocation. +#[derive(Clone)] +pub struct ModuleReloc { + /// The offset at which the relocation applies, *relative to the + /// containing section*. + pub offset: CodeOffset, + /// The kind of relocation. + pub kind: Reloc, + /// The external symbol / name to which this relocation refers. + pub name: ModuleRelocTarget, + /// The addend to add to the symbol value. + pub addend: i64, +} + +impl ModuleReloc { + /// Converts a `FinalizedMachReloc` produced from a `Function` into a `ModuleReloc`. + pub fn from_mach_reloc( + mach_reloc: &FinalizedMachReloc, + func: &Function, + func_id: FuncId, + ) -> Self { + let name = match mach_reloc.target { + FinalizedRelocTarget::ExternalName(ExternalName::User(reff)) => { + let name = &func.params.user_named_funcs()[reff]; + ModuleRelocTarget::user(name.namespace, name.index) + } + FinalizedRelocTarget::ExternalName(ExternalName::TestCase(_)) => unimplemented!(), + FinalizedRelocTarget::ExternalName(ExternalName::LibCall(libcall)) => { + ModuleRelocTarget::LibCall(libcall) + } + FinalizedRelocTarget::ExternalName(ExternalName::KnownSymbol(ks)) => { + ModuleRelocTarget::KnownSymbol(ks) + } + FinalizedRelocTarget::Func(offset) => { + ModuleRelocTarget::FunctionOffset(func_id, offset) + } + }; + Self { + offset: mach_reloc.offset, + kind: mach_reloc.kind, + name, + addend: mach_reloc.addend, + } + } +} + +/// A function identifier for use in the `Module` interface. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct FuncId(u32); +entity_impl!(FuncId, "funcid"); + +/// Function identifiers are namespace 0 in `ir::ExternalName` +impl From for ModuleRelocTarget { + fn from(id: FuncId) -> Self { + Self::User { + namespace: 0, + index: id.0, + } + } +} + +impl FuncId { + /// Get the `FuncId` for the function named by `name`. + pub fn from_name(name: &ModuleRelocTarget) -> FuncId { + if let ModuleRelocTarget::User { namespace, index } = name { + debug_assert_eq!(*namespace, 0); + FuncId::from_u32(*index) + } else { + panic!("unexpected name in DataId::from_name") + } + } +} + +/// A data object identifier for use in the `Module` interface. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct DataId(u32); +entity_impl!(DataId, "dataid"); + +/// Data identifiers are namespace 1 in `ir::ExternalName` +impl From for ModuleRelocTarget { + fn from(id: DataId) -> Self { + Self::User { + namespace: 1, + index: id.0, + } + } +} + +impl DataId { + /// Get the `DataId` for the data object named by `name`. + pub fn from_name(name: &ModuleRelocTarget) -> DataId { + if let ModuleRelocTarget::User { namespace, index } = name { + debug_assert_eq!(*namespace, 1); + DataId::from_u32(*index) + } else { + panic!("unexpected name in DataId::from_name") + } + } +} + +/// Linkage refers to where an entity is defined and who can see it. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub enum Linkage { + /// Defined outside of a module. + Import, + /// Defined inside the module, but not visible outside it. + Local, + /// Defined inside the module, visible outside it, and may be preempted. + Preemptible, + /// Defined inside the module, visible inside the current static linkage unit, but not outside. + /// + /// A static linkage unit is the combination of all object files passed to a linker to create + /// an executable or dynamic library. + Hidden, + /// Defined inside the module, and visible outside it. + Export, +} + +impl Linkage { + fn merge(a: Self, b: Self) -> Self { + match a { + Self::Export => Self::Export, + Self::Hidden => match b { + Self::Export => Self::Export, + Self::Preemptible => Self::Preemptible, + _ => Self::Hidden, + }, + Self::Preemptible => match b { + Self::Export => Self::Export, + _ => Self::Preemptible, + }, + Self::Local => match b { + Self::Export => Self::Export, + Self::Hidden => Self::Hidden, + Self::Preemptible => Self::Preemptible, + Self::Local | Self::Import => Self::Local, + }, + Self::Import => b, + } + } + + /// Test whether this linkage can have a definition. + pub fn is_definable(self) -> bool { + match self { + Self::Import => false, + Self::Local | Self::Preemptible | Self::Hidden | Self::Export => true, + } + } + + /// Test whether this linkage will have a definition that cannot be preempted. + pub fn is_final(self) -> bool { + match self { + Self::Import | Self::Preemptible => false, + Self::Local | Self::Hidden | Self::Export => true, + } + } +} + +/// A declared name may refer to either a function or data declaration +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub enum FuncOrDataId { + /// When it's a FuncId + Func(FuncId), + /// When it's a DataId + Data(DataId), +} + +/// Mapping to `ModuleExtName` is trivial based on the `FuncId` and `DataId` mapping. +impl From for ModuleRelocTarget { + fn from(id: FuncOrDataId) -> Self { + match id { + FuncOrDataId::Func(funcid) => Self::from(funcid), + FuncOrDataId::Data(dataid) => Self::from(dataid), + } + } +} + +/// Information about a function which can be called. +#[derive(Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +#[allow(missing_docs, reason = "self-describing fields")] +pub struct FunctionDeclaration { + pub name: Option, + pub linkage: Linkage, + pub signature: ir::Signature, +} + +impl FunctionDeclaration { + /// The linkage name of the function. + /// + /// Synthesized from the given function id if it is an anonymous function. + pub fn linkage_name(&self, id: FuncId) -> Cow<'_, str> { + match &self.name { + Some(name) => Cow::Borrowed(name), + // Symbols starting with .L are completely omitted from the symbol table after linking. + // Using hexadecimal instead of decimal for slightly smaller symbol names and often + // slightly faster linking. + None => Cow::Owned(format!(".Lfn{:x}", id.as_u32())), + } + } + + fn merge( + &mut self, + id: FuncId, + linkage: Linkage, + sig: &ir::Signature, + ) -> Result<(), ModuleError> { + self.linkage = Linkage::merge(self.linkage, linkage); + if &self.signature != sig { + return Err(ModuleError::IncompatibleSignature( + self.linkage_name(id).into_owned(), + self.signature.clone(), + sig.clone(), + )); + } + Ok(()) + } +} + +/// Error messages for all `Module` methods +#[derive(Debug)] +pub enum ModuleError { + /// Indicates an identifier was used before it was declared + Undeclared(String), + + /// Indicates an identifier was used as data/function first, but then used as the other + IncompatibleDeclaration(String), + + /// Indicates a function identifier was declared with a + /// different signature than declared previously + IncompatibleSignature(String, ir::Signature, ir::Signature), + + /// Indicates an identifier was defined more than once + DuplicateDefinition(String), + + /// Indicates an identifier was defined, but was declared as an import + InvalidImportDefinition(String), + + /// Wraps a `cranelift-codegen` error + Compilation(CodegenError), + + /// Memory allocation failure from a backend + Allocation { + /// Tell where the allocation came from + message: &'static str, + /// Io error the allocation failed with + err: std::io::Error, + }, + + /// Wraps a generic error from a backend + Backend(anyhow::Error), + + /// Wraps an error from a flag definition. + Flag(SetError), +} + +impl<'a> From> for ModuleError { + fn from(err: CompileError<'a>) -> Self { + Self::Compilation(err.inner) + } +} + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for ModuleError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Undeclared { .. } + | Self::IncompatibleDeclaration { .. } + | Self::IncompatibleSignature { .. } + | Self::DuplicateDefinition { .. } + | Self::InvalidImportDefinition { .. } => None, + Self::Compilation(source) => Some(source), + Self::Allocation { err: source, .. } => Some(source), + Self::Backend(source) => Some(&**source), + Self::Flag(source) => Some(source), + } + } +} + +impl std::fmt::Display for ModuleError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Undeclared(name) => { + write!(f, "Undeclared identifier: {name}") + } + Self::IncompatibleDeclaration(name) => { + write!(f, "Incompatible declaration of identifier: {name}",) + } + Self::IncompatibleSignature(name, prev_sig, new_sig) => { + write!( + f, + "Function {name} signature {new_sig:?} is incompatible with previous declaration {prev_sig:?}", + ) + } + Self::DuplicateDefinition(name) => { + write!(f, "Duplicate definition of identifier: {name}") + } + Self::InvalidImportDefinition(name) => { + write!( + f, + "Invalid to define identifier declared as an import: {name}", + ) + } + Self::Compilation(err) => { + write!(f, "Compilation error: {err}") + } + Self::Allocation { message, err } => { + write!(f, "Allocation error: {message}: {err}") + } + Self::Backend(err) => write!(f, "Backend error: {err}"), + Self::Flag(err) => write!(f, "Flag error: {err}"), + } + } +} + +impl std::convert::From for ModuleError { + fn from(source: CodegenError) -> Self { + Self::Compilation { 0: source } + } +} + +impl std::convert::From for ModuleError { + fn from(source: SetError) -> Self { + Self::Flag { 0: source } + } +} + +/// A convenient alias for a `Result` that uses `ModuleError` as the error type. +pub type ModuleResult = Result; + +/// Information about a data object which can be accessed. +#[derive(Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +#[allow(missing_docs, reason = "self-describing fields")] +pub struct DataDeclaration { + pub name: Option, + pub linkage: Linkage, + pub writable: bool, + pub tls: bool, +} + +impl DataDeclaration { + /// The linkage name of the data object. + /// + /// Synthesized from the given data id if it is an anonymous function. + pub fn linkage_name(&self, id: DataId) -> Cow<'_, str> { + match &self.name { + Some(name) => Cow::Borrowed(name), + // Symbols starting with .L are completely omitted from the symbol table after linking. + // Using hexadecimal instead of decimal for slightly smaller symbol names and often + // slightly faster linking. + None => Cow::Owned(format!(".Ldata{:x}", id.as_u32())), + } + } + + fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool) { + self.linkage = Linkage::merge(self.linkage, linkage); + self.writable = self.writable || writable; + assert_eq!( + self.tls, tls, + "Can't change TLS data object to normal or in the opposite way", + ); + } +} + +/// A translated `ExternalName` into something global we can handle. +#[derive(Clone, Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub enum ModuleRelocTarget { + /// User defined function, converted from `ExternalName::User`. + User { + /// Arbitrary. + namespace: u32, + /// Arbitrary. + index: u32, + }, + /// Call into a library function. + LibCall(ir::LibCall), + /// Symbols known to the linker. + KnownSymbol(ir::KnownSymbol), + /// A offset inside a function + FunctionOffset(FuncId, CodeOffset), +} + +impl ModuleRelocTarget { + /// Creates a user-defined external name. + pub fn user(namespace: u32, index: u32) -> Self { + Self::User { namespace, index } + } +} + +impl Display for ModuleRelocTarget { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::User { namespace, index } => write!(f, "u{namespace}:{index}"), + Self::LibCall(lc) => write!(f, "%{lc}"), + Self::KnownSymbol(ks) => write!(f, "{ks}"), + Self::FunctionOffset(fname, offset) => write!(f, "{fname}+{offset}"), + } + } +} + +/// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated +/// into `FunctionDeclaration`s and `DataDeclaration`s. +#[derive(Debug, Default)] +pub struct ModuleDeclarations { + /// A version marker used to ensure that serialized clif ir is never deserialized with a + /// different version of Cranelift. + // Note: This must be the first field to ensure that Serde will deserialize it before + // attempting to deserialize other fields that are potentially changed between versions. + _version_marker: VersionMarker, + + names: HashMap, + functions: PrimaryMap, + data_objects: PrimaryMap, +} + +#[cfg(feature = "enable-serde")] +mod serialize { + // This is manually implementing Serialize and Deserialize to avoid serializing the names field, + // which can be entirely reconstructed from the functions and data_objects fields, saving space. + + use super::*; + + use serde::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Unexpected, Visitor}; + use serde::ser::{Serialize, SerializeStruct, Serializer}; + use std::fmt; + + fn get_names( + functions: &PrimaryMap, + data_objects: &PrimaryMap, + ) -> Result, E> { + let mut names = HashMap::new(); + for (func_id, decl) in functions.iter() { + if let Some(name) = &decl.name { + let old = names.insert(name.clone(), FuncOrDataId::Func(func_id)); + if old.is_some() { + return Err(E::invalid_value( + Unexpected::Other("duplicate name"), + &"FunctionDeclaration's with no duplicate names", + )); + } + } + } + for (data_id, decl) in data_objects.iter() { + if let Some(name) = &decl.name { + let old = names.insert(name.clone(), FuncOrDataId::Data(data_id)); + if old.is_some() { + return Err(E::invalid_value( + Unexpected::Other("duplicate name"), + &"DataDeclaration's with no duplicate names", + )); + } + } + } + Ok(names) + } + + impl Serialize for ModuleDeclarations { + fn serialize(&self, s: S) -> Result { + let ModuleDeclarations { + _version_marker, + functions, + data_objects, + names: _, + } = self; + + let mut state = s.serialize_struct("ModuleDeclarations", 4)?; + state.serialize_field("_version_marker", _version_marker)?; + state.serialize_field("functions", functions)?; + state.serialize_field("data_objects", data_objects)?; + state.end() + } + } + + enum ModuleDeclarationsField { + VersionMarker, + Functions, + DataObjects, + Ignore, + } + + struct ModuleDeclarationsFieldVisitor; + + impl<'de> serde::de::Visitor<'de> for ModuleDeclarationsFieldVisitor { + type Value = ModuleDeclarationsField; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("field identifier") + } + + fn visit_u64(self, val: u64) -> Result { + match val { + 0u64 => Ok(ModuleDeclarationsField::VersionMarker), + 1u64 => Ok(ModuleDeclarationsField::Functions), + 2u64 => Ok(ModuleDeclarationsField::DataObjects), + _ => Ok(ModuleDeclarationsField::Ignore), + } + } + + fn visit_str(self, val: &str) -> Result { + match val { + "_version_marker" => Ok(ModuleDeclarationsField::VersionMarker), + "functions" => Ok(ModuleDeclarationsField::Functions), + "data_objects" => Ok(ModuleDeclarationsField::DataObjects), + _ => Ok(ModuleDeclarationsField::Ignore), + } + } + + fn visit_bytes(self, val: &[u8]) -> Result { + match val { + b"_version_marker" => Ok(ModuleDeclarationsField::VersionMarker), + b"functions" => Ok(ModuleDeclarationsField::Functions), + b"data_objects" => Ok(ModuleDeclarationsField::DataObjects), + _ => Ok(ModuleDeclarationsField::Ignore), + } + } + } + + impl<'de> Deserialize<'de> for ModuleDeclarationsField { + #[inline] + fn deserialize>(d: D) -> Result { + d.deserialize_identifier(ModuleDeclarationsFieldVisitor) + } + } + + struct ModuleDeclarationsVisitor; + + impl<'de> Visitor<'de> for ModuleDeclarationsVisitor { + type Value = ModuleDeclarations; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("struct ModuleDeclarations") + } + + #[inline] + fn visit_seq>(self, mut seq: A) -> Result { + let _version_marker = match seq.next_element()? { + Some(val) => val, + None => { + return Err(Error::invalid_length( + 0usize, + &"struct ModuleDeclarations with 4 elements", + )); + } + }; + let functions = match seq.next_element()? { + Some(val) => val, + None => { + return Err(Error::invalid_length( + 2usize, + &"struct ModuleDeclarations with 4 elements", + )); + } + }; + let data_objects = match seq.next_element()? { + Some(val) => val, + None => { + return Err(Error::invalid_length( + 3usize, + &"struct ModuleDeclarations with 4 elements", + )); + } + }; + let names = get_names(&functions, &data_objects)?; + Ok(ModuleDeclarations { + _version_marker, + names, + functions, + data_objects, + }) + } + + #[inline] + fn visit_map>(self, mut map: A) -> Result { + let mut _version_marker: Option = None; + let mut functions: Option> = None; + let mut data_objects: Option> = None; + while let Some(key) = map.next_key::()? { + match key { + ModuleDeclarationsField::VersionMarker => { + if _version_marker.is_some() { + return Err(Error::duplicate_field("_version_marker")); + } + _version_marker = Some(map.next_value()?); + } + ModuleDeclarationsField::Functions => { + if functions.is_some() { + return Err(Error::duplicate_field("functions")); + } + functions = Some(map.next_value()?); + } + ModuleDeclarationsField::DataObjects => { + if data_objects.is_some() { + return Err(Error::duplicate_field("data_objects")); + } + data_objects = Some(map.next_value()?); + } + _ => { + map.next_value::()?; + } + } + } + let _version_marker = match _version_marker { + Some(_version_marker) => _version_marker, + None => return Err(Error::missing_field("_version_marker")), + }; + let functions = match functions { + Some(functions) => functions, + None => return Err(Error::missing_field("functions")), + }; + let data_objects = match data_objects { + Some(data_objects) => data_objects, + None => return Err(Error::missing_field("data_objects")), + }; + let names = get_names(&functions, &data_objects)?; + Ok(ModuleDeclarations { + _version_marker, + names, + functions, + data_objects, + }) + } + } + + impl<'de> Deserialize<'de> for ModuleDeclarations { + fn deserialize>(d: D) -> Result { + d.deserialize_struct( + "ModuleDeclarations", + &["_version_marker", "functions", "data_objects"], + ModuleDeclarationsVisitor, + ) + } + } +} + +impl ModuleDeclarations { + /// Get the module identifier for a given name, if that name + /// has been declared. + pub fn get_name(&self, name: &str) -> Option { + self.names.get(name).copied() + } + + /// Get an iterator of all function declarations + pub fn get_functions(&self) -> impl Iterator { + self.functions.iter() + } + + /// Return whether `name` names a function, rather than a data object. + pub fn is_function(name: &ModuleRelocTarget) -> bool { + match name { + ModuleRelocTarget::User { namespace, .. } => *namespace == 0, + ModuleRelocTarget::LibCall(_) + | ModuleRelocTarget::KnownSymbol(_) + | ModuleRelocTarget::FunctionOffset(..) => { + panic!("unexpected module ext name") + } + } + } + + /// Get the `FunctionDeclaration` for the function named by `name`. + pub fn get_function_decl(&self, func_id: FuncId) -> &FunctionDeclaration { + &self.functions[func_id] + } + + /// Get an iterator of all data declarations + pub fn get_data_objects(&self) -> impl Iterator { + self.data_objects.iter() + } + + /// Get the `DataDeclaration` for the data object named by `name`. + pub fn get_data_decl(&self, data_id: DataId) -> &DataDeclaration { + &self.data_objects[data_id] + } + + /// Declare a function in this module. + pub fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &ir::Signature, + ) -> ModuleResult<(FuncId, Linkage)> { + // TODO: Can we avoid allocating names so often? + use super::hash_map::Entry::*; + match self.names.entry(name.to_owned()) { + Occupied(entry) => match *entry.get() { + FuncOrDataId::Func(id) => { + let existing = &mut self.functions[id]; + existing.merge(id, linkage, signature)?; + Ok((id, existing.linkage)) + } + FuncOrDataId::Data(..) => { + Err(ModuleError::IncompatibleDeclaration(name.to_owned())) + } + }, + Vacant(entry) => { + let id = self.functions.push(FunctionDeclaration { + name: Some(name.to_owned()), + linkage, + signature: signature.clone(), + }); + entry.insert(FuncOrDataId::Func(id)); + Ok((id, self.functions[id].linkage)) + } + } + } + + /// Declare an anonymous function in this module. + pub fn declare_anonymous_function( + &mut self, + signature: &ir::Signature, + ) -> ModuleResult { + let id = self.functions.push(FunctionDeclaration { + name: None, + linkage: Linkage::Local, + signature: signature.clone(), + }); + Ok(id) + } + + /// Declare a data object in this module. + pub fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult<(DataId, Linkage)> { + // TODO: Can we avoid allocating names so often? + use super::hash_map::Entry::*; + match self.names.entry(name.to_owned()) { + Occupied(entry) => match *entry.get() { + FuncOrDataId::Data(id) => { + let existing = &mut self.data_objects[id]; + existing.merge(linkage, writable, tls); + Ok((id, existing.linkage)) + } + + FuncOrDataId::Func(..) => { + Err(ModuleError::IncompatibleDeclaration(name.to_owned())) + } + }, + Vacant(entry) => { + let id = self.data_objects.push(DataDeclaration { + name: Some(name.to_owned()), + linkage, + writable, + tls, + }); + entry.insert(FuncOrDataId::Data(id)); + Ok((id, self.data_objects[id].linkage)) + } + } + } + + /// Declare an anonymous data object in this module. + pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult { + let id = self.data_objects.push(DataDeclaration { + name: None, + linkage: Linkage::Local, + writable, + tls, + }); + Ok(id) + } +} + +/// A `Module` is a utility for collecting functions and data objects, and linking them together. +pub trait Module { + /// Return the `TargetIsa` to compile for. + fn isa(&self) -> &dyn isa::TargetIsa; + + /// Get all declarations in this module. + fn declarations(&self) -> &ModuleDeclarations; + + /// Get the module identifier for a given name, if that name + /// has been declared. + fn get_name(&self, name: &str) -> Option { + self.declarations().get_name(name) + } + + /// Return the target information needed by frontends to produce Cranelift IR + /// for the current target. + fn target_config(&self) -> isa::TargetFrontendConfig { + self.isa().frontend_config() + } + + /// Create a new `Context` initialized for use with this `Module`. + /// + /// This ensures that the `Context` is initialized with the default calling + /// convention for the `TargetIsa`. + fn make_context(&self) -> Context { + let mut ctx = Context::new(); + ctx.func.signature.call_conv = self.isa().default_call_conv(); + ctx + } + + /// Clear the given `Context` and reset it for use with a new function. + /// + /// This ensures that the `Context` is initialized with the default calling + /// convention for the `TargetIsa`. + fn clear_context(&self, ctx: &mut Context) { + ctx.clear(); + ctx.func.signature.call_conv = self.isa().default_call_conv(); + } + + /// Create a new empty `Signature` with the default calling convention for + /// the `TargetIsa`, to which parameter and return types can be added for + /// declaring a function to be called by this `Module`. + fn make_signature(&self) -> ir::Signature { + ir::Signature::new(self.isa().default_call_conv()) + } + + /// Clear the given `Signature` and reset for use with a new function. + /// + /// This ensures that the `Signature` is initialized with the default + /// calling convention for the `TargetIsa`. + fn clear_signature(&self, sig: &mut ir::Signature) { + sig.clear(self.isa().default_call_conv()); + } + + /// Declare a function in this module. + fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &ir::Signature, + ) -> ModuleResult; + + /// Declare an anonymous function in this module. + fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult; + + /// Declare a data object in this module. + fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult; + + /// Declare an anonymous data object in this module. + fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult; + + /// Use this when you're building the IR of a function to reference a function. + /// + /// TODO: Coalesce redundant decls and signatures. + /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. + fn declare_func_in_func(&mut self, func_id: FuncId, func: &mut ir::Function) -> ir::FuncRef { + let decl = &self.declarations().functions[func_id]; + let signature = func.import_signature(decl.signature.clone()); + let user_name_ref = func.declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: func_id.as_u32(), + }); + let colocated = decl.linkage.is_final(); + func.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(user_name_ref), + signature, + colocated, + }) + } + + /// Use this when you're building the IR of a function to reference a data object. + /// + /// TODO: Same as above. + fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { + let decl = &self.declarations().data_objects[data]; + let colocated = decl.linkage.is_final(); + let user_name_ref = func.declare_imported_user_function(ir::UserExternalName { + namespace: 1, + index: data.as_u32(), + }); + func.create_global_value(ir::GlobalValueData::Symbol { + name: ir::ExternalName::user(user_name_ref), + offset: ir::immediates::Imm64::new(0), + colocated, + tls: decl.tls, + }) + } + + /// TODO: Same as above. + fn declare_func_in_data(&self, func_id: FuncId, data: &mut DataDescription) -> ir::FuncRef { + data.import_function(ModuleRelocTarget::user(0, func_id.as_u32())) + } + + /// TODO: Same as above. + fn declare_data_in_data(&self, data_id: DataId, data: &mut DataDescription) -> ir::GlobalValue { + data.import_global_value(ModuleRelocTarget::user(1, data_id.as_u32())) + } + + /// Define a function, producing the function body from the given `Context`. + /// + /// Returns the size of the function's code and constant data. + /// + /// Unlike [`define_function_with_control_plane`] this uses a default [`ControlPlane`] for + /// convenience. + /// + /// Note: After calling this function the given `Context` will contain the compiled function. + /// + /// [`define_function_with_control_plane`]: Self::define_function_with_control_plane + fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> ModuleResult<()> { + self.define_function_with_control_plane(func, ctx, &mut ControlPlane::default()) + } + + /// Define a function, producing the function body from the given `Context`. + /// + /// Returns the size of the function's code and constant data. + /// + /// Note: After calling this function the given `Context` will contain the compiled function. + fn define_function_with_control_plane( + &mut self, + func: FuncId, + ctx: &mut Context, + ctrl_plane: &mut ControlPlane, + ) -> ModuleResult<()>; + + /// Define a function, taking the function body from the given `bytes`. + /// + /// This function is generally only useful if you need to precisely specify + /// the emitted instructions for some reason; otherwise, you should use + /// `define_function`. + /// + /// Returns the size of the function's code. + fn define_function_bytes( + &mut self, + func_id: FuncId, + func: &ir::Function, + alignment: u64, + bytes: &[u8], + relocs: &[FinalizedMachReloc], + ) -> ModuleResult<()>; + + /// Define a data object, producing the data contents from the given `DataContext`. + fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()>; +} + +impl Module for &mut M { + fn isa(&self) -> &dyn isa::TargetIsa { + (**self).isa() + } + + fn declarations(&self) -> &ModuleDeclarations { + (**self).declarations() + } + + fn get_name(&self, name: &str) -> Option { + (**self).get_name(name) + } + + fn target_config(&self) -> isa::TargetFrontendConfig { + (**self).target_config() + } + + fn make_context(&self) -> Context { + (**self).make_context() + } + + fn clear_context(&self, ctx: &mut Context) { + (**self).clear_context(ctx) + } + + fn make_signature(&self) -> ir::Signature { + (**self).make_signature() + } + + fn clear_signature(&self, sig: &mut ir::Signature) { + (**self).clear_signature(sig) + } + + fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &ir::Signature, + ) -> ModuleResult { + (**self).declare_function(name, linkage, signature) + } + + fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult { + (**self).declare_anonymous_function(signature) + } + + fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult { + (**self).declare_data(name, linkage, writable, tls) + } + + fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult { + (**self).declare_anonymous_data(writable, tls) + } + + fn declare_func_in_func(&mut self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { + (**self).declare_func_in_func(func, in_func) + } + + fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { + (**self).declare_data_in_func(data, func) + } + + fn declare_func_in_data(&self, func_id: FuncId, data: &mut DataDescription) -> ir::FuncRef { + (**self).declare_func_in_data(func_id, data) + } + + fn declare_data_in_data(&self, data_id: DataId, data: &mut DataDescription) -> ir::GlobalValue { + (**self).declare_data_in_data(data_id, data) + } + + fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> ModuleResult<()> { + (**self).define_function(func, ctx) + } + + fn define_function_with_control_plane( + &mut self, + func: FuncId, + ctx: &mut Context, + ctrl_plane: &mut ControlPlane, + ) -> ModuleResult<()> { + (**self).define_function_with_control_plane(func, ctx, ctrl_plane) + } + + fn define_function_bytes( + &mut self, + func_id: FuncId, + func: &ir::Function, + alignment: u64, + bytes: &[u8], + relocs: &[FinalizedMachReloc], + ) -> ModuleResult<()> { + (**self).define_function_bytes(func_id, func, alignment, bytes, relocs) + } + + fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> { + (**self).define_data(data_id, data) + } +} + +impl Module for Box { + fn isa(&self) -> &dyn isa::TargetIsa { + (**self).isa() + } + + fn declarations(&self) -> &ModuleDeclarations { + (**self).declarations() + } + + fn get_name(&self, name: &str) -> Option { + (**self).get_name(name) + } + + fn target_config(&self) -> isa::TargetFrontendConfig { + (**self).target_config() + } + + fn make_context(&self) -> Context { + (**self).make_context() + } + + fn clear_context(&self, ctx: &mut Context) { + (**self).clear_context(ctx) + } + + fn make_signature(&self) -> ir::Signature { + (**self).make_signature() + } + + fn clear_signature(&self, sig: &mut ir::Signature) { + (**self).clear_signature(sig) + } + + fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &ir::Signature, + ) -> ModuleResult { + (**self).declare_function(name, linkage, signature) + } + + fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult { + (**self).declare_anonymous_function(signature) + } + + fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult { + (**self).declare_data(name, linkage, writable, tls) + } + + fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult { + (**self).declare_anonymous_data(writable, tls) + } + + fn declare_func_in_func(&mut self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { + (**self).declare_func_in_func(func, in_func) + } + + fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { + (**self).declare_data_in_func(data, func) + } + + fn declare_func_in_data(&self, func_id: FuncId, data: &mut DataDescription) -> ir::FuncRef { + (**self).declare_func_in_data(func_id, data) + } + + fn declare_data_in_data(&self, data_id: DataId, data: &mut DataDescription) -> ir::GlobalValue { + (**self).declare_data_in_data(data_id, data) + } + + fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> ModuleResult<()> { + (**self).define_function(func, ctx) + } + + fn define_function_with_control_plane( + &mut self, + func: FuncId, + ctx: &mut Context, + ctrl_plane: &mut ControlPlane, + ) -> ModuleResult<()> { + (**self).define_function_with_control_plane(func, ctx, ctrl_plane) + } + + fn define_function_bytes( + &mut self, + func_id: FuncId, + func: &ir::Function, + alignment: u64, + bytes: &[u8], + relocs: &[FinalizedMachReloc], + ) -> ModuleResult<()> { + (**self).define_function_bytes(func_id, func, alignment, bytes, relocs) + } + + fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> { + (**self).define_data(data_id, data) + } +} diff --git a/deps/crates/vendor/cranelift-module/src/traps.rs b/deps/crates/vendor/cranelift-module/src/traps.rs new file mode 100644 index 00000000000000..2344d4189b5360 --- /dev/null +++ b/deps/crates/vendor/cranelift-module/src/traps.rs @@ -0,0 +1,14 @@ +//! Defines `TrapSite`. + +use cranelift_codegen::{binemit, ir}; + +/// Record of the arguments cranelift passes to `TrapSink::trap`. +#[derive(Clone, Debug)] +pub struct TrapSite { + /// Offset into function. + pub offset: binemit::CodeOffset, + /// Source location given to cranelift. + pub srcloc: ir::SourceLoc, + /// Trap code, as determined by cranelift. + pub code: ir::TrapCode, +} diff --git a/deps/crates/vendor/cranelift-native/.cargo-checksum.json b/deps/crates/vendor/cranelift-native/.cargo-checksum.json new file mode 100644 index 00000000000000..0c7f26ad9458e0 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"1f3614b77c7867e29328c76ef86a986a0a5945c9efd9ebeaa9b94d40488878b1","Cargo.lock":"698a6fe99dce43cef19fc47b6cf233c60571a1ba512c49f45d65b13d8c5c79c7","Cargo.toml":"924bb0168653096f982b35e39587694cd319903dae29aa83d669966bcdf552b1","Cargo.toml.orig":"00cd9c2f97c6213e481cdd3566b9728d7825c81ac23543deed5f9fd22fa8dfe8","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"3dcebfe863bb34056d13c895732889ba1b732f9e958ff3c32284b3565eaacbd6","src/lib.rs":"491343bb15f9c44e61e3bbbaec60e83282233b1666117968b4a693e14751640a","src/riscv.rs":"e2e2ed044ba089676cae33b2b2548d6247753fe2c07504cc335c13cb6fd65d6e"},"package":"b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-native/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-native/.cargo_vcs_info.json new file mode 100644 index 00000000000000..4389789a4b811b --- /dev/null +++ b/deps/crates/vendor/cranelift-native/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/native" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-native/Cargo.lock b/deps/crates/vendor/cranelift-native/Cargo.lock new file mode 100644 index 00000000000000..1f970f83cfcee0 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/Cargo.lock @@ -0,0 +1,261 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" + +[[package]] +name = "cranelift-native" +version = "0.116.1" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regalloc2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/deps/crates/vendor/cranelift-native/Cargo.toml b/deps/crates/vendor/cranelift-native/Cargo.toml new file mode 100644 index 00000000000000..16848db3197815 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-native" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Support for targeting the host with Cranelift" +documentation = "https://docs.rs/cranelift-native" +readme = "README.md" +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_native" +path = "src/lib.rs" + +[dependencies.cranelift-codegen] +version = "0.116.1" +features = [ + "std", + "unwind", +] +default-features = false + +[dependencies.target-lexicon] +version = "0.13.0" + +[features] +core = ["cranelift-codegen/core"] +default = ["std"] +std = ["cranelift-codegen/std"] + +[target.'cfg(any(target_arch = "s390x", target_arch = "riscv64"))'.dependencies.libc] +version = "0.2.112" +default-features = true diff --git a/deps/crates/vendor/cranelift-native/Cargo.toml.orig b/deps/crates/vendor/cranelift-native/Cargo.toml.orig new file mode 100644 index 00000000000000..b0a4c681dfa100 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/Cargo.toml.orig @@ -0,0 +1,24 @@ +[package] +name = "cranelift-native" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +description = "Support for targeting the host with Cranelift" +documentation = "https://docs.rs/cranelift-native" +repository = "https://github.com/bytecodealliance/wasmtime" +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" +edition.workspace = true +rust-version.workspace = true + +[dependencies] +cranelift-codegen = { workspace = true } +target-lexicon = { workspace = true } + +[target.'cfg(any(target_arch = "s390x", target_arch = "riscv64"))'.dependencies] +libc = { workspace = true } + +[features] +default = ["std"] +std = ["cranelift-codegen/std"] +core = ["cranelift-codegen/core"] diff --git a/deps/crates/vendor/cranelift-native/LICENSE b/deps/crates/vendor/cranelift-native/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-native/README.md b/deps/crates/vendor/cranelift-native/README.md new file mode 100644 index 00000000000000..10f01bc9062518 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/README.md @@ -0,0 +1,3 @@ +This crate performs autodetection of the host architecture, which can be used to +configure [Cranelift](https://crates.io/crates/cranelift) to generate code +specialized for the machine it's running on. diff --git a/deps/crates/vendor/cranelift-native/src/lib.rs b/deps/crates/vendor/cranelift-native/src/lib.rs new file mode 100644 index 00000000000000..f159a33d5ed7b8 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/src/lib.rs @@ -0,0 +1,195 @@ +//! Performs autodetection of the host for the purposes of running +//! Cranelift to generate code to run on the same machine. + +#![deny(missing_docs)] + +use cranelift_codegen::isa; +use cranelift_codegen::settings::Configurable; +use target_lexicon::Triple; + +#[cfg(all(target_arch = "riscv64", target_os = "linux"))] +mod riscv; + +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +pub fn builder() -> Result { + builder_with_options(true) +} + +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +/// +/// Selects the given backend variant specifically; this is +/// useful when more than one backend exists for a given target +/// (e.g., on x86-64). +pub fn builder_with_options(infer_native_flags: bool) -> Result { + let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err { + isa::LookupError::SupportDisabled => "support for architecture disabled at compile time", + isa::LookupError::Unsupported => "unsupported architecture", + })?; + if infer_native_flags { + self::infer_native_flags(&mut isa_builder)?; + } + Ok(isa_builder) +} + +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +/// +/// Selects the given backend variant specifically; this is +/// useful when more than one backend exists for a given target +/// (e.g., on x86-64). +pub fn infer_native_flags(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> { + #[cfg(target_arch = "x86_64")] + { + if !std::is_x86_feature_detected!("sse2") { + return Err("x86 support requires SSE2"); + } + + if std::is_x86_feature_detected!("cmpxchg16b") { + isa_builder.enable("has_cmpxchg16b").unwrap(); + } + if std::is_x86_feature_detected!("sse3") { + isa_builder.enable("has_sse3").unwrap(); + } + if std::is_x86_feature_detected!("ssse3") { + isa_builder.enable("has_ssse3").unwrap(); + } + if std::is_x86_feature_detected!("sse4.1") { + isa_builder.enable("has_sse41").unwrap(); + } + if std::is_x86_feature_detected!("sse4.2") { + isa_builder.enable("has_sse42").unwrap(); + } + if std::is_x86_feature_detected!("popcnt") { + isa_builder.enable("has_popcnt").unwrap(); + } + if std::is_x86_feature_detected!("avx") { + isa_builder.enable("has_avx").unwrap(); + } + if std::is_x86_feature_detected!("avx2") { + isa_builder.enable("has_avx2").unwrap(); + } + if std::is_x86_feature_detected!("fma") { + isa_builder.enable("has_fma").unwrap(); + } + if std::is_x86_feature_detected!("bmi1") { + isa_builder.enable("has_bmi1").unwrap(); + } + if std::is_x86_feature_detected!("bmi2") { + isa_builder.enable("has_bmi2").unwrap(); + } + if std::is_x86_feature_detected!("avx512bitalg") { + isa_builder.enable("has_avx512bitalg").unwrap(); + } + if std::is_x86_feature_detected!("avx512dq") { + isa_builder.enable("has_avx512dq").unwrap(); + } + if std::is_x86_feature_detected!("avx512f") { + isa_builder.enable("has_avx512f").unwrap(); + } + if std::is_x86_feature_detected!("avx512vl") { + isa_builder.enable("has_avx512vl").unwrap(); + } + if std::is_x86_feature_detected!("avx512vbmi") { + isa_builder.enable("has_avx512vbmi").unwrap(); + } + if std::is_x86_feature_detected!("lzcnt") { + isa_builder.enable("has_lzcnt").unwrap(); + } + } + + #[cfg(target_arch = "aarch64")] + { + if std::arch::is_aarch64_feature_detected!("lse") { + isa_builder.enable("has_lse").unwrap(); + } + + if std::arch::is_aarch64_feature_detected!("paca") { + isa_builder.enable("has_pauth").unwrap(); + } + + if std::arch::is_aarch64_feature_detected!("fp16") { + isa_builder.enable("has_fp16").unwrap(); + } + + if cfg!(target_os = "macos") { + // Pointer authentication is always available on Apple Silicon. + isa_builder.enable("sign_return_address").unwrap(); + // macOS enforces the use of the B key for return addresses. + isa_builder.enable("sign_return_address_with_bkey").unwrap(); + } + } + + // There is no is_s390x_feature_detected macro yet, so for now + // we use getauxval from the libc crate directly. + #[cfg(all(target_arch = "s390x", target_os = "linux"))] + { + let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; + const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768; + if (v & HWCAP_S390X_VXRS_EXT2) != 0 { + isa_builder.enable("has_vxrs_ext2").unwrap(); + // There is no separate HWCAP bit for mie2, so assume + // that any machine with vxrs_ext2 also has mie2. + isa_builder.enable("has_mie2").unwrap(); + } + } + + // `is_riscv_feature_detected` is nightly only for now, use + // getauxval from the libc crate directly as a temporary measure. + #[cfg(all(target_arch = "riscv64", target_os = "linux"))] + { + // Try both hwcap and cpuinfo + // HWCAP only returns single letter extensions, cpuinfo returns all of + // them but may not be available in some systems (QEMU < 8.1). + riscv::hwcap_detect(isa_builder)?; + + // Ignore errors for cpuinfo. QEMU versions prior to 8.1 do not emulate + // the cpuinfo interface, so we can't rely on it being present for now. + let _ = riscv::cpuinfo_detect(isa_builder); + } + + // On all other architectures (e.g. wasm32) we won't infer any native flags, + // but still need to use the `isa_builder` to avoid compiler warnings. + let _ = isa_builder; + Ok(()) +} + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg(test)] +mod tests { + use super::builder; + use cranelift_codegen::isa::CallConv; + use cranelift_codegen::settings; + + #[test] + fn test() { + if let Ok(isa_builder) = builder() { + let flag_builder = settings::builder(); + let isa = isa_builder + .finish(settings::Flags::new(flag_builder)) + .unwrap(); + + if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64); + } else if cfg!(unix) { + assert_eq!(isa.default_call_conv(), CallConv::SystemV); + } else if cfg!(windows) { + assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall); + } + + if cfg!(target_pointer_width = "64") { + assert_eq!(isa.pointer_bits(), 64); + } else if cfg!(target_pointer_width = "32") { + assert_eq!(isa.pointer_bits(), 32); + } else if cfg!(target_pointer_width = "16") { + assert_eq!(isa.pointer_bits(), 16); + } + } + } +} diff --git a/deps/crates/vendor/cranelift-native/src/riscv.rs b/deps/crates/vendor/cranelift-native/src/riscv.rs new file mode 100644 index 00000000000000..4152816f7ab177 --- /dev/null +++ b/deps/crates/vendor/cranelift-native/src/riscv.rs @@ -0,0 +1,128 @@ +use cranelift_codegen::settings::Configurable; +use std::fs::File; +use std::io::{BufRead, BufReader}; + +pub fn hwcap_detect(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> { + let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; + + const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a'); + const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a'); + const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a'); + const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a'); + const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a'); + const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a'); + + if (v & HWCAP_RISCV_EXT_A) != 0 { + isa_builder.enable("has_a").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_C) != 0 { + isa_builder.enable("has_c").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_D) != 0 { + isa_builder.enable("has_d").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_F) != 0 { + isa_builder.enable("has_f").unwrap(); + + // TODO: There doesn't seem to be a bit associated with this extension + // rust enables it with the `f` extension: + // https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43 + isa_builder.enable("has_zicsr").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_M) != 0 { + isa_builder.enable("has_m").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_V) != 0 { + isa_builder.enable("has_v").unwrap(); + } + + // In general extensions that are longer than one letter + // won't have a bit associated with them. The Linux kernel + // is currently working on a new way to query the extensions. + Ok(()) +} + +/// Read the /proc/cpuinfo file and detect the extensions. +/// +/// We are looking for the isa line string, which contains the extensions. +/// The format for this string is specified in the linux user space ABI for RISC-V: +/// https://github.com/torvalds/linux/blob/09a9639e56c01c7a00d6c0ca63f4c7c41abe075d/Documentation/riscv/uabi.rst +/// +/// The format is fairly similar to the one specified in the RISC-V ISA manual, but +/// all lower case. +/// +/// An example ISA string is: rv64imafdcvh_zawrs_zba_zbb_zicbom_zicboz_zicsr_zifencei_zihintpause +pub fn cpuinfo_detect(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> { + let file = File::open("/proc/cpuinfo").map_err(|_| "failed to open /proc/cpuinfo")?; + + let isa_string = BufReader::new(file) + .lines() + .filter_map(Result::ok) + .find_map(|line| { + if let Some((k, v)) = line.split_once(':') { + if k.trim_end() == "isa" { + return Some(v.trim().to_string()); + } + } + None + }) + .ok_or("failed to find isa line in /proc/cpuinfo")?; + + for ext in isa_string_extensions(&isa_string) { + // Try enabling all the extensions that are parsed. + // Cranelift won't recognize all of them, but that's okay we just ignore them. + // Extensions flags in the RISC-V backend have the format of `has_x` for the `x` extension. + let _ = isa_builder.enable(&format!("has_{ext}")); + } + + Ok(()) +} + +/// Parses an ISA string and returns an iterator over the extensions. +fn isa_string_extensions(isa: &str) -> Vec<&str> { + let mut parts = isa.split('_'); + let mut extensions = Vec::new(); + // The first entry has the form `rv64imafdcvh`, we need to skip the architecture ("rv64"). + // Each of the letters after the cpu architecture is an extension, so return them + // individually. + if let Some(letters) = parts.next().unwrap().strip_prefix("rv64") { + extensions.extend(letters.matches(|_| true)); + extensions.extend(parts); + } + extensions +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_isa() { + let isa_string = "rv64imafdcvh_zawrs_zba_zbb_zicbom_zicboz_zicsr_zifencei_zihintpause"; + let extensions = vec![ + "i", + "m", + "a", + "f", + "d", + "c", + "v", + "h", + "zawrs", + "zba", + "zbb", + "zicbom", + "zicboz", + "zicsr", + "zifencei", + "zihintpause", + ]; + + assert_eq!(isa_string_extensions(isa_string), extensions,); + } +} diff --git a/deps/crates/vendor/cranelift/.cargo-checksum.json b/deps/crates/vendor/cranelift/.cargo-checksum.json new file mode 100644 index 00000000000000..42472593d4a5c9 --- /dev/null +++ b/deps/crates/vendor/cranelift/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"40aaf7d5c362f823b6c8d0c3cb556dbcc9ddcce3f53aaebe472892d6e600fde8","Cargo.lock":"7fe2de9c47e301a850ec67ed40fcb632e23afc0eb96e8db57268abfece5dcc3b","Cargo.toml":"c48468f8a012b52163ff858a7de78e23834ec7027468affbe758339c14a44082","Cargo.toml.orig":"87eecc46175592f705ed6c0f45b68460a3415cc2ce823f831b82e493dfce1eac","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"cca05890114266f31e36b0c764ce808fad0e2d4d81ab08157d42bbf1b2a65315","src/lib.rs":"dec1608cedb99ca28d07632fcfe337ff8bade721c5d516eb4f9ef92114eafbcd"},"package":"a71de5e59f616d79d14d2c71aa2799ce898241d7f10f7e64a4997014b4000a28"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift/.cargo_vcs_info.json b/deps/crates/vendor/cranelift/.cargo_vcs_info.json new file mode 100644 index 00000000000000..8538c168c538db --- /dev/null +++ b/deps/crates/vendor/cranelift/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/umbrella" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift/Cargo.lock b/deps/crates/vendor/cranelift/Cargo.lock new file mode 100644 index 00000000000000..a101c57e0dafe4 --- /dev/null +++ b/deps/crates/vendor/cranelift/Cargo.lock @@ -0,0 +1,545 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cranelift" +version = "0.116.1" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", + "cranelift-interpreter", + "cranelift-jit", + "cranelift-module", + "cranelift-native", + "cranelift-object", +] + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", +] + +[[package]] +name = "cranelift-frontend" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +dependencies = [ + "cranelift-codegen", + "hashbrown 0.14.3", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-interpreter" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608c41606486f44992e4ec01284600fbe0886c87b72e0180a34c24fb60defb4f" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "libm", + "log", + "smallvec", + "thiserror", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" + +[[package]] +name = "cranelift-jit" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e65c42755a719b09662b00c700daaf76cc35d5ace1f5c002ad404b591ff1978" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-module", + "cranelift-native", + "libc", + "log", + "region", + "target-lexicon", + "wasmtime-jit-icache-coherence", + "windows-sys 0.59.0", +] + +[[package]] +name = "cranelift-module" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "hashbrown 0.14.3", +] + +[[package]] +name = "cranelift-native" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-object" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aad5a6d3e379493c3f8b35dc61c93d0bf5f27003bbe20614e0200b0ec372ef52" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-module", + "log", + "object", + "target-lexicon", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "crc32fast", + "hashbrown 0.15.2", + "indexmap", + "memchr", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regalloc2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags", + "libc", + "mach2", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "29.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/deps/crates/vendor/cranelift/Cargo.toml b/deps/crates/vendor/cranelift/Cargo.toml new file mode 100644 index 00000000000000..18ddfc2c7548b7 --- /dev/null +++ b/deps/crates/vendor/cranelift/Cargo.toml @@ -0,0 +1,92 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Umbrella for commonly-used cranelift crates" +documentation = "https://docs.rs/cranelift" +readme = "README.md" +keywords = [ + "compile", + "compiler", + "jit", +] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift" +path = "src/lib.rs" + +[dependencies.cranelift-codegen] +version = "0.116.1" +features = [ + "std", + "unwind", +] +default-features = false + +[dependencies.cranelift-frontend] +version = "0.116.1" +optional = true + +[dependencies.cranelift-interpreter] +version = "0.116.1" +optional = true + +[dependencies.cranelift-jit] +version = "0.116.1" +optional = true + +[dependencies.cranelift-module] +version = "0.116.1" +optional = true + +[dependencies.cranelift-native] +version = "0.116.1" +optional = true + +[dependencies.cranelift-object] +version = "0.116.1" +optional = true + +[features] +core = [ + "cranelift-codegen/core", + "cranelift-frontend?/core", + "cranelift-module?/core", +] +default = [ + "std", + "frontend", +] +frontend = ["dep:cranelift-frontend"] +interpreter = ["dep:cranelift-interpreter"] +jit = ["dep:cranelift-jit"] +module = ["dep:cranelift-module"] +native = ["dep:cranelift-native"] +object = ["dep:cranelift-object"] +std = [ + "cranelift-codegen/std", + "cranelift-frontend?/std", + "cranelift-module?/std", +] diff --git a/deps/crates/vendor/cranelift/Cargo.toml.orig b/deps/crates/vendor/cranelift/Cargo.toml.orig new file mode 100644 index 00000000000000..e00fd8effbd0fe --- /dev/null +++ b/deps/crates/vendor/cranelift/Cargo.toml.orig @@ -0,0 +1,41 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift" +version = "0.116.1" +description = "Umbrella for commonly-used cranelift crates" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift" +repository = "https://github.com/bytecodealliance/wasmtime" +categories = ["no-std"] +readme = "README.md" +keywords = ["compile", "compiler", "jit"] +edition.workspace = true +rust-version.workspace = true + +[dependencies] +cranelift-codegen = { workspace = true } +cranelift-frontend = { workspace = true, optional = true } +cranelift-interpreter = { workspace = true, optional = true } +cranelift-jit = { workspace = true, optional = true } +cranelift-module = { workspace = true, optional = true } +cranelift-native = { workspace = true, optional = true } +cranelift-object = { workspace = true, optional = true } + +[features] +default = ["std", "frontend"] +frontend = ["dep:cranelift-frontend"] +interpreter = ["dep:cranelift-interpreter"] +jit = ["dep:cranelift-jit"] +module = ["dep:cranelift-module"] +native = ["dep:cranelift-native"] +object = ["dep:cranelift-object"] +std = [ + "cranelift-codegen/std", + "cranelift-frontend?/std", + "cranelift-module?/std", +] +core = [ + "cranelift-codegen/core", + "cranelift-frontend?/core", + "cranelift-module?/core", +] diff --git a/deps/crates/vendor/cranelift/LICENSE b/deps/crates/vendor/cranelift/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift/README.md b/deps/crates/vendor/cranelift/README.md new file mode 100644 index 00000000000000..134b3140bfb4a3 --- /dev/null +++ b/deps/crates/vendor/cranelift/README.md @@ -0,0 +1,3 @@ +This is an umbrella crate which contains no code of its own, but pulls in +other cranelift library crates to provide a convenient one-line dependency, +and a prelude, for common use cases. diff --git a/deps/crates/vendor/cranelift/src/lib.rs b/deps/crates/vendor/cranelift/src/lib.rs new file mode 100644 index 00000000000000..cfda269c735f33 --- /dev/null +++ b/deps/crates/vendor/cranelift/src/lib.rs @@ -0,0 +1,41 @@ +//! Cranelift umbrella crate, providing a convenient one-line dependency. + +#![deny(missing_docs)] +#![no_std] + +/// Provide these crates, renamed to reduce stutter. +pub use cranelift_codegen as codegen; +#[cfg(feature = "frontend")] +pub use cranelift_frontend as frontend; +#[cfg(feature = "interpreter")] +pub use cranelift_interpreter as interpreter; +#[cfg(feature = "jit")] +pub use cranelift_jit as jit; +#[cfg(feature = "module")] +pub use cranelift_module as module; +#[cfg(feature = "native")] +pub use cranelift_native as native; +#[cfg(feature = "object")] +pub use cranelift_object as object; + +/// A prelude providing convenient access to commonly-used cranelift features. Use +/// as `use cranelift::prelude::*`. +pub mod prelude { + pub use crate::codegen; + pub use crate::codegen::entity::EntityRef; + pub use crate::codegen::ir::condcodes::{FloatCC, IntCC}; + pub use crate::codegen::ir::immediates::{Ieee32, Ieee64, Imm64, Uimm64}; + pub use crate::codegen::ir::types; + pub use crate::codegen::ir::{ + AbiParam, Block, ExtFuncData, ExternalName, GlobalValueData, InstBuilder, JumpTableData, + MemFlags, Signature, StackSlotData, StackSlotKind, TrapCode, Type, Value, + }; + pub use crate::codegen::isa; + pub use crate::codegen::settings::{self, Configurable}; + + #[cfg(feature = "frontend")] + pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +} + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/deps/crates/vendor/equivalent/.cargo-checksum.json b/deps/crates/vendor/equivalent/.cargo-checksum.json new file mode 100644 index 00000000000000..fb8a50a7131fc1 --- /dev/null +++ b/deps/crates/vendor/equivalent/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"7a265eb795c96fb83f685289f6c0b0c317e2029ef7fba66eb26205f1ccd79efd",".github/workflows/ci.yml":"90d216ed7331b2c441f61251f11e9bdaa005c3b115d6fdebf96dc5dac4308833","Cargo.lock":"2eea7e967981d2fd6ad933bab8c5c987ac6235a5697bb67bfe414764dc83b528","Cargo.toml":"92fcf6d8b32d99f40a5053b9026e417c958d6f5f19581c632d675211b7eeb9f9","Cargo.toml.orig":"763d2c9054b7e6d3a908639cb6ec7487006b699f90f40f0d368d313548cc93b0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349","README.md":"bbcbb8419f9bb01a51d3d5e808fe35651d423014992a72be3e7acd518485f190","src/lib.rs":"1dd84363f561b30b1da713486c6b583900353e62c569d7ba1dd84eb2c04f1a14"},"package":"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"} \ No newline at end of file diff --git a/deps/crates/vendor/equivalent/.cargo_vcs_info.json b/deps/crates/vendor/equivalent/.cargo_vcs_info.json new file mode 100644 index 00000000000000..3ddaf6508be703 --- /dev/null +++ b/deps/crates/vendor/equivalent/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "44cdd44f8b8ebb5f9ae096c7550a5e74ffb7d6ae" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/equivalent/.github/workflows/ci.yml b/deps/crates/vendor/equivalent/.github/workflows/ci.yml new file mode 100644 index 00000000000000..06260a00b81da0 --- /dev/null +++ b/deps/crates/vendor/equivalent/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + merge_group: + +name: CI + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.6.0 # MSRV + - rust: stable + - rust: beta + - rust: nightly + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - name: Tests + run: | + cargo build --verbose + cargo test --verbose + + # One job that "summarizes" the success state of this pipeline. This can then be added to branch + # protection, rather than having to add each job separately. + success: + name: Success + runs-on: ubuntu-latest + needs: [tests] + # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/deps/crates/vendor/equivalent/Cargo.lock b/deps/crates/vendor/equivalent/Cargo.lock new file mode 100644 index 00000000000000..3de893db1802f7 --- /dev/null +++ b/deps/crates/vendor/equivalent/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "equivalent" +version = "1.0.2" + diff --git a/deps/crates/vendor/equivalent/Cargo.toml b/deps/crates/vendor/equivalent/Cargo.toml new file mode 100644 index 00000000000000..95eff849f249bc --- /dev/null +++ b/deps/crates/vendor/equivalent/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +rust-version = "1.6" +name = "equivalent" +version = "1.0.2" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Traits for key comparison in maps." +readme = "README.md" +keywords = [ + "hashmap", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/indexmap-rs/equivalent" + +[lib] +name = "equivalent" +path = "src/lib.rs" diff --git a/deps/crates/vendor/equivalent/Cargo.toml.orig b/deps/crates/vendor/equivalent/Cargo.toml.orig new file mode 100644 index 00000000000000..68f430312622a4 --- /dev/null +++ b/deps/crates/vendor/equivalent/Cargo.toml.orig @@ -0,0 +1,9 @@ +[package] +name = "equivalent" +version = "1.0.2" +rust-version = "1.6" +license = "Apache-2.0 OR MIT" +description = "Traits for key comparison in maps." +repository = "https://github.com/indexmap-rs/equivalent" +keywords = ["hashmap", "no_std"] +categories = ["data-structures", "no-std"] diff --git a/deps/crates/vendor/equivalent/LICENSE-APACHE b/deps/crates/vendor/equivalent/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/equivalent/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/equivalent/LICENSE-MIT b/deps/crates/vendor/equivalent/LICENSE-MIT new file mode 100644 index 00000000000000..5ac40dae7f6f1a --- /dev/null +++ b/deps/crates/vendor/equivalent/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016--2023 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/equivalent/README.md b/deps/crates/vendor/equivalent/README.md new file mode 100644 index 00000000000000..8ff7e24c8ce92c --- /dev/null +++ b/deps/crates/vendor/equivalent/README.md @@ -0,0 +1,25 @@ +# Equivalent + +[![crates.io](https://img.shields.io/crates/v/equivalent.svg)](https://crates.io/crates/equivalent) +[![docs](https://docs.rs/equivalent/badge.svg)](https://docs.rs/equivalent) + +`Equivalent` and `Comparable` are Rust traits for key comparison in maps. + +These may be used in the implementation of maps where the lookup type `Q` +may be different than the stored key type `K`. + +* `Q: Equivalent` checks for equality, similar to the `HashMap` + constraint `K: Borrow, Q: Eq`. +* `Q: Comparable` checks the ordering, similar to the `BTreeMap` + constraint `K: Borrow, Q: Ord`. + +These traits are not used by the maps in the standard library, but they may +add more flexibility in third-party map implementations, especially in +situations where a strict `K: Borrow` relationship is not available. + +## License + +Equivalent is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). See [LICENSE-APACHE](LICENSE-APACHE) and +[LICENSE-MIT](LICENSE-MIT) for details. Opening a pull request is +assumed to signal agreement with these licensing terms. diff --git a/deps/crates/vendor/equivalent/src/lib.rs b/deps/crates/vendor/equivalent/src/lib.rs new file mode 100644 index 00000000000000..09ba58dff3a872 --- /dev/null +++ b/deps/crates/vendor/equivalent/src/lib.rs @@ -0,0 +1,113 @@ +//! [`Equivalent`] and [`Comparable`] are traits for key comparison in maps. +//! +//! These may be used in the implementation of maps where the lookup type `Q` +//! may be different than the stored key type `K`. +//! +//! * `Q: Equivalent` checks for equality, similar to the `HashMap` +//! constraint `K: Borrow, Q: Eq`. +//! * `Q: Comparable` checks the ordering, similar to the `BTreeMap` +//! constraint `K: Borrow, Q: Ord`. +//! +//! These traits are not used by the maps in the standard library, but they may +//! add more flexibility in third-party map implementations, especially in +//! situations where a strict `K: Borrow` relationship is not available. +//! +//! # Examples +//! +//! ``` +//! use equivalent::*; +//! use std::cmp::Ordering; +//! +//! pub struct Pair(pub A, pub B); +//! +//! impl<'a, A: ?Sized, B: ?Sized, C, D> Equivalent<(C, D)> for Pair<&'a A, &'a B> +//! where +//! A: Equivalent, +//! B: Equivalent, +//! { +//! fn equivalent(&self, key: &(C, D)) -> bool { +//! self.0.equivalent(&key.0) && self.1.equivalent(&key.1) +//! } +//! } +//! +//! impl<'a, A: ?Sized, B: ?Sized, C, D> Comparable<(C, D)> for Pair<&'a A, &'a B> +//! where +//! A: Comparable, +//! B: Comparable, +//! { +//! fn compare(&self, key: &(C, D)) -> Ordering { +//! match self.0.compare(&key.0) { +//! Ordering::Equal => self.1.compare(&key.1), +//! not_equal => not_equal, +//! } +//! } +//! } +//! +//! fn main() { +//! let key = (String::from("foo"), String::from("bar")); +//! let q1 = Pair("foo", "bar"); +//! let q2 = Pair("boo", "bar"); +//! let q3 = Pair("foo", "baz"); +//! +//! assert!(q1.equivalent(&key)); +//! assert!(!q2.equivalent(&key)); +//! assert!(!q3.equivalent(&key)); +//! +//! assert_eq!(q1.compare(&key), Ordering::Equal); +//! assert_eq!(q2.compare(&key), Ordering::Less); +//! assert_eq!(q3.compare(&key), Ordering::Greater); +//! } +//! ``` + +#![no_std] + +use core::borrow::Borrow; +use core::cmp::Ordering; + +/// Key equivalence trait. +/// +/// This trait allows hash table lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Eq`, just +/// like `HashMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +/// +/// # Contract +/// +/// The implementor **must** hash like `K`, if it is hashable. +pub trait Equivalent { + /// Compare self to `key` and return `true` if they are equal. + fn equivalent(&self, key: &K) -> bool; +} + +impl Equivalent for Q +where + Q: Eq, + K: Borrow, +{ + #[inline] + fn equivalent(&self, key: &K) -> bool { + PartialEq::eq(self, key.borrow()) + } +} + +/// Key ordering trait. +/// +/// This trait allows ordered map lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Ord`, just +/// like `BTreeMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +pub trait Comparable: Equivalent { + /// Compare self to `key` and return their ordering. + fn compare(&self, key: &K) -> Ordering; +} + +impl Comparable for Q +where + Q: Ord, + K: Borrow, +{ + #[inline] + fn compare(&self, key: &K) -> Ordering { + Ord::cmp(self, key.borrow()) + } +} diff --git a/deps/crates/vendor/fallible-iterator/.cargo-checksum.json b/deps/crates/vendor/fallible-iterator/.cargo-checksum.json new file mode 100644 index 00000000000000..8654a3790c5f69 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"1477739f2a32cb87775e5e3758e503c373cf0cc1a3098c0d79b48c0d5ec04dfa",".github/workflows/rust.yml":"2aa6eac687124ec29e81ad52490de733354b1c497ea49200c823579f51a69f27","CHANGELOG.md":"ec998938be9e986d87f89f035b561045b9df6a014c889c1e09006e8a1f055504","Cargo.toml":"1eefc77c1092c098db3822fd01220a0015a1e3851320a953665823fb9b46b4c1","Cargo.toml.orig":"84ac9af2002c5190150223fbecfef0df6bcbe64b9e7d687988d5068980c53293","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"0816e154b159ba255c563f7c8c7df5bbb8cc5fc96f5ab8cf9f4743b4f41fe7eb","README.md":"852506da2ff54c00f46b440019585356be034cc35f7908bbb0a80249a8b782f8","src/lib.rs":"58c73ed996f1c80425784b655db890b0bd04c72eeb97ce57f17d610bb28ea78d","src/test.rs":"507ec94f625d6d1b4dbb957f055efe3486ff553b7b7b4a78019018c791b0bf28"},"package":"2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"} \ No newline at end of file diff --git a/deps/crates/vendor/fallible-iterator/.cargo_vcs_info.json b/deps/crates/vendor/fallible-iterator/.cargo_vcs_info.json new file mode 100644 index 00000000000000..7d1e1e6ba9d641 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "11cfa0558045e52bdb473c9eab6a1eb35a54e302" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/fallible-iterator/.github/workflows/rust.yml b/deps/crates/vendor/fallible-iterator/.github/workflows/rust.yml new file mode 100644 index 00000000000000..eae522bb5a625b --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/.github/workflows/rust.yml @@ -0,0 +1,30 @@ +on: [push, pull_request] + +name: Continuous integration + +jobs: + test: + name: Test Suite + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - beta + - nightly + - 1.36.0 # MSRV + + steps: + - uses: actions/checkout@v3 + + - name: Install rust nightly + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + + - uses: taiki-e/install-action@v2 + with: + tool: cargo-hack + + - run: cargo hack build --feature-powerset --all-targets + - run: cargo hack test --feature-powerset --all-targets diff --git a/deps/crates/vendor/fallible-iterator/CHANGELOG.md b/deps/crates/vendor/fallible-iterator/CHANGELOG.md new file mode 100644 index 00000000000000..a791507678230b --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/CHANGELOG.md @@ -0,0 +1,39 @@ +# Change Log + +## [v0.3.0] - 2023-05-22 + +### Removed + +* `FromFallibleIterator` trait is removed, `FallibleIterator::collect` now requires `std::iter::FromIterator`, + which has strictly more implementations. + +### Added + +* add convenient wrapper for std::iter::Iterator +* more utilities mirroring std::iter +* Peekable methods +* `IteratorExt` for convenient conversion +* `FallibleIterator::unwrap` + +## [v0.2.0] - 2019-03-10 + +### Changed + +* All closures used by adaptor methods now return `Result`s. +* `FromFallibleIterator::from_fallible_iterator` has been renamed to `from_fallible_iter` and now takes an + `IntoFallibleIterator`. +* `IntoFallibleIterator::into_fallible_iterator` has been renamed to `into_fallible_iter`. +* `IntoFallibleIterator::IntoIter` has been renamed to `IntoFallibleIter`. + +### Removed + +* `FallibleIterator::and_then` has been removed as `FallibleIterator::map` is now equivalent. + +### Added + +* Added `step_by`, `for_each`, `skip_while`, `take_while`, `skip`, `scan`, `flat_map`, `flatten`, `inspect`, + `partition`, `find_map`, `max_by`, `min_by`, `unzip`, `cycle`, and `try_fold` to `FallibleIterator`. +* Added `rfold` and `try_rfold` to `DoubleEndedFallibleIterator`. + +[Unreleased]: https://github.com/sfackler/rust-fallible-iterator/compare/v0.2.0...master +[v0.2.0]: https://github.com/sfackler/rust-fallible-iterator/compare/v0.1.5...v0.2.0 diff --git a/deps/crates/vendor/fallible-iterator/Cargo.toml b/deps/crates/vendor/fallible-iterator/Cargo.toml new file mode 100644 index 00000000000000..ed372d5ee75b7f --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "fallible-iterator" +version = "0.3.0" +authors = ["Steven Fackler "] +description = "Fallible iterator traits" +readme = "README.md" +categories = [ + "algorithms", + "no-std", +] +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/rust-fallible-iterator" + +[features] +alloc = [] +default = ["alloc"] +std = ["alloc"] diff --git a/deps/crates/vendor/fallible-iterator/Cargo.toml.orig b/deps/crates/vendor/fallible-iterator/Cargo.toml.orig new file mode 100644 index 00000000000000..000e1bff821ec8 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/Cargo.toml.orig @@ -0,0 +1,16 @@ +[package] +name = "fallible-iterator" +version = "0.3.0" +authors = ["Steven Fackler "] +edition = "2018" +license = "MIT/Apache-2.0" +description = "Fallible iterator traits" +repository = "https://github.com/sfackler/rust-fallible-iterator" +readme = "README.md" +categories = ["algorithms", "no-std"] + +[features] +default = ["alloc"] +alloc = [] +# Legacy feature, no longer needed but retained for backwards compatibility. +std = ["alloc"] diff --git a/deps/crates/vendor/fallible-iterator/LICENSE-APACHE b/deps/crates/vendor/fallible-iterator/LICENSE-APACHE new file mode 100644 index 00000000000000..8f71f43fee3f78 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/deps/crates/vendor/fallible-iterator/LICENSE-MIT b/deps/crates/vendor/fallible-iterator/LICENSE-MIT new file mode 100644 index 00000000000000..a7cfbe047326ef --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 The rust-openssl-verify Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/deps/crates/vendor/fallible-iterator/README.md b/deps/crates/vendor/fallible-iterator/README.md new file mode 100644 index 00000000000000..a0ea216a550250 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/README.md @@ -0,0 +1,16 @@ +[![crates.io](https://img.shields.io/crates/v/fallible-iterator.svg)](https://crates.io/crates/fallible-iterator) +[![docs.rs](https://docs.rs/fallible-iterator/badge.svg)](https://docs.rs/fallible-iterator) + +![Continuous integration](https://github.com/sfackler/rust-fallible-iterator/actions/workflows/rust.yml/badge.svg?branch=master&event=push) + +# rust-fallible-iterator + +"Fallible" iterators for Rust. + +## Features + +If the `std` or `alloc` features are enabled, this crate provides implementations for +`Box`, `Vec`, `BTreeMap`, and `BTreeSet`. If the `std` feature is enabled, this crate +additionally provides implementations for `HashMap` and `HashSet`. + +If the `std` feature is disabled, this crate does not depend on `libstd`. diff --git a/deps/crates/vendor/fallible-iterator/src/lib.rs b/deps/crates/vendor/fallible-iterator/src/lib.rs new file mode 100644 index 00000000000000..88e8d557a77194 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/src/lib.rs @@ -0,0 +1,2808 @@ +//! "Fallible" iterators. +//! +//! The iterator APIs in the Rust standard library do not support iteration +//! that can fail in a first class manner. These iterators are typically modeled +//! as iterating over `Result` values; for example, the `Lines` iterator +//! returns `io::Result`s. When simply iterating over these types, the +//! value being iterated over must be unwrapped in some way before it can be +//! used: +//! +//! ```ignore +//! for line in reader.lines() { +//! let line = line?; +//! // work with line +//! } +//! ``` +//! +//! In addition, many of the additional methods on the `Iterator` trait will +//! not behave properly in the presence of errors when working with these kinds +//! of iterators. For example, if one wanted to count the number of lines of +//! text in a `Read`er, this might be a way to go about it: +//! +//! ```ignore +//! let count = reader.lines().count(); +//! ``` +//! +//! This will return the proper value when the reader operates successfully, but +//! if it encounters an IO error, the result will either be slightly higher than +//! expected if the error is transient, or it may run forever if the error is +//! returned repeatedly! +//! +//! In contrast, a fallible iterator is built around the concept that a call to +//! `next` can fail. The trait has an additional `Error` associated type in +//! addition to the `Item` type, and `next` returns `Result, +//! Self::Error>` rather than `Option`. Methods like `count` return +//! `Result`s as well. +//! +//! This does mean that fallible iterators are incompatible with Rust's `for` +//! loop syntax, but `while let` loops offer a similar level of ergonomics: +//! +//! ```ignore +//! while let Some(item) = iter.next()? { +//! // work with item +//! } +//! ``` +//! +//! ## Fallible closure arguments +//! +//! Like `Iterator`, many `FallibleIterator` methods take closures as arguments. +//! These use the same signatures as their `Iterator` counterparts, except that +//! `FallibleIterator` expects the closures to be fallible: they return +//! `Result` instead of simply `T`. +//! +//! For example, the standard library's `Iterator::filter` adapter method +//! filters the underlying iterator according to a predicate provided by the +//! user, whose return type is `bool`. In `FallibleIterator::filter`, however, +//! the predicate returns `Result`: +//! +//! ``` +//! # use std::error::Error; +//! # use std::str::FromStr; +//! # use fallible_iterator::{convert, FallibleIterator}; +//! let numbers = convert("100\n200\nfern\n400".lines().map(Ok::<&str, Box>)); +//! let big_numbers = numbers.filter(|n| Ok(u64::from_str(n)? > 100)); +//! assert!(big_numbers.count().is_err()); +//! ``` +#![doc(html_root_url = "https://docs.rs/fallible-iterator/0.2")] +#![warn(missing_docs)] +#![no_std] + +use core::cmp::{self, Ordering}; +use core::convert::Infallible; +use core::iter; +use core::marker::PhantomData; + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +#[cfg(all(test, feature = "alloc"))] +mod test; + +enum FoldStop { + Break(T), + Err(E), +} + +impl From for FoldStop { + #[inline] + fn from(e: E) -> FoldStop { + FoldStop::Err(e) + } +} + +trait ResultExt { + fn unpack_fold(self) -> Result; +} + +impl ResultExt for Result> { + #[inline] + fn unpack_fold(self) -> Result { + match self { + Ok(v) => Ok(v), + Err(FoldStop::Break(v)) => Ok(v), + Err(FoldStop::Err(e)) => Err(e), + } + } +} + +/// An `Iterator`-like trait that allows for calculation of items to fail. +pub trait FallibleIterator { + /// The type being iterated over. + type Item; + + /// The error type. + type Error; + + /// Advances the iterator and returns the next value. + /// + /// Returns `Ok(None)` when iteration is finished. + /// + /// The behavior of calling this method after a previous call has returned + /// `Ok(None)` or `Err` is implementation defined. + fn next(&mut self) -> Result, Self::Error>; + + /// Returns bounds on the remaining length of the iterator. + /// + /// Specifically, the first half of the returned tuple is a lower bound and + /// the second half is an upper bound. + /// + /// For the upper bound, `None` indicates that the upper bound is either + /// unknown or larger than can be represented as a `usize`. + /// + /// Both bounds assume that all remaining calls to `next` succeed. That is, + /// `next` could return an `Err` in fewer calls than specified by the lower + /// bound. + /// + /// The default implementation returns `(0, None)`, which is correct for + /// any iterator. + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, None) + } + + /// Consumes the iterator, returning the number of remaining items. + #[inline] + fn count(self) -> Result + where + Self: Sized, + { + self.fold(0, |n, _| Ok(n + 1)) + } + + /// Returns the last element of the iterator. + #[inline] + fn last(self) -> Result, Self::Error> + where + Self: Sized, + { + self.fold(None, |_, v| Ok(Some(v))) + } + + /// Returns the `n`th element of the iterator. + #[inline] + fn nth(&mut self, mut n: usize) -> Result, Self::Error> { + while let Some(e) = self.next()? { + if n == 0 { + return Ok(Some(e)); + } + n -= 1; + } + Ok(None) + } + + /// Returns an iterator starting at the same point, but stepping by the given amount at each iteration. + /// + /// # Panics + /// + /// Panics if `step` is 0. + #[inline] + fn step_by(self, step: usize) -> StepBy + where + Self: Sized, + { + assert!(step != 0); + StepBy { + it: self, + step: step - 1, + first_take: true, + } + } + + /// Returns an iterator which yields the elements of this iterator followed + /// by another. + #[inline] + fn chain(self, it: I) -> Chain + where + I: IntoFallibleIterator, + Self: Sized, + { + Chain { + front: self, + back: it, + state: ChainState::Both, + } + } + + /// Returns an iterator that yields pairs of this iterator's and another + /// iterator's values. + #[inline] + fn zip(self, o: I) -> Zip + where + Self: Sized, + I: IntoFallibleIterator, + { + Zip(self, o.into_fallible_iter()) + } + + /// Returns an iterator which applies a fallible transform to the elements + /// of the underlying iterator. + #[inline] + fn map(self, f: F) -> Map + where + Self: Sized, + F: FnMut(Self::Item) -> Result, + { + Map { it: self, f } + } + + /// Calls a fallible closure on each element of an iterator. + #[inline] + fn for_each(self, mut f: F) -> Result<(), Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result<(), Self::Error>, + { + self.fold((), move |(), item| f(item)) + } + + /// Returns an iterator which uses a predicate to determine which values + /// should be yielded. The predicate may fail; such failures are passed to + /// the caller. + #[inline] + fn filter(self, f: F) -> Filter + where + Self: Sized, + F: FnMut(&Self::Item) -> Result, + { + Filter { it: self, f } + } + + /// Returns an iterator which both filters and maps. The closure may fail; + /// such failures are passed along to the consumer. + #[inline] + fn filter_map(self, f: F) -> FilterMap + where + Self: Sized, + F: FnMut(Self::Item) -> Result, Self::Error>, + { + FilterMap { it: self, f } + } + + /// Returns an iterator which yields the current iteration count as well + /// as the value. + #[inline] + fn enumerate(self) -> Enumerate + where + Self: Sized, + { + Enumerate { it: self, n: 0 } + } + + /// Returns an iterator that can peek at the next element without consuming + /// it. + #[inline] + fn peekable(self) -> Peekable + where + Self: Sized, + { + Peekable { + it: self, + next: None, + } + } + + /// Returns an iterator that skips elements based on a predicate. + #[inline] + fn skip_while

(self, predicate: P) -> SkipWhile + where + Self: Sized, + P: FnMut(&Self::Item) -> Result, + { + SkipWhile { + it: self, + flag: false, + predicate, + } + } + + /// Returns an iterator that yields elements based on a predicate. + #[inline] + fn take_while

(PhantomData
); + + impl SectionKind { + fn endian<'input, E>(self) -> Endian + where + E: Endianity, + T: UnwindSection>, + T::Offset: UnwindOffset, + { + if E::default().is_big_endian() { + Endian::Big + } else { + Endian::Little + } + } + + fn section<'input, E>(self, contents: &'input [u8]) -> T + where + E: Endianity, + T: UnwindSection> + ReadSection>, + T::Offset: UnwindOffset, + { + EndianSlice::new(contents, E::default()).into() + } + } + + fn debug_frame_le<'a>() -> SectionKind>> { + SectionKind(PhantomData) + } + + fn debug_frame_be<'a>() -> SectionKind>> { + SectionKind(PhantomData) + } + + fn eh_frame_le<'a>() -> SectionKind>> { + SectionKind(PhantomData) + } + + fn parse_fde( + section: Section, + input: &mut R, + get_cie: F, + ) -> Result> + where + R: Reader, + Section: UnwindSection, + O: UnwindOffset, + F: FnMut(&Section, &BaseAddresses, O) -> Result>, + { + let bases = Default::default(); + match parse_cfi_entry(&bases, §ion, input) { + Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie), + Ok(_) => Err(Error::NoEntryAtGivenOffset), + Err(e) => Err(e), + } + } + + // Mixin methods for `Section` to help define binary test data. + + trait CfiSectionMethods: GimliSectionMethods { + fn cie<'aug, 'input, E, T>( + self, + _kind: SectionKind, + augmentation: Option<&'aug str>, + cie: &mut CommonInformationEntry>, + ) -> Self + where + E: Endianity, + T: UnwindSection>, + T::Offset: UnwindOffset; + fn fde<'a, 'input, E, T, L>( + self, + _kind: SectionKind, + cie_offset: L, + fde: &mut FrameDescriptionEntry>, + ) -> Self + where + E: Endianity, + T: UnwindSection>, + T::Offset: UnwindOffset, + L: ToLabelOrNum<'a, u64>; + } + + impl CfiSectionMethods for Section { + fn cie<'aug, 'input, E, T>( + self, + _kind: SectionKind, + augmentation: Option<&'aug str>, + cie: &mut CommonInformationEntry>, + ) -> Self + where + E: Endianity, + T: UnwindSection>, + T::Offset: UnwindOffset, + { + cie.offset = self.size() as _; + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = match cie.format { + Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff), + Format::Dwarf64 => { + let section = self.D32(0xffff_ffff); + section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff) + } + }; + + let mut section = section.D8(cie.version); + + if let Some(augmentation) = augmentation { + section = section.append_bytes(augmentation.as_bytes()); + } + + // Null terminator for augmentation string. + let section = section.D8(0); + + let section = if T::has_address_and_segment_sizes(cie.version) { + section.D8(cie.address_size).D8(0) + } else { + section + }; + + let section = section + .uleb(cie.code_alignment_factor) + .sleb(cie.data_alignment_factor) + .uleb(cie.return_address_register.0.into()) + .append_bytes(cie.initial_instructions.slice()) + .mark(&end); + + cie.length = (&end - &start) as usize; + length.set_const(cie.length as u64); + + section + } + + fn fde<'a, 'input, E, T, L>( + self, + _kind: SectionKind, + cie_offset: L, + fde: &mut FrameDescriptionEntry>, + ) -> Self + where + E: Endianity, + T: UnwindSection>, + T::Offset: UnwindOffset, + L: ToLabelOrNum<'a, u64>, + { + fde.offset = self.size() as _; + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + assert_eq!(fde.format, fde.cie.format); + + let section = match T::cie_offset_encoding(fde.format) { + CieOffsetEncoding::U32 => { + let section = self.D32(&length).mark(&start); + match cie_offset.to_labelornum() { + LabelOrNum::Label(ref l) => section.D32(l), + LabelOrNum::Num(o) => section.D32(o as u32), + } + } + CieOffsetEncoding::U64 => { + let section = self.D32(0xffff_ffff); + section.D64(&length).mark(&start).D64(cie_offset) + } + }; + + let section = match fde.cie.address_size { + 4 => section + .D32(fde.initial_address() as u32) + .D32(fde.len() as u32), + 8 => section.D64(fde.initial_address()).D64(fde.len()), + x => panic!("Unsupported address size: {}", x), + }; + + let section = if let Some(ref augmentation) = fde.augmentation { + let cie_aug = fde + .cie + .augmentation + .expect("FDE has augmentation, but CIE doesn't"); + + if let Some(lsda) = augmentation.lsda { + // We only support writing `DW_EH_PE_absptr` here. + assert_eq!( + cie_aug + .lsda + .expect("FDE has lsda, but CIE doesn't") + .format(), + constants::DW_EH_PE_absptr + ); + + // Augmentation data length + let section = section.uleb(u64::from(fde.cie.address_size)); + match fde.cie.address_size { + 4 => section.D32({ + let x: u64 = lsda.pointer(); + x as u32 + }), + 8 => section.D64({ + let x: u64 = lsda.pointer(); + x + }), + x => panic!("Unsupported address size: {}", x), + } + } else { + // Even if we don't have any augmentation data, if there is + // an augmentation defined, we need to put the length in. + section.uleb(0) + } + } else { + section + }; + + let section = section.append_bytes(fde.instructions.slice()).mark(&end); + + fde.length = (&end - &start) as usize; + length.set_const(fde.length as u64); + + section + } + } + + trait ResultExt { + fn map_eof(self, input: &[u8]) -> Self; + } + + impl ResultExt for Result { + fn map_eof(self, input: &[u8]) -> Self { + match self { + Err(Error::UnexpectedEof(id)) => { + let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); + Err(Error::UnexpectedEof(id)) + } + r => r, + } + } + } + + fn assert_parse_cie<'input, E>( + kind: SectionKind>>, + section: Section, + address_size: u8, + expected: Result<( + EndianSlice<'input, E>, + CommonInformationEntry>, + )>, + ) where + E: Endianity, + { + let section = section.get_contents().unwrap(); + let mut debug_frame = kind.section(§ion); + debug_frame.set_address_size(address_size); + let input = &mut EndianSlice::new(§ion, E::default()); + let bases = Default::default(); + let result = CommonInformationEntry::parse(&bases, &debug_frame, input); + let result = result.map(|cie| (*input, cie)).map_eof(§ion); + assert_eq!(result, expected); + } + + #[test] + fn test_parse_cie_incomplete_length_32() { + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()).L16(5); + assert_parse_cie( + kind, + section, + 8, + Err(Error::UnexpectedEof(ReaderOffsetId(0))), + ); + } + + #[test] + fn test_parse_cie_incomplete_length_64() { + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .L32(0xffff_ffff) + .L32(12345); + assert_parse_cie( + kind, + section, + 8, + Err(Error::UnexpectedEof(ReaderOffsetId(4))), + ); + } + + #[test] + fn test_parse_cie_incomplete_id_32() { + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + // The length is not large enough to contain the ID. + .B32(3) + .B32(0xffff_ffff); + assert_parse_cie( + kind, + section, + 8, + Err(Error::UnexpectedEof(ReaderOffsetId(4))), + ); + } + + #[test] + fn test_parse_cie_bad_id_32() { + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + // Initial length + .B32(4) + // Not the CIE Id. + .B32(0xbad1_bad2); + assert_parse_cie(kind, section, 8, Err(Error::NotCieId)); + } + + #[test] + fn test_parse_cie_32_bad_version() { + let mut cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 99, + augmentation: None, + address_size: 4, + code_alignment_factor: 1, + data_alignment_factor: 2, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&[], LittleEndian), + }; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); + assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99))); + } + + #[test] + fn test_parse_cie_unknown_augmentation() { + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let augmentation = "replicant"; + let expected_rest = [1, 2, 3]; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + // Initial length + .L32(&length) + .mark(&start) + // CIE Id + .L32(0xffff_ffff) + // Version + .D8(4) + // Augmentation + .append_bytes(augmentation.as_bytes()) + // Null terminator + .D8(0) + // Extra augmented data that we can't understand. + .L32(1) + .L32(2) + .L32(3) + .L32(4) + .L32(5) + .L32(6) + .mark(&end) + .append_bytes(&expected_rest); + + let expected_length = (&end - &start) as u64; + length.set_const(expected_length); + + assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation)); + } + + fn test_parse_cie(format: Format, version: u8, address_size: u8) { + let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie = CommonInformationEntry { + offset: 0, + length: 0, + format, + version, + augmentation: None, + address_size, + code_alignment_factor: 16, + data_alignment_factor: 32, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), + }; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .cie(kind, None, &mut cie) + .append_bytes(&expected_rest); + + assert_parse_cie( + kind, + section, + address_size, + Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)), + ); + } + + #[test] + fn test_parse_cie_32_ok() { + test_parse_cie(Format::Dwarf32, 1, 4); + test_parse_cie(Format::Dwarf32, 1, 8); + test_parse_cie(Format::Dwarf32, 4, 4); + test_parse_cie(Format::Dwarf32, 4, 8); + } + + #[test] + fn test_parse_cie_64_ok() { + test_parse_cie(Format::Dwarf64, 1, 4); + test_parse_cie(Format::Dwarf64, 1, 8); + test_parse_cie(Format::Dwarf64, 4, 4); + test_parse_cie(Format::Dwarf64, 4, 8); + } + + #[test] + fn test_parse_cie_length_too_big() { + let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 0, + data_alignment_factor: 0, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), + }; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); + + let mut contents = section.get_contents().unwrap(); + + // Overwrite the length to be too big. + contents[0] = 0; + contents[1] = 0; + contents[2] = 0; + contents[3] = 255; + + let debug_frame = DebugFrame::new(&contents, LittleEndian); + let bases = Default::default(); + assert_eq!( + CommonInformationEntry::parse( + &bases, + &debug_frame, + &mut EndianSlice::new(&contents, LittleEndian) + ) + .map_eof(&contents), + Err(Error::UnexpectedEof(ReaderOffsetId(4))) + ); + } + + #[test] + fn test_parse_fde_incomplete_length_32() { + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()).L16(5); + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, LittleEndian); + assert_eq!( + parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), + Err(Error::UnexpectedEof(ReaderOffsetId(0))) + ); + } + + #[test] + fn test_parse_fde_incomplete_length_64() { + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .L32(0xffff_ffff) + .L32(12345); + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, LittleEndian); + assert_eq!( + parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), + Err(Error::UnexpectedEof(ReaderOffsetId(4))) + ); + } + + #[test] + fn test_parse_fde_incomplete_cie_pointer_32() { + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + // The length is not large enough to contain the CIE pointer. + .B32(3) + .B32(1994); + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, BigEndian); + assert_eq!( + parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), + Err(Error::UnexpectedEof(ReaderOffsetId(4))) + ); + } + + #[test] + fn test_parse_fde_32_ok() { + let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let cie_offset = 0xbad0_bad1; + let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); + + let cie = CommonInformationEntry { + offset: 0, + length: 100, + format: Format::Dwarf32, + version: 4, + augmentation: None, + // DWARF32 with a 64 bit address size! Holy moly! + address_size: 8, + code_alignment_factor: 3, + data_alignment_factor: 2, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&[], LittleEndian), + }; + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_beef, + address_range: 39, + augmentation: None, + instructions: EndianSlice::new(&expected_instrs, LittleEndian), + }; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&expected_rest); + + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, LittleEndian); + + let get_cie = |_: &_, _: &_, offset| { + assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); + Ok(cie.clone()) + }; + + assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_fde_64_ok() { + let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let cie_offset = 0xbad0_bad1; + let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); + + let cie = CommonInformationEntry { + offset: 0, + length: 100, + format: Format::Dwarf64, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 3, + data_alignment_factor: 2, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&[], LittleEndian), + }; + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf64, + cie: cie.clone(), + initial_address: 0xfeed_beef, + address_range: 999, + augmentation: None, + instructions: EndianSlice::new(&expected_instrs, LittleEndian), + }; + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&expected_rest); + + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, LittleEndian); + + let get_cie = |_: &_, _: &_, offset| { + assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); + Ok(cie.clone()) + }; + + assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_entry_on_cie_32_ok() { + let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 16, + data_alignment_factor: 32, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&expected_instrs, BigEndian), + }; + + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + .cie(kind, None, &mut cie) + .append_bytes(&expected_rest); + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, BigEndian); + + let bases = Default::default(); + assert_eq!( + parse_cfi_entry(&bases, &debug_frame, rest), + Ok(Some(CieOrFde::Cie(cie))) + ); + assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); + } + + #[test] + fn test_parse_cfi_entry_on_fde_32_ok() { + let cie_offset = 0x1234_5678; + let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); + + let cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 16, + data_alignment_factor: 32, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&[], BigEndian), + }; + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_beef, + address_range: 39, + augmentation: None, + instructions: EndianSlice::new(&expected_instrs, BigEndian), + }; + + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&expected_rest); + + let section = section.get_contents().unwrap(); + let debug_frame = kind.section(§ion); + let rest = &mut EndianSlice::new(§ion, BigEndian); + + let bases = Default::default(); + match parse_cfi_entry(&bases, &debug_frame, rest) { + Ok(Some(CieOrFde::Fde(partial))) => { + assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); + + assert_eq!(partial.length, fde.length); + assert_eq!(partial.format, fde.format); + assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize)); + + let get_cie = |_: &_, _: &_, offset| { + assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); + Ok(cie.clone()) + }; + + assert_eq!(partial.parse(get_cie), Ok(fde)); + } + otherwise => panic!("Unexpected result: {:#?}", otherwise), + } + } + + #[test] + fn test_cfi_entries_iter() { + let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); + + let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); + + let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect(); + + let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie1 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 1, + data_alignment_factor: 2, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian), + }; + + let mut cie2 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 3, + data_alignment_factor: 2, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian), + }; + + let cie1_location = Label::new(); + let cie2_location = Label::new(); + + // Write the CIEs first so that their length gets set before we clone + // them into the FDEs and our equality assertions down the line end up + // with all the CIEs always having he correct length. + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + .mark(&cie1_location) + .cie(kind, None, &mut cie1) + .mark(&cie2_location) + .cie(kind, None, &mut cie2); + + let mut fde1 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie1.clone(), + initial_address: 0xfeed_beef, + address_range: 39, + augmentation: None, + instructions: EndianSlice::new(&expected_instrs3, BigEndian), + }; + + let mut fde2 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie2.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: None, + instructions: EndianSlice::new(&expected_instrs4, BigEndian), + }; + + let section = + section + .fde(kind, &cie1_location, &mut fde1) + .fde(kind, &cie2_location, &mut fde2); + + section.start().set_const(0); + + let cie1_offset = cie1_location.value().unwrap() as usize; + let cie2_offset = cie2_location.value().unwrap() as usize; + + let contents = section.get_contents().unwrap(); + let debug_frame = kind.section(&contents); + + let bases = Default::default(); + let mut entries = debug_frame.entries(&bases); + + assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone())))); + assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone())))); + + match entries.next() { + Ok(Some(CieOrFde::Fde(partial))) => { + assert_eq!(partial.length, fde1.length); + assert_eq!(partial.format, fde1.format); + assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset)); + + let get_cie = |_: &_, _: &_, offset| { + assert_eq!(offset, DebugFrameOffset(cie1_offset)); + Ok(cie1.clone()) + }; + assert_eq!(partial.parse(get_cie), Ok(fde1)); + } + otherwise => panic!("Unexpected result: {:#?}", otherwise), + } + + match entries.next() { + Ok(Some(CieOrFde::Fde(partial))) => { + assert_eq!(partial.length, fde2.length); + assert_eq!(partial.format, fde2.format); + assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset)); + + let get_cie = |_: &_, _: &_, offset| { + assert_eq!(offset, DebugFrameOffset(cie2_offset)); + Ok(cie2.clone()) + }; + assert_eq!(partial.parse(get_cie), Ok(fde2)); + } + otherwise => panic!("Unexpected result: {:#?}", otherwise), + } + + assert_eq!(entries.next(), Ok(None)); + } + + #[test] + fn test_parse_cie_from_offset() { + let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf64, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 4, + data_alignment_factor: 8, + return_address_register: Register(12), + initial_instructions: EndianSlice::new(&instrs, LittleEndian), + }; + + let cie_location = Label::new(); + + let kind = debug_frame_le(); + let section = Section::with_endian(kind.endian()) + .append_bytes(&filler) + .mark(&cie_location) + .cie(kind, None, &mut cie) + .append_bytes(&filler); + + section.start().set_const(0); + + let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize); + + let contents = section.get_contents().unwrap(); + let debug_frame = kind.section(&contents); + let bases = Default::default(); + + assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie)); + } + + fn parse_cfi_instruction( + input: &mut R, + address_size: u8, + ) -> Result> { + let section = input.clone(); + let parameters = &PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size, + section: §ion, + }; + CallFrameInstruction::parse(input, None, parameters, Vendor::Default) + } + + #[test] + fn test_parse_cfi_instruction_advance_loc() { + let expected_rest = [1, 2, 3, 4]; + let expected_delta = 42; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_advance_loc.0 | expected_delta) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(expected_delta), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_offset() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 3; + let expected_offset = 1997; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_offset.0 | expected_reg) + .uleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Offset { + register: Register(expected_reg.into()), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_restore() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 3; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_restore.0 | expected_reg) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Restore { + register: Register(expected_reg.into()), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_nop() { + let expected_rest = [1, 2, 3, 4]; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_nop.0) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Nop) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_set_loc() { + let expected_rest = [1, 2, 3, 4]; + let expected_addr = 0xdead_beef; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_set_loc.0) + .L64(expected_addr) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::SetLoc { + address: expected_addr, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_set_loc_encoding() { + let text_base = 0xfeed_face; + let addr_offset = 0xbeef; + let expected_addr = text_base + addr_offset; + let expected_rest = [1, 2, 3, 4]; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_set_loc.0) + .L64(addr_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + let parameters = &PointerEncodingParameters { + bases: &BaseAddresses::default().set_text(text_base).eh_frame, + func_base: None, + address_size: 8, + section: &EndianSlice::new(&[], LittleEndian), + }; + assert_eq!( + CallFrameInstruction::parse( + input, + Some(constants::DW_EH_PE_textrel), + parameters, + Vendor::Default + ), + Ok(CallFrameInstruction::SetLoc { + address: expected_addr, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_advance_loc1() { + let expected_rest = [1, 2, 3, 4]; + let expected_delta = 8; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_advance_loc1.0) + .D8(expected_delta) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(expected_delta), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_advance_loc2() { + let expected_rest = [1, 2, 3, 4]; + let expected_delta = 500; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_advance_loc2.0) + .L16(expected_delta) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(expected_delta), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_advance_loc4() { + let expected_rest = [1, 2, 3, 4]; + let expected_delta = 1 << 20; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_advance_loc4.0) + .L32(expected_delta) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::AdvanceLoc { + delta: expected_delta, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_offset_extended() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 7; + let expected_offset = 33; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_offset_extended.0) + .uleb(expected_reg.into()) + .uleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Offset { + register: Register(expected_reg), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_restore_extended() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 7; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_restore_extended.0) + .uleb(expected_reg.into()) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Restore { + register: Register(expected_reg), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_undefined() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 7; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_undefined.0) + .uleb(expected_reg.into()) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Undefined { + register: Register(expected_reg), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_same_value() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 7; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_same_value.0) + .uleb(expected_reg.into()) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::SameValue { + register: Register(expected_reg), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_register() { + let expected_rest = [1, 2, 3, 4]; + let expected_dest_reg = 7; + let expected_src_reg = 8; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_register.0) + .uleb(expected_dest_reg.into()) + .uleb(expected_src_reg.into()) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Register { + dest_register: Register(expected_dest_reg), + src_register: Register(expected_src_reg), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_remember_state() { + let expected_rest = [1, 2, 3, 4]; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_remember_state.0) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::RememberState) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_restore_state() { + let expected_rest = [1, 2, 3, 4]; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_restore_state.0) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::RestoreState) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 2; + let expected_offset = 0; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa.0) + .uleb(expected_reg.into()) + .uleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfa { + register: Register(expected_reg), + offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa_register() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 2; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa_register.0) + .uleb(expected_reg.into()) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfaRegister { + register: Register(expected_reg), + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa_offset() { + let expected_rest = [1, 2, 3, 4]; + let expected_offset = 23; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa_offset.0) + .uleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfaOffset { + offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa_expression() { + let expected_rest = [1, 2, 3, 4]; + let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa_expression.0) + .D8(&length) + .mark(&start) + .append_bytes(&expected_expr) + .mark(&end) + .append_bytes(&expected_rest); + + length.set_const((&end - &start) as u64); + let expected_expression = UnwindExpression { + offset: (&start - §ion.start()) as usize, + length: (&end - &start) as usize, + }; + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfaExpression { + expression: expected_expression, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_expression() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 99; + let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_expression.0) + .uleb(expected_reg.into()) + .D8(&length) + .mark(&start) + .append_bytes(&expected_expr) + .mark(&end) + .append_bytes(&expected_rest); + + length.set_const((&end - &start) as u64); + let expected_expression = UnwindExpression { + offset: (&start - §ion.start()) as usize, + length: (&end - &start) as usize, + }; + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::Expression { + register: Register(expected_reg), + expression: expected_expression, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_offset_extended_sf() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 7; + let expected_offset = -33; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_offset_extended_sf.0) + .uleb(expected_reg.into()) + .sleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::OffsetExtendedSf { + register: Register(expected_reg), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa_sf() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 2; + let expected_offset = -9999; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa_sf.0) + .uleb(expected_reg.into()) + .sleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfaSf { + register: Register(expected_reg), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_def_cfa_offset_sf() { + let expected_rest = [1, 2, 3, 4]; + let expected_offset = -123; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_def_cfa_offset_sf.0) + .sleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::DefCfaOffsetSf { + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_val_offset() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 50; + let expected_offset = 23; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_val_offset.0) + .uleb(expected_reg.into()) + .uleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::ValOffset { + register: Register(expected_reg), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_val_offset_sf() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 50; + let expected_offset = -23; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_val_offset_sf.0) + .uleb(expected_reg.into()) + .sleb(expected_offset) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::ValOffsetSf { + register: Register(expected_reg), + factored_offset: expected_offset, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_val_expression() { + let expected_rest = [1, 2, 3, 4]; + let expected_reg = 50; + let expected_expr = [2, 2, 1, 1, 5, 5]; + + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_val_expression.0) + .uleb(expected_reg.into()) + .D8(&length) + .mark(&start) + .append_bytes(&expected_expr) + .mark(&end) + .append_bytes(&expected_rest); + + length.set_const((&end - &start) as u64); + let expected_expression = UnwindExpression { + offset: (&start - §ion.start()) as usize, + length: (&end - &start) as usize, + }; + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + + assert_eq!( + parse_cfi_instruction(input, 8), + Ok(CallFrameInstruction::ValExpression { + register: Register(expected_reg), + expression: expected_expression, + }) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_negate_ra_state() { + let expected_rest = [1, 2, 3, 4]; + let section = Section::with_endian(Endian::Little) + .D8(constants::DW_CFA_AARCH64_negate_ra_state.0) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + let parameters = &PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 8, + section: &EndianSlice::default(), + }; + assert_eq!( + CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64), + Ok(CallFrameInstruction::NegateRaState) + ); + assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_cfi_instruction_unknown_instruction() { + let expected_rest = [1, 2, 3, 4]; + let unknown_instr = constants::DwCfa(0b0011_1111); + let section = Section::with_endian(Endian::Little) + .D8(unknown_instr.0) + .append_bytes(&expected_rest); + let contents = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&contents, LittleEndian); + assert_eq!( + parse_cfi_instruction(input, 8), + Err(Error::UnknownCallFrameInstruction(unknown_instr)) + ); + } + + #[test] + fn test_call_frame_instruction_iter_ok() { + let expected_reg = 50; + let expected_expr = [2, 2, 1, 1, 5, 5]; + let expected_delta = 230; + + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = Section::with_endian(Endian::Big) + .D8(constants::DW_CFA_val_expression.0) + .uleb(expected_reg.into()) + .D8(&length) + .mark(&start) + .append_bytes(&expected_expr) + .mark(&end) + .D8(constants::DW_CFA_advance_loc1.0) + .D8(expected_delta); + + length.set_const((&end - &start) as u64); + let expected_expression = UnwindExpression { + offset: (&start - §ion.start()) as usize, + length: (&end - &start) as usize, + }; + let contents = section.get_contents().unwrap(); + let input = EndianSlice::new(&contents, BigEndian); + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 8, + section: &input, + }; + let mut iter = CallFrameInstructionIter { + input, + address_encoding: None, + parameters, + vendor: Vendor::Default, + }; + + assert_eq!( + iter.next(), + Ok(Some(CallFrameInstruction::ValExpression { + register: Register(expected_reg), + expression: expected_expression, + })) + ); + + assert_eq!( + iter.next(), + Ok(Some(CallFrameInstruction::AdvanceLoc { + delta: u32::from(expected_delta), + })) + ); + + assert_eq!(iter.next(), Ok(None)); + } + + #[test] + fn test_call_frame_instruction_iter_err() { + // DW_CFA_advance_loc1 without an operand. + let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0); + + let contents = section.get_contents().unwrap(); + let input = EndianSlice::new(&contents, BigEndian); + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 8, + section: &EndianSlice::default(), + }; + let mut iter = CallFrameInstructionIter { + input, + address_encoding: None, + parameters, + vendor: Vendor::Default, + }; + + assert_eq!( + iter.next().map_eof(&contents), + Err(Error::UnexpectedEof(ReaderOffsetId(1))) + ); + assert_eq!(iter.next(), Ok(None)); + } + + fn assert_eval<'a, I>( + mut initial_ctx: UnwindContext, + expected_ctx: UnwindContext, + cie: CommonInformationEntry>, + fde: Option>>, + instructions: I, + ) where + I: AsRef<[(Result, CallFrameInstruction)]>, + { + { + let section = &DebugFrame::from(EndianSlice::default()); + let bases = &BaseAddresses::default(); + let mut table = match fde { + Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde), + None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie), + }; + for (expected_result, instruction) in instructions.as_ref() { + assert_eq!(*expected_result, table.evaluate(instruction.clone())); + } + } + + assert_eq!(expected_ctx, initial_ctx); + } + + fn make_test_cie<'a>() -> CommonInformationEntry> { + CommonInformationEntry { + offset: 0, + format: Format::Dwarf64, + length: 0, + return_address_register: Register(0), + version: 4, + address_size: mem::size_of::() as u8, + initial_instructions: EndianSlice::new(&[], LittleEndian), + augmentation: None, + data_alignment_factor: 2, + code_alignment_factor: 3, + } + } + + #[test] + fn test_eval_set_loc() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected.row_mut().end_address = 42; + let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_set_loc_backwards() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.row_mut().start_address = 999; + let expected = ctx.clone(); + let instructions = [( + Err(Error::InvalidAddressRange), + CallFrameInstruction::SetLoc { address: 42 }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_advance_loc() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.row_mut().start_address = 3; + let mut expected = ctx.clone(); + expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor; + let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_advance_loc_overflow_32() { + let mut cie = make_test_cie(); + cie.address_size = 4; + let mut ctx = UnwindContext::new(); + ctx.row_mut().start_address = u32::MAX.into(); + let expected = ctx.clone(); + let instructions = [( + Err(Error::AddressOverflow), + CallFrameInstruction::AdvanceLoc { delta: 42 }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_advance_loc_overflow_64() { + let mut cie = make_test_cie(); + cie.address_size = 8; + let mut ctx = UnwindContext::new(); + ctx.row_mut().start_address = u64::MAX; + let expected = ctx.clone(); + let instructions = [( + Err(Error::AddressOverflow), + CallFrameInstruction::AdvanceLoc { delta: 42 }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected.set_cfa(CfaRule::RegisterAndOffset { + register: Register(42), + offset: 36, + }); + let instructions = [( + Ok(false), + CallFrameInstruction::DefCfa { + register: Register(42), + offset: 36, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_sf() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected.set_cfa(CfaRule::RegisterAndOffset { + register: Register(42), + offset: 36 * cie.data_alignment_factor as i64, + }); + let instructions = [( + Ok(false), + CallFrameInstruction::DefCfaSf { + register: Register(42), + factored_offset: 36, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_register() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.set_cfa(CfaRule::RegisterAndOffset { + register: Register(3), + offset: 8, + }); + let mut expected = ctx.clone(); + expected.set_cfa(CfaRule::RegisterAndOffset { + register: Register(42), + offset: 8, + }); + let instructions = [( + Ok(false), + CallFrameInstruction::DefCfaRegister { + register: Register(42), + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_register_invalid_context() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.set_cfa(CfaRule::Expression(UnwindExpression { + offset: 0, + length: 0, + })); + let expected = ctx.clone(); + let instructions = [( + Err(Error::CfiInstructionInInvalidContext), + CallFrameInstruction::DefCfaRegister { + register: Register(42), + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_offset() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.set_cfa(CfaRule::RegisterAndOffset { + register: Register(3), + offset: 8, + }); + let mut expected = ctx.clone(); + expected.set_cfa(CfaRule::RegisterAndOffset { + register: Register(3), + offset: 42, + }); + let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_offset_invalid_context() { + let cie = make_test_cie(); + let mut ctx = UnwindContext::new(); + ctx.set_cfa(CfaRule::Expression(UnwindExpression { + offset: 10, + length: 11, + })); + let expected = ctx.clone(); + let instructions = [( + Err(Error::CfiInstructionInInvalidContext), + CallFrameInstruction::DefCfaOffset { offset: 1993 }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_def_cfa_expression() { + let expr = UnwindExpression { + offset: 10, + length: 11, + }; + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected.set_cfa(CfaRule::Expression(expr)); + let instructions = [( + Ok(false), + CallFrameInstruction::DefCfaExpression { expression: expr }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_undefined() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(Register(5), RegisterRule::Undefined) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::Undefined { + register: Register(5), + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_same_value() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(Register(0), RegisterRule::SameValue) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::SameValue { + register: Register(0), + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_offset() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule( + Register(2), + RegisterRule::Offset(3 * cie.data_alignment_factor), + ) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::Offset { + register: Register(2), + factored_offset: 3, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_offset_extended_sf() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule( + Register(4), + RegisterRule::Offset(-3 * cie.data_alignment_factor), + ) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::OffsetExtendedSf { + register: Register(4), + factored_offset: -3, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_val_offset() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule( + Register(5), + RegisterRule::ValOffset(7 * cie.data_alignment_factor), + ) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::ValOffset { + register: Register(5), + factored_offset: 7, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_val_offset_sf() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule( + Register(5), + RegisterRule::ValOffset(-7 * cie.data_alignment_factor), + ) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::ValOffsetSf { + register: Register(5), + factored_offset: -7, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_expression() { + let expr = UnwindExpression { + offset: 10, + length: 11, + }; + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(Register(9), RegisterRule::Expression(expr)) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::Expression { + register: Register(9), + expression: expr, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_val_expression() { + let expr = UnwindExpression { + offset: 10, + length: 11, + }; + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(Register(9), RegisterRule::ValExpression(expr)) + .unwrap(); + let instructions = [( + Ok(false), + CallFrameInstruction::ValExpression { + register: Register(9), + expression: expr, + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_restore() { + let cie = make_test_cie(); + let fde = FrameDescriptionEntry { + offset: 0, + format: Format::Dwarf64, + length: 0, + address_range: 0, + augmentation: None, + initial_address: 0, + cie: cie.clone(), + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let mut ctx = UnwindContext::new(); + ctx.set_register_rule(Register(0), RegisterRule::Offset(1)) + .unwrap(); + ctx.save_initial_rules().unwrap(); + let expected = ctx.clone(); + ctx.set_register_rule(Register(0), RegisterRule::Offset(2)) + .unwrap(); + + let instructions = [( + Ok(false), + CallFrameInstruction::Restore { + register: Register(0), + }, + )]; + assert_eval(ctx, expected, cie, Some(fde), instructions); + } + + #[test] + fn test_eval_restore_havent_saved_initial_context() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let expected = ctx.clone(); + let instructions = [( + Err(Error::CfiInstructionInInvalidContext), + CallFrameInstruction::Restore { + register: Register(0), + }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_remember_state() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected.push_row().unwrap(); + let instructions = [(Ok(false), CallFrameInstruction::RememberState)]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_restore_state() { + let cie = make_test_cie(); + + let mut ctx = UnwindContext::new(); + ctx.set_start_address(1); + ctx.set_register_rule(Register(0), RegisterRule::SameValue) + .unwrap(); + let mut expected = ctx.clone(); + ctx.push_row().unwrap(); + ctx.set_start_address(2); + ctx.set_register_rule(Register(0), RegisterRule::Offset(16)) + .unwrap(); + + // Restore state should preserve current location. + expected.set_start_address(2); + + let instructions = [ + // First one pops just fine. + (Ok(false), CallFrameInstruction::RestoreState), + // Second pop would try to pop out of bounds. + ( + Err(Error::PopWithEmptyStack), + CallFrameInstruction::RestoreState, + ), + ]; + + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_negate_ra_state() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1)) + .unwrap(); + let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)]; + assert_eval(ctx, expected, cie, None, instructions); + + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0)) + .unwrap(); + let instructions = [ + (Ok(false), CallFrameInstruction::NegateRaState), + (Ok(false), CallFrameInstruction::NegateRaState), + ]; + assert_eval(ctx, expected, cie, None, instructions); + + // NegateRaState can't be used with other instructions. + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let mut expected = ctx.clone(); + expected + .set_register_rule( + crate::AArch64::RA_SIGN_STATE, + RegisterRule::Offset(cie.data_alignment_factor as i64), + ) + .unwrap(); + let instructions = [ + ( + Ok(false), + CallFrameInstruction::Offset { + register: crate::AArch64::RA_SIGN_STATE, + factored_offset: 1, + }, + ), + ( + Err(Error::CfiInstructionInInvalidContext), + CallFrameInstruction::NegateRaState, + ), + ]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_nop() { + let cie = make_test_cie(); + let ctx = UnwindContext::new(); + let expected = ctx.clone(); + let instructions = [(Ok(false), CallFrameInstruction::Nop)]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_unwind_table_cie_no_rule() { + let initial_instructions = Section::with_endian(Endian::Little) + // The CFA is -12 from register 4. + .D8(constants::DW_CFA_def_cfa_sf.0) + .uleb(4) + .sleb(-12) + .append_repeated(constants::DW_CFA_nop.0, 4); + let initial_instructions = initial_instructions.get_contents().unwrap(); + + let cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), + }; + + let instructions = Section::with_endian(Endian::Little) + // A bunch of nop padding. + .append_repeated(constants::DW_CFA_nop.0, 8); + let instructions = instructions.get_contents().unwrap(); + + let fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0, + address_range: 100, + augmentation: None, + instructions: EndianSlice::new(&instructions, LittleEndian), + }; + + let section = &DebugFrame::from(EndianSlice::default()); + let bases = &BaseAddresses::default(); + let mut ctx = Box::new(UnwindContext::new()); + + let mut table = fde + .rows(section, bases, &mut ctx) + .expect("Should run initial program OK"); + assert!(table.ctx.is_initialized); + let expected_initial_rule = (Register(0), RegisterRule::Undefined); + assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule)); + + { + let row = table.next_row().expect("Should evaluate first row OK"); + let expected = UnwindTableRow { + start_address: 0, + end_address: 100, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [].iter().collect(), + }; + assert_eq!(Some(&expected), row); + } + + // All done! + assert_eq!(Ok(None), table.next_row()); + assert_eq!(Ok(None), table.next_row()); + } + + #[test] + fn test_unwind_table_cie_single_rule() { + let initial_instructions = Section::with_endian(Endian::Little) + // The CFA is -12 from register 4. + .D8(constants::DW_CFA_def_cfa_sf.0) + .uleb(4) + .sleb(-12) + // Register 3 is 4 from the CFA. + .D8(constants::DW_CFA_offset.0 | 3) + .uleb(4) + .append_repeated(constants::DW_CFA_nop.0, 4); + let initial_instructions = initial_instructions.get_contents().unwrap(); + + let cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), + }; + + let instructions = Section::with_endian(Endian::Little) + // A bunch of nop padding. + .append_repeated(constants::DW_CFA_nop.0, 8); + let instructions = instructions.get_contents().unwrap(); + + let fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0, + address_range: 100, + augmentation: None, + instructions: EndianSlice::new(&instructions, LittleEndian), + }; + + let section = &DebugFrame::from(EndianSlice::default()); + let bases = &BaseAddresses::default(); + let mut ctx = Box::new(UnwindContext::new()); + + let mut table = fde + .rows(section, bases, &mut ctx) + .expect("Should run initial program OK"); + assert!(table.ctx.is_initialized); + let expected_initial_rule = (Register(3), RegisterRule::Offset(4)); + assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule)); + + { + let row = table.next_row().expect("Should evaluate first row OK"); + let expected = UnwindTableRow { + start_address: 0, + end_address: 100, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(), + }; + assert_eq!(Some(&expected), row); + } + + // All done! + assert_eq!(Ok(None), table.next_row()); + assert_eq!(Ok(None), table.next_row()); + } + + #[test] + fn test_unwind_table_cie_invalid_rule() { + let initial_instructions1 = Section::with_endian(Endian::Little) + // Test that stack length is reset. + .D8(constants::DW_CFA_remember_state.0) + // Test that stack value is reset (different register from that used later). + .D8(constants::DW_CFA_offset.0 | 4) + .uleb(8) + // Invalid due to missing operands. + .D8(constants::DW_CFA_offset.0); + let initial_instructions1 = initial_instructions1.get_contents().unwrap(); + + let cie1 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian), + }; + + let initial_instructions2 = Section::with_endian(Endian::Little) + // Register 3 is 4 from the CFA. + .D8(constants::DW_CFA_offset.0 | 3) + .uleb(4) + .append_repeated(constants::DW_CFA_nop.0, 4); + let initial_instructions2 = initial_instructions2.get_contents().unwrap(); + + let cie2 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian), + }; + + let fde1 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie1.clone(), + initial_address: 0, + address_range: 100, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let fde2 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie2.clone(), + initial_address: 0, + address_range: 100, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let section = &DebugFrame::from(EndianSlice::default()); + let bases = &BaseAddresses::default(); + let mut ctx = Box::new(UnwindContext::new()); + + let table = fde1 + .rows(section, bases, &mut ctx) + .map_eof(&initial_instructions1); + assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4)))); + assert!(!ctx.is_initialized); + assert_eq!(ctx.stack.len(), 2); + assert_eq!(ctx.initial_rule, None); + + let _table = fde2 + .rows(section, bases, &mut ctx) + .expect("Should run initial program OK"); + assert!(ctx.is_initialized); + assert_eq!(ctx.stack.len(), 1); + let expected_initial_rule = (Register(3), RegisterRule::Offset(4)); + assert_eq!(ctx.initial_rule, Some(expected_initial_rule)); + } + + #[test] + fn test_unwind_table_next_row() { + #[allow(clippy::identity_op)] + let initial_instructions = Section::with_endian(Endian::Little) + // The CFA is -12 from register 4. + .D8(constants::DW_CFA_def_cfa_sf.0) + .uleb(4) + .sleb(-12) + // Register 0 is 8 from the CFA. + .D8(constants::DW_CFA_offset.0 | 0) + .uleb(8) + // Register 3 is 4 from the CFA. + .D8(constants::DW_CFA_offset.0 | 3) + .uleb(4) + .append_repeated(constants::DW_CFA_nop.0, 4); + let initial_instructions = initial_instructions.get_contents().unwrap(); + + let cie = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), + }; + + let instructions = Section::with_endian(Endian::Little) + // Initial instructions form a row, advance the address by 1. + .D8(constants::DW_CFA_advance_loc1.0) + .D8(1) + // Register 0 is -16 from the CFA. + .D8(constants::DW_CFA_offset_extended_sf.0) + .uleb(0) + .sleb(-16) + // Finish this row, advance the address by 32. + .D8(constants::DW_CFA_advance_loc1.0) + .D8(32) + // Register 3 is -4 from the CFA. + .D8(constants::DW_CFA_offset_extended_sf.0) + .uleb(3) + .sleb(-4) + // Finish this row, advance the address by 64. + .D8(constants::DW_CFA_advance_loc1.0) + .D8(64) + // Register 5 is 4 from the CFA. + .D8(constants::DW_CFA_offset.0 | 5) + .uleb(4) + // A bunch of nop padding. + .append_repeated(constants::DW_CFA_nop.0, 8); + let instructions = instructions.get_contents().unwrap(); + + let fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0, + address_range: 100, + augmentation: None, + instructions: EndianSlice::new(&instructions, LittleEndian), + }; + + let section = &DebugFrame::from(EndianSlice::default()); + let bases = &BaseAddresses::default(); + let mut ctx = Box::new(UnwindContext::new()); + + let mut table = fde + .rows(section, bases, &mut ctx) + .expect("Should run initial program OK"); + assert!(table.ctx.is_initialized); + assert!(table.ctx.initial_rule.is_none()); + let expected_initial_rules: RegisterRuleMap<_> = [ + (Register(0), RegisterRule::Offset(8)), + (Register(3), RegisterRule::Offset(4)), + ] + .iter() + .collect(); + assert_eq!(table.ctx.stack[0].registers, expected_initial_rules); + + { + let row = table.next_row().expect("Should evaluate first row OK"); + let expected = UnwindTableRow { + start_address: 0, + end_address: 1, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [ + (Register(0), RegisterRule::Offset(8)), + (Register(3), RegisterRule::Offset(4)), + ] + .iter() + .collect(), + }; + assert_eq!(Some(&expected), row); + } + + { + let row = table.next_row().expect("Should evaluate second row OK"); + let expected = UnwindTableRow { + start_address: 1, + end_address: 33, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [ + (Register(0), RegisterRule::Offset(-16)), + (Register(3), RegisterRule::Offset(4)), + ] + .iter() + .collect(), + }; + assert_eq!(Some(&expected), row); + } + + { + let row = table.next_row().expect("Should evaluate third row OK"); + let expected = UnwindTableRow { + start_address: 33, + end_address: 97, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [ + (Register(0), RegisterRule::Offset(-16)), + (Register(3), RegisterRule::Offset(-4)), + ] + .iter() + .collect(), + }; + assert_eq!(Some(&expected), row); + } + + { + let row = table.next_row().expect("Should evaluate fourth row OK"); + let expected = UnwindTableRow { + start_address: 97, + end_address: 100, + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [ + (Register(0), RegisterRule::Offset(-16)), + (Register(3), RegisterRule::Offset(-4)), + (Register(5), RegisterRule::Offset(4)), + ] + .iter() + .collect(), + }; + assert_eq!(Some(&expected), row); + } + + // All done! + assert_eq!(Ok(None), table.next_row()); + assert_eq!(Ok(None), table.next_row()); + } + + #[test] + fn test_unwind_info_for_address_ok() { + let instrs1 = Section::with_endian(Endian::Big) + // The CFA is -12 from register 4. + .D8(constants::DW_CFA_def_cfa_sf.0) + .uleb(4) + .sleb(-12); + let instrs1 = instrs1.get_contents().unwrap(); + + let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); + + let instrs3 = Section::with_endian(Endian::Big) + // Initial instructions form a row, advance the address by 100. + .D8(constants::DW_CFA_advance_loc1.0) + .D8(100) + // Register 0 is -16 from the CFA. + .D8(constants::DW_CFA_offset_extended_sf.0) + .uleb(0) + .sleb(-16); + let instrs3 = instrs3.get_contents().unwrap(); + + let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); + + let mut cie1 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 8, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(3), + initial_instructions: EndianSlice::new(&instrs1, BigEndian), + }; + + let mut cie2 = CommonInformationEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + version: 4, + augmentation: None, + address_size: 4, + code_alignment_factor: 1, + data_alignment_factor: 1, + return_address_register: Register(1), + initial_instructions: EndianSlice::new(&instrs2, BigEndian), + }; + + let cie1_location = Label::new(); + let cie2_location = Label::new(); + + // Write the CIEs first so that their length gets set before we clone + // them into the FDEs and our equality assertions down the line end up + // with all the CIEs always having he correct length. + let kind = debug_frame_be(); + let section = Section::with_endian(kind.endian()) + .mark(&cie1_location) + .cie(kind, None, &mut cie1) + .mark(&cie2_location) + .cie(kind, None, &mut cie2); + + let mut fde1 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie1.clone(), + initial_address: 0xfeed_beef, + address_range: 200, + augmentation: None, + instructions: EndianSlice::new(&instrs3, BigEndian), + }; + + let mut fde2 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie2.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: None, + instructions: EndianSlice::new(&instrs4, BigEndian), + }; + + let section = + section + .fde(kind, &cie1_location, &mut fde1) + .fde(kind, &cie2_location, &mut fde2); + section.start().set_const(0); + + let contents = section.get_contents().unwrap(); + let debug_frame = kind.section(&contents); + + // Get the second row of the unwind table in `instrs3`. + let bases = Default::default(); + let mut ctx = Box::new(UnwindContext::new()); + let result = debug_frame.unwind_info_for_address( + &bases, + &mut ctx, + 0xfeed_beef + 150, + DebugFrame::cie_from_offset, + ); + assert!(result.is_ok()); + let unwind_info = result.unwrap(); + + assert_eq!( + *unwind_info, + UnwindTableRow { + start_address: fde1.initial_address() + 100, + end_address: fde1.end_address(), + saved_args_size: 0, + cfa: CfaRule::RegisterAndOffset { + register: Register(4), + offset: -12, + }, + registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(), + } + ); + } + + #[test] + fn test_unwind_info_for_address_not_found() { + let debug_frame = DebugFrame::new(&[], NativeEndian); + let bases = Default::default(); + let mut ctx = Box::new(UnwindContext::new()); + let result = debug_frame.unwind_info_for_address( + &bases, + &mut ctx, + 0xbadb_ad99, + DebugFrame::cie_from_offset, + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress); + } + + #[test] + fn test_eh_frame_hdr_unknown_version() { + let bases = BaseAddresses::default(); + let buf = &[42]; + let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::UnknownVersion(42)); + } + + #[test] + fn test_eh_frame_hdr_omit_ehptr() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0xff) + .L8(0x03) + .L8(0x0b) + .L32(2) + .L32(10) + .L32(1) + .L32(20) + .L32(2) + .L32(0); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding); + } + + #[test] + fn test_eh_frame_hdr_omit_count() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x0b) + .L8(0xff) + .L8(0x0b) + .L32(0x12345); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); + assert!(result.table().is_none()); + } + + #[test] + fn test_eh_frame_hdr_omit_table() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x0b) + .L8(0x03) + .L8(0xff) + .L32(0x12345) + .L32(2); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); + assert!(result.table().is_none()); + } + + #[test] + fn test_eh_frame_hdr_varlen_table() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x0b) + .L8(0x03) + .L8(0x01) + .L32(0x12345) + .L32(2); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); + let table = result.table(); + assert!(table.is_some()); + let table = table.unwrap(); + assert_eq!( + table.lookup(0, &bases), + Err(Error::VariableLengthSearchTable) + ); + } + + #[test] + fn test_eh_frame_hdr_indirect_length() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x0b) + .L8(0x83) + .L8(0x0b) + .L32(0x12345) + .L32(2); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding); + } + + #[test] + fn test_eh_frame_hdr_indirect_ptrs() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x8b) + .L8(0x03) + .L8(0x8b) + .L32(0x12345) + .L32(2) + .L32(10) + .L32(1) + .L32(20) + .L32(2); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345)); + let table = result.table(); + assert!(table.is_some()); + let table = table.unwrap(); + assert_eq!( + table.lookup(0, &bases), + Err(Error::UnsupportedPointerEncoding) + ); + } + + #[test] + fn test_eh_frame_hdr_good() { + let section = Section::with_endian(Endian::Little) + .L8(1) + .L8(0x0b) + .L8(0x03) + .L8(0x0b) + .L32(0x12345) + .L32(2) + .L32(10) + .L32(1) + .L32(20) + .L32(2); + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); + let table = result.table(); + assert!(table.is_some()); + let table = table.unwrap(); + assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1))); + assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1))); + assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1))); + assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1))); + assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1))); + assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2))); + assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2))); + assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2))); + } + + #[test] + fn test_eh_frame_fde_for_address_good() { + // First, setup eh_frame + // Write the CIE first so that its length gets set before we clone it + // into the FDE. + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + + let start_of_cie = Label::new(); + let end_of_cie = Label::new(); + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .append_repeated(0, 16) + .mark(&start_of_cie) + .cie(kind, None, &mut cie) + .mark(&end_of_cie); + + let mut fde1 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 9, + address_range: 4, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + let mut fde2 = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 20, + address_range: 8, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let start_of_fde1 = Label::new(); + let start_of_fde2 = Label::new(); + + let section = section + // +4 for the FDE length before the CIE offset. + .mark(&start_of_fde1) + .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1) + .mark(&start_of_fde2) + .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2); + + section.start().set_const(0); + let section = section.get_contents().unwrap(); + let eh_frame = kind.section(§ion); + + // Setup eh_frame_hdr + let section = Section::with_endian(kind.endian()) + .L8(1) + .L8(0x0b) + .L8(0x03) + .L8(0x0b) + .L32(0x12345) + .L32(2) + .L32(10) + .L32(0x12345 + start_of_fde1.value().unwrap() as u32) + .L32(20) + .L32(0x12345 + start_of_fde2.value().unwrap() as u32); + + let section = section.get_contents().unwrap(); + let bases = BaseAddresses::default(); + let eh_frame_hdr = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); + assert!(eh_frame_hdr.is_ok()); + let eh_frame_hdr = eh_frame_hdr.unwrap(); + + let table = eh_frame_hdr.table(); + assert!(table.is_some()); + let table = table.unwrap(); + + let bases = Default::default(); + let mut iter = table.iter(&bases); + assert_eq!( + iter.next(), + Ok(Some(( + Pointer::Direct(10), + Pointer::Direct(0x12345 + start_of_fde1.value().unwrap()) + ))) + ); + assert_eq!( + iter.next(), + Ok(Some(( + Pointer::Direct(20), + Pointer::Direct(0x12345 + start_of_fde2.value().unwrap()) + ))) + ); + assert_eq!(iter.next(), Ok(None)); + + assert_eq!( + table.iter(&bases).nth(0), + Ok(Some(( + Pointer::Direct(10), + Pointer::Direct(0x12345 + start_of_fde1.value().unwrap()) + ))) + ); + + assert_eq!( + table.iter(&bases).nth(1), + Ok(Some(( + Pointer::Direct(20), + Pointer::Direct(0x12345 + start_of_fde2.value().unwrap()) + ))) + ); + assert_eq!(table.iter(&bases).nth(2), Ok(None)); + + let f = |_: &_, _: &_, o: EhFrameOffset| { + assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); + Ok(cie.clone()) + }; + assert_eq!( + table.fde_for_address(&eh_frame, &bases, 9, f), + Ok(fde1.clone()) + ); + assert_eq!( + table.fde_for_address(&eh_frame, &bases, 10, f), + Ok(fde1.clone()) + ); + assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1)); + assert_eq!( + table.fde_for_address(&eh_frame, &bases, 19, f), + Err(Error::NoUnwindInfoForAddress) + ); + assert_eq!( + table.fde_for_address(&eh_frame, &bases, 20, f), + Ok(fde2.clone()) + ); + assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2)); + assert_eq!( + table.fde_for_address(&eh_frame, &bases, 100_000, f), + Err(Error::NoUnwindInfoForAddress) + ); + } + + #[test] + fn test_eh_frame_stops_at_zero_length() { + let mut cie = make_test_cie(); + let kind = eh_frame_le(); + let section = Section::with_endian(Endian::Little) + .L32(0) + .cie(kind, None, &mut cie) + .L32(0); + let contents = section.get_contents().unwrap(); + let eh_frame = kind.section(&contents); + let bases = Default::default(); + + let mut entries = eh_frame.entries(&bases); + assert_eq!(entries.next(), Ok(None)); + + assert_eq!( + eh_frame.cie_from_offset(&bases, EhFrameOffset(0)), + Err(Error::NoEntryAtGivenOffset) + ); + } + + #[test] + fn test_debug_frame_skips_zero_length() { + let mut cie = make_test_cie(); + let kind = debug_frame_le(); + let section = Section::with_endian(Endian::Little) + .L32(0) + .cie(kind, None, &mut cie) + .L32(0); + let contents = section.get_contents().unwrap(); + let debug_frame = kind.section(&contents); + let bases = Default::default(); + + let mut entries = debug_frame.entries(&bases); + assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie)))); + assert_eq!(entries.next(), Ok(None)); + + assert_eq!( + debug_frame.cie_from_offset(&bases, DebugFrameOffset(0)), + Err(Error::NoEntryAtGivenOffset) + ); + } + + fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result { + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf64, + cie: make_test_cie(), + initial_address: 0xfeed_beef, + address_range: 39, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .append_bytes(buf) + .fde(kind, cie_offset as u64, &mut fde) + .append_bytes(buf); + + let section = section.get_contents().unwrap(); + let eh_frame = kind.section(§ion); + let input = &mut EndianSlice::new(§ion[buf.len()..], LittleEndian); + + let bases = Default::default(); + match parse_cfi_entry(&bases, &eh_frame, input) { + Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0), + Err(e) => Err(e), + otherwise => panic!("Unexpected result: {:#?}", otherwise), + } + } + + #[test] + fn test_eh_frame_resolve_cie_offset_ok() { + let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let cie_offset = 2; + // + 4 for size of length field + assert_eq!( + resolve_cie_offset(&buf, buf.len() + 4 - cie_offset), + Ok(cie_offset) + ); + } + + #[test] + fn test_eh_frame_resolve_cie_offset_out_of_bounds() { + let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + assert_eq!( + resolve_cie_offset(&buf, buf.len() + 4 + 2), + Err(Error::OffsetOutOfBounds) + ); + } + + #[test] + fn test_eh_frame_resolve_cie_offset_underflow() { + let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + assert_eq!( + resolve_cie_offset(&buf, usize::MAX), + Err(Error::OffsetOutOfBounds) + ); + } + + #[test] + fn test_eh_frame_fde_ok() { + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + + let start_of_cie = Label::new(); + let end_of_cie = Label::new(); + + // Write the CIE first so that its length gets set before we clone it + // into the FDE. + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .append_repeated(0, 16) + .mark(&start_of_cie) + .cie(kind, None, &mut cie) + .mark(&end_of_cie); + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_beef, + address_range: 999, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let section = section + // +4 for the FDE length before the CIE offset. + .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde); + + section.start().set_const(0); + let section = section.get_contents().unwrap(); + let eh_frame = kind.section(§ion); + let section = EndianSlice::new(§ion, LittleEndian); + + let mut offset = None; + let result = parse_fde( + eh_frame, + &mut section.range_from(end_of_cie.value().unwrap() as usize..), + |_, _, o| { + offset = Some(o); + assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); + Ok(cie.clone()) + }, + ); + match result { + Ok(actual) => assert_eq!(actual, fde), + otherwise => panic!("Unexpected result {:?}", otherwise), + } + assert!(offset.is_some()); + } + + #[test] + fn test_eh_frame_fde_out_of_bounds() { + let mut cie = make_test_cie(); + cie.version = 1; + + let end_of_cie = Label::new(); + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf64, + cie: cie.clone(), + initial_address: 0xfeed_beef, + address_range: 999, + augmentation: None, + instructions: EndianSlice::new(&[], LittleEndian), + }; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .cie(kind, None, &mut cie) + .mark(&end_of_cie) + .fde(kind, 99_999_999_999_999, &mut fde); + + section.start().set_const(0); + let section = section.get_contents().unwrap(); + let eh_frame = kind.section(§ion); + let section = EndianSlice::new(§ion, LittleEndian); + + let result = parse_fde( + eh_frame, + &mut section.range_from(end_of_cie.value().unwrap() as usize..), + UnwindSection::cie_from_offset, + ); + assert_eq!(result, Err(Error::OffsetOutOfBounds)); + } + + #[test] + fn test_augmentation_parse_not_z_augmentation() { + let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian); + let bases = Default::default(); + let address_size = 8; + let section = EhFrame::new(&[], NativeEndian); + let input = &mut EndianSlice::new(&[], NativeEndian); + assert_eq!( + Augmentation::parse(augmentation, &bases, address_size, §ion, input), + Err(Error::UnknownAugmentation) + ); + } + + #[test] + fn test_augmentation_parse_just_signal_trampoline() { + let aug_str = &mut EndianSlice::new(b"S", LittleEndian); + let bases = Default::default(); + let address_size = 8; + let section = EhFrame::new(&[], LittleEndian); + let input = &mut EndianSlice::new(&[], LittleEndian); + + let augmentation = Augmentation { + is_signal_trampoline: true, + ..Default::default() + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + } + + #[test] + fn test_augmentation_parse_unknown_part_of_z_augmentation() { + // The 'Z' character is not defined by the z-style augmentation. + let bases = Default::default(); + let address_size = 8; + let section = Section::with_endian(Endian::Little) + .uleb(4) + .append_repeated(4, 4) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian); + assert_eq!( + Augmentation::parse(augmentation, &bases, address_size, §ion, input), + Err(Error::UnknownAugmentation) + ); + } + + #[test] + #[allow(non_snake_case)] + fn test_augmentation_parse_L() { + let bases = Default::default(); + let address_size = 8; + let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let section = Section::with_endian(Endian::Little) + .uleb(1) + .D8(constants::DW_EH_PE_uleb128.0) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let aug_str = &mut EndianSlice::new(b"zL", LittleEndian); + + let augmentation = Augmentation { + lsda: Some(constants::DW_EH_PE_uleb128), + ..Default::default() + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + #[allow(non_snake_case)] + fn test_augmentation_parse_P() { + let bases = Default::default(); + let address_size = 8; + let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let section = Section::with_endian(Endian::Little) + .uleb(9) + .D8(constants::DW_EH_PE_udata8.0) + .L64(0xf00d_f00d) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let aug_str = &mut EndianSlice::new(b"zP", LittleEndian); + + let augmentation = Augmentation { + personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))), + ..Default::default() + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + #[allow(non_snake_case)] + fn test_augmentation_parse_R() { + let bases = Default::default(); + let address_size = 8; + let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let section = Section::with_endian(Endian::Little) + .uleb(1) + .D8(constants::DW_EH_PE_udata4.0) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let aug_str = &mut EndianSlice::new(b"zR", LittleEndian); + + let augmentation = Augmentation { + fde_address_encoding: Some(constants::DW_EH_PE_udata4), + ..Default::default() + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + #[allow(non_snake_case)] + fn test_augmentation_parse_S() { + let bases = Default::default(); + let address_size = 8; + let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let section = Section::with_endian(Endian::Little) + .uleb(0) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let aug_str = &mut EndianSlice::new(b"zS", LittleEndian); + + let augmentation = Augmentation { + is_signal_trampoline: true, + ..Default::default() + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_augmentation_parse_all() { + let bases = Default::default(); + let address_size = 8; + let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let section = Section::with_endian(Endian::Little) + .uleb(1 + 9 + 1) + // L + .D8(constants::DW_EH_PE_uleb128.0) + // P + .D8(constants::DW_EH_PE_udata8.0) + .L64(0x1bad_f00d) + // R + .D8(constants::DW_EH_PE_uleb128.0) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + let input = &mut section.section().clone(); + let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian); + + let augmentation = Augmentation { + lsda: Some(constants::DW_EH_PE_uleb128), + personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))), + fde_address_encoding: Some(constants::DW_EH_PE_uleb128), + is_signal_trampoline: true, + }; + + assert_eq!( + Augmentation::parse(aug_str, &bases, address_size, §ion, input), + Ok(augmentation) + ); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_eh_frame_fde_no_augmentation() { + let instrs = [1, 2, 3, 4]; + let cie_offset = 1; + + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: None, + instructions: EndianSlice::new(&instrs, LittleEndian), + }; + + let rest = [1, 2, 3, 4]; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = kind.section(§ion); + let input = &mut section.section().clone(); + + let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); + assert_eq!(result, Ok(fde)); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_eh_frame_fde_empty_augmentation() { + let instrs = [1, 2, 3, 4]; + let cie_offset = 1; + + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + cie.augmentation = Some(Augmentation::default()); + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: Some(AugmentationData::default()), + instructions: EndianSlice::new(&instrs, LittleEndian), + }; + + let rest = [1, 2, 3, 4]; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = kind.section(§ion); + let input = &mut section.section().clone(); + + let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); + assert_eq!(result, Ok(fde)); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_eh_frame_fde_lsda_augmentation() { + let instrs = [1, 2, 3, 4]; + let cie_offset = 1; + + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + cie.augmentation = Some(Augmentation::default()); + cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr); + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: Some(AugmentationData { + lsda: Some(Pointer::Direct(0x1122_3344)), + }), + instructions: EndianSlice::new(&instrs, LittleEndian), + }; + + let rest = [1, 2, 3, 4]; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = kind.section(§ion); + let input = &mut section.section().clone(); + + let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); + assert_eq!(result, Ok(fde)); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_eh_frame_fde_lsda_function_relative() { + let instrs = [1, 2, 3, 4]; + let cie_offset = 1; + + let mut cie = make_test_cie(); + cie.format = Format::Dwarf32; + cie.version = 1; + cie.augmentation = Some(Augmentation::default()); + cie.augmentation.as_mut().unwrap().lsda = + Some(constants::DW_EH_PE_funcrel | constants::DW_EH_PE_absptr); + + let mut fde = FrameDescriptionEntry { + offset: 0, + length: 0, + format: Format::Dwarf32, + cie: cie.clone(), + initial_address: 0xfeed_face, + address_range: 9000, + augmentation: Some(AugmentationData { + lsda: Some(Pointer::Direct(0xbeef)), + }), + instructions: EndianSlice::new(&instrs, LittleEndian), + }; + + let rest = [1, 2, 3, 4]; + + let kind = eh_frame_le(); + let section = Section::with_endian(kind.endian()) + .append_repeated(10, 10) + .fde(kind, cie_offset, &mut fde) + .append_bytes(&rest) + .get_contents() + .unwrap(); + let section = kind.section(§ion); + let input = &mut section.section().range_from(10..); + + // Adjust the FDE's augmentation to be relative to the function. + fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef)); + + let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); + assert_eq!(result, Ok(fde)); + assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); + } + + #[test] + fn test_eh_frame_cie_personality_function_relative_bad_context() { + let instrs = [1, 2, 3, 4]; + + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let aug_len = Label::new(); + let aug_start = Label::new(); + let aug_end = Label::new(); + + let section = Section::with_endian(Endian::Little) + // Length + .L32(&length) + .mark(&start) + // CIE ID + .L32(0) + // Version + .D8(1) + // Augmentation + .append_bytes(b"zP\0") + // Code alignment factor + .uleb(1) + // Data alignment factor + .sleb(1) + // Return address register + .uleb(1) + // Augmentation data length. This is a uleb, be we rely on the value + // being less than 2^7 and therefore a valid uleb (can't use Label + // with uleb). + .D8(&aug_len) + .mark(&aug_start) + // Augmentation data. Personality encoding and then encoded pointer. + .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0) + .uleb(1) + .mark(&aug_end) + // Initial instructions + .append_bytes(&instrs) + .mark(&end); + + length.set_const((&end - &start) as u64); + aug_len.set_const((&aug_end - &aug_start) as u64); + + let section = section.get_contents().unwrap(); + let section = EhFrame::new(§ion, LittleEndian); + + let bases = BaseAddresses::default(); + let mut iter = section.entries(&bases); + assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext)); + } + + #[test] + fn register_rule_map_eq() { + // Different order, but still equal. + let map1: RegisterRuleMap = [ + (Register(0), RegisterRule::SameValue), + (Register(3), RegisterRule::Offset(1)), + ] + .iter() + .collect(); + let map2: RegisterRuleMap = [ + (Register(3), RegisterRule::Offset(1)), + (Register(0), RegisterRule::SameValue), + ] + .iter() + .collect(); + assert_eq!(map1, map2); + assert_eq!(map2, map1); + + // Not equal. + let map3: RegisterRuleMap = [ + (Register(0), RegisterRule::SameValue), + (Register(2), RegisterRule::Offset(1)), + ] + .iter() + .collect(); + let map4: RegisterRuleMap = [ + (Register(3), RegisterRule::Offset(1)), + (Register(0), RegisterRule::SameValue), + ] + .iter() + .collect(); + assert!(map3 != map4); + assert!(map4 != map3); + + // One has undefined explicitly set, other implicitly has undefined. + let mut map5 = RegisterRuleMap::::default(); + map5.set(Register(0), RegisterRule::SameValue).unwrap(); + map5.set(Register(0), RegisterRule::Undefined).unwrap(); + let map6 = RegisterRuleMap::::default(); + assert_eq!(map5, map6); + assert_eq!(map6, map5); + } + + #[test] + fn iter_register_rules() { + let row = UnwindTableRow:: { + registers: [ + (Register(0), RegisterRule::SameValue), + (Register(1), RegisterRule::Offset(1)), + (Register(2), RegisterRule::ValOffset(2)), + ] + .iter() + .collect(), + ..Default::default() + }; + + let mut found0 = false; + let mut found1 = false; + let mut found2 = false; + + for &(register, ref rule) in row.registers() { + match register.0 { + 0 => { + assert!(!found0); + found0 = true; + assert_eq!(*rule, RegisterRule::SameValue); + } + 1 => { + assert!(!found1); + found1 = true; + assert_eq!(*rule, RegisterRule::Offset(1)); + } + 2 => { + assert!(!found2); + found2 = true; + assert_eq!(*rule, RegisterRule::ValOffset(2)); + } + x => panic!("Unexpected register rule: ({}, {:?})", x, rule), + } + } + + assert!(found0); + assert!(found1); + assert!(found2); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn size_of_unwind_ctx() { + use core::mem; + let size = mem::size_of::>(); + let max_size = 30968; + if size > max_size { + assert_eq!(size, max_size); + } + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn size_of_register_rule_map() { + use core::mem; + let size = mem::size_of::>(); + let max_size = 6152; + if size > max_size { + assert_eq!(size, max_size); + } + } + + #[test] + fn test_parse_pointer_encoding_ok() { + use crate::endianity::NativeEndian; + let expected = constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_pcrel; + let input = [expected.0, 1, 2, 3, 4]; + let input = &mut EndianSlice::new(&input, NativeEndian); + assert_eq!(parse_pointer_encoding(input), Ok(expected)); + assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian)); + } + + #[test] + fn test_parse_pointer_encoding_bad_encoding() { + use crate::endianity::NativeEndian; + let expected = + constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0); + let input = [expected.0, 1, 2, 3, 4]; + let input = &mut EndianSlice::new(&input, NativeEndian); + assert_eq!( + Err(Error::UnknownPointerEncoding(expected)), + parse_pointer_encoding(input) + ); + } + + #[test] + fn test_parse_encoded_pointer_absptr() { + let encoding = constants::DW_EH_PE_absptr; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L32(0xf00d_f00d) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0xf00d_f00d)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_pcrel() { + let encoding = constants::DW_EH_PE_pcrel; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .append_repeated(0, 0x10) + .L32(0x1) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input.range_from(0x10..); + + let parameters = PointerEncodingParameters { + bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame, + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x111)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_pcrel_undefined() { + let encoding = constants::DW_EH_PE_pcrel; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::PcRelativePointerButSectionBaseIsUndefined) + ); + } + + #[test] + fn test_parse_encoded_pointer_textrel() { + let encoding = constants::DW_EH_PE_textrel; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L32(0x1) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &BaseAddresses::default().set_text(0x10).eh_frame, + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x11)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_textrel_undefined() { + let encoding = constants::DW_EH_PE_textrel; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::TextRelativePointerButTextBaseIsUndefined) + ); + } + + #[test] + fn test_parse_encoded_pointer_datarel() { + let encoding = constants::DW_EH_PE_datarel; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L32(0x1) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &BaseAddresses::default().set_got(0x10).eh_frame, + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x11)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_datarel_undefined() { + let encoding = constants::DW_EH_PE_datarel; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::DataRelativePointerButDataBaseIsUndefined) + ); + } + + #[test] + fn test_parse_encoded_pointer_funcrel() { + let encoding = constants::DW_EH_PE_funcrel; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L32(0x1) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: Some(0x10), + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x11)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_funcrel_undefined() { + let encoding = constants::DW_EH_PE_funcrel; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::FuncRelativePointerInBadContext) + ); + } + + #[test] + fn test_parse_encoded_pointer_uleb128() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_uleb128; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .uleb(0x12_3456) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x12_3456)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_udata2() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata2; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L16(0x1234) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x1234)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_udata4() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata4; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L32(0x1234_5678) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x1234_5678)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_udata8() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata8; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .L64(0x1234_5678_1234_5678) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 8, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x1234_5678_1234_5678)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_sleb128() { + let encoding = constants::DW_EH_PE_textrel | constants::DW_EH_PE_sleb128; + let expected_rest = [1, 2, 3, 4]; + + let input = Section::with_endian(Endian::Little) + .sleb(-0x1111) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame, + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(0x1111_0000)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_sdata2() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata2; + let expected_rest = [1, 2, 3, 4]; + let expected = 0x111_i16; + + let input = Section::with_endian(Endian::Little) + .L16(expected as u16) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(expected as u64)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_sdata4() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata4; + let expected_rest = [1, 2, 3, 4]; + let expected = 0x111_1111_i32; + + let input = Section::with_endian(Endian::Little) + .L32(expected as u32) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(expected as u64)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_sdata8() { + let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata8; + let expected_rest = [1, 2, 3, 4]; + let expected = -0x11_1111_1222_2222_i64; + + let input = Section::with_endian(Endian::Little) + .L64(expected as u64) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 8, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Direct(expected as u64)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_encoded_pointer_omit() { + let encoding = constants::DW_EH_PE_omit; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::CannotParseOmitPointerEncoding) + ); + assert_eq!(rest, input); + } + + #[test] + fn test_parse_encoded_pointer_bad_encoding() { + let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1); + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::UnknownPointerEncoding(encoding)) + ); + } + + #[test] + fn test_parse_encoded_pointer_aligned() { + // FIXME: support this encoding! + + let encoding = constants::DW_EH_PE_aligned; + + let input = Section::with_endian(Endian::Little).L32(0x1); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Err(Error::UnsupportedPointerEncoding) + ); + } + + #[test] + fn test_parse_encoded_pointer_indirect() { + let expected_rest = [1, 2, 3, 4]; + let encoding = constants::DW_EH_PE_indirect; + + let input = Section::with_endian(Endian::Little) + .L32(0x1234_5678) + .append_bytes(&expected_rest); + let input = input.get_contents().unwrap(); + let input = EndianSlice::new(&input, LittleEndian); + let mut rest = input; + + let parameters = PointerEncodingParameters { + bases: &SectionBaseAddresses::default(), + func_base: None, + address_size: 4, + section: &input, + }; + assert_eq!( + parse_encoded_pointer(encoding, ¶meters, &mut rest), + Ok(Pointer::Indirect(0x1234_5678)) + ); + assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_unwind_context_reuse() { + fn unwind_one(ctx: &mut UnwindContext, data: &[u8]) { + let debug_frame = DebugFrame::new(data, NativeEndian); + let bases = Default::default(); + let result = debug_frame.unwind_info_for_address( + &bases, + ctx, + 0xbadb_ad99, + DebugFrame::cie_from_offset, + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress); + } + + // Use the same context for two different data lifetimes. + let mut ctx: UnwindContext = UnwindContext::new(); + { + let data1 = vec![]; + unwind_one(&mut ctx, &data1); + } + { + let data2 = vec![]; + unwind_one(&mut ctx, &data2); + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/dwarf.rs b/deps/crates/vendor/gimli/src/read/dwarf.rs new file mode 100644 index 00000000000000..c836d8457b57f2 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/dwarf.rs @@ -0,0 +1,1681 @@ +use alloc::string::String; +use alloc::sync::Arc; + +use crate::common::{ + DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase, + DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, + DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwarfFileType, DwoId, Encoding, + LocationListsOffset, RangeListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset, +}; +use crate::constants; +use crate::read::{ + Abbreviations, AbbreviationsCache, AbbreviationsCacheStrategy, AttributeValue, DebugAbbrev, + DebugAddr, DebugAranges, DebugCuIndex, DebugInfo, DebugInfoUnitHeadersIter, DebugLine, + DebugLineStr, DebugLoc, DebugLocLists, DebugRanges, DebugRngLists, DebugStr, DebugStrOffsets, + DebugTuIndex, DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, + EntriesRaw, EntriesTree, Error, IncompleteLineProgram, IndexSectionId, LocListIter, + LocationLists, Range, RangeLists, RawLocListIter, RawRngListIter, Reader, ReaderOffset, + ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, + UnitOffset, UnitType, +}; + +/// All of the commonly used DWARF sections. +/// +/// This is useful for storing sections when `T` does not implement `Reader`. +/// It can be used to create a `Dwarf` that references the data in `self`. +/// If `T` does implement `Reader`, then use `Dwarf` directly. +/// +/// ## Example Usage +/// +/// It can be useful to load DWARF sections into owned data structures, +/// such as `Vec`. However, we do not implement the `Reader` trait +/// for `Vec`, because it would be very inefficient, but this trait +/// is required for all of the methods that parse the DWARF data. +/// So we first load the DWARF sections into `Vec`s, and then use +/// `borrow` to create `Reader`s that reference the data. +/// +/// ```rust,no_run +/// # fn example() -> Result<(), gimli::Error> { +/// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; +/// // Read the DWARF sections into `Vec`s with whatever object loader you're using. +/// let dwarf_sections: gimli::DwarfSections> = gimli::DwarfSections::load(loader)?; +/// // Create references to the DWARF sections. +/// let dwarf: gimli::Dwarf<_> = dwarf_sections.borrow(|section| { +/// gimli::EndianSlice::new(§ion, gimli::LittleEndian) +/// }); +/// # unreachable!() +/// # } +/// ``` +#[derive(Debug, Default)] +pub struct DwarfSections { + /// The `.debug_abbrev` section. + pub debug_abbrev: DebugAbbrev, + /// The `.debug_addr` section. + pub debug_addr: DebugAddr, + /// The `.debug_aranges` section. + pub debug_aranges: DebugAranges, + /// The `.debug_info` section. + pub debug_info: DebugInfo, + /// The `.debug_line` section. + pub debug_line: DebugLine, + /// The `.debug_line_str` section. + pub debug_line_str: DebugLineStr, + /// The `.debug_str` section. + pub debug_str: DebugStr, + /// The `.debug_str_offsets` section. + pub debug_str_offsets: DebugStrOffsets, + /// The `.debug_types` section. + pub debug_types: DebugTypes, + /// The `.debug_loc` section. + pub debug_loc: DebugLoc, + /// The `.debug_loclists` section. + pub debug_loclists: DebugLocLists, + /// The `.debug_ranges` section. + pub debug_ranges: DebugRanges, + /// The `.debug_rnglists` section. + pub debug_rnglists: DebugRngLists, +} + +impl DwarfSections { + /// Try to load the DWARF sections using the given loader function. + /// + /// `section` loads a DWARF section from the object file. + /// It should return an empty section if the section does not exist. + pub fn load(mut section: F) -> core::result::Result + where + F: FnMut(SectionId) -> core::result::Result, + { + Ok(DwarfSections { + // Section types are inferred. + debug_abbrev: Section::load(&mut section)?, + debug_addr: Section::load(&mut section)?, + debug_aranges: Section::load(&mut section)?, + debug_info: Section::load(&mut section)?, + debug_line: Section::load(&mut section)?, + debug_line_str: Section::load(&mut section)?, + debug_str: Section::load(&mut section)?, + debug_str_offsets: Section::load(&mut section)?, + debug_types: Section::load(&mut section)?, + debug_loc: Section::load(&mut section)?, + debug_loclists: Section::load(&mut section)?, + debug_ranges: Section::load(&mut section)?, + debug_rnglists: Section::load(&mut section)?, + }) + } + + /// Create a `Dwarf` structure that references the data in `self`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf + where + F: FnMut(&'a T) -> R, + { + Dwarf::from_sections(DwarfSections { + debug_abbrev: self.debug_abbrev.borrow(&mut borrow), + debug_addr: self.debug_addr.borrow(&mut borrow), + debug_aranges: self.debug_aranges.borrow(&mut borrow), + debug_info: self.debug_info.borrow(&mut borrow), + debug_line: self.debug_line.borrow(&mut borrow), + debug_line_str: self.debug_line_str.borrow(&mut borrow), + debug_str: self.debug_str.borrow(&mut borrow), + debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), + debug_types: self.debug_types.borrow(&mut borrow), + debug_loc: self.debug_loc.borrow(&mut borrow), + debug_loclists: self.debug_loclists.borrow(&mut borrow), + debug_ranges: self.debug_ranges.borrow(&mut borrow), + debug_rnglists: self.debug_rnglists.borrow(&mut borrow), + }) + } + + /// Create a `Dwarf` structure that references the data in `self` and `sup`. + /// + /// This is like `borrow`, but also includes the supplementary object file. + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// ## Example Usage + /// + /// ```rust,no_run + /// # fn example() -> Result<(), gimli::Error> { + /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; + /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; + /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. + /// let dwarf_sections: gimli::DwarfSections> = gimli::DwarfSections::load(loader)?; + /// let dwarf_sup_sections: gimli::DwarfSections> = gimli::DwarfSections::load(sup_loader)?; + /// // Create references to the DWARF sections. + /// let dwarf = dwarf_sections.borrow_with_sup(&dwarf_sup_sections, |section| { + /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) + /// }); + /// # unreachable!() + /// # } + /// ``` + pub fn borrow_with_sup<'a, F, R>(&'a self, sup: &'a Self, mut borrow: F) -> Dwarf + where + F: FnMut(&'a T) -> R, + { + let mut dwarf = self.borrow(&mut borrow); + dwarf.set_sup(sup.borrow(&mut borrow)); + dwarf + } +} + +/// All of the commonly used DWARF sections, and other common information. +#[derive(Debug, Default)] +pub struct Dwarf { + /// The `.debug_abbrev` section. + pub debug_abbrev: DebugAbbrev, + + /// The `.debug_addr` section. + pub debug_addr: DebugAddr, + + /// The `.debug_aranges` section. + pub debug_aranges: DebugAranges, + + /// The `.debug_info` section. + pub debug_info: DebugInfo, + + /// The `.debug_line` section. + pub debug_line: DebugLine, + + /// The `.debug_line_str` section. + pub debug_line_str: DebugLineStr, + + /// The `.debug_str` section. + pub debug_str: DebugStr, + + /// The `.debug_str_offsets` section. + pub debug_str_offsets: DebugStrOffsets, + + /// The `.debug_types` section. + pub debug_types: DebugTypes, + + /// The location lists in the `.debug_loc` and `.debug_loclists` sections. + pub locations: LocationLists, + + /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections. + pub ranges: RangeLists, + + /// The type of this file. + pub file_type: DwarfFileType, + + /// The DWARF sections for a supplementary object file. + pub sup: Option>>, + + /// A cache of previously parsed abbreviations for units in this file. + pub abbreviations_cache: AbbreviationsCache, +} + +impl Dwarf { + /// Try to load the DWARF sections using the given loader function. + /// + /// `section` loads a DWARF section from the object file. + /// It should return an empty section if the section does not exist. + /// + /// After loading, the user should set the `file_type` field and + /// call `load_sup` if required. + pub fn load(section: F) -> core::result::Result + where + F: FnMut(SectionId) -> core::result::Result, + { + let sections = DwarfSections::load(section)?; + Ok(Self::from_sections(sections)) + } + + /// Load the DWARF sections from the supplementary object file. + /// + /// `section` operates the same as for `load`. + /// + /// Sets `self.sup`, replacing any previous value. + pub fn load_sup(&mut self, section: F) -> core::result::Result<(), E> + where + F: FnMut(SectionId) -> core::result::Result, + { + self.set_sup(Self::load(section)?); + Ok(()) + } + + /// Create a `Dwarf` structure from the given sections. + /// + /// The caller should set the `file_type` and `sup` fields if required. + fn from_sections(sections: DwarfSections) -> Self { + Dwarf { + debug_abbrev: sections.debug_abbrev, + debug_addr: sections.debug_addr, + debug_aranges: sections.debug_aranges, + debug_info: sections.debug_info, + debug_line: sections.debug_line, + debug_line_str: sections.debug_line_str, + debug_str: sections.debug_str, + debug_str_offsets: sections.debug_str_offsets, + debug_types: sections.debug_types, + locations: LocationLists::new(sections.debug_loc, sections.debug_loclists), + ranges: RangeLists::new(sections.debug_ranges, sections.debug_rnglists), + file_type: DwarfFileType::Main, + sup: None, + abbreviations_cache: AbbreviationsCache::new(), + } + } + + /// Create a `Dwarf` structure that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// ## Example Usage + /// + /// It can be useful to load DWARF sections into owned data structures, + /// such as `Vec`. However, we do not implement the `Reader` trait + /// for `Vec`, because it would be very inefficient, but this trait + /// is required for all of the methods that parse the DWARF data. + /// So we first load the DWARF sections into `Vec`s, and then use + /// `borrow` to create `Reader`s that reference the data. + /// + /// ```rust,no_run + /// # fn example() -> Result<(), gimli::Error> { + /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; + /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; + /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. + /// let mut owned_dwarf: gimli::Dwarf> = gimli::Dwarf::load(loader)?; + /// owned_dwarf.load_sup(sup_loader)?; + /// // Create references to the DWARF sections. + /// let dwarf = owned_dwarf.borrow(|section| { + /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) + /// }); + /// # unreachable!() + /// # } + /// ``` + #[deprecated(note = "use `DwarfSections::borrow` instead")] + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf + where + F: FnMut(&'a T) -> R, + { + Dwarf { + debug_abbrev: self.debug_abbrev.borrow(&mut borrow), + debug_addr: self.debug_addr.borrow(&mut borrow), + debug_aranges: self.debug_aranges.borrow(&mut borrow), + debug_info: self.debug_info.borrow(&mut borrow), + debug_line: self.debug_line.borrow(&mut borrow), + debug_line_str: self.debug_line_str.borrow(&mut borrow), + debug_str: self.debug_str.borrow(&mut borrow), + debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), + debug_types: self.debug_types.borrow(&mut borrow), + locations: self.locations.borrow(&mut borrow), + ranges: self.ranges.borrow(&mut borrow), + file_type: self.file_type, + sup: self.sup().map(|sup| Arc::new(sup.borrow(borrow))), + abbreviations_cache: AbbreviationsCache::new(), + } + } + + /// Store the DWARF sections for the supplementary object file. + pub fn set_sup(&mut self, sup: Dwarf) { + self.sup = Some(Arc::new(sup)); + } + + /// Return a reference to the DWARF sections for the supplementary object file. + pub fn sup(&self) -> Option<&Dwarf> { + self.sup.as_ref().map(Arc::as_ref) + } +} + +impl Dwarf { + /// Parse abbreviations and store them in the cache. + /// + /// This will iterate over the units in `self.debug_info` to determine the + /// abbreviations offsets. + /// + /// Errors during parsing abbreviations are also stored in the cache. + /// Errors during iterating over the units are ignored. + pub fn populate_abbreviations_cache(&mut self, strategy: AbbreviationsCacheStrategy) { + self.abbreviations_cache + .populate(strategy, &self.debug_abbrev, self.debug_info.units()); + } + + /// Iterate the unit headers in the `.debug_info` section. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + #[inline] + pub fn units(&self) -> DebugInfoUnitHeadersIter { + self.debug_info.units() + } + + /// Construct a new `Unit` from the given unit header. + #[inline] + pub fn unit(&self, header: UnitHeader) -> Result> { + Unit::new(self, header) + } + + /// Iterate the type-unit headers in the `.debug_types` section. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + #[inline] + pub fn type_units(&self) -> DebugTypesUnitHeadersIter { + self.debug_types.units() + } + + /// Parse the abbreviations for a compilation unit. + #[inline] + pub fn abbreviations(&self, unit: &UnitHeader) -> Result> { + self.abbreviations_cache + .get(&self.debug_abbrev, unit.debug_abbrev_offset()) + } + + /// Return the string offset at the given index. + #[inline] + pub fn string_offset( + &self, + unit: &Unit, + index: DebugStrOffsetsIndex, + ) -> Result> { + self.debug_str_offsets + .get_str_offset(unit.header.format(), unit.str_offsets_base, index) + } + + /// Return the string at the given offset in `.debug_str`. + #[inline] + pub fn string(&self, offset: DebugStrOffset) -> Result { + self.debug_str.get_str(offset) + } + + /// Return the string at the given offset in `.debug_line_str`. + #[inline] + pub fn line_string(&self, offset: DebugLineStrOffset) -> Result { + self.debug_line_str.get_str(offset) + } + + /// Return the string at the given offset in the `.debug_str` + /// in the supplementary object file. + #[inline] + pub fn sup_string(&self, offset: DebugStrOffset) -> Result { + if let Some(sup) = self.sup() { + sup.debug_str.get_str(offset) + } else { + Err(Error::ExpectedStringAttributeValue) + } + } + + /// Return an attribute value as a string slice. + /// + /// If the attribute value is one of: + /// + /// - an inline `DW_FORM_string` string + /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section + /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary + /// object file + /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str` + /// section + /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit + /// + /// then return the attribute's string value. Returns an error if the attribute + /// value does not have a string form, or if a string form has an invalid value. + pub fn attr_string(&self, unit: &Unit, attr: AttributeValue) -> Result { + match attr { + AttributeValue::String(string) => Ok(string), + AttributeValue::DebugStrRef(offset) => self.string(offset), + AttributeValue::DebugStrRefSup(offset) => self.sup_string(offset), + AttributeValue::DebugLineStrRef(offset) => self.line_string(offset), + AttributeValue::DebugStrOffsetsIndex(index) => { + let offset = self.string_offset(unit, index)?; + self.string(offset) + } + _ => Err(Error::ExpectedStringAttributeValue), + } + } + + /// Return the address at the given index. + pub fn address(&self, unit: &Unit, index: DebugAddrIndex) -> Result { + self.debug_addr + .get_address(unit.encoding().address_size, unit.addr_base, index) + } + + /// Try to return an attribute value as an address. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_addr` + /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit + /// + /// then return the address. + /// Returns `None` for other forms. + pub fn attr_address(&self, unit: &Unit, attr: AttributeValue) -> Result> { + match attr { + AttributeValue::Addr(addr) => Ok(Some(addr)), + AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some), + _ => Ok(None), + } + } + + /// Return the range list offset for the given raw offset. + /// + /// This handles adding `DW_AT_GNU_ranges_base` if required. + pub fn ranges_offset_from_raw( + &self, + unit: &Unit, + offset: RawRangeListsOffset, + ) -> RangeListsOffset { + if self.file_type == DwarfFileType::Dwo && unit.header.version() < 5 { + RangeListsOffset(offset.0.wrapping_add(unit.rnglists_base.0)) + } else { + RangeListsOffset(offset.0) + } + } + + /// Return the range list offset at the given index. + pub fn ranges_offset( + &self, + unit: &Unit, + index: DebugRngListsIndex, + ) -> Result> { + self.ranges + .get_offset(unit.encoding(), unit.rnglists_base, index) + } + + /// Iterate over the `RangeListEntry`s starting at the given offset. + pub fn ranges( + &self, + unit: &Unit, + offset: RangeListsOffset, + ) -> Result> { + self.ranges.ranges( + offset, + unit.encoding(), + unit.low_pc, + &self.debug_addr, + unit.addr_base, + ) + } + + /// Iterate over the `RawRngListEntry`ies starting at the given offset. + pub fn raw_ranges( + &self, + unit: &Unit, + offset: RangeListsOffset, + ) -> Result> { + self.ranges.raw_ranges(offset, unit.encoding()) + } + + /// Try to return an attribute value as a range list offset. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections + /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit + /// + /// then return the range list offset of the range list. + /// Returns `None` for other forms. + pub fn attr_ranges_offset( + &self, + unit: &Unit, + attr: AttributeValue, + ) -> Result>> { + match attr { + AttributeValue::RangeListsRef(offset) => { + Ok(Some(self.ranges_offset_from_raw(unit, offset))) + } + AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some), + _ => Ok(None), + } + } + + /// Try to return an attribute value as a range list entry iterator. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections + /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit + /// + /// then return an iterator over the entries in the range list. + /// Returns `None` for other forms. + pub fn attr_ranges( + &self, + unit: &Unit, + attr: AttributeValue, + ) -> Result>> { + match self.attr_ranges_offset(unit, attr)? { + Some(offset) => Ok(Some(self.ranges(unit, offset)?)), + None => Ok(None), + } + } + + /// Return an iterator for the address ranges of a `DebuggingInformationEntry`. + /// + /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`. + pub fn die_ranges( + &self, + unit: &Unit, + entry: &DebuggingInformationEntry<'_, '_, R>, + ) -> Result> { + let mut low_pc = None; + let mut high_pc = None; + let mut size = None; + let mut attrs = entry.attrs(); + while let Some(attr) = attrs.next()? { + match attr.name() { + constants::DW_AT_low_pc => { + low_pc = Some( + self.attr_address(unit, attr.value())? + .ok_or(Error::UnsupportedAttributeForm)?, + ); + } + constants::DW_AT_high_pc => match attr.value() { + AttributeValue::Udata(val) => size = Some(val), + attr => { + high_pc = Some( + self.attr_address(unit, attr)? + .ok_or(Error::UnsupportedAttributeForm)?, + ); + } + }, + constants::DW_AT_ranges => { + if let Some(list) = self.attr_ranges(unit, attr.value())? { + return Ok(RangeIter(RangeIterInner::List(list))); + } + } + _ => {} + } + } + let range = low_pc.and_then(|begin| { + let end = size.map(|size| begin + size).or(high_pc); + // TODO: perhaps return an error if `end` is `None` + end.map(|end| Range { begin, end }) + }); + Ok(RangeIter(RangeIterInner::Single(range))) + } + + /// Return an iterator for the address ranges of a `Unit`. + /// + /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the + /// root `DebuggingInformationEntry`. + pub fn unit_ranges(&self, unit: &Unit) -> Result> { + let mut cursor = unit.header.entries(&unit.abbreviations); + cursor.next_dfs()?; + let root = cursor.current().ok_or(Error::MissingUnitDie)?; + self.die_ranges(unit, root) + } + + /// Return the location list offset at the given index. + pub fn locations_offset( + &self, + unit: &Unit, + index: DebugLocListsIndex, + ) -> Result> { + self.locations + .get_offset(unit.encoding(), unit.loclists_base, index) + } + + /// Iterate over the `LocationListEntry`s starting at the given offset. + pub fn locations( + &self, + unit: &Unit, + offset: LocationListsOffset, + ) -> Result> { + match self.file_type { + DwarfFileType::Main => self.locations.locations( + offset, + unit.encoding(), + unit.low_pc, + &self.debug_addr, + unit.addr_base, + ), + DwarfFileType::Dwo => self.locations.locations_dwo( + offset, + unit.encoding(), + unit.low_pc, + &self.debug_addr, + unit.addr_base, + ), + } + } + + /// Iterate over the raw `LocationListEntry`s starting at the given offset. + pub fn raw_locations( + &self, + unit: &Unit, + offset: LocationListsOffset, + ) -> Result> { + match self.file_type { + DwarfFileType::Main => self.locations.raw_locations(offset, unit.encoding()), + DwarfFileType::Dwo => self.locations.raw_locations_dwo(offset, unit.encoding()), + } + } + + /// Try to return an attribute value as a location list offset. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections + /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit + /// + /// then return the location list offset of the location list. + /// Returns `None` for other forms. + pub fn attr_locations_offset( + &self, + unit: &Unit, + attr: AttributeValue, + ) -> Result>> { + match attr { + AttributeValue::LocationListsRef(offset) => Ok(Some(offset)), + AttributeValue::DebugLocListsIndex(index) => { + self.locations_offset(unit, index).map(Some) + } + _ => Ok(None), + } + } + + /// Try to return an attribute value as a location list entry iterator. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections + /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit + /// + /// then return an iterator over the entries in the location list. + /// Returns `None` for other forms. + pub fn attr_locations( + &self, + unit: &Unit, + attr: AttributeValue, + ) -> Result>> { + match self.attr_locations_offset(unit, attr)? { + Some(offset) => Ok(Some(self.locations(unit, offset)?)), + None => Ok(None), + } + } + + /// Call `Reader::lookup_offset_id` for each section, and return the first match. + /// + /// The first element of the tuple is `true` for supplementary sections. + pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> { + None.or_else(|| self.debug_abbrev.lookup_offset_id(id)) + .or_else(|| self.debug_addr.lookup_offset_id(id)) + .or_else(|| self.debug_aranges.lookup_offset_id(id)) + .or_else(|| self.debug_info.lookup_offset_id(id)) + .or_else(|| self.debug_line.lookup_offset_id(id)) + .or_else(|| self.debug_line_str.lookup_offset_id(id)) + .or_else(|| self.debug_str.lookup_offset_id(id)) + .or_else(|| self.debug_str_offsets.lookup_offset_id(id)) + .or_else(|| self.debug_types.lookup_offset_id(id)) + .or_else(|| self.locations.lookup_offset_id(id)) + .or_else(|| self.ranges.lookup_offset_id(id)) + .map(|(id, offset)| (false, id, offset)) + .or_else(|| { + self.sup() + .and_then(|sup| sup.lookup_offset_id(id)) + .map(|(_, id, offset)| (true, id, offset)) + }) + } + + /// Returns a string representation of the given error. + /// + /// This uses information from the DWARF sections to provide more information in some cases. + pub fn format_error(&self, err: Error) -> String { + #[allow(clippy::single_match)] + match err { + Error::UnexpectedEof(id) => match self.lookup_offset_id(id) { + Some((sup, section, offset)) => { + return format!( + "{} at {}{}+0x{:x}", + err, + section.name(), + if sup { "(sup)" } else { "" }, + offset.into_u64(), + ); + } + None => {} + }, + _ => {} + } + err.description().into() + } +} + +impl Dwarf { + /// Assuming `self` was loaded from a .dwo, take the appropriate + /// sections from `parent` (which contains the skeleton unit for this + /// dwo) such as `.debug_addr` and merge them into this `Dwarf`. + pub fn make_dwo(&mut self, parent: &Dwarf) { + self.file_type = DwarfFileType::Dwo; + // These sections are always taken from the parent file and not the dwo. + self.debug_addr = parent.debug_addr.clone(); + // .debug_rnglists comes from the DWO, .debug_ranges comes from the + // parent file. + self.ranges + .set_debug_ranges(parent.ranges.debug_ranges().clone()); + self.sup.clone_from(&parent.sup); + } +} + +/// The sections from a `.dwp` file. +/// +/// This is useful for storing sections when `T` does not implement `Reader`. +/// It can be used to create a `DwarfPackage` that references the data in `self`. +/// If `T` does implement `Reader`, then use `DwarfPackage` directly. +/// +/// ## Example Usage +/// +/// It can be useful to load DWARF sections into owned data structures, +/// such as `Vec`. However, we do not implement the `Reader` trait +/// for `Vec`, because it would be very inefficient, but this trait +/// is required for all of the methods that parse the DWARF data. +/// So we first load the DWARF sections into `Vec`s, and then use +/// `borrow` to create `Reader`s that reference the data. +/// +/// ```rust,no_run +/// # fn example() -> Result<(), gimli::Error> { +/// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; +/// // Read the DWARF sections into `Vec`s with whatever object loader you're using. +/// let dwp_sections: gimli::DwarfPackageSections> = gimli::DwarfPackageSections::load(loader)?; +/// // Create references to the DWARF sections. +/// let dwp: gimli::DwarfPackage<_> = dwp_sections.borrow( +/// |section| gimli::EndianSlice::new(§ion, gimli::LittleEndian), +/// gimli::EndianSlice::new(&[], gimli::LittleEndian), +/// )?; +/// # unreachable!() +/// # } +/// ``` +#[derive(Debug, Default)] +pub struct DwarfPackageSections { + /// The `.debug_cu_index` section. + pub cu_index: DebugCuIndex, + /// The `.debug_tu_index` section. + pub tu_index: DebugTuIndex, + /// The `.debug_abbrev.dwo` section. + pub debug_abbrev: DebugAbbrev, + /// The `.debug_info.dwo` section. + pub debug_info: DebugInfo, + /// The `.debug_line.dwo` section. + pub debug_line: DebugLine, + /// The `.debug_str.dwo` section. + pub debug_str: DebugStr, + /// The `.debug_str_offsets.dwo` section. + pub debug_str_offsets: DebugStrOffsets, + /// The `.debug_loc.dwo` section. + /// + /// Only present when using GNU split-dwarf extension to DWARF 4. + pub debug_loc: DebugLoc, + /// The `.debug_loclists.dwo` section. + pub debug_loclists: DebugLocLists, + /// The `.debug_rnglists.dwo` section. + pub debug_rnglists: DebugRngLists, + /// The `.debug_types.dwo` section. + /// + /// Only present when using GNU split-dwarf extension to DWARF 4. + pub debug_types: DebugTypes, +} + +impl DwarfPackageSections { + /// Try to load the `.dwp` sections using the given loader function. + /// + /// `section` loads a DWARF section from the object file. + /// It should return an empty section if the section does not exist. + pub fn load(mut section: F) -> core::result::Result + where + F: FnMut(SectionId) -> core::result::Result, + E: From, + { + Ok(DwarfPackageSections { + // Section types are inferred. + cu_index: Section::load(&mut section)?, + tu_index: Section::load(&mut section)?, + debug_abbrev: Section::load(&mut section)?, + debug_info: Section::load(&mut section)?, + debug_line: Section::load(&mut section)?, + debug_str: Section::load(&mut section)?, + debug_str_offsets: Section::load(&mut section)?, + debug_loc: Section::load(&mut section)?, + debug_loclists: Section::load(&mut section)?, + debug_rnglists: Section::load(&mut section)?, + debug_types: Section::load(&mut section)?, + }) + } + + /// Create a `DwarfPackage` structure that references the data in `self`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F, empty: R) -> Result> + where + F: FnMut(&'a T) -> R, + R: Reader, + { + DwarfPackage::from_sections( + DwarfPackageSections { + cu_index: self.cu_index.borrow(&mut borrow), + tu_index: self.tu_index.borrow(&mut borrow), + debug_abbrev: self.debug_abbrev.borrow(&mut borrow), + debug_info: self.debug_info.borrow(&mut borrow), + debug_line: self.debug_line.borrow(&mut borrow), + debug_str: self.debug_str.borrow(&mut borrow), + debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), + debug_loc: self.debug_loc.borrow(&mut borrow), + debug_loclists: self.debug_loclists.borrow(&mut borrow), + debug_rnglists: self.debug_rnglists.borrow(&mut borrow), + debug_types: self.debug_types.borrow(&mut borrow), + }, + empty, + ) + } +} + +/// The sections from a `.dwp` file, with parsed indices. +#[derive(Debug)] +pub struct DwarfPackage { + /// The compilation unit index in the `.debug_cu_index` section. + pub cu_index: UnitIndex, + + /// The type unit index in the `.debug_tu_index` section. + pub tu_index: UnitIndex, + + /// The `.debug_abbrev.dwo` section. + pub debug_abbrev: DebugAbbrev, + + /// The `.debug_info.dwo` section. + pub debug_info: DebugInfo, + + /// The `.debug_line.dwo` section. + pub debug_line: DebugLine, + + /// The `.debug_str.dwo` section. + pub debug_str: DebugStr, + + /// The `.debug_str_offsets.dwo` section. + pub debug_str_offsets: DebugStrOffsets, + + /// The `.debug_loc.dwo` section. + /// + /// Only present when using GNU split-dwarf extension to DWARF 4. + pub debug_loc: DebugLoc, + + /// The `.debug_loclists.dwo` section. + pub debug_loclists: DebugLocLists, + + /// The `.debug_rnglists.dwo` section. + pub debug_rnglists: DebugRngLists, + + /// The `.debug_types.dwo` section. + /// + /// Only present when using GNU split-dwarf extension to DWARF 4. + pub debug_types: DebugTypes, + + /// An empty section. + /// + /// Used when creating `Dwarf`. + pub empty: R, +} + +impl DwarfPackage { + /// Try to load the `.dwp` sections using the given loader function. + /// + /// `section` loads a DWARF section from the object file. + /// It should return an empty section if the section does not exist. + pub fn load(section: F, empty: R) -> core::result::Result + where + F: FnMut(SectionId) -> core::result::Result, + E: From, + { + let sections = DwarfPackageSections::load(section)?; + Ok(Self::from_sections(sections, empty)?) + } + + /// Create a `DwarfPackage` structure from the given sections. + fn from_sections(sections: DwarfPackageSections, empty: R) -> Result { + Ok(DwarfPackage { + cu_index: sections.cu_index.index()?, + tu_index: sections.tu_index.index()?, + debug_abbrev: sections.debug_abbrev, + debug_info: sections.debug_info, + debug_line: sections.debug_line, + debug_str: sections.debug_str, + debug_str_offsets: sections.debug_str_offsets, + debug_loc: sections.debug_loc, + debug_loclists: sections.debug_loclists, + debug_rnglists: sections.debug_rnglists, + debug_types: sections.debug_types, + empty, + }) + } + + /// Find the compilation unit with the given DWO identifier and return its section + /// contributions. + /// + /// ## Example Usage + /// + /// ```rust,no_run + /// # fn example( + /// # dwarf: &gimli::Dwarf, + /// # dwp: &gimli::DwarfPackage, + /// # dwo_id: gimli::DwoId, + /// # ) -> Result<(), gimli::Error> { + /// if let Some(dwo) = dwp.find_cu(dwo_id, dwarf)? { + /// let dwo_header = dwo.units().next()?.expect("DWO should have one unit"); + /// let dwo_unit = dwo.unit(dwo_header)?; + /// // Do something with `dwo_unit`. + /// } + /// # unreachable!() + /// # } + pub fn find_cu(&self, id: DwoId, parent: &Dwarf) -> Result>> { + let row = match self.cu_index.find(id.0) { + Some(row) => row, + None => return Ok(None), + }; + self.cu_sections(row, parent).map(Some) + } + + /// Find the type unit with the given type signature and return its section + /// contributions. + pub fn find_tu( + &self, + signature: DebugTypeSignature, + parent: &Dwarf, + ) -> Result>> { + let row = match self.tu_index.find(signature.0) { + Some(row) => row, + None => return Ok(None), + }; + self.tu_sections(row, parent).map(Some) + } + + /// Return the section contributions of the compilation unit at the given index. + /// + /// The index must be in the range `1..cu_index.unit_count`. + /// + /// This function should only be needed by low level parsers. + pub fn cu_sections(&self, index: u32, parent: &Dwarf) -> Result> { + self.sections(self.cu_index.sections(index)?, parent) + } + + /// Return the section contributions of the compilation unit at the given index. + /// + /// The index must be in the range `1..tu_index.unit_count`. + /// + /// This function should only be needed by low level parsers. + pub fn tu_sections(&self, index: u32, parent: &Dwarf) -> Result> { + self.sections(self.tu_index.sections(index)?, parent) + } + + /// Return the section contributions of a unit. + /// + /// This function should only be needed by low level parsers. + pub fn sections( + &self, + sections: UnitIndexSectionIterator<'_, R>, + parent: &Dwarf, + ) -> Result> { + let mut abbrev_offset = 0; + let mut abbrev_size = 0; + let mut info_offset = 0; + let mut info_size = 0; + let mut line_offset = 0; + let mut line_size = 0; + let mut loc_offset = 0; + let mut loc_size = 0; + let mut loclists_offset = 0; + let mut loclists_size = 0; + let mut str_offsets_offset = 0; + let mut str_offsets_size = 0; + let mut rnglists_offset = 0; + let mut rnglists_size = 0; + let mut types_offset = 0; + let mut types_size = 0; + for section in sections { + match section.section { + IndexSectionId::DebugAbbrev => { + abbrev_offset = section.offset; + abbrev_size = section.size; + } + IndexSectionId::DebugInfo => { + info_offset = section.offset; + info_size = section.size; + } + IndexSectionId::DebugLine => { + line_offset = section.offset; + line_size = section.size; + } + IndexSectionId::DebugLoc => { + loc_offset = section.offset; + loc_size = section.size; + } + IndexSectionId::DebugLocLists => { + loclists_offset = section.offset; + loclists_size = section.size; + } + IndexSectionId::DebugStrOffsets => { + str_offsets_offset = section.offset; + str_offsets_size = section.size; + } + IndexSectionId::DebugRngLists => { + rnglists_offset = section.offset; + rnglists_size = section.size; + } + IndexSectionId::DebugTypes => { + types_offset = section.offset; + types_size = section.size; + } + IndexSectionId::DebugMacro | IndexSectionId::DebugMacinfo => { + // These are valid but we can't parse these yet. + } + } + } + + let debug_abbrev = self.debug_abbrev.dwp_range(abbrev_offset, abbrev_size)?; + let debug_info = self.debug_info.dwp_range(info_offset, info_size)?; + let debug_line = self.debug_line.dwp_range(line_offset, line_size)?; + let debug_loc = self.debug_loc.dwp_range(loc_offset, loc_size)?; + let debug_loclists = self + .debug_loclists + .dwp_range(loclists_offset, loclists_size)?; + let debug_str_offsets = self + .debug_str_offsets + .dwp_range(str_offsets_offset, str_offsets_size)?; + let debug_rnglists = self + .debug_rnglists + .dwp_range(rnglists_offset, rnglists_size)?; + let debug_types = self.debug_types.dwp_range(types_offset, types_size)?; + + let debug_str = self.debug_str.clone(); + + let debug_addr = parent.debug_addr.clone(); + let debug_ranges = parent.ranges.debug_ranges().clone(); + + let debug_aranges = self.empty.clone().into(); + let debug_line_str = self.empty.clone().into(); + + Ok(Dwarf { + debug_abbrev, + debug_addr, + debug_aranges, + debug_info, + debug_line, + debug_line_str, + debug_str, + debug_str_offsets, + debug_types, + locations: LocationLists::new(debug_loc, debug_loclists), + ranges: RangeLists::new(debug_ranges, debug_rnglists), + file_type: DwarfFileType::Dwo, + sup: parent.sup.clone(), + abbreviations_cache: AbbreviationsCache::new(), + }) + } +} + +/// All of the commonly used information for a unit in the `.debug_info` or `.debug_types` +/// sections. +#[derive(Debug)] +pub struct Unit::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// The header of the unit. + pub header: UnitHeader, + + /// The parsed abbreviations for the unit. + pub abbreviations: Arc, + + /// The `DW_AT_name` attribute of the unit. + pub name: Option, + + /// The `DW_AT_comp_dir` attribute of the unit. + pub comp_dir: Option, + + /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0. + pub low_pc: u64, + + /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0. + pub str_offsets_base: DebugStrOffsetsBase, + + /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0. + pub addr_base: DebugAddrBase, + + /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0. + pub loclists_base: DebugLocListsBase, + + /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0. + pub rnglists_base: DebugRngListsBase, + + /// The line number program of the unit. + pub line_program: Option>, + + /// The DWO ID of a skeleton unit or split compilation unit. + pub dwo_id: Option, +} + +impl Unit { + /// Construct a new `Unit` from the given unit header. + #[inline] + pub fn new(dwarf: &Dwarf, header: UnitHeader) -> Result { + let abbreviations = dwarf.abbreviations(&header)?; + Self::new_with_abbreviations(dwarf, header, abbreviations) + } + + /// Construct a new `Unit` from the given unit header and abbreviations. + /// + /// The abbreviations for this call can be obtained using `dwarf.abbreviations(&header)`. + /// The caller may implement caching to reuse the `Abbreviations` across units with the + /// same `header.debug_abbrev_offset()` value. + #[inline] + pub fn new_with_abbreviations( + dwarf: &Dwarf, + header: UnitHeader, + abbreviations: Arc, + ) -> Result { + let mut unit = Unit { + abbreviations, + name: None, + comp_dir: None, + low_pc: 0, + str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), + // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided. + addr_base: DebugAddrBase(R::Offset::from_u8(0)), + loclists_base: DebugLocListsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), + rnglists_base: DebugRngListsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), + line_program: None, + dwo_id: match header.type_() { + UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => Some(dwo_id), + _ => None, + }, + header, + }; + let mut name = None; + let mut comp_dir = None; + let mut line_program_offset = None; + let mut low_pc_attr = None; + + { + let mut cursor = unit.header.entries(&unit.abbreviations); + cursor.next_dfs()?; + let root = cursor.current().ok_or(Error::MissingUnitDie)?; + let mut attrs = root.attrs(); + while let Some(attr) = attrs.next()? { + match attr.name() { + constants::DW_AT_name => { + name = Some(attr.value()); + } + constants::DW_AT_comp_dir => { + comp_dir = Some(attr.value()); + } + constants::DW_AT_low_pc => { + low_pc_attr = Some(attr.value()); + } + constants::DW_AT_stmt_list => { + if let AttributeValue::DebugLineRef(offset) = attr.value() { + line_program_offset = Some(offset); + } + } + constants::DW_AT_str_offsets_base => { + if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() { + unit.str_offsets_base = base; + } + } + constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { + if let AttributeValue::DebugAddrBase(base) = attr.value() { + unit.addr_base = base; + } + } + constants::DW_AT_loclists_base => { + if let AttributeValue::DebugLocListsBase(base) = attr.value() { + unit.loclists_base = base; + } + } + constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { + if let AttributeValue::DebugRngListsBase(base) = attr.value() { + unit.rnglists_base = base; + } + } + constants::DW_AT_GNU_dwo_id => { + if unit.dwo_id.is_none() { + if let AttributeValue::DwoId(dwo_id) = attr.value() { + unit.dwo_id = Some(dwo_id); + } + } + } + _ => {} + } + } + } + + unit.name = match name { + Some(val) => dwarf.attr_string(&unit, val).ok(), + None => None, + }; + unit.comp_dir = match comp_dir { + Some(val) => dwarf.attr_string(&unit, val).ok(), + None => None, + }; + unit.line_program = match line_program_offset { + Some(offset) => Some(dwarf.debug_line.program( + offset, + unit.header.address_size(), + unit.comp_dir.clone(), + unit.name.clone(), + )?), + None => None, + }; + if let Some(low_pc_attr) = low_pc_attr { + if let Some(addr) = dwarf.attr_address(&unit, low_pc_attr)? { + unit.low_pc = addr; + } + } + Ok(unit) + } + + /// Return a reference to this unit and its associated `Dwarf`. + pub fn unit_ref<'a>(&'a self, dwarf: &'a Dwarf) -> UnitRef<'a, R> { + UnitRef::new(dwarf, self) + } + + /// Return the encoding parameters for this unit. + #[inline] + pub fn encoding(&self) -> Encoding { + self.header.encoding() + } + + /// Read the `DebuggingInformationEntry` at the given offset. + pub fn entry( + &self, + offset: UnitOffset, + ) -> Result> { + self.header.entry(&self.abbreviations, offset) + } + + /// Navigate this unit's `DebuggingInformationEntry`s. + #[inline] + pub fn entries(&self) -> EntriesCursor<'_, '_, R> { + self.header.entries(&self.abbreviations) + } + + /// Navigate this unit's `DebuggingInformationEntry`s + /// starting at the given offset. + #[inline] + pub fn entries_at_offset( + &self, + offset: UnitOffset, + ) -> Result> { + self.header.entries_at_offset(&self.abbreviations, offset) + } + + /// Navigate this unit's `DebuggingInformationEntry`s as a tree + /// starting at the given offset. + #[inline] + pub fn entries_tree( + &self, + offset: Option>, + ) -> Result> { + self.header.entries_tree(&self.abbreviations, offset) + } + + /// Read the raw data that defines the Debugging Information Entries. + #[inline] + pub fn entries_raw( + &self, + offset: Option>, + ) -> Result> { + self.header.entries_raw(&self.abbreviations, offset) + } + + /// Copy attributes that are subject to relocation from another unit. This is intended + /// to be used to copy attributes from a skeleton compilation unit to the corresponding + /// split compilation unit. + pub fn copy_relocated_attributes(&mut self, other: &Unit) { + self.low_pc = other.low_pc; + self.addr_base = other.addr_base; + if self.header.version() < 5 { + self.rnglists_base = other.rnglists_base; + } + } + + /// Find the dwo name (if any) for this unit, automatically handling the differences + /// between the standardized DWARF 5 split DWARF format and the pre-DWARF 5 GNU + /// extension. + /// + /// The returned value is relative to this unit's `comp_dir`. + pub fn dwo_name(&self) -> Result>> { + let mut entries = self.entries(); + entries.next_entry()?; + let entry = entries.current().ok_or(Error::MissingUnitDie)?; + if self.header.version() < 5 { + entry.attr_value(constants::DW_AT_GNU_dwo_name) + } else { + entry.attr_value(constants::DW_AT_dwo_name) + } + } +} + +/// A reference to a `Unit` and its associated `Dwarf`. +/// +/// These often need to be passed around together, so this struct makes that easier. +/// +/// It implements `Deref` to `Unit`, so you can use it as if it were a `Unit`. +/// It also implements methods that correspond to methods on `Dwarf` that take a `Unit`. +#[derive(Debug)] +pub struct UnitRef<'a, R: Reader> { + /// The `Dwarf` that contains the unit. + pub dwarf: &'a Dwarf, + + /// The `Unit` being referenced. + pub unit: &'a Unit, +} + +impl<'a, R: Reader> Clone for UnitRef<'a, R> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, R: Reader> Copy for UnitRef<'a, R> {} + +impl<'a, R: Reader> core::ops::Deref for UnitRef<'a, R> { + type Target = Unit; + + fn deref(&self) -> &Self::Target { + self.unit + } +} + +impl<'a, R: Reader> UnitRef<'a, R> { + /// Construct a new `UnitRef` from a `Dwarf` and a `Unit`. + pub fn new(dwarf: &'a Dwarf, unit: &'a Unit) -> Self { + UnitRef { dwarf, unit } + } + + /// Return the string offset at the given index. + #[inline] + pub fn string_offset( + &self, + index: DebugStrOffsetsIndex, + ) -> Result> { + self.dwarf.string_offset(self.unit, index) + } + + /// Return the string at the given offset in `.debug_str`. + #[inline] + pub fn string(&self, offset: DebugStrOffset) -> Result { + self.dwarf.string(offset) + } + + /// Return the string at the given offset in `.debug_line_str`. + #[inline] + pub fn line_string(&self, offset: DebugLineStrOffset) -> Result { + self.dwarf.line_string(offset) + } + + /// Return the string at the given offset in the `.debug_str` + /// in the supplementary object file. + #[inline] + pub fn sup_string(&self, offset: DebugStrOffset) -> Result { + self.dwarf.sup_string(offset) + } + + /// Return an attribute value as a string slice. + /// + /// See [`Dwarf::attr_string`] for more information. + pub fn attr_string(&self, attr: AttributeValue) -> Result { + self.dwarf.attr_string(self.unit, attr) + } + + /// Return the address at the given index. + pub fn address(&self, index: DebugAddrIndex) -> Result { + self.dwarf.address(self.unit, index) + } + + /// Try to return an attribute value as an address. + /// + /// See [`Dwarf::attr_address`] for more information. + pub fn attr_address(&self, attr: AttributeValue) -> Result> { + self.dwarf.attr_address(self.unit, attr) + } + + /// Return the range list offset for the given raw offset. + /// + /// This handles adding `DW_AT_GNU_ranges_base` if required. + pub fn ranges_offset_from_raw( + &self, + offset: RawRangeListsOffset, + ) -> RangeListsOffset { + self.dwarf.ranges_offset_from_raw(self.unit, offset) + } + + /// Return the range list offset at the given index. + pub fn ranges_offset( + &self, + index: DebugRngListsIndex, + ) -> Result> { + self.dwarf.ranges_offset(self.unit, index) + } + + /// Iterate over the `RangeListEntry`s starting at the given offset. + pub fn ranges(&self, offset: RangeListsOffset) -> Result> { + self.dwarf.ranges(self.unit, offset) + } + + /// Iterate over the `RawRngListEntry`ies starting at the given offset. + pub fn raw_ranges(&self, offset: RangeListsOffset) -> Result> { + self.dwarf.raw_ranges(self.unit, offset) + } + + /// Try to return an attribute value as a range list offset. + /// + /// See [`Dwarf::attr_ranges_offset`] for more information. + pub fn attr_ranges_offset( + &self, + attr: AttributeValue, + ) -> Result>> { + self.dwarf.attr_ranges_offset(self.unit, attr) + } + + /// Try to return an attribute value as a range list entry iterator. + /// + /// See [`Dwarf::attr_ranges`] for more information. + pub fn attr_ranges(&self, attr: AttributeValue) -> Result>> { + self.dwarf.attr_ranges(self.unit, attr) + } + + /// Return an iterator for the address ranges of a `DebuggingInformationEntry`. + /// + /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`. + pub fn die_ranges(&self, entry: &DebuggingInformationEntry<'_, '_, R>) -> Result> { + self.dwarf.die_ranges(self.unit, entry) + } + + /// Return an iterator for the address ranges of the `Unit`. + /// + /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the + /// root `DebuggingInformationEntry`. + pub fn unit_ranges(&self) -> Result> { + self.dwarf.unit_ranges(self.unit) + } + + /// Return the location list offset at the given index. + pub fn locations_offset( + &self, + index: DebugLocListsIndex, + ) -> Result> { + self.dwarf.locations_offset(self.unit, index) + } + + /// Iterate over the `LocationListEntry`s starting at the given offset. + pub fn locations(&self, offset: LocationListsOffset) -> Result> { + self.dwarf.locations(self.unit, offset) + } + + /// Iterate over the raw `LocationListEntry`s starting at the given offset. + pub fn raw_locations( + &self, + offset: LocationListsOffset, + ) -> Result> { + self.dwarf.raw_locations(self.unit, offset) + } + + /// Try to return an attribute value as a location list offset. + /// + /// See [`Dwarf::attr_locations_offset`] for more information. + pub fn attr_locations_offset( + &self, + attr: AttributeValue, + ) -> Result>> { + self.dwarf.attr_locations_offset(self.unit, attr) + } + + /// Try to return an attribute value as a location list entry iterator. + /// + /// See [`Dwarf::attr_locations`] for more information. + pub fn attr_locations(&self, attr: AttributeValue) -> Result>> { + self.dwarf.attr_locations(self.unit, attr) + } +} + +impl UnitSectionOffset { + /// Convert an offset to be relative to the start of the given unit, + /// instead of relative to the start of the section. + /// + /// Returns `None` if the offset is not within the unit entries. + pub fn to_unit_offset(&self, unit: &Unit) -> Option> + where + R: Reader, + { + let (offset, unit_offset) = match (self, unit.header.offset()) { + ( + UnitSectionOffset::DebugInfoOffset(offset), + UnitSectionOffset::DebugInfoOffset(unit_offset), + ) => (offset.0, unit_offset.0), + ( + UnitSectionOffset::DebugTypesOffset(offset), + UnitSectionOffset::DebugTypesOffset(unit_offset), + ) => (offset.0, unit_offset.0), + _ => return None, + }; + let offset = match offset.checked_sub(unit_offset) { + Some(offset) => UnitOffset(offset), + None => return None, + }; + if !unit.header.is_valid_offset(offset) { + return None; + } + Some(offset) + } +} + +impl UnitOffset { + /// Convert an offset to be relative to the start of the .debug_info section, + /// instead of relative to the start of the given compilation unit. + /// + /// Does not check that the offset is valid. + pub fn to_unit_section_offset(&self, unit: &Unit) -> UnitSectionOffset + where + R: Reader, + { + match unit.header.offset() { + UnitSectionOffset::DebugInfoOffset(unit_offset) => { + DebugInfoOffset(unit_offset.0 + self.0).into() + } + UnitSectionOffset::DebugTypesOffset(unit_offset) => { + DebugTypesOffset(unit_offset.0 + self.0).into() + } + } + } +} + +/// An iterator for the address ranges of a `DebuggingInformationEntry`. +/// +/// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`. +#[derive(Debug)] +pub struct RangeIter(RangeIterInner); + +#[derive(Debug)] +enum RangeIterInner { + Single(Option), + List(RngListIter), +} + +impl Default for RangeIter { + fn default() -> Self { + RangeIter(RangeIterInner::Single(None)) + } +} + +impl RangeIter { + /// Advance the iterator to the next range. + pub fn next(&mut self) -> Result> { + match self.0 { + RangeIterInner::Single(ref mut range) => Ok(range.take()), + RangeIterInner::List(ref mut list) => list.next(), + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for RangeIter { + type Item = Range; + type Error = Error; + + #[inline] + fn next(&mut self) -> ::core::result::Result, Self::Error> { + RangeIter::next(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::read::EndianSlice; + use crate::{Endianity, LittleEndian}; + + /// Ensure that `Dwarf` is covariant wrt R. + #[test] + fn test_dwarf_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf>) -> Dwarf> { + x + } + } + + /// Ensure that `Unit` is covariant wrt R. + #[test] + fn test_dwarf_unit_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>(x: Unit>) -> Unit> { + x + } + } + + #[test] + fn test_send() { + fn assert_is_send() {} + assert_is_send::>>(); + assert_is_send::>>(); + } + + #[test] + fn test_format_error() { + let dwarf_sections = DwarfSections::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap(); + let sup_sections = DwarfSections::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap(); + let dwarf = dwarf_sections.borrow_with_sup(&sup_sections, |section| { + EndianSlice::new(section, LittleEndian) + }); + + match dwarf.debug_str.get_str(DebugStrOffset(1)) { + Ok(r) => panic!("Unexpected str {:?}", r), + Err(e) => { + assert_eq!( + dwarf.format_error(e), + "Hit the end of input before it was expected at .debug_str+0x1" + ); + } + } + match dwarf.sup().unwrap().debug_str.get_str(DebugStrOffset(1)) { + Ok(r) => panic!("Unexpected str {:?}", r), + Err(e) => { + assert_eq!( + dwarf.format_error(e), + "Hit the end of input before it was expected at .debug_str(sup)+0x1" + ); + } + } + assert_eq!(dwarf.format_error(Error::Io), Error::Io.description()); + } +} diff --git a/deps/crates/vendor/gimli/src/read/endian_reader.rs b/deps/crates/vendor/gimli/src/read/endian_reader.rs new file mode 100644 index 00000000000000..5e65b4d1cfb859 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/endian_reader.rs @@ -0,0 +1,651 @@ +//! Defining custom `Reader`s quickly. + +use alloc::borrow::Cow; +use alloc::rc::Rc; +use alloc::string::String; +use alloc::sync::Arc; +use core::fmt::Debug; +use core::hash::{Hash, Hasher}; +use core::ops::{Deref, Index, Range, RangeFrom, RangeTo}; +use core::slice; +use core::str; +use stable_deref_trait::CloneStableDeref; + +use crate::endianity::Endianity; +use crate::read::{Error, Reader, ReaderOffsetId, Result}; + +/// A reference counted, non-thread-safe slice of bytes and associated +/// endianity. +/// +/// ``` +/// # #[cfg(feature = "std")] { +/// use std::rc::Rc; +/// +/// let buf = Rc::from(&[1, 2, 3, 4][..]); +/// let reader = gimli::EndianRcSlice::new(buf, gimli::NativeEndian); +/// # let _ = reader; +/// # } +/// ``` +pub type EndianRcSlice = EndianReader>; + +/// An atomically reference counted, thread-safe slice of bytes and associated +/// endianity. +/// +/// ``` +/// # #[cfg(feature = "std")] { +/// use std::sync::Arc; +/// +/// let buf = Arc::from(&[1, 2, 3, 4][..]); +/// let reader = gimli::EndianArcSlice::new(buf, gimli::NativeEndian); +/// # let _ = reader; +/// # } +/// ``` +pub type EndianArcSlice = EndianReader>; + +/// An easy way to define a custom `Reader` implementation with a reference to a +/// generic buffer of bytes and an associated endianity. +/// +/// Note that the whole original buffer is kept alive in memory even if there is +/// only one reader that references only a handful of bytes from that original +/// buffer. That is, `EndianReader` will not do any copying, moving, or +/// compacting in order to free up unused regions of the original buffer. If you +/// require this kind of behavior, it is up to you to implement `Reader` +/// directly by-hand. +/// +/// # Example +/// +/// Say you have an `mmap`ed file that you want to serve as a `gimli::Reader`. +/// You can wrap that `mmap`ed file up in a `MmapFile` type and use +/// `EndianReader>` or `EndianReader>` as readers as +/// long as `MmapFile` dereferences to the underlying `[u8]` data. +/// +/// ``` +/// use std::io; +/// use std::ops::Deref; +/// use std::path::Path; +/// use std::slice; +/// use std::sync::Arc; +/// +/// /// A type that represents an `mmap`ed file. +/// #[derive(Debug)] +/// pub struct MmapFile { +/// ptr: *const u8, +/// len: usize, +/// } +/// +/// impl MmapFile { +/// pub fn new(path: &Path) -> io::Result { +/// // Call `mmap` and check for errors and all that... +/// # unimplemented!() +/// } +/// } +/// +/// impl Drop for MmapFile { +/// fn drop(&mut self) { +/// // Call `munmap` to clean up after ourselves... +/// # unimplemented!() +/// } +/// } +/// +/// // And `MmapFile` can deref to a slice of the `mmap`ed region of memory. +/// impl Deref for MmapFile { +/// type Target = [u8]; +/// fn deref(&self) -> &[u8] { +/// unsafe { +/// slice::from_raw_parts(self.ptr, self.len) +/// } +/// } +/// } +/// +/// /// A type that represents a shared `mmap`ed file. +/// #[derive(Debug, Clone)] +/// pub struct ArcMmapFile(Arc); +/// +/// // And `ArcMmapFile` can deref to a slice of the `mmap`ed region of memory. +/// impl Deref for ArcMmapFile { +/// type Target = [u8]; +/// fn deref(&self) -> &[u8] { +/// &self.0 +/// } +/// } +/// +/// // These are both valid for any `Rc` or `Arc`. +/// unsafe impl gimli::StableDeref for ArcMmapFile {} +/// unsafe impl gimli::CloneStableDeref for ArcMmapFile {} +/// +/// /// A `gimli::Reader` that is backed by an `mmap`ed file! +/// pub type MmapFileReader = gimli::EndianReader; +/// # fn test(_: &MmapFileReader) { } +/// ``` +#[derive(Debug, Clone, Copy)] +pub struct EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + range: SubRange, + endian: Endian, +} + +impl PartialEq> for EndianReader +where + Endian: Endianity, + T1: CloneStableDeref + Debug, + T2: CloneStableDeref + Debug, +{ + fn eq(&self, rhs: &EndianReader) -> bool { + self.bytes() == rhs.bytes() + } +} + +impl Eq for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ +} + +impl Hash for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + fn hash(&self, state: &mut H) { + // This must match the `PartialEq` implementation. + self.bytes().hash(state); + } +} + +// This is separated out from `EndianReader` so that we can avoid running afoul +// of borrowck. We need to `read_slice(&mut self, ...) -> &[u8]` and then call +// `self.endian.read_whatever` on the result. The problem is that the returned +// slice keeps the `&mut self` borrow active, so we wouldn't be able to access +// `self.endian`. Splitting the sub-range out from the endian lets us work +// around this, making it so that only the `self.range` borrow is held active, +// not all of `self`. +// +// This also serves to encapsulate the unsafe code concerning `CloneStableDeref`. +// The `bytes` member is held so that the bytes live long enough, and the +// `CloneStableDeref` ensures these bytes never move. The `ptr` and `len` +// members point inside `bytes`, and are updated during read operations. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct SubRange +where + T: CloneStableDeref + Debug, +{ + bytes: T, + ptr: *const u8, + len: usize, +} + +unsafe impl Send for SubRange where T: CloneStableDeref + Debug + Send {} + +unsafe impl Sync for SubRange where T: CloneStableDeref + Debug + Sync {} + +impl SubRange +where + T: CloneStableDeref + Debug, +{ + #[inline] + fn new(bytes: T) -> Self { + let ptr = bytes.as_ptr(); + let len = bytes.len(); + SubRange { bytes, ptr, len } + } + + #[inline] + fn bytes(&self) -> &[u8] { + // Safe because `T` implements `CloneStableDeref`, `bytes` can't be modified, + // and all operations that modify `ptr` and `len` ensure they stay in range. + unsafe { slice::from_raw_parts(self.ptr, self.len) } + } + + #[inline] + fn len(&self) -> usize { + self.len + } + + #[inline] + fn truncate(&mut self, len: usize) { + assert!(len <= self.len); + self.len = len; + } + + #[inline] + fn skip(&mut self, len: usize) { + assert!(len <= self.len); + self.ptr = unsafe { self.ptr.add(len) }; + self.len -= len; + } + + #[inline] + fn read_slice(&mut self, len: usize) -> Option<&[u8]> { + if self.len() < len { + None + } else { + // Same as for `bytes()`. + let bytes = unsafe { slice::from_raw_parts(self.ptr, len) }; + self.skip(len); + Some(bytes) + } + } +} + +impl EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + /// Construct a new `EndianReader` with the given bytes. + #[inline] + pub fn new(bytes: T, endian: Endian) -> EndianReader { + EndianReader { + range: SubRange::new(bytes), + endian, + } + } + + /// Return a reference to the raw bytes underlying this reader. + #[inline] + pub fn bytes(&self) -> &[u8] { + self.range.bytes() + } +} + +/// # Range Methods +/// +/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't +/// implement `Index>` to return a new `EndianReader` the way we +/// would like to. Instead, we abandon fancy indexing operators and have these +/// plain old methods. +impl EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + /// Take the given `start..end` range of the underlying buffer and return a + /// new `EndianReader`. + /// + /// ``` + /// # #[cfg(feature = "std")] { + /// use gimli::{EndianReader, LittleEndian}; + /// use std::sync::Arc; + /// + /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); + /// let reader = EndianReader::new(buf.clone(), LittleEndian); + /// assert_eq!(reader.range(1..3), + /// EndianReader::new(&buf[1..3], LittleEndian)); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics if the range is out of bounds. + pub fn range(&self, idx: Range) -> EndianReader { + let mut r = self.clone(); + r.range.skip(idx.start); + r.range.truncate(idx.len()); + r + } + + /// Take the given `start..` range of the underlying buffer and return a new + /// `EndianReader`. + /// + /// ``` + /// # #[cfg(feature = "std")] { + /// use gimli::{EndianReader, LittleEndian}; + /// use std::sync::Arc; + /// + /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); + /// let reader = EndianReader::new(buf.clone(), LittleEndian); + /// assert_eq!(reader.range_from(2..), + /// EndianReader::new(&buf[2..], LittleEndian)); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics if the range is out of bounds. + pub fn range_from(&self, idx: RangeFrom) -> EndianReader { + let mut r = self.clone(); + r.range.skip(idx.start); + r + } + + /// Take the given `..end` range of the underlying buffer and return a new + /// `EndianReader`. + /// + /// ``` + /// # #[cfg(feature = "std")] { + /// use gimli::{EndianReader, LittleEndian}; + /// use std::sync::Arc; + /// + /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); + /// let reader = EndianReader::new(buf.clone(), LittleEndian); + /// assert_eq!(reader.range_to(..3), + /// EndianReader::new(&buf[..3], LittleEndian)); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics if the range is out of bounds. + pub fn range_to(&self, idx: RangeTo) -> EndianReader { + let mut r = self.clone(); + r.range.truncate(idx.end); + r + } +} + +impl Index for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + type Output = u8; + fn index(&self, idx: usize) -> &Self::Output { + &self.bytes()[idx] + } +} + +impl Index> for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + type Output = [u8]; + fn index(&self, idx: RangeFrom) -> &Self::Output { + &self.bytes()[idx] + } +} + +impl Deref for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.bytes() + } +} + +impl Reader for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + type Endian = Endian; + type Offset = usize; + + #[inline] + fn endian(&self) -> Endian { + self.endian + } + + #[inline] + fn len(&self) -> usize { + self.range.len() + } + + #[inline] + fn empty(&mut self) { + self.range.truncate(0); + } + + #[inline] + fn truncate(&mut self, len: usize) -> Result<()> { + if self.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + self.range.truncate(len); + Ok(()) + } + } + + #[inline] + fn offset_from(&self, base: &EndianReader) -> usize { + let base_ptr = base.bytes().as_ptr() as usize; + let ptr = self.bytes().as_ptr() as usize; + debug_assert!(base_ptr <= ptr); + debug_assert!(ptr + self.bytes().len() <= base_ptr + base.bytes().len()); + ptr - base_ptr + } + + #[inline] + fn offset_id(&self) -> ReaderOffsetId { + ReaderOffsetId(self.bytes().as_ptr() as u64) + } + + #[inline] + fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { + let id = id.0; + let self_id = self.bytes().as_ptr() as u64; + let self_len = self.bytes().len() as u64; + if id >= self_id && id <= self_id + self_len { + Some((id - self_id) as usize) + } else { + None + } + } + + #[inline] + fn find(&self, byte: u8) -> Result { + self.bytes() + .iter() + .position(|x| *x == byte) + .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) + } + + #[inline] + fn skip(&mut self, len: usize) -> Result<()> { + if self.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + self.range.skip(len); + Ok(()) + } + } + + #[inline] + fn split(&mut self, len: usize) -> Result { + if self.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + let mut r = self.clone(); + r.range.truncate(len); + self.range.skip(len); + Ok(r) + } + } + + #[inline] + fn to_slice(&self) -> Result> { + Ok(self.bytes().into()) + } + + #[inline] + fn to_string(&self) -> Result> { + match str::from_utf8(self.bytes()) { + Ok(s) => Ok(s.into()), + _ => Err(Error::BadUtf8), + } + } + + #[inline] + fn to_string_lossy(&self) -> Result> { + Ok(String::from_utf8_lossy(self.bytes())) + } + + #[inline] + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { + match self.range.read_slice(buf.len()) { + Some(slice) => { + buf.copy_from_slice(slice); + Ok(()) + } + None => Err(Error::UnexpectedEof(self.offset_id())), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::endianity::NativeEndian; + use crate::read::Reader; + + fn native_reader + Debug>( + bytes: T, + ) -> EndianReader { + EndianReader::new(bytes, NativeEndian) + } + + const BUF: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + + #[test] + fn test_reader_split() { + let mut reader = native_reader(BUF); + let left = reader.split(3).unwrap(); + assert_eq!(left, native_reader(&BUF[..3])); + assert_eq!(reader, native_reader(&BUF[3..])); + } + + #[test] + fn test_reader_split_out_of_bounds() { + let mut reader = native_reader(BUF); + assert!(reader.split(30).is_err()); + } + + #[test] + fn bytes_and_len_and_range_and_eq() { + let reader = native_reader(BUF); + assert_eq!(reader.len(), BUF.len()); + assert_eq!(reader.bytes(), BUF); + assert_eq!(reader, native_reader(BUF)); + + let range = reader.range(2..8); + let buf_range = &BUF[2..8]; + assert_eq!(range.len(), buf_range.len()); + assert_eq!(range.bytes(), buf_range); + assert_ne!(range, native_reader(BUF)); + assert_eq!(range, native_reader(buf_range)); + + let range_from = range.range_from(1..); + let buf_range_from = &buf_range[1..]; + assert_eq!(range_from.len(), buf_range_from.len()); + assert_eq!(range_from.bytes(), buf_range_from); + assert_ne!(range_from, native_reader(BUF)); + assert_eq!(range_from, native_reader(buf_range_from)); + + let range_to = range_from.range_to(..4); + let buf_range_to = &buf_range_from[..4]; + assert_eq!(range_to.len(), buf_range_to.len()); + assert_eq!(range_to.bytes(), buf_range_to); + assert_ne!(range_to, native_reader(BUF)); + assert_eq!(range_to, native_reader(buf_range_to)); + } + + #[test] + fn find() { + let mut reader = native_reader(BUF); + reader.skip(2).unwrap(); + assert_eq!( + reader.find(5), + Ok(BUF[2..].iter().position(|x| *x == 5).unwrap()) + ); + } + + #[test] + fn indexing() { + let mut reader = native_reader(BUF); + reader.skip(2).unwrap(); + assert_eq!(reader[0], BUF[2]); + } + + #[test] + #[should_panic] + fn indexing_out_of_bounds() { + let mut reader = native_reader(BUF); + reader.skip(2).unwrap(); + let _ = reader[900]; + } + + #[test] + fn endian() { + let reader = native_reader(BUF); + assert_eq!(reader.endian(), NativeEndian); + } + + #[test] + fn empty() { + let mut reader = native_reader(BUF); + assert!(!reader.is_empty()); + reader.empty(); + assert!(reader.is_empty()); + assert!(reader.bytes().is_empty()); + } + + #[test] + fn truncate() { + let reader = native_reader(BUF); + let mut reader = reader.range(2..8); + reader.truncate(2).unwrap(); + assert_eq!(reader.bytes(), &BUF[2..4]); + } + + #[test] + fn offset_from() { + let reader = native_reader(BUF); + let sub = reader.range(2..8); + assert_eq!(sub.offset_from(&reader), 2); + } + + #[test] + fn skip() { + let mut reader = native_reader(BUF); + reader.skip(2).unwrap(); + assert_eq!(reader.bytes(), &BUF[2..]); + } + + #[test] + fn to_slice() { + assert_eq!( + native_reader(BUF).range(2..5).to_slice(), + Ok(Cow::from(&BUF[2..5])) + ); + } + + #[test] + fn to_string_ok() { + let buf = b"hello, world!"; + let reader = native_reader(&buf[..]); + let reader = reader.range_from(7..); + assert_eq!(reader.to_string(), Ok(Cow::from("world!"))); + } + + // The rocket emoji (🚀 = [0xf0, 0x9f, 0x9a, 0x80]) but rotated left by one + // to make it invalid UTF-8. + const BAD_UTF8: &[u8] = &[0x9f, 0x9a, 0x80, 0xf0]; + + #[test] + fn to_string_err() { + let reader = native_reader(BAD_UTF8); + assert!(reader.to_string().is_err()); + } + + #[test] + fn to_string_lossy() { + let reader = native_reader(BAD_UTF8); + assert_eq!(reader.to_string_lossy(), Ok(Cow::from("����"))); + } + + #[test] + fn read_u8_array() { + let mut reader = native_reader(BAD_UTF8); + reader.skip(1).unwrap(); + let arr: [u8; 2] = reader.read_u8_array().unwrap(); + assert_eq!(arr, &BAD_UTF8[1..3]); + assert_eq!(reader.bytes(), &BAD_UTF8[3..]); + } +} diff --git a/deps/crates/vendor/gimli/src/read/endian_slice.rs b/deps/crates/vendor/gimli/src/read/endian_slice.rs new file mode 100644 index 00000000000000..03351429ef25b5 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/endian_slice.rs @@ -0,0 +1,360 @@ +//! Working with byte slices that have an associated endianity. + +#[cfg(feature = "read")] +use alloc::borrow::Cow; +#[cfg(feature = "read")] +use alloc::string::String; +use core::fmt; +use core::ops::{Deref, Range, RangeFrom, RangeTo}; +use core::str; + +use crate::endianity::Endianity; +use crate::read::{Error, Reader, ReaderOffsetId, Result}; + +/// A `&[u8]` slice with endianity metadata. +/// +/// This implements the `Reader` trait, which is used for all reading of DWARF sections. +#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EndianSlice<'input, Endian> +where + Endian: Endianity, +{ + slice: &'input [u8], + endian: Endian, +} + +impl<'input, Endian> EndianSlice<'input, Endian> +where + Endian: Endianity, +{ + /// Construct a new `EndianSlice` with the given slice and endianity. + #[inline] + pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> { + EndianSlice { slice, endian } + } + + /// Return a reference to the raw slice. + #[inline] + #[doc(hidden)] + #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")] + pub fn buf(&self) -> &'input [u8] { + self.slice + } + + /// Return a reference to the raw slice. + #[inline] + pub fn slice(&self) -> &'input [u8] { + self.slice + } + + /// Split the slice in two at the given index, resulting in the tuple where + /// the first item has range [0, idx), and the second has range [idx, + /// len). Panics if the index is out of bounds. + #[inline] + pub fn split_at( + &self, + idx: usize, + ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) { + (self.range_to(..idx), self.range_from(idx..)) + } + + /// Find the first occurrence of a byte in the slice, and return its index. + #[inline] + pub fn find(&self, byte: u8) -> Option { + self.slice.iter().position(|ch| *ch == byte) + } + + /// Return the offset of the start of the slice relative to the start + /// of the given slice. + #[inline] + pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize { + let base_ptr = base.slice.as_ptr() as usize; + let ptr = self.slice.as_ptr() as usize; + debug_assert!(base_ptr <= ptr); + debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len()); + ptr - base_ptr + } + + /// Converts the slice to a string using `str::from_utf8`. + /// + /// Returns an error if the slice contains invalid characters. + #[inline] + pub fn to_string(&self) -> Result<&'input str> { + str::from_utf8(self.slice).map_err(|_| Error::BadUtf8) + } + + /// Converts the slice to a string, including invalid characters, + /// using `String::from_utf8_lossy`. + #[cfg(feature = "read")] + #[inline] + pub fn to_string_lossy(&self) -> Cow<'input, str> { + String::from_utf8_lossy(self.slice) + } + + #[inline] + fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> { + if self.slice.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + let val = &self.slice[..len]; + self.slice = &self.slice[len..]; + Ok(val) + } + } +} + +/// # Range Methods +/// +/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't +/// implement `Index>` to return a new `EndianSlice` the way we would +/// like to. Instead, we abandon fancy indexing operators and have these plain +/// old methods. +impl<'input, Endian> EndianSlice<'input, Endian> +where + Endian: Endianity, +{ + /// Take the given `start..end` range of the underlying slice and return a + /// new `EndianSlice`. + /// + /// ``` + /// use gimli::{EndianSlice, LittleEndian}; + /// + /// let slice = &[0x01, 0x02, 0x03, 0x04]; + /// let endian_slice = EndianSlice::new(slice, LittleEndian); + /// assert_eq!(endian_slice.range(1..3), + /// EndianSlice::new(&slice[1..3], LittleEndian)); + /// ``` + pub fn range(&self, idx: Range) -> EndianSlice<'input, Endian> { + EndianSlice { + slice: &self.slice[idx], + endian: self.endian, + } + } + + /// Take the given `start..` range of the underlying slice and return a new + /// `EndianSlice`. + /// + /// ``` + /// use gimli::{EndianSlice, LittleEndian}; + /// + /// let slice = &[0x01, 0x02, 0x03, 0x04]; + /// let endian_slice = EndianSlice::new(slice, LittleEndian); + /// assert_eq!(endian_slice.range_from(2..), + /// EndianSlice::new(&slice[2..], LittleEndian)); + /// ``` + pub fn range_from(&self, idx: RangeFrom) -> EndianSlice<'input, Endian> { + EndianSlice { + slice: &self.slice[idx], + endian: self.endian, + } + } + + /// Take the given `..end` range of the underlying slice and return a new + /// `EndianSlice`. + /// + /// ``` + /// use gimli::{EndianSlice, LittleEndian}; + /// + /// let slice = &[0x01, 0x02, 0x03, 0x04]; + /// let endian_slice = EndianSlice::new(slice, LittleEndian); + /// assert_eq!(endian_slice.range_to(..3), + /// EndianSlice::new(&slice[..3], LittleEndian)); + /// ``` + pub fn range_to(&self, idx: RangeTo) -> EndianSlice<'input, Endian> { + EndianSlice { + slice: &self.slice[idx], + endian: self.endian, + } + } +} + +impl<'input, Endian> Deref for EndianSlice<'input, Endian> +where + Endian: Endianity, +{ + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.slice + } +} + +impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> { + fmt.debug_tuple("EndianSlice") + .field(&self.endian) + .field(&DebugBytes(self.slice)) + .finish() + } +} + +struct DebugBytes<'input>(&'input [u8]); + +impl<'input> core::fmt::Debug for DebugBytes<'input> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> { + let mut list = fmt.debug_list(); + list.entries(self.0.iter().take(8).copied().map(DebugByte)); + if self.0.len() > 8 { + list.entry(&DebugLen(self.0.len())); + } + list.finish() + } +} + +struct DebugByte(u8); + +impl fmt::Debug for DebugByte { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "0x{:02x}", self.0) + } +} + +struct DebugLen(usize); + +impl fmt::Debug for DebugLen { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "...; {}", self.0) + } +} + +impl<'input, Endian> Reader for EndianSlice<'input, Endian> +where + Endian: Endianity, +{ + type Endian = Endian; + type Offset = usize; + + #[inline] + fn endian(&self) -> Endian { + self.endian + } + + #[inline] + fn len(&self) -> usize { + self.slice.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.slice.is_empty() + } + + #[inline] + fn empty(&mut self) { + self.slice = &[]; + } + + #[inline] + fn truncate(&mut self, len: usize) -> Result<()> { + if self.slice.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + self.slice = &self.slice[..len]; + Ok(()) + } + } + + #[inline] + fn offset_from(&self, base: &Self) -> usize { + self.offset_from(*base) + } + + #[inline] + fn offset_id(&self) -> ReaderOffsetId { + ReaderOffsetId(self.slice.as_ptr() as u64) + } + + #[inline] + fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { + let id = id.0; + let self_id = self.slice.as_ptr() as u64; + let self_len = self.slice.len() as u64; + if id >= self_id && id <= self_id + self_len { + Some((id - self_id) as usize) + } else { + None + } + } + + #[inline] + fn find(&self, byte: u8) -> Result { + self.find(byte) + .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) + } + + #[inline] + fn skip(&mut self, len: usize) -> Result<()> { + if self.slice.len() < len { + Err(Error::UnexpectedEof(self.offset_id())) + } else { + self.slice = &self.slice[len..]; + Ok(()) + } + } + + #[inline] + fn split(&mut self, len: usize) -> Result { + let slice = self.read_slice(len)?; + Ok(EndianSlice::new(slice, self.endian)) + } + + #[cfg(not(feature = "read"))] + fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed { + super::reader::seal_if_no_alloc::Sealed + } + + #[cfg(feature = "read")] + #[inline] + fn to_slice(&self) -> Result> { + Ok(self.slice.into()) + } + + #[cfg(feature = "read")] + #[inline] + fn to_string(&self) -> Result> { + match str::from_utf8(self.slice) { + Ok(s) => Ok(s.into()), + _ => Err(Error::BadUtf8), + } + } + + #[cfg(feature = "read")] + #[inline] + fn to_string_lossy(&self) -> Result> { + Ok(String::from_utf8_lossy(self.slice)) + } + + #[inline] + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { + let slice = self.read_slice(buf.len())?; + buf.copy_from_slice(slice); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::endianity::NativeEndian; + + #[test] + fn test_endian_slice_split_at() { + let endian = NativeEndian; + let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let eb = EndianSlice::new(slice, endian); + assert_eq!( + eb.split_at(3), + ( + EndianSlice::new(&slice[..3], endian), + EndianSlice::new(&slice[3..], endian) + ) + ); + } + + #[test] + #[should_panic] + fn test_endian_slice_split_at_out_of_bounds() { + let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let eb = EndianSlice::new(slice, NativeEndian); + eb.split_at(30); + } +} diff --git a/deps/crates/vendor/gimli/src/read/index.rs b/deps/crates/vendor/gimli/src/read/index.rs new file mode 100644 index 00000000000000..bd8e74bf1fd765 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/index.rs @@ -0,0 +1,631 @@ +use core::slice; + +use crate::common::SectionId; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section}; + +/// The data in the `.debug_cu_index` section of a `.dwp` file. +/// +/// This section contains the compilation unit index. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugCuIndex { + section: R, +} + +impl<'input, Endian> DebugCuIndex> +where + Endian: Endianity, +{ + /// Construct a new `DebugCuIndex` instance from the data in the `.debug_cu_index` + /// section. + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugCuIndex { + /// Create a `DebugCuIndex` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfPackageSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugCuIndex + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugCuIndex { + fn id() -> SectionId { + SectionId::DebugCuIndex + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugCuIndex { + fn from(section: R) -> Self { + DebugCuIndex { section } + } +} + +impl DebugCuIndex { + /// Parse the index header. + pub fn index(self) -> Result> { + UnitIndex::parse(self.section) + } +} + +/// The data in the `.debug_tu_index` section of a `.dwp` file. +/// +/// This section contains the type unit index. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugTuIndex { + section: R, +} + +impl<'input, Endian> DebugTuIndex> +where + Endian: Endianity, +{ + /// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index` + /// section. + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugTuIndex { + /// Create a `DebugTuIndex` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfPackageSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTuIndex + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugTuIndex { + fn id() -> SectionId { + SectionId::DebugTuIndex + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugTuIndex { + fn from(section: R) -> Self { + DebugTuIndex { section } + } +} + +impl DebugTuIndex { + /// Parse the index header. + pub fn index(self) -> Result> { + UnitIndex::parse(self.section) + } +} + +const SECTION_COUNT_MAX: u8 = 8; + +/// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`. +#[derive(Debug, Clone)] +pub struct UnitIndex { + version: u16, + section_count: u32, + unit_count: u32, + slot_count: u32, + hash_ids: R, + hash_rows: R, + // Only `section_count` values are valid. + sections: [IndexSectionId; SECTION_COUNT_MAX as usize], + offsets: R, + sizes: R, +} + +impl UnitIndex { + fn parse(mut input: R) -> Result> { + if input.is_empty() { + return Ok(UnitIndex { + version: 0, + section_count: 0, + unit_count: 0, + slot_count: 0, + hash_ids: input.clone(), + hash_rows: input.clone(), + sections: [IndexSectionId::DebugAbbrev; SECTION_COUNT_MAX as usize], + offsets: input.clone(), + sizes: input.clone(), + }); + } + + // GNU split-dwarf extension to DWARF 4 uses a 32-bit version, + // but DWARF 5 uses a 16-bit version followed by 16-bit padding. + let mut original_input = input.clone(); + let version; + if input.read_u32()? == 2 { + version = 2 + } else { + version = original_input.read_u16()?; + if version != 5 { + return Err(Error::UnknownVersion(version.into())); + } + } + + let section_count = input.read_u32()?; + let unit_count = input.read_u32()?; + let slot_count = input.read_u32()?; + if slot_count != 0 && (slot_count & (slot_count - 1) != 0 || slot_count <= unit_count) { + return Err(Error::InvalidIndexSlotCount); + } + + let hash_ids = input.split(R::Offset::from_u64(u64::from(slot_count) * 8)?)?; + let hash_rows = input.split(R::Offset::from_u64(u64::from(slot_count) * 4)?)?; + + let mut sections = [IndexSectionId::DebugAbbrev; SECTION_COUNT_MAX as usize]; + if section_count > SECTION_COUNT_MAX.into() { + return Err(Error::InvalidIndexSectionCount); + } + for i in 0..section_count { + let section = input.read_u32()?; + sections[i as usize] = if version == 2 { + match constants::DwSectV2(section) { + constants::DW_SECT_V2_INFO => IndexSectionId::DebugInfo, + constants::DW_SECT_V2_TYPES => IndexSectionId::DebugTypes, + constants::DW_SECT_V2_ABBREV => IndexSectionId::DebugAbbrev, + constants::DW_SECT_V2_LINE => IndexSectionId::DebugLine, + constants::DW_SECT_V2_LOC => IndexSectionId::DebugLoc, + constants::DW_SECT_V2_STR_OFFSETS => IndexSectionId::DebugStrOffsets, + constants::DW_SECT_V2_MACINFO => IndexSectionId::DebugMacinfo, + constants::DW_SECT_V2_MACRO => IndexSectionId::DebugMacro, + section => return Err(Error::UnknownIndexSectionV2(section)), + } + } else { + match constants::DwSect(section) { + constants::DW_SECT_INFO => IndexSectionId::DebugInfo, + constants::DW_SECT_ABBREV => IndexSectionId::DebugAbbrev, + constants::DW_SECT_LINE => IndexSectionId::DebugLine, + constants::DW_SECT_LOCLISTS => IndexSectionId::DebugLocLists, + constants::DW_SECT_STR_OFFSETS => IndexSectionId::DebugStrOffsets, + constants::DW_SECT_MACRO => IndexSectionId::DebugMacro, + constants::DW_SECT_RNGLISTS => IndexSectionId::DebugRngLists, + section => return Err(Error::UnknownIndexSection(section)), + } + }; + } + + let offsets = input.split(R::Offset::from_u64( + u64::from(unit_count) * u64::from(section_count) * 4, + )?)?; + let sizes = input.split(R::Offset::from_u64( + u64::from(unit_count) * u64::from(section_count) * 4, + )?)?; + + Ok(UnitIndex { + version, + section_count, + unit_count, + slot_count, + hash_ids, + hash_rows, + sections, + offsets, + sizes, + }) + } + + /// Find `id` in the index hash table, and return the row index. + /// + /// `id` may be a compilation unit ID if this index is from `.debug_cu_index`, + /// or a type signature if this index is from `.debug_tu_index`. + pub fn find(&self, id: u64) -> Option { + if self.slot_count == 0 { + return None; + } + let mask = u64::from(self.slot_count - 1); + let mut hash1 = id & mask; + let hash2 = ((id >> 32) & mask) | 1; + for _ in 0..self.slot_count { + // The length of these arrays was validated in `UnitIndex::parse`. + let mut hash_ids = self.hash_ids.clone(); + hash_ids.skip(R::Offset::from_u64(hash1 * 8).ok()?).ok()?; + let hash_id = hash_ids.read_u64().ok()?; + if hash_id == id { + let mut hash_rows = self.hash_rows.clone(); + hash_rows.skip(R::Offset::from_u64(hash1 * 4).ok()?).ok()?; + let hash_row = hash_rows.read_u32().ok()?; + return Some(hash_row); + } + if hash_id == 0 { + return None; + } + hash1 = (hash1 + hash2) & mask; + } + None + } + + /// Return the section offsets and sizes for the given row index. + pub fn sections(&self, mut row: u32) -> Result> { + if row == 0 { + return Err(Error::InvalidIndexRow); + } + row -= 1; + if row >= self.unit_count { + return Err(Error::InvalidIndexRow); + } + let mut offsets = self.offsets.clone(); + offsets.skip(R::Offset::from_u64( + u64::from(row) * u64::from(self.section_count) * 4, + )?)?; + let mut sizes = self.sizes.clone(); + sizes.skip(R::Offset::from_u64( + u64::from(row) * u64::from(self.section_count) * 4, + )?)?; + Ok(UnitIndexSectionIterator { + sections: self.sections[..self.section_count as usize].iter(), + offsets, + sizes, + }) + } + + /// Return the version. + /// + /// Defaults to 0 for empty sections. + pub fn version(&self) -> u16 { + self.version + } + + /// Return the number of sections. + pub fn section_count(&self) -> u32 { + self.section_count + } + + /// Return the number of units. + pub fn unit_count(&self) -> u32 { + self.unit_count + } + + /// Return the number of slots. + pub fn slot_count(&self) -> u32 { + self.slot_count + } +} + +/// An iterator over the section offsets and sizes for a row in a `UnitIndex`. +#[derive(Debug, Clone)] +pub struct UnitIndexSectionIterator<'index, R: Reader> { + sections: slice::Iter<'index, IndexSectionId>, + offsets: R, + sizes: R, +} + +impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> { + type Item = UnitIndexSection; + + fn next(&mut self) -> Option { + let section = *self.sections.next()?; + // The length of these arrays was validated in `UnitIndex::parse`. + let offset = self.offsets.read_u32().ok()?; + let size = self.sizes.read_u32().ok()?; + Some(UnitIndexSection { + section, + offset, + size, + }) + } +} + +/// Information about a unit's contribution to a section in a `.dwp` file. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UnitIndexSection { + /// The section kind. + pub section: IndexSectionId, + /// The base offset of the unit's contribution to the section. + pub offset: u32, + /// The size of the unit's contribution to the section. + pub size: u32, +} + +/// Section kinds which are permitted in a `.dwp` index. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IndexSectionId { + /// The `.debug_abbrev.dwo` section. + DebugAbbrev, + /// The `.debug_info.dwo` section. + DebugInfo, + /// The `.debug_line.dwo` section. + DebugLine, + /// The `.debug_loc.dwo` section. + DebugLoc, + /// The `.debug_loclists.dwo` section. + DebugLocLists, + /// The `.debug_macinfo.dwo` section. + DebugMacinfo, + /// The `.debug_macro.dwo` section. + DebugMacro, + /// The `.debug_rnglists.dwo` section. + DebugRngLists, + /// The `.debug_str_offsets.dwo` section. + DebugStrOffsets, + /// The `.debug_types.dwo` section. + DebugTypes, +} + +impl IndexSectionId { + /// Returns the corresponding `SectionId`. + pub fn section_id(self) -> SectionId { + match self { + IndexSectionId::DebugAbbrev => SectionId::DebugAbbrev, + IndexSectionId::DebugInfo => SectionId::DebugInfo, + IndexSectionId::DebugLine => SectionId::DebugLine, + IndexSectionId::DebugLoc => SectionId::DebugLoc, + IndexSectionId::DebugLocLists => SectionId::DebugLocLists, + IndexSectionId::DebugMacro => SectionId::DebugMacro, + IndexSectionId::DebugMacinfo => SectionId::DebugMacinfo, + IndexSectionId::DebugRngLists => SectionId::DebugRngLists, + IndexSectionId::DebugStrOffsets => SectionId::DebugStrOffsets, + IndexSectionId::DebugTypes => SectionId::DebugTypes, + } + } + + /// Returns the ELF section name for this kind, when found in a .dwo or .dwp file. + pub fn dwo_name(self) -> &'static str { + self.section_id().dwo_name().unwrap() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::endianity::BigEndian; + use test_assembler::{Endian, Section}; + + #[test] + fn test_empty() { + let buf = EndianSlice::new(&[], BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.version(), 0); + assert_eq!(index.unit_count(), 0); + assert_eq!(index.slot_count(), 0); + assert!(index.find(0).is_none()); + } + + #[test] + fn test_zero_slots() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D32(2).D32(0).D32(0).D32(0); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.version(), 2); + assert_eq!(index.unit_count(), 0); + assert_eq!(index.slot_count(), 0); + assert!(index.find(0).is_none()); + } + + #[test] + fn test_version_2() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D32(2).D32(0).D32(0).D32(1) + // Slots. + .D64(0).D32(0); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.version, 2); + } + + #[test] + fn test_version_5() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D16(5).D16(0).D32(0).D32(0).D32(1) + // Slots. + .D64(0).D32(0); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.version, 5); + } + + #[test] + fn test_version_5_invalid() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D32(5).D32(0).D32(0).D32(1) + // Slots. + .D64(0).D32(0); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + assert!(UnitIndex::parse(buf).is_err()); + } + + #[test] + fn test_version_2_sections() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D32(2).D32(8).D32(1).D32(2) + // Slots. + .D64(0).D64(0).D32(0).D32(0) + // Sections. + .D32(constants::DW_SECT_V2_INFO.0) + .D32(constants::DW_SECT_V2_TYPES.0) + .D32(constants::DW_SECT_V2_ABBREV.0) + .D32(constants::DW_SECT_V2_LINE.0) + .D32(constants::DW_SECT_V2_LOC.0) + .D32(constants::DW_SECT_V2_STR_OFFSETS.0) + .D32(constants::DW_SECT_V2_MACINFO.0) + .D32(constants::DW_SECT_V2_MACRO.0) + // Offsets. + .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18) + // Sizes. + .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27).D32(28); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.section_count, 8); + assert_eq!( + index.sections, + [ + IndexSectionId::DebugInfo, + IndexSectionId::DebugTypes, + IndexSectionId::DebugAbbrev, + IndexSectionId::DebugLine, + IndexSectionId::DebugLoc, + IndexSectionId::DebugStrOffsets, + IndexSectionId::DebugMacinfo, + IndexSectionId::DebugMacro, + ] + ); + #[rustfmt::skip] + let expect = [ + UnitIndexSection { section: IndexSectionId::DebugInfo, offset: 11, size: 21 }, + UnitIndexSection { section: IndexSectionId::DebugTypes, offset: 12, size: 22 }, + UnitIndexSection { section: IndexSectionId::DebugAbbrev, offset: 13, size: 23 }, + UnitIndexSection { section: IndexSectionId::DebugLine, offset: 14, size: 24 }, + UnitIndexSection { section: IndexSectionId::DebugLoc, offset: 15, size: 25 }, + UnitIndexSection { section: IndexSectionId::DebugStrOffsets, offset: 16, size: 26 }, + UnitIndexSection { section: IndexSectionId::DebugMacinfo, offset: 17, size: 27 }, + UnitIndexSection { section: IndexSectionId::DebugMacro, offset: 18, size: 28 }, + ]; + let mut sections = index.sections(1).unwrap(); + for section in &expect { + assert_eq!(*section, sections.next().unwrap()); + } + assert!(sections.next().is_none()); + } + + #[test] + fn test_version_5_sections() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D16(5).D16(0).D32(7).D32(1).D32(2) + // Slots. + .D64(0).D64(0).D32(0).D32(0) + // Sections. + .D32(constants::DW_SECT_INFO.0) + .D32(constants::DW_SECT_ABBREV.0) + .D32(constants::DW_SECT_LINE.0) + .D32(constants::DW_SECT_LOCLISTS.0) + .D32(constants::DW_SECT_STR_OFFSETS.0) + .D32(constants::DW_SECT_MACRO.0) + .D32(constants::DW_SECT_RNGLISTS.0) + // Offsets. + .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17) + // Sizes. + .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.section_count, 7); + assert_eq!( + index.sections[..7], + [ + IndexSectionId::DebugInfo, + IndexSectionId::DebugAbbrev, + IndexSectionId::DebugLine, + IndexSectionId::DebugLocLists, + IndexSectionId::DebugStrOffsets, + IndexSectionId::DebugMacro, + IndexSectionId::DebugRngLists, + ] + ); + #[rustfmt::skip] + let expect = [ + UnitIndexSection { section: IndexSectionId::DebugInfo, offset: 11, size: 21 }, + UnitIndexSection { section: IndexSectionId::DebugAbbrev, offset: 12, size: 22 }, + UnitIndexSection { section: IndexSectionId::DebugLine, offset: 13, size: 23 }, + UnitIndexSection { section: IndexSectionId::DebugLocLists, offset: 14, size: 24 }, + UnitIndexSection { section: IndexSectionId::DebugStrOffsets, offset: 15, size: 25 }, + UnitIndexSection { section: IndexSectionId::DebugMacro, offset: 16, size: 26 }, + UnitIndexSection { section: IndexSectionId::DebugRngLists, offset: 17, size: 27 }, + ]; + let mut sections = index.sections(1).unwrap(); + for section in &expect { + assert_eq!(*section, sections.next().unwrap()); + } + assert!(sections.next().is_none()); + + assert!(index.sections(0).is_err()); + assert!(index.sections(2).is_err()); + } + + #[test] + fn test_hash() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D16(5).D16(0).D32(2).D32(3).D32(4) + // Slots. + .D64(0xffff_fff2_ffff_fff1) + .D64(0xffff_fff0_ffff_fff1) + .D64(0xffff_fff1_ffff_fff1) + .D64(0) + .D32(3).D32(1).D32(2).D32(0) + // Sections. + .D32(constants::DW_SECT_INFO.0) + .D32(constants::DW_SECT_ABBREV.0) + // Offsets. + .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0) + // Sizes. + .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0); + let buf = section.get_contents().unwrap(); + let buf = EndianSlice::new(&buf, BigEndian); + let index = UnitIndex::parse(buf).unwrap(); + assert_eq!(index.version(), 5); + assert_eq!(index.slot_count(), 4); + assert_eq!(index.unit_count(), 3); + assert_eq!(index.section_count(), 2); + assert_eq!(index.find(0xffff_fff0_ffff_fff1), Some(1)); + assert_eq!(index.find(0xffff_fff1_ffff_fff1), Some(2)); + assert_eq!(index.find(0xffff_fff2_ffff_fff1), Some(3)); + assert_eq!(index.find(0xffff_fff3_ffff_fff1), None); + } + + #[test] + fn test_cu_index() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D16(5).D16(0).D32(0).D32(0).D32(1) + // Slots. + .D64(0).D32(0); + let buf = section.get_contents().unwrap(); + let cu_index = DebugCuIndex::new(&buf, BigEndian); + let index = cu_index.index().unwrap(); + assert_eq!(index.version, 5); + } + + #[test] + fn test_tu_index() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Big) + // Header. + .D16(5).D16(0).D32(0).D32(0).D32(1) + // Slots. + .D64(0).D32(0); + let buf = section.get_contents().unwrap(); + let tu_index = DebugTuIndex::new(&buf, BigEndian); + let index = tu_index.index().unwrap(); + assert_eq!(index.version, 5); + } +} diff --git a/deps/crates/vendor/gimli/src/read/line.rs b/deps/crates/vendor/gimli/src/read/line.rs new file mode 100644 index 00000000000000..3fcf2efdecea73 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/line.rs @@ -0,0 +1,3185 @@ +use alloc::vec::Vec; +use core::num::{NonZeroU64, Wrapping}; + +use crate::common::{ + DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format, + LineEncoding, SectionId, +}; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::{ + AttributeValue, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, Result, Section, +}; + +/// The `DebugLine` struct contains the source location to instruction mapping +/// found in the `.debug_line` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugLine { + debug_line_section: R, +} + +impl<'input, Endian> DebugLine> +where + Endian: Endianity, +{ + /// Construct a new `DebugLine` instance from the data in the `.debug_line` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_line` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugLine, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_line_section_somehow = || &buf; + /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_line_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_line_section, endian)) + } +} + +impl DebugLine { + /// Parse the line number program whose header is at the given `offset` in the + /// `.debug_line` section. + /// + /// The `address_size` must match the compilation unit that the lines apply to. + /// The `comp_dir` should be from the `DW_AT_comp_dir` attribute of the compilation + /// unit. The `comp_name` should be from the `DW_AT_name` attribute of the + /// compilation unit. + /// + /// ```rust,no_run + /// use gimli::{DebugLine, DebugLineOffset, IncompleteLineProgram, EndianSlice, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_line_section_somehow = || &buf; + /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); + /// + /// // In a real example, we'd grab the offset via a compilation unit + /// // entry's `DW_AT_stmt_list` attribute, and the address size from that + /// // unit directly. + /// let offset = DebugLineOffset(0); + /// let address_size = 8; + /// + /// let program = debug_line.program(offset, address_size, None, None) + /// .expect("should have found a header at that offset, and parsed it OK"); + /// ``` + pub fn program( + &self, + offset: DebugLineOffset, + address_size: u8, + comp_dir: Option, + comp_name: Option, + ) -> Result> { + let input = &mut self.debug_line_section.clone(); + input.skip(offset.0)?; + let header = LineProgramHeader::parse(input, offset, address_size, comp_dir, comp_name)?; + let program = IncompleteLineProgram { header }; + Ok(program) + } +} + +impl DebugLine { + /// Create a `DebugLine` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLine + where + F: FnMut(&'a T) -> R, + { + borrow(&self.debug_line_section).into() + } +} + +impl Section for DebugLine { + fn id() -> SectionId { + SectionId::DebugLine + } + + fn reader(&self) -> &R { + &self.debug_line_section + } +} + +impl From for DebugLine { + fn from(debug_line_section: R) -> Self { + DebugLine { debug_line_section } + } +} + +/// Deprecated. `LineNumberProgram` has been renamed to `LineProgram`. +#[deprecated(note = "LineNumberProgram has been renamed to LineProgram, use that instead.")] +pub type LineNumberProgram = dyn LineProgram; + +/// A `LineProgram` provides access to a `LineProgramHeader` and +/// a way to add files to the files table if necessary. Gimli consumers should +/// never need to use or see this trait. +pub trait LineProgram::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// Get a reference to the held `LineProgramHeader`. + fn header(&self) -> &LineProgramHeader; + /// Add a file to the file table if necessary. + fn add_file(&mut self, file: FileEntry); +} + +impl LineProgram for IncompleteLineProgram +where + R: Reader, + Offset: ReaderOffset, +{ + fn header(&self) -> &LineProgramHeader { + &self.header + } + fn add_file(&mut self, file: FileEntry) { + self.header.file_names.push(file); + } +} + +impl<'program, R, Offset> LineProgram for &'program CompleteLineProgram +where + R: Reader, + Offset: ReaderOffset, +{ + fn header(&self) -> &LineProgramHeader { + &self.header + } + fn add_file(&mut self, _: FileEntry) { + // Nop. Our file table is already complete. + } +} + +/// Deprecated. `StateMachine` has been renamed to `LineRows`. +#[deprecated(note = "StateMachine has been renamed to LineRows, use that instead.")] +pub type StateMachine = LineRows; + +/// Executes a `LineProgram` to iterate over the rows in the matrix of line number information. +/// +/// "The hypothetical machine used by a consumer of the line number information +/// to expand the byte-coded instruction stream into a matrix of line number +/// information." -- Section 6.2.1 +#[derive(Debug, Clone)] +pub struct LineRows::Offset> +where + Program: LineProgram, + R: Reader, + Offset: ReaderOffset, +{ + program: Program, + row: LineRow, + instructions: LineInstructions, +} + +type OneShotLineRows::Offset> = + LineRows, Offset>; + +type ResumedLineRows<'program, R, Offset = ::Offset> = + LineRows, Offset>; + +impl LineRows +where + Program: LineProgram, + R: Reader, + Offset: ReaderOffset, +{ + fn new(program: IncompleteLineProgram) -> OneShotLineRows { + let row = LineRow::new(program.header()); + let instructions = LineInstructions { + input: program.header().program_buf.clone(), + }; + LineRows { + program, + row, + instructions, + } + } + + fn resume<'program>( + program: &'program CompleteLineProgram, + sequence: &LineSequence, + ) -> ResumedLineRows<'program, R, Offset> { + let row = LineRow::new(program.header()); + let instructions = sequence.instructions.clone(); + LineRows { + program, + row, + instructions, + } + } + + /// Get a reference to the header for this state machine's line number + /// program. + #[inline] + pub fn header(&self) -> &LineProgramHeader { + self.program.header() + } + + /// Parse and execute the next instructions in the line number program until + /// another row in the line number matrix is computed. + /// + /// The freshly computed row is returned as `Ok(Some((header, row)))`. + /// If the matrix is complete, and there are no more new rows in the line + /// number matrix, then `Ok(None)` is returned. If there was an error parsing + /// an instruction, then `Err(e)` is returned. + /// + /// Unfortunately, the references mean that this cannot be a + /// `FallibleIterator`. + pub fn next_row(&mut self) -> Result, &LineRow)>> { + // Perform any reset that was required after copying the previous row. + self.row.reset(self.program.header()); + + loop { + // Split the borrow here, rather than calling `self.header()`. + match self.instructions.next_instruction(self.program.header()) { + Err(err) => return Err(err), + Ok(None) => return Ok(None), + Ok(Some(instruction)) => { + if self.row.execute(instruction, &mut self.program)? { + if self.row.tombstone { + // Perform any reset that was required for the tombstone row. + // Normally this is done when `next_row` is called again, but for + // tombstones we loop immediately. + self.row.reset(self.program.header()); + } else { + return Ok(Some((self.header(), &self.row))); + } + } + // Fall through, parse the next instruction, and see if that + // yields a row. + } + } + } + } +} + +/// Deprecated. `Opcode` has been renamed to `LineInstruction`. +#[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")] +pub type Opcode = LineInstruction::Offset>; + +/// A parsed line number program instruction. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LineInstruction::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// > ### 6.2.5.1 Special Opcodes + /// > + /// > Each ubyte special opcode has the following effect on the state machine: + /// > + /// > 1. Add a signed integer to the line register. + /// > + /// > 2. Modify the operation pointer by incrementing the address and + /// > op_index registers as described below. + /// > + /// > 3. Append a row to the matrix using the current values of the state + /// > machine registers. + /// > + /// > 4. Set the basic_block register to “false.” + /// > + /// > 5. Set the prologue_end register to “false.” + /// > + /// > 6. Set the epilogue_begin register to “false.” + /// > + /// > 7. Set the discriminator register to 0. + /// > + /// > All of the special opcodes do those same seven things; they differ from + /// > one another only in what values they add to the line, address and + /// > op_index registers. + Special(u8), + + /// "[`LineInstruction::Copy`] appends a row to the matrix using the current + /// values of the state machine registers. Then it sets the discriminator + /// register to 0, and sets the basic_block, prologue_end and epilogue_begin + /// registers to “false.”" + Copy, + + /// "The DW_LNS_advance_pc opcode takes a single unsigned LEB128 operand as + /// the operation advance and modifies the address and op_index registers + /// [the same as `LineInstruction::Special`]" + AdvancePc(u64), + + /// "The DW_LNS_advance_line opcode takes a single signed LEB128 operand and + /// adds that value to the line register of the state machine." + AdvanceLine(i64), + + /// "The DW_LNS_set_file opcode takes a single unsigned LEB128 operand and + /// stores it in the file register of the state machine." + SetFile(u64), + + /// "The DW_LNS_set_column opcode takes a single unsigned LEB128 operand and + /// stores it in the column register of the state machine." + SetColumn(u64), + + /// "The DW_LNS_negate_stmt opcode takes no operands. It sets the is_stmt + /// register of the state machine to the logical negation of its current + /// value." + NegateStatement, + + /// "The DW_LNS_set_basic_block opcode takes no operands. It sets the + /// basic_block register of the state machine to “true.”" + SetBasicBlock, + + /// > The DW_LNS_const_add_pc opcode takes no operands. It advances the + /// > address and op_index registers by the increments corresponding to + /// > special opcode 255. + /// > + /// > When the line number program needs to advance the address by a small + /// > amount, it can use a single special opcode, which occupies a single + /// > byte. When it needs to advance the address by up to twice the range of + /// > the last special opcode, it can use DW_LNS_const_add_pc followed by a + /// > special opcode, for a total of two bytes. Only if it needs to advance + /// > the address by more than twice that range will it need to use both + /// > DW_LNS_advance_pc and a special opcode, requiring three or more bytes. + ConstAddPc, + + /// > The DW_LNS_fixed_advance_pc opcode takes a single uhalf (unencoded) + /// > operand and adds it to the address register of the state machine and + /// > sets the op_index register to 0. This is the only standard opcode whose + /// > operand is not a variable length number. It also does not multiply the + /// > operand by the minimum_instruction_length field of the header. + FixedAddPc(u16), + + /// "[`LineInstruction::SetPrologueEnd`] sets the prologue_end register to “true”." + SetPrologueEnd, + + /// "[`LineInstruction::SetEpilogueBegin`] sets the epilogue_begin register to + /// “true”." + SetEpilogueBegin, + + /// "The DW_LNS_set_isa opcode takes a single unsigned LEB128 operand and + /// stores that value in the isa register of the state machine." + SetIsa(u64), + + /// An unknown standard opcode with zero operands. + UnknownStandard0(constants::DwLns), + + /// An unknown standard opcode with one operand. + UnknownStandard1(constants::DwLns, u64), + + /// An unknown standard opcode with multiple operands. + UnknownStandardN(constants::DwLns, R), + + /// > [`LineInstruction::EndSequence`] sets the end_sequence register of the state + /// > machine to “true” and appends a row to the matrix using the current + /// > values of the state-machine registers. Then it resets the registers to + /// > the initial values specified above (see Section 6.2.2). Every line + /// > number program sequence must end with a DW_LNE_end_sequence instruction + /// > which creates a row whose address is that of the byte after the last + /// > target machine instruction of the sequence. + EndSequence, + + /// > The DW_LNE_set_address opcode takes a single relocatable address as an + /// > operand. The size of the operand is the size of an address on the target + /// > machine. It sets the address register to the value given by the + /// > relocatable address and sets the op_index register to 0. + /// > + /// > All of the other line number program opcodes that affect the address + /// > register add a delta to it. This instruction stores a relocatable value + /// > into it instead. + SetAddress(u64), + + /// Defines a new source file in the line number program and appends it to + /// the line number program header's list of source files. + DefineFile(FileEntry), + + /// "The DW_LNE_set_discriminator opcode takes a single parameter, an + /// unsigned LEB128 integer. It sets the discriminator register to the new + /// value." + SetDiscriminator(u64), + + /// An unknown extended opcode and the slice of its unparsed operands. + UnknownExtended(constants::DwLne, R), +} + +impl LineInstruction +where + R: Reader, + Offset: ReaderOffset, +{ + fn parse<'header>( + header: &'header LineProgramHeader, + input: &mut R, + ) -> Result> + where + R: 'header, + { + let opcode = input.read_u8()?; + if opcode == 0 { + let length = input.read_uleb128().and_then(R::Offset::from_u64)?; + let mut instr_rest = input.split(length)?; + let opcode = instr_rest.read_u8()?; + + match constants::DwLne(opcode) { + constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence), + + constants::DW_LNE_set_address => { + let address = instr_rest.read_address(header.address_size())?; + Ok(LineInstruction::SetAddress(address)) + } + + constants::DW_LNE_define_file => { + if header.version() <= 4 { + let path_name = instr_rest.read_null_terminated_slice()?; + let entry = FileEntry::parse(&mut instr_rest, path_name)?; + Ok(LineInstruction::DefineFile(entry)) + } else { + Ok(LineInstruction::UnknownExtended( + constants::DW_LNE_define_file, + instr_rest, + )) + } + } + + constants::DW_LNE_set_discriminator => { + let discriminator = instr_rest.read_uleb128()?; + Ok(LineInstruction::SetDiscriminator(discriminator)) + } + + otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)), + } + } else if opcode >= header.opcode_base { + Ok(LineInstruction::Special(opcode)) + } else { + match constants::DwLns(opcode) { + constants::DW_LNS_copy => Ok(LineInstruction::Copy), + + constants::DW_LNS_advance_pc => { + let advance = input.read_uleb128()?; + Ok(LineInstruction::AdvancePc(advance)) + } + + constants::DW_LNS_advance_line => { + let increment = input.read_sleb128()?; + Ok(LineInstruction::AdvanceLine(increment)) + } + + constants::DW_LNS_set_file => { + let file = input.read_uleb128()?; + Ok(LineInstruction::SetFile(file)) + } + + constants::DW_LNS_set_column => { + let column = input.read_uleb128()?; + Ok(LineInstruction::SetColumn(column)) + } + + constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement), + + constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock), + + constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc), + + constants::DW_LNS_fixed_advance_pc => { + let advance = input.read_u16()?; + Ok(LineInstruction::FixedAddPc(advance)) + } + + constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd), + + constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin), + + constants::DW_LNS_set_isa => { + let isa = input.read_uleb128()?; + Ok(LineInstruction::SetIsa(isa)) + } + + otherwise => { + let mut opcode_lengths = header.standard_opcode_lengths().clone(); + opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?; + let num_args = opcode_lengths.read_u8()? as usize; + match num_args { + 0 => Ok(LineInstruction::UnknownStandard0(otherwise)), + 1 => { + let arg = input.read_uleb128()?; + Ok(LineInstruction::UnknownStandard1(otherwise, arg)) + } + _ => { + let mut args = input.clone(); + for _ in 0..num_args { + input.read_uleb128()?; + } + let len = input.offset_from(&args); + args.truncate(len)?; + Ok(LineInstruction::UnknownStandardN(otherwise, args)) + } + } + } + } + } + } +} + +/// Deprecated. `OpcodesIter` has been renamed to `LineInstructions`. +#[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")] +pub type OpcodesIter = LineInstructions; + +/// An iterator yielding parsed instructions. +/// +/// See +/// [`LineProgramHeader::instructions`](./struct.LineProgramHeader.html#method.instructions) +/// for more details. +#[derive(Clone, Debug)] +pub struct LineInstructions { + input: R, +} + +impl LineInstructions { + fn remove_trailing(&self, other: &LineInstructions) -> Result> { + let offset = other.input.offset_from(&self.input); + let mut input = self.input.clone(); + input.truncate(offset)?; + Ok(LineInstructions { input }) + } +} + +impl LineInstructions { + /// Advance the iterator and return the next instruction. + /// + /// Returns the newly parsed instruction as `Ok(Some(instruction))`. Returns + /// `Ok(None)` when iteration is complete and all instructions have already been + /// parsed and yielded. If an error occurs while parsing the next attribute, + /// then this error is returned as `Err(e)`, and all subsequent calls return + /// `Ok(None)`. + /// + /// Unfortunately, the `header` parameter means that this cannot be a + /// `FallibleIterator`. + #[inline(always)] + pub fn next_instruction( + &mut self, + header: &LineProgramHeader, + ) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + match LineInstruction::parse(header, &mut self.input) { + Ok(instruction) => Ok(Some(instruction)), + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +/// Deprecated. `LineNumberRow` has been renamed to `LineRow`. +#[deprecated(note = "LineNumberRow has been renamed to LineRow, use that instead.")] +pub type LineNumberRow = LineRow; + +/// A row in the line number program's resulting matrix. +/// +/// Each row is a copy of the registers of the state machine, as defined in section 6.2.2. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LineRow { + tombstone: bool, + address: u64, + op_index: Wrapping, + file: u64, + line: Wrapping, + column: u64, + is_stmt: bool, + basic_block: bool, + end_sequence: bool, + prologue_end: bool, + epilogue_begin: bool, + isa: u64, + discriminator: u64, +} + +impl LineRow { + /// Create a line number row in the initial state for the given program. + pub fn new(header: &LineProgramHeader) -> Self { + LineRow { + // "At the beginning of each sequence within a line number program, the + // state of the registers is:" -- Section 6.2.2 + tombstone: false, + address: 0, + op_index: Wrapping(0), + file: 1, + line: Wrapping(1), + column: 0, + // "determined by default_is_stmt in the line number program header" + is_stmt: header.line_encoding.default_is_stmt, + basic_block: false, + end_sequence: false, + prologue_end: false, + epilogue_begin: false, + // "The isa value 0 specifies that the instruction set is the + // architecturally determined default instruction set. This may be fixed + // by the ABI, or it may be specified by other means, for example, by + // the object file description." + isa: 0, + discriminator: 0, + } + } + + /// "The program-counter value corresponding to a machine instruction + /// generated by the compiler." + #[inline] + pub fn address(&self) -> u64 { + self.address + } + + /// > An unsigned integer representing the index of an operation within a VLIW + /// > instruction. The index of the first operation is 0. For non-VLIW + /// > architectures, this register will always be 0. + /// > + /// > The address and op_index registers, taken together, form an operation + /// > pointer that can reference any individual operation with the + /// > instruction stream. + #[inline] + pub fn op_index(&self) -> u64 { + self.op_index.0 + } + + /// "An unsigned integer indicating the identity of the source file + /// corresponding to a machine instruction." + #[inline] + pub fn file_index(&self) -> u64 { + self.file + } + + /// The source file corresponding to the current machine instruction. + #[inline] + pub fn file<'header, R: Reader>( + &self, + header: &'header LineProgramHeader, + ) -> Option<&'header FileEntry> { + header.file(self.file) + } + + /// "An unsigned integer indicating a source line number. Lines are numbered + /// beginning at 1. The compiler may emit the value 0 in cases where an + /// instruction cannot be attributed to any source line." + /// Line number values of 0 are represented as `None`. + #[inline] + pub fn line(&self) -> Option { + NonZeroU64::new(self.line.0) + } + + /// "An unsigned integer indicating a column number within a source + /// line. Columns are numbered beginning at 1. The value 0 is reserved to + /// indicate that a statement begins at the “left edge” of the line." + #[inline] + pub fn column(&self) -> ColumnType { + NonZeroU64::new(self.column) + .map(ColumnType::Column) + .unwrap_or(ColumnType::LeftEdge) + } + + /// "A boolean indicating that the current instruction is a recommended + /// breakpoint location. A recommended breakpoint location is intended to + /// “represent” a line, a statement and/or a semantically distinct subpart + /// of a statement." + #[inline] + pub fn is_stmt(&self) -> bool { + self.is_stmt + } + + /// "A boolean indicating that the current instruction is the beginning of a + /// basic block." + #[inline] + pub fn basic_block(&self) -> bool { + self.basic_block + } + + /// "A boolean indicating that the current address is that of the first byte + /// after the end of a sequence of target machine instructions. end_sequence + /// terminates a sequence of lines; therefore other information in the same + /// row is not meaningful." + #[inline] + pub fn end_sequence(&self) -> bool { + self.end_sequence + } + + /// "A boolean indicating that the current address is one (of possibly many) + /// where execution should be suspended for an entry breakpoint of a + /// function." + #[inline] + pub fn prologue_end(&self) -> bool { + self.prologue_end + } + + /// "A boolean indicating that the current address is one (of possibly many) + /// where execution should be suspended for an exit breakpoint of a + /// function." + #[inline] + pub fn epilogue_begin(&self) -> bool { + self.epilogue_begin + } + + /// Tag for the current instruction set architecture. + /// + /// > An unsigned integer whose value encodes the applicable instruction set + /// > architecture for the current instruction. + /// > + /// > The encoding of instruction sets should be shared by all users of a + /// > given architecture. It is recommended that this encoding be defined by + /// > the ABI authoring committee for each architecture. + #[inline] + pub fn isa(&self) -> u64 { + self.isa + } + + /// "An unsigned integer identifying the block to which the current + /// instruction belongs. Discriminator values are assigned arbitrarily by + /// the DWARF producer and serve to distinguish among multiple blocks that + /// may all be associated with the same source file, line, and column. Where + /// only one block exists for a given source position, the discriminator + /// value should be zero." + #[inline] + pub fn discriminator(&self) -> u64 { + self.discriminator + } + + /// Execute the given instruction, and return true if a new row in the + /// line number matrix needs to be generated. + /// + /// Unknown opcodes are treated as no-ops. + #[inline] + pub fn execute( + &mut self, + instruction: LineInstruction, + program: &mut Program, + ) -> Result + where + Program: LineProgram, + R: Reader, + { + Ok(match instruction { + LineInstruction::Special(opcode) => { + self.exec_special_opcode(opcode, program.header())?; + true + } + + LineInstruction::Copy => true, + + LineInstruction::AdvancePc(operation_advance) => { + self.apply_operation_advance(operation_advance, program.header())?; + false + } + + LineInstruction::AdvanceLine(line_increment) => { + self.apply_line_advance(line_increment); + false + } + + LineInstruction::SetFile(file) => { + self.file = file; + false + } + + LineInstruction::SetColumn(column) => { + self.column = column; + false + } + + LineInstruction::NegateStatement => { + self.is_stmt = !self.is_stmt; + false + } + + LineInstruction::SetBasicBlock => { + self.basic_block = true; + false + } + + LineInstruction::ConstAddPc => { + let adjusted = self.adjust_opcode(255, program.header()); + let operation_advance = adjusted / program.header().line_encoding.line_range; + self.apply_operation_advance(u64::from(operation_advance), program.header())?; + false + } + + LineInstruction::FixedAddPc(operand) => { + if !self.tombstone { + let address_size = program.header().address_size(); + self.address = self.address.add_sized(u64::from(operand), address_size)?; + self.op_index.0 = 0; + } + false + } + + LineInstruction::SetPrologueEnd => { + self.prologue_end = true; + false + } + + LineInstruction::SetEpilogueBegin => { + self.epilogue_begin = true; + false + } + + LineInstruction::SetIsa(isa) => { + self.isa = isa; + false + } + + LineInstruction::EndSequence => { + self.end_sequence = true; + true + } + + LineInstruction::SetAddress(address) => { + // If the address is a tombstone, then skip instructions until the next address. + // DWARF specifies a tombstone value of -1, but many linkers use 0. + // However, 0 may be a valid address, so we only skip that if we have previously + // seen a higher address. Additionally, gold may keep the relocation addend, + // so we treat all lower addresses as tombstones instead of just 0. + // This works because DWARF specifies that addresses are monotonically increasing + // within a sequence; the alternative is to return an error. + let tombstone_address = !0 >> (64 - program.header().encoding.address_size * 8); + self.tombstone = address < self.address || address == tombstone_address; + if !self.tombstone { + self.address = address; + self.op_index.0 = 0; + } + false + } + + LineInstruction::DefineFile(entry) => { + program.add_file(entry); + false + } + + LineInstruction::SetDiscriminator(discriminator) => { + self.discriminator = discriminator; + false + } + + // Compatibility with future opcodes. + LineInstruction::UnknownStandard0(_) + | LineInstruction::UnknownStandard1(_, _) + | LineInstruction::UnknownStandardN(_, _) + | LineInstruction::UnknownExtended(_, _) => false, + }) + } + + /// Perform any reset that was required after copying the previous row. + #[inline] + pub fn reset(&mut self, header: &LineProgramHeader) { + if self.end_sequence { + // Previous instruction was EndSequence, so reset everything + // as specified in Section 6.2.5.3. + *self = Self::new(header); + } else { + // Previous instruction was one of: + // - Special - specified in Section 6.2.5.1, steps 4-7 + // - Copy - specified in Section 6.2.5.2 + // The reset behaviour is the same in both cases. + self.discriminator = 0; + self.basic_block = false; + self.prologue_end = false; + self.epilogue_begin = false; + } + } + + /// Step 1 of section 6.2.5.1 + fn apply_line_advance(&mut self, line_increment: i64) { + if line_increment < 0 { + let decrement = -line_increment as u64; + if decrement <= self.line.0 { + self.line.0 -= decrement; + } else { + self.line.0 = 0; + } + } else { + self.line += Wrapping(line_increment as u64); + } + } + + /// Step 2 of section 6.2.5.1 + fn apply_operation_advance( + &mut self, + operation_advance: u64, + header: &LineProgramHeader, + ) -> Result<()> { + if self.tombstone { + return Ok(()); + } + + let operation_advance = Wrapping(operation_advance); + + let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length); + let minimum_instruction_length = Wrapping(minimum_instruction_length); + + let maximum_operations_per_instruction = + u64::from(header.line_encoding.maximum_operations_per_instruction); + let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction); + + let address_advance = if maximum_operations_per_instruction.0 == 1 { + self.op_index.0 = 0; + minimum_instruction_length * operation_advance + } else { + let op_index_with_advance = self.op_index + operation_advance; + self.op_index = op_index_with_advance % maximum_operations_per_instruction; + minimum_instruction_length + * (op_index_with_advance / maximum_operations_per_instruction) + }; + self.address = self + .address + .add_sized(address_advance.0, header.address_size())?; + Ok(()) + } + + #[inline] + fn adjust_opcode(&self, opcode: u8, header: &LineProgramHeader) -> u8 { + opcode - header.opcode_base + } + + /// Section 6.2.5.1 + fn exec_special_opcode( + &mut self, + opcode: u8, + header: &LineProgramHeader, + ) -> Result<()> { + let adjusted_opcode = self.adjust_opcode(opcode, header); + + let line_range = header.line_encoding.line_range; + let line_advance = adjusted_opcode % line_range; + let operation_advance = adjusted_opcode / line_range; + + // Step 1 + let line_base = i64::from(header.line_encoding.line_base); + self.apply_line_advance(line_base + i64::from(line_advance)); + + // Step 2 + self.apply_operation_advance(u64::from(operation_advance), header)?; + Ok(()) + } +} + +/// The type of column that a row is referring to. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ColumnType { + /// The `LeftEdge` means that the statement begins at the start of the new + /// line. + LeftEdge, + /// A column number, whose range begins at 1. + Column(NonZeroU64), +} + +/// Deprecated. `LineNumberSequence` has been renamed to `LineSequence`. +#[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")] +pub type LineNumberSequence = LineSequence; + +/// A sequence within a line number program. A sequence, as defined in section +/// 6.2.5 of the standard, is a linear subset of a line number program within +/// which addresses are monotonically increasing. +#[derive(Clone, Debug)] +pub struct LineSequence { + /// The first address that is covered by this sequence within the line number + /// program. + pub start: u64, + /// The first address that is *not* covered by this sequence within the line + /// number program. + pub end: u64, + instructions: LineInstructions, +} + +/// Deprecated. `LineNumberProgramHeader` has been renamed to `LineProgramHeader`. +#[deprecated( + note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead." +)] +pub type LineNumberProgramHeader = LineProgramHeader; + +/// A header for a line number program in the `.debug_line` section, as defined +/// in section 6.2.4 of the standard. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LineProgramHeader::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + encoding: Encoding, + offset: DebugLineOffset, + unit_length: Offset, + + header_length: Offset, + + line_encoding: LineEncoding, + + /// "The number assigned to the first special opcode." + opcode_base: u8, + + /// "This array specifies the number of LEB128 operands for each of the + /// standard opcodes. The first element of the array corresponds to the + /// opcode whose value is 1, and the last element corresponds to the opcode + /// whose value is `opcode_base - 1`." + standard_opcode_lengths: R, + + /// "A sequence of directory entry format descriptions." + directory_entry_format: Vec, + + /// > Entries in this sequence describe each path that was searched for + /// > included source files in this compilation. (The paths include those + /// > directories specified explicitly by the user for the compiler to search + /// > and those the compiler searches without explicit direction.) Each path + /// > entry is either a full path name or is relative to the current directory + /// > of the compilation. + /// > + /// > The last entry is followed by a single null byte. + include_directories: Vec>, + + /// "A sequence of file entry format descriptions." + file_name_entry_format: Vec, + + /// "Entries in this sequence describe source files that contribute to the + /// line number information for this compilation unit or is used in other + /// contexts." + file_names: Vec>, + + /// The encoded line program instructions. + program_buf: R, + + /// The current directory of the compilation. + comp_dir: Option, + + /// The primary source file. + comp_file: Option>, +} + +impl LineProgramHeader +where + R: Reader, + Offset: ReaderOffset, +{ + /// Return the offset of the line number program header in the `.debug_line` section. + pub fn offset(&self) -> DebugLineOffset { + self.offset + } + + /// Return the length of the line number program and header, not including + /// the length of the encoded length itself. + pub fn unit_length(&self) -> R::Offset { + self.unit_length + } + + /// Return the encoding parameters for this header's line program. + pub fn encoding(&self) -> Encoding { + self.encoding + } + + /// Get the version of this header's line program. + pub fn version(&self) -> u16 { + self.encoding.version + } + + /// Get the length of the encoded line number program header, not including + /// the length of the encoded length itself. + pub fn header_length(&self) -> R::Offset { + self.header_length + } + + /// Get the size in bytes of a target machine address. + pub fn address_size(&self) -> u8 { + self.encoding.address_size + } + + /// Whether this line program is encoded in 64- or 32-bit DWARF. + pub fn format(&self) -> Format { + self.encoding.format + } + + /// Get the line encoding parameters for this header's line program. + pub fn line_encoding(&self) -> LineEncoding { + self.line_encoding + } + + /// Get the minimum instruction length any instruction in this header's line + /// program may have. + pub fn minimum_instruction_length(&self) -> u8 { + self.line_encoding.minimum_instruction_length + } + + /// Get the maximum number of operations each instruction in this header's + /// line program may have. + pub fn maximum_operations_per_instruction(&self) -> u8 { + self.line_encoding.maximum_operations_per_instruction + } + + /// Get the default value of the `is_stmt` register for this header's line + /// program. + pub fn default_is_stmt(&self) -> bool { + self.line_encoding.default_is_stmt + } + + /// Get the line base for this header's line program. + pub fn line_base(&self) -> i8 { + self.line_encoding.line_base + } + + /// Get the line range for this header's line program. + pub fn line_range(&self) -> u8 { + self.line_encoding.line_range + } + + /// Get opcode base for this header's line program. + pub fn opcode_base(&self) -> u8 { + self.opcode_base + } + + /// An array of `u8` that specifies the number of LEB128 operands for + /// each of the standard opcodes. + pub fn standard_opcode_lengths(&self) -> &R { + &self.standard_opcode_lengths + } + + /// Get the format of a directory entry. + pub fn directory_entry_format(&self) -> &[FileEntryFormat] { + &self.directory_entry_format[..] + } + + /// Get the set of include directories for this header's line program. + /// + /// For DWARF version <= 4, the compilation's current directory is not included + /// in the return value, but is implicitly considered to be in the set per spec. + pub fn include_directories(&self) -> &[AttributeValue] { + &self.include_directories[..] + } + + /// The include directory with the given directory index. + /// + /// A directory index of 0 corresponds to the compilation unit directory. + pub fn directory(&self, directory: u64) -> Option> { + if self.encoding.version <= 4 { + if directory == 0 { + self.comp_dir.clone().map(AttributeValue::String) + } else { + let directory = directory as usize - 1; + self.include_directories.get(directory).cloned() + } + } else { + self.include_directories.get(directory as usize).cloned() + } + } + + /// Get the format of a file name entry. + pub fn file_name_entry_format(&self) -> &[FileEntryFormat] { + &self.file_name_entry_format[..] + } + + /// Return true if the file entries may have valid timestamps. + /// + /// Only returns false if we definitely know that all timestamp fields + /// are invalid. + pub fn file_has_timestamp(&self) -> bool { + self.encoding.version <= 4 + || self + .file_name_entry_format + .iter() + .any(|x| x.content_type == constants::DW_LNCT_timestamp) + } + + /// Return true if the file entries may have valid sizes. + /// + /// Only returns false if we definitely know that all size fields + /// are invalid. + pub fn file_has_size(&self) -> bool { + self.encoding.version <= 4 + || self + .file_name_entry_format + .iter() + .any(|x| x.content_type == constants::DW_LNCT_size) + } + + /// Return true if the file name entry format contains an MD5 field. + pub fn file_has_md5(&self) -> bool { + self.file_name_entry_format + .iter() + .any(|x| x.content_type == constants::DW_LNCT_MD5) + } + + /// Return true if the file name entry format contains a source field. + pub fn file_has_source(&self) -> bool { + self.file_name_entry_format + .iter() + .any(|x| x.content_type == constants::DW_LNCT_LLVM_source) + } + + /// Get the list of source files that appear in this header's line program. + pub fn file_names(&self) -> &[FileEntry] { + &self.file_names[..] + } + + /// The source file with the given file index. + /// + /// A file index of 0 corresponds to the compilation unit file. + /// Note that a file index of 0 is invalid for DWARF version <= 4, + /// but we support it anyway. + pub fn file(&self, file: u64) -> Option<&FileEntry> { + if self.encoding.version <= 4 { + if file == 0 { + self.comp_file.as_ref() + } else { + let file = file as usize - 1; + self.file_names.get(file) + } + } else { + self.file_names.get(file as usize) + } + } + + /// Get the raw, un-parsed `EndianSlice` containing this header's line number + /// program. + /// + /// ``` + /// # fn foo() { + /// use gimli::{LineProgramHeader, EndianSlice, NativeEndian}; + /// + /// fn get_line_number_program_header<'a>() -> LineProgramHeader> { + /// // Get a line number program header from some offset in a + /// // `.debug_line` section... + /// # unimplemented!() + /// } + /// + /// let header = get_line_number_program_header(); + /// let raw_program = header.raw_program_buf(); + /// println!("The length of the raw program in bytes is {}", raw_program.len()); + /// # } + /// ``` + pub fn raw_program_buf(&self) -> R { + self.program_buf.clone() + } + + /// Iterate over the instructions in this header's line number program, parsing + /// them as we go. + pub fn instructions(&self) -> LineInstructions { + LineInstructions { + input: self.program_buf.clone(), + } + } + + fn parse( + input: &mut R, + offset: DebugLineOffset, + mut address_size: u8, + mut comp_dir: Option, + comp_name: Option, + ) -> Result> { + let (unit_length, format) = input.read_initial_length()?; + let rest = &mut input.split(unit_length)?; + + let version = rest.read_u16()?; + if version < 2 || version > 5 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + if version >= 5 { + address_size = rest.read_address_size()?; + let segment_selector_size = rest.read_u8()?; + if segment_selector_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + } + + let encoding = Encoding { + format, + version, + address_size, + }; + + let header_length = rest.read_length(format)?; + + let mut program_buf = rest.clone(); + program_buf.skip(header_length)?; + rest.truncate(header_length)?; + + let minimum_instruction_length = rest.read_u8()?; + if minimum_instruction_length == 0 { + return Err(Error::MinimumInstructionLengthZero); + } + + // This field did not exist before DWARF 4, but is specified to be 1 for + // non-VLIW architectures, which makes it a no-op. + let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 }; + if maximum_operations_per_instruction == 0 { + return Err(Error::MaximumOperationsPerInstructionZero); + } + + let default_is_stmt = rest.read_u8()? != 0; + let line_base = rest.read_i8()?; + let line_range = rest.read_u8()?; + if line_range == 0 { + return Err(Error::LineRangeZero); + } + let line_encoding = LineEncoding { + minimum_instruction_length, + maximum_operations_per_instruction, + default_is_stmt, + line_base, + line_range, + }; + + let opcode_base = rest.read_u8()?; + if opcode_base == 0 { + return Err(Error::OpcodeBaseZero); + } + + let standard_opcode_count = R::Offset::from_u8(opcode_base - 1); + let standard_opcode_lengths = rest.split(standard_opcode_count)?; + + let directory_entry_format; + let mut include_directories = Vec::new(); + if version <= 4 { + directory_entry_format = Vec::new(); + loop { + let directory = rest.read_null_terminated_slice()?; + if directory.is_empty() { + break; + } + include_directories.push(AttributeValue::String(directory)); + } + } else { + comp_dir = None; + directory_entry_format = FileEntryFormat::parse(rest)?; + let count = rest.read_uleb128()?; + for _ in 0..count { + include_directories.push(parse_directory_v5( + rest, + encoding, + &directory_entry_format, + )?); + } + } + + let comp_file; + let file_name_entry_format; + let mut file_names = Vec::new(); + if version <= 4 { + comp_file = comp_name.map(|name| FileEntry { + path_name: AttributeValue::String(name), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }); + + file_name_entry_format = Vec::new(); + loop { + let path_name = rest.read_null_terminated_slice()?; + if path_name.is_empty() { + break; + } + file_names.push(FileEntry::parse(rest, path_name)?); + } + } else { + comp_file = None; + file_name_entry_format = FileEntryFormat::parse(rest)?; + let count = rest.read_uleb128()?; + for _ in 0..count { + file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?); + } + } + + let header = LineProgramHeader { + encoding, + offset, + unit_length, + header_length, + line_encoding, + opcode_base, + standard_opcode_lengths, + directory_entry_format, + include_directories, + file_name_entry_format, + file_names, + program_buf, + comp_dir, + comp_file, + }; + Ok(header) + } +} + +/// Deprecated. `IncompleteLineNumberProgram` has been renamed to `IncompleteLineProgram`. +#[deprecated( + note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead." +)] +pub type IncompleteLineNumberProgram = IncompleteLineProgram; + +/// A line number program that has not been run to completion. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IncompleteLineProgram::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + header: LineProgramHeader, +} + +impl IncompleteLineProgram +where + R: Reader, + Offset: ReaderOffset, +{ + /// Retrieve the `LineProgramHeader` for this program. + pub fn header(&self) -> &LineProgramHeader { + &self.header + } + + /// Construct a new `LineRows` for executing this program to iterate + /// over rows in the line information matrix. + pub fn rows(self) -> OneShotLineRows { + OneShotLineRows::new(self) + } + + /// Execute the line number program, completing the `IncompleteLineProgram` + /// into a `CompleteLineProgram` and producing an array of sequences within + /// the line number program that can later be used with + /// `CompleteLineProgram::resume_from`. + /// + /// ``` + /// # fn foo() { + /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; + /// + /// fn get_line_number_program<'a>() -> IncompleteLineProgram> { + /// // Get a line number program from some offset in a + /// // `.debug_line` section... + /// # unimplemented!() + /// } + /// + /// let program = get_line_number_program(); + /// let (program, sequences) = program.sequences().unwrap(); + /// println!("There are {} sequences in this line number program", sequences.len()); + /// # } + /// ``` + #[allow(clippy::type_complexity)] + pub fn sequences(self) -> Result<(CompleteLineProgram, Vec>)> { + let mut sequences = Vec::new(); + let mut rows = self.rows(); + let mut instructions = rows.instructions.clone(); + let mut sequence_start_addr = None; + loop { + let sequence_end_addr; + if rows.next_row()?.is_none() { + break; + } + + let row = &rows.row; + if row.end_sequence() { + sequence_end_addr = row.address(); + } else if sequence_start_addr.is_none() { + sequence_start_addr = Some(row.address()); + continue; + } else { + continue; + } + + // We just finished a sequence. + sequences.push(LineSequence { + // In theory one could have multiple DW_LNE_end_sequence instructions + // in a row. + start: sequence_start_addr.unwrap_or(0), + end: sequence_end_addr, + instructions: instructions.remove_trailing(&rows.instructions)?, + }); + sequence_start_addr = None; + instructions = rows.instructions.clone(); + } + + let program = CompleteLineProgram { + header: rows.program.header, + }; + Ok((program, sequences)) + } +} + +/// Deprecated. `CompleteLineNumberProgram` has been renamed to `CompleteLineProgram`. +#[deprecated( + note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead." +)] +pub type CompleteLineNumberProgram = CompleteLineProgram; + +/// A line number program that has previously been run to completion. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CompleteLineProgram::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + header: LineProgramHeader, +} + +impl CompleteLineProgram +where + R: Reader, + Offset: ReaderOffset, +{ + /// Retrieve the `LineProgramHeader` for this program. + pub fn header(&self) -> &LineProgramHeader { + &self.header + } + + /// Construct a new `LineRows` for executing the subset of the line + /// number program identified by 'sequence' and generating the line information + /// matrix. + /// + /// ``` + /// # fn foo() { + /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; + /// + /// fn get_line_number_program<'a>() -> IncompleteLineProgram> { + /// // Get a line number program from some offset in a + /// // `.debug_line` section... + /// # unimplemented!() + /// } + /// + /// let program = get_line_number_program(); + /// let (program, sequences) = program.sequences().unwrap(); + /// for sequence in &sequences { + /// let mut sm = program.resume_from(sequence); + /// } + /// # } + /// ``` + pub fn resume_from<'program>( + &'program self, + sequence: &LineSequence, + ) -> ResumedLineRows<'program, R, Offset> { + ResumedLineRows::resume(self, sequence) + } +} + +/// An entry in the `LineProgramHeader`'s `file_names` set. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct FileEntry::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + path_name: AttributeValue, + directory_index: u64, + timestamp: u64, + size: u64, + md5: [u8; 16], + source: Option>, +} + +impl FileEntry +where + R: Reader, + Offset: ReaderOffset, +{ + // version 2-4 + fn parse(input: &mut R, path_name: R) -> Result> { + let directory_index = input.read_uleb128()?; + let timestamp = input.read_uleb128()?; + let size = input.read_uleb128()?; + + let entry = FileEntry { + path_name: AttributeValue::String(path_name), + directory_index, + timestamp, + size, + md5: [0; 16], + source: None, + }; + + Ok(entry) + } + + /// > A slice containing the full or relative path name of + /// > a source file. If the entry contains a file name or a relative path + /// > name, the file is located relative to either the compilation directory + /// > (as specified by the DW_AT_comp_dir attribute given in the compilation + /// > unit) or one of the directories in the include_directories section. + pub fn path_name(&self) -> AttributeValue { + self.path_name.clone() + } + + /// > An unsigned LEB128 number representing the directory index of the + /// > directory in which the file was found. + /// > + /// > ... + /// > + /// > The directory index represents an entry in the include_directories + /// > section of the line number program header. The index is 0 if the file + /// > was found in the current directory of the compilation, 1 if it was found + /// > in the first directory in the include_directories section, and so + /// > on. The directory index is ignored for file names that represent full + /// > path names. + pub fn directory_index(&self) -> u64 { + self.directory_index + } + + /// Get this file's directory. + /// + /// A directory index of 0 corresponds to the compilation unit directory. + pub fn directory(&self, header: &LineProgramHeader) -> Option> { + header.directory(self.directory_index) + } + + /// The implementation-defined time of last modification of the file, + /// or 0 if not available. + pub fn timestamp(&self) -> u64 { + self.timestamp + } + + /// "An unsigned LEB128 number representing the time of last modification of + /// the file, or 0 if not available." + // Terminology changed in DWARF version 5. + #[doc(hidden)] + pub fn last_modification(&self) -> u64 { + self.timestamp + } + + /// The size of the file in bytes, or 0 if not available. + pub fn size(&self) -> u64 { + self.size + } + + /// "An unsigned LEB128 number representing the length in bytes of the file, + /// or 0 if not available." + // Terminology changed in DWARF version 5. + #[doc(hidden)] + pub fn length(&self) -> u64 { + self.size + } + + /// A 16-byte MD5 digest of the file contents. + /// + /// Only valid if `LineProgramHeader::file_has_md5` returns `true`. + pub fn md5(&self) -> &[u8; 16] { + &self.md5 + } + + /// The source code of this file. (UTF-8 source text string with "\n" line + /// endings). + /// + /// Note: For DWARF v5 files this may return an empty attribute that + /// indicates that no source code is available, which this function + /// represents as `Some()`. + pub fn source(&self) -> Option> { + self.source.clone() + } +} + +/// The format of a component of an include directory or file name entry. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct FileEntryFormat { + /// The type of information that is represented by the component. + pub content_type: constants::DwLnct, + + /// The encoding form of the component value. + pub form: constants::DwForm, +} + +impl FileEntryFormat { + fn parse(input: &mut R) -> Result> { + let format_count = input.read_u8()? as usize; + let mut format = Vec::with_capacity(format_count); + let mut path_count = 0; + for _ in 0..format_count { + let content_type = input.read_uleb128()?; + let content_type = if content_type > u64::from(u16::MAX) { + constants::DwLnct(u16::MAX) + } else { + constants::DwLnct(content_type as u16) + }; + if content_type == constants::DW_LNCT_path { + path_count += 1; + } + + let form = constants::DwForm(input.read_uleb128_u16()?); + + format.push(FileEntryFormat { content_type, form }); + } + if path_count != 1 { + return Err(Error::MissingFileEntryFormatPath); + } + Ok(format) + } +} + +fn parse_directory_v5( + input: &mut R, + encoding: Encoding, + formats: &[FileEntryFormat], +) -> Result> { + let mut path_name = None; + + for format in formats { + let value = parse_attribute(input, encoding, format.form)?; + if format.content_type == constants::DW_LNCT_path { + path_name = Some(value); + } + } + + Ok(path_name.unwrap()) +} + +fn parse_file_v5( + input: &mut R, + encoding: Encoding, + formats: &[FileEntryFormat], +) -> Result> { + let mut path_name = None; + let mut directory_index = 0; + let mut timestamp = 0; + let mut size = 0; + let mut md5 = [0; 16]; + let mut source = None; + + for format in formats { + let value = parse_attribute(input, encoding, format.form)?; + match format.content_type { + constants::DW_LNCT_path => path_name = Some(value), + constants::DW_LNCT_directory_index => { + if let Some(value) = value.udata_value() { + directory_index = value; + } + } + constants::DW_LNCT_timestamp => { + if let Some(value) = value.udata_value() { + timestamp = value; + } + } + constants::DW_LNCT_size => { + if let Some(value) = value.udata_value() { + size = value; + } + } + constants::DW_LNCT_MD5 => { + if let AttributeValue::Block(mut value) = value { + if value.len().into_u64() == 16 { + md5 = value.read_u8_array()?; + } + } + } + constants::DW_LNCT_LLVM_source => { + source = Some(value); + } + // Ignore unknown content types. + _ => {} + } + } + + Ok(FileEntry { + path_name: path_name.unwrap(), + directory_index, + timestamp, + size, + md5, + source, + }) +} + +// TODO: this should be shared with unit::parse_attribute(), but that is hard to do. +fn parse_attribute( + input: &mut R, + encoding: Encoding, + form: constants::DwForm, +) -> Result> { + Ok(match form { + constants::DW_FORM_block1 => { + let len = input.read_u8().map(R::Offset::from_u8)?; + let block = input.split(len)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block2 => { + let len = input.read_u16().map(R::Offset::from_u16)?; + let block = input.split(len)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block4 => { + let len = input.read_u32().map(R::Offset::from_u32)?; + let block = input.split(len)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block => { + let len = input.read_uleb128().and_then(R::Offset::from_u64)?; + let block = input.split(len)?; + AttributeValue::Block(block) + } + constants::DW_FORM_data1 => { + let data = input.read_u8()?; + AttributeValue::Data1(data) + } + constants::DW_FORM_data2 => { + let data = input.read_u16()?; + AttributeValue::Data2(data) + } + constants::DW_FORM_data4 => { + let data = input.read_u32()?; + AttributeValue::Data4(data) + } + constants::DW_FORM_data8 => { + let data = input.read_u64()?; + AttributeValue::Data8(data) + } + constants::DW_FORM_data16 => { + let block = input.split(R::Offset::from_u8(16))?; + AttributeValue::Block(block) + } + constants::DW_FORM_udata => { + let data = input.read_uleb128()?; + AttributeValue::Udata(data) + } + constants::DW_FORM_sdata => { + let data = input.read_sleb128()?; + AttributeValue::Sdata(data) + } + constants::DW_FORM_flag => { + let present = input.read_u8()?; + AttributeValue::Flag(present != 0) + } + constants::DW_FORM_sec_offset => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::SecOffset(offset) + } + constants::DW_FORM_string => { + let string = input.read_null_terminated_slice()?; + AttributeValue::String(string) + } + constants::DW_FORM_strp => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugStrRef(DebugStrOffset(offset)) + } + constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) + } + constants::DW_FORM_line_strp => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) + } + constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx1 => { + let index = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx2 => { + let index = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx3 => { + let index = input.read_uint(3).and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx4 => { + let index = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + _ => { + return Err(Error::UnknownForm(form)); + } + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::constants; + use crate::endianity::LittleEndian; + use crate::read::{EndianSlice, Error}; + use crate::test_util::GimliSectionMethods; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + #[test] + fn test_parse_debug_line_32_ok() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 62. + 0x3e, 0x00, 0x00, 0x00, + // Version. + 0x04, 0x00, + // Header length = 40. + 0x28, 0x00, 0x00, 0x00, + // Minimum instruction length. + 0x01, + // Maximum operations per byte. + 0x01, + // Default is_stmt. + 0x01, + // Line base. + 0x00, + // Line range. + 0x01, + // Opcode base. + 0x03, + // Standard opcode lengths for opcodes 1 .. opcode base - 1. + 0x01, 0x02, + // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' + 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, + // File names + // foo.rs + 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, + 0x00, + 0x00, + 0x00, + // bar.h + 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, + 0x01, + 0x00, + 0x00, + // End file names. + 0x00, + + // Dummy line program data. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next line program. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian); + let comp_name = EndianSlice::new(b"/comp_name", LittleEndian); + + let header = + LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name)) + .expect("should parse header ok"); + + assert_eq!( + *rest, + EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) + ); + + assert_eq!(header.offset, DebugLineOffset(0)); + assert_eq!(header.version(), 4); + assert_eq!(header.minimum_instruction_length(), 1); + assert_eq!(header.maximum_operations_per_instruction(), 1); + assert!(header.default_is_stmt()); + assert_eq!(header.line_base(), 0); + assert_eq!(header.line_range(), 1); + assert_eq!(header.opcode_base(), 3); + assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir))); + assert_eq!( + header.file(0).unwrap().path_name, + AttributeValue::String(comp_name) + ); + + let expected_lengths = [1, 2]; + assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths); + + let expected_include_directories = [ + AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)), + AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)), + ]; + assert_eq!(header.include_directories(), &expected_include_directories); + + let expected_file_names = [ + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }, + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)), + directory_index: 1, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }, + ]; + assert_eq!(header.file_names(), &expected_file_names); + } + + #[test] + fn test_parse_debug_line_header_length_too_short() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 62. + 0x3e, 0x00, 0x00, 0x00, + // Version. + 0x04, 0x00, + // Header length = 20. TOO SHORT!!! + 0x15, 0x00, 0x00, 0x00, + // Minimum instruction length. + 0x01, + // Maximum operations per byte. + 0x01, + // Default is_stmt. + 0x01, + // Line base. + 0x00, + // Line range. + 0x01, + // Opcode base. + 0x03, + // Standard opcode lengths for opcodes 1 .. opcode base - 1. + 0x01, 0x02, + // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' + 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, + // File names + // foo.rs + 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, + 0x00, + 0x00, + 0x00, + // bar.h + 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, + 0x01, + 0x00, + 0x00, + // End file names. + 0x00, + + // Dummy line program data. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next line program. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let input = &mut EndianSlice::new(&buf, LittleEndian); + + match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_parse_debug_line_unit_length_too_short() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 40. TOO SHORT!!! + 0x28, 0x00, 0x00, 0x00, + // Version. + 0x04, 0x00, + // Header length = 40. + 0x28, 0x00, 0x00, 0x00, + // Minimum instruction length. + 0x01, + // Maximum operations per byte. + 0x01, + // Default is_stmt. + 0x01, + // Line base. + 0x00, + // Line range. + 0x01, + // Opcode base. + 0x03, + // Standard opcode lengths for opcodes 1 .. opcode base - 1. + 0x01, 0x02, + // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' + 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, + // File names + // foo.rs + 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, + 0x00, + 0x00, + 0x00, + // bar.h + 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, + 0x01, + 0x00, + 0x00, + // End file names. + 0x00, + + // Dummy line program data. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next line program. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let input = &mut EndianSlice::new(&buf, LittleEndian); + + match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + const OPCODE_BASE: u8 = 13; + const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1]; + + fn make_test_header( + buf: EndianSlice<'_, LittleEndian>, + ) -> LineProgramHeader> { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 8, + }; + let line_encoding = LineEncoding { + line_base: -3, + line_range: 12, + ..Default::default() + }; + LineProgramHeader { + encoding, + offset: DebugLineOffset(0), + unit_length: 1, + header_length: 1, + line_encoding, + opcode_base: OPCODE_BASE, + standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian), + file_names: vec![ + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }, + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }, + ], + include_directories: vec![], + directory_entry_format: vec![], + file_name_entry_format: vec![], + program_buf: buf, + comp_dir: None, + comp_file: None, + } + } + + fn make_test_program( + buf: EndianSlice<'_, LittleEndian>, + ) -> IncompleteLineProgram> { + IncompleteLineProgram { + header: make_test_header(buf), + } + } + + #[test] + fn test_parse_special_opcodes() { + for i in OPCODE_BASE..u8::MAX { + let input = [i, 0, 0, 0]; + let input = EndianSlice::new(&input, LittleEndian); + let header = make_test_header(input); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!(*rest, *input.range_from(1..)); + assert_eq!(opcode, LineInstruction::Special(i)); + } + } + + #[test] + fn test_parse_standard_opcodes() { + fn test( + raw: constants::DwLns, + operands: Operands, + expected: LineInstruction>, + ) where + Operands: AsRef<[u8]>, + { + let mut input = Vec::new(); + input.push(raw.0); + input.extend_from_slice(operands.as_ref()); + + let expected_rest = [0, 1, 2, 3, 4]; + input.extend_from_slice(&expected_rest); + + let input = EndianSlice::new(&input, LittleEndian); + let header = make_test_header(input); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!(opcode, expected); + assert_eq!(*rest, expected_rest); + } + + test(constants::DW_LNS_copy, [], LineInstruction::Copy); + test( + constants::DW_LNS_advance_pc, + [42], + LineInstruction::AdvancePc(42), + ); + test( + constants::DW_LNS_advance_line, + [9], + LineInstruction::AdvanceLine(9), + ); + test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7)); + test( + constants::DW_LNS_set_column, + [1], + LineInstruction::SetColumn(1), + ); + test( + constants::DW_LNS_negate_stmt, + [], + LineInstruction::NegateStatement, + ); + test( + constants::DW_LNS_set_basic_block, + [], + LineInstruction::SetBasicBlock, + ); + test( + constants::DW_LNS_const_add_pc, + [], + LineInstruction::ConstAddPc, + ); + test( + constants::DW_LNS_fixed_advance_pc, + [42, 0], + LineInstruction::FixedAddPc(42), + ); + test( + constants::DW_LNS_set_prologue_end, + [], + LineInstruction::SetPrologueEnd, + ); + test( + constants::DW_LNS_set_isa, + [57 + 0x80, 100], + LineInstruction::SetIsa(12857), + ); + } + + #[test] + fn test_parse_unknown_standard_opcode_no_args() { + let input = [OPCODE_BASE, 1, 2, 3]; + let input = EndianSlice::new(&input, LittleEndian); + let mut standard_opcode_lengths = Vec::new(); + let mut header = make_test_header(input); + standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); + standard_opcode_lengths.push(0); + header.opcode_base += 1; + header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!( + opcode, + LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE)) + ); + assert_eq!(*rest, *input.range_from(1..)); + } + + #[test] + fn test_parse_unknown_standard_opcode_one_arg() { + let input = [OPCODE_BASE, 1, 2, 3]; + let input = EndianSlice::new(&input, LittleEndian); + let mut standard_opcode_lengths = Vec::new(); + let mut header = make_test_header(input); + standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); + standard_opcode_lengths.push(1); + header.opcode_base += 1; + header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!( + opcode, + LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1) + ); + assert_eq!(*rest, *input.range_from(2..)); + } + + #[test] + fn test_parse_unknown_standard_opcode_many_args() { + let input = [OPCODE_BASE, 1, 2, 3]; + let input = EndianSlice::new(&input, LittleEndian); + let args = input.range_from(1..); + let mut standard_opcode_lengths = Vec::new(); + let mut header = make_test_header(input); + standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); + standard_opcode_lengths.push(3); + header.opcode_base += 1; + header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!( + opcode, + LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args) + ); + assert_eq!(*rest, []); + } + + #[test] + fn test_parse_extended_opcodes() { + fn test( + raw: constants::DwLne, + operands: Operands, + expected: LineInstruction>, + ) where + Operands: AsRef<[u8]>, + { + let mut input = Vec::new(); + input.push(0); + + let operands = operands.as_ref(); + input.push(1 + operands.len() as u8); + + input.push(raw.0); + input.extend_from_slice(operands); + + let expected_rest = [0, 1, 2, 3, 4]; + input.extend_from_slice(&expected_rest); + + let input = EndianSlice::new(&input, LittleEndian); + let header = make_test_header(input); + + let mut rest = input; + let opcode = + LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); + + assert_eq!(opcode, expected); + assert_eq!(*rest, expected_rest); + } + + test( + constants::DW_LNE_end_sequence, + [], + LineInstruction::EndSequence, + ); + test( + constants::DW_LNE_set_address, + [1, 2, 3, 4, 5, 6, 7, 8], + LineInstruction::SetAddress(578_437_695_752_307_201), + ); + test( + constants::DW_LNE_set_discriminator, + [42], + LineInstruction::SetDiscriminator(42), + ); + + let mut file = Vec::new(); + // "foo.c" + let path_name = [b'f', b'o', b'o', b'.', b'c', 0]; + file.extend_from_slice(&path_name); + // Directory index. + file.push(0); + // Last modification of file. + file.push(1); + // Size of file. + file.push(2); + + test( + constants::DW_LNE_define_file, + file, + LineInstruction::DefineFile(FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), + directory_index: 0, + timestamp: 1, + size: 2, + md5: [0; 16], + source: None, + }), + ); + + // Unknown extended opcode. + let operands = [1, 2, 3, 4, 5, 6]; + let opcode = constants::DwLne(99); + test( + opcode, + operands, + LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)), + ); + } + + #[test] + fn test_file_entry_directory() { + let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0]; + + let mut file = FileEntry { + path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)), + directory_index: 1, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }; + + let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian)); + header.include_directories.push(dir); + + assert_eq!(file.directory(&header), Some(dir)); + + // Now test the compilation's current directory. + file.directory_index = 0; + assert_eq!(file.directory(&header), None); + } + + fn assert_exec_opcode<'input>( + header: LineProgramHeader>, + mut registers: LineRow, + opcode: LineInstruction>, + expected_registers: LineRow, + expect_new_row: bool, + ) { + let mut program = IncompleteLineProgram { header }; + let is_new_row = registers.execute(opcode, &mut program); + + assert_eq!(is_new_row, Ok(expect_new_row)); + assert_eq!(registers, expected_registers); + } + + #[test] + fn test_exec_special_noop() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::Special(16); + let expected_registers = initial_registers; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_negative_line_advance() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.line.0 = 10; + + let opcode = LineInstruction::Special(13); + + let mut expected_registers = initial_registers; + expected_registers.line.0 -= 3; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_positive_line_advance() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let initial_registers = LineRow::new(&header); + + let opcode = LineInstruction::Special(19); + + let mut expected_registers = initial_registers; + expected_registers.line.0 += 3; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_positive_address_advance() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let initial_registers = LineRow::new(&header); + + let opcode = LineInstruction::Special(52); + + let mut expected_registers = initial_registers; + expected_registers.address += 3; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_positive_address_and_line_advance() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let initial_registers = LineRow::new(&header); + + let opcode = LineInstruction::Special(55); + + let mut expected_registers = initial_registers; + expected_registers.address += 3; + expected_registers.line.0 += 3; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_positive_address_and_negative_line_advance() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.line.0 = 10; + + let opcode = LineInstruction::Special(49); + + let mut expected_registers = initial_registers; + expected_registers.address += 3; + expected_registers.line.0 -= 3; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_special_line_underflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.line.0 = 2; + + // -3 line advance. + let opcode = LineInstruction::Special(13); + + let mut expected_registers = initial_registers; + // Clamp at 0. No idea if this is the best way to handle this situation + // or not... + expected_registers.line.0 = 0; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_copy() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.address = 1337; + initial_registers.line.0 = 42; + + let opcode = LineInstruction::Copy; + + let expected_registers = initial_registers; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_advance_pc() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::AdvancePc(42); + + let mut expected_registers = initial_registers; + expected_registers.address += 42; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_advance_pc_overflow_32() { + let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); + header.encoding.address_size = 4; + let mut registers = LineRow::new(&header); + registers.address = u32::MAX.into(); + let opcode = LineInstruction::AdvancePc(42); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + + #[test] + fn test_exec_advance_pc_overflow_64() { + let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); + header.encoding.address_size = 8; + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + let opcode = LineInstruction::AdvancePc(42); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + + #[test] + fn test_exec_advance_line() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::AdvanceLine(42); + + let mut expected_registers = initial_registers; + expected_registers.line.0 += 42; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_advance_line_overflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let opcode = LineInstruction::AdvanceLine(42); + + let mut initial_registers = LineRow::new(&header); + initial_registers.line.0 = u64::MAX; + + let mut expected_registers = initial_registers; + expected_registers.line.0 = 41; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_set_file_in_bounds() { + for file_idx in 1..3 { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetFile(file_idx); + + let mut expected_registers = initial_registers; + expected_registers.file = file_idx; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + } + + #[test] + fn test_exec_set_file_out_of_bounds() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetFile(100); + + // The spec doesn't say anything about rejecting input programs + // that set the file register out of bounds of the actual number + // of files that have been defined. Instead, we cross our + // fingers and hope that one gets defined before + // `LineRow::file` gets called and handle the error at + // that time if need be. + let mut expected_registers = initial_registers; + expected_registers.file = 100; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_file_entry_file_index_out_of_bounds() { + // These indices are 1-based, so 0 is invalid. 100 is way more than the + // number of files defined in the header. + let out_of_bounds_indices = [0, 100]; + + for file_idx in &out_of_bounds_indices[..] { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut row = LineRow::new(&header); + + row.file = *file_idx; + + assert_eq!(row.file(&header), None); + } + } + + #[test] + fn test_file_entry_file_index_in_bounds() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut row = LineRow::new(&header); + + row.file = 2; + + assert_eq!(row.file(&header), Some(&header.file_names()[1])); + } + + #[test] + fn test_exec_set_column() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetColumn(42); + + let mut expected_registers = initial_registers; + expected_registers.column = 42; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_negate_statement() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::NegateStatement; + + let mut expected_registers = initial_registers; + expected_registers.is_stmt = !initial_registers.is_stmt; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_set_basic_block() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.basic_block = false; + + let opcode = LineInstruction::SetBasicBlock; + + let mut expected_registers = initial_registers; + expected_registers.basic_block = true; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_const_add_pc() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::ConstAddPc; + + let mut expected_registers = initial_registers; + expected_registers.address += 20; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_const_add_pc_overflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + let opcode = LineInstruction::ConstAddPc; + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + + #[test] + fn test_exec_fixed_add_pc() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.op_index.0 = 1; + + let opcode = LineInstruction::FixedAddPc(10); + + let mut expected_registers = initial_registers; + expected_registers.address += 10; + expected_registers.op_index.0 = 0; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_fixed_add_pc_overflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + registers.op_index.0 = 1; + let opcode = LineInstruction::FixedAddPc(10); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + + #[test] + fn test_exec_set_prologue_end() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + + let mut initial_registers = LineRow::new(&header); + initial_registers.prologue_end = false; + + let opcode = LineInstruction::SetPrologueEnd; + + let mut expected_registers = initial_registers; + expected_registers.prologue_end = true; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_set_isa() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetIsa(1993); + + let mut expected_registers = initial_registers; + expected_registers.isa = 1993; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_unknown_standard_0() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111)); + let expected_registers = initial_registers; + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_unknown_standard_1() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2); + let expected_registers = initial_registers; + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_unknown_standard_n() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::UnknownStandardN( + constants::DwLns(111), + EndianSlice::new(&[2, 2, 2], LittleEndian), + ); + let expected_registers = initial_registers; + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_end_sequence() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::EndSequence; + + let mut expected_registers = initial_registers; + expected_registers.end_sequence = true; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); + } + + #[test] + fn test_exec_set_address() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetAddress(3030); + + let mut expected_registers = initial_registers; + expected_registers.address = 3030; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_set_address_tombstone() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetAddress(!0); + + let mut expected_registers = initial_registers; + expected_registers.tombstone = true; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_set_address_backwards() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut initial_registers = LineRow::new(&header); + initial_registers.address = 1; + let opcode = LineInstruction::SetAddress(0); + + let mut expected_registers = initial_registers; + expected_registers.tombstone = true; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_define_file() { + let mut program = make_test_program(EndianSlice::new(&[], LittleEndian)); + let mut row = LineRow::new(program.header()); + + let file = FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [0; 16], + source: None, + }; + + let opcode = LineInstruction::DefineFile(file); + let is_new_row = row.execute(opcode, &mut program).unwrap(); + + assert!(!is_new_row); + assert_eq!(Some(&file), program.header().file_names.last()); + } + + #[test] + fn test_exec_set_discriminator() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::SetDiscriminator(9); + + let mut expected_registers = initial_registers; + expected_registers.discriminator = 9; + + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + #[test] + fn test_exec_unknown_extended() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let initial_registers = LineRow::new(&header); + let opcode = LineInstruction::UnknownExtended( + constants::DwLne(74), + EndianSlice::new(&[], LittleEndian), + ); + let expected_registers = initial_registers; + assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + } + + /// Ensure that `LineRows` is covariant wrt R. + /// This only needs to compile. + #[allow(dead_code, unreachable_code, unused_variables)] + #[allow(clippy::diverging_sub_expression)] + fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8]) + where + 'a: 'b, + { + let a: &OneShotLineRows> = unimplemented!(); + let _: &OneShotLineRows> = a; + } + + #[test] + fn test_parse_debug_line_v5_ok() { + let expected_lengths = &[1, 2]; + let expected_program = &[0, 1, 2, 3, 4]; + let expected_rest = &[5, 6, 7, 8, 9]; + let expected_include_directories = [ + AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)), + AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)), + ]; + let expected_file_names = [ + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)), + directory_index: 0, + timestamp: 0, + size: 0, + md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + source: Some(AttributeValue::String(EndianSlice::new( + b"foobar", + LittleEndian, + ))), + }, + FileEntry { + path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)), + directory_index: 1, + timestamp: 0, + size: 0, + md5: [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + ], + source: Some(AttributeValue::String(EndianSlice::new( + b"quux", + LittleEndian, + ))), + }, + ]; + + for format in [Format::Dwarf32, Format::Dwarf64] { + let length = Label::new(); + let header_length = Label::new(); + let start = Label::new(); + let header_start = Label::new(); + let end = Label::new(); + let header_end = Label::new(); + let section = Section::with_endian(Endian::Little) + .initial_length(format, &length, &start) + .D16(5) + // Address size. + .D8(4) + // Segment selector size. + .D8(0) + .word_label(format.word_size(), &header_length) + .mark(&header_start) + // Minimum instruction length. + .D8(1) + // Maximum operations per byte. + .D8(1) + // Default is_stmt. + .D8(1) + // Line base. + .D8(0) + // Line range. + .D8(1) + // Opcode base. + .D8(expected_lengths.len() as u8 + 1) + // Standard opcode lengths for opcodes 1 .. opcode base - 1. + .append_bytes(expected_lengths) + // Directory entry format count. + .D8(1) + .uleb(constants::DW_LNCT_path.0 as u64) + .uleb(constants::DW_FORM_string.0 as u64) + // Directory count. + .D8(2) + .append_bytes(b"dir1\0") + .append_bytes(b"dir2\0") + // File entry format count. + .D8(4) + .uleb(constants::DW_LNCT_path.0 as u64) + .uleb(constants::DW_FORM_string.0 as u64) + .uleb(constants::DW_LNCT_directory_index.0 as u64) + .uleb(constants::DW_FORM_data1.0 as u64) + .uleb(constants::DW_LNCT_MD5.0 as u64) + .uleb(constants::DW_FORM_data16.0 as u64) + .uleb(constants::DW_LNCT_LLVM_source.0 as u64) + .uleb(constants::DW_FORM_string.0 as u64) + // File count. + .D8(2) + .append_bytes(b"file1\0") + .D8(0) + .append_bytes(&expected_file_names[0].md5) + .append_bytes(b"foobar\0") + .append_bytes(b"file2\0") + .D8(1) + .append_bytes(&expected_file_names[1].md5) + .append_bytes(b"quux\0") + .mark(&header_end) + // Dummy line program data. + .append_bytes(expected_program) + .mark(&end) + // Dummy trailing data. + .append_bytes(expected_rest); + length.set_const((&end - &start) as u64); + header_length.set_const((&header_end - &header_start) as u64); + let section = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(§ion, LittleEndian); + + let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None) + .expect("should parse header ok"); + + assert_eq!(header.raw_program_buf().slice(), expected_program); + assert_eq!(input.slice(), expected_rest); + + assert_eq!(header.offset, DebugLineOffset(0)); + assert_eq!(header.version(), 5); + assert_eq!(header.address_size(), 4); + assert_eq!(header.minimum_instruction_length(), 1); + assert_eq!(header.maximum_operations_per_instruction(), 1); + assert!(header.default_is_stmt()); + assert_eq!(header.line_base(), 0); + assert_eq!(header.line_range(), 1); + assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1); + assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths); + assert_eq!( + header.directory_entry_format(), + &[FileEntryFormat { + content_type: constants::DW_LNCT_path, + form: constants::DW_FORM_string, + }] + ); + assert_eq!(header.include_directories(), expected_include_directories); + assert_eq!(header.directory(0), Some(expected_include_directories[0])); + assert_eq!( + header.file_name_entry_format(), + &[ + FileEntryFormat { + content_type: constants::DW_LNCT_path, + form: constants::DW_FORM_string, + }, + FileEntryFormat { + content_type: constants::DW_LNCT_directory_index, + form: constants::DW_FORM_data1, + }, + FileEntryFormat { + content_type: constants::DW_LNCT_MD5, + form: constants::DW_FORM_data16, + }, + FileEntryFormat { + content_type: constants::DW_LNCT_LLVM_source, + form: constants::DW_FORM_string, + } + ] + ); + assert_eq!(header.file_names(), expected_file_names); + assert_eq!(header.file(0), Some(&expected_file_names[0])); + } + } + + #[test] + fn test_sequences() { + #[rustfmt::skip] + let buf = [ + // 32-bit length + 94, 0x00, 0x00, 0x00, + // Version. + 0x04, 0x00, + // Header length = 40. + 0x28, 0x00, 0x00, 0x00, + // Minimum instruction length. + 0x01, + // Maximum operations per byte. + 0x01, + // Default is_stmt. + 0x01, + // Line base. + 0x00, + // Line range. + 0x01, + // Opcode base. + 0x03, + // Standard opcode lengths for opcodes 1 .. opcode base - 1. + 0x01, 0x02, + // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' + 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, + // File names + // foo.rs + 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, + 0x00, + 0x00, + 0x00, + // bar.h + 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, + 0x01, + 0x00, + 0x00, + // End file names. + 0x00, + + 0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 1, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 2, + 0, 1, constants::DW_LNE_end_sequence.0, + + // Tombstone + 0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 1, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 2, + 0, 1, constants::DW_LNE_end_sequence.0, + + 0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 1, + constants::DW_LNS_copy.0, + constants::DW_LNS_advance_pc.0, 2, + 0, 1, constants::DW_LNE_end_sequence.0, + ]; + assert_eq!(buf[0] as usize, buf.len() - 4); + + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None) + .expect("should parse header ok"); + let program = IncompleteLineProgram { header }; + + let sequences = program.sequences().unwrap().1; + assert_eq!(sequences.len(), 2); + assert_eq!(sequences[0].start, 1); + assert_eq!(sequences[0].end, 4); + assert_eq!(sequences[1].start, 11); + assert_eq!(sequences[1].end, 14); + } +} diff --git a/deps/crates/vendor/gimli/src/read/lists.rs b/deps/crates/vendor/gimli/src/read/lists.rs new file mode 100644 index 00000000000000..bb41901ddca448 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/lists.rs @@ -0,0 +1,68 @@ +use crate::common::{Encoding, Format}; +use crate::read::{Error, Reader, Result}; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct ListsHeader { + encoding: Encoding, + #[allow(dead_code)] + offset_entry_count: u32, +} + +impl Default for ListsHeader { + fn default() -> Self { + ListsHeader { + encoding: Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 0, + }, + offset_entry_count: 0, + } + } +} + +impl ListsHeader { + /// Return the serialized size of the table header. + #[allow(dead_code)] + #[inline] + fn size(self) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + ListsHeader::size_for_encoding(self.encoding) + } + + /// Return the serialized size of the table header. + #[inline] + pub(crate) fn size_for_encoding(encoding: Encoding) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + encoding.format.initial_length_size() + 2 + 1 + 1 + 4 + } +} + +// TODO: add an iterator over headers in the appropriate sections section +#[allow(dead_code)] +fn parse_header(input: &mut R) -> Result { + let (length, format) = input.read_initial_length()?; + input.truncate(length)?; + + let version = input.read_u16()?; + if version != 5 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + let address_size = input.read_address_size()?; + let segment_selector_size = input.read_u8()?; + if segment_selector_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + let offset_entry_count = input.read_u32()?; + + let encoding = Encoding { + format, + version, + address_size, + }; + Ok(ListsHeader { + encoding, + offset_entry_count, + }) +} diff --git a/deps/crates/vendor/gimli/src/read/loclists.rs b/deps/crates/vendor/gimli/src/read/loclists.rs new file mode 100644 index 00000000000000..26450186d9cbcf --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/loclists.rs @@ -0,0 +1,1132 @@ +use crate::common::{ + DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding, + LocationListsOffset, SectionId, +}; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::{ + lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, + ReaderAddress, ReaderOffset, ReaderOffsetId, Result, Section, +}; + +/// The raw contents of the `.debug_loc` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugLoc { + pub(crate) section: R, +} + +impl<'input, Endian> DebugLoc> +where + Endian: Endianity, +{ + /// Construct a new `DebugLoc` instance from the data in the `.debug_loc` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_loc` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugLoc, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_loc_section_somehow = || &buf; + /// let debug_loc = DebugLoc::new(read_debug_loc_section_somehow(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugLoc { + /// Create a `DebugLoc` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLoc + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugLoc { + fn id() -> SectionId { + SectionId::DebugLoc + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugLoc { + fn from(section: R) -> Self { + DebugLoc { section } + } +} + +/// The `DebugLocLists` struct represents the DWARF data +/// found in the `.debug_loclists` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugLocLists { + section: R, +} + +impl<'input, Endian> DebugLocLists> +where + Endian: Endianity, +{ + /// Construct a new `DebugLocLists` instance from the data in the `.debug_loclists` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_loclists` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugLocLists, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_loclists_section_somehow = || &buf; + /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugLocLists { + /// Create a `DebugLocLists` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLocLists + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugLocLists { + fn id() -> SectionId { + SectionId::DebugLocLists + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugLocLists { + fn from(section: R) -> Self { + DebugLocLists { section } + } +} + +pub(crate) type LocListsHeader = ListsHeader; + +impl DebugLocListsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugLocListsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding))) + } else { + DebugLocListsBase(Offset::from_u8(0)) + } + } +} + +/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. +#[derive(Debug, Default, Clone, Copy)] +pub struct LocationLists { + debug_loc: DebugLoc, + debug_loclists: DebugLocLists, +} + +impl LocationLists { + /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and + /// `.debug_loclists` sections. + pub fn new(debug_loc: DebugLoc, debug_loclists: DebugLocLists) -> LocationLists { + LocationLists { + debug_loc, + debug_loclists, + } + } +} + +impl LocationLists { + /// Create a `LocationLists` that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `Dwarf::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists + where + F: FnMut(&'a T) -> R, + { + LocationLists { + debug_loc: borrow(&self.debug_loc.section).into(), + debug_loclists: borrow(&self.debug_loclists.section).into(), + } + } +} + +impl LocationLists { + /// Iterate over the `LocationListEntry`s starting at the given offset. + /// + /// The `unit_encoding` must match the compilation unit that the + /// offset was contained in. + /// + /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the + /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location + /// list. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn locations( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, + base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> Result> { + Ok(LocListIter::new( + self.raw_locations(offset, unit_encoding)?, + base_address, + debug_addr.clone(), + debug_addr_base, + )) + } + + /// Similar to `locations`, but with special handling for .dwo files. + /// This should only been used when this `LocationLists` was loaded from a + /// .dwo file. + pub fn locations_dwo( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, + base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> Result> { + Ok(LocListIter::new( + self.raw_locations_dwo(offset, unit_encoding)?, + base_address, + debug_addr.clone(), + debug_addr_base, + )) + } + + /// Iterate over the raw `LocationListEntry`s starting at the given offset. + /// + /// The `unit_encoding` must match the compilation unit that the + /// offset was contained in. + /// + /// This iterator does not perform any processing of the location entries, + /// such as handling base addresses. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn raw_locations( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, + ) -> Result> { + let (mut input, format) = if unit_encoding.version <= 4 { + (self.debug_loc.section.clone(), LocListsFormat::Bare) + } else { + (self.debug_loclists.section.clone(), LocListsFormat::Lle) + }; + input.skip(offset.0)?; + Ok(RawLocListIter::new(input, unit_encoding, format)) + } + + /// Similar to `raw_locations`, but with special handling for .dwo files. + /// This should only been used when this `LocationLists` was loaded from a + /// .dwo file. + pub fn raw_locations_dwo( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, + ) -> Result> { + let mut input = if unit_encoding.version <= 4 { + // In the GNU split dwarf extension the locations are present in the + // .debug_loc section but are encoded with the DW_LLE values used + // for the DWARF 5 .debug_loclists section. + self.debug_loc.section.clone() + } else { + self.debug_loclists.section.clone() + }; + input.skip(offset.0)?; + Ok(RawLocListIter::new( + input, + unit_encoding, + LocListsFormat::Lle, + )) + } + + /// Returns the `.debug_loclists` offset at the given `base` and `index`. + /// + /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_loclistx` attribute. + pub fn get_offset( + &self, + unit_encoding: Encoding, + base: DebugLocListsBase, + index: DebugLocListsIndex, + ) -> Result> { + let format = unit_encoding.format; + let input = &mut self.debug_loclists.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(format.word_size()), + )?)?; + input + .read_offset(format) + .map(|x| LocationListsOffset(base.0 + x)) + } + + /// Call `Reader::lookup_offset_id` for each section, and return the first match. + pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { + self.debug_loc + .lookup_offset_id(id) + .or_else(|| self.debug_loclists.lookup_offset_id(id)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LocListsFormat { + /// The bare location list format used before DWARF 5. + Bare, + /// The DW_LLE encoded range list format used in DWARF 5 and the non-standard GNU + /// split dwarf extension. + Lle, +} + +/// A raw iterator over a location list. +/// +/// This iterator does not perform any processing of the location entries, +/// such as handling base addresses. +#[derive(Debug)] +pub struct RawLocListIter { + input: R, + encoding: Encoding, + format: LocListsFormat, +} + +/// A raw entry in .debug_loclists. +#[derive(Clone, Debug)] +pub enum RawLocListEntry { + /// A location from DWARF version <= 4. + AddressOrOffsetPair { + /// Start of range. May be an address or an offset. + begin: u64, + /// End of range. May be an address or an offset. + end: u64, + /// expression + data: Expression, + }, + /// DW_LLE_base_address + BaseAddress { + /// base address + addr: u64, + }, + /// DW_LLE_base_addressx + BaseAddressx { + /// base address + addr: DebugAddrIndex, + }, + /// DW_LLE_startx_endx + StartxEndx { + /// start of range + begin: DebugAddrIndex, + /// end of range + end: DebugAddrIndex, + /// expression + data: Expression, + }, + /// DW_LLE_startx_length + StartxLength { + /// start of range + begin: DebugAddrIndex, + /// length of range + length: u64, + /// expression + data: Expression, + }, + /// DW_LLE_offset_pair + OffsetPair { + /// start of range + begin: u64, + /// end of range + end: u64, + /// expression + data: Expression, + }, + /// DW_LLE_default_location + DefaultLocation { + /// expression + data: Expression, + }, + /// DW_LLE_start_end + StartEnd { + /// start of range + begin: u64, + /// end of range + end: u64, + /// expression + data: Expression, + }, + /// DW_LLE_start_length + StartLength { + /// start of range + begin: u64, + /// length of range + length: u64, + /// expression + data: Expression, + }, +} + +fn parse_data(input: &mut R, encoding: Encoding) -> Result> { + if encoding.version >= 5 { + let len = R::Offset::from_u64(input.read_uleb128()?)?; + Ok(Expression(input.split(len)?)) + } else { + // In the GNU split-dwarf extension this is a fixed 2 byte value. + let len = R::Offset::from_u16(input.read_u16()?); + Ok(Expression(input.split(len)?)) + } +} + +impl RawLocListEntry { + /// Parse a location list entry from `.debug_loclists` + fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result> { + Ok(match format { + LocListsFormat::Bare => { + let range = RawRange::parse(input, encoding.address_size)?; + if range.is_end() { + None + } else if range.is_base_address(encoding.address_size) { + Some(RawLocListEntry::BaseAddress { addr: range.end }) + } else { + let len = R::Offset::from_u16(input.read_u16()?); + let data = Expression(input.split(len)?); + Some(RawLocListEntry::AddressOrOffsetPair { + begin: range.begin, + end: range.end, + data, + }) + } + } + LocListsFormat::Lle => match constants::DwLle(input.read_u8()?) { + constants::DW_LLE_end_of_list => None, + constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + length: if encoding.version >= 5 { + input.read_uleb128()? + } else { + // In the GNU split-dwarf extension this is a fixed 4 byte value. + input.read_u32()? as u64 + }, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { + begin: input.read_uleb128()?, + end: input.read_uleb128()?, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { + addr: input.read_address(encoding.address_size)?, + }), + constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { + begin: input.read_address(encoding.address_size)?, + end: input.read_address(encoding.address_size)?, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { + begin: input.read_address(encoding.address_size)?, + length: input.read_uleb128()?, + data: parse_data(input, encoding)?, + }), + entry => { + return Err(Error::UnknownLocListsEntry(entry)); + } + }, + }) + } +} + +impl RawLocListIter { + /// Construct a `RawLocListIter`. + fn new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter { + RawLocListIter { + input, + encoding, + format, + } + } + + /// Advance the iterator to the next location. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + match RawLocListEntry::parse(&mut self.input, self.encoding, self.format) { + Ok(entry) => { + if entry.is_none() { + self.input.empty(); + } + Ok(entry) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for RawLocListIter { + type Item = RawLocListEntry; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + RawLocListIter::next(self) + } +} + +/// An iterator over a location list. +/// +/// This iterator internally handles processing of base address selection entries +/// and list end entries. Thus, it only returns location entries that are valid +/// and already adjusted for the base address. +#[derive(Debug)] +pub struct LocListIter { + raw: RawLocListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, +} + +impl LocListIter { + /// Construct a `LocListIter`. + fn new( + raw: RawLocListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> LocListIter { + LocListIter { + raw, + base_address, + debug_addr, + debug_addr_base, + } + } + + #[inline] + fn get_address(&self, index: DebugAddrIndex) -> Result { + self.debug_addr + .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) + } + + /// Advance the iterator to the next location. + pub fn next(&mut self) -> Result>> { + loop { + let raw_loc = match self.raw.next()? { + Some(loc) => loc, + None => return Ok(None), + }; + + let loc = self.convert_raw(raw_loc)?; + if loc.is_some() { + return Ok(loc); + } + } + } + + /// Return the next raw location. + /// + /// The raw location should be passed to `convert_raw`. + #[doc(hidden)] + pub fn next_raw(&mut self) -> Result>> { + self.raw.next() + } + + /// Convert a raw location into a location, and update the state of the iterator. + /// + /// The raw location should have been obtained from `next_raw`. + #[doc(hidden)] + pub fn convert_raw( + &mut self, + raw_loc: RawLocListEntry, + ) -> Result>> { + let address_size = self.raw.encoding.address_size; + let mask = u64::ones_sized(address_size); + let tombstone = if self.raw.encoding.version <= 4 { + mask - 1 + } else { + mask + }; + + let (range, data) = match raw_loc { + RawLocListEntry::BaseAddress { addr } => { + self.base_address = addr; + return Ok(None); + } + RawLocListEntry::BaseAddressx { addr } => { + self.base_address = self.get_address(addr)?; + return Ok(None); + } + RawLocListEntry::StartxEndx { begin, end, data } => { + let begin = self.get_address(begin)?; + let end = self.get_address(end)?; + (Range { begin, end }, data) + } + RawLocListEntry::StartxLength { + begin, + length, + data, + } => { + let begin = self.get_address(begin)?; + let end = begin.wrapping_add_sized(length, address_size); + (Range { begin, end }, data) + } + RawLocListEntry::DefaultLocation { data } => ( + Range { + begin: 0, + end: u64::MAX, + }, + data, + ), + RawLocListEntry::AddressOrOffsetPair { begin, end, data } + | RawLocListEntry::OffsetPair { begin, end, data } => { + // Skip tombstone entries (see below). + if self.base_address == tombstone { + return Ok(None); + } + let mut range = Range { begin, end }; + range.add_base_address(self.base_address, self.raw.encoding.address_size); + (range, data) + } + RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data), + RawLocListEntry::StartLength { + begin, + length, + data, + } => { + let end = begin.wrapping_add_sized(length, address_size); + (Range { begin, end }, data) + } + }; + + // Skip tombstone entries. + // + // DWARF specifies a tombstone value of -1 or -2, but many linkers use 0 or 1. + // However, 0/1 may be a valid address, so we can't always reliably skip them. + // One case where we can skip them is for address pairs, where both values are + // replaced by tombstones and thus `begin` equals `end`. Since these entries + // are empty, it's safe to skip them even if they aren't tombstones. + // + // In addition to skipping tombstone entries, we also skip invalid entries + // where `begin` is greater than `end`. This can occur due to compiler bugs. + if range.begin == tombstone || range.begin >= range.end { + return Ok(None); + } + + Ok(Some(LocationListEntry { range, data })) + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for LocListIter { + type Item = LocationListEntry; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + LocListIter::next(self) + } +} + +/// A location list entry from the `.debug_loc` or `.debug_loclists` sections. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocationListEntry { + /// The address range that this location is valid for. + pub range: Range, + + /// The data containing a single location description. + pub data: Expression, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::Format; + use crate::constants::*; + use crate::endianity::LittleEndian; + use crate::read::{EndianSlice, Range}; + use crate::test_util::GimliSectionMethods; + use alloc::vec::Vec; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + #[test] + fn test_loclists() { + let format = Format::Dwarf32; + for size in [4, 8] { + let tombstone = u64::ones_sized(size); + let tombstone_0 = 0; + let encoding = Encoding { + format, + version: 5, + address_size: size, + }; + + let section = Section::with_endian(Endian::Little) + .word(size, 0x0300_0000) + .word(size, 0x0301_0300) + .word(size, 0x0301_0400) + .word(size, 0x0301_0500) + .word(size, tombstone) + .word(size, 0x0301_0600) + .word(size, tombstone_0); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .initial_length(format, &length, &start) + .L16(encoding.version) + .L8(encoding.address_size) + .L8(0) + .L32(0) + .mark(&first); + + let mut expected_locations = Vec::new(); + let mut expect_location = |begin, end, data| { + expected_locations.push(LocationListEntry { + range: Range { begin, end }, + data: Expression(EndianSlice::new(data, LittleEndian)), + }); + }; + + // An offset pair using the unit base address. + section = section.L8(DW_LLE_offset_pair.0).uleb(0x10200).uleb(0x10300); + section = section.uleb(4).L32(2); + expect_location(0x0101_0200, 0x0101_0300, &[2, 0, 0, 0]); + + section = section.L8(DW_LLE_base_address.0).word(size, 0x0200_0000); + section = section.L8(DW_LLE_offset_pair.0).uleb(0x10400).uleb(0x10500); + section = section.uleb(4).L32(3); + expect_location(0x0201_0400, 0x0201_0500, &[3, 0, 0, 0]); + + section = section + .L8(DW_LLE_start_end.0) + .word(size, 0x201_0a00) + .word(size, 0x201_0b00); + section = section.uleb(4).L32(6); + expect_location(0x0201_0a00, 0x0201_0b00, &[6, 0, 0, 0]); + + section = section + .L8(DW_LLE_start_length.0) + .word(size, 0x201_0c00) + .uleb(0x100); + section = section.uleb(4).L32(7); + expect_location(0x0201_0c00, 0x0201_0d00, &[7, 0, 0, 0]); + + // An offset pair that starts at 0. + section = section.L8(DW_LLE_base_address.0).word(size, 0); + section = section.L8(DW_LLE_offset_pair.0).uleb(0).uleb(1); + section = section.uleb(4).L32(8); + expect_location(0, 1, &[8, 0, 0, 0]); + + // An offset pair that ends at -1. + section = section.L8(DW_LLE_base_address.0).word(size, 0); + section = section.L8(DW_LLE_offset_pair.0).uleb(0).uleb(tombstone); + section = section.uleb(4).L32(9); + expect_location(0, tombstone, &[9, 0, 0, 0]); + + section = section.L8(DW_LLE_default_location.0).uleb(4).L32(10); + expect_location(0, u64::MAX, &[10, 0, 0, 0]); + + section = section.L8(DW_LLE_base_addressx.0).uleb(0); + section = section.L8(DW_LLE_offset_pair.0).uleb(0x10100).uleb(0x10200); + section = section.uleb(4).L32(11); + expect_location(0x0301_0100, 0x0301_0200, &[11, 0, 0, 0]); + + section = section.L8(DW_LLE_startx_endx.0).uleb(1).uleb(2); + section = section.uleb(4).L32(12); + expect_location(0x0301_0300, 0x0301_0400, &[12, 0, 0, 0]); + + section = section.L8(DW_LLE_startx_length.0).uleb(3).uleb(0x100); + section = section.uleb(4).L32(13); + expect_location(0x0301_0500, 0x0301_0600, &[13, 0, 0, 0]); + + // Tombstone entries, all of which should be ignored. + section = section.L8(DW_LLE_base_addressx.0).uleb(4); + section = section.L8(DW_LLE_offset_pair.0).uleb(0x11100).uleb(0x11200); + section = section.uleb(4).L32(20); + + section = section.L8(DW_LLE_base_address.0).word(size, tombstone); + section = section.L8(DW_LLE_offset_pair.0).uleb(0x11300).uleb(0x11400); + section = section.uleb(4).L32(21); + + section = section.L8(DW_LLE_startx_endx.0).uleb(4).uleb(5); + section = section.uleb(4).L32(22); + section = section.L8(DW_LLE_startx_length.0).uleb(4).uleb(0x100); + section = section.uleb(4).L32(23); + section = section + .L8(DW_LLE_start_end.0) + .word(size, tombstone) + .word(size, 0x201_1500); + section = section.uleb(4).L32(24); + section = section + .L8(DW_LLE_start_length.0) + .word(size, tombstone) + .uleb(0x100); + section = section.uleb(4).L32(25); + + // Ignore some instances of 0 for tombstone. + section = section.L8(DW_LLE_startx_endx.0).uleb(6).uleb(6); + section = section.uleb(4).L32(30); + section = section + .L8(DW_LLE_start_end.0) + .word(size, tombstone_0) + .word(size, tombstone_0); + section = section.uleb(4).L32(31); + + // Ignore empty ranges. + section = section.L8(DW_LLE_base_address.0).word(size, 0); + section = section.L8(DW_LLE_offset_pair.0).uleb(0).uleb(0); + section = section.uleb(4).L32(41); + section = section.L8(DW_LLE_base_address.0).word(size, 0x10000); + section = section.L8(DW_LLE_offset_pair.0).uleb(0x1234).uleb(0x1234); + section = section.uleb(4).L32(42); + + // A valid range after the tombstones. + section = section + .L8(DW_LLE_start_end.0) + .word(size, 0x201_1600) + .word(size, 0x201_1700); + section = section.uleb(4).L32(100); + expect_location(0x0201_1600, 0x0201_1700, &[100, 0, 0, 0]); + + section = section.L8(DW_LLE_end_of_list.0); + section = section.mark(&end); + // Some extra data. + section = section.word(size, 0x1234_5678); + length.set_const((&end - &start) as u64); + + let offset = LocationListsOffset((&first - §ion.start()) as usize); + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&[], LittleEndian); + let debug_loclists = DebugLocLists::new(&buf, LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists); + let mut locations = loclists + .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); + + for expected_location in expected_locations { + let location = locations.next(); + assert_eq!( + location, + Ok(Some(expected_location)), + "read {:x?}, expect {:x?}", + location, + expected_location + ); + } + assert_eq!(locations.next(), Ok(None)); + } + } + + #[test] + fn test_location_list() { + for size in [4, 8] { + let base = u64::ones_sized(size); + let tombstone = u64::ones_sized(size) - 1; + let start = Label::new(); + let first = Label::new(); + let mut section = Section::with_endian(Endian::Little) + // A location before the offset. + .mark(&start) + .word(size, 0x10000) + .word(size, 0x10100) + .L16(4) + .L32(1) + .mark(&first); + + let mut expected_locations = Vec::new(); + let mut expect_location = |begin, end, data| { + expected_locations.push(LocationListEntry { + range: Range { begin, end }, + data: Expression(EndianSlice::new(data, LittleEndian)), + }); + }; + + // A normal location. + section = section.word(size, 0x10200).word(size, 0x10300); + section = section.L16(4).L32(2); + expect_location(0x0101_0200, 0x0101_0300, &[2, 0, 0, 0]); + // A base address selection followed by a normal location. + section = section.word(size, base).word(size, 0x0200_0000); + section = section.word(size, 0x10400).word(size, 0x10500); + section = section.L16(4).L32(3); + expect_location(0x0201_0400, 0x0201_0500, &[3, 0, 0, 0]); + // An empty location range followed by a normal location. + section = section.word(size, 0x10600).word(size, 0x10600); + section = section.L16(4).L32(4); + section = section.word(size, 0x10800).word(size, 0x10900); + section = section.L16(4).L32(5); + expect_location(0x0201_0800, 0x0201_0900, &[5, 0, 0, 0]); + // A location range that starts at 0. + section = section.word(size, base).word(size, 0); + section = section.word(size, 0).word(size, 1); + section = section.L16(4).L32(6); + expect_location(0, 1, &[6, 0, 0, 0]); + // A location range that ends at -1. + section = section.word(size, base).word(size, 0); + section = section.word(size, 0).word(size, base); + section = section.L16(4).L32(7); + expect_location(0, base, &[7, 0, 0, 0]); + // A normal location with tombstone. + section = section.word(size, tombstone).word(size, tombstone); + section = section.L16(4).L32(8); + // A base address selection with tombstone followed by a normal location. + section = section.word(size, base).word(size, tombstone); + section = section.word(size, 0x10a00).word(size, 0x10b00); + section = section.L16(4).L32(9); + // A location list end. + section = section.word(size, 0).word(size, 0); + // Some extra data. + section = section.word(size, 0x1234_5678); + + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists); + let offset = LocationListsOffset((&first - &start) as usize); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: size, + }; + let mut locations = loclists + .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); + + for expected_location in expected_locations { + let location = locations.next(); + assert_eq!( + location, + Ok(Some(expected_location)), + "read {:x?}, expect {:x?}", + location, + expected_location + ); + } + assert_eq!(locations.next(), Ok(None)); + + // An offset at the end of buf. + let mut locations = loclists + .locations( + LocationListsOffset(buf.len()), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(locations.next(), Ok(None)); + } + } + + #[test] + fn test_locations_invalid() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + // An invalid location range. + .L32(0x20000).L32(0x10000).L16(4).L32(1) + // An invalid range after wrapping. + .L32(0x20000).L32(0xff01_0000).L16(4).L32(2); + + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + + // An invalid location range. + let mut locations = loclists + .locations( + LocationListsOffset(0x0), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(locations.next(), Ok(None)); + + // An invalid location range after wrapping. + let mut locations = loclists + .locations( + LocationListsOffset(14), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(locations.next(), Ok(None)); + + // An invalid offset. + match loclists.locations( + LocationListsOffset(buf.len() + 1), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_get_offset() { + for format in [Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version: 5, + address_size: 4, + }; + + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(encoding.version) + .D8(encoding.address_size) + .D8(0) + .D32(20) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + let section = section.get_contents().unwrap(); + + let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian)); + let debug_loclists = DebugLocLists::from(EndianSlice::new(§ion, LittleEndian)); + let locations = LocationLists::new(debug_loc, debug_loclists); + + let base = DebugLocListsBase((&first - &zero) as usize); + assert_eq!( + locations.get_offset(encoding, base, DebugLocListsIndex(0)), + Ok(LocationListsOffset(base.0 + 1000)) + ); + assert_eq!( + locations.get_offset(encoding, base, DebugLocListsIndex(19)), + Ok(LocationListsOffset(base.0 + 1019)) + ); + } + } + + #[test] + fn test_loclists_gnu_v4_split_dwarf() { + #[rustfmt::skip] + let buf = [ + 0x03, // DW_LLE_startx_length + 0x00, // ULEB encoded b7 + 0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8 + 0x03, 0x00, // Fixed two byte length of the location + 0x11, 0x00, // DW_OP_constu 0 + 0x9f, // DW_OP_stack_value + // Padding data + //0x99, 0x99, 0x99, 0x99 + ]; + let data_buf = [0x11, 0x00, 0x9f]; + let expected_data = EndianSlice::new(&data_buf, LittleEndian); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists); + let debug_addr = + &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + + // An invalid location range. + let mut locations = loclists + .locations_dwo( + LocationListsOffset(0x0), + encoding, + 0, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0209 + }, + data: Expression(expected_data), + })) + ); + } +} diff --git a/deps/crates/vendor/gimli/src/read/lookup.rs b/deps/crates/vendor/gimli/src/read/lookup.rs new file mode 100644 index 00000000000000..1d082f24f495cc --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/lookup.rs @@ -0,0 +1,202 @@ +use core::marker::PhantomData; + +use crate::common::{DebugInfoOffset, Format}; +use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset}; + +// The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have +// similar structures. They consist of a header with metadata and an offset into the +// .debug_info section for the entire compilation unit, and a series +// of following entries that list addresses (for .debug_aranges) or names +// (for .debug_pubnames and .debug_pubtypes) that are covered. +// +// Because these three tables all have similar structures, we abstract out some of +// the parsing mechanics. + +pub trait LookupParser { + /// The type of the produced header. + type Header; + /// The type of the produced entry. + type Entry; + + /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries + /// corresponding to this header (without the header itself), and the parsed representation of + /// the header itself. + fn parse_header(input: &mut R) -> Result<(R, Self::Header)>; + + /// Parse a single entry from `input`. Returns either a parsed representation of the entry + /// or None if `input` is exhausted. + fn parse_entry(input: &mut R, header: &Self::Header) -> Result>; +} + +#[derive(Clone, Debug)] +pub struct DebugLookup +where + R: Reader, + Parser: LookupParser, +{ + input_buffer: R, + phantom: PhantomData, +} + +impl From for DebugLookup +where + R: Reader, + Parser: LookupParser, +{ + fn from(input_buffer: R) -> Self { + DebugLookup { + input_buffer, + phantom: PhantomData, + } + } +} + +impl DebugLookup +where + R: Reader, + Parser: LookupParser, +{ + pub fn items(&self) -> LookupEntryIter { + LookupEntryIter { + current_set: None, + remaining_input: self.input_buffer.clone(), + } + } + + pub fn reader(&self) -> &R { + &self.input_buffer + } +} + +#[derive(Clone, Debug)] +pub struct LookupEntryIter +where + R: Reader, + Parser: LookupParser, +{ + current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end. + remaining_input: R, +} + +impl LookupEntryIter +where + R: Reader, + Parser: LookupParser, +{ + /// Advance the iterator and return the next entry. + /// + /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns + /// `Ok(None)` when iteration is complete and all entries have already been + /// parsed and yielded. If an error occurs while parsing the next entry, + /// then this error is returned as `Err(e)`, and all subsequent calls return + /// `Ok(None)`. + /// + /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn next(&mut self) -> Result> { + loop { + if let Some((ref mut input, ref header)) = self.current_set { + if !input.is_empty() { + match Parser::parse_entry(input, header) { + Ok(Some(entry)) => return Ok(Some(entry)), + Ok(None) => {} + Err(e) => { + input.empty(); + self.remaining_input.empty(); + return Err(e); + } + } + } + } + if self.remaining_input.is_empty() { + self.current_set = None; + return Ok(None); + } + match Parser::parse_header(&mut self.remaining_input) { + Ok(set) => { + self.current_set = Some(set); + } + Err(e) => { + self.current_set = None; + self.remaining_input.empty(); + return Err(e); + } + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PubStuffHeader { + format: Format, + length: T, + version: u16, + unit_offset: DebugInfoOffset, + unit_length: T, +} + +pub trait PubStuffEntry { + fn new( + die_offset: UnitOffset, + name: R, + unit_header_offset: DebugInfoOffset, + ) -> Self; +} + +#[derive(Clone, Debug)] +pub struct PubStuffParser +where + R: Reader, + Entry: PubStuffEntry, +{ + // This struct is never instantiated. + phantom: PhantomData<(R, Entry)>, +} + +impl LookupParser for PubStuffParser +where + R: Reader, + Entry: PubStuffEntry, +{ + type Header = PubStuffHeader; + type Entry = Entry; + + /// Parse an pubthings set header. Returns a tuple of the + /// pubthings to be parsed for this set, and the newly created PubThingHeader struct. + fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { + let (length, format) = input.read_initial_length()?; + let mut rest = input.split(length)?; + + let version = rest.read_u16()?; + if version != 2 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + let unit_offset = parse_debug_info_offset(&mut rest, format)?; + let unit_length = rest.read_length(format)?; + + let header = PubStuffHeader { + format, + length, + version, + unit_offset, + unit_length, + }; + Ok((rest, header)) + } + + /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing. + fn parse_entry(input: &mut R, header: &Self::Header) -> Result> { + let offset = input.read_offset(header.format)?; + if offset.into_u64() == 0 { + input.empty(); + Ok(None) + } else { + let name = input.read_null_terminated_slice()?; + Ok(Some(Self::Entry::new( + UnitOffset(offset), + name, + header.unit_offset, + ))) + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/mod.rs b/deps/crates/vendor/gimli/src/read/mod.rs new file mode 100644 index 00000000000000..5c2b6cc8090e8a --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/mod.rs @@ -0,0 +1,850 @@ +//! Read DWARF debugging information. +//! +//! * [Example Usage](#example-usage) +//! * [API Structure](#api-structure) +//! * [Using with `FallibleIterator`](#using-with-fallibleiterator) +//! +//! ## Example Usage +//! +//! Print out all of the functions in the debuggee program: +//! +//! ```rust,no_run +//! # fn example() -> Result<(), gimli::Error> { +//! # type R = gimli::EndianSlice<'static, gimli::LittleEndian>; +//! # let get_file_section_reader = |name| -> Result { unimplemented!() }; +//! # let get_sup_file_section_reader = |name| -> Result { unimplemented!() }; +//! // Read the DWARF sections with whatever object loader you're using. +//! // These closures should return a `Reader` instance (e.g. `EndianSlice`). +//! let loader = |section: gimli::SectionId| { get_file_section_reader(section.name()) }; +//! let sup_loader = |section: gimli::SectionId| { get_sup_file_section_reader(section.name()) }; +//! let mut dwarf = gimli::Dwarf::load(loader)?; +//! dwarf.load_sup(sup_loader)?; +//! +//! // Iterate over all compilation units. +//! let mut iter = dwarf.units(); +//! while let Some(header) = iter.next()? { +//! // Parse the abbreviations and other information for this compilation unit. +//! let unit = dwarf.unit(header)?; +//! +//! // Iterate over all of this compilation unit's entries. +//! let mut entries = unit.entries(); +//! while let Some((_, entry)) = entries.next_dfs()? { +//! // If we find an entry for a function, print it. +//! if entry.tag() == gimli::DW_TAG_subprogram { +//! println!("Found a function: {:?}", entry); +//! } +//! } +//! } +//! # unreachable!() +//! # } +//! ``` +//! +//! Full example programs: +//! +//! * [A simple parser](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/simple.rs) +//! +//! * [A `dwarfdump` +//! clone](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarfdump.rs) +//! +//! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) +//! +//! * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into +//! code generation by making debugging information readable +//! +//! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the +//! compilers used to create each compilation unit within a shared library or +//! executable (via `DW_AT_producer`) +//! +//! * [`dwarf-validate`](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarf-validate.rs), +//! a program to validate the integrity of some DWARF and its references +//! between sections and compilation units. +//! +//! ## API Structure +//! +//! * Basic familiarity with DWARF is assumed. +//! +//! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF +//! sections. It has methods that simplify access to debugging data that spans +//! multiple sections. Use of this type is optional, but recommended. +//! +//! * The [`DwarfPackage`](./struct.Dwarf.html) type contains the DWARF +//! package (DWP) sections. It has methods to find a DWARF object (DWO) +//! within the package. +//! +//! * Each section gets its own type. Consider these types the entry points to +//! the library: +//! +//! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section. +//! +//! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section. +//! +//! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges` +//! section. +//! +//! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section. +//! +//! * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section. +//! +//! * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section. +//! +//! * [`DebugLineStr`](./struct.DebugLineStr.html): The `.debug_line_str` section. +//! +//! * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section. +//! +//! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section. +//! +//! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames` +//! section. +//! +//! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes` +//! section. +//! +//! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section. +//! +//! * [`DebugRngLists`](./struct.DebugRngLists.html): The `.debug_rnglists` section. +//! +//! * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section. +//! +//! * [`DebugStrOffsets`](./struct.DebugStrOffsets.html): The `.debug_str_offsets` section. +//! +//! * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section. +//! +//! * [`DebugCuIndex`](./struct.DebugCuIndex.html): The `.debug_cu_index` section. +//! +//! * [`DebugTuIndex`](./struct.DebugTuIndex.html): The `.debug_tu_index` section. +//! +//! * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section. +//! +//! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section. +//! +//! * Each section type exposes methods for accessing the debugging data encoded +//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) +//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for +//! iterating over the compilation units defined within it. +//! +//! * Offsets into a section are strongly typed: an offset into `.debug_info` is +//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be +//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because +//! `DebugLine` represents the `.debug_line` section. There are similar types +//! for offsets relative to a compilation unit rather than a section. +//! +//! ## Using with `FallibleIterator` +//! +//! The standard library's `Iterator` trait and related APIs do not play well +//! with iterators where the `next` operation is fallible. One can make the +//! `Iterator`'s associated `Item` type be a `Result`, however the +//! provided methods cannot gracefully handle the case when an `Err` is +//! returned. +//! +//! This situation led to the +//! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's +//! existence. You can read more of the rationale for its existence in its +//! docs. The crate provides the helpers you have come to expect (eg `map`, +//! `filter`, etc) for iterators that can fail. +//! +//! `gimli`'s many lazy parsing iterators are a perfect match for the +//! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not +//! done eagerly. Parse errors later in the input might only be discovered after +//! having iterated through many items. +//! +//! To use `gimli` iterators with `FallibleIterator`, import the crate and trait +//! into your code: +//! +//! ``` +//! # #[cfg(feature = "fallible-iterator")] +//! # fn foo() { +//! // Use the `FallibleIterator` trait so its methods are in scope! +//! use fallible_iterator::FallibleIterator; +//! use gimli::{DebugAranges, EndianSlice, LittleEndian}; +//! +//! fn find_sum_of_address_range_lengths(aranges: DebugAranges>) +//! -> gimli::Result +//! { +//! // `DebugAranges::headers` returns a `FallibleIterator`! +//! aranges.headers() +//! // `flat_map` is provided by `FallibleIterator`! +//! .flat_map(|header| Ok(header.entries())) +//! // `map` is provided by `FallibleIterator`! +//! .map(|arange| Ok(arange.length())) +//! // `fold` is provided by `FallibleIterator`! +//! .fold(0, |sum, len| Ok(sum + len)) +//! } +//! # } +//! # fn main() {} +//! ``` + +use core::fmt::{self, Debug}; +use core::result; +#[cfg(feature = "std")] +use std::{error, io}; + +use crate::common::{Register, SectionId}; +use crate::constants; + +mod util; +pub use util::*; + +mod addr; +pub use self::addr::*; + +mod cfi; +pub use self::cfi::*; + +#[cfg(feature = "read")] +mod dwarf; +#[cfg(feature = "read")] +pub use self::dwarf::*; + +mod endian_slice; +pub use self::endian_slice::*; + +#[cfg(feature = "endian-reader")] +mod endian_reader; +#[cfg(feature = "endian-reader")] +pub use self::endian_reader::*; + +mod reader; +pub use self::reader::*; + +mod relocate; +pub use self::relocate::*; + +#[cfg(feature = "read")] +mod abbrev; +#[cfg(feature = "read")] +pub use self::abbrev::*; + +mod aranges; +pub use self::aranges::*; + +mod index; +pub use self::index::*; + +#[cfg(feature = "read")] +mod line; +#[cfg(feature = "read")] +pub use self::line::*; + +mod lists; + +mod loclists; +pub use self::loclists::*; + +#[cfg(feature = "read")] +mod lookup; + +mod op; +pub use self::op::*; + +#[cfg(feature = "read")] +mod pubnames; +#[cfg(feature = "read")] +pub use self::pubnames::*; + +#[cfg(feature = "read")] +mod pubtypes; +#[cfg(feature = "read")] +pub use self::pubtypes::*; + +mod rnglists; +pub use self::rnglists::*; + +mod str; +pub use self::str::*; + +/// An offset into the current compilation or type unit. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct UnitOffset(pub T); + +#[cfg(feature = "read")] +mod unit; +#[cfg(feature = "read")] +pub use self::unit::*; + +mod value; +pub use self::value::*; + +/// Indicates that storage should be allocated on heap. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct StoreOnHeap; + +/// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across +/// `gimli` versions, we export this type alias. +#[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")] +pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; + +/// An error that occurred when parsing. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum Error { + /// An I/O error occurred while reading. + Io, + /// Found a PC relative pointer, but the section base is undefined. + PcRelativePointerButSectionBaseIsUndefined, + /// Found a `.text` relative pointer, but the `.text` base is undefined. + TextRelativePointerButTextBaseIsUndefined, + /// Found a data relative pointer, but the data base is undefined. + DataRelativePointerButDataBaseIsUndefined, + /// Found a function relative pointer in a context that does not have a + /// function base. + FuncRelativePointerInBadContext, + /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding. + CannotParseOmitPointerEncoding, + /// An error parsing an unsigned LEB128 value. + BadUnsignedLeb128, + /// An error parsing a signed LEB128 value. + BadSignedLeb128, + /// An abbreviation declared that its tag is zero, but zero is reserved for + /// null records. + AbbreviationTagZero, + /// An attribute specification declared that its form is zero, but zero is + /// reserved for null records. + AttributeFormZero, + /// The abbreviation's has-children byte was not one of + /// `DW_CHILDREN_{yes,no}`. + BadHasChildren, + /// The specified length is impossible. + BadLength, + /// Found an unknown `DW_FORM_*` type. + UnknownForm(constants::DwForm), + /// Expected a zero, found something else. + ExpectedZero, + /// Found an abbreviation code that has already been used. + DuplicateAbbreviationCode, + /// Found a duplicate arange. + DuplicateArange, + /// Found an unknown reserved length value. + UnknownReservedLength, + /// Found an unknown DWARF version. + UnknownVersion(u64), + /// Found a record with an unknown abbreviation code. + UnknownAbbreviation(u64), + /// Hit the end of input before it was expected. + UnexpectedEof(ReaderOffsetId), + /// Read a null entry before it was expected. + UnexpectedNull, + /// Found an unknown standard opcode. + UnknownStandardOpcode(constants::DwLns), + /// Found an unknown extended opcode. + UnknownExtendedOpcode(constants::DwLne), + /// Found an unknown location-lists format. + UnknownLocListsEntry(constants::DwLle), + /// Found an unknown range-lists format. + UnknownRangeListsEntry(constants::DwRle), + /// The specified address size is not supported. + UnsupportedAddressSize(u8), + /// The specified offset size is not supported. + UnsupportedOffsetSize(u8), + /// The specified field size is not supported. + UnsupportedFieldSize(u8), + /// The minimum instruction length must not be zero. + MinimumInstructionLengthZero, + /// The maximum operations per instruction must not be zero. + MaximumOperationsPerInstructionZero, + /// The line range must not be zero. + LineRangeZero, + /// The opcode base must not be zero. + OpcodeBaseZero, + /// Found an invalid UTF-8 string. + BadUtf8, + /// Expected to find the CIE ID, but found something else. + NotCieId, + /// Expected to find a pointer to a CIE, but found the CIE ID instead. + NotCiePointer, + /// Expected to find a pointer to an FDE, but found a CIE instead. + NotFdePointer, + /// Invalid branch target for a DW_OP_bra or DW_OP_skip. + BadBranchTarget(u64), + /// DW_OP_push_object_address used but no address passed in. + InvalidPushObjectAddress, + /// Not enough items on the stack when evaluating an expression. + NotEnoughStackItems, + /// Too many iterations to compute the expression. + TooManyIterations, + /// An unrecognized operation was found while parsing a DWARF + /// expression. + InvalidExpression(constants::DwOp), + /// An unsupported operation was found while evaluating a DWARF expression. + UnsupportedEvaluation, + /// The expression had a piece followed by an expression + /// terminator without a piece. + InvalidPiece, + /// An expression-terminating operation was followed by something + /// other than the end of the expression or a piece operation. + InvalidExpressionTerminator(u64), + /// Division or modulus by zero when evaluating an expression. + DivisionByZero, + /// An expression operation used mismatching types. + TypeMismatch, + /// An expression operation required an integral type but saw a + /// floating point type. + IntegralTypeRequired, + /// An expression operation used types that are not supported. + UnsupportedTypeOperation, + /// The shift value in an expression must be a non-negative integer. + InvalidShiftExpression, + /// The size of a deref expression must not be larger than the size of an address. + InvalidDerefSize(u8), + /// An unknown DW_CFA_* instruction. + UnknownCallFrameInstruction(constants::DwCfa), + /// The end of an address range was before the beginning. + InvalidAddressRange, + /// An address calculation overflowed. + /// + /// This is returned in cases where the address is expected to be + /// larger than a previous address, but the calculation overflowed. + AddressOverflow, + /// Encountered a call frame instruction in a context in which it is not + /// valid. + CfiInstructionInInvalidContext, + /// When evaluating call frame instructions, found a `DW_CFA_restore_state` + /// stack pop instruction, but the stack was empty, and had nothing to pop. + PopWithEmptyStack, + /// Do not have unwind info for the given address. + NoUnwindInfoForAddress, + /// An offset value was larger than the maximum supported value. + UnsupportedOffset, + /// The given pointer encoding is either unknown or invalid. + UnknownPointerEncoding(constants::DwEhPe), + /// Did not find an entry at the given offset. + NoEntryAtGivenOffset, + /// The given offset is out of bounds. + OffsetOutOfBounds, + /// Found an unknown CFI augmentation. + UnknownAugmentation, + /// We do not support the given pointer encoding yet. + UnsupportedPointerEncoding, + /// Registers larger than `u16` are not supported. + UnsupportedRegister(u64), + /// The CFI program defined more register rules than we have storage for. + TooManyRegisterRules, + /// Attempted to push onto the CFI or evaluation stack, but it was already + /// at full capacity. + StackFull, + /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded, + /// which makes binary search impossible. + VariableLengthSearchTable, + /// The `DW_UT_*` value for this unit is not supported yet. + UnsupportedUnitType, + /// Ranges using AddressIndex are not supported yet. + UnsupportedAddressIndex, + /// Nonzero segment selector sizes aren't supported yet. + UnsupportedSegmentSize, + /// A compilation unit or type unit is missing its top level DIE. + MissingUnitDie, + /// A DIE attribute used an unsupported form. + UnsupportedAttributeForm, + /// Missing DW_LNCT_path in file entry format. + MissingFileEntryFormatPath, + /// Expected an attribute value to be a string form. + ExpectedStringAttributeValue, + /// `DW_FORM_implicit_const` used in an invalid context. + InvalidImplicitConst, + /// Invalid section count in `.dwp` index. + InvalidIndexSectionCount, + /// Invalid slot count in `.dwp` index. + InvalidIndexSlotCount, + /// Invalid hash row in `.dwp` index. + InvalidIndexRow, + /// Unknown section type in `.dwp` index. + UnknownIndexSection(constants::DwSect), + /// Unknown section type in version 2 `.dwp` index. + UnknownIndexSectionV2(constants::DwSectV2), +} + +impl fmt::Display for Error { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> ::core::result::Result<(), fmt::Error> { + write!(f, "{}", self.description()) + } +} + +impl Error { + /// A short description of the error. + pub fn description(&self) -> &str { + match *self { + Error::Io => "An I/O error occurred while reading.", + Error::PcRelativePointerButSectionBaseIsUndefined => { + "Found a PC relative pointer, but the section base is undefined." + } + Error::TextRelativePointerButTextBaseIsUndefined => { + "Found a `.text` relative pointer, but the `.text` base is undefined." + } + Error::DataRelativePointerButDataBaseIsUndefined => { + "Found a data relative pointer, but the data base is undefined." + } + Error::FuncRelativePointerInBadContext => { + "Found a function relative pointer in a context that does not have a function base." + } + Error::CannotParseOmitPointerEncoding => { + "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." + } + Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", + Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", + Error::AbbreviationTagZero => { + "An abbreviation declared that its tag is zero, + but zero is reserved for null records" + } + Error::AttributeFormZero => { + "An attribute specification declared that its form is zero, + but zero is reserved for null records" + } + Error::BadHasChildren => { + "The abbreviation's has-children byte was not one of + `DW_CHILDREN_{yes,no}`" + } + Error::BadLength => "The specified length is impossible", + Error::UnknownForm(_) => "Found an unknown `DW_FORM_*` type", + Error::ExpectedZero => "Expected a zero, found something else", + Error::DuplicateAbbreviationCode => { + "Found an abbreviation code that has already been used" + } + Error::DuplicateArange => "Found a duplicate arange", + Error::UnknownReservedLength => "Found an unknown reserved length value", + Error::UnknownVersion(_) => "Found an unknown DWARF version", + Error::UnknownAbbreviation(_) => "Found a record with an unknown abbreviation code", + Error::UnexpectedEof(_) => "Hit the end of input before it was expected", + Error::UnexpectedNull => "Read a null entry before it was expected.", + Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", + Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", + Error::UnknownLocListsEntry(_) => "Found an unknown location lists entry", + Error::UnknownRangeListsEntry(_) => "Found an unknown range lists entry", + Error::UnsupportedAddressSize(_) => "The specified address size is not supported", + Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", + Error::UnsupportedFieldSize(_) => "The specified field size is not supported", + Error::MinimumInstructionLengthZero => { + "The minimum instruction length must not be zero." + } + Error::MaximumOperationsPerInstructionZero => { + "The maximum operations per instruction must not be zero." + } + Error::LineRangeZero => "The line range must not be zero.", + Error::OpcodeBaseZero => "The opcode base must not be zero.", + Error::BadUtf8 => "Found an invalid UTF-8 string.", + Error::NotCieId => "Expected to find the CIE ID, but found something else.", + Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", + Error::NotFdePointer => { + "Expected to find an FDE pointer, but found a CIE pointer instead." + } + Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", + Error::InvalidPushObjectAddress => { + "DW_OP_push_object_address used but no object address given" + } + Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", + Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", + Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", + Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression", + Error::InvalidPiece => { + "DWARF expression has piece followed by non-piece expression at end" + } + Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", + Error::DivisionByZero => "Division or modulus by zero when evaluating expression", + Error::TypeMismatch => "Type mismatch when evaluating expression", + Error::IntegralTypeRequired => "Integral type expected when evaluating expression", + Error::UnsupportedTypeOperation => { + "An expression operation used types that are not supported" + } + Error::InvalidShiftExpression => { + "The shift value in an expression must be a non-negative integer." + } + Error::InvalidDerefSize(_) => { + "The size of a deref expression must not be larger than the size of an address." + } + Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", + Error::InvalidAddressRange => { + "The end of an address range must not be before the beginning." + } + Error::AddressOverflow => "An address calculation overflowed.", + Error::CfiInstructionInInvalidContext => { + "Encountered a call frame instruction in a context in which it is not valid." + } + Error::PopWithEmptyStack => { + "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ + instruction, but the stack was empty, and had nothing to pop." + } + Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", + Error::UnsupportedOffset => { + "An offset value was larger than the maximum supported value." + } + Error::UnknownPointerEncoding(_) => { + "The given pointer encoding is either unknown or invalid." + } + Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", + Error::OffsetOutOfBounds => "The given offset is out of bounds.", + Error::UnknownAugmentation => "Found an unknown CFI augmentation.", + Error::UnsupportedPointerEncoding => { + "We do not support the given pointer encoding yet." + } + Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", + Error::TooManyRegisterRules => { + "The CFI program defined more register rules than we have storage for." + } + Error::StackFull => { + "Attempted to push onto the CFI stack, but it was already at full capacity." + } + Error::VariableLengthSearchTable => { + "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ + which makes binary search impossible." + } + Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", + Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", + Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", + Error::MissingUnitDie => { + "A compilation unit or type unit is missing its top level DIE." + } + Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", + Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", + Error::ExpectedStringAttributeValue => { + "Expected an attribute value to be a string form." + } + Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.", + Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.", + Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.", + Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.", + Error::UnknownIndexSection(_) => "Unknown section type in `.dwp` index.", + Error::UnknownIndexSectionV2(_) => "Unknown section type in version 2 `.dwp` index.", + } + } +} + +#[cfg(feature = "std")] +impl error::Error for Error {} + +#[cfg(feature = "std")] +impl From for Error { + fn from(_: io::Error) -> Self { + Error::Io + } +} + +/// The result of a parse. +pub type Result = result::Result; + +/// A convenience trait for loading DWARF sections from object files. To be +/// used like: +/// +/// ``` +/// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; +/// +/// let buf = [0x00, 0x01, 0x02, 0x03]; +/// let reader = EndianSlice::new(&buf, LittleEndian); +/// let loader = |name| -> Result<_, ()> { Ok(reader) }; +/// +/// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); +/// ``` +pub trait Section: From { + /// Returns the section id for this type. + fn id() -> SectionId; + + /// Returns the ELF section name for this type. + fn section_name() -> &'static str { + Self::id().name() + } + + /// Returns the ELF section name (if any) for this type when used in a dwo + /// file. + fn dwo_section_name() -> Option<&'static str> { + Self::id().dwo_name() + } + + /// Returns the XCOFF section name (if any) for this type when used in a XCOFF + /// file. + fn xcoff_section_name() -> Option<&'static str> { + Self::id().xcoff_name() + } + + /// Try to load the section using the given loader function. + fn load(f: F) -> core::result::Result + where + F: FnOnce(SectionId) -> core::result::Result, + { + f(Self::id()).map(From::from) + } + + /// Returns the `Reader` for this section. + fn reader(&self) -> &R + where + R: Reader; + + /// Returns the subrange of the section that is the contribution of + /// a unit in a `.dwp` file. + fn dwp_range(&self, offset: u32, size: u32) -> Result + where + R: Reader, + { + let mut data = self.reader().clone(); + data.skip(R::Offset::from_u32(offset))?; + data.truncate(R::Offset::from_u32(size))?; + Ok(data.into()) + } + + /// Returns the `Reader` for this section. + fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> + where + R: Reader, + { + self.reader() + .lookup_offset_id(id) + .map(|offset| (Self::id(), offset)) + } +} + +impl Register { + pub(crate) fn from_u64(x: u64) -> Result { + let y = x as u16; + if u64::from(y) == x { + Ok(Register(y)) + } else { + Err(Error::UnsupportedRegister(x)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::Format; + use crate::endianity::LittleEndian; + use test_assembler::{Endian, Section}; + + #[test] + fn test_parse_initial_length_32_ok() { + let section = Section::with_endian(Endian::Little).L32(0x7856_3412); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_initial_length() { + Ok((length, format)) => { + assert_eq!(input.len(), 0); + assert_eq!(format, Format::Dwarf32); + assert_eq!(0x7856_3412, length); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_parse_initial_length_64_ok() { + let section = Section::with_endian(Endian::Little) + // Dwarf_64_INITIAL_UNIT_LENGTH + .L32(0xffff_ffff) + // Actual length + .L64(0xffde_bc9a_7856_3412); + let buf = section.get_contents().unwrap(); + let input = &mut EndianSlice::new(&buf, LittleEndian); + + #[cfg(target_pointer_width = "64")] + match input.read_initial_length() { + Ok((length, format)) => { + assert_eq!(input.len(), 0); + assert_eq!(format, Format::Dwarf64); + assert_eq!(0xffde_bc9a_7856_3412, length); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + + #[cfg(target_pointer_width = "32")] + match input.read_initial_length() { + Err(Error::UnsupportedOffset) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_initial_length_unknown_reserved_value() { + let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_initial_length() { + Err(Error::UnknownReservedLength) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_initial_length_incomplete() { + let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_initial_length() { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_initial_length_64_incomplete() { + let section = Section::with_endian(Endian::Little) + // Dwarf_64_INITIAL_UNIT_LENGTH + .L32(0xffff_ffff) + // Actual length is not long enough. + .L32(0x7856_3412); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_initial_length() { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_offset_32() { + let section = Section::with_endian(Endian::Little).L32(0x0123_4567); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_offset(Format::Dwarf32) { + Ok(val) => { + assert_eq!(input.len(), 0); + assert_eq!(val, 0x0123_4567); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_offset_64_small() { + let section = Section::with_endian(Endian::Little).L64(0x0123_4567); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_offset(Format::Dwarf64) { + Ok(val) => { + assert_eq!(input.len(), 0); + assert_eq!(val, 0x0123_4567); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_offset_64_large() { + let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_offset(Format::Dwarf64) { + Ok(val) => { + assert_eq!(input.len(), 0); + assert_eq!(val, 0x0123_4567_89ab_cdef); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn test_parse_offset_64_large() { + let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); + let buf = section.get_contents().unwrap(); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + match input.read_offset(Format::Dwarf64) { + Err(Error::UnsupportedOffset) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } +} diff --git a/deps/crates/vendor/gimli/src/read/op.rs b/deps/crates/vendor/gimli/src/read/op.rs new file mode 100644 index 00000000000000..0f9261a0599035 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/op.rs @@ -0,0 +1,4182 @@ +//! Functions for parsing and evaluating DWARF expressions. + +#[cfg(feature = "read")] +use alloc::vec::Vec; +use core::mem; + +use super::util::{ArrayLike, ArrayVec}; +use crate::common::{DebugAddrIndex, DebugInfoOffset, Encoding, Register}; +use crate::constants; +use crate::read::{Error, Reader, ReaderOffset, Result, StoreOnHeap, UnitOffset, Value, ValueType}; + +/// A reference to a DIE, either relative to the current CU or +/// relative to the section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DieReference { + /// A CU-relative reference. + UnitRef(UnitOffset), + /// A section-relative reference. + DebugInfoRef(DebugInfoOffset), +} + +/// A single decoded DWARF expression operation. +/// +/// DWARF expression evaluation is done in two parts: first the raw +/// bytes of the next part of the expression are decoded; and then the +/// decoded operation is evaluated. This approach lets other +/// consumers inspect the DWARF expression without reimplementing the +/// decoding operation. +/// +/// Multiple DWARF opcodes may decode into a single `Operation`. For +/// example, both `DW_OP_deref` and `DW_OP_xderef` are represented +/// using `Operation::Deref`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Operation::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// Dereference the topmost value of the stack. + Deref { + /// The DIE of the base type or 0 to indicate the generic type + base_type: UnitOffset, + /// The size of the data to dereference. + size: u8, + /// True if the dereference operation takes an address space + /// argument from the stack; false otherwise. + space: bool, + }, + /// Drop an item from the stack. + Drop, + /// Pick an item from the stack and push it on top of the stack. + /// This operation handles `DW_OP_pick`, `DW_OP_dup`, and + /// `DW_OP_over`. + Pick { + /// The index, from the top of the stack, of the item to copy. + index: u8, + }, + /// Swap the top two stack items. + Swap, + /// Rotate the top three stack items. + Rot, + /// Take the absolute value of the top of the stack. + Abs, + /// Bitwise `and` of the top two values on the stack. + And, + /// Divide the top two values on the stack. + Div, + /// Subtract the top two values on the stack. + Minus, + /// Modulus of the top two values on the stack. + Mod, + /// Multiply the top two values on the stack. + Mul, + /// Negate the top of the stack. + Neg, + /// Bitwise `not` of the top of the stack. + Not, + /// Bitwise `or` of the top two values on the stack. + Or, + /// Add the top two values on the stack. + Plus, + /// Add a constant to the topmost value on the stack. + PlusConstant { + /// The value to add. + value: u64, + }, + /// Logical left shift of the 2nd value on the stack by the number + /// of bits given by the topmost value on the stack. + Shl, + /// Right shift of the 2nd value on the stack by the number of + /// bits given by the topmost value on the stack. + Shr, + /// Arithmetic left shift of the 2nd value on the stack by the + /// number of bits given by the topmost value on the stack. + Shra, + /// Bitwise `xor` of the top two values on the stack. + Xor, + /// Branch to the target location if the top of stack is nonzero. + Bra { + /// The relative offset to the target bytecode. + target: i16, + }, + /// Compare the top two stack values for equality. + Eq, + /// Compare the top two stack values using `>=`. + Ge, + /// Compare the top two stack values using `>`. + Gt, + /// Compare the top two stack values using `<=`. + Le, + /// Compare the top two stack values using `<`. + Lt, + /// Compare the top two stack values using `!=`. + Ne, + /// Unconditional branch to the target location. + Skip { + /// The relative offset to the target bytecode. + target: i16, + }, + /// Push an unsigned constant value on the stack. This handles multiple + /// DWARF opcodes. + UnsignedConstant { + /// The value to push. + value: u64, + }, + /// Push a signed constant value on the stack. This handles multiple + /// DWARF opcodes. + SignedConstant { + /// The value to push. + value: i64, + }, + /// Indicate that this piece's location is in the given register. + /// + /// Completes the piece or expression. + Register { + /// The register number. + register: Register, + }, + /// Find the value of the given register, add the offset, and then + /// push the resulting sum on the stack. + RegisterOffset { + /// The register number. + register: Register, + /// The offset to add. + offset: i64, + /// The DIE of the base type or 0 to indicate the generic type + base_type: UnitOffset, + }, + /// Compute the frame base (using `DW_AT_frame_base`), add the + /// given offset, and then push the resulting sum on the stack. + FrameOffset { + /// The offset to add. + offset: i64, + }, + /// No operation. + Nop, + /// Push the object address on the stack. + PushObjectAddress, + /// Evaluate a DWARF expression as a subroutine. The expression + /// comes from the `DW_AT_location` attribute of the indicated + /// DIE. + Call { + /// The DIE to use. + offset: DieReference, + }, + /// Compute the address of a thread-local variable and push it on + /// the stack. + TLS, + /// Compute the call frame CFA and push it on the stack. + CallFrameCFA, + /// Terminate a piece. + Piece { + /// The size of this piece in bits. + size_in_bits: u64, + /// The bit offset of this piece. If `None`, then this piece + /// was specified using `DW_OP_piece` and should start at the + /// next byte boundary. + bit_offset: Option, + }, + /// The object has no location, but has a known constant value. + /// + /// Represents `DW_OP_implicit_value`. + /// Completes the piece or expression. + ImplicitValue { + /// The implicit value to use. + data: R, + }, + /// The object has no location, but its value is at the top of the stack. + /// + /// Represents `DW_OP_stack_value`. + /// Completes the piece or expression. + StackValue, + /// The object is a pointer to a value which has no actual location, + /// such as an implicit value or a stack value. + /// + /// Represents `DW_OP_implicit_pointer`. + /// Completes the piece or expression. + ImplicitPointer { + /// The `.debug_info` offset of the value that this is an implicit pointer into. + value: DebugInfoOffset, + /// The byte offset into the value that the implicit pointer points to. + byte_offset: i64, + }, + /// Evaluate an expression at the entry to the current subprogram, and push it on the stack. + /// + /// Represents `DW_OP_entry_value`. + EntryValue { + /// The expression to be evaluated. + expression: R, + }, + /// This represents a parameter that was optimized out. + /// + /// The offset points to the definition of the parameter, and is + /// matched to the `DW_TAG_GNU_call_site_parameter` in the caller that also + /// points to the same definition of the parameter. + /// + /// Represents `DW_OP_GNU_parameter_ref`. + ParameterRef { + /// The DIE to use. + offset: UnitOffset, + }, + /// Relocate the address if needed, and push it on the stack. + /// + /// Represents `DW_OP_addr`. + Address { + /// The offset to add. + address: u64, + }, + /// Read the address at the given index in `.debug_addr, relocate the address if needed, + /// and push it on the stack. + /// + /// Represents `DW_OP_addrx`. + AddressIndex { + /// The index of the address in `.debug_addr`. + index: DebugAddrIndex, + }, + /// Read the address at the given index in `.debug_addr, and push it on the stack. + /// Do not relocate the address. + /// + /// Represents `DW_OP_constx`. + ConstantIndex { + /// The index of the address in `.debug_addr`. + index: DebugAddrIndex, + }, + /// Interpret the value bytes as a constant of a given type, and push it on the stack. + /// + /// Represents `DW_OP_const_type`. + TypedLiteral { + /// The DIE of the base type. + base_type: UnitOffset, + /// The value bytes. + value: R, + }, + /// Pop the top stack entry, convert it to a different type, and push it on the stack. + /// + /// Represents `DW_OP_convert`. + Convert { + /// The DIE of the base type. + base_type: UnitOffset, + }, + /// Pop the top stack entry, reinterpret the bits in its value as a different type, + /// and push it on the stack. + /// + /// Represents `DW_OP_reinterpret`. + Reinterpret { + /// The DIE of the base type. + base_type: UnitOffset, + }, + /// The index of a local in the currently executing function. + /// + /// Represents `DW_OP_WASM_location 0x00`. + /// Completes the piece or expression. + WasmLocal { + /// The index of the local. + index: u32, + }, + /// The index of a global. + /// + /// Represents `DW_OP_WASM_location 0x01` or `DW_OP_WASM_location 0x03`. + /// Completes the piece or expression. + WasmGlobal { + /// The index of the global. + index: u32, + }, + /// The index of an item on the operand stack. + /// + /// Represents `DW_OP_WASM_location 0x02`. + /// Completes the piece or expression. + WasmStack { + /// The index of the stack item. 0 is the bottom of the operand stack. + index: u32, + }, +} + +#[derive(Debug)] +enum OperationEvaluationResult { + Piece, + Incomplete, + Complete { location: Location }, + Waiting(EvaluationWaiting, EvaluationResult), +} + +/// A single location of a piece of the result of a DWARF expression. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Location::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// The piece is empty. Ordinarily this means the piece has been + /// optimized away. + Empty, + /// The piece is found in a register. + Register { + /// The register number. + register: Register, + }, + /// The piece is found in memory. + Address { + /// The address. + address: u64, + }, + /// The piece has no location but its value is known. + Value { + /// The value. + value: Value, + }, + /// The piece is represented by some constant bytes. + Bytes { + /// The value. + value: R, + }, + /// The piece is a pointer to a value which has no actual location. + ImplicitPointer { + /// The `.debug_info` offset of the value that this is an implicit pointer into. + value: DebugInfoOffset, + /// The byte offset into the value that the implicit pointer points to. + byte_offset: i64, + }, +} + +impl Location +where + R: Reader, + Offset: ReaderOffset, +{ + /// Return true if the piece is empty. + pub fn is_empty(&self) -> bool { + matches!(*self, Location::Empty) + } +} + +/// The description of a single piece of the result of a DWARF +/// expression. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Piece::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// If given, the size of the piece in bits. If `None`, there + /// must be only one piece whose size is all of the object. + pub size_in_bits: Option, + /// If given, the bit offset of the piece within the location. + /// If the location is a `Location::Register` or `Location::Value`, + /// then this offset is from the least significant bit end of + /// the register or value. + /// If the location is a `Location::Address` then the offset uses + /// the bit numbering and direction conventions of the language + /// and target system. + /// + /// If `None`, the piece starts at the location. If the + /// location is a register whose size is larger than the piece, + /// then placement within the register is defined by the ABI. + pub bit_offset: Option, + /// Where this piece is to be found. + pub location: Location, +} + +// A helper function to handle branch offsets. +fn compute_pc(pc: &R, bytecode: &R, offset: i16) -> Result { + let pc_offset = pc.offset_from(bytecode); + let new_pc_offset = pc_offset.wrapping_add(R::Offset::from_i16(offset)); + if new_pc_offset > bytecode.len() { + Err(Error::BadBranchTarget(new_pc_offset.into_u64())) + } else { + let mut new_pc = bytecode.clone(); + new_pc.skip(new_pc_offset)?; + Ok(new_pc) + } +} + +fn generic_type() -> UnitOffset { + UnitOffset(O::from_u64(0).unwrap()) +} + +impl Operation +where + R: Reader, + Offset: ReaderOffset, +{ + /// Parse a single DWARF expression operation. + /// + /// This is useful when examining a DWARF expression for reasons other + /// than direct evaluation. + /// + /// `bytes` points to a the operation to decode. It should point into + /// the same array as `bytecode`, which should be the entire + /// expression. + pub fn parse(bytes: &mut R, encoding: Encoding) -> Result> { + let opcode = bytes.read_u8()?; + let name = constants::DwOp(opcode); + match name { + constants::DW_OP_addr => { + let address = bytes.read_address(encoding.address_size)?; + Ok(Operation::Address { address }) + } + constants::DW_OP_deref => Ok(Operation::Deref { + base_type: generic_type(), + size: encoding.address_size, + space: false, + }), + constants::DW_OP_const1u => { + let value = bytes.read_u8()?; + Ok(Operation::UnsignedConstant { + value: u64::from(value), + }) + } + constants::DW_OP_const1s => { + let value = bytes.read_i8()?; + Ok(Operation::SignedConstant { + value: i64::from(value), + }) + } + constants::DW_OP_const2u => { + let value = bytes.read_u16()?; + Ok(Operation::UnsignedConstant { + value: u64::from(value), + }) + } + constants::DW_OP_const2s => { + let value = bytes.read_i16()?; + Ok(Operation::SignedConstant { + value: i64::from(value), + }) + } + constants::DW_OP_const4u => { + let value = bytes.read_u32()?; + Ok(Operation::UnsignedConstant { + value: u64::from(value), + }) + } + constants::DW_OP_const4s => { + let value = bytes.read_i32()?; + Ok(Operation::SignedConstant { + value: i64::from(value), + }) + } + constants::DW_OP_const8u => { + let value = bytes.read_u64()?; + Ok(Operation::UnsignedConstant { value }) + } + constants::DW_OP_const8s => { + let value = bytes.read_i64()?; + Ok(Operation::SignedConstant { value }) + } + constants::DW_OP_constu => { + let value = bytes.read_uleb128()?; + Ok(Operation::UnsignedConstant { value }) + } + constants::DW_OP_consts => { + let value = bytes.read_sleb128()?; + Ok(Operation::SignedConstant { value }) + } + constants::DW_OP_dup => Ok(Operation::Pick { index: 0 }), + constants::DW_OP_drop => Ok(Operation::Drop), + constants::DW_OP_over => Ok(Operation::Pick { index: 1 }), + constants::DW_OP_pick => { + let value = bytes.read_u8()?; + Ok(Operation::Pick { index: value }) + } + constants::DW_OP_swap => Ok(Operation::Swap), + constants::DW_OP_rot => Ok(Operation::Rot), + constants::DW_OP_xderef => Ok(Operation::Deref { + base_type: generic_type(), + size: encoding.address_size, + space: true, + }), + constants::DW_OP_abs => Ok(Operation::Abs), + constants::DW_OP_and => Ok(Operation::And), + constants::DW_OP_div => Ok(Operation::Div), + constants::DW_OP_minus => Ok(Operation::Minus), + constants::DW_OP_mod => Ok(Operation::Mod), + constants::DW_OP_mul => Ok(Operation::Mul), + constants::DW_OP_neg => Ok(Operation::Neg), + constants::DW_OP_not => Ok(Operation::Not), + constants::DW_OP_or => Ok(Operation::Or), + constants::DW_OP_plus => Ok(Operation::Plus), + constants::DW_OP_plus_uconst => { + let value = bytes.read_uleb128()?; + Ok(Operation::PlusConstant { value }) + } + constants::DW_OP_shl => Ok(Operation::Shl), + constants::DW_OP_shr => Ok(Operation::Shr), + constants::DW_OP_shra => Ok(Operation::Shra), + constants::DW_OP_xor => Ok(Operation::Xor), + constants::DW_OP_bra => { + let target = bytes.read_i16()?; + Ok(Operation::Bra { target }) + } + constants::DW_OP_eq => Ok(Operation::Eq), + constants::DW_OP_ge => Ok(Operation::Ge), + constants::DW_OP_gt => Ok(Operation::Gt), + constants::DW_OP_le => Ok(Operation::Le), + constants::DW_OP_lt => Ok(Operation::Lt), + constants::DW_OP_ne => Ok(Operation::Ne), + constants::DW_OP_skip => { + let target = bytes.read_i16()?; + Ok(Operation::Skip { target }) + } + constants::DW_OP_lit0 + | constants::DW_OP_lit1 + | constants::DW_OP_lit2 + | constants::DW_OP_lit3 + | constants::DW_OP_lit4 + | constants::DW_OP_lit5 + | constants::DW_OP_lit6 + | constants::DW_OP_lit7 + | constants::DW_OP_lit8 + | constants::DW_OP_lit9 + | constants::DW_OP_lit10 + | constants::DW_OP_lit11 + | constants::DW_OP_lit12 + | constants::DW_OP_lit13 + | constants::DW_OP_lit14 + | constants::DW_OP_lit15 + | constants::DW_OP_lit16 + | constants::DW_OP_lit17 + | constants::DW_OP_lit18 + | constants::DW_OP_lit19 + | constants::DW_OP_lit20 + | constants::DW_OP_lit21 + | constants::DW_OP_lit22 + | constants::DW_OP_lit23 + | constants::DW_OP_lit24 + | constants::DW_OP_lit25 + | constants::DW_OP_lit26 + | constants::DW_OP_lit27 + | constants::DW_OP_lit28 + | constants::DW_OP_lit29 + | constants::DW_OP_lit30 + | constants::DW_OP_lit31 => Ok(Operation::UnsignedConstant { + value: (opcode - constants::DW_OP_lit0.0).into(), + }), + constants::DW_OP_reg0 + | constants::DW_OP_reg1 + | constants::DW_OP_reg2 + | constants::DW_OP_reg3 + | constants::DW_OP_reg4 + | constants::DW_OP_reg5 + | constants::DW_OP_reg6 + | constants::DW_OP_reg7 + | constants::DW_OP_reg8 + | constants::DW_OP_reg9 + | constants::DW_OP_reg10 + | constants::DW_OP_reg11 + | constants::DW_OP_reg12 + | constants::DW_OP_reg13 + | constants::DW_OP_reg14 + | constants::DW_OP_reg15 + | constants::DW_OP_reg16 + | constants::DW_OP_reg17 + | constants::DW_OP_reg18 + | constants::DW_OP_reg19 + | constants::DW_OP_reg20 + | constants::DW_OP_reg21 + | constants::DW_OP_reg22 + | constants::DW_OP_reg23 + | constants::DW_OP_reg24 + | constants::DW_OP_reg25 + | constants::DW_OP_reg26 + | constants::DW_OP_reg27 + | constants::DW_OP_reg28 + | constants::DW_OP_reg29 + | constants::DW_OP_reg30 + | constants::DW_OP_reg31 => Ok(Operation::Register { + register: Register((opcode - constants::DW_OP_reg0.0).into()), + }), + constants::DW_OP_breg0 + | constants::DW_OP_breg1 + | constants::DW_OP_breg2 + | constants::DW_OP_breg3 + | constants::DW_OP_breg4 + | constants::DW_OP_breg5 + | constants::DW_OP_breg6 + | constants::DW_OP_breg7 + | constants::DW_OP_breg8 + | constants::DW_OP_breg9 + | constants::DW_OP_breg10 + | constants::DW_OP_breg11 + | constants::DW_OP_breg12 + | constants::DW_OP_breg13 + | constants::DW_OP_breg14 + | constants::DW_OP_breg15 + | constants::DW_OP_breg16 + | constants::DW_OP_breg17 + | constants::DW_OP_breg18 + | constants::DW_OP_breg19 + | constants::DW_OP_breg20 + | constants::DW_OP_breg21 + | constants::DW_OP_breg22 + | constants::DW_OP_breg23 + | constants::DW_OP_breg24 + | constants::DW_OP_breg25 + | constants::DW_OP_breg26 + | constants::DW_OP_breg27 + | constants::DW_OP_breg28 + | constants::DW_OP_breg29 + | constants::DW_OP_breg30 + | constants::DW_OP_breg31 => { + let value = bytes.read_sleb128()?; + Ok(Operation::RegisterOffset { + register: Register((opcode - constants::DW_OP_breg0.0).into()), + offset: value, + base_type: generic_type(), + }) + } + constants::DW_OP_regx => { + let register = bytes.read_uleb128().and_then(Register::from_u64)?; + Ok(Operation::Register { register }) + } + constants::DW_OP_fbreg => { + let value = bytes.read_sleb128()?; + Ok(Operation::FrameOffset { offset: value }) + } + constants::DW_OP_bregx => { + let register = bytes.read_uleb128().and_then(Register::from_u64)?; + let offset = bytes.read_sleb128()?; + Ok(Operation::RegisterOffset { + register, + offset, + base_type: generic_type(), + }) + } + constants::DW_OP_piece => { + let size = bytes.read_uleb128()?; + Ok(Operation::Piece { + size_in_bits: 8 * size, + bit_offset: None, + }) + } + constants::DW_OP_deref_size => { + let size = bytes.read_u8()?; + Ok(Operation::Deref { + base_type: generic_type(), + size, + space: false, + }) + } + constants::DW_OP_xderef_size => { + let size = bytes.read_u8()?; + Ok(Operation::Deref { + base_type: generic_type(), + size, + space: true, + }) + } + constants::DW_OP_nop => Ok(Operation::Nop), + constants::DW_OP_push_object_address => Ok(Operation::PushObjectAddress), + constants::DW_OP_call2 => { + let value = bytes.read_u16().map(R::Offset::from_u16)?; + Ok(Operation::Call { + offset: DieReference::UnitRef(UnitOffset(value)), + }) + } + constants::DW_OP_call4 => { + let value = bytes.read_u32().map(R::Offset::from_u32)?; + Ok(Operation::Call { + offset: DieReference::UnitRef(UnitOffset(value)), + }) + } + constants::DW_OP_call_ref => { + let value = bytes.read_offset(encoding.format)?; + Ok(Operation::Call { + offset: DieReference::DebugInfoRef(DebugInfoOffset(value)), + }) + } + constants::DW_OP_form_tls_address | constants::DW_OP_GNU_push_tls_address => { + Ok(Operation::TLS) + } + constants::DW_OP_call_frame_cfa => Ok(Operation::CallFrameCFA), + constants::DW_OP_bit_piece => { + let size = bytes.read_uleb128()?; + let offset = bytes.read_uleb128()?; + Ok(Operation::Piece { + size_in_bits: size, + bit_offset: Some(offset), + }) + } + constants::DW_OP_implicit_value => { + let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + let data = bytes.split(len)?; + Ok(Operation::ImplicitValue { data }) + } + constants::DW_OP_stack_value => Ok(Operation::StackValue), + constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => { + let value = if encoding.version == 2 { + bytes + .read_address(encoding.address_size) + .and_then(Offset::from_u64)? + } else { + bytes.read_offset(encoding.format)? + }; + let byte_offset = bytes.read_sleb128()?; + Ok(Operation::ImplicitPointer { + value: DebugInfoOffset(value), + byte_offset, + }) + } + constants::DW_OP_addrx | constants::DW_OP_GNU_addr_index => { + let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::AddressIndex { + index: DebugAddrIndex(index), + }) + } + constants::DW_OP_constx | constants::DW_OP_GNU_const_index => { + let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::ConstantIndex { + index: DebugAddrIndex(index), + }) + } + constants::DW_OP_entry_value | constants::DW_OP_GNU_entry_value => { + let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + let expression = bytes.split(len)?; + Ok(Operation::EntryValue { expression }) + } + constants::DW_OP_GNU_parameter_ref => { + let value = bytes.read_u32().map(R::Offset::from_u32)?; + Ok(Operation::ParameterRef { + offset: UnitOffset(value), + }) + } + constants::DW_OP_const_type | constants::DW_OP_GNU_const_type => { + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + let len = bytes.read_u8()?; + let value = bytes.split(R::Offset::from_u8(len))?; + Ok(Operation::TypedLiteral { + base_type: UnitOffset(base_type), + value, + }) + } + constants::DW_OP_regval_type | constants::DW_OP_GNU_regval_type => { + let register = bytes.read_uleb128().and_then(Register::from_u64)?; + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::RegisterOffset { + register, + offset: 0, + base_type: UnitOffset(base_type), + }) + } + constants::DW_OP_deref_type | constants::DW_OP_GNU_deref_type => { + let size = bytes.read_u8()?; + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::Deref { + base_type: UnitOffset(base_type), + size, + space: false, + }) + } + constants::DW_OP_xderef_type => { + let size = bytes.read_u8()?; + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::Deref { + base_type: UnitOffset(base_type), + size, + space: true, + }) + } + constants::DW_OP_convert | constants::DW_OP_GNU_convert => { + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::Convert { + base_type: UnitOffset(base_type), + }) + } + constants::DW_OP_reinterpret | constants::DW_OP_GNU_reinterpret => { + let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::Reinterpret { + base_type: UnitOffset(base_type), + }) + } + constants::DW_OP_WASM_location => match bytes.read_u8()? { + 0x0 => { + let index = bytes.read_uleb128_u32()?; + Ok(Operation::WasmLocal { index }) + } + 0x1 => { + let index = bytes.read_uleb128_u32()?; + Ok(Operation::WasmGlobal { index }) + } + 0x2 => { + let index = bytes.read_uleb128_u32()?; + Ok(Operation::WasmStack { index }) + } + 0x3 => { + let index = bytes.read_u32()?; + Ok(Operation::WasmGlobal { index }) + } + _ => Err(Error::InvalidExpression(name)), + }, + _ => Err(Error::InvalidExpression(name)), + } + } +} + +#[derive(Debug)] +enum EvaluationState { + Start(Option), + Ready, + Error(Error), + Complete, + Waiting(EvaluationWaiting), +} + +#[derive(Debug)] +enum EvaluationWaiting { + Memory, + Register { offset: i64 }, + FrameBase { offset: i64 }, + Tls, + Cfa, + AtLocation, + EntryValue, + ParameterRef, + RelocatedAddress, + IndexedAddress, + TypedLiteral { value: R }, + Convert, + Reinterpret, +} + +/// The state of an `Evaluation` after evaluating a DWARF expression. +/// The evaluation is either `Complete`, or it requires more data +/// to continue, as described by the variant. +#[derive(Debug, PartialEq)] +pub enum EvaluationResult { + /// The `Evaluation` is complete, and `Evaluation::result()` can be called. + Complete, + /// The `Evaluation` needs a value from memory to proceed further. Once the + /// caller determines what value to provide it should resume the `Evaluation` + /// by calling `Evaluation::resume_with_memory`. + RequiresMemory { + /// The address of the value required. + address: u64, + /// The size of the value required. This is guaranteed to be at most the + /// word size of the target architecture. + size: u8, + /// If not `None`, a target-specific address space value. + space: Option, + /// The DIE of the base type or 0 to indicate the generic type + base_type: UnitOffset, + }, + /// The `Evaluation` needs a value from a register to proceed further. Once + /// the caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_register`. + RequiresRegister { + /// The register number. + register: Register, + /// The DIE of the base type or 0 to indicate the generic type + base_type: UnitOffset, + }, + /// The `Evaluation` needs the frame base address to proceed further. Once + /// the caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_frame_base`. The frame + /// base address is the address produced by the location description in the + /// `DW_AT_frame_base` attribute of the current function. + RequiresFrameBase, + /// The `Evaluation` needs a value from TLS to proceed further. Once the + /// caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_tls`. + RequiresTls(u64), + /// The `Evaluation` needs the CFA to proceed further. Once the caller + /// determines what value to provide it should resume the `Evaluation` by + /// calling `Evaluation::resume_with_call_frame_cfa`. + RequiresCallFrameCfa, + /// The `Evaluation` needs the DWARF expression at the given location to + /// proceed further. Once the caller determines what value to provide it + /// should resume the `Evaluation` by calling + /// `Evaluation::resume_with_at_location`. + RequiresAtLocation(DieReference), + /// The `Evaluation` needs the value produced by evaluating a DWARF + /// expression at the entry point of the current subprogram. Once the + /// caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_entry_value`. + RequiresEntryValue(Expression), + /// The `Evaluation` needs the value of the parameter at the given location + /// in the current function's caller. Once the caller determines what value + /// to provide it should resume the `Evaluation` by calling + /// `Evaluation::resume_with_parameter_ref`. + RequiresParameterRef(UnitOffset), + /// The `Evaluation` needs an address to be relocated to proceed further. + /// Once the caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`. + RequiresRelocatedAddress(u64), + /// The `Evaluation` needs an address from the `.debug_addr` section. + /// This address may also need to be relocated. + /// Once the caller determines what value to provide it should resume the + /// `Evaluation` by calling `Evaluation::resume_with_indexed_address`. + RequiresIndexedAddress { + /// The index of the address in the `.debug_addr` section, + /// relative to the `DW_AT_addr_base` of the compilation unit. + index: DebugAddrIndex, + /// Whether the address also needs to be relocated. + relocate: bool, + }, + /// The `Evaluation` needs the `ValueType` for the base type DIE at + /// the give unit offset. Once the caller determines what value to provide it + /// should resume the `Evaluation` by calling + /// `Evaluation::resume_with_base_type`. + RequiresBaseType(UnitOffset), +} + +/// The bytecode for a DWARF expression or location description. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Expression(pub R); + +impl Expression { + /// Create an evaluation for this expression. + /// + /// The `encoding` is determined by the + /// [`CompilationUnitHeader`](struct.CompilationUnitHeader.html) or + /// [`TypeUnitHeader`](struct.TypeUnitHeader.html) that this expression + /// relates to. + /// + /// # Examples + /// ```rust,no_run + /// use gimli::Expression; + /// # let endian = gimli::LittleEndian; + /// # let debug_info = gimli::DebugInfo::from(gimli::EndianSlice::new(&[], endian)); + /// # let unit = debug_info.units().next().unwrap().unwrap(); + /// # let bytecode = gimli::EndianSlice::new(&[], endian); + /// let expression = gimli::Expression(bytecode); + /// let mut eval = expression.evaluation(unit.encoding()); + /// let mut result = eval.evaluate().unwrap(); + /// ``` + #[cfg(feature = "read")] + #[inline] + pub fn evaluation(self, encoding: Encoding) -> Evaluation { + Evaluation::new(self.0, encoding) + } + + /// Return an iterator for the operations in the expression. + pub fn operations(self, encoding: Encoding) -> OperationIter { + OperationIter { + input: self.0, + encoding, + } + } +} + +/// An iterator for the operations in an expression. +#[derive(Debug, Clone, Copy)] +pub struct OperationIter { + input: R, + encoding: Encoding, +} + +impl OperationIter { + /// Read the next operation in an expression. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + match Operation::parse(&mut self.input, self.encoding) { + Ok(op) => Ok(Some(op)), + Err(e) => { + self.input.empty(); + Err(e) + } + } + } + + /// Return the current byte offset of the iterator. + pub fn offset_from(&self, expression: &Expression) -> R::Offset { + self.input.offset_from(&expression.0) + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for OperationIter { + type Item = Operation; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + OperationIter::next(self) + } +} + +/// Specification of what storage should be used for [`Evaluation`]. +/// +#[cfg_attr( + feature = "read", + doc = " +Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results +on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`]. +" +)] +/// +/// If you need to avoid [`Evaluation`] from allocating memory, e.g. for signal safety, +/// you can provide you own storage specification: +/// ```rust,no_run +/// # use gimli::*; +/// # let bytecode = EndianSlice::new(&[], LittleEndian); +/// # let encoding = unimplemented!(); +/// # let get_register_value = |_, _| Value::Generic(42); +/// # let get_frame_base = || 0xdeadbeef; +/// # +/// struct StoreOnStack; +/// +/// impl EvaluationStorage for StoreOnStack { +/// type Stack = [Value; 64]; +/// type ExpressionStack = [(R, R); 4]; +/// type Result = [Piece; 1]; +/// } +/// +/// let mut eval = Evaluation::<_, StoreOnStack>::new_in(bytecode, encoding); +/// let mut result = eval.evaluate().unwrap(); +/// while result != EvaluationResult::Complete { +/// match result { +/// EvaluationResult::RequiresRegister { register, base_type } => { +/// let value = get_register_value(register, base_type); +/// result = eval.resume_with_register(value).unwrap(); +/// }, +/// EvaluationResult::RequiresFrameBase => { +/// let frame_base = get_frame_base(); +/// result = eval.resume_with_frame_base(frame_base).unwrap(); +/// }, +/// _ => unimplemented!(), +/// }; +/// } +/// +/// let result = eval.as_result(); +/// println!("{:?}", result); +/// ``` +pub trait EvaluationStorage { + /// The storage used for the evaluation stack. + type Stack: ArrayLike; + /// The storage used for the expression stack. + type ExpressionStack: ArrayLike; + /// The storage used for the results. + type Result: ArrayLike>; +} + +#[cfg(feature = "read")] +impl EvaluationStorage for StoreOnHeap { + type Stack = Vec; + type ExpressionStack = Vec<(R, R)>; + type Result = Vec>; +} + +/// A DWARF expression evaluator. +/// +/// # Usage +/// A DWARF expression may require additional data to produce a final result, +/// such as the value of a register or a memory location. Once initial setup +/// is complete (i.e. `set_initial_value()`, `set_object_address()`) the +/// consumer calls the `evaluate()` method. That returns an `EvaluationResult`, +/// which is either `EvaluationResult::Complete` or a value indicating what +/// data is needed to resume the `Evaluation`. The consumer is responsible for +/// producing that data and resuming the computation with the correct method, +/// as documented for `EvaluationResult`. Only once an `EvaluationResult::Complete` +/// is returned can the consumer call `result()`. +/// +/// This design allows the consumer of `Evaluation` to decide how and when to +/// produce the required data and resume the computation. The `Evaluation` can +/// be driven synchronously (as shown below) or by some asynchronous mechanism +/// such as futures. +/// +/// # Examples +/// ```rust,no_run +/// use gimli::{Evaluation, EvaluationResult, Expression}; +/// # let bytecode = gimli::EndianSlice::new(&[], gimli::LittleEndian); +/// # let encoding = unimplemented!(); +/// # let get_register_value = |_, _| gimli::Value::Generic(42); +/// # let get_frame_base = || 0xdeadbeef; +/// +/// let mut eval = Evaluation::new(bytecode, encoding); +/// let mut result = eval.evaluate().unwrap(); +/// while result != EvaluationResult::Complete { +/// match result { +/// EvaluationResult::RequiresRegister { register, base_type } => { +/// let value = get_register_value(register, base_type); +/// result = eval.resume_with_register(value).unwrap(); +/// }, +/// EvaluationResult::RequiresFrameBase => { +/// let frame_base = get_frame_base(); +/// result = eval.resume_with_frame_base(frame_base).unwrap(); +/// }, +/// _ => unimplemented!(), +/// }; +/// } +/// +/// let result = eval.result(); +/// println!("{:?}", result); +/// ``` +#[derive(Debug)] +pub struct Evaluation = StoreOnHeap> { + bytecode: R, + encoding: Encoding, + object_address: Option, + max_iterations: Option, + iteration: u32, + state: EvaluationState, + + // Stack operations are done on word-sized values. We do all + // operations on 64-bit values, and then mask the results + // appropriately when popping. + addr_mask: u64, + + // The stack. + stack: ArrayVec, + + // The next operation to decode and evaluate. + pc: R, + + // If we see a DW_OP_call* operation, the previous PC and bytecode + // is stored here while evaluating the subroutine. + expression_stack: ArrayVec, + + value_result: Option, + result: ArrayVec, +} + +#[cfg(feature = "read")] +impl Evaluation { + /// Create a new DWARF expression evaluator. + /// + /// The new evaluator is created without an initial value, without + /// an object address, and without a maximum number of iterations. + pub fn new(bytecode: R, encoding: Encoding) -> Self { + Self::new_in(bytecode, encoding) + } + + /// Get the result of this `Evaluation`. + /// + /// # Panics + /// Panics if this `Evaluation` has not been driven to completion. + pub fn result(self) -> Vec> { + match self.state { + EvaluationState::Complete => self.result.into_vec(), + _ => { + panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed") + } + } + } +} + +impl> Evaluation { + /// Create a new DWARF expression evaluator. + /// + /// The new evaluator is created without an initial value, without + /// an object address, and without a maximum number of iterations. + pub fn new_in(bytecode: R, encoding: Encoding) -> Self { + let pc = bytecode.clone(); + Evaluation { + bytecode, + encoding, + object_address: None, + max_iterations: None, + iteration: 0, + state: EvaluationState::Start(None), + addr_mask: if encoding.address_size == 8 { + !0u64 + } else { + (1 << (8 * u64::from(encoding.address_size))) - 1 + }, + stack: Default::default(), + expression_stack: Default::default(), + pc, + value_result: None, + result: Default::default(), + } + } + + /// Set an initial value to be pushed on the DWARF expression + /// evaluator's stack. This can be used in cases like + /// `DW_AT_vtable_elem_location`, which require a value on the + /// stack before evaluation commences. If no initial value is + /// set, and the expression uses an opcode requiring the initial + /// value, then evaluation will fail with an error. + /// + /// # Panics + /// Panics if `set_initial_value()` has already been called, or if + /// `evaluate()` has already been called. + pub fn set_initial_value(&mut self, value: u64) { + match self.state { + EvaluationState::Start(None) => { + self.state = EvaluationState::Start(Some(value)); + } + _ => panic!( + "`Evaluation::set_initial_value` was called twice, or after evaluation began." + ), + }; + } + + /// Set the enclosing object's address, as used by + /// `DW_OP_push_object_address`. If no object address is set, and + /// the expression uses an opcode requiring the object address, + /// then evaluation will fail with an error. + pub fn set_object_address(&mut self, value: u64) { + self.object_address = Some(value); + } + + /// Set the maximum number of iterations to be allowed by the + /// expression evaluator. + /// + /// An iteration corresponds approximately to the evaluation of a + /// single operation in an expression ("approximately" because the + /// implementation may allow two such operations in some cases). + /// The default is not to have a maximum; once set, it's not + /// possible to go back to this default state. This value can be + /// set to avoid denial of service attacks by bad DWARF bytecode. + pub fn set_max_iterations(&mut self, value: u32) { + self.max_iterations = Some(value); + } + + fn pop(&mut self) -> Result { + match self.stack.pop() { + Some(value) => Ok(value), + None => Err(Error::NotEnoughStackItems), + } + } + + fn push(&mut self, value: Value) -> Result<()> { + self.stack.try_push(value).map_err(|_| Error::StackFull) + } + + fn evaluate_one_operation(&mut self) -> Result> { + let operation = Operation::parse(&mut self.pc, self.encoding)?; + + match operation { + Operation::Deref { + base_type, + size, + space, + } => { + if size > self.encoding.address_size { + return Err(Error::InvalidDerefSize(size)); + } + let entry = self.pop()?; + let addr = entry.to_u64(self.addr_mask)?; + let addr_space = if space { + let entry = self.pop()?; + let value = entry.to_u64(self.addr_mask)?; + Some(value) + } else { + None + }; + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Memory, + EvaluationResult::RequiresMemory { + address: addr, + size, + space: addr_space, + base_type, + }, + )); + } + + Operation::Drop => { + self.pop()?; + } + Operation::Pick { index } => { + let len = self.stack.len(); + let index = index as usize; + if index >= len { + return Err(Error::NotEnoughStackItems); + } + let value = self.stack[len - index - 1]; + self.push(value)?; + } + Operation::Swap => { + let top = self.pop()?; + let next = self.pop()?; + self.push(top)?; + self.push(next)?; + } + Operation::Rot => { + let one = self.pop()?; + let two = self.pop()?; + let three = self.pop()?; + self.push(one)?; + self.push(three)?; + self.push(two)?; + } + + Operation::Abs => { + let value = self.pop()?; + let result = value.abs(self.addr_mask)?; + self.push(result)?; + } + Operation::And => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.and(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Div => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.div(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Minus => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.sub(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Mod => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.rem(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Mul => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.mul(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Neg => { + let v = self.pop()?; + let result = v.neg(self.addr_mask)?; + self.push(result)?; + } + Operation::Not => { + let value = self.pop()?; + let result = value.not(self.addr_mask)?; + self.push(result)?; + } + Operation::Or => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.or(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Plus => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.add(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::PlusConstant { value } => { + let lhs = self.pop()?; + let rhs = Value::from_u64(lhs.value_type(), value)?; + let result = lhs.add(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Shl => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.shl(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Shr => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.shr(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Shra => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.shra(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Xor => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.xor(rhs, self.addr_mask)?; + self.push(result)?; + } + + Operation::Bra { target } => { + let entry = self.pop()?; + let v = entry.to_u64(self.addr_mask)?; + if v != 0 { + self.pc = compute_pc(&self.pc, &self.bytecode, target)?; + } + } + + Operation::Eq => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.eq(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Ge => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.ge(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Gt => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.gt(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Le => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.le(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Lt => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.lt(rhs, self.addr_mask)?; + self.push(result)?; + } + Operation::Ne => { + let rhs = self.pop()?; + let lhs = self.pop()?; + let result = lhs.ne(rhs, self.addr_mask)?; + self.push(result)?; + } + + Operation::Skip { target } => { + self.pc = compute_pc(&self.pc, &self.bytecode, target)?; + } + + Operation::UnsignedConstant { value } => { + self.push(Value::Generic(value))?; + } + + Operation::SignedConstant { value } => { + self.push(Value::Generic(value as u64))?; + } + + Operation::RegisterOffset { + register, + offset, + base_type, + } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Register { offset }, + EvaluationResult::RequiresRegister { + register, + base_type, + }, + )); + } + + Operation::FrameOffset { offset } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::FrameBase { offset }, + EvaluationResult::RequiresFrameBase, + )); + } + + Operation::Nop => {} + + Operation::PushObjectAddress => { + if let Some(value) = self.object_address { + self.push(Value::Generic(value))?; + } else { + return Err(Error::InvalidPushObjectAddress); + } + } + + Operation::Call { offset } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::AtLocation, + EvaluationResult::RequiresAtLocation(offset), + )); + } + + Operation::TLS => { + let entry = self.pop()?; + let index = entry.to_u64(self.addr_mask)?; + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Tls, + EvaluationResult::RequiresTls(index), + )); + } + + Operation::CallFrameCFA => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Cfa, + EvaluationResult::RequiresCallFrameCfa, + )); + } + + Operation::Register { register } => { + let location = Location::Register { register }; + return Ok(OperationEvaluationResult::Complete { location }); + } + + Operation::ImplicitValue { ref data } => { + let location = Location::Bytes { + value: data.clone(), + }; + return Ok(OperationEvaluationResult::Complete { location }); + } + + Operation::StackValue => { + let value = self.pop()?; + let location = Location::Value { value }; + return Ok(OperationEvaluationResult::Complete { location }); + } + + Operation::ImplicitPointer { value, byte_offset } => { + let location = Location::ImplicitPointer { value, byte_offset }; + return Ok(OperationEvaluationResult::Complete { location }); + } + + Operation::EntryValue { ref expression } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::EntryValue, + EvaluationResult::RequiresEntryValue(Expression(expression.clone())), + )); + } + + Operation::ParameterRef { offset } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::ParameterRef, + EvaluationResult::RequiresParameterRef(offset), + )); + } + + Operation::Address { address } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::RelocatedAddress, + EvaluationResult::RequiresRelocatedAddress(address), + )); + } + + Operation::AddressIndex { index } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::IndexedAddress, + EvaluationResult::RequiresIndexedAddress { + index, + relocate: true, + }, + )); + } + + Operation::ConstantIndex { index } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::IndexedAddress, + EvaluationResult::RequiresIndexedAddress { + index, + relocate: false, + }, + )); + } + + Operation::Piece { + size_in_bits, + bit_offset, + } => { + let location = if self.stack.is_empty() { + Location::Empty + } else { + let entry = self.pop()?; + let address = entry.to_u64(self.addr_mask)?; + Location::Address { address } + }; + self.result + .try_push(Piece { + size_in_bits: Some(size_in_bits), + bit_offset, + location, + }) + .map_err(|_| Error::StackFull)?; + return Ok(OperationEvaluationResult::Piece); + } + + Operation::TypedLiteral { base_type, value } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::TypedLiteral { value }, + EvaluationResult::RequiresBaseType(base_type), + )); + } + Operation::Convert { base_type } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Convert, + EvaluationResult::RequiresBaseType(base_type), + )); + } + Operation::Reinterpret { base_type } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::Reinterpret, + EvaluationResult::RequiresBaseType(base_type), + )); + } + Operation::WasmLocal { .. } + | Operation::WasmGlobal { .. } + | Operation::WasmStack { .. } => { + return Err(Error::UnsupportedEvaluation); + } + } + + Ok(OperationEvaluationResult::Incomplete) + } + + /// Get the result if this is an evaluation for a value. + /// + /// Returns `None` if the evaluation contained operations that are only + /// valid for location descriptions. + /// + /// # Panics + /// Panics if this `Evaluation` has not been driven to completion. + pub fn value_result(&self) -> Option { + match self.state { + EvaluationState::Complete => self.value_result, + _ => { + panic!("Called `Evaluation::value_result` on an `Evaluation` that has not been completed") + } + } + } + + /// Get the result of this `Evaluation`. + /// + /// # Panics + /// Panics if this `Evaluation` has not been driven to completion. + pub fn as_result(&self) -> &[Piece] { + match self.state { + EvaluationState::Complete => &self.result, + _ => { + panic!( + "Called `Evaluation::as_result` on an `Evaluation` that has not been completed" + ) + } + } + } + + /// Evaluate a DWARF expression. This method should only ever be called + /// once. If the returned `EvaluationResult` is not + /// `EvaluationResult::Complete`, the caller should provide the required + /// value and resume the evaluation by calling the appropriate resume_with + /// method on `Evaluation`. + pub fn evaluate(&mut self) -> Result> { + match self.state { + EvaluationState::Start(initial_value) => { + if let Some(value) = initial_value { + self.push(Value::Generic(value))?; + } + self.state = EvaluationState::Ready; + } + EvaluationState::Ready => {} + EvaluationState::Error(err) => return Err(err), + EvaluationState::Complete => return Ok(EvaluationResult::Complete), + EvaluationState::Waiting(_) => panic!(), + }; + + match self.evaluate_internal() { + Ok(r) => Ok(r), + Err(e) => { + self.state = EvaluationState::Error(e); + Err(e) + } + } + } + + /// Resume the `Evaluation` with the provided memory `value`. This will apply + /// the provided memory value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresMemory`. + pub fn resume_with_memory(&mut self, value: Value) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::Memory) => { + self.push(value)?; + } + _ => panic!( + "Called `Evaluation::resume_with_memory` without a preceding `EvaluationResult::RequiresMemory`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `register` value. This will apply + /// the provided register value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresRegister`. + pub fn resume_with_register(&mut self, value: Value) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::Register { offset }) => { + let offset = Value::from_u64(value.value_type(), offset as u64)?; + let value = value.add(offset, self.addr_mask)?; + self.push(value)?; + } + _ => panic!( + "Called `Evaluation::resume_with_register` without a preceding `EvaluationResult::RequiresRegister`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `frame_base`. This will + /// apply the provided frame base value to the evaluation and continue + /// evaluating opcodes until the evaluation is completed, reaches an error, + /// or needs more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresFrameBase`. + pub fn resume_with_frame_base(&mut self, frame_base: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::FrameBase { offset }) => { + self.push(Value::Generic(frame_base.wrapping_add(offset as u64)))?; + } + _ => panic!( + "Called `Evaluation::resume_with_frame_base` without a preceding `EvaluationResult::RequiresFrameBase`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `value`. This will apply + /// the provided TLS value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresTls`. + pub fn resume_with_tls(&mut self, value: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::Tls) => { + self.push(Value::Generic(value))?; + } + _ => panic!( + "Called `Evaluation::resume_with_tls` without a preceding `EvaluationResult::RequiresTls`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `cfa`. This will + /// apply the provided CFA value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresCallFrameCfa`. + pub fn resume_with_call_frame_cfa(&mut self, cfa: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::Cfa) => { + self.push(Value::Generic(cfa))?; + } + _ => panic!( + "Called `Evaluation::resume_with_call_frame_cfa` without a preceding `EvaluationResult::RequiresCallFrameCfa`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `bytes`. This will + /// continue processing the evaluation with the new expression provided + /// until the evaluation is completed, reaches an error, or needs more + /// information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresAtLocation`. + pub fn resume_with_at_location(&mut self, mut bytes: R) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::AtLocation) => { + if !bytes.is_empty() { + let mut pc = bytes.clone(); + mem::swap(&mut pc, &mut self.pc); + mem::swap(&mut bytes, &mut self.bytecode); + self.expression_stack.try_push((pc, bytes)).map_err(|_| Error::StackFull)?; + } + } + _ => panic!( + "Called `Evaluation::resume_with_at_location` without a precedeing `EvaluationResult::RequiresAtLocation`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `entry_value`. This will + /// apply the provided entry value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresEntryValue`. + pub fn resume_with_entry_value(&mut self, entry_value: Value) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::EntryValue) => { + self.push(entry_value)?; + } + _ => panic!( + "Called `Evaluation::resume_with_entry_value` without a preceding `EvaluationResult::RequiresEntryValue`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `parameter_value`. This will + /// apply the provided parameter value to the evaluation and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresParameterRef`. + pub fn resume_with_parameter_ref( + &mut self, + parameter_value: u64, + ) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::ParameterRef) => { + self.push(Value::Generic(parameter_value))?; + } + _ => panic!( + "Called `Evaluation::resume_with_parameter_ref` without a preceding `EvaluationResult::RequiresParameterRef`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided relocated `address`. This will use the + /// provided relocated address for the operation that required it, and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with + /// `EvaluationResult::RequiresRelocatedAddress`. + pub fn resume_with_relocated_address(&mut self, address: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::RelocatedAddress) => { + self.push(Value::Generic(address))?; + } + _ => panic!( + "Called `Evaluation::resume_with_relocated_address` without a preceding `EvaluationResult::RequiresRelocatedAddress`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided indexed `address`. This will use the + /// provided indexed address for the operation that required it, and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with + /// `EvaluationResult::RequiresIndexedAddress`. + pub fn resume_with_indexed_address(&mut self, address: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::IndexedAddress) => { + self.push(Value::Generic(address))?; + } + _ => panic!( + "Called `Evaluation::resume_with_indexed_address` without a preceding `EvaluationResult::RequiresIndexedAddress`" + ), + }; + + self.evaluate_internal() + } + + /// Resume the `Evaluation` with the provided `base_type`. This will use the + /// provided base type for the operation that required it, and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresBaseType`. + pub fn resume_with_base_type(&mut self, base_type: ValueType) -> Result> { + let value = match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::TypedLiteral { ref value }) => { + Value::parse(base_type, value.clone())? + } + EvaluationState::Waiting(EvaluationWaiting::Convert) => { + let entry = self.pop()?; + entry.convert(base_type, self.addr_mask)? + } + EvaluationState::Waiting(EvaluationWaiting::Reinterpret) => { + let entry = self.pop()?; + entry.reinterpret(base_type, self.addr_mask)? + } + _ => panic!( + "Called `Evaluation::resume_with_base_type` without a preceding `EvaluationResult::RequiresBaseType`" + ), + }; + self.push(value)?; + self.evaluate_internal() + } + + fn end_of_expression(&mut self) -> bool { + while self.pc.is_empty() { + match self.expression_stack.pop() { + Some((newpc, newbytes)) => { + self.pc = newpc; + self.bytecode = newbytes; + } + None => return true, + } + } + false + } + + fn evaluate_internal(&mut self) -> Result> { + while !self.end_of_expression() { + self.iteration += 1; + if let Some(max_iterations) = self.max_iterations { + if self.iteration > max_iterations { + return Err(Error::TooManyIterations); + } + } + + let op_result = self.evaluate_one_operation()?; + match op_result { + OperationEvaluationResult::Piece => {} + OperationEvaluationResult::Incomplete => { + if self.end_of_expression() && !self.result.is_empty() { + // We saw a piece earlier and then some + // unterminated piece. It's not clear this is + // well-defined. + return Err(Error::InvalidPiece); + } + } + OperationEvaluationResult::Complete { location } => { + if self.end_of_expression() { + if !self.result.is_empty() { + // We saw a piece earlier and then some + // unterminated piece. It's not clear this is + // well-defined. + return Err(Error::InvalidPiece); + } + self.result + .try_push(Piece { + size_in_bits: None, + bit_offset: None, + location, + }) + .map_err(|_| Error::StackFull)?; + } else { + // If there are more operations, then the next operation must + // be a Piece. + match Operation::parse(&mut self.pc, self.encoding)? { + Operation::Piece { + size_in_bits, + bit_offset, + } => { + self.result + .try_push(Piece { + size_in_bits: Some(size_in_bits), + bit_offset, + location, + }) + .map_err(|_| Error::StackFull)?; + } + _ => { + let value = + self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1; + return Err(Error::InvalidExpressionTerminator(value)); + } + } + } + } + OperationEvaluationResult::Waiting(waiting, result) => { + self.state = EvaluationState::Waiting(waiting); + return Ok(result); + } + } + } + + // If no pieces have been seen, use the stack top as the + // result. + if self.result.is_empty() { + let entry = self.pop()?; + self.value_result = Some(entry); + let addr = entry.to_u64(self.addr_mask)?; + self.result + .try_push(Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Address { address: addr }, + }) + .map_err(|_| Error::StackFull)?; + } + + self.state = EvaluationState::Complete; + Ok(EvaluationResult::Complete) + } +} + +#[cfg(test)] +// Tests require leb128::write. +#[cfg(feature = "write")] +mod tests { + use super::*; + use crate::common::Format; + use crate::constants; + use crate::endianity::LittleEndian; + use crate::leb128; + use crate::read::{EndianSlice, Error, Result, UnitOffset}; + use crate::test_util::GimliSectionMethods; + use test_assembler::{Endian, Section}; + + fn encoding4() -> Encoding { + Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + } + } + + fn encoding8() -> Encoding { + Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + } + } + + #[test] + fn test_compute_pc() { + // Contents don't matter for this test, just length. + let bytes = [0, 1, 2, 3, 4]; + let bytecode = &bytes[..]; + let ebuf = &EndianSlice::new(bytecode, LittleEndian); + + assert_eq!(compute_pc(ebuf, ebuf, 0), Ok(*ebuf)); + assert_eq!( + compute_pc(ebuf, ebuf, -1), + Err(Error::BadBranchTarget(usize::MAX as u64)) + ); + assert_eq!(compute_pc(ebuf, ebuf, 5), Ok(ebuf.range_from(5..))); + assert_eq!( + compute_pc(&ebuf.range_from(3..), ebuf, -2), + Ok(ebuf.range_from(1..)) + ); + assert_eq!( + compute_pc(&ebuf.range_from(2..), ebuf, 2), + Ok(ebuf.range_from(4..)) + ); + } + + fn check_op_parse_simple<'input>( + input: &'input [u8], + expect: &Operation>, + encoding: Encoding, + ) { + let buf = EndianSlice::new(input, LittleEndian); + let mut pc = buf; + let value = Operation::parse(&mut pc, encoding); + match value { + Ok(val) => { + assert_eq!(val, *expect); + assert_eq!(pc.len(), 0); + } + _ => panic!("Unexpected result"), + } + } + + fn check_op_parse_eof(input: &[u8], encoding: Encoding) { + let buf = EndianSlice::new(input, LittleEndian); + let mut pc = buf; + match Operation::parse(&mut pc, encoding) { + Err(Error::UnexpectedEof(id)) => { + assert!(buf.lookup_offset_id(id).is_some()); + } + + _ => panic!("Unexpected result"), + } + } + + fn check_op_parse( + input: F, + expect: &Operation>, + encoding: Encoding, + ) where + F: Fn(Section) -> Section, + { + let input = input(Section::with_endian(Endian::Little)) + .get_contents() + .unwrap(); + for i in 1..input.len() { + check_op_parse_eof(&input[..i], encoding); + } + check_op_parse_simple(&input, expect, encoding); + } + + #[test] + fn test_op_parse_onebyte() { + // Doesn't matter for this test. + let encoding = encoding4(); + + // Test all single-byte opcodes. + #[rustfmt::skip] + let inputs = [ + ( + constants::DW_OP_deref, + Operation::Deref { + base_type: generic_type(), + size: encoding.address_size, + space: false, + }, + ), + (constants::DW_OP_dup, Operation::Pick { index: 0 }), + (constants::DW_OP_drop, Operation::Drop), + (constants::DW_OP_over, Operation::Pick { index: 1 }), + (constants::DW_OP_swap, Operation::Swap), + (constants::DW_OP_rot, Operation::Rot), + ( + constants::DW_OP_xderef, + Operation::Deref { + base_type: generic_type(), + size: encoding.address_size, + space: true, + }, + ), + (constants::DW_OP_abs, Operation::Abs), + (constants::DW_OP_and, Operation::And), + (constants::DW_OP_div, Operation::Div), + (constants::DW_OP_minus, Operation::Minus), + (constants::DW_OP_mod, Operation::Mod), + (constants::DW_OP_mul, Operation::Mul), + (constants::DW_OP_neg, Operation::Neg), + (constants::DW_OP_not, Operation::Not), + (constants::DW_OP_or, Operation::Or), + (constants::DW_OP_plus, Operation::Plus), + (constants::DW_OP_shl, Operation::Shl), + (constants::DW_OP_shr, Operation::Shr), + (constants::DW_OP_shra, Operation::Shra), + (constants::DW_OP_xor, Operation::Xor), + (constants::DW_OP_eq, Operation::Eq), + (constants::DW_OP_ge, Operation::Ge), + (constants::DW_OP_gt, Operation::Gt), + (constants::DW_OP_le, Operation::Le), + (constants::DW_OP_lt, Operation::Lt), + (constants::DW_OP_ne, Operation::Ne), + (constants::DW_OP_lit0, Operation::UnsignedConstant { value: 0 }), + (constants::DW_OP_lit1, Operation::UnsignedConstant { value: 1 }), + (constants::DW_OP_lit2, Operation::UnsignedConstant { value: 2 }), + (constants::DW_OP_lit3, Operation::UnsignedConstant { value: 3 }), + (constants::DW_OP_lit4, Operation::UnsignedConstant { value: 4 }), + (constants::DW_OP_lit5, Operation::UnsignedConstant { value: 5 }), + (constants::DW_OP_lit6, Operation::UnsignedConstant { value: 6 }), + (constants::DW_OP_lit7, Operation::UnsignedConstant { value: 7 }), + (constants::DW_OP_lit8, Operation::UnsignedConstant { value: 8 }), + (constants::DW_OP_lit9, Operation::UnsignedConstant { value: 9 }), + (constants::DW_OP_lit10, Operation::UnsignedConstant { value: 10 }), + (constants::DW_OP_lit11, Operation::UnsignedConstant { value: 11 }), + (constants::DW_OP_lit12, Operation::UnsignedConstant { value: 12 }), + (constants::DW_OP_lit13, Operation::UnsignedConstant { value: 13 }), + (constants::DW_OP_lit14, Operation::UnsignedConstant { value: 14 }), + (constants::DW_OP_lit15, Operation::UnsignedConstant { value: 15 }), + (constants::DW_OP_lit16, Operation::UnsignedConstant { value: 16 }), + (constants::DW_OP_lit17, Operation::UnsignedConstant { value: 17 }), + (constants::DW_OP_lit18, Operation::UnsignedConstant { value: 18 }), + (constants::DW_OP_lit19, Operation::UnsignedConstant { value: 19 }), + (constants::DW_OP_lit20, Operation::UnsignedConstant { value: 20 }), + (constants::DW_OP_lit21, Operation::UnsignedConstant { value: 21 }), + (constants::DW_OP_lit22, Operation::UnsignedConstant { value: 22 }), + (constants::DW_OP_lit23, Operation::UnsignedConstant { value: 23 }), + (constants::DW_OP_lit24, Operation::UnsignedConstant { value: 24 }), + (constants::DW_OP_lit25, Operation::UnsignedConstant { value: 25 }), + (constants::DW_OP_lit26, Operation::UnsignedConstant { value: 26 }), + (constants::DW_OP_lit27, Operation::UnsignedConstant { value: 27 }), + (constants::DW_OP_lit28, Operation::UnsignedConstant { value: 28 }), + (constants::DW_OP_lit29, Operation::UnsignedConstant { value: 29 }), + (constants::DW_OP_lit30, Operation::UnsignedConstant { value: 30 }), + (constants::DW_OP_lit31, Operation::UnsignedConstant { value: 31 }), + (constants::DW_OP_reg0, Operation::Register { register: Register(0) }), + (constants::DW_OP_reg1, Operation::Register { register: Register(1) }), + (constants::DW_OP_reg2, Operation::Register { register: Register(2) }), + (constants::DW_OP_reg3, Operation::Register { register: Register(3) }), + (constants::DW_OP_reg4, Operation::Register { register: Register(4) }), + (constants::DW_OP_reg5, Operation::Register { register: Register(5) }), + (constants::DW_OP_reg6, Operation::Register { register: Register(6) }), + (constants::DW_OP_reg7, Operation::Register { register: Register(7) }), + (constants::DW_OP_reg8, Operation::Register { register: Register(8) }), + (constants::DW_OP_reg9, Operation::Register { register: Register(9) }), + (constants::DW_OP_reg10, Operation::Register { register: Register(10) }), + (constants::DW_OP_reg11, Operation::Register { register: Register(11) }), + (constants::DW_OP_reg12, Operation::Register { register: Register(12) }), + (constants::DW_OP_reg13, Operation::Register { register: Register(13) }), + (constants::DW_OP_reg14, Operation::Register { register: Register(14) }), + (constants::DW_OP_reg15, Operation::Register { register: Register(15) }), + (constants::DW_OP_reg16, Operation::Register { register: Register(16) }), + (constants::DW_OP_reg17, Operation::Register { register: Register(17) }), + (constants::DW_OP_reg18, Operation::Register { register: Register(18) }), + (constants::DW_OP_reg19, Operation::Register { register: Register(19) }), + (constants::DW_OP_reg20, Operation::Register { register: Register(20) }), + (constants::DW_OP_reg21, Operation::Register { register: Register(21) }), + (constants::DW_OP_reg22, Operation::Register { register: Register(22) }), + (constants::DW_OP_reg23, Operation::Register { register: Register(23) }), + (constants::DW_OP_reg24, Operation::Register { register: Register(24) }), + (constants::DW_OP_reg25, Operation::Register { register: Register(25) }), + (constants::DW_OP_reg26, Operation::Register { register: Register(26) }), + (constants::DW_OP_reg27, Operation::Register { register: Register(27) }), + (constants::DW_OP_reg28, Operation::Register { register: Register(28) }), + (constants::DW_OP_reg29, Operation::Register { register: Register(29) }), + (constants::DW_OP_reg30, Operation::Register { register: Register(30) }), + (constants::DW_OP_reg31, Operation::Register { register: Register(31) }), + (constants::DW_OP_nop, Operation::Nop), + (constants::DW_OP_push_object_address, Operation::PushObjectAddress), + (constants::DW_OP_form_tls_address, Operation::TLS), + (constants::DW_OP_GNU_push_tls_address, Operation::TLS), + (constants::DW_OP_call_frame_cfa, Operation::CallFrameCFA), + (constants::DW_OP_stack_value, Operation::StackValue), + ]; + + let input = []; + check_op_parse_eof(&input[..], encoding); + + for item in inputs.iter() { + let (opcode, ref result) = *item; + check_op_parse(|s| s.D8(opcode.0), result, encoding); + } + } + + #[test] + fn test_op_parse_twobyte() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let inputs = [ + ( + constants::DW_OP_const1u, + 23, + Operation::UnsignedConstant { value: 23 }, + ), + ( + constants::DW_OP_const1s, + (-23i8) as u8, + Operation::SignedConstant { value: -23 }, + ), + (constants::DW_OP_pick, 7, Operation::Pick { index: 7 }), + ( + constants::DW_OP_deref_size, + 19, + Operation::Deref { + base_type: generic_type(), + size: 19, + space: false, + }, + ), + ( + constants::DW_OP_xderef_size, + 19, + Operation::Deref { + base_type: generic_type(), + size: 19, + space: true, + }, + ), + ]; + + for item in inputs.iter() { + let (opcode, arg, ref result) = *item; + check_op_parse(|s| s.D8(opcode.0).D8(arg), result, encoding); + } + } + + #[test] + fn test_op_parse_threebyte() { + // Doesn't matter for this test. + let encoding = encoding4(); + + // While bra and skip are 3-byte opcodes, they aren't tested here, + // but rather specially in their own function. + let inputs = [ + ( + constants::DW_OP_const2u, + 23, + Operation::UnsignedConstant { value: 23 }, + ), + ( + constants::DW_OP_const2s, + (-23i16) as u16, + Operation::SignedConstant { value: -23 }, + ), + ( + constants::DW_OP_call2, + 1138, + Operation::Call { + offset: DieReference::UnitRef(UnitOffset(1138)), + }, + ), + ( + constants::DW_OP_bra, + (-23i16) as u16, + Operation::Bra { target: -23 }, + ), + ( + constants::DW_OP_skip, + (-23i16) as u16, + Operation::Skip { target: -23 }, + ), + ]; + + for item in inputs.iter() { + let (opcode, arg, ref result) = *item; + check_op_parse(|s| s.D8(opcode.0).L16(arg), result, encoding); + } + } + + #[test] + fn test_op_parse_fivebyte() { + // There are some tests here that depend on address size. + let encoding = encoding4(); + + let inputs = [ + ( + constants::DW_OP_addr, + 0x1234_5678, + Operation::Address { + address: 0x1234_5678, + }, + ), + ( + constants::DW_OP_const4u, + 0x1234_5678, + Operation::UnsignedConstant { value: 0x1234_5678 }, + ), + ( + constants::DW_OP_const4s, + (-23i32) as u32, + Operation::SignedConstant { value: -23 }, + ), + ( + constants::DW_OP_call4, + 0x1234_5678, + Operation::Call { + offset: DieReference::UnitRef(UnitOffset(0x1234_5678)), + }, + ), + ( + constants::DW_OP_call_ref, + 0x1234_5678, + Operation::Call { + offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678)), + }, + ), + ]; + + for item in inputs.iter() { + let (op, arg, ref expect) = *item; + check_op_parse(|s| s.D8(op.0).L32(arg), expect, encoding); + } + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_op_parse_ninebyte() { + // There are some tests here that depend on address size. + let encoding = encoding8(); + + let inputs = [ + ( + constants::DW_OP_addr, + 0x1234_5678_1234_5678, + Operation::Address { + address: 0x1234_5678_1234_5678, + }, + ), + ( + constants::DW_OP_const8u, + 0x1234_5678_1234_5678, + Operation::UnsignedConstant { + value: 0x1234_5678_1234_5678, + }, + ), + ( + constants::DW_OP_const8s, + (-23i64) as u64, + Operation::SignedConstant { value: -23 }, + ), + ( + constants::DW_OP_call_ref, + 0x1234_5678_1234_5678, + Operation::Call { + offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678_1234_5678)), + }, + ), + ]; + + for item in inputs.iter() { + let (op, arg, ref expect) = *item; + check_op_parse(|s| s.D8(op.0).L64(arg), expect, encoding); + } + } + + #[test] + fn test_op_parse_sleb() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let values = [ + -1i64, + 0, + 1, + 0x100, + 0x1eee_eeee, + 0x7fff_ffff_ffff_ffff, + -0x100, + -0x1eee_eeee, + -0x7fff_ffff_ffff_ffff, + ]; + for value in values.iter() { + let mut inputs = vec![ + ( + constants::DW_OP_consts.0, + Operation::SignedConstant { value: *value }, + ), + ( + constants::DW_OP_fbreg.0, + Operation::FrameOffset { offset: *value }, + ), + ]; + + for i in 0..32 { + inputs.push(( + constants::DW_OP_breg0.0 + i, + Operation::RegisterOffset { + register: Register(i.into()), + offset: *value, + base_type: UnitOffset(0), + }, + )); + } + + for item in inputs.iter() { + let (op, ref expect) = *item; + check_op_parse(|s| s.D8(op).sleb(*value), expect, encoding); + } + } + } + + #[test] + fn test_op_parse_uleb() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let values = [ + 0, + 1, + 0x100, + (!0u16).into(), + 0x1eee_eeee, + 0x7fff_ffff_ffff_ffff, + !0u64, + ]; + for value in values.iter() { + let mut inputs = vec![ + ( + constants::DW_OP_constu, + Operation::UnsignedConstant { value: *value }, + ), + ( + constants::DW_OP_plus_uconst, + Operation::PlusConstant { value: *value }, + ), + ]; + + if *value <= (!0u16).into() { + inputs.push(( + constants::DW_OP_regx, + Operation::Register { + register: Register::from_u64(*value).unwrap(), + }, + )); + } + + if *value <= (!0u32).into() { + inputs.extend(&[ + ( + constants::DW_OP_addrx, + Operation::AddressIndex { + index: DebugAddrIndex(*value as usize), + }, + ), + ( + constants::DW_OP_constx, + Operation::ConstantIndex { + index: DebugAddrIndex(*value as usize), + }, + ), + ]); + } + + // FIXME + if *value < !0u64 / 8 { + inputs.push(( + constants::DW_OP_piece, + Operation::Piece { + size_in_bits: 8 * value, + bit_offset: None, + }, + )); + } + + for item in inputs.iter() { + let (op, ref expect) = *item; + let input = Section::with_endian(Endian::Little) + .D8(op.0) + .uleb(*value) + .get_contents() + .unwrap(); + check_op_parse_simple(&input, expect, encoding); + } + } + } + + #[test] + fn test_op_parse_bregx() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let uvalues = [0, 1, 0x100, !0u16]; + let svalues = [ + -1i64, + 0, + 1, + 0x100, + 0x1eee_eeee, + 0x7fff_ffff_ffff_ffff, + -0x100, + -0x1eee_eeee, + -0x7fff_ffff_ffff_ffff, + ]; + + for v1 in uvalues.iter() { + for v2 in svalues.iter() { + check_op_parse( + |s| s.D8(constants::DW_OP_bregx.0).uleb((*v1).into()).sleb(*v2), + &Operation::RegisterOffset { + register: Register(*v1), + offset: *v2, + base_type: UnitOffset(0), + }, + encoding, + ); + } + } + } + + #[test] + fn test_op_parse_bit_piece() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let values = [0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, !0u64]; + + for v1 in values.iter() { + for v2 in values.iter() { + let input = Section::with_endian(Endian::Little) + .D8(constants::DW_OP_bit_piece.0) + .uleb(*v1) + .uleb(*v2) + .get_contents() + .unwrap(); + check_op_parse_simple( + &input, + &Operation::Piece { + size_in_bits: *v1, + bit_offset: Some(*v2), + }, + encoding, + ); + } + } + } + + #[test] + fn test_op_parse_implicit_value() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let data = b"hello"; + + check_op_parse( + |s| { + s.D8(constants::DW_OP_implicit_value.0) + .uleb(data.len() as u64) + .append_bytes(&data[..]) + }, + &Operation::ImplicitValue { + data: EndianSlice::new(&data[..], LittleEndian), + }, + encoding, + ); + } + + #[test] + fn test_op_parse_const_type() { + // Doesn't matter for this test. + let encoding = encoding4(); + + let data = b"hello"; + + check_op_parse( + |s| { + s.D8(constants::DW_OP_const_type.0) + .uleb(100) + .D8(data.len() as u8) + .append_bytes(&data[..]) + }, + &Operation::TypedLiteral { + base_type: UnitOffset(100), + value: EndianSlice::new(&data[..], LittleEndian), + }, + encoding, + ); + check_op_parse( + |s| { + s.D8(constants::DW_OP_GNU_const_type.0) + .uleb(100) + .D8(data.len() as u8) + .append_bytes(&data[..]) + }, + &Operation::TypedLiteral { + base_type: UnitOffset(100), + value: EndianSlice::new(&data[..], LittleEndian), + }, + encoding, + ); + } + + #[test] + fn test_op_parse_regval_type() { + // Doesn't matter for this test. + let encoding = encoding4(); + + check_op_parse( + |s| s.D8(constants::DW_OP_regval_type.0).uleb(1).uleb(100), + &Operation::RegisterOffset { + register: Register(1), + offset: 0, + base_type: UnitOffset(100), + }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_GNU_regval_type.0).uleb(1).uleb(100), + &Operation::RegisterOffset { + register: Register(1), + offset: 0, + base_type: UnitOffset(100), + }, + encoding, + ); + } + + #[test] + fn test_op_parse_deref_type() { + // Doesn't matter for this test. + let encoding = encoding4(); + + check_op_parse( + |s| s.D8(constants::DW_OP_deref_type.0).D8(8).uleb(100), + &Operation::Deref { + base_type: UnitOffset(100), + size: 8, + space: false, + }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_GNU_deref_type.0).D8(8).uleb(100), + &Operation::Deref { + base_type: UnitOffset(100), + size: 8, + space: false, + }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_xderef_type.0).D8(8).uleb(100), + &Operation::Deref { + base_type: UnitOffset(100), + size: 8, + space: true, + }, + encoding, + ); + } + + #[test] + fn test_op_convert() { + // Doesn't matter for this test. + let encoding = encoding4(); + + check_op_parse( + |s| s.D8(constants::DW_OP_convert.0).uleb(100), + &Operation::Convert { + base_type: UnitOffset(100), + }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_GNU_convert.0).uleb(100), + &Operation::Convert { + base_type: UnitOffset(100), + }, + encoding, + ); + } + + #[test] + fn test_op_reinterpret() { + // Doesn't matter for this test. + let encoding = encoding4(); + + check_op_parse( + |s| s.D8(constants::DW_OP_reinterpret.0).uleb(100), + &Operation::Reinterpret { + base_type: UnitOffset(100), + }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_GNU_reinterpret.0).uleb(100), + &Operation::Reinterpret { + base_type: UnitOffset(100), + }, + encoding, + ); + } + + #[test] + fn test_op_parse_implicit_pointer() { + for op in &[ + constants::DW_OP_implicit_pointer, + constants::DW_OP_GNU_implicit_pointer, + ] { + check_op_parse( + |s| s.D8(op.0).D32(0x1234_5678).sleb(0x123), + &Operation::ImplicitPointer { + value: DebugInfoOffset(0x1234_5678), + byte_offset: 0x123, + }, + encoding4(), + ); + + check_op_parse( + |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), + &Operation::ImplicitPointer { + value: DebugInfoOffset(0x1234_5678), + byte_offset: 0x123, + }, + encoding8(), + ); + + check_op_parse( + |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), + &Operation::ImplicitPointer { + value: DebugInfoOffset(0x1234_5678), + byte_offset: 0x123, + }, + Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }, + ) + } + } + + #[test] + fn test_op_parse_entry_value() { + for op in &[ + constants::DW_OP_entry_value, + constants::DW_OP_GNU_entry_value, + ] { + let data = b"hello"; + check_op_parse( + |s| s.D8(op.0).uleb(data.len() as u64).append_bytes(&data[..]), + &Operation::EntryValue { + expression: EndianSlice::new(&data[..], LittleEndian), + }, + encoding4(), + ); + } + } + + #[test] + fn test_op_parse_gnu_parameter_ref() { + check_op_parse( + |s| s.D8(constants::DW_OP_GNU_parameter_ref.0).D32(0x1234_5678), + &Operation::ParameterRef { + offset: UnitOffset(0x1234_5678), + }, + encoding4(), + ) + } + + #[test] + fn test_op_wasm() { + // Doesn't matter for this test. + let encoding = encoding4(); + + check_op_parse( + |s| s.D8(constants::DW_OP_WASM_location.0).D8(0).uleb(1000), + &Operation::WasmLocal { index: 1000 }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_WASM_location.0).D8(1).uleb(1000), + &Operation::WasmGlobal { index: 1000 }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_WASM_location.0).D8(2).uleb(1000), + &Operation::WasmStack { index: 1000 }, + encoding, + ); + check_op_parse( + |s| s.D8(constants::DW_OP_WASM_location.0).D8(3).D32(1000), + &Operation::WasmGlobal { index: 1000 }, + encoding, + ); + } + + enum AssemblerEntry { + Op(constants::DwOp), + Mark(u8), + Branch(u8), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + Uleb(u64), + Sleb(u64), + } + + fn assemble(entries: &[AssemblerEntry]) -> Vec { + let mut result = Vec::new(); + + struct Marker(Option, Vec); + + let mut markers = Vec::new(); + for _ in 0..256 { + markers.push(Marker(None, Vec::new())); + } + + fn write(stack: &mut [u8], index: usize, mut num: u64, nbytes: u8) { + for i in 0..nbytes as usize { + stack[index + i] = (num & 0xff) as u8; + num >>= 8; + } + } + + fn push(stack: &mut Vec, num: u64, nbytes: u8) { + let index = stack.len(); + for _ in 0..nbytes { + stack.push(0); + } + write(stack, index, num, nbytes); + } + + for item in entries { + match *item { + AssemblerEntry::Op(op) => result.push(op.0), + AssemblerEntry::Mark(num) => { + assert!(markers[num as usize].0.is_none()); + markers[num as usize].0 = Some(result.len()); + } + AssemblerEntry::Branch(num) => { + markers[num as usize].1.push(result.len()); + push(&mut result, 0, 2); + } + AssemblerEntry::U8(num) => result.push(num), + AssemblerEntry::U16(num) => push(&mut result, u64::from(num), 2), + AssemblerEntry::U32(num) => push(&mut result, u64::from(num), 4), + AssemblerEntry::U64(num) => push(&mut result, num, 8), + AssemblerEntry::Uleb(num) => { + leb128::write::unsigned(&mut result, num).unwrap(); + } + AssemblerEntry::Sleb(num) => { + leb128::write::signed(&mut result, num as i64).unwrap(); + } + } + } + + // Update all the branches. + for marker in markers { + if let Some(offset) = marker.0 { + for branch_offset in marker.1 { + let delta = offset.wrapping_sub(branch_offset + 2) as u64; + write(&mut result, branch_offset, delta, 2); + } + } + } + + result + } + + fn check_eval_with_args( + program: &[AssemblerEntry], + expect: Result<&[Piece>]>, + encoding: Encoding, + object_address: Option, + initial_value: Option, + max_iterations: Option, + f: F, + ) where + for<'a> F: Fn( + &mut Evaluation>, + EvaluationResult>, + ) -> Result>>, + { + let bytes = assemble(program); + let bytes = EndianSlice::new(&bytes, LittleEndian); + + let mut eval = Evaluation::new(bytes, encoding); + + if let Some(val) = object_address { + eval.set_object_address(val); + } + if let Some(val) = initial_value { + eval.set_initial_value(val); + } + if let Some(val) = max_iterations { + eval.set_max_iterations(val); + } + + let result = match eval.evaluate() { + Err(e) => Err(e), + Ok(r) => f(&mut eval, r), + }; + + match (result, expect) { + (Ok(EvaluationResult::Complete), Ok(pieces)) => { + let vec = eval.result(); + assert_eq!(vec.len(), pieces.len()); + for i in 0..pieces.len() { + assert_eq!(vec[i], pieces[i]); + } + } + (Err(f1), Err(f2)) => { + assert_eq!(f1, f2); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + fn check_eval( + program: &[AssemblerEntry], + expect: Result<&[Piece>]>, + encoding: Encoding, + ) { + check_eval_with_args(program, expect, encoding, None, None, None, |_, result| { + Ok(result) + }); + } + + #[test] + fn test_eval_arith() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Indices of marks in the assembly. + let done = 0; + let fail = 1; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_const1u), U8(23), + Op(DW_OP_const1s), U8((-23i8) as u8), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const2u), U16(23), + Op(DW_OP_const2s), U16((-23i16) as u16), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4u), U32(0x1111_2222), + Op(DW_OP_const4s), U32((-0x1111_2222i32) as u32), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + // Plus should overflow. + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1u), U8(1), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_plus_uconst), Uleb(1), + Op(DW_OP_bra), Branch(fail), + + // Minus should underflow. + Op(DW_OP_const1s), U8(0), + Op(DW_OP_const1u), U8(1), + Op(DW_OP_minus), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_abs), + Op(DW_OP_const1u), U8(1), + Op(DW_OP_minus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4u), U32(0xf078_fffe), + Op(DW_OP_const4u), U32(0x0f87_0001), + Op(DW_OP_and), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4u), U32(0xf078_fffe), + Op(DW_OP_const4u), U32(0xf000_00fe), + Op(DW_OP_and), + Op(DW_OP_const4u), U32(0xf000_00fe), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + // Division is signed. + Op(DW_OP_const1s), U8(0xfe), + Op(DW_OP_const1s), U8(2), + Op(DW_OP_div), + Op(DW_OP_plus_uconst), Uleb(1), + Op(DW_OP_bra), Branch(fail), + + // Mod is unsigned. + Op(DW_OP_const1s), U8(0xfd), + Op(DW_OP_const1s), U8(2), + Op(DW_OP_mod), + Op(DW_OP_neg), + Op(DW_OP_plus_uconst), Uleb(1), + Op(DW_OP_bra), Branch(fail), + + // Overflow is defined for multiplication. + Op(DW_OP_const4u), U32(0x8000_0001), + Op(DW_OP_lit2), + Op(DW_OP_mul), + Op(DW_OP_lit2), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4u), U32(0xf0f0_f0f0), + Op(DW_OP_const4u), U32(0xf0f0_f0f0), + Op(DW_OP_xor), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4u), U32(0xf0f0_f0f0), + Op(DW_OP_const4u), U32(0x0f0f_0f0f), + Op(DW_OP_or), + Op(DW_OP_not), + Op(DW_OP_bra), Branch(fail), + + // In 32 bit mode, values are truncated. + Op(DW_OP_const8u), U64(0xffff_ffff_0000_0000), + Op(DW_OP_lit2), + Op(DW_OP_div), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1u), U8(0xff), + Op(DW_OP_lit1), + Op(DW_OP_shl), + Op(DW_OP_const2u), U16(0x1fe), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1u), U8(0xff), + Op(DW_OP_const1u), U8(50), + Op(DW_OP_shl), + Op(DW_OP_bra), Branch(fail), + + // Absurd shift. + Op(DW_OP_const1u), U8(0xff), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_shl), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_lit1), + Op(DW_OP_shr), + Op(DW_OP_const4u), U32(0x7fff_ffff), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1u), U8(0xff), + Op(DW_OP_shr), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_lit1), + Op(DW_OP_shra), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1u), U8(0xff), + Op(DW_OP_shra), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + // Success. + Op(DW_OP_lit0), + Op(DW_OP_nop), + Op(DW_OP_skip), Branch(done), + + Mark(fail), + Op(DW_OP_lit1), + + Mark(done), + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0), + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + } + + #[test] + fn test_eval_arith64() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Indices of marks in the assembly. + let done = 0; + let fail = 1; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_const8u), U64(0x1111_2222_3333_4444), + Op(DW_OP_const8s), U64((-0x1111_2222_3333_4444i64) as u64), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_constu), Uleb(0x1111_2222_3333_4444), + Op(DW_OP_consts), Sleb((-0x1111_2222_3333_4444i64) as u64), + Op(DW_OP_plus), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit1), + Op(DW_OP_plus_uconst), Uleb(!0u64), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit1), + Op(DW_OP_neg), + Op(DW_OP_not), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), + Op(DW_OP_const1u), U8(63), + Op(DW_OP_shr), + Op(DW_OP_lit1), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), + Op(DW_OP_const1u), U8(62), + Op(DW_OP_shra), + Op(DW_OP_plus_uconst), Uleb(2), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit1), + Op(DW_OP_const1u), U8(63), + Op(DW_OP_shl), + Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + // Success. + Op(DW_OP_lit0), + Op(DW_OP_nop), + Op(DW_OP_skip), Branch(done), + + Mark(fail), + Op(DW_OP_lit1), + + Mark(done), + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0), + }, + }]; + + check_eval(&program, Ok(&result), encoding8()); + } + + #[test] + fn test_eval_compare() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Indices of marks in the assembly. + let done = 0; + let fail = 1; + + #[rustfmt::skip] + let program = [ + // Comparisons are signed. + Op(DW_OP_const1s), U8(1), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_lt), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1s), U8(1), + Op(DW_OP_gt), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(1), + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_le), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1s), U8(1), + Op(DW_OP_ge), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const1s), U8(0xff), + Op(DW_OP_const1s), U8(1), + Op(DW_OP_eq), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_const4s), U32(1), + Op(DW_OP_const1s), U8(1), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + // Success. + Op(DW_OP_lit0), + Op(DW_OP_nop), + Op(DW_OP_skip), Branch(done), + + Mark(fail), + Op(DW_OP_lit1), + + Mark(done), + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0), + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + } + + #[test] + fn test_eval_stack() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_lit17), // -- 17 + Op(DW_OP_dup), // -- 17 17 + Op(DW_OP_over), // -- 17 17 17 + Op(DW_OP_minus), // -- 17 0 + Op(DW_OP_swap), // -- 0 17 + Op(DW_OP_dup), // -- 0 17 17 + Op(DW_OP_plus_uconst), Uleb(1), // -- 0 17 18 + Op(DW_OP_rot), // -- 18 0 17 + Op(DW_OP_pick), U8(2), // -- 18 0 17 18 + Op(DW_OP_pick), U8(3), // -- 18 0 17 18 18 + Op(DW_OP_minus), // -- 18 0 17 0 + Op(DW_OP_drop), // -- 18 0 17 + Op(DW_OP_swap), // -- 18 17 0 + Op(DW_OP_drop), // -- 18 17 + Op(DW_OP_minus), // -- 1 + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(1), + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + } + + #[test] + fn test_eval_lit_and_reg() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + let mut program = Vec::new(); + program.push(Op(DW_OP_lit0)); + for i in 0..32 { + program.push(Op(DwOp(DW_OP_lit0.0 + i))); + program.push(Op(DwOp(DW_OP_breg0.0 + i))); + program.push(Sleb(u64::from(i))); + program.push(Op(DW_OP_plus)); + program.push(Op(DW_OP_plus)); + } + + program.push(Op(DW_OP_bregx)); + program.push(Uleb(0x1234)); + program.push(Sleb(0x1234)); + program.push(Op(DW_OP_plus)); + + program.push(Op(DW_OP_stack_value)); + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(496), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = eval.resume_with_register(match result { + EvaluationResult::RequiresRegister { + register, + base_type, + } => { + assert_eq!(base_type, UnitOffset(0)); + Value::Generic(u64::from(register.0).wrapping_neg()) + } + _ => panic!(), + })?; + } + Ok(result) + }, + ); + } + + #[test] + fn test_eval_memory() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Indices of marks in the assembly. + let done = 0; + let fail = 1; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_deref), + Op(DW_OP_const4u), U32(0xffff_fffc), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_deref_size), U8(2), + Op(DW_OP_const4u), U32(0xfffc), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit1), + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_xderef), + Op(DW_OP_const4u), U32(0xffff_fffd), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit1), + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_xderef_size), U8(2), + Op(DW_OP_const4u), U32(0xfffd), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit17), + Op(DW_OP_form_tls_address), + Op(DW_OP_constu), Uleb(!17), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_lit17), + Op(DW_OP_GNU_push_tls_address), + Op(DW_OP_constu), Uleb(!17), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_addrx), Uleb(0x10), + Op(DW_OP_deref), + Op(DW_OP_const4u), U32(0x4040), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_constx), Uleb(17), + Op(DW_OP_form_tls_address), + Op(DW_OP_constu), Uleb(!27), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + // Success. + Op(DW_OP_lit0), + Op(DW_OP_nop), + Op(DW_OP_skip), Branch(done), + + Mark(fail), + Op(DW_OP_lit1), + + Mark(done), + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = match result { + EvaluationResult::RequiresMemory { + address, + size, + space, + base_type, + } => { + assert_eq!(base_type, UnitOffset(0)); + let mut v = address << 2; + if let Some(value) = space { + v += value; + } + v &= (1u64 << (8 * size)) - 1; + eval.resume_with_memory(Value::Generic(v))? + } + EvaluationResult::RequiresTls(slot) => eval.resume_with_tls(!slot)?, + EvaluationResult::RequiresRelocatedAddress(address) => { + eval.resume_with_relocated_address(address)? + } + EvaluationResult::RequiresIndexedAddress { index, relocate } => { + if relocate { + eval.resume_with_indexed_address(0x1000 + index.0 as u64)? + } else { + eval.resume_with_indexed_address(10 + index.0 as u64)? + } + } + _ => panic!(), + }; + } + + Ok(result) + }, + ); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_deref_size), U8(8), + ]; + check_eval_with_args( + &program, + Err(Error::InvalidDerefSize(8)), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = match result { + EvaluationResult::RequiresMemory { + address, + size, + space, + base_type, + } => { + assert_eq!(base_type, UnitOffset(0)); + let mut v = address << 2; + if let Some(value) = space { + v += value; + } + v &= (1u64 << (8 * size)) - 1; + eval.resume_with_memory(Value::Generic(v))? + } + EvaluationResult::RequiresRelocatedAddress(address) => { + eval.resume_with_relocated_address(address)? + } + _ => panic!("Unexpected result: {:?}", result), + }; + } + + Ok(result) + }, + ); + } + + #[test] + fn test_eval_register() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + for i in 0..32 { + #[rustfmt::skip] + let program = [ + Op(DwOp(DW_OP_reg0.0 + i)), + // Included only in the "bad" run. + Op(DW_OP_lit23), + ]; + let ok_result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Register { + register: Register(i.into()), + }, + }]; + + check_eval(&program[..1], Ok(&ok_result), encoding4()); + + check_eval( + &program, + Err(Error::InvalidExpressionTerminator(1)), + encoding4(), + ); + } + + #[rustfmt::skip] + let program = [ + Op(DW_OP_regx), Uleb(0x1234) + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Register { + register: Register(0x1234), + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + } + + #[test] + fn test_eval_context() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Test `frame_base` and `call_frame_cfa` callbacks. + #[rustfmt::skip] + let program = [ + Op(DW_OP_fbreg), Sleb((-8i8) as u64), + Op(DW_OP_call_frame_cfa), + Op(DW_OP_plus), + Op(DW_OP_neg), + Op(DW_OP_stack_value) + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(9), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding8(), + None, + None, + None, + |eval, result| { + match result { + EvaluationResult::RequiresFrameBase => {} + _ => panic!(), + }; + match eval.resume_with_frame_base(0x0123_4567_89ab_cdef)? { + EvaluationResult::RequiresCallFrameCfa => {} + _ => panic!(), + }; + eval.resume_with_call_frame_cfa(0xfedc_ba98_7654_3210) + }, + ); + + // Test `evaluate_entry_value` callback. + #[rustfmt::skip] + let program = [ + Op(DW_OP_entry_value), Uleb(8), U64(0x1234_5678), + Op(DW_OP_stack_value) + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0x1234_5678), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding8(), + None, + None, + None, + |eval, result| { + let entry_value = match result { + EvaluationResult::RequiresEntryValue(mut expression) => { + expression.0.read_u64()? + } + _ => panic!(), + }; + eval.resume_with_entry_value(Value::Generic(entry_value)) + }, + ); + + // Test missing `object_address` field. + #[rustfmt::skip] + let program = [ + Op(DW_OP_push_object_address), + ]; + + check_eval_with_args( + &program, + Err(Error::InvalidPushObjectAddress), + encoding4(), + None, + None, + None, + |_, _| panic!(), + ); + + // Test `object_address` field. + #[rustfmt::skip] + let program = [ + Op(DW_OP_push_object_address), + Op(DW_OP_stack_value), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(0xff), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding8(), + Some(0xff), + None, + None, + |_, result| Ok(result), + ); + + // Test `initial_value` field. + #[rustfmt::skip] + let program = [ + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Address { + address: 0x1234_5678, + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding8(), + None, + Some(0x1234_5678), + None, + |_, result| Ok(result), + ); + } + + #[test] + fn test_eval_empty_stack() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_stack_value) + ]; + + check_eval(&program, Err(Error::NotEnoughStackItems), encoding4()); + } + + #[test] + fn test_eval_call() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + #[rustfmt::skip] + let program = [ + Op(DW_OP_lit23), + Op(DW_OP_call2), U16(0x7755), + Op(DW_OP_call4), U32(0x7755_aaee), + Op(DW_OP_call_ref), U32(0x7755_aaee), + Op(DW_OP_stack_value) + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(23), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, result| { + let buf = EndianSlice::new(&[], LittleEndian); + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf)?; + + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf)?; + + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf) + }, + ); + + // DW_OP_lit2 DW_OP_mul + const SUBR: &[u8] = &[0x32, 0x1e]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { + value: Value::Generic(184), + }, + }]; + + check_eval_with_args( + &program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, result| { + let buf = EndianSlice::new(SUBR, LittleEndian); + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf)?; + + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf)?; + + match result { + EvaluationResult::RequiresAtLocation(_) => {} + _ => panic!(), + }; + + eval.resume_with_at_location(buf) + }, + ); + } + + #[test] + fn test_eval_pieces() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + // Example from DWARF 2.6.1.3. + #[rustfmt::skip] + let program = [ + Op(DW_OP_reg3), + Op(DW_OP_piece), Uleb(4), + Op(DW_OP_reg4), + Op(DW_OP_piece), Uleb(2), + ]; + + let result = [ + Piece { + size_in_bits: Some(32), + bit_offset: None, + location: Location::Register { + register: Register(3), + }, + }, + Piece { + size_in_bits: Some(16), + bit_offset: None, + location: Location::Register { + register: Register(4), + }, + }, + ]; + + check_eval(&program, Ok(&result), encoding4()); + + // Example from DWARF 2.6.1.3 (but hacked since dealing with fbreg + // in the tests is a pain). + #[rustfmt::skip] + let program = [ + Op(DW_OP_reg0), + Op(DW_OP_piece), Uleb(4), + Op(DW_OP_piece), Uleb(4), + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_piece), Uleb(4), + ]; + + let result = [ + Piece { + size_in_bits: Some(32), + bit_offset: None, + location: Location::Register { + register: Register(0), + }, + }, + Piece { + size_in_bits: Some(32), + bit_offset: None, + location: Location::Empty, + }, + Piece { + size_in_bits: Some(32), + bit_offset: None, + location: Location::Address { + address: 0x7fff_ffff, + }, + }, + ]; + + check_eval_with_args( + &program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = match result { + EvaluationResult::RequiresRelocatedAddress(address) => { + eval.resume_with_relocated_address(address)? + } + _ => panic!(), + }; + } + + Ok(result) + }, + ); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_implicit_value), Uleb(5), + U8(23), U8(24), U8(25), U8(26), U8(0), + ]; + + const BYTES: &[u8] = &[23, 24, 25, 26, 0]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Bytes { + value: EndianSlice::new(BYTES, LittleEndian), + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_lit7), + Op(DW_OP_stack_value), + Op(DW_OP_bit_piece), Uleb(5), Uleb(0), + Op(DW_OP_bit_piece), Uleb(3), Uleb(0), + ]; + + let result = [ + Piece { + size_in_bits: Some(5), + bit_offset: Some(0), + location: Location::Value { + value: Value::Generic(7), + }, + }, + Piece { + size_in_bits: Some(3), + bit_offset: Some(0), + location: Location::Empty, + }, + ]; + + check_eval(&program, Ok(&result), encoding4()); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_lit7), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Address { address: 7 }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_implicit_pointer), U32(0x1234_5678), Sleb(0x123), + ]; + + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::ImplicitPointer { + value: DebugInfoOffset(0x1234_5678), + byte_offset: 0x123, + }, + }]; + + check_eval(&program, Ok(&result), encoding4()); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_reg3), + Op(DW_OP_piece), Uleb(4), + Op(DW_OP_reg4), + ]; + + check_eval(&program, Err(Error::InvalidPiece), encoding4()); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_reg3), + Op(DW_OP_piece), Uleb(4), + Op(DW_OP_lit0), + ]; + + check_eval(&program, Err(Error::InvalidPiece), encoding4()); + } + + #[test] + fn test_eval_max_iterations() { + // It's nice if an operation and its arguments can fit on a single + // line in the test program. + use self::AssemblerEntry::*; + use crate::constants::*; + + #[rustfmt::skip] + let program = [ + Mark(1), + Op(DW_OP_skip), Branch(1), + ]; + + check_eval_with_args( + &program, + Err(Error::TooManyIterations), + encoding4(), + None, + None, + Some(150), + |_, _| panic!(), + ); + } + + #[test] + fn test_eval_typed_stack() { + use self::AssemblerEntry::*; + use crate::constants::*; + + let base_types = [ + ValueType::Generic, + ValueType::U16, + ValueType::U32, + ValueType::F32, + ]; + + // TODO: convert, reinterpret + #[rustfmt::skip] + let tests = [ + ( + &[ + Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), + Op(DW_OP_stack_value), + ][..], + Value::U16(0x1234), + ), + ( + &[ + Op(DW_OP_regval_type), Uleb(0x1234), Uleb(1), + Op(DW_OP_stack_value), + ][..], + Value::U16(0x2340), + ), + ( + &[ + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_deref_type), U8(2), Uleb(1), + Op(DW_OP_stack_value), + ][..], + Value::U16(0xfff0), + ), + ( + &[ + Op(DW_OP_lit1), + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_xderef_type), U8(2), Uleb(1), + Op(DW_OP_stack_value), + ][..], + Value::U16(0xfff1), + ), + ( + &[ + Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), + Op(DW_OP_convert), Uleb(2), + Op(DW_OP_stack_value), + ][..], + Value::U32(0x1234), + ), + ( + &[ + Op(DW_OP_const_type), Uleb(2), U8(4), U32(0x3f80_0000), + Op(DW_OP_reinterpret), Uleb(3), + Op(DW_OP_stack_value), + ][..], + Value::F32(1.0), + ), + ]; + for &(program, value) in &tests { + let result = [Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Value { value }, + }]; + + check_eval_with_args( + program, + Ok(&result), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = match result { + EvaluationResult::RequiresMemory { + address, + size, + space, + base_type, + } => { + let mut v = address << 4; + if let Some(value) = space { + v += value; + } + v &= (1u64 << (8 * size)) - 1; + let v = Value::from_u64(base_types[base_type.0], v)?; + eval.resume_with_memory(v)? + } + EvaluationResult::RequiresRegister { + register, + base_type, + } => { + let v = Value::from_u64( + base_types[base_type.0], + u64::from(register.0) << 4, + )?; + eval.resume_with_register(v)? + } + EvaluationResult::RequiresBaseType(offset) => { + eval.resume_with_base_type(base_types[offset.0])? + } + EvaluationResult::RequiresRelocatedAddress(address) => { + eval.resume_with_relocated_address(address)? + } + _ => panic!("Unexpected result {:?}", result), + } + } + Ok(result) + }, + ); + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/pubnames.rs b/deps/crates/vendor/gimli/src/read/pubnames.rs new file mode 100644 index 00000000000000..e8b7e5528633fc --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/pubnames.rs @@ -0,0 +1,141 @@ +use crate::common::{DebugInfoOffset, SectionId}; +use crate::endianity::Endianity; +use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; +use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset}; + +/// A single parsed pubname. +#[derive(Debug, Clone)] +pub struct PubNamesEntry { + unit_header_offset: DebugInfoOffset, + die_offset: UnitOffset, + name: R, +} + +impl PubNamesEntry { + /// Returns the name this entry refers to. + pub fn name(&self) -> &R { + &self.name + } + + /// Returns the offset into the .debug_info section for the header of the compilation unit + /// which contains this name. + pub fn unit_header_offset(&self) -> DebugInfoOffset { + self.unit_header_offset + } + + /// Returns the offset into the compilation unit for the debugging information entry which + /// has this name. + pub fn die_offset(&self) -> UnitOffset { + self.die_offset + } +} + +impl PubStuffEntry for PubNamesEntry { + fn new( + die_offset: UnitOffset, + name: R, + unit_header_offset: DebugInfoOffset, + ) -> Self { + PubNamesEntry { + unit_header_offset, + die_offset, + name, + } + } +} + +/// The `DebugPubNames` struct represents the DWARF public names information +/// found in the `.debug_pubnames` section. +#[derive(Debug, Clone)] +pub struct DebugPubNames(DebugLookup>>); + +impl<'input, Endian> DebugPubNames> +where + Endian: Endianity, +{ + /// Construct a new `DebugPubNames` instance from the data in the `.debug_pubnames` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_pubnames` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugPubNames, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_pubnames_section_somehow = || &buf; + /// let debug_pubnames = + /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_pubnames_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_pubnames_section, endian)) + } +} + +impl DebugPubNames { + /// Iterate the pubnames in the `.debug_pubnames` section. + /// + /// ``` + /// use gimli::{DebugPubNames, EndianSlice, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_pubnames_section_somehow = || &buf; + /// let debug_pubnames = + /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); + /// + /// let mut iter = debug_pubnames.items(); + /// while let Some(pubname) = iter.next().unwrap() { + /// println!("pubname {} found!", pubname.name().to_string_lossy()); + /// } + /// ``` + pub fn items(&self) -> PubNamesEntryIter { + PubNamesEntryIter(self.0.items()) + } +} + +impl Section for DebugPubNames { + fn id() -> SectionId { + SectionId::DebugPubNames + } + + fn reader(&self) -> &R { + self.0.reader() + } +} + +impl From for DebugPubNames { + fn from(debug_pubnames_section: R) -> Self { + DebugPubNames(DebugLookup::from(debug_pubnames_section)) + } +} + +/// An iterator over the pubnames from a `.debug_pubnames` section. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Debug, Clone)] +pub struct PubNamesEntryIter(LookupEntryIter>>); + +impl PubNamesEntryIter { + /// Advance the iterator and return the next pubname. + /// + /// Returns the newly parsed pubname as `Ok(Some(pubname))`. Returns + /// `Ok(None)` when iteration is complete and all pubnames have already been + /// parsed and yielded. If an error occurs while parsing the next pubname, + /// then this error is returned as `Err(e)`, and all subsequent calls return + /// `Ok(None)`. + pub fn next(&mut self) -> Result>> { + self.0.next() + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for PubNamesEntryIter { + type Item = PubNamesEntry; + type Error = crate::read::Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + self.0.next() + } +} diff --git a/deps/crates/vendor/gimli/src/read/pubtypes.rs b/deps/crates/vendor/gimli/src/read/pubtypes.rs new file mode 100644 index 00000000000000..6723b42228125e --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/pubtypes.rs @@ -0,0 +1,141 @@ +use crate::common::{DebugInfoOffset, SectionId}; +use crate::endianity::Endianity; +use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; +use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset}; + +/// A single parsed pubtype. +#[derive(Debug, Clone)] +pub struct PubTypesEntry { + unit_header_offset: DebugInfoOffset, + die_offset: UnitOffset, + name: R, +} + +impl PubTypesEntry { + /// Returns the name of the type this entry refers to. + pub fn name(&self) -> &R { + &self.name + } + + /// Returns the offset into the .debug_info section for the header of the compilation unit + /// which contains the type with this name. + pub fn unit_header_offset(&self) -> DebugInfoOffset { + self.unit_header_offset + } + + /// Returns the offset into the compilation unit for the debugging information entry which + /// the type with this name. + pub fn die_offset(&self) -> UnitOffset { + self.die_offset + } +} + +impl PubStuffEntry for PubTypesEntry { + fn new( + die_offset: UnitOffset, + name: R, + unit_header_offset: DebugInfoOffset, + ) -> Self { + PubTypesEntry { + unit_header_offset, + die_offset, + name, + } + } +} + +/// The `DebugPubTypes` struct represents the DWARF public types information +/// found in the `.debug_info` section. +#[derive(Debug, Clone)] +pub struct DebugPubTypes(DebugLookup>>); + +impl<'input, Endian> DebugPubTypes> +where + Endian: Endianity, +{ + /// Construct a new `DebugPubTypes` instance from the data in the `.debug_pubtypes` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_pubtypes` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugPubTypes, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_pubtypes_somehow = || &buf; + /// let debug_pubtypes = + /// DebugPubTypes::new(read_debug_pubtypes_somehow(), LittleEndian); + /// ``` + pub fn new(debug_pubtypes_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_pubtypes_section, endian)) + } +} + +impl DebugPubTypes { + /// Iterate the pubtypes in the `.debug_pubtypes` section. + /// + /// ``` + /// use gimli::{DebugPubTypes, EndianSlice, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_pubtypes_section_somehow = || &buf; + /// let debug_pubtypes = + /// DebugPubTypes::new(read_debug_pubtypes_section_somehow(), LittleEndian); + /// + /// let mut iter = debug_pubtypes.items(); + /// while let Some(pubtype) = iter.next().unwrap() { + /// println!("pubtype {} found!", pubtype.name().to_string_lossy()); + /// } + /// ``` + pub fn items(&self) -> PubTypesEntryIter { + PubTypesEntryIter(self.0.items()) + } +} + +impl Section for DebugPubTypes { + fn id() -> SectionId { + SectionId::DebugPubTypes + } + + fn reader(&self) -> &R { + self.0.reader() + } +} + +impl From for DebugPubTypes { + fn from(debug_pubtypes_section: R) -> Self { + DebugPubTypes(DebugLookup::from(debug_pubtypes_section)) + } +} + +/// An iterator over the pubtypes from a `.debug_pubtypes` section. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Debug, Clone)] +pub struct PubTypesEntryIter(LookupEntryIter>>); + +impl PubTypesEntryIter { + /// Advance the iterator and return the next pubtype. + /// + /// Returns the newly parsed pubtype as `Ok(Some(pubtype))`. Returns + /// `Ok(None)` when iteration is complete and all pubtypes have already been + /// parsed and yielded. If an error occurs while parsing the next pubtype, + /// then this error is returned as `Err(e)`, and all subsequent calls return + /// `Ok(None)`. + pub fn next(&mut self) -> Result>> { + self.0.next() + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for PubTypesEntryIter { + type Item = PubTypesEntry; + type Error = crate::read::Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + self.0.next() + } +} diff --git a/deps/crates/vendor/gimli/src/read/reader.rs b/deps/crates/vendor/gimli/src/read/reader.rs new file mode 100644 index 00000000000000..b1654feb6b7a60 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/reader.rs @@ -0,0 +1,554 @@ +#[cfg(feature = "read")] +use alloc::borrow::Cow; +use core::convert::TryInto; +use core::fmt::Debug; +use core::hash::Hash; +use core::ops::{Add, AddAssign, Sub}; + +use crate::common::Format; +use crate::endianity::Endianity; +use crate::leb128; +use crate::read::{Error, Result}; + +/// An identifier for an offset within a section reader. +/// +/// This is used for error reporting. The meaning of this value is specific to +/// each reader implementation. The values should be chosen to be unique amongst +/// all readers. If values are not unique then errors may point to the wrong reader. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ReaderOffsetId(pub u64); + +/// A trait for offsets with a DWARF section. +/// +/// This allows consumers to choose a size that is appropriate for their address space. +pub trait ReaderOffset: + Debug + Copy + Eq + Ord + Hash + Add + AddAssign + Sub +{ + /// Convert a u8 to an offset. + fn from_u8(offset: u8) -> Self; + + /// Convert a u16 to an offset. + fn from_u16(offset: u16) -> Self; + + /// Convert an i16 to an offset. + fn from_i16(offset: i16) -> Self; + + /// Convert a u32 to an offset. + fn from_u32(offset: u32) -> Self; + + /// Convert a u64 to an offset. + /// + /// Returns `Error::UnsupportedOffset` if the value is too large. + fn from_u64(offset: u64) -> Result; + + /// Convert an offset to a u64. + fn into_u64(self) -> u64; + + /// Wrapping (modular) addition. Computes `self + other`. + fn wrapping_add(self, other: Self) -> Self; + + /// Checked subtraction. Computes `self - other`. + fn checked_sub(self, other: Self) -> Option; +} + +impl ReaderOffset for u64 { + #[inline] + fn from_u8(offset: u8) -> Self { + u64::from(offset) + } + + #[inline] + fn from_u16(offset: u16) -> Self { + u64::from(offset) + } + + #[inline] + fn from_i16(offset: i16) -> Self { + offset as u64 + } + + #[inline] + fn from_u32(offset: u32) -> Self { + u64::from(offset) + } + + #[inline] + fn from_u64(offset: u64) -> Result { + Ok(offset) + } + + #[inline] + fn into_u64(self) -> u64 { + self + } + + #[inline] + fn wrapping_add(self, other: Self) -> Self { + self.wrapping_add(other) + } + + #[inline] + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } +} + +impl ReaderOffset for u32 { + #[inline] + fn from_u8(offset: u8) -> Self { + u32::from(offset) + } + + #[inline] + fn from_u16(offset: u16) -> Self { + u32::from(offset) + } + + #[inline] + fn from_i16(offset: i16) -> Self { + offset as u32 + } + + #[inline] + fn from_u32(offset: u32) -> Self { + offset + } + + #[inline] + fn from_u64(offset64: u64) -> Result { + let offset = offset64 as u32; + if u64::from(offset) == offset64 { + Ok(offset) + } else { + Err(Error::UnsupportedOffset) + } + } + + #[inline] + fn into_u64(self) -> u64 { + u64::from(self) + } + + #[inline] + fn wrapping_add(self, other: Self) -> Self { + self.wrapping_add(other) + } + + #[inline] + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } +} + +impl ReaderOffset for usize { + #[inline] + fn from_u8(offset: u8) -> Self { + offset as usize + } + + #[inline] + fn from_u16(offset: u16) -> Self { + offset as usize + } + + #[inline] + fn from_i16(offset: i16) -> Self { + offset as usize + } + + #[inline] + fn from_u32(offset: u32) -> Self { + offset as usize + } + + #[inline] + fn from_u64(offset64: u64) -> Result { + let offset = offset64 as usize; + if offset as u64 == offset64 { + Ok(offset) + } else { + Err(Error::UnsupportedOffset) + } + } + + #[inline] + fn into_u64(self) -> u64 { + self as u64 + } + + #[inline] + fn wrapping_add(self, other: Self) -> Self { + self.wrapping_add(other) + } + + #[inline] + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } +} + +/// A trait for addresses within a DWARF section. +/// +/// Currently this is a simple extension trait for `u64`, but it may be expanded +/// in the future to support user-defined address types. +pub(crate) trait ReaderAddress: Sized { + /// Add a length to an address of the given size. + /// + /// Returns an error for overflow. + fn add_sized(self, length: u64, size: u8) -> Result; + + /// Add a length to an address of the given size. + /// + /// Wraps the result to the size of the address to allow for the possibility + /// that the length is a negative value. + fn wrapping_add_sized(self, length: u64, size: u8) -> Self; + + /// The all-ones value of an address of the given size. + fn ones_sized(size: u8) -> Self; +} + +impl ReaderAddress for u64 { + #[inline] + fn add_sized(self, length: u64, size: u8) -> Result { + let address = self.checked_add(length).ok_or(Error::AddressOverflow)?; + let mask = Self::ones_sized(size); + if address & !mask != 0 { + return Err(Error::AddressOverflow); + } + Ok(address) + } + + #[inline] + fn wrapping_add_sized(self, length: u64, size: u8) -> Self { + let mask = Self::ones_sized(size); + self.wrapping_add(length) & mask + } + + #[inline] + fn ones_sized(size: u8) -> Self { + !0 >> (64 - size * 8) + } +} + +#[cfg(not(feature = "read"))] +pub(crate) mod seal_if_no_alloc { + #[derive(Debug)] + pub struct Sealed; +} + +/// A trait for reading the data from a DWARF section. +/// +/// All read operations advance the section offset of the reader +/// unless specified otherwise. +/// +/// ## Choosing a `Reader` Implementation +/// +/// `gimli` comes with a few different `Reader` implementations and lets you +/// choose the one that is right for your use case. A `Reader` is essentially a +/// view into the raw bytes that make up some DWARF, but this view might borrow +/// the underlying data or use reference counting ownership, and it might be +/// thread safe or not. +/// +/// | Implementation | Ownership | Thread Safe | Notes | +/// |:------------------|:------------------|:------------|:------| +/// | [`EndianSlice`](./struct.EndianSlice.html) | Borrowed | Yes | Fastest, but requires that all of your code work with borrows. | +/// | [`EndianRcSlice`](./struct.EndianRcSlice.html) | Reference counted | No | Shared ownership via reference counting, which alleviates the borrow restrictions of `EndianSlice` but imposes reference counting increments and decrements. Cannot be sent across threads, because the reference count is not atomic. | +/// | [`EndianArcSlice`](./struct.EndianArcSlice.html) | Reference counted | Yes | The same as `EndianRcSlice`, but uses atomic reference counting, and therefore reference counting operations are slower but `EndianArcSlice`s may be sent across threads. | +/// | [`EndianReader`](./struct.EndianReader.html) | Same as `T` | Same as `T` | Escape hatch for easily defining your own type of `Reader`. | +pub trait Reader: Debug + Clone { + /// The endianity of bytes that are read. + type Endian: Endianity; + + /// The type used for offsets and lengths. + type Offset: ReaderOffset; + + /// Return the endianity of bytes that are read. + fn endian(&self) -> Self::Endian; + + /// Return the number of bytes remaining. + fn len(&self) -> Self::Offset; + + /// Set the number of bytes remaining to zero. + fn empty(&mut self); + + /// Set the number of bytes remaining to the specified length. + fn truncate(&mut self, len: Self::Offset) -> Result<()>; + + /// Return the offset of this reader's data relative to the start of + /// the given base reader's data. + /// + /// May panic if this reader's data is not contained within the given + /// base reader's data. + fn offset_from(&self, base: &Self) -> Self::Offset; + + /// Return an identifier for the current reader offset. + fn offset_id(&self) -> ReaderOffsetId; + + /// Return the offset corresponding to the given `id` if + /// it is associated with this reader. + fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option; + + /// Find the index of the first occurrence of the given byte. + /// The offset of the reader is not changed. + fn find(&self, byte: u8) -> Result; + + /// Discard the specified number of bytes. + fn skip(&mut self, len: Self::Offset) -> Result<()>; + + /// Split a reader in two. + /// + /// A new reader is returned that can be used to read the next + /// `len` bytes, and `self` is advanced so that it reads the remainder. + fn split(&mut self, len: Self::Offset) -> Result; + + /// This trait cannot be implemented if "read" feature is not enabled. + /// + /// `Reader` trait has a few methods that depend on `alloc` crate. + /// Disallowing `Reader` trait implementation prevents a crate that only depends on + /// "read-core" from being broken if another crate depending on `gimli` enables + /// "read" feature. + #[cfg(not(feature = "read"))] + fn cannot_implement() -> seal_if_no_alloc::Sealed; + + /// Return all remaining data as a clone-on-write slice. + /// + /// The slice will be borrowed where possible, but some readers may + /// always return an owned vector. + /// + /// Does not advance the reader. + #[cfg(feature = "read")] + fn to_slice(&self) -> Result>; + + /// Convert all remaining data to a clone-on-write string. + /// + /// The string will be borrowed where possible, but some readers may + /// always return an owned string. + /// + /// Does not advance the reader. + /// + /// Returns an error if the data contains invalid characters. + #[cfg(feature = "read")] + fn to_string(&self) -> Result>; + + /// Convert all remaining data to a clone-on-write string, including invalid characters. + /// + /// The string will be borrowed where possible, but some readers may + /// always return an owned string. + /// + /// Does not advance the reader. + #[cfg(feature = "read")] + fn to_string_lossy(&self) -> Result>; + + /// Read exactly `buf.len()` bytes into `buf`. + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>; + + /// Read a u8 array. + #[inline] + fn read_u8_array(&mut self) -> Result + where + A: Sized + Default + AsMut<[u8]>, + { + let mut val = Default::default(); + self.read_slice(>::as_mut(&mut val))?; + Ok(val) + } + + /// Return true if the number of bytes remaining is zero. + #[inline] + fn is_empty(&self) -> bool { + self.len() == Self::Offset::from_u8(0) + } + + /// Read a u8. + #[inline] + fn read_u8(&mut self) -> Result { + let a: [u8; 1] = self.read_u8_array()?; + Ok(a[0]) + } + + /// Read an i8. + #[inline] + fn read_i8(&mut self) -> Result { + let a: [u8; 1] = self.read_u8_array()?; + Ok(a[0] as i8) + } + + /// Read a u16. + #[inline] + fn read_u16(&mut self) -> Result { + let a: [u8; 2] = self.read_u8_array()?; + Ok(self.endian().read_u16(&a)) + } + + /// Read an i16. + #[inline] + fn read_i16(&mut self) -> Result { + let a: [u8; 2] = self.read_u8_array()?; + Ok(self.endian().read_i16(&a)) + } + + /// Read a u32. + #[inline] + fn read_u32(&mut self) -> Result { + let a: [u8; 4] = self.read_u8_array()?; + Ok(self.endian().read_u32(&a)) + } + + /// Read an i32. + #[inline] + fn read_i32(&mut self) -> Result { + let a: [u8; 4] = self.read_u8_array()?; + Ok(self.endian().read_i32(&a)) + } + + /// Read a u64. + #[inline] + fn read_u64(&mut self) -> Result { + let a: [u8; 8] = self.read_u8_array()?; + Ok(self.endian().read_u64(&a)) + } + + /// Read an i64. + #[inline] + fn read_i64(&mut self) -> Result { + let a: [u8; 8] = self.read_u8_array()?; + Ok(self.endian().read_i64(&a)) + } + + /// Read a f32. + #[inline] + fn read_f32(&mut self) -> Result { + let a: [u8; 4] = self.read_u8_array()?; + Ok(self.endian().read_f32(&a)) + } + + /// Read a f64. + #[inline] + fn read_f64(&mut self) -> Result { + let a: [u8; 8] = self.read_u8_array()?; + Ok(self.endian().read_f64(&a)) + } + + /// Read an unsigned n-bytes integer u64. + /// + /// # Panics + /// + /// Panics when nbytes < 1 or nbytes > 8 + #[inline] + fn read_uint(&mut self, n: usize) -> Result { + let mut buf = [0; 8]; + self.read_slice(&mut buf[..n])?; + Ok(self.endian().read_uint(&buf[..n])) + } + + /// Read a null-terminated slice, and return it (excluding the null). + fn read_null_terminated_slice(&mut self) -> Result { + let idx = self.find(0)?; + let val = self.split(idx)?; + self.skip(Self::Offset::from_u8(1))?; + Ok(val) + } + + /// Skip a LEB128 encoded integer. + fn skip_leb128(&mut self) -> Result<()> { + leb128::read::skip(self) + } + + /// Read an unsigned LEB128 encoded integer. + fn read_uleb128(&mut self) -> Result { + leb128::read::unsigned(self) + } + + /// Read an unsigned LEB128 encoded u32. + fn read_uleb128_u32(&mut self) -> Result { + leb128::read::unsigned(self)? + .try_into() + .map_err(|_| Error::BadUnsignedLeb128) + } + + /// Read an unsigned LEB128 encoded u16. + fn read_uleb128_u16(&mut self) -> Result { + leb128::read::u16(self) + } + + /// Read a signed LEB128 encoded integer. + fn read_sleb128(&mut self) -> Result { + leb128::read::signed(self) + } + + /// Read an initial length field. + /// + /// This field is encoded as either a 32-bit length or + /// a 64-bit length, and the returned `Format` indicates which. + fn read_initial_length(&mut self) -> Result<(Self::Offset, Format)> { + const MAX_DWARF_32_UNIT_LENGTH: u32 = 0xffff_fff0; + const DWARF_64_INITIAL_UNIT_LENGTH: u32 = 0xffff_ffff; + + let val = self.read_u32()?; + if val < MAX_DWARF_32_UNIT_LENGTH { + Ok((Self::Offset::from_u32(val), Format::Dwarf32)) + } else if val == DWARF_64_INITIAL_UNIT_LENGTH { + let val = self.read_u64().and_then(Self::Offset::from_u64)?; + Ok((val, Format::Dwarf64)) + } else { + Err(Error::UnknownReservedLength) + } + } + + /// Read a byte and validate it as an address size. + fn read_address_size(&mut self) -> Result { + let size = self.read_u8()?; + match size { + 1 | 2 | 4 | 8 => Ok(size), + _ => Err(Error::UnsupportedAddressSize(size)), + } + } + + /// Read an address-sized integer, and return it as a `u64`. + fn read_address(&mut self, address_size: u8) -> Result { + match address_size { + 1 => self.read_u8().map(u64::from), + 2 => self.read_u16().map(u64::from), + 4 => self.read_u32().map(u64::from), + 8 => self.read_u64(), + otherwise => Err(Error::UnsupportedAddressSize(otherwise)), + } + } + + /// Parse a word-sized integer according to the DWARF format. + /// + /// These are always used to encode section offsets or lengths, + /// and so have a type of `Self::Offset`. + fn read_word(&mut self, format: Format) -> Result { + match format { + Format::Dwarf32 => self.read_u32().map(Self::Offset::from_u32), + Format::Dwarf64 => self.read_u64().and_then(Self::Offset::from_u64), + } + } + + /// Parse a word-sized section length according to the DWARF format. + #[inline] + fn read_length(&mut self, format: Format) -> Result { + self.read_word(format) + } + + /// Parse a word-sized section offset according to the DWARF format. + #[inline] + fn read_offset(&mut self, format: Format) -> Result { + self.read_word(format) + } + + /// Parse a section offset of the given size. + /// + /// This is used for `DW_FORM_ref_addr` values in DWARF version 2. + fn read_sized_offset(&mut self, size: u8) -> Result { + match size { + 1 => self.read_u8().map(u64::from), + 2 => self.read_u16().map(u64::from), + 4 => self.read_u32().map(u64::from), + 8 => self.read_u64(), + otherwise => Err(Error::UnsupportedOffsetSize(otherwise)), + } + .and_then(Self::Offset::from_u64) + } +} diff --git a/deps/crates/vendor/gimli/src/read/relocate.rs b/deps/crates/vendor/gimli/src/read/relocate.rs new file mode 100644 index 00000000000000..d26c2bf8cbddea --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/relocate.rs @@ -0,0 +1,153 @@ +#[cfg(feature = "read")] +use alloc::borrow::Cow; +use core::fmt::Debug; + +use crate::common::Format; +use crate::read::{Reader, ReaderOffset, ReaderOffsetId, Result}; + +/// Trait for relocating addresses and offsets while reading a section. +pub trait Relocate { + /// Relocate an address which was read from the given section offset. + fn relocate_address(&self, offset: T, value: u64) -> Result; + + /// Relocate a value which was read from the given section offset. + fn relocate_offset(&self, offset: T, value: T) -> Result; +} + +/// A `Reader` which applies relocations to addresses and offsets. +/// +/// This is useful for reading sections which contain relocations, +/// such as those in a relocatable object file. +/// It is generally not used for reading sections in an executable file. +#[derive(Debug, Clone)] +pub struct RelocateReader, T: Relocate> { + section: R, + reader: R, + relocate: T, +} + +impl RelocateReader +where + R: Reader, + T: Relocate, +{ + /// Create a new `RelocateReader` which applies relocations to the given section reader. + pub fn new(section: R, relocate: T) -> Self { + let reader = section.clone(); + Self { + section, + reader, + relocate, + } + } +} + +impl Reader for RelocateReader +where + R: Reader, + T: Relocate + Debug + Clone, +{ + type Endian = R::Endian; + type Offset = R::Offset; + + fn read_address(&mut self, address_size: u8) -> Result { + let offset = self.reader.offset_from(&self.section); + let value = self.reader.read_address(address_size)?; + self.relocate.relocate_address(offset, value) + } + + fn read_offset(&mut self, format: Format) -> Result { + let offset = self.reader.offset_from(&self.section); + let value = self.reader.read_offset(format)?; + self.relocate.relocate_offset(offset, value) + } + + fn read_sized_offset(&mut self, size: u8) -> Result { + let offset = self.reader.offset_from(&self.section); + let value = self.reader.read_sized_offset(size)?; + self.relocate.relocate_offset(offset, value) + } + + #[inline] + fn split(&mut self, len: Self::Offset) -> Result { + let mut other = self.clone(); + other.reader.truncate(len)?; + self.reader.skip(len)?; + Ok(other) + } + + // All remaining methods simply delegate to `self.reader`. + + #[inline] + fn endian(&self) -> Self::Endian { + self.reader.endian() + } + + #[inline] + fn len(&self) -> Self::Offset { + self.reader.len() + } + + #[inline] + fn empty(&mut self) { + self.reader.empty() + } + + #[inline] + fn truncate(&mut self, len: Self::Offset) -> Result<()> { + self.reader.truncate(len) + } + + #[inline] + fn offset_from(&self, base: &Self) -> Self::Offset { + self.reader.offset_from(&base.reader) + } + + #[inline] + fn offset_id(&self) -> ReaderOffsetId { + self.reader.offset_id() + } + + #[inline] + fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { + self.reader.lookup_offset_id(id) + } + + #[inline] + fn find(&self, byte: u8) -> Result { + self.reader.find(byte) + } + + #[inline] + fn skip(&mut self, len: Self::Offset) -> Result<()> { + self.reader.skip(len) + } + + #[cfg(not(feature = "read"))] + fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed { + super::reader::seal_if_no_alloc::Sealed + } + + #[cfg(feature = "read")] + #[inline] + fn to_slice(&self) -> Result> { + self.reader.to_slice() + } + + #[cfg(feature = "read")] + #[inline] + fn to_string(&self) -> Result> { + self.reader.to_string() + } + + #[cfg(feature = "read")] + #[inline] + fn to_string_lossy(&self) -> Result> { + self.reader.to_string_lossy() + } + + #[inline] + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { + self.reader.read_slice(buf) + } +} diff --git a/deps/crates/vendor/gimli/src/read/rnglists.rs b/deps/crates/vendor/gimli/src/read/rnglists.rs new file mode 100644 index 00000000000000..4b9795558d3663 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/rnglists.rs @@ -0,0 +1,1050 @@ +use crate::common::{ + DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding, + RangeListsOffset, SectionId, +}; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::{ + lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, + ReaderOffsetId, Result, Section, +}; + +/// The raw contents of the `.debug_ranges` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugRanges { + pub(crate) section: R, +} + +impl<'input, Endian> DebugRanges> +where + Endian: Endianity, +{ + /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_ranges` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugRanges, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_ranges_section_somehow = || &buf; + /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugRanges { + /// Create a `DebugRanges` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugRanges + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugRanges { + fn id() -> SectionId { + SectionId::DebugRanges + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugRanges { + fn from(section: R) -> Self { + DebugRanges { section } + } +} + +/// The `DebugRngLists` struct represents the contents of the +/// `.debug_rnglists` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugRngLists { + section: R, +} + +impl<'input, Endian> DebugRngLists> +where + Endian: Endianity, +{ + /// Construct a new `DebugRngLists` instance from the data in the + /// `.debug_rnglists` section. + /// + /// It is the caller's responsibility to read the `.debug_rnglists` + /// section and present it as a `&[u8]` slice. That means using some ELF + /// loader on Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugRngLists, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_rnglists_section_somehow = || &buf; + /// let debug_rnglists = + /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl DebugRngLists { + /// Create a `DebugRngLists` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugRngLists + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugRngLists { + fn id() -> SectionId { + SectionId::DebugRngLists + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugRngLists { + fn from(section: R) -> Self { + DebugRngLists { section } + } +} + +#[allow(unused)] +pub(crate) type RngListsHeader = ListsHeader; + +impl DebugRngListsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugRngListsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding))) + } else { + DebugRngListsBase(Offset::from_u8(0)) + } + } +} + +/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections. +#[derive(Debug, Default, Clone, Copy)] +pub struct RangeLists { + debug_ranges: DebugRanges, + debug_rnglists: DebugRngLists, +} + +impl RangeLists { + /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and + /// `.debug_rnglists` sections. + pub fn new(debug_ranges: DebugRanges, debug_rnglists: DebugRngLists) -> RangeLists { + RangeLists { + debug_ranges, + debug_rnglists, + } + } + + /// Return the `.debug_ranges` section. + pub fn debug_ranges(&self) -> &DebugRanges { + &self.debug_ranges + } + + /// Replace the `.debug_ranges` section. + /// + /// This is useful for `.dwo` files when using the GNU split-dwarf extension to DWARF 4. + pub fn set_debug_ranges(&mut self, debug_ranges: DebugRanges) { + self.debug_ranges = debug_ranges; + } + + /// Return the `.debug_rnglists` section. + pub fn debug_rnglists(&self) -> &DebugRngLists { + &self.debug_rnglists + } +} + +impl RangeLists { + /// Create a `RangeLists` that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `Dwarf::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> RangeLists + where + F: FnMut(&'a T) -> R, + { + RangeLists { + debug_ranges: borrow(&self.debug_ranges.section).into(), + debug_rnglists: borrow(&self.debug_rnglists.section).into(), + } + } +} + +impl RangeLists { + /// Iterate over the `Range` list entries starting at the given offset. + /// + /// The `unit_version` and `address_size` must match the compilation unit that the + /// offset was contained in. + /// + /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the + /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn ranges( + &self, + offset: RangeListsOffset, + unit_encoding: Encoding, + base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> Result> { + Ok(RngListIter::new( + self.raw_ranges(offset, unit_encoding)?, + base_address, + debug_addr.clone(), + debug_addr_base, + )) + } + + /// Iterate over the `RawRngListEntry`ies starting at the given offset. + /// + /// The `unit_encoding` must match the compilation unit that the + /// offset was contained in. + /// + /// This iterator does not perform any processing of the range entries, + /// such as handling base addresses. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn raw_ranges( + &self, + offset: RangeListsOffset, + unit_encoding: Encoding, + ) -> Result> { + let (mut input, format) = if unit_encoding.version <= 4 { + (self.debug_ranges.section.clone(), RangeListsFormat::Bare) + } else { + (self.debug_rnglists.section.clone(), RangeListsFormat::Rle) + }; + input.skip(offset.0)?; + Ok(RawRngListIter::new(input, unit_encoding, format)) + } + + /// Returns the `.debug_rnglists` offset at the given `base` and `index`. + /// + /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_rnglistx` attribute. + /// + /// The `unit_encoding` must match the compilation unit that the + /// index was contained in. + pub fn get_offset( + &self, + unit_encoding: Encoding, + base: DebugRngListsBase, + index: DebugRngListsIndex, + ) -> Result> { + let format = unit_encoding.format; + let input = &mut self.debug_rnglists.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(format.word_size()), + )?)?; + input + .read_offset(format) + .map(|x| RangeListsOffset(base.0 + x)) + } + + /// Call `Reader::lookup_offset_id` for each section, and return the first match. + pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { + self.debug_ranges + .lookup_offset_id(id) + .or_else(|| self.debug_rnglists.lookup_offset_id(id)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RangeListsFormat { + /// The bare range list format used before DWARF 5. + Bare, + /// The DW_RLE encoded range list format used in DWARF 5. + Rle, +} + +/// A raw iterator over an address range list. +/// +/// This iterator does not perform any processing of the range entries, +/// such as handling base addresses. +#[derive(Debug)] +pub struct RawRngListIter { + input: R, + encoding: Encoding, + format: RangeListsFormat, +} + +/// A raw entry in .debug_rnglists +#[derive(Clone, Debug)] +pub enum RawRngListEntry { + /// A range from DWARF version <= 4. + AddressOrOffsetPair { + /// Start of range. May be an address or an offset. + begin: u64, + /// End of range. May be an address or an offset. + end: u64, + }, + /// DW_RLE_base_address + BaseAddress { + /// base address + addr: u64, + }, + /// DW_RLE_base_addressx + BaseAddressx { + /// base address + addr: DebugAddrIndex, + }, + /// DW_RLE_startx_endx + StartxEndx { + /// start of range + begin: DebugAddrIndex, + /// end of range + end: DebugAddrIndex, + }, + /// DW_RLE_startx_length + StartxLength { + /// start of range + begin: DebugAddrIndex, + /// length of range + length: u64, + }, + /// DW_RLE_offset_pair + OffsetPair { + /// start of range + begin: u64, + /// end of range + end: u64, + }, + /// DW_RLE_start_end + StartEnd { + /// start of range + begin: u64, + /// end of range + end: u64, + }, + /// DW_RLE_start_length + StartLength { + /// start of range + begin: u64, + /// length of range + length: u64, + }, +} + +impl RawRngListEntry { + /// Parse a range entry from `.debug_rnglists` + fn parse>( + input: &mut R, + encoding: Encoding, + format: RangeListsFormat, + ) -> Result> { + Ok(match format { + RangeListsFormat::Bare => { + let range = RawRange::parse(input, encoding.address_size)?; + if range.is_end() { + None + } else if range.is_base_address(encoding.address_size) { + Some(RawRngListEntry::BaseAddress { addr: range.end }) + } else { + Some(RawRngListEntry::AddressOrOffsetPair { + begin: range.begin, + end: range.end, + }) + } + } + RangeListsFormat::Rle => match constants::DwRle(input.read_u8()?) { + constants::DW_RLE_end_of_list => None, + constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + length: input.read_uleb128()?, + }), + constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { + begin: input.read_uleb128()?, + end: input.read_uleb128()?, + }), + constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { + addr: input.read_address(encoding.address_size)?, + }), + constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { + begin: input.read_address(encoding.address_size)?, + end: input.read_address(encoding.address_size)?, + }), + constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { + begin: input.read_address(encoding.address_size)?, + length: input.read_uleb128()?, + }), + entry => { + return Err(Error::UnknownRangeListsEntry(entry)); + } + }, + }) + } +} + +impl RawRngListIter { + /// Construct a `RawRngListIter`. + fn new(input: R, encoding: Encoding, format: RangeListsFormat) -> RawRngListIter { + RawRngListIter { + input, + encoding, + format, + } + } + + /// Advance the iterator to the next range. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + match RawRngListEntry::parse(&mut self.input, self.encoding, self.format) { + Ok(range) => { + if range.is_none() { + self.input.empty(); + } + Ok(range) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for RawRngListIter { + type Item = RawRngListEntry; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + RawRngListIter::next(self) + } +} + +/// An iterator over an address range list. +/// +/// This iterator internally handles processing of base addresses and different +/// entry types. Thus, it only returns range entries that are valid +/// and already adjusted for the base address. +#[derive(Debug)] +pub struct RngListIter { + raw: RawRngListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, +} + +impl RngListIter { + /// Construct a `RngListIter`. + fn new( + raw: RawRngListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> RngListIter { + RngListIter { + raw, + base_address, + debug_addr, + debug_addr_base, + } + } + + #[inline] + fn get_address(&self, index: DebugAddrIndex) -> Result { + self.debug_addr + .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) + } + + /// Advance the iterator to the next range. + pub fn next(&mut self) -> Result> { + loop { + let raw_range = match self.raw.next()? { + Some(range) => range, + None => return Ok(None), + }; + + let range = self.convert_raw(raw_range)?; + if range.is_some() { + return Ok(range); + } + } + } + + /// Return the next raw range. + /// + /// The raw range should be passed to `convert_range`. + #[doc(hidden)] + pub fn next_raw(&mut self) -> Result>> { + self.raw.next() + } + + /// Convert a raw range into a range, and update the state of the iterator. + /// + /// The raw range should have been obtained from `next_raw`. + #[doc(hidden)] + pub fn convert_raw(&mut self, raw_range: RawRngListEntry) -> Result> { + let address_size = self.raw.encoding.address_size; + let mask = u64::ones_sized(address_size); + let tombstone = if self.raw.encoding.version <= 4 { + mask - 1 + } else { + mask + }; + + let range = match raw_range { + RawRngListEntry::BaseAddress { addr } => { + self.base_address = addr; + return Ok(None); + } + RawRngListEntry::BaseAddressx { addr } => { + self.base_address = self.get_address(addr)?; + return Ok(None); + } + RawRngListEntry::StartxEndx { begin, end } => { + let begin = self.get_address(begin)?; + let end = self.get_address(end)?; + Range { begin, end } + } + RawRngListEntry::StartxLength { begin, length } => { + let begin = self.get_address(begin)?; + let end = begin.wrapping_add_sized(length, address_size); + Range { begin, end } + } + RawRngListEntry::AddressOrOffsetPair { begin, end } + | RawRngListEntry::OffsetPair { begin, end } => { + // Skip tombstone entries (see below). + if self.base_address == tombstone { + return Ok(None); + } + let mut range = Range { begin, end }; + range.add_base_address(self.base_address, self.raw.encoding.address_size); + range + } + RawRngListEntry::StartEnd { begin, end } => Range { begin, end }, + RawRngListEntry::StartLength { begin, length } => { + let end = begin.wrapping_add_sized(length, address_size); + Range { begin, end } + } + }; + + // Skip tombstone entries. + // + // DWARF specifies a tombstone value of -1 or -2, but many linkers use 0 or 1. + // However, 0/1 may be a valid address, so we can't always reliably skip them. + // One case where we can skip them is for address pairs, where both values are + // replaced by tombstones and thus `begin` equals `end`. Since these entries + // are empty, it's safe to skip them even if they aren't tombstones. + // + // In addition to skipping tombstone entries, we also skip invalid entries + // where `begin` is greater than `end`. This can occur due to compiler bugs. + if range.begin == tombstone || range.begin >= range.end { + return Ok(None); + } + + Ok(Some(range)) + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for RngListIter { + type Item = Range; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + RngListIter::next(self) + } +} + +/// A raw address range from the `.debug_ranges` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct RawRange { + /// The beginning address of the range. + pub begin: u64, + + /// The first address past the end of the range. + pub end: u64, +} + +impl RawRange { + /// Check if this is a range end entry. + #[inline] + pub fn is_end(&self) -> bool { + self.begin == 0 && self.end == 0 + } + + /// Check if this is a base address selection entry. + /// + /// A base address selection entry changes the base address that subsequent + /// range entries are relative to. + #[inline] + pub fn is_base_address(&self, address_size: u8) -> bool { + self.begin == !0 >> (64 - address_size * 8) + } + + /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. + #[inline] + pub fn parse(input: &mut R, address_size: u8) -> Result { + let begin = input.read_address(address_size)?; + let end = input.read_address(address_size)?; + let range = RawRange { begin, end }; + Ok(range) + } +} + +/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Range { + /// The beginning address of the range. + pub begin: u64, + + /// The first address past the end of the range. + pub end: u64, +} + +impl Range { + /// Add a base address to this range. + #[inline] + pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) { + self.begin = base_address.wrapping_add_sized(self.begin, address_size); + self.end = base_address.wrapping_add_sized(self.end, address_size); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::Format; + use crate::constants::*; + use crate::endianity::LittleEndian; + use crate::test_util::GimliSectionMethods; + use alloc::vec::Vec; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + #[test] + fn test_rnglists() { + let format = Format::Dwarf32; + for size in [4, 8] { + let tombstone = u64::ones_sized(size); + let tombstone_0 = 0; + let encoding = Encoding { + format, + version: 5, + address_size: size, + }; + let section = Section::with_endian(Endian::Little) + .word(size, 0x0300_0000) + .word(size, 0x0301_0300) + .word(size, 0x0301_0400) + .word(size, 0x0301_0500) + .word(size, tombstone) + .word(size, 0x0301_0600) + .word(size, tombstone_0); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .initial_length(format, &length, &start) + .L16(encoding.version) + .L8(encoding.address_size) + .L8(0) + .L32(0) + .mark(&first); + + let mut expected_ranges = Vec::new(); + let mut expect_range = |begin, end| { + expected_ranges.push(Range { begin, end }); + }; + + // An offset pair using the unit base address. + section = section.L8(DW_RLE_offset_pair.0).uleb(0x10200).uleb(0x10300); + expect_range(0x0101_0200, 0x0101_0300); + + section = section.L8(DW_RLE_base_address.0).word(size, 0x0200_0000); + section = section.L8(DW_RLE_offset_pair.0).uleb(0x10400).uleb(0x10500); + expect_range(0x0201_0400, 0x0201_0500); + + section = section + .L8(DW_RLE_start_end.0) + .word(size, 0x201_0a00) + .word(size, 0x201_0b00); + expect_range(0x0201_0a00, 0x0201_0b00); + + section = section + .L8(DW_RLE_start_length.0) + .word(size, 0x201_0c00) + .uleb(0x100); + expect_range(0x0201_0c00, 0x0201_0d00); + + // An offset pair that starts at 0. + section = section.L8(DW_RLE_base_address.0).word(size, 0); + section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(1); + expect_range(0, 1); + + // An offset pair that ends at -1. + section = section.L8(DW_RLE_base_address.0).word(size, 0); + section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(tombstone); + expect_range(0, tombstone); + + section = section.L8(DW_RLE_base_addressx.0).uleb(0); + section = section.L8(DW_RLE_offset_pair.0).uleb(0x10100).uleb(0x10200); + expect_range(0x0301_0100, 0x0301_0200); + + section = section.L8(DW_RLE_startx_endx.0).uleb(1).uleb(2); + expect_range(0x0301_0300, 0x0301_0400); + + section = section.L8(DW_RLE_startx_length.0).uleb(3).uleb(0x100); + expect_range(0x0301_0500, 0x0301_0600); + + // Tombstone entries, all of which should be ignored. + section = section.L8(DW_RLE_base_addressx.0).uleb(4); + section = section.L8(DW_RLE_offset_pair.0).uleb(0x11100).uleb(0x11200); + + section = section.L8(DW_RLE_base_address.0).word(size, tombstone); + section = section.L8(DW_RLE_offset_pair.0).uleb(0x11300).uleb(0x11400); + + section = section.L8(DW_RLE_startx_endx.0).uleb(4).uleb(5); + section = section.L8(DW_RLE_startx_length.0).uleb(4).uleb(0x100); + section = section + .L8(DW_RLE_start_end.0) + .word(size, tombstone) + .word(size, 0x201_1500); + section = section + .L8(DW_RLE_start_length.0) + .word(size, tombstone) + .uleb(0x100); + + // Ignore some instances of 0 for tombstone. + section = section.L8(DW_RLE_startx_endx.0).uleb(6).uleb(6); + section = section + .L8(DW_RLE_start_end.0) + .word(size, tombstone_0) + .word(size, tombstone_0); + + // Ignore empty ranges. + section = section.L8(DW_RLE_base_address.0).word(size, 0); + section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(0); + section = section.L8(DW_RLE_base_address.0).word(size, 0x10000); + section = section.L8(DW_RLE_offset_pair.0).uleb(0x1234).uleb(0x1234); + + // A valid range after the tombstones. + section = section + .L8(DW_RLE_start_end.0) + .word(size, 0x201_1600) + .word(size, 0x201_1700); + expect_range(0x0201_1600, 0x0201_1700); + + section = section.L8(DW_RLE_end_of_list.0); + section = section.mark(&end); + // Some extra data. + section = section.word(size, 0x1234_5678); + length.set_const((&end - &start) as u64); + + let offset = RangeListsOffset((&first - §ion.start()) as usize); + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&[], LittleEndian); + let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists); + let mut ranges = rnglists + .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); + + for expected_range in expected_ranges { + let range = ranges.next(); + assert_eq!( + range, + Ok(Some(expected_range)), + "read {:x?}, expect {:x?}", + range, + expected_range + ); + } + assert_eq!(ranges.next(), Ok(None)); + + // An offset at the end of buf. + let mut ranges = rnglists + .ranges( + RangeListsOffset(buf.len()), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + } + } + + #[test] + fn test_raw_range() { + let range = RawRange { + begin: 0, + end: 0xffff_ffff, + }; + assert!(!range.is_end()); + assert!(!range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = RawRange { begin: 0, end: 0 }; + assert!(range.is_end()); + assert!(!range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = RawRange { + begin: 0xffff_ffff, + end: 0, + }; + assert!(!range.is_end()); + assert!(range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = RawRange { + begin: 0xffff_ffff_ffff_ffff, + end: 0, + }; + assert!(!range.is_end()); + assert!(!range.is_base_address(4)); + assert!(range.is_base_address(8)); + } + + #[test] + fn test_ranges() { + for size in [4, 8] { + let base = u64::ones_sized(size); + let tombstone = u64::ones_sized(size) - 1; + let start = Label::new(); + let first = Label::new(); + let mut section = Section::with_endian(Endian::Little) + // A range before the offset. + .mark(&start) + .word(size, 0x10000) + .word(size, 0x10100) + .mark(&first); + + let mut expected_ranges = Vec::new(); + let mut expect_range = |begin, end| { + expected_ranges.push(Range { begin, end }); + }; + + // A normal range. + section = section.word(size, 0x10200).word(size, 0x10300); + expect_range(0x0101_0200, 0x0101_0300); + // A base address selection followed by a normal range. + section = section.word(size, base).word(size, 0x0200_0000); + section = section.word(size, 0x10400).word(size, 0x10500); + expect_range(0x0201_0400, 0x0201_0500); + // An empty range followed by a normal range. + section = section.word(size, 0x10600).word(size, 0x10600); + section = section.word(size, 0x10800).word(size, 0x10900); + expect_range(0x0201_0800, 0x0201_0900); + // A range that starts at 0. + section = section.word(size, base).word(size, 0); + section = section.word(size, 0).word(size, 1); + expect_range(0, 1); + // A range that ends at -1. + section = section.word(size, base).word(size, 0); + section = section.word(size, 0).word(size, base); + expect_range(0, base); + // A normal range with tombstone. + section = section.word(size, tombstone).word(size, tombstone); + // A base address selection with tombstone followed by a normal range. + section = section.word(size, base).word(size, tombstone); + section = section.word(size, 0x10a00).word(size, 0x10b00); + // A range end. + section = section.word(size, 0).word(size, 0); + // Some extra data. + section = section.word(size, 0x1234_5678); + + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists); + let offset = RangeListsOffset((&first - &start) as usize); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: size, + }; + let mut ranges = rnglists + .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); + + for expected_range in expected_ranges { + let range = ranges.next(); + assert_eq!( + range, + Ok(Some(expected_range)), + "read {:x?}, expect {:x?}", + range, + expected_range + ); + } + assert_eq!(ranges.next(), Ok(None)); + + // An offset at the end of buf. + let mut ranges = rnglists + .ranges( + RangeListsOffset(buf.len()), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + } + } + + #[test] + fn test_ranges_invalid() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + // An invalid range. + .L32(0x20000).L32(0x10000) + // An invalid range after wrapping. + .L32(0x20000).L32(0xff01_0000); + + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + + // An invalid range. + let mut ranges = rnglists + .ranges( + RangeListsOffset(0x0), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + + // An invalid range after wrapping. + let mut ranges = rnglists + .ranges( + RangeListsOffset(0x8), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + + // An invalid offset. + match rnglists.ranges( + RangeListsOffset(buf.len() + 1), + encoding, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_get_offset() { + for format in [Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version: 5, + address_size: 4, + }; + + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(encoding.version) + .D8(encoding.address_size) + .D8(0) + .D32(20) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + let section = section.get_contents().unwrap(); + + let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian)); + let debug_rnglists = DebugRngLists::from(EndianSlice::new(§ion, LittleEndian)); + let ranges = RangeLists::new(debug_ranges, debug_rnglists); + + let base = DebugRngListsBase((&first - &zero) as usize); + assert_eq!( + ranges.get_offset(encoding, base, DebugRngListsIndex(0)), + Ok(RangeListsOffset(base.0 + 1000)) + ); + assert_eq!( + ranges.get_offset(encoding, base, DebugRngListsIndex(19)), + Ok(RangeListsOffset(base.0 + 1019)) + ); + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/str.rs b/deps/crates/vendor/gimli/src/read/str.rs new file mode 100644 index 00000000000000..df7ab1ccd2236d --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/str.rs @@ -0,0 +1,291 @@ +use crate::common::{ + DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType, + Encoding, SectionId, +}; +use crate::endianity::Endianity; +use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section}; +use crate::Format; + +/// The `DebugStr` struct represents the DWARF strings +/// found in the `.debug_str` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugStr { + debug_str_section: R, +} + +impl<'input, Endian> DebugStr> +where + Endian: Endianity, +{ + /// Construct a new `DebugStr` instance from the data in the `.debug_str` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_str` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugStr, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_str_section_somehow = || &buf; + /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_str_section, endian)) + } +} + +impl DebugStr { + /// Lookup a string from the `.debug_str` section by DebugStrOffset. + /// + /// ``` + /// use gimli::{DebugStr, DebugStrOffset, LittleEndian}; + /// + /// # let buf = [0x01, 0x02, 0x00]; + /// # let offset = DebugStrOffset(0); + /// # let read_debug_str_section_somehow = || &buf; + /// # let debug_str_offset_somehow = || offset; + /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); + /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow())); + /// ``` + pub fn get_str(&self, offset: DebugStrOffset) -> Result { + let input = &mut self.debug_str_section.clone(); + input.skip(offset.0)?; + input.read_null_terminated_slice() + } +} + +impl DebugStr { + /// Create a `DebugStr` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr + where + F: FnMut(&'a T) -> R, + { + borrow(&self.debug_str_section).into() + } +} + +impl Section for DebugStr { + fn id() -> SectionId { + SectionId::DebugStr + } + + fn reader(&self) -> &R { + &self.debug_str_section + } +} + +impl From for DebugStr { + fn from(debug_str_section: R) -> Self { + DebugStr { debug_str_section } + } +} + +/// The raw contents of the `.debug_str_offsets` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugStrOffsets { + section: R, +} + +impl DebugStrOffsets { + // TODO: add an iterator over the sets of entries in the section. + // This is not needed for common usage of the section though. + + /// Returns the `.debug_str` offset at the given `base` and `index`. + /// + /// A set of entries in the `.debug_str_offsets` section consists of a header + /// followed by a series of string table offsets. + /// + /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_strx` attribute. + /// + /// The `format` must be the DWARF format of the compilation unit. This format must + /// match the header. However, note that we do not parse the header to validate this, + /// since locating the header is unreliable, and the GNU extensions do not emit it. + pub fn get_str_offset( + &self, + format: Format, + base: DebugStrOffsetsBase, + index: DebugStrOffsetsIndex, + ) -> Result> { + let input = &mut self.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(format.word_size()), + )?)?; + input.read_offset(format).map(DebugStrOffset) + } +} + +impl DebugStrOffsets { + /// Create a `DebugStrOffsets` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugStrOffsets { + fn id() -> SectionId { + SectionId::DebugStrOffsets + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugStrOffsets { + fn from(section: R) -> Self { + DebugStrOffsets { section } + } +} + +impl DebugStrOffsetsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugStrOffsetsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + // initial_length_size + version + 2 bytes of padding. + DebugStrOffsetsBase(Offset::from_u8( + encoding.format.initial_length_size() + 2 + 2, + )) + } else { + DebugStrOffsetsBase(Offset::from_u8(0)) + } + } +} + +/// The `DebugLineStr` struct represents the DWARF strings +/// found in the `.debug_line_str` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugLineStr { + section: R, +} + +impl<'input, Endian> DebugLineStr> +where + Endian: Endianity, +{ + /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_line_str` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugLineStr, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_line_str_section_somehow = || &buf; + /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_line_str_section, endian)) + } +} + +impl DebugLineStr { + /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. + pub fn get_str(&self, offset: DebugLineStrOffset) -> Result { + let input = &mut self.section.clone(); + input.skip(offset.0)?; + input.read_null_terminated_slice() + } +} + +impl DebugLineStr { + /// Create a `DebugLineStr` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugLineStr { + fn id() -> SectionId { + SectionId::DebugLineStr + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugLineStr { + fn from(section: R) -> Self { + DebugLineStr { section } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_util::GimliSectionMethods; + use crate::LittleEndian; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + #[test] + fn test_get_str_offset() { + for format in [Format::Dwarf32, Format::Dwarf64] { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D16(0) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + + let section = section.get_contents().unwrap(); + let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); + let base = DebugStrOffsetsBase((&first - &zero) as usize); + + assert_eq!( + debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), + Ok(DebugStrOffset(1000)) + ); + assert_eq!( + debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), + Ok(DebugStrOffset(1019)) + ); + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/unit.rs b/deps/crates/vendor/gimli/src/read/unit.rs new file mode 100644 index 00000000000000..e8e38620d9bcfe --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/unit.rs @@ -0,0 +1,6128 @@ +//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections. + +use core::cell::Cell; +use core::ops::{Range, RangeFrom, RangeTo}; + +use crate::common::{ + DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, + DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset, + DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, + DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format, + LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset, +}; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::abbrev::get_attribute_size; +use crate::read::{ + Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error, + Expression, Reader, ReaderOffset, Result, Section, UnitOffset, +}; + +impl DebugTypesOffset { + /// Convert an offset to be relative to the start of the given unit, + /// instead of relative to the start of the .debug_types section. + /// Returns `None` if the offset is not within the unit entries. + pub fn to_unit_offset(&self, unit: &UnitHeader) -> Option> + where + R: Reader, + { + let unit_offset = unit.offset().as_debug_types_offset()?; + let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); + if !unit.is_valid_offset(offset) { + return None; + } + Some(offset) + } +} + +impl DebugInfoOffset { + /// Convert an offset to be relative to the start of the given unit, + /// instead of relative to the start of the .debug_info section. + /// Returns `None` if the offset is not within this unit entries. + pub fn to_unit_offset(&self, unit: &UnitHeader) -> Option> + where + R: Reader, + { + let unit_offset = unit.offset().as_debug_info_offset()?; + let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); + if !unit.is_valid_offset(offset) { + return None; + } + Some(offset) + } +} + +impl UnitOffset { + /// Convert an offset to be relative to the start of the .debug_info section, + /// instead of relative to the start of the given unit. Returns None if the + /// provided unit lives in the .debug_types section. + pub fn to_debug_info_offset(&self, unit: &UnitHeader) -> Option> + where + R: Reader, + { + let unit_offset = unit.offset().as_debug_info_offset()?; + Some(DebugInfoOffset(unit_offset.0 + self.0)) + } + + /// Convert an offset to be relative to the start of the .debug_types section, + /// instead of relative to the start of the given unit. Returns None if the + /// provided unit lives in the .debug_info section. + pub fn to_debug_types_offset(&self, unit: &UnitHeader) -> Option> + where + R: Reader, + { + let unit_offset = unit.offset().as_debug_types_offset()?; + Some(DebugTypesOffset(unit_offset.0 + self.0)) + } +} + +/// The `DebugInfo` struct represents the DWARF debugging information found in +/// the `.debug_info` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugInfo { + debug_info_section: R, +} + +impl<'input, Endian> DebugInfo> +where + Endian: Endianity, +{ + /// Construct a new `DebugInfo` instance from the data in the `.debug_info` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_info` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugInfo, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_info_section_somehow = || &buf; + /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_info_section, endian)) + } +} + +impl DebugInfo { + /// Iterate the units in this `.debug_info` section. + /// + /// ``` + /// use gimli::{DebugInfo, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_info_section_somehow = || &buf; + /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); + /// + /// let mut iter = debug_info.units(); + /// while let Some(unit) = iter.next().unwrap() { + /// println!("unit's length is {}", unit.unit_length()); + /// } + /// ``` + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn units(&self) -> DebugInfoUnitHeadersIter { + DebugInfoUnitHeadersIter { + input: self.debug_info_section.clone(), + offset: DebugInfoOffset(R::Offset::from_u8(0)), + } + } + + /// Get the UnitHeader located at offset from this .debug_info section. + /// + /// + pub fn header_from_offset(&self, offset: DebugInfoOffset) -> Result> { + let input = &mut self.debug_info_section.clone(); + input.skip(offset.0)?; + parse_unit_header(input, offset.into()) + } +} + +impl DebugInfo { + /// Create a `DebugInfo` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo + where + F: FnMut(&'a T) -> R, + { + borrow(&self.debug_info_section).into() + } +} + +impl Section for DebugInfo { + fn id() -> SectionId { + SectionId::DebugInfo + } + + fn reader(&self) -> &R { + &self.debug_info_section + } +} + +impl From for DebugInfo { + fn from(debug_info_section: R) -> Self { + DebugInfo { debug_info_section } + } +} + +/// An iterator over the units of a .debug_info section. +/// +/// See the [documentation on +/// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail. +#[derive(Clone, Debug)] +pub struct DebugInfoUnitHeadersIter { + input: R, + offset: DebugInfoOffset, +} + +impl DebugInfoUnitHeadersIter { + /// Advance the iterator to the next unit header. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + Ok(None) + } else { + let len = self.input.len(); + match parse_unit_header(&mut self.input, self.offset.into()) { + Ok(header) => { + self.offset.0 += len - self.input.len(); + Ok(Some(header)) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter { + type Item = UnitHeader; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + DebugInfoUnitHeadersIter::next(self) + } +} + +/// Parse the unit type from the unit header. +fn parse_unit_type(input: &mut R) -> Result { + let val = input.read_u8()?; + Ok(constants::DwUt(val)) +} + +/// Parse the `debug_abbrev_offset` in the compilation unit header. +fn parse_debug_abbrev_offset( + input: &mut R, + format: Format, +) -> Result> { + input.read_offset(format).map(DebugAbbrevOffset) +} + +/// Parse the `debug_info_offset` in the arange header. +pub(crate) fn parse_debug_info_offset( + input: &mut R, + format: Format, +) -> Result> { + input.read_offset(format).map(DebugInfoOffset) +} + +/// This enum specifies the type of the unit and any type +/// specific data carried in the header (e.g. the type +/// signature/type offset of a type unit). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UnitType +where + Offset: ReaderOffset, +{ + /// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions, + /// any unit appearing in the .debug_info section. + Compilation, + /// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing + /// in the .debug_types section. + Type { + /// The unique type signature for this type unit. + type_signature: DebugTypeSignature, + /// The offset within this type unit where the type is defined. + type_offset: UnitOffset, + }, + /// A unit with type `DW_UT_partial`. The root DIE of this unit should be a + /// `DW_TAG_partial_unit`. + Partial, + /// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to + /// link this with the corresponding `SplitCompilation` unit in a dwo file. + /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead + /// be a `Compilation` unit with the dwo_id present as an attribute on the + /// root DIE. + Skeleton(DwoId), + /// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to + /// link this with the corresponding `Skeleton` unit in the original binary. + /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead + /// be a `Compilation` unit with the dwo_id present as an attribute on the + /// root DIE. + SplitCompilation(DwoId), + /// A unit with type `DW_UT_split_type`. A split type unit is identical to a + /// conventional type unit except for the section in which it appears. + SplitType { + /// The unique type signature for this type unit. + type_signature: DebugTypeSignature, + /// The offset within this type unit where the type is defined. + type_offset: UnitOffset, + }, +} + +impl UnitType +where + Offset: ReaderOffset, +{ + // TODO: This will be used by the DWARF writing code once it + // supports unit types other than simple compilation units. + #[allow(unused)] + pub(crate) fn dw_ut(&self) -> constants::DwUt { + match self { + UnitType::Compilation => constants::DW_UT_compile, + UnitType::Type { .. } => constants::DW_UT_type, + UnitType::Partial => constants::DW_UT_partial, + UnitType::Skeleton(_) => constants::DW_UT_skeleton, + UnitType::SplitCompilation(_) => constants::DW_UT_split_compile, + UnitType::SplitType { .. } => constants::DW_UT_split_type, + } + } +} + +/// The common fields for the headers of compilation units and +/// type units. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UnitHeader::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + encoding: Encoding, + unit_length: Offset, + unit_type: UnitType, + debug_abbrev_offset: DebugAbbrevOffset, + unit_offset: UnitSectionOffset, + entries_buf: R, +} + +/// Static methods. +impl UnitHeader +where + R: Reader, + Offset: ReaderOffset, +{ + /// Construct a new `UnitHeader`. + pub fn new( + encoding: Encoding, + unit_length: Offset, + unit_type: UnitType, + debug_abbrev_offset: DebugAbbrevOffset, + unit_offset: UnitSectionOffset, + entries_buf: R, + ) -> Self { + UnitHeader { + encoding, + unit_length, + unit_type, + debug_abbrev_offset, + unit_offset, + entries_buf, + } + } +} + +/// Instance methods. +impl UnitHeader +where + R: Reader, + Offset: ReaderOffset, +{ + /// Get the offset of this unit within its section. + pub fn offset(&self) -> UnitSectionOffset { + self.unit_offset + } + + /// Return the serialized size of the common unit header for the given + /// DWARF format. + pub fn size_of_header(&self) -> usize { + let unit_length_size = self.encoding.format.initial_length_size() as usize; + let version_size = 2; + let debug_abbrev_offset_size = self.encoding.format.word_size() as usize; + let address_size_size = 1; + let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 }; + let type_specific_size = match self.unit_type { + UnitType::Compilation | UnitType::Partial => 0, + UnitType::Type { .. } | UnitType::SplitType { .. } => { + let type_signature_size = 8; + let type_offset_size = self.encoding.format.word_size() as usize; + type_signature_size + type_offset_size + } + UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8, + }; + + unit_length_size + + version_size + + debug_abbrev_offset_size + + address_size_size + + unit_type_size + + type_specific_size + } + + /// Get the length of the debugging info for this compilation unit, not + /// including the byte length of the encoded length itself. + pub fn unit_length(&self) -> Offset { + self.unit_length + } + + /// Get the length of the debugging info for this compilation unit, + /// including the byte length of the encoded length itself. + pub fn length_including_self(&self) -> Offset { + Offset::from_u8(self.format().initial_length_size()) + self.unit_length + } + + /// Return the encoding parameters for this unit. + pub fn encoding(&self) -> Encoding { + self.encoding + } + + /// Get the DWARF version of the debugging info for this compilation unit. + pub fn version(&self) -> u16 { + self.encoding.version + } + + /// Get the UnitType of this unit. + pub fn type_(&self) -> UnitType { + self.unit_type + } + + /// The offset into the `.debug_abbrev` section for this compilation unit's + /// debugging information entries' abbreviations. + pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { + self.debug_abbrev_offset + } + + /// The size of addresses (in bytes) in this compilation unit. + pub fn address_size(&self) -> u8 { + self.encoding.address_size + } + + /// Whether this compilation unit is encoded in 64- or 32-bit DWARF. + pub fn format(&self) -> Format { + self.encoding.format + } + + /// The serialized size of the header for this compilation unit. + pub fn header_size(&self) -> Offset { + self.length_including_self() - self.entries_buf.len() + } + + pub(crate) fn is_valid_offset(&self, offset: UnitOffset) -> bool { + let size_of_header = self.header_size(); + if offset.0 < size_of_header { + return false; + } + + let relative_to_entries_buf = offset.0 - size_of_header; + relative_to_entries_buf < self.entries_buf.len() + } + + /// Get the underlying bytes for the supplied range. + pub fn range(&self, idx: Range>) -> Result { + if !self.is_valid_offset(idx.start) { + return Err(Error::OffsetOutOfBounds); + } + if !self.is_valid_offset(idx.end) { + return Err(Error::OffsetOutOfBounds); + } + assert!(idx.start <= idx.end); + let size_of_header = self.header_size(); + let start = idx.start.0 - size_of_header; + let end = idx.end.0 - size_of_header; + let mut input = self.entries_buf.clone(); + input.skip(start)?; + input.truncate(end - start)?; + Ok(input) + } + + /// Get the underlying bytes for the supplied range. + pub fn range_from(&self, idx: RangeFrom>) -> Result { + if !self.is_valid_offset(idx.start) { + return Err(Error::OffsetOutOfBounds); + } + let start = idx.start.0 - self.header_size(); + let mut input = self.entries_buf.clone(); + input.skip(start)?; + Ok(input) + } + + /// Get the underlying bytes for the supplied range. + pub fn range_to(&self, idx: RangeTo>) -> Result { + if !self.is_valid_offset(idx.end) { + return Err(Error::OffsetOutOfBounds); + } + let end = idx.end.0 - self.header_size(); + let mut input = self.entries_buf.clone(); + input.truncate(end)?; + Ok(input) + } + + /// Read the `DebuggingInformationEntry` at the given offset. + pub fn entry<'me, 'abbrev>( + &'me self, + abbreviations: &'abbrev Abbreviations, + offset: UnitOffset, + ) -> Result> { + let mut input = self.range_from(offset..)?; + let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?; + entry.ok_or(Error::NoEntryAtGivenOffset) + } + + /// Navigate this unit's `DebuggingInformationEntry`s. + pub fn entries<'me, 'abbrev>( + &'me self, + abbreviations: &'abbrev Abbreviations, + ) -> EntriesCursor<'abbrev, 'me, R> { + EntriesCursor { + unit: self, + input: self.entries_buf.clone(), + abbreviations, + cached_current: None, + delta_depth: 0, + } + } + + /// Navigate this compilation unit's `DebuggingInformationEntry`s + /// starting at the given offset. + pub fn entries_at_offset<'me, 'abbrev>( + &'me self, + abbreviations: &'abbrev Abbreviations, + offset: UnitOffset, + ) -> Result> { + let input = self.range_from(offset..)?; + Ok(EntriesCursor { + unit: self, + input, + abbreviations, + cached_current: None, + delta_depth: 0, + }) + } + + /// Navigate this unit's `DebuggingInformationEntry`s as a tree + /// starting at the given offset. + pub fn entries_tree<'me, 'abbrev>( + &'me self, + abbreviations: &'abbrev Abbreviations, + offset: Option>, + ) -> Result> { + let input = match offset { + Some(offset) => self.range_from(offset..)?, + None => self.entries_buf.clone(), + }; + Ok(EntriesTree::new(input, self, abbreviations)) + } + + /// Read the raw data that defines the Debugging Information Entries. + pub fn entries_raw<'me, 'abbrev>( + &'me self, + abbreviations: &'abbrev Abbreviations, + offset: Option>, + ) -> Result> { + let input = match offset { + Some(offset) => self.range_from(offset..)?, + None => self.entries_buf.clone(), + }; + Ok(EntriesRaw { + input, + unit: self, + abbreviations, + depth: 0, + }) + } + + /// Parse this unit's abbreviations. + pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { + debug_abbrev.abbreviations(self.debug_abbrev_offset()) + } +} + +/// Parse a unit header. +fn parse_unit_header( + input: &mut R, + unit_offset: UnitSectionOffset, +) -> Result> +where + R: Reader, + Offset: ReaderOffset, +{ + let (unit_length, format) = input.read_initial_length()?; + let mut rest = input.split(unit_length)?; + + let version = rest.read_u16()?; + let abbrev_offset; + let address_size; + let unit_type; + // DWARF 1 was very different, and is obsolete, so isn't supported by this + // reader. + if 2 <= version && version <= 4 { + abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; + address_size = rest.read_address_size()?; + // Before DWARF5, all units in the .debug_info section are compilation + // units, and all units in the .debug_types section are type units. + unit_type = match unit_offset { + UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile, + UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type, + }; + } else if version == 5 { + unit_type = parse_unit_type(&mut rest)?; + address_size = rest.read_address_size()?; + abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; + } else { + return Err(Error::UnknownVersion(u64::from(version))); + } + let encoding = Encoding { + format, + version, + address_size, + }; + + // Parse any data specific to this type of unit. + let unit_type = match unit_type { + constants::DW_UT_compile => UnitType::Compilation, + constants::DW_UT_type => { + let type_signature = parse_type_signature(&mut rest)?; + let type_offset = parse_type_offset(&mut rest, format)?; + UnitType::Type { + type_signature, + type_offset, + } + } + constants::DW_UT_partial => UnitType::Partial, + constants::DW_UT_skeleton => { + let dwo_id = parse_dwo_id(&mut rest)?; + UnitType::Skeleton(dwo_id) + } + constants::DW_UT_split_compile => { + let dwo_id = parse_dwo_id(&mut rest)?; + UnitType::SplitCompilation(dwo_id) + } + constants::DW_UT_split_type => { + let type_signature = parse_type_signature(&mut rest)?; + let type_offset = parse_type_offset(&mut rest, format)?; + UnitType::SplitType { + type_signature, + type_offset, + } + } + _ => return Err(Error::UnsupportedUnitType), + }; + + Ok(UnitHeader::new( + encoding, + unit_length, + unit_type, + abbrev_offset, + unit_offset, + rest, + )) +} + +/// Parse a dwo_id from a header +fn parse_dwo_id(input: &mut R) -> Result { + Ok(DwoId(input.read_u64()?)) +} + +/// A Debugging Information Entry (DIE). +/// +/// DIEs have a set of attributes and optionally have children DIEs as well. +#[derive(Clone, Debug)] +pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = ::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + offset: UnitOffset, + attrs_slice: R, + attrs_len: Cell>, + abbrev: &'abbrev Abbreviation, + unit: &'unit UnitHeader, +} + +impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// Construct a new `DebuggingInformationEntry`. + pub fn new( + offset: UnitOffset, + attrs_slice: R, + abbrev: &'abbrev Abbreviation, + unit: &'unit UnitHeader, + ) -> Self { + DebuggingInformationEntry { + offset, + attrs_slice, + attrs_len: Cell::new(None), + abbrev, + unit, + } + } + + /// Get this entry's code. + pub fn code(&self) -> u64 { + self.abbrev.code() + } + + /// Get this entry's offset. + pub fn offset(&self) -> UnitOffset { + self.offset + } + + /// Get this entry's `DW_TAG_whatever` tag. + /// + /// ``` + /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; + /// # let info_buf = [ + /// # // Comilation unit header + /// # + /// # // 32-bit unit length = 12 + /// # 0x0c, 0x00, 0x00, 0x00, + /// # // Version 4 + /// # 0x04, 0x00, + /// # // debug_abbrev_offset + /// # 0x00, 0x00, 0x00, 0x00, + /// # // Address size + /// # 0x04, + /// # + /// # // DIEs + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # ]; + /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); + /// # let abbrev_buf = [ + /// # // Code + /// # 0x01, + /// # // DW_TAG_subprogram + /// # 0x2e, + /// # // DW_CHILDREN_no + /// # 0x00, + /// # // Begin attributes + /// # // Attribute name = DW_AT_name + /// # 0x03, + /// # // Attribute form = DW_FORM_string + /// # 0x08, + /// # // End attributes + /// # 0x00, + /// # 0x00, + /// # // Null terminator + /// # 0x00 + /// # ]; + /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); + /// # let unit = debug_info.units().next().unwrap().unwrap(); + /// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); + /// # let mut cursor = unit.entries(&abbrevs); + /// # let (_, entry) = cursor.next_dfs().unwrap().unwrap(); + /// # let mut get_some_entry = || entry; + /// let entry = get_some_entry(); + /// + /// match entry.tag() { + /// gimli::DW_TAG_subprogram => + /// println!("this entry contains debug info about a function"), + /// gimli::DW_TAG_inlined_subroutine => + /// println!("this entry contains debug info about a particular instance of inlining"), + /// gimli::DW_TAG_variable => + /// println!("this entry contains debug info about a local variable"), + /// gimli::DW_TAG_formal_parameter => + /// println!("this entry contains debug info about a function parameter"), + /// otherwise => + /// println!("this entry is some other kind of data: {:?}", otherwise), + /// }; + /// ``` + pub fn tag(&self) -> constants::DwTag { + self.abbrev.tag() + } + + /// Return true if this entry's type can have children, false otherwise. + pub fn has_children(&self) -> bool { + self.abbrev.has_children() + } + + /// Iterate over this entry's set of attributes. + /// + /// ``` + /// use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; + /// + /// // Read the `.debug_info` section. + /// + /// # let info_buf = [ + /// # // Comilation unit header + /// # + /// # // 32-bit unit length = 12 + /// # 0x0c, 0x00, 0x00, 0x00, + /// # // Version 4 + /// # 0x04, 0x00, + /// # // debug_abbrev_offset + /// # 0x00, 0x00, 0x00, 0x00, + /// # // Address size + /// # 0x04, + /// # + /// # // DIEs + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # ]; + /// # let read_debug_info_section_somehow = || &info_buf; + /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); + /// + /// // Get the data about the first compilation unit out of the `.debug_info`. + /// + /// let unit = debug_info.units().next() + /// .expect("Should have at least one compilation unit") + /// .expect("and it should parse ok"); + /// + /// // Read the `.debug_abbrev` section and parse the + /// // abbreviations for our compilation unit. + /// + /// # let abbrev_buf = [ + /// # // Code + /// # 0x01, + /// # // DW_TAG_subprogram + /// # 0x2e, + /// # // DW_CHILDREN_no + /// # 0x00, + /// # // Begin attributes + /// # // Attribute name = DW_AT_name + /// # 0x03, + /// # // Attribute form = DW_FORM_string + /// # 0x08, + /// # // End attributes + /// # 0x00, + /// # 0x00, + /// # // Null terminator + /// # 0x00 + /// # ]; + /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; + /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); + /// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); + /// + /// // Get the first entry from that compilation unit. + /// + /// let mut cursor = unit.entries(&abbrevs); + /// let (_, entry) = cursor.next_dfs() + /// .expect("Should parse next entry") + /// .expect("Should have at least one entry"); + /// + /// // Finally, print the first entry's attributes. + /// + /// let mut attrs = entry.attrs(); + /// while let Some(attr) = attrs.next().unwrap() { + /// println!("Attribute name = {:?}", attr.name()); + /// println!("Attribute value = {:?}", attr.value()); + /// } + /// ``` + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> { + AttrsIter { + input: self.attrs_slice.clone(), + attributes: self.abbrev.attributes(), + entry: self, + } + } + + /// Find the first attribute in this entry which has the given name, + /// and return it. Returns `Ok(None)` if no attribute is found. + pub fn attr(&self, name: constants::DwAt) -> Result>> { + let mut attrs = self.attrs(); + while let Some(attr) = attrs.next()? { + if attr.name() == name { + return Ok(Some(attr)); + } + } + Ok(None) + } + + /// Find the first attribute in this entry which has the given name, + /// and return its raw value. Returns `Ok(None)` if no attribute is found. + pub fn attr_value_raw(&self, name: constants::DwAt) -> Result>> { + self.attr(name) + .map(|attr| attr.map(|attr| attr.raw_value())) + } + + /// Find the first attribute in this entry which has the given name, + /// and return its normalized value. Returns `Ok(None)` if no + /// attribute is found. + pub fn attr_value(&self, name: constants::DwAt) -> Result>> { + self.attr(name).map(|attr| attr.map(|attr| attr.value())) + } + + /// Return the input buffer after the last attribute. + #[inline(always)] + fn after_attrs(&self) -> Result { + if let Some(attrs_len) = self.attrs_len.get() { + let mut input = self.attrs_slice.clone(); + input.skip(attrs_len)?; + Ok(input) + } else { + let mut attrs = self.attrs(); + while attrs.next()?.is_some() {} + Ok(attrs.input) + } + } + + /// Use the `DW_AT_sibling` attribute to find the input buffer for the + /// next sibling. Returns `None` if the attribute is missing or invalid. + fn sibling(&self) -> Option { + let attr = self.attr_value(constants::DW_AT_sibling); + if let Ok(Some(AttributeValue::UnitRef(offset))) = attr { + if offset.0 > self.offset.0 { + if let Ok(input) = self.unit.range_from(offset..) { + return Some(input); + } + } + } + None + } + + /// Parse an entry. Returns `Ok(None)` for null entries. + #[inline(always)] + fn parse( + input: &mut R, + unit: &'unit UnitHeader, + abbreviations: &'abbrev Abbreviations, + ) -> Result> { + let offset = unit.header_size() + input.offset_from(&unit.entries_buf); + let code = input.read_uleb128()?; + if code == 0 { + return Ok(None); + }; + let abbrev = abbreviations + .get(code) + .ok_or(Error::UnknownAbbreviation(code))?; + Ok(Some(DebuggingInformationEntry { + offset: UnitOffset(offset), + attrs_slice: input.clone(), + attrs_len: Cell::new(None), + abbrev, + unit, + })) + } +} + +/// The value of an attribute in a `DebuggingInformationEntry`. +// +// Set the discriminant size so that all variants use the same alignment +// for their data. This gives better code generation in `parse_attribute`. +#[repr(u64)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum AttributeValue::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// "Refers to some location in the address space of the described program." + Addr(u64), + + /// A slice of an arbitrary number of bytes. + Block(R), + + /// A one byte constant data value. How to interpret the byte depends on context. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data1(u8), + + /// A two byte constant data value. How to interpret the bytes depends on context. + /// + /// These bytes have been converted from `R::Endian`. This may need to be reversed + /// if this was not required. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data2(u16), + + /// A four byte constant data value. How to interpret the bytes depends on context. + /// + /// These bytes have been converted from `R::Endian`. This may need to be reversed + /// if this was not required. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data4(u32), + + /// An eight byte constant data value. How to interpret the bytes depends on context. + /// + /// These bytes have been converted from `R::Endian`. This may need to be reversed + /// if this was not required. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data8(u64), + + /// A signed integer constant. + Sdata(i64), + + /// An unsigned integer constant. + Udata(u64), + + /// "The information bytes contain a DWARF expression (see Section 2.5) or + /// location description (see Section 2.6)." + Exprloc(Expression), + + /// A boolean that indicates presence or absence of the attribute. + Flag(bool), + + /// An offset into another section. Which section this is an offset into + /// depends on context. + SecOffset(Offset), + + /// An offset to a set of addresses in the `.debug_addr` section. + DebugAddrBase(DebugAddrBase), + + /// An index into a set of addresses in the `.debug_addr` section. + DebugAddrIndex(DebugAddrIndex), + + /// An offset into the current compilation unit. + UnitRef(UnitOffset), + + /// An offset into the current `.debug_info` section, but possibly a + /// different compilation unit from the current one. + DebugInfoRef(DebugInfoOffset), + + /// An offset into the `.debug_info` section of the supplementary object file. + DebugInfoRefSup(DebugInfoOffset), + + /// An offset into the `.debug_line` section. + DebugLineRef(DebugLineOffset), + + /// An offset into either the `.debug_loc` section or the `.debug_loclists` section. + LocationListsRef(LocationListsOffset), + + /// An offset to a set of offsets in the `.debug_loclists` section. + DebugLocListsBase(DebugLocListsBase), + + /// An index into a set of offsets in the `.debug_loclists` section. + DebugLocListsIndex(DebugLocListsIndex), + + /// An offset into the `.debug_macinfo` section. + DebugMacinfoRef(DebugMacinfoOffset), + + /// An offset into the `.debug_macro` section. + DebugMacroRef(DebugMacroOffset), + + /// An offset into the `.debug_ranges` section. + RangeListsRef(RawRangeListsOffset), + + /// An offset to a set of offsets in the `.debug_rnglists` section. + DebugRngListsBase(DebugRngListsBase), + + /// An index into a set of offsets in the `.debug_rnglists` section. + DebugRngListsIndex(DebugRngListsIndex), + + /// A type signature. + DebugTypesRef(DebugTypeSignature), + + /// An offset into the `.debug_str` section. + DebugStrRef(DebugStrOffset), + + /// An offset into the `.debug_str` section of the supplementary object file. + DebugStrRefSup(DebugStrOffset), + + /// An offset to a set of entries in the `.debug_str_offsets` section. + DebugStrOffsetsBase(DebugStrOffsetsBase), + + /// An index into a set of entries in the `.debug_str_offsets` section. + DebugStrOffsetsIndex(DebugStrOffsetsIndex), + + /// An offset into the `.debug_line_str` section. + DebugLineStrRef(DebugLineStrOffset), + + /// A slice of bytes representing a string. Does not include a final null byte. + /// Not guaranteed to be UTF-8 or anything like that. + String(R), + + /// The value of a `DW_AT_encoding` attribute. + Encoding(constants::DwAte), + + /// The value of a `DW_AT_decimal_sign` attribute. + DecimalSign(constants::DwDs), + + /// The value of a `DW_AT_endianity` attribute. + Endianity(constants::DwEnd), + + /// The value of a `DW_AT_accessibility` attribute. + Accessibility(constants::DwAccess), + + /// The value of a `DW_AT_visibility` attribute. + Visibility(constants::DwVis), + + /// The value of a `DW_AT_virtuality` attribute. + Virtuality(constants::DwVirtuality), + + /// The value of a `DW_AT_language` attribute. + Language(constants::DwLang), + + /// The value of a `DW_AT_address_class` attribute. + AddressClass(constants::DwAddr), + + /// The value of a `DW_AT_identifier_case` attribute. + IdentifierCase(constants::DwId), + + /// The value of a `DW_AT_calling_convention` attribute. + CallingConvention(constants::DwCc), + + /// The value of a `DW_AT_inline` attribute. + Inline(constants::DwInl), + + /// The value of a `DW_AT_ordering` attribute. + Ordering(constants::DwOrd), + + /// An index into the filename entries from the line number information + /// table for the compilation unit containing this value. + FileIndex(u64), + + /// An implementation-defined identifier uniquely identifying a compilation + /// unit. + DwoId(DwoId), +} + +/// An attribute in a `DebuggingInformationEntry`, consisting of a name and +/// associated value. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Attribute { + name: constants::DwAt, + value: AttributeValue, +} + +impl Attribute { + /// Get this attribute's name. + pub fn name(&self) -> constants::DwAt { + self.name + } + + /// Get this attribute's raw value. + pub fn raw_value(&self) -> AttributeValue { + self.value.clone() + } + + /// Get this attribute's normalized value. + /// + /// Attribute values can potentially be encoded in multiple equivalent forms, + /// and may have special meaning depending on the attribute name. This method + /// converts the attribute value to a normalized form based on the attribute + /// name. + /// + /// See "Table 7.5: Attribute encodings" and "Table 7.6: Attribute form encodings". + pub fn value(&self) -> AttributeValue { + // Table 7.5 shows the possible attribute classes for each name. + // Table 7.6 shows the possible attribute classes for each form. + // For each attribute name, we need to match on the form, and + // convert it to one of the classes that is allowed for both + // the name and the form. + // + // The individual class conversions rarely vary for each name, + // so for each class conversion we define a macro that matches + // on the allowed forms for that class. + // + // For some classes, we don't need to do any conversion, so their + // macro is empty. In the future we may want to fill them in to + // provide strict checking of the forms for each class. For now, + // they simply provide a way to document the allowed classes for + // each name. + + // DW_FORM_addr + // DW_FORM_addrx + // DW_FORM_addrx1 + // DW_FORM_addrx2 + // DW_FORM_addrx3 + // DW_FORM_addrx4 + macro_rules! address { + () => {}; + } + // DW_FORM_sec_offset + macro_rules! addrptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugAddrBase(DebugAddrBase(offset)); + } + }; + } + // DW_FORM_block + // DW_FORM_block1 + // DW_FORM_block2 + // DW_FORM_block4 + macro_rules! block { + () => {}; + } + // DW_FORM_sdata + // DW_FORM_udata + // DW_FORM_data1 + // DW_FORM_data2 + // DW_FORM_data4 + // DW_FORM_data8 + // DW_FORM_data16 + // DW_FORM_implicit_const + macro_rules! constant { + ($value:ident, $variant:ident) => { + if let Some(value) = self.$value() { + return AttributeValue::$variant(value); + } + }; + ($value:ident, $variant:ident, $constant:ident) => { + if let Some(value) = self.$value() { + return AttributeValue::$variant(constants::$constant(value)); + } + }; + } + // DW_FORM_exprloc + macro_rules! exprloc { + () => { + if let Some(value) = self.exprloc_value() { + return AttributeValue::Exprloc(value); + } + }; + } + // DW_FORM_flag + // DW_FORM_flag_present + macro_rules! flag { + () => {}; + } + // DW_FORM_sec_offset + macro_rules! lineptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugLineRef(DebugLineOffset(offset)); + } + }; + } + // This also covers `loclist` in DWARF version 5. + // DW_FORM_sec_offset + // DW_FORM_loclistx + macro_rules! loclistptr { + () => { + // DebugLocListsIndex is also an allowed form in DWARF version 5. + if let Some(offset) = self.offset_value() { + return AttributeValue::LocationListsRef(LocationListsOffset(offset)); + } + }; + } + // DW_FORM_sec_offset + macro_rules! loclistsptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset)); + } + }; + } + // DWARF version <= 4. + // DW_FORM_sec_offset + macro_rules! macinfoptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset)); + } + }; + } + // DWARF version >= 5. + // DW_FORM_sec_offset + macro_rules! macroptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugMacroRef(DebugMacroOffset(offset)); + } + }; + } + // DW_FORM_ref_addr + // DW_FORM_ref1 + // DW_FORM_ref2 + // DW_FORM_ref4 + // DW_FORM_ref8 + // DW_FORM_ref_udata + // DW_FORM_ref_sig8 + // DW_FORM_ref_sup4 + // DW_FORM_ref_sup8 + macro_rules! reference { + () => {}; + } + // This also covers `rnglist` in DWARF version 5. + // DW_FORM_sec_offset + // DW_FORM_rnglistx + macro_rules! rangelistptr { + () => { + // DebugRngListsIndex is also an allowed form in DWARF version 5. + if let Some(offset) = self.offset_value() { + return AttributeValue::RangeListsRef(RawRangeListsOffset(offset)); + } + }; + } + // DW_FORM_sec_offset + macro_rules! rnglistsptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset)); + } + }; + } + // DW_FORM_string + // DW_FORM_strp + // DW_FORM_strx + // DW_FORM_strx1 + // DW_FORM_strx2 + // DW_FORM_strx3 + // DW_FORM_strx4 + // DW_FORM_strp_sup + // DW_FORM_line_strp + macro_rules! string { + () => {}; + } + // DW_FORM_sec_offset + macro_rules! stroffsetsptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset)); + } + }; + } + // This isn't a separate form but it's useful to distinguish it from a generic udata. + macro_rules! dwoid { + () => { + if let Some(value) = self.udata_value() { + return AttributeValue::DwoId(DwoId(value)); + } + }; + } + + // Perform the allowed class conversions for each attribute name. + match self.name { + constants::DW_AT_sibling => { + reference!(); + } + constants::DW_AT_location => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_name => { + string!(); + } + constants::DW_AT_ordering => { + constant!(u8_value, Ordering, DwOrd); + } + constants::DW_AT_byte_size + | constants::DW_AT_bit_offset + | constants::DW_AT_bit_size => { + constant!(udata_value, Udata); + exprloc!(); + reference!(); + } + constants::DW_AT_stmt_list => { + lineptr!(); + } + constants::DW_AT_low_pc => { + address!(); + } + constants::DW_AT_high_pc => { + address!(); + constant!(udata_value, Udata); + } + constants::DW_AT_language => { + constant!(u16_value, Language, DwLang); + } + constants::DW_AT_discr => { + reference!(); + } + constants::DW_AT_discr_value => { + // constant: depends on type of DW_TAG_variant_part, + // so caller must normalize. + } + constants::DW_AT_visibility => { + constant!(u8_value, Visibility, DwVis); + } + constants::DW_AT_import => { + reference!(); + } + constants::DW_AT_string_length => { + exprloc!(); + loclistptr!(); + reference!(); + } + constants::DW_AT_common_reference => { + reference!(); + } + constants::DW_AT_comp_dir => { + string!(); + } + constants::DW_AT_const_value => { + // TODO: constant: sign depends on DW_AT_type. + block!(); + string!(); + } + constants::DW_AT_containing_type => { + reference!(); + } + constants::DW_AT_default_value => { + // TODO: constant: sign depends on DW_AT_type. + reference!(); + flag!(); + } + constants::DW_AT_inline => { + constant!(u8_value, Inline, DwInl); + } + constants::DW_AT_is_optional => { + flag!(); + } + constants::DW_AT_lower_bound => { + // TODO: constant: sign depends on DW_AT_type. + exprloc!(); + reference!(); + } + constants::DW_AT_producer => { + string!(); + } + constants::DW_AT_prototyped => { + flag!(); + } + constants::DW_AT_return_addr => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_start_scope => { + // TODO: constant + rangelistptr!(); + } + constants::DW_AT_bit_stride => { + constant!(udata_value, Udata); + exprloc!(); + reference!(); + } + constants::DW_AT_upper_bound => { + // TODO: constant: sign depends on DW_AT_type. + exprloc!(); + reference!(); + } + constants::DW_AT_abstract_origin => { + reference!(); + } + constants::DW_AT_accessibility => { + constant!(u8_value, Accessibility, DwAccess); + } + constants::DW_AT_address_class => { + constant!(udata_value, AddressClass, DwAddr); + } + constants::DW_AT_artificial => { + flag!(); + } + constants::DW_AT_base_types => { + reference!(); + } + constants::DW_AT_calling_convention => { + constant!(u8_value, CallingConvention, DwCc); + } + constants::DW_AT_count => { + // TODO: constant + exprloc!(); + reference!(); + } + constants::DW_AT_data_member_location => { + // Constants must be handled before loclistptr so that DW_FORM_data4/8 + // are correctly interpreted for DWARF version 4+. + constant!(udata_value, Udata); + exprloc!(); + loclistptr!(); + } + constants::DW_AT_decl_column => { + constant!(udata_value, Udata); + } + constants::DW_AT_decl_file => { + constant!(udata_value, FileIndex); + } + constants::DW_AT_decl_line => { + constant!(udata_value, Udata); + } + constants::DW_AT_declaration => { + flag!(); + } + constants::DW_AT_discr_list => { + block!(); + } + constants::DW_AT_encoding => { + constant!(u8_value, Encoding, DwAte); + } + constants::DW_AT_external => { + flag!(); + } + constants::DW_AT_frame_base => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_friend => { + reference!(); + } + constants::DW_AT_identifier_case => { + constant!(u8_value, IdentifierCase, DwId); + } + constants::DW_AT_macro_info => { + macinfoptr!(); + } + constants::DW_AT_namelist_item => { + reference!(); + } + constants::DW_AT_priority => { + reference!(); + } + constants::DW_AT_segment => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_specification => { + reference!(); + } + constants::DW_AT_static_link => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_type => { + reference!(); + } + constants::DW_AT_use_location => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_variable_parameter => { + flag!(); + } + constants::DW_AT_virtuality => { + constant!(u8_value, Virtuality, DwVirtuality); + } + constants::DW_AT_vtable_elem_location => { + exprloc!(); + loclistptr!(); + } + constants::DW_AT_allocated => { + // TODO: constant + exprloc!(); + reference!(); + } + constants::DW_AT_associated => { + // TODO: constant + exprloc!(); + reference!(); + } + constants::DW_AT_data_location => { + exprloc!(); + } + constants::DW_AT_byte_stride => { + constant!(udata_value, Udata); + exprloc!(); + reference!(); + } + constants::DW_AT_entry_pc => { + // TODO: constant + address!(); + } + constants::DW_AT_use_UTF8 => { + flag!(); + } + constants::DW_AT_extension => { + reference!(); + } + constants::DW_AT_ranges => { + rangelistptr!(); + } + constants::DW_AT_trampoline => { + address!(); + flag!(); + reference!(); + string!(); + } + constants::DW_AT_call_column => { + constant!(udata_value, Udata); + } + constants::DW_AT_call_file => { + constant!(udata_value, FileIndex); + } + constants::DW_AT_call_line => { + constant!(udata_value, Udata); + } + constants::DW_AT_description => { + string!(); + } + constants::DW_AT_binary_scale => { + // TODO: constant + } + constants::DW_AT_decimal_scale => { + // TODO: constant + } + constants::DW_AT_small => { + reference!(); + } + constants::DW_AT_decimal_sign => { + constant!(u8_value, DecimalSign, DwDs); + } + constants::DW_AT_digit_count => { + // TODO: constant + } + constants::DW_AT_picture_string => { + string!(); + } + constants::DW_AT_mutable => { + flag!(); + } + constants::DW_AT_threads_scaled => { + flag!(); + } + constants::DW_AT_explicit => { + flag!(); + } + constants::DW_AT_object_pointer => { + reference!(); + } + constants::DW_AT_endianity => { + constant!(u8_value, Endianity, DwEnd); + } + constants::DW_AT_elemental => { + flag!(); + } + constants::DW_AT_pure => { + flag!(); + } + constants::DW_AT_recursive => { + flag!(); + } + constants::DW_AT_signature => { + reference!(); + } + constants::DW_AT_main_subprogram => { + flag!(); + } + constants::DW_AT_data_bit_offset => { + // TODO: constant + } + constants::DW_AT_const_expr => { + flag!(); + } + constants::DW_AT_enum_class => { + flag!(); + } + constants::DW_AT_linkage_name => { + string!(); + } + constants::DW_AT_string_length_bit_size => { + // TODO: constant + } + constants::DW_AT_string_length_byte_size => { + // TODO: constant + } + constants::DW_AT_rank => { + // TODO: constant + exprloc!(); + } + constants::DW_AT_str_offsets_base => { + stroffsetsptr!(); + } + constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { + addrptr!(); + } + constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { + rnglistsptr!(); + } + constants::DW_AT_dwo_name => { + string!(); + } + constants::DW_AT_reference => { + flag!(); + } + constants::DW_AT_rvalue_reference => { + flag!(); + } + constants::DW_AT_macros => { + macroptr!(); + } + constants::DW_AT_call_all_calls => { + flag!(); + } + constants::DW_AT_call_all_source_calls => { + flag!(); + } + constants::DW_AT_call_all_tail_calls => { + flag!(); + } + constants::DW_AT_call_return_pc => { + address!(); + } + constants::DW_AT_call_value => { + exprloc!(); + } + constants::DW_AT_call_origin => { + exprloc!(); + } + constants::DW_AT_call_parameter => { + reference!(); + } + constants::DW_AT_call_pc => { + address!(); + } + constants::DW_AT_call_tail_call => { + flag!(); + } + constants::DW_AT_call_target => { + exprloc!(); + } + constants::DW_AT_call_target_clobbered => { + exprloc!(); + } + constants::DW_AT_call_data_location => { + exprloc!(); + } + constants::DW_AT_call_data_value => { + exprloc!(); + } + constants::DW_AT_noreturn => { + flag!(); + } + constants::DW_AT_alignment => { + // TODO: constant + } + constants::DW_AT_export_symbols => { + flag!(); + } + constants::DW_AT_deleted => { + flag!(); + } + constants::DW_AT_defaulted => { + // TODO: constant + } + constants::DW_AT_loclists_base => { + loclistsptr!(); + } + constants::DW_AT_GNU_dwo_id => { + dwoid!(); + } + _ => {} + } + self.value.clone() + } + + /// Try to convert this attribute's value to a u8. + #[inline] + pub fn u8_value(&self) -> Option { + self.value.u8_value() + } + + /// Try to convert this attribute's value to a u16. + #[inline] + pub fn u16_value(&self) -> Option { + self.value.u16_value() + } + + /// Try to convert this attribute's value to an unsigned integer. + #[inline] + pub fn udata_value(&self) -> Option { + self.value.udata_value() + } + + /// Try to convert this attribute's value to a signed integer. + #[inline] + pub fn sdata_value(&self) -> Option { + self.value.sdata_value() + } + + /// Try to convert this attribute's value to an offset. + #[inline] + pub fn offset_value(&self) -> Option { + self.value.offset_value() + } + + /// Try to convert this attribute's value to an expression or location buffer. + /// + /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. + /// The standard doesn't mention `DW_FORM_block*` as a possible form, but + /// it is encountered in practice. + #[inline] + pub fn exprloc_value(&self) -> Option> { + self.value.exprloc_value() + } + + /// Try to return this attribute's value as a string slice. + /// + /// If this attribute's value is either an inline `DW_FORM_string` string, + /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` + /// section, return the attribute's string value as `Some`. Other attribute + /// value forms are returned as `None`. + /// + /// Warning: this function does not handle all possible string forms. + /// Use `Dwarf::attr_string` instead. + #[inline] + pub fn string_value(&self, debug_str: &DebugStr) -> Option { + self.value.string_value(debug_str) + } + + /// Try to return this attribute's value as a string slice. + /// + /// If this attribute's value is either an inline `DW_FORM_string` string, + /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` + /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary + /// object file, return the attribute's string value as `Some`. Other attribute + /// value forms are returned as `None`. + /// + /// Warning: this function does not handle all possible string forms. + /// Use `Dwarf::attr_string` instead. + #[inline] + pub fn string_value_sup( + &self, + debug_str: &DebugStr, + debug_str_sup: Option<&DebugStr>, + ) -> Option { + self.value.string_value_sup(debug_str, debug_str_sup) + } +} + +impl AttributeValue +where + R: Reader, + Offset: ReaderOffset, +{ + /// Try to convert this attribute's value to a u8. + pub fn u8_value(&self) -> Option { + if let Some(value) = self.udata_value() { + if value <= u64::from(u8::MAX) { + return Some(value as u8); + } + } + None + } + + /// Try to convert this attribute's value to a u16. + pub fn u16_value(&self) -> Option { + if let Some(value) = self.udata_value() { + if value <= u64::from(u16::MAX) { + return Some(value as u16); + } + } + None + } + + /// Try to convert this attribute's value to an unsigned integer. + pub fn udata_value(&self) -> Option { + Some(match *self { + AttributeValue::Data1(data) => u64::from(data), + AttributeValue::Data2(data) => u64::from(data), + AttributeValue::Data4(data) => u64::from(data), + AttributeValue::Data8(data) => data, + AttributeValue::Udata(data) => data, + AttributeValue::Sdata(data) => { + if data < 0 { + // Maybe we should emit a warning here + return None; + } + data as u64 + } + _ => return None, + }) + } + + /// Try to convert this attribute's value to a signed integer. + pub fn sdata_value(&self) -> Option { + Some(match *self { + AttributeValue::Data1(data) => i64::from(data as i8), + AttributeValue::Data2(data) => i64::from(data as i16), + AttributeValue::Data4(data) => i64::from(data as i32), + AttributeValue::Data8(data) => data as i64, + AttributeValue::Sdata(data) => data, + AttributeValue::Udata(data) => { + if data > i64::MAX as u64 { + // Maybe we should emit a warning here + return None; + } + data as i64 + } + _ => return None, + }) + } + + /// Try to convert this attribute's value to an offset. + pub fn offset_value(&self) -> Option { + // While offsets will be DW_FORM_data4/8 in DWARF version 2/3, + // these have already been converted to `SecOffset. + if let AttributeValue::SecOffset(offset) = *self { + Some(offset) + } else { + None + } + } + + /// Try to convert this attribute's value to an expression or location buffer. + /// + /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. + /// The standard doesn't mention `DW_FORM_block*` as a possible form, but + /// it is encountered in practice. + pub fn exprloc_value(&self) -> Option> { + Some(match *self { + AttributeValue::Block(ref data) => Expression(data.clone()), + AttributeValue::Exprloc(ref data) => data.clone(), + _ => return None, + }) + } + + /// Try to return this attribute's value as a string slice. + /// + /// If this attribute's value is either an inline `DW_FORM_string` string, + /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` + /// section, return the attribute's string value as `Some`. Other attribute + /// value forms are returned as `None`. + /// + /// Warning: this function does not handle all possible string forms. + /// Use `Dwarf::attr_string` instead. + pub fn string_value(&self, debug_str: &DebugStr) -> Option { + match *self { + AttributeValue::String(ref string) => Some(string.clone()), + AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), + _ => None, + } + } + + /// Try to return this attribute's value as a string slice. + /// + /// If this attribute's value is either an inline `DW_FORM_string` string, + /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` + /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary + /// object file, return the attribute's string value as `Some`. Other attribute + /// value forms are returned as `None`. + /// + /// Warning: this function does not handle all possible string forms. + /// Use `Dwarf::attr_string` instead. + pub fn string_value_sup( + &self, + debug_str: &DebugStr, + debug_str_sup: Option<&DebugStr>, + ) -> Option { + match *self { + AttributeValue::String(ref string) => Some(string.clone()), + AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), + AttributeValue::DebugStrRefSup(offset) => { + debug_str_sup.and_then(|s| s.get_str(offset).ok()) + } + _ => None, + } + } +} + +fn length_u8_value(input: &mut R) -> Result { + let len = input.read_u8().map(R::Offset::from_u8)?; + input.split(len) +} + +fn length_u16_value(input: &mut R) -> Result { + let len = input.read_u16().map(R::Offset::from_u16)?; + input.split(len) +} + +fn length_u32_value(input: &mut R) -> Result { + let len = input.read_u32().map(R::Offset::from_u32)?; + input.split(len) +} + +fn length_uleb128_value(input: &mut R) -> Result { + let len = input.read_uleb128().and_then(R::Offset::from_u64)?; + input.split(len) +} + +// Return true if the given `name` can be a section offset in DWARF version 2/3. +// This is required to correctly handle relocations. +fn allow_section_offset(name: constants::DwAt, version: u16) -> bool { + match name { + constants::DW_AT_location + | constants::DW_AT_stmt_list + | constants::DW_AT_string_length + | constants::DW_AT_return_addr + | constants::DW_AT_start_scope + | constants::DW_AT_frame_base + | constants::DW_AT_macro_info + | constants::DW_AT_macros + | constants::DW_AT_segment + | constants::DW_AT_static_link + | constants::DW_AT_use_location + | constants::DW_AT_vtable_elem_location + | constants::DW_AT_ranges => true, + constants::DW_AT_data_member_location => version == 2 || version == 3, + _ => false, + } +} + +pub(crate) fn parse_attribute( + input: &mut R, + encoding: Encoding, + spec: AttributeSpecification, +) -> Result> { + let mut form = spec.form(); + loop { + let value = match form { + constants::DW_FORM_indirect => { + let dynamic_form = input.read_uleb128_u16()?; + form = constants::DwForm(dynamic_form); + continue; + } + constants::DW_FORM_addr => { + let addr = input.read_address(encoding.address_size)?; + AttributeValue::Addr(addr) + } + constants::DW_FORM_block1 => { + let block = length_u8_value(input)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block2 => { + let block = length_u16_value(input)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block4 => { + let block = length_u32_value(input)?; + AttributeValue::Block(block) + } + constants::DW_FORM_block => { + let block = length_uleb128_value(input)?; + AttributeValue::Block(block) + } + constants::DW_FORM_data1 => { + let data = input.read_u8()?; + AttributeValue::Data1(data) + } + constants::DW_FORM_data2 => { + let data = input.read_u16()?; + AttributeValue::Data2(data) + } + constants::DW_FORM_data4 => { + // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. + // Ensure we handle relocations here. + if encoding.format == Format::Dwarf32 + && allow_section_offset(spec.name(), encoding.version) + { + let offset = input.read_offset(Format::Dwarf32)?; + AttributeValue::SecOffset(offset) + } else { + let data = input.read_u32()?; + AttributeValue::Data4(data) + } + } + constants::DW_FORM_data8 => { + // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. + // Ensure we handle relocations here. + if encoding.format == Format::Dwarf64 + && allow_section_offset(spec.name(), encoding.version) + { + let offset = input.read_offset(Format::Dwarf64)?; + AttributeValue::SecOffset(offset) + } else { + let data = input.read_u64()?; + AttributeValue::Data8(data) + } + } + constants::DW_FORM_data16 => { + let block = input.split(R::Offset::from_u8(16))?; + AttributeValue::Block(block) + } + constants::DW_FORM_udata => { + let data = input.read_uleb128()?; + AttributeValue::Udata(data) + } + constants::DW_FORM_sdata => { + let data = input.read_sleb128()?; + AttributeValue::Sdata(data) + } + constants::DW_FORM_exprloc => { + let block = length_uleb128_value(input)?; + AttributeValue::Exprloc(Expression(block)) + } + constants::DW_FORM_flag => { + let present = input.read_u8()?; + AttributeValue::Flag(present != 0) + } + constants::DW_FORM_flag_present => { + // FlagPresent is this weird compile time always true thing that + // isn't actually present in the serialized DIEs, only in the abbreviation. + AttributeValue::Flag(true) + } + constants::DW_FORM_sec_offset => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::SecOffset(offset) + } + constants::DW_FORM_ref1 => { + let reference = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::UnitRef(UnitOffset(reference)) + } + constants::DW_FORM_ref2 => { + let reference = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::UnitRef(UnitOffset(reference)) + } + constants::DW_FORM_ref4 => { + let reference = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::UnitRef(UnitOffset(reference)) + } + constants::DW_FORM_ref8 => { + let reference = input.read_u64().and_then(R::Offset::from_u64)?; + AttributeValue::UnitRef(UnitOffset(reference)) + } + constants::DW_FORM_ref_udata => { + let reference = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::UnitRef(UnitOffset(reference)) + } + constants::DW_FORM_ref_addr => { + // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr + // has the same size as an address on the target system. This was changed + // in DWARF version 3. + let offset = if encoding.version == 2 { + input.read_sized_offset(encoding.address_size)? + } else { + input.read_offset(encoding.format)? + }; + AttributeValue::DebugInfoRef(DebugInfoOffset(offset)) + } + constants::DW_FORM_ref_sig8 => { + let signature = input.read_u64()?; + AttributeValue::DebugTypesRef(DebugTypeSignature(signature)) + } + constants::DW_FORM_ref_sup4 => { + let offset = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) + } + constants::DW_FORM_ref_sup8 => { + let offset = input.read_u64().and_then(R::Offset::from_u64)?; + AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) + } + constants::DW_FORM_GNU_ref_alt => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) + } + constants::DW_FORM_string => { + let string = input.read_null_terminated_slice()?; + AttributeValue::String(string) + } + constants::DW_FORM_strp => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugStrRef(DebugStrOffset(offset)) + } + constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) + } + constants::DW_FORM_line_strp => { + let offset = input.read_offset(encoding.format)?; + AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) + } + constants::DW_FORM_implicit_const => { + let data = spec + .implicit_const_value() + .ok_or(Error::InvalidImplicitConst)?; + AttributeValue::Sdata(data) + } + constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx1 => { + let index = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx2 => { + let index = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx3 => { + let index = input.read_uint(3).and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx4 => { + let index = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx1 => { + let index = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx2 => { + let index = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx3 => { + let index = input.read_uint(3).and_then(R::Offset::from_u64)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx4 => { + let index = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_loclistx => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index)) + } + constants::DW_FORM_rnglistx => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index)) + } + _ => { + return Err(Error::UnknownForm(form)); + } + }; + let attr = Attribute { + name: spec.name(), + value, + }; + return Ok(attr); + } +} + +pub(crate) fn skip_attributes( + input: &mut R, + encoding: Encoding, + specs: &[AttributeSpecification], +) -> Result<()> { + let mut skip_bytes = R::Offset::from_u8(0); + for spec in specs { + let mut form = spec.form(); + loop { + if let Some(len) = get_attribute_size(form, encoding) { + // We know the length of this attribute. Accumulate that length. + skip_bytes += R::Offset::from_u8(len); + break; + } + + // We have encountered a variable-length attribute. + if skip_bytes != R::Offset::from_u8(0) { + // Skip the accumulated skip bytes and then read the attribute normally. + input.skip(skip_bytes)?; + skip_bytes = R::Offset::from_u8(0); + } + + match form { + constants::DW_FORM_indirect => { + let dynamic_form = input.read_uleb128_u16()?; + form = constants::DwForm(dynamic_form); + continue; + } + constants::DW_FORM_block1 => { + skip_bytes = input.read_u8().map(R::Offset::from_u8)?; + } + constants::DW_FORM_block2 => { + skip_bytes = input.read_u16().map(R::Offset::from_u16)?; + } + constants::DW_FORM_block4 => { + skip_bytes = input.read_u32().map(R::Offset::from_u32)?; + } + constants::DW_FORM_block | constants::DW_FORM_exprloc => { + skip_bytes = input.read_uleb128().and_then(R::Offset::from_u64)?; + } + constants::DW_FORM_string => { + let _ = input.read_null_terminated_slice()?; + } + constants::DW_FORM_udata + | constants::DW_FORM_sdata + | constants::DW_FORM_ref_udata + | constants::DW_FORM_strx + | constants::DW_FORM_GNU_str_index + | constants::DW_FORM_addrx + | constants::DW_FORM_GNU_addr_index + | constants::DW_FORM_loclistx + | constants::DW_FORM_rnglistx => { + input.skip_leb128()?; + } + _ => { + return Err(Error::UnknownForm(form)); + } + }; + break; + } + } + if skip_bytes != R::Offset::from_u8(0) { + // Skip the remaining accumulated skip bytes. + input.skip(skip_bytes)?; + } + Ok(()) +} + +/// An iterator over a particular entry's attributes. +/// +/// See [the documentation for +/// `DebuggingInformationEntry::attrs()`](./struct.DebuggingInformationEntry.html#method.attrs) +/// for details. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Clone, Copy, Debug)] +pub struct AttrsIter<'abbrev, 'entry, 'unit, R: Reader> { + input: R, + attributes: &'abbrev [AttributeSpecification], + entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>, +} + +impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> { + /// Advance the iterator and return the next attribute. + /// + /// Returns `None` when iteration is finished. If an error + /// occurs while parsing the next attribute, then this error + /// is returned, and all subsequent calls return `None`. + #[inline(always)] + pub fn next(&mut self) -> Result>> { + if self.attributes.is_empty() { + // Now that we have parsed all of the attributes, we know where + // either (1) this entry's children start, if the abbreviation says + // this entry has children; or (2) where this entry's siblings + // begin. + if let Some(end) = self.entry.attrs_len.get() { + debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice)); + } else { + self.entry + .attrs_len + .set(Some(self.input.offset_from(&self.entry.attrs_slice))); + } + + return Ok(None); + } + + let spec = self.attributes[0]; + let rest_spec = &self.attributes[1..]; + match parse_attribute(&mut self.input, self.entry.unit.encoding(), spec) { + Ok(attr) => { + self.attributes = rest_spec; + Ok(Some(attr)) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl<'abbrev, 'entry, 'unit, R: Reader> fallible_iterator::FallibleIterator + for AttrsIter<'abbrev, 'entry, 'unit, R> +{ + type Item = Attribute; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + AttrsIter::next(self) + } +} + +/// A raw reader of the data that defines the Debugging Information Entries. +/// +/// `EntriesRaw` provides primitives to read the components of Debugging Information +/// Entries (DIEs). A DIE consists of an abbreviation code (read with `read_abbreviation`) +/// followed by a number of attributes (read with `read_attribute`). +/// The user must provide the control flow to read these correctly. +/// In particular, all attributes must always be read before reading another +/// abbreviation code. +/// +/// `EntriesRaw` lacks some features of `EntriesCursor`, such as the ability to skip +/// to the next sibling DIE. However, this also allows it to optimize better, since it +/// does not need to perform the extra bookkeeping required to support these features, +/// and thus it is suitable for cases where performance is important. +/// +/// ## Example Usage +/// ```rust,no_run +/// # fn example() -> Result<(), gimli::Error> { +/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); +/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); +/// let unit = get_some_unit(); +/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); +/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); +/// let abbrevs = get_abbrevs_for_unit(&unit); +/// +/// let mut entries = unit.entries_raw(&abbrevs, None)?; +/// while !entries.is_empty() { +/// let abbrev = if let Some(abbrev) = entries.read_abbreviation()? { +/// abbrev +/// } else { +/// // Null entry with no attributes. +/// continue +/// }; +/// match abbrev.tag() { +/// gimli::DW_TAG_subprogram => { +/// // Loop over attributes for DIEs we care about. +/// for spec in abbrev.attributes() { +/// let attr = entries.read_attribute(*spec)?; +/// match attr.name() { +/// // Handle attributes. +/// _ => {} +/// } +/// } +/// } +/// _ => { +/// // Skip attributes for DIEs we don't care about. +/// entries.skip_attributes(abbrev.attributes()); +/// } +/// } +/// } +/// # unreachable!() +/// # } +/// ``` +#[derive(Clone, Debug)] +pub struct EntriesRaw<'abbrev, 'unit, R> +where + R: Reader, +{ + input: R, + unit: &'unit UnitHeader, + abbreviations: &'abbrev Abbreviations, + depth: isize, +} + +impl<'abbrev, 'unit, R: Reader> EntriesRaw<'abbrev, 'unit, R> { + /// Return true if there is no more input. + #[inline] + pub fn is_empty(&self) -> bool { + self.input.is_empty() + } + + /// Return the unit offset at which the reader will read next. + /// + /// If you want the offset of the next entry, then this must be called prior to reading + /// the next entry. + pub fn next_offset(&self) -> UnitOffset { + UnitOffset(self.unit.header_size() + self.input.offset_from(&self.unit.entries_buf)) + } + + /// Return the depth of the next entry. + /// + /// This depth is updated when `read_abbreviation` is called, and is updated + /// based on null entries and the `has_children` field in the abbreviation. + #[inline] + pub fn next_depth(&self) -> isize { + self.depth + } + + /// Read an abbreviation code and lookup the corresponding `Abbreviation`. + /// + /// Returns `Ok(None)` for null entries. + #[inline] + pub fn read_abbreviation(&mut self) -> Result> { + let code = self.input.read_uleb128()?; + if code == 0 { + self.depth -= 1; + return Ok(None); + }; + let abbrev = self + .abbreviations + .get(code) + .ok_or(Error::UnknownAbbreviation(code))?; + if abbrev.has_children() { + self.depth += 1; + } + Ok(Some(abbrev)) + } + + /// Read an attribute. + #[inline] + pub fn read_attribute(&mut self, spec: AttributeSpecification) -> Result> { + parse_attribute(&mut self.input, self.unit.encoding(), spec) + } + + /// Skip all the attributes of an abbreviation. + #[inline] + pub fn skip_attributes(&mut self, specs: &[AttributeSpecification]) -> Result<()> { + skip_attributes(&mut self.input, self.unit.encoding(), specs) + } +} + +/// A cursor into the Debugging Information Entries tree for a compilation unit. +/// +/// The `EntriesCursor` can traverse the DIE tree in DFS order using `next_dfs()`, +/// or skip to the next sibling of the entry the cursor is currently pointing to +/// using `next_sibling()`. +/// +/// It is also possible to traverse the DIE tree at a lower abstraction level +/// using `next_entry()`. This method does not skip over null entries, or provide +/// any indication of the current tree depth. In this case, you must use `current()` +/// to obtain the current entry, and `current().has_children()` to determine if +/// the entry following the current entry will be a sibling or child. `current()` +/// will return `None` if the current entry is a null entry, which signifies the +/// end of the current tree depth. +#[derive(Clone, Debug)] +pub struct EntriesCursor<'abbrev, 'unit, R> +where + R: Reader, +{ + input: R, + unit: &'unit UnitHeader, + abbreviations: &'abbrev Abbreviations, + cached_current: Option>, + delta_depth: isize, +} + +impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> { + /// Get a reference to the entry that the cursor is currently pointing to. + /// + /// If the cursor is not pointing at an entry, or if the current entry is a + /// null entry, then `None` is returned. + #[inline] + pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> { + self.cached_current.as_ref() + } + + /// Move the cursor to the next DIE in the tree. + /// + /// Returns `Some` if there is a next entry, even if this entry is null. + /// If there is no next entry, then `None` is returned. + pub fn next_entry(&mut self) -> Result> { + if let Some(ref current) = self.cached_current { + self.input = current.after_attrs()?; + } + + if self.input.is_empty() { + self.cached_current = None; + self.delta_depth = 0; + return Ok(None); + } + + match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { + Ok(Some(entry)) => { + self.delta_depth = entry.has_children() as isize; + self.cached_current = Some(entry); + Ok(Some(())) + } + Ok(None) => { + self.delta_depth = -1; + self.cached_current = None; + Ok(Some(())) + } + Err(e) => { + self.input.empty(); + self.delta_depth = 0; + self.cached_current = None; + Err(e) + } + } + } + + /// Move the cursor to the next DIE in the tree in DFS order. + /// + /// Upon successful movement of the cursor, return the delta traversal + /// depth and the entry: + /// + /// * If we moved down into the previous current entry's children, we get + /// `Some((1, entry))`. + /// + /// * If we moved to the previous current entry's sibling, we get + /// `Some((0, entry))`. + /// + /// * If the previous entry does not have any siblings and we move up to + /// its parent's next sibling, then we get `Some((-1, entry))`. Note that + /// if the parent doesn't have a next sibling, then it could go up to the + /// parent's parent's next sibling and return `Some((-2, entry))`, etc. + /// + /// If there is no next entry, then `None` is returned. + /// + /// Here is an example that finds the first entry in a compilation unit that + /// does not have any children. + /// + /// ``` + /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; + /// # let info_buf = [ + /// # // Comilation unit header + /// # + /// # // 32-bit unit length = 25 + /// # 0x19, 0x00, 0x00, 0x00, + /// # // Version 4 + /// # 0x04, 0x00, + /// # // debug_abbrev_offset + /// # 0x00, 0x00, 0x00, 0x00, + /// # // Address size + /// # 0x04, + /// # + /// # // DIEs + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // End of children + /// # 0x00, + /// # + /// # // End of children + /// # 0x00, + /// # + /// # // End of children + /// # 0x00, + /// # ]; + /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); + /// # + /// # let abbrev_buf = [ + /// # // Code + /// # 0x01, + /// # // DW_TAG_subprogram + /// # 0x2e, + /// # // DW_CHILDREN_yes + /// # 0x01, + /// # // Begin attributes + /// # // Attribute name = DW_AT_name + /// # 0x03, + /// # // Attribute form = DW_FORM_string + /// # 0x08, + /// # // End attributes + /// # 0x00, + /// # 0x00, + /// # // Null terminator + /// # 0x00 + /// # ]; + /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); + /// # + /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); + /// + /// let unit = get_some_unit(); + /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); + /// let abbrevs = get_abbrevs_for_unit(&unit); + /// + /// let mut first_entry_with_no_children = None; + /// let mut cursor = unit.entries(&abbrevs); + /// + /// // Move the cursor to the root. + /// assert!(cursor.next_dfs().unwrap().is_some()); + /// + /// // Traverse the DIE tree in depth-first search order. + /// let mut depth = 0; + /// while let Some((delta_depth, current)) = cursor.next_dfs().expect("Should parse next dfs") { + /// // Update depth value, and break out of the loop when we + /// // return to the original starting position. + /// depth += delta_depth; + /// if depth <= 0 { + /// break; + /// } + /// + /// first_entry_with_no_children = Some(current.clone()); + /// } + /// + /// println!("The first entry with no children is {:?}", + /// first_entry_with_no_children.unwrap()); + /// ``` + pub fn next_dfs( + &mut self, + ) -> Result)>> { + let mut delta_depth = self.delta_depth; + loop { + // The next entry should be the one we want. + if self.next_entry()?.is_some() { + if let Some(ref entry) = self.cached_current { + return Ok(Some((delta_depth, entry))); + } + + // next_entry() read a null entry. + delta_depth += self.delta_depth; + } else { + return Ok(None); + } + } + } + + /// Move the cursor to the next sibling DIE of the current one. + /// + /// Returns `Ok(Some(entry))` when the cursor has been moved to + /// the next sibling, `Ok(None)` when there is no next sibling. + /// + /// The depth of the cursor is never changed if this method returns `Ok`. + /// Once `Ok(None)` is returned, this method will continue to return + /// `Ok(None)` until either `next_entry` or `next_dfs` is called. + /// + /// Here is an example that iterates over all of the direct children of the + /// root entry: + /// + /// ``` + /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; + /// # let info_buf = [ + /// # // Comilation unit header + /// # + /// # // 32-bit unit length = 25 + /// # 0x19, 0x00, 0x00, 0x00, + /// # // Version 4 + /// # 0x04, 0x00, + /// # // debug_abbrev_offset + /// # 0x00, 0x00, 0x00, 0x00, + /// # // Address size + /// # 0x04, + /// # + /// # // DIEs + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // Abbreviation code + /// # 0x01, + /// # // Attribute of form DW_FORM_string = "foo\0" + /// # 0x66, 0x6f, 0x6f, 0x00, + /// # + /// # // Children + /// # + /// # // End of children + /// # 0x00, + /// # + /// # // End of children + /// # 0x00, + /// # + /// # // End of children + /// # 0x00, + /// # ]; + /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); + /// # + /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); + /// + /// # let abbrev_buf = [ + /// # // Code + /// # 0x01, + /// # // DW_TAG_subprogram + /// # 0x2e, + /// # // DW_CHILDREN_yes + /// # 0x01, + /// # // Begin attributes + /// # // Attribute name = DW_AT_name + /// # 0x03, + /// # // Attribute form = DW_FORM_string + /// # 0x08, + /// # // End attributes + /// # 0x00, + /// # 0x00, + /// # // Null terminator + /// # 0x00 + /// # ]; + /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); + /// # + /// let unit = get_some_unit(); + /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); + /// let abbrevs = get_abbrevs_for_unit(&unit); + /// + /// let mut cursor = unit.entries(&abbrevs); + /// + /// // Move the cursor to the root. + /// assert!(cursor.next_dfs().unwrap().is_some()); + /// + /// // Move the cursor to the root's first child. + /// assert!(cursor.next_dfs().unwrap().is_some()); + /// + /// // Iterate the root's children. + /// loop { + /// { + /// let current = cursor.current().expect("Should be at an entry"); + /// println!("{:?} is a child of the root", current); + /// } + /// + /// if cursor.next_sibling().expect("Should parse next sibling").is_none() { + /// break; + /// } + /// } + /// ``` + pub fn next_sibling( + &mut self, + ) -> Result>> { + if self.current().is_none() { + // We're already at the null for the end of the sibling list. + return Ok(None); + } + + // Loop until we find an entry at the current level. + let mut depth = 0; + loop { + // Use is_some() and unwrap() to keep borrow checker happy. + if self.current().is_some() && self.current().unwrap().has_children() { + if let Some(sibling_input) = self.current().unwrap().sibling() { + // Fast path: this entry has a DW_AT_sibling + // attribute pointing to its sibling, so jump + // to it (which keeps us at the same depth). + self.input = sibling_input; + self.cached_current = None; + } else { + // This entry has children, so the next entry is + // down one level. + depth += 1; + } + } + + if self.next_entry()?.is_none() { + // End of input. + return Ok(None); + } + + if depth == 0 { + // Found an entry at the current level. + return Ok(self.current()); + } + + if self.current().is_none() { + // A null entry means the end of a child list, so we're + // back up a level. + depth -= 1; + } + } + } +} + +/// The state information for a tree view of the Debugging Information Entries. +/// +/// The `EntriesTree` can be used to recursively iterate through the DIE +/// tree, following the parent/child relationships. The `EntriesTree` contains +/// shared state for all nodes in the tree, avoiding any duplicate parsing of +/// entries during the traversal. +/// +/// ## Example Usage +/// ```rust,no_run +/// # fn example() -> Result<(), gimli::Error> { +/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); +/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); +/// let unit = get_some_unit(); +/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); +/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); +/// let abbrevs = get_abbrevs_for_unit(&unit); +/// +/// let mut tree = unit.entries_tree(&abbrevs, None)?; +/// let root = tree.root()?; +/// process_tree(root)?; +/// # unreachable!() +/// # } +/// +/// fn process_tree(mut node: gimli::EntriesTreeNode) -> gimli::Result<()> +/// where R: gimli::Reader +/// { +/// { +/// // Examine the entry attributes. +/// let mut attrs = node.entry().attrs(); +/// while let Some(attr) = attrs.next()? { +/// } +/// } +/// let mut children = node.children(); +/// while let Some(child) = children.next()? { +/// // Recursively process a child. +/// process_tree(child); +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Clone, Debug)] +pub struct EntriesTree<'abbrev, 'unit, R> +where + R: Reader, +{ + root: R, + unit: &'unit UnitHeader, + abbreviations: &'abbrev Abbreviations, + input: R, + entry: Option>, + depth: isize, +} + +impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> { + fn new(root: R, unit: &'unit UnitHeader, abbreviations: &'abbrev Abbreviations) -> Self { + let input = root.clone(); + EntriesTree { + root, + unit, + abbreviations, + input, + entry: None, + depth: 0, + } + } + + /// Returns the root node of the tree. + pub fn root<'me>(&'me mut self) -> Result> { + self.input = self.root.clone(); + self.entry = + DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?; + if self.entry.is_none() { + return Err(Error::UnexpectedNull); + } + self.depth = 0; + Ok(EntriesTreeNode::new(self, 1)) + } + + /// Move the cursor to the next entry at the specified depth. + /// + /// Requires `depth <= self.depth + 1`. + /// + /// Returns `true` if successful. + fn next(&mut self, depth: isize) -> Result { + if self.depth < depth { + debug_assert_eq!(self.depth + 1, depth); + + match self.entry { + Some(ref entry) => { + if !entry.has_children() { + return Ok(false); + } + self.depth += 1; + self.input = entry.after_attrs()?; + } + None => return Ok(false), + } + + if self.input.is_empty() { + self.entry = None; + return Ok(false); + } + + return match DebuggingInformationEntry::parse( + &mut self.input, + self.unit, + self.abbreviations, + ) { + Ok(entry) => { + self.entry = entry; + Ok(self.entry.is_some()) + } + Err(e) => { + self.input.empty(); + self.entry = None; + Err(e) + } + }; + } + + loop { + match self.entry { + Some(ref entry) => { + if entry.has_children() { + if let Some(sibling_input) = entry.sibling() { + // Fast path: this entry has a DW_AT_sibling + // attribute pointing to its sibling, so jump + // to it (which keeps us at the same depth). + self.input = sibling_input; + } else { + // This entry has children, so the next entry is + // down one level. + self.depth += 1; + self.input = entry.after_attrs()?; + } + } else { + // This entry has no children, so next entry is at same depth. + self.input = entry.after_attrs()?; + } + } + None => { + // This entry is a null, so next entry is up one level. + self.depth -= 1; + } + } + + if self.input.is_empty() { + self.entry = None; + return Ok(false); + } + + match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { + Ok(entry) => { + self.entry = entry; + if self.depth == depth { + return Ok(self.entry.is_some()); + } + } + Err(e) => { + self.input.empty(); + self.entry = None; + return Err(e); + } + } + } + } +} + +/// A node in the Debugging Information Entry tree. +/// +/// The root node of a tree can be obtained +/// via [`EntriesTree::root`](./struct.EntriesTree.html#method.root). +#[derive(Debug)] +pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> { + tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, + depth: isize, +} + +impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { + fn new( + tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, + depth: isize, + ) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { + debug_assert!(tree.entry.is_some()); + EntriesTreeNode { tree, depth } + } + + /// Returns the current entry in the tree. + pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> { + // We never create a node without an entry. + self.tree.entry.as_ref().unwrap() + } + + /// Create an iterator for the children of the current entry. + /// + /// The current entry can no longer be accessed after creating the + /// iterator. + pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { + EntriesTreeIter::new(self.tree, self.depth) + } +} + +/// An iterator that allows traversal of the children of an +/// `EntriesTreeNode`. +/// +/// The items returned by this iterator are also `EntriesTreeNode`s, +/// which allow recursive traversal of grandchildren, etc. +#[derive(Debug)] +pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> { + tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, + depth: isize, + empty: bool, +} + +impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { + fn new( + tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, + depth: isize, + ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { + EntriesTreeIter { + tree, + depth, + empty: false, + } + } + + /// Returns an `EntriesTreeNode` for the next child entry. + /// + /// Returns `None` if there are no more children. + pub fn next<'me>(&'me mut self) -> Result>> { + if self.empty { + Ok(None) + } else if self.tree.next(self.depth)? { + Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1))) + } else { + self.empty = true; + Ok(None) + } + } +} + +/// Parse a type unit header's unique type signature. Callers should handle +/// unique-ness checking. +fn parse_type_signature(input: &mut R) -> Result { + input.read_u64().map(DebugTypeSignature) +} + +/// Parse a type unit header's type offset. +fn parse_type_offset(input: &mut R, format: Format) -> Result> { + input.read_offset(format).map(UnitOffset) +} + +/// The `DebugTypes` struct represents the DWARF type information +/// found in the `.debug_types` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugTypes { + debug_types_section: R, +} + +impl<'input, Endian> DebugTypes> +where + Endian: Endianity, +{ + /// Construct a new `DebugTypes` instance from the data in the `.debug_types` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_types` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugTypes, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_types_section_somehow = || &buf; + /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_types_section, endian)) + } +} + +impl DebugTypes { + /// Create a `DebugTypes` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes + where + F: FnMut(&'a T) -> R, + { + borrow(&self.debug_types_section).into() + } +} + +impl Section for DebugTypes { + fn id() -> SectionId { + SectionId::DebugTypes + } + + fn reader(&self) -> &R { + &self.debug_types_section + } +} + +impl From for DebugTypes { + fn from(debug_types_section: R) -> Self { + DebugTypes { + debug_types_section, + } + } +} + +impl DebugTypes { + /// Iterate the type-units in this `.debug_types` section. + /// + /// ``` + /// use gimli::{DebugTypes, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_types_section_somehow = || &buf; + /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); + /// + /// let mut iter = debug_types.units(); + /// while let Some(unit) = iter.next().unwrap() { + /// println!("unit's length is {}", unit.unit_length()); + /// } + /// ``` + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn units(&self) -> DebugTypesUnitHeadersIter { + DebugTypesUnitHeadersIter { + input: self.debug_types_section.clone(), + offset: DebugTypesOffset(R::Offset::from_u8(0)), + } + } +} + +/// An iterator over the type-units of this `.debug_types` section. +/// +/// See the [documentation on +/// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for +/// more detail. +#[derive(Clone, Debug)] +pub struct DebugTypesUnitHeadersIter { + input: R, + offset: DebugTypesOffset, +} + +impl DebugTypesUnitHeadersIter { + /// Advance the iterator to the next type unit header. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + Ok(None) + } else { + let len = self.input.len(); + match parse_unit_header(&mut self.input, self.offset.into()) { + Ok(header) => { + self.offset.0 += len - self.input.len(); + Ok(Some(header)) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for DebugTypesUnitHeadersIter { + type Item = UnitHeader; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + DebugTypesUnitHeadersIter::next(self) + } +} + +#[cfg(test)] +// Tests require leb128::write. +#[cfg(feature = "write")] +mod tests { + use super::*; + use crate::constants; + use crate::constants::*; + use crate::endianity::{Endianity, LittleEndian}; + use crate::leb128; + use crate::read::abbrev::tests::AbbrevSectionMethods; + use crate::read::{ + Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, + }; + use crate::test_util::GimliSectionMethods; + use alloc::vec::Vec; + use core::cell::Cell; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + // Mixin methods for `Section` to help define binary test data. + + trait UnitSectionMethods { + fn unit(self, unit: &mut UnitHeader>) -> Self + where + E: Endianity; + fn die(self, code: u64, attr: F) -> Self + where + F: Fn(Section) -> Section; + fn die_null(self) -> Self; + fn attr_string(self, s: &str) -> Self; + fn attr_ref1(self, o: u8) -> Self; + fn offset(self, offset: usize, format: Format) -> Self; + } + + impl UnitSectionMethods for Section { + fn unit(self, unit: &mut UnitHeader>) -> Self + where + E: Endianity, + { + let size = self.size(); + let length = Label::new(); + let start = Label::new(); + let end = Label::new(); + + let section = match unit.format() { + Format::Dwarf32 => self.L32(&length), + Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length), + }; + + let section = match unit.version() { + 2..=4 => section + .mark(&start) + .L16(unit.version()) + .offset(unit.debug_abbrev_offset.0, unit.format()) + .D8(unit.address_size()), + 5 => section + .mark(&start) + .L16(unit.version()) + .D8(unit.type_().dw_ut().0) + .D8(unit.address_size()) + .offset(unit.debug_abbrev_offset.0, unit.format()), + _ => unreachable!(), + }; + + let section = match unit.type_() { + UnitType::Compilation | UnitType::Partial => { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + section + } + UnitType::Type { + type_signature, + type_offset, + } + | UnitType::SplitType { + type_signature, + type_offset, + } => { + if unit.version() == 5 { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + } else { + unit.unit_offset = DebugTypesOffset(size as usize).into(); + } + section + .L64(type_signature.0) + .offset(type_offset.0, unit.format()) + } + UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + section.L64(dwo_id.0) + } + }; + + let section = section.append_bytes(unit.entries_buf.slice()).mark(&end); + + unit.unit_length = (&end - &start) as usize; + length.set_const(unit.unit_length as u64); + + section + } + + fn die(self, code: u64, attr: F) -> Self + where + F: Fn(Section) -> Section, + { + let section = self.uleb(code); + attr(section) + } + + fn die_null(self) -> Self { + self.D8(0) + } + + fn attr_string(self, attr: &str) -> Self { + self.append_bytes(attr.as_bytes()).D8(0) + } + + fn attr_ref1(self, attr: u8) -> Self { + self.D8(attr) + } + + fn offset(self, offset: usize, format: Format) -> Self { + match format { + Format::Dwarf32 => self.L32(offset as u32), + Format::Dwarf64 => self.L64(offset as u64), + } + } + } + + /// Ensure that `UnitHeader` is covariant wrt R. + #[test] + fn test_unit_header_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: UnitHeader>, + ) -> UnitHeader> { + x + } + } + + #[test] + fn test_parse_debug_abbrev_offset_32() { + let section = Section::with_endian(Endian::Little).L32(0x0403_0201); + let buf = section.get_contents().unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_abbrev_offset(buf, Format::Dwarf32) { + Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_debug_abbrev_offset_32_incomplete() { + let buf = [0x01, 0x02]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_abbrev_offset(buf, Format::Dwarf32) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_debug_abbrev_offset_64() { + let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); + let buf = section.get_contents().unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_abbrev_offset(buf, Format::Dwarf64) { + Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_debug_abbrev_offset_64_incomplete() { + let buf = [0x01, 0x02]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_abbrev_offset(buf, Format::Dwarf64) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_debug_info_offset_32() { + let section = Section::with_endian(Endian::Little).L32(0x0403_0201); + let buf = section.get_contents().unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_info_offset(buf, Format::Dwarf32) { + Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_debug_info_offset_32_incomplete() { + let buf = [0x01, 0x02]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_info_offset(buf, Format::Dwarf32) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_debug_info_offset_64() { + let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); + let buf = section.get_contents().unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_info_offset(buf, Format::Dwarf64) { + Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_debug_info_offset_64_incomplete() { + let buf = [0x01, 0x02]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_debug_info_offset(buf, Format::Dwarf64) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_units() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let mut unit64 = UnitHeader { + encoding: Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + }, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let mut unit32 = UnitHeader { + encoding: Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut unit64) + .unit(&mut unit32); + let buf = section.get_contents().unwrap(); + + let debug_info = DebugInfo::new(&buf, LittleEndian); + let mut units = debug_info.units(); + + assert_eq!(units.next(), Ok(Some(unit64))); + assert_eq!(units.next(), Ok(Some(unit32))); + assert_eq!(units.next(), Ok(None)); + } + + #[test] + fn test_unit_version_unknown_version() { + let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnknownVersion(0xcdab)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + + let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnknownVersion(1)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_unit_version_incomplete() { + let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_partial_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Partial, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_partial_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Partial, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_skeleton_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_skeleton_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_split_compilation_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_split_compilation_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_type_offset_32_ok() { + let buf = [0x12, 0x34, 0x56, 0x78, 0x00]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_type_offset(rest, Format::Dwarf32) { + Ok(offset) => { + assert_eq!(rest.len(), 1); + assert_eq!(UnitOffset(0x7856_3412), offset); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_type_offset_64_ok() { + let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_type_offset(rest, Format::Dwarf64) { + Ok(offset) => { + assert_eq!(rest.len(), 1); + assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset); + } + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_parse_type_offset_incomplete() { + // Need at least 4 bytes. + let buf = [0xff, 0xff, 0xff]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_type_offset(rest, Format::Dwarf32) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_type_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugTypesOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_type_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugTypesOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_type_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_type_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_split_type_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitType { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_split_type_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitType { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + fn section_contents(f: F) -> Vec + where + F: Fn(Section) -> Section, + { + f(Section::with_endian(Endian::Little)) + .get_contents() + .unwrap() + } + + #[test] + fn test_attribute_value() { + let mut unit = test_parse_attribute_unit_default(); + let endian = unit.entries_buf.endian(); + + let block_data = &[1, 2, 3, 4]; + let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data)); + let block = EndianSlice::new(&buf, endian); + + let buf = section_contents(|s| s.L32(0x0102_0304)); + let data4 = EndianSlice::new(&buf, endian); + + let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708)); + let data8 = EndianSlice::new(&buf, endian); + + let tests = [ + ( + Format::Dwarf32, + 2, + constants::DW_AT_data_member_location, + constants::DW_FORM_block, + block, + AttributeValue::Block(EndianSlice::new(block_data, endian)), + AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))), + ), + ( + Format::Dwarf32, + 2, + constants::DW_AT_data_member_location, + constants::DW_FORM_data4, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), + ), + ( + Format::Dwarf64, + 2, + constants::DW_AT_data_member_location, + constants::DW_FORM_data4, + data4, + AttributeValue::Data4(0x0102_0304), + AttributeValue::Udata(0x0102_0304), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_data_member_location, + constants::DW_FORM_data4, + data4, + AttributeValue::Data4(0x0102_0304), + AttributeValue::Udata(0x0102_0304), + ), + ( + Format::Dwarf32, + 2, + constants::DW_AT_data_member_location, + constants::DW_FORM_data8, + data8, + AttributeValue::Data8(0x0102_0304_0506_0708), + AttributeValue::Udata(0x0102_0304_0506_0708), + ), + #[cfg(target_pointer_width = "64")] + ( + Format::Dwarf64, + 2, + constants::DW_AT_data_member_location, + constants::DW_FORM_data8, + data8, + AttributeValue::SecOffset(0x0102_0304_0506_0708), + AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), + ), + ( + Format::Dwarf64, + 4, + constants::DW_AT_data_member_location, + constants::DW_FORM_data8, + data8, + AttributeValue::Data8(0x0102_0304_0506_0708), + AttributeValue::Udata(0x0102_0304_0506_0708), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_location, + constants::DW_FORM_data4, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), + ), + #[cfg(target_pointer_width = "64")] + ( + Format::Dwarf64, + 4, + constants::DW_AT_location, + constants::DW_FORM_data8, + data8, + AttributeValue::SecOffset(0x0102_0304_0506_0708), + AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_str_offsets_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_stmt_list, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugLineRef(DebugLineOffset(0x0102_0304)), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_addr_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_rnglists_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)), + ), + ( + Format::Dwarf32, + 4, + constants::DW_AT_loclists_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)), + ), + ]; + + for test in tests.iter() { + let (format, version, name, form, mut input, expect_raw, expect_value) = *test; + unit.encoding.format = format; + unit.encoding.version = version; + let spec = AttributeSpecification::new(name, form, None); + let attribute = + parse_attribute(&mut input, unit.encoding(), spec).expect("Should parse attribute"); + assert_eq!(attribute.raw_value(), expect_raw); + assert_eq!(attribute.value(), expect_value); + } + } + + #[test] + fn test_attribute_udata_sdata_value() { + #[allow(clippy::type_complexity)] + let tests: &[( + AttributeValue>, + Option, + Option, + )] = &[ + (AttributeValue::Data1(1), Some(1), Some(1)), + ( + AttributeValue::Data1(u8::MAX), + Some(u64::from(u8::MAX)), + Some(-1), + ), + (AttributeValue::Data2(1), Some(1), Some(1)), + ( + AttributeValue::Data2(u16::MAX), + Some(u64::from(u16::MAX)), + Some(-1), + ), + (AttributeValue::Data4(1), Some(1), Some(1)), + ( + AttributeValue::Data4(u32::MAX), + Some(u64::from(u32::MAX)), + Some(-1), + ), + (AttributeValue::Data8(1), Some(1), Some(1)), + (AttributeValue::Data8(u64::MAX), Some(u64::MAX), Some(-1)), + (AttributeValue::Sdata(1), Some(1), Some(1)), + (AttributeValue::Sdata(-1), None, Some(-1)), + (AttributeValue::Udata(1), Some(1), Some(1)), + (AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None), + ]; + for test in tests.iter() { + let (value, expect_udata, expect_sdata) = *test; + let attribute = Attribute { + name: DW_AT_data_member_location, + value, + }; + assert_eq!(attribute.udata_value(), expect_udata); + assert_eq!(attribute.sdata_value(), expect_sdata); + } + } + + fn test_parse_attribute_unit( + address_size: u8, + format: Format, + endian: Endian, + ) -> UnitHeader> + where + Endian: Endianity, + { + let encoding = Encoding { + format, + version: 4, + address_size, + }; + UnitHeader::new( + encoding, + 7, + UnitType::Compilation, + DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), + EndianSlice::new(&[], endian), + ) + } + + fn test_parse_attribute_unit_default() -> UnitHeader> { + test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian) + } + + fn test_parse_attribute<'input, Endian>( + buf: &'input [u8], + len: usize, + unit: &UnitHeader>, + form: constants::DwForm, + value: AttributeValue>, + ) where + Endian: Endianity, + { + let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form, None); + + let expect = Attribute { + name: constants::DW_AT_low_pc, + value, + }; + + let rest = &mut EndianSlice::new(buf, Endian::default()); + match parse_attribute(rest, unit.encoding(), spec) { + Ok(attr) => { + assert_eq!(attr, expect); + assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default())); + if let Some(size) = spec.size(unit) { + assert_eq!(rest.len() + size, buf.len()); + } + } + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + }; + } + + #[test] + fn test_parse_attribute_addr() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_addr; + let value = AttributeValue::Addr(0x0403_0201); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addr8() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; + let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_addr; + let value = AttributeValue::Addr(0x0807_0605_0403_0201); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_block1() { + // Length of data (3), three bytes of data, two bytes of left over input. + let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_block1; + let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_block2() { + // Two byte length of data (2), two bytes of data, two bytes of left over input. + let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_block2; + let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_block4() { + // Four byte length of data (2), two bytes of data, no left over input. + let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_block4; + let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian)); + test_parse_attribute(&buf, 6, &unit, form, value); + } + + #[test] + fn test_parse_attribute_block() { + // LEB length of data (2, one byte), two bytes of data, no left over input. + let buf = [0x02, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_block; + let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian)); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_data1() { + let buf = [0x03]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_data1; + let value = AttributeValue::Data1(0x03); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_data2() { + let buf = [0x02, 0x01, 0x0]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_data2; + let value = AttributeValue::Data2(0x0102); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_data4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_data4; + let value = AttributeValue::Data4(0x0403_0201); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_data8() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_data8; + let value = AttributeValue::Data8(0x0807_0605_0403_0201); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_udata() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_udata; + let value = AttributeValue::Udata(4097); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_sdata() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::signed(&mut writable, -4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_sdata; + let value = AttributeValue::Sdata(-4097); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_exprloc() { + // LEB length of data (2, one byte), two bytes of data, one byte left over input. + let buf = [0x02, 0x99, 0x99, 0x11]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_exprloc; + let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian))); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_flag_true() { + let buf = [0x42]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_flag; + let value = AttributeValue::Flag(true); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_flag_false() { + let buf = [0x00]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_flag; + let value = AttributeValue::Flag(false); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_flag_present() { + let buf = [0x01, 0x02, 0x03, 0x04]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_flag_present; + let value = AttributeValue::Flag(true); + // DW_FORM_flag_present does not consume any bytes of the input stream. + test_parse_attribute(&buf, 0, &unit, form, value); + } + + #[test] + fn test_parse_attribute_sec_offset_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_sec_offset; + let value = AttributeValue::SecOffset(0x0403_0201); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_sec_offset_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_sec_offset; + let value = AttributeValue::SecOffset(0x0807_0605_0403_0201); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_ref1() { + let buf = [0x03]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref1; + let value = AttributeValue::UnitRef(UnitOffset(3)); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_ref2() { + let buf = [0x02, 0x01, 0x0]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref2; + let value = AttributeValue::UnitRef(UnitOffset(258)); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_ref4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref4; + let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_ref8() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref8; + let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_ref_sup4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref_sup4; + let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_ref_sup8() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref_sup8; + let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_refudata() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref_udata; + let value = AttributeValue::UnitRef(UnitOffset(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_refaddr_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_ref_addr; + let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_refaddr_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_ref_addr; + let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_refaddr_version2() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + unit.encoding.version = 2; + let form = constants::DW_FORM_ref_addr; + let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_refaddr8_version2() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); + unit.encoding.version = 2; + let form = constants::DW_FORM_ref_addr; + let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_gnu_ref_alt_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_GNU_ref_alt; + let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_gnu_ref_alt_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_GNU_ref_alt; + let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_refsig8() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_ref_sig8; + let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_string() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99]; + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_string; + let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian)); + test_parse_attribute(&buf, 6, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strp_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_strp; + let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_strp_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strp; + let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strp_sup_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_strp_sup; + let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_strp_sup_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strp_sup; + let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_gnu_strp_alt_32() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); + let form = constants::DW_FORM_GNU_strp_alt; + let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_attribute_gnu_strp_alt_64() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_GNU_strp_alt; + let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); + test_parse_attribute(&buf, 8, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_strx; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx1() { + let buf = [0x01, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx1; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01)); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx2() { + let buf = [0x01, 0x02, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx2; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201)); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx3() { + let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx3; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201)); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx4; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_addrx; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx1() { + let buf = [0x01, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx1; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01)); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx2() { + let buf = [0x01, 0x02, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx2; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201)); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx3() { + let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx3; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201)); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx4; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_loclistx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_loclistx; + let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_rnglistx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_rnglistx; + let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_indirect() { + let mut buf = [0; 100]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0.into()) + .expect("should write udata") + + leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_indirect; + let value = AttributeValue::Udata(9_999_999); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_indirect_implicit_const() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut buf = [0; 100]; + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, constants::DW_FORM_implicit_const.0.into()) + .expect("should write implicit_const"); + + let input = &mut EndianSlice::new(&buf, LittleEndian); + let spec = + AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_indirect, None); + assert_eq!( + parse_attribute(input, encoding, spec), + Err(Error::InvalidImplicitConst) + ); + } + + #[test] + fn test_attrs_iter() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let unit = UnitHeader::new( + encoding, + 7, + UnitType::Compilation, + DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), + EndianSlice::new(&[], LittleEndian), + ); + + let abbrev = Abbreviation::new( + 42, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_yes, + vec![ + AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), + AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), + AttributeSpecification::new( + constants::DW_AT_high_pc, + constants::DW_FORM_addr, + None, + ), + ] + .into(), + ); + + // "foo", 42, 1337, 4 dangling bytes of 0xaa where children would be + let buf = [ + 0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa, + 0xaa, 0xaa, + ]; + + let entry = DebuggingInformationEntry { + offset: UnitOffset(0), + attrs_slice: EndianSlice::new(&buf, LittleEndian), + attrs_len: Cell::new(None), + abbrev: &abbrev, + unit: &unit, + }; + + let mut attrs = AttrsIter { + input: EndianSlice::new(&buf, LittleEndian), + attributes: abbrev.attributes(), + entry: &entry, + }; + + match attrs.next() { + Ok(Some(attr)) => { + assert_eq!( + attr, + Attribute { + name: constants::DW_AT_name, + value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), + } + ); + } + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + + assert!(entry.attrs_len.get().is_none()); + + match attrs.next() { + Ok(Some(attr)) => { + assert_eq!( + attr, + Attribute { + name: constants::DW_AT_low_pc, + value: AttributeValue::Addr(0x2a), + } + ); + } + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + + assert!(entry.attrs_len.get().is_none()); + + match attrs.next() { + Ok(Some(attr)) => { + assert_eq!( + attr, + Attribute { + name: constants::DW_AT_high_pc, + value: AttributeValue::Addr(0x539), + } + ); + } + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + + assert!(entry.attrs_len.get().is_none()); + + assert!(attrs.next().expect("should parse next").is_none()); + assert!(entry.attrs_len.get().is_some()); + assert_eq!( + entry.attrs_len.get().expect("should have entry.attrs_len"), + buf.len() - 4 + ) + } + + #[test] + fn test_attrs_iter_incomplete() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let unit = UnitHeader::new( + encoding, + 7, + UnitType::Compilation, + DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), + EndianSlice::new(&[], LittleEndian), + ); + + let abbrev = Abbreviation::new( + 42, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_yes, + vec![ + AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), + AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), + AttributeSpecification::new( + constants::DW_AT_high_pc, + constants::DW_FORM_addr, + None, + ), + ] + .into(), + ); + + // "foo" + let buf = [0x66, 0x6f, 0x6f, 0x00]; + + let entry = DebuggingInformationEntry { + offset: UnitOffset(0), + attrs_slice: EndianSlice::new(&buf, LittleEndian), + attrs_len: Cell::new(None), + abbrev: &abbrev, + unit: &unit, + }; + + let mut attrs = AttrsIter { + input: EndianSlice::new(&buf, LittleEndian), + attributes: abbrev.attributes(), + entry: &entry, + }; + + match attrs.next() { + Ok(Some(attr)) => { + assert_eq!( + attr, + Attribute { + name: constants::DW_AT_name, + value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), + } + ); + } + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + + assert!(entry.attrs_len.get().is_none()); + + // Return error for incomplete attribute. + assert!(attrs.next().is_err()); + assert!(entry.attrs_len.get().is_none()); + + // Return error for all subsequent calls. + assert!(attrs.next().is_err()); + assert!(attrs.next().is_err()); + assert!(attrs.next().is_err()); + assert!(attrs.next().is_err()); + assert!(entry.attrs_len.get().is_none()); + } + + fn assert_entry_name( + entry: &DebuggingInformationEntry<'_, '_, EndianSlice<'_, Endian>>, + name: &str, + ) where + Endian: Endianity, + { + let value = entry + .attr_value(constants::DW_AT_name) + .expect("Should have parsed the name attribute") + .expect("Should have found the name attribute"); + + assert_eq!( + value, + AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default())) + ); + } + + fn assert_current_name( + cursor: &EntriesCursor<'_, '_, EndianSlice<'_, Endian>>, + name: &str, + ) where + Endian: Endianity, + { + let entry = cursor.current().expect("Should have an entry result"); + assert_entry_name(entry, name); + } + + fn assert_next_entry( + cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>, + name: &str, + ) where + Endian: Endianity, + { + cursor + .next_entry() + .expect("Should parse next entry") + .expect("Should have an entry"); + assert_current_name(cursor, name); + } + + fn assert_next_entry_null(cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>) + where + Endian: Endianity, + { + cursor + .next_entry() + .expect("Should parse next entry") + .expect("Should have an entry"); + assert!(cursor.current().is_none()); + } + + fn assert_next_dfs( + cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>, + name: &str, + depth: isize, + ) where + Endian: Endianity, + { + { + let (val, entry) = cursor + .next_dfs() + .expect("Should parse next dfs") + .expect("Should not be done with traversal"); + assert_eq!(val, depth); + assert_entry_name(entry, name); + } + assert_current_name(cursor, name); + } + + fn assert_next_sibling( + cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>, + name: &str, + ) where + Endian: Endianity, + { + { + let entry = cursor + .next_sibling() + .expect("Should parse next sibling") + .expect("Should not be done with traversal"); + assert_entry_name(entry, name); + } + assert_current_name(cursor, name); + } + + fn assert_valid_sibling_ptr(cursor: &EntriesCursor<'_, '_, EndianSlice<'_, Endian>>) + where + Endian: Endianity, + { + let sibling_ptr = cursor + .current() + .expect("Should have current entry") + .attr_value(constants::DW_AT_sibling); + match sibling_ptr { + Ok(Some(AttributeValue::UnitRef(offset))) => { + cursor + .unit + .range_from(offset..) + .expect("Sibling offset should be valid"); + } + _ => panic!("Invalid sibling pointer {:?}", sibling_ptr), + } + } + + fn entries_cursor_tests_abbrev_buf() -> Vec { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev_null(); + section.get_contents().unwrap() + } + + fn entries_cursor_tests_debug_info_buf() -> Vec { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .die(1, |s| s.attr_string("001")) + .die(1, |s| s.attr_string("002")) + .die(1, |s| s.attr_string("003")) + .die_null() + .die_null() + .die(1, |s| s.attr_string("004")) + .die(1, |s| s.attr_string("005")) + .die_null() + .die(1, |s| s.attr_string("006")) + .die_null() + .die_null() + .die(1, |s| s.attr_string("007")) + .die(1, |s| s.attr_string("008")) + .die(1, |s| s.attr_string("009")) + .die_null() + .die_null() + .die_null() + .die(1, |s| s.attr_string("010")) + .die_null() + .die_null(); + let entries_buf = section.get_contents().unwrap(); + + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), + }; + let section = Section::with_endian(Endian::Little).unit(&mut unit); + section.get_contents().unwrap() + } + + #[test] + fn test_cursor_next_entry_incomplete() { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .die(1, |s| s.attr_string("001")) + .die(1, |s| s.attr_string("002")) + .die(1, |s| s); + let entries_buf = section.get_contents().unwrap(); + + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), + }; + let section = Section::with_endian(Endian::Little).unit(&mut unit); + let info_buf = §ion.get_contents().unwrap(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + + assert_next_entry(&mut cursor, "001"); + assert_next_entry(&mut cursor, "002"); + + { + // Entry code is present, but none of the attributes. + cursor + .next_entry() + .expect("Should parse next entry") + .expect("Should have an entry"); + let entry = cursor.current().expect("Should have an entry result"); + assert!(entry.attrs().next().is_err()); + } + + assert!(cursor.next_entry().is_err()); + assert!(cursor.next_entry().is_err()); + } + + #[test] + fn test_cursor_next_entry() { + let info_buf = &entries_cursor_tests_debug_info_buf(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + + assert_next_entry(&mut cursor, "001"); + assert_next_entry(&mut cursor, "002"); + assert_next_entry(&mut cursor, "003"); + assert_next_entry_null(&mut cursor); + assert_next_entry_null(&mut cursor); + assert_next_entry(&mut cursor, "004"); + assert_next_entry(&mut cursor, "005"); + assert_next_entry_null(&mut cursor); + assert_next_entry(&mut cursor, "006"); + assert_next_entry_null(&mut cursor); + assert_next_entry_null(&mut cursor); + assert_next_entry(&mut cursor, "007"); + assert_next_entry(&mut cursor, "008"); + assert_next_entry(&mut cursor, "009"); + assert_next_entry_null(&mut cursor); + assert_next_entry_null(&mut cursor); + assert_next_entry_null(&mut cursor); + assert_next_entry(&mut cursor, "010"); + assert_next_entry_null(&mut cursor); + assert_next_entry_null(&mut cursor); + + assert!(cursor + .next_entry() + .expect("Should parse next entry") + .is_none()); + assert!(cursor.current().is_none()); + } + + #[test] + fn test_cursor_next_dfs() { + let info_buf = &entries_cursor_tests_debug_info_buf(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + + assert_next_dfs(&mut cursor, "001", 0); + assert_next_dfs(&mut cursor, "002", 1); + assert_next_dfs(&mut cursor, "003", 1); + assert_next_dfs(&mut cursor, "004", -1); + assert_next_dfs(&mut cursor, "005", 1); + assert_next_dfs(&mut cursor, "006", 0); + assert_next_dfs(&mut cursor, "007", -1); + assert_next_dfs(&mut cursor, "008", 1); + assert_next_dfs(&mut cursor, "009", 1); + assert_next_dfs(&mut cursor, "010", -2); + + assert!(cursor.next_dfs().expect("Should parse next dfs").is_none()); + assert!(cursor.current().is_none()); + } + + #[test] + fn test_cursor_next_sibling_no_sibling_ptr() { + let info_buf = &entries_cursor_tests_debug_info_buf(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + + assert_next_dfs(&mut cursor, "001", 0); + + // Down to the first child of the root entry. + + assert_next_dfs(&mut cursor, "002", 1); + + // Now iterate all children of the root via `next_sibling`. + + assert_next_sibling(&mut cursor, "004"); + assert_next_sibling(&mut cursor, "007"); + assert_next_sibling(&mut cursor, "010"); + + // There should be no more siblings. + + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor.current().is_none()); + } + + #[test] + fn test_cursor_next_sibling_continuation() { + let info_buf = &entries_cursor_tests_debug_info_buf(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + + assert_next_dfs(&mut cursor, "001", 0); + + // Down to the first child of the root entry. + + assert_next_dfs(&mut cursor, "002", 1); + + // Get the next sibling, then iterate its children + + assert_next_sibling(&mut cursor, "004"); + assert_next_dfs(&mut cursor, "005", 1); + assert_next_sibling(&mut cursor, "006"); + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + + // And we should be able to continue with the children of the root entry. + + assert_next_dfs(&mut cursor, "007", -1); + assert_next_sibling(&mut cursor, "010"); + + // There should be no more siblings. + + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor.current().is_none()); + } + + fn entries_cursor_sibling_abbrev_buf() -> Vec { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr(DW_AT_sibling, DW_FORM_ref1) + .abbrev_attr_null() + .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev_null(); + section.get_contents().unwrap() + } + + fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec { + let start = Label::new(); + let sibling004_ref = Label::new(); + let sibling004 = Label::new(); + let sibling009_ref = Label::new(); + let sibling009 = Label::new(); + + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .mark(&start) + .die(2, |s| s.attr_string("001")) + // Valid sibling attribute. + .die(1, |s| s.attr_string("002").D8(&sibling004_ref)) + // Invalid code to ensure the sibling attribute was used. + .die(10, |s| s.attr_string("003")) + .die_null() + .die_null() + .mark(&sibling004) + // Invalid sibling attribute. + .die(1, |s| s.attr_string("004").attr_ref1(255)) + .die(2, |s| s.attr_string("005")) + .die_null() + .die_null() + // Sibling attribute in child only. + .die(2, |s| s.attr_string("006")) + // Valid sibling attribute. + .die(1, |s| s.attr_string("007").D8(&sibling009_ref)) + // Invalid code to ensure the sibling attribute was used. + .die(10, |s| s.attr_string("008")) + .die_null() + .die_null() + .mark(&sibling009) + .die(2, |s| s.attr_string("009")) + .die_null() + .die_null() + // No sibling attribute. + .die(2, |s| s.attr_string("010")) + .die(2, |s| s.attr_string("011")) + .die_null() + .die_null() + .die_null(); + + let offset = header_size as u64 + (&sibling004 - &start) as u64; + sibling004_ref.set_const(offset); + + let offset = header_size as u64 + (&sibling009 - &start) as u64; + sibling009_ref.set_const(offset); + + section.get_contents().unwrap() + } + + fn test_cursor_next_sibling_with_ptr( + cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, LittleEndian>>, + ) { + assert_next_dfs(cursor, "001", 0); + + // Down to the first child of the root. + + assert_next_dfs(cursor, "002", 1); + + // Now iterate all children of the root via `next_sibling`. + + assert_valid_sibling_ptr(cursor); + assert_next_sibling(cursor, "004"); + assert_next_sibling(cursor, "006"); + assert_next_sibling(cursor, "010"); + + // There should be no more siblings. + + assert!(cursor + .next_sibling() + .expect("Should parse next sibling") + .is_none()); + assert!(cursor.current().is_none()); + } + + #[test] + fn test_debug_info_next_sibling_with_ptr() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), + }; + let header_size = unit.size_of_header(); + let entries_buf = entries_cursor_sibling_entries_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); + let section = Section::with_endian(Endian::Little).unit(&mut unit); + let info_buf = section.get_contents().unwrap(); + let debug_info = DebugInfo::new(&info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrev_buf = entries_cursor_sibling_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + test_cursor_next_sibling_with_ptr(&mut cursor); + } + + #[test] + fn test_debug_types_next_sibling_with_ptr() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0), + type_offset: UnitOffset(0), + }, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), + }; + let header_size = unit.size_of_header(); + let entries_buf = entries_cursor_sibling_entries_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); + let section = Section::with_endian(Endian::Little).unit(&mut unit); + let info_buf = section.get_contents().unwrap(); + let debug_types = DebugTypes::new(&info_buf, LittleEndian); + + let unit = debug_types + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrev_buf = entries_cursor_sibling_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit.entries(&abbrevs); + test_cursor_next_sibling_with_ptr(&mut cursor); + } + + #[test] + fn test_entries_at_offset() { + let info_buf = &entries_cursor_tests_debug_info_buf(); + let debug_info = DebugInfo::new(info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); + let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut cursor = unit + .entries_at_offset(&abbrevs, UnitOffset(unit.header_size())) + .unwrap(); + assert_next_entry(&mut cursor, "001"); + + let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0)); + match cursor { + Err(Error::OffsetOutOfBounds) => {} + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + } + + fn entries_tree_tests_debug_abbrevs_buf() -> Vec { + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev_null() + .get_contents() + .unwrap(); + section + } + + fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec, UnitOffset) { + let start = Label::new(); + let entry2 = Label::new(); + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .mark(&start) + .die(1, |s| s.attr_string("root")) + .die(1, |s| s.attr_string("1")) + .die(1, |s| s.attr_string("1a")) + .die_null() + .die(2, |s| s.attr_string("1b")) + .die_null() + .mark(&entry2) + .die(1, |s| s.attr_string("2")) + .die(1, |s| s.attr_string("2a")) + .die(1, |s| s.attr_string("2a1")) + .die_null() + .die_null() + .die(1, |s| s.attr_string("2b")) + .die(2, |s| s.attr_string("2b1")) + .die_null() + .die_null() + .die(1, |s| s.attr_string("3")) + .die(1, |s| s.attr_string("3a")) + .die(2, |s| s.attr_string("3a1")) + .die(2, |s| s.attr_string("3a2")) + .die_null() + .die(2, |s| s.attr_string("3b")) + .die_null() + .die(2, |s| s.attr_string("final")) + .die_null() + .get_contents() + .unwrap(); + let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize); + (section, entry2) + } + + #[test] + fn test_entries_tree() { + fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>( + node: Result< + Option>>, + >, + name: &str, + ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>> + where + Endian: Endianity, + { + let node = node + .expect("Should parse entry") + .expect("Should have entry"); + assert_entry_name(node.entry(), name); + node.children() + } + + fn assert_null( + node: Result>>>, + ) { + match node { + Ok(None) => {} + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + } + + let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf(); + let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); + + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), + }; + let header_size = unit.size_of_header(); + let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); + let info_buf = Section::with_endian(Endian::Little) + .unit(&mut unit) + .get_contents() + .unwrap(); + let debug_info = DebugInfo::new(&info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("Should parse unit") + .expect("and it should be some"); + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + let mut tree = unit + .entries_tree(&abbrevs, None) + .expect("Should have entries tree"); + + // Test we can restart iteration of the tree. + { + let mut iter = assert_entry(tree.root().map(Some), "root"); + assert_entry(iter.next(), "1"); + } + { + let mut iter = assert_entry(tree.root().map(Some), "root"); + assert_entry(iter.next(), "1"); + } + + let mut iter = assert_entry(tree.root().map(Some), "root"); + { + // Test iteration with children. + let mut iter = assert_entry(iter.next(), "1"); + { + // Test iteration with children flag, but no children. + let mut iter = assert_entry(iter.next(), "1a"); + assert_null(iter.next()); + assert_null(iter.next()); + } + { + // Test iteration without children flag. + let mut iter = assert_entry(iter.next(), "1b"); + assert_null(iter.next()); + assert_null(iter.next()); + } + assert_null(iter.next()); + assert_null(iter.next()); + } + { + // Test skipping over children. + let mut iter = assert_entry(iter.next(), "2"); + assert_entry(iter.next(), "2a"); + assert_entry(iter.next(), "2b"); + assert_null(iter.next()); + } + { + // Test skipping after partial iteration. + let mut iter = assert_entry(iter.next(), "3"); + { + let mut iter = assert_entry(iter.next(), "3a"); + assert_entry(iter.next(), "3a1"); + // Parent iter should be able to skip over "3a2". + } + assert_entry(iter.next(), "3b"); + assert_null(iter.next()); + } + assert_entry(iter.next(), "final"); + assert_null(iter.next()); + + // Test starting at an offset. + let mut tree = unit + .entries_tree(&abbrevs, Some(entry2)) + .expect("Should have entries tree"); + let mut iter = assert_entry(tree.root().map(Some), "2"); + assert_entry(iter.next(), "2a"); + assert_entry(iter.next(), "2b"); + assert_null(iter.next()); + } + + #[test] + fn test_entries_raw() { + fn assert_abbrev<'abbrev, Endian>( + entries: &mut EntriesRaw<'abbrev, '_, EndianSlice<'_, Endian>>, + tag: DwTag, + ) -> &'abbrev Abbreviation + where + Endian: Endianity, + { + let abbrev = entries + .read_abbreviation() + .expect("Should parse abbrev") + .expect("Should have abbrev"); + assert_eq!(abbrev.tag(), tag); + abbrev + } + + fn assert_null(entries: &mut EntriesRaw<'_, '_, EndianSlice<'_, Endian>>) + where + Endian: Endianity, + { + match entries.read_abbreviation() { + Ok(None) => {} + otherwise => { + panic!("Unexpected parse result = {:#?}", otherwise); + } + } + } + + fn assert_attr( + entries: &mut EntriesRaw<'_, '_, EndianSlice<'_, Endian>>, + spec: Option, + name: DwAt, + value: &str, + ) where + Endian: Endianity, + { + let spec = spec.expect("Should have attribute specification"); + let attr = entries + .read_attribute(spec) + .expect("Should parse attribute"); + assert_eq!(attr.name(), name); + assert_eq!( + attr.value(), + AttributeValue::String(EndianSlice::new(value.as_bytes(), Endian::default())) + ); + } + + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr(DW_AT_linkage_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev(2, DW_TAG_variable, DW_CHILDREN_no) + .abbrev_attr(DW_AT_name, DW_FORM_string) + .abbrev_attr_null() + .abbrev_null(); + let abbrevs_buf = section.get_contents().unwrap(); + let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); + + #[rustfmt::skip] + let section = Section::with_endian(Endian::Little) + .die(1, |s| s.attr_string("f1").attr_string("l1")) + .die(2, |s| s.attr_string("v1")) + .die(2, |s| s.attr_string("v2")) + .die(1, |s| s.attr_string("f2").attr_string("l2")) + .die_null() + .die_null(); + let entries_buf = section.get_contents().unwrap(); + + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), + }; + let section = Section::with_endian(Endian::Little).unit(&mut unit); + let info_buf = section.get_contents().unwrap(); + let debug_info = DebugInfo::new(&info_buf, LittleEndian); + + let unit = debug_info + .units() + .next() + .expect("should have a unit result") + .expect("and it should be ok"); + + let abbrevs = unit + .abbreviations(&debug_abbrev) + .expect("Should parse abbreviations"); + + let mut entries = unit + .entries_raw(&abbrevs, None) + .expect("Should have entries"); + + assert_eq!(entries.next_depth(), 0); + let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); + let mut attrs = abbrev.attributes().iter().copied(); + assert_attr(&mut entries, attrs.next(), DW_AT_name, "f1"); + assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l1"); + assert!(attrs.next().is_none()); + + assert_eq!(entries.next_depth(), 1); + let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); + let mut attrs = abbrev.attributes().iter().copied(); + assert_attr(&mut entries, attrs.next(), DW_AT_name, "v1"); + assert!(attrs.next().is_none()); + + assert_eq!(entries.next_depth(), 1); + let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); + let mut attrs = abbrev.attributes().iter().copied(); + assert_attr(&mut entries, attrs.next(), DW_AT_name, "v2"); + assert!(attrs.next().is_none()); + + assert_eq!(entries.next_depth(), 1); + let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); + let mut attrs = abbrev.attributes().iter().copied(); + assert_attr(&mut entries, attrs.next(), DW_AT_name, "f2"); + assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l2"); + assert!(attrs.next().is_none()); + + assert_eq!(entries.next_depth(), 2); + assert_null(&mut entries); + + assert_eq!(entries.next_depth(), 1); + assert_null(&mut entries); + + assert_eq!(entries.next_depth(), 0); + assert!(entries.is_empty()); + } + + #[test] + fn test_debug_info_offset() { + let padding = &[0; 10]; + let entries = &[0; 20]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(entries, LittleEndian), + }; + Section::with_endian(Endian::Little) + .append_bytes(padding) + .unit(&mut unit); + let offset = padding.len(); + let header_length = unit.size_of_header(); + let length = unit.length_including_self(); + assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None); + assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None); + assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None); + assert_eq!( + DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit), + None + ); + assert_eq!( + DebugInfoOffset(offset + header_length).to_unit_offset(&unit), + Some(UnitOffset(header_length)) + ); + assert_eq!( + DebugInfoOffset(offset + length - 1).to_unit_offset(&unit), + Some(UnitOffset(length - 1)) + ); + assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None); + assert_eq!( + UnitOffset(header_length).to_debug_info_offset(&unit), + Some(DebugInfoOffset(offset + header_length)) + ); + assert_eq!( + UnitOffset(length - 1).to_debug_info_offset(&unit), + Some(DebugInfoOffset(offset + length - 1)) + ); + } + + #[test] + fn test_debug_types_offset() { + let padding = &[0; 10]; + let entries = &[0; 20]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0), + type_offset: UnitOffset(0), + }, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(entries, LittleEndian), + }; + Section::with_endian(Endian::Little) + .append_bytes(padding) + .unit(&mut unit); + let offset = padding.len(); + let header_length = unit.size_of_header(); + let length = unit.length_including_self(); + assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None); + assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None); + assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None); + assert_eq!( + DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit), + None + ); + assert_eq!( + DebugTypesOffset(offset + header_length).to_unit_offset(&unit), + Some(UnitOffset(header_length)) + ); + assert_eq!( + DebugTypesOffset(offset + length - 1).to_unit_offset(&unit), + Some(UnitOffset(length - 1)) + ); + assert_eq!( + DebugTypesOffset(offset + length).to_unit_offset(&unit), + None + ); + assert_eq!( + UnitOffset(header_length).to_debug_types_offset(&unit), + Some(DebugTypesOffset(offset + header_length)) + ); + assert_eq!( + UnitOffset(length - 1).to_debug_types_offset(&unit), + Some(DebugTypesOffset(offset + length - 1)) + ); + } + + #[test] + fn test_length_including_self() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), + }; + unit.encoding.format = Format::Dwarf32; + assert_eq!(unit.length_including_self(), 4); + unit.encoding.format = Format::Dwarf64; + assert_eq!(unit.length_including_self(), 12); + unit.unit_length = 10; + assert_eq!(unit.length_including_self(), 22); + } + + #[test] + fn test_parse_type_unit_abbrevs() { + let types_buf = [ + // Type unit header + 0x25, 0x00, 0x00, 0x00, // 32-bit unit length = 37 + 0x04, 0x00, // Version 4 + 0x00, 0x00, 0x00, 0x00, // debug_abbrev_offset + 0x04, // Address size + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Type signature + 0x01, 0x02, 0x03, 0x04, // Type offset + // DIEs + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + 0x00, // End of children + 0x00, // End of children + 0x00, // End of children + ]; + let debug_types = DebugTypes::new(&types_buf, LittleEndian); + + let abbrev_buf = [ + // Code + 0x01, // DW_TAG_subprogram + 0x2e, // DW_CHILDREN_yes + 0x01, // Begin attributes + 0x03, // Attribute name = DW_AT_name + 0x08, // Attribute form = DW_FORM_string + 0x00, 0x00, // End attributes + 0x00, // Null terminator + ]; + + let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); + + let unit = get_some_type_unit(); + + let read_debug_abbrev_section_somehow = || &abbrev_buf; + let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); + let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); + } +} diff --git a/deps/crates/vendor/gimli/src/read/util.rs b/deps/crates/vendor/gimli/src/read/util.rs new file mode 100644 index 00000000000000..39adab321fe067 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/util.rs @@ -0,0 +1,265 @@ +#[cfg(feature = "read")] +use alloc::boxed::Box; +#[cfg(feature = "read")] +use alloc::vec::Vec; +use core::fmt; +use core::mem::MaybeUninit; +use core::ops; +use core::ptr; +use core::slice; + +mod sealed { + /// # Safety + /// Implementer must not modify the content in storage. + pub unsafe trait Sealed { + type Storage; + + fn new_storage() -> Self::Storage; + + fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> { + Err(CapacityFull) + } + } + + #[derive(Clone, Copy, Debug)] + pub struct CapacityFull; +} + +use sealed::*; + +/// Marker trait for types that can be used as backing storage when a growable array type is needed. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +pub trait ArrayLike: Sealed { + /// Type of the elements being stored. + type Item; + + #[doc(hidden)] + fn as_slice(storage: &Self::Storage) -> &[MaybeUninit]; + + #[doc(hidden)] + fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit]; +} + +// SAFETY: does not modify the content in storage. +unsafe impl Sealed for [T; N] { + type Storage = [MaybeUninit; N]; + + fn new_storage() -> Self::Storage { + // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. + unsafe { MaybeUninit::uninit().assume_init() } + } +} + +impl ArrayLike for [T; N] { + type Item = T; + + fn as_slice(storage: &Self::Storage) -> &[MaybeUninit] { + storage + } + + fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit] { + storage + } +} + +// SAFETY: does not modify the content in storage. +#[cfg(feature = "read")] +unsafe impl Sealed for Box<[T; N]> { + type Storage = Box<[MaybeUninit; N]>; + + fn new_storage() -> Self::Storage { + // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. + Box::new(unsafe { MaybeUninit::uninit().assume_init() }) + } +} + +#[cfg(feature = "read")] +impl ArrayLike for Box<[T; N]> { + type Item = T; + + fn as_slice(storage: &Self::Storage) -> &[MaybeUninit] { + &storage[..] + } + + fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit] { + &mut storage[..] + } +} + +#[cfg(feature = "read")] +unsafe impl Sealed for Vec { + type Storage = Box<[MaybeUninit]>; + + fn new_storage() -> Self::Storage { + Box::new([]) + } + + fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> { + let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into(); + vec.reserve(additional); + // SAFETY: This is a `Vec` of `MaybeUninit`. + unsafe { vec.set_len(vec.capacity()) }; + *storage = vec.into_boxed_slice(); + Ok(()) + } +} + +#[cfg(feature = "read")] +impl ArrayLike for Vec { + type Item = T; + + fn as_slice(storage: &Self::Storage) -> &[MaybeUninit] { + storage + } + + fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit] { + storage + } +} + +pub(crate) struct ArrayVec { + storage: A::Storage, + len: usize, +} + +impl ArrayVec { + pub fn new() -> Self { + Self { + storage: A::new_storage(), + len: 0, + } + } + + pub fn clear(&mut self) { + let ptr: *mut [A::Item] = &mut **self; + // Set length first so the type invariant is upheld even if `drop_in_place` panicks. + self.len = 0; + // SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length. + unsafe { ptr::drop_in_place(ptr) }; + } + + pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> { + let mut storage = A::as_mut_slice(&mut self.storage); + if self.len >= storage.len() { + A::grow(&mut self.storage, 1)?; + storage = A::as_mut_slice(&mut self.storage); + } + + storage[self.len] = MaybeUninit::new(value); + self.len += 1; + Ok(()) + } + + pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> { + assert!(index <= self.len); + + let mut storage = A::as_mut_slice(&mut self.storage); + if self.len >= storage.len() { + A::grow(&mut self.storage, 1)?; + storage = A::as_mut_slice(&mut self.storage); + } + + // SAFETY: storage[index] is filled later. + unsafe { + let p = storage.as_mut_ptr().add(index); + core::ptr::copy(p as *const _, p.add(1), self.len - index); + } + storage[index] = MaybeUninit::new(element); + self.len += 1; + Ok(()) + } + + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + self.len -= 1; + // SAFETY: this element is valid and we "forget" it by setting the length. + Some(unsafe { A::as_slice(&self.storage)[self.len].as_ptr().read() }) + } + } + + pub fn swap_remove(&mut self, index: usize) -> A::Item { + assert!(self.len > 0); + A::as_mut_slice(&mut self.storage).swap(index, self.len - 1); + self.pop().unwrap() + } +} + +#[cfg(feature = "read")] +impl ArrayVec> { + pub fn into_vec(mut self) -> Vec { + let len = core::mem::replace(&mut self.len, 0); + let storage = core::mem::replace(&mut self.storage, Box::new([])); + let slice = Box::leak(storage); + debug_assert!(len <= slice.len()); + // SAFETY: valid elements. + unsafe { Vec::from_raw_parts(slice.as_mut_ptr() as *mut T, len, slice.len()) } + } +} + +impl Drop for ArrayVec { + fn drop(&mut self) { + self.clear(); + } +} + +impl Default for ArrayVec { + fn default() -> Self { + Self::new() + } +} + +impl ops::Deref for ArrayVec { + type Target = [A::Item]; + + fn deref(&self) -> &[A::Item] { + let slice = &A::as_slice(&self.storage); + debug_assert!(self.len <= slice.len()); + // SAFETY: valid elements. + unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) } + } +} + +impl ops::DerefMut for ArrayVec { + fn deref_mut(&mut self) -> &mut [A::Item] { + let slice = &mut A::as_mut_slice(&mut self.storage); + debug_assert!(self.len <= slice.len()); + // SAFETY: valid elements. + unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) } + } +} + +impl Clone for ArrayVec +where + A::Item: Clone, +{ + fn clone(&self) -> Self { + let mut new = Self::default(); + for value in &**self { + new.try_push(value.clone()).unwrap(); + } + new + } +} + +impl PartialEq for ArrayVec +where + A::Item: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl Eq for ArrayVec where A::Item: Eq {} + +impl fmt::Debug for ArrayVec +where + A::Item: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} diff --git a/deps/crates/vendor/gimli/src/read/value.rs b/deps/crates/vendor/gimli/src/read/value.rs new file mode 100644 index 00000000000000..114736dbbed8f9 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/value.rs @@ -0,0 +1,1621 @@ +//! Definitions for values used in DWARF expressions. + +use crate::constants; +#[cfg(feature = "read")] +use crate::read::{AttributeValue, DebuggingInformationEntry}; +use crate::read::{Error, Reader, Result}; + +/// Convert a u64 to an i64, with sign extension if required. +/// +/// This is primarily used when needing to treat `Value::Generic` +/// as a signed value. +#[inline] +fn sign_extend(value: u64, mask: u64) -> i64 { + let value = (value & mask) as i64; + let sign = ((mask >> 1) + 1) as i64; + (value ^ sign).wrapping_sub(sign) +} + +#[inline] +fn mask_bit_size(addr_mask: u64) -> u32 { + 64 - addr_mask.leading_zeros() +} + +/// The type of an entry on the DWARF stack. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ValueType { + /// The generic type, which is address-sized and of unspecified sign, + /// as specified in the DWARF 5 standard, section 2.5.1. + /// This type is also used to represent address base types. + Generic, + /// Signed 8-bit integer type. + I8, + /// Unsigned 8-bit integer type. + U8, + /// Signed 16-bit integer type. + I16, + /// Unsigned 16-bit integer type. + U16, + /// Signed 32-bit integer type. + I32, + /// Unsigned 32-bit integer type. + U32, + /// Signed 64-bit integer type. + I64, + /// Unsigned 64-bit integer type. + U64, + /// 32-bit floating point type. + F32, + /// 64-bit floating point type. + F64, +} + +/// The value of an entry on the DWARF stack. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Value { + /// A generic value, which is address-sized and of unspecified sign. + Generic(u64), + /// A signed 8-bit integer value. + I8(i8), + /// An unsigned 8-bit integer value. + U8(u8), + /// A signed 16-bit integer value. + I16(i16), + /// An unsigned 16-bit integer value. + U16(u16), + /// A signed 32-bit integer value. + I32(i32), + /// An unsigned 32-bit integer value. + U32(u32), + /// A signed 64-bit integer value. + I64(i64), + /// An unsigned 64-bit integer value. + U64(u64), + /// A 32-bit floating point value. + F32(f32), + /// A 64-bit floating point value. + F64(f64), +} + +impl ValueType { + /// The size in bits of a value for this type. + pub fn bit_size(self, addr_mask: u64) -> u32 { + match self { + ValueType::Generic => mask_bit_size(addr_mask), + ValueType::I8 | ValueType::U8 => 8, + ValueType::I16 | ValueType::U16 => 16, + ValueType::I32 | ValueType::U32 | ValueType::F32 => 32, + ValueType::I64 | ValueType::U64 | ValueType::F64 => 64, + } + } + + /// Construct a `ValueType` from the attributes of a base type DIE. + pub fn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option { + Some(match (encoding, byte_size) { + (constants::DW_ATE_signed, 1) => ValueType::I8, + (constants::DW_ATE_signed, 2) => ValueType::I16, + (constants::DW_ATE_signed, 4) => ValueType::I32, + (constants::DW_ATE_signed, 8) => ValueType::I64, + (constants::DW_ATE_unsigned, 1) => ValueType::U8, + (constants::DW_ATE_unsigned, 2) => ValueType::U16, + (constants::DW_ATE_unsigned, 4) => ValueType::U32, + (constants::DW_ATE_unsigned, 8) => ValueType::U64, + (constants::DW_ATE_float, 4) => ValueType::F32, + (constants::DW_ATE_float, 8) => ValueType::F64, + _ => return None, + }) + } + + /// Construct a `ValueType` from a base type DIE. + #[cfg(feature = "read")] + pub fn from_entry( + entry: &DebuggingInformationEntry<'_, '_, R>, + ) -> Result> { + if entry.tag() != constants::DW_TAG_base_type { + return Ok(None); + } + let mut encoding = None; + let mut byte_size = None; + let mut endianity = constants::DW_END_default; + let mut attrs = entry.attrs(); + while let Some(attr) = attrs.next()? { + match attr.name() { + constants::DW_AT_byte_size => byte_size = attr.udata_value(), + constants::DW_AT_encoding => { + if let AttributeValue::Encoding(x) = attr.value() { + encoding = Some(x); + } + } + constants::DW_AT_endianity => { + if let AttributeValue::Endianity(x) = attr.value() { + endianity = x; + } + } + _ => {} + } + } + + if endianity != constants::DW_END_default { + // TODO: we could check if it matches the reader endianity, + // but normally it would use DW_END_default in that case. + return Ok(None); + } + + if let (Some(encoding), Some(byte_size)) = (encoding, byte_size) { + Ok(ValueType::from_encoding(encoding, byte_size)) + } else { + Ok(None) + } + } +} + +impl Value { + /// Return the `ValueType` corresponding to this `Value`. + pub fn value_type(&self) -> ValueType { + match *self { + Value::Generic(_) => ValueType::Generic, + Value::I8(_) => ValueType::I8, + Value::U8(_) => ValueType::U8, + Value::I16(_) => ValueType::I16, + Value::U16(_) => ValueType::U16, + Value::I32(_) => ValueType::I32, + Value::U32(_) => ValueType::U32, + Value::I64(_) => ValueType::I64, + Value::U64(_) => ValueType::U64, + Value::F32(_) => ValueType::F32, + Value::F64(_) => ValueType::F64, + } + } + + /// Read a `Value` with the given `value_type` from a `Reader`. + pub fn parse(value_type: ValueType, mut bytes: R) -> Result { + let value = match value_type { + ValueType::I8 => Value::I8(bytes.read_i8()?), + ValueType::U8 => Value::U8(bytes.read_u8()?), + ValueType::I16 => Value::I16(bytes.read_i16()?), + ValueType::U16 => Value::U16(bytes.read_u16()?), + ValueType::I32 => Value::I32(bytes.read_i32()?), + ValueType::U32 => Value::U32(bytes.read_u32()?), + ValueType::I64 => Value::I64(bytes.read_i64()?), + ValueType::U64 => Value::U64(bytes.read_u64()?), + ValueType::F32 => Value::F32(bytes.read_f32()?), + ValueType::F64 => Value::F64(bytes.read_f64()?), + _ => return Err(Error::UnsupportedTypeOperation), + }; + Ok(value) + } + + /// Convert a `Value` to a `u64`. + /// + /// The `ValueType` of `self` must be integral. + /// Values are sign extended if the source value is signed. + pub fn to_u64(self, addr_mask: u64) -> Result { + let value = match self { + Value::Generic(value) => value & addr_mask, + Value::I8(value) => value as u64, + Value::U8(value) => u64::from(value), + Value::I16(value) => value as u64, + Value::U16(value) => u64::from(value), + Value::I32(value) => value as u64, + Value::U32(value) => u64::from(value), + Value::I64(value) => value as u64, + Value::U64(value) => value, + _ => return Err(Error::IntegralTypeRequired), + }; + Ok(value) + } + + /// Create a `Value` with the given `value_type` from a `u64` value. + /// + /// The `value_type` may be integral or floating point. + /// The result is truncated if the `u64` value does + /// not fit the bounds of the `value_type`. + pub fn from_u64(value_type: ValueType, value: u64) -> Result { + let value = match value_type { + ValueType::Generic => Value::Generic(value), + ValueType::I8 => Value::I8(value as i8), + ValueType::U8 => Value::U8(value as u8), + ValueType::I16 => Value::I16(value as i16), + ValueType::U16 => Value::U16(value as u16), + ValueType::I32 => Value::I32(value as i32), + ValueType::U32 => Value::U32(value as u32), + ValueType::I64 => Value::I64(value as i64), + ValueType::U64 => Value::U64(value), + ValueType::F32 => Value::F32(value as f32), + ValueType::F64 => Value::F64(value as f64), + }; + Ok(value) + } + + /// Create a `Value` with the given `value_type` from a `f32` value. + /// + /// The `value_type` may be integral or floating point. + /// The result is not defined if the `f32` value does + /// not fit the bounds of the `value_type`. + fn from_f32(value_type: ValueType, value: f32) -> Result { + let value = match value_type { + ValueType::Generic => Value::Generic(value as u64), + ValueType::I8 => Value::I8(value as i8), + ValueType::U8 => Value::U8(value as u8), + ValueType::I16 => Value::I16(value as i16), + ValueType::U16 => Value::U16(value as u16), + ValueType::I32 => Value::I32(value as i32), + ValueType::U32 => Value::U32(value as u32), + ValueType::I64 => Value::I64(value as i64), + ValueType::U64 => Value::U64(value as u64), + ValueType::F32 => Value::F32(value), + ValueType::F64 => Value::F64(f64::from(value)), + }; + Ok(value) + } + + /// Create a `Value` with the given `value_type` from a `f64` value. + /// + /// The `value_type` may be integral or floating point. + /// The result is not defined if the `f64` value does + /// not fit the bounds of the `value_type`. + fn from_f64(value_type: ValueType, value: f64) -> Result { + let value = match value_type { + ValueType::Generic => Value::Generic(value as u64), + ValueType::I8 => Value::I8(value as i8), + ValueType::U8 => Value::U8(value as u8), + ValueType::I16 => Value::I16(value as i16), + ValueType::U16 => Value::U16(value as u16), + ValueType::I32 => Value::I32(value as i32), + ValueType::U32 => Value::U32(value as u32), + ValueType::I64 => Value::I64(value as i64), + ValueType::U64 => Value::U64(value as u64), + ValueType::F32 => Value::F32(value as f32), + ValueType::F64 => Value::F64(value), + }; + Ok(value) + } + + /// Convert a `Value` to the given `value_type`. + /// + /// When converting between integral types, the result is truncated + /// if the source value does not fit the bounds of the `value_type`. + /// When converting from floating point types, the result is not defined + /// if the source value does not fit the bounds of the `value_type`. + /// + /// This corresponds to the DWARF `DW_OP_convert` operation. + pub fn convert(self, value_type: ValueType, addr_mask: u64) -> Result { + match self { + Value::F32(value) => Value::from_f32(value_type, value), + Value::F64(value) => Value::from_f64(value_type, value), + _ => Value::from_u64(value_type, self.to_u64(addr_mask)?), + } + } + + /// Reinterpret the bits in a `Value` as the given `value_type`. + /// + /// The source and result value types must have equal sizes. + /// + /// This corresponds to the DWARF `DW_OP_reinterpret` operation. + pub fn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result { + if self.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) { + return Err(Error::TypeMismatch); + } + let bits = match self { + Value::Generic(value) => value, + Value::I8(value) => value as u64, + Value::U8(value) => u64::from(value), + Value::I16(value) => value as u64, + Value::U16(value) => u64::from(value), + Value::I32(value) => value as u64, + Value::U32(value) => u64::from(value), + Value::I64(value) => value as u64, + Value::U64(value) => value, + Value::F32(value) => u64::from(f32::to_bits(value)), + Value::F64(value) => f64::to_bits(value), + }; + let value = match value_type { + ValueType::Generic => Value::Generic(bits), + ValueType::I8 => Value::I8(bits as i8), + ValueType::U8 => Value::U8(bits as u8), + ValueType::I16 => Value::I16(bits as i16), + ValueType::U16 => Value::U16(bits as u16), + ValueType::I32 => Value::I32(bits as i32), + ValueType::U32 => Value::U32(bits as u32), + ValueType::I64 => Value::I64(bits as i64), + ValueType::U64 => Value::U64(bits), + ValueType::F32 => Value::F32(f32::from_bits(bits as u32)), + ValueType::F64 => Value::F64(f64::from_bits(bits)), + }; + Ok(value) + } + + /// Perform an absolute value operation. + /// + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_abs` operation. + pub fn abs(self, addr_mask: u64) -> Result { + // wrapping_abs() can be used because DWARF specifies that the result is undefined + // for negative minimal values. + let value = match self { + Value::Generic(value) => { + Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64) + } + Value::I8(value) => Value::I8(value.wrapping_abs()), + Value::I16(value) => Value::I16(value.wrapping_abs()), + Value::I32(value) => Value::I32(value.wrapping_abs()), + Value::I64(value) => Value::I64(value.wrapping_abs()), + // f32/f64::abs() is not available in libcore + Value::F32(value) => Value::F32(if value < 0. { -value } else { value }), + Value::F64(value) => Value::F64(if value < 0. { -value } else { value }), + Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self, + }; + Ok(value) + } + + /// Perform a negation operation. + /// + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_neg` operation. + pub fn neg(self, addr_mask: u64) -> Result { + // wrapping_neg() can be used because DWARF specifies that the result is undefined + // for negative minimal values. + let value = match self { + Value::Generic(value) => { + Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64) + } + Value::I8(value) => Value::I8(value.wrapping_neg()), + Value::I16(value) => Value::I16(value.wrapping_neg()), + Value::I32(value) => Value::I32(value.wrapping_neg()), + Value::I64(value) => Value::I64(value.wrapping_neg()), + Value::F32(value) => Value::F32(-value), + Value::F64(value) => Value::F64(-value), + // It's unclear if these should implicitly convert to a signed value. + // For now, we don't support them. + Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { + return Err(Error::UnsupportedTypeOperation); + } + }; + Ok(value) + } + + /// Perform an addition operation. + /// + /// This operation requires matching types. + /// + /// This corresponds to the DWARF `DW_OP_plus` operation. + pub fn add(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + Value::Generic(v1.wrapping_add(v2) & addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_add(v2)), + (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_add(v2)), + (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_add(v2)), + (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_add(v2)), + (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)), + (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)), + (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)), + (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)), + (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 + v2), + (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 + v2), + _ => return Err(Error::TypeMismatch), + }; + Ok(value) + } + + /// Perform a subtraction operation. + /// + /// This operation requires matching types. + /// + /// This corresponds to the DWARF `DW_OP_minus` operation. + pub fn sub(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + Value::Generic(v1.wrapping_sub(v2) & addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_sub(v2)), + (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_sub(v2)), + (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_sub(v2)), + (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_sub(v2)), + (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_sub(v2)), + (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_sub(v2)), + (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_sub(v2)), + (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_sub(v2)), + (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 - v2), + (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 - v2), + _ => return Err(Error::TypeMismatch), + }; + Ok(value) + } + + /// Perform a multiplication operation. + /// + /// This operation requires matching types. + /// + /// This corresponds to the DWARF `DW_OP_mul` operation. + pub fn mul(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + Value::Generic(v1.wrapping_mul(v2) & addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_mul(v2)), + (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_mul(v2)), + (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_mul(v2)), + (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_mul(v2)), + (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_mul(v2)), + (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_mul(v2)), + (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_mul(v2)), + (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_mul(v2)), + (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 * v2), + (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 * v2), + _ => return Err(Error::TypeMismatch), + }; + Ok(value) + } + + /// Perform a division operation. + /// + /// This operation requires matching types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_div` operation. + pub fn div(self, rhs: Value, addr_mask: u64) -> Result { + match rhs { + Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => { + return Err(Error::DivisionByZero); + } + Value::I8(0) + | Value::U8(0) + | Value::I16(0) + | Value::U16(0) + | Value::I32(0) + | Value::U32(0) + | Value::I64(0) + | Value::U64(0) => { + return Err(Error::DivisionByZero); + } + _ => {} + } + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + // Signed division + Value::Generic( + sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64, + ) + } + (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)), + (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)), + (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)), + (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)), + (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)), + (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)), + (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)), + (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)), + (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2), + (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2), + _ => return Err(Error::TypeMismatch), + }; + Ok(value) + } + + /// Perform a remainder operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as an unsigned value. + /// + /// This corresponds to the DWARF `DW_OP_mod` operation. + pub fn rem(self, rhs: Value, addr_mask: u64) -> Result { + match rhs { + Value::Generic(rhs) if (rhs & addr_mask) == 0 => { + return Err(Error::DivisionByZero); + } + Value::I8(0) + | Value::U8(0) + | Value::I16(0) + | Value::U16(0) + | Value::I32(0) + | Value::U32(0) + | Value::I64(0) + | Value::U64(0) => { + return Err(Error::DivisionByZero); + } + _ => {} + } + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + // Unsigned modulus + Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask)) + } + (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)), + (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)), + (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)), + (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)), + (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)), + (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)), + (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)), + (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)), + (Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired), + (Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired), + _ => return Err(Error::TypeMismatch), + }; + Ok(value) + } + + /// Perform a bitwise not operation. + /// + /// This operation requires matching integral types. + /// + /// This corresponds to the DWARF `DW_OP_not` operation. + pub fn not(self, addr_mask: u64) -> Result { + let value_type = self.value_type(); + let v = self.to_u64(addr_mask)?; + Value::from_u64(value_type, !v) + } + + /// Perform a bitwise and operation. + /// + /// This operation requires matching integral types. + /// + /// This corresponds to the DWARF `DW_OP_and` operation. + pub fn and(self, rhs: Value, addr_mask: u64) -> Result { + let value_type = self.value_type(); + if value_type != rhs.value_type() { + return Err(Error::TypeMismatch); + } + let v1 = self.to_u64(addr_mask)?; + let v2 = rhs.to_u64(addr_mask)?; + Value::from_u64(value_type, v1 & v2) + } + + /// Perform a bitwise or operation. + /// + /// This operation requires matching integral types. + /// + /// This corresponds to the DWARF `DW_OP_or` operation. + pub fn or(self, rhs: Value, addr_mask: u64) -> Result { + let value_type = self.value_type(); + if value_type != rhs.value_type() { + return Err(Error::TypeMismatch); + } + let v1 = self.to_u64(addr_mask)?; + let v2 = rhs.to_u64(addr_mask)?; + Value::from_u64(value_type, v1 | v2) + } + + /// Perform a bitwise exclusive-or operation. + /// + /// This operation requires matching integral types. + /// + /// This corresponds to the DWARF `DW_OP_xor` operation. + pub fn xor(self, rhs: Value, addr_mask: u64) -> Result { + let value_type = self.value_type(); + if value_type != rhs.value_type() { + return Err(Error::TypeMismatch); + } + let v1 = self.to_u64(addr_mask)?; + let v2 = rhs.to_u64(addr_mask)?; + Value::from_u64(value_type, v1 ^ v2) + } + + /// Convert value to bit length suitable for a shift operation. + /// + /// If the value is negative then an error is returned. + fn shift_length(self) -> Result { + let value = match self { + Value::Generic(value) => value, + Value::I8(value) if value >= 0 => value as u64, + Value::U8(value) => u64::from(value), + Value::I16(value) if value >= 0 => value as u64, + Value::U16(value) => u64::from(value), + Value::I32(value) if value >= 0 => value as u64, + Value::U32(value) => u64::from(value), + Value::I64(value) if value >= 0 => value as u64, + Value::U64(value) => value, + _ => return Err(Error::InvalidShiftExpression), + }; + Ok(value) + } + + /// Perform a shift left operation. + /// + /// This operation requires integral types. + /// If the shift length exceeds the type size, then 0 is returned. + /// If the shift length is negative then an error is returned. + /// + /// This corresponds to the DWARF `DW_OP_shl` operation. + pub fn shl(self, rhs: Value, addr_mask: u64) -> Result { + let v2 = rhs.shift_length()?; + let value = match self { + Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { + 0 + } else { + (v1 & addr_mask) << v2 + }), + Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }), + Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }), + Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }), + Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }), + Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }), + Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }), + Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }), + Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }), + _ => return Err(Error::IntegralTypeRequired), + }; + Ok(value) + } + + /// Perform a logical shift right operation. + /// + /// This operation requires an unsigned integral type for the value. + /// If the value type is `Generic`, then it is interpreted as an unsigned value. + /// + /// This operation requires an integral type for the shift length. + /// If the shift length exceeds the type size, then 0 is returned. + /// If the shift length is negative then an error is returned. + /// + /// This corresponds to the DWARF `DW_OP_shr` operation. + pub fn shr(self, rhs: Value, addr_mask: u64) -> Result { + let v2 = rhs.shift_length()?; + let value = match self { + Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { + 0 + } else { + (v1 & addr_mask) >> v2 + }), + Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }), + Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }), + Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }), + Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }), + // It's unclear if signed values should implicitly convert to an unsigned value. + // For now, we don't support them. + Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => { + return Err(Error::UnsupportedTypeOperation); + } + _ => return Err(Error::IntegralTypeRequired), + }; + Ok(value) + } + + /// Perform an arithmetic shift right operation. + /// + /// This operation requires a signed integral type for the value. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This operation requires an integral type for the shift length. + /// If the shift length exceeds the type size, then 0 is returned for positive values, + /// and -1 is returned for negative values. + /// If the shift length is negative then an error is returned. + /// + /// This corresponds to the DWARF `DW_OP_shra` operation. + pub fn shra(self, rhs: Value, addr_mask: u64) -> Result { + let v2 = rhs.shift_length()?; + let value = match self { + Value::Generic(v1) => { + let v1 = sign_extend(v1, addr_mask); + let value = if v2 >= u64::from(mask_bit_size(addr_mask)) { + if v1 < 0 { + !0 + } else { + 0 + } + } else { + (v1 >> v2) as u64 + }; + Value::Generic(value) + } + Value::I8(v1) => Value::I8(if v2 >= 8 { + if v1 < 0 { + !0 + } else { + 0 + } + } else { + v1 >> v2 + }), + Value::I16(v1) => Value::I16(if v2 >= 16 { + if v1 < 0 { + !0 + } else { + 0 + } + } else { + v1 >> v2 + }), + Value::I32(v1) => Value::I32(if v2 >= 32 { + if v1 < 0 { + !0 + } else { + 0 + } + } else { + v1 >> v2 + }), + Value::I64(v1) => Value::I64(if v2 >= 64 { + if v1 < 0 { + !0 + } else { + 0 + } + } else { + v1 >> v2 + }), + // It's unclear if unsigned values should implicitly convert to a signed value. + // For now, we don't support them. + Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { + return Err(Error::UnsupportedTypeOperation); + } + _ => return Err(Error::IntegralTypeRequired), + }; + Ok(value) + } + + /// Perform the `==` relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_eq` operation. + pub fn eq(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 == v2, + (Value::U8(v1), Value::U8(v2)) => v1 == v2, + (Value::I16(v1), Value::I16(v2)) => v1 == v2, + (Value::U16(v1), Value::U16(v2)) => v1 == v2, + (Value::I32(v1), Value::I32(v2)) => v1 == v2, + (Value::U32(v1), Value::U32(v2)) => v1 == v2, + (Value::I64(v1), Value::I64(v2)) => v1 == v2, + (Value::U64(v1), Value::U64(v2)) => v1 == v2, + (Value::F32(v1), Value::F32(v2)) => v1 == v2, + (Value::F64(v1), Value::F64(v2)) => v1 == v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } + + /// Perform the `>=` relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_ge` operation. + pub fn ge(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 >= v2, + (Value::U8(v1), Value::U8(v2)) => v1 >= v2, + (Value::I16(v1), Value::I16(v2)) => v1 >= v2, + (Value::U16(v1), Value::U16(v2)) => v1 >= v2, + (Value::I32(v1), Value::I32(v2)) => v1 >= v2, + (Value::U32(v1), Value::U32(v2)) => v1 >= v2, + (Value::I64(v1), Value::I64(v2)) => v1 >= v2, + (Value::U64(v1), Value::U64(v2)) => v1 >= v2, + (Value::F32(v1), Value::F32(v2)) => v1 >= v2, + (Value::F64(v1), Value::F64(v2)) => v1 >= v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } + + /// Perform the `>` relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_gt` operation. + pub fn gt(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 > v2, + (Value::U8(v1), Value::U8(v2)) => v1 > v2, + (Value::I16(v1), Value::I16(v2)) => v1 > v2, + (Value::U16(v1), Value::U16(v2)) => v1 > v2, + (Value::I32(v1), Value::I32(v2)) => v1 > v2, + (Value::U32(v1), Value::U32(v2)) => v1 > v2, + (Value::I64(v1), Value::I64(v2)) => v1 > v2, + (Value::U64(v1), Value::U64(v2)) => v1 > v2, + (Value::F32(v1), Value::F32(v2)) => v1 > v2, + (Value::F64(v1), Value::F64(v2)) => v1 > v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } + + /// Perform the `<= relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_le` operation. + pub fn le(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 <= v2, + (Value::U8(v1), Value::U8(v2)) => v1 <= v2, + (Value::I16(v1), Value::I16(v2)) => v1 <= v2, + (Value::U16(v1), Value::U16(v2)) => v1 <= v2, + (Value::I32(v1), Value::I32(v2)) => v1 <= v2, + (Value::U32(v1), Value::U32(v2)) => v1 <= v2, + (Value::I64(v1), Value::I64(v2)) => v1 <= v2, + (Value::U64(v1), Value::U64(v2)) => v1 <= v2, + (Value::F32(v1), Value::F32(v2)) => v1 <= v2, + (Value::F64(v1), Value::F64(v2)) => v1 <= v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } + + /// Perform the `< relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_lt` operation. + pub fn lt(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 < v2, + (Value::U8(v1), Value::U8(v2)) => v1 < v2, + (Value::I16(v1), Value::I16(v2)) => v1 < v2, + (Value::U16(v1), Value::U16(v2)) => v1 < v2, + (Value::I32(v1), Value::I32(v2)) => v1 < v2, + (Value::U32(v1), Value::U32(v2)) => v1 < v2, + (Value::I64(v1), Value::I64(v2)) => v1 < v2, + (Value::U64(v1), Value::U64(v2)) => v1 < v2, + (Value::F32(v1), Value::F32(v2)) => v1 < v2, + (Value::F64(v1), Value::F64(v2)) => v1 < v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } + + /// Perform the `!= relational operation. + /// + /// This operation requires matching integral types. + /// If the value type is `Generic`, then it is interpreted as a signed value. + /// + /// This corresponds to the DWARF `DW_OP_ne` operation. + pub fn ne(self, rhs: Value, addr_mask: u64) -> Result { + let value = match (self, rhs) { + (Value::Generic(v1), Value::Generic(v2)) => { + sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask) + } + (Value::I8(v1), Value::I8(v2)) => v1 != v2, + (Value::U8(v1), Value::U8(v2)) => v1 != v2, + (Value::I16(v1), Value::I16(v2)) => v1 != v2, + (Value::U16(v1), Value::U16(v2)) => v1 != v2, + (Value::I32(v1), Value::I32(v2)) => v1 != v2, + (Value::U32(v1), Value::U32(v2)) => v1 != v2, + (Value::I64(v1), Value::I64(v2)) => v1 != v2, + (Value::U64(v1), Value::U64(v2)) => v1 != v2, + (Value::F32(v1), Value::F32(v2)) => v1 != v2, + (Value::F64(v1), Value::F64(v2)) => v1 != v2, + _ => return Err(Error::TypeMismatch), + }; + Ok(Value::Generic(value as u64)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::{DebugAbbrevOffset, DebugInfoOffset, Encoding, Format}; + use crate::endianity::LittleEndian; + use crate::read::{ + Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader, + UnitOffset, UnitType, + }; + + #[test] + #[rustfmt::skip] + fn valuetype_from_encoding() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let unit = UnitHeader::new( + encoding, + 7, + UnitType::Compilation, + DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), + EndianSlice::new(&[], LittleEndian), + ); + + let abbrev = Abbreviation::new( + 42, + constants::DW_TAG_base_type, + constants::DW_CHILDREN_no, + vec![ + AttributeSpecification::new( + constants::DW_AT_byte_size, + constants::DW_FORM_udata, + None, + ), + AttributeSpecification::new( + constants::DW_AT_encoding, + constants::DW_FORM_udata, + None, + ), + AttributeSpecification::new( + constants::DW_AT_endianity, + constants::DW_FORM_udata, + None, + ), + ].into(), + ); + + for &(attrs, result) in &[ + ([0x01, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I8), + ([0x02, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I16), + ([0x04, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I32), + ([0x08, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I64), + ([0x01, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U8), + ([0x02, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U16), + ([0x04, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U32), + ([0x08, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U64), + ([0x04, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F32), + ([0x08, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F64), + ] { + let entry = DebuggingInformationEntry::new( + UnitOffset(0), + EndianSlice::new(&attrs, LittleEndian), + &abbrev, + &unit, + ); + assert_eq!(ValueType::from_entry(&entry), Ok(Some(result))); + } + + for attrs in &[ + [0x03, constants::DW_ATE_signed.0, constants::DW_END_default.0], + [0x02, constants::DW_ATE_signed.0, constants::DW_END_big.0], + ] { + let entry = DebuggingInformationEntry::new( + UnitOffset(0), + EndianSlice::new(attrs, LittleEndian), + &abbrev, + &unit, + ); + assert_eq!(ValueType::from_entry(&entry), Ok(None)); + } + } + + #[test] + fn value_convert() { + let addr_mask = !0 >> 32; + for &(v, t, result) in &[ + (Value::Generic(1), ValueType::I8, Ok(Value::I8(1))), + (Value::I8(1), ValueType::U8, Ok(Value::U8(1))), + (Value::U8(1), ValueType::I16, Ok(Value::I16(1))), + (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), + (Value::U16(1), ValueType::I32, Ok(Value::I32(1))), + (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), + (Value::U32(1), ValueType::F32, Ok(Value::F32(1.))), + (Value::F32(1.), ValueType::I64, Ok(Value::I64(1))), + (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), + (Value::U64(1), ValueType::F64, Ok(Value::F64(1.))), + (Value::F64(1.), ValueType::Generic, Ok(Value::Generic(1))), + ] { + assert_eq!(v.convert(t, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_reinterpret() { + let addr_mask = !0 >> 32; + for &(v, t, result) in &[ + // 8-bit + (Value::I8(-1), ValueType::U8, Ok(Value::U8(0xff))), + (Value::U8(0xff), ValueType::I8, Ok(Value::I8(-1))), + // 16-bit + (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), + (Value::U16(1), ValueType::I16, Ok(Value::I16(1))), + // 32-bit + (Value::Generic(1), ValueType::I32, Ok(Value::I32(1))), + (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), + (Value::U32(0x3f80_0000), ValueType::F32, Ok(Value::F32(1.0))), + (Value::F32(1.0), ValueType::Generic, Ok(Value::Generic(0x3f80_0000))), + // Type mismatches + (Value::Generic(1), ValueType::U8, Err(Error::TypeMismatch)), + (Value::U8(1), ValueType::U16, Err(Error::TypeMismatch)), + (Value::U16(1), ValueType::U32, Err(Error::TypeMismatch)), + (Value::U32(1), ValueType::U64, Err(Error::TypeMismatch)), + (Value::U64(1), ValueType::Generic, Err(Error::TypeMismatch)), + ] { + assert_eq!(v.reinterpret(t, addr_mask), result); + } + + let addr_mask = !0; + for &(v, t, result) in &[ + // 64-bit + (Value::Generic(1), ValueType::I64, Ok(Value::I64(1))), + (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), + (Value::U64(0x3ff0_0000_0000_0000), ValueType::F64, Ok(Value::F64(1.0))), + (Value::F64(1.0), ValueType::Generic, Ok(Value::Generic(0x3ff0_0000_0000_0000))), + ] { + assert_eq!(v.reinterpret(t, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_abs() { + let addr_mask = 0xffff_ffff; + for &(v, result) in &[ + (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), + (Value::I8(-1), Ok(Value::I8(1))), + (Value::U8(1), Ok(Value::U8(1))), + (Value::I16(-1), Ok(Value::I16(1))), + (Value::U16(1), Ok(Value::U16(1))), + (Value::I32(-1), Ok(Value::I32(1))), + (Value::U32(1), Ok(Value::U32(1))), + (Value::I64(-1), Ok(Value::I64(1))), + (Value::U64(1), Ok(Value::U64(1))), + (Value::F32(-1.), Ok(Value::F32(1.))), + (Value::F64(-1.), Ok(Value::F64(1.))), + ] { + assert_eq!(v.abs(addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_neg() { + let addr_mask = 0xffff_ffff; + for &(v, result) in &[ + (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), + (Value::I8(1), Ok(Value::I8(-1))), + (Value::U8(1), Err(Error::UnsupportedTypeOperation)), + (Value::I16(1), Ok(Value::I16(-1))), + (Value::U16(1), Err(Error::UnsupportedTypeOperation)), + (Value::I32(1), Ok(Value::I32(-1))), + (Value::U32(1), Err(Error::UnsupportedTypeOperation)), + (Value::I64(1), Ok(Value::I64(-1))), + (Value::U64(1), Err(Error::UnsupportedTypeOperation)), + (Value::F32(1.), Ok(Value::F32(-1.))), + (Value::F64(1.), Ok(Value::F64(-1.))), + ] { + assert_eq!(v.neg(addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_add() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(1), Value::Generic(2), Ok(Value::Generic(3))), + (Value::I8(-1), Value::I8(2), Ok(Value::I8(1))), + (Value::U8(1), Value::U8(2), Ok(Value::U8(3))), + (Value::I16(-1), Value::I16(2), Ok(Value::I16(1))), + (Value::U16(1), Value::U16(2), Ok(Value::U16(3))), + (Value::I32(-1), Value::I32(2), Ok(Value::I32(1))), + (Value::U32(1), Value::U32(2), Ok(Value::U32(3))), + (Value::I64(-1), Value::I64(2), Ok(Value::I64(1))), + (Value::U64(1), Value::U64(2), Ok(Value::U64(3))), + (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(1.))), + (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(1.))), + (Value::Generic(1), Value::U32(2), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.add(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_sub() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), + (Value::I8(-1), Value::I8(2), Ok(Value::I8(-3))), + (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), + (Value::I16(-1), Value::I16(2), Ok(Value::I16(-3))), + (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), + (Value::I32(-1), Value::I32(2), Ok(Value::I32(-3))), + (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), + (Value::I64(-1), Value::I64(2), Ok(Value::I64(-3))), + (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), + (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(-3.))), + (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(-3.))), + (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.sub(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_mul() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(2), Value::Generic(3), Ok(Value::Generic(6))), + (Value::I8(-2), Value::I8(3), Ok(Value::I8(-6))), + (Value::U8(2), Value::U8(3), Ok(Value::U8(6))), + (Value::I16(-2), Value::I16(3), Ok(Value::I16(-6))), + (Value::U16(2), Value::U16(3), Ok(Value::U16(6))), + (Value::I32(-2), Value::I32(3), Ok(Value::I32(-6))), + (Value::U32(2), Value::U32(3), Ok(Value::U32(6))), + (Value::I64(-2), Value::I64(3), Ok(Value::I64(-6))), + (Value::U64(2), Value::U64(3), Ok(Value::U64(6))), + (Value::F32(-2.), Value::F32(3.), Ok(Value::F32(-6.))), + (Value::F64(-2.), Value::F64(3.), Ok(Value::F64(-6.))), + (Value::Generic(2), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.mul(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_div() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(6), Value::Generic(3), Ok(Value::Generic(2))), + (Value::I8(-6), Value::I8(3), Ok(Value::I8(-2))), + (Value::U8(6), Value::U8(3), Ok(Value::U8(2))), + (Value::I16(-6), Value::I16(3), Ok(Value::I16(-2))), + (Value::U16(6), Value::U16(3), Ok(Value::U16(2))), + (Value::I32(-6), Value::I32(3), Ok(Value::I32(-2))), + (Value::U32(6), Value::U32(3), Ok(Value::U32(2))), + (Value::I64(-6), Value::I64(3), Ok(Value::I64(-2))), + (Value::U64(6), Value::U64(3), Ok(Value::U64(2))), + (Value::F32(-6.), Value::F32(3.), Ok(Value::F32(-2.))), + (Value::F64(-6.), Value::F64(3.), Ok(Value::F64(-2.))), + (Value::Generic(6), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.div(v2, addr_mask), result); + } + for &(v1, v2, result) in &[ + (Value::Generic(6), Value::Generic(0), Err(Error::DivisionByZero)), + (Value::I8(-6), Value::I8(0), Err(Error::DivisionByZero)), + (Value::U8(6), Value::U8(0), Err(Error::DivisionByZero)), + (Value::I16(-6), Value::I16(0), Err(Error::DivisionByZero)), + (Value::U16(6), Value::U16(0), Err(Error::DivisionByZero)), + (Value::I32(-6), Value::I32(0), Err(Error::DivisionByZero)), + (Value::U32(6), Value::U32(0), Err(Error::DivisionByZero)), + (Value::I64(-6), Value::I64(0), Err(Error::DivisionByZero)), + (Value::U64(6), Value::U64(0), Err(Error::DivisionByZero)), + (Value::F32(-6.), Value::F32(0.), Ok(Value::F32(-6. / 0.))), + (Value::F64(-6.), Value::F64(0.), Ok(Value::F64(-6. / 0.))), + ] { + assert_eq!(v1.div(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_rem() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), + (Value::I8(-3), Value::I8(2), Ok(Value::I8(-1))), + (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), + (Value::I16(-3), Value::I16(2), Ok(Value::I16(-1))), + (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), + (Value::I32(-3), Value::I32(2), Ok(Value::I32(-1))), + (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), + (Value::I64(-3), Value::I64(2), Ok(Value::I64(-1))), + (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), + (Value::F32(-3.), Value::F32(2.), Err(Error::IntegralTypeRequired)), + (Value::F64(-3.), Value::F64(2.), Err(Error::IntegralTypeRequired)), + (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.rem(v2, addr_mask), result); + } + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(0), Err(Error::DivisionByZero)), + (Value::I8(-3), Value::I8(0), Err(Error::DivisionByZero)), + (Value::U8(3), Value::U8(0), Err(Error::DivisionByZero)), + (Value::I16(-3), Value::I16(0), Err(Error::DivisionByZero)), + (Value::U16(3), Value::U16(0), Err(Error::DivisionByZero)), + (Value::I32(-3), Value::I32(0), Err(Error::DivisionByZero)), + (Value::U32(3), Value::U32(0), Err(Error::DivisionByZero)), + (Value::I64(-3), Value::I64(0), Err(Error::DivisionByZero)), + (Value::U64(3), Value::U64(0), Err(Error::DivisionByZero)), + ] { + assert_eq!(v1.rem(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_not() { + let addr_mask = 0xffff_ffff; + for &(v, result) in &[ + (Value::Generic(1), Ok(Value::Generic(!1))), + (Value::I8(1), Ok(Value::I8(!1))), + (Value::U8(1), Ok(Value::U8(!1))), + (Value::I16(1), Ok(Value::I16(!1))), + (Value::U16(1), Ok(Value::U16(!1))), + (Value::I32(1), Ok(Value::I32(!1))), + (Value::U32(1), Ok(Value::U32(!1))), + (Value::I64(1), Ok(Value::I64(!1))), + (Value::U64(1), Ok(Value::U64(!1))), + (Value::F32(1.), Err(Error::IntegralTypeRequired)), + (Value::F64(1.), Err(Error::IntegralTypeRequired)), + ] { + assert_eq!(v.not(addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_and() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(1))), + (Value::I8(3), Value::I8(5), Ok(Value::I8(1))), + (Value::U8(3), Value::U8(5), Ok(Value::U8(1))), + (Value::I16(3), Value::I16(5), Ok(Value::I16(1))), + (Value::U16(3), Value::U16(5), Ok(Value::U16(1))), + (Value::I32(3), Value::I32(5), Ok(Value::I32(1))), + (Value::U32(3), Value::U32(5), Ok(Value::U32(1))), + (Value::I64(3), Value::I64(5), Ok(Value::I64(1))), + (Value::U64(3), Value::U64(5), Ok(Value::U64(1))), + (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), + (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), + (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.and(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_or() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(7))), + (Value::I8(3), Value::I8(5), Ok(Value::I8(7))), + (Value::U8(3), Value::U8(5), Ok(Value::U8(7))), + (Value::I16(3), Value::I16(5), Ok(Value::I16(7))), + (Value::U16(3), Value::U16(5), Ok(Value::U16(7))), + (Value::I32(3), Value::I32(5), Ok(Value::I32(7))), + (Value::U32(3), Value::U32(5), Ok(Value::U32(7))), + (Value::I64(3), Value::I64(5), Ok(Value::I64(7))), + (Value::U64(3), Value::U64(5), Ok(Value::U64(7))), + (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), + (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), + (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.or(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_xor() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(6))), + (Value::I8(3), Value::I8(5), Ok(Value::I8(6))), + (Value::U8(3), Value::U8(5), Ok(Value::U8(6))), + (Value::I16(3), Value::I16(5), Ok(Value::I16(6))), + (Value::U16(3), Value::U16(5), Ok(Value::U16(6))), + (Value::I32(3), Value::I32(5), Ok(Value::I32(6))), + (Value::U32(3), Value::U32(5), Ok(Value::U32(6))), + (Value::I64(3), Value::I64(5), Ok(Value::I64(6))), + (Value::U64(3), Value::U64(5), Ok(Value::U64(6))), + (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), + (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), + (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.xor(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_shl() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + // One of each type + (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(96))), + (Value::I8(3), Value::U8(5), Ok(Value::I8(96))), + (Value::U8(3), Value::I8(5), Ok(Value::U8(96))), + (Value::I16(3), Value::U16(5), Ok(Value::I16(96))), + (Value::U16(3), Value::I16(5), Ok(Value::U16(96))), + (Value::I32(3), Value::U32(5), Ok(Value::I32(96))), + (Value::U32(3), Value::I32(5), Ok(Value::U32(96))), + (Value::I64(3), Value::U64(5), Ok(Value::I64(96))), + (Value::U64(3), Value::I64(5), Ok(Value::U64(96))), + (Value::F32(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), + (Value::F64(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), + // Invalid shifts + (Value::U8(3), Value::I8(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(3), Value::I16(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(3), Value::I32(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(3), Value::I64(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(3), Value::F32(5.), Err(Error::InvalidShiftExpression)), + (Value::U8(3), Value::F64(5.), Err(Error::InvalidShiftExpression)), + // Large shifts + (Value::Generic(3), Value::Generic(32), Ok(Value::Generic(0))), + (Value::I8(3), Value::U8(8), Ok(Value::I8(0))), + (Value::U8(3), Value::I8(9), Ok(Value::U8(0))), + (Value::I16(3), Value::U16(17), Ok(Value::I16(0))), + (Value::U16(3), Value::I16(16), Ok(Value::U16(0))), + (Value::I32(3), Value::U32(32), Ok(Value::I32(0))), + (Value::U32(3), Value::I32(33), Ok(Value::U32(0))), + (Value::I64(3), Value::U64(65), Ok(Value::I64(0))), + (Value::U64(3), Value::I64(64), Ok(Value::U64(0))), + ] { + assert_eq!(v1.shl(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_shr() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + // One of each type + (Value::Generic(96), Value::Generic(5), Ok(Value::Generic(3))), + (Value::I8(96), Value::U8(5), Err(Error::UnsupportedTypeOperation)), + (Value::U8(96), Value::I8(5), Ok(Value::U8(3))), + (Value::I16(96), Value::U16(5), Err(Error::UnsupportedTypeOperation)), + (Value::U16(96), Value::I16(5), Ok(Value::U16(3))), + (Value::I32(96), Value::U32(5), Err(Error::UnsupportedTypeOperation)), + (Value::U32(96), Value::I32(5), Ok(Value::U32(3))), + (Value::I64(96), Value::U64(5), Err(Error::UnsupportedTypeOperation)), + (Value::U64(96), Value::I64(5), Ok(Value::U64(3))), + (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), + (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), + // Invalid shifts + (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), + // Large shifts + (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), + (Value::U8(96), Value::I8(9), Ok(Value::U8(0))), + (Value::U16(96), Value::I16(16), Ok(Value::U16(0))), + (Value::U32(96), Value::I32(33), Ok(Value::U32(0))), + (Value::U64(96), Value::I64(64), Ok(Value::U64(0))), + ] { + assert_eq!(v1.shr(v2, addr_mask), result); + } + } + + #[test] + #[rustfmt::skip] + fn value_shra() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + // One of each type + (Value::Generic(u64::from(-96i32 as u32)), Value::Generic(5), Ok(Value::Generic(-3i64 as u64))), + (Value::I8(-96), Value::U8(5), Ok(Value::I8(-3))), + (Value::U8(96), Value::I8(5), Err(Error::UnsupportedTypeOperation)), + (Value::I16(-96), Value::U16(5), Ok(Value::I16(-3))), + (Value::U16(96), Value::I16(5), Err(Error::UnsupportedTypeOperation)), + (Value::I32(-96), Value::U32(5), Ok(Value::I32(-3))), + (Value::U32(96), Value::I32(5), Err(Error::UnsupportedTypeOperation)), + (Value::I64(-96), Value::U64(5), Ok(Value::I64(-3))), + (Value::U64(96), Value::I64(5), Err(Error::UnsupportedTypeOperation)), + (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), + (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), + // Invalid shifts + (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), + (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), + // Large shifts + (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), + (Value::I8(96), Value::U8(8), Ok(Value::I8(0))), + (Value::I8(-96), Value::U8(8), Ok(Value::I8(-1))), + (Value::I16(96), Value::U16(17), Ok(Value::I16(0))), + (Value::I16(-96), Value::U16(17), Ok(Value::I16(-1))), + (Value::I32(96), Value::U32(32), Ok(Value::I32(0))), + (Value::I32(-96), Value::U32(32), Ok(Value::I32(-1))), + (Value::I64(96), Value::U64(65), Ok(Value::I64(0))), + (Value::I64(-96), Value::U64(65), Ok(Value::I64(-1))), + ] { + assert_eq!(v1.shra(v2, addr_mask), result); + } + } + + #[test] + fn value_eq() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(1))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), + (Value::I8(3), Value::I8(3), Ok(Value::Generic(1))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), + (Value::U8(3), Value::U8(3), Ok(Value::Generic(1))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), + (Value::I16(3), Value::I16(3), Ok(Value::Generic(1))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), + (Value::U16(3), Value::U16(3), Ok(Value::Generic(1))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), + (Value::I32(3), Value::I32(3), Ok(Value::Generic(1))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), + (Value::U32(3), Value::U32(3), Ok(Value::Generic(1))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), + (Value::I64(3), Value::I64(3), Ok(Value::Generic(1))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), + (Value::U64(3), Value::U64(3), Ok(Value::Generic(1))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), + (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(1))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), + (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(1))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.eq(v2, addr_mask), result); + } + } + + #[test] + fn value_ne() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(0))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), + (Value::I8(3), Value::I8(3), Ok(Value::Generic(0))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), + (Value::U8(3), Value::U8(3), Ok(Value::Generic(0))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), + (Value::I16(3), Value::I16(3), Ok(Value::Generic(0))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), + (Value::U16(3), Value::U16(3), Ok(Value::Generic(0))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), + (Value::I32(3), Value::I32(3), Ok(Value::Generic(0))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), + (Value::U32(3), Value::U32(3), Ok(Value::Generic(0))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), + (Value::I64(3), Value::I64(3), Ok(Value::Generic(0))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), + (Value::U64(3), Value::U64(3), Ok(Value::Generic(0))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), + (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(0))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), + (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(0))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.ne(v2, addr_mask), result); + } + } + + #[test] + fn value_ge() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), + (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), + (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), + (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), + (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), + (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), + (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), + (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), + (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), + (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), + (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.ge(v2, addr_mask), result); + } + } + + #[test] + fn value_gt() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), + (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), + (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), + (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), + (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), + (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), + (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), + (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), + (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), + (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), + (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.gt(v2, addr_mask), result); + } + } + + #[test] + fn value_le() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), + (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), + (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), + (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), + (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), + (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), + (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), + (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), + (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), + (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), + (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.le(v2, addr_mask), result); + } + } + + #[test] + fn value_lt() { + let addr_mask = 0xffff_ffff; + for &(v1, v2, result) in &[ + (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), + (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), + (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), + (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), + (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), + (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), + (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), + (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), + (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), + (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), + (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), + (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), + (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), + (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), + (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), + (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), + (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), + (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), + (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), + (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), + (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), + (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), + (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), + ] { + assert_eq!(v1.lt(v2, addr_mask), result); + } + } +} diff --git a/deps/crates/vendor/gimli/src/test_util.rs b/deps/crates/vendor/gimli/src/test_util.rs new file mode 100644 index 00000000000000..706aaf934633f5 --- /dev/null +++ b/deps/crates/vendor/gimli/src/test_util.rs @@ -0,0 +1,53 @@ +#![allow(missing_docs)] + +use crate::Format; +use test_assembler::{Label, Section}; + +pub trait GimliSectionMethods { + fn sleb(self, val: i64) -> Self; + fn uleb(self, val: u64) -> Self; + fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self; + fn word(self, size: u8, val: u64) -> Self; + fn word_label(self, size: u8, val: &Label) -> Self; +} + +impl GimliSectionMethods for Section { + fn sleb(mut self, mut val: i64) -> Self { + while val & !0x3f != 0 && val | 0x3f != -1 { + self = self.D8(val as u8 | 0x80); + val >>= 7; + } + self.D8(val as u8 & 0x7f) + } + + fn uleb(mut self, mut val: u64) -> Self { + while val & !0x7f != 0 { + self = self.D8(val as u8 | 0x80); + val >>= 7; + } + self.D8(val as u8) + } + + fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self { + match format { + Format::Dwarf32 => self.D32(length).mark(start), + Format::Dwarf64 => self.D32(0xffff_ffff).D64(length).mark(start), + } + } + + fn word(self, size: u8, val: u64) -> Self { + match size { + 4 => self.D32(val as u32), + 8 => self.D64(val), + _ => panic!("unsupported word size"), + } + } + + fn word_label(self, size: u8, val: &Label) -> Self { + match size { + 4 => self.D32(val), + 8 => self.D64(val), + _ => panic!("unsupported word size"), + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/abbrev.rs b/deps/crates/vendor/gimli/src/write/abbrev.rs new file mode 100644 index 00000000000000..7cdfa969c4835b --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/abbrev.rs @@ -0,0 +1,188 @@ +use alloc::vec::Vec; +use indexmap::IndexSet; +use std::ops::{Deref, DerefMut}; + +use crate::common::{DebugAbbrevOffset, SectionId}; +use crate::constants; +use crate::write::{Result, Section, Writer}; + +/// A table of abbreviations that will be stored in a `.debug_abbrev` section. +// Requirements: +// - values are `Abbreviation` +// - insertion returns an abbreviation code for use in writing a DIE +// - inserting a duplicate returns the code of the existing value +#[derive(Debug, Default)] +pub(crate) struct AbbreviationTable { + abbrevs: IndexSet, +} + +impl AbbreviationTable { + /// Add an abbreviation to the table and return its code. + pub fn add(&mut self, abbrev: Abbreviation) -> u64 { + let (code, _) = self.abbrevs.insert_full(abbrev); + // Code must be non-zero + (code + 1) as u64 + } + + /// Write the abbreviation table to the `.debug_abbrev` section. + pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { + for (code, abbrev) in self.abbrevs.iter().enumerate() { + w.write_uleb128((code + 1) as u64)?; + abbrev.write(w)?; + } + // Null abbreviation code + w.write_u8(0) + } +} + +/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: +/// its tag type, whether it has children, and its set of attributes. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct Abbreviation { + tag: constants::DwTag, + has_children: bool, + attributes: Vec, +} + +impl Abbreviation { + /// Construct a new `Abbreviation`. + #[inline] + pub fn new( + tag: constants::DwTag, + has_children: bool, + attributes: Vec, + ) -> Abbreviation { + Abbreviation { + tag, + has_children, + attributes, + } + } + + /// Write the abbreviation to the `.debug_abbrev` section. + pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { + w.write_uleb128(self.tag.0.into())?; + w.write_u8(if self.has_children { + constants::DW_CHILDREN_yes.0 + } else { + constants::DW_CHILDREN_no.0 + })?; + for attr in &self.attributes { + attr.write(w)?; + } + // Null name and form + w.write_u8(0)?; + w.write_u8(0) + } +} + +/// The description of an attribute in an abbreviated type. +// TODO: support implicit const +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct AttributeSpecification { + name: constants::DwAt, + form: constants::DwForm, +} + +impl AttributeSpecification { + /// Construct a new `AttributeSpecification`. + #[inline] + pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification { + AttributeSpecification { name, form } + } + + /// Write the attribute specification to the `.debug_abbrev` section. + #[inline] + pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { + w.write_uleb128(self.name.0.into())?; + w.write_uleb128(self.form.0.into()) + } +} + +define_section!( + DebugAbbrev, + DebugAbbrevOffset, + "A writable `.debug_abbrev` section." +); + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::constants; + use crate::read; + use crate::write::EndianVec; + use crate::LittleEndian; + + #[test] + fn test_abbreviation_table() { + let mut abbrevs = AbbreviationTable::default(); + let abbrev1 = Abbreviation::new( + constants::DW_TAG_subprogram, + false, + vec![AttributeSpecification::new( + constants::DW_AT_name, + constants::DW_FORM_string, + )], + ); + let abbrev2 = Abbreviation::new( + constants::DW_TAG_compile_unit, + true, + vec![ + AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp), + AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2), + ], + ); + let code1 = abbrevs.add(abbrev1.clone()); + assert_eq!(code1, 1); + let code2 = abbrevs.add(abbrev2.clone()); + assert_eq!(code2, 2); + assert_eq!(abbrevs.add(abbrev1.clone()), code1); + assert_eq!(abbrevs.add(abbrev2.clone()), code2); + + let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian)); + let debug_abbrev_offset = debug_abbrev.offset(); + assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0)); + abbrevs.write(&mut debug_abbrev).unwrap(); + assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17)); + + let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian); + let read_abbrevs = read_debug_abbrev + .abbreviations(debug_abbrev_offset) + .unwrap(); + + let read_abbrev1 = read_abbrevs.get(code1).unwrap(); + assert_eq!(abbrev1.tag, read_abbrev1.tag()); + assert_eq!(abbrev1.has_children, read_abbrev1.has_children()); + assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len()); + assert_eq!( + abbrev1.attributes[0].name, + read_abbrev1.attributes()[0].name() + ); + assert_eq!( + abbrev1.attributes[0].form, + read_abbrev1.attributes()[0].form() + ); + + let read_abbrev2 = read_abbrevs.get(code2).unwrap(); + assert_eq!(abbrev2.tag, read_abbrev2.tag()); + assert_eq!(abbrev2.has_children, read_abbrev2.has_children()); + assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len()); + assert_eq!( + abbrev2.attributes[0].name, + read_abbrev2.attributes()[0].name() + ); + assert_eq!( + abbrev2.attributes[0].form, + read_abbrev2.attributes()[0].form() + ); + assert_eq!( + abbrev2.attributes[1].name, + read_abbrev2.attributes()[1].name() + ); + assert_eq!( + abbrev2.attributes[1].form, + read_abbrev2.attributes()[1].form() + ); + } +} diff --git a/deps/crates/vendor/gimli/src/write/cfi.rs b/deps/crates/vendor/gimli/src/write/cfi.rs new file mode 100644 index 00000000000000..8d0a5205ed19b1 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/cfi.rs @@ -0,0 +1,1070 @@ +use alloc::vec::Vec; +use indexmap::IndexSet; +use std::ops::{Deref, DerefMut}; + +use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId}; +use crate::constants; +use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer}; + +define_section!( + DebugFrame, + DebugFrameOffset, + "A writable `.debug_frame` section." +); + +define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section."); + +define_id!(CieId, "An identifier for a CIE in a `FrameTable`."); + +/// A table of frame description entries. +#[derive(Debug, Default)] +pub struct FrameTable { + /// Base id for CIEs. + base_id: BaseId, + /// The common information entries. + cies: IndexSet, + /// The frame description entries. + fdes: Vec<(CieId, FrameDescriptionEntry)>, +} + +impl FrameTable { + /// Add a CIE and return its id. + /// + /// If the CIE already exists, then return the id of the existing CIE. + pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId { + let (index, _) = self.cies.insert_full(cie); + CieId::new(self.base_id, index) + } + + /// The number of CIEs. + pub fn cie_count(&self) -> usize { + self.cies.len() + } + + /// Add a FDE. + /// + /// Does not check for duplicates. + /// + /// # Panics + /// + /// Panics if the CIE id is invalid. + pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) { + debug_assert_eq!(self.base_id, cie.base_id); + self.fdes.push((cie, fde)); + } + + /// The number of FDEs. + pub fn fde_count(&self) -> usize { + self.fdes.len() + } + + /// Write the frame table entries to the given `.debug_frame` section. + pub fn write_debug_frame(&self, w: &mut DebugFrame) -> Result<()> { + self.write(&mut w.0, false) + } + + /// Write the frame table entries to the given `.eh_frame` section. + pub fn write_eh_frame(&self, w: &mut EhFrame) -> Result<()> { + self.write(&mut w.0, true) + } + + fn write(&self, w: &mut W, eh_frame: bool) -> Result<()> { + let mut cie_offsets = vec![None; self.cies.len()]; + for (cie_id, fde) in &self.fdes { + let cie_index = cie_id.index; + let cie = self.cies.get_index(cie_index).unwrap(); + let cie_offset = match cie_offsets[cie_index] { + Some(offset) => offset, + None => { + // Only write CIEs as they are referenced. + let offset = cie.write(w, eh_frame)?; + cie_offsets[cie_index] = Some(offset); + offset + } + }; + + fde.write(w, eh_frame, cie_offset, cie)?; + } + // TODO: write length 0 terminator for eh_frame? + Ok(()) + } +} + +/// A common information entry. This contains information that is shared between FDEs. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CommonInformationEntry { + encoding: Encoding, + + /// A constant that is factored out of code offsets. + /// + /// This should be set to the minimum instruction length. + /// Writing a code offset that is not a multiple of this factor will generate an error. + code_alignment_factor: u8, + + /// A constant that is factored out of data offsets. + /// + /// This should be set to the minimum data alignment for the frame. + /// Writing a data offset that is not a multiple of this factor will generate an error. + data_alignment_factor: i8, + + /// The return address register. This might not correspond to an actual machine register. + return_address_register: Register, + + /// The address of the personality function and its encoding. + pub personality: Option<(constants::DwEhPe, Address)>, + + /// The encoding to use for the LSDA address in FDEs. + /// + /// If set then all FDEs which use this CIE must have a LSDA address. + pub lsda_encoding: Option, + + /// The encoding to use for addresses in FDEs. + pub fde_address_encoding: constants::DwEhPe, + + /// True for signal trampolines. + pub signal_trampoline: bool, + + /// The initial instructions upon entry to this function. + instructions: Vec, +} + +impl CommonInformationEntry { + /// Create a new common information entry. + /// + /// The encoding version must be a CFI version, not a DWARF version. + pub fn new( + encoding: Encoding, + code_alignment_factor: u8, + data_alignment_factor: i8, + return_address_register: Register, + ) -> Self { + CommonInformationEntry { + encoding, + code_alignment_factor, + data_alignment_factor, + return_address_register, + personality: None, + lsda_encoding: None, + fde_address_encoding: constants::DW_EH_PE_absptr, + signal_trampoline: false, + instructions: Vec::new(), + } + } + + /// Add an initial instruction. + pub fn add_instruction(&mut self, instruction: CallFrameInstruction) { + self.instructions.push(instruction); + } + + fn has_augmentation(&self) -> bool { + self.personality.is_some() + || self.lsda_encoding.is_some() + || self.signal_trampoline + || self.fde_address_encoding != constants::DW_EH_PE_absptr + } + + /// Returns the section offset of the CIE. + fn write(&self, w: &mut W, eh_frame: bool) -> Result { + let encoding = self.encoding; + let offset = w.len(); + + let length_offset = w.write_initial_length(encoding.format)?; + let length_base = w.len(); + + if eh_frame { + w.write_u32(0)?; + } else { + match encoding.format { + Format::Dwarf32 => w.write_u32(0xffff_ffff)?, + Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?, + } + } + + if eh_frame { + if encoding.version != 1 { + return Err(Error::UnsupportedVersion(encoding.version)); + }; + } else { + match encoding.version { + 1 | 3 | 4 => {} + _ => return Err(Error::UnsupportedVersion(encoding.version)), + }; + } + w.write_u8(encoding.version as u8)?; + + let augmentation = self.has_augmentation(); + if augmentation { + w.write_u8(b'z')?; + if self.lsda_encoding.is_some() { + w.write_u8(b'L')?; + } + if self.personality.is_some() { + w.write_u8(b'P')?; + } + if self.fde_address_encoding != constants::DW_EH_PE_absptr { + w.write_u8(b'R')?; + } + if self.signal_trampoline { + w.write_u8(b'S')?; + } + } + w.write_u8(0)?; + + if encoding.version >= 4 { + w.write_u8(encoding.address_size)?; + w.write_u8(0)?; // segment_selector_size + } + + w.write_uleb128(self.code_alignment_factor.into())?; + w.write_sleb128(self.data_alignment_factor.into())?; + + if !eh_frame && encoding.version == 1 { + let register = self.return_address_register.0 as u8; + if u16::from(register) != self.return_address_register.0 { + return Err(Error::ValueTooLarge); + } + w.write_u8(register)?; + } else { + w.write_uleb128(self.return_address_register.0.into())?; + } + + if augmentation { + let augmentation_length_offset = w.len(); + w.write_u8(0)?; + let augmentation_length_base = w.len(); + + if let Some(eh_pe) = self.lsda_encoding { + w.write_u8(eh_pe.0)?; + } + if let Some((eh_pe, address)) = self.personality { + w.write_u8(eh_pe.0)?; + w.write_eh_pointer(address, eh_pe, encoding.address_size)?; + } + if self.fde_address_encoding != constants::DW_EH_PE_absptr { + w.write_u8(self.fde_address_encoding.0)?; + } + + let augmentation_length = (w.len() - augmentation_length_base) as u64; + debug_assert!(augmentation_length < 0x80); + w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?; + } + + for instruction in &self.instructions { + instruction.write(w, encoding, self)?; + } + + write_nop( + w, + encoding.format.word_size() as usize + w.len() - length_base, + encoding.address_size, + )?; + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, encoding.format)?; + + Ok(offset) + } +} + +/// A frame description entry. There should be one FDE per function. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FrameDescriptionEntry { + /// The initial address of the function. + address: Address, + + /// The length in bytes of the function. + length: u32, + + /// The address of the LSDA. + pub lsda: Option
, + + /// The instructions for this function, ordered by offset. + instructions: Vec<(u32, CallFrameInstruction)>, +} + +impl FrameDescriptionEntry { + /// Create a new frame description entry for a function. + pub fn new(address: Address, length: u32) -> Self { + FrameDescriptionEntry { + address, + length, + lsda: None, + instructions: Vec::new(), + } + } + + /// Add an instruction. + /// + /// Instructions must be added in increasing order of offset, or writing will fail. + pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) { + debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset); + self.instructions.push((offset, instruction)); + } + + fn write( + &self, + w: &mut W, + eh_frame: bool, + cie_offset: usize, + cie: &CommonInformationEntry, + ) -> Result<()> { + let encoding = cie.encoding; + let length_offset = w.write_initial_length(encoding.format)?; + let length_base = w.len(); + + if eh_frame { + // .eh_frame uses a relative offset which doesn't need relocation. + w.write_udata((w.len() - cie_offset) as u64, 4)?; + } else { + w.write_offset( + cie_offset, + SectionId::DebugFrame, + encoding.format.word_size(), + )?; + } + + if cie.fde_address_encoding != constants::DW_EH_PE_absptr { + w.write_eh_pointer( + self.address, + cie.fde_address_encoding, + encoding.address_size, + )?; + w.write_eh_pointer_data( + self.length.into(), + cie.fde_address_encoding.format(), + encoding.address_size, + )?; + } else { + w.write_address(self.address, encoding.address_size)?; + w.write_udata(self.length.into(), encoding.address_size)?; + } + + if cie.has_augmentation() { + let augmentation_length_offset = w.len(); + w.write_u8(0)?; + let augmentation_length_base = w.len(); + + debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some()); + if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) { + w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?; + } + + let augmentation_length = (w.len() - augmentation_length_base) as u64; + debug_assert!(augmentation_length < 0x80); + w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?; + } + + let mut prev_offset = 0; + for (offset, instruction) in &self.instructions { + write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?; + prev_offset = *offset; + instruction.write(w, encoding, cie)?; + } + + write_nop( + w, + encoding.format.word_size() as usize + w.len() - length_base, + encoding.address_size, + )?; + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, encoding.format)?; + + Ok(()) + } +} + +/// An instruction in a frame description entry. +/// +/// This may be a CFA definition, a register rule, or some other directive. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum CallFrameInstruction { + /// Define the CFA rule to use the provided register and offset. + Cfa(Register, i32), + /// Update the CFA rule to use the provided register. The offset is unchanged. + CfaRegister(Register), + /// Update the CFA rule to use the provided offset. The register is unchanged. + CfaOffset(i32), + /// Define the CFA rule to use the provided expression. + CfaExpression(Expression), + + /// Restore the initial rule for the register. + Restore(Register), + /// The previous value of the register is not recoverable. + Undefined(Register), + /// The register has not been modified. + SameValue(Register), + /// The previous value of the register is saved at address CFA + offset. + Offset(Register, i32), + /// The previous value of the register is CFA + offset. + ValOffset(Register, i32), + /// The previous value of the register is stored in another register. + Register(Register, Register), + /// The previous value of the register is saved at address given by the expression. + Expression(Register, Expression), + /// The previous value of the register is given by the expression. + ValExpression(Register, Expression), + + /// Push all register rules onto a stack. + RememberState, + /// Pop all register rules off the stack. + RestoreState, + /// The size of the arguments that have been pushed onto the stack. + ArgsSize(u32), + + /// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register. + NegateRaState, +} + +impl CallFrameInstruction { + fn write( + &self, + w: &mut W, + encoding: Encoding, + cie: &CommonInformationEntry, + ) -> Result<()> { + match *self { + CallFrameInstruction::Cfa(register, offset) => { + if offset < 0 { + let offset = factored_data_offset(offset, cie.data_alignment_factor)?; + w.write_u8(constants::DW_CFA_def_cfa_sf.0)?; + w.write_uleb128(register.0.into())?; + w.write_sleb128(offset.into())?; + } else { + // Unfactored offset. + w.write_u8(constants::DW_CFA_def_cfa.0)?; + w.write_uleb128(register.0.into())?; + w.write_uleb128(offset as u64)?; + } + } + CallFrameInstruction::CfaRegister(register) => { + w.write_u8(constants::DW_CFA_def_cfa_register.0)?; + w.write_uleb128(register.0.into())?; + } + CallFrameInstruction::CfaOffset(offset) => { + if offset < 0 { + let offset = factored_data_offset(offset, cie.data_alignment_factor)?; + w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?; + w.write_sleb128(offset.into())?; + } else { + // Unfactored offset. + w.write_u8(constants::DW_CFA_def_cfa_offset.0)?; + w.write_uleb128(offset as u64)?; + } + } + CallFrameInstruction::CfaExpression(ref expression) => { + w.write_u8(constants::DW_CFA_def_cfa_expression.0)?; + w.write_uleb128(expression.size(encoding, None) as u64)?; + expression.write(w, None, encoding, None)?; + } + CallFrameInstruction::Restore(register) => { + if register.0 < 0x40 { + w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?; + } else { + w.write_u8(constants::DW_CFA_restore_extended.0)?; + w.write_uleb128(register.0.into())?; + } + } + CallFrameInstruction::Undefined(register) => { + w.write_u8(constants::DW_CFA_undefined.0)?; + w.write_uleb128(register.0.into())?; + } + CallFrameInstruction::SameValue(register) => { + w.write_u8(constants::DW_CFA_same_value.0)?; + w.write_uleb128(register.0.into())?; + } + CallFrameInstruction::Offset(register, offset) => { + let offset = factored_data_offset(offset, cie.data_alignment_factor)?; + if offset < 0 { + w.write_u8(constants::DW_CFA_offset_extended_sf.0)?; + w.write_uleb128(register.0.into())?; + w.write_sleb128(offset.into())?; + } else if register.0 < 0x40 { + w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?; + w.write_uleb128(offset as u64)?; + } else { + w.write_u8(constants::DW_CFA_offset_extended.0)?; + w.write_uleb128(register.0.into())?; + w.write_uleb128(offset as u64)?; + } + } + CallFrameInstruction::ValOffset(register, offset) => { + let offset = factored_data_offset(offset, cie.data_alignment_factor)?; + if offset < 0 { + w.write_u8(constants::DW_CFA_val_offset_sf.0)?; + w.write_uleb128(register.0.into())?; + w.write_sleb128(offset.into())?; + } else { + w.write_u8(constants::DW_CFA_val_offset.0)?; + w.write_uleb128(register.0.into())?; + w.write_uleb128(offset as u64)?; + } + } + CallFrameInstruction::Register(register1, register2) => { + w.write_u8(constants::DW_CFA_register.0)?; + w.write_uleb128(register1.0.into())?; + w.write_uleb128(register2.0.into())?; + } + CallFrameInstruction::Expression(register, ref expression) => { + w.write_u8(constants::DW_CFA_expression.0)?; + w.write_uleb128(register.0.into())?; + w.write_uleb128(expression.size(encoding, None) as u64)?; + expression.write(w, None, encoding, None)?; + } + CallFrameInstruction::ValExpression(register, ref expression) => { + w.write_u8(constants::DW_CFA_val_expression.0)?; + w.write_uleb128(register.0.into())?; + w.write_uleb128(expression.size(encoding, None) as u64)?; + expression.write(w, None, encoding, None)?; + } + CallFrameInstruction::RememberState => { + w.write_u8(constants::DW_CFA_remember_state.0)?; + } + CallFrameInstruction::RestoreState => { + w.write_u8(constants::DW_CFA_restore_state.0)?; + } + CallFrameInstruction::ArgsSize(size) => { + w.write_u8(constants::DW_CFA_GNU_args_size.0)?; + w.write_uleb128(size.into())?; + } + CallFrameInstruction::NegateRaState => { + w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?; + } + } + Ok(()) + } +} + +fn write_advance_loc( + w: &mut W, + code_alignment_factor: u8, + prev_offset: u32, + offset: u32, +) -> Result<()> { + if offset == prev_offset { + return Ok(()); + } + let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?; + if delta < 0x40 { + w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?; + } else if delta < 0x100 { + w.write_u8(constants::DW_CFA_advance_loc1.0)?; + w.write_u8(delta as u8)?; + } else if delta < 0x10000 { + w.write_u8(constants::DW_CFA_advance_loc2.0)?; + w.write_u16(delta as u16)?; + } else { + w.write_u8(constants::DW_CFA_advance_loc4.0)?; + w.write_u32(delta)?; + } + Ok(()) +} + +fn write_nop(w: &mut W, len: usize, align: u8) -> Result<()> { + debug_assert_eq!(align & (align - 1), 0); + let tail_len = (!len + 1) & (align as usize - 1); + for _ in 0..tail_len { + w.write_u8(constants::DW_CFA_nop.0)?; + } + Ok(()) +} + +fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result { + if offset < prev_offset { + return Err(Error::InvalidFrameCodeOffset(offset)); + } + let delta = offset - prev_offset; + let factor = u32::from(factor); + let factored_delta = delta / factor; + if delta != factored_delta * factor { + return Err(Error::InvalidFrameCodeOffset(offset)); + } + Ok(factored_delta) +} + +fn factored_data_offset(offset: i32, factor: i8) -> Result { + let factor = i32::from(factor); + let factored_offset = offset / factor; + if offset != factored_offset * factor { + return Err(Error::InvalidFrameDataOffset(offset)); + } + Ok(factored_offset) +} + +#[cfg(feature = "read")] +pub(crate) mod convert { + use super::*; + use crate::read::{self, Reader}; + use crate::write::{ConvertError, ConvertResult}; + use std::collections::{hash_map, HashMap}; + + impl FrameTable { + /// Create a frame table by reading the data in the given section. + /// + /// `convert_address` is a function to convert read addresses into the `Address` + /// type. For non-relocatable addresses, this function may simply return + /// `Address::Constant(address)`. For relocatable addresses, it is the caller's + /// responsibility to determine the symbol and addend corresponding to the address + /// and return `Address::Symbol { symbol, addend }`. + pub fn from( + frame: &Section, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult + where + R: Reader, + Section: read::UnwindSection, + Section::Offset: read::UnwindOffset, + { + let bases = read::BaseAddresses::default().set_eh_frame(0); + + let mut frame_table = FrameTable::default(); + + let mut cie_ids = HashMap::new(); + let mut entries = frame.entries(&bases); + while let Some(entry) = entries.next()? { + let partial = match entry { + read::CieOrFde::Cie(_) => continue, + read::CieOrFde::Fde(partial) => partial, + }; + + // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only + // stored a reference. + let from_fde = partial.parse(Section::cie_from_offset)?; + let from_cie = from_fde.cie(); + let cie_id = match cie_ids.entry(from_cie.offset()) { + hash_map::Entry::Occupied(o) => *o.get(), + hash_map::Entry::Vacant(e) => { + let cie = + CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?; + let cie_id = frame_table.add_cie(cie); + e.insert(cie_id); + cie_id + } + }; + let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?; + frame_table.add_fde(cie_id, fde); + } + + Ok(frame_table) + } + } + + impl CommonInformationEntry { + fn from( + from_cie: &read::CommonInformationEntry, + frame: &Section, + bases: &read::BaseAddresses, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult + where + R: Reader, + Section: read::UnwindSection, + Section::Offset: read::UnwindOffset, + { + let mut cie = CommonInformationEntry::new( + from_cie.encoding(), + from_cie.code_alignment_factor() as u8, + from_cie.data_alignment_factor() as i8, + from_cie.return_address_register(), + ); + + cie.personality = match from_cie.personality_with_encoding() { + // We treat these the same because the encoding already determines + // whether it is indirect. + Some((eh_pe, read::Pointer::Direct(p))) + | Some((eh_pe, read::Pointer::Indirect(p))) => { + let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; + Some((eh_pe, address)) + } + _ => None, + }; + cie.lsda_encoding = from_cie.lsda_encoding(); + cie.fde_address_encoding = from_cie + .fde_address_encoding() + .unwrap_or(constants::DW_EH_PE_absptr); + cie.signal_trampoline = from_cie.is_signal_trampoline(); + + let mut offset = 0; + let mut from_instructions = from_cie.instructions(frame, bases); + while let Some(from_instruction) = from_instructions.next()? { + if let Some(instruction) = CallFrameInstruction::from( + from_instruction, + from_cie, + frame, + convert_address, + &mut offset, + )? { + cie.instructions.push(instruction); + } + } + Ok(cie) + } + } + + impl FrameDescriptionEntry { + fn from( + from_fde: &read::FrameDescriptionEntry, + frame: &Section, + bases: &read::BaseAddresses, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult + where + R: Reader, + Section: read::UnwindSection, + Section::Offset: read::UnwindOffset, + { + let address = + convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?; + let length = from_fde.len() as u32; + let mut fde = FrameDescriptionEntry::new(address, length); + + match from_fde.lsda() { + // We treat these the same because the encoding already determines + // whether it is indirect. + Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => { + let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; + fde.lsda = Some(address); + } + None => {} + } + + let from_cie = from_fde.cie(); + let mut offset = 0; + let mut from_instructions = from_fde.instructions(frame, bases); + while let Some(from_instruction) = from_instructions.next()? { + if let Some(instruction) = CallFrameInstruction::from( + from_instruction, + from_cie, + frame, + convert_address, + &mut offset, + )? { + fde.instructions.push((offset, instruction)); + } + } + + Ok(fde) + } + } + + impl CallFrameInstruction { + fn from( + from_instruction: read::CallFrameInstruction, + from_cie: &read::CommonInformationEntry, + frame: &Section, + convert_address: &dyn Fn(u64) -> Option
, + offset: &mut u32, + ) -> ConvertResult> + where + R: Reader, + Section: read::UnwindSection, + { + let convert_expression = + |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address); + // TODO: validate integer type conversions + Ok(Some(match from_instruction { + read::CallFrameInstruction::SetLoc { .. } => { + return Err(ConvertError::UnsupportedCfiInstruction); + } + read::CallFrameInstruction::AdvanceLoc { delta } => { + *offset += delta * from_cie.code_alignment_factor() as u32; + return Ok(None); + } + read::CallFrameInstruction::DefCfa { register, offset } => { + CallFrameInstruction::Cfa(register, offset as i32) + } + read::CallFrameInstruction::DefCfaSf { + register, + factored_offset, + } => { + let offset = factored_offset * from_cie.data_alignment_factor(); + CallFrameInstruction::Cfa(register, offset as i32) + } + read::CallFrameInstruction::DefCfaRegister { register } => { + CallFrameInstruction::CfaRegister(register) + } + + read::CallFrameInstruction::DefCfaOffset { offset } => { + CallFrameInstruction::CfaOffset(offset as i32) + } + read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => { + let offset = factored_offset * from_cie.data_alignment_factor(); + CallFrameInstruction::CfaOffset(offset as i32) + } + read::CallFrameInstruction::DefCfaExpression { expression } => { + let expression = expression.get(frame)?; + CallFrameInstruction::CfaExpression(convert_expression(expression)?) + } + read::CallFrameInstruction::Undefined { register } => { + CallFrameInstruction::Undefined(register) + } + read::CallFrameInstruction::SameValue { register } => { + CallFrameInstruction::SameValue(register) + } + read::CallFrameInstruction::Offset { + register, + factored_offset, + } => { + let offset = factored_offset as i64 * from_cie.data_alignment_factor(); + CallFrameInstruction::Offset(register, offset as i32) + } + read::CallFrameInstruction::OffsetExtendedSf { + register, + factored_offset, + } => { + let offset = factored_offset * from_cie.data_alignment_factor(); + CallFrameInstruction::Offset(register, offset as i32) + } + read::CallFrameInstruction::ValOffset { + register, + factored_offset, + } => { + let offset = factored_offset as i64 * from_cie.data_alignment_factor(); + CallFrameInstruction::ValOffset(register, offset as i32) + } + read::CallFrameInstruction::ValOffsetSf { + register, + factored_offset, + } => { + let offset = factored_offset * from_cie.data_alignment_factor(); + CallFrameInstruction::ValOffset(register, offset as i32) + } + read::CallFrameInstruction::Register { + dest_register, + src_register, + } => CallFrameInstruction::Register(dest_register, src_register), + read::CallFrameInstruction::Expression { + register, + expression, + } => { + let expression = expression.get(frame)?; + CallFrameInstruction::Expression(register, convert_expression(expression)?) + } + read::CallFrameInstruction::ValExpression { + register, + expression, + } => { + let expression = expression.get(frame)?; + CallFrameInstruction::ValExpression(register, convert_expression(expression)?) + } + read::CallFrameInstruction::Restore { register } => { + CallFrameInstruction::Restore(register) + } + read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState, + read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState, + read::CallFrameInstruction::ArgsSize { size } => { + CallFrameInstruction::ArgsSize(size as u32) + } + read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState, + read::CallFrameInstruction::Nop => return Ok(None), + })) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::arch::X86_64; + use crate::read; + use crate::write::EndianVec; + use crate::{LittleEndian, Vendor}; + + #[test] + fn test_frame_table() { + for &version in &[1, 3, 4] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let mut frames = FrameTable::default(); + + let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); + let cie1_id = frames.add_cie(cie1.clone()); + assert_eq!(cie1_id, frames.add_cie(cie1.clone())); + + let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); + cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr); + cie2.personality = + Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234))); + cie2.signal_trampoline = true; + let cie2_id = frames.add_cie(cie2.clone()); + assert_ne!(cie1_id, cie2_id); + assert_eq!(cie2_id, frames.add_cie(cie2.clone())); + + let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); + frames.add_fde(cie1_id, fde1.clone()); + + let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20); + frames.add_fde(cie1_id, fde2.clone()); + + let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30); + fde3.lsda = Some(Address::Constant(0x3300)); + frames.add_fde(cie2_id, fde3.clone()); + + let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40); + fde4.lsda = Some(Address::Constant(0x4400)); + frames.add_fde(cie2_id, fde4.clone()); + + let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); + cie3.fde_address_encoding = + constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4; + cie3.lsda_encoding = + Some(constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4); + cie3.personality = Some(( + constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4, + Address::Constant(0x1235), + )); + cie3.signal_trampoline = true; + let cie3_id = frames.add_cie(cie3.clone()); + assert_ne!(cie2_id, cie3_id); + assert_eq!(cie3_id, frames.add_cie(cie3.clone())); + + let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50); + fde5.lsda = Some(Address::Constant(0x5500)); + frames.add_fde(cie3_id, fde5.clone()); + + // Test writing `.debug_frame`. + let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); + frames.write_debug_frame(&mut debug_frame).unwrap(); + + let mut read_debug_frame = + read::DebugFrame::new(debug_frame.slice(), LittleEndian); + read_debug_frame.set_address_size(address_size); + let convert_frames = FrameTable::from(&read_debug_frame, &|address| { + Some(Address::Constant(address)) + }) + .unwrap(); + assert_eq!(frames.cies, convert_frames.cies); + assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); + for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { + assert_eq!(a.1, b.1); + } + + if version == 1 { + // Test writing `.eh_frame`. + let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian)); + frames.write_eh_frame(&mut eh_frame).unwrap(); + + let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian); + read_eh_frame.set_address_size(address_size); + let convert_frames = FrameTable::from(&read_eh_frame, &|address| { + Some(Address::Constant(address)) + }) + .unwrap(); + assert_eq!(frames.cies, convert_frames.cies); + assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); + for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { + assert_eq!(a.1, b.1); + } + } + } + } + } + } + + #[test] + fn test_frame_instruction() { + let mut expression = Expression::new(); + expression.op_constu(0); + + let cie_instructions = [ + CallFrameInstruction::Cfa(X86_64::RSP, 8), + CallFrameInstruction::Offset(X86_64::RA, -8), + ]; + + let fde_instructions = [ + (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)), + (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)), + (2, CallFrameInstruction::CfaRegister(X86_64::RBP)), + (4, CallFrameInstruction::CfaOffset(8)), + (4, CallFrameInstruction::CfaOffset(0)), + (4, CallFrameInstruction::CfaOffset(-8)), + (6, CallFrameInstruction::CfaExpression(expression.clone())), + (8, CallFrameInstruction::Restore(Register(1))), + (8, CallFrameInstruction::Restore(Register(101))), + (10, CallFrameInstruction::Undefined(Register(2))), + (12, CallFrameInstruction::SameValue(Register(3))), + (14, CallFrameInstruction::Offset(Register(4), 16)), + (14, CallFrameInstruction::Offset(Register(104), 16)), + (16, CallFrameInstruction::ValOffset(Register(5), -24)), + (16, CallFrameInstruction::ValOffset(Register(5), 24)), + (18, CallFrameInstruction::Register(Register(6), Register(7))), + ( + 20, + CallFrameInstruction::Expression(Register(8), expression.clone()), + ), + ( + 22, + CallFrameInstruction::ValExpression(Register(9), expression.clone()), + ), + (24 + 0x80, CallFrameInstruction::RememberState), + (26 + 0x280, CallFrameInstruction::RestoreState), + (28 + 0x20280, CallFrameInstruction::ArgsSize(23)), + ]; + + let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)]; + + for &version in &[1, 3, 4] { + for &address_size in &[4, 8] { + for &vendor in &[Vendor::Default, Vendor::AArch64] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let mut frames = FrameTable::default(); + + let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA); + for i in &cie_instructions { + cie.add_instruction(i.clone()); + } + let cie_id = frames.add_cie(cie); + + let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); + for (o, i) in &fde_instructions { + fde.add_instruction(*o, i.clone()); + } + frames.add_fde(cie_id, fde); + + if vendor == Vendor::AArch64 { + let mut fde = + FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10); + for (o, i) in &fde_instructions_aarch64 { + fde.add_instruction(*o, i.clone()); + } + frames.add_fde(cie_id, fde); + } + + let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); + frames.write_debug_frame(&mut debug_frame).unwrap(); + + let mut read_debug_frame = + read::DebugFrame::new(debug_frame.slice(), LittleEndian); + read_debug_frame.set_address_size(address_size); + read_debug_frame.set_vendor(vendor); + let frames = FrameTable::from(&read_debug_frame, &|address| { + Some(Address::Constant(address)) + }) + .unwrap(); + + assert_eq!( + &frames.cies.get_index(0).unwrap().instructions, + &cie_instructions + ); + assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions); + if vendor == Vendor::AArch64 { + assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64); + } + } + } + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/dwarf.rs b/deps/crates/vendor/gimli/src/write/dwarf.rs new file mode 100644 index 00000000000000..ea507126a537f6 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/dwarf.rs @@ -0,0 +1,138 @@ +use alloc::vec::Vec; + +use crate::common::Encoding; +use crate::write::{ + AbbreviationTable, LineProgram, LineStringTable, Result, Sections, StringTable, Unit, + UnitTable, Writer, +}; + +/// Writable DWARF information for more than one unit. +#[derive(Debug, Default)] +pub struct Dwarf { + /// A table of units. These are primarily stored in the `.debug_info` section, + /// but they also contain information that is stored in other sections. + pub units: UnitTable, + + /// Extra line number programs that are not associated with a unit. + /// + /// These should only be used when generating DWARF5 line-only debug + /// information. + pub line_programs: Vec, + + /// A table of strings that will be stored in the `.debug_line_str` section. + pub line_strings: LineStringTable, + + /// A table of strings that will be stored in the `.debug_str` section. + pub strings: StringTable, +} + +impl Dwarf { + /// Create a new `Dwarf` instance. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Write the DWARF information to the given sections. + pub fn write(&mut self, sections: &mut Sections) -> Result<()> { + let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; + let strings = self.strings.write(&mut sections.debug_str)?; + self.units.write(sections, &line_strings, &strings)?; + for line_program in &self.line_programs { + line_program.write( + &mut sections.debug_line, + line_program.encoding(), + &line_strings, + &strings, + )?; + } + Ok(()) + } +} + +/// Writable DWARF information for a single unit. +#[derive(Debug)] +pub struct DwarfUnit { + /// A unit. This is primarily stored in the `.debug_info` section, + /// but also contains information that is stored in other sections. + pub unit: Unit, + + /// A table of strings that will be stored in the `.debug_line_str` section. + pub line_strings: LineStringTable, + + /// A table of strings that will be stored in the `.debug_str` section. + pub strings: StringTable, +} + +impl DwarfUnit { + /// Create a new `DwarfUnit`. + /// + /// Note: you should set `self.unit.line_program` after creation. + /// This cannot be done earlier because it may need to reference + /// `self.line_strings`. + pub fn new(encoding: Encoding) -> Self { + let unit = Unit::new(encoding, LineProgram::none()); + DwarfUnit { + unit, + line_strings: LineStringTable::default(), + strings: StringTable::default(), + } + } + + /// Write the DWARf information to the given sections. + pub fn write(&mut self, sections: &mut Sections) -> Result<()> { + let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; + let strings = self.strings.write(&mut sections.debug_str)?; + + let abbrev_offset = sections.debug_abbrev.offset(); + let mut abbrevs = AbbreviationTable::default(); + + self.unit.write( + sections, + abbrev_offset, + &mut abbrevs, + &line_strings, + &strings, + )?; + // None should exist because we didn't give out any UnitId. + assert!(sections.debug_info_refs.is_empty()); + assert!(sections.debug_loc_refs.is_empty()); + assert!(sections.debug_loclists_refs.is_empty()); + + abbrevs.write(&mut sections.debug_abbrev)?; + Ok(()) + } +} + +#[cfg(feature = "read")] +pub(crate) mod convert { + use super::*; + use crate::read::{self, Reader}; + use crate::write::{Address, ConvertResult}; + + impl Dwarf { + /// Create a `write::Dwarf` by converting a `read::Dwarf`. + /// + /// `convert_address` is a function to convert read addresses into the `Address` + /// type. For non-relocatable addresses, this function may simply return + /// `Address::Constant(address)`. For relocatable addresses, it is the caller's + /// responsibility to determine the symbol and addend corresponding to the address + /// and return `Address::Symbol { symbol, addend }`. + pub fn from>( + dwarf: &read::Dwarf, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult { + let mut line_strings = LineStringTable::default(); + let mut strings = StringTable::default(); + let units = UnitTable::from(dwarf, &mut line_strings, &mut strings, convert_address)?; + // TODO: convert the line programs that were not referenced by a unit. + let line_programs = Vec::new(); + Ok(Dwarf { + units, + line_programs, + line_strings, + strings, + }) + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/endian_vec.rs b/deps/crates/vendor/gimli/src/write/endian_vec.rs new file mode 100644 index 00000000000000..7b040606a0fb4c --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/endian_vec.rs @@ -0,0 +1,117 @@ +use alloc::vec::Vec; +use std::mem; + +use crate::endianity::Endianity; +use crate::write::{Error, Result, Writer}; + +/// A `Vec` with endianity metadata. +/// +/// This implements the `Writer` trait, which is used for all writing of DWARF sections. +#[derive(Debug, Clone)] +pub struct EndianVec +where + Endian: Endianity, +{ + vec: Vec, + endian: Endian, +} + +impl EndianVec +where + Endian: Endianity, +{ + /// Construct an empty `EndianVec` with the given endianity. + pub fn new(endian: Endian) -> EndianVec { + EndianVec { + vec: Vec::new(), + endian, + } + } + + /// Return a reference to the raw slice. + pub fn slice(&self) -> &[u8] { + &self.vec + } + + /// Convert into a `Vec`. + pub fn into_vec(self) -> Vec { + self.vec + } + + /// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place. + pub fn take(&mut self) -> Vec { + let mut vec = Vec::new(); + mem::swap(&mut self.vec, &mut vec); + vec + } +} + +impl Writer for EndianVec +where + Endian: Endianity, +{ + type Endian = Endian; + + #[inline] + fn endian(&self) -> Self::Endian { + self.endian + } + + #[inline] + fn len(&self) -> usize { + self.vec.len() + } + + fn write(&mut self, bytes: &[u8]) -> Result<()> { + self.vec.extend(bytes); + Ok(()) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + if offset > self.vec.len() { + return Err(Error::OffsetOutOfBounds); + } + let to = &mut self.vec[offset..]; + if bytes.len() > to.len() { + return Err(Error::LengthOutOfBounds); + } + let to = &mut to[..bytes.len()]; + to.copy_from_slice(bytes); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::LittleEndian; + + #[test] + fn test_endian_vec() { + let mut w = EndianVec::new(LittleEndian); + assert_eq!(w.endian(), LittleEndian); + assert_eq!(w.len(), 0); + + w.write(&[1, 2]).unwrap(); + assert_eq!(w.slice(), &[1, 2]); + assert_eq!(w.len(), 2); + + w.write(&[3, 4, 5]).unwrap(); + assert_eq!(w.slice(), &[1, 2, 3, 4, 5]); + assert_eq!(w.len(), 5); + + w.write_at(0, &[6, 7]).unwrap(); + assert_eq!(w.slice(), &[6, 7, 3, 4, 5]); + assert_eq!(w.len(), 5); + + w.write_at(3, &[8, 9]).unwrap(); + assert_eq!(w.slice(), &[6, 7, 3, 8, 9]); + assert_eq!(w.len(), 5); + + assert_eq!(w.write_at(4, &[6, 7]), Err(Error::LengthOutOfBounds)); + assert_eq!(w.write_at(5, &[6, 7]), Err(Error::LengthOutOfBounds)); + assert_eq!(w.write_at(6, &[6, 7]), Err(Error::OffsetOutOfBounds)); + + assert_eq!(w.into_vec(), vec![6, 7, 3, 8, 9]); + } +} diff --git a/deps/crates/vendor/gimli/src/write/line.rs b/deps/crates/vendor/gimli/src/write/line.rs new file mode 100644 index 00000000000000..0e5c06243274c6 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/line.rs @@ -0,0 +1,1946 @@ +use alloc::vec::Vec; +use indexmap::{IndexMap, IndexSet}; +use std::ops::{Deref, DerefMut}; + +use crate::common::{DebugLineOffset, Encoding, Format, LineEncoding, SectionId}; +use crate::constants; +use crate::leb128; +use crate::write::{ + Address, DebugLineStrOffsets, DebugStrOffsets, Error, LineStringId, LineStringTable, Result, + Section, StringId, Writer, +}; + +/// The number assigned to the first special opcode. +// +// We output all instructions for all DWARF versions, since readers +// should be able to ignore instructions they don't support. +const OPCODE_BASE: u8 = 13; + +/// A line number program. +#[derive(Debug, Clone)] +pub struct LineProgram { + /// True if this line program was created with `LineProgram::none()`. + none: bool, + encoding: Encoding, + line_encoding: LineEncoding, + + /// A list of source directory path names. + /// + /// If a path is relative, then the directory is located relative to the working + /// directory of the compilation unit. + /// + /// The first entry is for the working directory of the compilation unit. + directories: IndexSet, + + /// A list of source file entries. + /// + /// Each entry has a path name and a directory. + /// + /// If a path is a relative, then the file is located relative to the + /// directory. Otherwise the directory is meaningless. + /// + /// Does not include comp_file, even for version >= 5. + files: IndexMap<(LineString, DirectoryId), FileInfo>, + + /// True if the file entries may have valid timestamps. + /// + /// Entries may still have a timestamp of 0 even if this is set. + /// For version <= 4, this is ignored. + /// For version 5, this controls whether to emit `DW_LNCT_timestamp`. + pub file_has_timestamp: bool, + + /// True if the file entries may have valid sizes. + /// + /// Entries may still have a size of 0 even if this is set. + /// For version <= 4, this is ignored. + /// For version 5, this controls whether to emit `DW_LNCT_size`. + pub file_has_size: bool, + + /// True if the file entries have valid MD5 checksums. + /// + /// For version <= 4, this is ignored. + /// For version 5, this controls whether to emit `DW_LNCT_MD5`. + pub file_has_md5: bool, + + /// True if the file entries have embedded source code. + /// + /// For version <= 4, this is ignored. + /// For version 5, this controls whether to emit `DW_LNCT_LLVM_source`. + pub file_has_source: bool, + + prev_row: LineRow, + row: LineRow, + // TODO: this probably should be either rows or sequences instead + instructions: Vec, + in_sequence: bool, +} + +impl LineProgram { + /// Create a new `LineProgram`. + /// + /// `comp_dir` defines the working directory of the compilation unit, + /// and must be the same as the `DW_AT_comp_dir` attribute + /// of the compilation unit DIE. + /// + /// `comp_file` and `comp_file_info` define the primary source file + /// of the compilation unit and must be the same as the `DW_AT_name` + /// attribute of the compilation unit DIE. + /// + /// # Panics + /// + /// Panics if `line_encoding.line_base` > 0. + /// + /// Panics if `line_encoding.line_base` + `line_encoding.line_range` <= 0. + /// + /// Panics if `comp_dir` is empty or contains a null byte. + /// + /// Panics if `comp_file` is empty or contains a null byte. + pub fn new( + encoding: Encoding, + line_encoding: LineEncoding, + comp_dir: LineString, + comp_file: LineString, + comp_file_info: Option, + ) -> LineProgram { + // We require a special opcode for a line advance of 0. + // See the debug_asserts in generate_row(). + assert!(line_encoding.line_base <= 0); + assert!(line_encoding.line_base + line_encoding.line_range as i8 > 0); + let mut program = LineProgram { + none: false, + encoding, + line_encoding, + directories: IndexSet::new(), + files: IndexMap::new(), + prev_row: LineRow::initial_state(encoding, line_encoding), + row: LineRow::initial_state(encoding, line_encoding), + instructions: Vec::new(), + in_sequence: false, + file_has_timestamp: false, + file_has_size: false, + file_has_md5: false, + file_has_source: false, + }; + // For all DWARF versions, directory index 0 is comp_dir. + // For version <= 4, the entry is implicit. We still add + // it here so that we use it, but we don't emit it. + let comp_dir_id = program.add_directory(comp_dir); + // For DWARF version >= 5, file index 0 is comp_file and must exist. + if encoding.version >= 5 { + program.add_file(comp_file, comp_dir_id, comp_file_info); + } + program + } + + /// Create a new `LineProgram` with no fields set. + /// + /// This can be used when the `LineProgram` will not be used. + /// + /// You should not attempt to add files or line instructions to + /// this line program, or write it to the `.debug_line` section. + pub fn none() -> Self { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 0, + }; + let line_encoding = LineEncoding::default(); + LineProgram { + none: true, + encoding, + line_encoding, + directories: IndexSet::new(), + files: IndexMap::new(), + prev_row: LineRow::initial_state(encoding, line_encoding), + row: LineRow::initial_state(encoding, line_encoding), + instructions: Vec::new(), + in_sequence: false, + file_has_timestamp: false, + file_has_size: false, + file_has_md5: false, + file_has_source: false, + } + } + + /// Return true if this line program was created with `LineProgram::none()`. + #[inline] + pub fn is_none(&self) -> bool { + self.none + } + + /// Return the encoding parameters for this line program. + #[inline] + pub fn encoding(&self) -> Encoding { + self.encoding + } + + /// Return the DWARF version for this line program. + #[inline] + pub fn version(&self) -> u16 { + self.encoding.version + } + + /// Return the address size in bytes for this line program. + #[inline] + pub fn address_size(&self) -> u8 { + self.encoding.address_size + } + + /// Return the DWARF format for this line program. + #[inline] + pub fn format(&self) -> Format { + self.encoding.format + } + + /// Return the id for the working directory of the compilation unit. + #[inline] + pub fn default_directory(&self) -> DirectoryId { + DirectoryId(0) + } + + /// Add a directory entry and return its id. + /// + /// If the directory already exists, then return the id of the existing entry. + /// + /// If the path is relative, then the directory is located relative to the working + /// directory of the compilation unit. + /// + /// # Panics + /// + /// Panics if `directory` is empty or contains a null byte. + pub fn add_directory(&mut self, directory: LineString) -> DirectoryId { + if let LineString::String(ref val) = directory { + // For DWARF version <= 4, directories must not be empty. + // The first directory isn't emitted so skip the check for it. + if self.encoding.version <= 4 && !self.directories.is_empty() { + assert!(!val.is_empty()); + } + assert!(!val.contains(&0)); + } + let (index, _) = self.directories.insert_full(directory); + DirectoryId(index) + } + + /// Get a reference to a directory entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + pub fn get_directory(&self, id: DirectoryId) -> &LineString { + self.directories.get_index(id.0).unwrap() + } + + /// Add a file entry and return its id. + /// + /// If the file already exists, then return the id of the existing entry. + /// + /// If the file path is relative, then the file is located relative + /// to the directory. Otherwise the directory is meaningless, but it + /// is still used as a key for file entries. + /// + /// If `info` is `None`, then new entries are assigned + /// default information, and existing entries are unmodified. + /// + /// If `info` is not `None`, then it is always assigned to the + /// entry, even if the entry already exists. + /// + /// # Panics + /// + /// Panics if 'file' is empty or contains a null byte. + pub fn add_file( + &mut self, + file: LineString, + directory: DirectoryId, + info: Option, + ) -> FileId { + if let LineString::String(ref val) = file { + if self.encoding.version <= 4 { + assert!(!val.is_empty()); + } + assert!(!val.contains(&0)); + } + + let key = (file, directory); + let index = if let Some(info) = info { + let (index, _) = self.files.insert_full(key, info); + index + } else { + let entry = self.files.entry(key); + let index = entry.index(); + entry.or_default(); + index + }; + FileId::new(index) + } + + /// Get a reference to a file entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + pub fn get_file(&self, id: FileId) -> (&LineString, DirectoryId) { + self.files + .get_index(id.index()) + .map(|entry| (&(entry.0).0, (entry.0).1)) + .unwrap() + } + + /// Get a reference to the info for a file entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + pub fn get_file_info(&self, id: FileId) -> &FileInfo { + self.files + .get_index(id.index()) + .map(|entry| entry.1) + .unwrap() + } + + /// Get a mutable reference to the info for a file entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + pub fn get_file_info_mut(&mut self, id: FileId) -> &mut FileInfo { + self.files + .get_index_mut(id.index()) + .map(|entry| entry.1) + .unwrap() + } + + /// Begin a new sequence and set its base address. + /// + /// # Panics + /// + /// Panics if a sequence has already begun. + pub fn begin_sequence(&mut self, address: Option
) { + assert!(!self.in_sequence); + self.in_sequence = true; + if let Some(address) = address { + self.instructions.push(LineInstruction::SetAddress(address)); + } + } + + /// End the sequence, and reset the row to its default values. + /// + /// Only the `address_offset` and op_index` fields of the current row are used. + /// + /// # Panics + /// + /// Panics if a sequence has not begun. + pub fn end_sequence(&mut self, address_offset: u64) { + assert!(self.in_sequence); + self.in_sequence = false; + self.row.address_offset = address_offset; + let op_advance = self.op_advance(); + if op_advance != 0 { + self.instructions + .push(LineInstruction::AdvancePc(op_advance)); + } + self.instructions.push(LineInstruction::EndSequence); + self.prev_row = LineRow::initial_state(self.encoding, self.line_encoding); + self.row = LineRow::initial_state(self.encoding, self.line_encoding); + } + + /// Return true if a sequence has begun. + #[inline] + pub fn in_sequence(&self) -> bool { + self.in_sequence + } + + /// Returns a reference to the data for the current row. + #[inline] + pub fn row(&mut self) -> &mut LineRow { + &mut self.row + } + + /// Generates the line number information instructions for the current row. + /// + /// After the instructions are generated, it sets `discriminator` to 0, and sets + /// `basic_block`, `prologue_end`, and `epilogue_begin` to false. + /// + /// # Panics + /// + /// Panics if a sequence has not begun. + /// Panics if the address_offset decreases. + pub fn generate_row(&mut self) { + assert!(self.in_sequence); + + // Output fields that are reset on every row. + if self.row.discriminator != 0 { + self.instructions + .push(LineInstruction::SetDiscriminator(self.row.discriminator)); + self.row.discriminator = 0; + } + if self.row.basic_block { + self.instructions.push(LineInstruction::SetBasicBlock); + self.row.basic_block = false; + } + if self.row.prologue_end { + self.instructions.push(LineInstruction::SetPrologueEnd); + self.row.prologue_end = false; + } + if self.row.epilogue_begin { + self.instructions.push(LineInstruction::SetEpilogueBegin); + self.row.epilogue_begin = false; + } + + // Output fields that are not reset on every row. + if self.row.is_statement != self.prev_row.is_statement { + self.instructions.push(LineInstruction::NegateStatement); + } + if self.row.file != self.prev_row.file { + self.instructions + .push(LineInstruction::SetFile(self.row.file)); + } + if self.row.column != self.prev_row.column { + self.instructions + .push(LineInstruction::SetColumn(self.row.column)); + } + if self.row.isa != self.prev_row.isa { + self.instructions + .push(LineInstruction::SetIsa(self.row.isa)); + } + + // Advance the line, address, and operation index. + let line_base = i64::from(self.line_encoding.line_base) as u64; + let line_range = u64::from(self.line_encoding.line_range); + let line_advance = self.row.line as i64 - self.prev_row.line as i64; + let op_advance = self.op_advance(); + + // Default to special advances of 0. + let special_base = u64::from(OPCODE_BASE); + // TODO: handle lack of special opcodes for 0 line advance + debug_assert!(self.line_encoding.line_base <= 0); + debug_assert!(self.line_encoding.line_base + self.line_encoding.line_range as i8 >= 0); + let special_default = special_base.wrapping_sub(line_base); + let mut special = special_default; + let mut use_special = false; + + if line_advance != 0 { + let special_line = (line_advance as u64).wrapping_sub(line_base); + if special_line < line_range { + special = special_base + special_line; + use_special = true; + } else { + self.instructions + .push(LineInstruction::AdvanceLine(line_advance)); + } + } + + if op_advance != 0 { + // Using ConstAddPc can save a byte. + let (special_op_advance, const_add_pc) = if special + op_advance * line_range <= 255 { + (op_advance, false) + } else { + let op_range = (255 - special_base) / line_range; + (op_advance - op_range, true) + }; + + let special_op = special_op_advance * line_range; + if special + special_op <= 255 { + special += special_op; + use_special = true; + if const_add_pc { + self.instructions.push(LineInstruction::ConstAddPc); + } + } else { + self.instructions + .push(LineInstruction::AdvancePc(op_advance)); + } + } + + if use_special && special != special_default { + debug_assert!(special >= special_base); + debug_assert!(special <= 255); + self.instructions + .push(LineInstruction::Special(special as u8)); + } else { + self.instructions.push(LineInstruction::Copy); + } + + self.prev_row = self.row; + } + + fn op_advance(&self) -> u64 { + debug_assert!(self.row.address_offset >= self.prev_row.address_offset); + let mut address_advance = self.row.address_offset - self.prev_row.address_offset; + if self.line_encoding.minimum_instruction_length != 1 { + debug_assert_eq!( + self.row.address_offset % u64::from(self.line_encoding.minimum_instruction_length), + 0 + ); + address_advance /= u64::from(self.line_encoding.minimum_instruction_length); + } + address_advance * u64::from(self.line_encoding.maximum_operations_per_instruction) + + self.row.op_index + - self.prev_row.op_index + } + + /// Returns true if the line number program has no instructions. + /// + /// Does not check the file or directory entries. + #[inline] + pub fn is_empty(&self) -> bool { + self.instructions.is_empty() + } + + /// Write the line number program to the given section. + /// + /// # Panics + /// + /// Panics if `self.is_none()`. + pub fn write( + &self, + w: &mut DebugLine, + encoding: Encoding, + debug_line_str_offsets: &DebugLineStrOffsets, + debug_str_offsets: &DebugStrOffsets, + ) -> Result { + assert!(!self.is_none()); + + if encoding.version < self.version() + || encoding.format != self.format() + || encoding.address_size != self.address_size() + { + return Err(Error::IncompatibleLineProgramEncoding); + } + + let offset = w.offset(); + + let length_offset = w.write_initial_length(self.format())?; + let length_base = w.len(); + + if self.version() < 2 || self.version() > 5 { + return Err(Error::UnsupportedVersion(self.version())); + } + w.write_u16(self.version())?; + + if self.version() >= 5 { + w.write_u8(self.address_size())?; + // Segment selector size. + w.write_u8(0)?; + } + + let header_length_offset = w.len(); + w.write_udata(0, self.format().word_size())?; + let header_length_base = w.len(); + + w.write_u8(self.line_encoding.minimum_instruction_length)?; + if self.version() >= 4 { + w.write_u8(self.line_encoding.maximum_operations_per_instruction)?; + } else if self.line_encoding.maximum_operations_per_instruction != 1 { + return Err(Error::NeedVersion(4)); + }; + w.write_u8(if self.line_encoding.default_is_stmt { + 1 + } else { + 0 + })?; + w.write_u8(self.line_encoding.line_base as u8)?; + w.write_u8(self.line_encoding.line_range)?; + w.write_u8(OPCODE_BASE)?; + w.write(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1])?; + + if self.version() <= 4 { + // The first directory is stored as DW_AT_comp_dir. + for dir in self.directories.iter().skip(1) { + dir.write( + w, + constants::DW_FORM_string, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + } + w.write_u8(0)?; + + for ((file, dir), info) in self.files.iter() { + file.write( + w, + constants::DW_FORM_string, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + w.write_uleb128(dir.0 as u64)?; + w.write_uleb128(info.timestamp)?; + w.write_uleb128(info.size)?; + } + w.write_u8(0)?; + } else { + // Directory entry formats (only ever 1). + w.write_u8(1)?; + w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; + let dir_form = self.directories.get_index(0).unwrap().form(); + w.write_uleb128(dir_form.0.into())?; + + // Directory entries. + w.write_uleb128(self.directories.len() as u64)?; + for dir in self.directories.iter() { + dir.write( + w, + dir_form, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + } + + // File name entry formats. + let count = 2 + + if self.file_has_timestamp { 1 } else { 0 } + + if self.file_has_size { 1 } else { 0 } + + if self.file_has_md5 { 1 } else { 0 } + + if self.file_has_source { 1 } else { 0 }; + w.write_u8(count)?; + w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; + let file_form = (self.files.get_index(0).unwrap().0).0.form(); + w.write_uleb128(file_form.0.into())?; + w.write_uleb128(u64::from(constants::DW_LNCT_directory_index.0))?; + w.write_uleb128(constants::DW_FORM_udata.0.into())?; + if self.file_has_timestamp { + w.write_uleb128(u64::from(constants::DW_LNCT_timestamp.0))?; + w.write_uleb128(constants::DW_FORM_udata.0.into())?; + } + if self.file_has_size { + w.write_uleb128(u64::from(constants::DW_LNCT_size.0))?; + w.write_uleb128(constants::DW_FORM_udata.0.into())?; + } + if self.file_has_md5 { + w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?; + w.write_uleb128(constants::DW_FORM_data16.0.into())?; + } + if self.file_has_source { + w.write_uleb128(u64::from(constants::DW_LNCT_LLVM_source.0))?; + w.write_uleb128(constants::DW_FORM_string.0.into())?; + } + + // File name entries. + w.write_uleb128(self.files.len() as u64)?; + let mut write_file = |file: &LineString, dir: DirectoryId, info: &FileInfo| { + file.write( + w, + file_form, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + w.write_uleb128(dir.0 as u64)?; + if self.file_has_timestamp { + w.write_uleb128(info.timestamp)?; + } + if self.file_has_size { + w.write_uleb128(info.size)?; + } + if self.file_has_md5 { + w.write(&info.md5)?; + } + if self.file_has_source { + // Note: An empty DW_LNCT_LLVM_source is interpreted as missing + // source code. Included source code should always be + // terminated by a "\n" line ending. + let empty_str = LineString::String(Vec::new()); + let source = info.source.as_ref().unwrap_or(&empty_str); + source.write( + w, + constants::DW_FORM_string, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + } + Ok(()) + }; + for ((file, dir), info) in self.files.iter() { + write_file(file, *dir, info)?; + } + } + + let header_length = (w.len() - header_length_base) as u64; + w.write_udata_at( + header_length_offset, + header_length, + self.format().word_size(), + )?; + + for instruction in &self.instructions { + instruction.write(w, self.encoding)?; + } + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, self.format())?; + + Ok(offset) + } +} + +/// A row in the line number table that corresponds to a machine instruction. +#[derive(Debug, Clone, Copy)] +pub struct LineRow { + /// The offset of the instruction from the start address of the sequence. + pub address_offset: u64, + /// The index of an operation within a VLIW instruction. + /// + /// The index of the first operation is 0. + /// Set to 0 for non-VLIW instructions. + pub op_index: u64, + + /// The source file corresponding to the instruction. + pub file: FileId, + /// The line number within the source file. + /// + /// Lines are numbered beginning at 1. Set to 0 if there is no source line. + pub line: u64, + /// The column number within the source line. + /// + /// Columns are numbered beginning at 1. Set to 0 for the "left edge" of the line. + pub column: u64, + /// An additional discriminator used to distinguish between source locations. + /// This value is assigned arbitrarily by the DWARF producer. + pub discriminator: u64, + + /// Set to true if the instruction is a recommended breakpoint for a statement. + pub is_statement: bool, + /// Set to true if the instruction is the beginning of a basic block. + pub basic_block: bool, + /// Set to true if the instruction is a recommended breakpoint at the entry of a + /// function. + pub prologue_end: bool, + /// Set to true if the instruction is a recommended breakpoint prior to the exit of + /// a function. + pub epilogue_begin: bool, + + /// The instruction set architecture of the instruction. + /// + /// Set to 0 for the default ISA. Other values are defined by the architecture ABI. + pub isa: u64, +} + +impl LineRow { + /// Return the initial state as specified in the DWARF standard. + fn initial_state(encoding: Encoding, line_encoding: LineEncoding) -> Self { + LineRow { + address_offset: 0, + op_index: 0, + + file: FileId::initial_state(encoding.version), + line: 1, + column: 0, + discriminator: 0, + + is_statement: line_encoding.default_is_stmt, + basic_block: false, + prologue_end: false, + epilogue_begin: false, + + isa: 0, + } + } +} + +/// An instruction in a line number program. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LineInstruction { + // Special opcodes + Special(u8), + + // Standard opcodes + Copy, + AdvancePc(u64), + AdvanceLine(i64), + SetFile(FileId), + SetColumn(u64), + NegateStatement, + SetBasicBlock, + ConstAddPc, + // DW_LNS_fixed_advance_pc is not supported. + SetPrologueEnd, + SetEpilogueBegin, + SetIsa(u64), + + // Extended opcodes + EndSequence, + // TODO: this doubles the size of this enum. + SetAddress(Address), + // DW_LNE_define_file is not supported. + SetDiscriminator(u64), +} + +impl LineInstruction { + /// Write the line number instruction to the given section. + fn write(self, w: &mut DebugLine, encoding: Encoding) -> Result<()> { + use self::LineInstruction::*; + match self { + Special(val) => w.write_u8(val)?, + Copy => w.write_u8(constants::DW_LNS_copy.0)?, + AdvancePc(val) => { + w.write_u8(constants::DW_LNS_advance_pc.0)?; + w.write_uleb128(val)?; + } + AdvanceLine(val) => { + w.write_u8(constants::DW_LNS_advance_line.0)?; + w.write_sleb128(val)?; + } + SetFile(val) => { + w.write_u8(constants::DW_LNS_set_file.0)?; + w.write_uleb128(val.raw(encoding.version))?; + } + SetColumn(val) => { + w.write_u8(constants::DW_LNS_set_column.0)?; + w.write_uleb128(val)?; + } + NegateStatement => w.write_u8(constants::DW_LNS_negate_stmt.0)?, + SetBasicBlock => w.write_u8(constants::DW_LNS_set_basic_block.0)?, + ConstAddPc => w.write_u8(constants::DW_LNS_const_add_pc.0)?, + SetPrologueEnd => w.write_u8(constants::DW_LNS_set_prologue_end.0)?, + SetEpilogueBegin => w.write_u8(constants::DW_LNS_set_epilogue_begin.0)?, + SetIsa(val) => { + w.write_u8(constants::DW_LNS_set_isa.0)?; + w.write_uleb128(val)?; + } + EndSequence => { + w.write_u8(0)?; + w.write_uleb128(1)?; + w.write_u8(constants::DW_LNE_end_sequence.0)?; + } + SetAddress(address) => { + w.write_u8(0)?; + w.write_uleb128(1 + u64::from(encoding.address_size))?; + w.write_u8(constants::DW_LNE_set_address.0)?; + w.write_address(address, encoding.address_size)?; + } + SetDiscriminator(val) => { + let mut bytes = [0u8; 10]; + // bytes is long enough so this will never fail. + let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); + w.write_u8(0)?; + w.write_uleb128(1 + len as u64)?; + w.write_u8(constants::DW_LNE_set_discriminator.0)?; + w.write(&bytes[..len])?; + } + } + Ok(()) + } +} + +/// A string value for use in defining paths in line number programs. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum LineString { + /// A slice of bytes representing a string. Must not include null bytes. + /// Not guaranteed to be UTF-8 or anything like that. + String(Vec), + + /// A reference to a string in the `.debug_str` section. + StringRef(StringId), + + /// A reference to a string in the `.debug_line_str` section. + LineStringRef(LineStringId), +} + +impl LineString { + /// Create a `LineString` using the normal form for the given encoding. + pub fn new(val: T, encoding: Encoding, line_strings: &mut LineStringTable) -> Self + where + T: Into>, + { + let val = val.into(); + if encoding.version <= 4 { + LineString::String(val) + } else { + LineString::LineStringRef(line_strings.add(val)) + } + } + + fn form(&self) -> constants::DwForm { + match *self { + LineString::String(..) => constants::DW_FORM_string, + LineString::StringRef(..) => constants::DW_FORM_strp, + LineString::LineStringRef(..) => constants::DW_FORM_line_strp, + } + } + + fn write( + &self, + w: &mut DebugLine, + form: constants::DwForm, + encoding: Encoding, + debug_line_str_offsets: &DebugLineStrOffsets, + debug_str_offsets: &DebugStrOffsets, + ) -> Result<()> { + if form != self.form() { + return Err(Error::LineStringFormMismatch); + } + + match *self { + LineString::String(ref val) => { + if encoding.version <= 4 { + debug_assert!(!val.is_empty()); + } + w.write(val)?; + w.write_u8(0)?; + } + LineString::StringRef(val) => { + if encoding.version < 5 { + return Err(Error::NeedVersion(5)); + } + w.write_offset( + debug_str_offsets.get(val).0, + SectionId::DebugStr, + encoding.format.word_size(), + )?; + } + LineString::LineStringRef(val) => { + if encoding.version < 5 { + return Err(Error::NeedVersion(5)); + } + w.write_offset( + debug_line_str_offsets.get(val).0, + SectionId::DebugLineStr, + encoding.format.word_size(), + )?; + } + } + Ok(()) + } +} + +/// An identifier for a directory in a `LineProgram`. +/// +/// Defaults to the working directory of the compilation unit. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DirectoryId(usize); + +// Force FileId access via the methods. +mod id { + /// An identifier for a file in a `LineProgram`. + // + // We internally use a 0-based index for all versions, but + // emit a 1-based index for DWARF version <= 4. + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct FileId(usize); + + impl FileId { + /// Create a `FileId` given a 0-based index into `LineProgram::files`. + pub(crate) fn new(index: usize) -> Self { + FileId(index) + } + + /// The 0-based index of the file in `LineProgram::files`. + pub(super) fn index(self) -> usize { + self.0 + } + + /// The initial state of the file register. + pub(super) fn initial_state(version: u16) -> Self { + if version == 5 { + // For version 5, the files are 0-based and the default file is 1, + // which is a 0-based index of 1. + FileId(1) + } else { + // For version <= 4, the files are 1-based and the default file is 1, + // which is a 0-based index of 0. + // For version >= 6, the files are 0-based and the default file is 0, + // which is a 0-based index of 0. + FileId(0) + } + } + + /// Convert to a raw value used for writing. + /// + /// This converts to a 1-based index for DWARF version <= 4. + pub(crate) fn raw(self, version: u16) -> u64 { + if version <= 4 { + self.0 as u64 + 1 + } else { + self.0 as u64 + } + } + } +} +pub use self::id::*; + +/// Extra information for file in a `LineProgram`. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct FileInfo { + /// The implementation defined timestamp of the last modification of the file, + /// or 0 if not available. + pub timestamp: u64, + + /// The size of the file in bytes, or 0 if not available. + pub size: u64, + + /// A 16-byte MD5 digest of the file contents. + /// + /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`. + pub md5: [u8; 16], + + /// Optionally some embedded sourcecode. + /// + /// Only used if version >= 5 and `LineProgram::file_has_source` is `true`. + /// + /// NOTE: This currently only supports the `LineString::String` variant, + /// since we're encoding the string with `DW_FORM_string`. + /// Other variants will result in an `LineStringFormMismatch` error. + pub source: Option, +} + +define_section!( + DebugLine, + DebugLineOffset, + "A writable `.debug_line` section." +); + +#[cfg(feature = "read")] +mod convert { + use super::*; + use crate::read::{self, Reader}; + use crate::write::{self, ConvertError, ConvertResult}; + + impl LineProgram { + /// Create a line number program by reading the data from the given program. + /// + /// Return the program and a mapping from file index to `FileId`. + pub fn from>( + mut from_program: read::IncompleteLineProgram, + dwarf: &read::Dwarf, + line_strings: &mut write::LineStringTable, + strings: &mut write::StringTable, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult<(LineProgram, Vec)> { + // Create mappings in case the source has duplicate files or directories. + let mut dirs = Vec::new(); + let mut files = Vec::new(); + + let mut program = { + let from_header = from_program.header(); + let encoding = from_header.encoding(); + + let comp_dir = match from_header.directory(0) { + Some(comp_dir) => LineString::from(comp_dir, dwarf, line_strings, strings)?, + None => LineString::new(&[][..], encoding, line_strings), + }; + + let comp_name = match from_header.file(0) { + Some(comp_file) => { + if comp_file.directory_index() != 0 { + return Err(ConvertError::InvalidDirectoryIndex); + } + LineString::from(comp_file.path_name(), dwarf, line_strings, strings)? + } + None => LineString::new(&[][..], encoding, line_strings), + }; + + if from_header.line_base() > 0 { + return Err(ConvertError::InvalidLineBase); + } + let mut program = LineProgram::new( + encoding, + from_header.line_encoding(), + comp_dir, + comp_name, + None, // We'll set this later if needed when we add the file again. + ); + + if from_header.version() <= 4 { + // The first directory is implicit. + dirs.push(DirectoryId(0)); + // A file index of 0 is invalid for version <= 4, but putting + // something there makes the indexing easier. + files.push(FileId::new(0)); + } + + for from_dir in from_header.include_directories() { + let from_dir = + LineString::from(from_dir.clone(), dwarf, line_strings, strings)?; + dirs.push(program.add_directory(from_dir)); + } + + program.file_has_timestamp = from_header.file_has_timestamp(); + program.file_has_size = from_header.file_has_size(); + program.file_has_md5 = from_header.file_has_md5(); + program.file_has_source = from_header.file_has_source(); + for from_file in from_header.file_names().iter() { + let from_name = + LineString::from(from_file.path_name(), dwarf, line_strings, strings)?; + let from_dir = from_file.directory_index(); + if from_dir >= dirs.len() as u64 { + return Err(ConvertError::InvalidDirectoryIndex); + } + let from_dir = dirs[from_dir as usize]; + let from_info = Some(FileInfo { + timestamp: from_file.timestamp(), + size: from_file.size(), + md5: *from_file.md5(), + source: match from_file.source() { + Some(source) => { + Some(LineString::from(source, dwarf, line_strings, strings)?) + } + None => None, + }, + }); + files.push(program.add_file(from_name, from_dir, from_info)); + } + + program + }; + + // We can't use the `from_program.rows()` because that wouldn't let + // us preserve address relocations. + let mut from_row = read::LineRow::new(from_program.header()); + let mut instructions = from_program.header().instructions(); + let mut address = None; + while let Some(instruction) = instructions.next_instruction(from_program.header())? { + match instruction { + read::LineInstruction::SetAddress(val) => { + if program.in_sequence() { + return Err(ConvertError::UnsupportedLineInstruction); + } + match convert_address(val) { + Some(val) => address = Some(val), + None => return Err(ConvertError::InvalidAddress), + } + from_row + .execute(read::LineInstruction::SetAddress(0), &mut from_program)?; + } + read::LineInstruction::DefineFile(_) => { + return Err(ConvertError::UnsupportedLineInstruction); + } + _ => { + if from_row.execute(instruction, &mut from_program)? { + if !program.in_sequence() { + program.begin_sequence(address); + address = None; + } + if from_row.end_sequence() { + program.end_sequence(from_row.address()); + } else { + program.row().address_offset = from_row.address(); + program.row().op_index = from_row.op_index(); + program.row().file = { + let file = from_row.file_index(); + if file >= files.len() as u64 { + return Err(ConvertError::InvalidFileIndex); + } + if file == 0 && program.version() <= 4 { + return Err(ConvertError::InvalidFileIndex); + } + files[file as usize] + }; + program.row().line = match from_row.line() { + Some(line) => line.get(), + None => 0, + }; + program.row().column = match from_row.column() { + read::ColumnType::LeftEdge => 0, + read::ColumnType::Column(val) => val.get(), + }; + program.row().discriminator = from_row.discriminator(); + program.row().is_statement = from_row.is_stmt(); + program.row().basic_block = from_row.basic_block(); + program.row().prologue_end = from_row.prologue_end(); + program.row().epilogue_begin = from_row.epilogue_begin(); + program.row().isa = from_row.isa(); + program.generate_row(); + } + from_row.reset(from_program.header()); + } + } + }; + } + Ok((program, files)) + } + } + + impl LineString { + fn from>( + from_attr: read::AttributeValue, + dwarf: &read::Dwarf, + line_strings: &mut write::LineStringTable, + strings: &mut write::StringTable, + ) -> ConvertResult { + Ok(match from_attr { + read::AttributeValue::String(r) => LineString::String(r.to_slice()?.to_vec()), + read::AttributeValue::DebugStrRef(offset) => { + let r = dwarf.debug_str.get_str(offset)?; + let id = strings.add(r.to_slice()?); + LineString::StringRef(id) + } + read::AttributeValue::DebugLineStrRef(offset) => { + let r = dwarf.debug_line_str.get_str(offset)?; + let id = line_strings.add(r.to_slice()?); + LineString::LineStringRef(id) + } + _ => return Err(ConvertError::UnsupportedLineStringForm), + }) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::read; + use crate::write::{AttributeValue, Dwarf, EndianVec, Sections, Unit}; + use crate::LittleEndian; + + #[test] + fn test_line_program() { + let dir1 = LineString::String(b"dir1".to_vec()); + let file1 = LineString::String(b"file1".to_vec()); + let dir2 = LineString::String(b"dir2".to_vec()); + let file2 = LineString::String(b"file2".to_vec()); + + let mut dwarf = Dwarf::new(); + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let mut program = LineProgram::new( + encoding, + LineEncoding::default(), + dir1.clone(), + file1.clone(), + None, + ); + + assert_eq!(&dir1, program.get_directory(program.default_directory())); + program.file_has_timestamp = true; + program.file_has_size = true; + if encoding.version >= 5 { + program.file_has_md5 = true; + } + + // Note: Embedded source code is an accepted extension + // that will become part of DWARF v6. We're using the LLVM extension + // here for v5. + if encoding.version >= 5 { + program.file_has_source = true; + } + + let dir_id = program.add_directory(dir2.clone()); + assert_eq!(&dir2, program.get_directory(dir_id)); + assert_eq!(dir_id, program.add_directory(dir2.clone())); + + let file_info = FileInfo { + timestamp: 1, + size: 2, + md5: if encoding.version >= 5 { + [3; 16] + } else { + [0; 16] + }, + source: (encoding.version >= 5) + .then(|| LineString::String(b"the source code\n".to_vec())), + }; + let file_id = program.add_file(file2.clone(), dir_id, Some(file_info.clone())); + assert_eq!((&file2, dir_id), program.get_file(file_id)); + assert_eq!(file_info, *program.get_file_info(file_id)); + + program.get_file_info_mut(file_id).size = 3; + assert_ne!(file_info, *program.get_file_info(file_id)); + assert_eq!(file_id, program.add_file(file2.clone(), dir_id, None)); + assert_ne!(file_info, *program.get_file_info(file_id)); + assert_eq!( + file_id, + program.add_file(file2.clone(), dir_id, Some(file_info.clone())) + ); + assert_eq!(file_info, *program.get_file_info(file_id)); + + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + root.set( + constants::DW_AT_comp_dir, + AttributeValue::String(b"dir1".to_vec()), + ); + root.set( + constants::DW_AT_name, + AttributeValue::String(b"file1".to_vec()), + ); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + root.set( + constants::DW_AT_decl_file, + AttributeValue::FileIndex(Some(file_id)), + ); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + } + } + } + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + let read_dwarf = sections.read(LittleEndian); + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))).unwrap(); + + let mut convert_units = convert_dwarf.units.iter(); + for (_, unit) in dwarf.units.iter() { + let program = &unit.line_program; + let root = unit.get(unit.root()); + let Some(AttributeValue::FileIndex(Some(file_id))) = + root.get(constants::DW_AT_decl_file) + else { + panic!("missing DW_AT_decl_file"); + }; + + let (_, convert_unit) = convert_units.next().unwrap(); + let convert_program = &convert_unit.line_program; + let convert_root = convert_unit.get(convert_unit.root()); + let Some(AttributeValue::FileIndex(Some(convert_file_id))) = + convert_root.get(constants::DW_AT_decl_file) + else { + panic!("missing DW_AT_decl_file"); + }; + + assert_eq!(convert_program.version(), program.version()); + assert_eq!(convert_program.address_size(), program.address_size()); + assert_eq!(convert_program.format(), program.format()); + + let (file, dir) = program.get_file(*file_id); + let (convert_file, convert_dir) = convert_program.get_file(*convert_file_id); + assert_eq!(file, convert_file); + assert_eq!( + program.get_directory(dir), + convert_program.get_directory(convert_dir) + ); + assert_eq!( + program.get_file_info(*file_id), + convert_program.get_file_info(*convert_file_id) + ); + } + } + + #[test] + fn test_line_row() { + let dir1 = &b"dir1"[..]; + let file1 = &b"file1"[..]; + let file2 = &b"file2"[..]; + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let line_base = -5; + let line_range = 14; + let neg_line_base = (-line_base) as u8; + let mut program = LineProgram::new( + encoding, + LineEncoding { + line_base, + line_range, + ..Default::default() + }, + LineString::String(dir1.to_vec()), + LineString::String(file1.to_vec()), + None, + ); + let dir_id = program.default_directory(); + let file1_id = + program.add_file(LineString::String(file1.to_vec()), dir_id, None); + let file2_id = + program.add_file(LineString::String(file2.to_vec()), dir_id, None); + + // Test sequences. + { + let mut program = program.clone(); + let address = Address::Constant(0x12); + program.begin_sequence(Some(address)); + assert_eq!( + program.instructions, + vec![LineInstruction::SetAddress(address)] + ); + } + + { + let mut program = program.clone(); + program.begin_sequence(None); + assert_eq!(program.instructions, Vec::new()); + } + + { + let mut program = program.clone(); + program.begin_sequence(None); + program.end_sequence(0x1234); + assert_eq!( + program.instructions, + vec![ + LineInstruction::AdvancePc(0x1234), + LineInstruction::EndSequence + ] + ); + } + + // Create a base program. + program.begin_sequence(None); + program.row.line = 0x1000; + program.generate_row(); + let base_row = program.row; + let base_instructions = program.instructions.clone(); + + // Create test cases. + let mut tests = Vec::new(); + + let row = base_row; + tests.push((row, vec![LineInstruction::Copy])); + + let mut row = base_row; + row.line -= u64::from(neg_line_base); + tests.push((row, vec![LineInstruction::Special(OPCODE_BASE)])); + + let mut row = base_row; + row.line += u64::from(line_range) - 1; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![LineInstruction::Special(OPCODE_BASE + line_range - 1)], + )); + + let mut row = base_row; + row.line += u64::from(line_range); + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![ + LineInstruction::AdvanceLine(i64::from(line_range - neg_line_base)), + LineInstruction::Copy, + ], + )); + + let mut row = base_row; + row.address_offset = 1; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![LineInstruction::Special(OPCODE_BASE + line_range)], + )); + + let op_range = (255 - OPCODE_BASE) / line_range; + let mut row = base_row; + row.address_offset = u64::from(op_range); + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![LineInstruction::Special( + OPCODE_BASE + op_range * line_range, + )], + )); + + let mut row = base_row; + row.address_offset = u64::from(op_range); + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); + row.line -= u64::from(neg_line_base); + tests.push((row, vec![LineInstruction::Special(255)])); + + let mut row = base_row; + row.address_offset = u64::from(op_range); + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![LineInstruction::ConstAddPc, LineInstruction::Copy], + )); + + let mut row = base_row; + row.address_offset = u64::from(op_range); + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![ + LineInstruction::ConstAddPc, + LineInstruction::Special(OPCODE_BASE + 6), + ], + )); + + let mut row = base_row; + row.address_offset = u64::from(op_range) * 2; + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![LineInstruction::ConstAddPc, LineInstruction::Special(255)], + )); + + let mut row = base_row; + row.address_offset = u64::from(op_range) * 2; + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![ + LineInstruction::AdvancePc(row.address_offset), + LineInstruction::Copy, + ], + )); + + let mut row = base_row; + row.address_offset = u64::from(op_range) * 2; + row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; + row.line -= u64::from(neg_line_base); + tests.push(( + row, + vec![ + LineInstruction::AdvancePc(row.address_offset), + LineInstruction::Special(OPCODE_BASE + 6), + ], + )); + + let mut row = base_row; + row.address_offset = 0x1234; + tests.push(( + row, + vec![LineInstruction::AdvancePc(0x1234), LineInstruction::Copy], + )); + + let mut row = base_row; + row.line += 0x1234; + tests.push(( + row, + vec![LineInstruction::AdvanceLine(0x1234), LineInstruction::Copy], + )); + + let mut row = base_row; + row.file = file1_id; + if version == 5 { + // Version 5 is 0-based, but the default file is 1, so this row + // will need to set the file. + tests.push(( + row, + vec![LineInstruction::SetFile(file1_id), LineInstruction::Copy], + )); + } else { + // This is the first file, so normally this is already the default. + tests.push((row, vec![LineInstruction::Copy])); + } + + let mut row = base_row; + row.file = file2_id; + if version == 5 { + tests.push((row, vec![LineInstruction::Copy])); + } else { + tests.push(( + row, + vec![LineInstruction::SetFile(file2_id), LineInstruction::Copy], + )); + } + + let mut row = base_row; + row.column = 0x1234; + tests.push(( + row, + vec![LineInstruction::SetColumn(0x1234), LineInstruction::Copy], + )); + + let mut row = base_row; + row.discriminator = 0x1234; + tests.push(( + row, + vec![ + LineInstruction::SetDiscriminator(0x1234), + LineInstruction::Copy, + ], + )); + + let mut row = base_row; + row.is_statement = !row.is_statement; + tests.push(( + row, + vec![LineInstruction::NegateStatement, LineInstruction::Copy], + )); + + let mut row = base_row; + row.basic_block = true; + tests.push(( + row, + vec![LineInstruction::SetBasicBlock, LineInstruction::Copy], + )); + + let mut row = base_row; + row.prologue_end = true; + tests.push(( + row, + vec![LineInstruction::SetPrologueEnd, LineInstruction::Copy], + )); + + let mut row = base_row; + row.epilogue_begin = true; + tests.push(( + row, + vec![LineInstruction::SetEpilogueBegin, LineInstruction::Copy], + )); + + let mut row = base_row; + row.isa = 0x1234; + tests.push(( + row, + vec![LineInstruction::SetIsa(0x1234), LineInstruction::Copy], + )); + + for test in tests { + // Test generate_row(). + let mut program = program.clone(); + program.row = test.0; + program.generate_row(); + assert_eq!( + &program.instructions[base_instructions.len()..], + &test.1[..] + ); + + // Test LineProgram::from(). + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + let read_dwarf = sections.read(LittleEndian); + + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))) + .unwrap(); + let convert_unit = convert_dwarf.units.iter().next().unwrap().1; + let convert_program = &convert_unit.line_program; + + assert_eq!( + &convert_program.instructions[base_instructions.len()..], + &test.1[..] + ); + } + } + } + } + } + + #[test] + fn test_line_instruction() { + let dir1 = &b"dir1"[..]; + let file1 = &b"file1"[..]; + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let mut program = LineProgram::new( + encoding, + LineEncoding::default(), + LineString::String(dir1.to_vec()), + LineString::String(file1.to_vec()), + None, + ); + let dir_id = program.default_directory(); + let file_id = + program.add_file(LineString::String(file1.to_vec()), dir_id, None); + + for (inst, expect_inst) in &[ + ( + LineInstruction::Special(OPCODE_BASE), + read::LineInstruction::Special(OPCODE_BASE), + ), + ( + LineInstruction::Special(255), + read::LineInstruction::Special(255), + ), + (LineInstruction::Copy, read::LineInstruction::Copy), + ( + LineInstruction::AdvancePc(0x12), + read::LineInstruction::AdvancePc(0x12), + ), + ( + LineInstruction::AdvanceLine(0x12), + read::LineInstruction::AdvanceLine(0x12), + ), + ( + LineInstruction::SetFile(file_id), + read::LineInstruction::SetFile(file_id.raw(encoding.version)), + ), + ( + LineInstruction::SetColumn(0x12), + read::LineInstruction::SetColumn(0x12), + ), + ( + LineInstruction::NegateStatement, + read::LineInstruction::NegateStatement, + ), + ( + LineInstruction::SetBasicBlock, + read::LineInstruction::SetBasicBlock, + ), + ( + LineInstruction::ConstAddPc, + read::LineInstruction::ConstAddPc, + ), + ( + LineInstruction::SetPrologueEnd, + read::LineInstruction::SetPrologueEnd, + ), + ( + LineInstruction::SetEpilogueBegin, + read::LineInstruction::SetEpilogueBegin, + ), + ( + LineInstruction::SetIsa(0x12), + read::LineInstruction::SetIsa(0x12), + ), + ( + LineInstruction::EndSequence, + read::LineInstruction::EndSequence, + ), + ( + LineInstruction::SetAddress(Address::Constant(0x12)), + read::LineInstruction::SetAddress(0x12), + ), + ( + LineInstruction::SetDiscriminator(0x12), + read::LineInstruction::SetDiscriminator(0x12), + ), + ][..] + { + let mut program = program.clone(); + program.instructions.push(*inst); + + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let read_unit_header = read_dwarf.units().next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit_header).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let read_header = read_unit.line_program.as_ref().unwrap().header(); + let mut read_insts = read_header.instructions(); + assert_eq!( + *expect_inst, + read_insts.next_instruction(read_header).unwrap().unwrap() + ); + assert_eq!(None, read_insts.next_instruction(read_header).unwrap()); + } + } + } + } + } + + // Test that the address/line advance is correct. We don't test for optimality. + #[test] + fn test_advance() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 8, + }; + + let dir1 = &b"dir1"[..]; + let file1 = &b"file1"[..]; + + let addresses = 0..50; + let lines = -10..25i64; + + for minimum_instruction_length in [1, 4] { + for maximum_operations_per_instruction in [1, 3] { + for line_base in [-5, 0] { + for line_range in [10, 20] { + let line_encoding = LineEncoding { + minimum_instruction_length, + maximum_operations_per_instruction, + line_base, + line_range, + default_is_stmt: true, + }; + let mut program = LineProgram::new( + encoding, + line_encoding, + LineString::String(dir1.to_vec()), + LineString::String(file1.to_vec()), + None, + ); + for address_advance in addresses.clone() { + program.begin_sequence(Some(Address::Constant(0x1000))); + program.row().line = 0x10000; + program.generate_row(); + for line_advance in lines.clone() { + { + let row = program.row(); + row.address_offset += + address_advance * u64::from(minimum_instruction_length); + row.line = row.line.wrapping_add(line_advance as u64); + } + program.generate_row(); + } + let address_offset = program.row().address_offset + + u64::from(minimum_instruction_length); + program.end_sequence(address_offset); + } + + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let read_unit_header = read_dwarf.units().next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit_header).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let read_program = read_unit.line_program.clone().unwrap(); + + let mut rows = read_program.rows(); + for address_advance in addresses.clone() { + let mut address; + let mut line; + { + let row = rows.next_row().unwrap().unwrap().1; + address = row.address(); + line = row.line().unwrap().get(); + } + assert_eq!(address, 0x1000); + assert_eq!(line, 0x10000); + for line_advance in lines.clone() { + let row = rows.next_row().unwrap().unwrap().1; + assert_eq!( + row.address() - address, + address_advance * u64::from(minimum_instruction_length) + ); + assert_eq!( + (row.line().unwrap().get() as i64) - (line as i64), + line_advance + ); + address = row.address(); + line = row.line().unwrap().get(); + } + let row = rows.next_row().unwrap().unwrap().1; + assert!(row.end_sequence()); + } + } + } + } + } + } + + #[test] + fn test_line_string() { + let version = 5; + + let file1 = "file1"; + + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + let files: &mut [&mut dyn Fn(&mut Dwarf) -> LineString] = &mut [ + &mut |_dwarf| LineString::String(file1.as_bytes().to_vec()), + &mut |dwarf| LineString::StringRef(dwarf.strings.add(file1)), + &mut |dwarf| LineString::LineStringRef(dwarf.line_strings.add(file1)), + ]; + + for file in files { + let mut dwarf = Dwarf::new(); + let file = file(&mut dwarf); + + let mut program = LineProgram::new( + encoding, + LineEncoding::default(), + LineString::String(b"dir".to_vec()), + file.clone(), + None, + ); + program.begin_sequence(Some(Address::Constant(0x1000))); + program.row().line = 0x10000; + program.generate_row(); + + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + dwarf.units.add(unit); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let read_unit_header = read_dwarf.units().next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit_header).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let read_program = read_unit.line_program.clone().unwrap(); + let read_header = read_program.header(); + let read_file = read_header.file(0).unwrap(); + let read_path = read_unit.attr_string(read_file.path_name()).unwrap(); + assert_eq!(read_path.slice(), file1.as_bytes()); + } + } + } + } + + #[test] + fn test_missing_comp_dir() { + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + let mut program = LineProgram::new( + encoding, + LineEncoding::default(), + LineString::String(Vec::new()), + LineString::String(Vec::new()), + None, + ); + // Ensure the program is not empty. + let dir_id = program.default_directory(); + let file_id = + program.add_file(LineString::String(b"file1".to_vec()), dir_id, None); + program.begin_sequence(Some(Address::Constant(0x1000))); + program.row().file = file_id; + program.row().line = 0x10000; + program.generate_row(); + + let mut unit = Unit::new(encoding, program); + let root = unit.get_mut(unit.root()); + // Testing missing DW_AT_comp_dir/DW_AT_name. + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + let read_dwarf = sections.read(LittleEndian); + let _convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))) + .unwrap(); + } + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/loc.rs b/deps/crates/vendor/gimli/src/write/loc.rs new file mode 100644 index 00000000000000..543b2ae33a8778 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/loc.rs @@ -0,0 +1,561 @@ +use alloc::vec::Vec; +use indexmap::IndexSet; +use std::ops::{Deref, DerefMut}; + +use crate::common::{Encoding, LocationListsOffset, SectionId}; +use crate::write::{ + Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets, + Writer, +}; + +define_section!( + DebugLoc, + LocationListsOffset, + "A writable `.debug_loc` section." +); +define_section!( + DebugLocLists, + LocationListsOffset, + "A writable `.debug_loclists` section." +); + +define_offsets!( + LocationListOffsets: LocationListId => LocationListsOffset, + "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections." +); + +define_id!( + LocationListId, + "An identifier for a location list in a `LocationListTable`." +); + +/// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section. +#[derive(Debug, Default)] +pub struct LocationListTable { + base_id: BaseId, + locations: IndexSet, +} + +impl LocationListTable { + /// Add a location list to the table. + pub fn add(&mut self, loc_list: LocationList) -> LocationListId { + let (index, _) = self.locations.insert_full(loc_list); + LocationListId::new(self.base_id, index) + } + + /// Get a reference to a location list. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get(&self, id: LocationListId) -> &LocationList { + debug_assert_eq!(self.base_id, id.base_id); + &self.locations[id.index] + } + + /// Write the location list table to the appropriate section for the given DWARF version. + pub(crate) fn write( + &self, + sections: &mut Sections, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + ) -> Result { + if self.locations.is_empty() { + return Ok(LocationListOffsets::none()); + } + + match encoding.version { + 2..=4 => self.write_loc( + &mut sections.debug_loc, + &mut sections.debug_loc_refs, + encoding, + unit_offsets, + ), + 5 => self.write_loclists( + &mut sections.debug_loclists, + &mut sections.debug_loclists_refs, + encoding, + unit_offsets, + ), + _ => Err(Error::UnsupportedVersion(encoding.version)), + } + } + + /// Write the location list table to the `.debug_loc` section. + fn write_loc( + &self, + w: &mut DebugLoc, + refs: &mut Vec, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + ) -> Result { + let address_size = encoding.address_size; + let mut offsets = Vec::new(); + for loc_list in self.locations.iter() { + offsets.push(w.offset()); + for loc in &loc_list.0 { + // Note that we must ensure none of the ranges have both begin == 0 and end == 0. + // We do this by ensuring that begin != end, which is a bit more restrictive + // than required, but still seems reasonable. + match *loc { + Location::BaseAddress { address } => { + let marker = !0 >> (64 - address_size * 8); + w.write_udata(marker, address_size)?; + w.write_address(address, address_size)?; + } + Location::OffsetPair { + begin, + end, + ref data, + } => { + if begin == end { + return Err(Error::InvalidRange); + } + w.write_udata(begin, address_size)?; + w.write_udata(end, address_size)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::StartEnd { + begin, + end, + ref data, + } => { + if begin == end { + return Err(Error::InvalidRange); + } + w.write_address(begin, address_size)?; + w.write_address(end, address_size)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::StartLength { + begin, + length, + ref data, + } => { + let end = match begin { + Address::Constant(begin) => Address::Constant(begin + length), + Address::Symbol { symbol, addend } => Address::Symbol { + symbol, + addend: addend + length as i64, + }, + }; + if begin == end { + return Err(Error::InvalidRange); + } + w.write_address(begin, address_size)?; + w.write_address(end, address_size)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::DefaultLocation { .. } => { + return Err(Error::InvalidRange); + } + } + } + w.write_udata(0, address_size)?; + w.write_udata(0, address_size)?; + } + Ok(LocationListOffsets { + base_id: self.base_id, + offsets, + }) + } + + /// Write the location list table to the `.debug_loclists` section. + fn write_loclists( + &self, + w: &mut DebugLocLists, + refs: &mut Vec, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + ) -> Result { + let mut offsets = Vec::new(); + + if encoding.version != 5 { + return Err(Error::NeedVersion(5)); + } + + let length_offset = w.write_initial_length(encoding.format)?; + let length_base = w.len(); + + w.write_u16(encoding.version)?; + w.write_u8(encoding.address_size)?; + w.write_u8(0)?; // segment_selector_size + w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) + // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list + + for loc_list in self.locations.iter() { + offsets.push(w.offset()); + for loc in &loc_list.0 { + match *loc { + Location::BaseAddress { address } => { + w.write_u8(crate::constants::DW_LLE_base_address.0)?; + w.write_address(address, encoding.address_size)?; + } + Location::OffsetPair { + begin, + end, + ref data, + } => { + w.write_u8(crate::constants::DW_LLE_offset_pair.0)?; + w.write_uleb128(begin)?; + w.write_uleb128(end)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::StartEnd { + begin, + end, + ref data, + } => { + w.write_u8(crate::constants::DW_LLE_start_end.0)?; + w.write_address(begin, encoding.address_size)?; + w.write_address(end, encoding.address_size)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::StartLength { + begin, + length, + ref data, + } => { + w.write_u8(crate::constants::DW_LLE_start_length.0)?; + w.write_address(begin, encoding.address_size)?; + w.write_uleb128(length)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + Location::DefaultLocation { ref data } => { + w.write_u8(crate::constants::DW_LLE_default_location.0)?; + write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; + } + } + } + + w.write_u8(crate::constants::DW_LLE_end_of_list.0)?; + } + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, encoding.format)?; + + Ok(LocationListOffsets { + base_id: self.base_id, + offsets, + }) + } +} + +/// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct LocationList(pub Vec); + +/// A single location. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum Location { + /// DW_LLE_base_address + BaseAddress { + /// Base address. + address: Address, + }, + /// DW_LLE_offset_pair + OffsetPair { + /// Start of range relative to base address. + begin: u64, + /// End of range relative to base address. + end: u64, + /// Location description. + data: Expression, + }, + /// DW_LLE_start_end + StartEnd { + /// Start of range. + begin: Address, + /// End of range. + end: Address, + /// Location description. + data: Expression, + }, + /// DW_LLE_start_length + StartLength { + /// Start of range. + begin: Address, + /// Length of range. + length: u64, + /// Location description. + data: Expression, + }, + /// DW_LLE_default_location + DefaultLocation { + /// Location description. + data: Expression, + }, +} + +fn write_expression( + w: &mut W, + refs: &mut Vec, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + val: &Expression, +) -> Result<()> { + let size = val.size(encoding, unit_offsets) as u64; + if encoding.version <= 4 { + w.write_udata(size, 2)?; + } else { + w.write_uleb128(size)?; + } + val.write(w, Some(refs), encoding, unit_offsets)?; + Ok(()) +} + +#[cfg(feature = "read")] +mod convert { + use super::*; + + use crate::read::{self, Reader}; + use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; + + impl LocationList { + /// Create a location list by reading the data from the give location list iter. + pub(crate) fn from>( + mut from: read::RawLocListIter, + context: &ConvertUnitContext<'_, R>, + ) -> ConvertResult { + let mut have_base_address = context.base_address != Address::Constant(0); + let convert_address = + |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); + let convert_expression = |x| { + Expression::from( + x, + context.unit.encoding(), + Some(context.dwarf), + Some(context.unit), + Some(context.entry_ids), + context.convert_address, + ) + }; + let mut loc_list = Vec::new(); + while let Some(from_loc) = from.next()? { + let loc = match from_loc { + read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => { + // These were parsed as addresses, even if they are offsets. + let begin = convert_address(begin)?; + let end = convert_address(end)?; + let data = convert_expression(data)?; + match (begin, end) { + (Address::Constant(begin_offset), Address::Constant(end_offset)) => { + if have_base_address { + Location::OffsetPair { + begin: begin_offset, + end: end_offset, + data, + } + } else { + Location::StartEnd { begin, end, data } + } + } + _ => { + if have_base_address { + // At least one of begin/end is an address, but we also have + // a base address. Adding addresses is undefined. + return Err(ConvertError::InvalidRangeRelativeAddress); + } + Location::StartEnd { begin, end, data } + } + } + } + read::RawLocListEntry::BaseAddress { addr } => { + have_base_address = true; + let address = convert_address(addr)?; + Location::BaseAddress { address } + } + read::RawLocListEntry::BaseAddressx { addr } => { + have_base_address = true; + let address = convert_address(context.dwarf.address(context.unit, addr)?)?; + Location::BaseAddress { address } + } + read::RawLocListEntry::StartxEndx { begin, end, data } => { + let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; + let end = convert_address(context.dwarf.address(context.unit, end)?)?; + let data = convert_expression(data)?; + Location::StartEnd { begin, end, data } + } + read::RawLocListEntry::StartxLength { + begin, + length, + data, + } => { + let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; + let data = convert_expression(data)?; + Location::StartLength { + begin, + length, + data, + } + } + read::RawLocListEntry::OffsetPair { begin, end, data } => { + let data = convert_expression(data)?; + Location::OffsetPair { begin, end, data } + } + read::RawLocListEntry::StartEnd { begin, end, data } => { + let begin = convert_address(begin)?; + let end = convert_address(end)?; + let data = convert_expression(data)?; + Location::StartEnd { begin, end, data } + } + read::RawLocListEntry::StartLength { + begin, + length, + data, + } => { + let begin = convert_address(begin)?; + let data = convert_expression(data)?; + Location::StartLength { + begin, + length, + data, + } + } + read::RawLocListEntry::DefaultLocation { data } => { + let data = convert_expression(data)?; + Location::DefaultLocation { data } + } + }; + // In some cases, existing data may contain begin == end, filtering + // these out. + match loc { + Location::StartLength { length: 0, .. } => continue, + Location::StartEnd { begin, end, .. } if begin == end => continue, + Location::OffsetPair { begin, end, .. } if begin == end => continue, + _ => (), + } + loc_list.push(loc); + } + Ok(LocationList(loc_list)) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::common::{ + DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, + DebugStrOffsetsBase, Format, + }; + use crate::read; + use crate::write::{ + ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable, + }; + use crate::LittleEndian; + use std::collections::HashMap; + use std::sync::Arc; + + #[test] + fn test_loc_list() { + let mut line_strings = LineStringTable::default(); + let mut strings = StringTable::default(); + let mut expression = Expression::new(); + expression.op_constu(0); + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + let mut loc_list = LocationList(vec![ + Location::StartLength { + begin: Address::Constant(6666), + length: 7777, + data: expression.clone(), + }, + Location::StartEnd { + begin: Address::Constant(4444), + end: Address::Constant(5555), + data: expression.clone(), + }, + Location::BaseAddress { + address: Address::Constant(1111), + }, + Location::OffsetPair { + begin: 2222, + end: 3333, + data: expression.clone(), + }, + ]); + if version >= 5 { + loc_list.0.push(Location::DefaultLocation { + data: expression.clone(), + }); + } + + let mut locations = LocationListTable::default(); + let loc_list_id = locations.add(loc_list.clone()); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap(); + assert!(sections.debug_loc_refs.is_empty()); + assert!(sections.debug_loclists_refs.is_empty()); + + let read_debug_loc = + read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); + let read_debug_loclists = + read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); + let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists); + let offset = loc_list_offsets.get(loc_list_id); + let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap(); + + let dwarf = read::Dwarf { + locations: read_loc, + ..Default::default() + }; + let unit = read::Unit { + header: read::UnitHeader::new( + encoding, + 0, + read::UnitType::Compilation, + DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), + read::EndianSlice::default(), + ), + abbreviations: Arc::new(read::Abbreviations::default()), + name: None, + comp_dir: None, + low_pc: 0, + str_offsets_base: DebugStrOffsetsBase(0), + addr_base: DebugAddrBase(0), + loclists_base: DebugLocListsBase(0), + rnglists_base: DebugRngListsBase(0), + line_program: None, + dwo_id: None, + }; + let context = ConvertUnitContext { + dwarf: &dwarf, + unit: &unit, + line_strings: &mut line_strings, + strings: &mut strings, + ranges: &mut RangeListTable::default(), + locations: &mut locations, + convert_address: &|address| Some(Address::Constant(address)), + base_address: Address::Constant(0), + line_program_offset: None, + line_program_files: Vec::new(), + entry_ids: &HashMap::new(), + }; + let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap(); + + if version <= 4 { + loc_list.0[0] = Location::StartEnd { + begin: Address::Constant(6666), + end: Address::Constant(6666 + 7777), + data: expression.clone(), + }; + } + assert_eq!(loc_list, convert_loc_list); + } + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/mod.rs b/deps/crates/vendor/gimli/src/write/mod.rs new file mode 100644 index 00000000000000..b7adbbe265ab14 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/mod.rs @@ -0,0 +1,428 @@ +//! Write DWARF debugging information. +//! +//! ## API Structure +//! +//! This module works by building up a representation of the debugging information +//! in memory, and then writing it all at once. It supports two major use cases: +//! +//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF +//! for a single compilation unit. +//! +//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple +//! compilation units. +//! +//! The module also supports reading in DWARF debugging information and writing it out +//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) +//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert +//! it to a writable instance. +//! +//! ## Example Usage +//! +//! Write a compilation unit containing only the top level DIE. +//! +//! ```rust +//! use gimli::write::{ +//! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, +//! }; +//! +//! fn example() -> Result<(), Error> { +//! // Choose the encoding parameters. +//! let encoding = gimli::Encoding { +//! format: gimli::Format::Dwarf32, +//! version: 5, +//! address_size: 8, +//! }; +//! // Create a container for a single compilation unit. +//! let mut dwarf = DwarfUnit::new(encoding); +//! // Set a range attribute on the root DIE. +//! let range_list = RangeList(vec![Range::StartLength { +//! begin: Address::Constant(0x100), +//! length: 42, +//! }]); +//! let range_list_id = dwarf.unit.ranges.add(range_list); +//! let root = dwarf.unit.root(); +//! dwarf.unit.get_mut(root).set( +//! gimli::DW_AT_ranges, +//! AttributeValue::RangeListRef(range_list_id), +//! ); +//! // Create a `Vec` for each DWARF section. +//! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); +//! // Finally, write the DWARF data to the sections. +//! dwarf.write(&mut sections)?; +//! sections.for_each(|id, data| { +//! // Here you can add the data to the output object file. +//! Ok(()) +//! }) +//! } +//! # fn main() { +//! # example().unwrap(); +//! # } + +use std::error; +use std::fmt; +use std::result; + +use crate::constants; + +mod endian_vec; +pub use self::endian_vec::*; + +mod writer; +pub use self::writer::*; + +mod relocate; +pub use self::relocate::*; + +#[macro_use] +mod section; +pub use self::section::*; + +macro_rules! define_id { + ($name:ident, $docs:expr) => { + #[doc=$docs] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct $name { + base_id: BaseId, + index: usize, + } + + impl $name { + #[inline] + fn new(base_id: BaseId, index: usize) -> Self { + $name { base_id, index } + } + } + }; +} + +macro_rules! define_offsets { + ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { + #[doc=$off_doc] + #[derive(Debug)] + pub struct $offsets { + base_id: BaseId, + // We know ids start at 0. + offsets: Vec<$offset>, + } + + impl $offsets { + /// Return an empty list of offsets. + #[inline] + pub fn none() -> Self { + $offsets { + base_id: BaseId::default(), + offsets: Vec::new(), + } + } + + /// Get the offset + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get(&self, id: $id) -> $offset { + debug_assert_eq!(self.base_id, id.base_id); + self.offsets[id.index] + } + + /// Return the number of offsets. + #[inline] + pub fn count(&self) -> usize { + self.offsets.len() + } + } + }; +} + +mod abbrev; +pub use self::abbrev::*; + +mod cfi; +pub use self::cfi::*; + +mod dwarf; +pub use self::dwarf::*; + +mod line; +pub use self::line::*; + +mod loc; +pub use self::loc::*; + +mod op; +pub use self::op::*; + +mod range; +pub use self::range::*; + +mod str; +pub use self::str::*; + +mod unit; +pub use self::unit::*; + +/// An error that occurred when writing. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + /// The given offset is out of bounds. + OffsetOutOfBounds, + /// The given length is out of bounds. + LengthOutOfBounds, + /// The attribute value is an invalid for writing. + InvalidAttributeValue, + /// The value is too large for the encoding form. + ValueTooLarge, + /// Unsupported word size. + UnsupportedWordSize(u8), + /// Unsupported DWARF version. + UnsupportedVersion(u16), + /// The unit length is too large for the requested DWARF format. + InitialLengthOverflow, + /// The address is invalid. + InvalidAddress, + /// The reference is invalid. + InvalidReference, + /// A requested feature requires a different DWARF version. + NeedVersion(u16), + /// Strings in line number program have mismatched forms. + LineStringFormMismatch, + /// The range is empty or otherwise invalid. + InvalidRange, + /// The line number program encoding is incompatible with the unit encoding. + IncompatibleLineProgramEncoding, + /// Could not encode code offset for a frame instruction. + InvalidFrameCodeOffset(u32), + /// Could not encode data offset for a frame instruction. + InvalidFrameDataOffset(i32), + /// Unsupported eh_frame pointer encoding. + UnsupportedPointerEncoding(constants::DwEhPe), + /// Unsupported reference in CFI expression. + UnsupportedCfiExpressionReference, + /// Unsupported forward reference in expression. + UnsupportedExpressionForwardReference, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> { + match *self { + Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), + Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), + Error::InvalidAttributeValue => { + write!(f, "The attribute value is an invalid for writing.") + } + Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), + Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), + Error::UnsupportedVersion(version) => { + write!(f, "Unsupported DWARF version: {}", version) + } + Error::InitialLengthOverflow => write!( + f, + "The unit length is too large for the requested DWARF format." + ), + Error::InvalidAddress => write!(f, "The address is invalid."), + Error::InvalidReference => write!(f, "The reference is invalid."), + Error::NeedVersion(version) => write!( + f, + "A requested feature requires a DWARF version {}.", + version + ), + Error::LineStringFormMismatch => { + write!(f, "Strings in line number program have mismatched forms.") + } + Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), + Error::IncompatibleLineProgramEncoding => write!( + f, + "The line number program encoding is incompatible with the unit encoding." + ), + Error::InvalidFrameCodeOffset(offset) => write!( + f, + "Could not encode code offset ({}) for a frame instruction.", + offset, + ), + Error::InvalidFrameDataOffset(offset) => write!( + f, + "Could not encode data offset ({}) for a frame instruction.", + offset, + ), + Error::UnsupportedPointerEncoding(eh_pe) => { + write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) + } + Error::UnsupportedCfiExpressionReference => { + write!(f, "Unsupported reference in CFI expression.") + } + Error::UnsupportedExpressionForwardReference => { + write!(f, "Unsupported forward reference in expression.") + } + } + } +} + +impl error::Error for Error {} + +/// The result of a write. +pub type Result = result::Result; + +/// An address. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Address { + /// A fixed address that does not require relocation. + Constant(u64), + /// An address that is relative to a symbol which may be relocated. + Symbol { + /// The symbol that the address is relative to. + /// + /// The meaning of this value is decided by the writer, but + /// will typically be an index into a symbol table. + symbol: usize, + /// The offset of the address relative to the symbol. + /// + /// This will typically be used as the addend in a relocation. + addend: i64, + }, +} + +/// A reference to a `.debug_info` entry. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Reference { + /// An external symbol. + /// + /// The meaning of this value is decided by the writer, but + /// will typically be an index into a symbol table. + Symbol(usize), + /// An entry in the same section. + /// + /// This only supports references in units that are emitted together. + Entry(UnitId, UnitEntryId), +} + +// This type is only used in debug assertions. +#[cfg(not(debug_assertions))] +type BaseId = (); + +#[cfg(debug_assertions)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct BaseId(usize); + +#[cfg(debug_assertions)] +impl Default for BaseId { + fn default() -> Self { + use std::sync::atomic; + static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); + BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) + } +} + +#[cfg(feature = "read")] +mod convert { + use super::*; + use crate::read; + + pub(crate) use super::unit::convert::*; + + /// An error that occurred when converting a read value into a write value. + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub enum ConvertError { + /// An error occurred when reading. + Read(read::Error), + /// Writing of this attribute value is not implemented yet. + UnsupportedAttributeValue, + /// This attribute value is an invalid name/form combination. + InvalidAttributeValue, + /// A `.debug_info` reference does not refer to a valid entry. + InvalidDebugInfoOffset, + /// An address could not be converted. + InvalidAddress, + /// Writing this line number instruction is not implemented yet. + UnsupportedLineInstruction, + /// Writing this form of line string is not implemented yet. + UnsupportedLineStringForm, + /// A `.debug_line` file index is invalid. + InvalidFileIndex, + /// A `.debug_line` directory index is invalid. + InvalidDirectoryIndex, + /// A `.debug_line` line base is invalid. + InvalidLineBase, + /// A `.debug_line` reference is invalid. + InvalidLineRef, + /// A `.debug_info` unit entry reference is invalid. + InvalidUnitRef, + /// A `.debug_info` reference is invalid. + InvalidDebugInfoRef, + /// Invalid relative address in a range list. + InvalidRangeRelativeAddress, + /// Writing this CFI instruction is not implemented yet. + UnsupportedCfiInstruction, + /// Writing indirect pointers is not implemented yet. + UnsupportedIndirectAddress, + /// Writing this expression operation is not implemented yet. + UnsupportedOperation, + /// Operation branch target is invalid. + InvalidBranchTarget, + /// Writing this unit type is not supported yet. + UnsupportedUnitType, + } + + impl fmt::Display for ConvertError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> { + use self::ConvertError::*; + match *self { + Read(ref e) => e.fmt(f), + UnsupportedAttributeValue => { + write!(f, "Writing of this attribute value is not implemented yet.") + } + InvalidAttributeValue => write!( + f, + "This attribute value is an invalid name/form combination." + ), + InvalidDebugInfoOffset => write!( + f, + "A `.debug_info` reference does not refer to a valid entry." + ), + InvalidAddress => write!(f, "An address could not be converted."), + UnsupportedLineInstruction => write!( + f, + "Writing this line number instruction is not implemented yet." + ), + UnsupportedLineStringForm => write!( + f, + "Writing this form of line string is not implemented yet." + ), + InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), + InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), + InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), + InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), + InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."), + InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."), + InvalidRangeRelativeAddress => { + write!(f, "Invalid relative address in a range list.") + } + UnsupportedCfiInstruction => { + write!(f, "Writing this CFI instruction is not implemented yet.") + } + UnsupportedIndirectAddress => { + write!(f, "Writing indirect pointers is not implemented yet.") + } + UnsupportedOperation => write!( + f, + "Writing this expression operation is not implemented yet." + ), + InvalidBranchTarget => write!(f, "Operation branch target is invalid."), + UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), + } + } + } + + impl error::Error for ConvertError {} + + impl From for ConvertError { + fn from(e: read::Error) -> Self { + ConvertError::Read(e) + } + } + + /// The result of a conversion. + pub type ConvertResult = result::Result; +} +#[cfg(feature = "read")] +pub use self::convert::*; diff --git a/deps/crates/vendor/gimli/src/write/op.rs b/deps/crates/vendor/gimli/src/write/op.rs new file mode 100644 index 00000000000000..67a2c9b9c9ada5 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/op.rs @@ -0,0 +1,1605 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; + +use crate::common::{Encoding, Register}; +use crate::constants::{self, DwOp}; +use crate::leb128::write::{sleb128_size, uleb128_size}; +use crate::write::{ + Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer, +}; + +/// The bytecode for a DWARF expression or location description. +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] +pub struct Expression { + operations: Vec, +} + +impl Expression { + /// Create an empty expression. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Create an expression from raw bytecode. + /// + /// This does not support operations that require references, such as `DW_OP_addr`. + #[inline] + pub fn raw(bytecode: Vec) -> Self { + Expression { + operations: vec![Operation::Raw(bytecode)], + } + } + + /// Add an operation to the expression. + /// + /// This should only be used for operations that have no explicit operands. + pub fn op(&mut self, opcode: DwOp) { + self.operations.push(Operation::Simple(opcode)); + } + + /// Add a `DW_OP_addr` operation to the expression. + pub fn op_addr(&mut self, address: Address) { + self.operations.push(Operation::Address(address)); + } + + /// Add a `DW_OP_constu` operation to the expression. + /// + /// This may be emitted as a smaller equivalent operation. + pub fn op_constu(&mut self, value: u64) { + self.operations.push(Operation::UnsignedConstant(value)); + } + + /// Add a `DW_OP_consts` operation to the expression. + /// + /// This may be emitted as a smaller equivalent operation. + pub fn op_consts(&mut self, value: i64) { + self.operations.push(Operation::SignedConstant(value)); + } + + /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression. + pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) { + self.operations.push(Operation::ConstantType(base, value)); + } + + /// Add a `DW_OP_fbreg` operation to the expression. + pub fn op_fbreg(&mut self, offset: i64) { + self.operations.push(Operation::FrameOffset(offset)); + } + + /// Add a `DW_OP_bregx` operation to the expression. + /// + /// This may be emitted as a smaller equivalent operation. + pub fn op_breg(&mut self, register: Register, offset: i64) { + self.operations + .push(Operation::RegisterOffset(register, offset)); + } + + /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression. + /// + /// This may be emitted as a smaller equivalent operation. + pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) { + self.operations + .push(Operation::RegisterType(register, base)); + } + + /// Add a `DW_OP_pick` operation to the expression. + /// + /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation. + pub fn op_pick(&mut self, index: u8) { + self.operations.push(Operation::Pick(index)); + } + + /// Add a `DW_OP_deref` operation to the expression. + pub fn op_deref(&mut self) { + self.operations.push(Operation::Deref { space: false }); + } + + /// Add a `DW_OP_xderef` operation to the expression. + pub fn op_xderef(&mut self) { + self.operations.push(Operation::Deref { space: true }); + } + + /// Add a `DW_OP_deref_size` operation to the expression. + pub fn op_deref_size(&mut self, size: u8) { + self.operations + .push(Operation::DerefSize { size, space: false }); + } + + /// Add a `DW_OP_xderef_size` operation to the expression. + pub fn op_xderef_size(&mut self, size: u8) { + self.operations + .push(Operation::DerefSize { size, space: true }); + } + + /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression. + pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) { + self.operations.push(Operation::DerefType { + size, + base, + space: false, + }); + } + + /// Add a `DW_OP_xderef_type` operation to the expression. + pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) { + self.operations.push(Operation::DerefType { + size, + base, + space: true, + }); + } + + /// Add a `DW_OP_plus_uconst` operation to the expression. + pub fn op_plus_uconst(&mut self, value: u64) { + self.operations.push(Operation::PlusConstant(value)); + } + + /// Add a `DW_OP_skip` operation to the expression. + /// + /// Returns the index of the operation. The caller must call `set_target` with + /// this index to set the target of the branch. + pub fn op_skip(&mut self) -> usize { + let index = self.next_index(); + self.operations.push(Operation::Skip(!0)); + index + } + + /// Add a `DW_OP_bra` operation to the expression. + /// + /// Returns the index of the operation. The caller must call `set_target` with + /// this index to set the target of the branch. + pub fn op_bra(&mut self) -> usize { + let index = self.next_index(); + self.operations.push(Operation::Branch(!0)); + index + } + + /// Return the index that will be assigned to the next operation. + /// + /// This can be passed to `set_target`. + #[inline] + pub fn next_index(&self) -> usize { + self.operations.len() + } + + /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation . + pub fn set_target(&mut self, operation: usize, new_target: usize) { + debug_assert!(new_target <= self.next_index()); + debug_assert_ne!(operation, new_target); + match self.operations[operation] { + Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => { + *target = new_target; + } + _ => unimplemented!(), + } + } + + /// Add a `DW_OP_call4` operation to the expression. + pub fn op_call(&mut self, entry: UnitEntryId) { + self.operations.push(Operation::Call(entry)); + } + + /// Add a `DW_OP_call_ref` operation to the expression. + pub fn op_call_ref(&mut self, entry: Reference) { + self.operations.push(Operation::CallRef(entry)); + } + + /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression. + /// + /// `base` is the DIE of the base type, or `None` for the generic type. + pub fn op_convert(&mut self, base: Option) { + self.operations.push(Operation::Convert(base)); + } + + /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression. + /// + /// `base` is the DIE of the base type, or `None` for the generic type. + pub fn op_reinterpret(&mut self, base: Option) { + self.operations.push(Operation::Reinterpret(base)); + } + + /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression. + pub fn op_entry_value(&mut self, expression: Expression) { + self.operations.push(Operation::EntryValue(expression)); + } + + /// Add a `DW_OP_regx` operation to the expression. + /// + /// This may be emitted as a smaller equivalent operation. + pub fn op_reg(&mut self, register: Register) { + self.operations.push(Operation::Register(register)); + } + + /// Add a `DW_OP_implicit_value` operation to the expression. + pub fn op_implicit_value(&mut self, data: Box<[u8]>) { + self.operations.push(Operation::ImplicitValue(data)); + } + + /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression. + pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) { + self.operations + .push(Operation::ImplicitPointer { entry, byte_offset }); + } + + /// Add a `DW_OP_piece` operation to the expression. + pub fn op_piece(&mut self, size_in_bytes: u64) { + self.operations.push(Operation::Piece { size_in_bytes }); + } + + /// Add a `DW_OP_bit_piece` operation to the expression. + pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) { + self.operations.push(Operation::BitPiece { + size_in_bits, + bit_offset, + }); + } + + /// Add a `DW_OP_GNU_parameter_ref` operation to the expression. + pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) { + self.operations.push(Operation::ParameterRef(entry)); + } + + /// Add a `DW_OP_WASM_location 0x0` operation to the expression. + pub fn op_wasm_local(&mut self, index: u32) { + self.operations.push(Operation::WasmLocal(index)); + } + + /// Add a `DW_OP_WASM_location 0x1` operation to the expression. + pub fn op_wasm_global(&mut self, index: u32) { + self.operations.push(Operation::WasmGlobal(index)); + } + + /// Add a `DW_OP_WASM_location 0x2` operation to the expression. + pub fn op_wasm_stack(&mut self, index: u32) { + self.operations.push(Operation::WasmStack(index)); + } + + pub(crate) fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { + let mut size = 0; + for operation in &self.operations { + size += operation.size(encoding, unit_offsets); + } + size + } + + pub(crate) fn write( + &self, + w: &mut W, + mut refs: Option<&mut Vec>, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + ) -> Result<()> { + // TODO: only calculate offsets if needed? + let mut offsets = Vec::with_capacity(self.operations.len()); + let mut offset = w.len(); + for operation in &self.operations { + offsets.push(offset); + offset += operation.size(encoding, unit_offsets); + } + offsets.push(offset); + for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) { + debug_assert_eq!(w.len(), offset); + operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?; + } + Ok(()) + } +} + +/// A single DWARF operation. +// +// This type is intentionally not public so that we can change the +// representation of expressions as needed. +// +// Variants are listed in the order they appear in Section 2.5. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum Operation { + /// Raw bytecode. + /// + /// Does not support references. + Raw(Vec), + /// An operation that has no explicit operands. + /// + /// Represents: + /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot` + /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa` + /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`, + /// `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`, + /// `DW_OP_shra`, `DW_OP_xor` + /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne` + /// - `DW_OP_nop` + /// - `DW_OP_stack_value` + Simple(DwOp), + /// Relocate the address if needed, and push it on the stack. + /// + /// Represents `DW_OP_addr`. + Address(Address), + /// Push an unsigned constant value on the stack. + /// + /// Represents `DW_OP_constu`. + UnsignedConstant(u64), + /// Push a signed constant value on the stack. + /// + /// Represents `DW_OP_consts`. + SignedConstant(i64), + /* TODO: requires .debug_addr write support + /// Read the address at the given index in `.debug_addr, relocate the address if needed, + /// and push it on the stack. + /// + /// Represents `DW_OP_addrx`. + AddressIndex(DebugAddrIndex), + /// Read the address at the given index in `.debug_addr, and push it on the stack. + /// Do not relocate the address. + /// + /// Represents `DW_OP_constx`. + ConstantIndex(DebugAddrIndex), + */ + /// Interpret the value bytes as a constant of a given type, and push it on the stack. + /// + /// Represents `DW_OP_const_type`. + ConstantType(UnitEntryId, Box<[u8]>), + /// Compute the frame base (using `DW_AT_frame_base`), add the + /// given offset, and then push the resulting sum on the stack. + /// + /// Represents `DW_OP_fbreg`. + FrameOffset(i64), + /// Find the contents of the given register, add the offset, and then + /// push the resulting sum on the stack. + /// + /// Represents `DW_OP_bregx`. + RegisterOffset(Register, i64), + /// Interpret the contents of the given register as a value of the given type, + /// and push it on the stack. + /// + /// Represents `DW_OP_regval_type`. + RegisterType(Register, UnitEntryId), + /// Copy the item at a stack index and push it on top of the stack. + /// + /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`. + Pick(u8), + /// Pop the topmost value of the stack, dereference it, and push the + /// resulting value. + /// + /// Represents `DW_OP_deref` and `DW_OP_xderef`. + Deref { + /// True if the dereference operation takes an address space + /// argument from the stack; false otherwise. + space: bool, + }, + /// Pop the topmost value of the stack, dereference it to obtain a value + /// of the given size, and push the resulting value. + /// + /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`. + DerefSize { + /// True if the dereference operation takes an address space + /// argument from the stack; false otherwise. + space: bool, + /// The size of the data to dereference. + size: u8, + }, + /// Pop the topmost value of the stack, dereference it to obtain a value + /// of the given type, and push the resulting value. + /// + /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`. + DerefType { + /// True if the dereference operation takes an address space + /// argument from the stack; false otherwise. + space: bool, + /// The size of the data to dereference. + size: u8, + /// The DIE of the base type, or `None` for the generic type. + base: UnitEntryId, + }, + /// Add an unsigned constant to the topmost value on the stack. + /// + /// Represents `DW_OP_plus_uconst`. + PlusConstant(u64), + /// Unconditional branch to the target location. + /// + /// The value is the index within the expression of the operation to branch to. + /// This will be converted to a relative offset when writing. + /// + /// Represents `DW_OP_skip`. + Skip(usize), + /// Branch to the target location if the top of stack is nonzero. + /// + /// The value is the index within the expression of the operation to branch to. + /// This will be converted to a relative offset when writing. + /// + /// Represents `DW_OP_bra`. + Branch(usize), + /// Evaluate a DWARF expression as a subroutine. + /// + /// The expression comes from the `DW_AT_location` attribute of the indicated DIE. + /// + /// Represents `DW_OP_call4`. + Call(UnitEntryId), + /// Evaluate an external DWARF expression as a subroutine. + /// + /// The expression comes from the `DW_AT_location` attribute of the indicated DIE, + /// which may be in another compilation unit or shared object. + /// + /// Represents `DW_OP_call_ref`. + CallRef(Reference), + /// Pop the top stack entry, convert it to a different type, and push it on the stack. + /// + /// Represents `DW_OP_convert`. + Convert(Option), + /// Pop the top stack entry, reinterpret the bits in its value as a different type, + /// and push it on the stack. + /// + /// Represents `DW_OP_reinterpret`. + Reinterpret(Option), + /// Evaluate an expression at the entry to the current subprogram, and push it on the stack. + /// + /// Represents `DW_OP_entry_value`. + EntryValue(Expression), + // FIXME: EntryRegister + /// Indicate that this piece's location is in the given register. + /// + /// Completes the piece or expression. + /// + /// Represents `DW_OP_regx`. + Register(Register), + /// The object has no location, but has a known constant value. + /// + /// Completes the piece or expression. + /// + /// Represents `DW_OP_implicit_value`. + ImplicitValue(Box<[u8]>), + /// The object is a pointer to a value which has no actual location, such as + /// an implicit value or a stack value. + /// + /// Completes the piece or expression. + /// + /// Represents `DW_OP_implicit_pointer`. + ImplicitPointer { + /// The DIE of the value that this is an implicit pointer into. + entry: Reference, + /// The byte offset into the value that the implicit pointer points to. + byte_offset: i64, + }, + /// Terminate a piece. + /// + /// Represents `DW_OP_piece`. + Piece { + /// The size of this piece in bytes. + size_in_bytes: u64, + }, + /// Terminate a piece with a size in bits. + /// + /// Represents `DW_OP_bit_piece`. + BitPiece { + /// The size of this piece in bits. + size_in_bits: u64, + /// The bit offset of this piece. + bit_offset: u64, + }, + /// This represents a parameter that was optimized out. + /// + /// The entry is the definition of the parameter, and is matched to + /// the `DW_TAG_GNU_call_site_parameter` in the caller that also + /// points to the same definition of the parameter. + /// + /// Represents `DW_OP_GNU_parameter_ref`. + ParameterRef(UnitEntryId), + /// The index of a local in the currently executing function. + /// + /// Represents `DW_OP_WASM_location 0x00`. + WasmLocal(u32), + /// The index of a global. + /// + /// Represents `DW_OP_WASM_location 0x01`. + WasmGlobal(u32), + /// The index of an item on the operand stack. + /// + /// Represents `DW_OP_WASM_location 0x02`. + WasmStack(u32), +} + +impl Operation { + fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { + let base_size = |base| { + // Errors are handled during writes. + match unit_offsets { + Some(offsets) => uleb128_size(offsets.unit_offset(base)), + None => 0, + } + }; + 1 + match *self { + Operation::Raw(ref bytecode) => return bytecode.len(), + Operation::Simple(_) => 0, + Operation::Address(_) => encoding.address_size as usize, + Operation::UnsignedConstant(value) => { + if value < 32 { + 0 + } else { + uleb128_size(value) + } + } + Operation::SignedConstant(value) => sleb128_size(value), + Operation::ConstantType(base, ref value) => base_size(base) + 1 + value.len(), + Operation::FrameOffset(offset) => sleb128_size(offset), + Operation::RegisterOffset(register, offset) => { + if register.0 < 32 { + sleb128_size(offset) + } else { + uleb128_size(register.0.into()) + sleb128_size(offset) + } + } + Operation::RegisterType(register, base) => { + uleb128_size(register.0.into()) + base_size(base) + } + Operation::Pick(index) => { + if index > 1 { + 1 + } else { + 0 + } + } + Operation::Deref { .. } => 0, + Operation::DerefSize { .. } => 1, + Operation::DerefType { base, .. } => 1 + base_size(base), + Operation::PlusConstant(value) => uleb128_size(value), + Operation::Skip(_) => 2, + Operation::Branch(_) => 2, + Operation::Call(_) => 4, + Operation::CallRef(_) => encoding.format.word_size() as usize, + Operation::Convert(base) => match base { + Some(base) => base_size(base), + None => 1, + }, + Operation::Reinterpret(base) => match base { + Some(base) => base_size(base), + None => 1, + }, + Operation::EntryValue(ref expression) => { + let length = expression.size(encoding, unit_offsets); + uleb128_size(length as u64) + length + } + Operation::Register(register) => { + if register.0 < 32 { + 0 + } else { + uleb128_size(register.0.into()) + } + } + Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(), + Operation::ImplicitPointer { byte_offset, .. } => { + let size = if encoding.version == 2 { + encoding.address_size + } else { + encoding.format.word_size() + }; + size as usize + sleb128_size(byte_offset) + } + Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes), + Operation::BitPiece { + size_in_bits, + bit_offset, + } => uleb128_size(size_in_bits) + uleb128_size(bit_offset), + Operation::ParameterRef(_) => 4, + Operation::WasmLocal(index) + | Operation::WasmGlobal(index) + | Operation::WasmStack(index) => 1 + uleb128_size(index.into()), + } + } + + pub(crate) fn write( + &self, + w: &mut W, + refs: Option<&mut Vec>, + encoding: Encoding, + unit_offsets: Option<&UnitOffsets>, + offsets: &[usize], + ) -> Result<()> { + let entry_offset = |entry| match unit_offsets { + Some(offsets) => { + let offset = offsets.unit_offset(entry); + if offset == 0 { + Err(Error::UnsupportedExpressionForwardReference) + } else { + Ok(offset) + } + } + None => Err(Error::UnsupportedCfiExpressionReference), + }; + match *self { + Operation::Raw(ref bytecode) => w.write(bytecode)?, + Operation::Simple(opcode) => w.write_u8(opcode.0)?, + Operation::Address(address) => { + w.write_u8(constants::DW_OP_addr.0)?; + w.write_address(address, encoding.address_size)?; + } + Operation::UnsignedConstant(value) => { + if value < 32 { + w.write_u8(constants::DW_OP_lit0.0 + value as u8)?; + } else { + w.write_u8(constants::DW_OP_constu.0)?; + w.write_uleb128(value)?; + } + } + Operation::SignedConstant(value) => { + w.write_u8(constants::DW_OP_consts.0)?; + w.write_sleb128(value)?; + } + Operation::ConstantType(base, ref value) => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_const_type.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_const_type.0)?; + } + w.write_uleb128(entry_offset(base)?)?; + w.write_udata(value.len() as u64, 1)?; + w.write(value)?; + } + Operation::FrameOffset(offset) => { + w.write_u8(constants::DW_OP_fbreg.0)?; + w.write_sleb128(offset)?; + } + Operation::RegisterOffset(register, offset) => { + if register.0 < 32 { + w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?; + } else { + w.write_u8(constants::DW_OP_bregx.0)?; + w.write_uleb128(register.0.into())?; + } + w.write_sleb128(offset)?; + } + Operation::RegisterType(register, base) => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_regval_type.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_regval_type.0)?; + } + w.write_uleb128(register.0.into())?; + w.write_uleb128(entry_offset(base)?)?; + } + Operation::Pick(index) => match index { + 0 => w.write_u8(constants::DW_OP_dup.0)?, + 1 => w.write_u8(constants::DW_OP_over.0)?, + _ => { + w.write_u8(constants::DW_OP_pick.0)?; + w.write_u8(index)?; + } + }, + Operation::Deref { space } => { + if space { + w.write_u8(constants::DW_OP_xderef.0)?; + } else { + w.write_u8(constants::DW_OP_deref.0)?; + } + } + Operation::DerefSize { space, size } => { + if space { + w.write_u8(constants::DW_OP_xderef_size.0)?; + } else { + w.write_u8(constants::DW_OP_deref_size.0)?; + } + w.write_u8(size)?; + } + Operation::DerefType { space, size, base } => { + if space { + w.write_u8(constants::DW_OP_xderef_type.0)?; + } else { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_deref_type.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_deref_type.0)?; + } + } + w.write_u8(size)?; + w.write_uleb128(entry_offset(base)?)?; + } + Operation::PlusConstant(value) => { + w.write_u8(constants::DW_OP_plus_uconst.0)?; + w.write_uleb128(value)?; + } + Operation::Skip(target) => { + w.write_u8(constants::DW_OP_skip.0)?; + let offset = offsets[target] as i64 - (w.len() as i64 + 2); + w.write_sdata(offset, 2)?; + } + Operation::Branch(target) => { + w.write_u8(constants::DW_OP_bra.0)?; + let offset = offsets[target] as i64 - (w.len() as i64 + 2); + w.write_sdata(offset, 2)?; + } + Operation::Call(entry) => { + w.write_u8(constants::DW_OP_call4.0)?; + // TODO: this probably won't work in practice, because we may + // only know the offsets of base type DIEs at this point. + w.write_udata(entry_offset(entry)?, 4)?; + } + Operation::CallRef(entry) => { + w.write_u8(constants::DW_OP_call_ref.0)?; + let size = encoding.format.word_size(); + match entry { + Reference::Symbol(symbol) => w.write_reference(symbol, size)?, + Reference::Entry(unit, entry) => { + let refs = refs.ok_or(Error::InvalidReference)?; + refs.push(DebugInfoReference { + offset: w.len(), + unit, + entry, + size, + }); + w.write_udata(0, size)?; + } + } + } + Operation::Convert(base) => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_convert.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_convert.0)?; + } + match base { + Some(base) => w.write_uleb128(entry_offset(base)?)?, + None => w.write_u8(0)?, + } + } + Operation::Reinterpret(base) => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_reinterpret.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_reinterpret.0)?; + } + match base { + Some(base) => w.write_uleb128(entry_offset(base)?)?, + None => w.write_u8(0)?, + } + } + Operation::EntryValue(ref expression) => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_entry_value.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_entry_value.0)?; + } + let length = expression.size(encoding, unit_offsets); + w.write_uleb128(length as u64)?; + expression.write(w, refs, encoding, unit_offsets)?; + } + Operation::Register(register) => { + if register.0 < 32 { + w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?; + } else { + w.write_u8(constants::DW_OP_regx.0)?; + w.write_uleb128(register.0.into())?; + } + } + Operation::ImplicitValue(ref data) => { + w.write_u8(constants::DW_OP_implicit_value.0)?; + w.write_uleb128(data.len() as u64)?; + w.write(data)?; + } + Operation::ImplicitPointer { entry, byte_offset } => { + if encoding.version >= 5 { + w.write_u8(constants::DW_OP_implicit_pointer.0)?; + } else { + w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?; + } + let size = if encoding.version == 2 { + encoding.address_size + } else { + encoding.format.word_size() + }; + match entry { + Reference::Symbol(symbol) => { + w.write_reference(symbol, size)?; + } + Reference::Entry(unit, entry) => { + let refs = refs.ok_or(Error::InvalidReference)?; + refs.push(DebugInfoReference { + offset: w.len(), + unit, + entry, + size, + }); + w.write_udata(0, size)?; + } + } + w.write_sleb128(byte_offset)?; + } + Operation::Piece { size_in_bytes } => { + w.write_u8(constants::DW_OP_piece.0)?; + w.write_uleb128(size_in_bytes)?; + } + Operation::BitPiece { + size_in_bits, + bit_offset, + } => { + w.write_u8(constants::DW_OP_bit_piece.0)?; + w.write_uleb128(size_in_bits)?; + w.write_uleb128(bit_offset)?; + } + Operation::ParameterRef(entry) => { + w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?; + w.write_udata(entry_offset(entry)?, 4)?; + } + Operation::WasmLocal(index) => { + w.write(&[constants::DW_OP_WASM_location.0, 0])?; + w.write_uleb128(index.into())?; + } + Operation::WasmGlobal(index) => { + w.write(&[constants::DW_OP_WASM_location.0, 1])?; + w.write_uleb128(index.into())?; + } + Operation::WasmStack(index) => { + w.write(&[constants::DW_OP_WASM_location.0, 2])?; + w.write_uleb128(index.into())?; + } + } + Ok(()) + } +} + +#[cfg(feature = "read")] +pub(crate) mod convert { + use super::*; + use crate::common::UnitSectionOffset; + use crate::read::{self, Reader}; + use crate::write::{ConvertError, ConvertResult, UnitId}; + use std::collections::HashMap; + + impl Expression { + /// Create an expression from the input expression. + pub fn from>( + from_expression: read::Expression, + encoding: Encoding, + dwarf: Option<&read::Dwarf>, + unit: Option<&read::Unit>, + entry_ids: Option<&HashMap>, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult { + let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> { + let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; + let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; + let id = entry_ids + .get(&offset.to_unit_section_offset(unit)) + .ok_or(ConvertError::InvalidUnitRef)?; + Ok(id.1) + }; + let convert_debug_info_offset = |offset| -> ConvertResult<_> { + // TODO: support relocations + let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; + let id = entry_ids + .get(&UnitSectionOffset::DebugInfoOffset(offset)) + .ok_or(ConvertError::InvalidDebugInfoRef)?; + Ok(Reference::Entry(id.0, id.1)) + }; + + // Calculate offsets for use in branch/skip operations. + let mut offsets = Vec::new(); + let mut offset = 0; + let mut from_operations = from_expression.clone().operations(encoding); + while from_operations.next()?.is_some() { + offsets.push(offset); + offset = from_operations.offset_from(&from_expression); + } + offsets.push(from_expression.0.len()); + + let mut from_operations = from_expression.clone().operations(encoding); + let mut operations = Vec::new(); + while let Some(from_operation) = from_operations.next()? { + let operation = match from_operation { + read::Operation::Deref { + base_type, + size, + space, + } => { + if base_type.0 != 0 { + let base = convert_unit_offset(base_type)?; + Operation::DerefType { space, size, base } + } else if size != encoding.address_size { + Operation::DerefSize { space, size } + } else { + Operation::Deref { space } + } + } + read::Operation::Drop => Operation::Simple(constants::DW_OP_drop), + read::Operation::Pick { index } => Operation::Pick(index), + read::Operation::Swap => Operation::Simple(constants::DW_OP_swap), + read::Operation::Rot => Operation::Simple(constants::DW_OP_rot), + read::Operation::Abs => Operation::Simple(constants::DW_OP_abs), + read::Operation::And => Operation::Simple(constants::DW_OP_and), + read::Operation::Div => Operation::Simple(constants::DW_OP_div), + read::Operation::Minus => Operation::Simple(constants::DW_OP_minus), + read::Operation::Mod => Operation::Simple(constants::DW_OP_mod), + read::Operation::Mul => Operation::Simple(constants::DW_OP_mul), + read::Operation::Neg => Operation::Simple(constants::DW_OP_neg), + read::Operation::Not => Operation::Simple(constants::DW_OP_not), + read::Operation::Or => Operation::Simple(constants::DW_OP_or), + read::Operation::Plus => Operation::Simple(constants::DW_OP_plus), + read::Operation::PlusConstant { value } => Operation::PlusConstant(value), + read::Operation::Shl => Operation::Simple(constants::DW_OP_shl), + read::Operation::Shr => Operation::Simple(constants::DW_OP_shr), + read::Operation::Shra => Operation::Simple(constants::DW_OP_shra), + read::Operation::Xor => Operation::Simple(constants::DW_OP_xor), + read::Operation::Eq => Operation::Simple(constants::DW_OP_eq), + read::Operation::Ge => Operation::Simple(constants::DW_OP_ge), + read::Operation::Gt => Operation::Simple(constants::DW_OP_gt), + read::Operation::Le => Operation::Simple(constants::DW_OP_le), + read::Operation::Lt => Operation::Simple(constants::DW_OP_lt), + read::Operation::Ne => Operation::Simple(constants::DW_OP_ne), + read::Operation::Bra { target } => { + let offset = from_operations + .offset_from(&from_expression) + .wrapping_add(i64::from(target) as usize); + let index = offsets + .binary_search(&offset) + .map_err(|_| ConvertError::InvalidBranchTarget)?; + Operation::Branch(index) + } + read::Operation::Skip { target } => { + let offset = from_operations + .offset_from(&from_expression) + .wrapping_add(i64::from(target) as usize); + let index = offsets + .binary_search(&offset) + .map_err(|_| ConvertError::InvalidBranchTarget)?; + Operation::Skip(index) + } + read::Operation::UnsignedConstant { value } => { + Operation::UnsignedConstant(value) + } + read::Operation::SignedConstant { value } => Operation::SignedConstant(value), + read::Operation::Register { register } => Operation::Register(register), + read::Operation::RegisterOffset { + register, + offset, + base_type, + } => { + if base_type.0 != 0 { + Operation::RegisterType(register, convert_unit_offset(base_type)?) + } else { + Operation::RegisterOffset(register, offset) + } + } + read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset), + read::Operation::Nop => Operation::Simple(constants::DW_OP_nop), + read::Operation::PushObjectAddress => { + Operation::Simple(constants::DW_OP_push_object_address) + } + read::Operation::Call { offset } => match offset { + read::DieReference::UnitRef(offset) => { + Operation::Call(convert_unit_offset(offset)?) + } + read::DieReference::DebugInfoRef(offset) => { + Operation::CallRef(convert_debug_info_offset(offset)?) + } + }, + read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address), + read::Operation::CallFrameCFA => { + Operation::Simple(constants::DW_OP_call_frame_cfa) + } + read::Operation::Piece { + size_in_bits, + bit_offset: None, + } => Operation::Piece { + size_in_bytes: size_in_bits / 8, + }, + read::Operation::Piece { + size_in_bits, + bit_offset: Some(bit_offset), + } => Operation::BitPiece { + size_in_bits, + bit_offset, + }, + read::Operation::ImplicitValue { data } => { + Operation::ImplicitValue(data.to_slice()?.into_owned().into()) + } + read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value), + read::Operation::ImplicitPointer { value, byte_offset } => { + let entry = convert_debug_info_offset(value)?; + Operation::ImplicitPointer { entry, byte_offset } + } + read::Operation::EntryValue { expression } => { + let expression = Expression::from( + read::Expression(expression), + encoding, + dwarf, + unit, + entry_ids, + convert_address, + )?; + Operation::EntryValue(expression) + } + read::Operation::ParameterRef { offset } => { + let entry = convert_unit_offset(offset)?; + Operation::ParameterRef(entry) + } + read::Operation::Address { address } => { + let address = + convert_address(address).ok_or(ConvertError::InvalidAddress)?; + Operation::Address(address) + } + read::Operation::AddressIndex { index } => { + let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; + let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; + let val = dwarf.address(unit, index)?; + let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?; + Operation::Address(address) + } + read::Operation::ConstantIndex { index } => { + let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; + let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; + let val = dwarf.address(unit, index)?; + Operation::UnsignedConstant(val) + } + read::Operation::TypedLiteral { base_type, value } => { + let entry = convert_unit_offset(base_type)?; + Operation::ConstantType(entry, value.to_slice()?.into_owned().into()) + } + read::Operation::Convert { base_type } => { + if base_type.0 == 0 { + Operation::Convert(None) + } else { + let entry = convert_unit_offset(base_type)?; + Operation::Convert(Some(entry)) + } + } + read::Operation::Reinterpret { base_type } => { + if base_type.0 == 0 { + Operation::Reinterpret(None) + } else { + let entry = convert_unit_offset(base_type)?; + Operation::Reinterpret(Some(entry)) + } + } + read::Operation::WasmLocal { index } => Operation::WasmLocal(index), + read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index), + read::Operation::WasmStack { index } => Operation::WasmStack(index), + }; + operations.push(operation); + } + Ok(Expression { operations }) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::common::{DebugInfoOffset, Format}; + use crate::read; + use crate::write::{AttributeValue, Dwarf, EndianVec, LineProgram, Sections, Unit}; + use crate::LittleEndian; + use std::collections::HashMap; + + #[test] + #[allow(clippy::type_complexity)] + fn test_operation() { + for version in [2, 3, 4, 5] { + for address_size in [4, 8] { + for format in [Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + let mut dwarf = Dwarf::new(); + let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none())); + let unit = dwarf.units.get_mut(unit_id); + + // Create an entry that can be referenced by the expression. + let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type); + let reference = Reference::Entry(unit_id, entry_id); + + // The offsets for the above entry when reading back the expression. + struct ReadState { + debug_info_offset: DebugInfoOffset, + entry_offset: read::UnitOffset, + } + + let mut reg_expression = Expression::new(); + reg_expression.op_reg(Register(23)); + + let operations: &[( + &dyn Fn(&mut Expression), + Operation, + &dyn Fn(&ReadState) -> read::Operation<_>, + )] = &[ + ( + &|x| x.op_deref(), + Operation::Deref { space: false }, + &|_| read::Operation::Deref { + base_type: read::UnitOffset(0), + size: address_size, + space: false, + }, + ), + ( + &|x| x.op_xderef(), + Operation::Deref { space: true }, + &|_| read::Operation::Deref { + base_type: read::UnitOffset(0), + size: address_size, + space: true, + }, + ), + ( + &|x| x.op_deref_size(2), + Operation::DerefSize { + space: false, + size: 2, + }, + &|_| read::Operation::Deref { + base_type: read::UnitOffset(0), + size: 2, + space: false, + }, + ), + ( + &|x| x.op_xderef_size(2), + Operation::DerefSize { + space: true, + size: 2, + }, + &|_| read::Operation::Deref { + base_type: read::UnitOffset(0), + size: 2, + space: true, + }, + ), + ( + &|x| x.op_deref_type(2, entry_id), + Operation::DerefType { + space: false, + size: 2, + base: entry_id, + }, + &|x| read::Operation::Deref { + base_type: x.entry_offset, + size: 2, + space: false, + }, + ), + ( + &|x| x.op_xderef_type(2, entry_id), + Operation::DerefType { + space: true, + size: 2, + base: entry_id, + }, + &|x| read::Operation::Deref { + base_type: x.entry_offset, + size: 2, + space: true, + }, + ), + ( + &|x| x.op(constants::DW_OP_drop), + Operation::Simple(constants::DW_OP_drop), + &|_| read::Operation::Drop, + ), + (&|x| x.op_pick(0), Operation::Pick(0), &|_| { + read::Operation::Pick { index: 0 } + }), + (&|x| x.op_pick(1), Operation::Pick(1), &|_| { + read::Operation::Pick { index: 1 } + }), + (&|x| x.op_pick(2), Operation::Pick(2), &|_| { + read::Operation::Pick { index: 2 } + }), + ( + &|x| x.op(constants::DW_OP_swap), + Operation::Simple(constants::DW_OP_swap), + &|_| read::Operation::Swap, + ), + ( + &|x| x.op(constants::DW_OP_rot), + Operation::Simple(constants::DW_OP_rot), + &|_| read::Operation::Rot, + ), + ( + &|x| x.op(constants::DW_OP_abs), + Operation::Simple(constants::DW_OP_abs), + &|_| read::Operation::Abs, + ), + ( + &|x| x.op(constants::DW_OP_and), + Operation::Simple(constants::DW_OP_and), + &|_| read::Operation::And, + ), + ( + &|x| x.op(constants::DW_OP_div), + Operation::Simple(constants::DW_OP_div), + &|_| read::Operation::Div, + ), + ( + &|x| x.op(constants::DW_OP_minus), + Operation::Simple(constants::DW_OP_minus), + &|_| read::Operation::Minus, + ), + ( + &|x| x.op(constants::DW_OP_mod), + Operation::Simple(constants::DW_OP_mod), + &|_| read::Operation::Mod, + ), + ( + &|x| x.op(constants::DW_OP_mul), + Operation::Simple(constants::DW_OP_mul), + &|_| read::Operation::Mul, + ), + ( + &|x| x.op(constants::DW_OP_neg), + Operation::Simple(constants::DW_OP_neg), + &|_| read::Operation::Neg, + ), + ( + &|x| x.op(constants::DW_OP_not), + Operation::Simple(constants::DW_OP_not), + &|_| read::Operation::Not, + ), + ( + &|x| x.op(constants::DW_OP_or), + Operation::Simple(constants::DW_OP_or), + &|_| read::Operation::Or, + ), + ( + &|x| x.op(constants::DW_OP_plus), + Operation::Simple(constants::DW_OP_plus), + &|_| read::Operation::Plus, + ), + ( + &|x| x.op_plus_uconst(23), + Operation::PlusConstant(23), + &|_| read::Operation::PlusConstant { value: 23 }, + ), + ( + &|x| x.op(constants::DW_OP_shl), + Operation::Simple(constants::DW_OP_shl), + &|_| read::Operation::Shl, + ), + ( + &|x| x.op(constants::DW_OP_shr), + Operation::Simple(constants::DW_OP_shr), + &|_| read::Operation::Shr, + ), + ( + &|x| x.op(constants::DW_OP_shra), + Operation::Simple(constants::DW_OP_shra), + &|_| read::Operation::Shra, + ), + ( + &|x| x.op(constants::DW_OP_xor), + Operation::Simple(constants::DW_OP_xor), + &|_| read::Operation::Xor, + ), + ( + &|x| x.op(constants::DW_OP_eq), + Operation::Simple(constants::DW_OP_eq), + &|_| read::Operation::Eq, + ), + ( + &|x| x.op(constants::DW_OP_ge), + Operation::Simple(constants::DW_OP_ge), + &|_| read::Operation::Ge, + ), + ( + &|x| x.op(constants::DW_OP_gt), + Operation::Simple(constants::DW_OP_gt), + &|_| read::Operation::Gt, + ), + ( + &|x| x.op(constants::DW_OP_le), + Operation::Simple(constants::DW_OP_le), + &|_| read::Operation::Le, + ), + ( + &|x| x.op(constants::DW_OP_lt), + Operation::Simple(constants::DW_OP_lt), + &|_| read::Operation::Lt, + ), + ( + &|x| x.op(constants::DW_OP_ne), + Operation::Simple(constants::DW_OP_ne), + &|_| read::Operation::Ne, + ), + ( + &|x| x.op_constu(23), + Operation::UnsignedConstant(23), + &|_| read::Operation::UnsignedConstant { value: 23 }, + ), + ( + &|x| x.op_consts(-23), + Operation::SignedConstant(-23), + &|_| read::Operation::SignedConstant { value: -23 }, + ), + ( + &|x| x.op_reg(Register(23)), + Operation::Register(Register(23)), + &|_| read::Operation::Register { + register: Register(23), + }, + ), + ( + &|x| x.op_reg(Register(123)), + Operation::Register(Register(123)), + &|_| read::Operation::Register { + register: Register(123), + }, + ), + ( + &|x| x.op_breg(Register(23), 34), + Operation::RegisterOffset(Register(23), 34), + &|_| read::Operation::RegisterOffset { + register: Register(23), + offset: 34, + base_type: read::UnitOffset(0), + }, + ), + ( + &|x| x.op_breg(Register(123), 34), + Operation::RegisterOffset(Register(123), 34), + &|_| read::Operation::RegisterOffset { + register: Register(123), + offset: 34, + base_type: read::UnitOffset(0), + }, + ), + ( + &|x| x.op_regval_type(Register(23), entry_id), + Operation::RegisterType(Register(23), entry_id), + &|x| read::Operation::RegisterOffset { + register: Register(23), + offset: 0, + base_type: x.entry_offset, + }, + ), + (&|x| x.op_fbreg(34), Operation::FrameOffset(34), &|_| { + read::Operation::FrameOffset { offset: 34 } + }), + ( + &|x| x.op(constants::DW_OP_nop), + Operation::Simple(constants::DW_OP_nop), + &|_| read::Operation::Nop, + ), + ( + &|x| x.op(constants::DW_OP_push_object_address), + Operation::Simple(constants::DW_OP_push_object_address), + &|_| read::Operation::PushObjectAddress, + ), + (&|x| x.op_call(entry_id), Operation::Call(entry_id), &|x| { + read::Operation::Call { + offset: read::DieReference::UnitRef(x.entry_offset), + } + }), + ( + &|x| x.op_call_ref(reference), + Operation::CallRef(reference), + &|x| read::Operation::Call { + offset: read::DieReference::DebugInfoRef(x.debug_info_offset), + }, + ), + ( + &|x| x.op(constants::DW_OP_form_tls_address), + Operation::Simple(constants::DW_OP_form_tls_address), + &|_| read::Operation::TLS, + ), + ( + &|x| x.op(constants::DW_OP_call_frame_cfa), + Operation::Simple(constants::DW_OP_call_frame_cfa), + &|_| read::Operation::CallFrameCFA, + ), + ( + &|x| x.op_piece(23), + Operation::Piece { size_in_bytes: 23 }, + &|_| read::Operation::Piece { + size_in_bits: 23 * 8, + bit_offset: None, + }, + ), + ( + &|x| x.op_bit_piece(23, 34), + Operation::BitPiece { + size_in_bits: 23, + bit_offset: 34, + }, + &|_| read::Operation::Piece { + size_in_bits: 23, + bit_offset: Some(34), + }, + ), + ( + &|x| x.op_implicit_value(vec![23].into()), + Operation::ImplicitValue(vec![23].into()), + &|_| read::Operation::ImplicitValue { + data: read::EndianSlice::new(&[23], LittleEndian), + }, + ), + ( + &|x| x.op(constants::DW_OP_stack_value), + Operation::Simple(constants::DW_OP_stack_value), + &|_| read::Operation::StackValue, + ), + ( + &|x| x.op_implicit_pointer(reference, 23), + Operation::ImplicitPointer { + entry: reference, + byte_offset: 23, + }, + &|x| read::Operation::ImplicitPointer { + value: x.debug_info_offset, + byte_offset: 23, + }, + ), + ( + &|x| x.op_entry_value(reg_expression.clone()), + Operation::EntryValue(reg_expression.clone()), + &|_| read::Operation::EntryValue { + expression: read::EndianSlice::new( + &[constants::DW_OP_reg23.0], + LittleEndian, + ), + }, + ), + ( + &|x| x.op_gnu_parameter_ref(entry_id), + Operation::ParameterRef(entry_id), + &|x| read::Operation::ParameterRef { + offset: x.entry_offset, + }, + ), + ( + &|x| x.op_addr(Address::Constant(23)), + Operation::Address(Address::Constant(23)), + &|_| read::Operation::Address { address: 23 }, + ), + ( + &|x| x.op_const_type(entry_id, vec![23].into()), + Operation::ConstantType(entry_id, vec![23].into()), + &|x| read::Operation::TypedLiteral { + base_type: x.entry_offset, + value: read::EndianSlice::new(&[23], LittleEndian), + }, + ), + (&|x| x.op_convert(None), Operation::Convert(None), &|_| { + read::Operation::Convert { + base_type: read::UnitOffset(0), + } + }), + ( + &|x| x.op_convert(Some(entry_id)), + Operation::Convert(Some(entry_id)), + &|x| read::Operation::Convert { + base_type: x.entry_offset, + }, + ), + ( + &|x| x.op_reinterpret(None), + Operation::Reinterpret(None), + &|_| read::Operation::Reinterpret { + base_type: read::UnitOffset(0), + }, + ), + ( + &|x| x.op_reinterpret(Some(entry_id)), + Operation::Reinterpret(Some(entry_id)), + &|x| read::Operation::Reinterpret { + base_type: x.entry_offset, + }, + ), + ( + &|x| x.op_wasm_local(1000), + Operation::WasmLocal(1000), + &|_| read::Operation::WasmLocal { index: 1000 }, + ), + ( + &|x| x.op_wasm_global(1000), + Operation::WasmGlobal(1000), + &|_| read::Operation::WasmGlobal { index: 1000 }, + ), + ( + &|x| x.op_wasm_stack(1000), + Operation::WasmStack(1000), + &|_| read::Operation::WasmStack { index: 1000 }, + ), + ]; + + // Create a single expression containing all operations. + let mut expression = Expression::new(); + let start_index = expression.next_index(); + for (f, o, _) in operations { + f(&mut expression); + assert_eq!(expression.operations.last(), Some(o)); + } + + let bra_index = expression.op_bra(); + let skip_index = expression.op_skip(); + expression.op(constants::DW_OP_nop); + let end_index = expression.next_index(); + expression.set_target(bra_index, start_index); + expression.set_target(skip_index, end_index); + + // Create an entry containing the expression. + let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram); + let subprogram = unit.get_mut(subprogram_id); + subprogram.set( + constants::DW_AT_location, + AttributeValue::Exprloc(expression), + ); + + // Write the DWARF, then parse it. + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + let read_unit_header = read_units.next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit_header).unwrap(); + let mut read_entries = read_unit.entries(); + let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(read_entry.tag(), constants::DW_TAG_compile_unit); + + // Determine the offset of the entry that can be referenced by the expression. + let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(read_entry.tag(), constants::DW_TAG_base_type); + let read_state = ReadState { + debug_info_offset: read_entry + .offset() + .to_debug_info_offset(&read_unit.header) + .unwrap(), + entry_offset: read_entry.offset(), + }; + + // Get the expression. + let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(read_entry.tag(), constants::DW_TAG_subprogram); + let read_attr = read_entry + .attr_value(constants::DW_AT_location) + .unwrap() + .unwrap(); + let read_expression = read_attr.exprloc_value().unwrap(); + let mut read_operations = read_expression.operations(encoding); + for (_, _, operation) in operations { + assert_eq!(read_operations.next(), Ok(Some(operation(&read_state)))); + } + + // 4 = DW_OP_skip + i16 + DW_OP_nop + assert_eq!( + read_operations.next(), + Ok(Some(read::Operation::Bra { + target: -(read_expression.0.len() as i16) + 4 + })) + ); + // 1 = DW_OP_nop + assert_eq!( + read_operations.next(), + Ok(Some(read::Operation::Skip { target: 1 })) + ); + assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop))); + assert_eq!(read_operations.next(), Ok(None)); + + let mut entry_ids = HashMap::new(); + entry_ids.insert(read_state.debug_info_offset.into(), (unit_id, entry_id)); + let convert_expression = Expression::from( + read_expression, + encoding, + Some(&read_dwarf), + Some(&read_unit), + Some(&entry_ids), + &|address| Some(Address::Constant(address)), + ) + .unwrap(); + let mut convert_operations = convert_expression.operations.iter(); + for (_, operation, _) in operations { + assert_eq!(convert_operations.next(), Some(operation)); + } + assert_eq!( + convert_operations.next(), + Some(&Operation::Branch(start_index)) + ); + assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index))); + assert_eq!( + convert_operations.next(), + Some(&Operation::Simple(constants::DW_OP_nop)) + ); + } + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/range.rs b/deps/crates/vendor/gimli/src/write/range.rs new file mode 100644 index 00000000000000..10a55fb6b50a26 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/range.rs @@ -0,0 +1,427 @@ +use alloc::vec::Vec; +use indexmap::IndexSet; +use std::ops::{Deref, DerefMut}; + +use crate::common::{Encoding, RangeListsOffset, SectionId}; +use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer}; + +define_section!( + DebugRanges, + RangeListsOffset, + "A writable `.debug_ranges` section." +); +define_section!( + DebugRngLists, + RangeListsOffset, + "A writable `.debug_rnglists` section." +); + +define_offsets!( + RangeListOffsets: RangeListId => RangeListsOffset, + "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections." +); + +define_id!( + RangeListId, + "An identifier for a range list in a `RangeListTable`." +); + +/// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section. +#[derive(Debug, Default)] +pub struct RangeListTable { + base_id: BaseId, + ranges: IndexSet, +} + +impl RangeListTable { + /// Add a range list to the table. + pub fn add(&mut self, range_list: RangeList) -> RangeListId { + let (index, _) = self.ranges.insert_full(range_list); + RangeListId::new(self.base_id, index) + } + + /// Get a reference to a location list. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get(&self, id: RangeListId) -> &RangeList { + debug_assert_eq!(self.base_id, id.base_id); + &self.ranges[id.index] + } + + /// Write the range list table to the appropriate section for the given DWARF version. + pub(crate) fn write( + &self, + sections: &mut Sections, + encoding: Encoding, + ) -> Result { + if self.ranges.is_empty() { + return Ok(RangeListOffsets::none()); + } + + match encoding.version { + 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size), + 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding), + _ => Err(Error::UnsupportedVersion(encoding.version)), + } + } + + /// Write the range list table to the `.debug_ranges` section. + fn write_ranges( + &self, + w: &mut DebugRanges, + address_size: u8, + ) -> Result { + let mut offsets = Vec::new(); + for range_list in self.ranges.iter() { + offsets.push(w.offset()); + for range in &range_list.0 { + // Note that we must ensure none of the ranges have both begin == 0 and end == 0. + // We do this by ensuring that begin != end, which is a bit more restrictive + // than required, but still seems reasonable. + match *range { + Range::BaseAddress { address } => { + let marker = !0 >> (64 - address_size * 8); + w.write_udata(marker, address_size)?; + w.write_address(address, address_size)?; + } + Range::OffsetPair { begin, end } => { + if begin == end { + return Err(Error::InvalidRange); + } + w.write_udata(begin, address_size)?; + w.write_udata(end, address_size)?; + } + Range::StartEnd { begin, end } => { + if begin == end { + return Err(Error::InvalidRange); + } + w.write_address(begin, address_size)?; + w.write_address(end, address_size)?; + } + Range::StartLength { begin, length } => { + let end = match begin { + Address::Constant(begin) => Address::Constant(begin + length), + Address::Symbol { symbol, addend } => Address::Symbol { + symbol, + addend: addend + length as i64, + }, + }; + if begin == end { + return Err(Error::InvalidRange); + } + w.write_address(begin, address_size)?; + w.write_address(end, address_size)?; + } + } + } + w.write_udata(0, address_size)?; + w.write_udata(0, address_size)?; + } + Ok(RangeListOffsets { + base_id: self.base_id, + offsets, + }) + } + + /// Write the range list table to the `.debug_rnglists` section. + fn write_rnglists( + &self, + w: &mut DebugRngLists, + encoding: Encoding, + ) -> Result { + let mut offsets = Vec::new(); + + if encoding.version != 5 { + return Err(Error::NeedVersion(5)); + } + + let length_offset = w.write_initial_length(encoding.format)?; + let length_base = w.len(); + + w.write_u16(encoding.version)?; + w.write_u8(encoding.address_size)?; + w.write_u8(0)?; // segment_selector_size + w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) + // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list + + for range_list in self.ranges.iter() { + offsets.push(w.offset()); + for range in &range_list.0 { + match *range { + Range::BaseAddress { address } => { + w.write_u8(crate::constants::DW_RLE_base_address.0)?; + w.write_address(address, encoding.address_size)?; + } + Range::OffsetPair { begin, end } => { + w.write_u8(crate::constants::DW_RLE_offset_pair.0)?; + w.write_uleb128(begin)?; + w.write_uleb128(end)?; + } + Range::StartEnd { begin, end } => { + w.write_u8(crate::constants::DW_RLE_start_end.0)?; + w.write_address(begin, encoding.address_size)?; + w.write_address(end, encoding.address_size)?; + } + Range::StartLength { begin, length } => { + w.write_u8(crate::constants::DW_RLE_start_length.0)?; + w.write_address(begin, encoding.address_size)?; + w.write_uleb128(length)?; + } + } + } + + w.write_u8(crate::constants::DW_RLE_end_of_list.0)?; + } + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, encoding.format)?; + + Ok(RangeListOffsets { + base_id: self.base_id, + offsets, + }) + } +} + +/// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct RangeList(pub Vec); + +/// A single range. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum Range { + /// DW_RLE_base_address + BaseAddress { + /// Base address. + address: Address, + }, + /// DW_RLE_offset_pair + OffsetPair { + /// Start of range relative to base address. + begin: u64, + /// End of range relative to base address. + end: u64, + }, + /// DW_RLE_start_end + StartEnd { + /// Start of range. + begin: Address, + /// End of range. + end: Address, + }, + /// DW_RLE_start_length + StartLength { + /// Start of range. + begin: Address, + /// Length of range. + length: u64, + }, +} + +#[cfg(feature = "read")] +mod convert { + use super::*; + + use crate::read::{self, Reader}; + use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; + + impl RangeList { + /// Create a range list by reading the data from the give range list iter. + pub(crate) fn from>( + mut from: read::RawRngListIter, + context: &ConvertUnitContext<'_, R>, + ) -> ConvertResult { + let mut have_base_address = context.base_address != Address::Constant(0); + let convert_address = + |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); + let mut ranges = Vec::new(); + while let Some(from_range) = from.next()? { + let range = match from_range { + read::RawRngListEntry::AddressOrOffsetPair { begin, end } => { + // These were parsed as addresses, even if they are offsets. + let begin = convert_address(begin)?; + let end = convert_address(end)?; + match (begin, end) { + (Address::Constant(begin_offset), Address::Constant(end_offset)) => { + if have_base_address { + Range::OffsetPair { + begin: begin_offset, + end: end_offset, + } + } else { + Range::StartEnd { begin, end } + } + } + _ => { + if have_base_address { + // At least one of begin/end is an address, but we also have + // a base address. Adding addresses is undefined. + return Err(ConvertError::InvalidRangeRelativeAddress); + } + Range::StartEnd { begin, end } + } + } + } + read::RawRngListEntry::BaseAddress { addr } => { + have_base_address = true; + let address = convert_address(addr)?; + Range::BaseAddress { address } + } + read::RawRngListEntry::BaseAddressx { addr } => { + have_base_address = true; + let address = convert_address(context.dwarf.address(context.unit, addr)?)?; + Range::BaseAddress { address } + } + read::RawRngListEntry::StartxEndx { begin, end } => { + let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; + let end = convert_address(context.dwarf.address(context.unit, end)?)?; + Range::StartEnd { begin, end } + } + read::RawRngListEntry::StartxLength { begin, length } => { + let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; + Range::StartLength { begin, length } + } + read::RawRngListEntry::OffsetPair { begin, end } => { + Range::OffsetPair { begin, end } + } + read::RawRngListEntry::StartEnd { begin, end } => { + let begin = convert_address(begin)?; + let end = convert_address(end)?; + Range::StartEnd { begin, end } + } + read::RawRngListEntry::StartLength { begin, length } => { + let begin = convert_address(begin)?; + Range::StartLength { begin, length } + } + }; + // Filtering empty ranges out. + match range { + Range::StartLength { length: 0, .. } => continue, + Range::StartEnd { begin, end, .. } if begin == end => continue, + Range::OffsetPair { begin, end, .. } if begin == end => continue, + _ => (), + } + ranges.push(range); + } + Ok(RangeList(ranges)) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::common::{ + DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, + DebugStrOffsetsBase, Format, + }; + use crate::read; + use crate::write::{ + ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable, + StringTable, + }; + use crate::LittleEndian; + use std::collections::HashMap; + use std::sync::Arc; + + #[test] + fn test_range() { + let mut line_strings = LineStringTable::default(); + let mut strings = StringTable::default(); + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + let mut range_list = RangeList(vec![ + Range::StartLength { + begin: Address::Constant(6666), + length: 7777, + }, + Range::StartEnd { + begin: Address::Constant(4444), + end: Address::Constant(5555), + }, + Range::BaseAddress { + address: Address::Constant(1111), + }, + Range::OffsetPair { + begin: 2222, + end: 3333, + }, + ]); + + let mut ranges = RangeListTable::default(); + let range_list_id = ranges.add(range_list.clone()); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); + + let read_debug_ranges = + read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); + let read_debug_rnglists = + read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); + let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists); + let offset = range_list_offsets.get(range_list_id); + let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap(); + + let dwarf = read::Dwarf { + ranges: read_ranges, + ..Default::default() + }; + let unit = read::Unit { + header: read::UnitHeader::new( + encoding, + 0, + read::UnitType::Compilation, + DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), + read::EndianSlice::default(), + ), + abbreviations: Arc::new(read::Abbreviations::default()), + name: None, + comp_dir: None, + low_pc: 0, + str_offsets_base: DebugStrOffsetsBase(0), + addr_base: DebugAddrBase(0), + loclists_base: DebugLocListsBase(0), + rnglists_base: DebugRngListsBase(0), + line_program: None, + dwo_id: None, + }; + let context = ConvertUnitContext { + dwarf: &dwarf, + unit: &unit, + line_strings: &mut line_strings, + strings: &mut strings, + ranges: &mut ranges, + locations: &mut LocationListTable::default(), + convert_address: &|address| Some(Address::Constant(address)), + base_address: Address::Constant(0), + line_program_offset: None, + line_program_files: Vec::new(), + entry_ids: &HashMap::new(), + }; + let convert_range_list = RangeList::from(read_range_list, &context).unwrap(); + + if version <= 4 { + range_list.0[0] = Range::StartEnd { + begin: Address::Constant(6666), + end: Address::Constant(6666 + 7777), + }; + } + assert_eq!(range_list, convert_range_list); + } + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/relocate.rs b/deps/crates/vendor/gimli/src/write/relocate.rs new file mode 100644 index 00000000000000..ff8dde13b71428 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/relocate.rs @@ -0,0 +1,280 @@ +use crate::constants; +use crate::write::{Address, Error, Result, Writer}; +use crate::SectionId; + +/// A relocation to be applied to a section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Relocation { + /// The offset within the section where the relocation should be applied. + pub offset: usize, + /// The size of the value to be relocated. + pub size: u8, + /// The target of the relocation. + pub target: RelocationTarget, + /// The addend to be applied to the relocated value. + pub addend: i64, + /// The pointer encoding for relocations in unwind information. + pub eh_pe: Option, +} + +/// The target of a relocation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RelocationTarget { + /// The relocation target is a symbol. + /// + /// The meaning of this value is decided by the writer, but + /// will typically be an index into a symbol table. + Symbol(usize), + /// The relocation target is a section. + Section(SectionId), +} + +/// A `Writer` which also records relocations. +pub trait RelocateWriter { + /// The type of the writer being used to write the section data. + type Writer: Writer; + + /// Get the writer being used to write the section data. + fn writer(&self) -> &Self::Writer; + + /// Get the writer being used to write the section data. + fn writer_mut(&mut self) -> &mut Self::Writer; + + /// Record a relocation. + fn relocate(&mut self, relocation: Relocation); +} + +impl Writer for T { + type Endian = <::Writer as Writer>::Endian; + + fn endian(&self) -> Self::Endian { + self.writer().endian() + } + + fn len(&self) -> usize { + self.writer().len() + } + + fn write(&mut self, bytes: &[u8]) -> Result<()> { + self.writer_mut().write(bytes) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + self.writer_mut().write_at(offset, bytes) + } + + fn write_address(&mut self, address: Address, size: u8) -> Result<()> { + match address { + Address::Constant(val) => self.writer_mut().write_udata(val, size), + Address::Symbol { symbol, addend } => { + self.relocate(Relocation { + offset: self.len(), + size, + target: RelocationTarget::Symbol(symbol), + addend, + eh_pe: None, + }); + self.writer_mut().write_udata(0, size) + } + } + } + + fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { + self.relocate(Relocation { + offset: self.len(), + size, + target: RelocationTarget::Section(section), + addend: val as i64, + eh_pe: None, + }); + self.writer_mut().write_udata(0, size) + } + + fn write_offset_at( + &mut self, + offset: usize, + val: usize, + section: SectionId, + size: u8, + ) -> Result<()> { + self.relocate(Relocation { + offset, + size, + target: RelocationTarget::Section(section), + addend: val as i64, + eh_pe: None, + }); + self.writer_mut().write_udata_at(offset, 0, size) + } + + fn write_eh_pointer( + &mut self, + address: Address, + eh_pe: constants::DwEhPe, + size: u8, + ) -> Result<()> { + match address { + Address::Constant(_) => self.writer_mut().write_eh_pointer(address, eh_pe, size), + Address::Symbol { symbol, addend } => { + let size = match eh_pe.format() { + constants::DW_EH_PE_absptr => size, + constants::DW_EH_PE_udata2 => 2, + constants::DW_EH_PE_udata4 => 4, + constants::DW_EH_PE_udata8 => 8, + constants::DW_EH_PE_sdata2 => 2, + constants::DW_EH_PE_sdata4 => 4, + constants::DW_EH_PE_sdata8 => 8, + _ => return Err(Error::UnsupportedPointerEncoding(eh_pe)), + }; + self.relocate(Relocation { + offset: self.len(), + size, + target: RelocationTarget::Symbol(symbol), + addend, + eh_pe: Some(eh_pe), + }); + self.writer_mut().write_udata(0, size) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::write::EndianVec; + use crate::{LittleEndian, SectionId}; + use alloc::vec::Vec; + + struct Section { + writer: EndianVec, + relocations: Vec, + } + + impl RelocateWriter for Section { + type Writer = EndianVec; + + fn writer(&self) -> &Self::Writer { + &self.writer + } + + fn writer_mut(&mut self) -> &mut Self::Writer { + &mut self.writer + } + + fn relocate(&mut self, relocation: Relocation) { + self.relocations.push(relocation); + } + } + + #[test] + fn test_relocate_writer() { + let mut expected_data = Vec::new(); + let mut expected_relocations = Vec::new(); + + let mut section = Section { + writer: EndianVec::new(LittleEndian), + relocations: Vec::new(), + }; + + // No relocation for plain data. + section.write_udata(0x12345678, 4).unwrap(); + expected_data.extend_from_slice(&0x12345678u32.to_le_bytes()); + + // No relocation for a constant address. + section + .write_address(Address::Constant(0x87654321), 4) + .unwrap(); + expected_data.extend_from_slice(&0x87654321u32.to_le_bytes()); + + // Relocation for a symbol address. + let offset = section.len(); + section + .write_address( + Address::Symbol { + symbol: 1, + addend: 0x12345678, + }, + 4, + ) + .unwrap(); + expected_data.extend_from_slice(&[0; 4]); + expected_relocations.push(Relocation { + offset, + size: 4, + target: RelocationTarget::Symbol(1), + addend: 0x12345678, + eh_pe: None, + }); + + // Relocation for a section offset. + let offset = section.len(); + section + .write_offset(0x12345678, SectionId::DebugAbbrev, 4) + .unwrap(); + expected_data.extend_from_slice(&[0; 4]); + expected_relocations.push(Relocation { + offset, + size: 4, + target: RelocationTarget::Section(SectionId::DebugAbbrev), + addend: 0x12345678, + eh_pe: None, + }); + + // Relocation for a section offset at a specific offset. + let offset = section.len(); + section.write_udata(0x12345678, 4).unwrap(); + section + .write_offset_at(offset, 0x12345678, SectionId::DebugStr, 4) + .unwrap(); + expected_data.extend_from_slice(&[0; 4]); + expected_relocations.push(Relocation { + offset, + size: 4, + target: RelocationTarget::Section(SectionId::DebugStr), + addend: 0x12345678, + eh_pe: None, + }); + + // No relocation for a constant in unwind information. + section + .write_eh_pointer(Address::Constant(0x87654321), constants::DW_EH_PE_absptr, 8) + .unwrap(); + expected_data.extend_from_slice(&0x87654321u64.to_le_bytes()); + + // No relocation for a relative constant in unwind information. + let offset = section.len(); + section + .write_eh_pointer( + Address::Constant(offset as u64 - 8), + constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4, + 8, + ) + .unwrap(); + expected_data.extend_from_slice(&(-8i32).to_le_bytes()); + + // Relocation for a symbol in unwind information. + let offset = section.len(); + section + .write_eh_pointer( + Address::Symbol { + symbol: 2, + addend: 0x12345678, + }, + constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4, + 8, + ) + .unwrap(); + expected_data.extend_from_slice(&[0; 4]); + expected_relocations.push(Relocation { + offset, + size: 4, + target: RelocationTarget::Symbol(2), + addend: 0x12345678, + eh_pe: Some(constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4), + }); + + assert_eq!(section.writer.into_vec(), expected_data); + assert_eq!(section.relocations, expected_relocations); + } +} diff --git a/deps/crates/vendor/gimli/src/write/section.rs b/deps/crates/vendor/gimli/src/write/section.rs new file mode 100644 index 00000000000000..6439680647e998 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/section.rs @@ -0,0 +1,227 @@ +use std::ops::DerefMut; +use std::result; +use std::vec::Vec; + +use crate::common::SectionId; +use crate::write::{ + DebugAbbrev, DebugFrame, DebugInfo, DebugInfoReference, DebugLine, DebugLineStr, DebugLoc, + DebugLocLists, DebugRanges, DebugRngLists, DebugStr, EhFrame, Writer, +}; + +macro_rules! define_section { + ($name:ident, $offset:ident, $docs:expr) => { + #[doc=$docs] + #[derive(Debug, Default)] + pub struct $name(pub W); + + impl $name { + /// Return the offset of the next write. + pub fn offset(&self) -> $offset { + $offset(self.len()) + } + } + + impl From for $name { + #[inline] + fn from(w: W) -> Self { + $name(w) + } + } + + impl Deref for $name { + type Target = W; + + #[inline] + fn deref(&self) -> &W { + &self.0 + } + } + + impl DerefMut for $name { + #[inline] + fn deref_mut(&mut self) -> &mut W { + &mut self.0 + } + } + + impl Section for $name { + #[inline] + fn id(&self) -> SectionId { + SectionId::$name + } + } + }; +} + +/// Functionality common to all writable DWARF sections. +pub trait Section: DerefMut { + /// Returns the DWARF section kind for this type. + fn id(&self) -> SectionId; + + /// Returns the ELF section name for this type. + fn name(&self) -> &'static str { + self.id().name() + } +} + +/// All of the writable DWARF sections. +#[derive(Debug, Default)] +pub struct Sections { + /// The `.debug_abbrev` section. + pub debug_abbrev: DebugAbbrev, + /// The `.debug_info` section. + pub debug_info: DebugInfo, + /// The `.debug_line` section. + pub debug_line: DebugLine, + /// The `.debug_line_str` section. + pub debug_line_str: DebugLineStr, + /// The `.debug_ranges` section. + pub debug_ranges: DebugRanges, + /// The `.debug_rnglists` section. + pub debug_rnglists: DebugRngLists, + /// The `.debug_loc` section. + pub debug_loc: DebugLoc, + /// The `.debug_loclists` section. + pub debug_loclists: DebugLocLists, + /// The `.debug_str` section. + pub debug_str: DebugStr, + /// The `.debug_frame` section. + pub debug_frame: DebugFrame, + /// The `.eh_frame` section. + pub eh_frame: EhFrame, + /// Unresolved references in the `.debug_info` section. + pub(crate) debug_info_refs: Vec, + /// Unresolved references in the `.debug_loc` section. + pub(crate) debug_loc_refs: Vec, + /// Unresolved references in the `.debug_loclists` section. + pub(crate) debug_loclists_refs: Vec, +} + +impl Sections { + /// Create a new `Sections` using clones of the given `section`. + pub fn new(section: W) -> Self { + Sections { + debug_abbrev: DebugAbbrev(section.clone()), + debug_info: DebugInfo(section.clone()), + debug_line: DebugLine(section.clone()), + debug_line_str: DebugLineStr(section.clone()), + debug_ranges: DebugRanges(section.clone()), + debug_rnglists: DebugRngLists(section.clone()), + debug_loc: DebugLoc(section.clone()), + debug_loclists: DebugLocLists(section.clone()), + debug_str: DebugStr(section.clone()), + debug_frame: DebugFrame(section.clone()), + eh_frame: EhFrame(section), + debug_info_refs: Vec::new(), + debug_loc_refs: Vec::new(), + debug_loclists_refs: Vec::new(), + } + } +} + +impl Sections { + /// Get the section with the given `id`. + pub fn get(&self, id: SectionId) -> Option<&W> { + match id { + SectionId::DebugAbbrev => Some(&self.debug_abbrev.0), + SectionId::DebugInfo => Some(&self.debug_info.0), + SectionId::DebugLine => Some(&self.debug_line.0), + SectionId::DebugLineStr => Some(&self.debug_line_str.0), + SectionId::DebugRanges => Some(&self.debug_ranges.0), + SectionId::DebugRngLists => Some(&self.debug_rnglists.0), + SectionId::DebugLoc => Some(&self.debug_loc.0), + SectionId::DebugLocLists => Some(&self.debug_loclists.0), + SectionId::DebugStr => Some(&self.debug_str.0), + SectionId::DebugFrame => Some(&self.debug_frame.0), + SectionId::EhFrame => Some(&self.eh_frame.0), + _ => None, + } + } + + /// Get the section with the given `id`. + pub fn get_mut(&mut self, id: SectionId) -> Option<&mut W> { + match id { + SectionId::DebugAbbrev => Some(&mut self.debug_abbrev.0), + SectionId::DebugInfo => Some(&mut self.debug_info.0), + SectionId::DebugLine => Some(&mut self.debug_line.0), + SectionId::DebugLineStr => Some(&mut self.debug_line_str.0), + SectionId::DebugRanges => Some(&mut self.debug_ranges.0), + SectionId::DebugRngLists => Some(&mut self.debug_rnglists.0), + SectionId::DebugLoc => Some(&mut self.debug_loc.0), + SectionId::DebugLocLists => Some(&mut self.debug_loclists.0), + SectionId::DebugStr => Some(&mut self.debug_str.0), + SectionId::DebugFrame => Some(&mut self.debug_frame.0), + SectionId::EhFrame => Some(&mut self.eh_frame.0), + _ => None, + } + } + + /// For each section, call `f` once with a shared reference. + pub fn for_each<'a, F, E>(&'a self, mut f: F) -> result::Result<(), E> + where + F: FnMut(SectionId, &'a W) -> result::Result<(), E>, + { + macro_rules! f { + ($s:expr) => { + f($s.id(), &$s) + }; + } + // Ordered so that earlier sections do not reference later sections. + f!(self.debug_abbrev)?; + f!(self.debug_str)?; + f!(self.debug_line_str)?; + f!(self.debug_line)?; + f!(self.debug_ranges)?; + f!(self.debug_rnglists)?; + f!(self.debug_loc)?; + f!(self.debug_loclists)?; + f!(self.debug_info)?; + f!(self.debug_frame)?; + f!(self.eh_frame)?; + Ok(()) + } + + /// For each section, call `f` once with a mutable reference. + pub fn for_each_mut<'a, F, E>(&'a mut self, mut f: F) -> result::Result<(), E> + where + F: FnMut(SectionId, &'a mut W) -> result::Result<(), E>, + { + macro_rules! f { + ($s:expr) => { + f($s.id(), &mut $s) + }; + } + // Ordered so that earlier sections do not reference later sections. + f!(self.debug_abbrev)?; + f!(self.debug_str)?; + f!(self.debug_line_str)?; + f!(self.debug_line)?; + f!(self.debug_ranges)?; + f!(self.debug_rnglists)?; + f!(self.debug_loc)?; + f!(self.debug_loclists)?; + f!(self.debug_info)?; + f!(self.debug_frame)?; + f!(self.eh_frame)?; + Ok(()) + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::{read, write::EndianVec, Endianity}; + + impl Sections> { + pub(crate) fn read(&self, endian: E) -> read::Dwarf> { + read::Dwarf::load(|section_id| -> read::Result<_> { + Ok(read::EndianSlice::new( + self.get(section_id).map(|w| w.slice()).unwrap_or_default(), + endian, + )) + }) + .unwrap() + } + } +} diff --git a/deps/crates/vendor/gimli/src/write/str.rs b/deps/crates/vendor/gimli/src/write/str.rs new file mode 100644 index 00000000000000..83285c035f4584 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/str.rs @@ -0,0 +1,172 @@ +use alloc::vec::Vec; +use indexmap::IndexSet; +use std::ops::{Deref, DerefMut}; + +use crate::common::{DebugLineStrOffset, DebugStrOffset, SectionId}; +use crate::write::{BaseId, Result, Section, Writer}; + +// Requirements: +// - values are `[u8]`, null bytes are not allowed +// - insertion returns a fixed id +// - inserting a duplicate returns the id of the existing value +// - able to convert an id to a section offset +// Optional? +// - able to get an existing value given an id +// +// Limitations of current implementation (using IndexSet): +// - inserting requires either an allocation for duplicates, +// or a double lookup for non-duplicates +// - doesn't preserve offsets when updating an existing `.debug_str` section +// +// Possible changes: +// - calculate offsets as we add values, and use that as the id. +// This would avoid the need for DebugStrOffsets but would make it +// hard to implement `get`. +macro_rules! define_string_table { + ($name:ident, $id:ident, $section:ident, $offsets:ident, $docs:expr) => { + #[doc=$docs] + #[derive(Debug, Default)] + pub struct $name { + base_id: BaseId, + strings: IndexSet>, + } + + impl $name { + /// Add a string to the string table and return its id. + /// + /// If the string already exists, then return the id of the existing string. + /// + /// # Panics + /// + /// Panics if `bytes` contains a null byte. + pub fn add(&mut self, bytes: T) -> $id + where + T: Into>, + { + let bytes = bytes.into(); + assert!(!bytes.contains(&0)); + let (index, _) = self.strings.insert_full(bytes); + $id::new(self.base_id, index) + } + + /// Return the number of strings in the table. + #[inline] + pub fn count(&self) -> usize { + self.strings.len() + } + + /// Get a reference to a string in the table. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + pub fn get(&self, id: $id) -> &[u8] { + debug_assert_eq!(self.base_id, id.base_id); + self.strings.get_index(id.index).map(Vec::as_slice).unwrap() + } + + /// Write the string table to the `.debug_str` section. + /// + /// Returns the offsets at which the strings are written. + pub fn write(&self, w: &mut $section) -> Result<$offsets> { + let mut offsets = Vec::new(); + for bytes in self.strings.iter() { + offsets.push(w.offset()); + w.write(bytes)?; + w.write_u8(0)?; + } + + Ok($offsets { + base_id: self.base_id, + offsets, + }) + } + } + }; +} + +define_id!(StringId, "An identifier for a string in a `StringTable`."); + +define_string_table!( + StringTable, + StringId, + DebugStr, + DebugStrOffsets, + "A table of strings that will be stored in a `.debug_str` section." +); + +define_section!(DebugStr, DebugStrOffset, "A writable `.debug_str` section."); + +define_offsets!( + DebugStrOffsets: StringId => DebugStrOffset, + "The section offsets of all strings within a `.debug_str` section." +); + +define_id!( + LineStringId, + "An identifier for a string in a `LineStringTable`." +); + +define_string_table!( + LineStringTable, + LineStringId, + DebugLineStr, + DebugLineStrOffsets, + "A table of strings that will be stored in a `.debug_line_str` section." +); + +define_section!( + DebugLineStr, + DebugLineStrOffset, + "A writable `.debug_line_str` section." +); + +define_offsets!( + DebugLineStrOffsets: LineStringId => DebugLineStrOffset, + "The section offsets of all strings within a `.debug_line_str` section." +); + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::read; + use crate::write::EndianVec; + use crate::LittleEndian; + + #[test] + fn test_string_table() { + let mut strings = StringTable::default(); + assert_eq!(strings.count(), 0); + let id1 = strings.add(&b"one"[..]); + let id2 = strings.add(&b"two"[..]); + assert_eq!(strings.add(&b"one"[..]), id1); + assert_eq!(strings.add(&b"two"[..]), id2); + assert_eq!(strings.get(id1), &b"one"[..]); + assert_eq!(strings.get(id2), &b"two"[..]); + assert_eq!(strings.count(), 2); + + let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); + let offsets = strings.write(&mut debug_str).unwrap(); + assert_eq!(debug_str.slice(), b"one\0two\0"); + assert_eq!(offsets.get(id1), DebugStrOffset(0)); + assert_eq!(offsets.get(id2), DebugStrOffset(4)); + assert_eq!(offsets.count(), 2); + } + + #[test] + fn test_string_table_read() { + let mut strings = StringTable::default(); + let id1 = strings.add(&b"one"[..]); + let id2 = strings.add(&b"two"[..]); + + let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); + let offsets = strings.write(&mut debug_str).unwrap(); + + let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); + let str1 = read_debug_str.get_str(offsets.get(id1)).unwrap(); + let str2 = read_debug_str.get_str(offsets.get(id2)).unwrap(); + assert_eq!(str1.slice(), &b"one"[..]); + assert_eq!(str2.slice(), &b"two"[..]); + } +} diff --git a/deps/crates/vendor/gimli/src/write/unit.rs b/deps/crates/vendor/gimli/src/write/unit.rs new file mode 100644 index 00000000000000..c7f54e96f18157 --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/unit.rs @@ -0,0 +1,3034 @@ +use alloc::vec::Vec; +use std::ops::{Deref, DerefMut}; +use std::slice; + +use crate::common::{ + DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset, + DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId, +}; +use crate::constants; +use crate::leb128::write::{sleb128_size, uleb128_size}; +use crate::write::{ + Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets, + DebugStrOffsets, Error, Expression, FileId, LineProgram, LineStringId, LocationListId, + LocationListOffsets, LocationListTable, RangeListId, RangeListOffsets, RangeListTable, + Reference, Result, Section, Sections, StringId, Writer, +}; + +define_id!(UnitId, "An identifier for a unit in a `UnitTable`."); + +define_id!(UnitEntryId, "An identifier for an entry in a `Unit`."); + +/// A table of units that will be stored in the `.debug_info` section. +#[derive(Debug, Default)] +pub struct UnitTable { + base_id: BaseId, + units: Vec, +} + +impl UnitTable { + /// Create a new unit and add it to the table. + /// + /// `address_size` must be in bytes. + /// + /// Returns the `UnitId` of the new unit. + #[inline] + pub fn add(&mut self, unit: Unit) -> UnitId { + let id = UnitId::new(self.base_id, self.units.len()); + self.units.push(unit); + id + } + + /// Return the number of units. + #[inline] + pub fn count(&self) -> usize { + self.units.len() + } + + /// Return the id of a unit. + /// + /// # Panics + /// + /// Panics if `index >= self.count()`. + #[inline] + pub fn id(&self, index: usize) -> UnitId { + assert!(index < self.count()); + UnitId::new(self.base_id, index) + } + + /// Get a reference to a unit. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get(&self, id: UnitId) -> &Unit { + debug_assert_eq!(self.base_id, id.base_id); + &self.units[id.index] + } + + /// Get a mutable reference to a unit. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get_mut(&mut self, id: UnitId) -> &mut Unit { + debug_assert_eq!(self.base_id, id.base_id); + &mut self.units[id.index] + } + + /// Get an iterator for the units. + pub fn iter(&self) -> impl Iterator { + self.units + .iter() + .enumerate() + .map(move |(index, unit)| (UnitId::new(self.base_id, index), unit)) + } + + /// Get a mutable iterator for the units. + pub fn iter_mut(&mut self) -> impl Iterator { + let base_id = self.base_id; + self.units + .iter_mut() + .enumerate() + .map(move |(index, unit)| (UnitId::new(base_id, index), unit)) + } + + /// Write the units to the given sections. + /// + /// `strings` must contain the `.debug_str` offsets of the corresponding + /// `StringTable`. + pub fn write( + &mut self, + sections: &mut Sections, + line_strings: &DebugLineStrOffsets, + strings: &DebugStrOffsets, + ) -> Result { + let mut offsets = DebugInfoOffsets { + base_id: self.base_id, + units: Vec::new(), + }; + for unit in &mut self.units { + // TODO: maybe share abbreviation tables + let abbrev_offset = sections.debug_abbrev.offset(); + let mut abbrevs = AbbreviationTable::default(); + + offsets.units.push(unit.write( + sections, + abbrev_offset, + &mut abbrevs, + line_strings, + strings, + )?); + + abbrevs.write(&mut sections.debug_abbrev)?; + } + + write_section_refs( + &mut sections.debug_info_refs, + &mut sections.debug_info.0, + &offsets, + )?; + write_section_refs( + &mut sections.debug_loc_refs, + &mut sections.debug_loc.0, + &offsets, + )?; + write_section_refs( + &mut sections.debug_loclists_refs, + &mut sections.debug_loclists.0, + &offsets, + )?; + + Ok(offsets) + } +} + +fn write_section_refs( + references: &mut Vec, + w: &mut W, + offsets: &DebugInfoOffsets, +) -> Result<()> { + for r in references.drain(..) { + let entry_offset = offsets.entry(r.unit, r.entry).0; + debug_assert_ne!(entry_offset, 0); + w.write_offset_at(r.offset, entry_offset, SectionId::DebugInfo, r.size)?; + } + Ok(()) +} + +/// A unit's debugging information. +#[derive(Debug)] +pub struct Unit { + base_id: BaseId, + /// The encoding parameters for this unit. + encoding: Encoding, + /// The line number program for this unit. + pub line_program: LineProgram, + /// A table of range lists used by this unit. + pub ranges: RangeListTable, + /// A table of location lists used by this unit. + pub locations: LocationListTable, + /// All entries in this unit. The order is unrelated to the tree order. + // Requirements: + // - entries form a tree + // - entries can be added in any order + // - entries have a fixed id + // - able to quickly lookup an entry from its id + // Limitations of current implementation: + // - mutable iteration of children is messy due to borrow checker + entries: Vec, + /// The index of the root entry in entries. + root: UnitEntryId, +} + +impl Unit { + /// Create a new `Unit`. + pub fn new(encoding: Encoding, line_program: LineProgram) -> Self { + let base_id = BaseId::default(); + let ranges = RangeListTable::default(); + let locations = LocationListTable::default(); + let mut entries = Vec::new(); + let root = DebuggingInformationEntry::new( + base_id, + &mut entries, + None, + constants::DW_TAG_compile_unit, + ); + Unit { + base_id, + encoding, + line_program, + ranges, + locations, + entries, + root, + } + } + + /// Return the encoding parameters for this unit. + #[inline] + pub fn encoding(&self) -> Encoding { + self.encoding + } + + /// Return the DWARF version for this unit. + #[inline] + pub fn version(&self) -> u16 { + self.encoding.version + } + + /// Return the address size in bytes for this unit. + #[inline] + pub fn address_size(&self) -> u8 { + self.encoding.address_size + } + + /// Return the DWARF format for this unit. + #[inline] + pub fn format(&self) -> Format { + self.encoding.format + } + + /// Return the number of `DebuggingInformationEntry`s created for this unit. + /// + /// This includes entries that no longer have a parent. + #[inline] + pub fn count(&self) -> usize { + self.entries.len() + } + + /// Return the id of the root entry. + #[inline] + pub fn root(&self) -> UnitEntryId { + self.root + } + + /// Add a new `DebuggingInformationEntry` to this unit and return its id. + /// + /// The `parent` must be within the same unit. + /// + /// # Panics + /// + /// Panics if `parent` is invalid. + #[inline] + pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId { + debug_assert_eq!(self.base_id, parent.base_id); + DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag) + } + + /// Get a reference to an entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry { + debug_assert_eq!(self.base_id, id.base_id); + &self.entries[id.index] + } + + /// Get a mutable reference to an entry. + /// + /// # Panics + /// + /// Panics if `id` is invalid. + #[inline] + pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry { + debug_assert_eq!(self.base_id, id.base_id); + &mut self.entries[id.index] + } + + /// Return true if `self.line_program` is used by a DIE. + fn line_program_in_use(&self) -> bool { + if self.line_program.is_none() { + return false; + } + if !self.line_program.is_empty() { + return true; + } + + for entry in &self.entries { + for attr in &entry.attrs { + if let AttributeValue::FileIndex(Some(_)) = attr.value { + return true; + } + } + } + + false + } + + /// Write the unit to the given sections. + pub(crate) fn write( + &mut self, + sections: &mut Sections, + abbrev_offset: DebugAbbrevOffset, + abbrevs: &mut AbbreviationTable, + line_strings: &DebugLineStrOffsets, + strings: &DebugStrOffsets, + ) -> Result { + let line_program = if self.line_program_in_use() { + self.entries[self.root.index] + .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + Some(self.line_program.write( + &mut sections.debug_line, + self.encoding, + line_strings, + strings, + )?) + } else { + self.entries[self.root.index].delete(constants::DW_AT_stmt_list); + None + }; + + // TODO: use .debug_types for type units in DWARF v4. + let w = &mut sections.debug_info; + + let mut offsets = UnitOffsets { + base_id: self.base_id, + unit: w.offset(), + // Entries can be written in any order, so create the complete vec now. + entries: vec![EntryOffset::none(); self.entries.len()], + }; + + let length_offset = w.write_initial_length(self.format())?; + let length_base = w.len(); + + w.write_u16(self.version())?; + if 2 <= self.version() && self.version() <= 4 { + w.write_offset( + abbrev_offset.0, + SectionId::DebugAbbrev, + self.format().word_size(), + )?; + w.write_u8(self.address_size())?; + } else if self.version() == 5 { + w.write_u8(constants::DW_UT_compile.0)?; + w.write_u8(self.address_size())?; + w.write_offset( + abbrev_offset.0, + SectionId::DebugAbbrev, + self.format().word_size(), + )?; + } else { + return Err(Error::UnsupportedVersion(self.version())); + } + + // Calculate all DIE offsets, so that we are able to output references to them. + // However, references to base types in expressions use ULEB128, so base types + // must be moved to the front before we can calculate offsets. + self.reorder_base_types(); + let mut offset = w.len(); + self.entries[self.root.index].calculate_offsets( + self, + &mut offset, + &mut offsets, + abbrevs, + )?; + + let range_lists = self.ranges.write(sections, self.encoding)?; + // Location lists can't be written until we have DIE offsets. + let loc_lists = self + .locations + .write(sections, self.encoding, Some(&offsets))?; + + let w = &mut sections.debug_info; + let mut unit_refs = Vec::new(); + self.entries[self.root.index].write( + w, + &mut sections.debug_info_refs, + &mut unit_refs, + self, + &mut offsets, + line_program, + line_strings, + strings, + &range_lists, + &loc_lists, + )?; + + let length = (w.len() - length_base) as u64; + w.write_initial_length_at(length_offset, length, self.format())?; + + for (offset, entry) in unit_refs { + // This does not need relocation. + w.write_udata_at( + offset.0, + offsets.unit_offset(entry), + self.format().word_size(), + )?; + } + + Ok(offsets) + } + + /// Reorder base types to come first so that typed stack operations + /// can get their offset. + fn reorder_base_types(&mut self) { + let root = &self.entries[self.root.index]; + let mut root_children = Vec::with_capacity(root.children.len()); + for entry in &root.children { + if self.entries[entry.index].tag == constants::DW_TAG_base_type { + root_children.push(*entry); + } + } + for entry in &root.children { + if self.entries[entry.index].tag != constants::DW_TAG_base_type { + root_children.push(*entry); + } + } + self.entries[self.root.index].children = root_children; + } +} + +/// A Debugging Information Entry (DIE). +/// +/// DIEs have a set of attributes and optionally have children DIEs as well. +/// +/// DIEs form a tree without any cycles. This is enforced by specifying the +/// parent when creating a DIE, and disallowing changes of parent. +#[derive(Debug)] +pub struct DebuggingInformationEntry { + id: UnitEntryId, + parent: Option, + tag: constants::DwTag, + /// Whether to emit `DW_AT_sibling`. + sibling: bool, + attrs: Vec, + children: Vec, +} + +impl DebuggingInformationEntry { + /// Create a new `DebuggingInformationEntry`. + /// + /// # Panics + /// + /// Panics if `parent` is invalid. + #[allow(clippy::new_ret_no_self)] + fn new( + base_id: BaseId, + entries: &mut Vec, + parent: Option, + tag: constants::DwTag, + ) -> UnitEntryId { + let id = UnitEntryId::new(base_id, entries.len()); + entries.push(DebuggingInformationEntry { + id, + parent, + tag, + sibling: false, + attrs: Vec::new(), + children: Vec::new(), + }); + if let Some(parent) = parent { + debug_assert_eq!(base_id, parent.base_id); + assert_ne!(parent, id); + entries[parent.index].children.push(id); + } + id + } + + /// Return the id of this entry. + #[inline] + pub fn id(&self) -> UnitEntryId { + self.id + } + + /// Return the parent of this entry. + #[inline] + pub fn parent(&self) -> Option { + self.parent + } + + /// Return the tag of this entry. + #[inline] + pub fn tag(&self) -> constants::DwTag { + self.tag + } + + /// Return `true` if a `DW_AT_sibling` attribute will be emitted. + #[inline] + pub fn sibling(&self) -> bool { + self.sibling + } + + /// Set whether a `DW_AT_sibling` attribute will be emitted. + /// + /// The attribute will only be emitted if the DIE has children. + #[inline] + pub fn set_sibling(&mut self, sibling: bool) { + self.sibling = sibling; + } + + /// Iterate over the attributes of this entry. + #[inline] + pub fn attrs(&self) -> slice::Iter<'_, Attribute> { + self.attrs.iter() + } + + /// Iterate over the attributes of this entry for modification. + #[inline] + pub fn attrs_mut(&mut self) -> slice::IterMut<'_, Attribute> { + self.attrs.iter_mut() + } + + /// Get an attribute. + pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> { + self.attrs + .iter() + .find(|attr| attr.name == name) + .map(|attr| &attr.value) + } + + /// Get an attribute for modification. + pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> { + self.attrs + .iter_mut() + .find(|attr| attr.name == name) + .map(|attr| &mut attr.value) + } + + /// Set an attribute. + /// + /// Replaces any existing attribute with the same name. + /// + /// # Panics + /// + /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead. + pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) { + assert_ne!(name, constants::DW_AT_sibling); + if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) { + attr.value = value; + return; + } + self.attrs.push(Attribute { name, value }); + } + + /// Delete an attribute. + /// + /// Replaces any existing attribute with the same name. + pub fn delete(&mut self, name: constants::DwAt) { + self.attrs.retain(|x| x.name != name); + } + + /// Iterate over the children of this entry. + /// + /// Note: use `Unit::add` to add a new child to this entry. + #[inline] + pub fn children(&self) -> slice::Iter<'_, UnitEntryId> { + self.children.iter() + } + + /// Delete a child entry and all of its children. + pub fn delete_child(&mut self, id: UnitEntryId) { + self.children.retain(|&child| child != id); + } + + /// Return the type abbreviation for this DIE. + fn abbreviation(&self, encoding: Encoding) -> Result { + let mut attrs = Vec::new(); + + if self.sibling && !self.children.is_empty() { + let form = match encoding.format { + Format::Dwarf32 => constants::DW_FORM_ref4, + Format::Dwarf64 => constants::DW_FORM_ref8, + }; + attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form)); + } + + for attr in &self.attrs { + attrs.push(attr.specification(encoding)?); + } + + Ok(Abbreviation::new( + self.tag, + !self.children.is_empty(), + attrs, + )) + } + + fn calculate_offsets( + &self, + unit: &Unit, + offset: &mut usize, + offsets: &mut UnitOffsets, + abbrevs: &mut AbbreviationTable, + ) -> Result<()> { + offsets.entries[self.id.index].offset = DebugInfoOffset(*offset); + offsets.entries[self.id.index].abbrev = abbrevs.add(self.abbreviation(unit.encoding())?); + *offset += self.size(unit, offsets); + if !self.children.is_empty() { + for child in &self.children { + unit.entries[child.index].calculate_offsets(unit, offset, offsets, abbrevs)?; + } + // Null child + *offset += 1; + } + Ok(()) + } + + fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { + let mut size = uleb128_size(offsets.abbrev(self.id)); + if self.sibling && !self.children.is_empty() { + size += unit.format().word_size() as usize; + } + for attr in &self.attrs { + size += attr.value.size(unit, offsets); + } + size + } + + /// Write the entry to the given sections. + fn write( + &self, + w: &mut DebugInfo, + debug_info_refs: &mut Vec, + unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, + unit: &Unit, + offsets: &mut UnitOffsets, + line_program: Option, + line_strings: &DebugLineStrOffsets, + strings: &DebugStrOffsets, + range_lists: &RangeListOffsets, + loc_lists: &LocationListOffsets, + ) -> Result<()> { + debug_assert_eq!(offsets.debug_info_offset(self.id), w.offset()); + w.write_uleb128(offsets.abbrev(self.id))?; + + let sibling_offset = if self.sibling && !self.children.is_empty() { + let offset = w.offset(); + w.write_udata(0, unit.format().word_size())?; + Some(offset) + } else { + None + }; + + for attr in &self.attrs { + attr.value.write( + w, + debug_info_refs, + unit_refs, + unit, + offsets, + line_program, + line_strings, + strings, + range_lists, + loc_lists, + )?; + } + + if !self.children.is_empty() { + for child in &self.children { + unit.entries[child.index].write( + w, + debug_info_refs, + unit_refs, + unit, + offsets, + line_program, + line_strings, + strings, + range_lists, + loc_lists, + )?; + } + // Null child + w.write_u8(0)?; + } + + if let Some(offset) = sibling_offset { + let next_offset = (w.offset().0 - offsets.unit.0) as u64; + // This does not need relocation. + w.write_udata_at(offset.0, next_offset, unit.format().word_size())?; + } + Ok(()) + } +} + +/// An attribute in a `DebuggingInformationEntry`, consisting of a name and +/// associated value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Attribute { + name: constants::DwAt, + value: AttributeValue, +} + +impl Attribute { + /// Get the name of this attribute. + #[inline] + pub fn name(&self) -> constants::DwAt { + self.name + } + + /// Get the value of this attribute. + #[inline] + pub fn get(&self) -> &AttributeValue { + &self.value + } + + /// Set the value of this attribute. + #[inline] + pub fn set(&mut self, value: AttributeValue) { + self.value = value; + } + + /// Return the type specification for this attribute. + fn specification(&self, encoding: Encoding) -> Result { + Ok(AttributeSpecification::new( + self.name, + self.value.form(encoding)?, + )) + } +} + +/// The value of an attribute in a `DebuggingInformationEntry`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AttributeValue { + /// "Refers to some location in the address space of the described program." + Address(Address), + + /// A slice of an arbitrary number of bytes. + Block(Vec), + + /// A one byte constant data value. How to interpret the byte depends on context. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data1(u8), + + /// A two byte constant data value. How to interpret the bytes depends on context. + /// + /// This value will be converted to the target endian before writing. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data2(u16), + + /// A four byte constant data value. How to interpret the bytes depends on context. + /// + /// This value will be converted to the target endian before writing. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data4(u32), + + /// An eight byte constant data value. How to interpret the bytes depends on context. + /// + /// This value will be converted to the target endian before writing. + /// + /// From section 7 of the standard: "Depending on context, it may be a + /// signed integer, an unsigned integer, a floating-point constant, or + /// anything else." + Data8(u64), + + /// A signed integer constant. + Sdata(i64), + + /// An unsigned integer constant. + Udata(u64), + + /// "The information bytes contain a DWARF expression (see Section 2.5) or + /// location description (see Section 2.6)." + Exprloc(Expression), + + /// A boolean that indicates presence or absence of the attribute. + Flag(bool), + + /// An attribute that is always present. + FlagPresent, + + /// A reference to a `DebuggingInformationEntry` in this unit. + UnitRef(UnitEntryId), + + /// A reference to a `DebuggingInformationEntry` in a potentially different unit. + DebugInfoRef(Reference), + + /// An offset into the `.debug_info` section of the supplementary object file. + /// + /// The API does not currently assist with generating this offset. + /// This variant will be removed from the API once support for writing + /// supplementary object files is implemented. + DebugInfoRefSup(DebugInfoOffset), + + /// A reference to a line number program. + LineProgramRef, + + /// A reference to a location list. + LocationListRef(LocationListId), + + /// An offset into the `.debug_macinfo` section. + /// + /// The API does not currently assist with generating this offset. + /// This variant will be removed from the API once support for writing + /// `.debug_macinfo` sections is implemented. + DebugMacinfoRef(DebugMacinfoOffset), + + /// An offset into the `.debug_macro` section. + /// + /// The API does not currently assist with generating this offset. + /// This variant will be removed from the API once support for writing + /// `.debug_macro` sections is implemented. + DebugMacroRef(DebugMacroOffset), + + /// A reference to a range list. + RangeListRef(RangeListId), + + /// A type signature. + /// + /// The API does not currently assist with generating this signature. + /// This variant will be removed from the API once support for writing + /// `.debug_types` sections is implemented. + DebugTypesRef(DebugTypeSignature), + + /// A reference to a string in the `.debug_str` section. + StringRef(StringId), + + /// An offset into the `.debug_str` section of the supplementary object file. + /// + /// The API does not currently assist with generating this offset. + /// This variant will be removed from the API once support for writing + /// supplementary object files is implemented. + DebugStrRefSup(DebugStrOffset), + + /// A reference to a string in the `.debug_line_str` section. + LineStringRef(LineStringId), + + /// A slice of bytes representing a string. Must not include null bytes. + /// Not guaranteed to be UTF-8 or anything like that. + String(Vec), + + /// The value of a `DW_AT_encoding` attribute. + Encoding(constants::DwAte), + + /// The value of a `DW_AT_decimal_sign` attribute. + DecimalSign(constants::DwDs), + + /// The value of a `DW_AT_endianity` attribute. + Endianity(constants::DwEnd), + + /// The value of a `DW_AT_accessibility` attribute. + Accessibility(constants::DwAccess), + + /// The value of a `DW_AT_visibility` attribute. + Visibility(constants::DwVis), + + /// The value of a `DW_AT_virtuality` attribute. + Virtuality(constants::DwVirtuality), + + /// The value of a `DW_AT_language` attribute. + Language(constants::DwLang), + + /// The value of a `DW_AT_address_class` attribute. + AddressClass(constants::DwAddr), + + /// The value of a `DW_AT_identifier_case` attribute. + IdentifierCase(constants::DwId), + + /// The value of a `DW_AT_calling_convention` attribute. + CallingConvention(constants::DwCc), + + /// The value of a `DW_AT_inline` attribute. + Inline(constants::DwInl), + + /// The value of a `DW_AT_ordering` attribute. + Ordering(constants::DwOrd), + + /// An index into the filename entries from the line number information + /// table for the unit containing this value. + FileIndex(Option), +} + +impl AttributeValue { + /// Return the form that will be used to encode this value. + pub fn form(&self, encoding: Encoding) -> Result { + // TODO: missing forms: + // - DW_FORM_indirect + // - DW_FORM_implicit_const + // - FW_FORM_block1/block2/block4 + // - DW_FORM_str/strx1/strx2/strx3/strx4 + // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4 + // - DW_FORM_data16 + // - DW_FORM_line_strp + // - DW_FORM_loclistx + // - DW_FORM_rnglistx + let form = match *self { + AttributeValue::Address(_) => constants::DW_FORM_addr, + AttributeValue::Block(_) => constants::DW_FORM_block, + AttributeValue::Data1(_) => constants::DW_FORM_data1, + AttributeValue::Data2(_) => constants::DW_FORM_data2, + AttributeValue::Data4(_) => constants::DW_FORM_data4, + AttributeValue::Data8(_) => constants::DW_FORM_data8, + AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc, + AttributeValue::Flag(_) => constants::DW_FORM_flag, + AttributeValue::FlagPresent => constants::DW_FORM_flag_present, + AttributeValue::UnitRef(_) => { + // Using a fixed size format lets us write a placeholder before we know + // the value. + match encoding.format { + Format::Dwarf32 => constants::DW_FORM_ref4, + Format::Dwarf64 => constants::DW_FORM_ref8, + } + } + AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr, + AttributeValue::DebugInfoRefSup(_) => { + // TODO: should this depend on the size of supplementary section? + match encoding.format { + Format::Dwarf32 => constants::DW_FORM_ref_sup4, + Format::Dwarf64 => constants::DW_FORM_ref_sup8, + } + } + AttributeValue::LineProgramRef + | AttributeValue::LocationListRef(_) + | AttributeValue::DebugMacinfoRef(_) + | AttributeValue::DebugMacroRef(_) + | AttributeValue::RangeListRef(_) => { + if encoding.version == 2 || encoding.version == 3 { + match encoding.format { + Format::Dwarf32 => constants::DW_FORM_data4, + Format::Dwarf64 => constants::DW_FORM_data8, + } + } else { + constants::DW_FORM_sec_offset + } + } + AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8, + AttributeValue::StringRef(_) => constants::DW_FORM_strp, + AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup, + AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp, + AttributeValue::String(_) => constants::DW_FORM_string, + AttributeValue::Encoding(_) + | AttributeValue::DecimalSign(_) + | AttributeValue::Endianity(_) + | AttributeValue::Accessibility(_) + | AttributeValue::Visibility(_) + | AttributeValue::Virtuality(_) + | AttributeValue::Language(_) + | AttributeValue::AddressClass(_) + | AttributeValue::IdentifierCase(_) + | AttributeValue::CallingConvention(_) + | AttributeValue::Inline(_) + | AttributeValue::Ordering(_) + | AttributeValue::FileIndex(_) + | AttributeValue::Udata(_) => constants::DW_FORM_udata, + AttributeValue::Sdata(_) => constants::DW_FORM_sdata, + }; + Ok(form) + } + + fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { + macro_rules! debug_assert_form { + ($form:expr) => { + debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) + }; + } + match *self { + AttributeValue::Address(_) => { + debug_assert_form!(constants::DW_FORM_addr); + unit.address_size() as usize + } + AttributeValue::Block(ref val) => { + debug_assert_form!(constants::DW_FORM_block); + uleb128_size(val.len() as u64) + val.len() + } + AttributeValue::Data1(_) => { + debug_assert_form!(constants::DW_FORM_data1); + 1 + } + AttributeValue::Data2(_) => { + debug_assert_form!(constants::DW_FORM_data2); + 2 + } + AttributeValue::Data4(_) => { + debug_assert_form!(constants::DW_FORM_data4); + 4 + } + AttributeValue::Data8(_) => { + debug_assert_form!(constants::DW_FORM_data8); + 8 + } + AttributeValue::Sdata(val) => { + debug_assert_form!(constants::DW_FORM_sdata); + sleb128_size(val) + } + AttributeValue::Udata(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val) + } + AttributeValue::Exprloc(ref val) => { + debug_assert_form!(constants::DW_FORM_exprloc); + let size = val.size(unit.encoding(), Some(offsets)); + uleb128_size(size as u64) + size + } + AttributeValue::Flag(_) => { + debug_assert_form!(constants::DW_FORM_flag); + 1 + } + AttributeValue::FlagPresent => { + debug_assert_form!(constants::DW_FORM_flag_present); + 0 + } + AttributeValue::UnitRef(_) => { + match unit.format() { + Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), + Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), + } + unit.format().word_size() as usize + } + AttributeValue::DebugInfoRef(_) => { + debug_assert_form!(constants::DW_FORM_ref_addr); + if unit.version() == 2 { + unit.address_size() as usize + } else { + unit.format().word_size() as usize + } + } + AttributeValue::DebugInfoRefSup(_) => { + match unit.format() { + Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), + Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), + } + unit.format().word_size() as usize + } + AttributeValue::LineProgramRef => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + unit.format().word_size() as usize + } + AttributeValue::LocationListRef(_) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + unit.format().word_size() as usize + } + AttributeValue::DebugMacinfoRef(_) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + unit.format().word_size() as usize + } + AttributeValue::DebugMacroRef(_) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + unit.format().word_size() as usize + } + AttributeValue::RangeListRef(_) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + unit.format().word_size() as usize + } + AttributeValue::DebugTypesRef(_) => { + debug_assert_form!(constants::DW_FORM_ref_sig8); + 8 + } + AttributeValue::StringRef(_) => { + debug_assert_form!(constants::DW_FORM_strp); + unit.format().word_size() as usize + } + AttributeValue::DebugStrRefSup(_) => { + debug_assert_form!(constants::DW_FORM_strp_sup); + unit.format().word_size() as usize + } + AttributeValue::LineStringRef(_) => { + debug_assert_form!(constants::DW_FORM_line_strp); + unit.format().word_size() as usize + } + AttributeValue::String(ref val) => { + debug_assert_form!(constants::DW_FORM_string); + val.len() + 1 + } + AttributeValue::Encoding(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::DecimalSign(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Endianity(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Accessibility(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Visibility(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Virtuality(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Language(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::AddressClass(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0) + } + AttributeValue::IdentifierCase(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::CallingConvention(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Inline(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::Ordering(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.0 as u64) + } + AttributeValue::FileIndex(val) => { + debug_assert_form!(constants::DW_FORM_udata); + uleb128_size(val.map(|id| id.raw(unit.version())).unwrap_or(0)) + } + } + } + + /// Write the attribute value to the given sections. + fn write( + &self, + w: &mut DebugInfo, + debug_info_refs: &mut Vec, + unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, + unit: &Unit, + offsets: &UnitOffsets, + line_program: Option, + line_strings: &DebugLineStrOffsets, + strings: &DebugStrOffsets, + range_lists: &RangeListOffsets, + loc_lists: &LocationListOffsets, + ) -> Result<()> { + macro_rules! debug_assert_form { + ($form:expr) => { + debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) + }; + } + match *self { + AttributeValue::Address(val) => { + debug_assert_form!(constants::DW_FORM_addr); + w.write_address(val, unit.address_size())?; + } + AttributeValue::Block(ref val) => { + debug_assert_form!(constants::DW_FORM_block); + w.write_uleb128(val.len() as u64)?; + w.write(val)?; + } + AttributeValue::Data1(val) => { + debug_assert_form!(constants::DW_FORM_data1); + w.write_u8(val)?; + } + AttributeValue::Data2(val) => { + debug_assert_form!(constants::DW_FORM_data2); + w.write_u16(val)?; + } + AttributeValue::Data4(val) => { + debug_assert_form!(constants::DW_FORM_data4); + w.write_u32(val)?; + } + AttributeValue::Data8(val) => { + debug_assert_form!(constants::DW_FORM_data8); + w.write_u64(val)?; + } + AttributeValue::Sdata(val) => { + debug_assert_form!(constants::DW_FORM_sdata); + w.write_sleb128(val)?; + } + AttributeValue::Udata(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(val)?; + } + AttributeValue::Exprloc(ref val) => { + debug_assert_form!(constants::DW_FORM_exprloc); + w.write_uleb128(val.size(unit.encoding(), Some(offsets)) as u64)?; + val.write( + &mut w.0, + Some(debug_info_refs), + unit.encoding(), + Some(offsets), + )?; + } + AttributeValue::Flag(val) => { + debug_assert_form!(constants::DW_FORM_flag); + w.write_u8(val as u8)?; + } + AttributeValue::FlagPresent => { + debug_assert_form!(constants::DW_FORM_flag_present); + } + AttributeValue::UnitRef(id) => { + match unit.format() { + Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), + Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), + } + unit_refs.push((w.offset(), id)); + w.write_udata(0, unit.format().word_size())?; + } + AttributeValue::DebugInfoRef(reference) => { + debug_assert_form!(constants::DW_FORM_ref_addr); + let size = if unit.version() == 2 { + unit.address_size() + } else { + unit.format().word_size() + }; + match reference { + Reference::Symbol(symbol) => w.write_reference(symbol, size)?, + Reference::Entry(unit, entry) => { + debug_info_refs.push(DebugInfoReference { + offset: w.len(), + unit, + entry, + size, + }); + w.write_udata(0, size)?; + } + } + } + AttributeValue::DebugInfoRefSup(val) => { + match unit.format() { + Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), + Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), + } + w.write_udata(val.0 as u64, unit.format().word_size())?; + } + AttributeValue::LineProgramRef => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + match line_program { + Some(line_program) => { + w.write_offset( + line_program.0, + SectionId::DebugLine, + unit.format().word_size(), + )?; + } + None => return Err(Error::InvalidAttributeValue), + } + } + AttributeValue::LocationListRef(val) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + let section = if unit.version() <= 4 { + SectionId::DebugLoc + } else { + SectionId::DebugLocLists + }; + w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?; + } + AttributeValue::DebugMacinfoRef(val) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?; + } + AttributeValue::DebugMacroRef(val) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?; + } + AttributeValue::RangeListRef(val) => { + if unit.version() >= 4 { + debug_assert_form!(constants::DW_FORM_sec_offset); + } + let section = if unit.version() <= 4 { + SectionId::DebugRanges + } else { + SectionId::DebugRngLists + }; + w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?; + } + AttributeValue::DebugTypesRef(val) => { + debug_assert_form!(constants::DW_FORM_ref_sig8); + w.write_u64(val.0)?; + } + AttributeValue::StringRef(val) => { + debug_assert_form!(constants::DW_FORM_strp); + w.write_offset( + strings.get(val).0, + SectionId::DebugStr, + unit.format().word_size(), + )?; + } + AttributeValue::DebugStrRefSup(val) => { + debug_assert_form!(constants::DW_FORM_strp_sup); + w.write_udata(val.0 as u64, unit.format().word_size())?; + } + AttributeValue::LineStringRef(val) => { + debug_assert_form!(constants::DW_FORM_line_strp); + w.write_offset( + line_strings.get(val).0, + SectionId::DebugLineStr, + unit.format().word_size(), + )?; + } + AttributeValue::String(ref val) => { + debug_assert_form!(constants::DW_FORM_string); + w.write(val)?; + w.write_u8(0)?; + } + AttributeValue::Encoding(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::DecimalSign(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Endianity(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Accessibility(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Visibility(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Virtuality(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Language(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::AddressClass(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(val.0)?; + } + AttributeValue::IdentifierCase(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::CallingConvention(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Inline(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::Ordering(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(u64::from(val.0))?; + } + AttributeValue::FileIndex(val) => { + debug_assert_form!(constants::DW_FORM_udata); + w.write_uleb128(val.map(|id| id.raw(unit.version())).unwrap_or(0))?; + } + } + Ok(()) + } +} + +define_section!( + DebugInfo, + DebugInfoOffset, + "A writable `.debug_info` section." +); + +/// The section offsets of all elements within a `.debug_info` section. +#[derive(Debug, Default)] +pub struct DebugInfoOffsets { + base_id: BaseId, + units: Vec, +} + +impl DebugInfoOffsets { + /// Get the `.debug_info` section offset for the given unit. + #[inline] + pub fn unit(&self, unit: UnitId) -> DebugInfoOffset { + debug_assert_eq!(self.base_id, unit.base_id); + self.units[unit.index].unit + } + + /// Get the `.debug_info` section offset for the given entry. + #[inline] + pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset { + debug_assert_eq!(self.base_id, unit.base_id); + self.units[unit.index].debug_info_offset(entry) + } +} + +/// The section offsets of all elements of a unit within a `.debug_info` section. +#[derive(Debug)] +pub(crate) struct UnitOffsets { + base_id: BaseId, + unit: DebugInfoOffset, + entries: Vec, +} + +impl UnitOffsets { + /// Get the .debug_info offset for the given entry. + #[inline] + pub(crate) fn debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset { + debug_assert_eq!(self.base_id, entry.base_id); + let offset = self.entries[entry.index].offset; + debug_assert_ne!(offset.0, 0); + offset + } + + /// Get the unit offset for the given entry. + #[inline] + pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> u64 { + let offset = self.debug_info_offset(entry); + (offset.0 - self.unit.0) as u64 + } + + /// Get the abbreviation code for the given entry. + #[inline] + pub(crate) fn abbrev(&self, entry: UnitEntryId) -> u64 { + debug_assert_eq!(self.base_id, entry.base_id); + self.entries[entry.index].abbrev + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct EntryOffset { + offset: DebugInfoOffset, + abbrev: u64, +} + +impl EntryOffset { + fn none() -> Self { + EntryOffset { + offset: DebugInfoOffset(0), + abbrev: 0, + } + } +} + +/// A reference to a `.debug_info` entry that has yet to be resolved. +#[derive(Debug, Clone, Copy)] +pub(crate) struct DebugInfoReference { + /// The offset within the section of the reference. + pub offset: usize, + /// The size of the reference. + pub size: u8, + /// The unit containing the entry. + pub unit: UnitId, + /// The entry being referenced. + pub entry: UnitEntryId, +} + +#[cfg(feature = "read")] +pub(crate) mod convert { + use super::*; + use crate::common::{DwoId, UnitSectionOffset}; + use crate::read::{self, Reader}; + use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList}; + use std::collections::HashMap; + + pub(crate) struct ConvertUnit> { + from_unit: read::Unit, + base_id: BaseId, + encoding: Encoding, + entries: Vec, + entry_offsets: Vec, + root: UnitEntryId, + } + + pub(crate) struct ConvertUnitContext<'a, R: Reader> { + pub dwarf: &'a read::Dwarf, + pub unit: &'a read::Unit, + pub line_strings: &'a mut write::LineStringTable, + pub strings: &'a mut write::StringTable, + pub ranges: &'a mut write::RangeListTable, + pub locations: &'a mut write::LocationListTable, + pub convert_address: &'a dyn Fn(u64) -> Option
, + pub base_address: Address, + pub line_program_offset: Option, + pub line_program_files: Vec, + pub entry_ids: &'a HashMap, + } + + impl UnitTable { + /// Create a unit table by reading the data in the given sections. + /// + /// This also updates the given tables with the values that are referenced from + /// attributes in this section. + /// + /// `convert_address` is a function to convert read addresses into the `Address` + /// type. For non-relocatable addresses, this function may simply return + /// `Address::Constant(address)`. For relocatable addresses, it is the caller's + /// responsibility to determine the symbol and addend corresponding to the address + /// and return `Address::Symbol { symbol, addend }`. + pub fn from>( + dwarf: &read::Dwarf, + line_strings: &mut write::LineStringTable, + strings: &mut write::StringTable, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult { + let base_id = BaseId::default(); + let mut unit_entries = Vec::new(); + let mut entry_ids = HashMap::new(); + + let mut from_units = dwarf.units(); + while let Some(from_unit) = from_units.next()? { + let unit_id = UnitId::new(base_id, unit_entries.len()); + unit_entries.push(Unit::convert_entries( + from_unit, + unit_id, + &mut entry_ids, + dwarf, + )?); + } + + // Attributes must be converted in a separate pass so that we can handle + // references to other compilation units. + let mut units = Vec::new(); + for unit_entries in unit_entries.drain(..) { + units.push(Unit::convert_attributes( + unit_entries, + &entry_ids, + dwarf, + line_strings, + strings, + convert_address, + )?); + } + + Ok(UnitTable { base_id, units }) + } + } + + impl Unit { + /// Create a unit by reading the data in the input sections. + /// + /// Does not add entry attributes. + pub(crate) fn convert_entries>( + from_header: read::UnitHeader, + unit_id: UnitId, + entry_ids: &mut HashMap, + dwarf: &read::Dwarf, + ) -> ConvertResult> { + match from_header.type_() { + read::UnitType::Compilation => (), + _ => return Err(ConvertError::UnsupportedUnitType), + } + let base_id = BaseId::default(); + + let from_unit = dwarf.unit(from_header)?; + let encoding = from_unit.encoding(); + + let mut entries = Vec::new(); + let mut entry_offsets = Vec::new(); + + let mut from_tree = from_unit.entries_tree(None)?; + let from_root = from_tree.root()?; + let root = DebuggingInformationEntry::convert_entry( + from_root, + &from_unit, + base_id, + &mut entries, + &mut entry_offsets, + entry_ids, + None, + unit_id, + )?; + + Ok(ConvertUnit { + from_unit, + base_id, + encoding, + entries, + entry_offsets, + root, + }) + } + + /// Create entry attributes by reading the data in the input sections. + fn convert_attributes>( + unit: ConvertUnit, + entry_ids: &HashMap, + dwarf: &read::Dwarf, + line_strings: &mut write::LineStringTable, + strings: &mut write::StringTable, + convert_address: &dyn Fn(u64) -> Option
, + ) -> ConvertResult { + let from_unit = unit.from_unit; + let base_address = + convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?; + + let (line_program_offset, line_program, line_program_files) = + match from_unit.line_program { + Some(ref from_program) => { + let from_program = from_program.clone(); + let line_program_offset = from_program.header().offset(); + let (line_program, line_program_files) = LineProgram::from( + from_program, + dwarf, + line_strings, + strings, + convert_address, + )?; + (Some(line_program_offset), line_program, line_program_files) + } + None => (None, LineProgram::none(), Vec::new()), + }; + + let mut ranges = RangeListTable::default(); + let mut locations = LocationListTable::default(); + + let mut context = ConvertUnitContext { + entry_ids, + dwarf, + unit: &from_unit, + line_strings, + strings, + ranges: &mut ranges, + locations: &mut locations, + convert_address, + base_address, + line_program_offset, + line_program_files, + }; + + let mut entries = unit.entries; + for entry in &mut entries { + entry.convert_attributes(&mut context, &unit.entry_offsets)?; + } + + Ok(Unit { + base_id: unit.base_id, + encoding: unit.encoding, + line_program, + ranges, + locations, + entries, + root: unit.root, + }) + } + } + + impl DebuggingInformationEntry { + /// Create an entry by reading the data in the input sections. + /// + /// Does not add the entry attributes. + fn convert_entry>( + from: read::EntriesTreeNode<'_, '_, '_, R>, + from_unit: &read::Unit, + base_id: BaseId, + entries: &mut Vec, + entry_offsets: &mut Vec, + entry_ids: &mut HashMap, + parent: Option, + unit_id: UnitId, + ) -> ConvertResult { + let from_entry = from.entry(); + let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag()); + let offset = from_entry.offset(); + entry_offsets.push(offset); + entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id)); + + let mut from_children = from.children(); + while let Some(from_child) = from_children.next()? { + DebuggingInformationEntry::convert_entry( + from_child, + from_unit, + base_id, + entries, + entry_offsets, + entry_ids, + Some(id), + unit_id, + )?; + } + Ok(id) + } + + /// Create an entry's attributes by reading the data in the input sections. + fn convert_attributes>( + &mut self, + context: &mut ConvertUnitContext<'_, R>, + entry_offsets: &[read::UnitOffset], + ) -> ConvertResult<()> { + let offset = entry_offsets[self.id.index]; + let from = context.unit.entry(offset)?; + let mut from_attrs = from.attrs(); + while let Some(from_attr) = from_attrs.next()? { + if from_attr.name() == constants::DW_AT_sibling { + // This may point to a null entry, so we have to treat it differently. + self.set_sibling(true); + } else if let Some(attr) = Attribute::from(context, &from_attr)? { + self.set(attr.name, attr.value); + } + } + Ok(()) + } + } + + impl Attribute { + /// Create an attribute by reading the data in the given sections. + pub(crate) fn from>( + context: &mut ConvertUnitContext<'_, R>, + from: &read::Attribute, + ) -> ConvertResult> { + let value = AttributeValue::from(context, from.value())?; + Ok(value.map(|value| Attribute { + name: from.name(), + value, + })) + } + } + + impl AttributeValue { + /// Create an attribute value by reading the data in the given sections. + pub(crate) fn from>( + context: &mut ConvertUnitContext<'_, R>, + from: read::AttributeValue, + ) -> ConvertResult> { + let to = match from { + read::AttributeValue::Addr(val) => match (context.convert_address)(val) { + Some(val) => AttributeValue::Address(val), + None => return Err(ConvertError::InvalidAddress), + }, + read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()), + read::AttributeValue::Data1(val) => AttributeValue::Data1(val), + read::AttributeValue::Data2(val) => AttributeValue::Data2(val), + read::AttributeValue::Data4(val) => AttributeValue::Data4(val), + read::AttributeValue::Data8(val) => AttributeValue::Data8(val), + read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val), + read::AttributeValue::Udata(val) => AttributeValue::Udata(val), + read::AttributeValue::Exprloc(expression) => { + let expression = Expression::from( + expression, + context.unit.encoding(), + Some(context.dwarf), + Some(context.unit), + Some(context.entry_ids), + context.convert_address, + )?; + AttributeValue::Exprloc(expression) + } + // TODO: it would be nice to preserve the flag form. + read::AttributeValue::Flag(val) => AttributeValue::Flag(val), + read::AttributeValue::DebugAddrBase(_base) => { + // We convert all address indices to addresses, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugAddrIndex(index) => { + let val = context.dwarf.address(context.unit, index)?; + match (context.convert_address)(val) { + Some(val) => AttributeValue::Address(val), + None => return Err(ConvertError::InvalidAddress), + } + } + read::AttributeValue::UnitRef(val) => { + if !context.unit.header.is_valid_offset(val) { + return Err(ConvertError::InvalidUnitRef); + } + let id = context + .entry_ids + .get(&val.to_unit_section_offset(context.unit)) + .ok_or(ConvertError::InvalidUnitRef)?; + AttributeValue::UnitRef(id.1) + } + read::AttributeValue::DebugInfoRef(val) => { + // TODO: support relocation of this value + let id = context + .entry_ids + .get(&UnitSectionOffset::DebugInfoOffset(val)) + .ok_or(ConvertError::InvalidDebugInfoRef)?; + AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1)) + } + read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val), + read::AttributeValue::DebugLineRef(val) => { + // There should only be the line program in the CU DIE which we've already + // converted, so check if it matches that. + if Some(val) == context.line_program_offset { + AttributeValue::LineProgramRef + } else { + return Err(ConvertError::InvalidLineRef); + } + } + read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val), + read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val), + read::AttributeValue::LocationListsRef(val) => { + let iter = context + .dwarf + .locations + .raw_locations(val, context.unit.encoding())?; + let loc_list = LocationList::from(iter, context)?; + let loc_id = context.locations.add(loc_list); + AttributeValue::LocationListRef(loc_id) + } + read::AttributeValue::DebugLocListsBase(_base) => { + // We convert all location list indices to offsets, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugLocListsIndex(index) => { + let offset = context.dwarf.locations_offset(context.unit, index)?; + let iter = context + .dwarf + .locations + .raw_locations(offset, context.unit.encoding())?; + let loc_list = LocationList::from(iter, context)?; + let loc_id = context.locations.add(loc_list); + AttributeValue::LocationListRef(loc_id) + } + read::AttributeValue::RangeListsRef(offset) => { + let offset = context.dwarf.ranges_offset_from_raw(context.unit, offset); + let iter = context.dwarf.raw_ranges(context.unit, offset)?; + let range_list = RangeList::from(iter, context)?; + let range_id = context.ranges.add(range_list); + AttributeValue::RangeListRef(range_id) + } + read::AttributeValue::DebugRngListsBase(_base) => { + // We convert all range list indices to offsets, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugRngListsIndex(index) => { + let offset = context.dwarf.ranges_offset(context.unit, index)?; + let iter = context + .dwarf + .ranges + .raw_ranges(offset, context.unit.encoding())?; + let range_list = RangeList::from(iter, context)?; + let range_id = context.ranges.add(range_list); + AttributeValue::RangeListRef(range_id) + } + read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val), + read::AttributeValue::DebugStrRef(offset) => { + let r = context.dwarf.string(offset)?; + let id = context.strings.add(r.to_slice()?); + AttributeValue::StringRef(id) + } + read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val), + read::AttributeValue::DebugStrOffsetsBase(_base) => { + // We convert all string offsets to `.debug_str` references, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugStrOffsetsIndex(index) => { + let offset = context.dwarf.string_offset(context.unit, index)?; + let r = context.dwarf.string(offset)?; + let id = context.strings.add(r.to_slice()?); + AttributeValue::StringRef(id) + } + read::AttributeValue::DebugLineStrRef(offset) => { + let r = context.dwarf.line_string(offset)?; + let id = context.line_strings.add(r.to_slice()?); + AttributeValue::LineStringRef(id) + } + read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()), + read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val), + read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val), + read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val), + read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val), + read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val), + read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val), + read::AttributeValue::Language(val) => AttributeValue::Language(val), + read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val), + read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val), + read::AttributeValue::CallingConvention(val) => { + AttributeValue::CallingConvention(val) + } + read::AttributeValue::Inline(val) => AttributeValue::Inline(val), + read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val), + read::AttributeValue::FileIndex(val) => { + if val == 0 && context.unit.encoding().version <= 4 { + AttributeValue::FileIndex(None) + } else { + match context.line_program_files.get(val as usize) { + Some(id) => AttributeValue::FileIndex(Some(*id)), + None => return Err(ConvertError::InvalidFileIndex), + } + } + } + // Should always be a more specific section reference. + read::AttributeValue::SecOffset(_) => { + return Err(ConvertError::InvalidAttributeValue); + } + read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val), + }; + Ok(Some(to)) + } + } +} + +#[cfg(test)] +#[cfg(feature = "read")] +mod tests { + use super::*; + use crate::common::LineEncoding; + use crate::constants; + use crate::read; + use crate::write::{ + Dwarf, DwarfUnit, EndianVec, LineString, Location, LocationList, Range, RangeList, + }; + use crate::LittleEndian; + use std::mem; + + #[test] + fn test_unit_table() { + let mut dwarf = Dwarf::new(); + let unit_id1 = dwarf.units.add(Unit::new( + Encoding { + version: 4, + address_size: 8, + format: Format::Dwarf32, + }, + LineProgram::none(), + )); + let unit2 = dwarf.units.add(Unit::new( + Encoding { + version: 2, + address_size: 4, + format: Format::Dwarf64, + }, + LineProgram::none(), + )); + let unit3 = dwarf.units.add(Unit::new( + Encoding { + version: 5, + address_size: 4, + format: Format::Dwarf32, + }, + LineProgram::none(), + )); + assert_eq!(dwarf.units.count(), 3); + { + let unit1 = dwarf.units.get_mut(unit_id1); + assert_eq!(unit1.version(), 4); + assert_eq!(unit1.address_size(), 8); + assert_eq!(unit1.format(), Format::Dwarf32); + assert_eq!(unit1.count(), 1); + + let root_id = unit1.root(); + assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0)); + { + let root = unit1.get_mut(root_id); + assert_eq!(root.id(), root_id); + assert!(root.parent().is_none()); + assert_eq!(root.tag(), constants::DW_TAG_compile_unit); + + // Test get/get_mut + assert!(root.get(constants::DW_AT_producer).is_none()); + assert!(root.get_mut(constants::DW_AT_producer).is_none()); + let mut producer = AttributeValue::String(b"root"[..].into()); + root.set(constants::DW_AT_producer, producer.clone()); + assert_eq!(root.get(constants::DW_AT_producer), Some(&producer)); + assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer)); + + // Test attrs + let mut attrs = root.attrs(); + let attr = attrs.next().unwrap(); + assert_eq!(attr.name(), constants::DW_AT_producer); + assert_eq!(attr.get(), &producer); + assert!(attrs.next().is_none()); + } + + let child1 = unit1.add(root_id, constants::DW_TAG_subprogram); + assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1)); + { + let child1 = unit1.get_mut(child1); + assert_eq!(child1.parent(), Some(root_id)); + + let tmp = AttributeValue::String(b"tmp"[..].into()); + child1.set(constants::DW_AT_name, tmp.clone()); + assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp)); + + // Test attrs_mut + let name = AttributeValue::StringRef(dwarf.strings.add(&b"child1"[..])); + { + let attr = child1.attrs_mut().next().unwrap(); + assert_eq!(attr.name(), constants::DW_AT_name); + attr.set(name.clone()); + } + assert_eq!(child1.get(constants::DW_AT_name), Some(&name)); + } + + let child2 = unit1.add(root_id, constants::DW_TAG_subprogram); + assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2)); + { + let child2 = unit1.get_mut(child2); + assert_eq!(child2.parent(), Some(root_id)); + + let tmp = AttributeValue::String(b"tmp"[..].into()); + child2.set(constants::DW_AT_name, tmp.clone()); + assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp)); + + // Test replace + let name = AttributeValue::StringRef(dwarf.strings.add(&b"child2"[..])); + child2.set(constants::DW_AT_name, name.clone()); + assert_eq!(child2.get(constants::DW_AT_name), Some(&name)); + } + + { + let root = unit1.get(root_id); + assert_eq!( + root.children().cloned().collect::>(), + vec![child1, child2] + ); + } + } + { + let unit2 = dwarf.units.get(unit2); + assert_eq!(unit2.version(), 2); + assert_eq!(unit2.address_size(), 4); + assert_eq!(unit2.format(), Format::Dwarf64); + assert_eq!(unit2.count(), 1); + + let root = unit2.root(); + assert_eq!(root, UnitEntryId::new(unit2.base_id, 0)); + let root = unit2.get(root); + assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0)); + assert!(root.parent().is_none()); + assert_eq!(root.tag(), constants::DW_TAG_compile_unit); + } + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + println!("{:?}", sections.debug_str); + println!("{:?}", sections.debug_info); + println!("{:?}", sections.debug_abbrev); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + + { + let read_unit1 = read_units.next().unwrap().unwrap(); + let unit1 = dwarf.units.get(unit_id1); + assert_eq!(unit1.version(), read_unit1.version()); + assert_eq!(unit1.address_size(), read_unit1.address_size()); + assert_eq!(unit1.format(), read_unit1.format()); + + let read_unit1 = read_dwarf.unit(read_unit1).unwrap(); + let mut read_entries = read_unit1.entries(); + + let root = unit1.get(unit1.root()); + { + let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(depth, 0); + assert_eq!(root.tag(), read_root.tag()); + assert!(read_root.has_children()); + + let producer = match root.get(constants::DW_AT_producer).unwrap() { + AttributeValue::String(ref producer) => &**producer, + otherwise => panic!("unexpected {:?}", otherwise), + }; + assert_eq!(producer, b"root"); + let read_producer = read_root + .attr_value(constants::DW_AT_producer) + .unwrap() + .unwrap(); + assert_eq!( + read_dwarf + .attr_string(&read_unit1, read_producer) + .unwrap() + .slice(), + producer + ); + } + + let mut children = root.children().cloned(); + + { + let child = children.next().unwrap(); + assert_eq!(child, UnitEntryId::new(unit1.base_id, 1)); + let child = unit1.get(child); + let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(depth, 1); + assert_eq!(child.tag(), read_child.tag()); + assert!(!read_child.has_children()); + + let name = match child.get(constants::DW_AT_name).unwrap() { + AttributeValue::StringRef(name) => *name, + otherwise => panic!("unexpected {:?}", otherwise), + }; + let name = dwarf.strings.get(name); + assert_eq!(name, b"child1"); + let read_name = read_child + .attr_value(constants::DW_AT_name) + .unwrap() + .unwrap(); + assert_eq!( + read_dwarf + .attr_string(&read_unit1, read_name) + .unwrap() + .slice(), + name + ); + } + + { + let child = children.next().unwrap(); + assert_eq!(child, UnitEntryId::new(unit1.base_id, 2)); + let child = unit1.get(child); + let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(depth, 0); + assert_eq!(child.tag(), read_child.tag()); + assert!(!read_child.has_children()); + + let name = match child.get(constants::DW_AT_name).unwrap() { + AttributeValue::StringRef(name) => *name, + otherwise => panic!("unexpected {:?}", otherwise), + }; + let name = dwarf.strings.get(name); + assert_eq!(name, b"child2"); + let read_name = read_child + .attr_value(constants::DW_AT_name) + .unwrap() + .unwrap(); + assert_eq!( + read_dwarf + .attr_string(&read_unit1, read_name) + .unwrap() + .slice(), + name + ); + } + + assert!(read_entries.next_dfs().unwrap().is_none()); + } + + { + let read_unit2 = read_units.next().unwrap().unwrap(); + let unit2 = dwarf.units.get(unit2); + assert_eq!(unit2.version(), read_unit2.version()); + assert_eq!(unit2.address_size(), read_unit2.address_size()); + assert_eq!(unit2.format(), read_unit2.format()); + + let abbrevs = read_dwarf.abbreviations(&read_unit2).unwrap(); + let mut read_entries = read_unit2.entries(&abbrevs); + + { + let root = unit2.get(unit2.root()); + let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(depth, 0); + assert_eq!(root.tag(), read_root.tag()); + assert!(!read_root.has_children()); + } + + assert!(read_entries.next_dfs().unwrap().is_none()); + } + + { + let read_unit3 = read_units.next().unwrap().unwrap(); + let unit3 = dwarf.units.get(unit3); + assert_eq!(unit3.version(), read_unit3.version()); + assert_eq!(unit3.address_size(), read_unit3.address_size()); + assert_eq!(unit3.format(), read_unit3.format()); + + let abbrevs = read_dwarf.abbreviations(&read_unit3).unwrap(); + let mut read_entries = read_unit3.entries(&abbrevs); + + { + let root = unit3.get(unit3.root()); + let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); + assert_eq!(depth, 0); + assert_eq!(root.tag(), read_root.tag()); + assert!(!read_root.has_children()); + } + + assert!(read_entries.next_dfs().unwrap().is_none()); + } + + assert!(read_units.next().unwrap().is_none()); + + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))).unwrap(); + assert_eq!(convert_dwarf.units.count(), dwarf.units.count()); + + for i in 0..convert_dwarf.units.count() { + let unit_id = dwarf.units.id(i); + let unit = dwarf.units.get(unit_id); + let convert_unit_id = convert_dwarf.units.id(i); + let convert_unit = convert_dwarf.units.get(convert_unit_id); + assert_eq!(convert_unit.version(), unit.version()); + assert_eq!(convert_unit.address_size(), unit.address_size()); + assert_eq!(convert_unit.format(), unit.format()); + assert_eq!(convert_unit.count(), unit.count()); + + let root = unit.get(unit.root()); + let convert_root = convert_unit.get(convert_unit.root()); + assert_eq!(convert_root.tag(), root.tag()); + for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { + assert_eq!(convert_attr, attr); + } + } + } + + #[test] + fn test_attribute_value() { + let string_data = "string data"; + let line_string_data = "line string data"; + + let data = vec![1, 2, 3, 4]; + let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian); + + let mut expression = Expression::new(); + expression.op_constu(57); + let read_expression = read::Expression(read::EndianSlice::new( + &[constants::DW_OP_constu.0, 57], + LittleEndian, + )); + + let range = RangeList(vec![Range::StartEnd { + begin: Address::Constant(0x1234), + end: Address::Constant(0x2345), + }]); + + let location = LocationList(vec![Location::StartEnd { + begin: Address::Constant(0x1234), + end: Address::Constant(0x2345), + data: expression.clone(), + }]); + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + let mut dwarf = Dwarf::new(); + let unit = dwarf.units.add(Unit::new(encoding, LineProgram::none())); + let unit = dwarf.units.get_mut(unit); + let loc_id = unit.locations.add(location.clone()); + let range_id = unit.ranges.add(range.clone()); + // Create a string with a non-zero id/offset. + dwarf.strings.add("dummy string"); + let string_id = dwarf.strings.add(string_data); + dwarf.line_strings.add("dummy line string"); + let line_string_id = dwarf.line_strings.add(line_string_data); + + let attributes = &[ + ( + constants::DW_AT_name, + AttributeValue::Address(Address::Constant(0x1234)), + read::AttributeValue::Addr(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Block(data.clone()), + read::AttributeValue::Block(read_data), + ), + ( + constants::DW_AT_name, + AttributeValue::Data1(0x12), + read::AttributeValue::Data1(0x12), + ), + ( + constants::DW_AT_name, + AttributeValue::Data2(0x1234), + read::AttributeValue::Data2(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Data4(0x1234), + read::AttributeValue::Data4(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Data8(0x1234), + read::AttributeValue::Data8(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Sdata(0x1234), + read::AttributeValue::Sdata(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Udata(0x1234), + read::AttributeValue::Udata(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::Exprloc(expression.clone()), + read::AttributeValue::Exprloc(read_expression), + ), + ( + constants::DW_AT_name, + AttributeValue::Flag(false), + read::AttributeValue::Flag(false), + ), + /* + ( + constants::DW_AT_name, + AttributeValue::FlagPresent, + read::AttributeValue::Flag(true), + ), + */ + ( + constants::DW_AT_name, + AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), + read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), + ), + ( + constants::DW_AT_macro_info, + AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)), + read::AttributeValue::SecOffset(0x1234), + ), + ( + constants::DW_AT_macros, + AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)), + read::AttributeValue::SecOffset(0x1234), + ), + ( + constants::DW_AT_name, + AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), + read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), + ), + ( + constants::DW_AT_name, + AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), + read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), + ), + ( + constants::DW_AT_name, + AttributeValue::String(data.clone()), + read::AttributeValue::String(read_data), + ), + ( + constants::DW_AT_encoding, + AttributeValue::Encoding(constants::DwAte(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_decimal_sign, + AttributeValue::DecimalSign(constants::DwDs(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_endianity, + AttributeValue::Endianity(constants::DwEnd(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_accessibility, + AttributeValue::Accessibility(constants::DwAccess(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_visibility, + AttributeValue::Visibility(constants::DwVis(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_virtuality, + AttributeValue::Virtuality(constants::DwVirtuality(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_language, + AttributeValue::Language(constants::DwLang(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_address_class, + AttributeValue::AddressClass(constants::DwAddr(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_identifier_case, + AttributeValue::IdentifierCase(constants::DwId(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_calling_convention, + AttributeValue::CallingConvention(constants::DwCc(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_ordering, + AttributeValue::Ordering(constants::DwOrd(0x12)), + read::AttributeValue::Udata(0x12), + ), + ( + constants::DW_AT_inline, + AttributeValue::Inline(constants::DwInl(0x12)), + read::AttributeValue::Udata(0x12), + ), + ]; + + let mut add_attribute = |name, value| { + let entry_id = unit.add(unit.root(), constants::DW_TAG_subprogram); + let entry = unit.get_mut(entry_id); + entry.set(name, value); + }; + for (name, value, _) in attributes { + add_attribute(*name, value.clone()); + } + add_attribute( + constants::DW_AT_location, + AttributeValue::LocationListRef(loc_id), + ); + add_attribute( + constants::DW_AT_ranges, + AttributeValue::RangeListRef(range_id), + ); + add_attribute(constants::DW_AT_name, AttributeValue::StringRef(string_id)); + add_attribute( + constants::DW_AT_name, + AttributeValue::LineStringRef(line_string_id), + ); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + let read_unit = read_units.next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let mut read_entries = read_unit.entries(); + let (_, _root) = read_entries.next_dfs().unwrap().unwrap(); + + let mut get_attribute = |name| { + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + entry.attr(name).unwrap().unwrap() + }; + for (name, _, expect_value) in attributes { + let read_value = &get_attribute(*name).raw_value(); + // read::AttributeValue is invariant in the lifetime of R. + // The lifetimes here are all okay, so transmute it. + let read_value = unsafe { + mem::transmute::< + &read::AttributeValue>, + &read::AttributeValue>, + >(read_value) + }; + assert_eq!(read_value, expect_value); + } + + let read_attr = get_attribute(constants::DW_AT_location).value(); + let read::AttributeValue::LocationListsRef(read_loc_offset) = read_attr else { + panic!("unexpected {:?}", read_attr); + }; + let mut read_locations = read_unit.locations(read_loc_offset).unwrap(); + let read_location = read_locations.next().unwrap().unwrap(); + assert_eq!(read_location.range.begin, 0x1234); + assert_eq!(read_location.range.end, 0x2345); + assert_eq!(read_location.data, read_expression); + + let read_attr = get_attribute(constants::DW_AT_ranges).value(); + let read::AttributeValue::RangeListsRef(read_range_offset) = read_attr else { + panic!("unexpected {:?}", read_attr); + }; + let read_range_offset = read_unit.ranges_offset_from_raw(read_range_offset); + let mut read_ranges = read_unit.ranges(read_range_offset).unwrap(); + let read_range = read_ranges.next().unwrap().unwrap(); + assert_eq!(read_range.begin, 0x1234); + assert_eq!(read_range.end, 0x2345); + + let read_string = get_attribute(constants::DW_AT_name).raw_value(); + let read::AttributeValue::DebugStrRef(read_string_offset) = read_string else { + panic!("unexpected {:?}", read_string); + }; + assert_eq!( + read_dwarf.string(read_string_offset).unwrap().slice(), + string_data.as_bytes() + ); + + let read_line_string = get_attribute(constants::DW_AT_name).raw_value(); + let read::AttributeValue::DebugLineStrRef(read_line_string_offset) = + read_line_string + else { + panic!("unexpected {:?}", read_line_string); + }; + assert_eq!( + read_dwarf + .line_string(read_line_string_offset) + .unwrap() + .slice(), + line_string_data.as_bytes() + ); + + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))) + .unwrap(); + let convert_unit = convert_dwarf.units.get(convert_dwarf.units.id(0)); + let convert_root = convert_unit.get(convert_unit.root()); + let mut convert_entries = convert_root.children(); + + let mut get_convert_attr = |name| { + let convert_entry = convert_unit.get(*convert_entries.next().unwrap()); + convert_entry.get(name).unwrap() + }; + for (name, attr, _) in attributes { + let convert_attr = get_convert_attr(*name); + assert_eq!(convert_attr, attr); + } + + let convert_attr = get_convert_attr(constants::DW_AT_location); + let AttributeValue::LocationListRef(convert_loc_id) = convert_attr else { + panic!("unexpected {:?}", convert_attr); + }; + let convert_location = convert_unit.locations.get(*convert_loc_id); + assert_eq!(*convert_location, location); + + let convert_attr = get_convert_attr(constants::DW_AT_ranges); + let AttributeValue::RangeListRef(convert_range_id) = convert_attr else { + panic!("unexpected {:?}", convert_attr); + }; + let convert_range = convert_unit.ranges.get(*convert_range_id); + assert_eq!(*convert_range, range); + + let convert_attr = get_convert_attr(constants::DW_AT_name); + let AttributeValue::StringRef(convert_string_id) = convert_attr else { + panic!("unexpected {:?}", convert_attr); + }; + let convert_string = convert_dwarf.strings.get(*convert_string_id); + assert_eq!(convert_string, string_data.as_bytes()); + + let convert_attr = get_convert_attr(constants::DW_AT_name); + let AttributeValue::LineStringRef(convert_line_string_id) = convert_attr else { + panic!("unexpected {:?}", convert_attr); + }; + let convert_line_string = + convert_dwarf.line_strings.get(*convert_line_string_id); + assert_eq!(convert_line_string, line_string_data.as_bytes()); + } + } + } + } + + #[test] + fn test_unit_ref() { + let mut dwarf = Dwarf::new(); + let unit_id1 = dwarf.units.add(Unit::new( + Encoding { + version: 4, + address_size: 8, + format: Format::Dwarf32, + }, + LineProgram::none(), + )); + assert_eq!(unit_id1, dwarf.units.id(0)); + let unit_id2 = dwarf.units.add(Unit::new( + Encoding { + version: 2, + address_size: 4, + format: Format::Dwarf64, + }, + LineProgram::none(), + )); + assert_eq!(unit_id2, dwarf.units.id(1)); + let unit1_child1 = UnitEntryId::new(dwarf.units.get(unit_id1).base_id, 1); + let unit1_child2 = UnitEntryId::new(dwarf.units.get(unit_id1).base_id, 2); + let unit2_child1 = UnitEntryId::new(dwarf.units.get(unit_id2).base_id, 1); + let unit2_child2 = UnitEntryId::new(dwarf.units.get(unit_id2).base_id, 2); + { + let unit1 = dwarf.units.get_mut(unit_id1); + let root = unit1.root(); + let child_id1 = unit1.add(root, constants::DW_TAG_subprogram); + assert_eq!(child_id1, unit1_child1); + let child_id2 = unit1.add(root, constants::DW_TAG_subprogram); + assert_eq!(child_id2, unit1_child2); + { + let child1 = unit1.get_mut(child_id1); + child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); + } + { + let child2 = unit1.get_mut(child_id2); + child2.set( + constants::DW_AT_type, + AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)), + ); + } + } + { + let unit2 = dwarf.units.get_mut(unit_id2); + let root = unit2.root(); + let child_id1 = unit2.add(root, constants::DW_TAG_subprogram); + assert_eq!(child_id1, unit2_child1); + let child_id2 = unit2.add(root, constants::DW_TAG_subprogram); + assert_eq!(child_id2, unit2_child2); + { + let child1 = unit2.get_mut(child_id1); + child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); + } + { + let child2 = unit2.get_mut(child_id2); + child2.set( + constants::DW_AT_type, + AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)), + ); + } + } + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + println!("{:?}", sections.debug_info); + println!("{:?}", sections.debug_abbrev); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + + let read_unit = read_units.next().unwrap().unwrap(); + let abbrevs = read_dwarf.abbreviations(&read_unit).unwrap(); + let mut read_entries = read_unit.entries(&abbrevs); + let (_, _root) = read_entries.next_dfs().unwrap().unwrap(); + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + let read_unit1_child1_attr = entry.attr_value(constants::DW_AT_type).unwrap(); + let read_unit1_child1_section_offset = + entry.offset().to_debug_info_offset(&read_unit).unwrap(); + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + let read_unit1_child2_attr = entry.attr_value(constants::DW_AT_type).unwrap(); + let read_unit1_child2_offset = entry.offset(); + + let read_unit = read_units.next().unwrap().unwrap(); + let abbrevs = read_dwarf.abbreviations(&read_unit).unwrap(); + let mut read_entries = read_unit.entries(&abbrevs); + let (_, _root) = read_entries.next_dfs().unwrap().unwrap(); + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + let read_unit2_child1_attr = entry.attr_value(constants::DW_AT_type).unwrap(); + let read_unit2_child1_section_offset = + entry.offset().to_debug_info_offset(&read_unit).unwrap(); + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + let read_unit2_child2_attr = entry.attr_value(constants::DW_AT_type).unwrap(); + let read_unit2_child2_offset = entry.offset(); + + assert_eq!( + read_unit1_child1_attr, + Some(read::AttributeValue::UnitRef(read_unit1_child2_offset)) + ); + assert_eq!( + read_unit1_child2_attr, + Some(read::AttributeValue::DebugInfoRef( + read_unit2_child1_section_offset + )) + ); + assert_eq!( + read_unit2_child1_attr, + Some(read::AttributeValue::UnitRef(read_unit2_child2_offset)) + ); + assert_eq!( + read_unit2_child2_attr, + Some(read::AttributeValue::DebugInfoRef( + read_unit1_child1_section_offset + )) + ); + + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))).unwrap(); + let convert_units = &convert_dwarf.units; + assert_eq!(convert_units.count(), dwarf.units.count()); + + for i in 0..convert_units.count() { + let unit = dwarf.units.get(dwarf.units.id(i)); + let convert_unit = convert_units.get(convert_units.id(i)); + assert_eq!(convert_unit.version(), unit.version()); + assert_eq!(convert_unit.address_size(), unit.address_size()); + assert_eq!(convert_unit.format(), unit.format()); + assert_eq!(convert_unit.count(), unit.count()); + + let root = unit.get(unit.root()); + let convert_root = convert_unit.get(convert_unit.root()); + assert_eq!(convert_root.tag(), root.tag()); + for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { + assert_eq!(convert_attr, attr); + } + + let child1 = unit.get(UnitEntryId::new(unit.base_id, 1)); + let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1)); + assert_eq!(convert_child1.tag(), child1.tag()); + for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) { + assert_eq!(convert_attr.name, attr.name); + match (convert_attr.value.clone(), attr.value.clone()) { + ( + AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), + AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), + ) => { + assert_eq!(convert_unit.index, unit.index); + assert_eq!(convert_entry.index, entry.index); + } + (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { + assert_eq!(convert_id.index, id.index); + } + (convert_value, value) => assert_eq!(convert_value, value), + } + } + + let child2 = unit.get(UnitEntryId::new(unit.base_id, 2)); + let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2)); + assert_eq!(convert_child2.tag(), child2.tag()); + for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) { + assert_eq!(convert_attr.name, attr.name); + match (convert_attr.value.clone(), attr.value.clone()) { + ( + AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), + AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), + ) => { + assert_eq!(convert_unit.index, unit.index); + assert_eq!(convert_entry.index, entry.index); + } + (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { + assert_eq!(convert_id.index, id.index); + } + (convert_value, value) => assert_eq!(convert_value, value), + } + } + } + } + + #[test] + fn test_sibling() { + fn add_child( + unit: &mut Unit, + parent: UnitEntryId, + tag: constants::DwTag, + name: &str, + ) -> UnitEntryId { + let id = unit.add(parent, tag); + let child = unit.get_mut(id); + child.set(constants::DW_AT_name, AttributeValue::String(name.into())); + child.set_sibling(true); + id + } + + fn add_children(unit: &mut Unit) { + let root = unit.root(); + let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1"); + add_child(unit, child1, constants::DW_TAG_variable, "grandchild1"); + add_child(unit, root, constants::DW_TAG_subprogram, "child2"); + add_child(unit, root, constants::DW_TAG_subprogram, "child3"); + } + + fn next_child>( + entries: &mut read::EntriesCursor<'_, '_, R>, + ) -> (read::UnitOffset, Option) { + let (_, entry) = entries.next_dfs().unwrap().unwrap(); + let offset = entry.offset(); + let sibling = + entry + .attr_value(constants::DW_AT_sibling) + .unwrap() + .map(|attr| match attr { + read::AttributeValue::UnitRef(offset) => offset, + _ => panic!("bad sibling value"), + }); + (offset, sibling) + } + + fn check_sibling>( + unit: read::UnitHeader, + dwarf: &read::Dwarf, + ) { + let unit = dwarf.unit(unit).unwrap(); + let mut entries = unit.entries(); + // root + entries.next_dfs().unwrap().unwrap(); + // child1 + let (_, sibling1) = next_child(&mut entries); + // grandchild1 + entries.next_dfs().unwrap().unwrap(); + // child2 + let (offset2, sibling2) = next_child(&mut entries); + // child3 + let (_, _) = next_child(&mut entries); + assert_eq!(sibling1, Some(offset2)); + assert_eq!(sibling2, None); + } + + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 8, + }; + let mut dwarf = Dwarf::new(); + let unit_id1 = dwarf.units.add(Unit::new(encoding, LineProgram::none())); + add_children(dwarf.units.get_mut(unit_id1)); + let unit_id2 = dwarf.units.add(Unit::new(encoding, LineProgram::none())); + add_children(dwarf.units.get_mut(unit_id2)); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + println!("{:?}", sections.debug_info); + println!("{:?}", sections.debug_abbrev); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + check_sibling(read_units.next().unwrap().unwrap(), &read_dwarf); + check_sibling(read_units.next().unwrap().unwrap(), &read_dwarf); + } + + #[test] + fn test_line_ref() { + let dir_bytes = b"dir"; + let file_bytes1 = b"file1"; + let file_bytes2 = b"file2"; + let file_string1 = LineString::String(file_bytes1.to_vec()); + let file_string2 = LineString::String(file_bytes2.to_vec()); + + for &version in &[2, 3, 4, 5] { + for &address_size in &[4, 8] { + for &format in &[Format::Dwarf32, Format::Dwarf64] { + let encoding = Encoding { + format, + version, + address_size, + }; + + // The line program we'll be referencing. + let mut line_program = LineProgram::new( + encoding, + LineEncoding::default(), + LineString::String(dir_bytes.to_vec()), + file_string1.clone(), + None, + ); + let dir = line_program.default_directory(); + // For version >= 5, this will reuse the existing file at index 0. + let file1 = line_program.add_file(file_string1.clone(), dir, None); + let file2 = line_program.add_file(file_string2.clone(), dir, None); + + let mut unit = Unit::new(encoding, line_program); + let root = unit.get_mut(unit.root()); + root.set( + constants::DW_AT_name, + AttributeValue::String(file_bytes1.to_vec()), + ); + root.set( + constants::DW_AT_comp_dir, + AttributeValue::String(dir_bytes.to_vec()), + ); + root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); + + let child = unit.add(unit.root(), constants::DW_TAG_subprogram); + unit.get_mut(child).set( + constants::DW_AT_decl_file, + AttributeValue::FileIndex(Some(file1)), + ); + + let child = unit.add(unit.root(), constants::DW_TAG_subprogram); + unit.get_mut(child).set( + constants::DW_AT_call_file, + AttributeValue::FileIndex(Some(file2)), + ); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let mut read_units = read_dwarf.units(); + let read_unit = read_units.next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let read_line_program = read_unit.line_program.as_ref().unwrap().header(); + let mut read_entries = read_unit.entries(); + let (_, _root) = read_entries.next_dfs().unwrap().unwrap(); + + let mut get_path = |name| { + let (_, entry) = read_entries.next_dfs().unwrap().unwrap(); + let read_attr = entry.attr(name).unwrap().unwrap(); + let read::AttributeValue::FileIndex(read_file_index) = read_attr.value() + else { + panic!("unexpected {:?}", read_attr); + }; + let read_file = read_line_program.file(read_file_index).unwrap(); + let read_path = read_unit + .attr_string(read_file.path_name()) + .unwrap() + .slice(); + (read_file_index, read_path) + }; + + let (read_index, read_path) = get_path(constants::DW_AT_decl_file); + assert_eq!(read_index, if version >= 5 { 0 } else { 1 }); + assert_eq!(read_path, file_bytes1); + + let (read_index, read_path) = get_path(constants::DW_AT_call_file); + assert_eq!(read_index, if version >= 5 { 1 } else { 2 }); + assert_eq!(read_path, file_bytes2); + + let convert_dwarf = + Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))) + .unwrap(); + let convert_unit = convert_dwarf.units.get(convert_dwarf.units.id(0)); + let convert_root = convert_unit.get(convert_unit.root()); + let mut convert_entries = convert_root.children(); + + let mut get_convert_path = |name| { + let convert_entry = convert_unit.get(*convert_entries.next().unwrap()); + let convert_attr = convert_entry.get(name).unwrap(); + let AttributeValue::FileIndex(Some(convert_file_index)) = convert_attr + else { + panic!("unexpected {:?}", convert_attr); + }; + convert_unit.line_program.get_file(*convert_file_index).0 + }; + + let convert_path = get_convert_path(constants::DW_AT_decl_file); + assert_eq!(convert_path, &file_string1); + + let convert_path = get_convert_path(constants::DW_AT_call_file); + assert_eq!(convert_path, &file_string2); + } + } + } + } + + #[test] + fn test_line_program_used() { + for used in [false, true] { + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 8, + }; + + let line_program = LineProgram::new( + encoding, + LineEncoding::default(), + LineString::String(b"comp_dir".to_vec()), + LineString::String(b"comp_name".to_vec()), + None, + ); + + let mut unit = Unit::new(encoding, line_program); + let file_id = if used { Some(FileId::new(0)) } else { None }; + let root = unit.root(); + unit.get_mut(root).set( + constants::DW_AT_decl_file, + AttributeValue::FileIndex(file_id), + ); + + let mut dwarf = Dwarf::new(); + dwarf.units.add(unit); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + dwarf.write(&mut sections).unwrap(); + assert_eq!(!used, sections.debug_line.slice().is_empty()); + } + } + + #[test] + fn test_delete_child() { + fn set_name(unit: &mut Unit, id: UnitEntryId, name: &str) { + let entry = unit.get_mut(id); + entry.set(constants::DW_AT_name, AttributeValue::String(name.into())); + } + fn check_name( + entry: &read::DebuggingInformationEntry<'_, '_, R>, + unit: read::UnitRef<'_, R>, + name: &str, + ) { + let name_attr = entry.attr(constants::DW_AT_name).unwrap().unwrap(); + let entry_name = unit.attr_string(name_attr.value()).unwrap(); + let entry_name_str = entry_name.to_string().unwrap(); + assert_eq!(entry_name_str, name); + } + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 8, + }; + let mut dwarf = DwarfUnit::new(encoding); + let root = dwarf.unit.root(); + + // Add and delete entries in the root unit + let child1 = dwarf.unit.add(root, constants::DW_TAG_subprogram); + set_name(&mut dwarf.unit, child1, "child1"); + let grandchild1 = dwarf.unit.add(child1, constants::DW_TAG_variable); + set_name(&mut dwarf.unit, grandchild1, "grandchild1"); + let child2 = dwarf.unit.add(root, constants::DW_TAG_subprogram); + set_name(&mut dwarf.unit, child2, "child2"); + // This deletes both `child1` and its child `grandchild1` + dwarf.unit.get_mut(root).delete_child(child1); + let child3 = dwarf.unit.add(root, constants::DW_TAG_subprogram); + set_name(&mut dwarf.unit, child3, "child3"); + let child4 = dwarf.unit.add(root, constants::DW_TAG_subprogram); + set_name(&mut dwarf.unit, child4, "child4"); + let grandchild4 = dwarf.unit.add(child4, constants::DW_TAG_variable); + set_name(&mut dwarf.unit, grandchild4, "grandchild4"); + dwarf.unit.get_mut(child4).delete_child(grandchild4); + + let mut sections = Sections::new(EndianVec::new(LittleEndian)); + + // Write DWARF data which should only include `child2`, `child3` and `child4` + dwarf.write(&mut sections).unwrap(); + + let read_dwarf = sections.read(LittleEndian); + let read_unit = read_dwarf.units().next().unwrap().unwrap(); + let read_unit = read_dwarf.unit(read_unit).unwrap(); + let read_unit = read_unit.unit_ref(&read_dwarf); + let mut entries = read_unit.entries(); + // root + entries.next_dfs().unwrap().unwrap(); + // child2 + let (_, read_child2) = entries.next_dfs().unwrap().unwrap(); + check_name(read_child2, read_unit, "child2"); + // child3 + let (_, read_child3) = entries.next_dfs().unwrap().unwrap(); + check_name(read_child3, read_unit, "child3"); + // child4 + let (_, read_child4) = entries.next_dfs().unwrap().unwrap(); + check_name(read_child4, read_unit, "child4"); + // There should be no more entries + assert!(entries.next_dfs().unwrap().is_none()); + } +} diff --git a/deps/crates/vendor/gimli/src/write/writer.rs b/deps/crates/vendor/gimli/src/write/writer.rs new file mode 100644 index 00000000000000..9ee071bf61f82b --- /dev/null +++ b/deps/crates/vendor/gimli/src/write/writer.rs @@ -0,0 +1,493 @@ +use crate::common::{Format, SectionId}; +use crate::constants; +use crate::endianity::Endianity; +use crate::leb128; +use crate::write::{Address, Error, Result}; + +/// A trait for writing the data to a DWARF section. +/// +/// All write operations append to the section unless otherwise specified. +#[allow(clippy::len_without_is_empty)] +pub trait Writer { + /// The endianity of bytes that are written. + type Endian: Endianity; + + /// Return the endianity of bytes that are written. + fn endian(&self) -> Self::Endian; + + /// Return the current section length. + /// + /// This may be used as an offset for future `write_at` calls. + fn len(&self) -> usize; + + /// Write a slice. + fn write(&mut self, bytes: &[u8]) -> Result<()>; + + /// Write a slice at a given offset. + /// + /// The write must not extend past the current section length. + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; + + /// Write an address. + /// + /// If the writer supports relocations, then it must provide its own implementation + /// of this method. + // TODO: use write_reference instead? + fn write_address(&mut self, address: Address, size: u8) -> Result<()> { + match address { + Address::Constant(val) => self.write_udata(val, size), + Address::Symbol { .. } => Err(Error::InvalidAddress), + } + } + + /// Write an address with a `.eh_frame` pointer encoding. + /// + /// The given size is only used for `DW_EH_PE_absptr` formats. + /// + /// If the writer supports relocations, then it must provide its own implementation + /// of this method. + fn write_eh_pointer( + &mut self, + address: Address, + eh_pe: constants::DwEhPe, + size: u8, + ) -> Result<()> { + match address { + Address::Constant(val) => { + // Indirect doesn't matter here. + let val = match eh_pe.application() { + constants::DW_EH_PE_absptr => val, + constants::DW_EH_PE_pcrel => { + // TODO: better handling of sign + let offset = self.len() as u64; + val.wrapping_sub(offset) + } + _ => { + return Err(Error::UnsupportedPointerEncoding(eh_pe)); + } + }; + self.write_eh_pointer_data(val, eh_pe.format(), size) + } + Address::Symbol { .. } => Err(Error::InvalidAddress), + } + } + + /// Write a value with a `.eh_frame` pointer format. + /// + /// The given size is only used for `DW_EH_PE_absptr` formats. + /// + /// This must not be used directly for values that may require relocation. + fn write_eh_pointer_data( + &mut self, + val: u64, + format: constants::DwEhPe, + size: u8, + ) -> Result<()> { + match format { + constants::DW_EH_PE_absptr => self.write_udata(val, size), + constants::DW_EH_PE_uleb128 => self.write_uleb128(val), + constants::DW_EH_PE_udata2 => self.write_udata(val, 2), + constants::DW_EH_PE_udata4 => self.write_udata(val, 4), + constants::DW_EH_PE_udata8 => self.write_udata(val, 8), + constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64), + constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2), + constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4), + constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8), + _ => Err(Error::UnsupportedPointerEncoding(format)), + } + } + + /// Write an offset that is relative to the start of the given section. + /// + /// If the writer supports relocations, then it must provide its own implementation + /// of this method. + fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> { + self.write_udata(val as u64, size) + } + + /// Write an offset that is relative to the start of the given section. + /// + /// If the writer supports relocations, then it must provide its own implementation + /// of this method. + fn write_offset_at( + &mut self, + offset: usize, + val: usize, + _section: SectionId, + size: u8, + ) -> Result<()> { + self.write_udata_at(offset, val as u64, size) + } + + /// Write a reference to a symbol. + /// + /// If the writer supports symbols, then it must provide its own implementation + /// of this method. + fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> { + Err(Error::InvalidReference) + } + + /// Write a u8. + fn write_u8(&mut self, val: u8) -> Result<()> { + let bytes = [val]; + self.write(&bytes) + } + + /// Write a u16. + fn write_u16(&mut self, val: u16) -> Result<()> { + let mut bytes = [0; 2]; + self.endian().write_u16(&mut bytes, val); + self.write(&bytes) + } + + /// Write a u32. + fn write_u32(&mut self, val: u32) -> Result<()> { + let mut bytes = [0; 4]; + self.endian().write_u32(&mut bytes, val); + self.write(&bytes) + } + + /// Write a u64. + fn write_u64(&mut self, val: u64) -> Result<()> { + let mut bytes = [0; 8]; + self.endian().write_u64(&mut bytes, val); + self.write(&bytes) + } + + /// Write a u8 at the given offset. + fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> { + let bytes = [val]; + self.write_at(offset, &bytes) + } + + /// Write a u16 at the given offset. + fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> { + let mut bytes = [0; 2]; + self.endian().write_u16(&mut bytes, val); + self.write_at(offset, &bytes) + } + + /// Write a u32 at the given offset. + fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> { + let mut bytes = [0; 4]; + self.endian().write_u32(&mut bytes, val); + self.write_at(offset, &bytes) + } + + /// Write a u64 at the given offset. + fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> { + let mut bytes = [0; 8]; + self.endian().write_u64(&mut bytes, val); + self.write_at(offset, &bytes) + } + + /// Write unsigned data of the given size. + /// + /// Returns an error if the value is too large for the size. + /// This must not be used directly for values that may require relocation. + fn write_udata(&mut self, val: u64, size: u8) -> Result<()> { + match size { + 1 => { + let write_val = val as u8; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u8(write_val) + } + 2 => { + let write_val = val as u16; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u16(write_val) + } + 4 => { + let write_val = val as u32; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u32(write_val) + } + 8 => self.write_u64(val), + otherwise => Err(Error::UnsupportedWordSize(otherwise)), + } + } + + /// Write signed data of the given size. + /// + /// Returns an error if the value is too large for the size. + /// This must not be used directly for values that may require relocation. + fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> { + match size { + 1 => { + let write_val = val as i8; + if val != i64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u8(write_val as u8) + } + 2 => { + let write_val = val as i16; + if val != i64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u16(write_val as u16) + } + 4 => { + let write_val = val as i32; + if val != i64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u32(write_val as u32) + } + 8 => self.write_u64(val as u64), + otherwise => Err(Error::UnsupportedWordSize(otherwise)), + } + } + + /// Write a word of the given size at the given offset. + /// + /// Returns an error if the value is too large for the size. + /// This must not be used directly for values that may require relocation. + fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> { + match size { + 1 => { + let write_val = val as u8; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u8_at(offset, write_val) + } + 2 => { + let write_val = val as u16; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u16_at(offset, write_val) + } + 4 => { + let write_val = val as u32; + if val != u64::from(write_val) { + return Err(Error::ValueTooLarge); + } + self.write_u32_at(offset, write_val) + } + 8 => self.write_u64_at(offset, val), + otherwise => Err(Error::UnsupportedWordSize(otherwise)), + } + } + + /// Write an unsigned LEB128 encoded integer. + fn write_uleb128(&mut self, val: u64) -> Result<()> { + let mut bytes = [0u8; 10]; + // bytes is long enough so this will never fail. + let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); + self.write(&bytes[..len]) + } + + /// Read an unsigned LEB128 encoded integer. + fn write_sleb128(&mut self, val: i64) -> Result<()> { + let mut bytes = [0u8; 10]; + // bytes is long enough so this will never fail. + let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap(); + self.write(&bytes[..len]) + } + + /// Write an initial length according to the given DWARF format. + /// + /// This will only write a length of zero, since the length isn't + /// known yet, and a subsequent call to `write_initial_length_at` + /// will write the actual length. + fn write_initial_length(&mut self, format: Format) -> Result { + if format == Format::Dwarf64 { + self.write_u32(0xffff_ffff)?; + } + let offset = InitialLengthOffset(self.len()); + self.write_udata(0, format.word_size())?; + Ok(offset) + } + + /// Write an initial length at the given offset according to the given DWARF format. + /// + /// `write_initial_length` must have previously returned the offset. + fn write_initial_length_at( + &mut self, + offset: InitialLengthOffset, + length: u64, + format: Format, + ) -> Result<()> { + self.write_udata_at(offset.0, length, format.word_size()) + } +} + +/// The offset at which an initial length should be written. +#[derive(Debug, Clone, Copy)] +pub struct InitialLengthOffset(usize); + +#[cfg(test)] +mod tests { + use super::*; + use crate::write; + use crate::{BigEndian, LittleEndian}; + + #[test] + fn test_writer() { + let mut w = write::EndianVec::new(LittleEndian); + w.write_address(Address::Constant(0x1122_3344), 4).unwrap(); + assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); + assert_eq!( + w.write_address( + Address::Symbol { + symbol: 0, + addend: 0 + }, + 4 + ), + Err(Error::InvalidAddress) + ); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_offset(0x1122_3344, SectionId::DebugInfo, 4) + .unwrap(); + assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); + w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2) + .unwrap(); + assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_u8(0x11).unwrap(); + w.write_u16(0x2233).unwrap(); + w.write_u32(0x4455_6677).unwrap(); + w.write_u64(0x8081_8283_8485_8687).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x11, + 0x33, 0x22, + 0x77, 0x66, 0x55, 0x44, + 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, + ]); + w.write_u8_at(14, 0x11).unwrap(); + w.write_u16_at(12, 0x2233).unwrap(); + w.write_u32_at(8, 0x4455_6677).unwrap(); + w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, + 0x77, 0x66, 0x55, 0x44, + 0x33, 0x22, + 0x11, + ]); + + let mut w = write::EndianVec::new(BigEndian); + w.write_u8(0x11).unwrap(); + w.write_u16(0x2233).unwrap(); + w.write_u32(0x4455_6677).unwrap(); + w.write_u64(0x8081_8283_8485_8687).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x11, + 0x22, 0x33, + 0x44, 0x55, 0x66, 0x77, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + ]); + w.write_u8_at(14, 0x11).unwrap(); + w.write_u16_at(12, 0x2233).unwrap(); + w.write_u32_at(8, 0x4455_6677).unwrap(); + w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x44, 0x55, 0x66, 0x77, + 0x22, 0x33, + 0x11, + ]); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_udata(0x11, 1).unwrap(); + w.write_udata(0x2233, 2).unwrap(); + w.write_udata(0x4455_6677, 4).unwrap(); + w.write_udata(0x8081_8283_8485_8687, 8).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x11, + 0x33, 0x22, + 0x77, 0x66, 0x55, 0x44, + 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, + ]); + assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge)); + assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge)); + assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge)); + assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3))); + w.write_udata_at(14, 0x11, 1).unwrap(); + w.write_udata_at(12, 0x2233, 2).unwrap(); + w.write_udata_at(8, 0x4455_6677, 4).unwrap(); + w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap(); + #[rustfmt::skip] + assert_eq!(w.slice(), &[ + 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, + 0x77, 0x66, 0x55, 0x44, + 0x33, 0x22, + 0x11, + ]); + assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge)); + assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge)); + assert_eq!( + w.write_udata_at(0, 0x1_0000_0000, 4), + Err(Error::ValueTooLarge) + ); + assert_eq!( + w.write_udata_at(0, 0x00, 3), + Err(Error::UnsupportedWordSize(3)) + ); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_uleb128(0).unwrap(); + assert_eq!(w.slice(), &[0]); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_uleb128(u64::MAX).unwrap(); + assert_eq!( + w.slice(), + &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1] + ); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_sleb128(0).unwrap(); + assert_eq!(w.slice(), &[0]); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_sleb128(i64::MAX).unwrap(); + assert_eq!( + w.slice(), + &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0] + ); + + let mut w = write::EndianVec::new(LittleEndian); + w.write_sleb128(i64::MIN).unwrap(); + assert_eq!( + w.slice(), + &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f] + ); + + let mut w = write::EndianVec::new(LittleEndian); + let offset = w.write_initial_length(Format::Dwarf32).unwrap(); + assert_eq!(w.slice(), &[0, 0, 0, 0]); + w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32) + .unwrap(); + assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); + assert_eq!( + w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32), + Err(Error::ValueTooLarge) + ); + + let mut w = write::EndianVec::new(LittleEndian); + let offset = w.write_initial_length(Format::Dwarf64).unwrap(); + assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]); + w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64) + .unwrap(); + assert_eq!( + w.slice(), + &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11] + ); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/.cargo-checksum.json b/deps/crates/vendor/hashbrown-0.14.5/.cargo-checksum.json new file mode 100644 index 00000000000000..7af7b4d0664754 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"b1f17aefeca2e91526393fbf93f76ddb51f4c1693746a8f598bfb0f3444a7a6f","CHANGELOG.md":"1a844fe3b7466b41ca1d5914af197d5aeed7cb14f30ebe4be351367d7ca905d2","Cargo.toml":"c011f10385da722056537329f3fcf8c9b93af742e79e38885c0152a0105fc227","Cargo.toml.orig":"6d7350ae61b9df7a42e4e2293fbfa8cc5a7ab351732d45e178dcfc7b413d3819","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"84c222ce49510535419d338b7532a72a2bf22b7466e44de78d92d25b6c7d636b","benches/bench.rs":"ef7bc025922f077d307c565640c005d056e3d6c1713448a95aae92d3c22c1005","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"0625e6a5e3b8ecc8901a12aeeea54393fd84617fb3a14d98a34d2d2bddb8d257","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"96fdf39b3f601f77152d7ce84541b8f51f32b9274b7da9c294862892e721a5d8","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"04012fb2e99648819b4bc0044107ed3cb94013e242b7865075c5bd9ebf1b6865","src/external_trait_impls/rayon/set.rs":"7539348ff7bc6e3cce6b3c019d62dc401eea0138c578fef729c2593e8ead1cfa","src/external_trait_impls/rayon/table.rs":"8778d29509c68b5b7cb66859db025d3939ce22e7cf370b20ff3dea4fe4b29fd0","src/external_trait_impls/rkyv/hash_map.rs":"7abe24318143b776016052b05840656afc858b1ba5252f3d418d61972477f53d","src/external_trait_impls/rkyv/hash_set.rs":"38d969125d17d606492ec4ec9fc06b7e7118eb903240dacf40de21b9b06fa5c8","src/external_trait_impls/rkyv/mod.rs":"54399ce5574fd1d84b7b0cb4238fa3e898575e89a6724299be009d2172bda02e","src/external_trait_impls/serde.rs":"6dbe104dee16b453b6b048b541c6e02c6d067d970dfafd243fc4360288b0168c","src/lib.rs":"74e250c18e55994a4a902eaa06aca034559d6de53501ed4bf9010fabc67e88a2","src/macros.rs":"98a26b908fc0fbe6a58d008a317e550013d615eb3cc17a5054a573c62c1d74cb","src/map.rs":"d484f2f81e5b4acf4b615f187241e34c3016aaaca53a5e71019cceb993c4ebd7","src/raw/alloc.rs":"902f8588d0fdee3e5c3dc02410f41d4b38ac88843727387f929f3186b3a2d322","src/raw/bitmask.rs":"3b3dce8d6a48856ada19085abf43908f124ab3419fcf434b9ca64d7bff243f67","src/raw/generic.rs":"efc5e603be3e9a17935aef1836a38ce01c78a0093b2af0671548eb5459b37921","src/raw/mod.rs":"16bbabf42dde9f3fb17c4f7e768aef47752d839bf624b81d24a48af3d418b3a2","src/raw/neon.rs":"9907d8ebc36fc3df562dde478ea9b72213fda65288a304718d8647f0029dc9ad","src/raw/sse2.rs":"39038e3344e49f4638e211bcdbf56565ac53e90dce56172cc3b526fea911c2af","src/rustc_entry.rs":"8142ed89b50155602ef8c1628382bd62d3ee903920fe49d403d4100a278c6ba4","src/scopeguard.rs":"1a246e08a63c06cd8ad934bd7da229421bf804f991ae93cd7e242da27ca6c601","src/set.rs":"a620ed68bd1610b76c4c1890615d71b2c04928bf5b345133a0588a065bce06fa","src/table.rs":"7b7174099d2e3cade0caeddd73e29b7395f3b9f4f1f21013f885b52cd93438cb","tests/equivalent_trait.rs":"84faa3fe9d67c375d03fec81f0f1412c47862477d42e84e7d235258236338d5b","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/raw.rs":"43ed2f98877533a0905611d9a30f26b183dd3e103e3856eeab80e7b8ac7894d3","tests/rayon.rs":"39cb24ab45fce8087bb54948715c8b6973ebfba1a325292b5b3cd9aab50b5fd2","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"9f8011c29d1059aadb54b6dd4623521d5178b4278b4a56021ef2cee4bbb19fd9"},"package":"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown-0.14.5/.cargo_vcs_info.json b/deps/crates/vendor/hashbrown-0.14.5/.cargo_vcs_info.json new file mode 100644 index 00000000000000..71be7844d3b827 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "025d0f58b62d074f5fd660a22fe293cdc237d589" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown-0.14.5/CHANGELOG.md b/deps/crates/vendor/hashbrown-0.14.5/CHANGELOG.md new file mode 100644 index 00000000000000..8c4068089a5575 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/CHANGELOG.md @@ -0,0 +1,532 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/) +and this project adheres to [Semantic Versioning](https://semver.org/). + +## [Unreleased] + +### Changed + +- Changed `hash_set::{Entry, VacantEntry}::insert` to return `OccupiedEntry`. (#495) + +## [v0.14.5] - 2024-04-28 + +### Fixed + +- Fixed index calculation in panic guard of `clone_from_impl`. (#511) + +## ~~[v0.14.4] - 2024-03-19~~ + +This release was _yanked_ due to a breaking change. + +## [v0.14.3] - 2023-11-26 + +### Added + +- Specialized `fold` implementation of iterators. (#480) + +### Fixed + +- Avoid using unstable `ptr::invalid_mut` on nightly. (#481) + +## [v0.14.2] - 2023-10-19 + +### Added + +- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466) + +### Fixed + +- Disabled the use of NEON instructions on big-endian ARM. (#475) +- Disabled the use of NEON instructions on Miri. (#476) + +## [v0.14.1] - 2023-09-28 + +### Added + +- Allow serializing `HashMap`s that use a custom allocator. (#449) + +### Changed + +- Use the `Equivalent` trait from the `equivalent` crate. (#442) +- Slightly improved performance of table resizing. (#451) +- Relaxed MSRV to 1.63.0. (#457) +- Removed `Clone` requirement from custom allocators. (#468) + +### Fixed + +- Fixed custom allocators being leaked in some situations. (#439, #465) + +## [v0.14.0] - 2023-06-01 + +### Added + +- Support for `allocator-api2` crate + for interfacing with custom allocators on stable. (#417) +- Optimized implementation for ARM using NEON instructions. (#430) +- Support for rkyv serialization. (#432) +- `Equivalent` trait to look up values without `Borrow`. (#345) +- `Hash{Map,Set}::raw_table_mut` is added whic returns a mutable reference. (#404) +- Fast path for `clear` on empty tables. (#428) + +### Changed + +- Optimized insertion to only perform a single lookup. (#277) +- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining + elements when the iterator is dropped. #(374) +- Bumped MSRV to 1.64.0. (#431) +- `{Map,Set}::raw_table` now returns an immutable reference. (#404) +- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is + specified in generics. (#389) +- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387) +- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429) +- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429) +- `RawTable::remove` now also returns an `InsertSlot`. (#429) +- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429) +- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427) +- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423) +- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with` + were changed to give a `&K` instead of a `&Q` to the closure. + +### Removed + +- Support for `bumpalo` as an allocator with custom wrapper. + Use `allocator-api2` feature in `bumpalo` to use it as an allocator + for `hashbrown` collections. (#417) + +## [v0.13.2] - 2023-01-12 + +### Fixed + +- Added `#[inline(always)]` to `find_inner`. (#375) +- Fixed `RawTable::allocation_info` for empty tables. (#376) + +## [v0.13.1] - 2022-11-10 + +### Added + +- Added `Equivalent` trait to customize key lookups. (#350) +- Added support for 16-bit targets. (#368) +- Added `RawTable::allocation_info` which provides information about the memory + usage of a table. (#371) + +### Changed + +- Bumped MSRV to 1.61.0. +- Upgraded to `ahash` 0.8. (#357) +- Make `with_hasher_in` const. (#355) +- The following methods have been removed from the `RawTable` API in favor of + safer alternatives: + - `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead. + - `Bucket::read` => Use `RawTable::remove` instead. + - `Bucket::drop` => Use `RawTable::erase` instead. + - `Bucket::write` => Use `Bucket::as_mut` instead. + +### Fixed + +- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362) +- Fixed issue with field retagging in scopeguard. (#359) + +## [v0.12.3] - 2022-07-17 + +### Fixed + +- Fixed double-drop in `RawTable::clone_from`. (#348) + +## [v0.12.2] - 2022-07-09 + +### Added + +- Added `Entry` API for `HashSet`. (#342) +- Added `Extend<&'a (K, V)> for HashMap`. (#340) +- Added length-based short-circuiting for hash table iteration. (#338) +- Added a function to access the `RawTable` of a `HashMap`. (#335) + +### Changed + +- Edited `do_alloc` to reduce LLVM IR generated. (#341) + +## [v0.12.1] - 2022-05-02 + +### Fixed + +- Fixed underflow in `RawIterRange::size_hint`. (#325) +- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325) + +## [v0.12.0] - 2022-01-17 + +### Added + +- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297) +- Added an `allocator()` getter to HashMap and HashSet. (#257) +- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293) +- Added `into_keys` and `into_values` to HashMap. (#295) +- Implement `From` on `HashSet` and `HashMap`. (#298) +- Added `entry_ref` API to `HashMap`. (#201) + +### Changed + +- Bumped minimum Rust version to 1.56.1 and edition to 2021. +- Use u64 for the GroupWord on WebAssembly. (#271) +- Optimized `find`. (#279) +- Made rehashing and resizing less generic to reduce compilation time. (#282) +- Inlined small functions. (#283) +- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292) +- Relaxed the bounds on `Debug` for `HashSet`. (#296) +- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291) +- Don't hash the key when searching in an empty table. (#305) + +### Fixed + +- Guard against allocations exceeding isize::MAX. (#268) +- Made `RawTable::insert_no_grow` unsafe. (#254) +- Inline `static_empty`. (#280) +- Fixed trait bounds on Send/Sync impls. (#303) + +## [v0.11.2] - 2021-03-25 + +### Fixed + +- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) + +## [v0.11.1] - 2021-03-20 + +### Fixed + +- Added missing `pub` modifier to `BumpWrapper`. (#251) + +## [v0.11.0] - 2021-03-14 + +### Added +- Added safe `try_insert_no_grow` method to `RawTable`. (#229) +- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) +- Implemented `Default` for `RawTable`. (#237) +- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and + `HashMap::get_each_key_value_mut`. (#239) +- Added `From>` for `HashSet`. (#235) +- Added `try_insert` method to `HashMap`. (#247) + +### Changed +- The minimum Rust version has been bumped to 1.49.0. (#230) +- Significantly improved compilation times by reducing the amount of generated IR. (#205) + +### Removed +- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) +- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) + +### Fixed +- Fixed union length comparison. (#228) + +## ~~[v0.10.0] - 2021-01-16~~ + +This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) + +### Changed +- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) +- Improved branch prediction hints on stable. (#209) +- Optimized hashing of primitive types with AHash using specialization. (#207) +- Only instantiate `RawTable`'s reserve functions once per key-value. (#204) + +## [v0.9.1] - 2020-09-28 + +### Added +- Added safe methods to `RawTable` (#202): + - `get`: `find` and `as_ref` + - `get_mut`: `find` and `as_mut` + - `insert_entry`: `insert` and `as_mut` + - `remove_entry`: `find` and `remove` + - `erase_entry`: `find` and `erase` + +### Changed +- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) +- Made `RawTable::drain` safe. (#201) + +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + +## [v0.8.2] - 2020-08-08 + +### Changed +- Avoid closures to improve compile times. (#183) +- Do not iterate to drop if empty. (#182) + +## [v0.8.1] - 2020-07-16 + +### Added +- Added `erase` and `remove` to `RawTable`. (#171) +- Added `try_with_capacity` to `RawTable`. (#174) +- Added methods that allow re-using a `RawIter` for `RawDrain`, + `RawIntoIter`, and `RawParIter`. (#175) +- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175) +- Added a `drain_filter` function to `HashSet`. (#179) + +### Changed +- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176) +- `insert_no_grow` is now exposed under the `"raw"` feature. (#180) + +## [v0.8.0] - 2020-06-18 + +### Fixed +- Marked `RawTable::par_iter` as `unsafe`. (#157) + +### Changed +- Reduced the size of `HashMap`. (#159) +- No longer create tables with a capacity of 1 element. (#162) +- Removed `K: Eq + Hash` bounds on `retain`. (#163) +- Pulled in `HashMap` changes from rust-lang/rust (#164): + - `extend_one` support on nightly. + - `CollectionAllocErr` renamed to `TryReserveError`. + - Added `HashSet::get_or_insert_owned`. + - `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`. + +## [v0.7.2] - 2020-04-27 + +### Added +- Added `or_insert_with_key` to `Entry`. (#152) + +### Fixed +- Partially reverted `Clone` optimization which was unsound. (#154) + +### Changed +- Disabled use of `const-random` by default, which prevented reproducible builds. (#155) +- Optimized `repeat` function. (#150) +- Use `NonNull` for buckets, which improves codegen for iterators. (#148) + +## [v0.7.1] - 2020-03-16 + +### Added +- Added `HashMap::get_key_value_mut`. (#145) + +### Changed +- Optimized `Clone` implementation. (#146) + +## [v0.7.0] - 2020-01-31 + +### Added +- Added a `drain_filter` function to `HashMap`. (#135) + +### Changed +- Updated `ahash` dependency to 0.3. (#141) +- Optimized set union and intersection. (#130) +- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123) +- `RawTable::bucket_index` can now be used under the `raw` feature. (#128) + +## [v0.6.3] - 2019-10-31 + +### Added +- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the + `compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125) + +## [v0.6.2] - 2019-10-23 + +### Added +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between + runtime performance and compilation time. (#119) + +## [v0.6.1] - 2019-10-04 + +### Added +- Added `Entry::insert` and `RawEntryMut::insert`. (#118) + +### Changed +- `Group::static_empty` was changed from a `const` to a `static` (#116). + +## [v0.6.0] - 2019-08-13 + +### Fixed +- Fixed AHash accidentally depending on `std`. (#110) + +### Changed +- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency). + +## ~~[v0.5.1] - 2019-08-04~~ + +This release was _yanked_ due to a breaking change for users of `no-default-features`. + +### Added +- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108) +- Added entry-like methods for `HashSet`. (#98) + +### Changed +- Changed the default hasher from FxHash to AHash. (#97) +- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96) + +### Fixed +- We now avoid growing the table during insertions when it wasn't necessary. (#106) +- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100) +- Relaxed `lazy_static` version. (#92) + +## [v0.5.0] - 2019-06-12 + +### Fixed +- Resize with a more conservative amount of space after deletions. (#86) + +### Changed +- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89) + +## [v0.4.0] - 2019-05-30 + +### Fixed +- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82) + +## [v0.3.1] - 2019-05-30 + +### Fixed +- Fixed incorrect use of slice in unsafe code. (#80) + +## [v0.3.0] - 2019-04-23 + +### Changed +- Changed shrink_to to not panic if min_capacity < capacity. (#67) + +### Fixed +- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66) + +## [v0.2.2] - 2019-04-16 + +### Fixed +- Inlined non-nightly lowest_set_bit_nonzero. (#64) +- Fixed build on latest nightly. (#65) + +## [v0.2.1] - 2019-04-14 + +### Changed +- Use for_each in map Extend and FromIterator. (#58) +- Improved worst-case performance of HashSet.is_subset. (#61) + +### Fixed +- Removed incorrect debug_assert. (#60) + +## [v0.2.0] - 2019-03-31 + +### Changed +- The code has been updated to Rust 2018 edition. This means that the minimum + Rust version has been bumped to 1.31 (2018 edition). + +### Added +- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54) +- Added support for using hashbrown as the hash table implementation in libstd. (#46) + +### Fixed +- Fixed cargo build with minimal-versions. (#45) +- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46) +- ZST keys and values are now handled properly. (#46) + +## [v0.1.8] - 2019-01-14 + +### Added +- Rayon parallel iterator support (#37) +- `raw_entry` support (#31) +- `#[may_dangle]` on nightly (#31) +- `try_reserve` support (#31) + +### Fixed +- Fixed variance on `IterMut`. (#31) + +## [v0.1.7] - 2018-12-05 + +### Fixed +- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32) +- Fixed overflow in rehash_in_place. (#33) + +## [v0.1.6] - 2018-11-17 + +### Fixed +- Fixed compile error on nightly. (#29) + +## [v0.1.5] - 2018-11-08 + +### Fixed +- Fixed subtraction overflow in generic::Group::match_byte. (#28) + +## [v0.1.4] - 2018-11-04 + +### Fixed +- Fixed a bug in the `erase_no_drop` implementation. (#26) + +## [v0.1.3] - 2018-11-01 + +### Added +- Serde support. (#14) + +### Fixed +- Make the compiler inline functions more aggressively. (#20) + +## [v0.1.2] - 2018-10-31 + +### Fixed +- `clear` segfaults when called on an empty table. (#13) + +## [v0.1.1] - 2018-10-30 + +### Fixed +- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3) +- Missing `Send` and `Sync` for hash map and iterator types. (#7) +- Bug when inserting into a table smaller than the group width. (#5) + +## v0.1.0 - 2018-10-29 + +- Initial release + +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...HEAD +[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5 +[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4 +[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3 +[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2 +[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0 +[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2 +[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1 +[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3 +[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2 +[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1 +[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0 +[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2 +[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1 +[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 +[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 +[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 +[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 +[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0 +[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0 +[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0 +[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0 +[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8 +[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7 +[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1 diff --git a/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml b/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml new file mode 100644 index 00000000000000..0a5434e4946451 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml @@ -0,0 +1,137 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.63.0" +name = "hashbrown" +version = "0.14.5" +authors = ["Amanieu d'Antras "] +exclude = [ + ".github", + "/ci/*", +] +description = "A Rust port of Google's SwissTable hash map" +readme = "README.md" +keywords = [ + "hash", + "no_std", + "hashmap", + "swisstable", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" + +[package.metadata.docs.rs] +features = [ + "nightly", + "rayon", + "serde", + "raw", +] +rustdoc-args = ["--generate-link-to-definition"] + +[dependencies.ahash] +version = "0.8.7" +optional = true +default-features = false + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.allocator-api2] +version = "0.2.9" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.equivalent] +version = "1.0" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.0" +optional = true + +[dependencies.rkyv] +version = "0.7.42" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.25" +optional = true +default-features = false + +[dev-dependencies.bumpalo] +version = "3.13.0" +features = ["allocator-api2"] + +[dev-dependencies.doc-comment] +version = "0.3.1" + +[dev-dependencies.fnv] +version = "1.0.7" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.rand] +version = "0.8.3" +features = ["small_rng"] + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.rkyv] +version = "0.7.42" +features = ["validation"] + +[dev-dependencies.serde_test] +version = "1.0" + +[features] +default = [ + "ahash", + "inline-more", + "allocator-api2", +] +inline-more = [] +nightly = [ + "allocator-api2?/nightly", + "bumpalo/allocator_api", +] +raw = [] +rustc-dep-of-std = [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api", +] +rustc-internal-api = [] diff --git a/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml.orig b/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml.orig new file mode 100644 index 00000000000000..7e50b438f69248 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/Cargo.toml.orig @@ -0,0 +1,71 @@ +[package] +name = "hashbrown" +version = "0.14.5" +authors = ["Amanieu d'Antras "] +description = "A Rust port of Google's SwissTable hash map" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +exclude = [".github", "/ci/*"] +edition = "2021" +rust-version = "1.63.0" + +[dependencies] +# For the default hasher +ahash = { version = "0.8.7", default-features = false, optional = true } + +# For external trait impls +rayon = { version = "1.0", optional = true } +serde = { version = "1.0.25", default-features = false, optional = true } +rkyv = { version = "0.7.42", optional = true, default-features = false, features = [ + "alloc", +] } + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +# Support for allocators that use allocator-api2 +allocator-api2 = { version = "0.2.9", optional = true, default-features = false, features = [ + "alloc", +] } + +# Equivalent trait which can be shared with other hash table implementations. +equivalent = { version = "1.0", optional = true, default-features = false } + +[dev-dependencies] +lazy_static = "1.4" +rand = { version = "0.8.3", features = ["small_rng"] } +rayon = "1.0" +fnv = "1.0.7" +serde_test = "1.0" +doc-comment = "0.3.1" +bumpalo = { version = "3.13.0", features = ["allocator-api2"] } +rkyv = { version = "0.7.42", features = ["validation"] } + +[features] +default = ["ahash", "inline-more", "allocator-api2"] + +nightly = ["allocator-api2?/nightly", "bumpalo/allocator_api"] + +rustc-internal-api = [] +rustc-dep-of-std = [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api", +] +raw = [] + +# Enables usage of `#[inline]` on far more functions than by default in this +# crate. This may lead to a performance increase but often comes at a compile +# time cost. +inline-more = [] + +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw"] +rustdoc-args = ["--generate-link-to-definition"] diff --git a/deps/crates/vendor/hashbrown-0.14.5/LICENSE-APACHE b/deps/crates/vendor/hashbrown-0.14.5/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/hashbrown-0.14.5/LICENSE-MIT b/deps/crates/vendor/hashbrown-0.14.5/LICENSE-MIT new file mode 100644 index 00000000000000..5afc2a7b0acabd --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/hashbrown-0.14.5/README.md b/deps/crates/vendor/hashbrown-0.14.5/README.md new file mode 100644 index 00000000000000..5eaef8bd017873 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/README.md @@ -0,0 +1,125 @@ +hashbrown +========= + +[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions) +[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) +[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.63.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) + +This crate is a Rust port of Google's high-performance [SwissTable] hash +map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +and `HashSet` types. + +The original C++ version of SwissTable can be found [here], and this +[CppCon talk] gives an overview of how the algorithm works. + +Since Rust 1.36, this is now the `HashMap` implementation for the Rust standard +library. However you may still want to use this crate instead since it works +in environments without `std`, such as embedded systems and kernels. + +[SwissTable]: https://abseil.io/blog/20180927-swisstables +[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +## [Change log](CHANGELOG.md) + +## Features + +- Drop-in replacement for the standard library `HashMap` and `HashSet` types. +- Uses [AHash](https://github.com/tkaitchuck/aHash) as the default hasher, which is much faster than SipHash. + However, AHash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Around 2x faster than the previous standard library `HashMap`. +- Lower memory usage: only 1 byte of overhead per entry instead of 8. +- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). +- Empty hash maps do not allocate any memory. +- SIMD lookups to scan multiple hash entries in parallel. + +## Performance + +Compared to the previous implementation of `std::collections::HashMap` (Rust 1.35). + +With the hashbrown default AHash hasher: + +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :-------------------------- | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 | +| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 | +| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 | +| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 | +| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 | +| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 | +| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 | +| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 | +| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 | +| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 | +| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 | +| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 | +| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 | +| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 | +| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 | + + +With the libstd default SipHash hasher: + +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :------------------------ | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_std_highbits | 19,216 | 16,885 | -2,331 | -12.13% | x 1.14 | +| insert_std_random | 19,179 | 17,034 | -2,145 | -11.18% | x 1.13 | +| insert_std_serial | 19,462 | 17,493 | -1,969 | -10.12% | x 1.11 | +| insert_erase_std_highbits | 50,825 | 35,847 | -14,978 | -29.47% | x 1.42 | +| insert_erase_std_random | 51,448 | 35,392 | -16,056 | -31.21% | x 1.45 | +| insert_erase_std_serial | 87,711 | 38,091 | -49,620 | -56.57% | x 2.30 | +| iter_std_highbits | 1,378 | 1,159 | -219 | -15.89% | x 1.19 | +| iter_std_random | 1,395 | 1,132 | -263 | -18.85% | x 1.23 | +| iter_std_serial | 1,704 | 1,105 | -599 | -35.15% | x 1.54 | +| lookup_std_highbits | 17,195 | 13,642 | -3,553 | -20.66% | x 1.26 | +| lookup_std_random | 17,181 | 13,773 | -3,408 | -19.84% | x 1.25 | +| lookup_std_serial | 15,483 | 13,651 | -1,832 | -11.83% | x 1.13 | +| lookup_fail_std_highbits | 20,926 | 13,474 | -7,452 | -35.61% | x 1.55 | +| lookup_fail_std_random | 21,766 | 13,505 | -8,261 | -37.95% | x 1.61 | +| lookup_fail_std_serial | 19,336 | 13,519 | -5,817 | -30.08% | x 1.43 | + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hashbrown = "0.14" +``` + +Then: + +```rust +use hashbrown::HashMap; + +let mut map = HashMap::new(); +map.insert(1, "one"); +``` +## Flags +This crate has the following Cargo features: + +- `nightly`: Enables nightly-only features including: `#[may_dangle]`. +- `serde`: Enables serde serialization support. +- `rkyv`: Enables rkyv serialization support. +- `rayon`: Enables rayon parallel iterator support. +- `raw`: Enables access to the experimental and unsafe `RawTable` API. +- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost + of compilation time. (enabled by default) +- `ahash`: Compiles with ahash as default hasher. (enabled by default) +- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) + +## License + +Licensed under either of: + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/deps/crates/vendor/hashbrown-0.14.5/benches/bench.rs b/deps/crates/vendor/hashbrown-0.14.5/benches/bench.rs new file mode 100644 index 00000000000000..346bd7ef8983a1 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/benches/bench.rs @@ -0,0 +1,331 @@ +// This benchmark suite contains some benchmarks along a set of dimensions: +// Hasher: std default (SipHash) and crate default (AHash). +// Int key distribution: low bit heavy, top bit heavy, and random. +// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter +#![feature(test)] + +extern crate test; + +use test::{black_box, Bencher}; + +use hashbrown::hash_map::DefaultHashBuilder; +use hashbrown::{HashMap, HashSet}; +use std::{ + collections::hash_map::RandomState, + sync::atomic::{self, AtomicUsize}, +}; + +const SIZE: usize = 1000; + +// The default hashmap when using this crate directly. +type AHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; + +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + state: usize, +} + +impl RandomKeys { + fn new() -> Self { + RandomKeys { state: 0 } + } +} + +impl Iterator for RandomKeys { + type Item = usize; + fn next(&mut self) -> Option { + // Add 1 then multiply by some 32 bit prime. + self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781); + Some(self.state) + } +} + +// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path +// when dropping maps/entries (most real world usages likely have drop in the key or value) +lazy_static::lazy_static! { + static ref SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0); +} + +#[derive(Clone)] +struct DropType(usize); +impl Drop for DropType { + fn drop(&mut self) { + SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst); + } +} + +macro_rules! bench_suite { + ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident, + $bench_ahash_highbits:ident, $bench_std_highbits:ident, + $bench_ahash_random:ident, $bench_std_random:ident) => { + $bench_macro!($bench_ahash_serial, AHashMap, 0..); + $bench_macro!($bench_std_serial, StdHashMap, 0..); + $bench_macro!( + $bench_ahash_highbits, + AHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!( + $bench_std_highbits, + StdHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new()); + $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default()); + b.iter(|| { + m.clear(); + for i in ($keydist).take(SIZE) { + m.insert(i, (DropType(i), [i; 20])); + } + black_box(&mut m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert, + insert_ahash_serial, + insert_std_serial, + insert_ahash_highbits, + insert_std_highbits, + insert_ahash_random, + insert_std_random +); + +macro_rules! bench_grow_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + black_box(&mut m); + }) + } + }; +} + +bench_suite!( + bench_grow_insert, + grow_insert_ahash_serial, + grow_insert_std_serial, + grow_insert_ahash_highbits, + grow_insert_std_highbits, + grow_insert_ahash_random, + grow_insert_std_random +); + +macro_rules! bench_insert_erase { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut base = $maptype::default(); + for i in ($keydist).take(SIZE) { + base.insert(i, DropType(i)); + } + let skip = $keydist.skip(SIZE); + b.iter(|| { + let mut m = base.clone(); + let mut add_iter = skip.clone(); + let mut remove_iter = $keydist; + // While keeping the size constant, + // replace the first keydist with the second. + for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) { + m.insert(add, DropType(add)); + black_box(m.remove(&remove)); + } + black_box(m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert_erase, + insert_erase_ahash_serial, + insert_erase_std_serial, + insert_erase_ahash_highbits, + insert_erase_std_highbits, + insert_erase_ahash_random, + insert_erase_std_random +); + +macro_rules! bench_lookup { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist.take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in $keydist.take(SIZE) { + black_box(m.get(&i)); + } + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_lookup, + lookup_ahash_serial, + lookup_std_serial, + lookup_ahash_highbits, + lookup_std_highbits, + lookup_ahash_random, + lookup_std_random +); + +macro_rules! bench_lookup_fail { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(SIZE) { + black_box(m.get(&i)); + } + }) + } + }; +} + +bench_suite!( + bench_lookup_fail, + lookup_fail_ahash_serial, + lookup_fail_std_serial, + lookup_fail_ahash_highbits, + lookup_fail_std_highbits, + lookup_fail_ahash_random, + lookup_fail_std_random +); + +macro_rules! bench_iter { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }) + } + }; +} + +bench_suite!( + bench_iter, + iter_ahash_serial, + iter_std_serial, + iter_ahash_highbits, + iter_std_highbits, + iter_ahash_random, + iter_std_random +); + +#[bench] +fn clone_small(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_small(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn clone_large(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_large(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn rehash_in_place(b: &mut Bencher) { + b.iter(|| { + let mut set = HashSet::new(); + + // Each loop triggers one rehash + for _ in 0..10 { + for i in 0..223 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + set.clear(); + } + }); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/benches/insert_unique_unchecked.rs b/deps/crates/vendor/hashbrown-0.14.5/benches/insert_unique_unchecked.rs new file mode 100644 index 00000000000000..857ad18e57e0b4 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/benches/insert_unique_unchecked.rs @@ -0,0 +1,32 @@ +//! Compare `insert` and `insert_unique_unchecked` operations performance. + +#![feature(test)] + +extern crate test; + +use hashbrown::HashMap; +use test::Bencher; + +#[bench] +fn insert(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + m.insert(k, k); + } + m + }); +} + +#[bench] +fn insert_unique_unchecked(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + m.insert_unique_unchecked(k, k); + } + m + }); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/clippy.toml b/deps/crates/vendor/hashbrown-0.14.5/clippy.toml new file mode 100644 index 00000000000000..d98bf2c09b13a4 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ] diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/mod.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/mod.rs new file mode 100644 index 00000000000000..01d386b0464740 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/mod.rs @@ -0,0 +1,6 @@ +#[cfg(feature = "rayon")] +pub(crate) mod rayon; +#[cfg(feature = "rkyv")] +mod rkyv; +#[cfg(feature = "serde")] +mod serde; diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs new file mode 100644 index 00000000000000..070b08cd56d7b2 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs @@ -0,0 +1,27 @@ +use alloc::collections::LinkedList; +use alloc::vec::Vec; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Helper for collecting parallel iterators to an intermediary +#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending! +pub(super) fn collect(iter: I) -> (LinkedList>, usize) { + let list = iter + .into_par_iter() + .fold(Vec::new, |mut vec, elem| { + vec.push(elem); + vec + }) + .map(|vec| { + let mut list = LinkedList::new(); + list.push_back(vec); + list + }) + .reduce(LinkedList::new, |mut list1, mut list2| { + list1.append(&mut list2); + list1 + }); + + let len = list.iter().map(Vec::len).sum(); + (list, len) +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs new file mode 100644 index 00000000000000..2534dc9b2ba2ae --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs @@ -0,0 +1,721 @@ +//! Rayon extensions for `HashMap`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_map::HashMap; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to keys in a map. +/// +/// This iterator is created by the [`par_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().0 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParKeys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to values in a map. +/// +/// This iterator is created by the [`par_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().1 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParValues<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_mut(); + (&r.0, &mut r.1) + }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over mutable references to values in a map. +/// +/// This iterator is created by the [`par_values_mut`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &mut x.as_mut().1 }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParDrain<'a, K, V, A: Allocator = Global> { + inner: RawParDrain<'a, (K, V), A>, +} + +impl ParallelIterator for ParDrain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashMap { + /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl HashMap { + /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } + } +} + +impl HashMap +where + K: Eq + Hash + Sync, + V: PartialEq + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Returns `true` if the map is equal to another, + /// i.e. both maps contain the same keys mapped to the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .into_par_iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl IntoParallelIterator for HashMap { + type Item = (K, V); + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.table.into_par_iter(), + } + } +} + +impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +/// Collect (key, value) pairs from a parallel iterator into a +/// hashmap. If multiple pairs correspond to the same key, then the +/// ones produced earlier in the parallel iterator will be +/// overwritten, just as with a sequential iterator. +impl FromParallelIterator<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut map = HashMap::default(); + map.par_extend(par_iter); + map + } +} + +/// Extend a hash map with items from a parallel iterator. +impl ParallelExtend<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash map with copied items from a parallel iterator. +impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap +where + K: Copy + Eq + Hash + Sync, + V: Copy + Sync, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashMap` -- no custom advantage. +fn extend(map: &mut HashMap, par_iter: I) +where + K: Eq + Hash, + S: BuildHasher, + I: IntoParallelIterator, + A: Allocator, + HashMap: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire length if the map is empty. + // Otherwise reserve half the length (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if map.is_empty() { len } else { (len + 1) / 2 }; + map.reserve(reserve); + for vec in list { + map.extend(vec); + } +} + +#[cfg(test)] +mod test_par_map { + use alloc::vec::Vec; + use core::hash::{Hash, Hasher}; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_map::HashMap; + + struct Dropable<'a> { + k: usize, + counter: &'a AtomicUsize, + } + + impl Dropable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> { + counter.fetch_add(1, Ordering::Relaxed); + + Dropable { k, counter } + } + } + + impl Drop for Dropable<'_> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + impl Clone for Dropable<'_> { + fn clone(&self) -> Self { + Dropable::new(self.k, self.counter) + } + } + + impl Hash for Dropable<'_> { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.k.hash(state); + } + } + + impl PartialEq for Dropable<'_> { + fn eq(&self, other: &Self) -> bool { + self.k == other.k + } + } + + impl Eq for Dropable<'_> {} + + #[test] + fn test_into_iter_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the iterator does not leak anything. + drop(hm.clone().into_par_iter()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect(); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_drain_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let mut hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the drain iterator does not leak anything. + drop(hm.clone().par_drain()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect(); + assert!(hm.is_empty()); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.par_drain().count(), 0); + assert_eq!(m.par_keys().count(), 0); + assert_eq!(m.par_values().count(), 0); + assert_eq!(m.par_values_mut().count(), 0); + assert_eq!(m.par_iter().count(), 0); + assert_eq!(m.par_iter_mut().count(), 0); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_par_iter().count(), 0); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let observed = AtomicUsize::new(0); + + m.par_iter().for_each(|(k, v)| { + assert_eq!(*v, *k * 2); + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(!m1.par_eq(&m2)); + + m2.insert(3, 4); + + assert!(m1.par_eq(&m2)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.par_iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.par_extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs new file mode 100644 index 00000000000000..61ca69b61d7f26 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs @@ -0,0 +1,5 @@ +mod helpers; +pub(crate) mod map; +pub(crate) mod raw; +pub(crate) mod set; +pub(crate) mod table; diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs new file mode 100644 index 00000000000000..612be47a55d16e --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs @@ -0,0 +1,230 @@ +use crate::raw::Bucket; +use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; +use crate::scopeguard::guard; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use rayon::iter::{ + plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, + ParallelIterator, +}; + +/// Parallel iterator which returns a raw pointer to every full bucket in the table. +pub struct RawParIter { + iter: RawIterRange, +} + +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + +impl From> for RawParIter { + fn from(it: RawIter) -> Self { + RawParIter { iter: it.iter } + } +} + +impl ParallelIterator for RawParIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let producer = ParIterProducer { iter: self.iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Producer which returns a `Bucket` for every element. +struct ParIterProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParIterProducer { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.split(); + let left = ParIterProducer { iter: left }; + let right = right.map(|right| ParIterProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(self, folder: F) -> F + where + F: Folder, + { + folder.consume_iter(self.iter) + } +} + +/// Parallel iterator which consumes a table and returns elements. +pub struct RawIntoParIter { + table: RawTable, +} + +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.par_iter() + } +} + +impl ParallelIterator for RawIntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let iter = unsafe { self.table.iter().iter }; + let _guard = guard(self.table.into_allocation(), |alloc| { + if let Some((ptr, layout, ref alloc)) = *alloc { + unsafe { + alloc.deallocate(ptr, layout); + } + } + }); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Parallel iterator which consumes elements without freeing the table storage. +pub struct RawParDrain<'a, T, A: Allocator = Global> { + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. + table: NonNull>, + marker: PhantomData<&'a RawTable>, +} + +unsafe impl Send for RawParDrain<'_, T, A> {} + +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.as_ref().par_iter() + } +} + +impl ParallelIterator for RawParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let _guard = guard(self.table, |table| unsafe { + table.as_mut().clear_no_drop(); + }); + let iter = unsafe { self.table.as_ref().iter().iter }; + mem::forget(self); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +impl Drop for RawParDrain<'_, T, A> { + fn drop(&mut self) { + // If drive_unindexed is not called then simply clear the table. + unsafe { + self.table.as_mut().clear(); + } + } +} + +/// Producer which will consume all elements in the range, even if it is dropped +/// halfway through. +struct ParDrainProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParDrainProducer { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.clone().split(); + mem::forget(self); + let left = ParDrainProducer { iter: left }; + let right = right.map(|right| ParDrainProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(mut self, mut folder: F) -> F + where + F: Folder, + { + // Make sure to modify the iterator in-place so that any remaining + // elements are processed in our Drop impl. + for item in &mut self.iter { + folder = folder.consume(unsafe { item.read() }); + if folder.full() { + return folder; + } + } + + // If we processed all elements then we don't need to run the drop. + mem::forget(self); + folder + } +} + +impl Drop for ParDrainProducer { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // Drop all remaining elements + if mem::needs_drop::() { + for item in &mut self.iter { + unsafe { + item.drop(); + } + } + } + } +} + +impl RawTable { + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn par_iter(&self) -> RawParIter { + RawParIter { + iter: self.iter().iter, + } + } + + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_par_iter(self) -> RawIntoParIter { + RawIntoParIter { table: self } + } + + /// Returns a parallel iterator which consumes all elements of a `RawTable` + /// without freeing its memory allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> { + RawParDrain { + table: NonNull::from(self), + marker: PhantomData, + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs new file mode 100644 index 00000000000000..3de98fccb89d1d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs @@ -0,0 +1,659 @@ +//! Rayon extensions for `HashSet`. + +use super::map; +use crate::hash_set::HashSet; +use crate::raw::{Allocator, Global}; +use core::hash::{BuildHasher, Hash}; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over elements of a consumed set. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: map::IntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel draining iterator over entries of a set. +/// +/// This iterator is created by the [`par_drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: map::ParDrain<'a, T, (), A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in a set. +/// +/// This iterator is created by the [`par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the difference of +/// sets. +/// +/// This iterator is created by the [`par_difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| !self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the symmetric +/// difference of sets. +/// +/// This iterator is created by the [`par_symmetric_difference`] method on +/// [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .par_difference(self.b) + .chain(self.b.par_difference(self.a)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the intersection of +/// sets. +/// +/// This iterator is created by the [`par_intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParIntersection<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the union of sets. +/// +/// This iterator is created by the [`par_union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParUnion<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.a.len() <= self.b.len() { + (self.a, self.b) + } else { + (self.b, self.a) + }; + larger + .into_par_iter() + .chain(smaller.par_difference(larger)) + .drive_unindexed(consumer) + } +} + +impl HashSet +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Visits (potentially in parallel) the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { + ParUnion { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the difference, + /// i.e. the values that are in `self` but not in `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> { + ParDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the symmetric + /// difference, i.e. the values that are in `self` or in `other` but not in both. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_symmetric_difference<'a>( + &'a self, + other: &'a Self, + ) -> ParSymmetricDifference<'a, T, S, A> { + ParSymmetricDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the + /// intersection, i.e. the values that are both in `self` and `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> { + ParIntersection { a: self, b: other } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_disjoint(&self, other: &Self) -> bool { + self.into_par_iter().all(|x| !other.contains(x)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_subset(&self, other: &Self) -> bool { + if self.len() <= other.len() { + self.into_par_iter().all(|x| other.contains(x)) + } else { + false + } + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_superset(&self, other: &Self) -> bool { + other.par_is_subset(self) + } + + /// Returns `true` if the set is equal to another, + /// i.e. both sets contain the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.par_is_subset(other) + } +} + +impl HashSet +where + T: Eq + Hash + Send, + A: Allocator + Send, +{ + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the set's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } + } +} + +impl IntoParallelIterator for HashSet { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.map.into_par_iter(), + } + } +} + +impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: self.map.par_keys(), + } + } +} + +/// Collect values from a parallel iterator into a hashset. +impl FromParallelIterator for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut set = HashSet::default(); + set.par_extend(par_iter); + set + } +} + +/// Extend a hash set with items from a parallel iterator. +impl ParallelExtend for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash set with copied items from a parallel iterator. +impl<'a, T, S> ParallelExtend<&'a T> for HashSet +where + T: 'a + Copy + Eq + Hash + Sync, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashSet` -- no custom advantage. +fn extend(set: &mut HashSet, par_iter: I) +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, + I: IntoParallelIterator, + HashSet: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Values may be already present or show multiple times in the iterator. + // Reserve the entire length if the set is empty. + // Otherwise reserve half the length (rounded up), so the set + // will only resize twice in the worst case. + let reserve = if set.is_empty() { len } else { (len + 1) / 2 }; + set.reserve(reserve); + for vec in list { + set.extend(vec); + } +} + +#[cfg(test)] +mod test_par_set { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_set::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.par_is_disjoint(&ys)); + assert!(!ys.par_is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(!b.par_is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(b.par_is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let i = a + .par_intersection(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let expected = [1, 5, 11]; + let i = a + .par_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let expected = [-2, 1, 5, 11, 14, 22]; + let i = a + .par_symmetric_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + let i = a + .par_union(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.par_iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(!s1.par_eq(&s2)); + + s2.insert(3); + + assert!(s1.par_eq(&s2)); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.par_extend(&[2, 3, 4][..]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.par_extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs new file mode 100644 index 00000000000000..e8e50944ad98ab --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs @@ -0,0 +1,252 @@ +//! Rayon extensions for `HashTable`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_table::HashTable; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_ref() }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> { + type Item = &'a mut T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_mut() }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain +/// [`HashTable`]: /hashbrown/struct.HashTable.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: RawParDrain<'a, T, A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashTable { + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.raw.par_drain(), + } + } +} + +impl IntoParallelIterator for HashTable { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.raw.into_par_iter(), + } + } +} + +impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable { + type Item = &'a mut T; + type Iter = ParIterMut<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test_par_table { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::{ + hash_map::{make_hash, DefaultHashBuilder}, + hash_table::HashTable, + }; + + #[test] + fn test_iterate() { + let hasher = DefaultHashBuilder::default(); + let mut a = HashTable::new(); + for i in 0..32 { + a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_move_iter() { + let hasher = DefaultHashBuilder::default(); + let hs = { + let mut hs = HashTable::new(); + + hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x)); + hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x)); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs new file mode 100644 index 00000000000000..fae7f76763a9d7 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs @@ -0,0 +1,125 @@ +use crate::HashMap; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_map::{ArchivedHashMap, HashMapResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashMap +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashMap; + type Resolver = HashMapResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashMap::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashMap +where + K: Serialize + Hash + Eq, + K::Archived: Hash + Eq, + V: Serialize, + S: Serializer + ScratchSpace + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashMap::serialize_from_iter(self.iter(), serializer) } + } +} + +impl + Deserialize, D> for ArchivedHashMap +where + K::Archived: Deserialize + Hash + Eq, + V::Archived: Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashMap::with_capacity_and_hasher(self.len(), S::default()); + for (k, v) in self.iter() { + result.insert(k.deserialize(deserializer)?, v.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq, S: BuildHasher> + PartialEq> for ArchivedHashMap +{ + #[inline] + fn eq(&self, other: &HashMap) -> bool { + if self.len() != other.len() { + false + } else { + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| value.eq(v))) + } + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq> + PartialEq> for HashMap +{ + #[inline] + fn eq(&self, other: &ArchivedHashMap) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashMap; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for (k, v) in value.iter() { + let (ak, av) = archived.get_key_value(k.as_str()).unwrap(); + assert_eq!(k, ak); + assert_eq!(v, av); + } + + let deserialized: HashMap = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index map"); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs new file mode 100644 index 00000000000000..c8a69cf4fca584 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs @@ -0,0 +1,123 @@ +use crate::HashSet; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_set::{ArchivedHashSet, HashSetResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashSet +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashSet; + type Resolver = HashSetResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashSet::::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashSet +where + K::Archived: Hash + Eq, + K: Serialize + Hash + Eq, + S: ScratchSpace + Serializer + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashSet::serialize_from_iter(self.iter(), serializer) } + } +} + +impl Deserialize, D> for ArchivedHashSet +where + K: Archive + Hash + Eq, + K::Archived: Deserialize + Hash + Eq, + D: Fallible + ?Sized, + S: Default + BuildHasher, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashSet::with_hasher(S::default()); + for k in self.iter() { + result.insert(k.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for ArchivedHashSet +{ + #[inline] + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { + false + } else { + self.iter().all(|key| other.get(key).is_some()) + } + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for HashSet +{ + #[inline] + fn eq(&self, other: &ArchivedHashSet) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashSet; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for k in value.iter() { + let ak = archived.get(k.as_str()).unwrap(); + assert_eq!(k, ak); + } + + let deserialized: HashSet = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index set"); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs new file mode 100644 index 00000000000000..2bde6a06538c12 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs @@ -0,0 +1,2 @@ +mod hash_map; +mod hash_set; diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/serde.rs b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/serde.rs new file mode 100644 index 00000000000000..0a76dbec25c433 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/external_trait_impls/serde.rs @@ -0,0 +1,220 @@ +mod size_hint { + use core::cmp; + + /// This presumably exists to prevent denial of service attacks. + /// + /// Original discussion: https://github.com/serde-rs/serde/issues/1114. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } +} + +mod map { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_map::HashMap; + + use super::size_hint; + + impl Serialize for HashMap + where + K: Serialize + Eq + Hash, + V: Serialize, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + + impl<'de, K, V, S, A> Deserialize<'de> for HashMap + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, K, V, S, A> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + let mut values = HashMap::with_capacity_and_hasher_in( + size_hint::cautious(map.size_hint()), + S::default(), + A::default(), + ); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_set::HashSet; + + use super::size_hint; + + impl Serialize for HashSet + where + T: Serialize + Eq + Hash, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + + impl<'de, T, S, A> Deserialize<'de> for HashSet + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, T, S, A> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashSet; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + let mut values = HashSet::with_capacity_and_hasher_in( + size_hint::cautious(seq.size_hint()), + S::default(), + A::default(), + ); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + #[allow(clippy::missing_errors_doc)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet) + where + A: Allocator; + + impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A> + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + self.0.clear(); + self.0.reserve(size_hint::cautious(seq.size_hint())); + + while let Some(value) = seq.next_element()? { + self.0.insert(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/lib.rs b/deps/crates/vendor/hashbrown-0.14.5/src/lib.rs new file mode 100644 index 00000000000000..f03ddb6ad963f7 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/lib.rs @@ -0,0 +1,188 @@ +//! This crate is a Rust port of Google's high-performance [SwissTable] hash +//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +//! and `HashSet` types. +//! +//! The original C++ version of [SwissTable] can be found [here], and this +//! [CppCon talk] gives an overview of how the algorithm works. +//! +//! [SwissTable]: https://abseil.io/blog/20180927-swisstables +//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +#![no_std] +#![cfg_attr( + feature = "nightly", + feature( + test, + core_intrinsics, + dropck_eyepatch, + min_specialization, + extend_one, + allocator_api, + slice_ptr_get, + maybe_uninit_array_assume_init, + strict_provenance + ) +)] +#![allow( + clippy::doc_markdown, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::option_if_let_else, + clippy::redundant_else, + clippy::manual_map, + clippy::missing_safety_doc, + clippy::missing_errors_doc +)] +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] +#![cfg_attr(feature = "nightly", allow(internal_features))] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg_attr(test, macro_use)] +extern crate alloc; + +#[cfg(feature = "nightly")] +#[cfg(doctest)] +doc_comment::doctest!("../README.md"); + +#[macro_use] +mod macros; + +#[cfg(feature = "raw")] +/// Experimental and unsafe `RawTable` API. This module is only available if the +/// `raw` feature is enabled. +pub mod raw { + // The RawTable API is still experimental and is not properly documented yet. + #[allow(missing_docs)] + #[path = "mod.rs"] + mod inner; + pub use inner::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::raw::*; + } +} +#[cfg(not(feature = "raw"))] +mod raw; + +mod external_trait_impls; +mod map; +#[cfg(feature = "rustc-internal-api")] +mod rustc_entry; +mod scopeguard; +mod set; +mod table; + +pub mod hash_map { + //! A hash map implemented with quadratic probing and SIMD lookup. + pub use crate::map::*; + + #[cfg(feature = "rustc-internal-api")] + pub use crate::rustc_entry::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::map::*; + } +} +pub mod hash_set { + //! A hash set implemented as a `HashMap` where the value is `()`. + pub use crate::set::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash sets. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::set::*; + } +} +pub mod hash_table { + //! A hash table implemented with quadratic probing and SIMD lookup. + pub use crate::table::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash tables. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::table::*; + } +} + +pub use crate::map::HashMap; +pub use crate::set::HashSet; +pub use crate::table::HashTable; + +#[cfg(feature = "equivalent")] +pub use equivalent::Equivalent; + +// This is only used as a fallback when building as part of `std`. +#[cfg(not(feature = "equivalent"))] +/// Key equivalence trait. +/// +/// This trait defines the function used to compare the input value with the +/// map keys (or set values) during a lookup operation such as [`HashMap::get`] +/// or [`HashSet::contains`]. +/// It is provided with a blanket implementation based on the +/// [`Borrow`](core::borrow::Borrow) trait. +/// +/// # Correctness +/// +/// Equivalent values must hash to the same value. +pub trait Equivalent { + /// Checks if this value is equivalent to the given key. + /// + /// Returns `true` if both values are equivalent, and `false` otherwise. + /// + /// # Correctness + /// + /// When this function returns `true`, both `self` and `key` must hash to + /// the same value. + fn equivalent(&self, key: &K) -> bool; +} + +#[cfg(not(feature = "equivalent"))] +impl Equivalent for Q +where + Q: Eq, + K: core::borrow::Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + self == key.borrow() + } +} + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: alloc::alloc::Layout, + }, +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/macros.rs b/deps/crates/vendor/hashbrown-0.14.5/src/macros.rs new file mode 100644 index 00000000000000..eaba6bed1fcb6b --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/macros.rs @@ -0,0 +1,70 @@ +// See the cfg-if crate. +#[allow(unused_macro_rules)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +// Helper macro for specialization. This also helps avoid parse errors if the +// default fn syntax for specialization changes in the future. +#[cfg(feature = "nightly")] +macro_rules! default_fn { + (#[$($a:tt)*] $($tt:tt)*) => { + #[$($a)*] default $($tt)* + } +} +#[cfg(not(feature = "nightly"))] +macro_rules! default_fn { + ($($tt:tt)*) => { + $($tt)* + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/map.rs b/deps/crates/vendor/hashbrown-0.14.5/src/map.rs new file mode 100644 index 00000000000000..88a826582b79f6 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/map.rs @@ -0,0 +1,8960 @@ +use crate::raw::{ + Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable, +}; +use crate::{Equivalent, TryReserveError}; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ops::Index; + +/// Default hasher for `HashMap`. +#[cfg(feature = "ahash")] +pub type DefaultHashBuilder = core::hash::BuildHasherDefault; + +/// Dummy default hasher for `HashMap`. +#[cfg(not(feature = "ahash"))] +pub enum DefaultHashBuilder {} + +/// A hash map implemented with quadratic probing and SIMD lookup. +/// +/// The default hashing algorithm is currently [`AHash`], though this is +/// subject to change at any point in the future. This hash function is very +/// fast for all types of keys, but this algorithm will typically *not* protect +/// against attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashMap` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); +/// } +/// ``` +/// +/// `HashMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`fnv`]: https://crates.io/crates/fnv +/// [`AHash`]: https://crates.io/crates/ahash +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +/// +/// A `HashMap` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .into_iter().collect(); +/// // use the values stored in map +/// ``` +pub struct HashMap { + pub(crate) hash_builder: S, + pub(crate) table: RawTable<(K, V), A>, +} + +impl Clone for HashMap { + fn clone(&self) -> Self { + HashMap { + hash_builder: self.hash_builder.clone(), + table: self.table.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.table.clone_from(&source.table); + + // Update hash_builder only if we successfully cloned all elements. + self.hash_builder.clone_from(&source.hash_builder); + } +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +where + Q: Hash, + S: BuildHasher, +{ + move |val| make_hash::(hash_builder, &val.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ +where + Q: ?Sized + Equivalent, +{ + move |x| k.equivalent(&x.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ +where + Q: ?Sized + Equivalent, +{ + move |x| k.equivalent(x) +} + +#[cfg(not(feature = "nightly"))] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + use core::hash::Hasher; + let mut state = hash_builder.build_hasher(); + val.hash(&mut state); + state.finish() +} + +#[cfg(feature = "nightly")] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + hash_builder.hash_one(val) +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher`](HashMap::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher`](HashMap::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default()) + } +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher_in`](HashMap::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::new_in(&bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// + /// // The created HashMap also doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// // Now we insert element inside created HashMap + /// map.insert("One", 1); + /// // We can see that the HashMap holds 1 element + /// assert_eq!(map.len(), 1); + /// // And it also allocates some capacity + /// assert!(map.capacity() > 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self::with_hasher_in(DefaultHashBuilder::default(), alloc) + } + + /// Creates an empty `HashMap` with the specified capacity using the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher_in`](HashMap::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::with_capacity_in(5, &bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = map.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashMap + /// map.insert("One", 1); + /// map.insert("Two", 2); + /// map.insert("Three", 3); + /// map.insert("Four", 4); + /// map.insert("Five", 5); + /// + /// // We can see that the HashMap holds 5 elements + /// assert_eq!(map.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(map.capacity(), empty_map_capacity) + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The hash map is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } +} + +impl HashMap { + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.table.allocator() + } + + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. It will be allocated with the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. It will be allocated with the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<&str> = Vec::new(); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// vec.push(*key); + /// } + /// + /// // The `Keys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [11, 12, 13]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + inner: self.iter_mut(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + Iter { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in &map { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 2), ("b", 4), ("c", 6)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + IterMut { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + #[cfg(test)] + #[cfg_attr(feature = "inline-more", inline)] + fn raw_capacity(&self) -> usize { + self.table.buckets() + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// let capacity_before_drain = a.capacity(); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// // As we can see, the map is empty and contains no element. + /// assert!(a.is_empty() && a.len() == 0); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_drain); + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// { // Iterator is dropped without being consumed. + /// let d = a.drain(); + /// } + /// + /// // But the map is empty even if we do not use Drain iterator. + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { + inner: self.table.drain(), + } + } + + /// Retains only the elements specified by the predicate. Keeps the + /// allocated memory for reuse. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// assert_eq!(map.len(), 8); + /// + /// map.retain(|&k, _| k % 2 == 0); + /// + /// // We can see, that the number of elements inside map is changed. + /// assert_eq!(map.len(), 4); + /// + /// let mut vec: Vec<(i32, i32)> = map.iter().map(|(&k, &v)| (k, v)).collect(); + /// vec.sort_unstable(); + /// assert_eq!(vec, [(0, 0), (2, 20), (4, 40), (6, 60)]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.table.iter() { + let &mut (ref key, ref mut value) = item.as_mut(); + if !f(key, value) { + self.table.erase(item); + } + } + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all pairs `(k, v)` such that `f(&k, &mut v)` returns `true` out + /// into another iterator. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// Keeps the allocated memory for reuse. + /// + /// [`retain()`]: HashMap::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// let drained: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// { // Iterator is dropped without being consumed. + /// let d = map.extract_if(|k, _v| k % 2 != 0); + /// } + /// + /// // ExtractIf was not exhausted, therefore no elements were drained. + /// assert_eq!(map.len(), 8); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.table.iter() }, + table: &mut self.table, + }, + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// let capacity_before_clear = a.capacity(); + /// + /// a.clear(); + /// + /// // Map is empty. + /// assert!(a.is_empty()); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_clear); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.table.clear(); + } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + inner: self.into_iter(), + } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + inner: self.into_iter(), + } + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashMap::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.reserve(10); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.table + .reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned: + /// ``` + /// # fn test() { + /// use hashbrown::HashMap; + /// use hashbrown::TryReserveError; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.try_reserve(usize::MAX) { + /// Err(error) => match error { + /// TryReserveError::CapacityOverflow => {} + /// _ => panic!("TryReserveError::AllocError ?"), + /// }, + /// _ => panic!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(not(miri))] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.table + .try_reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.table + .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// This function does nothing if the current capacity is smaller than the + /// supplied minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.table + .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { + let hash = make_hash::(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { + Entry::Occupied(OccupiedEntry { + hash, + key: Some(key), + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } + + /// Gets the given key's corresponding entry by reference in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut words: HashMap = HashMap::new(); + /// let source = ["poneyland", "horseyland", "poneyland", "poneyland"]; + /// for (i, &s) in source.iter().enumerate() { + /// let counter = words.entry_ref(s).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(words["poneyland"], 3); + /// assert_eq!(words["horseyland"], 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry_ref<'a, 'b, Q: ?Sized>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.hash_builder, key); + if let Some(elem) = self.table.find(hash, equivalent_key(key)) { + EntryRef::Occupied(OccupiedEntryRef { + hash, + key: Some(KeyOrRef::Borrowed(key)), + elem, + table: self, + }) + } else { + EntryRef::Vacant(VacantEntryRef { + hash, + key: KeyOrRef::Borrowed(key), + table: self, + }) + } + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + #[inline] + fn get_inner(&self, k: &Q) -> Option<&(K, V)> + where + Q: Hash + Equivalent, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get(hash, equivalent_key(k)) + } + } + + /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// let (k, v) = map.get_key_value_mut(&1).unwrap(); + /// assert_eq!(k, &1); + /// assert_eq!(v, &mut "a"); + /// *v = "b"; + /// assert_eq!(map.get_key_value_mut(&1), Some((&1, &mut "b"))); + /// assert_eq!(map.get_key_value_mut(&2), None); + /// ``` + #[inline] + pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (ref key, ref mut value)) => Some((key, value)), + None => None, + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains_key(&self, k: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.get_inner(k).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// + /// assert_eq!(map.get_mut(&2), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (_, ref mut v)) => Some(v), + None => None, + } + } + + #[inline] + fn get_inner_mut(&mut self, k: &Q) -> Option<&mut (K, V)> + where + Q: Hash + Equivalent, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get_mut(hash, equivalent_key(k)) + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + where + Q: Hash + Equivalent, + { + self.get_many_mut_inner(ks).map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut V; N]> + where + Q: Hash + Equivalent, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the keys + /// are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// (&"Bodleian Library".to_string(), &mut 1602), + /// (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691), + /// ]), + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub fn get_many_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[(&'_ K, &'_ mut V); N]> + where + Q: Hash + Equivalent, + { + self.get_many_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys, without validating that the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_key_value_mut`](`HashMap::get_many_key_value_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// (&"Bodleian Library".to_string(), &mut 1602), + /// (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691), + /// ]), + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub unsafe fn get_many_key_value_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[(&'_ K, &'_ mut V); N]> + where + Q: Hash + Equivalent, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + fn get_many_mut_inner( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut (K, V); N]> + where + Q: Hash + Equivalent, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + unsafe fn get_many_unchecked_mut_inner( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut (K, V); N]> + where + Q: Hash + Equivalent, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + fn build_hashes_inner(&self, ks: [&Q; N]) -> [u64; N] + where + Q: Hash + Equivalent, + { + let mut hashes = [0_u64; N]; + for i in 0..N { + hashes[i] = make_hash::(&self.hash_builder, ks[i]); + } + hashes + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [`std::collections`] + /// [module-level documentation] for more. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// [`std::collections`]: https://doc.rust-lang.org/std/collections/index.html + /// [module-level documentation]: https://doc.rust-lang.org/std/collections/index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = make_hash::(&self.hash_builder, &k); + let hasher = make_hasher::<_, V, S>(&self.hash_builder); + match self + .table + .find_or_find_insert_slot(hash, equivalent_key(&k), hasher) + { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), + Err(slot) => { + unsafe { + self.table.insert_in_slot(hash, slot, (k, v)); + } + None + } + } + } + + /// Insert a key-value pair into the map without checking + /// if the key already exists in the map. + /// + /// Returns a reference to the key and value just inserted. + /// + /// This operation is safe if a key does not exist in the map. + /// + /// However, if a key exists in the map already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the map + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the map. + /// For example, when constructing a map from another map, we know + /// that keys are unique. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map1 = HashMap::new(); + /// assert_eq!(map1.insert(1, "a"), None); + /// assert_eq!(map1.insert(2, "b"), None); + /// assert_eq!(map1.insert(3, "c"), None); + /// assert_eq!(map1.len(), 3); + /// + /// let mut map2 = HashMap::new(); + /// + /// for (key, value) in map1.into_iter() { + /// map2.insert_unique_unchecked(key, value); + /// } + /// + /// let (key, value) = map2.insert_unique_unchecked(4, "d"); + /// assert_eq!(key, &4); + /// assert_eq!(value, &mut "d"); + /// *value = "e"; + /// + /// assert_eq!(map2[&1], "a"); + /// assert_eq!(map2[&2], "b"); + /// assert_eq!(map2[&3], "c"); + /// assert_eq!(map2[&4], "e"); + /// assert_eq!(map2.len(), 4); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { + let hash = make_hash::(&self.hash_builder, &k); + let bucket = self + .table + .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); + let (k_ref, v_ref) = unsafe { bucket.as_mut() }; + (k_ref, v_ref) + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// # Errors + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::OccupiedError; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// match map.try_insert(37, "b") { + /// Err(OccupiedError { entry, value }) => { + /// assert_eq!(entry.key(), &37); + /// assert_eq!(entry.get(), &"a"); + /// assert_eq!(value, "b"); + /// } + /// _ => panic!() + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert( + &mut self, + key: K, + value: V, + ) -> Result<&mut V, OccupiedError<'_, K, V, S, A>> { + match self.entry(key) { + Entry::Occupied(entry) => Err(OccupiedError { entry, value }), + Entry::Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map holds none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, k: &Q) -> Option + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.remove_entry(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.remove_entry(hash, equivalent_key(k)) + } +} + +impl HashMap { + /// Creates a raw entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the HashMap into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and + /// more foolproof APIs like `entry` should be preferred when possible. + /// + /// In particular, the hash used to initialized the raw entry must still be + /// consistent with the hash of the key that is ultimately stored in the entry. + /// This is because implementations of HashMap may need to recompute hashes + /// when resizing, at which point only the keys are available. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map[&"a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = compute_hash(map.hasher(), &"c"); + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry().from_key(&"c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = compute_hash(map.hasher(), &key); + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map[&"d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get(&"d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S, A> { + RawEntryBuilderMut { map: self } + } + + /// Creates a raw immutable entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// `get` should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = compute_hash(map.hasher(), k); + /// let v = map.get(&k).cloned(); + /// let kv = v.as_ref().map(|v| (&k, v)); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry().from_key(&k), kv); + /// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S, A> { + RawEntryBuilder { map: self } + } + + /// Returns a reference to the [`RawTable`] used underneath [`HashMap`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// See [`raw_table_mut`] for more. + /// + /// [`raw_table_mut`]: Self::raw_table_mut + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(K, V), A> { + &self.table + } + + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashMap`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the map that can be useful + /// for extending the HashMap's API, but may lead to *[undefined behavior]*. + /// + /// [`HashMap`]: struct.HashMap.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 10), ("b", 20), ("c", 30)]); + /// assert_eq!(map.len(), 3); + /// + /// // Let's imagine that we have a value and a hash of the key, but not the key itself. + /// // However, if you want to remove the value from the map by hash and value, and you + /// // know exactly that the value is unique, then you can create a function like this: + /// fn remove_by_hash( + /// map: &mut HashMap, + /// hash: u64, + /// is_match: F, + /// ) -> Option<(K, V)> + /// where + /// F: Fn(&(K, V)) -> bool, + /// { + /// let raw_table = map.raw_table_mut(); + /// match raw_table.find(hash, is_match) { + /// Some(bucket) => Some(unsafe { raw_table.remove(bucket).0 }), + /// None => None, + /// } + /// } + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash = compute_hash(map.hasher(), "a"); + /// assert_eq!(remove_by_hash(&mut map, hash, |(_, v)| *v == 10), Some(("a", 10))); + /// assert_eq!(map.get(&"a"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table_mut(&mut self) -> &mut RawTable<(K, V), A> { + &mut self.table + } +} + +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator, +{ +} + +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HashMap +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// // You can specify all types of HashMap, including hasher and allocator. + /// // Created map is empty and don't allocate memory + /// let map: HashMap = Default::default(); + /// assert_eq!(map.capacity(), 0); + /// let map: HashMap = HashMap::default(); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::with_hasher_in(Default::default(), Default::default()) + } +} + +impl Index<&Q> for HashMap +where + K: Eq + Hash, + Q: Hash + Equivalent, + S: BuildHasher, + A: Allocator, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", "One"), ("b", "Two")].into(); + /// + /// assert_eq!(map[&"a"], "One"); + /// assert_eq!(map[&"b"], "Two"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "ahash")] +impl From<[(K, V); N]> for HashMap +where + K: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map1 = HashMap::from([(1, 2), (3, 4)]); + /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + arr.into_iter().collect() + } +} + +/// An iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a V)`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((&1, &"a")), Some((&2, &"b")), Some((&3, &"c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct Iter<'a, K, V> { + inner: RawIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a mut V)`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut iter = map.iter_mut(); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct IterMut<'a, K, V> { + inner: RawIter<(K, V)>, + // To ensure invariance with respect to V + marker: PhantomData<(&'a K, &'a mut V)>, +} + +// We override the default Send impl which has K: Sync instead of K: Send. Both +// are correct, but this one is more general since it allows keys which +// implement Send but not Sync. +unsafe impl Send for IterMut<'_, K, V> {} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.into_iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `IntoIter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct IntoIter { + inner: RawIntoIter<(K, V), A>, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `K`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_keys`]: struct.HashMap.html#method.into_keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.into_keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `IntoKeys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(1), Some(2), Some(3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct IntoKeys { + inner: IntoIter, +} + +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} + +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(k, _)| k)) + .finish() + } +} + +/// An owning iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `V`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. The map cannot be used after calling that method. +/// +/// [`into_values`]: struct.HashMap.html#method.into_values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.into_values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `IntoValues` iterator produces values in arbitrary order, so +/// // the values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some("a"), Some("b"), Some("c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct IntoValues { + inner: IntoIter, +} + +impl Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} + +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, v)| v)) + .finish() + } +} + +/// An iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a K`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `Keys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&1), Some(&2), Some(&3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct Keys<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Keys { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a V`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `Values` iterator produces values in arbitrary order, so the +/// // values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&"a"), Some(&"b"), Some(&"c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct Values<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Values { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap` in arbitrary +/// order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut drain_iter = map.drain(); +/// let mut vec = vec![drain_iter.next(), drain_iter.next(), drain_iter.next()]; +/// +/// // The `Drain` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(drain_iter.next(), None); +/// assert_eq!(drain_iter.next(), None); +/// ``` +pub struct Drain<'a, K, V, A: Allocator = Global> { + inner: RawDrain<'a, (K, V), A>, +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate +/// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashMap.html#method.extract_if +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut extract_if = map.extract_if(|k, _v| k % 2 != 0); +/// let mut vec = vec![extract_if.next(), extract_if.next()]; +/// +/// // The `ExtractIf` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")),Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(extract_if.next(), None); +/// assert_eq!(extract_if.next(), None); +/// drop(extract_if); +/// +/// assert_eq!(map.len(), 1); +/// ``` +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> +where + F: FnMut(&K, &mut V) -> bool, +{ + f: F, + inner: RawExtractIf<'a, (K, V), A>, +} + +impl Iterator for ExtractIf<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator, +{ + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +/// A mutable iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a mut V`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut values = map.values_mut(); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct ValuesMut<'a, K, V> { + inner: IterMut<'a, K, V>, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry_mut`] docs for usage examples. +/// +/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{RawEntryBuilderMut, RawEntryMut::Vacant, RawEntryMut::Occupied}; +/// use hashbrown::HashMap; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16)]); +/// assert_eq!(map.len(), 6); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let builder: RawEntryBuilderMut<_, _, _> = map.raw_entry_mut(); +/// +/// // Existing key +/// match builder.from_key(&6) { +/// Vacant(_) => unreachable!(), +/// Occupied(view) => assert_eq!(view.get(), &16), +/// } +/// +/// for key in 0..12 { +/// let hash = compute_hash(map.hasher(), &key); +/// let value = map.get(&key).cloned(); +/// let key_value = value.as_ref().map(|v| (&key, v)); +/// +/// println!("Key: {} and value: {:?}", key, value); +/// +/// match map.raw_entry_mut().from_key(&key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// } +/// +/// assert_eq!(map.len(), 6); +/// ``` +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator = Global> { + map: &'a mut HashMap, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This is a lower-level version of [`Entry`]. +/// +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`Entry`]: enum.Entry.html +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([('a', 1), ('b', 2), ('c', 3)]); +/// assert_eq!(map.len(), 3); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// // Existing key (insert) +/// let raw: RawEntryMut<_, _, _> = map.raw_entry_mut().from_key(&'a'); +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = raw.insert('a', 10); +/// assert_eq!(map.len(), 3); +/// +/// // Nonexistent key (insert) +/// map.raw_entry_mut().from_key(&'d').insert('d', 40); +/// assert_eq!(map.len(), 4); +/// +/// // Existing key (or_insert) +/// let hash = compute_hash(map.hasher(), &'b'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'b') +/// .or_insert('b', 20); +/// assert_eq!(kv, (&mut 'b', &mut 2)); +/// *kv.1 = 20; +/// assert_eq!(map.len(), 4); +/// +/// // Nonexistent key (or_insert) +/// let hash = compute_hash(map.hasher(), &'e'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'e') +/// .or_insert('e', 50); +/// assert_eq!(kv, (&mut 'e', &mut 50)); +/// assert_eq!(map.len(), 5); +/// +/// // Existing key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'c'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'c') +/// .or_insert_with(|| ('c', 30)); +/// assert_eq!(kv, (&mut 'c', &mut 3)); +/// *kv.1 = 30; +/// assert_eq!(map.len(), 5); +/// +/// // Nonexistent key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'f'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'f') +/// .or_insert_with(|| ('f', 60)); +/// assert_eq!(kv, (&mut 'f', &mut 60)); +/// assert_eq!(map.len(), 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [('a', 10), ('b', 20), ('c', 30), ('d', 40), ('e', 50), ('f', 60)]); +/// ``` +pub enum RawEntryMut<'a, K, V, S, A: Allocator = Global> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(_) => { } + /// } + /// ``` + Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.raw_entry_mut().from_key("a") { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(_) => { } + /// } + /// ``` + Vacant(RawVacantEntryMut<'a, K, V, S, A>), +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = map.raw_entry_mut().from_key(&"a").insert("a", 100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// let new_v = (*v) * 10; +/// *v = new_v; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.raw_entry().from_key(&"c"), None); +/// assert_eq!(map.len(), 2); +/// +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "b") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("b", 20)); +/// } +/// } +/// assert_eq!(map.get(&"b"), None); +/// assert_eq!(map.len(), 1); +/// ``` +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator = Global> { + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawVacantEntryMut}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let raw_v: RawVacantEntryMut<_, _, _> = match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(view) => view, +/// RawEntryMut::Occupied(_) => unreachable!(), +/// }; +/// raw_v.insert("a", 10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"b") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// let (k, value) = view.insert("b", 2); +/// assert_eq!((*k, *value), ("b", 2)); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "c") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// assert_eq!(view.insert("c", 30), (&mut "c", &mut 30)); +/// } +/// } +/// assert!(map[&"c"] == 30 && map.len() == 3); +/// ``` +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator = Global> { + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry`] docs for usage examples. +/// +/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, RawEntryBuilder}; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 10), (2, 20), (3, 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// for k in 0..6 { +/// let hash = compute_hash(map.hasher(), &k); +/// let v = map.get(&k).cloned(); +/// let kv = v.as_ref().map(|v| (&k, v)); +/// +/// println!("Key: {} and value: {:?}", k, v); +/// let builder: RawEntryBuilder<_, _, _> = map.raw_entry(); +/// assert_eq!(builder.from_key(&k), kv); +/// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); +/// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); +/// } +/// ``` +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator = Global> { + map: &'a HashMap, +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key(&key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + S: BuildHasher, + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Creates a `RawEntryMut` from the given key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key_hashed_nocheck(hash, &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + Q: Equivalent, + { + self.from_hash(hash, equivalent(k)) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_hash(hash, |k| k == &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + self.search(hash, is_match) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + match self.map.table.find(hash, |(k, _)| is_match(k)) { + Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { + elem, + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + None => RawEntryMut::Vacant(RawVacantEntryMut { + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { + /// Access an immutable entry by key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// assert_eq!(map.raw_entry().from_key(&key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Access an immutable entry by a key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> + where + Q: Equivalent, + { + self.from_hash(hash, equivalent(k)) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + match self.map.table.get(hash, |(k, _)| is_match(k)) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + /// Access an immutable entry by hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_hash(hash, |k| k == &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + self.search(hash, is_match) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry, and returns a RawOccupiedEntryMut. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37); + /// + /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(mut entry) => { + entry.insert(value); + entry + } + RawEntryMut::Vacant(entry) => entry.insert_entry(key, value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { + /// ("poneyland", "hoho".to_string()) + /// }); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => { + let (k, v) = default(); + entry.insert(k, v) + } + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 0); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + match self { + RawEntryMut::Occupied(mut entry) => { + { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + RawEntryMut::Occupied(entry) + } + RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } +} + +impl<'a, K, V, S, A: Allocator> RawOccupiedEntryMut<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.key(), &"a") + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Gets a mutable reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// *o.key_mut() = key_two.clone(); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key_mut(&mut self) -> &mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Converts the entry into a mutable reference to the key in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => inside_key = o.into_key(), + /// } + /// *inside_key = key_two.clone(); + /// + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> &'a mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get(), &100), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let value: &mut u32; + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => value = o.into_mut(), + /// } + /// *value += 900; + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => *o.get_mut() += 900, + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get_key_value(), (&"a", &100)), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value(&self) -> (&K, &V) { + unsafe { + let (key, value) = self.elem.as_ref(); + (key, value) + } + } + + /// Gets a mutable reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let (inside_key, inside_value) = o.get_key_value_mut(); + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// } + /// } + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// let inside_value: &mut u32; + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => { + /// let tuple = o.into_key_value(); + /// inside_key = tuple.0; + /// inside_value = tuple.1; + /// } + /// } + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => assert_eq!(o.insert(1000), 100), + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let old_key = o.insert_key(key_two.clone()); + /// assert!(Rc::ptr_eq(&old_key, &key_one)); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove(), 100), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove_entry(), ("a", 100)), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let raw_entry = match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 100); + /// Some(v + 900) + /// }), + /// }; + /// let raw_entry = match raw_entry { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 1000); + /// None + /// }), + /// }; + /// match raw_entry { + /// RawEntryMut::Vacant(_) => { }, + /// RawEntryMut::Occupied(_) => panic!(), + /// }; + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"c") { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!(v.insert("c", 300), (&mut "c", &mut 300)), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + self.insert_hashed_nocheck(hash, key, value) + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "c"; + /// let hash = compute_hash(map.hasher(), &key); + /// + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_hashed_nocheck(hash, key, 300), + /// (&mut "c", &mut 300) + /// ), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::shadow_unrelated)] + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let &mut (ref mut k, ref mut v) = self.table.insert_entry( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + (k, v) + } + + /// Set the value of an entry with a custom hasher function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn make_hasher(hash_builder: &S) -> impl Fn(&K) -> u64 + '_ + /// where + /// K: Hash + ?Sized, + /// S: BuildHasher, + /// { + /// move |key: &K| { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash_builder = map.hasher().clone(); + /// let hash = make_hasher(&hash_builder)(&key); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| q == &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_with_hasher(hash, key, 100, make_hasher(&hash_builder)), + /// (&mut "a", &mut 100) + /// ), + /// } + /// map.extend([("b", 200), ("c", 300), ("d", 400), ("e", 500), ("f", 600)]); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_hasher( + self, + hash: u64, + key: K, + value: V, + hasher: H, + ) -> (&'a mut K, &'a mut V) + where + H: Fn(&K) -> u64, + { + let &mut (ref mut k, ref mut v) = self + .table + .insert_entry(hash, (key, value), |x| hasher(&x.0)); + (k, v) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + let elem = self.table.insert( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + RawOccupiedEntryMut { + elem, + table: self.table, + hash_builder: self.hash_builder, + } + } +} + +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +impl Debug for RawEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), + } + } +} + +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() + } +} + +impl Debug for RawEntryBuilder<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let entry: Entry<_, _, _> = map.entry("a"); +/// let _raw_o: OccupiedEntry<_, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5), ("f", 6)]); +/// ``` +pub enum Entry<'a, K, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, K, V, S, A>), +} + +impl Debug for Entry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// let _entry_o: OccupiedEntry<_, _, _> = map.entry("a").insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.get(&"c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl Send for OccupiedEntry<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl Debug for OccupiedEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, VacantEntry}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// let entry_v: VacantEntry<_, _, _> = match map.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry("b") { +/// Entry::Occupied(_) => unreachable!(), +/// Entry::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: K, + table: &'a mut HashMap, +} + +impl Debug for VacantEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied, +/// with any borrowed form of the map's key type. +/// +/// +/// This `enum` is constructed from the [`entry_ref`] method on [`HashMap`]. +/// +/// [`Hash`] and [`Eq`] on the borrowed form of the map's key type *must* match those +/// for the key type. It also require that key may be constructed from the borrowed +/// form through the [`From`] trait. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry_ref`]: struct.HashMap.html#method.entry_ref +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntryRef}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let key = String::from("a"); +/// let entry: EntryRef<_, _, _, _> = map.entry_ref(&key); +/// let _raw_o: OccupiedEntryRef<_, _, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry_ref("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry_ref("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry_ref("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry_ref("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry_ref("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// for (key, value) in ["a", "b", "c", "d", "e", "f"].into_iter().zip(1..=6) { +/// assert_eq!(map[key], value) +/// } +/// assert_eq!(map.len(), 6); +/// ``` +pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap<_, _> = [("a".to_owned(), 100), ("b".into(), 200)].into(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Vacant(_) => unreachable!(), + /// EntryRef::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntryRef<'a, 'b, K, Q, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Occupied(_) => unreachable!(), + /// EntryRef::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>), +} + +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug + for EntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + EntryRef::Vacant(ref v) => f.debug_tuple("EntryRef").field(v).finish(), + EntryRef::Occupied(ref o) => f.debug_tuple("EntryRef").field(o).finish(), + } + } +} + +enum KeyOrRef<'a, K, Q: ?Sized> { + Borrowed(&'a Q), + Owned(K), +} + +impl<'a, K, Q: ?Sized> KeyOrRef<'a, K, Q> { + fn into_owned(self) -> K + where + K: From<&'a Q>, + { + match self { + Self::Borrowed(borrowed) => borrowed.into(), + Self::Owned(owned) => owned, + } + } +} + +impl<'a, K: Borrow, Q: ?Sized> AsRef for KeyOrRef<'a, K, Q> { + fn as_ref(&self) -> &Q { + match self { + Self::Borrowed(borrowed) => borrowed, + Self::Owned(owned) => owned.borrow(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// [`EntryRef`]: enum.EntryRef.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntryRef}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// +/// let key = String::from("a"); +/// let _entry_o: OccupiedEntryRef<_, _, _, _> = map.entry_ref(&key).insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry_ref("a") { +/// EntryRef::Vacant(_) => unreachable!(), +/// EntryRef::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map["a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry_ref("c") { +/// EntryRef::Vacant(_) => unreachable!(), +/// EntryRef::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c".to_owned(), 30)); +/// } +/// } +/// assert_eq!(map.get("c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: Option>, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl<'a, 'b, K, Q, V, S, A> Send for OccupiedEntryRef<'a, 'b, K, Q, V, S, A> +where + K: Send, + Q: Sync + ?Sized, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl<'a, 'b, K, Q, V, S, A> Sync for OccupiedEntryRef<'a, 'b, K, Q, V, S, A> +where + K: Sync, + Q: Sync + ?Sized, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug + for OccupiedEntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntryRef") + .field("key", &self.key().borrow()) + .field("value", &self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// [`EntryRef`]: enum.EntryRef.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, VacantEntryRef}; +/// +/// let mut map = HashMap::::new(); +/// +/// let entry_v: VacantEntryRef<_, _, _, _> = match map.entry_ref("a") { +/// EntryRef::Vacant(view) => view, +/// EntryRef::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map["a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry_ref("b") { +/// EntryRef::Occupied(_) => unreachable!(), +/// EntryRef::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map["b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: KeyOrRef<'b, K, Q>, + table: &'a mut HashMap, +} + +impl, Q: ?Sized + Debug, V, S, A: Allocator> Debug + for VacantEntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntryRef").field(&self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, OccupiedError}; +/// +/// let mut map: HashMap<_, _> = [("a", 10), ("b", 20)].into(); +/// +/// // try_insert method returns mutable reference to the value if keys are vacant, +/// // but if the map did have key present, nothing is updated, and the provided +/// // value is returned inside `Err(_)` variant +/// match map.try_insert("a", 100) { +/// Err(OccupiedError { mut entry, value }) => { +/// assert_eq!(entry.key(), &"a"); +/// assert_eq!(value, 100); +/// assert_eq!(entry.insert(100), 10) +/// } +/// _ => unreachable!(), +/// } +/// assert_eq!(map[&"a"], 100); +/// ``` +pub struct OccupiedError<'a, K, V, S, A: Allocator = Global> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, S, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +impl Debug for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +impl<'a, K: Debug, V: Debug, S, A: Allocator> fmt::Display for OccupiedError<'a, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// Return the same `Iter` struct as by the [`iter`] method on [`HashMap`]. + /// + /// [`iter`]: struct.HashMap.html#method.iter + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map_one: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); + /// let mut map_two = HashMap::new(); + /// + /// for (key, value) in &map_one { + /// println!("Key: {}, Value: {}", key, value); + /// map_two.insert_unique_unchecked(*key, *value); + /// } + /// + /// assert_eq!(map_one, map_two); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order + /// with mutable references to the values. The iterator element type is + /// `(&'a K, &'a mut V)`. + /// + /// Return the same `IterMut` struct as by the [`iter_mut`] method on + /// [`HashMap`]. + /// + /// [`iter_mut`]: struct.HashMap.html#method.iter_mut + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// for (key, value) in &mut map { + /// println!("Key: {}, Value: {}", key, value); + /// *value *= 2; + /// } + /// + /// let mut vec = map.iter().collect::>(); + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(&"a", &2), (&"b", &4), (&"c", &6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// // Not possible with .iter() + /// let mut vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so + /// // the items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.table.into_iter(), + } + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_ref(); + Some((&r.0, &r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_ref(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_mut(); + Some((&r.0, &mut r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_mut(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +impl ExactSizeIterator for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Keys<'_, K, V> {} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Values<'_, K, V> {} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a mut V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, val)| val)) + .finish() + } +} + +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, K, V, A> {} + +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry("horseland").key(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } +} + +impl<'a, K, V: Default, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland", Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.key(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland", 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// let value: &mut u32; + /// match map.entry("poneyland") { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let key_one = Rc::new("Stringthing".to_string()); + /// let key_two = Rc::new("Stringthing".to_string()); + /// + /// map.insert(key_one.clone(), 15); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.entry(key_two.clone()) { + /// Entry::Occupied(entry) => { + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// assert!(Rc::ptr_eq(&key_one, &old_key) && old_value == 15); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// assert_eq!(map[&"Stringthing".to_owned()], 16); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, usize> = HashMap::with_capacity(6); + /// let mut keys_one: Vec> = Vec::with_capacity(6); + /// let mut keys_two: Vec> = Vec::with_capacity(6); + /// + /// for (value, key) in ["a", "b", "c", "d", "e", "f"].into_iter().enumerate() { + /// let rc_key = Rc::new(key.to_owned()); + /// keys_one.push(rc_key.clone()); + /// map.insert(rc_key.clone(), value); + /// keys_two.push(Rc::new(key.to_owned())); + /// } + /// + /// assert!( + /// keys_one.iter().all(|key| Rc::strong_count(key) == 2) + /// && keys_two.iter().all(|key| Rc::strong_count(key) == 1) + /// ); + /// + /// reclaim_memory(&mut map, &keys_two); + /// + /// assert!( + /// keys_one.iter().all(|key| Rc::strong_count(key) == 1) + /// && keys_two.iter().all(|key| Rc::strong_count(key) == 2) + /// ); + /// + /// fn reclaim_memory(map: &mut HashMap, usize>, keys: &[Rc]) { + /// for key in keys { + /// if let Entry::Occupied(entry) = map.entry(key.clone()) { + /// // Replaces the entry's key with our version of it in `keys`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// match map.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + key: None, + elem, + table: self.table, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntryRef. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let entry = map.entry_ref("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), "horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(mut entry) => { + entry.insert(value); + entry + } + EntryRef::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function an access to the borrower form of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash + Borrow + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => { + let value = default(entry.key.as_ref()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry_ref("horseland").key(), "horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + match *self { + EntryRef::Occupied(ref entry) => entry.key().borrow(), + EntryRef::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + EntryRef::Occupied(mut entry) => { + f(entry.get_mut()); + EntryRef::Occupied(entry) + } + EntryRef::Vacant(entry) => EntryRef::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// EntryRef::Vacant(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// } + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland".to_string(), 42); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, "poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// EntryRef::Occupied(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// EntryRef::Vacant(e) => assert_eq!(e.key(), "poneyland"), + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + EntryRef::Occupied(entry) => entry.replace_entry_with(f), + EntryRef::Vacant(_) => self, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland".to_string(), Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry_ref("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// match map.entry_ref("poneyland") { + /// EntryRef::Vacant(_) => panic!(), + /// EntryRef::Occupied(entry) => assert_eq!(entry.key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland".to_owned(), 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements but capacity is equal to the old one + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// match map.entry_ref("poneyland") { + /// EntryRef::Vacant(_) => panic!(), + /// EntryRef::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntryRef` which may outlive the + /// destruction of the `EntryRef` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the OccupiedEntryRef into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntryRef`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// let value: &mut u32; + /// match map.entry_ref("poneyland") { + /// EntryRef::Occupied(entry) => value = entry.into_mut(), + /// EntryRef::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements but capacity is equal to the old one + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let key: Rc = Rc::from("Stringthing"); + /// + /// map.insert(key.clone(), 15); + /// assert_eq!(Rc::strong_count(&key), 2); + /// + /// match map.entry_ref("Stringthing") { + /// EntryRef::Occupied(entry) => { + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// assert!(Rc::ptr_eq(&key, &old_key) && old_value == 15); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(Rc::strong_count(&key), 1); + /// assert_eq!(map["Stringthing"], 16); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) + where + K: From<&'b Q>, + { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap().into_owned()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, usize> = HashMap::with_capacity(6); + /// let mut keys: Vec> = Vec::with_capacity(6); + /// + /// for (value, key) in ["a", "b", "c", "d", "e", "f"].into_iter().enumerate() { + /// let rc_key: Rc = Rc::from(key); + /// keys.push(rc_key.clone()); + /// map.insert(rc_key.clone(), value); + /// } + /// + /// assert!(keys.iter().all(|key| Rc::strong_count(key) == 2)); + /// + /// // It doesn't matter that we kind of use a vector with the same keys, + /// // because all keys will be newly created from the references + /// reclaim_memory(&mut map, &keys); + /// + /// assert!(keys.iter().all(|key| Rc::strong_count(key) == 1)); + /// + /// fn reclaim_memory(map: &mut HashMap, usize>, keys: &[Rc]) { + /// for key in keys { + /// if let EntryRef::Occupied(entry) = map.entry_ref(key.as_ref()) { + /// // Replaces the entry's key with our version of it in `keys`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K + where + K: From<&'b Q>, + { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap().into_owned()) + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.insert("poneyland".to_string(), 42); + /// + /// let entry = match map.entry_ref("poneyland") { + /// EntryRef::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, "poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// EntryRef::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// EntryRef::Occupied(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry_ref("poneyland") { + /// EntryRef::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// EntryRef::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// EntryRef::Vacant(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// } + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(KeyOrRef::Owned(key)); + None + } + }); + + if let Some(key) = spare_key { + EntryRef::Vacant(VacantEntryRef { + hash: self.hash, + key, + table: self.table, + }) + } else { + EntryRef::Occupied(self) + } + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'a, 'b, K, Q, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntryRef`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// assert_eq!(map.entry_ref(key).key(), "poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + self.key.as_ref() + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// match map.entry_ref(key) { + /// EntryRef::Occupied(_) => panic!(), + /// EntryRef::Vacant(v) => assert_eq!(v.into_key(), "poneyland".to_owned()), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K + where + K: From<&'b Q>, + { + self.key.into_owned() + } + + /// Sets the value of the entry with the VacantEntryRef's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// if let EntryRef::Vacant(o) = map.entry_ref(key) { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key.into_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key.into_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntryRef { + hash: self.hash, + key: None, + elem, + table: self.table, + } + } +} + +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let mut map = + Self::with_capacity_and_hasher_in(iter.size_hint().0, S::default(), A::default()); + iter.for_each(|(k, v)| { + map.insert(k, v); + }); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let some_iter = [(1, 1), (2, 2)].into_iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr); + /// let old_map_len = map.len(); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(map); + /// assert_eq!(new_map.len(), old_map_len); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { + additional + } else { + (additional + 1) / 2 + }; + self.reserve(reserve); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter().map(|(k, v)| (k, v)); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec.iter().map(|(k, v)| (k, v))); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr.iter().map(|(k, v)| (k, v))); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(&map); + /// assert_eq!(new_map, map); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (&'a K, &'a V)) { + self.insert(*k, *v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<&'a (K, V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(&some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(&some_arr); + /// + /// let mut vec: Vec<_> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|&(key, value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, &(k, v): &'a (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new, A: Allocator>( + v: IntoIter<&'static str, u8, A>, + ) -> IntoIter<&'new str, u8, A> { + v + } + fn into_iter_val<'new, A: Allocator>( + v: IntoIter, + ) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} + +#[cfg(test)] +mod test_map { + use super::DefaultHashBuilder; + use super::Entry::{Occupied, Vacant}; + use super::EntryRef; + use super::{HashMap, RawEntryMut}; + use alloc::string::{String, ToString}; + use alloc::sync::Arc; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::alloc::Layout; + use core::ptr::NonNull; + use core::sync::atomic::{AtomicI8, Ordering}; + use rand::{rngs::SmallRng, Rng, SeedableRng}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::usize; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); + } + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + #[test] + fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + #[allow(clippy::redundant_clone)] + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + #[test] + fn test_clone_from() { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + m2.clone_from(&m); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + thread_local! { static DROP_VECTOR: RefCell> = const { RefCell::new(Vec::new()) } } + + #[derive(Hash, PartialEq, Eq)] + struct Droppable { + k: usize, + } + + impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } + } + + impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Droppable { + fn clone(&self) -> Self { + Droppable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_entry_ref() { + let mut m: HashMap = HashMap::new(); + match m.entry_ref("poneyland") { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(_) => {} + } + assert!(*m.entry_ref("poneyland").or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: takes too long + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(1, 3).is_some()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_insert_unique_unchecked() { + let mut map = HashMap::new(); + let (k1, v1) = map.insert_unique_unchecked(10, 11); + assert_eq!((&10, &mut 11), (k1, v1)); + let (k2, v2) = map.insert_unique_unchecked(20, 21); + assert_eq!((&20, &mut 21), (k2, v2)); + assert_eq!(Some(&11), map.get(&10)); + assert_eq!(Some(&21), map.get(&20)); + assert_eq!(None, map.get(&30)); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2; + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{map:?}"); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.raw_capacity(), 1); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); + + assert_eq!(raw_cap, initial_raw_cap * 2); + + let mut i = 0; + for _ in 0..raw_cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.raw_capacity(), raw_cap); + + for _ in 0..raw_cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); + + for _ in 0..raw_cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.raw_capacity(), new_raw_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.raw_capacity(), raw_cap); + // again, a little more than half full + for _ in 0..raw_cap / 2 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.raw_capacity(), initial_raw_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + #[allow(clippy::no_effect)] // false positive lint + map[&4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_ref() { + let xs = [ + ("One".to_owned(), 10), + ("Two".to_owned(), 20), + ("Three".to_owned(), 30), + ("Four".to_owned(), 40), + ("Five".to_owned(), 50), + ("Six".to_owned(), 60), + ]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry_ref("One") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get("One").unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry_ref("Two") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get("Two").unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry_ref("Three") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get("Three"), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry_ref("Ten") { + EntryRef::Occupied(_) => unreachable!(), + EntryRef::Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get("Ten").unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_entry_ref_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + match m.entry_ref(x.as_str()) { + EntryRef::Vacant(_) => {} + EntryRef::Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_extend_ref_k_ref_v() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref_kv_tuple() { + use std::ops::AddAssign; + let mut a = HashMap::new(); + a.insert(0, 0); + + fn create_arr + Copy, const N: usize>(start: T, step: T) -> [(T, T); N] { + let mut outs: [(T, T); N] = [(start, start); N]; + let mut element = step; + outs.iter_mut().skip(1).for_each(|(k, v)| { + *k += element; + *v += element; + element += step; + }); + outs + } + + let for_iter: Vec<_> = (0..100).map(|i| (i, i)).collect(); + let iter = for_iter.iter(); + let vec: Vec<_> = (100..200).map(|i| (i, i)).collect(); + a.extend(iter); + a.extend(&vec); + a.extend(create_arr::(200, 1)); + + assert_eq!(a.len(), 300); + + for item in 0..300 { + assert_eq!(a[&item], item); + } + } + + #[test] + fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); + } + + #[test] + fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key, value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_ref_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.to_owned(), value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry_ref(key) { + EntryRef::Vacant(_) => panic!(), + EntryRef::Occupied(e) => assert_eq!(key, e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_ref_key() { + let mut a: HashMap = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry_ref(key) { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(e) => { + assert_eq!(key, e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_occupied_entry_ref_replace_entry_with() { + let mut a: HashMap = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry_ref(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + EntryRef::Occupied(e) => { + assert_eq!(e.key(), key); + assert_eq!(e.get(), &new_value); + } + EntryRef::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry_ref(key) { + EntryRef::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, new_value); + None + }), + EntryRef::Vacant(_) => panic!(), + }; + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_ref_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry_ref(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + a.insert(key.to_owned(), value); + + let entry = a.entry_ref(key).and_replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + EntryRef::Occupied(e) => { + assert_eq!(e.key(), key); + assert_eq!(e.get(), &new_value); + } + EntryRef::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry_ref(key).and_replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, new_value); + None + }); + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_replace_entry_ref_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.entry_ref(x.as_str()).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } + + #[test] + fn test_extract_if() { + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + let drained = map.extract_if(|&k, _| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(map.len(), 4); + } + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + map.extract_if(|&k, _| k % 2 == 0).for_each(drop); + assert_eq!(map.len(), 4); + } + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) + fn test_try_reserve() { + use crate::TryReserveError::{AllocError, CapacityOverflow}; + + const MAX_ISIZE: usize = isize::MAX as usize; + + let mut empty_bytes: HashMap = HashMap::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(usize::MAX) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_ISIZE) { + } else { + panic!("isize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_ISIZE / 5) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a few more hashmaps to ensure the allocation will fail. + let mut empty_bytes2: HashMap = HashMap::new(); + let _ = empty_bytes2.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes3: HashMap = HashMap::new(); + let _ = empty_bytes3.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes4: HashMap = HashMap::new(); + if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_ISIZE / 5) { + } else { + panic!("isize::MAX / 5 should trigger an OOM!"); + } + } + } + + #[test] + fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1_i32, 10_i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + super::make_hash::(map.hasher(), &k) + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).copied(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } + } + + #[test] + fn test_key_without_hash_impl() { + #[derive(Debug)] + struct IntWrapper(u64); + + let mut m: HashMap = HashMap::default(); + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 0"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(0, IntWrapper(0), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_none()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(1, |k| k.0 == 1) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 1"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(1, IntWrapper(1), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let occupied_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(e) => e, + RawEntryMut::Vacant(..) => panic!("Couldn't find entry for key 0"), + }; + occupied_entry.remove(); + } + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + + #[test] + #[cfg(feature = "raw")] + fn test_into_iter_refresh() { + #[cfg(miri)] + const N: usize = 32; + #[cfg(not(miri))] + const N: usize = 128; + + let mut rng = rand::thread_rng(); + for n in 0..N { + let mut map = HashMap::new(); + for i in 0..n { + assert!(map.insert(i, 2 * i).is_none()); + } + let hash_builder = map.hasher().clone(); + + let mut it = unsafe { map.table.iter() }; + assert_eq!(it.len(), n); + + let mut i = 0; + let mut left = n; + let mut removed = Vec::new(); + loop { + // occasionally remove some elements + if i < n && rng.gen_bool(0.1) { + let hash_value = super::make_hash(&hash_builder, &i); + + unsafe { + let e = map.table.find(hash_value, |q| q.0.eq(&i)); + if let Some(e) = e { + it.reflect_remove(&e); + let t = map.table.remove(e).0; + removed.push(t); + left -= 1; + } else { + assert!(removed.contains(&(i, 2 * i)), "{i} not in {removed:?}"); + let e = map.table.insert( + hash_value, + (i, 2 * i), + super::make_hasher::<_, usize, _>(&hash_builder), + ); + it.reflect_insert(&e); + if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) { + removed.swap_remove(p); + } + left += 1; + } + } + } + + let e = it.next(); + if e.is_none() { + break; + } + assert!(i < n); + let t = unsafe { e.unwrap().as_ref() }; + assert!(!removed.contains(t)); + let (key, value) = t; + assert_eq!(*value, 2 * key); + i += 1; + } + assert!(i <= n); + + // just for safety: + assert_eq!(map.table.len(), left); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP; + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } + + #[test] + fn test_get_each_mut() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + map.insert("bar".to_owned(), 10); + map.insert("baz".to_owned(), 20); + map.insert("qux".to_owned(), 30); + + let xs = map.get_many_mut(["foo", "qux"]); + assert_eq!(xs, Some([&mut 0, &mut 30])); + + let xs = map.get_many_mut(["foo", "dud"]); + assert_eq!(xs, None); + + let xs = map.get_many_mut(["foo", "foo"]); + assert_eq!(xs, None); + + let ys = map.get_many_key_value_mut(["bar", "baz"]); + assert_eq!( + ys, + Some([(&"bar".to_owned(), &mut 10), (&"baz".to_owned(), &mut 20),]), + ); + + let ys = map.get_many_key_value_mut(["bar", "dip"]); + assert_eq!(ys, None); + + let ys = map.get_many_key_value_mut(["baz", "baz"]); + assert_eq!(ys, None); + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_from_double_drop() { + #[derive(Clone)] + struct CheckedDrop { + panic_in_drop: bool, + dropped: bool, + } + impl Drop for CheckedDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + const DISARMED: CheckedDrop = CheckedDrop { + panic_in_drop: false, + dropped: false, + }; + const ARMED: CheckedDrop = CheckedDrop { + panic_in_drop: true, + dropped: false, + }; + + let mut map1 = HashMap::new(); + map1.insert(1, DISARMED); + map1.insert(2, DISARMED); + map1.insert(3, DISARMED); + map1.insert(4, DISARMED); + + let mut map2 = HashMap::new(); + map2.insert(1, DISARMED); + map2.insert(2, ARMED); + map2.insert(3, DISARMED); + map2.insert(4, DISARMED); + + map2.clone_from(&map1); + } + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_from_memory_leaks() { + use alloc::vec::Vec; + + struct CheckedClone { + panic_in_clone: bool, + need_drop: Vec, + } + impl Clone for CheckedClone { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + need_drop: self.need_drop.clone(), + } + } + } + let mut map1 = HashMap::new(); + map1.insert( + 1, + CheckedClone { + panic_in_clone: false, + need_drop: vec![0, 1, 2], + }, + ); + map1.insert( + 2, + CheckedClone { + panic_in_clone: false, + need_drop: vec![3, 4, 5], + }, + ); + map1.insert( + 3, + CheckedClone { + panic_in_clone: true, + need_drop: vec![6, 7, 8], + }, + ); + let _map2 = map1.clone(); + } + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl MyAlloc { + fn new(drop_count: Arc) -> Self { + MyAlloc { + _inner: Arc::new(MyAllocInner { drop_count }), + } + } + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + #[test] + fn test_hashmap_into_iter_bug() { + let dropped: Arc = Arc::new(AtomicI8::new(1)); + + { + let mut map = HashMap::with_capacity_in(10, MyAlloc::new(dropped.clone())); + for i in 0..10 { + map.entry(i).or_insert_with(|| "i".to_string()); + } + + for (k, v) in map { + println!("{}, {}", k, v); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[derive(Debug)] + struct CheckedCloneDrop { + panic_in_clone: bool, + panic_in_drop: bool, + dropped: bool, + data: T, + } + + impl CheckedCloneDrop { + fn new(panic_in_clone: bool, panic_in_drop: bool, data: T) -> Self { + CheckedCloneDrop { + panic_in_clone, + panic_in_drop, + dropped: false, + data, + } + } + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + panic_in_drop: self.panic_in_drop, + dropped: self.dropped, + data: self.data.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + /// Return hashmap with predefined distribution of elements. + /// All elements will be located in the same order as elements + /// returned by iterator. + /// + /// This function does not panic, but returns an error as a `String` + /// to distinguish between a test panic and an error in the input data. + fn get_test_map( + iter: I, + mut fun: impl FnMut(u64) -> T, + alloc: A, + ) -> Result, DefaultHashBuilder, A>, String> + where + I: Iterator + Clone + ExactSizeIterator, + A: Allocator, + T: PartialEq + core::fmt::Debug, + { + use crate::scopeguard::guard; + + let mut map: HashMap, _, A> = + HashMap::with_capacity_in(iter.size_hint().0, alloc); + { + let mut guard = guard(&mut map, |map| { + for (_, value) in map.iter_mut() { + value.panic_in_drop = false + } + }); + + let mut count = 0; + // Hash and Key must be equal to each other for controlling the elements placement. + for (panic_in_clone, panic_in_drop) in iter.clone() { + if core::mem::needs_drop::() && panic_in_drop { + return Err(String::from( + "panic_in_drop can be set with a type that doesn't need to be dropped", + )); + } + guard.table.insert( + count, + ( + count, + CheckedCloneDrop::new(panic_in_clone, panic_in_drop, fun(count)), + ), + |(k, _)| *k, + ); + count += 1; + } + + // Let's check that all elements are located as we wanted + let mut check_count = 0; + for ((key, value), (panic_in_clone, panic_in_drop)) in guard.iter().zip(iter) { + if *key != check_count { + return Err(format!( + "key != check_count,\nkey: `{}`,\ncheck_count: `{}`", + key, check_count + )); + } + if value.dropped + || value.panic_in_clone != panic_in_clone + || value.panic_in_drop != panic_in_drop + || value.data != fun(check_count) + { + return Err(format!( + "Value is not equal to expected,\nvalue: `{:?}`,\nexpected: \ + `CheckedCloneDrop {{ panic_in_clone: {}, panic_in_drop: {}, dropped: {}, data: {:?} }}`", + value, panic_in_clone, panic_in_drop, false, fun(check_count) + )); + } + check_count += 1; + } + + if guard.len() != check_count as usize { + return Err(format!( + "map.len() != check_count,\nmap.len(): `{}`,\ncheck_count: `{}`", + guard.len(), + check_count + )); + } + + if count != check_count { + return Err(format!( + "count != check_count,\ncount: `{}`,\ncheck_count: `{}`", + count, check_count + )); + } + core::mem::forget(guard); + } + Ok(map) + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + const ARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + const DISARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_memory_leaks_and_double_drop_one() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap>, DefaultHashBuilder, MyAlloc> = + match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // Clone should normally clone a few elements, and then (when the + // clone function panics), deallocate both its own memory, memory + // of `dropped: Arc` and the memory of already cloned + // elements (Vec memory inside CheckedCloneDrop). + let _map2 = map.clone(); + } + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_memory_leaks_and_double_drop_two() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap, DefaultHashBuilder, _> = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + let mut map2 = match get_test_map( + DISARMED_FLAGS.into_iter().zip(ARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // The `clone_from` should try to drop the elements of `map2` without + // double drop and leaking the allocator. Elements that have not been + // dropped leak their memory. + map2.clone_from(&map); + } + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| vec![n * 2], MyAlloc::new(dropped.clone())) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() != scope_map.table.buckets() { + return format!( + "map.table.buckets() != scope_map.table.buckets(),\nleft: `{}`,\nright: `{}`", + map.table.buckets(), scope_map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are not equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_not_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + [DISARMED].into_iter().zip([DISARMED]), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n * 2], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() == scope_map.table.buckets() { + return format!( + "map.table.buckets() == scope_map.table.buckets(): `{}`", + map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/alloc.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/alloc.rs new file mode 100644 index 00000000000000..15299e7b09941d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/alloc.rs @@ -0,0 +1,86 @@ +pub(crate) use self::inner::{do_alloc, Allocator, Global}; + +// Nightly-case. +// Use unstable `allocator_api` feature. +// This is compatible with `allocator-api2` which can be enabled or not. +// This is used when building for `std`. +#[cfg(feature = "nightly")] +mod inner { + use crate::alloc::alloc::Layout; + pub use crate::alloc::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.as_non_null_ptr()), + Err(_) => Err(()), + } + } +} + +// Basic non-nightly case. +// This uses `allocator-api2` enabled by default. +// If any crate enables "nightly" in `allocator-api2`, +// this will be equivalent to the nightly case, +// since `allocator_api2::alloc::Allocator` would be re-export of +// `core::alloc::Allocator`. +#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] +mod inner { + use crate::alloc::alloc::Layout; + pub use allocator_api2::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.cast()), + Err(_) => Err(()), + } + } +} + +// No-defaults case. +// When building with default-features turned off and +// neither `nightly` nor `allocator-api2` is enabled, +// this will be used. +// Making it impossible to use any custom allocator with collections defined +// in this crate. +// Any crate in build-tree can enable `allocator-api2`, +// or `nightly` without disturbing users that don't want to use it. +#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] +mod inner { + use crate::alloc::alloc::{alloc, dealloc, Layout}; + use core::ptr::NonNull; + + #[allow(clippy::missing_safety_doc)] // not exposed outside of this crate + pub unsafe trait Allocator { + fn allocate(&self, layout: Layout) -> Result, ()>; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + } + + #[derive(Copy, Clone)] + pub struct Global; + + unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, ()> { + unsafe { NonNull::new(alloc(layout)).ok_or(()) } + } + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout); + } + } + + impl Default for Global { + #[inline] + fn default() -> Self { + Global + } + } + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc.allocate(layout) + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/bitmask.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/bitmask.rs new file mode 100644 index 00000000000000..6576b3c5c03e9e --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/bitmask.rs @@ -0,0 +1,133 @@ +use super::imp::{ + BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, +}; + +/// A bit mask which contains the result of a `Match` operation on a `Group` and +/// allows iterating through them. +/// +/// The bit mask is arranged so that low-order bits represent lower memory +/// addresses for group match results. +/// +/// For implementation reasons, the bits in the set may be sparsely packed with +/// groups of 8 bits representing one element. If any of these bits are non-zero +/// then this element is considered to true in the mask. If this is the +/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be +/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is +/// similarly a mask of all the actually-used bits. +/// +/// To iterate over a bit mask, it must be converted to a form where only 1 bit +/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the +/// mask bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMask(pub(crate) BitMaskWord); + +#[allow(clippy::use_self)] +impl BitMask { + /// Returns a new `BitMask` with all bits inverted. + #[inline] + #[must_use] + #[allow(dead_code)] + pub(crate) fn invert(self) -> Self { + BitMask(self.0 ^ BITMASK_MASK) + } + + /// Returns a new `BitMask` with the lowest bit removed. + #[inline] + #[must_use] + fn remove_lowest_bit(self) -> Self { + BitMask(self.0 & (self.0 - 1)) + } + + /// Returns whether the `BitMask` has at least one set bit. + #[inline] + pub(crate) fn any_bit_set(self) -> bool { + self.0 != 0 + } + + /// Returns the first set bit in the `BitMask`, if there is one. + #[inline] + pub(crate) fn lowest_set_bit(self) -> Option { + if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { + Some(Self::nonzero_trailing_zeros(nonzero)) + } else { + None + } + } + + /// Returns the number of trailing zeroes in the `BitMask`. + #[inline] + pub(crate) fn trailing_zeros(self) -> usize { + // ARM doesn't have a trailing_zeroes instruction, and instead uses + // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM + // versions (pre-ARMv7) don't have RBIT and need to emulate it + // instead. Since we only have 1 bit set in each byte on ARM, we can + // use swap_bytes (REV) + leading_zeroes instead. + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE + } else { + self.0.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Same as above but takes a `NonZeroBitMaskWord`. + #[inline] + fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + // SAFETY: A byte-swapped non-zero value is still non-zero. + let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; + swapped.leading_zeros() as usize / BITMASK_STRIDE + } else { + nonzero.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Returns the number of leading zeroes in the `BitMask`. + #[inline] + pub(crate) fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize / BITMASK_STRIDE + } +} + +impl IntoIterator for BitMask { + type Item = usize; + type IntoIter = BitMaskIter; + + #[inline] + fn into_iter(self) -> BitMaskIter { + // A BitMask only requires each element (group of bits) to be non-zero. + // However for iteration we need each element to only contain 1 bit. + BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) + } +} + +/// Iterator over the contents of a `BitMask`, returning the indices of set +/// bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMaskIter(pub(crate) BitMask); + +impl BitMaskIter { + /// Flip the bit in the mask for the entry at the given index. + /// + /// Returns the bit's previous state. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + #[cfg(feature = "raw")] + pub(crate) unsafe fn flip(&mut self, index: usize) -> bool { + // NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. + let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); + self.0 .0 ^= mask; + // The bit was set if the bit is now 0. + self.0 .0 & mask == 0 + } +} + +impl Iterator for BitMaskIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let bit = self.0.lowest_set_bit()?; + self.0 = self.0.remove_lowest_bit(); + Some(bit) + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/generic.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/generic.rs new file mode 100644 index 00000000000000..c668b0642a551f --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/generic.rs @@ -0,0 +1,157 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::{mem, ptr}; + +// Use the native word size as the group size. Using a 64-bit group size on +// a 32-bit architecture will just end up being more expensive because +// shifts and multiplies will need to be emulated. + +cfg_if! { + if #[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "wasm32", + ))] { + type GroupWord = u64; + type NonZeroGroupWord = core::num::NonZeroU64; + } else { + type GroupWord = u32; + type NonZeroGroupWord = core::num::NonZeroU32; + } +} + +pub(crate) type BitMaskWord = GroupWord; +pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord; +pub(crate) const BITMASK_STRIDE: usize = 8; +// We only care about the highest bit of each byte for the mask. +#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)] +pub(crate) const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Helper function to replicate a byte across a `GroupWord`. +#[inline] +fn repeat(byte: u8) -> GroupWord { + GroupWord::from_ne_bytes([byte; Group::WIDTH]) +} + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a word-sized integer. +#[derive(Copy, Clone)] +pub(crate) struct Group(GroupWord); + +// We perform all operations in the native endianness, and convert to +// little-endian just before creating a BitMask. The can potentially +// enable the compiler to eliminate unnecessary byte swaps if we are +// only checking whether a BitMask is empty. +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(ptr::read_unaligned(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(ptr::read(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + ptr::write(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + /// + /// This function may return a false positive in certain cases where + /// the byte in the group differs from the searched value only in its + /// lowest bit. This is fine because: + /// - This never happens for `EMPTY` and `DELETED`, only full entries. + /// - The check for key equality will catch these. + /// - This only happens if there is at least 1 true match. + /// - The chance of this happening is very low (< 1% chance per byte). + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + // This algorithm is derived from + // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + let cmp = self.0 ^ repeat(byte); + BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + // If the high bit is set, then the byte must be either: + // 1111_1111 (EMPTY) or 1000_0000 (DELETED). + // So we can just check if the top two bits are 1 by ANDing them. + BitMask((self.0 & (self.0 << 1) & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask((self.0 & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let full = 1000_0000 (true) or 0000_0000 (false) + // !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry) + // !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry) + let full = !self.0 & repeat(0x80); + Group(!full + (full >> 7)) + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/mod.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/mod.rs new file mode 100644 index 00000000000000..c8e8e29122aafc --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/mod.rs @@ -0,0 +1,4817 @@ +use crate::alloc::alloc::{handle_alloc_error, Layout}; +use crate::scopeguard::{guard, ScopeGuard}; +use crate::TryReserveError; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use core::{hint, ptr}; + +cfg_if! { + // Use the SSE2 implementation if possible: it allows us to scan 16 buckets + // at once instead of 8. We don't bother with AVX since it would require + // runtime dispatch and wouldn't gain us much anyways: the probability of + // finding a match drops off drastically after the first few buckets. + // + // I attempted an implementation on ARM using NEON instructions, but it + // turns out that most NEON instructions have multi-cycle latency, which in + // the end outweighs any gains over the generic implementation. + if #[cfg(all( + target_feature = "sse2", + any(target_arch = "x86", target_arch = "x86_64"), + not(miri), + ))] { + mod sse2; + use sse2 as imp; + } else if #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + // NEON intrinsics are currently broken on big-endian targets. + // See https://github.com/rust-lang/stdarch/issues/1484. + target_endian = "little", + not(miri), + ))] { + mod neon; + use neon as imp; + } else { + mod generic; + use generic as imp; + } +} + +mod alloc; +pub(crate) use self::alloc::{do_alloc, Allocator, Global}; + +mod bitmask; + +use self::bitmask::BitMaskIter; +use self::imp::Group; + +// Branch prediction hint. This is currently only available on nightly but it +// consistently improves performance by 10-15%. +#[cfg(not(feature = "nightly"))] +use core::convert::identity as likely; +#[cfg(not(feature = "nightly"))] +use core::convert::identity as unlikely; +#[cfg(feature = "nightly")] +use core::intrinsics::{likely, unlikely}; + +// FIXME: use strict provenance functions once they are stable. +// Implement it with a transmute for now. +#[inline(always)] +#[allow(clippy::useless_transmute)] // clippy is wrong, cast and transmute are different here +fn invalid_mut(addr: usize) -> *mut T { + unsafe { core::mem::transmute(addr) } +} + +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + to.offset_from(from) as usize +} + +/// Whether memory allocation errors should return an error or abort. +#[derive(Copy, Clone)] +enum Fallibility { + Fallible, + Infallible, +} + +impl Fallibility { + /// Error to return on capacity overflow. + #[cfg_attr(feature = "inline-more", inline)] + fn capacity_overflow(self) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::CapacityOverflow, + Fallibility::Infallible => panic!("Hash table capacity overflow"), + } + } + + /// Error to return on allocation error. + #[cfg_attr(feature = "inline-more", inline)] + fn alloc_err(self, layout: Layout) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::AllocError { layout }, + Fallibility::Infallible => handle_alloc_error(layout), + } + } +} + +trait SizedTypeProperties: Sized { + const IS_ZERO_SIZED: bool = mem::size_of::() == 0; + const NEEDS_DROP: bool = mem::needs_drop::(); +} + +impl SizedTypeProperties for T {} + +/// Control byte value for an empty bucket. +const EMPTY: u8 = 0b1111_1111; + +/// Control byte value for a deleted bucket. +const DELETED: u8 = 0b1000_0000; + +/// Checks whether a control byte represents a full bucket (top bit is clear). +#[inline] +fn is_full(ctrl: u8) -> bool { + ctrl & 0x80 == 0 +} + +/// Checks whether a control byte represents a special value (top bit is set). +#[inline] +fn is_special(ctrl: u8) -> bool { + ctrl & 0x80 != 0 +} + +/// Checks whether a special control value is EMPTY (just check 1 bit). +#[inline] +fn special_is_empty(ctrl: u8) -> bool { + debug_assert!(is_special(ctrl)); + ctrl & 0x01 != 0 +} + +/// Primary hash function, used to select the initial bucket to probe from. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h1(hash: u64) -> usize { + // On 32-bit platforms we simply ignore the higher hash bits. + hash as usize +} + +// Constant for h2 function that grabing the top 7 bits of the hash. +const MIN_HASH_LEN: usize = if mem::size_of::() < mem::size_of::() { + mem::size_of::() +} else { + mem::size_of::() +}; + +/// Secondary hash function, saved in the low 7 bits of the control byte. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h2(hash: u64) -> u8 { + // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit + // value, some hash functions (such as FxHash) produce a usize result + // instead, which means that the top 32 bits are 0 on 32-bit platforms. + // So we use MIN_HASH_LEN constant to handle this. + let top7 = hash >> (MIN_HASH_LEN * 8 - 7); + (top7 & 0x7f) as u8 // truncation +} + +/// Probe sequence based on triangular numbers, which is guaranteed (since our +/// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// +struct ProbeSeq { + pos: usize, + stride: usize, +} + +impl ProbeSeq { + #[inline] + fn move_next(&mut self, bucket_mask: usize) { + // We should have found an empty bucket by now and ended the probe. + debug_assert!( + self.stride <= bucket_mask, + "Went past end of probe sequence" + ); + + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= bucket_mask; + } +} + +/// Returns the number of buckets needed to hold the given number of items, +/// taking the maximum load factor into account. +/// +/// Returns `None` if an overflow occurs. +// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258 +#[cfg_attr(target_os = "emscripten", inline(never))] +#[cfg_attr(not(target_os = "emscripten"), inline)] +fn capacity_to_buckets(cap: usize) -> Option { + debug_assert_ne!(cap, 0); + + // For small tables we require at least 1 empty bucket so that lookups are + // guaranteed to terminate if an element doesn't exist in the table. + if cap < 8 { + // We don't bother with a table size of 2 buckets since that can only + // hold a single element. Instead we skip directly to a 4 bucket table + // which can hold 3 elements. + return Some(if cap < 4 { 4 } else { 8 }); + } + + // Otherwise require 1/8 buckets to be empty (87.5% load) + // + // Be careful when modifying this, calculate_layout relies on the + // overflow check here. + let adjusted_cap = cap.checked_mul(8)? / 7; + + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous division). + Some(adjusted_cap.next_power_of_two()) +} + +/// Returns the maximum effective capacity for the given bucket mask, taking +/// the maximum load factor into account. +#[inline] +fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { + if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. + bucket_mask + } else { + // For larger tables we reserve 12.5% of the slots as empty. + ((bucket_mask + 1) / 8) * 7 + } +} + +/// Helper which allows the max calculation for ctrl_align to be statically computed for each T +/// while keeping the rest of `calculate_layout_for` independent of `T` +#[derive(Copy, Clone)] +struct TableLayout { + size: usize, + ctrl_align: usize, +} + +impl TableLayout { + #[inline] + const fn new() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size(), + ctrl_align: if layout.align() > Group::WIDTH { + layout.align() + } else { + Group::WIDTH + }, + } + } + + #[inline] + fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> { + debug_assert!(buckets.is_power_of_two()); + + let TableLayout { size, ctrl_align } = self; + // Manual layout calculation since Layout methods are not yet stable. + let ctrl_offset = + size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); + let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + + // We need an additional check to ensure that the allocation doesn't + // exceed `isize::MAX` (https://github.com/rust-lang/rust/pull/95295). + if len > isize::MAX as usize - (ctrl_align - 1) { + return None; + } + + Some(( + unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, + ctrl_offset, + )) + } +} + +/// A reference to an empty bucket into which an can be inserted. +pub struct InsertSlot { + index: usize, +} + +/// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. +pub struct Bucket { + // Actually it is pointer to next element than element itself + // this is needed to maintain pointer arithmetic invariants + // keeping direct pointer to element introduces difficulty. + // Using `NonNull` for variance and niche layout + ptr: NonNull, +} + +// This Send impl is needed for rayon support. This is safe since Bucket is +// never exposed in a public API. +unsafe impl Send for Bucket {} + +impl Clone for Bucket { + #[inline] + fn clone(&self) -> Self { + Self { ptr: self.ptr } + } +} + +impl Bucket { + /// Creates a [`Bucket`] that contain pointer to the data. + /// The pointer calculation is performed by calculating the + /// offset from given `base` pointer (convenience for + /// `base.as_ptr().sub(index)`). + /// + /// `index` is in units of `T`; e.g., an `index` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// If the `T` is a ZST, then we instead track the index of the element + /// in the table so that `erase` works properly (return + /// `NonNull::new_unchecked((index + 1) as *mut T)`) + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and the safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for the [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * the `base` pointer must not be `dangling` and must points to the + /// end of the first `value element` from the `data part` of the table, i.e. + /// must be the pointer that returned by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn from_base_index(base: NonNull, index: usize) -> Self { + // If mem::size_of::() != 0 then return a pointer to an `element` in + // the data part of the table (we start counting from "0", so that + // in the expression T[last], the "last" index actually one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"): + // + // `from_base_index(base, 1).as_ptr()` returns a pointer that + // points here in the data part of the table + // (to the start of T1) + // | + // | `base: NonNull` must point here + // | (to the end of T0 or to the start of C0) + // v v + // [Padding], Tlast, ..., |T1|, T0, |C0, C1, ..., Clast + // ^ + // `from_base_index(base, 1)` returns a pointer + // that points here in the data part of the table + // (to the end of T1) + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes + // or metadata for data. + let ptr = if T::IS_ZERO_SIZED { + // won't overflow because index must be less than length (bucket_mask) + // and bucket_mask is guaranteed to be less than `isize::MAX` + // (see TableLayout::calculate_layout_for method) + invalid_mut(index + 1) + } else { + base.as_ptr().sub(index) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Calculates the index of a [`Bucket`] as distance between two pointers + /// (convenience for `base.as_ptr().offset_from(self.ptr.as_ptr()) as usize`). + /// The returned value is in units of T: the distance in bytes divided by + /// [`core::mem::size_of::()`]. + /// + /// If the `T` is a ZST, then we return the index of the element in + /// the table so that `erase` works properly (return `self.ptr.as_ptr() as usize - 1`). + /// + /// This function is the inverse of [`from_base_index`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*const T>::offset_from`] method of `*const T`. + /// + /// Thus, in order to uphold the safety contracts for [`<*const T>::offset_from`] + /// method, as well as for the correct logic of the work of this crate, the + /// following rules are necessary and sufficient: + /// + /// * `base` contained pointer must not be `dangling` and must point to the + /// end of the first `element` from the `data part` of the table, i.e. + /// must be a pointer that returns by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `self` also must not contain dangling pointer; + /// + /// * both `self` and `base` must be created from the same [`RawTable`] + /// (or [`RawTableInner`]). + /// + /// If `mem::size_of::() == 0`, this function is always safe. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`from_base_index`]: crate::raw::Bucket::from_base_index + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTableInner`]: RawTableInner + /// [`<*const T>::offset_from`]: https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.offset_from + #[inline] + unsafe fn to_base_index(&self, base: NonNull) -> usize { + // If mem::size_of::() != 0 then return an index under which we used to store the + // `element` in the data part of the table (we start counting from "0", so + // that in the expression T[last], the "last" index actually is one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"). + // For example for 5th element in table calculation is performed like this: + // + // mem::size_of::() + // | + // | `self = from_base_index(base, 5)` that returns pointer + // | that points here in tha data part of the table + // | (to the end of T5) + // | | `base: NonNull` must point here + // v | (to the end of T0 or to the start of C0) + // /???\ v v + // [Padding], Tlast, ..., |T10|, ..., T5|, T4, T3, T2, T1, T0, |C0, C1, C2, C3, C4, C5, ..., C10, ..., Clast + // \__________ __________/ + // \/ + // `bucket.to_base_index(base)` = 5 + // (base.as_ptr() as usize - self.ptr.as_ptr() as usize) / mem::size_of::() + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes or metadata for data. + if T::IS_ZERO_SIZED { + // this can not be UB + self.ptr.as_ptr() as usize - 1 + } else { + offset_from(base.as_ptr(), self.ptr.as_ptr()) + } + } + + /// Acquires the underlying raw pointer `*mut T` to `data`. + /// + /// # Note + /// + /// If `T` is not [`Copy`], do not use `*mut T` methods that can cause calling the + /// destructor of `T` (for example the [`<*mut T>::drop_in_place`] method), because + /// for properly dropping the data we also need to clear `data` control bytes. If we + /// drop data, but do not clear `data control byte` it leads to double drop when + /// [`RawTable`] goes out of scope. + /// + /// If you modify an already initialized `value`, so [`Hash`] and [`Eq`] on the new + /// `T` value and its borrowed form *must* match those for the old `T` value, as the map + /// will not re-evaluate where the new value should go, meaning the value may become + /// "lost" if their location does not reflect their state. + /// + /// [`RawTable`]: crate::raw::RawTable + /// [`<*mut T>::drop_in_place`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.drop_in_place + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value = ("a", 100); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, i32)> = table.find(hash, |(k1, _)| k1 == &value.0).unwrap(); + /// + /// assert_eq!(unsafe { &*bucket.as_ptr() }, &("a", 100)); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn as_ptr(&self) -> *mut T { + if T::IS_ZERO_SIZED { + // Just return an arbitrary ZST pointer which is properly aligned + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) + } else { + unsafe { self.ptr.as_ptr().sub(1) } + } + } + + /// Create a new [`Bucket`] that is offset from the `self` by the given + /// `offset`. The pointer calculation is performed by calculating the + /// offset from `self` pointer (convenience for `self.ptr.as_ptr().sub(offset)`). + /// This function is used for iterators. + /// + /// `offset` is in units of `T`; e.g., a `offset` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * `self` contained pointer must not be `dangling`; + /// + /// * `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other + /// words, `self.to_base_index() + ofset + 1` must be no greater than the number returned + /// by the function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other words, + /// `self.to_base_index() + ofset + 1` must be no greater than the number returned by the + /// function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn next_n(&self, offset: usize) -> Self { + let ptr = if T::IS_ZERO_SIZED { + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) + } else { + self.ptr.as_ptr().sub(offset) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Executes the destructor (if any) of the pointed-to `data`. + /// + /// # Safety + /// + /// See [`ptr::drop_in_place`] for safety concerns. + /// + /// You should use [`RawTable::erase`] instead of this function, + /// or be careful with calling this function directly, because for + /// properly dropping the data we need also clear `data` control bytes. + /// If we drop data, but do not erase `data control byte` it leads to + /// double drop when [`RawTable`] goes out of scope. + /// + /// [`ptr::drop_in_place`]: https://doc.rust-lang.org/core/ptr/fn.drop_in_place.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::erase`]: crate::raw::RawTable::erase + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn drop(&self) { + self.as_ptr().drop_in_place(); + } + + /// Reads the `value` from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// # Safety + /// + /// See [`ptr::read`] for safety concerns. + /// + /// You should use [`RawTable::remove`] instead of this function, + /// or be careful with calling this function directly, because compiler + /// calls its destructor when readed `value` goes out of scope. It + /// can cause double dropping when [`RawTable`] goes out of scope, + /// because of not erased `data control byte`. + /// + /// [`ptr::read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::remove`]: crate::raw::RawTable::remove + #[inline] + pub(crate) unsafe fn read(&self) -> T { + self.as_ptr().read() + } + + /// Overwrites a memory location with the given `value` without reading + /// or dropping the old value (like [`ptr::write`] function). + /// + /// # Safety + /// + /// See [`ptr::write`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::write`]: https://doc.rust-lang.org/core/ptr/fn.write.html + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[inline] + pub(crate) unsafe fn write(&self, val: T) { + self.as_ptr().write(val); + } + + /// Returns a shared immutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_ref`] for safety concerns. + /// + /// [`NonNull::as_ref`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_ref + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &("A pony", "is a small horse".to_owned()) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn as_ref<'a>(&self) -> &'a T { + &*self.as_ptr() + } + + /// Returns a unique mutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_mut`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`NonNull::as_mut`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_mut + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// unsafe { + /// bucket + /// .as_mut() + /// .1 + /// .push_str(" less than 147 cm at the withers") + /// }; + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &( + /// "A pony", + /// "is a small horse less than 147 cm at the withers".to_owned() + /// ) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn as_mut<'a>(&self) -> &'a mut T { + &mut *self.as_ptr() + } + + /// Copies `size_of` bytes from `other` to `self`. The source + /// and destination may *not* overlap. + /// + /// # Safety + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns. + /// + /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of + /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values + /// in the region beginning at `*self` and the region beginning at `*other` can + /// [violate memory safety]. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::copy_nonoverlapping`]: https://doc.rust-lang.org/core/ptr/fn.copy_nonoverlapping.html + /// [`read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [violate memory safety]: https://doc.rust-lang.org/std/ptr/fn.read.html#ownership-of-the-returned-value + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[cfg(feature = "raw")] + #[inline] + pub unsafe fn copy_from_nonoverlapping(&self, other: &Self) { + self.as_ptr().copy_from_nonoverlapping(other.as_ptr(), 1); + } +} + +/// A raw hash table with an unsafe API. +pub struct RawTable { + table: RawTableInner, + alloc: A, + // Tell dropck that we own instances of T. + marker: PhantomData, +} + +/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless +/// of how many different key-value types are used. +struct RawTableInner { + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. + bucket_mask: usize, + + // [Padding], T1, T2, ..., Tlast, C1, C2, ... + // ^ points here + ctrl: NonNull, + + // Number of elements that can be inserted before we need to grow the table + growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + pub const fn new() -> Self { + Self { + table: RawTableInner::NEW, + alloc: Global, + marker: PhantomData, + } + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } +} + +impl RawTable { + const TABLE_LAYOUT: TableLayout = TableLayout::new::(); + + /// Creates a new empty hash table without allocating any memory, using the + /// given allocator. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + pub const fn new_in(alloc: A) -> Self { + Self { + table: RawTableInner::NEW, + alloc, + marker: PhantomData, + } + } + + /// Allocates a new hash table with the given number of buckets. + /// + /// The control bytes are left uninitialized. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + Ok(Self { + table: RawTableInner::new_uninitialized( + &alloc, + Self::TABLE_LAYOUT, + buckets, + fallibility, + )?, + alloc, + marker: PhantomData, + }) + } + + /// Attempts to allocate a new hash table using the given allocator, with at least enough + /// capacity for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Ok(Self { + table: RawTableInner::fallible_with_capacity( + &alloc, + Self::TABLE_LAYOUT, + capacity, + Fallibility::Fallible, + )?, + alloc, + marker: PhantomData, + }) + } + + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + table: RawTableInner::with_capacity(&alloc, Self::TABLE_LAYOUT, capacity), + alloc, + marker: PhantomData, + } + } + + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub fn data_end(&self) -> NonNull { + // `self.table.ctrl.cast()` returns pointer that + // points here (to the end of `T0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTable::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + self.table.ctrl.cast() + } + + /// Returns pointer to start of data table. + #[inline] + #[cfg(any(feature = "raw", feature = "nightly"))] + pub unsafe fn data_start(&self) -> NonNull { + NonNull::new_unchecked(self.data_end().as_ptr().wrapping_sub(self.buckets())) + } + + /// Return the information about memory allocated by the table. + /// + /// `RawTable` allocates single memory block to store both data and metadata. + /// This function returns allocation size and alignment and the beginning of the area. + /// These are the arguments which will be passed to `dealloc` when the table is dropped. + /// + /// This function might be useful for memory profiling. + #[inline] + #[cfg(feature = "raw")] + pub fn allocation_info(&self) -> (NonNull, Layout) { + // SAFETY: We use the same `table_layout` that was used to allocate + // this table. + unsafe { self.table.allocation_info_or_zero(Self::TABLE_LAYOUT) } + } + + /// Returns the index of a bucket from a `Bucket`. + #[inline] + pub unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { + bucket.to_base_index(self.data_end()) + } + + /// Returns a pointer to an element in the table. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the caller of this function must observe the + /// following safety rules: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTable::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// [`RawTable::buckets`]: RawTable::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub unsafe fn bucket(&self, index: usize) -> Bucket { + // If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + // (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + // the "buckets" number of our `RawTable`, i.e. "n = RawTable::buckets() - 1"): + // + // `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + // part of the `RawTable`, i.e. to the start of T3 (see `Bucket::as_ptr`) + // | + // | `base = self.data_end()` points here + // | (to the start of CT0 or to the end of T0) + // v v + // [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + // ^ \__________ __________/ + // `table.bucket(3)` returns a pointer that points \/ + // here in the `data` part of the `RawTable` (to additional control bytes + // the end of T3) `m = Group::WIDTH - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`; + // CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + // the heap works properly, even if the result of `h1(hash) & self.table.bucket_mask` + // is equal to `self.table.bucket_mask`). See also `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.table.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.table.bucket_mask = self.buckets() - 1`. + debug_assert_ne!(self.table.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Erases an element from the table without dropping it. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn erase_no_drop(&mut self, item: &Bucket) { + let index = self.bucket_index(item); + self.table.erase(index); + } + + /// Erases an element from the table, dropping it in place. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn erase(&mut self, item: Bucket) { + // Erase the element from the table first since drop might panic. + self.erase_no_drop(&item); + item.drop(); + } + + /// Finds and erases an element from the table, dropping it in place. + /// Returns true if an element was found. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn erase_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> bool { + // Avoid `Option::map` because it bloats LLVM IR. + if let Some(bucket) = self.find(hash, eq) { + unsafe { + self.erase(bucket); + } + true + } else { + false + } + } + + /// Removes an element from the table, returning it. + /// + /// This also returns an `InsertSlot` pointing to the newly free bucket. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn remove(&mut self, item: Bucket) -> (T, InsertSlot) { + self.erase_no_drop(&item); + ( + item.read(), + InsertSlot { + index: self.bucket_index(&item), + }, + ) + } + + /// Finds and removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { self.remove(bucket).0 }), + None => None, + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear_no_drop(&mut self) { + self.table.clear_no_drop(); + } + + /// Removes all elements from the table without freeing the backing memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + if self.is_empty() { + // Special case empty table to avoid surprising O(capacity) time. + return; + } + // Ensure that the table is reset even if one of the drops panic + let mut self_ = guard(self, |self_| self_.clear_no_drop()); + unsafe { + // SAFETY: ScopeGuard sets to zero the `items` field of the table + // even in case of panic during the dropping of the elements so + // that there will be no double drop of the elements. + self_.table.drop_elements::(); + } + } + + /// Shrinks the table to fit `max(self.len(), min_size)` elements. + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. + let min_size = usize::max(self.table.items, min_size); + if min_size == 0 { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let min_buckets = match capacity_to_buckets(min_size) { + Some(buckets) => buckets, + None => return, + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets < self.buckets() { + // Fast path if the table is empty + if self.table.items == 0 { + let new_inner = + RawTableInner::with_capacity(&self.alloc, Self::TABLE_LAYOUT, min_size); + let mut old_inner = mem::replace(&mut self.table, new_inner); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: + // 1. We know for sure that `min_size >= self.table.items`. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: The result of calling the `resize` function cannot be an error + // because `fallibility == Fallibility::Infallible. + hint::unreachable_unchecked() + } + } + } + } + } + + /// Ensures that at least `additional` items can be inserted into the table + /// without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + if unlikely(additional > self.table.growth_left) { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: All allocation errors will be caught inside `RawTableInner::reserve_rehash`. + hint::unreachable_unchecked() + } + } + } + } + + /// Tries to ensure that at least `additional` items can be inserted into + /// the table without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + if additional > self.table.growth_left { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Fallible) } + } else { + Ok(()) + } + } + + /// Out-of-line slow path for `reserve` and `try_reserve`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cold] + #[inline(never)] + unsafe fn reserve_rehash( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + unsafe { + // SAFETY: + // 1. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 2. The `drop` function is the actual drop function of the elements stored in + // the table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.reserve_rehash_inner( + &self.alloc, + additional, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + if T::NEEDS_DROP { + Some(mem::transmute(ptr::drop_in_place:: as unsafe fn(*mut T))) + } else { + None + }, + ) + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// The caller of this function must ensure that `capacity >= self.table.items` + /// otherwise: + /// + /// * If `self.table.items != 0`, calling of this function with `capacity` + /// equal to 0 (`capacity == 0`) results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function are never return (will go into an + /// infinite loop). + /// + /// See [`RawTableInner::find_insert_slot`] for more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn resize( + &mut self, + capacity: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + // SAFETY: + // 1. The caller of this function guarantees that `capacity >= self.table.items`. + // 2. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.resize_inner( + &self.alloc, + capacity, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + ) + } + + /// Inserts a new element into the table, and returns its raw bucket. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose `RawTable::new_uninitialized` in a public API. + // + // 2. We reserve additional space (if necessary) right after calling this function. + let mut slot = self.table.find_insert_slot(hash); + + // We can avoid growing the table once we have reached our load factor if we are replacing + // a tombstone. This works since the number of EMPTY slots does not change in this case. + // + // SAFETY: The function is guaranteed to return [`InsertSlot`] that contains an index + // in the range `0..=self.buckets()`. + let old_ctrl = *self.table.ctrl(slot.index); + if unlikely(self.table.growth_left == 0 && special_is_empty(old_ctrl)) { + self.reserve(1, hasher); + // SAFETY: We know for sure that `RawTableInner` has control bytes + // initialized and that there is extra space in the table. + slot = self.table.find_insert_slot(hash); + } + + self.insert_in_slot(hash, slot, value) + } + } + + /// Attempts to insert a new element without growing the table and return its raw bucket. + /// + /// Returns an `Err` containing the given element if inserting it would require growing the + /// table. + /// + /// This does not check if the given element already exists in the table. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert_no_grow(&mut self, hash: u64, value: T) -> Result, T> { + unsafe { + match self.table.prepare_insert_no_grow(hash) { + Ok(index) => { + let bucket = self.bucket(index); + bucket.write(value); + Ok(bucket) + } + Err(()) => Err(value), + } + } + } + + /// Inserts a new element into the table, and returns a mutable reference to it. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T { + unsafe { self.insert(hash, value, hasher).as_mut() } + } + + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(any(feature = "raw", feature = "rustc-internal-api"))] + pub unsafe fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { + let (index, old_ctrl) = self.table.prepare_insert_slot(hash); + let bucket = self.table.bucket(index); + + // If we are replacing a DELETED entry then we don't need to update + // the load counter. + self.table.growth_left -= special_is_empty(old_ctrl) as usize; + + bucket.write(value); + self.table.items += 1; + bucket + } + + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.table.ctrl(index); + debug_assert!(self.is_bucket_full(index)); + let old_growth_left = self.table.growth_left; + let item = self.remove(bucket).0; + if let Some(new_item) = f(item) { + self.table.growth_left = old_growth_left; + self.table.set_ctrl(index, old_ctrl); + self.table.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + + /// Searches for an element in the table. If the element is not found, + /// returns `Err` with the position of a slot where an element with the + /// same hash could be inserted. + /// + /// This function may resize the table if additional space is required for + /// inserting an element. + #[inline] + pub fn find_or_find_insert_slot( + &mut self, + hash: u64, + mut eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Result, InsertSlot> { + self.reserve(1, hasher); + + unsafe { + // SAFETY: + // 1. We know for sure that there is at least one empty `bucket` in the table. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since we will + // never expose `RawTable::new_uninitialized` in a public API. + // 3. The `find_or_find_insert_slot_inner` function returns the `index` of only the full bucket, + // which is in the range `0..self.buckets()` (since there is at least one empty `bucket` in + // the table), so calling `self.bucket(index)` and `Bucket::as_ref` is safe. + match self + .table + .find_or_find_insert_slot_inner(hash, &mut |index| eq(self.bucket(index).as_ref())) + { + // SAFETY: See explanation above. + Ok(index) => Ok(self.bucket(index)), + Err(slot) => Err(slot), + } + } + } + + /// Inserts a new element into the table in the given slot, and returns its + /// raw bucket. + /// + /// # Safety + /// + /// `slot` must point to a slot previously returned by + /// `find_or_find_insert_slot`, and no mutation of the table must have + /// occurred since that call. + #[inline] + pub unsafe fn insert_in_slot(&mut self, hash: u64, slot: InsertSlot, value: T) -> Bucket { + let old_ctrl = *self.table.ctrl(slot.index); + self.table.record_item_insert_at(slot.index, old_ctrl, hash); + + let bucket = self.bucket(slot.index); + bucket.write(value); + bucket + } + + /// Searches for an element in the table. + #[inline] + pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since we + // will never expose `RawTable::new_uninitialized` in a public API. + // 1. The `find_inner` function returns the `index` of only the full bucket, which is in + // the range `0..self.buckets()`, so calling `self.bucket(index)` and `Bucket::as_ref` + // is safe. + let result = self + .table + .find_inner(hash, &mut |index| eq(self.bucket(index).as_ref())); + + // Avoid `Option::map` because it bloats LLVM IR. + match result { + // SAFETY: See explanation above. + Some(index) => Some(self.bucket(index)), + None => None, + } + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + /// Gets a mutable reference to an element in the table. + #[inline] + pub fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + /// Attempts to get mutable references to `N` entries in the table at once. + /// + /// Returns an array of length `N` with the results of each query. + /// + /// At most one mutable reference will be returned to any entry. `None` will be returned if any + /// of the hashes are duplicates. `None` will be returned if the hash is not found. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + unsafe { + let ptrs = self.get_many_mut_pointers(hashes, eq)?; + + for (i, &cur) in ptrs.iter().enumerate() { + if ptrs[..i].iter().any(|&prev| ptr::eq::(prev, cur)) { + return None; + } + } + // All bucket are distinct from all previous buckets so we're clear to return the result + // of the lookup. + + // TODO use `MaybeUninit::array_assume_init` here instead once that's stable. + Some(mem::transmute_copy(&ptrs)) + } + } + + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + let ptrs = self.get_many_mut_pointers(hashes, eq)?; + Some(mem::transmute_copy(&ptrs)) + } + + unsafe fn get_many_mut_pointers( + &mut self, + hashes: [u64; N], + mut eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[*mut T; N]> { + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut outs: MaybeUninit<[*mut T; N]> = MaybeUninit::uninit(); + let outs_ptr = outs.as_mut_ptr(); + + for (i, &hash) in hashes.iter().enumerate() { + let cur = self.find(hash, |k| eq(i, k))?; + *(*outs_ptr).get_unchecked_mut(i) = cur.as_mut(); + } + + // TODO use `MaybeUninit::array_assume_init` here instead once that's stable. + Some(outs.assume_init()) + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the table might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + #[inline] + pub fn capacity(&self) -> usize { + self.table.items + self.table.growth_left + } + + /// Returns the number of elements in the table. + #[inline] + pub fn len(&self) -> usize { + self.table.items + } + + /// Returns `true` if the table contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of buckets in the table. + #[inline] + pub fn buckets(&self) -> usize { + self.table.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + pub unsafe fn is_bucket_full(&self, index: usize) -> bool { + self.table.is_bucket_full(index) + } + + /// Returns an iterator over every element in the table. It is up to + /// the caller to ensure that the `RawTable` outlives the `RawIter`. + /// Because we cannot make the `next` method unsafe on the `RawIter` + /// struct, we have to make the `iter` method unsafe. + #[inline] + pub unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. The caller must uphold the safety contract for `iter` method. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + self.table.iter() + } + + /// Returns an iterator over occupied buckets that could match a given hash. + /// + /// `RawTable` only stores 7 bits of the hash value, so this iterator may + /// return items that have a hash value different than the one provided. You + /// should always validate the returned values before using them. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHash`. Because we cannot make the `next` method unsafe on the + /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash { + RawIterHash::new(self, hash) + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> RawDrain<'_, T, A> { + unsafe { + let iter = self.iter(); + self.drain_iter_from(iter) + } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn drain_iter_from(&mut self, iter: RawIter) -> RawDrain<'_, T, A> { + debug_assert_eq!(iter.len(), self.len()); + RawDrain { + iter, + table: mem::replace(&mut self.table, RawTableInner::NEW), + orig_table: NonNull::from(&mut self.table), + marker: PhantomData, + } + } + + /// Returns an iterator which consumes all elements from the table. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + pub unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { + debug_assert_eq!(iter.len(), self.len()); + + let allocation = self.into_allocation(); + RawIntoIter { + iter, + allocation, + marker: PhantomData, + } + } + + /// Converts the table into a raw allocation. The contents of the table + /// should be dropped using a `RawIter` before freeing the allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout, A)> { + let alloc = if self.table.is_empty_singleton() { + None + } else { + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = + match Self::TABLE_LAYOUT.calculate_layout_for(self.table.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + Some(( + unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + unsafe { ptr::read(&self.alloc) }, + )) + }; + mem::forget(self); + alloc + } +} + +unsafe impl Send for RawTable +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawTable +where + T: Sync, + A: Sync, +{ +} + +impl RawTableInner { + const NEW: Self = RawTableInner::new(); + + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never accessed + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + const fn new() -> Self { + Self { + // Be careful to cast the entire slice to a raw pointer. + ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, + bucket_mask: 0, + items: 0, + growth_left: 0, + } + } +} + +impl RawTableInner { + /// Allocates a new [`RawTableInner`] with the given number of buckets. + /// The control bytes and buckets are left uninitialized. + /// + /// # Safety + /// + /// The caller of this function must ensure that the `buckets` is power of two + /// and also initialize all control bytes of the length `self.bucket_mask + 1 + + /// Group::WIDTH` with the [`EMPTY`] bytes. + /// + /// See also [`Allocator`] API for other safety concerns. + /// + /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: &A, + table_layout: TableLayout, + buckets: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + debug_assert!(buckets.is_power_of_two()); + + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(buckets) { + Some(lco) => lco, + None => return Err(fallibility.capacity_overflow()), + }; + + let ptr: NonNull = match do_alloc(alloc, layout) { + Ok(block) => block.cast(), + Err(_) => return Err(fallibility.alloc_err(layout)), + }; + + // SAFETY: null pointer will be caught in above check + let ctrl = NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)); + Ok(Self { + ctrl, + bucket_mask: buckets - 1, + items: 0, + growth_left: bucket_mask_to_capacity(buckets - 1), + }) + } + + /// Attempts to allocate a new [`RawTableInner`] with at least enough + /// capacity for inserting the given number of elements without reallocating. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. + #[inline] + fn fallible_with_capacity( + alloc: &A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + if capacity == 0 { + Ok(Self::NEW) + } else { + // SAFETY: We checked that we could successfully allocate the new table, and then + // initialized all control bytes with the constant `EMPTY` byte. + unsafe { + let buckets = + capacity_to_buckets(capacity).ok_or_else(|| fallibility.capacity_overflow())?; + + let result = Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes()); + + Ok(result) + } + } + } + + /// Allocates a new [`RawTableInner`] with at least enough capacity for inserting + /// the given number of elements without reallocating. + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`fallible_with_capacity`] instead if you want to + /// handle memory allocation failure. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. + /// + /// [`fallible_with_capacity`]: RawTableInner::fallible_with_capacity + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + fn with_capacity(alloc: &A, table_layout: TableLayout, capacity: usize) -> Self + where + A: Allocator, + { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::fallible_with_capacity(alloc, table_layout, capacity, Fallibility::Infallible) { + Ok(table_inner) => table_inner, + // SAFETY: All allocation errors will be caught inside `RawTableInner::new_uninitialized`. + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Fixes up an insertion slot returned by the [`RawTableInner::find_insert_slot_in_group`] method. + /// + /// In tables smaller than the group width (`self.buckets() < Group::WIDTH`), trailing control + /// bytes outside the range of the table are filled with [`EMPTY`] entries. These will unfortunately + /// trigger a match of [`RawTableInner::find_insert_slot_in_group`] function. This is because + /// the `Some(bit)` returned by `group.match_empty_or_deleted().lowest_set_bit()` after masking + /// (`(probe_seq.pos + bit) & self.bucket_mask`) may point to a full bucket that is already occupied. + /// We detect this situation here and perform a second scan starting at the beginning of the table. + /// This second scan is guaranteed to find an empty slot (due to the load factor) before hitting the + /// trailing control bytes (containing [`EMPTY`] bytes). + /// + /// If this function is called correctly, it is guaranteed to return [`InsertSlot`] with an + /// index of an empty or deleted bucket in the range `0..self.buckets()` (see `Warning` and + /// `Safety`). + /// + /// # Warning + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise if the table is less than + /// the group width (`self.buckets() < Group::WIDTH`) this function returns an index outside of the + /// table indices range `0..self.buckets()` (`0..=self.bucket_mask`). Attempt to write data at that + /// index will cause immediate [`undefined behavior`]. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::ctrl`] method. + /// Thus, in order to uphold those safety contracts, as well as for the correct logic of the work + /// of this crate, the following rules are necessary and sufficient: + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise calling this + /// function results in [`undefined behavior`]. + /// + /// * This function must only be used on insertion slots found by [`RawTableInner::find_insert_slot_in_group`] + /// (after the `find_insert_slot_in_group` function, but before insertion into the table). + /// + /// * The `index` must not be greater than the `self.bucket_mask`, i.e. `(index + 1) <= self.buckets()` + /// (this one is provided by the [`RawTableInner::find_insert_slot_in_group`] function). + /// + /// Calling this function with an index not provided by [`RawTableInner::find_insert_slot_in_group`] + /// may result in [`undefined behavior`] even if the index satisfies the safety rules of the + /// [`RawTableInner::ctrl`] function (`index < self.bucket_mask + 1 + Group::WIDTH`). + /// + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::find_insert_slot_in_group`]: RawTableInner::find_insert_slot_in_group + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn fix_insert_slot(&self, mut index: usize) -> InsertSlot { + // SAFETY: The caller of this function ensures that `index` is in the range `0..=self.bucket_mask`. + if unlikely(self.is_bucket_full(index)) { + debug_assert!(self.bucket_mask < Group::WIDTH); + // SAFETY: + // + // * Since the caller of this function ensures that the control bytes are properly + // initialized and `ptr = self.ctrl(0)` points to the start of the array of control + // bytes, therefore: `ctrl` is valid for reads, properly aligned to `Group::WIDTH` + // and points to the properly initialized control bytes (see also + // `TableLayout::calculate_layout_for` and `ptr::read`); + // + // * Because the caller of this function ensures that the index was provided by the + // `self.find_insert_slot_in_group()` function, so for for tables larger than the + // group width (self.buckets() >= Group::WIDTH), we will never end up in the given + // branch, since `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_slot_in_group` + // cannot return a full bucket index. For tables smaller than the group width, calling + // the `unwrap_unchecked` function is also safe, as the trailing control bytes outside + // the range of the table are filled with EMPTY bytes (and we know for sure that there + // is at least one FULL bucket), so this second scan either finds an empty slot (due to + // the load factor) or hits the trailing control bytes (containing EMPTY). + index = Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit() + .unwrap_unchecked(); + } + InsertSlot { index } + } + + /// Finds the position to insert something in a group. + /// + /// **This may have false positives and must be fixed up with `fix_insert_slot` + /// before it's used.** + /// + /// The function is guaranteed to return the index of an empty or deleted [`Bucket`] + /// in the range `0..self.buckets()` (`0..=self.bucket_mask`). + #[inline] + fn find_insert_slot_in_group(&self, group: &Group, probe_seq: &ProbeSeq) -> Option { + let bit = group.match_empty_or_deleted().lowest_set_bit(); + + if likely(bit.is_some()) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + Some((probe_seq.pos + bit.unwrap()) & self.bucket_mask) + } else { + None + } + } + + /// Searches for an element in the table, or a potential slot where that element could + /// be inserted (an empty or deleted [`Bucket`] index). + /// + /// This uses dynamic dispatch to reduce the amount of code generated, but that is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element (as `Ok(index)`). If the element is not found and there is at least 1 + /// empty or deleted [`Bucket`] in the table, the function is guaranteed to return + /// [InsertSlot] with an index in the range `0..self.buckets()`, but in any case, + /// if this function returns [`InsertSlot`], it will contain an index in the range + /// `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_or_find_insert_slot_inner( + &self, + hash: u64, + eq: &mut dyn FnMut(usize) -> bool, + ) -> Result { + let mut insert_slot = None; + + let h2_hash = h2(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_byte(h2_hash) { + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Ok(index); + } + } + + // We didn't find the element we were looking for in the group, try to get an + // insertion slot from the group if we don't have one yet. + if likely(insert_slot.is_none()) { + insert_slot = self.find_insert_slot_in_group(&group, &probe_seq); + } + + // Only stop the search if the group contains at least one empty element. + // Otherwise, the element that we are looking for might be in a following group. + if likely(group.match_empty().any_bit_set()) { + // We must have found a insert slot by now, since the current group contains at + // least one. For tables smaller than the group width, there will still be an + // empty element in the current (and only) group due to the load factor. + unsafe { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + return Err(self.fix_insert_slot(insert_slot.unwrap_unchecked())); + } + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting a new + /// element and sets the hash for that slot. Returns an index of that slot and the + /// old control byte stored in the found index. + /// + /// This function does not check if the given element exists in the table. Also, + /// this function does not check if there is enough space in the table to insert + /// a new element. Caller of the funtion must make ensure that the table has at + /// least 1 empty or deleted `bucket`, otherwise this function will never return + /// (will go into an infinite loop) for tables larger than the group width, or + /// return an index outside of the table indices range if the table is less than + /// the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an `index` in the range `0..self.buckets()`, but in any case, + /// if this function returns an `index` it will be in the range `0..=self.buckets()`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for the + /// [`RawTableInner::set_ctrl_h2`] and [`RawTableInner::find_insert_slot`] methods. + /// Thus, in order to uphold the safety contracts for that methods, as well as for + /// the correct logic of the work of this crate, you must observe the following rules + /// when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated and has properly initialized + /// control bytes otherwise calling this function results in [`undefined behavior`]. + /// + /// * The caller of this function must ensure that the "data" parts of the table + /// will have an entry in the returned index (matching the given hash) right + /// after calling this function. + /// + /// Attempt to write data at the `index` returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// The caller must independently increase the `items` field of the table, and also, + /// if the old control byte was [`EMPTY`], then decrease the table's `growth_left` + /// field, and do not change it if the old control byte was [`DELETED`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + #[inline] + unsafe fn prepare_insert_slot(&mut self, hash: u64) -> (usize, u8) { + // SAFETY: Caller of this function ensures that the control bytes are properly initialized. + let index: usize = self.find_insert_slot(hash).index; + // SAFETY: + // 1. The `find_insert_slot` function either returns an `index` less than or + // equal to `self.buckets() = self.bucket_mask + 1` of the table, or never + // returns if it cannot find an empty or deleted slot. + // 2. The caller of this function guarantees that the table has already been + // allocated + let old_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + (index, old_ctrl) + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element, returning the `index` for the new [`Bucket`]. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return [`InsertSlot`] with an index in the range `0..self.buckets()`, + /// but in any case, if this function returns [`InsertSlot`], it will contain an index + /// in the range `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_insert_slot(&self, hash: u64) -> InsertSlot { + let mut probe_seq = self.probe_seq(hash); + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + let index = self.find_insert_slot_in_group(&group, &probe_seq); + if likely(index.is_some()) { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + unsafe { + return self.fix_insert_slot(index.unwrap_unchecked()); + } + } + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an element in a table, returning the `index` of the found element. + /// This uses dynamic dispatch to reduce the amount of code generated, but it is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, + /// this function will also never return (will go into an infinite loop). + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element as `Some(index)`, so the index will always be in the range + /// `0..self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { + let h2_hash = h2(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask`. + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new_in). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_byte(h2_hash) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Some(index); + } + } + + if likely(group.match_empty().any_bit_set()) { + return None; + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Prepares for rehashing data in place (that is, without allocating new memory). + /// Converts all full index `control bytes` to `DELETED` and all `DELETED` control + /// bytes to `EMPTY`, i.e. performs the following conversion: + /// + /// - `EMPTY` control bytes -> `EMPTY`; + /// - `DELETED` control bytes -> `EMPTY`; + /// - `FULL` control bytes -> `DELETED`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The caller of this function must convert the `DELETED` bytes back to `FULL` + /// bytes when re-inserting them into their ideal position (which was impossible + /// to do during the first insert due to tombstones). If the caller does not do + /// this, then calling this function may result in a memory leak. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise + /// calling this function results in [`undefined behavior`]. + /// + /// Calling this function on a table that has not been allocated results in + /// [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + unsafe fn prepare_rehash_in_place(&mut self) { + // Bulk convert all full control bytes to DELETED, and all DELETED control bytes to EMPTY. + // This effectively frees up all buckets containing a DELETED entry. + // + // SAFETY: + // 1. `i` is guaranteed to be within bounds since we are iterating from zero to `buckets - 1`; + // 2. Even if `i` will be `i == self.bucket_mask`, it is safe to call `Group::load_aligned` + // due to the extended control bytes range, which is `self.bucket_mask + 1 + Group::WIDTH`; + // 3. The caller of this function guarantees that [`RawTableInner`] has already been allocated; + // 4. We can use `Group::load_aligned` and `Group::store_aligned` here since we start from 0 + // and go to the end with a step equal to `Group::WIDTH` (see TableLayout::calculate_layout_for). + for i in (0..self.buckets()).step_by(Group::WIDTH) { + let group = Group::load_aligned(self.ctrl(i)); + let group = group.convert_special_to_empty_and_full_to_deleted(); + group.store_aligned(self.ctrl(i)); + } + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + // + // SAFETY: The caller of this function guarantees that [`RawTableInner`] + // has already been allocated + if unlikely(self.buckets() < Group::WIDTH) { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + self.ctrl(0) + .copy_to(self.ctrl(Group::WIDTH), self.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + self.ctrl(0) + .copy_to(self.ctrl(self.buckets()), Group::WIDTH); + } + } + + /// Returns an iterator over every element in the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result + /// is [`undefined behavior`]: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `RawIter`. Because we cannot make the `next` method unsafe on + /// the `RawIter` struct, we have to make the `iter` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise using the returned [`RawIter`] results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.data_end()` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. `data` bucket index in the table is equal to the `ctrl` index (i.e. + // equal to zero). + // 3. We pass the exact value of buckets of the table to the function. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + // SAFETY: See explanation above + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()), + items: self.items, + } + } + + /// Executes the destructors (if any) of the values stored in the table. + /// + /// # Note + /// + /// This function does not erase the control bytes of the table and does + /// not make any changes to the `items` or `growth_left` fields of the + /// table. If necessary, the caller of this function must manually set + /// up these table fields, for example using the [`clear_no_drop`] function. + /// + /// Be careful during calling this function, because drop function of + /// the elements can panic, and this can leave table in an inconsistent + /// state. + /// + /// # Safety + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise calling this function may result in [`undefined behavior`]. + /// + /// If `T` is a type that should be dropped and **the table is not empty**, + /// calling this function more than once results in [`undefined behavior`]. + /// + /// If `T` is not [`Copy`], attempting to use values stored in the table after + /// calling this function may result in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`Bucket::drop`] / [`Bucket::as_ptr`] methods, for more information + /// about of properly removing or saving `element` from / into the [`RawTable`] / + /// [`RawTableInner`]. + /// + /// [`Bucket::drop`]: Bucket::drop + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`clear_no_drop`]: RawTableInner::clear_no_drop + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_elements(&mut self) { + // Check that `self.items != 0`. Protects against the possibility + // of creating an iterator on an table with uninitialized control bytes. + if T::NEEDS_DROP && self.items != 0 { + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `RawIter` iterator, and the caller of this function + // must uphold the safety contract for `drop_elements` method. + for item in self.iter::() { + // SAFETY: The caller must uphold the safety contract for + // `drop_elements` method. + item.drop(); + } + } + } + + /// Executes the destructors (if any) of the values stored in the table and than + /// deallocates the table. + /// + /// # Note + /// + /// Calling this function automatically makes invalid (dangling) all instances of + /// buckets ([`Bucket`]) and makes invalid (dangling) the `ctrl` field of the table. + /// + /// This function does not make any changes to the `bucket_mask`, `items` or `growth_left` + /// fields of the table. If necessary, the caller of this function must manually set + /// up these table fields. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * Calling this function more than once; + /// + /// * The type `T` must be the actual type of the elements stored in the table. + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that + /// was used to allocate this table. + /// + /// The caller of this function should pay attention to the possibility of the + /// elements' drop function panicking, because this: + /// + /// * May leave the table in an inconsistent state; + /// + /// * Memory is never deallocated, so a memory leak may occur. + /// + /// Attempt to use the `ctrl` field of the table (dereference) after calling this + /// function results in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`RawTableInner::drop_elements`] or [`RawTableInner::free_buckets`] + /// for more information. + /// + /// [`RawTableInner::drop_elements`]: RawTableInner::drop_elements + /// [`RawTableInner::free_buckets`]: RawTableInner::free_buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_inner_table(&mut self, alloc: &A, table_layout: TableLayout) { + if !self.is_empty_singleton() { + unsafe { + // SAFETY: The caller must uphold the safety contract for `drop_inner_table` method. + self.drop_elements::(); + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller must uphold the safety contract for `drop_inner_table` method. + self.free_buckets(alloc, table_layout); + } + } + } + + /// Returns a pointer to an element in the table (convenience for + /// `Bucket::from_base_index(self.data_end::(), index)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived from the + /// safety rules of the [`Bucket::from_base_index`] function. Therefore, when calling + /// this function, the following safety rules must be observed: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// * The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`Bucket`] may result in [`undefined behavior`]. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + /// part of the `RawTableInner`, i.e. to the start of T3 (see [`Bucket::as_ptr`]) + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// ^ \__________ __________/ + /// `table.bucket(3)` returns a pointer that points \/ + /// here in the `data` part of the `RawTableInner` additional control bytes + /// (to the end of T3) `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`Bucket::from_base_index`]: Bucket::from_base_index + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Returns a raw `*mut u8` pointer to the start of the `data` element in the table + /// (convenience for `self.data_end::().as_ptr().sub((index + 1) * size_of)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned `*mut u8`, + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`; + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket_ptr(3, mem::size_of::())` returns a pointer that points here in the + /// `data` part of the `RawTableInner`, i.e. to the start of T3 + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// \__________ __________/ + /// \/ + /// additional control bytes + /// `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + let base: *mut u8 = self.data_end().as_ptr(); + base.sub((index + 1) * size_of) + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation (convenience for `self.ctrl.cast()`). + /// + /// This function actually returns a pointer to the end of the `data element` at + /// index "0" (zero). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Note + /// + /// The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`NonNull`] may result in [`undefined behavior`]. + /// + /// ```none + /// `table.data_end::()` returns pointer that points here + /// (to the end of `T0`) + /// ∨ + /// [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + /// \________ ________/ + /// \/ + /// `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`. + /// CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + /// with loading `Group` bytes from the heap works properly, even if the result + /// of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + /// `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + fn data_end(&self) -> NonNull { + self.ctrl.cast() + } + + /// Returns an iterator-like object for a probe sequence on the table. + /// + /// This iterator never terminates, but is guaranteed to visit each bucket + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. + #[inline] + fn probe_seq(&self, hash: u64) -> ProbeSeq { + ProbeSeq { + // This is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + pos: h1(hash) & self.bucket_mask, + stride: 0, + } + } + + /// Returns the index of a bucket for which a value must be inserted if there is enough rooom + /// in the table, otherwise returns error + #[cfg(feature = "raw")] + #[inline] + unsafe fn prepare_insert_no_grow(&mut self, hash: u64) -> Result { + let index = self.find_insert_slot(hash).index; + let old_ctrl = *self.ctrl(index); + if unlikely(self.growth_left == 0 && special_is_empty(old_ctrl)) { + Err(()) + } else { + self.record_item_insert_at(index, old_ctrl, hash); + Ok(index) + } + } + + #[inline] + unsafe fn record_item_insert_at(&mut self, index: usize, old_ctrl: u8, hash: u64) { + self.growth_left -= usize::from(special_is_empty(old_ctrl)); + self.set_ctrl_h2(index, hash); + self.items += 1; + } + + #[inline] + fn is_in_same_group(&self, i: usize, new_i: usize, hash: u64) -> bool { + let probe_seq_pos = self.probe_seq(hash).pos; + let probe_index = + |pos: usize| (pos.wrapping_sub(probe_seq_pos) & self.bucket_mask) / Group::WIDTH; + probe_index(i) == probe_index(new_i) + } + + /// Sets a control byte to the hash, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl`] + /// method. Thus, in order to uphold the safety contracts for the method, you must observe the + /// following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl`]: RawTableInner::set_ctrl + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl_h2(&mut self, index: usize, hash: u64) { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl_h2`] + self.set_ctrl(index, h2(hash)); + } + + /// Replaces the hash in the control byte at the given index with the provided one, + /// and possibly also replicates the new control byte at the end of the array of control + /// bytes, returning the old control byte. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl_h2`] + /// and [`RawTableInner::ctrl`] methods. Thus, in order to uphold the safety contracts for both + /// methods, you must observe the following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn replace_ctrl_h2(&mut self, index: usize, hash: u64) -> u8 { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::replace_ctrl_h2`] + let prev_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + prev_ctrl + } + + /// Sets a control byte, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl(&mut self, index: usize, ctrl: u8) { + // Replicate the first Group::WIDTH control bytes at the end of + // the array without using a branch. If the tables smaller than + // the group width (self.buckets() < Group::WIDTH), + // `index2 = Group::WIDTH + index`, otherwise `index2` is: + // + // - If index >= Group::WIDTH then index == index2. + // - Otherwise index2 == self.bucket_mask + 1 + index. + // + // The very last replicated control byte is never actually read because + // we mask the initial index for unaligned loads, but we write it + // anyways because it makes the set_ctrl implementation simpler. + // + // If there are fewer buckets than Group::WIDTH then this code will + // replicate the buckets at the end of the trailing group. For example + // with 2 buckets and a group size of 4, the control bytes will look + // like this: + // + // Real | Replicated + // --------------------------------------------- + // | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- + + // This is the same as `(index.wrapping_sub(Group::WIDTH)) % self.buckets() + Group::WIDTH` + // because the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl`] + *self.ctrl(index) = ctrl; + *self.ctrl(index2) = ctrl; + } + + /// Returns a pointer to a control byte. + /// + /// # Safety + /// + /// For the allocated [`RawTableInner`], the result is [`Undefined Behavior`], + /// if the `index` is greater than the `self.bucket_mask + 1 + Group::WIDTH`. + /// In that case, calling this function with `index == self.bucket_mask + 1 + Group::WIDTH` + /// will return a pointer to the end of the allocated table and it is useless on its own. + /// + /// Calling this function with `index >= self.bucket_mask + 1 + Group::WIDTH` on a + /// table that has not been allocated results in [`Undefined Behavior`]. + /// + /// So to satisfy both requirements you should always follow the rule that + /// `index < self.bucket_mask + 1 + Group::WIDTH` + /// + /// Calling this function on [`RawTableInner`] that are not already allocated is safe + /// for read-only purpose. + /// + /// See also [`Bucket::as_ptr()`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr()`]: Bucket::as_ptr() + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn ctrl(&self, index: usize) -> *mut u8 { + debug_assert!(index < self.num_ctrl_bytes()); + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::ctrl`] + self.ctrl.as_ptr().add(index) + } + + #[inline] + fn buckets(&self) -> usize { + self.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + unsafe fn is_bucket_full(&self, index: usize) -> bool { + debug_assert!(index < self.buckets()); + is_full(*self.ctrl(index)) + } + + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating, + /// and return it inside ScopeGuard to protect against panic in the hash + /// function. + /// + /// # Note + /// + /// It is recommended (but not required): + /// + /// * That the new table's `capacity` be greater than or equal to `self.items`. + /// + /// * The `alloc` is the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `table_layout` is the same [`TableLayout`] as the `TableLayout` used + /// to allocate this table. + /// + /// If `table_layout` does not match the `TableLayout` that was used to allocate + /// this table, then using `mem::swap` with the `self` and the new table returned + /// by this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + fn prepare_resize<'a, A>( + &self, + alloc: &'a A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result, TryReserveError> + where + A: Allocator, + { + debug_assert!(self.items <= capacity); + + // Allocate and initialize the new table. + let new_table = + RawTableInner::fallible_with_capacity(alloc, table_layout, capacity, fallibility)?; + + // The hash function may panic, in which case we simply free the new + // table without dropping any elements that may have been copied into + // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. + Ok(guard(new_table, move |self_| { + if !self_.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that the `alloc` and `table_layout` matches the + // [`Allocator`] and [`TableLayout`] used to allocate this table. + unsafe { self_.free_buckets(alloc, table_layout) }; + } + })) + } + + /// Reserves or rehashes to make room for `additional` more elements. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table. + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn reserve_rehash_inner( + &mut self, + alloc: &A, + additional: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + drop: Option, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let new_items = match self.items.checked_add(additional) { + Some(new_items) => new_items, + None => return Err(fallibility.capacity_overflow()), + }; + let full_capacity = bucket_mask_to_capacity(self.bucket_mask); + if new_items <= full_capacity / 2 { + // Rehash in-place without re-allocating if we have plenty of spare + // capacity that is locked up due to DELETED entries. + + // SAFETY: + // 1. We know for sure that `[`RawTableInner`]` has already been allocated + // (since new_items <= full_capacity / 2); + // 2. The caller ensures that `drop` function is the actual drop function of + // the elements stored in the table. + // 3. The caller ensures that `layout` matches the [`TableLayout`] that was + // used to allocate this table. + // 4. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.rehash_in_place(hasher, layout.size, drop); + Ok(()) + } else { + // Otherwise, conservatively resize to at least the next size up + // to avoid churning deletes into frequent rehashes. + // + // SAFETY: + // 1. We know for sure that `capacity >= self.items`. + // 2. The caller ensures that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.resize_inner( + alloc, + usize::max(new_items, full_capacity + 1), + hasher, + fallibility, + layout, + ) + } + } + + /// Returns an iterator over full buckets indices in the table. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `FullBucketsIndices`. Because we cannot make the `next` method + /// unsafe on the `FullBucketsIndices` struct, we have to make the + /// `full_buckets_indices` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + #[inline(always)] + unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.ctrl(0)` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. The value of `items` is equal to the amount of data (values) added + // to the table. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, Group::WIDTH + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + let ctrl = NonNull::new_unchecked(self.ctrl(0)); + + FullBucketsIndices { + // Load the first group + // SAFETY: See explanation above. + current_group: Group::load_aligned(ctrl.as_ptr()).match_full().into_iter(), + group_first_index: 0, + ctrl, + items: self.items, + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table; + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The caller of this function must ensure that `capacity >= self.items` + /// otherwise: + /// + /// * If `self.items != 0`, calling of this function with `capacity == 0` + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// are never return (will go into an infinite loop). + /// + /// Note: It is recommended (but not required) that the new table's `capacity` + /// be greater than or equal to `self.items`. In case if `capacity <= self.items` + /// this function can never return. See [`RawTableInner::find_insert_slot`] for + /// more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn resize_inner( + &mut self, + alloc: &A, + capacity: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // SAFETY: We know for sure that `alloc` and `layout` matches the [`Allocator`] and [`TableLayout`] + // that were used to allocate this table. + let mut new_table = self.prepare_resize(alloc, layout, capacity, fallibility)?; + + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `FullBucketsIndices` iterator, and the caller of this + // function ensures that the control bytes are properly initialized. + for full_byte_index in self.full_buckets_indices() { + // This may panic. + let hash = hasher(self, full_byte_index); + + // SAFETY: + // We can use a simpler version of insert() here since: + // 1. There are no DELETED entries. + // 2. We know there is enough space in the table. + // 3. All elements are unique. + // 4. The caller of this function guarantees that `capacity > 0` + // so `new_table` must already have some allocated memory. + // 5. We set `growth_left` and `items` fields of the new table + // after the loop. + // 6. We insert into the table, at the returned index, the data + // matching the given hash immediately after calling this function. + let (new_index, _) = new_table.prepare_insert_slot(hash); + + // SAFETY: + // + // * `src` is valid for reads of `layout.size` bytes, since the + // table is alive and the `full_byte_index` is guaranteed to be + // within bounds (see `FullBucketsIndices::next_impl`); + // + // * `dst` is valid for writes of `layout.size` bytes, since the + // caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate old table and we have the `new_index` + // returned by `prepare_insert_slot`. + // + // * Both `src` and `dst` are properly aligned. + // + // * Both `src` and `dst` point to different region of memory. + ptr::copy_nonoverlapping( + self.bucket_ptr(full_byte_index, layout.size), + new_table.bucket_ptr(new_index, layout.size), + layout.size, + ); + } + + // The hash function didn't panic, so we can safely set the + // `growth_left` and `items` fields of the new table. + new_table.growth_left -= self.items; + new_table.items = self.items; + + // We successfully copied all elements without panicking. Now replace + // self with the new table. The old table will have its memory freed but + // the items will not be dropped (since they have been moved into the + // new table). + // SAFETY: The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + mem::swap(self, &mut new_table); + + Ok(()) + } + + /// Rehashes the contents of the table in place (i.e. without changing the + /// allocation). + /// + /// If `hasher` panics then some the table's contents may be lost. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[cfg_attr(feature = "inline-more", inline(always))] + #[cfg_attr(not(feature = "inline-more"), inline)] + unsafe fn rehash_in_place( + &mut self, + hasher: &dyn Fn(&mut Self, usize) -> u64, + size_of: usize, + drop: Option, + ) { + // If the hash function panics then properly clean up any elements + // that we haven't rehashed yet. We unfortunately can't preserve the + // element since we lost their hash and have no way of recovering it + // without risking another panic. + self.prepare_rehash_in_place(); + + let mut guard = guard(self, move |self_| { + if let Some(drop) = drop { + for i in 0..self_.buckets() { + if *self_.ctrl(i) == DELETED { + self_.set_ctrl(i, EMPTY); + drop(self_.bucket_ptr(i, size_of)); + self_.items -= 1; + } + } + } + self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items; + }); + + // At this point, DELETED elements are elements that we haven't + // rehashed yet. Find them and re-insert them at their ideal + // position. + 'outer: for i in 0..guard.buckets() { + if *guard.ctrl(i) != DELETED { + continue; + } + + let i_p = guard.bucket_ptr(i, size_of); + + 'inner: loop { + // Hash the current item + let hash = hasher(*guard, i); + + // Search for a suitable place to put it + // + // SAFETY: Caller of this function ensures that the control bytes + // are properly initialized. + let new_i = guard.find_insert_slot(hash).index; + + // Probing works by scanning through all of the control + // bytes in groups, which may not be aligned to the group + // size. If both the new and old position fall within the + // same unaligned group, then there is no benefit in moving + // it and we can just continue to the next item. + if likely(guard.is_in_same_group(i, new_i, hash)) { + guard.set_ctrl_h2(i, hash); + continue 'outer; + } + + let new_i_p = guard.bucket_ptr(new_i, size_of); + + // We are moving the current item to a new position. Write + // our H2 to the control byte of the new position. + let prev_ctrl = guard.replace_ctrl_h2(new_i, hash); + if prev_ctrl == EMPTY { + guard.set_ctrl(i, EMPTY); + // If the target slot is empty, simply move the current + // element into the new slot and clear the old control + // byte. + ptr::copy_nonoverlapping(i_p, new_i_p, size_of); + continue 'outer; + } else { + // If the target slot is occupied, swap the two elements + // and then continue processing the element that we just + // swapped into the old slot. + debug_assert_eq!(prev_ctrl, DELETED); + ptr::swap_nonoverlapping(i_p, new_i_p, size_of); + continue 'inner; + } + } + } + + guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items; + + mem::forget(guard); + } + + /// Deallocates the table without dropping any entries. + /// + /// # Note + /// + /// This function must be called only after [`drop_elements`](RawTableInner::drop_elements), + /// else it can lead to leaking of memory. Also calling this function automatically + /// makes invalid (dangling) all instances of buckets ([`Bucket`]) and makes invalid + /// (dangling) the `ctrl` field of the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that was used + /// to allocate this table. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn free_buckets(&mut self, alloc: &A, table_layout: TableLayout) + where + A: Allocator, + { + // SAFETY: The caller must uphold the safety contract for `free_buckets` + // method. + let (ptr, layout) = self.allocation_info(table_layout); + alloc.deallocate(ptr, layout); + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. + /// + /// # Safety + /// + /// Caller of this function must observe the following safety rules: + /// + /// * The [`RawTableInner`] has already been allocated, otherwise + /// calling this function results in [`undefined behavior`] + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + ( + // SAFETY: The caller must uphold the safety contract for `allocation_info` method. + unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + ) + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. If [`RawTableInner`] has not been allocated, this + /// function return `dangling` pointer and `()` (unit) layout. + /// + /// # Safety + /// + /// The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[cfg(feature = "raw")] + unsafe fn allocation_info_or_zero(&self, table_layout: TableLayout) -> (NonNull, Layout) { + if self.is_empty_singleton() { + (NonNull::dangling(), Layout::new::<()>()) + } else { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + unsafe { self.allocation_info(table_layout) } + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[inline] + fn clear_no_drop(&mut self) { + if !self.is_empty_singleton() { + unsafe { + self.ctrl(0).write_bytes(EMPTY, self.num_ctrl_bytes()); + } + } + self.items = 0; + self.growth_left = bucket_mask_to_capacity(self.bucket_mask); + } + + /// Erases the [`Bucket`]'s control byte at the given index so that it does not + /// triggered as full, decreases the `items` of the table and, if it can be done, + /// increases `self.growth_left`. + /// + /// This function does not actually erase / drop the [`Bucket`] itself, i.e. it + /// does not make any changes to the `data` parts of the table. The caller of this + /// function must take care to properly drop the `data`, otherwise calling this + /// function may result in a memory leak. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * It must be the full control byte at the given position; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// Calling this function on a table with no elements is unspecified, but calling subsequent + /// functions is likely to result in [`undefined behavior`] due to overflow subtraction + /// (`self.items -= 1 cause overflow when self.items == 0`). + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn erase(&mut self, index: usize) { + debug_assert!(self.is_bucket_full(index)); + + // This is the same as `index.wrapping_sub(Group::WIDTH) % self.buckets()` because + // the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + // SAFETY: + // - The caller must uphold the safety contract for `erase` method; + // - `index_before` is guaranteed to be in range due to masking with `self.bucket_mask` + let empty_before = Group::load(self.ctrl(index_before)).match_empty(); + let empty_after = Group::load(self.ctrl(index)).match_empty(); + + // Inserting and searching in the map is performed by two key functions: + // + // - The `find_insert_slot` function that looks up the index of any `EMPTY` or `DELETED` + // slot in a group to be able to insert. If it doesn't find an `EMPTY` or `DELETED` + // slot immediately in the first group, it jumps to the next `Group` looking for it, + // and so on until it has gone through all the groups in the control bytes. + // + // - The `find_inner` function that looks for the index of the desired element by looking + // at all the `FULL` bytes in the group. If it did not find the element right away, and + // there is no `EMPTY` byte in the group, then this means that the `find_insert_slot` + // function may have found a suitable slot in the next group. Therefore, `find_inner` + // jumps further, and if it does not find the desired element and again there is no `EMPTY` + // byte, then it jumps further, and so on. The search stops only if `find_inner` function + // finds the desired element or hits an `EMPTY` slot/byte. + // + // Accordingly, this leads to two consequences: + // + // - The map must have `EMPTY` slots (bytes); + // + // - You can't just mark the byte to be erased as `EMPTY`, because otherwise the `find_inner` + // function may stumble upon an `EMPTY` byte before finding the desired element and stop + // searching. + // + // Thus it is necessary to check all bytes after and before the erased element. If we are in + // a contiguous `Group` of `FULL` or `DELETED` bytes (the number of `FULL` or `DELETED` bytes + // before and after is greater than or equal to `Group::WIDTH`), then we must mark our byte as + // `DELETED` in order for the `find_inner` function to go further. On the other hand, if there + // is at least one `EMPTY` slot in the `Group`, then the `find_inner` function will still stumble + // upon an `EMPTY` byte, so we can safely mark our erased byte as `EMPTY` as well. + // + // Finally, since `index_before == (index.wrapping_sub(Group::WIDTH) & self.bucket_mask) == index` + // and given all of the above, tables smaller than the group width (self.buckets() < Group::WIDTH) + // cannot have `DELETED` bytes. + // + // Note that in this context `leading_zeros` refers to the bytes at the end of a group, while + // `trailing_zeros` refers to the bytes at the beginning of a group. + let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { + DELETED + } else { + self.growth_left += 1; + EMPTY + }; + // SAFETY: the caller must uphold the safety contract for `erase` method. + self.set_ctrl(index, ctrl); + self.items -= 1; + } +} + +impl Clone for RawTable { + fn clone(&self) -> Self { + if self.table.is_empty_singleton() { + Self::new_in(self.alloc.clone()) + } else { + unsafe { + // Avoid `Result::ok_or_else` because it bloats LLVM IR. + // + // SAFETY: This is safe as we are taking the size of an already allocated table + // and therefore сapacity overflow cannot occur, `self.table.buckets()` is power + // of two and all allocator errors will be caught inside `RawTableInner::new_uninitialized`. + let mut new_table = match Self::new_uninitialized( + self.alloc.clone(), + self.table.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + + // Cloning elements may fail (the clone function may panic). But we don't + // need to worry about uninitialized control bits, since: + // 1. The number of items (elements) in the table is zero, which means that + // the control bits will not be readed by Drop function. + // 2. The `clone_from_spec` method will first copy all control bits from + // `self` (thus initializing them). But this will not affect the `Drop` + // function, since the `clone_from_spec` function sets `items` only after + // successfully clonning all elements. + new_table.clone_from_spec(self); + new_table + } + } + } + + fn clone_from(&mut self, source: &Self) { + if source.table.is_empty_singleton() { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + unsafe { + // Make sure that if any panics occurs, we clear the table and + // leave it in an empty state. + let mut self_ = guard(self, |self_| { + self_.clear_no_drop(); + }); + + // First, drop all our elements without clearing the control + // bytes. If this panics then the scope guard will clear the + // table, leaking any elements that were not dropped yet. + // + // This leak is unavoidable: we can't try dropping more elements + // since this could lead to another panic and abort the process. + // + // SAFETY: If something gets wrong we clear our table right after + // dropping the elements, so there is no double drop, since `items` + // will be equal to zero. + self_.table.drop_elements::(); + + // If necessary, resize our table to match the source. + if self_.buckets() != source.buckets() { + let new_inner = match RawTableInner::new_uninitialized( + &self_.alloc, + Self::TABLE_LAYOUT, + source.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + // Replace the old inner with new uninitialized one. It's ok, since if something gets + // wrong `ScopeGuard` will initialize all control bytes and leave empty table. + let mut old_inner = mem::replace(&mut self_.table, new_inner); + if !old_inner.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that `alloc` and `table_layout` matches + // the [`Allocator`] and [`TableLayout`] that were used to allocate this table. + old_inner.free_buckets(&self_.alloc, Self::TABLE_LAYOUT); + } + } + + // Cloning elements may fail (the clone function may panic), but the `ScopeGuard` + // inside the `clone_from_impl` function will take care of that, dropping all + // cloned elements if necessary. Our `ScopeGuard` will clear the table. + self_.clone_from_spec(source); + + // Disarm the scope guard if cloning was successful. + ScopeGuard::into_inner(self_); + } + } + } +} + +/// Specialization of `clone_from` for `Copy` types +trait RawTableClone { + unsafe fn clone_from_spec(&mut self, source: &Self); +} +impl RawTableClone for RawTable { + default_fn! { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + self.clone_from_impl(source); + } + } +} +#[cfg(feature = "nightly")] +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + source + .data_start() + .as_ptr() + .copy_to_nonoverlapping(self.data_start().as_ptr(), self.table.buckets()); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl RawTable { + /// Common code for clone and clone_from. Assumes: + /// - `self.buckets() == source.buckets()`. + /// - Any existing elements have been dropped. + /// - The control bytes are not initialized yet. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_impl(&mut self, source: &Self) { + // Copy the control bytes unchanged. We do this in a single pass + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + + // The cloning of elements may panic, in which case we need + // to make sure we drop only the elements that have been + // cloned so far. + let mut guard = guard((0, &mut *self), |(index, self_)| { + if T::NEEDS_DROP { + for i in 0..*index { + if self_.is_bucket_full(i) { + self_.bucket(i).drop(); + } + } + } + }); + + for from in source.iter() { + let index = source.bucket_index(&from); + let to = guard.1.bucket(index); + to.write(from.as_ref().clone()); + + // Update the index in case we need to unwind. + guard.0 = index + 1; + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } + + /// Variant of `clone_from` to use when a hasher is available. + #[cfg(feature = "raw")] + pub fn clone_from_with_hasher(&mut self, source: &Self, hasher: impl Fn(&T) -> u64) { + // If we have enough capacity in the table, just clear it and insert + // elements one by one. We don't do this if we have the same number of + // buckets as the source since we can just copy the contents directly + // in that case. + if self.table.buckets() != source.table.buckets() + && bucket_mask_to_capacity(self.table.bucket_mask) >= source.len() + { + self.clear(); + + let mut guard_self = guard(&mut *self, |self_| { + // Clear the partially copied table if a panic occurs, otherwise + // items and growth_left will be out of sync with the contents + // of the table. + self_.clear(); + }); + + unsafe { + for item in source.iter() { + // This may panic. + let item = item.as_ref().clone(); + let hash = hasher(&item); + + // We can use a simpler version of insert() here since: + // - there are no DELETED entries. + // - we know there is enough space in the table. + // - all elements are unique. + let (index, _) = guard_self.table.prepare_insert_slot(hash); + guard_self.bucket(index).write(item); + } + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard_self); + + self.table.items = source.table.items; + self.table.growth_left -= source.table.items; + } else { + self.clone_from(source); + } + } +} + +impl Default for RawTable { + #[inline] + fn default() -> Self { + Self::new_in(Default::default()) + } +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} + +impl IntoIterator for RawTable { + type Item = T; + type IntoIter = RawIntoIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> RawIntoIter { + unsafe { + let iter = self.iter(); + self.into_iter_from(iter) + } + } +} + +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does +/// not track an item count. +pub(crate) struct RawIterRange { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. + end: *const u8, +} + +impl RawIterRange { + /// Returns a `RawIterRange` covering a subset of a table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * `ctrl` must be [valid] for reads, i.e. table outlives the `RawIterRange`; + /// + /// * `ctrl` must be properly aligned to the group size (Group::WIDTH); + /// + /// * `ctrl` must point to the array of properly initialized control bytes; + /// + /// * `data` must be the [`Bucket`] at the `ctrl` index in the table; + /// + /// * the value of `len` must be less than or equal to the number of table buckets, + /// and the returned value of `ctrl.as_ptr().add(len).offset_from(ctrl.as_ptr())` + /// must be positive. + /// + /// * The `ctrl.add(len)` pointer must be either in bounds or one + /// byte past the end of the same [allocated table]. + /// + /// * The `len` must be a power of two. + /// + /// [valid]: https://doc.rust-lang.org/std/ptr/index.html#safety + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let end = ctrl.add(len); + + // Load the first group and advance ctrl to point to the next group + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let current_group = Group::load_aligned(ctrl).match_full(); + let next_ctrl = ctrl.add(Group::WIDTH); + + Self { + current_group: current_group.into_iter(), + data, + next_ctrl, + end, + } + } + + /// Splits a `RawIterRange` into two halves. + /// + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rayon")] + pub(crate) fn split(mut self) -> (Self, Option>) { + unsafe { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. + (self, None) + } else { + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.next_n(Group::WIDTH).next_n(mid), + len - mid, + ); + debug_assert_eq!( + self.data.next_n(Group::WIDTH).next_n(mid).ptr, + tail.data.ptr + ); + debug_assert_eq!(self.end, tail.end); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); + (self, Some(tail)) + } + } + } + + /// # Safety + /// If DO_CHECK_PTR_RANGE is false, caller must ensure that we never try to iterate + /// after yielding all elements. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn next_impl(&mut self) -> Option> { + loop { + if let Some(index) = self.current_group.next() { + return Some(self.data.next_n(index)); + } + + if DO_CHECK_PTR_RANGE && self.next_ctrl >= self.end { + return None; + } + + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. + /// + /// `fold_impl()` takes three arguments: the number of items remaining in + /// the iterator, an initial value, and a closure with two arguments: an + /// 'accumulator', and an element. The closure returns the value that the + /// accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first call. + /// + /// After applying this closure to every element of the iterator, `fold_impl()` + /// returns the accumulator. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `RawIterRange`; + /// + /// * The provided `n` value must match the actual number of items + /// in the table. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::while_let_on_iterator)] + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn fold_impl(mut self, mut n: usize, mut acc: B, mut f: F) -> B + where + F: FnMut(B, Bucket) -> B, + { + loop { + while let Some(index) = self.current_group.next() { + // The returned `index` will always be in the range `0..Group::WIDTH`, + // so that calling `self.data.next_n(index)` is safe (see detailed explanation below). + debug_assert!(n != 0); + let bucket = self.data.next_n(index); + acc = f(acc, bucket); + n -= 1; + } + + if n == 0 { + return acc; + } + + // SAFETY: The caller of this function ensures that: + // + // 1. The provided `n` value matches the actual number of items in the table; + // 2. The table is alive and did not moved. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.current_group` will read bytes + // from the `self.buckets() - Group::WIDTH` index. We know also that + // `self.current_group.next()` will always retun indices within the range + // `0..Group::WIDTH`. + // + // Knowing all of the above and taking into account that we are synchronizing + // the `self.data` index with the index we used to read the `self.current_group`, + // the subsequent `self.data.next_n(index)` will always return a bucket with + // an index number less than `self.buckets()`. + // + // The last `self.next_ctrl`, whose index would be `self.buckets()`, will never + // actually be read, since we should have already yielded all the elements of + // the table. + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } +} + +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} + +impl Clone for RawIterRange { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + next_ctrl: self.next_ctrl, + current_group: self.current_group, + end: self.end, + } + } +} + +impl Iterator for RawIterRange { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + unsafe { + // SAFETY: We set checker flag to true. + self.next_impl::() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We don't have an item count, so just guess based on the range size. + let remaining_buckets = if self.end > self.next_ctrl { + unsafe { offset_from(self.end, self.next_ctrl) } + } else { + 0 + }; + + // Add a group width to include the group we are currently processing. + (0, Some(Group::WIDTH + remaining_buckets)) + } +} + +impl FusedIterator for RawIterRange {} + +/// Iterator which returns a raw pointer to every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket (unless `reflect_remove` is called). +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator (unless `reflect_insert` is called). +/// - The order in which the iterator yields bucket is unspecified and may +/// change in the future. +pub struct RawIter { + pub(crate) iter: RawIterRange, + items: usize, +} + +impl RawIter { + /// Refresh the iterator so that it reflects a removal from the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each removed bucket before `next` is called again. + /// + /// This method should be called _before_ the removal is made. It is not necessary to call this + /// method if you are removing an item that this iterator yielded in the past. + #[cfg(feature = "raw")] + pub unsafe fn reflect_remove(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, false); + } + + /// Refresh the iterator so that it reflects an insertion into the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each insert before `next` is called again. + /// + /// This method does not guarantee that an insertion of a bucket with a greater + /// index than the last one yielded will be reflected in the iterator. + /// + /// This method should be called _after_ the given insert is made. + #[cfg(feature = "raw")] + pub unsafe fn reflect_insert(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, true); + } + + /// Refresh the iterator so that it reflects a change to the state of the given bucket. + #[cfg(feature = "raw")] + unsafe fn reflect_toggle_full(&mut self, b: &Bucket, is_insert: bool) { + if b.as_ptr() > self.iter.data.as_ptr() { + // The iterator has already passed the bucket's group. + // So the toggle isn't relevant to this iterator. + return; + } + + if self.iter.next_ctrl < self.iter.end + && b.as_ptr() <= self.iter.data.next_n(Group::WIDTH).as_ptr() + { + // The iterator has not yet reached the bucket's group. + // We don't need to reload anything, but we do need to adjust the item count. + + if cfg!(debug_assertions) { + // Double-check that the user isn't lying to us by checking the bucket state. + // To do that, we need to find its control byte. We know that self.iter.data is + // at self.iter.next_ctrl - Group::WIDTH, so we work from there: + let offset = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let ctrl = self.iter.next_ctrl.sub(Group::WIDTH).add(offset); + // This method should be called _before_ a removal, or _after_ an insert, + // so in both cases the ctrl byte should indicate that the bucket is full. + assert!(is_full(*ctrl)); + } + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + return; + } + + // The iterator is at the bucket group that the toggled bucket is in. + // We need to do two things: + // + // - Determine if the iterator already yielded the toggled bucket. + // If it did, we're done. + // - Otherwise, update the iterator cached group so that it won't + // yield a to-be-removed bucket, or _will_ yield a to-be-added bucket. + // We'll also need to update the item count accordingly. + if let Some(index) = self.iter.current_group.0.lowest_set_bit() { + let next_bucket = self.iter.data.next_n(index); + if b.as_ptr() > next_bucket.as_ptr() { + // The toggled bucket is "before" the bucket the iterator would yield next. We + // therefore don't need to do anything --- the iterator has already passed the + // bucket in question. + // + // The item count must already be correct, since a removal or insert "prior" to + // the iterator's position wouldn't affect the item count. + } else { + // The removed bucket is an upcoming bucket. We need to make sure it does _not_ + // get yielded, and also that it's no longer included in the item count. + // + // NOTE: We can't just reload the group here, both since that might reflect + // inserts we've already passed, and because that might inadvertently unset the + // bits for _other_ removals. If we do that, we'd have to also decrement the + // item count for those other bits that we unset. But the presumably subsequent + // call to reflect for those buckets might _also_ decrement the item count. + // Instead, we _just_ flip the bit for the particular bucket the caller asked + // us to reflect. + let our_bit = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let was_full = self.iter.current_group.flip(our_bit); + debug_assert_ne!(was_full, is_insert); + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + if cfg!(debug_assertions) { + if b.as_ptr() == next_bucket.as_ptr() { + // The removed bucket should no longer be next + debug_assert_ne!(self.iter.current_group.0.lowest_set_bit(), Some(index)); + } else { + // We should not have changed what bucket comes next. + debug_assert_eq!(self.iter.current_group.0.lowest_set_bit(), Some(index)); + } + } + } + } else { + // We must have already iterated past the removed item. + } + } + + unsafe fn drop_elements(&mut self) { + if T::NEEDS_DROP && self.items != 0 { + for item in self { + item.drop(); + } + } + } +} + +impl Clone for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + items: self.items, + } + } +} + +impl Iterator for RawIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + // Inner iterator iterates over buckets + // so it can do unnecessary work if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: We check number of items to yield using `items` field. + self.iter.next_impl::() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + unsafe { self.iter.fold_impl(self.items, init, f) } + } +} + +impl ExactSizeIterator for RawIter {} +impl FusedIterator for RawIter {} + +/// Iterator which returns an index of every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding index of that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields indices of the buckets is unspecified +/// and may change in the future. +pub(crate) struct FullBucketsIndices { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Initial value of the bytes' indices of the current group (relative + // to the start of the control bytes). + group_first_index: usize, + + // Pointer to the current group of control bytes, + // Must be aligned to the group size (Group::WIDTH). + ctrl: NonNull, + + // Number of elements in the table. + items: usize, +} + +impl FullBucketsIndices { + /// Advances the iterator and returns the next value. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `FullBucketsIndices`; + /// + /// * It never tries to iterate after getting all elements. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn next_impl(&mut self) -> Option { + loop { + if let Some(index) = self.current_group.next() { + // The returned `self.group_first_index + index` will always + // be in the range `0..self.buckets()`. See explanation below. + return Some(self.group_first_index + index); + } + + // SAFETY: The caller of this function ensures that: + // + // 1. It never tries to iterate after getting all the elements; + // 2. The table is alive and did not moved; + // 3. The first `self.ctrl` pointed to the start of the array of control bytes. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // the start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.ctrl` will be equal to + // the `self.buckets() - Group::WIDTH`, so `self.current_group.next()` + // will always contains indices within the range `0..Group::WIDTH`, + // and subsequent `self.group_first_index + index` will always return a + // number less than `self.buckets()`. + self.ctrl = NonNull::new_unchecked(self.ctrl.as_ptr().add(Group::WIDTH)); + + // SAFETY: See explanation above. + self.current_group = Group::load_aligned(self.ctrl.as_ptr()) + .match_full() + .into_iter(); + self.group_first_index += Group::WIDTH; + } + } +} + +impl Iterator for FullBucketsIndices { + type Item = usize; + + /// Advances the iterator and returns the next value. It is up to + /// the caller to ensure that the `RawTable` outlives the `FullBucketsIndices`, + /// because we cannot make the `next` method unsafe. + #[inline(always)] + fn next(&mut self) -> Option { + // Return if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: + // 1. We check number of items to yield using `items` field. + // 2. The caller ensures that the table is alive and has not moved. + self.next_impl() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for FullBucketsIndices {} +impl FusedIterator for FullBucketsIndices {} + +/// Iterator which consumes a table and returns elements. +pub struct RawIntoIter { + iter: RawIter, + allocation: Option<(NonNull, Layout, A)>, + marker: PhantomData, +} + +impl RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawIntoIter +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawIntoIter +where + T: Sync, + A: Sync, +{ +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} + +impl Iterator for RawIntoIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { Some(self.iter.next()?.read()) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} + +/// Iterator which consumes elements without freeing the table storage. +pub struct RawDrain<'a, T, A: Allocator = Global> { + iter: RawIter, + + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: RawTableInner, + orig_table: NonNull, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. + marker: PhantomData<&'a RawTable>, +} + +impl RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawDrain<'_, T, A> +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawDrain<'_, T, A> +where + T: Sync, + A: Sync, +{ +} + +impl Drop for RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements. Note that this may panic. + self.iter.drop_elements(); + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&self.table, 1); + } + } +} + +impl Iterator for RawDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { + let item = self.iter.next()?; + Some(item.read()) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} + +/// Iterator over occupied buckets that could match a given hash. +/// +/// `RawTable` only stores 7 bits of the hash value, so this iterator may return +/// items that have a hash value different than the one provided. You should +/// always validate the returned values before using them. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields buckets is unspecified and may +/// change in the future. +pub struct RawIterHash { + inner: RawIterHashInner, + _marker: PhantomData, +} + +struct RawIterHashInner { + // See `RawTableInner`'s corresponding fields for details. + // We can't store a `*const RawTableInner` as it would get + // invalidated by the user calling `&mut` methods on `RawTable`. + bucket_mask: usize, + ctrl: NonNull, + + // The top 7 bits of the hash. + h2_hash: u8, + + // The sequence of groups to probe in the search. + probe_seq: ProbeSeq, + + group: Group, + + // The elements within the group with a matching h2-hash. + bitmask: BitMaskIter, +} + +impl RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + unsafe fn new(table: &RawTable, hash: u64) -> Self { + RawIterHash { + inner: RawIterHashInner::new(&table.table, hash), + _marker: PhantomData, + } + } +} +impl RawIterHashInner { + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + unsafe fn new(table: &RawTableInner, hash: u64) -> Self { + let h2_hash = h2(hash); + let probe_seq = table.probe_seq(hash); + let group = Group::load(table.ctrl(probe_seq.pos)); + let bitmask = group.match_byte(h2_hash).into_iter(); + + RawIterHashInner { + bucket_mask: table.bucket_mask, + ctrl: table.ctrl, + h2_hash, + probe_seq, + group, + bitmask, + } + } +} + +impl Iterator for RawIterHash { + type Item = Bucket; + + fn next(&mut self) -> Option> { + unsafe { + match self.inner.next() { + Some(index) => { + // Can't use `RawTable::bucket` here as we don't have + // an actual `RawTable` reference to use. + debug_assert!(index <= self.inner.bucket_mask); + let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index); + Some(bucket) + } + None => None, + } + } + } +} + +impl Iterator for RawIterHashInner { + type Item = usize; + + fn next(&mut self) -> Option { + unsafe { + loop { + if let Some(bit) = self.bitmask.next() { + let index = (self.probe_seq.pos + bit) & self.bucket_mask; + return Some(index); + } + if likely(self.group.match_empty().any_bit_set()) { + return None; + } + self.probe_seq.move_next(self.bucket_mask); + + // Can't use `RawTableInner::ctrl` here as we don't have + // an actual `RawTableInner` reference to use. + let index = self.probe_seq.pos; + debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH); + let group_ctrl = self.ctrl.as_ptr().add(index); + + self.group = Group::load(group_ctrl); + self.bitmask = self.group.match_byte(self.h2_hash).into_iter(); + } + } + } +} + +pub(crate) struct RawExtractIf<'a, T, A: Allocator> { + pub iter: RawIter, + pub table: &'a mut RawTable, +} + +impl RawExtractIf<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn next(&mut self, mut f: F) -> Option + where + F: FnMut(&mut T) -> bool, + { + unsafe { + for item in &mut self.iter { + if f(item.as_mut()) { + return Some(self.table.remove(item).0); + } + } + } + None + } +} + +#[cfg(test)] +mod test_map { + use super::*; + + fn rehash_in_place(table: &mut RawTable, hasher: impl Fn(&T) -> u64) { + unsafe { + table.table.rehash_in_place( + &|table, index| hasher(table.bucket::(index).as_ref()), + mem::size_of::(), + if mem::needs_drop::() { + Some(mem::transmute(ptr::drop_in_place:: as unsafe fn(*mut T))) + } else { + None + }, + ); + } + } + + #[test] + fn rehash() { + let mut table = RawTable::new(); + let hasher = |i: &u64| *i; + for i in 0..100 { + table.insert(i, i, hasher); + } + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + + rehash_in_place(&mut table, hasher); + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + } + + /// CHECKING THAT WE ARE NOT TRYING TO READ THE MEMORY OF + /// AN UNINITIALIZED TABLE DURING THE DROP + #[test] + fn test_drop_uninitialized() { + use ::alloc::vec::Vec; + + let table = unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap() + }; + drop(table); + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_drop_zero_items() { + use ::alloc::vec::Vec; + unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + let table = + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap(); + + // WE SIMULATE, AS IT WERE, A FULL TABLE. + + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `table.table.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + table + .table + .ctrl(0) + .write_bytes(EMPTY, table.table.num_ctrl_bytes()); + + // SAFETY: table.capacity() is guaranteed to be smaller than table.buckets() + table.table.ctrl(0).write_bytes(0, table.capacity()); + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if table.buckets() < Group::WIDTH { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(Group::WIDTH), table.table.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(table.table.buckets()), Group::WIDTH); + } + drop(table); + } + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_catch_panic_clone_from() { + use ::alloc::sync::Arc; + use ::alloc::vec::Vec; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + struct CheckedCloneDrop { + panic_in_clone: bool, + dropped: bool, + need_drop: Vec, + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + dropped: self.dropped, + need_drop: self.need_drop.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + let mut table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + + for (idx, panic_in_clone) in core::iter::repeat(DISARMED).take(7).enumerate() { + let idx = idx as u64; + table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx], + }, + ), + |(k, _)| *k, + ); + } + + assert_eq!(table.len(), 7); + + thread::scope(|s| { + let result = s.spawn(|| { + let armed_flags = [ + DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + let mut scope_table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + for (idx, &panic_in_clone) in armed_flags.iter().enumerate() { + let idx = idx as u64; + scope_table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx + 100], + }, + ), + |(k, _)| *k, + ); + } + table.clone_from(&scope_table); + }); + assert!(result.join().is_err()); + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(table.len(), 0); + assert_eq!(unsafe { table.iter().count() }, 0); + assert_eq!(unsafe { table.iter().iter.count() }, 0); + + for idx in 0..table.buckets() { + let idx = idx as u64; + assert!( + table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/neon.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/neon.rs new file mode 100644 index 00000000000000..44e82d57d54a18 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/neon.rs @@ -0,0 +1,124 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::arch::aarch64 as neon; +use core::mem; +use core::num::NonZeroU64; + +pub(crate) type BitMaskWord = u64; +pub(crate) type NonZeroBitMaskWord = NonZeroU64; +pub(crate) const BITMASK_STRIDE: usize = 8; +pub(crate) const BITMASK_MASK: BitMaskWord = !0; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 64-bit NEON value. +#[derive(Copy, Clone)] +pub(crate) struct Group(neon::uint8x8_t); + +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(neon::vld1_u8(ptr)) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(neon::vld1_u8(ptr)) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + neon::vst1_u8(ptr, self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + unsafe { + let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(byte)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + unsafe { + let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80))) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/raw/sse2.rs b/deps/crates/vendor/hashbrown-0.14.5/src/raw/sse2.rs new file mode 100644 index 00000000000000..956ba5d2654941 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/raw/sse2.rs @@ -0,0 +1,149 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::mem; +use core::num::NonZeroU16; + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as x86; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit SSE value. +#[derive(Copy, Clone)] +pub(crate) struct Group(x86::__m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + #[allow(clippy::items_after_statements)] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(x86::_mm_loadu_si128(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(x86::_mm_load_si128(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + x86::_mm_store_si128(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which have + /// the given value. + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + #[allow( + clippy::cast_possible_wrap, // byte: u8 as i8 + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(byte as i8)); + BitMask(x86::_mm_movemask_epi8(cmp) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + #[allow( + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask(x86::_mm_movemask_epi8(self.0) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[allow( + clippy::cast_possible_wrap, // byte: 0x80_u8 as i8 + )] + unsafe { + let zero = x86::_mm_setzero_si128(); + let special = x86::_mm_cmpgt_epi8(zero, self.0); + Group(x86::_mm_or_si128( + special, + x86::_mm_set1_epi8(0x80_u8 as i8), + )) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/rustc_entry.rs b/deps/crates/vendor/hashbrown-0.14.5/src/rustc_entry.rs new file mode 100644 index 00000000000000..defbd4bb88fb8e --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/rustc_entry.rs @@ -0,0 +1,630 @@ +use self::RustcEntry::*; +use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::raw::{Allocator, Bucket, Global, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + key: Some(key), + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry +pub enum RustcEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V, A>), +} + +impl Debug for RustcEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcOccupiedEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, +} + +unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> +where + K: Send, + V: Send, + A: Allocator + Send, +{ +} +unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> +where + K: Sync, + V: Sync, + A: Allocator + Sync, +{ +} + +impl Debug for RustcOccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcVacantEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + hash: u64, + key: K, + table: &'a mut RawTable<(K, V), A>, +} + +impl Debug for RustcVacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> { + /// Sets the value of the entry, and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.rustc_entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + match self { + Vacant(entry) => entry.insert_entry(value), + Occupied(mut entry) => { + entry.insert(value); + entry + } + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } +} + +impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V { + unsafe { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + &mut bucket.as_mut().1 + } + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) }; + RustcOccupiedEntry { + key: None, + elem: bucket, + table: self.table, + } + } +} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl Drain<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/scopeguard.rs b/deps/crates/vendor/hashbrown-0.14.5/src/scopeguard.rs new file mode 100644 index 00000000000000..382d06043ef601 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/scopeguard.rs @@ -0,0 +1,72 @@ +// Extracted from the scopeguard crate +use core::{ + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr, +}; + +pub struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + pub fn into_inner(guard: Self) -> T { + // Cannot move out of Drop-implementing types, so + // ptr::read the value out of a ManuallyDrop + // Don't use mem::forget as that might invalidate value + let guard = ManuallyDrop::new(guard); + unsafe { + let value = ptr::read(&guard.value); + // read the closure so that it is dropped + let _ = ptr::read(&guard.dropfn); + value + } + } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/set.rs b/deps/crates/vendor/hashbrown-0.14.5/src/set.rs new file mode 100644 index 00000000000000..2125a7ac819d86 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/set.rs @@ -0,0 +1,2970 @@ +#[cfg(feature = "raw")] +use crate::raw::RawTable; +use crate::{Equivalent, TryReserveError}; +use alloc::borrow::ToOwned; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::{BitAnd, BitOr, BitXor, Sub}; + +use super::map::{self, DefaultHashBuilder, HashMap, Keys}; +use crate::raw::{Allocator, Global, RawExtractIf}; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// A hash set implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or +/// unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashSet` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`]. This will in the +/// future be implied by [`Eq`]. +/// +/// ``` +/// use hashbrown::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{:?}", x); +/// } +/// ``` +/// +/// A `HashSet` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashSet; +/// +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].into_iter().collect(); +/// // use the values stored in the set +/// ``` +/// +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +pub struct HashSet { + pub(crate) map: HashMap, +} + +impl Clone for HashSet { + fn clone(&self) -> Self { + HashSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher`](HashSet::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher`](HashSet::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity), + } + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher_in`](HashSet::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + map: HashMap::new_in(alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher_in`](HashSet::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_in(capacity, alloc), + } + } +} + +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + iter: self.map.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.into_iter().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(|k, _| f(k)); + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashSet::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.map.table.iter() }, + table: &mut self.map.table, + }, + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.map.clear(); + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } +} + +impl HashSet +where + A: Allocator, +{ + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.map.allocator() + } + + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher_in(hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_hasher_in(hasher, alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_and_hasher_in(capacity, hasher, alloc), + } + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = set.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + self.map.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashSet::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S, A> { + Difference { + iter: self.iter(), + other, + } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S, A> { + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Intersection { + iter: smaller.iter(), + other: larger, + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S, A> { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Union { + iter: larger.iter().chain(smaller.difference(larger)), + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains(&self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.get_key_value(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(&value) + .or_insert(value, ()) + .0 + } + + /// Inserts an owned copy of the given `value` into the set if it is not + /// present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_owned(pet); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + pub fn get_or_insert_owned(&mut self, value: &Q) -> &T + where + Q: Hash + Equivalent + ToOwned, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (value.to_owned(), ())) + .0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + Q: Hash + Equivalent, + F: FnOnce(&Q) -> T, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (f(value), ())) + .0 + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { + match self.map.entry(value) { + map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), + map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), + } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + pub fn is_disjoint(&self, other: &Self) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + pub fn is_subset(&self, other: &Self) -> bool { + self.len() <= other.len() && self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert a value the set without checking if the value already exists in the set. + /// + /// Returns a reference to the value just inserted. + /// + /// This operation is safe if a value does not exist in the set. + /// + /// However, if a value exists in the set already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the set + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the set. + /// For example, when constructing a set from another set, we know + /// that values are unique. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_unique_unchecked(&mut self, value: T) -> &T { + self.map.insert_unique_unchecked(value, ()).0 + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(&mut self, value: T) -> Option { + match self.map.entry(value) { + map::Entry::Occupied(occupied) => Some(occupied.replace_key()), + map::Entry::Vacant(vacant) => { + vacant.insert(()); + None + } + } + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.remove_entry(value) { + Some((k, _)) => Some(k), + None => None, + } + } +} + +impl HashSet { + /// Returns a reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(T, ()), A> { + self.map.raw_table() + } + + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table_mut(&mut self) -> &mut RawTable<(T, ()), A> { + self.map.raw_table_mut() + } +} + +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for HashSet +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl From> for HashSet +where + A: Allocator, +{ + fn from(map: HashMap) -> Self { + Self { map } + } +} + +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher_in(Default::default(), Default::default()); + set.extend(iter); + set + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "ahash")] +impl From<[T; N]> for HashSet +where + T: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set1 = HashSet::from([1, 2, 3, 4]); + /// let set2: HashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + arr.into_iter().collect() + } +} + +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.map.extend(iter.into_iter().map(|k| (k, ()))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: T) { + self.map.insert(k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().copied()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: &'a T) { + self.map.insert(*k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl Default for HashSet +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter +pub struct Iter<'a, K> { + iter: Keys<'a, K, ()>, +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter +pub struct IntoIter { + iter: map::IntoIter, +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain +pub struct Drain<'a, K, A: Allocator = Global> { + iter: map::Drain<'a, K, (), A>, +} + +/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashSet.html#method.extract_if +/// [`HashSet`]: struct.HashSet.html +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, F, A: Allocator = Global> +where + F: FnMut(&K) -> bool, +{ + f: F, + inner: RawExtractIf<'a, (K, ()), A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection +pub struct Intersection<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference +pub struct Difference<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference +pub struct SymmetricDifference<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union +pub struct Union<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +impl Clone for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} +impl<'a, K> ExactSizeIterator for Iter<'a, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Iter<'_, K> {} + +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Iterator for IntoIter { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for Drain<'_, K, A> { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for Drain<'_, K, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Drain<'_, K, A> {} + +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for ExtractIf<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner + .next(|&mut (ref k, ())| (self.f)(k)) + .map(|(k, ())| k) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} + +impl Clone for Intersection<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + f(acc, elt) + } else { + acc + } + }) + } +} + +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl Clone for Difference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + acc + } else { + f(acc, elt) + } + }) + } +} + +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for SymmetricDifference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for Union<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_, _> = set.entry("a"); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +pub enum Entry<'a, T, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<_> = ["a", "b"].into(); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S, A>), +} + +impl fmt::Debug for Entry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o: OccupiedEntry<_, _> = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, T, S, A: Allocator = Global> { + inner: map::OccupiedEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, VacantEntry}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v: VacantEntry<_, _> = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +pub struct VacantEntry<'a, T, S, A: Allocator = Global> { + inner: map::VacantEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for VacantEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> T { + self.inner.remove_entry().0 + } + + /// Replaces the entry, returning the old value. The new value in the hash map will be + /// the value used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// use std::rc::Rc; + /// + /// let mut set: HashSet> = HashSet::new(); + /// let key_one = Rc::new("Stringthing".to_string()); + /// let key_two = Rc::new("Stringthing".to_string()); + /// + /// set.insert(key_one.clone()); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match set.entry(key_two.clone()) { + /// Entry::Occupied(entry) => { + /// let old_key: Rc = entry.replace(); + /// assert!(Rc::ptr_eq(&key_one, &old_key)); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// assert!(set.contains(&"Stringthing".to_owned())); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(self) -> T { + self.inner.replace_key() + } +} + +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_value(self) -> T { + self.inner.into_key() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) + where + T: Hash, + S: BuildHasher, + { + self.inner.insert(()); + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { + inner: self.inner.insert_entry(()), + } + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new, A: Allocator>(v: IntoIter<&'static str, A>) -> IntoIter<&'new str, A> { + v + } + fn difference<'a, 'new, A: Allocator>( + v: Difference<'a, &'static str, DefaultHashBuilder, A>, + ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn symmetric_difference<'a, 'new, A: Allocator>( + v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, + ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn intersection<'a, 'new, A: Allocator>( + v: Intersection<'a, &'static str, DefaultHashBuilder, A>, + ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn union<'a, 'new, A: Allocator>( + v: Union<'a, &'static str, DefaultHashBuilder, A>, + ) -> Union<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn drain<'new, A: Allocator>(d: Drain<'static, &'static str, A>) -> Drain<'new, &'new str, A> { + d + } +} + +#[cfg(test)] +mod test_set { + use super::super::map::DefaultHashBuilder; + use super::HashSet; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); + } + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_map() { + let mut a = crate::HashMap::new(); + a.insert(1, ()); + a.insert(2, ()); + a.insert(3, ()); + a.insert(4, ()); + + let a: HashSet<_> = a.into(); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().copied().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{set:?}"); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + if !s.is_empty() { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } + } + + #[test] + fn test_replace() { + use core::hash; + + #[derive(Debug)] + #[allow(dead_code)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend([2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } + + #[test] + fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().copied().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } + + #[test] + fn test_extract_if() { + { + let mut set: HashSet = (0..8).collect(); + let drained = set.extract_if(|&k| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![0, 2, 4, 6], out); + assert_eq!(set.len(), 4); + } + { + let mut set: HashSet = (0..8).collect(); + set.extract_if(|&k| k % 2 == 0).for_each(drop); + assert_eq!(set.len(), 4, "Removes non-matching items on drop"); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET; + set.insert(19); + assert!(set.contains(&19)); + } + + #[test] + fn rehash_in_place() { + let mut set = HashSet::new(); + + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/src/table.rs b/deps/crates/vendor/hashbrown-0.14.5/src/table.rs new file mode 100644 index 00000000000000..faf8a6330f67f4 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/src/table.rs @@ -0,0 +1,2070 @@ +use core::{fmt, iter::FusedIterator, marker::PhantomData}; + +use crate::{ + raw::{ + Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter, + RawTable, + }, + TryReserveError, +}; + +/// Low-level hash table with explicit hashing. +/// +/// The primary use case for this type over [`HashMap`] or [`HashSet`] is to +/// support types that do not implement the [`Hash`] and [`Eq`] traits, but +/// instead require additional data not contained in the key itself to compute a +/// hash and compare two elements for equality. +/// +/// Examples of when this can be useful include: +/// - An `IndexMap` implementation where indices into a `Vec` are stored as +/// elements in a `HashTable`. Hashing and comparing the elements +/// requires indexing the associated `Vec` to get the actual value referred to +/// by the index. +/// - Avoiding re-computing a hash when it is already known. +/// - Mutating the key of an element in a way that doesn't affect its hash. +/// +/// To achieve this, `HashTable` methods that search for an element in the table +/// require a hash value and equality function to be explicitly passed in as +/// arguments. The method will then iterate over the elements with the given +/// hash and call the equality function on each of them, until a match is found. +/// +/// In most cases, a `HashTable` will not be exposed directly in an API. It will +/// instead be wrapped in a helper type which handles the work of calculating +/// hash values and comparing elements. +/// +/// Due to its low-level nature, this type provides fewer guarantees than +/// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot +/// yourself in the foot by having multiple elements with identical keys in the +/// table. The table itself will still function correctly and lookups will +/// arbitrarily return one of the matching elements. However you should avoid +/// doing this because it changes the runtime of hash table operations from +/// `O(1)` to `O(k)` where `k` is the number of duplicate entries. +/// +/// [`HashMap`]: super::HashMap +/// [`HashSet`]: super::HashSet +pub struct HashTable +where + A: Allocator, +{ + pub(crate) raw: RawTable, +} + +impl HashTable { + /// Creates an empty `HashTable`. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::new(); + /// assert_eq!(table.len(), 0); + /// assert_eq!(table.capacity(), 0); + /// ``` + pub const fn new() -> Self { + Self { + raw: RawTable::new(), + } + } + + /// Creates an empty `HashTable` with the specified capacity. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::with_capacity(10); + /// assert_eq!(table.len(), 0); + /// assert!(table.capacity() >= 10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +impl HashTable +where + A: Allocator, +{ + /// Creates an empty `HashTable` using the given allocator. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::new_in(&bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// + /// // The created HashTable also doesn't allocate memory + /// assert_eq!(table.capacity(), 0); + /// + /// // Now we insert element inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// // We can see that the HashTable holds 1 element + /// assert_eq!(table.len(), 1); + /// // And it also allocates some capacity + /// assert!(table.capacity() > 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub const fn new_in(alloc: A) -> Self { + Self { + raw: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashTable` with the specified capacity using the given allocator. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::with_capacity_in(5, &bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = table.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// table.insert_unique(hasher(&"Two"), "Two", hasher); + /// table.insert_unique(hasher(&"Three"), "Three", hasher); + /// table.insert_unique(hasher(&"Four"), "Four", hasher); + /// table.insert_unique(hasher(&"Five"), "Five", hasher); + /// + /// // We can see that the HashTable holds 5 elements + /// assert_eq!(table.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(table.capacity(), empty_map_capacity) + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + raw: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the underlying allocator. + pub fn allocator(&self) -> &A { + self.raw.allocator() + } + + /// Returns a reference to an entry in the table with the given hash and + /// which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); + /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + self.raw.get(hash, eq) + } + + /// Returns a mutable reference to an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// When mutating an entry, you should ensure that it still retains the same + /// hash value as when it was inserted, otherwise lookups of that entry may + /// fail to find it. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { + /// val.1 = "b"; + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + self.raw.get_mut(hash, eq) + } + + /// Returns an `OccupiedEntry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table. Call + /// [`HashTable::entry`] instead if you wish to insert an entry if the + /// lookup fails. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { + /// entry.remove(); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.find(hash, eq) { + Some(bucket) => Ok(OccupiedEntry { + hash, + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns an `Entry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table, or insert a new + /// entry with the given hash if one doesn't already exist. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// This method may grow the table in preparation for an insertion. Call + /// [`HashTable::find_entry`] if this is undesirable. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) + /// { + /// entry.remove(); + /// } + /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { + /// entry.insert((2, "b")); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Entry<'_, T, A> { + match self.raw.find_or_find_insert_slot(hash, eq, hasher) { + Ok(bucket) => Entry::Occupied(OccupiedEntry { + hash, + bucket, + table: self, + }), + Err(insert_slot) => Entry::Vacant(VacantEntry { + hash, + insert_slot, + table: self, + }), + } + } + + /// Inserts an element into the `HashTable` with the given hash value, but + /// without checking whether an equivalent element already exists within the + /// table. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert_unique( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> OccupiedEntry<'_, T, A> { + let bucket = self.raw.insert(hash, value, hasher); + OccupiedEntry { + hash, + bucket, + table: self, + } + } + + /// Clears the table, removing all values. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// v.clear(); + /// assert!(v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn clear(&mut self) { + self.raw.clear(); + } + + /// Shrinks the capacity of the table as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to_fit(hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(self.len(), hasher) + } + + /// Shrinks the capacity of the table with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to(10, hasher); + /// assert!(table.capacity() >= 10); + /// table.shrink_to(0, hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(min_capacity, hasher); + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.reserve(10, hasher); + /// assert!(table.capacity() >= 10); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + self.raw.reserve(additional, hasher) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table + /// .try_reserve(10, hasher) + /// .expect("why is the test harness OOMing on 10 bytes?"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + self.raw.try_reserve(additional, hasher) + } + + /// Returns the number of elements the table can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let table: HashTable = HashTable::with_capacity(100); + /// assert!(table.capacity() >= 100); + /// ``` + pub fn capacity(&self) -> usize { + self.raw.capacity() + } + + /// Returns the number of elements in the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert_eq!(v.len(), 0); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert_eq!(v.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert!(v.is_empty()); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert!(!v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for x in table.iter() { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with mutable references to the elements. + /// The iterator element type is `&'a mut T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// + /// // Update all values + /// for val in table.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [2, 4, 6]); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=6 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// table.retain(|&mut x| x % 2 == 0); + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.raw.iter() { + if !f(item.as_mut()) { + self.raw.erase(item); + } + } + } + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=3 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// assert!(!table.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in table.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + inner: self.raw.drain(), + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashTable::retain + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 0..8 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// let drained: Vec = table.extract_if(|&mut v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = table.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.raw.iter() }, + table: &mut self.raw, + }, + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashTable::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_unchecked_mut(hashes, eq) + } +} + +impl IntoIterator for HashTable +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.raw.into_iter(), + } + } +} + +impl<'a, T, A> IntoIterator for &'a HashTable +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, A> IntoIterator for &'a mut HashTable +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl Default for HashTable +where + A: Allocator + Default, +{ + fn default() -> Self { + Self { + raw: Default::default(), + } + } +} + +impl Clone for HashTable +where + T: Clone, + A: Allocator + Clone, +{ + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + +impl fmt::Debug for HashTable +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +/// A view into a single entry in a table, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashTable`]. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`entry`]: struct.HashTable.html#method.entry +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); +/// assert_eq!(table.len(), 3); +/// // Nonexistent value (insert) +/// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); +/// +/// // Existing value (or_insert) +/// table +/// .entry(hasher(&"b"), |&x| x == "b", hasher) +/// .or_insert("b"); +/// // Nonexistent value (or_insert) +/// table +/// .entry(hasher(&"e"), |&x| x == "e", hasher) +/// .or_insert("e"); +/// +/// println!("Our HashTable: {:?}", table); +/// +/// let mut vec: Vec<_> = table.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub enum Entry<'a, T, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in ["a", "b"] { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => {} + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::<&str>::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => {} + /// Entry::Occupied(_) => unreachable!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Vacant(VacantEntry<'a, T, A>), +} + +impl fmt::Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +impl<'a, T, A> Entry<'a, T, A> +where + A: Allocator, +{ + /// Sets the value of the entry, replacing any existing value if there is + /// one, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// let entry = table + /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) + /// .insert("horseyland"); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(mut entry) => { + *entry.get_mut() = value; + entry + } + Entry::Vacant(entry) => entry.insert(value), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // nonexistent key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// + /// // existing key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// assert_eq!(table.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty.. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) + /// .or_insert_with(|| "poneyland".to_string()); + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |x| x == "poneyland") + /// .is_some()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 42)) + /// ); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 43)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +/// A view into an occupied entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); +/// assert_eq!(table.len(), 3); +/// +/// // Existing key +/// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(table.len(), 3); +/// +/// // Existing key (take) +/// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove().0, "c"); +/// } +/// } +/// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); +/// assert_eq!(table.len(), 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct OccupiedEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + bucket: Bucket, + table: &'a mut HashTable, +} + +unsafe impl Send for OccupiedEntry<'_, T, A> +where + T: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, T, A> +where + T: Sync, + A: Sync + Allocator, +{ +} + +impl fmt::Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +impl<'a, T, A> OccupiedEntry<'a, T, A> +where + A: Allocator, +{ + /// Takes the value out of the entry, and returns it along with a + /// `VacantEntry` that can be used to insert another value with the same + /// hash as the one that was just removed. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// // The table is empty + /// assert!(table.is_empty() && table.capacity() == 0); + /// + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// let capacity_before_remove = table.capacity(); + /// + /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// assert_eq!(o.remove().0, "poneyland"); + /// } + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_none()); + /// // Now table hold none elements but capacity is equal to the old one + /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> (T, VacantEntry<'a, T, A>) { + let (val, slot) = unsafe { self.table.raw.remove(self.bucket) }; + ( + val, + VacantEntry { + hash: self.hash, + insert_slot: slot, + table: self.table, + }, + ) + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// + /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get(&self) -> &T { + unsafe { self.bucket.as_ref() } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// if let Entry::Occupied(mut o) = table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// o.get_mut().1 += 10; + /// assert_eq!(o.get().1, 22); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().1 += 2; + /// } + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 24)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the table itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// let value: &mut (&str, u32); + /// match table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// value.1 += 10; + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 22)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn into_mut(self) -> &'a mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// A view into a vacant entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, VacantEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert("a"); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct VacantEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + insert_slot: InsertSlot, + table: &'a mut HashTable, +} + +impl fmt::Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("VacantEntry") + } +} + +impl<'a, T, A> VacantEntry<'a, T, A> +where + A: Allocator, +{ + /// Inserts a new element into the table with the hash that was used to + /// obtain the `VacantEntry`. + /// + /// An `OccupiedEntry` is returned for the newly inserted element. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// o.insert("poneyland"); + /// } + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), + /// Some(&"poneyland") + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + let bucket = unsafe { + self.table + .raw + .insert_in_slot(self.hash, self.insert_slot, value) + }; + OccupiedEntry { + hash: self.hash, + bucket, + table: self.table, + } + } + + /// Converts the VacantEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`]. +/// +/// This type only exists due to [limitations] in Rust's NLL borrow checker. In +/// the future, `find_entry` will return an `Option` and this +/// type will be removed. +/// +/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{AbsentEntry, Entry, HashTable}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); +/// entry_v +/// .into_table() +/// .insert_unique(hasher(&"a"), "a", hasher); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct AbsentEntry<'a, T, A = Global> +where + A: Allocator, +{ + table: &'a mut HashTable, +} + +impl fmt::Debug for AbsentEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("AbsentEntry") + } +} + +impl<'a, T, A> AbsentEntry<'a, T, A> +where + A: Allocator, +{ + /// Converts the AbsentEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// An iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashTable.html#method.iter +/// [`HashTable`]: struct.HashTable.html +pub struct Iter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +/// A mutable iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashTable.html#method.iter_mut +/// [`HashTable`]: struct.HashTable.html +pub struct IterMut<'a, T> { + inner: RawIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl ExactSizeIterator for IterMut<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterMut<'_, T> {} + +/// An owning iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `T`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashTable`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The table cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashTable.html#method.into_iter +/// [`HashTable`]: struct.HashTable.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +pub struct IntoIter +where + A: Allocator, +{ + inner: RawIntoIter, +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for IntoIter +where + A: Allocator, +{ + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoIter where A: Allocator {} + +/// A draining iterator over the items of a `HashTable`. +/// +/// This `struct` is created by the [`drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`drain`]: struct.HashTable.html#method.drain +pub struct Drain<'a, T, A: Allocator = Global> { + inner: RawDrain<'a, T, A>, +} + +impl Drain<'_, T, A> { + /// Returns a iterator of references over the remaining items. + fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Drain<'_, T, A> { + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, T, A> {} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by [`HashTable::extract_if`]. See its +/// documentation for more. +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, T, F, A: Allocator = Global> +where + F: FnMut(&mut T) -> bool, +{ + f: F, + inner: RawExtractIf<'a, T, A>, +} + +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next(|val| (self.f)(val)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/equivalent_trait.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/equivalent_trait.rs new file mode 100644 index 00000000000000..713dddd53c7c6a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use hashbrown::Equivalent; +use hashbrown::HashMap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let mut map = HashMap::new(); + map.insert((s("a"), s("b")), 1); + map.insert((s("a"), s("x")), 2); + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = HashMap::new(); + map.insert(s("a"), 1); + map.insert(s("b"), 2); + map.insert(s("x"), 3); + map.insert(s("y"), 4); + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.remove("b"), Some(2)); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/hasher.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/hasher.rs new file mode 100644 index 00000000000000..e455e3d3c9a844 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/hasher.rs @@ -0,0 +1,65 @@ +//! Sanity check that alternate hashers work correctly. + +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use std::hash::{BuildHasher, BuildHasherDefault, Hasher}; + +fn check() { + let range = 0..1_000; + + let mut set = HashSet::::default(); + set.extend(range.clone()); + + assert!(!set.contains(&i32::min_value())); + assert!(!set.contains(&(range.start - 1))); + for i in range.clone() { + assert!(set.contains(&i)); + } + assert!(!set.contains(&range.end)); + assert!(!set.contains(&i32::max_value())); +} + +/// Use hashbrown's default hasher. +#[test] +fn default() { + check::(); +} + +/// Use std's default hasher. +#[test] +fn random_state() { + check::(); +} + +/// Use a constant 0 hash. +#[test] +fn zero() { + #[derive(Default)] + struct ZeroHasher; + + impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} + +/// Use a constant maximum hash. +#[test] +fn max() { + #[derive(Default)] + struct MaxHasher; + + impl Hasher for MaxHasher { + fn finish(&self) -> u64 { + u64::max_value() + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/raw.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/raw.rs new file mode 100644 index 00000000000000..858836e63be442 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/raw.rs @@ -0,0 +1,11 @@ +#![cfg(feature = "raw")] + +use hashbrown::raw::RawTable; +use std::mem; + +#[test] +fn test_allocation_info() { + assert_eq!(RawTable::<()>::new().allocation_info().1.size(), 0); + assert_eq!(RawTable::::new().allocation_info().1.size(), 0); + assert!(RawTable::::with_capacity(1).allocation_info().1.size() > mem::size_of::()); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/rayon.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/rayon.rs new file mode 100644 index 00000000000000..d55e5a9804dd2a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/rayon.rs @@ -0,0 +1,535 @@ +#![cfg(feature = "rayon")] + +#[macro_use] +extern crate lazy_static; + +use hashbrown::{HashMap, HashSet}; +use rayon::iter::{ + IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend, + ParallelIterator, +}; + +macro_rules! assert_eq3 { + ($e1:expr, $e2:expr, $e3:expr) => {{ + assert_eq!($e1, $e2); + assert_eq!($e1, $e3); + assert_eq!($e2, $e3); + }}; +} + +lazy_static! { + static ref MAP_EMPTY: HashMap = HashMap::new(); + static ref MAP: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m.insert('c', 30); + m.insert('e', 50); + m.insert('f', 60); + m.insert('d', 40); + m + }; +} + +#[test] +fn map_seq_par_equivalence_iter_empty() { + let vec_seq = MAP_EMPTY.iter().collect::>(); + let vec_par = MAP_EMPTY.par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter() { + let mut vec_seq = MAP.iter().collect::>(); + let mut vec_par = MAP.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &10), + (&'b', &20), + (&'c', &30), + (&'d', &40), + (&'e', &50), + (&'f', &60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_keys_empty() { + let vec_seq = MAP_EMPTY.keys().collect::>(); + let vec_par = MAP_EMPTY.par_keys().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_keys() { + let mut vec_seq = MAP.keys().collect::>(); + let mut vec_par = MAP.par_keys().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_empty() { + let vec_seq = MAP_EMPTY.values().collect::>(); + let vec_par = MAP_EMPTY.par_values().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values() { + let mut vec_seq = MAP.values().collect::>(); + let mut vec_par = MAP.par_values().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&10, &20, &30, &40, &50, &60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_iter_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.iter_mut().collect::>(); + let vec_par = map2.par_iter_mut().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.iter_mut().collect::>(); + let mut vec_par = map2.par_iter_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &mut 10), + (&'b', &mut 20), + (&'c', &mut 30), + (&'d', &mut 40), + (&'e', &mut 50), + (&'f', &mut 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.values_mut().collect::>(); + let vec_par = map2.par_values_mut().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.values_mut().collect::>(); + let mut vec_par = map2.par_values_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_into_iter_empty() { + let vec_seq = MAP_EMPTY.clone().into_iter().collect::>(); + let vec_par = MAP_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_into_iter() { + let mut vec_seq = MAP.clone().into_iter().collect::>(); + let mut vec_par = MAP.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + ('a', 10), + ('b', 20), + ('c', 30), + ('d', 40), + ('e', 50), + ('f', 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref MAP_VEC_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_VEC: Vec<(char, u32)> = vec![ + ('b', 20), + ('a', 10), + ('c', 30), + ('e', 50), + ('f', 60), + ('d', 40), + ]; +} + +#[test] +fn map_seq_par_equivalence_collect_empty() { + let map_expected = MAP_EMPTY.clone(); + let map_seq = MAP_VEC_EMPTY.clone().into_iter().collect::>(); + let map_par = MAP_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +#[test] +fn map_seq_par_equivalence_collect() { + let map_expected = MAP.clone(); + let map_seq = MAP_VEC.clone().into_iter().collect::>(); + let map_par = MAP_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +lazy_static! { + static ref MAP_EXISTING_EMPTY: HashMap = HashMap::new(); + static ref MAP_EXISTING: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m + }; + static ref MAP_EXTENSION_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_EXTENSION: Vec<(char, u32)> = vec![('c', 30), ('e', 50), ('f', 60), ('d', 40),]; +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashMap::new(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend() { + let expected = MAP_EXTENSION.iter().copied().collect::>(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend_empty() { + let expected = MAP_EXISTING.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend() { + let expected = MAP.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +lazy_static! { + static ref SET_EMPTY: HashSet = HashSet::new(); + static ref SET: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s.insert('c'); + s.insert('e'); + s.insert('f'); + s.insert('d'); + s + }; +} + +#[test] +fn set_seq_par_equivalence_iter_empty() { + let vec_seq = SET_EMPTY.iter().collect::>(); + let vec_par = SET_EMPTY.par_iter().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn set_seq_par_equivalence_iter() { + let mut vec_seq = SET.iter().collect::>(); + let mut vec_par = SET.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn set_seq_par_equivalence_into_iter_empty() { + let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); + let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); + + // Work around type inference failure introduced by rend dev-dependency. + let empty: [char; 0] = []; + assert_eq3!(vec_seq, vec_par, empty); +} + +#[test] +fn set_seq_par_equivalence_into_iter() { + let mut vec_seq = SET.clone().into_iter().collect::>(); + let mut vec_par = SET.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref SET_VEC_EMPTY: Vec = vec![]; + static ref SET_VEC: Vec = vec!['b', 'a', 'c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_collect_empty() { + let set_expected = SET_EMPTY.clone(); + let set_seq = SET_VEC_EMPTY.clone().into_iter().collect::>(); + let set_par = SET_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +#[test] +fn set_seq_par_equivalence_collect() { + let set_expected = SET.clone(); + let set_seq = SET_VEC.clone().into_iter().collect::>(); + let set_par = SET_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +lazy_static! { + static ref SET_EXISTING_EMPTY: HashSet = HashSet::new(); + static ref SET_EXISTING: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s + }; + static ref SET_EXTENSION_EMPTY: Vec = vec![]; + static ref SET_EXTENSION: Vec = vec!['c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashSet::new(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend() { + let expected = SET_EXTENSION.iter().copied().collect::>(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend_empty() { + let expected = SET_EXISTING.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend() { + let expected = SET.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +lazy_static! { + static ref SET_A: HashSet = ['a', 'b', 'c', 'd'].iter().copied().collect(); + static ref SET_B: HashSet = ['a', 'b', 'e', 'f'].iter().copied().collect(); + static ref SET_DIFF_AB: HashSet = ['c', 'd'].iter().copied().collect(); + static ref SET_DIFF_BA: HashSet = ['e', 'f'].iter().copied().collect(); + static ref SET_SYMM_DIFF_AB: HashSet = ['c', 'd', 'e', 'f'].iter().copied().collect(); + static ref SET_INTERSECTION_AB: HashSet = ['a', 'b'].iter().copied().collect(); + static ref SET_UNION_AB: HashSet = + ['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect(); +} + +#[test] +fn set_seq_par_equivalence_difference() { + let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::>(); + let diff_ab_par = SET_A + .par_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB); + + let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::>(); + let diff_ba_par = SET_B + .par_difference(&*SET_A) + .copied() + .collect::>(); + + assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA); +} + +#[test] +fn set_seq_par_equivalence_symmetric_difference() { + let symm_diff_ab_seq = SET_A + .symmetric_difference(&*SET_B) + .copied() + .collect::>(); + let symm_diff_ab_par = SET_A + .par_symmetric_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB); +} + +#[test] +fn set_seq_par_equivalence_intersection() { + let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::>(); + let intersection_ab_par = SET_A + .par_intersection(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!( + intersection_ab_seq, + intersection_ab_par, + *SET_INTERSECTION_AB + ); +} + +#[test] +fn set_seq_par_equivalence_union() { + let union_ab_seq = SET_A.union(&*SET_B).copied().collect::>(); + let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::>(); + + assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/serde.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/serde.rs new file mode 100644 index 00000000000000..a642348b3b3b23 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/serde.rs @@ -0,0 +1,65 @@ +#![cfg(feature = "serde")] + +use core::hash::BuildHasherDefault; +use fnv::FnvHasher; +use hashbrown::{HashMap, HashSet}; +use serde_test::{assert_tokens, Token}; + +// We use FnvHash for this test because we rely on the ordering +type FnvHashMap = HashMap>; +type FnvHashSet = HashSet>; + +#[test] +fn map_serde_tokens_empty() { + let map = FnvHashMap::::default(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens() { + let mut map = FnvHashMap::default(); + map.insert('b', 20); + map.insert('a', 10); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('c'), + Token::I32(30), + Token::Char('b'), + Token::I32(20), + Token::MapEnd, + ], + ); +} + +#[test] +fn set_serde_tokens_empty() { + let set = FnvHashSet::::default(); + + assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); +} + +#[test] +fn set_serde_tokens() { + let mut set = FnvHashSet::default(); + set.insert(20); + set.insert(10); + set.insert(30); + + assert_tokens( + &set, + &[ + Token::Seq { len: Some(3) }, + Token::I32(30), + Token::I32(20), + Token::I32(10), + Token::SeqEnd, + ], + ); +} diff --git a/deps/crates/vendor/hashbrown-0.14.5/tests/set.rs b/deps/crates/vendor/hashbrown-0.14.5/tests/set.rs new file mode 100644 index 00000000000000..86ec9647664bf5 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.14.5/tests/set.rs @@ -0,0 +1,34 @@ +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng}; +use std::iter; + +#[test] +fn test_hashset_insert_remove() { + let mut m: HashSet> = HashSet::new(); + let seed = u64::from_le_bytes(*b"testseed"); + + let rng = &mut SmallRng::seed_from_u64(seed); + let tx: Vec> = iter::repeat_with(|| { + rng.sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect() + }) + .take(4096) + .collect(); + + // more readable with explicit `true` / `false` + #[allow(clippy::bool_assert_comparison)] + for _ in 0..32 { + for x in &tx { + assert_eq!(m.contains(x), false); + assert_eq!(m.insert(x.clone()), true); + } + for (i, x) in tx.iter().enumerate() { + println!("removing {i} {x:?}"); + assert_eq!(m.remove(x), true); + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/.cargo-checksum.json b/deps/crates/vendor/hashbrown-0.15.5/.cargo-checksum.json new file mode 100644 index 00000000000000..88908a45f3f36c --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"69f3640939af23a14ac672aea0bb01e5c91ff62a2caff3fd29214bc57168d882","CHANGELOG.md":"ed7f31b98a975fee4392dc5de7bbedbabc00dcd5c3c60ade87a83b836401ba6f","Cargo.lock":"196f9d29807a2eba97e03e5816ce3579e2ee444d7a8787e2e4c93156e0e68792","Cargo.toml":"32bc47a47ae4759fd559ca2cbb43a597f679ff4ebcfa67c850794cc4cd52aea5","Cargo.toml.orig":"734e730bbb3eb5446b8c8ea6f2e904faecdb9603bcbbf7e5b503e0603367ce33","Cross.toml":"47aeebdfd782a5052346ce29bf750c225828e108aca723486c3839adba5d6901","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"34a16e7bc599e9d4ec600b477176a4a1328e6fb1f3f8d1525fb54f398553daef","benches/bench.rs":"c323748bcf76d54cdaa152ec79dd2581f9d6b2c950f93e799ba38a28800e1fc9","benches/insert_unique_unchecked.rs":"dfe644035cad6ff13b280e3d72c9df2569491ecddc84f7c2502daf940814a63e","benches/set_ops.rs":"936cd15055c25d42aabc6bde738e3135da541520b40633c4fba940eb73e06f4d","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/control/bitmask.rs":"53dcdac056620f02c475b618d33e69f34152ea559d86bd4545546144f017baa0","src/control/group/generic.rs":"939b2e35e6ea5430a606a054ffc8ea3e22b867d83f2afed15525cf59a617eb6e","src/control/group/lsx.rs":"8a8783e466dbf995106e4fa3202d15fe99b0ac0f485ee7c699c3ba3bf346d1dd","src/control/group/mod.rs":"03d5cacaf762fcb0c9878e9f56355c7c9d0935d688d01c5e0d12aa673e16795d","src/control/group/neon.rs":"bde7726d321bd036cb9001818f962784346b932087b9f655c85ab26667d55fbb","src/control/group/sse2.rs":"833da90ab3fd72d306d5b999de96a4b6b52aa1a16ee7273c89bd12c9ead3bc45","src/control/mod.rs":"83fede19e9c5a26fd2c7372e6cf92547d32ade4cd69fde8a0eaaeb1be6ddc2ba","src/control/tag.rs":"9c94ab42aad3918bd77ffafdeb253f7f773a8f98bf56e36b85ebdc7a11ef676b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"e1e08653c6c3d2f0586638ab7baf082c06fdc5551b5852b0f9e73aa9484b4955","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"04012fb2e99648819b4bc0044107ed3cb94013e242b7865075c5bd9ebf1b6865","src/external_trait_impls/rayon/set.rs":"7539348ff7bc6e3cce6b3c019d62dc401eea0138c578fef729c2593e8ead1cfa","src/external_trait_impls/rayon/table.rs":"aebd92261f44aef2e4c13a80a566e0308655396a3cc6f973d330d2f5ba26fc45","src/external_trait_impls/serde.rs":"f83dae5dd2243c0a1b278f9f040023e98c0e2744c78ad0243a7bb5d877a8e8ee","src/lib.rs":"a4ba7b15d4cfc524432877f3ad27e323d67f15706bb113052f77ff541718c0a6","src/macros.rs":"98a26b908fc0fbe6a58d008a317e550013d615eb3cc17a5054a573c62c1d74cb","src/map.rs":"7ad82c1a141b824be1201ea0014623b2433d32080f528ef3958e65d04ddb7688","src/raw/alloc.rs":"10474e218b922b0a32227578c09acd5b05c32ad223c4dbf0af3cbd7869c000f2","src/raw/mod.rs":"a88cd291be71cd2f6119a1f8b4030a0429b6b1f8771b7f2a8b140c1824788bed","src/raw_entry.rs":"41f54fabf968b6ba19a6fbb41372f7e86e1ccd221622591816fe48bcc3797369","src/rustc_entry.rs":"9c189a957af1ec5ff3549d15176c1608ca1c68330604a50b2ea19316a5dd14e2","src/scopeguard.rs":"1a246e08a63c06cd8ad934bd7da229421bf804f991ae93cd7e242da27ca6c601","src/set.rs":"cd7d05424d731f0ad5eb4cf255e9a4d970b96fb68398cc904481af942a106fb4","src/table.rs":"285620edfe390d0ea77983ae471943f145ea414caa81926010ef0de4647ef13e","src/util.rs":"c929f855589653727016bd8577db7ca234e7e0820f1f2dc0cfe49f13f5056168","tests/equivalent_trait.rs":"84faa3fe9d67c375d03fec81f0f1412c47862477d42e84e7d235258236338d5b","tests/hasher.rs":"fd06130f011660743202904221f3f7487d8d143d8903c73cd3a76d079ebbe9fb","tests/rayon.rs":"39cb24ab45fce8087bb54948715c8b6973ebfba1a325292b5b3cd9aab50b5fd2","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"fd9ffc6f8a435f2fbcada826c33599d682d9f688f0f8dbb14fcd1e442d4c2647"},"package":"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown-0.15.5/.cargo_vcs_info.json b/deps/crates/vendor/hashbrown-0.15.5/.cargo_vcs_info.json new file mode 100644 index 00000000000000..94e46c904338bc --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "b751eef8e99ccf3652046ef4a9e1ec47c1bfb78d" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown-0.15.5/CHANGELOG.md b/deps/crates/vendor/hashbrown-0.15.5/CHANGELOG.md new file mode 100644 index 00000000000000..fd38a96591462c --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/CHANGELOG.md @@ -0,0 +1,619 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.15.5](https://github.com/rust-lang/hashbrown/compare/v0.15.4...v0.15.5) - 2025-08-07 + +### Added + +- Added `Entry::or_default_entry` and `Entry::or_insert_entry`. + +### Changed + +- Re-implemented likely/unlikely with `#[cold]` + +## [0.15.4](https://github.com/rust-lang/hashbrown/compare/v0.15.3...v0.15.4) - 2025-06-05 + +### Changed + +- Removed optional dependency on compiler-builtins. This only affects building as part of `std`. + +## [0.15.3](https://github.com/rust-lang/hashbrown/compare/v0.15.2...v0.15.3) - 2025-04-29 + +### Added + +- SIMD implementation for LoongArch (#592, requires nightly) + +### Changed + +- Optimized insertion path by avoiding an unnecessary `match_empty` (#607) +- Increased minimum table size for small types (#615) +- Dropped FnMut trait bounds from `ExtractIf` data structures (#616) +- Relaxed constraint in `hash_map::EntryRef` insertion methods `K: From<&Q>` to &Q: `Into` (#611) +- Added allocator template argument for `rustc_iter` (#605) +- The `allocator-api2/nightly` feature is no longer enabled by `hashbrown/nightly` (#606) + +## [v0.15.2] - 2024-11-14 + +### Added + +- Marked `const fn` constructors as `rustc_const_stable_indirect` when built as + part of the standard library. (#586) + +## [v0.15.1] - 2024-11-03 + +This release removes the `borsh` feature introduced in 0.15.0 because it was +found to be incorrectly implemented. Users should use the `hashbrown` feature of +the `borsh` crate instead which provides the same trait implementations. + +## ~~[v0.15.0] - 2024-10-01~~ + +This release was _yanked_ due to a broken implementation of the `borsh` feature. + +This update contains breaking changes that remove the `raw` API with the hope of +centralising on the `HashTable` API in the future. You can follow the discussion +and progress in #545 to discuss features you think should be added to this API +that were previously only possible on the `raw` API. + +### Added + +- Added `borsh` feature with `BorshSerialize` and `BorshDeserialize` impls. (#525) +- Added `Assign` impls for `HashSet` operators. (#529) +- Added `Default` impls for iterator types. (#542) +- Added `HashTable::iter_hash{,_mut}` methods. (#549) +- Added `Hash{Table,Map,Set}::allocation_size` methods. (#553) +- Implemented `Debug` and `FusedIterator` for all `HashTable` iterators. (#561) +- Specialized `Iterator::fold` for all `HashTable` iterators. (#561) + +### Changed + +- Changed `hash_set::VacantEntry::insert` to return `OccupiedEntry`. (#495) +- Improved`hash_set::Difference::size_hint` lower-bound. (#530) +- Improved `HashSet::is_disjoint` performance. (#531) +- `equivalent` feature is now enabled by default. (#532) +- `HashSet` operators now return a set with the same allocator. (#529) +- Changed the default hasher to foldhash. (#563) +- `ahash` feature has been renamed to `default-hasher`. (#533) +- Entry API has been reworked and several methods have been renamed. (#535) +- `Hash{Map,Set}::insert_unique_unchecked` is now unsafe. (#556) +- The signature of `get_many_mut` and related methods was changed. (#562) + +### Fixed + +* Fixed typos, stray backticks in docs. (#558, #560) + +### Removed + +- Raw entry API is now under `raw-entry` feature, to be eventually removed. (#534, #555) +- Raw table API has been made private and the `raw` feature is removed; + in the future, all code should be using the `HashTable` API instead. (#531, #546) +- `rykv` feature was removed; this is now provided by the `rykv` crate instead. (#554) +- `HashSet::get_or_insert_owned` was removed in favor of `get_or_insert_with`. (#555) + +## [v0.14.5] - 2024-04-28 + +### Fixed + +- Fixed index calculation in panic guard of `clone_from_impl`. (#511) + +## ~~[v0.14.4] - 2024-03-19~~ + +This release was _yanked_ due to a breaking change. + +## [v0.14.3] - 2023-11-26 + +### Added + +- Specialized `fold` implementation of iterators. (#480) + +### Fixed + +- Avoid using unstable `ptr::invalid_mut` on nightly. (#481) + +## [v0.14.2] - 2023-10-19 + +### Added + +- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466) + +### Fixed + +- Disabled the use of NEON instructions on big-endian ARM. (#475) +- Disabled the use of NEON instructions on Miri. (#476) + +## [v0.14.1] - 2023-09-28 + +### Added + +- Allow serializing `HashMap`s that use a custom allocator. (#449) + +### Changed + +- Use the `Equivalent` trait from the `equivalent` crate. (#442) +- Slightly improved performance of table resizing. (#451) +- Relaxed MSRV to 1.63.0. (#457) +- Removed `Clone` requirement from custom allocators. (#468) + +### Fixed + +- Fixed custom allocators being leaked in some situations. (#439, #465) + +## [v0.14.0] - 2023-06-01 + +### Added + +- Support for `allocator-api2` crate + for interfacing with custom allocators on stable. (#417) +- Optimized implementation for ARM using NEON instructions. (#430) +- Support for rkyv serialization. (#432) +- `Equivalent` trait to look up values without `Borrow`. (#345) +- `Hash{Map,Set}::raw_table_mut` is added which returns a mutable reference. (#404) +- Fast path for `clear` on empty tables. (#428) + +### Changed + +- Optimized insertion to only perform a single lookup. (#277) +- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining + elements when the iterator is dropped. #(374) +- Bumped MSRV to 1.64.0. (#431) +- `{Map,Set}::raw_table` now returns an immutable reference. (#404) +- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is + specified in generics. (#389) +- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387) +- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429) +- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429) +- `RawTable::remove` now also returns an `InsertSlot`. (#429) +- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429) +- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427) +- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423) +- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with` + were changed to give a `&K` instead of a `&Q` to the closure. + +### Removed + +- Support for `bumpalo` as an allocator with custom wrapper. + Use `allocator-api2` feature in `bumpalo` to use it as an allocator + for `hashbrown` collections. (#417) + +## [v0.13.2] - 2023-01-12 + +### Fixed + +- Added `#[inline(always)]` to `find_inner`. (#375) +- Fixed `RawTable::allocation_info` for empty tables. (#376) + +## [v0.13.1] - 2022-11-10 + +### Added + +- Added `Equivalent` trait to customize key lookups. (#350) +- Added support for 16-bit targets. (#368) +- Added `RawTable::allocation_info` which provides information about the memory + usage of a table. (#371) + +### Changed + +- Bumped MSRV to 1.61.0. +- Upgraded to `ahash` 0.8. (#357) +- Make `with_hasher_in` const. (#355) +- The following methods have been removed from the `RawTable` API in favor of + safer alternatives: + - `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead. + - `Bucket::read` => Use `RawTable::remove` instead. + - `Bucket::drop` => Use `RawTable::erase` instead. + - `Bucket::write` => Use `Bucket::as_mut` instead. + +### Fixed + +- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362) +- Fixed issue with field retagging in scopeguard. (#359) + +## [v0.12.3] - 2022-07-17 + +### Fixed + +- Fixed double-drop in `RawTable::clone_from`. (#348) + +## [v0.12.2] - 2022-07-09 + +### Added + +- Added `Entry` API for `HashSet`. (#342) +- Added `Extend<&'a (K, V)> for HashMap`. (#340) +- Added length-based short-circuiting for hash table iteration. (#338) +- Added a function to access the `RawTable` of a `HashMap`. (#335) + +### Changed + +- Edited `do_alloc` to reduce LLVM IR generated. (#341) + +## [v0.12.1] - 2022-05-02 + +### Fixed + +- Fixed underflow in `RawIterRange::size_hint`. (#325) +- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325) + +## [v0.12.0] - 2022-01-17 + +### Added + +- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297) +- Added an `allocator()` getter to HashMap and HashSet. (#257) +- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293) +- Added `into_keys` and `into_values` to HashMap. (#295) +- Implement `From` on `HashSet` and `HashMap`. (#298) +- Added `entry_ref` API to `HashMap`. (#201) + +### Changed + +- Bumped minimum Rust version to 1.56.1 and edition to 2021. +- Use u64 for the GroupWord on WebAssembly. (#271) +- Optimized `find`. (#279) +- Made rehashing and resizing less generic to reduce compilation time. (#282) +- Inlined small functions. (#283) +- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292) +- Relaxed the bounds on `Debug` for `HashSet`. (#296) +- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291) +- Don't hash the key when searching in an empty table. (#305) + +### Fixed + +- Guard against allocations exceeding isize::MAX. (#268) +- Made `RawTable::insert_no_grow` unsafe. (#254) +- Inline `static_empty`. (#280) +- Fixed trait bounds on Send/Sync impls. (#303) + +## [v0.11.2] - 2021-03-25 + +### Fixed + +- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) + +## [v0.11.1] - 2021-03-20 + +### Fixed + +- Added missing `pub` modifier to `BumpWrapper`. (#251) + +## [v0.11.0] - 2021-03-14 + +### Added +- Added safe `try_insert_no_grow` method to `RawTable`. (#229) +- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) +- Implemented `Default` for `RawTable`. (#237) +- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and + `HashMap::get_each_key_value_mut`. (#239) +- Added `From>` for `HashSet`. (#235) +- Added `try_insert` method to `HashMap`. (#247) + +### Changed +- The minimum Rust version has been bumped to 1.49.0. (#230) +- Significantly improved compilation times by reducing the amount of generated IR. (#205) + +### Removed +- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) +- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) + +### Fixed +- Fixed union length comparison. (#228) + +## ~~[v0.10.0] - 2021-01-16~~ + +This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) + +### Changed +- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) +- Improved branch prediction hints on stable. (#209) +- Optimized hashing of primitive types with AHash using specialization. (#207) +- Only instantiate `RawTable`'s reserve functions once per key-value. (#204) + +## [v0.9.1] - 2020-09-28 + +### Added +- Added safe methods to `RawTable` (#202): + - `get`: `find` and `as_ref` + - `get_mut`: `find` and `as_mut` + - `insert_entry`: `insert` and `as_mut` + - `remove_entry`: `find` and `remove` + - `erase_entry`: `find` and `erase` + +### Changed +- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) +- Made `RawTable::drain` safe. (#201) + +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + +## [v0.8.2] - 2020-08-08 + +### Changed +- Avoid closures to improve compile times. (#183) +- Do not iterate to drop if empty. (#182) + +## [v0.8.1] - 2020-07-16 + +### Added +- Added `erase` and `remove` to `RawTable`. (#171) +- Added `try_with_capacity` to `RawTable`. (#174) +- Added methods that allow re-using a `RawIter` for `RawDrain`, + `RawIntoIter`, and `RawParIter`. (#175) +- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175) +- Added a `drain_filter` function to `HashSet`. (#179) + +### Changed +- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176) +- `insert_no_grow` is now exposed under the `"raw"` feature. (#180) + +## [v0.8.0] - 2020-06-18 + +### Fixed +- Marked `RawTable::par_iter` as `unsafe`. (#157) + +### Changed +- Reduced the size of `HashMap`. (#159) +- No longer create tables with a capacity of 1 element. (#162) +- Removed `K: Eq + Hash` bounds on `retain`. (#163) +- Pulled in `HashMap` changes from rust-lang/rust (#164): + - `extend_one` support on nightly. + - `CollectionAllocErr` renamed to `TryReserveError`. + - Added `HashSet::get_or_insert_owned`. + - `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`. + +## [v0.7.2] - 2020-04-27 + +### Added +- Added `or_insert_with_key` to `Entry`. (#152) + +### Fixed +- Partially reverted `Clone` optimization which was unsound. (#154) + +### Changed +- Disabled use of `const-random` by default, which prevented reproducible builds. (#155) +- Optimized `repeat` function. (#150) +- Use `NonNull` for buckets, which improves codegen for iterators. (#148) + +## [v0.7.1] - 2020-03-16 + +### Added +- Added `HashMap::get_key_value_mut`. (#145) + +### Changed +- Optimized `Clone` implementation. (#146) + +## [v0.7.0] - 2020-01-31 + +### Added +- Added a `drain_filter` function to `HashMap`. (#135) + +### Changed +- Updated `ahash` dependency to 0.3. (#141) +- Optimized set union and intersection. (#130) +- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123) +- `RawTable::bucket_index` can now be used under the `raw` feature. (#128) + +## [v0.6.3] - 2019-10-31 + +### Added +- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the + `compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125) + +## [v0.6.2] - 2019-10-23 + +### Added +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between + runtime performance and compilation time. (#119) + +## [v0.6.1] - 2019-10-04 + +### Added +- Added `Entry::insert` and `RawEntryMut::insert`. (#118) + +### Changed +- `Group::static_empty` was changed from a `const` to a `static` (#116). + +## [v0.6.0] - 2019-08-13 + +### Fixed +- Fixed AHash accidentally depending on `std`. (#110) + +### Changed +- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency). + +## ~~[v0.5.1] - 2019-08-04~~ + +This release was _yanked_ due to a breaking change for users of `no-default-features`. + +### Added +- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108) +- Added entry-like methods for `HashSet`. (#98) + +### Changed +- Changed the default hasher from FxHash to AHash. (#97) +- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96) + +### Fixed +- We now avoid growing the table during insertions when it wasn't necessary. (#106) +- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100) +- Relaxed `lazy_static` version. (#92) + +## [v0.5.0] - 2019-06-12 + +### Fixed +- Resize with a more conservative amount of space after deletions. (#86) + +### Changed +- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89) + +## [v0.4.0] - 2019-05-30 + +### Fixed +- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82) + +## [v0.3.1] - 2019-05-30 + +### Fixed +- Fixed incorrect use of slice in unsafe code. (#80) + +## [v0.3.0] - 2019-04-23 + +### Changed +- Changed shrink_to to not panic if min_capacity < capacity. (#67) + +### Fixed +- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66) + +## [v0.2.2] - 2019-04-16 + +### Fixed +- Inlined non-nightly lowest_set_bit_nonzero. (#64) +- Fixed build on latest nightly. (#65) + +## [v0.2.1] - 2019-04-14 + +### Changed +- Use for_each in map Extend and FromIterator. (#58) +- Improved worst-case performance of HashSet.is_subset. (#61) + +### Fixed +- Removed incorrect debug_assert. (#60) + +## [v0.2.0] - 2019-03-31 + +### Changed +- The code has been updated to Rust 2018 edition. This means that the minimum + Rust version has been bumped to 1.31 (2018 edition). + +### Added +- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54) +- Added support for using hashbrown as the hash table implementation in libstd. (#46) + +### Fixed +- Fixed cargo build with minimal-versions. (#45) +- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46) +- ZST keys and values are now handled properly. (#46) + +## [v0.1.8] - 2019-01-14 + +### Added +- Rayon parallel iterator support (#37) +- `raw_entry` support (#31) +- `#[may_dangle]` on nightly (#31) +- `try_reserve` support (#31) + +### Fixed +- Fixed variance on `IterMut`. (#31) + +## [v0.1.7] - 2018-12-05 + +### Fixed +- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32) +- Fixed overflow in rehash_in_place. (#33) + +## [v0.1.6] - 2018-11-17 + +### Fixed +- Fixed compile error on nightly. (#29) + +## [v0.1.5] - 2018-11-08 + +### Fixed +- Fixed subtraction overflow in generic::Group::match_byte. (#28) + +## [v0.1.4] - 2018-11-04 + +### Fixed +- Fixed a bug in the `erase_no_drop` implementation. (#26) + +## [v0.1.3] - 2018-11-01 + +### Added +- Serde support. (#14) + +### Fixed +- Make the compiler inline functions more aggressively. (#20) + +## [v0.1.2] - 2018-10-31 + +### Fixed +- `clear` segfaults when called on an empty table. (#13) + +## [v0.1.1] - 2018-10-30 + +### Fixed +- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3) +- Missing `Send` and `Sync` for hash map and iterator types. (#7) +- Bug when inserting into a table smaller than the group width. (#5) + +## v0.1.0 - 2018-10-29 + +- Initial release + +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.15.2...HEAD +[v0.15.2]: https://github.com/rust-lang/hashbrown/compare/v0.15.1...v0.15.2 +[v0.15.1]: https://github.com/rust-lang/hashbrown/compare/v0.15.0...v0.15.1 +[v0.15.0]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...v0.15.0 +[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5 +[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4 +[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3 +[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2 +[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0 +[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2 +[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1 +[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3 +[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2 +[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1 +[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0 +[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2 +[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1 +[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 +[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 +[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 +[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 +[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0 +[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0 +[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0 +[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0 +[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8 +[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7 +[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1 diff --git a/deps/crates/vendor/hashbrown-0.15.5/Cargo.lock b/deps/crates/vendor/hashbrown-0.15.5/Cargo.lock new file mode 100644 index 00000000000000..c573fcca63a193 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/Cargo.lock @@ -0,0 +1,306 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +dependencies = [ + "allocator-api2", + "bumpalo", + "doc-comment", + "equivalent", + "fnv", + "foldhash", + "lazy_static", + "rand", + "rayon", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "serde", + "serde_test", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_test" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml b/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml new file mode 100644 index 00000000000000..cc4b1af72031c3 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml @@ -0,0 +1,164 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65.0" +name = "hashbrown" +version = "0.15.5" +authors = ["Amanieu d'Antras "] +build = false +exclude = [ + ".github", + "/ci/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A Rust port of Google's SwissTable hash map" +readme = "README.md" +keywords = [ + "hash", + "no_std", + "hashmap", + "swisstable", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" + +[package.metadata.docs.rs] +features = [ + "nightly", + "rayon", + "serde", + "raw-entry", +] +rustdoc-args = ["--generate-link-to-definition"] + +[features] +default = [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry", +] +default-hasher = ["dep:foldhash"] +inline-more = [] +nightly = ["bumpalo/allocator_api"] +raw-entry = [] +rustc-dep-of-std = [ + "nightly", + "core", + "alloc", + "rustc-internal-api", +] +rustc-internal-api = [] + +[lib] +name = "hashbrown" +path = "src/lib.rs" + +[[test]] +name = "equivalent_trait" +path = "tests/equivalent_trait.rs" + +[[test]] +name = "hasher" +path = "tests/hasher.rs" + +[[test]] +name = "rayon" +path = "tests/rayon.rs" + +[[test]] +name = "serde" +path = "tests/serde.rs" + +[[test]] +name = "set" +path = "tests/set.rs" + +[[bench]] +name = "bench" +path = "benches/bench.rs" + +[[bench]] +name = "insert_unique_unchecked" +path = "benches/insert_unique_unchecked.rs" + +[[bench]] +name = "set_ops" +path = "benches/set_ops.rs" + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.allocator-api2] +version = "0.2.9" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.equivalent] +version = "1.0" +optional = true +default-features = false + +[dependencies.foldhash] +version = "0.1.2" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.2" +optional = true + +[dependencies.serde] +version = "1.0.25" +optional = true +default-features = false + +[dev-dependencies.bumpalo] +version = "3.13.0" +features = ["allocator-api2"] + +[dev-dependencies.doc-comment] +version = "0.3.1" + +[dev-dependencies.fnv] +version = "1.0.7" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.rand] +version = "0.9.0" +features = ["small_rng"] + +[dev-dependencies.rayon] +version = "1.2" + +[dev-dependencies.serde_test] +version = "1.0" diff --git a/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml.orig b/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml.orig new file mode 100644 index 00000000000000..4d870fa410f318 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/Cargo.toml.orig @@ -0,0 +1,77 @@ +[package] +name = "hashbrown" +version = "0.15.5" +authors = ["Amanieu d'Antras "] +description = "A Rust port of Google's SwissTable hash map" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +exclude = [".github", "/ci/*"] +edition = "2021" +rust-version = "1.65.0" + +[dependencies] +# For the default hasher +foldhash = { version = "0.1.2", default-features = false, optional = true } + +# For external trait impls +rayon = { version = "1.2", optional = true } +serde = { version = "1.0.25", default-features = false, optional = true } + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +# Support for allocators that use allocator-api2 +allocator-api2 = { version = "0.2.9", optional = true, default-features = false, features = [ + "alloc", +] } + +# Equivalent trait which can be shared with other hash table implementations. +equivalent = { version = "1.0", optional = true, default-features = false } + +[dev-dependencies] +lazy_static = "1.4" +rand = { version = "0.9.0", features = ["small_rng"] } +rayon = "1.2" +fnv = "1.0.7" +serde_test = "1.0" +doc-comment = "0.3.1" +bumpalo = { version = "3.13.0", features = ["allocator-api2"] } + +[features] +default = ["default-hasher", "inline-more", "allocator-api2", "equivalent", "raw-entry"] + +# Enables use of nightly features. This is only guaranteed to work on the latest +# version of nightly Rust. +nightly = ["bumpalo/allocator_api"] + +# Enables the RustcEntry API used to provide the standard library's Entry API. +rustc-internal-api = [] + +# Internal feature used when building as part of the standard library. +rustc-dep-of-std = [ + "nightly", + "core", + "alloc", + "rustc-internal-api", +] + +# Enables the deprecated RawEntry API. +raw-entry = [] + +# Provides a default hasher. Currently this is foldhash but this is subject to +# change in the future. Note that the default hasher does *not* provide HashDoS +# resistance, unlike the one in the standard library. +default-hasher = ["dep:foldhash"] + +# Enables usage of `#[inline]` on far more functions than by default in this +# crate. This may lead to a performance increase but often comes at a compile +# time cost. +inline-more = [] + +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw-entry"] +rustdoc-args = ["--generate-link-to-definition"] diff --git a/deps/crates/vendor/hashbrown-0.15.5/Cross.toml b/deps/crates/vendor/hashbrown-0.15.5/Cross.toml new file mode 100644 index 00000000000000..de635703246761 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/Cross.toml @@ -0,0 +1,3 @@ +# FIXME: Drop this config when cross is updated to support loongarch64-linux-gnu +[target.loongarch64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/loongarch64-unknown-linux-gnu:edge" diff --git a/deps/crates/vendor/hashbrown-0.15.5/LICENSE-APACHE b/deps/crates/vendor/hashbrown-0.15.5/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/hashbrown-0.15.5/LICENSE-MIT b/deps/crates/vendor/hashbrown-0.15.5/LICENSE-MIT new file mode 100644 index 00000000000000..5afc2a7b0acabd --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/hashbrown-0.15.5/README.md b/deps/crates/vendor/hashbrown-0.15.5/README.md new file mode 100644 index 00000000000000..83a53811599715 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/README.md @@ -0,0 +1,80 @@ +hashbrown +========= + +[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions) +[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) +[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.65.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) + +This crate is a Rust port of Google's high-performance [SwissTable] hash +map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +and `HashSet` types. + +The original C++ version of SwissTable can be found [here], and this +[CppCon talk] gives an overview of how the algorithm works. + +Since Rust 1.36, this is now the `HashMap` implementation for the Rust standard +library. However you may still want to use this crate instead since it works +in environments without `std`, such as embedded systems and kernels. + +[SwissTable]: https://abseil.io/blog/20180927-swisstables +[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +## [Change log](CHANGELOG.md) + +## Features + +- Drop-in replacement for the standard library `HashMap` and `HashSet` types. +- Uses [foldhash](https://github.com/orlp/foldhash) as the default hasher, which is much faster than SipHash. + However, foldhash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Around 2x faster than the previous standard library `HashMap`. +- Lower memory usage: only 1 byte of overhead per entry instead of 8. +- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). +- Empty hash maps do not allocate any memory. +- SIMD lookups to scan multiple hash entries in parallel. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hashbrown = "0.15" +``` + +Then: + +```rust +use hashbrown::HashMap; + +let mut map = HashMap::new(); +map.insert(1, "one"); +``` +## Flags +This crate has the following Cargo features: + +- `nightly`: Enables nightly-only features including: `#[may_dangle]`. +- `serde`: Enables serde serialization support. +- `rayon`: Enables rayon parallel iterator support. +- `equivalent`: Allows comparisons to be customized with the `Equivalent` trait. (enabled by default) +- `raw-entry`: Enables access to the deprecated `RawEntry` API. +- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost + of compilation time. (enabled by default) +- `default-hasher`: Compiles with foldhash as default hasher. (enabled by default) +- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) + +## License + +Licensed under either of: + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/deps/crates/vendor/hashbrown-0.15.5/benches/bench.rs b/deps/crates/vendor/hashbrown-0.15.5/benches/bench.rs new file mode 100644 index 00000000000000..111c5d54f711e6 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/benches/bench.rs @@ -0,0 +1,329 @@ +// This benchmark suite contains some benchmarks along a set of dimensions: +// Hasher: std default (SipHash) and crate default (foldhash). +// Int key distribution: low bit heavy, top bit heavy, and random. +// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter +#![feature(test)] + +extern crate test; + +use test::{black_box, Bencher}; + +use hashbrown::DefaultHashBuilder; +use hashbrown::{HashMap, HashSet}; +use std::{ + collections::hash_map::RandomState, + sync::atomic::{self, AtomicUsize}, +}; + +const SIZE: usize = 1000; + +// The default hashmap when using this crate directly. +type FoldHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; + +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + state: usize, +} + +impl RandomKeys { + fn new() -> Self { + RandomKeys { state: 0 } + } +} + +impl Iterator for RandomKeys { + type Item = usize; + fn next(&mut self) -> Option { + // Add 1 then multiply by some 32 bit prime. + self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781); + Some(self.state) + } +} + +// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path +// when dropping maps/entries (most real world usages likely have drop in the key or value) +static SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0); + +#[derive(Clone)] +struct DropType(usize); +impl Drop for DropType { + fn drop(&mut self) { + SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst); + } +} + +macro_rules! bench_suite { + ($bench_macro:ident, $bench_foldhash_serial:ident, $bench_std_serial:ident, + $bench_foldhash_highbits:ident, $bench_std_highbits:ident, + $bench_foldhash_random:ident, $bench_std_random:ident) => { + $bench_macro!($bench_foldhash_serial, FoldHashMap, 0..); + $bench_macro!($bench_std_serial, StdHashMap, 0..); + $bench_macro!( + $bench_foldhash_highbits, + FoldHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!( + $bench_std_highbits, + StdHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!($bench_foldhash_random, FoldHashMap, RandomKeys::new()); + $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default()); + b.iter(|| { + m.clear(); + for i in ($keydist).take(SIZE) { + m.insert(i, (DropType(i), [i; 20])); + } + black_box(&mut m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert, + insert_foldhash_serial, + insert_std_serial, + insert_foldhash_highbits, + insert_std_highbits, + insert_foldhash_random, + insert_std_random +); + +macro_rules! bench_grow_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + black_box(&mut m); + }) + } + }; +} + +bench_suite!( + bench_grow_insert, + grow_insert_foldhash_serial, + grow_insert_std_serial, + grow_insert_foldhash_highbits, + grow_insert_std_highbits, + grow_insert_foldhash_random, + grow_insert_std_random +); + +macro_rules! bench_insert_erase { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut base = $maptype::default(); + for i in ($keydist).take(SIZE) { + base.insert(i, DropType(i)); + } + let skip = $keydist.skip(SIZE); + b.iter(|| { + let mut m = base.clone(); + let mut add_iter = skip.clone(); + let mut remove_iter = $keydist; + // While keeping the size constant, + // replace the first keydist with the second. + for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) { + m.insert(add, DropType(add)); + black_box(m.remove(&remove)); + } + black_box(m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert_erase, + insert_erase_foldhash_serial, + insert_erase_std_serial, + insert_erase_foldhash_highbits, + insert_erase_std_highbits, + insert_erase_foldhash_random, + insert_erase_std_random +); + +macro_rules! bench_lookup { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist.take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in $keydist.take(SIZE) { + black_box(m.get(&i)); + } + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_lookup, + lookup_foldhash_serial, + lookup_std_serial, + lookup_foldhash_highbits, + lookup_std_highbits, + lookup_foldhash_random, + lookup_std_random +); + +macro_rules! bench_lookup_fail { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(SIZE) { + black_box(m.get(&i)); + } + }) + } + }; +} + +bench_suite!( + bench_lookup_fail, + lookup_fail_foldhash_serial, + lookup_fail_std_serial, + lookup_fail_foldhash_highbits, + lookup_fail_std_highbits, + lookup_fail_foldhash_random, + lookup_fail_std_random +); + +macro_rules! bench_iter { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }) + } + }; +} + +bench_suite!( + bench_iter, + iter_foldhash_serial, + iter_std_serial, + iter_foldhash_highbits, + iter_std_highbits, + iter_foldhash_random, + iter_std_random +); + +#[bench] +fn clone_small(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_small(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn clone_large(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_large(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn rehash_in_place(b: &mut Bencher) { + b.iter(|| { + let mut set = HashSet::new(); + + // Each loop triggers one rehash + for _ in 0..10 { + for i in 0..223 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + set.clear(); + } + }); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/benches/insert_unique_unchecked.rs b/deps/crates/vendor/hashbrown-0.15.5/benches/insert_unique_unchecked.rs new file mode 100644 index 00000000000000..cfd69cdb7d013a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/benches/insert_unique_unchecked.rs @@ -0,0 +1,34 @@ +//! Compare `insert` and `insert_unique_unchecked` operations performance. + +#![feature(test)] + +extern crate test; + +use hashbrown::HashMap; +use test::Bencher; + +#[bench] +fn insert(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + m.insert(k, k); + } + m + }); +} + +#[bench] +fn insert_unique_unchecked(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + unsafe { + m.insert_unique_unchecked(k, k); + } + } + m + }); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/benches/set_ops.rs b/deps/crates/vendor/hashbrown-0.15.5/benches/set_ops.rs new file mode 100644 index 00000000000000..3b2ab5f28c29c0 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/benches/set_ops.rs @@ -0,0 +1,148 @@ +//! This file contains benchmarks for the ops traits implemented by HashSet. +//! Each test is intended to have a defined larger and smaller set, +//! but using a larger size for the "small" set works just as well. +//! +//! Each assigning test is done in the configuration that is faster. Cheating, I know. +//! The exception to this is Sub, because there the result differs. So I made two benchmarks for Sub. + +#![feature(test)] + +extern crate test; + +use hashbrown::HashSet; +use test::Bencher; + +/// The number of items to generate for the larger of the sets. +const LARGE_SET_SIZE: usize = 1000; + +/// The number of items to generate for the smaller of the sets. +const SMALL_SET_SIZE: usize = 100; + +/// The number of keys present in both sets. +const OVERLAP: usize = + [LARGE_SET_SIZE, SMALL_SET_SIZE][(LARGE_SET_SIZE < SMALL_SET_SIZE) as usize] / 2; + +/// Creates a set containing end - start unique string elements. +fn create_set(start: usize, end: usize) -> HashSet { + (start..end).map(|nr| format!("key{}", nr)).collect() +} + +#[bench] +fn set_ops_bit_or(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| &large_set | &small_set) +} + +#[bench] +fn set_ops_bit_and(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| &large_set & &small_set) +} + +#[bench] +fn set_ops_bit_xor(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| &large_set ^ &small_set) +} + +#[bench] +fn set_ops_sub_large_small(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| &large_set - &small_set) +} + +#[bench] +fn set_ops_sub_small_large(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| &small_set - &large_set) +} + +#[bench] +fn set_ops_bit_or_assign(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| { + let mut set = large_set.clone(); + set |= &small_set; + set + }); +} + +#[bench] +fn set_ops_bit_and_assign(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| { + let mut set = small_set.clone(); + set &= &large_set; + set + }); +} + +#[bench] +fn set_ops_bit_xor_assign(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| { + let mut set = large_set.clone(); + set ^= &small_set; + set + }); +} + +#[bench] +fn set_ops_sub_assign_large_small(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| { + let mut set = large_set.clone(); + set -= &small_set; + set + }); +} + +#[bench] +fn set_ops_sub_assign_small_large(b: &mut Bencher) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + b.iter(|| { + let mut set = small_set.clone(); + set -= &large_set; + set + }); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/clippy.toml b/deps/crates/vendor/hashbrown-0.15.5/clippy.toml new file mode 100644 index 00000000000000..d98bf2c09b13a4 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ] diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/bitmask.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/bitmask.rs new file mode 100644 index 00000000000000..cfacfce677fb52 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/bitmask.rs @@ -0,0 +1,117 @@ +use super::group::{ + BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, +}; + +/// A bit mask which contains the result of a `Match` operation on a `Group` and +/// allows iterating through them. +/// +/// The bit mask is arranged so that low-order bits represent lower memory +/// addresses for group match results. +/// +/// For implementation reasons, the bits in the set may be sparsely packed with +/// groups of 8 bits representing one element. If any of these bits are non-zero +/// then this element is considered to true in the mask. If this is the +/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be +/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is +/// similarly a mask of all the actually-used bits. +/// +/// To iterate over a bit mask, it must be converted to a form where only 1 bit +/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the +/// mask bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMask(pub(crate) BitMaskWord); + +#[allow(clippy::use_self)] +impl BitMask { + /// Returns a new `BitMask` with all bits inverted. + #[inline] + #[must_use] + #[allow(dead_code)] + pub(crate) fn invert(self) -> Self { + BitMask(self.0 ^ BITMASK_MASK) + } + + /// Returns a new `BitMask` with the lowest bit removed. + #[inline] + #[must_use] + fn remove_lowest_bit(self) -> Self { + BitMask(self.0 & (self.0 - 1)) + } + + /// Returns whether the `BitMask` has at least one set bit. + #[inline] + pub(crate) fn any_bit_set(self) -> bool { + self.0 != 0 + } + + /// Returns the first set bit in the `BitMask`, if there is one. + #[inline] + pub(crate) fn lowest_set_bit(self) -> Option { + if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { + Some(Self::nonzero_trailing_zeros(nonzero)) + } else { + None + } + } + + /// Returns the number of trailing zeroes in the `BitMask`. + #[inline] + pub(crate) fn trailing_zeros(self) -> usize { + // ARM doesn't have a trailing_zeroes instruction, and instead uses + // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM + // versions (pre-ARMv7) don't have RBIT and need to emulate it + // instead. Since we only have 1 bit set in each byte on ARM, we can + // use swap_bytes (REV) + leading_zeroes instead. + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE + } else { + self.0.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Same as above but takes a `NonZeroBitMaskWord`. + #[inline] + fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + // SAFETY: A byte-swapped non-zero value is still non-zero. + let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; + swapped.leading_zeros() as usize / BITMASK_STRIDE + } else { + nonzero.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Returns the number of leading zeroes in the `BitMask`. + #[inline] + pub(crate) fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize / BITMASK_STRIDE + } +} + +impl IntoIterator for BitMask { + type Item = usize; + type IntoIter = BitMaskIter; + + #[inline] + fn into_iter(self) -> BitMaskIter { + // A BitMask only requires each element (group of bits) to be non-zero. + // However for iteration we need each element to only contain 1 bit. + BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) + } +} + +/// Iterator over the contents of a `BitMask`, returning the indices of set +/// bits. +#[derive(Clone)] +pub(crate) struct BitMaskIter(pub(crate) BitMask); + +impl Iterator for BitMaskIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let bit = self.0.lowest_set_bit()?; + self.0 = self.0.remove_lowest_bit(); + Some(bit) + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/group/generic.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/generic.rs new file mode 100644 index 00000000000000..223070997face2 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/generic.rs @@ -0,0 +1,154 @@ +use super::super::{BitMask, Tag}; +use core::{mem, ptr}; + +// Use the native word size as the group size. Using a 64-bit group size on +// a 32-bit architecture will just end up being more expensive because +// shifts and multiplies will need to be emulated. + +cfg_if! { + if #[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "wasm32", + ))] { + type GroupWord = u64; + type NonZeroGroupWord = core::num::NonZeroU64; + } else { + type GroupWord = u32; + type NonZeroGroupWord = core::num::NonZeroU32; + } +} + +pub(crate) type BitMaskWord = GroupWord; +pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord; +pub(crate) const BITMASK_STRIDE: usize = 8; +// We only care about the highest bit of each tag for the mask. +#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)] +pub(crate) const BITMASK_MASK: BitMaskWord = u64::from_ne_bytes([Tag::DELETED.0; 8]) as GroupWord; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Helper function to replicate a tag across a `GroupWord`. +#[inline] +fn repeat(tag: Tag) -> GroupWord { + GroupWord::from_ne_bytes([tag.0; Group::WIDTH]) +} + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a word-sized integer. +#[derive(Copy, Clone)] +pub(crate) struct Group(GroupWord); + +// We perform all operations in the native endianness, and convert to +// little-endian just before creating a BitMask. The can potentially +// enable the compiler to eliminate unnecessary byte swaps if we are +// only checking whether a BitMask is empty. +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + Group(ptr::read_unaligned(ptr.cast())) + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + Group(ptr::read(ptr.cast())) + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + ptr::write(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all tags in the group which *may* + /// have the given value. + /// + /// This function may return a false positive in certain cases where + /// the tag in the group differs from the searched value only in its + /// lowest bit. This is fine because: + /// - This never happens for `EMPTY` and `DELETED`, only full entries. + /// - The check for key equality will catch these. + /// - This only happens if there is at least 1 true match. + /// - The chance of this happening is very low (< 1% chance per byte). + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + // This algorithm is derived from + // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + let cmp = self.0 ^ repeat(tag); + BitMask((cmp.wrapping_sub(repeat(Tag(0x01))) & !cmp & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + // If the high bit is set, then the tag must be either: + // 1111_1111 (EMPTY) or 1000_0000 (DELETED). + // So we can just check if the top two bits are 1 by ANDing them. + BitMask((self.0 & (self.0 << 1) & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask((self.0 & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let full = 1000_0000 (true) or 0000_0000 (false) + // !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry) + // !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry) + let full = !self.0 & repeat(Tag::DELETED); + Group(!full + (full >> 7)) + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/group/lsx.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/lsx.rs new file mode 100644 index 00000000000000..5f45bc8d33fbd4 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/lsx.rs @@ -0,0 +1,137 @@ +use super::super::{BitMask, Tag}; +use core::mem; +use core::num::NonZeroU16; + +use core::arch::loongarch64::*; +use mem::transmute; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit LSX value. +#[derive(Copy, Clone)] +pub(crate) struct Group(v16i8); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + #[allow(clippy::items_after_statements)] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + Group(lsx_vld::<0>(ptr.cast())) + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + Group(lsx_vld::<0>(ptr.cast())) + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + lsx_vst::<0>(self.0, ptr.cast()); + } + + /// Returns a `BitMask` indicating all tags in the group which have + /// the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + #[allow(clippy::missing_transmute_annotations)] + unsafe { + let cmp = lsx_vseq_b(self.0, lsx_vreplgr2vr_b(tag.0 as i32)); + BitMask(lsx_vpickve2gr_hu::<0>(transmute(lsx_vmskltz_b(cmp))) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + #[allow(clippy::missing_transmute_annotations)] + unsafe { + let cmp = lsx_vseqi_b::<{ Tag::EMPTY.0 as i8 as i32 }>(self.0); + BitMask(lsx_vpickve2gr_hu::<0>(transmute(lsx_vmskltz_b(cmp))) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + #[allow(clippy::missing_transmute_annotations)] + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(lsx_vpickve2gr_hu::<0>(transmute(lsx_vmskltz_b(self.0))) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + #[allow(clippy::missing_transmute_annotations)] + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(lsx_vpickve2gr_hu::<0>(transmute(lsx_vmskgez_b(self.0))) as u16) + } + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[allow(clippy::missing_transmute_annotations)] + unsafe { + let zero = lsx_vreplgr2vr_b(0); + let special = lsx_vslt_b(self.0, zero); + Group(transmute(lsx_vor_v( + transmute(special), + transmute(lsx_vreplgr2vr_b(Tag::DELETED.0 as i32)), + ))) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/group/mod.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/mod.rs new file mode 100644 index 00000000000000..fe2d7748341b0f --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/mod.rs @@ -0,0 +1,43 @@ +cfg_if! { + // Use the SSE2 implementation if possible: it allows us to scan 16 buckets + // at once instead of 8. We don't bother with AVX since it would require + // runtime dispatch and wouldn't gain us much anyways: the probability of + // finding a match drops off drastically after the first few buckets. + // + // I attempted an implementation on ARM using NEON instructions, but it + // turns out that most NEON instructions have multi-cycle latency, which in + // the end outweighs any gains over the generic implementation. + if #[cfg(all( + target_feature = "sse2", + any(target_arch = "x86", target_arch = "x86_64"), + not(miri), + ))] { + mod sse2; + use sse2 as imp; + } else if #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + // NEON intrinsics are currently broken on big-endian targets. + // See https://github.com/rust-lang/stdarch/issues/1484. + target_endian = "little", + not(miri), + ))] { + mod neon; + use neon as imp; + } else if #[cfg(all( + feature = "nightly", + target_arch = "loongarch64", + target_feature = "lsx", + not(miri), + ))] { + mod lsx; + use lsx as imp; + } else { + mod generic; + use generic as imp; + } +} +pub(crate) use self::imp::Group; +pub(super) use self::imp::{ + BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, +}; diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/group/neon.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/neon.rs new file mode 100644 index 00000000000000..9374cb3881622f --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/neon.rs @@ -0,0 +1,121 @@ +use super::super::{BitMask, Tag}; +use core::arch::aarch64 as neon; +use core::mem; +use core::num::NonZeroU64; + +pub(crate) type BitMaskWord = u64; +pub(crate) type NonZeroBitMaskWord = NonZeroU64; +pub(crate) const BITMASK_STRIDE: usize = 8; +pub(crate) const BITMASK_MASK: BitMaskWord = !0; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 64-bit NEON value. +#[derive(Copy, Clone)] +pub(crate) struct Group(neon::uint8x8_t); + +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + Group(neon::vld1_u8(ptr.cast())) + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + Group(neon::vld1_u8(ptr.cast())) + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + neon::vst1_u8(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all tags in the group which *may* + /// have the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + unsafe { + let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(tag.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_tag(Tag::EMPTY) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + unsafe { + let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80))) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/group/sse2.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/sse2.rs new file mode 100644 index 00000000000000..0d4b1082204d1b --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/group/sse2.rs @@ -0,0 +1,146 @@ +use super::super::{BitMask, Tag}; +use core::mem; +use core::num::NonZeroU16; + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as x86; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit SSE value. +#[derive(Copy, Clone)] +pub(crate) struct Group(x86::__m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + #[allow(clippy::items_after_statements)] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + Group(x86::_mm_loadu_si128(ptr.cast())) + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + Group(x86::_mm_load_si128(ptr.cast())) + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + x86::_mm_store_si128(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all tags in the group which have + /// the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + #[allow( + clippy::cast_possible_wrap, // tag.0: Tag as i8 + // tag: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(tag.0 as i8)); + BitMask(x86::_mm_movemask_epi8(cmp) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_tag(Tag::EMPTY) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + #[allow( + // tag: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(x86::_mm_movemask_epi8(self.0) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[allow( + clippy::cast_possible_wrap, // tag: Tag::DELETED.0 as i8 + )] + unsafe { + let zero = x86::_mm_setzero_si128(); + let special = x86::_mm_cmpgt_epi8(zero, self.0); + Group(x86::_mm_or_si128( + special, + x86::_mm_set1_epi8(Tag::DELETED.0 as i8), + )) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/mod.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/mod.rs new file mode 100644 index 00000000000000..62ef8bfcc9bcce --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/mod.rs @@ -0,0 +1,10 @@ +mod bitmask; +mod group; +mod tag; + +use self::bitmask::BitMask; +pub(crate) use self::{ + bitmask::BitMaskIter, + group::Group, + tag::{Tag, TagSliceExt}, +}; diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/control/tag.rs b/deps/crates/vendor/hashbrown-0.15.5/src/control/tag.rs new file mode 100644 index 00000000000000..817dd55cd6388e --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/control/tag.rs @@ -0,0 +1,83 @@ +use core::{fmt, mem}; + +/// Single tag in a control group. +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub(crate) struct Tag(pub(super) u8); +impl Tag { + /// Control tag value for an empty bucket. + pub(crate) const EMPTY: Tag = Tag(0b1111_1111); + + /// Control tag value for a deleted bucket. + pub(crate) const DELETED: Tag = Tag(0b1000_0000); + + /// Checks whether a control tag represents a full bucket (top bit is clear). + #[inline] + pub(crate) const fn is_full(self) -> bool { + self.0 & 0x80 == 0 + } + + /// Checks whether a control tag represents a special value (top bit is set). + #[inline] + pub(crate) const fn is_special(self) -> bool { + self.0 & 0x80 != 0 + } + + /// Checks whether a special control value is EMPTY (just check 1 bit). + #[inline] + pub(crate) const fn special_is_empty(self) -> bool { + debug_assert!(self.is_special()); + self.0 & 0x01 != 0 + } + + /// Creates a control tag representing a full bucket with the given hash. + #[inline] + #[allow(clippy::cast_possible_truncation)] + pub(crate) const fn full(hash: u64) -> Tag { + // Constant for function that grabs the top 7 bits of the hash. + const MIN_HASH_LEN: usize = if mem::size_of::() < mem::size_of::() { + mem::size_of::() + } else { + mem::size_of::() + }; + + // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit + // value, some hash functions (such as FxHash) produce a usize result + // instead, which means that the top 32 bits are 0 on 32-bit platforms. + // So we use MIN_HASH_LEN constant to handle this. + let top7 = hash >> (MIN_HASH_LEN * 8 - 7); + Tag((top7 & 0x7f) as u8) // truncation + } +} +impl fmt::Debug for Tag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_special() { + if self.special_is_empty() { + f.pad("EMPTY") + } else { + f.pad("DELETED") + } + } else { + f.debug_tuple("full").field(&(self.0 & 0x7F)).finish() + } + } +} + +/// Extension trait for slices of tags. +pub(crate) trait TagSliceExt { + /// Fills the control with the given tag. + fn fill_tag(&mut self, tag: Tag); + + /// Clears out the control. + #[inline] + fn fill_empty(&mut self) { + self.fill_tag(Tag::EMPTY) + } +} +impl TagSliceExt for [Tag] { + #[inline] + fn fill_tag(&mut self, tag: Tag) { + // SAFETY: We have access to the entire slice, so, we can write to the entire slice. + unsafe { self.as_mut_ptr().write_bytes(tag.0, self.len()) } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/mod.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/mod.rs new file mode 100644 index 00000000000000..ef497836cb9895 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/mod.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "rayon")] +pub(crate) mod rayon; +#[cfg(feature = "serde")] +mod serde; diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/helpers.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/helpers.rs new file mode 100644 index 00000000000000..070b08cd56d7b2 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/helpers.rs @@ -0,0 +1,27 @@ +use alloc::collections::LinkedList; +use alloc::vec::Vec; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Helper for collecting parallel iterators to an intermediary +#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending! +pub(super) fn collect(iter: I) -> (LinkedList>, usize) { + let list = iter + .into_par_iter() + .fold(Vec::new, |mut vec, elem| { + vec.push(elem); + vec + }) + .map(|vec| { + let mut list = LinkedList::new(); + list.push_back(vec); + list + }) + .reduce(LinkedList::new, |mut list1, mut list2| { + list1.append(&mut list2); + list1 + }); + + let len = list.iter().map(Vec::len).sum(); + (list, len) +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/map.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/map.rs new file mode 100644 index 00000000000000..9623ca747c5358 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/map.rs @@ -0,0 +1,721 @@ +//! Rayon extensions for `HashMap`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_map::HashMap; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to keys in a map. +/// +/// This iterator is created by the [`par_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().0 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParKeys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to values in a map. +/// +/// This iterator is created by the [`par_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().1 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParValues<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_mut(); + (&r.0, &mut r.1) + }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over mutable references to values in a map. +/// +/// This iterator is created by the [`par_values_mut`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &mut x.as_mut().1 }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParDrain<'a, K, V, A: Allocator = Global> { + inner: RawParDrain<'a, (K, V), A>, +} + +impl ParallelIterator for ParDrain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashMap { + /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl HashMap { + /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } + } +} + +impl HashMap +where + K: Eq + Hash + Sync, + V: PartialEq + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Returns `true` if the map is equal to another, + /// i.e. both maps contain the same keys mapped to the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .into_par_iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl IntoParallelIterator for HashMap { + type Item = (K, V); + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.table.into_par_iter(), + } + } +} + +impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +/// Collect (key, value) pairs from a parallel iterator into a +/// hashmap. If multiple pairs correspond to the same key, then the +/// ones produced earlier in the parallel iterator will be +/// overwritten, just as with a sequential iterator. +impl FromParallelIterator<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut map = HashMap::default(); + map.par_extend(par_iter); + map + } +} + +/// Extend a hash map with items from a parallel iterator. +impl ParallelExtend<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash map with copied items from a parallel iterator. +impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap +where + K: Copy + Eq + Hash + Sync, + V: Copy + Sync, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashMap` -- no custom advantage. +fn extend(map: &mut HashMap, par_iter: I) +where + K: Eq + Hash, + S: BuildHasher, + I: IntoParallelIterator, + A: Allocator, + HashMap: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire length if the map is empty. + // Otherwise reserve half the length (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if map.is_empty() { len } else { (len + 1) / 2 }; + map.reserve(reserve); + for vec in list { + map.extend(vec); + } +} + +#[cfg(test)] +mod test_par_map { + use alloc::vec::Vec; + use core::hash::{Hash, Hasher}; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_map::HashMap; + + struct Droppable<'a> { + k: usize, + counter: &'a AtomicUsize, + } + + impl Droppable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Droppable<'_> { + counter.fetch_add(1, Ordering::Relaxed); + + Droppable { k, counter } + } + } + + impl Drop for Droppable<'_> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + impl Clone for Droppable<'_> { + fn clone(&self) -> Self { + Droppable::new(self.k, self.counter) + } + } + + impl Hash for Droppable<'_> { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.k.hash(state); + } + } + + impl PartialEq for Droppable<'_> { + fn eq(&self, other: &Self) -> bool { + self.k == other.k + } + } + + impl Eq for Droppable<'_> {} + + #[test] + fn test_into_iter_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Droppable::new(i, &key); + let d2 = Droppable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the iterator does not leak anything. + drop(hm.clone().into_par_iter()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect(); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_drain_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let mut hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Droppable::new(i, &key); + let d2 = Droppable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the drain iterator does not leak anything. + drop(hm.clone().par_drain()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect(); + assert!(hm.is_empty()); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.par_drain().count(), 0); + assert_eq!(m.par_keys().count(), 0); + assert_eq!(m.par_values().count(), 0); + assert_eq!(m.par_values_mut().count(), 0); + assert_eq!(m.par_iter().count(), 0); + assert_eq!(m.par_iter_mut().count(), 0); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_par_iter().count(), 0); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let observed = AtomicUsize::new(0); + + m.par_iter().for_each(|(k, v)| { + assert_eq!(*v, *k * 2); + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(!m1.par_eq(&m2)); + + m2.insert(3, 4); + + assert!(m1.par_eq(&m2)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.par_iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.par_extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/mod.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/mod.rs new file mode 100644 index 00000000000000..61ca69b61d7f26 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/mod.rs @@ -0,0 +1,5 @@ +mod helpers; +pub(crate) mod map; +pub(crate) mod raw; +pub(crate) mod set; +pub(crate) mod table; diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/raw.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/raw.rs new file mode 100644 index 00000000000000..612be47a55d16e --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/raw.rs @@ -0,0 +1,230 @@ +use crate::raw::Bucket; +use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; +use crate::scopeguard::guard; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use rayon::iter::{ + plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, + ParallelIterator, +}; + +/// Parallel iterator which returns a raw pointer to every full bucket in the table. +pub struct RawParIter { + iter: RawIterRange, +} + +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + +impl From> for RawParIter { + fn from(it: RawIter) -> Self { + RawParIter { iter: it.iter } + } +} + +impl ParallelIterator for RawParIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let producer = ParIterProducer { iter: self.iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Producer which returns a `Bucket` for every element. +struct ParIterProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParIterProducer { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.split(); + let left = ParIterProducer { iter: left }; + let right = right.map(|right| ParIterProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(self, folder: F) -> F + where + F: Folder, + { + folder.consume_iter(self.iter) + } +} + +/// Parallel iterator which consumes a table and returns elements. +pub struct RawIntoParIter { + table: RawTable, +} + +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.par_iter() + } +} + +impl ParallelIterator for RawIntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let iter = unsafe { self.table.iter().iter }; + let _guard = guard(self.table.into_allocation(), |alloc| { + if let Some((ptr, layout, ref alloc)) = *alloc { + unsafe { + alloc.deallocate(ptr, layout); + } + } + }); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Parallel iterator which consumes elements without freeing the table storage. +pub struct RawParDrain<'a, T, A: Allocator = Global> { + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. + table: NonNull>, + marker: PhantomData<&'a RawTable>, +} + +unsafe impl Send for RawParDrain<'_, T, A> {} + +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.as_ref().par_iter() + } +} + +impl ParallelIterator for RawParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let _guard = guard(self.table, |table| unsafe { + table.as_mut().clear_no_drop(); + }); + let iter = unsafe { self.table.as_ref().iter().iter }; + mem::forget(self); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +impl Drop for RawParDrain<'_, T, A> { + fn drop(&mut self) { + // If drive_unindexed is not called then simply clear the table. + unsafe { + self.table.as_mut().clear(); + } + } +} + +/// Producer which will consume all elements in the range, even if it is dropped +/// halfway through. +struct ParDrainProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParDrainProducer { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.clone().split(); + mem::forget(self); + let left = ParDrainProducer { iter: left }; + let right = right.map(|right| ParDrainProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(mut self, mut folder: F) -> F + where + F: Folder, + { + // Make sure to modify the iterator in-place so that any remaining + // elements are processed in our Drop impl. + for item in &mut self.iter { + folder = folder.consume(unsafe { item.read() }); + if folder.full() { + return folder; + } + } + + // If we processed all elements then we don't need to run the drop. + mem::forget(self); + folder + } +} + +impl Drop for ParDrainProducer { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // Drop all remaining elements + if mem::needs_drop::() { + for item in &mut self.iter { + unsafe { + item.drop(); + } + } + } + } +} + +impl RawTable { + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn par_iter(&self) -> RawParIter { + RawParIter { + iter: self.iter().iter, + } + } + + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_par_iter(self) -> RawIntoParIter { + RawIntoParIter { table: self } + } + + /// Returns a parallel iterator which consumes all elements of a `RawTable` + /// without freeing its memory allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> { + RawParDrain { + table: NonNull::from(self), + marker: PhantomData, + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/set.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/set.rs new file mode 100644 index 00000000000000..3de98fccb89d1d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/set.rs @@ -0,0 +1,659 @@ +//! Rayon extensions for `HashSet`. + +use super::map; +use crate::hash_set::HashSet; +use crate::raw::{Allocator, Global}; +use core::hash::{BuildHasher, Hash}; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over elements of a consumed set. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: map::IntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel draining iterator over entries of a set. +/// +/// This iterator is created by the [`par_drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: map::ParDrain<'a, T, (), A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in a set. +/// +/// This iterator is created by the [`par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the difference of +/// sets. +/// +/// This iterator is created by the [`par_difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| !self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the symmetric +/// difference of sets. +/// +/// This iterator is created by the [`par_symmetric_difference`] method on +/// [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .par_difference(self.b) + .chain(self.b.par_difference(self.a)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the intersection of +/// sets. +/// +/// This iterator is created by the [`par_intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParIntersection<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the union of sets. +/// +/// This iterator is created by the [`par_union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParUnion<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.a.len() <= self.b.len() { + (self.a, self.b) + } else { + (self.b, self.a) + }; + larger + .into_par_iter() + .chain(smaller.par_difference(larger)) + .drive_unindexed(consumer) + } +} + +impl HashSet +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Visits (potentially in parallel) the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { + ParUnion { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the difference, + /// i.e. the values that are in `self` but not in `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> { + ParDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the symmetric + /// difference, i.e. the values that are in `self` or in `other` but not in both. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_symmetric_difference<'a>( + &'a self, + other: &'a Self, + ) -> ParSymmetricDifference<'a, T, S, A> { + ParSymmetricDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the + /// intersection, i.e. the values that are both in `self` and `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> { + ParIntersection { a: self, b: other } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_disjoint(&self, other: &Self) -> bool { + self.into_par_iter().all(|x| !other.contains(x)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_subset(&self, other: &Self) -> bool { + if self.len() <= other.len() { + self.into_par_iter().all(|x| other.contains(x)) + } else { + false + } + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_superset(&self, other: &Self) -> bool { + other.par_is_subset(self) + } + + /// Returns `true` if the set is equal to another, + /// i.e. both sets contain the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.par_is_subset(other) + } +} + +impl HashSet +where + T: Eq + Hash + Send, + A: Allocator + Send, +{ + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the set's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } + } +} + +impl IntoParallelIterator for HashSet { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.map.into_par_iter(), + } + } +} + +impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: self.map.par_keys(), + } + } +} + +/// Collect values from a parallel iterator into a hashset. +impl FromParallelIterator for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut set = HashSet::default(); + set.par_extend(par_iter); + set + } +} + +/// Extend a hash set with items from a parallel iterator. +impl ParallelExtend for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash set with copied items from a parallel iterator. +impl<'a, T, S> ParallelExtend<&'a T> for HashSet +where + T: 'a + Copy + Eq + Hash + Sync, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashSet` -- no custom advantage. +fn extend(set: &mut HashSet, par_iter: I) +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, + I: IntoParallelIterator, + HashSet: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Values may be already present or show multiple times in the iterator. + // Reserve the entire length if the set is empty. + // Otherwise reserve half the length (rounded up), so the set + // will only resize twice in the worst case. + let reserve = if set.is_empty() { len } else { (len + 1) / 2 }; + set.reserve(reserve); + for vec in list { + set.extend(vec); + } +} + +#[cfg(test)] +mod test_par_set { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_set::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.par_is_disjoint(&ys)); + assert!(!ys.par_is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(!b.par_is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(b.par_is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let i = a + .par_intersection(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let expected = [1, 5, 11]; + let i = a + .par_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let expected = [-2, 1, 5, 11, 14, 22]; + let i = a + .par_symmetric_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + let i = a + .par_union(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.par_iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(!s1.par_eq(&s2)); + + s2.insert(3); + + assert!(s1.par_eq(&s2)); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.par_extend(&[2, 3, 4][..]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.par_extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/table.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/table.rs new file mode 100644 index 00000000000000..cb04a03dfaa959 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/rayon/table.rs @@ -0,0 +1,249 @@ +//! Rayon extensions for `HashTable`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_table::HashTable; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_ref() }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> { + type Item = &'a mut T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_mut() }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain +/// [`HashTable`]: /hashbrown/struct.HashTable.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: RawParDrain<'a, T, A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashTable { + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.raw.par_drain(), + } + } +} + +impl IntoParallelIterator for HashTable { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.raw.into_par_iter(), + } + } +} + +impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable { + type Item = &'a mut T; + type Iter = ParIterMut<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test_par_table { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::{hash_map::make_hash, hash_table::HashTable, DefaultHashBuilder}; + + #[test] + fn test_iterate() { + let hasher = DefaultHashBuilder::default(); + let mut a = HashTable::new(); + for i in 0..32 { + a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_move_iter() { + let hasher = DefaultHashBuilder::default(); + let hs = { + let mut hs = HashTable::new(); + + hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x)); + hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x)); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/serde.rs b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/serde.rs new file mode 100644 index 00000000000000..f9eb05fd7154cf --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/external_trait_impls/serde.rs @@ -0,0 +1,220 @@ +mod size_hint { + use core::cmp; + + /// This presumably exists to prevent denial of service attacks. + /// + /// Original discussion: https://github.com/serde-rs/serde/issues/1114. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } +} + +mod map { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_map::HashMap; + + use super::size_hint; + + impl Serialize for HashMap + where + K: Serialize + Eq + Hash, + V: Serialize, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + + impl<'de, K, V, S, A> Deserialize<'de> for HashMap + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, K, V, S, A> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + let mut values = HashMap::with_capacity_and_hasher_in( + size_hint::cautious(map.size_hint()), + S::default(), + A::default(), + ); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_set::HashSet; + + use super::size_hint; + + impl Serialize for HashSet + where + T: Serialize + Eq + Hash, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + + impl<'de, T, S, A> Deserialize<'de> for HashSet + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, T, S, A> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashSet; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + let mut values = HashSet::with_capacity_and_hasher_in( + size_hint::cautious(seq.size_hint()), + S::default(), + A::default(), + ); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + #[allow(clippy::missing_errors_doc)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet) + where + A: Allocator; + + impl<'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'_, T, S, A> + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + self.0.clear(); + self.0.reserve(size_hint::cautious(seq.size_hint())); + + while let Some(value) = seq.next_element()? { + self.0.insert(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/lib.rs b/deps/crates/vendor/hashbrown-0.15.5/src/lib.rs new file mode 100644 index 00000000000000..e79da830fa5ebf --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/lib.rs @@ -0,0 +1,188 @@ +//! This crate is a Rust port of Google's high-performance [SwissTable] hash +//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +//! and `HashSet` types. +//! +//! The original C++ version of [SwissTable] can be found [here], and this +//! [CppCon talk] gives an overview of how the algorithm works. +//! +//! [SwissTable]: https://abseil.io/blog/20180927-swisstables +//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +#![no_std] +#![cfg_attr( + feature = "nightly", + feature( + test, + core_intrinsics, + dropck_eyepatch, + min_specialization, + extend_one, + allocator_api, + slice_ptr_get, + maybe_uninit_array_assume_init, + strict_provenance_lints + ) +)] +#![cfg_attr(feature = "rustc-dep-of-std", feature(rustc_attrs))] +#![allow( + clippy::doc_markdown, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::option_if_let_else, + clippy::redundant_else, + clippy::manual_map, + clippy::missing_safety_doc, + clippy::missing_errors_doc +)] +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] +#![cfg_attr( + feature = "nightly", + allow(clippy::incompatible_msrv, internal_features) +)] +#![cfg_attr( + all(feature = "nightly", target_arch = "loongarch64"), + feature(stdarch_loongarch) +)] + +/// Default hasher for [`HashMap`] and [`HashSet`]. +#[cfg(feature = "default-hasher")] +pub type DefaultHashBuilder = foldhash::fast::RandomState; + +/// Dummy default hasher for [`HashMap`] and [`HashSet`]. +#[cfg(not(feature = "default-hasher"))] +pub enum DefaultHashBuilder {} + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg_attr(test, macro_use)] +#[cfg_attr(feature = "rustc-dep-of-std", allow(unused_extern_crates))] +extern crate alloc; + +#[cfg(feature = "nightly")] +#[cfg(doctest)] +doc_comment::doctest!("../README.md"); + +#[macro_use] +mod macros; + +mod control; +mod raw; +mod util; + +mod external_trait_impls; +mod map; +#[cfg(feature = "raw-entry")] +mod raw_entry; +#[cfg(feature = "rustc-internal-api")] +mod rustc_entry; +mod scopeguard; +mod set; +mod table; + +pub mod hash_map { + //! A hash map implemented with quadratic probing and SIMD lookup. + pub use crate::map::*; + + #[cfg(feature = "rustc-internal-api")] + pub use crate::rustc_entry::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::map::*; + } +} +pub mod hash_set { + //! A hash set implemented as a `HashMap` where the value is `()`. + pub use crate::set::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash sets. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::set::*; + } +} +pub mod hash_table { + //! A hash table implemented with quadratic probing and SIMD lookup. + pub use crate::table::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash tables. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::table::*; + } +} + +pub use crate::map::HashMap; +pub use crate::set::HashSet; +pub use crate::table::HashTable; + +#[cfg(feature = "equivalent")] +pub use equivalent::Equivalent; + +// This is only used as a fallback when building as part of `std`. +#[cfg(not(feature = "equivalent"))] +/// Key equivalence trait. +/// +/// This trait defines the function used to compare the input value with the +/// map keys (or set values) during a lookup operation such as [`HashMap::get`] +/// or [`HashSet::contains`]. +/// It is provided with a blanket implementation based on the +/// [`Borrow`](core::borrow::Borrow) trait. +/// +/// # Correctness +/// +/// Equivalent values must hash to the same value. +pub trait Equivalent { + /// Checks if this value is equivalent to the given key. + /// + /// Returns `true` if both values are equivalent, and `false` otherwise. + /// + /// # Correctness + /// + /// When this function returns `true`, both `self` and `key` must hash to + /// the same value. + fn equivalent(&self, key: &K) -> bool; +} + +#[cfg(not(feature = "equivalent"))] +impl Equivalent for Q +where + Q: Eq, + K: core::borrow::Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + self == key.borrow() + } +} + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: alloc::alloc::Layout, + }, +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/macros.rs b/deps/crates/vendor/hashbrown-0.15.5/src/macros.rs new file mode 100644 index 00000000000000..eaba6bed1fcb6b --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/macros.rs @@ -0,0 +1,70 @@ +// See the cfg-if crate. +#[allow(unused_macro_rules)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +// Helper macro for specialization. This also helps avoid parse errors if the +// default fn syntax for specialization changes in the future. +#[cfg(feature = "nightly")] +macro_rules! default_fn { + (#[$($a:tt)*] $($tt:tt)*) => { + #[$($a)*] default $($tt)* + } +} +#[cfg(not(feature = "nightly"))] +macro_rules! default_fn { + ($($tt:tt)*) => { + $($tt)* + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/map.rs b/deps/crates/vendor/hashbrown-0.15.5/src/map.rs new file mode 100644 index 00000000000000..91013945b9118a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/map.rs @@ -0,0 +1,6583 @@ +use crate::raw::{ + Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable, +}; +use crate::{DefaultHashBuilder, Equivalent, TryReserveError}; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ops::Index; + +#[cfg(feature = "raw-entry")] +pub use crate::raw_entry::*; + +/// A hash map implemented with quadratic probing and SIMD lookup. +/// +/// The default hashing algorithm is currently [`foldhash`], though this is +/// subject to change at any point in the future. This hash function is very +/// fast for all types of keys, but this algorithm will typically *not* protect +/// against attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashMap` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); +/// } +/// ``` +/// +/// `HashMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`fnv`]: https://crates.io/crates/fnv +/// [`foldhash`]: https://crates.io/crates/foldhash +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +/// +/// A `HashMap` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .into_iter().collect(); +/// // use the values stored in map +/// ``` +pub struct HashMap { + pub(crate) hash_builder: S, + pub(crate) table: RawTable<(K, V), A>, +} + +impl Clone for HashMap { + fn clone(&self) -> Self { + HashMap { + hash_builder: self.hash_builder.clone(), + table: self.table.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.table.clone_from(&source.table); + + // Update hash_builder only if we successfully cloned all elements. + self.hash_builder.clone_from(&source.hash_builder); + } +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +where + Q: Hash, + S: BuildHasher, +{ + move |val| make_hash::(hash_builder, &val.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ +where + Q: Equivalent + ?Sized, +{ + move |x| k.equivalent(&x.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +#[allow(dead_code)] +pub(crate) fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ +where + Q: Equivalent + ?Sized, +{ + move |x| k.equivalent(x) +} + +#[cfg(not(feature = "nightly"))] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + use core::hash::Hasher; + let mut state = hash_builder.build_hasher(); + val.hash(&mut state); + state.finish() +} + +#[cfg(feature = "nightly")] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + hash_builder.hash_one(val) +} + +#[cfg(feature = "default-hasher")] +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher`](HashMap::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher`](HashMap::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default()) + } +} + +#[cfg(feature = "default-hasher")] +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher_in`](HashMap::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::new_in(&bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// + /// // The created HashMap also doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// // Now we insert element inside created HashMap + /// map.insert("One", 1); + /// // We can see that the HashMap holds 1 element + /// assert_eq!(map.len(), 1); + /// // And it also allocates some capacity + /// assert!(map.capacity() > 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self::with_hasher_in(DefaultHashBuilder::default(), alloc) + } + + /// Creates an empty `HashMap` with the specified capacity using the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher_in`](HashMap::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::with_capacity_in(5, &bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = map.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashMap + /// map.insert("One", 1); + /// map.insert("Two", 2); + /// map.insert("Three", 3); + /// map.insert("Four", 4); + /// map.insert("Five", 5); + /// + /// // We can see that the HashMap holds 5 elements + /// assert_eq!(map.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(map.capacity(), empty_map_capacity) + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The hash map is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher(hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } +} + +impl HashMap { + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.table.allocator() + } + + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. It will be allocated with the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. It will be allocated with the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<&str> = Vec::new(); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// vec.push(*key); + /// } + /// + /// // The `Keys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [11, 12, 13]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + inner: self.iter_mut(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + Iter { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in &map { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 2), ("b", 4), ("c", 6)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + IterMut { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + #[cfg(test)] + #[cfg_attr(feature = "inline-more", inline)] + fn raw_capacity(&self) -> usize { + self.table.buckets() + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// let capacity_before_drain = a.capacity(); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// // As we can see, the map is empty and contains no element. + /// assert!(a.is_empty() && a.len() == 0); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_drain); + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// { // Iterator is dropped without being consumed. + /// let d = a.drain(); + /// } + /// + /// // But the map is empty even if we do not use Drain iterator. + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { + inner: self.table.drain(), + } + } + + /// Retains only the elements specified by the predicate. Keeps the + /// allocated memory for reuse. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// assert_eq!(map.len(), 8); + /// + /// map.retain(|&k, _| k % 2 == 0); + /// + /// // We can see, that the number of elements inside map is changed. + /// assert_eq!(map.len(), 4); + /// + /// let mut vec: Vec<(i32, i32)> = map.iter().map(|(&k, &v)| (k, v)).collect(); + /// vec.sort_unstable(); + /// assert_eq!(vec, [(0, 0), (2, 20), (4, 40), (6, 60)]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.table.iter() { + let &mut (ref key, ref mut value) = item.as_mut(); + if !f(key, value) { + self.table.erase(item); + } + } + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all pairs `(k, v)` such that `f(&k, &mut v)` returns `true` out + /// into another iterator. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// Keeps the allocated memory for reuse. + /// + /// [`retain()`]: HashMap::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// let drained: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// { // Iterator is dropped without being consumed. + /// let d = map.extract_if(|k, _v| k % 2 != 0); + /// } + /// + /// // ExtractIf was not exhausted, therefore no elements were drained. + /// assert_eq!(map.len(), 8); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.table.iter() }, + table: &mut self.table, + }, + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// let capacity_before_clear = a.capacity(); + /// + /// a.clear(); + /// + /// // Map is empty. + /// assert!(a.is_empty()); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_clear); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.table.clear(); + } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + inner: self.into_iter(), + } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + inner: self.into_iter(), + } + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashMap::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.reserve(10); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.table + .reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned: + /// ``` + /// # fn test() { + /// use hashbrown::HashMap; + /// use hashbrown::TryReserveError; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.try_reserve(usize::MAX) { + /// Err(error) => match error { + /// TryReserveError::CapacityOverflow => {} + /// _ => panic!("TryReserveError::AllocError ?"), + /// }, + /// _ => panic!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(not(miri))] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.table + .try_reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.table + .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// This function does nothing if the current capacity is smaller than the + /// supplied minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.table + .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { + let hash = make_hash::(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { + Entry::Occupied(OccupiedEntry { + hash, + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } + + /// Gets the given key's corresponding entry by reference in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut words: HashMap = HashMap::new(); + /// let source = ["poneyland", "horseyland", "poneyland", "poneyland"]; + /// for (i, &s) in source.iter().enumerate() { + /// let counter = words.entry_ref(s).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(words["poneyland"], 3); + /// assert_eq!(words["horseyland"], 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry_ref<'a, 'b, Q>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.hash_builder, key); + if let Some(elem) = self.table.find(hash, equivalent_key(key)) { + EntryRef::Occupied(OccupiedEntry { + hash, + elem, + table: self, + }) + } else { + EntryRef::Vacant(VacantEntryRef { + hash, + key, + table: self, + }) + } + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + #[inline] + fn get_inner(&self, k: &Q) -> Option<&(K, V)> + where + Q: Hash + Equivalent + ?Sized, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get(hash, equivalent_key(k)) + } + } + + /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// let (k, v) = map.get_key_value_mut(&1).unwrap(); + /// assert_eq!(k, &1); + /// assert_eq!(v, &mut "a"); + /// *v = "b"; + /// assert_eq!(map.get_key_value_mut(&1), Some((&1, &mut "b"))); + /// assert_eq!(map.get_key_value_mut(&2), None); + /// ``` + #[inline] + pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (ref key, ref mut value)) => Some((key, value)), + None => None, + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains_key(&self, k: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + self.get_inner(k).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// + /// assert_eq!(map.get_mut(&2), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (_, ref mut v)) => Some(v), + None => None, + } + } + + #[inline] + fn get_inner_mut(&mut self, k: &Q) -> Option<&mut (K, V)> + where + Q: Hash + Equivalent + ?Sized, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get_mut(hash, equivalent_key(k)) + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // Get Athenæum and Bodleian Library + /// let [Some(a), Some(b)] = libraries.get_many_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) else { panic!() }; + /// + /// // Assert values of Athenæum and Library of Congress + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// None + /// ] + /// ); + /// ``` + /// + /// ```should_panic + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Athenæum".to_string(), 1807); + /// + /// // Duplicate keys panic! + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// ``` + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_many_mut_inner(ks).map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be used if + /// the key is missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // SAFETY: The keys do not overlap. + /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) }) else { panic!() }; + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]) }; + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]) }; + /// // Missing keys result in None + /// assert_eq!(got, [Some(&mut 1807), None]); + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// Some((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)), + /// ], + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, [Some((&"Bodleian Library".to_string(), &mut 1602)), None]); + /// ``` + /// + /// ```should_panic + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// + /// // Duplicate keys result in panic! + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// ``` + pub fn get_many_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_many_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys, without validating that the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_key_value_mut`](`HashMap::get_many_key_value_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// Some((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)), + /// ], + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// None, + /// ], + /// ); + /// ``` + pub unsafe fn get_many_key_value_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + fn get_many_mut_inner(&mut self, ks: [&Q; N]) -> [Option<&'_ mut (K, V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + unsafe fn get_many_unchecked_mut_inner( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut (K, V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + fn build_hashes_inner(&self, ks: [&Q; N]) -> [u64; N] + where + Q: Hash + Equivalent + ?Sized, + { + let mut hashes = [0_u64; N]; + for i in 0..N { + hashes[i] = make_hash::(&self.hash_builder, ks[i]); + } + hashes + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [`std::collections`] + /// [module-level documentation] for more. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// [`std::collections`]: https://doc.rust-lang.org/std/collections/index.html + /// [module-level documentation]: https://doc.rust-lang.org/std/collections/index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = make_hash::(&self.hash_builder, &k); + match self.find_or_find_insert_slot(hash, &k) { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), + Err(slot) => { + unsafe { + self.table.insert_in_slot(hash, slot, (k, v)); + } + None + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn find_or_find_insert_slot( + &mut self, + hash: u64, + key: &Q, + ) -> Result, crate::raw::InsertSlot> + where + Q: Equivalent + ?Sized, + { + self.table.find_or_find_insert_slot( + hash, + equivalent_key(key), + make_hasher(&self.hash_builder), + ) + } + + /// Insert a key-value pair into the map without checking + /// if the key already exists in the map. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the map. + /// For example, when constructing a map from another map, we know + /// that keys are unique. + /// + /// Returns a reference to the key and value just inserted. + /// + /// # Safety + /// + /// This operation is safe if a key does not exist in the map. + /// + /// However, if a key exists in the map already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the map + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashMap` + /// may be passed to unsafe code which does expect the map to behave + /// correctly, and would cause unsoundness as a result. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map1 = HashMap::new(); + /// assert_eq!(map1.insert(1, "a"), None); + /// assert_eq!(map1.insert(2, "b"), None); + /// assert_eq!(map1.insert(3, "c"), None); + /// assert_eq!(map1.len(), 3); + /// + /// let mut map2 = HashMap::new(); + /// + /// for (key, value) in map1.into_iter() { + /// unsafe { + /// map2.insert_unique_unchecked(key, value); + /// } + /// } + /// + /// let (key, value) = unsafe { map2.insert_unique_unchecked(4, "d") }; + /// assert_eq!(key, &4); + /// assert_eq!(value, &mut "d"); + /// *value = "e"; + /// + /// assert_eq!(map2[&1], "a"); + /// assert_eq!(map2[&2], "b"); + /// assert_eq!(map2[&3], "c"); + /// assert_eq!(map2[&4], "e"); + /// assert_eq!(map2.len(), 4); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { + let hash = make_hash::(&self.hash_builder, &k); + let bucket = self + .table + .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); + let (k_ref, v_ref) = unsafe { bucket.as_mut() }; + (k_ref, v_ref) + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// # Errors + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::OccupiedError; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// match map.try_insert(37, "b") { + /// Err(OccupiedError { entry, value }) => { + /// assert_eq!(entry.key(), &37); + /// assert_eq!(entry.get(), &"a"); + /// assert_eq!(value, "b"); + /// } + /// _ => panic!() + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert( + &mut self, + key: K, + value: V, + ) -> Result<&mut V, OccupiedError<'_, K, V, S, A>> { + match self.entry(key) { + Entry::Occupied(entry) => Err(OccupiedError { entry, value }), + Entry::Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map holds none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, k: &Q) -> Option + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.remove_entry(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.remove_entry(hash, equivalent_key(k)) + } + + /// Returns the total amount of memory allocated internally by the hash + /// set, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.table.allocation_size() + } +} + +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator, +{ +} + +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HashMap +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// // You can specify all types of HashMap, including hasher and allocator. + /// // Created map is empty and don't allocate memory + /// let map: HashMap = Default::default(); + /// assert_eq!(map.capacity(), 0); + /// let map: HashMap = HashMap::default(); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::with_hasher_in(Default::default(), Default::default()) + } +} + +impl Index<&Q> for HashMap +where + K: Eq + Hash, + Q: Hash + Equivalent + ?Sized, + S: BuildHasher, + A: Allocator, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", "One"), ("b", "Two")].into(); + /// + /// assert_eq!(map[&"a"], "One"); + /// assert_eq!(map[&"b"], "Two"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "default-hasher")] +impl From<[(K, V); N]> for HashMap +where + K: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map1 = HashMap::from([(1, 2), (3, 4)]); + /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + arr.into_iter().collect() + } +} + +/// An iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a V)`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((&1, &"a")), Some((&2, &"b")), Some((&3, &"c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct Iter<'a, K, V> { + inner: RawIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a mut V)`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut iter = map.iter_mut(); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct IterMut<'a, K, V> { + inner: RawIter<(K, V)>, + // To ensure invariance with respect to V + marker: PhantomData<(&'a K, &'a mut V)>, +} + +// We override the default Send impl which has K: Sync instead of K: Send. Both +// are correct, but this one is more general since it allows keys which +// implement Send but not Sync. +unsafe impl Send for IterMut<'_, K, V> {} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.into_iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `IntoIter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct IntoIter { + inner: RawIntoIter<(K, V), A>, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `K`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_keys`]: struct.HashMap.html#method.into_keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.into_keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `IntoKeys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(1), Some(2), Some(3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct IntoKeys { + inner: IntoIter, +} + +impl Default for IntoKeys { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} + +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(k, _)| k)) + .finish() + } +} + +/// An owning iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `V`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. The map cannot be used after calling that method. +/// +/// [`into_values`]: struct.HashMap.html#method.into_values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.into_values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `IntoValues` iterator produces values in arbitrary order, so +/// // the values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some("a"), Some("b"), Some("c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct IntoValues { + inner: IntoIter, +} + +impl Default for IntoValues { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} + +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, v)| v)) + .finish() + } +} + +/// An iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a K`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `Keys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&1), Some(&2), Some(&3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct Keys<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Keys { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a V`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `Values` iterator produces values in arbitrary order, so the +/// // values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&"a"), Some(&"b"), Some(&"c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct Values<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Values { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap` in arbitrary +/// order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut drain_iter = map.drain(); +/// let mut vec = vec![drain_iter.next(), drain_iter.next(), drain_iter.next()]; +/// +/// // The `Drain` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(drain_iter.next(), None); +/// assert_eq!(drain_iter.next(), None); +/// ``` +pub struct Drain<'a, K, V, A: Allocator = Global> { + inner: RawDrain<'a, (K, V), A>, +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate +/// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashMap.html#method.extract_if +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut extract_if = map.extract_if(|k, _v| k % 2 != 0); +/// let mut vec = vec![extract_if.next(), extract_if.next()]; +/// +/// // The `ExtractIf` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")),Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(extract_if.next(), None); +/// assert_eq!(extract_if.next(), None); +/// drop(extract_if); +/// +/// assert_eq!(map.len(), 1); +/// ``` +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, (K, V), A>, +} + +impl Iterator for ExtractIf<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator, +{ + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +/// A mutable iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a mut V`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut values = map.values_mut(); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct ValuesMut<'a, K, V> { + inner: IterMut<'a, K, V>, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let entry: Entry<_, _, _> = map.entry("a"); +/// let _raw_o: OccupiedEntry<_, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5), ("f", 6)]); +/// ``` +pub enum Entry<'a, K, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, K, V, S, A>), +} + +impl Debug for Entry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a [`HashMap`]. +/// It is part of the [`Entry`] and [`EntryRef`] enums. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// let _entry_o: OccupiedEntry<_, _, _> = map.entry("a").insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.get(&"c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl Send for OccupiedEntry<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl Debug for OccupiedEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, VacantEntry}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// let entry_v: VacantEntry<_, _, _> = match map.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry("b") { +/// Entry::Occupied(_) => unreachable!(), +/// Entry::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: K, + table: &'a mut HashMap, +} + +impl Debug for VacantEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied, +/// with any borrowed form of the map's key type. +/// +/// +/// This `enum` is constructed from the [`entry_ref`] method on [`HashMap`]. +/// +/// [`Hash`] and [`Eq`] on the borrowed form of the map's key type *must* match those +/// for the key type. It also require that key may be constructed from the borrowed +/// form through the [`From`] trait. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry_ref`]: struct.HashMap.html#method.entry_ref +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let key = String::from("a"); +/// let entry: EntryRef<_, _, _, _> = map.entry_ref(&key); +/// let _raw_o: OccupiedEntry<_, _, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry_ref("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry_ref("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry_ref("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry_ref("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry_ref("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// for (key, value) in ["a", "b", "c", "d", "e", "f"].into_iter().zip(1..=6) { +/// assert_eq!(map[key], value) +/// } +/// assert_eq!(map.len(), 6); +/// ``` +pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap<_, _> = [("a".to_owned(), 100), ("b".into(), 200)].into(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Vacant(_) => unreachable!(), + /// EntryRef::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Occupied(_) => unreachable!(), + /// EntryRef::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>), +} + +impl Debug for EntryRef<'_, '_, K, Q, V, S, A> +where + K: Debug + Borrow, + Q: Debug + ?Sized, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + EntryRef::Vacant(ref v) => f.debug_tuple("EntryRef").field(v).finish(), + EntryRef::Occupied(ref o) => f.debug_tuple("EntryRef").field(o).finish(), + } + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// [`EntryRef`]: enum.EntryRef.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, VacantEntryRef}; +/// +/// let mut map = HashMap::::new(); +/// +/// let entry_v: VacantEntryRef<_, _, _, _> = match map.entry_ref("a") { +/// EntryRef::Vacant(view) => view, +/// EntryRef::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map["a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry_ref("b") { +/// EntryRef::Occupied(_) => unreachable!(), +/// EntryRef::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map["b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: &'b Q, + table: &'a mut HashMap, +} + +impl Debug for VacantEntryRef<'_, '_, K, Q, V, S, A> +where + K: Borrow, + Q: Debug + ?Sized, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntryRef").field(&self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, OccupiedError}; +/// +/// let mut map: HashMap<_, _> = [("a", 10), ("b", 20)].into(); +/// +/// // try_insert method returns mutable reference to the value if keys are vacant, +/// // but if the map did have key present, nothing is updated, and the provided +/// // value is returned inside `Err(_)` variant +/// match map.try_insert("a", 100) { +/// Err(OccupiedError { mut entry, value }) => { +/// assert_eq!(entry.key(), &"a"); +/// assert_eq!(value, 100); +/// assert_eq!(entry.insert(100), 10) +/// } +/// _ => unreachable!(), +/// } +/// assert_eq!(map[&"a"], 100); +/// ``` +pub struct OccupiedError<'a, K, V, S, A: Allocator = Global> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, S, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +impl Debug for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +impl fmt::Display for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// Return the same `Iter` struct as by the [`iter`] method on [`HashMap`]. + /// + /// [`iter`]: struct.HashMap.html#method.iter + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map_one: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); + /// let mut map_two = HashMap::new(); + /// + /// for (key, value) in &map_one { + /// println!("Key: {}, Value: {}", key, value); + /// map_two.insert(*key, *value); + /// } + /// + /// assert_eq!(map_one, map_two); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order + /// with mutable references to the values. The iterator element type is + /// `(&'a K, &'a mut V)`. + /// + /// Return the same `IterMut` struct as by the [`iter_mut`] method on + /// [`HashMap`]. + /// + /// [`iter_mut`]: struct.HashMap.html#method.iter_mut + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// for (key, value) in &mut map { + /// println!("Key: {}, Value: {}", key, value); + /// *value *= 2; + /// } + /// + /// let mut vec = map.iter().collect::>(); + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(&"a", &2), (&"b", &4), (&"c", &6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// // Not possible with .iter() + /// let mut vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so + /// // the items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.table.into_iter(), + } + } +} + +impl Default for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_ref(); + Some((&r.0, &r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_ref(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +impl Default for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_mut(); + Some((&r.0, &mut r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_mut(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Default for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +impl ExactSizeIterator for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Keys<'_, K, V> {} + +impl Default for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Values<'_, K, V> {} + +impl Default for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a mut V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, val)| val)) + .finish() + } +} + +impl Iterator for Drain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, K, V, A> {} + +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// let entry = map.entry("poneyland").or_insert_entry(3); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &3); + /// + /// // existing key + /// let mut entry = map.entry("poneyland").or_insert_entry(10); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_entry(self, default: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry("horseland").key(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } +} + +impl<'a, K, V: Default, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland", Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.key(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland", 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// let value: &mut u32; + /// match map.entry("poneyland") { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// match map.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the [`VacantEntry`]'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + /// Sets the value of the entry with the [`VacantEntry`]'s key, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + elem, + table: self.table, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let entry = map.entry_ref("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), "horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + match self { + EntryRef::Occupied(mut entry) => { + entry.insert(value); + entry + } + EntryRef::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function an access to the borrower form of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash + Borrow, + &'b Q: Into, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => { + let value = default(entry.key); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry_ref("horseland").key(), "horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + match *self { + EntryRef::Occupied(ref entry) => entry.key().borrow(), + EntryRef::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + EntryRef::Occupied(mut entry) => { + f(entry.get_mut()); + EntryRef::Occupied(entry) + } + EntryRef::Vacant(entry) => EntryRef::Vacant(entry), + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland".to_string(), Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry_ref("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(Default::default()), + } + } + + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// let entry = map.entry_ref("poneyland").or_default_entry(); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &None); + /// + /// // existing key + /// map.insert("horseland".to_string(), Some(3)); + /// let entry = map.entry_ref("horseland").or_default_entry(); + /// assert_eq!(entry.key(), &"horseland"); + /// assert_eq!(entry.get(), &Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default_entry(self) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry, + EntryRef::Vacant(entry) => entry.insert_entry(Default::default()), + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'a, 'b, K, Q, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntryRef`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// assert_eq!(map.entry_ref(key).key(), "poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &'b Q { + self.key + } + + /// Sets the value of the entry with the `VacantEntryRef`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// if let EntryRef::Vacant(o) = map.entry_ref(key) { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key.into(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + /// Sets the value of the entry with the [`VacantEntryRef`]'s key, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let EntryRef::Vacant(v) = map.entry_ref("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + &'b Q: Into, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key.into(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + elem, + table: self.table, + } + } +} + +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let mut map = + Self::with_capacity_and_hasher_in(iter.size_hint().0, S::default(), A::default()); + iter.for_each(|(k, v)| { + map.insert(k, v); + }); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let some_iter = [(1, 1), (2, 2)].into_iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr); + /// let old_map_len = map.len(); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(map); + /// assert_eq!(new_map.len(), old_map_len); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { + additional + } else { + (additional + 1) / 2 + }; + self.reserve(reserve); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter().map(|(k, v)| (k, v)); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec.iter().map(|(k, v)| (k, v))); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr.iter().map(|(k, v)| (k, v))); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(&map); + /// assert_eq!(new_map, map); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (&'a K, &'a V)) { + self.insert(*k, *v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<&'a (K, V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(&some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(&some_arr); + /// + /// let mut vec: Vec<_> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|&(key, value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, &(k, v): &'a (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new, A: Allocator>( + v: IntoIter<&'static str, u8, A>, + ) -> IntoIter<&'new str, u8, A> { + v + } + fn into_iter_val<'new, A: Allocator>( + v: IntoIter, + ) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} + +#[cfg(test)] +mod test_map { + use super::DefaultHashBuilder; + use super::Entry::{Occupied, Vacant}; + use super::EntryRef; + use super::HashMap; + use crate::raw::{AllocError, Allocator, Global}; + use alloc::string::{String, ToString}; + use alloc::sync::Arc; + use core::alloc::Layout; + use core::ptr::NonNull; + use core::sync::atomic::{AtomicI8, Ordering}; + use rand::{rngs::SmallRng, Rng, SeedableRng}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); + } + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + #[test] + fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + #[allow(clippy::redundant_clone)] + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + #[test] + fn test_clone_from() { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + m2.clone_from(&m); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + thread_local! { static DROP_VECTOR: RefCell> = const { RefCell::new(Vec::new()) } } + + #[derive(Hash, PartialEq, Eq)] + struct Droppable { + k: usize, + } + + impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } + } + + impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Droppable { + fn clone(&self) -> Self { + Droppable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_entry_ref() { + let mut m: HashMap = HashMap::new(); + match m.entry_ref("poneyland") { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(_) => {} + } + assert!(*m.entry_ref("poneyland").or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: takes too long + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); + let mut hashmap: HashMap = HashMap::default(); + let key = &1; + let result = hashmap.get_mut(key); + assert!(result.is_none()); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(1, 3).is_some()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_insert_unique_unchecked() { + let mut map = HashMap::new(); + let (k1, v1) = unsafe { map.insert_unique_unchecked(10, 11) }; + assert_eq!((&10, &mut 11), (k1, v1)); + let (k2, v2) = unsafe { map.insert_unique_unchecked(20, 21) }; + assert_eq!((&20, &mut 21), (k2, v2)); + assert_eq!(Some(&11), map.get(&10)); + assert_eq!(Some(&21), map.get(&20)); + assert_eq!(None, map.get(&30)); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2; + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{map:?}"); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.raw_capacity(), 1); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); + + assert_eq!(raw_cap, initial_raw_cap * 2); + + let mut i = 0; + for _ in 0..raw_cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.raw_capacity(), raw_cap); + + for _ in 0..raw_cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); + + for _ in 0..raw_cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.raw_capacity(), new_raw_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.raw_capacity(), raw_cap); + // again, a little more than half full + for _ in 0..raw_cap / 2 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.raw_capacity(), initial_raw_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + #[allow(clippy::no_effect)] // false positive lint + map[&4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_ref() { + let xs = [ + ("One".to_owned(), 10), + ("Two".to_owned(), 20), + ("Three".to_owned(), 30), + ("Four".to_owned(), 40), + ("Five".to_owned(), 50), + ("Six".to_owned(), 60), + ]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry_ref("One") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get("One").unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry_ref("Two") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get("Two").unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry_ref("Three") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get("Three"), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry_ref("Ten") { + EntryRef::Occupied(_) => unreachable!(), + EntryRef::Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get("Ten").unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_entry_ref_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + match m.entry_ref(x.as_str()) { + EntryRef::Vacant(_) => {} + EntryRef::Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_extend_ref_k_ref_v() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref_kv_tuple() { + use std::ops::AddAssign; + let mut a = HashMap::new(); + a.insert(0, 0); + + fn create_arr + Copy, const N: usize>(start: T, step: T) -> [(T, T); N] { + let mut outs: [(T, T); N] = [(start, start); N]; + let mut element = step; + outs.iter_mut().skip(1).for_each(|(k, v)| { + *k += element; + *v += element; + element += step; + }); + outs + } + + let for_iter: Vec<_> = (0..100).map(|i| (i, i)).collect(); + let iter = for_iter.iter(); + let vec: Vec<_> = (100..200).map(|i| (i, i)).collect(); + a.extend(iter); + a.extend(&vec); + a.extend(create_arr::(200, 1)); + + assert_eq!(a.len(), 300); + + for item in 0..300 { + assert_eq!(a[&item], item); + } + } + + #[test] + fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); + } + + #[test] + fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key, value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_ref_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.to_owned(), value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry_ref(key) { + EntryRef::Vacant(_) => panic!(), + EntryRef::Occupied(e) => assert_eq!(key, e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_ref_key() { + let mut a: HashMap = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry_ref(key) { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(e) => { + assert_eq!(key, e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } + + #[test] + fn test_extract_if() { + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + let drained = map.extract_if(|&k, _| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(map.len(), 4); + } + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + map.extract_if(|&k, _| k % 2 == 0).for_each(drop); + assert_eq!(map.len(), 4); + } + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) + fn test_try_reserve() { + use crate::TryReserveError::{AllocError, CapacityOverflow}; + + const MAX_ISIZE: usize = isize::MAX as usize; + + let mut empty_bytes: HashMap = HashMap::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(usize::MAX) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_ISIZE) { + } else { + panic!("isize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_ISIZE / 5) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a few more hashmaps to ensure the allocation will fail. + let mut empty_bytes2: HashMap = HashMap::new(); + let _ = empty_bytes2.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes3: HashMap = HashMap::new(); + let _ = empty_bytes3.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes4: HashMap = HashMap::new(); + if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_ISIZE / 5) { + } else { + panic!("isize::MAX / 5 should trigger an OOM!"); + } + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP; + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } + + #[test] + fn test_get_many_mut() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + map.insert("bar".to_owned(), 10); + map.insert("baz".to_owned(), 20); + map.insert("qux".to_owned(), 30); + + let xs = map.get_many_mut(["foo", "qux"]); + assert_eq!(xs, [Some(&mut 0), Some(&mut 30)]); + + let xs = map.get_many_mut(["foo", "dud"]); + assert_eq!(xs, [Some(&mut 0), None]); + + let ys = map.get_many_key_value_mut(["bar", "baz"]); + assert_eq!( + ys, + [ + Some((&"bar".to_owned(), &mut 10)), + Some((&"baz".to_owned(), &mut 20)) + ], + ); + + let ys = map.get_many_key_value_mut(["bar", "dip"]); + assert_eq!(ys, [Some((&"bar".to_string(), &mut 10)), None]); + } + + #[test] + #[should_panic = "duplicate keys found"] + fn test_get_many_mut_duplicate() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + + let _xs = map.get_many_mut(["foo", "foo"]); + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_from_double_drop() { + #[derive(Clone)] + struct CheckedDrop { + panic_in_drop: bool, + dropped: bool, + } + impl Drop for CheckedDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + const DISARMED: CheckedDrop = CheckedDrop { + panic_in_drop: false, + dropped: false, + }; + const ARMED: CheckedDrop = CheckedDrop { + panic_in_drop: true, + dropped: false, + }; + + let mut map1 = HashMap::new(); + map1.insert(1, DISARMED); + map1.insert(2, DISARMED); + map1.insert(3, DISARMED); + map1.insert(4, DISARMED); + + let mut map2 = HashMap::new(); + map2.insert(1, DISARMED); + map2.insert(2, ARMED); + map2.insert(3, DISARMED); + map2.insert(4, DISARMED); + + map2.clone_from(&map1); + } + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_from_memory_leaks() { + use alloc::vec::Vec; + + struct CheckedClone { + panic_in_clone: bool, + need_drop: Vec, + } + impl Clone for CheckedClone { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + need_drop: self.need_drop.clone(), + } + } + } + let mut map1 = HashMap::new(); + map1.insert( + 1, + CheckedClone { + panic_in_clone: false, + need_drop: vec![0, 1, 2], + }, + ); + map1.insert( + 2, + CheckedClone { + panic_in_clone: false, + need_drop: vec![3, 4, 5], + }, + ); + map1.insert( + 3, + CheckedClone { + panic_in_clone: true, + need_drop: vec![6, 7, 8], + }, + ); + let _map2 = map1.clone(); + } + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl MyAlloc { + fn new(drop_count: Arc) -> Self { + MyAlloc { + _inner: Arc::new(MyAllocInner { drop_count }), + } + } + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + #[test] + fn test_hashmap_into_iter_bug() { + let dropped: Arc = Arc::new(AtomicI8::new(1)); + + { + let mut map = HashMap::with_capacity_in(10, MyAlloc::new(dropped.clone())); + for i in 0..10 { + map.entry(i).or_insert_with(|| "i".to_string()); + } + + for (k, v) in map { + println!("{k}, {v}"); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[derive(Debug)] + struct CheckedCloneDrop { + panic_in_clone: bool, + panic_in_drop: bool, + dropped: bool, + data: T, + } + + impl CheckedCloneDrop { + fn new(panic_in_clone: bool, panic_in_drop: bool, data: T) -> Self { + CheckedCloneDrop { + panic_in_clone, + panic_in_drop, + dropped: false, + data, + } + } + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + panic_in_drop: self.panic_in_drop, + dropped: self.dropped, + data: self.data.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + /// Return hashmap with predefined distribution of elements. + /// All elements will be located in the same order as elements + /// returned by iterator. + /// + /// This function does not panic, but returns an error as a `String` + /// to distinguish between a test panic and an error in the input data. + fn get_test_map( + iter: I, + mut fun: impl FnMut(u64) -> T, + alloc: A, + ) -> Result, DefaultHashBuilder, A>, String> + where + I: Iterator + Clone + ExactSizeIterator, + A: Allocator, + T: PartialEq + core::fmt::Debug, + { + use crate::scopeguard::guard; + + let mut map: HashMap, _, A> = + HashMap::with_capacity_in(iter.size_hint().0, alloc); + { + let mut guard = guard(&mut map, |map| { + for (_, value) in map.iter_mut() { + value.panic_in_drop = false + } + }); + + let mut count = 0; + // Hash and Key must be equal to each other for controlling the elements placement. + for (panic_in_clone, panic_in_drop) in iter.clone() { + if core::mem::needs_drop::() && panic_in_drop { + return Err(String::from( + "panic_in_drop can be set with a type that doesn't need to be dropped", + )); + } + guard.table.insert( + count, + ( + count, + CheckedCloneDrop::new(panic_in_clone, panic_in_drop, fun(count)), + ), + |(k, _)| *k, + ); + count += 1; + } + + // Let's check that all elements are located as we wanted + let mut check_count = 0; + for ((key, value), (panic_in_clone, panic_in_drop)) in guard.iter().zip(iter) { + if *key != check_count { + return Err(format!( + "key != check_count,\nkey: `{key}`,\ncheck_count: `{check_count}`" + )); + } + if value.dropped + || value.panic_in_clone != panic_in_clone + || value.panic_in_drop != panic_in_drop + || value.data != fun(check_count) + { + return Err(format!( + "Value is not equal to expected,\nvalue: `{:?}`,\nexpected: \ + `CheckedCloneDrop {{ panic_in_clone: {}, panic_in_drop: {}, dropped: {}, data: {:?} }}`", + value, panic_in_clone, panic_in_drop, false, fun(check_count) + )); + } + check_count += 1; + } + + if guard.len() != check_count as usize { + return Err(format!( + "map.len() != check_count,\nmap.len(): `{}`,\ncheck_count: `{}`", + guard.len(), + check_count + )); + } + + if count != check_count { + return Err(format!( + "count != check_count,\ncount: `{count}`,\ncheck_count: `{check_count}`" + )); + } + core::mem::forget(guard); + } + Ok(map) + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + const ARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + const DISARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_memory_leaks_and_double_drop_one() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap>, DefaultHashBuilder, MyAlloc> = + match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // Clone should normally clone a few elements, and then (when the + // clone function panics), deallocate both its own memory, memory + // of `dropped: Arc` and the memory of already cloned + // elements (Vec memory inside CheckedCloneDrop). + let _map2 = map.clone(); + } + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_memory_leaks_and_double_drop_two() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap, DefaultHashBuilder, _> = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + let mut map2 = match get_test_map( + DISARMED_FLAGS.into_iter().zip(ARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // The `clone_from` should try to drop the elements of `map2` without + // double drop and leaking the allocator. Elements that have not been + // dropped leak their memory. + map2.clone_from(&map); + } + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| vec![n * 2], MyAlloc::new(dropped.clone())) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() != scope_map.table.buckets() { + return format!( + "map.table.buckets() != scope_map.table.buckets(),\nleft: `{}`,\nright: `{}`", + map.table.buckets(), scope_map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are not equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_not_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + [DISARMED].into_iter().zip([DISARMED]), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n * 2], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() == scope_map.table.buckets() { + return format!( + "map.table.buckets() == scope_map.table.buckets(): `{}`", + map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[test] + fn test_allocation_info() { + assert_eq!(HashMap::<(), ()>::new().allocation_size(), 0); + assert_eq!(HashMap::::new().allocation_size(), 0); + assert!( + HashMap::::with_capacity(1).allocation_size() > core::mem::size_of::() + ); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/raw/alloc.rs b/deps/crates/vendor/hashbrown-0.15.5/src/raw/alloc.rs new file mode 100644 index 00000000000000..c01e2a45c3c07a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/raw/alloc.rs @@ -0,0 +1,92 @@ +#[cfg(test)] +pub(crate) use self::inner::AllocError; +pub(crate) use self::inner::{do_alloc, Allocator, Global}; + +// Nightly-case. +// Use unstable `allocator_api` feature. +// This is compatible with `allocator-api2` which can be enabled or not. +// This is used when building for `std`. +#[cfg(feature = "nightly")] +mod inner { + #[cfg(test)] + pub use crate::alloc::alloc::AllocError; + use crate::alloc::alloc::Layout; + pub use crate::alloc::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.as_non_null_ptr()), + Err(_) => Err(()), + } + } +} + +// Basic non-nightly case. +// This uses `allocator-api2` enabled by default. +// If any crate enables "nightly" in `allocator-api2`, +// this will be equivalent to the nightly case, +// since `allocator_api2::alloc::Allocator` would be re-export of +// `core::alloc::Allocator`. +#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] +mod inner { + use crate::alloc::alloc::Layout; + #[cfg(test)] + pub use allocator_api2::alloc::AllocError; + pub use allocator_api2::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.cast()), + Err(_) => Err(()), + } + } +} + +// No-defaults case. +// When building with default-features turned off and +// neither `nightly` nor `allocator-api2` is enabled, +// this will be used. +// Making it impossible to use any custom allocator with collections defined +// in this crate. +// Any crate in build-tree can enable `allocator-api2`, +// or `nightly` without disturbing users that don't want to use it. +#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] +mod inner { + use crate::alloc::alloc::{alloc, dealloc, Layout}; + use core::ptr::NonNull; + + #[allow(clippy::missing_safety_doc)] // not exposed outside of this crate + pub unsafe trait Allocator { + fn allocate(&self, layout: Layout) -> Result, ()>; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + } + + #[derive(Copy, Clone)] + pub struct Global; + + unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, ()> { + unsafe { NonNull::new(alloc(layout)).ok_or(()) } + } + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout); + } + } + + impl Default for Global { + #[inline] + fn default() -> Self { + Global + } + } + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc.allocate(layout) + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/raw/mod.rs b/deps/crates/vendor/hashbrown-0.15.5/src/raw/mod.rs new file mode 100644 index 00000000000000..c0d82a1b5c8c17 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/raw/mod.rs @@ -0,0 +1,4436 @@ +use crate::alloc::alloc::{handle_alloc_error, Layout}; +use crate::control::{BitMaskIter, Group, Tag, TagSliceExt}; +use crate::scopeguard::{guard, ScopeGuard}; +use crate::util::{invalid_mut, likely, unlikely}; +use crate::TryReserveError; +use core::array; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use core::slice; +use core::{hint, ptr}; + +mod alloc; +#[cfg(test)] +pub(crate) use self::alloc::AllocError; +pub(crate) use self::alloc::{do_alloc, Allocator, Global}; + +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + to.offset_from(from) as usize +} + +/// Whether memory allocation errors should return an error or abort. +#[derive(Copy, Clone)] +enum Fallibility { + Fallible, + Infallible, +} + +impl Fallibility { + /// Error to return on capacity overflow. + #[cfg_attr(feature = "inline-more", inline)] + fn capacity_overflow(self) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::CapacityOverflow, + Fallibility::Infallible => panic!("Hash table capacity overflow"), + } + } + + /// Error to return on allocation error. + #[cfg_attr(feature = "inline-more", inline)] + fn alloc_err(self, layout: Layout) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::AllocError { layout }, + Fallibility::Infallible => handle_alloc_error(layout), + } + } +} + +trait SizedTypeProperties: Sized { + const IS_ZERO_SIZED: bool = mem::size_of::() == 0; + const NEEDS_DROP: bool = mem::needs_drop::(); +} + +impl SizedTypeProperties for T {} + +/// Primary hash function, used to select the initial bucket to probe from. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h1(hash: u64) -> usize { + // On 32-bit platforms we simply ignore the higher hash bits. + hash as usize +} + +/// Probe sequence based on triangular numbers, which is guaranteed (since our +/// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// +#[derive(Clone)] +struct ProbeSeq { + pos: usize, + stride: usize, +} + +impl ProbeSeq { + #[inline] + fn move_next(&mut self, bucket_mask: usize) { + // We should have found an empty bucket by now and ended the probe. + debug_assert!( + self.stride <= bucket_mask, + "Went past end of probe sequence" + ); + + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= bucket_mask; + } +} + +/// Returns the number of buckets needed to hold the given number of items, +/// taking the maximum load factor into account. +/// +/// Returns `None` if an overflow occurs. +// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258 +#[cfg_attr(target_os = "emscripten", inline(never))] +#[cfg_attr(not(target_os = "emscripten"), inline)] +fn capacity_to_buckets(cap: usize, table_layout: TableLayout) -> Option { + debug_assert_ne!(cap, 0); + + // For small tables we require at least 1 empty bucket so that lookups are + // guaranteed to terminate if an element doesn't exist in the table. + if cap < 15 { + // Consider a small TableLayout like { size: 1, ctrl_align: 16 } on a + // platform with Group::WIDTH of 16 (like x86_64 with SSE2). For small + // bucket sizes, this ends up wasting quite a few bytes just to pad to + // the relatively larger ctrl_align: + // + // | capacity | buckets | bytes allocated | bytes per item | + // | -------- | ------- | --------------- | -------------- | + // | 3 | 4 | 36 | (Yikes!) 12.0 | + // | 7 | 8 | 40 | (Poor) 5.7 | + // | 14 | 16 | 48 | 3.4 | + // | 28 | 32 | 80 | 3.3 | + // + // In general, buckets * table_layout.size >= table_layout.ctrl_align + // must be true to avoid these edges. This is implemented by adjusting + // the minimum capacity upwards for small items. This code only needs + // to handle ctrl_align which are less than or equal to Group::WIDTH, + // because valid layout sizes are always a multiple of the alignment, + // so anything with alignment over the Group::WIDTH won't hit this edge + // case. + + // This is brittle, e.g. if we ever add 32 byte groups, it will select + // 3 regardless of the table_layout.size. + let min_cap = match (Group::WIDTH, table_layout.size) { + (16, 0..=1) => 14, + (16, 2..=3) => 7, + (8, 0..=1) => 7, + _ => 3, + }; + let cap = min_cap.max(cap); + // We don't bother with a table size of 2 buckets since that can only + // hold a single element. Instead, we skip directly to a 4 bucket table + // which can hold 3 elements. + return Some(if cap < 4 { + 4 + } else if cap < 8 { + 8 + } else { + 16 + }); + } + + // Otherwise require 1/8 buckets to be empty (87.5% load) + // + // Be careful when modifying this, calculate_layout relies on the + // overflow check here. + let adjusted_cap = cap.checked_mul(8)? / 7; + + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous division). + Some(adjusted_cap.next_power_of_two()) +} + +/// Returns the maximum effective capacity for the given bucket mask, taking +/// the maximum load factor into account. +#[inline] +fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { + if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. + bucket_mask + } else { + // For larger tables we reserve 12.5% of the slots as empty. + ((bucket_mask + 1) / 8) * 7 + } +} + +/// Helper which allows the max calculation for `ctrl_align` to be statically computed for each `T` +/// while keeping the rest of `calculate_layout_for` independent of `T` +#[derive(Copy, Clone)] +struct TableLayout { + size: usize, + ctrl_align: usize, +} + +impl TableLayout { + #[inline] + const fn new() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size(), + ctrl_align: if layout.align() > Group::WIDTH { + layout.align() + } else { + Group::WIDTH + }, + } + } + + #[inline] + fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> { + debug_assert!(buckets.is_power_of_two()); + + let TableLayout { size, ctrl_align } = self; + // Manual layout calculation since Layout methods are not yet stable. + let ctrl_offset = + size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); + let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + + // We need an additional check to ensure that the allocation doesn't + // exceed `isize::MAX` (https://github.com/rust-lang/rust/pull/95295). + if len > isize::MAX as usize - (ctrl_align - 1) { + return None; + } + + Some(( + unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, + ctrl_offset, + )) + } +} + +/// A reference to an empty bucket into which an can be inserted. +pub struct InsertSlot { + index: usize, +} + +/// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. +pub struct Bucket { + // Actually it is pointer to next element than element itself + // this is needed to maintain pointer arithmetic invariants + // keeping direct pointer to element introduces difficulty. + // Using `NonNull` for variance and niche layout + ptr: NonNull, +} + +// This Send impl is needed for rayon support. This is safe since Bucket is +// never exposed in a public API. +unsafe impl Send for Bucket {} + +impl Clone for Bucket { + #[inline] + fn clone(&self) -> Self { + Self { ptr: self.ptr } + } +} + +impl Bucket { + /// Creates a [`Bucket`] that contain pointer to the data. + /// The pointer calculation is performed by calculating the + /// offset from given `base` pointer (convenience for + /// `base.as_ptr().sub(index)`). + /// + /// `index` is in units of `T`; e.g., an `index` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// If the `T` is a ZST, then we instead track the index of the element + /// in the table so that `erase` works properly (return + /// `NonNull::new_unchecked((index + 1) as *mut T)`) + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and the safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for the [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * the `base` pointer must not be `dangling` and must points to the + /// end of the first `value element` from the `data part` of the table, i.e. + /// must be the pointer that returned by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn from_base_index(base: NonNull, index: usize) -> Self { + // If mem::size_of::() != 0 then return a pointer to an `element` in + // the data part of the table (we start counting from "0", so that + // in the expression T[last], the "last" index actually one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"): + // + // `from_base_index(base, 1).as_ptr()` returns a pointer that + // points here in the data part of the table + // (to the start of T1) + // | + // | `base: NonNull` must point here + // | (to the end of T0 or to the start of C0) + // v v + // [Padding], Tlast, ..., |T1|, T0, |C0, C1, ..., Clast + // ^ + // `from_base_index(base, 1)` returns a pointer + // that points here in the data part of the table + // (to the end of T1) + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes + // or metadata for data. + let ptr = if T::IS_ZERO_SIZED { + // won't overflow because index must be less than length (bucket_mask) + // and bucket_mask is guaranteed to be less than `isize::MAX` + // (see TableLayout::calculate_layout_for method) + invalid_mut(index + 1) + } else { + base.as_ptr().sub(index) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Calculates the index of a [`Bucket`] as distance between two pointers + /// (convenience for `base.as_ptr().offset_from(self.ptr.as_ptr()) as usize`). + /// The returned value is in units of T: the distance in bytes divided by + /// [`core::mem::size_of::()`]. + /// + /// If the `T` is a ZST, then we return the index of the element in + /// the table so that `erase` works properly (return `self.ptr.as_ptr() as usize - 1`). + /// + /// This function is the inverse of [`from_base_index`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*const T>::offset_from`] method of `*const T`. + /// + /// Thus, in order to uphold the safety contracts for [`<*const T>::offset_from`] + /// method, as well as for the correct logic of the work of this crate, the + /// following rules are necessary and sufficient: + /// + /// * `base` contained pointer must not be `dangling` and must point to the + /// end of the first `element` from the `data part` of the table, i.e. + /// must be a pointer that returns by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `self` also must not contain dangling pointer; + /// + /// * both `self` and `base` must be created from the same [`RawTable`] + /// (or [`RawTableInner`]). + /// + /// If `mem::size_of::() == 0`, this function is always safe. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`from_base_index`]: crate::raw::Bucket::from_base_index + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTableInner`]: RawTableInner + /// [`<*const T>::offset_from`]: https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.offset_from + #[inline] + unsafe fn to_base_index(&self, base: NonNull) -> usize { + // If mem::size_of::() != 0 then return an index under which we used to store the + // `element` in the data part of the table (we start counting from "0", so + // that in the expression T[last], the "last" index actually is one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"). + // For example for 5th element in table calculation is performed like this: + // + // mem::size_of::() + // | + // | `self = from_base_index(base, 5)` that returns pointer + // | that points here in the data part of the table + // | (to the end of T5) + // | | `base: NonNull` must point here + // v | (to the end of T0 or to the start of C0) + // /???\ v v + // [Padding], Tlast, ..., |T10|, ..., T5|, T4, T3, T2, T1, T0, |C0, C1, C2, C3, C4, C5, ..., C10, ..., Clast + // \__________ __________/ + // \/ + // `bucket.to_base_index(base)` = 5 + // (base.as_ptr() as usize - self.ptr.as_ptr() as usize) / mem::size_of::() + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes or metadata for data. + if T::IS_ZERO_SIZED { + // this can not be UB + self.ptr.as_ptr() as usize - 1 + } else { + offset_from(base.as_ptr(), self.ptr.as_ptr()) + } + } + + /// Acquires the underlying raw pointer `*mut T` to `data`. + /// + /// # Note + /// + /// If `T` is not [`Copy`], do not use `*mut T` methods that can cause calling the + /// destructor of `T` (for example the [`<*mut T>::drop_in_place`] method), because + /// for properly dropping the data we also need to clear `data` control bytes. If we + /// drop data, but do not clear `data control byte` it leads to double drop when + /// [`RawTable`] goes out of scope. + /// + /// If you modify an already initialized `value`, so [`Hash`] and [`Eq`] on the new + /// `T` value and its borrowed form *must* match those for the old `T` value, as the map + /// will not re-evaluate where the new value should go, meaning the value may become + /// "lost" if their location does not reflect their state. + /// + /// [`RawTable`]: crate::raw::RawTable + /// [`<*mut T>::drop_in_place`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.drop_in_place + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[inline] + pub fn as_ptr(&self) -> *mut T { + if T::IS_ZERO_SIZED { + // Just return an arbitrary ZST pointer which is properly aligned + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) + } else { + unsafe { self.ptr.as_ptr().sub(1) } + } + } + + /// Acquires the underlying non-null pointer `*mut T` to `data`. + #[inline] + fn as_non_null(&self) -> NonNull { + // SAFETY: `self.ptr` is already a `NonNull` + unsafe { NonNull::new_unchecked(self.as_ptr()) } + } + + /// Create a new [`Bucket`] that is offset from the `self` by the given + /// `offset`. The pointer calculation is performed by calculating the + /// offset from `self` pointer (convenience for `self.ptr.as_ptr().sub(offset)`). + /// This function is used for iterators. + /// + /// `offset` is in units of `T`; e.g., a `offset` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * `self` contained pointer must not be `dangling`; + /// + /// * `self.to_base_index() + offset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + offset) <= RawTableInner.bucket_mask` or, in other + /// words, `self.to_base_index() + offset + 1` must be no greater than the number returned + /// by the function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `self.to_base_index() + offset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + offset) <= RawTableInner.bucket_mask` or, in other words, + /// `self.to_base_index() + offset + 1` must be no greater than the number returned by the + /// function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn next_n(&self, offset: usize) -> Self { + let ptr = if T::IS_ZERO_SIZED { + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) + } else { + self.ptr.as_ptr().sub(offset) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Executes the destructor (if any) of the pointed-to `data`. + /// + /// # Safety + /// + /// See [`ptr::drop_in_place`] for safety concerns. + /// + /// You should use [`RawTable::erase`] instead of this function, + /// or be careful with calling this function directly, because for + /// properly dropping the data we need also clear `data` control bytes. + /// If we drop data, but do not erase `data control byte` it leads to + /// double drop when [`RawTable`] goes out of scope. + /// + /// [`ptr::drop_in_place`]: https://doc.rust-lang.org/core/ptr/fn.drop_in_place.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::erase`]: crate::raw::RawTable::erase + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn drop(&self) { + self.as_ptr().drop_in_place(); + } + + /// Reads the `value` from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// # Safety + /// + /// See [`ptr::read`] for safety concerns. + /// + /// You should use [`RawTable::remove`] instead of this function, + /// or be careful with calling this function directly, because compiler + /// calls its destructor when the read `value` goes out of scope. It + /// can cause double dropping when [`RawTable`] goes out of scope, + /// because of not erased `data control byte`. + /// + /// [`ptr::read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::remove`]: crate::raw::RawTable::remove + #[inline] + pub(crate) unsafe fn read(&self) -> T { + self.as_ptr().read() + } + + /// Overwrites a memory location with the given `value` without reading + /// or dropping the old value (like [`ptr::write`] function). + /// + /// # Safety + /// + /// See [`ptr::write`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::write`]: https://doc.rust-lang.org/core/ptr/fn.write.html + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[inline] + pub(crate) unsafe fn write(&self, val: T) { + self.as_ptr().write(val); + } + + /// Returns a shared immutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_ref`] for safety concerns. + /// + /// [`NonNull::as_ref`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_ref + #[inline] + pub unsafe fn as_ref<'a>(&self) -> &'a T { + &*self.as_ptr() + } + + /// Returns a unique mutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_mut`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`NonNull::as_mut`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_mut + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[inline] + pub unsafe fn as_mut<'a>(&self) -> &'a mut T { + &mut *self.as_ptr() + } +} + +/// A raw hash table with an unsafe API. +pub struct RawTable { + table: RawTableInner, + alloc: A, + // Tell dropck that we own instances of T. + marker: PhantomData, +} + +/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless +/// of how many different key-value types are used. +struct RawTableInner { + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. + bucket_mask: usize, + + // [Padding], T_n, ..., T1, T0, C0, C1, ... + // ^ points here + ctrl: NonNull, + + // Number of elements that can be inserted before we need to grow the table + growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn new() -> Self { + Self { + table: RawTableInner::NEW, + alloc: Global, + marker: PhantomData, + } + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } +} + +impl RawTable { + const TABLE_LAYOUT: TableLayout = TableLayout::new::(); + + /// Creates a new empty hash table without allocating any memory, using the + /// given allocator. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn new_in(alloc: A) -> Self { + Self { + table: RawTableInner::NEW, + alloc, + marker: PhantomData, + } + } + + /// Allocates a new hash table with the given number of buckets. + /// + /// The control bytes are left uninitialized. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + Ok(Self { + table: RawTableInner::new_uninitialized( + &alloc, + Self::TABLE_LAYOUT, + buckets, + fallibility, + )?, + alloc, + marker: PhantomData, + }) + } + + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + table: RawTableInner::with_capacity(&alloc, Self::TABLE_LAYOUT, capacity), + alloc, + marker: PhantomData, + } + } + + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub fn data_end(&self) -> NonNull { + // `self.table.ctrl.cast()` returns pointer that + // points here (to the end of `T0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTable::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + self.table.ctrl.cast() + } + + /// Returns pointer to start of data table. + #[inline] + #[cfg(feature = "nightly")] + pub unsafe fn data_start(&self) -> NonNull { + NonNull::new_unchecked(self.data_end().as_ptr().wrapping_sub(self.buckets())) + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + // SAFETY: We use the same `table_layout` that was used to allocate + // this table. + unsafe { self.table.allocation_size_or_zero(Self::TABLE_LAYOUT) } + } + + /// Returns the index of a bucket from a `Bucket`. + #[inline] + pub unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { + bucket.to_base_index(self.data_end()) + } + + /// Returns a pointer to an element in the table. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the caller of this function must observe the + /// following safety rules: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTable::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// [`RawTable::buckets`]: RawTable::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub unsafe fn bucket(&self, index: usize) -> Bucket { + // If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + // (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + // the "buckets" number of our `RawTable`, i.e. "n = RawTable::buckets() - 1"): + // + // `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + // part of the `RawTable`, i.e. to the start of T3 (see `Bucket::as_ptr`) + // | + // | `base = self.data_end()` points here + // | (to the start of CT0 or to the end of T0) + // v v + // [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + // ^ \__________ __________/ + // `table.bucket(3)` returns a pointer that points \/ + // here in the `data` part of the `RawTable` (to additional control bytes + // the end of T3) `m = Group::WIDTH - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`; + // CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + // the heap works properly, even if the result of `h1(hash) & self.table.bucket_mask` + // is equal to `self.table.bucket_mask`). See also `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.table.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.table.bucket_mask = self.buckets() - 1`. + debug_assert_ne!(self.table.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Erases an element from the table without dropping it. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn erase_no_drop(&mut self, item: &Bucket) { + let index = self.bucket_index(item); + self.table.erase(index); + } + + /// Erases an element from the table, dropping it in place. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn erase(&mut self, item: Bucket) { + // Erase the element from the table first since drop might panic. + self.erase_no_drop(&item); + item.drop(); + } + + /// Removes an element from the table, returning it. + /// + /// This also returns an `InsertSlot` pointing to the newly free bucket. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn remove(&mut self, item: Bucket) -> (T, InsertSlot) { + self.erase_no_drop(&item); + ( + item.read(), + InsertSlot { + index: self.bucket_index(&item), + }, + ) + } + + /// Finds and removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { self.remove(bucket).0 }), + None => None, + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear_no_drop(&mut self) { + self.table.clear_no_drop(); + } + + /// Removes all elements from the table without freeing the backing memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + if self.is_empty() { + // Special case empty table to avoid surprising O(capacity) time. + return; + } + // Ensure that the table is reset even if one of the drops panic + let mut self_ = guard(self, |self_| self_.clear_no_drop()); + unsafe { + // SAFETY: ScopeGuard sets to zero the `items` field of the table + // even in case of panic during the dropping of the elements so + // that there will be no double drop of the elements. + self_.table.drop_elements::(); + } + } + + /// Shrinks the table to fit `max(self.len(), min_size)` elements. + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. + let min_size = usize::max(self.table.items, min_size); + if min_size == 0 { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let min_buckets = match capacity_to_buckets(min_size, Self::TABLE_LAYOUT) { + Some(buckets) => buckets, + None => return, + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets < self.buckets() { + // Fast path if the table is empty + if self.table.items == 0 { + let new_inner = + RawTableInner::with_capacity(&self.alloc, Self::TABLE_LAYOUT, min_size); + let mut old_inner = mem::replace(&mut self.table, new_inner); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: + // 1. We know for sure that `min_size >= self.table.items`. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: The result of calling the `resize` function cannot be an error + // because `fallibility == Fallibility::Infallible. + hint::unreachable_unchecked() + } + } + } + } + } + + /// Ensures that at least `additional` items can be inserted into the table + /// without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + if unlikely(additional > self.table.growth_left) { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: All allocation errors will be caught inside `RawTableInner::reserve_rehash`. + hint::unreachable_unchecked() + } + } + } + } + + /// Tries to ensure that at least `additional` items can be inserted into + /// the table without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + if additional > self.table.growth_left { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Fallible) } + } else { + Ok(()) + } + } + + /// Out-of-line slow path for `reserve` and `try_reserve`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cold] + #[inline(never)] + unsafe fn reserve_rehash( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + unsafe { + // SAFETY: + // 1. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 2. The `drop` function is the actual drop function of the elements stored in + // the table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.reserve_rehash_inner( + &self.alloc, + additional, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + if T::NEEDS_DROP { + Some(|ptr| ptr::drop_in_place(ptr as *mut T)) + } else { + None + }, + ) + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// The caller of this function must ensure that `capacity >= self.table.items` + /// otherwise: + /// + /// * If `self.table.items != 0`, calling of this function with `capacity` + /// equal to 0 (`capacity == 0`) results in [`undefined behavior`]. + /// + /// * If `self.table.items > capacity_to_buckets(capacity, Self::TABLE_LAYOUT)` + /// calling this function are never return (will loop infinitely). + /// + /// See [`RawTableInner::find_insert_slot`] for more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn resize( + &mut self, + capacity: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + // SAFETY: + // 1. The caller of this function guarantees that `capacity >= self.table.items`. + // 2. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.resize_inner( + &self.alloc, + capacity, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + ) + } + + /// Inserts a new element into the table, and returns its raw bucket. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose `RawTable::new_uninitialized` in a public API. + // + // 2. We reserve additional space (if necessary) right after calling this function. + let mut slot = self.table.find_insert_slot(hash); + + // We can avoid growing the table once we have reached our load factor if we are replacing + // a tombstone. This works since the number of EMPTY slots does not change in this case. + // + // SAFETY: The function is guaranteed to return [`InsertSlot`] that contains an index + // in the range `0..=self.buckets()`. + let old_ctrl = *self.table.ctrl(slot.index); + if unlikely(self.table.growth_left == 0 && old_ctrl.special_is_empty()) { + self.reserve(1, hasher); + // SAFETY: We know for sure that `RawTableInner` has control bytes + // initialized and that there is extra space in the table. + slot = self.table.find_insert_slot(hash); + } + + self.insert_in_slot(hash, slot, value) + } + } + + /// Inserts a new element into the table, and returns a mutable reference to it. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T { + unsafe { self.insert(hash, value, hasher).as_mut() } + } + + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rustc-internal-api")] + pub unsafe fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { + let (index, old_ctrl) = self.table.prepare_insert_slot(hash); + let bucket = self.table.bucket(index); + + // If we are replacing a DELETED entry then we don't need to update + // the load counter. + self.table.growth_left -= old_ctrl.special_is_empty() as usize; + + bucket.write(value); + self.table.items += 1; + bucket + } + + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.table.ctrl(index); + debug_assert!(self.is_bucket_full(index)); + let old_growth_left = self.table.growth_left; + let item = self.remove(bucket).0; + if let Some(new_item) = f(item) { + self.table.growth_left = old_growth_left; + self.table.set_ctrl(index, old_ctrl); + self.table.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + + /// Searches for an element in the table. If the element is not found, + /// returns `Err` with the position of a slot where an element with the + /// same hash could be inserted. + /// + /// This function may resize the table if additional space is required for + /// inserting an element. + #[inline] + pub fn find_or_find_insert_slot( + &mut self, + hash: u64, + mut eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Result, InsertSlot> { + self.reserve(1, hasher); + + unsafe { + // SAFETY: + // 1. We know for sure that there is at least one empty `bucket` in the table. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since we will + // never expose `RawTable::new_uninitialized` in a public API. + // 3. The `find_or_find_insert_slot_inner` function returns the `index` of only the full bucket, + // which is in the range `0..self.buckets()` (since there is at least one empty `bucket` in + // the table), so calling `self.bucket(index)` and `Bucket::as_ref` is safe. + match self + .table + .find_or_find_insert_slot_inner(hash, &mut |index| eq(self.bucket(index).as_ref())) + { + // SAFETY: See explanation above. + Ok(index) => Ok(self.bucket(index)), + Err(slot) => Err(slot), + } + } + } + + /// Inserts a new element into the table in the given slot, and returns its + /// raw bucket. + /// + /// # Safety + /// + /// `slot` must point to a slot previously returned by + /// `find_or_find_insert_slot`, and no mutation of the table must have + /// occurred since that call. + #[inline] + pub unsafe fn insert_in_slot(&mut self, hash: u64, slot: InsertSlot, value: T) -> Bucket { + let old_ctrl = *self.table.ctrl(slot.index); + self.table.record_item_insert_at(slot.index, old_ctrl, hash); + + let bucket = self.bucket(slot.index); + bucket.write(value); + bucket + } + + /// Searches for an element in the table. + #[inline] + pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since we + // will never expose `RawTable::new_uninitialized` in a public API. + // 1. The `find_inner` function returns the `index` of only the full bucket, which is in + // the range `0..self.buckets()`, so calling `self.bucket(index)` and `Bucket::as_ref` + // is safe. + let result = self + .table + .find_inner(hash, &mut |index| eq(self.bucket(index).as_ref())); + + // Avoid `Option::map` because it bloats LLVM IR. + match result { + // SAFETY: See explanation above. + Some(index) => Some(self.bucket(index)), + None => None, + } + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + /// Gets a mutable reference to an element in the table. + #[inline] + pub fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + /// Attempts to get mutable references to `N` entries in the table at once. + /// + /// Returns an array of length `N` with the results of each query. + /// + /// At most one mutable reference will be returned to any entry. `None` will be returned if any + /// of the hashes are duplicates. `None` will be returned if the hash is not found. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + unsafe { + let ptrs = self.get_many_mut_pointers(hashes, eq); + + for (i, cur) in ptrs.iter().enumerate() { + if cur.is_some() && ptrs[..i].contains(cur) { + panic!("duplicate keys found"); + } + } + // All bucket are distinct from all previous buckets so we're clear to return the result + // of the lookup. + + ptrs.map(|ptr| ptr.map(|mut ptr| ptr.as_mut())) + } + } + + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + let ptrs = self.get_many_mut_pointers(hashes, eq); + ptrs.map(|ptr| ptr.map(|mut ptr| ptr.as_mut())) + } + + unsafe fn get_many_mut_pointers( + &mut self, + hashes: [u64; N], + mut eq: impl FnMut(usize, &T) -> bool, + ) -> [Option>; N] { + array::from_fn(|i| { + self.find(hashes[i], |k| eq(i, k)) + .map(|cur| cur.as_non_null()) + }) + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the table might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + #[inline] + pub fn capacity(&self) -> usize { + self.table.items + self.table.growth_left + } + + /// Returns the number of elements in the table. + #[inline] + pub fn len(&self) -> usize { + self.table.items + } + + /// Returns `true` if the table contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of buckets in the table. + #[inline] + pub fn buckets(&self) -> usize { + self.table.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + pub unsafe fn is_bucket_full(&self, index: usize) -> bool { + self.table.is_bucket_full(index) + } + + /// Returns an iterator over every element in the table. It is up to + /// the caller to ensure that the `RawTable` outlives the `RawIter`. + /// Because we cannot make the `next` method unsafe on the `RawIter` + /// struct, we have to make the `iter` method unsafe. + #[inline] + pub unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. The caller must uphold the safety contract for `iter` method. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + self.table.iter() + } + + /// Returns an iterator over occupied buckets that could match a given hash. + /// + /// `RawTable` only stores 7 bits of the hash value, so this iterator may + /// return items that have a hash value different than the one provided. You + /// should always validate the returned values before using them. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHash`. Because we cannot make the `next` method unsafe on the + /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash { + RawIterHash::new(self, hash) + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> RawDrain<'_, T, A> { + unsafe { + let iter = self.iter(); + self.drain_iter_from(iter) + } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn drain_iter_from(&mut self, iter: RawIter) -> RawDrain<'_, T, A> { + debug_assert_eq!(iter.len(), self.len()); + RawDrain { + iter, + table: mem::replace(&mut self.table, RawTableInner::NEW), + orig_table: NonNull::from(&mut self.table), + marker: PhantomData, + } + } + + /// Returns an iterator which consumes all elements from the table. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + pub unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { + debug_assert_eq!(iter.len(), self.len()); + + let allocation = self.into_allocation(); + RawIntoIter { + iter, + allocation, + marker: PhantomData, + } + } + + /// Converts the table into a raw allocation. The contents of the table + /// should be dropped using a `RawIter` before freeing the allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout, A)> { + let alloc = if self.table.is_empty_singleton() { + None + } else { + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = + match Self::TABLE_LAYOUT.calculate_layout_for(self.table.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + Some(( + unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset).cast()) }, + layout, + unsafe { ptr::read(&self.alloc) }, + )) + }; + mem::forget(self); + alloc + } +} + +unsafe impl Send for RawTable +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawTable +where + T: Sync, + A: Sync, +{ +} + +impl RawTableInner { + const NEW: Self = RawTableInner::new(); + + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never accessed + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + const fn new() -> Self { + Self { + // Be careful to cast the entire slice to a raw pointer. + ctrl: unsafe { + NonNull::new_unchecked(Group::static_empty().as_ptr().cast_mut().cast()) + }, + bucket_mask: 0, + items: 0, + growth_left: 0, + } + } +} + +impl RawTableInner { + /// Allocates a new [`RawTableInner`] with the given number of buckets. + /// The control bytes and buckets are left uninitialized. + /// + /// # Safety + /// + /// The caller of this function must ensure that the `buckets` is power of two + /// and also initialize all control bytes of the length `self.bucket_mask + 1 + + /// Group::WIDTH` with the [`Tag::EMPTY`] bytes. + /// + /// See also [`Allocator`] API for other safety concerns. + /// + /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: &A, + table_layout: TableLayout, + buckets: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + debug_assert!(buckets.is_power_of_two()); + + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(buckets) { + Some(lco) => lco, + None => return Err(fallibility.capacity_overflow()), + }; + + let ptr: NonNull = match do_alloc(alloc, layout) { + Ok(block) => block.cast(), + Err(_) => return Err(fallibility.alloc_err(layout)), + }; + + // SAFETY: null pointer will be caught in above check + let ctrl = NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)); + Ok(Self { + ctrl, + bucket_mask: buckets - 1, + items: 0, + growth_left: bucket_mask_to_capacity(buckets - 1), + }) + } + + /// Attempts to allocate a new [`RawTableInner`] with at least enough + /// capacity for inserting the given number of elements without reallocating. + /// + /// All the control bytes are initialized with the [`Tag::EMPTY`] bytes. + #[inline] + fn fallible_with_capacity( + alloc: &A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + if capacity == 0 { + Ok(Self::NEW) + } else { + // SAFETY: We checked that we could successfully allocate the new table, and then + // initialized all control bytes with the constant `Tag::EMPTY` byte. + unsafe { + let buckets = capacity_to_buckets(capacity, table_layout) + .ok_or_else(|| fallibility.capacity_overflow())?; + + let mut result = + Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + result.ctrl_slice().fill_empty(); + + Ok(result) + } + } + } + + /// Allocates a new [`RawTableInner`] with at least enough capacity for inserting + /// the given number of elements without reallocating. + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`fallible_with_capacity`] instead if you want to + /// handle memory allocation failure. + /// + /// All the control bytes are initialized with the [`Tag::EMPTY`] bytes. + /// + /// [`fallible_with_capacity`]: RawTableInner::fallible_with_capacity + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + fn with_capacity(alloc: &A, table_layout: TableLayout, capacity: usize) -> Self + where + A: Allocator, + { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::fallible_with_capacity(alloc, table_layout, capacity, Fallibility::Infallible) { + Ok(table_inner) => table_inner, + // SAFETY: All allocation errors will be caught inside `RawTableInner::new_uninitialized`. + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Fixes up an insertion slot returned by the [`RawTableInner::find_insert_slot_in_group`] method. + /// + /// In tables smaller than the group width (`self.buckets() < Group::WIDTH`), trailing control + /// bytes outside the range of the table are filled with [`Tag::EMPTY`] entries. These will unfortunately + /// trigger a match of [`RawTableInner::find_insert_slot_in_group`] function. This is because + /// the `Some(bit)` returned by `group.match_empty_or_deleted().lowest_set_bit()` after masking + /// (`(probe_seq.pos + bit) & self.bucket_mask`) may point to a full bucket that is already occupied. + /// We detect this situation here and perform a second scan starting at the beginning of the table. + /// This second scan is guaranteed to find an empty slot (due to the load factor) before hitting the + /// trailing control bytes (containing [`Tag::EMPTY`] bytes). + /// + /// If this function is called correctly, it is guaranteed to return [`InsertSlot`] with an + /// index of an empty or deleted bucket in the range `0..self.buckets()` (see `Warning` and + /// `Safety`). + /// + /// # Warning + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise if the table is less than + /// the group width (`self.buckets() < Group::WIDTH`) this function returns an index outside of the + /// table indices range `0..self.buckets()` (`0..=self.bucket_mask`). Attempt to write data at that + /// index will cause immediate [`undefined behavior`]. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::ctrl`] method. + /// Thus, in order to uphold those safety contracts, as well as for the correct logic of the work + /// of this crate, the following rules are necessary and sufficient: + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise calling this + /// function results in [`undefined behavior`]. + /// + /// * This function must only be used on insertion slots found by [`RawTableInner::find_insert_slot_in_group`] + /// (after the `find_insert_slot_in_group` function, but before insertion into the table). + /// + /// * The `index` must not be greater than the `self.bucket_mask`, i.e. `(index + 1) <= self.buckets()` + /// (this one is provided by the [`RawTableInner::find_insert_slot_in_group`] function). + /// + /// Calling this function with an index not provided by [`RawTableInner::find_insert_slot_in_group`] + /// may result in [`undefined behavior`] even if the index satisfies the safety rules of the + /// [`RawTableInner::ctrl`] function (`index < self.bucket_mask + 1 + Group::WIDTH`). + /// + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::find_insert_slot_in_group`]: RawTableInner::find_insert_slot_in_group + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn fix_insert_slot(&self, mut index: usize) -> InsertSlot { + // SAFETY: The caller of this function ensures that `index` is in the range `0..=self.bucket_mask`. + if unlikely(self.is_bucket_full(index)) { + debug_assert!(self.bucket_mask < Group::WIDTH); + // SAFETY: + // + // * Since the caller of this function ensures that the control bytes are properly + // initialized and `ptr = self.ctrl(0)` points to the start of the array of control + // bytes, therefore: `ctrl` is valid for reads, properly aligned to `Group::WIDTH` + // and points to the properly initialized control bytes (see also + // `TableLayout::calculate_layout_for` and `ptr::read`); + // + // * Because the caller of this function ensures that the index was provided by the + // `self.find_insert_slot_in_group()` function, so for for tables larger than the + // group width (self.buckets() >= Group::WIDTH), we will never end up in the given + // branch, since `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_slot_in_group` + // cannot return a full bucket index. For tables smaller than the group width, calling + // the `unwrap_unchecked` function is also safe, as the trailing control bytes outside + // the range of the table are filled with EMPTY bytes (and we know for sure that there + // is at least one FULL bucket), so this second scan either finds an empty slot (due to + // the load factor) or hits the trailing control bytes (containing EMPTY). + index = Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit() + .unwrap_unchecked(); + } + InsertSlot { index } + } + + /// Finds the position to insert something in a group. + /// + /// **This may have false positives and must be fixed up with `fix_insert_slot` + /// before it's used.** + /// + /// The function is guaranteed to return the index of an empty or deleted [`Bucket`] + /// in the range `0..self.buckets()` (`0..=self.bucket_mask`). + #[inline] + fn find_insert_slot_in_group(&self, group: &Group, probe_seq: &ProbeSeq) -> Option { + let bit = group.match_empty_or_deleted().lowest_set_bit(); + + if likely(bit.is_some()) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + Some((probe_seq.pos + bit.unwrap()) & self.bucket_mask) + } else { + None + } + } + + /// Searches for an element in the table, or a potential slot where that element could + /// be inserted (an empty or deleted [`Bucket`] index). + /// + /// This uses dynamic dispatch to reduce the amount of code generated, but that is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element (as `Ok(index)`). If the element is not found and there is at least 1 + /// empty or deleted [`Bucket`] in the table, the function is guaranteed to return + /// [`InsertSlot`] with an index in the range `0..self.buckets()`, but in any case, + /// if this function returns [`InsertSlot`], it will contain an index in the range + /// `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_or_find_insert_slot_inner( + &self, + hash: u64, + eq: &mut dyn FnMut(usize) -> bool, + ) -> Result { + let mut insert_slot = None; + + let tag_hash = Tag::full(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because the number + // of buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_tag(tag_hash) { + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Ok(index); + } + } + + // We didn't find the element we were looking for in the group, try to get an + // insertion slot from the group if we don't have one yet. + if likely(insert_slot.is_none()) { + insert_slot = self.find_insert_slot_in_group(&group, &probe_seq); + } + + if let Some(insert_slot) = insert_slot { + // Only stop the search if the group contains at least one empty element. + // Otherwise, the element that we are looking for might be in a following group. + if likely(group.match_empty().any_bit_set()) { + // We must have found a insert slot by now, since the current group contains at + // least one. For tables smaller than the group width, there will still be an + // empty element in the current (and only) group due to the load factor. + unsafe { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + return Err(self.fix_insert_slot(insert_slot)); + } + } + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting a new + /// element and sets the hash for that slot. Returns an index of that slot and the + /// old control byte stored in the found index. + /// + /// This function does not check if the given element exists in the table. Also, + /// this function does not check if there is enough space in the table to insert + /// a new element. The caller of the function must make sure that the table has at + /// least 1 empty or deleted `bucket`, otherwise this function will never return + /// (will go into an infinite loop) for tables larger than the group width, or + /// return an index outside of the table indices range if the table is less than + /// the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an `index` in the range `0..self.buckets()`, but in any case, + /// if this function returns an `index` it will be in the range `0..=self.buckets()`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for the + /// [`RawTableInner::set_ctrl_hash`] and [`RawTableInner::find_insert_slot`] methods. + /// Thus, in order to uphold the safety contracts for that methods, as well as for + /// the correct logic of the work of this crate, you must observe the following rules + /// when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated and has properly initialized + /// control bytes otherwise calling this function results in [`undefined behavior`]. + /// + /// * The caller of this function must ensure that the "data" parts of the table + /// will have an entry in the returned index (matching the given hash) right + /// after calling this function. + /// + /// Attempt to write data at the `index` returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] + /// control bytes outside the table range. + /// + /// The caller must independently increase the `items` field of the table, and also, + /// if the old control byte was [`Tag::EMPTY`], then decrease the table's `growth_left` + /// field, and do not change it if the old control byte was [`Tag::DELETED`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::set_ctrl_hash`]: RawTableInner::set_ctrl_hash + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + #[inline] + unsafe fn prepare_insert_slot(&mut self, hash: u64) -> (usize, Tag) { + // SAFETY: Caller of this function ensures that the control bytes are properly initialized. + let index: usize = self.find_insert_slot(hash).index; + // SAFETY: + // 1. The `find_insert_slot` function either returns an `index` less than or + // equal to `self.buckets() = self.bucket_mask + 1` of the table, or never + // returns if it cannot find an empty or deleted slot. + // 2. The caller of this function guarantees that the table has already been + // allocated + let old_ctrl = *self.ctrl(index); + self.set_ctrl_hash(index, hash); + (index, old_ctrl) + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element, returning the `index` for the new [`Bucket`]. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return [`InsertSlot`] with an index in the range `0..self.buckets()`, + /// but in any case, if this function returns [`InsertSlot`], it will contain an index + /// in the range `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_insert_slot(&self, hash: u64) -> InsertSlot { + let mut probe_seq = self.probe_seq(hash); + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because the number + // of buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + let index = self.find_insert_slot_in_group(&group, &probe_seq); + if likely(index.is_some()) { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + unsafe { + return self.fix_insert_slot(index.unwrap_unchecked()); + } + } + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an element in a table, returning the `index` of the found element. + /// This uses dynamic dispatch to reduce the amount of code generated, but it is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, + /// this function will also never return (will go into an infinite loop). + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element as `Some(index)`, so the index will always be in the range + /// `0..self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { + let tag_hash = Tag::full(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask`. + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new_in). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_tag(tag_hash) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Some(index); + } + } + + if likely(group.match_empty().any_bit_set()) { + return None; + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Prepares for rehashing data in place (that is, without allocating new memory). + /// Converts all full index `control bytes` to `Tag::DELETED` and all `Tag::DELETED` control + /// bytes to `Tag::EMPTY`, i.e. performs the following conversion: + /// + /// - `Tag::EMPTY` control bytes -> `Tag::EMPTY`; + /// - `Tag::DELETED` control bytes -> `Tag::EMPTY`; + /// - `FULL` control bytes -> `Tag::DELETED`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The caller of this function must convert the `Tag::DELETED` bytes back to `FULL` + /// bytes when re-inserting them into their ideal position (which was impossible + /// to do during the first insert due to tombstones). If the caller does not do + /// this, then calling this function may result in a memory leak. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise + /// calling this function results in [`undefined behavior`]. + /// + /// Calling this function on a table that has not been allocated results in + /// [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + unsafe fn prepare_rehash_in_place(&mut self) { + // Bulk convert all full control bytes to DELETED, and all DELETED control bytes to EMPTY. + // This effectively frees up all buckets containing a DELETED entry. + // + // SAFETY: + // 1. `i` is guaranteed to be within bounds since we are iterating from zero to `buckets - 1`; + // 2. Even if `i` will be `i == self.bucket_mask`, it is safe to call `Group::load_aligned` + // due to the extended control bytes range, which is `self.bucket_mask + 1 + Group::WIDTH`; + // 3. The caller of this function guarantees that [`RawTableInner`] has already been allocated; + // 4. We can use `Group::load_aligned` and `Group::store_aligned` here since we start from 0 + // and go to the end with a step equal to `Group::WIDTH` (see TableLayout::calculate_layout_for). + for i in (0..self.buckets()).step_by(Group::WIDTH) { + let group = Group::load_aligned(self.ctrl(i)); + let group = group.convert_special_to_empty_and_full_to_deleted(); + group.store_aligned(self.ctrl(i)); + } + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + // + // SAFETY: The caller of this function guarantees that [`RawTableInner`] + // has already been allocated + if unlikely(self.buckets() < Group::WIDTH) { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + self.ctrl(0) + .copy_to(self.ctrl(Group::WIDTH), self.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + self.ctrl(0) + .copy_to(self.ctrl(self.buckets()), Group::WIDTH); + } + } + + /// Returns an iterator over every element in the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result + /// is [`undefined behavior`]: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `RawIter`. Because we cannot make the `next` method unsafe on + /// the `RawIter` struct, we have to make the `iter` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise using the returned [`RawIter`] results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.data_end()` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. `data` bucket index in the table is equal to the `ctrl` index (i.e. + // equal to zero). + // 3. We pass the exact value of buckets of the table to the function. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + // SAFETY: See explanation above + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()), + items: self.items, + } + } + + /// Executes the destructors (if any) of the values stored in the table. + /// + /// # Note + /// + /// This function does not erase the control bytes of the table and does + /// not make any changes to the `items` or `growth_left` fields of the + /// table. If necessary, the caller of this function must manually set + /// up these table fields, for example using the [`clear_no_drop`] function. + /// + /// Be careful during calling this function, because drop function of + /// the elements can panic, and this can leave table in an inconsistent + /// state. + /// + /// # Safety + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise calling this function may result in [`undefined behavior`]. + /// + /// If `T` is a type that should be dropped and **the table is not empty**, + /// calling this function more than once results in [`undefined behavior`]. + /// + /// If `T` is not [`Copy`], attempting to use values stored in the table after + /// calling this function may result in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`Bucket::drop`] / [`Bucket::as_ptr`] methods, for more information + /// about of properly removing or saving `element` from / into the [`RawTable`] / + /// [`RawTableInner`]. + /// + /// [`Bucket::drop`]: Bucket::drop + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`clear_no_drop`]: RawTableInner::clear_no_drop + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_elements(&mut self) { + // Check that `self.items != 0`. Protects against the possibility + // of creating an iterator on an table with uninitialized control bytes. + if T::NEEDS_DROP && self.items != 0 { + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `RawIter` iterator, and the caller of this function + // must uphold the safety contract for `drop_elements` method. + for item in self.iter::() { + // SAFETY: The caller must uphold the safety contract for + // `drop_elements` method. + item.drop(); + } + } + } + + /// Executes the destructors (if any) of the values stored in the table and than + /// deallocates the table. + /// + /// # Note + /// + /// Calling this function automatically makes invalid (dangling) all instances of + /// buckets ([`Bucket`]) and makes invalid (dangling) the `ctrl` field of the table. + /// + /// This function does not make any changes to the `bucket_mask`, `items` or `growth_left` + /// fields of the table. If necessary, the caller of this function must manually set + /// up these table fields. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * Calling this function more than once; + /// + /// * The type `T` must be the actual type of the elements stored in the table. + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that + /// was used to allocate this table. + /// + /// The caller of this function should pay attention to the possibility of the + /// elements' drop function panicking, because this: + /// + /// * May leave the table in an inconsistent state; + /// + /// * Memory is never deallocated, so a memory leak may occur. + /// + /// Attempt to use the `ctrl` field of the table (dereference) after calling this + /// function results in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`RawTableInner::drop_elements`] or [`RawTableInner::free_buckets`] + /// for more information. + /// + /// [`RawTableInner::drop_elements`]: RawTableInner::drop_elements + /// [`RawTableInner::free_buckets`]: RawTableInner::free_buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_inner_table(&mut self, alloc: &A, table_layout: TableLayout) { + if !self.is_empty_singleton() { + unsafe { + // SAFETY: The caller must uphold the safety contract for `drop_inner_table` method. + self.drop_elements::(); + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller must uphold the safety contract for `drop_inner_table` method. + self.free_buckets(alloc, table_layout); + } + } + } + + /// Returns a pointer to an element in the table (convenience for + /// `Bucket::from_base_index(self.data_end::(), index)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived from the + /// safety rules of the [`Bucket::from_base_index`] function. Therefore, when calling + /// this function, the following safety rules must be observed: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// * The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`Bucket`] may result in [`undefined behavior`]. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + /// part of the `RawTableInner`, i.e. to the start of T3 (see [`Bucket::as_ptr`]) + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// ^ \__________ __________/ + /// `table.bucket(3)` returns a pointer that points \/ + /// here in the `data` part of the `RawTableInner` additional control bytes + /// (to the end of T3) `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`Bucket::from_base_index`]: Bucket::from_base_index + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Returns a raw `*mut u8` pointer to the start of the `data` element in the table + /// (convenience for `self.data_end::().as_ptr().sub((index + 1) * size_of)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned `*mut u8`, + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`; + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket_ptr(3, mem::size_of::())` returns a pointer that points here in the + /// `data` part of the `RawTableInner`, i.e. to the start of T3 + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// \__________ __________/ + /// \/ + /// additional control bytes + /// `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + let base: *mut u8 = self.data_end().as_ptr(); + base.sub((index + 1) * size_of) + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation (convenience for `self.ctrl.cast()`). + /// + /// This function actually returns a pointer to the end of the `data element` at + /// index "0" (zero). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Note + /// + /// The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`NonNull`] may result in [`undefined behavior`]. + /// + /// ```none + /// `table.data_end::()` returns pointer that points here + /// (to the end of `T0`) + /// ∨ + /// [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + /// \________ ________/ + /// \/ + /// `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`. + /// CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + /// with loading `Group` bytes from the heap works properly, even if the result + /// of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + /// `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + fn data_end(&self) -> NonNull { + self.ctrl.cast() + } + + /// Returns an iterator-like object for a probe sequence on the table. + /// + /// This iterator never terminates, but is guaranteed to visit each bucket + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. + #[inline] + fn probe_seq(&self, hash: u64) -> ProbeSeq { + ProbeSeq { + // This is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + pos: h1(hash) & self.bucket_mask, + stride: 0, + } + } + + #[inline] + unsafe fn record_item_insert_at(&mut self, index: usize, old_ctrl: Tag, hash: u64) { + self.growth_left -= usize::from(old_ctrl.special_is_empty()); + self.set_ctrl_hash(index, hash); + self.items += 1; + } + + #[inline] + fn is_in_same_group(&self, i: usize, new_i: usize, hash: u64) -> bool { + let probe_seq_pos = self.probe_seq(hash).pos; + let probe_index = + |pos: usize| (pos.wrapping_sub(probe_seq_pos) & self.bucket_mask) / Group::WIDTH; + probe_index(i) == probe_index(new_i) + } + + /// Sets a control byte to the hash, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl`] + /// method. Thus, in order to uphold the safety contracts for the method, you must observe the + /// following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl`]: RawTableInner::set_ctrl + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl_hash(&mut self, index: usize, hash: u64) { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl_hash`] + self.set_ctrl(index, Tag::full(hash)); + } + + /// Replaces the hash in the control byte at the given index with the provided one, + /// and possibly also replicates the new control byte at the end of the array of control + /// bytes, returning the old control byte. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl_hash`] + /// and [`RawTableInner::ctrl`] methods. Thus, in order to uphold the safety contracts for both + /// methods, you must observe the following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl_hash`]: RawTableInner::set_ctrl_hash + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn replace_ctrl_hash(&mut self, index: usize, hash: u64) -> Tag { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::replace_ctrl_hash`] + let prev_ctrl = *self.ctrl(index); + self.set_ctrl_hash(index, hash); + prev_ctrl + } + + /// Sets a control byte, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl(&mut self, index: usize, ctrl: Tag) { + // Replicate the first Group::WIDTH control bytes at the end of + // the array without using a branch. If the tables smaller than + // the group width (self.buckets() < Group::WIDTH), + // `index2 = Group::WIDTH + index`, otherwise `index2` is: + // + // - If index >= Group::WIDTH then index == index2. + // - Otherwise index2 == self.bucket_mask + 1 + index. + // + // The very last replicated control byte is never actually read because + // we mask the initial index for unaligned loads, but we write it + // anyways because it makes the set_ctrl implementation simpler. + // + // If there are fewer buckets than Group::WIDTH then this code will + // replicate the buckets at the end of the trailing group. For example + // with 2 buckets and a group size of 4, the control bytes will look + // like this: + // + // Real | Replicated + // --------------------------------------------- + // | [A] | [B] | [Tag::EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- + + // This is the same as `(index.wrapping_sub(Group::WIDTH)) % self.buckets() + Group::WIDTH` + // because the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl`] + *self.ctrl(index) = ctrl; + *self.ctrl(index2) = ctrl; + } + + /// Returns a pointer to a control byte. + /// + /// # Safety + /// + /// For the allocated [`RawTableInner`], the result is [`Undefined Behavior`], + /// if the `index` is greater than the `self.bucket_mask + 1 + Group::WIDTH`. + /// In that case, calling this function with `index == self.bucket_mask + 1 + Group::WIDTH` + /// will return a pointer to the end of the allocated table and it is useless on its own. + /// + /// Calling this function with `index >= self.bucket_mask + 1 + Group::WIDTH` on a + /// table that has not been allocated results in [`Undefined Behavior`]. + /// + /// So to satisfy both requirements you should always follow the rule that + /// `index < self.bucket_mask + 1 + Group::WIDTH` + /// + /// Calling this function on [`RawTableInner`] that are not already allocated is safe + /// for read-only purpose. + /// + /// See also [`Bucket::as_ptr()`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr()`]: Bucket::as_ptr() + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn ctrl(&self, index: usize) -> *mut Tag { + debug_assert!(index < self.num_ctrl_bytes()); + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::ctrl`] + self.ctrl.as_ptr().add(index).cast() + } + + /// Gets the slice of all control bytes. + fn ctrl_slice(&mut self) -> &mut [Tag] { + // SAFETY: We've intiailized all control bytes, and have the correct number. + unsafe { slice::from_raw_parts_mut(self.ctrl.as_ptr().cast(), self.num_ctrl_bytes()) } + } + + #[inline] + fn buckets(&self) -> usize { + self.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + unsafe fn is_bucket_full(&self, index: usize) -> bool { + debug_assert!(index < self.buckets()); + (*self.ctrl(index)).is_full() + } + + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating, + /// and return it inside `ScopeGuard` to protect against panic in the hash + /// function. + /// + /// # Note + /// + /// It is recommended (but not required): + /// + /// * That the new table's `capacity` be greater than or equal to `self.items`. + /// + /// * The `alloc` is the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `table_layout` is the same [`TableLayout`] as the `TableLayout` used + /// to allocate this table. + /// + /// If `table_layout` does not match the `TableLayout` that was used to allocate + /// this table, then using `mem::swap` with the `self` and the new table returned + /// by this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + fn prepare_resize<'a, A>( + &self, + alloc: &'a A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result, TryReserveError> + where + A: Allocator, + { + debug_assert!(self.items <= capacity); + + // Allocate and initialize the new table. + let new_table = + RawTableInner::fallible_with_capacity(alloc, table_layout, capacity, fallibility)?; + + // The hash function may panic, in which case we simply free the new + // table without dropping any elements that may have been copied into + // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. + Ok(guard(new_table, move |self_| { + if !self_.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that the `alloc` and `table_layout` matches the + // [`Allocator`] and [`TableLayout`] used to allocate this table. + unsafe { self_.free_buckets(alloc, table_layout) }; + } + })) + } + + /// Reserves or rehashes to make room for `additional` more elements. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table. + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn reserve_rehash_inner( + &mut self, + alloc: &A, + additional: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + drop: Option, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let new_items = match self.items.checked_add(additional) { + Some(new_items) => new_items, + None => return Err(fallibility.capacity_overflow()), + }; + let full_capacity = bucket_mask_to_capacity(self.bucket_mask); + if new_items <= full_capacity / 2 { + // Rehash in-place without re-allocating if we have plenty of spare + // capacity that is locked up due to DELETED entries. + + // SAFETY: + // 1. We know for sure that `[`RawTableInner`]` has already been allocated + // (since new_items <= full_capacity / 2); + // 2. The caller ensures that `drop` function is the actual drop function of + // the elements stored in the table. + // 3. The caller ensures that `layout` matches the [`TableLayout`] that was + // used to allocate this table. + // 4. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.rehash_in_place(hasher, layout.size, drop); + Ok(()) + } else { + // Otherwise, conservatively resize to at least the next size up + // to avoid churning deletes into frequent rehashes. + // + // SAFETY: + // 1. We know for sure that `capacity >= self.items`. + // 2. The caller ensures that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.resize_inner( + alloc, + usize::max(new_items, full_capacity + 1), + hasher, + fallibility, + layout, + ) + } + } + + /// Returns an iterator over full buckets indices in the table. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `FullBucketsIndices`. Because we cannot make the `next` method + /// unsafe on the `FullBucketsIndices` struct, we have to make the + /// `full_buckets_indices` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + #[inline(always)] + unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.ctrl(0)` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. The value of `items` is equal to the amount of data (values) added + // to the table. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, Group::WIDTH + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + let ctrl = NonNull::new_unchecked(self.ctrl(0).cast::()); + + FullBucketsIndices { + // Load the first group + // SAFETY: See explanation above. + current_group: Group::load_aligned(ctrl.as_ptr().cast()) + .match_full() + .into_iter(), + group_first_index: 0, + ctrl, + items: self.items, + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table; + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The caller of this function must ensure that `capacity >= self.items` + /// otherwise: + /// + /// * If `self.items != 0`, calling of this function with `capacity == 0` + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// are never return (will go into an infinite loop). + /// + /// Note: It is recommended (but not required) that the new table's `capacity` + /// be greater than or equal to `self.items`. In case if `capacity <= self.items` + /// this function can never return. See [`RawTableInner::find_insert_slot`] for + /// more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn resize_inner( + &mut self, + alloc: &A, + capacity: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // SAFETY: We know for sure that `alloc` and `layout` matches the [`Allocator`] and [`TableLayout`] + // that were used to allocate this table. + let mut new_table = self.prepare_resize(alloc, layout, capacity, fallibility)?; + + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `FullBucketsIndices` iterator, and the caller of this + // function ensures that the control bytes are properly initialized. + for full_byte_index in self.full_buckets_indices() { + // This may panic. + let hash = hasher(self, full_byte_index); + + // SAFETY: + // We can use a simpler version of insert() here since: + // 1. There are no DELETED entries. + // 2. We know there is enough space in the table. + // 3. All elements are unique. + // 4. The caller of this function guarantees that `capacity > 0` + // so `new_table` must already have some allocated memory. + // 5. We set `growth_left` and `items` fields of the new table + // after the loop. + // 6. We insert into the table, at the returned index, the data + // matching the given hash immediately after calling this function. + let (new_index, _) = new_table.prepare_insert_slot(hash); + + // SAFETY: + // + // * `src` is valid for reads of `layout.size` bytes, since the + // table is alive and the `full_byte_index` is guaranteed to be + // within bounds (see `FullBucketsIndices::next_impl`); + // + // * `dst` is valid for writes of `layout.size` bytes, since the + // caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate old table and we have the `new_index` + // returned by `prepare_insert_slot`. + // + // * Both `src` and `dst` are properly aligned. + // + // * Both `src` and `dst` point to different region of memory. + ptr::copy_nonoverlapping( + self.bucket_ptr(full_byte_index, layout.size), + new_table.bucket_ptr(new_index, layout.size), + layout.size, + ); + } + + // The hash function didn't panic, so we can safely set the + // `growth_left` and `items` fields of the new table. + new_table.growth_left -= self.items; + new_table.items = self.items; + + // We successfully copied all elements without panicking. Now replace + // self with the new table. The old table will have its memory freed but + // the items will not be dropped (since they have been moved into the + // new table). + // SAFETY: The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + mem::swap(self, &mut new_table); + + Ok(()) + } + + /// Rehashes the contents of the table in place (i.e. without changing the + /// allocation). + /// + /// If `hasher` panics then some the table's contents may be lost. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[cfg_attr(feature = "inline-more", inline(always))] + #[cfg_attr(not(feature = "inline-more"), inline)] + unsafe fn rehash_in_place( + &mut self, + hasher: &dyn Fn(&mut Self, usize) -> u64, + size_of: usize, + drop: Option, + ) { + // If the hash function panics then properly clean up any elements + // that we haven't rehashed yet. We unfortunately can't preserve the + // element since we lost their hash and have no way of recovering it + // without risking another panic. + self.prepare_rehash_in_place(); + + let mut guard = guard(self, move |self_| { + if let Some(drop) = drop { + for i in 0..self_.buckets() { + if *self_.ctrl(i) == Tag::DELETED { + self_.set_ctrl(i, Tag::EMPTY); + drop(self_.bucket_ptr(i, size_of)); + self_.items -= 1; + } + } + } + self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items; + }); + + // At this point, DELETED elements are elements that we haven't + // rehashed yet. Find them and re-insert them at their ideal + // position. + 'outer: for i in 0..guard.buckets() { + if *guard.ctrl(i) != Tag::DELETED { + continue; + } + + let i_p = guard.bucket_ptr(i, size_of); + + 'inner: loop { + // Hash the current item + let hash = hasher(*guard, i); + + // Search for a suitable place to put it + // + // SAFETY: Caller of this function ensures that the control bytes + // are properly initialized. + let new_i = guard.find_insert_slot(hash).index; + + // Probing works by scanning through all of the control + // bytes in groups, which may not be aligned to the group + // size. If both the new and old position fall within the + // same unaligned group, then there is no benefit in moving + // it and we can just continue to the next item. + if likely(guard.is_in_same_group(i, new_i, hash)) { + guard.set_ctrl_hash(i, hash); + continue 'outer; + } + + let new_i_p = guard.bucket_ptr(new_i, size_of); + + // We are moving the current item to a new position. Write + // our H2 to the control byte of the new position. + let prev_ctrl = guard.replace_ctrl_hash(new_i, hash); + if prev_ctrl == Tag::EMPTY { + guard.set_ctrl(i, Tag::EMPTY); + // If the target slot is empty, simply move the current + // element into the new slot and clear the old control + // byte. + ptr::copy_nonoverlapping(i_p, new_i_p, size_of); + continue 'outer; + } else { + // If the target slot is occupied, swap the two elements + // and then continue processing the element that we just + // swapped into the old slot. + debug_assert_eq!(prev_ctrl, Tag::DELETED); + ptr::swap_nonoverlapping(i_p, new_i_p, size_of); + continue 'inner; + } + } + } + + guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items; + + mem::forget(guard); + } + + /// Deallocates the table without dropping any entries. + /// + /// # Note + /// + /// This function must be called only after [`drop_elements`](RawTableInner::drop_elements), + /// else it can lead to leaking of memory. Also calling this function automatically + /// makes invalid (dangling) all instances of buckets ([`Bucket`]) and makes invalid + /// (dangling) the `ctrl` field of the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that was used + /// to allocate this table. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn free_buckets(&mut self, alloc: &A, table_layout: TableLayout) + where + A: Allocator, + { + // SAFETY: The caller must uphold the safety contract for `free_buckets` + // method. + let (ptr, layout) = self.allocation_info(table_layout); + alloc.deallocate(ptr, layout); + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. + /// + /// # Safety + /// + /// Caller of this function must observe the following safety rules: + /// + /// * The [`RawTableInner`] has already been allocated, otherwise + /// calling this function results in [`undefined behavior`] + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + ( + // SAFETY: The caller must uphold the safety contract for `allocation_info` method. + unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + ) + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + /// + /// # Safety + /// + /// The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn allocation_size_or_zero(&self, table_layout: TableLayout) -> usize { + if self.is_empty_singleton() { + 0 + } else { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + unsafe { self.allocation_info(table_layout).1.size() } + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[inline] + fn clear_no_drop(&mut self) { + if !self.is_empty_singleton() { + self.ctrl_slice().fill_empty(); + } + self.items = 0; + self.growth_left = bucket_mask_to_capacity(self.bucket_mask); + } + + /// Erases the [`Bucket`]'s control byte at the given index so that it does not + /// triggered as full, decreases the `items` of the table and, if it can be done, + /// increases `self.growth_left`. + /// + /// This function does not actually erase / drop the [`Bucket`] itself, i.e. it + /// does not make any changes to the `data` parts of the table. The caller of this + /// function must take care to properly drop the `data`, otherwise calling this + /// function may result in a memory leak. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * It must be the full control byte at the given position; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// Calling this function on a table with no elements is unspecified, but calling subsequent + /// functions is likely to result in [`undefined behavior`] due to overflow subtraction + /// (`self.items -= 1 cause overflow when self.items == 0`). + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn erase(&mut self, index: usize) { + debug_assert!(self.is_bucket_full(index)); + + // This is the same as `index.wrapping_sub(Group::WIDTH) % self.buckets()` because + // the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + // SAFETY: + // - The caller must uphold the safety contract for `erase` method; + // - `index_before` is guaranteed to be in range due to masking with `self.bucket_mask` + let empty_before = Group::load(self.ctrl(index_before)).match_empty(); + let empty_after = Group::load(self.ctrl(index)).match_empty(); + + // Inserting and searching in the map is performed by two key functions: + // + // - The `find_insert_slot` function that looks up the index of any `Tag::EMPTY` or `Tag::DELETED` + // slot in a group to be able to insert. If it doesn't find an `Tag::EMPTY` or `Tag::DELETED` + // slot immediately in the first group, it jumps to the next `Group` looking for it, + // and so on until it has gone through all the groups in the control bytes. + // + // - The `find_inner` function that looks for the index of the desired element by looking + // at all the `FULL` bytes in the group. If it did not find the element right away, and + // there is no `Tag::EMPTY` byte in the group, then this means that the `find_insert_slot` + // function may have found a suitable slot in the next group. Therefore, `find_inner` + // jumps further, and if it does not find the desired element and again there is no `Tag::EMPTY` + // byte, then it jumps further, and so on. The search stops only if `find_inner` function + // finds the desired element or hits an `Tag::EMPTY` slot/byte. + // + // Accordingly, this leads to two consequences: + // + // - The map must have `Tag::EMPTY` slots (bytes); + // + // - You can't just mark the byte to be erased as `Tag::EMPTY`, because otherwise the `find_inner` + // function may stumble upon an `Tag::EMPTY` byte before finding the desired element and stop + // searching. + // + // Thus it is necessary to check all bytes after and before the erased element. If we are in + // a contiguous `Group` of `FULL` or `Tag::DELETED` bytes (the number of `FULL` or `Tag::DELETED` bytes + // before and after is greater than or equal to `Group::WIDTH`), then we must mark our byte as + // `Tag::DELETED` in order for the `find_inner` function to go further. On the other hand, if there + // is at least one `Tag::EMPTY` slot in the `Group`, then the `find_inner` function will still stumble + // upon an `Tag::EMPTY` byte, so we can safely mark our erased byte as `Tag::EMPTY` as well. + // + // Finally, since `index_before == (index.wrapping_sub(Group::WIDTH) & self.bucket_mask) == index` + // and given all of the above, tables smaller than the group width (self.buckets() < Group::WIDTH) + // cannot have `Tag::DELETED` bytes. + // + // Note that in this context `leading_zeros` refers to the bytes at the end of a group, while + // `trailing_zeros` refers to the bytes at the beginning of a group. + let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { + Tag::DELETED + } else { + self.growth_left += 1; + Tag::EMPTY + }; + // SAFETY: the caller must uphold the safety contract for `erase` method. + self.set_ctrl(index, ctrl); + self.items -= 1; + } +} + +impl Clone for RawTable { + fn clone(&self) -> Self { + if self.table.is_empty_singleton() { + Self::new_in(self.alloc.clone()) + } else { + unsafe { + // Avoid `Result::ok_or_else` because it bloats LLVM IR. + // + // SAFETY: This is safe as we are taking the size of an already allocated table + // and therefore capacity overflow cannot occur, `self.table.buckets()` is power + // of two and all allocator errors will be caught inside `RawTableInner::new_uninitialized`. + let mut new_table = match Self::new_uninitialized( + self.alloc.clone(), + self.table.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + + // Cloning elements may fail (the clone function may panic). But we don't + // need to worry about uninitialized control bits, since: + // 1. The number of items (elements) in the table is zero, which means that + // the control bits will not be read by Drop function. + // 2. The `clone_from_spec` method will first copy all control bits from + // `self` (thus initializing them). But this will not affect the `Drop` + // function, since the `clone_from_spec` function sets `items` only after + // successfully cloning all elements. + new_table.clone_from_spec(self); + new_table + } + } + } + + fn clone_from(&mut self, source: &Self) { + if source.table.is_empty_singleton() { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + unsafe { + // Make sure that if any panics occurs, we clear the table and + // leave it in an empty state. + let mut self_ = guard(self, |self_| { + self_.clear_no_drop(); + }); + + // First, drop all our elements without clearing the control + // bytes. If this panics then the scope guard will clear the + // table, leaking any elements that were not dropped yet. + // + // This leak is unavoidable: we can't try dropping more elements + // since this could lead to another panic and abort the process. + // + // SAFETY: If something gets wrong we clear our table right after + // dropping the elements, so there is no double drop, since `items` + // will be equal to zero. + self_.table.drop_elements::(); + + // If necessary, resize our table to match the source. + if self_.buckets() != source.buckets() { + let new_inner = match RawTableInner::new_uninitialized( + &self_.alloc, + Self::TABLE_LAYOUT, + source.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + // Replace the old inner with new uninitialized one. It's ok, since if something gets + // wrong `ScopeGuard` will initialize all control bytes and leave empty table. + let mut old_inner = mem::replace(&mut self_.table, new_inner); + if !old_inner.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that `alloc` and `table_layout` matches + // the [`Allocator`] and [`TableLayout`] that were used to allocate this table. + old_inner.free_buckets(&self_.alloc, Self::TABLE_LAYOUT); + } + } + + // Cloning elements may fail (the clone function may panic), but the `ScopeGuard` + // inside the `clone_from_impl` function will take care of that, dropping all + // cloned elements if necessary. Our `ScopeGuard` will clear the table. + self_.clone_from_spec(source); + + // Disarm the scope guard if cloning was successful. + ScopeGuard::into_inner(self_); + } + } + } +} + +/// Specialization of `clone_from` for `Copy` types +trait RawTableClone { + unsafe fn clone_from_spec(&mut self, source: &Self); +} +impl RawTableClone for RawTable { + default_fn! { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + self.clone_from_impl(source); + } + } +} +#[cfg(feature = "nightly")] +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + source + .data_start() + .as_ptr() + .copy_to_nonoverlapping(self.data_start().as_ptr(), self.table.buckets()); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl RawTable { + /// Common code for `clone` and `clone_from`. Assumes: + /// - `self.buckets() == source.buckets()`. + /// - Any existing elements have been dropped. + /// - The control bytes are not initialized yet. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_impl(&mut self, source: &Self) { + // Copy the control bytes unchanged. We do this in a single pass + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + + // The cloning of elements may panic, in which case we need + // to make sure we drop only the elements that have been + // cloned so far. + let mut guard = guard((0, &mut *self), |(index, self_)| { + if T::NEEDS_DROP { + for i in 0..*index { + if self_.is_bucket_full(i) { + self_.bucket(i).drop(); + } + } + } + }); + + for from in source.iter() { + let index = source.bucket_index(&from); + let to = guard.1.bucket(index); + to.write(from.as_ref().clone()); + + // Update the index in case we need to unwind. + guard.0 = index + 1; + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl Default for RawTable { + #[inline] + fn default() -> Self { + Self::new_in(Default::default()) + } +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} + +impl IntoIterator for RawTable { + type Item = T; + type IntoIter = RawIntoIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> RawIntoIter { + unsafe { + let iter = self.iter(); + self.into_iter_from(iter) + } + } +} + +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does +/// not track an item count. +pub(crate) struct RawIterRange { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. + end: *const u8, +} + +impl RawIterRange { + /// Returns a `RawIterRange` covering a subset of a table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * `ctrl` must be [valid] for reads, i.e. table outlives the `RawIterRange`; + /// + /// * `ctrl` must be properly aligned to the group size (`Group::WIDTH`); + /// + /// * `ctrl` must point to the array of properly initialized control bytes; + /// + /// * `data` must be the [`Bucket`] at the `ctrl` index in the table; + /// + /// * the value of `len` must be less than or equal to the number of table buckets, + /// and the returned value of `ctrl.as_ptr().add(len).offset_from(ctrl.as_ptr())` + /// must be positive. + /// + /// * The `ctrl.add(len)` pointer must be either in bounds or one + /// byte past the end of the same [allocated table]. + /// + /// * The `len` must be a power of two. + /// + /// [valid]: https://doc.rust-lang.org/std/ptr/index.html#safety + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let end = ctrl.add(len); + + // Load the first group and advance ctrl to point to the next group + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let current_group = Group::load_aligned(ctrl.cast()).match_full(); + let next_ctrl = ctrl.add(Group::WIDTH); + + Self { + current_group: current_group.into_iter(), + data, + next_ctrl, + end, + } + } + + /// Splits a `RawIterRange` into two halves. + /// + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rayon")] + pub(crate) fn split(mut self) -> (Self, Option>) { + unsafe { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. + (self, None) + } else { + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.next_n(Group::WIDTH).next_n(mid), + len - mid, + ); + debug_assert_eq!( + self.data.next_n(Group::WIDTH).next_n(mid).ptr, + tail.data.ptr + ); + debug_assert_eq!(self.end, tail.end); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); + (self, Some(tail)) + } + } + } + + /// # Safety + /// If `DO_CHECK_PTR_RANGE` is false, caller must ensure that we never try to iterate + /// after yielding all elements. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn next_impl(&mut self) -> Option> { + loop { + if let Some(index) = self.current_group.next() { + return Some(self.data.next_n(index)); + } + + if DO_CHECK_PTR_RANGE && self.next_ctrl >= self.end { + return None; + } + + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + self.current_group = Group::load_aligned(self.next_ctrl.cast()) + .match_full() + .into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. + /// + /// `fold_impl()` takes three arguments: the number of items remaining in + /// the iterator, an initial value, and a closure with two arguments: an + /// 'accumulator', and an element. The closure returns the value that the + /// accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first call. + /// + /// After applying this closure to every element of the iterator, `fold_impl()` + /// returns the accumulator. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `RawIterRange`; + /// + /// * The provided `n` value must match the actual number of items + /// in the table. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::while_let_on_iterator)] + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn fold_impl(mut self, mut n: usize, mut acc: B, mut f: F) -> B + where + F: FnMut(B, Bucket) -> B, + { + loop { + while let Some(index) = self.current_group.next() { + // The returned `index` will always be in the range `0..Group::WIDTH`, + // so that calling `self.data.next_n(index)` is safe (see detailed explanation below). + debug_assert!(n != 0); + let bucket = self.data.next_n(index); + acc = f(acc, bucket); + n -= 1; + } + + if n == 0 { + return acc; + } + + // SAFETY: The caller of this function ensures that: + // + // 1. The provided `n` value matches the actual number of items in the table; + // 2. The table is alive and did not moved. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.current_group` will read bytes + // from the `self.buckets() - Group::WIDTH` index. We know also that + // `self.current_group.next()` will always return indices within the range + // `0..Group::WIDTH`. + // + // Knowing all of the above and taking into account that we are synchronizing + // the `self.data` index with the index we used to read the `self.current_group`, + // the subsequent `self.data.next_n(index)` will always return a bucket with + // an index number less than `self.buckets()`. + // + // The last `self.next_ctrl`, whose index would be `self.buckets()`, will never + // actually be read, since we should have already yielded all the elements of + // the table. + self.current_group = Group::load_aligned(self.next_ctrl.cast()) + .match_full() + .into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } +} + +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} + +impl Clone for RawIterRange { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + next_ctrl: self.next_ctrl, + current_group: self.current_group.clone(), + end: self.end, + } + } +} + +impl Iterator for RawIterRange { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + unsafe { + // SAFETY: We set checker flag to true. + self.next_impl::() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We don't have an item count, so just guess based on the range size. + let remaining_buckets = if self.end > self.next_ctrl { + unsafe { offset_from(self.end, self.next_ctrl) } + } else { + 0 + }; + + // Add a group width to include the group we are currently processing. + (0, Some(Group::WIDTH + remaining_buckets)) + } +} + +impl FusedIterator for RawIterRange {} + +/// Iterator which returns a raw pointer to every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket (unless `reflect_remove` is called). +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator (unless `reflect_insert` is called). +/// - The order in which the iterator yields bucket is unspecified and may +/// change in the future. +pub struct RawIter { + pub(crate) iter: RawIterRange, + items: usize, +} + +impl RawIter { + unsafe fn drop_elements(&mut self) { + if T::NEEDS_DROP && self.items != 0 { + for item in self { + item.drop(); + } + } + } +} + +impl Clone for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + items: self.items, + } + } +} +impl Default for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + // SAFETY: Because the table is static, it always outlives the iter. + unsafe { RawTableInner::NEW.iter() } + } +} + +impl Iterator for RawIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + // Inner iterator iterates over buckets + // so it can do unnecessary work if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: We check number of items to yield using `items` field. + self.iter.next_impl::() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + unsafe { self.iter.fold_impl(self.items, init, f) } + } +} + +impl ExactSizeIterator for RawIter {} +impl FusedIterator for RawIter {} + +/// Iterator which returns an index of every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding index of that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields indices of the buckets is unspecified +/// and may change in the future. +pub(crate) struct FullBucketsIndices { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Initial value of the bytes' indices of the current group (relative + // to the start of the control bytes). + group_first_index: usize, + + // Pointer to the current group of control bytes, + // Must be aligned to the group size (Group::WIDTH). + ctrl: NonNull, + + // Number of elements in the table. + items: usize, +} + +impl FullBucketsIndices { + /// Advances the iterator and returns the next value. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `FullBucketsIndices`; + /// + /// * It never tries to iterate after getting all elements. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn next_impl(&mut self) -> Option { + loop { + if let Some(index) = self.current_group.next() { + // The returned `self.group_first_index + index` will always + // be in the range `0..self.buckets()`. See explanation below. + return Some(self.group_first_index + index); + } + + // SAFETY: The caller of this function ensures that: + // + // 1. It never tries to iterate after getting all the elements; + // 2. The table is alive and did not moved; + // 3. The first `self.ctrl` pointed to the start of the array of control bytes. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // the start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.ctrl` will be equal to + // the `self.buckets() - Group::WIDTH`, so `self.current_group.next()` + // will always contains indices within the range `0..Group::WIDTH`, + // and subsequent `self.group_first_index + index` will always return a + // number less than `self.buckets()`. + self.ctrl = NonNull::new_unchecked(self.ctrl.as_ptr().add(Group::WIDTH)); + + // SAFETY: See explanation above. + self.current_group = Group::load_aligned(self.ctrl.as_ptr().cast()) + .match_full() + .into_iter(); + self.group_first_index += Group::WIDTH; + } + } +} + +impl Iterator for FullBucketsIndices { + type Item = usize; + + /// Advances the iterator and returns the next value. It is up to + /// the caller to ensure that the `RawTable` outlives the `FullBucketsIndices`, + /// because we cannot make the `next` method unsafe. + #[inline(always)] + fn next(&mut self) -> Option { + // Return if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: + // 1. We check number of items to yield using `items` field. + // 2. The caller ensures that the table is alive and has not moved. + self.next_impl() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for FullBucketsIndices {} +impl FusedIterator for FullBucketsIndices {} + +/// Iterator which consumes a table and returns elements. +pub struct RawIntoIter { + iter: RawIter, + allocation: Option<(NonNull, Layout, A)>, + marker: PhantomData, +} + +impl RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawIntoIter +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawIntoIter +where + T: Sync, + A: Sync, +{ +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} + +impl Default for RawIntoIter { + fn default() -> Self { + Self { + iter: Default::default(), + allocation: None, + marker: PhantomData, + } + } +} +impl Iterator for RawIntoIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { Some(self.iter.next()?.read()) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} + +/// Iterator which consumes elements without freeing the table storage. +pub struct RawDrain<'a, T, A: Allocator = Global> { + iter: RawIter, + + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: RawTableInner, + orig_table: NonNull, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. + marker: PhantomData<&'a RawTable>, +} + +impl RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawDrain<'_, T, A> +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawDrain<'_, T, A> +where + T: Sync, + A: Sync, +{ +} + +impl Drop for RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements. Note that this may panic. + self.iter.drop_elements(); + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&self.table, 1); + } + } +} + +impl Iterator for RawDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { + let item = self.iter.next()?; + Some(item.read()) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} + +/// Iterator over occupied buckets that could match a given hash. +/// +/// `RawTable` only stores 7 bits of the hash value, so this iterator may return +/// items that have a hash value different than the one provided. You should +/// always validate the returned values before using them. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields buckets is unspecified and may +/// change in the future. +pub struct RawIterHash { + inner: RawIterHashInner, + _marker: PhantomData, +} + +#[derive(Clone)] +struct RawIterHashInner { + // See `RawTableInner`'s corresponding fields for details. + // We can't store a `*const RawTableInner` as it would get + // invalidated by the user calling `&mut` methods on `RawTable`. + bucket_mask: usize, + ctrl: NonNull, + + // The top 7 bits of the hash. + tag_hash: Tag, + + // The sequence of groups to probe in the search. + probe_seq: ProbeSeq, + + group: Group, + + // The elements within the group with a matching tag-hash. + bitmask: BitMaskIter, +} + +impl RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(table: &RawTable, hash: u64) -> Self { + RawIterHash { + inner: RawIterHashInner::new(&table.table, hash), + _marker: PhantomData, + } + } +} + +impl Clone for RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + _marker: PhantomData, + } + } +} + +impl Default for RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + // SAFETY: Because the table is static, it always outlives the iter. + inner: unsafe { RawIterHashInner::new(&RawTableInner::NEW, 0) }, + _marker: PhantomData, + } + } +} + +impl RawIterHashInner { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(table: &RawTableInner, hash: u64) -> Self { + let tag_hash = Tag::full(hash); + let probe_seq = table.probe_seq(hash); + let group = Group::load(table.ctrl(probe_seq.pos)); + let bitmask = group.match_tag(tag_hash).into_iter(); + + RawIterHashInner { + bucket_mask: table.bucket_mask, + ctrl: table.ctrl, + tag_hash, + probe_seq, + group, + bitmask, + } + } +} + +impl Iterator for RawIterHash { + type Item = Bucket; + + fn next(&mut self) -> Option> { + unsafe { + match self.inner.next() { + Some(index) => { + // Can't use `RawTable::bucket` here as we don't have + // an actual `RawTable` reference to use. + debug_assert!(index <= self.inner.bucket_mask); + let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index); + Some(bucket) + } + None => None, + } + } + } +} + +impl Iterator for RawIterHashInner { + type Item = usize; + + fn next(&mut self) -> Option { + unsafe { + loop { + if let Some(bit) = self.bitmask.next() { + let index = (self.probe_seq.pos + bit) & self.bucket_mask; + return Some(index); + } + if likely(self.group.match_empty().any_bit_set()) { + return None; + } + self.probe_seq.move_next(self.bucket_mask); + + // Can't use `RawTableInner::ctrl` here as we don't have + // an actual `RawTableInner` reference to use. + let index = self.probe_seq.pos; + debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH); + let group_ctrl = self.ctrl.as_ptr().add(index).cast(); + + self.group = Group::load(group_ctrl); + self.bitmask = self.group.match_tag(self.tag_hash).into_iter(); + } + } + } +} + +pub(crate) struct RawExtractIf<'a, T, A: Allocator> { + pub iter: RawIter, + pub table: &'a mut RawTable, +} + +impl RawExtractIf<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn next(&mut self, mut f: F) -> Option + where + F: FnMut(&mut T) -> bool, + { + unsafe { + for item in &mut self.iter { + if f(item.as_mut()) { + return Some(self.table.remove(item).0); + } + } + } + None + } +} + +#[cfg(test)] +mod test_map { + use super::*; + + #[test] + fn test_minimum_capacity_for_small_types() { + #[track_caller] + fn test_t() { + let raw_table: RawTable = RawTable::with_capacity(1); + let actual_buckets = raw_table.buckets(); + let min_buckets = Group::WIDTH / core::mem::size_of::(); + assert!( + actual_buckets >= min_buckets, + "expected at least {min_buckets} buckets, got {actual_buckets} buckets" + ); + } + + test_t::(); + + // This is only "small" for some platforms, like x86_64 with SSE2, but + // there's no harm in running it on other platforms. + test_t::(); + } + + fn rehash_in_place(table: &mut RawTable, hasher: impl Fn(&T) -> u64) { + unsafe { + table.table.rehash_in_place( + &|table, index| hasher(table.bucket::(index).as_ref()), + mem::size_of::(), + if mem::needs_drop::() { + Some(|ptr| ptr::drop_in_place(ptr as *mut T)) + } else { + None + }, + ); + } + } + + #[test] + fn rehash() { + let mut table = RawTable::new(); + let hasher = |i: &u64| *i; + for i in 0..100 { + table.insert(i, i, hasher); + } + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + + rehash_in_place(&mut table, hasher); + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + } + + /// CHECKING THAT WE ARE NOT TRYING TO READ THE MEMORY OF + /// AN UNINITIALIZED TABLE DURING THE DROP + #[test] + fn test_drop_uninitialized() { + use ::alloc::vec::Vec; + + let table = unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap() + }; + drop(table); + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_drop_zero_items() { + use ::alloc::vec::Vec; + unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + let mut table = + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap(); + + // WE SIMULATE, AS IT WERE, A FULL TABLE. + + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `table.table.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + table.table.ctrl_slice().fill_empty(); + + // SAFETY: table.capacity() is guaranteed to be smaller than table.buckets() + table.table.ctrl(0).write_bytes(0, table.capacity()); + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if table.buckets() < Group::WIDTH { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(Group::WIDTH), table.table.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(table.table.buckets()), Group::WIDTH); + } + drop(table); + } + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_catch_panic_clone_from() { + use super::{AllocError, Allocator, Global}; + use ::alloc::sync::Arc; + use ::alloc::vec::Vec; + use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + struct CheckedCloneDrop { + panic_in_clone: bool, + dropped: bool, + need_drop: Vec, + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + dropped: self.dropped, + need_drop: self.need_drop.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + let mut table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + + for (idx, panic_in_clone) in core::iter::repeat(DISARMED).take(7).enumerate() { + let idx = idx as u64; + table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx], + }, + ), + |(k, _)| *k, + ); + } + + assert_eq!(table.len(), 7); + + thread::scope(|s| { + let result = s.spawn(|| { + let armed_flags = [ + DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + let mut scope_table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + for (idx, &panic_in_clone) in armed_flags.iter().enumerate() { + let idx = idx as u64; + scope_table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx + 100], + }, + ), + |(k, _)| *k, + ); + } + table.clone_from(&scope_table); + }); + assert!(result.join().is_err()); + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(table.len(), 0); + assert_eq!(unsafe { table.iter().count() }, 0); + assert_eq!(unsafe { table.iter().iter.count() }, 0); + + for idx in 0..table.buckets() { + let idx = idx as u64; + assert!( + table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/raw_entry.rs b/deps/crates/vendor/hashbrown-0.15.5/src/raw_entry.rs new file mode 100644 index 00000000000000..480ebdbe1fb9b9 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/raw_entry.rs @@ -0,0 +1,1740 @@ +use crate::hash_map::{equivalent, make_hash, make_hasher}; +use crate::raw::{Allocator, Bucket, Global, RawTable}; +use crate::{Equivalent, HashMap}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap { + /// Creates a raw entry builder for the `HashMap`. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the `HashMap` into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and + /// more foolproof APIs like `entry` should be preferred when possible. + /// + /// In particular, the hash used to initialized the raw entry must still be + /// consistent with the hash of the key that is ultimately stored in the entry. + /// This is because implementations of `HashMap` may need to recompute hashes + /// when resizing, at which point only the keys are available. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map[&"a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = compute_hash(map.hasher(), &"c"); + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry().from_key(&"c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = compute_hash(map.hasher(), &key); + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map[&"d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get(&"d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S, A> { + RawEntryBuilderMut { map: self } + } + + /// Creates a raw immutable entry builder for the `HashMap`. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// `get` should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = compute_hash(map.hasher(), k); + /// let v = map.get(&k).cloned(); + /// let kv = v.as_ref().map(|v| (&k, v)); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry().from_key(&k), kv); + /// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S, A> { + RawEntryBuilder { map: self } + } +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry_mut`] docs for usage examples. +/// +/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{RawEntryBuilderMut, RawEntryMut::Vacant, RawEntryMut::Occupied}; +/// use hashbrown::HashMap; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16)]); +/// assert_eq!(map.len(), 6); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let builder: RawEntryBuilderMut<_, _, _> = map.raw_entry_mut(); +/// +/// // Existing key +/// match builder.from_key(&6) { +/// Vacant(_) => unreachable!(), +/// Occupied(view) => assert_eq!(view.get(), &16), +/// } +/// +/// for key in 0..12 { +/// let hash = compute_hash(map.hasher(), &key); +/// let value = map.get(&key).cloned(); +/// let key_value = value.as_ref().map(|v| (&key, v)); +/// +/// println!("Key: {} and value: {:?}", key, value); +/// +/// match map.raw_entry_mut().from_key(&key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// } +/// +/// assert_eq!(map.len(), 6); +/// ``` +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator = Global> { + map: &'a mut HashMap, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This is a lower-level version of [`Entry`]. +/// +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`Entry`]: enum.Entry.html +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([('a', 1), ('b', 2), ('c', 3)]); +/// assert_eq!(map.len(), 3); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// // Existing key (insert) +/// let raw: RawEntryMut<_, _, _> = map.raw_entry_mut().from_key(&'a'); +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = raw.insert('a', 10); +/// assert_eq!(map.len(), 3); +/// +/// // Nonexistent key (insert) +/// map.raw_entry_mut().from_key(&'d').insert('d', 40); +/// assert_eq!(map.len(), 4); +/// +/// // Existing key (or_insert) +/// let hash = compute_hash(map.hasher(), &'b'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'b') +/// .or_insert('b', 20); +/// assert_eq!(kv, (&mut 'b', &mut 2)); +/// *kv.1 = 20; +/// assert_eq!(map.len(), 4); +/// +/// // Nonexistent key (or_insert) +/// let hash = compute_hash(map.hasher(), &'e'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'e') +/// .or_insert('e', 50); +/// assert_eq!(kv, (&mut 'e', &mut 50)); +/// assert_eq!(map.len(), 5); +/// +/// // Existing key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'c'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'c') +/// .or_insert_with(|| ('c', 30)); +/// assert_eq!(kv, (&mut 'c', &mut 3)); +/// *kv.1 = 30; +/// assert_eq!(map.len(), 5); +/// +/// // Nonexistent key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'f'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'f') +/// .or_insert_with(|| ('f', 60)); +/// assert_eq!(kv, (&mut 'f', &mut 60)); +/// assert_eq!(map.len(), 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [('a', 10), ('b', 20), ('c', 30), ('d', 40), ('e', 50), ('f', 60)]); +/// ``` +pub enum RawEntryMut<'a, K, V, S, A: Allocator = Global> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(_) => { } + /// } + /// ``` + Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.raw_entry_mut().from_key("a") { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(_) => { } + /// } + /// ``` + Vacant(RawVacantEntryMut<'a, K, V, S, A>), +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = map.raw_entry_mut().from_key(&"a").insert("a", 100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// let new_v = (*v) * 10; +/// *v = new_v; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.raw_entry().from_key(&"c"), None); +/// assert_eq!(map.len(), 2); +/// +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "b") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("b", 20)); +/// } +/// } +/// assert_eq!(map.get(&"b"), None); +/// assert_eq!(map.len(), 1); +/// ``` +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator = Global> { + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawVacantEntryMut}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let raw_v: RawVacantEntryMut<_, _, _> = match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(view) => view, +/// RawEntryMut::Occupied(_) => unreachable!(), +/// }; +/// raw_v.insert("a", 10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"b") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// let (k, value) = view.insert("b", 2); +/// assert_eq!((*k, *value), ("b", 2)); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "c") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// assert_eq!(view.insert("c", 30), (&mut "c", &mut 30)); +/// } +/// } +/// assert!(map[&"c"] == 30 && map.len() == 3); +/// ``` +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator = Global> { + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry`] docs for usage examples. +/// +/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, RawEntryBuilder}; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 10), (2, 20), (3, 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// for k in 0..6 { +/// let hash = compute_hash(map.hasher(), &k); +/// let v = map.get(&k).cloned(); +/// let kv = v.as_ref().map(|v| (&k, v)); +/// +/// println!("Key: {} and value: {:?}", k, v); +/// let builder: RawEntryBuilder<_, _, _> = map.raw_entry(); +/// assert_eq!(builder.from_key(&k), kv); +/// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); +/// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); +/// } +/// ``` +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator = Global> { + map: &'a HashMap, +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key(&key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + S: BuildHasher, + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Creates a `RawEntryMut` from the given key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key_hashed_nocheck(hash, &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + Q: Equivalent + ?Sized, + { + self.from_hash(hash, equivalent(k)) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_hash(hash, |k| k == &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + self.search(hash, is_match) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + match self.map.table.find(hash, |(k, _)| is_match(k)) { + Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { + elem, + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + None => RawEntryMut::Vacant(RawVacantEntryMut { + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { + /// Access an immutable entry by key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// assert_eq!(map.raw_entry().from_key(&key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Access an immutable entry by a key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> + where + Q: Equivalent + ?Sized, + { + self.from_hash(hash, equivalent(k)) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + match self.map.table.get(hash, |(k, _)| is_match(k)) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + /// Access an immutable entry by hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_hash(hash, |k| k == &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + self.search(hash, is_match) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry, and returns a `RawOccupiedEntryMut`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37); + /// + /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(mut entry) => { + entry.insert(value); + entry + } + RawEntryMut::Vacant(entry) => entry.insert_entry(key, value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { + /// ("poneyland", "hoho".to_string()) + /// }); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => { + let (k, v) = default(); + entry.insert(k, v) + } + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 0); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + match self { + RawEntryMut::Occupied(mut entry) => { + { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + RawEntryMut::Occupied(entry) + } + RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } +} + +impl<'a, K, V, S, A: Allocator> RawOccupiedEntryMut<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.key(), &"a") + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Gets a mutable reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// *o.key_mut() = key_two.clone(); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key_mut(&mut self) -> &mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Converts the entry into a mutable reference to the key in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => inside_key = o.into_key(), + /// } + /// *inside_key = key_two.clone(); + /// + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> &'a mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get(), &100), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let value: &mut u32; + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => value = o.into_mut(), + /// } + /// *value += 900; + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => *o.get_mut() += 900, + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get_key_value(), (&"a", &100)), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value(&self) -> (&K, &V) { + unsafe { + let (key, value) = self.elem.as_ref(); + (key, value) + } + } + + /// Gets a mutable reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let (inside_key, inside_value) = o.get_key_value_mut(); + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// } + /// } + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// let inside_value: &mut u32; + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => { + /// let tuple = o.into_key_value(); + /// inside_key = tuple.0; + /// inside_value = tuple.1; + /// } + /// } + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => assert_eq!(o.insert(1000), 100), + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let old_key = o.insert_key(key_two.clone()); + /// assert!(Rc::ptr_eq(&old_key, &key_one)); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove(), 100), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove_entry(), ("a", 100)), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let raw_entry = match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 100); + /// Some(v + 900) + /// }), + /// }; + /// let raw_entry = match raw_entry { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 1000); + /// None + /// }), + /// }; + /// match raw_entry { + /// RawEntryMut::Vacant(_) => { }, + /// RawEntryMut::Occupied(_) => panic!(), + /// }; + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"c") { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!(v.insert("c", 300), (&mut "c", &mut 300)), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + self.insert_hashed_nocheck(hash, key, value) + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "c"; + /// let hash = compute_hash(map.hasher(), &key); + /// + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_hashed_nocheck(hash, key, 300), + /// (&mut "c", &mut 300) + /// ), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::shadow_unrelated)] + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let &mut (ref mut k, ref mut v) = self.table.insert_entry( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + (k, v) + } + + /// Set the value of an entry with a custom hasher function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn make_hasher(hash_builder: &S) -> impl Fn(&K) -> u64 + '_ + /// where + /// K: Hash + ?Sized, + /// S: BuildHasher, + /// { + /// move |key: &K| { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash_builder = map.hasher().clone(); + /// let hash = make_hasher(&hash_builder)(&key); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| q == &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_with_hasher(hash, key, 100, make_hasher(&hash_builder)), + /// (&mut "a", &mut 100) + /// ), + /// } + /// map.extend([("b", 200), ("c", 300), ("d", 400), ("e", 500), ("f", 600)]); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_hasher( + self, + hash: u64, + key: K, + value: V, + hasher: H, + ) -> (&'a mut K, &'a mut V) + where + H: Fn(&K) -> u64, + { + let &mut (ref mut k, ref mut v) = self + .table + .insert_entry(hash, (key, value), |x| hasher(&x.0)); + (k, v) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + let elem = self.table.insert( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + RawOccupiedEntryMut { + elem, + table: self.table, + hash_builder: self.hash_builder, + } + } +} + +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +impl Debug for RawEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), + } + } +} + +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() + } +} + +impl Debug for RawEntryBuilder<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +#[cfg(test)] +mod test_map { + use super::HashMap; + use super::RawEntryMut; + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1_i32, 10_i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + super::make_hash::(map.hasher(), &k) + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).copied(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } + } + + #[test] + fn test_key_without_hash_impl() { + #[derive(Debug)] + struct IntWrapper(u64); + + let mut m: HashMap = HashMap::default(); + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 0"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(0, IntWrapper(0), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_none()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(1, |k| k.0 == 1) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 1"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(1, IntWrapper(1), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let occupied_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(e) => e, + RawEntryMut::Vacant(..) => panic!("Couldn't find entry for key 0"), + }; + occupied_entry.remove(); + } + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/rustc_entry.rs b/deps/crates/vendor/hashbrown-0.15.5/src/rustc_entry.rs new file mode 100644 index 00000000000000..233fe7a2dd3bea --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/rustc_entry.rs @@ -0,0 +1,567 @@ +use self::RustcEntry::*; +use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::raw::{Allocator, Bucket, Global, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry +pub enum RustcEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V, A>), +} + +impl Debug for RustcEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcOccupiedEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, +} + +unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> +where + K: Send, + V: Send, + A: Allocator + Send, +{ +} +unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> +where + K: Sync, + V: Sync, + A: Allocator + Sync, +{ +} + +impl Debug for RustcOccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcVacantEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + hash: u64, + key: K, + table: &'a mut RawTable<(K, V), A>, +} + +impl Debug for RustcVacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> { + /// Sets the value of the entry, and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.rustc_entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + match self { + Vacant(entry) => entry.insert_entry(value), + Occupied(mut entry) => { + entry.insert(value); + entry + } + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } +} + +impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V { + unsafe { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + &mut bucket.as_mut().1 + } + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) }; + RustcOccupiedEntry { + elem: bucket, + table: self.table, + } + } +} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/scopeguard.rs b/deps/crates/vendor/hashbrown-0.15.5/src/scopeguard.rs new file mode 100644 index 00000000000000..382d06043ef601 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/scopeguard.rs @@ -0,0 +1,72 @@ +// Extracted from the scopeguard crate +use core::{ + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr, +}; + +pub struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + pub fn into_inner(guard: Self) -> T { + // Cannot move out of Drop-implementing types, so + // ptr::read the value out of a ManuallyDrop + // Don't use mem::forget as that might invalidate value + let guard = ManuallyDrop::new(guard); + unsafe { + let value = ptr::read(&guard.value); + // read the closure so that it is dropped + let _ = ptr::read(&guard.dropfn); + value + } + } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/set.rs b/deps/crates/vendor/hashbrown-0.15.5/src/set.rs new file mode 100644 index 00000000000000..5c512b8b8e738d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/set.rs @@ -0,0 +1,3121 @@ +use crate::{Equivalent, TryReserveError}; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign}; +use core::{fmt, mem}; +use map::make_hash; + +use super::map::{self, HashMap, Keys}; +use crate::raw::{Allocator, Global, RawExtractIf}; +use crate::DefaultHashBuilder; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// A hash set implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or +/// unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashSet` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`]. This will in the +/// future be implied by [`Eq`]. +/// +/// ``` +/// use hashbrown::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{:?}", x); +/// } +/// ``` +/// +/// A `HashSet` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashSet; +/// +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].into_iter().collect(); +/// // use the values stored in the set +/// ``` +/// +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +pub struct HashSet { + pub(crate) map: HashMap, +} + +impl Clone for HashSet { + fn clone(&self) -> Self { + HashSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +#[cfg(feature = "default-hasher")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher`](HashSet::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher`](HashSet::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity), + } + } +} + +#[cfg(feature = "default-hasher")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher_in`](HashSet::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + map: HashMap::new_in(alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher_in`](HashSet::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_in(capacity, alloc), + } + } +} + +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + iter: self.map.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.into_iter().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(|k, _| f(k)); + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashSet::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.map.table.iter() }, + table: &mut self.map.table, + }, + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.map.clear(); + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } +} + +impl HashSet +where + A: Allocator, +{ + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.map.allocator() + } + + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher_in(hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_hasher_in(hasher, alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_and_hasher_in(capacity, hasher, alloc), + } + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = set.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + self.map.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashSet::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S, A> { + Difference { + iter: self.iter(), + other, + } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S, A> { + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Intersection { + iter: smaller.iter(), + other: larger, + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S, A> { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Union { + iter: larger.iter().chain(smaller.difference(larger)), + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains(&self, value: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.get_key_value(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert(&mut self, value: T) -> &T { + let hash = make_hash(&self.map.hash_builder, &value); + let bucket = match self.map.find_or_find_insert_slot(hash, &value) { + Ok(bucket) => bucket, + Err(slot) => unsafe { self.map.table.insert_in_slot(hash, slot, (value, ())) }, + }; + unsafe { &bucket.as_ref().0 } + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + /// + /// The following example will panic because the new value doesn't match. + /// + /// ```should_panic + /// let mut set = hashbrown::HashSet::new(); + /// set.get_or_insert_with("rust", |_| String::new()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + Q: Hash + Equivalent + ?Sized, + F: FnOnce(&Q) -> T, + { + let hash = make_hash(&self.map.hash_builder, value); + let bucket = match self.map.find_or_find_insert_slot(hash, value) { + Ok(bucket) => bucket, + Err(slot) => { + let new = f(value); + assert!(value.equivalent(&new), "new value is not equivalent"); + unsafe { self.map.table.insert_in_slot(hash, slot, (new, ())) } + } + }; + unsafe { &bucket.as_ref().0 } + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert(); + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { + match self.map.entry(value) { + map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), + map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), + } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + pub fn is_disjoint(&self, other: &Self) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + pub fn is_subset(&self, other: &Self) -> bool { + self.len() <= other.len() && self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert a value the set without checking if the value already exists in the set. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the set. + /// For example, when constructing a set from another set, we know + /// that values are unique. + /// + /// # Safety + /// + /// This operation is safe if a value does not exist in the set. + /// + /// However, if a value exists in the set already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the set + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashSet` + /// may be passed to unsafe code which does expect the set to behave + /// correctly, and would cause unsoundness as a result. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_unique_unchecked(&mut self, value: T) -> &T { + self.map.insert_unique_unchecked(value, ()).0 + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(&mut self, value: T) -> Option { + let hash = make_hash(&self.map.hash_builder, &value); + match self.map.find_or_find_insert_slot(hash, &value) { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().0 }, value)), + Err(slot) => { + unsafe { + self.map.table.insert_in_slot(hash, slot, (value, ())); + } + None + } + } + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.remove_entry(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Returns the total amount of memory allocated internally by the hash + /// set, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.map.allocation_size() + } +} + +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for HashSet +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl From> for HashSet +where + A: Allocator, +{ + fn from(map: HashMap) -> Self { + Self { map } + } +} + +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher_in(Default::default(), Default::default()); + set.extend(iter); + set + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "default-hasher")] +impl From<[T; N]> for HashSet +where + T: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set1 = HashSet::from([1, 2, 3, 4]); + /// let set2: HashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + arr.into_iter().collect() + } +} + +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.map.extend(iter.into_iter().map(|k| (k, ()))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: T) { + self.map.insert(k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().copied()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: &'a T) { + self.map.insert(*k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl Default for HashSet +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +impl BitOrAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the union of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a |= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor_assign(&mut self, rhs: &HashSet) { + for item in rhs { + if !self.contains(item) { + self.insert(item.clone()); + } + } + } +} + +impl BitAndAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the intersection of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// a &= &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand_assign(&mut self, rhs: &HashSet) { + self.retain(|item| rhs.contains(item)); + } +} + +impl BitXorAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the symmetric difference of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a ^= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor_assign(&mut self, rhs: &HashSet) { + for item in rhs { + let hash = make_hash(&self.map.hash_builder, item); + match self.map.find_or_find_insert_slot(hash, item) { + Ok(bucket) => unsafe { + self.map.table.remove(bucket); + }, + Err(slot) => unsafe { + self.map + .table + .insert_in_slot(hash, slot, (item.clone(), ())); + }, + } + } + } +} + +impl SubAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the difference of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a -= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub_assign(&mut self, rhs: &HashSet) { + if rhs.len() < self.len() { + for item in rhs { + self.remove(item); + } + } else { + self.retain(|item| !rhs.contains(item)); + } + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter +pub struct Iter<'a, K> { + iter: Keys<'a, K, ()>, +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter +pub struct IntoIter { + iter: map::IntoIter, +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain +pub struct Drain<'a, K, A: Allocator = Global> { + iter: map::Drain<'a, K, (), A>, +} + +/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashSet.html#method.extract_if +/// [`HashSet`]: struct.HashSet.html +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, (K, ()), A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection +pub struct Intersection<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference +pub struct Difference<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference +pub struct SymmetricDifference<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union +pub struct Union<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +impl Clone for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} +impl Default for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Iter { + iter: Default::default(), + } + } +} +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} +impl ExactSizeIterator for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Iter<'_, K> {} + +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IntoIter { + iter: Default::default(), + } + } +} +impl Iterator for IntoIter { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for Drain<'_, K, A> { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for Drain<'_, K, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Drain<'_, K, A> {} + +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for ExtractIf<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner + .next(|&mut (ref k, ())| (self.f)(k)) + .map(|(k, ())| k) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} + +impl Clone for Intersection<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + f(acc, elt) + } else { + acc + } + }) + } +} + +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl Clone for Difference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + (lower.saturating_sub(self.other.len()), upper) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + acc + } else { + f(acc, elt) + } + }) + } +} + +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for SymmetricDifference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for Union<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_, _> = set.entry("a"); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +pub enum Entry<'a, T, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<_> = ["a", "b"].into(); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S, A>), +} + +impl fmt::Debug for Entry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o: OccupiedEntry<_, _> = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, T, S, A: Allocator = Global> { + inner: map::OccupiedEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, VacantEntry}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v: VacantEntry<_, _> = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => { view.insert(); }, +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +pub struct VacantEntry<'a, T, S, A: Allocator = Global> { + inner: map::VacantEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for VacantEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> T { + self.inner.remove_entry().0 + } +} + +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_value(self) -> T { + self.inner.into_key() + } + + /// Sets the value of the entry with the `VacantEntry`'s value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { + inner: self.inner.insert_entry(()), + } + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new, A: Allocator>(v: IntoIter<&'static str, A>) -> IntoIter<&'new str, A> { + v + } + fn difference<'a, 'new, A: Allocator>( + v: Difference<'a, &'static str, DefaultHashBuilder, A>, + ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn symmetric_difference<'a, 'new, A: Allocator>( + v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, + ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn intersection<'a, 'new, A: Allocator>( + v: Intersection<'a, &'static str, DefaultHashBuilder, A>, + ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn union<'a, 'new, A: Allocator>( + v: Union<'a, &'static str, DefaultHashBuilder, A>, + ) -> Union<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn drain<'new, A: Allocator>(d: Drain<'static, &'static str, A>) -> Drain<'new, &'new str, A> { + d + } +} + +#[cfg(test)] +mod test_set { + use super::{make_hash, Equivalent, HashSet}; + use crate::DefaultHashBuilder; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); + } + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_sub_assign() { + let mut a: HashSet<_> = vec![1, 2, 3, 4, 5].into_iter().collect(); + let b: HashSet<_> = vec![4, 5, 6].into_iter().collect(); + + a -= &b; + + let mut i = 0; + let expected = [1, 2, 3]; + for x in &a { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_map() { + let mut a = crate::HashMap::new(); + a.insert(1, ()); + a.insert(2, ()); + a.insert(3, ()); + a.insert(4, ()); + + let a: HashSet<_> = a.into(); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().copied().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{set:?}"); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + if !s.is_empty() { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } + } + + #[test] + fn test_replace() { + use core::hash; + + #[derive(Debug)] + #[allow(dead_code)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend([2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } + + #[test] + fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().copied().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } + + #[test] + fn test_extract_if() { + { + let mut set: HashSet = (0..8).collect(); + let drained = set.extract_if(|&k| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![0, 2, 4, 6], out); + assert_eq!(set.len(), 4); + } + { + let mut set: HashSet = (0..8).collect(); + set.extract_if(|&k| k % 2 == 0).for_each(drop); + assert_eq!(set.len(), 4, "Removes non-matching items on drop"); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET; + set.insert(19); + assert!(set.contains(&19)); + } + + #[test] + fn rehash_in_place() { + let mut set = HashSet::new(); + + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } + + #[test] + fn test_allocation_info() { + assert_eq!(HashSet::<()>::new().allocation_size(), 0); + assert_eq!(HashSet::::new().allocation_size(), 0); + assert!(HashSet::::with_capacity(1).allocation_size() > core::mem::size_of::()); + } + + #[test] + fn duplicate_insert() { + let mut set = HashSet::new(); + set.insert(1); + set.get_or_insert_with(&1, |_| 1); + set.get_or_insert_with(&1, |_| 1); + assert!([1].iter().eq(set.iter())); + } + + #[test] + #[should_panic] + fn some_invalid_equivalent() { + use core::hash::{Hash, Hasher}; + struct Invalid { + count: u32, + other: u32, + } + + struct InvalidRef { + count: u32, + other: u32, + } + + impl PartialEq for Invalid { + fn eq(&self, other: &Self) -> bool { + self.count == other.count && self.other == other.other + } + } + impl Eq for Invalid {} + + impl Equivalent for InvalidRef { + fn equivalent(&self, key: &Invalid) -> bool { + self.count == key.count && self.other == key.other + } + } + impl Hash for Invalid { + fn hash(&self, state: &mut H) { + self.count.hash(state); + } + } + impl Hash for InvalidRef { + fn hash(&self, state: &mut H) { + self.count.hash(state); + } + } + let mut set: HashSet = HashSet::new(); + let key = InvalidRef { count: 1, other: 1 }; + let value = Invalid { count: 1, other: 2 }; + if make_hash(set.hasher(), &key) == make_hash(set.hasher(), &value) { + set.get_or_insert_with(&key, |_| value); + } + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/table.rs b/deps/crates/vendor/hashbrown-0.15.5/src/table.rs new file mode 100644 index 00000000000000..2565f6f8be6693 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/table.rs @@ -0,0 +1,2380 @@ +use core::{fmt, iter::FusedIterator, marker::PhantomData}; + +use crate::{ + raw::{ + Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter, + RawIterHash, RawTable, + }, + TryReserveError, +}; + +/// Low-level hash table with explicit hashing. +/// +/// The primary use case for this type over [`HashMap`] or [`HashSet`] is to +/// support types that do not implement the [`Hash`] and [`Eq`] traits, but +/// instead require additional data not contained in the key itself to compute a +/// hash and compare two elements for equality. +/// +/// Examples of when this can be useful include: +/// - An `IndexMap` implementation where indices into a `Vec` are stored as +/// elements in a `HashTable`. Hashing and comparing the elements +/// requires indexing the associated `Vec` to get the actual value referred to +/// by the index. +/// - Avoiding re-computing a hash when it is already known. +/// - Mutating the key of an element in a way that doesn't affect its hash. +/// +/// To achieve this, `HashTable` methods that search for an element in the table +/// require a hash value and equality function to be explicitly passed in as +/// arguments. The method will then iterate over the elements with the given +/// hash and call the equality function on each of them, until a match is found. +/// +/// In most cases, a `HashTable` will not be exposed directly in an API. It will +/// instead be wrapped in a helper type which handles the work of calculating +/// hash values and comparing elements. +/// +/// Due to its low-level nature, this type provides fewer guarantees than +/// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot +/// yourself in the foot by having multiple elements with identical keys in the +/// table. The table itself will still function correctly and lookups will +/// arbitrarily return one of the matching elements. However you should avoid +/// doing this because it changes the runtime of hash table operations from +/// `O(1)` to `O(k)` where `k` is the number of duplicate entries. +/// +/// [`HashMap`]: super::HashMap +/// [`HashSet`]: super::HashSet +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +pub struct HashTable +where + A: Allocator, +{ + pub(crate) raw: RawTable, +} + +impl HashTable { + /// Creates an empty `HashTable`. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::new(); + /// assert_eq!(table.len(), 0); + /// assert_eq!(table.capacity(), 0); + /// ``` + pub const fn new() -> Self { + Self { + raw: RawTable::new(), + } + } + + /// Creates an empty `HashTable` with the specified capacity. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::with_capacity(10); + /// assert_eq!(table.len(), 0); + /// assert!(table.capacity() >= 10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +impl HashTable +where + A: Allocator, +{ + /// Creates an empty `HashTable` using the given allocator. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use bumpalo::Bump; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::new_in(&bump); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// + /// // The created HashTable also doesn't allocate memory + /// assert_eq!(table.capacity(), 0); + /// + /// // Now we insert element inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// // We can see that the HashTable holds 1 element + /// assert_eq!(table.len(), 1); + /// // And it also allocates some capacity + /// assert!(table.capacity() > 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub const fn new_in(alloc: A) -> Self { + Self { + raw: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashTable` with the specified capacity using the given allocator. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use bumpalo::Bump; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::with_capacity_in(5, &bump); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = table.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// table.insert_unique(hasher(&"Two"), "Two", hasher); + /// table.insert_unique(hasher(&"Three"), "Three", hasher); + /// table.insert_unique(hasher(&"Four"), "Four", hasher); + /// table.insert_unique(hasher(&"Five"), "Five", hasher); + /// + /// // We can see that the HashTable holds 5 elements + /// assert_eq!(table.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(table.capacity(), empty_map_capacity) + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + raw: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the underlying allocator. + pub fn allocator(&self) -> &A { + self.raw.allocator() + } + + /// Returns a reference to an entry in the table with the given hash and + /// which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); + /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + self.raw.get(hash, eq) + } + + /// Returns a mutable reference to an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// When mutating an entry, you should ensure that it still retains the same + /// hash value as when it was inserted, otherwise lookups of that entry may + /// fail to find it. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { + /// val.1 = "b"; + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + self.raw.get_mut(hash, eq) + } + + /// Returns an `OccupiedEntry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table. Call + /// [`HashTable::entry`] instead if you wish to insert an entry if the + /// lookup fails. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { + /// entry.remove(); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.find(hash, eq) { + Some(bucket) => Ok(OccupiedEntry { + hash, + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns an `Entry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table, or insert a new + /// entry with the given hash if one doesn't already exist. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// This method may grow the table in preparation for an insertion. Call + /// [`HashTable::find_entry`] if this is undesirable. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) + /// { + /// entry.remove(); + /// } + /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { + /// entry.insert((2, "b")); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Entry<'_, T, A> { + match self.raw.find_or_find_insert_slot(hash, eq, hasher) { + Ok(bucket) => Entry::Occupied(OccupiedEntry { + hash, + bucket, + table: self, + }), + Err(insert_slot) => Entry::Vacant(VacantEntry { + hash, + insert_slot, + table: self, + }), + } + } + + /// Inserts an element into the `HashTable` with the given hash value, but + /// without checking whether an equivalent element already exists within the + /// table. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut v = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert_unique( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> OccupiedEntry<'_, T, A> { + let bucket = self.raw.insert(hash, value, hasher); + OccupiedEntry { + hash, + bucket, + table: self, + } + } + + /// Clears the table, removing all values. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut v = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// v.clear(); + /// assert!(v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn clear(&mut self) { + self.raw.clear(); + } + + /// Shrinks the capacity of the table as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to_fit(hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(self.len(), hasher) + } + + /// Shrinks the capacity of the table with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to(10, hasher); + /// assert!(table.capacity() >= 10); + /// table.shrink_to(0, hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(min_capacity, hasher); + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.reserve(10, hasher); + /// assert!(table.capacity() >= 10); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + self.raw.reserve(additional, hasher) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table + /// .try_reserve(10, hasher) + /// .expect("why is the test harness OOMing on 10 bytes?"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + self.raw.try_reserve(additional, hasher) + } + + /// Returns the number of elements the table can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let table: HashTable = HashTable::with_capacity(100); + /// assert!(table.capacity() >= 100); + /// ``` + pub fn capacity(&self) -> usize { + self.raw.capacity() + } + + /// Returns the number of elements in the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert_eq!(v.len(), 0); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert_eq!(v.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert!(v.is_empty()); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert!(!v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for x in table.iter() { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with mutable references to the elements. + /// The iterator element type is `&'a mut T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// + /// // Update all values + /// for val in table.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [2, 4, 6]); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements which may match a hash. + /// The iterator element type is `&'a T`. + /// + /// This iterator may return elements from the table that have a hash value + /// different than the one provided. You should always validate the returned + /// values before using them. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "a", hasher); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "c", hasher); + /// + /// // Will print "a" and "b" (and possibly "c") in an arbitrary order. + /// for x in table.iter_hash(hasher(&"a")) { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_hash(&self, hash: u64) -> IterHash<'_, T> { + IterHash { + inner: unsafe { self.raw.iter_hash(hash) }, + marker: PhantomData, + } + } + + /// A mutable iterator visiting all elements which may match a hash. + /// The iterator element type is `&'a mut T`. + /// + /// This iterator may return elements from the table that have a hash value + /// different than the one provided. You should always validate the returned + /// values before using them. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 2, hasher); + /// table.insert_unique(hasher(&1), 3, hasher); + /// table.insert_unique(hasher(&2), 5, hasher); + /// + /// // Update matching values + /// for val in table.iter_hash_mut(hasher(&1)) { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The values will contain 4 and 6 and may contain either 5 or 10. + /// assert!(vec.contains(&4)); + /// assert!(vec.contains(&6)); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_hash_mut(&mut self, hash: u64) -> IterHashMut<'_, T> { + IterHashMut { + inner: unsafe { self.raw.iter_hash(hash) }, + marker: PhantomData, + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=6 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// table.retain(|&mut x| x % 2 == 0); + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.raw.iter() { + if !f(item.as_mut()) { + self.raw.erase(item); + } + } + } + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=3 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// assert!(!table.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in table.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + inner: self.raw.drain(), + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashTable::retain + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 0..8 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// let drained: Vec = table.extract_if(|&mut v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = table.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.raw.iter() }, + table: &mut self.raw, + }, + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// [Some(&mut ("Athenæum", 1807)), Some(&mut ("Library of Congress", 1800))], + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, [Some(&mut ("Athenæum", 1807)), None]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + /// + /// ```should_panic + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// # use hashbrown::{HashTable, DefaultHashBuilder}; + /// # use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Athenæum", 1807), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// // Duplicate keys result in a panic! + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test(); + /// # #[cfg(not(feature = "nightly"))] + /// # panic!(); + /// # } + /// ``` + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + self.raw.get_many_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashTable::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// [Some(&mut ("Athenæum", 1807)), Some(&mut ("Library of Congress", 1800))], + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, [Some(&mut ("Athenæum", 1807)), None]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + self.raw.get_many_unchecked_mut(hashes, eq) + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.raw.allocation_size() + } +} + +impl IntoIterator for HashTable +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.raw.into_iter(), + } + } +} + +impl<'a, T, A> IntoIterator for &'a HashTable +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, A> IntoIterator for &'a mut HashTable +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl Default for HashTable +where + A: Allocator + Default, +{ + fn default() -> Self { + Self { + raw: Default::default(), + } + } +} + +impl Clone for HashTable +where + T: Clone, + A: Allocator + Clone, +{ + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + +impl fmt::Debug for HashTable +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +/// A view into a single entry in a table, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashTable`]. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`entry`]: struct.HashTable.html#method.entry +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, OccupiedEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); +/// assert_eq!(table.len(), 3); +/// // Nonexistent value (insert) +/// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); +/// +/// // Existing value (or_insert) +/// table +/// .entry(hasher(&"b"), |&x| x == "b", hasher) +/// .or_insert("b"); +/// // Nonexistent value (or_insert) +/// table +/// .entry(hasher(&"e"), |&x| x == "e", hasher) +/// .or_insert("e"); +/// +/// println!("Our HashTable: {:?}", table); +/// +/// let mut vec: Vec<_> = table.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub enum Entry<'a, T, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::{Entry, OccupiedEntry}; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in ["a", "b"] { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => {} + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::{Entry, OccupiedEntry}; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::<&str>::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => {} + /// Entry::Occupied(_) => unreachable!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Vacant(VacantEntry<'a, T, A>), +} + +impl fmt::Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +impl<'a, T, A> Entry<'a, T, A> +where + A: Allocator, +{ + /// Sets the value of the entry, replacing any existing value if there is + /// one, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// let entry = table + /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) + /// .insert("horseyland"); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(mut entry) => { + *entry.get_mut() = value; + entry + } + Entry::Vacant(entry) => entry.insert(value), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // nonexistent key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// + /// // existing key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// assert_eq!(table.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty.. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) + /// .or_insert_with(|| "poneyland".to_string()); + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |x| x == "poneyland") + /// .is_some()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 42)) + /// ); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 43)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +/// A view into an occupied entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, OccupiedEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); +/// assert_eq!(table.len(), 3); +/// +/// // Existing key +/// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(table.len(), 3); +/// +/// // Existing key (take) +/// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove().0, "c"); +/// } +/// } +/// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); +/// assert_eq!(table.len(), 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct OccupiedEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + bucket: Bucket, + table: &'a mut HashTable, +} + +unsafe impl Send for OccupiedEntry<'_, T, A> +where + T: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, T, A> +where + T: Sync, + A: Sync + Allocator, +{ +} + +impl fmt::Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +impl<'a, T, A> OccupiedEntry<'a, T, A> +where + A: Allocator, +{ + /// Takes the value out of the entry, and returns it along with a + /// `VacantEntry` that can be used to insert another value with the same + /// hash as the one that was just removed. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// // The table is empty + /// assert!(table.is_empty() && table.capacity() == 0); + /// + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// let capacity_before_remove = table.capacity(); + /// + /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// assert_eq!(o.remove().0, "poneyland"); + /// } + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_none()); + /// // Now table hold none elements but capacity is equal to the old one + /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> (T, VacantEntry<'a, T, A>) { + let (val, slot) = unsafe { self.table.raw.remove(self.bucket) }; + ( + val, + VacantEntry { + hash: self.hash, + insert_slot: slot, + table: self.table, + }, + ) + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// + /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get(&self) -> &T { + unsafe { self.bucket.as_ref() } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// if let Entry::Occupied(mut o) = table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// o.get_mut().1 += 10; + /// assert_eq!(o.get().1, 22); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().1 += 2; + /// } + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 24)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the table itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// let value: &mut (&str, u32); + /// match table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// value.1 += 10; + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 22)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn into_mut(self) -> &'a mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// A view into a vacant entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, VacantEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert("a"); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct VacantEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + insert_slot: InsertSlot, + table: &'a mut HashTable, +} + +impl fmt::Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("VacantEntry") + } +} + +impl<'a, T, A> VacantEntry<'a, T, A> +where + A: Allocator, +{ + /// Inserts a new element into the table with the hash that was used to + /// obtain the `VacantEntry`. + /// + /// An `OccupiedEntry` is returned for the newly inserted element. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// o.insert("poneyland"); + /// } + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), + /// Some(&"poneyland") + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + let bucket = unsafe { + self.table + .raw + .insert_in_slot(self.hash, self.insert_slot, value) + }; + OccupiedEntry { + hash: self.hash, + bucket, + table: self.table, + } + } + + /// Converts the `VacantEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`]. +/// +/// This type only exists due to [limitations] in Rust's NLL borrow checker. In +/// the future, `find_entry` will return an `Option` and this +/// type will be removed. +/// +/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{AbsentEntry, Entry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); +/// entry_v +/// .into_table() +/// .insert_unique(hasher(&"a"), "a", hasher); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct AbsentEntry<'a, T, A = Global> +where + A: Allocator, +{ + table: &'a mut HashTable, +} + +impl fmt::Debug for AbsentEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("AbsentEntry") + } +} + +impl<'a, T, A> AbsentEntry<'a, T, A> +where + A: Allocator, +{ + /// Converts the `AbsentEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// An iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashTable.html#method.iter +/// [`HashTable`]: struct.HashTable.html +pub struct Iter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a T>, +} + +impl Default for Iter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Iter { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl<'a, T> Clone for Iter<'a, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Iter<'a, T> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashTable.html#method.iter_mut +/// [`HashTable`]: struct.HashTable.html +pub struct IterMut<'a, T> { + inner: RawIter, + marker: PhantomData<&'a mut T>, +} + +impl Default for IterMut<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterMut { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl ExactSizeIterator for IterMut<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterMut<'_, T> {} + +impl fmt::Debug for IterMut<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(Iter { + inner: self.inner.clone(), + marker: PhantomData, + }) + .finish() + } +} + +/// An iterator over the entries of a `HashTable` that could match a given hash. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter_hash`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_hash`]: struct.HashTable.html#method.iter_hash +/// [`HashTable`]: struct.HashTable.html +pub struct IterHash<'a, T> { + inner: RawIterHash, + marker: PhantomData<&'a T>, +} + +impl Default for IterHash<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterHash { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for IterHash<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl FusedIterator for IterHash<'_, T> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl<'a, T> Clone for IterHash<'a, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> IterHash<'a, T> { + IterHash { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for IterHash<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashTable` that could match a given hash. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_hash_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_hash_mut`]: struct.HashTable.html#method.iter_hash_mut +/// [`HashTable`]: struct.HashTable.html +pub struct IterHashMut<'a, T> { + inner: RawIterHash, + marker: PhantomData<&'a mut T>, +} + +impl Default for IterHashMut<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterHashMut { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for IterHashMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl FusedIterator for IterHashMut<'_, T> {} + +impl fmt::Debug for IterHashMut<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(IterHash { + inner: self.inner.clone(), + marker: PhantomData, + }) + .finish() + } +} + +/// An owning iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `T`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashTable`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The table cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashTable.html#method.into_iter +/// [`HashTable`]: struct.HashTable.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +pub struct IntoIter +where + A: Allocator, +{ + inner: RawIntoIter, +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IntoIter { + inner: Default::default(), + } + } +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for IntoIter +where + A: Allocator, +{ + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoIter where A: Allocator {} + +impl fmt::Debug for IntoIter +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(Iter { + inner: self.inner.iter(), + marker: PhantomData, + }) + .finish() + } +} + +/// A draining iterator over the items of a `HashTable`. +/// +/// This `struct` is created by the [`drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`drain`]: struct.HashTable.html#method.drain +pub struct Drain<'a, T, A: Allocator = Global> { + inner: RawDrain<'a, T, A>, +} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for Drain<'_, T, A> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Drain<'_, T, A> {} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(Iter { + inner: self.inner.iter(), + marker: PhantomData, + }) + .finish() + } +} + +/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by [`HashTable::extract_if`]. See its +/// documentation for more. +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, T, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, T, A>, +} + +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next(|val| (self.f)(val)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {} + +#[cfg(test)] +mod tests { + use super::HashTable; + + #[test] + fn test_allocation_info() { + assert_eq!(HashTable::<()>::new().allocation_size(), 0); + assert_eq!(HashTable::::new().allocation_size(), 0); + assert!(HashTable::::with_capacity(1).allocation_size() > core::mem::size_of::()); + } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/src/util.rs b/deps/crates/vendor/hashbrown-0.15.5/src/util.rs new file mode 100644 index 00000000000000..90a8df311c2b2d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/src/util.rs @@ -0,0 +1,38 @@ +// FIXME: Replace with `core::hint::{likely, unlikely}` once they are stable. +#[cfg(feature = "nightly")] +pub(crate) use core::intrinsics::{likely, unlikely}; + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +#[cold] +fn cold_path() {} + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +pub(crate) fn likely(b: bool) -> bool { + if b { + true + } else { + cold_path(); + false + } +} + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +pub(crate) fn unlikely(b: bool) -> bool { + if b { + cold_path(); + true + } else { + false + } +} + +// FIXME: use strict provenance functions once they are stable. +// Implement it with a transmute for now. +#[inline(always)] +#[allow(clippy::useless_transmute)] // clippy is wrong, cast and transmute are different here +pub(crate) fn invalid_mut(addr: usize) -> *mut T { + unsafe { core::mem::transmute(addr) } +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/tests/equivalent_trait.rs b/deps/crates/vendor/hashbrown-0.15.5/tests/equivalent_trait.rs new file mode 100644 index 00000000000000..713dddd53c7c6a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use hashbrown::Equivalent; +use hashbrown::HashMap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let mut map = HashMap::new(); + map.insert((s("a"), s("b")), 1); + map.insert((s("a"), s("x")), 2); + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = HashMap::new(); + map.insert(s("a"), 1); + map.insert(s("b"), 2); + map.insert(s("x"), 3); + map.insert(s("y"), 4); + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.remove("b"), Some(2)); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/tests/hasher.rs b/deps/crates/vendor/hashbrown-0.15.5/tests/hasher.rs new file mode 100644 index 00000000000000..22373784442943 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/tests/hasher.rs @@ -0,0 +1,65 @@ +//! Sanity check that alternate hashers work correctly. + +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use std::hash::{BuildHasher, BuildHasherDefault, Hasher}; + +fn check() { + let range = 0..1_000; + + let mut set = HashSet::::default(); + set.extend(range.clone()); + + assert!(!set.contains(&i32::MIN)); + assert!(!set.contains(&(range.start - 1))); + for i in range.clone() { + assert!(set.contains(&i)); + } + assert!(!set.contains(&range.end)); + assert!(!set.contains(&i32::MAX)); +} + +/// Use hashbrown's default hasher. +#[test] +fn default() { + check::(); +} + +/// Use std's default hasher. +#[test] +fn random_state() { + check::(); +} + +/// Use a constant 0 hash. +#[test] +fn zero() { + #[derive(Default)] + struct ZeroHasher; + + impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} + +/// Use a constant maximum hash. +#[test] +fn max() { + #[derive(Default)] + struct MaxHasher; + + impl Hasher for MaxHasher { + fn finish(&self) -> u64 { + u64::MAX + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/tests/rayon.rs b/deps/crates/vendor/hashbrown-0.15.5/tests/rayon.rs new file mode 100644 index 00000000000000..d55e5a9804dd2a --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/tests/rayon.rs @@ -0,0 +1,535 @@ +#![cfg(feature = "rayon")] + +#[macro_use] +extern crate lazy_static; + +use hashbrown::{HashMap, HashSet}; +use rayon::iter::{ + IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend, + ParallelIterator, +}; + +macro_rules! assert_eq3 { + ($e1:expr, $e2:expr, $e3:expr) => {{ + assert_eq!($e1, $e2); + assert_eq!($e1, $e3); + assert_eq!($e2, $e3); + }}; +} + +lazy_static! { + static ref MAP_EMPTY: HashMap = HashMap::new(); + static ref MAP: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m.insert('c', 30); + m.insert('e', 50); + m.insert('f', 60); + m.insert('d', 40); + m + }; +} + +#[test] +fn map_seq_par_equivalence_iter_empty() { + let vec_seq = MAP_EMPTY.iter().collect::>(); + let vec_par = MAP_EMPTY.par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter() { + let mut vec_seq = MAP.iter().collect::>(); + let mut vec_par = MAP.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &10), + (&'b', &20), + (&'c', &30), + (&'d', &40), + (&'e', &50), + (&'f', &60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_keys_empty() { + let vec_seq = MAP_EMPTY.keys().collect::>(); + let vec_par = MAP_EMPTY.par_keys().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_keys() { + let mut vec_seq = MAP.keys().collect::>(); + let mut vec_par = MAP.par_keys().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_empty() { + let vec_seq = MAP_EMPTY.values().collect::>(); + let vec_par = MAP_EMPTY.par_values().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values() { + let mut vec_seq = MAP.values().collect::>(); + let mut vec_par = MAP.par_values().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&10, &20, &30, &40, &50, &60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_iter_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.iter_mut().collect::>(); + let vec_par = map2.par_iter_mut().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.iter_mut().collect::>(); + let mut vec_par = map2.par_iter_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &mut 10), + (&'b', &mut 20), + (&'c', &mut 30), + (&'d', &mut 40), + (&'e', &mut 50), + (&'f', &mut 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.values_mut().collect::>(); + let vec_par = map2.par_values_mut().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.values_mut().collect::>(); + let mut vec_par = map2.par_values_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_into_iter_empty() { + let vec_seq = MAP_EMPTY.clone().into_iter().collect::>(); + let vec_par = MAP_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_into_iter() { + let mut vec_seq = MAP.clone().into_iter().collect::>(); + let mut vec_par = MAP.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + ('a', 10), + ('b', 20), + ('c', 30), + ('d', 40), + ('e', 50), + ('f', 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref MAP_VEC_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_VEC: Vec<(char, u32)> = vec![ + ('b', 20), + ('a', 10), + ('c', 30), + ('e', 50), + ('f', 60), + ('d', 40), + ]; +} + +#[test] +fn map_seq_par_equivalence_collect_empty() { + let map_expected = MAP_EMPTY.clone(); + let map_seq = MAP_VEC_EMPTY.clone().into_iter().collect::>(); + let map_par = MAP_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +#[test] +fn map_seq_par_equivalence_collect() { + let map_expected = MAP.clone(); + let map_seq = MAP_VEC.clone().into_iter().collect::>(); + let map_par = MAP_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +lazy_static! { + static ref MAP_EXISTING_EMPTY: HashMap = HashMap::new(); + static ref MAP_EXISTING: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m + }; + static ref MAP_EXTENSION_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_EXTENSION: Vec<(char, u32)> = vec![('c', 30), ('e', 50), ('f', 60), ('d', 40),]; +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashMap::new(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend() { + let expected = MAP_EXTENSION.iter().copied().collect::>(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend_empty() { + let expected = MAP_EXISTING.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend() { + let expected = MAP.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +lazy_static! { + static ref SET_EMPTY: HashSet = HashSet::new(); + static ref SET: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s.insert('c'); + s.insert('e'); + s.insert('f'); + s.insert('d'); + s + }; +} + +#[test] +fn set_seq_par_equivalence_iter_empty() { + let vec_seq = SET_EMPTY.iter().collect::>(); + let vec_par = SET_EMPTY.par_iter().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn set_seq_par_equivalence_iter() { + let mut vec_seq = SET.iter().collect::>(); + let mut vec_par = SET.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn set_seq_par_equivalence_into_iter_empty() { + let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); + let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); + + // Work around type inference failure introduced by rend dev-dependency. + let empty: [char; 0] = []; + assert_eq3!(vec_seq, vec_par, empty); +} + +#[test] +fn set_seq_par_equivalence_into_iter() { + let mut vec_seq = SET.clone().into_iter().collect::>(); + let mut vec_par = SET.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref SET_VEC_EMPTY: Vec = vec![]; + static ref SET_VEC: Vec = vec!['b', 'a', 'c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_collect_empty() { + let set_expected = SET_EMPTY.clone(); + let set_seq = SET_VEC_EMPTY.clone().into_iter().collect::>(); + let set_par = SET_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +#[test] +fn set_seq_par_equivalence_collect() { + let set_expected = SET.clone(); + let set_seq = SET_VEC.clone().into_iter().collect::>(); + let set_par = SET_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +lazy_static! { + static ref SET_EXISTING_EMPTY: HashSet = HashSet::new(); + static ref SET_EXISTING: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s + }; + static ref SET_EXTENSION_EMPTY: Vec = vec![]; + static ref SET_EXTENSION: Vec = vec!['c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashSet::new(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend() { + let expected = SET_EXTENSION.iter().copied().collect::>(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend_empty() { + let expected = SET_EXISTING.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend() { + let expected = SET.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +lazy_static! { + static ref SET_A: HashSet = ['a', 'b', 'c', 'd'].iter().copied().collect(); + static ref SET_B: HashSet = ['a', 'b', 'e', 'f'].iter().copied().collect(); + static ref SET_DIFF_AB: HashSet = ['c', 'd'].iter().copied().collect(); + static ref SET_DIFF_BA: HashSet = ['e', 'f'].iter().copied().collect(); + static ref SET_SYMM_DIFF_AB: HashSet = ['c', 'd', 'e', 'f'].iter().copied().collect(); + static ref SET_INTERSECTION_AB: HashSet = ['a', 'b'].iter().copied().collect(); + static ref SET_UNION_AB: HashSet = + ['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect(); +} + +#[test] +fn set_seq_par_equivalence_difference() { + let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::>(); + let diff_ab_par = SET_A + .par_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB); + + let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::>(); + let diff_ba_par = SET_B + .par_difference(&*SET_A) + .copied() + .collect::>(); + + assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA); +} + +#[test] +fn set_seq_par_equivalence_symmetric_difference() { + let symm_diff_ab_seq = SET_A + .symmetric_difference(&*SET_B) + .copied() + .collect::>(); + let symm_diff_ab_par = SET_A + .par_symmetric_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB); +} + +#[test] +fn set_seq_par_equivalence_intersection() { + let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::>(); + let intersection_ab_par = SET_A + .par_intersection(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!( + intersection_ab_seq, + intersection_ab_par, + *SET_INTERSECTION_AB + ); +} + +#[test] +fn set_seq_par_equivalence_union() { + let union_ab_seq = SET_A.union(&*SET_B).copied().collect::>(); + let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::>(); + + assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/tests/serde.rs b/deps/crates/vendor/hashbrown-0.15.5/tests/serde.rs new file mode 100644 index 00000000000000..a642348b3b3b23 --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/tests/serde.rs @@ -0,0 +1,65 @@ +#![cfg(feature = "serde")] + +use core::hash::BuildHasherDefault; +use fnv::FnvHasher; +use hashbrown::{HashMap, HashSet}; +use serde_test::{assert_tokens, Token}; + +// We use FnvHash for this test because we rely on the ordering +type FnvHashMap = HashMap>; +type FnvHashSet = HashSet>; + +#[test] +fn map_serde_tokens_empty() { + let map = FnvHashMap::::default(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens() { + let mut map = FnvHashMap::default(); + map.insert('b', 20); + map.insert('a', 10); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('c'), + Token::I32(30), + Token::Char('b'), + Token::I32(20), + Token::MapEnd, + ], + ); +} + +#[test] +fn set_serde_tokens_empty() { + let set = FnvHashSet::::default(); + + assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); +} + +#[test] +fn set_serde_tokens() { + let mut set = FnvHashSet::default(); + set.insert(20); + set.insert(10); + set.insert(30); + + assert_tokens( + &set, + &[ + Token::Seq { len: Some(3) }, + Token::I32(30), + Token::I32(20), + Token::I32(10), + Token::SeqEnd, + ], + ); +} diff --git a/deps/crates/vendor/hashbrown-0.15.5/tests/set.rs b/deps/crates/vendor/hashbrown-0.15.5/tests/set.rs new file mode 100644 index 00000000000000..d25f3d459e377d --- /dev/null +++ b/deps/crates/vendor/hashbrown-0.15.5/tests/set.rs @@ -0,0 +1,34 @@ +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use rand::{distr::Alphanumeric, rngs::SmallRng, Rng, SeedableRng}; +use std::iter; + +#[test] +fn test_hashset_insert_remove() { + let mut m: HashSet> = HashSet::new(); + let seed = u64::from_le_bytes(*b"testseed"); + + let rng = &mut SmallRng::seed_from_u64(seed); + let tx: Vec> = iter::repeat_with(|| { + rng.sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect() + }) + .take(4096) + .collect(); + + // more readable with explicit `true` / `false` + #[allow(clippy::bool_assert_comparison)] + for _ in 0..32 { + for x in &tx { + assert_eq!(m.contains(x), false); + assert_eq!(m.insert(x.clone()), true); + } + for (i, x) in tx.iter().enumerate() { + println!("removing {i} {x:?}"); + assert_eq!(m.remove(x), true); + } + } +} diff --git a/deps/crates/vendor/hashbrown/.cargo-checksum.json b/deps/crates/vendor/hashbrown/.cargo-checksum.json new file mode 100644 index 00000000000000..e5e945c87c8412 --- /dev/null +++ b/deps/crates/vendor/hashbrown/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"803392e4d2f4e80c1553f6a32c20da6ed00c95c154a3e5d890ef891ae8d21797","CHANGELOG.md":"6f0fd2619eccf0f920593293177b62fce5cb5357af4e5a656b422f1e253bf0fa","Cargo.lock":"0f68a377f467ab247b6e16d9cdad927bd6a561e34ab2587356185a3a6040d0d6","Cargo.toml":"564e1fe565896de6ed4811222b105d3e4abe54c2097b9c14bef5e7c92bc1bb83","Cargo.toml.orig":"5c7253cc5a964ea6d59c8f52c7f8d25a76afb367059826155c63aa40ffb084aa","Cross.toml":"47aeebdfd782a5052346ce29bf750c225828e108aca723486c3839adba5d6901","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"f793b5cfaab5702b9e8bcf5ac7ec5bb198bdf2a89c1861070c1ad64b33a27ad3","benches/bench.rs":"63fb7937742da3d6223e5b52beed98ac4b4b27b712d13cf71da22d9d025d8f18","benches/general_ops.rs":"82430662ad66109c3b1026edf8ed89faee09a23fd34291cf7b2e68903ab5f718","benches/insert_unique_unchecked.rs":"ed3fad0a5c5ca654f0ab16694cb48152046d5a503e85902cd83cbdda7d9c89c4","benches/set_ops.rs":"14ba987967d74eae0f0775e20371c14aa533032bc03cb6a48653c12f32df01a3","benches/with_capacity.rs":"65efebbedbb9ede57ba8b9e60674358e4dd6124aadc58ffa3084b4b94d2ed65a","clippy.toml":"b350f0ed39349f1151326c565f5ea8dea3cf9e2a708c33b435ceb5f98ec5237c","src/alloc.rs":"7ffdd9a84787cb1f93b31184c32733649324faf500bcc3012197ee91353c9ac7","src/control/bitmask.rs":"5aaa52db03d2d17fe85fed67aa2bdc4ea376a0bf0e18010576e794b502d44689","src/control/group/generic.rs":"5d244fc9f9cd05ab8b92954452b43d8c321452d0dfa8816c2b1ce539fbb3270b","src/control/group/lsx.rs":"2164bb735d9123fb4ebb452a91a76d2ed84b277602c6ea79564e439e1c148359","src/control/group/mod.rs":"32150c3ac5bd4197ce122fea5b45ec1047c1e5227a4ba940aef6ceab2c00f54b","src/control/group/neon.rs":"bd8366684d86f456b9880940bbc72d7aabfb642d88a7bdd90de66ef7f643fae5","src/control/group/sse2.rs":"53d7d09c72332232b4562aa7dfabf18e5f57c5009a672b2cfac7193ef468b349","src/control/mod.rs":"83fede19e9c5a26fd2c7372e6cf92547d32ade4cd69fde8a0eaaeb1be6ddc2ba","src/control/tag.rs":"691dc7aa8d720e6df59a82ac11d66c72802ffffc684620c8ff29523352aefd13","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"1d882a124ffbdfd168796dcc3767205cb578d0643fdd91b768efea340fbdc9ec","src/external_trait_impls/rayon/map.rs":"2819b0e7bb77594710a0173d2a7bda318350096f79d0e0e3be4e92c616d38f69","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"518dcab0a1399b91411a7b93ed8b8e02543d5404cfc45e67b891ddc811e487b7","src/external_trait_impls/rayon/set.rs":"f58a884cb2d74ecb6e165d4f63710199db8b4c4e9935e355e258ae7eb9d76fa8","src/external_trait_impls/rayon/table.rs":"6703ed24b69510b74a6777388d6fe303f8838c740c809ea4ce5e9c87aec088df","src/external_trait_impls/serde.rs":"cbb5f60e0b093730a340e6133b0b5f5842ba6398a454acdabd635ae75c1d8010","src/hasher.rs":"939bc4f8c9e2d7e7ace266a8c121360ab4b44ad0540cdee06951e0197d96bc3c","src/lib.rs":"23de74f311e3584574b39041df306b0cbb9ecb700ed33fba1e02ba9d26f70a23","src/macros.rs":"4c949a8c44e457c4f04f0b55d5c1e0214b52a6ed2951f265af0113b0d2adb015","src/map.rs":"b79497ce537ffc5ed4f8f3399434b9216c01e7927fdc434fee190e9e9ce2abb0","src/raw.rs":"0c8ad353ba95817e72b0a8fea48fa2599099ea3def374f254ab6402a9c468d22","src/raw_entry.rs":"6393317a9818e2a9121b76d53083cd5ce358bc63e2702e17b9c138914d6842ee","src/rustc_entry.rs":"9d7ca1d375ace25d2107e09a840ac950dfacbd3543dde424e0f1e714878bdec6","src/scopeguard.rs":"aa557686a2090eee1da25e960a4461d3750725065a4a1266b80a2eadfec38b2a","src/set.rs":"71485eb08e622a7aeb1978817233f0e9c75f4daec87d2d6fa6eba6e0aaf80f2f","src/table.rs":"9d37739758f9df08d23c3ab792d29547b04bfd29b08900407a0d2b8ecd26cda9","src/util.rs":"02546d6e681f833405b8a15ef9bc8d3e80b1ef3bce65caf70d8e16cbadf4a410","tests/equivalent_trait.rs":"092e4b137b6abf7d57277f77ebc4f3641eba22a650dade79f2b0d793062627fb","tests/hasher.rs":"fd06130f011660743202904221f3f7487d8d143d8903c73cd3a76d079ebbe9fb","tests/hasher_unwind.rs":"d36a1650a5cf7a5f424250d80abe8496385f6395e37fd9262262724c22306a0f","tests/rayon.rs":"5470842da0372b03059de3c8eaeb59b72bfd52eb76026d0eda51cf4634047add","tests/serde.rs":"27689fe22b6301db7fdf01de19be621b2d9af7d2ad157c000600bfe760f1cbb3","tests/set.rs":"dc4e546c94f95869ce85f55ce8e10b9d100b7b0ef6e80e1720b94af621f45ed0"},"package":"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown/.cargo_vcs_info.json b/deps/crates/vendor/hashbrown/.cargo_vcs_info.json new file mode 100644 index 00000000000000..ff0304abcb01d3 --- /dev/null +++ b/deps/crates/vendor/hashbrown/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "d290456969d0e89e6799d8a673c95112962b70ec" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/hashbrown/CHANGELOG.md b/deps/crates/vendor/hashbrown/CHANGELOG.md new file mode 100644 index 00000000000000..25f26c0c0e37c6 --- /dev/null +++ b/deps/crates/vendor/hashbrown/CHANGELOG.md @@ -0,0 +1,669 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.17.0](https://github.com/rust-lang/hashbrown/compare/v0.16.1...v0.17.0) - 2026-04-06 + +### Added + +- Added `hash_table::OccupiedEntry::replace_entry_with` (#669) +- Added `hash_map::{OccupiedEntry::into_entry, VacantEntryRef::insert_entry_with_key}` (#670) +- Added `hash_table::UnsafeIter` (#667) +- Added `iter` methods to various `HashTable` iterators (#667) +- Added `HashMap::{replace_key,replace_key_unchecked,insert_with_key_unchecked}` (#681) +- Added `into_map` methods to all `HashMap` entry types (#686) +- Added `into_table` methods to all `HashTable` entry types (#686) +- Added `#[must_use]` to constructors (#697) +- `TryReserveError` now implements `Error` (#698) + +### Changed + +- Changed `EntryRef` to use `ToOwned` (#670) +- Bumped MSRV to 1.85 (2024 edition) (#676) + +### Fixed + +- `HashTable:clone_from` now forwards to `RawTable::clone_from` instead of using the default implementation (#668) +- Fixed potential UB in `RawTableInner::fallible_with_capacity` (#692) +- Fixed incorrect length if a hasher panics during rehash (#710) + +## [0.16.1](https://github.com/rust-lang/hashbrown/compare/v0.16.0...v0.16.1) - 2025-11-20 + +### Added + +- Added `HashTable` methods related to the raw bucket index (#657) +- Added `VacantEntryRef::insert_with_key` (#579) + +### Changed + +- Removed specialization for `Copy` types (#662) +- The `get_many_mut` family of methods have been renamed to `get_disjoint_mut` + to match the standard library. The old names are still present for now, but + deprecated. (#648) +- Recognize and use over-sized allocations when using custom allocators. (#523) +- Depend on `serde_core` instead of `serde`. (#649) +- Optimized `collect` on rayon parallel iterators. (#652) + +## [0.16.0](https://github.com/rust-lang/hashbrown/compare/v0.15.5...v0.16.0) - 2025-08-28 + +### Changed + +- Bump foldhash, the default hasher, to 0.2.0. +- Replaced `DefaultHashBuilder` with a newtype wrapper around `foldhash` instead + of re-exporting it directly. + +## [0.15.5](https://github.com/rust-lang/hashbrown/compare/v0.15.4...v0.15.5) - 2025-08-07 + +### Added + +- Added `Entry::or_default_entry` and `Entry::or_insert_entry`. + +### Changed + +- Re-implemented likely/unlikely with `#[cold]` + +## [0.15.4](https://github.com/rust-lang/hashbrown/compare/v0.15.3...v0.15.4) - 2025-06-05 + +### Changed + +- Removed optional dependency on compiler-builtins. This only affects building as part of `std`. + +## [0.15.3](https://github.com/rust-lang/hashbrown/compare/v0.15.2...v0.15.3) - 2025-04-29 + +### Added + +- SIMD implementation for LoongArch (#592, requires nightly) + +### Changed + +- Optimized insertion path by avoiding an unnecessary `match_empty` (#607) +- Increased minimum table size for small types (#615) +- Dropped FnMut trait bounds from `ExtractIf` data structures (#616) +- Relaxed constraint in `hash_map::EntryRef` insertion methods `K: From<&Q>` to &Q: `Into` (#611) +- Added allocator template argument for `rustc_iter` (#605) +- The `allocator-api2/nightly` feature is no longer enabled by `hashbrown/nightly` (#606) + +## [v0.15.2] - 2024-11-14 + +### Added + +- Marked `const fn` constructors as `rustc_const_stable_indirect` when built as + part of the standard library. (#586) + +## [v0.15.1] - 2024-11-03 + +This release removes the `borsh` feature introduced in 0.15.0 because it was +found to be incorrectly implemented. Users should use the `hashbrown` feature of +the `borsh` crate instead which provides the same trait implementations. + +## ~~[v0.15.0] - 2024-10-01~~ + +This release was _yanked_ due to a broken implementation of the `borsh` feature. + +This update contains breaking changes that remove the `raw` API with the hope of +centralising on the `HashTable` API in the future. You can follow the discussion +and progress in #545 to discuss features you think should be added to this API +that were previously only possible on the `raw` API. + +### Added + +- Added `borsh` feature with `BorshSerialize` and `BorshDeserialize` impls. (#525) +- Added `Assign` impls for `HashSet` operators. (#529) +- Added `Default` impls for iterator types. (#542) +- Added `HashTable::iter_hash{,_mut}` methods. (#549) +- Added `Hash{Table,Map,Set}::allocation_size` methods. (#553) +- Implemented `Debug` and `FusedIterator` for all `HashTable` iterators. (#561) +- Specialized `Iterator::fold` for all `HashTable` iterators. (#561) + +### Changed + +- Changed `hash_set::VacantEntry::insert` to return `OccupiedEntry`. (#495) +- Improved`hash_set::Difference::size_hint` lower-bound. (#530) +- Improved `HashSet::is_disjoint` performance. (#531) +- `equivalent` feature is now enabled by default. (#532) +- `HashSet` operators now return a set with the same allocator. (#529) +- Changed the default hasher to foldhash. (#563) +- `ahash` feature has been renamed to `default-hasher`. (#533) +- Entry API has been reworked and several methods have been renamed. (#535) +- `Hash{Map,Set}::insert_unique_unchecked` is now unsafe. (#556) +- The signature of `get_many_mut` and related methods was changed. (#562) + +### Fixed + +* Fixed typos, stray backticks in docs. (#558, #560) + +### Removed + +- Raw entry API is now under `raw-entry` feature, to be eventually removed. (#534, #555) +- Raw table API has been made private and the `raw` feature is removed; + in the future, all code should be using the `HashTable` API instead. (#531, #546) +- `rykv` feature was removed; this is now provided by the `rykv` crate instead. (#554) +- `HashSet::get_or_insert_owned` was removed in favor of `get_or_insert_with`. (#555) + +## [v0.14.5] - 2024-04-28 + +### Fixed + +- Fixed index calculation in panic guard of `clone_from_impl`. (#511) + +## ~~[v0.14.4] - 2024-03-19~~ + +This release was _yanked_ due to a breaking change. + +## [v0.14.3] - 2023-11-26 + +### Added + +- Specialized `fold` implementation of iterators. (#480) + +### Fixed + +- Avoid using unstable `ptr::invalid_mut` on nightly. (#481) + +## [v0.14.2] - 2023-10-19 + +### Added + +- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466) + +### Fixed + +- Disabled the use of NEON instructions on big-endian ARM. (#475) +- Disabled the use of NEON instructions on Miri. (#476) + +## [v0.14.1] - 2023-09-28 + +### Added + +- Allow serializing `HashMap`s that use a custom allocator. (#449) + +### Changed + +- Use the `Equivalent` trait from the `equivalent` crate. (#442) +- Slightly improved performance of table resizing. (#451) +- Relaxed MSRV to 1.63.0. (#457) +- Removed `Clone` requirement from custom allocators. (#468) + +### Fixed + +- Fixed custom allocators being leaked in some situations. (#439, #465) + +## [v0.14.0] - 2023-06-01 + +### Added + +- Support for `allocator-api2` crate + for interfacing with custom allocators on stable. (#417) +- Optimized implementation for ARM using NEON instructions. (#430) +- Support for rkyv serialization. (#432) +- `Equivalent` trait to look up values without `Borrow`. (#345) +- `Hash{Map,Set}::raw_table_mut` is added which returns a mutable reference. (#404) +- Fast path for `clear` on empty tables. (#428) + +### Changed + +- Optimized insertion to only perform a single lookup. (#277) +- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining + elements when the iterator is dropped. #(374) +- Bumped MSRV to 1.64.0. (#431) +- `{Map,Set}::raw_table` now returns an immutable reference. (#404) +- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is + specified in generics. (#389) +- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387) +- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429) +- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429) +- `RawTable::remove` now also returns an `InsertSlot`. (#429) +- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429) +- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427) +- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423) +- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with` + were changed to give a `&K` instead of a `&Q` to the closure. + +### Removed + +- Support for `bumpalo` as an allocator with custom wrapper. + Use `allocator-api2` feature in `bumpalo` to use it as an allocator + for `hashbrown` collections. (#417) + +## [v0.13.2] - 2023-01-12 + +### Fixed + +- Added `#[inline(always)]` to `find_inner`. (#375) +- Fixed `RawTable::allocation_info` for empty tables. (#376) + +## [v0.13.1] - 2022-11-10 + +### Added + +- Added `Equivalent` trait to customize key lookups. (#350) +- Added support for 16-bit targets. (#368) +- Added `RawTable::allocation_info` which provides information about the memory + usage of a table. (#371) + +### Changed + +- Bumped MSRV to 1.61.0. +- Upgraded to `ahash` 0.8. (#357) +- Make `with_hasher_in` const. (#355) +- The following methods have been removed from the `RawTable` API in favor of + safer alternatives: + - `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead. + - `Bucket::read` => Use `RawTable::remove` instead. + - `Bucket::drop` => Use `RawTable::erase` instead. + - `Bucket::write` => Use `Bucket::as_mut` instead. + +### Fixed + +- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362) +- Fixed issue with field retagging in scopeguard. (#359) + +## [v0.12.3] - 2022-07-17 + +### Fixed + +- Fixed double-drop in `RawTable::clone_from`. (#348) + +## [v0.12.2] - 2022-07-09 + +### Added + +- Added `Entry` API for `HashSet`. (#342) +- Added `Extend<&'a (K, V)> for HashMap`. (#340) +- Added length-based short-circuiting for hash table iteration. (#338) +- Added a function to access the `RawTable` of a `HashMap`. (#335) + +### Changed + +- Edited `do_alloc` to reduce LLVM IR generated. (#341) + +## [v0.12.1] - 2022-05-02 + +### Fixed + +- Fixed underflow in `RawIterRange::size_hint`. (#325) +- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325) + +## [v0.12.0] - 2022-01-17 + +### Added + +- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297) +- Added an `allocator()` getter to HashMap and HashSet. (#257) +- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293) +- Added `into_keys` and `into_values` to HashMap. (#295) +- Implement `From` on `HashSet` and `HashMap`. (#298) +- Added `entry_ref` API to `HashMap`. (#201) + +### Changed + +- Bumped minimum Rust version to 1.56.1 and edition to 2021. +- Use u64 for the GroupWord on WebAssembly. (#271) +- Optimized `find`. (#279) +- Made rehashing and resizing less generic to reduce compilation time. (#282) +- Inlined small functions. (#283) +- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292) +- Relaxed the bounds on `Debug` for `HashSet`. (#296) +- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291) +- Don't hash the key when searching in an empty table. (#305) + +### Fixed + +- Guard against allocations exceeding isize::MAX. (#268) +- Made `RawTable::insert_no_grow` unsafe. (#254) +- Inline `static_empty`. (#280) +- Fixed trait bounds on Send/Sync impls. (#303) + +## [v0.11.2] - 2021-03-25 + +### Fixed + +- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) + +## [v0.11.1] - 2021-03-20 + +### Fixed + +- Added missing `pub` modifier to `BumpWrapper`. (#251) + +## [v0.11.0] - 2021-03-14 + +### Added +- Added safe `try_insert_no_grow` method to `RawTable`. (#229) +- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) +- Implemented `Default` for `RawTable`. (#237) +- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and + `HashMap::get_each_key_value_mut`. (#239) +- Added `From>` for `HashSet`. (#235) +- Added `try_insert` method to `HashMap`. (#247) + +### Changed +- The minimum Rust version has been bumped to 1.49.0. (#230) +- Significantly improved compilation times by reducing the amount of generated IR. (#205) + +### Removed +- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) +- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) + +### Fixed +- Fixed union length comparison. (#228) + +## ~~[v0.10.0] - 2021-01-16~~ + +This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) + +### Changed +- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) +- Improved branch prediction hints on stable. (#209) +- Optimized hashing of primitive types with AHash using specialization. (#207) +- Only instantiate `RawTable`'s reserve functions once per key-value. (#204) + +## [v0.9.1] - 2020-09-28 + +### Added +- Added safe methods to `RawTable` (#202): + - `get`: `find` and `as_ref` + - `get_mut`: `find` and `as_mut` + - `insert_entry`: `insert` and `as_mut` + - `remove_entry`: `find` and `remove` + - `erase_entry`: `find` and `erase` + +### Changed +- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) +- Made `RawTable::drain` safe. (#201) + +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + +## [v0.8.2] - 2020-08-08 + +### Changed +- Avoid closures to improve compile times. (#183) +- Do not iterate to drop if empty. (#182) + +## [v0.8.1] - 2020-07-16 + +### Added +- Added `erase` and `remove` to `RawTable`. (#171) +- Added `try_with_capacity` to `RawTable`. (#174) +- Added methods that allow re-using a `RawIter` for `RawDrain`, + `RawIntoIter`, and `RawParIter`. (#175) +- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175) +- Added a `drain_filter` function to `HashSet`. (#179) + +### Changed +- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176) +- `insert_no_grow` is now exposed under the `"raw"` feature. (#180) + +## [v0.8.0] - 2020-06-18 + +### Fixed +- Marked `RawTable::par_iter` as `unsafe`. (#157) + +### Changed +- Reduced the size of `HashMap`. (#159) +- No longer create tables with a capacity of 1 element. (#162) +- Removed `K: Eq + Hash` bounds on `retain`. (#163) +- Pulled in `HashMap` changes from rust-lang/rust (#164): + - `extend_one` support on nightly. + - `CollectionAllocErr` renamed to `TryReserveError`. + - Added `HashSet::get_or_insert_owned`. + - `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`. + +## [v0.7.2] - 2020-04-27 + +### Added +- Added `or_insert_with_key` to `Entry`. (#152) + +### Fixed +- Partially reverted `Clone` optimization which was unsound. (#154) + +### Changed +- Disabled use of `const-random` by default, which prevented reproducible builds. (#155) +- Optimized `repeat` function. (#150) +- Use `NonNull` for buckets, which improves codegen for iterators. (#148) + +## [v0.7.1] - 2020-03-16 + +### Added +- Added `HashMap::get_key_value_mut`. (#145) + +### Changed +- Optimized `Clone` implementation. (#146) + +## [v0.7.0] - 2020-01-31 + +### Added +- Added a `drain_filter` function to `HashMap`. (#135) + +### Changed +- Updated `ahash` dependency to 0.3. (#141) +- Optimized set union and intersection. (#130) +- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123) +- `RawTable::bucket_index` can now be used under the `raw` feature. (#128) + +## [v0.6.3] - 2019-10-31 + +### Added +- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the + `compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125) + +## [v0.6.2] - 2019-10-23 + +### Added +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between + runtime performance and compilation time. (#119) + +## [v0.6.1] - 2019-10-04 + +### Added +- Added `Entry::insert` and `RawEntryMut::insert`. (#118) + +### Changed +- `Group::static_empty` was changed from a `const` to a `static` (#116). + +## [v0.6.0] - 2019-08-13 + +### Fixed +- Fixed AHash accidentally depending on `std`. (#110) + +### Changed +- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency). + +## ~~[v0.5.1] - 2019-08-04~~ + +This release was _yanked_ due to a breaking change for users of `no-default-features`. + +### Added +- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108) +- Added entry-like methods for `HashSet`. (#98) + +### Changed +- Changed the default hasher from FxHash to AHash. (#97) +- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96) + +### Fixed +- We now avoid growing the table during insertions when it wasn't necessary. (#106) +- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100) +- Relaxed `lazy_static` version. (#92) + +## [v0.5.0] - 2019-06-12 + +### Fixed +- Resize with a more conservative amount of space after deletions. (#86) + +### Changed +- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89) + +## [v0.4.0] - 2019-05-30 + +### Fixed +- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82) + +## [v0.3.1] - 2019-05-30 + +### Fixed +- Fixed incorrect use of slice in unsafe code. (#80) + +## [v0.3.0] - 2019-04-23 + +### Changed +- Changed shrink_to to not panic if min_capacity < capacity. (#67) + +### Fixed +- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66) + +## [v0.2.2] - 2019-04-16 + +### Fixed +- Inlined non-nightly lowest_set_bit_nonzero. (#64) +- Fixed build on latest nightly. (#65) + +## [v0.2.1] - 2019-04-14 + +### Changed +- Use for_each in map Extend and FromIterator. (#58) +- Improved worst-case performance of HashSet.is_subset. (#61) + +### Fixed +- Removed incorrect debug_assert. (#60) + +## [v0.2.0] - 2019-03-31 + +### Changed +- The code has been updated to Rust 2018 edition. This means that the minimum + Rust version has been bumped to 1.31 (2018 edition). + +### Added +- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54) +- Added support for using hashbrown as the hash table implementation in libstd. (#46) + +### Fixed +- Fixed cargo build with minimal-versions. (#45) +- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46) +- ZST keys and values are now handled properly. (#46) + +## [v0.1.8] - 2019-01-14 + +### Added +- Rayon parallel iterator support (#37) +- `raw_entry` support (#31) +- `#[may_dangle]` on nightly (#31) +- `try_reserve` support (#31) + +### Fixed +- Fixed variance on `IterMut`. (#31) + +## [v0.1.7] - 2018-12-05 + +### Fixed +- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32) +- Fixed overflow in rehash_in_place. (#33) + +## [v0.1.6] - 2018-11-17 + +### Fixed +- Fixed compile error on nightly. (#29) + +## [v0.1.5] - 2018-11-08 + +### Fixed +- Fixed subtraction overflow in generic::Group::match_byte. (#28) + +## [v0.1.4] - 2018-11-04 + +### Fixed +- Fixed a bug in the `erase_no_drop` implementation. (#26) + +## [v0.1.3] - 2018-11-01 + +### Added +- Serde support. (#14) + +### Fixed +- Make the compiler inline functions more aggressively. (#20) + +## [v0.1.2] - 2018-10-31 + +### Fixed +- `clear` segfaults when called on an empty table. (#13) + +## [v0.1.1] - 2018-10-30 + +### Fixed +- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3) +- Missing `Send` and `Sync` for hash map and iterator types. (#7) +- Bug when inserting into a table smaller than the group width. (#5) + +## v0.1.0 - 2018-10-29 + +- Initial release + +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.15.2...HEAD +[v0.15.2]: https://github.com/rust-lang/hashbrown/compare/v0.15.1...v0.15.2 +[v0.15.1]: https://github.com/rust-lang/hashbrown/compare/v0.15.0...v0.15.1 +[v0.15.0]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...v0.15.0 +[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5 +[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4 +[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3 +[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2 +[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0 +[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2 +[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1 +[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3 +[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2 +[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1 +[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0 +[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2 +[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1 +[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 +[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 +[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 +[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 +[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0 +[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0 +[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0 +[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0 +[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8 +[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7 +[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1 diff --git a/deps/crates/vendor/hashbrown/Cargo.lock b/deps/crates/vendor/hashbrown/Cargo.lock new file mode 100644 index 00000000000000..9a76fd99d4860b --- /dev/null +++ b/deps/crates/vendor/hashbrown/Cargo.lock @@ -0,0 +1,673 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "criterion" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +dependencies = [ + "allocator-api2", + "bumpalo", + "criterion", + "equivalent", + "fnv", + "foldhash", + "libc", + "rand", + "rayon", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "serde", + "serde_core", + "serde_test", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_test" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/deps/crates/vendor/hashbrown/Cargo.toml b/deps/crates/vendor/hashbrown/Cargo.toml new file mode 100644 index 00000000000000..3b5e1bf0ea02ef --- /dev/null +++ b/deps/crates/vendor/hashbrown/Cargo.toml @@ -0,0 +1,202 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2024" +rust-version = "1.85.0" +name = "hashbrown" +version = "0.17.0" +authors = ["Amanieu d'Antras "] +build = false +exclude = [ + ".github", + "/ci/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A Rust port of Google's SwissTable hash map" +readme = "README.md" +keywords = [ + "hash", + "no_std", + "hashmap", + "swisstable", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" + +[package.metadata.docs.rs] +features = [ + "nightly", + "rayon", + "serde", + "raw-entry", +] +rustdoc-args = ["--generate-link-to-definition"] + +[features] +default = [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry", +] +default-hasher = ["dep:foldhash"] +inline-more = [] +nightly = [ + "foldhash?/nightly", + "bumpalo/allocator_api", +] +raw-entry = [] +rustc-dep-of-std = [ + "nightly", + "core", + "alloc", + "rustc-internal-api", +] +rustc-internal-api = [] +serde = [ + "dep:serde_core", + "dep:serde", +] + +[lib] +name = "hashbrown" +path = "src/lib.rs" + +[[test]] +name = "equivalent_trait" +path = "tests/equivalent_trait.rs" + +[[test]] +name = "hasher" +path = "tests/hasher.rs" + +[[test]] +name = "hasher_unwind" +path = "tests/hasher_unwind.rs" + +[[test]] +name = "rayon" +path = "tests/rayon.rs" + +[[test]] +name = "serde" +path = "tests/serde.rs" + +[[test]] +name = "set" +path = "tests/set.rs" + +[[bench]] +name = "bench" +path = "benches/bench.rs" +harness = false + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.allocator-api2] +version = "0.2.9" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.equivalent] +version = "1.0" +optional = true +default-features = false + +[dependencies.foldhash] +version = "0.2.0" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.9.0" +optional = true + +[dependencies.serde_core] +version = "1.0.221" +optional = true +default-features = false + +[dev-dependencies.bumpalo] +version = "3.13.0" +features = ["allocator-api2"] + +[dev-dependencies.criterion] +version = "0.7" +features = ["html_reports"] + +[dev-dependencies.fnv] +version = "1.0.7" + +[dev-dependencies.rand] +version = "0.9.0" +features = ["small_rng"] + +[dev-dependencies.rayon] +version = "1.2" + +[dev-dependencies.serde_test] +version = "1.0" + +[target."cfg(any())".dependencies.serde] +version = "1.0.220" +optional = true +default-features = false + +[target."cfg(unix)".dev-dependencies.libc] +version = "0.2.155" + +[lints.clippy] +borrow_as_ptr = "warn" +doc_markdown = "allow" +manual_let_else = "warn" +manual_map = "allow" +missing_errors_doc = "allow" +missing_safety_doc = "allow" +module_name_repetitions = "allow" +must_use_candidate = "allow" +needless_continue = "warn" +option_if_let_else = "allow" +ptr_as_ptr = "warn" +ptr_cast_constness = "warn" +redundant_else = "warn" +ref_as_ptr = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" + +[lints.rust] +bare_trait_objects = "warn" +elided_lifetimes_in_paths = "warn" +ellipsis_inclusive_range_patterns = "warn" +explicit_outlives_requirements = "warn" +missing_docs = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_extern_crates = "warn" diff --git a/deps/crates/vendor/hashbrown/Cargo.toml.orig b/deps/crates/vendor/hashbrown/Cargo.toml.orig new file mode 100644 index 00000000000000..0bcb60112ad90a --- /dev/null +++ b/deps/crates/vendor/hashbrown/Cargo.toml.orig @@ -0,0 +1,127 @@ +[package] +name = "hashbrown" +version = "0.17.0" +authors = ["Amanieu d'Antras "] +description = "A Rust port of Google's SwissTable hash map" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +exclude = [".github", "/ci/*"] +edition = "2024" + +# Make sure to sync this MSRV in the README badge and CI workflows +rust-version = "1.85.0" +autobenches = false + +[lints.rust] +missing_docs = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" + +# rust_2018_idioms +bare_trait_objects = "warn" +elided_lifetimes_in_paths = "warn" +ellipsis_inclusive_range_patterns = "warn" +explicit_outlives_requirements = "warn" +unused_extern_crates = "warn" + +[lints.clippy] +doc_markdown = "allow" +manual_map = "allow" +missing_errors_doc = "allow" +missing_safety_doc = "allow" +module_name_repetitions = "allow" +must_use_candidate = "allow" +option_if_let_else = "allow" + +borrow_as_ptr = "warn" +manual_let_else = "warn" +needless_continue = "warn" +ptr_as_ptr = "warn" +ptr_cast_constness = "warn" +redundant_else = "warn" +ref_as_ptr = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" + +[dependencies] +# For the default hasher +foldhash = { version = "0.2.0", default-features = false, optional = true } + +# For external trait impls +rayon = { version = "1.9.0", optional = true } +serde_core = { version = "1.0.221", default-features = false, optional = true } + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +# Support for allocators that use allocator-api2 +allocator-api2 = { version = "0.2.9", optional = true, default-features = false, features = [ + "alloc", +] } + +# Equivalent trait which can be shared with other hash table implementations. +# NB: this is a public dependency because `Equivalent` is re-exported! +equivalent = { version = "1.0", optional = true, default-features = false } + +# serde v1.0.220 is the first version that released with `serde_core`. +# This is required to avoid conflict with other `serde` users which may require an older version. +[target.'cfg(any())'.dependencies] +serde = { version = "1.0.220", default-features = false, optional = true } + +[dev-dependencies] +rand = { version = "0.9.0", features = ["small_rng"] } +rayon = "1.2" +fnv = "1.0.7" +serde_test = "1.0" +bumpalo = { version = "3.13.0", features = ["allocator-api2"] } +criterion = { version = "0.7", features = ["html_reports"] } + +[target.'cfg(unix)'.dev-dependencies] +libc = "0.2.155" + +[features] +default = [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry", +] + +# Enables use of nightly features. This is only guaranteed to work on the latest +# version of nightly Rust. +nightly = ["foldhash?/nightly", "bumpalo/allocator_api"] + +# Enables the RustcEntry API used to provide the standard library's Entry API. +rustc-internal-api = [] + +# Internal feature used when building as part of the standard library. +rustc-dep-of-std = ["nightly", "core", "alloc", "rustc-internal-api"] + +# Enables serde support. +serde = ["dep:serde_core", "dep:serde"] + +# Enables the deprecated RawEntry API. +raw-entry = [] + +# Provides a default hasher. Currently this is foldhash but this is subject to +# change in the future. Note that the default hasher does *not* provide HashDoS +# resistance, unlike the one in the standard library. +default-hasher = ["dep:foldhash"] + +# Enables usage of `#[inline]` on far more functions than by default in this +# crate. This may lead to a performance increase but often comes at a compile +# time cost. +inline-more = [] + +[[bench]] +name = "bench" +harness = false + +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw-entry"] +rustdoc-args = ["--generate-link-to-definition"] diff --git a/deps/crates/vendor/hashbrown/Cross.toml b/deps/crates/vendor/hashbrown/Cross.toml new file mode 100644 index 00000000000000..de635703246761 --- /dev/null +++ b/deps/crates/vendor/hashbrown/Cross.toml @@ -0,0 +1,3 @@ +# FIXME: Drop this config when cross is updated to support loongarch64-linux-gnu +[target.loongarch64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/loongarch64-unknown-linux-gnu:edge" diff --git a/deps/crates/vendor/hashbrown/LICENSE-APACHE b/deps/crates/vendor/hashbrown/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/hashbrown/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/hashbrown/LICENSE-MIT b/deps/crates/vendor/hashbrown/LICENSE-MIT new file mode 100644 index 00000000000000..5afc2a7b0acabd --- /dev/null +++ b/deps/crates/vendor/hashbrown/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/hashbrown/README.md b/deps/crates/vendor/hashbrown/README.md new file mode 100644 index 00000000000000..fc566be2d21649 --- /dev/null +++ b/deps/crates/vendor/hashbrown/README.md @@ -0,0 +1,82 @@ +hashbrown +========= + +[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions) +[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) +[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.85.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) + +This crate is a Rust port of Google's high-performance [SwissTable] hash +map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +and `HashSet` types. + +The original C++ version of SwissTable can be found [here], and this +[CppCon talk] gives an overview of how the algorithm works. + +Since Rust 1.36, the Rust standard library has adopted this implementation for +`HashMap`, using its own default hasher (see [`std::hash::DefaultHasher`](https://doc.rust-lang.org/std/hash/struct.DefaultHasher.html)). +However you may still want to use this crate instead since it works in +environments without `std`, such as embedded systems and kernels. + +[SwissTable]: https://abseil.io/blog/20180927-swisstables +[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +## [Change log](CHANGELOG.md) + +## Features + +- Drop-in replacement for the standard library `HashMap` and `HashSet` types. +- Uses [foldhash](https://github.com/orlp/foldhash) as the default hasher, which is much faster than SipHash. + However, foldhash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Around 2x faster than the previous standard library `HashMap`. +- Lower memory usage: only 1 byte of overhead per entry instead of 8. +- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). +- Empty hash maps do not allocate any memory. +- SIMD lookups to scan multiple hash entries in parallel. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hashbrown = "0.16" +``` + +Then: + +```rust +use hashbrown::HashMap; + +let mut map = HashMap::new(); +map.insert(1, "one"); +``` + +## Flags +This crate has the following Cargo features: + +- `nightly`: Enables nightly-only features including: `#[may_dangle]`. +- `serde`: Enables serde serialization support. +- `rayon`: Enables rayon parallel iterator support. +- `equivalent`: Allows comparisons to be customized with the `Equivalent` trait. (enabled by default) +- `raw-entry`: Enables access to the deprecated `RawEntry` API. +- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost + of compilation time. (enabled by default) +- `default-hasher`: Compiles with foldhash as default hasher. (enabled by default) +- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) + +## License + +Licensed under either of: + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/deps/crates/vendor/hashbrown/benches/bench.rs b/deps/crates/vendor/hashbrown/benches/bench.rs new file mode 100644 index 00000000000000..7103f68bf9a495 --- /dev/null +++ b/deps/crates/vendor/hashbrown/benches/bench.rs @@ -0,0 +1,17 @@ +#![expect(missing_docs)] // criterion_group! generates a public bench entrypoint + +use criterion::{criterion_group, criterion_main}; + +mod general_ops; +mod insert_unique_unchecked; +mod set_ops; +mod with_capacity; + +criterion_group!( + benches, + general_ops::register_benches, + insert_unique_unchecked::register_benches, + set_ops::register_benches, + with_capacity::register_benches +); +criterion_main!(benches); diff --git a/deps/crates/vendor/hashbrown/benches/general_ops.rs b/deps/crates/vendor/hashbrown/benches/general_ops.rs new file mode 100644 index 00000000000000..1a95e52342ef87 --- /dev/null +++ b/deps/crates/vendor/hashbrown/benches/general_ops.rs @@ -0,0 +1,425 @@ +//! This benchmark suite contains some benchmarks along a set of dimensions: +//! * Hasher: std default (SipHash) and crate default (foldhash). +//! * Int key distribution: low bit heavy, top bit heavy, and random. +//! * Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter +use criterion::Criterion; +use hashbrown::DefaultHashBuilder; +use hashbrown::{HashMap, HashSet}; +use std::{ + collections::hash_map::RandomState, + hint::black_box, + sync::atomic::{self, AtomicUsize}, +}; + +const SIZE: usize = 1000; +const OP_COUNT: usize = 500; + +// The default hashmap when using this crate directly. +type FoldHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; + +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + state: usize, +} + +impl RandomKeys { + fn new() -> Self { + Self { state: 0 } + } +} + +impl Iterator for RandomKeys { + type Item = usize; + + fn next(&mut self) -> Option { + // Add 1 then multiply by some 32 bit prime. + self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781); + Some(self.state) + } +} + +// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path +// when dropping maps/entries (most real world usages likely have drop in the key or value) +static SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0); + +#[derive(Clone)] +struct DropType(usize); + +impl Drop for DropType { + fn drop(&mut self) { + SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst); + } +} + +fn observe_side_effect() { + black_box(SIDE_EFFECT.load(atomic::Ordering::SeqCst)); +} + +macro_rules! bench_suite { + ($c:ident, $bench_macro:ident, $bench_foldhash_serial:ident, $bench_std_serial:ident, + $bench_foldhash_highbits:ident, $bench_std_highbits:ident, + $bench_foldhash_random:ident, $bench_std_random:ident) => { + $bench_macro!($c, $bench_foldhash_serial, FoldHashMap, 0..); + $bench_macro!($c, $bench_std_serial, StdHashMap, 0..); + $bench_macro!( + $c, + $bench_foldhash_highbits, + FoldHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!( + $c, + $bench_std_highbits, + StdHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!($c, $bench_foldhash_random, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $bench_std_random, StdHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_suite_2 { + ($c:ident, $bench_macro:ident, + $name0:ident, $size0:literal, $name1:ident, $size1:literal, + $name2:ident, $size2:literal, $name3:ident, $size3:literal, + $name4:ident, $size4:literal, $name5:ident, $size5:literal, + $name6:ident, $size6:literal, $name7:ident, $size7:literal) => { + $bench_macro!($c, $name0, $size0, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name1, $size1, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name2, $size2, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name3, $size3, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name4, $size4, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name5, $size5, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name6, $size6, FoldHashMap, RandomKeys::new()); + $bench_macro!($c, $name7, $size7, FoldHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_insert { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default()); + b.iter(|| { + m.clear(); + for i in ($keydist).take(SIZE) { + m.insert(i, (DropType(i), [i; 20])); + } + black_box(&mut m); + }); + }); + observe_side_effect(); + }}; +} + +macro_rules! bench_grow_insert { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + b.iter(|| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + black_box(&mut m); + }); + }); + }}; +} + +macro_rules! bench_insert_erase { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut base = $maptype::default(); + for i in ($keydist).take(SIZE) { + base.insert(i, DropType(i)); + } + let skip = $keydist.skip(SIZE); + b.iter(|| { + let mut m = base.clone(); + let mut add_iter = skip.clone(); + let mut remove_iter = $keydist; + // While keeping the size constant, + // replace the first keydist with the second. + for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) { + m.insert(add, DropType(add)); + black_box(m.remove(&remove)); + } + black_box(m); + }); + }); + observe_side_effect(); + }}; +} + +macro_rules! bench_lookup { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in ($keydist).take(SIZE) { + black_box(m.get(&i)); + } + }); + }); + observe_side_effect(); + }}; +} + +macro_rules! bench_lookup_fail { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(SIZE) { + black_box(m.get(&i)); + } + }); + }); + }}; +} + +macro_rules! bench_lookup_load_factor { + ($c:ident, $name:ident, $size:literal, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::default(); + for i in ($keydist).take($size) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in ($keydist).take(OP_COUNT) { + black_box(m.get(&i)); + } + }); + }); + }}; +} + +macro_rules! bench_lookup_fail_load_factor { + ($c:ident, $name:ident, $size:literal, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take($size) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(OP_COUNT) { + black_box(m.get(&i)); + } + }); + }); + }}; +} + +macro_rules! bench_iter { + ($c:ident, $name:ident, $maptype:ident, $keydist:expr) => {{ + $c.bench_function(stringify!($name), |b| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }); + }); + }}; +} + +pub(crate) fn register_benches(c: &mut Criterion) { + bench_suite!( + c, + bench_insert, + insert_foldhash_serial, + insert_std_serial, + insert_foldhash_highbits, + insert_std_highbits, + insert_foldhash_random, + insert_std_random + ); + + bench_suite!( + c, + bench_grow_insert, + grow_insert_foldhash_serial, + grow_insert_std_serial, + grow_insert_foldhash_highbits, + grow_insert_std_highbits, + grow_insert_foldhash_random, + grow_insert_std_random + ); + + bench_suite!( + c, + bench_insert_erase, + insert_erase_foldhash_serial, + insert_erase_std_serial, + insert_erase_foldhash_highbits, + insert_erase_std_highbits, + insert_erase_foldhash_random, + insert_erase_std_random + ); + + bench_suite!( + c, + bench_lookup, + lookup_foldhash_serial, + lookup_std_serial, + lookup_foldhash_highbits, + lookup_std_highbits, + lookup_foldhash_random, + lookup_std_random + ); + + bench_suite!( + c, + bench_lookup_fail, + lookup_fail_foldhash_serial, + lookup_fail_std_serial, + lookup_fail_foldhash_highbits, + lookup_fail_std_highbits, + lookup_fail_foldhash_random, + lookup_fail_std_random + ); + + bench_suite_2!( + c, + bench_lookup_load_factor, + loadfactor_lookup_14500, + 14500, + loadfactor_lookup_16500, + 16500, + loadfactor_lookup_18500, + 18500, + loadfactor_lookup_20500, + 20500, + loadfactor_lookup_22500, + 22500, + loadfactor_lookup_24500, + 24500, + loadfactor_lookup_26500, + 26500, + loadfactor_lookup_28500, + 28500 + ); + + bench_suite_2!( + c, + bench_lookup_fail_load_factor, + loadfactor_lookup_fail_14500, + 14500, + loadfactor_lookup_fail_16500, + 16500, + loadfactor_lookup_fail_18500, + 18500, + loadfactor_lookup_fail_20500, + 20500, + loadfactor_lookup_fail_22500, + 22500, + loadfactor_lookup_fail_24500, + 24500, + loadfactor_lookup_fail_26500, + 26500, + loadfactor_lookup_fail_28500, + 28500 + ); + + bench_suite!( + c, + bench_iter, + iter_foldhash_serial, + iter_std_serial, + iter_foldhash_highbits, + iter_std_highbits, + iter_foldhash_random, + iter_std_random + ); + + c.bench_function("clone_small", |b| { + let mut m = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }); + }); + + c.bench_function("clone_from_small", |b| { + let mut m = HashMap::new(); + let mut other = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + other.clone_from(&m); + black_box(&mut other); + }); + }); + + c.bench_function("clone_large", |b| { + let mut m = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }); + }); + + c.bench_function("clone_from_large", |b| { + let mut m = HashMap::new(); + let mut other = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + other.clone_from(&m); + black_box(&mut other); + }); + }); + + c.bench_function("rehash_in_place", |b| { + b.iter(|| { + let mut set = HashSet::new(); + + // Each loop triggers one rehash + for _ in 0..10 { + for i in 0..223 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + set.clear(); + } + }); + }); +} diff --git a/deps/crates/vendor/hashbrown/benches/insert_unique_unchecked.rs b/deps/crates/vendor/hashbrown/benches/insert_unique_unchecked.rs new file mode 100644 index 00000000000000..402a218201f526 --- /dev/null +++ b/deps/crates/vendor/hashbrown/benches/insert_unique_unchecked.rs @@ -0,0 +1,32 @@ +//! Compare `insert` and `insert_unique_unchecked` operations performance. +use criterion::Criterion; +use hashbrown::HashMap; +use std::hint::black_box; + +pub(crate) fn register_benches(c: &mut Criterion) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{i}yyyy")).collect(); + + c.bench_function("insert", |b| { + let mut m = HashMap::with_capacity(1000); + b.iter(|| { + m.clear(); + for k in &keys { + m.insert(k, k); + } + black_box(m.len()) + }); + }); + + c.bench_function("insert_unique_unchecked", |b| { + let mut m = HashMap::with_capacity(1000); + b.iter(|| { + m.clear(); + for k in &keys { + unsafe { + m.insert_unique_unchecked(k, k); + } + } + black_box(m.len()) + }); + }); +} diff --git a/deps/crates/vendor/hashbrown/benches/set_ops.rs b/deps/crates/vendor/hashbrown/benches/set_ops.rs new file mode 100644 index 00000000000000..6826688d95761f --- /dev/null +++ b/deps/crates/vendor/hashbrown/benches/set_ops.rs @@ -0,0 +1,91 @@ +//! This file contains benchmarks for the ops traits implemented by HashSet. +//! Each test is intended to have a defined larger and smaller set, +//! but using a larger size for the "small" set works just as well. +//! +//! Each assigning test is done in the configuration that is faster. Cheating, I know. +//! The exception to this is Sub, because there the result differs. So I made two benchmarks for Sub. +use criterion::Criterion; +use hashbrown::HashSet; + +/// The number of items to generate for the larger of the sets. +const LARGE_SET_SIZE: usize = 1000; + +/// The number of items to generate for the smaller of the sets. +const SMALL_SET_SIZE: usize = 100; + +/// The number of keys present in both sets. +const OVERLAP: usize = + [LARGE_SET_SIZE, SMALL_SET_SIZE][(LARGE_SET_SIZE < SMALL_SET_SIZE) as usize] / 2; + +/// Creates a set containing end - start unique string elements. +fn create_set(start: usize, end: usize) -> HashSet { + (start..end).map(|nr| format!("key{nr}")).collect() +} + +pub(crate) fn register_benches(c: &mut Criterion) { + let large_set = create_set(0, LARGE_SET_SIZE); + let small_set = create_set( + LARGE_SET_SIZE - OVERLAP, + LARGE_SET_SIZE + SMALL_SET_SIZE - OVERLAP, + ); + + c.bench_function("set_ops_bit_or", |b| { + b.iter(|| &large_set | &small_set); + }); + + c.bench_function("set_ops_bit_and", |b| { + b.iter(|| &large_set & &small_set); + }); + + c.bench_function("set_ops_bit_xor", |b| { + b.iter(|| &large_set ^ &small_set); + }); + + c.bench_function("set_ops_sub_large_small", |b| { + b.iter(|| &large_set - &small_set); + }); + + c.bench_function("set_ops_sub_small_large", |b| { + b.iter(|| &small_set - &large_set); + }); + + c.bench_function("set_ops_bit_or_assign", |b| { + b.iter(|| { + let mut set = large_set.clone(); + set |= &small_set; + set + }); + }); + + c.bench_function("set_ops_bit_and_assign", |b| { + b.iter(|| { + let mut set = small_set.clone(); + set &= &large_set; + set + }); + }); + + c.bench_function("set_ops_bit_xor_assign", |b| { + b.iter(|| { + let mut set = large_set.clone(); + set ^= &small_set; + set + }); + }); + + c.bench_function("set_ops_sub_assign_large_small", |b| { + b.iter(|| { + let mut set = large_set.clone(); + set -= &small_set; + set + }); + }); + + c.bench_function("set_ops_sub_assign_small_large", |b| { + b.iter(|| { + let mut set = small_set.clone(); + set -= &large_set; + set + }); + }); +} diff --git a/deps/crates/vendor/hashbrown/benches/with_capacity.rs b/deps/crates/vendor/hashbrown/benches/with_capacity.rs new file mode 100644 index 00000000000000..c1299244225df6 --- /dev/null +++ b/deps/crates/vendor/hashbrown/benches/with_capacity.rs @@ -0,0 +1,36 @@ +use criterion::Criterion; +use hashbrown::HashMap; +use std::hint::black_box; + +type Map = HashMap; + +macro_rules! bench_with_capacity { + ($c:ident, $name:ident, $cap:expr) => { + $c.bench_function(stringify!($name), |b| { + b.iter(|| { + // Construct a new empty map with a given capacity and return it to avoid + // being optimized away. Dropping it measures allocation + minimal setup. + let m: Map = Map::with_capacity($cap); + black_box(m) + }); + }); + }; +} + +pub(crate) fn register_benches(c: &mut Criterion) { + bench_with_capacity!(c, with_capacity_000000, 0); + bench_with_capacity!(c, with_capacity_000001, 1); + bench_with_capacity!(c, with_capacity_000003, 3); + bench_with_capacity!(c, with_capacity_000007, 7); + bench_with_capacity!(c, with_capacity_000008, 8); + bench_with_capacity!(c, with_capacity_000016, 16); + bench_with_capacity!(c, with_capacity_000032, 32); + bench_with_capacity!(c, with_capacity_000064, 64); + bench_with_capacity!(c, with_capacity_000128, 128); + bench_with_capacity!(c, with_capacity_000256, 256); + bench_with_capacity!(c, with_capacity_000512, 512); + bench_with_capacity!(c, with_capacity_001024, 1024); + bench_with_capacity!(c, with_capacity_004096, 4096); + bench_with_capacity!(c, with_capacity_016384, 16384); + bench_with_capacity!(c, with_capacity_065536, 65536); +} diff --git a/deps/crates/vendor/hashbrown/clippy.toml b/deps/crates/vendor/hashbrown/clippy.toml new file mode 100644 index 00000000000000..10719990a748a2 --- /dev/null +++ b/deps/crates/vendor/hashbrown/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = ["CppCon", "SwissTable", "SipHash", "HashDoS"] diff --git a/deps/crates/vendor/hashbrown/src/alloc.rs b/deps/crates/vendor/hashbrown/src/alloc.rs new file mode 100644 index 00000000000000..cad84df98cb693 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/alloc.rs @@ -0,0 +1,103 @@ +#[cfg(test)] +pub(crate) use self::inner::AllocError; +pub(crate) use self::inner::{Allocator, Global, do_alloc}; + +// Nightly-case. +// Use unstable `allocator_api` feature. +// This is compatible with `allocator-api2` which can be enabled or not. +// This is used when building for `std`. +#[cfg(feature = "nightly")] +mod inner { + use core::ptr::NonNull; + #[cfg(test)] + pub(crate) use stdalloc::alloc::AllocError; + use stdalloc::alloc::Layout; + pub(crate) use stdalloc::alloc::{Allocator, Global}; + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr), + Err(_) => Err(()), + } + } +} + +// Basic non-nightly case. +// This uses `allocator-api2` enabled by default. +// If any crate enables "nightly" in `allocator-api2`, +// this will be equivalent to the nightly case, +// since `allocator_api2::alloc::Allocator` would be re-export of +// `core::alloc::Allocator`. +#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] +mod inner { + #[cfg(test)] + pub(crate) use allocator_api2::alloc::AllocError; + pub(crate) use allocator_api2::alloc::{Allocator, Global}; + use core::ptr::NonNull; + use stdalloc::alloc::Layout; + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr), + Err(_) => Err(()), + } + } +} + +// No-defaults case. +// When building with default-features turned off and +// neither `nightly` nor `allocator-api2` is enabled, +// this will be used. +// Making it impossible to use any custom allocator with collections defined +// in this crate. +// Any crate in build-tree can enable `allocator-api2`, +// or `nightly` without disturbing users that don't want to use it. +#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] +mod inner { + use core::ptr::NonNull; + use stdalloc::alloc::{Layout, alloc, dealloc}; + + #[expect(clippy::missing_safety_doc)] // not exposed outside of this crate + pub unsafe trait Allocator { + fn allocate(&self, layout: Layout) -> Result, ()>; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + } + + #[derive(Copy, Clone)] + pub struct Global; + + unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, ()> { + match unsafe { NonNull::new(alloc(layout)) } { + Some(data) => { + // SAFETY: this is NonNull::slice_from_raw_parts. + Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + data.as_ptr(), + layout.size(), + )) + }) + } + None => Err(()), + } + } + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + dealloc(ptr.as_ptr(), layout); + } + } + } + + impl Default for Global { + #[inline] + fn default() -> Self { + Global + } + } + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc.allocate(layout) + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/bitmask.rs b/deps/crates/vendor/hashbrown/src/control/bitmask.rs new file mode 100644 index 00000000000000..72283126cfd5df --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/bitmask.rs @@ -0,0 +1,107 @@ +use super::group::{BITMASK_ITER_MASK, BITMASK_STRIDE, BitMaskWord, NonZeroBitMaskWord}; + +/// A bit mask which contains the result of a `Match` operation on a `Group` and +/// allows iterating through them. +/// +/// The bit mask is arranged so that low-order bits represent lower memory +/// addresses for group match results. +/// +/// For implementation reasons, the bits in the set may be sparsely packed with +/// groups of 8 bits representing one element. If any of these bits are non-zero +/// then this element is considered to true in the mask. If this is the +/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be +/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is +/// similarly a mask of all the actually-used bits. +/// +/// To iterate over a bit mask, it must be converted to a form where only 1 bit +/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the +/// mask bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMask(pub(crate) BitMaskWord); + +#[expect(clippy::use_self)] +impl BitMask { + /// Returns a new `BitMask` with the lowest bit removed. + #[inline] + #[must_use] + fn remove_lowest_bit(self) -> Self { + BitMask(self.0 & (self.0 - 1)) + } + + /// Returns whether the `BitMask` has at least one set bit. + #[inline] + pub(crate) fn any_bit_set(self) -> bool { + self.0 != 0 + } + + /// Returns the first set bit in the `BitMask`, if there is one. + #[inline] + pub(crate) fn lowest_set_bit(self) -> Option { + if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { + Some(Self::nonzero_trailing_zeros(nonzero)) + } else { + None + } + } + + /// Returns the number of trailing zeroes in the `BitMask`. + #[inline] + pub(crate) fn trailing_zeros(self) -> usize { + // ARM doesn't have a trailing_zeroes instruction, and instead uses + // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM + // versions (pre-ARMv7) don't have RBIT and need to emulate it + // instead. Since we only have 1 bit set in each byte on ARM, we can + // use swap_bytes (REV) + leading_zeroes instead. + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE + } else { + self.0.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Same as above but takes a `NonZeroBitMaskWord`. + #[inline] + fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + // SAFETY: A byte-swapped non-zero value is still non-zero. + let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; + swapped.leading_zeros() as usize / BITMASK_STRIDE + } else { + nonzero.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Returns the number of leading zeroes in the `BitMask`. + #[inline] + pub(crate) fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize / BITMASK_STRIDE + } +} + +impl IntoIterator for BitMask { + type Item = usize; + type IntoIter = BitMaskIter; + + #[inline] + fn into_iter(self) -> BitMaskIter { + // A BitMask only requires each element (group of bits) to be non-zero. + // However for iteration we need each element to only contain 1 bit. + BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) + } +} + +/// Iterator over the contents of a `BitMask`, returning the indices of set +/// bits. +#[derive(Clone)] +pub(crate) struct BitMaskIter(pub(crate) BitMask); + +impl Iterator for BitMaskIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let bit = self.0.lowest_set_bit()?; + self.0 = self.0.remove_lowest_bit(); + Some(bit) + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/group/generic.rs b/deps/crates/vendor/hashbrown/src/control/group/generic.rs new file mode 100644 index 00000000000000..09d5cd8a253856 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/group/generic.rs @@ -0,0 +1,152 @@ +use super::super::{BitMask, Tag}; +use core::{mem, ptr}; + +// Use the native word size as the group size. Using a 64-bit group size on +// a 32-bit architecture will just end up being more expensive because +// shifts and multiplies will need to be emulated. + +cfg_if! { + if #[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "wasm32", + ))] { + type GroupWord = u64; + type NonZeroGroupWord = core::num::NonZeroU64; + } else { + type GroupWord = u32; + type NonZeroGroupWord = core::num::NonZeroU32; + } +} + +pub(crate) type BitMaskWord = GroupWord; +pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord; +pub(crate) const BITMASK_STRIDE: usize = 8; +// We only care about the highest bit of each tag for the mask. +const BITMASK_MASK: BitMaskWord = u64::from_ne_bytes([Tag::DELETED.0; 8]) as GroupWord; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Helper function to replicate a tag across a `GroupWord`. +#[inline] +fn repeat(tag: Tag) -> GroupWord { + GroupWord::from_ne_bytes([tag.0; Group::WIDTH]) +} + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a word-sized integer. +#[derive(Copy, Clone)] +pub(crate) struct Group(GroupWord); + +// We perform all operations in the native endianness, and convert to +// little-endian just before creating a BitMask. The can potentially +// enable the compiler to eliminate unnecessary byte swaps if we are +// only checking whether a BitMask is empty. +#[expect(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + unsafe { Group(ptr::read_unaligned(ptr.cast())) } + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { Group(ptr::read(ptr.cast())) } + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { + ptr::write(ptr.cast(), self.0); + } + } + + /// Returns a `BitMask` indicating all tags in the group which *may* + /// have the given value. + /// + /// This function may return a false positive in certain cases where + /// the tag in the group differs from the searched value only in its + /// lowest bit. This is fine because: + /// - This never happens for `EMPTY` and `DELETED`, only full entries. + /// - The check for key equality will catch these. + /// - This only happens if there is at least 1 true match. + /// - The chance of this happening is very low (< 1% chance per tag). + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + // This algorithm is derived from + // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + let cmp = self.0 ^ repeat(tag); + BitMask((cmp.wrapping_sub(repeat(Tag(0x01))) & !cmp & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + // If the high bit is set, then the tag must be either: + // 1111_1111 (EMPTY) or 1000_0000 (DELETED). + // So we can just check if the top two bits are 1 by ANDing them. + BitMask((self.0 & (self.0 << 1) & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask((self.0 & repeat(Tag::DELETED)).to_le()) + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + BitMask(self.match_empty_or_deleted().0 ^ BITMASK_MASK) + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let full = 1000_0000 (true) or 0000_0000 (false) + // !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry) + // !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry) + let full = !self.0 & repeat(Tag::DELETED); + Group(!full + (full >> 7)) + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/group/lsx.rs b/deps/crates/vendor/hashbrown/src/control/group/lsx.rs new file mode 100644 index 00000000000000..031c75c830490b --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/group/lsx.rs @@ -0,0 +1,125 @@ +use super::super::{BitMask, Tag}; +use core::mem; +use core::num::NonZeroU16; + +use core::arch::loongarch64::*; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit LSX value. +#[derive(Copy, Clone)] +pub(crate) struct Group(m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[expect(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + unsafe { Group(lsx_vld::<0>(ptr.cast())) } + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { Group(lsx_vld::<0>(ptr.cast())) } + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { + lsx_vst::<0>(self.0, ptr.cast()); + } + } + + /// Returns a `BitMask` indicating all tags in the group which have + /// the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + unsafe { + let cmp = lsx_vseq_b(self.0, lsx_vreplgr2vr_b(tag.0 as i32)); + BitMask(lsx_vpickve2gr_hu::<0>(lsx_vmskltz_b(cmp)) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + unsafe { + let cmp = lsx_vseqi_b::<{ Tag::EMPTY.0 as i8 as i32 }>(self.0); + BitMask(lsx_vpickve2gr_hu::<0>(lsx_vmskltz_b(cmp)) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(lsx_vpickve2gr_hu::<0>(lsx_vmskltz_b(self.0)) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(lsx_vpickve2gr_hu::<0>(lsx_vmskgez_b(self.0)) as u16) + } + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let zero = lsx_vreplgr2vr_b(0); + let special = lsx_vslt_b(self.0, zero); + Group(lsx_vor_v(special, lsx_vreplgr2vr_b(Tag::DELETED.0 as i32))) + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/group/mod.rs b/deps/crates/vendor/hashbrown/src/control/group/mod.rs new file mode 100644 index 00000000000000..7c526d8cca17a0 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/group/mod.rs @@ -0,0 +1,48 @@ +// TESTING NOTE: +// +// Because this module uses `cfg(..)` to select an implementation, it will not +// be linted without being run on targets that actually load each of these +// modules. Be sure to edit `ci/tools.sh` to add in the necessary cfgs if you +// change these, so that your implementation gets properly linted. + +cfg_if! { + // Use the SSE2 implementation if possible: it allows us to scan 16 buckets + // at once instead of 8. We don't bother with AVX since it would require + // runtime dispatch and wouldn't gain us much anyways: the probability of + // finding a match drops off drastically after the first few buckets. + // + // I attempted an implementation on ARM using NEON instructions, but it + // turns out that most NEON instructions have multi-cycle latency, which in + // the end outweighs any gains over the generic implementation. + if #[cfg(all( + target_feature = "sse2", + any(target_arch = "x86", target_arch = "x86_64"), + not(miri), + ))] { + mod sse2; + use sse2 as imp; + } else if #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + // NEON intrinsics are currently broken on big-endian targets. + // See https://github.com/rust-lang/stdarch/issues/1484. + target_endian = "little", + not(miri), + ))] { + mod neon; + use neon as imp; + } else if #[cfg(all( + feature = "nightly", + target_arch = "loongarch64", + target_feature = "lsx", + not(miri), + ))] { + mod lsx; + use lsx as imp; + } else { + mod generic; + use generic as imp; + } +} +pub(crate) use self::imp::Group; +pub(super) use self::imp::{BITMASK_ITER_MASK, BITMASK_STRIDE, BitMaskWord, NonZeroBitMaskWord}; diff --git a/deps/crates/vendor/hashbrown/src/control/group/neon.rs b/deps/crates/vendor/hashbrown/src/control/group/neon.rs new file mode 100644 index 00000000000000..c64b891696852e --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/group/neon.rs @@ -0,0 +1,119 @@ +use super::super::{BitMask, Tag}; +use core::arch::aarch64 as neon; +use core::mem; +use core::num::NonZeroU64; + +pub(crate) type BitMaskWord = u64; +pub(crate) type NonZeroBitMaskWord = NonZeroU64; +pub(crate) const BITMASK_STRIDE: usize = 8; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 64-bit NEON value. +#[derive(Copy, Clone)] +pub(crate) struct Group(neon::uint8x8_t); + +#[expect(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + unsafe { Group(neon::vld1_u8(ptr.cast())) } + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { Group(neon::vld1_u8(ptr.cast())) } + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { + neon::vst1_u8(ptr.cast(), self.0); + } + } + + /// Returns a `BitMask` indicating all tags in the group which *may* + /// have the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + unsafe { + let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(tag.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_tag(Tag::EMPTY) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + unsafe { + let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80))) + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/group/sse2.rs b/deps/crates/vendor/hashbrown/src/control/group/sse2.rs new file mode 100644 index 00000000000000..2b12c0104fa4bc --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/group/sse2.rs @@ -0,0 +1,143 @@ +use super::super::{BitMask, Tag}; +use core::mem; +use core::num::NonZeroU16; + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as x86; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control tags which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit SSE value. +#[derive(Copy, Clone)] +pub(crate) struct Group(x86::__m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[expect(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty tags, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [Tag; Group::WIDTH] { + #[repr(C)] + struct AlignedTags { + _align: [Group; 0], + tags: [Tag; Group::WIDTH], + } + const ALIGNED_TAGS: AlignedTags = AlignedTags { + _align: [], + tags: [Tag::EMPTY; Group::WIDTH], + }; + &ALIGNED_TAGS.tags + } + + /// Loads a group of tags starting at the given address. + #[inline] + pub(crate) unsafe fn load(ptr: *const Tag) -> Self { + unsafe { Group(x86::_mm_loadu_si128(ptr.cast())) } + } + + /// Loads a group of tags starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn load_aligned(ptr: *const Tag) -> Self { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { Group(x86::_mm_load_si128(ptr.cast())) } + } + + /// Stores the group of tags to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + pub(crate) unsafe fn store_aligned(self, ptr: *mut Tag) { + debug_assert_eq!(ptr.align_offset(mem::align_of::()), 0); + unsafe { + x86::_mm_store_si128(ptr.cast(), self.0); + } + } + + /// Returns a `BitMask` indicating all tags in the group which have + /// the given value. + #[inline] + pub(crate) fn match_tag(self, tag: Tag) -> BitMask { + #[expect( + clippy::cast_possible_wrap, // tag.0: Tag as i8 + // tag: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(tag.0 as i8)); + BitMask(x86::_mm_movemask_epi8(cmp) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_tag(Tag::EMPTY) + } + + /// Returns a `BitMask` indicating all tags in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + #[expect( + // tag: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + // A tag is EMPTY or DELETED iff the high bit is set + BitMask(x86::_mm_movemask_epi8(self.0) as u16) + } + } + + /// Returns a `BitMask` indicating all tags in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + BitMask(!self.match_empty_or_deleted().0) + } + + /// Performs the following transformation on all tags in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > tag = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[expect( + clippy::cast_possible_wrap, // tag: Tag::DELETED.0 as i8 + )] + unsafe { + let zero = x86::_mm_setzero_si128(); + let special = x86::_mm_cmpgt_epi8(zero, self.0); + Group(x86::_mm_or_si128( + special, + x86::_mm_set1_epi8(Tag::DELETED.0 as i8), + )) + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/control/mod.rs b/deps/crates/vendor/hashbrown/src/control/mod.rs new file mode 100644 index 00000000000000..62ef8bfcc9bcce --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/mod.rs @@ -0,0 +1,10 @@ +mod bitmask; +mod group; +mod tag; + +use self::bitmask::BitMask; +pub(crate) use self::{ + bitmask::BitMaskIter, + group::Group, + tag::{Tag, TagSliceExt}, +}; diff --git a/deps/crates/vendor/hashbrown/src/control/tag.rs b/deps/crates/vendor/hashbrown/src/control/tag.rs new file mode 100644 index 00000000000000..486bbba701a696 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/control/tag.rs @@ -0,0 +1,82 @@ +use core::{fmt, mem}; + +/// Single tag in a control group. +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub(crate) struct Tag(pub(super) u8); +impl Tag { + /// Control tag value for an empty bucket. + pub(crate) const EMPTY: Tag = Tag(0b1111_1111); + + /// Control tag value for a deleted bucket. + pub(crate) const DELETED: Tag = Tag(0b1000_0000); + + /// Checks whether a control tag represents a full bucket (top bit is clear). + #[inline] + pub(crate) const fn is_full(self) -> bool { + self.0 & 0x80 == 0 + } + + /// Checks whether a control tag represents a special value (top bit is set). + #[inline] + pub(crate) const fn is_special(self) -> bool { + self.0 & 0x80 != 0 + } + + /// Checks whether a special control value is EMPTY (just check 1 bit). + #[inline] + pub(crate) const fn special_is_empty(self) -> bool { + debug_assert!(self.is_special()); + self.0 & 0x01 != 0 + } + + /// Creates a control tag representing a full bucket with the given hash. + #[inline] + pub(crate) const fn full(hash: u64) -> Tag { + // Constant for function that grabs the top 7 bits of the hash. + const MIN_HASH_LEN: usize = if mem::size_of::() < mem::size_of::() { + mem::size_of::() + } else { + mem::size_of::() + }; + + // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit + // value, some hash functions (such as FxHash) produce a usize result + // instead, which means that the top 32 bits are 0 on 32-bit platforms. + // So we use MIN_HASH_LEN constant to handle this. + let top7 = hash >> (MIN_HASH_LEN * 8 - 7); + Tag((top7 & 0x7f) as u8) // truncation + } +} +impl fmt::Debug for Tag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_special() { + if self.special_is_empty() { + f.pad("EMPTY") + } else { + f.pad("DELETED") + } + } else { + f.debug_tuple("full").field(&(self.0 & 0x7F)).finish() + } + } +} + +/// Extension trait for slices of tags. +pub(crate) trait TagSliceExt { + /// Fills the control with the given tag. + fn fill_tag(&mut self, tag: Tag); + + /// Clears out the control. + #[inline] + fn fill_empty(&mut self) { + self.fill_tag(Tag::EMPTY); + } +} +impl TagSliceExt for [mem::MaybeUninit] { + #[inline] + fn fill_tag(&mut self, tag: Tag) { + // SAFETY: We have access to the entire slice, so, we can write to the entire slice. + unsafe { self.as_mut_ptr().write_bytes(tag.0, self.len()) } + } +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/mod.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/mod.rs new file mode 100644 index 00000000000000..ef497836cb9895 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/mod.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "rayon")] +pub(crate) mod rayon; +#[cfg(feature = "serde")] +mod serde; diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/helpers.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/helpers.rs new file mode 100644 index 00000000000000..b8fb43a37af3b2 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/helpers.rs @@ -0,0 +1,13 @@ +use stdalloc::collections::LinkedList; +use stdalloc::vec::Vec; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Helper for collecting parallel iterators to an intermediary +#[expect(clippy::linkedlist)] // yes, we need linked list here for efficient appending! +pub(super) fn collect(iter: I) -> (LinkedList>, usize) { + let list = iter.into_par_iter().collect_vec_list(); + + let len = list.iter().map(Vec::len).sum(); + (list, len) +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/map.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/map.rs new file mode 100644 index 00000000000000..1a33c5ff308e48 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/map.rs @@ -0,0 +1,713 @@ +//! Rayon extensions for `HashMap`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::HashMap; +use crate::alloc::{Allocator, Global}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: rayon::iter::IntoParallelRefIterator::par_iter +/// [`IntoParallelRefIterator`]: rayon::iter::IntoParallelRefIterator +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to keys in a map. +/// +/// This iterator is created by the [`par_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_keys`]: HashMap::par_keys +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().0 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParKeys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to values in a map. +/// +/// This iterator is created by the [`par_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values`]: HashMap::par_values +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().1 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParValues<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: rayon::iter::IntoParallelRefMutIterator::par_iter_mut +/// [`IntoParallelRefMutIterator`]: rayon::iter::IntoParallelRefMutIterator +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_mut(); + (&r.0, &mut r.1) + }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over mutable references to values in a map. +/// +/// This iterator is created by the [`par_values_mut`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values_mut`]: HashMap::par_values_mut +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &mut x.as_mut().1 }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: HashMap::into_par_iter +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_drain`]: HashMap::par_drain +pub struct ParDrain<'a, K, V, A: Allocator = Global> { + inner: RawParDrain<'a, (K, V), A>, +} + +impl ParallelIterator for ParDrain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashMap { + /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl HashMap { + /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } + } +} + +impl HashMap +where + K: Eq + Hash + Sync, + V: PartialEq + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Returns `true` if the map is equal to another, + /// i.e. both maps contain the same keys mapped to the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .into_par_iter() + .all(|(key, value)| other.get(key).is_some_and(|v| *value == *v)) + } +} + +impl IntoParallelIterator for HashMap { + type Item = (K, V); + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.table.into_par_iter(), + } + } +} + +impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +/// Collect (key, value) pairs from a parallel iterator into a +/// hashmap. If multiple pairs correspond to the same key, then the +/// ones produced earlier in the parallel iterator will be +/// overwritten, just as with a sequential iterator. +impl FromParallelIterator<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut map = HashMap::default(); + map.par_extend(par_iter); + map + } +} + +/// Extend a hash map with items from a parallel iterator. +impl ParallelExtend<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash map with copied items from a parallel iterator. +impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap +where + K: Copy + Eq + Hash + Sync, + V: Copy + Sync, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashMap` -- no custom advantage. +fn extend(map: &mut HashMap, par_iter: I) +where + K: Eq + Hash, + S: BuildHasher, + I: IntoParallelIterator, + A: Allocator, + HashMap: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire length if the map is empty. + // Otherwise reserve half the length (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if map.is_empty() { len } else { len.div_ceil(2) }; + map.reserve(reserve); + for vec in list { + map.extend(vec); + } +} + +#[cfg(test)] +mod test_par_map { + use core::hash::{Hash, Hasher}; + use core::sync::atomic::{AtomicUsize, Ordering}; + use stdalloc::vec::Vec; + + use rayon::prelude::*; + + use crate::HashMap; + + struct Droppable<'a> { + k: usize, + counter: &'a AtomicUsize, + } + + impl Droppable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Droppable<'_> { + counter.fetch_add(1, Ordering::Relaxed); + + Droppable { k, counter } + } + } + + impl Drop for Droppable<'_> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + impl Clone for Droppable<'_> { + fn clone(&self) -> Self { + Droppable::new(self.k, self.counter) + } + } + + impl Hash for Droppable<'_> { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.k.hash(state); + } + } + + impl PartialEq for Droppable<'_> { + fn eq(&self, other: &Self) -> bool { + self.k == other.k + } + } + + impl Eq for Droppable<'_> {} + + #[test] + fn test_into_iter_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Droppable::new(i, &key); + let d2 = Droppable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the iterator does not leak anything. + drop(hm.clone().into_par_iter()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect(); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_drain_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let mut hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Droppable::new(i, &key); + let d2 = Droppable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the drain iterator does not leak anything. + drop(hm.clone().par_drain()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect(); + assert!(hm.is_empty()); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.par_drain().count(), 0); + assert_eq!(m.par_keys().count(), 0); + assert_eq!(m.par_values().count(), 0); + assert_eq!(m.par_values_mut().count(), 0); + assert_eq!(m.par_iter().count(), 0); + assert_eq!(m.par_iter_mut().count(), 0); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_par_iter().count(), 0); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let observed = AtomicUsize::new(0); + + m.par_iter().for_each(|(k, v)| { + assert_eq!(*v, *k * 2); + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(!m1.par_eq(&m2)); + + m2.insert(3, 4); + + assert!(m1.par_eq(&m2)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.par_iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.par_extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/mod.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/mod.rs new file mode 100644 index 00000000000000..61ca69b61d7f26 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/mod.rs @@ -0,0 +1,5 @@ +mod helpers; +pub(crate) mod map; +pub(crate) mod raw; +pub(crate) mod set; +pub(crate) mod table; diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/raw.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/raw.rs new file mode 100644 index 00000000000000..b8fc069d025318 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/raw.rs @@ -0,0 +1,232 @@ +use crate::alloc::{Allocator, Global}; +use crate::raw::{Bucket, RawIter, RawIterRange, RawTable}; +use crate::scopeguard::guard; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use rayon::iter::{ + ParallelIterator, + plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, +}; + +/// Parallel iterator which returns a raw pointer to every full bucket in the table. +pub(crate) struct RawParIter { + iter: RawIterRange, +} + +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + +impl From> for RawParIter { + fn from(it: RawIter) -> Self { + RawParIter { iter: it.iter } + } +} + +impl ParallelIterator for RawParIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let producer = ParIterProducer { iter: self.iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Producer which returns a `Bucket` for every element. +struct ParIterProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParIterProducer { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.split(); + let left = ParIterProducer { iter: left }; + let right = right.map(|right| ParIterProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(self, folder: F) -> F + where + F: Folder, + { + folder.consume_iter(self.iter) + } +} + +/// Parallel iterator which consumes a table and returns elements. +pub(crate) struct RawIntoParIter { + table: RawTable, +} + +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + unsafe { self.table.par_iter() } + } +} + +impl ParallelIterator for RawIntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let iter = unsafe { self.table.iter().iter }; + let _guard = guard(self.table.into_allocation(), |alloc| { + if let Some((ptr, layout, ref alloc)) = *alloc { + unsafe { + alloc.deallocate(ptr, layout); + } + } + }); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Parallel iterator which consumes elements without freeing the table storage. +pub(crate) struct RawParDrain<'a, T, A: Allocator = Global> { + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. + table: NonNull>, + marker: PhantomData<&'a RawTable>, +} + +unsafe impl Send for RawParDrain<'_, T, A> {} + +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + unsafe { self.table.as_ref().par_iter() } + } +} + +impl ParallelIterator for RawParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let _guard = guard(self.table, |table| unsafe { + table.as_mut().clear_no_drop(); + }); + let iter = unsafe { self.table.as_ref().iter().iter }; + mem::forget(self); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +impl Drop for RawParDrain<'_, T, A> { + fn drop(&mut self) { + // If drive_unindexed is not called then simply clear the table. + unsafe { + self.table.as_mut().clear(); + } + } +} + +/// Producer which will consume all elements in the range, even if it is dropped +/// halfway through. +struct ParDrainProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParDrainProducer { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.clone().split(); + mem::forget(self); + let left = ParDrainProducer { iter: left }; + let right = right.map(|right| ParDrainProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(mut self, mut folder: F) -> F + where + F: Folder, + { + // Make sure to modify the iterator in-place so that any remaining + // elements are processed in our Drop impl. + for item in &mut self.iter { + folder = folder.consume(unsafe { item.read() }); + if folder.full() { + return folder; + } + } + + // If we processed all elements then we don't need to run the drop. + mem::forget(self); + folder + } +} + +impl Drop for ParDrainProducer { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // Drop all remaining elements + if mem::needs_drop::() { + for item in &mut self.iter { + unsafe { + item.drop(); + } + } + } + } +} + +impl RawTable { + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn par_iter(&self) -> RawParIter { + unsafe { + RawParIter { + iter: self.iter().iter, + } + } + } + + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_par_iter(self) -> RawIntoParIter { + RawIntoParIter { table: self } + } + + /// Returns a parallel iterator which consumes all elements of a `RawTable` + /// without freeing its memory allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn par_drain(&mut self) -> RawParDrain<'_, T, A> { + RawParDrain { + table: NonNull::from(self), + marker: PhantomData, + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/set.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/set.rs new file mode 100644 index 00000000000000..205d2e0b10042c --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/set.rs @@ -0,0 +1,652 @@ +//! Rayon extensions for `HashSet`. + +use super::map; +use crate::HashSet; +use crate::alloc::{Allocator, Global}; +use core::hash::{BuildHasher, Hash}; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over elements of a consumed set. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: rayon::iter::IntoParallelIterator::into_par_iter +/// [`IntoParallelIterator`]: rayon::iter::IntoParallelIterator +pub struct IntoParIter { + inner: map::IntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel draining iterator over entries of a set. +/// +/// This iterator is created by the [`par_drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_drain`]: HashSet::par_drain +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: map::ParDrain<'a, T, (), A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in a set. +/// +/// This iterator is created by the [`par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: rayon::iter::IntoParallelRefIterator::par_iter +/// [`IntoParallelRefIterator`]: rayon::iter::IntoParallelRefIterator +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the difference of +/// sets. +/// +/// This iterator is created by the [`par_difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_difference`]: HashSet::par_difference +pub struct ParDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| !self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the symmetric +/// difference of sets. +/// +/// This iterator is created by the [`par_symmetric_difference`] method on +/// [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_symmetric_difference`]: HashSet::par_symmetric_difference +pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .par_difference(self.b) + .chain(self.b.par_difference(self.a)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the intersection of +/// sets. +/// +/// This iterator is created by the [`par_intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_intersection`]: HashSet::par_intersection +pub struct ParIntersection<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the union of sets. +/// +/// This iterator is created by the [`par_union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_union`]: HashSet::par_union +pub struct ParUnion<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.a.len() <= self.b.len() { + (self.a, self.b) + } else { + (self.b, self.a) + }; + larger + .into_par_iter() + .chain(smaller.par_difference(larger)) + .drive_unindexed(consumer) + } +} + +impl HashSet +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Visits (potentially in parallel) the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { + ParUnion { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the difference, + /// i.e. the values that are in `self` but not in `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> { + ParDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the symmetric + /// difference, i.e. the values that are in `self` or in `other` but not in both. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_symmetric_difference<'a>( + &'a self, + other: &'a Self, + ) -> ParSymmetricDifference<'a, T, S, A> { + ParSymmetricDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the + /// intersection, i.e. the values that are both in `self` and `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> { + ParIntersection { a: self, b: other } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_disjoint(&self, other: &Self) -> bool { + self.into_par_iter().all(|x| !other.contains(x)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_subset(&self, other: &Self) -> bool { + if self.len() <= other.len() { + self.into_par_iter().all(|x| other.contains(x)) + } else { + false + } + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_superset(&self, other: &Self) -> bool { + other.par_is_subset(self) + } + + /// Returns `true` if the set is equal to another, + /// i.e. both sets contain the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.par_is_subset(other) + } +} + +impl HashSet +where + T: Eq + Hash + Send, + A: Allocator + Send, +{ + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the set's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } + } +} + +impl IntoParallelIterator for HashSet { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.map.into_par_iter(), + } + } +} + +impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: self.map.par_keys(), + } + } +} + +/// Collect values from a parallel iterator into a hashset. +impl FromParallelIterator for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut set = HashSet::default(); + set.par_extend(par_iter); + set + } +} + +/// Extend a hash set with items from a parallel iterator. +impl ParallelExtend for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash set with copied items from a parallel iterator. +impl<'a, T, S> ParallelExtend<&'a T> for HashSet +where + T: 'a + Copy + Eq + Hash + Sync, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashSet` -- no custom advantage. +fn extend(set: &mut HashSet, par_iter: I) +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, + I: IntoParallelIterator, + HashSet: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Values may be already present or show multiple times in the iterator. + // Reserve the entire length if the set is empty. + // Otherwise reserve half the length (rounded up), so the set + // will only resize twice in the worst case. + let reserve = if set.is_empty() { len } else { len.div_ceil(2) }; + set.reserve(reserve); + for vec in list { + set.extend(vec); + } +} + +#[cfg(test)] +mod test_par_set { + use core::sync::atomic::{AtomicUsize, Ordering}; + use stdalloc::vec::Vec; + + use rayon::prelude::*; + + use crate::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.par_is_disjoint(&ys)); + assert!(!ys.par_is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(!b.par_is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(b.par_is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let i = a + .par_intersection(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let expected = [1, 5, 11]; + let i = a + .par_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let expected = [-2, 1, 5, 11, 14, 22]; + let i = a + .par_symmetric_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + let i = a + .par_union(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.par_iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(!s1.par_eq(&s2)); + + s2.insert(3); + + assert!(s1.par_eq(&s2)); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.par_extend(&[2, 3, 4][..]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.par_extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/table.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/table.rs new file mode 100644 index 00000000000000..20298f40e4c3d6 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/rayon/table.rs @@ -0,0 +1,245 @@ +//! Rayon extensions for `HashTable`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::HashTable; +use crate::alloc::{Allocator, Global}; +use core::fmt; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: rayon::iter::IntoParallelRefIterator::par_iter +/// [`IntoParallelRefIterator`]: rayon::iter::IntoParallelRefIterator +pub struct ParIter<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_ref() }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: rayon::iter::IntoParallelRefMutIterator::par_iter_mut +/// [`IntoParallelRefMutIterator`]: rayon::iter::IntoParallelRefMutIterator +pub struct ParIterMut<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> { + type Item = &'a mut T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_mut() }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: rayon::iter::IntoParallelIterator::into_par_iter +/// [`IntoParallelIterator`]: rayon::iter::IntoParallelIterator +pub struct IntoParIter { + inner: RawIntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`par_drain`]: HashTable::par_drain +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: RawParDrain<'a, T, A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashTable { + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.raw.par_drain(), + } + } +} + +impl IntoParallelIterator for HashTable { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.raw.into_par_iter(), + } + } +} + +impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable { + type Item = &'a mut T; + type Iter = ParIterMut<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test_par_table { + use core::sync::atomic::{AtomicUsize, Ordering}; + use stdalloc::vec::Vec; + + use rayon::prelude::*; + + use crate::{DefaultHashBuilder, hash_map::make_hash, hash_table::HashTable}; + + #[test] + fn test_iterate() { + let hasher = DefaultHashBuilder::default(); + let mut a = HashTable::new(); + for i in 0..32 { + a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_move_iter() { + let hasher = DefaultHashBuilder::default(); + let hs = { + let mut hs = HashTable::new(); + + hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x)); + hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x)); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } +} diff --git a/deps/crates/vendor/hashbrown/src/external_trait_impls/serde.rs b/deps/crates/vendor/hashbrown/src/external_trait_impls/serde.rs new file mode 100644 index 00000000000000..f55eee48590202 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/external_trait_impls/serde.rs @@ -0,0 +1,219 @@ +mod size_hint { + use core::cmp; + + /// This presumably exists to prevent denial of service attacks. + /// + /// Original discussion: https://github.com/serde-rs/serde/issues/1114. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } +} + +mod map { + use crate::alloc::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde_core::de::{Deserialize, Deserializer, MapAccess, Visitor}; + use serde_core::ser::{Serialize, Serializer}; + + use crate::HashMap; + + use super::size_hint; + + impl Serialize for HashMap + where + K: Serialize + Eq + Hash, + V: Serialize, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + + impl<'de, K, V, S, A> Deserialize<'de> for HashMap + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, K, V, S, A> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + let mut values = HashMap::with_capacity_and_hasher_in( + size_hint::cautious(map.size_hint()), + S::default(), + A::default(), + ); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use crate::alloc::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde_core::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde_core::ser::{Serialize, Serializer}; + + use crate::HashSet; + + use super::size_hint; + + impl Serialize for HashSet + where + T: Serialize + Eq + Hash, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + + impl<'de, T, S, A> Deserialize<'de> for HashSet + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, T, S, A> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashSet; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + let mut values = HashSet::with_capacity_and_hasher_in( + size_hint::cautious(seq.size_hint()), + S::default(), + A::default(), + ); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet) + where + A: Allocator; + + impl<'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'_, T, S, A> + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + self.0.clear(); + self.0.reserve(size_hint::cautious(seq.size_hint())); + + while let Some(value) = seq.next_element()? { + self.0.insert(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/hasher.rs b/deps/crates/vendor/hashbrown/src/hasher.rs new file mode 100644 index 00000000000000..7ec8aa16dc1893 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/hasher.rs @@ -0,0 +1,77 @@ +#[cfg(feature = "default-hasher")] +use { + core::hash::{BuildHasher, Hasher}, + foldhash::fast::RandomState, +}; + +/// Default hash builder for the `S` type parameter of +/// [`HashMap`](crate::HashMap) and [`HashSet`](crate::HashSet). +/// +/// This only implements `BuildHasher` when the "default-hasher" crate feature +/// is enabled; otherwise it just serves as a placeholder, and a custom `S` type +/// must be used to have a fully functional `HashMap` or `HashSet`. +#[derive(Clone, Debug, Default)] +pub struct DefaultHashBuilder { + #[cfg(feature = "default-hasher")] + inner: RandomState, +} + +#[cfg(feature = "default-hasher")] +impl BuildHasher for DefaultHashBuilder { + type Hasher = DefaultHasher; + + #[inline(always)] + fn build_hasher(&self) -> Self::Hasher { + DefaultHasher { + inner: self.inner.build_hasher(), + } + } +} + +/// Default hasher for [`HashMap`](crate::HashMap) and [`HashSet`](crate::HashSet). +#[cfg(feature = "default-hasher")] +#[derive(Clone)] +pub struct DefaultHasher { + inner: ::Hasher, +} + +#[cfg(feature = "default-hasher")] +macro_rules! forward_writes { + ($( $write:ident ( $ty:ty ) , )*) => {$( + #[inline(always)] + fn $write(&mut self, arg: $ty) { + self.inner.$write(arg); + } + )*} +} + +#[cfg(feature = "default-hasher")] +impl Hasher for DefaultHasher { + forward_writes! { + write(&[u8]), + write_u8(u8), + write_u16(u16), + write_u32(u32), + write_u64(u64), + write_u128(u128), + write_usize(usize), + write_i8(i8), + write_i16(i16), + write_i32(i32), + write_i64(i64), + write_i128(i128), + write_isize(isize), + } + + // feature(hasher_prefixfree_extras) + #[cfg(feature = "nightly")] + forward_writes! { + write_length_prefix(usize), + write_str(&str), + } + + #[inline(always)] + fn finish(&self) -> u64 { + self.inner.finish() + } +} diff --git a/deps/crates/vendor/hashbrown/src/lib.rs b/deps/crates/vendor/hashbrown/src/lib.rs new file mode 100644 index 00000000000000..effc178a3faf7d --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/lib.rs @@ -0,0 +1,189 @@ +//! This crate is a Rust port of Google's high-performance [SwissTable] hash +//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +//! and `HashSet` types. +//! +//! The original C++ version of [SwissTable] can be found [here], and this +//! [CppCon talk] gives an overview of how the algorithm works. +//! +//! [SwissTable]: https://abseil.io/blog/20180927-swisstables +//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +#![cfg_attr(not(doc), no_std)] +#![cfg_attr( + feature = "nightly", + feature( + core_intrinsics, + dropck_eyepatch, + min_specialization, + trivial_clone, + extend_one, + allocator_api, + strict_provenance_lints + ) +)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] +#![cfg_attr(feature = "rustc-dep-of-std", feature(rustc_attrs))] +#![cfg_attr(feature = "nightly", expect(internal_features))] +#![cfg_attr( + all(feature = "nightly", target_arch = "loongarch64"), + feature(stdarch_loongarch) +)] +#![cfg_attr( + all(feature = "nightly", feature = "default-hasher"), + feature(hasher_prefixfree_extras) +)] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg_attr(test, macro_use)] +#[cfg_attr(feature = "rustc-dep-of-std", allow(unused_extern_crates))] +extern crate alloc as stdalloc; + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; + +#[macro_use] +mod macros; + +mod alloc; +mod control; +mod hasher; +mod raw; +mod util; + +mod external_trait_impls; +mod map; +#[cfg(feature = "raw-entry")] +mod raw_entry; +#[cfg(feature = "rustc-internal-api")] +mod rustc_entry; +mod scopeguard; +mod set; +mod table; + +pub use crate::hasher::DefaultHashBuilder; +#[cfg(feature = "default-hasher")] +pub use crate::hasher::DefaultHasher; + +pub mod hash_map { + //! A hash map implemented with quadratic probing and SIMD lookup. + pub use crate::map::*; + + #[cfg(feature = "rustc-internal-api")] + pub use crate::rustc_entry::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: ::rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::map::*; + } +} +pub mod hash_set { + //! A hash set implemented as a `HashMap` where the value is `()`. + pub use crate::set::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash sets. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: ::rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::set::*; + } +} +pub mod hash_table { + //! A hash table implemented with quadratic probing and SIMD lookup. + pub use crate::table::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash tables. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: ::rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::table::*; + } +} + +pub use crate::map::HashMap; +pub use crate::set::HashSet; +pub use crate::table::HashTable; + +#[cfg(feature = "equivalent")] +pub use equivalent::Equivalent; + +// This is only used as a fallback when building as part of `std`. +#[cfg(not(feature = "equivalent"))] +/// Key equivalence trait. +/// +/// This trait defines the function used to compare the input value with the +/// map keys (or set values) during a lookup operation such as [`HashMap::get`] +/// or [`HashSet::contains`]. +/// It is provided with a blanket implementation based on the +/// [`Borrow`](core::borrow::Borrow) trait. +/// +/// # Correctness +/// +/// Equivalent values must hash to the same value. +pub trait Equivalent { + /// Checks if this value is equivalent to the given key. + /// + /// Returns `true` if both values are equivalent, and `false` otherwise. + /// + /// # Correctness + /// + /// When this function returns `true`, both `self` and `key` must hash to + /// the same value. + fn equivalent(&self, key: &K) -> bool; +} + +#[cfg(not(feature = "equivalent"))] +impl Equivalent for Q +where + Q: Eq, + K: core::borrow::Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + self == key.borrow() + } +} + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: stdalloc::alloc::Layout, + }, +} + +// matches stdalloc::collections::TryReserveError +impl core::fmt::Display for TryReserveError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("memory allocation failed")?; + let reason = match self { + TryReserveError::CapacityOverflow => { + " because the computed capacity exceeded the collection's maximum" + } + TryReserveError::AllocError { .. } => " because the memory allocator returned an error", + }; + f.write_str(reason) + } +} + +impl core::error::Error for TryReserveError {} diff --git a/deps/crates/vendor/hashbrown/src/macros.rs b/deps/crates/vendor/hashbrown/src/macros.rs new file mode 100644 index 00000000000000..7177d221230273 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/macros.rs @@ -0,0 +1,70 @@ +// See the cfg-if crate. +#[expect(unused_macro_rules)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +// Helper macro for specialization. This also helps avoid parse errors if the +// default fn syntax for specialization changes in the future. +#[cfg(feature = "nightly")] +macro_rules! default_fn { + (#[$($a:tt)*] $($tt:tt)*) => { + #[$($a)*] default $($tt)* + } +} +#[cfg(not(feature = "nightly"))] +macro_rules! default_fn { + ($($tt:tt)*) => { + $($tt)* + } +} diff --git a/deps/crates/vendor/hashbrown/src/map.rs b/deps/crates/vendor/hashbrown/src/map.rs new file mode 100644 index 00000000000000..22cafef5927eda --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/map.rs @@ -0,0 +1,7030 @@ +use crate::alloc::{Allocator, Global}; +use crate::raw::{Bucket, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable}; +use crate::{DefaultHashBuilder, Equivalent, TryReserveError}; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ops::Index; +use stdalloc::borrow::ToOwned; + +#[cfg(feature = "raw-entry")] +pub use crate::raw_entry::*; + +/// A hash map implemented with quadratic probing and SIMD lookup. +/// +/// The default hashing algorithm is currently [`foldhash`], though this is +/// subject to change at any point in the future. This hash function is very +/// fast for all types of keys, but this algorithm will typically *not* protect +/// against attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashMap` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); +/// } +/// ``` +/// +/// `HashMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`RefCell`]: std::cell::RefCell +/// [`Cell`]: std::cell::Cell +/// [`default`]: Default::default +/// [`with_hasher`]: HashMap::with_hasher +/// [`with_capacity_and_hasher`]: HashMap::with_capacity_and_hasher +/// [`fnv`]: https://crates.io/crates/fnv +/// [`foldhash`]: https://crates.io/crates/foldhash +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +/// +/// A `HashMap` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .into_iter().collect(); +/// // use the values stored in map +/// ``` +pub struct HashMap { + pub(crate) hash_builder: S, + pub(crate) table: RawTable<(K, V), A>, +} + +impl Clone for HashMap { + fn clone(&self) -> Self { + HashMap { + hash_builder: self.hash_builder.clone(), + table: self.table.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.table.clone_from(&source.table); + + // Update hash_builder only if we successfully cloned all elements. + self.hash_builder.clone_from(&source.hash_builder); + } +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +where + Q: Hash, + S: BuildHasher, +{ + move |val| make_hash::(hash_builder, &val.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ +where + Q: Equivalent + ?Sized, +{ + move |x| k.equivalent(&x.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like `RawTable::reserve` from being generated +#[cfg_attr(feature = "inline-more", inline)] +#[cfg(feature = "raw-entry")] +pub(crate) fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ +where + Q: Equivalent + ?Sized, +{ + move |x| k.equivalent(x) +} + +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + hash_builder.hash_one(val) +} + +#[cfg(feature = "default-hasher")] +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher`](HashMap::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher`](HashMap::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default()) + } +} + +#[cfg(feature = "default-hasher")] +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher_in`](HashMap::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::new_in(&bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// + /// // The created HashMap also doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// // Now we insert element inside created HashMap + /// map.insert("One", 1); + /// // We can see that the HashMap holds 1 element + /// assert_eq!(map.len(), 1); + /// // And it also allocates some capacity + /// assert!(map.capacity() > 1); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self::with_hasher_in(DefaultHashBuilder::default(), alloc) + } + + /// Creates an empty `HashMap` with the specified capacity using the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher_in`](HashMap::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::with_capacity_in(5, &bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = map.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashMap + /// map.insert("One", 1); + /// map.insert("Two", 2); + /// map.insert("Three", 3); + /// map.insert("Four", 4); + /// map.insert("Five", 5); + /// + /// // We can see that the HashMap holds 5 elements + /// assert_eq!(map.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(map.capacity(), empty_map_capacity) + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The hash map is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// + /// map.insert(1, 2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher(hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// + /// map.insert(1, 2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } +} + +impl HashMap { + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.table.allocator() + } + + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. It will be allocated with the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. It will be allocated with the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<&str> = Vec::new(); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// vec.push(*key); + /// } + /// + /// // The `Keys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [11, 12, 13]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + inner: self.iter_mut(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + Iter { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in &map { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 2), ("b", 4), ("c", 6)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + IterMut { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + #[cfg(test)] + #[cfg_attr(feature = "inline-more", inline)] + fn raw_capacity(&self) -> usize { + self.table.num_buckets() + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// let capacity_before_drain = a.capacity(); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// // As we can see, the map is empty and contains no element. + /// assert!(a.is_empty() && a.len() == 0); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_drain); + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// { // Iterator is dropped without being consumed. + /// let d = a.drain(); + /// } + /// + /// // But the map is empty even if we do not use Drain iterator. + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { + inner: self.table.drain(), + } + } + + /// Retains only the elements specified by the predicate. Keeps the + /// allocated memory for reuse. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// assert_eq!(map.len(), 8); + /// + /// map.retain(|&k, _| k % 2 == 0); + /// + /// // We can see, that the number of elements inside map is changed. + /// assert_eq!(map.len(), 4); + /// + /// let mut vec: Vec<(i32, i32)> = map.iter().map(|(&k, &v)| (k, v)).collect(); + /// vec.sort_unstable(); + /// assert_eq!(vec, [(0, 0), (2, 20), (4, 40), (6, 60)]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.table.iter() { + let &mut (ref key, ref mut value) = item.as_mut(); + if !f(key, value) { + self.table.erase(item); + } + } + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all pairs `(k, v)` such that `f(&k, &mut v)` returns `true` out + /// into another iterator. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// Keeps the allocated memory for reuse. + /// + /// [`retain()`]: HashMap::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// let drained: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// { // Iterator is dropped without being consumed. + /// let d = map.extract_if(|k, _v| k % 2 != 0); + /// } + /// + /// // ExtractIf was not exhausted, therefore no elements were drained. + /// assert_eq!(map.len(), 8); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.table.iter() }, + table: &mut self.table, + }, + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// let capacity_before_clear = a.capacity(); + /// + /// a.clear(); + /// + /// // Map is empty. + /// assert!(a.is_empty()); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_clear); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.table.clear(); + } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + inner: self.into_iter(), + } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + inner: self.into_iter(), + } + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashMap::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`abort`]: stdalloc::alloc::handle_alloc_error + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.reserve(10); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.table + .reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned: + /// ``` + /// # fn test() { + /// use hashbrown::HashMap; + /// use hashbrown::TryReserveError; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.try_reserve(usize::MAX) { + /// Err(error) => match error { + /// TryReserveError::CapacityOverflow => {} + /// _ => panic!("TryReserveError::AllocError ?"), + /// }, + /// _ => panic!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(not(miri))] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.table + .try_reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.table + .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// This function does nothing if the current capacity is smaller than the + /// supplied minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.table + .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { + let hash = make_hash::(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { + Entry::Occupied(OccupiedEntry { + hash, + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } + + /// Gets the given key's corresponding entry by reference in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut words: HashMap = HashMap::new(); + /// let source = ["poneyland", "horseyland", "poneyland", "poneyland"]; + /// for (i, &s) in source.iter().enumerate() { + /// let counter = words.entry_ref(s).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(words["poneyland"], 3); + /// assert_eq!(words["horseyland"], 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry_ref<'a, 'b, Q>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.hash_builder, key); + if let Some(elem) = self.table.find(hash, equivalent_key(key)) { + EntryRef::Occupied(OccupiedEntry { + hash, + elem, + table: self, + }) + } else { + EntryRef::Vacant(VacantEntryRef { + hash, + key, + table: self, + }) + } + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + match self.table.get(hash, equivalent_key(k)) { + Some((_, v)) => Some(v), + None => None, + } + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + match self.table.get(hash, equivalent_key(k)) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + } + + /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// let (k, v) = map.get_key_value_mut(&1).unwrap(); + /// assert_eq!(k, &1); + /// assert_eq!(v, &mut "a"); + /// *v = "b"; + /// assert_eq!(map.get_key_value_mut(&1), Some((&1, &mut "b"))); + /// assert_eq!(map.get_key_value_mut(&2), None); + /// ``` + #[inline] + pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + match self.table.get_mut(hash, equivalent_key(k)) { + Some(&mut (ref key, ref mut value)) => Some((key, value)), + None => None, + } + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains_key(&self, k: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + if self.table.is_empty() { + false + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get(hash, equivalent_key(k)).is_some() + } + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// + /// assert_eq!(map.get_mut(&2), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + match self.table.get_mut(hash, equivalent_key(k)) { + Some(&mut (_, ref mut v)) => Some(v), + None => None, + } + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // Get Athenæum and Bodleian Library + /// let [Some(a), Some(b)] = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) else { panic!() }; + /// + /// // Assert values of Athenæum and Library of Congress + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// None + /// ] + /// ); + /// ``` + /// + /// ```should_panic + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Athenæum".to_string(), 1807); + /// + /// // Duplicate keys panic! + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// ``` + pub fn get_disjoint_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_disjoint_mut_inner(ks) + .map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once. + #[deprecated(note = "use `get_disjoint_mut` instead")] + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_disjoint_mut(ks) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be used if + /// the key is missing. + /// + /// For a safe alternative see [`get_disjoint_mut`](`HashMap::get_disjoint_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // SAFETY: The keys do not overlap. + /// let [Some(a), Some(b)] = (unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) }) else { panic!() }; + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]) }; + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]) }; + /// // Missing keys result in None + /// assert_eq!(got, [Some(&mut 1807), None]); + /// ``` + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + unsafe { + self.get_disjoint_unchecked_mut_inner(ks) + .map(|res| res.map(|(_, v)| v)) + } + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + #[deprecated(note = "use `get_disjoint_unchecked_mut` instead")] + pub unsafe fn get_many_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] + where + Q: Hash + Equivalent + ?Sized, + { + unsafe { self.get_disjoint_unchecked_mut(ks) } + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_disjoint_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// Some((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)), + /// ], + /// ); + /// // Missing keys result in None + /// let got = libraries.get_disjoint_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, [Some((&"Bodleian Library".to_string(), &mut 1602)), None]); + /// ``` + /// + /// ```should_panic + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// + /// // Duplicate keys result in panic! + /// let got = libraries.get_disjoint_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// ``` + pub fn get_disjoint_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_disjoint_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + #[deprecated(note = "use `get_disjoint_key_value_mut` instead")] + pub fn get_many_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + self.get_disjoint_key_value_mut(ks) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys, without validating that the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_disjoint_key_value_mut`](`HashMap::get_disjoint_key_value_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_disjoint_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// Some((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)), + /// ], + /// ); + /// // Missing keys result in None + /// let got = libraries.get_disjoint_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some((&"Bodleian Library".to_string(), &mut 1602)), + /// None, + /// ], + /// ); + /// ``` + pub unsafe fn get_disjoint_key_value_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + unsafe { + self.get_disjoint_unchecked_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys, without validating that the values are unique. + #[deprecated(note = "use `get_disjoint_key_value_unchecked_mut` instead")] + pub unsafe fn get_many_key_value_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<(&'_ K, &'_ mut V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + unsafe { self.get_disjoint_key_value_unchecked_mut(ks) } + } + + fn get_disjoint_mut_inner( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut (K, V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_disjoint_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + unsafe fn get_disjoint_unchecked_mut_inner( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut (K, V)>; N] + where + Q: Hash + Equivalent + ?Sized, + { + unsafe { + let hashes = self.build_hashes_inner(ks); + self.table + .get_disjoint_unchecked_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + } + + fn build_hashes_inner(&self, ks: [&Q; N]) -> [u64; N] + where + Q: Hash + Equivalent + ?Sized, + { + let mut hashes = [0_u64; N]; + for i in 0..N { + hashes[i] = make_hash::(&self.hash_builder, ks[i]); + } + hashes + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [`std::collections`] + /// module-level documentation for more. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = make_hash(&self.hash_builder, &k); + let equivalent = equivalent_key(&k); + let hasher = make_hasher(&self.hash_builder); + match self + .table + .find_or_find_insert_index(hash, equivalent, hasher) + { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), + Err(index) => { + unsafe { + self.table.insert_at_index(hash, index, (k, v)); + } + None + } + } + } + + /// Insert a key-value pair into the map without checking + /// if the key already exists in the map. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the map. + /// For example, when constructing a map from another map, we know + /// that keys are unique. + /// + /// Returns a reference to the key and value just inserted. + /// + /// # Safety + /// + /// This operation is safe if a key does not exist in the map. + /// + /// However, if a key exists in the map already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the map + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashMap` + /// may be passed to unsafe code which does expect the map to behave + /// correctly, and would cause unsoundness as a result. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map1 = HashMap::new(); + /// assert_eq!(map1.insert(1, "a"), None); + /// assert_eq!(map1.insert(2, "b"), None); + /// assert_eq!(map1.insert(3, "c"), None); + /// assert_eq!(map1.len(), 3); + /// + /// let mut map2 = HashMap::new(); + /// + /// for (key, value) in map1.into_iter() { + /// unsafe { + /// map2.insert_unique_unchecked(key, value); + /// } + /// } + /// + /// let (key, value) = unsafe { map2.insert_unique_unchecked(4, "d") }; + /// assert_eq!(key, &4); + /// assert_eq!(value, &mut "d"); + /// *value = "e"; + /// + /// assert_eq!(map2[&1], "a"); + /// assert_eq!(map2[&2], "b"); + /// assert_eq!(map2[&3], "c"); + /// assert_eq!(map2[&4], "e"); + /// assert_eq!(map2.len(), 4); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { + let hash = make_hash::(&self.hash_builder, &k); + let bucket = self + .table + .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); + let (k_ref, v_ref) = unsafe { bucket.as_mut() }; + (k_ref, v_ref) + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// # Errors + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::OccupiedError; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// match map.try_insert(37, "b") { + /// Err(OccupiedError { entry, value }) => { + /// assert_eq!(entry.key(), &37); + /// assert_eq!(entry.get(), &"a"); + /// assert_eq!(value, "b"); + /// } + /// _ => panic!() + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert( + &mut self, + key: K, + value: V, + ) -> Result<&mut V, OccupiedError<'_, K, V, S, A>> { + match self.entry(key) { + Entry::Occupied(entry) => Err(OccupiedError { entry, value }), + Entry::Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map holds none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, k: &Q) -> Option + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.remove_entry(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.remove_entry(hash, equivalent_key(k)) + } + + /// Returns the total amount of memory allocated internally by the hash + /// set, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.table.allocation_size() + } +} + +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).is_some_and(|v| *value == *v)) + } +} + +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator, +{ +} + +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HashMap +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use std::hash::RandomState; + /// + /// // You can specify all types of HashMap, including hasher and allocator. + /// // Created map is empty and don't allocate memory + /// let map: HashMap = Default::default(); + /// assert_eq!(map.capacity(), 0); + /// let map: HashMap = HashMap::default(); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::with_hasher_in(Default::default(), Default::default()) + } +} + +impl Index<&Q> for HashMap +where + K: Eq + Hash, + Q: Hash + Equivalent + ?Sized, + S: BuildHasher, + A: Allocator, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", "One"), ("b", "Two")].into(); + /// + /// assert_eq!(map[&"a"], "One"); + /// assert_eq!(map[&"b"], "Two"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "default-hasher")] +impl From<[(K, V); N]> for HashMap +where + K: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map1 = HashMap::from([(1, 2), (3, 4)]); + /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + arr.into_iter().collect() + } +} + +/// An iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a V)`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: HashMap::iter +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((&1, &"a")), Some((&2, &"b")), Some((&3, &"c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct Iter<'a, K, V> { + inner: RawIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a mut V)`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: HashMap::iter_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut iter = map.iter_mut(); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct IterMut<'a, K, V> { + inner: RawIter<(K, V)>, + // To ensure invariance with respect to V + marker: PhantomData<(&'a K, &'a mut V)>, +} + +// We override the default Send impl which has K: Sync instead of K: Send. Both +// are correct, but this one is more general since it allows keys which +// implement Send but not Sync. +unsafe impl Send for IterMut<'_, K, V> {} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_iter`]: HashMap::into_iter +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.into_iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `IntoIter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct IntoIter { + inner: RawIntoIter<(K, V), A>, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `K`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_keys`]: HashMap::into_keys +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.into_keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `IntoKeys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(1), Some(2), Some(3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct IntoKeys { + inner: IntoIter, +} + +impl Default for IntoKeys { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} + +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(k, _)| k)) + .finish() + } +} + +/// An owning iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `V`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. The map cannot be used after calling that method. +/// +/// [`into_values`]: HashMap::into_values +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.into_values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `IntoValues` iterator produces values in arbitrary order, so +/// // the values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some("a"), Some("b"), Some("c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct IntoValues { + inner: IntoIter, +} + +impl Default for IntoValues { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} + +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, v)| v)) + .finish() + } +} + +/// An iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a K`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: HashMap::keys +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `Keys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&1), Some(&2), Some(&3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct Keys<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Keys { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a V`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: HashMap::values +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `Values` iterator produces values in arbitrary order, so the +/// // values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&"a"), Some(&"b"), Some(&"c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct Values<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Values { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap` in arbitrary +/// order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: HashMap::drain +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut drain_iter = map.drain(); +/// let mut vec = vec![drain_iter.next(), drain_iter.next(), drain_iter.next()]; +/// +/// // The `Drain` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(drain_iter.next(), None); +/// assert_eq!(drain_iter.next(), None); +/// ``` +pub struct Drain<'a, K, V, A: Allocator = Global> { + inner: RawDrain<'a, (K, V), A>, +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate +/// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`extract_if`]: HashMap::extract_if +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut extract_if = map.extract_if(|k, _v| k % 2 != 0); +/// let mut vec = vec![extract_if.next(), extract_if.next()]; +/// +/// // The `ExtractIf` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")),Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(extract_if.next(), None); +/// assert_eq!(extract_if.next(), None); +/// drop(extract_if); +/// +/// assert_eq!(map.len(), 1); +/// ``` +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, (K, V), A>, +} + +impl Iterator for ExtractIf<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator, +{ + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +/// A mutable iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a mut V`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: HashMap::values_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut values = map.values_mut(); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct ValuesMut<'a, K, V> { + inner: IterMut<'a, K, V>, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`entry`]: HashMap::entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let entry: Entry<_, _, _> = map.entry("a"); +/// let _raw_o: OccupiedEntry<_, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5), ("f", 6)]); +/// ``` +pub enum Entry<'a, K, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, K, V, S, A>), +} + +impl Debug for Entry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a [`HashMap`]. +/// It is part of the [`Entry`] and [`EntryRef`] enums. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// let _entry_o: OccupiedEntry<_, _, _> = map.entry("a").insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.get(&"c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl Send for OccupiedEntry<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl Debug for OccupiedEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, VacantEntry}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// let entry_v: VacantEntry<_, _, _> = match map.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry("b") { +/// Entry::Occupied(_) => unreachable!(), +/// Entry::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: K, + table: &'a mut HashMap, +} + +impl Debug for VacantEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied, +/// with any borrowed form of the map's key type. +/// +/// +/// This `enum` is constructed from the [`entry_ref`] method on [`HashMap`]. +/// +/// [`Hash`] and [`Eq`] on the borrowed form of the map's key type *must* match those +/// for the key type. It also require that key may be constructed from the borrowed +/// form through the [`ToOwned`] trait. +/// +/// [`entry_ref`]: HashMap::entry_ref +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let key = String::from("a"); +/// let entry: EntryRef<_, _, _, _> = map.entry_ref(&key); +/// let _raw_o: OccupiedEntry<_, _, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry_ref("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry_ref("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry_ref("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry_ref("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry_ref("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// for (key, value) in ["a", "b", "c", "d", "e", "f"].into_iter().zip(1..=6) { +/// assert_eq!(map[key], value) +/// } +/// assert_eq!(map.len(), 6); +/// ``` +pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap<_, _> = [("a".to_owned(), 100), ("b".into(), 200)].into(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Vacant(_) => unreachable!(), + /// EntryRef::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Occupied(_) => unreachable!(), + /// EntryRef::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>), +} + +impl Debug for EntryRef<'_, '_, K, Q, V, S, A> +where + K: Debug + Borrow, + Q: Debug + ?Sized, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + EntryRef::Vacant(ref v) => f.debug_tuple("EntryRef").field(v).finish(), + EntryRef::Occupied(ref o) => f.debug_tuple("EntryRef").field(o).finish(), + } + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, VacantEntryRef}; +/// +/// let mut map = HashMap::::new(); +/// +/// let entry_v: VacantEntryRef<_, _, _, _> = match map.entry_ref("a") { +/// EntryRef::Vacant(view) => view, +/// EntryRef::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map["a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry_ref("b") { +/// EntryRef::Occupied(_) => unreachable!(), +/// EntryRef::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map["b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntryRef<'map, 'key, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: &'key Q, + table: &'map mut HashMap, +} + +impl Debug for VacantEntryRef<'_, '_, K, Q, V, S, A> +where + K: Borrow, + Q: Debug + ?Sized, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntryRef").field(&self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, OccupiedError}; +/// +/// let mut map: HashMap<_, _> = [("a", 10), ("b", 20)].into(); +/// +/// // try_insert method returns mutable reference to the value if keys are vacant, +/// // but if the map did have key present, nothing is updated, and the provided +/// // value is returned inside `Err(_)` variant +/// match map.try_insert("a", 100) { +/// Err(OccupiedError { mut entry, value }) => { +/// assert_eq!(entry.key(), &"a"); +/// assert_eq!(value, 100); +/// assert_eq!(entry.insert(100), 10) +/// } +/// _ => unreachable!(), +/// } +/// assert_eq!(map[&"a"], 100); +/// ``` +pub struct OccupiedError<'a, K, V, S, A: Allocator = Global> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, S, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +impl Debug for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +impl fmt::Display for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// Return the same `Iter` struct as by the [`iter`] method on [`HashMap`]. + /// + /// [`iter`]: HashMap::iter + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map_one: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); + /// let mut map_two = HashMap::new(); + /// + /// for (key, value) in &map_one { + /// println!("Key: {}, Value: {}", key, value); + /// map_two.insert(*key, *value); + /// } + /// + /// assert_eq!(map_one, map_two); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order + /// with mutable references to the values. The iterator element type is + /// `(&'a K, &'a mut V)`. + /// + /// Return the same `IterMut` struct as by the [`iter_mut`] method on + /// [`HashMap`]. + /// + /// [`iter_mut`]: HashMap::iter_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// for (key, value) in &mut map { + /// println!("Key: {}, Value: {}", key, value); + /// *value *= 2; + /// } + /// + /// let mut vec = map.iter().collect::>(); + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(&"a", &2), (&"b", &4), (&"c", &6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// // Not possible with .iter() + /// let mut vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so + /// // the items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.table.into_iter(), + } + } +} + +impl Default for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_ref(); + Some((&r.0, &r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_ref(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +impl Default for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_mut(); + Some((&r.0, &mut r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_mut(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl Iterator for IntoIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Default for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +impl ExactSizeIterator for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Keys<'_, K, V> {} + +impl Default for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Values<'_, K, V> {} + +impl Default for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a mut V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, val)| val)) + .finish() + } +} + +impl Iterator for Drain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, K, V, A> {} + +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// let entry = map.entry("poneyland").or_insert_entry(3); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &3); + /// + /// // existing key + /// let mut entry = map.entry("poneyland").or_insert_entry(10); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_entry(self, default: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry("horseland").key(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } + + /// Converts the `Entry` into a mutable reference to the underlying map. + pub fn into_map(self) -> &'a mut HashMap { + match self { + Entry::Occupied(entry) => entry.table, + Entry::Vacant(entry) => entry.table, + } + } +} + +impl<'a, K, V: Default, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland", Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.key(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Replaces the key in the entry with a new one. + /// + /// # Panics + /// + /// This method panics if `key` is not equivalent to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let old_key = "poneyland"; + /// let new_key = Box::leak(old_key.to_owned().into_boxed_str()); + /// map.entry(old_key).or_insert(12); + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(mut entry) => { + /// let replaced = entry.replace_key(new_key); + /// assert!(std::ptr::eq(replaced, old_key)); + /// assert!(std::ptr::eq(*entry.key(), new_key)); + /// }, + /// } + /// + /// # // appease miri; no memory leaks here! + /// # drop(map); + /// # unsafe { + /// # Box::from_raw(new_key); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(&mut self, key: K) -> K + where + K: Equivalent, + { + assert!( + self.key().equivalent(&key), + "replaced key is not equivalent to the one in the entry" + ); + + // SAFETY: We verified that the keys were equivalent. + unsafe { self.replace_key_unchecked(key) } + } + + /// Replaces the key in the entry with a new one, without checking the + /// equivalence of the key. + /// + /// # Safety + /// + /// This operation is safe if you replace the key with an equivalent one. + /// + /// Additionally, this operation (and following operations) are guaranteed + /// to not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashMap` + /// may be passed to unsafe code which does expect the map to behave + /// correctly. If the map has keys at unexpected positions inside it, + /// future operations may panic, loop forever, or return unexpected results, + /// potentially violating memory safety. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let old_key = "poneyland"; + /// let new_key = Box::leak(old_key.to_owned().into_boxed_str()); + /// map.entry(old_key).or_insert(12); + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(mut entry) => { + /// let replaced = unsafe { entry.replace_key_unchecked(new_key) }; + /// assert!(std::ptr::eq(replaced, old_key)); + /// assert!(std::ptr::eq(*entry.key(), new_key)); + /// }, + /// } + /// + /// # // appease miri; no memory leaks here! + /// # drop(map); + /// # unsafe { + /// # Box::from_raw(new_key); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_key_unchecked(&mut self, key: K) -> K { + mem::replace(unsafe { &mut self.elem.as_mut().0 }, key) + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland", 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// let value: &mut u32; + /// match map.entry("poneyland") { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the `OccupiedEntry` into a reference to the key and a + /// mutable reference to the value in the entry with a lifetime bound to the + /// map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`key`] and + /// [`get_mut`]. + /// + /// [`key`]: Self::key + /// [`get_mut`]: Self::get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// let key_val: (&&str, &mut u32); + /// match map.entry("poneyland") { + /// Entry::Occupied(entry) => key_val = entry.into_entry(), + /// Entry::Vacant(_) => panic!(), + /// } + /// *key_val.1 += 10; + /// + /// assert_eq!(key_val, (&"poneyland", &mut 22)); + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_entry(self) -> (&'a K, &'a mut V) { + let (key, val) = unsafe { self.elem.as_mut() }; + (key, val) + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the underlying map. + pub fn into_map(self) -> &'a mut HashMap { + self.table + } +} + +impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// match map.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the [`VacantEntry`]'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + /// Sets the value of the entry with the [`VacantEntry`]'s key, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + elem, + table: self.table, + } + } + + /// Converts the `VacantEntry` into a mutable reference to the underlying map. + pub fn into_map(self) -> &'a mut HashMap { + self.table + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let entry = map.entry_ref("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), "horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(mut entry) => { + entry.insert(value); + entry + } + EntryRef::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function an access to the borrower form of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash + Borrow, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => { + let value = default(entry.key); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry_ref("horseland").key(), "horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + match *self { + EntryRef::Occupied(ref entry) => entry.key().borrow(), + EntryRef::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + EntryRef::Occupied(mut entry) => { + f(entry.get_mut()); + EntryRef::Occupied(entry) + } + EntryRef::Vacant(entry) => EntryRef::Vacant(entry), + } + } + + /// Converts the `EntryRef` into a mutable reference to the underlying map. + pub fn into_map(self) -> &'a mut HashMap { + match self { + EntryRef::Occupied(entry) => entry.table, + EntryRef::Vacant(entry) => entry.table, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland".to_string(), Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry_ref("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(Default::default()), + } + } + + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// let entry = map.entry_ref("poneyland").or_default_entry(); + /// assert_eq!(entry.key(), &"poneyland"); + /// assert_eq!(entry.get(), &None); + /// + /// // existing key + /// map.insert("horseland".to_string(), Some(3)); + /// let entry = map.entry_ref("horseland").or_default_entry(); + /// assert_eq!(entry.key(), &"horseland"); + /// assert_eq!(entry.get(), &Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default_entry(self) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry, + EntryRef::Vacant(entry) => entry.insert_entry(Default::default()), + } + } +} + +impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K, Q, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntryRef`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// assert_eq!(map.entry_ref(key).key(), "poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &'key Q { + self.key + } + + /// Sets the value of the entry with the `VacantEntryRef`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// if let EntryRef::Vacant(o) = map.entry_ref(key) { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'map mut V + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key.to_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + /// Sets the key and value of the entry and returns a mutable reference to + /// the inserted value. + /// + /// Unlike [`VacantEntryRef::insert`], this method allows the key to be + /// explicitly specified, which is useful for key types that don't implement + /// `ToOwned`. + /// + /// # Panics + /// + /// This method panics if `key` is not equivalent to the key used to create + /// the `VacantEntryRef`. + /// + /// # Example + /// + /// ``` + /// use hashbrown::hash_map::EntryRef; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::<(String, String), char>::new(); + /// let k = ("c".to_string(), "C".to_string()); + /// let v = match map.entry_ref(&k) { + /// // Insert cannot be used here because tuples do not implement ToOwned. + /// // However this works because we can manually clone instead. + /// EntryRef::Vacant(r) => r.insert_with_key(k.clone(), 'c'), + /// // In this branch we avoid the clone. + /// EntryRef::Occupied(r) => r.into_mut(), + /// }; + /// assert_eq!(*v, 'c'); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_key(self, key: K, value: V) -> &'map mut V + where + K: Hash, + Q: Equivalent, + S: BuildHasher, + { + self.insert_entry_with_key(key, value).into_mut() + } + + /// Sets the key and value of the entry and returns a mutable reference to + /// the inserted value, without checking the equivalence of the key. + /// + /// See [`insert_with_key`](Self::insert_with_key) for more information. + /// + /// # Safety + /// + /// This operation is safe if the keys are equivalent. + /// + /// Additionally, this operation (and following operations) are guaranteed + /// to not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashMap` + /// may be passed to unsafe code which does expect the map to behave + /// correctly. If the map has keys at unexpected positions inside it, + /// future operations may panic, loop forever, or return unexpected results, + /// potentially violating memory safety. + /// + /// # Example + /// + /// ``` + /// use hashbrown::hash_map::EntryRef; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::<(String, String), char>::new(); + /// let k = ("c".to_string(), "C".to_string()); + /// let v = match map.entry_ref(&k) { + /// // SAFETY: We trust the `Clone` implementation to return an equivalent value + /// EntryRef::Vacant(r) => unsafe { r.insert_with_key_unchecked(k.clone(), 'c') }, + /// // In this branch we avoid the clone. + /// EntryRef::Occupied(r) => r.into_mut(), + /// }; + /// assert_eq!(*v, 'c'); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_with_key_unchecked(self, key: K, value: V) -> &'map mut V + where + K: Hash, + S: BuildHasher, + { + // SAFETY: Guaranteed by caller. + unsafe { self.insert_entry_with_key_unchecked(key, value) }.into_mut() + } + + /// Sets the value of the entry with the [`VacantEntryRef`]'s key, + /// and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let EntryRef::Vacant(v) = map.entry_ref(&"poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'map, K, V, S, A> + where + K: Hash, + Q: ToOwned, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key.to_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + elem, + table: self.table, + } + } + + /// Sets the key and value of the entry and returns an [`OccupiedEntry`]. + /// + /// Unlike [`VacantEntryRef::insert_entry`], this method allows the key to + /// be explicitly specified, which is useful for key types that don't + /// implement `ToOwned`. + /// + /// # Panics + /// + /// This method panics if `key` is not equivalent to the key used to create + /// the `VacantEntryRef`. + /// + /// # Example + /// + /// ``` + /// use hashbrown::hash_map::EntryRef; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::<(String, String), char>::new(); + /// let k = ("c".to_string(), "C".to_string()); + /// let r = match map.entry_ref(&k) { + /// // Insert cannot be used here because tuples do not implement ToOwned. + /// // However this works because we can manually clone instead. + /// EntryRef::Vacant(r) => r.insert_entry_with_key(k.clone(), 'c'), + /// // In this branch we avoid the clone. + /// EntryRef::Occupied(r) => r, + /// }; + /// assert_eq!(r.get(), &'c'); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry_with_key(self, key: K, value: V) -> OccupiedEntry<'map, K, V, S, A> + where + K: Hash, + Q: Equivalent, + S: BuildHasher, + { + assert!( + (self.key).equivalent(&key), + "key used for Entry creation is not equivalent to the one used for insertion" + ); + // SAFETY: We checked equivalence first. + unsafe { self.insert_entry_with_key_unchecked(key, value) } + } + + /// Sets the key and value of the entry and returns an [`OccupiedEntry`], + /// without checking the equivalence of the key. + /// + /// See [`insert_entry_with_key`](Self::insert_entry_with_key) for more information. + /// + /// # Safety + /// + /// This operation is safe if the keys are equivalent. + /// + /// Additionally, this operation (and following operations) are guaranteed + /// to not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashMap` + /// may be passed to unsafe code which does expect the map to behave + /// correctly. If the map has keys at unexpected positions inside it, + /// future operations may panic, loop forever, or return unexpected results, + /// potentially violating memory safety. + /// + /// # Example + /// + /// ``` + /// use hashbrown::hash_map::EntryRef; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::<(String, String), char>::new(); + /// let k = ("c".to_string(), "C".to_string()); + /// let r = match map.entry_ref(&k) { + /// // SAFETY: We trust the `Clone` implementation to return an equivalent key + /// EntryRef::Vacant(r) => unsafe { r.insert_entry_with_key_unchecked(k.clone(), 'c') }, + /// // In this branch we avoid the clone. + /// EntryRef::Occupied(r) => r, + /// }; + /// assert_eq!(r.get(), &'c'); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_entry_with_key_unchecked( + self, + key: K, + value: V, + ) -> OccupiedEntry<'map, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + elem, + table: self.table, + } + } + + /// Converts the `VacantEntryRef` into a mutable reference to the underlying map. + pub fn into_map(self) -> &'map mut HashMap { + self.table + } +} + +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let mut map = + Self::with_capacity_and_hasher_in(iter.size_hint().0, S::default(), A::default()); + iter.for_each(|(k, v)| { + map.insert(k, v); + }); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let some_iter = [(1, 1), (2, 2)].into_iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr); + /// let old_map_len = map.len(); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(map); + /// assert_eq!(new_map.len(), old_map_len); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + iter.size_hint().0.div_ceil(2) + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { + additional + } else { + additional.div_ceil(2) + }; + self.reserve(reserve); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter().map(|(k, v)| (k, v)); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec.iter().map(|(k, v)| (k, v))); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr.iter().map(|(k, v)| (k, v))); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(&map); + /// assert_eq!(new_map, map); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (&'a K, &'a V)) { + self.insert(*k, *v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<&'a (K, V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(&some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(&some_arr); + /// + /// let mut vec: Vec<_> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|&(key, value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, &(k, v): &'a (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +#[expect(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new, A: Allocator>( + v: IntoIter<&'static str, u8, A>, + ) -> IntoIter<&'new str, u8, A> { + v + } + fn into_iter_val<'new, A: Allocator>( + v: IntoIter, + ) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} + +#[cfg(test)] +mod test_map { + use super::DefaultHashBuilder; + use super::Entry::{Occupied, Vacant}; + use super::EntryRef; + use super::HashMap; + use crate::alloc::{AllocError, Allocator, Global}; + use core::alloc::Layout; + use core::ptr::NonNull; + use core::sync::atomic::{AtomicI8, Ordering}; + use rand::{Rng, SeedableRng, rngs::SmallRng}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::vec::Vec; + use stdalloc::string::String; + use stdalloc::sync::Arc; + + #[test] + fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); + } + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + #[test] + fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + #[test] + fn test_clone_from() { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + m2.clone_from(&m); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + thread_local! { static DROP_VECTOR: RefCell> = const { RefCell::new(Vec::new()) } } + + #[derive(Hash, PartialEq, Eq)] + struct Droppable { + k: usize, + } + + impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } + } + + impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Droppable { + fn clone(&self) -> Self { + Droppable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_entry_ref() { + let mut m: HashMap = HashMap::new(); + match m.entry_ref("poneyland") { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(_) => {} + } + assert!(*m.entry_ref("poneyland").or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: takes too long + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); + let mut hashmap: HashMap = HashMap::default(); + let key = &1; + let result = hashmap.get_mut(key); + assert!(result.is_none()); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(1, 3).is_some()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_insert_unique_unchecked() { + let mut map = HashMap::new(); + let (k1, v1) = unsafe { map.insert_unique_unchecked(10, 11) }; + assert_eq!((&10, &mut 11), (k1, v1)); + let (k2, v2) = unsafe { map.insert_unique_unchecked(20, 21) }; + assert_eq!((&20, &mut 21), (k2, v2)); + assert_eq!(Some(&11), map.get(&10)); + assert_eq!(Some(&21), map.get(&20)); + assert_eq!(None, map.get(&30)); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2; + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{map:?}"); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.raw_capacity(), 1); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); + + assert_eq!(raw_cap, initial_raw_cap * 2); + + let mut i = 0; + for _ in 0..raw_cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.raw_capacity(), raw_cap); + + for _ in 0..raw_cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); + + for _ in 0..raw_cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.raw_capacity(), new_raw_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.raw_capacity(), raw_cap); + // again, a little more than half full + for _ in 0..raw_cap / 2 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.raw_capacity(), initial_raw_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + _ = map[&4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_ref() { + let xs = [ + ("One".to_owned(), 10), + ("Two".to_owned(), 20), + ("Three".to_owned(), 30), + ("Four".to_owned(), 40), + ("Five".to_owned(), 50), + ("Six".to_owned(), 60), + ]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry_ref("One") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get("One").unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry_ref("Two") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get("Two").unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry_ref("Three") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get("Three"), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry_ref("Ten") { + EntryRef::Occupied(_) => unreachable!(), + EntryRef::Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get("Ten").unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + #![expect(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_entry_ref_take_doesnt_corrupt() { + #![expect(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + match m.entry_ref(x.as_str()) { + EntryRef::Vacant(_) => {} + EntryRef::Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_extend_ref_k_ref_v() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + fn test_extend_ref_kv_tuple() { + use std::ops::AddAssign; + let mut a = HashMap::new(); + a.insert(0, 0); + + fn create_arr + Copy, const N: usize>(start: T, step: T) -> [(T, T); N] { + let mut outs: [(T, T); N] = [(start, start); N]; + let mut element = step; + outs.iter_mut().skip(1).for_each(|(k, v)| { + *k += element; + *v += element; + element += step; + }); + outs + } + + let for_iter: Vec<_> = (0..100).map(|i| (i, i)).collect(); + let iter = for_iter.iter(); + let vec: Vec<_> = (100..200).map(|i| (i, i)).collect(); + a.extend(iter); + a.extend(&vec); + a.extend(create_arr::(200, 1)); + + assert_eq!(a.len(), 300); + + for item in 0..300 { + assert_eq!(a[&item], item); + } + } + + #[test] + fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); + } + + #[test] + fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key, value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_ref_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.to_owned(), value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry_ref(key) { + EntryRef::Vacant(_) => panic!(), + EntryRef::Occupied(e) => assert_eq!(key, e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_ref_key() { + let mut a: HashMap = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry_ref(key) { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(e) => { + assert_eq!(key, e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![expect(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } + + #[test] + fn test_extract_if() { + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + let drained = map.extract_if(|&k, _| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(map.len(), 4); + } + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + map.extract_if(|&k, _| k % 2 == 0).for_each(drop); + assert_eq!(map.len(), 4); + } + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) + fn test_try_reserve() { + use crate::TryReserveError::{AllocError, CapacityOverflow}; + + const MAX_ISIZE: usize = isize::MAX as usize; + + let mut empty_bytes: HashMap = HashMap::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(usize::MAX) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_ISIZE) { + } else { + panic!("isize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_ISIZE / 5) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a few more hashmaps to ensure the allocation will fail. + let mut empty_bytes2: HashMap = HashMap::new(); + let _ = empty_bytes2.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes3: HashMap = HashMap::new(); + let _ = empty_bytes3.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes4: HashMap = HashMap::new(); + if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_ISIZE / 5) { + } else { + panic!("isize::MAX / 5 should trigger an OOM!"); + } + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP; + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } + + #[test] + fn test_get_disjoint_mut() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + map.insert("bar".to_owned(), 10); + map.insert("baz".to_owned(), 20); + map.insert("qux".to_owned(), 30); + + let xs = map.get_disjoint_mut(["foo", "qux"]); + assert_eq!(xs, [Some(&mut 0), Some(&mut 30)]); + + let xs = map.get_disjoint_mut(["foo", "dud"]); + assert_eq!(xs, [Some(&mut 0), None]); + + let ys = map.get_disjoint_key_value_mut(["bar", "baz"]); + assert_eq!( + ys, + [ + Some((&"bar".to_owned(), &mut 10)), + Some((&"baz".to_owned(), &mut 20)) + ], + ); + + let ys = map.get_disjoint_key_value_mut(["bar", "dip"]); + assert_eq!(ys, [Some((&"bar".to_owned(), &mut 10)), None]); + } + + #[test] + #[should_panic = "duplicate keys found"] + fn test_get_disjoint_mut_duplicate() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + + let _xs = map.get_disjoint_mut(["foo", "foo"]); + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_from_double_drop() { + #[derive(Clone)] + struct CheckedDrop { + panic_in_drop: bool, + dropped: bool, + } + impl Drop for CheckedDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + const DISARMED: CheckedDrop = CheckedDrop { + panic_in_drop: false, + dropped: false, + }; + const ARMED: CheckedDrop = CheckedDrop { + panic_in_drop: true, + dropped: false, + }; + + let mut map1 = HashMap::new(); + map1.insert(1, DISARMED); + map1.insert(2, DISARMED); + map1.insert(3, DISARMED); + map1.insert(4, DISARMED); + + let mut map2 = HashMap::new(); + map2.insert(1, DISARMED); + map2.insert(2, ARMED); + map2.insert(3, DISARMED); + map2.insert(4, DISARMED); + + map2.clone_from(&map1); + } + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_from_memory_leaks() { + use stdalloc::vec::Vec; + + struct CheckedClone { + panic_in_clone: bool, + need_drop: Vec, + } + impl Clone for CheckedClone { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + need_drop: self.need_drop.clone(), + } + } + } + let mut map1 = HashMap::new(); + map1.insert( + 1, + CheckedClone { + panic_in_clone: false, + need_drop: vec![0, 1, 2], + }, + ); + map1.insert( + 2, + CheckedClone { + panic_in_clone: false, + need_drop: vec![3, 4, 5], + }, + ); + map1.insert( + 3, + CheckedClone { + panic_in_clone: true, + need_drop: vec![6, 7, 8], + }, + ); + let _map2 = map1.clone(); + } + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl MyAlloc { + fn new(drop_count: Arc) -> Self { + MyAlloc { + _inner: Arc::new(MyAllocInner { drop_count }), + } + } + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + let g = Global; + g.deallocate(ptr, layout); + } + } + } + + #[test] + fn test_hashmap_into_iter_bug() { + let dropped: Arc = Arc::new(AtomicI8::new(1)); + + { + let mut map = HashMap::with_capacity_in(10, MyAlloc::new(dropped.clone())); + for i in 0..10 { + map.entry(i).or_insert_with(|| "i".to_owned()); + } + + for (k, v) in map { + println!("{k}, {v}"); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[derive(Debug)] + struct CheckedCloneDrop { + panic_in_clone: bool, + panic_in_drop: bool, + dropped: bool, + data: T, + } + + impl CheckedCloneDrop { + fn new(panic_in_clone: bool, panic_in_drop: bool, data: T) -> Self { + CheckedCloneDrop { + panic_in_clone, + panic_in_drop, + dropped: false, + data, + } + } + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + panic_in_drop: self.panic_in_drop, + dropped: self.dropped, + data: self.data.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + /// Return hashmap with predefined distribution of elements. + /// All elements will be located in the same order as elements + /// returned by iterator. + /// + /// This function does not panic, but returns an error as a `String` + /// to distinguish between a test panic and an error in the input data. + fn get_test_map( + iter: I, + mut fun: impl FnMut(u64) -> T, + alloc: A, + ) -> Result, DefaultHashBuilder, A>, String> + where + I: Iterator + Clone + ExactSizeIterator, + A: Allocator, + T: PartialEq + core::fmt::Debug, + { + use crate::scopeguard::guard; + + let mut map: HashMap, _, A> = + HashMap::with_capacity_in(iter.size_hint().0, alloc); + { + let mut guard = guard(&mut map, |map| { + for (_, value) in map.iter_mut() { + value.panic_in_drop = false; + } + }); + + let mut count = 0; + // Hash and Key must be equal to each other for controlling the elements placement. + for (panic_in_clone, panic_in_drop) in iter.clone() { + if core::mem::needs_drop::() && panic_in_drop { + return Err(String::from( + "panic_in_drop can be set with a type that doesn't need to be dropped", + )); + } + guard.table.insert( + count, + ( + count, + CheckedCloneDrop::new(panic_in_clone, panic_in_drop, fun(count)), + ), + |(k, _)| *k, + ); + count += 1; + } + + // Let's check that all elements are located as we wanted + let mut check_count = 0; + for ((key, value), (panic_in_clone, panic_in_drop)) in guard.iter().zip(iter) { + if *key != check_count { + return Err(format!( + "key != check_count,\nkey: `{key}`,\ncheck_count: `{check_count}`" + )); + } + if value.dropped + || value.panic_in_clone != panic_in_clone + || value.panic_in_drop != panic_in_drop + || value.data != fun(check_count) + { + return Err(format!( + "Value is not equal to expected,\nvalue: `{:?}`,\nexpected: \ + `CheckedCloneDrop {{ panic_in_clone: {}, panic_in_drop: {}, dropped: {}, data: {:?} }}`", + value, + panic_in_clone, + panic_in_drop, + false, + fun(check_count) + )); + } + check_count += 1; + } + + if guard.len() != check_count as usize { + return Err(format!( + "map.len() != check_count,\nmap.len(): `{}`,\ncheck_count: `{}`", + guard.len(), + check_count + )); + } + + if count != check_count { + return Err(format!( + "count != check_count,\ncount: `{count}`,\ncheck_count: `{check_count}`" + )); + } + core::mem::forget(guard); + } + Ok(map) + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + const ARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + const DISARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_memory_leaks_and_double_drop_one() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap>, DefaultHashBuilder, MyAlloc> = + match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // Clone should normally clone a few elements, and then (when the + // clone function panics), deallocate both its own memory, memory + // of `dropped: Arc` and the memory of already cloned + // elements (Vec memory inside CheckedCloneDrop). + let _map2 = map.clone(); + } + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_memory_leaks_and_double_drop_two() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap, DefaultHashBuilder, _> = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + let mut map2 = match get_test_map( + DISARMED_FLAGS.into_iter().zip(ARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // The `clone_from` should try to drop the elements of `map2` without + // double drop and leaking the allocator. Elements that have not been + // dropped leak their memory. + map2.clone_from(&map); + } + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are equal to each other). + #[test] + #[cfg(panic = "unwind")] + fn test_catch_panic_clone_from_when_len_is_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| vec![n * 2], MyAlloc::new(dropped.clone())) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.num_buckets() != scope_map.table.num_buckets() { + return format!( + "map.table.num_buckets() != scope_map.table.num_buckets(),\nleft: `{}`,\nright: `{}`", + map.table.num_buckets(), scope_map.table.num_buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.num_buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are not equal to each other). + #[test] + #[cfg(panic = "unwind")] + fn test_catch_panic_clone_from_when_len_is_not_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + [DISARMED].into_iter().zip([DISARMED]), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n * 2], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.num_buckets() == scope_map.table.num_buckets() { + return format!( + "map.table.num_buckets() == scope_map.table.num_buckets(): `{}`", + map.table.num_buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.num_buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[test] + fn test_allocation_info() { + assert_eq!(HashMap::<(), ()>::new().allocation_size(), 0); + assert_eq!(HashMap::::new().allocation_size(), 0); + assert!( + HashMap::::with_capacity(1).allocation_size() > core::mem::size_of::() + ); + } +} + +#[cfg(all(test, unix, any(feature = "nightly", feature = "allocator-api2")))] +mod test_map_with_mmap_allocations { + use super::HashMap; + use crate::raw::prev_pow2; + use core::alloc::Layout; + use core::ptr::{NonNull, null_mut}; + + #[cfg(feature = "nightly")] + use core::alloc::{AllocError, Allocator}; + + #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))] + use allocator_api2::alloc::{AllocError, Allocator}; + + /// This is not a production quality allocator, just good enough for + /// some basic tests. + #[derive(Clone, Copy, Debug)] + struct MmapAllocator { + /// Guarantee this is a power of 2. + page_size: usize, + } + + impl MmapAllocator { + fn new() -> Result { + let result = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; + if result < 1 { + return Err(AllocError); + } + + let page_size = result as usize; + if page_size.is_power_of_two() { + Ok(Self { page_size }) + } else { + Err(AllocError) + } + } + + fn fit_to_page_size(&self, n: usize) -> Result { + // If n=0, give a single page (wasteful, I know). + let n = if n == 0 { self.page_size } else { n }; + + match n & (self.page_size - 1) { + 0 => Ok(n), + rem => n.checked_add(self.page_size - rem).ok_or(AllocError), + } + } + } + + unsafe impl Allocator for MmapAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + if layout.align() > self.page_size { + return Err(AllocError); + } + + let null = null_mut(); + let len = self.fit_to_page_size(layout.size())? as libc::size_t; + let prot = libc::PROT_READ | libc::PROT_WRITE; + let flags = libc::MAP_PRIVATE | libc::MAP_ANON; + let addr = unsafe { libc::mmap(null, len, prot, flags, -1, 0) }; + + // mmap returns MAP_FAILED on failure, not Null. + if addr == libc::MAP_FAILED { + return Err(AllocError); + } + + if let Some(data) = NonNull::new(addr.cast()) { + // SAFETY: this is NonNull::slice_from_raw_parts. + Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(data.as_ptr(), len)) + }) + } else { + // This branch shouldn't be taken in practice, but since we + // cannot return null as a valid pointer in our type system, + // we attempt to handle it. + _ = unsafe { libc::munmap(addr, len) }; + Err(AllocError) + } + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + // If they allocated it with this layout, it must round correctly. + let size = self.fit_to_page_size(layout.size()).unwrap(); + let _result = libc::munmap(ptr.as_ptr().cast(), size); + debug_assert_eq!(0, _result); + } + } + } + + #[test] + fn test_tiny_allocation_gets_rounded_to_page_size() { + let alloc = MmapAllocator::new().unwrap(); + let mut map: HashMap = HashMap::with_capacity_in(1, alloc); + + // Size of an element plus its control byte. + let rough_bucket_size = core::mem::size_of::<(usize, ())>() + 1; + + // Accounting for some misc. padding that's likely in the allocation + // due to rounding to group width, etc. + let overhead = 3 * core::mem::size_of::(); + let num_buckets = (alloc.page_size - overhead) / rough_bucket_size; + // Buckets are always powers of 2. + let min_elems = prev_pow2(num_buckets); + // Real load-factor is 7/8, but this is a lower estimation, so 1/2. + let min_capacity = min_elems >> 1; + let capacity = map.capacity(); + assert!( + capacity >= min_capacity, + "failed: {capacity} >= {min_capacity}" + ); + + // Fill it up. + for i in 0..capacity { + map.insert(i, ()); + } + // Capacity should not have changed and it should be full. + assert_eq!(capacity, map.len()); + assert_eq!(capacity, map.capacity()); + + // Alright, make it grow. + map.insert(capacity, ()); + assert!( + capacity < map.capacity(), + "failed: {capacity} < {}", + map.capacity() + ); + } +} diff --git a/deps/crates/vendor/hashbrown/src/raw.rs b/deps/crates/vendor/hashbrown/src/raw.rs new file mode 100644 index 00000000000000..39f50ef7890f71 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/raw.rs @@ -0,0 +1,4630 @@ +use crate::TryReserveError; +use crate::control::{BitMaskIter, Group, Tag, TagSliceExt}; +use crate::scopeguard::{ScopeGuard, guard}; +use crate::util::{invalid_mut, likely, unlikely}; +use core::array; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ptr; +use core::ptr::NonNull; +use core::slice; +use stdalloc::alloc::{Layout, handle_alloc_error}; + +#[cfg(test)] +use crate::alloc::AllocError; +use crate::alloc::{Allocator, Global, do_alloc}; + +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + unsafe { to.offset_from(from) as usize } +} + +/// Whether memory allocation errors should return an error or abort. +#[derive(Copy, Clone)] +enum Fallibility { + Fallible, + Infallible, +} + +impl Fallibility { + /// Error to return on capacity overflow. + #[cfg_attr(feature = "inline-more", inline)] + fn capacity_overflow(self) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::CapacityOverflow, + Fallibility::Infallible => panic!("Hash table capacity overflow"), + } + } + + /// Error to return on allocation error. + #[cfg_attr(feature = "inline-more", inline)] + fn alloc_err(self, layout: Layout) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::AllocError { layout }, + Fallibility::Infallible => handle_alloc_error(layout), + } + } +} + +trait SizedTypeProperties: Sized { + const IS_ZERO_SIZED: bool = mem::size_of::() == 0; + const NEEDS_DROP: bool = mem::needs_drop::(); +} + +impl SizedTypeProperties for T {} + +/// Primary hash function, used to select the initial bucket to probe from. +#[inline] +#[expect(clippy::cast_possible_truncation)] +fn h1(hash: u64) -> usize { + // On 32-bit platforms we simply ignore the higher hash bits. + hash as usize +} + +/// Probe sequence based on triangular numbers, which is guaranteed (since our +/// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// +#[derive(Clone)] +struct ProbeSeq { + pos: usize, + stride: usize, +} + +impl ProbeSeq { + #[inline] + fn move_next(&mut self, bucket_mask: usize) { + // We should have found an empty bucket by now and ended the probe. + debug_assert!( + self.stride <= bucket_mask, + "Went past end of probe sequence" + ); + + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= bucket_mask; + } +} + +/// Returns the number of buckets needed to hold the given number of items, +/// taking the maximum load factor into account. +/// +/// Returns `None` if an overflow occurs. +/// +/// This ensures that `buckets * table_layout.size >= table_layout.ctrl_align`. +// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258 +#[cfg_attr(target_os = "emscripten", inline(never))] +#[cfg_attr(not(target_os = "emscripten"), inline)] +fn capacity_to_buckets(cap: usize, table_layout: TableLayout) -> Option { + debug_assert_ne!(cap, 0); + + // For small tables we require at least 1 empty bucket so that lookups are + // guaranteed to terminate if an element doesn't exist in the table. + if cap < 15 { + // Consider a small TableLayout like { size: 1, ctrl_align: 16 } on a + // platform with Group::WIDTH of 16 (like x86_64 with SSE2). For small + // bucket sizes, this ends up wasting quite a few bytes just to pad to + // the relatively larger ctrl_align: + // + // | capacity | buckets | bytes allocated | bytes per item | + // | -------- | ------- | --------------- | -------------- | + // | 3 | 4 | 36 | (Yikes!) 12.0 | + // | 7 | 8 | 40 | (Poor) 5.7 | + // | 14 | 16 | 48 | 3.4 | + // | 28 | 32 | 80 | 3.3 | + // + // In general, buckets * table_layout.size >= table_layout.ctrl_align + // must be true to avoid these edges. This is implemented by adjusting + // the minimum capacity upwards for small items. This code only needs + // to handle ctrl_align which are less than or equal to Group::WIDTH, + // because valid layout sizes are always a multiple of the alignment, + // so anything with alignment over the Group::WIDTH won't hit this edge + // case. + + // This is brittle, e.g. if we ever add 32 byte groups, it will select + // 3 regardless of the table_layout.size. + let min_cap = match (Group::WIDTH, table_layout.size) { + (16, 0..=1) => 14, + (16, 2..=3) | (8, 0..=1) => 7, + _ => 3, + }; + let cap = min_cap.max(cap); + // We don't bother with a table size of 2 buckets since that can only + // hold a single element. Instead, we skip directly to a 4 bucket table + // which can hold 3 elements. + let buckets = if cap < 4 { + 4 + } else if cap < 8 { + 8 + } else { + 16 + }; + ensure_bucket_bytes_at_least_ctrl_align(table_layout, buckets); + return Some(buckets); + } + + // Otherwise require 1/8 buckets to be empty (87.5% load) + // + // Be careful when modifying this, calculate_layout relies on the + // overflow check here. + let adjusted_cap = cap.checked_mul(8)? / 7; + + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous division). + let buckets = adjusted_cap.next_power_of_two(); + ensure_bucket_bytes_at_least_ctrl_align(table_layout, buckets); + Some(buckets) +} + +// `maximum_buckets_in` relies on the property that for non-ZST `T`, any +// chosen `buckets` will satisfy `buckets * table_layout.size >= +// table_layout.ctrl_align`, so `calculate_layout_for` does not need to add +// extra padding beyond `table_layout.size * buckets`. If small-table bucket +// selection or growth policy changes, revisit `maximum_buckets_in`. +#[inline] +fn ensure_bucket_bytes_at_least_ctrl_align(table_layout: TableLayout, buckets: usize) { + if table_layout.size != 0 { + let prod = table_layout.size.saturating_mul(buckets); + debug_assert!(prod >= table_layout.ctrl_align); + } +} + +/// Returns the maximum effective capacity for the given bucket mask, taking +/// the maximum load factor into account. +#[inline] +fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { + if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. + bucket_mask + } else { + // For larger tables we reserve 12.5% of the slots as empty. + ((bucket_mask + 1) / 8) * 7 + } +} + +/// Helper which allows the max calculation for `ctrl_align` to be statically computed for each `T` +/// while keeping the rest of `calculate_layout_for` independent of `T` +#[derive(Copy, Clone)] +struct TableLayout { + size: usize, + ctrl_align: usize, +} + +impl TableLayout { + #[inline] + const fn new() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size(), + ctrl_align: if layout.align() > Group::WIDTH { + layout.align() + } else { + Group::WIDTH + }, + } + } + + #[inline] + fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> { + debug_assert!(buckets.is_power_of_two()); + + let TableLayout { size, ctrl_align } = self; + // Manual layout calculation since Layout methods are not yet stable. + let ctrl_offset = + size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); + let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + + // We need an additional check to ensure that the allocation doesn't + // exceed `isize::MAX` (https://github.com/rust-lang/rust/pull/95295). + if len > isize::MAX as usize - (ctrl_align - 1) { + return None; + } + + Some(( + unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, + ctrl_offset, + )) + } +} + +/// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. +pub(crate) struct Bucket { + // Actually it is pointer to next element than element itself + // this is needed to maintain pointer arithmetic invariants + // keeping direct pointer to element introduces difficulty. + // Using `NonNull` for variance and niche layout + ptr: NonNull, +} + +// This Send impl is needed for rayon support. This is safe since Bucket is +// never exposed in a public API. +unsafe impl Send for Bucket {} + +impl Clone for Bucket { + #[inline] + fn clone(&self) -> Self { + Self { ptr: self.ptr } + } +} + +impl Bucket { + /// Creates a [`Bucket`] that contain pointer to the data. + /// The pointer calculation is performed by calculating the + /// offset from given `base` pointer (convenience for + /// `base.as_ptr().sub(index)`). + /// + /// `index` is in units of `T`; e.g., an `index` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// If the `T` is a ZST, then we instead track the index of the element + /// in the table so that `erase` works properly (return + /// `NonNull::new_unchecked((index + 1) as *mut T)`) + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and the safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for the [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * the `base` pointer must not be `dangling` and must points to the + /// end of the first `value element` from the `data part` of the table, i.e. + /// must be the pointer that returned by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::num_buckets`] or [`RawTableInner::num_buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::num_buckets`] or [`RawTableInner::num_buckets`]. + #[inline] + unsafe fn from_base_index(base: NonNull, index: usize) -> Self { + // If mem::size_of::() != 0 then return a pointer to an `element` in + // the data part of the table (we start counting from "0", so that + // in the expression T[last], the "last" index actually one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"): + // + // `from_base_index(base, 1).as_ptr()` returns a pointer that + // points here in the data part of the table + // (to the start of T1) + // | + // | `base: NonNull` must point here + // | (to the end of T0 or to the start of C0) + // v v + // [Padding], Tlast, ..., |T1|, T0, |C0, C1, ..., Clast + // ^ + // `from_base_index(base, 1)` returns a pointer + // that points here in the data part of the table + // (to the end of T1) + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes + // or metadata for data. + let ptr = if T::IS_ZERO_SIZED { + // won't overflow because index must be less than length (bucket_mask) + // and bucket_mask is guaranteed to be less than `isize::MAX` + // (see TableLayout::calculate_layout_for method) + invalid_mut(index + 1) + } else { + unsafe { base.as_ptr().sub(index) } + }; + Self { + ptr: unsafe { NonNull::new_unchecked(ptr) }, + } + } + + /// Calculates the index of a [`Bucket`] as distance between two pointers + /// (convenience for `base.as_ptr().offset_from(self.ptr.as_ptr()) as usize`). + /// The returned value is in units of T: the distance in bytes divided by + /// [`core::mem::size_of::()`]. + /// + /// If the `T` is a ZST, then we return the index of the element in + /// the table so that `erase` works properly (return `self.ptr.as_ptr() as usize - 1`). + /// + /// This function is the inverse of [`from_base_index`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*const T>::offset_from`] method of `*const T`. + /// + /// Thus, in order to uphold the safety contracts for [`<*const T>::offset_from`] + /// method, as well as for the correct logic of the work of this crate, the + /// following rules are necessary and sufficient: + /// + /// * `base` contained pointer must not be `dangling` and must point to the + /// end of the first `element` from the `data part` of the table, i.e. + /// must be a pointer that returns by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `self` also must not contain dangling pointer; + /// + /// * both `self` and `base` must be created from the same [`RawTable`] + /// (or [`RawTableInner`]). + /// + /// If `mem::size_of::() == 0`, this function is always safe. + #[inline] + unsafe fn to_base_index(&self, base: NonNull) -> usize { + // If mem::size_of::() != 0 then return an index under which we used to store the + // `element` in the data part of the table (we start counting from "0", so + // that in the expression T[last], the "last" index actually is one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"). + // For example for 5th element in table calculation is performed like this: + // + // mem::size_of::() + // | + // | `self = from_base_index(base, 5)` that returns pointer + // | that points here in the data part of the table + // | (to the end of T5) + // | | `base: NonNull` must point here + // v | (to the end of T0 or to the start of C0) + // /???\ v v + // [Padding], Tlast, ..., |T10|, ..., T5|, T4, T3, T2, T1, T0, |C0, C1, C2, C3, C4, C5, ..., C10, ..., Clast + // \__________ __________/ + // \/ + // `bucket.to_base_index(base)` = 5 + // (base.as_ptr() as usize - self.ptr.as_ptr() as usize) / mem::size_of::() + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes or metadata for data. + if T::IS_ZERO_SIZED { + // this can not be UB + self.ptr.as_ptr() as usize - 1 + } else { + unsafe { offset_from(base.as_ptr(), self.ptr.as_ptr()) } + } + } + + /// Acquires the underlying raw pointer `*mut T` to `data`. + /// + /// # Note + /// + /// If `T` is not [`Copy`], do not use `*mut T` methods that can cause calling the + /// destructor of `T` (for example the [`<*mut T>::drop_in_place`] method), because + /// for properly dropping the data we also need to clear `data` control bytes. If we + /// drop data, but do not clear `data control byte` it leads to double drop when + /// [`RawTable`] goes out of scope. + /// + /// If you modify an already initialized `value`, so [`Hash`] and [`Eq`] on the new + /// `T` value and its borrowed form *must* match those for the old `T` value, as the map + /// will not re-evaluate where the new value should go, meaning the value may become + /// "lost" if their location does not reflect their state. + #[inline] + pub(crate) fn as_ptr(&self) -> *mut T { + if T::IS_ZERO_SIZED { + // Just return an arbitrary ZST pointer which is properly aligned + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) + } else { + unsafe { self.ptr.as_ptr().sub(1) } + } + } + + /// Acquires the underlying non-null pointer `*mut T` to `data`. + #[inline] + fn as_non_null(&self) -> NonNull { + // SAFETY: `self.ptr` is already a `NonNull` + unsafe { NonNull::new_unchecked(self.as_ptr()) } + } + + /// Create a new [`Bucket`] that is offset from the `self` by the given + /// `offset`. The pointer calculation is performed by calculating the + /// offset from `self` pointer (convenience for `self.ptr.as_ptr().sub(offset)`). + /// This function is used for iterators. + /// + /// `offset` is in units of `T`; e.g., a `offset` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * `self` contained pointer must not be `dangling`; + /// + /// * `self.to_base_index() + offset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + offset) <= RawTableInner.bucket_mask` or, in other + /// words, `self.to_base_index() + offset + 1` must be no greater than the number returned + /// by the function [`RawTable::num_buckets`] or [`RawTableInner::num_buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `self.to_base_index() + offset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + offset) <= RawTableInner.bucket_mask` or, in other words, + /// `self.to_base_index() + offset + 1` must be no greater than the number returned by the + /// function [`RawTable::num_buckets`] or [`RawTableInner::num_buckets`]. + #[inline] + unsafe fn next_n(&self, offset: usize) -> Self { + let ptr = if T::IS_ZERO_SIZED { + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) + } else { + unsafe { self.ptr.as_ptr().sub(offset) } + }; + Self { + ptr: unsafe { NonNull::new_unchecked(ptr) }, + } + } + + /// Executes the destructor (if any) of the pointed-to `data`. + /// + /// # Safety + /// + /// See [`ptr::drop_in_place`] for safety concerns. + /// + /// You should use [`RawTable::erase`] instead of this function, + /// or be careful with calling this function directly, because for + /// properly dropping the data we need also clear `data` control bytes. + /// If we drop data, but do not erase `data control byte` it leads to + /// double drop when [`RawTable`] goes out of scope. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn drop(&self) { + unsafe { + self.as_ptr().drop_in_place(); + } + } + + /// Reads the `value` from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// # Safety + /// + /// See [`ptr::read`] for safety concerns. + /// + /// You should use [`RawTable::remove`] instead of this function, + /// or be careful with calling this function directly, because compiler + /// calls its destructor when the read `value` goes out of scope. It + /// can cause double dropping when [`RawTable`] goes out of scope, + /// because of not erased `data control byte`. + #[inline] + pub(crate) unsafe fn read(&self) -> T { + unsafe { self.as_ptr().read() } + } + + /// Overwrites a memory location with the given `value` without reading + /// or dropping the old value (like [`ptr::write`] function). + /// + /// # Safety + /// + /// See [`ptr::write`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + #[inline] + pub(crate) unsafe fn write(&self, val: T) { + unsafe { + self.as_ptr().write(val); + } + } + + /// Returns a shared immutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_ref`] for safety concerns. + #[inline] + pub(crate) unsafe fn as_ref<'a>(&self) -> &'a T { + unsafe { &*self.as_ptr() } + } + + /// Returns a unique mutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_mut`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + #[inline] + pub(crate) unsafe fn as_mut<'a>(&self) -> &'a mut T { + unsafe { &mut *self.as_ptr() } + } +} + +/// A raw hash table with an unsafe API. +pub(crate) struct RawTable { + table: RawTableInner, + alloc: A, + // Tell dropck that we own instances of T. + marker: PhantomData, +} + +/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless +/// of how many different key-value types are used. +struct RawTableInner { + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. + bucket_mask: usize, + + // [Padding], T_n, ..., T1, T0, C0, C1, ... + // ^ points here + ctrl: NonNull, + + // Number of elements that can be inserted before we need to grow the table + growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub(crate) const fn new() -> Self { + Self { + table: RawTableInner::NEW, + alloc: Global, + marker: PhantomData, + } + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } +} + +impl RawTable { + const TABLE_LAYOUT: TableLayout = TableLayout::new::(); + + /// Creates a new empty hash table without allocating any memory, using the + /// given allocator. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub(crate) const fn new_in(alloc: A) -> Self { + Self { + table: RawTableInner::NEW, + alloc, + marker: PhantomData, + } + } + + /// Allocates a new hash table with the given number of buckets. + /// + /// The control bytes are left uninitialized. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + Ok(Self { + table: unsafe { + RawTableInner::new_uninitialized(&alloc, Self::TABLE_LAYOUT, buckets, fallibility) + }?, + alloc, + marker: PhantomData, + }) + } + + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + table: RawTableInner::with_capacity(&alloc, Self::TABLE_LAYOUT, capacity), + alloc, + marker: PhantomData, + } + } + + /// Returns a reference to the underlying allocator. + #[inline] + pub(crate) fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub(crate) fn data_end(&self) -> NonNull { + // `self.table.ctrl.cast()` returns pointer that + // points here (to the end of `T0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTable::num_buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + self.table.ctrl.cast() + } + + /// Returns pointer to start of data table. + #[inline] + #[cfg(feature = "nightly")] + pub(crate) unsafe fn data_start(&self) -> NonNull { + unsafe { NonNull::new_unchecked(self.data_end().as_ptr().wrapping_sub(self.num_buckets())) } + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub(crate) fn allocation_size(&self) -> usize { + // SAFETY: We use the same `table_layout` that was used to allocate + // this table. + unsafe { self.table.allocation_size_or_zero(Self::TABLE_LAYOUT) } + } + + /// Returns the index of a bucket from a `Bucket`. + #[inline] + pub(crate) unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { + unsafe { bucket.to_base_index(self.data_end()) } + } + + /// Returns a pointer to an element in the table. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the caller of this function must observe the + /// following safety rules: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTable::num_buckets`] + /// function, i.e. `(index + 1) <= self.num_buckets()`. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::num_buckets`] function, i.e. + /// `(index + 1) <= self.num_buckets()`. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub(crate) unsafe fn bucket(&self, index: usize) -> Bucket { + // If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + // (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + // the "buckets" number of our `RawTable`, i.e. "n = RawTable::num_buckets() - 1"): + // + // `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + // part of the `RawTable`, i.e. to the start of T3 (see `Bucket::as_ptr`) + // | + // | `base = self.data_end()` points here + // | (to the start of CT0 or to the end of T0) + // v v + // [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + // ^ \__________ __________/ + // `table.bucket(3)` returns a pointer that points \/ + // here in the `data` part of the `RawTable` (to additional control bytes + // the end of T3) `m = Group::WIDTH - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`; + // CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + // the heap works properly, even if the result of `h1(hash) & self.table.bucket_mask` + // is equal to `self.table.bucket_mask`). See also `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.table.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + // of buckets is a power of two, and `self.table.bucket_mask = self.num_buckets() - 1`. + debug_assert_ne!(self.table.bucket_mask, 0); + debug_assert!(index < self.num_buckets()); + unsafe { Bucket::from_base_index(self.data_end(), index) } + } + + /// Erases an element from the table without dropping it. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn erase_no_drop(&mut self, item: &Bucket) { + unsafe { + let index = self.bucket_index(item); + self.table.erase(index); + } + } + + /// Erases an element from the table, dropping it in place. + #[cfg_attr(feature = "inline-more", inline)] + #[expect(clippy::needless_pass_by_value)] + pub(crate) unsafe fn erase(&mut self, item: Bucket) { + unsafe { + // Erase the element from the table first since drop might panic. + self.erase_no_drop(&item); + item.drop(); + } + } + + /// Removes an element from the table, returning it. + /// + /// This also returns an index to the newly free bucket. + #[cfg_attr(feature = "inline-more", inline)] + #[expect(clippy::needless_pass_by_value)] + pub(crate) unsafe fn remove(&mut self, item: Bucket) -> (T, usize) { + unsafe { + self.erase_no_drop(&item); + (item.read(), self.bucket_index(&item)) + } + } + + /// Removes an element from the table, returning it. + /// + /// This also returns an index to the newly free bucket + /// and the former `Tag` for that bucket. + #[cfg_attr(feature = "inline-more", inline)] + #[expect(clippy::needless_pass_by_value)] + pub(crate) unsafe fn remove_tagged(&mut self, item: Bucket) -> (T, usize, Tag) { + unsafe { + let index = self.bucket_index(&item); + let tag = *self.table.ctrl(index); + self.table.erase(index); + (item.read(), index, tag) + } + } + + /// Finds and removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { self.remove(bucket).0 }), + None => None, + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn clear_no_drop(&mut self) { + self.table.clear_no_drop(); + } + + /// Removes all elements from the table without freeing the backing memory. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn clear(&mut self) { + if self.is_empty() { + // Special case empty table to avoid surprising O(capacity) time. + return; + } + // Ensure that the table is reset even if one of the drops panic + let mut self_ = guard(self, |self_| self_.clear_no_drop()); + unsafe { + // SAFETY: ScopeGuard sets to zero the `items` field of the table + // even in case of panic during the dropping of the elements so + // that there will be no double drop of the elements. + self_.table.drop_elements::(); + } + } + + /// Shrinks the table to fit `max(self.len(), min_size)` elements. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. + let min_size = usize::max(self.table.items, min_size); + if min_size == 0 { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let Some(min_buckets) = capacity_to_buckets(min_size, Self::TABLE_LAYOUT) else { + return; + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets < self.num_buckets() { + // Fast path if the table is empty + if self.table.items == 0 { + let new_inner = + RawTableInner::with_capacity(&self.alloc, Self::TABLE_LAYOUT, min_size); + let mut old_inner = mem::replace(&mut self.table, new_inner); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + // SAFETY: + // 1. We know for sure that `min_size >= self.table.items`. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + let result = unsafe { self.resize(min_size, hasher, Fallibility::Infallible) }; + + // SAFETY: The result of calling the `resize` function cannot be an error + // because `fallibility == Fallibility::Infallible. + unsafe { result.unwrap_unchecked() }; + } + } + } + + /// Ensures that at least `additional` items can be inserted into the table + /// without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + if unlikely(additional > self.table.growth_left) { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + let result = + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Infallible) }; + + // SAFETY: All allocation errors will be caught inside `RawTableInner::reserve_rehash`. + unsafe { result.unwrap_unchecked() }; + } + } + + /// Tries to ensure that at least `additional` items can be inserted into + /// the table without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + if additional > self.table.growth_left { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Fallible) } + } else { + Ok(()) + } + } + + /// Out-of-line slow path for `reserve` and `try_reserve`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cold] + #[inline(never)] + unsafe fn reserve_rehash( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + unsafe { + // SAFETY: + // 1. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 2. The `drop` function is the actual drop function of the elements stored in + // the table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.reserve_rehash_inner( + &self.alloc, + additional, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + if T::NEEDS_DROP { + Some(|ptr| ptr::drop_in_place(ptr.cast::())) + } else { + None + }, + ) + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// The caller of this function must ensure that `capacity >= self.table.items` + /// otherwise: + /// + /// * If `self.table.items != 0`, calling of this function with `capacity` + /// equal to 0 (`capacity == 0`) results in [`undefined behavior`]. + /// + /// * If `self.table.items > capacity_to_buckets(capacity, Self::TABLE_LAYOUT)` + /// calling this function are never return (will loop infinitely). + /// + /// See [`RawTableInner::find_insert_index`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn resize( + &mut self, + capacity: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + // SAFETY: + // 1. The caller of this function guarantees that `capacity >= self.table.items`. + // 2. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + unsafe { + self.table.resize_inner( + &self.alloc, + capacity, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + ) + } + } + + /// Inserts a new element into the table, and returns its raw bucket. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose `RawTable::new_uninitialized` in a public API. + // + // 2. We reserve additional space (if necessary) right after calling this function. + let mut index = self.table.find_insert_index(hash); + + // We can avoid growing the table once we have reached our load factor if we are replacing + // a tombstone. This works since the number of EMPTY slots does not change in this case. + // + // SAFETY: The function is guaranteed to return an index in the range `0..=self.num_buckets()`. + let old_ctrl = *self.table.ctrl(index); + if unlikely(self.table.growth_left == 0 && old_ctrl.special_is_empty()) { + self.reserve(1, hasher); + // SAFETY: We know for sure that `RawTableInner` has control bytes + // initialized and that there is extra space in the table. + index = self.table.find_insert_index(hash); + } + + self.insert_at_index(hash, index, value) + } + } + + /// Inserts a new element into the table, and returns a mutable reference to it. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn insert_entry( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> &mut T { + unsafe { self.insert(hash, value, hasher).as_mut() } + } + + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rustc-internal-api")] + pub(crate) unsafe fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { + unsafe { + let (index, old_ctrl) = self.table.prepare_insert_index(hash); + let bucket = self.table.bucket(index); + + // If we are replacing a DELETED entry then we don't need to update + // the load counter. + self.table.growth_left -= old_ctrl.special_is_empty() as usize; + + bucket.write(value); + self.table.items += 1; + bucket + } + } + + /// Temporarily removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns tag for bucket if the bucket is emptied out. + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> Option + where + F: FnOnce(T) -> Option, + { + unsafe { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.table.ctrl(index); + debug_assert!(self.is_bucket_full(index)); + let old_growth_left = self.table.growth_left; + let item = self.remove(bucket).0; + if let Some(new_item) = f(item) { + self.table.growth_left = old_growth_left; + self.table.set_ctrl(index, old_ctrl); + self.table.items += 1; + self.bucket(index).write(new_item); + None + } else { + Some(old_ctrl) + } + } + } + + /// Searches for an element in the table. If the element is not found, + /// returns `Err` with the position of a slot where an element with the + /// same hash could be inserted. + /// + /// This function may resize the table if additional space is required for + /// inserting an element. + #[inline] + pub(crate) fn find_or_find_insert_index( + &mut self, + hash: u64, + mut eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Result, usize> { + self.reserve(1, hasher); + + unsafe { + // SAFETY: + // 1. We know for sure that there is at least one empty `bucket` in the table. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since we will + // never expose `RawTable::new_uninitialized` in a public API. + // 3. The `find_or_find_insert_index_inner` function returns the `index` of only the full bucket, + // which is in the range `0..self.num_buckets()` (since there is at least one empty `bucket` in + // the table), so calling `self.bucket(index)` and `Bucket::as_ref` is safe. + match self + .table + .find_or_find_insert_index_inner(hash, &mut |index| eq(self.bucket(index).as_ref())) + { + // SAFETY: See explanation above. + Ok(index) => Ok(self.bucket(index)), + Err(index) => Err(index), + } + } + } + + /// Inserts a new element into the table at the given index with the given hash, + /// and returns its raw bucket. + /// + /// # Safety + /// + /// `index` must point to a slot previously returned by + /// `find_or_find_insert_index`, and no mutation of the table must have + /// occurred since that call. + #[inline] + pub(crate) unsafe fn insert_at_index( + &mut self, + hash: u64, + index: usize, + value: T, + ) -> Bucket { + unsafe { self.insert_tagged_at_index(Tag::full(hash), index, value) } + } + + /// Inserts a new element into the table at the given index with the given tag, + /// and returns its raw bucket. + /// + /// # Safety + /// + /// `index` must point to a slot previously returned by + /// `find_or_find_insert_index`, and no mutation of the table must have + /// occurred since that call. + #[inline] + pub(crate) unsafe fn insert_tagged_at_index( + &mut self, + tag: Tag, + index: usize, + value: T, + ) -> Bucket { + unsafe { + let old_ctrl = *self.table.ctrl(index); + self.table.record_item_insert_at(index, old_ctrl, tag); + + let bucket = self.bucket(index); + bucket.write(value); + bucket + } + } + + /// Searches for an element in the table. + #[inline] + pub(crate) fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since we + // will never expose `RawTable::new_uninitialized` in a public API. + // 1. The `find_inner` function returns the `index` of only the full bucket, which is in + // the range `0..self.num_buckets()`, so calling `self.bucket(index)` and `Bucket::as_ref` + // is safe. + let result = self + .table + .find_inner(hash, &mut |index| eq(self.bucket(index).as_ref())); + + // Avoid `Option::map` because it bloats LLVM IR. + match result { + // SAFETY: See explanation above. + Some(index) => Some(self.bucket(index)), + None => None, + } + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub(crate) fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + /// Gets a mutable reference to an element in the table. + #[inline] + pub(crate) fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + /// Gets a reference to an element in the table at the given bucket index. + #[inline] + pub(crate) fn get_bucket(&self, index: usize) -> Option<&T> { + unsafe { + if index < self.num_buckets() && self.is_bucket_full(index) { + Some(self.bucket(index).as_ref()) + } else { + None + } + } + } + + /// Gets a mutable reference to an element in the table at the given bucket index. + #[inline] + pub(crate) fn get_bucket_mut(&mut self, index: usize) -> Option<&mut T> { + unsafe { + if index < self.num_buckets() && self.is_bucket_full(index) { + Some(self.bucket(index).as_mut()) + } else { + None + } + } + } + + /// Returns a pointer to an element in the table, but only after verifying that + /// the index is in-bounds and the bucket is occupied. + #[inline] + pub(crate) fn checked_bucket(&self, index: usize) -> Option> { + unsafe { + if index < self.num_buckets() && self.is_bucket_full(index) { + Some(self.bucket(index)) + } else { + None + } + } + } + + /// Attempts to get mutable references to `N` entries in the table at once. + /// + /// Returns an array of length `N` with the results of each query. + /// + /// At most one mutable reference will be returned to any entry. `None` will be returned if any + /// of the hashes are duplicates. `None` will be returned if the hash is not found. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + pub(crate) fn get_disjoint_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + unsafe { + let ptrs = self.get_disjoint_mut_pointers(hashes, eq); + + for (i, cur) in ptrs.iter().enumerate() { + if cur.is_some() && ptrs[..i].contains(cur) { + panic!("duplicate keys found"); + } + } + // All bucket are distinct from all previous buckets so we're clear to return the result + // of the lookup. + + ptrs.map(|ptr| ptr.map(|mut ptr| ptr.as_mut())) + } + } + + pub(crate) unsafe fn get_disjoint_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + let ptrs = unsafe { self.get_disjoint_mut_pointers(hashes, eq) }; + ptrs.map(|ptr| ptr.map(|mut ptr| unsafe { ptr.as_mut() })) + } + + unsafe fn get_disjoint_mut_pointers( + &mut self, + hashes: [u64; N], + mut eq: impl FnMut(usize, &T) -> bool, + ) -> [Option>; N] { + array::from_fn(|i| { + self.find(hashes[i], |k| eq(i, k)) + .map(|cur| cur.as_non_null()) + }) + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the table might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + #[inline] + pub(crate) fn capacity(&self) -> usize { + self.table.items + self.table.growth_left + } + + /// Returns the number of elements in the table. + #[inline] + pub(crate) fn len(&self) -> usize { + self.table.items + } + + /// Returns `true` if the table contains no elements. + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of buckets in the table. + #[inline] + pub(crate) fn num_buckets(&self) -> usize { + self.table.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + pub(crate) unsafe fn is_bucket_full(&self, index: usize) -> bool { + unsafe { self.table.is_bucket_full(index) } + } + + /// Returns an iterator over every element in the table. It is up to + /// the caller to ensure that the `RawTable` outlives the `RawIter`. + /// Because we cannot make the `next` method unsafe on the `RawIter` + /// struct, we have to make the `iter` method unsafe. + #[inline] + pub(crate) unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. The caller must uphold the safety contract for `iter` method. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.table.iter() } + } + + /// Returns an iterator over occupied buckets that could match a given hash. + /// + /// `RawTable` only stores 7 bits of the hash value, so this iterator may + /// return items that have a hash value different than the one provided. You + /// should always validate the returned values before using them. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHash`. Because we cannot make the `next` method unsafe on the + /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn iter_hash(&self, hash: u64) -> RawIterHash { + unsafe { RawIterHash::new(self, hash) } + } + + /// Returns an iterator over occupied bucket indices that could match a given hash. + /// + /// `RawTable` only stores 7 bits of the hash value, so this iterator may + /// return items that have a hash value different than the one provided. You + /// should always validate the returned values before using them. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHashIndices`. Because we cannot make the `next` method unsafe on the + /// `RawIterHashIndices` struct, we have to make the `iter_hash_buckets` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn iter_hash_buckets(&self, hash: u64) -> RawIterHashIndices { + unsafe { RawIterHashIndices::new(&self.table, hash) } + } + + /// Returns an iterator over full buckets indices in the table. + /// + /// See [`RawTableInner::full_buckets_indices`] for safety conditions. + #[inline(always)] + pub(crate) unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + unsafe { self.table.full_buckets_indices() } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn drain(&mut self) -> RawDrain<'_, T, A> { + unsafe { + let iter = self.iter(); + self.drain_iter_from(iter) + } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn drain_iter_from(&mut self, iter: RawIter) -> RawDrain<'_, T, A> { + debug_assert_eq!(iter.len(), self.len()); + RawDrain { + iter, + table: mem::replace(&mut self.table, RawTableInner::NEW), + orig_table: NonNull::from(&mut self.table), + marker: PhantomData, + } + } + + /// Returns an iterator which consumes all elements from the table. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + pub(crate) unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { + debug_assert_eq!(iter.len(), self.len()); + + let allocation = self.into_allocation(); + RawIntoIter { + iter, + allocation, + marker: PhantomData, + } + } + + /// Converts the table into a raw allocation. The contents of the table + /// should be dropped using a `RawIter` before freeing the allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout, A)> { + let alloc = if self.table.is_empty_singleton() { + None + } else { + let (layout, ctrl_offset) = { + let option = Self::TABLE_LAYOUT.calculate_layout_for(self.table.num_buckets()); + unsafe { option.unwrap_unchecked() } + }; + Some(( + unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset).cast()) }, + layout, + unsafe { ptr::read(&raw const self.alloc) }, + )) + }; + mem::forget(self); + alloc + } +} + +unsafe impl Send for RawTable +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawTable +where + T: Sync, + A: Sync, +{ +} + +impl RawTableInner { + const NEW: Self = RawTableInner::new(); + + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never accessed + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + const fn new() -> Self { + Self { + // Be careful to cast the entire slice to a raw pointer. + ctrl: unsafe { + NonNull::new_unchecked(Group::static_empty().as_ptr().cast_mut().cast()) + }, + bucket_mask: 0, + items: 0, + growth_left: 0, + } + } +} + +/// Find the previous power of 2. If it's already a power of 2, it's unchanged. +/// Passing zero is undefined behavior. +pub(crate) fn prev_pow2(z: usize) -> usize { + let shift = mem::size_of::() * 8 - 1; + 1 << (shift - (z.leading_zeros() as usize)) +} + +/// Finds the largest number of buckets that can fit in `allocation_size` +/// provided the given TableLayout. +/// +/// This relies on some invariants of `capacity_to_buckets`, so only feed in +/// an `allocation_size` calculated from `capacity_to_buckets`. +fn maximum_buckets_in( + allocation_size: usize, + table_layout: TableLayout, + group_width: usize, +) -> usize { + // Given an equation like: + // z >= x * y + x + g + // x can be maximized by doing: + // x = (z - g) / (y + 1) + // If you squint: + // x is the number of buckets + // y is the table_layout.size + // z is the size of the allocation + // g is the group width + // But this is ignoring the padding needed for ctrl_align. + // If we remember these restrictions: + // x is always a power of 2 + // Layout size for T must always be a multiple of T + // Then the alignment can be ignored if we add the constraint: + // x * y >= table_layout.ctrl_align + // This is taken care of by `capacity_to_buckets`. + // It may be helpful to understand this if you remember that: + // ctrl_offset = align(x * y, ctrl_align) + let x = (allocation_size - group_width) / (table_layout.size + 1); + prev_pow2(x) +} + +impl RawTableInner { + /// Allocates a new [`RawTableInner`] with the given number of buckets. + /// The control bytes and buckets are left uninitialized. + /// + /// # Safety + /// + /// The caller of this function must ensure that the `buckets` is power of two + /// and also initialize all control bytes of the length `self.bucket_mask + 1 + + /// Group::WIDTH` with the [`Tag::EMPTY`] bytes. + /// + /// See also [`Allocator`] API for other safety concerns. + /// + /// [`Allocator`]: stdalloc::alloc::Allocator + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: &A, + table_layout: TableLayout, + mut buckets: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + debug_assert!(buckets.is_power_of_two()); + + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let Some((layout, mut ctrl_offset)) = table_layout.calculate_layout_for(buckets) else { + return Err(fallibility.capacity_overflow()); + }; + + let ptr: NonNull = match do_alloc(alloc, layout) { + Ok(block) => { + // The allocator can't return a value smaller than was + // requested, so this can be != instead of >=. + if block.len() != layout.size() { + // Utilize over-sized allocations. + let x = maximum_buckets_in(block.len(), table_layout, Group::WIDTH); + debug_assert!(x >= buckets); + // Calculate the new ctrl_offset. + let (oversized_layout, oversized_ctrl_offset) = { + let option = table_layout.calculate_layout_for(x); + unsafe { option.unwrap_unchecked() } + }; + debug_assert!(oversized_layout.size() <= block.len()); + debug_assert!(oversized_ctrl_offset >= ctrl_offset); + ctrl_offset = oversized_ctrl_offset; + buckets = x; + } + + block.cast() + } + Err(_) => return Err(fallibility.alloc_err(layout)), + }; + + // SAFETY: null pointer will be caught in above check + let ctrl = unsafe { NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)) }; + Ok(Self { + ctrl, + bucket_mask: buckets - 1, + items: 0, + growth_left: bucket_mask_to_capacity(buckets - 1), + }) + } + + /// Attempts to allocate a new [`RawTableInner`] with at least enough + /// capacity for inserting the given number of elements without reallocating. + /// + /// All the control bytes are initialized with the [`Tag::EMPTY`] bytes. + #[inline] + fn fallible_with_capacity( + alloc: &A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + if capacity == 0 { + Ok(Self::NEW) + } else { + // SAFETY: We checked that we could successfully allocate the new table, and then + // initialized all control bytes with the constant `Tag::EMPTY` byte. + unsafe { + let buckets = capacity_to_buckets(capacity, table_layout) + .ok_or_else(|| fallibility.capacity_overflow())?; + + let mut result = + Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + result.ctrl_slice().fill_empty(); + + Ok(result) + } + } + } + + /// Allocates a new [`RawTableInner`] with at least enough capacity for inserting + /// the given number of elements without reallocating. + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`fallible_with_capacity`] instead if you want to + /// handle memory allocation failure. + /// + /// All the control bytes are initialized with the [`Tag::EMPTY`] bytes. + /// + /// [`fallible_with_capacity`]: RawTableInner::fallible_with_capacity + /// [`abort`]: stdalloc::abort::handle_alloc_error + fn with_capacity(alloc: &A, table_layout: TableLayout, capacity: usize) -> Self + where + A: Allocator, + { + let result = + Self::fallible_with_capacity(alloc, table_layout, capacity, Fallibility::Infallible); + + // SAFETY: All allocation errors will be caught inside `RawTableInner::new_uninitialized`. + unsafe { result.unwrap_unchecked() } + } + + /// Fixes up an insertion index returned by the [`RawTableInner::find_insert_index_in_group`] method. + /// + /// In tables smaller than the group width (`self.num_buckets() < Group::WIDTH`), trailing control + /// bytes outside the range of the table are filled with [`Tag::EMPTY`] entries. These will unfortunately + /// trigger a match of [`RawTableInner::find_insert_index_in_group`] function. This is because + /// the `Some(bit)` returned by `group.match_empty_or_deleted().lowest_set_bit()` after masking + /// (`(probe_seq.pos + bit) & self.bucket_mask`) may point to a full bucket that is already occupied. + /// We detect this situation here and perform a second scan starting at the beginning of the table. + /// This second scan is guaranteed to find an empty slot (due to the load factor) before hitting the + /// trailing control bytes (containing [`Tag::EMPTY`] bytes). + /// + /// If this function is called correctly, it is guaranteed to return an index of an empty or + /// deleted bucket in the range `0..self.num_buckets()` (see `Warning` and `Safety`). + /// + /// # Warning + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise if the table is less than + /// the group width (`self.num_buckets() < Group::WIDTH`) this function returns an index outside of the + /// table indices range `0..self.num_buckets()` (`0..=self.bucket_mask`). Attempt to write data at that + /// index will cause immediate [`undefined behavior`]. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::ctrl`] method. + /// Thus, in order to uphold those safety contracts, as well as for the correct logic of the work + /// of this crate, the following rules are necessary and sufficient: + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise calling this + /// function results in [`undefined behavior`]. + /// + /// * This function must only be used on insertion indices found by [`RawTableInner::find_insert_index_in_group`] + /// (after the `find_insert_index_in_group` function, but before insertion into the table). + /// + /// * The `index` must not be greater than the `self.bucket_mask`, i.e. `(index + 1) <= self.num_buckets()` + /// (this one is provided by the [`RawTableInner::find_insert_index_in_group`] function). + /// + /// Calling this function with an index not provided by [`RawTableInner::find_insert_index_in_group`] + /// may result in [`undefined behavior`] even if the index satisfies the safety rules of the + /// [`RawTableInner::ctrl`] function (`index < self.bucket_mask + 1 + Group::WIDTH`). + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn fix_insert_index(&self, mut index: usize) -> usize { + // SAFETY: The caller of this function ensures that `index` is in the range `0..=self.bucket_mask`. + if unlikely(unsafe { self.is_bucket_full(index) }) { + debug_assert!(self.bucket_mask < Group::WIDTH); + // SAFETY: + // + // * Since the caller of this function ensures that the control bytes are properly + // initialized and `ptr = self.ctrl(0)` points to the start of the array of control + // bytes, therefore: `ctrl` is valid for reads, properly aligned to `Group::WIDTH` + // and points to the properly initialized control bytes (see also + // `TableLayout::calculate_layout_for` and `ptr::read`); + // + // * Because the caller of this function ensures that the index was provided by the + // `self.find_insert_index_in_group()` function, so for for tables larger than the + // group width (self.num_buckets() >= Group::WIDTH), we will never end up in the given + // branch, since `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_index_in_group` + // cannot return a full bucket index. For tables smaller than the group width, calling + // the `unwrap_unchecked` function is also safe, as the trailing control bytes outside + // the range of the table are filled with EMPTY bytes (and we know for sure that there + // is at least one FULL bucket), so this second scan either finds an empty slot (due to + // the load factor) or hits the trailing control bytes (containing EMPTY). + index = unsafe { + Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit() + .unwrap_unchecked() + }; + } + index + } + + /// Finds the position to insert something in a group. + /// + /// **This may have false positives and must be fixed up with `fix_insert_index` + /// before it's used.** + /// + /// The function is guaranteed to return the index of an empty or deleted [`Bucket`] + /// in the range `0..self.num_buckets()` (`0..=self.bucket_mask`). + #[inline] + fn find_insert_index_in_group(&self, group: &Group, probe_seq: &ProbeSeq) -> Option { + let bit = group.match_empty_or_deleted().lowest_set_bit(); + + if likely(bit.is_some()) { + // This is the same as `(probe_seq.pos + bit) % self.num_buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + Some((probe_seq.pos + bit.unwrap()) & self.bucket_mask) + } else { + None + } + } + + /// Searches for an element in the table, or a potential slot where that element could + /// be inserted (an empty or deleted [`Bucket`] index). + /// + /// This uses dynamic dispatch to reduce the amount of code generated, but that is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element (as `Ok(index)`). If the element is not found and there is at least 1 + /// empty or deleted [`Bucket`] in the table, the function is guaranteed to return + /// an index in the range `0..self.num_buckets()`, but in any case, if this function + /// returns `Err`, it will contain an index in the range `0..=self.num_buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the index returned by this function when the table is less than + /// the group width and if there was not at least one empty or deleted bucket in the table + /// will cause immediate [`undefined behavior`]. This is because in this case the function + /// will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] control + /// bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_or_find_insert_index_inner( + &self, + hash: u64, + eq: &mut dyn FnMut(usize) -> bool, + ) -> Result { + let mut insert_index = None; + + let tag_hash = Tag::full(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.num_buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because the number + // of buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_tag(tag_hash) { + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Ok(index); + } + } + + // We didn't find the element we were looking for in the group, try to get an + // insertion slot from the group if we don't have one yet. + if likely(insert_index.is_none()) { + insert_index = self.find_insert_index_in_group(&group, &probe_seq); + } + + if let Some(insert_index) = insert_index { + // Only stop the search if the group contains at least one empty element. + // Otherwise, the element that we are looking for might be in a following group. + if likely(group.match_empty().any_bit_set()) { + // We must have found a insert slot by now, since the current group contains at + // least one. For tables smaller than the group width, there will still be an + // empty element in the current (and only) group due to the load factor. + unsafe { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the index found by `self.find_insert_index_in_group` + return Err(self.fix_insert_index(insert_index)); + } + } + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting a new + /// element and sets the hash for that slot. Returns an index of that slot and the + /// old control byte stored in the found index. + /// + /// This function does not check if the given element exists in the table. Also, + /// this function does not check if there is enough space in the table to insert + /// a new element. The caller of the function must make sure that the table has at + /// least 1 empty or deleted `bucket`, otherwise this function will never return + /// (will go into an infinite loop) for tables larger than the group width, or + /// return an index outside of the table indices range if the table is less than + /// the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an `index` in the range `0..self.num_buckets()`, but in any case, + /// if this function returns an `index` it will be in the range `0..=self.num_buckets()`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for the + /// [`RawTableInner::set_ctrl_hash`] and [`RawTableInner::find_insert_index`] methods. + /// Thus, in order to uphold the safety contracts for that methods, as well as for + /// the correct logic of the work of this crate, you must observe the following rules + /// when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated and has properly initialized + /// control bytes otherwise calling this function results in [`undefined behavior`]. + /// + /// * The caller of this function must ensure that the "data" parts of the table + /// will have an entry in the returned index (matching the given hash) right + /// after calling this function. + /// + /// Attempt to write data at the `index` returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] + /// control bytes outside the table range. + /// + /// The caller must independently increase the `items` field of the table, and also, + /// if the old control byte was [`Tag::EMPTY`], then decrease the table's `growth_left` + /// field, and do not change it if the old control byte was [`Tag::DELETED`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn prepare_insert_index(&mut self, hash: u64) -> (usize, Tag) { + unsafe { + // SAFETY: Caller of this function ensures that the control bytes are properly initialized. + let index: usize = self.find_insert_index(hash); + // SAFETY: + // 1. The `find_insert_index` function either returns an `index` less than or + // equal to `self.num_buckets() = self.bucket_mask + 1` of the table, or never + // returns if it cannot find an empty or deleted slot. + // 2. The caller of this function guarantees that the table has already been + // allocated + let old_ctrl = *self.ctrl(index); + self.set_ctrl_hash(index, hash); + (index, old_ctrl) + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element, returning the `index` for the new [`Bucket`]. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an index in the range `0..self.num_buckets()`, but in any case, + /// it will contain an index in the range `0..=self.num_buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the index returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`Tag::EMPTY`] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_insert_index(&self, hash: u64) -> usize { + let mut probe_seq = self.probe_seq(hash); + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.num_buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because the number + // of buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + let index = self.find_insert_index_in_group(&group, &probe_seq); + if likely(index.is_some()) { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_index_in_group` + unsafe { + return self.fix_insert_index(index.unwrap_unchecked()); + } + } + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an element in a table, returning the `index` of the found element. + /// This uses dynamic dispatch to reduce the amount of code generated, but it is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, + /// this function will also never return (will go into an infinite loop). + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element as `Some(index)`, so the index will always be in the range + /// `0..self.num_buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { + let tag_hash = Tag::full(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.num_buckets() - 1` + // of the table due to masking with `self.bucket_mask`. + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new_in). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_tag(tag_hash) { + // This is the same as `(probe_seq.pos + bit) % self.num_buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Some(index); + } + } + + if likely(group.match_empty().any_bit_set()) { + return None; + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Prepares for rehashing data in place (that is, without allocating new memory). + /// Converts all full index `control bytes` to `Tag::DELETED` and all `Tag::DELETED` control + /// bytes to `Tag::EMPTY`, i.e. performs the following conversion: + /// + /// - `Tag::EMPTY` control bytes -> `Tag::EMPTY`; + /// - `Tag::DELETED` control bytes -> `Tag::EMPTY`; + /// - `FULL` control bytes -> `Tag::DELETED`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The caller of this function must convert the `Tag::DELETED` bytes back to `FULL` + /// bytes when re-inserting them into their ideal position (which was impossible + /// to do during the first insert due to tombstones). If the caller does not do + /// this, then calling this function may result in a memory leak. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise + /// calling this function results in [`undefined behavior`]. + /// + /// Calling this function on a table that has not been allocated results in + /// [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn prepare_rehash_in_place(&mut self) { + // Bulk convert all full control bytes to DELETED, and all DELETED control bytes to EMPTY. + // This effectively frees up all buckets containing a DELETED entry. + // + // SAFETY: + // 1. `i` is guaranteed to be within bounds since we are iterating from zero to `buckets - 1`; + // 2. Even if `i` will be `i == self.bucket_mask`, it is safe to call `Group::load_aligned` + // due to the extended control bytes range, which is `self.bucket_mask + 1 + Group::WIDTH`; + // 3. The caller of this function guarantees that [`RawTableInner`] has already been allocated; + // 4. We can use `Group::load_aligned` and `Group::store_aligned` here since we start from 0 + // and go to the end with a step equal to `Group::WIDTH` (see TableLayout::calculate_layout_for). + unsafe { + for i in (0..self.num_buckets()).step_by(Group::WIDTH) { + let group = Group::load_aligned(self.ctrl(i)); + let group = group.convert_special_to_empty_and_full_to_deleted(); + group.store_aligned(self.ctrl(i)); + } + } + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if unlikely(self.num_buckets() < Group::WIDTH) { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.num_buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + unsafe { + self.ctrl(0) + .copy_to(self.ctrl(Group::WIDTH), self.num_buckets()); + } + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.num_buckets() == self.bucket_mask + 1` is safe + unsafe { + self.ctrl(0) + .copy_to(self.ctrl(self.num_buckets()), Group::WIDTH); + } + } + } + + /// Returns an iterator over every element in the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result + /// is [`undefined behavior`]: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `RawIter`. Because we cannot make the `next` method unsafe on + /// the `RawIter` struct, we have to make the `iter` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise using the returned [`RawIter`] results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.data_end()` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. `data` bucket index in the table is equal to the `ctrl` index (i.e. + // equal to zero). + // 3. We pass the exact value of buckets of the table to the function. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::num_buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + unsafe { + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + // SAFETY: See explanation above + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.num_buckets()), + items: self.items, + } + } + } + + /// Executes the destructors (if any) of the values stored in the table. + /// + /// # Note + /// + /// This function does not erase the control bytes of the table and does + /// not make any changes to the `items` or `growth_left` fields of the + /// table. If necessary, the caller of this function must manually set + /// up these table fields, for example using the [`clear_no_drop`] function. + /// + /// Be careful during calling this function, because drop function of + /// the elements can panic, and this can leave table in an inconsistent + /// state. + /// + /// # Safety + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise calling this function may result in [`undefined behavior`]. + /// + /// If `T` is a type that should be dropped and **the table is not empty**, + /// calling this function more than once results in [`undefined behavior`]. + /// + /// If `T` is not [`Copy`], attempting to use values stored in the table after + /// calling this function may result in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`Bucket::drop`] / [`Bucket::as_ptr`] methods, for more information + /// about of properly removing or saving `element` from / into the [`RawTable`] / + /// [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_elements(&mut self) { + // Check that `self.items != 0`. Protects against the possibility + // of creating an iterator on an table with uninitialized control bytes. + if T::NEEDS_DROP && self.items != 0 { + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `RawIter` iterator, and the caller of this function + // must uphold the safety contract for `drop_elements` method. + unsafe { + for item in self.iter::() { + // SAFETY: The caller must uphold the safety contract for + // `drop_elements` method. + item.drop(); + } + } + } + } + + /// Executes the destructors (if any) of the values stored in the table and than + /// deallocates the table. + /// + /// # Note + /// + /// Calling this function automatically makes invalid (dangling) all instances of + /// buckets ([`Bucket`]) and makes invalid (dangling) the `ctrl` field of the table. + /// + /// This function does not make any changes to the `bucket_mask`, `items` or `growth_left` + /// fields of the table. If necessary, the caller of this function must manually set + /// up these table fields. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * Calling this function more than once; + /// + /// * The type `T` must be the actual type of the elements stored in the table. + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that + /// was used to allocate this table. + /// + /// The caller of this function should pay attention to the possibility of the + /// elements' drop function panicking, because this: + /// + /// * May leave the table in an inconsistent state; + /// + /// * Memory is never deallocated, so a memory leak may occur. + /// + /// Attempt to use the `ctrl` field of the table (dereference) after calling this + /// function results in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`RawTableInner::drop_elements`] or [`RawTableInner::free_buckets`] + /// for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_inner_table(&mut self, alloc: &A, table_layout: TableLayout) { + if !self.is_empty_singleton() { + // SAFETY: The caller must uphold the safety contract for `drop_inner_table` method. + unsafe { + self.drop_elements::(); + } + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller must uphold the safety contract for `drop_inner_table` method. + unsafe { + self.free_buckets(alloc, table_layout); + } + } + } + + /// Returns a pointer to an element in the table (convenience for + /// `Bucket::from_base_index(self.data_end::(), index)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived from the + /// safety rules of the [`Bucket::from_base_index`] function. Therefore, when calling + /// this function, the following safety rules must be observed: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::num_buckets`] + /// function, i.e. `(index + 1) <= self.num_buckets()`. + /// + /// * The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`Bucket`] may result in [`undefined behavior`]. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::num_buckets`] function, i.e. + /// `(index + 1) <= self.num_buckets()`. + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::num_buckets() - 1"): + /// + /// `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + /// part of the `RawTableInner`, i.e. to the start of T3 (see [`Bucket::as_ptr`]) + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// ^ \__________ __________/ + /// `table.bucket(3)` returns a pointer that points \/ + /// here in the `data` part of the `RawTableInner` additional control bytes + /// (to the end of T3) `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.num_buckets()); + unsafe { Bucket::from_base_index(self.data_end(), index) } + } + + /// Returns a raw `*mut u8` pointer to the start of the `data` element in the table + /// (convenience for `self.data_end::().as_ptr().sub((index + 1) * size_of)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned `*mut u8`, + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::num_buckets`] + /// function, i.e. `(index + 1) <= self.num_buckets()`; + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::num_buckets() - 1"): + /// + /// `table.bucket_ptr(3, mem::size_of::())` returns a pointer that points here in the + /// `data` part of the `RawTableInner`, i.e. to the start of T3 + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// \__________ __________/ + /// \/ + /// additional control bytes + /// `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.num_buckets()); + unsafe { + let base: *mut u8 = self.data_end().as_ptr(); + base.sub((index + 1) * size_of) + } + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation (convenience for `self.ctrl.cast()`). + /// + /// This function actually returns a pointer to the end of the `data element` at + /// index "0" (zero). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Note + /// + /// The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`NonNull`] may result in [`undefined behavior`]. + /// + /// ```none + /// `table.data_end::()` returns pointer that points here + /// (to the end of `T0`) + /// ∨ + /// [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + /// \________ ________/ + /// \/ + /// `n = buckets - 1`, i.e. `RawTableInner::num_buckets() - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`. + /// CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + /// with loading `Group` bytes from the heap works properly, even if the result + /// of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + /// `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.num_buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + fn data_end(&self) -> NonNull { + self.ctrl.cast() + } + + /// Returns an iterator-like object for a probe sequence on the table. + /// + /// This iterator never terminates, but is guaranteed to visit each bucket + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. + #[inline] + fn probe_seq(&self, hash: u64) -> ProbeSeq { + ProbeSeq { + // This is the same as `hash as usize % self.num_buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + pos: h1(hash) & self.bucket_mask, + stride: 0, + } + } + + #[inline] + unsafe fn record_item_insert_at(&mut self, index: usize, old_ctrl: Tag, new_ctrl: Tag) { + self.growth_left -= usize::from(old_ctrl.special_is_empty()); + unsafe { + self.set_ctrl(index, new_ctrl); + } + self.items += 1; + } + + #[inline] + fn is_in_same_group(&self, i: usize, new_i: usize, hash: u64) -> bool { + let probe_seq_pos = self.probe_seq(hash).pos; + let probe_index = + |pos: usize| (pos.wrapping_sub(probe_seq_pos) & self.bucket_mask) / Group::WIDTH; + probe_index(i) == probe_index(new_i) + } + + /// Sets a control byte to the hash, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl`] + /// method. Thus, in order to uphold the safety contracts for the method, you must observe the + /// following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::num_buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl_hash(&mut self, index: usize, hash: u64) { + unsafe { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl_hash`] + self.set_ctrl(index, Tag::full(hash)); + } + } + + /// Replaces the hash in the control byte at the given index with the provided one, + /// and possibly also replicates the new control byte at the end of the array of control + /// bytes, returning the old control byte. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl_hash`] + /// and [`RawTableInner::ctrl`] methods. Thus, in order to uphold the safety contracts for both + /// methods, you must observe the following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::num_buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn replace_ctrl_hash(&mut self, index: usize, hash: u64) -> Tag { + unsafe { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::replace_ctrl_hash`] + let prev_ctrl = *self.ctrl(index); + self.set_ctrl_hash(index, hash); + prev_ctrl + } + } + + /// Sets a control byte, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::num_buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl(&mut self, index: usize, ctrl: Tag) { + // Replicate the first Group::WIDTH control bytes at the end of + // the array without using a branch. If the tables smaller than + // the group width (self.num_buckets() < Group::WIDTH), + // `index2 = Group::WIDTH + index`, otherwise `index2` is: + // + // - If index >= Group::WIDTH then index == index2. + // - Otherwise index2 == self.bucket_mask + 1 + index. + // + // The very last replicated control byte is never actually read because + // we mask the initial index for unaligned loads, but we write it + // anyways because it makes the set_ctrl implementation simpler. + // + // If there are fewer buckets than Group::WIDTH then this code will + // replicate the buckets at the end of the trailing group. For example + // with 2 buckets and a group size of 4, the control bytes will look + // like this: + // + // Real | Replicated + // --------------------------------------------- + // | [A] | [B] | [Tag::EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- + + // This is the same as `(index.wrapping_sub(Group::WIDTH)) % self.num_buckets() + Group::WIDTH` + // because the number of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl`] + unsafe { + *self.ctrl(index) = ctrl; + *self.ctrl(index2) = ctrl; + } + } + + /// Returns a pointer to a control byte. + /// + /// # Safety + /// + /// For the allocated [`RawTableInner`], the result is [`Undefined Behavior`], + /// if the `index` is greater than the `self.bucket_mask + 1 + Group::WIDTH`. + /// In that case, calling this function with `index == self.bucket_mask + 1 + Group::WIDTH` + /// will return a pointer to the end of the allocated table and it is useless on its own. + /// + /// Calling this function with `index >= self.bucket_mask + 1 + Group::WIDTH` on a + /// table that has not been allocated results in [`Undefined Behavior`]. + /// + /// So to satisfy both requirements you should always follow the rule that + /// `index < self.bucket_mask + 1 + Group::WIDTH` + /// + /// Calling this function on [`RawTableInner`] that are not already allocated is safe + /// for read-only purpose. + /// + /// See also [`Bucket::as_ptr()`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn ctrl(&self, index: usize) -> *mut Tag { + debug_assert!(index < self.num_ctrl_bytes()); + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::ctrl`] + unsafe { self.ctrl.as_ptr().add(index).cast() } + } + + /// Gets the slice of all control bytes, as possibily uninitialized tags. + fn ctrl_slice(&mut self) -> &mut [mem::MaybeUninit] { + // SAFETY: We have the correct number of control bytes. + unsafe { slice::from_raw_parts_mut(self.ctrl.as_ptr().cast(), self.num_ctrl_bytes()) } + } + + #[inline] + fn num_buckets(&self) -> usize { + self.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + unsafe fn is_bucket_full(&self, index: usize) -> bool { + debug_assert!(index < self.num_buckets()); + unsafe { (*self.ctrl(index)).is_full() } + } + + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating, + /// and return it inside `ScopeGuard` to protect against panic in the hash + /// function. + /// + /// # Note + /// + /// It is recommended (but not required): + /// + /// * That the new table's `capacity` be greater than or equal to `self.items`. + /// + /// * The `alloc` is the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `table_layout` is the same [`TableLayout`] as the `TableLayout` used + /// to allocate this table. + /// + /// If `table_layout` does not match the `TableLayout` that was used to allocate + /// this table, then using `mem::swap` with the `self` and the new table returned + /// by this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + fn prepare_resize<'a, A>( + &self, + alloc: &'a A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result, TryReserveError> + where + A: Allocator, + { + debug_assert!(self.items <= capacity); + + // Allocate and initialize the new table. + let new_table = + RawTableInner::fallible_with_capacity(alloc, table_layout, capacity, fallibility)?; + + // The hash function may panic, in which case we simply free the new + // table without dropping any elements that may have been copied into + // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. + Ok(guard(new_table, move |self_| { + if !self_.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that the `alloc` and `table_layout` matches the + // [`Allocator`] and [`TableLayout`] used to allocate this table. + unsafe { self_.free_buckets(alloc, table_layout) }; + } + })) + } + + /// Reserves or rehashes to make room for `additional` more elements. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table. + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[expect(clippy::inline_always)] + #[inline(always)] + unsafe fn reserve_rehash_inner( + &mut self, + alloc: &A, + additional: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + drop: Option, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let Some(new_items) = self.items.checked_add(additional) else { + return Err(fallibility.capacity_overflow()); + }; + let full_capacity = bucket_mask_to_capacity(self.bucket_mask); + if new_items <= full_capacity / 2 { + // Rehash in-place without re-allocating if we have plenty of spare + // capacity that is locked up due to DELETED entries. + + // SAFETY: + // 1. We know for sure that `[`RawTableInner`]` has already been allocated + // (since new_items <= full_capacity / 2); + // 2. The caller ensures that `drop` function is the actual drop function of + // the elements stored in the table. + // 3. The caller ensures that `layout` matches the [`TableLayout`] that was + // used to allocate this table. + // 4. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + unsafe { + self.rehash_in_place(hasher, layout.size, drop); + } + Ok(()) + } else { + // Otherwise, conservatively resize to at least the next size up + // to avoid churning deletes into frequent rehashes. + // + // SAFETY: + // 1. We know for sure that `capacity >= self.items`. + // 2. The caller ensures that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + unsafe { + self.resize_inner( + alloc, + usize::max(new_items, full_capacity + 1), + hasher, + fallibility, + layout, + ) + } + } + } + + /// Returns an iterator over full buckets indices in the table. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `FullBucketsIndices`. Because we cannot make the `next` method + /// unsafe on the `FullBucketsIndices` struct, we have to make the + /// `full_buckets_indices` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + #[inline(always)] + unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.ctrl(0)` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. The value of `items` is equal to the amount of data (values) added + // to the table. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, Group::WIDTH + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::num_buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + unsafe { + let ctrl = NonNull::new_unchecked(self.ctrl(0).cast::()); + + FullBucketsIndices { + // Load the first group + // SAFETY: See explanation above. + current_group: Group::load_aligned(ctrl.as_ptr().cast()) + .match_full() + .into_iter(), + group_first_index: 0, + ctrl, + items: self.items, + } + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table; + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The caller of this function must ensure that `capacity >= self.items` + /// otherwise: + /// + /// * If `self.items != 0`, calling of this function with `capacity == 0` + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// are never return (will go into an infinite loop). + /// + /// Note: It is recommended (but not required) that the new table's `capacity` + /// be greater than or equal to `self.items`. In case if `capacity <= self.items` + /// this function can never return. See [`RawTableInner::find_insert_index`] for + /// more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[expect(clippy::inline_always)] + #[inline(always)] + unsafe fn resize_inner( + &mut self, + alloc: &A, + capacity: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // SAFETY: We know for sure that `alloc` and `layout` matches the [`Allocator`] and [`TableLayout`] + // that were used to allocate this table. + let mut new_table = self.prepare_resize(alloc, layout, capacity, fallibility)?; + + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `FullBucketsIndices` iterator, and the caller of this + // function ensures that the control bytes are properly initialized. + unsafe { + for full_byte_index in self.full_buckets_indices() { + // This may panic. + let hash = hasher(self, full_byte_index); + + // SAFETY: + // We can use a simpler version of insert() here since: + // 1. There are no DELETED entries. + // 2. We know there is enough space in the table. + // 3. All elements are unique. + // 4. The caller of this function guarantees that `capacity > 0` + // so `new_table` must already have some allocated memory. + // 5. We set `growth_left` and `items` fields of the new table + // after the loop. + // 6. We insert into the table, at the returned index, the data + // matching the given hash immediately after calling this function. + let (new_index, _) = new_table.prepare_insert_index(hash); + + // SAFETY: + // + // * `src` is valid for reads of `layout.size` bytes, since the + // table is alive and the `full_byte_index` is guaranteed to be + // within bounds (see `FullBucketsIndices::next_impl`); + // + // * `dst` is valid for writes of `layout.size` bytes, since the + // caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate old table and we have the `new_index` + // returned by `prepare_insert_index`. + // + // * Both `src` and `dst` are properly aligned. + // + // * Both `src` and `dst` point to different region of memory. + ptr::copy_nonoverlapping( + self.bucket_ptr(full_byte_index, layout.size), + new_table.bucket_ptr(new_index, layout.size), + layout.size, + ); + } + } + + // The hash function didn't panic, so we can safely set the + // `growth_left` and `items` fields of the new table. + new_table.growth_left -= self.items; + new_table.items = self.items; + + // We successfully copied all elements without panicking. Now replace + // self with the new table. The old table will have its memory freed but + // the items will not be dropped (since they have been moved into the + // new table). + // SAFETY: The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + mem::swap(self, &mut new_table); + + Ok(()) + } + + /// Rehashes the contents of the table in place (i.e. without changing the + /// allocation). + /// + /// If `hasher` panics then some the table's contents may be lost. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg_attr(feature = "inline-more", expect(clippy::inline_always))] + #[cfg_attr(feature = "inline-more", inline(always))] + #[cfg_attr(not(feature = "inline-more"), inline)] + unsafe fn rehash_in_place( + &mut self, + hasher: &dyn Fn(&mut Self, usize) -> u64, + size_of: usize, + drop: Option, + ) { + // If the hash function panics then properly clean up any elements + // that we haven't rehashed yet. We unfortunately can't preserve the + // element since we lost their hash and have no way of recovering it + // without risking another panic. + unsafe { + self.prepare_rehash_in_place(); + } + + let mut guard = guard(self, move |self_| { + for i in 0..self_.num_buckets() { + unsafe { + // Any elements that haven't been rehashed yet have a + // DELETED tag. These need to be dropped and have their tag + // reset to EMPTY. + if *self_.ctrl(i) == Tag::DELETED { + self_.set_ctrl(i, Tag::EMPTY); + if let Some(drop) = drop { + drop(self_.bucket_ptr(i, size_of)); + } + self_.items -= 1; + } + } + } + self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items; + }); + + // At this point, DELETED elements are elements that we haven't + // rehashed yet. Find them and re-insert them at their ideal + // position. + 'outer: for i in 0..guard.num_buckets() { + unsafe { + if *guard.ctrl(i) != Tag::DELETED { + continue; + } + } + + let i_p = unsafe { guard.bucket_ptr(i, size_of) }; + + loop { + // Hash the current item + let hash = hasher(*guard, i); + + // Search for a suitable place to put it + // + // SAFETY: Caller of this function ensures that the control bytes + // are properly initialized. + let new_i = unsafe { guard.find_insert_index(hash) }; + + // Probing works by scanning through all of the control + // bytes in groups, which may not be aligned to the group + // size. If both the new and old position fall within the + // same unaligned group, then there is no benefit in moving + // it and we can just continue to the next item. + if likely(guard.is_in_same_group(i, new_i, hash)) { + unsafe { guard.set_ctrl_hash(i, hash) }; + continue 'outer; + } + + let new_i_p = unsafe { guard.bucket_ptr(new_i, size_of) }; + + // We are moving the current item to a new position. Write + // our H2 to the control byte of the new position. + let prev_ctrl = unsafe { guard.replace_ctrl_hash(new_i, hash) }; + if prev_ctrl == Tag::EMPTY { + unsafe { guard.set_ctrl(i, Tag::EMPTY) }; + // If the target slot is empty, simply move the current + // element into the new slot and clear the old control + // byte. + unsafe { + ptr::copy_nonoverlapping(i_p, new_i_p, size_of); + } + continue 'outer; + } + + // If the target slot is occupied, swap the two elements + // and then continue processing the element that we just + // swapped into the old slot. + debug_assert_eq!(prev_ctrl, Tag::DELETED); + unsafe { + ptr::swap_nonoverlapping(i_p, new_i_p, size_of); + } + } + } + + guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items; + + mem::forget(guard); + } + + /// Deallocates the table without dropping any entries. + /// + /// # Note + /// + /// This function must be called only after [`drop_elements`](RawTableInner::drop_elements), + /// else it can lead to leaking of memory. Also calling this function automatically + /// makes invalid (dangling) all instances of buckets ([`Bucket`]) and makes invalid + /// (dangling) the `ctrl` field of the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that was used + /// to allocate this table. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: stdalloc::alloc::GlobalAlloc::dealloc + /// [`Allocator::deallocate`]: stdalloc::alloc::Allocator::deallocate + #[inline] + unsafe fn free_buckets(&mut self, alloc: &A, table_layout: TableLayout) + where + A: Allocator, + { + unsafe { + // SAFETY: The caller must uphold the safety contract for `free_buckets` + // method. + let (ptr, layout) = self.allocation_info(table_layout); + alloc.deallocate(ptr, layout); + } + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. + /// + /// # Safety + /// + /// Caller of this function must observe the following safety rules: + /// + /// * The [`RawTableInner`] has already been allocated, otherwise + /// calling this function results in [`undefined behavior`] + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: stdalloc::GlobalAlloc::dealloc + /// [`Allocator::deallocate`]: stdalloc::Allocator::deallocate + #[inline] + unsafe fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + + let (layout, ctrl_offset) = { + let option = table_layout.calculate_layout_for(self.num_buckets()); + unsafe { option.unwrap_unchecked() } + }; + ( + // SAFETY: The caller must uphold the safety contract for `allocation_info` method. + unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + ) + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + /// + /// # Safety + /// + /// The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn allocation_size_or_zero(&self, table_layout: TableLayout) -> usize { + if self.is_empty_singleton() { + 0 + } else { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + unsafe { self.allocation_info(table_layout).1.size() } + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[inline] + fn clear_no_drop(&mut self) { + if !self.is_empty_singleton() { + self.ctrl_slice().fill_empty(); + } + self.items = 0; + self.growth_left = bucket_mask_to_capacity(self.bucket_mask); + } + + /// Erases the [`Bucket`]'s control byte at the given index so that it does not + /// triggered as full, decreases the `items` of the table and, if it can be done, + /// increases `self.growth_left`. + /// + /// This function does not actually erase / drop the [`Bucket`] itself, i.e. it + /// does not make any changes to the `data` parts of the table. The caller of this + /// function must take care to properly drop the `data`, otherwise calling this + /// function may result in a memory leak. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * It must be the full control byte at the given position; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::num_buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// Calling this function on a table with no elements is unspecified, but calling subsequent + /// functions is likely to result in [`undefined behavior`] due to overflow subtraction + /// (`self.items -= 1 cause overflow when self.items == 0`). + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn erase(&mut self, index: usize) { + unsafe { + debug_assert!(self.is_bucket_full(index)); + } + + // This is the same as `index.wrapping_sub(Group::WIDTH) % self.num_buckets()` because + // the number of buckets is a power of two, and `self.bucket_mask = self.num_buckets() - 1`. + let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + // SAFETY: + // - The caller must uphold the safety contract for `erase` method; + // - `index_before` is guaranteed to be in range due to masking with `self.bucket_mask` + let (empty_before, empty_after) = unsafe { + ( + Group::load(self.ctrl(index_before)).match_empty(), + Group::load(self.ctrl(index)).match_empty(), + ) + }; + + // Inserting and searching in the map is performed by two key functions: + // + // - The `find_insert_index` function that looks up the index of any `Tag::EMPTY` or `Tag::DELETED` + // slot in a group to be able to insert. If it doesn't find an `Tag::EMPTY` or `Tag::DELETED` + // slot immediately in the first group, it jumps to the next `Group` looking for it, + // and so on until it has gone through all the groups in the control bytes. + // + // - The `find_inner` function that looks for the index of the desired element by looking + // at all the `FULL` bytes in the group. If it did not find the element right away, and + // there is no `Tag::EMPTY` byte in the group, then this means that the `find_insert_index` + // function may have found a suitable slot in the next group. Therefore, `find_inner` + // jumps further, and if it does not find the desired element and again there is no `Tag::EMPTY` + // byte, then it jumps further, and so on. The search stops only if `find_inner` function + // finds the desired element or hits an `Tag::EMPTY` slot/byte. + // + // Accordingly, this leads to two consequences: + // + // - The map must have `Tag::EMPTY` slots (bytes); + // + // - You can't just mark the byte to be erased as `Tag::EMPTY`, because otherwise the `find_inner` + // function may stumble upon an `Tag::EMPTY` byte before finding the desired element and stop + // searching. + // + // Thus it is necessary to check all bytes after and before the erased element. If we are in + // a contiguous `Group` of `FULL` or `Tag::DELETED` bytes (the number of `FULL` or `Tag::DELETED` bytes + // before and after is greater than or equal to `Group::WIDTH`), then we must mark our byte as + // `Tag::DELETED` in order for the `find_inner` function to go further. On the other hand, if there + // is at least one `Tag::EMPTY` slot in the `Group`, then the `find_inner` function will still stumble + // upon an `Tag::EMPTY` byte, so we can safely mark our erased byte as `Tag::EMPTY` as well. + // + // Finally, since `index_before == (index.wrapping_sub(Group::WIDTH) & self.bucket_mask) == index` + // and given all of the above, tables smaller than the group width (self.num_buckets() < Group::WIDTH) + // cannot have `Tag::DELETED` bytes. + // + // Note that in this context `leading_zeros` refers to the bytes at the end of a group, while + // `trailing_zeros` refers to the bytes at the beginning of a group. + let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { + Tag::DELETED + } else { + self.growth_left += 1; + Tag::EMPTY + }; + // SAFETY: the caller must uphold the safety contract for `erase` method. + unsafe { + self.set_ctrl(index, ctrl); + } + self.items -= 1; + } +} + +impl Clone for RawTable { + fn clone(&self) -> Self { + if self.table.is_empty_singleton() { + Self::new_in(self.alloc.clone()) + } else { + // SAFETY: This is safe as we are taking the size of an already allocated table + // and therefore capacity overflow cannot occur, `self.table.num_buckets()` is power + // of two and all allocator errors will be caught inside `RawTableInner::new_uninitialized`. + let result = unsafe { + Self::new_uninitialized( + self.alloc.clone(), + self.table.num_buckets(), + Fallibility::Infallible, + ) + }; + + // SAFETY: The result of calling the `new_uninitialized` function cannot be an error + // because `fallibility == Fallibility::Infallible. + let mut new_table = unsafe { result.unwrap_unchecked() }; + + // SAFETY: + // Cloning elements may fail (the clone function may panic). But we don't + // need to worry about uninitialized control bits, since: + // 1. The number of items (elements) in the table is zero, which means that + // the control bits will not be read by Drop function. + // 2. The `clone_from_spec` method will first copy all control bits from + // `self` (thus initializing them). But this will not affect the `Drop` + // function, since the `clone_from_spec` function sets `items` only after + // successfully cloning all elements. + unsafe { new_table.clone_from_spec(self) }; + new_table + } + } + + fn clone_from(&mut self, source: &Self) { + if source.table.is_empty_singleton() { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + unsafe { + // Make sure that if any panics occurs, we clear the table and + // leave it in an empty state. + let mut self_ = guard(self, |self_| { + self_.clear_no_drop(); + }); + + // First, drop all our elements without clearing the control + // bytes. If this panics then the scope guard will clear the + // table, leaking any elements that were not dropped yet. + // + // This leak is unavoidable: we can't try dropping more elements + // since this could lead to another panic and abort the process. + // + // SAFETY: If something gets wrong we clear our table right after + // dropping the elements, so there is no double drop, since `items` + // will be equal to zero. + self_.table.drop_elements::(); + + // If necessary, resize our table to match the source. + if self_.num_buckets() != source.num_buckets() { + let new_inner = { + let result = RawTableInner::new_uninitialized( + &self_.alloc, + Self::TABLE_LAYOUT, + source.num_buckets(), + Fallibility::Infallible, + ); + result.unwrap_unchecked() + }; + // Replace the old inner with new uninitialized one. It's ok, since if something gets + // wrong `ScopeGuard` will initialize all control bytes and leave empty table. + let mut old_inner = mem::replace(&mut self_.table, new_inner); + if !old_inner.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that `alloc` and `table_layout` matches + // the [`Allocator`] and [`TableLayout`] that were used to allocate this table. + old_inner.free_buckets(&self_.alloc, Self::TABLE_LAYOUT); + } + } + + // Cloning elements may fail (the clone function may panic), but the `ScopeGuard` + // inside the `clone_from_impl` function will take care of that, dropping all + // cloned elements if necessary. Our `ScopeGuard` will clear the table. + self_.clone_from_spec(source); + + // Disarm the scope guard if cloning was successful. + ScopeGuard::into_inner(self_); + } + } + } +} + +/// Specialization of `clone_from` for `Copy` types +trait RawTableClone { + unsafe fn clone_from_spec(&mut self, source: &Self); +} +impl RawTableClone for RawTable { + default_fn! { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + unsafe { + self.clone_from_impl(source); + } + } + } +} +#[cfg(feature = "nightly")] +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + unsafe { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + source + .data_start() + .as_ptr() + .copy_to_nonoverlapping(self.data_start().as_ptr(), self.table.num_buckets()); + } + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl RawTable { + /// Common code for `clone` and `clone_from`. Assumes: + /// - `self.num_buckets() == source.num_buckets()`. + /// - Any existing elements have been dropped. + /// - The control bytes are not initialized yet. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_impl(&mut self, source: &Self) { + // Copy the control bytes unchanged. We do this in a single pass + unsafe { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + } + + // The cloning of elements may panic, in which case we need + // to make sure we drop only the elements that have been + // cloned so far. + let mut guard = guard((0, &mut *self), |(index, self_)| { + if T::NEEDS_DROP { + for i in 0..*index { + unsafe { + if self_.is_bucket_full(i) { + self_.bucket(i).drop(); + } + } + } + } + }); + + unsafe { + for from in source.iter() { + let index = source.bucket_index(&from); + let to = guard.1.bucket(index); + to.write(from.as_ref().clone()); + + // Update the index in case we need to unwind. + guard.0 = index + 1; + } + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl Default for RawTable { + #[inline] + fn default() -> Self { + Self::new_in(Default::default()) + } +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + unsafe { + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + unsafe { + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} + +impl IntoIterator for RawTable { + type Item = T; + type IntoIter = RawIntoIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> RawIntoIter { + unsafe { + let iter = self.iter(); + self.into_iter_from(iter) + } + } +} + +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does +/// not track an item count. +pub(crate) struct RawIterRange { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. + end: *const u8, +} + +impl RawIterRange { + /// Returns a `RawIterRange` covering a subset of a table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * `ctrl` must be valid for reads, i.e. table outlives the `RawIterRange`; + /// + /// * `ctrl` must be properly aligned to the group size (`Group::WIDTH`); + /// + /// * `ctrl` must point to the array of properly initialized control bytes; + /// + /// * `data` must be the [`Bucket`] at the `ctrl` index in the table; + /// + /// * the value of `len` must be less than or equal to the number of table buckets, + /// and the returned value of `ctrl.as_ptr().add(len).offset_from(ctrl.as_ptr())` + /// must be positive. + /// + /// * The `ctrl.add(len)` pointer must be either in bounds or one + /// byte past the end of the same [allocated table]. + /// + /// * The `len` must be a power of two. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let end = unsafe { ctrl.add(len) }; + + // Load the first group and advance ctrl to point to the next group + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let (current_group, next_ctrl) = unsafe { + ( + Group::load_aligned(ctrl.cast()).match_full(), + ctrl.add(Group::WIDTH), + ) + }; + + Self { + current_group: current_group.into_iter(), + data, + next_ctrl, + end, + } + } + + /// Splits a `RawIterRange` into two halves. + /// + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rayon")] + pub(crate) fn split(mut self) -> (Self, Option>) { + unsafe { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. + (self, None) + } else { + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.next_n(Group::WIDTH).next_n(mid), + len - mid, + ); + debug_assert_eq!( + self.data.next_n(Group::WIDTH).next_n(mid).ptr, + tail.data.ptr + ); + debug_assert_eq!(self.end, tail.end); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); + (self, Some(tail)) + } + } + } + + /// # Safety + /// If `DO_CHECK_PTR_RANGE` is false, caller must ensure that we never try to iterate + /// after yielding all elements. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn next_impl(&mut self) -> Option> { + loop { + if let Some(index) = self.current_group.next() { + return Some(unsafe { self.data.next_n(index) }); + } + + if DO_CHECK_PTR_RANGE && self.next_ctrl >= self.end { + return None; + } + + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + unsafe { + self.current_group = Group::load_aligned(self.next_ctrl.cast()) + .match_full() + .into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + } + + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. + /// + /// `fold_impl()` takes three arguments: the number of items remaining in + /// the iterator, an initial value, and a closure with two arguments: an + /// 'accumulator', and an element. The closure returns the value that the + /// accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first call. + /// + /// After applying this closure to every element of the iterator, `fold_impl()` + /// returns the accumulator. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `RawIterRange`; + /// + /// * The provided `n` value must match the actual number of items + /// in the table. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[expect(clippy::while_let_on_iterator)] + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn fold_impl(mut self, mut n: usize, mut acc: B, mut f: F) -> B + where + F: FnMut(B, Bucket) -> B, + { + loop { + while let Some(index) = self.current_group.next() { + // The returned `index` will always be in the range `0..Group::WIDTH`, + // so that calling `self.data.next_n(index)` is safe (see detailed explanation below). + debug_assert!(n != 0); + let bucket = unsafe { self.data.next_n(index) }; + acc = f(acc, bucket); + n -= 1; + } + + if n == 0 { + return acc; + } + + // SAFETY: The caller of this function ensures that: + // + // 1. The provided `n` value matches the actual number of items in the table; + // 2. The table is alive and did not moved. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.num_buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.current_group` will read bytes + // from the `self.num_buckets() - Group::WIDTH` index. We know also that + // `self.current_group.next()` will always return indices within the range + // `0..Group::WIDTH`. + // + // Knowing all of the above and taking into account that we are synchronizing + // the `self.data` index with the index we used to read the `self.current_group`, + // the subsequent `self.data.next_n(index)` will always return a bucket with + // an index number less than `self.num_buckets()`. + // + // The last `self.next_ctrl`, whose index would be `self.num_buckets()`, will never + // actually be read, since we should have already yielded all the elements of + // the table. + unsafe { + self.current_group = Group::load_aligned(self.next_ctrl.cast()) + .match_full() + .into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + } +} + +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} + +impl Clone for RawIterRange { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + next_ctrl: self.next_ctrl, + current_group: self.current_group.clone(), + end: self.end, + } + } +} + +impl Iterator for RawIterRange { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + unsafe { + // SAFETY: We set checker flag to true. + self.next_impl::() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We don't have an item count, so just guess based on the range size. + let remaining_buckets = if self.end > self.next_ctrl { + unsafe { offset_from(self.end, self.next_ctrl) } + } else { + 0 + }; + + // Add a group width to include the group we are currently processing. + (0, Some(Group::WIDTH + remaining_buckets)) + } +} + +impl FusedIterator for RawIterRange {} + +/// Iterator which returns a raw pointer to every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket (unless `reflect_remove` is called). +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator (unless `reflect_insert` is called). +/// - The order in which the iterator yields bucket is unspecified and may +/// change in the future. +pub(crate) struct RawIter { + pub(crate) iter: RawIterRange, + items: usize, +} + +impl RawIter { + unsafe fn drop_elements(&mut self) { + unsafe { + if T::NEEDS_DROP && self.items != 0 { + for item in self { + item.drop(); + } + } + } + } +} + +impl Clone for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + items: self.items, + } + } +} +impl Default for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + // SAFETY: Because the table is static, it always outlives the iter. + unsafe { RawTableInner::NEW.iter() } + } +} + +impl Iterator for RawIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + // Inner iterator iterates over buckets + // so it can do unnecessary work if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: We check number of items to yield using `items` field. + self.iter.next_impl::() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + unsafe { self.iter.fold_impl(self.items, init, f) } + } +} + +impl ExactSizeIterator for RawIter {} +impl FusedIterator for RawIter {} + +/// Iterator which returns an index of every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding index of that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields indices of the buckets is unspecified +/// and may change in the future. +#[derive(Clone)] +pub(crate) struct FullBucketsIndices { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Initial value of the bytes' indices of the current group (relative + // to the start of the control bytes). + group_first_index: usize, + + // Pointer to the current group of control bytes, + // Must be aligned to the group size (Group::WIDTH). + ctrl: NonNull, + + // Number of elements in the table. + items: usize, +} + +impl Default for FullBucketsIndices { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + // SAFETY: Because the table is static, it always outlives the iter. + unsafe { RawTableInner::NEW.full_buckets_indices() } + } +} + +impl FullBucketsIndices { + /// Advances the iterator and returns the next value. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `FullBucketsIndices`; + /// + /// * It never tries to iterate after getting all elements. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn next_impl(&mut self) -> Option { + loop { + if let Some(index) = self.current_group.next() { + // The returned `self.group_first_index + index` will always + // be in the range `0..self.num_buckets()`. See explanation below. + return Some(self.group_first_index + index); + } + + // SAFETY: The caller of this function ensures that: + // + // 1. It never tries to iterate after getting all the elements; + // 2. The table is alive and did not moved; + // 3. The first `self.ctrl` pointed to the start of the array of control bytes. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.num_buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // the start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.ctrl` will be equal to + // the `self.num_buckets() - Group::WIDTH`, so `self.current_group.next()` + // will always contains indices within the range `0..Group::WIDTH`, + // and subsequent `self.group_first_index + index` will always return a + // number less than `self.num_buckets()`. + unsafe { + self.ctrl = NonNull::new_unchecked(self.ctrl.as_ptr().add(Group::WIDTH)); + } + + // SAFETY: See explanation above. + unsafe { + self.current_group = Group::load_aligned(self.ctrl.as_ptr().cast()) + .match_full() + .into_iter(); + self.group_first_index += Group::WIDTH; + } + } + } +} + +impl Iterator for FullBucketsIndices { + type Item = usize; + + /// Advances the iterator and returns the next value. It is up to + /// the caller to ensure that the `RawTable` outlives the `FullBucketsIndices`, + /// because we cannot make the `next` method unsafe. + #[inline(always)] + fn next(&mut self) -> Option { + // Return if we already yielded all items. + if self.items == 0 { + return None; + } + + // SAFETY: + // 1. We check number of items to yield using `items` field. + // 2. The caller ensures that the table is alive and has not moved. + let nxt = unsafe { self.next_impl() }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for FullBucketsIndices {} +impl FusedIterator for FullBucketsIndices {} + +/// Iterator which consumes a table and returns elements. +pub(crate) struct RawIntoIter { + iter: RawIter, + allocation: Option<(NonNull, Layout, A)>, + marker: PhantomData, +} + +impl RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawIntoIter +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawIntoIter +where + T: Sync, + A: Sync, +{ +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} + +impl Default for RawIntoIter { + fn default() -> Self { + Self { + iter: Default::default(), + allocation: None, + marker: PhantomData, + } + } +} +impl Iterator for RawIntoIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { Some(self.iter.next()?.read()) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} + +/// Iterator which consumes elements without freeing the table storage. +pub(crate) struct RawDrain<'a, T, A: Allocator = Global> { + iter: RawIter, + + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: RawTableInner, + orig_table: NonNull, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. + marker: PhantomData<&'a RawTable>, +} + +impl RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawDrain<'_, T, A> +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawDrain<'_, T, A> +where + T: Sync, + A: Sync, +{ +} + +impl Drop for RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements. Note that this may panic. + self.iter.drop_elements(); + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&raw const self.table, 1); + } + } +} + +impl Iterator for RawDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { + let item = self.iter.next()?; + Some(item.read()) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} + +/// Iterator over occupied buckets that could match a given hash. +/// +/// `RawTable` only stores 7 bits of the hash value, so this iterator may return +/// items that have a hash value different than the one provided. You should +/// always validate the returned values before using them. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields buckets is unspecified and may +/// change in the future. +pub(crate) struct RawIterHash { + inner: RawIterHashIndices, + _marker: PhantomData, +} + +#[derive(Clone)] +pub(crate) struct RawIterHashIndices { + // See `RawTableInner`'s corresponding fields for details. + // We can't store a `*const RawTableInner` as it would get + // invalidated by the user calling `&mut` methods on `RawTable`. + bucket_mask: usize, + ctrl: NonNull, + + // The top 7 bits of the hash. + tag_hash: Tag, + + // The sequence of groups to probe in the search. + probe_seq: ProbeSeq, + + group: Group, + + // The elements within the group with a matching tag-hash. + bitmask: BitMaskIter, +} + +impl RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(table: &RawTable, hash: u64) -> Self { + RawIterHash { + inner: unsafe { RawIterHashIndices::new(&table.table, hash) }, + _marker: PhantomData, + } + } +} + +impl Clone for RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + _marker: PhantomData, + } + } +} + +impl Default for RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + inner: RawIterHashIndices::default(), + _marker: PhantomData, + } + } +} + +impl Default for RawIterHashIndices { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + // SAFETY: Because the table is static, it always outlives the iter. + unsafe { RawIterHashIndices::new(&RawTableInner::NEW, 0) } + } +} + +impl RawIterHashIndices { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(table: &RawTableInner, hash: u64) -> Self { + let tag_hash = Tag::full(hash); + let probe_seq = table.probe_seq(hash); + let group = unsafe { Group::load(table.ctrl(probe_seq.pos)) }; + let bitmask = group.match_tag(tag_hash).into_iter(); + + RawIterHashIndices { + bucket_mask: table.bucket_mask, + ctrl: table.ctrl, + tag_hash, + probe_seq, + group, + bitmask, + } + } +} + +impl Iterator for RawIterHash { + type Item = Bucket; + + fn next(&mut self) -> Option> { + unsafe { + match self.inner.next() { + Some(index) => { + // Can't use `RawTable::bucket` here as we don't have + // an actual `RawTable` reference to use. + debug_assert!(index <= self.inner.bucket_mask); + let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index); + Some(bucket) + } + None => None, + } + } + } +} + +impl Iterator for RawIterHashIndices { + type Item = usize; + + fn next(&mut self) -> Option { + unsafe { + loop { + if let Some(bit) = self.bitmask.next() { + let index = (self.probe_seq.pos + bit) & self.bucket_mask; + return Some(index); + } + if likely(self.group.match_empty().any_bit_set()) { + return None; + } + self.probe_seq.move_next(self.bucket_mask); + + // Can't use `RawTableInner::ctrl` here as we don't have + // an actual `RawTableInner` reference to use. + let index = self.probe_seq.pos; + debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH); + let group_ctrl = self.ctrl.as_ptr().add(index).cast(); + + self.group = Group::load(group_ctrl); + self.bitmask = self.group.match_tag(self.tag_hash).into_iter(); + } + } + } +} + +pub(crate) struct RawExtractIf<'a, T, A: Allocator> { + pub iter: RawIter, + pub table: &'a mut RawTable, +} + +impl RawExtractIf<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn next(&mut self, mut f: F) -> Option + where + F: FnMut(&mut T) -> bool, + { + unsafe { + for item in &mut self.iter { + if f(item.as_mut()) { + return Some(self.table.remove(item).0); + } + } + } + None + } +} + +#[cfg(test)] +mod test_map { + use super::*; + + #[test] + fn test_prev_pow2() { + // Skip 0, not defined for that input. + let mut pow2: usize = 1; + while (pow2 << 1) > 0 { + let next_pow2 = pow2 << 1; + assert_eq!(pow2, prev_pow2(pow2)); + // Need to skip 2, because it's also a power of 2, so it doesn't + // return the previous power of 2. + if next_pow2 > 2 { + assert_eq!(pow2, prev_pow2(pow2 + 1)); + assert_eq!(pow2, prev_pow2(next_pow2 - 1)); + } + pow2 = next_pow2; + } + } + + #[test] + fn test_minimum_capacity_for_small_types() { + #[track_caller] + fn test_t() { + let raw_table: RawTable = RawTable::with_capacity(1); + let actual_buckets = raw_table.num_buckets(); + let min_buckets = Group::WIDTH / core::mem::size_of::(); + assert!( + actual_buckets >= min_buckets, + "expected at least {min_buckets} buckets, got {actual_buckets} buckets" + ); + } + + test_t::(); + + // This is only "small" for some platforms, like x86_64 with SSE2, but + // there's no harm in running it on other platforms. + test_t::(); + } + + fn rehash_in_place(table: &mut RawTable, hasher: impl Fn(&T) -> u64) { + unsafe { + table.table.rehash_in_place( + &|table, index| hasher(table.bucket::(index).as_ref()), + mem::size_of::(), + if mem::needs_drop::() { + Some(|ptr| ptr::drop_in_place(ptr.cast::())) + } else { + None + }, + ); + } + } + + #[test] + fn rehash() { + let mut table = RawTable::new(); + let hasher = |i: &u64| *i; + for i in 0..100 { + table.insert(i, i, hasher); + } + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + + rehash_in_place(&mut table, hasher); + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + } + + /// CHECKING THAT WE ARE NOT TRYING TO READ THE MEMORY OF + /// AN UNINITIALIZED TABLE DURING THE DROP + #[test] + fn test_drop_uninitialized() { + use stdalloc::vec::Vec; + + let table = unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap() + }; + drop(table); + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_drop_zero_items() { + use stdalloc::vec::Vec; + unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + let mut table = + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap(); + + // WE SIMULATE, AS IT WERE, A FULL TABLE. + + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `table.table.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + table.table.ctrl_slice().fill_empty(); + + // SAFETY: table.capacity() is guaranteed to be smaller than table.num_buckets() + table.table.ctrl(0).write_bytes(0, table.capacity()); + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if table.num_buckets() < Group::WIDTH { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.num_buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(Group::WIDTH), table.table.num_buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.num_buckets() == self.bucket_mask + 1` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(table.table.num_buckets()), Group::WIDTH); + } + drop(table); + } + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + #[cfg(panic = "unwind")] + fn test_catch_panic_clone_from() { + use super::{AllocError, Allocator, Global}; + use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; + use stdalloc::sync::Arc; + use stdalloc::vec::Vec; + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + let g = Global; + g.deallocate(ptr, layout); + } + } + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + struct CheckedCloneDrop { + panic_in_clone: bool, + dropped: bool, + need_drop: Vec, + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + dropped: self.dropped, + need_drop: self.need_drop.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + let mut table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + + for (idx, panic_in_clone) in core::iter::repeat_n(DISARMED, 7).enumerate() { + let idx = idx as u64; + table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx], + }, + ), + |(k, _)| *k, + ); + } + + assert_eq!(table.len(), 7); + + thread::scope(|s| { + let result = s.spawn(|| { + let armed_flags = [ + DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + let mut scope_table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + for (idx, &panic_in_clone) in armed_flags.iter().enumerate() { + let idx = idx as u64; + scope_table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx + 100], + }, + ), + |(k, _)| *k, + ); + } + table.clone_from(&scope_table); + }); + assert!(result.join().is_err()); + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(table.len(), 0); + assert_eq!(unsafe { table.iter().count() }, 0); + assert_eq!(unsafe { table.iter().iter.count() }, 0); + + for idx in 0..table.num_buckets() { + let idx = idx as u64; + assert!( + table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } +} diff --git a/deps/crates/vendor/hashbrown/src/raw_entry.rs b/deps/crates/vendor/hashbrown/src/raw_entry.rs new file mode 100644 index 00000000000000..13b71bc3e1fbf9 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/raw_entry.rs @@ -0,0 +1,1729 @@ +use crate::Equivalent; +use crate::alloc::{Allocator, Global}; +use crate::map::{HashMap, equivalent, make_hash, make_hasher}; +use crate::raw::{Bucket, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap { + /// Creates a raw entry builder for the `HashMap`. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the `HashMap` into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and + /// more foolproof APIs like `entry` should be preferred when possible. + /// + /// In particular, the hash used to initialized the raw entry must still be + /// consistent with the hash of the key that is ultimately stored in the entry. + /// This is because implementations of `HashMap` may need to recompute hashes + /// when resizing, at which point only the keys are available. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map[&"a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = compute_hash(map.hasher(), &"c"); + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry().from_key(&"c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = compute_hash(map.hasher(), &key); + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map[&"d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get(&"d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S, A> { + RawEntryBuilderMut { map: self } + } + + /// Creates a raw immutable entry builder for the `HashMap`. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// `get` should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = compute_hash(map.hasher(), k); + /// let v = map.get(&k).cloned(); + /// let kv = v.as_ref().map(|v| (&k, v)); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry().from_key(&k), kv); + /// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S, A> { + RawEntryBuilder { map: self } + } +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry_mut`] docs for usage examples. +/// +/// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{RawEntryBuilderMut, RawEntryMut::Vacant, RawEntryMut::Occupied}; +/// use hashbrown::HashMap; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16)]); +/// assert_eq!(map.len(), 6); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let builder: RawEntryBuilderMut<_, _, _> = map.raw_entry_mut(); +/// +/// // Existing key +/// match builder.from_key(&6) { +/// Vacant(_) => unreachable!(), +/// Occupied(view) => assert_eq!(view.get(), &16), +/// } +/// +/// for key in 0..12 { +/// let hash = compute_hash(map.hasher(), &key); +/// let value = map.get(&key).cloned(); +/// let key_value = value.as_ref().map(|v| (&key, v)); +/// +/// println!("Key: {} and value: {:?}", key, value); +/// +/// match map.raw_entry_mut().from_key(&key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// } +/// +/// assert_eq!(map.len(), 6); +/// ``` +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator = Global> { + map: &'a mut HashMap, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This is a lower-level version of [`Entry`]. +/// +/// [`Entry`]: crate::hash_map::Entry +/// +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. +/// +/// [`raw_entry_mut`]: HashMap::raw_entry_mut +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([('a', 1), ('b', 2), ('c', 3)]); +/// assert_eq!(map.len(), 3); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// // Existing key (insert) +/// let raw: RawEntryMut<_, _, _> = map.raw_entry_mut().from_key(&'a'); +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = raw.insert('a', 10); +/// assert_eq!(map.len(), 3); +/// +/// // Nonexistent key (insert) +/// map.raw_entry_mut().from_key(&'d').insert('d', 40); +/// assert_eq!(map.len(), 4); +/// +/// // Existing key (or_insert) +/// let hash = compute_hash(map.hasher(), &'b'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'b') +/// .or_insert('b', 20); +/// assert_eq!(kv, (&mut 'b', &mut 2)); +/// *kv.1 = 20; +/// assert_eq!(map.len(), 4); +/// +/// // Nonexistent key (or_insert) +/// let hash = compute_hash(map.hasher(), &'e'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'e') +/// .or_insert('e', 50); +/// assert_eq!(kv, (&mut 'e', &mut 50)); +/// assert_eq!(map.len(), 5); +/// +/// // Existing key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'c'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'c') +/// .or_insert_with(|| ('c', 30)); +/// assert_eq!(kv, (&mut 'c', &mut 3)); +/// *kv.1 = 30; +/// assert_eq!(map.len(), 5); +/// +/// // Nonexistent key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'f'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'f') +/// .or_insert_with(|| ('f', 60)); +/// assert_eq!(kv, (&mut 'f', &mut 60)); +/// assert_eq!(map.len(), 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [('a', 10), ('b', 20), ('c', 30), ('d', 40), ('e', 50), ('f', 60)]); +/// ``` +pub enum RawEntryMut<'a, K, V, S, A: Allocator = Global> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(_) => { } + /// } + /// ``` + Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.raw_entry_mut().from_key("a") { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(_) => { } + /// } + /// ``` + Vacant(RawVacantEntryMut<'a, K, V, S, A>), +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = map.raw_entry_mut().from_key(&"a").insert("a", 100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// let new_v = (*v) * 10; +/// *v = new_v; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.raw_entry().from_key(&"c"), None); +/// assert_eq!(map.len(), 2); +/// +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "b") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("b", 20)); +/// } +/// } +/// assert_eq!(map.get(&"b"), None); +/// assert_eq!(map.len(), 1); +/// ``` +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator = Global> { + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawVacantEntryMut}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let raw_v: RawVacantEntryMut<_, _, _> = match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(view) => view, +/// RawEntryMut::Occupied(_) => unreachable!(), +/// }; +/// raw_v.insert("a", 10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"b") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// let (k, value) = view.insert("b", 2); +/// assert_eq!((*k, *value), ("b", 2)); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "c") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// assert_eq!(view.insert("c", 30), (&mut "c", &mut 30)); +/// } +/// } +/// assert!(map[&"c"] == 30 && map.len() == 3); +/// ``` +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator = Global> { + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry`] docs for usage examples. +/// +/// [`HashMap::raw_entry`]: HashMap::raw_entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, RawEntryBuilder}; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 10), (2, 20), (3, 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// for k in 0..6 { +/// let hash = compute_hash(map.hasher(), &k); +/// let v = map.get(&k).cloned(); +/// let kv = v.as_ref().map(|v| (&k, v)); +/// +/// println!("Key: {} and value: {:?}", k, v); +/// let builder: RawEntryBuilder<_, _, _> = map.raw_entry(); +/// assert_eq!(builder.from_key(&k), kv); +/// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); +/// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); +/// } +/// ``` +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator = Global> { + map: &'a HashMap, +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key(&key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + S: BuildHasher, + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Creates a `RawEntryMut` from the given key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key_hashed_nocheck(hash, &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[inline] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + Q: Equivalent + ?Sized, + { + self.from_hash(hash, equivalent(k)) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_hash(hash, |k| k == &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + self.search(hash, is_match) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + match self.map.table.find(hash, |(k, _)| is_match(k)) { + Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { + elem, + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + None => RawEntryMut::Vacant(RawVacantEntryMut { + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { + /// Access an immutable entry by key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// assert_eq!(map.raw_entry().from_key(&key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: Hash + Equivalent + ?Sized, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Access an immutable entry by a key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> + where + Q: Equivalent + ?Sized, + { + self.from_hash(hash, equivalent(k)) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + match self.map.table.get(hash, |(k, _)| is_match(k)) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + /// Access an immutable entry by hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_hash(hash, |k| k == &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + self.search(hash, is_match) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry, and returns a `RawOccupiedEntryMut`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37); + /// + /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(mut entry) => { + entry.insert(value); + entry + } + RawEntryMut::Vacant(entry) => entry.insert_entry(key, value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { + /// ("poneyland", "hoho".to_string()) + /// }); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => { + let (k, v) = default(); + entry.insert(k, v) + } + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 0); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + match self { + RawEntryMut::Occupied(mut entry) => { + { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + RawEntryMut::Occupied(entry) + } + RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } +} + +impl<'a, K, V, S, A: Allocator> RawOccupiedEntryMut<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.key(), &"a") + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Gets a mutable reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// *o.key_mut() = key_two.clone(); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key_mut(&mut self) -> &mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Converts the entry into a mutable reference to the key in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => inside_key = o.into_key(), + /// } + /// *inside_key = key_two.clone(); + /// + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> &'a mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get(), &100), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let value: &mut u32; + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => value = o.into_mut(), + /// } + /// *value += 900; + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => *o.get_mut() += 900, + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get_key_value(), (&"a", &100)), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value(&self) -> (&K, &V) { + unsafe { + let (key, value) = self.elem.as_ref(); + (key, value) + } + } + + /// Gets a mutable reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let (inside_key, inside_value) = o.get_key_value_mut(); + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// } + /// } + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// let inside_value: &mut u32; + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => { + /// let tuple = o.into_key_value(); + /// inside_key = tuple.0; + /// inside_value = tuple.1; + /// } + /// } + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => assert_eq!(o.insert(1000), 100), + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let old_key = o.insert_key(key_two.clone()); + /// assert!(Rc::ptr_eq(&old_key, &key_one)); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove(), 100), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove_entry(), ("a", 100)), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let raw_entry = match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 100); + /// Some(v + 900) + /// }), + /// }; + /// let raw_entry = match raw_entry { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 1000); + /// None + /// }), + /// }; + /// match raw_entry { + /// RawEntryMut::Vacant(_) => { }, + /// RawEntryMut::Occupied(_) => panic!(), + /// }; + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let tag = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if tag.is_none() { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"c") { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!(v.insert("c", 300), (&mut "c", &mut 300)), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + self.insert_hashed_nocheck(hash, key, value) + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "c"; + /// let hash = compute_hash(map.hasher(), &key); + /// + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_hashed_nocheck(hash, key, 300), + /// (&mut "c", &mut 300) + /// ), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let &mut (ref mut k, ref mut v) = self.table.insert_entry( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + (k, v) + } + + /// Set the value of an entry with a custom hasher function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn make_hasher(hash_builder: &S) -> impl Fn(&K) -> u64 + '_ + /// where + /// K: Hash + ?Sized, + /// S: BuildHasher, + /// { + /// move |key: &K| { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash_builder = map.hasher().clone(); + /// let hash = make_hasher(&hash_builder)(&key); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| q == &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_with_hasher(hash, key, 100, make_hasher(&hash_builder)), + /// (&mut "a", &mut 100) + /// ), + /// } + /// map.extend([("b", 200), ("c", 300), ("d", 400), ("e", 500), ("f", 600)]); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_hasher( + self, + hash: u64, + key: K, + value: V, + hasher: H, + ) -> (&'a mut K, &'a mut V) + where + H: Fn(&K) -> u64, + { + let &mut (ref mut k, ref mut v) = self + .table + .insert_entry(hash, (key, value), |x| hasher(&x.0)); + (k, v) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + let elem = self.table.insert( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + RawOccupiedEntryMut { + elem, + table: self.table, + hash_builder: self.hash_builder, + } + } +} + +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +impl Debug for RawEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), + } + } +} + +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() + } +} + +impl Debug for RawEntryBuilder<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +#[cfg(test)] +mod test_map { + use super::HashMap; + use super::RawEntryMut; + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1_i32, 10_i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + super::make_hash::(map.hasher(), &k) + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).copied(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } + } + + #[test] + fn test_key_without_hash_impl() { + #[derive(Debug)] + struct IntWrapper(u64); + + let mut m: HashMap = HashMap::default(); + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 0"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(0, IntWrapper(0), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_none()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(1, |k| k.0 == 1) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 1"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(1, IntWrapper(1), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let occupied_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(e) => e, + RawEntryMut::Vacant(..) => panic!("Couldn't find entry for key 0"), + }; + occupied_entry.remove(); + } + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } +} diff --git a/deps/crates/vendor/hashbrown/src/rustc_entry.rs b/deps/crates/vendor/hashbrown/src/rustc_entry.rs new file mode 100644 index 00000000000000..d442f79036ba0a --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/rustc_entry.rs @@ -0,0 +1,563 @@ +use self::RustcEntry::*; +use crate::alloc::{Allocator, Global}; +use crate::map::{Drain, HashMap, IntoIter, Iter, IterMut, make_hash}; +use crate::raw::{Bucket, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`]. +/// +/// [`rustc_entry`]: HashMap::rustc_entry +pub enum RustcEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V, A>), +} + +impl Debug for RustcEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +pub struct RustcOccupiedEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, +} + +unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> +where + K: Send, + V: Send, + A: Allocator + Send, +{ +} +unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> +where + K: Sync, + V: Sync, + A: Allocator + Sync, +{ +} + +impl Debug for RustcOccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +pub struct RustcVacantEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + hash: u64, + key: K, + table: &'a mut RawTable<(K, V), A>, +} + +impl Debug for RustcVacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> { + /// Sets the value of the entry, and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.rustc_entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + match self { + Vacant(entry) => entry.insert_entry(value), + Occupied(mut entry) => { + entry.insert(value); + entry + } + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } +} + +impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V { + unsafe { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + &mut bucket.as_mut().1 + } + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) }; + RustcOccupiedEntry { + elem: bucket, + table: self.table, + } + } +} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} diff --git a/deps/crates/vendor/hashbrown/src/scopeguard.rs b/deps/crates/vendor/hashbrown/src/scopeguard.rs new file mode 100644 index 00000000000000..26532b84bfd129 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/scopeguard.rs @@ -0,0 +1,72 @@ +// Extracted from the scopeguard crate +use core::{ + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr, +}; + +pub(crate) struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub(crate) fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + pub(crate) fn into_inner(guard: Self) -> T { + // Cannot move out of Drop-implementing types, so + // ptr::read the value out of a ManuallyDrop + // Don't use mem::forget as that might invalidate value + let guard = ManuallyDrop::new(guard); + unsafe { + let value = ptr::read(&raw const guard.value); + // read the closure so that it is dropped + let _ = ptr::read(&raw const guard.dropfn); + value + } + } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value); + } +} diff --git a/deps/crates/vendor/hashbrown/src/set.rs b/deps/crates/vendor/hashbrown/src/set.rs new file mode 100644 index 00000000000000..cea1690f13eb68 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/set.rs @@ -0,0 +1,3089 @@ +use crate::{Equivalent, TryReserveError}; +use core::cell::UnsafeCell; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign}; + +use super::map::{self, HashMap, Keys}; +use crate::DefaultHashBuilder; +use crate::alloc::{Allocator, Global}; +use crate::raw::RawExtractIf; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// A hash set implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or +/// unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashSet` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`]. This will in the +/// future be implied by [`Eq`]. +/// +/// ``` +/// use hashbrown::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{:?}", x); +/// } +/// ``` +/// +/// A `HashSet` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashSet; +/// +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].into_iter().collect(); +/// // use the values stored in the set +/// ``` +/// +/// [`Cell`]: std::cell::Cell +/// [`RefCell`]: std::cell::RefCell +pub struct HashSet { + pub(crate) map: HashMap, +} + +impl Clone for HashSet { + fn clone(&self) -> Self { + HashSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +#[cfg(feature = "default-hasher")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher`](HashSet::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher`](HashSet::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity), + } + } +} + +#[cfg(feature = "default-hasher")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher_in`](HashSet::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + map: HashMap::new_in(alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher_in`](HashSet::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_in(capacity, alloc), + } + } +} + +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + iter: self.map.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.into_iter().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(|k, _| f(k)); + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashSet::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.map.table.iter() }, + table: &mut self.map.table, + }, + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.map.clear(); + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } +} + +impl HashSet +where + A: Allocator, +{ + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.map.allocator() + } + + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] + pub const fn with_hasher_in(hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_hasher_in(hasher, alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`std::hash::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[must_use] + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_and_hasher_in(capacity, hasher, alloc), + } + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = set.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + self.map.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashSet::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`abort`]: stdalloc::alloc::handle_alloc_error + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S, A> { + Difference { + iter: self.iter(), + other, + } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S, A> { + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Intersection { + iter: smaller.iter(), + other: larger, + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S, A> { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Union { + iter: larger.iter().chain(smaller.difference(larger)), + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + /// + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains(&self, value: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + /// + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.get_key_value(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert(&mut self, value: T) -> &T { + match self.map.entry(value) { + map::Entry::Occupied(entry) => entry, + map::Entry::Vacant(entry) => entry.insert_entry(()), + } + .into_entry() + .0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + /// + /// The following example will panic because the new value doesn't match. + /// + /// ```should_panic + /// let mut set = hashbrown::HashSet::new(); + /// set.get_or_insert_with("rust", |_| String::new()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + Q: Hash + Equivalent + ?Sized, + F: FnOnce(&Q) -> T, + { + match self.map.entry_ref(value) { + map::EntryRef::Occupied(entry) => entry, + map::EntryRef::Vacant(entry) => entry.insert_entry_with_key(f(value), ()), + } + .into_entry() + .0 + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert(); + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { + match self.map.entry(value) { + map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), + map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), + } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + pub fn is_disjoint(&self, other: &Self) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + pub fn is_subset(&self, other: &Self) -> bool { + self.len() <= other.len() && self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert a value the set without checking if the value already exists in the set. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the set. + /// For example, when constructing a set from another set, we know + /// that values are unique. + /// + /// # Safety + /// + /// This operation is safe if a value does not exist in the set. + /// + /// However, if a value exists in the set already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the set + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// However this operation is still unsafe because the resulting `HashSet` + /// may be passed to unsafe code which does expect the set to behave + /// correctly, and would cause unsoundness as a result. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn insert_unique_unchecked(&mut self, value: T) -> &T { + unsafe { self.map.insert_unique_unchecked(value, ()).0 } + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(&mut self, value: T) -> Option { + let value = UnsafeCell::new(value); + // SAFETY: We know the key is no longer accessed after the initial check. + match self.map.entry_ref(unsafe { &*value.get() }) { + map::EntryRef::Occupied(mut entry) => { + // SAFETY: We know the key will not be accessed any more, and + // that the key is equivalent to the one in the entry. + Some(unsafe { entry.replace_key_unchecked(value.into_inner()) }) + } + map::EntryRef::Vacant(entry) => { + // SAFETY: A value is equivalent to itself. + unsafe { + entry.insert_with_key_unchecked(value.into_inner(), ()); + } + None + } + } + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + /// + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent + ?Sized, + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + /// + #[cfg_attr(feature = "inline-more", inline)] + pub fn take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent + ?Sized, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.remove_entry(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Returns the total amount of memory allocated internally by the hash + /// set, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.map.allocation_size() + } +} + +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for HashSet +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl From> for HashSet +where + A: Allocator, +{ + fn from(map: HashMap) -> Self { + Self { map } + } +} + +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher_in(Default::default(), Default::default()); + set.extend(iter); + set + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "default-hasher")] +impl From<[T; N]> for HashSet +where + T: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set1 = HashSet::from([1, 2, 3, 4]); + /// let set2: HashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + arr.into_iter().collect() + } +} + +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.map.extend(iter.into_iter().map(|k| (k, ()))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: T) { + self.map.insert(k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().copied()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: &'a T) { + self.map.insert(*k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl Default for HashSet +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +impl BitOrAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the union of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a |= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor_assign(&mut self, rhs: &HashSet) { + for item in rhs { + if !self.contains(item) { + self.insert(item.clone()); + } + } + } +} + +impl BitAndAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the intersection of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// a &= &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand_assign(&mut self, rhs: &HashSet) { + self.retain(|item| rhs.contains(item)); + } +} + +impl BitXorAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the symmetric difference of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a ^= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor_assign(&mut self, rhs: &HashSet) { + for item in rhs { + match self.map.entry_ref(item) { + map::EntryRef::Occupied(entry) => { + entry.remove(); + } + map::EntryRef::Vacant(entry) => { + entry.insert(()); + } + } + } + } +} + +impl SubAssign<&HashSet> for HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher, + A: Allocator, +{ + /// Modifies this set to contain the difference of `self` and `rhs`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// a -= &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &a { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub_assign(&mut self, rhs: &HashSet) { + if rhs.len() < self.len() { + for item in rhs { + self.remove(item); + } + } else { + self.retain(|item| !rhs.contains(item)); + } + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`iter`]: HashSet::iter +pub struct Iter<'a, K> { + iter: Keys<'a, K, ()>, +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: HashSet::into_iter +pub struct IntoIter { + iter: map::IntoIter, +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`drain`]: HashSet::drain +pub struct Drain<'a, K, A: Allocator = Global> { + iter: map::Drain<'a, K, (), A>, +} + +/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its +/// documentation for more. +/// +/// [`extract_if`]: HashSet::extract_if +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, (K, ()), A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`intersection`]: HashSet::intersection +pub struct Intersection<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`difference`]: HashSet::difference +pub struct Difference<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`symmetric_difference`]: HashSet::symmetric_difference +pub struct SymmetricDifference<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`union`]: HashSet::union +pub struct Union<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +impl Clone for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} +impl Default for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Iter { + iter: Default::default(), + } + } +} +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} +impl ExactSizeIterator for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Iter<'_, K> {} + +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IntoIter { + iter: Default::default(), + } + } +} +impl Iterator for IntoIter { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for Drain<'_, K, A> { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for Drain<'_, K, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Drain<'_, K, A> {} + +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for ExtractIf<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner + .next(|&mut (ref k, ())| (self.f)(k)) + .map(|(k, ())| k) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} + +impl Clone for Intersection<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + f(acc, elt) + } else { + acc + } + }) + } +} + +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl Clone for Difference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + (lower.saturating_sub(self.other.len()), upper) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + acc + } else { + f(acc, elt) + } + }) + } +} + +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for SymmetricDifference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for Union<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`entry`]: HashSet::entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_, _> = set.entry("a"); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +pub enum Entry<'a, T, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<_> = ["a", "b"].into(); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S, A>), +} + +impl fmt::Debug for Entry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o: OccupiedEntry<_, _> = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, T, S, A: Allocator = Global> { + inner: map::OccupiedEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, VacantEntry}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v: VacantEntry<_, _> = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => { view.insert(); }, +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +pub struct VacantEntry<'a, T, S, A: Allocator = Global> { + inner: map::VacantEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for VacantEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> T { + self.inner.remove_entry().0 + } +} + +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_value(self) -> T { + self.inner.into_key() + } + + /// Sets the value of the entry with the `VacantEntry`'s value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { + inner: self.inner.insert_entry(()), + } + } +} + +#[expect(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new, A: Allocator>(v: IntoIter<&'static str, A>) -> IntoIter<&'new str, A> { + v + } + fn difference<'a, 'new, A: Allocator>( + v: Difference<'a, &'static str, DefaultHashBuilder, A>, + ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn symmetric_difference<'a, 'new, A: Allocator>( + v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, + ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn intersection<'a, 'new, A: Allocator>( + v: Intersection<'a, &'static str, DefaultHashBuilder, A>, + ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn union<'a, 'new, A: Allocator>( + v: Union<'a, &'static str, DefaultHashBuilder, A>, + ) -> Union<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn drain<'new, A: Allocator>(d: Drain<'static, &'static str, A>) -> Drain<'new, &'new str, A> { + d + } +} + +#[cfg(test)] +mod test_set { + use super::{Equivalent, HashSet}; + use crate::DefaultHashBuilder; + use crate::map::make_hash; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); + } + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_sub_assign() { + let mut a: HashSet<_> = vec![1, 2, 3, 4, 5].into_iter().collect(); + let b: HashSet<_> = vec![4, 5, 6].into_iter().collect(); + + a -= &b; + + let mut i = 0; + let expected = [1, 2, 3]; + for x in &a { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_map() { + let mut a = crate::HashMap::new(); + a.insert(1, ()); + a.insert(2, ()); + a.insert(3, ()); + a.insert(4, ()); + + let a: HashSet<_> = a.into(); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().copied().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{set:?}"); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + if !s.is_empty() { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } + } + + #[test] + fn test_replace() { + use core::hash; + + #[derive(Debug)] + #[expect(dead_code)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend([2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } + + #[test] + fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().copied().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } + + #[test] + fn test_extract_if() { + { + let mut set: HashSet = (0..8).collect(); + let drained = set.extract_if(|&k| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![0, 2, 4, 6], out); + assert_eq!(set.len(), 4); + } + { + let mut set: HashSet = (0..8).collect(); + set.extract_if(|&k| k % 2 == 0).for_each(drop); + assert_eq!(set.len(), 4, "Removes non-matching items on drop"); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET; + set.insert(19); + assert!(set.contains(&19)); + } + + #[test] + fn rehash_in_place() { + let mut set = HashSet::new(); + + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } + + #[test] + fn test_allocation_info() { + assert_eq!(HashSet::<()>::new().allocation_size(), 0); + assert_eq!(HashSet::::new().allocation_size(), 0); + assert!(HashSet::::with_capacity(1).allocation_size() > core::mem::size_of::()); + } + + #[test] + fn duplicate_insert() { + let mut set = HashSet::new(); + set.insert(1); + set.get_or_insert_with(&1, |_| 1); + set.get_or_insert_with(&1, |_| 1); + assert!([1].iter().eq(set.iter())); + } + + #[test] + #[should_panic] + fn some_invalid_equivalent() { + use core::hash::{Hash, Hasher}; + struct Invalid { + count: u32, + other: u32, + } + + struct InvalidRef { + count: u32, + other: u32, + } + + impl PartialEq for Invalid { + fn eq(&self, other: &Self) -> bool { + self.count == other.count && self.other == other.other + } + } + impl Eq for Invalid {} + + impl Equivalent for InvalidRef { + fn equivalent(&self, key: &Invalid) -> bool { + self.count == key.count && self.other == key.other + } + } + impl Hash for Invalid { + fn hash(&self, state: &mut H) { + self.count.hash(state); + } + } + impl Hash for InvalidRef { + fn hash(&self, state: &mut H) { + self.count.hash(state); + } + } + let mut set: HashSet = HashSet::new(); + let key = InvalidRef { count: 1, other: 1 }; + let value = Invalid { count: 1, other: 2 }; + if make_hash(set.hasher(), &key) == make_hash(set.hasher(), &value) { + set.get_or_insert_with(&key, |_| value); + } + } +} diff --git a/deps/crates/vendor/hashbrown/src/table.rs b/deps/crates/vendor/hashbrown/src/table.rs new file mode 100644 index 00000000000000..f50f575f6c0ac2 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/table.rs @@ -0,0 +1,3197 @@ +use core::{fmt, iter::FusedIterator, marker::PhantomData, ptr::NonNull}; + +use crate::{ + TryReserveError, + alloc::{Allocator, Global}, + control::Tag, + raw::{ + Bucket, FullBucketsIndices, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawIterHash, + RawIterHashIndices, RawTable, + }, +}; + +/// Low-level hash table with explicit hashing. +/// +/// The primary use case for this type over [`HashMap`] or [`HashSet`] is to +/// support types that do not implement the [`Hash`] and [`Eq`] traits, but +/// instead require additional data not contained in the key itself to compute a +/// hash and compare two elements for equality. +/// +/// Examples of when this can be useful include: +/// - An `IndexMap` implementation where indices into a `Vec` are stored as +/// elements in a `HashTable`. Hashing and comparing the elements +/// requires indexing the associated `Vec` to get the actual value referred to +/// by the index. +/// - Avoiding re-computing a hash when it is already known. +/// - Mutating the key of an element in a way that doesn't affect its hash. +/// +/// To achieve this, `HashTable` methods that search for an element in the table +/// require a hash value and equality function to be explicitly passed in as +/// arguments. The method will then iterate over the elements with the given +/// hash and call the equality function on each of them, until a match is found. +/// +/// In most cases, a `HashTable` will not be exposed directly in an API. It will +/// instead be wrapped in a helper type which handles the work of calculating +/// hash values and comparing elements. +/// +/// Due to its low-level nature, this type provides fewer guarantees than +/// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot +/// yourself in the foot by having multiple elements with identical keys in the +/// table. The table itself will still function correctly and lookups will +/// arbitrarily return one of the matching elements. However you should avoid +/// doing this because it changes the runtime of hash table operations from +/// `O(1)` to `O(k)` where `k` is the number of duplicate entries. +/// +/// [`HashMap`]: super::HashMap +/// [`HashSet`]: super::HashSet +/// [`Hash`]: core::hash::Hash +pub struct HashTable +where + A: Allocator, +{ + pub(crate) raw: RawTable, +} + +impl HashTable { + /// Creates an empty `HashTable`. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::new(); + /// assert_eq!(table.len(), 0); + /// assert_eq!(table.capacity(), 0); + /// ``` + #[must_use] + pub const fn new() -> Self { + Self { + raw: RawTable::new(), + } + } + + /// Creates an empty `HashTable` with the specified capacity. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::with_capacity(10); + /// assert_eq!(table.len(), 0); + /// assert!(table.capacity() >= 10); + /// ``` + #[must_use] + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +impl HashTable +where + A: Allocator, +{ + /// Creates an empty `HashTable` using the given allocator. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use bumpalo::Bump; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::new_in(&bump); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// + /// // The created HashTable also doesn't allocate memory + /// assert_eq!(table.capacity(), 0); + /// + /// // Now we insert element inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// // We can see that the HashTable holds 1 element + /// assert_eq!(table.len(), 1); + /// // And it also allocates some capacity + /// assert!(table.capacity() > 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[must_use] + pub const fn new_in(alloc: A) -> Self { + Self { + raw: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashTable` with the specified capacity using the given allocator. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use bumpalo::Bump; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::with_capacity_in(5, &bump); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = table.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// table.insert_unique(hasher(&"Two"), "Two", hasher); + /// table.insert_unique(hasher(&"Three"), "Three", hasher); + /// table.insert_unique(hasher(&"Four"), "Four", hasher); + /// table.insert_unique(hasher(&"Five"), "Five", hasher); + /// + /// // We can see that the HashTable holds 5 elements + /// assert_eq!(table.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(table.capacity(), empty_map_capacity) + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[must_use] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + raw: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the underlying allocator. + pub fn allocator(&self) -> &A { + self.raw.allocator() + } + + /// Returns a reference to an entry in the table with the given hash and + /// which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); + /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + self.raw.get(hash, eq) + } + + /// Returns a mutable reference to an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// When mutating an entry, you should ensure that it still retains the same + /// hash value as when it was inserted, otherwise lookups of that entry may + /// fail to find it. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { + /// val.1 = "b"; + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + self.raw.get_mut(hash, eq) + } + + /// Returns an `OccupiedEntry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table. Call + /// [`HashTable::entry`] instead if you wish to insert an entry if the + /// lookup fails. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { + /// entry.remove(); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.find(hash, eq) { + Some(bucket) => Ok(OccupiedEntry { + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns the bucket index in the table for an entry with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to store a borrow-free "reference" to the entry, later using + /// [`get_bucket`][Self::get_bucket], [`get_bucket_mut`][Self::get_bucket_mut], or + /// [`get_bucket_entry`][Self::get_bucket_entry] to access it again without hash probing. + /// + /// The index is only meaningful as long as the table is not resized and no entries are added + /// or removed. After such changes, it may end up pointing to a different entry or none at all. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 1), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 2), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 3), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert_eq!(table.get_bucket(index), Some(&(2, 2))); + /// + /// // Mutation would invalidate any normal reference + /// for (_key, value) in &mut table { + /// *value *= 11; + /// } + /// + /// // The index still reaches the same key with the updated value + /// assert_eq!(table.get_bucket(index), Some(&(2, 22))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_bucket_index(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + match self.raw.find(hash, eq) { + Some(bucket) => Some(unsafe { self.raw.bucket_index(&bucket) }), + None => None, + } + } + + /// Returns an `Entry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table, or insert a new + /// entry with the given hash if one doesn't already exist. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// This method may grow the table in preparation for an insertion. Call + /// [`HashTable::find_entry`] if this is undesirable. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) + /// { + /// entry.remove(); + /// } + /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { + /// entry.insert((2, "b")); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Entry<'_, T, A> { + match self.raw.find_or_find_insert_index(hash, eq, hasher) { + Ok(bucket) => Entry::Occupied(OccupiedEntry { + bucket, + table: self, + }), + Err(insert_index) => Entry::Vacant(VacantEntry { + tag: Tag::full(hash), + index: insert_index, + table: self, + }), + } + } + + /// Returns an `OccupiedEntry` for the given bucket index in the table, + /// or `AbsentEntry` if it is unoccupied or out of bounds. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// + /// assert!(table.get_bucket_entry(usize::MAX).is_err()); + /// + /// let occupied_entry = table.get_bucket_entry(index).unwrap(); + /// assert_eq!(occupied_entry.get(), &(2, 'b')); + /// assert_eq!(occupied_entry.remove().0, (2, 'b')); + /// + /// assert!(table.find(hasher(&2), |val| val.0 == 2).is_none()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_bucket_entry( + &mut self, + index: usize, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.checked_bucket(index) { + Some(bucket) => Ok(OccupiedEntry { + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns an `OccupiedEntry` for the given bucket index in the table, + /// without checking whether the index is in-bounds or occupied. + /// + /// For a safe alternative, see [`get_bucket_entry`](Self::get_bucket_entry). + /// + /// # Safety + /// + /// It is *[undefined behavior]* to call this method with an index that is + /// out-of-bounds or unoccupied, even if the resulting entry is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert!(std::ptr::eq( + /// table.get_bucket_entry(index).unwrap().into_mut(), + /// unsafe { table.get_bucket_entry_unchecked(index).into_mut() }, + /// )); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn get_bucket_entry_unchecked(&mut self, index: usize) -> OccupiedEntry<'_, T, A> { + OccupiedEntry { + bucket: unsafe { self.raw.bucket(index) }, + table: self, + } + } + + /// Gets a reference to an entry in the table at the given bucket index, + /// or `None` if it is unoccupied or out of bounds. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert_eq!(table.get_bucket(index), Some(&(2, 'b'))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_bucket(&self, index: usize) -> Option<&T> { + self.raw.get_bucket(index) + } + + /// Gets a reference to an entry in the table at the given bucket index, + /// without checking whether the index is in-bounds or occupied. + /// + /// For a safe alternative, see [`get_bucket`](Self::get_bucket). + /// + /// # Safety + /// + /// It is *[undefined behavior]* to call this method with an index that is + /// out-of-bounds or unoccupied, even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert!(std::ptr::eq( + /// table.get_bucket(index).unwrap(), + /// unsafe { table.get_bucket_unchecked(index) }, + /// )); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn get_bucket_unchecked(&self, index: usize) -> &T { + unsafe { self.raw.bucket(index).as_ref() } + } + + /// Gets a mutable reference to an entry in the table at the given bucket index, + /// or `None` if it is unoccupied or out of bounds. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert_eq!(table.get_bucket(index), Some(&(2, 'b'))); + /// if let Some((_key, value)) = table.get_bucket_mut(index) { + /// *value = 'B'; + /// } + /// assert_eq!(table.get_bucket(index), Some(&(2, 'B'))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_bucket_mut(&mut self, index: usize) -> Option<&mut T> { + self.raw.get_bucket_mut(index) + } + + /// Gets a mutable reference to an entry in the table at the given bucket index, + /// without checking whether the index is in-bounds or occupied. + /// + /// For a safe alternative, see [`get_bucket_mut`](Self::get_bucket_mut). + /// + /// # Safety + /// + /// It is *[undefined behavior]* to call this method with an index that is + /// out-of-bounds or unoccupied, even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// let index = table.find_bucket_index(hasher(&2), |val| val.0 == 2).unwrap(); + /// assert!(std::ptr::eq( + /// table.get_bucket_mut(index).unwrap(), + /// unsafe { table.get_bucket_unchecked_mut(index) }, + /// )); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn get_bucket_unchecked_mut(&mut self, index: usize) -> &mut T { + unsafe { self.raw.bucket(index).as_mut() } + } + + /// Inserts an element into the `HashTable` with the given hash value, but + /// without checking whether an equivalent element already exists within the + /// table. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut v = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert_unique( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> OccupiedEntry<'_, T, A> { + let bucket = self.raw.insert(hash, value, hasher); + OccupiedEntry { + bucket, + table: self, + } + } + + /// Clears the table, removing all values. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut v = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// v.clear(); + /// assert!(v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn clear(&mut self) { + self.raw.clear(); + } + + /// Shrinks the capacity of the table as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to_fit(hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(self.len(), hasher); + } + + /// Shrinks the capacity of the table with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to(10, hasher); + /// assert!(table.capacity() >= 10); + /// table.shrink_to(0, hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(min_capacity, hasher); + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`abort`]: stdalloc::alloc::handle_alloc_error + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.reserve(10, hasher); + /// assert!(table.capacity() >= 10); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + self.raw.reserve(additional, hasher); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table + /// .try_reserve(10, hasher) + /// .expect("why is the test harness OOMing on 10 bytes?"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + self.raw.try_reserve(additional, hasher) + } + + /// Returns the raw number of buckets allocated in the table. + /// + /// This is an upper bound on any methods that take or return a bucket index, + /// as opposed to the usable [`capacity`](Self::capacity) for entries which is + /// reduced by an unspecified load factor. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 'a'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 'b'), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 'c'), |val| hasher(&val.0)); + /// + /// // Each entry is available at some index in the bucket range. + /// let count = (0..table.num_buckets()) + /// .filter_map(|i| table.get_bucket(i)) + /// .count(); + /// assert_eq!(count, 3); + /// + /// assert_eq!(table.get_bucket(table.num_buckets()), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn num_buckets(&self) -> usize { + self.raw.num_buckets() + } + + /// Returns the number of elements the table can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let table: HashTable = HashTable::with_capacity(100); + /// assert!(table.capacity() >= 100); + /// ``` + pub fn capacity(&self) -> usize { + self.raw.capacity() + } + + /// Returns the number of elements in the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert_eq!(v.len(), 0); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert_eq!(v.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert!(v.is_empty()); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert!(!v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "a", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for x in table.iter() { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with mutable references to the elements. + /// The iterator element type is `&'a mut T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// + /// // Update all values + /// for val in table.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [2, 4, 6]); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with pointers to the elements. + /// The iterator element type is `NonNull`. + /// + /// This iterator is intended for APIs where only part of the elements are + /// mutable, with the remainder being immutable. In these cases, wrapping + /// the ordinary mutable iterator is incorrect because all components of + /// the element type will be [invariant]. A correct implementation will use + /// an appropriate [`PhantomData`] marker to make the immutable parts + /// [covariant] and the mutable parts invariant. + /// + /// [invariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.invariant + /// [covariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.covariant + /// + /// See the documentation for [`UnsafeIter`] for more information on how + /// to correctly use this. + pub fn unsafe_iter(&mut self) -> UnsafeIter<'_, T> { + UnsafeIter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator producing the `usize` indices of all occupied buckets. + /// + /// The order in which the iterator yields indices is unspecified + /// and may change in the future. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "a", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for index in table.iter_buckets() { + /// println!("{index}: {}", table.get_bucket(index).unwrap()); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_buckets(&self) -> IterBuckets<'_, T> { + IterBuckets { + inner: unsafe { self.raw.full_buckets_indices() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements which may match a hash. + /// The iterator element type is `&'a T`. + /// + /// This iterator may return elements from the table that have a hash value + /// different than the one provided. You should always validate the returned + /// values before using them. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "a", hasher); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "c", hasher); + /// + /// // Will print "a" and "b" (and possibly "c") in an arbitrary order. + /// for x in table.iter_hash(hasher(&"a")) { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_hash(&self, hash: u64) -> IterHash<'_, T> { + IterHash { + inner: unsafe { self.raw.iter_hash(hash) }, + marker: PhantomData, + } + } + + /// A mutable iterator visiting all elements which may match a hash. + /// The iterator element type is `&'a mut T`. + /// + /// This iterator may return elements from the table that have a hash value + /// different than the one provided. You should always validate the returned + /// values before using them. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 2, hasher); + /// table.insert_unique(hasher(&1), 3, hasher); + /// table.insert_unique(hasher(&2), 5, hasher); + /// + /// // Update matching values + /// for val in table.iter_hash_mut(hasher(&1)) { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The values will contain 4 and 6 and may contain either 5 or 10. + /// assert!(vec.contains(&4)); + /// assert!(vec.contains(&6)); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_hash_mut(&mut self, hash: u64) -> IterHashMut<'_, T> { + IterHashMut { + inner: unsafe { self.raw.iter_hash(hash) }, + marker: PhantomData, + } + } + + /// An iterator producing the `usize` indices of all buckets which may match a hash. + /// + /// This iterator may return indices from the table that have a hash value + /// different than the one provided. You should always validate the returned + /// values before using them. + /// + /// The order in which the iterator yields indices is unspecified + /// and may change in the future. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "a", hasher); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "c", hasher); + /// + /// // Will print the indices with "a" and "b" (and possibly "c") in an arbitrary order. + /// for index in table.iter_hash_buckets(hasher(&"a")) { + /// println!("{index}: {}", table.get_bucket(index).unwrap()); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_hash_buckets(&self, hash: u64) -> IterHashBuckets<'_, T> { + IterHashBuckets { + inner: unsafe { self.raw.iter_hash_buckets(hash) }, + marker: PhantomData, + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=6 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// table.retain(|&mut x| x % 2 == 0); + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.raw.iter() { + if !f(item.as_mut()) { + self.raw.erase(item); + } + } + } + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=3 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// assert!(!table.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in table.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + inner: self.raw.drain(), + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashTable::retain + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 0..8 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// let drained: Vec = table.extract_if(|&mut v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = table.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.raw.iter() }, + table: &mut self.raw, + }, + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_disjoint_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// [Some(&mut ("Athenæum", 1807)), Some(&mut ("Library of Congress", 1800))], + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_disjoint_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, [Some(&mut ("Athenæum", 1807)), None]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + /// + /// ```should_panic + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// # use hashbrown::{HashTable, DefaultHashBuilder}; + /// # use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Athenæum", 1807), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// // Duplicate keys result in a panic! + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_disjoint_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test(); + /// # #[cfg(not(feature = "nightly"))] + /// # panic!(); + /// # } + /// ``` + pub fn get_disjoint_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + self.raw.get_disjoint_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once. + #[deprecated(note = "use `get_disjoint_mut` instead")] + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + self.raw.get_disjoint_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_disjoint_mut`](`HashTable::get_disjoint_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_disjoint_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// [Some(&mut ("Athenæum", 1807)), Some(&mut ("Library of Congress", 1800))], + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_disjoint_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, [Some(&mut ("Athenæum", 1807)), None]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + unsafe { self.raw.get_disjoint_unchecked_mut(hashes, eq) } + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + #[deprecated(note = "use `get_disjoint_unchecked_mut` instead")] + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> [Option<&'_ mut T>; N] { + unsafe { self.raw.get_disjoint_unchecked_mut(hashes, eq) } + } + + /// Returns the total amount of memory allocated internally by the hash + /// table, in bytes. + /// + /// The returned number is informational only. It is intended to be + /// primarily used for memory profiling. + #[inline] + pub fn allocation_size(&self) -> usize { + self.raw.allocation_size() + } +} + +impl IntoIterator for HashTable +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.raw.into_iter(), + } + } +} + +impl<'a, T, A> IntoIterator for &'a HashTable +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, A> IntoIterator for &'a mut HashTable +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl Default for HashTable +where + A: Allocator + Default, +{ + fn default() -> Self { + Self { + raw: Default::default(), + } + } +} + +impl Clone for HashTable +where + T: Clone, + A: Allocator + Clone, +{ + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.raw.clone_from(&source.raw); + } +} + +impl fmt::Debug for HashTable +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +/// A view into a single entry in a table, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashTable`]. +/// +/// [`entry`]: HashTable::entry +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, OccupiedEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); +/// assert_eq!(table.len(), 3); +/// // Nonexistent value (insert) +/// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); +/// +/// // Existing value (or_insert) +/// table +/// .entry(hasher(&"b"), |&x| x == "b", hasher) +/// .or_insert("b"); +/// // Nonexistent value (or_insert) +/// table +/// .entry(hasher(&"e"), |&x| x == "e", hasher) +/// .or_insert("e"); +/// +/// println!("Our HashTable: {:?}", table); +/// +/// let mut vec: Vec<_> = table.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub enum Entry<'a, T, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::{Entry, OccupiedEntry}; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in ["a", "b"] { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => {} + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::{Entry, OccupiedEntry}; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::<&str>::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => {} + /// Entry::Occupied(_) => unreachable!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Vacant(VacantEntry<'a, T, A>), +} + +impl fmt::Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +impl<'a, T, A> Entry<'a, T, A> +where + A: Allocator, +{ + /// Sets the value of the entry, replacing any existing value if there is + /// one, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// let entry = table + /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) + /// .insert("horseyland"); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(mut entry) => { + *entry.get_mut() = value; + entry + } + Entry::Vacant(entry) => entry.insert(value), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // nonexistent key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// + /// // existing key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// assert_eq!(table.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty.. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) + /// .or_insert_with(|| "poneyland".to_string()); + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |x| x == "poneyland") + /// .is_some()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 42)) + /// ); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 43)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Converts the `Entry` into a mutable reference to the underlying table. + pub fn into_table(self) -> &'a mut HashTable { + match self { + Entry::Occupied(entry) => entry.table, + Entry::Vacant(entry) => entry.table, + } + } +} + +/// A view into an occupied entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, OccupiedEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); +/// assert_eq!(table.len(), 3); +/// +/// // Existing key +/// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(table.len(), 3); +/// +/// // Existing key (take) +/// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove().0, "c"); +/// } +/// } +/// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); +/// assert_eq!(table.len(), 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct OccupiedEntry<'a, T, A = Global> +where + A: Allocator, +{ + bucket: Bucket, + table: &'a mut HashTable, +} + +unsafe impl Send for OccupiedEntry<'_, T, A> +where + T: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, T, A> +where + T: Sync, + A: Sync + Allocator, +{ +} + +impl fmt::Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +impl<'a, T, A> OccupiedEntry<'a, T, A> +where + A: Allocator, +{ + /// Takes the value out of the entry, and returns it along with a + /// `VacantEntry` that can be used to insert another value with the same + /// hash as the one that was just removed. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// // The table is empty + /// assert!(table.is_empty() && table.capacity() == 0); + /// + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// let capacity_before_remove = table.capacity(); + /// + /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// assert_eq!(o.remove().0, "poneyland"); + /// } + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_none()); + /// // Now table hold none elements but capacity is equal to the old one + /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> (T, VacantEntry<'a, T, A>) { + let (val, index, tag) = unsafe { self.table.raw.remove_tagged(self.bucket) }; + ( + val, + VacantEntry { + tag, + index, + table: self.table, + }, + ) + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// + /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get(&self) -> &T { + unsafe { self.bucket.as_ref() } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// if let Entry::Occupied(mut o) = table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// o.get_mut().1 += 10; + /// assert_eq!(o.get().1, 22); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().1 += 2; + /// } + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 24)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the table itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// let value: &mut (&str, u32); + /// match table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// value.1 += 10; + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 22)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn into_mut(self) -> &'a mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the `OccupiedEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } + + /// Returns the bucket index in the table for this entry. + /// + /// This can be used to store a borrow-free "reference" to the entry, later using + /// [`HashTable::get_bucket`], [`HashTable::get_bucket_mut`], or + /// [`HashTable::get_bucket_entry`] to access it again without hash probing. + /// + /// The index is only meaningful as long as the table is not resized and no entries are added + /// or removed. After such changes, it may end up pointing to a different entry or none at all. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, 1), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&2), (2, 2), |val| hasher(&val.0)); + /// table.insert_unique(hasher(&3), (3, 3), |val| hasher(&val.0)); + /// + /// let index = table + /// .entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) + /// .or_insert((2, -2)) + /// .bucket_index(); + /// assert_eq!(table.get_bucket(index), Some(&(2, 2))); + /// + /// // Full mutation would invalidate any normal reference + /// for (_key, value) in &mut table { + /// *value *= 11; + /// } + /// + /// // The index still reaches the same key with the updated value + /// assert_eq!(table.get_bucket(index), Some(&(2, 22))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn bucket_index(&self) -> usize { + unsafe { self.table.raw.bucket_index(&self.bucket) } + } + + /// Provides owned access to the value of the entry and allows to replace or + /// remove it based on the value of the returned option. + /// + /// The hash of the new item should be the same as the old item. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use hashbrown::hash_table::Entry; + /// use std::hash::BuildHasher; + /// + /// let mut table = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |(key, _): &_| hasher.hash_one(key); + /// table.insert_unique(hasher(&("poneyland", 42)), ("poneyland", 42), hasher); + /// + /// let entry = match table.entry(hasher(&("poneyland", 42)), |entry| entry.0 == "poneyland", hasher) { + /// Entry::Occupied(e) => unsafe { + /// e.replace_entry_with(|(k, v)| { + /// assert_eq!(k, "poneyland"); + /// assert_eq!(v, 42); + /// Some(("poneyland", v + 1)) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.get(), &("poneyland", 43)); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// let entry = match table.entry(hasher(&("poneyland", 43)), |entry| entry.0 == "poneyland", hasher) { + /// Entry::Occupied(e) => unsafe { e.replace_entry_with(|(_k, _v)| None) }, + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// // nice! + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, T, A> + where + F: FnOnce(T) -> Option, + { + unsafe { + match self.table.raw.replace_bucket_with(self.bucket.clone(), f) { + None => Entry::Occupied(self), + Some(tag) => Entry::Vacant(VacantEntry { + tag, + index: self.bucket_index(), + table: self.table, + }), + } + } + } +} + +/// A view into a vacant entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{Entry, VacantEntry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert("a"); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct VacantEntry<'a, T, A = Global> +where + A: Allocator, +{ + tag: Tag, + index: usize, + table: &'a mut HashTable, +} + +impl fmt::Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("VacantEntry") + } +} + +impl<'a, T, A> VacantEntry<'a, T, A> +where + A: Allocator, +{ + /// Inserts a new element into the table with the hash that was used to + /// obtain the `VacantEntry`. + /// + /// An `OccupiedEntry` is returned for the newly inserted element. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use hashbrown::hash_table::Entry; + /// use hashbrown::{HashTable, DefaultHashBuilder}; + /// use std::hash::BuildHasher; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = DefaultHashBuilder::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// o.insert("poneyland"); + /// } + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), + /// Some(&"poneyland") + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + let bucket = unsafe { + self.table + .raw + .insert_tagged_at_index(self.tag, self.index, value) + }; + OccupiedEntry { + bucket, + table: self.table, + } + } + + /// Converts the `VacantEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`] +/// and [`HashTable::get_bucket_entry`]. +/// +/// This type only exists due to [limitations] in Rust's NLL borrow checker. In +/// the future, those methods will return an `Option` and this +/// type will be removed. +/// +/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use hashbrown::hash_table::{AbsentEntry, Entry}; +/// use hashbrown::{HashTable, DefaultHashBuilder}; +/// use std::hash::BuildHasher; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = DefaultHashBuilder::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); +/// entry_v +/// .into_table() +/// .insert_unique(hasher(&"a"), "a", hasher); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct AbsentEntry<'a, T, A = Global> +where + A: Allocator, +{ + table: &'a mut HashTable, +} + +impl fmt::Debug for AbsentEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("AbsentEntry") + } +} + +impl<'a, T, A> AbsentEntry<'a, T, A> +where + A: Allocator, +{ + /// Converts the `AbsentEntry` into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// An iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter`]: HashTable::iter +pub struct Iter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a T>, +} + +impl Default for Iter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Iter { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl<'a, T> Clone for Iter<'a, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Iter<'a, T> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: HashTable::iter_mut +pub struct IterMut<'a, T> { + inner: RawIter, + marker: PhantomData<&'a mut T>, +} +impl<'a, T> IterMut<'a, T> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl Default for IterMut<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterMut { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl ExactSizeIterator for IterMut<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterMut<'_, T> {} + +impl fmt::Debug for IterMut<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// An unsafe iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `NonNull`. +/// +/// This `struct` is created by the [`unsafe_iter`] method on [`HashTable`]. +/// +/// This is used for implementations of iterators with "mixed" mutability on +/// the iterated elements. For example, a mutable iterator for a map may return +/// an immutable key alongside a mutable value, even though these are both +/// stored inside the table. +/// +/// If you have no idea what any of this means, you probably should be using +/// [`IterMut`] instead, as it does not have any safety requirements. +/// +/// # Safety +/// +/// In order to correctly use this iterator, it should be wrapped in a safe +/// iterator struct with the appropriate [`PhantomData`] marker to indicate the +/// correct [variance]. +/// +/// For example, below is a simplified [`hash_map::IterMut`] implementation +/// that correctly returns a [covariant] key, and an [invariant] value: +/// +/// [variance]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance +/// [covariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.covariant +/// [invariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.invariant +/// [`hash_map::IterMut`]: crate::hash_map::IterMut +/// [`unsafe_iter`]: HashTable::unsafe_iter +/// +/// ```rust +/// use core::marker::PhantomData; +/// use hashbrown::hash_table; +/// +/// pub struct IterMut<'a, K, V> { +/// inner: hash_table::UnsafeIter<'a, (K, V)>, +/// // Covariant over keys, invariant over values +/// marker: PhantomData<(&'a K, &'a mut V)>, +/// } +/// impl<'a, K, V> Iterator for IterMut<'a, K, V> { +/// // Immutable keys, mutable values +/// type Item = (&'a K, &'a mut V); +/// +/// fn next(&mut self) -> Option { +/// // SAFETY: The lifetime of the dereferenced pointer is derived from +/// // the lifetime of its iterator, ensuring that it's always valid. +/// // Additionally, we match the mutability in `self.marker` to ensure +/// // the correct variance. +/// let &mut (ref key, ref mut val) = unsafe { self.inner.next()?.as_mut() }; +/// Some((key, val)) +/// } +/// } +/// ``` +pub struct UnsafeIter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a ()>, +} +impl<'a, T> UnsafeIter<'a, T> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl Default for UnsafeIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + UnsafeIter { + inner: Default::default(), + marker: PhantomData, + } + } +} +impl<'a, T> Iterator for UnsafeIter<'a, T> { + type Item = NonNull; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { NonNull::new_unchecked(bucket.as_ptr()) }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, bucket| unsafe { + f(acc, NonNull::new_unchecked(bucket.as_ptr())) + }) + } +} + +impl ExactSizeIterator for UnsafeIter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for UnsafeIter<'_, T> {} + +impl fmt::Debug for UnsafeIter<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// An iterator producing the `usize` indices of all occupied buckets, +/// within the range `0..table.num_buckets()`. +/// +/// The order in which the iterator yields indices is unspecified +/// and may change in the future. +/// +/// This `struct` is created by the [`HashTable::iter_buckets`] method. See its +/// documentation for more. +pub struct IterBuckets<'a, T> { + inner: FullBucketsIndices, + marker: PhantomData<&'a T>, +} + +impl Clone for IterBuckets<'_, T> { + #[inline] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl Default for IterBuckets<'_, T> { + #[inline] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl Iterator for IterBuckets<'_, T> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl ExactSizeIterator for IterBuckets<'_, T> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterBuckets<'_, T> {} + +impl fmt::Debug for IterBuckets<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the entries of a `HashTable` that could match a given hash. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter_hash`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_hash`]: HashTable::iter_hash +pub struct IterHash<'a, T> { + inner: RawIterHash, + marker: PhantomData<&'a T>, +} + +impl Default for IterHash<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterHash { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for IterHash<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl FusedIterator for IterHash<'_, T> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl<'a, T> Clone for IterHash<'a, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> IterHash<'a, T> { + IterHash { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for IterHash<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashTable` that could match a given hash. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_hash_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_hash_mut`]: HashTable::iter_hash_mut +pub struct IterHashMut<'a, T> { + inner: RawIterHash, + marker: PhantomData<&'a mut T>, +} + +impl Default for IterHashMut<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IterHashMut { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl<'a, T> Iterator for IterHashMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl FusedIterator for IterHashMut<'_, T> {} + +impl fmt::Debug for IterHashMut<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(IterHash { + inner: self.inner.clone(), + marker: PhantomData, + }) + .finish() + } +} + +/// An iterator producing the `usize` indices of all buckets which may match a hash. +/// +/// This `struct` is created by the [`HashTable::iter_hash_buckets`] method. See its +/// documentation for more. +pub struct IterHashBuckets<'a, T> { + inner: RawIterHashIndices, + marker: PhantomData<&'a T>, +} + +impl Clone for IterHashBuckets<'_, T> { + #[inline] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl Default for IterHashBuckets<'_, T> { + #[inline] + fn default() -> Self { + Self { + inner: Default::default(), + marker: PhantomData, + } + } +} + +impl Iterator for IterHashBuckets<'_, T> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } +} + +impl FusedIterator for IterHashBuckets<'_, T> {} + +impl fmt::Debug for IterHashBuckets<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An owning iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `T`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashTable`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The table cannot be used after calling that method. +/// +/// [`into_iter`]: HashTable::into_iter +pub struct IntoIter +where + A: Allocator, +{ + inner: RawIntoIter, +} +impl IntoIter +where + A: Allocator, +{ + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +impl Default for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + IntoIter { + inner: Default::default(), + } + } +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for IntoIter +where + A: Allocator, +{ + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoIter where A: Allocator {} + +impl fmt::Debug for IntoIter +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// A draining iterator over the items of a `HashTable`. +/// +/// This `struct` is created by the [`drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`drain`]: HashTable::drain +pub struct Drain<'a, T, A: Allocator = Global> { + inner: RawDrain<'a, T, A>, +} +impl<'a, T, A: Allocator> Drain<'a, T, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for Drain<'_, T, A> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Drain<'_, T, A> {} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by [`HashTable::extract_if`]. See its +/// documentation for more. +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, T, F, A: Allocator = Global> { + f: F, + inner: RawExtractIf<'a, T, A>, +} + +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next(|val| (self.f)(val)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {} + +#[cfg(test)] +mod tests { + use super::HashTable; + + #[test] + fn test_allocation_info() { + assert_eq!(HashTable::<()>::new().allocation_size(), 0); + assert_eq!(HashTable::::new().allocation_size(), 0); + assert!(HashTable::::with_capacity(1).allocation_size() > core::mem::size_of::()); + } +} diff --git a/deps/crates/vendor/hashbrown/src/util.rs b/deps/crates/vendor/hashbrown/src/util.rs new file mode 100644 index 00000000000000..8667f34dca4239 --- /dev/null +++ b/deps/crates/vendor/hashbrown/src/util.rs @@ -0,0 +1,37 @@ +// FIXME: Replace with `core::hint::{likely, unlikely}` once they are stable. +#[cfg(feature = "nightly")] +pub(crate) use core::intrinsics::{likely, unlikely}; + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +#[cold] +fn cold_path() {} + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +pub(crate) fn likely(b: bool) -> bool { + if b { + true + } else { + cold_path(); + false + } +} + +#[cfg(not(feature = "nightly"))] +#[inline(always)] +pub(crate) fn unlikely(b: bool) -> bool { + if b { + cold_path(); + true + } else { + false + } +} + +// FIXME: use strict provenance functions once they are stable. +// Implement it with a transmute for now. +#[inline(always)] +pub(crate) fn invalid_mut(addr: usize) -> *mut T { + unsafe { core::mem::transmute(addr) } +} diff --git a/deps/crates/vendor/hashbrown/tests/equivalent_trait.rs b/deps/crates/vendor/hashbrown/tests/equivalent_trait.rs new file mode 100644 index 00000000000000..31f0a63e2c07b7 --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/equivalent_trait.rs @@ -0,0 +1,55 @@ +#![expect(missing_docs)] // https://github.com/rust-lang/rust/issues/137561 + +use hashbrown::Equivalent; +use hashbrown::HashMap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let mut map = HashMap::new(); + map.insert((s("a"), s("b")), 1); + map.insert((s("a"), s("x")), 2); + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = HashMap::new(); + map.insert(s("a"), 1); + map.insert(s("b"), 2); + map.insert(s("x"), 3); + map.insert(s("y"), 4); + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.remove("b"), Some(2)); +} diff --git a/deps/crates/vendor/hashbrown/tests/hasher.rs b/deps/crates/vendor/hashbrown/tests/hasher.rs new file mode 100644 index 00000000000000..22373784442943 --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/hasher.rs @@ -0,0 +1,65 @@ +//! Sanity check that alternate hashers work correctly. + +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use std::hash::{BuildHasher, BuildHasherDefault, Hasher}; + +fn check() { + let range = 0..1_000; + + let mut set = HashSet::::default(); + set.extend(range.clone()); + + assert!(!set.contains(&i32::MIN)); + assert!(!set.contains(&(range.start - 1))); + for i in range.clone() { + assert!(set.contains(&i)); + } + assert!(!set.contains(&range.end)); + assert!(!set.contains(&i32::MAX)); +} + +/// Use hashbrown's default hasher. +#[test] +fn default() { + check::(); +} + +/// Use std's default hasher. +#[test] +fn random_state() { + check::(); +} + +/// Use a constant 0 hash. +#[test] +fn zero() { + #[derive(Default)] + struct ZeroHasher; + + impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} + +/// Use a constant maximum hash. +#[test] +fn max() { + #[derive(Default)] + struct MaxHasher; + + impl Hasher for MaxHasher { + fn finish(&self) -> u64 { + u64::MAX + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} diff --git a/deps/crates/vendor/hashbrown/tests/hasher_unwind.rs b/deps/crates/vendor/hashbrown/tests/hasher_unwind.rs new file mode 100644 index 00000000000000..8d4c49cf15c63f --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/hasher_unwind.rs @@ -0,0 +1,158 @@ +//! Repro for a caught-panic corruption path in `std::collections::HashMap`. +//! +//! The bug class is: start a multi-step internal transition, let user code +//! panic in the middle, catch the unwind, and keep using the partially updated +//! object. +//! +//! In this case the user-controlled hook is `BuildHasher::build_hasher` during +//! an in-place rehash. The table keeps its logical length after the panic, but +//! lookups can no longer find the original keys and iteration starts yielding +//! repeated garbage-like entries. + +use hashbrown::HashMap; +use std::collections::BTreeSet; +use std::{ + hash::{BuildHasher, Hash, Hasher}, + panic::{AssertUnwindSafe, catch_unwind}, + sync::Mutex, + sync::atomic::{AtomicUsize, Ordering}, +}; + +/// One-shot panic switch used to trigger the first `build_hasher` call that +/// occurs inside `reserve(1)`. +static PANIC_COUNTER: AtomicUsize = AtomicUsize::new(0); +static TEST_LOCK: Mutex<()> = Mutex::new(()); + +/// A deterministic hasher that maps everything to the same bucket group. +/// +/// This maximizes collisions and makes the in-place rehash path easy to reach +/// with a small, fixed workload. +#[derive(Default)] +struct ZeroHasher; + +impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + + fn write(&mut self, _bytes: &[u8]) {} +} + +/// `BuildHasher` that panics once when armed. +/// +/// Using a panicking build hook mirrors the upstream interner trigger more +/// closely than a panicking `Hash` impl. +#[derive(Clone, Default)] +struct PanicBuildHasher; + +impl BuildHasher for PanicBuildHasher { + type Hasher = ZeroHasher; + + fn build_hasher(&self) -> Self::Hasher { + if PANIC_COUNTER.fetch_sub(1, Ordering::SeqCst) == 0 { + panic!("panic in BuildHasher::build_hasher"); + } + ZeroHasher + } +} + +/// Simple integer key type so the test can verify reachability after the panic. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +struct Key(u64); + +type Map = HashMap; + +/// Fill a map until `len == capacity`. +/// +/// With the current toolchain this yields a map with `len == capacity == 224` +/// when constructed from `with_capacity_and_hasher(128, ...)`. +fn make_full_map() -> Map { + PANIC_COUNTER.store(!0, Ordering::SeqCst); + let mut map = HashMap::with_capacity_and_hasher(128, PanicBuildHasher); + for i in 0.. { + map.insert(Key(i), i); + if map.len() == map.capacity() { + return map; + } + } + unreachable!() +} + +fn panics_silently(f: impl FnOnce()) -> bool { + let previous_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let panicked = catch_unwind(AssertUnwindSafe(f)).is_err(); + std::panic::set_hook(previous_hook); + panicked +} + +fn hashmap_reserve_survives_panicking_build_hasher_inner(count: usize) { + // Phase 1: fill a colliding table, then carve out the exact tombstone + // pattern that forces `reserve(1)` down the in-place rehash path. + let mut map = make_full_map(); + let original_len = map.len(); + assert_eq!( + (map.len(), map.capacity()), + (224, 224), + "this minimized workload is tuned for the validated std/hashbrown layout" + ); + + for i in 1..114 { + assert_eq!(map.remove(&Key(i)), Some(i)); + } + assert_eq!( + map.len(), + 111, + "setup should leave the expected tombstone pattern" + ); + + // Phase 2: make `BuildHasher::build_hasher` panic during the rehash, then + // keep using the recovered map. + PANIC_COUNTER.store(count, Ordering::SeqCst); + let reserve_panicked = panics_silently(|| { + map.reserve(1); + }); + assert!( + reserve_panicked, + "the minimized workload should panic during the in-place rehash" + ); + + // Phase 3: a correct table should keep every surviving key reachable and + // should not start yielding duplicate entries. + let mut expected_visible_keys: Vec<_> = map.keys().map(|&Key(i)| i).collect(); + let visible_keys: Vec<_> = (0..original_len as u64) + .filter(|&i| map.get(&Key(i)).copied() == Some(i)) + .collect(); + expected_visible_keys.sort(); + let iter_sample: Vec<_> = map.iter().take(8).map(|(k, v)| (k.0, *v)).collect(); + let distinct_entries = iter_sample.iter().copied().collect::>(); + + assert_eq!( + map.len(), + expected_visible_keys.len(), + "the table length should stay coherent" + ); + assert_eq!( + visible_keys, expected_visible_keys, + "the surviving keys should stay reachable after the caught panic" + ); + assert_eq!( + distinct_entries.len(), + iter_sample.len(), + "the iterator sample should not contain duplicate entries after the caught panic" + ); +} + +#[test] +fn hashmap_reserve_survives_panicking_build_hasher() { + let _guard = TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + if cfg!(miri) { + for i in [0, 50, 110] { + hashmap_reserve_survives_panicking_build_hasher_inner(i); + } + } else { + for i in 0..111 { + hashmap_reserve_survives_panicking_build_hasher_inner(i); + } + } +} diff --git a/deps/crates/vendor/hashbrown/tests/rayon.rs b/deps/crates/vendor/hashbrown/tests/rayon.rs new file mode 100644 index 00000000000000..2b8fb257ec2164 --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/rayon.rs @@ -0,0 +1,536 @@ +#![expect(missing_docs)] // https://github.com/rust-lang/rust/issues/137561 +#![cfg(feature = "rayon")] + +use hashbrown::{HashMap, HashSet}; +use rayon::iter::{ + IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend, + ParallelIterator, +}; +use std::sync::LazyLock; + +macro_rules! assert_eq3 { + ($e1:expr, $e2:expr, $e3:expr) => {{ + assert_eq!($e1, $e2); + assert_eq!($e1, $e3); + assert_eq!($e2, $e3); + }}; +} + +static MAP_EMPTY: LazyLock> = LazyLock::new(HashMap::new); + +static MAP: LazyLock> = LazyLock::new(|| { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m.insert('c', 30); + m.insert('e', 50); + m.insert('f', 60); + m.insert('d', 40); + m +}); + +#[test] +fn map_seq_par_equivalence_iter_empty() { + let vec_seq = MAP_EMPTY.iter().collect::>(); + let vec_par = MAP_EMPTY.par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter() { + let mut vec_seq = MAP.iter().collect::>(); + let mut vec_par = MAP.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &10), + (&'b', &20), + (&'c', &30), + (&'d', &40), + (&'e', &50), + (&'f', &60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_keys_empty() { + let vec_seq = MAP_EMPTY.keys().collect::>(); + let vec_par = MAP_EMPTY.par_keys().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_keys() { + let mut vec_seq = MAP.keys().collect::>(); + let mut vec_par = MAP.par_keys().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_empty() { + let vec_seq = MAP_EMPTY.values().collect::>(); + let vec_par = MAP_EMPTY.par_values().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values() { + let mut vec_seq = MAP.values().collect::>(); + let mut vec_par = MAP.par_values().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&10, &20, &30, &40, &50, &60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_iter_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.iter_mut().collect::>(); + let vec_par = map2.par_iter_mut().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.iter_mut().collect::>(); + let mut vec_par = map2.par_iter_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &mut 10), + (&'b', &mut 20), + (&'c', &mut 30), + (&'d', &mut 40), + (&'e', &mut 50), + (&'f', &mut 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.values_mut().collect::>(); + let vec_par = map2.par_values_mut().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.values_mut().collect::>(); + let mut vec_par = map2.par_values_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_into_iter_empty() { + let vec_seq = MAP_EMPTY.clone().into_iter().collect::>(); + let vec_par = MAP_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_into_iter() { + let mut vec_seq = MAP.clone().into_iter().collect::>(); + let mut vec_par = MAP.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + ('a', 10), + ('b', 20), + ('c', 30), + ('d', 40), + ('e', 50), + ('f', 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +static MAP_VEC_EMPTY: &[(char, u32)] = &[]; + +static MAP_VEC: &[(char, u32)] = &[ + ('b', 20), + ('a', 10), + ('c', 30), + ('e', 50), + ('f', 60), + ('d', 40), +]; + +#[test] +fn map_seq_par_equivalence_collect_empty() { + let map_expected = MAP_EMPTY.clone(); + let map_seq = MAP_VEC_EMPTY.iter().copied().collect::>(); + let map_par = MAP_VEC_EMPTY.par_iter().copied().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +#[test] +fn map_seq_par_equivalence_collect() { + let map_expected = MAP.clone(); + let map_seq = MAP_VEC.iter().copied().collect::>(); + let map_par = MAP_VEC.par_iter().copied().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +static MAP_EXISTING_EMPTY: LazyLock> = LazyLock::new(HashMap::new); + +static MAP_EXISTING: LazyLock> = LazyLock::new(|| { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m +}); + +static MAP_EXTENSION_EMPTY: &[(char, u32)] = &[]; + +static MAP_EXTENSION: &[(char, u32)] = &[('c', 30), ('e', 50), ('f', 60), ('d', 40)]; + +#[test] +fn map_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashMap::new(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend() { + let expected = MAP_EXTENSION.iter().copied().collect::>(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend_empty() { + let expected = MAP_EXISTING.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend() { + let expected = MAP.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +static SET_EMPTY: LazyLock> = LazyLock::new(HashSet::new); + +static SET: LazyLock> = LazyLock::new(|| { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s.insert('c'); + s.insert('e'); + s.insert('f'); + s.insert('d'); + s +}); + +#[test] +fn set_seq_par_equivalence_iter_empty() { + let vec_seq = SET_EMPTY.iter().collect::>(); + let vec_par = SET_EMPTY.par_iter().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn set_seq_par_equivalence_iter() { + let mut vec_seq = SET.iter().collect::>(); + let mut vec_par = SET.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn set_seq_par_equivalence_into_iter_empty() { + let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); + let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); + + // Work around type inference failure introduced by rend dev-dependency. + let empty: [char; 0] = []; + assert_eq3!(vec_seq, vec_par, empty); +} + +#[test] +fn set_seq_par_equivalence_into_iter() { + let mut vec_seq = SET.clone().into_iter().collect::>(); + let mut vec_par = SET.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +static SET_VEC_EMPTY: &[char] = &[]; + +static SET_VEC: &[char] = &['b', 'a', 'c', 'e', 'f', 'd']; + +#[test] +fn set_seq_par_equivalence_collect_empty() { + let set_expected = SET_EMPTY.clone(); + let set_seq = SET_VEC_EMPTY.iter().copied().collect::>(); + let set_par = SET_VEC_EMPTY.par_iter().copied().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +#[test] +fn set_seq_par_equivalence_collect() { + let set_expected = SET.clone(); + let set_seq = SET_VEC.iter().copied().collect::>(); + let set_par = SET_VEC.par_iter().copied().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +static SET_EXISTING_EMPTY: LazyLock> = LazyLock::new(HashSet::new); + +static SET_EXISTING: LazyLock> = LazyLock::new(|| { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s +}); + +static SET_EXTENSION_EMPTY: &[char] = &[]; + +static SET_EXTENSION: &[char] = &['c', 'e', 'f', 'd']; + +#[test] +fn set_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashSet::new(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend() { + let expected = SET_EXTENSION.iter().copied().collect::>(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend_empty() { + let expected = SET_EXISTING.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend() { + let expected = SET.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +static SET_A: LazyLock> = + LazyLock::new(|| ['a', 'b', 'c', 'd'].iter().copied().collect()); + +static SET_B: LazyLock> = + LazyLock::new(|| ['a', 'b', 'e', 'f'].iter().copied().collect()); + +static SET_DIFF_AB: LazyLock> = + LazyLock::new(|| ['c', 'd'].iter().copied().collect()); + +static SET_DIFF_BA: LazyLock> = + LazyLock::new(|| ['e', 'f'].iter().copied().collect()); + +static SET_SYMM_DIFF_AB: LazyLock> = + LazyLock::new(|| ['c', 'd', 'e', 'f'].iter().copied().collect()); + +static SET_INTERSECTION_AB: LazyLock> = + LazyLock::new(|| ['a', 'b'].iter().copied().collect()); + +static SET_UNION_AB: LazyLock> = + LazyLock::new(|| ['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect()); + +#[test] +fn set_seq_par_equivalence_difference() { + let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::>(); + let diff_ab_par = SET_A + .par_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB); + + let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::>(); + let diff_ba_par = SET_B + .par_difference(&*SET_A) + .copied() + .collect::>(); + + assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA); +} + +#[test] +fn set_seq_par_equivalence_symmetric_difference() { + let symm_diff_ab_seq = SET_A + .symmetric_difference(&*SET_B) + .copied() + .collect::>(); + let symm_diff_ab_par = SET_A + .par_symmetric_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB); +} + +#[test] +fn set_seq_par_equivalence_intersection() { + let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::>(); + let intersection_ab_par = SET_A + .par_intersection(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!( + intersection_ab_seq, + intersection_ab_par, + *SET_INTERSECTION_AB + ); +} + +#[test] +fn set_seq_par_equivalence_union() { + let union_ab_seq = SET_A.union(&*SET_B).copied().collect::>(); + let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::>(); + + assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB); +} diff --git a/deps/crates/vendor/hashbrown/tests/serde.rs b/deps/crates/vendor/hashbrown/tests/serde.rs new file mode 100644 index 00000000000000..b77f3fc14411ef --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/serde.rs @@ -0,0 +1,66 @@ +#![expect(missing_docs)] // https://github.com/rust-lang/rust/issues/137561 +#![cfg(feature = "serde")] + +use core::hash::BuildHasherDefault; +use fnv::FnvHasher; +use hashbrown::{HashMap, HashSet}; +use serde_test::{Token, assert_tokens}; + +// We use FnvHash for this test because we rely on the ordering +type FnvHashMap = HashMap>; +type FnvHashSet = HashSet>; + +#[test] +fn map_serde_tokens_empty() { + let map = FnvHashMap::::default(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens() { + let mut map = FnvHashMap::default(); + map.insert('b', 20); + map.insert('a', 10); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('c'), + Token::I32(30), + Token::Char('b'), + Token::I32(20), + Token::MapEnd, + ], + ); +} + +#[test] +fn set_serde_tokens_empty() { + let set = FnvHashSet::::default(); + + assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); +} + +#[test] +fn set_serde_tokens() { + let mut set = FnvHashSet::default(); + set.insert(20); + set.insert(10); + set.insert(30); + + assert_tokens( + &set, + &[ + Token::Seq { len: Some(3) }, + Token::I32(30), + Token::I32(20), + Token::I32(10), + Token::SeqEnd, + ], + ); +} diff --git a/deps/crates/vendor/hashbrown/tests/set.rs b/deps/crates/vendor/hashbrown/tests/set.rs new file mode 100644 index 00000000000000..2fa13c128145d4 --- /dev/null +++ b/deps/crates/vendor/hashbrown/tests/set.rs @@ -0,0 +1,35 @@ +#![expect(missing_docs)] // https://github.com/rust-lang/rust/issues/137561 +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use rand::{Rng, SeedableRng, distr::Alphanumeric, rngs::SmallRng}; +use std::iter; + +#[test] +fn test_hashset_insert_remove() { + let mut m: HashSet> = HashSet::new(); + let seed = u64::from_le_bytes(*b"testseed"); + + let rng = &mut SmallRng::seed_from_u64(seed); + let tx: Vec> = iter::repeat_with(|| { + rng.sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect() + }) + .take(4096) + .collect(); + + // more readable with explicit `true` / `false` + #[expect(clippy::bool_assert_comparison)] + for _ in 0..32 { + for x in &tx { + assert_eq!(m.contains(x), false); + assert_eq!(m.insert(x.clone()), true); + } + for (i, x) in tx.iter().enumerate() { + println!("removing {i} {x:?}"); + assert_eq!(m.remove(x), true); + } + } +} diff --git a/deps/crates/vendor/indexmap/.cargo-checksum.json b/deps/crates/vendor/indexmap/.cargo-checksum.json new file mode 100644 index 00000000000000..e5bc68cff7f03f --- /dev/null +++ b/deps/crates/vendor/indexmap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"adaa445c6325cbe511c8e7a2ce67fc45bc91dd6b332b0c06dc1abce39c38fbb4",".github/workflows/ci.yml":"f3271ea1cd81e367fe4da00b7d7491defb405002746312a3076b561fd34a0218","Cargo.lock":"c6744b14310e90e5ac90503ea50a132a0a53adcc5e15ad0c957e86087bb6a47a","Cargo.toml":"0057dba2c19b1fc812bc3a98d0b01994071028a3497463358c98b98212792de8","Cargo.toml.orig":"e23e8a3d8bd015402c58e2865e7a5a4511162bb12aeb57a488827eb648731c37","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.md":"f002494bf69e5b7dde911cfdb99330dfdbc4780d79a8e51847dfb7d883d9ab0f","RELEASES.md":"d0337e8981562fbf48eca08cf9a9927b9b0ccdb510cb091d6f2ea1b473668e3e","benches/bench.rs":"f4ab391f10c79ef83a941f56cd9d6514895f0b2919d4f600d6b8b80cb5e56fa3","benches/faststring.rs":"38ec254f92a8ba2cef274a7d4ada16b0dd1a1d8f8b4b50562cc9b79f9c088c39","src/arbitrary.rs":"068713b1e8e762dbe9e4d19d555e77c17e59408335a40f4777d6100340605655","src/borsh.rs":"9c26c7f7a9806d1b430ebacb01f26d65d7fbeb27a8ab8b87212aeb4d920ee19e","src/inner.rs":"25aae06c59c18867063c3da9b10525a9406a836057e0a1bcc0db508910521577","src/inner/entry.rs":"880b5b4ea2c21cd140185e0b6fa484c39d2ac6a82e3ff6bfda9847cbcbd0f6e8","src/inner/extract.rs":"54685eac822503118d9130c1800f132949dcf50be8dad0efea593f556c9442fb","src/lib.rs":"c8e2f1c0e488ab63d832392a83e34fa82293854bfb5ff3def8eeca9545ab2bdd","src/macros.rs":"5ff0f20fe33364c705da3cb3a7d0bc6c4afd519df7618b1baf1ed97bb7769bf3","src/map.rs":"c6a9ceed8854b8bbf82ed925bc1dee645ec528d926c3ca8aec443ffcc1c51afd","src/map/entry.rs":"90acbd60895fe24b6e64af42adfec9d01557638e4b89e5cb0473d5b8804568c7","src/map/iter.rs":"a2eab456006765faad980525cd3d3aeab95efdb66adb763ceb9efc11a6e6209d","src/map/mutable.rs":"326bc6c5e93acab742019b3bb332b14fd818fd39635f68ab1600bcd0d5dd28e0","src/map/raw_entry_v1.rs":"2361860d3c8b4550a089341d9c4be8c360e4869ca68f7dd91321c542195aa6f4","src/map/serde_seq.rs":"0518228a52b45501bd321f22edddeefec322832c05393225a044b2f6dd54ad5f","src/map/slice.rs":"e865ab8dc2a6d3540703ea0e4e9e0f0682b1619de94853bc417cbb1a1b782c59","src/map/tests.rs":"a46cbd29b2a0b104d8825c1727ea9fd4ae41e6b410bc0a5c44537f9c2eeee39a","src/rayon/map.rs":"0286ff799bdbfd4db5713717d61f825605407815ec5164fbe83f6411b5462109","src/rayon/mod.rs":"da256bc6ce16bd7aee261b60e27fcc15cb20fd400ff022aade7a8ab9f0033482","src/rayon/set.rs":"643c511a07522365ba37422fb83457e87a6eb9a1ab3ee919340b14ab725a76b6","src/serde.rs":"03ccd0903f077280700a149a2040f7cbcecc102570281b0cc8e0cd71fd6696b8","src/set.rs":"18fdc81a3ae43d66943eb96ed73508a099a37a737adcb83218c5b3531e3feeb4","src/set/iter.rs":"7d0113e94845f1aa4db290e9fcff5bf9a81a529aac246f08ef2659579984492c","src/set/mutable.rs":"93fb39ab685a1b4fd98e66f51389fa6eeb3158d73c8b8d9cce117af01f79be5e","src/set/slice.rs":"33907e8047d590244480004ccb4e0ca142858551b8fb6f1e3c6affee8e4a32d7","src/set/tests.rs":"9c64101fb9be53dc212a446b099db2f5757a97c991449b126e4fbdc6cf89cec2","src/sval.rs":"30474f4a6cd820ff348d7a28017226152171ca7921f90a10faf7301429c46abf","src/util.rs":"a0e512cf0bc5ccdeff5a64629da2cd976d7f6586194cc6901c118bc8b6287132","tests/equivalent_trait.rs":"aaf1192b96f9f59dccd4c0bd0e06c2f9943730864bcc852bfd52289de8e9c2b7","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"4d89f06122d599db2771061bc3d273c61c54ce15935fe321e91569a45709cc4f","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"} \ No newline at end of file diff --git a/deps/crates/vendor/indexmap/.cargo_vcs_info.json b/deps/crates/vendor/indexmap/.cargo_vcs_info.json new file mode 100644 index 00000000000000..9cb057d8125098 --- /dev/null +++ b/deps/crates/vendor/indexmap/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "bcd165baeb12bdf6e57a31d9869e9839e25679c6" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/indexmap/.github/workflows/ci.yml b/deps/crates/vendor/indexmap/.github/workflows/ci.yml new file mode 100644 index 00000000000000..fddf5f1427a0dd --- /dev/null +++ b/deps/crates/vendor/indexmap/.github/workflows/ci.yml @@ -0,0 +1,139 @@ +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + merge_group: + +name: CI + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.85.0 # MSRV + features: + - rust: stable + features: arbitrary + - rust: stable + features: quickcheck + - rust: stable + features: rayon + - rust: stable + features: serde + - rust: stable + features: sval + - rust: stable + features: borsh + - rust: stable + features: std + - rust: beta + features: + - rust: nightly + bench: test build benchmarks + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - name: Tests + run: | + cargo build --verbose --features "${{ matrix.features }}" + cargo doc --verbose --features "${{ matrix.features }}" + cargo test --verbose --features "${{ matrix.features }}" + cargo test --release --verbose --features "${{ matrix.features }}" + - name: Tests (serde) + if: matrix.features == 'serde' + run: | + cargo test --verbose -p test-serde + - name: Tests (sval) + if: matrix.features == 'sval' + run: | + cargo test --verbose -p test-sval + - name: Test run benchmarks + if: matrix.bench != '' + run: cargo test -v --benches + + nostd_build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.85.0 + target: thumbv6m-none-eabi + - rust: stable + target: thumbv6m-none-eabi + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + - name: Tests + run: | + cargo build -vv --target=${{ matrix.target }} --no-default-features + cargo build -v -p test-nostd --target=${{ matrix.target }} + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@beta + with: + components: clippy + - run: cargo clippy --all-features + + miri: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: miri, rust-src + - uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest + if: github.event_name == 'merge_group' + - run: cargo miri nextest run + if: github.event_name == 'merge_group' + - run: cargo miri test --doc + + minimal-versions: + name: Check MSRV and minimal-versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/rust-toolchain@1.85.0 # MSRV + - uses: taiki-e/install-action@v2 + with: + tool: cargo-hack + - name: Lock minimal direct dependencies + run: cargo +nightly hack generate-lockfile --remove-dev-deps -Z direct-minimal-versions + - name: Build (nightly) + run: cargo +nightly build --verbose --all-features + - name: Build (MSRV) + run: cargo build --verbose --features arbitrary,quickcheck,serde,sval,rayon + + # One job that "summarizes" the success state of this pipeline. This can then be added to branch + # protection, rather than having to add each job separately. + success: + name: Success + runs-on: ubuntu-latest + needs: [tests, nostd_build, clippy, miri, minimal-versions] + # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/deps/crates/vendor/indexmap/Cargo.lock b/deps/crates/vendor/indexmap/Cargo.lock new file mode 100644 index 00000000000000..ef841ac17d6109 --- /dev/null +++ b/deps/crates/vendor/indexmap/Cargo.lock @@ -0,0 +1,522 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "cfg_aliases", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +dependencies = [ + "arbitrary", + "borsh", + "equivalent", + "fastrand", + "fnv", + "hashbrown 0.17.0", + "itertools", + "quickcheck", + "rayon", + "serde", + "serde_core", + "sval", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quickcheck" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b" +dependencies = [ + "rand", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sval" +version = "2.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb9318255ebd817902d7e279d8f8e39b35b1b9954decd5eb9ea0e30e5fd2b6a" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.1", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.13.1", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.1", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.13.1", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.1", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/deps/crates/vendor/indexmap/Cargo.toml b/deps/crates/vendor/indexmap/Cargo.toml new file mode 100644 index 00000000000000..962d4c57defb2f --- /dev/null +++ b/deps/crates/vendor/indexmap/Cargo.toml @@ -0,0 +1,167 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2024" +rust-version = "1.85" +name = "indexmap" +version = "2.14.0" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A hash table with consistent order and fast iteration." +documentation = "https://docs.rs/indexmap/" +readme = "README.md" +keywords = [ + "hashmap", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/indexmap-rs/indexmap" + +[package.metadata.release] +allow-branch = ["main"] +sign-tag = true +tag-name = "{{version}}" + +[package.metadata.docs.rs] +features = [ + "arbitrary", + "quickcheck", + "serde", + "borsh", + "rayon", + "sval", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[features] +default = ["std"] +serde = [ + "dep:serde_core", + "dep:serde", +] +std = [] +test_debug = [] + +[lib] +name = "indexmap" +path = "src/lib.rs" +bench = false + +[[test]] +name = "equivalent_trait" +path = "tests/equivalent_trait.rs" + +[[test]] +name = "macros_full_path" +path = "tests/macros_full_path.rs" + +[[test]] +name = "quick" +path = "tests/quick.rs" + +[[test]] +name = "tests" +path = "tests/tests.rs" + +[[bench]] +name = "bench" +path = "benches/bench.rs" + +[[bench]] +name = "faststring" +path = "benches/faststring.rs" + +[dependencies.arbitrary] +version = "1.0" +optional = true +default-features = false + +[dependencies.borsh] +version = "1.2" +optional = true +default-features = false + +[dependencies.equivalent] +version = "1.0" +default-features = false + +[dependencies.hashbrown] +version = "0.17" +default-features = false + +[dependencies.quickcheck] +version = "1.0" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.9" +optional = true + +[dependencies.serde_core] +version = "1.0.220" +optional = true +default-features = false + +[dependencies.sval] +version = "2" +optional = true +default-features = false + +[dev-dependencies.fastrand] +version = "2" +default-features = false + +[dev-dependencies.fnv] +version = "1.0" + +[dev-dependencies.itertools] +version = "0.14" + +[dev-dependencies.quickcheck] +version = "1.1" +default-features = false + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] +default-features = false + +[target."cfg(any())".dependencies.serde] +version = "1.0.220" +optional = true +default-features = false + +[lints.clippy] +style = "allow" + +[lints.rust] +private-bounds = "deny" +private-interfaces = "deny" +rust-2018-idioms = "warn" +unnameable-types = "deny" +unreachable-pub = "deny" +unsafe-code = "deny" + +[profile.bench] +debug = 2 diff --git a/deps/crates/vendor/indexmap/Cargo.toml.orig b/deps/crates/vendor/indexmap/Cargo.toml.orig new file mode 100644 index 00000000000000..ae02d906b58d83 --- /dev/null +++ b/deps/crates/vendor/indexmap/Cargo.toml.orig @@ -0,0 +1,76 @@ +[package] +name = "indexmap" +edition = "2024" +version = "2.14.0" +documentation = "https://docs.rs/indexmap/" +repository = "https://github.com/indexmap-rs/indexmap" +license = "Apache-2.0 OR MIT" +description = "A hash table with consistent order and fast iteration." +keywords = ["hashmap", "no_std"] +categories = ["data-structures", "no-std"] +rust-version = "1.85" + +[lib] +bench = false + +[dependencies] +equivalent = { version = "1.0", default-features = false } +hashbrown = { version = "0.17", default-features = false } + +arbitrary = { version = "1.0", optional = true, default-features = false } +quickcheck = { version = "1.0", optional = true, default-features = false } +serde_core = { version = "1.0.220", optional = true, default-features = false } +rayon = { version = "1.9", optional = true } +sval = { version = "2", optional = true, default-features = false } + +# deprecated: use borsh's "indexmap" feature instead. +borsh = { version = "1.2", optional = true, default-features = false } + +# serde v1.0.220 is the first version that released with `serde_core`. +# This is required to avoid conflict with other `serde` users which may require an older version. +[target.'cfg(any())'.dependencies] +serde = { version = "1.0.220", default-features = false, optional = true } + +[dev-dependencies] +itertools = "0.14" +fastrand = { version = "2", default-features = false } +quickcheck = { version = "1.1", default-features = false } +fnv = "1.0" +serde = { version = "1.0", default-features = false, features = ["derive"] } + +[features] +default = ["std"] +std = [] +serde = ["dep:serde_core", "dep:serde"] + +# for testing only, of course +test_debug = [] + +[profile.bench] +debug = true + +[package.metadata.release] +allow-branch = ["main"] +sign-tag = true +tag-name = "{{version}}" + +[package.metadata.docs.rs] +features = ["arbitrary", "quickcheck", "serde", "borsh", "rayon", "sval"] +rustdoc-args = ["--cfg", "docsrs"] + +[workspace] +members = ["test-nostd", "test-serde", "test-sval"] + +[lints.rust] +private-bounds = "deny" +private-interfaces = "deny" +unnameable-types = "deny" +unreachable-pub = "deny" + +# We *mostly* avoid unsafe code, but there are a few fine-grained cases allowed +unsafe-code = "deny" + +rust-2018-idioms = "warn" + +[lints.clippy] +style = "allow" diff --git a/deps/crates/vendor/indexmap/LICENSE-APACHE b/deps/crates/vendor/indexmap/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/indexmap/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/indexmap/LICENSE-MIT b/deps/crates/vendor/indexmap/LICENSE-MIT new file mode 100644 index 00000000000000..8b8181068b3cb5 --- /dev/null +++ b/deps/crates/vendor/indexmap/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016--2017 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/indexmap/README.md b/deps/crates/vendor/indexmap/README.md new file mode 100644 index 00000000000000..afcd7bba65c507 --- /dev/null +++ b/deps/crates/vendor/indexmap/README.md @@ -0,0 +1,59 @@ +# indexmap + +[![build status](https://github.com/indexmap-rs/indexmap/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/indexmap-rs/indexmap/actions) +[![crates.io](https://img.shields.io/crates/v/indexmap.svg)](https://crates.io/crates/indexmap) +[![docs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap) +[![rustc](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://img.shields.io/badge/rust-1.85%2B-orange.svg) + +A pure-Rust hash table which preserves (in a limited sense) insertion order. + +This crate implements compact map and set data-structures, +where the iteration order of the keys is independent from their hash or +value. It preserves insertion order (except after removals), and it +allows lookup of entries by either hash table key or numerical index. + +Note: this crate was originally released under the name `ordermap`, +but it was renamed to `indexmap` to better reflect its features. +The [`ordermap`](https://crates.io/crates/ordermap) crate now exists +as a wrapper over `indexmap` with stronger ordering properties. + +# Background + +This was inspired by Python 3.6's new dict implementation (which remembers +the insertion order and is fast to iterate, and is compact in memory). + +Some of those features were translated to Rust, and some were not. The result +was indexmap, a hash table that has following properties: + +- Order is **independent of hash function** and hash values of keys. +- Fast to iterate. +- Indexed in compact space. +- Preserves insertion order **as long** as you don't call `.remove()`, + `.swap_remove()`, or other methods that explicitly change order. + The alternate `.shift_remove()` does preserve relative order. +- Uses hashbrown for the inner table, just like Rust's libstd `HashMap` does. + +## Performance + +`IndexMap` derives a couple of performance facts directly from how it is constructed, +which is roughly: + +> A raw hash table of key-value indices, and a vector of key-value pairs. + +- Iteration is very fast since it is on the dense key-values. +- Removal is fast since it moves memory areas only in the table, + and uses a single swap in the vector. +- Lookup is fast-ish because the initial 7-bit hash lookup uses SIMD, and indices are + densely stored. Lookup also is slow-ish since the actual key-value pairs are stored + separately. (Visible when cpu caches size is limiting.) + +- In practice, `IndexMap` has been tested out as the hashmap in rustc in [PR45282] and + the performance was roughly on par across the whole workload. +- If you want the properties of `IndexMap`, or its strongest performance points + fits your workload, it might be the best hash table implementation. + +[PR45282]: https://github.com/rust-lang/rust/pull/45282 + +# Recent Changes + +See [RELEASES.md](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md). diff --git a/deps/crates/vendor/indexmap/RELEASES.md b/deps/crates/vendor/indexmap/RELEASES.md new file mode 100644 index 00000000000000..6d8b42b29a17e0 --- /dev/null +++ b/deps/crates/vendor/indexmap/RELEASES.md @@ -0,0 +1,624 @@ +# Releases + +## 2.14.0 (2026-04-09) + +- **MSRV**: Rust 1.85.0 or later is now required. +- Updated the `hashbrown` dependency to 0.17. +- Made more `map::Slice` methods `const`: `new_mut`, `first_mut`, `last_mut`, + `split_at_mut`, `split_at_mut_checked`, `split_first_mut`, `split_last_mut` + +## 2.13.1 (2026-04-02) + +- Made some `Slice` methods `const`: + - `map::Slice::{first,last,split_at,split_at_checked,split_first,split_last}` + - `set::Slice::{first,last,split_at,split_at_checked,split_first,split_last}` + +## 2.13.0 (2026-01-07) + +- Implemented `Clone` for `IntoKeys` and `IntoValues`. +- Added `map::Slice::split_at_checked` and `split_at_mut_checked`. +- Added `set::Slice::split_at_checked`. + +## 2.12.1 (2025-11-20) + +- Simplified a lot of internals using `hashbrown`'s new bucket API. + +## 2.12.0 (2025-10-17) + +- **MSRV**: Rust 1.82.0 or later is now required. +- Updated the `hashbrown` dependency to 0.16 alone. +- Error types now implement `core::error::Error`. +- Added `pop_if` methods to `IndexMap` and `IndexSet`, similar to the + method for `Vec` added in Rust 1.86. + +## 2.11.4 (2025-09-18) + +- Updated the `hashbrown` dependency to a range allowing 0.15 or 0.16. + +## 2.11.3 (2025-09-15) + +- Make the minimum `serde` version only apply when "serde" is enabled. + +## 2.11.2 (2025-09-15) + +- Switched the "serde" feature to depend on `serde_core`, improving build + parallelism in cases where other dependents have enabled "serde/derive". + +## 2.11.1 (2025-09-08) + +- Added a `get_key_value_mut` method to `IndexMap`. +- Removed the unnecessary `Ord` bound on `insert_sorted_by` methods. + +## 2.11.0 (2025-08-22) + +- Added `insert_sorted_by` and `insert_sorted_by_key` methods to `IndexMap`, + `IndexSet`, and `VacantEntry`, like customizable versions of `insert_sorted`. +- Added `is_sorted`, `is_sorted_by`, and `is_sorted_by_key` methods to + `IndexMap` and `IndexSet`, as well as their `Slice` counterparts. +- Added `sort_by_key` and `sort_unstable_by_key` methods to `IndexMap` and + `IndexSet`, as well as parallel counterparts. +- Added `replace_index` methods to `IndexMap`, `IndexSet`, and `VacantEntry` + to replace the key (or set value) at a given index. +- Added optional `sval` serialization support. + +## 2.10.0 (2025-06-26) + +- Added `extract_if` methods to `IndexMap` and `IndexSet`, similar to the + methods for `HashMap` and `HashSet` with ranges like `Vec::extract_if`. +- Added more `#[track_caller]` annotations to functions that may panic. + +## 2.9.0 (2025-04-04) + +- Added a `get_disjoint_mut` method to `IndexMap`, matching Rust 1.86's + `HashMap` method. +- Added a `get_disjoint_indices_mut` method to `IndexMap` and `map::Slice`, + matching Rust 1.86's `get_disjoint_mut` method on slices. +- Deprecated the `borsh` feature in favor of their own `indexmap` feature, + solving a cyclic dependency that occurred via `borsh-derive`. + +## 2.8.0 (2025-03-10) + +- Added `indexmap_with_default!` and `indexset_with_default!` to be used with + alternative hashers, especially when using the crate without `std`. +- Implemented `PartialEq` between each `Slice` and `[]`/arrays. +- Removed the internal `rustc-rayon` feature and dependency. + +## 2.7.1 (2025-01-19) + +- Added `#[track_caller]` to functions that may panic. +- Improved memory reservation for `insert_entry`. + +## 2.7.0 (2024-11-30) + +- Added methods `Entry::insert_entry` and `VacantEntry::insert_entry`, returning + an `OccupiedEntry` after insertion. + +## 2.6.0 (2024-10-01) + +- Implemented `Clone` for `map::IntoIter` and `set::IntoIter`. +- Updated the `hashbrown` dependency to version 0.15. + +## 2.5.0 (2024-08-30) + +- Added an `insert_before` method to `IndexMap` and `IndexSet`, as an + alternative to `shift_insert` with different behavior on existing entries. +- Added `first_entry` and `last_entry` methods to `IndexMap`. +- Added `From` implementations between `IndexedEntry` and `OccupiedEntry`. + +## 2.4.0 (2024-08-13) + +- Added methods `IndexMap::append` and `IndexSet::append`, moving all items from + one map or set into another, and leaving the original capacity for reuse. + +## 2.3.0 (2024-07-31) + +- Added trait `MutableEntryKey` for opt-in mutable access to map entry keys. +- Added method `MutableKeys::iter_mut2` for opt-in mutable iteration of map + keys and values. + +## 2.2.6 (2024-03-22) + +- Added trait `MutableValues` for opt-in mutable access to set values. + +## 2.2.5 (2024-02-29) + +- Added optional `borsh` serialization support. + +## 2.2.4 (2024-02-28) + +- Added an `insert_sorted` method on `IndexMap`, `IndexSet`, and `VacantEntry`. +- Avoid hashing for lookups in single-entry maps. +- Limit preallocated memory in `serde` deserializers. + +## 2.2.3 (2024-02-11) + +- Added `move_index` and `swap_indices` methods to `IndexedEntry`, + `OccupiedEntry`, and `RawOccupiedEntryMut`, functioning like the existing + methods on `IndexMap`. +- Added `shift_insert` methods on `VacantEntry` and `RawVacantEntryMut`, as + well as `shift_insert_hashed_nocheck` on the latter, to insert the new entry + at a particular index. +- Added `shift_insert` methods on `IndexMap` and `IndexSet` to insert a new + entry at a particular index, or else move an existing entry there. + +## 2.2.2 (2024-01-31) + +- Added indexing methods to raw entries: `RawEntryBuilder::from_hash_full`, + `RawEntryBuilder::index_from_hash`, and `RawEntryMut::index`. + +## 2.2.1 (2024-01-28) + +- Corrected the signature of `RawOccupiedEntryMut::into_key(self) -> &'a mut K`, + This a breaking change from 2.2.0, but that version was published for less + than a day and has now been yanked. + +## 2.2.0 (2024-01-28) + +- The new `IndexMap::get_index_entry` method finds an entry by its index for + in-place manipulation. + +- The `Keys` iterator now implements `Index` for quick access to the + entry's key, compared to indexing the map to get the value. + +- The new `IndexMap::splice` and `IndexSet::splice` methods will drain the + given range as an iterator, and then replace that range with entries from + an input iterator. + +- The new trait `RawEntryApiV1` offers opt-in access to a raw entry API for + `IndexMap`, corresponding to the unstable API on `HashSet` as of Rust 1.75. + +- Many `IndexMap` and `IndexSet` methods have relaxed their type constraints, + e.g. removing `K: Hash` on methods that don't actually need to hash. + +- Removal methods `remove`, `remove_entry`, and `take` are now deprecated + in favor of their `shift_` or `swap_` prefixed variants, which are more + explicit about their effect on the index and order of remaining items. + The deprecated methods will remain to guide drop-in replacements from + `HashMap` and `HashSet` toward the prefixed methods. + +## 2.1.0 (2023-10-31) + +- Empty slices can now be created with `map::Slice::{new, new_mut}` and + `set::Slice::new`. In addition, `Slice::new`, `len`, and `is_empty` are + now `const` functions on both types. + +- `IndexMap`, `IndexSet`, and their respective `Slice`s all have binary + search methods for sorted data: map `binary_search_keys` and set + `binary_search` for plain comparison, `binary_search_by` for custom + comparators, `binary_search_by_key` for key extraction, and + `partition_point` for boolean conditions. + +## 2.0.2 (2023-09-29) + +- The `hashbrown` dependency has been updated to version 0.14.1 to + complete the support for Rust 1.63. + +## 2.0.1 (2023-09-27) + +- **MSRV**: Rust 1.63.0 is now supported as well, pending publication of + `hashbrown`'s relaxed MSRV (or use cargo `--ignore-rust-version`). + +## 2.0.0 (2023-06-23) + +- **MSRV**: Rust 1.64.0 or later is now required. + +- The `"std"` feature is no longer auto-detected. It is included in the + default feature set, or else can be enabled like any other Cargo feature. + +- The `"serde-1"` feature has been removed, leaving just the optional + `"serde"` dependency to be enabled like a feature itself. + +- `IndexMap::get_index_mut` now returns `Option<(&K, &mut V)>`, changing + the key part from `&mut K` to `&K`. There is also a new alternative + `MutableKeys::get_index_mut2` to access the former behavior. + +- The new `map::Slice` and `set::Slice` offer a linear view of maps + and sets, behaving a lot like normal `[(K, V)]` and `[T]` slices. Notably, + comparison traits like `Eq` only consider items in order, rather than hash + lookups, and slices even implement `Hash`. + +- `IndexMap` and `IndexSet` now have `sort_by_cached_key` and + `par_sort_by_cached_key` methods which perform stable sorts in place + using a key extraction function. + +- `IndexMap` and `IndexSet` now have `reserve_exact`, `try_reserve`, and + `try_reserve_exact` methods that correspond to the same methods on `Vec`. + However, exactness only applies to the direct capacity for items, while the + raw hash table still follows its own rules for capacity and load factor. + +- The `Equivalent` trait is now re-exported from the `equivalent` crate, + intended as a common base to allow types to work with multiple map types. + +- The `hashbrown` dependency has been updated to version 0.14. + +- The `serde_seq` module has been moved from the crate root to below the + `map` module. + +## 1.9.3 (2023-03-24) + +- Bump the `rustc-rayon` dependency, for compiler use only. + +## 1.9.2 (2022-11-17) + +- `IndexMap` and `IndexSet` both implement `arbitrary::Arbitrary<'_>` and + `quickcheck::Arbitrary` if those optional dependency features are enabled. + +## 1.9.1 (2022-06-21) + +- The MSRV now allows Rust 1.56.0 as well. However, currently `hashbrown` + 0.12.1 requires 1.56.1, so users on 1.56.0 should downgrade that to 0.12.0 + until there is a later published version relaxing its requirement. + +## 1.9.0 (2022-06-16) + +- **MSRV**: Rust 1.56.1 or later is now required. + +- The `hashbrown` dependency has been updated to version 0.12. + +- `IterMut` and `ValuesMut` now implement `Debug`. + +- The new `IndexMap::shrink_to` and `IndexSet::shrink_to` methods shrink + the capacity with a lower bound. + +- The new `IndexMap::move_index` and `IndexSet::move_index` methods change + the position of an item from one index to another, shifting the items + between to accommodate the move. + +## 1.8.2 (2022-05-27) + +- Bump the `rustc-rayon` dependency, for compiler use only. + +## 1.8.1 (2022-03-29) + +- The new `IndexSet::replace_full` will return the index of the item along + with the replaced value, if any, by @zakcutner in PR [222]. + +[222]: https://github.com/indexmap-rs/indexmap/pull/222 + +## 1.8.0 (2022-01-07) + +- The new `IndexMap::into_keys` and `IndexMap::into_values` will consume + the map into keys or values, respectively, matching Rust 1.54's `HashMap` + methods, by @taiki-e in PR [195]. + +- More of the iterator types implement `Debug`, `ExactSizeIterator`, and + `FusedIterator`, by @cuviper in PR [196]. + +- `IndexMap` and `IndexSet` now implement rayon's `ParallelDrainRange`, + by @cuviper in PR [197]. + +- `IndexMap::with_hasher` and `IndexSet::with_hasher` are now `const` + functions, allowing static maps and sets, by @mwillsey in PR [203]. + +- `IndexMap` and `IndexSet` now implement `From` for arrays, matching + Rust 1.56's implementation for `HashMap`, by @rouge8 in PR [205]. + +- `IndexMap` and `IndexSet` now have methods `sort_unstable_keys`, + `sort_unstable_by`, `sorted_unstable_by`, and `par_*` equivalents, + which sort in-place without preserving the order of equal items, by + @bhgomes in PR [211]. + +[195]: https://github.com/indexmap-rs/indexmap/pull/195 +[196]: https://github.com/indexmap-rs/indexmap/pull/196 +[197]: https://github.com/indexmap-rs/indexmap/pull/197 +[203]: https://github.com/indexmap-rs/indexmap/pull/203 +[205]: https://github.com/indexmap-rs/indexmap/pull/205 +[211]: https://github.com/indexmap-rs/indexmap/pull/211 + +## 1.7.0 (2021-06-29) + +- **MSRV**: Rust 1.49 or later is now required. + +- The `hashbrown` dependency has been updated to version 0.11. + +## 1.6.2 (2021-03-05) + +- Fixed to match `std` behavior, `OccupiedEntry::key` now references the + existing key in the map instead of the lookup key, by @cuviper in PR [170]. + +- The new `Entry::or_insert_with_key` matches Rust 1.50's `Entry` method, + passing `&K` to the callback to create a value, by @cuviper in PR [175]. + +[170]: https://github.com/indexmap-rs/indexmap/pull/170 +[175]: https://github.com/indexmap-rs/indexmap/pull/175 + +## 1.6.1 (2020-12-14) + +- The new `serde_seq` module implements `IndexMap` serialization as a + sequence to ensure order is preserved, by @cuviper in PR [158]. + +- New methods on maps and sets work like the `Vec`/slice methods by the same name: + `truncate`, `split_off`, `first`, `first_mut`, `last`, `last_mut`, and + `swap_indices`, by @cuviper in PR [160]. + +[158]: https://github.com/indexmap-rs/indexmap/pull/158 +[160]: https://github.com/indexmap-rs/indexmap/pull/160 + +## 1.6.0 (2020-09-05) + +- **MSRV**: Rust 1.36 or later is now required. + +- The `hashbrown` dependency has been updated to version 0.9. + +## 1.5.2 (2020-09-01) + +- The new "std" feature will force the use of `std` for users that explicitly + want the default `S = RandomState`, bypassing the autodetection added in 1.3.0, + by @cuviper in PR [145]. + +[145]: https://github.com/indexmap-rs/indexmap/pull/145 + +## 1.5.1 (2020-08-07) + +- Values can now be indexed by their `usize` position by @cuviper in PR [132]. + +- Some of the generic bounds have been relaxed to match `std` by @cuviper in PR [141]. + +- `drain` now accepts any `R: RangeBounds` by @cuviper in PR [142]. + +[132]: https://github.com/indexmap-rs/indexmap/pull/132 +[141]: https://github.com/indexmap-rs/indexmap/pull/141 +[142]: https://github.com/indexmap-rs/indexmap/pull/142 + +## 1.5.0 (2020-07-17) + +- **MSRV**: Rust 1.32 or later is now required. + +- The inner hash table is now based on `hashbrown` by @cuviper in PR [131]. + This also completes the method `reserve` and adds `shrink_to_fit`. + +- Add new methods `get_key_value`, `remove_entry`, `swap_remove_entry`, + and `shift_remove_entry`, by @cuviper in PR [136] + +- `Clone::clone_from` reuses allocations by @cuviper in PR [125] + +- Add new method `reverse` by @linclelinkpart5 in PR [128] + +[125]: https://github.com/indexmap-rs/indexmap/pull/125 +[128]: https://github.com/indexmap-rs/indexmap/pull/128 +[131]: https://github.com/indexmap-rs/indexmap/pull/131 +[136]: https://github.com/indexmap-rs/indexmap/pull/136 + +## 1.4.0 (2020-06-01) + +- Add new method `get_index_of` by @Thermatrix in PR [115] and [120] + +- Fix build script rebuild-if-changed configuration to use "build.rs"; + fixes issue [123]. Fix by @cuviper. + +- Dev-dependencies (rand and quickcheck) have been updated. The crate's tests + now run using Rust 1.32 or later (MSRV for building the crate has not changed). + by @kjeremy and @bluss + +[123]: https://github.com/indexmap-rs/indexmap/issues/123 +[115]: https://github.com/indexmap-rs/indexmap/pull/115 +[120]: https://github.com/indexmap-rs/indexmap/pull/120 + +## 1.3.2 (2020-02-05) + +- Maintenance update to regenerate the published `Cargo.toml`. + +## 1.3.1 (2020-01-15) + +- Maintenance update for formatting and `autocfg` 1.0. + +## 1.3.0 (2019-10-18) + +- The deprecation messages in the previous version have been removed. + (The methods have not otherwise changed.) Docs for removal methods have been + improved. +- From Rust 1.36, this crate supports being built **without std**, requiring + `alloc` instead. This is enabled automatically when it is detected that + `std` is not available. There is no crate feature to enable/disable to + trigger this. The new build-dep `autocfg` enables this. + +## 1.2.0 (2019-09-08) + +- Plain `.remove()` now has a deprecation message, it informs the user + about picking one of the removal functions `swap_remove` and `shift_remove` + which have different performance and order semantics. + Plain `.remove()` will not be removed, the warning message and method + will remain until further. + +- Add new method `shift_remove` for order preserving removal on the map, + and `shift_take` for the corresponding operation on the set. + +- Add methods `swap_remove`, `swap_remove_entry` to `Entry`. + +- Fix indexset/indexmap to support full paths, like `indexmap::indexmap!()` + +- Internal improvements: fix warnings, deprecations and style lints + +## 1.1.0 (2019-08-20) + +- Added optional feature `"rayon"` that adds parallel iterator support + to `IndexMap` and `IndexSet` using Rayon. This includes all the regular + iterators in parallel versions, and parallel sort. + +- Implemented `Clone` for `map::{Iter, Keys, Values}` and + `set::{Difference, Intersection, Iter, SymmetricDifference, Union}` + +- Implemented `Debug` for `map::{Entry, IntoIter, Iter, Keys, Values}` and + `set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}` + +- Serde trait `IntoDeserializer` are implemented for `IndexMap` and `IndexSet`. + +- Minimum Rust version requirement increased to Rust 1.30 for development builds. + +## 1.0.2 (2018-10-22) + +- The new methods `IndexMap::insert_full` and `IndexSet::insert_full` are + both like `insert` with the index included in the return value. + +- The new method `Entry::and_modify` can be used to modify occupied + entries, matching the new methods of `std` maps in Rust 1.26. + +- The new method `Entry::or_default` inserts a default value in unoccupied + entries, matching the new methods of `std` maps in Rust 1.28. + +## 1.0.1 (2018-03-24) + +- Document Rust version policy for the crate (see rustdoc) + +## 1.0.0 (2018-03-11) + +- This is the 1.0 release for `indexmap`! (the crate and datastructure + formerly known as “ordermap”) +- `OccupiedEntry::insert` changed its signature, to use `&mut self` for + the method receiver, matching the equivalent method for a standard + `HashMap`. Thanks to @dtolnay for finding this bug. +- The deprecated old names from ordermap were removed: `OrderMap`, + `OrderSet`, `ordermap!{}`, `orderset!{}`. Use the new `IndexMap` + etc names instead. + +## 0.4.1 (2018-02-14) + +- Renamed crate to `indexmap`; the `ordermap` crate is now deprecated + and the types `OrderMap/Set` now have a deprecation notice. + +## 0.4.0 (2018-02-02) + +- This is the last release series for this `ordermap` under that name, + because the crate is **going to be renamed** to `indexmap` (with types + `IndexMap`, `IndexSet`) and no change in functionality! +- The map and its associated structs moved into the `map` submodule of the + crate, so that the map and set are symmetric + + + The iterators, `Entry` and other structs are now under `ordermap::map::` + +- Internally refactored `OrderMap` so that all the main algorithms + (insertion, lookup, removal etc) that don't use the `S` parameter (the + hasher) are compiled without depending on `S`, which reduces generics bloat. + +- `Entry` no longer has a type parameter `S`, which is just like + the standard `HashMap`'s entry. + +- Minimum Rust version requirement increased to Rust 1.18 + +## 0.3.5 (2018-01-14) + +- Documentation improvements + +## 0.3.4 (2018-01-04) + +- The `.retain()` methods for `OrderMap` and `OrderSet` now + traverse the elements in order, and the retained elements **keep their order** +- Added new methods `.sort_by()`, `.sort_keys()` to `OrderMap` and + `.sort_by()`, `.sort()` to `OrderSet`. These methods allow you to + sort the maps in place efficiently. + +## 0.3.3 (2017-12-28) + +- Document insertion behaviour better by @lucab +- Updated dependences (no feature changes) by @ignatenkobrain + +## 0.3.2 (2017-11-25) + +- Add `OrderSet` by @cuviper! +- `OrderMap::drain` is now (too) a double ended iterator. + +## 0.3.1 (2017-11-19) + +- In all ordermap iterators, forward the `collect` method to the underlying + iterator as well. +- Add crates.io categories. + +## 0.3.0 (2017-10-07) + +- The methods `get_pair`, `get_pair_index` were both replaced by + `get_full` (and the same for the mutable case). +- Method `swap_remove_pair` replaced by `swap_remove_full`. +- Add trait `MutableKeys` for opt-in mutable key access. Mutable key access + is only possible through the methods of this extension trait. +- Add new trait `Equivalent` for key equivalence. This extends the + `Borrow` trait mechanism for `OrderMap::get` in a backwards compatible + way, just some minor type inference related issues may become apparent. + See [#10] for more information. +- Implement `Extend<(&K, &V)>` by @xfix. + +[#10]: https://github.com/indexmap-rs/indexmap/pull/10 + +## 0.2.13 (2017-09-30) + +- Fix deserialization to support custom hashers by @Techcable. +- Add methods `.index()` on the entry types by @garro95. + +## 0.2.12 (2017-09-11) + +- Add methods `.with_hasher()`, `.hasher()`. + +## 0.2.11 (2017-08-29) + +- Support `ExactSizeIterator` for the iterators. By @Binero. +- Use `Box<[Pos]>` internally, saving a word in the `OrderMap` struct. +- Serde support, with crate feature `"serde-1"`. By @xfix. + +## 0.2.10 (2017-04-29) + +- Add iterator `.drain(..)` by @stevej. + +## 0.2.9 (2017-03-26) + +- Add method `.is_empty()` by @overvenus. +- Implement `PartialEq, Eq` by @overvenus. +- Add method `.sorted_by()`. + +## 0.2.8 (2017-03-01) + +- Add iterators `.values()` and `.values_mut()`. +- Fix compatibility with 32-bit platforms. + +## 0.2.7 (2016-11-02) + +- Add `.retain()`. + +## 0.2.6 (2016-11-02) + +- Add `OccupiedEntry::remove_entry` and other minor entry methods, + so that it now has all the features of `HashMap`'s entries. + +## 0.2.5 (2016-10-31) + +- Improved `.pop()` slightly. + +## 0.2.4 (2016-10-22) + +- Improved performance of `.insert()` ([#3]) by @pczarn. + +[#3]: https://github.com/indexmap-rs/indexmap/pull/3 + +## 0.2.3 (2016-10-11) + +- Generalize `Entry` for now, so that it works on hashmaps with non-default + hasher. However, there's a lingering compat issue since libstd `HashMap` + does not parameterize its entries by the hasher (`S` typarm). +- Special case some iterator methods like `.nth()`. + +## 0.2.2 (2016-10-02) + +- Disable the verbose `Debug` impl by default. + +## 0.2.1 (2016-10-02) + +- Fix doc links and clarify docs. + +## 0.2.0 (2016-10-01) + +- Add more `HashMap` methods & compat with its API. +- Experimental support for `.entry()` (the simplest parts of the API). +- Add `.reserve()` (placeholder impl). +- Add `.remove()` as synonym for `.swap_remove()`. +- Changed `.insert()` to swap value if the entry already exists, and + return `Option`. +- Experimental support as an *indexed* hash map! Added methods + `.get_index()`, `.get_index_mut()`, `.swap_remove_index()`, + `.get_pair_index()`, `.get_pair_index_mut()`. + +## 0.1.2 (2016-09-19) + +- Implement the 32/32 split idea for `Pos` which improves cache utilization + and lookup performance. + +## 0.1.1 (2016-09-16) + +- Initial release. diff --git a/deps/crates/vendor/indexmap/benches/bench.rs b/deps/crates/vendor/indexmap/benches/bench.rs new file mode 100644 index 00000000000000..3c5e199381e31e --- /dev/null +++ b/deps/crates/vendor/indexmap/benches/bench.rs @@ -0,0 +1,750 @@ +#![feature(test)] + +extern crate test; + +use fnv::FnvHasher; +use std::hash::BuildHasherDefault; +use std::hash::Hash; +use std::hint::black_box; +use std::sync::LazyLock; +type FnvBuilder = BuildHasherDefault; + +use test::Bencher; + +use indexmap::IndexMap; + +use std::collections::HashMap; + +/// Use a consistently seeded Rng for benchmark stability +fn small_rng() -> fastrand::Rng { + let seed = u64::from_le_bytes(*b"indexmap"); + fastrand::Rng::with_seed(seed) +} + +#[bench] +fn new_hashmap(b: &mut Bencher) { + b.iter(|| HashMap::::new()); +} + +#[bench] +fn new_indexmap(b: &mut Bencher) { + b.iter(|| IndexMap::::new()); +} + +#[bench] +fn with_capacity_10e5_hashmap(b: &mut Bencher) { + b.iter(|| HashMap::::with_capacity(10_000)); +} + +#[bench] +fn with_capacity_10e5_indexmap(b: &mut Bencher) { + b.iter(|| IndexMap::::with_capacity(10_000)); +} + +#[bench] +fn insert_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_str_10_000(b: &mut Bencher) { + let c = 10_000; + let ss = Vec::from_iter((0..c).map(|x| x.to_string())); + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for key in &ss { + map.insert(&key[..], ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_str_10_000(b: &mut Bencher) { + let c = 10_000; + let ss = Vec::from_iter((0..c).map(|x| x.to_string())); + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for key in &ss { + map.insert(&key[..], ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_int_bigvalue_10_000(b: &mut Bencher) { + let c = 10_000; + let value = [0u64; 10]; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for i in 0..c { + map.insert(i, value); + } + map + }); +} + +#[bench] +fn insert_indexmap_int_bigvalue_10_000(b: &mut Bencher) { + let c = 10_000; + let value = [0u64; 10]; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for i in 0..c { + map.insert(i, value); + } + map + }); +} + +#[bench] +fn insert_hashmap_100_000(b: &mut Bencher) { + let c = 100_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_100_000(b: &mut Bencher) { + let c = 100_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn entry_hashmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.entry(x).or_insert(()); + } + map + }); +} + +#[bench] +fn entry_indexmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.entry(x).or_insert(()); + } + map + }); +} + +#[bench] +fn iter_sum_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| map.keys().sum::()); +} + +#[bench] +fn iter_sum_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| map.keys().sum::()); +} + +#[bench] +fn iter_black_box_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| { + for &key in map.keys() { + black_box(key); + } + }); +} + +#[bench] +fn iter_black_box_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| { + for &key in map.keys() { + black_box(key); + } + }); +} + +fn shuffled_keys(iter: I) -> Vec +where + I: IntoIterator, +{ + let mut v = Vec::from_iter(iter); + let mut rng = small_rng(); + rng.shuffle(&mut v); + v +} + +#[bench] +fn lookup_hashmap_10_000_exist(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in 5000..c { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_10_000_noexist(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in c..15000 { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in 5000..c { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_noexist(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in c..15000 { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +// number of items to look up +const LOOKUP_MAP_SIZE: u32 = 100_000_u32; +const LOOKUP_SAMPLE_SIZE: u32 = 5000; +const SORT_MAP_SIZE: usize = 10_000; + +// use (lazy) statics so that comparison benchmarks use the exact same inputs + +static KEYS: LazyLock> = LazyLock::new(|| shuffled_keys(0..LOOKUP_MAP_SIZE)); + +static HMAP_100K: LazyLock> = LazyLock::new(|| { + let c = LOOKUP_MAP_SIZE; + let mut map = HashMap::with_capacity(c as usize); + let keys = &*KEYS; + for &key in keys { + map.insert(key, key); + } + map +}); + +static IMAP_100K: LazyLock> = LazyLock::new(|| { + let c = LOOKUP_MAP_SIZE; + let mut map = IndexMap::with_capacity(c as usize); + let keys = &*KEYS; + for &key in keys { + map.insert(key, key); + } + map +}); + +static IMAP_SORT_U32: LazyLock> = LazyLock::new(|| { + let mut map = IndexMap::with_capacity(SORT_MAP_SIZE); + for &key in &KEYS[..SORT_MAP_SIZE] { + map.insert(key, key); + } + map +}); + +static IMAP_SORT_S: LazyLock> = LazyLock::new(|| { + let mut map = IndexMap::with_capacity(SORT_MAP_SIZE); + for &key in &KEYS[..SORT_MAP_SIZE] { + map.insert(format!("{:^16x}", &key), String::new()); + } + map +}); + +#[bench] +fn lookup_hashmap_100_000_multi(b: &mut Bencher) { + let map = &*HMAP_100K; + b.iter(|| { + let mut found = 0; + for key in 0..LOOKUP_SAMPLE_SIZE { + found += map.get(&key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_100_000_multi(b: &mut Bencher) { + let map = &*IMAP_100K; + b.iter(|| { + let mut found = 0; + for key in 0..LOOKUP_SAMPLE_SIZE { + found += map.get(&key).is_some() as u32; + } + found + }); +} + +// inorder: Test looking up keys in the same order as they were inserted +#[bench] +fn lookup_hashmap_100_000_inorder_multi(b: &mut Bencher) { + let map = &*HMAP_100K; + let keys = &*KEYS; + b.iter(|| { + let mut found = 0; + for key in &keys[0..LOOKUP_SAMPLE_SIZE as usize] { + found += map.get(key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_100_000_inorder_multi(b: &mut Bencher) { + let map = &*IMAP_100K; + let keys = &*KEYS; + b.iter(|| { + let mut found = 0; + for key in &keys[0..LOOKUP_SAMPLE_SIZE as usize] { + found += map.get(key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_100_000_single(b: &mut Bencher) { + let map = &*HMAP_100K; + let mut iter = (0..LOOKUP_MAP_SIZE + LOOKUP_SAMPLE_SIZE).cycle(); + b.iter(|| { + let key = iter.next().unwrap(); + map.get(&key).is_some() + }); +} + +#[bench] +fn lookup_indexmap_100_000_single(b: &mut Bencher) { + let map = &*IMAP_100K; + let mut iter = (0..LOOKUP_MAP_SIZE + LOOKUP_SAMPLE_SIZE).cycle(); + b.iter(|| { + let key = iter.next().unwrap(); + map.get(&key).is_some() + }); +} + +const GROW_SIZE: usize = 100_000; +type GrowKey = u32; + +// Test grow/resize without preallocation +#[bench] +fn grow_fnv_hashmap_100_000(b: &mut Bencher) { + b.iter(|| { + let mut map: HashMap<_, _, FnvBuilder> = HashMap::default(); + for x in 0..GROW_SIZE { + map.insert(x as GrowKey, x as GrowKey); + } + map + }); +} + +#[bench] +fn grow_fnv_indexmap_100_000(b: &mut Bencher) { + b.iter(|| { + let mut map: IndexMap<_, _, FnvBuilder> = IndexMap::default(); + for x in 0..GROW_SIZE { + map.insert(x as GrowKey, x as GrowKey); + } + map + }); +} + +const MERGE: u64 = 10_000; +#[bench] +fn hashmap_merge_simple(b: &mut Bencher) { + let first_map: HashMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: HashMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + b.iter(|| { + let mut merged = first_map.clone(); + merged.extend(second_map.iter().map(|(&k, &v)| (k, v))); + merged + }); +} + +#[bench] +fn hashmap_merge_shuffle(b: &mut Bencher) { + let first_map: HashMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: HashMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + let mut v = Vec::new(); + let mut rng = small_rng(); + b.iter(|| { + let mut merged = first_map.clone(); + v.extend(second_map.iter().map(|(&k, &v)| (k, v))); + rng.shuffle(&mut v); + merged.extend(v.drain(..)); + + merged + }); +} + +#[bench] +fn indexmap_merge_simple(b: &mut Bencher) { + let first_map: IndexMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: IndexMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + b.iter(|| { + let mut merged = first_map.clone(); + merged.extend(second_map.iter().map(|(&k, &v)| (k, v))); + merged + }); +} + +#[bench] +fn indexmap_merge_shuffle(b: &mut Bencher) { + let first_map: IndexMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: IndexMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + let mut v = Vec::new(); + let mut rng = small_rng(); + b.iter(|| { + let mut merged = first_map.clone(); + v.extend(second_map.iter().map(|(&k, &v)| (k, v))); + rng.shuffle(&mut v); + merged.extend(v.drain(..)); + + merged + }); +} + +#[bench] +fn swap_remove_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + let mut keys = Vec::from_iter(map.keys().copied()); + let mut rng = small_rng(); + rng.shuffle(&mut keys); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.swap_remove(key); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn shift_remove_indexmap_100_000_few(b: &mut Bencher) { + let map = IMAP_100K.clone(); + let mut keys = Vec::from_iter(map.keys().copied()); + let mut rng = small_rng(); + rng.shuffle(&mut keys); + keys.truncate(50); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.shift_remove(key); + } + assert_eq!(map.len(), IMAP_100K.len() - keys.len()); + map + }); +} + +#[bench] +fn shift_remove_indexmap_2_000_full(b: &mut Bencher) { + let mut keys = KEYS[..2_000].to_vec(); + let mut map = IndexMap::with_capacity(keys.len()); + for &key in &keys { + map.insert(key, key); + } + let mut rng = small_rng(); + rng.shuffle(&mut keys); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.shift_remove(key); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn pop_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + while !map.is_empty() { + map.pop(); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn few_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 7 == 0); + map + }); +} + +#[bench] +fn few_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 7 == 0); + map + }); +} + +#[bench] +fn half_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 2 == 0); + map + }); +} + +#[bench] +fn half_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 2 == 0); + map + }); +} + +#[bench] +fn many_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 100 != 0); + map + }); +} + +#[bench] +fn many_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 100 != 0); + map + }); +} + +// simple sort impl for comparison +pub fn simple_sort(m: &mut IndexMap) { + let mut ordered: Vec<_> = m.drain(..).collect(); + ordered.sort_by(|left, right| left.0.cmp(&right.0)); + m.extend(ordered); +} + +#[bench] +fn indexmap_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + map.sort_keys(); + map + }); +} + +#[bench] +fn indexmap_simple_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + simple_sort(&mut map); + map + }); +} + +#[bench] +fn indexmap_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + map.sort_keys(); + map + }); +} + +#[bench] +fn indexmap_simple_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + simple_sort(&mut map); + map + }); +} + +// measure the fixed overhead of cloning in sort benchmarks +#[bench] +fn indexmap_clone_for_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + b.iter(|| map.clone()); +} + +#[bench] +fn indexmap_clone_for_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + b.iter(|| map.clone()); +} diff --git a/deps/crates/vendor/indexmap/benches/faststring.rs b/deps/crates/vendor/indexmap/benches/faststring.rs new file mode 100644 index 00000000000000..bfe39590836a8c --- /dev/null +++ b/deps/crates/vendor/indexmap/benches/faststring.rs @@ -0,0 +1,183 @@ +#![feature(test)] + +extern crate test; + +use test::Bencher; + +use indexmap::IndexMap; + +use std::collections::HashMap; + +use std::hash::{Hash, Hasher}; + +use std::borrow::Borrow; +use std::ops::Deref; + +/// Use a consistently seeded Rng for benchmark stability +fn small_rng() -> fastrand::Rng { + let seed = u64::from_le_bytes(*b"indexmap"); + fastrand::Rng::with_seed(seed) +} + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(transparent)] +pub struct OneShot(pub T); + +impl Hash for OneShot { + fn hash(&self, h: &mut H) { + h.write(self.0.as_bytes()) + } +} + +impl<'a, S> From<&'a S> for &'a OneShot +where + S: AsRef, +{ + #[allow(unsafe_code)] + fn from(s: &'a S) -> Self { + let s: &str = s.as_ref(); + // SAFETY: OneShot is a `repr(transparent)` wrapper + unsafe { &*(s as *const str as *const OneShot) } + } +} + +impl Hash for OneShot { + fn hash(&self, h: &mut H) { + h.write(self.0.as_bytes()) + } +} + +impl Borrow> for OneShot { + fn borrow(&self) -> &OneShot { + <&OneShot>::from(&self.0) + } +} + +impl Deref for OneShot { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +fn shuffled_keys(iter: I) -> Vec +where + I: IntoIterator, +{ + let mut v = Vec::from_iter(iter); + let mut rng = small_rng(); + rng.shuffle(&mut v); + v +} + +#[bench] +fn insert_hashmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_string_oneshot_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(OneShot(x.to_string()), ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn lookup_hashmap_10_000_exist_string(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key.to_string(), 1); + } + let lookups = (5000..c).map(|x| x.to_string()).collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_10_000_exist_string_oneshot(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(OneShot(key.to_string()), 1); + } + let lookups = (5000..c) + .map(|x| OneShot(x.to_string())) + .collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist_string(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key.to_string(), 1); + } + let lookups = (5000..c).map(|x| x.to_string()).collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist_string_oneshot(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(OneShot(key.to_string()), 1); + } + let lookups = (5000..c) + .map(|x| OneShot(x.to_string())) + .collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} diff --git a/deps/crates/vendor/indexmap/src/arbitrary.rs b/deps/crates/vendor/indexmap/src/arbitrary.rs new file mode 100644 index 00000000000000..7798438c156772 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/arbitrary.rs @@ -0,0 +1,77 @@ +#[cfg(feature = "arbitrary")] +#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] +mod impl_arbitrary { + use crate::{IndexMap, IndexSet}; + use arbitrary::{Arbitrary, Result, Unstructured}; + use core::hash::{BuildHasher, Hash}; + + impl<'a, K, V, S> Arbitrary<'a> for IndexMap + where + K: Arbitrary<'a> + Hash + Eq, + V: Arbitrary<'a>, + S: BuildHasher + Default, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + } + + impl<'a, T, S> Arbitrary<'a> for IndexSet + where + T: Arbitrary<'a> + Hash + Eq, + S: BuildHasher + Default, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + } +} + +#[cfg(feature = "quickcheck")] +#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))] +mod impl_quickcheck { + use crate::{IndexMap, IndexSet}; + use alloc::boxed::Box; + use alloc::vec::Vec; + use core::hash::{BuildHasher, Hash}; + use quickcheck::{Arbitrary, Gen}; + + impl Arbitrary for IndexMap + where + K: Arbitrary + Hash + Eq, + V: Arbitrary, + S: BuildHasher + Default + Clone + 'static, + { + fn arbitrary(g: &mut Gen) -> Self { + Self::from_iter(Vec::arbitrary(g)) + } + + fn shrink(&self) -> Box> { + let vec = Vec::from_iter(self.clone()); + Box::new(vec.shrink().map(Self::from_iter)) + } + } + + impl Arbitrary for IndexSet + where + T: Arbitrary + Hash + Eq, + S: BuildHasher + Default + Clone + 'static, + { + fn arbitrary(g: &mut Gen) -> Self { + Self::from_iter(Vec::arbitrary(g)) + } + + fn shrink(&self) -> Box> { + let vec = Vec::from_iter(self.clone()); + Box::new(vec.shrink().map(Self::from_iter)) + } + } +} diff --git a/deps/crates/vendor/indexmap/src/borsh.rs b/deps/crates/vendor/indexmap/src/borsh.rs new file mode 100644 index 00000000000000..b104920848e68c --- /dev/null +++ b/deps/crates/vendor/indexmap/src/borsh.rs @@ -0,0 +1,127 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "borsh")))] + +use alloc::vec::Vec; +use core::hash::BuildHasher; +use core::hash::Hash; + +use borsh::error::ERROR_ZST_FORBIDDEN; +use borsh::io::{Error, ErrorKind, Read, Result, Write}; +use borsh::{BorshDeserialize, BorshSerialize}; + +use crate::map::IndexMap; +use crate::set::IndexSet; + +// NOTE: the real `#[deprecated]` attribute doesn't work for trait implementations, +// but we can get close by mimicking the message style for documentation. +///

+impl BorshSerialize for IndexMap +where + K: BorshSerialize, + V: BorshSerialize, +{ + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + check_zst::()?; + + let iterator = self.iter(); + + u32::try_from(iterator.len()) + .map_err(|_| ErrorKind::InvalidData)? + .serialize(writer)?; + + for (key, value) in iterator { + key.serialize(writer)?; + value.serialize(writer)?; + } + + Ok(()) + } +} + +///
👎Deprecated: use borsh's indexmap feature instead.
+impl BorshDeserialize for IndexMap +where + K: BorshDeserialize + Eq + Hash, + V: BorshDeserialize, + S: BuildHasher + Default, +{ + #[inline] + fn deserialize_reader(reader: &mut R) -> Result { + check_zst::()?; + let vec = >::deserialize_reader(reader)?; + Ok(vec.into_iter().collect::>()) + } +} + +///
👎Deprecated: use borsh's indexmap feature instead.
+impl BorshSerialize for IndexSet +where + T: BorshSerialize, +{ + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + check_zst::()?; + + let iterator = self.iter(); + + u32::try_from(iterator.len()) + .map_err(|_| ErrorKind::InvalidData)? + .serialize(writer)?; + + for item in iterator { + item.serialize(writer)?; + } + + Ok(()) + } +} + +///
👎Deprecated: use borsh's indexmap feature instead.
+impl BorshDeserialize for IndexSet +where + T: BorshDeserialize + Eq + Hash, + S: BuildHasher + Default, +{ + #[inline] + fn deserialize_reader(reader: &mut R) -> Result { + check_zst::()?; + let vec = >::deserialize_reader(reader)?; + Ok(vec.into_iter().collect::>()) + } +} + +fn check_zst() -> Result<()> { + if size_of::() == 0 { + return Err(Error::new(ErrorKind::InvalidData, ERROR_ZST_FORBIDDEN)); + } + Ok(()) +} + +#[cfg(test)] +mod borsh_tests { + use super::*; + + #[test] + fn map_borsh_roundtrip() { + let original_map: IndexMap = { + let mut map = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + map + }; + let serialized_map = borsh::to_vec(&original_map).unwrap(); + let deserialized_map: IndexMap = + BorshDeserialize::try_from_slice(&serialized_map).unwrap(); + assert_eq!(original_map, deserialized_map); + } + + #[test] + fn set_borsh_roundtrip() { + let original_map: IndexSet = [1, 2, 3, 4, 5, 6].into_iter().collect(); + let serialized_map = borsh::to_vec(&original_map).unwrap(); + let deserialized_map: IndexSet = + BorshDeserialize::try_from_slice(&serialized_map).unwrap(); + assert_eq!(original_map, deserialized_map); + } +} diff --git a/deps/crates/vendor/indexmap/src/inner.rs b/deps/crates/vendor/indexmap/src/inner.rs new file mode 100644 index 00000000000000..2923ef7dd03f39 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/inner.rs @@ -0,0 +1,698 @@ +//! This is the core implementation that doesn't depend on the hasher at all. +//! +//! The methods of `Core` don't use any Hash properties of K. +//! +//! It's cleaner to separate them out, then the compiler checks that we are not +//! using Hash at all in these methods. +//! +//! However, we should probably not let this show in the public API or docs. + +mod entry; +mod extract; + +use alloc::vec::{self, Vec}; +use core::mem; +use core::ops::RangeBounds; +use hashbrown::hash_table; + +use crate::util::simplify_range; +use crate::{Bucket, Equivalent, HashValue, TryReserveError}; + +type Indices = hash_table::HashTable; +type Entries = Vec>; + +pub use entry::{OccupiedEntry, VacantEntry}; +pub(crate) use extract::ExtractCore; + +/// Core of the map that does not depend on S +#[cfg_attr(feature = "test_debug", derive(Debug))] +pub(crate) struct Core { + /// indices mapping from the entry hash to its index. + indices: Indices, + /// entries is a dense vec maintaining entry order. + entries: Entries, +} + +#[inline(always)] +fn get_hash(entries: &[Bucket]) -> impl Fn(&usize) -> u64 + use<'_, K, V> { + move |&i| entries[i].hash.get() +} + +#[inline] +fn equivalent<'a, K, V, Q: ?Sized + Equivalent>( + key: &'a Q, + entries: &'a [Bucket], +) -> impl Fn(&usize) -> bool + use<'a, K, V, Q> { + move |&i| Q::equivalent(key, &entries[i].key) +} + +#[inline] +fn erase_index(table: &mut Indices, hash: HashValue, index: usize) { + if let Ok(entry) = table.find_entry(hash.get(), move |&i| i == index) { + entry.remove(); + } else if cfg!(debug_assertions) { + panic!("index not found"); + } +} + +#[inline] +fn update_index(table: &mut Indices, hash: HashValue, old: usize, new: usize) { + let index = table + .find_mut(hash.get(), move |&i| i == old) + .expect("index not found"); + *index = new; +} + +/// Inserts many entries into the indices table without reallocating, +/// and without regard for duplication. +/// +/// ***Panics*** if there is not sufficient capacity already. +fn insert_bulk_no_grow(indices: &mut Indices, entries: &[Bucket]) { + assert!(indices.capacity() - indices.len() >= entries.len()); + for entry in entries { + indices.insert_unique(entry.hash.get(), indices.len(), |_| unreachable!()); + } +} + +impl Clone for Core +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + let mut new = Self::new(); + new.clone_from(self); + new + } + + fn clone_from(&mut self, other: &Self) { + self.indices.clone_from(&other.indices); + if self.entries.capacity() < other.entries.len() { + // If we must resize, match the indices capacity. + let additional = other.entries.len() - self.entries.len(); + self.reserve_entries(additional); + } + self.entries.clone_from(&other.entries); + } +} + +impl Core { + /// The maximum capacity before the `entries` allocation would exceed `isize::MAX`. + const MAX_ENTRIES_CAPACITY: usize = (isize::MAX as usize) / size_of::>(); + + #[inline] + pub(crate) const fn new() -> Self { + Core { + indices: Indices::new(), + entries: Vec::new(), + } + } + + #[inline] + pub(crate) fn with_capacity(n: usize) -> Self { + Core { + indices: Indices::with_capacity(n), + entries: Vec::with_capacity(n), + } + } + + #[inline] + pub(crate) fn into_entries(self) -> Entries { + self.entries + } + + #[inline] + pub(crate) fn as_entries(&self) -> &[Bucket] { + &self.entries + } + + #[inline] + pub(crate) fn as_entries_mut(&mut self) -> &mut [Bucket] { + &mut self.entries + } + + pub(crate) fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Bucket]), + { + f(&mut self.entries); + self.rebuild_hash_table(); + } + + #[inline] + pub(crate) fn len(&self) -> usize { + debug_assert_eq!(self.entries.len(), self.indices.len()); + self.indices.len() + } + + #[inline] + pub(crate) fn capacity(&self) -> usize { + Ord::min(self.indices.capacity(), self.entries.capacity()) + } + + pub(crate) fn clear(&mut self) { + self.indices.clear(); + self.entries.clear(); + } + + pub(crate) fn truncate(&mut self, len: usize) { + if len < self.len() { + self.erase_indices(len, self.entries.len()); + self.entries.truncate(len); + } + } + + #[track_caller] + pub(crate) fn drain(&mut self, range: R) -> vec::Drain<'_, Bucket> + where + R: RangeBounds, + { + let range = simplify_range(range, self.entries.len()); + self.erase_indices(range.start, range.end); + self.entries.drain(range) + } + + #[cfg(feature = "rayon")] + pub(crate) fn par_drain(&mut self, range: R) -> rayon::vec::Drain<'_, Bucket> + where + K: Send, + V: Send, + R: RangeBounds, + { + use rayon::iter::ParallelDrainRange; + let range = simplify_range(range, self.entries.len()); + self.erase_indices(range.start, range.end); + self.entries.par_drain(range) + } + + #[track_caller] + pub(crate) fn split_off(&mut self, at: usize) -> Self { + let len = self.entries.len(); + assert!( + at <= len, + "index out of bounds: the len is {len} but the index is {at}. Expected index <= len" + ); + + self.erase_indices(at, self.entries.len()); + let entries = self.entries.split_off(at); + + let mut indices = Indices::with_capacity(entries.len()); + insert_bulk_no_grow(&mut indices, &entries); + Self { indices, entries } + } + + #[track_caller] + pub(crate) fn split_splice(&mut self, range: R) -> (Self, vec::IntoIter>) + where + R: RangeBounds, + { + let range = simplify_range(range, self.len()); + self.erase_indices(range.start, self.entries.len()); + let entries = self.entries.split_off(range.end); + let drained = self.entries.split_off(range.start); + + let mut indices = Indices::with_capacity(entries.len()); + insert_bulk_no_grow(&mut indices, &entries); + (Self { indices, entries }, drained.into_iter()) + } + + /// Append from another map without checking whether items already exist. + pub(crate) fn append_unchecked(&mut self, other: &mut Self) { + self.reserve(other.len()); + insert_bulk_no_grow(&mut self.indices, &other.entries); + self.entries.append(&mut other.entries); + other.indices.clear(); + } + + /// Reserve capacity for `additional` more key-value pairs. + pub(crate) fn reserve(&mut self, additional: usize) { + self.indices.reserve(additional, get_hash(&self.entries)); + // Only grow entries if necessary, since we also round up capacity. + if additional > self.entries.capacity() - self.entries.len() { + self.reserve_entries(additional); + } + } + + /// Reserve capacity for `additional` more key-value pairs, without over-allocating. + pub(crate) fn reserve_exact(&mut self, additional: usize) { + self.indices.reserve(additional, get_hash(&self.entries)); + self.entries.reserve_exact(additional); + } + + /// Try to reserve capacity for `additional` more key-value pairs. + pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.indices + .try_reserve(additional, get_hash(&self.entries)) + .map_err(TryReserveError::from_hashbrown)?; + // Only grow entries if necessary, since we also round up capacity. + if additional > self.entries.capacity() - self.entries.len() { + self.try_reserve_entries(additional) + } else { + Ok(()) + } + } + + /// Try to reserve entries capacity, rounded up to match the indices + fn try_reserve_entries(&mut self, additional: usize) -> Result<(), TryReserveError> { + // Use a soft-limit on the maximum capacity, but if the caller explicitly + // requested more, do it and let them have the resulting error. + let new_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); + let try_add = new_capacity - self.entries.len(); + if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { + return Ok(()); + } + self.entries + .try_reserve_exact(additional) + .map_err(TryReserveError::from_alloc) + } + + /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating. + pub(crate) fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.indices + .try_reserve(additional, get_hash(&self.entries)) + .map_err(TryReserveError::from_hashbrown)?; + self.entries + .try_reserve_exact(additional) + .map_err(TryReserveError::from_alloc) + } + + /// Shrink the capacity of the map with a lower bound + pub(crate) fn shrink_to(&mut self, min_capacity: usize) { + self.indices + .shrink_to(min_capacity, get_hash(&self.entries)); + self.entries.shrink_to(min_capacity); + } + + /// Remove the last key-value pair + pub(crate) fn pop(&mut self) -> Option<(K, V)> { + if let Some(entry) = self.entries.pop() { + let last = self.entries.len(); + erase_index(&mut self.indices, entry.hash, last); + Some((entry.key, entry.value)) + } else { + None + } + } + + /// Return the index in `entries` where an equivalent key can be found + pub(crate) fn get_index_of(&self, hash: HashValue, key: &Q) -> Option + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + self.indices.find(hash.get(), eq).copied() + } + + /// Return the index in `entries` where an equivalent key can be found + pub(crate) fn get_index_of_raw(&self, hash: HashValue, mut is_match: F) -> Option + where + F: FnMut(&K) -> bool, + { + let eq = move |&i: &usize| is_match(&self.entries[i].key); + self.indices.find(hash.get(), eq).copied() + } + + /// Append a key-value pair to `entries`, + /// *without* checking whether it already exists. + fn push_entry(&mut self, hash: HashValue, key: K, value: V) { + if self.entries.len() == self.entries.capacity() { + // Reserve our own capacity synced to the indices, + // rather than letting `Vec::push` just double it. + self.reserve_entries(1); + } + self.entries.push(Bucket { hash, key, value }); + } + + pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option) + where + K: Eq, + { + let eq = equivalent(&key, &self.entries); + let hasher = get_hash(&self.entries); + match self.indices.entry(hash.get(), eq, hasher) { + hash_table::Entry::Occupied(entry) => { + let i = *entry.get(); + (i, Some(mem::replace(&mut self.entries[i].value, value))) + } + hash_table::Entry::Vacant(entry) => { + let i = self.entries.len(); + entry.insert(i); + self.push_entry(hash, key, value); + debug_assert_eq!(self.indices.len(), self.entries.len()); + (i, None) + } + } + } + + /// Same as `insert_full`, except it also replaces the key + pub(crate) fn replace_full( + &mut self, + hash: HashValue, + key: K, + value: V, + ) -> (usize, Option<(K, V)>) + where + K: Eq, + { + let eq = equivalent(&key, &self.entries); + let hasher = get_hash(&self.entries); + match self.indices.entry(hash.get(), eq, hasher) { + hash_table::Entry::Occupied(entry) => { + let i = *entry.get(); + let entry = &mut self.entries[i]; + let kv = ( + mem::replace(&mut entry.key, key), + mem::replace(&mut entry.value, value), + ); + (i, Some(kv)) + } + hash_table::Entry::Vacant(entry) => { + let i = self.entries.len(); + entry.insert(i); + self.push_entry(hash, key, value); + debug_assert_eq!(self.indices.len(), self.entries.len()); + (i, None) + } + } + } + + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); + let (key, value) = self.shift_remove_finish(index); + Some((index, key, value)) + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + let (index, _) = self.indices.find_entry(hash.get(), eq).ok()?.remove(); + let (key, value) = self.swap_remove_finish(index); + Some((index, key, value)) + } + + /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` + /// + /// All of these items should still be at their original location in `entries`. + /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`. + fn erase_indices(&mut self, start: usize, end: usize) { + let (init, shifted_entries) = self.entries.split_at(end); + let (start_entries, erased_entries) = init.split_at(start); + + let erased = erased_entries.len(); + let shifted = shifted_entries.len(); + let half_capacity = self.indices.capacity() / 2; + + // Use a heuristic between different strategies + if erased == 0 { + // Degenerate case, nothing to do + } else if start + shifted < half_capacity && start < erased { + // Reinsert everything, as there are few kept indices + self.indices.clear(); + + // Reinsert stable indices, then shifted indices + insert_bulk_no_grow(&mut self.indices, start_entries); + insert_bulk_no_grow(&mut self.indices, shifted_entries); + } else if erased + shifted < half_capacity { + // Find each affected index, as there are few to adjust + + // Find erased indices + for (i, entry) in (start..).zip(erased_entries) { + erase_index(&mut self.indices, entry.hash, i); + } + + // Find shifted indices + for ((new, old), entry) in (start..).zip(end..).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, old, new); + } + } else { + // Sweep the whole table for adjustments + let offset = end - start; + self.indices.retain(move |i| { + if *i >= end { + *i -= offset; + true + } else { + *i < start + } + }); + } + + debug_assert_eq!(self.indices.len(), start + shifted); + } + + pub(crate) fn retain_in_order(&mut self, mut keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + self.entries + .retain_mut(|entry| keep(&mut entry.key, &mut entry.value)); + if self.entries.len() < self.indices.len() { + self.rebuild_hash_table(); + } + } + + fn rebuild_hash_table(&mut self) { + self.indices.clear(); + insert_bulk_no_grow(&mut self.indices, &self.entries); + } + + pub(crate) fn reverse(&mut self) { + self.entries.reverse(); + + // No need to save hash indices, can easily calculate what they should + // be, given that this is an in-place reversal. + let len = self.entries.len(); + for i in &mut self.indices { + *i = len - *i - 1; + } + } + + /// Reserve entries capacity, rounded up to match the indices + #[inline] + fn reserve_entries(&mut self, additional: usize) { + // Use a soft-limit on the maximum capacity, but if the caller explicitly + // requested more, do it and let them have the resulting panic. + let try_capacity = Ord::min(self.indices.capacity(), Self::MAX_ENTRIES_CAPACITY); + let try_add = try_capacity - self.entries.len(); + if try_add > additional && self.entries.try_reserve_exact(try_add).is_ok() { + return; + } + self.entries.reserve_exact(additional); + } + + /// Insert a key-value pair in `entries`, + /// *without* checking whether it already exists. + pub(super) fn insert_unique(&mut self, hash: HashValue, key: K, value: V) -> &mut Bucket { + let i = self.indices.len(); + debug_assert_eq!(i, self.entries.len()); + self.indices + .insert_unique(hash.get(), i, get_hash(&self.entries)); + self.push_entry(hash, key, value); + &mut self.entries[i] + } + + /// Replaces the key at the given index, + /// *without* checking whether it already exists. + #[track_caller] + pub(crate) fn replace_index_unique(&mut self, index: usize, hash: HashValue, key: K) -> K { + // NB: This removal and insertion isn't "no grow" (with unreachable hasher) + // because hashbrown's tombstones might force a resize anyway. + erase_index(&mut self.indices, self.entries[index].hash, index); + self.indices + .insert_unique(hash.get(), index, get_hash(&self.entries)); + + let entry = &mut self.entries[index]; + entry.hash = hash; + mem::replace(&mut entry.key, key) + } + + /// Insert a key-value pair in `entries` at a particular index, + /// *without* checking whether it already exists. + pub(crate) fn shift_insert_unique( + &mut self, + index: usize, + hash: HashValue, + key: K, + value: V, + ) -> &mut Bucket { + let end = self.indices.len(); + assert!(index <= end); + // Increment others first so we don't have duplicate indices. + self.increment_indices(index, end); + let entries = &*self.entries; + self.indices.insert_unique(hash.get(), index, move |&i| { + // Adjust for the incremented indices to find hashes. + debug_assert_ne!(i, index); + let i = if i < index { i } else { i - 1 }; + entries[i].hash.get() + }); + if self.entries.len() == self.entries.capacity() { + // Reserve our own capacity synced to the indices, + // rather than letting `Vec::insert` just double it. + self.reserve_entries(1); + } + self.entries.insert(index, Bucket { hash, key, value }); + &mut self.entries[index] + } + + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.shift_remove_finish(index)) + } + None => None, + } + } + + /// Remove an entry by shifting all entries that follow it + /// + /// The index should already be removed from `self.indices`. + fn shift_remove_finish(&mut self, index: usize) -> (K, V) { + // Correct indices that point to the entries that followed the removed entry. + self.decrement_indices(index + 1, self.entries.len()); + + // Use Vec::remove to actually remove the entry. + let entry = self.entries.remove(index); + (entry.key, entry.value) + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.swap_remove_finish(index)) + } + None => None, + } + } + + /// Finish removing an entry by swapping it with the last + /// + /// The index should already be removed from `self.indices`. + fn swap_remove_finish(&mut self, index: usize) -> (K, V) { + // use swap_remove, but then we need to update the index that points + // to the other entry that has to move + let entry = self.entries.swap_remove(index); + + // correct index that points to the entry that had to swap places + if let Some(entry) = self.entries.get(index) { + // was not last element + // examine new element in `index` and find it in indices + let last = self.entries.len(); + update_index(&mut self.indices, entry.hash, last, index); + } + + (entry.key, entry.value) + } + + /// Decrement all indices in the range `start..end`. + /// + /// The index `start - 1` should not exist in `self.indices`. + /// All entries should still be in their original positions. + fn decrement_indices(&mut self, start: usize, end: usize) { + // Use a heuristic between a full sweep vs. a `find()` for every shifted item. + let shifted_entries = &self.entries[start..end]; + if shifted_entries.len() > self.indices.capacity() / 2 { + // Shift all indices in range. + for i in &mut self.indices { + if start <= *i && *i < end { + *i -= 1; + } + } + } else { + // Find each entry in range to shift its index. + for (i, entry) in (start..end).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, i, i - 1); + } + } + } + + /// Increment all indices in the range `start..end`. + /// + /// The index `end` should not exist in `self.indices`. + /// All entries should still be in their original positions. + fn increment_indices(&mut self, start: usize, end: usize) { + // Use a heuristic between a full sweep vs. a `find()` for every shifted item. + let shifted_entries = &self.entries[start..end]; + if shifted_entries.len() > self.indices.capacity() / 2 { + // Shift all indices in range. + for i in &mut self.indices { + if start <= *i && *i < end { + *i += 1; + } + } + } else { + // Find each entry in range to shift its index, updated in reverse so + // we never have duplicated indices that might have a hash collision. + for (i, entry) in (start..end).zip(shifted_entries).rev() { + update_index(&mut self.indices, entry.hash, i, i + 1); + } + } + } + + #[track_caller] + pub(super) fn move_index(&mut self, from: usize, to: usize) { + let from_hash = self.entries[from].hash; + if from != to { + let _ = self.entries[to]; // explicit bounds check + + // Find the bucket index first so we won't lose it among other updated indices. + let bucket = self + .indices + .find_bucket_index(from_hash.get(), move |&i| i == from) + .expect("index not found"); + + self.move_index_inner(from, to); + *self.indices.get_bucket_mut(bucket).unwrap() = to; + } + } + + fn move_index_inner(&mut self, from: usize, to: usize) { + // Update all other indices and rotate the entry positions. + if from < to { + self.decrement_indices(from + 1, to + 1); + self.entries[from..=to].rotate_left(1); + } else if to < from { + self.increment_indices(to, from); + self.entries[to..=from].rotate_right(1); + } + } + + #[track_caller] + pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { + // If they're equal and in-bounds, there's nothing to do. + if a == b && a < self.entries.len() { + return; + } + + // We'll get a "nice" bounds-check from indexing `entries`, + // and then we expect to find it in the table as well. + match self.indices.get_disjoint_mut( + [self.entries[a].hash.get(), self.entries[b].hash.get()], + move |i, &x| if i == 0 { x == a } else { x == b }, + ) { + [Some(ref_a), Some(ref_b)] => { + mem::swap(ref_a, ref_b); + self.entries.swap(a, b); + } + _ => panic!("indices not found"), + } + } +} + +#[test] +fn assert_send_sync() { + fn assert_send_sync() {} + assert_send_sync::>(); +} diff --git a/deps/crates/vendor/indexmap/src/inner/entry.rs b/deps/crates/vendor/indexmap/src/inner/entry.rs new file mode 100644 index 00000000000000..bcea438fee467b --- /dev/null +++ b/deps/crates/vendor/indexmap/src/inner/entry.rs @@ -0,0 +1,398 @@ +use super::{Bucket, Core, equivalent, get_hash}; +use crate::HashValue; +use crate::map::{Entry, IndexedEntry}; +use core::cmp::Ordering; +use core::mem; + +impl<'a, K, V> Entry<'a, K, V> { + pub(crate) fn new(map: &'a mut Core, hash: HashValue, key: K) -> Self + where + K: Eq, + { + let eq = equivalent(&key, &map.entries); + match map.indices.find_entry(hash.get(), eq) { + Ok(entry) => Entry::Occupied(OccupiedEntry { + bucket: entry.bucket_index(), + index: *entry.get(), + map, + }), + Err(_) => Entry::Vacant(VacantEntry { map, hash, key }), + } + } +} + +/// A view into an occupied entry in an [`IndexMap`][crate::IndexMap]. +/// It is part of the [`Entry`] enum. +pub struct OccupiedEntry<'a, K, V> { + map: &'a mut Core, + // We have a mutable reference to the map, which keeps these two + // indices valid and pointing to the correct entry. + index: usize, + bucket: usize, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Constructor for `RawEntryMut::from_hash` + pub(crate) fn from_hash( + map: &'a mut Core, + hash: HashValue, + mut is_match: F, + ) -> Result> + where + F: FnMut(&K) -> bool, + { + let entries = &*map.entries; + let eq = move |&i: &usize| is_match(&entries[i].key); + match map.indices.find_entry(hash.get(), eq) { + Ok(entry) => Ok(OccupiedEntry { + bucket: entry.bucket_index(), + index: *entry.get(), + map, + }), + Err(_) => Err(map), + } + } + + pub(crate) fn into_core(self) -> &'a mut Core { + self.map + } + + pub(crate) fn get_bucket(&self) -> &Bucket { + &self.map.entries[self.index] + } + + pub(crate) fn get_bucket_mut(&mut self) -> &mut Bucket { + &mut self.map.entries[self.index] + } + + pub(crate) fn into_bucket(self) -> &'a mut Bucket { + &mut self.map.entries[self.index] + } + + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.index + } + + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key(&self) -> &K { + &self.get_bucket().key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.get_bucket().value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// [`Entry`] value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + &mut self.get_bucket_mut().value + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + &mut self.into_bucket().value + } + + /// Sets the value of the entry to `value`, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove()`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(self) -> V { + self.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(self) -> (K, V) { + self.swap_remove_entry() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.swap_remove_finish(self.index) + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(mut self) -> (K, V) { + self.remove_index(); + self.map.shift_remove_finish(self.index) + } + + fn remove_index(&mut self) { + let entry = self.map.indices.get_bucket_entry(self.bucket).unwrap(); + debug_assert_eq!(*entry.get(), self.index); + entry.remove(); + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn move_index(self, to: usize) { + if self.index != to { + let _ = self.map.entries[to]; // explicit bounds check + self.map.move_index_inner(self.index, to); + self.update_index(to); + } + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn swap_indices(self, other: usize) { + if self.index != other { + // Since we already know where our bucket is, we only need to find the other. + let hash = self.map.entries[other].hash; + let other_mut = self.map.indices.find_mut(hash.get(), move |&i| i == other); + *other_mut.expect("index not found") = self.index; + + self.map.entries.swap(self.index, other); + self.update_index(other); + } + } + + fn update_index(self, to: usize) { + let index = self.map.indices.get_bucket_mut(self.bucket).unwrap(); + debug_assert_eq!(*index, self.index); + *index = to; + } +} + +impl<'a, K, V> From> for OccupiedEntry<'a, K, V> { + fn from(other: IndexedEntry<'a, K, V>) -> Self { + let index = other.index(); + let map = other.into_core(); + let hash = map.entries[index].hash; + let bucket = map + .indices + .find_bucket_index(hash.get(), move |&i| i == index) + .expect("index not found"); + Self { map, index, bucket } + } +} + +/// A view into a vacant entry in an [`IndexMap`][crate::IndexMap]. +/// It is part of the [`Entry`] enum. +pub struct VacantEntry<'a, K, V> { + map: &'a mut Core, + hash: HashValue, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Return the index where a key-value pair may be inserted. + pub fn index(&self) -> usize { + self.map.indices.len() + } + + /// Gets a reference to the key that was used to find the entry. + pub fn key(&self) -> &K { + &self.key + } + + pub(crate) fn key_mut(&mut self) -> &mut K { + &mut self.key + } + + /// Takes ownership of the key, leaving the entry vacant. + pub fn into_key(self) -> K { + self.key + } + + /// Inserts the entry's key and the given value into the map, and returns a mutable reference + /// to the value. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert(self, value: V) -> &'a mut V { + let Self { map, hash, key } = self; + map.insert_unique(hash, key, value).value_mut() + } + + /// Inserts the entry's key and the given value into the map, and returns an `OccupiedEntry`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + let Self { map, hash, key } = self; + let index = map.indices.len(); + debug_assert_eq!(index, map.entries.len()); + let bucket = map + .indices + .insert_unique(hash.get(), index, get_hash(&map.entries)) + .bucket_index(); + map.push_entry(hash, key, value); + OccupiedEntry { map, index, bucket } + } + + /// Inserts the entry's key and the given value into the map at its ordered + /// position among sorted keys, and returns the new index and a mutable + /// reference to the value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted(self, value: V) -> (usize, &'a mut V) + where + K: Ord, + { + let slice = crate::map::Slice::from_slice(&self.map.entries); + let i = slice.binary_search_keys(&self.key).unwrap_err(); + (i, self.shift_insert(i, value)) + } + + /// Inserts the entry's key and the given value into the map at its ordered + /// position among keys sorted by `cmp`, and returns the new index and a + /// mutable reference to the value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by(self, value: V, mut cmp: F) -> (usize, &'a mut V) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let slice = crate::map::Slice::from_slice(&self.map.entries); + let (Ok(i) | Err(i)) = slice.binary_search_by(|k, v| cmp(k, v, &self.key, &value)); + (i, self.shift_insert(i, value)) + } + + /// Inserts the entry's key and the given value into the map at its ordered + /// position using a sort-key extraction function, and returns the new index + /// and a mutable reference to the value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by_key(self, value: V, mut sort_key: F) -> (usize, &'a mut V) + where + B: Ord, + F: FnMut(&K, &V) -> B, + { + let search_key = sort_key(&self.key, &value); + let slice = crate::map::Slice::from_slice(&self.map.entries); + let (Ok(i) | Err(i)) = slice.binary_search_by_key(&search_key, sort_key); + (i, self.shift_insert(i, value)) + } + + /// Inserts the entry's key and the given value into the map at the given index, + /// shifting others to the right, and returns a mutable reference to the value. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn shift_insert(self, index: usize, value: V) -> &'a mut V { + self.map + .shift_insert_unique(index, self.hash, self.key, value) + .value_mut() + } + + /// Replaces the key at the given index with this entry's key, returning the + /// old key and an `OccupiedEntry` for that index. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn replace_index(self, index: usize) -> (K, OccupiedEntry<'a, K, V>) { + let Self { map, hash, key } = self; + + // NB: This removal and insertion isn't "no grow" (with unreachable hasher) + // because hashbrown's tombstones might force a resize anyway. + let old_hash = map.entries[index].hash; + map.indices + .find_entry(old_hash.get(), move |&i| i == index) + .expect("index not found") + .remove(); + let bucket = map + .indices + .insert_unique(hash.get(), index, get_hash(&map.entries)) + .bucket_index(); + + let entry = &mut map.entries[index]; + entry.hash = hash; + let old_key = mem::replace(&mut entry.key, key); + + (old_key, OccupiedEntry { map, index, bucket }) + } +} diff --git a/deps/crates/vendor/indexmap/src/inner/extract.rs b/deps/crates/vendor/indexmap/src/inner/extract.rs new file mode 100644 index 00000000000000..b85c22ebcccc72 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/inner/extract.rs @@ -0,0 +1,108 @@ +#![allow(unsafe_code)] + +use super::{Bucket, Core}; +use crate::util::simplify_range; + +use core::ops::RangeBounds; + +impl Core { + #[track_caller] + pub(crate) fn extract(&mut self, range: R) -> ExtractCore<'_, K, V> + where + R: RangeBounds, + { + let range = simplify_range(range, self.entries.len()); + + // SAFETY: We must have consistent lengths to start, so that's a hard assertion. + // Then the worst `set_len` can do is leak items if `ExtractCore` doesn't drop. + assert_eq!(self.entries.len(), self.indices.len()); + unsafe { + self.entries.set_len(range.start); + } + ExtractCore { + map: self, + new_len: range.start, + current: range.start, + end: range.end, + } + } +} + +pub(crate) struct ExtractCore<'a, K, V> { + map: &'a mut Core, + new_len: usize, + current: usize, + end: usize, +} + +impl Drop for ExtractCore<'_, K, V> { + fn drop(&mut self) { + let old_len = self.map.indices.len(); + let mut new_len = self.new_len; + + debug_assert!(new_len <= self.current); + debug_assert!(self.current <= self.end); + debug_assert!(self.current <= old_len); + debug_assert!(old_len <= self.map.entries.capacity()); + + // SAFETY: We assume `new_len` and `current` were correctly maintained by the iterator. + // So `entries[new_len..current]` were extracted, but the rest before and after are valid. + unsafe { + if new_len == self.current { + // Nothing was extracted, so any remaining items can be left in place. + new_len = old_len; + } else if self.current < old_len { + // Need to shift the remaining items down. + let tail_len = old_len - self.current; + let base = self.map.entries.as_mut_ptr(); + let src = base.add(self.current); + let dest = base.add(new_len); + src.copy_to(dest, tail_len); + new_len += tail_len; + } + self.map.entries.set_len(new_len); + } + + if new_len != old_len { + // We don't keep track of *which* items were extracted, so reindex everything. + self.map.rebuild_hash_table(); + } + } +} + +impl ExtractCore<'_, K, V> { + pub(crate) fn extract_if(&mut self, mut pred: F) -> Option> + where + F: FnMut(&mut Bucket) -> bool, + { + debug_assert!(self.end <= self.map.entries.capacity()); + + let base = self.map.entries.as_mut_ptr(); + while self.current < self.end { + // SAFETY: We're maintaining both indices within bounds of the original entries, so + // 0..new_len and current..indices.len() are always valid items for our Drop to keep. + unsafe { + let item = base.add(self.current); + if pred(&mut *item) { + // Extract it! + self.current += 1; + return Some(item.read()); + } else { + // Keep it, shifting it down if needed. + if self.new_len != self.current { + debug_assert!(self.new_len < self.current); + let dest = base.add(self.new_len); + item.copy_to_nonoverlapping(dest, 1); + } + self.current += 1; + self.new_len += 1; + } + } + } + None + } + + pub(crate) fn remaining(&self) -> usize { + self.end - self.current + } +} diff --git a/deps/crates/vendor/indexmap/src/lib.rs b/deps/crates/vendor/indexmap/src/lib.rs new file mode 100644 index 00000000000000..78abbb5d6071ef --- /dev/null +++ b/deps/crates/vendor/indexmap/src/lib.rs @@ -0,0 +1,284 @@ +#![no_std] + +//! [`IndexMap`] is a hash table where the iteration order of the key-value +//! pairs is independent of the hash values of the keys. +//! +//! [`IndexSet`] is a corresponding hash set using the same implementation and +//! with similar properties. +//! +//! ### Highlights +//! +//! [`IndexMap`] and [`IndexSet`] are drop-in compatible with the std `HashMap` +//! and `HashSet`, but they also have some features of note: +//! +//! - The ordering semantics (see their documentation for details) +//! - Sorting methods and the [`.pop()`][IndexMap::pop] methods. +//! - The [`Equivalent`] trait, which offers more flexible equality definitions +//! between borrowed and owned versions of keys. +//! - The [`MutableKeys`][map::MutableKeys] trait, which gives opt-in mutable +//! access to map keys, and [`MutableValues`][set::MutableValues] for sets. +//! +//! ### Feature Flags +//! +//! To reduce the amount of compiled code in the crate by default, certain +//! features are gated behind [feature flags]. These allow you to opt in to (or +//! out of) functionality. Below is a list of the features available in this +//! crate. +//! +//! * `std`: Enables features which require the Rust standard library. For more +//! information see the section on [`no_std`]. +//! * `rayon`: Enables parallel iteration and other parallel methods. +//! * `serde`: Adds implementations for [`Serialize`] and [`Deserialize`] +//! to [`IndexMap`] and [`IndexSet`]. Alternative implementations for +//! (de)serializing [`IndexMap`] as an ordered sequence are available in the +//! [`map::serde_seq`] module. +//! * `arbitrary`: Adds implementations for the [`arbitrary::Arbitrary`] trait +//! to [`IndexMap`] and [`IndexSet`]. +//! * `quickcheck`: Adds implementations for the [`quickcheck::Arbitrary`] trait +//! to [`IndexMap`] and [`IndexSet`]. +//! * `borsh` (**deprecated**): Adds implementations for [`BorshSerialize`] and +//! [`BorshDeserialize`] to [`IndexMap`] and [`IndexSet`]. Due to a cyclic +//! dependency that arose between [`borsh`] and `indexmap`, `borsh v1.5.6` +//! added an `indexmap` feature that should be used instead of enabling the +//! feature here. +//! +//! _Note: only the `std` feature is enabled by default._ +//! +//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section +//! [`no_std`]: #no-standard-library-targets +//! [`Serialize`]: `::serde_core::Serialize` +//! [`Deserialize`]: `::serde_core::Deserialize` +//! [`BorshSerialize`]: `::borsh::BorshSerialize` +//! [`BorshDeserialize`]: `::borsh::BorshDeserialize` +//! [`borsh`]: `::borsh` +//! [`arbitrary::Arbitrary`]: `::arbitrary::Arbitrary` +//! [`quickcheck::Arbitrary`]: `::quickcheck::Arbitrary` +//! +//! ### Alternate Hashers +//! +//! [`IndexMap`] and [`IndexSet`] have a default hasher type +//! [`S = RandomState`][std::hash::RandomState], +//! just like the standard `HashMap` and `HashSet`, which is resistant to +//! HashDoS attacks but not the most performant. Type aliases can make it easier +//! to use alternate hashers: +//! +//! ``` +//! use fnv::FnvBuildHasher; +//! use indexmap::{IndexMap, IndexSet}; +//! +//! type FnvIndexMap = IndexMap; +//! type FnvIndexSet = IndexSet; +//! +//! let std: IndexSet = (0..100).collect(); +//! let fnv: FnvIndexSet = (0..100).collect(); +//! assert_eq!(std, fnv); +//! ``` +//! +//! ### Rust Version +//! +//! This version of indexmap requires Rust 1.85 or later. +//! +//! The indexmap 2.x release series will use a carefully considered version +//! upgrade policy, where in a later 2.x version, we will raise the minimum +//! required Rust version. +//! +//! ## No Standard Library Targets +//! +//! This crate supports being built without `std`, requiring `alloc` instead. +//! This is chosen by disabling the default "std" cargo feature, by adding +//! `default-features = false` to your dependency specification. +//! +//! - Creating maps and sets using [`new`][IndexMap::new] and +//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. +//! Use methods [`IndexMap::default`], [`with_hasher`][IndexMap::with_hasher], +//! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead. +//! A no-std compatible hasher will be needed as well, for example +//! from the crate `twox-hash`. +//! - Macros [`indexmap!`] and [`indexset!`] are unavailable without `std`. Use +//! the macros [`indexmap_with_default!`] and [`indexset_with_default!`] instead. + +#![cfg_attr(docsrs, feature(doc_cfg))] + +extern crate alloc; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +mod arbitrary; +mod inner; +#[macro_use] +mod macros; +#[cfg(feature = "borsh")] +mod borsh; +#[cfg(feature = "serde")] +mod serde; +#[cfg(feature = "sval")] +mod sval; +mod util; + +pub mod map; +pub mod set; + +// Placed after `map` and `set` so new `rayon` methods on the types +// are documented after the "normal" methods. +#[cfg(feature = "rayon")] +mod rayon; + +pub use crate::map::IndexMap; +pub use crate::set::IndexSet; +pub use equivalent::Equivalent; + +// shared private items + +/// Hash value newtype. Not larger than usize, since anything larger +/// isn't used for selecting position anyway. +#[derive(Clone, Copy, Debug, PartialEq)] +struct HashValue(usize); + +impl HashValue { + #[inline(always)] + fn get(self) -> u64 { + self.0 as u64 + } +} + +#[derive(Copy, Debug)] +struct Bucket { + hash: HashValue, + key: K, + value: V, +} + +impl Clone for Bucket +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + Bucket { + hash: self.hash, + key: self.key.clone(), + value: self.value.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.hash = other.hash; + self.key.clone_from(&other.key); + self.value.clone_from(&other.value); + } +} + +impl Bucket { + // field accessors -- used for `f` instead of closures in `.map(f)` + const fn key_ref(&self) -> &K { + &self.key + } + const fn value_ref(&self) -> &V { + &self.value + } + const fn value_mut(&mut self) -> &mut V { + &mut self.value + } + fn key(self) -> K { + self.key + } + fn value(self) -> V { + self.value + } + fn key_value(self) -> (K, V) { + (self.key, self.value) + } + const fn refs(&self) -> (&K, &V) { + (&self.key, &self.value) + } + const fn ref_mut(&mut self) -> (&K, &mut V) { + (&self.key, &mut self.value) + } + const fn muts(&mut self) -> (&mut K, &mut V) { + (&mut self.key, &mut self.value) + } +} + +/// The error type for [`try_reserve`][IndexMap::try_reserve] methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct TryReserveError { + kind: TryReserveErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum TryReserveErrorKind { + // The standard library's kind is currently opaque to us, otherwise we could unify this. + Std(alloc::collections::TryReserveError), + CapacityOverflow, + AllocError { layout: alloc::alloc::Layout }, +} + +// These are not `From` so we don't expose them in our public API. +impl TryReserveError { + fn from_alloc(error: alloc::collections::TryReserveError) -> Self { + Self { + kind: TryReserveErrorKind::Std(error), + } + } + + fn from_hashbrown(error: hashbrown::TryReserveError) -> Self { + Self { + kind: match error { + hashbrown::TryReserveError::CapacityOverflow => { + TryReserveErrorKind::CapacityOverflow + } + hashbrown::TryReserveError::AllocError { layout } => { + TryReserveErrorKind::AllocError { layout } + } + }, + } + } +} + +impl core::fmt::Display for TryReserveError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let reason = match &self.kind { + TryReserveErrorKind::Std(e) => return core::fmt::Display::fmt(e, f), + TryReserveErrorKind::CapacityOverflow => { + " because the computed capacity exceeded the collection's maximum" + } + TryReserveErrorKind::AllocError { .. } => { + " because the memory allocator returned an error" + } + }; + f.write_str("memory allocation failed")?; + f.write_str(reason) + } +} + +impl core::error::Error for TryReserveError {} + +// NOTE: This is copied from the slice module in the std lib. +/// The error type returned by [`get_disjoint_indices_mut`][`IndexMap::get_disjoint_indices_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array. +// (or different but overlapping indices when ranges are provided) +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetDisjointMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, +} + +impl core::fmt::Display for GetDisjointMutError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let msg = match self { + GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds", + GetDisjointMutError::OverlappingIndices => "there were overlapping indices", + }; + + core::fmt::Display::fmt(msg, f) + } +} + +impl core::error::Error for GetDisjointMutError {} diff --git a/deps/crates/vendor/indexmap/src/macros.rs b/deps/crates/vendor/indexmap/src/macros.rs new file mode 100644 index 00000000000000..49c90dbec77beb --- /dev/null +++ b/deps/crates/vendor/indexmap/src/macros.rs @@ -0,0 +1,252 @@ +/// Create an [`IndexMap`][crate::IndexMap] from a list of key-value pairs +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexmap_with_default; +/// use fnv::FnvHasher; +/// +/// let map = indexmap_with_default!{ +/// FnvHasher; +/// "a" => 1, +/// "b" => 2, +/// }; +/// assert_eq!(map["a"], 1); +/// assert_eq!(map["b"], 2); +/// assert_eq!(map.get("c"), None); +/// +/// // "a" is the first key +/// assert_eq!(map.keys().next(), Some(&"a")); +/// ``` +#[macro_export] +macro_rules! indexmap_with_default { + ($H:ty; $($key:expr => $value:expr,)+) => { $crate::indexmap_with_default!($H; $($key => $value),+) }; + ($H:ty; $($key:expr => $value:expr),*) => {{ + let builder = ::core::hash::BuildHasherDefault::<$H>::default(); + const CAP: usize = <[()]>::len(&[$({ stringify!($key); }),*]); + #[allow(unused_mut)] + // Specify your custom `H` (must implement Default + Hasher) as the hasher: + let mut map = $crate::IndexMap::with_capacity_and_hasher(CAP, builder); + $( + map.insert($key, $value); + )* + map + }}; +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[macro_export] +/// Create an [`IndexMap`][crate::IndexMap] from a list of key-value pairs +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexmap; +/// +/// let map = indexmap!{ +/// "a" => 1, +/// "b" => 2, +/// }; +/// assert_eq!(map["a"], 1); +/// assert_eq!(map["b"], 2); +/// assert_eq!(map.get("c"), None); +/// +/// // "a" is the first key +/// assert_eq!(map.keys().next(), Some(&"a")); +/// ``` +macro_rules! indexmap { + ($($key:expr => $value:expr,)+) => { $crate::indexmap!($($key => $value),+) }; + ($($key:expr => $value:expr),*) => { + { + // Note: `stringify!($key)` is just here to consume the repetition, + // but we throw away that string literal during constant evaluation. + const CAP: usize = <[()]>::len(&[$({ stringify!($key); }),*]); + let mut map = $crate::IndexMap::with_capacity(CAP); + $( + map.insert($key, $value); + )* + map + } + }; +} + +/// Create an [`IndexSet`][crate::IndexSet] from a list of values +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexset_with_default; +/// use fnv::FnvHasher; +/// +/// let set = indexset_with_default!{ +/// FnvHasher; +/// "a", +/// "b", +/// }; +/// assert!(set.contains("a")); +/// assert!(set.contains("b")); +/// assert!(!set.contains("c")); +/// +/// // "a" is the first value +/// assert_eq!(set.iter().next(), Some(&"a")); +/// ``` +#[macro_export] +macro_rules! indexset_with_default { + ($H:ty; $($value:expr,)+) => { $crate::indexset_with_default!($H; $($value),+) }; + ($H:ty; $($value:expr),*) => {{ + let builder = ::core::hash::BuildHasherDefault::<$H>::new(); + const CAP: usize = <[()]>::len(&[$({ stringify!($value); }),*]); + #[allow(unused_mut)] + // Specify your custom `H` (must implement Default + Hash) as the hasher: + let mut set = $crate::IndexSet::with_capacity_and_hasher(CAP, builder); + $( + set.insert($value); + )* + set + }}; +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[macro_export] +/// Create an [`IndexSet`][crate::IndexSet] from a list of values +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexset; +/// +/// let set = indexset!{ +/// "a", +/// "b", +/// }; +/// assert!(set.contains("a")); +/// assert!(set.contains("b")); +/// assert!(!set.contains("c")); +/// +/// // "a" is the first value +/// assert_eq!(set.iter().next(), Some(&"a")); +/// ``` +macro_rules! indexset { + ($($value:expr,)+) => { $crate::indexset!($($value),+) }; + ($($value:expr),*) => { + { + // Note: `stringify!($value)` is just here to consume the repetition, + // but we throw away that string literal during constant evaluation. + const CAP: usize = <[()]>::len(&[$({ stringify!($value); }),*]); + let mut set = $crate::IndexSet::with_capacity(CAP); + $( + set.insert($value); + )* + set + } + }; +} + +// generate all the Iterator methods by just forwarding to the underlying +// self.iter and mapping its element. +macro_rules! iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + // same mapping function for both options and iterators + ($map_elt:expr) => { + fn next(&mut self) -> Option { + self.iter.next().map($map_elt) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn count(self) -> usize { + self.iter.len() + } + + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n).map($map_elt) + } + + fn last(mut self) -> Option { + self.next_back() + } + + fn collect(self) -> C + where + C: FromIterator, + { + // NB: forwarding this directly to standard iterators will + // allow it to leverage unstable traits like `TrustedLen`. + self.iter.map($map_elt).collect() + } + }; +} + +macro_rules! double_ended_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + // same mapping function for both options and iterators + ($map_elt:expr) => { + fn next_back(&mut self) -> Option { + self.iter.next_back().map($map_elt) + } + + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n).map($map_elt) + } + }; +} + +// generate `ParallelIterator` methods by just forwarding to the underlying +// self.entries and mapping its elements. +#[cfg(feature = "rayon")] +macro_rules! parallel_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + ($map_elt:expr) => { + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.entries + .into_par_iter() + .map($map_elt) + .drive_unindexed(consumer) + } + + // NB: This allows indexed collection, e.g. directly into a `Vec`, but the + // underlying iterator must really be indexed. We should remove this if we + // start having tombstones that must be filtered out. + fn opt_len(&self) -> Option { + Some(self.entries.len()) + } + }; +} + +// generate `IndexedParallelIterator` methods by just forwarding to the underlying +// self.entries and mapping its elements. +#[cfg(feature = "rayon")] +macro_rules! indexed_parallel_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + ($map_elt:expr) => { + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + self.entries.into_par_iter().map($map_elt).drive(consumer) + } + + fn len(&self) -> usize { + self.entries.len() + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + self.entries + .into_par_iter() + .map($map_elt) + .with_producer(callback) + } + }; +} diff --git a/deps/crates/vendor/indexmap/src/map.rs b/deps/crates/vendor/indexmap/src/map.rs new file mode 100644 index 00000000000000..1c2bb4b4c0295c --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map.rs @@ -0,0 +1,1892 @@ +//! [`IndexMap`] is a hash table where the iteration order of the key-value +//! pairs is independent of the hash values of the keys. + +mod entry; +mod iter; +mod mutable; +mod slice; + +pub mod raw_entry_v1; + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +pub mod serde_seq; + +#[cfg(test)] +mod tests; + +pub use self::entry::{Entry, IndexedEntry}; +pub use crate::inner::{OccupiedEntry, VacantEntry}; + +pub use self::iter::{ + Drain, ExtractIf, IntoIter, IntoKeys, IntoValues, Iter, IterMut, IterMut2, Keys, Splice, + Values, ValuesMut, +}; +pub use self::mutable::MutableEntryKey; +pub use self::mutable::MutableKeys; +pub use self::raw_entry_v1::RawEntryApiV1; +pub use self::slice::Slice; + +#[cfg(feature = "rayon")] +pub use crate::rayon::map as rayon; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::mem; +use core::ops::{Index, IndexMut, RangeBounds}; + +#[cfg(feature = "std")] +use std::hash::RandomState; + +use crate::inner::Core; +use crate::util::{third, try_simplify_range}; +use crate::{Bucket, Equivalent, GetDisjointMutError, HashValue, TryReserveError}; + +/// A hash table where the iteration order of the key-value pairs is independent +/// of the hash values of the keys. +/// +/// The interface is closely compatible with the standard +/// [`HashMap`][std::collections::HashMap], +/// but also has additional features. +/// +/// # Order +/// +/// The key-value pairs have a consistent order that is determined by +/// the sequence of insertion and removal calls on the map. The order does +/// not depend on the keys or the hash function at all. +/// +/// All iterators traverse the map in *the order*. +/// +/// The insertion order is preserved, with **notable exceptions** like the +/// [`.remove()`][Self::remove] or [`.swap_remove()`][Self::swap_remove] methods. +/// Methods such as [`.sort_by()`][Self::sort_by] of +/// course result in a new order, depending on the sorting order. +/// +/// # Indices +/// +/// The key-value pairs are indexed in a compact range without holes in the +/// range `0..self.len()`. For example, the method `.get_full` looks up the +/// index for a key, and the method `.get_index` looks up the key-value pair by +/// index. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// // count the frequency of each letter in a sentence. +/// let mut letters = IndexMap::new(); +/// for ch in "a short treatise on fungi".chars() { +/// *letters.entry(ch).or_insert(0) += 1; +/// } +/// +/// assert_eq!(letters[&'s'], 2); +/// assert_eq!(letters[&'t'], 3); +/// assert_eq!(letters[&'u'], 1); +/// assert_eq!(letters.get(&'y'), None); +/// ``` +#[cfg(feature = "std")] +pub struct IndexMap { + pub(crate) core: Core, + hash_builder: S, +} +#[cfg(not(feature = "std"))] +pub struct IndexMap { + pub(crate) core: Core, + hash_builder: S, +} + +impl Clone for IndexMap +where + K: Clone, + V: Clone, + S: Clone, +{ + fn clone(&self) -> Self { + IndexMap { + core: self.core.clone(), + hash_builder: self.hash_builder.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.core.clone_from(&other.core); + self.hash_builder.clone_from(&other.hash_builder); + } +} + +impl fmt::Debug for IndexMap +where + K: fmt::Debug, + V: fmt::Debug, +{ + #[cfg(not(feature = "test_debug"))] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } + + #[cfg(feature = "test_debug")] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Let the inner `Core` print all of its details + f.debug_struct("IndexMap") + .field("core", &self.core) + .finish() + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl IndexMap { + /// Create a new map. (Does not allocate.) + #[inline] + pub fn new() -> Self { + Self::with_capacity(0) + } + + /// Create a new map with capacity for `n` key-value pairs. (Does not + /// allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + #[inline] + pub fn with_capacity(n: usize) -> Self { + Self::with_capacity_and_hasher(n, <_>::default()) + } +} + +impl IndexMap { + /// Create a new map with capacity for `n` key-value pairs. (Does not + /// allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + #[inline] + pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self { + if n == 0 { + Self::with_hasher(hash_builder) + } else { + IndexMap { + core: Core::with_capacity(n), + hash_builder, + } + } + } + + /// Create a new map with `hash_builder`. + /// + /// This function is `const`, so it + /// can be called in `static` contexts. + pub const fn with_hasher(hash_builder: S) -> Self { + IndexMap { + core: Core::new(), + hash_builder, + } + } + + #[inline] + pub(crate) fn into_entries(self) -> Vec> { + self.core.into_entries() + } + + #[inline] + pub(crate) fn as_entries(&self) -> &[Bucket] { + self.core.as_entries() + } + + #[inline] + pub(crate) fn as_entries_mut(&mut self) -> &mut [Bucket] { + self.core.as_entries_mut() + } + + pub(crate) fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Bucket]), + { + self.core.with_entries(f); + } + + /// Return the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the map might be able to hold more, + /// but is guaranteed to be able to hold at least this many. + /// + /// Computes in **O(1)** time. + pub fn capacity(&self) -> usize { + self.core.capacity() + } + + /// Return a reference to the map's `BuildHasher`. + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Return the number of key-value pairs in the map. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn len(&self) -> usize { + self.core.len() + } + + /// Returns true if the map contains no elements. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return an iterator over the key-value pairs of the map, in their order + pub fn iter(&self) -> Iter<'_, K, V> { + Iter::new(self.as_entries()) + } + + /// Return an iterator over the key-value pairs of the map, in their order + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut::new(self.as_entries_mut()) + } + + /// Return an iterator over the keys of the map, in their order + pub fn keys(&self) -> Keys<'_, K, V> { + Keys::new(self.as_entries()) + } + + /// Return an owning iterator over the keys of the map, in their order + pub fn into_keys(self) -> IntoKeys { + IntoKeys::new(self.into_entries()) + } + + /// Return an iterator over the values of the map, in their order + pub fn values(&self) -> Values<'_, K, V> { + Values::new(self.as_entries()) + } + + /// Return an iterator over mutable references to the values of the map, + /// in their order + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut::new(self.as_entries_mut()) + } + + /// Return an owning iterator over the values of the map, in their order + pub fn into_values(self) -> IntoValues { + IntoValues::new(self.into_entries()) + } + + /// Remove all key-value pairs in the map, while preserving its capacity. + /// + /// Computes in **O(n)** time. + pub fn clear(&mut self) { + self.core.clear(); + } + + /// Shortens the map, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the map's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.core.truncate(len); + } + + /// Clears the `IndexMap` in the given index range, returning those + /// key-value pairs as a drain iterator. + /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To drain the map entirely, use `RangeFull` + /// like `map.drain(..)`. + /// + /// This shifts down all entries following the drained range to fill the + /// gap, and keeps the allocated memory for reuse. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + #[track_caller] + pub fn drain(&mut self, range: R) -> Drain<'_, K, V> + where + R: RangeBounds, + { + Drain::new(self.core.drain(range)) + } + + /// Creates an iterator which uses a closure to determine if an element should be removed, + /// for all elements in the given range. + /// + /// If the closure returns true, the element is removed from the map and yielded. + /// If the closure returns false, or panics, the element remains in the map and will not be + /// yielded. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To check the entire map, use `RangeFull` + /// like `map.extract_if(.., predicate)`. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain`]: IndexMap::retain + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let mut map: IndexMap = (0..8).map(|x| (x, x)).collect(); + /// let extracted: IndexMap = map.extract_if(.., |k, _v| k % 2 == 0).collect(); + /// + /// let evens = extracted.keys().copied().collect::>(); + /// let odds = map.keys().copied().collect::>(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[track_caller] + pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, F> + where + F: FnMut(&K, &mut V) -> bool, + R: RangeBounds, + { + ExtractIf::new(&mut self.core, range, pred) + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated map containing the elements in the range + /// `[at, len)`. After the call, the original map will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + #[track_caller] + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + core: self.core.split_off(at), + hash_builder: self.hash_builder.clone(), + } + } + + /// Reserve capacity for `additional` more key-value pairs. + /// + /// Computes in **O(n)** time. + pub fn reserve(&mut self, additional: usize) { + self.core.reserve(additional); + } + + /// Reserve capacity for `additional` more key-value pairs, without over-allocating. + /// + /// Unlike `reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn reserve_exact(&mut self, additional: usize) { + self.core.reserve_exact(additional); + } + + /// Try to reserve capacity for `additional` more key-value pairs. + /// + /// Computes in **O(n)** time. + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.core.try_reserve(additional) + } + + /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating. + /// + /// Unlike `try_reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.core.try_reserve_exact(additional) + } + + /// Shrink the capacity of the map as much as possible. + /// + /// Computes in **O(n)** time. + pub fn shrink_to_fit(&mut self) { + self.core.shrink_to(0); + } + + /// Shrink the capacity of the map with a lower limit. + /// + /// Computes in **O(n)** time. + pub fn shrink_to(&mut self, min_capacity: usize) { + self.core.shrink_to(min_capacity); + } +} + +impl IndexMap +where + K: Hash + Eq, + S: BuildHasher, +{ + /// Insert a key-value pair in the map. + /// + /// If an equivalent key already exists in the map: the key remains and + /// retains in its place in the order, its corresponding value is updated + /// with `value`, and the older value is returned inside `Some(_)`. + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted, last in order, and `None` is returned. + /// + /// Computes in **O(1)** time (amortized average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// or [`insert_full`][Self::insert_full] if you need to get the index of + /// the corresponding key-value pair. + pub fn insert(&mut self, key: K, value: V) -> Option { + self.insert_full(key, value).1 + } + + /// Insert a key-value pair in the map, and get their index. + /// + /// If an equivalent key already exists in the map: the key remains and + /// retains in its place in the order, its corresponding value is updated + /// with `value`, and the older value is returned inside `(index, Some(_))`. + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted, last in order, and `(index, None)` is returned. + /// + /// Computes in **O(1)** time (amortized average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify. + pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option) { + let hash = self.hash(&key); + self.core.insert_full(hash, key, value) + } + + /// Insert a key-value pair in the map at its ordered position among sorted keys. + /// + /// This is equivalent to finding the position with + /// [`binary_search_keys`][Self::binary_search_keys], then either updating + /// it or calling [`insert_before`][Self::insert_before] for a new key. + /// + /// If the sorted key is found in the map, its corresponding value is + /// updated with `value`, and the older value is returned inside + /// `(index, Some(_))`. Otherwise, the new key-value pair is inserted at + /// the sorted position, and `(index, None)` is returned. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). Instead of repeating calls to + /// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert] + /// or [`extend`][Self::extend] and only call [`sort_keys`][Self::sort_keys] + /// or [`sort_unstable_keys`][Self::sort_unstable_keys] once. + pub fn insert_sorted(&mut self, key: K, value: V) -> (usize, Option) + where + K: Ord, + { + match self.binary_search_keys(&key) { + Ok(i) => (i, Some(mem::replace(&mut self[i], value))), + Err(i) => self.insert_before(i, key, value), + } + } + + /// Insert a key-value pair in the map at its ordered position among keys + /// sorted by `cmp`. + /// + /// This is equivalent to finding the position with + /// [`binary_search_by`][Self::binary_search_by], then calling + /// [`insert_before`][Self::insert_before] with the given key and value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by(&mut self, key: K, value: V, mut cmp: F) -> (usize, Option) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let (Ok(i) | Err(i)) = self.binary_search_by(|k, v| cmp(k, v, &key, &value)); + self.insert_before(i, key, value) + } + + /// Insert a key-value pair in the map at its ordered position + /// using a sort-key extraction function. + /// + /// This is equivalent to finding the position with + /// [`binary_search_by_key`][Self::binary_search_by_key] with `sort_key(key)`, then + /// calling [`insert_before`][Self::insert_before] with the given key and value. + /// + /// If the existing keys are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the key-value + /// pair is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by_key( + &mut self, + key: K, + value: V, + mut sort_key: F, + ) -> (usize, Option) + where + B: Ord, + F: FnMut(&K, &V) -> B, + { + let search_key = sort_key(&key, &value); + let (Ok(i) | Err(i)) = self.binary_search_by_key(&search_key, sort_key); + self.insert_before(i, key, value) + } + + /// Insert a key-value pair in the map before the entry at the given index, or at the end. + /// + /// If an equivalent key already exists in the map: the key remains and + /// is moved to the new position in the map, its corresponding value is updated + /// with `value`, and the older value is returned inside `Some(_)`. The returned index + /// will either be the given index or one less, depending on how the entry moved. + /// (See [`shift_insert`](Self::shift_insert) for different behavior here.) + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted exactly at the given index, and `None` is returned. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..=map.len()` (inclusive). + /// + /// Computes in **O(n)** time (average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// perhaps only using the index for new entries with [`VacantEntry::shift_insert`]. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// let mut map: IndexMap = ('a'..='z').map(|c| (c, ())).collect(); + /// + /// // The new key '*' goes exactly at the given index. + /// assert_eq!(map.get_index_of(&'*'), None); + /// assert_eq!(map.insert_before(10, '*', ()), (10, None)); + /// assert_eq!(map.get_index_of(&'*'), Some(10)); + /// + /// // Moving the key 'a' up will shift others down, so this moves *before* 10 to index 9. + /// assert_eq!(map.insert_before(10, 'a', ()), (9, Some(()))); + /// assert_eq!(map.get_index_of(&'a'), Some(9)); + /// assert_eq!(map.get_index_of(&'*'), Some(10)); + /// + /// // Moving the key 'z' down will shift others up, so this moves to exactly 10. + /// assert_eq!(map.insert_before(10, 'z', ()), (10, Some(()))); + /// assert_eq!(map.get_index_of(&'z'), Some(10)); + /// assert_eq!(map.get_index_of(&'*'), Some(11)); + /// + /// // Moving or inserting before the endpoint is also valid. + /// assert_eq!(map.len(), 27); + /// assert_eq!(map.insert_before(map.len(), '*', ()), (26, Some(()))); + /// assert_eq!(map.get_index_of(&'*'), Some(26)); + /// assert_eq!(map.insert_before(map.len(), '+', ()), (27, None)); + /// assert_eq!(map.get_index_of(&'+'), Some(27)); + /// assert_eq!(map.len(), 28); + /// ``` + #[track_caller] + pub fn insert_before(&mut self, mut index: usize, key: K, value: V) -> (usize, Option) { + let len = self.len(); + + assert!( + index <= len, + "index out of bounds: the len is {len} but the index is {index}. Expected index <= len" + ); + + match self.entry(key) { + Entry::Occupied(mut entry) => { + if index > entry.index() { + // Some entries will shift down when this one moves up, + // so "insert before index" becomes "move to index - 1", + // keeping the entry at the original index unmoved. + index -= 1; + } + let old = mem::replace(entry.get_mut(), value); + entry.move_index(index); + (index, Some(old)) + } + Entry::Vacant(entry) => { + entry.shift_insert(index, value); + (index, None) + } + } + } + + /// Insert a key-value pair in the map at the given index. + /// + /// If an equivalent key already exists in the map: the key remains and + /// is moved to the given index in the map, its corresponding value is updated + /// with `value`, and the older value is returned inside `Some(_)`. + /// Note that existing entries **cannot** be moved to `index == map.len()`! + /// (See [`insert_before`](Self::insert_before) for different behavior here.) + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted at the given index, and `None` is returned. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..map.len()` (exclusive) when moving an existing entry, or + /// `0..=map.len()` (inclusive) when inserting a new key. + /// + /// Computes in **O(n)** time (average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// perhaps only using the index for new entries with [`VacantEntry::shift_insert`]. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// let mut map: IndexMap = ('a'..='z').map(|c| (c, ())).collect(); + /// + /// // The new key '*' goes exactly at the given index. + /// assert_eq!(map.get_index_of(&'*'), None); + /// assert_eq!(map.shift_insert(10, '*', ()), None); + /// assert_eq!(map.get_index_of(&'*'), Some(10)); + /// + /// // Moving the key 'a' up to 10 will shift others down, including the '*' that was at 10. + /// assert_eq!(map.shift_insert(10, 'a', ()), Some(())); + /// assert_eq!(map.get_index_of(&'a'), Some(10)); + /// assert_eq!(map.get_index_of(&'*'), Some(9)); + /// + /// // Moving the key 'z' down to 9 will shift others up, including the '*' that was at 9. + /// assert_eq!(map.shift_insert(9, 'z', ()), Some(())); + /// assert_eq!(map.get_index_of(&'z'), Some(9)); + /// assert_eq!(map.get_index_of(&'*'), Some(10)); + /// + /// // Existing keys can move to len-1 at most, but new keys can insert at the endpoint. + /// assert_eq!(map.len(), 27); + /// assert_eq!(map.shift_insert(map.len() - 1, '*', ()), Some(())); + /// assert_eq!(map.get_index_of(&'*'), Some(26)); + /// assert_eq!(map.shift_insert(map.len(), '+', ()), None); + /// assert_eq!(map.get_index_of(&'+'), Some(27)); + /// assert_eq!(map.len(), 28); + /// ``` + /// + /// ```should_panic + /// use indexmap::IndexMap; + /// let mut map: IndexMap = ('a'..='z').map(|c| (c, ())).collect(); + /// + /// // This is an invalid index for moving an existing key! + /// map.shift_insert(map.len(), 'a', ()); + /// ``` + #[track_caller] + pub fn shift_insert(&mut self, index: usize, key: K, value: V) -> Option { + let len = self.len(); + match self.entry(key) { + Entry::Occupied(mut entry) => { + assert!( + index < len, + "index out of bounds: the len is {len} but the index is {index}" + ); + + let old = mem::replace(entry.get_mut(), value); + entry.move_index(index); + Some(old) + } + Entry::Vacant(entry) => { + assert!( + index <= len, + "index out of bounds: the len is {len} but the index is {index}. Expected index <= len" + ); + + entry.shift_insert(index, value); + None + } + } + } + + /// Replaces the key at the given index. The new key does not need to be + /// equivalent to the one it is replacing, but it must be unique to the rest + /// of the map. + /// + /// Returns `Ok(old_key)` if successful, or `Err((other_index, key))` if an + /// equivalent key already exists at a different index. The map will be + /// unchanged in the error case. + /// + /// Direct indexing can be used to change the corresponding value: simply + /// `map[index] = value`, or `mem::replace(&mut map[index], value)` to + /// retrieve the old value as well. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn replace_index(&mut self, index: usize, key: K) -> Result { + // If there's a direct match, we don't even need to hash it. + let entry = &mut self.as_entries_mut()[index]; + if key == entry.key { + return Ok(mem::replace(&mut entry.key, key)); + } + + let hash = self.hash(&key); + if let Some(i) = self.core.get_index_of(hash, &key) { + debug_assert_ne!(i, index); + return Err((i, key)); + } + Ok(self.core.replace_index_unique(index, hash, key)) + } + + /// Get the given key's corresponding entry in the map for insertion and/or + /// in-place manipulation. + /// + /// Computes in **O(1)** time (amortized average). + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + let hash = self.hash(&key); + Entry::new(&mut self.core, hash, key) + } + + /// Creates a splicing iterator that replaces the specified range in the map + /// with the given `replace_with` key-value iterator and yields the removed + /// items. `replace_with` does not need to be the same length as `range`. + /// + /// The `range` is removed even if the iterator is not consumed until the + /// end. It is unspecified how many elements are removed from the map if the + /// `Splice` value is leaked. + /// + /// The input iterator `replace_with` is only consumed when the `Splice` + /// value is dropped. If a key from the iterator matches an existing entry + /// in the map (outside of `range`), then the value will be updated in that + /// position. Otherwise, the new key-value pair will be inserted in the + /// replaced `range`. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let mut map = IndexMap::from([(0, '_'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]); + /// let new = [(5, 'E'), (4, 'D'), (3, 'C'), (2, 'B'), (1, 'A')]; + /// let removed: Vec<_> = map.splice(2..4, new).collect(); + /// + /// // 1 and 4 got new values, while 5, 3, and 2 were newly inserted. + /// assert!(map.into_iter().eq([(0, '_'), (1, 'A'), (5, 'E'), (3, 'C'), (2, 'B'), (4, 'D')])); + /// assert_eq!(removed, &[(2, 'b'), (3, 'c')]); + /// ``` + #[track_caller] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, K, V, S> + where + R: RangeBounds, + I: IntoIterator, + { + Splice::new(self, range, replace_with.into_iter()) + } + + /// Moves all key-value pairs from `other` into `self`, leaving `other` empty. + /// + /// This is equivalent to calling [`insert`][Self::insert] for each + /// key-value pair from `other` in order, which means that for keys that + /// already exist in `self`, their value is updated in the current position. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// // Note: Key (3) is present in both maps. + /// let mut a = IndexMap::from([(3, "c"), (2, "b"), (1, "a")]); + /// let mut b = IndexMap::from([(3, "d"), (4, "e"), (5, "f")]); + /// let old_capacity = b.capacity(); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 5); + /// assert_eq!(b.len(), 0); + /// assert_eq!(b.capacity(), old_capacity); + /// + /// assert!(a.keys().eq(&[3, 2, 1, 4, 5])); + /// assert_eq!(a[&3], "d"); // "c" was overwritten. + /// ``` + pub fn append(&mut self, other: &mut IndexMap) { + self.extend(other.drain(..)); + } +} + +impl IndexMap +where + S: BuildHasher, +{ + pub(crate) fn hash(&self, key: &Q) -> HashValue { + let h = self.hash_builder.hash_one(key); + HashValue(h as usize) + } + + /// Return `true` if an equivalent to `key` exists in the map. + /// + /// Computes in **O(1)** time (average). + pub fn contains_key(&self, key: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.get_index_of(key).is_some() + } + + /// Return a reference to the stored value for `key`, if it is present, + /// else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get(&self, key: &Q) -> Option<&V> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some(&entry.value) + } else { + None + } + } + + /// Return references to the stored key-value pair for the lookup `key`, + /// if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some((&entry.key, &entry.value)) + } else { + None + } + } + + /// Return the index with references to the stored key-value pair for the + /// lookup `key`, if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some((i, &entry.key, &entry.value)) + } else { + None + } + } + + /// Return the item index for `key`, if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_index_of(&self, key: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + match self.as_entries() { + [] => None, + [x] => key.equivalent(&x.key).then_some(0), + _ => { + let hash = self.hash(key); + self.core.get_index_of(hash, key) + } + } + } + + /// Return a mutable reference to the stored value for `key`, + /// if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some(&mut entry.value) + } else { + None + } + } + + /// Return a reference and mutable references to the stored key-value pair + /// for the lookup `key`, if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_key_value_mut(&mut self, key: &Q) -> Option<(&K, &mut V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((&entry.key, &mut entry.value)) + } else { + None + } + } + + /// Return the index with a reference and mutable reference to the stored + /// key-value pair for the lookup `key`, if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_full_mut(&mut self, key: &Q) -> Option<(usize, &K, &mut V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &entry.key, &mut entry.value)) + } else { + None + } + } + + /// Return the values for `N` keys. + /// + /// ***Panics*** if any key is duplicated. + /// + /// # Examples + /// + /// ``` + /// let mut map = indexmap::IndexMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_mut([&2, &1]), [Some(&mut 'c'), Some(&mut 'a')]); + /// ``` + #[track_caller] + pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> [Option<&mut V>; N] + where + Q: ?Sized + Hash + Equivalent, + { + let indices = keys.map(|key| self.get_index_of(key)); + match self.as_mut_slice().get_disjoint_opt_mut(indices) { + Err(GetDisjointMutError::IndexOutOfBounds) => { + unreachable!( + "Internal error: indices should never be OOB as we got them from get_index_of" + ); + } + Err(GetDisjointMutError::OverlappingIndices) => { + panic!("duplicate keys found"); + } + Ok(key_values) => key_values.map(|kv_opt| kv_opt.map(|kv| kv.1)), + } + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// **NOTE:** This is equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove(key)`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(&mut self, key: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.swap_remove(key) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// **NOTE:** This is equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: ?Sized + Hash + Equivalent, + { + self.swap_remove_entry(key) + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(&mut self, key: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.swap_remove_full(key).map(third) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.swap_remove_full(key) { + Some((_, key, value)) => Some((key, value)), + None => None, + } + } + + /// Remove the key-value pair equivalent to `key` and return it and + /// the index it had. + /// + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.as_entries() { + [x] if key.equivalent(&x.key) => { + let (k, v) = self.core.pop()?; + Some((0, k, v)) + } + [_] | [] => None, + _ => { + let hash = self.hash(key); + self.core.swap_remove_full(hash, key) + } + } + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// Like [`Vec::remove`], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(&mut self, key: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.shift_remove_full(key).map(third) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// Like [`Vec::remove`], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.shift_remove_full(key) { + Some((_, key, value)) => Some((key, value)), + None => None, + } + } + + /// Remove the key-value pair equivalent to `key` and return it and + /// the index it had. + /// + /// Like [`Vec::remove`], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.as_entries() { + [x] if key.equivalent(&x.key) => { + let (k, v) = self.core.pop()?; + Some((0, k, v)) + } + [_] | [] => None, + _ => { + let hash = self.hash(key); + self.core.shift_remove_full(hash, key) + } + } + } +} + +impl IndexMap { + /// Remove the last key-value pair + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + #[doc(alias = "pop_last")] // like `BTreeMap` + pub fn pop(&mut self) -> Option<(K, V)> { + self.core.pop() + } + + /// Removes and returns the last key-value pair from a map if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the map + /// is empty (the predicate will not be called in that case). + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let init = [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]; + /// let mut map = IndexMap::from(init); + /// let pred = |key: &i32, _value: &mut char| *key % 2 == 0; + /// + /// assert_eq!(map.pop_if(pred), Some((4, 'd'))); + /// assert_eq!(map.as_slice(), &init[..3]); + /// assert_eq!(map.pop_if(pred), None); + /// ``` + pub fn pop_if(&mut self, predicate: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)> { + let (last_key, last_value) = self.last_mut()?; + if predicate(last_key, last_value) { + self.core.pop() + } else { + None + } + } + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.core.retain_in_order(move |k, v| keep(k, v)); + } + + /// Sort the map's key-value pairs by the default ordering of the keys. + /// + /// This is a stable sort -- but equivalent keys should not normally coexist in + /// a map at all, so [`sort_unstable_keys`][Self::sort_unstable_keys] is preferred + /// because it is generally faster and doesn't allocate auxiliary memory. + /// + /// See [`sort_by`](Self::sort_by) for details. + pub fn sort_keys(&mut self) + where + K: Ord, + { + self.with_entries(move |entries| { + entries.sort_by(move |a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + /// + /// Computes in **O(n log n + c)** time and **O(n)** space where *n* is + /// the length of the map and *c* the capacity. The sort is stable. + pub fn sort_by(&mut self, mut cmp: F) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + self.with_entries(move |entries| { + entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map and return a by-value iterator of + /// the key-value pairs with the result. + /// + /// The sort is stable. + pub fn sorted_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoIter::new(entries) + } + + /// Sort the map's key-value pairs in place using a sort-key extraction function. + /// + /// Computes in **O(n log n + c)** time and **O(n)** space where *n* is + /// the length of the map and *c* the capacity. The sort is stable. + pub fn sort_by_key(&mut self, mut sort_key: F) + where + T: Ord, + F: FnMut(&K, &V) -> T, + { + self.with_entries(move |entries| { + entries.sort_by_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Sort the map's key-value pairs by the default ordering of the keys, but + /// may not preserve the order of equal elements. + /// + /// See [`sort_unstable_by`](Self::sort_unstable_by) for details. + pub fn sort_unstable_keys(&mut self) + where + K: Ord, + { + self.with_entries(move |entries| { + entries.sort_unstable_by(move |a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place using the comparison function `cmp`, but + /// may not preserve the order of equal elements. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + /// + /// Computes in **O(n log n + c)** time where *n* is + /// the length of the map and *c* is the capacity. The sort is unstable. + pub fn sort_unstable_by(&mut self, mut cmp: F) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + self.with_entries(move |entries| { + entries.sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map and return a by-value iterator of + /// the key-value pairs with the result. + /// + /// The sort is unstable. + #[inline] + pub fn sorted_unstable_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoIter::new(entries) + } + + /// Sort the map's key-value pairs in place using a sort-key extraction function. + /// + /// Computes in **O(n log n + c)** time where *n* is + /// the length of the map and *c* is the capacity. The sort is unstable. + pub fn sort_unstable_by_key(&mut self, mut sort_key: F) + where + T: Ord, + F: FnMut(&K, &V) -> T, + { + self.with_entries(move |entries| { + entries.sort_unstable_by_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Sort the map's key-value pairs in place using a sort-key extraction function. + /// + /// During sorting, the function is called at most once per entry, by using temporary storage + /// to remember the results of its evaluation. The order of calls to the function is + /// unspecified and may change between versions of `indexmap` or the standard library. + /// + /// Computes in **O(m n + n log n + c)** time () and **O(n)** space, where the function is + /// **O(m)**, *n* is the length of the map, and *c* the capacity. The sort is stable. + pub fn sort_by_cached_key(&mut self, mut sort_key: F) + where + T: Ord, + F: FnMut(&K, &V) -> T, + { + self.with_entries(move |entries| { + entries.sort_by_cached_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Search over a sorted map for a key. + /// + /// Returns the position where that key is present, or the position where it can be inserted to + /// maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the key up + /// using [`get_index_of`][IndexMap::get_index_of], but this can also position missing keys. + pub fn binary_search_keys(&self, x: &K) -> Result + where + K: Ord, + { + self.as_slice().binary_search_keys(x) + } + + /// Search over a sorted map with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> Ordering, + { + self.as_slice().binary_search_by(f) + } + + /// Search over a sorted map with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> B, + B: Ord, + { + self.as_slice().binary_search_by_key(b, f) + } + + /// Checks if the keys of this map are sorted. + #[inline] + pub fn is_sorted(&self) -> bool + where + K: PartialOrd, + { + self.as_slice().is_sorted() + } + + /// Checks if this map is sorted using the given comparator function. + #[inline] + pub fn is_sorted_by<'a, F>(&'a self, cmp: F) -> bool + where + F: FnMut(&'a K, &'a V, &'a K, &'a V) -> bool, + { + self.as_slice().is_sorted_by(cmp) + } + + /// Checks if this map is sorted using the given sort-key function. + #[inline] + pub fn is_sorted_by_key<'a, F, T>(&'a self, sort_key: F) -> bool + where + F: FnMut(&'a K, &'a V) -> T, + T: PartialOrd, + { + self.as_slice().is_sorted_by_key(sort_key) + } + + /// Returns the index of the partition point of a sorted map according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&K, &V) -> bool, + { + self.entries + .partition_point(move |a| pred(&a.key, &a.value)) + } + + /// Get an array of `N` key-value pairs by `N` indices + /// + /// Valid indices are *0 <= index < self.len()* and each index needs to be unique. + pub fn get_disjoint_mut( + &mut self, + indices: [usize; N], + ) -> Result<[(&K, &mut V); N], GetDisjointMutError> { + let indices = indices.map(Some); + let key_values = self.get_disjoint_opt_mut(indices)?; + Ok(key_values.map(Option::unwrap)) + } + + #[allow(unsafe_code)] + pub(crate) fn get_disjoint_opt_mut( + &mut self, + indices: [Option; N], + ) -> Result<[Option<(&K, &mut V)>; N], GetDisjointMutError> { + // SAFETY: Can't allow duplicate indices as we would return several mutable refs to the same data. + let len = self.len(); + for i in 0..N { + if let Some(idx) = indices[i] { + if idx >= len { + return Err(GetDisjointMutError::IndexOutOfBounds); + } else if indices[..i].contains(&Some(idx)) { + return Err(GetDisjointMutError::OverlappingIndices); + } + } + } + + let entries_ptr = self.entries.as_mut_ptr(); + let out = indices.map(|idx_opt| { + match idx_opt { + Some(idx) => { + // SAFETY: The base pointer is valid as it comes from a slice and the reference is always + // in-bounds & unique as we've already checked the indices above. + let kv = unsafe { (*(entries_ptr.add(idx))).ref_mut() }; + Some(kv) + } + None => None, + } + }); + + Ok(out) + } +} + +impl<'a, K, V> IntoIterator for &'a Slice { + type IntoIter = Iter<'a, K, V>; + type Item = (&'a K, &'a V); + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, K, V> IntoIterator for &'a mut Slice { + type IntoIter = IterMut<'a, K, V>; + type Item = (&'a K, &'a mut V); + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl IntoIterator for Box> { + type IntoIter = IntoIter; + type Item = (K, V); + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +impl Default for &'_ Slice { + fn default() -> Self { + Slice::from_slice(&[]) + } +} + +impl Default for &'_ mut Slice { + fn default() -> Self { + Slice::from_mut_slice(&mut []) + } +} + +impl Default for Box> { + fn default() -> Self { + Slice::from_boxed(Box::default()) + } +} + +impl Clone for Box> { + fn clone(&self) -> Self { + Slice::from_boxed(self.entries.to_vec().into_boxed_slice()) + } +} + +impl From<&Slice> for Box> { + fn from(slice: &Slice) -> Self { + Slice::from_boxed(Box::from(&slice.entries)) + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +impl PartialEq> for Slice +where + K: PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + slice_eq(&self.entries, &other.entries, |b1, b2| { + b1.key == b2.key && b1.value == b2.value + }) + } +} + +impl PartialEq<[(K2, V2)]> for Slice +where + K: PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &[(K2, V2)]) -> bool { + slice_eq(&self.entries, other, |b, t| b.key == t.0 && b.value == t.1) + } +} + +impl PartialEq> for [(K, V)] +where + K: PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + slice_eq(self, &other.entries, |t, b| t.0 == b.key && t.1 == b.value) + } +} + +impl PartialEq<[(K2, V2); N]> for Slice +where + K: PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &[(K2, V2); N]) -> bool { + >::eq(self, other) + } +} + +impl PartialEq> for [(K, V); N] +where + K: PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + <[_] as PartialEq<_>>::eq(self, other) + } +} + +impl Eq for Slice {} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.len().hash(state); + for (key, value) in self { + key.hash(state); + value.hash(state); + } + } +} + +impl Index for Slice { + type Output = V; + + fn index(&self, index: usize) -> &V { + &self.entries[index].value + } +} + +impl IndexMut for Slice { + fn index_mut(&mut self, index: usize) -> &mut V { + &mut self.entries[index].value + } +} + +// We can't have `impl> Index` because that conflicts +// both upstream with `Index` and downstream with `Index<&Q>`. +// Instead, we repeat the implementations for all the core range types. +macro_rules! impl_index { + ($($range:ty),*) => {$( + impl Index<$range> for IndexMap { + type Output = Slice; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.as_entries()[range]) + } + } + + impl IndexMut<$range> for IndexMap { + fn index_mut(&mut self, range: $range) -> &mut Self::Output { + Slice::from_mut_slice(&mut self.as_entries_mut()[range]) + } + } + + impl Index<$range> for Slice { + type Output = Slice; + + fn index(&self, range: $range) -> &Self { + Self::from_slice(&self.entries[range]) + } + } + + impl IndexMut<$range> for Slice { + fn index_mut(&mut self, range: $range) -> &mut Self { + Self::from_mut_slice(&mut self.entries[range]) + } + } + )*} +} +impl_index!( + ops::Range, + ops::RangeFrom, + ops::RangeFull, + ops::RangeInclusive, + ops::RangeTo, + ops::RangeToInclusive, + (Bound, Bound) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn slice_index() { + fn check( + vec_slice: &[(i32, i32)], + map_slice: &Slice, + sub_slice: &Slice, + ) { + assert_eq!(map_slice as *const _, sub_slice as *const _); + itertools::assert_equal( + vec_slice.iter().copied(), + map_slice.iter().map(|(&k, &v)| (k, v)), + ); + itertools::assert_equal(vec_slice.iter().map(|(k, _)| k), map_slice.keys()); + itertools::assert_equal(vec_slice.iter().map(|(_, v)| v), map_slice.values()); + } + + let vec: Vec<(i32, i32)> = (0..10).map(|i| (i, i * i)).collect(); + let map: IndexMap = vec.iter().cloned().collect(); + let slice = map.as_slice(); + + // RangeFull + check(&vec[..], &map[..], &slice[..]); + + for i in 0usize..10 { + // Index + assert_eq!(vec[i].1, map[i]); + assert_eq!(vec[i].1, slice[i]); + assert_eq!(map[&(i as i32)], map[i]); + assert_eq!(map[&(i as i32)], slice[i]); + + // RangeFrom + check(&vec[i..], &map[i..], &slice[i..]); + + // RangeTo + check(&vec[..i], &map[..i], &slice[..i]); + + // RangeToInclusive + check(&vec[..=i], &map[..=i], &slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check(&vec[i + 1..], &map[bounds], &slice[bounds]); + + for j in i..=10 { + // Range + check(&vec[i..j], &map[i..j], &slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check(&vec[i..=j], &map[i..=j], &slice[i..=j]); + } + } + } + + #[test] + fn slice_index_mut() { + fn check_mut( + vec_slice: &[(i32, i32)], + map_slice: &mut Slice, + sub_slice: &mut Slice, + ) { + assert_eq!(map_slice, sub_slice); + itertools::assert_equal( + vec_slice.iter().copied(), + map_slice.iter_mut().map(|(&k, &mut v)| (k, v)), + ); + itertools::assert_equal( + vec_slice.iter().map(|&(_, v)| v), + map_slice.values_mut().map(|&mut v| v), + ); + } + + let vec: Vec<(i32, i32)> = (0..10).map(|i| (i, i * i)).collect(); + let mut map: IndexMap = vec.iter().cloned().collect(); + let mut map2 = map.clone(); + let slice = map2.as_mut_slice(); + + // RangeFull + check_mut(&vec[..], &mut map[..], &mut slice[..]); + + for i in 0usize..10 { + // IndexMut + assert_eq!(&mut map[i], &mut slice[i]); + + // RangeFrom + check_mut(&vec[i..], &mut map[i..], &mut slice[i..]); + + // RangeTo + check_mut(&vec[..i], &mut map[..i], &mut slice[..i]); + + // RangeToInclusive + check_mut(&vec[..=i], &mut map[..=i], &mut slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check_mut(&vec[i + 1..], &mut map[bounds], &mut slice[bounds]); + + for j in i..=10 { + // Range + check_mut(&vec[i..j], &mut map[i..j], &mut slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check_mut(&vec[i..=j], &mut map[i..=j], &mut slice[i..=j]); + } + } + } + + #[test] + fn slice_new() { + let slice: &Slice = Slice::new(); + assert!(slice.is_empty()); + assert_eq!(slice.len(), 0); + } + + #[test] + fn slice_new_mut() { + let slice: &mut Slice = Slice::new_mut(); + assert!(slice.is_empty()); + assert_eq!(slice.len(), 0); + } + + #[test] + fn slice_get_index_mut() { + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + + { + let (key, value) = slice.get_index_mut(0).unwrap(); + assert_eq!(*key, 0); + assert_eq!(*value, 0); + + *value = 11; + } + + assert_eq!(slice[0], 11); + + { + let result = slice.get_index_mut(11); + assert!(result.is_none()); + } + } + + #[test] + fn slice_split_first() { + let slice: &mut Slice = Slice::new_mut(); + let result = slice.split_first(); + assert!(result.is_none()); + + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + + { + let (first, rest) = slice.split_first().unwrap(); + assert_eq!(first, (&0, &0)); + assert_eq!(rest.len(), 9); + } + assert_eq!(slice.len(), 10); + } + + #[test] + fn slice_split_first_mut() { + let slice: &mut Slice = Slice::new_mut(); + let result = slice.split_first_mut(); + assert!(result.is_none()); + + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + + { + let (first, rest) = slice.split_first_mut().unwrap(); + assert_eq!(first, (&0, &mut 0)); + assert_eq!(rest.len(), 9); + + *first.1 = 11; + } + assert_eq!(slice.len(), 10); + assert_eq!(slice[0], 11); + } + + #[test] + fn slice_split_last() { + let slice: &mut Slice = Slice::new_mut(); + let result = slice.split_last(); + assert!(result.is_none()); + + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + + { + let (last, rest) = slice.split_last().unwrap(); + assert_eq!(last, (&9, &81)); + assert_eq!(rest.len(), 9); + } + assert_eq!(slice.len(), 10); + } + + #[test] + fn slice_split_last_mut() { + let slice: &mut Slice = Slice::new_mut(); + let result = slice.split_last_mut(); + assert!(result.is_none()); + + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + + { + let (last, rest) = slice.split_last_mut().unwrap(); + assert_eq!(last, (&9, &mut 81)); + assert_eq!(rest.len(), 9); + + *last.1 = 100; + } + + assert_eq!(slice.len(), 10); + assert_eq!(slice[slice.len() - 1], 100); + } + + #[test] + fn slice_get_range() { + let mut map: IndexMap = (0..10).map(|i| (i, i * i)).collect(); + let slice: &mut Slice = map.as_mut_slice(); + let subslice = slice.get_range(3..6).unwrap(); + assert_eq!(subslice.len(), 3); + assert_eq!(subslice, &[(3, 9), (4, 16), (5, 25)]); + } +} diff --git a/deps/crates/vendor/indexmap/src/map/tests.rs b/deps/crates/vendor/indexmap/src/map/tests.rs new file mode 100644 index 00000000000000..79041905bd1c7b --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/tests.rs @@ -0,0 +1,1312 @@ +use super::*; +use std::string::String; + +#[test] +fn it_works() { + let mut map = IndexMap::new(); + assert_eq!(map.is_empty(), true); + map.insert(1, ()); + map.insert(1, ()); + assert_eq!(map.len(), 1); + assert!(map.get(&1).is_some()); + assert_eq!(map.is_empty(), false); +} + +#[test] +fn new() { + let map = IndexMap::::new(); + println!("{:?}", map); + assert_eq!(map.capacity(), 0); + assert_eq!(map.len(), 0); + assert_eq!(map.is_empty(), true); +} + +#[test] +fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + println!("{:?}", map); + + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } +} + +#[test] +fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, None); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), i + 1); + } + + let len = map.len(); + for &elt in &present { + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, Some(elt)); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), len); + } +} + +#[test] +fn insert_2() { + let mut map = IndexMap::with_capacity(16); + + let mut keys = vec![]; + keys.extend(0..16); + keys.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &keys { + let old_map = map.clone(); + map.insert(i, ()); + for key in old_map.keys() { + if map.get(key).is_none() { + println!("old_map: {:?}", old_map); + println!("map: {:?}", map); + panic!("did not find {} in map", key); + } + } + } + + for &i in &keys { + assert!(map.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, ()); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + for (i, k) in (0..insert.len()).zip(map.keys()) { + assert_eq!(map.get_index(i).unwrap().0, k); + } +} + +#[test] +fn shift_insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.shift_insert(0, elt, ()); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().rev().zip(map.keys()) { + assert_eq!(a, b); + } + for (i, k) in (0..insert.len()).zip(map.keys()) { + assert_eq!(map.get_index(i).unwrap().0, k); + } + + // "insert" that moves an existing entry + map.shift_insert(0, insert[0], ()); + assert_eq!(map.keys().count(), insert.len()); + assert_eq!(insert[0], map.keys()[0]); + for (a, b) in insert[1..].iter().rev().zip(map.keys().skip(1)) { + assert_eq!(a, b); + } +} + +#[test] +fn insert_sorted_bad() { + let mut map = IndexMap::new(); + map.insert(10, ()); + for i in 0..10 { + map.insert(i, ()); + } + + // The binary search will want to insert this at the end (index == len()), + // but that's only possible for *new* inserts. It should still be handled + // without panicking though, and in this case it's simple enough that we + // know the exact result. (But don't read this as an API guarantee!) + assert_eq!(map.first(), Some((&10, &()))); + map.insert_sorted(10, ()); + assert_eq!(map.last(), Some((&10, &()))); + assert!(map.keys().copied().eq(0..=10)); + + // Other out-of-order entries can also "insert" to a binary-searched + // position, moving in either direction. + map.move_index(5, 0); + map.move_index(6, 10); + assert_eq!(map.first(), Some((&5, &()))); + assert_eq!(map.last(), Some((&6, &()))); + map.insert_sorted(5, ()); // moves back up + map.insert_sorted(6, ()); // moves back down + assert!(map.keys().copied().eq(0..=10)); +} + +#[test] +fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + + println!("{:?}", map); + for &elt in &insert { + map.insert(elt * 10, elt); + } + for &elt in &insert { + map.insert(elt * 100, elt); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + map.insert(elt * 100 + i as i32, elt); + } + println!("{:?}", map); + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } +} + +#[test] +fn reserve() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + map.reserve(100); + let capacity = map.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), capacity); + assert_eq!(map.get(&i), Some(&(i * i))); + } + map.insert(capacity, std::usize::MAX); + assert_eq!(map.len(), capacity + 1); + assert!(map.capacity() > capacity); + assert_eq!(map.get(&capacity), Some(&std::usize::MAX)); +} + +#[test] +fn try_reserve() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + assert_eq!(map.try_reserve(100), Ok(())); + assert!(map.capacity() >= 100); + assert!(map.try_reserve(usize::MAX).is_err()); +} + +#[test] +fn shrink_to_fit() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + for i in 0..100 { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert!(map.capacity() >= i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + map.shrink_to_fit(); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + } +} + +#[test] +fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &key in &remove_fail { + assert!(map.swap_remove_full(&key).is_none()); + } + println!("{:?}", map); + for &key in &remove { + //println!("{:?}", map); + let index = map.get_full(&key).unwrap().0; + assert_eq!(map.swap_remove_full(&key), Some((index, key, key))); + } + println!("{:?}", map); + + for key in &insert { + assert_eq!(map.get(key).is_some(), !remove.contains(key)); + } + assert_eq!(map.len(), insert.len() - remove.len()); + assert_eq!(map.keys().count(), insert.len() - remove.len()); +} + +#[test] +fn remove_to_empty() { + let mut map = indexmap! { 0 => 0, 4 => 4, 5 => 5 }; + map.swap_remove(&5).unwrap(); + map.swap_remove(&4).unwrap(); + map.swap_remove(&0).unwrap(); + assert!(map.is_empty()); +} + +#[test] +fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt * 2); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and map + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let (out_map, _) = map.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_map); + } + assert_eq!(vector.len(), map.len()); + for (a, b) in vector.iter().zip(map.keys()) { + assert_eq!(a, b); + } +} + +#[test] +fn partial_eq_and_eq() { + let mut map_a = IndexMap::new(); + map_a.insert(1, "1"); + map_a.insert(2, "2"); + let mut map_b = map_a.clone(); + assert_eq!(map_a, map_b); + map_b.swap_remove(&1); + assert_ne!(map_a, map_b); + + let map_c: IndexMap<_, String> = map_b.into_iter().map(|(k, v)| (k, v.into())).collect(); + assert_ne!(map_a, map_c); + assert_ne!(map_c, map_a); +} + +#[test] +fn extend() { + let mut map = IndexMap::new(); + map.extend(vec![(&1, &2), (&3, &4)]); + map.extend(vec![(5, 6)]); + assert_eq!( + map.into_iter().collect::>(), + vec![(1, 2), (3, 4), (5, 6)] + ); +} + +#[test] +fn entry() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.insert(2, "2"); + { + let e = map.entry(3); + assert_eq!(e.index(), 2); + let e = e.or_insert("3"); + assert_eq!(e, &"3"); + } + + let e = map.entry(2); + assert_eq!(e.index(), 1); + assert_eq!(e.key(), &2); + match e { + Entry::Occupied(ref e) => assert_eq!(e.get(), &"2"), + Entry::Vacant(_) => panic!(), + } + assert_eq!(e.or_insert("4"), &"2"); +} + +#[test] +fn entry_and_modify() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.entry(1).and_modify(|x| *x = "2"); + assert_eq!(Some(&"2"), map.get(&1)); + + map.entry(2).and_modify(|x| *x = "doesn't exist"); + assert_eq!(None, map.get(&2)); +} + +#[test] +fn entry_or_default() { + let mut map = IndexMap::new(); + + #[derive(Debug, PartialEq)] + enum TestEnum { + DefaultValue, + NonDefaultValue, + } + + impl Default for TestEnum { + fn default() -> Self { + TestEnum::DefaultValue + } + } + + map.insert(1, TestEnum::NonDefaultValue); + assert_eq!(&mut TestEnum::NonDefaultValue, map.entry(1).or_default()); + + assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default()); +} + +#[test] +fn occupied_entry_key() { + // These keys match hash and equality, but their addresses are distinct. + let (k1, k2) = (&mut 1, &mut 1); + let k1_ptr = k1 as *const i32; + let k2_ptr = k2 as *const i32; + assert_ne!(k1_ptr, k2_ptr); + + let mut map = IndexMap::new(); + map.insert(k1, "value"); + match map.entry(k2) { + Entry::Occupied(ref e) => { + // `OccupiedEntry::key` should reference the key in the map, + // not the key that was used to find the entry. + let ptr = *e.key() as *const i32; + assert_eq!(ptr, k1_ptr); + assert_ne!(ptr, k2_ptr); + } + Entry::Vacant(_) => panic!(), + } +} + +#[test] +fn get_index_entry() { + let mut map = IndexMap::new(); + + assert!(map.get_index_entry(0).is_none()); + assert!(map.first_entry().is_none()); + assert!(map.last_entry().is_none()); + + map.insert(0, "0"); + map.insert(1, "1"); + map.insert(2, "2"); + map.insert(3, "3"); + + assert!(map.get_index_entry(4).is_none()); + + { + let e = map.get_index_entry(1).unwrap(); + assert_eq!(*e.key(), 1); + assert_eq!(*e.get(), "1"); + assert_eq!(e.swap_remove(), "1"); + } + + { + let mut e = map.get_index_entry(1).unwrap(); + assert_eq!(*e.key(), 3); + assert_eq!(*e.get(), "3"); + assert_eq!(e.insert("4"), "3"); + } + + assert_eq!(*map.get(&3).unwrap(), "4"); + + { + let e = map.first_entry().unwrap(); + assert_eq!(*e.key(), 0); + assert_eq!(*e.get(), "0"); + } + + { + let e = map.last_entry().unwrap(); + assert_eq!(*e.key(), 2); + assert_eq!(*e.get(), "2"); + } +} + +#[test] +fn from_entries() { + let mut map = IndexMap::from([(1, "1"), (2, "2"), (3, "3")]); + + { + let e = match map.entry(1) { + Entry::Occupied(e) => IndexedEntry::from(e), + Entry::Vacant(_) => panic!(), + }; + assert_eq!(e.index(), 0); + assert_eq!(*e.key(), 1); + assert_eq!(*e.get(), "1"); + } + + { + let e = match map.get_index_entry(1) { + Some(e) => OccupiedEntry::from(e), + None => panic!(), + }; + assert_eq!(e.index(), 1); + assert_eq!(*e.key(), 2); + assert_eq!(*e.get(), "2"); + } +} + +#[test] +fn keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec = map.into_keys().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: IndexMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2 + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); +} + +#[test] +fn into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec = map.into_values().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn drain_range() { + // Test the various heuristics of `erase_indices` + for range in [ + 0..0, // nothing erased + 10..90, // reinsert the few kept (..10 and 90..) + 80..90, // update the few to adjust (80..) + 20..30, // sweep everything + ] { + let mut vec = Vec::from_iter(0..100); + let mut map: IndexMap = (0..100).map(|i| (i, ())).collect(); + drop(vec.drain(range.clone())); + drop(map.drain(range)); + assert!(vec.iter().eq(map.keys())); + for (i, x) in vec.iter().enumerate() { + assert_eq!(map.get_index_of(x), Some(i)); + } + } +} + +#[test] +#[cfg(feature = "std")] +fn from_array() { + let map = IndexMap::from([(1, 2), (3, 4)]); + let mut expected = IndexMap::new(); + expected.insert(1, 2); + expected.insert(3, 4); + + assert_eq!(map, expected) +} + +#[test] +fn iter_default() { + struct K; + struct V; + fn assert_default() + where + T: Default + Iterator, + { + assert!(T::default().next().is_none()); + } + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); + assert_default::>(); +} + +#[test] +fn get_index_mut2() { + let mut map: IndexMap = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + + { + let (key, value) = map.get_index_mut2(0).unwrap(); + assert_eq!(*key, 1); + assert_eq!(*value, 2); + + *value = 7; + } + assert_eq!(map[0], 7); + + { + let (key, _) = map.get_index_mut2(0).unwrap(); + *key = 8; + } + assert_eq!(map.get_index(0).unwrap().0, &8); +} + +#[test] +fn shift_shift_remove_index() { + let mut map: IndexMap = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + map.insert(7, 8); + map.insert(9, 10); + + let result = map.shift_remove_index(1); + assert_eq!(result, Some((3, 4))); + assert_eq!(map.len(), 4); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8), (9, 10)]); + + let result = map.shift_remove_index(1); + assert_eq!(result, Some((5, 6))); + assert_eq!(map.len(), 3); + assert_eq!(map.as_slice(), &[(1, 2), (7, 8), (9, 10)]); + + let result = map.shift_remove_index(2); + assert_eq!(result, Some((9, 10))); + assert_eq!(map.len(), 2); + assert_eq!(map.as_slice(), &[(1, 2), (7, 8)]); + + let result = map.shift_remove_index(2); + assert_eq!(result, None); + assert_eq!(map.len(), 2); + assert_eq!(map.as_slice(), &[(1, 2), (7, 8)]); +} + +#[test] +fn shift_remove_entry() { + let mut map: IndexMap = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + map.insert(7, 8); + map.insert(9, 10); + + let result = map.shift_remove_entry(&3); + assert_eq!(result, Some((3, 4))); + assert_eq!(map.len(), 4); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8), (9, 10)]); + + let result = map.shift_remove_entry(&9); + assert_eq!(result, Some((9, 10))); + assert_eq!(map.len(), 3); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8)]); + + let result = map.shift_remove_entry(&9); + assert_eq!(result, None); + assert_eq!(map.len(), 3); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8)]); +} + +#[test] +fn shift_remove_full() { + let mut map: IndexMap = IndexMap::new(); + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + map.insert(7, 8); + map.insert(9, 10); + + let result = map.shift_remove_full(&3); + assert_eq!(result, Some((1, 3, 4))); + assert_eq!(map.len(), 4); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8), (9, 10)]); + + let result = map.shift_remove_full(&9); + assert_eq!(result, Some((3, 9, 10))); + assert_eq!(map.len(), 3); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8)]); + + let result = map.shift_remove_full(&9); + assert_eq!(result, None); + assert_eq!(map.len(), 3); + assert_eq!(map.as_slice(), &[(1, 2), (5, 6), (7, 8)]); +} + +#[test] +fn sorted_unstable_by() { + let mut map: IndexMap = IndexMap::new(); + map.extend(vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50)]); + let sorted = map.sorted_unstable_by(|_a, b, _c, d| d.cmp(&b)); + + assert_eq!( + sorted.as_slice(), + &[(5, 50), (4, 40), (3, 30), (2, 20), (1, 10)] + ); +} + +#[test] +fn into_boxed_slice() { + let mut map: IndexMap = IndexMap::new(); + for i in 0..5 { + map.insert(i, i * 10); + } + let boxed_slice: Box> = map.into_boxed_slice(); + assert_eq!(boxed_slice.len(), 5); + assert_eq!( + boxed_slice.as_ref(), + &[(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)] + ); +} + +#[test] +fn last_mut() { + let mut map: IndexMap<&str, i32> = IndexMap::new(); + + let last_entry = map.last_mut(); + assert_eq!(last_entry, None); + + map.insert("key1", 1); + map.insert("key2", 2); + map.insert("key3", 3); + let last_entry = map.last_mut(); + assert_eq!(last_entry, Some((&"key3", &mut 3))); + + *last_entry.unwrap().1 = 4; + assert_eq!(map.get("key3"), Some(&4)); +} + +#[test] +#[should_panic = "index out of bounds"] +fn insert_before_oob() { + let mut map: IndexMap = IndexMap::new(); + let _ = map.insert_before(0, 'a', ()); + let _ = map.insert_before(1, 'b', ()); + map.insert_before(3, 'd', ()); +} + +#[test] +fn clear() { + let mut map: IndexMap = IndexMap::new(); + map.extend(vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50)]); + map.clear(); + assert_eq!(map.len(), 0); +} + +#[test] +fn get_range() { + let mut index_map: IndexMap = IndexMap::new(); + index_map.insert(1, 10); + index_map.insert(2, 20); + index_map.insert(3, 30); + index_map.insert(4, 40); + index_map.insert(5, 50); + + let result = index_map.get_range(2..2); + assert!(result.unwrap().is_empty()); + + let result = index_map.get_range(4..2); + assert!(result.is_none()); + + let result = index_map.get_range(2..4); + let slice: &Slice = result.unwrap(); + assert_eq!(slice.len(), 2); + assert_eq!(slice, &[(3, 30), (4, 40)]); +} + +#[test] +fn get_range_mut() { + let mut index_map: IndexMap = IndexMap::new(); + index_map.insert(1, 10); + index_map.insert(2, 20); + index_map.insert(3, 30); + index_map.insert(4, 40); + index_map.insert(5, 50); + + let result = index_map.get_range_mut(2..2); + assert!(result.unwrap().is_empty()); + + let result = index_map.get_range_mut(4..2); + assert!(result.is_none()); + + let result = index_map.get_range_mut(2..4); + let slice: &mut Slice = result.unwrap(); + assert_eq!(slice.len(), 2); + assert_eq!(slice, &mut [(3, 30), (4, 40)]); + + for i in 0..slice.len() { + slice[i] += 1; + } + assert_eq!(slice, &mut [(3, 31), (4, 41)]); +} + +#[test] +#[should_panic = "index out of bounds"] +fn shift_insert_oob() { + let mut map: IndexMap = IndexMap::new(); + map.shift_insert(0, 1, 10); + map.shift_insert(1, 2, 20); + map.shift_insert(2, 3, 30); + map.shift_insert(5, 4, 40); +} + +#[test] +fn test_binary_search_by() { + // adapted from std's test for binary_search + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(0)); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&3)), Err(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Ok(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(1)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(4)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&9)), Err(6)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(5)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(5)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0)); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&1)), Ok(0)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&2)), Err(1)); + assert!(match b.binary_search_by(|_, x| x.cmp(&3)) { + Ok(1..=3) => true, + _ => false, + }); + assert!(match b.binary_search_by(|_, x| x.cmp(&3)) { + Ok(1..=3) => true, + _ => false, + }); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Err(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Ok(4)); + assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Err(5)); +} + +#[test] +fn test_binary_search_by_key() { + // adapted from std's test for binary_search + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(0)); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&3, |_, &x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(1)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(4)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&9, |_, &x| x), Err(6)); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(5)); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(5)); + assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0)); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&1, |_, &x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&2, |_, &x| x), Err(1)); + assert!(match b.binary_search_by_key(&3, |_, &x| x) { + Ok(1..=3) => true, + _ => false, + }); + assert!(match b.binary_search_by_key(&3, |_, &x| x) { + Ok(1..=3) => true, + _ => false, + }); + assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Ok(4)); + assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Err(5)); +} + +#[test] +fn test_partition_point() { + // adapted from std's test for partition_point + let b: IndexMap<_, i32> = [] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 5), 0); + + let b: IndexMap<_, i32> = [4] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 3), 0); + assert_eq!(b.partition_point(|_, &x| x < 4), 0); + assert_eq!(b.partition_point(|_, &x| x < 5), 1); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 5), 3); + assert_eq!(b.partition_point(|_, &x| x < 6), 3); + assert_eq!(b.partition_point(|_, &x| x < 7), 4); + assert_eq!(b.partition_point(|_, &x| x < 8), 4); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 9), 6); + + let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 6), 3); + assert_eq!(b.partition_point(|_, &x| x < 5), 3); + assert_eq!(b.partition_point(|_, &x| x < 8), 5); + + let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 7), 5); + assert_eq!(b.partition_point(|_, &x| x < 0), 0); + + let b: IndexMap<_, i32> = [1, 3, 3, 3, 7] + .into_iter() + .enumerate() + .map(|(i, x)| (i + 100, x)) + .collect(); + assert_eq!(b.partition_point(|_, &x| x < 0), 0); + assert_eq!(b.partition_point(|_, &x| x < 1), 0); + assert_eq!(b.partition_point(|_, &x| x < 2), 1); + assert_eq!(b.partition_point(|_, &x| x < 3), 1); + assert_eq!(b.partition_point(|_, &x| x < 4), 4); + assert_eq!(b.partition_point(|_, &x| x < 5), 4); + assert_eq!(b.partition_point(|_, &x| x < 6), 4); + assert_eq!(b.partition_point(|_, &x| x < 7), 4); + assert_eq!(b.partition_point(|_, &x| x < 8), 5); +} + +macro_rules! move_index_oob { + ($test:ident, $from:expr, $to:expr) => { + #[test] + #[should_panic(expected = "index out of bounds")] + fn $test() { + let mut map: IndexMap = (0..10).map(|k| (k, ())).collect(); + map.move_index($from, $to); + } + }; +} +move_index_oob!(test_move_index_out_of_bounds_0_10, 0, 10); +move_index_oob!(test_move_index_out_of_bounds_0_max, 0, usize::MAX); +move_index_oob!(test_move_index_out_of_bounds_10_0, 10, 0); +move_index_oob!(test_move_index_out_of_bounds_max_0, usize::MAX, 0); + +#[test] +fn disjoint_mut_empty_map() { + let mut map: IndexMap = IndexMap::default(); + assert_eq!( + map.get_disjoint_mut([&0, &1, &2, &3]), + [None, None, None, None] + ); +} + +#[test] +fn disjoint_mut_empty_param() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([] as [&u32; 0]), []); +} + +#[test] +fn disjoint_mut_single_fail() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([&0]), [None]); +} + +#[test] +fn disjoint_mut_single_success() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([&1]), [Some(&mut 10)]); +} + +#[test] +fn disjoint_mut_multi_success() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + assert_eq!( + map.get_disjoint_mut([&1, &2]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut([&1, &3]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut([&3, &1, &4, &2]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_success_unsized_key() { + let mut map: IndexMap<&'static str, u32> = IndexMap::default(); + map.insert("1", 100); + map.insert("2", 200); + map.insert("3", 300); + map.insert("4", 400); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_success_borrow_key() { + let mut map: IndexMap = IndexMap::default(); + map.insert("1".into(), 100); + map.insert("2".into(), 200); + map.insert("3".into(), 300); + map.insert("4".into(), 400); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_fail_missing() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + + assert_eq!(map.get_disjoint_mut([&1, &5]), [Some(&mut 100), None]); + assert_eq!(map.get_disjoint_mut([&5, &6]), [None, None]); + assert_eq!( + map.get_disjoint_mut([&1, &5, &4]), + [Some(&mut 100), None, Some(&mut 400)] + ); +} + +#[test] +#[should_panic] +fn disjoint_mut_multi_fail_duplicate_panic() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 100); + map.get_disjoint_mut([&1, &2, &1]); +} + +#[test] +fn disjoint_indices_mut_fail_oob() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!( + map.get_disjoint_indices_mut([1, 3]), + Err(crate::GetDisjointMutError::IndexOutOfBounds) + ); +} + +#[test] +fn disjoint_indices_mut_empty() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!(map.get_disjoint_indices_mut([]), Ok([])); +} + +#[test] +fn disjoint_indices_mut_success() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!(map.get_disjoint_indices_mut([0]), Ok([(&1, &mut 10)])); + + assert_eq!(map.get_disjoint_indices_mut([1]), Ok([(&321, &mut 20)])); + assert_eq!( + map.get_disjoint_indices_mut([0, 1]), + Ok([(&1, &mut 10), (&321, &mut 20)]) + ); +} + +#[test] +fn disjoint_indices_mut_fail_duplicate() { + let mut map: IndexMap = IndexMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!( + map.get_disjoint_indices_mut([1, 0, 1]), + Err(crate::GetDisjointMutError::OverlappingIndices) + ); +} + +#[test] +fn insert_sorted_by_key() { + let mut values = [(-1, 8), (3, 18), (-27, 2), (-2, 5)]; + let mut map: IndexMap = IndexMap::new(); + for (key, value) in values { + let (_, old) = map.insert_sorted_by_key(key, value, |k, _| k.abs()); + assert_eq!(old, None); + } + values.sort_by_key(|(key, _)| key.abs()); + assert_eq!(values, *map.as_slice()); + + for (key, value) in &mut values { + let (_, old) = map.insert_sorted_by_key(*key, -*value, |k, _| k.abs()); + assert_eq!(old, Some(*value)); + *value = -*value; + } + assert_eq!(values, *map.as_slice()); +} + +#[test] +fn insert_sorted_by() { + let mut values = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]; + let mut map: IndexMap = IndexMap::new(); + for (key, value) in values { + let (_, old) = map.insert_sorted_by(key, value, |key1, _, key2, _| key2.cmp(key1)); + assert_eq!(old, None); + } + values.reverse(); + assert_eq!(values, *map.as_slice()); + + for (key, value) in &mut values { + let (_, old) = map.insert_sorted_by(*key, -*value, |key1, _, key2, _| key2.cmp(key1)); + assert_eq!(old, Some(*value)); + *value = -*value; + } + assert_eq!(values, *map.as_slice()); +} + +#[test] +fn is_sorted() { + fn expect(map: &IndexMap, e: [bool; 7]) { + assert_eq!(e[0], map.is_sorted()); + assert_eq!(e[1], map.is_sorted_by(|k1, _, k2, _| k1 < k2)); + assert_eq!(e[2], map.is_sorted_by(|k1, _, k2, _| k1 > k2)); + assert_eq!(e[3], map.is_sorted_by(|_, v1, _, v2| v1 < v2)); + assert_eq!(e[4], map.is_sorted_by(|_, v1, _, v2| v1 > v2)); + assert_eq!(e[5], map.is_sorted_by_key(|k, _| k)); + assert_eq!(e[6], map.is_sorted_by_key(|_, v| v)); + } + + let mut map = IndexMap::from_iter((0..10).map(|i| (i, i * i))); + expect(&map, [true, true, false, true, false, true, true]); + + map[5] = -1; + expect(&map, [true, true, false, false, false, true, false]); + + map[5] = 25; + map.replace_index(5, -1).unwrap(); + expect(&map, [false, false, false, true, false, false, true]); +} + +#[test] +fn is_sorted_trivial() { + fn expect(map: &IndexMap, e: [bool; 5]) { + assert_eq!(e[0], map.is_sorted()); + assert_eq!(e[1], map.is_sorted_by(|_, _, _, _| true)); + assert_eq!(e[2], map.is_sorted_by(|_, _, _, _| false)); + assert_eq!(e[3], map.is_sorted_by_key(|_, _| 0f64)); + assert_eq!(e[4], map.is_sorted_by_key(|_, _| f64::NAN)); + } + + let mut map = IndexMap::new(); + expect(&map, [true, true, true, true, true]); + + map.insert(0, 0); + expect(&map, [true, true, true, true, true]); + + map.insert(1, 1); + expect(&map, [true, true, false, true, false]); + + map.reverse(); + expect(&map, [false, true, false, true, false]); +} diff --git a/deps/crates/vendor/indexmap/src/rayon/map.rs b/deps/crates/vendor/indexmap/src/rayon/map.rs new file mode 100644 index 00000000000000..826663478f9167 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/rayon/map.rs @@ -0,0 +1,686 @@ +//! Parallel iterator types for [`IndexMap`] with [`rayon`][::rayon]. +//! +//! You will rarely need to interact with this module directly unless you need to name one of the +//! iterator types. + +use super::collect; +use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use rayon::prelude::*; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::ops::RangeBounds; + +use crate::Bucket; +use crate::IndexMap; +use crate::map::Slice; + +impl IntoParallelIterator for IndexMap +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +impl IntoParallelIterator for Box> +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_par_iter`] method +/// (provided by rayon's [`IntoParallelIterator`] trait). See its documentation for more. +pub struct IntoParIter { + entries: Vec>, +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + parallel_iterator_methods!(Bucket::key_value); +} + +impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key_value); +} + +impl<'a, K, V, S> IntoParallelIterator for &'a IndexMap +where + K: Sync, + V: Sync, +{ + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } +} + +impl<'a, K, V> IntoParallelIterator for &'a Slice +where + K: Sync, + V: Sync, +{ + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: &self.entries, + } + } +} + +/// A parallel iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_iter`] method +/// (provided by rayon's [`IntoParallelRefIterator`] trait). See its documentation for more. +/// +/// [`IndexMap::par_iter`]: ../struct.IndexMap.html#method.par_iter +pub struct ParIter<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParIter<'_, K, V> { + fn clone(&self) -> Self { + ParIter { ..*self } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + parallel_iterator_methods!(Bucket::refs); +} + +impl IndexedParallelIterator for ParIter<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::refs); +} + +impl<'a, K, V, S> IntoParallelIterator for &'a mut IndexMap +where + K: Sync + Send, + V: Send, +{ + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + entries: self.as_entries_mut(), + } + } +} + +impl<'a, K, V> IntoParallelIterator for &'a mut Slice +where + K: Sync + Send, + V: Send, +{ + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + entries: &mut self.entries, + } + } +} + +/// A parallel mutable iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_iter_mut`] method +/// (provided by rayon's [`IntoParallelRefMutIterator`] trait). See its documentation for more. +/// +/// [`IndexMap::par_iter_mut`]: ../struct.IndexMap.html#method.par_iter_mut +pub struct ParIterMut<'a, K, V> { + entries: &'a mut [Bucket], +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync + Send, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + parallel_iterator_methods!(Bucket::ref_mut); +} + +impl IndexedParallelIterator for ParIterMut<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::ref_mut); +} + +impl<'a, K, V, S> ParallelDrainRange for &'a mut IndexMap +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = ParDrain<'a, K, V>; + + fn par_drain>(self, range: R) -> Self::Iter { + ParDrain { + entries: self.core.par_drain(range), + } + } +} + +/// A parallel draining iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_drain`] method +/// (provided by rayon's [`ParallelDrainRange`] trait). See its documentation for more. +/// +/// [`IndexMap::par_drain`]: ../struct.IndexMap.html#method.par_drain +pub struct ParDrain<'a, K: Send, V: Send> { + entries: rayon::vec::Drain<'a, Bucket>, +} + +impl ParallelIterator for ParDrain<'_, K, V> { + type Item = (K, V); + + parallel_iterator_methods!(Bucket::key_value); +} + +impl IndexedParallelIterator for ParDrain<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::key_value); +} + +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl IndexMap +where + K: Sync, + V: Sync, +{ + /// Return a parallel iterator over the keys of the map. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + entries: self.as_entries(), + } + } + + /// Return a parallel iterator over the values of the map. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + entries: self.as_entries(), + } + } +} + +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl Slice +where + K: Sync, + V: Sync, +{ + /// Return a parallel iterator over the keys of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + entries: &self.entries, + } + } + + /// Return a parallel iterator over the values of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + entries: &self.entries, + } + } +} + +impl IndexMap +where + K: Hash + Eq + Sync, + V: Sync, + S: BuildHasher, +{ + /// Returns `true` if `self` contains all of the same key-value pairs as `other`, + /// regardless of each map's indexed order, determined in parallel. + pub fn par_eq(&self, other: &IndexMap) -> bool + where + V: PartialEq, + V2: Sync, + S2: BuildHasher + Sync, + { + self.len() == other.len() + && self + .par_iter() + .all(move |(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +/// A parallel iterator over the keys of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_keys`] method. +/// See its documentation for more. +pub struct ParKeys<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParKeys<'_, K, V> { + fn clone(&self) -> Self { + ParKeys { ..*self } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + parallel_iterator_methods!(Bucket::key_ref); +} + +impl IndexedParallelIterator for ParKeys<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::key_ref); +} + +/// A parallel iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_values`] method. +/// See its documentation for more. +pub struct ParValues<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParValues<'_, K, V> { + fn clone(&self) -> Self { + ParValues { ..*self } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + parallel_iterator_methods!(Bucket::value_ref); +} + +impl IndexedParallelIterator for ParValues<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::value_ref); +} + +impl IndexMap +where + K: Send, + V: Send, +{ + /// Return a parallel iterator over mutable references to the values of the map + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + entries: self.as_entries_mut(), + } + } +} + +impl Slice +where + K: Send, + V: Send, +{ + /// Return a parallel iterator over mutable references to the the values of the map slice. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the slice is still preserved for operations like `reduce` and `collect`. + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + entries: &mut self.entries, + } + } +} + +impl IndexMap +where + K: Send, + V: Send, +{ + /// Sort the map's key-value pairs in parallel, by the default ordering of the keys. + pub fn par_sort_keys(&mut self) + where + K: Ord, + { + self.with_entries(|entries| { + entries.par_sort_by(|a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place and in parallel, using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + pub fn par_sort_by(&mut self, cmp: F) + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map in parallel and return a by-value parallel + /// iterator of the key-value pairs with the result. + pub fn par_sorted_by(self, cmp: F) -> IntoParIter + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoParIter { entries } + } + + /// Sort the map's key-value pairs in place and in parallel, using a sort-key extraction + /// function. + pub fn par_sort_by_key(&mut self, sort_key: F) + where + T: Ord, + F: Fn(&K, &V) -> T + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Sort the map's key-value pairs in parallel, by the default ordering of the keys. + pub fn par_sort_unstable_keys(&mut self) + where + K: Ord, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(|a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place and in parallel, using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + pub fn par_sort_unstable_by(&mut self, cmp: F) + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map in parallel and return a by-value parallel + /// iterator of the key-value pairs with the result. + pub fn par_sorted_unstable_by(self, cmp: F) -> IntoParIter + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoParIter { entries } + } + + /// Sort the map's key-value pairs in place and in parallel, using a sort-key extraction + /// function. + pub fn par_sort_unstable_by_key(&mut self, sort_key: F) + where + T: Ord, + F: Fn(&K, &V) -> T + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_unstable_by_key(move |a| sort_key(&a.key, &a.value)); + }); + } + + /// Sort the map's key-value pairs in place and in parallel, using a sort-key extraction + /// function. + pub fn par_sort_by_cached_key(&mut self, sort_key: F) + where + T: Ord + Send, + F: Fn(&K, &V) -> T + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_cached_key(move |a| sort_key(&a.key, &a.value)); + }); + } +} + +/// A parallel mutable iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::par_values_mut`] method. +/// See its documentation for more. +pub struct ParValuesMut<'a, K, V> { + entries: &'a mut [Bucket], +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Send, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + parallel_iterator_methods!(Bucket::value_mut); +} + +impl IndexedParallelIterator for ParValuesMut<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::value_mut); +} + +impl FromParallelIterator<(K, V)> for IndexMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default + Send, +{ + fn from_par_iter(iter: I) -> Self + where + I: IntoParallelIterator, + { + let list = collect(iter); + let len = list.iter().map(Vec::len).sum(); + let mut map = Self::with_capacity_and_hasher(len, S::default()); + for vec in list { + map.extend(vec); + } + map + } +} + +impl ParallelExtend<(K, V)> for IndexMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for IndexMap +where + K: Copy + Eq + Hash + Send + Sync, + V: Copy + Send + Sync, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::String; + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, ()); + } + + assert_eq!(map.par_keys().count(), map.len()); + assert_eq!(map.par_keys().count(), insert.len()); + insert.par_iter().zip(map.par_keys()).for_each(|(a, b)| { + assert_eq!(a, b); + }); + (0..insert.len()) + .into_par_iter() + .zip(map.par_keys()) + .for_each(|(i, k)| { + assert_eq!(map.get_index(i).unwrap().0, k); + }); + } + + #[test] + fn partial_eq_and_eq() { + let mut map_a = IndexMap::new(); + map_a.insert(1, "1"); + map_a.insert(2, "2"); + let mut map_b = map_a.clone(); + assert!(map_a.par_eq(&map_b)); + map_b.swap_remove(&1); + assert!(!map_a.par_eq(&map_b)); + map_b.insert(3, "3"); + assert!(!map_a.par_eq(&map_b)); + + let map_c: IndexMap<_, String> = + map_b.into_par_iter().map(|(k, v)| (k, v.into())).collect(); + assert!(!map_a.par_eq(&map_c)); + assert!(!map_c.par_eq(&map_a)); + } + + #[test] + fn extend() { + let mut map = IndexMap::new(); + map.par_extend(vec![(&1, &2), (&3, &4)]); + map.par_extend(vec![(5, 6)]); + assert_eq!( + map.into_par_iter().collect::>(), + vec![(1, 2), (3, 4), (5, 6)] + ); + } + + #[test] + fn keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: IndexMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } +} diff --git a/deps/crates/vendor/indexmap/src/rayon/mod.rs b/deps/crates/vendor/indexmap/src/rayon/mod.rs new file mode 100644 index 00000000000000..73e7fa0e438e98 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/rayon/mod.rs @@ -0,0 +1,15 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "rayon")))] + +use rayon::prelude::*; + +use alloc::collections::LinkedList; +use alloc::vec::Vec; + +pub mod map; +pub mod set; + +// This form of intermediate collection is also how Rayon collects `HashMap`. +// Note that the order will also be preserved! +fn collect(iter: I) -> LinkedList> { + iter.into_par_iter().collect_vec_list() +} diff --git a/deps/crates/vendor/indexmap/src/rayon/set.rs b/deps/crates/vendor/indexmap/src/rayon/set.rs new file mode 100644 index 00000000000000..86e1f7ba9ee48f --- /dev/null +++ b/deps/crates/vendor/indexmap/src/rayon/set.rs @@ -0,0 +1,777 @@ +//! Parallel iterator types for [`IndexSet`] with [rayon][::rayon]. +//! +//! You will rarely need to interact with this module directly unless you need to name one of the +//! iterator types. + +use super::collect; +use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use rayon::prelude::*; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::ops::RangeBounds; + +use crate::IndexSet; +use crate::set::Slice; + +type Bucket = crate::Bucket; + +impl IntoParallelIterator for IndexSet +where + T: Send, +{ + type Item = T; + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +impl IntoParallelIterator for Box> +where + T: Send, +{ + type Item = T; + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::into_par_iter`] method +/// (provided by rayon's [`IntoParallelIterator`] trait). See its documentation for more. +pub struct IntoParIter { + entries: Vec>, +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + parallel_iterator_methods!(Bucket::key); +} + +impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key); +} + +impl<'a, T, S> IntoParallelIterator for &'a IndexSet +where + T: Sync, +{ + type Item = &'a T; + type Iter = ParIter<'a, T>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } +} + +impl<'a, T> IntoParallelIterator for &'a Slice +where + T: Sync, +{ + type Item = &'a T; + type Iter = ParIter<'a, T>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: &self.entries, + } + } +} + +/// A parallel iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::par_iter`] method +/// (provided by rayon's [`IntoParallelRefIterator`] trait). See its documentation for more. +/// +/// [`IndexSet::par_iter`]: ../struct.IndexSet.html#method.par_iter +pub struct ParIter<'a, T> { + entries: &'a [Bucket], +} + +impl Clone for ParIter<'_, T> { + fn clone(&self) -> Self { + ParIter { ..*self } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + parallel_iterator_methods!(Bucket::key_ref); +} + +impl IndexedParallelIterator for ParIter<'_, T> { + indexed_parallel_iterator_methods!(Bucket::key_ref); +} + +impl<'a, T, S> ParallelDrainRange for &'a mut IndexSet +where + T: Send, +{ + type Item = T; + type Iter = ParDrain<'a, T>; + + fn par_drain>(self, range: R) -> Self::Iter { + ParDrain { + entries: self.map.core.par_drain(range), + } + } +} + +/// A parallel draining iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::par_drain`] method +/// (provided by rayon's [`ParallelDrainRange`] trait). See its documentation for more. +/// +/// [`IndexSet::par_drain`]: ../struct.IndexSet.html#method.par_drain +pub struct ParDrain<'a, T: Send> { + entries: rayon::vec::Drain<'a, Bucket>, +} + +impl ParallelIterator for ParDrain<'_, T> { + type Item = T; + + parallel_iterator_methods!(Bucket::key); +} + +impl IndexedParallelIterator for ParDrain<'_, T> { + indexed_parallel_iterator_methods!(Bucket::key); +} + +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl IndexSet +where + T: Hash + Eq + Sync, + S: BuildHasher + Sync, +{ + /// Return a parallel iterator over the values that are in `self` but not `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the `self` set is still preserved for operations like `reduce` and `collect`. + pub fn par_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParDifference<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParDifference { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over the values that are in `self` or `other`, + /// but not in both. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the sets is still preserved for operations like `reduce` and `collect`. + /// Values from `self` are produced in their original order, followed by + /// values from `other` in their original order. + pub fn par_symmetric_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParSymmetricDifference<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParSymmetricDifference { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over the values that are in both `self` and `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the `self` set is still preserved for operations like `reduce` and `collect`. + pub fn par_intersection<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParIntersection<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParIntersection { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over all values that are in `self` or `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the sets is still preserved for operations like `reduce` and `collect`. + /// Values from `self` are produced in their original order, followed by + /// values that are unique to `other` in their original order. + pub fn par_union<'a, S2>(&'a self, other: &'a IndexSet) -> ParUnion<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParUnion { + set1: self, + set2: other, + } + } + + /// Returns `true` if `self` contains all of the same values as `other`, + /// regardless of each set's indexed order, determined in parallel. + pub fn par_eq(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + self.len() == other.len() && self.par_is_subset(other) + } + + /// Returns `true` if `self` has no elements in common with `other`, + /// determined in parallel. + pub fn par_is_disjoint(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + if self.len() <= other.len() { + self.par_iter().all(move |value| !other.contains(value)) + } else { + other.par_iter().all(move |value| !self.contains(value)) + } + } + + /// Returns `true` if all elements of `other` are contained in `self`, + /// determined in parallel. + pub fn par_is_superset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + other.par_is_subset(self) + } + + /// Returns `true` if all elements of `self` are contained in `other`, + /// determined in parallel. + pub fn par_is_subset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + self.len() <= other.len() && self.par_iter().all(move |value| other.contains(value)) + } +} + +/// A parallel iterator producing elements in the difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::par_difference`] method. +/// See its documentation for more. +pub struct ParDifference<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParDifference { ..*self } + } +} + +impl fmt::Debug for ParDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.difference(self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParDifference<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .filter(move |&item| !set2.contains(item)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the intersection of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::par_intersection`] method. +/// See its documentation for more. +pub struct ParIntersection<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParIntersection<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParIntersection { ..*self } + } +} + +impl fmt::Debug for ParIntersection<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.intersection(self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParIntersection<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .filter(move |&item| set2.contains(item)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the symmetric difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::par_symmetric_difference`] method. +/// See its documentation for more. +pub struct ParSymmetricDifference<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParSymmetricDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParSymmetricDifference { ..*self } + } +} + +impl fmt::Debug for ParSymmetricDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.symmetric_difference(self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParSymmetricDifference<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_difference(set2) + .chain(set2.par_difference(set1)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the union of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::par_union`] method. +/// See its documentation for more. +pub struct ParUnion<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParUnion<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParUnion { ..*self } + } +} + +impl fmt::Debug for ParUnion<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.set1.union(self.set2)).finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParUnion<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .chain(set2.par_difference(set1)) + .drive_unindexed(consumer) + } +} + +/// Parallel sorting methods. +/// +/// The following methods **require crate feature `"rayon"`**. +impl IndexSet +where + T: Send, +{ + /// Sort the set's values in parallel by their default ordering. + pub fn par_sort(&mut self) + where + T: Ord, + { + self.with_entries(|entries| { + entries.par_sort_by(|a, b| T::cmp(&a.key, &b.key)); + }); + } + + /// Sort the set's values in place and in parallel, using the comparison function `cmp`. + pub fn par_sort_by(&mut self, cmp: F) + where + F: Fn(&T, &T) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_by(move |a, b| cmp(&a.key, &b.key)); + }); + } + + /// Sort the values of the set in parallel and return a by-value parallel iterator of + /// the values with the result. + pub fn par_sorted_by(self, cmp: F) -> IntoParIter + where + F: Fn(&T, &T) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_by(move |a, b| cmp(&a.key, &b.key)); + IntoParIter { entries } + } + + /// Sort the set's values in place and in parallel, using a key extraction function. + pub fn par_sort_by_key(&mut self, sort_key: F) + where + K: Ord, + F: Fn(&T) -> K + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_key(move |a| sort_key(&a.key)); + }); + } + + /// Sort the set's values in parallel by their default ordering. + pub fn par_sort_unstable(&mut self) + where + T: Ord, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(|a, b| T::cmp(&a.key, &b.key)); + }); + } + + /// Sort the set's values in place and in parallel, using the comparison function `cmp`. + pub fn par_sort_unstable_by(&mut self, cmp: F) + where + F: Fn(&T, &T) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); + }); + } + + /// Sort the values of the set in parallel and return a by-value parallel iterator of + /// the values with the result. + pub fn par_sorted_unstable_by(self, cmp: F) -> IntoParIter + where + F: Fn(&T, &T) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); + IntoParIter { entries } + } + + /// Sort the set's values in place and in parallel, using a key extraction function. + pub fn par_sort_unstable_by_key(&mut self, sort_key: F) + where + K: Ord, + F: Fn(&T) -> K + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_unstable_by_key(move |a| sort_key(&a.key)); + }); + } + + /// Sort the set's values in place and in parallel, using a key extraction function. + pub fn par_sort_by_cached_key(&mut self, sort_key: F) + where + K: Ord + Send, + F: Fn(&T) -> K + Sync, + { + self.with_entries(move |entries| { + entries.par_sort_by_cached_key(move |a| sort_key(&a.key)); + }); + } +} + +impl FromParallelIterator for IndexSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default + Send, +{ + fn from_par_iter(iter: I) -> Self + where + I: IntoParallelIterator, + { + let list = collect(iter); + let len = list.iter().map(Vec::len).sum(); + let mut set = Self::with_capacity_and_hasher(len, S::default()); + for vec in list { + set.extend(vec); + } + set + } +} + +impl ParallelExtend for IndexSet +where + T: Eq + Hash + Send, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +impl<'a, T: 'a, S> ParallelExtend<&'a T> for IndexSet +where + T: Copy + Eq + Hash + Send + Sync, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.par_iter().count(), set.len()); + assert_eq!(set.par_iter().count(), insert.len()); + insert.par_iter().zip(&set).for_each(|(a, b)| { + assert_eq!(a, b); + }); + (0..insert.len()) + .into_par_iter() + .zip(&set) + .for_each(|(i, v)| { + assert_eq!(set.get_index(i).unwrap(), v); + }); + } + + #[test] + fn partial_eq_and_eq() { + let mut set_a = IndexSet::new(); + set_a.insert(1); + set_a.insert(2); + let mut set_b = set_a.clone(); + assert!(set_a.par_eq(&set_b)); + set_b.swap_remove(&1); + assert!(!set_a.par_eq(&set_b)); + set_b.insert(3); + assert!(!set_a.par_eq(&set_b)); + + let set_c: IndexSet<_> = set_b.into_par_iter().collect(); + assert!(!set_a.par_eq(&set_c)); + assert!(!set_c.par_eq(&set_a)); + } + + #[test] + fn extend() { + let mut set = IndexSet::new(); + set.par_extend(vec![&1, &2, &3, &4]); + set.par_extend(vec![5, 6]); + assert_eq!( + set.into_par_iter().collect::>(), + vec![1, 2, 3, 4, 5, 6] + ); + } + + #[test] + fn comparisons() { + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).collect(); + + assert!(!set_a.par_is_disjoint(&set_a)); + assert!(set_a.par_is_subset(&set_a)); + assert!(set_a.par_is_superset(&set_a)); + + assert!(set_a.par_is_disjoint(&set_b)); + assert!(set_b.par_is_disjoint(&set_a)); + assert!(!set_a.par_is_subset(&set_b)); + assert!(!set_b.par_is_subset(&set_a)); + assert!(!set_a.par_is_superset(&set_b)); + assert!(!set_b.par_is_superset(&set_a)); + + assert!(!set_a.par_is_disjoint(&set_c)); + assert!(!set_c.par_is_disjoint(&set_a)); + assert!(set_a.par_is_subset(&set_c)); + assert!(!set_c.par_is_subset(&set_a)); + assert!(!set_a.par_is_superset(&set_c)); + assert!(set_c.par_is_superset(&set_a)); + + assert!(!set_c.par_is_disjoint(&set_d)); + assert!(!set_d.par_is_disjoint(&set_c)); + assert!(!set_c.par_is_subset(&set_d)); + assert!(!set_d.par_is_subset(&set_c)); + assert!(!set_c.par_is_superset(&set_d)); + assert!(!set_d.par_is_superset(&set_c)); + } + + #[test] + fn iter_comparisons() { + use std::iter::empty; + + fn check<'a, I1, I2>(iter1: I1, iter2: I2) + where + I1: ParallelIterator, + I2: Iterator, + { + let v1: Vec<_> = iter1.copied().collect(); + let v2: Vec<_> = iter2.collect(); + assert_eq!(v1, v2); + } + + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + check(set_a.par_difference(&set_a), empty()); + check(set_a.par_symmetric_difference(&set_a), empty()); + check(set_a.par_intersection(&set_a), 0..3); + check(set_a.par_union(&set_a), 0..3); + + check(set_a.par_difference(&set_b), 0..3); + check(set_b.par_difference(&set_a), 3..6); + check(set_a.par_symmetric_difference(&set_b), 0..6); + check(set_b.par_symmetric_difference(&set_a), (3..6).chain(0..3)); + check(set_a.par_intersection(&set_b), empty()); + check(set_b.par_intersection(&set_a), empty()); + check(set_a.par_union(&set_b), 0..6); + check(set_b.par_union(&set_a), (3..6).chain(0..3)); + + check(set_a.par_difference(&set_c), empty()); + check(set_c.par_difference(&set_a), 3..6); + check(set_a.par_symmetric_difference(&set_c), 3..6); + check(set_c.par_symmetric_difference(&set_a), 3..6); + check(set_a.par_intersection(&set_c), 0..3); + check(set_c.par_intersection(&set_a), 0..3); + check(set_a.par_union(&set_c), 0..6); + check(set_c.par_union(&set_a), 0..6); + + check(set_c.par_difference(&set_d), 0..3); + check(set_d.par_difference(&set_c), (6..9).rev()); + check( + set_c.par_symmetric_difference(&set_d), + (0..3).chain((6..9).rev()), + ); + check( + set_d.par_symmetric_difference(&set_c), + (6..9).rev().chain(0..3), + ); + check(set_c.par_intersection(&set_d), 3..6); + check(set_d.par_intersection(&set_c), (3..6).rev()); + check(set_c.par_union(&set_d), (0..6).chain((6..9).rev())); + check(set_d.par_union(&set_c), (3..9).rev().chain(0..3)); + } +} diff --git a/deps/crates/vendor/indexmap/src/serde.rs b/deps/crates/vendor/indexmap/src/serde.rs new file mode 100644 index 00000000000000..fe1886659e32b2 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/serde.rs @@ -0,0 +1,165 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] + +use serde_core::de::value::{MapDeserializer, SeqDeserializer}; +use serde_core::de::{ + Deserialize, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor, +}; +use serde_core::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::{Bucket, IndexMap, IndexSet}; + +/// Limit our preallocated capacity from a deserializer `size_hint()`. +/// +/// We do account for the `Bucket` overhead from its saved `hash` field, but we don't count the +/// `RawTable` allocation or the fact that its raw capacity will be rounded up to a power of two. +/// The "max" is an arbitrary choice anyway, not something that needs precise adherence. +/// +/// This is based on the internal `serde::de::size_hint::cautious(hint)` function. +pub(crate) fn cautious_capacity(hint: Option) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + Ord::min( + hint.unwrap_or(0), + MAX_PREALLOC_BYTES / size_of::>(), + ) +} + +impl Serialize for IndexMap +where + K: Serialize, + V: Serialize, +{ + fn serialize(&self, serializer: T) -> Result + where + T: Serializer, + { + serializer.collect_map(self) + } +} + +struct IndexMapVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for IndexMapVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a map") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let capacity = cautious_capacity::(map.size_hint()); + let mut values = IndexMap::with_capacity_and_hasher(capacity, S::default()); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } +} + +impl<'de, K, V, S> Deserialize<'de> for IndexMap +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(IndexMapVisitor(PhantomData)) + } +} + +impl<'de, K, V, S, E> IntoDeserializer<'de, E> for IndexMap +where + K: IntoDeserializer<'de, E> + Eq + Hash, + V: IntoDeserializer<'de, E>, + S: BuildHasher, + E: Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +impl Serialize for IndexSet +where + T: Serialize, +{ + fn serialize(&self, serializer: Se) -> Result + where + Se: Serializer, + { + serializer.collect_seq(self) + } +} + +struct IndexSetVisitor(PhantomData<(T, S)>); + +impl<'de, T, S> Visitor<'de> for IndexSetVisitor +where + T: Deserialize<'de> + Eq + Hash, + S: Default + BuildHasher, +{ + type Value = IndexSet; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a set") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = cautious_capacity::(seq.size_hint()); + let mut values = IndexSet::with_capacity_and_hasher(capacity, S::default()); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } +} + +impl<'de, T, S> Deserialize<'de> for IndexSet +where + T: Deserialize<'de> + Eq + Hash, + S: Default + BuildHasher, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(IndexSetVisitor(PhantomData)) + } +} + +impl<'de, T, S, E> IntoDeserializer<'de, E> for IndexSet +where + T: IntoDeserializer<'de, E> + Eq + Hash, + S: BuildHasher, + E: Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} diff --git a/deps/crates/vendor/indexmap/src/set.rs b/deps/crates/vendor/indexmap/src/set.rs new file mode 100644 index 00000000000000..38b0761a9958f3 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/set.rs @@ -0,0 +1,1478 @@ +//! A hash set implemented using [`IndexMap`] + +mod iter; +mod mutable; +mod slice; + +#[cfg(test)] +mod tests; + +pub use self::iter::{ + Difference, Drain, ExtractIf, Intersection, IntoIter, Iter, Splice, SymmetricDifference, Union, +}; +pub use self::mutable::MutableValues; +pub use self::slice::Slice; + +use crate::TryReserveError; +#[cfg(feature = "rayon")] +pub use crate::rayon::set as rayon; + +#[cfg(feature = "std")] +use std::hash::RandomState; + +use crate::util::try_simplify_range; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub}; + +use super::{Equivalent, IndexMap}; + +type Bucket = super::Bucket; + +/// A hash set where the iteration order of the values is independent of their +/// hash values. +/// +/// The interface is closely compatible with the standard +/// [`HashSet`][std::collections::HashSet], +/// but also has additional features. +/// +/// # Order +/// +/// The values have a consistent order that is determined by the sequence of +/// insertion and removal calls on the set. The order does not depend on the +/// values or the hash function at all. Note that insertion order and value +/// are not affected if a re-insertion is attempted once an element is +/// already present. +/// +/// All iterators traverse the set *in order*. Set operation iterators like +/// [`IndexSet::union`] produce a concatenated order, as do their matching "bitwise" +/// operators. See their documentation for specifics. +/// +/// The insertion order is preserved, with **notable exceptions** like the +/// [`.remove()`][Self::remove] or [`.swap_remove()`][Self::swap_remove] methods. +/// Methods such as [`.sort_by()`][Self::sort_by] of +/// course result in a new order, depending on the sorting order. +/// +/// # Indices +/// +/// The values are indexed in a compact range without holes in the range +/// `0..self.len()`. For example, the method `.get_full` looks up the index for +/// a value, and the method `.get_index` looks up the value by index. +/// +/// # Complexity +/// +/// Internally, `IndexSet` just holds an [`IndexMap`](IndexMap). Thus the complexity +/// of the two are the same for most methods. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexSet; +/// +/// // Collects which letters appear in a sentence. +/// let letters: IndexSet<_> = "a short treatise on fungi".chars().collect(); +/// +/// assert!(letters.contains(&'s')); +/// assert!(letters.contains(&'t')); +/// assert!(letters.contains(&'u')); +/// assert!(!letters.contains(&'y')); +/// ``` +#[cfg(feature = "std")] +pub struct IndexSet { + pub(crate) map: IndexMap, +} +#[cfg(not(feature = "std"))] +pub struct IndexSet { + pub(crate) map: IndexMap, +} + +impl Clone for IndexSet +where + T: Clone, + S: Clone, +{ + fn clone(&self) -> Self { + IndexSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.map.clone_from(&other.map); + } +} + +impl fmt::Debug for IndexSet +where + T: fmt::Debug, +{ + #[cfg(not(feature = "test_debug"))] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } + + #[cfg(feature = "test_debug")] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Let the inner `IndexMap` print all of its details + f.debug_struct("IndexSet").field("map", &self.map).finish() + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl IndexSet { + /// Create a new set. (Does not allocate.) + pub fn new() -> Self { + IndexSet { + map: IndexMap::new(), + } + } + + /// Create a new set with capacity for `n` elements. + /// (Does not allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + pub fn with_capacity(n: usize) -> Self { + IndexSet { + map: IndexMap::with_capacity(n), + } + } +} + +impl IndexSet { + /// Create a new set with capacity for `n` elements. + /// (Does not allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self { + IndexSet { + map: IndexMap::with_capacity_and_hasher(n, hash_builder), + } + } + + /// Create a new set with `hash_builder`. + /// + /// This function is `const`, so it + /// can be called in `static` contexts. + pub const fn with_hasher(hash_builder: S) -> Self { + IndexSet { + map: IndexMap::with_hasher(hash_builder), + } + } + + #[inline] + pub(crate) fn into_entries(self) -> Vec> { + self.map.into_entries() + } + + #[inline] + pub(crate) fn as_entries(&self) -> &[Bucket] { + self.map.as_entries() + } + + pub(crate) fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Bucket]), + { + self.map.with_entries(f); + } + + /// Return the number of elements the set can hold without reallocating. + /// + /// This number is a lower bound; the set might be able to hold more, + /// but is guaranteed to be able to hold at least this many. + /// + /// Computes in **O(1)** time. + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// Return a reference to the set's `BuildHasher`. + pub fn hasher(&self) -> &S { + self.map.hasher() + } + + /// Return the number of elements in the set. + /// + /// Computes in **O(1)** time. + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns true if the set contains no elements. + /// + /// Computes in **O(1)** time. + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Return an iterator over the values of the set, in their order + pub fn iter(&self) -> Iter<'_, T> { + Iter::new(self.as_entries()) + } + + /// Remove all elements in the set, while preserving its capacity. + /// + /// Computes in **O(n)** time. + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Shortens the set, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the set's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.map.truncate(len); + } + + /// Clears the `IndexSet` in the given index range, returning those values + /// as a drain iterator. + /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To drain the set entirely, use `RangeFull` + /// like `set.drain(..)`. + /// + /// This shifts down all entries following the drained range to fill the + /// gap, and keeps the allocated memory for reuse. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + #[track_caller] + pub fn drain(&mut self, range: R) -> Drain<'_, T> + where + R: RangeBounds, + { + Drain::new(self.map.core.drain(range)) + } + + /// Creates an iterator which uses a closure to determine if a value should be removed, + /// for all values in the given range. + /// + /// If the closure returns true, then the value is removed and yielded. + /// If the closure returns false, the value will remain in the list and will not be yielded + /// by the iterator. + /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To check the entire set, use `RangeFull` + /// like `set.extract_if(.., predicate)`. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain`]: IndexSet::retain + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut set: IndexSet = (0..8).collect(); + /// let extracted: IndexSet = set.extract_if(.., |v| v % 2 == 0).collect(); + /// + /// let evens = extracted.into_iter().collect::>(); + /// let odds = set.into_iter().collect::>(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[track_caller] + pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, T, F> + where + F: FnMut(&T) -> bool, + R: RangeBounds, + { + ExtractIf::new(&mut self.map.core, range, pred) + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated set containing the elements in the range + /// `[at, len)`. After the call, the original set will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + #[track_caller] + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + map: self.map.split_off(at), + } + } + + /// Reserve capacity for `additional` more values. + /// + /// Computes in **O(n)** time. + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Reserve capacity for `additional` more values, without over-allocating. + /// + /// Unlike `reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn reserve_exact(&mut self, additional: usize) { + self.map.reserve_exact(additional); + } + + /// Try to reserve capacity for `additional` more values. + /// + /// Computes in **O(n)** time. + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Try to reserve capacity for `additional` more values, without over-allocating. + /// + /// Unlike `try_reserve`, this does not deliberately over-allocate the entry capacity to avoid + /// frequent re-allocations. However, the underlying data structures may still have internal + /// capacity requirements, and the allocator itself may give more space than requested, so this + /// cannot be relied upon to be precisely minimal. + /// + /// Computes in **O(n)** time. + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve_exact(additional) + } + + /// Shrink the capacity of the set as much as possible. + /// + /// Computes in **O(n)** time. + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Shrink the capacity of the set with a lower limit. + /// + /// Computes in **O(n)** time. + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } +} + +impl IndexSet +where + T: Hash + Eq, + S: BuildHasher, +{ + /// Insert the value into the set. + /// + /// If an equivalent item already exists in the set, it returns + /// `false` leaving the original value in the set and without + /// altering its insertion order. Otherwise, it inserts the new + /// item and returns `true`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert the value into the set, and get its index. + /// + /// If an equivalent item already exists in the set, it returns + /// the index of the existing item and `false`, leaving the + /// original value in the set and without altering its insertion + /// order. Otherwise, it inserts the new item and returns the index + /// of the inserted item and `true`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert_full(&mut self, value: T) -> (usize, bool) { + let (index, existing) = self.map.insert_full(value, ()); + (index, existing.is_none()) + } + + /// Insert the value into the set at its ordered position among sorted values. + /// + /// This is equivalent to finding the position with + /// [`binary_search`][Self::binary_search], and if needed calling + /// [`insert_before`][Self::insert_before] for a new value. + /// + /// If the sorted item is found in the set, it returns the index of that + /// existing item and `false`, without any change. Otherwise, it inserts the + /// new item and returns its sorted index and `true`. + /// + /// If the existing items are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the value + /// is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). Instead of repeating calls to + /// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert] + /// or [`extend`][Self::extend] and only call [`sort`][Self::sort] or + /// [`sort_unstable`][Self::sort_unstable] once. + pub fn insert_sorted(&mut self, value: T) -> (usize, bool) + where + T: Ord, + { + let (index, existing) = self.map.insert_sorted(value, ()); + (index, existing.is_none()) + } + + /// Insert the value into the set at its ordered position among values + /// sorted by `cmp`. + /// + /// This is equivalent to finding the position with + /// [`binary_search_by`][Self::binary_search_by], then calling + /// [`insert_before`][Self::insert_before]. + /// + /// If the existing items are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the value + /// is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by(&mut self, value: T, mut cmp: F) -> (usize, bool) + where + F: FnMut(&T, &T) -> Ordering, + { + let (index, existing) = self + .map + .insert_sorted_by(value, (), |a, (), b, ()| cmp(a, b)); + (index, existing.is_none()) + } + + /// Insert the value into the set at its ordered position among values + /// using a sort-key extraction function. + /// + /// This is equivalent to finding the position with + /// [`binary_search_by_key`][Self::binary_search_by_key] with `sort_key(key)`, + /// then calling [`insert_before`][Self::insert_before]. + /// + /// If the existing items are **not** already sorted, then the insertion + /// index is unspecified (like [`slice::binary_search`]), but the value + /// is moved to or inserted at that position regardless. + /// + /// Computes in **O(n)** time (average). + pub fn insert_sorted_by_key(&mut self, value: T, mut sort_key: F) -> (usize, bool) + where + B: Ord, + F: FnMut(&T) -> B, + { + let (index, existing) = self.map.insert_sorted_by_key(value, (), |k, _| sort_key(k)); + (index, existing.is_none()) + } + + /// Insert the value into the set before the value at the given index, or at the end. + /// + /// If an equivalent item already exists in the set, it returns `false` leaving the + /// original value in the set, but moved to the new position. The returned index + /// will either be the given index or one less, depending on how the value moved. + /// (See [`shift_insert`](Self::shift_insert) for different behavior here.) + /// + /// Otherwise, it inserts the new value exactly at the given index and returns `true`. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..=set.len()` (inclusive). + /// + /// Computes in **O(n)** time (average). + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// let mut set: IndexSet = ('a'..='z').collect(); + /// + /// // The new value '*' goes exactly at the given index. + /// assert_eq!(set.get_index_of(&'*'), None); + /// assert_eq!(set.insert_before(10, '*'), (10, true)); + /// assert_eq!(set.get_index_of(&'*'), Some(10)); + /// + /// // Moving the value 'a' up will shift others down, so this moves *before* 10 to index 9. + /// assert_eq!(set.insert_before(10, 'a'), (9, false)); + /// assert_eq!(set.get_index_of(&'a'), Some(9)); + /// assert_eq!(set.get_index_of(&'*'), Some(10)); + /// + /// // Moving the value 'z' down will shift others up, so this moves to exactly 10. + /// assert_eq!(set.insert_before(10, 'z'), (10, false)); + /// assert_eq!(set.get_index_of(&'z'), Some(10)); + /// assert_eq!(set.get_index_of(&'*'), Some(11)); + /// + /// // Moving or inserting before the endpoint is also valid. + /// assert_eq!(set.len(), 27); + /// assert_eq!(set.insert_before(set.len(), '*'), (26, false)); + /// assert_eq!(set.get_index_of(&'*'), Some(26)); + /// assert_eq!(set.insert_before(set.len(), '+'), (27, true)); + /// assert_eq!(set.get_index_of(&'+'), Some(27)); + /// assert_eq!(set.len(), 28); + /// ``` + #[track_caller] + pub fn insert_before(&mut self, index: usize, value: T) -> (usize, bool) { + let (index, existing) = self.map.insert_before(index, value, ()); + (index, existing.is_none()) + } + + /// Insert the value into the set at the given index. + /// + /// If an equivalent item already exists in the set, it returns `false` leaving + /// the original value in the set, but moved to the given index. + /// Note that existing values **cannot** be moved to `index == set.len()`! + /// (See [`insert_before`](Self::insert_before) for different behavior here.) + /// + /// Otherwise, it inserts the new value at the given index and returns `true`. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..set.len()` (exclusive) when moving an existing value, or + /// `0..=set.len()` (inclusive) when inserting a new value. + /// + /// Computes in **O(n)** time (average). + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// let mut set: IndexSet = ('a'..='z').collect(); + /// + /// // The new value '*' goes exactly at the given index. + /// assert_eq!(set.get_index_of(&'*'), None); + /// assert_eq!(set.shift_insert(10, '*'), true); + /// assert_eq!(set.get_index_of(&'*'), Some(10)); + /// + /// // Moving the value 'a' up to 10 will shift others down, including the '*' that was at 10. + /// assert_eq!(set.shift_insert(10, 'a'), false); + /// assert_eq!(set.get_index_of(&'a'), Some(10)); + /// assert_eq!(set.get_index_of(&'*'), Some(9)); + /// + /// // Moving the value 'z' down to 9 will shift others up, including the '*' that was at 9. + /// assert_eq!(set.shift_insert(9, 'z'), false); + /// assert_eq!(set.get_index_of(&'z'), Some(9)); + /// assert_eq!(set.get_index_of(&'*'), Some(10)); + /// + /// // Existing values can move to len-1 at most, but new values can insert at the endpoint. + /// assert_eq!(set.len(), 27); + /// assert_eq!(set.shift_insert(set.len() - 1, '*'), false); + /// assert_eq!(set.get_index_of(&'*'), Some(26)); + /// assert_eq!(set.shift_insert(set.len(), '+'), true); + /// assert_eq!(set.get_index_of(&'+'), Some(27)); + /// assert_eq!(set.len(), 28); + /// ``` + /// + /// ```should_panic + /// use indexmap::IndexSet; + /// let mut set: IndexSet = ('a'..='z').collect(); + /// + /// // This is an invalid index for moving an existing value! + /// set.shift_insert(set.len(), 'a'); + /// ``` + #[track_caller] + pub fn shift_insert(&mut self, index: usize, value: T) -> bool { + self.map.shift_insert(index, value, ()).is_none() + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace(&mut self, value: T) -> Option { + self.replace_full(value).1 + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the index of the item and its replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace_full(&mut self, value: T) -> (usize, Option) { + let hash = self.map.hash(&value); + match self.map.core.replace_full(hash, value, ()) { + (i, Some((replaced, ()))) => (i, Some(replaced)), + (i, None) => (i, None), + } + } + + /// Replaces the value at the given index. The new value does not need to be + /// equivalent to the one it is replacing, but it must be unique to the rest + /// of the set. + /// + /// Returns `Ok(old_value)` if successful, or `Err((other_index, value))` if + /// an equivalent value already exists at a different index. The set will be + /// unchanged in the error case. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn replace_index(&mut self, index: usize, value: T) -> Result { + self.map.replace_index(index, value) + } + + /// Return an iterator over the values that are in `self` but not `other`. + /// + /// Values are produced in the same order that they appear in `self`. + pub fn difference<'a, S2>(&'a self, other: &'a IndexSet) -> Difference<'a, T, S2> + where + S2: BuildHasher, + { + Difference::new(self, other) + } + + /// Return an iterator over the values that are in `self` or `other`, + /// but not in both. + /// + /// Values from `self` are produced in their original order, followed by + /// values from `other` in their original order. + pub fn symmetric_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> SymmetricDifference<'a, T, S, S2> + where + S2: BuildHasher, + { + SymmetricDifference::new(self, other) + } + + /// Return an iterator over the values that are in both `self` and `other`. + /// + /// Values are produced in the same order that they appear in `self`. + pub fn intersection<'a, S2>(&'a self, other: &'a IndexSet) -> Intersection<'a, T, S2> + where + S2: BuildHasher, + { + Intersection::new(self, other) + } + + /// Return an iterator over all values that are in `self` or `other`. + /// + /// Values from `self` are produced in their original order, followed by + /// values that are unique to `other` in their original order. + pub fn union<'a, S2>(&'a self, other: &'a IndexSet) -> Union<'a, T, S> + where + S2: BuildHasher, + { + Union::new(self, other) + } + + /// Creates a splicing iterator that replaces the specified range in the set + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// The `range` is removed even if the iterator is not consumed until the + /// end. It is unspecified how many elements are removed from the set if the + /// `Splice` value is leaked. + /// + /// The input iterator `replace_with` is only consumed when the `Splice` + /// value is dropped. If a value from the iterator matches an existing entry + /// in the set (outside of `range`), then the original will be unchanged. + /// Otherwise, the new value will be inserted in the replaced `range`. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut set = IndexSet::from([0, 1, 2, 3, 4]); + /// let new = [5, 4, 3, 2, 1]; + /// let removed: Vec<_> = set.splice(2..4, new).collect(); + /// + /// // 1 and 4 kept their positions, while 5, 3, and 2 were newly inserted. + /// assert!(set.into_iter().eq([0, 1, 5, 3, 2, 4])); + /// assert_eq!(removed, &[2, 3]); + /// ``` + #[track_caller] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, T, S> + where + R: RangeBounds, + I: IntoIterator, + { + Splice::new(self, range, replace_with.into_iter()) + } + + /// Moves all values from `other` into `self`, leaving `other` empty. + /// + /// This is equivalent to calling [`insert`][Self::insert] for each value + /// from `other` in order, which means that values that already exist + /// in `self` are unchanged in their current position. + /// + /// See also [`union`][Self::union] to iterate the combined values by + /// reference, without modifying `self` or `other`. + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut a = IndexSet::from([3, 2, 1]); + /// let mut b = IndexSet::from([3, 4, 5]); + /// let old_capacity = b.capacity(); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 5); + /// assert_eq!(b.len(), 0); + /// assert_eq!(b.capacity(), old_capacity); + /// + /// assert!(a.iter().eq(&[3, 2, 1, 4, 5])); + /// ``` + pub fn append(&mut self, other: &mut IndexSet) { + self.map.append(&mut other.map); + } +} + +impl IndexSet +where + S: BuildHasher, +{ + /// Return `true` if an equivalent to `value` exists in the set. + /// + /// Computes in **O(1)** time (average). + pub fn contains(&self, value: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.map.contains_key(value) + } + + /// Return a reference to the value stored in the set, if it is present, + /// else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: ?Sized + Hash + Equivalent, + { + self.map.get_key_value(value).map(|(x, &())| x) + } + + /// Return item index and value + pub fn get_full(&self, value: &Q) -> Option<(usize, &T)> + where + Q: ?Sized + Hash + Equivalent, + { + self.map.get_full(value).map(|(i, x, &())| (i, x)) + } + + /// Return item index, if it exists in the set + /// + /// Computes in **O(1)** time (average). + pub fn get_index_of(&self, value: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.map.get_index_of(value) + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// **NOTE:** This is equivalent to [`.swap_remove(value)`][Self::swap_remove], replacing this + /// value's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the values in the set, use + /// [`.shift_remove(value)`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the set order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(&mut self, value: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.swap_remove(value) + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `false` if `value` was not in the set. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(&mut self, value: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.map.swap_remove(value).is_some() + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// Like [`Vec::remove`], the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `false` if `value` was not in the set. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(&mut self, value: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.map.shift_remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// **NOTE:** This is equivalent to [`.swap_take(value)`][Self::swap_take], replacing this + /// value's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the values in the set, use + /// [`.shift_take(value)`][Self::shift_take] instead. + #[deprecated(note = "`take` disrupts the set order -- \ + use `swap_take` or `shift_take` for explicit behavior.")] + pub fn take(&mut self, value: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.swap_take(value) + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `value` was not in the set. + /// + /// Computes in **O(1)** time (average). + pub fn swap_take(&mut self, value: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.map.swap_remove_entry(value).map(|(x, ())| x) + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// Like [`Vec::remove`], the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `value` was not in the set. + /// + /// Computes in **O(n)** time (average). + pub fn shift_take(&mut self, value: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.map.shift_remove_entry(value).map(|(x, ())| x) + } + + /// Remove the value from the set return it and the index it had. + /// + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `value` was not in the set. + pub fn swap_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + where + Q: ?Sized + Hash + Equivalent, + { + self.map.swap_remove_full(value).map(|(i, x, ())| (i, x)) + } + + /// Remove the value from the set return it and the index it had. + /// + /// Like [`Vec::remove`], the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `value` was not in the set. + pub fn shift_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + where + Q: ?Sized + Hash + Equivalent, + { + self.map.shift_remove_full(value).map(|(i, x, ())| (i, x)) + } +} + +impl IndexSet { + /// Remove the last value + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + #[doc(alias = "pop_last")] // like `BTreeSet` + pub fn pop(&mut self) -> Option { + self.map.pop().map(|(x, ())| x) + } + + /// Removes and returns the last value from a set if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the set + /// is empty (the predicate will not be called in that case). + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + /// + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut set = IndexSet::from([1, 2, 3, 4]); + /// let pred = |x: &i32| *x % 2 == 0; + /// + /// assert_eq!(set.pop_if(pred), Some(4)); + /// assert_eq!(set.as_slice(), &[1, 2, 3]); + /// assert_eq!(set.pop_if(pred), None); + /// ``` + pub fn pop_if(&mut self, predicate: impl FnOnce(&T) -> bool) -> Option { + let last = self.last()?; + if predicate(last) { self.pop() } else { None } + } + + /// Scan through each value in the set and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(move |x, &mut ()| keep(x)) + } + + /// Sort the set's values by their default ordering. + /// + /// This is a stable sort -- but equivalent values should not normally coexist in + /// a set at all, so [`sort_unstable`][Self::sort_unstable] is preferred + /// because it is generally faster and doesn't allocate auxiliary memory. + /// + /// See [`sort_by`](Self::sort_by) for details. + pub fn sort(&mut self) + where + T: Ord, + { + self.map.sort_keys() + } + + /// Sort the set's values in place using the comparison function `cmp`. + /// + /// Computes in **O(n log n)** time and **O(n)** space. The sort is stable. + pub fn sort_by(&mut self, mut cmp: F) + where + F: FnMut(&T, &T) -> Ordering, + { + self.map.sort_by(move |a, (), b, ()| cmp(a, b)); + } + + /// Sort the values of the set and return a by-value iterator of + /// the values with the result. + /// + /// The sort is stable. + pub fn sorted_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&T, &T) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_by(move |a, b| cmp(&a.key, &b.key)); + IntoIter::new(entries) + } + + /// Sort the set's values in place using a key extraction function. + /// + /// Computes in **O(n log n)** time and **O(n)** space. The sort is stable. + pub fn sort_by_key(&mut self, mut sort_key: F) + where + K: Ord, + F: FnMut(&T) -> K, + { + self.with_entries(move |entries| { + entries.sort_by_key(move |a| sort_key(&a.key)); + }); + } + + /// Sort the set's values by their default ordering. + /// + /// See [`sort_unstable_by`](Self::sort_unstable_by) for details. + pub fn sort_unstable(&mut self) + where + T: Ord, + { + self.map.sort_unstable_keys() + } + + /// Sort the set's values in place using the comparison function `cmp`. + /// + /// Computes in **O(n log n)** time. The sort is unstable. + pub fn sort_unstable_by(&mut self, mut cmp: F) + where + F: FnMut(&T, &T) -> Ordering, + { + self.map.sort_unstable_by(move |a, _, b, _| cmp(a, b)) + } + + /// Sort the values of the set and return a by-value iterator of + /// the values with the result. + pub fn sorted_unstable_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&T, &T) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); + IntoIter::new(entries) + } + + /// Sort the set's values in place using a key extraction function. + /// + /// Computes in **O(n log n)** time. The sort is unstable. + pub fn sort_unstable_by_key(&mut self, mut sort_key: F) + where + K: Ord, + F: FnMut(&T) -> K, + { + self.with_entries(move |entries| { + entries.sort_unstable_by_key(move |a| sort_key(&a.key)); + }); + } + + /// Sort the set's values in place using a key extraction function. + /// + /// During sorting, the function is called at most once per entry, by using temporary storage + /// to remember the results of its evaluation. The order of calls to the function is + /// unspecified and may change between versions of `indexmap` or the standard library. + /// + /// Computes in **O(m n + n log n + c)** time () and **O(n)** space, where the function is + /// **O(m)**, *n* is the length of the map, and *c* the capacity. The sort is stable. + pub fn sort_by_cached_key(&mut self, mut sort_key: F) + where + K: Ord, + F: FnMut(&T) -> K, + { + self.with_entries(move |entries| { + entries.sort_by_cached_key(move |a| sort_key(&a.key)); + }); + } + + /// Search over a sorted set for a value. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the value up + /// using [`get_index_of`][IndexSet::get_index_of], but this can also position missing values. + pub fn binary_search(&self, x: &T) -> Result + where + T: Ord, + { + self.as_slice().binary_search(x) + } + + /// Search over a sorted set with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + where + F: FnMut(&'a T) -> Ordering, + { + self.as_slice().binary_search_by(f) + } + + /// Search over a sorted set with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.as_slice().binary_search_by_key(b, f) + } + + /// Checks if the values of this set are sorted. + #[inline] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + self.as_slice().is_sorted() + } + + /// Checks if this set is sorted using the given comparator function. + #[inline] + pub fn is_sorted_by<'a, F>(&'a self, cmp: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.as_slice().is_sorted_by(cmp) + } + + /// Checks if this set is sorted using the given sort-key function. + #[inline] + pub fn is_sorted_by_key<'a, F, K>(&'a self, sort_key: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.as_slice().is_sorted_by_key(sort_key) + } + + /// Returns the index of the partition point of a sorted set according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + self.as_slice().partition_point(pred) + } + + /// Reverses the order of the set's values in place. + /// + /// Computes in **O(n)** time and **O(1)** space. + pub fn reverse(&mut self) { + self.map.reverse() + } + + /// Returns a slice of all the values in the set. + /// + /// Computes in **O(1)** time. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.as_entries()) + } + + /// Converts into a boxed slice of all the values in the set. + /// + /// Note that this will drop the inner hash table and any excess capacity. + pub fn into_boxed_slice(self) -> Box> { + Slice::from_boxed(self.into_entries().into_boxed_slice()) + } + + /// Get a value by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_index(&self, index: usize) -> Option<&T> { + self.as_entries().get(index).map(Bucket::key_ref) + } + + /// Returns a slice of values in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + let entries = self.as_entries(); + let range = try_simplify_range(range, entries.len())?; + entries.get(range).map(Slice::from_slice) + } + + /// Get the first value + /// + /// Computes in **O(1)** time. + pub fn first(&self) -> Option<&T> { + self.as_entries().first().map(Bucket::key_ref) + } + + /// Get the last value + /// + /// Computes in **O(1)** time. + pub fn last(&self) -> Option<&T> { + self.as_entries().last().map(Bucket::key_ref) + } + + /// Remove the value by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Like [`Vec::swap_remove`], the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_index(&mut self, index: usize) -> Option { + self.map.swap_remove_index(index).map(|(x, ())| x) + } + + /// Remove the value by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Like [`Vec::remove`], the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_index(&mut self, index: usize) -> Option { + self.map.shift_remove_index(index).map(|(x, ())| x) + } + + /// Moves the position of a value from one index to another + /// by shifting all other values in-between. + /// + /// * If `from < to`, the other values will shift down while the targeted value moves up. + /// * If `from > to`, the other values will shift up while the targeted value moves down. + /// + /// ***Panics*** if `from` or `to` are out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn move_index(&mut self, from: usize, to: usize) { + self.map.move_index(from, to) + } + + /// Swaps the position of two values in the set. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.map.swap_indices(a, b) + } +} + +/// Access [`IndexSet`] values at indexed positions. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexSet; +/// +/// let mut set = IndexSet::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// set.insert(word.to_string()); +/// } +/// assert_eq!(set[0], "Lorem"); +/// assert_eq!(set[1], "ipsum"); +/// set.reverse(); +/// assert_eq!(set[0], "amet"); +/// assert_eq!(set[1], "sit"); +/// set.sort(); +/// assert_eq!(set[0], "Lorem"); +/// assert_eq!(set[1], "amet"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexSet; +/// +/// let mut set = IndexSet::new(); +/// set.insert("foo"); +/// println!("{:?}", set[10]); // panics! +/// ``` +impl Index for IndexSet { + type Output = T; + + /// Returns a reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &T { + if let Some(value) = self.get_index(index) { + value + } else { + panic!( + "index out of bounds: the len is {len} but the index is {index}", + len = self.len() + ); + } + } +} + +impl FromIterator for IndexSet +where + T: Hash + Eq, + S: BuildHasher + Default, +{ + fn from_iter>(iterable: I) -> Self { + let iter = iterable.into_iter().map(|x| (x, ())); + IndexSet { + map: IndexMap::from_iter(iter), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl From<[T; N]> for IndexSet +where + T: Eq + Hash, +{ + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let set1 = IndexSet::from([1, 2, 3, 4]); + /// let set2: IndexSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + Self::from_iter(arr) + } +} + +impl Extend for IndexSet +where + T: Hash + Eq, + S: BuildHasher, +{ + fn extend>(&mut self, iterable: I) { + let iter = iterable.into_iter().map(|x| (x, ())); + self.map.extend(iter); + } +} + +impl<'a, T, S> Extend<&'a T> for IndexSet +where + T: Hash + Eq + Copy + 'a, + S: BuildHasher, +{ + fn extend>(&mut self, iterable: I) { + let iter = iterable.into_iter().copied(); + self.extend(iter); + } +} + +impl Default for IndexSet +where + S: Default, +{ + /// Return an empty [`IndexSet`] + fn default() -> Self { + IndexSet { + map: IndexMap::default(), + } + } +} + +impl PartialEq> for IndexSet +where + T: Hash + Eq, + S1: BuildHasher, + S2: BuildHasher, +{ + fn eq(&self, other: &IndexSet) -> bool { + self.len() == other.len() && self.is_subset(other) + } +} + +impl Eq for IndexSet +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl IndexSet +where + T: Eq + Hash, + S: BuildHasher, +{ + /// Returns `true` if `self` has no elements in common with `other`. + pub fn is_disjoint(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + if self.len() <= other.len() { + self.iter().all(move |value| !other.contains(value)) + } else { + other.iter().all(move |value| !self.contains(value)) + } + } + + /// Returns `true` if all elements of `self` are contained in `other`. + pub fn is_subset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + self.len() <= other.len() && self.iter().all(move |value| other.contains(value)) + } + + /// Returns `true` if all elements of `other` are contained in `self`. + pub fn is_superset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + other.is_subset(self) + } +} + +impl BitAnd<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set intersection, cloned into a new set. + /// + /// Values are collected in the same order that they appear in `self`. + fn bitand(self, other: &IndexSet) -> Self::Output { + self.intersection(other).cloned().collect() + } +} + +impl BitOr<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set union, cloned into a new set. + /// + /// Values from `self` are collected in their original order, followed by + /// values that are unique to `other` in their original order. + fn bitor(self, other: &IndexSet) -> Self::Output { + self.union(other).cloned().collect() + } +} + +impl BitXor<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set symmetric-difference, cloned into a new set. + /// + /// Values from `self` are collected in their original order, followed by + /// values from `other` in their original order. + fn bitxor(self, other: &IndexSet) -> Self::Output { + self.symmetric_difference(other).cloned().collect() + } +} + +impl Sub<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set difference, cloned into a new set. + /// + /// Values are collected in the same order that they appear in `self`. + fn sub(self, other: &IndexSet) -> Self::Output { + self.difference(other).cloned().collect() + } +} diff --git a/deps/crates/vendor/indexmap/src/set/iter.rs b/deps/crates/vendor/indexmap/src/set/iter.rs new file mode 100644 index 00000000000000..08c2baef1dc7fb --- /dev/null +++ b/deps/crates/vendor/indexmap/src/set/iter.rs @@ -0,0 +1,680 @@ +use super::{Bucket, IndexSet, Slice}; +use crate::inner::{Core, ExtractCore}; + +use alloc::vec::{self, Vec}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::RangeBounds; +use core::slice::Iter as SliceIter; + +impl<'a, T, S> IntoIterator for &'a IndexSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for IndexSet { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +/// An iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::iter`] method. +/// See its documentation for more. +pub struct Iter<'a, T> { + iter: SliceIter<'a, Bucket>, +} + +impl<'a, T> Iter<'a, T> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &'a Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Iter<'_, T> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Iter<'_, T> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// An owning iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::into_iter`] method +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +#[derive(Clone)] +pub struct IntoIter { + iter: vec::IntoIter>, +} + +impl IntoIter { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for IntoIter { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoIter { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A draining iterator over the items of an [`IndexSet`]. +/// +/// This `struct` is created by the [`IndexSet::drain`] method. +/// See its documentation for more. +pub struct Drain<'a, T> { + iter: vec::Drain<'a, Bucket>, +} + +impl<'a, T> Drain<'a, T> { + pub(super) fn new(iter: vec::Drain<'a, Bucket>) -> Self { + Self { iter } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for Drain<'_, T> { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for Drain<'_, T> { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for Drain<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, T> {} + +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +/// A lazy iterator producing elements in the difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::difference`] method. +/// See its documentation for more. +pub struct Difference<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Difference<'a, T, S> { + pub(super) fn new(set: &'a IndexSet, other: &'a IndexSet) -> Self { + Self { + iter: set.iter(), + other, + } + } +} + +impl<'a, T, S> Iterator for Difference<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Difference<'_, T, S> { + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Difference<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the intersection of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::intersection`] method. +/// See its documentation for more. +pub struct Intersection<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Intersection<'a, T, S> { + pub(super) fn new(set: &'a IndexSet, other: &'a IndexSet) -> Self { + Self { + iter: set.iter(), + other, + } + } +} + +impl<'a, T, S> Iterator for Intersection<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Intersection<'_, T, S> { + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Intersection<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the symmetric difference of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::symmetric_difference`] method. +/// See its documentation for more. +pub struct SymmetricDifference<'a, T, S1, S2> { + iter: Chain, Difference<'a, T, S1>>, +} + +impl<'a, T, S1, S2> SymmetricDifference<'a, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + pub(super) fn new(set1: &'a IndexSet, set2: &'a IndexSet) -> Self { + let diff1 = set1.difference(set2); + let diff2 = set2.difference(set1); + Self { + iter: diff1.chain(diff2), + } + } +} + +impl<'a, T, S1, S2> Iterator for SymmetricDifference<'a, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ +} + +impl Clone for SymmetricDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for SymmetricDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the union of [`IndexSet`]s. +/// +/// This `struct` is created by the [`IndexSet::union`] method. +/// See its documentation for more. +pub struct Union<'a, T, S> { + iter: Chain, Difference<'a, T, S>>, +} + +impl<'a, T, S> Union<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + pub(super) fn new(set1: &'a IndexSet, set2: &'a IndexSet) -> Self + where + S2: BuildHasher, + { + Self { + iter: set1.iter().chain(set2.difference(set1)), + } + } +} + +impl<'a, T, S> Iterator for Union<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Union<'_, T, S> { + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Union<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A splicing iterator for `IndexSet`. +/// +/// This `struct` is created by [`IndexSet::splice()`]. +/// See its documentation for more. +pub struct Splice<'a, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + iter: crate::map::Splice<'a, UnitValue, T, (), S>, +} + +impl<'a, I, T, S> Splice<'a, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + #[track_caller] + pub(super) fn new(set: &'a mut IndexSet, range: R, replace_with: I) -> Self + where + R: RangeBounds, + { + Self { + iter: set.map.splice(range, UnitValue(replace_with)), + } + } +} + +impl Iterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + type Item = T; + + fn next(&mut self) -> Option { + Some(self.iter.next()?.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + Some(self.iter.next_back()?.0) + } +} + +impl ExactSizeIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Splice<'_, I, T, S> +where + I: Iterator, + T: Hash + Eq, + S: BuildHasher, +{ +} + +struct UnitValue(I); + +impl Iterator for UnitValue { + type Item = (I::Item, ()); + + fn next(&mut self) -> Option { + self.0.next().map(|x| (x, ())) + } +} + +impl fmt::Debug for Splice<'_, I, T, S> +where + I: fmt::Debug + Iterator, + T: fmt::Debug + Hash + Eq, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.iter, f) + } +} + +impl fmt::Debug for UnitValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +/// An extracting iterator for `IndexSet`. +/// +/// This `struct` is created by [`IndexSet::extract_if()`]. +/// See its documentation for more. +pub struct ExtractIf<'a, T, F> { + inner: ExtractCore<'a, T, ()>, + pred: F, +} + +impl ExtractIf<'_, T, F> { + #[track_caller] + pub(super) fn new(core: &mut Core, range: R, pred: F) -> ExtractIf<'_, T, F> + where + R: RangeBounds, + F: FnMut(&T) -> bool, + { + ExtractIf { + inner: core.extract(range), + pred, + } + } +} + +impl Iterator for ExtractIf<'_, T, F> +where + F: FnMut(&T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner + .extract_if(|bucket| (self.pred)(bucket.key_ref())) + .map(Bucket::key) + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.inner.remaining())) + } +} + +impl FusedIterator for ExtractIf<'_, T, F> where F: FnMut(&T) -> bool {} + +impl fmt::Debug for ExtractIf<'_, T, F> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} diff --git a/deps/crates/vendor/indexmap/src/set/mutable.rs b/deps/crates/vendor/indexmap/src/set/mutable.rs new file mode 100644 index 00000000000000..b555f9ae96d866 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/set/mutable.rs @@ -0,0 +1,85 @@ +use core::hash::{BuildHasher, Hash}; + +use super::{Equivalent, IndexSet}; +use crate::map::MutableKeys; + +/// Opt-in mutable access to [`IndexSet`] values. +/// +/// These methods expose `&mut T`, mutable references to the value as it is stored +/// in the set. +/// You are allowed to modify the values in the set **if the modification +/// does not change the value's hash and equality**. +/// +/// If values are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `IndexSet`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +#[expect(private_bounds)] +pub trait MutableValues: Sealed { + type Value; + + /// Return item index and mutable reference to the value + /// + /// Computes in **O(1)** time (average). + fn get_full_mut2(&mut self, value: &Q) -> Option<(usize, &mut Self::Value)> + where + Q: ?Sized + Hash + Equivalent; + + /// Return mutable reference to the value at an index. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + fn get_index_mut2(&mut self, index: usize) -> Option<&mut Self::Value>; + + /// Scan through each value in the set and keep those where the + /// closure `keep` returns `true`. + /// + /// The values are visited in order, and remaining values keep their order. + /// + /// Computes in **O(n)** time (average). + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut Self::Value) -> bool; +} + +/// Opt-in mutable access to [`IndexSet`] values. +/// +/// See [`MutableValues`] for more information. +impl MutableValues for IndexSet +where + S: BuildHasher, +{ + type Value = T; + + fn get_full_mut2(&mut self, value: &Q) -> Option<(usize, &mut T)> + where + Q: ?Sized + Hash + Equivalent, + { + match self.map.get_full_mut2(value) { + Some((index, value, ())) => Some((index, value)), + None => None, + } + } + + fn get_index_mut2(&mut self, index: usize) -> Option<&mut T> { + match self.map.get_index_mut2(index) { + Some((value, ())) => Some(value), + None => None, + } + } + + fn retain2(&mut self, mut keep: F) + where + F: FnMut(&mut T) -> bool, + { + self.map.retain2(move |value, ()| keep(value)); + } +} + +trait Sealed {} + +impl Sealed for IndexSet {} diff --git a/deps/crates/vendor/indexmap/src/set/slice.rs b/deps/crates/vendor/indexmap/src/set/slice.rs new file mode 100644 index 00000000000000..857e06d9abd2d2 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/set/slice.rs @@ -0,0 +1,428 @@ +use super::{Bucket, IndexSet, IntoIter, Iter}; +use crate::util::{slice_eq, try_simplify_range}; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{self, Bound, Index, RangeBounds}; + +/// A dynamically-sized slice of values in an [`IndexSet`]. +/// +/// This supports indexed operations much like a `[T]` slice, +/// but not any hashed operations on the values. +/// +/// Unlike `IndexSet`, `Slice` does consider the order for [`PartialEq`] +/// and [`Eq`], and it also implements [`PartialOrd`], [`Ord`], and [`Hash`]. +#[repr(transparent)] +pub struct Slice { + pub(crate) entries: [Bucket], +} + +// SAFETY: `Slice` is a transparent wrapper around `[Bucket]`, +// and reference lifetimes are bound together in function signatures. +#[allow(unsafe_code)] +impl Slice { + pub(super) const fn from_slice(entries: &[Bucket]) -> &Self { + unsafe { &*(entries as *const [Bucket] as *const Self) } + } + + pub(super) fn from_boxed(entries: Box<[Bucket]>) -> Box { + unsafe { Box::from_raw(Box::into_raw(entries) as *mut Self) } + } + + fn into_boxed(self: Box) -> Box<[Bucket]> { + unsafe { Box::from_raw(Box::into_raw(self) as *mut [Bucket]) } + } +} + +impl Slice { + pub(crate) fn into_entries(self: Box) -> Vec> { + self.into_boxed().into_vec() + } + + /// Returns an empty slice. + pub const fn new<'a>() -> &'a Self { + Self::from_slice(&[]) + } + + /// Return the number of elements in the set slice. + pub const fn len(&self) -> usize { + self.entries.len() + } + + /// Returns true if the set slice contains no elements. + pub const fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + /// Get a value by index. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_index(&self, index: usize) -> Option<&T> { + self.entries.get(index).map(Bucket::key_ref) + } + + /// Returns a slice of values in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range>(&self, range: R) -> Option<&Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get(range).map(Self::from_slice) + } + + /// Get the first value. + pub const fn first(&self) -> Option<&T> { + if let [first, ..] = &self.entries { + Some(&first.key) + } else { + None + } + } + + /// Get the last value. + pub const fn last(&self) -> Option<&T> { + if let [.., last] = &self.entries { + Some(&last.key) + } else { + None + } + } + + /// Divides one slice into two at an index. + /// + /// ***Panics*** if `index > len`. + /// For a non-panicking alternative see [`split_at_checked`][Self::split_at_checked]. + #[track_caller] + pub const fn split_at(&self, index: usize) -> (&Self, &Self) { + let (first, second) = self.entries.split_at(index); + (Self::from_slice(first), Self::from_slice(second)) + } + + /// Divides one slice into two at an index. + /// + /// Returns `None` if `index > len`. + pub const fn split_at_checked(&self, index: usize) -> Option<(&Self, &Self)> { + if let Some((first, second)) = self.entries.split_at_checked(index) { + Some((Self::from_slice(first), Self::from_slice(second))) + } else { + None + } + } + + /// Returns the first value and the rest of the slice, + /// or `None` if it is empty. + pub const fn split_first(&self) -> Option<(&T, &Self)> { + if let [first, rest @ ..] = &self.entries { + Some((&first.key, Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the last value and the rest of the slice, + /// or `None` if it is empty. + pub const fn split_last(&self) -> Option<(&T, &Self)> { + if let [rest @ .., last] = &self.entries { + Some((&last.key, Self::from_slice(rest))) + } else { + None + } + } + + /// Return an iterator over the values of the set slice. + pub fn iter(&self) -> Iter<'_, T> { + Iter::new(&self.entries) + } + + /// Search over a sorted set for a value. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the value up in + /// the set this is a slice from using [`IndexSet::get_index_of`], but this can also position + /// missing values. + pub fn binary_search(&self, x: &T) -> Result + where + T: Ord, + { + self.binary_search_by(|p| p.cmp(x)) + } + + /// Search over a sorted set with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: FnMut(&'a T) -> Ordering, + { + self.entries.binary_search_by(move |a| f(&a.key)) + } + + /// Search over a sorted set with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.binary_search_by(|k| f(k).cmp(b)) + } + + /// Checks if the values of this slice are sorted. + #[inline] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + self.entries.is_sorted_by(|a, b| a.key <= b.key) + } + + /// Checks if this slice is sorted using the given comparator function. + #[inline] + pub fn is_sorted_by<'a, F>(&'a self, mut cmp: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.entries.is_sorted_by(move |a, b| cmp(&a.key, &b.key)) + } + + /// Checks if this slice is sorted using the given sort-key function. + #[inline] + pub fn is_sorted_by_key<'a, F, K>(&'a self, mut sort_key: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.entries.is_sorted_by_key(move |a| sort_key(&a.key)) + } + + /// Returns the index of the partition point of a sorted set according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + self.entries.partition_point(move |a| pred(&a.key)) + } +} + +impl<'a, T> IntoIterator for &'a Slice { + type IntoIter = Iter<'a, T>; + type Item = &'a T; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Box> { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +impl Default for &'_ Slice { + fn default() -> Self { + Slice::from_slice(&[]) + } +} + +impl Default for Box> { + fn default() -> Self { + Slice::from_boxed(Box::default()) + } +} + +impl Clone for Box> { + fn clone(&self) -> Self { + Slice::from_boxed(self.entries.to_vec().into_boxed_slice()) + } +} + +impl From<&Slice> for Box> { + fn from(slice: &Slice) -> Self { + Slice::from_boxed(Box::from(&slice.entries)) + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +impl PartialEq> for Slice +where + T: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + slice_eq(&self.entries, &other.entries, |b1, b2| b1.key == b2.key) + } +} + +impl PartialEq<[U]> for Slice +where + T: PartialEq, +{ + fn eq(&self, other: &[U]) -> bool { + slice_eq(&self.entries, other, |b, o| b.key == *o) + } +} + +impl PartialEq> for [T] +where + T: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + slice_eq(self, &other.entries, |o, b| *o == b.key) + } +} + +impl PartialEq<[U; N]> for Slice +where + T: PartialEq, +{ + fn eq(&self, other: &[U; N]) -> bool { + >::eq(self, other) + } +} + +impl PartialEq> for [T; N] +where + T: PartialEq, +{ + fn eq(&self, other: &Slice) -> bool { + <[T] as PartialEq>>::eq(self, other) + } +} + +impl Eq for Slice {} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.len().hash(state); + for value in self { + value.hash(state); + } + } +} + +impl Index for Slice { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.entries[index].key + } +} + +// We can't have `impl> Index` because that conflicts with `Index`. +// Instead, we repeat the implementations for all the core range types. +macro_rules! impl_index { + ($($range:ty),*) => {$( + impl Index<$range> for IndexSet { + type Output = Slice; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.as_entries()[range]) + } + } + + impl Index<$range> for Slice { + type Output = Self; + + fn index(&self, range: $range) -> &Self::Output { + Slice::from_slice(&self.entries[range]) + } + } + )*} +} +impl_index!( + ops::Range, + ops::RangeFrom, + ops::RangeFull, + ops::RangeInclusive, + ops::RangeTo, + ops::RangeToInclusive, + (Bound, Bound) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn slice_index() { + fn check(vec_slice: &[i32], set_slice: &Slice, sub_slice: &Slice) { + assert_eq!(set_slice as *const _, sub_slice as *const _); + itertools::assert_equal(vec_slice, set_slice); + } + + let vec: Vec = (0..10).map(|i| i * i).collect(); + let set: IndexSet = vec.iter().cloned().collect(); + let slice = set.as_slice(); + + // RangeFull + check(&vec[..], &set[..], &slice[..]); + + for i in 0usize..10 { + // Index + assert_eq!(vec[i], set[i]); + assert_eq!(vec[i], slice[i]); + + // RangeFrom + check(&vec[i..], &set[i..], &slice[i..]); + + // RangeTo + check(&vec[..i], &set[..i], &slice[..i]); + + // RangeToInclusive + check(&vec[..=i], &set[..=i], &slice[..=i]); + + // (Bound, Bound) + let bounds = (Bound::Excluded(i), Bound::Unbounded); + check(&vec[i + 1..], &set[bounds], &slice[bounds]); + + for j in i..=10 { + // Range + check(&vec[i..j], &set[i..j], &slice[i..j]); + } + + for j in i..10 { + // RangeInclusive + check(&vec[i..=j], &set[i..=j], &slice[i..=j]); + } + } + } +} diff --git a/deps/crates/vendor/indexmap/src/set/tests.rs b/deps/crates/vendor/indexmap/src/set/tests.rs new file mode 100644 index 00000000000000..bf761e087b4980 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/set/tests.rs @@ -0,0 +1,1060 @@ +use super::*; +use std::string::String; + +#[test] +fn it_works() { + let mut set = IndexSet::new(); + assert_eq!(set.is_empty(), true); + set.insert(1); + set.insert(1); + assert_eq!(set.len(), 1); + assert!(set.get(&1).is_some()); + assert_eq!(set.is_empty(), false); +} + +#[test] +fn new() { + let set = IndexSet::::new(); + println!("{:?}", set); + assert_eq!(set.capacity(), 0); + assert_eq!(set.len(), 0); + assert_eq!(set.is_empty(), true); +} + +#[test] +fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + let (index, success) = set.insert_full(elt); + assert!(success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, success) = set.insert_full(elt); + assert!(!success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } +} + +#[test] +fn insert_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.insert(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn insert_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let inserted = set.insert(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(inserted, false); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } +} + +#[test] +fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..insert.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } +} + +#[test] +fn shift_insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.shift_insert(0, elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().rev().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..insert.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } + + // "insert" that moves an existing entry + set.shift_insert(0, insert[0]); + assert_eq!(set.iter().count(), insert.len()); + assert_eq!(insert[0], set[0]); + for (a, b) in insert[1..].iter().rev().zip(set.iter().skip(1)) { + assert_eq!(a, b); + } +} + +#[test] +fn replace() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in replace.iter().enumerate() { + assert_eq!(set.len(), i); + set.replace(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn replace_full() { + let replace = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in replace.iter().enumerate() { + assert_eq!(set.len(), i); + let (index, replaced) = set.replace_full(elt); + assert!(replaced.is_none()); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, replaced) = set.replace_full(elt); + assert_eq!(Some(elt), replaced); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } +} + +#[test] +fn replace_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.replace(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } +} + +#[test] +fn replace_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let replaced = set.replace(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(replaced, Some(0)); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } +} + +#[test] +fn replace_order() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &replace { + set.replace(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), replace.len()); + for (a, b) in replace.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..replace.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } +} + +#[test] +fn replace_change() { + // Check pointers to make sure it really changes + let mut set = indexset!(vec![42]); + let old_ptr = set[0].as_ptr(); + let new = set[0].clone(); + let new_ptr = new.as_ptr(); + assert_ne!(old_ptr, new_ptr); + let replaced = set.replace(new).unwrap(); + assert_eq!(replaced.as_ptr(), old_ptr); +} + +#[test] +fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in insert.iter().enumerate() { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + + println!("{:?}", set); + for &elt in &insert { + set.insert(elt * 10); + } + for &elt in &insert { + set.insert(elt * 100); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + set.insert(elt * 100 + i as i32); + } + println!("{:?}", set); + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } +} + +#[test] +fn reserve() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + set.reserve(100); + let capacity = set.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), capacity); + assert_eq!(set.get(&i), Some(&i)); + } + set.insert(capacity); + assert_eq!(set.len(), capacity + 1); + assert!(set.capacity() > capacity); + assert_eq!(set.get(&capacity), Some(&capacity)); +} + +#[test] +fn try_reserve() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + assert_eq!(set.try_reserve(100), Ok(())); + assert!(set.capacity() >= 100); + assert!(set.try_reserve(usize::MAX).is_err()); +} + +#[test] +fn shrink_to_fit() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + for i in 0..100 { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert!(set.capacity() >= i + 1); + assert_eq!(set.get(&i), Some(&i)); + set.shrink_to_fit(); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), i + 1); + assert_eq!(set.get(&i), Some(&i)); + } +} + +#[test] +fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &value in &remove_fail { + assert!(set.swap_remove_full(&value).is_none()); + } + println!("{:?}", set); + for &value in &remove { + //println!("{:?}", set); + let index = set.get_full(&value).unwrap().0; + assert_eq!(set.swap_remove_full(&value), Some((index, value))); + } + println!("{:?}", set); + + for value in &insert { + assert_eq!(set.get(value).is_some(), !remove.contains(value)); + } + assert_eq!(set.len(), insert.len() - remove.len()); + assert_eq!(set.iter().count(), insert.len() - remove.len()); +} + +#[test] +fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and set + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let out_set = set.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_set); + } + assert_eq!(vector.len(), set.len()); + for (a, b) in vector.iter().zip(set.iter()) { + assert_eq!(a, b); + } +} + +#[test] +fn partial_eq_and_eq() { + let mut set_a = IndexSet::new(); + set_a.insert(1); + set_a.insert(2); + let mut set_b = set_a.clone(); + assert_eq!(set_a, set_b); + set_b.swap_remove(&1); + assert_ne!(set_a, set_b); + + let set_c: IndexSet<_> = set_b.into_iter().collect(); + assert_ne!(set_a, set_c); + assert_ne!(set_c, set_a); +} + +#[test] +fn extend() { + let mut set = IndexSet::new(); + set.extend(vec![&1, &2, &3, &4]); + set.extend(vec![5, 6]); + assert_eq!(set.into_iter().collect::>(), vec![1, 2, 3, 4, 5, 6]); +} + +#[test] +fn comparisons() { + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).collect(); + + assert!(!set_a.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_a)); + assert!(set_a.is_superset(&set_a)); + + assert!(set_a.is_disjoint(&set_b)); + assert!(set_b.is_disjoint(&set_a)); + assert!(!set_a.is_subset(&set_b)); + assert!(!set_b.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_b)); + assert!(!set_b.is_superset(&set_a)); + + assert!(!set_a.is_disjoint(&set_c)); + assert!(!set_c.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_c)); + assert!(!set_c.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_c)); + assert!(set_c.is_superset(&set_a)); + + assert!(!set_c.is_disjoint(&set_d)); + assert!(!set_d.is_disjoint(&set_c)); + assert!(!set_c.is_subset(&set_d)); + assert!(!set_d.is_subset(&set_c)); + assert!(!set_c.is_superset(&set_d)); + assert!(!set_d.is_superset(&set_c)); +} + +#[test] +fn iter_comparisons() { + use std::iter::empty; + + fn check<'a, I1, I2>(iter1: I1, iter2: I2) + where + I1: Iterator, + I2: Iterator, + { + assert!(iter1.copied().eq(iter2)); + } + + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + check(set_a.difference(&set_a), empty()); + check(set_a.symmetric_difference(&set_a), empty()); + check(set_a.intersection(&set_a), 0..3); + check(set_a.union(&set_a), 0..3); + + check(set_a.difference(&set_b), 0..3); + check(set_b.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_b), 0..6); + check(set_b.symmetric_difference(&set_a), (3..6).chain(0..3)); + check(set_a.intersection(&set_b), empty()); + check(set_b.intersection(&set_a), empty()); + check(set_a.union(&set_b), 0..6); + check(set_b.union(&set_a), (3..6).chain(0..3)); + + check(set_a.difference(&set_c), empty()); + check(set_c.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_c), 3..6); + check(set_c.symmetric_difference(&set_a), 3..6); + check(set_a.intersection(&set_c), 0..3); + check(set_c.intersection(&set_a), 0..3); + check(set_a.union(&set_c), 0..6); + check(set_c.union(&set_a), 0..6); + + check(set_c.difference(&set_d), 0..3); + check(set_d.difference(&set_c), (6..9).rev()); + check( + set_c.symmetric_difference(&set_d), + (0..3).chain((6..9).rev()), + ); + check(set_d.symmetric_difference(&set_c), (6..9).rev().chain(0..3)); + check(set_c.intersection(&set_d), 3..6); + check(set_d.intersection(&set_c), (3..6).rev()); + check(set_c.union(&set_d), (0..6).chain((6..9).rev())); + check(set_d.union(&set_c), (3..9).rev().chain(0..3)); +} + +#[test] +fn ops() { + let empty = IndexSet::::new(); + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + #[allow(clippy::eq_op)] + { + assert_eq!(&set_a & &set_a, set_a); + assert_eq!(&set_a | &set_a, set_a); + assert_eq!(&set_a ^ &set_a, empty); + assert_eq!(&set_a - &set_a, empty); + } + + assert_eq!(&set_a & &set_b, empty); + assert_eq!(&set_b & &set_a, empty); + assert_eq!(&set_a | &set_b, set_c); + assert_eq!(&set_b | &set_a, set_c); + assert_eq!(&set_a ^ &set_b, set_c); + assert_eq!(&set_b ^ &set_a, set_c); + assert_eq!(&set_a - &set_b, set_a); + assert_eq!(&set_b - &set_a, set_b); + + assert_eq!(&set_a & &set_c, set_a); + assert_eq!(&set_c & &set_a, set_a); + assert_eq!(&set_a | &set_c, set_c); + assert_eq!(&set_c | &set_a, set_c); + assert_eq!(&set_a ^ &set_c, set_b); + assert_eq!(&set_c ^ &set_a, set_b); + assert_eq!(&set_a - &set_c, empty); + assert_eq!(&set_c - &set_a, set_b); + + assert_eq!(&set_c & &set_d, set_b); + assert_eq!(&set_d & &set_c, set_b); + assert_eq!(&set_c | &set_d, &set_a | &set_d); + assert_eq!(&set_d | &set_c, &set_a | &set_d); + assert_eq!(&set_c ^ &set_d, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_d ^ &set_c, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_c - &set_d, set_a); + assert_eq!(&set_d - &set_c, &set_d - &set_b); +} + +#[test] +#[cfg(feature = "std")] +fn from_array() { + let set1 = IndexSet::from([1, 2, 3, 4]); + let set2: IndexSet<_> = [1, 2, 3, 4].into(); + + assert_eq!(set1, set2); +} + +#[test] +fn iter_default() { + struct Item; + fn assert_default() + where + T: Default + Iterator, + { + assert!(T::default().next().is_none()); + } + assert_default::>(); + assert_default::>(); +} + +#[test] +#[allow(deprecated)] +fn take() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(10); + assert_eq!(index_set.len(), 1); + + let result = index_set.take(&10); + assert_eq!(result, Some(10)); + assert_eq!(index_set.len(), 0); + + let result = index_set.take(&20); + assert_eq!(result, None); +} + +#[test] +fn swap_take() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(10); + index_set.insert(20); + index_set.insert(30); + index_set.insert(40); + assert_eq!(index_set.len(), 4); + + let result = index_set.swap_take(&20); + assert_eq!(result, Some(20)); + assert_eq!(index_set.len(), 3); + assert_eq!(index_set.as_slice(), &[10, 40, 30]); + + let result = index_set.swap_take(&50); + assert_eq!(result, None); +} + +#[test] +fn sort_unstable() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(30); + index_set.insert(20); + index_set.insert(10); + + index_set.sort_unstable(); + assert_eq!(index_set.as_slice(), &[10, 20, 30]); +} + +#[test] +fn try_reserve_exact() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(10); + index_set.insert(20); + index_set.insert(30); + index_set.shrink_to_fit(); + assert_eq!(index_set.capacity(), 3); + + index_set.try_reserve_exact(2).unwrap(); + assert_eq!(index_set.capacity(), 5); +} + +#[test] +fn shift_remove_full() { + let mut set: IndexSet = IndexSet::new(); + set.insert(10); + set.insert(20); + set.insert(30); + set.insert(40); + set.insert(50); + + let result = set.shift_remove_full(&20); + assert_eq!(result, Some((1, 20))); + assert_eq!(set.len(), 4); + assert_eq!(set.as_slice(), &[10, 30, 40, 50]); + + let result = set.shift_remove_full(&50); + assert_eq!(result, Some((3, 50))); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[10, 30, 40]); + + let result = set.shift_remove_full(&60); + assert_eq!(result, None); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[10, 30, 40]); +} + +#[test] +fn shift_remove_index() { + let mut set: IndexSet = IndexSet::new(); + set.insert(10); + set.insert(20); + set.insert(30); + set.insert(40); + set.insert(50); + + let result = set.shift_remove_index(1); + assert_eq!(result, Some(20)); + assert_eq!(set.len(), 4); + assert_eq!(set.as_slice(), &[10, 30, 40, 50]); + + let result = set.shift_remove_index(1); + assert_eq!(result, Some(30)); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[10, 40, 50]); + + let result = set.shift_remove_index(3); + assert_eq!(result, None); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[10, 40, 50]); +} + +#[test] +fn sort_unstable_by() { + let mut set: IndexSet = IndexSet::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + set.sort_unstable_by(|a, b| b.cmp(a)); + assert_eq!(set.as_slice(), &[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); +} + +#[test] +fn sort_by() { + let mut set: IndexSet = IndexSet::new(); + set.insert(3); + set.insert(1); + set.insert(2); + set.sort_by(|a, b| a.cmp(b)); + assert_eq!(set.as_slice(), &[1, 2, 3]); +} + +#[test] +fn drain() { + let mut set: IndexSet = IndexSet::new(); + set.insert(1); + set.insert(2); + set.insert(3); + + { + let drain = set.drain(0..2); + assert_eq!(drain.as_slice(), &[1, 2]); + } + + assert_eq!(set.len(), 1); + assert_eq!(set.as_slice(), &[3]); +} + +#[test] +fn split_off() { + let mut set: IndexSet = IndexSet::from([1, 2, 3, 4, 5]); + let split_set: IndexSet = set.split_off(3); + + assert_eq!(split_set.len(), 2); + assert_eq!(split_set.as_slice(), &[4, 5]); + + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[1, 2, 3]); +} + +#[test] +fn retain() { + let mut set: IndexSet = IndexSet::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + set.retain(|&x| x > 4); + assert_eq!(set.len(), 6); + assert_eq!(set.as_slice(), &[5, 6, 7, 8, 9, 10]); + + set.retain(|_| false); + assert_eq!(set.len(), 0); +} + +#[test] +fn first() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(10); + index_set.insert(20); + index_set.insert(30); + + let result = index_set.first(); + assert_eq!(*result.unwrap(), 10); + + index_set.clear(); + let result = index_set.first(); + assert!(result.is_none()); +} + +#[test] +fn sort_by_key() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(3); + index_set.insert(1); + index_set.insert(2); + index_set.insert(0); + index_set.sort_by_key(|&x| -x); + assert_eq!(index_set.as_slice(), &[3, 2, 1, 0]); +} + +#[test] +fn sort_unstable_by_key() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(3); + index_set.insert(1); + index_set.insert(2); + index_set.insert(0); + index_set.sort_unstable_by_key(|&x| -x); + assert_eq!(index_set.as_slice(), &[3, 2, 1, 0]); +} + +#[test] +fn sort_by_cached_key() { + let mut index_set: IndexSet = IndexSet::new(); + index_set.insert(3); + index_set.insert(1); + index_set.insert(2); + index_set.insert(0); + index_set.sort_by_cached_key(|&x| -x); + assert_eq!(index_set.as_slice(), &[3, 2, 1, 0]); +} + +#[test] +fn insert_sorted() { + let mut set: IndexSet = IndexSet::::new(); + set.insert_sorted(1); + set.insert_sorted(3); + assert_eq!(set.insert_sorted(2), (1, true)); +} + +#[test] +fn binary_search() { + let mut set: IndexSet = IndexSet::new(); + set.insert(100); + set.insert(300); + set.insert(200); + set.insert(400); + let result = set.binary_search(&200); + assert_eq!(result, Ok(2)); + + let result = set.binary_search(&500); + assert_eq!(result, Err(4)); +} + +#[test] +fn sorted_unstable_by() { + let mut set: IndexSet = IndexSet::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + set.sort_unstable_by(|a, b| b.cmp(a)); + assert_eq!(set.as_slice(), &[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); +} + +#[test] +fn last() { + let mut set: IndexSet = IndexSet::new(); + set.insert(1); + set.insert(2); + set.insert(3); + set.insert(4); + set.insert(5); + set.insert(6); + + assert_eq!(set.last(), Some(&6)); + + set.pop(); + assert_eq!(set.last(), Some(&5)); + + set.clear(); + assert_eq!(set.last(), None); +} + +#[test] +fn get_range() { + let set: IndexSet = IndexSet::from([1, 2, 3, 4, 5]); + let result = set.get_range(0..3); + let slice: &Slice = result.unwrap(); + assert_eq!(slice, &[1, 2, 3]); + + let result = set.get_range(0..0); + assert_eq!(result.unwrap().len(), 0); + + let result = set.get_range(2..1); + assert!(result.is_none()); +} + +#[test] +fn shift_take() { + let mut set: IndexSet = IndexSet::new(); + set.insert(1); + set.insert(2); + set.insert(3); + set.insert(4); + set.insert(5); + + let result = set.shift_take(&2); + assert_eq!(result, Some(2)); + assert_eq!(set.len(), 4); + assert_eq!(set.as_slice(), &[1, 3, 4, 5]); + + let result = set.shift_take(&5); + assert_eq!(result, Some(5)); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[1, 3, 4]); + + let result = set.shift_take(&5); + assert_eq!(result, None); + assert_eq!(set.len(), 3); + assert_eq!(set.as_slice(), &[1, 3, 4]); +} + +#[test] +fn test_binary_search_by() { + // adapted from std's test for binary_search + let b: IndexSet = [].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(0)); + + let b: IndexSet = [4].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&3)), Err(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&4)), Ok(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(1)); + + let b: IndexSet = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Err(4)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Ok(4)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&9)), Err(6)); + + let b: IndexSet = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Ok(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(3)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Ok(5)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Err(5)); + assert_eq!(b.binary_search_by(|x| x.cmp(&0)), Err(0)); + + let b: IndexSet = [1, 3, 3, 3, 7].into(); + assert_eq!(b.binary_search_by(|x| x.cmp(&0)), Err(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&1)), Ok(0)); + assert_eq!(b.binary_search_by(|x| x.cmp(&2)), Err(1)); + // diff from std as set merges the duplicate keys + assert!(match b.binary_search_by(|x| x.cmp(&3)) { + Ok(1..=2) => true, + _ => false, + }); + assert!(match b.binary_search_by(|x| x.cmp(&3)) { + Ok(1..=2) => true, + _ => false, + }); + assert_eq!(b.binary_search_by(|x| x.cmp(&4)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&5)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&6)), Err(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&7)), Ok(2)); + assert_eq!(b.binary_search_by(|x| x.cmp(&8)), Err(3)); +} + +#[test] +fn test_binary_search_by_key() { + // adapted from std's test for binary_search + let b: IndexSet = [].into(); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(0)); + + let b: IndexSet = [4].into(); + assert_eq!(b.binary_search_by_key(&3, |&x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&4, |&x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(1)); + + let b: IndexSet = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Err(4)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Ok(4)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.binary_search_by_key(&9, |&x| x), Err(6)); + + let b: IndexSet = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Ok(3)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(3)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Ok(5)); + + let b: IndexSet = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Err(5)); + assert_eq!(b.binary_search_by_key(&0, |&x| x), Err(0)); + + let b: IndexSet = [1, 3, 3, 3, 7].into(); + assert_eq!(b.binary_search_by_key(&0, |&x| x), Err(0)); + assert_eq!(b.binary_search_by_key(&1, |&x| x), Ok(0)); + assert_eq!(b.binary_search_by_key(&2, |&x| x), Err(1)); + // diff from std as set merges the duplicate keys + assert!(match b.binary_search_by_key(&3, |&x| x) { + Ok(1..=2) => true, + _ => false, + }); + assert!(match b.binary_search_by_key(&3, |&x| x) { + Ok(1..=2) => true, + _ => false, + }); + assert_eq!(b.binary_search_by_key(&4, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&5, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&6, |&x| x), Err(2)); + assert_eq!(b.binary_search_by_key(&7, |&x| x), Ok(2)); + assert_eq!(b.binary_search_by_key(&8, |&x| x), Err(3)); +} + +#[test] +fn test_partition_point() { + // adapted from std's test for partition_point + let b: IndexSet = [].into(); + assert_eq!(b.partition_point(|&x| x < 5), 0); + + let b: IndexSet<_> = [4].into(); + assert_eq!(b.partition_point(|&x| x < 3), 0); + assert_eq!(b.partition_point(|&x| x < 4), 0); + assert_eq!(b.partition_point(|&x| x < 5), 1); + + let b: IndexSet<_> = [1, 2, 4, 6, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 4); + + let b: IndexSet<_> = [1, 2, 4, 5, 6, 8].into(); + assert_eq!(b.partition_point(|&x| x < 9), 6); + + let b: IndexSet<_> = [1, 2, 4, 6, 7, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 8), 5); + + let b: IndexSet<_> = [1, 2, 4, 5, 6, 8, 9].into(); + assert_eq!(b.partition_point(|&x| x < 7), 5); + assert_eq!(b.partition_point(|&x| x < 0), 0); + + let b: IndexSet<_> = [1, 3, 3, 3, 7].into(); + assert_eq!(b.partition_point(|&x| x < 0), 0); + assert_eq!(b.partition_point(|&x| x < 1), 0); + assert_eq!(b.partition_point(|&x| x < 2), 1); + assert_eq!(b.partition_point(|&x| x < 3), 1); + assert_eq!(b.partition_point(|&x| x < 4), 2); // diff from std as set merges the duplicate keys + assert_eq!(b.partition_point(|&x| x < 5), 2); + assert_eq!(b.partition_point(|&x| x < 6), 2); + assert_eq!(b.partition_point(|&x| x < 7), 2); + assert_eq!(b.partition_point(|&x| x < 8), 3); +} + +#[test] +fn is_sorted() { + fn expect(set: &IndexSet, e: [bool; 4]) { + assert_eq!(e[0], set.is_sorted()); + assert_eq!(e[1], set.is_sorted_by(|v1, v2| v1 < v2)); + assert_eq!(e[2], set.is_sorted_by(|v1, v2| v1 > v2)); + assert_eq!(e[3], set.is_sorted_by_key(|v| v)); + } + + let mut set = IndexSet::::from_iter(0..10); + expect(&set, [true, true, false, true]); + + set.replace_index(5, -1).unwrap(); + expect(&set, [false, false, false, false]); +} + +#[test] +fn is_sorted_trivial() { + fn expect(set: &IndexSet, e: [bool; 5]) { + assert_eq!(e[0], set.is_sorted()); + assert_eq!(e[1], set.is_sorted_by(|_, _| true)); + assert_eq!(e[2], set.is_sorted_by(|_, _| false)); + assert_eq!(e[3], set.is_sorted_by_key(|_| 0f64)); + assert_eq!(e[4], set.is_sorted_by_key(|_| f64::NAN)); + } + + let mut set = IndexSet::::default(); + expect(&set, [true, true, true, true, true]); + + set.insert(0); + expect(&set, [true, true, true, true, true]); + + set.insert(1); + expect(&set, [true, true, false, true, false]); + + set.reverse(); + expect(&set, [false, true, false, true, false]); +} diff --git a/deps/crates/vendor/indexmap/src/sval.rs b/deps/crates/vendor/indexmap/src/sval.rs new file mode 100644 index 00000000000000..73f096cf815eaf --- /dev/null +++ b/deps/crates/vendor/indexmap/src/sval.rs @@ -0,0 +1,36 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "sval")))] + +use crate::{IndexMap, IndexSet}; +use sval::{Stream, Value}; + +impl Value for IndexMap { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval::Result { + stream.map_begin(Some(self.len()))?; + + for (k, v) in self { + stream.map_key_begin()?; + stream.value(k)?; + stream.map_key_end()?; + + stream.map_value_begin()?; + stream.value(v)?; + stream.map_value_end()?; + } + + stream.map_end() + } +} + +impl Value for IndexSet { + fn stream<'sval, ST: Stream<'sval> + ?Sized>(&'sval self, stream: &mut ST) -> sval::Result { + stream.seq_begin(Some(self.len()))?; + + for value in self { + stream.seq_value_begin()?; + stream.value(value)?; + stream.seq_value_end()?; + } + + stream.seq_end() + } +} diff --git a/deps/crates/vendor/indexmap/src/util.rs b/deps/crates/vendor/indexmap/src/util.rs new file mode 100644 index 00000000000000..8b3b2b48fd921f --- /dev/null +++ b/deps/crates/vendor/indexmap/src/util.rs @@ -0,0 +1,78 @@ +use core::ops::{Bound, Range, RangeBounds}; + +pub(crate) fn third(t: (A, B, C)) -> C { + t.2 +} + +#[track_caller] +pub(crate) fn simplify_range(range: R, len: usize) -> Range +where + R: RangeBounds, +{ + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) if i <= len => i, + Bound::Excluded(&i) if i < len => i + 1, + Bound::Included(i) | Bound::Excluded(i) => { + panic!("range start index {i} out of range for slice of length {len}") + } + }; + let end = match range.end_bound() { + Bound::Unbounded => len, + Bound::Excluded(&i) if i <= len => i, + Bound::Included(&i) if i < len => i + 1, + Bound::Included(i) | Bound::Excluded(i) => { + panic!("range end index {i} out of range for slice of length {len}") + } + }; + if start > end { + panic!( + "range start index {:?} should be <= range end index {:?}", + range.start_bound(), + range.end_bound() + ); + } + start..end +} + +pub(crate) fn try_simplify_range(range: R, len: usize) -> Option> +where + R: RangeBounds, +{ + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) if i <= len => i, + Bound::Excluded(&i) if i < len => i + 1, + _ => return None, + }; + let end = match range.end_bound() { + Bound::Unbounded => len, + Bound::Excluded(&i) if i <= len => i, + Bound::Included(&i) if i < len => i + 1, + _ => return None, + }; + if start > end { + return None; + } + Some(start..end) +} + +// Generic slice equality -- copied from the standard library but adding a custom comparator, +// allowing for our `Bucket` wrapper on either or both sides. +pub(crate) fn slice_eq(left: &[T], right: &[U], eq: impl Fn(&T, &U) -> bool) -> bool { + if left.len() != right.len() { + return false; + } + + // Implemented as explicit indexing rather + // than zipped iterators for performance reasons. + // See PR https://github.com/rust-lang/rust/pull/116846 + for i in 0..left.len() { + // bound checks are optimized away + if !eq(&left[i], &right[i]) { + return false; + } + } + + true +} diff --git a/deps/crates/vendor/indexmap/tests/equivalent_trait.rs b/deps/crates/vendor/indexmap/tests/equivalent_trait.rs new file mode 100644 index 00000000000000..e12c768f0aad7a --- /dev/null +++ b/deps/crates/vendor/indexmap/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use indexmap::Equivalent; +use indexmap::indexmap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let map = indexmap! { + (s("a"), s("b")) => 1, + (s("a"), s("x")) => 2, + }; + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = indexmap! { + s("a") => 1, s("b") => 2, + s("x") => 3, s("y") => 4, + }; + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.swap_remove("b"), Some(2)); +} diff --git a/deps/crates/vendor/indexmap/tests/macros_full_path.rs b/deps/crates/vendor/indexmap/tests/macros_full_path.rs new file mode 100644 index 00000000000000..2467d9b4f5d4d0 --- /dev/null +++ b/deps/crates/vendor/indexmap/tests/macros_full_path.rs @@ -0,0 +1,19 @@ +#[test] +fn test_create_map() { + let _m = indexmap::indexmap! { + 1 => 2, + 7 => 1, + 2 => 2, + 3 => 3, + }; +} + +#[test] +fn test_create_set() { + let _s = indexmap::indexset! { + 1, + 7, + 2, + 3, + }; +} diff --git a/deps/crates/vendor/indexmap/tests/quick.rs b/deps/crates/vendor/indexmap/tests/quick.rs new file mode 100644 index 00000000000000..3f64b096fbe2f0 --- /dev/null +++ b/deps/crates/vendor/indexmap/tests/quick.rs @@ -0,0 +1,896 @@ +use indexmap::{IndexMap, IndexSet}; +use itertools::Itertools; + +use quickcheck::Arbitrary; +use quickcheck::Gen; +use quickcheck::QuickCheck; +use quickcheck::TestResult; + +use fnv::FnvHasher; +use std::hash::{BuildHasher, BuildHasherDefault}; +type FnvBuilder = BuildHasherDefault; +type IndexMapFnv = IndexMap; + +use std::cmp::min; +use std::collections::HashMap; +use std::collections::HashSet; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::Bound; +use std::ops::Deref; + +use indexmap::map::Entry; +use std::collections::hash_map::Entry as StdEntry; + +fn set<'a, T: 'a, I>(iter: I) -> HashSet +where + I: IntoIterator, + T: Copy + Hash + Eq, +{ + iter.into_iter().copied().collect() +} + +fn indexmap<'a, T: 'a, I>(iter: I) -> IndexMap +where + I: IntoIterator, + T: Copy + Hash + Eq, +{ + IndexMap::from_iter(iter.into_iter().copied().map(|k| (k, ()))) +} + +// Helper macro to allow us to use smaller quickcheck limits under miri. +macro_rules! quickcheck_limit { + (@as_items $($i:item)*) => ($($i)*); + { + $( + $(#[$m:meta])* + fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { + $($code:tt)* + } + )* + } => ( + quickcheck::quickcheck! { + @as_items + $( + #[test] + $(#[$m])* + fn $fn_name() { + fn prop($($arg_name: $arg_ty),*) -> $ret { + $($code)* + } + let mut quickcheck = QuickCheck::new(); + if cfg!(miri) { + quickcheck = quickcheck + .rng(Gen::new(10)) + .tests(10) + .max_tests(100); + } + + quickcheck.quickcheck(prop as fn($($arg_ty),*) -> $ret); + } + )* + } + ) +} + +quickcheck_limit! { + fn contains(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + insert.iter().all(|&key| map.get(&key).is_some()) + } + + fn contains_not(insert: Vec, not: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let nots = &set(¬) - &set(&insert); + nots.iter().all(|&key| map.get(&key).is_none()) + } + + fn insert_remove(insert: Vec, remove: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + for &key in &remove { + map.swap_remove(&key); + } + let elements = &set(&insert) - &set(&remove); + map.len() == elements.len() && map.iter().count() == elements.len() && + elements.iter().all(|k| map.get(k).is_some()) + } + + fn insertion_order(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + itertools::assert_equal(insert.iter().unique(), map.keys()); + true + } + + fn insert_sorted(insert: Vec<(u32, u32)>) -> bool { + let mut hmap = HashMap::new(); + let mut map = IndexMap::new(); + let mut map2 = IndexMap::new(); + for &(key, value) in &insert { + hmap.insert(key, value); + map.insert_sorted(key, value); + match map2.entry(key) { + Entry::Occupied(e) => *e.into_mut() = value, + Entry::Vacant(e) => { e.insert_sorted(value); } + } + } + itertools::assert_equal(hmap.iter().sorted(), &map); + itertools::assert_equal(&map, &map2); + true + } + + fn insert_sorted_by(insert: Vec<(u32, u32)>) -> bool { + let mut hmap = HashMap::new(); + let mut map = IndexMap::new(); + let mut map2 = IndexMap::new(); + for &(key, value) in &insert { + hmap.insert(key, value); + map.insert_sorted_by(key, value, |key1, _, key2, _| key2.cmp(key1)); + match map2.entry(key) { + Entry::Occupied(e) => *e.into_mut() = value, + Entry::Vacant(e) => { + e.insert_sorted_by(value, |key1, _, key2, _| key2.cmp(key1)); + } + } + } + let hsorted = hmap.iter().sorted_by(|(key1, _), (key2, _)| key2.cmp(key1)); + itertools::assert_equal(hsorted, &map); + itertools::assert_equal(&map, &map2); + true + } + + fn insert_sorted_by_key(insert: Vec<(i32, u32)>) -> bool { + let mut hmap = HashMap::new(); + let mut map = IndexMap::new(); + let mut map2 = IndexMap::new(); + for &(key, value) in &insert { + hmap.insert(key, value); + map.insert_sorted_by_key(key, value, |&k, _| (k.unsigned_abs(), k)); + match map2.entry(key) { + Entry::Occupied(e) => *e.into_mut() = value, + Entry::Vacant(e) => { + e.insert_sorted_by_key(value, |&k, _| (k.unsigned_abs(), k)); + } + } + } + let hsorted = hmap.iter().sorted_by_key(|&(&k, _)| (k.unsigned_abs(), k)); + itertools::assert_equal(hsorted, &map); + itertools::assert_equal(&map, &map2); + true + } + + fn replace_index(insert: Vec, index: u8, new_key: u8) -> TestResult { + if insert.is_empty() { + return TestResult::discard(); + } + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let mut index = usize::from(index); + if index < map.len() { + match map.replace_index(index, new_key) { + Ok(old_key) => { + assert!(old_key == new_key || !map.contains_key(&old_key)); + } + Err((i, key)) => { + assert_eq!(key, new_key); + index = i; + } + } + assert_eq!(map.get_index_of(&new_key), Some(index)); + assert_eq!(map.get_index(index), Some((&new_key, &()))); + TestResult::passed() + } else { + TestResult::must_fail(move || map.replace_index(index, new_key)) + } + } + + fn vacant_replace_index(insert: Vec, index: u8, new_key: u8) -> TestResult { + if insert.is_empty() { + return TestResult::discard(); + } + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let index = usize::from(index); + if let Some((&old_key, &())) = map.get_index(index) { + match map.entry(new_key) { + Entry::Occupied(_) => return TestResult::discard(), + Entry::Vacant(entry) => { + let (replaced_key, entry) = entry.replace_index(index); + assert_eq!(old_key, replaced_key); + assert_eq!(*entry.key(), new_key); + } + }; + assert!(!map.contains_key(&old_key)); + assert_eq!(map.get_index_of(&new_key), Some(index)); + assert_eq!(map.get_index(index), Some((&new_key, &()))); + TestResult::passed() + } else { + TestResult::must_fail(move || map.replace_index(index, new_key)) + } + } + + fn pop(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let mut pops = Vec::new(); + while let Some((key, _v)) = map.pop() { + pops.push(key); + } + pops.reverse(); + + itertools::assert_equal(insert.iter().unique(), &pops); + true + } + + fn with_cap(template: Vec<()>) -> bool { + let cap = template.len(); + let map: IndexMap = IndexMap::with_capacity(cap); + println!("wish: {}, got: {} (diff: {})", cap, map.capacity(), map.capacity() as isize - cap as isize); + map.capacity() >= cap + } + + fn drain_full(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let mut clone = map.clone(); + let drained = clone.drain(..); + for (key, _) in drained { + map.swap_remove(&key); + } + map.is_empty() + } + + fn drain_bounds(insert: Vec, range: (Bound, Bound)) -> TestResult { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + + // First see if `Vec::drain` is happy with this range. + let result = std::panic::catch_unwind(|| { + let mut keys: Vec = map.keys().copied().collect(); + keys.drain(range); + keys + }); + + if let Ok(keys) = result { + map.drain(range); + // Check that our `drain` matches the same key order. + assert!(map.keys().eq(&keys)); + // Check that hash lookups all work too. + assert!(keys.iter().all(|key| map.contains_key(key))); + TestResult::passed() + } else { + // If `Vec::drain` panicked, so should we. + TestResult::must_fail(move || { map.drain(range); }) + } + } + + fn extract_if_odd(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &x in &insert { + map.insert(x, x.to_string()); + } + + let (odd, even): (Vec<_>, Vec<_>) = map.keys().copied().partition(|k| k % 2 == 1); + + let extracted: Vec<_> = map + .extract_if(.., |k, _| k % 2 == 1) + .map(|(k, _)| k) + .collect(); + + even.iter().all(|k| map.contains_key(k)) + && map.keys().eq(&even) + && extracted == odd + } + + fn extract_if_odd_limit(insert: Vec, limit: usize) -> bool { + let mut map = IndexMap::new(); + for &x in &insert { + map.insert(x, x.to_string()); + } + let limit = limit % (map.len() + 1); + + let mut i = 0; + let (odd, other): (Vec<_>, Vec<_>) = map.keys().copied().partition(|k| { + k % 2 == 1 && i < limit && { i += 1; true } + }); + + let extracted: Vec<_> = map + .extract_if(.., |k, _| k % 2 == 1) + .map(|(k, _)| k) + .take(limit) + .collect(); + + other.iter().all(|k| map.contains_key(k)) + && map.keys().eq(&other) + && extracted == odd + } + + fn shift_remove(insert: Vec, remove: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + for &key in &remove { + map.shift_remove(&key); + } + let elements = &set(&insert) - &set(&remove); + + // Check that order is preserved after removals + let mut iter = map.keys(); + for &key in insert.iter().unique() { + if elements.contains(&key) { + assert_eq!(Some(&key), iter.next()); + } + } + + map.len() == elements.len() && map.iter().count() == elements.len() && + elements.iter().all(|k| map.get(k).is_some()) + } + + fn indexing(insert: Vec) -> bool { + let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect(); + let set: IndexSet<_> = map.keys().copied().collect(); + assert_eq!(map.len(), set.len()); + + for (i, &key) in set.iter().enumerate() { + assert_eq!(map.get_index(i), Some((&key, &key))); + assert_eq!(set.get_index(i), Some(&key)); + assert_eq!(map[i], key); + assert_eq!(set[i], key); + + *map.get_index_mut(i).unwrap().1 >>= 1; + map[i] <<= 1; + } + + set.iter().enumerate().all(|(i, &key)| { + let value = key & !1; + map[&key] == value && map[i] == value + }) + } + + // Use `u8` test indices so quickcheck is less likely to go out of bounds. + fn set_swap_indices(vec: Vec, a: u8, b: u8) -> TestResult { + let mut set = IndexSet::::from_iter(vec); + let a = usize::from(a); + let b = usize::from(b); + + if a >= set.len() || b >= set.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(set.iter().cloned()); + vec.swap(a, b); + + set.swap_indices(a, b); + + // Check both iteration order and hash lookups + assert!(set.iter().eq(vec.iter())); + assert!(vec.iter().enumerate().all(|(i, x)| { + set.get_index_of(x) == Some(i) + })); + TestResult::passed() + } + + fn map_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, IndexMap::swap_indices) + } + + fn occupied_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.entry(key) { + Entry::Occupied(entry) => entry.swap_indices(to), + _ => unreachable!(), + } + }) + } + + fn indexed_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_swap_indices(vec, from, to, |map, from, to| { + map.get_index_entry(from).unwrap().swap_indices(to); + }) + } + + fn raw_occupied_entry_swap_indices(vec: Vec, from: u8, to: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_swap_indices(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Occupied(entry) => entry.swap_indices(to), + _ => unreachable!(), + } + }) + } + + // Use `u8` test indices so quickcheck is less likely to go out of bounds. + fn set_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + let mut set = IndexSet::::from_iter(vec); + let from = usize::from(from); + let to = usize::from(to); + + if from >= set.len() || to >= set.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(set.iter().cloned()); + let x = vec.remove(from); + vec.insert(to, x); + + set.move_index(from, to); + + // Check both iteration order and hash lookups + assert!(set.iter().eq(vec.iter())); + assert!(vec.iter().enumerate().all(|(i, x)| { + set.get_index_of(x) == Some(i) + })); + TestResult::passed() + } + + fn map_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, IndexMap::move_index) + } + + fn occupied_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.entry(key) { + Entry::Occupied(entry) => entry.move_index(to), + _ => unreachable!(), + } + }) + } + + fn indexed_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + test_map_move_index(vec, from, to, |map, from, to| { + map.get_index_entry(from).unwrap().move_index(to); + }) + } + + fn raw_occupied_entry_move_index(vec: Vec, from: u8, to: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_move_index(vec, from, to, |map, from, to| { + let key = map.keys()[from]; + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Occupied(entry) => entry.move_index(to), + _ => unreachable!(), + } + }) + } + + fn occupied_entry_shift_insert(vec: Vec, i: u8) -> TestResult { + test_map_shift_insert(vec, i, |map, i, key| { + match map.entry(key) { + Entry::Vacant(entry) => entry.shift_insert(i, ()), + _ => unreachable!(), + }; + }) + } + + fn raw_occupied_entry_shift_insert(vec: Vec, i: u8) -> TestResult { + use indexmap::map::raw_entry_v1::{RawEntryApiV1, RawEntryMut}; + test_map_shift_insert(vec, i, |map, i, key| { + match map.raw_entry_mut_v1().from_key(&key) { + RawEntryMut::Vacant(entry) => entry.shift_insert(i, key, ()), + _ => unreachable!(), + }; + }) + } +} + +fn test_map_swap_indices(vec: Vec, a: u8, b: u8, swap_indices: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, usize), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let a = usize::from(a); + let b = usize::from(b); + + if a >= map.len() || b >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + vec.swap(a, b); + + swap_indices(&mut map, a, b); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!( + vec.iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) }) + ); + TestResult::passed() +} + +fn test_map_move_index(vec: Vec, from: u8, to: u8, move_index: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, usize), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let from = usize::from(from); + let to = usize::from(to); + + if from >= map.len() || to >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + let x = vec.remove(from); + vec.insert(to, x); + + move_index(&mut map, from, to); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!( + vec.iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) }) + ); + TestResult::passed() +} + +fn test_map_shift_insert(vec: Vec, i: u8, shift_insert: F) -> TestResult +where + F: FnOnce(&mut IndexMap, usize, u8), +{ + let mut map = IndexMap::::from_iter(vec.into_iter().map(|k| (k, ()))); + let i = usize::from(i); + if i >= map.len() { + return TestResult::discard(); + } + + let mut vec = Vec::from_iter(map.keys().copied()); + let x = vec.pop().unwrap(); + vec.insert(i, x); + + let (last, ()) = map.pop().unwrap(); + assert_eq!(x, last); + map.shrink_to_fit(); // so we might have to grow and rehash the table + + shift_insert(&mut map, i, last); + + // Check both iteration order and hash lookups + assert!(map.keys().eq(vec.iter())); + assert!( + vec.iter() + .enumerate() + .all(|(i, x)| { map.get_index_of(x) == Some(i) }) + ); + TestResult::passed() +} + +use crate::Op::*; +#[derive(Copy, Clone, Debug)] +enum Op { + Add(K, V), + Remove(K), + AddEntry(K, V), + RemoveEntry(K), +} + +impl Arbitrary for Op +where + K: Arbitrary, + V: Arbitrary, +{ + fn arbitrary(g: &mut Gen) -> Self { + match u32::arbitrary(g) % 4 { + 0 => Add(K::arbitrary(g), V::arbitrary(g)), + 1 => AddEntry(K::arbitrary(g), V::arbitrary(g)), + 2 => Remove(K::arbitrary(g)), + _ => RemoveEntry(K::arbitrary(g)), + } + } +} + +fn do_ops(ops: &[Op], a: &mut IndexMap, b: &mut HashMap) +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + for op in ops { + match *op { + Add(ref k, ref v) => { + a.insert(k.clone(), v.clone()); + b.insert(k.clone(), v.clone()); + } + AddEntry(ref k, ref v) => { + a.entry(k.clone()).or_insert_with(|| v.clone()); + b.entry(k.clone()).or_insert_with(|| v.clone()); + } + Remove(ref k) => { + a.swap_remove(k); + b.remove(k); + } + RemoveEntry(ref k) => { + if let Entry::Occupied(ent) = a.entry(k.clone()) { + ent.swap_remove_entry(); + } + if let StdEntry::Occupied(ent) = b.entry(k.clone()) { + ent.remove_entry(); + } + } + } + //println!("{:?}", a); + } +} + +fn assert_maps_equivalent(a: &IndexMap, b: &HashMap) -> bool +where + K: Hash + Eq + Debug, + V: Eq + Debug, +{ + assert_eq!(a.len(), b.len()); + assert_eq!(a.iter().next().is_some(), b.iter().next().is_some()); + for key in a.keys() { + assert!(b.contains_key(key), "b does not contain {:?}", key); + } + for key in b.keys() { + assert!(a.get(key).is_some(), "a does not contain {:?}", key); + } + for key in a.keys() { + assert_eq!(a[key], b[key]); + } + true +} + +quickcheck_limit! { + fn operations_i8(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + assert_maps_equivalent(&map, &reference) + } + + fn operations_string(ops: Vec>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + assert_maps_equivalent(&map, &reference) + } + + fn keys_values(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + let mut visit = IndexMap::new(); + for (k, v) in map.keys().zip(map.values()) { + assert_eq!(&map[k], v); + assert!(!visit.contains_key(k)); + visit.insert(*k, *v); + } + assert_eq!(visit.len(), reference.len()); + true + } + + fn keys_values_mut(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + let mut visit = IndexMap::new(); + let keys = Vec::from_iter(map.keys().copied()); + for (k, v) in keys.iter().zip(map.values_mut()) { + assert_eq!(&reference[k], v); + assert!(!visit.contains_key(k)); + visit.insert(*k, *v); + } + assert_eq!(visit.len(), reference.len()); + true + } + + fn equality(ops1: Vec>, removes: Vec) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops1, &mut map, &mut reference); + let mut ops2 = ops1.clone(); + for &r in &removes { + if !ops2.is_empty() { + let i = r % ops2.len(); + ops2.remove(i); + } + } + let mut map2 = IndexMapFnv::default(); + let mut reference2 = HashMap::new(); + do_ops(&ops2, &mut map2, &mut reference2); + assert_eq!(map == map2, reference == reference2); + true + } + + fn retain_ordered(keys: Large>, remove: Large>) -> () { + let mut map = indexmap(keys.iter()); + let initial_map = map.clone(); // deduplicated in-order input + let remove_map = indexmap(remove.iter()); + let keys_s = set(keys.iter()); + let remove_s = set(remove.iter()); + let answer = &keys_s - &remove_s; + map.retain(|k, _| !remove_map.contains_key(k)); + + // check the values + assert_eq!(map.len(), answer.len()); + for key in &answer { + assert!(map.contains_key(key)); + } + // check the order + itertools::assert_equal(map.keys(), initial_map.keys().filter(|&k| !remove_map.contains_key(k))); + } + + fn sort_1(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + let mut answer = keyvals.0; + answer.sort_by_key(|t| t.0); + + // reverse dedup: Because IndexMap::from_iter keeps the last value for + // identical keys + answer.reverse(); + answer.dedup_by_key(|t| t.0); + answer.reverse(); + + map.sort_by(|k1, _, k2, _| Ord::cmp(k1, k2)); + + // check it contains all the values it should + for &(key, val) in &answer { + assert_eq!(map[&key], val); + } + + // check the order + + let mapv = Vec::from_iter(map); + assert_eq!(answer, mapv); + + } + + fn sort_2(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + map.sort_by(|_, v1, _, v2| Ord::cmp(v1, v2)); + assert_sorted_by_key(map, |t| t.1); + } + + fn sort_3(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + map.sort_by_cached_key(|&k, _| std::cmp::Reverse(k)); + assert_sorted_by_key(map, |t| std::cmp::Reverse(t.0)); + } + + fn reverse(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + + fn generate_answer(input: &Vec<(i8, i8)>) -> Vec<(i8, i8)> { + // to mimic what `IndexMap::from_iter` does: + // need to get (A) the unique keys in forward order, and (B) the + // last value of each of those keys. + + // create (A): an iterable that yields the unique keys in ltr order + let mut seen_keys = HashSet::new(); + let unique_keys_forward = input.iter().filter_map(move |(k, _)| { + if seen_keys.contains(k) { None } + else { seen_keys.insert(*k); Some(*k) } + }); + + // create (B): a mapping of keys to the last value seen for that key + // this is the same as reversing the input and taking the first + // value seen for that key! + let mut last_val_per_key = HashMap::new(); + for &(k, v) in input.iter().rev() { + if !last_val_per_key.contains_key(&k) { + last_val_per_key.insert(k, v); + } + } + + // iterate over the keys in (A) in order, and match each one with + // the corresponding last value from (B) + let mut ans: Vec<_> = unique_keys_forward + .map(|k| (k, *last_val_per_key.get(&k).unwrap())) + .collect(); + + // finally, since this test is testing `.reverse()`, reverse the + // answer in-place + ans.reverse(); + + ans + } + + let answer = generate_answer(&keyvals.0); + + // perform the work + map.reverse(); + + // check it contains all the values it should + for &(key, val) in &answer { + assert_eq!(map[&key], val); + } + + // check the order + let mapv = Vec::from_iter(map); + assert_eq!(answer, mapv); + } +} + +fn assert_sorted_by_key(iterable: I, key: Key) +where + I: IntoIterator, + Key: Fn(&I::Item) -> X, + X: Ord, +{ + let input = Vec::from_iter(iterable); + let mut sorted = input.clone(); + sorted.sort_by_key(key); + assert_eq!(input, sorted); +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +struct Alpha(String); + +impl Deref for Alpha { + type Target = String; + fn deref(&self) -> &String { + &self.0 + } +} + +const ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyz"; + +impl Arbitrary for Alpha { + fn arbitrary(g: &mut Gen) -> Self { + let len = usize::arbitrary(g) % g.size(); + let len = min(len, 16); + Alpha( + (0..len) + .map(|_| ALPHABET[usize::arbitrary(g) % ALPHABET.len()] as char) + .collect(), + ) + } + + fn shrink(&self) -> Box> { + Box::new((**self).shrink().map(Alpha)) + } +} + +/// quickcheck Arbitrary adaptor -- make a larger vec +#[derive(Clone, Debug)] +struct Large(T); + +impl Deref for Large { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +impl Arbitrary for Large> +where + T: Arbitrary, +{ + fn arbitrary(g: &mut Gen) -> Self { + let len = usize::arbitrary(g) % (g.size() * 10); + Large((0..len).map(|_| T::arbitrary(g)).collect()) + } + + fn shrink(&self) -> Box> { + Box::new((**self).shrink().map(Large)) + } +} diff --git a/deps/crates/vendor/indexmap/tests/tests.rs b/deps/crates/vendor/indexmap/tests/tests.rs new file mode 100644 index 00000000000000..7d522f1c970808 --- /dev/null +++ b/deps/crates/vendor/indexmap/tests/tests.rs @@ -0,0 +1,28 @@ +use indexmap::{indexmap, indexset}; + +#[test] +fn test_sort() { + let m = indexmap! { + 1 => 2, + 7 => 1, + 2 => 2, + 3 => 3, + }; + + itertools::assert_equal( + m.sorted_by(|_k1, v1, _k2, v2| v1.cmp(v2)), + vec![(7, 1), (1, 2), (2, 2), (3, 3)], + ); +} + +#[test] +fn test_sort_set() { + let s = indexset! { + 1, + 7, + 2, + 3, + }; + + itertools::assert_equal(s.sorted_by(|v1, v2| v1.cmp(v2)), vec![1, 2, 3, 7]); +} diff --git a/deps/crates/vendor/libc/.cargo-checksum.json b/deps/crates/vendor/libc/.cargo-checksum.json new file mode 100644 index 00000000000000..ccc85371846e27 --- /dev/null +++ b/deps/crates/vendor/libc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"79f4e131fdc5bb4c9e7e0bd24728a9988a8c5d41a0aac106f906a181d3b6e52f",".editorconfig":"e57fecd6b82cd69640ca1bc4e44f0c7acfe5fc12f641f14af9536e323b4159db",".git-blame-ignore-revs":"761aa385c661241fa77c15b502c361398cf500bbb9f8c3a4579b412c4c6249d7",".release-plz.toml":"fcf2d382c4a2abd96caf9cc391b63e0c94d5832f5c48e9ab9eb4b2c847c0887c",".rustfmt.toml":"c88d9ba0e884291a2904d43cc7b940fafcb1ab443cdb7bcfca7117809c4f2816","CHANGELOG.md":"4a8d73789fafa25546de9333d49eed4a1a2e99075fd323b556bc1f65feb19f53","CONTRIBUTING.md":"a79d97a32ebab59a5d7b360f9f9bd5b8e98b58cd83a7c0853059347f1f81cb53","Cargo.lock":"f73065fee2180d2c25908eb5dadd8a152a7906095b1f2bca0f1da26087d67775","Cargo.toml":"9a45433b9dc5f1dcd397062608a320c2ab472319e79566ea4646dfff3ca67821","Cargo.toml.orig":"1aa1b972f961d26c76f62db1292be9d7fc4d24ccccbe8a3c22ffd3a6fc1c2c8d","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e","README.md":"cc560a2a9ab2a264fe78ec49fe5e5aed8cffdb8ad011a7dfeaaccbf161696bd8","build.rs":"4b348c53d0a0cd0067ef9887b50f60a1fffdc5d00dda5c0e27fae6aa0ce3dee8","src/fuchsia/aarch64.rs":"34105478e20e9ce40b9e484eea6494e2408fead17c13500da90a2d44d996ce63","src/fuchsia/mod.rs":"b4fc067b8408844fb80be9d017896e41763e2595fcd3526c4fcfed809dd90459","src/fuchsia/riscv64.rs":"a91ae8276df139f6181591be7209f9a68e9f3de5eec881c2e1c9768c53c4e292","src/fuchsia/x86_64.rs":"543ea567b29d646afc026956ee5e652c10e87256789058e7e39f91bf2fe8bf14","src/hermit.rs":"b8e56d680321459a27740aa95fe6576ee6d4e223abce74c0a4795fe998c6c30f","src/lib.rs":"cc2d16d6a06b312913276cb785d637d0755e3afbafc92f18376692dc31e1dc77","src/macros.rs":"e1a7439f50a1d7a47a3268b625e36e7c9a916909f5b3a7fae35217e454e5680c","src/new/aix/mod.rs":"df0de5d8e452a8abb27727b8451b2ceff3bb856f7e5d9e9306df5177e4c6326f","src/new/aix/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/apple/libc/signal.rs":"a960b6153775d791055b278534f79e21f8ff76c2c0c2891271e7abdf26e193d3","src/new/apple/libc/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/apple/libpthread/mod.rs":"1e99efe513b0ee1fa6e53daf5950fc027380b1d71d793eca9e5b22af7b331b5b","src/new/apple/libpthread/pthread_/introspection.rs":"3c797ded6d1a55670f9537a997407cf2267e6c7e7dbfa360d32474e2432979af","src/new/apple/libpthread/pthread_/pthread.rs":"c2b680120ec8db839e702c4340bc39748ac34c806b5fc08acea0a4593131a015","src/new/apple/libpthread/pthread_/pthread_impl.rs":"57a9925a75b79d092c65288b8a8eb21bfb6c7de4c70d37a49018b4eb8b32a646","src/new/apple/libpthread/pthread_/pthread_spis.rs":"1ba51c251249822fae222db6a19e17278ffffc424fc6eea30282a6171491edbe","src/new/apple/libpthread/pthread_/qos.rs":"40f816fb6cebd19ead21197671e5425b454144515ee4b966d00db32ba6b0dfe5","src/new/apple/libpthread/pthread_/sched.rs":"7b22a3204e72d5013ebac7b830235d50883aefca86d720f1f38b93d54e309477","src/new/apple/libpthread/pthread_/spawn.rs":"daef8af8ed0b3d16922c2f5a511a67f57f69b5f80dfe37362bd0b410213f95ca","src/new/apple/libpthread/pthread_/stack_np.rs":"d1b6e2eab1850c303f8eec4059b3e8ec57d69eb47c216243f6b4b7523761fc29","src/new/apple/libpthread/sys/_pthread/_pthread_types.rs":"a7a4307d7c3f91a6b03f76599fac5f40de556e5652123c6bc3b95df2bfa685de","src/new/apple/libpthread/sys/mod.rs":"337265fe49d77a7dcc879cd23e4f5baedcffab4808433dfb6ab9deb4ab490380","src/new/apple/libpthread/sys/qos.rs":"a6297cbab4089b330416bfcbe13b6d7aa8e75352299295046429b2e9d3bada42","src/new/apple/mod.rs":"45464bc6661b88e55856acb6ce4c47467a9aba44083e42b0e0d87d80ca3c11fd","src/new/apple/xnu/arm/_mcontext.rs":"63f1c62b47e7d7181c2b85f3cd3833c69a29eb0cad37a5754bfa6b5954ae7f6f","src/new/apple/xnu/i386/_mcontext.rs":"50543eaa5cf1d87f900b0c3e531dbfefd7586e1be2be3406223b2319edfcb7f2","src/new/apple/xnu/mach/arm/_structs.rs":"8e4af554170cef61c9143f92a283fd7eef66ad78824f194bbc89b098c6049a43","src/new/apple/xnu/mach/i386/_structs.rs":"d7316b7d3fa5e55a5818cfd8a1977921bb14e07133648cffa8f4d9da2e31a604","src/new/apple/xnu/mach/machine/_structs.rs":"82f5a7f751897c882ed4c378d6282976ff21cf0c9cdf7f3be3cecd369a63b6f8","src/new/apple/xnu/mach/mod.rs":"46aad5c7197df2cc57c4392d9019034236233f0240bc7975f9e22ac33c9d40ed","src/new/apple/xnu/machine/_mcontext.rs":"166b0a450b730e2a943ca08a0c70061effb77ff9eff6f41c7b0c51b2d4215db9","src/new/apple/xnu/mod.rs":"b35c4301d54dd2a207c32750f09f989dcc2de6e470a5cfa936de69c550555c7e","src/new/apple/xnu/sys/_types/_ucontext.rs":"1651132d39042f0fc8cca7a23c890da0031b74359472189f851fb3458f2fde3e","src/new/apple/xnu/sys/mod.rs":"734e1803a311320fd6f0b7b10929fe90a0b27322e792c95d42c620cc59b25563","src/new/apple/xnu/sys/signal.rs":"a03cb64ec19326657c87ff8a5a31c2e6bc1deb55f9a7343ab1b2420819ed72bf","src/new/bionic_libc/mod.rs":"5b2b375123095ae59617ffc1b5e13970ae685c823e3cecf014a173d56162d77c","src/new/bionic_libc/pthread.rs":"d40b7f8421cf78d61f23224c3bda17407e40a1c85dd8122ca4f290624b21d8a1","src/new/bionic_libc/sys/mod.rs":"570e7c97f7c1efb14e167a3f0688547fbc907ed9dca93ad6d90dc719289cb6f1","src/new/bionic_libc/sys/socket.rs":"19877b1de0e235a01734f9aebf20fc1ff1a01fd17302ed1a7d7b520a9fa68edb","src/new/bionic_libc/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/common/bsd.rs":"8282cc2b87ca3afc6b01216fe3c3fe1818a3d57e95aa8d1e1a36cc5af1660609","src/new/common/freebsd_like.rs":"156dce9baa6b0ac57d483ffb582a913b9e4944cf10bbb5711a64da5f496a55c2","src/new/common/linux_like/mod.rs":"d42e65b3d6fccd5ba85a8397abb28267a96bfb76b6b47754000fbe9332c03fe4","src/new/common/linux_like/pthread.rs":"a1a33b1e27cd159ab1035c73e72fa8b0c266dd5a28f1079ad74d3c370857f097","src/new/common/mod.rs":"5bcbce2960ff0840ab67a1ba5011009fa1f0f7697cff745d1461bf2b1460ddc6","src/new/common/netbsd_like.rs":"4327dd28d929f2c7b316f9241c44da6f6069d3db4381fb82700ec6d70d749041","src/new/common/posix/mod.rs":"f64b9d7f78e924529c62f2cd78199075eb334e0db9479cb59787f2740bd82d51","src/new/common/posix/pthread.rs":"7bd380ac6cda7940f5e160b6f9d1cf45885f2ba1d7e96014828b13e830eaf230","src/new/common/posix/unistd.rs":"3f633a8c6776d1442f014717785fea3f068d1d3edbfad545d445f8076cb58447","src/new/common/solarish.rs":"ac208e1ad95d07b7528419fd9c573612d58af3d50766816b81667570ccb8b3b3","src/new/cygwin/mod.rs":"9de4cba157252e7731256d60192468f5a759ebd33ab2b509819ffc7557adced5","src/new/cygwin/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/dragonfly/mod.rs":"7b96df7e566874a736d0c33ffc9e75a5f80e674da990cb664556728769ff25f9","src/new/dragonfly/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/emscripten/mod.rs":"d0ec81b919d9d078bb7d66d9429c08b609e2b0fab512be30aa22cc00fa620660","src/new/emscripten/pthread.rs":"65b51deca94ba18d81608191a5523c37f9508a87a76934006d1173869996531c","src/new/emscripten/sched.rs":"6f0a5b3cefb42bb01feabf34ad92d4bdbe5743263d4cd7b754baf921da81a127","src/new/emscripten/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/espidf/mod.rs":"c89c7d3b96583d84888aae0c463dc49b5af61b34a97e9cde52fb9b62d301a023","src/new/freebsd/mod.rs":"cca5cd6815abcaf276799618b748117eee7a6484bc48c629773eaed622188ccc","src/new/freebsd/sys/file.rs":"4dffceca36eaa53c3ace434e4fed1309009448c67ea6684a067a2cf362235e02","src/new/freebsd/sys/mod.rs":"1b064e41914b6e434be2b0c9d3f21f0365eaeeb358a231010c9b817bbd8f730e","src/new/freebsd/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/fuchsia/mod.rs":"c15b2da96c52281e86d4f114522999e6e713723f4950d62c2d544be641b28722","src/new/fuchsia/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/glibc/mod.rs":"1867ccaee8fe486b3723d683db23b40b2ff0c029c9d6281fd63d6de9de77d4fd","src/new/glibc/posix/unistd.rs":"b8528999ecab0a4883c0d89b1cb3c585a666255ab4a4bf5bfc705f7613edd8f4","src/new/glibc/sysdeps/nptl/mod.rs":"36c75e15c94efdc9db1ff8747cc557b5a314e0e3fdb006581f4a96b322ccde9d","src/new/glibc/sysdeps/nptl/pthread.rs":"b3bb630c736ffbe99081f5bec4c99f50cc36fe159b8059594b1d6965d178936c","src/new/glibc/sysdeps/unix/linux/mod.rs":"9a7c4d5c62c37166b35d2daa69a3dc8f5b4548ef49955463ae41393e260a4cb5","src/new/glibc/sysdeps/unix/linux/net/route.rs":"d8ec70bbaa919692430fdd608b70db11dbfe86b202760727dfd474a4b25b35c2","src/new/glibc/sysdeps/unix/mod.rs":"aa6d2fb4c32f5e1139cae14bcf7cee5935657aeff97df9c064ae9acd67620d04","src/new/haiku/mod.rs":"b3863768692c6da24fc28fdcf0c29a9dd9e3a84f301d4bee6ccc4f802befc4f8","src/new/haiku/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/hermit_abi/mod.rs":"25e5d698f292b95057f18dfe203fa96316326e0ca103da532190bb17c29cfdcf","src/new/horizon/mod.rs":"44b47e15d429026d369adfc16a4e9783cdda1be3d0a04f17c283da06573df886","src/new/hurd/mod.rs":"190a149192c237634df3e49c4834d05299aee91a3d399f356d97c36d35571a59","src/new/illumos/mod.rs":"eb5dd158844f63375a6fbb881d63279b12865342d1bb0da221216b7aa9c474b5","src/new/illumos/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/l4re/mod.rs":"d0cd277d7c0b32cd5d3619f7a188f3e646da8f71ae07012dccd921b3fb2b2300","src/new/linux_uapi/linux/can.rs":"b30565ca3a98f76f98a6410fdd0649336270aa1ae4c677d1ce0d67a9be8803ee","src/new/linux_uapi/linux/can/bcm.rs":"1718a1c3aae686d18ec83dff1560439d61de244bfaf332256cc2b42b85fe5249","src/new/linux_uapi/linux/can/error.rs":"5c5ef6d7c2b9432ebbf6147f96cd260e10686f449f879e64db4757670a6ec638","src/new/linux_uapi/linux/can/j1939.rs":"ab2a330c3d3cca3ac6a693b381661772036e10a6dc0004db3809a4f42cf724ba","src/new/linux_uapi/linux/can/netlink.rs":"2d90a0cb5dc9a15365c99c5101db1698f2da2df66704cfefdafd06252bcabe3e","src/new/linux_uapi/linux/can/raw.rs":"933ed151ce976b869b239abc031bb626dd3fa48ec3dd63d2c2b1b891c7bedf1c","src/new/linux_uapi/linux/keyctl.rs":"c25ee20a54a14d56de2c886c32f718b7a403b18152cc81bd7726f974cdf5b3a3","src/new/linux_uapi/linux/membarrier.rs":"5d6b55b1f7410aeb24ce6bcdbac0d33144b14dc048641ebccb5adc697ea7de2f","src/new/linux_uapi/linux/mod.rs":"c17b121acb9e3bd807ab58e532a19bf76f7a19a38ae94e7812beb14ddc3362b0","src/new/linux_uapi/linux/netlink.rs":"1ee00c018a23cac0ade157d6c725b3e6f0b69b23b46b9690c5ab398c889527b7","src/new/linux_uapi/linux/pidfd.rs":"6500c63d1ccaf4b7e14a36f225fd309bce9de80a50b81bca14bc6bded6ebd04e","src/new/linux_uapi/mod.rs":"76cc081d46d008fe05fbb3d7f007fb62374d4efd9464916bbeb9b20c288c6416","src/new/mod.rs":"360bd97f6f1cc19143289c05c0f9e3b86029918f6d9ed78d09c752c81a53ae6c","src/new/musl/arch/generic/mod.rs":"106383ed35cb7526bbbb0e16ce3521ddb2a9e61fb533687922fc9b43cd654af7","src/new/musl/arch/mips/bits/socket.rs":"eb4dff2ab581eb893e0e6547ae7a7d86453caa069b61272a818256280a23ca71","src/new/musl/arch/mips/mod.rs":"cc6c0a24ef77b7c404887fb5b7a7fd15c2a79e2a3396531ea0058636cacb3018","src/new/musl/arch/mips64/bits/socket.rs":"eb4dff2ab581eb893e0e6547ae7a7d86453caa069b61272a818256280a23ca71","src/new/musl/arch/mips64/mod.rs":"40242447a56ed21249f0417f87a7ccd074a366f19eb1353d94e904f370e0f20f","src/new/musl/arch/mod.rs":"31a73fedfd8606e04352425fb4917181f2d7376f445cb61a5460bd682ce29ed4","src/new/musl/mod.rs":"6b2e092bdc907d2d236a5f6ad977d931e13e99425a3738a62769220697cc13de","src/new/musl/pthread.rs":"e76e8f71cba55b45e4aa954970f939142595b828fd7e83586fc9145299a3b1cb","src/new/musl/sched.rs":"6f0a5b3cefb42bb01feabf34ad92d4bdbe5743263d4cd7b754baf921da81a127","src/new/musl/sys/socket.rs":"ed9de77a5937115aada325ce3d68b31e24e7ac21691dc2cb52c4e4695aa1e1dd","src/new/musl/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/netbsd/mod.rs":"d7bddddf98b09188a6fe541feaaaecdee85eb55fee2aa3cf670f7e6afa4ac342","src/new/netbsd/net/if_.rs":"5083d0f9d84de47c8b6fae60c9bb74d7c0586a80ccb8d625e5e2b4876e7f9444","src/new/netbsd/sys/file.rs":"a30095d85a4f8af49494f9b38114415f5c30e1d96a8c882eb7efd83a1cb6816a","src/new/netbsd/sys/ipc.rs":"91af85c26b3dca2a0661c820871d176baf29c00d53540f4807b9b28f9f3dfae4","src/new/netbsd/sys/mod.rs":"2dfbbf18e7585b64acfeb2f39d0495b50c142caec680db64bb4655e182347262","src/new/netbsd/sys/socket.rs":"a926087991d4cd7ebe31a3f626b5a196047c20955e9e3c99f5abe50b899b1ef3","src/new/netbsd/sys/statvfs.rs":"875c73a2c18ef78c7363b2196282579b88beca2d42ed24bda4fe8e7800db9bd4","src/new/netbsd/sys/time.rs":"7d420d5384e13ca361aaf9a7fc9faafe29a55b216988c8252a891d2232407a0c","src/new/netbsd/sys/timex.rs":"1b476328c16ce06e316485bd9dc751f31e51f63d0c07e438bf3227e66da07768","src/new/netbsd/sys/types.rs":"a0ec3ac038f0026c285ebfd869a8ae062117b1ff29855cbcf570f7f55860c854","src/new/netbsd/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/netbsd/utmp_.rs":"cbd35108f4ad7fd3c4fc65b888ba7813a29e3ed4af7920604df8085345f81973","src/new/netbsd/utmpx_.rs":"27171f826d6d2bf962a1d973a3427477ae960ad5dccc947c481d45f17ae645f0","src/new/newlib/mod.rs":"046372b698393e20436c85b28dac6f02b5cc7d599d134637bbdaa89f2530d1a6","src/new/newlib/unistd.rs":"15e74fb2c22e2343faa06a7a61baca198d7867cd70f8a4ead6cdc1f4fae24905","src/new/nto/mod.rs":"2e80a71385d3344a5f0b95b8d509148b52ea1a253d87e8f27345956d119f7e58","src/new/nto/net/bpf.rs":"1ee0b92315fb2926085777a024cb92d7c1f71328eca1af09a3db0417f180d263","src/new/nto/net/if_.rs":"cdea96569bb155c7372da481dbf00630aadfadb68ef07bfe94d258a6c600b82b","src/new/nto/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/nuttx/mod.rs":"7dbbf039987cb5ca17d2a1a562dc967de1c31b970568f728339cd5b9c8e05e25","src/new/nuttx/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/openbsd/mod.rs":"7d86ff099ddfdc8c383f49a1f6fa9c1169810cbe0c1c57d0e86dc14cb1d87320","src/new/openbsd/sys/ipc.rs":"dd37c821138dbf723d637319ad0849e9ed0b2fce1d498e7e38627a8b0a8bf142","src/new/openbsd/sys/mod.rs":"a8fd8f1cb50bffb34db04d1040048e7c23043fea834c1915453b5d539034a845","src/new/openbsd/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/qurt/dlfcn.rs":"8bfec94f78786e2eee9d4306efbf9ad977cf2b3f0d930f8cc65186e922371a9a","src/new/qurt/errno.rs":"2456f7f7557e4716f8b65b1ef67281f795c70ad1d5515d6b001d26c07b943af3","src/new/qurt/fcntl.rs":"ce176e0c9fb6799004cfc9f1fe5eb20ab7226cf8d304bf8ae9cfe4e3f37ad680","src/new/qurt/limits.rs":"5c76ea0d9560d5da65fe7ecaba8e45766dd56b203523979359e5436062306359","src/new/qurt/mod.rs":"6325ef45b6ad49aaba335a52b85a90eceaf5b2d782c06210edefc1999c1fcf99","src/new/qurt/pthread.rs":"8e64d22f2c73ea8559bd7c4de5d21b077969638e1e12c979c1d77c1a2ea2aaf2","src/new/qurt/semaphore.rs":"eb995a92cdead52ee61c3f498c7e408430b8430cd6cb6be74b47e6728c6773ae","src/new/qurt/signal.rs":"3d9b0cdba135af86fed0846b710fef48edba54a034e14147c7e7785db282a335","src/new/qurt/stdio.rs":"280e1faa29c7e2749469a9f9c4b0fa4ba8e0cee42a6e53d9376be6b8e3b8c2ff","src/new/qurt/stdlib.rs":"7d2aad4837a4be08083be8153ecf3e95d8c70469598fbad25793c4cfed1939d8","src/new/qurt/sys/mman.rs":"c0b862bf262564507796b1cdda967c601d265e6a1f1abfe1a5b6d45aa0742df6","src/new/qurt/sys/mod.rs":"e8585c4d447d02d1f4b72183e3d8b8c0d57301ca7099534ce2086a7a3d384b7d","src/new/qurt/sys/sched.rs":"12dfe86d5bb8c96a8624b3a408df7bc1595dfc71ca870e9ea586f68a32bc67f6","src/new/qurt/sys/stat.rs":"bbd98cd523dfc7e34c163bc2d397be8ed08401fe24d85d617b581d31e5bdb708","src/new/qurt/sys/types.rs":"c23c7f02eaa198f04991f0dede9e55279effd49ec4a341fb13064f68c19f24ca","src/new/qurt/time.rs":"598e21d7205714c2f8c92e7dd1f6f7162d5552c453ac68aeb3d38346cff52e4a","src/new/qurt/unistd.rs":"49b2b023a1276f9de2e093f03609e8cb5b0cefa9f0ea96b5bf3009d159b0dcd8","src/new/redox/mod.rs":"aaeaa40c0bffde42973cd1809c1c845075f92fac95a074fe3d01d4fb02dc0992","src/new/relibc/mod.rs":"5c6955e052d8b7ead97179e356c369ffcc435e09fcca4def3e100568845e7296","src/new/relibc/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/rtems/mod.rs":"8ad621434ced0a9d1c0ed5d68514f59b0c8bd4c77fdad81eb09e671e7a42cf1d","src/new/sgx/mod.rs":"c500dc72eff5cbf99c9d7e0e3f1faa3c680bfd7f6ac0166fa1a35fd0d7e69f41","src/new/sgx/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/solaris/mod.rs":"ce8a152ebacb9e8e0d87829d166e3ead64222ead397371bd557e18eefdcafe3d","src/new/solaris/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/solid/mod.rs":"dc5c3c8a627972865ef0a968125e74b2f87636dc89dd2df0f7cea9a40d7c6beb","src/new/teeos/mod.rs":"1d69f212e2a848a32292eef9ad16a44a8d5cf80c7d43db5f445dbd1a49400e3b","src/new/trusty/mod.rs":"3f009fef70cbe062126c82f1f9274cba60b12d3766b825d66326666a1f240fc2","src/new/uclibc/mod.rs":"c3f988f3eb289ba6bc3b2535b82163a7ff160288b7494c156f0fba62143cf2d5","src/new/uclibc/pthread.rs":"ab235319003806c5f20aef5f851af472480e88ff13d2a5f730870efb95e7982e","src/new/uclibc/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/ucrt/mod.rs":"4fd3a973de4c4c6349e76320e09b13701ac284e7ae03c671054b1eeebb86215d","src/new/vita/mod.rs":"196d6ca5c9b1ccc602a6270c3cf0b0bdbd39246066d1a8385df03ba45b31d368","src/new/vxworks/mod.rs":"fa569763957eb87e7e1ce5fa07293116c66661ff0c21d277fda5b30c61451176","src/new/vxworks/unistd.rs":"bcbb65f70759cd84c81fc24ea36aac423edb8f9d7148f65b545ee63954411fd1","src/new/wasi/mod.rs":"2a74140697bc528193214aad11edc632923bd0cf8350d24f6d600f849dd19e19","src/new/xous/mod.rs":"69016c5c153d9a14003b15558cab96b4691a927586c20ca493fc8d3bb65594eb","src/primitives.rs":"af323402fee13278461bcaec6a06a15dfca24a02d48b0570c88e2746288d7078","src/psp.rs":"081cf4e5127ba10ebb62a9a5f8f849dd92742693db443db429d446ee472b5d41","src/qurt/mod.rs":"5af8edfb34f5431586b7ae00b341daa4312737c1e39c16348b1fff1d1cb8c642","src/sgx.rs":"964d6af358f5c85f948275090e5a7854e0169c43b5c338070b6a4cd156ebc9e6","src/solid/aarch64.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/solid/arm.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/solid/mod.rs":"0b5a07cf7df8227fecc13ea5b7ddf0bb9520c8be44bfb8c15f9449715911dfa0","src/switch.rs":"5db5be2d9c235c00f74b25cceabdf2ce5ec9e1936f991815513e4edf5dec0d56","src/teeos/mod.rs":"ad18343da08ebb6c1fba77fb8efe9ce4551519bea617c1a000aa92f3e50b8565","src/trusty.rs":"cc90bf6b35a515021a3155aa3cc5fcab33457b8fbb2ac7259f0b694d33625fd8","src/types.rs":"5d7831b60664bbe955e00b9b8c75cf834e27295ad36f249f9aee534f533571bc","src/unix/aix/mod.rs":"89a4848c84c15b827021da8b92770d73505bb2edf3ca2429dbcfd007dec02721","src/unix/aix/powerpc64.rs":"724b02ca3afb2722930de172b3144a6bffb70792612a7fbe53553cac58bd2ccc","src/unix/bsd/apple/b32/mod.rs":"30a6d351260806e98666ee4ba64b783d1fe1d8b1d32c3ba7766bd5d638dab2dd","src/unix/bsd/apple/b64/aarch64/mod.rs":"bf2e39a80c8d768c2969197b80fafa50608ac0186b4f4aea53e7fa8bf40d2214","src/unix/bsd/apple/b64/mod.rs":"2619b6afd99e938157753c436e969aa1703b0404b913e456e469df5c6d69538f","src/unix/bsd/apple/b64/x86_64/mod.rs":"ff16a360cb478a4c2e912b9779a806d0e3439e4c5110e0325c82af5ee8429591","src/unix/bsd/apple/mod.rs":"8f3299d0de1c3f39aad406c7955760168734300d62850bdcc862611fc25a199b","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"3ec640c35a0b5c0dfdf3fb981e6c3ac74e33781941ecca67390d076b167b5564","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"f13a68b825a58596b5d3339378b0812b778481a291aeacb41de74cb65ad66d3f","src/unix/bsd/freebsdlike/freebsd/arm.rs":"d627ed0bf17932ec0e3226944a4f9714805b27a953778b309d914545cf21b82a","src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs":"316e70938d2b050fd67e5aaf0bcdd0a70d55f195b26ce4ad6055cdf05cea2e61","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"811c3f1aeb70dfd051abc9d3357e8eca9564c08b85d3ea6f81caacfa559e3060","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"87fdf9253ff788b9b66d0bd26b1e7e401e80d165bb4278833dfb80046ee06064","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"7153ee461d9c41e5b849603561dd118091af53a7c990d94a171a4e1412381ec8","src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs":"64c4bd82eaf30a2681417f982fce28de7d1b0743bfaa14004692a56cee44be21","src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs":"bee7fcbb5ff8d1a011b56afa025bcab87bff3e3f90d5d4e0bbbb5349f5bc6b5f","src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs":"64c4bd82eaf30a2681417f982fce28de7d1b0743bfaa14004692a56cee44be21","src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs":"4dbfaa01fce15bcaaab3d70f9f8da3b2e34a93cb2ca0d380b582926bbe43c2ce","src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs":"d6e66809e109dc779efe5584b79d34fcd6fdba91973a415d64ae66f481f45940","src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs":"55c0ce55e6c140d9c0c8b3fce76b23e975eff6c4d5eeb14c9581f8e51638e34a","src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs":"d6e66809e109dc779efe5584b79d34fcd6fdba91973a415d64ae66f481f45940","src/unix/bsd/freebsdlike/freebsd/mod.rs":"ab3734f8aa742fe5c3b5e31c29f0a99e7522abe28b3f7560ccf01f7c64305ca8","src/unix/bsd/freebsdlike/freebsd/powerpc.rs":"af7a43826e3ca9e5e7c3d7c1b50defa482074fd9909de3ee2e52cd0109c1a950","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"f7be922bddd7a4b7da863d6aba057aab2d27f500c7101596bbaaccf075133451","src/unix/bsd/freebsdlike/freebsd/riscv64.rs":"69242a001ab21b6e06b7442c37a89dbc5a67660c7c3cade1d46b65adf32a5669","src/unix/bsd/freebsdlike/freebsd/x86.rs":"5165242f0c82040898dbf711294ba45c5ab2635d39d0bbf9cc899b816415e2a4","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"84044f397dbf13a1c517885c7b234efa2900d116324a4cca626d2f8df398d655","src/unix/bsd/freebsdlike/mod.rs":"c183016e0d192bd490958e4aeb5022dd203ca288abe8f1f502b2d1215b47e30c","src/unix/bsd/mod.rs":"a51588c418deaa58acecddc08c3578cd45659af7a6aec055447ec05143534b0d","src/unix/bsd/netbsdlike/mod.rs":"78f8873b9b91362253031ad6d3d6ee61640496b1c24b75b3ab9186e1eb35a545","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"ba2425edbf025f13ab3c3534d1671d310392df3a7d237539817d9cfa675971c8","src/unix/bsd/netbsdlike/netbsd/arm.rs":"8dd57613695dec1b2104ec35839f0b9b6d234c6cc80365e9fef9ca977c1865a0","src/unix/bsd/netbsdlike/netbsd/mips.rs":"20cdd8d1427c986ecc3fcf7960d337917a13cfd8386dd2d54f8693a23d60892f","src/unix/bsd/netbsdlike/netbsd/mod.rs":"12d1e288aa3c351000721502e3cbd7115d7d5584ffc5c37f5c00e9c56f657385","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"c19c4edbc73b5a97b51e3e2ad39b9fee02ad15e80c70ceb3a1abfe977e5c0ead","src/unix/bsd/netbsdlike/netbsd/riscv64.rs":"f446c996f00e4d15fd25461a30c767c05d083df9e047b0da497ce7c545acfa96","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"d50816e830225779ac9e9a55a7e3e097882153d72987061d76a96ee736c8af9c","src/unix/bsd/netbsdlike/netbsd/x86.rs":"3006b6a086c0241f5383ca101e7b9357368d713f9c38400633491656d110798e","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"13dd36a0db740930155b5f28fedfac606c7291c0276bbf2c2b3fe03a4dbd2a51","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"13c91b304dfb5c3c26777863827c7b3707fe245fcf50da32caab641aff998c63","src/unix/bsd/netbsdlike/openbsd/arm.rs":"f064d935f416ca9f7e5e767b9b46da2250c997d667c0c7f4b4c7dfe02d0258c3","src/unix/bsd/netbsdlike/openbsd/mips64.rs":"bee7664d88f8451ae22552fc0721b6b6a6dee2493cc42bcb9829c1e47e4b05f5","src/unix/bsd/netbsdlike/openbsd/mod.rs":"9943458aaf3a35ce0d3b259b0b666d29347b04cb1a1722e6450073e71f894398","src/unix/bsd/netbsdlike/openbsd/powerpc.rs":"f064d935f416ca9f7e5e767b9b46da2250c997d667c0c7f4b4c7dfe02d0258c3","src/unix/bsd/netbsdlike/openbsd/powerpc64.rs":"1f62a42e2970c42de9e3492fbf3cd5b45410889f033743579266342d1a9e2a00","src/unix/bsd/netbsdlike/openbsd/riscv64.rs":"b2cf3778bfb51d1c0277f0e92963a04f734be3e29879c6c09a25bad2d9b5ab6a","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"8d4c5a4cae63e09e1c156164ddc82e0fc77926841d4d4e419dd2e7a7b7145f58","src/unix/bsd/netbsdlike/openbsd/x86.rs":"e6da2fdff7706fd3eac147d3aaf16afdd8542f231f502660d1d89c79b5eca21b","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"bc7ed75ce66059aafa7a86986aefff267b2c951e47558453fe13ce1bdb48dc0b","src/unix/cygwin/mod.rs":"0da02791aefa8c45531abbea9a9f55b3c3d0d7e8d9af0c250d969ce22b48ee95","src/unix/haiku/b32.rs":"c3f8678ceee65a3094d8133b0d1a94470860e0b1867977f0569c52c5a20e039f","src/unix/haiku/b64.rs":"f97ce9225f4710893dab03ab3e13bc62152cc84f90c597ec88f6dc1f4c27d242","src/unix/haiku/bsd.rs":"4d9af31fdac2561ee5f942dca97dd2f48139ca74660d40b854b307fa5679d1c8","src/unix/haiku/mod.rs":"5a619d44c8e1205ada8f4bf67cf94b8f133949d15d505cba5dceb65557eaa736","src/unix/haiku/native.rs":"85836b1063ddc01c176c61cff8c006cf6f5dc4b1f465f41b5c330aa372a44ab6","src/unix/haiku/x86_64.rs":"def40c16609b5d62c3cdbba6a38340720a96b326ad98d53838554e4b6878d2ee","src/unix/hurd/b32.rs":"501f426f7aeb60acf4119064100dd94bbdfebff2cec785428708059d853dc123","src/unix/hurd/b64.rs":"b9b2082e721a5ec89ba55fd5a16bbffcc8a05ca7cef6dbfbd78aff0806cb931f","src/unix/hurd/mod.rs":"287a2fdd2065fc8a13c4932b3f241d1453607e74829b6d2012a44b6f5f36f654","src/unix/linux_like/android/b32/arm.rs":"5c6ad12746052b86846f9d7c3bd484d15bd3e2113785a19220186ab2a9bb31ba","src/unix/linux_like/android/b32/mod.rs":"04edc73374218c6b854929cae4bc5171ad5066f3636f87235640ec20a49f1559","src/unix/linux_like/android/b32/x86/mod.rs":"72cd0fb5a067170e7409359b6c0114f5472e313060b9642e2e48dc9fabfd4614","src/unix/linux_like/android/b64/aarch64/mod.rs":"66def5f0af9594af50535eba7501bce89620010a7d7aa769ef401235b03efa88","src/unix/linux_like/android/b64/mod.rs":"5afe4dc379ae30ddab9295e5ab8ac89f39f5129f519612d7528bfbfeb0a1d934","src/unix/linux_like/android/b64/riscv64/mod.rs":"47c97eeb221c48bd08c2fc2ddf5f9f4d20c185df76681fe14e3a0950fb37ecbf","src/unix/linux_like/android/b64/x86_64/mod.rs":"4d6eb98fd17e821d0e05755ccb3f4f2b6e37bfbab533894ed444138b750e6b08","src/unix/linux_like/android/mod.rs":"9f0cce22a507e263c4a9bf3501fbd85e14b2e7e9a71c6fe1e046ee051470a1eb","src/unix/linux_like/emscripten/lfs64.rs":"486f987bc39653a48e6538ab0e8263cd2c1bd3d4732a2c573f89f7a037936c38","src/unix/linux_like/emscripten/mod.rs":"538dbcd492324f0254c1ed1f66ad8e7bc9e367cdd70a004cb0183b6fb368e64a","src/unix/linux_like/l4re/mod.rs":"47c07dc3c5e368ec9a64b33af9a314f51e5ed6c7fc6456bfba919d661a812275","src/unix/linux_like/l4re/uclibc/aarch64/mod.rs":"3111d03e5f43dfe1639fe7189903044cb980591c0580a62e8b511de4943201e2","src/unix/linux_like/l4re/uclibc/mod.rs":"3678301a89b80f638ea90b4ec2e3d225bb186eaba3d07f324969e46b81a1955a","src/unix/linux_like/l4re/uclibc/x86_64/mod.rs":"89bb7c67398c836c7f17727338c6032e7667307f02ef0f5d0121031fea1aa358","src/unix/linux_like/linux/arch/generic/mod.rs":"f531e877d712eb30cddf97c76273b7ba7fef19cf8eaafd60ca9ac26019b49adf","src/unix/linux_like/linux/arch/mips/mod.rs":"dcc1d2e85dd2087f61635c753d1781ec70dcba5c95aee285255f09216ea1e0f8","src/unix/linux_like/linux/arch/mod.rs":"8bc5898b03760a95dd4f124ac76ad92e5ae36b2d0644203d752ef2b37e487c3a","src/unix/linux_like/linux/arch/powerpc/mod.rs":"77b286fce4ac755ec840b9c70824a648314b3a5ed2a385d291138589647fdbaf","src/unix/linux_like/linux/arch/sparc/mod.rs":"46f3bd08ec01147af43c93a22c21956af038fa5f6e56643f8e39ca30721bf8cd","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"60d5c7667d81db0ad9faf65edc79420b2100cab27699e03de4d415de931e9f58","src/unix/linux_like/linux/gnu/b32/csky/mod.rs":"627e61997c33fc12fca9e337d248d8531ef0751f21f70110b65631a0e481b66d","src/unix/linux_like/linux/gnu/b32/m68k/mod.rs":"2ea8f649fc9f01829de439ffe0fdbf9566602ed6ec0088128167af1080c3a1b2","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"8b3254b47401cde6118f9eea7e98319af8174d99feac451949e673a28ed4ff6e","src/unix/linux_like/linux/gnu/b32/mod.rs":"5ff89d834a09550c9393965bfd2b74e0f9ab6059bc76f2a827faed631afe10a7","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"585983c6617a590ee0ac5217280d03642efcf721bd80fdabd6b9477031574fee","src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs":"a5e6c931ca8da568626233f2aa5ee0dd0b8e4e1e8905d52ab9dd0ea618376c2f","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"0ddd77054079d7f7ee7aede95552e6494f67fc3db332ec1f5f83a9d09e1a9710","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"e370a80bfdec000347c384f080b30c6f537dc51e17e715c2dd8a360e6a1407f3","src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs":"638b2d717dcf5b59a0058c3dabab43edd84de9d1d7da6e16ad0c58e863000417","src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs":"28c11e70467b2f00735d3a04c369e96e04fd44d0587ee33359f38328b0677ee6","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"7948baae6e8dfbbba78caaea27a2ef059dbe5f0a2b533bd89cc5d6c5dd7f7f1d","src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs":"242cd513eca13d14fbcc326369bb54006782260a558f0c2367102471d4081631","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"007809bca7493eab4ac99a30b4495f73b544d7c882b81b5ca719c1b70761e0bf","src/unix/linux_like/linux/gnu/b64/mod.rs":"64d4182c10180692d381d8eea3d9ce8a6d47289b9c1218070241c5a445d9f1a0","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"4dafacc390ff02ae3c34591a1605e1ac380c13338928a7e2e1ce748fc1e46323","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"f1a54e0bc0d791ad642e07df5f8d4eda1b4d497059c0e5d20b52e094ed635b19","src/unix/linux_like/linux/gnu/b64/s390x.rs":"741d95cf29b65a9fa5c7316b888f8c79f944376b308c7929eb21054b5a16a83d","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"adc09bb20980ee2d5892a2f68949505bed2fa00954b837aa0a15eeb04edd53cb","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"d72ae5556347be715e3fdfc084e7e95a184504f1575230f163ab7a72a405cb24","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"07240332eaf44996d86e37b12d71b519b499c9c9b57898441c58ac2e8c0cb6f7","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"914898b781dfe6b2f755730d6000223d1beea177731e180ccbfdd84a0b8b3bd9","src/unix/linux_like/linux/gnu/mod.rs":"0ff72f74b015bc9ef4d1732fc5594945fdb5ca388e4aa0be71260fecb90e6f1f","src/unix/linux_like/linux/mod.rs":"3d293f05bfb6f9605e238399e404bf77ca91f4f7def6596f77f404c71b80b572","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"7dc4b9a4d723d6868a84e81dbd5953b234c4540db3edd5a4a7ea0e154b101d91","src/unix/linux_like/linux/musl/b32/hexagon.rs":"17063ab52334500ec67d9f1f706bfcd493092d7a7f28f3b5558915cce756885e","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"64f6b834d3d98db1c2d95d40371c644f71170d7710fcdd933f1ff51c3fbe2c70","src/unix/linux_like/linux/musl/b32/mod.rs":"6630c3ae8e27eb2bae6309bef4c96be9a21ebb877ce281b881a73589b7264a7a","src/unix/linux_like/linux/musl/b32/powerpc.rs":"a946612120ed9700ff1e4e729b0f8107a40f9ed7f5b320357552d5475441042d","src/unix/linux_like/linux/musl/b32/riscv32/mod.rs":"df3e3bbd2f69420b6de3a1d9aa242402f0bf26c77c573b2debea53af964f07d7","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"83e340712e8acd89cefcb5eef0e826da79f47a7a42784699df90604c4e9a8712","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"b165f81469b144a9c6d60486c3a8b4770fce5f4ad67958aad3c0b0ee85fde117","src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs":"9885dd43e46d3f34156b2871c3c08a88775efecb9eab0b4ed9bf396c1cb509d3","src/unix/linux_like/linux/musl/b64/mips64.rs":"24dd0c412ae02b84552a1803b4369dcc0fa3b989f9b6a406f404690c757fbc8b","src/unix/linux_like/linux/musl/b64/mod.rs":"1ce1eee49b1c7c5c02fe04b1539a0316becf0295763e3e18b1088895ed937373","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"5f2a8d0a5b6a4d044c75ba433b4f69e27d475cbd5ba81e659e756757b5c36111","src/unix/linux_like/linux/musl/b64/riscv64/mod.rs":"d5298d224be38474d05c53ffda6384fdb24771774e5c19f84898c23e4603459c","src/unix/linux_like/linux/musl/b64/s390x.rs":"77079b262e2fda7b569c19236f264f460c157051bac349928306a07c4cb61195","src/unix/linux_like/linux/musl/b64/wasm32/mod.rs":"bd65c06c4e422cb859be803e0dc7404513c13e9d9c3c672f5462f0bbd3dc8ef2","src/unix/linux_like/linux/musl/b64/wasm32/wali.rs":"006149b7af0145dc40123fc7991d853c7f2c5c77bbc9c8a44c276be0d99a1343","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"4535e44cfc85c66253c4cda347366d54c3ffa8e0b47b4b89cd87d96fb4005b1e","src/unix/linux_like/linux/musl/lfs64.rs":"61b1eae698d93dbd7c665e920ef685fd6eea0c4a2d96acc1d5f111d87b88ef38","src/unix/linux_like/linux/musl/mod.rs":"56c79797cafb7949f639f84a5a34676b34d776c843f0ad49ddca0684092580f4","src/unix/linux_like/linux/uclibc/arm/mod.rs":"9eb48a19e49cd2a989f6daae9552dd477d645bc2540a8bae5ac71894565375b0","src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs":"0b3c063ff6510c68577f8789ff87c1b630dc1c219611070fa91aa2b5b5ec595f","src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs":"3a3b90f896a07f5d17e3440bbff7b3153aed564732ef2e468167c7a425922ea8","src/unix/linux_like/linux/uclibc/mips/mod.rs":"e552f579a8dc9e690891113aa6360607ad962bd84cbb60c370b5c5f7c7d1d8c0","src/unix/linux_like/linux/uclibc/mod.rs":"413b7cc1cd88580162836dc8b1cf1fa569b3431248c13e030a1f50519ddaa875","src/unix/linux_like/linux/uclibc/x86_64/mod.rs":"53937263439095a4af0e5d583eb6cc621dd07a41aaa154b2f4cd1ec799dd7187","src/unix/linux_like/linux_l4re_shared.rs":"c21e27065fb45df318fe76366f8250cf1e6bb0a15394f4d6bc69686d774a780c","src/unix/linux_like/mod.rs":"399dc67be0898f73946145b26e12bf23beeb9048fb86b69affdc56be5622bf19","src/unix/mod.rs":"32699be951ec02142e7de59f34ae0f6162620576a4bd88ae372d39d2027421ea","src/unix/newlib/aarch64/mod.rs":"d72d067a433bf24ee6b6255c4d04ea7c966518b8d064560c593f1ab23c025962","src/unix/newlib/arm/mod.rs":"95b6e4b3cd1eeb0386d4867e9e4c3438305aa3e8ae75697e06720aa06540a666","src/unix/newlib/espidf/mod.rs":"cbaf10ccdb429719003cac3f3cd4aa0aa63a12a383afc5bd88a4ab3abaef9e2e","src/unix/newlib/generic.rs":"c435a955d72878a71ea0719a75a4579818da6a2e01635f9fe1073d9a0d67352f","src/unix/newlib/horizon/mod.rs":"7c4680766b9986a379fc354a183f4072c1c70d643307edd1a0ca8e0f2c34d5a8","src/unix/newlib/mod.rs":"1aac15b55a852732174bcfee52f3b1452c3e491461a87b70a7ee4c97a458785f","src/unix/newlib/powerpc/mod.rs":"4d6dca09ea5dc000cbd39fb939a9b1a743d819931dfca3c896659e919a07a7da","src/unix/newlib/rtems/mod.rs":"7d06863f1942a90c9a6dd412637b93c18df00e7397cb1289176b9a2a19004b7c","src/unix/newlib/vita/mod.rs":"2f9bf66b40c2aa611033faf3ade5510dc9789af7302571fade40a1715398f06c","src/unix/nto/aarch64.rs":"73ad54ebca13454a75c7b0815e853175070a8ac2eefa338012a03e8b59f01e0c","src/unix/nto/mod.rs":"ddcb98afedf905c0af8819af1591a0c7df629a187ceb35108aeaa467c4879746","src/unix/nto/neutrino.rs":"bb9d24ccee3b9e53af6d028f04ecb646e216ac1a9e2b2ade54bc06135ce3ac59","src/unix/nto/x86_64.rs":"c2e46c6ab4c02c8f773298ec1e90eeccac43c09fa111ac9ae63408abc6eff584","src/unix/nuttx/mod.rs":"4083559d825d2af9ade2c3f14e29802315c9a79091ce8d480c438c3242c7ba80","src/unix/redox/mod.rs":"40dbff61515612a7275ca1454a912ddc08f1b6f73bc084f4b563213bd46fde94","src/unix/solarish/compat.rs":"3d120a056208c03215cfbe3eef1584105160d133c0aa4557bb38018c177640b0","src/unix/solarish/illumos.rs":"74fa022e2799fed83ddeefecfdf559fff63e315ba36304845d65c9721b3ce3b7","src/unix/solarish/mod.rs":"03d1a75ecb758dde3c9ae3c3300c6d241e5e2481329724e32cfca6ffd5882cb3","src/unix/solarish/solaris.rs":"2be39ce5f464823359e7e2e4bae94c9acac9245042570df11a0ed75d49f8acad","src/unix/solarish/x86.rs":"44261c1f1b300dac9fa0dab93ec85d0c3b3c48b15bc4515b9820c9421cff7427","src/unix/solarish/x86_64.rs":"eec1602998dbd3b3aeb2d9a5bd66fc53a6fbbcd7967ed0bb2dd61a8c176023e4","src/unix/solarish/x86_common.rs":"4ae02d88622f7f080f5e8cd328f13187edbc5e124fb3e05e4cf212597f6cce48","src/vxworks/aarch64.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/vxworks/arm.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/vxworks/mod.rs":"e687423e39c07ca03d735f464537f40cc6d45407eaf6bbcfcead4a26a2e68881","src/vxworks/powerpc.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/vxworks/powerpc64.rs":"4d4236500f98858fc249f3b6858af5009851c8c582031926b8195b2646f7da5e","src/vxworks/riscv32.rs":"b1f933205800f0da00f975d53b18fe0035e075cc4613acf110a09a277dc3302a","src/vxworks/riscv64.rs":"b1f933205800f0da00f975d53b18fe0035e075cc4613acf110a09a277dc3302a","src/vxworks/x86.rs":"b1f933205800f0da00f975d53b18fe0035e075cc4613acf110a09a277dc3302a","src/vxworks/x86_64.rs":"b1f933205800f0da00f975d53b18fe0035e075cc4613acf110a09a277dc3302a","src/wasi/mod.rs":"bf128fa1c53277185b638eb953c5b8d503ae7a182780470b40b06f7c29331f38","src/wasi/p2.rs":"feecc0485eabd2c32bc5d800df6ad1b9b4d282741342fb08792f2635204e1e08","src/windows/gnu/mod.rs":"6422acc5c5a82122c11efb84882778e30888c0693c0993fbf7f3baa59e4cbbb5","src/windows/mod.rs":"01da11840df8118ad12f40dc38e921b4ecfd1045badc700d456f549789df24d4","src/windows/msvc/mod.rs":"40410b26b606d1b59b0742b2632f3cd0a28a5429f784f9693fae0a78c15b3889","src/xous.rs":"1a83621c40248ad4d0c08e1fd4c1107d5efcbc2f4f0169538b7b4a885abedbfa","tests/const_fn.rs":"8ac3171d7bced3576a4e93f48570b3e00c553d7510ab85a7473ae3b716a812dc"},"package":"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"} \ No newline at end of file diff --git a/deps/crates/vendor/libc/.cargo_vcs_info.json b/deps/crates/vendor/libc/.cargo_vcs_info.json new file mode 100644 index 00000000000000..2e53efb9b43706 --- /dev/null +++ b/deps/crates/vendor/libc/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "42620ffc4109dc32e02f1cae9e63a3f4311b4b71" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/libc/.editorconfig b/deps/crates/vendor/libc/.editorconfig new file mode 100644 index 00000000000000..155c9905f91e13 --- /dev/null +++ b/deps/crates/vendor/libc/.editorconfig @@ -0,0 +1,7 @@ +[*.sh] +# See https://github.com/mvdan/sh/blob/master/cmd/shfmt/shfmt.1.scd#examples +indent_style = space +indent_size = 4 + +switch_case_indent = true +space_redirects = true diff --git a/deps/crates/vendor/libc/.git-blame-ignore-revs b/deps/crates/vendor/libc/.git-blame-ignore-revs new file mode 100644 index 00000000000000..d358a2cd3d3498 --- /dev/null +++ b/deps/crates/vendor/libc/.git-blame-ignore-revs @@ -0,0 +1,6 @@ +# Format macro bodies +50f26e08e146b7e9c7d1af9614486eba327d1e31 + +# Automated changes related to the 2021 edition upgrade +643182f7da26cedb09349b8bb3735c2e58ba24e6 +108310db03e7db35ef48a902d9ce9a88ab8f9b77 diff --git a/deps/crates/vendor/libc/.release-plz.toml b/deps/crates/vendor/libc/.release-plz.toml new file mode 100644 index 00000000000000..6442af58ad98e9 --- /dev/null +++ b/deps/crates/vendor/libc/.release-plz.toml @@ -0,0 +1,49 @@ +[workspace] +git_release_name = "{{ version }}" +git_tag_name = "{{ version }}" + +[changelog] +body = """ +## [{{ version | trim_start_matches(pat="v") }}]\ + {%- if release_link -%}\ + ({{ release_link }})\ + {% endif %} \ + - {{ timestamp | date(format="%Y-%m-%d") }} +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group | upper_first }} + {% for commit in commits %} + - {% if commit.scope -%}{{ commit.scope | upper_first }}: {% endif %} + {%- if commit.breaking %}[**breaking**] {% endif %} + {{- commit.message }} + {%- if commit.links %} ([{{ commit.links.1.text }}]({{ commit.links.1.href }})){% endif -%} + {% endfor %} +{% endfor %} +{%- if github -%} +{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors ❤️ +{% endif %}\ +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor -%} +{%- endif %} +""" + +commit_parsers = [ + { message = '(?i)^(\w+: )?feat', group = "added" }, + { message = '(?i)^(\w+: )?add', group = "added" }, + { message = '(?i)^(\w+: )?change', group = "changed" }, + { message = '(?i)^(\w+: )?cleanup', group = "cleanup" }, + { message = '(?i)^(\w+: )?deprecate', group = "deprecated" }, + { message = '(?i)^(\w+: )?remove', group = "removed" }, + { message = '(?i)^(\w+: )?fix', group = "fixed" }, + { message = '(?i)^(\w+: )?fix', group = "fixed" }, + { message = '^.*', group = "other" }, +] + +link_parsers = [ + # Extract backport patterns + { pattern = '\(backport <.*/(\d+)>\)', text = "#$1", href = "https://github.com/rust-lang/libc/pull/$1"} +] diff --git a/deps/crates/vendor/libc/.rustfmt.toml b/deps/crates/vendor/libc/.rustfmt.toml new file mode 100644 index 00000000000000..42e6cff32e7401 --- /dev/null +++ b/deps/crates/vendor/libc/.rustfmt.toml @@ -0,0 +1,6 @@ +edition = "2021" +error_on_line_overflow = true +group_imports = "StdExternalCrate" +imports_granularity = "Module" +# This crate gets large lists of reexports. Use vertical to reduce conflicts. +imports_layout = "Vertical" diff --git a/deps/crates/vendor/libc/CHANGELOG.md b/deps/crates/vendor/libc/CHANGELOG.md new file mode 100644 index 00000000000000..0e37267c097065 --- /dev/null +++ b/deps/crates/vendor/libc/CHANGELOG.md @@ -0,0 +1,1034 @@ +# Changelog + +## [0.2.186](https://github.com/rust-lang/libc/compare/0.2.185...0.2.186) - 2026-04-24 + +### Added + +- Apple: Add `KEVENT_FLAG_*` constants ([#5070](https://github.com/rust-lang/libc/pull/5070)) +- Linux: Add `PR_SET_MEMORY_MERGE` and `PR_GET_MEMORY_MERGE` ([#5060](https://github.com/rust-lang/libc/pull/5060)) + +### Changed + +- CI: Migrate FreeBSD CI from Cirrus CI to GitHub Actions ([#5058](https://github.com/rust-lang/libc/pull/5058)) + +## [0.2.185](https://github.com/rust-lang/libc/compare/0.2.184...0.2.185) - 2026-04-13 + +### Added + +- EspIDF: Add `espidf_picolibc` cfg for picolibc `O_*` flag values ([#5035](https://github.com/rust-lang/libc/pull/5035)) +- Hexagon: add missing constants and fix types for linux-musl ([#5042](https://github.com/rust-lang/libc/pull/5042)) +- Redox: Add semaphore functions ([#5051](https://github.com/rust-lang/libc/pull/5051)) +- Windows: Add `sprintf`, `snprintf`, and the `scanf` family ([#5024](https://github.com/rust-lang/libc/pull/5024)) + +### Fixed + +- Hexagon: Decouple `time64` types from musl symbol redirects ([#5040](https://github.com/rust-lang/libc/pull/5040)) +- Horizon: Change `POLL` constants from `c_short` to `c_int` ([#5045](https://github.com/rust-lang/libc/pull/5045)) + + +## [0.2.184](https://github.com/rust-lang/libc/compare/0.2.183...0.2.184) - 2026-04-01 + +### MSRV + +This release increases the MSRV of `libc` to 1.65. With this update, you can now always use the +`core::ffi::c_*` types with `libc` definitions, since `libc` has been changed to reexport from +`core` rather than redefining them. (This _usually_ worked before but had edge cases.) +([#4972](https://github.com/rust-lang/libc/pull/4972)) + +### Added + +- BSD: Add `IP_MINTTL` to bsd ([#5026](https://github.com/rust-lang/libc/pull/5026)) +- Cygwin: Add `TIOCM_DSR` ([#5031](https://github.com/rust-lang/libc/pull/5031)) +- FreeBSD: Added `xfile` structe and file descriptor types ([#5002](https://github.com/rust-lang/libc/pull/5002)) +- Linux: Add CAN netlink bindings ([#5011](https://github.com/rust-lang/libc/pull/5011)) +- Linux: Add `struct ethhdr` ([#4239](https://github.com/rust-lang/libc/pull/4239)) +- Linux: Add `struct ifinfomsg` ([#5012](https://github.com/rust-lang/libc/pull/5012)) +- Linux: Define `max_align_t` for riscv64 ([#5029](https://github.com/rust-lang/libc/pull/5029)) +- NetBSD: Add missing `CLOCK_` constants ([#5020](https://github.com/rust-lang/libc/pull/5020)) +- NuttX: Add `_SC_HOST_NAME_MAX` ([#5004](https://github.com/rust-lang/libc/pull/5004)) +- VxWorks: Add `flock` and `F_*LCK` constants ([#4043](https://github.com/rust-lang/libc/pull/4043)) +- WASI: Add all `_SC_*` sysconf constants ([#5023](https://github.com/rust-lang/libc/pull/5023)) + +### Deprecated + +The remaining fixed-width integer aliases, `__uint128_t`, `__uint128`, `__int128_t`, and `__int128`, +have been deprecated. Use `i128` and `u128` instead. ([#4343](https://github.com/rust-lang/libc/pull/4343)) + +### Fixed + +- **breaking** Redox: Fix signal action constant types ([#5009](https://github.com/rust-lang/libc/pull/5009)) +- EspIDF: Correct the value of `DT_*` constants ([#5034](https://github.com/rust-lang/libc/pull/5034)) +- Redox: Fix locale values and add `RTLD_NOLOAD`, some TCP constants ([#5025](https://github.com/rust-lang/libc/pull/5025)) +- Various: Use `Padding::new()` rather than `Padding::uninit()` ([#5036](https://github.com/rust-lang/libc/pull/5036)) + +### Changed + +- **potentially breaking** Linux: Add new fields to `struct ptrace_syscall_info` ([#4966](https://github.com/rust-lang/libc/pull/4966)) +- Re-export `core::ffi` integer types rather than redefining ([#5015](https://github.com/rust-lang/libc/pull/5015)) +- Redox: Update `F_DUPFD`, `IP`, and `TCP` constants to match relibc ([#4990](https://github.com/rust-lang/libc/pull/4990)) + + + +## [0.2.183](https://github.com/rust-lang/libc/compare/0.2.182...0.2.183) - 2026-03-08 + +### Added + +- ESP-IDF: Add `SOMAXCONN` ([#4993](https://github.com/rust-lang/libc/pull/4993)) +- Linux: Add `name_to_handle_at` and `open_by_handle_at` ([#4988](https://github.com/rust-lang/libc/pull/4988)) +- NetBSD: Add `kinfo_file`, `kinfo_pcb`, and related constants ([#4985](https://github.com/rust-lang/libc/pull/4985)) +- OpenBSD: Add `kinfo_file` and related constants ([#4991](https://github.com/rust-lang/libc/pull/4991)) +- VxWorks: Add additional structs and defines ([#5003](https://github.com/rust-lang/libc/pull/5003)) +- Various: Implement `Default` for `timeval` and `timespec` ([#4976](https://github.com/rust-lang/libc/pull/4976)) + +### Fixed + +- Hexagon musl: Enable unstable 64-bit `time_t` support and `musl_v1_2_3` ([#4992](https://github.com/rust-lang/libc/pull/4992)) +- Nintendo Switch: Fix target support ([#4982](https://github.com/rust-lang/libc/pull/4982)) +- OpenBSD: Wrap an unused field in `Padding` ([#4997](https://github.com/rust-lang/libc/pull/4997)) +- Redox: Change `sigaction.sa_flags` to `c_int` ([#4986](https://github.com/rust-lang/libc/pull/4986)) +- Redox: Fix `blkcnt_t` type ([#4994](https://github.com/rust-lang/libc/pull/4994)) + +## [0.2.182](https://github.com/rust-lang/libc/compare/0.2.181...0.2.182) - 2026-02-13 + +### Added + +- Android, Linux: Add `tgkill` ([#4970](https://github.com/rust-lang/libc/pull/4970)) +- Redox: Add `RENAME_NOREPLACE` ([#4968](https://github.com/rust-lang/libc/pull/4968)) +- Redox: Add `renameat2` ([#4968](https://github.com/rust-lang/libc/pull/4968)) + + +## [0.2.181](https://github.com/rust-lang/libc/compare/0.2.180...0.2.181) - 2026-02-09 + +### Added + +- Apple: Add `MADV_ZERO` ([#4924](https://github.com/rust-lang/libc/pull/4924)) +- Redox: Add `makedev`, `major`, and `minor` ([#4928](https://github.com/rust-lang/libc/pull/4928)) +- GLibc: Add `PTRACE_SET_SYSCALL_INFO` ([#4933](https://github.com/rust-lang/libc/pull/4933)) +- OpenBSD: Add more kqueue related constants for ([#4945](https://github.com/rust-lang/libc/pull/4945)) +- Linux: add CAN error types ([#4944](https://github.com/rust-lang/libc/pull/4944)) +- OpenBSD: Add siginfo_t::si_status ([#4946](https://github.com/rust-lang/libc/pull/4946)) +- QNX NTO: Add `max_align_t` ([#4927](https://github.com/rust-lang/libc/pull/4927)) +- Illumos: Add `_CS_PATH` ([#4956](https://github.com/rust-lang/libc/pull/4956)) +- OpenBSD: add `ppoll` ([#4957](https://github.com/rust-lang/libc/pull/4957)) + +### Fixed + +- **breaking**: Redox: Fix the type of dev_t ([#4928](https://github.com/rust-lang/libc/pull/4928)) +- AIX: Change 'tv_nsec' of 'struct timespec' to type 'c_long' ([#4931](https://github.com/rust-lang/libc/pull/4931)) +- AIX: Use 'struct st_timespec' in 'struct stat{,64}' ([#4931](https://github.com/rust-lang/libc/pull/4931)) +- Glibc: Link old version of `tc{g,s}etattr` ([#4938](https://github.com/rust-lang/libc/pull/4938)) +- Glibc: Link the correct version of `cf{g,s}et{i,o}speed` on mips{32,64}r6 ([#4938](https://github.com/rust-lang/libc/pull/4938)) +- OpenBSD: Fix constness of tm.tm_zone ([#4948](https://github.com/rust-lang/libc/pull/4948)) +- OpenBSD: Fix the definition of `ptrace_thread_state` ([#4947](https://github.com/rust-lang/libc/pull/4947)) +- QuRT: Fix type visibility and defs ([#4932](https://github.com/rust-lang/libc/pull/4932)) +- Redox: Fix values for `PTHREAD_MUTEX_{NORMAL, RECURSIVE}` ([#4943](https://github.com/rust-lang/libc/pull/4943)) +- Various: Mark additional fields as private padding ([#4922](https://github.com/rust-lang/libc/pull/4922)) + +### Changed + +- Fuchsia: Update `SO_*` constants ([#4937](https://github.com/rust-lang/libc/pull/4937)) +- Revert "musl: convert inline timespecs to timespec" (resolves build issues on targets only supported by Musl 1.2.3+ ) ([#4958](https://github.com/rust-lang/libc/pull/4958)) + + +## [0.2.180](https://github.com/rust-lang/libc/compare/0.2.179...0.2.180) - 2026-01-08 + +### Added + +- QNX: Add missing BPF and ifreq structures ([#4769](https://github.com/rust-lang/libc/pull/4769)) + +### Fixed + +- Linux, L4Re: address soundness issues of `CMSG_NXTHDR` ([#4903](https://github.com/rust-lang/libc/pull/4903)) +- Linux-like: Handle zero-sized payload differences in `CMSG_NXTHDR` ([#4903](https://github.com/rust-lang/libc/pull/4903)) +- Musl: Fix incorrect definitions of struct stat on some 32-bit architectures ([#4914](https://github.com/rust-lang/libc/pull/4914)) +- NetBSD: RISC-V 64: Correct `mcontext` type definitions ([#4886](https://github.com/rust-lang/libc/pull/4886)) +- uClibc: Re-enable `__SIZEOF_PTHREAD_COND_T` on non-L4Re uclibc ([#4915](https://github.com/rust-lang/libc/pull/4915)) +- uClibc: Restructure Linux `netlink` module to resolve build errors ([#4915](https://github.com/rust-lang/libc/pull/4915)) + + +## [0.2.179](https://github.com/rust-lang/libc/compare/0.2.178...0.2.179) - 2025-01-03 + +With this release, we now have _unstable_ support for 64-bit `time_t` on 32-bit +platforms with both Musl and Glibc. Testing is appreciated! + +For now, these can be enabled by setting environment variables during build: + +```text +RUST_LIBC_UNSTABLE_MUSL_V1_2_3=1 +RUST_LIBC_UNSTABLE_GNU_TIME_BITS=64 +``` + +Note that the exact configuration will change in the future. Setting the +`MUSL_V1_2_3` variable also enables some newer API unrelated to `time_t`. + +### Added + +- L4Re: Add uclibc aarch64 support ([#4479](https://github.com/rust-lang/libc/pull/4479)) +- Linux, Android: Add a generic definition for `XCASE` ([#4847](https://github.com/rust-lang/libc/pull/4847)) +- Linux-like: Add `NAME_MAX` ([#4888](https://github.com/rust-lang/libc/pull/4888)) +- Linux: Add `AT_EXECVE_CHECK` ([#4422](https://github.com/rust-lang/libc/pull/4422)) +- Linux: Add the `SUN_LEN` macro ([#4269](https://github.com/rust-lang/libc/pull/4269)) +- Linux: add `getitimer` and `setitimer` ([#4890](https://github.com/rust-lang/libc/pull/4890)) +- Linux: add `pthread_tryjoin_n` and `pthread_timedjoin_np` ([#4887](https://github.com/rust-lang/libc/pull/4887)) +- Musl: Add unstable support for 64-bit `time_t` on 32-bit platforms ([#4463](https://github.com/rust-lang/libc/pull/4463)) +- NetBSD, OpenBSD: Add interface `LINK_STATE_*` definitions from `sys/net/if.h` ([#4751](https://github.com/rust-lang/libc/pull/4751)) +- QuRT: Add support for Qualcomm QuRT ([#4845](https://github.com/rust-lang/libc/pull/4845)) +- Types: Add Padding::uninit() ([#4862](https://github.com/rust-lang/libc/pull/4862)) + +### Fixed + +- Glibc: Link old version of `cf{g,s}et{i,o}speed` ([#4882](https://github.com/rust-lang/libc/pull/4882)) +- L4Re: Fixes for `pthread` ([#4479](https://github.com/rust-lang/libc/pull/4479)) +- L4re: Fix a wide variety of incorrect definitions ([#4479](https://github.com/rust-lang/libc/pull/4479)) +- Musl: Fix the value of `CPU_SETSIZE` on musl 1.2+ ([#4865](https://github.com/rust-lang/libc/pull/4865)) +- Musl: RISC-V: fix public padding fields in `stat/stat64` ([#4463](https://github.com/rust-lang/libc/pull/4463)) +- Musl: s390x: Fix definition of `SIGSTKSZ`/`MINSIGSTKSZ` ([#4884](https://github.com/rust-lang/libc/pull/4884)) +- NetBSD: Arm: Fix `PT_{GET,SET}FPREGS`, `_REG_TIPDR`, and `_REG_{LR,SP}` ([#4899](https://github.com/rust-lang/libc/pull/4899)) +- NetBSD: Fix `if_msghdr` alignment ([#4902](https://github.com/rust-lang/libc/pull/4902)) +- NetBSD: Fix `siginfo_t` layout on 32-bit platforms ([#4904](https://github.com/rust-lang/libc/pull/4904)) +- NetBSD: change definition of `pthread_spin_t` to allow arch redefinition. ([#4899](https://github.com/rust-lang/libc/pull/4899)) +- Newlib: Fix ambiguous glob exports and other warnings for Vita and 3DS ([#4875](https://github.com/rust-lang/libc/pull/4875)) +- QNX: Fix build error ([#4879](https://github.com/rust-lang/libc/pull/4879)) + +### Changed + +- CI: Update CI images to FreeBSD 15.0-release ([#4857](https://github.com/rust-lang/libc/pull/4857)) +- L4Re: Make `pthread` struct fields private ([#4876](https://github.com/rust-lang/libc/pull/4876)) +- Linux, Fuchsia: Mark mq_attr padding area as such ([#4858](https://github.com/rust-lang/libc/pull/4858)) +- Types: Wrap a number of private fields in the `Padding` type ([#4862](https://github.com/rust-lang/libc/pull/4862)) + +### Removed + +- Build: Remove `RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64` ([#4865](https://github.com/rust-lang/libc/pull/4865)) +- WASI: Remove nonexistent clocks ([#4880](https://github.com/rust-lang/libc/pull/4880)) + + +## [0.2.178](https://github.com/rust-lang/libc/compare/0.2.177...0.2.178) - 2025-12-01 + +### Added + +- BSD: Add `issetugid` ([#4744](https://github.com/rust-lang/libc/pull/4744)) +- Cygwin: Add missing utmp/x.h, grp.h, and stdio.h interfaces ([#4827](https://github.com/rust-lang/libc/pull/4827)) +- Linux s390x musl: Add `__psw_t`/`fprefset_t`/`*context_t` ([#4726](https://github.com/rust-lang/libc/pull/4726)) +- Linux, Android: Add definition for IUCLC ([#4846](https://github.com/rust-lang/libc/pull/4846)) +- Linux, FreeBSD: Add `AT_HWCAP{3,4}` ([#4734](https://github.com/rust-lang/libc/pull/4734)) +- Linux: Add definitions from linux/can/bcm.h ([#4683](https://github.com/rust-lang/libc/pull/4683)) +- Linux: Add syscalls 451-469 for m68k ([#4850](https://github.com/rust-lang/libc/pull/4850)) +- Linux: PowerPC: Add 'ucontext.h' definitions ([#4696](https://github.com/rust-lang/libc/pull/4696)) +- NetBSD: Define `eventfd` ([#4830](https://github.com/rust-lang/libc/pull/4830)) +- Newlib: Add missing constants from `unistd.h` ([#4811](https://github.com/rust-lang/libc/pull/4811)) +- QNX NTO: Add `cfmakeraw` ([#4704](https://github.com/rust-lang/libc/pull/4704)) +- QNX NTO: Add `cfsetspeed` ([#4704](https://github.com/rust-lang/libc/pull/4704)) +- Redox: Add `getresgid` and `getresuid` ([#4752](https://github.com/rust-lang/libc/pull/4752)) +- Redox: Add `setresgid` and `setresuid` ([#4752](https://github.com/rust-lang/libc/pull/4752)) +- VxWorks: Add definitions from `select.h`, `stat.h`, `poll.h`, `ttycom.h`, `utsname.h`, `resource.h`, `mman.h`, `udp.h`, `in.h`, `in6.h`, `if.h`, `fnmatch.h`, and `sioLibCommon.h` ([#4781](https://github.com/rust-lang/libc/pull/4781)) +- VxWorks: Add missing defines/functions needed by rust stdlib ([#4779](https://github.com/rust-lang/libc/pull/4779)) +- WASI: Add more definitions for libstd ([#4747](https://github.com/rust-lang/libc/pull/4747)) + +### Deprecated + +- Apple: Deprecate `TIOCREMOTE` ([#4764](https://github.com/rust-lang/libc/pull/4764)) + +### Fixed + +Note that there were a large number of fixes on NetBSD for this `libc` release, some of which include minor breakage. + +- AIX: Change errno `EWOULDBLOCK` to make it an alias of `EAGAIN` ([#4790](https://github.com/rust-lang/libc/pull/4790)) +- AIX: Resolve function comparison and `unnecessary_transmutes` warnings ([#4780](https://github.com/rust-lang/libc/pull/4780)) +- Apple: Correct the value of `SF_SETTABLE` ([#4764](https://github.com/rust-lang/libc/pull/4764)) +- DragonflyBSD: Fix the type of `mcontext_t.mc_fpregs` ([#]()) +- EspIDF: Fix the duplicate definition of `gethostname` ([#4773](https://github.com/rust-lang/libc/pull/4773)) +- L4Re: Update available pthread API ([#4836](https://github.com/rust-lang/libc/pull/4836)) +- Linux: Correct the value of `NFT_MSG_MAX` ([#4761](https://github.com/rust-lang/libc/pull/4761)) +- Linux: Remove incorrect `repr(align(8))` for `canxl_frame` ([#4760](https://github.com/rust-lang/libc/pull/4760)) +- Make `eventfd` argument names match OS docs/headers ([#4830](https://github.com/rust-lang/libc/pull/4830)) +- NetBSD: Account for upstream changes to ptrace with LWP ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Correct `ipc_perm`, split from OpenBSD as `ipc.rs` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Correct a number of symbol link names ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Correct the type of `kinfo_vmentry.kve_path` ([#]()) +- NetBSD: Fix `uucred.cr_ngroups` from `int` to `short` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Fix the type of `kevent.udata` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Fix the type of `mcontext_t.__fpregs` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Fix the value of `PT_SUSPEND` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Fix the values of FNM_* constants ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Increase the size of `sockaddr_dl.sdl_data` from 12 to 24 ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `if_.rs`, fix the definition of `ifreq` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `time.rs`, fix the values of `CLOCK_*_CPUTIME_ID` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `timex.rs` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `types.rs`, correct the definition of `lwpid_t` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `utmp_.rs`, correct the definition of `lastlog` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Introduce `utmpx_.rs`, correct utmpx definitions ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Make `_cpuset` an extern type ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: RISC-V 64: Fix the `mcontext` types ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- Nuttx: Resolve warnings ([#4773](https://github.com/rust-lang/libc/pull/4773)) +- OHOS: Don't emit duplicate lfs64 definitions ([#4804](https://github.com/rust-lang/libc/pull/4804)) +- Redox: Fix the type of `pid_t` ([#4825](https://github.com/rust-lang/libc/pull/4825)) +- WASI: Gate `__wasilibc_register_preopened_fd` ([#4837](https://github.com/rust-lang/libc/pull/4837)) +- Wali: Fix unknown config ([#4773](https://github.com/rust-lang/libc/pull/4773)) + +### Changed + +- AIX: Declare field 'tv_nsec' of structure 'timespec' as 'i32' in both 32-bit and 64-bit modes ([#4750](https://github.com/rust-lang/libc/pull/4750)) +- DragonFly: Avoid usage of `thread_local` ([#3653](https://github.com/rust-lang/libc/pull/3653)) +- Linux: Update the definition for `ucontext_t` and unskip its tests ([#4760](https://github.com/rust-lang/libc/pull/4760)) +- MinGW: Set `L_tmpnam` and `TMP_MAX` to the UCRT value ([#4566](https://github.com/rust-lang/libc/pull/4566)) +- WASI: More closely align pthread type reprs ([#4747](https://github.com/rust-lang/libc/pull/4747)) +- Simplify rustc-check-cfg emission in build.rs ([#4724](https://github.com/rust-lang/libc/pull/4724)) +- Transition a number of definitions to the new source structure (internal change) + +### Removed + +- MIPS Musl: Remove rogue definition of `SIGSTKFLT` ([#4749](https://github.com/rust-lang/libc/pull/4749)) +- NetBSD: Make `statvfs.f_spare` non-public ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Remove BPF constants ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Remove `*_MAXID` constants and `AT_SUN_LDPGSIZE` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Remove `IFF_NOTRAILERS` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Remove `vm_size_t` ([#4782](https://github.com/rust-lang/libc/pull/4782)) +- NetBSD: Replace REG_ENOSYS with REG_ILLSEQ ([#4782](https://github.com/rust-lang/libc/pull/4782)) + + +## [0.2.177](https://github.com/rust-lang/libc/compare/0.2.176...0.2.177) - 2025-10-09 + +### Added + +- Apple: Add `TIOCGETA`, `TIOCSETA`, `TIOCSETAW`, `TIOCSETAF` constants ([#4736](https://github.com/rust-lang/libc/pull/4736)) +- Apple: Add `pthread_cond_timedwait_relative_np` ([#4719](https://github.com/rust-lang/libc/pull/4719)) +- BSDs: Add `_CS_PATH` constant ([#4738](https://github.com/rust-lang/libc/pull/4738)) +- Linux-like: Add `SIGEMT` for mips* and sparc* architectures ([#4730](https://github.com/rust-lang/libc/pull/4730)) +- OpenBSD: Add `elf_aux_info` ([#4729](https://github.com/rust-lang/libc/pull/4729)) +- Redox: Add more sysconf constants ([#4728](https://github.com/rust-lang/libc/pull/4728)) +- Windows: Add `wcsnlen` ([#4721](https://github.com/rust-lang/libc/pull/4721)) + +### Changed + +- WASIP2: Invert conditional to include p2 APIs ([#4733](https://github.com/rust-lang/libc/pull/4733)) + +## [0.2.176](https://github.com/rust-lang/libc/compare/0.2.175...0.2.176) - 2025-09-23 + +### Support + +- The default FreeBSD version has been raised from 11 to 12. This matches `rustc` since 1.78. ([#2406](https://github.com/rust-lang/libc/pull/2406)) +- `Debug` is now always implemented, rather than being gated behind the `extra_traits` feature. ([#4624](https://github.com/rust-lang/libc/pull/4624)) + +### Added + +- AIX: Restore some non-POSIX functions guarded by the `_KERNEL` macro. ([#4607](https://github.com/rust-lang/libc/pull/4607)) +- FreeBSD 14: Add `st_fileref` to `struct stat` ([#4642](https://github.com/rust-lang/libc/pull/4642)) +- Haiku: Add the `accept4` POSIX call ([#4586](https://github.com/rust-lang/libc/pull/4586)) +- Introduce a wrapper for representing padding ([#4632](https://github.com/rust-lang/libc/pull/4632)) +- Linux: Add `EM_RISCV` ([#4659](https://github.com/rust-lang/libc/pull/4659)) +- Linux: Add `MS_NOSYMFOLLOW` ([#4389](https://github.com/rust-lang/libc/pull/4389)) +- Linux: Add `backtrace_symbols(_fd)` ([#4668](https://github.com/rust-lang/libc/pull/4668)) +- Linux: Add missing `SOL_PACKET` optnames ([#4669](https://github.com/rust-lang/libc/pull/4669)) +- Musl s390x: Add `SYS_mseal` ([#4549](https://github.com/rust-lang/libc/pull/4549)) +- NuttX: Add `__errno` ([#4687](https://github.com/rust-lang/libc/pull/4687)) +- Redox: Add `dirfd`, `VDISABLE`, and resource consts ([#4660](https://github.com/rust-lang/libc/pull/4660)) +- Redox: Add more `resource.h`, `fcntl.h` constants ([#4666](https://github.com/rust-lang/libc/pull/4666)) +- Redox: Enable `strftime` and `mkostemp[s]` ([#4629](https://github.com/rust-lang/libc/pull/4629)) +- Unix, Windows: Add `qsort_r` (Unix), and `qsort(_s)` (Windows) ([#4677](https://github.com/rust-lang/libc/pull/4677)) +- Unix: Add `dlvsym` for Linux-gnu, FreeBSD, and NetBSD ([#4671](https://github.com/rust-lang/libc/pull/4671)) +- Unix: Add `sigqueue` ([#4620](https://github.com/rust-lang/libc/pull/4620)) + +### Changed + +- FreeBSD 15: Mark `kinfo_proc` as non-exhaustive ([#4553](https://github.com/rust-lang/libc/pull/4553)) +- FreeBSD: Set the ELF symbol version for `readdir_r` ([#4694](https://github.com/rust-lang/libc/pull/4694)) +- Linux: Correct the config for whether or not `epoll_event` is packed ([#4639](https://github.com/rust-lang/libc/pull/4639)) +- Tests: Replace the old `ctest` with the much more reliable new implementation ([#4655](https://github.com/rust-lang/libc/pull/4655) and many related PRs) + +### Fixed + +- AIX: Fix the type of the 4th arguement of `getgrnam_r` ([#4656](https://github.com/rust-lang/libc/pull/4656 +- FreeBSD: Limit `P_IDLEPROC` to FreeBSD 15 ([#4640](https://github.com/rust-lang/libc/pull/4640)) +- FreeBSD: Limit `mcontext_t::mc_tlsbase` to FreeBSD 15 ([#4640](https://github.com/rust-lang/libc/pull/464)) +- FreeBSD: Update gating of `mcontext_t.mc_tlsbase` ([#4703](https://github.com/rust-lang/libc/pull/4703)) +- Musl s390x: Correct the definition of `statfs[64]` ([#4549](https://github.com/rust-lang/libc/pull/4549)) +- Musl s390x: Make `fpreg_t` a union ([#4549](https://github.com/rust-lang/libc/pull/4549)) +- Redox: Fix the types of `gid_t` and `uid_t` ([#4689](https://github.com/rust-lang/libc/pull/4689)) +- Redox: Fix the value of `MAP_FIXED` ([#4684](https://github.com/rust-lang/libc/pull/4684)) + +### Deprecated + +- Apple: Correct the `deprecated` attribute for `iconv` ([`a97a0b53`](https://github.com/rust-lang/libc/commit/a97a0b53fb7faf5f99cd720ab12b1b8a5bf9f950)) +- FreeBSD: Deprecate `TIOCMGDTRWAIT` and `TIOCMSDTRWAIT` ([#4685](https://github.com/rust-lang/libc/pull/4685)) + +### Removed + +- FreeBSD: Remove `JAIL_{GET,SET}_MASK`, `_MC_FLAG_MASK` ([#4691](https://github.com/rust-lang/libc/pull/4691)) + +## [0.2.175](https://github.com/rust-lang/libc/compare/0.2.174...0.2.175) - 2025-08-10 + +### Added + +- AIX: Add `getpeereid` ([#4524](https://github.com/rust-lang/libc/pull/4524)) +- AIX: Add `struct ld_info` and friends ([#4578](https://github.com/rust-lang/libc/pull/4578)) +- AIX: Retore `struct winsize` ([#4577](https://github.com/rust-lang/libc/pull/4577)) +- Android: Add UDP socket option constants ([#4619](https://github.com/rust-lang/libc/pull/4619)) +- Android: Add `CLONE_CLEAR_SIGHAND` and `CLONE_INTO_CGROUP` ([#4502](https://github.com/rust-lang/libc/pull/4502)) +- Android: Add more `prctl` constants ([#4531](https://github.com/rust-lang/libc/pull/4531)) +- FreeBSD Add further TCP stack-related constants ([#4196](https://github.com/rust-lang/libc/pull/4196)) +- FreeBSD x86-64: Add `mcontext_t.mc_tlsbase ` ([#4503](https://github.com/rust-lang/libc/pull/4503)) +- FreeBSD15: Add `kinfo_proc.ki_uerrmsg` ([#4552](https://github.com/rust-lang/libc/pull/4552)) +- FreeBSD: Add `in_conninfo` ([#4482](https://github.com/rust-lang/libc/pull/4482)) +- FreeBSD: Add `xinpgen` and related types ([#4482](https://github.com/rust-lang/libc/pull/4482)) +- FreeBSD: Add `xktls_session` ([#4482](https://github.com/rust-lang/libc/pull/4482)) +- Haiku: Add functionality from `libbsd` ([#4221](https://github.com/rust-lang/libc/pull/4221)) +- Linux: Add `SECBIT_*` ([#4480](https://github.com/rust-lang/libc/pull/4480)) +- NetBSD, OpenBSD: Export `ioctl` request generator macros ([#4460](https://github.com/rust-lang/libc/pull/4460)) +- NetBSD: Add `ptsname_r` ([#4608](https://github.com/rust-lang/libc/pull/4608)) +- RISCV32: Add time-related syscalls ([#4612](https://github.com/rust-lang/libc/pull/4612)) +- Solarish: Add `strftime*` ([#4453](https://github.com/rust-lang/libc/pull/4453)) +- linux: Add `EXEC_RESTRICT_*` and `EXEC_DENY_*` ([#4545](https://github.com/rust-lang/libc/pull/4545)) + +### Changed + +- AIX: Add `const` to signatures to be consistent with other platforms ([#4563](https://github.com/rust-lang/libc/pull/4563)) + +### Fixed + +- AIX: Fix the type of `struct statvfs.f_fsid` ([#4576](https://github.com/rust-lang/libc/pull/4576)) +- AIX: Fix the type of constants for the `ioctl` `request` argument ([#4582](https://github.com/rust-lang/libc/pull/4582)) +- AIX: Fix the types of `stat{,64}.st_*tim` ([#4597](https://github.com/rust-lang/libc/pull/4597)) +- AIX: Use unique `errno` values ([#4507](https://github.com/rust-lang/libc/pull/4507)) +- Build: Fix an incorrect `target_os` -> `target_arch` check ([#4550](https://github.com/rust-lang/libc/pull/4550)) +- FreeBSD: Fix the type of `xktls_session_onedir.ifnet` ([#4552](https://github.com/rust-lang/libc/pull/4552)) +- Mips64 musl: Fix the type of `nlink_t` ([#4509](https://github.com/rust-lang/libc/pull/4509)) +- Mips64 musl: Use a special MIPS definition of `stack_t` ([#4528](https://github.com/rust-lang/libc/pull/4528)) +- Mips64: Fix `SI_TIMER`, `SI_MESGQ` and `SI_ASYNCIO` definitions ([#4529](https://github.com/rust-lang/libc/pull/4529)) +- Musl Mips64: Swap the order of `si_errno` and `si_code` in `siginfo_t` ([#4530](https://github.com/rust-lang/libc/pull/4530)) +- Musl Mips64: Use a special MIPS definition of `statfs` ([#4527](https://github.com/rust-lang/libc/pull/4527)) +- Musl: Fix the definition of `fanotify_event_metadata` ([#4510](https://github.com/rust-lang/libc/pull/4510)) +- NetBSD: Correct `enum fae_action` to be `#[repr(C)]` ([#60a8cfd5](https://github.com/rust-lang/libc/commit/60a8cfd564f83164d45b9533ff7a0d7371878f2a)) +- PSP: Correct `char` -> `c_char` ([eaab4fc3](https://github.com/rust-lang/libc/commit/eaab4fc3f05dc646a953d4fd5ba46dfa1f8bd6f6)) +- PowerPC musl: Fix `termios` definitions ([#4518](https://github.com/rust-lang/libc/pull/4518)) +- PowerPC musl: Fix the definition of `EDEADLK` ([#4517](https://github.com/rust-lang/libc/pull/4517)) +- PowerPC musl: Fix the definition of `NCCS` ([#4513](https://github.com/rust-lang/libc/pull/4513)) +- PowerPC musl: Fix the definitions of `MAP_LOCKED` and `MAP_NORESERVE` ([#4516](https://github.com/rust-lang/libc/pull/4516)) +- PowerPC64 musl: Fix the definition of `shmid_ds` ([#4519](https://github.com/rust-lang/libc/pull/4519)) + +### Deprecated + +- Linux: `MAP_32BIT` is only defined on x86 on non-x86 architectures ([#4511](https://github.com/rust-lang/libc/pull/4511)) + +### Removed + +- AIX: Remove duplicate constant definitions `FIND` and `ENTER` ([#4588](https://github.com/rust-lang/libc/pull/4588)) +- s390x musl: Remove `O_FSYNC` ([#4515](https://github.com/rust-lang/libc/pull/4515)) +- s390x musl: Remove `RTLD_DEEPBIND` ([#4515](https://github.com/rust-lang/libc/pull/4515)) + + +## [0.2.174](https://github.com/rust-lang/libc/compare/0.2.173...0.2.174) - 2025-06-17 + +### Added + +- Linux: Make `pidfd_info` fields pub ([#4487](https://github.com/rust-lang/libc/pull/4487)) + +### Fixed + +- Gnu x32: Add missing `timespec.tv_nsec` ([#4497](https://github.com/rust-lang/libc/pull/4497)) +- NuttX: Use `nlink_t` type for `st_nlink` in `struct stat` definition ([#4483](https://github.com/rust-lang/libc/pull/4483)) + +### Other + +- Allow new `unpredictable_function_pointer_comparisons` lints ([#4489](https://github.com/rust-lang/libc/pull/4489)) +- OpenBSD: Fix some clippy warnings to use `pointer::cast`. ([#4490](https://github.com/rust-lang/libc/pull/4490)) +- Remove unessecary semicolons from definitions of `CMSG_NXTHDR`. ([#4492](https://github.com/rust-lang/libc/pull/4492)) + + +## [0.2.173](https://github.com/rust-lang/libc/compare/0.2.172...0.2.173) - 2025-06-09 + +### Added + +- AIX: Add an AIX triple to Cargo.toml for doc ([#4475](https://github.com/rust-lang/libc/pull/4475)) +- FreeBSD: Add the `SO_SPLICE` socket option support for FreeBSD >= 14.2 ([#4451](https://github.com/rust-lang/libc/pull/4451)) +- Linux GNU: Prepare for supporting `_TIME_BITS=64` ([#4433](https://github.com/rust-lang/libc/pull/4433)) +- Linux: Add constant PACKET_IGNORE_OUTGOING ([#4319](https://github.com/rust-lang/libc/pull/4319)) +- Linux: Add constants and types for `nsfs` ioctls ([#4436](https://github.com/rust-lang/libc/pull/4436)) +- Linux: Add constants for Memory-Deny-Write-Execute `prctls` ([#4400](https://github.com/rust-lang/libc/pull/4400)) +- Linux: Add constants from `linux/cn_proc.h` and `linux/connector.h` ([#4434](https://github.com/rust-lang/libc/pull/4434)) +- Linux: Add new flags for `pwritev2` and `preadv2` ([#4452](https://github.com/rust-lang/libc/pull/4452)) +- Linux: Add pid_type enum values ([#4403](https://github.com/rust-lang/libc/pull/4403)) +- Linux: Update pidfd constants and types (Linux 6.9-6.15) ([#4402](https://github.com/rust-lang/libc/pull/4402)) +- Loongarch64 musl: Define the `MADV_SOFT_OFFLINE` constant ([#4448](https://github.com/rust-lang/libc/pull/4448)) +- Musl: Add new fields since 1.2.0/1.2.2 to `struct tcp_info` ([#4443](https://github.com/rust-lang/libc/pull/4443)) +- Musl: Prepare for supporting v1.2.3 ([#4443](https://github.com/rust-lang/libc/pull/4443)) +- NuttX: Add `arc4random` and `arc4random_buf` ([#4464](https://github.com/rust-lang/libc/pull/4464)) +- RISC-V Musl: Add `MADV_SOFT_OFFLINE` definition ([#4447](https://github.com/rust-lang/libc/pull/4447)) +- Redox: Define SCM_RIGHTS ([#4440](https://github.com/rust-lang/libc/pull/4440)) +- VxWorks: Add missing UTIME defines and TASK_RENAME_LENGTH ([#4407](https://github.com/rust-lang/libc/pull/4407)) +- Windows: Add more `time.h` functions ([#4427](https://github.com/rust-lang/libc/pull/4427)) + +### Changed + +- Redox: Update `SA_` constants. ([#4426](https://github.com/rust-lang/libc/pull/4426)) +- Redox: make `CMSG_ALIGN`, `CMSG_LEN`, and `CMSG_SPACE` const functions ([#4441](https://github.com/rust-lang/libc/pull/4441)) + +### Fixed + +- AIX: Enable libc-test and fix definitions/declarations. ([#4450](https://github.com/rust-lang/libc/pull/4450)) +- Emscripten: Fix querying emcc on windows (use emcc.bat) ([#4248](https://github.com/rust-lang/libc/pull/4248)) +- Hurd: Fix build from missing `fpos_t` ([#4472](https://github.com/rust-lang/libc/pull/4472)) +- Loongarch64 Musl: Fix the `struct ipc_perm` bindings ([#4384](https://github.com/rust-lang/libc/pull/4384)) +- Musl: Fix the `O_LARGEFILE` constant value. ([#4443](https://github.com/rust-lang/libc/pull/4443)) + +## [0.2.172](https://github.com/rust-lang/libc/compare/0.2.171...0.2.172) - 2025-04-14 + +### Added + +- Android: Add `getauxval` for 32-bit targets ([#4338](https://github.com/rust-lang/libc/pull/4338)) +- Android: Add `if_tun.h` ioctls ([#4379](https://github.com/rust-lang/libc/pull/4379)) +- Android: Define `SO_BINDTOIFINDEX` ([#4391](https://github.com/rust-lang/libc/pull/4391)) +- Cygwin: Add `posix_spawn_file_actions_add[f]chdir[_np]` ([#4387](https://github.com/rust-lang/libc/pull/4387)) +- Cygwin: Add new socket options ([#4350](https://github.com/rust-lang/libc/pull/4350)) +- Cygwin: Add statfs & fcntl ([#4321](https://github.com/rust-lang/libc/pull/4321)) +- FreeBSD: Add `filedesc` and `fdescenttbl` ([#4327](https://github.com/rust-lang/libc/pull/4327)) +- Glibc: Add unstable support for _FILE_OFFSET_BITS=64 ([#4345](https://github.com/rust-lang/libc/pull/4345)) +- Hermit: Add `AF_UNSPEC` ([#4344](https://github.com/rust-lang/libc/pull/4344)) +- Hermit: Add `AF_VSOCK` ([#4344](https://github.com/rust-lang/libc/pull/4344)) +- Illumos, NetBSD: Add `timerfd` APIs ([#4333](https://github.com/rust-lang/libc/pull/4333)) +- Linux: Add `_IO`, `_IOW`, `_IOR`, `_IOWR` to the exported API ([#4325](https://github.com/rust-lang/libc/pull/4325)) +- Linux: Add `tcp_info` to uClibc bindings ([#4347](https://github.com/rust-lang/libc/pull/4347)) +- Linux: Add further BPF program flags ([#4356](https://github.com/rust-lang/libc/pull/4356)) +- Linux: Add missing INPUT_PROP_XXX flags from `input-event-codes.h` ([#4326](https://github.com/rust-lang/libc/pull/4326)) +- Linux: Add missing TLS bindings ([#4296](https://github.com/rust-lang/libc/pull/4296)) +- Linux: Add more constants from `seccomp.h` ([#4330](https://github.com/rust-lang/libc/pull/4330)) +- Linux: Add more glibc `ptrace_sud_config` and related `PTRACE_*ET_SYSCALL_USER_DISPATCH_CONFIG`. ([#4386](https://github.com/rust-lang/libc/pull/4386)) +- Linux: Add new netlink flags ([#4288](https://github.com/rust-lang/libc/pull/4288)) +- Linux: Define ioctl codes on more architectures ([#4382](https://github.com/rust-lang/libc/pull/4382)) +- Linux: Add missing `pthread_attr_setstack` ([#4349](https://github.com/rust-lang/libc/pull/4349)) +- Musl: Add missing `utmpx` API ([#4332](https://github.com/rust-lang/libc/pull/4332)) +- Musl: Enable `getrandom` on all platforms ([#4346](https://github.com/rust-lang/libc/pull/4346)) +- NuttX: Add more signal constants ([#4353](https://github.com/rust-lang/libc/pull/4353)) +- QNX: Add QNX 7.1-iosock and 8.0 to list of additional cfgs ([#4169](https://github.com/rust-lang/libc/pull/4169)) +- QNX: Add support for alternative Neutrino network stack `io-sock` ([#4169](https://github.com/rust-lang/libc/pull/4169)) +- Redox: Add more `sys/socket.h` and `sys/uio.h` definitions ([#4388](https://github.com/rust-lang/libc/pull/4388)) +- Solaris: Temporarily define `O_DIRECT` and `SIGINFO` ([#4348](https://github.com/rust-lang/libc/pull/4348)) +- Solarish: Add `secure_getenv` ([#4342](https://github.com/rust-lang/libc/pull/4342)) +- VxWorks: Add missing `d_type` member to `dirent` ([#4352](https://github.com/rust-lang/libc/pull/4352)) +- VxWorks: Add missing signal-related constsants ([#4352](https://github.com/rust-lang/libc/pull/4352)) +- VxWorks: Add more error codes ([#4337](https://github.com/rust-lang/libc/pull/4337)) + +### Deprecated + +- FreeBSD: Deprecate `TCP_PCAP_OUT` and `TCP_PCAP_IN` ([#4381](https://github.com/rust-lang/libc/pull/4381)) + +### Fixed + +- Cygwin: Fix member types of `statfs` ([#4324](https://github.com/rust-lang/libc/pull/4324)) +- Cygwin: Fix tests ([#4357](https://github.com/rust-lang/libc/pull/4357)) +- Hermit: Make `AF_INET = 3` ([#4344](https://github.com/rust-lang/libc/pull/4344)) +- Musl: Fix the syscall table on RISC-V-32 ([#4335](https://github.com/rust-lang/libc/pull/4335)) +- Musl: Fix the value of `SA_ONSTACK` on RISC-V-32 ([#4335](https://github.com/rust-lang/libc/pull/4335)) +- VxWorks: Fix a typo in the `waitpid` parameter name ([#4334](https://github.com/rust-lang/libc/pull/4334)) + +### Removed + +- Musl: Remove `O_FSYNC` on RISC-V-32 (use `O_SYNC` instead) ([#4335](https://github.com/rust-lang/libc/pull/4335)) +- Musl: Remove `RTLD_DEEPBIND` on RISC-V-32 ([#4335](https://github.com/rust-lang/libc/pull/4335)) + +### Other + +- CI: Add matrix env variables to the environment ([#4345](https://github.com/rust-lang/libc/pull/4345)) +- CI: Always deny warnings ([#4363](https://github.com/rust-lang/libc/pull/4363)) +- CI: Always upload successfully created artifacts ([#4345](https://github.com/rust-lang/libc/pull/4345)) +- CI: Install musl from source for loongarch64 ([#4320](https://github.com/rust-lang/libc/pull/4320)) +- CI: Revert "Also skip `MFD_EXEC` and `MFD_NOEXEC_SEAL` on sparc64" ([#]()) +- CI: Use `$PWD` instead of `$(pwd)` in run-docker ([#4345](https://github.com/rust-lang/libc/pull/4345)) +- Solarish: Restrict `openpty` and `forkpty` polyfills to Illumos, replace Solaris implementation with bindings ([#4329](https://github.com/rust-lang/libc/pull/4329)) +- Testing: Ensure the makedev test does not emit unused errors ([#4363](https://github.com/rust-lang/libc/pull/4363)) + +## [0.2.171](https://github.com/rust-lang/libc/compare/0.2.170...0.2.171) - 2025-03-11 + +### Added + +- Android: Add `if_nameindex`/`if_freenameindex` support ([#4247](https://github.com/rust-lang/libc/pull/4247)) +- Apple: Add missing proc types and constants ([#4310](https://github.com/rust-lang/libc/pull/4310)) +- BSD: Add `devname` ([#4285](https://github.com/rust-lang/libc/pull/4285)) +- Cygwin: Add PTY and group API ([#4309](https://github.com/rust-lang/libc/pull/4309)) +- Cygwin: Add support ([#4279](https://github.com/rust-lang/libc/pull/4279)) +- FreeBSD: Make `spawn.h` interfaces available on all FreeBSD-like systems ([#4294](https://github.com/rust-lang/libc/pull/4294)) +- Linux: Add `AF_XDP` structs for all Linux environments ([#4163](https://github.com/rust-lang/libc/pull/4163)) +- Linux: Add SysV semaphore constants ([#4286](https://github.com/rust-lang/libc/pull/4286)) +- Linux: Add `F_SEAL_EXEC` ([#4316](https://github.com/rust-lang/libc/pull/4316)) +- Linux: Add `SO_PREFER_BUSY_POLL` and `SO_BUSY_POLL_BUDGET` ([#3917](https://github.com/rust-lang/libc/pull/3917)) +- Linux: Add `devmem` structs ([#4299](https://github.com/rust-lang/libc/pull/4299)) +- Linux: Add socket constants up to `SO_DEVMEM_DONTNEED` ([#4299](https://github.com/rust-lang/libc/pull/4299)) +- NetBSD, OpenBSD, DragonflyBSD: Add `closefrom` ([#4290](https://github.com/rust-lang/libc/pull/4290)) +- NuttX: Add `pw_passwd` field to `passwd` ([#4222](https://github.com/rust-lang/libc/pull/4222)) +- Solarish: define `IP_BOUND_IF` and `IPV6_BOUND_IF` ([#4287](https://github.com/rust-lang/libc/pull/4287)) +- Wali: Add bindings for `wasm32-wali-linux-musl` target ([#4244](https://github.com/rust-lang/libc/pull/4244)) + +### Changed + +- AIX: Use `sa_sigaction` instead of a union ([#4250](https://github.com/rust-lang/libc/pull/4250)) +- Make `msqid_ds.__msg_cbytes` public ([#4301](https://github.com/rust-lang/libc/pull/4301)) +- Unix: Make all `major`, `minor`, `makedev` into `const fn` ([#4208](https://github.com/rust-lang/libc/pull/4208)) + +### Deprecated + +- Linux: Deprecate obsolete packet filter interfaces ([#4267](https://github.com/rust-lang/libc/pull/4267)) + +### Fixed + +- Cygwin: Fix strerror_r ([#4308](https://github.com/rust-lang/libc/pull/4308)) +- Cygwin: Fix usage of f! ([#4308](https://github.com/rust-lang/libc/pull/4308)) +- Hermit: Make `stat::st_size` signed ([#4298](https://github.com/rust-lang/libc/pull/4298)) +- Linux: Correct values for `SI_TIMER`, `SI_MESGQ`, `SI_ASYNCIO` ([#4292](https://github.com/rust-lang/libc/pull/4292)) +- NuttX: Update `tm_zone` and `d_name` fields to use `c_char` type ([#4222](https://github.com/rust-lang/libc/pull/4222)) +- Xous: Include the prelude to define `c_int` ([#4304](https://github.com/rust-lang/libc/pull/4304)) + +### Other + +- Add labels to FIXMEs ([#4231](https://github.com/rust-lang/libc/pull/4231), [#4232](https://github.com/rust-lang/libc/pull/4232), [#4234](https://github.com/rust-lang/libc/pull/4234), [#4235](https://github.com/rust-lang/libc/pull/4235), [#4236](https://github.com/rust-lang/libc/pull/4236)) +- CI: Fix "cannot find libc" error on Sparc64 ([#4317](https://github.com/rust-lang/libc/pull/4317)) +- CI: Fix "cannot find libc" error on s390x ([#4317](https://github.com/rust-lang/libc/pull/4317)) +- CI: Pass `--no-self-update` to `rustup update` ([#4306](https://github.com/rust-lang/libc/pull/4306)) +- CI: Remove tests for the `i586-pc-windows-msvc` target ([#4311](https://github.com/rust-lang/libc/pull/4311)) +- CI: Remove the `check_cfg` job ([#4322](https://github.com/rust-lang/libc/pull/4312)) +- Change the range syntax that is giving `ctest` problems ([#4311](https://github.com/rust-lang/libc/pull/4311)) +- Linux: Split out the stat struct for gnu/b32/mips ([#4276](https://github.com/rust-lang/libc/pull/4276)) + +### Removed + +- NuttX: Remove `pthread_set_name_np` ([#4251](https://github.com/rust-lang/libc/pull/4251)) + +## [0.2.170](https://github.com/rust-lang/libc/compare/0.2.169...0.2.170) - 2025-02-23 + +### Added + +- Android: Declare `setdomainname` and `getdomainname` +- FreeBSD: Add `evdev` structures +- FreeBSD: Add the new `st_filerev` field to `stat32` ([#4254](https://github.com/rust-lang/libc/pull/4254)) +- Linux: Add `SI_*`` and `TRAP_*`` signal codes +- Linux: Add experimental configuration to enable 64-bit time in kernel APIs, set by `RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64`. +- Linux: Add recent socket timestamping flags +- Linux: Added new CANFD_FDF flag for the flags field of canfd_frame +- Musl: add CLONE_NEWTIME +- Solarish: add the posix_spawn family of functions + +### Deprecated + +- Linux: deprecate kernel modules syscalls + +### Changed + +- Emscripten: Assume version is at least 3.1.42 + +### Fixed + +- BSD: Correct the definition of `WEXITSTATUS` +- Hurd: Fix CMSG_DATA on 64bit systems ([#4240](https://github.com/rust-lang/libc/pull/424)) +- NetBSD: fix `getmntinfo` ([#4265](https://github.com/rust-lang/libc/pull/4265) +- VxWorks: Fix the size of `time_t` + +### Other + +- Add labels to FIXMEs , , +- CI: Bump FreeBSD CI to 13.4 and 14.2 +- Copy definitions from core::ffi and centralize them +- Define c_char at top-level and remove per-target c_char definitions +- Port style.rs to syn and add tests for the style checker + +## [0.2.169](https://github.com/rust-lang/libc/compare/0.2.168...0.2.169) - 2024-12-18 + +### Added + +- FreeBSD: add more socket TCP stack constants +- Fuchsia: add a `sockaddr_vm` definition + +### Fixed + +**Breaking**: [rust-lang/rust#132975](https://github.com/rust-lang/rust/pull/132975) corrected the signedness of `core::ffi::c_char` on various Tier 2 and Tier 3 platforms (mostly Arm and RISC-V) to match Clang. This release contains the corresponding changes to `libc`, including the following specific pull requests: + +- ESP-IDF: Replace arch-conditional `c_char` with a reexport +- Fix `c_char` on various targets +- Mirror `c_char` configuration from `rust-lang/rust` + +### Cleanup + +- Do not re-export `c_void` in target-specific code + +## [0.2.168](https://github.com/rust-lang/libc/compare/0.2.167...0.2.168) - 2024-12-09 + +### Added + +- Linux: Add new process flags ([#4174](https://github.com/rust-lang/libc/pull/4174)) +- Linux: Make `IFA_*` constants available on all Linux targets +- Linux: add `MAP_DROPPABLE` +- Solaris, Illumos: add `SIGRTMIN` and `SIGRTMAX` +- Unix, Linux: adding POSIX `memccpy` and `mempcpy` GNU extension +- CI: Upload artifacts created by libc-test +- CI: Use workflow commands to group output by target +- CI: add caching + +## [0.2.167](https://github.com/rust-lang/libc/compare/0.2.166...0.2.167) - 2024-11-28 + +### Added + +- Solarish: add `st_fstype` to `stat` +- Trusty: Add `intptr_t` and `uintptr_t` ([#4161](https://github.com/rust-lang/libc/pull/4161)) + +### Fixed + +- Fix the build with `rustc-dep-of-std` +- Wasi: Add back unsafe block for `clockid_t` static variables ([#4157](https://github.com/rust-lang/libc/pull/4157)) + +### Cleanup + +- Create an internal prelude +- Fix `unused_qualifications` + +### Other + +- CI: Check various FreeBSD versions ([#4159](https://github.com/rust-lang/libc/pull/4159)) +- CI: add a timeout for all jobs +- CI: verify MSRV for `wasm32-wasi` +- Migrate to the 2021 edition + +### Removed + +- Remove one unused import after the edition 2021 bump + +## [0.2.166](https://github.com/rust-lang/libc/compare/0.2.165...0.2.166) - 2024-11-26 + +### Fixed + +This release resolves two cases of unintentional breakage from the previous release: + +- Revert removal of array size hacks [#4150](https://github.com/rust-lang/libc/pull/4150) +- Ensure `const extern` functions are always enabled [#4151](https://github.com/rust-lang/libc/pull/4151) + +## [0.2.165](https://github.com/rust-lang/libc/compare/0.2.164...0.2.165) - 2024-11-25 + +### Added + +- Android: add `mkostemp`, `mkostemps` +- Android: add a few API 30 calls +- Android: add missing syscall constants +- Apple: add `in6_ifreq` +- Apple: add missing `sysctl` net types (before release: remove `if_family_id` ([#4137](https://github.com/rust-lang/libc/pulls/4137))) +- Freebsd: add `kcmp` call support +- Hurd: add `MAP_32BIT` and `MAP_EXCL` +- Hurd: add `domainname` field to `utsname` ([#4089](https://github.com/rust-lang/libc/pulls/4089)) +- Linux GNU: add `f_flags` to struct `statfs` for arm, mips, powerpc and x86 +- Linux GNU: add `malloc_stats` +- Linux: add ELF relocation-related structs +- Linux: add `ptp_*` structs +- Linux: add `ptp_clock_caps` +- Linux: add `ptp_pin_function` and most `PTP_` constants +- Linux: add missing AF_XDP structs & constants +- Linux: add missing netfilter consts ([#3734](https://github.com/rust-lang/libc/pulls/3734)) +- Linux: add struct and constants for the `mount_setattr` syscall +- Linux: add wireless API +- Linux: expose the `len8_dlc` field of `can_frame` +- Musl: add `utmpx` API +- Musl: add missing syscall constants +- NetBSD: add `mcontext`-related data for RISCV64 +- Redox: add new `netinet` constants ) +- Solarish: add `_POSIX_VDISABLE` ([#4103](https://github.com/rust-lang/libc/pulls/4103)) +- Tests: Add a test that the `const extern fn` macro works +- Tests: Add test of primitive types against `std` +- Unix: Add `htonl`, `htons`, `ntohl`, `ntohs` +- Unix: add `aligned_alloc` +- Windows: add `aligned_realloc` + +### Fixed + +- **breaking** Hurd: fix `MAP_HASSEMAPHORE` name ([#4127](https://github.com/rust-lang/libc/pulls/4127)) +- **breaking** ulibc Mips: fix `SA_*` mismatched types ([#3211](https://github.com/rust-lang/libc/pulls/3211)) +- Aix: fix an enum FFI safety warning +- Haiku: fix some typos ([#3664](https://github.com/rust-lang/libc/pulls/3664)) +- Tests: fix `Elf{32,64}_Relr`-related tests +- Tests: fix libc-tests for `loongarch64-linux-musl` +- Tests: fix some clippy warnings +- Tests: fix tests on `riscv64gc-unknown-freebsd` + +### Deprecated + +- Apple: deprecate `iconv_open` +- Apple: deprecate `mach_task_self` +- Apple: update `mach` deprecation notices for things that were removed in `main` + +### Cleanup + +- Adjust the `f!` macro to be more flexible +- Aix: remove duplicate constants +- CI: make scripts more uniform +- Drop the `libc_align` conditional +- Drop the `libc_cfg_target_vendor` conditional +- Drop the `libc_const_size_of` conditional +- Drop the `libc_core_cvoid` conditional +- Drop the `libc_int128` conditional +- Drop the `libc_non_exhaustive` conditional +- Drop the `libc_packedN` conditional +- Drop the `libc_priv_mod_use` conditional +- Drop the `libc_union` conditional +- Drop the `long_array` conditional +- Drop the `ptr_addr_of` conditional +- Drop warnings about deprecated cargo features +- Eliminate uses of `struct_formatter` +- Fix a few other array size hacks +- Glibc: remove redundant definitions ([#3261](https://github.com/rust-lang/libc/pulls/3261)) +- Musl: remove redundant definitions ([#3261](https://github.com/rust-lang/libc/pulls/3261)) +- Musl: unify definitions of `siginfo_t` ([#3261](https://github.com/rust-lang/libc/pulls/3261)) +- Musl: unify definitions of statfs and statfs64 ([#3261](https://github.com/rust-lang/libc/pulls/3261)) +- Musl: unify definitions of statvfs and statvfs64 ([#3261](https://github.com/rust-lang/libc/pulls/3261)) +- Musl: unify statx definitions ([#3978](https://github.com/rust-lang/libc/pulls/3978)) +- Remove array size hacks for Rust < 1.47 +- Remove repetitive words +- Use #[derive] for Copy/Clone in s! and friends +- Use some tricks to format macro bodies + +### Other + +- Apply formatting to macro bodies +- Bump libc-test to Rust 2021 Edition +- CI: Add a check that semver files don't contain duplicate entries +- CI: Add `fanotify_event_info_fid` to FAM-exempt types +- CI: Allow rustfmt to organize imports ([#4136](https://github.com/rust-lang/libc/pulls/4136)) +- CI: Always run rustfmt +- CI: Change 32-bit Docker images to use EOL repos +- CI: Change 64-bit Docker images to ubuntu:24.10 +- CI: Disable the check for >1 s! invocation +- CI: Ensure build channels get run even if FILTER is unset +- CI: Ensure there is a fallback for no_std +- CI: Fix cases where unset variables cause errors +- CI: Naming adjustments and cleanup +- CI: Only invoke rustup if running in CI +- CI: Remove the logic to handle old rust versions +- CI: Set -u (error on unset) in all script files +- CI: add support for `loongarch64-unknown-linux-musl` +- CI: make `aarch64-apple-darwin` not a nightly-only target +- CI: run shellcheck on all scripts +- CI: update musl headers to Linux 6.6 +- CI: use qemu-sparc64 to run sparc64 tests +- Drop the `libc_const_extern_fn` conditional +- Drop the `libc_underscore_const_names` conditional +- Explicitly set the edition to 2015 +- Introduce a `git-blame-ignore-revs` file +- Tests: Ignore fields as required on Ubuntu 24.10 +- Tests: skip `ATF_*` constants for OpenBSD +- Triagebot: Add an autolabel for CI + +## [0.2.164](https://github.com/rust-lang/libc/compare/0.2.163...0.2.164) - 2024-11-16 + +### MSRV + +This release increases the MSRV of `libc` to 1.63. + +### Other + +- CI: remove tests with rust < 1.63 +- MSRV: document the MSRV of the stable channel to be 1.63 +- MacOS: move ifconf to s_no_extra_traits + +## [0.2.163](https://github.com/rust-lang/libc/compare/0.2.162...0.2.163) - 2024-11-16 + +### Added + +- Aix: add more `dlopen` flags +- Android: add group calls +- FreeBSD: add `TCP_FUNCTION_BLK` and `TCP_FUNCTION_ALIAS` +- Linux: add `confstr` +- Solarish: add `aio` +- Solarish: add `arc4random*` + +### Changed + +- Emscripten: upgrade emsdk to 3.1.68 +- Hurd: use more standard types +- Hurd: use the standard `ssize_t = isize` +- Solaris: fix `confstr` and `ucontext_t` + +### Other + +- CI: add Solaris +- CI: add `i686-unknown-freebsd` +- CI: ensure that calls to `sort` do not depend on locale +- Specify `rust-version` in `Cargo.toml` + +## [0.2.162](https://github.com/rust-lang/libc/compare/0.2.161...0.2.162) - 2024-11-07 + +### Added + +- Android: fix the alignment of `uc_mcontext` on arm64 +- Apple: add `host_cpu_load_info` +- ESP-IDF: add a time flag +- FreeBSD: add the `CLOSE_RANGE_CLOEXEC` flag +- FreeBSD: fix test errors regarding `__gregset_t` +- FreeBSD: fix tests on x86 FreeBSD 15 +- FreeBSD: make `ucontext_t` and `mcontext_t` available on all architectures +- Haiku: add `getentropy` +- Illumos: add `syncfs` +- Illumos: add some recently-added constants +- Linux: add `ioctl` flags +- Linux: add epoll busy polling parameters +- NuttX: add `pthread_[get/set]name_np` +- RTEMS: add `arc4random_buf` +- Trusty OS: add initial support +- WASIp2: expand socket support + +### Fixed + +- Emscripten: don't pass `-lc` +- Hurd: change `st_fsid` field to `st_dev` +- Hurd: fix the definition of `utsname` +- Illumos/Solaris: fix `FNM_CASEFOLD` definition +- Solaris: fix all tests + +### Other + +- CI: Add loongarch64 +- CI: Check that semver files are sorted +- CI: Re-enable the FreeBSD 15 job +- Clean up imports and `extern crate` usage +- Convert `mode_t` constants to octal +- Remove the `wasm32-wasi` target that has been deleted upstream + +## [0.2.161](https://github.com/rust-lang/libc/compare/0.2.160...0.2.161) - 2024-10-17 + +### Fixed + +- OpenBSD: fix `FNM_PATHNAME` and `FNM_NOESCAPE` values + +## [0.2.160](https://github.com/rust-lang/libc/compare/0.2.159...0.2.160) - 2024-10-17 + +### Added + +- Android: add `PR_GET_NAME` and `PR_SET_NAME` +- Apple: add `F_TRANSFEREXTENTS` +- Apple: add `mach_error_string` +- Apple: add additional `pthread` APIs +- Apple: add the `LOCAL_PEERTOKEN` socket option +- BSD: add `RTF_*`, `RTA_*`, `RTAX_*`, and `RTM_*` definitions +- Emscripten: add `AT_EACCESS` +- Emscripten: add `getgrgid`, `getgrnam`, `getgrnam_r` and `getgrgid_r` +- Emscripten: add `getpwnam_r` and `getpwuid_r` +- FreeBSD: add `POLLRDHUP` +- Haiku: add `arc4random` +- Illumos: add `ptsname_r` +- Linux: add `fanotify` interfaces +- Linux: add `tcp_info` +- Linux: add additional AF_PACKET options +- Linux: make Elf constants always available +- Musl x86: add `iopl` and `ioperm` +- Musl: add `posix_spawn` chdir functions +- Musl: add `utmpx.h` constants +- NetBSD: add `sysctlnametomib`, `CLOCK_THREAD_CPUTIME_ID` and `CLOCK_PROCESS_CPUTIME_ID` +- Nuttx: initial support +- RTEMS: add `getentropy` +- RTEMS: initial support +- Solarish: add `POLLRDHUP`, `POSIX_FADV_*`, `O_RSYNC`, and `posix_fallocate` +- Unix: add `fnmatch.h` +- VxWorks: add riscv64 support +- VxWorks: update constants related to the scheduler + +### Changed + +- Redox: change `ino_t` to be `c_ulonglong` + +### Fixed + +- ESP-IDF: fix mismatched constants and structs +- FreeBSD: fix `struct stat` on FreeBSD 12+ + +### Other + +- CI: Fix CI for FreeBSD 15 +- Docs: link to `windows-sys` + +## [0.2.159](https://github.com/rust-lang/libc/compare/0.2.158...0.2.159) - 2024-09-24 + +### Added + +- Android: add more `AT_*` constants in +- Apple: add missing `NOTE_*` constants in +- Hermit: add missing error numbers in +- Hurd: add `__timeval` for 64-bit support in +- Linux: add `epoll_pwait2` in +- Linux: add `mq_notify` in +- Linux: add missing `NFT_CT_*` constants in +- Linux: add the `fchmodat2` syscall in +- Linux: add the `mseal` syscall in +- OpenBSD: add `sendmmsg` and `recvmmsg` in +- Unix: add `IN6ADDR_ANY_INIT` and `IN6ADDR_LOOPBACK_INIT` in +- VxWorks: add `S_ISVTX` in +- VxWorks: add `vxCpuLib` and `taskLib` functions +- WASIp2: add definitions for `std::net` support in + +### Fixed + +- Correctly handle version checks when `clippy-driver` is used + +### Changed + +- EspIdf: change signal constants to c_int in +- HorizonOS: update network definitions in +- Linux: combine `ioctl` APIs in +- WASI: enable CI testing in +- WASIp2: enable CI testing in + +## [0.2.158](https://github.com/rust-lang/libc/compare/0.2.157...0.2.158) - 2024-08-19 + +### Other +- WASI: fix missing `Iterator` with `rustc-dep-of-std` in + +## [0.2.157](https://github.com/rust-lang/libc/compare/0.2.156...0.2.157) - 2024-08-17 + +### Added + +- Apple: add `_NSGetArgv`, `_NSGetArgc` and `_NSGetProgname` in +- Build: add `RUSTC_WRAPPER` support in +- FreeBSD: add `execvpe` support from 14.1 release in +- Fuchsia: add `SO_BINDTOIFINDEX` +- Linux: add `klogctl` in +- MacOS: add `fcntl` OFD commands in +- NetBSD: add `_lwp_park` in +- Solaris: add missing networking support in +- Unix: add `pthread_equal` in +- WASI: add `select`, `FD_SET`, `FD_ZERO`, `FD_ISSET ` in + +### Fixed +- TEEOS: fix octal notation for `O_*` constants in + +### Changed +- FreeBSD: always use freebsd12 when `rustc_dep_of_std` is set in + +## [0.2.156](https://github.com/rust-lang/libc/compare/v0.2.155...v0.2.156) - 2024-08-15 + +### Added +- Apple: add `F_ALLOCATEPERSIST` in +- Apple: add `os_sync_wait_on_address` and related definitions in +- BSD: generalise `IPV6_DONTFRAG` to all BSD targets in +- FreeBSD/DragonFly: add `IP_RECVTTL`/`IPV6_RECVHOPLIMIT` in +- Hurd: add `XATTR_CREATE`, `XATTR_REPLACE` in +- Linux GNU: `confstr` API and `_CS_*` in +- Linux musl: add `preadv2` and `pwritev2` (1.2.5 min.) in +- VxWorks: add the constant `SOMAXCONN` in +- VxWorks: add a few errnoLib related constants in + +### Fixed +- Solaris/illumos: Change `ifa_flags` type to u64 in +- QNX 7.0: Disable `libregex` in + +### Changed +- QNX NTO: update platform support in +- `addr_of!(EXTERN_STATIC)` is now considered safe in + +### Removed +- Apple: remove `rmx_state` in + +### Other +- Update or remove CI tests that have been failing diff --git a/deps/crates/vendor/libc/CONTRIBUTING.md b/deps/crates/vendor/libc/CONTRIBUTING.md new file mode 100644 index 00000000000000..f43cda673d37b1 --- /dev/null +++ b/deps/crates/vendor/libc/CONTRIBUTING.md @@ -0,0 +1,126 @@ +# Contributing to `libc` + +Welcome! If you are reading this document, it means you are interested in +contributing to the `libc` crate. + +## v1.0 Roadmap + +`libc` has two active branches: `main` and `libc-0.2`. `main` is for active +development of the upcoming v1.0 release, and should be the target of all pull +requests. `libc-0.2` is for updates to the currently released version. + +If a pull request to `main` is a good candidate for inclusion in an `0.2.x` +release, include `@rustbot label stable-nominated` in a comment to propose this. +Good candidates will usually meet the following: + +1. The included changes are non-breaking. +2. The change applies cleanly to both branches. +3. There is a usecase that justifies inclusion in a stable release (all + additions should always have a usecase, hopefully). + +Once a `stable-nominated` PR targeting `main` has merged, it can be cherry +picked to the `libc-0.2` branch. A maintainer will likely do these cherry picks +in a batch. + +Alternatively, you can start this process yourself by creating a new branch +based on `libc-0.2` and running `git cherry-pick -xe commit-sha-on-main` +(`git +cherry-pick -xe start-sha^..end-sha` if a range of commits is needed). +`git` will automatically add the "cherry picked from commit" note, but try to +add a backport note so the original PR gets crosslinked: + +``` +# ... original commit message ... + +(backport ) # add manually +(cherry picked from commit 104b6a4ae31c726814c36318dc718470cc96e167) # added by git +``` + +Once the cherry-pick is complete, open a PR targeting `libc-0.2`. + +See the [tracking issue](https://github.com/rust-lang/libc/issues/3248) for +details. + +## Adding an API + +Want to use an API which currently isn't bound in `libc`? It's quite easy to add +one! + +The internal structure of this crate is designed to minimize the number of +`#[cfg]` attributes in order to easily be able to add new items which apply to +all platforms in the future. As a result, the crate is organized hierarchically +based on platform. Each module has a number of `#[cfg]`'d children, but only one +is ever actually compiled. Each module then reexports all the contents of its +children. + +This means that for each platform that libc supports, the path from a leaf +module to the root will contain all bindings for the platform in question. +Consequently, this indicates where an API should be added! Adding an API at a +particular level in the hierarchy means that it is supported on all the child +platforms of that level. For example, when adding a Unix API it should be added +to `src/unix/mod.rs`, but when adding a Linux-only API it should be added to +`src/unix/linux_like/linux/mod.rs`. + +If you're not 100% sure at what level of the hierarchy an API should be added +at, fear not! This crate has CI support which tests any binding against all +platforms supported, so you'll see failures if an API is added at the wrong +level or has different signatures across platforms. + +New symbol(s) (i.e. functions, constants etc.) should also be added to the +symbols list(s) found in the `libc-test/semver` directory. These lists keep +track of what symbols are public in the libc crate and ensures they remain +available between changes to the crate. If the new symbol(s) are available on +all supported Unixes it should be added to `unix.txt` list1, +otherwise they should be added to the OS specific list(s). + +With that in mind, the steps for adding a new API are: + +1. Determine where in the module hierarchy your API should be added. +2. Add the API, including adding new symbol(s) to the semver lists. +3. Send a PR to this repo. +4. Wait for CI to pass, fixing errors. +5. Wait for a merge! + +1: Note that this list has nothing to do with any Unix or Posix +standard, it's just a list shared among all OSs that declare `#[cfg(unix)]`. + +## Test before you commit + +We have two automated tests running on +[GitHub Actions](https://github.com/rust-lang/libc/actions): + +1. `libc-test` + - `cd libc-test && cargo test` + - Use the `skip_*()` functions in `build.rs` if you really need a workaround. +2. Style checker + - [`./ci/style.py`](https://github.com/rust-lang/libc/blob/main/ci/style.py) + +## Breaking change policy + +Sometimes an upstream adds a breaking change to their API e.g. removing outdated +items, changing the type signature, etc. And we probably should follow that +change to build the `libc` crate successfully. It's annoying to do the +equivalent of semver-major versioning for each such change. Instead, we mark the +item as deprecated and do the actual change after a certain period. The steps +are: + +1. Add `#[deprecated(since = "", note="")]` attribute to the item. + - The `since` field should have a next version of `libc` (e.g., if the current + version is `0.2.1`, it should be `0.2.2`). + - The `note` field should have a reason to deprecate and a tracking issue to + call for comments (e.g., "We consider removing this as the upstream removed + it. If you're using it, please comment on #XXX"). +2. If we don't see any concerns for a while, do the change actually. + +## Supported target policy + +When Rust removes a support for a target, the libc crate also may remove the +support at any time. + +## Releasing your change to crates.io + +This repository uses [release-plz] to handle releases. Once your pull request +has been merged, a maintainer just needs to verify the generated changelog, then +merge the bot's release PR. This will automatically publish to crates.io! + +[release-plz]: https://github.com/MarcoIeni/release-plz diff --git a/deps/crates/vendor/libc/Cargo.lock b/deps/crates/vendor/libc/Cargo.lock new file mode 100644 index 00000000000000..3f41b68601c4a0 --- /dev/null +++ b/deps/crates/vendor/libc/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "libc" +version = "0.2.186" +dependencies = [ + "rustc-std-workspace-core", +] + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" diff --git a/deps/crates/vendor/libc/Cargo.toml b/deps/crates/vendor/libc/Cargo.toml new file mode 100644 index 00000000000000..991aac2cd941e7 --- /dev/null +++ b/deps/crates/vendor/libc/Cargo.toml @@ -0,0 +1,229 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "libc" +version = "0.2.186" +authors = ["The Rust Project Developers"] +build = "build.rs" +exclude = [ + "/ci/*", + "/.github/*", + "/triagebot.toml", + "cherry-pick-stable.sh", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Raw FFI bindings to platform libraries like libc." +readme = "README.md" +keywords = [ + "libc", + "ffi", + "bindings", + "operating", + "system", +] +categories = [ + "external-ffi-bindings", + "no-std", + "os", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/libc" + +[package.metadata.docs.rs] +features = ["extra_traits"] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", + "aarch64-unknown-linux-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "aarch64-pc-windows-gnullvm", + "aarch64-unknown-linux-musl", + "aarch64-unknown-linux-ohos", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-ohos", + "i686-pc-windows-gnu", + "loongarch64-unknown-linux-gnu", + "loongarch64-unknown-linux-musl", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "riscv64gc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "sparcv9-sun-solaris", + "x86_64-apple-darwin", + "x86_64-pc-solaris", + "x86_64-pc-windows-gnullvm", + "x86_64-unknown-freebsd", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-musl", + "x86_64-unknown-linux-ohos", + "x86_64-unknown-netbsd", + "aarch64-apple-ios", + "aarch64-apple-tvos", + "aarch64-apple-visionos", + "aarch64-apple-watchos", + "aarch64-linux-android", + "aarch64-unknown-fuchsia", + "arm-linux-androideabi", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "arm64ec-pc-windows-msvc", + "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-musleabihf", + "i586-unknown-linux-gnu", + "i586-unknown-linux-musl", + "i686-linux-android", + "i686-unknown-freebsd", + "i686-unknown-linux-musl", + "nvptx64-nvidia-cuda", + "riscv64gc-unknown-linux-musl", + "sparc64-unknown-linux-gnu", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "wasm32-unknown-emscripten", + "wasm32-unknown-unknown", + "wasm32-wasip1", + "wasm32-wasip2", + "x86_64-fortanix-unknown-sgx", + "x86_64-linux-android", + "x86_64-unknown-fuchsia", + "x86_64-unknown-linux-gnux32", + "x86_64-unknown-redox", + "aarch64-unknown-freebsd", + "aarch64-unknown-hermit", + "aarch64-unknown-illumos", + "aarch64-unknown-netbsd", + "aarch64-unknown-nto-qnx800", + "aarch64-unknown-openbsd", + "aarch64-unknown-redox", + "aarch64-wrs-vxworks", + "aarch64_be-unknown-linux-gnu", + "aarch64_be-unknown-linux-musl", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", + "armv7-linux-androideabi", + "armv7-wrs-vxworks-eabihf", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "hexagon-unknown-linux-musl", + "i686-unknown-haiku", + "i686-unknown-netbsd", + "i686-unknown-openbsd", + "i686-wrs-vxworks", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips64-unknown-linux-gnuabi64", + "mips64-unknown-linux-muslabi64", + "mips64el-unknown-linux-gnuabi64", + "mips64el-unknown-linux-muslabi64", + "mipsel-sony-psp", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-netbsd", + "powerpc-wrs-vxworks", + "powerpc-wrs-vxworks-spe", + "powerpc64-ibm-aix", + "powerpc64-unknown-freebsd", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", + "powerpc64-wrs-vxworks", + "riscv32-wrs-vxworks", + "riscv32gc-unknown-linux-musl", + "riscv32i-unknown-none-elf", + "riscv32imac-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "riscv64-wrs-vxworks", + "riscv64gc-unknown-freebsd", + "riscv64gc-unknown-hermit", + "riscv64gc-unknown-none-elf", + "riscv64imac-unknown-none-elf", + "s390x-unknown-linux-musl", + "sparc-unknown-linux-gnu", + "sparc64-unknown-netbsd", + "thumbv6m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "wasm32-wasip3", + "x86_64-apple-ios", + "x86_64-pc-cygwin", + "x86_64-unknown-dragonfly", + "x86_64-unknown-haiku", + "x86_64-unknown-hermit", + "x86_64-unknown-hurd-gnu", + "x86_64-unknown-l4re-uclibc", + "x86_64-unknown-openbsd", + "x86_64-wrs-vxworks", +] +cargo-args = ["-Zbuild-std=core"] + +[package.metadata.cargo-semver-checks.lints] +repr_align_removed = "warn" +global_value_marked_deprecated = "warn" + +[features] +align = [] +const-extern-fn = [] +default = ["std"] +extra_traits = [] +rustc-dep-of-std = [ + "align", + "rustc-std-workspace-core", +] +std = [] +use_std = ["std"] + +[lib] +name = "libc" +path = "src/lib.rs" + +[[test]] +name = "const_fn" +path = "tests/const_fn.rs" + +[dependencies.rustc-std-workspace-core] +version = "1.0.1" +optional = true + +[lints.clippy] +expl_impl_clone_on_copy = "allow" +explicit_iter_loop = "warn" +identity_op = "allow" +manual_assert = "warn" +map_unwrap_or = "warn" +missing_safety_doc = "allow" +non_minimal_cfg = "allow" +ptr_as_ptr = "warn" +uninlined_format_args = "allow" +unnecessary_cast = "allow" +unnecessary_semicolon = "warn" +used_underscore_binding = "allow" + +[lints.rust] +unused_qualifications = "allow" diff --git a/deps/crates/vendor/libc/Cargo.toml.orig b/deps/crates/vendor/libc/Cargo.toml.orig new file mode 100644 index 00000000000000..a448d888c77389 --- /dev/null +++ b/deps/crates/vendor/libc/Cargo.toml.orig @@ -0,0 +1,218 @@ +[package] +name = "libc" +version = "0.2.186" +keywords = ["libc", "ffi", "bindings", "operating", "system"] +categories = ["external-ffi-bindings", "no-std", "os"] +exclude = ["/ci/*", "/.github/*", "/triagebot.toml", "cherry-pick-stable.sh"] +description = "Raw FFI bindings to platform libraries like libc." +authors = ["The Rust Project Developers"] +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/libc" +rust-version = "1.65" + +[package.metadata.docs.rs] +features = ["extra_traits"] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + # Note: Keep this in sync with ci/verify-build.py + # + # Tier 1 + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", + "aarch64-unknown-linux-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + # + # Tier 2 with host tools + "aarch64-pc-windows-gnullvm", + "aarch64-unknown-linux-musl", + "aarch64-unknown-linux-ohos", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-ohos", + "i686-pc-windows-gnu", + "loongarch64-unknown-linux-gnu", + "loongarch64-unknown-linux-musl", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "riscv64gc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "sparcv9-sun-solaris", + "x86_64-apple-darwin", + "x86_64-pc-solaris", + "x86_64-pc-windows-gnullvm", + "x86_64-unknown-freebsd", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-musl", + "x86_64-unknown-linux-ohos", + "x86_64-unknown-netbsd", + # + # Tier 2 without host tools + "aarch64-apple-ios", + "aarch64-apple-tvos", + "aarch64-apple-visionos", + "aarch64-apple-watchos", + "aarch64-linux-android", + "aarch64-unknown-fuchsia", + "arm-linux-androideabi", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "arm64ec-pc-windows-msvc", + "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-musleabihf", + "i586-unknown-linux-gnu", + "i586-unknown-linux-musl", + "i686-linux-android", + "i686-unknown-freebsd", + "i686-unknown-linux-musl", + "nvptx64-nvidia-cuda", + "riscv64gc-unknown-linux-musl", + "sparc64-unknown-linux-gnu", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "wasm32-unknown-emscripten", + "wasm32-unknown-unknown", + "wasm32-wasip1", + "wasm32-wasip2", + "x86_64-fortanix-unknown-sgx", + "x86_64-linux-android", + "x86_64-unknown-fuchsia", + "x86_64-unknown-linux-gnux32", + "x86_64-unknown-redox", + # + # Tier 3 targets that are distinct enough to be useful, or have historically + # been documented. + "aarch64-unknown-freebsd", + "aarch64-unknown-hermit", + "aarch64-unknown-illumos", + "aarch64-unknown-netbsd", + "aarch64-unknown-nto-qnx800", + "aarch64-unknown-openbsd", + "aarch64-unknown-redox", + "aarch64-wrs-vxworks", + "aarch64_be-unknown-linux-gnu", + "aarch64_be-unknown-linux-musl", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", + "armv7-linux-androideabi", + "armv7-wrs-vxworks-eabihf", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "hexagon-unknown-linux-musl", + "i686-unknown-haiku", + "i686-unknown-netbsd", + "i686-unknown-openbsd", + "i686-wrs-vxworks", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips64-unknown-linux-gnuabi64", + "mips64-unknown-linux-muslabi64", + "mips64el-unknown-linux-gnuabi64", + "mips64el-unknown-linux-muslabi64", + "mipsel-sony-psp", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-netbsd", + "powerpc-wrs-vxworks", + "powerpc-wrs-vxworks-spe", + "powerpc64-ibm-aix", + "powerpc64-unknown-freebsd", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", + "powerpc64-wrs-vxworks", + "riscv32-wrs-vxworks", + "riscv32gc-unknown-linux-musl", + "riscv32i-unknown-none-elf", + "riscv32imac-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "riscv64-wrs-vxworks", + "riscv64gc-unknown-freebsd", + "riscv64gc-unknown-hermit", + "riscv64gc-unknown-none-elf", + "riscv64imac-unknown-none-elf", + "s390x-unknown-linux-musl", + "sparc-unknown-linux-gnu", + "sparc64-unknown-netbsd", + "thumbv6m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "wasm32-wasip3", + "x86_64-apple-ios", + "x86_64-pc-cygwin", + "x86_64-unknown-dragonfly", + "x86_64-unknown-haiku", + "x86_64-unknown-hermit", + "x86_64-unknown-hurd-gnu", + "x86_64-unknown-l4re-uclibc", + "x86_64-unknown-openbsd", + "x86_64-wrs-vxworks" +] +cargo-args = ["-Zbuild-std=core"] + +[dependencies] +rustc-std-workspace-core = { version = "1.0.1", optional = true } + +[features] +default = ["std"] +std = [] +rustc-dep-of-std = ['align', 'rustc-std-workspace-core'] +extra_traits = [] + +# `const-extern-function` is deprecated and no longer does anything +const-extern-fn = [] + +# `align` is deprecated and no longer does anything +align = [] + +# use_std is deprecated, use `std` instead +use_std = ['std'] + +[workspace] +members = [ + "ctest", + "libc-test", +] + +# FIXME(msrv): These should be renamed as `[workspace.lints.*]` once MSRV is above 1.64 +# This way all crates can use it with `[lints] workspace=true` section + +[lints.rust] +# FIXME(cleanup): make ident usage consistent in each file +unused_qualifications = "allow" + +[lints.clippy] +# Enable pedantic lints - use this manually once in a while, but don't enable by default +# pedantic = { level = "warn", priority = -1 } + +# We are okay with the current state of these lints +explicit_iter_loop = "warn" +identity_op = "allow" # some expressions like `0 | x` are clearer for bit ops +manual_assert = "warn" +map_unwrap_or = "warn" +missing_safety_doc = "allow" # safety? in libc? seriously? +non_minimal_cfg = "allow" # for some reason cfg_if! sometimes trigger this +ptr_as_ptr = "warn" +unnecessary_semicolon = "warn" + +# FIXME(clippy): these should be fixed if possible +expl_impl_clone_on_copy = "allow" +uninlined_format_args = "allow" +unnecessary_cast = "allow" # some casts like `as usize` are only needed for some targets +used_underscore_binding = "allow" + +[package.metadata.cargo-semver-checks.lints] +# Alignment is an internal detail that users must not rely upon +repr_align_removed = "warn" +# We deprecate things all the time +global_value_marked_deprecated = "warn" diff --git a/deps/crates/vendor/libc/LICENSE-APACHE b/deps/crates/vendor/libc/LICENSE-APACHE new file mode 100644 index 00000000000000..1b5ec8b78e237b --- /dev/null +++ b/deps/crates/vendor/libc/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/deps/crates/vendor/libc/LICENSE-MIT b/deps/crates/vendor/libc/LICENSE-MIT new file mode 100644 index 00000000000000..f4095b2fa2d9b6 --- /dev/null +++ b/deps/crates/vendor/libc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/libc/README.md b/deps/crates/vendor/libc/README.md new file mode 100644 index 00000000000000..76ecb8673bb545 --- /dev/null +++ b/deps/crates/vendor/libc/README.md @@ -0,0 +1,115 @@ +# libc - Raw FFI bindings to platforms' system libraries + +[![GHA Status]][GitHub Actions] [![Latest Version]][crates.io] [![Documentation]][docs.rs] ![License] + +`libc` provides all of the definitions necessary to easily interoperate with C +code (or "C-like" code) on each of the platforms that Rust supports. This +includes type definitions (e.g. `c_int`), constants (e.g. `EINVAL`) as well as +function headers (e.g. `malloc`). + +This crate exports all underlying platform types, functions, and constants under +the crate root, so all items are accessible as `libc::foo`. The types and values +of all the exported APIs match the platform that libc is compiled for. + +Windows API bindings are not included in this crate. If you are looking for +WinAPI bindings, consider using crates like [windows-sys]. + +More detailed information about the design of this library can be found in its +[associated RFC][rfc]. + +[rfc]: https://github.com/rust-lang/rfcs/blob/HEAD/text/1291-promote-libc.md +[windows-sys]: https://docs.rs/windows-sys + +## v1.0 Roadmap + +Currently, `libc` has two active branches: `main` for the upcoming v1.0 release, +and `libc-0.2` for the currently published version. By default all pull requests +should target `main`; once reviewed, they can be cherry picked to the `libc-0.2` +branch if needed. + +We will stop making new v0.2 releases once v1.0 is released. + +See the section in [CONTRIBUTING.md](CONTRIBUTING.md#v10-roadmap) for more +details. + +## Usage + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +libc = "0.2" +``` + +## Features + +* `std`: by default `libc` links to the standard library. Disable this feature + to remove this dependency and be able to use `libc` in `#![no_std]` crates. + +* `extra_traits`: all `struct`s implemented in `libc` are `Copy` and `Clone`. + This feature derives `Debug`, `Eq`, `Hash`, and `PartialEq`. + +The following features are deprecated: + +* `use_std`: this is equivalent to `std` +* `const-extern-fn`: this is now enabled by default +* `align`: this is now enabled by default + +## Rust version support + +The minimum supported Rust toolchain version is currently **Rust 1.65**. + +Increases to the MSRV are allowed to change without a major (i.e. semver- +breaking) release in order to avoid a ripple effect in the ecosystem. A policy +for when this may change is a work in progress. + +`libc` may continue to compile with Rust versions older than the current MSRV +but this is not guaranteed. + +## Platform support + +You can see the platform(target)-specific docs on [docs.rs], select a platform +you want to see. + +See [`ci/verify-build.py`](https://github.com/rust-lang/libc/blob/HEAD/ci/verify-build.py) for +the platforms on which `libc` is guaranteed to build for each Rust toolchain. +The test matrices at [GitHub Actions] show the platforms in which `libc` tests +are run. + +

+ +## License + +This project is licensed under either of + +* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) + ([LICENSE-APACHE](https://github.com/rust-lang/libc/blob/HEAD/LICENSE-APACHE)) + +* [MIT License](https://opensource.org/licenses/MIT) + ([LICENSE-MIT](https://github.com/rust-lang/libc/blob/HEAD/LICENSE-MIT)) + +at your option. + +## Contributing + +We welcome all people who want to contribute. Please see the +[contributing instructions] for more information. + +[contributing instructions]: https://github.com/rust-lang/libc/blob/HEAD/CONTRIBUTING.md + +Contributions in any form (issues, pull requests, etc.) to this project must +adhere to Rust's [Code of Conduct]. + +[Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `libc` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[GitHub Actions]: https://github.com/rust-lang/libc/actions +[GHA Status]: https://github.com/rust-lang/libc/workflows/CI/badge.svg +[crates.io]: https://crates.io/crates/libc +[Latest Version]: https://img.shields.io/crates/v/libc.svg +[Documentation]: https://docs.rs/libc/badge.svg +[docs.rs]: https://docs.rs/libc +[License]: https://img.shields.io/crates/l/libc.svg diff --git a/deps/crates/vendor/libc/build.rs b/deps/crates/vendor/libc/build.rs new file mode 100644 index 00000000000000..34df96aa7ce0f1 --- /dev/null +++ b/deps/crates/vendor/libc/build.rs @@ -0,0 +1,346 @@ +use std::env::VarError; +use std::process::{ + Command, + Output, +}; +use std::{ + env, + str, +}; + +// List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we +// need to know all the possible cfgs that this script will set. If you need to set another cfg +// make sure to add it to this list as well. +const ALLOWED_CFGS: &[&str] = &[ + "emscripten_old_stat_abi", + // Should be enabled by users if esp-idf (>=6.0) is build with picolibc instead of newlib. + "espidf_picolibc", + "espidf_time32", + "freebsd10", + "freebsd11", + "freebsd12", + "freebsd13", + "freebsd14", + "freebsd15", + // Corresponds to `_FILE_OFFSET_BITS=64` in glibc + "gnu_file_offset_bits64", + // Corresponds to `_TIME_BITS=64` in glibc + "gnu_time_bits64", + "libc_deny_warnings", + // Corresponds to `__USE_TIME_BITS64` in UAPI + "linux_time_bits64", + "musl_v1_2_3", + // musl v1.2.3+ && 32-bit: time_t is i64, struct layouts change + "musl32_time64", + // Corresponds to `_REDIR_TIME64` in musl: symbol redirects to __*_time64 + "musl_redir_time64", + "vxworks_lt_25_09", +]; + +// Extra values to allow for check-cfg. +const CHECK_CFG_EXTRA: &[(&str, &[&str])] = &[ + ( + "target_os", + &[ + "switch", "aix", "ohos", "hurd", "rtems", "visionos", "nuttx", "cygwin", "qurt", + ], + ), + ( + "target_env", + &["illumos", "wasi", "aix", "ohos", "nto71_iosock", "nto80"], + ), + ( + "target_arch", + &["loongarch64", "mips32r6", "mips64r6", "csky"], + ), +]; + +/// Musl architectures that define `_REDIR_TIME64` (i.e. those that transitioned +/// from 32-bit to 64-bit `time_t` and need `__*_time64` symbol redirects). +const MUSL_REDIR_TIME64_ARCHES: &[&str] = &["arm", "mips", "powerpc", "x86"]; + +fn main() { + // Avoid unnecessary re-building. + println!("cargo:rerun-if-changed=build.rs"); + + let (rustc_minor_ver, _is_nightly) = rustc_minor_nightly(); + let libc_ci = env_flag("LIBC_CI"); + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_ptr_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap_or_default(); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); + + // The ABI of libc used by std is backward compatible with FreeBSD 12. + // The ABI of libc from crates.io is backward compatible with FreeBSD 12. + // + // On CI, we detect the actual FreeBSD version and match its ABI exactly, + // running tests to ensure that the ABI is correct. + println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_FREEBSD_VERSION"); + // Allow overriding the default version for testing + let which_freebsd = if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") { + let vers = version.parse().unwrap(); + println!("cargo:warning=setting FreeBSD version to {vers}"); + vers + } else if libc_ci { + which_freebsd().unwrap_or(12) + } else { + 12 + }; + + match which_freebsd { + x if x < 10 => panic!("FreeBSD older than 10 is not supported"), + 10 => set_cfg("freebsd10"), + 11 => set_cfg("freebsd11"), + 12 => set_cfg("freebsd12"), + 13 => set_cfg("freebsd13"), + 14 => set_cfg("freebsd14"), + _ => set_cfg("freebsd15"), + } + + match emcc_version_code() { + Some(v) if (v < 30142) => set_cfg("emscripten_old_stat_abi"), + // Non-Emscripten or version >= 3.1.42. + _ => (), + } + + match vxworks_version_code() { + Some(v) if (v < (25, 9)) => set_cfg("vxworks_lt_25_09"), + // VxWorks version >= 25.09 + _ => (), + } + + let mut musl_v1_2_3 = env_flag("RUST_LIBC_UNSTABLE_MUSL_V1_2_3"); + println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_MUSL_V1_2_3"); + + // OpenHarmony uses a fork of the musl libc + let musl = target_env == "musl" || target_env == "ohos"; + + // loongarch64, hexagon, and ohos only exist with recent musl + if target_arch == "loongarch64" || target_arch == "hexagon" || target_env == "ohos" { + musl_v1_2_3 = true; + } + + if musl && musl_v1_2_3 { + set_cfg("musl_v1_2_3"); + if target_ptr_width == "32" { + set_cfg("musl32_time64"); + set_cfg("linux_time_bits64"); + } + if MUSL_REDIR_TIME64_ARCHES.contains(&target_arch.as_str()) { + set_cfg("musl_redir_time64"); + } + } + + let linux_time_bits64 = env::var("RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64").is_ok(); + println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64"); + if linux_time_bits64 { + set_cfg("linux_time_bits64"); + } + println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS"); + println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_GNU_TIME_BITS"); + if target_env == "gnu" + && target_os == "linux" + && target_ptr_width == "32" + && target_arch != "riscv32" + && target_arch != "x86_64" + { + let defaultbits = "32".to_string(); + let (timebits, filebits) = match ( + env::var("RUST_LIBC_UNSTABLE_GNU_TIME_BITS"), + env::var("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS"), + ) { + (Ok(_), Ok(_)) => panic!("Do not set both RUST_LIBC_UNSTABLE_GNU_TIME_BITS and RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS"), + (Err(_), Err(_)) => (defaultbits.clone(), defaultbits.clone()), + (Ok(tb), Err(_)) if tb == "64" => (tb.clone(), tb.clone()), + (Ok(tb), Err(_)) if tb == "32" => (tb, defaultbits.clone()), + (Ok(_), Err(_)) => panic!("Invalid value for RUST_LIBC_UNSTABLE_GNU_TIME_BITS, must be 32 or 64"), + (Err(_), Ok(fb)) if fb == "32" || fb == "64" => (defaultbits.clone(), fb), + (Err(_), Ok(_)) => panic!("Invalid value for RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS, must be 32 or 64"), + }; + let valid_bits = ["32", "64"]; + assert!( + valid_bits.contains(&filebits.as_str()) && valid_bits.contains(&timebits.as_str()), + "Invalid value for RUST_LIBC_UNSTABLE_GNU_TIME_BITS or RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS, must be 32, 64 or unset" + ); + assert!( + !(filebits == "32" && timebits == "64"), + "RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS must be 64 or unset if RUST_LIBC_UNSTABLE_GNU_TIME_BITS is 64" + ); + if timebits == "64" { + set_cfg("linux_time_bits64"); + set_cfg("gnu_time_bits64"); + } + if filebits == "64" { + set_cfg("gnu_file_offset_bits64"); + } + } + + // On CI: deny all warnings + if libc_ci { + set_cfg("libc_deny_warnings"); + } + + // Since Rust 1.80, configuration that isn't recognized by default needs to be provided to + // avoid warnings. + if rustc_minor_ver >= 80 { + for cfg in ALLOWED_CFGS { + println!("cargo:rustc-check-cfg=cfg({cfg})"); + } + for &(name, values) in CHECK_CFG_EXTRA { + let values = values.join("\",\""); + println!("cargo:rustc-check-cfg=cfg({name},values(\"{values}\"))"); + } + } +} + +/// Run `rustc --version` and capture the output, adjusting arguments as needed if `clippy-driver` +/// is used instead. +fn rustc_version_cmd(is_clippy_driver: bool) -> Output { + let rustc = env::var_os("RUSTC").expect("Failed to get rustc version: missing RUSTC env"); + + let mut cmd = match env::var_os("RUSTC_WRAPPER") { + Some(ref wrapper) if wrapper.is_empty() => Command::new(rustc), + Some(wrapper) => { + let mut cmd = Command::new(wrapper); + cmd.arg(rustc); + if is_clippy_driver { + cmd.arg("--rustc"); + } + + cmd + } + None => Command::new(rustc), + }; + + cmd.arg("--version"); + + let output = cmd.output().expect("Failed to get rustc version"); + + assert!( + output.status.success(), + "failed to run rustc: {}", + String::from_utf8_lossy(output.stderr.as_slice()) + ); + + output +} + +/// Return the minor version of `rustc`, as well as a bool indicating whether or not the version +/// is a nightly. +fn rustc_minor_nightly() -> (u32, bool) { + macro_rules! otry { + ($e:expr) => { + match $e { + Some(e) => e, + None => panic!("Failed to get rustc version"), + } + }; + } + + let mut output = rustc_version_cmd(false); + + if otry!(str::from_utf8(&output.stdout).ok()).starts_with("clippy") { + output = rustc_version_cmd(true); + } + + let version = otry!(str::from_utf8(&output.stdout).ok()); + + let mut pieces = version.split('.'); + + assert_eq!( + pieces.next(), + Some("rustc 1"), + "Failed to get rustc version" + ); + + let minor = pieces.next(); + + // If `rustc` was built from a tarball, its version string + // will have neither a git hash nor a commit date + // (e.g. "rustc 1.39.0"). Treat this case as non-nightly, + // since a nightly build should either come from CI + // or a git checkout + let nightly_raw = otry!(pieces.next()).split('-').nth(1); + let nightly = nightly_raw.map_or(false, |raw| { + raw.starts_with("dev") || raw.starts_with("nightly") + }); + let minor = otry!(otry!(minor).parse().ok()); + + (minor, nightly) +} + +fn which_freebsd() -> Option { + let output = Command::new("freebsd-version").output().ok()?; + if !output.status.success() { + return None; + } + + let stdout = String::from_utf8(output.stdout).ok()?; + + match &stdout { + s if s.starts_with("10") => Some(10), + s if s.starts_with("11") => Some(11), + s if s.starts_with("12") => Some(12), + s if s.starts_with("13") => Some(13), + s if s.starts_with("14") => Some(14), + s if s.starts_with("15") => Some(15), + _ => None, + } +} + +fn emcc_version_code() -> Option { + let emcc = if cfg!(target_os = "windows") { + "emcc.bat" + } else { + "emcc" + }; + + let output = Command::new(emcc).arg("-dumpversion").output().ok()?; + if !output.status.success() { + return None; + } + + let version = String::from_utf8(output.stdout).ok()?; + + // Some Emscripten versions come with `-git` attached, so split the + // version string also on the `-` char. + let mut pieces = version.trim().split(['.', '-']); + + let major = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let minor = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let patch = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + + Some(major * 10000 + minor * 100 + patch) +} + +/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build +/// environment, in `(minor, patch)` form. Currently the only major version supported by Rust +/// is 7. +fn vxworks_version_code() -> Option<(u32, u32)> { + let version = env::var("WIND_RELEASE_ID").ok()?; + + let mut pieces = version.trim().split(['.']); + + let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + + Some((major, minor)) +} + +fn set_cfg(cfg: &str) { + assert!( + ALLOWED_CFGS.contains(&cfg), + "trying to set cfg {cfg}, but it is not in ALLOWED_CFGS", + ); + println!("cargo:rustc-cfg={cfg}"); +} + +/// Return true if the env is set to a value other than `0`. +fn env_flag(key: &str) -> bool { + match env::var(key) { + Ok(x) if x == "0" => false, + Err(VarError::NotPresent) => false, + Err(VarError::NotUnicode(_)) => panic!("non-unicode var for `{key}`"), + Ok(_) => true, + } +} diff --git a/deps/crates/vendor/libc/src/fuchsia/aarch64.rs b/deps/crates/vendor/libc/src/fuchsia/aarch64.rs new file mode 100644 index 00000000000000..93090f7238d7a7 --- /dev/null +++ b/deps/crates/vendor/libc/src/fuchsia/aarch64.rs @@ -0,0 +1,69 @@ +use crate::off_t; +use crate::prelude::*; + +pub type __u64 = c_ulonglong; +pub type wchar_t = u32; +pub type nlink_t = c_ulong; +pub type blksize_t = c_long; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad0: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad1: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_uint; 2]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad0: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad1: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_uint; 2]>, + } + + pub struct ipc_perm { + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_ushort, + __unused1: Padding, + __unused2: Padding, + } +} + +// From https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/third_party/ulib/musl/include/bits/signal.h;l=20-21;drc=0827b18ab9540c46f8037f407d17ea15a79e9ba7 +pub const MINSIGSTKSZ: size_t = 6144; +pub const SIGSTKSZ: size_t = 12288; diff --git a/deps/crates/vendor/libc/src/fuchsia/mod.rs b/deps/crates/vendor/libc/src/fuchsia/mod.rs new file mode 100644 index 00000000000000..3e35faa7b71146 --- /dev/null +++ b/deps/crates/vendor/libc/src/fuchsia/mod.rs @@ -0,0 +1,4026 @@ +//! Definitions found commonly among almost all Unix derivatives +//! +//! More functions and definitions can be found in the more specific modules +//! according to the platform in question. + +use crate::prelude::*; + +// PUB_TYPE + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type locale_t = *mut c_void; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type pid_t = i32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type sighandler_t = size_t; +pub type cc_t = c_uchar; +pub type sa_family_t = u16; +pub type pthread_key_t = c_uint; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type clockid_t = c_int; +pub type key_t = c_int; +pub type id_t = c_uint; +pub type useconds_t = u32; +pub type dev_t = u64; +pub type socklen_t = u32; +pub type pthread_t = c_ulong; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type mqd_t = c_int; +pub type nfds_t = c_ulong; +pub type nl_item = c_int; +pub type idtype_t = c_uint; +pub type loff_t = c_longlong; + +pub type __u8 = c_uchar; +pub type __u16 = c_ushort; +pub type __s16 = c_short; +pub type __u32 = c_uint; +pub type __s32 = c_int; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; + +pub type clock_t = c_long; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; + +pub type shmatt_t = c_ulong; +pub type msgqnum_t = c_ulong; +pub type msglen_t = c_ulong; +pub type fsblkcnt_t = c_ulonglong; +pub type fsfilcnt_t = c_ulonglong; +pub type rlim_t = c_ulonglong; + +extern_ty! { + pub enum timezone {} + pub enum DIR {} + pub enum fpos64_t {} // FIXME(fuchsia): fill this out with a struct +} + +// PUB_STRUCT + +s! { + pub struct group { + pub gr_name: *mut c_char, + pub gr_passwd: *mut c_char, + pub gr_gid: crate::gid_t, + pub gr_mem: *mut *mut c_char, + } + + pub struct utimbuf { + pub actime: time_t, + pub modtime: time_t, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + // FIXME(fuchsia): the rlimit and rusage related functions and types don't exist + // within zircon. Are there reasons for keeping them around? + pub struct rlimit { + pub rlim_cur: rlim_t, + pub rlim_max: rlim_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad1: Padding, + pub ru_ixrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad2: Padding, + pub ru_idrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad3: Padding, + pub ru_isrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad4: Padding, + pub ru_minflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad5: Padding, + pub ru_majflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad6: Padding, + pub ru_nswap: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad7: Padding, + pub ru_inblock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad8: Padding, + pub ru_oublock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad9: Padding, + pub ru_msgsnd: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad10: Padding, + pub ru_msgrcv: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad11: Padding, + pub ru_nsignals: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad12: Padding, + pub ru_nvcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad13: Padding, + pub ru_nivcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad14: Padding, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + pub struct hostent { + pub h_name: *mut c_char, + pub h_aliases: *mut *mut c_char, + pub h_addrtype: c_int, + pub h_length: c_int, + pub h_addr_list: *mut *mut c_char, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + pub struct pollfd { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + } + + pub struct winsize { + pub ws_row: c_ushort, + pub ws_col: c_ushort, + pub ws_xpixel: c_ushort, + pub ws_ypixel: c_ushort, + } + + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + pub struct sigval { + // Actually a union of an int and a void* + pub sival_ptr: *mut c_void, + } + + // + pub struct itimerval { + pub it_interval: crate::timeval, + pub it_value: crate::timeval, + } + + // + pub struct tms { + pub tms_utime: crate::clock_t, + pub tms_stime: crate::clock_t, + pub tms_cutime: crate::clock_t, + pub tms_cstime: crate::clock_t, + } + + pub struct servent { + pub s_name: *mut c_char, + pub s_aliases: *mut *mut c_char, + pub s_port: c_int, + pub s_proto: *mut c_char, + } + + pub struct protoent { + pub p_name: *mut c_char, + pub p_aliases: *mut *mut c_char, + pub p_proto: c_int, + } + + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: crate::sigevent, + __td: *mut c_void, + __lock: [c_int; 2], + __err: c_int, + __ret: ssize_t, + pub aio_offset: off_t, + __next: *mut c_void, + __prev: *mut c_void, + #[cfg(target_pointer_width = "32")] + __dummy4: [c_char; 24], + #[cfg(target_pointer_width = "64")] + __dummy4: [c_char; 16], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub __c_ispeed: crate::speed_t, + pub __c_ospeed: crate::speed_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct ucred { + pub pid: crate::pid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_vm { + pub svm_family: sa_family_t, + svm_reserved1: Padding, + pub svm_port: crate::in_port_t, + pub svm_cid: c_uint, + pub svm_zero: [u8; 4], + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + + pub ai_addr: *mut crate::sockaddr, + + pub ai_canonname: *mut c_char, + + pub ai_next: *mut addrinfo, + } + + pub struct sockaddr_ll { + pub sll_family: c_ushort, + pub sll_protocol: c_ushort, + pub sll_ifindex: c_int, + pub sll_hatype: c_ushort, + pub sll_pkttype: c_uchar, + pub sll_halen: c_uchar, + pub sll_addr: [c_uchar; 8], + } + + pub struct fd_set { + fds_bits: [c_ulong; FD_SETSIZE as usize / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + pub struct sched_param { + pub sched_priority: c_int, + pub sched_ss_low_priority: c_int, + pub sched_ss_repl_period: crate::timespec, + pub sched_ss_init_budget: crate::timespec, + pub sched_ss_max_repl: c_int, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct epoll_event { + pub events: u32, + pub u64: u64, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_ifu: *mut crate::sockaddr, // FIXME(union) This should be a union + pub ifa_data: *mut c_void, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct spwd { + pub sp_namp: *mut c_char, + pub sp_pwdp: *mut c_char, + pub sp_lstchg: c_long, + pub sp_min: c_long, + pub sp_max: c_long, + pub sp_warn: c_long, + pub sp_inact: c_long, + pub sp_expire: c_long, + pub sp_flag: c_ulong, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: c_ulong, + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))] + __f_unused: Padding, + #[cfg(target_endian = "big")] + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct dqblk { + pub dqb_bhardlimit: u64, + pub dqb_bsoftlimit: u64, + pub dqb_curspace: u64, + pub dqb_ihardlimit: u64, + pub dqb_isoftlimit: u64, + pub dqb_curinodes: u64, + pub dqb_btime: u64, + pub dqb_itime: u64, + pub dqb_valid: u32, + } + + pub struct signalfd_siginfo { + pub ssi_signo: u32, + pub ssi_errno: i32, + pub ssi_code: i32, + pub ssi_pid: u32, + pub ssi_uid: u32, + pub ssi_fd: i32, + pub ssi_tid: u32, + pub ssi_band: u32, + pub ssi_overrun: u32, + pub ssi_trapno: u32, + pub ssi_status: i32, + pub ssi_int: i32, + pub ssi_ptr: u64, + pub ssi_utime: u64, + pub ssi_stime: u64, + pub ssi_addr: u64, + pub ssi_addr_lsb: u16, + _pad2: Padding, + pub ssi_syscall: i32, + pub ssi_call_addr: u64, + pub ssi_arch: u32, + _pad: Padding<[u8; 28]>, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct fsid_t { + __val: [c_int; 2], + } + + pub struct cpu_set_t { + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))] + bits: [u32; 32], + #[cfg(not(all(target_pointer_width = "32", not(target_arch = "x86_64"))))] + bits: [u64; 16], + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: c_int, + pub msgmap: c_int, + pub msgmax: c_int, + pub msgmnb: c_int, + pub msgmni: c_int, + pub msgssz: c_int, + pub msgtql: c_int, + pub msgseg: c_ushort, + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct input_event { + pub time: crate::timeval, + pub type_: crate::__u16, + pub code: crate::__u16, + pub value: crate::__s32, + } + + pub struct input_id { + pub bustype: crate::__u16, + pub vendor: crate::__u16, + pub product: crate::__u16, + pub version: crate::__u16, + } + + pub struct input_absinfo { + pub value: crate::__s32, + pub minimum: crate::__s32, + pub maximum: crate::__s32, + pub fuzz: crate::__s32, + pub flat: crate::__s32, + pub resolution: crate::__s32, + } + + pub struct input_keymap_entry { + pub flags: crate::__u8, + pub len: crate::__u8, + pub index: crate::__u16, + pub keycode: crate::__u32, + pub scancode: [crate::__u8; 32], + } + + pub struct input_mask { + pub type_: crate::__u32, + pub codes_size: crate::__u32, + pub codes_ptr: crate::__u64, + } + + pub struct ff_replay { + pub length: crate::__u16, + pub delay: crate::__u16, + } + + pub struct ff_trigger { + pub button: crate::__u16, + pub interval: crate::__u16, + } + + pub struct ff_envelope { + pub attack_length: crate::__u16, + pub attack_level: crate::__u16, + pub fade_length: crate::__u16, + pub fade_level: crate::__u16, + } + + pub struct ff_constant_effect { + pub level: crate::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_ramp_effect { + pub start_level: crate::__s16, + pub end_level: crate::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_condition_effect { + pub right_saturation: crate::__u16, + pub left_saturation: crate::__u16, + + pub right_coeff: crate::__s16, + pub left_coeff: crate::__s16, + + pub deadband: crate::__u16, + pub center: crate::__s16, + } + + pub struct ff_periodic_effect { + pub waveform: crate::__u16, + pub period: crate::__u16, + pub magnitude: crate::__s16, + pub offset: crate::__s16, + pub phase: crate::__u16, + + pub envelope: ff_envelope, + + pub custom_len: crate::__u32, + pub custom_data: *mut crate::__s16, + } + + pub struct ff_rumble_effect { + pub strong_magnitude: crate::__u16, + pub weak_magnitude: crate::__u16, + } + + pub struct ff_effect { + pub type_: crate::__u16, + pub id: crate::__s16, + pub direction: crate::__u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + // FIXME(1.0): this is actually a union + #[cfg(target_pointer_width = "64")] + pub u: [u64; 4], + #[cfg(target_pointer_width = "32")] + pub u: [u32; 7], + } + + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: size_t, + pub dlpi_tls_data: *mut c_void, + } + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct statfs64 { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_frsize: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct pthread_attr_t { + __size: [u64; 7], + } + + pub struct sigset_t { + __val: [c_ulong; 16], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } + + pub struct statfs { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_frsize: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 4], + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + __pad1: Padding, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + __pad2: Padding, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub __pad1: c_int, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct sem_t { + __val: [c_int; 8], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct termios2 { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; 19], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + #[cfg_attr( + any(target_pointer_width = "32", target_arch = "x86_64"), + repr(align(4)) + )] + #[cfg_attr( + not(any(target_pointer_width = "32", target_arch = "x86_64")), + repr(align(8)) + )] + pub struct pthread_mutexattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct pthread_rwlockattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_CONDATTR_T], + } + + pub struct sysinfo { + pub uptime: c_ulong, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + __reserved: Padding<[c_char; 256]>, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_pad2: Padding<[u8; 128 - 2 - 8]>, + __ss_align: size_t, + } + + pub struct utsname { + pub sysname: [c_char; 65], + pub nodename: [c_char; 65], + pub release: [c_char; 65], + pub version: [c_char; 65], + pub machine: [c_char; 65], + pub domainname: [c_char; 65], + } + + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_off: off_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct dirent64 { + pub d_ino: crate::ino64_t, + pub d_off: off64_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + // x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 + pub struct mq_attr { + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_flags: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_maxmsg: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_msgsize: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_curmsgs: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pad: Padding<[i64; 4]>, + + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_flags: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_maxmsg: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_msgsize: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_curmsgs: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pad: Padding<[c_long; 4]>, + } + + pub struct sockaddr_nl { + pub nl_family: crate::sa_family_t, + nl_pad: Padding, + pub nl_pid: u32, + pub nl_groups: u32, + } + + // FIXME(msrv): suggested method was added in 1.85 + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigevent { + pub sigev_value: crate::sigval, + pub sigev_signo: c_int, + pub sigev_notify: c_int, + pub sigev_notify_function: fn(crate::sigval), + pub sigev_notify_attributes: *mut pthread_attr_t, + pub __pad: [c_char; 56 - 3 * 8], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "x86_64") + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any(target_arch = "arm", target_arch = "x86_64")) + ), + repr(align(8)) + )] + pub struct pthread_mutex_t { + size: [u8; crate::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any(target_arch = "arm", target_arch = "x86_64") + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any(target_arch = "arm", target_arch = "x86_64")) + ), + repr(align(8)) + )] + pub struct pthread_rwlock_t { + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + #[cfg_attr(target_arch = "x86", repr(align(4)))] + #[cfg_attr(not(target_arch = "x86"), repr(align(8)))] + pub struct pthread_cond_t { + size: [u8; crate::__SIZEOF_PTHREAD_COND_T], + } +} + +// PUB_CONST + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = !0 as sighandler_t; + +pub const DT_UNKNOWN: u8 = 0; +pub const DT_FIFO: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_REG: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; + +pub const FD_CLOEXEC: c_int = 0x1; + +pub const USRQUOTA: c_int = 0; +pub const GRPQUOTA: c_int = 1; + +pub const SIGIOT: c_int = 6; + +pub const S_ISUID: mode_t = 0o4000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISVTX: mode_t = 0o1000; + +pub const IF_NAMESIZE: size_t = 16; +pub const IFNAMSIZ: size_t = IF_NAMESIZE; + +pub const LOG_EMERG: c_int = 0; +pub const LOG_ALERT: c_int = 1; +pub const LOG_CRIT: c_int = 2; +pub const LOG_ERR: c_int = 3; +pub const LOG_WARNING: c_int = 4; +pub const LOG_NOTICE: c_int = 5; +pub const LOG_INFO: c_int = 6; +pub const LOG_DEBUG: c_int = 7; + +pub const LOG_KERN: c_int = 0; +pub const LOG_USER: c_int = 1 << 3; +pub const LOG_MAIL: c_int = 2 << 3; +pub const LOG_DAEMON: c_int = 3 << 3; +pub const LOG_AUTH: c_int = 4 << 3; +pub const LOG_SYSLOG: c_int = 5 << 3; +pub const LOG_LPR: c_int = 6 << 3; +pub const LOG_NEWS: c_int = 7 << 3; +pub const LOG_UUCP: c_int = 8 << 3; +pub const LOG_LOCAL0: c_int = 16 << 3; +pub const LOG_LOCAL1: c_int = 17 << 3; +pub const LOG_LOCAL2: c_int = 18 << 3; +pub const LOG_LOCAL3: c_int = 19 << 3; +pub const LOG_LOCAL4: c_int = 20 << 3; +pub const LOG_LOCAL5: c_int = 21 << 3; +pub const LOG_LOCAL6: c_int = 22 << 3; +pub const LOG_LOCAL7: c_int = 23 << 3; + +pub const LOG_PID: c_int = 0x01; +pub const LOG_CONS: c_int = 0x02; +pub const LOG_ODELAY: c_int = 0x04; +pub const LOG_NDELAY: c_int = 0x08; +pub const LOG_NOWAIT: c_int = 0x10; + +pub const LOG_PRIMASK: c_int = 7; +pub const LOG_FACMASK: c_int = 0x3f8; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const PRIO_MIN: c_int = -20; +pub const PRIO_MAX: c_int = 20; + +pub const IPPROTO_ICMP: c_int = 1; +pub const IPPROTO_ICMPV6: c_int = 58; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_UDP: c_int = 17; +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_IPV6: c_int = 41; + +pub const INADDR_LOOPBACK: in_addr_t = 2130706433; +pub const INADDR_ANY: in_addr_t = 0; +pub const INADDR_BROADCAST: in_addr_t = 4294967295; +pub const INADDR_NONE: in_addr_t = 4294967295; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; + +// Linux-specific fcntls +pub const F_SETLEASE: c_int = 1024; +pub const F_GETLEASE: c_int = 1025; +pub const F_NOTIFY: c_int = 1026; +pub const F_CANCELLK: c_int = 1029; +pub const F_DUPFD_CLOEXEC: c_int = 1030; +pub const F_SETPIPE_SZ: c_int = 1031; +pub const F_GETPIPE_SZ: c_int = 1032; +pub const F_ADD_SEALS: c_int = 1033; +pub const F_GET_SEALS: c_int = 1034; + +pub const F_SEAL_SEAL: c_int = 0x0001; +pub const F_SEAL_SHRINK: c_int = 0x0002; +pub const F_SEAL_GROW: c_int = 0x0004; +pub const F_SEAL_WRITE: c_int = 0x0008; + +// FIXME(#235): Include file sealing fcntls once we have a way to verify them. + +pub const SIGTRAP: c_int = 5; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC: crate::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 3; +pub const CLOCK_MONOTONIC_RAW: crate::clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: crate::clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: crate::clockid_t = 6; +pub const CLOCK_BOOTTIME: crate::clockid_t = 7; +pub const CLOCK_REALTIME_ALARM: crate::clockid_t = 8; +pub const CLOCK_BOOTTIME_ALARM: crate::clockid_t = 9; +pub const CLOCK_SGI_CYCLE: crate::clockid_t = 10; +pub const CLOCK_TAI: crate::clockid_t = 11; +pub const TIMER_ABSTIME: c_int = 1; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_LOCKS: c_int = 10; +pub const RLIMIT_SIGPENDING: c_int = 11; +pub const RLIMIT_MSGQUEUE: c_int = 12; +pub const RLIMIT_NICE: c_int = 13; +pub const RLIMIT_RTPRIO: c_int = 14; + +pub const RUSAGE_SELF: c_int = 0; + +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; + +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const LC_CTYPE: c_int = 0; +pub const LC_NUMERIC: c_int = 1; +pub const LC_TIME: c_int = 2; +pub const LC_COLLATE: c_int = 3; +pub const LC_MONETARY: c_int = 4; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = 6; +pub const LC_CTYPE_MASK: c_int = 1 << LC_CTYPE; +pub const LC_NUMERIC_MASK: c_int = 1 << LC_NUMERIC; +pub const LC_TIME_MASK: c_int = 1 << LC_TIME; +pub const LC_COLLATE_MASK: c_int = 1 << LC_COLLATE; +pub const LC_MONETARY_MASK: c_int = 1 << LC_MONETARY; +pub const LC_MESSAGES_MASK: c_int = 1 << LC_MESSAGES; +// LC_ALL_MASK defined per platform + +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +// MS_ flags for msync(2) +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; +pub const MS_SYNC: c_int = 0x0004; + +// MS_ flags for mount(2) +pub const MS_RDONLY: c_ulong = 0x01; +pub const MS_NOSUID: c_ulong = 0x02; +pub const MS_NODEV: c_ulong = 0x04; +pub const MS_NOEXEC: c_ulong = 0x08; +pub const MS_SYNCHRONOUS: c_ulong = 0x10; +pub const MS_REMOUNT: c_ulong = 0x20; +pub const MS_MANDLOCK: c_ulong = 0x40; +pub const MS_DIRSYNC: c_ulong = 0x80; +pub const MS_NOATIME: c_ulong = 0x0400; +pub const MS_NODIRATIME: c_ulong = 0x0800; +pub const MS_BIND: c_ulong = 0x1000; +pub const MS_MOVE: c_ulong = 0x2000; +pub const MS_REC: c_ulong = 0x4000; +pub const MS_SILENT: c_ulong = 0x8000; +pub const MS_POSIXACL: c_ulong = 0x010000; +pub const MS_UNBINDABLE: c_ulong = 0x020000; +pub const MS_PRIVATE: c_ulong = 0x040000; +pub const MS_SLAVE: c_ulong = 0x080000; +pub const MS_SHARED: c_ulong = 0x100000; +pub const MS_RELATIME: c_ulong = 0x200000; +pub const MS_KERNMOUNT: c_ulong = 0x400000; +pub const MS_I_VERSION: c_ulong = 0x800000; +pub const MS_STRICTATIME: c_ulong = 0x1000000; +pub const MS_ACTIVE: c_ulong = 0x40000000; +pub const MS_NOUSER: c_ulong = 0x80000000; +pub const MS_MGC_VAL: c_ulong = 0xc0ed0000; +pub const MS_MGC_MSK: c_ulong = 0xffff0000; +pub const MS_RMT_MASK: c_ulong = 0x800051; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const SCM_RIGHTS: c_int = 0x01; +pub const SCM_CREDENTIALS: c_int = 0x02; + +pub const PROT_GROWSDOWN: c_int = 0x1000000; +pub const PROT_GROWSUP: c_int = 0x2000000; + +pub const MAP_TYPE: c_int = 0x000f; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 8; +pub const MADV_REMOVE: c_int = 9; +pub const MADV_DONTFORK: c_int = 10; +pub const MADV_DOFORK: c_int = 11; +pub const MADV_MERGEABLE: c_int = 12; +pub const MADV_UNMERGEABLE: c_int = 13; +pub const MADV_HUGEPAGE: c_int = 14; +pub const MADV_NOHUGEPAGE: c_int = 15; +pub const MADV_DONTDUMP: c_int = 16; +pub const MADV_DODUMP: c_int = 17; +pub const MADV_HWPOISON: c_int = 100; +pub const MADV_SOFT_OFFLINE: c_int = 101; + +pub const IFF_UP: c_int = 0x1; +pub const IFF_BROADCAST: c_int = 0x2; +pub const IFF_DEBUG: c_int = 0x4; +pub const IFF_LOOPBACK: c_int = 0x8; +pub const IFF_POINTOPOINT: c_int = 0x10; +pub const IFF_NOTRAILERS: c_int = 0x20; +pub const IFF_RUNNING: c_int = 0x40; +pub const IFF_NOARP: c_int = 0x80; +pub const IFF_PROMISC: c_int = 0x100; +pub const IFF_ALLMULTI: c_int = 0x200; +pub const IFF_MASTER: c_int = 0x400; +pub const IFF_SLAVE: c_int = 0x800; +pub const IFF_MULTICAST: c_int = 0x1000; +pub const IFF_PORTSEL: c_int = 0x2000; +pub const IFF_AUTOMEDIA: c_int = 0x4000; +pub const IFF_DYNAMIC: c_int = 0x8000; +pub const IFF_TUN: c_int = 0x0001; +pub const IFF_TAP: c_int = 0x0002; +pub const IFF_NO_PI: c_int = 0x1000; + +pub const SOL_IP: c_int = 0; +pub const SOL_TCP: c_int = 6; +pub const SOL_UDP: c_int = 17; +pub const SOL_IPV6: c_int = 41; +pub const SOL_ICMPV6: c_int = 58; +pub const SOL_RAW: c_int = 255; +pub const SOL_DECNET: c_int = 261; +pub const SOL_X25: c_int = 262; +pub const SOL_PACKET: c_int = 263; +pub const SOL_ATM: c_int = 264; +pub const SOL_AAL: c_int = 265; +pub const SOL_IRDA: c_int = 266; +pub const SOL_NETBEUI: c_int = 267; +pub const SOL_LLC: c_int = 268; +pub const SOL_DCCP: c_int = 269; +pub const SOL_NETLINK: c_int = 270; +pub const SOL_TIPC: c_int = 271; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = 1; +pub const AF_LOCAL: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_AX25: c_int = 3; +pub const AF_IPX: c_int = 4; +pub const AF_APPLETALK: c_int = 5; +pub const AF_NETROM: c_int = 6; +pub const AF_BRIDGE: c_int = 7; +pub const AF_ATMPVC: c_int = 8; +pub const AF_X25: c_int = 9; +pub const AF_INET6: c_int = 10; +pub const AF_ROSE: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_NETBEUI: c_int = 13; +pub const AF_SECURITY: c_int = 14; +pub const AF_KEY: c_int = 15; +pub const AF_NETLINK: c_int = 16; +pub const AF_ROUTE: c_int = AF_NETLINK; +pub const AF_PACKET: c_int = 17; +pub const AF_ASH: c_int = 18; +pub const AF_ECONET: c_int = 19; +pub const AF_ATMSVC: c_int = 20; +pub const AF_RDS: c_int = 21; +pub const AF_SNA: c_int = 22; +pub const AF_IRDA: c_int = 23; +pub const AF_PPPOX: c_int = 24; +pub const AF_WANPIPE: c_int = 25; +pub const AF_LLC: c_int = 26; +pub const AF_CAN: c_int = 29; +pub const AF_TIPC: c_int = 30; +pub const AF_BLUETOOTH: c_int = 31; +pub const AF_IUCV: c_int = 32; +pub const AF_RXRPC: c_int = 33; +pub const AF_ISDN: c_int = 34; +pub const AF_PHONET: c_int = 35; +pub const AF_IEEE802154: c_int = 36; +pub const AF_CAIF: c_int = 37; +pub const AF_ALG: c_int = 38; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_AX25: c_int = AF_AX25; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_NETROM: c_int = AF_NETROM; +pub const PF_BRIDGE: c_int = AF_BRIDGE; +pub const PF_ATMPVC: c_int = AF_ATMPVC; +pub const PF_X25: c_int = AF_X25; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_ROSE: c_int = AF_ROSE; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_NETBEUI: c_int = AF_NETBEUI; +pub const PF_SECURITY: c_int = AF_SECURITY; +pub const PF_KEY: c_int = AF_KEY; +pub const PF_NETLINK: c_int = AF_NETLINK; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_PACKET: c_int = AF_PACKET; +pub const PF_ASH: c_int = AF_ASH; +pub const PF_ECONET: c_int = AF_ECONET; +pub const PF_ATMSVC: c_int = AF_ATMSVC; +pub const PF_RDS: c_int = AF_RDS; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_IRDA: c_int = AF_IRDA; +pub const PF_PPPOX: c_int = AF_PPPOX; +pub const PF_WANPIPE: c_int = AF_WANPIPE; +pub const PF_LLC: c_int = AF_LLC; +pub const PF_CAN: c_int = AF_CAN; +pub const PF_TIPC: c_int = AF_TIPC; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_IUCV: c_int = AF_IUCV; +pub const PF_RXRPC: c_int = AF_RXRPC; +pub const PF_ISDN: c_int = AF_ISDN; +pub const PF_PHONET: c_int = AF_PHONET; +pub const PF_IEEE802154: c_int = AF_IEEE802154; +pub const PF_CAIF: c_int = AF_CAIF; +pub const PF_ALG: c_int = AF_ALG; + +pub const SOMAXCONN: c_int = 128; + +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTROUTE: c_int = 4; +pub const MSG_CTRUNC: c_int = 8; +pub const MSG_TRUNC: c_int = 0x20; +pub const MSG_DONTWAIT: c_int = 0x40; +pub const MSG_EOR: c_int = 0x80; +pub const MSG_WAITALL: c_int = 0x100; +pub const MSG_FIN: c_int = 0x200; +pub const MSG_SYN: c_int = 0x400; +pub const MSG_CONFIRM: c_int = 0x800; +pub const MSG_RST: c_int = 0x1000; +pub const MSG_ERRQUEUE: c_int = 0x2000; +pub const MSG_NOSIGNAL: c_int = 0x4000; +pub const MSG_MORE: c_int = 0x8000; +pub const MSG_WAITFORONE: c_int = 0x10000; +pub const MSG_FASTOPEN: c_int = 0x20000000; +pub const MSG_CMSG_CLOEXEC: c_int = 0x40000000; + +pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; + +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; + +pub const IP_TOS: c_int = 1; +pub const IP_TTL: c_int = 2; +pub const IP_HDRINCL: c_int = 3; +pub const IP_RECVTOS: c_int = 13; +pub const IP_FREEBIND: c_int = 15; +pub const IP_TRANSPARENT: c_int = 19; +pub const IP_MULTICAST_IF: c_int = 32; +pub const IP_MULTICAST_TTL: c_int = 33; +pub const IP_MULTICAST_LOOP: c_int = 34; +pub const IP_ADD_MEMBERSHIP: c_int = 35; +pub const IP_DROP_MEMBERSHIP: c_int = 36; + +pub const IPV6_UNICAST_HOPS: c_int = 16; +pub const IPV6_MULTICAST_IF: c_int = 17; +pub const IPV6_MULTICAST_HOPS: c_int = 18; +pub const IPV6_MULTICAST_LOOP: c_int = 19; +pub const IPV6_ADD_MEMBERSHIP: c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: c_int = 21; +pub const IPV6_V6ONLY: c_int = 26; +pub const IPV6_RECVPKTINFO: c_int = 49; +pub const IPV6_RECVTCLASS: c_int = 66; +pub const IPV6_TCLASS: c_int = 67; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; +pub const TCP_CORK: c_int = 3; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; +pub const TCP_SYNCNT: c_int = 7; +pub const TCP_LINGER2: c_int = 8; +pub const TCP_DEFER_ACCEPT: c_int = 9; +pub const TCP_WINDOW_CLAMP: c_int = 10; +pub const TCP_INFO: c_int = 11; +pub const TCP_QUICKACK: c_int = 12; +pub const TCP_CONGESTION: c_int = 13; + +pub const SO_DEBUG: c_int = 1; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 2; + +pub const PATH_MAX: c_int = 4096; + +pub const FD_SETSIZE: usize = 1024; + +pub const EPOLLIN: c_int = 0x1; +pub const EPOLLPRI: c_int = 0x2; +pub const EPOLLOUT: c_int = 0x4; +pub const EPOLLRDNORM: c_int = 0x40; +pub const EPOLLRDBAND: c_int = 0x80; +pub const EPOLLWRNORM: c_int = 0x100; +pub const EPOLLWRBAND: c_int = 0x200; +pub const EPOLLMSG: c_int = 0x400; +pub const EPOLLERR: c_int = 0x8; +pub const EPOLLHUP: c_int = 0x10; +pub const EPOLLET: c_int = 0x80000000; + +pub const EPOLL_CTL_ADD: c_int = 1; +pub const EPOLL_CTL_MOD: c_int = 3; +pub const EPOLL_CTL_DEL: c_int = 2; + +pub const MNT_DETACH: c_int = 0x2; +pub const MNT_EXPIRE: c_int = 0x4; + +pub const Q_GETFMT: c_int = 0x800004; +pub const Q_GETINFO: c_int = 0x800005; +pub const Q_SETINFO: c_int = 0x800006; +pub const QIF_BLIMITS: u32 = 1; +pub const QIF_SPACE: u32 = 2; +pub const QIF_ILIMITS: u32 = 4; +pub const QIF_INODES: u32 = 8; +pub const QIF_BTIME: u32 = 16; +pub const QIF_ITIME: u32 = 32; +pub const QIF_LIMITS: u32 = 5; +pub const QIF_USAGE: u32 = 10; +pub const QIF_TIMES: u32 = 48; +pub const QIF_ALL: u32 = 63; + +pub const MNT_FORCE: c_int = 0x1; + +pub const Q_SYNC: c_int = 0x800001; +pub const Q_QUOTAON: c_int = 0x800002; +pub const Q_QUOTAOFF: c_int = 0x800003; +pub const Q_GETQUOTA: c_int = 0x800007; +pub const Q_SETQUOTA: c_int = 0x800008; + +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const NL0: c_int = 0x00000000; +pub const NL1: c_int = 0x00000100; +pub const TAB0: c_int = 0x00000000; +pub const CR0: c_int = 0x00000000; +pub const FF0: c_int = 0x00000000; +pub const BS0: c_int = 0x00000000; +pub const VT0: c_int = 0x00000000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNPAR: crate::tcflag_t = 0x00000004; +pub const PARMRK: crate::tcflag_t = 0x00000008; +pub const INPCK: crate::tcflag_t = 0x00000010; +pub const ISTRIP: crate::tcflag_t = 0x00000020; +pub const INLCR: crate::tcflag_t = 0x00000040; +pub const IGNCR: crate::tcflag_t = 0x00000080; +pub const ICRNL: crate::tcflag_t = 0x00000100; +pub const IXANY: crate::tcflag_t = 0x00000800; +pub const IMAXBEL: crate::tcflag_t = 0x00002000; +pub const OPOST: crate::tcflag_t = 0x1; +pub const CS5: crate::tcflag_t = 0x00000000; +pub const CRTSCTS: crate::tcflag_t = 0x80000000; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const OCRNL: crate::tcflag_t = 0o000010; +pub const ONOCR: crate::tcflag_t = 0o000020; +pub const ONLRET: crate::tcflag_t = 0o000040; +pub const OFILL: crate::tcflag_t = 0o000100; +pub const OFDEL: crate::tcflag_t = 0o000200; + +pub const CLONE_VM: c_int = 0x100; +pub const CLONE_FS: c_int = 0x200; +pub const CLONE_FILES: c_int = 0x400; +pub const CLONE_SIGHAND: c_int = 0x800; +pub const CLONE_PTRACE: c_int = 0x2000; +pub const CLONE_VFORK: c_int = 0x4000; +pub const CLONE_PARENT: c_int = 0x8000; +pub const CLONE_THREAD: c_int = 0x10000; +pub const CLONE_NEWNS: c_int = 0x20000; +pub const CLONE_SYSVSEM: c_int = 0x40000; +pub const CLONE_SETTLS: c_int = 0x80000; +pub const CLONE_PARENT_SETTID: c_int = 0x100000; +pub const CLONE_CHILD_CLEARTID: c_int = 0x200000; +pub const CLONE_DETACHED: c_int = 0x400000; +pub const CLONE_UNTRACED: c_int = 0x800000; +pub const CLONE_CHILD_SETTID: c_int = 0x01000000; +pub const CLONE_NEWUTS: c_int = 0x04000000; +pub const CLONE_NEWIPC: c_int = 0x08000000; +pub const CLONE_NEWUSER: c_int = 0x10000000; +pub const CLONE_NEWPID: c_int = 0x20000000; +pub const CLONE_NEWNET: c_int = 0x40000000; +pub const CLONE_IO: c_int = 0x80000000; +pub const CLONE_NEWCGROUP: c_int = 0x02000000; + +pub const WNOHANG: c_int = 0x00000001; +pub const WUNTRACED: c_int = 0x00000002; +pub const WSTOPPED: c_int = WUNTRACED; +pub const WEXITED: c_int = 0x00000004; +pub const WCONTINUED: c_int = 0x00000008; +pub const WNOWAIT: c_int = 0x01000000; + +// Options set using PTRACE_SETOPTIONS. +pub const PTRACE_O_TRACESYSGOOD: c_int = 0x00000001; +pub const PTRACE_O_TRACEFORK: c_int = 0x00000002; +pub const PTRACE_O_TRACEVFORK: c_int = 0x00000004; +pub const PTRACE_O_TRACECLONE: c_int = 0x00000008; +pub const PTRACE_O_TRACEEXEC: c_int = 0x00000010; +pub const PTRACE_O_TRACEVFORKDONE: c_int = 0x00000020; +pub const PTRACE_O_TRACEEXIT: c_int = 0x00000040; +pub const PTRACE_O_TRACESECCOMP: c_int = 0x00000080; +pub const PTRACE_O_EXITKILL: c_int = 0x00100000; +pub const PTRACE_O_SUSPEND_SECCOMP: c_int = 0x00200000; +pub const PTRACE_O_MASK: c_int = 0x003000ff; + +// Wait extended result codes for the above trace options. +pub const PTRACE_EVENT_FORK: c_int = 1; +pub const PTRACE_EVENT_VFORK: c_int = 2; +pub const PTRACE_EVENT_CLONE: c_int = 3; +pub const PTRACE_EVENT_EXEC: c_int = 4; +pub const PTRACE_EVENT_VFORK_DONE: c_int = 5; +pub const PTRACE_EVENT_EXIT: c_int = 6; +pub const PTRACE_EVENT_SECCOMP: c_int = 7; +// PTRACE_EVENT_STOP was added to glibc in 2.26 +// pub const PTRACE_EVENT_STOP: c_int = 128; + +pub const __WNOTHREAD: c_int = 0x20000000; +pub const __WALL: c_int = 0x40000000; +pub const __WCLONE: c_int = 0x80000000; + +pub const SPLICE_F_MOVE: c_uint = 0x01; +pub const SPLICE_F_NONBLOCK: c_uint = 0x02; +pub const SPLICE_F_MORE: c_uint = 0x04; +pub const SPLICE_F_GIFT: c_uint = 0x08; + +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_LAZY: c_int = 1; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; + +pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x100; +pub const AT_REMOVEDIR: c_int = 0x200; +pub const AT_EACCESS: c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: c_int = 0x400; +pub const AT_NO_AUTOMOUNT: c_int = 0x800; +pub const AT_EMPTY_PATH: c_int = 0x1000; + +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_FTP: c_int = 11 << 3; +pub const LOG_PERROR: c_int = 0x20; + +pub const PIPE_BUF: usize = 4096; + +pub const SI_LOAD_SHIFT: c_uint = 16; + +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const SIGEV_SIGNAL: c_int = 0; +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; +pub const POLLRDNORM: c_short = 0x040; +pub const POLLRDBAND: c_short = 0x080; + +pub const ABDAY_1: crate::nl_item = 0x20000; +pub const ABDAY_2: crate::nl_item = 0x20001; +pub const ABDAY_3: crate::nl_item = 0x20002; +pub const ABDAY_4: crate::nl_item = 0x20003; +pub const ABDAY_5: crate::nl_item = 0x20004; +pub const ABDAY_6: crate::nl_item = 0x20005; +pub const ABDAY_7: crate::nl_item = 0x20006; + +pub const DAY_1: crate::nl_item = 0x20007; +pub const DAY_2: crate::nl_item = 0x20008; +pub const DAY_3: crate::nl_item = 0x20009; +pub const DAY_4: crate::nl_item = 0x2000A; +pub const DAY_5: crate::nl_item = 0x2000B; +pub const DAY_6: crate::nl_item = 0x2000C; +pub const DAY_7: crate::nl_item = 0x2000D; + +pub const ABMON_1: crate::nl_item = 0x2000E; +pub const ABMON_2: crate::nl_item = 0x2000F; +pub const ABMON_3: crate::nl_item = 0x20010; +pub const ABMON_4: crate::nl_item = 0x20011; +pub const ABMON_5: crate::nl_item = 0x20012; +pub const ABMON_6: crate::nl_item = 0x20013; +pub const ABMON_7: crate::nl_item = 0x20014; +pub const ABMON_8: crate::nl_item = 0x20015; +pub const ABMON_9: crate::nl_item = 0x20016; +pub const ABMON_10: crate::nl_item = 0x20017; +pub const ABMON_11: crate::nl_item = 0x20018; +pub const ABMON_12: crate::nl_item = 0x20019; + +pub const MON_1: crate::nl_item = 0x2001A; +pub const MON_2: crate::nl_item = 0x2001B; +pub const MON_3: crate::nl_item = 0x2001C; +pub const MON_4: crate::nl_item = 0x2001D; +pub const MON_5: crate::nl_item = 0x2001E; +pub const MON_6: crate::nl_item = 0x2001F; +pub const MON_7: crate::nl_item = 0x20020; +pub const MON_8: crate::nl_item = 0x20021; +pub const MON_9: crate::nl_item = 0x20022; +pub const MON_10: crate::nl_item = 0x20023; +pub const MON_11: crate::nl_item = 0x20024; +pub const MON_12: crate::nl_item = 0x20025; + +pub const AM_STR: crate::nl_item = 0x20026; +pub const PM_STR: crate::nl_item = 0x20027; + +pub const D_T_FMT: crate::nl_item = 0x20028; +pub const D_FMT: crate::nl_item = 0x20029; +pub const T_FMT: crate::nl_item = 0x2002A; +pub const T_FMT_AMPM: crate::nl_item = 0x2002B; + +pub const ERA: crate::nl_item = 0x2002C; +pub const ERA_D_FMT: crate::nl_item = 0x2002E; +pub const ALT_DIGITS: crate::nl_item = 0x2002F; +pub const ERA_D_T_FMT: crate::nl_item = 0x20030; +pub const ERA_T_FMT: crate::nl_item = 0x20031; + +pub const CODESET: crate::nl_item = 14; + +pub const CRNCYSTR: crate::nl_item = 0x4000F; + +pub const RUSAGE_THREAD: c_int = 1; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const RADIXCHAR: crate::nl_item = 0x10000; +pub const THOUSEP: crate::nl_item = 0x10001; + +pub const YESEXPR: crate::nl_item = 0x50000; +pub const NOEXPR: crate::nl_item = 0x50001; +pub const YESSTR: crate::nl_item = 0x50002; +pub const NOSTR: crate::nl_item = 0x50003; + +pub const FILENAME_MAX: c_uint = 4096; +pub const L_tmpnam: c_uint = 20; +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; + +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = 60; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_NZERO: c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_STREAMS: c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; + +pub const RLIM_SAVED_MAX: crate::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: crate::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: c_int = 1 << 0; +pub const GLOB_MARK: c_int = 1 << 1; +pub const GLOB_NOSORT: c_int = 1 << 2; +pub const GLOB_DOOFFS: c_int = 1 << 3; +pub const GLOB_NOCHECK: c_int = 1 << 4; +pub const GLOB_APPEND: c_int = 1 << 5; +pub const GLOB_NOESCAPE: c_int = 1 << 6; + +pub const GLOB_NOSPACE: c_int = 1; +pub const GLOB_ABORTED: c_int = 2; +pub const GLOB_NOMATCH: c_int = 3; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; + +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; + +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +pub const IFF_LOWER_UP: c_int = 0x10000; +pub const IFF_DORMANT: c_int = 0x20000; +pub const IFF_ECHO: c_int = 0x40000; + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; +pub const ST_NODEV: c_ulong = 4; +pub const ST_NOEXEC: c_ulong = 8; +pub const ST_SYNCHRONOUS: c_ulong = 16; +pub const ST_MANDLOCK: c_ulong = 64; +pub const ST_WRITE: c_ulong = 128; +pub const ST_APPEND: c_ulong = 256; +pub const ST_IMMUTABLE: c_ulong = 512; +pub const ST_NOATIME: c_ulong = 1024; +pub const ST_NODIRATIME: c_ulong = 2048; + +pub const RTLD_NEXT: *mut c_void = -1i64 as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_NOW: c_int = 0x2; + +pub const TCP_MD5SIG: c_int = 14; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], +}; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const RENAME_NOREPLACE: c_int = 1; +pub const RENAME_EXCHANGE: c_int = 2; +pub const RENAME_WHITEOUT: c_int = 4; + +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_BATCH: c_int = 3; +pub const SCHED_IDLE: c_int = 5; + +// netinet/in.h +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// pup +pub const IPPROTO_PUP: c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +pub const IPPROTO_MTP: c_int = 92; +pub const IPPROTO_BEETPH: c_int = 94; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_COMP: c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: c_int = 132; +pub const IPPROTO_MH: c_int = 135; +pub const IPPROTO_UDPLITE: c_int = 136; +pub const IPPROTO_MPLS: c_int = 137; +/// raw IP packet +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MAX: c_int = 256; + +pub const AF_IB: c_int = 27; +pub const AF_MPLS: c_int = 28; +pub const AF_NFC: c_int = 39; +pub const AF_VSOCK: c_int = 40; +pub const PF_IB: c_int = AF_IB; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_NFC: c_int = AF_NFC; +pub const PF_VSOCK: c_int = AF_VSOCK; + +// System V IPC +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_CREAT: c_int = 0o1000; +pub const IPC_EXCL: c_int = 0o2000; +pub const IPC_NOWAIT: c_int = 0o4000; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; +pub const IPC_INFO: c_int = 3; +pub const MSG_STAT: c_int = 11; +pub const MSG_INFO: c_int = 12; + +pub const MSG_NOERROR: c_int = 0o10000; +pub const MSG_EXCEPT: c_int = 0o20000; +pub const MSG_COPY: c_int = 0o40000; + +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; + +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_REMAP: c_int = 0o40000; +pub const SHM_EXEC: c_int = 0o100000; + +pub const SHM_LOCK: c_int = 11; +pub const SHM_UNLOCK: c_int = 12; + +pub const SHM_HUGETLB: c_int = 0o4000; +pub const SHM_NORESERVE: c_int = 0o10000; + +pub const EPOLLRDHUP: c_int = 0x2000; +pub const EPOLLEXCLUSIVE: c_int = 0x10000000; +pub const EPOLLONESHOT: c_int = 0x40000000; + +pub const QFMT_VFS_OLD: c_int = 1; +pub const QFMT_VFS_V0: c_int = 2; +pub const QFMT_VFS_V1: c_int = 4; + +pub const EFD_SEMAPHORE: c_int = 0x1; + +pub const LOG_NFACILITIES: c_int = 24; + +pub const SEM_FAILED: *mut crate::sem_t = ptr::null_mut(); + +pub const RB_AUTOBOOT: c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: c_int = 0x4321fedcu32 as i32; +pub const RB_SW_SUSPEND: c_int = 0xd000fce2u32 as i32; +pub const RB_KEXEC: c_int = 0x45584543u32 as i32; + +pub const AI_PASSIVE: c_int = 0x0001; +pub const AI_CANONNAME: c_int = 0x0002; +pub const AI_NUMERICHOST: c_int = 0x0004; +pub const AI_V4MAPPED: c_int = 0x0008; +pub const AI_ALL: c_int = 0x0010; +pub const AI_ADDRCONFIG: c_int = 0x0020; + +pub const AI_NUMERICSERV: c_int = 0x0400; + +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_OVERFLOW: c_int = -12; + +pub const NI_NUMERICHOST: c_int = 1; +pub const NI_NUMERICSERV: c_int = 2; +pub const NI_NOFQDN: c_int = 4; +pub const NI_NAMEREQD: c_int = 8; +pub const NI_DGRAM: c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: c_uint = 4; + +pub const EAI_SYSTEM: c_int = -11; + +pub const AIO_CANCELED: c_int = 0; +pub const AIO_NOTCANCELED: c_int = 1; +pub const AIO_ALLDONE: c_int = 2; +pub const LIO_READ: c_int = 0; +pub const LIO_WRITE: c_int = 1; +pub const LIO_NOP: c_int = 2; +pub const LIO_WAIT: c_int = 0; +pub const LIO_NOWAIT: c_int = 1; + +pub const MREMAP_MAYMOVE: c_int = 1; +pub const MREMAP_FIXED: c_int = 2; + +pub const PR_SET_PDEATHSIG: c_int = 1; +pub const PR_GET_PDEATHSIG: c_int = 2; + +pub const PR_GET_DUMPABLE: c_int = 3; +pub const PR_SET_DUMPABLE: c_int = 4; + +pub const PR_GET_UNALIGN: c_int = 5; +pub const PR_SET_UNALIGN: c_int = 6; +pub const PR_UNALIGN_NOPRINT: c_int = 1; +pub const PR_UNALIGN_SIGBUS: c_int = 2; + +pub const PR_GET_KEEPCAPS: c_int = 7; +pub const PR_SET_KEEPCAPS: c_int = 8; + +pub const PR_GET_FPEMU: c_int = 9; +pub const PR_SET_FPEMU: c_int = 10; +pub const PR_FPEMU_NOPRINT: c_int = 1; +pub const PR_FPEMU_SIGFPE: c_int = 2; + +pub const PR_GET_FPEXC: c_int = 11; +pub const PR_SET_FPEXC: c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: c_int = 0x80; +pub const PR_FP_EXC_DIV: c_int = 0x010000; +pub const PR_FP_EXC_OVF: c_int = 0x020000; +pub const PR_FP_EXC_UND: c_int = 0x040000; +pub const PR_FP_EXC_RES: c_int = 0x080000; +pub const PR_FP_EXC_INV: c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: c_int = 0; +pub const PR_FP_EXC_NONRECOV: c_int = 1; +pub const PR_FP_EXC_ASYNC: c_int = 2; +pub const PR_FP_EXC_PRECISE: c_int = 3; + +pub const PR_GET_TIMING: c_int = 13; +pub const PR_SET_TIMING: c_int = 14; +pub const PR_TIMING_STATISTICAL: c_int = 0; +pub const PR_TIMING_TIMESTAMP: c_int = 1; + +pub const PR_SET_NAME: c_int = 15; +pub const PR_GET_NAME: c_int = 16; + +pub const PR_GET_ENDIAN: c_int = 19; +pub const PR_SET_ENDIAN: c_int = 20; +pub const PR_ENDIAN_BIG: c_int = 0; +pub const PR_ENDIAN_LITTLE: c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: c_int = 2; + +pub const PR_GET_SECCOMP: c_int = 21; +pub const PR_SET_SECCOMP: c_int = 22; + +pub const PR_CAPBSET_READ: c_int = 23; +pub const PR_CAPBSET_DROP: c_int = 24; + +pub const PR_GET_TSC: c_int = 25; +pub const PR_SET_TSC: c_int = 26; +pub const PR_TSC_ENABLE: c_int = 1; +pub const PR_TSC_SIGSEGV: c_int = 2; + +pub const PR_GET_SECUREBITS: c_int = 27; +pub const PR_SET_SECUREBITS: c_int = 28; + +pub const PR_SET_TIMERSLACK: c_int = 29; +pub const PR_GET_TIMERSLACK: c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; + +pub const PR_MCE_KILL: c_int = 33; +pub const PR_MCE_KILL_CLEAR: c_int = 0; +pub const PR_MCE_KILL_SET: c_int = 1; + +pub const PR_MCE_KILL_LATE: c_int = 0; +pub const PR_MCE_KILL_EARLY: c_int = 1; +pub const PR_MCE_KILL_DEFAULT: c_int = 2; + +pub const PR_MCE_KILL_GET: c_int = 34; + +pub const PR_SET_MM: c_int = 35; +pub const PR_SET_MM_START_CODE: c_int = 1; +pub const PR_SET_MM_END_CODE: c_int = 2; +pub const PR_SET_MM_START_DATA: c_int = 3; +pub const PR_SET_MM_END_DATA: c_int = 4; +pub const PR_SET_MM_START_STACK: c_int = 5; +pub const PR_SET_MM_START_BRK: c_int = 6; +pub const PR_SET_MM_BRK: c_int = 7; +pub const PR_SET_MM_ARG_START: c_int = 8; +pub const PR_SET_MM_ARG_END: c_int = 9; +pub const PR_SET_MM_ENV_START: c_int = 10; +pub const PR_SET_MM_ENV_END: c_int = 11; +pub const PR_SET_MM_AUXV: c_int = 12; +pub const PR_SET_MM_EXE_FILE: c_int = 13; +pub const PR_SET_MM_MAP: c_int = 14; +pub const PR_SET_MM_MAP_SIZE: c_int = 15; + +pub const PR_SET_PTRACER: c_int = 0x59616d61; +pub const PR_SET_PTRACER_ANY: c_ulong = 0xffffffffffffffff; + +pub const PR_SET_CHILD_SUBREAPER: c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: c_int = 39; + +pub const PR_GET_TID_ADDRESS: c_int = 40; + +pub const PR_SET_THP_DISABLE: c_int = 41; +pub const PR_GET_THP_DISABLE: c_int = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT: c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: c_int = 44; + +pub const PR_SET_FP_MODE: c_int = 45; +pub const PR_GET_FP_MODE: c_int = 46; +pub const PR_FP_MODE_FR: c_int = 1 << 0; +pub const PR_FP_MODE_FRE: c_int = 1 << 1; + +pub const PR_CAP_AMBIENT: c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: c_int = 4; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +pub const TFD_CLOEXEC: c_int = O_CLOEXEC; +pub const TFD_NONBLOCK: c_int = O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: c_int = 1; + +pub const XATTR_CREATE: c_int = 0x1; +pub const XATTR_REPLACE: c_int = 0x2; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +pub const FALLOC_FL_KEEP_SIZE: c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: c_int = 0x02; +pub const FALLOC_FL_COLLAPSE_RANGE: c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: c_int = 0x40; + +// On Linux, libc doesn't define this constant, libattr does instead. +// We still define it for Linux as it's defined by libc on other platforms, +// and it's mentioned in the man pages for getxattr and setxattr. +pub const ENOATTR: c_int = crate::ENODATA; + +pub const SO_ORIGINAL_DST: c_int = 80; +pub const IUTF8: crate::tcflag_t = 0x00004000; +pub const CMSPAR: crate::tcflag_t = 0o10000000000; + +pub const MFD_CLOEXEC: c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: c_uint = 0x0002; + +// these are used in the p_type field of Elf32_Phdr and Elf64_Phdr, which has +// the type Elf32Word and Elf64Word respectively. Luckily, both of those are u32 +// so we can use that type here to avoid having to cast. +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_NUM: u32 = 8; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_STACK: u32 = 0x6474e551; +pub const PT_GNU_RELRO: u32 = 0x6474e552; + +// Ethernet protocol IDs. +pub const ETH_P_LOOP: c_int = 0x0060; +pub const ETH_P_PUP: c_int = 0x0200; +pub const ETH_P_PUPAT: c_int = 0x0201; +pub const ETH_P_IP: c_int = 0x0800; +pub const ETH_P_X25: c_int = 0x0805; +pub const ETH_P_ARP: c_int = 0x0806; +pub const ETH_P_BPQ: c_int = 0x08FF; +pub const ETH_P_IEEEPUP: c_int = 0x0a00; +pub const ETH_P_IEEEPUPAT: c_int = 0x0a01; +pub const ETH_P_BATMAN: c_int = 0x4305; +pub const ETH_P_DEC: c_int = 0x6000; +pub const ETH_P_DNA_DL: c_int = 0x6001; +pub const ETH_P_DNA_RC: c_int = 0x6002; +pub const ETH_P_DNA_RT: c_int = 0x6003; +pub const ETH_P_LAT: c_int = 0x6004; +pub const ETH_P_DIAG: c_int = 0x6005; +pub const ETH_P_CUST: c_int = 0x6006; +pub const ETH_P_SCA: c_int = 0x6007; +pub const ETH_P_TEB: c_int = 0x6558; +pub const ETH_P_RARP: c_int = 0x8035; +pub const ETH_P_ATALK: c_int = 0x809B; +pub const ETH_P_AARP: c_int = 0x80F3; +pub const ETH_P_8021Q: c_int = 0x8100; +pub const ETH_P_IPX: c_int = 0x8137; +pub const ETH_P_IPV6: c_int = 0x86DD; +pub const ETH_P_PAUSE: c_int = 0x8808; +pub const ETH_P_SLOW: c_int = 0x8809; +pub const ETH_P_WCCP: c_int = 0x883E; +pub const ETH_P_MPLS_UC: c_int = 0x8847; +pub const ETH_P_MPLS_MC: c_int = 0x8848; +pub const ETH_P_ATMMPOA: c_int = 0x884c; +pub const ETH_P_PPP_DISC: c_int = 0x8863; +pub const ETH_P_PPP_SES: c_int = 0x8864; +pub const ETH_P_LINK_CTL: c_int = 0x886c; +pub const ETH_P_ATMFATE: c_int = 0x8884; +pub const ETH_P_PAE: c_int = 0x888E; +pub const ETH_P_AOE: c_int = 0x88A2; +pub const ETH_P_8021AD: c_int = 0x88A8; +pub const ETH_P_802_EX1: c_int = 0x88B5; +pub const ETH_P_TIPC: c_int = 0x88CA; +pub const ETH_P_8021AH: c_int = 0x88E7; +pub const ETH_P_MVRP: c_int = 0x88F5; +pub const ETH_P_1588: c_int = 0x88F7; +pub const ETH_P_PRP: c_int = 0x88FB; +pub const ETH_P_FCOE: c_int = 0x8906; +pub const ETH_P_TDLS: c_int = 0x890D; +pub const ETH_P_FIP: c_int = 0x8914; +pub const ETH_P_80221: c_int = 0x8917; +pub const ETH_P_LOOPBACK: c_int = 0x9000; +pub const ETH_P_QINQ1: c_int = 0x9100; +pub const ETH_P_QINQ2: c_int = 0x9200; +pub const ETH_P_QINQ3: c_int = 0x9300; +pub const ETH_P_EDSA: c_int = 0xDADA; +pub const ETH_P_AF_IUCV: c_int = 0xFBFB; + +pub const ETH_P_802_3_MIN: c_int = 0x0600; + +pub const ETH_P_802_3: c_int = 0x0001; +pub const ETH_P_AX25: c_int = 0x0002; +pub const ETH_P_ALL: c_int = 0x0003; +pub const ETH_P_802_2: c_int = 0x0004; +pub const ETH_P_SNAP: c_int = 0x0005; +pub const ETH_P_DDCMP: c_int = 0x0006; +pub const ETH_P_WAN_PPP: c_int = 0x0007; +pub const ETH_P_PPP_MP: c_int = 0x0008; +pub const ETH_P_LOCALTALK: c_int = 0x0009; +pub const ETH_P_CAN: c_int = 0x000C; +pub const ETH_P_CANFD: c_int = 0x000D; +pub const ETH_P_PPPTALK: c_int = 0x0010; +pub const ETH_P_TR_802_2: c_int = 0x0011; +pub const ETH_P_MOBITEX: c_int = 0x0015; +pub const ETH_P_CONTROL: c_int = 0x0016; +pub const ETH_P_IRDA: c_int = 0x0017; +pub const ETH_P_ECONET: c_int = 0x0018; +pub const ETH_P_HDLC: c_int = 0x0019; +pub const ETH_P_ARCNET: c_int = 0x001A; +pub const ETH_P_DSA: c_int = 0x001B; +pub const ETH_P_TRAILER: c_int = 0x001C; +pub const ETH_P_PHONET: c_int = 0x00F5; +pub const ETH_P_IEEE802154: c_int = 0x00F6; +pub const ETH_P_CAIF: c_int = 0x00F7; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 0x00040000; +pub const O_NOATIME: c_int = 0x00002000; +pub const O_CLOEXEC: c_int = 0x00000100; +pub const O_TMPFILE: c_int = 0x00004000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const BUFSIZ: c_uint = 1024; +pub const TMP_MAX: c_uint = 10000; +pub const FOPEN_MAX: c_uint = 1000; +pub const O_PATH: c_int = 0x00400000; +pub const O_EXEC: c_int = O_PATH; +pub const O_SEARCH: c_int = O_PATH; +pub const O_ACCMODE: c_int = 03 | O_SEARCH; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const NI_MAXHOST: crate::socklen_t = 255; +pub const PTHREAD_STACK_MIN: size_t = 2048; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const RLIM_INFINITY: crate::rlim_t = !0; +pub const RLIMIT_RTTIME: c_int = 15; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIMIT_NLIMITS: c_int = 16; +#[allow(deprecated)] +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = RLIMIT_NLIMITS; + +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +pub const SOCK_DCCP: c_int = 6; +pub const SOCK_PACKET: c_int = 10; + +pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16; +pub const TCP_THIN_DUPACK: c_int = 17; +pub const TCP_USER_TIMEOUT: c_int = 18; +pub const TCP_REPAIR: c_int = 19; +pub const TCP_REPAIR_QUEUE: c_int = 20; +pub const TCP_QUEUE_SEQ: c_int = 21; +pub const TCP_REPAIR_OPTIONS: c_int = 22; +pub const TCP_FASTOPEN: c_int = 23; +pub const TCP_TIMESTAMP: c_int = 24; + +pub const SIGUNUSED: c_int = crate::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const CPU_SETSIZE: c_int = 128; + +pub const PTRACE_TRACEME: c_int = 0; +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_PEEKUSER: c_int = 3; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_POKEUSER: c_int = 6; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; +pub const PTRACE_GETFPXREGS: c_int = 18; +pub const PTRACE_SETFPXREGS: c_int = 19; +pub const PTRACE_SYSCALL: c_int = 24; +pub const PTRACE_SETOPTIONS: c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: c_int = 0x4201; +pub const PTRACE_GETSIGINFO: c_int = 0x4202; +pub const PTRACE_SETSIGINFO: c_int = 0x4203; +pub const PTRACE_GETREGSET: c_int = 0x4204; +pub const PTRACE_SETREGSET: c_int = 0x4205; +pub const PTRACE_SEIZE: c_int = 0x4206; +pub const PTRACE_INTERRUPT: c_int = 0x4207; +pub const PTRACE_LISTEN: c_int = 0x4208; +pub const PTRACE_PEEKSIGINFO: c_int = 0x4209; + +pub const EPOLLWAKEUP: c_int = 0x20000000; + +pub const EFD_NONBLOCK: c_int = crate::O_NONBLOCK; + +pub const SFD_NONBLOCK: c_int = crate::O_NONBLOCK; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const TIOCINQ: c_int = crate::FIONREAD; + +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; + +pub const O_ASYNC: c_int = 0x00000400; + +pub const FIOCLEX: c_int = 0x5451; +pub const FIONBIO: c_int = 0x5421; + +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_NOFILE: c_int = 7; +pub const RLIMIT_AS: c_int = 9; +pub const RLIMIT_NPROC: c_int = 6; +pub const RLIMIT_MEMLOCK: c_int = 8; + +pub const O_APPEND: c_int = 0x00100000; +pub const O_CREAT: c_int = 0x00010000; +pub const O_EXCL: c_int = 0x00020000; +pub const O_NOCTTY: c_int = 0x00000200; +pub const O_NONBLOCK: c_int = 0x00000010; +pub const O_SYNC: c_int = 0x00000040 | O_DSYNC; +pub const O_RSYNC: c_int = O_SYNC; +pub const O_DSYNC: c_int = 0x00000020; + +pub const SOCK_CLOEXEC: c_int = 0o2000000; +pub const SOCK_NONBLOCK: c_int = 0o4000; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_SEQPACKET: c_int = 5; + +pub const SOL_SOCKET: c_int = 1; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 20; +pub const SO_SNDTIMEO: c_int = 21; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_TIMESTAMP: c_int = 29; +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_TIMESTAMPNS: c_int = 35; +pub const SO_MARK: c_int = 36; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_BUSY_POLL: c_int = 46; +pub const SO_COOKIE: c_int = 57; +pub const SO_BINDTOIFINDEX: c_int = 62; +pub const SO_FUCHSIA_MARK: c_int = 10000; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: c_int = 0x040000; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const TCGETS: c_int = 0x5401; +pub const TCSETS: c_int = 0x5402; +pub const TCSETSW: c_int = 0x5403; +pub const TCSETSF: c_int = 0x5404; +pub const TCGETA: c_int = 0x5405; +pub const TCSETA: c_int = 0x5406; +pub const TCSETAW: c_int = 0x5407; +pub const TCSETAF: c_int = 0x5408; +pub const TCSBRK: c_int = 0x5409; +pub const TCXONC: c_int = 0x540A; +pub const TCFLSH: c_int = 0x540B; +pub const TIOCGSOFTCAR: c_int = 0x5419; +pub const TIOCSSOFTCAR: c_int = 0x541A; +pub const TIOCLINUX: c_int = 0x541C; +pub const TIOCGSERIAL: c_int = 0x541E; +pub const TIOCEXCL: c_int = 0x540C; +pub const TIOCNXCL: c_int = 0x540D; +pub const TIOCSCTTY: c_int = 0x540E; +pub const TIOCGPGRP: c_int = 0x540F; +pub const TIOCSPGRP: c_int = 0x5410; +pub const TIOCOUTQ: c_int = 0x5411; +pub const TIOCSTI: c_int = 0x5412; +pub const TIOCGWINSZ: c_int = 0x5413; +pub const TIOCSWINSZ: c_int = 0x5414; +pub const TIOCMGET: c_int = 0x5415; +pub const TIOCMBIS: c_int = 0x5416; +pub const TIOCMBIC: c_int = 0x5417; +pub const TIOCMSET: c_int = 0x5418; +pub const FIONREAD: c_int = 0x541B; +pub const TIOCCONS: c_int = 0x541D; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RI: c_int = TIOCM_RNG; + +pub const O_DIRECTORY: c_int = 0x00080000; +pub const O_DIRECT: c_int = 0x00000800; +pub const O_LARGEFILE: c_int = 0x00001000; +pub const O_NOFOLLOW: c_int = 0x00000080; + +pub const HUGETLB_FLAG_ENCODE_SHIFT: u32 = 26; +pub const MAP_HUGE_SHIFT: u32 = 26; + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +// END_PUB_CONST + +f! { + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + cmsg.offset(1) as *mut c_uchar + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as size_t) < size_of::() { + core::ptr::null_mut::() + } else if __CMSG_NEXT(cmsg).add(size_of::()) >= __MHDR_END(mhdr) { + core::ptr::null_mut::() + } else { + __CMSG_NEXT(cmsg).cast() + } + } + + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as size_t >= size_of::() { + (*mhdr).msg_control.cast() + } else { + core::ptr::null_mut::() + } + } + + pub const fn CMSG_ALIGN(len: size_t) -> size_t { + (len + size_of::() - 1) & !(size_of::() - 1) + } + + pub const fn CMSG_SPACE(len: c_uint) -> c_uint { + (CMSG_ALIGN(len as size_t) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub const fn CMSG_LEN(len: c_uint) -> c_uint { + (CMSG_ALIGN(size_of::()) + len as size_t) as c_uint + } +} + +safe_f! { + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0x7f) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn QCMD(cmd: c_int, type_: c_int) -> c_int { + (cmd << 8) | (type_ & 0x00ff) + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as c_uint + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as c_uint + } +} + +fn __CMSG_LEN(cmsg: *const cmsghdr) -> ssize_t { + ((unsafe { (*cmsg).cmsg_len as size_t } + size_of::() - 1) & !(size_of::() - 1)) + as ssize_t +} + +fn __CMSG_NEXT(cmsg: *const cmsghdr) -> *mut c_uchar { + (unsafe { cmsg.offset(__CMSG_LEN(cmsg)) }) as *mut c_uchar +} + +fn __MHDR_END(mhdr: *const msghdr) -> *mut c_uchar { + unsafe { (*mhdr).msg_control.offset((*mhdr).msg_controllen as isize) }.cast() +} + +// EXTERN_FN + +#[link(name = "c")] +#[link(name = "fdio")] +extern "C" {} + +extern_ty! { + pub enum FILE {} + pub enum fpos_t {} // FIXME(fuchsia): fill this out with a struct +} + +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atof(s: *const c_char) -> c_double; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atol(s: *const c_char) -> c_long; + pub fn atoll(s: *const c_char) -> c_longlong; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtof(s: *const c_char, endp: *mut *mut c_char) -> c_float; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoll(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoull(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulonglong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern "C" fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn getpwnam(name: *const c_char) -> *mut passwd; + pub fn getpwuid(uid: crate::uid_t) -> *mut passwd; + + pub fn fprintf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn snprintf(s: *mut c_char, n: size_t, format: *const c_char, ...) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + pub fn fscanf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn scanf(format: *const c_char, ...) -> c_int; + pub fn sscanf(s: *const c_char, format: *const c_char, ...) -> c_int; + pub fn getchar_unlocked() -> c_int; + pub fn putchar_unlocked(c: c_int) -> c_int; + + pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int; + pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int; + pub fn listen(socket: c_int, backlog: c_int) -> c_int; + pub fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int; + pub fn getpeername(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) + -> c_int; + pub fn getsockname(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) + -> c_int; + pub fn setsockopt( + socket: c_int, + level: c_int, + name: c_int, + value: *const c_void, + option_len: socklen_t, + ) -> c_int; + pub fn socketpair( + domain: c_int, + type_: c_int, + protocol: c_int, + socket_vector: *mut c_int, + ) -> c_int; + pub fn sendto( + socket: c_int, + buf: *const c_void, + len: size_t, + flags: c_int, + addr: *const sockaddr, + addrlen: socklen_t, + ) -> ssize_t; + pub fn shutdown(socket: c_int, how: c_int) -> c_int; + + pub fn chmod(path: *const c_char, mode: mode_t) -> c_int; + pub fn fchmod(fd: c_int, mode: mode_t) -> c_int; + + pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; + + pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; + + pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; + + pub fn pclose(stream: *mut crate::FILE) -> c_int; + pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut crate::FILE; + pub fn fileno(stream: *mut crate::FILE) -> c_int; + + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + pub fn creat(path: *const c_char, mode: mode_t) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; + + pub fn opendir(dirname: *const c_char) -> *mut crate::DIR; + pub fn readdir(dirp: *mut crate::DIR) -> *mut crate::dirent; + pub fn readdir_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent, + result: *mut *mut crate::dirent, + ) -> c_int; + pub fn closedir(dirp: *mut crate::DIR) -> c_int; + pub fn rewinddir(dirp: *mut crate::DIR); + + pub fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int, ...) -> c_int; + pub fn fchmodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, flags: c_int) -> c_int; + pub fn fchown(fd: c_int, owner: crate::uid_t, group: crate::gid_t) -> c_int; + pub fn fchownat( + dirfd: c_int, + pathname: *const c_char, + owner: crate::uid_t, + group: crate::gid_t, + flags: c_int, + ) -> c_int; + pub fn fstatat(dirfd: c_int, pathname: *const c_char, buf: *mut stat, flags: c_int) -> c_int; + pub fn linkat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + pub fn mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn readlinkat( + dirfd: c_int, + pathname: *const c_char, + buf: *mut c_char, + bufsiz: size_t, + ) -> ssize_t; + pub fn renameat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + ) -> c_int; + pub fn symlinkat(target: *const c_char, newdirfd: c_int, linkpath: *const c_char) -> c_int; + pub fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int; + + pub fn access(path: *const c_char, amode: c_int) -> c_int; + pub fn alarm(seconds: c_uint) -> c_uint; + pub fn chdir(dir: *const c_char) -> c_int; + pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; + pub fn lchown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; + pub fn close(fd: c_int) -> c_int; + pub fn dup(fd: c_int) -> c_int; + pub fn dup2(src: c_int, dst: c_int) -> c_int; + + pub fn execl(path: *const c_char, arg0: *const c_char, ...) -> c_int; + pub fn execle(path: *const c_char, arg0: *const c_char, ...) -> c_int; + pub fn execlp(file: *const c_char, arg0: *const c_char, ...) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int; + pub fn execve( + prog: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; + + pub fn fork() -> pid_t; + pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + pub fn getegid() -> gid_t; + pub fn geteuid() -> uid_t; + pub fn getgid() -> gid_t; + pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; + pub fn getlogin() -> *mut c_char; + pub fn getopt(argc: c_int, argv: *const *mut c_char, optstr: *const c_char) -> c_int; + pub fn getpgid(pid: pid_t) -> pid_t; + pub fn getpgrp() -> pid_t; + pub fn getpid() -> pid_t; + pub fn getppid() -> pid_t; + pub fn getuid() -> uid_t; + pub fn isatty(fd: c_int) -> c_int; + pub fn link(src: *const c_char, dst: *const c_char) -> c_int; + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: c_int) -> c_long; + pub fn pause() -> c_int; + pub fn pipe(fds: *mut c_int) -> c_int; + pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; + pub fn rmdir(path: *const c_char) -> c_int; + pub fn seteuid(uid: uid_t) -> c_int; + pub fn setegid(gid: gid_t) -> c_int; + pub fn setgid(gid: gid_t) -> c_int; + pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int; + pub fn setsid() -> pid_t; + pub fn setuid(uid: uid_t) -> c_int; + pub fn sleep(secs: c_uint) -> c_uint; + pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int; + pub fn tcgetpgrp(fd: c_int) -> pid_t; + pub fn tcsetpgrp(fd: c_int, pgrp: crate::pid_t) -> c_int; + pub fn ttyname(fd: c_int) -> *mut c_char; + pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *mut c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t; + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn umask(mask: mode_t) -> mode_t; + + pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int; + + pub fn kill(pid: pid_t, sig: c_int) -> c_int; + + pub fn mlock(addr: *const c_void, len: size_t) -> c_int; + pub fn munlock(addr: *const c_void, len: size_t) -> c_int; + pub fn mlockall(flags: c_int) -> c_int; + pub fn munlockall() -> c_int; + + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + + pub fn if_nametoindex(ifname: *const c_char) -> c_uint; + pub fn if_indextoname(ifindex: c_uint, ifname: *mut c_char) -> *mut c_char; + + pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; + + pub fn fsync(fd: c_int) -> c_int; + + pub fn setenv(name: *const c_char, val: *const c_char, overwrite: c_int) -> c_int; + pub fn unsetenv(name: *const c_char) -> c_int; + + pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int; + + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; + + pub fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char; + + pub fn flock(fd: c_int, operation: c_int) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn times(buf: *mut crate::tms) -> crate::clock_t; + + pub fn pthread_self() -> crate::pthread_t; + pub fn pthread_join(native: crate::pthread_t, value: *mut *mut c_void) -> c_int; + pub fn pthread_exit(value: *mut c_void) -> !; + pub fn pthread_attr_init(attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_destroy(attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_getstacksize( + attr: *const crate::pthread_attr_t, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setstacksize(attr: *mut crate::pthread_attr_t, stack_size: size_t) + -> c_int; + pub fn pthread_attr_setdetachstate(attr: *mut crate::pthread_attr_t, state: c_int) -> c_int; + pub fn pthread_detach(thread: crate::pthread_t) -> c_int; + pub fn sched_yield() -> c_int; + pub fn pthread_key_create( + key: *mut pthread_key_t, + dtor: Option, + ) -> c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int; + pub fn pthread_mutex_init( + lock: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t, + ) -> c_int; + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: c_int) -> c_int; + + pub fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int; + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_cond_timedwait( + cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int; + pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int; + pub fn pthread_rwlock_init( + lock: *mut pthread_rwlock_t, + attr: *const pthread_rwlockattr_t, + ) -> c_int; + pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) -> c_int; + pub fn pthread_getname_np(thread: crate::pthread_t, name: *mut c_char, len: size_t) -> c_int; + pub fn pthread_setname_np(thread: crate::pthread_t, name: *const c_char) -> c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn getsockopt( + sockfd: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut crate::socklen_t, + ) -> c_int; + pub fn raise(signum: c_int) -> c_int; + pub fn sigaction(signum: c_int, act: *const sigaction, oldact: *mut sigaction) -> c_int; + + pub fn utimes(filename: *const c_char, times: *const crate::timeval) -> c_int; + pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void; + pub fn dlerror() -> *mut c_char; + pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; + pub fn dlclose(handle: *mut c_void) -> c_int; + pub fn dladdr(addr: *const c_void, info: *mut Dl_info) -> c_int; + + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + pub fn freeaddrinfo(res: *mut addrinfo); + pub fn gai_strerror(errcode: c_int) -> *const c_char; + pub fn res_init() -> c_int; + + pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn mktime(tm: *mut tm) -> time_t; + pub fn time(time: *mut time_t) -> time_t; + pub fn gmtime(time_p: *const time_t) -> *mut tm; + pub fn localtime(time_p: *const time_t) -> *mut tm; + + pub fn mknod(pathname: *const c_char, mode: mode_t, dev: crate::dev_t) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn gethostname(name: *mut c_char, len: size_t) -> c_int; + pub fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut servent; + pub fn getprotobyname(name: *const c_char) -> *mut protoent; + pub fn getprotobynumber(proto: c_int) -> *mut protoent; + pub fn usleep(secs: c_uint) -> c_int; + pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn putenv(string: *mut c_char) -> c_int; + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int; + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; + pub fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char; + pub fn localeconv() -> *mut lconv; + + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_wait(sem: *mut sem_t) -> c_int; + pub fn sem_trywait(sem: *mut sem_t) -> c_int; + pub fn sem_post(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn statvfs(path: *const c_char, buf: *mut statvfs) -> c_int; + pub fn fstatvfs(fd: c_int, buf: *mut statvfs) -> c_int; + + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> ssize_t; + + pub fn sigemptyset(set: *mut sigset_t) -> c_int; + pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int; + pub fn sigfillset(set: *mut sigset_t) -> c_int; + pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int; + pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int; + + pub fn sigprocmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sigpending(set: *mut sigset_t) -> c_int; + + pub fn timegm(tm: *mut crate::tm) -> time_t; + + pub fn getsid(pid: pid_t) -> pid_t; + + pub fn sysconf(name: c_int) -> c_long; + + pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int; + + pub fn pselect( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timespec, + sigmask: *const sigset_t, + ) -> c_int; + pub fn fseeko(stream: *mut crate::FILE, offset: off_t, whence: c_int) -> c_int; + pub fn ftello(stream: *mut crate::FILE) -> off_t; + pub fn tcdrain(fd: c_int) -> c_int; + pub fn cfgetispeed(termios: *const crate::termios) -> crate::speed_t; + pub fn cfgetospeed(termios: *const crate::termios) -> crate::speed_t; + pub fn cfmakeraw(termios: *mut crate::termios); + pub fn cfsetispeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + pub fn cfsetospeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + pub fn cfsetspeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + pub fn tcgetattr(fd: c_int, termios: *mut crate::termios) -> c_int; + pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *const crate::termios) -> c_int; + pub fn tcflow(fd: c_int, action: c_int) -> c_int; + pub fn tcflush(fd: c_int, action: c_int) -> c_int; + pub fn tcgetsid(fd: c_int) -> crate::pid_t; + pub fn tcsendbreak(fd: c_int, duration: c_int) -> c_int; + pub fn mkstemp(template: *mut c_char) -> c_int; + pub fn mkdtemp(template: *mut c_char) -> *mut c_char; + + pub fn tmpnam(ptr: *mut c_char) -> *mut c_char; + + pub fn openlog(ident: *const c_char, logopt: c_int, facility: c_int); + pub fn closelog(); + pub fn setlogmask(maskpri: c_int) -> c_int; + pub fn syslog(priority: c_int, message: *const c_char, ...); + + pub fn grantpt(fd: c_int) -> c_int; + pub fn posix_openpt(flags: c_int) -> c_int; + pub fn ptsname(fd: c_int) -> *mut c_char; + pub fn unlockpt(fd: c_int) -> c_int; + + pub fn fdatasync(fd: c_int) -> c_int; + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + pub fn pthread_getattr_np(native: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn setgroups(ngroups: size_t, ptr: *const crate::gid_t) -> c_int; + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + + pub fn fdopendir(fd: c_int) -> *mut crate::DIR; + + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int; + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn clearenv() -> c_int; + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + pub fn setreuid(ruid: crate::uid_t, euid: crate::uid_t) -> c_int; + pub fn setregid(rgid: crate::gid_t, egid: crate::gid_t) -> c_int; + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + pub fn acct(filename: *const c_char) -> c_int; + pub fn brk(addr: *mut c_void) -> c_int; + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + + // System V IPC + pub fn shmget(key: crate::key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> crate::key_t; + pub fn semget(key: crate::key_t, nsems: c_int, semflag: c_int) -> c_int; + pub fn semop(semid: c_int, sops: *mut crate::sembuf, nsops: size_t) -> c_int; + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + pub fn msgctl(msqid: c_int, cmd: c_int, buf: *mut msqid_ds) -> c_int; + pub fn msgget(key: crate::key_t, msgflg: c_int) -> c_int; + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + pub fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: size_t, msgflg: c_int) -> c_int; + + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn __errno_location() -> *mut c_int; + + pub fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn readahead(fd: c_int, offset: off64_t, count: size_t) -> ssize_t; + pub fn signalfd(fd: c_int, mask: *const crate::sigset_t, flags: c_int) -> c_int; + pub fn timerfd_create(clockid: c_int, flags: c_int) -> c_int; + pub fn timerfd_gettime(fd: c_int, curr_value: *mut itimerspec) -> c_int; + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec, + ) -> c_int; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn quotactl(cmd: c_int, special: *const c_char, id: c_int, data: *mut c_char) -> c_int; + pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int; + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn reboot(how_to: c_int) -> c_int; + pub fn setfsgid(gid: crate::gid_t) -> c_int; + pub fn setfsuid(uid: crate::uid_t) -> c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn sync_file_range(fd: c_int, offset: off64_t, nbytes: off64_t, flags: c_uint) -> c_int; + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn futimes(fd: c_int, times: *const crate::timeval) -> c_int; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + pub fn setdomainname(name: *const c_char, len: size_t) -> c_int; + pub fn vhangup() -> c_int; + pub fn sendmmsg(sockfd: c_int, msgvec: *mut mmsghdr, vlen: c_uint, flags: c_int) -> c_int; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *mut crate::timespec, + ) -> c_int; + pub fn sync(); + pub fn syscall(num: c_long, ...) -> c_long; + pub fn sched_getaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *mut cpu_set_t, + ) -> c_int; + pub fn sched_setaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *const cpu_set_t, + ) -> c_int; + pub fn umount(target: *const c_char) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn tee(fd_in: c_int, fd_out: c_int, len: size_t, flags: c_uint) -> ssize_t; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + pub fn splice( + fd_in: c_int, + off_in: *mut crate::loff_t, + fd_out: c_int, + off_out: *mut crate::loff_t, + len: size_t, + flags: c_uint, + ) -> ssize_t; + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn swapoff(puath: *const c_char) -> c_int; + pub fn vmsplice(fd: c_int, iov: *const crate::iovec, nr_segs: size_t, flags: c_uint) + -> ssize_t; + pub fn mount( + src: *const c_char, + target: *const c_char, + fstype: *const c_char, + flags: c_ulong, + data: *const c_void, + ) -> c_int; + pub fn personality(persona: c_ulong) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: nfds_t, + timeout: *const crate::timespec, + sigmask: *const sigset_t, + ) -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn clone( + cb: extern "C" fn(*mut c_void) -> c_int, + child_stack: *mut c_void, + flags: c_int, + arg: *mut c_void, + ... + ) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn umount2(target: *const c_char, flags: c_int) -> c_int; + pub fn swapon(path: *const c_char, swapflags: c_int) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn( + info: *mut crate::dl_phdr_info, + size: size_t, + data: *mut c_void, + ) -> c_int, + >, + data: *mut c_void, + ) -> c_int; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(any(target_arch = "riscv64"))] { + mod riscv64; + pub use self::riscv64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/fuchsia/riscv64.rs b/deps/crates/vendor/libc/src/fuchsia/riscv64.rs new file mode 100644 index 00000000000000..bc93cc3bff0a92 --- /dev/null +++ b/deps/crates/vendor/libc/src/fuchsia/riscv64.rs @@ -0,0 +1,46 @@ +use crate::off_t; +use crate::prelude::*; + +// From psABI Calling Convention for RV64 +pub type __u64 = c_ulonglong; +pub type wchar_t = i32; + +pub type nlink_t = c_ulong; +pub type blksize_t = c_long; + +pub type stat64 = stat; +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + // Not actually used, IPC calls just return ENOSYS + pub struct ipc_perm { + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_ushort, + __unused1: Padding, + __unused2: Padding, + } +} diff --git a/deps/crates/vendor/libc/src/fuchsia/x86_64.rs b/deps/crates/vendor/libc/src/fuchsia/x86_64.rs new file mode 100644 index 00000000000000..fc42cd9810985f --- /dev/null +++ b/deps/crates/vendor/libc/src/fuchsia/x86_64.rs @@ -0,0 +1,110 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = c_long; +pub type __u64 = c_ulonglong; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __reserved: Padding<[c_long; 3]>, + } + + pub struct mcontext_t { + __private: [u64; 32], + } + + pub struct ipc_perm { + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + __private: [u8; 512], + } +} + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: c_int = 0; +pub const R14: c_int = 1; +pub const R13: c_int = 2; +pub const R12: c_int = 3; +pub const RBP: c_int = 4; +pub const RBX: c_int = 5; +pub const R11: c_int = 6; +pub const R10: c_int = 7; +pub const R9: c_int = 8; +pub const R8: c_int = 9; +pub const RAX: c_int = 10; +pub const RCX: c_int = 11; +pub const RDX: c_int = 12; +pub const RSI: c_int = 13; +pub const RDI: c_int = 14; +pub const ORIG_RAX: c_int = 15; +pub const RIP: c_int = 16; +pub const CS: c_int = 17; +pub const EFLAGS: c_int = 18; +pub const RSP: c_int = 19; +pub const SS: c_int = 20; +pub const FS_BASE: c_int = 21; +pub const GS_BASE: c_int = 22; +pub const DS: c_int = 23; +pub const ES: c_int = 24; +pub const FS: c_int = 25; +pub const GS: c_int = 26; + +pub const MAP_32BIT: c_int = 0x0040; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; diff --git a/deps/crates/vendor/libc/src/hermit.rs b/deps/crates/vendor/libc/src/hermit.rs new file mode 100644 index 00000000000000..2cbf57393104e3 --- /dev/null +++ b/deps/crates/vendor/libc/src/hermit.rs @@ -0,0 +1,562 @@ +//! Hermit C type definitions + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; +pub type intptr_t = isize; +pub type uintptr_t = usize; + +pub type size_t = usize; +pub type ssize_t = isize; +pub type ptrdiff_t = isize; + +pub type clockid_t = i32; +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type mode_t = u32; +pub type nfds_t = usize; +pub type pid_t = i32; +pub type sa_family_t = u8; +pub type socklen_t = u32; +pub type time_t = i64; + +s! { + pub struct addrinfo { + pub ai_flags: i32, + pub ai_family: i32, + pub ai_socktype: i32, + pub ai_protocol: i32, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct dirent64 { + pub d_ino: u64, + pub d_off: i64, + pub d_reclen: u16, + pub d_type: u8, + pub d_name: [c_char; 256], + } + + #[repr(align(4))] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct iovec { + iov_base: *mut c_void, + iov_len: usize, + } + + pub struct pollfd { + pub fd: i32, + pub events: i16, + pub revents: i16, + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[u8; 112]>, + } + + pub struct stat { + pub st_dev: u64, + pub st_ino: u64, + pub st_nlink: u64, + pub st_mode: mode_t, + pub st_uid: u32, + pub st_gid: u32, + pub st_rdev: u64, + pub st_size: i64, + pub st_blksize: i64, + pub st_blocks: i64, + pub st_atim: timespec, + pub st_mtim: timespec, + pub st_ctim: timespec, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: i32, + } +} + +pub const AF_UNSPEC: i32 = 0; +pub const AF_INET: i32 = 3; +pub const AF_INET6: i32 = 1; +pub const AF_VSOCK: i32 = 2; + +pub const CLOCK_REALTIME: clockid_t = 1; +pub const CLOCK_MONOTONIC: clockid_t = 4; + +pub const DT_UNKNOWN: u8 = 0; +pub const DT_FIFO: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_REG: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; +pub const DT_WHT: u8 = 14; + +pub const EAI_AGAIN: i32 = 2; +pub const EAI_BADFLAGS: i32 = 3; +pub const EAI_FAIL: i32 = 4; +pub const EAI_FAMILY: i32 = 5; +pub const EAI_MEMORY: i32 = 6; +pub const EAI_NODATA: i32 = 7; +pub const EAI_NONAME: i32 = 8; +pub const EAI_SERVICE: i32 = 9; +pub const EAI_SOCKTYPE: i32 = 10; +pub const EAI_SYSTEM: i32 = 11; +pub const EAI_OVERFLOW: i32 = 14; + +pub const EFD_SEMAPHORE: i16 = 0o1; +pub const EFD_NONBLOCK: i16 = 0o4000; +pub const EFD_CLOEXEC: i16 = 0o40000; + +pub const F_DUPFD: i32 = 0; +pub const F_GETFD: i32 = 1; +pub const F_SETFD: i32 = 2; +pub const F_GETFL: i32 = 3; +pub const F_SETFL: i32 = 4; + +pub const FD_CLOEXEC: i32 = 1; + +pub const FIONBIO: i32 = 0x8008667e; + +pub const FUTEX_RELATIVE_TIMEOUT: u32 = 1; + +pub const IP_TOS: i32 = 1; +pub const IP_TTL: i32 = 2; +pub const IP_ADD_MEMBERSHIP: i32 = 3; +pub const IP_DROP_MEMBERSHIP: i32 = 4; +pub const IP_MULTICAST_TTL: i32 = 5; +pub const IP_MULTICAST_LOOP: i32 = 7; + +pub const IPPROTO_IP: i32 = 0; +pub const IPPROTO_TCP: i32 = 6; +pub const IPPROTO_UDP: i32 = 17; +pub const IPPROTO_IPV6: i32 = 41; + +pub const IPV6_ADD_MEMBERSHIP: i32 = 12; +pub const IPV6_DROP_MEMBERSHIP: i32 = 13; +pub const IPV6_MULTICAST_LOOP: i32 = 19; +pub const IPV6_V6ONLY: i32 = 27; + +pub const MSG_PEEK: i32 = 1; + +pub const O_RDONLY: i32 = 0o0; +pub const O_WRONLY: i32 = 0o1; +pub const O_RDWR: i32 = 0o2; +pub const O_CREAT: i32 = 0o100; +pub const O_EXCL: i32 = 0o200; +pub const O_TRUNC: i32 = 0o1000; +pub const O_APPEND: i32 = 0o2000; +pub const O_NONBLOCK: i32 = 0o4000; +pub const O_DIRECTORY: i32 = 0o200000; + +pub const POLLIN: i16 = 0x1; +pub const POLLPRI: i16 = 0x2; +pub const POLLOUT: i16 = 0x4; +pub const POLLERR: i16 = 0x8; +pub const POLLHUP: i16 = 0x10; +pub const POLLNVAL: i16 = 0x20; +pub const POLLRDNORM: i16 = 0x040; +pub const POLLRDBAND: i16 = 0x080; +pub const POLLWRNORM: i16 = 0x0100; +pub const POLLWRBAND: i16 = 0x0200; +pub const POLLRDHUP: i16 = 0x2000; + +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; + +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFIFO: mode_t = 0o1_0000; + +pub const SHUT_RD: i32 = 0; +pub const SHUT_WR: i32 = 1; +pub const SHUT_RDWR: i32 = 2; + +pub const SO_REUSEADDR: i32 = 0x0004; +pub const SO_KEEPALIVE: i32 = 0x0008; +pub const SO_BROADCAST: i32 = 0x0020; +pub const SO_LINGER: i32 = 0x0080; +pub const SO_SNDBUF: i32 = 0x1001; +pub const SO_RCVBUF: i32 = 0x1002; +pub const SO_SNDTIMEO: i32 = 0x1005; +pub const SO_RCVTIMEO: i32 = 0x1006; +pub const SO_ERROR: i32 = 0x1007; + +pub const SOCK_STREAM: i32 = 1; +pub const SOCK_DGRAM: i32 = 2; +pub const SOCK_NONBLOCK: i32 = 0o4000; +pub const SOCK_CLOEXEC: i32 = 0o40000; + +pub const SOL_SOCKET: i32 = 4095; + +pub const STDIN_FILENO: c_int = 0; +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; + +pub const TCP_NODELAY: i32 = 1; + +pub const EPERM: i32 = 1; +pub const ENOENT: i32 = 2; +pub const ESRCH: i32 = 3; +pub const EINTR: i32 = 4; +pub const EIO: i32 = 5; +pub const ENXIO: i32 = 6; +pub const E2BIG: i32 = 7; +pub const ENOEXEC: i32 = 8; +pub const EBADF: i32 = 9; +pub const ECHILD: i32 = 10; +pub const EAGAIN: i32 = 11; +pub const ENOMEM: i32 = 12; +pub const EACCES: i32 = 13; +pub const EFAULT: i32 = 14; +pub const ENOTBLK: i32 = 15; +pub const EBUSY: i32 = 16; +pub const EEXIST: i32 = 17; +pub const EXDEV: i32 = 18; +pub const ENODEV: i32 = 19; +pub const ENOTDIR: i32 = 20; +pub const EISDIR: i32 = 21; +pub const EINVAL: i32 = 22; +pub const ENFILE: i32 = 23; +pub const EMFILE: i32 = 24; +pub const ENOTTY: i32 = 25; +pub const ETXTBSY: i32 = 26; +pub const EFBIG: i32 = 27; +pub const ENOSPC: i32 = 28; +pub const ESPIPE: i32 = 29; +pub const EROFS: i32 = 30; +pub const EMLINK: i32 = 31; +pub const EPIPE: i32 = 32; +pub const EDOM: i32 = 33; +pub const ERANGE: i32 = 34; +pub const EDEADLK: i32 = 35; +pub const ENAMETOOLONG: i32 = 36; +pub const ENOLCK: i32 = 37; +pub const ENOSYS: i32 = 38; +pub const ENOTEMPTY: i32 = 39; +pub const ELOOP: i32 = 40; +pub const EWOULDBLOCK: i32 = EAGAIN; +pub const ENOMSG: i32 = 42; +pub const EIDRM: i32 = 43; +pub const ECHRNG: i32 = 44; +pub const EL2NSYNC: i32 = 45; +pub const EL3HLT: i32 = 46; +pub const EL3RST: i32 = 47; +pub const ELNRNG: i32 = 48; +pub const EUNATCH: i32 = 49; +pub const ENOCSI: i32 = 50; +pub const EL2HLT: i32 = 51; +pub const EBADE: i32 = 52; +pub const EBADR: i32 = 53; +pub const EXFULL: i32 = 54; +pub const ENOANO: i32 = 55; +pub const EBADRQC: i32 = 56; +pub const EBADSLT: i32 = 57; +pub const EDEADLOCK: i32 = EDEADLK; +pub const EBFONT: i32 = 59; +pub const ENOSTR: i32 = 60; +pub const ENODATA: i32 = 61; +pub const ETIME: i32 = 62; +pub const ENOSR: i32 = 63; +pub const ENONET: i32 = 64; +pub const ENOPKG: i32 = 65; +pub const EREMOTE: i32 = 66; +pub const ENOLINK: i32 = 67; +pub const EADV: i32 = 68; +pub const ESRMNT: i32 = 69; +pub const ECOMM: i32 = 70; +pub const EPROTO: i32 = 71; +pub const EMULTIHOP: i32 = 72; +pub const EDOTDOT: i32 = 73; +pub const EBADMSG: i32 = 74; +pub const EOVERFLOW: i32 = 75; +pub const ENOTUNIQ: i32 = 76; +pub const EBADFD: i32 = 77; +pub const EREMCHG: i32 = 78; +pub const ELIBACC: i32 = 79; +pub const ELIBBAD: i32 = 80; +pub const ELIBSCN: i32 = 81; +pub const ELIBMAX: i32 = 82; +pub const ELIBEXEC: i32 = 83; +pub const EILSEQ: i32 = 84; +pub const ERESTART: i32 = 85; +pub const ESTRPIPE: i32 = 86; +pub const EUSERS: i32 = 87; +pub const ENOTSOCK: i32 = 88; +pub const EDESTADDRREQ: i32 = 89; +pub const EMSGSIZE: i32 = 90; +pub const EPROTOTYPE: i32 = 91; +pub const ENOPROTOOPT: i32 = 92; +pub const EPROTONOSUPPORT: i32 = 93; +pub const ESOCKTNOSUPPORT: i32 = 94; +pub const EOPNOTSUPP: i32 = 95; +pub const EPFNOSUPPORT: i32 = 96; +pub const EAFNOSUPPORT: i32 = 97; +pub const EADDRINUSE: i32 = 98; +pub const EADDRNOTAVAIL: i32 = 99; +pub const ENETDOWN: i32 = 100; +pub const ENETUNREACH: i32 = 101; +pub const ENETRESET: i32 = 102; +pub const ECONNABORTED: i32 = 103; +pub const ECONNRESET: i32 = 104; +pub const ENOBUFS: i32 = 105; +pub const EISCONN: i32 = 106; +pub const ENOTCONN: i32 = 107; +pub const ESHUTDOWN: i32 = 108; +pub const ETOOMANYREFS: i32 = 109; +pub const ETIMEDOUT: i32 = 110; +pub const ECONNREFUSED: i32 = 111; +pub const EHOSTDOWN: i32 = 112; +pub const EHOSTUNREACH: i32 = 113; +pub const EALREADY: i32 = 114; +pub const EINPROGRESS: i32 = 115; +pub const ESTALE: i32 = 116; +pub const EUCLEAN: i32 = 117; +pub const ENOTNAM: i32 = 118; +pub const ENAVAIL: i32 = 119; +pub const EISNAM: i32 = 120; +pub const EREMOTEIO: i32 = 121; +pub const EDQUOT: i32 = 122; +pub const ENOMEDIUM: i32 = 123; +pub const EMEDIUMTYPE: i32 = 124; +pub const ECANCELED: i32 = 125; +pub const ENOKEY: i32 = 126; +pub const EKEYEXPIRED: i32 = 127; +pub const EKEYREVOKED: i32 = 128; +pub const EKEYREJECTED: i32 = 129; +pub const EOWNERDEAD: i32 = 130; +pub const ENOTRECOVERABLE: i32 = 131; +pub const ERFKILL: i32 = 132; +pub const EHWPOISON: i32 = 133; + +extern "C" { + #[link_name = "sys_alloc"] + pub fn alloc(size: usize, align: usize) -> *mut u8; + + #[link_name = "sys_alloc_zeroed"] + pub fn alloc_zeroed(size: usize, align: usize) -> *mut u8; + + #[link_name = "sys_realloc"] + pub fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8; + + #[link_name = "sys_dealloc"] + pub fn dealloc(ptr: *mut u8, size: usize, align: usize); + + #[link_name = "sys_exit"] + pub fn exit(status: i32) -> !; + + #[link_name = "sys_abort"] + pub fn abort() -> !; + + #[link_name = "sys_errno"] + pub fn errno() -> i32; + + #[link_name = "sys_clock_gettime"] + pub fn clock_gettime(clockid: clockid_t, tp: *mut timespec) -> i32; + + #[link_name = "sys_nanosleep"] + pub fn nanosleep(req: *const timespec) -> i32; + + #[link_name = "sys_available_parallelism"] + pub fn available_parallelism() -> usize; + + #[link_name = "sys_futex_wait"] + pub fn futex_wait( + address: *mut u32, + expected: u32, + timeout: *const timespec, + flags: u32, + ) -> i32; + + #[link_name = "sys_futex_wake"] + pub fn futex_wake(address: *mut u32, count: i32) -> i32; + + #[link_name = "sys_stat"] + pub fn stat(path: *const c_char, stat: *mut stat) -> i32; + + #[link_name = "sys_fstat"] + pub fn fstat(fd: i32, stat: *mut stat) -> i32; + + #[link_name = "sys_lstat"] + pub fn lstat(path: *const c_char, stat: *mut stat) -> i32; + + #[link_name = "sys_open"] + pub fn open(path: *const c_char, flags: i32, mode: mode_t) -> i32; + + #[link_name = "sys_unlink"] + pub fn unlink(path: *const c_char) -> i32; + + #[link_name = "sys_mkdir"] + pub fn mkdir(path: *const c_char, mode: mode_t) -> i32; + + #[link_name = "sys_rmdir"] + pub fn rmdir(path: *const c_char) -> i32; + + #[link_name = "sys_read"] + pub fn read(fd: i32, buf: *mut u8, len: usize) -> isize; + + #[link_name = "sys_write"] + pub fn write(fd: i32, buf: *const u8, len: usize) -> isize; + + #[link_name = "sys_readv"] + pub fn readv(fd: i32, iov: *const iovec, iovcnt: usize) -> isize; + + #[link_name = "sys_writev"] + pub fn writev(fd: i32, iov: *const iovec, iovcnt: usize) -> isize; + + #[link_name = "sys_close"] + pub fn close(fd: i32) -> i32; + + #[link_name = "sys_dup"] + pub fn dup(fd: i32) -> i32; + + #[link_name = "sys_fcntl"] + pub fn fcntl(fd: i32, cmd: i32, arg: i32) -> i32; + + #[link_name = "sys_getdents64"] + pub fn getdents64(fd: i32, dirp: *mut dirent64, count: usize) -> isize; + + #[link_name = "sys_getaddrinfo"] + pub fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> i32; + + #[link_name = "sys_freeaddrinfo"] + pub fn freeaddrinfo(ai: *mut addrinfo); + + #[link_name = "sys_socket"] + pub fn socket(domain: i32, ty: i32, protocol: i32) -> i32; + + #[link_name = "sys_bind"] + pub fn bind(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32; + + #[link_name = "sys_listen"] + pub fn listen(sockfd: i32, backlog: i32) -> i32; + + #[link_name = "sys_accept"] + pub fn accept(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32; + + #[link_name = "sys_connect"] + pub fn connect(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32; + + #[link_name = "sys_recv"] + pub fn recv(sockfd: i32, buf: *mut u8, len: usize, flags: i32) -> isize; + + #[link_name = "sys_recvfrom"] + pub fn recvfrom( + sockfd: i32, + buf: *mut c_void, + len: usize, + flags: i32, + addr: *mut sockaddr, + addrlen: *mut socklen_t, + ) -> isize; + + #[link_name = "sys_send"] + pub fn send(sockfd: i32, buf: *const c_void, len: usize, flags: i32) -> isize; + + #[link_name = "sys_sendto"] + pub fn sendto( + sockfd: i32, + buf: *const c_void, + len: usize, + flags: i32, + to: *const sockaddr, + tolen: socklen_t, + ) -> isize; + + #[link_name = "sys_getpeername"] + pub fn getpeername(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32; + + #[link_name = "sys_getsockname"] + pub fn getsockname(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32; + + #[link_name = "sys_getsockopt"] + pub fn getsockopt( + sockfd: i32, + level: i32, + optname: i32, + optval: *mut c_void, + optlen: *mut socklen_t, + ) -> i32; + + #[link_name = "sys_setsockopt"] + pub fn setsockopt( + sockfd: i32, + level: i32, + optname: i32, + optval: *const c_void, + optlen: socklen_t, + ) -> i32; + + #[link_name = "sys_ioctl"] + pub fn ioctl(sockfd: i32, cmd: i32, argp: *mut c_void) -> i32; + + #[link_name = "sys_shutdown"] + pub fn shutdown(sockfd: i32, how: i32) -> i32; + + #[link_name = "sys_eventfd"] + pub fn eventfd(initval: u64, flags: i16) -> i32; + + #[link_name = "sys_poll"] + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: i32) -> i32; +} diff --git a/deps/crates/vendor/libc/src/lib.rs b/deps/crates/vendor/libc/src/lib.rs new file mode 100644 index 00000000000000..a00de4e2e06385 --- /dev/null +++ b/deps/crates/vendor/libc/src/lib.rs @@ -0,0 +1,168 @@ +//! libc - Raw FFI bindings to platforms' system libraries +#![crate_name = "libc"] +#![crate_type = "rlib"] +#![allow( + renamed_and_removed_lints, // Keep this order. + unknown_lints, // Keep this order. + nonstandard_style, + overflowing_literals, + unused_macros, + unused_macro_rules, +)] +#![warn( + missing_copy_implementations, + missing_debug_implementations, + safe_packed_borrows +)] +// Prepare for a future upgrade +#![warn(rust_2024_compatibility)] +// Things missing for 2024 that are blocked on MSRV or breakage +#![allow( + missing_unsafe_on_extern, + edition_2024_expr_fragment_specifier, + // Allowed globally, the warning is enabled in individual modules as we work through them + unsafe_op_in_unsafe_fn +)] +#![cfg_attr(libc_deny_warnings, deny(warnings))] +// Attributes needed when building as part of the standard library +#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, no_core))] +#![cfg_attr(feature = "rustc-dep-of-std", allow(internal_features))] +// Some targets don't need `link_cfg` and emit a warning. +#![cfg_attr(feature = "rustc-dep-of-std", allow(unused_features))] +// DIFF(1.0): The thread local references that raise this lint were removed in 1.0 +#![cfg_attr(feature = "rustc-dep-of-std", allow(static_mut_refs))] +#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)] +#![cfg_attr(feature = "rustc-dep-of-std", no_core)] + +#[macro_use] +mod macros; +mod new; + +cfg_if! { + if #[cfg(feature = "rustc-dep-of-std")] { + extern crate rustc_std_workspace_core as core; + } +} + +pub use core::ffi::c_void; + +#[allow(unused_imports)] // needed while the module is empty on some platforms +pub use new::*; + +cfg_if! { + if #[cfg(windows)] { + mod primitives; + pub use crate::primitives::*; + + mod windows; + pub use crate::windows::*; + + prelude!(); + } else if #[cfg(target_os = "fuchsia")] { + mod primitives; + pub use crate::primitives::*; + + mod fuchsia; + pub use crate::fuchsia::*; + + prelude!(); + } else if #[cfg(target_os = "switch")] { + mod primitives; + pub use primitives::*; + + mod switch; + pub use switch::*; + + prelude!(); + } else if #[cfg(target_os = "psp")] { + mod primitives; + pub use primitives::*; + + mod psp; + pub use crate::psp::*; + + prelude!(); + } else if #[cfg(target_os = "vxworks")] { + mod primitives; + pub use crate::primitives::*; + + mod vxworks; + pub use crate::vxworks::*; + + prelude!(); + } else if #[cfg(target_os = "qurt")] { + mod primitives; + pub use crate::primitives::*; + + mod qurt; + pub use crate::qurt::*; + + prelude!(); + } else if #[cfg(target_os = "solid_asp3")] { + mod primitives; + pub use crate::primitives::*; + + mod solid; + pub use crate::solid::*; + + prelude!(); + } else if #[cfg(unix)] { + mod primitives; + pub use crate::primitives::*; + + mod unix; + pub use crate::unix::*; + + prelude!(); + } else if #[cfg(target_os = "hermit")] { + mod primitives; + pub use crate::primitives::*; + + mod hermit; + pub use crate::hermit::*; + + prelude!(); + } else if #[cfg(target_os = "teeos")] { + mod primitives; + pub use primitives::*; + + mod teeos; + pub use teeos::*; + + prelude!(); + } else if #[cfg(target_os = "trusty")] { + mod primitives; + pub use crate::primitives::*; + + mod trusty; + pub use crate::trusty::*; + + prelude!(); + } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] { + mod primitives; + pub use crate::primitives::*; + + mod sgx; + pub use crate::sgx::*; + + prelude!(); + } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] { + mod primitives; + pub use crate::primitives::*; + + mod wasi; + pub use crate::wasi::*; + + prelude!(); + } else if #[cfg(target_os = "xous")] { + mod primitives; + pub use crate::primitives::*; + + mod xous; + pub use crate::xous::*; + + prelude!(); + } else { + // non-supported targets: empty... + } +} diff --git a/deps/crates/vendor/libc/src/macros.rs b/deps/crates/vendor/libc/src/macros.rs new file mode 100644 index 00000000000000..2d2d3908847142 --- /dev/null +++ b/deps/crates/vendor/libc/src/macros.rs @@ -0,0 +1,654 @@ +/// A macro for defining #[cfg] if-else statements. +/// +/// This is similar to the `if/elif` C preprocessor macro by allowing definition +/// of a cascade of `#[cfg]` cases, emitting the implementation which matches +/// first. +/// +/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// without having to rewrite each clause multiple times. +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated `cfg`s in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), + $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +/// Create an internal crate prelude with `core` reexports and common types. +macro_rules! prelude { + () => { + mod types; + + /// Frequently-used types that are available on all platforms + /// + /// We need to reexport the core types so this works with `rust-dep-of-std`. + mod prelude { + // Exports from `core` + #[allow(unused_imports)] + pub(crate) use core::clone::Clone; + #[allow(unused_imports)] + pub(crate) use core::default::Default; + #[allow(unused_imports)] + pub(crate) use core::marker::{ + Copy, + Send, + Sync, + }; + #[allow(unused_imports)] + pub(crate) use core::option::Option; + #[allow(unused_imports)] + pub(crate) use core::prelude::v1::derive; + #[allow(unused_imports)] + pub(crate) use core::{ + cfg, + fmt, + hash, + iter, + mem, + ptr, + }; + + #[allow(unused_imports)] + pub(crate) use fmt::Debug; + #[allow(unused_imports)] + pub(crate) use mem::{ + align_of, + align_of_val, + size_of, + size_of_val, + }; + + #[allow(unused_imports)] + pub(crate) use crate::types::{ + CEnumRepr, + Padding, + }; + // Commonly used types defined in this crate + #[allow(unused_imports)] + pub(crate) use crate::{ + c_char, + c_double, + c_float, + c_int, + c_long, + c_longlong, + c_short, + c_uchar, + c_uint, + c_ulong, + c_ulonglong, + c_ushort, + c_void, + intptr_t, + size_t, + ssize_t, + uintptr_t, + }; + } + }; +} + +/// Implement `Clone`, `Copy`, and `Debug` for one or more structs, as well as `PartialEq`, `Eq`, +/// and `Hash` if the `extra_traits` feature is enabled. +/// +/// Also mark the type with `repr(C)`. +/// +/// Use [`s_no_extra_traits`] for structs where the `extra_traits` feature does not +/// make sense, and for unions. +macro_rules! s { + ($( + $(#[$attr:meta])* + $pub:vis $t:ident $i:ident { $($field:tt)* } + )*) => ($( + s!(it: $(#[$attr])* $pub $t $i { $($field)* }); + )*); + + (it: $(#[$attr:meta])* $pub:vis union $i:ident { $($field:tt)* }) => ( + compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead"); + ); + + (it: $(#[$attr:meta])* $pub:vis struct $i:ident { $($field:tt)* }) => ( + #[repr(C)] + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + )] + #[cfg_attr( + feature = "extra_traits", + ::core::prelude::v1::derive(PartialEq, Eq, Hash) + )] + #[allow(deprecated)] + $(#[$attr])* + $pub struct $i { $($field)* } + ); +} + +/// Implement `Clone`, `Copy`, and `Debug` for a tuple struct, as well as `PartialEq`, `Eq`, +/// and `Hash` if the `extra_traits` feature is enabled. +/// +/// Unlike `s!`, this does *not* mark the type with `repr(C)`. Users should provide their own +/// `repr` attribute via `$attr` as necessary. +macro_rules! s_paren { + ($( + $(#[$attr:meta])* + $pub:vis struct $i:ident ( $($field:tt)* ); + )*) => ($( + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + )] + #[cfg_attr( + feature = "extra_traits", + ::core::prelude::v1::derive(PartialEq, Eq, Hash) + )] + $(#[$attr])* + $pub struct $i ( $($field)* ); + )*); +} + +/// Implement `Clone`, `Copy`, and `Debug` for one or more structs/unions, but exclude `PartialEq`, +/// `Eq`, and `Hash`. +/// +/// Also mark the type with `repr(C)`. +/// +/// Most structs will prefer to use [`s`]. +macro_rules! s_no_extra_traits { + ($( + $(#[$attr:meta])* + $pub:vis $t:ident $i:ident { $($field:tt)* } + )*) => ($( + s_no_extra_traits!(it: $(#[$attr])* $pub $t $i { $($field)* }); + )*); + + (it: $(#[$attr:meta])* $pub:vis union $i:ident { $($field:tt)* }) => ( + #[repr(C)] + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + )] + $(#[$attr])* + $pub union $i { $($field)* } + + impl ::core::fmt::Debug for $i { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct(::core::stringify!($i)).finish_non_exhaustive() + } + } + ); + + (it: $(#[$attr:meta])* $pub:vis struct $i:ident { $($field:tt)* }) => ( + #[repr(C)] + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + )] + $(#[$attr])* + $pub struct $i { $($field)* } + ); +} + +/// Create an uninhabited type that can't be constructed. It implements `Debug`, `Clone`, +/// and `Copy`, but these aren't meaningful for extern types so they should eventually +/// be removed. +/// +/// Really what we want here is something that also can't be named without indirection (in +/// ADTs or function signatures), but this doesn't exist. +macro_rules! extern_ty { + ($( + $(#[$attr:meta])* + pub enum $i:ident {} + )*) => ($( + $(#[$attr])* + // FIXME(1.0): the type is uninhabited so these traits are unreachable and could be + // removed. + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + )] + pub enum $i { } + )*); +} + +/// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and +/// `PartialEq` if the `extra_traits` feature is enabled. +// FIXME(#4419): Replace all uses of `e!` with `c_enum!` +macro_rules! e { + ($( + $(#[$attr:meta])* + pub enum $i:ident { $($field:tt)* } + )*) => ($( + #[cfg_attr( + feature = "extra_traits", + ::core::prelude::v1::derive(Eq, Hash, PartialEq) + )] + #[::core::prelude::v1::derive( + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + )] + $(#[$attr])* + pub enum $i { $($field)* } + )*); +} + +/// Represent a C enum as Rust constants and a type. +/// +/// C enums can't soundly be mapped to Rust enums since C enums are allowed to have duplicates or +/// unlisted values, but this is UB in Rust. This enum doesn't implement any traits, its main +/// purpose is to calculate the correct enum values. +/// +/// Use the magic name `#anon` if the C enum doesn't create a type. +/// +/// See for more. +macro_rules! c_enum { + // Matcher for multiple enums + ($( + $(#[repr($repr:ty)])? + pub enum $($ty_name:ident)? $(#$anon:ident)? { + $($vis:vis $variant:ident $(= $value:expr)?,)+ + } + )+) => { + $(c_enum!(@single; + $(#[repr($repr)])? + pub enum $($ty_name)? $(#$anon)? { + $($vis $variant $(= $value)?,)+ + } + );)+ + }; + + // Matcher for a single enum + (@single; + $(#[repr($repr:ty)])? + pub enum $ty_name:ident { + $($vis:vis $variant:ident $(= $value:expr)?,)+ + } + ) => { + pub type $ty_name = c_enum!(@ty $($repr)?); + c_enum! { + @variant; + ty: $ty_name; + default: 0; + variants: [$($vis $variant $(= $value)?,)+] + } + }; + + // Matcher for a single anonymous enum + (@single; + $(#[repr($repr:ty)])? + pub enum #anon { + $($vis:vis $variant:ident $(= $value:expr)?,)+ + } + ) => { + c_enum! { + @variant; + ty: c_enum!(@ty $($repr)?); + default: 0; + variants: [$($vis $variant $(= $value)?,)+] + } + }; + + // Matcher for variants: eats a single variant then recurses with the rest + (@variant; ty: $_ty_name:ty; default: $_idx:expr; variants: []) => { /* end of the chain */ }; + ( + @variant; + ty: $ty_name:ty; + default: $default_val:expr; + variants: [ + $vis:vis $variant:ident $(= $value:expr)?, + $($tail:tt)* + ] + ) => { + $vis const $variant: $ty_name = { + #[allow(unused_variables)] + let r = $default_val; + $(let r = $value;)? + r + }; + + // The next value is always one more than the previous value, unless + // set explicitly. + c_enum! { + @variant; + ty: $ty_name; + default: $variant + 1; + variants: [$($tail)*] + } + }; + + // Use a specific type if provided, otherwise default to `CEnumRepr` + (@ty $repr:ty) => { $repr }; + (@ty) => { $crate::prelude::CEnumRepr }; +} + +/// Define a `unsafe` function. +macro_rules! f { + ($( + $(#[$attr:meta])* + // Less than ideal hack to match either `fn` or `const fn`. + pub $(fn $i:ident)? $(const fn $const_i:ident)? + ($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty + $body:block + )+) => {$( + #[inline] + $(#[$attr])* + pub $(unsafe extern "C" fn $i)? $(const unsafe extern "C" fn $const_i)? + ($($arg: $argty),*) -> $ret + $body + )+}; +} + +/// Define a safe function. +macro_rules! safe_f { + ($( + $(#[$attr:meta])* + // Less than ideal hack to match either `fn` or `const fn`. + pub $(fn $i:ident)? $(const fn $const_i:ident)? + ($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty + $body:block + )+) => {$( + #[inline] + $(#[$attr])* + pub $(extern "C" fn $i)? $(const extern "C" fn $const_i)? + ($($arg: $argty),*) -> $ret + $body + )+}; +} + +// This macro is used to deprecate items that should be accessed via the mach2 crate +macro_rules! deprecated_mach { + (pub const $id:ident: $ty:ty = $expr:expr;) => { + #[deprecated( + since = "0.2.55", + note = "Use the `mach2` crate instead", + )] + #[allow(deprecated)] + pub const $id: $ty = $expr; + }; + ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => { + $( + deprecated_mach!( + pub const $id: $ty = $expr; + ); + )* + }; + (pub type $id:ident = $ty:ty;) => { + #[deprecated( + since = "0.2.55", + note = "Use the `mach2` crate instead", + )] + #[allow(deprecated)] + pub type $id = $ty; + }; + ($(pub type $id:ident = $ty:ty;)*) => { + $( + deprecated_mach!( + pub type $id = $ty; + ); + )* + } +} + +/// Polyfill for std's `offset_of`. +// FIXME(msrv): stabilized in std in 1.77 +macro_rules! offset_of { + ($Ty:path, $field:ident) => {{ + // Taken from bytemuck, avoids accidentally calling on deref + #[allow(clippy::unneeded_field_pattern)] + let $Ty { $field: _, .. }; + let data = core::mem::MaybeUninit::<$Ty>::uninit(); + let ptr = data.as_ptr(); + // nested unsafe, see f! + #[allow(unused_unsafe)] + // SAFETY: computed address is inbounds since we have a stack alloc for T + let fptr = unsafe { core::ptr::addr_of!((*ptr).$field) }; + let off = (fptr as usize).checked_sub(ptr as usize).unwrap(); + core::assert!(off <= core::mem::size_of::<$Ty>()); + off + }}; +} + +#[cfg(test)] +mod tests { + use core::any::TypeId; + + use crate::types::CEnumRepr; + + #[test] + fn c_enum_basic() { + // By default, variants get sequential values. + c_enum! { + pub enum e { + VAR0, + VAR1, + VAR2, + } + + // Also check enums that don't create a type. + pub enum #anon { + ANON0, + ANON1, + ANON2, + } + } + + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(VAR0, 0 as CEnumRepr); + assert_eq!(VAR1, 1 as CEnumRepr); + assert_eq!(VAR2, 2 as CEnumRepr); + + assert_eq!(type_id_of_val(&ANON0), TypeId::of::()); + assert_eq!(ANON0, 0 as CEnumRepr); + assert_eq!(ANON1, 1 as CEnumRepr); + assert_eq!(ANON2, 2 as CEnumRepr); + } + + #[test] + fn c_enum_repr() { + // Check specifying the integer representation + c_enum! { + #[repr(u16)] + pub enum e { + VAR0, + } + + #[repr(u16)] + pub enum #anon { + ANON0, + } + } + + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(VAR0, 0_u16); + + assert_eq!(type_id_of_val(&ANON0), TypeId::of::()); + assert_eq!(ANON0, 0_u16); + } + + #[test] + fn c_enum_set_value() { + // Setting an explicit value resets the count. + c_enum! { + pub enum e { + VAR2 = 2, + VAR3, + VAR4, + } + } + + assert_eq!(VAR2, 2 as CEnumRepr); + assert_eq!(VAR3, 3 as CEnumRepr); + assert_eq!(VAR4, 4 as CEnumRepr); + } + + #[test] + fn c_enum_multiple_set_value() { + // C enums always take one more than the previous value, unless set to a specific + // value. Duplicates are allowed. + c_enum! { + pub enum e { + VAR0, + VAR2_0 = 2, + VAR3_0, + VAR4_0, + VAR2_1 = 2, + VAR3_1, + VAR4_1, + } + } + + assert_eq!(VAR0, 0 as CEnumRepr); + assert_eq!(VAR2_0, 2 as CEnumRepr); + assert_eq!(VAR3_0, 3 as CEnumRepr); + assert_eq!(VAR4_0, 4 as CEnumRepr); + assert_eq!(VAR2_1, 2 as CEnumRepr); + assert_eq!(VAR3_1, 3 as CEnumRepr); + assert_eq!(VAR4_1, 4 as CEnumRepr); + } + + #[test] + fn c_enum_vis() { + mod priv1 { + c_enum! { + #[repr(u8)] + pub enum e1 { + PRIV_ON_1 = 10, + // Variant should still be usable within its visibility + pub PUB1 = PRIV_ON_1 * 2, + } + } + } + mod priv2 { + c_enum! { + #[repr(u16)] + pub enum e2 { + pub PRIV_ON_1 = 42, + pub PUB2 = PRIV_ON_1 * 2, + } + } + } + + use priv1::*; + use priv2::*; + + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(PUB1, 10u8 * 2); + assert_eq!(PUB2, 42u16 * 2); + // Verify that the default is private. If `PRIV_ON_1` was actually public in `priv1`, this + // would be an ambiguous import and/or type mismatch error. + assert_eq!(PRIV_ON_1, 42u16); + } + + fn type_id_of_val(_: &T) -> TypeId { + TypeId::of::() + } + + #[test] + fn test_offset_of() { + #[repr(C)] + struct Off1 { + a: u8, + b: u32, + c: Off2, + d: u64, + } + + #[repr(C)] + #[repr(align(128))] + struct Off2 {} + + assert_eq!(core::mem::offset_of!(Off1, a), offset_of!(Off1, a)); + assert_eq!(core::mem::offset_of!(Off1, b), offset_of!(Off1, b)); + assert_eq!(core::mem::offset_of!(Off1, c), offset_of!(Off1, c)); + assert_eq!(core::mem::offset_of!(Off1, d), offset_of!(Off1, d)); + } +} + +#[cfg(test)] +#[allow(unused)] +mod macro_checks { + s! { + pub struct S1 { + pub a: u32, + b: u32, + } + + struct S1Priv { + pub a: u32, + b: u32, + } + } + + s_no_extra_traits! { + pub struct S2 { + pub a: u32, + b: u32, + } + + struct S2Priv { + pub a: u32, + b: u32, + } + + pub union U2 { + pub a: u32, + b: f32, + } + + union U2Priv { + pub a: u32, + b: f32, + } + } +} diff --git a/deps/crates/vendor/libc/src/new/aix/mod.rs b/deps/crates/vendor/libc/src/new/aix/mod.rs new file mode 100644 index 00000000000000..c99b206b71688e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/aix/mod.rs @@ -0,0 +1,6 @@ +//! IBM AIX libc. +//! +//! * Headers are not public +//! * Manual pages: (under "Technical reference" for that version) + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/aix/unistd.rs b/deps/crates/vendor/libc/src/new/aix/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/aix/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/apple/libc/signal.rs b/deps/crates/vendor/libc/src/new/apple/libc/signal.rs new file mode 100644 index 00000000000000..b5f8d59b2d7f3a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libc/signal.rs @@ -0,0 +1,5 @@ +//! Header: `signal.h` +//! +//! + +pub use crate::sys::signal::*; diff --git a/deps/crates/vendor/libc/src/new/apple/libc/unistd.rs b/deps/crates/vendor/libc/src/new/apple/libc/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libc/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/mod.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/mod.rs new file mode 100644 index 00000000000000..66f25e6f7ba48e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/mod.rs @@ -0,0 +1,20 @@ +//! Source from libpthread + +/// Directory: `pthread/` +/// +/// Note that this module has a trailing underscore to avoid conflicting with its child `pthread` +/// module. +/// +/// +pub(crate) mod pthread_ { + pub(crate) mod introspection; + pub(crate) mod pthread; + pub(crate) mod pthread_impl; + pub(crate) mod pthread_spis; + pub(crate) mod qos; + pub(crate) mod sched; + pub(crate) mod spawn; + pub(crate) mod stack_np; +} + +pub(crate) mod sys; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/introspection.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/introspection.rs new file mode 100644 index 00000000000000..6509e22be3c081 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/introspection.rs @@ -0,0 +1,36 @@ +//! Header: `pthread/introspection.h` +//! +//! + +use crate::prelude::*; +pub use crate::pthread_::pthread::*; + +c_enum! { + #[repr(c_uint)] + pub enum #anon { + pub PTHREAD_INTROSPECTION_THREAD_CREATE = 1, + pub PTHREAD_INTROSPECTION_THREAD_START, + pub PTHREAD_INTROSPECTION_THREAD_TERMINATE, + pub PTHREAD_INTROSPECTION_THREAD_DESTROY, + } +} + +pub type pthread_introspection_hook_t = + extern "C" fn(event: c_uint, thread: pthread_t, addr: *mut c_void, size: size_t); + +extern "C" { + // Available from Big Sur + pub fn pthread_introspection_hook_install( + hook: pthread_introspection_hook_t, + ) -> pthread_introspection_hook_t; + pub fn pthread_introspection_setspecific_np( + thread: pthread_t, + key: pthread_key_t, + value: *const c_void, + ) -> c_int; + + pub fn pthread_introspection_getspecific_np( + thread: pthread_t, + key: pthread_key_t, + ) -> *mut c_void; +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread.rs new file mode 100644 index 00000000000000..a7e56bef8f11b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread.rs @@ -0,0 +1,76 @@ +//! Header: `pthread.h` or `pthread/pthread.h` +//! +//! + +use crate::prelude::*; +pub use crate::pthread_::qos::*; +pub use crate::pthread_::sched::*; +// No need to import from the `_pthread_attr_t` and similar modules since `_pthread_types` has +// everything we need. +pub use crate::sys::_pthread::_pthread_types::*; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 1; +pub const PTHREAD_CREATE_DETACHED: c_int = 2; + +pub const PTHREAD_INHERIT_SCHED: c_int = 1; +pub const PTHREAD_EXPLICIT_SCHED: c_int = 2; + +pub const PTHREAD_CANCEL_ENABLE: c_int = 0x01; +pub const PTHREAD_CANCEL_DISABLE: c_int = 0x00; +pub const PTHREAD_CANCEL_DEFERRED: c_int = 0x02; +pub const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 0x00; + +pub const PTHREAD_CANCELED: *mut c_void = 1 as *mut c_void; + +pub const PTHREAD_SCOPE_SYSTEM: c_int = 1; +pub const PTHREAD_SCOPE_PROCESS: c_int = 2; + +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 2; + +pub const PTHREAD_PRIO_NONE: c_int = 0; +pub const PTHREAD_PRIO_INHERIT: c_int = 1; +pub const PTHREAD_PRIO_PROTECT: c_int = 2; + +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; + +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __sig: _PTHREAD_RWLOCK_SIG_init, + __opaque: [0; __PTHREAD_RWLOCK_SIZE__], +}; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __sig: _PTHREAD_MUTEX_SIG_init, + __opaque: [0; __PTHREAD_MUTEX_SIZE__], +}; + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __sig: _PTHREAD_COND_SIG_init, + __opaque: [0; __PTHREAD_COND_SIZE__], +}; + +pub const PTHREAD_ONCE_INIT: crate::pthread_once_t = crate::pthread_once_t { + __sig: _PTHREAD_ONCE_SIG_INIT, + __opaque: [0; __PTHREAD_ONCE_SIZE__], +}; + +pub use crate::new::common::posix::pthread::{ + pthread_attr_getinheritsched, + pthread_attr_getschedparam, + pthread_attr_getschedpolicy, + pthread_attr_setinheritsched, + pthread_attr_setschedparam, + pthread_attr_setschedpolicy, + pthread_condattr_getpshared, + pthread_condattr_setpshared, + pthread_getschedparam, + pthread_mutexattr_getpshared, + pthread_mutexattr_setpshared, + pthread_once, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, + pthread_setschedparam, +}; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_impl.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_impl.rs new file mode 100644 index 00000000000000..92c5e2733c44e8 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_impl.rs @@ -0,0 +1,12 @@ +use crate::prelude::*; + +// FIXME(apple): these should all be `pub(crate)` +pub const _PTHREAD_MUTEX_SIG_init: c_long = 0x32AAABA7; + +pub const _PTHREAD_COND_SIG_init: c_long = 0x3CB0B1BB; +pub(crate) const _PTHREAD_ONCE_SIG_INIT: c_long = 0x30B1BCBA; +pub const _PTHREAD_RWLOCK_SIG_init: c_long = 0x2DA8B3B4; + +pub const SCHED_OTHER: c_int = 1; +pub const SCHED_FIFO: c_int = 4; +pub const SCHED_RR: c_int = 2; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_spis.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_spis.rs new file mode 100644 index 00000000000000..24e3fedc9d307b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/pthread_spis.rs @@ -0,0 +1,14 @@ +//! Header: `pthread/pthread_spis.h` +//! +//! + +use crate::prelude::*; + +extern "C" { + pub fn pthread_create_from_mach_thread( + thread: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/qos.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/qos.rs new file mode 100644 index 00000000000000..8b68c78ffb8262 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/qos.rs @@ -0,0 +1,25 @@ +//! Header: `pthread/qos.h` +//! +//! + +use crate::prelude::*; +pub use crate::sys::qos::*; + +extern "C" { + pub fn pthread_attr_set_qos_class_np( + attr: *mut crate::pthread_attr_t, + class: qos_class_t, + priority: c_int, + ) -> c_int; + pub fn pthread_attr_get_qos_class_np( + attr: *mut crate::pthread_attr_t, + class: *mut qos_class_t, + priority: *mut c_int, + ) -> c_int; + pub fn pthread_set_qos_class_self_np(class: qos_class_t, priority: c_int) -> c_int; + pub fn pthread_get_qos_class_np( + thread: crate::pthread_t, + class: *mut qos_class_t, + priority: *mut c_int, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/sched.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/sched.rs new file mode 100644 index 00000000000000..d25a6cb0827552 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/sched.rs @@ -0,0 +1,9 @@ +pub use crate::new::pthread_::pthread_impl::*; +use crate::prelude::*; + +s! { + pub struct sched_param { + pub sched_priority: c_int, + __opaque: [c_char; 4], + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/spawn.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/spawn.rs new file mode 100644 index 00000000000000..c5bdb7ababf10e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/spawn.rs @@ -0,0 +1,16 @@ +//! Header: `pthread/spawn.h` +//! +//! + +use crate::prelude::*; + +extern "C" { + pub fn posix_spawnattr_set_qos_class_np( + attr: *mut crate::posix_spawnattr_t, + qos_class: crate::qos_class_t, + ) -> c_int; + pub fn posix_spawnattr_get_qos_class_np( + attr: *const crate::posix_spawnattr_t, + qos_class: *mut crate::qos_class_t, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/stack_np.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/stack_np.rs new file mode 100644 index 00000000000000..0d501cdbb6f0b9 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/pthread_/stack_np.rs @@ -0,0 +1,12 @@ +//! Header: `pthread/stack_np.h` +//! +//! + +use crate::prelude::*; + +extern "C" { + pub fn pthread_stack_frame_decode_np( + frame_addr: uintptr_t, + return_addr: *mut uintptr_t, + ) -> uintptr_t; +} diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/sys/_pthread/_pthread_types.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/_pthread/_pthread_types.rs new file mode 100644 index 00000000000000..95e181c13f05d8 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/_pthread/_pthread_types.rs @@ -0,0 +1,79 @@ +//! Header: `sys/_pthread/_pthread_types.h` +//! +//! +//! +//! Note that the actual header defines `_opaque_pthread_*` structs which are typedefed to +//! `__darwin_pthread*` structs, and typedefed again in separate `_pthread_*.h` files to their final +//! `pthread_` name. This isn't useful for us so we simplify a bit and just define everything here. + +use crate::prelude::*; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const __PTHREAD_SIZE__: usize = 8176; + pub const __PTHREAD_ATTR_SIZE__: usize = 56; + pub const __PTHREAD_MUTEXATTR_SIZE__: usize = 8; + pub const __PTHREAD_MUTEX_SIZE__: usize = 56; + pub const __PTHREAD_CONDATTR_SIZE__: usize = 8; + pub const __PTHREAD_COND_SIZE__: usize = 40; + pub const __PTHREAD_ONCE_SIZE__: usize = 8; + pub const __PTHREAD_RWLOCK_SIZE__: usize = 192; + pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 16; + } else { + pub const __PTHREAD_SIZE__: usize = 4088; + pub const __PTHREAD_ATTR_SIZE__: usize = 36; + pub const __PTHREAD_MUTEXATTR_SIZE__: usize = 8; + pub const __PTHREAD_MUTEX_SIZE__: usize = 40; + pub const __PTHREAD_CONDATTR_SIZE__: usize = 4; + pub const __PTHREAD_COND_SIZE__: usize = 24; + pub const __PTHREAD_ONCE_SIZE__: usize = 4; + pub const __PTHREAD_RWLOCK_SIZE__: usize = 124; + pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 12; + } +} + +s! { + pub struct pthread_attr_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [c_char; __PTHREAD_ATTR_SIZE__], + } + + pub struct pthread_cond_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_COND_SIZE__], + } + + pub struct pthread_condattr_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_CONDATTR_SIZE__], + } + + pub struct pthread_mutex_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_MUTEX_SIZE__], + } + + pub struct pthread_mutexattr_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_MUTEXATTR_SIZE__], + } + + pub struct pthread_once_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [c_char; __PTHREAD_ONCE_SIZE__], + } + + pub struct pthread_rwlock_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_RWLOCK_SIZE__], + } + + pub struct pthread_rwlockattr_t { + pub(crate) __sig: c_long, + pub(crate) __opaque: [u8; __PTHREAD_RWLOCKATTR_SIZE__], + } +} + +pub type pthread_key_t = c_ulong; + +pub use crate::pthread_t; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/sys/mod.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/mod.rs new file mode 100644 index 00000000000000..da0a229547cb20 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/mod.rs @@ -0,0 +1,14 @@ +//! Directory: `sys/` +//! +//! + +/// Directory: `sys/_pthread/` +/// +/// +pub(crate) mod _pthread { + // We don't have the `_pthread_attr_t` and similar modules to match `_pthread_attr_t.h`, + // everything is defined in `_pthread_types`. + pub(crate) mod _pthread_types; +} + +pub(crate) mod qos; diff --git a/deps/crates/vendor/libc/src/new/apple/libpthread/sys/qos.rs b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/qos.rs new file mode 100644 index 00000000000000..9d9a2eb3dfcb99 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/libpthread/sys/qos.rs @@ -0,0 +1,22 @@ +//! Header: `sys/qos.h` +//! +//! + +use crate::prelude::*; + +#[derive(Debug)] +#[repr(u32)] +pub enum qos_class_t { + QOS_CLASS_USER_INTERACTIVE = 0x21, + QOS_CLASS_USER_INITIATED = 0x19, + QOS_CLASS_DEFAULT = 0x15, + QOS_CLASS_UTILITY = 0x11, + QOS_CLASS_BACKGROUND = 0x09, + QOS_CLASS_UNSPECIFIED = 0x00, +} +impl Copy for qos_class_t {} +impl Clone for qos_class_t { + fn clone(&self) -> qos_class_t { + *self + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/mod.rs b/deps/crates/vendor/libc/src/new/apple/mod.rs new file mode 100644 index 00000000000000..beb8caab63c205 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/mod.rs @@ -0,0 +1,20 @@ +//! Apple interfaces. +//! +//! The Xcode SDK includes interfaces that are split across a couple of different libraries. Most +//! of these are available at . + +/// Entrypoint for Apple headers, usually found as part of the Xcode SDK. +/// +/// +mod libc { + pub(crate) mod signal; + pub(crate) mod unistd; +} + +mod libpthread; +mod xnu; + +pub(crate) use libc::*; +pub(crate) use libpthread::pthread_; +pub(crate) use pthread_::pthread; +pub(crate) use xnu::*; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/arm/_mcontext.rs b/deps/crates/vendor/libc/src/new/apple/xnu/arm/_mcontext.rs new file mode 100644 index 00000000000000..ae22f7a4ec7773 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/arm/_mcontext.rs @@ -0,0 +1,15 @@ +//! Header: `arm/_mcontext.h` +//! +//! + +pub use crate::mach::machine::_structs::*; + +s! { + pub struct __darwin_mcontext64 { + pub __es: __darwin_arm_exception_state64, + pub __ss: __darwin_arm_thread_state64, + pub __ns: __darwin_arm_neon_state64, + } +} + +pub type mcontext_t = *mut __darwin_mcontext64; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/i386/_mcontext.rs b/deps/crates/vendor/libc/src/new/apple/xnu/i386/_mcontext.rs new file mode 100644 index 00000000000000..2b07ad1bf6e648 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/i386/_mcontext.rs @@ -0,0 +1,15 @@ +//! Header: `i386/_mcontext.h` +//! +//! + +pub use crate::mach::machine::_structs::*; + +s! { + pub struct __darwin_mcontext64 { + pub __es: __darwin_x86_exception_state64, + pub __ss: __darwin_x86_thread_state64, + pub __fs: __darwin_x86_float_state64, + } +} + +pub type mcontext_t = *mut __darwin_mcontext64; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/mach/arm/_structs.rs b/deps/crates/vendor/libc/src/new/apple/xnu/mach/arm/_structs.rs new file mode 100644 index 00000000000000..6160e773fd33b9 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/mach/arm/_structs.rs @@ -0,0 +1,37 @@ +//! Header: `arm/_structs.h` +//! +//! + +#[cfg(target_arch = "arm")] +use crate::prelude::*; + +s! { + pub struct __darwin_arm_exception_state64 { + pub __far: u64, + pub __esr: u32, + pub __exception: u32, + } + + pub struct __darwin_arm_thread_state64 { + pub __x: [u64; 29], + pub __fp: u64, + pub __lr: u64, + pub __sp: u64, + pub __pc: u64, + pub __cpsr: u32, + pub __pad: u32, + } + + #[cfg(target_arch = "aarch64")] + pub struct __darwin_arm_neon_state64 { + pub __v: [u128; 32], + pub __fpsr: u32, + pub __fpcr: u32, + } + + #[cfg(target_arch = "arm")] + #[repr(align(16))] + pub struct __darwin_arm_neon_state64 { + opaque: [c_char; (32 * 16) + (2 * size_of::())], + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/mach/i386/_structs.rs b/deps/crates/vendor/libc/src/new/apple/xnu/mach/i386/_structs.rs new file mode 100644 index 00000000000000..15822f7710de81 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/mach/i386/_structs.rs @@ -0,0 +1,92 @@ +//! Header: `i386/_structs.h` +//! +//! + +use crate::prelude::*; + +s! { + pub struct __darwin_mmst_reg { + pub __mmst_reg: [c_char; 10], + pub __mmst_rsrv: [c_char; 6], + } + + pub struct __darwin_xmm_reg { + pub __xmm_reg: [c_char; 16], + } + + pub struct __darwin_x86_thread_state64 { + pub __rax: u64, + pub __rbx: u64, + pub __rcx: u64, + pub __rdx: u64, + pub __rdi: u64, + pub __rsi: u64, + pub __rbp: u64, + pub __rsp: u64, + pub __r8: u64, + pub __r9: u64, + pub __r10: u64, + pub __r11: u64, + pub __r12: u64, + pub __r13: u64, + pub __r14: u64, + pub __r15: u64, + pub __rip: u64, + pub __rflags: u64, + pub __cs: u64, + pub __fs: u64, + pub __gs: u64, + } + + pub struct __darwin_x86_exception_state64 { + pub __trapno: u16, + pub __cpu: u16, + pub __err: u32, + pub __faultvaddr: u64, + } + + pub struct __darwin_x86_float_state64 { + pub __fpu_reserved: [c_int; 2], + __fpu_fcw: c_short, + __fpu_fsw: c_short, + pub __fpu_ftw: u8, + pub __fpu_rsrv1: u8, + pub __fpu_fop: u16, + pub __fpu_ip: u32, + pub __fpu_cs: u16, + pub __fpu_rsrv2: u16, + pub __fpu_dp: u32, + pub __fpu_ds: u16, + pub __fpu_rsrv3: u16, + pub __fpu_mxcsr: u32, + pub __fpu_mxcsrmask: u32, + pub __fpu_stmm0: __darwin_mmst_reg, + pub __fpu_stmm1: __darwin_mmst_reg, + pub __fpu_stmm2: __darwin_mmst_reg, + pub __fpu_stmm3: __darwin_mmst_reg, + pub __fpu_stmm4: __darwin_mmst_reg, + pub __fpu_stmm5: __darwin_mmst_reg, + pub __fpu_stmm6: __darwin_mmst_reg, + pub __fpu_stmm7: __darwin_mmst_reg, + pub __fpu_xmm0: __darwin_xmm_reg, + pub __fpu_xmm1: __darwin_xmm_reg, + pub __fpu_xmm2: __darwin_xmm_reg, + pub __fpu_xmm3: __darwin_xmm_reg, + pub __fpu_xmm4: __darwin_xmm_reg, + pub __fpu_xmm5: __darwin_xmm_reg, + pub __fpu_xmm6: __darwin_xmm_reg, + pub __fpu_xmm7: __darwin_xmm_reg, + pub __fpu_xmm8: __darwin_xmm_reg, + pub __fpu_xmm9: __darwin_xmm_reg, + pub __fpu_xmm10: __darwin_xmm_reg, + pub __fpu_xmm11: __darwin_xmm_reg, + pub __fpu_xmm12: __darwin_xmm_reg, + pub __fpu_xmm13: __darwin_xmm_reg, + pub __fpu_xmm14: __darwin_xmm_reg, + pub __fpu_xmm15: __darwin_xmm_reg, + // FIXME(apple): this field is actually [u8; 96], but defining it with a bigger type allows + // us to auto-implement traits for it since the length of the array is less than 32 + __fpu_rsrv4: [u32; 24], + pub __fpu_reserved1: c_int, + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/mach/machine/_structs.rs b/deps/crates/vendor/libc/src/new/apple/xnu/mach/machine/_structs.rs new file mode 100644 index 00000000000000..6acae8d9acbd76 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/mach/machine/_structs.rs @@ -0,0 +1,13 @@ +//! Header: `mach/machine/_structs.h` +//! +//! + +cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + pub use crate::mach::i386::_structs::*; + } else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { + pub use crate::mach::arm::_structs::*; + } else { + // Unsupported arch + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/mach/mod.rs b/deps/crates/vendor/libc/src/new/apple/xnu/mach/mod.rs new file mode 100644 index 00000000000000..90751260a7a7c3 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/mach/mod.rs @@ -0,0 +1,20 @@ +//! Directory: `mach/` +//! +//! + +/// Directory: `mach/arm` +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +pub(crate) mod arm { + pub(crate) mod _structs; +} + +/// Directory: `mach/i386` +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub(crate) mod i386 { + pub(crate) mod _structs; +} + +/// Directory: `mach/machine` +pub(crate) mod machine { + pub(crate) mod _structs; +} diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/machine/_mcontext.rs b/deps/crates/vendor/libc/src/new/apple/xnu/machine/_mcontext.rs new file mode 100644 index 00000000000000..004b94707e33ad --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/machine/_mcontext.rs @@ -0,0 +1,11 @@ +//! Header: `machine/_mcontext.h` + +cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + pub use crate::i386::_mcontext::*; + } else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { + pub use crate::arm::_mcontext::*; + } else { + // Unsupported arch + } +} diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/mod.rs b/deps/crates/vendor/libc/src/new/apple/xnu/mod.rs new file mode 100644 index 00000000000000..8b8afb6bc39d33 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/mod.rs @@ -0,0 +1,30 @@ +//! Source from XNU +//! +//! We omit nesting for the `bsd` module since most items of interest are in there. + +/// Directory: `arm/` +/// +/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/arm +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +pub(crate) mod arm { + pub(crate) mod _mcontext; +} + +/// Directory: `i386/` +/// +/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/i386 +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub(crate) mod i386 { + pub(crate) mod _mcontext; +} + +pub(crate) mod mach; + +/// Directory: `machine/` +/// +/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/machine +pub(crate) mod machine { + pub(crate) mod _mcontext; +} + +pub(crate) mod sys; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/sys/_types/_ucontext.rs b/deps/crates/vendor/libc/src/new/apple/xnu/sys/_types/_ucontext.rs new file mode 100644 index 00000000000000..53bc0f22d6691c --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/sys/_types/_ucontext.rs @@ -0,0 +1,17 @@ +//! Header: `sys/_types/_ucontext.h` + +pub use crate::machine::_mcontext::*; +use crate::prelude::*; + +s! { + pub struct __darwin_ucontext { + pub uc_onstack: c_int, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: crate::stack_t, + pub uc_link: *mut ucontext_t, + pub uc_mcsize: usize, + pub uc_mcontext: mcontext_t, + } +} + +pub type ucontext_t = __darwin_ucontext; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/sys/mod.rs b/deps/crates/vendor/libc/src/new/apple/xnu/sys/mod.rs new file mode 100644 index 00000000000000..ad4a204898cb8f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/sys/mod.rs @@ -0,0 +1,15 @@ +//! Directory: `sys/` +//! +//! + +pub(crate) mod signal; + +/// Directory: `sys/_types` +/// +/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/sys/_types +pub(crate) mod _types { + pub(crate) mod _ucontext; +} + +// Bit of a hack since the directories get merged and we can't have >1 sys module. +pub(crate) use crate::new::apple::libpthread::sys::*; diff --git a/deps/crates/vendor/libc/src/new/apple/xnu/sys/signal.rs b/deps/crates/vendor/libc/src/new/apple/xnu/sys/signal.rs new file mode 100644 index 00000000000000..844793e119b317 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/apple/xnu/sys/signal.rs @@ -0,0 +1,6 @@ +//! Header: `sys/signal.h` +//! +//! + +pub use crate::machine::_mcontext::*; +pub use crate::sys::_types::_ucontext::*; diff --git a/deps/crates/vendor/libc/src/new/bionic_libc/mod.rs b/deps/crates/vendor/libc/src/new/bionic_libc/mod.rs new file mode 100644 index 00000000000000..1dd186e4f940f6 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/bionic_libc/mod.rs @@ -0,0 +1,7 @@ +//! This directory maps to `bionic/libc/include` in the Android source. +//! +//! + +pub(crate) mod pthread; +pub(crate) mod sys; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/bionic_libc/pthread.rs b/deps/crates/vendor/libc/src/new/bionic_libc/pthread.rs new file mode 100644 index 00000000000000..4997547ff09058 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/bionic_libc/pthread.rs @@ -0,0 +1,42 @@ +//! Header: `unistd.h` + +pub use crate::new::common::linux_like::pthread::{ + pthread_getattr_np, + pthread_setname_np, +}; +pub use crate::new::common::posix::pthread::{ + pthread_atfork, + pthread_attr_getguardsize, + pthread_attr_getinheritsched, + pthread_attr_getstack, + pthread_attr_setguardsize, + pthread_attr_setinheritsched, + pthread_attr_setstack, + pthread_barrier_destroy, + pthread_barrier_init, + pthread_barrier_wait, + pthread_barrierattr_destroy, + pthread_barrierattr_getpshared, + pthread_barrierattr_init, + pthread_barrierattr_setpshared, + pthread_condattr_getclock, + pthread_condattr_getpshared, + pthread_condattr_setclock, + pthread_condattr_setpshared, + pthread_create, + pthread_getcpuclockid, + pthread_getschedparam, + pthread_kill, + pthread_mutex_timedlock, + pthread_mutexattr_getpshared, + pthread_mutexattr_setpshared, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, + pthread_setschedparam, + pthread_sigmask, + pthread_spin_destroy, + pthread_spin_init, + pthread_spin_lock, + pthread_spin_trylock, + pthread_spin_unlock, +}; diff --git a/deps/crates/vendor/libc/src/new/bionic_libc/sys/mod.rs b/deps/crates/vendor/libc/src/new/bionic_libc/sys/mod.rs new file mode 100644 index 00000000000000..a882cbd99fca1c --- /dev/null +++ b/deps/crates/vendor/libc/src/new/bionic_libc/sys/mod.rs @@ -0,0 +1,3 @@ +//! Directory: `sys/` + +pub(crate) mod socket; diff --git a/deps/crates/vendor/libc/src/new/bionic_libc/sys/socket.rs b/deps/crates/vendor/libc/src/new/bionic_libc/sys/socket.rs new file mode 100644 index 00000000000000..c4a4e781275d98 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/bionic_libc/sys/socket.rs @@ -0,0 +1,51 @@ +//! Header: `sys/socket.h` + +use crate::prelude::*; + +s! { + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: size_t, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct ucred { + pub pid: crate::pid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } +} + +extern "C" { + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sendmmsg( + sockfd: c_int, + msgvec: *const crate::mmsghdr, + vlen: c_uint, + flags: c_int, + ) -> c_int; + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; +} diff --git a/deps/crates/vendor/libc/src/new/bionic_libc/unistd.rs b/deps/crates/vendor/libc/src/new/bionic_libc/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/bionic_libc/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/common/bsd.rs b/deps/crates/vendor/libc/src/new/common/bsd.rs new file mode 100644 index 00000000000000..818daf93489c9b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/bsd.rs @@ -0,0 +1 @@ +//! Interfaces common across the BSD family. diff --git a/deps/crates/vendor/libc/src/new/common/freebsd_like.rs b/deps/crates/vendor/libc/src/new/common/freebsd_like.rs new file mode 100644 index 00000000000000..f49f2c9c2c06e2 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/freebsd_like.rs @@ -0,0 +1 @@ +//! Interfaces common in FreeBSD-derived operating systems. This includes FreeBSD and DragonFlyBSD. diff --git a/deps/crates/vendor/libc/src/new/common/linux_like/mod.rs b/deps/crates/vendor/libc/src/new/common/linux_like/mod.rs new file mode 100644 index 00000000000000..9c41fe256ceffb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/linux_like/mod.rs @@ -0,0 +1,9 @@ +//! API that primarily comes from Linux but is also used other platforms (e.g. Android). + +#[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "l4re", + target_os = "linux" +))] +pub(crate) mod pthread; diff --git a/deps/crates/vendor/libc/src/new/common/linux_like/pthread.rs b/deps/crates/vendor/libc/src/new/common/linux_like/pthread.rs new file mode 100644 index 00000000000000..b54d385f9c05f7 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/linux_like/pthread.rs @@ -0,0 +1,25 @@ +use crate::prelude::*; + +extern "C" { + #[cfg(any(target_os = "linux", target_os = "l4re"))] + pub fn pthread_getaffinity_np( + thread: crate::pthread_t, + cpusetsize: size_t, + cpuset: *mut crate::cpu_set_t, + ) -> c_int; + + pub fn pthread_getattr_np(native: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + + #[cfg(target_os = "linux")] + pub fn pthread_getname_np(thread: crate::pthread_t, name: *mut c_char, len: size_t) -> c_int; + + #[cfg(any(target_os = "linux", target_os = "l4re"))] + pub fn pthread_setaffinity_np( + thread: crate::pthread_t, + cpusetsize: size_t, + cpuset: *const crate::cpu_set_t, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn pthread_setname_np(thread: crate::pthread_t, name: *const c_char) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/common/mod.rs b/deps/crates/vendor/libc/src/new/common/mod.rs new file mode 100644 index 00000000000000..acb18917c8998b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/mod.rs @@ -0,0 +1,39 @@ +//! Interfaces that are common across multiple platforms +//! +//! We make these available everywhere but each platform must opt in to reexporting. +//! +//! There shouldn't be any repeated definitions or complex configuration in this module. On +//! platforms that don't use common APIs it is fine to use `#[cfg(not(...))]`, but if a platform +//! needs a custom definition then it should be defined in the platform-specific module. +//! +//! The goal is that platforms need to opt in to the definitions here, so that worst case we have +//! an unused warning on untested platforms (rather than exposing incorrect API). + +#[cfg(any( + target_vendor = "apple", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", +))] +pub(crate) mod bsd; + +#[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "l4re", + target_os = "linux", +))] +pub(crate) mod linux_like; + +#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] +pub(crate) mod freebsd_like; + +#[cfg(any(target_os = "netbsd", target_os = "openbsd"))] +pub(crate) mod netbsd_like; + +#[cfg(any(target_os = "illumos", target_os = "solaris"))] +pub(crate) mod solarish; + +#[cfg(target_family = "unix")] +pub(crate) mod posix; diff --git a/deps/crates/vendor/libc/src/new/common/netbsd_like.rs b/deps/crates/vendor/libc/src/new/common/netbsd_like.rs new file mode 100644 index 00000000000000..4267357ac90463 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/netbsd_like.rs @@ -0,0 +1 @@ +//! Interfaces common in NetBSD-derived operating systems. This includes NetBSD and OpenBSD. diff --git a/deps/crates/vendor/libc/src/new/common/posix/mod.rs b/deps/crates/vendor/libc/src/new/common/posix/mod.rs new file mode 100644 index 00000000000000..44ae64a980222b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/posix/mod.rs @@ -0,0 +1,15 @@ +//! POSIX APIs that are used by a number of platforms +//! +//! These can be found at: . + +// FIXME(pthread): eventually all platforms should use this module +#[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "l4re", + target_os = "linux", + target_os = "qurt", + target_vendor = "apple", +))] +pub(crate) mod pthread; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/common/posix/pthread.rs b/deps/crates/vendor/libc/src/new/common/posix/pthread.rs new file mode 100644 index 00000000000000..17d390669a4102 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/posix/pthread.rs @@ -0,0 +1,322 @@ +//! Header: `pthread.h` +//! +//! + +use crate::prelude::*; + +extern "C" { + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple", + ))] + pub fn pthread_attr_getinheritsched( + attr: *const crate::pthread_attr_t, + inheritsched: *mut c_int, + ) -> c_int; + + #[cfg(any(target_os = "l4re", target_os = "linux", target_vendor = "apple"))] + pub fn pthread_attr_getschedparam( + attr: *const crate::pthread_attr_t, + param: *mut crate::sched_param, + ) -> c_int; + + #[cfg(any(target_os = "l4re", target_os = "linux", target_vendor = "apple"))] + pub fn pthread_attr_getschedpolicy( + attr: *const crate::pthread_attr_t, + policy: *mut c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re" + ))] + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple" + ))] + pub fn pthread_attr_setinheritsched( + attr: *mut crate::pthread_attr_t, + inheritsched: c_int, + ) -> c_int; + + #[cfg(any(target_os = "l4re", target_os = "linux", target_vendor = "apple"))] + pub fn pthread_attr_setschedparam( + attr: *mut crate::pthread_attr_t, + param: *const crate::sched_param, + ) -> c_int; + + #[cfg(any(target_os = "l4re", target_os = "linux", target_vendor = "apple"))] + pub fn pthread_attr_setschedpolicy(attr: *mut crate::pthread_attr_t, policy: c_int) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re" + ))] + pub fn pthread_attr_setstack( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + stacksize: size_t, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrier_destroy(barrier: *mut crate::pthread_barrier_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrier_init( + barrier: *mut crate::pthread_barrier_t, + attr: *const crate::pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrier_wait(barrier: *mut crate::pthread_barrier_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrierattr_destroy(attr: *mut crate::pthread_barrierattr_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn pthread_barrierattr_getpshared( + attr: *const crate::pthread_barrierattr_t, + shared: *mut c_int, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrierattr_init(attr: *mut crate::pthread_barrierattr_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_barrierattr_setpshared( + attr: *mut crate::pthread_barrierattr_t, + shared: c_int, + ) -> c_int; + + #[cfg(any(target_os = "l4re", all(target_os = "linux", not(target_env = "ohos"))))] + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + pub fn pthread_condattr_getclock( + attr: *const crate::pthread_condattr_t, + clock_id: *mut crate::clockid_t, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple", + ))] + pub fn pthread_condattr_getpshared( + attr: *const crate::pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + pub fn pthread_condattr_setclock( + attr: *mut crate::pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re", + target_vendor = "apple", + ))] + pub fn pthread_condattr_setpshared( + attr: *mut crate::pthread_condattr_t, + pshared: c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "l4re", + target_os = "linux", + ))] + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn pthread_getcpuclockid(thread: crate::pthread_t, clk_id: *mut crate::clockid_t) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple", + ))] + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + + // FIXME(reorg): In recent POSIX versions, this is a signal.h function and not required + // in pthread. + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] + pub fn pthread_mutex_consistent(mutex: *mut crate::pthread_mutex_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + #[cfg_attr(gnu_time_bits64, link_name = "__pthread_mutex_timedlock64")] + #[cfg_attr(musl_redir_time64, link_name = "__pthread_mutex_timedlock_time64")] + pub fn pthread_mutex_timedlock( + lock: *mut crate::pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + + #[cfg(target_os = "linux")] + pub fn pthread_mutexattr_getprotocol( + attr: *const crate::pthread_mutexattr_t, + protocol: *mut c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple", + ))] + pub fn pthread_mutexattr_getpshared( + attr: *const crate::pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] + pub fn pthread_mutexattr_getrobust( + attr: *const crate::pthread_mutexattr_t, + robustness: *mut c_int, + ) -> c_int; + + #[cfg(target_os = "linux")] + pub fn pthread_mutexattr_setprotocol( + attr: *mut crate::pthread_mutexattr_t, + protocol: c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re", + target_vendor = "apple", + ))] + pub fn pthread_mutexattr_setpshared( + attr: *mut crate::pthread_mutexattr_t, + pshared: c_int, + ) -> c_int; + + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] + pub fn pthread_mutexattr_setrobust( + attr: *mut crate::pthread_mutexattr_t, + robustness: c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re", + target_vendor = "apple", + ))] + pub fn pthread_rwlockattr_getpshared( + attr: *const crate::pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "l4re", + target_vendor = "apple", + ))] + pub fn pthread_rwlockattr_setpshared( + attr: *mut crate::pthread_rwlockattr_t, + val: c_int, + ) -> c_int; + + // FIXME(1.0): These shoul be combined to the version that takes an optional unsafe function. + #[cfg(any(target_os = "l4re", target_os = "linux"))] + pub fn pthread_once(control: *mut crate::pthread_once_t, routine: extern "C" fn()) -> c_int; + #[cfg(target_vendor = "apple")] + pub fn pthread_once( + once_control: *mut crate::pthread_once_t, + init_routine: Option, + ) -> c_int; + + #[cfg(any( + target_os = "android", + target_os = "l4re", + target_os = "linux", + target_vendor = "apple", + ))] + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + #[cfg(target_os = "linux")] + pub fn pthread_setschedprio(native: crate::pthread_t, priority: c_int) -> c_int; + + // FIXME(reorg): In recent POSIX versions, this is a signal.h function and not required + // in pthread. + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_sigmask( + how: c_int, + set: *const crate::sigset_t, + oldset: *mut crate::sigset_t, + ) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_spin_destroy(lock: *mut crate::pthread_spinlock_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_spin_init(lock: *mut crate::pthread_spinlock_t, pshared: c_int) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_spin_lock(lock: *mut crate::pthread_spinlock_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_spin_trylock(lock: *mut crate::pthread_spinlock_t) -> c_int; + + #[cfg(any(target_os = "android", target_os = "l4re", target_os = "linux"))] + pub fn pthread_spin_unlock(lock: *mut crate::pthread_spinlock_t) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/common/posix/unistd.rs b/deps/crates/vendor/libc/src/new/common/posix/unistd.rs new file mode 100644 index 00000000000000..0c02cbaa699f47 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/posix/unistd.rs @@ -0,0 +1,9 @@ +//! Header: `unistd.h` +//! +//! + +use crate::prelude::*; + +pub const STDIN_FILENO: c_int = 0; +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; diff --git a/deps/crates/vendor/libc/src/new/common/solarish.rs b/deps/crates/vendor/libc/src/new/common/solarish.rs new file mode 100644 index 00000000000000..f966114e370ae6 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/common/solarish.rs @@ -0,0 +1 @@ +//! Interfaces common in solaris-derived operating systems. This includes Solaris and Illumos. diff --git a/deps/crates/vendor/libc/src/new/cygwin/mod.rs b/deps/crates/vendor/libc/src/new/cygwin/mod.rs new file mode 100644 index 00000000000000..356ae587653dfb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/cygwin/mod.rs @@ -0,0 +1,5 @@ +//! Cygwin libc. +//! +//! * Headers: + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/cygwin/unistd.rs b/deps/crates/vendor/libc/src/new/cygwin/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/cygwin/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/dragonfly/mod.rs b/deps/crates/vendor/libc/src/new/dragonfly/mod.rs new file mode 100644 index 00000000000000..4a1b2c4998d07b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/dragonfly/mod.rs @@ -0,0 +1,6 @@ +//! DragonFly BSD libc. +//! +//! * Headers: +//! * Manual pages: + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/dragonfly/unistd.rs b/deps/crates/vendor/libc/src/new/dragonfly/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/dragonfly/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/emscripten/mod.rs b/deps/crates/vendor/libc/src/new/emscripten/mod.rs new file mode 100644 index 00000000000000..9b74464059bb19 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/emscripten/mod.rs @@ -0,0 +1,7 @@ +//! Emscripten libc. +//! +//! * Headers: + +pub(crate) mod pthread; +pub(crate) mod sched; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/emscripten/pthread.rs b/deps/crates/vendor/libc/src/new/emscripten/pthread.rs new file mode 100644 index 00000000000000..21982b7979d43d --- /dev/null +++ b/deps/crates/vendor/libc/src/new/emscripten/pthread.rs @@ -0,0 +1,14 @@ +//! Header: `pthread.h` + +pub use crate::new::common::linux_like::pthread::pthread_getattr_np; +pub use crate::new::common::posix::pthread::{ + pthread_attr_getstack, + pthread_attr_setstack, + pthread_condattr_getclock, + pthread_condattr_setclock, + pthread_condattr_setpshared, + pthread_create, + pthread_mutexattr_setpshared, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, +}; diff --git a/deps/crates/vendor/libc/src/new/emscripten/sched.rs b/deps/crates/vendor/libc/src/new/emscripten/sched.rs new file mode 100644 index 00000000000000..3bf854ef33c29f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/emscripten/sched.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; + +cfg_if! { + if #[cfg(musl_v1_2_3)] { + s! { + struct __c_anon_sched_param__reserved2 { + __reserved1: crate::time_t, + __reserved2: c_long, + } + + pub struct sched_param { + pub sched_priority: c_int, + + __reserved1: Padding, + #[cfg(musl32_time64)] + __reserved2: Padding<[c_long; 4]>, + #[cfg(not(musl32_time64))] + __reserved2: Padding<[__c_anon_sched_param__reserved2; 2]>, + __reserved3: Padding, + } + } + } else { + s! { + pub struct sched_param { + pub sched_priority: c_int, + + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_low_priority: c_int, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_repl_period: crate::timespec, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_init_budget: crate::timespec, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_max_repl: c_int, + } + } + } +} diff --git a/deps/crates/vendor/libc/src/new/emscripten/unistd.rs b/deps/crates/vendor/libc/src/new/emscripten/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/emscripten/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/espidf/mod.rs b/deps/crates/vendor/libc/src/new/espidf/mod.rs new file mode 100644 index 00000000000000..061ea6e64614b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/espidf/mod.rs @@ -0,0 +1,2 @@ +//! Expressif libc. +// FIXME(espidf): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/freebsd/mod.rs b/deps/crates/vendor/libc/src/new/freebsd/mod.rs new file mode 100644 index 00000000000000..eedf235d1e2359 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/freebsd/mod.rs @@ -0,0 +1,7 @@ +//! FreeBSD libc. +//! +//! * Headers: +//! * Symbol map: + +pub(crate) mod sys; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/freebsd/sys/file.rs b/deps/crates/vendor/libc/src/new/freebsd/sys/file.rs new file mode 100644 index 00000000000000..3072c1de7d7630 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/freebsd/sys/file.rs @@ -0,0 +1,46 @@ +//! Header: `sys/file.h` +//! +//! https://github.com/freebsd/freebsd-src/blob/main/sys/sys/file.h + +use crate::prelude::*; + +pub const DTYPE_NONE: c_int = 0; +pub const DTYPE_VNODE: c_int = 1; +pub const DTYPE_SOCKET: c_int = 2; +pub const DTYPE_PIPE: c_int = 3; +pub const DTYPE_FIFO: c_int = 4; +pub const DTYPE_KQUEUE: c_int = 5; +pub const DTYPE_CRYPTO: c_int = 6; +pub const DTYPE_MQUEUE: c_int = 7; +pub const DTYPE_SHM: c_int = 8; +pub const DTYPE_SEM: c_int = 9; +pub const DTYPE_PTS: c_int = 10; +pub const DTYPE_DEV: c_int = 11; +pub const DTYPE_PROCDESC: c_int = 12; +pub const DTYPE_EVENTFD: c_int = 13; +pub const DTYPE_TIMERFD: c_int = 14; +pub const DTYPE_INOTIFY: c_int = 15; +pub const DTYPE_JAILDESC: c_int = 16; + +s! { + #[cfg(not(any(freebsd10, freebsd11)))] + pub struct xfile { + pub xf_size: crate::ksize_t, + pub xf_pid: crate::pid_t, + pub xf_uid: crate::uid_t, + pub xf_fd: c_int, + _xf_int_pad1: Padding, + pub xf_file: crate::kvaddr_t, + pub xf_type: c_short, + _xf_short_pad1: Padding, + pub xf_count: c_int, + pub xf_msgcount: c_int, + _xf_int_pad2: Padding, + pub xf_offset: crate::off_t, + pub xf_data: crate::kvaddr_t, + pub xf_vnode: crate::kvaddr_t, + pub xf_flag: c_uint, + _xf_int_pad3: Padding, + _xf_int64_pad: Padding<[i64; 6]>, + } +} diff --git a/deps/crates/vendor/libc/src/new/freebsd/sys/mod.rs b/deps/crates/vendor/libc/src/new/freebsd/sys/mod.rs new file mode 100644 index 00000000000000..210e674072c59f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/freebsd/sys/mod.rs @@ -0,0 +1,5 @@ +//! Directory: `sys/` +//! +//! https://github.com/freebsd/freebsd-src/tree/main/sys/sys' + +pub(crate) mod file; diff --git a/deps/crates/vendor/libc/src/new/freebsd/unistd.rs b/deps/crates/vendor/libc/src/new/freebsd/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/freebsd/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/fuchsia/mod.rs b/deps/crates/vendor/libc/src/new/fuchsia/mod.rs new file mode 100644 index 00000000000000..b3a908349bf3b4 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/fuchsia/mod.rs @@ -0,0 +1,4 @@ +//! Fuschia libc. +// FIXME(fuchsia): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/fuchsia/unistd.rs b/deps/crates/vendor/libc/src/new/fuchsia/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/fuchsia/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/glibc/mod.rs b/deps/crates/vendor/libc/src/new/glibc/mod.rs new file mode 100644 index 00000000000000..71d979b17ecc43 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/mod.rs @@ -0,0 +1,31 @@ +//! GNU libc. +//! +//! * Headers: (official) +//! * Headers: (mirror) +//! +//! This module structure is modeled after glibc's source tree. Its build system selects headers +//! from different locations based on the platform, which we mimic here with reexports. + +/// Source directory: `posix/` +/// +/// +mod posix { + pub(crate) mod unistd; +} + +/// Source directory: `sysdeps/` +/// +/// +mod sysdeps { + // FIXME(pthread): eventually all platforms should use this module + #[cfg(target_os = "linux")] + pub(crate) mod nptl; + pub(crate) mod unix; +} + +pub(crate) use posix::*; +// FIXME(pthread): eventually all platforms should use this module +#[cfg(target_os = "linux")] +pub(crate) use sysdeps::nptl::*; +#[cfg(target_os = "linux")] +pub(crate) use sysdeps::unix::linux::*; diff --git a/deps/crates/vendor/libc/src/new/glibc/posix/unistd.rs b/deps/crates/vendor/libc/src/new/glibc/posix/unistd.rs new file mode 100644 index 00000000000000..907066c458df28 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/posix/unistd.rs @@ -0,0 +1,9 @@ +//! Header: `unistd.h` +//! +//! + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/mod.rs b/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/mod.rs new file mode 100644 index 00000000000000..18e82e48b80a73 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/mod.rs @@ -0,0 +1,7 @@ +//! Source directory: `sysdeps/nptl/`o +//! +//! Native POSIX threading library. +//! +//! + +pub(crate) mod pthread; diff --git a/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/pthread.rs b/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/pthread.rs new file mode 100644 index 00000000000000..27b17285b53baf --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/sysdeps/nptl/pthread.rs @@ -0,0 +1,59 @@ +//! Source header: `sysdeps/nptl/pthread.h` +//! +//! + +pub use crate::new::common::linux_like::pthread::{ + pthread_getaffinity_np, + pthread_getattr_np, + pthread_getname_np, + pthread_setaffinity_np, + pthread_setname_np, +}; +pub use crate::new::common::posix::pthread::{ + pthread_atfork, + pthread_attr_getguardsize, + pthread_attr_getinheritsched, + pthread_attr_getschedparam, + pthread_attr_getschedpolicy, + pthread_attr_getstack, + pthread_attr_setguardsize, + pthread_attr_setinheritsched, + pthread_attr_setschedparam, + pthread_attr_setschedpolicy, + pthread_attr_setstack, + pthread_barrier_destroy, + pthread_barrier_init, + pthread_barrier_wait, + pthread_barrierattr_destroy, + pthread_barrierattr_getpshared, + pthread_barrierattr_init, + pthread_barrierattr_setpshared, + pthread_cancel, + pthread_condattr_getclock, + pthread_condattr_getpshared, + pthread_condattr_setclock, + pthread_condattr_setpshared, + pthread_create, + pthread_getcpuclockid, + pthread_getschedparam, + pthread_kill, + pthread_mutex_consistent, + pthread_mutex_timedlock, + pthread_mutexattr_getprotocol, + pthread_mutexattr_getpshared, + pthread_mutexattr_getrobust, + pthread_mutexattr_setprotocol, + pthread_mutexattr_setpshared, + pthread_mutexattr_setrobust, + pthread_once, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, + pthread_setschedparam, + pthread_setschedprio, + pthread_sigmask, + pthread_spin_destroy, + pthread_spin_init, + pthread_spin_lock, + pthread_spin_trylock, + pthread_spin_unlock, +}; diff --git a/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/mod.rs b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/mod.rs new file mode 100644 index 00000000000000..0ecee596c5b12d --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/mod.rs @@ -0,0 +1,10 @@ +//! Source directory: `sysdeps/unix/sysv/linux` (the `sysv` is flattened). +//! +//! + +/// Directory: `net/` +/// +/// Source directory: `sysdeps/unix/sysv/linux/net` +pub(crate) mod net { + pub(crate) mod route; +} diff --git a/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/net/route.rs b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/net/route.rs new file mode 100644 index 00000000000000..2851451652df0b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/linux/net/route.rs @@ -0,0 +1,30 @@ +//! Header: `net/route.h` +//! +//! Source header: `sysdeps/unix/sysv/linux/net/route.h` +//! + +use crate::prelude::*; + +s! { + pub struct rtentry { + pub rt_pad1: c_ulong, + pub rt_dst: crate::sockaddr, + pub rt_gateway: crate::sockaddr, + pub rt_genmask: crate::sockaddr, + pub rt_flags: c_ushort, + pub rt_pad2: c_short, + pub rt_pad3: c_ulong, + pub rt_tos: c_uchar, + pub rt_class: c_uchar, + // FIXME(1.0): private padding fields + #[cfg(target_pointer_width = "64")] + pub rt_pad4: [c_short; 3usize], + #[cfg(not(target_pointer_width = "64"))] + pub rt_pad4: c_short, + pub rt_metric: c_short, + pub rt_dev: *mut c_char, + pub rt_mtu: c_ulong, + pub rt_window: c_ulong, + pub rt_irtt: c_ushort, + } +} diff --git a/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/mod.rs b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/mod.rs new file mode 100644 index 00000000000000..55a895d4d0de2e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/glibc/sysdeps/unix/mod.rs @@ -0,0 +1,6 @@ +//! Source directory: `sysdeps/unix/` +//! +//! + +#[cfg(target_os = "linux")] +pub(crate) mod linux; diff --git a/deps/crates/vendor/libc/src/new/haiku/mod.rs b/deps/crates/vendor/libc/src/new/haiku/mod.rs new file mode 100644 index 00000000000000..a565afe10d9ce0 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/haiku/mod.rs @@ -0,0 +1,4 @@ +//! Haiku OS libc. +// FIXME(haiku): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/haiku/unistd.rs b/deps/crates/vendor/libc/src/new/haiku/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/haiku/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/hermit_abi/mod.rs b/deps/crates/vendor/libc/src/new/hermit_abi/mod.rs new file mode 100644 index 00000000000000..65f59fe12d6913 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/hermit_abi/mod.rs @@ -0,0 +1,3 @@ +//! Hermit kernel libc. +//! +//! * Headers: diff --git a/deps/crates/vendor/libc/src/new/horizon/mod.rs b/deps/crates/vendor/libc/src/new/horizon/mod.rs new file mode 100644 index 00000000000000..338e9f0a4d8403 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/horizon/mod.rs @@ -0,0 +1,2 @@ +//! Switch libc. +// FIXME(horizon): link to headers or manpages needed. diff --git a/deps/crates/vendor/libc/src/new/hurd/mod.rs b/deps/crates/vendor/libc/src/new/hurd/mod.rs new file mode 100644 index 00000000000000..12198d58bd5827 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/hurd/mod.rs @@ -0,0 +1,2 @@ +//! GNU Hurd libc. +// FIXME(hurd): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/illumos/mod.rs b/deps/crates/vendor/libc/src/new/illumos/mod.rs new file mode 100644 index 00000000000000..83d15da8801f2e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/illumos/mod.rs @@ -0,0 +1,4 @@ +//! Illumos libc. +// FIXME(illumos): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/illumos/unistd.rs b/deps/crates/vendor/libc/src/new/illumos/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/illumos/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/l4re/mod.rs b/deps/crates/vendor/libc/src/new/l4re/mod.rs new file mode 100644 index 00000000000000..cbf725f406b6b8 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/l4re/mod.rs @@ -0,0 +1,3 @@ +//! L4re. +//! +//! * Headers: diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can.rs new file mode 100644 index 00000000000000..c4ae2da5843454 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can.rs @@ -0,0 +1,135 @@ +//! Header: `uapi/linux/can.h` + +pub(crate) mod bcm; +pub(crate) mod error; +pub(crate) mod j1939; +pub(crate) mod netlink; +pub(crate) mod raw; + +use crate::prelude::*; + +pub const CAN_EFF_FLAG: canid_t = 0x80000000; +pub const CAN_RTR_FLAG: canid_t = 0x40000000; +pub const CAN_ERR_FLAG: canid_t = 0x20000000; + +pub const CAN_SFF_MASK: canid_t = 0x000007FF; +pub const CAN_EFF_MASK: canid_t = 0x1FFFFFFF; +pub const CAN_ERR_MASK: canid_t = 0x1FFFFFFF; +pub const CANXL_PRIO_MASK: crate::canid_t = CAN_SFF_MASK; + +pub type canid_t = u32; + +pub const CAN_SFF_ID_BITS: c_int = 11; +pub const CAN_EFF_ID_BITS: c_int = 29; +pub const CANXL_PRIO_BITS: c_int = CAN_SFF_ID_BITS; + +pub type can_err_mask_t = u32; + +pub const CAN_MAX_DLC: c_int = 8; +pub const CAN_MAX_DLEN: usize = 8; + +pub const CANFD_MAX_DLC: c_int = 15; +pub const CANFD_MAX_DLEN: usize = 64; + +pub const CANXL_MIN_DLC: c_int = 0; +pub const CANXL_MAX_DLC: c_int = 2047; +pub const CANXL_MAX_DLC_MASK: c_int = 0x07FF; +pub const CANXL_MIN_DLEN: usize = 1; +pub const CANXL_MAX_DLEN: usize = 2048; + +s! { + #[repr(align(8))] + pub struct can_frame { + pub can_id: canid_t, + // FIXME(1.0): this field was renamed to `len` in Linux 5.11 + pub can_dlc: u8, + __pad: Padding, + __res0: u8, + pub len8_dlc: u8, + pub data: [u8; CAN_MAX_DLEN], + } +} + +pub const CANFD_BRS: c_int = 0x01; +pub const CANFD_ESI: c_int = 0x02; +pub const CANFD_FDF: c_int = 0x04; + +s! { + #[repr(align(8))] + pub struct canfd_frame { + pub can_id: canid_t, + pub len: u8, + pub flags: u8, + __res0: u8, + __res1: u8, + pub data: [u8; CANFD_MAX_DLEN], + } +} + +pub const CANXL_XLF: c_int = 0x80; +pub const CANXL_SEC: c_int = 0x01; + +s! { + pub struct canxl_frame { + pub prio: canid_t, + pub flags: u8, + pub sdt: u8, + pub len: u16, + pub af: u32, + pub data: [u8; CANXL_MAX_DLEN], + } +} + +pub const CAN_MTU: usize = size_of::(); +pub const CANFD_MTU: usize = size_of::(); +pub const CANXL_MTU: usize = size_of::(); +// FIXME(offset_of): use `core::mem::offset_of!` once that is available +// https://github.com/rust-lang/rfcs/pull/3308 +// pub const CANXL_HDR_SIZE: usize = core::mem::offset_of!(canxl_frame, data); +pub const CANXL_HDR_SIZE: usize = 12; +pub const CANXL_MIN_MTU: usize = CANXL_HDR_SIZE + 64; +pub const CANXL_MAX_MTU: usize = CANXL_MTU; + +pub const CAN_RAW: c_int = 1; +pub const CAN_BCM: c_int = 2; +pub const CAN_TP16: c_int = 3; +pub const CAN_TP20: c_int = 4; +pub const CAN_MCNET: c_int = 5; +pub const CAN_ISOTP: c_int = 6; +pub const CAN_J1939: c_int = 7; +pub const CAN_NPROTO: c_int = 8; + +pub const SOL_CAN_BASE: c_int = 100; + +s_no_extra_traits! { + pub struct sockaddr_can { + pub can_family: crate::sa_family_t, + pub can_ifindex: c_int, + pub can_addr: __c_anonymous_sockaddr_can_can_addr, + } + + pub union __c_anonymous_sockaddr_can_can_addr { + pub tp: __c_anonymous_sockaddr_can_tp, + pub j1939: __c_anonymous_sockaddr_can_j1939, + } +} + +s! { + pub struct __c_anonymous_sockaddr_can_tp { + pub rx_id: canid_t, + pub tx_id: canid_t, + } + + pub struct __c_anonymous_sockaddr_can_j1939 { + pub name: u64, + pub pgn: u32, + pub addr: u8, + } + + pub struct can_filter { + pub can_id: canid_t, + pub can_mask: canid_t, + } +} + +pub const CAN_INV_FILTER: canid_t = 0x20000000; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/bcm.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/bcm.rs new file mode 100644 index 00000000000000..853f85f0408803 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/bcm.rs @@ -0,0 +1,52 @@ +//! Header: `linux/can/bcm.h` + +pub use crate::linux::can::*; + +s! { + pub struct bcm_timeval { + pub tv_sec: c_long, + pub tv_usec: c_long, + } + + pub struct bcm_msg_head { + pub opcode: u32, + pub flags: u32, + pub count: u32, + pub ival1: bcm_timeval, + pub ival2: bcm_timeval, + pub can_id: canid_t, + pub nframes: u32, + pub frames: [can_frame; 0], + } +} + +c_enum! { + #[repr(u32)] + pub enum #anon { + pub TX_SETUP = 1, + pub TX_DELETE, + pub TX_READ, + pub TX_SEND, + pub RX_SETUP, + pub RX_DELETE, + pub RX_READ, + pub TX_STATUS, + pub TX_EXPIRED, + pub RX_STATUS, + pub RX_TIMEOUT, + pub RX_CHANGED, + } +} + +pub const SETTIMER: u32 = 0x0001; +pub const STARTTIMER: u32 = 0x0002; +pub const TX_COUNTEVT: u32 = 0x0004; +pub const TX_ANNOUNCE: u32 = 0x0008; +pub const TX_CP_CAN_ID: u32 = 0x0010; +pub const RX_FILTER_ID: u32 = 0x0020; +pub const RX_CHECK_DLC: u32 = 0x0040; +pub const RX_NO_AUTOTIMER: u32 = 0x0080; +pub const RX_ANNOUNCE_RESUME: u32 = 0x0100; +pub const TX_RESET_MULTI_IDX: u32 = 0x0200; +pub const RX_RTR_FRAME: u32 = 0x0400; +pub const CAN_FD_FRAME: u32 = 0x0800; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/error.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/error.rs new file mode 100644 index 00000000000000..1b298ca40eca05 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/error.rs @@ -0,0 +1,73 @@ +//! Header: `linux/can/error.h` + +pub use crate::linux::can::*; + +pub const CAN_ERR_DLC: c_int = 8; + +pub const CAN_ERR_TX_TIMEOUT: c_uint = 0x00000001; +pub const CAN_ERR_LOSTARB: c_uint = 0x00000002; +pub const CAN_ERR_CRTL: c_uint = 0x00000004; +pub const CAN_ERR_PROT: c_uint = 0x00000008; +pub const CAN_ERR_TRX: c_uint = 0x00000010; +pub const CAN_ERR_ACK: c_uint = 0x00000020; +pub const CAN_ERR_BUSOFF: c_uint = 0x00000040; +pub const CAN_ERR_BUSERROR: c_uint = 0x00000080; +pub const CAN_ERR_RESTARTED: c_uint = 0x00000100; +pub const CAN_ERR_CNT: c_uint = 0x00000200; + +pub const CAN_ERR_LOSTARB_UNSPEC: c_int = 0x00; + +pub const CAN_ERR_CRTL_UNSPEC: c_int = 0x00; +pub const CAN_ERR_CRTL_RX_OVERFLOW: c_int = 0x01; +pub const CAN_ERR_CRTL_TX_OVERFLOW: c_int = 0x02; +pub const CAN_ERR_CRTL_RX_WARNING: c_int = 0x04; +pub const CAN_ERR_CRTL_TX_WARNING: c_int = 0x08; +pub const CAN_ERR_CRTL_RX_PASSIVE: c_int = 0x10; +pub const CAN_ERR_CRTL_TX_PASSIVE: c_int = 0x20; +pub const CAN_ERR_CRTL_ACTIVE: c_int = 0x40; + +pub const CAN_ERR_PROT_UNSPEC: c_int = 0x00; +pub const CAN_ERR_PROT_BIT: c_int = 0x01; +pub const CAN_ERR_PROT_FORM: c_int = 0x02; +pub const CAN_ERR_PROT_STUFF: c_int = 0x04; +pub const CAN_ERR_PROT_BIT0: c_int = 0x08; +pub const CAN_ERR_PROT_BIT1: c_int = 0x10; +pub const CAN_ERR_PROT_OVERLOAD: c_int = 0x20; +pub const CAN_ERR_PROT_ACTIVE: c_int = 0x40; +pub const CAN_ERR_PROT_TX: c_int = 0x80; + +pub const CAN_ERR_PROT_LOC_UNSPEC: c_int = 0x00; +pub const CAN_ERR_PROT_LOC_SOF: c_int = 0x03; +pub const CAN_ERR_PROT_LOC_ID28_21: c_int = 0x02; +pub const CAN_ERR_PROT_LOC_ID20_18: c_int = 0x06; +pub const CAN_ERR_PROT_LOC_SRTR: c_int = 0x04; +pub const CAN_ERR_PROT_LOC_IDE: c_int = 0x05; +pub const CAN_ERR_PROT_LOC_ID17_13: c_int = 0x07; +pub const CAN_ERR_PROT_LOC_ID12_05: c_int = 0x0F; +pub const CAN_ERR_PROT_LOC_ID04_00: c_int = 0x0E; +pub const CAN_ERR_PROT_LOC_RTR: c_int = 0x0C; +pub const CAN_ERR_PROT_LOC_RES1: c_int = 0x0D; +pub const CAN_ERR_PROT_LOC_RES0: c_int = 0x09; +pub const CAN_ERR_PROT_LOC_DLC: c_int = 0x0B; +pub const CAN_ERR_PROT_LOC_DATA: c_int = 0x0A; +pub const CAN_ERR_PROT_LOC_CRC_SEQ: c_int = 0x08; +pub const CAN_ERR_PROT_LOC_CRC_DEL: c_int = 0x18; +pub const CAN_ERR_PROT_LOC_ACK: c_int = 0x19; +pub const CAN_ERR_PROT_LOC_ACK_DEL: c_int = 0x1B; +pub const CAN_ERR_PROT_LOC_EOF: c_int = 0x1A; +pub const CAN_ERR_PROT_LOC_INTERM: c_int = 0x12; + +pub const CAN_ERR_TRX_UNSPEC: c_int = 0x00; +pub const CAN_ERR_TRX_CANH_NO_WIRE: c_int = 0x04; +pub const CAN_ERR_TRX_CANH_SHORT_TO_BAT: c_int = 0x05; +pub const CAN_ERR_TRX_CANH_SHORT_TO_VCC: c_int = 0x06; +pub const CAN_ERR_TRX_CANH_SHORT_TO_GND: c_int = 0x07; +pub const CAN_ERR_TRX_CANL_NO_WIRE: c_int = 0x40; +pub const CAN_ERR_TRX_CANL_SHORT_TO_BAT: c_int = 0x50; +pub const CAN_ERR_TRX_CANL_SHORT_TO_VCC: c_int = 0x60; +pub const CAN_ERR_TRX_CANL_SHORT_TO_GND: c_int = 0x70; +pub const CAN_ERR_TRX_CANL_SHORT_TO_CANH: c_int = 0x80; + +pub const CAN_ERROR_WARNING_THRESHOLD: c_int = 96; +pub const CAN_ERROR_PASSIVE_THRESHOLD: c_int = 128; +pub const CAN_BUS_OFF_THRESHOLD: c_int = 256; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/j1939.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/j1939.rs new file mode 100644 index 00000000000000..fdf425ce6c0c1b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/j1939.rs @@ -0,0 +1,60 @@ +//! `linux/can/j1939.h` + +pub use crate::linux::can::*; + +pub const J1939_MAX_UNICAST_ADDR: c_uchar = 0xfd; +pub const J1939_IDLE_ADDR: c_uchar = 0xfe; +pub const J1939_NO_ADDR: c_uchar = 0xff; +pub const J1939_NO_NAME: c_ulong = 0; +pub const J1939_PGN_REQUEST: c_uint = 0x0ea00; +pub const J1939_PGN_ADDRESS_CLAIMED: c_uint = 0x0ee00; +pub const J1939_PGN_ADDRESS_COMMANDED: c_uint = 0x0fed8; +pub const J1939_PGN_PDU1_MAX: c_uint = 0x3ff00; +pub const J1939_PGN_MAX: c_uint = 0x3ffff; +pub const J1939_NO_PGN: c_uint = 0x40000; + +pub type pgn_t = u32; +pub type priority_t = u8; +pub type name_t = u64; + +pub const SOL_CAN_J1939: c_int = SOL_CAN_BASE + CAN_J1939; + +// FIXME(cleanup): these could use c_enum if it can accept anonymous enums. + +pub const SO_J1939_FILTER: c_int = 1; +pub const SO_J1939_PROMISC: c_int = 2; +pub const SO_J1939_SEND_PRIO: c_int = 3; +pub const SO_J1939_ERRQUEUE: c_int = 4; + +pub const SCM_J1939_DEST_ADDR: c_int = 1; +pub const SCM_J1939_DEST_NAME: c_int = 2; +pub const SCM_J1939_PRIO: c_int = 3; +pub const SCM_J1939_ERRQUEUE: c_int = 4; + +pub const J1939_NLA_PAD: c_int = 0; +pub const J1939_NLA_BYTES_ACKED: c_int = 1; +pub const J1939_NLA_TOTAL_SIZE: c_int = 2; +pub const J1939_NLA_PGN: c_int = 3; +pub const J1939_NLA_SRC_NAME: c_int = 4; +pub const J1939_NLA_DEST_NAME: c_int = 5; +pub const J1939_NLA_SRC_ADDR: c_int = 6; +pub const J1939_NLA_DEST_ADDR: c_int = 7; + +pub const J1939_EE_INFO_NONE: c_int = 0; +pub const J1939_EE_INFO_TX_ABORT: c_int = 1; +pub const J1939_EE_INFO_RX_RTS: c_int = 2; +pub const J1939_EE_INFO_RX_DPO: c_int = 3; +pub const J1939_EE_INFO_RX_ABORT: c_int = 4; + +s! { + pub struct j1939_filter { + pub name: name_t, + pub name_mask: name_t, + pub pgn: pgn_t, + pub pgn_mask: pgn_t, + pub addr: u8, + pub addr_mask: u8, + } +} + +pub const J1939_FILTER_MAX: c_int = 512; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/netlink.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/netlink.rs new file mode 100644 index 00000000000000..2892941090cb95 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/netlink.rs @@ -0,0 +1,125 @@ +//! Header: `linux/can/netlink.h` + +use crate::prelude::*; + +s! { + pub struct can_bittiming { + pub bitrate: u32, + pub sample_point: u32, + pub tq: u32, + pub prop_seg: u32, + pub phase_seg1: u32, + pub phase_seg2: u32, + pub sjw: u32, + pub brp: u32, + } + + pub struct can_bittiming_const { + pub name: [c_char; 16], + pub tseg1_min: u32, + pub tseg1_max: u32, + pub tseg2_min: u32, + pub tseg2_max: u32, + pub sjw_max: u32, + pub brp_min: u32, + pub brp_max: u32, + pub brp_inc: u32, + } + + pub struct can_clock { + pub freq: u32, + } + + pub struct can_berr_counter { + pub txerr: u16, + pub rxerr: u16, + } + + pub struct can_ctrlmode { + pub mask: u32, + pub flags: u32, + } + + pub struct can_device_stats { + pub bus_error: u32, + pub error_warning: u32, + pub error_passive: u32, + pub bus_off: u32, + pub arbitration_lost: u32, + pub restarts: u32, + } +} + +c_enum! { + #[repr(c_uint)] + pub enum can_state { + pub CAN_STATE_ERROR_ACTIVE = 0, + pub CAN_STATE_ERROR_WARNING, + pub CAN_STATE_ERROR_PASSIVE, + pub CAN_STATE_BUS_OFF, + pub CAN_STATE_STOPPED, + pub CAN_STATE_SLEEPING, + } +} + +pub const CAN_CTRLMODE_LOOPBACK: u32 = 0x01; +pub const CAN_CTRLMODE_LISTENONLY: u32 = 0x02; +pub const CAN_CTRLMODE_3_SAMPLES: u32 = 0x04; +pub const CAN_CTRLMODE_ONE_SHOT: u32 = 0x08; +pub const CAN_CTRLMODE_BERR_REPORTING: u32 = 0x10; +pub const CAN_CTRLMODE_FD: u32 = 0x20; +pub const CAN_CTRLMODE_PRESUME_ACK: u32 = 0x40; +pub const CAN_CTRLMODE_FD_NON_ISO: u32 = 0x80; +pub const CAN_CTRLMODE_CC_LEN8_DLC: u32 = 0x100; +pub const CAN_CTRLMODE_TDC_AUTO: u32 = 0x200; +pub const CAN_CTRLMODE_TDC_MANUAL: u32 = 0x400; + +c_enum! { + #[repr(c_int)] + pub enum #anon { + pub IFLA_CAN_UNSPEC = 0, + pub IFLA_CAN_BITTIMING, + pub IFLA_CAN_BITTIMING_CONST, + pub IFLA_CAN_CLOCK, + pub IFLA_CAN_STATE, + pub IFLA_CAN_CTRLMODE, + pub IFLA_CAN_RESTART_MS, + pub IFLA_CAN_RESTART, + pub IFLA_CAN_BERR_COUNTER, + pub IFLA_CAN_DATA_BITTIMING, + pub IFLA_CAN_DATA_BITTIMING_CONST, + pub IFLA_CAN_TERMINATION, + pub IFLA_CAN_TERMINATION_CONST, + pub IFLA_CAN_BITRATE_CONST, + pub IFLA_CAN_DATA_BITRATE_CONST, + pub IFLA_CAN_BITRATE_MAX, + pub IFLA_CAN_TDC, + pub IFLA_CAN_CTRLMODE_EXT, + } +} + +c_enum! { + #[repr(c_int)] + pub enum #anon { + pub IFLA_CAN_TDC_UNSPEC = 0, + pub IFLA_CAN_TDC_TDCV_MIN, + pub IFLA_CAN_TDC_TDCV_MAX, + pub IFLA_CAN_TDC_TDCO_MIN, + pub IFLA_CAN_TDC_TDCO_MAX, + pub IFLA_CAN_TDC_TDCF_MIN, + pub IFLA_CAN_TDC_TDCF_MAX, + pub IFLA_CAN_TDC_TDCV, + pub IFLA_CAN_TDC_TDCO, + pub IFLA_CAN_TDC_TDCF, + } +} + +c_enum! { + #[repr(c_int)] + pub enum #anon { + pub IFLA_CAN_CTRLMODE_UNSPEC = 0, + pub IFLA_CAN_CTRLMODE_SUPPORTED, + } +} + +pub const CAN_TERMINATION_DISABLED: u16 = 0; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/raw.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/raw.rs new file mode 100644 index 00000000000000..470334bd5d1471 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/can/raw.rs @@ -0,0 +1,15 @@ +//! Header: `linux/can/raw.h` + +pub use crate::linux::can::*; + +pub const SOL_CAN_RAW: c_int = SOL_CAN_BASE + CAN_RAW; +pub const CAN_RAW_FILTER_MAX: c_int = 512; + +// FIXME(cleanup): use `c_enum!`, which needs to be adapted to allow omitting a type. +pub const CAN_RAW_FILTER: c_int = 1; +pub const CAN_RAW_ERR_FILTER: c_int = 2; +pub const CAN_RAW_LOOPBACK: c_int = 3; +pub const CAN_RAW_RECV_OWN_MSGS: c_int = 4; +pub const CAN_RAW_FD_FRAMES: c_int = 5; +pub const CAN_RAW_JOIN_FILTERS: c_int = 6; +pub const CAN_RAW_XL_FRAMES: c_int = 7; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/keyctl.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/keyctl.rs new file mode 100644 index 00000000000000..cc6527a8a5113e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/keyctl.rs @@ -0,0 +1,69 @@ +//! Header: `linux/keyctl.h` + +pub const KEY_SPEC_THREAD_KEYRING: i32 = -1; +pub const KEY_SPEC_PROCESS_KEYRING: i32 = -2; +pub const KEY_SPEC_SESSION_KEYRING: i32 = -3; +pub const KEY_SPEC_USER_KEYRING: i32 = -4; +pub const KEY_SPEC_USER_SESSION_KEYRING: i32 = -5; +pub const KEY_SPEC_GROUP_KEYRING: i32 = -6; +pub const KEY_SPEC_REQKEY_AUTH_KEY: i32 = -7; +pub const KEY_SPEC_REQUESTOR_KEYRING: i32 = -8; + +pub const KEY_REQKEY_DEFL_NO_CHANGE: i32 = -1; +pub const KEY_REQKEY_DEFL_DEFAULT: i32 = 0; +pub const KEY_REQKEY_DEFL_THREAD_KEYRING: i32 = 1; +pub const KEY_REQKEY_DEFL_PROCESS_KEYRING: i32 = 2; +pub const KEY_REQKEY_DEFL_SESSION_KEYRING: i32 = 3; +pub const KEY_REQKEY_DEFL_USER_KEYRING: i32 = 4; +pub const KEY_REQKEY_DEFL_USER_SESSION_KEYRING: i32 = 5; +pub const KEY_REQKEY_DEFL_GROUP_KEYRING: i32 = 6; +pub const KEY_REQKEY_DEFL_REQUESTOR_KEYRING: i32 = 7; + +pub const KEYCTL_GET_KEYRING_ID: u32 = 0; +pub const KEYCTL_JOIN_SESSION_KEYRING: u32 = 1; +pub const KEYCTL_UPDATE: u32 = 2; +pub const KEYCTL_REVOKE: u32 = 3; +pub const KEYCTL_CHOWN: u32 = 4; +pub const KEYCTL_SETPERM: u32 = 5; +pub const KEYCTL_DESCRIBE: u32 = 6; +pub const KEYCTL_CLEAR: u32 = 7; +pub const KEYCTL_LINK: u32 = 8; +pub const KEYCTL_UNLINK: u32 = 9; +pub const KEYCTL_SEARCH: u32 = 10; +pub const KEYCTL_READ: u32 = 11; +pub const KEYCTL_INSTANTIATE: u32 = 12; +pub const KEYCTL_NEGATE: u32 = 13; +pub const KEYCTL_SET_REQKEY_KEYRING: u32 = 14; +pub const KEYCTL_SET_TIMEOUT: u32 = 15; +pub const KEYCTL_ASSUME_AUTHORITY: u32 = 16; +pub const KEYCTL_GET_SECURITY: u32 = 17; +pub const KEYCTL_SESSION_TO_PARENT: u32 = 18; +pub const KEYCTL_REJECT: u32 = 19; +pub const KEYCTL_INSTANTIATE_IOV: u32 = 20; +pub const KEYCTL_INVALIDATE: u32 = 21; +pub const KEYCTL_GET_PERSISTENT: u32 = 22; +pub const KEYCTL_DH_COMPUTE: u32 = 23; +pub const KEYCTL_PKEY_QUERY: u32 = 24; +pub const KEYCTL_PKEY_ENCRYPT: u32 = 25; +pub const KEYCTL_PKEY_DECRYPT: u32 = 26; +pub const KEYCTL_PKEY_SIGN: u32 = 27; +pub const KEYCTL_PKEY_VERIFY: u32 = 28; +pub const KEYCTL_RESTRICT_KEYRING: u32 = 29; +pub const KEYCTL_MOVE: u32 = 30; +pub const KEYCTL_CAPABILITIES: u32 = 31; + +pub const KEYCTL_SUPPORTS_ENCRYPT: u32 = 0x01; +pub const KEYCTL_SUPPORTS_DECRYPT: u32 = 0x02; +pub const KEYCTL_SUPPORTS_SIGN: u32 = 0x04; +pub const KEYCTL_SUPPORTS_VERIFY: u32 = 0x08; + +pub const KEYCTL_CAPS0_CAPABILITIES: u32 = 0x01; +pub const KEYCTL_CAPS0_PERSISTENT_KEYRINGS: u32 = 0x02; +pub const KEYCTL_CAPS0_DIFFIE_HELLMAN: u32 = 0x04; +pub const KEYCTL_CAPS0_PUBLIC_KEY: u32 = 0x08; +pub const KEYCTL_CAPS0_BIG_KEY: u32 = 0x10; +pub const KEYCTL_CAPS0_INVALIDATE: u32 = 0x20; +pub const KEYCTL_CAPS0_RESTRICT_KEYRING: u32 = 0x40; +pub const KEYCTL_CAPS0_MOVE: u32 = 0x80; +pub const KEYCTL_CAPS1_NS_KEYRING_NAME: u32 = 0x01; +pub const KEYCTL_CAPS1_NS_KEY_TAG: u32 = 0x02; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/membarrier.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/membarrier.rs new file mode 100644 index 00000000000000..4446202cb3bfbb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/membarrier.rs @@ -0,0 +1,20 @@ +//! Header: `uapi/linux/membarrier.h` + +use crate::prelude::*; + +c_enum! { + // FIXME(1.0): incorrect repr signedness, this should be removed in a breaking change. + #[repr(c_int)] + pub enum membarrier_cmd { + pub MEMBARRIER_CMD_QUERY = 0, + pub MEMBARRIER_CMD_GLOBAL = 1 << 0, + pub MEMBARRIER_CMD_GLOBAL_EXPEDITED = 1 << 1, + pub MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = 1 << 2, + pub MEMBARRIER_CMD_PRIVATE_EXPEDITED = 1 << 3, + pub MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = 1 << 4, + pub MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = 1 << 5, + pub MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = 1 << 6, + pub MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = 1 << 7, + pub MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = 1 << 8, + } +} diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/mod.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/mod.rs new file mode 100644 index 00000000000000..09e2c3ece7417f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/mod.rs @@ -0,0 +1,9 @@ +//! Directory: `linux/` +//! +//! + +pub(crate) mod can; +pub(crate) mod keyctl; +pub(crate) mod membarrier; +pub(crate) mod netlink; +pub(crate) mod pidfd; diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/netlink.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/netlink.rs new file mode 100644 index 00000000000000..03e18d739300a1 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/netlink.rs @@ -0,0 +1,136 @@ +//! Header: `uapi/linux/netlink.h` + +use crate::prelude::*; + +pub const NETLINK_ROUTE: c_int = 0; +pub const NETLINK_UNUSED: c_int = 1; +pub const NETLINK_USERSOCK: c_int = 2; +pub const NETLINK_FIREWALL: c_int = 3; +pub const NETLINK_SOCK_DIAG: c_int = 4; +pub const NETLINK_NFLOG: c_int = 5; +pub const NETLINK_XFRM: c_int = 6; +pub const NETLINK_SELINUX: c_int = 7; +pub const NETLINK_ISCSI: c_int = 8; +pub const NETLINK_AUDIT: c_int = 9; +pub const NETLINK_FIB_LOOKUP: c_int = 10; +pub const NETLINK_CONNECTOR: c_int = 11; +pub const NETLINK_NETFILTER: c_int = 12; +pub const NETLINK_IP6_FW: c_int = 13; +pub const NETLINK_DNRTMSG: c_int = 14; +pub const NETLINK_KOBJECT_UEVENT: c_int = 15; +pub const NETLINK_GENERIC: c_int = 16; +pub const NETLINK_SCSITRANSPORT: c_int = 18; +pub const NETLINK_ECRYPTFS: c_int = 19; +pub const NETLINK_RDMA: c_int = 20; +pub const NETLINK_CRYPTO: c_int = 21; + +pub const NETLINK_INET_DIAG: c_int = NETLINK_SOCK_DIAG; + +pub const MAX_LINKS: c_int = 32; + +s! { + pub struct sockaddr_nl { + pub nl_family: crate::sa_family_t, + nl_pad: Padding, + pub nl_pid: u32, + pub nl_groups: u32, + } + + pub struct nlmsghdr { + pub nlmsg_len: u32, + pub nlmsg_type: u16, + pub nlmsg_flags: u16, + pub nlmsg_seq: u32, + pub nlmsg_pid: u32, + } +} + +pub const NLM_F_REQUEST: c_int = 1; +pub const NLM_F_MULTI: c_int = 2; +pub const NLM_F_ACK: c_int = 4; +pub const NLM_F_ECHO: c_int = 8; +pub const NLM_F_DUMP_INTR: c_int = 16; +pub const NLM_F_DUMP_FILTERED: c_int = 32; + +pub const NLM_F_ROOT: c_int = 0x100; +pub const NLM_F_MATCH: c_int = 0x200; +pub const NLM_F_ATOMIC: c_int = 0x400; +pub const NLM_F_DUMP: c_int = NLM_F_ROOT | NLM_F_MATCH; + +pub const NLM_F_REPLACE: c_int = 0x100; +pub const NLM_F_EXCL: c_int = 0x200; +pub const NLM_F_CREATE: c_int = 0x400; +pub const NLM_F_APPEND: c_int = 0x800; + +pub const NLM_F_NONREC: c_int = 0x100; + +pub const NLM_F_CAPPED: c_int = 0x100; +pub const NLM_F_ACK_TLVS: c_int = 0x200; + +pub const NLMSG_NOOP: c_int = 0x1; +pub const NLMSG_ERROR: c_int = 0x2; +pub const NLMSG_DONE: c_int = 0x3; +pub const NLMSG_OVERRUN: c_int = 0x4; + +pub const NLMSG_MIN_TYPE: c_int = 0x10; + +s! { + pub struct nlmsgerr { + pub error: c_int, + pub msg: nlmsghdr, + } +} + +pub const NETLINK_ADD_MEMBERSHIP: c_int = 1; +pub const NETLINK_DROP_MEMBERSHIP: c_int = 2; +pub const NETLINK_PKTINFO: c_int = 3; +pub const NETLINK_BROADCAST_ERROR: c_int = 4; +pub const NETLINK_NO_ENOBUFS: c_int = 5; +pub const NETLINK_RX_RING: c_int = 6; +pub const NETLINK_TX_RING: c_int = 7; +pub const NETLINK_LISTEN_ALL_NSID: c_int = 8; +pub const NETLINK_LIST_MEMBERSHIPS: c_int = 9; +pub const NETLINK_CAP_ACK: c_int = 10; +pub const NETLINK_EXT_ACK: c_int = 11; +pub const NETLINK_GET_STRICT_CHK: c_int = 12; + +s! { + pub struct nl_pktinfo { + pub group: u32, + } + + pub struct nl_mmap_req { + pub nm_block_size: c_uint, + pub nm_block_nr: c_uint, + pub nm_frame_size: c_uint, + pub nm_frame_nr: c_uint, + } + + pub struct nl_mmap_hdr { + pub nm_status: c_uint, + pub nm_len: c_uint, + pub nm_group: u32, + pub nm_pid: u32, + pub nm_uid: u32, + pub nm_gid: u32, + } +} + +s! { + pub struct nlattr { + pub nla_len: u16, + pub nla_type: u16, + } +} + +pub const NLA_F_NESTED: c_int = 1 << 15; +pub const NLA_F_NET_BYTEORDER: c_int = 1 << 14; +pub const NLA_TYPE_MASK: c_int = !(NLA_F_NESTED | NLA_F_NET_BYTEORDER); + +pub const NLA_ALIGNTO: c_int = 4; + +f! { + pub fn NLA_ALIGN(len: c_int) -> c_int { + return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1); + } +} diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/linux/pidfd.rs b/deps/crates/vendor/libc/src/new/linux_uapi/linux/pidfd.rs new file mode 100644 index 00000000000000..1835184a186017 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/linux/pidfd.rs @@ -0,0 +1,59 @@ +//! Header: `uapi/linux/pidfd.h` + +use crate::prelude::*; +use crate::{ + Ioctl, + _IO, + _IOWR, +}; + +/* Flags for pidfd_open(). */ +pub const PIDFD_NONBLOCK: c_uint = crate::O_NONBLOCK as c_uint; +pub const PIDFD_THREAD: c_uint = crate::O_EXCL as c_uint; + +/* Flags for pidfd_send_signal(). */ +pub const PIDFD_SIGNAL_THREAD: c_uint = 1 << 0; +pub const PIDFD_SIGNAL_THREAD_GROUP: c_uint = 1 << 1; +pub const PIDFD_SIGNAL_PROCESS_GROUP: c_uint = 1 << 2; + +/* Flags for pidfd_info. */ +pub const PIDFD_INFO_PID: c_uint = 1 << 0; +pub const PIDFD_INFO_CREDS: c_uint = 1 << 1; +pub const PIDFD_INFO_CGROUPID: c_uint = 1 << 2; +pub const PIDFD_INFO_EXIT: c_uint = 1 << 3; + +pub const PIDFD_INFO_SIZE_VER0: c_uint = 64; + +s! { + #[non_exhaustive] + pub struct pidfd_info { + pub mask: crate::__u64, + pub cgroupid: crate::__u64, + pub pid: crate::__u32, + pub tgid: crate::__u32, + pub ppid: crate::__u32, + pub ruid: crate::__u32, + pub rgid: crate::__u32, + pub euid: crate::__u32, + pub egid: crate::__u32, + pub suid: crate::__u32, + pub sgid: crate::__u32, + pub fsuid: crate::__u32, + pub fsgid: crate::__u32, + pub exit_code: crate::__s32, + } +} + +const PIDFS_IOCTL_MAGIC: c_uint = 0xFF; + +pub const PIDFD_GET_CGROUP_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 1); +pub const PIDFD_GET_IPC_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 2); +pub const PIDFD_GET_MNT_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 3); +pub const PIDFD_GET_NET_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 4); +pub const PIDFD_GET_PID_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 5); +pub const PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 6); +pub const PIDFD_GET_TIME_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 7); +pub const PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 8); +pub const PIDFD_GET_USER_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 9); +pub const PIDFD_GET_UTS_NAMESPACE: Ioctl = _IO(PIDFS_IOCTL_MAGIC, 10); +pub const PIDFD_GET_INFO: Ioctl = _IOWR::(PIDFS_IOCTL_MAGIC, 11); diff --git a/deps/crates/vendor/libc/src/new/linux_uapi/mod.rs b/deps/crates/vendor/libc/src/new/linux_uapi/mod.rs new file mode 100644 index 00000000000000..8ac3022d165781 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/linux_uapi/mod.rs @@ -0,0 +1,3 @@ +//! This directory maps to `include/uapi` in the Linux source tree. + +pub(crate) mod linux; diff --git a/deps/crates/vendor/libc/src/new/mod.rs b/deps/crates/vendor/libc/src/new/mod.rs new file mode 100644 index 00000000000000..1c5d6a6e17c256 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/mod.rs @@ -0,0 +1,239 @@ +//! This module contains the future directory structure. If possible, new definitions should +//! get added here. +//! +//! Eventually everything should be moved over, and we will move this directory to the top +//! level in `src`. +//! +//! # Basic structure +//! +//! Each child module here represents a library or group of libraries that we are binding. Each of +//! these has several submodules, representing either a directory or a header file in that library. +//! +//! `#include`s turn into `pub use ...*;` statements. Then at the root level (here), we choose +//! which top-level headers we want to reexport the definitions for. +//! +//! All modules are only crate-public since we don't reexport this structure. + +mod common; + +/* The `pub(crate) use ...` statements are commented while the modules are empty */ + +// Platform libraries and combined platform+libc +// +// Not supported or not needed: +// * amdhsa +// * cuda +// * lynxos178 +// * managarm +// * motor +// * none +// * psp +// * psx +// * uefi +// * unknown +// * vexos +// * zkvm +// +// Combined to target_vendor = "apple" +// * ios +// * macos +// * tvos +// * visionos +// * watchos +cfg_if! { + if #[cfg(target_os = "aix")] { + mod aix; + pub(crate) use aix::*; + } else if #[cfg(target_os = "android")] { + mod bionic_libc; + pub(crate) use bionic_libc::*; + } else if #[cfg(target_vendor = "apple")] { + mod apple; + pub(crate) use apple::*; + } else if #[cfg(target_os = "cygwin")] { + mod cygwin; + pub(crate) use cygwin::*; + } else if #[cfg(target_os = "dragonfly")] { + mod dragonfly; + pub(crate) use dragonfly::*; + } else if #[cfg(target_os = "emscripten")] { + mod emscripten; + pub use emscripten::sched::*; + pub(crate) use emscripten::*; + } else if #[cfg(target_os = "espidf")] { + mod espidf; + // pub(crate) use espidf::*; + } else if #[cfg(target_os = "freebsd")] { + mod freebsd; + pub(crate) use freebsd::*; + } else if #[cfg(target_os = "fuchsia")] { + mod fuchsia; + pub(crate) use fuchsia::*; + } else if #[cfg(target_os = "haiku")] { + mod haiku; + pub(crate) use haiku::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit_abi; + // pub(crate) use hermit_abi::*; + } else if #[cfg(target_os = "horizon")] { + mod horizon; + // pub(crate) use horizon::*; + } else if #[cfg(target_os = "hurd")] { + mod hurd; + // pub(crate) use hurd::*; + } else if #[cfg(target_os = "illumos")] { + mod illumos; + pub(crate) use illumos::*; + } else if #[cfg(target_os = "l4re")] { + mod l4re; + // pub(crate) use l4re::*; + } else if #[cfg(target_os = "linux")] { + mod linux_uapi; + pub(crate) use linux_uapi::*; + } else if #[cfg(target_os = "netbsd")] { + mod netbsd; + pub(crate) use netbsd::*; + } else if #[cfg(target_os = "nto")] { + mod nto; + pub(crate) use nto::*; + } else if #[cfg(target_os = "nuttx")] { + mod nuttx; + pub(crate) use nuttx::*; + } else if #[cfg(target_os = "openbsd")] { + mod openbsd; + pub(crate) use openbsd::*; + } else if #[cfg(target_os = "qurt")] { + pub mod qurt; + pub use qurt::*; + } else if #[cfg(target_os = "redox")] { + mod redox; + // pub(crate) use redox::*; + } else if #[cfg(target_os = "rtems")] { + mod rtems; + // pub(crate) use rtems::*; + } else if #[cfg(target_os = "solaris")] { + mod solaris; + pub(crate) use solaris::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + // pub(crate) use solid::*; + } else if #[cfg(target_os = "teeos")] { + mod teeos; + // pub(crate) use teeos::*; + } else if #[cfg(target_os = "trusty")] { + mod trusty; + // pub(crate) use trusty::*; + } else if #[cfg(target_os = "vita")] { + mod vita; + // pub(crate) use vita::*; + } else if #[cfg(target_os = "vxworks")] { + mod vxworks; + pub(crate) use vxworks::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + // pub(crate) use wasi::*; + } else if #[cfg(target_os = "windows")] { + mod ucrt; + // pub(crate) use ucrt::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + // pub(crate) use xous::*; + } +} + +// Multi-platform libc +cfg_if! { + // FIXME(vxworks): vxworks sets `target_env = "gnu"` but maybe shouldn't. + if #[cfg(all( + target_family = "unix", + target_env = "gnu", + not(target_os = "vxworks") + ))] { + mod glibc; + pub(crate) use glibc::*; + } else if #[cfg(any(target_env = "musl", target_env = "ohos"))] { + // OhOS also uses the musl libc + mod musl; + pub use musl::sched::*; + pub(crate) use musl::*; + } else if #[cfg(target_env = "newlib")] { + mod newlib; + pub(crate) use newlib::*; + } else if #[cfg(target_env = "relibc")] { + mod relibc; + pub(crate) use relibc::*; + } else if #[cfg(target_env = "sgx")] { + mod sgx; + // pub(crate) use sgx::*; + } else if #[cfg(target_env = "uclibc")] { + mod uclibc; + pub(crate) use uclibc::*; + } +} + +// Per-OS headers we export +cfg_if! { + if #[cfg(target_os = "android")] { + pub use sys::socket::*; + } else if #[cfg(target_os = "linux")] { + pub use linux::can::bcm::*; + pub use linux::can::error::*; + pub use linux::can::j1939::*; + pub use linux::can::netlink::*; + pub use linux::can::raw::*; + pub use linux::can::*; + pub use linux::keyctl::*; + pub use linux::membarrier::*; + pub use linux::netlink::*; + pub use linux::pidfd::*; + #[cfg(target_env = "gnu")] + pub use net::route::*; + } else if #[cfg(target_vendor = "apple")] { + pub use pthread::*; + pub use pthread_::introspection::*; + pub use pthread_::pthread_spis::*; + pub use pthread_::spawn::*; + pub use pthread_::stack_np::*; + pub use signal::*; + } else if #[cfg(target_os = "netbsd")] { + pub use net::if_::*; + pub use sys::file::*; + pub use sys::ipc::*; + pub use sys::socket::*; + pub use sys::statvfs::*; + pub use sys::time::*; + pub use sys::timex::*; + pub use sys::types::*; + pub use utmp_::*; + pub use utmpx_::*; + } else if #[cfg(target_os = "openbsd")] { + pub use sys::ipc::*; + } else if #[cfg(target_os = "nto")] { + pub use net::bpf::*; + pub use net::if_::*; + } else if #[cfg(target_os = "freebsd")] { + pub use sys::file::*; + } +} + +// Per-env headers we export +cfg_if! { + if #[cfg(any(target_env = "musl", target_env = "ohos"))] { + pub use sys::socket::*; + } +} + +// Per-family headers we export +cfg_if! { + if #[cfg(all(target_family = "unix", not(target_os = "qurt")))] { + // FIXME(pthread): eventually all platforms should use this module + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "l4re", + target_os = "linux" + ))] + pub use pthread::*; + pub use unistd::*; + } +} diff --git a/deps/crates/vendor/libc/src/new/musl/arch/generic/mod.rs b/deps/crates/vendor/libc/src/new/musl/arch/generic/mod.rs new file mode 100644 index 00000000000000..ac02505c882bf0 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/generic/mod.rs @@ -0,0 +1,7 @@ +//! Source directory: `arch/generic/` +//! +//! + +pub(crate) mod bits { + // Currently unused +} diff --git a/deps/crates/vendor/libc/src/new/musl/arch/mips/bits/socket.rs b/deps/crates/vendor/libc/src/new/musl/arch/mips/bits/socket.rs new file mode 100644 index 00000000000000..77b53e489c3d87 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/mips/bits/socket.rs @@ -0,0 +1,4 @@ +use crate::prelude::*; + +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_DGRAM: c_int = 1; diff --git a/deps/crates/vendor/libc/src/new/musl/arch/mips/mod.rs b/deps/crates/vendor/libc/src/new/musl/arch/mips/mod.rs new file mode 100644 index 00000000000000..2f02036d254ceb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/mips/mod.rs @@ -0,0 +1,7 @@ +//! Source directory: `arch/mips/` +//! +//! + +pub(crate) mod bits { + pub(crate) mod socket; +} diff --git a/deps/crates/vendor/libc/src/new/musl/arch/mips64/bits/socket.rs b/deps/crates/vendor/libc/src/new/musl/arch/mips64/bits/socket.rs new file mode 100644 index 00000000000000..77b53e489c3d87 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/mips64/bits/socket.rs @@ -0,0 +1,4 @@ +use crate::prelude::*; + +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_DGRAM: c_int = 1; diff --git a/deps/crates/vendor/libc/src/new/musl/arch/mips64/mod.rs b/deps/crates/vendor/libc/src/new/musl/arch/mips64/mod.rs new file mode 100644 index 00000000000000..6a45b067b998eb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/mips64/mod.rs @@ -0,0 +1,7 @@ +//! Source directory: `arch/mips64/` +//! +//! + +pub(crate) mod bits { + pub(crate) mod socket; +} diff --git a/deps/crates/vendor/libc/src/new/musl/arch/mod.rs b/deps/crates/vendor/libc/src/new/musl/arch/mod.rs new file mode 100644 index 00000000000000..514d7b4bdfea7b --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/arch/mod.rs @@ -0,0 +1,10 @@ +//! Source directory: `arch/` +//! +//! + +pub(crate) mod generic; + +#[cfg(target_arch = "mips")] +pub(crate) mod mips; +#[cfg(target_arch = "mips64")] +pub(crate) mod mips64; diff --git a/deps/crates/vendor/libc/src/new/musl/mod.rs b/deps/crates/vendor/libc/src/new/musl/mod.rs new file mode 100644 index 00000000000000..a6551c342da67f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/mod.rs @@ -0,0 +1,33 @@ +//! Musl libc. +//! +//! * Headers: (official) +//! * Headers: (mirror) + +// The musl build system includes `arch/$(ARCH)` (preferred if it exists) and `arch/generic` (used +// as the fallback). We can't exactly mirror this with glob exports, so instead we selectively +// reexport in a new module. +mod arch; + +pub(crate) mod bits { + cfg_if! { + if #[cfg(target_arch = "mips")] { + pub(crate) use super::arch::mips::bits::socket; + } else if #[cfg(target_arch = "mips64")] { + pub(crate) use super::arch::mips64::bits::socket; + } else { + // Reexports from generic will live here once we need them. + } + } +} + +pub(crate) mod pthread; + +/// Directory: `sys/` +/// +/// +pub(crate) mod sys { + pub(crate) mod socket; +} + +pub(crate) mod sched; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/musl/pthread.rs b/deps/crates/vendor/libc/src/new/musl/pthread.rs new file mode 100644 index 00000000000000..0d578bc9665dcc --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/pthread.rs @@ -0,0 +1,62 @@ +//! Header: `pthread.h` +//! +//! + +pub use crate::new::common::linux_like::pthread::{ + pthread_getaffinity_np, + pthread_getattr_np, + pthread_getname_np, + pthread_setaffinity_np, + pthread_setname_np, +}; +pub use crate::new::common::posix::pthread::{ + pthread_atfork, + pthread_attr_getguardsize, + pthread_attr_getinheritsched, + pthread_attr_getschedparam, + pthread_attr_getschedpolicy, + pthread_attr_getstack, + pthread_attr_setguardsize, + pthread_attr_setinheritsched, + pthread_attr_setschedparam, + pthread_attr_setschedpolicy, + pthread_attr_setstack, + pthread_barrier_destroy, + pthread_barrier_init, + pthread_barrier_wait, + pthread_barrierattr_destroy, + pthread_barrierattr_getpshared, + pthread_barrierattr_init, + pthread_barrierattr_setpshared, + pthread_condattr_getclock, + pthread_condattr_getpshared, + pthread_condattr_setclock, + pthread_condattr_setpshared, + pthread_create, + pthread_getcpuclockid, + pthread_getschedparam, + pthread_kill, + pthread_mutex_timedlock, + pthread_mutexattr_getprotocol, + pthread_mutexattr_getpshared, + pthread_mutexattr_setprotocol, + pthread_mutexattr_setpshared, + pthread_once, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, + pthread_setschedparam, + pthread_setschedprio, + pthread_sigmask, + pthread_spin_destroy, + pthread_spin_init, + pthread_spin_lock, + pthread_spin_trylock, + pthread_spin_unlock, +}; +#[cfg(not(target_env = "ohos"))] +pub use crate::new::common::posix::pthread::{ + pthread_cancel, + pthread_mutex_consistent, + pthread_mutexattr_getrobust, + pthread_mutexattr_setrobust, +}; diff --git a/deps/crates/vendor/libc/src/new/musl/sched.rs b/deps/crates/vendor/libc/src/new/musl/sched.rs new file mode 100644 index 00000000000000..3bf854ef33c29f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/sched.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; + +cfg_if! { + if #[cfg(musl_v1_2_3)] { + s! { + struct __c_anon_sched_param__reserved2 { + __reserved1: crate::time_t, + __reserved2: c_long, + } + + pub struct sched_param { + pub sched_priority: c_int, + + __reserved1: Padding, + #[cfg(musl32_time64)] + __reserved2: Padding<[c_long; 4]>, + #[cfg(not(musl32_time64))] + __reserved2: Padding<[__c_anon_sched_param__reserved2; 2]>, + __reserved3: Padding, + } + } + } else { + s! { + pub struct sched_param { + pub sched_priority: c_int, + + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_low_priority: c_int, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_repl_period: crate::timespec, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_init_budget: crate::timespec, + #[deprecated(since = "0.2.173", note = "This field has been removed upstream")] + pub sched_ss_max_repl: c_int, + } + } + } +} diff --git a/deps/crates/vendor/libc/src/new/musl/sys/socket.rs b/deps/crates/vendor/libc/src/new/musl/sys/socket.rs new file mode 100644 index 00000000000000..7d3f495955458d --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/sys/socket.rs @@ -0,0 +1,64 @@ +//! Header: `sys/socket.h` +//! +//! + +use crate::prelude::*; + +s! { + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + #[cfg(all(target_pointer_width = "64", target_endian = "big"))] + __pad1: Padding, + pub msg_iovlen: c_int, + #[cfg(all(target_pointer_width = "64", target_endian = "little"))] + __pad1: Padding, + pub msg_control: *mut c_void, + #[cfg(all(target_pointer_width = "64", target_endian = "big"))] + __pad2: Padding, + pub msg_controllen: crate::socklen_t, + #[cfg(all(target_pointer_width = "64", target_endian = "little"))] + __pad2: Padding, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + #[cfg(all(target_pointer_width = "64", target_endian = "big"))] + pub __pad1: c_int, + pub cmsg_len: crate::socklen_t, + #[cfg(all(target_pointer_width = "64", target_endian = "little"))] + pub __pad1: c_int, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } +} + +extern "C" { + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + ) -> c_int; + #[cfg_attr(musl_redir_time64, link_name = "__recvmmsg_time64")] + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + timeout: *mut crate::timespec, + ) -> c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] { + pub use crate::bits::socket::{ + SOCK_DGRAM, + SOCK_STREAM, + }; + } else { + pub const SOCK_STREAM: c_int = 1; + pub const SOCK_DGRAM: c_int = 2; + } +} diff --git a/deps/crates/vendor/libc/src/new/musl/unistd.rs b/deps/crates/vendor/libc/src/new/musl/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/musl/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/netbsd/mod.rs b/deps/crates/vendor/libc/src/new/netbsd/mod.rs new file mode 100644 index 00000000000000..5db71760c4de96 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/mod.rs @@ -0,0 +1,14 @@ +//! NetBSD libc. +//! +//! * Headers: +//! * Sys headers: +//! * Manual pages: + +pub(crate) mod net { + pub(crate) mod if_; +} + +pub(crate) mod sys; +pub(crate) mod unistd; +pub(crate) mod utmp_; +pub(crate) mod utmpx_; diff --git a/deps/crates/vendor/libc/src/new/netbsd/net/if_.rs b/deps/crates/vendor/libc/src/new/netbsd/net/if_.rs new file mode 100644 index 00000000000000..68f2d916269033 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/net/if_.rs @@ -0,0 +1,101 @@ +//! Header: `net/if.h` +//! +//! + +use crate::prelude::*; +use crate::IFNAMSIZ; + +s! { + pub struct if_data { + pub ifi_type: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_link_state: c_int, + pub ifi_mtu: u64, + pub ifi_metric: u64, + pub ifi_baudrate: u64, + pub ifi_ipackets: u64, + pub ifi_ierrors: u64, + pub ifi_opackets: u64, + pub ifi_oerrors: u64, + pub ifi_collisions: u64, + pub ifi_ibytes: u64, + pub ifi_obytes: u64, + pub ifi_imcasts: u64, + pub ifi_omcasts: u64, + pub ifi_iqdrops: u64, + pub ifi_noproto: u64, + pub ifi_lastchange: crate::timespec, + } +} + +pub const LINK_STATE_UNKNOWN: c_int = 0; // link invalid/unknown +pub const LINK_STATE_DOWN: c_int = 1; // link is down +pub const LINK_STATE_UP: c_int = 2; // link is up + +pub const IFF_UP: c_int = 0x0001; // interface is up +pub const IFF_BROADCAST: c_int = 0x0002; // broadcast address valid +pub const IFF_DEBUG: c_int = 0x0004; // turn on debugging +pub const IFF_LOOPBACK: c_int = 0x0008; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x0010; // interface is point-to-point link +pub const IFF_RUNNING: c_int = 0x0040; // resources allocated +pub const IFF_NOARP: c_int = 0x0080; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x0100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x0200; // receive all multicast packets +pub const IFF_OACTIVE: c_int = 0x0400; // transmission in progress +pub const IFF_SIMPLEX: c_int = 0x0800; // can't hear own transmissions +pub const IFF_LINK0: c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; // per link layer defined bit +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + +s! { + #[repr(C, align(8))] + pub struct if_msghdr { + pub ifm_msglen: c_ushort, + pub ifm_version: c_uchar, + pub ifm_type: c_uchar, + pub ifm_addrs: c_int, + pub ifm_flags: c_int, + pub ifm_index: c_ushort, + pub ifm_data: if_data, + } +} + +s_no_extra_traits! { + pub struct ifreq { + pub ifr_name: [c_char; IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub space: crate::sockaddr_storage, + pub ifru_flags: c_short, + pub ifru_addrflags: c_int, + pub ifru_metrics: c_int, + pub ifru_mtu: c_int, + pub ifru_dlt: c_int, + pub ifru_value: c_uint, + pub ifru_data: *mut c_void, + // buf and buflen are deprecated but they contribute to union size + ifru_b: __c_anonymous_ifr_ifru_ifru_b, + } + + struct __c_anonymous_ifr_ifru_ifru_b { + b_buflen: u32, + b_buf: *mut c_void, + } + + pub struct ifconf { + pub ifc_len: c_int, + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: *mut c_void, + pub ifcu_req: *mut ifreq, + } +} diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/file.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/file.rs new file mode 100644 index 00000000000000..103b68de4db1ff --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/file.rs @@ -0,0 +1,16 @@ +//! Header: `sys/file.h` +//! +//! + +use crate::prelude::*; + +pub const DTYPE_VNODE: c_int = 1; +pub const DTYPE_SOCKET: c_int = 2; +pub const DTYPE_PIPE: c_int = 3; +pub const DTYPE_KQUEUE: c_int = 4; +pub const DTYPE_MISC: c_int = 5; +pub const DTYPE_CRYPTO: c_int = 6; +pub const DTYPE_MQUEUE: c_int = 7; +pub const DTYPE_SEM: c_int = 8; +pub const DTYPE_EVENTFD: c_int = 9; +pub const DTYPE_TIMERFD: c_int = 10; diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/ipc.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/ipc.rs new file mode 100644 index 00000000000000..49a1c84d742967 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/ipc.rs @@ -0,0 +1,17 @@ +//! Header: `sys/ipc.h` +//! +//! + +use crate::prelude::*; + +s! { + pub struct ipc_perm { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub _seq: c_ushort, + pub _key: crate::key_t, + } +} diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/mod.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/mod.rs new file mode 100644 index 00000000000000..b7255d87b309da --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/mod.rs @@ -0,0 +1,11 @@ +//! Directory: `sys/` +//! +//! https://github.com/NetBSD/src/tree/trunk/sys/sys + +pub(crate) mod file; +pub(crate) mod ipc; +pub(crate) mod socket; +pub(crate) mod statvfs; +pub(crate) mod time; +pub(crate) mod timex; +pub(crate) mod types; diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/socket.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/socket.rs new file mode 100644 index 00000000000000..953526032efef9 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/socket.rs @@ -0,0 +1,44 @@ +//! Header: `sys/socket.h` +//! +//! +//! + +use crate::prelude::*; + +s_no_extra_traits! { + pub union __c_anonymous_pcb_sockaddr_src { + pub _kis_src: crate::sockaddr, + _kis_pad: Padding<[c_char; 256 + 8]>, + } + + pub union __c_anonymous_pcb_sockaddr_dst { + pub _kid_dst: crate::sockaddr, + _kid_pad: Padding<[c_char; 256 + 8]>, + } + + pub struct kinfo_pcb { + pub ki_pcbaddr: u64, + pub ki_ppcbaddr: u64, + pub ki_sockaddr: u64, + pub ki_family: u32, + pub ki_type: u32, + pub ki_protocol: u32, + pub ki_pflags: u32, + pub ki_sostate: u32, + pub ki_prstate: u32, + pub ki_tstate: i32, + pub ki_tflags: u32, + pub ki_rcvq: u64, + pub ki_sndq: u64, + pub ki_s: __c_anonymous_pcb_sockaddr_src, + pub ki_d: __c_anonymous_pcb_sockaddr_dst, + pub ki_inode: u64, + pub ki_vnode: u64, + pub ki_conn: u64, + pub ki_refs: u64, + pub ki_nextref: u64, + } +} + +pub const PCB_SLOP: c_int = 20; +pub const PCB_ALL: c_int = 0; diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/statvfs.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/statvfs.rs new file mode 100644 index 00000000000000..eee3766300ce66 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/statvfs.rs @@ -0,0 +1,47 @@ +//! Header: `sys/statvfs.h` +//! +//! + +use crate::prelude::*; + +const _VFS_NAMELEN: usize = 32; +const _VFS_MNAMELEN: usize = 1024; + +s! { + pub struct statvfs { + pub f_flag: c_ulong, + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_iosize: c_ulong, + + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_bresvd: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fresvd: crate::fsfilcnt_t, + + pub f_syncreads: u64, + pub f_syncwrites: u64, + + pub f_asyncreads: u64, + pub f_asyncwrites: u64, + + pub f_fsidx: crate::fsid_t, + pub f_fsid: c_ulong, + pub f_namemax: c_ulong, + pub f_owner: crate::uid_t, + + // This type is updated in a future version + f_spare: [u32; 4], + + pub f_fstypename: [c_char; _VFS_NAMELEN], + pub f_mntonname: [c_char; _VFS_MNAMELEN], + pub f_mntfromname: [c_char; _VFS_MNAMELEN], + // Added in NetBSD10 + // pub f_mntfromlabel: [c_char; _VFS_MNAMELEN], + } +} diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/time.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/time.rs new file mode 100644 index 00000000000000..b776b2a7db911a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/time.rs @@ -0,0 +1,15 @@ +//! Header: `sys/time.h` +//! +//! + +s! { + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } +} + +pub const CLOCK_VIRTUAL: crate::clockid_t = 1; +pub const CLOCK_PROF: crate::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 0x20000000; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 0x40000000; diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/timex.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/timex.rs new file mode 100644 index 00000000000000..82844bf0e732d0 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/timex.rs @@ -0,0 +1,95 @@ +//! Header: `sys/timex.h` +//! +//! + +use crate::prelude::*; + +pub const MAXPHASE: c_long = 500000000; +pub const MAXFREQ: c_long = 500000; +pub const MINSEC: c_int = 256; +pub const MAXSEC: c_int = 2048; +pub const NANOSECOND: c_long = 1000000000; +pub const SCALE_PPM: c_int = 65; +pub const MAXTC: c_int = 10; + +pub const MOD_OFFSET: c_uint = 0x0001; +pub const MOD_FREQUENCY: c_uint = 0x0002; +pub const MOD_MAXERROR: c_uint = 0x0004; +pub const MOD_ESTERROR: c_uint = 0x0008; +pub const MOD_STATUS: c_uint = 0x0010; +pub const MOD_TIMECONST: c_uint = 0x0020; +pub const MOD_PPSMAX: c_uint = 0x0040; +pub const MOD_TAI: c_uint = 0x0080; +pub const MOD_MICRO: c_uint = 0x1000; +pub const MOD_NANO: c_uint = 0x2000; +pub const MOD_CLKB: c_uint = 0x4000; +pub const MOD_CLKA: c_uint = 0x8000; + +pub const STA_PLL: c_int = 0x0001; +pub const STA_PPSFREQ: c_int = 0x0002; +pub const STA_PPSTIME: c_int = 0x0004; +pub const STA_FLL: c_int = 0x0008; +pub const STA_INS: c_int = 0x0010; +pub const STA_DEL: c_int = 0x0020; +pub const STA_UNSYNC: c_int = 0x0040; +pub const STA_FREQHOLD: c_int = 0x0080; +pub const STA_PPSSIGNAL: c_int = 0x0100; +pub const STA_PPSJITTER: c_int = 0x0200; +pub const STA_PPSWANDER: c_int = 0x0400; +pub const STA_PPSERROR: c_int = 0x0800; +pub const STA_CLOCKERR: c_int = 0x1000; +pub const STA_NANO: c_int = 0x2000; +pub const STA_MODE: c_int = 0x4000; +pub const STA_CLK: c_int = 0x8000; + +pub const STA_RONLY: c_int = STA_PPSSIGNAL + | STA_PPSJITTER + | STA_PPSWANDER + | STA_PPSERROR + | STA_CLOCKERR + | STA_NANO + | STA_MODE + | STA_CLK; + +pub const TIME_OK: c_int = 0; +pub const TIME_INS: c_int = 1; +pub const TIME_DEL: c_int = 2; +pub const TIME_OOP: c_int = 3; +pub const TIME_WAIT: c_int = 4; +pub const TIME_ERROR: c_int = 5; + +s! { + pub struct ntptimeval { + pub time: crate::timespec, + pub maxerror: c_long, + pub esterror: c_long, + pub tai: c_long, + pub time_state: c_int, + } + + pub struct timex { + pub modes: c_uint, + pub offset: c_long, + pub freq: c_long, + pub maxerror: c_long, + pub esterror: c_long, + pub status: c_int, + pub constant: c_long, + pub precision: c_long, + pub tolerance: c_long, + pub ppsfreq: c_long, + pub jitter: c_long, + pub shift: c_int, + pub stabil: c_long, + pub jitcnt: c_long, + pub calcnt: c_long, + pub errcnt: c_long, + pub stbcnt: c_long, + } +} + +extern "C" { + #[link_name = "__ntp_gettime50"] + pub fn ntp_gettime(buf: *mut ntptimeval) -> c_int; + pub fn ntp_adjtime(buf: *mut timex) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/netbsd/sys/types.rs b/deps/crates/vendor/libc/src/new/netbsd/sys/types.rs new file mode 100644 index 00000000000000..8dfc0494261701 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/sys/types.rs @@ -0,0 +1,16 @@ +//! Header: `sys/types.h` +//! +//! + +use crate::prelude::*; + +pub type dev_t = u64; + +pub type lwpid_t = i32; + +pub type mqd_t = c_int; +pub type cpuid_t = c_ulong; + +pub type clock_t = c_uint; +pub type timer_t = c_int; +pub type suseconds_t = c_int; diff --git a/deps/crates/vendor/libc/src/new/netbsd/unistd.rs b/deps/crates/vendor/libc/src/new/netbsd/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/netbsd/utmp_.rs b/deps/crates/vendor/libc/src/new/netbsd/utmp_.rs new file mode 100644 index 00000000000000..2047449053ce8f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/utmp_.rs @@ -0,0 +1,33 @@ +//! Header: `utmp.h` +//! +//! + +use crate::prelude::*; + +pub const UT_NAMESIZE: usize = 8; +pub const UT_LINESIZE: usize = 8; +pub const UT_HOSTSIZE: usize = 16; + +s! { + pub struct lastlog { + pub ll_time: crate::time_t, + pub ll_line: [c_char; UT_LINESIZE], + pub ll_host: [c_char; UT_HOSTSIZE], + } + + pub struct utmp { + pub ut_line: [c_char; UT_LINESIZE], + pub ut_name: [c_char; UT_NAMESIZE], + pub ut_host: [c_char; UT_HOSTSIZE], + pub ut_time: crate::time_t, + } +} + +#[link(name = "util")] +extern "C" { + pub fn utmpname(file: *const c_char) -> c_int; + pub fn setutent(); + #[link_name = "__getutent50"] + pub fn getutent() -> *mut utmp; + pub fn endutent(); +} diff --git a/deps/crates/vendor/libc/src/new/netbsd/utmpx_.rs b/deps/crates/vendor/libc/src/new/netbsd/utmpx_.rs new file mode 100644 index 00000000000000..7b07b0c1266437 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/netbsd/utmpx_.rs @@ -0,0 +1,92 @@ +//! Header: `utmpx.h` +//! +//! + +use crate::prelude::*; + +// pub const _PATH_UTMPX: &[c_char; 14] = b"/var/run/utmpx"; +// pub const _PATH_WTMPX: &[c_char; 14] = b"/var/log/wtmpx"; +// pub const _PATH_LASTLOGX: &[c_char; 17] = b"/var/log/lastlogx"; +// pub const _PATH_UTMP_UPDATE: &[c_char; 24] = b"/usr/libexec/utmp_update"; + +pub const _UTX_USERSIZE: usize = 32; +pub const _UTX_LINESIZE: usize = 32; +pub const _UTX_IDSIZE: usize = 4; +pub const _UTX_HOSTSIZE: usize = 256; + +pub const EMPTY: u16 = 0; +pub const RUN_LVL: u16 = 1; +pub const BOOT_TIME: u16 = 2; +pub const OLD_TIME: u16 = 3; +pub const NEW_TIME: u16 = 4; +pub const INIT_PROCESS: u16 = 5; +pub const LOGIN_PROCESS: u16 = 6; +pub const USER_PROCESS: u16 = 7; +pub const DEAD_PROCESS: u16 = 8; +pub const ACCOUNTING: u16 = 9; +pub const SIGNATURE: u16 = 10; +pub const DOWN_TIME: u16 = 11; + +// Expression based on the comment in NetBSD source. +pub const _UTX_PADSIZE: usize = if cfg!(target_pointer_width = "64") { + 36 +} else { + 40 +}; + +s! { + pub struct utmpx { + pub ut_name: [c_char; _UTX_USERSIZE], + pub ut_id: [c_char; _UTX_IDSIZE], + pub ut_line: [c_char; _UTX_LINESIZE], + pub ut_host: [c_char; _UTX_HOSTSIZE], + pub ut_session: u16, + pub ut_type: u16, + pub ut_pid: crate::pid_t, + pub ut_exit: __exit_status, // FIXME(netbsd): when anonymous struct are supported + pub ut_ss: crate::sockaddr_storage, + pub ut_tv: crate::timeval, + ut_pad: Padding<[u8; _UTX_PADSIZE]>, + } + + pub struct __exit_status { + pub e_termination: u16, + pub e_exit: u16, + } + + pub struct lastlogx { + pub ll_tv: crate::timeval, + pub ll_line: [c_char; _UTX_LINESIZE], + pub ll_host: [c_char; _UTX_HOSTSIZE], + pub ll_ss: crate::sockaddr_storage, + } +} + +#[link(name = "util")] +extern "C" { + pub fn setutxent(); + pub fn endutxent(); + + #[link_name = "__getutxent50"] + pub fn getutxent() -> *mut utmpx; + #[link_name = "__getutxid50"] + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + #[link_name = "__getutxline50"] + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + #[link_name = "__pututxline50"] + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + + #[link_name = "__updwtmpx50"] + pub fn updwtmpx(file: *const c_char, ut: *const utmpx) -> c_int; + #[link_name = "__getlastlogx50"] + pub fn getlastlogx(fname: *const c_char, uid: crate::uid_t, ll: *mut lastlogx) + -> *mut lastlogx; + + #[link_name = "__updlastlogx50"] + pub fn updlastlogx(fname: *const c_char, uid: crate::uid_t, ll: *mut lastlogx) -> c_int; + #[link_name = "__getutmp50"] + pub fn getutmp(ux: *const utmpx, u: *mut crate::utmp); + #[link_name = "__getutmpx50"] + pub fn getutmpx(u: *const crate::utmp, ux: *mut utmpx); + pub fn utmpxname(file: *const c_char) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/newlib/mod.rs b/deps/crates/vendor/libc/src/new/newlib/mod.rs new file mode 100644 index 00000000000000..b5c7e3dc73a0a7 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/newlib/mod.rs @@ -0,0 +1,4 @@ +//! Newlib libc. +// FIXME(newlib): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/newlib/unistd.rs b/deps/crates/vendor/libc/src/new/newlib/unistd.rs new file mode 100644 index 00000000000000..6b240be9b7698e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/newlib/unistd.rs @@ -0,0 +1,159 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; +use crate::prelude::*; + +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_JOB_CONTROL: c_int = 5; +pub const _SC_SAVED_IDS: c_int = 6; +pub const _SC_VERSION: c_int = 7; +pub const _SC_PAGESIZE: c_int = 8; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_NPROCESSORS_CONF: c_int = 9; +pub const _SC_NPROCESSORS_ONLN: c_int = 10; +pub const _SC_PHYS_PAGES: c_int = 11; +pub const _SC_AVPHYS_PAGES: c_int = 12; +pub const _SC_MQ_OPEN_MAX: c_int = 13; +pub const _SC_MQ_PRIO_MAX: c_int = 14; +pub const _SC_RTSIG_MAX: c_int = 15; +pub const _SC_SEM_NSEMS_MAX: c_int = 16; +pub const _SC_SEM_VALUE_MAX: c_int = 17; +pub const _SC_SIGQUEUE_MAX: c_int = 18; +pub const _SC_TIMER_MAX: c_int = 19; +pub const _SC_TZNAME_MAX: c_int = 20; +pub const _SC_ASYNCHRONOUS_IO: c_int = 21; +pub const _SC_FSYNC: c_int = 22; +pub const _SC_MAPPED_FILES: c_int = 23; +pub const _SC_MEMLOCK: c_int = 24; +pub const _SC_MEMLOCK_RANGE: c_int = 25; +pub const _SC_MEMORY_PROTECTION: c_int = 26; +pub const _SC_MESSAGE_PASSING: c_int = 27; +pub const _SC_PRIORITIZED_IO: c_int = 28; +pub const _SC_REALTIME_SIGNALS: c_int = 29; +pub const _SC_SEMAPHORES: c_int = 30; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 31; +pub const _SC_SYNCHRONIZED_IO: c_int = 32; +pub const _SC_TIMERS: c_int = 33; +pub const _SC_AIO_LISTIO_MAX: c_int = 34; +pub const _SC_AIO_MAX: c_int = 35; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 36; +pub const _SC_DELAYTIMER_MAX: c_int = 37; +pub const _SC_THREAD_KEYS_MAX: c_int = 38; +pub const _SC_THREAD_STACK_MIN: c_int = 39; +pub const _SC_THREAD_THREADS_MAX: c_int = 40; +pub const _SC_TTY_NAME_MAX: c_int = 41; +pub const _SC_THREADS: c_int = 42; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 43; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 44; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 45; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 46; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 47; +pub const _SC_THREAD_PRIO_CEILING: c_int = _SC_THREAD_PRIO_PROTECT; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 48; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 49; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 50; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 51; +pub const _SC_LOGIN_NAME_MAX: c_int = 52; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 53; +pub const _SC_ADVISORY_INFO: c_int = 54; +pub const _SC_ATEXIT_MAX: c_int = 55; +pub const _SC_BARRIERS: c_int = 56; +pub const _SC_BC_BASE_MAX: c_int = 57; +pub const _SC_BC_DIM_MAX: c_int = 58; +pub const _SC_BC_SCALE_MAX: c_int = 59; +pub const _SC_BC_STRING_MAX: c_int = 60; +pub const _SC_CLOCK_SELECTION: c_int = 61; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 62; +pub const _SC_CPUTIME: c_int = 63; +pub const _SC_EXPR_NEST_MAX: c_int = 64; +pub const _SC_HOST_NAME_MAX: c_int = 65; +pub const _SC_IOV_MAX: c_int = 66; +pub const _SC_IPV6: c_int = 67; +pub const _SC_LINE_MAX: c_int = 68; +pub const _SC_MONOTONIC_CLOCK: c_int = 69; +pub const _SC_RAW_SOCKETS: c_int = 70; +pub const _SC_READER_WRITER_LOCKS: c_int = 71; +pub const _SC_REGEXP: c_int = 72; +pub const _SC_RE_DUP_MAX: c_int = 73; +pub const _SC_SHELL: c_int = 74; +pub const _SC_SPAWN: c_int = 75; +pub const _SC_SPIN_LOCKS: c_int = 76; +pub const _SC_SPORADIC_SERVER: c_int = 77; +pub const _SC_SS_REPL_MAX: c_int = 78; +pub const _SC_SYMLOOP_MAX: c_int = 79; +pub const _SC_THREAD_CPUTIME: c_int = 80; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 81; +pub const _SC_TIMEOUTS: c_int = 82; +pub const _SC_TRACE: c_int = 83; +pub const _SC_TRACE_EVENT_FILTER: c_int = 84; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 85; +pub const _SC_TRACE_INHERIT: c_int = 86; +pub const _SC_TRACE_LOG: c_int = 87; +pub const _SC_TRACE_NAME_MAX: c_int = 88; +pub const _SC_TRACE_SYS_MAX: c_int = 89; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 90; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 91; +pub const _SC_V7_ILP32_OFF32: c_int = 92; +pub const _SC_V6_ILP32_OFF32: c_int = _SC_V7_ILP32_OFF32; +pub const _SC_XBS5_ILP32_OFF32: c_int = _SC_V7_ILP32_OFF32; +pub const _SC_V7_ILP32_OFFBIG: c_int = 93; +pub const _SC_V6_ILP32_OFFBIG: c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_V7_LP64_OFF64: c_int = 94; +pub const _SC_V6_LP64_OFF64: c_int = _SC_V7_LP64_OFF64; +pub const _SC_XBS5_LP64_OFF64: c_int = _SC_V7_LP64_OFF64; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 95; +pub const _SC_V6_LPBIG_OFFBIG: c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XOPEN_CRYPT: c_int = 96; +pub const _SC_XOPEN_ENH_I18N: c_int = 97; +pub const _SC_XOPEN_LEGACY: c_int = 98; +pub const _SC_XOPEN_REALTIME: c_int = 99; +pub const _SC_STREAM_MAX: c_int = 100; +pub const _SC_PRIORITY_SCHEDULING: c_int = 101; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 102; +pub const _SC_XOPEN_SHM: c_int = 103; +pub const _SC_XOPEN_STREAMS: c_int = 104; +pub const _SC_XOPEN_UNIX: c_int = 105; +pub const _SC_XOPEN_VERSION: c_int = 106; +pub const _SC_2_CHAR_TERM: c_int = 107; +pub const _SC_2_C_BIND: c_int = 108; +pub const _SC_2_C_DEV: c_int = 109; +pub const _SC_2_FORT_DEV: c_int = 110; +pub const _SC_2_FORT_RUN: c_int = 111; +pub const _SC_2_LOCALEDEF: c_int = 112; +pub const _SC_2_PBS: c_int = 113; +pub const _SC_2_PBS_ACCOUNTING: c_int = 114; +pub const _SC_2_PBS_CHECKPOINT: c_int = 115; +pub const _SC_2_PBS_LOCATE: c_int = 116; +pub const _SC_2_PBS_MESSAGE: c_int = 117; +pub const _SC_2_PBS_TRACK: c_int = 118; +pub const _SC_2_SW_DEV: c_int = 119; +pub const _SC_2_UPE: c_int = 120; +pub const _SC_2_VERSION: c_int = 121; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 122; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 123; +pub const _SC_XOPEN_UUCP: c_int = 124; +pub const _SC_LEVEL1_ICACHE_SIZE: c_int = 125; +pub const _SC_LEVEL1_ICACHE_ASSOC: c_int = 126; +pub const _SC_LEVEL1_ICACHE_LINESIZE: c_int = 127; +pub const _SC_LEVEL1_DCACHE_SIZE: c_int = 128; +pub const _SC_LEVEL1_DCACHE_ASSOC: c_int = 129; +pub const _SC_LEVEL1_DCACHE_LINESIZE: c_int = 130; +pub const _SC_LEVEL2_CACHE_SIZE: c_int = 131; +pub const _SC_LEVEL2_CACHE_ASSOC: c_int = 132; +pub const _SC_LEVEL2_CACHE_LINESIZE: c_int = 133; +pub const _SC_LEVEL3_CACHE_SIZE: c_int = 134; +pub const _SC_LEVEL3_CACHE_ASSOC: c_int = 135; +pub const _SC_LEVEL3_CACHE_LINESIZE: c_int = 136; +pub const _SC_LEVEL4_CACHE_SIZE: c_int = 137; +pub const _SC_LEVEL4_CACHE_ASSOC: c_int = 138; +pub const _SC_LEVEL4_CACHE_LINESIZE: c_int = 139; diff --git a/deps/crates/vendor/libc/src/new/nto/mod.rs b/deps/crates/vendor/libc/src/new/nto/mod.rs new file mode 100644 index 00000000000000..a625127ecd45e1 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nto/mod.rs @@ -0,0 +1,9 @@ +//! QNX Neutrino libc. +// FIXME(nto): link to manpages needed. + +pub(crate) mod unistd; + +pub(crate) mod net { + pub(crate) mod bpf; + pub(crate) mod if_; +} diff --git a/deps/crates/vendor/libc/src/new/nto/net/bpf.rs b/deps/crates/vendor/libc/src/new/nto/net/bpf.rs new file mode 100644 index 00000000000000..8b8dd71dc2ae03 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nto/net/bpf.rs @@ -0,0 +1,83 @@ +use crate::bpf_insn; + +pub const BPF_LD: u16 = 0x00; +pub const BPF_LDX: u16 = 0x01; +pub const BPF_ST: u16 = 0x02; +pub const BPF_STX: u16 = 0x03; +pub const BPF_ALU: u16 = 0x04; +pub const BPF_JMP: u16 = 0x05; +pub const BPF_RET: u16 = 0x06; +pub const BPF_MISC: u16 = 0x07; +pub const BPF_W: u16 = 0x00; +pub const BPF_H: u16 = 0x08; +pub const BPF_B: u16 = 0x10; +pub const BPF_IMM: u16 = 0x00; +pub const BPF_ABS: u16 = 0x20; +pub const BPF_IND: u16 = 0x40; +pub const BPF_MEM: u16 = 0x60; +pub const BPF_LEN: u16 = 0x80; +pub const BPF_MSH: u16 = 0xa0; +pub const BPF_ADD: u16 = 0x00; +pub const BPF_SUB: u16 = 0x10; +pub const BPF_MUL: u16 = 0x20; +pub const BPF_DIV: u16 = 0x30; +pub const BPF_OR: u16 = 0x40; +pub const BPF_AND: u16 = 0x50; +pub const BPF_LSH: u16 = 0x60; +pub const BPF_RSH: u16 = 0x70; +pub const BPF_NEG: u16 = 0x80; +pub const BPF_MOD: u16 = 0x90; +pub const BPF_XOR: u16 = 0xa0; +pub const BPF_JA: u16 = 0x00; +pub const BPF_JEQ: u16 = 0x10; +pub const BPF_JGT: u16 = 0x20; +pub const BPF_JGE: u16 = 0x30; +pub const BPF_JSET: u16 = 0x40; +pub const BPF_K: u16 = 0x00; +pub const BPF_X: u16 = 0x08; +pub const BPF_A: u16 = 0x10; +pub const BPF_TAX: u16 = 0x00; +pub const BPF_TXA: u16 = 0x80; + +f! { + pub fn BPF_CLASS(code: u32) -> u32 { + code & 0x07 + } + + pub fn BPF_SIZE(code: u32) -> u32 { + code & 0x18 + } + + pub fn BPF_MODE(code: u32) -> u32 { + code & 0xe0 + } + + pub fn BPF_OP(code: u32) -> u32 { + code & 0xf0 + } + + pub fn BPF_SRC(code: u32) -> u32 { + code & 0x08 + } + + pub fn BPF_RVAL(code: u32) -> u32 { + code & 0x18 + } + + pub fn BPF_MISCOP(code: u32) -> u32 { + code & 0xf8 + } + + pub fn BPF_STMT(code: u16, k: u32) -> bpf_insn { + bpf_insn { + code, + jt: 0, + jf: 0, + k, + } + } + + pub fn BPF_JUMP(code: u16, k: u32, jt: u8, jf: u8) -> bpf_insn { + bpf_insn { code, jt, jf, k } + } +} diff --git a/deps/crates/vendor/libc/src/new/nto/net/if_.rs b/deps/crates/vendor/libc/src/new/nto/net/if_.rs new file mode 100644 index 00000000000000..d71c1bb24b32ed --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nto/net/if_.rs @@ -0,0 +1,32 @@ +use crate::prelude::*; + +s_no_extra_traits! { + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_buffer: ifreq_buffer, + pub ifru_flags: [c_short; 2], + pub ifru_index: c_short, + pub ifru_jid: c_int, + pub ifru_metric: c_int, + pub ifru_mtu: c_int, + pub ifru_phys: c_int, + pub ifru_media: c_int, + pub ifru_data: *mut c_char, + pub ifru_cap: [c_int; 2], + pub ifru_fib: c_uint, + pub ifru_vlan_pcp: c_uchar, + } + + pub struct ifreq { + /// if name, e.g. "en0" + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub struct ifreq_buffer { + pub length: size_t, + pub buffer: *mut c_void, + } +} diff --git a/deps/crates/vendor/libc/src/new/nto/unistd.rs b/deps/crates/vendor/libc/src/new/nto/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nto/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/nuttx/mod.rs b/deps/crates/vendor/libc/src/new/nuttx/mod.rs new file mode 100644 index 00000000000000..513c945dbfd9bb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nuttx/mod.rs @@ -0,0 +1,4 @@ +//! RTEMS libc. +// FIXME(nuttx): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/nuttx/unistd.rs b/deps/crates/vendor/libc/src/new/nuttx/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/nuttx/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/openbsd/mod.rs b/deps/crates/vendor/libc/src/new/openbsd/mod.rs new file mode 100644 index 00000000000000..25fa784b2b0049 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/openbsd/mod.rs @@ -0,0 +1,7 @@ +//! OpenBSD libc. +//! +//! * Headers: +//! * Manual pages: + +pub(crate) mod sys; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/openbsd/sys/ipc.rs b/deps/crates/vendor/libc/src/new/openbsd/sys/ipc.rs new file mode 100644 index 00000000000000..59774405bcdd05 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/openbsd/sys/ipc.rs @@ -0,0 +1,17 @@ +//! Header: `sys/ipc.h` +//! +//! + +use crate::prelude::*; + +s! { + pub struct ipc_perm { + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub mode: crate::mode_t, + pub seq: c_ushort, + pub key: crate::key_t, + } +} diff --git a/deps/crates/vendor/libc/src/new/openbsd/sys/mod.rs b/deps/crates/vendor/libc/src/new/openbsd/sys/mod.rs new file mode 100644 index 00000000000000..7ba77c537356ea --- /dev/null +++ b/deps/crates/vendor/libc/src/new/openbsd/sys/mod.rs @@ -0,0 +1,5 @@ +//! Directory: `sys/` +//! +//! https://github.com/openbsd/src/tree/trunk/sys/sys + +pub(crate) mod ipc; diff --git a/deps/crates/vendor/libc/src/new/openbsd/unistd.rs b/deps/crates/vendor/libc/src/new/openbsd/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/openbsd/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/qurt/dlfcn.rs b/deps/crates/vendor/libc/src/new/qurt/dlfcn.rs new file mode 100644 index 00000000000000..668fcab54c2a5c --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/dlfcn.rs @@ -0,0 +1,26 @@ +//! Header: `dlfcn.h` +//! +//! Dynamic linking functions and constants from Hexagon toolchain. + +use crate::prelude::*; + +// Values for dlopen `mode` +pub const RTLD_LAZY: c_int = 1; +pub const RTLD_NOW: c_int = 2; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_LOCAL: c_int = 0x200; + +// Compatibility constant +pub const DL_LAZY: c_int = RTLD_LAZY; + +// Special handles +pub const RTLD_NEXT: *mut c_void = -1isize as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = -2isize as *mut c_void; +pub const RTLD_SELF: *mut c_void = -3isize as *mut c_void; + +extern "C" { + pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void; + pub fn dlclose(handle: *mut c_void) -> c_int; + pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; + pub fn dlerror() -> *mut c_char; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/errno.rs b/deps/crates/vendor/libc/src/new/qurt/errno.rs new file mode 100644 index 00000000000000..09db55c618a247 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/errno.rs @@ -0,0 +1,154 @@ +//! Header: `errno.h` + +use super::*; +use crate::prelude::*; + +// Standard error codes - verified to match QuRT SDK +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EMULTIHOP: c_int = 72; +pub const EDOTDOT: c_int = 73; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +extern "C" { + // Error number access + #[link_name = "__errno_location"] + pub fn __errno_location() -> *mut c_int; +} + +pub unsafe fn errno() -> c_int { + *__errno_location() +} + +pub unsafe fn set_errno(value: c_int) { + *__errno_location() = value; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/fcntl.rs b/deps/crates/vendor/libc/src/new/qurt/fcntl.rs new file mode 100644 index 00000000000000..0287292ad2f8e7 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/fcntl.rs @@ -0,0 +1,52 @@ +//! Header: `fcntl.h` + +use super::*; +use crate::prelude::*; + +// File access modes +pub const O_RDONLY: c_int = 0x0000; +pub const O_WRONLY: c_int = 0x0001; +pub const O_RDWR: c_int = 0x0002; +pub const O_ACCMODE: c_int = 0x0003; + +// File creation flags +pub const O_CREAT: c_int = 0x0040; +pub const O_EXCL: c_int = 0x0080; +pub const O_NOCTTY: c_int = 0x0100; +pub const O_TRUNC: c_int = 0x0200; + +// File status flags +pub const O_APPEND: c_int = 0x0400; +pub const O_NONBLOCK: c_int = 0x0800; +pub const O_SYNC: c_int = 0x1000; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_DSYNC: c_int = 0x1000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_CLOEXEC: c_int = 0x80000; + +// fcntl() commands +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETLK: c_int = 5; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_DUPFD_CLOEXEC: c_int = 1030; + +// File descriptor flags +pub const FD_CLOEXEC: c_int = 1; + +// Lock types for fcntl() +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; + +// Functions +extern "C" { + pub fn open(pathname: *const c_char, flags: c_int, ...) -> c_int; + pub fn creat(pathname: *const c_char, mode: mode_t) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/limits.rs b/deps/crates/vendor/libc/src/new/qurt/limits.rs new file mode 100644 index 00000000000000..ae1a007ff1c66e --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/limits.rs @@ -0,0 +1,41 @@ +//! Header: `limits.h` + +use super::*; +use crate::prelude::*; + +// Character properties +pub const CHAR_BIT: c_uint = 8; +pub const CHAR_MAX: c_char = 255; // unsigned char on Hexagon +pub const CHAR_MIN: c_char = 0; +pub const SCHAR_MAX: c_schar = 127; +pub const SCHAR_MIN: c_schar = -128; +pub const UCHAR_MAX: c_uchar = 255; + +// Integer properties +pub const INT_MAX: c_int = 2147483647; +pub const INT_MIN: c_int = (-2147483647 - 1); +pub const UINT_MAX: c_uint = 4294967295; + +pub const LONG_MAX: c_long = 2147483647; +pub const LONG_MIN: c_long = (-2147483647 - 1); +pub const ULONG_MAX: c_ulong = 4294967295; + +pub const SHRT_MAX: c_short = 32767; +pub const SHRT_MIN: c_short = (-32768); +pub const USHRT_MAX: c_ushort = 65535; + +// POSIX Limits +pub const ARG_MAX: c_int = 4096; +pub const CHILD_MAX: c_int = 25; +pub const LINK_MAX: c_int = 8; +pub const MAX_CANON: c_int = 255; +pub const MAX_INPUT: c_int = 255; +pub const NAME_MAX: c_int = 255; +pub const OPEN_MAX: c_int = 20; +pub const PATH_MAX: c_int = 260; +pub const PIPE_BUF: c_int = 512; +pub const STREAM_MAX: c_int = 20; +pub const TZNAME_MAX: c_int = 50; + +// Additional limits +pub const IOV_MAX: c_int = 16; diff --git a/deps/crates/vendor/libc/src/new/qurt/mod.rs b/deps/crates/vendor/libc/src/new/qurt/mod.rs new file mode 100644 index 00000000000000..52d7ae04881e15 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/mod.rs @@ -0,0 +1,375 @@ +//! QuRT (Qualcomm Real-Time OS) bindings +//! +//! QuRT is Qualcomm's real-time operating system for Hexagon DSP architectures. +//! Headers available via the +//! Hexagon SDK: https://softwarecenter.qualcomm.com/catalog/item/Hexagon_SDK + +use crate::prelude::*; + +// Basic C types for QuRT +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ptrdiff_t = isize; +pub type size_t = uintptr_t; +pub type ssize_t = c_int; + +// Process and system types +pub type pid_t = c_int; +pub type uid_t = c_uint; +pub type gid_t = c_uint; + +// Time types +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type useconds_t = c_ulong; +pub type clockid_t = c_int; +pub type timer_t = *mut c_void; + +// File system types +pub type dev_t = c_ulonglong; +pub type ino_t = c_ulonglong; +pub type mode_t = c_uint; +pub type nlink_t = c_uint; +pub type off_t = c_long; +pub type blkcnt_t = c_long; +pub type blksize_t = c_long; + +// Thread types based on QuRT pthread implementation +pub type pthread_t = c_uint; +pub type pthread_key_t = c_int; +pub type pthread_once_t = c_int; +pub type pthread_mutex_t = c_uint; +pub type pthread_mutexattr_t = c_uint; +pub type pthread_cond_t = c_uint; +pub type pthread_condattr_t = c_uint; +pub type pthread_attr_t = c_uint; +pub type pthread_rwlock_t = c_uint; +pub type pthread_rwlockattr_t = c_uint; +pub type pthread_spinlock_t = c_uint; +pub type pthread_barrier_t = c_uint; +pub type pthread_barrierattr_t = c_uint; + +// Network types +pub type socklen_t = c_uint; +pub type sa_family_t = c_ushort; +pub type in_addr_t = c_uint; +pub type in_port_t = c_ushort; + +// File descriptor types +pub type fd_set = c_ulong; + +// Standard C library types +extern_ty! { + pub enum FILE {} +} +pub type fpos_t = c_long; +pub type clock_t = c_long; + +// POSIX semaphore types +pub type sem_t = c_uint; + +// Message queue types +pub type mqd_t = c_int; + +// Additional file system types +pub type nfds_t = c_ulong; + +// Signal types +pub type sigset_t = c_ulong; + +// Variadic argument list type +pub type va_list = *mut c_char; + +// Additional missing types +pub type c_schar = i8; + +// Wide character type (hexagon-specific) +pub type wchar_t = u32; + +// Error type (compatible with std expectations) +pub type errno_t = c_int; + +// Resource limit type (for compatibility, not fully supported on QuRT) +pub type rlim_t = c_ulong; + +// Terminal types (for compatibility, not fully supported on QuRT) +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; + +// Division result types and structures +s! { + pub struct div_t { + pub quot: c_int, + pub rem: c_int, + } + + pub struct ldiv_t { + pub quot: c_long, + pub rem: c_long, + } + + pub struct lldiv_t { + pub quot: c_longlong, + pub rem: c_longlong, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_mtime: time_t, + pub st_ctime: time_t, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, + } + + pub struct dirent { + pub d_ino: c_long, + pub d_name: [c_char; 255], + } + + pub struct DIR { + pub index: c_int, + pub entry: dirent, + } + + // Terminal I/O structure (for compatibility, limited support on QuRT) + pub struct termios { + pub c_iflag: tcflag_t, + pub c_oflag: tcflag_t, + pub c_cflag: tcflag_t, + pub c_lflag: tcflag_t, + pub c_cc: [c_uchar; 32], + pub c_ispeed: speed_t, + pub c_ospeed: speed_t, + } + + // Resource limit structures (for compatibility, limited support on QuRT) + pub struct rlimit { + pub rlim_cur: rlim_t, + pub rlim_max: rlim_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + pub ru_ixrss: c_long, + pub ru_idrss: c_long, + pub ru_isrss: c_long, + pub ru_minflt: c_long, + pub ru_majflt: c_long, + pub ru_nswap: c_long, + pub ru_inblock: c_long, + pub ru_oublock: c_long, + pub ru_msgsnd: c_long, + pub ru_msgrcv: c_long, + pub ru_nsignals: c_long, + pub ru_nvcsw: c_long, + pub ru_nivcsw: c_long, + } + + // File lock structure (for compatibility) + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: pid_t, + } +} + +// Additional pthread constants +pub const PTHREAD_NAME_LEN: c_int = 16; +pub const PTHREAD_MAX_THREADS: c_uint = 512; +pub const PTHREAD_MIN_STACKSIZE: c_int = 512; +pub const PTHREAD_MAX_STACKSIZE: c_int = 1048576; +pub const PTHREAD_DEFAULT_STACKSIZE: c_int = 16384; +pub const PTHREAD_DEFAULT_PRIORITY: c_int = 1; +pub const PTHREAD_SPINLOCK_UNLOCKED: c_int = 0; +pub const PTHREAD_SPINLOCK_LOCKED: c_int = 1; + +// Additional time constants +pub const TIME_CONV_SCLK_FREQ: c_int = 19200000; +pub const CLOCK_MONOTONIC_RAW: clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: clockid_t = 6; +pub const CLOCK_BOOTTIME: clockid_t = 7; + +// Stdio constants +pub const L_tmpnam: c_uint = 260; +pub const TMP_MAX: c_uint = 25; +pub const FOPEN_MAX: c_uint = 20; + +// Error constants +pub const EOK: c_int = 0; + +// Semaphore constants +pub const SEM_FAILED: *mut sem_t = 0 as *mut sem_t; + +// Page size constants (hexagon-specific) +pub const PAGESIZE: size_t = 4096; +pub const PAGE_SIZE: size_t = 4096; + +// Directory entry types (hexagon-specific) +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; + +// Directory functions (dirent.h) +extern "C" { + pub fn opendir(name: *const c_char) -> *mut DIR; + pub fn readdir(dirp: *mut DIR) -> *mut dirent; + pub fn closedir(dirp: *const DIR) -> c_int; + pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; +} + +// Additional pthread functions +extern "C" { + pub fn pthread_attr_getstack( + attr: *const pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setstack( + attr: *mut pthread_attr_t, + stackaddr: *mut c_void, + stacksize: size_t, + ) -> c_int; +} + +// Additional time functions +extern "C" { + pub fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c_int; +} + +// POSIX semaphore functions +extern "C" { + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; +} + +// Additional stdlib functions +extern "C" { + pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void; +} + +// String functions (string.h) +extern "C" { + pub fn strlen(s: *const c_char) -> size_t; + pub fn strcpy(dest: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dest: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcat(dest: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncat(dest: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + pub fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strxfrm(dest: *mut c_char, src: *const c_char, n: size_t) -> size_t; + pub fn strchr(s: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(s: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(s: *const c_char, accept: *const c_char) -> size_t; + pub fn strcspn(s: *const c_char, reject: *const c_char) -> size_t; + pub fn strpbrk(s: *const c_char, accept: *const c_char) -> *mut c_char; + pub fn strstr(haystack: *const c_char, needle: *const c_char) -> *mut c_char; + pub fn strtok(s: *mut c_char, delim: *const c_char) -> *mut c_char; + pub fn strerror(errnum: c_int) -> *mut c_char; + pub fn memchr(s: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(s1: *const c_void, s2: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_void; +} + +// Additional unistd functions +extern "C" { + pub fn fork() -> pid_t; + pub fn execve( + filename: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; +} + +// Character classification functions (ctype.h) +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; +} + +pub(crate) mod dlfcn; +pub(crate) mod errno; +pub(crate) mod fcntl; +pub(crate) mod limits; +pub(crate) mod pthread; +pub(crate) mod semaphore; +pub(crate) mod signal; +pub(crate) mod stdio; +pub(crate) mod stdlib; +pub(crate) mod sys; +pub(crate) mod time; +pub(crate) mod unistd; + +// Re-export public items from submodules +pub use dlfcn::*; +pub use errno::*; +pub use fcntl::*; +pub use limits::*; +pub use pthread::*; +pub use semaphore::*; +pub use signal::*; +pub use stdio::*; +pub use stdlib::*; +pub use sys::mman::*; +pub use sys::sched::*; +pub use sys::stat::*; +pub use sys::types::*; +pub use time::*; +pub use unistd::*; diff --git a/deps/crates/vendor/libc/src/new/qurt/pthread.rs b/deps/crates/vendor/libc/src/new/qurt/pthread.rs new file mode 100644 index 00000000000000..543f7874c3dc65 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/pthread.rs @@ -0,0 +1,129 @@ +//! Header: `pthread.h` +//! +//! QuRT provides a subset of POSIX pthread functionality optimized for real-time systems. + +use super::*; +use crate::prelude::*; + +// Thread creation attributes +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +// Mutex types +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; + +// Mutex protocol +pub const PTHREAD_PRIO_NONE: c_int = 0; +pub const PTHREAD_PRIO_INHERIT: c_int = 1; +pub const PTHREAD_PRIO_PROTECT: c_int = 2; + +// Thread priority constants +pub const PTHREAD_MIN_PRIORITY: c_int = 0; +pub const PTHREAD_MAX_PRIORITY: c_int = 255; + +// Initializer constants +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0xFFFFFFFF; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0xFFFFFFFF; +pub const PTHREAD_ONCE_INIT: pthread_once_t = 0; + +// Stack size +pub const PTHREAD_STACK_MIN: size_t = 8192; + +// Additional pthread types and attributes +pub const PTHREAD_SCOPE_SYSTEM: c_int = 0; +pub const PTHREAD_SCOPE_PROCESS: c_int = 1; + +pub const PTHREAD_INHERIT_SCHED: c_int = 0; +pub const PTHREAD_EXPLICIT_SCHED: c_int = 1; + +extern "C" { + // Thread management + pub fn pthread_create( + thread: *mut pthread_t, + attr: *const pthread_attr_t, + start_routine: extern "C" fn(*mut c_void) -> *mut c_void, + arg: *mut c_void, + ) -> c_int; + pub fn pthread_join(thread: pthread_t, retval: *mut *mut c_void) -> c_int; + pub fn pthread_detach(thread: pthread_t) -> c_int; + pub fn pthread_exit(retval: *mut c_void) -> !; + pub fn pthread_self() -> pthread_t; + pub fn pthread_equal(t1: pthread_t, t2: pthread_t) -> c_int; + + // Thread attributes + pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stacksize: size_t) -> c_int; + pub fn pthread_attr_getstacksize(attr: *const pthread_attr_t, stacksize: *mut size_t) -> c_int; + pub fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, detachstate: c_int) -> c_int; + pub fn pthread_attr_getdetachstate( + attr: *const pthread_attr_t, + detachstate: *mut c_int, + ) -> c_int; + + // Mutex operations + pub fn pthread_mutex_init( + mutex: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t, + ) -> c_int; + pub fn pthread_mutex_destroy(mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int; + + // Mutex attributes + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, kind: c_int) -> c_int; + pub fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, kind: *mut c_int) -> c_int; + + // Condition variables + pub fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_cond_timedwait( + cond: *mut pthread_cond_t, + mutex: *mut pthread_mutex_t, + abstime: *const timespec, + ) -> c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int; + + // Condition variable attributes + pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int; + pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clock_id: clockid_t) -> c_int; + + // Thread-local storage + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: Option, + ) -> c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int; + + // One-time initialization + pub fn pthread_once(once_control: *mut pthread_once_t, init_routine: extern "C" fn()) -> c_int; + + // GNU extensions + pub fn pthread_getname_np(thread: pthread_t, name: *mut c_char, len: size_t) -> c_int; + + pub fn pthread_attr_setaffinity_np( + attr: *mut pthread_attr_t, + cpusetsize: size_t, + cpuset: *const cpu_set_t, + ) -> c_int; + + pub fn pthread_attr_getaffinity_np( + attr: *mut pthread_attr_t, + cpusetsize: size_t, + cpuset: *mut cpu_set_t, + ) -> c_int; + + // POSIX standard + pub fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/semaphore.rs b/deps/crates/vendor/libc/src/new/qurt/semaphore.rs new file mode 100644 index 00000000000000..86b37434f394fe --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/semaphore.rs @@ -0,0 +1,13 @@ +//! Header: `semaphore.h` + +use super::*; +use crate::prelude::*; + +extern "C" { + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_wait(sem: *mut sem_t) -> c_int; + pub fn sem_trywait(sem: *mut sem_t) -> c_int; + pub fn sem_post(sem: *mut sem_t) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/signal.rs b/deps/crates/vendor/libc/src/new/qurt/signal.rs new file mode 100644 index 00000000000000..f525fa15ff29e1 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/signal.rs @@ -0,0 +1,117 @@ +//! Header: `signal.h` + +use super::*; +use crate::prelude::*; + +// Standard signal numbers +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGBUS: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGUSR1: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGUSR2: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGSTKFLT: c_int = 16; +pub const SIGCHLD: c_int = 17; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGURG: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGIO: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIGSYS: c_int = 31; + +// Signal handling constants +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = !0 as sighandler_t; + +// Signal mask operations (QuRT uses different values than Linux) +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 3; + +// QuRT-specific signal constants +pub const POSIX_MSG: c_int = 7; +pub const POSIX_NOTIF: c_int = 8; +pub const SIGRTMIN: c_int = 10; +pub const SIGRTMAX: c_int = 32; + +// Notification types (from QuRT signal.h) +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; +pub const SA_SIGINFO: c_int = 1; + +pub type sighandler_t = size_t; + +// Signal structures based on QuRT SDK headers +s! { + pub struct sigval { + pub sival_int: c_int, + pub sival_ptr: *mut c_void, + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: sigval, + pub sigev_notify_function: Option, + pub sigev_notify_attributes: *mut pthread_attr_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_value: sigval, + } + + pub struct sigaction { + pub sa_handler: Option, + pub sa_mask: sigset_t, + pub sa_flags: c_int, + pub sa_sigaction: Option, + } +} + +extern "C" { + pub fn signal(sig: c_int, handler: sighandler_t) -> sighandler_t; + pub fn kill(pid: pid_t, sig: c_int) -> c_int; + pub fn raise(sig: c_int) -> c_int; + pub fn alarm(seconds: c_uint) -> c_uint; + pub fn pause() -> c_int; + + // Signal mask functions + pub fn sigemptyset(set: *mut sigset_t) -> c_int; + pub fn sigfillset(set: *mut sigset_t) -> c_int; + pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int; + pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int; + pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int; + pub fn sigprocmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sigpending(set: *mut sigset_t) -> c_int; + pub fn sigsuspend(mask: *const sigset_t) -> c_int; + + // QuRT-specific signal functions + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn _sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const timespec, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/stdio.rs b/deps/crates/vendor/libc/src/new/qurt/stdio.rs new file mode 100644 index 00000000000000..7130717764e8a1 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/stdio.rs @@ -0,0 +1,73 @@ +//! Header: `stdio.h` + +use super::*; +use crate::prelude::*; + +// Buffer size +pub const BUFSIZ: c_uint = 1024; +pub const FILENAME_MAX: c_uint = 260; + +// End of file +pub const EOF: c_int = -1; + +extern "C" { + // File operations + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, stream: *mut FILE) -> *mut FILE; + pub fn fclose(stream: *mut FILE) -> c_int; + pub fn fflush(stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nmemb: size_t, stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nmemb: size_t, stream: *mut FILE) -> size_t; + + // Character I/O + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + + // Line I/O + pub fn fgets(s: *mut c_char, size: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn gets(s: *mut c_char) -> *mut c_char; + pub fn puts(s: *const c_char) -> c_int; + + // Formatted I/O + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn fprintf(stream: *mut FILE, format: *const c_char, ...) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + pub fn snprintf(s: *mut c_char, n: size_t, format: *const c_char, ...) -> c_int; + pub fn vprintf(format: *const c_char, ap: crate::va_list) -> c_int; + pub fn vfprintf(stream: *mut FILE, format: *const c_char, ap: crate::va_list) -> c_int; + pub fn vsprintf(s: *mut c_char, format: *const c_char, ap: crate::va_list) -> c_int; + pub fn vsnprintf(s: *mut c_char, n: size_t, format: *const c_char, ap: crate::va_list) + -> c_int; + + // Input formatted functions + pub fn scanf(format: *const c_char, ...) -> c_int; + pub fn fscanf(stream: *mut FILE, format: *const c_char, ...) -> c_int; + pub fn sscanf(s: *const c_char, format: *const c_char, ...) -> c_int; + + // File positioning + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int; + + // Error handling + pub fn clearerr(stream: *mut FILE); + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + + // File management + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(old: *const c_char, new: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn tmpnam(s: *mut c_char) -> *mut c_char; + + // Buffer control + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buffer: *mut c_char); +} diff --git a/deps/crates/vendor/libc/src/new/qurt/stdlib.rs b/deps/crates/vendor/libc/src/new/qurt/stdlib.rs new file mode 100644 index 00000000000000..dc96e36eca5d2f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/stdlib.rs @@ -0,0 +1,67 @@ +//! Header: `stdlib.h` + +use super::*; +use crate::prelude::*; + +// Exit status constants +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; + +// Maximum values +pub const RAND_MAX: c_int = 32767; + +extern "C" { + // Memory management + pub fn malloc(size: size_t) -> *mut c_void; + pub fn calloc(nmemb: size_t, size: size_t) -> *mut c_void; + pub fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(ptr: *mut c_void); + + // Process control + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn atexit(function: extern "C" fn()) -> c_int; + + // Environment + pub fn getenv(name: *const c_char) -> *mut c_char; + pub fn setenv(name: *const c_char, value: *const c_char, overwrite: c_int) -> c_int; + pub fn unsetenv(name: *const c_char) -> c_int; + + // String/number conversion + pub fn atoi(nptr: *const c_char) -> c_int; + pub fn atol(nptr: *const c_char) -> c_long; + pub fn atoll(nptr: *const c_char) -> c_longlong; + pub fn strtol(nptr: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoul(nptr: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoll(nptr: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoull(nptr: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulonglong; + pub fn strtod(nptr: *const c_char, endptr: *mut *mut c_char) -> c_double; + pub fn strtof(nptr: *const c_char, endptr: *mut *mut c_char) -> c_float; + + // Random numbers + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + // Searching and sorting + pub fn qsort( + base: *mut c_void, + nmemb: size_t, + size: size_t, + compar: extern "C" fn(*const c_void, *const c_void) -> c_int, + ); + pub fn bsearch( + key: *const c_void, + base: *const c_void, + nmemb: size_t, + size: size_t, + compar: extern "C" fn(*const c_void, *const c_void) -> c_int, + ) -> *mut c_void; + + // Integer arithmetic + pub fn abs(j: c_int) -> c_int; + pub fn labs(j: c_long) -> c_long; + pub fn llabs(j: c_longlong) -> c_longlong; + pub fn div(numer: c_int, denom: c_int) -> div_t; + pub fn ldiv(numer: c_long, denom: c_long) -> ldiv_t; + pub fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/sys/mman.rs b/deps/crates/vendor/libc/src/new/qurt/sys/mman.rs new file mode 100644 index 00000000000000..a0a3b3aad8fe7c --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/sys/mman.rs @@ -0,0 +1,55 @@ +//! Header: `sys/mman.h` +//! +//! Memory mapping functions and constants from Hexagon toolchain. + +use super::super::*; +use crate::prelude::*; + +// Memory protection constants +pub const PROT_NONE: c_int = 0x00; +pub const PROT_READ: c_int = 0x01; +pub const PROT_WRITE: c_int = 0x02; +pub const PROT_EXEC: c_int = 0x04; + +// Memory mapping constants +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_ANON: c_int = 0x1000; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_RENAME: c_int = 0x0020; +pub const MAP_NORESERVE: c_int = 0x0040; +pub const MAP_INHERIT: c_int = 0x0080; +pub const MAP_HASSEMAPHORE: c_int = 0x0200; +pub const MAP_TRYFIXED: c_int = 0x0400; +pub const MAP_WIRED: c_int = 0x0800; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +// Memory sync constants +pub const MS_ASYNC: c_int = 0x01; +pub const MS_INVALIDATE: c_int = 0x02; +pub const MS_SYNC: c_int = 0x04; + +// Memory lock constants +pub const MCL_CURRENT: c_int = 0x01; +pub const MCL_FUTURE: c_int = 0x02; + +extern "C" { + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn mlock(addr: *const c_void, len: size_t) -> c_int; + pub fn munlock(addr: *const c_void, len: size_t) -> c_int; + pub fn mlockall(flags: c_int) -> c_int; + pub fn munlockall() -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/sys/mod.rs b/deps/crates/vendor/libc/src/new/qurt/sys/mod.rs new file mode 100644 index 00000000000000..f9ef6a435fb48c --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/sys/mod.rs @@ -0,0 +1,6 @@ +//! System headers (`sys/*`) + +pub(crate) mod mman; +pub(crate) mod sched; +pub(crate) mod stat; +pub(crate) mod types; diff --git a/deps/crates/vendor/libc/src/new/qurt/sys/sched.rs b/deps/crates/vendor/libc/src/new/qurt/sys/sched.rs new file mode 100644 index 00000000000000..56fed5ba008901 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/sys/sched.rs @@ -0,0 +1,24 @@ +//! Header: `sys/sched.h` +//! +//! QuRT scheduling parameters and functions. + +use crate::prelude::*; + +// Scheduling policies (from QuRT sys/sched.h) +pub const SCHED_FIFO: c_int = 0; +pub const SCHED_RR: c_int = 1; +pub const SCHED_SPORADIC: c_int = 2; +pub const SCHED_OTHER: c_int = 3; + +s! { + pub struct sched_param { + pub unimplemented: *mut c_void, + pub sched_priority: c_int, + } +} + +extern "C" { + pub fn sched_yield() -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/sys/stat.rs b/deps/crates/vendor/libc/src/new/qurt/sys/stat.rs new file mode 100644 index 00000000000000..a8ee211eb4e83a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/sys/stat.rs @@ -0,0 +1,36 @@ +//! Header: `sys/stat.h` + +use super::super::*; +use crate::prelude::*; + +// File type constants for stat.st_mode +pub const S_IFMT: mode_t = 0o170000; +pub const S_IFSOCK: mode_t = 0o140000; +pub const S_IFLNK: mode_t = 0o120000; +pub const S_IFREG: mode_t = 0o100000; +pub const S_IFBLK: mode_t = 0o060000; +pub const S_IFDIR: mode_t = 0o040000; +pub const S_IFCHR: mode_t = 0o020000; +pub const S_IFIFO: mode_t = 0o010000; + +// File permission constants +pub const S_ISUID: mode_t = 0o4000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISVTX: mode_t = 0o1000; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; + +extern "C" { + pub fn stat(pathname: *const c_char, statbuf: *mut stat) -> c_int; + pub fn fstat(fd: c_int, statbuf: *mut stat) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/sys/types.rs b/deps/crates/vendor/libc/src/new/qurt/sys/types.rs new file mode 100644 index 00000000000000..a5db5164414f7f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/sys/types.rs @@ -0,0 +1,9 @@ +//! Header: `sys/types.h` +//! +//! Note: Basic types are defined at the crate root level for qurt. +//! This module provides sys/types.h specific functions and constants. + +use super::super::*; +use crate::prelude::*; + +pub type cpu_set_t = c_uint; diff --git a/deps/crates/vendor/libc/src/new/qurt/time.rs b/deps/crates/vendor/libc/src/new/qurt/time.rs new file mode 100644 index 00000000000000..ab6f4453dbeab1 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/time.rs @@ -0,0 +1,34 @@ +//! Header: `time.h` + +use super::*; +use crate::prelude::*; + +// Clock types +pub const CLOCK_REALTIME: clockid_t = 0; +pub const CLOCK_MONOTONIC: clockid_t = 1; +pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 2; +pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 3; + +extern "C" { + pub fn time(tloc: *mut time_t) -> time_t; + pub fn clock() -> clock_t; + pub fn difftime(time1: time_t, time0: time_t) -> c_double; + pub fn mktime(tm: *mut tm) -> time_t; + pub fn gmtime(timep: *const time_t) -> *mut tm; + pub fn gmtime_r(timep: *const time_t, result: *mut tm) -> *mut tm; + pub fn localtime(timep: *const time_t) -> *mut tm; + pub fn localtime_r(timep: *const time_t, result: *mut tm) -> *mut tm; + pub fn asctime(tm: *const tm) -> *mut c_char; + pub fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char; + pub fn ctime(timep: *const time_t) -> *mut c_char; + pub fn ctime_r(timep: *const time_t, buf: *mut c_char) -> *mut c_char; + pub fn strftime( + s: *mut c_char, + maxsize: size_t, + format: *const c_char, + timeptr: *const tm, + ) -> size_t; + pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut tm) -> *mut c_char; + pub fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int; + pub fn nanosleep(req: *const timespec, rem: *mut timespec) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/new/qurt/unistd.rs b/deps/crates/vendor/libc/src/new/qurt/unistd.rs new file mode 100644 index 00000000000000..b973b60e667610 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/qurt/unistd.rs @@ -0,0 +1,248 @@ +//! Header: `unistd.h` + +use super::*; +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; +use crate::prelude::*; + +// Access mode constants +pub const F_OK: c_int = 0; +pub const X_OK: c_int = 1; +pub const W_OK: c_int = 2; +pub const R_OK: c_int = 4; + +// Whence constants for lseek +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; + +// pathconf constants (from bits/confname.h) +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; + +// sysconf constants (from bits/confname.h) +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EQUIV_CLASS_MAX: c_int = 41; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_CHARCLASS_NAME_MAX: c_int = 45; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_PII: c_int = 53; +pub const _SC_PII_XTI: c_int = 54; +pub const _SC_PII_SOCKET: c_int = 55; +pub const _SC_PII_INTERNET: c_int = 56; +pub const _SC_PII_OSI: c_int = 57; +pub const _SC_POLL: c_int = 58; +pub const _SC_SELECT: c_int = 59; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = _SC_UIO_MAXIOV; +pub const _SC_PII_INTERNET_STREAM: c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: c_int = 62; +pub const _SC_PII_OSI_COTS: c_int = 63; +pub const _SC_PII_OSI_CLTS: c_int = 64; +pub const _SC_PII_OSI_M: c_int = 65; +pub const _SC_T_IOV_MAX: c_int = 66; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_C_VERSION: c_int = 96; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_CHAR_BIT: c_int = 101; +pub const _SC_CHAR_MAX: c_int = 102; +pub const _SC_CHAR_MIN: c_int = 103; +pub const _SC_INT_MAX: c_int = 104; +pub const _SC_INT_MIN: c_int = 105; +pub const _SC_LONG_BIT: c_int = 106; +pub const _SC_WORD_BIT: c_int = 107; +pub const _SC_MB_LEN_MAX: c_int = 108; +pub const _SC_NZERO: c_int = 109; +pub const _SC_SSIZE_MAX: c_int = 110; +pub const _SC_SCHAR_MAX: c_int = 111; +pub const _SC_SCHAR_MIN: c_int = 112; +pub const _SC_SHRT_MAX: c_int = 113; +pub const _SC_SHRT_MIN: c_int = 114; +pub const _SC_UCHAR_MAX: c_int = 115; +pub const _SC_UINT_MAX: c_int = 116; +pub const _SC_ULONG_MAX: c_int = 117; +pub const _SC_USHRT_MAX: c_int = 118; +pub const _SC_NL_ARGMAX: c_int = 119; +pub const _SC_NL_LANGMAX: c_int = 120; +pub const _SC_NL_MSGMAX: c_int = 121; +pub const _SC_NL_NMAX: c_int = 122; +pub const _SC_NL_SETMAX: c_int = 123; +pub const _SC_NL_TEXTMAX: c_int = 124; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; + +extern "C" { + // File operations + pub fn access(pathname: *const c_char, mode: c_int) -> c_int; + pub fn close(fd: c_int) -> c_int; + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + pub fn unlink(pathname: *const c_char) -> c_int; + + // Directory operations + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + pub fn rmdir(pathname: *const c_char) -> c_int; + + // Process operations + pub fn getpid() -> pid_t; + + // Sleep functions + pub fn sleep(seconds: c_uint) -> c_uint; + + // System configuration + pub fn sysconf(name: c_int) -> c_long; +} diff --git a/deps/crates/vendor/libc/src/new/redox/mod.rs b/deps/crates/vendor/libc/src/new/redox/mod.rs new file mode 100644 index 00000000000000..cf7806a2437ad3 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/redox/mod.rs @@ -0,0 +1,3 @@ +//! Redox libc. +//! +//! * Headers: diff --git a/deps/crates/vendor/libc/src/new/relibc/mod.rs b/deps/crates/vendor/libc/src/new/relibc/mod.rs new file mode 100644 index 00000000000000..d2449123218a15 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/relibc/mod.rs @@ -0,0 +1,5 @@ +//! Redox OS libc. +//! +//! * Headers: + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/relibc/unistd.rs b/deps/crates/vendor/libc/src/new/relibc/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/relibc/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/rtems/mod.rs b/deps/crates/vendor/libc/src/new/rtems/mod.rs new file mode 100644 index 00000000000000..bd3dc3954c71eb --- /dev/null +++ b/deps/crates/vendor/libc/src/new/rtems/mod.rs @@ -0,0 +1,2 @@ +//! RTEMS libc. +// FIXME(rtems): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/sgx/mod.rs b/deps/crates/vendor/libc/src/new/sgx/mod.rs new file mode 100644 index 00000000000000..8c15dadb4a0b82 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/sgx/mod.rs @@ -0,0 +1 @@ +//! Fortanix SGX. diff --git a/deps/crates/vendor/libc/src/new/sgx/unistd.rs b/deps/crates/vendor/libc/src/new/sgx/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/sgx/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/solaris/mod.rs b/deps/crates/vendor/libc/src/new/solaris/mod.rs new file mode 100644 index 00000000000000..97ae47333deb48 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/solaris/mod.rs @@ -0,0 +1,5 @@ +//! Solaris libc. +//! +//! * Manual pages: (under "Reference Manuals") + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/solaris/unistd.rs b/deps/crates/vendor/libc/src/new/solaris/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/solaris/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/solid/mod.rs b/deps/crates/vendor/libc/src/new/solid/mod.rs new file mode 100644 index 00000000000000..4a197cfb62c5a0 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/solid/mod.rs @@ -0,0 +1,2 @@ +//! Kyoto Microcomputer SOLID. +// FIXME(solid): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/teeos/mod.rs b/deps/crates/vendor/libc/src/new/teeos/mod.rs new file mode 100644 index 00000000000000..96f44d3d39361f --- /dev/null +++ b/deps/crates/vendor/libc/src/new/teeos/mod.rs @@ -0,0 +1,2 @@ +//! Per the target docs, TEEOS uses part of musl as its libc. +// FIXME(teeos): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/trusty/mod.rs b/deps/crates/vendor/libc/src/new/trusty/mod.rs new file mode 100644 index 00000000000000..261ecb09e46de8 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/trusty/mod.rs @@ -0,0 +1,2 @@ +//! Trusty libc. +// FIXME(trusty): link to headers needed. diff --git a/deps/crates/vendor/libc/src/new/uclibc/mod.rs b/deps/crates/vendor/libc/src/new/uclibc/mod.rs new file mode 100644 index 00000000000000..6bf83ef2e1d385 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/uclibc/mod.rs @@ -0,0 +1,7 @@ +//! uClibc. +//! +//! * About: +//! * Headers: (mirror) + +pub(crate) mod pthread; +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/uclibc/pthread.rs b/deps/crates/vendor/libc/src/new/uclibc/pthread.rs new file mode 100644 index 00000000000000..c0f1731f153479 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/uclibc/pthread.rs @@ -0,0 +1,66 @@ +//! Header: `pthread.h` +//! +//! Note that The l4re port of uclibc doesn't yet support all `pthread_*` API that is +//! available upstream. + +pub use crate::new::common::linux_like::pthread::{ + pthread_getaffinity_np, + pthread_getattr_np, + pthread_setaffinity_np, +}; +#[cfg(not(target_os = "l4re"))] +pub use crate::new::common::linux_like::pthread::{ + pthread_getname_np, + pthread_setname_np, +}; +#[cfg(not(target_os = "l4re"))] +pub use crate::new::common::posix::pthread::{ + pthread_atfork, + pthread_barrierattr_getpshared, + pthread_condattr_getclock, + pthread_condattr_setclock, + pthread_getcpuclockid, + pthread_mutex_consistent, + pthread_mutexattr_getprotocol, + pthread_mutexattr_getrobust, + pthread_mutexattr_setprotocol, + pthread_mutexattr_setrobust, + pthread_setschedprio, +}; +pub use crate::new::common::posix::pthread::{ + pthread_attr_getguardsize, + pthread_attr_getinheritsched, + pthread_attr_getschedparam, + pthread_attr_getschedpolicy, + pthread_attr_getstack, + pthread_attr_setguardsize, + pthread_attr_setinheritsched, + pthread_attr_setschedparam, + pthread_attr_setschedpolicy, + pthread_attr_setstack, + pthread_barrier_destroy, + pthread_barrier_init, + pthread_barrier_wait, + pthread_barrierattr_destroy, + pthread_barrierattr_init, + pthread_barrierattr_setpshared, + pthread_cancel, + pthread_condattr_getpshared, + pthread_condattr_setpshared, + pthread_create, + pthread_getschedparam, + pthread_kill, + pthread_mutex_timedlock, + pthread_mutexattr_getpshared, + pthread_mutexattr_setpshared, + pthread_once, + pthread_rwlockattr_getpshared, + pthread_rwlockattr_setpshared, + pthread_setschedparam, + pthread_sigmask, + pthread_spin_destroy, + pthread_spin_init, + pthread_spin_lock, + pthread_spin_trylock, + pthread_spin_unlock, +}; diff --git a/deps/crates/vendor/libc/src/new/uclibc/unistd.rs b/deps/crates/vendor/libc/src/new/uclibc/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/uclibc/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/ucrt/mod.rs b/deps/crates/vendor/libc/src/new/ucrt/mod.rs new file mode 100644 index 00000000000000..f6b5f5d1ef8fc9 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/ucrt/mod.rs @@ -0,0 +1,4 @@ +//! Windows Universal C Runtime. +//! +//! * Manual pages: +//! * UCRT information: diff --git a/deps/crates/vendor/libc/src/new/vita/mod.rs b/deps/crates/vendor/libc/src/new/vita/mod.rs new file mode 100644 index 00000000000000..21205ebd046fbc --- /dev/null +++ b/deps/crates/vendor/libc/src/new/vita/mod.rs @@ -0,0 +1,2 @@ +//! VITASDK system library. +// FIXME(vita): link to headers or manpages needed. diff --git a/deps/crates/vendor/libc/src/new/vxworks/mod.rs b/deps/crates/vendor/libc/src/new/vxworks/mod.rs new file mode 100644 index 00000000000000..65630565e53e08 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/vxworks/mod.rs @@ -0,0 +1,4 @@ +//! VxWorks libc. +// FIXME(vxworks): link to headers needed. + +pub(crate) mod unistd; diff --git a/deps/crates/vendor/libc/src/new/vxworks/unistd.rs b/deps/crates/vendor/libc/src/new/vxworks/unistd.rs new file mode 100644 index 00000000000000..8d55ee5823315a --- /dev/null +++ b/deps/crates/vendor/libc/src/new/vxworks/unistd.rs @@ -0,0 +1,7 @@ +//! Header: `unistd.h` + +pub use crate::new::common::posix::unistd::{ + STDERR_FILENO, + STDIN_FILENO, + STDOUT_FILENO, +}; diff --git a/deps/crates/vendor/libc/src/new/wasi/mod.rs b/deps/crates/vendor/libc/src/new/wasi/mod.rs new file mode 100644 index 00000000000000..341e6d5d164997 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/wasi/mod.rs @@ -0,0 +1,3 @@ +//! WASI libc. +//! +//! * Headers: diff --git a/deps/crates/vendor/libc/src/new/xous/mod.rs b/deps/crates/vendor/libc/src/new/xous/mod.rs new file mode 100644 index 00000000000000..8a9a28586c4489 --- /dev/null +++ b/deps/crates/vendor/libc/src/new/xous/mod.rs @@ -0,0 +1,2 @@ +//! Xous libc. +// FIXME(xous): link to headers needed. diff --git a/deps/crates/vendor/libc/src/primitives.rs b/deps/crates/vendor/libc/src/primitives.rs new file mode 100644 index 00000000000000..228dbc2c554676 --- /dev/null +++ b/deps/crates/vendor/libc/src/primitives.rs @@ -0,0 +1,58 @@ +//! This module contains type aliases for C's platform-specific types +//! and fixed-width integer types. +//! +//! The platform-specific types definitions were taken from rust-lang/rust in +//! library/core/src/ffi/primitives.rs +//! +//! The fixed-width integer aliases are deprecated: use the Rust types instead. + +// FIXME(1.0): Deprecate these aliases in a few releases, remove in 1.0. +pub use core::ffi::{ + c_char, + c_double, + c_float, + c_int, + c_long, + c_longlong, + c_schar, + c_short, + c_uchar, + c_uint, + c_ulong, + c_ulonglong, + c_ushort, +}; + +#[deprecated(since = "0.2.55", note = "Use i8 instead.")] +pub type int8_t = i8; +#[deprecated(since = "0.2.55", note = "Use i16 instead.")] +pub type int16_t = i16; +#[deprecated(since = "0.2.55", note = "Use i32 instead.")] +pub type int32_t = i32; +#[deprecated(since = "0.2.55", note = "Use i64 instead.")] +pub type int64_t = i64; +#[deprecated(since = "0.2.55", note = "Use u8 instead.")] +pub type uint8_t = u8; +#[deprecated(since = "0.2.55", note = "Use u16 instead.")] +pub type uint16_t = u16; +#[deprecated(since = "0.2.55", note = "Use u32 instead.")] +pub type uint32_t = u32; +#[deprecated(since = "0.2.55", note = "Use u64 instead.")] +pub type uint64_t = u64; + +cfg_if! { + if #[cfg(all(target_arch = "aarch64", not(target_os = "windows")))] { + /// C `__int128` (a GCC extension that's part of many ABIs) + #[deprecated(since = "0.2.184", note = "Use i128 instead.")] + pub type __int128 = i128; + /// C `unsigned __int128` (a GCC extension that's part of many ABIs) + #[deprecated(since = "0.2.184", note = "Use u128 instead.")] + pub type __uint128 = u128; + /// C __int128_t (alternate name for [__int128][]) + #[deprecated(since = "0.2.184", note = "Use i128 instead.")] + pub type __int128_t = i128; + /// C __uint128_t (alternate name for [__uint128][]) + #[deprecated(since = "0.2.184", note = "Use u128 instead.")] + pub type __uint128_t = u128; + } +} diff --git a/deps/crates/vendor/libc/src/psp.rs b/deps/crates/vendor/libc/src/psp.rs new file mode 100644 index 00000000000000..823567127c4019 --- /dev/null +++ b/deps/crates/vendor/libc/src/psp.rs @@ -0,0 +1,4131 @@ +//! PSP C type definitions +//! +//! These type declarations are not enough, as they must be ultimately resolved +//! by the linker. Crates that use these definitions must, somewhere in the +//! crate graph, include a stub provider crate such as the `psp` crate. + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type SceKernelVTimerHandler = unsafe extern "C" fn( + uid: SceUid, + arg1: *mut SceKernelSysClock, + arg2: *mut SceKernelSysClock, + arg3: *mut c_void, +) -> u32; + +pub type SceKernelVTimerHandlerWide = + unsafe extern "C" fn(uid: SceUid, arg1: i64, arg2: i64, arg3: *mut c_void) -> u32; + +pub type SceKernelThreadEventHandler = + unsafe extern "C" fn(mask: i32, thid: SceUid, common: *mut c_void) -> i32; + +pub type SceKernelAlarmHandler = unsafe extern "C" fn(common: *mut c_void) -> u32; + +pub type SceKernelCallbackFunction = + unsafe extern "C" fn(arg1: i32, arg2: i32, arg: *mut c_void) -> i32; + +pub type SceKernelThreadEntry = unsafe extern "C" fn(args: usize, argp: *mut c_void) -> i32; + +pub type PowerCallback = extern "C" fn(unknown: i32, power_info: i32); + +pub type IoPermissions = i32; + +pub type UmdCallback = fn(unknown: i32, event: i32) -> i32; + +pub type SceMpegRingbufferCb = + Option i32>; + +pub type GuCallback = Option; +pub type GuSwapBuffersCallback = + Option; + +pub type SceNetAdhocctlHandler = + Option; + +pub type AdhocMatchingCallback = Option< + unsafe extern "C" fn( + matching_id: i32, + event: i32, + mac: *mut u8, + opt_len: i32, + opt_data: *mut c_void, + ), +>; + +pub type SceNetApctlHandler = Option< + unsafe extern "C" fn(oldState: i32, newState: i32, event: i32, error: i32, pArg: *mut c_void), +>; + +pub type HttpMallocFunction = Option *mut c_void>; +pub type HttpReallocFunction = + Option *mut c_void>; +pub type HttpFreeFunction = Option; +pub type HttpPasswordCB = Option< + unsafe extern "C" fn( + request: i32, + auth_type: HttpAuthType, + realm: *const u8, + username: *mut u8, + password: *mut u8, + need_entity: i32, + entity_body: *mut *mut u8, + entity_size: *mut usize, + save: *mut i32, + ) -> i32, +>; + +pub type socklen_t = u32; + +e! { + #[repr(u32)] + pub enum AudioFormat { + Stereo = 0, + Mono = 0x10, + } + + #[repr(u32)] + pub enum DisplayMode { + Lcd = 0, + } + + #[repr(u32)] + pub enum DisplayPixelFormat { + Psm5650 = 0, + Psm5551 = 1, + Psm4444 = 2, + Psm8888 = 3, + } + + #[repr(u32)] + pub enum DisplaySetBufSync { + Immediate = 0, + NextFrame = 1, + } + + #[repr(i32)] + pub enum AudioOutputFrequency { + Khz48 = 48000, + Khz44_1 = 44100, + Khz32 = 32000, + Khz24 = 24000, + Khz22_05 = 22050, + Khz16 = 16000, + Khz12 = 12000, + Khz11_025 = 11025, + Khz8 = 8000, + } + + #[repr(i32)] + pub enum AudioInputFrequency { + Khz44_1 = 44100, + Khz22_05 = 22050, + Khz11_025 = 11025, + } + + #[repr(u32)] + pub enum CtrlMode { + Digital = 0, + Analog, + } + + #[repr(i32)] + pub enum GeMatrixType { + Bone0 = 0, + Bone1, + Bone2, + Bone3, + Bone4, + Bone5, + Bone6, + Bone7, + World, + View, + Projection, + TexGen, + } + + #[repr(i32)] + pub enum GeListState { + Done = 0, + Queued, + DrawingDone, + StallReached, + CancelDone, + } + + #[repr(u8)] + pub enum GeCommand { + Nop = 0, + Vaddr = 0x1, + Iaddr = 0x2, + Prim = 0x4, + Bezier = 0x5, + Spline = 0x6, + BoundingBox = 0x7, + Jump = 0x8, + BJump = 0x9, + Call = 0xa, + Ret = 0xb, + End = 0xc, + Signal = 0xe, + Finish = 0xf, + Base = 0x10, + VertexType = 0x12, + OffsetAddr = 0x13, + Origin = 0x14, + Region1 = 0x15, + Region2 = 0x16, + LightingEnable = 0x17, + LightEnable0 = 0x18, + LightEnable1 = 0x19, + LightEnable2 = 0x1a, + LightEnable3 = 0x1b, + DepthClampEnable = 0x1c, + CullFaceEnable = 0x1d, + TextureMapEnable = 0x1e, + FogEnable = 0x1f, + DitherEnable = 0x20, + AlphaBlendEnable = 0x21, + AlphaTestEnable = 0x22, + ZTestEnable = 0x23, + StencilTestEnable = 0x24, + AntiAliasEnable = 0x25, + PatchCullEnable = 0x26, + ColorTestEnable = 0x27, + LogicOpEnable = 0x28, + BoneMatrixNumber = 0x2a, + BoneMatrixData = 0x2b, + MorphWeight0 = 0x2c, + MorphWeight1 = 0x2d, + MorphWeight2 = 0x2e, + MorphWeight3 = 0x2f, + MorphWeight4 = 0x30, + MorphWeight5 = 0x31, + MorphWeight6 = 0x32, + MorphWeight7 = 0x33, + PatchDivision = 0x36, + PatchPrimitive = 0x37, + PatchFacing = 0x38, + WorldMatrixNumber = 0x3a, + WorldMatrixData = 0x3b, + ViewMatrixNumber = 0x3c, + ViewMatrixData = 0x3d, + ProjMatrixNumber = 0x3e, + ProjMatrixData = 0x3f, + TGenMatrixNumber = 0x40, + TGenMatrixData = 0x41, + ViewportXScale = 0x42, + ViewportYScale = 0x43, + ViewportZScale = 0x44, + ViewportXCenter = 0x45, + ViewportYCenter = 0x46, + ViewportZCenter = 0x47, + TexScaleU = 0x48, + TexScaleV = 0x49, + TexOffsetU = 0x4a, + TexOffsetV = 0x4b, + OffsetX = 0x4c, + OffsetY = 0x4d, + ShadeMode = 0x50, + ReverseNormal = 0x51, + MaterialUpdate = 0x53, + MaterialEmissive = 0x54, + MaterialAmbient = 0x55, + MaterialDiffuse = 0x56, + MaterialSpecular = 0x57, + MaterialAlpha = 0x58, + MaterialSpecularCoef = 0x5b, + AmbientColor = 0x5c, + AmbientAlpha = 0x5d, + LightMode = 0x5e, + LightType0 = 0x5f, + LightType1 = 0x60, + LightType2 = 0x61, + LightType3 = 0x62, + Light0X = 0x63, + Light0Y, + Light0Z, + Light1X, + Light1Y, + Light1Z, + Light2X, + Light2Y, + Light2Z, + Light3X, + Light3Y, + Light3Z, + Light0DirectionX = 0x6f, + Light0DirectionY, + Light0DirectionZ, + Light1DirectionX, + Light1DirectionY, + Light1DirectionZ, + Light2DirectionX, + Light2DirectionY, + Light2DirectionZ, + Light3DirectionX, + Light3DirectionY, + Light3DirectionZ, + Light0ConstantAtten = 0x7b, + Light0LinearAtten, + Light0QuadtraticAtten, + Light1ConstantAtten, + Light1LinearAtten, + Light1QuadtraticAtten, + Light2ConstantAtten, + Light2LinearAtten, + Light2QuadtraticAtten, + Light3ConstantAtten, + Light3LinearAtten, + Light3QuadtraticAtten, + Light0ExponentAtten = 0x87, + Light1ExponentAtten, + Light2ExponentAtten, + Light3ExponentAtten, + Light0CutoffAtten = 0x8b, + Light1CutoffAtten, + Light2CutoffAtten, + Light3CutoffAtten, + Light0Ambient = 0x8f, + Light0Diffuse, + Light0Specular, + Light1Ambient, + Light1Diffuse, + Light1Specular, + Light2Ambient, + Light2Diffuse, + Light2Specular, + Light3Ambient, + Light3Diffuse, + Light3Specular, + Cull = 0x9b, + FrameBufPtr = 0x9c, + FrameBufWidth = 0x9d, + ZBufPtr = 0x9e, + ZBufWidth = 0x9f, + TexAddr0 = 0xa0, + TexAddr1, + TexAddr2, + TexAddr3, + TexAddr4, + TexAddr5, + TexAddr6, + TexAddr7, + TexBufWidth0 = 0xa8, + TexBufWidth1, + TexBufWidth2, + TexBufWidth3, + TexBufWidth4, + TexBufWidth5, + TexBufWidth6, + TexBufWidth7, + ClutAddr = 0xb0, + ClutAddrUpper = 0xb1, + TransferSrc, + TransferSrcW, + TransferDst, + TransferDstW, + TexSize0 = 0xb8, + TexSize1, + TexSize2, + TexSize3, + TexSize4, + TexSize5, + TexSize6, + TexSize7, + TexMapMode = 0xc0, + TexShadeLs = 0xc1, + TexMode = 0xc2, + TexFormat = 0xc3, + LoadClut = 0xc4, + ClutFormat = 0xc5, + TexFilter = 0xc6, + TexWrap = 0xc7, + TexLevel = 0xc8, + TexFunc = 0xc9, + TexEnvColor = 0xca, + TexFlush = 0xcb, + TexSync = 0xcc, + Fog1 = 0xcd, + Fog2 = 0xce, + FogColor = 0xcf, + TexLodSlope = 0xd0, + FramebufPixFormat = 0xd2, + ClearMode = 0xd3, + Scissor1 = 0xd4, + Scissor2 = 0xd5, + MinZ = 0xd6, + MaxZ = 0xd7, + ColorTest = 0xd8, + ColorRef = 0xd9, + ColorTestmask = 0xda, + AlphaTest = 0xdb, + StencilTest = 0xdc, + StencilOp = 0xdd, + ZTest = 0xde, + BlendMode = 0xdf, + BlendFixedA = 0xe0, + BlendFixedB = 0xe1, + Dith0 = 0xe2, + Dith1, + Dith2, + Dith3, + LogicOp = 0xe6, + ZWriteDisable = 0xe7, + MaskRgb = 0xe8, + MaskAlpha = 0xe9, + TransferStart = 0xea, + TransferSrcPos = 0xeb, + TransferDstPos = 0xec, + TransferSize = 0xee, + Vscx = 0xf0, + Vscy = 0xf1, + Vscz = 0xf2, + Vtcs = 0xf3, + Vtct = 0xf4, + Vtcq = 0xf5, + Vcv = 0xf6, + Vap = 0xf7, + Vfc = 0xf8, + Vscv = 0xf9, + + Unknown03 = 0x03, + Unknown0D = 0x0d, + Unknown11 = 0x11, + Unknown29 = 0x29, + Unknown34 = 0x34, + Unknown35 = 0x35, + Unknown39 = 0x39, + Unknown4E = 0x4e, + Unknown4F = 0x4f, + Unknown52 = 0x52, + Unknown59 = 0x59, + Unknown5A = 0x5a, + UnknownB6 = 0xb6, + UnknownB7 = 0xb7, + UnknownD1 = 0xd1, + UnknownED = 0xed, + UnknownEF = 0xef, + UnknownFA = 0xfa, + UnknownFB = 0xfb, + UnknownFC = 0xfc, + UnknownFD = 0xfd, + UnknownFE = 0xfe, + NopFF = 0xff, + } + + #[repr(i32)] + pub enum SceSysMemPartitionId { + SceKernelUnknownPartition = 0, + SceKernelPrimaryKernelPartition = 1, + SceKernelPrimaryUserPartition = 2, + SceKernelOtherKernelPartition1 = 3, + SceKernelOtherKernelPartition2 = 4, + SceKernelVshellPARTITION = 5, + SceKernelScUserPartition = 6, + SceKernelMeUserPartition = 7, + SceKernelExtendedScKernelPartition = 8, + SceKernelExtendedSc2KernelPartition = 9, + SceKernelExtendedMeKernelPartition = 10, + SceKernelVshellKernelPartition = 11, + SceKernelExtendedKernelPartition = 12, + } + + #[repr(i32)] + pub enum SceSysMemBlockTypes { + Low = 0, + High, + Addr, + } + + #[repr(u32)] + pub enum Interrupt { + Gpio = 4, + Ata = 5, + Umd = 6, + Mscm0 = 7, + Wlan = 8, + Audio = 10, + I2c = 12, + Sircs = 14, + Systimer0 = 15, + Systimer1 = 16, + Systimer2 = 17, + Systimer3 = 18, + Thread0 = 19, + Nand = 20, + Dmacplus = 21, + Dma0 = 22, + Dma1 = 23, + Memlmd = 24, + Ge = 25, + Vblank = 30, + Mecodec = 31, + Hpremote = 36, + Mscm1 = 60, + Mscm2 = 61, + Thread1 = 65, + Interrupt = 66, + } + + #[repr(u32)] + pub enum SubInterrupt { + Gpio = Interrupt::Gpio as u32, + Ata = Interrupt::Ata as u32, + Umd = Interrupt::Umd as u32, + Dmacplus = Interrupt::Dmacplus as u32, + Ge = Interrupt::Ge as u32, + Display = Interrupt::Vblank as u32, + } + + #[repr(u32)] + pub enum SceKernelIdListType { + Thread = 1, + Semaphore = 2, + EventFlag = 3, + Mbox = 4, + Vpl = 5, + Fpl = 6, + Mpipe = 7, + Callback = 8, + ThreadEventHandler = 9, + Alarm = 10, + VTimer = 11, + SleepThread = 64, + DelayThread = 65, + SuspendThread = 66, + DormantThread = 67, + } + + #[repr(i32)] + pub enum UsbCamResolution { + Px160_120 = 0, + Px176_144 = 1, + Px320_240 = 2, + Px352_288 = 3, + Px640_480 = 4, + Px1024_768 = 5, + Px1280_960 = 6, + Px480_272 = 7, + Px360_272 = 8, + } + + #[repr(i32)] + pub enum UsbCamResolutionEx { + Px160_120 = 0, + Px176_144 = 1, + Px320_240 = 2, + Px352_288 = 3, + Px360_272 = 4, + Px480_272 = 5, + Px640_480 = 6, + Px1024_768 = 7, + Px1280_960 = 8, + } + + #[repr(i32)] + pub enum UsbCamDelay { + NoDelay = 0, + Delay10Sec = 1, + Delay20Sec = 2, + Delay30Sec = 3, + } + + #[repr(i32)] + pub enum UsbCamFrameRate { + Fps3_75 = 0, + Fps5 = 1, + Fps7_5 = 2, + Fps10 = 3, + Fps15 = 4, + Fps20 = 5, + Fps30 = 6, + Fps60 = 7, + } + + #[repr(i32)] + pub enum UsbCamWb { + Auto = 0, + Daylight = 1, + Fluorescent = 2, + Incadescent = 3, + } + + #[repr(i32)] + pub enum UsbCamEffectMode { + Normal = 0, + Negative = 1, + Blackwhite = 2, + Sepia = 3, + Blue = 4, + Red = 5, + Green = 6, + } + + #[repr(i32)] + pub enum UsbCamEvLevel { + Pos2_0 = 0, + Pos1_7 = 1, + Pos1_5 = 2, + Pos1_3 = 3, + Pos1_0 = 4, + Pos0_7 = 5, + Pos0_5 = 6, + Pos0_3 = 7, + Zero = 8, + Neg0_3, + Neg0_5, + Neg0_7, + Neg1_0, + Neg1_3, + Neg1_5, + Neg1_7, + Neg2_0, + } + + #[repr(i32)] + pub enum RtcCheckValidError { + InvalidYear = -1, + InvalidMonth = -2, + InvalidDay = -3, + InvalidHour = -4, + InvalidMinutes = -5, + InvalidSeconds = -6, + InvalidMicroseconds = -7, + } + + #[repr(u32)] + pub enum PowerTick { + All = 0, + Suspend = 1, + Display = 6, + } + + #[repr(u32)] + pub enum IoAssignPerms { + RdWr = 0, + RdOnly = 1, + } + + #[repr(u32)] + pub enum IoWhence { + Set = 0, + Cur = 1, + End = 2, + } + + #[repr(u32)] + pub enum UmdType { + Game = 0x10, + Video = 0x20, + Audio = 0x40, + } + + #[repr(u32)] + pub enum GuPrimitive { + Points = 0, + Lines = 1, + LineStrip = 2, + Triangles = 3, + TriangleStrip = 4, + TriangleFan = 5, + Sprites = 6, + } + + #[repr(u32)] + pub enum PatchPrimitive { + Points = 0, + LineStrip = 2, + TriangleStrip = 4, + } + + #[repr(u32)] + pub enum GuState { + AlphaTest = 0, + DepthTest = 1, + ScissorTest = 2, + StencilTest = 3, + Blend = 4, + CullFace = 5, + Dither = 6, + Fog = 7, + ClipPlanes = 8, + Texture2D = 9, + Lighting = 10, + Light0 = 11, + Light1 = 12, + Light2 = 13, + Light3 = 14, + LineSmooth = 15, + PatchCullFace = 16, + ColorTest = 17, + ColorLogicOp = 18, + FaceNormalReverse = 19, + PatchFace = 20, + Fragment2X = 21, + } + + #[repr(u32)] + pub enum MatrixMode { + Projection = 0, + View = 1, + Model = 2, + Texture = 3, + } + + #[repr(u32)] + pub enum TexturePixelFormat { + Psm5650 = 0, + Psm5551 = 1, + Psm4444 = 2, + Psm8888 = 3, + PsmT4 = 4, + PsmT8 = 5, + PsmT16 = 6, + PsmT32 = 7, + PsmDxt1 = 8, + PsmDxt3 = 9, + PsmDxt5 = 10, + } + + #[repr(u32)] + pub enum SplineMode { + FillFill = 0, + OpenFill = 1, + FillOpen = 2, + OpenOpen = 3, + } + + #[repr(u32)] + pub enum ShadingModel { + Flat = 0, + Smooth = 1, + } + + #[repr(u32)] + pub enum LogicalOperation { + Clear = 0, + And = 1, + AndReverse = 2, + Copy = 3, + AndInverted = 4, + Noop = 5, + Xor = 6, + Or = 7, + Nor = 8, + Equiv = 9, + Inverted = 10, + OrReverse = 11, + CopyInverted = 12, + OrInverted = 13, + Nand = 14, + Set = 15, + } + + #[repr(u32)] + pub enum TextureFilter { + Nearest = 0, + Linear = 1, + NearestMipmapNearest = 4, + LinearMipmapNearest = 5, + NearestMipmapLinear = 6, + LinearMipmapLinear = 7, + } + + #[repr(u32)] + pub enum TextureMapMode { + TextureCoords = 0, + TextureMatrix = 1, + EnvironmentMap = 2, + } + + #[repr(u32)] + pub enum TextureLevelMode { + Auto = 0, + Const = 1, + Slope = 2, + } + + #[repr(u32)] + pub enum TextureProjectionMapMode { + Position = 0, + Uv = 1, + NormalizedNormal = 2, + Normal = 3, + } + + #[repr(u32)] + pub enum GuTexWrapMode { + Repeat = 0, + Clamp = 1, + } + + #[repr(u32)] + pub enum FrontFaceDirection { + Clockwise = 0, + CounterClockwise = 1, + } + + #[repr(u32)] + pub enum AlphaFunc { + Never = 0, + Always, + Equal, + NotEqual, + Less, + LessOrEqual, + Greater, + GreaterOrEqual, + } + + #[repr(u32)] + pub enum StencilFunc { + Never = 0, + Always, + Equal, + NotEqual, + Less, + LessOrEqual, + Greater, + GreaterOrEqual, + } + + #[repr(u32)] + pub enum ColorFunc { + Never = 0, + Always, + Equal, + NotEqual, + } + + #[repr(u32)] + pub enum DepthFunc { + Never = 0, + Always, + Equal, + NotEqual, + Less, + LessOrEqual, + Greater, + GreaterOrEqual, + } + + #[repr(u32)] + pub enum TextureEffect { + Modulate = 0, + Decal = 1, + Blend = 2, + Replace = 3, + Add = 4, + } + + #[repr(u32)] + pub enum TextureColorComponent { + Rgb = 0, + Rgba = 1, + } + + #[repr(u32)] + pub enum MipmapLevel { + None = 0, + Level1, + Level2, + Level3, + Level4, + Level5, + Level6, + Level7, + } + + #[repr(u32)] + pub enum BlendOp { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4, + Abs = 5, + } + + #[repr(u32)] + pub enum BlendSrc { + SrcColor = 0, + OneMinusSrcColor = 1, + SrcAlpha = 2, + OneMinusSrcAlpha = 3, + Fix = 10, + } + + #[repr(u32)] + pub enum BlendDst { + DstColor = 0, + OneMinusDstColor = 1, + DstAlpha = 4, + OneMinusDstAlpha = 5, + Fix = 10, + } + + #[repr(u32)] + pub enum StencilOperation { + Keep = 0, + Zero = 1, + Replace = 2, + Invert = 3, + Incr = 4, + Decr = 5, + } + + #[repr(u32)] + pub enum LightMode { + SingleColor = 0, + SeparateSpecularColor = 1, + } + + #[repr(u32)] + pub enum LightType { + Directional = 0, + Pointlight = 1, + Spotlight = 2, + } + + #[repr(u32)] + pub enum GuContextType { + Direct = 0, + Call = 1, + Send = 2, + } + + #[repr(u32)] + pub enum GuQueueMode { + Tail = 0, + Head = 1, + } + + #[repr(u32)] + pub enum GuSyncMode { + Finish = 0, + Signal = 1, + Done = 2, + List = 3, + Send = 4, + } + + #[repr(u32)] + pub enum GuSyncBehavior { + Wait = 0, + NoWait = 1, + } + + #[repr(u32)] + pub enum GuCallbackId { + Signal = 1, + Finish = 4, + } + + #[repr(u32)] + pub enum SignalBehavior { + Suspend = 1, + Continue = 2, + } + + #[repr(u32)] + pub enum ClutPixelFormat { + Psm5650 = 0, + Psm5551 = 1, + Psm4444 = 2, + Psm8888 = 3, + } + + #[repr(C)] + pub enum KeyType { + Directory = 1, + Integer = 2, + String = 3, + Bytes = 4, + } + + #[repr(u32)] + pub enum UtilityMsgDialogMode { + Error, + Text, + } + + #[repr(u32)] + pub enum UtilityMsgDialogPressed { + Unknown1, + Yes, + No, + Back, + } + + #[repr(u32)] + pub enum UtilityDialogButtonAccept { + Circle, + Cross, + } + + #[repr(u32)] + pub enum SceUtilityOskInputLanguage { + Default, + Japanese, + English, + French, + Spanish, + German, + Italian, + Dutch, + Portugese, + Russian, + Korean, + } + + #[repr(u32)] + pub enum SceUtilityOskInputType { + All, + LatinDigit, + LatinSymbol, + LatinLowercase = 4, + LatinUppercase = 8, + JapaneseDigit = 0x100, + JapaneseSymbol = 0x200, + JapaneseLowercase = 0x400, + JapaneseUppercase = 0x800, + JapaneseHiragana = 0x1000, + JapaneseHalfWidthKatakana = 0x2000, + JapaneseKatakana = 0x4000, + JapaneseKanji = 0x8000, + RussianLowercase = 0x10000, + RussianUppercase = 0x20000, + Korean = 0x40000, + Url = 0x80000, + } + + #[repr(u32)] + pub enum SceUtilityOskState { + None, + Initializing, + Initialized, + Visible, + Quit, + Finished, + } + + #[repr(u32)] + pub enum SceUtilityOskResult { + Unchanged, + Cancelled, + Changed, + } + + #[repr(u32)] + pub enum SystemParamLanguage { + Japanese, + English, + French, + Spanish, + German, + Italian, + Dutch, + Portugese, + Russian, + Korean, + ChineseTraditional, + ChineseSimplified, + } + + #[repr(u32)] + pub enum SystemParamId { + StringNickname = 1, + AdhocChannel, + WlanPowerSave, + DateFormat, + TimeFormat, + Timezone, + DaylightSavings, + Language, + Unknown, + } + + #[repr(u32)] + pub enum SystemParamAdhocChannel { + ChannelAutomatic = 0, + Channel1 = 1, + Channel6 = 6, + Channel11 = 11, + } + + #[repr(u32)] + pub enum SystemParamWlanPowerSaveState { + Off, + On, + } + + #[repr(u32)] + pub enum SystemParamDateFormat { + YYYYMMDD, + MMDDYYYY, + DDMMYYYY, + } + + #[repr(u32)] + pub enum SystemParamTimeFormat { + Hour24, + Hour12, + } + + #[repr(u32)] + pub enum SystemParamDaylightSavings { + Std, + Dst, + } + + #[repr(u32)] + pub enum AvModule { + AvCodec, + SasCore, + Atrac3Plus, + MpegBase, + Mp3, + Vaudio, + Aac, + G729, + } + + #[repr(u32)] + pub enum Module { + NetCommon = 0x100, + NetAdhoc, + NetInet, + NetParseUri, + NetHttp, + NetSsl, + + UsbPspCm = 0x200, + UsbMic, + UsbCam, + UsbGps, + + AvCodec = 0x300, + AvSascore, + AvAtrac3Plus, + AvMpegBase, + AvMp3, + AvVaudio, + AvAac, + AvG729, + + NpCommon = 0x400, + NpService, + NpMatching2, + NpDrm = 0x500, + + Irda = 0x600, + } + + #[repr(u32)] + pub enum NetModule { + NetCommon = 1, + NetAdhoc, + NetInet, + NetParseUri, + NetHttp, + NetSsl, + } + + #[repr(u32)] + pub enum UsbModule { + UsbPspCm = 1, + UsbAcc, + UsbMic, + UsbCam, + UsbGps, + } + + #[repr(u32)] + pub enum NetParam { + Name, + Ssid, + Secure, + WepKey, + IsStaticIp, + Ip, + NetMask, + Route, + ManualDns, + PrimaryDns, + SecondaryDns, + ProxyUser, + ProxyPass, + UseProxy, + ProxyServer, + ProxyPort, + Unknown1, + Unknown2, + } + + #[repr(u32)] + pub enum UtilityNetconfAction { + ConnectAP, + DisplayStatus, + ConnectAdhoc, + } + + #[repr(u32)] + pub enum UtilitySavedataMode { + AutoLoad, + AutoSave, + Load, + Save, + ListLoad, + ListSave, + ListDelete, + Delete, + } + + #[repr(u32)] + pub enum UtilitySavedataFocus { + Unknown1, + FirstList, + LastList, + Latest, + Oldest, + Unknown2, + Unknown3, + FirstEmpty, + LastEmpty, + } + + #[repr(u32)] + pub enum UtilityGameSharingMode { + Single = 1, + Multiple, + } + + #[repr(u32)] + pub enum UtilityGameSharingDataType { + File = 1, + Memory, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerInterfaceMode { + Full, + Limited, + None, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerCookieMode { + Disabled = 0, + Enabled, + Confirm, + Default, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerTextSize { + Large, + Normal, + Small, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerDisplayMode { + Normal, + Fit, + SmartFit, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerConnectMode { + Last, + ManualOnce, + ManualAll, + } + + #[repr(u32)] + pub enum UtilityHtmlViewerDisconnectMode { + Enable, + Disable, + Confirm, + } + + #[repr(u32)] + pub enum ScePspnetAdhocPtpState { + Closed, + Listen, + SynSent, + SynReceived, + Established, + } + + #[repr(u32)] + pub enum AdhocMatchingMode { + Host = 1, + Client, + Ptp, + } + + #[repr(u32)] + pub enum ApctlState { + Disconnected, + Scanning, + Joining, + GettingIp, + GotIp, + EapAuth, + KeyExchange, + } + + #[repr(u32)] + pub enum ApctlEvent { + ConnectRequest, + ScanRequest, + ScanComplete, + Established, + GetIp, + DisconnectRequest, + Error, + Info, + EapAuth, + KeyExchange, + Reconnect, + } + + #[repr(u32)] + pub enum ApctlInfo { + ProfileName, + Bssid, + Ssid, + SsidLength, + SecurityType, + Strength, + Channel, + PowerSave, + Ip, + SubnetMask, + Gateway, + PrimaryDns, + SecondaryDns, + UseProxy, + ProxyUrl, + ProxyPort, + EapType, + StartBrowser, + Wifisp, + } + + #[repr(u32)] + pub enum ApctlInfoSecurityType { + None, + Wep, + Wpa, + } + + #[repr(u32)] + pub enum HttpMethod { + Get, + Post, + Head, + } + + #[repr(u32)] + pub enum HttpAuthType { + Basic, + Digest, + } +} + +s_paren! { + #[repr(transparent)] + pub struct SceUid(pub i32); + + #[repr(transparent)] + #[allow(dead_code)] + pub struct SceMpeg(*mut *mut c_void); + + #[repr(transparent)] + #[allow(dead_code)] + pub struct SceMpegStream(*mut c_void); + + #[repr(transparent)] + pub struct Mp3Handle(pub i32); + + #[repr(transparent)] + #[allow(dead_code)] + pub struct RegHandle(u32); +} + +s! { + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: u8, + pub sa_data: [u8; 14], + } + + pub struct in_addr { + pub s_addr: u32, + } + + pub struct AudioInputParams { + pub unknown1: i32, + pub gain: i32, + pub unknown2: i32, + pub unknown3: i32, + pub unknown4: i32, + pub unknown5: i32, + } + + pub struct Atrac3BufferInfo { + pub puc_write_position_first_buf: *mut u8, + pub ui_writable_byte_first_buf: u32, + pub ui_min_write_byte_first_buf: u32, + pub ui_read_position_first_buf: u32, + pub puc_write_position_second_buf: *mut u8, + pub ui_writable_byte_second_buf: u32, + pub ui_min_write_byte_second_buf: u32, + pub ui_read_position_second_buf: u32, + } + + pub struct SceCtrlData { + pub timestamp: u32, + pub buttons: i32, + pub lx: u8, + pub ly: u8, + pub rsrv: [u8; 6], + } + + pub struct SceCtrlLatch { + pub ui_make: u32, + pub ui_break: u32, + pub ui_press: u32, + pub ui_release: u32, + } + + pub struct GeStack { + pub stack: [u32; 8], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct GeCallbackData { + pub signal_func: Option, + pub signal_arg: *mut c_void, + pub finish_func: Option, + pub finish_arg: *mut c_void, + } + + pub struct GeListArgs { + pub size: u32, + pub context: *mut GeContext, + pub num_stacks: u32, + pub stacks: *mut GeStack, + } + + pub struct GeBreakParam { + pub buf: [u32; 4], + } + + pub struct SceKernelLoadExecParam { + pub size: usize, + pub args: usize, + pub argp: *mut c_void, + pub key: *const u8, + } + + pub struct timeval { + pub tv_sec: i32, + pub tv_usec: i32, + } + + pub struct timezone { + pub tz_minutes_west: i32, + pub tz_dst_time: i32, + } + + pub struct IntrHandlerOptionParam { + size: i32, + entry: u32, + common: u32, + gp: u32, + intr_code: u16, + sub_count: u16, + intr_level: u16, + enabled: u16, + calls: u32, + field_1c: u32, + total_clock_lo: u32, + total_clock_hi: u32, + min_clock_lo: u32, + min_clock_hi: u32, + max_clock_lo: u32, + max_clock_hi: u32, + } + + pub struct SceKernelLMOption { + pub size: usize, + pub m_pid_text: SceUid, + pub m_pid_data: SceUid, + pub flags: u32, + pub position: u8, + pub access: u8, + pub c_reserved: [u8; 2usize], + } + + pub struct SceKernelSMOption { + pub size: usize, + pub m_pid_stack: SceUid, + pub stack_size: usize, + pub priority: i32, + pub attribute: u32, + } + + pub struct SceKernelModuleInfo { + pub size: usize, + pub n_segment: u8, + pub reserved: [u8; 3usize], + pub segment_addr: [i32; 4usize], + pub segment_size: [i32; 4usize], + pub entry_addr: u32, + pub gp_value: u32, + pub text_addr: u32, + pub text_size: u32, + pub data_size: u32, + pub bss_size: u32, + pub attribute: u16, + pub version: [u8; 2usize], + pub name: [u8; 28usize], + } + + pub struct DebugProfilerRegs { + pub enable: u32, + pub systemck: u32, + pub cpuck: u32, + pub internal: u32, + pub memory: u32, + pub copz: u32, + pub vfpu: u32, + pub sleep: u32, + pub bus_access: u32, + pub uncached_load: u32, + pub uncached_store: u32, + pub cached_load: u32, + pub cached_store: u32, + pub i_miss: u32, + pub d_miss: u32, + pub d_writeback: u32, + pub cop0_inst: u32, + pub fpu_inst: u32, + pub vfpu_inst: u32, + pub local_bus: u32, + } + + pub struct SceKernelSysClock { + pub low: u32, + pub hi: u32, + } + + pub struct SceKernelThreadOptParam { + pub size: usize, + pub stack_mpid: SceUid, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceKernelThreadInfo { + pub size: usize, + pub name: [u8; 32], + pub attr: u32, + pub status: i32, + pub entry: SceKernelThreadEntry, + pub stack: *mut c_void, + pub stack_size: i32, + pub gp_reg: *mut c_void, + pub init_priority: i32, + pub current_priority: i32, + pub wait_type: i32, + pub wait_id: SceUid, + pub wakeup_count: i32, + pub exit_status: i32, + pub run_clocks: SceKernelSysClock, + pub intr_preempt_count: u32, + pub thread_preempt_count: u32, + pub release_count: u32, + } + + pub struct SceKernelThreadRunStatus { + pub size: usize, + pub status: i32, + pub current_priority: i32, + pub wait_type: i32, + pub wait_id: i32, + pub wakeup_count: i32, + pub run_clocks: SceKernelSysClock, + pub intr_preempt_count: u32, + pub thread_preempt_count: u32, + pub release_count: u32, + } + + pub struct SceKernelSemaOptParam { + pub size: usize, + } + + pub struct SceKernelSemaInfo { + pub size: usize, + pub name: [u8; 32], + pub attr: u32, + pub init_count: i32, + pub current_count: i32, + pub max_count: i32, + pub num_wait_threads: i32, + } + + pub struct SceKernelEventFlagInfo { + pub size: usize, + pub name: [u8; 32], + pub attr: u32, + pub init_pattern: u32, + pub current_pattern: u32, + pub num_wait_threads: i32, + } + + pub struct SceKernelEventFlagOptParam { + pub size: usize, + } + + pub struct SceKernelMbxOptParam { + pub size: usize, + } + + pub struct SceKernelMbxInfo { + pub size: usize, + pub name: [u8; 32usize], + pub attr: u32, + pub num_wait_threads: i32, + pub num_messages: i32, + pub first_message: *mut c_void, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceKernelVTimerInfo { + pub size: usize, + pub name: [u8; 32], + pub active: i32, + pub base: SceKernelSysClock, + pub current: SceKernelSysClock, + pub schedule: SceKernelSysClock, + pub handler: SceKernelVTimerHandler, + pub common: *mut c_void, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceKernelThreadEventHandlerInfo { + pub size: usize, + pub name: [u8; 32], + pub thread_id: SceUid, + pub mask: i32, + pub handler: SceKernelThreadEventHandler, + pub common: *mut c_void, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceKernelAlarmInfo { + pub size: usize, + pub schedule: SceKernelSysClock, + pub handler: SceKernelAlarmHandler, + pub common: *mut c_void, + } + + pub struct SceKernelSystemStatus { + pub size: usize, + pub status: u32, + pub idle_clocks: SceKernelSysClock, + pub comes_out_of_idle_count: u32, + pub thread_switch_count: u32, + pub vfpu_switch_count: u32, + } + + pub struct SceKernelMppInfo { + pub size: usize, + pub name: [u8; 32], + pub attr: u32, + pub buf_size: i32, + pub free_size: i32, + pub num_send_wait_threads: i32, + pub num_receive_wait_threads: i32, + } + + pub struct SceKernelVplOptParam { + pub size: usize, + } + + pub struct SceKernelVplInfo { + pub size: usize, + pub name: [u8; 32], + pub attr: u32, + pub pool_size: i32, + pub free_size: i32, + pub num_wait_threads: i32, + } + + pub struct SceKernelFplOptParam { + pub size: usize, + } + + pub struct SceKernelFplInfo { + pub size: usize, + pub name: [u8; 32usize], + pub attr: u32, + pub block_size: i32, + pub num_blocks: i32, + pub free_blocks: i32, + pub num_wait_threads: i32, + } + + pub struct SceKernelVTimerOptParam { + pub size: usize, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceKernelCallbackInfo { + pub size: usize, + pub name: [u8; 32usize], + pub thread_id: SceUid, + pub callback: SceKernelCallbackFunction, + pub common: *mut c_void, + pub notify_count: i32, + pub notify_arg: i32, + } + + pub struct UsbCamSetupStillParam { + pub size: i32, + pub resolution: UsbCamResolution, + pub jpeg_size: i32, + pub reverse_flags: i32, + pub delay: UsbCamDelay, + pub comp_level: i32, + } + + pub struct UsbCamSetupStillExParam { + pub size: i32, + pub unk: u32, + pub resolution: UsbCamResolutionEx, + pub jpeg_size: i32, + pub comp_level: i32, + pub unk2: u32, + pub unk3: u32, + pub flip: i32, + pub mirror: i32, + pub delay: UsbCamDelay, + pub unk4: [u32; 5usize], + } + + pub struct UsbCamSetupVideoParam { + pub size: i32, + pub resolution: UsbCamResolution, + pub framerate: UsbCamFrameRate, + pub white_balance: UsbCamWb, + pub saturation: i32, + pub brightness: i32, + pub contrast: i32, + pub sharpness: i32, + pub effect_mode: UsbCamEffectMode, + pub frame_size: i32, + pub unk: u32, + pub evl_evel: UsbCamEvLevel, + } + + pub struct UsbCamSetupVideoExParam { + pub size: i32, + pub unk: u32, + pub resolution: UsbCamResolutionEx, + pub framerate: UsbCamFrameRate, + pub unk2: u32, + pub unk3: u32, + pub white_balance: UsbCamWb, + pub saturation: i32, + pub brightness: i32, + pub contrast: i32, + pub sharpness: i32, + pub unk4: u32, + pub unk5: u32, + pub unk6: [u32; 3usize], + pub effect_mode: UsbCamEffectMode, + pub unk7: u32, + pub unk8: u32, + pub unk9: u32, + pub unk10: u32, + pub unk11: u32, + pub frame_size: i32, + pub unk12: u32, + pub ev_level: UsbCamEvLevel, + } + + pub struct ScePspDateTime { + pub year: u16, + pub month: u16, + pub day: u16, + pub hour: u16, + pub minutes: u16, + pub seconds: u16, + pub microseconds: u32, + } + + pub struct SceIoStat { + pub st_mode: i32, + pub st_attr: i32, + pub st_size: i64, + pub st_ctime: ScePspDateTime, + pub st_atime: ScePspDateTime, + pub st_mtime: ScePspDateTime, + pub st_private: [u32; 6usize], + } + + pub struct UmdInfo { + pub size: u32, + pub type_: UmdType, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct SceMpegRingbuffer { + pub packets: i32, + pub unk0: u32, + pub unk1: u32, + pub unk2: u32, + pub unk3: u32, + pub data: *mut c_void, + pub callback: SceMpegRingbufferCb, + pub cb_param: *mut c_void, + pub unk4: u32, + pub unk5: u32, + pub sce_mpeg: *mut c_void, + } + + pub struct SceMpegAu { + pub pts_msb: u32, + pub pts: u32, + pub dts_msb: u32, + pub dts: u32, + pub es_buffer: u32, + pub au_size: u32, + } + + pub struct SceMpegAvcMode { + pub unk0: i32, + pub pixel_format: super::DisplayPixelFormat, + } + + #[repr(align(64))] + pub struct SceMpegLLI { + pub src: *mut c_void, + pub dst: *mut c_void, + pub next: *mut c_void, + pub size: i32, + } + + #[repr(align(64))] + pub struct SceMpegYCrCbBuffer { + pub frame_buffer_height16: i32, + pub frame_buffer_width16: i32, + pub unknown: i32, + pub unknown2: i32, + pub y_buffer: *mut c_void, + pub y_buffer2: *mut c_void, + pub cr_buffer: *mut c_void, + pub cb_buffer: *mut c_void, + pub cr_buffer2: *mut c_void, + pub cb_buffer2: *mut c_void, + + pub frame_height: i32, + pub frame_width: i32, + pub frame_buffer_width: i32, + pub unknown3: [i32; 11usize], + } + + pub struct ScePspSRect { + pub x: i16, + pub y: i16, + pub w: i16, + pub h: i16, + } + + pub struct ScePspIRect { + pub x: i32, + pub y: i32, + pub w: i32, + pub h: i32, + } + + pub struct ScePspL64Rect { + pub x: u64, + pub y: u64, + pub w: u64, + pub h: u64, + } + + pub struct ScePspSVector2 { + pub x: i16, + pub y: i16, + } + + pub struct ScePspIVector2 { + pub x: i32, + pub y: i32, + } + + pub struct ScePspL64Vector2 { + pub x: u64, + pub y: u64, + } + + pub struct ScePspSVector3 { + pub x: i16, + pub y: i16, + pub z: i16, + } + + pub struct ScePspIVector3 { + pub x: i32, + pub y: i32, + pub z: i32, + } + + pub struct ScePspL64Vector3 { + pub x: u64, + pub y: u64, + pub z: u64, + } + + pub struct ScePspSVector4 { + pub x: i16, + pub y: i16, + pub z: i16, + pub w: i16, + } + + pub struct ScePspIVector4 { + pub x: i32, + pub y: i32, + pub z: i32, + pub w: i32, + } + + pub struct ScePspL64Vector4 { + pub x: u64, + pub y: u64, + pub z: u64, + pub w: u64, + } + + pub struct ScePspIMatrix2 { + pub x: ScePspIVector2, + pub y: ScePspIVector2, + } + + pub struct ScePspIMatrix3 { + pub x: ScePspIVector3, + pub y: ScePspIVector3, + pub z: ScePspIVector3, + } + + #[repr(align(16))] + pub struct ScePspIMatrix4 { + pub x: ScePspIVector4, + pub y: ScePspIVector4, + pub z: ScePspIVector4, + pub w: ScePspIVector4, + } + + pub struct ScePspIMatrix4Unaligned { + pub x: ScePspIVector4, + pub y: ScePspIVector4, + pub z: ScePspIVector4, + pub w: ScePspIVector4, + } + + pub struct SceMp3InitArg { + pub mp3_stream_start: u32, + pub unk1: u32, + pub mp3_stream_end: u32, + pub unk2: u32, + pub mp3_buf: *mut c_void, + pub mp3_buf_size: i32, + pub pcm_buf: *mut c_void, + pub pcm_buf_size: i32, + } + + pub struct OpenPSID { + pub data: [u8; 16usize], + } + + pub struct UtilityDialogCommon { + pub size: u32, + pub language: SystemParamLanguage, + pub button_accept: UtilityDialogButtonAccept, + pub graphics_thread: i32, + pub access_thread: i32, + pub font_thread: i32, + pub sound_thread: i32, + pub result: i32, + pub reserved: [i32; 4usize], + } + + pub struct UtilityNetconfAdhoc { + pub name: [u8; 8usize], + pub timeout: u32, + } + + pub struct UtilityNetconfData { + pub base: UtilityDialogCommon, + pub action: UtilityNetconfAction, + pub adhocparam: *mut UtilityNetconfAdhoc, + pub hotspot: i32, + pub hotspot_connected: i32, + pub wifisp: i32, + } + + pub struct UtilitySavedataFileData { + pub buf: *mut c_void, + pub buf_size: usize, + pub size: usize, + pub unknown: i32, + } + + pub struct UtilitySavedataListSaveNewData { + pub icon0: UtilitySavedataFileData, + pub title: *mut u8, + } + + pub struct UtilityGameSharingParams { + pub base: UtilityDialogCommon, + pub unknown1: i32, + pub unknown2: i32, + pub name: [u8; 8usize], + pub unknown3: i32, + pub unknown4: i32, + pub unknown5: i32, + pub result: i32, + pub filepath: *mut u8, + pub mode: UtilityGameSharingMode, + pub datatype: UtilityGameSharingDataType, + pub data: *mut c_void, + pub datasize: u32, + } + + pub struct UtilityHtmlViewerParam { + pub base: UtilityDialogCommon, + pub memaddr: *mut c_void, + pub memsize: u32, + pub unknown1: i32, + pub unknown2: i32, + pub initialurl: *mut u8, + pub numtabs: u32, + pub interfacemode: UtilityHtmlViewerInterfaceMode, + pub options: i32, + pub dldirname: *mut u8, + pub dlfilename: *mut u8, + pub uldirname: *mut u8, + pub ulfilename: *mut u8, + pub cookiemode: UtilityHtmlViewerCookieMode, + pub unknown3: u32, + pub homeurl: *mut u8, + pub textsize: UtilityHtmlViewerTextSize, + pub displaymode: UtilityHtmlViewerDisplayMode, + pub connectmode: UtilityHtmlViewerConnectMode, + pub disconnectmode: UtilityHtmlViewerDisconnectMode, + pub memused: u32, + pub unknown4: [i32; 10usize], + } + + pub struct SceUtilityOskData { + pub unk_00: i32, + pub unk_04: i32, + pub language: SceUtilityOskInputLanguage, + pub unk_12: i32, + pub inputtype: SceUtilityOskInputType, + pub lines: i32, + pub unk_24: i32, + pub desc: *mut u16, + pub intext: *mut u16, + pub outtextlength: i32, + pub outtext: *mut u16, + pub result: SceUtilityOskResult, + pub outtextlimit: i32, + } + + pub struct SceUtilityOskParams { + pub base: UtilityDialogCommon, + pub datacount: i32, + pub data: *mut SceUtilityOskData, + pub state: SceUtilityOskState, + pub unk_60: i32, + } + + pub struct SceNetMallocStat { + pub pool: i32, + pub maximum: i32, + pub free: i32, + } + + pub struct SceNetAdhocctlAdhocId { + pub unknown: i32, + pub adhoc_id: [u8; 9usize], + pub unk: [u8; 3usize], + } + + pub struct SceNetAdhocctlScanInfo { + pub next: *mut SceNetAdhocctlScanInfo, + pub channel: i32, + pub name: [u8; 8usize], + pub bssid: [u8; 6usize], + pub unknown: [u8; 2usize], + pub unknown2: i32, + } + + pub struct SceNetAdhocctlGameModeInfo { + pub count: i32, + pub macs: [[u8; 6usize]; 16usize], + } + + pub struct SceNetAdhocPtpStat { + pub next: *mut SceNetAdhocPtpStat, + pub ptp_id: i32, + pub mac: [u8; 6usize], + pub peermac: [u8; 6usize], + pub port: u16, + pub peerport: u16, + pub sent_data: u32, + pub rcvd_data: u32, + pub state: ScePspnetAdhocPtpState, + } + + pub struct SceNetAdhocPdpStat { + pub next: *mut SceNetAdhocPdpStat, + pub pdp_id: i32, + pub mac: [u8; 6usize], + pub port: u16, + pub rcvd_data: u32, + } + + pub struct AdhocPoolStat { + pub size: i32, + pub maxsize: i32, + pub freesize: i32, + } +} + +s_no_extra_traits! { + pub struct GeContext { + pub context: [u32; 512], + } + + pub struct SceKernelUtilsSha1Context { + pub h: [u32; 5usize], + pub us_remains: u16, + pub us_computed: u16, + pub ull_total_len: u64, + pub buf: [u8; 64usize], + } + + pub struct SceKernelUtilsMt19937Context { + pub count: u32, + pub state: [u32; 624usize], + } + + pub struct SceKernelUtilsMd5Context { + pub h: [u32; 4usize], + pub pad: u32, + pub us_remains: u16, + pub us_computed: u16, + pub ull_total_len: u64, + pub buf: [u8; 64usize], + } + + pub struct SceIoDirent { + pub d_stat: SceIoStat, + pub d_name: [u8; 256usize], + pub d_private: *mut c_void, + pub dummy: i32, + } + + pub struct ScePspFRect { + pub x: f32, + pub y: f32, + pub w: f32, + pub h: f32, + } + + #[repr(align(16))] + pub struct ScePspFVector3 { + pub x: f32, + pub y: f32, + pub z: f32, + } + + #[repr(align(16))] + pub struct ScePspFVector4 { + pub x: f32, + pub y: f32, + pub z: f32, + pub w: f32, + } + + pub struct ScePspFVector4Unaligned { + pub x: f32, + pub y: f32, + pub z: f32, + pub w: f32, + } + + pub struct ScePspFVector2 { + pub x: f32, + pub y: f32, + } + + pub struct ScePspFMatrix2 { + pub x: ScePspFVector2, + pub y: ScePspFVector2, + } + + pub struct ScePspFMatrix3 { + pub x: ScePspFVector3, + pub y: ScePspFVector3, + pub z: ScePspFVector3, + } + + #[repr(align(16))] + pub struct ScePspFMatrix4 { + pub x: ScePspFVector4, + pub y: ScePspFVector4, + pub z: ScePspFVector4, + pub w: ScePspFVector4, + } + + pub struct ScePspFMatrix4Unaligned { + pub x: ScePspFVector4, + pub y: ScePspFVector4, + pub z: ScePspFVector4, + pub w: ScePspFVector4, + } + + pub union ScePspVector3 { + pub fv: ScePspFVector3, + pub iv: ScePspIVector3, + pub f: [f32; 3usize], + pub i: [i32; 3usize], + } + + pub union ScePspVector4 { + pub fv: ScePspFVector4, + pub iv: ScePspIVector4, + pub qw: u128, + pub f: [f32; 4usize], + pub i: [i32; 4usize], + } + + pub union ScePspMatrix2 { + pub fm: ScePspFMatrix2, + pub im: ScePspIMatrix2, + pub fv: [ScePspFVector2; 2usize], + pub iv: [ScePspIVector2; 2usize], + pub v: [ScePspVector2; 2usize], + pub f: [[f32; 2usize]; 2usize], + pub i: [[i32; 2usize]; 2usize], + } + + pub union ScePspMatrix3 { + pub fm: ScePspFMatrix3, + pub im: ScePspIMatrix3, + pub fv: [ScePspFVector3; 3usize], + pub iv: [ScePspIVector3; 3usize], + pub v: [ScePspVector3; 3usize], + pub f: [[f32; 3usize]; 3usize], + pub i: [[i32; 3usize]; 3usize], + } + + pub union ScePspVector2 { + pub fv: ScePspFVector2, + pub iv: ScePspIVector2, + pub f: [f32; 2usize], + pub i: [i32; 2usize], + } + + pub union ScePspMatrix4 { + pub fm: ScePspFMatrix4, + pub im: ScePspIMatrix4, + pub fv: [ScePspFVector4; 4usize], + pub iv: [ScePspIVector4; 4usize], + pub v: [ScePspVector4; 4usize], + pub f: [[f32; 4usize]; 4usize], + pub i: [[i32; 4usize]; 4usize], + } + + pub struct Key { + pub key_type: KeyType, + pub name: [u8; 256usize], + pub name_len: u32, + pub unk2: u32, + pub unk3: u32, + } + + pub struct UtilityMsgDialogParams { + pub base: UtilityDialogCommon, + pub unknown: i32, + pub mode: UtilityMsgDialogMode, + pub error_value: u32, + pub message: [u8; 512usize], + pub options: i32, + pub button_pressed: UtilityMsgDialogPressed, + } + + pub union UtilityNetData { + pub as_uint: u32, + pub as_string: [u8; 128usize], + } + + pub struct UtilitySavedataSFOParam { + pub title: [u8; 128usize], + pub savedata_title: [u8; 128usize], + pub detail: [u8; 1024usize], + pub parental_level: u8, + pub unknown: [u8; 3usize], + } + + pub struct SceUtilitySavedataParam { + pub base: UtilityDialogCommon, + pub mode: UtilitySavedataMode, + pub unknown1: i32, + pub overwrite: i32, + pub game_name: [u8; 13usize], + pub reserved: [u8; 3usize], + pub save_name: [u8; 20usize], + pub save_name_list: *mut [u8; 20usize], + pub file_name: [u8; 13usize], + pub reserved1: [u8; 3usize], + pub data_buf: *mut c_void, + pub data_buf_size: usize, + pub data_size: usize, + pub sfo_param: UtilitySavedataSFOParam, + pub icon0_file_data: UtilitySavedataFileData, + pub icon1_file_data: UtilitySavedataFileData, + pub pic1_file_data: UtilitySavedataFileData, + pub snd0_file_data: UtilitySavedataFileData, + pub new_data: *mut UtilitySavedataListSaveNewData, + pub focus: UtilitySavedataFocus, + pub unknown2: [i32; 4usize], + pub key: [u8; 16], + pub unknown3: [u8; 20], + } + + pub struct SceNetAdhocctlPeerInfo { + pub next: *mut SceNetAdhocctlPeerInfo, + pub nickname: [u8; 128usize], + pub mac: [u8; 6usize], + pub unknown: [u8; 6usize], + pub timestamp: u32, + } + + pub struct SceNetAdhocctlParams { + pub channel: i32, + pub name: [u8; 8usize], + pub bssid: [u8; 6usize], + pub nickname: [u8; 128usize], + } + + pub union SceNetApctlInfo { + pub name: [u8; 64usize], + pub bssid: [u8; 6usize], + pub ssid: [u8; 32usize], + pub ssid_length: u32, + pub security_type: u32, + pub strength: u8, + pub channel: u8, + pub power_save: u8, + pub ip: [u8; 16usize], + pub sub_net_mask: [u8; 16usize], + pub gateway: [u8; 16usize], + pub primary_dns: [u8; 16usize], + pub secondary_dns: [u8; 16usize], + pub use_proxy: u32, + pub proxy_url: [u8; 128usize], + pub proxy_port: u16, + pub eap_type: u32, + pub start_browser: u32, + pub wifisp: u32, + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const AUDIO_VOLUME_MAX: u32 = 0x8000; +pub const AUDIO_CHANNEL_MAX: u32 = 8; +pub const AUDIO_NEXT_CHANNEL: i32 = -1; +pub const AUDIO_SAMPLE_MIN: u32 = 64; +pub const AUDIO_SAMPLE_MAX: u32 = 65472; + +pub const PSP_CTRL_SELECT: i32 = 0x000001; +pub const PSP_CTRL_START: i32 = 0x000008; +pub const PSP_CTRL_UP: i32 = 0x000010; +pub const PSP_CTRL_RIGHT: i32 = 0x000020; +pub const PSP_CTRL_DOWN: i32 = 0x000040; +pub const PSP_CTRL_LEFT: i32 = 0x000080; +pub const PSP_CTRL_LTRIGGER: i32 = 0x000100; +pub const PSP_CTRL_RTRIGGER: i32 = 0x000200; +pub const PSP_CTRL_TRIANGLE: i32 = 0x001000; +pub const PSP_CTRL_CIRCLE: i32 = 0x002000; +pub const PSP_CTRL_CROSS: i32 = 0x004000; +pub const PSP_CTRL_SQUARE: i32 = 0x008000; +pub const PSP_CTRL_HOME: i32 = 0x010000; +pub const PSP_CTRL_HOLD: i32 = 0x020000; +pub const PSP_CTRL_NOTE: i32 = 0x800000; +pub const PSP_CTRL_SCREEN: i32 = 0x400000; +pub const PSP_CTRL_VOLUP: i32 = 0x100000; +pub const PSP_CTRL_VOLDOWN: i32 = 0x200000; +pub const PSP_CTRL_WLAN_UP: i32 = 0x040000; +pub const PSP_CTRL_REMOTE: i32 = 0x080000; +pub const PSP_CTRL_DISC: i32 = 0x1000000; +pub const PSP_CTRL_MS: i32 = 0x2000000; + +pub const USB_CAM_PID: i32 = 0x282; +pub const USB_BUS_DRIVER_NAME: &str = "USBBusDriver"; +pub const USB_CAM_DRIVER_NAME: &str = "USBCamDriver"; +pub const USB_CAM_MIC_DRIVER_NAME: &str = "USBCamMicDriver"; +pub const USB_STOR_DRIVER_NAME: &str = "USBStor_Driver"; + +pub const ACTIVATED: i32 = 0x200; +pub const CONNECTED: i32 = 0x020; +pub const ESTABLISHED: i32 = 0x002; + +pub const USB_CAM_FLIP: i32 = 1; +pub const USB_CAM_MIRROR: i32 = 0x100; + +pub const THREAD_ATTR_VFPU: i32 = 0x00004000; +pub const THREAD_ATTR_USER: i32 = 0x80000000; +pub const THREAD_ATTR_USBWLAN: i32 = 0xa0000000; +pub const THREAD_ATTR_VSH: i32 = 0xc0000000; +pub const THREAD_ATTR_SCRATCH_SRAM: i32 = 0x00008000; +pub const THREAD_ATTR_NO_FILLSTACK: i32 = 0x00100000; +pub const THREAD_ATTR_CLEAR_STACK: i32 = 0x00200000; + +pub const EVENT_WAIT_MULTIPLE: i32 = 0x200; + +pub const EVENT_WAIT_AND: i32 = 0; +pub const EVENT_WAIT_OR: i32 = 1; +pub const EVENT_WAIT_CLEAR: i32 = 0x20; + +pub const POWER_INFO_POWER_SWITCH: i32 = 0x80000000; +pub const POWER_INFO_HOLD_SWITCH: i32 = 0x40000000; +pub const POWER_INFO_STANDBY: i32 = 0x00080000; +pub const POWER_INFO_RESUME_COMPLETE: i32 = 0x00040000; +pub const POWER_INFO_RESUMING: i32 = 0x00020000; +pub const POWER_INFO_SUSPENDING: i32 = 0x00010000; +pub const POWER_INFO_AC_POWER: i32 = 0x00001000; +pub const POWER_INFO_BATTERY_LOW: i32 = 0x00000100; +pub const POWER_INFO_BATTERY_EXIST: i32 = 0x00000080; +pub const POWER_INFO_BATTERY_POWER: i32 = 0x0000007; + +pub const FIO_S_IFLNK: i32 = 0x4000; +pub const FIO_S_IFDIR: i32 = 0x1000; +pub const FIO_S_IFREG: i32 = 0x2000; +pub const FIO_S_ISUID: i32 = 0x0800; +pub const FIO_S_ISGID: i32 = 0x0400; +pub const FIO_S_ISVTX: i32 = 0x0200; +pub const FIO_S_IRUSR: i32 = 0x0100; +pub const FIO_S_IWUSR: i32 = 0x0080; +pub const FIO_S_IXUSR: i32 = 0x0040; +pub const FIO_S_IRGRP: i32 = 0x0020; +pub const FIO_S_IWGRP: i32 = 0x0010; +pub const FIO_S_IXGRP: i32 = 0x0008; +pub const FIO_S_IROTH: i32 = 0x0004; +pub const FIO_S_IWOTH: i32 = 0x0002; +pub const FIO_S_IXOTH: i32 = 0x0001; + +pub const FIO_SO_IFLNK: i32 = 0x0008; +pub const FIO_SO_IFDIR: i32 = 0x0010; +pub const FIO_SO_IFREG: i32 = 0x0020; +pub const FIO_SO_IROTH: i32 = 0x0004; +pub const FIO_SO_IWOTH: i32 = 0x0002; +pub const FIO_SO_IXOTH: i32 = 0x0001; + +pub const PSP_O_RD_ONLY: i32 = 0x0001; +pub const PSP_O_WR_ONLY: i32 = 0x0002; +pub const PSP_O_RD_WR: i32 = 0x0003; +pub const PSP_O_NBLOCK: i32 = 0x0004; +pub const PSP_O_DIR: i32 = 0x0008; +pub const PSP_O_APPEND: i32 = 0x0100; +pub const PSP_O_CREAT: i32 = 0x0200; +pub const PSP_O_TRUNC: i32 = 0x0400; +pub const PSP_O_EXCL: i32 = 0x0800; +pub const PSP_O_NO_WAIT: i32 = 0x8000; + +pub const UMD_NOT_PRESENT: i32 = 0x01; +pub const UMD_PRESENT: i32 = 0x02; +pub const UMD_CHANGED: i32 = 0x04; +pub const UMD_INITING: i32 = 0x08; +pub const UMD_INITED: i32 = 0x10; +pub const UMD_READY: i32 = 0x20; + +pub const PLAY_PAUSE: i32 = 0x1; +pub const FORWARD: i32 = 0x4; +pub const BACK: i32 = 0x8; +pub const VOL_UP: i32 = 0x10; +pub const VOL_DOWN: i32 = 0x20; +pub const HOLD: i32 = 0x80; + +pub const GU_PI: f32 = 3.141593; + +pub const GU_TEXTURE_8BIT: i32 = 1; +pub const GU_TEXTURE_16BIT: i32 = 2; +pub const GU_TEXTURE_32BITF: i32 = 3; +pub const GU_COLOR_5650: i32 = 4 << 2; +pub const GU_COLOR_5551: i32 = 5 << 2; +pub const GU_COLOR_4444: i32 = 6 << 2; +pub const GU_COLOR_8888: i32 = 7 << 2; +pub const GU_NORMAL_8BIT: i32 = 1 << 5; +pub const GU_NORMAL_16BIT: i32 = 2 << 5; +pub const GU_NORMAL_32BITF: i32 = 3 << 5; +pub const GU_VERTEX_8BIT: i32 = 1 << 7; +pub const GU_VERTEX_16BIT: i32 = 2 << 7; +pub const GU_VERTEX_32BITF: i32 = 3 << 7; +pub const GU_WEIGHT_8BIT: i32 = 1 << 9; +pub const GU_WEIGHT_16BIT: i32 = 2 << 9; +pub const GU_WEIGHT_32BITF: i32 = 3 << 9; +pub const GU_INDEX_8BIT: i32 = 1 << 11; +pub const GU_INDEX_16BIT: i32 = 2 << 11; +pub const GU_WEIGHTS1: i32 = (((1 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS2: i32 = (((2 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS3: i32 = (((3 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS4: i32 = (((4 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS5: i32 = (((5 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS6: i32 = (((6 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS7: i32 = (((7 - 1) & 7) << 14) as i32; +pub const GU_WEIGHTS8: i32 = (((8 - 1) & 7) << 14) as i32; +pub const GU_VERTICES1: i32 = (((1 - 1) & 7) << 18) as i32; +pub const GU_VERTICES2: i32 = (((2 - 1) & 7) << 18) as i32; +pub const GU_VERTICES3: i32 = (((3 - 1) & 7) << 18) as i32; +pub const GU_VERTICES4: i32 = (((4 - 1) & 7) << 18) as i32; +pub const GU_VERTICES5: i32 = (((5 - 1) & 7) << 18) as i32; +pub const GU_VERTICES6: i32 = (((6 - 1) & 7) << 18) as i32; +pub const GU_VERTICES7: i32 = (((7 - 1) & 7) << 18) as i32; +pub const GU_VERTICES8: i32 = (((8 - 1) & 7) << 18) as i32; +pub const GU_TRANSFORM_2D: i32 = 1 << 23; +pub const GU_TRANSFORM_3D: i32 = 0; + +pub const GU_COLOR_BUFFER_BIT: i32 = 1; +pub const GU_STENCIL_BUFFER_BIT: i32 = 2; +pub const GU_DEPTH_BUFFER_BIT: i32 = 4; +pub const GU_FAST_CLEAR_BIT: i32 = 16; + +pub const GU_AMBIENT: i32 = 1; +pub const GU_DIFFUSE: i32 = 2; +pub const GU_SPECULAR: i32 = 4; +pub const GU_UNKNOWN_LIGHT_COMPONENT: i32 = 8; + +pub const SYSTEM_REGISTRY: [u8; 7] = *b"/system"; +pub const REG_KEYNAME_SIZE: u32 = 27; + +pub const UTILITY_MSGDIALOG_ERROR: i32 = 0; +pub const UTILITY_MSGDIALOG_TEXT: i32 = 1; +pub const UTILITY_MSGDIALOG_YES_NO_BUTTONS: i32 = 0x10; +pub const UTILITY_MSGDIALOG_DEFAULT_NO: i32 = 0x100; + +pub const UTILITY_HTMLVIEWER_OPEN_SCE_START_PAGE: i32 = 0x000001; +pub const UTILITY_HTMLVIEWER_DISABLE_STARTUP_LIMITS: i32 = 0x000002; +pub const UTILITY_HTMLVIEWER_DISABLE_EXIT_DIALOG: i32 = 0x000004; +pub const UTILITY_HTMLVIEWER_DISABLE_CURSOR: i32 = 0x000008; +pub const UTILITY_HTMLVIEWER_DISABLE_DOWNLOAD_COMPLETE_DIALOG: i32 = 0x000010; +pub const UTILITY_HTMLVIEWER_DISABLE_DOWNLOAD_START_DIALOG: i32 = 0x000020; +pub const UTILITY_HTMLVIEWER_DISABLE_DOWNLOAD_DESTINATION_DIALOG: i32 = 0x000040; +pub const UTILITY_HTMLVIEWER_LOCK_DOWNLOAD_DESTINATION_DIALOG: i32 = 0x000080; +pub const UTILITY_HTMLVIEWER_DISABLE_TAB_DISPLAY: i32 = 0x000100; +pub const UTILITY_HTMLVIEWER_ENABLE_ANALOG_HOLD: i32 = 0x000200; +pub const UTILITY_HTMLVIEWER_ENABLE_FLASH: i32 = 0x000400; +pub const UTILITY_HTMLVIEWER_DISABLE_LRTRIGGER: i32 = 0x000800; + +extern "C" { + pub fn sceAudioChReserve(channel: i32, sample_count: i32, format: AudioFormat) -> i32; + pub fn sceAudioChRelease(channel: i32) -> i32; + pub fn sceAudioOutput(channel: i32, vol: i32, buf: *mut c_void) -> i32; + pub fn sceAudioOutputBlocking(channel: i32, vol: i32, buf: *mut c_void) -> i32; + pub fn sceAudioOutputPanned( + channel: i32, + left_vol: i32, + right_vol: i32, + buf: *mut c_void, + ) -> i32; + pub fn sceAudioOutputPannedBlocking( + channel: i32, + left_vol: i32, + right_vol: i32, + buf: *mut c_void, + ) -> i32; + pub fn sceAudioGetChannelRestLen(channel: i32) -> i32; + pub fn sceAudioGetChannelRestLength(channel: i32) -> i32; + pub fn sceAudioSetChannelDataLen(channel: i32, sample_count: i32) -> i32; + pub fn sceAudioChangeChannelConfig(channel: i32, format: AudioFormat) -> i32; + pub fn sceAudioChangeChannelVolume(channel: i32, left_vol: i32, right_vol: i32) -> i32; + pub fn sceAudioOutput2Reserve(sample_count: i32) -> i32; + pub fn sceAudioOutput2Release() -> i32; + pub fn sceAudioOutput2ChangeLength(sample_count: i32) -> i32; + pub fn sceAudioOutput2OutputBlocking(vol: i32, buf: *mut c_void) -> i32; + pub fn sceAudioOutput2GetRestSample() -> i32; + pub fn sceAudioSRCChReserve( + sample_count: i32, + freq: AudioOutputFrequency, + channels: i32, + ) -> i32; + pub fn sceAudioSRCChRelease() -> i32; + pub fn sceAudioSRCOutputBlocking(vol: i32, buf: *mut c_void) -> i32; + pub fn sceAudioInputInit(unknown1: i32, gain: i32, unknown2: i32) -> i32; + pub fn sceAudioInputInitEx(params: *mut AudioInputParams) -> i32; + pub fn sceAudioInputBlocking(sample_count: i32, freq: AudioInputFrequency, buf: *mut c_void); + pub fn sceAudioInput(sample_count: i32, freq: AudioInputFrequency, buf: *mut c_void); + pub fn sceAudioGetInputLength() -> i32; + pub fn sceAudioWaitInputEnd() -> i32; + pub fn sceAudioPollInputEnd() -> i32; + + pub fn sceAtracGetAtracID(ui_codec_type: u32) -> i32; + pub fn sceAtracSetDataAndGetID(buf: *mut c_void, bufsize: usize) -> i32; + pub fn sceAtracDecodeData( + atrac_id: i32, + out_samples: *mut u16, + out_n: *mut i32, + out_end: *mut i32, + out_remain_frame: *mut i32, + ) -> i32; + pub fn sceAtracGetRemainFrame(atrac_id: i32, out_remain_frame: *mut i32) -> i32; + pub fn sceAtracGetStreamDataInfo( + atrac_id: i32, + write_pointer: *mut *mut u8, + available_bytes: *mut u32, + read_offset: *mut u32, + ) -> i32; + pub fn sceAtracAddStreamData(atrac_id: i32, bytes_to_add: u32) -> i32; + pub fn sceAtracGetBitrate(atrac_id: i32, out_bitrate: *mut i32) -> i32; + pub fn sceAtracSetLoopNum(atrac_id: i32, nloops: i32) -> i32; + pub fn sceAtracReleaseAtracID(atrac_id: i32) -> i32; + pub fn sceAtracGetNextSample(atrac_id: i32, out_n: *mut i32) -> i32; + pub fn sceAtracGetMaxSample(atrac_id: i32, out_max: *mut i32) -> i32; + pub fn sceAtracGetBufferInfoForReseting( + atrac_id: i32, + ui_sample: u32, + pbuffer_info: *mut Atrac3BufferInfo, + ) -> i32; + pub fn sceAtracGetChannel(atrac_id: i32, pui_channel: *mut u32) -> i32; + pub fn sceAtracGetInternalErrorInfo(atrac_id: i32, pi_result: *mut i32) -> i32; + pub fn sceAtracGetLoopStatus( + atrac_id: i32, + pi_loop_num: *mut i32, + pui_loop_status: *mut u32, + ) -> i32; + pub fn sceAtracGetNextDecodePosition(atrac_id: i32, pui_sample_position: *mut u32) -> i32; + pub fn sceAtracGetSecondBufferInfo( + atrac_id: i32, + pui_position: *mut u32, + pui_data_byte: *mut u32, + ) -> i32; + pub fn sceAtracGetSoundSample( + atrac_id: i32, + pi_end_sample: *mut i32, + pi_loop_start_sample: *mut i32, + pi_loop_end_sample: *mut i32, + ) -> i32; + pub fn sceAtracResetPlayPosition( + atrac_id: i32, + ui_sample: u32, + ui_write_byte_first_buf: u32, + ui_write_byte_second_buf: u32, + ) -> i32; + pub fn sceAtracSetData(atrac_id: i32, puc_buffer_addr: *mut u8, ui_buffer_byte: u32) -> i32; + pub fn sceAtracSetHalfwayBuffer( + atrac_id: i32, + puc_buffer_addr: *mut u8, + ui_read_byte: u32, + ui_buffer_byte: u32, + ) -> i32; + pub fn sceAtracSetHalfwayBufferAndGetID( + puc_buffer_addr: *mut u8, + ui_read_byte: u32, + ui_buffer_byte: u32, + ) -> i32; + pub fn sceAtracSetSecondBuffer( + atrac_id: i32, + puc_second_buffer_addr: *mut u8, + ui_second_buffer_byte: u32, + ) -> i32; + + pub fn sceCtrlSetSamplingCycle(cycle: i32) -> i32; + pub fn sceCtrlGetSamplingCycle(pcycle: *mut i32) -> i32; + pub fn sceCtrlSetSamplingMode(mode: CtrlMode) -> i32; + pub fn sceCtrlGetSamplingMode(pmode: *mut i32) -> i32; + pub fn sceCtrlPeekBufferPositive(pad_data: *mut SceCtrlData, count: i32) -> i32; + pub fn sceCtrlPeekBufferNegative(pad_data: *mut SceCtrlData, count: i32) -> i32; + pub fn sceCtrlReadBufferPositive(pad_data: *mut SceCtrlData, count: i32) -> i32; + pub fn sceCtrlReadBufferNegative(pad_data: *mut SceCtrlData, count: i32) -> i32; + pub fn sceCtrlPeekLatch(latch_data: *mut SceCtrlLatch) -> i32; + pub fn sceCtrlReadLatch(latch_data: *mut SceCtrlLatch) -> i32; + pub fn sceCtrlSetIdleCancelThreshold(idlereset: i32, idleback: i32) -> i32; + pub fn sceCtrlGetIdleCancelThreshold(idlereset: *mut i32, idleback: *mut i32) -> i32; + + pub fn sceDisplaySetMode(mode: DisplayMode, width: usize, height: usize) -> u32; + pub fn sceDisplayGetMode(pmode: *mut i32, pwidth: *mut i32, pheight: *mut i32) -> i32; + pub fn sceDisplaySetFrameBuf( + top_addr: *const u8, + buffer_width: usize, + pixel_format: DisplayPixelFormat, + sync: DisplaySetBufSync, + ) -> u32; + pub fn sceDisplayGetFrameBuf( + top_addr: *mut *mut c_void, + buffer_width: *mut usize, + pixel_format: *mut DisplayPixelFormat, + sync: DisplaySetBufSync, + ) -> i32; + pub fn sceDisplayGetVcount() -> u32; + pub fn sceDisplayWaitVblank() -> i32; + pub fn sceDisplayWaitVblankCB() -> i32; + pub fn sceDisplayWaitVblankStart() -> i32; + pub fn sceDisplayWaitVblankStartCB() -> i32; + pub fn sceDisplayGetAccumulatedHcount() -> i32; + pub fn sceDisplayGetCurrentHcount() -> i32; + pub fn sceDisplayGetFramePerSec() -> f32; + pub fn sceDisplayIsForeground() -> i32; + pub fn sceDisplayIsVblank() -> i32; + + pub fn sceGeEdramGetSize() -> u32; + pub fn sceGeEdramGetAddr() -> *mut u8; + pub fn sceGeEdramSetAddrTranslation(width: i32) -> i32; + pub fn sceGeGetCmd(cmd: i32) -> u32; + pub fn sceGeGetMtx(type_: GeMatrixType, matrix: *mut c_void) -> i32; + pub fn sceGeGetStack(stack_id: i32, stack: *mut GeStack) -> i32; + pub fn sceGeSaveContext(context: *mut GeContext) -> i32; + pub fn sceGeRestoreContext(context: *const GeContext) -> i32; + pub fn sceGeListEnQueue( + list: *const c_void, + stall: *mut c_void, + cbid: i32, + arg: *mut GeListArgs, + ) -> i32; + pub fn sceGeListEnQueueHead( + list: *const c_void, + stall: *mut c_void, + cbid: i32, + arg: *mut GeListArgs, + ) -> i32; + pub fn sceGeListDeQueue(qid: i32) -> i32; + pub fn sceGeListUpdateStallAddr(qid: i32, stall: *mut c_void) -> i32; + pub fn sceGeListSync(qid: i32, sync_type: i32) -> GeListState; + pub fn sceGeDrawSync(sync_type: i32) -> GeListState; + pub fn sceGeBreak(mode: i32, p_param: *mut GeBreakParam) -> i32; + pub fn sceGeContinue() -> i32; + pub fn sceGeSetCallback(cb: *mut GeCallbackData) -> i32; + pub fn sceGeUnsetCallback(cbid: i32) -> i32; + + pub fn sceKernelExitGame(); + pub fn sceKernelRegisterExitCallback(id: SceUid) -> i32; + pub fn sceKernelLoadExec(file: *const u8, param: *mut SceKernelLoadExecParam) -> i32; + + pub fn sceKernelAllocPartitionMemory( + partition: SceSysMemPartitionId, + name: *const u8, + type_: SceSysMemBlockTypes, + size: u32, + addr: *mut c_void, + ) -> SceUid; + pub fn sceKernelGetBlockHeadAddr(blockid: SceUid) -> *mut c_void; + pub fn sceKernelFreePartitionMemory(blockid: SceUid) -> i32; + pub fn sceKernelTotalFreeMemSize() -> usize; + pub fn sceKernelMaxFreeMemSize() -> usize; + pub fn sceKernelDevkitVersion() -> u32; + pub fn sceKernelSetCompiledSdkVersion(version: u32) -> i32; + pub fn sceKernelGetCompiledSdkVersion() -> u32; + + pub fn sceKernelLibcTime(t: *mut i32) -> i32; + pub fn sceKernelLibcClock() -> u32; + pub fn sceKernelLibcGettimeofday(tp: *mut timeval, tzp: *mut timezone) -> i32; + pub fn sceKernelDcacheWritebackAll(); + pub fn sceKernelDcacheWritebackInvalidateAll(); + pub fn sceKernelDcacheWritebackRange(p: *const c_void, size: u32); + pub fn sceKernelDcacheWritebackInvalidateRange(p: *const c_void, size: u32); + pub fn sceKernelDcacheInvalidateRange(p: *const c_void, size: u32); + pub fn sceKernelIcacheInvalidateAll(); + pub fn sceKernelIcacheInvalidateRange(p: *const c_void, size: u32); + pub fn sceKernelUtilsMt19937Init(ctx: *mut SceKernelUtilsMt19937Context, seed: u32) -> i32; + pub fn sceKernelUtilsMt19937UInt(ctx: *mut SceKernelUtilsMt19937Context) -> u32; + pub fn sceKernelUtilsMd5Digest(data: *mut u8, size: u32, digest: *mut u8) -> i32; + pub fn sceKernelUtilsMd5BlockInit(ctx: *mut SceKernelUtilsMd5Context) -> i32; + pub fn sceKernelUtilsMd5BlockUpdate( + ctx: *mut SceKernelUtilsMd5Context, + data: *mut u8, + size: u32, + ) -> i32; + pub fn sceKernelUtilsMd5BlockResult(ctx: *mut SceKernelUtilsMd5Context, digest: *mut u8) + -> i32; + pub fn sceKernelUtilsSha1Digest(data: *mut u8, size: u32, digest: *mut u8) -> i32; + pub fn sceKernelUtilsSha1BlockInit(ctx: *mut SceKernelUtilsSha1Context) -> i32; + pub fn sceKernelUtilsSha1BlockUpdate( + ctx: *mut SceKernelUtilsSha1Context, + data: *mut u8, + size: u32, + ) -> i32; + pub fn sceKernelUtilsSha1BlockResult( + ctx: *mut SceKernelUtilsSha1Context, + digest: *mut u8, + ) -> i32; + + pub fn sceKernelRegisterSubIntrHandler( + int_no: i32, + no: i32, + handler: *mut c_void, + arg: *mut c_void, + ) -> i32; + pub fn sceKernelReleaseSubIntrHandler(int_no: i32, no: i32) -> i32; + pub fn sceKernelEnableSubIntr(int_no: i32, no: i32) -> i32; + pub fn sceKernelDisableSubIntr(int_no: i32, no: i32) -> i32; + pub fn QueryIntrHandlerInfo( + intr_code: SceUid, + sub_intr_code: SceUid, + data: *mut IntrHandlerOptionParam, + ) -> i32; + + pub fn sceKernelCpuSuspendIntr() -> u32; + pub fn sceKernelCpuResumeIntr(flags: u32); + pub fn sceKernelCpuResumeIntrWithSync(flags: u32); + pub fn sceKernelIsCpuIntrSuspended(flags: u32) -> i32; + pub fn sceKernelIsCpuIntrEnable() -> i32; + + pub fn sceKernelLoadModule( + path: *const u8, + flags: i32, + option: *mut SceKernelLMOption, + ) -> SceUid; + pub fn sceKernelLoadModuleMs( + path: *const u8, + flags: i32, + option: *mut SceKernelLMOption, + ) -> SceUid; + pub fn sceKernelLoadModuleByID( + fid: SceUid, + flags: i32, + option: *mut SceKernelLMOption, + ) -> SceUid; + pub fn sceKernelLoadModuleBufferUsbWlan( + buf_size: usize, + buf: *mut c_void, + flags: i32, + option: *mut SceKernelLMOption, + ) -> SceUid; + pub fn sceKernelStartModule( + mod_id: SceUid, + arg_size: usize, + argp: *mut c_void, + status: *mut i32, + option: *mut SceKernelSMOption, + ) -> i32; + pub fn sceKernelStopModule( + mod_id: SceUid, + arg_size: usize, + argp: *mut c_void, + status: *mut i32, + option: *mut SceKernelSMOption, + ) -> i32; + pub fn sceKernelUnloadModule(mod_id: SceUid) -> i32; + pub fn sceKernelSelfStopUnloadModule(unknown: i32, arg_size: usize, argp: *mut c_void) -> i32; + pub fn sceKernelStopUnloadSelfModule( + arg_size: usize, + argp: *mut c_void, + status: *mut i32, + option: *mut SceKernelSMOption, + ) -> i32; + pub fn sceKernelQueryModuleInfo(mod_id: SceUid, info: *mut SceKernelModuleInfo) -> i32; + pub fn sceKernelGetModuleIdList( + read_buf: *mut SceUid, + read_buf_size: i32, + id_count: *mut i32, + ) -> i32; + + pub fn sceKernelVolatileMemLock(unk: i32, ptr: *mut *mut c_void, size: *mut i32) -> i32; + pub fn sceKernelVolatileMemTryLock(unk: i32, ptr: *mut *mut c_void, size: *mut i32) -> i32; + pub fn sceKernelVolatileMemUnlock(unk: i32) -> i32; + + pub fn sceKernelStdin() -> SceUid; + pub fn sceKernelStdout() -> SceUid; + pub fn sceKernelStderr() -> SceUid; + + pub fn sceKernelGetThreadmanIdType(uid: SceUid) -> SceKernelIdListType; + pub fn sceKernelCreateThread( + name: *const u8, + entry: SceKernelThreadEntry, + init_priority: i32, + stack_size: i32, + attr: i32, + option: *mut SceKernelThreadOptParam, + ) -> SceUid; + pub fn sceKernelDeleteThread(thid: SceUid) -> i32; + pub fn sceKernelStartThread(id: SceUid, arg_len: usize, arg_p: *mut c_void) -> i32; + pub fn sceKernelExitThread(status: i32) -> i32; + pub fn sceKernelExitDeleteThread(status: i32) -> i32; + pub fn sceKernelTerminateThread(thid: SceUid) -> i32; + pub fn sceKernelTerminateDeleteThread(thid: SceUid) -> i32; + pub fn sceKernelSuspendDispatchThread() -> i32; + pub fn sceKernelResumeDispatchThread(state: i32) -> i32; + pub fn sceKernelSleepThread() -> i32; + pub fn sceKernelSleepThreadCB() -> i32; + pub fn sceKernelWakeupThread(thid: SceUid) -> i32; + pub fn sceKernelCancelWakeupThread(thid: SceUid) -> i32; + pub fn sceKernelSuspendThread(thid: SceUid) -> i32; + pub fn sceKernelResumeThread(thid: SceUid) -> i32; + pub fn sceKernelWaitThreadEnd(thid: SceUid, timeout: *mut u32) -> i32; + pub fn sceKernelWaitThreadEndCB(thid: SceUid, timeout: *mut u32) -> i32; + pub fn sceKernelDelayThread(delay: u32) -> i32; + pub fn sceKernelDelayThreadCB(delay: u32) -> i32; + pub fn sceKernelDelaySysClockThread(delay: *mut SceKernelSysClock) -> i32; + pub fn sceKernelDelaySysClockThreadCB(delay: *mut SceKernelSysClock) -> i32; + pub fn sceKernelChangeCurrentThreadAttr(unknown: i32, attr: i32) -> i32; + pub fn sceKernelChangeThreadPriority(thid: SceUid, priority: i32) -> i32; + pub fn sceKernelRotateThreadReadyQueue(priority: i32) -> i32; + pub fn sceKernelReleaseWaitThread(thid: SceUid) -> i32; + pub fn sceKernelGetThreadId() -> i32; + pub fn sceKernelGetThreadCurrentPriority() -> i32; + pub fn sceKernelGetThreadExitStatus(thid: SceUid) -> i32; + pub fn sceKernelCheckThreadStack() -> i32; + pub fn sceKernelGetThreadStackFreeSize(thid: SceUid) -> i32; + pub fn sceKernelReferThreadStatus(thid: SceUid, info: *mut SceKernelThreadInfo) -> i32; + pub fn sceKernelReferThreadRunStatus( + thid: SceUid, + status: *mut SceKernelThreadRunStatus, + ) -> i32; + pub fn sceKernelCreateSema( + name: *const u8, + attr: u32, + init_val: i32, + max_val: i32, + option: *mut SceKernelSemaOptParam, + ) -> SceUid; + pub fn sceKernelDeleteSema(sema_id: SceUid) -> i32; + pub fn sceKernelSignalSema(sema_id: SceUid, signal: i32) -> i32; + pub fn sceKernelWaitSema(sema_id: SceUid, signal: i32, timeout: *mut u32) -> i32; + pub fn sceKernelWaitSemaCB(sema_id: SceUid, signal: i32, timeout: *mut u32) -> i32; + pub fn sceKernelPollSema(sema_id: SceUid, signal: i32) -> i32; + pub fn sceKernelReferSemaStatus(sema_id: SceUid, info: *mut SceKernelSemaInfo) -> i32; + pub fn sceKernelCreateEventFlag( + name: *const u8, + attr: i32, + bits: i32, + opt: *mut SceKernelEventFlagOptParam, + ) -> SceUid; + pub fn sceKernelSetEventFlag(ev_id: SceUid, bits: u32) -> i32; + pub fn sceKernelClearEventFlag(ev_id: SceUid, bits: u32) -> i32; + pub fn sceKernelPollEventFlag(ev_id: SceUid, bits: u32, wait: i32, out_bits: *mut u32) -> i32; + pub fn sceKernelWaitEventFlag( + ev_id: SceUid, + bits: u32, + wait: i32, + out_bits: *mut u32, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelWaitEventFlagCB( + ev_id: SceUid, + bits: u32, + wait: i32, + out_bits: *mut u32, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelDeleteEventFlag(ev_id: SceUid) -> i32; + pub fn sceKernelReferEventFlagStatus(event: SceUid, status: *mut SceKernelEventFlagInfo) + -> i32; + pub fn sceKernelCreateMbx( + name: *const u8, + attr: u32, + option: *mut SceKernelMbxOptParam, + ) -> SceUid; + pub fn sceKernelDeleteMbx(mbx_id: SceUid) -> i32; + pub fn sceKernelSendMbx(mbx_id: SceUid, message: *mut c_void) -> i32; + pub fn sceKernelReceiveMbx(mbx_id: SceUid, message: *mut *mut c_void, timeout: *mut u32) + -> i32; + pub fn sceKernelReceiveMbxCB( + mbx_id: SceUid, + message: *mut *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelPollMbx(mbx_id: SceUid, pmessage: *mut *mut c_void) -> i32; + pub fn sceKernelCancelReceiveMbx(mbx_id: SceUid, num: *mut i32) -> i32; + pub fn sceKernelReferMbxStatus(mbx_id: SceUid, info: *mut SceKernelMbxInfo) -> i32; + pub fn sceKernelSetAlarm( + clock: u32, + handler: SceKernelAlarmHandler, + common: *mut c_void, + ) -> SceUid; + pub fn sceKernelSetSysClockAlarm( + clock: *mut SceKernelSysClock, + handler: *mut SceKernelAlarmHandler, + common: *mut c_void, + ) -> SceUid; + pub fn sceKernelCancelAlarm(alarm_id: SceUid) -> i32; + pub fn sceKernelReferAlarmStatus(alarm_id: SceUid, info: *mut SceKernelAlarmInfo) -> i32; + pub fn sceKernelCreateCallback( + name: *const u8, + func: SceKernelCallbackFunction, + arg: *mut c_void, + ) -> SceUid; + pub fn sceKernelReferCallbackStatus(cb: SceUid, status: *mut SceKernelCallbackInfo) -> i32; + pub fn sceKernelDeleteCallback(cb: SceUid) -> i32; + pub fn sceKernelNotifyCallback(cb: SceUid, arg2: i32) -> i32; + pub fn sceKernelCancelCallback(cb: SceUid) -> i32; + pub fn sceKernelGetCallbackCount(cb: SceUid) -> i32; + pub fn sceKernelCheckCallback() -> i32; + pub fn sceKernelGetThreadmanIdList( + type_: SceKernelIdListType, + read_buf: *mut SceUid, + read_buf_size: i32, + id_count: *mut i32, + ) -> i32; + pub fn sceKernelReferSystemStatus(status: *mut SceKernelSystemStatus) -> i32; + pub fn sceKernelCreateMsgPipe( + name: *const u8, + part: i32, + attr: i32, + unk1: *mut c_void, + opt: *mut c_void, + ) -> SceUid; + pub fn sceKernelDeleteMsgPipe(uid: SceUid) -> i32; + pub fn sceKernelSendMsgPipe( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelSendMsgPipeCB( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelTrySendMsgPipe( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + ) -> i32; + pub fn sceKernelReceiveMsgPipe( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelReceiveMsgPipeCB( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelTryReceiveMsgPipe( + uid: SceUid, + message: *mut c_void, + size: u32, + unk1: i32, + unk2: *mut c_void, + ) -> i32; + pub fn sceKernelCancelMsgPipe(uid: SceUid, send: *mut i32, recv: *mut i32) -> i32; + pub fn sceKernelReferMsgPipeStatus(uid: SceUid, info: *mut SceKernelMppInfo) -> i32; + pub fn sceKernelCreateVpl( + name: *const u8, + part: i32, + attr: i32, + size: u32, + opt: *mut SceKernelVplOptParam, + ) -> SceUid; + pub fn sceKernelDeleteVpl(uid: SceUid) -> i32; + pub fn sceKernelAllocateVpl( + uid: SceUid, + size: u32, + data: *mut *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelAllocateVplCB( + uid: SceUid, + size: u32, + data: *mut *mut c_void, + timeout: *mut u32, + ) -> i32; + pub fn sceKernelTryAllocateVpl(uid: SceUid, size: u32, data: *mut *mut c_void) -> i32; + pub fn sceKernelFreeVpl(uid: SceUid, data: *mut c_void) -> i32; + pub fn sceKernelCancelVpl(uid: SceUid, num: *mut i32) -> i32; + pub fn sceKernelReferVplStatus(uid: SceUid, info: *mut SceKernelVplInfo) -> i32; + pub fn sceKernelCreateFpl( + name: *const u8, + part: i32, + attr: i32, + size: u32, + blocks: u32, + opt: *mut SceKernelFplOptParam, + ) -> i32; + pub fn sceKernelDeleteFpl(uid: SceUid) -> i32; + pub fn sceKernelAllocateFpl(uid: SceUid, data: *mut *mut c_void, timeout: *mut u32) -> i32; + pub fn sceKernelAllocateFplCB(uid: SceUid, data: *mut *mut c_void, timeout: *mut u32) -> i32; + pub fn sceKernelTryAllocateFpl(uid: SceUid, data: *mut *mut c_void) -> i32; + pub fn sceKernelFreeFpl(uid: SceUid, data: *mut c_void) -> i32; + pub fn sceKernelCancelFpl(uid: SceUid, pnum: *mut i32) -> i32; + pub fn sceKernelReferFplStatus(uid: SceUid, info: *mut SceKernelFplInfo) -> i32; + pub fn sceKernelUSec2SysClock(usec: u32, clock: *mut SceKernelSysClock) -> i32; + pub fn sceKernelUSec2SysClockWide(usec: u32) -> i64; + pub fn sceKernelSysClock2USec( + clock: *mut SceKernelSysClock, + low: *mut u32, + high: *mut u32, + ) -> i32; + pub fn sceKernelSysClock2USecWide(clock: i64, low: *mut u32, high: *mut u32) -> i32; + pub fn sceKernelGetSystemTime(time: *mut SceKernelSysClock) -> i32; + pub fn sceKernelGetSystemTimeWide() -> i64; + pub fn sceKernelGetSystemTimeLow() -> u32; + pub fn sceKernelCreateVTimer(name: *const u8, opt: *mut SceKernelVTimerOptParam) -> SceUid; + pub fn sceKernelDeleteVTimer(uid: SceUid) -> i32; + pub fn sceKernelGetVTimerBase(uid: SceUid, base: *mut SceKernelSysClock) -> i32; + pub fn sceKernelGetVTimerBaseWide(uid: SceUid) -> i64; + pub fn sceKernelGetVTimerTime(uid: SceUid, time: *mut SceKernelSysClock) -> i32; + pub fn sceKernelGetVTimerTimeWide(uid: SceUid) -> i64; + pub fn sceKernelSetVTimerTime(uid: SceUid, time: *mut SceKernelSysClock) -> i32; + pub fn sceKernelSetVTimerTimeWide(uid: SceUid, time: i64) -> i64; + pub fn sceKernelStartVTimer(uid: SceUid) -> i32; + pub fn sceKernelStopVTimer(uid: SceUid) -> i32; + pub fn sceKernelSetVTimerHandler( + uid: SceUid, + time: *mut SceKernelSysClock, + handler: SceKernelVTimerHandler, + common: *mut c_void, + ) -> i32; + pub fn sceKernelSetVTimerHandlerWide( + uid: SceUid, + time: i64, + handler: SceKernelVTimerHandlerWide, + common: *mut c_void, + ) -> i32; + pub fn sceKernelCancelVTimerHandler(uid: SceUid) -> i32; + pub fn sceKernelReferVTimerStatus(uid: SceUid, info: *mut SceKernelVTimerInfo) -> i32; + pub fn sceKernelRegisterThreadEventHandler( + name: *const u8, + thread_id: SceUid, + mask: i32, + handler: SceKernelThreadEventHandler, + common: *mut c_void, + ) -> SceUid; + pub fn sceKernelReleaseThreadEventHandler(uid: SceUid) -> i32; + pub fn sceKernelReferThreadEventHandlerStatus( + uid: SceUid, + info: *mut SceKernelThreadEventHandlerInfo, + ) -> i32; + pub fn sceKernelReferThreadProfiler() -> *mut DebugProfilerRegs; + pub fn sceKernelReferGlobalProfiler() -> *mut DebugProfilerRegs; + + pub fn sceUsbStart(driver_name: *const u8, size: i32, args: *mut c_void) -> i32; + pub fn sceUsbStop(driver_name: *const u8, size: i32, args: *mut c_void) -> i32; + pub fn sceUsbActivate(pid: u32) -> i32; + pub fn sceUsbDeactivate(pid: u32) -> i32; + pub fn sceUsbGetState() -> i32; + pub fn sceUsbGetDrvState(driver_name: *const u8) -> i32; +} + +extern "C" { + pub fn sceUsbCamSetupStill(param: *mut UsbCamSetupStillParam) -> i32; + pub fn sceUsbCamSetupStillEx(param: *mut UsbCamSetupStillExParam) -> i32; + pub fn sceUsbCamStillInputBlocking(buf: *mut u8, size: usize) -> i32; + pub fn sceUsbCamStillInput(buf: *mut u8, size: usize) -> i32; + pub fn sceUsbCamStillWaitInputEnd() -> i32; + pub fn sceUsbCamStillPollInputEnd() -> i32; + pub fn sceUsbCamStillCancelInput() -> i32; + pub fn sceUsbCamStillGetInputLength() -> i32; + pub fn sceUsbCamSetupVideo( + param: *mut UsbCamSetupVideoParam, + work_area: *mut c_void, + work_area_size: i32, + ) -> i32; + pub fn sceUsbCamSetupVideoEx( + param: *mut UsbCamSetupVideoExParam, + work_area: *mut c_void, + work_area_size: i32, + ) -> i32; + pub fn sceUsbCamStartVideo() -> i32; + pub fn sceUsbCamStopVideo() -> i32; + pub fn sceUsbCamReadVideoFrameBlocking(buf: *mut u8, size: usize) -> i32; + pub fn sceUsbCamReadVideoFrame(buf: *mut u8, size: usize) -> i32; + pub fn sceUsbCamWaitReadVideoFrameEnd() -> i32; + pub fn sceUsbCamPollReadVideoFrameEnd() -> i32; + pub fn sceUsbCamGetReadVideoFrameSize() -> i32; + pub fn sceUsbCamSetSaturation(saturation: i32) -> i32; + pub fn sceUsbCamSetBrightness(brightness: i32) -> i32; + pub fn sceUsbCamSetContrast(contrast: i32) -> i32; + pub fn sceUsbCamSetSharpness(sharpness: i32) -> i32; + pub fn sceUsbCamSetImageEffectMode(effect_mode: UsbCamEffectMode) -> i32; + pub fn sceUsbCamSetEvLevel(exposure_level: UsbCamEvLevel) -> i32; + pub fn sceUsbCamSetReverseMode(reverse_flags: i32) -> i32; + pub fn sceUsbCamSetZoom(zoom: i32) -> i32; + pub fn sceUsbCamGetSaturation(saturation: *mut i32) -> i32; + pub fn sceUsbCamGetBrightness(brightness: *mut i32) -> i32; + pub fn sceUsbCamGetContrast(contrast: *mut i32) -> i32; + pub fn sceUsbCamGetSharpness(sharpness: *mut i32) -> i32; + pub fn sceUsbCamGetImageEffectMode(effect_mode: *mut UsbCamEffectMode) -> i32; + pub fn sceUsbCamGetEvLevel(exposure_level: *mut UsbCamEvLevel) -> i32; + pub fn sceUsbCamGetReverseMode(reverse_flags: *mut i32) -> i32; + pub fn sceUsbCamGetZoom(zoom: *mut i32) -> i32; + pub fn sceUsbCamAutoImageReverseSW(on: i32) -> i32; + pub fn sceUsbCamGetAutoImageReverseState() -> i32; + pub fn sceUsbCamGetLensDirection() -> i32; + + pub fn sceUsbstorBootRegisterNotify(event_flag: SceUid) -> i32; + pub fn sceUsbstorBootUnregisterNotify(event_flag: u32) -> i32; + pub fn sceUsbstorBootSetCapacity(size: u32) -> i32; + + pub fn scePowerRegisterCallback(slot: i32, cbid: SceUid) -> i32; + pub fn scePowerUnregisterCallback(slot: i32) -> i32; + pub fn scePowerIsPowerOnline() -> i32; + pub fn scePowerIsBatteryExist() -> i32; + pub fn scePowerIsBatteryCharging() -> i32; + pub fn scePowerGetBatteryChargingStatus() -> i32; + pub fn scePowerIsLowBattery() -> i32; + pub fn scePowerGetBatteryLifePercent() -> i32; + pub fn scePowerGetBatteryLifeTime() -> i32; + pub fn scePowerGetBatteryTemp() -> i32; + pub fn scePowerGetBatteryElec() -> i32; + pub fn scePowerGetBatteryVolt() -> i32; + pub fn scePowerSetCpuClockFrequency(cpufreq: i32) -> i32; + pub fn scePowerSetBusClockFrequency(busfreq: i32) -> i32; + pub fn scePowerGetCpuClockFrequency() -> i32; + pub fn scePowerGetCpuClockFrequencyInt() -> i32; + pub fn scePowerGetCpuClockFrequencyFloat() -> f32; + pub fn scePowerGetBusClockFrequency() -> i32; + pub fn scePowerGetBusClockFrequencyInt() -> i32; + pub fn scePowerGetBusClockFrequencyFloat() -> f32; + pub fn scePowerSetClockFrequency(pllfreq: i32, cpufreq: i32, busfreq: i32) -> i32; + pub fn scePowerLock(unknown: i32) -> i32; + pub fn scePowerUnlock(unknown: i32) -> i32; + pub fn scePowerTick(t: PowerTick) -> i32; + pub fn scePowerGetIdleTimer() -> i32; + pub fn scePowerIdleTimerEnable(unknown: i32) -> i32; + pub fn scePowerIdleTimerDisable(unknown: i32) -> i32; + pub fn scePowerRequestStandby() -> i32; + pub fn scePowerRequestSuspend() -> i32; + + pub fn sceWlanDevIsPowerOn() -> i32; + pub fn sceWlanGetSwitchState() -> i32; + pub fn sceWlanGetEtherAddr(ether_addr: *mut u8) -> i32; + + pub fn sceWlanDevAttach() -> i32; + pub fn sceWlanDevDetach() -> i32; + + pub fn sceRtcGetTickResolution() -> u32; + pub fn sceRtcGetCurrentTick(tick: *mut u64) -> i32; + pub fn sceRtcGetCurrentClock(tm: *mut ScePspDateTime, tz: i32) -> i32; + pub fn sceRtcGetCurrentClockLocalTime(tm: *mut ScePspDateTime) -> i32; + pub fn sceRtcConvertUtcToLocalTime(tick_utc: *const u64, tick_local: *mut u64) -> i32; + pub fn sceRtcConvertLocalTimeToUTC(tick_local: *const u64, tick_utc: *mut u64) -> i32; + pub fn sceRtcIsLeapYear(year: i32) -> i32; + pub fn sceRtcGetDaysInMonth(year: i32, month: i32) -> i32; + pub fn sceRtcGetDayOfWeek(year: i32, month: i32, day: i32) -> i32; + pub fn sceRtcCheckValid(date: *const ScePspDateTime) -> i32; + pub fn sceRtcSetTick(date: *mut ScePspDateTime, tick: *const u64) -> i32; + pub fn sceRtcGetTick(date: *const ScePspDateTime, tick: *mut u64) -> i32; + pub fn sceRtcCompareTick(tick1: *const u64, tick2: *const u64) -> i32; + pub fn sceRtcTickAddTicks(dest_tick: *mut u64, src_tick: *const u64, num_ticks: u64) -> i32; + pub fn sceRtcTickAddMicroseconds(dest_tick: *mut u64, src_tick: *const u64, num_ms: u64) + -> i32; + pub fn sceRtcTickAddSeconds(dest_tick: *mut u64, src_tick: *const u64, num_seconds: u64) + -> i32; + pub fn sceRtcTickAddMinutes(dest_tick: *mut u64, src_tick: *const u64, num_minutes: u64) + -> i32; + pub fn sceRtcTickAddHours(dest_tick: *mut u64, src_tick: *const u64, num_hours: u64) -> i32; + pub fn sceRtcTickAddDays(dest_tick: *mut u64, src_tick: *const u64, num_days: u64) -> i32; + pub fn sceRtcTickAddWeeks(dest_tick: *mut u64, src_tick: *const u64, num_weeks: u64) -> i32; + pub fn sceRtcTickAddMonths(dest_tick: *mut u64, src_tick: *const u64, num_months: u64) -> i32; + pub fn sceRtcTickAddYears(dest_tick: *mut u64, src_tick: *const u64, num_years: u64) -> i32; + pub fn sceRtcSetTime_t(date: *mut ScePspDateTime, time: u32) -> i32; + pub fn sceRtcGetTime_t(date: *const ScePspDateTime, time: *mut u32) -> i32; + pub fn sceRtcSetTime64_t(date: *mut ScePspDateTime, time: u64) -> i32; + pub fn sceRtcGetTime64_t(date: *const ScePspDateTime, time: *mut u64) -> i32; + pub fn sceRtcSetDosTime(date: *mut ScePspDateTime, dos_time: u32) -> i32; + pub fn sceRtcGetDosTime(date: *mut ScePspDateTime, dos_time: u32) -> i32; + pub fn sceRtcSetWin32FileTime(date: *mut ScePspDateTime, time: *mut u64) -> i32; + pub fn sceRtcGetWin32FileTime(date: *mut ScePspDateTime, time: *mut u64) -> i32; + pub fn sceRtcParseDateTime(dest_tick: *mut u64, date_string: *const u8) -> i32; + pub fn sceRtcFormatRFC3339( + psz_date_time: *mut c_char, + p_utc: *const u64, + time_zone_minutes: i32, + ) -> i32; + pub fn sceRtcFormatRFC3339LocalTime(psz_date_time: *mut c_char, p_utc: *const u64) -> i32; + pub fn sceRtcParseRFC3339(p_utc: *mut u64, psz_date_time: *const u8) -> i32; + pub fn sceRtcFormatRFC2822( + psz_date_time: *mut c_char, + p_utc: *const u64, + time_zone_minutes: i32, + ) -> i32; + pub fn sceRtcFormatRFC2822LocalTime(psz_date_time: *mut c_char, p_utc: *const u64) -> i32; + + pub fn sceIoOpen(file: *const u8, flags: i32, permissions: IoPermissions) -> SceUid; + pub fn sceIoOpenAsync(file: *const u8, flags: i32, permissions: IoPermissions) -> SceUid; + pub fn sceIoClose(fd: SceUid) -> i32; + pub fn sceIoCloseAsync(fd: SceUid) -> i32; + pub fn sceIoRead(fd: SceUid, data: *mut c_void, size: u32) -> i32; + pub fn sceIoReadAsync(fd: SceUid, data: *mut c_void, size: u32) -> i32; + pub fn sceIoWrite(fd: SceUid, data: *const c_void, size: usize) -> i32; + pub fn sceIoWriteAsync(fd: SceUid, data: *const c_void, size: u32) -> i32; + pub fn sceIoLseek(fd: SceUid, offset: i64, whence: IoWhence) -> i64; + pub fn sceIoLseekAsync(fd: SceUid, offset: i64, whence: IoWhence) -> i32; + pub fn sceIoLseek32(fd: SceUid, offset: i32, whence: IoWhence) -> i32; + pub fn sceIoLseek32Async(fd: SceUid, offset: i32, whence: IoWhence) -> i32; + pub fn sceIoRemove(file: *const u8) -> i32; + pub fn sceIoMkdir(dir: *const u8, mode: IoPermissions) -> i32; + pub fn sceIoRmdir(path: *const u8) -> i32; + pub fn sceIoChdir(path: *const u8) -> i32; + pub fn sceIoRename(oldname: *const u8, newname: *const u8) -> i32; + pub fn sceIoDopen(dirname: *const u8) -> SceUid; + pub fn sceIoDread(fd: SceUid, dir: *mut SceIoDirent) -> i32; + pub fn sceIoDclose(fd: SceUid) -> i32; + pub fn sceIoDevctl( + dev: *const u8, + cmd: u32, + indata: *mut c_void, + inlen: i32, + outdata: *mut c_void, + outlen: i32, + ) -> i32; + pub fn sceIoAssign( + dev1: *const u8, + dev2: *const u8, + dev3: *const u8, + mode: IoAssignPerms, + unk1: *mut c_void, + unk2: i32, + ) -> i32; + pub fn sceIoUnassign(dev: *const u8) -> i32; + pub fn sceIoGetstat(file: *const u8, stat: *mut SceIoStat) -> i32; + pub fn sceIoChstat(file: *const u8, stat: *mut SceIoStat, bits: i32) -> i32; + pub fn sceIoIoctl( + fd: SceUid, + cmd: u32, + indata: *mut c_void, + inlen: i32, + outdata: *mut c_void, + outlen: i32, + ) -> i32; + pub fn sceIoIoctlAsync( + fd: SceUid, + cmd: u32, + indata: *mut c_void, + inlen: i32, + outdata: *mut c_void, + outlen: i32, + ) -> i32; + pub fn sceIoSync(device: *const u8, unk: u32) -> i32; + pub fn sceIoWaitAsync(fd: SceUid, res: *mut i64) -> i32; + pub fn sceIoWaitAsyncCB(fd: SceUid, res: *mut i64) -> i32; + pub fn sceIoPollAsync(fd: SceUid, res: *mut i64) -> i32; + pub fn sceIoGetAsyncStat(fd: SceUid, poll: i32, res: *mut i64) -> i32; + pub fn sceIoCancel(fd: SceUid) -> i32; + pub fn sceIoGetDevType(fd: SceUid) -> i32; + pub fn sceIoChangeAsyncPriority(fd: SceUid, pri: i32) -> i32; + pub fn sceIoSetAsyncCallback(fd: SceUid, cb: SceUid, argp: *mut c_void) -> i32; + + pub fn sceJpegInitMJpeg() -> i32; + pub fn sceJpegFinishMJpeg() -> i32; + pub fn sceJpegCreateMJpeg(width: i32, height: i32) -> i32; + pub fn sceJpegDeleteMJpeg() -> i32; + pub fn sceJpegDecodeMJpeg(jpeg_buf: *mut u8, size: usize, rgba: *mut c_void, unk: u32) -> i32; + + pub fn sceUmdCheckMedium() -> i32; + pub fn sceUmdGetDiscInfo(info: *mut UmdInfo) -> i32; + pub fn sceUmdActivate(unit: i32, drive: *const u8) -> i32; + pub fn sceUmdDeactivate(unit: i32, drive: *const u8) -> i32; + pub fn sceUmdWaitDriveStat(state: i32) -> i32; + pub fn sceUmdWaitDriveStatWithTimer(state: i32, timeout: u32) -> i32; + pub fn sceUmdWaitDriveStatCB(state: i32, timeout: u32) -> i32; + pub fn sceUmdCancelWaitDriveStat() -> i32; + pub fn sceUmdGetDriveStat() -> i32; + pub fn sceUmdGetErrorStat() -> i32; + pub fn sceUmdRegisterUMDCallBack(cbid: i32) -> i32; + pub fn sceUmdUnRegisterUMDCallBack(cbid: i32) -> i32; + pub fn sceUmdReplacePermit() -> i32; + pub fn sceUmdReplaceProhibit() -> i32; + + pub fn sceMpegInit() -> i32; + pub fn sceMpegFinish(); + pub fn sceMpegRingbufferQueryMemSize(packets: i32) -> i32; + pub fn sceMpegRingbufferConstruct( + ringbuffer: *mut SceMpegRingbuffer, + packets: i32, + data: *mut c_void, + size: i32, + callback: SceMpegRingbufferCb, + cb_param: *mut c_void, + ) -> i32; + pub fn sceMpegRingbufferDestruct(ringbuffer: *mut SceMpegRingbuffer); + pub fn sceMpegRingbufferAvailableSize(ringbuffer: *mut SceMpegRingbuffer) -> i32; + pub fn sceMpegRingbufferPut( + ringbuffer: *mut SceMpegRingbuffer, + num_packets: i32, + available: i32, + ) -> i32; + pub fn sceMpegQueryMemSize(unk: i32) -> i32; + pub fn sceMpegCreate( + handle: SceMpeg, + data: *mut c_void, + size: i32, + ringbuffer: *mut SceMpegRingbuffer, + frame_width: i32, + unk1: i32, + unk2: i32, + ) -> i32; + pub fn sceMpegDelete(handle: SceMpeg); + pub fn sceMpegQueryStreamOffset(handle: SceMpeg, buffer: *mut c_void, offset: *mut i32) -> i32; + pub fn sceMpegQueryStreamSize(buffer: *mut c_void, size: *mut i32) -> i32; + pub fn sceMpegRegistStream(handle: SceMpeg, stream_id: i32, unk: i32) -> SceMpegStream; + pub fn sceMpegUnRegistStream(handle: SceMpeg, stream: SceMpegStream); + pub fn sceMpegFlushAllStream(handle: SceMpeg) -> i32; + pub fn sceMpegMallocAvcEsBuf(handle: SceMpeg) -> *mut c_void; + pub fn sceMpegFreeAvcEsBuf(handle: SceMpeg, buf: *mut c_void); + pub fn sceMpegQueryAtracEsSize(handle: SceMpeg, es_size: *mut i32, out_size: *mut i32) -> i32; + pub fn sceMpegInitAu(handle: SceMpeg, es_buffer: *mut c_void, au: *mut SceMpegAu) -> i32; + pub fn sceMpegGetAvcAu( + handle: SceMpeg, + stream: SceMpegStream, + au: *mut SceMpegAu, + unk: *mut i32, + ) -> i32; + pub fn sceMpegAvcDecodeMode(handle: SceMpeg, mode: *mut SceMpegAvcMode) -> i32; + pub fn sceMpegAvcDecode( + handle: SceMpeg, + au: *mut SceMpegAu, + iframe_width: i32, + buffer: *mut c_void, + init: *mut i32, + ) -> i32; + pub fn sceMpegAvcDecodeStop( + handle: SceMpeg, + frame_width: i32, + buffer: *mut c_void, + status: *mut i32, + ) -> i32; + pub fn sceMpegGetAtracAu( + handle: SceMpeg, + stream: SceMpegStream, + au: *mut SceMpegAu, + unk: *mut c_void, + ) -> i32; + pub fn sceMpegAtracDecode( + handle: SceMpeg, + au: *mut SceMpegAu, + buffer: *mut c_void, + init: i32, + ) -> i32; + + pub fn sceMpegBaseYCrCbCopyVme(yuv_buffer: *mut c_void, buffer: *mut i32, type_: i32) -> i32; + pub fn sceMpegBaseCscInit(width: i32) -> i32; + pub fn sceMpegBaseCscVme( + rgb_buffer: *mut c_void, + rgb_buffer2: *mut c_void, + width: i32, + y_cr_cb_buffer: *mut SceMpegYCrCbBuffer, + ) -> i32; + pub fn sceMpegbase_BEA18F91(lli: *mut SceMpegLLI) -> i32; + + pub fn sceHprmPeekCurrentKey(key: *mut i32) -> i32; + pub fn sceHprmPeekLatch(latch: *mut [u32; 4]) -> i32; + pub fn sceHprmReadLatch(latch: *mut [u32; 4]) -> i32; + pub fn sceHprmIsHeadphoneExist() -> i32; + pub fn sceHprmIsRemoteExist() -> i32; + pub fn sceHprmIsMicrophoneExist() -> i32; + + pub fn sceGuDepthBuffer(zbp: *mut c_void, zbw: i32); + pub fn sceGuDispBuffer(width: i32, height: i32, dispbp: *mut c_void, dispbw: i32); + pub fn sceGuDrawBuffer(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32); + pub fn sceGuDrawBufferList(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32); + pub fn sceGuDisplay(state: bool) -> bool; + pub fn sceGuDepthFunc(function: DepthFunc); + pub fn sceGuDepthMask(mask: i32); + pub fn sceGuDepthOffset(offset: i32); + pub fn sceGuDepthRange(near: i32, far: i32); + pub fn sceGuFog(near: f32, far: f32, color: u32); + pub fn sceGuInit(); + pub fn sceGuTerm(); + pub fn sceGuBreak(mode: i32); + pub fn sceGuContinue(); + pub fn sceGuSetCallback(signal: GuCallbackId, callback: GuCallback) -> GuCallback; + pub fn sceGuSignal(behavior: SignalBehavior, signal: i32); + pub fn sceGuSendCommandf(cmd: GeCommand, argument: f32); + pub fn sceGuSendCommandi(cmd: GeCommand, argument: i32); + pub fn sceGuGetMemory(size: i32) -> *mut c_void; + pub fn sceGuStart(context_type: GuContextType, list: *mut c_void); + pub fn sceGuFinish() -> i32; + pub fn sceGuFinishId(id: u32) -> i32; + pub fn sceGuCallList(list: *const c_void); + pub fn sceGuCallMode(mode: i32); + pub fn sceGuCheckList() -> i32; + pub fn sceGuSendList(mode: GuQueueMode, list: *const c_void, context: *mut GeContext); + pub fn sceGuSwapBuffers() -> *mut c_void; + pub fn sceGuSync(mode: GuSyncMode, behavior: GuSyncBehavior) -> GeListState; + pub fn sceGuDrawArray( + prim: GuPrimitive, + vtype: i32, + count: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGuBeginObject( + vtype: i32, + count: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGuEndObject(); + pub fn sceGuSetStatus(state: GuState, status: i32); + pub fn sceGuGetStatus(state: GuState) -> bool; + pub fn sceGuSetAllStatus(status: i32); + pub fn sceGuGetAllStatus() -> i32; + pub fn sceGuEnable(state: GuState); + pub fn sceGuDisable(state: GuState); + pub fn sceGuLight(light: i32, type_: LightType, components: i32, position: &ScePspFVector3); + pub fn sceGuLightAtt(light: i32, atten0: f32, atten1: f32, atten2: f32); + pub fn sceGuLightColor(light: i32, component: i32, color: u32); + pub fn sceGuLightMode(mode: LightMode); + pub fn sceGuLightSpot(light: i32, direction: &ScePspFVector3, exponent: f32, cutoff: f32); + pub fn sceGuClear(flags: i32); + pub fn sceGuClearColor(color: u32); + pub fn sceGuClearDepth(depth: u32); + pub fn sceGuClearStencil(stencil: u32); + pub fn sceGuPixelMask(mask: u32); + pub fn sceGuColor(color: u32); + pub fn sceGuColorFunc(func: ColorFunc, color: u32, mask: u32); + pub fn sceGuColorMaterial(components: i32); + pub fn sceGuAlphaFunc(func: AlphaFunc, value: i32, mask: i32); + pub fn sceGuAmbient(color: u32); + pub fn sceGuAmbientColor(color: u32); + pub fn sceGuBlendFunc(op: BlendOp, src: BlendSrc, dest: BlendDst, src_fix: u32, dest_fix: u32); + pub fn sceGuMaterial(components: i32, color: u32); + pub fn sceGuModelColor(emissive: u32, ambient: u32, diffuse: u32, specular: u32); + pub fn sceGuStencilFunc(func: StencilFunc, ref_: i32, mask: i32); + pub fn sceGuStencilOp(fail: StencilOperation, zfail: StencilOperation, zpass: StencilOperation); + pub fn sceGuSpecular(power: f32); + pub fn sceGuFrontFace(order: FrontFaceDirection); + pub fn sceGuLogicalOp(op: LogicalOperation); + pub fn sceGuSetDither(matrix: &ScePspIMatrix4); + pub fn sceGuShadeModel(mode: ShadingModel); + pub fn sceGuCopyImage( + psm: DisplayPixelFormat, + sx: i32, + sy: i32, + width: i32, + height: i32, + srcw: i32, + src: *mut c_void, + dx: i32, + dy: i32, + destw: i32, + dest: *mut c_void, + ); + pub fn sceGuTexEnvColor(color: u32); + pub fn sceGuTexFilter(min: TextureFilter, mag: TextureFilter); + pub fn sceGuTexFlush(); + pub fn sceGuTexFunc(tfx: TextureEffect, tcc: TextureColorComponent); + pub fn sceGuTexImage( + mipmap: MipmapLevel, + width: i32, + height: i32, + tbw: i32, + tbp: *const c_void, + ); + pub fn sceGuTexLevelMode(mode: TextureLevelMode, bias: f32); + pub fn sceGuTexMapMode(mode: TextureMapMode, a1: u32, a2: u32); + pub fn sceGuTexMode(tpsm: TexturePixelFormat, maxmips: i32, a2: i32, swizzle: i32); + pub fn sceGuTexOffset(u: f32, v: f32); + pub fn sceGuTexProjMapMode(mode: TextureProjectionMapMode); + pub fn sceGuTexScale(u: f32, v: f32); + pub fn sceGuTexSlope(slope: f32); + pub fn sceGuTexSync(); + pub fn sceGuTexWrap(u: GuTexWrapMode, v: GuTexWrapMode); + pub fn sceGuClutLoad(num_blocks: i32, cbp: *const c_void); + pub fn sceGuClutMode(cpsm: ClutPixelFormat, shift: u32, mask: u32, a3: u32); + pub fn sceGuOffset(x: u32, y: u32); + pub fn sceGuScissor(x: i32, y: i32, w: i32, h: i32); + pub fn sceGuViewport(cx: i32, cy: i32, width: i32, height: i32); + pub fn sceGuDrawBezier( + v_type: i32, + u_count: i32, + v_count: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGuPatchDivide(ulevel: u32, vlevel: u32); + pub fn sceGuPatchFrontFace(a0: u32); + pub fn sceGuPatchPrim(prim: PatchPrimitive); + pub fn sceGuDrawSpline( + v_type: i32, + u_count: i32, + v_count: i32, + u_edge: i32, + v_edge: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGuSetMatrix(type_: MatrixMode, matrix: &ScePspFMatrix4); + pub fn sceGuBoneMatrix(index: u32, matrix: &ScePspFMatrix4); + pub fn sceGuMorphWeight(index: i32, weight: f32); + pub fn sceGuDrawArrayN( + primitive_type: GuPrimitive, + v_type: i32, + count: i32, + a3: i32, + indices: *const c_void, + vertices: *const c_void, + ); + + pub fn sceGumDrawArray( + prim: GuPrimitive, + v_type: i32, + count: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGumDrawArrayN( + prim: GuPrimitive, + v_type: i32, + count: i32, + a3: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGumDrawBezier( + v_type: i32, + u_count: i32, + v_count: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGumDrawSpline( + v_type: i32, + u_count: i32, + v_count: i32, + u_edge: i32, + v_edge: i32, + indices: *const c_void, + vertices: *const c_void, + ); + pub fn sceGumFastInverse(); + pub fn sceGumFullInverse(); + pub fn sceGumLoadIdentity(); + pub fn sceGumLoadMatrix(m: &ScePspFMatrix4); + pub fn sceGumLookAt(eye: &ScePspFVector3, center: &ScePspFVector3, up: &ScePspFVector3); + pub fn sceGumMatrixMode(mode: MatrixMode); + pub fn sceGumMultMatrix(m: &ScePspFMatrix4); + pub fn sceGumOrtho(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32); + pub fn sceGumPerspective(fovy: f32, aspect: f32, near: f32, far: f32); + pub fn sceGumPopMatrix(); + pub fn sceGumPushMatrix(); + pub fn sceGumRotateX(angle: f32); + pub fn sceGumRotateY(angle: f32); + pub fn sceGumRotateZ(angle: f32); + pub fn sceGumRotateXYZ(v: &ScePspFVector3); + pub fn sceGumRotateZYX(v: &ScePspFVector3); + pub fn sceGumScale(v: &ScePspFVector3); + pub fn sceGumStoreMatrix(m: &mut ScePspFMatrix4); + pub fn sceGumTranslate(v: &ScePspFVector3); + pub fn sceGumUpdateMatrix(); + + pub fn sceMp3ReserveMp3Handle(args: *mut SceMp3InitArg) -> i32; + pub fn sceMp3ReleaseMp3Handle(handle: Mp3Handle) -> i32; + pub fn sceMp3InitResource() -> i32; + pub fn sceMp3TermResource() -> i32; + pub fn sceMp3Init(handle: Mp3Handle) -> i32; + pub fn sceMp3Decode(handle: Mp3Handle, dst: *mut *mut i16) -> i32; + pub fn sceMp3GetInfoToAddStreamData( + handle: Mp3Handle, + dst: *mut *mut u8, + to_write: *mut i32, + src_pos: *mut i32, + ) -> i32; + pub fn sceMp3NotifyAddStreamData(handle: Mp3Handle, size: i32) -> i32; + pub fn sceMp3CheckStreamDataNeeded(handle: Mp3Handle) -> i32; + pub fn sceMp3SetLoopNum(handle: Mp3Handle, loop_: i32) -> i32; + pub fn sceMp3GetLoopNum(handle: Mp3Handle) -> i32; + pub fn sceMp3GetSumDecodedSample(handle: Mp3Handle) -> i32; + pub fn sceMp3GetMaxOutputSample(handle: Mp3Handle) -> i32; + pub fn sceMp3GetSamplingRate(handle: Mp3Handle) -> i32; + pub fn sceMp3GetBitRate(handle: Mp3Handle) -> i32; + pub fn sceMp3GetMp3ChannelNum(handle: Mp3Handle) -> i32; + pub fn sceMp3ResetPlayPosition(handle: Mp3Handle) -> i32; + + pub fn sceRegOpenRegistry(reg: *mut Key, mode: i32, handle: *mut RegHandle) -> i32; + pub fn sceRegFlushRegistry(handle: RegHandle) -> i32; + pub fn sceRegCloseRegistry(handle: RegHandle) -> i32; + pub fn sceRegOpenCategory( + handle: RegHandle, + name: *const u8, + mode: i32, + dir_handle: *mut RegHandle, + ) -> i32; + pub fn sceRegRemoveCategory(handle: RegHandle, name: *const u8) -> i32; + pub fn sceRegCloseCategory(dir_handle: RegHandle) -> i32; + pub fn sceRegFlushCategory(dir_handle: RegHandle) -> i32; + pub fn sceRegGetKeyInfo( + dir_handle: RegHandle, + name: *const u8, + key_handle: *mut RegHandle, + type_: *mut KeyType, + size: *mut usize, + ) -> i32; + pub fn sceRegGetKeyInfoByName( + dir_handle: RegHandle, + name: *const u8, + type_: *mut KeyType, + size: *mut usize, + ) -> i32; + pub fn sceRegGetKeyValue( + dir_handle: RegHandle, + key_handle: RegHandle, + buf: *mut c_void, + size: usize, + ) -> i32; + pub fn sceRegGetKeyValueByName( + dir_handle: RegHandle, + name: *const u8, + buf: *mut c_void, + size: usize, + ) -> i32; + pub fn sceRegSetKeyValue( + dir_handle: RegHandle, + name: *const u8, + buf: *const c_void, + size: usize, + ) -> i32; + pub fn sceRegGetKeysNum(dir_handle: RegHandle, num: *mut i32) -> i32; + pub fn sceRegGetKeys(dir_handle: RegHandle, buf: *mut u8, num: i32) -> i32; + pub fn sceRegCreateKey(dir_handle: RegHandle, name: *const u8, type_: i32, size: usize) -> i32; + pub fn sceRegRemoveRegistry(key: *mut Key) -> i32; + + pub fn sceOpenPSIDGetOpenPSID(openpsid: *mut OpenPSID) -> i32; + + pub fn sceUtilityMsgDialogInitStart(params: *mut UtilityMsgDialogParams) -> i32; + pub fn sceUtilityMsgDialogShutdownStart(); + pub fn sceUtilityMsgDialogGetStatus() -> i32; + pub fn sceUtilityMsgDialogUpdate(n: i32); + pub fn sceUtilityMsgDialogAbort() -> i32; + pub fn sceUtilityNetconfInitStart(data: *mut UtilityNetconfData) -> i32; + pub fn sceUtilityNetconfShutdownStart() -> i32; + pub fn sceUtilityNetconfUpdate(unknown: i32) -> i32; + pub fn sceUtilityNetconfGetStatus() -> i32; + pub fn sceUtilityCheckNetParam(id: i32) -> i32; + pub fn sceUtilityGetNetParam(conf: i32, param: NetParam, data: *mut UtilityNetData) -> i32; + pub fn sceUtilitySavedataInitStart(params: *mut SceUtilitySavedataParam) -> i32; + pub fn sceUtilitySavedataGetStatus() -> i32; + pub fn sceUtilitySavedataShutdownStart() -> i32; + pub fn sceUtilitySavedataUpdate(unknown: i32); + pub fn sceUtilityGameSharingInitStart(params: *mut UtilityGameSharingParams) -> i32; + pub fn sceUtilityGameSharingShutdownStart(); + pub fn sceUtilityGameSharingGetStatus() -> i32; + pub fn sceUtilityGameSharingUpdate(n: i32); + pub fn sceUtilityHtmlViewerInitStart(params: *mut UtilityHtmlViewerParam) -> i32; + pub fn sceUtilityHtmlViewerShutdownStart() -> i32; + pub fn sceUtilityHtmlViewerUpdate(n: i32) -> i32; + pub fn sceUtilityHtmlViewerGetStatus() -> i32; + pub fn sceUtilitySetSystemParamInt(id: SystemParamId, value: i32) -> i32; + pub fn sceUtilitySetSystemParamString(id: SystemParamId, str: *const u8) -> i32; + pub fn sceUtilityGetSystemParamInt(id: SystemParamId, value: *mut i32) -> i32; + pub fn sceUtilityGetSystemParamString(id: SystemParamId, str: *mut u8, len: i32) -> i32; + pub fn sceUtilityOskInitStart(params: *mut SceUtilityOskParams) -> i32; + pub fn sceUtilityOskShutdownStart() -> i32; + pub fn sceUtilityOskUpdate(n: i32) -> i32; + pub fn sceUtilityOskGetStatus() -> i32; + pub fn sceUtilityLoadNetModule(module: NetModule) -> i32; + pub fn sceUtilityUnloadNetModule(module: NetModule) -> i32; + pub fn sceUtilityLoadAvModule(module: AvModule) -> i32; + pub fn sceUtilityUnloadAvModule(module: AvModule) -> i32; + pub fn sceUtilityLoadUsbModule(module: UsbModule) -> i32; + pub fn sceUtilityUnloadUsbModule(module: UsbModule) -> i32; + pub fn sceUtilityLoadModule(module: Module) -> i32; + pub fn sceUtilityUnloadModule(module: Module) -> i32; + pub fn sceUtilityCreateNetParam(conf: i32) -> i32; + pub fn sceUtilitySetNetParam(param: NetParam, val: *const c_void) -> i32; + pub fn sceUtilityCopyNetParam(src: i32, dest: i32) -> i32; + pub fn sceUtilityDeleteNetParam(conf: i32) -> i32; + + pub fn sceNetInit( + poolsize: i32, + calloutprio: i32, + calloutstack: i32, + netintrprio: i32, + netintrstack: i32, + ) -> i32; + pub fn sceNetTerm() -> i32; + pub fn sceNetFreeThreadinfo(thid: i32) -> i32; + pub fn sceNetThreadAbort(thid: i32) -> i32; + pub fn sceNetEtherStrton(name: *mut u8, mac: *mut u8); + pub fn sceNetEtherNtostr(mac: *mut u8, name: *mut u8); + pub fn sceNetGetLocalEtherAddr(mac: *mut u8) -> i32; + pub fn sceNetGetMallocStat(stat: *mut SceNetMallocStat) -> i32; + + pub fn sceNetAdhocctlInit( + stacksize: i32, + priority: i32, + adhoc_id: *mut SceNetAdhocctlAdhocId, + ) -> i32; + pub fn sceNetAdhocctlTerm() -> i32; + pub fn sceNetAdhocctlConnect(name: *const u8) -> i32; + pub fn sceNetAdhocctlDisconnect() -> i32; + pub fn sceNetAdhocctlGetState(event: *mut i32) -> i32; + pub fn sceNetAdhocctlCreate(name: *const u8) -> i32; + pub fn sceNetAdhocctlJoin(scaninfo: *mut SceNetAdhocctlScanInfo) -> i32; + pub fn sceNetAdhocctlGetAdhocId(id: *mut SceNetAdhocctlAdhocId) -> i32; + pub fn sceNetAdhocctlCreateEnterGameMode( + name: *const u8, + unknown: i32, + num: i32, + macs: *mut u8, + timeout: u32, + unknown2: i32, + ) -> i32; + pub fn sceNetAdhocctlJoinEnterGameMode( + name: *const u8, + hostmac: *mut u8, + timeout: u32, + unknown: i32, + ) -> i32; + pub fn sceNetAdhocctlGetGameModeInfo(gamemodeinfo: *mut SceNetAdhocctlGameModeInfo) -> i32; + pub fn sceNetAdhocctlExitGameMode() -> i32; + pub fn sceNetAdhocctlGetPeerList(length: *mut i32, buf: *mut c_void) -> i32; + pub fn sceNetAdhocctlGetPeerInfo( + mac: *mut u8, + size: i32, + peerinfo: *mut SceNetAdhocctlPeerInfo, + ) -> i32; + pub fn sceNetAdhocctlScan() -> i32; + pub fn sceNetAdhocctlGetScanInfo(length: *mut i32, buf: *mut c_void) -> i32; + pub fn sceNetAdhocctlAddHandler(handler: SceNetAdhocctlHandler, unknown: *mut c_void) -> i32; + pub fn sceNetAdhocctlDelHandler(id: i32) -> i32; + pub fn sceNetAdhocctlGetNameByAddr(mac: *mut u8, nickname: *mut u8) -> i32; + pub fn sceNetAdhocctlGetAddrByName( + nickname: *mut u8, + length: *mut i32, + buf: *mut c_void, + ) -> i32; + pub fn sceNetAdhocctlGetParameter(params: *mut SceNetAdhocctlParams) -> i32; + + pub fn sceNetAdhocInit() -> i32; + pub fn sceNetAdhocTerm() -> i32; + pub fn sceNetAdhocPdpCreate(mac: *mut u8, port: u16, buf_size: u32, unk1: i32) -> i32; + pub fn sceNetAdhocPdpDelete(id: i32, unk1: i32) -> i32; + pub fn sceNetAdhocPdpSend( + id: i32, + dest_mac_addr: *mut u8, + port: u16, + data: *mut c_void, + len: u32, + timeout: u32, + nonblock: i32, + ) -> i32; + pub fn sceNetAdhocPdpRecv( + id: i32, + src_mac_addr: *mut u8, + port: *mut u16, + data: *mut c_void, + data_length: *mut c_void, + timeout: u32, + nonblock: i32, + ) -> i32; + pub fn sceNetAdhocGetPdpStat(size: *mut i32, stat: *mut SceNetAdhocPdpStat) -> i32; + pub fn sceNetAdhocGameModeCreateMaster(data: *mut c_void, size: i32) -> i32; + pub fn sceNetAdhocGameModeCreateReplica(mac: *mut u8, data: *mut c_void, size: i32) -> i32; + pub fn sceNetAdhocGameModeUpdateMaster() -> i32; + pub fn sceNetAdhocGameModeUpdateReplica(id: i32, unk1: i32) -> i32; + pub fn sceNetAdhocGameModeDeleteMaster() -> i32; + pub fn sceNetAdhocGameModeDeleteReplica(id: i32) -> i32; + pub fn sceNetAdhocPtpOpen( + srcmac: *mut u8, + srcport: u16, + destmac: *mut u8, + destport: u16, + buf_size: u32, + delay: u32, + count: i32, + unk1: i32, + ) -> i32; + pub fn sceNetAdhocPtpConnect(id: i32, timeout: u32, nonblock: i32) -> i32; + pub fn sceNetAdhocPtpListen( + srcmac: *mut u8, + srcport: u16, + buf_size: u32, + delay: u32, + count: i32, + queue: i32, + unk1: i32, + ) -> i32; + pub fn sceNetAdhocPtpAccept( + id: i32, + mac: *mut u8, + port: *mut u16, + timeout: u32, + nonblock: i32, + ) -> i32; + pub fn sceNetAdhocPtpSend( + id: i32, + data: *mut c_void, + data_size: *mut i32, + timeout: u32, + nonblock: i32, + ) -> i32; + pub fn sceNetAdhocPtpRecv( + id: i32, + data: *mut c_void, + data_size: *mut i32, + timeout: u32, + nonblock: i32, + ) -> i32; + pub fn sceNetAdhocPtpFlush(id: i32, timeout: u32, nonblock: i32) -> i32; + pub fn sceNetAdhocPtpClose(id: i32, unk1: i32) -> i32; + pub fn sceNetAdhocGetPtpStat(size: *mut i32, stat: *mut SceNetAdhocPtpStat) -> i32; +} + +extern "C" { + pub fn sceNetAdhocMatchingInit(memsize: i32) -> i32; + pub fn sceNetAdhocMatchingTerm() -> i32; + pub fn sceNetAdhocMatchingCreate( + mode: AdhocMatchingMode, + max_peers: i32, + port: u16, + buf_size: i32, + hello_delay: u32, + ping_delay: u32, + init_count: i32, + msg_delay: u32, + callback: AdhocMatchingCallback, + ) -> i32; + pub fn sceNetAdhocMatchingDelete(matching_id: i32) -> i32; + pub fn sceNetAdhocMatchingStart( + matching_id: i32, + evth_pri: i32, + evth_stack: i32, + inth_pri: i32, + inth_stack: i32, + opt_len: i32, + opt_data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingStop(matching_id: i32) -> i32; + pub fn sceNetAdhocMatchingSelectTarget( + matching_id: i32, + mac: *mut u8, + opt_len: i32, + opt_data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingCancelTarget(matching_id: i32, mac: *mut u8) -> i32; + pub fn sceNetAdhocMatchingCancelTargetWithOpt( + matching_id: i32, + mac: *mut u8, + opt_len: i32, + opt_data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingSendData( + matching_id: i32, + mac: *mut u8, + data_len: i32, + data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingAbortSendData(matching_id: i32, mac: *mut u8) -> i32; + pub fn sceNetAdhocMatchingSetHelloOpt( + matching_id: i32, + opt_len: i32, + opt_data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingGetHelloOpt( + matching_id: i32, + opt_len: *mut i32, + opt_data: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingGetMembers( + matching_id: i32, + length: *mut i32, + buf: *mut c_void, + ) -> i32; + pub fn sceNetAdhocMatchingGetPoolMaxAlloc() -> i32; + pub fn sceNetAdhocMatchingGetPoolStat(poolstat: *mut AdhocPoolStat) -> i32; +} + +extern "C" { + pub fn sceNetApctlInit(stack_size: i32, init_priority: i32) -> i32; + pub fn sceNetApctlTerm() -> i32; + pub fn sceNetApctlGetInfo(code: ApctlInfo, pinfo: *mut SceNetApctlInfo) -> i32; + pub fn sceNetApctlAddHandler(handler: SceNetApctlHandler, parg: *mut c_void) -> i32; + pub fn sceNetApctlDelHandler(handler_id: i32) -> i32; + pub fn sceNetApctlConnect(conn_index: i32) -> i32; + pub fn sceNetApctlDisconnect() -> i32; + pub fn sceNetApctlGetState(pstate: *mut ApctlState) -> i32; + + pub fn sceNetInetInit() -> i32; + pub fn sceNetInetTerm() -> i32; + pub fn sceNetInetAccept(s: i32, addr: *mut sockaddr, addr_len: *mut socklen_t) -> i32; + pub fn sceNetInetBind(s: i32, my_addr: *const sockaddr, addr_len: socklen_t) -> i32; + pub fn sceNetInetConnect(s: i32, serv_addr: *const sockaddr, addr_len: socklen_t) -> i32; + pub fn sceNetInetGetsockopt( + s: i32, + level: i32, + opt_name: i32, + opt_val: *mut c_void, + optl_en: *mut socklen_t, + ) -> i32; + pub fn sceNetInetListen(s: i32, backlog: i32) -> i32; + pub fn sceNetInetRecv(s: i32, buf: *mut c_void, len: usize, flags: i32) -> usize; + pub fn sceNetInetRecvfrom( + s: i32, + buf: *mut c_void, + flags: usize, + arg1: i32, + from: *mut sockaddr, + from_len: *mut socklen_t, + ) -> usize; + pub fn sceNetInetSend(s: i32, buf: *const c_void, len: usize, flags: i32) -> usize; + pub fn sceNetInetSendto( + s: i32, + buf: *const c_void, + len: usize, + flags: i32, + to: *const sockaddr, + to_len: socklen_t, + ) -> usize; + pub fn sceNetInetSetsockopt( + s: i32, + level: i32, + opt_name: i32, + opt_val: *const c_void, + opt_len: socklen_t, + ) -> i32; + pub fn sceNetInetShutdown(s: i32, how: i32) -> i32; + pub fn sceNetInetSocket(domain: i32, type_: i32, protocol: i32) -> i32; + pub fn sceNetInetClose(s: i32) -> i32; + pub fn sceNetInetGetErrno() -> i32; + + pub fn sceSslInit(unknown1: i32) -> i32; + pub fn sceSslEnd() -> i32; + pub fn sceSslGetUsedMemoryMax(memory: *mut u32) -> i32; + pub fn sceSslGetUsedMemoryCurrent(memory: *mut u32) -> i32; + + pub fn sceHttpInit(unknown1: u32) -> i32; + pub fn sceHttpEnd() -> i32; + pub fn sceHttpCreateTemplate(agent: *mut u8, unknown1: i32, unknown2: i32) -> i32; + pub fn sceHttpDeleteTemplate(templateid: i32) -> i32; + pub fn sceHttpCreateConnection( + templateid: i32, + host: *mut u8, + unknown1: *mut u8, + port: u16, + unknown2: i32, + ) -> i32; + pub fn sceHttpCreateConnectionWithURL(templateid: i32, url: *const u8, unknown1: i32) -> i32; + pub fn sceHttpDeleteConnection(connection_id: i32) -> i32; + pub fn sceHttpCreateRequest( + connection_id: i32, + method: HttpMethod, + path: *mut u8, + content_length: u64, + ) -> i32; + pub fn sceHttpCreateRequestWithURL( + connection_id: i32, + method: HttpMethod, + url: *mut u8, + content_length: u64, + ) -> i32; + pub fn sceHttpDeleteRequest(request_id: i32) -> i32; + pub fn sceHttpSendRequest(request_id: i32, data: *mut c_void, data_size: u32) -> i32; + pub fn sceHttpAbortRequest(request_id: i32) -> i32; + pub fn sceHttpReadData(request_id: i32, data: *mut c_void, data_size: u32) -> i32; + pub fn sceHttpGetContentLength(request_id: i32, content_length: *mut u64) -> i32; + pub fn sceHttpGetStatusCode(request_id: i32, status_code: *mut i32) -> i32; + pub fn sceHttpSetResolveTimeOut(id: i32, timeout: u32) -> i32; + pub fn sceHttpSetResolveRetry(id: i32, count: i32) -> i32; + pub fn sceHttpSetConnectTimeOut(id: i32, timeout: u32) -> i32; + pub fn sceHttpSetSendTimeOut(id: i32, timeout: u32) -> i32; + pub fn sceHttpSetRecvTimeOut(id: i32, timeout: u32) -> i32; + pub fn sceHttpEnableKeepAlive(id: i32) -> i32; + pub fn sceHttpDisableKeepAlive(id: i32) -> i32; + pub fn sceHttpEnableRedirect(id: i32) -> i32; + pub fn sceHttpDisableRedirect(id: i32) -> i32; + pub fn sceHttpEnableCookie(id: i32) -> i32; + pub fn sceHttpDisableCookie(id: i32) -> i32; + pub fn sceHttpSaveSystemCookie() -> i32; + pub fn sceHttpLoadSystemCookie() -> i32; + pub fn sceHttpAddExtraHeader(id: i32, name: *mut u8, value: *mut u8, unknown1: i32) -> i32; + pub fn sceHttpDeleteHeader(id: i32, name: *const u8) -> i32; + pub fn sceHttpsInit(unknown1: i32, unknown2: i32, unknown3: i32, unknown4: i32) -> i32; + pub fn sceHttpsEnd() -> i32; + pub fn sceHttpsLoadDefaultCert(unknown1: i32, unknown2: i32) -> i32; + pub fn sceHttpDisableAuth(id: i32) -> i32; + pub fn sceHttpDisableCache(id: i32) -> i32; + pub fn sceHttpEnableAuth(id: i32) -> i32; + pub fn sceHttpEnableCache(id: i32) -> i32; + pub fn sceHttpEndCache() -> i32; + pub fn sceHttpGetAllHeader(request: i32, header: *mut *mut u8, header_size: *mut u32) -> i32; + pub fn sceHttpGetNetworkErrno(request: i32, err_num: *mut i32) -> i32; + pub fn sceHttpGetProxy( + id: i32, + activate_flag: *mut i32, + mode: *mut i32, + proxy_host: *mut u8, + len: usize, + proxy_port: *mut u16, + ) -> i32; + pub fn sceHttpInitCache(max_size: usize) -> i32; + pub fn sceHttpSetAuthInfoCB(id: i32, cbfunc: HttpPasswordCB) -> i32; + pub fn sceHttpSetProxy( + id: i32, + activate_flag: i32, + mode: i32, + new_proxy_host: *const u8, + new_proxy_port: u16, + ) -> i32; + pub fn sceHttpSetResHeaderMaxSize(id: i32, header_size: u32) -> i32; + pub fn sceHttpSetMallocFunction( + malloc_func: HttpMallocFunction, + free_func: HttpFreeFunction, + realloc_func: HttpReallocFunction, + ) -> i32; + + pub fn sceNetResolverInit() -> i32; + pub fn sceNetResolverCreate(rid: *mut i32, buf: *mut c_void, buf_length: u32) -> i32; + pub fn sceNetResolverDelete(rid: i32) -> i32; + pub fn sceNetResolverStartNtoA( + rid: i32, + hostname: *const u8, + addr: *mut in_addr, + timeout: u32, + retry: i32, + ) -> i32; + pub fn sceNetResolverStartAtoN( + rid: i32, + addr: *const in_addr, + hostname: *mut u8, + hostname_len: u32, + timeout: u32, + retry: i32, + ) -> i32; + pub fn sceNetResolverStop(rid: i32) -> i32; + pub fn sceNetResolverTerm() -> i32; +} diff --git a/deps/crates/vendor/libc/src/qurt/mod.rs b/deps/crates/vendor/libc/src/qurt/mod.rs new file mode 100644 index 00000000000000..b5e01f93093db2 --- /dev/null +++ b/deps/crates/vendor/libc/src/qurt/mod.rs @@ -0,0 +1,18 @@ +//! Interface to QuRT (Qualcomm Real-Time OS) C library +//! +//! This module re-exports items from the new module structure. +//! QuRT was introduced after the `src/new/` module structure was established, +//! so all definitions live in `src/new/qurt/` and are re-exported here +//! for compatibility with the existing libc structure. + +// Re-export everything from the new qurt module +pub use crate::new::qurt::*; + +// Architecture-specific modules (if any are needed in the future) +cfg_if! { + if #[cfg(target_arch = "hexagon")] { + // Currently no hexagon-specific items needed beyond what's in new/qurt + } else { + // Add other architectures as needed + } +} diff --git a/deps/crates/vendor/libc/src/sgx.rs b/deps/crates/vendor/libc/src/sgx.rs new file mode 100644 index 00000000000000..9cf9c6d3b41b8d --- /dev/null +++ b/deps/crates/vendor/libc/src/sgx.rs @@ -0,0 +1,15 @@ +//! SGX C types definition + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; diff --git a/deps/crates/vendor/libc/src/solid/aarch64.rs b/deps/crates/vendor/libc/src/solid/aarch64.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/solid/aarch64.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/solid/arm.rs b/deps/crates/vendor/libc/src/solid/arm.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/solid/arm.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/solid/mod.rs b/deps/crates/vendor/libc/src/solid/mod.rs new file mode 100644 index 00000000000000..0182f8150df675 --- /dev/null +++ b/deps/crates/vendor/libc/src/solid/mod.rs @@ -0,0 +1,865 @@ +//! Interface to the [SOLID] C library +//! +//! [SOLID]: https://solid.kmckk.com/ + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type uintptr_t = usize; +pub type intptr_t = isize; +pub type ptrdiff_t = isize; +pub type size_t = crate::uintptr_t; +pub type ssize_t = intptr_t; + +pub type clock_t = c_uint; +pub type time_t = i64; +pub type clockid_t = c_int; +pub type timer_t = c_int; +pub type suseconds_t = c_int; +pub type useconds_t = c_uint; + +pub type sighandler_t = size_t; + +// sys/ansi.h +pub type __caddr_t = *mut c_char; +pub type __gid_t = u32; +pub type __in_addr_t = u32; +pub type __in_port_t = u16; +pub type __mode_t = u32; +pub type __off_t = i64; +pub type __pid_t = i32; +pub type __sa_family_t = u8; +pub type __socklen_t = c_uint; +pub type __uid_t = u32; +pub type __fsblkcnt_t = u64; +pub type __fsfilcnt_t = u64; + +// locale.h +pub type locale_t = usize; + +// nl_types.h +pub type nl_item = c_long; + +// sys/types.h +pub type __va_list = *mut c_char; +pub type u_int8_t = u8; +pub type u_int16_t = u16; +pub type u_int32_t = u32; +pub type u_int64_t = u64; +pub type u_char = c_uchar; +pub type u_short = c_ushort; +pub type u_int = c_uint; +pub type u_long = c_ulong; +pub type unchar = c_uchar; +pub type ushort = c_ushort; +pub type uint = c_uint; +pub type ulong = c_ulong; +pub type u_quad_t = u64; +pub type quad_t = i64; +pub type qaddr_t = *mut quad_t; +pub type longlong_t = i64; +pub type u_longlong_t = u64; +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type fsblkcnt_t = __fsblkcnt_t; +pub type fsfilcnt_t = __fsfilcnt_t; +pub type caddr_t = __caddr_t; +pub type daddr_t = i64; +pub type dev_t = u64; +pub type fixpt_t = u32; +pub type gid_t = __gid_t; +pub type idtype_t = c_int; +pub type id_t = u32; +pub type ino_t = u64; +pub type key_t = c_long; +pub type mode_t = __mode_t; +pub type nlink_t = u32; +pub type off_t = __off_t; +pub type pid_t = __pid_t; +pub type lwpid_t = i32; +pub type rlim_t = u64; +pub type segsz_t = i32; +pub type swblk_t = i32; +pub type mqd_t = c_int; +pub type cpuid_t = c_ulong; +pub type psetid_t = c_int; + +s! { + // stat.h + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: c_short, + pub st_nlink: c_short, + pub st_uid: c_short, + pub st_gid: c_short, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_mtime: time_t, + pub st_ctime: time_t, + pub st_blksize: blksize_t, + } + + // time.h + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *mut c_char, + } + + // stdlib.h + pub struct qdiv_t { + pub quot: quad_t, + pub rem: quad_t, + } + pub struct lldiv_t { + pub quot: c_longlong, + pub rem: c_longlong, + } + pub struct div_t { + pub quot: c_int, + pub rem: c_int, + } + pub struct ldiv_t { + pub quot: c_long, + pub rem: c_long, + } + + // locale.h + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_n_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: c_long, + pub tv_usec: c_long, + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 0x7fffffff; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const BUFSIZ: c_uint = 1024; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 1024; + +pub const O_RDONLY: c_int = 1; +pub const O_WRONLY: c_int = 2; +pub const O_RDWR: c_int = 4; +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 0x10; +pub const O_EXCL: c_int = 0x400; +pub const O_TEXT: c_int = 0x100; +pub const O_BINARY: c_int = 0x200; +pub const O_TRUNC: c_int = 0x20; +pub const S_IEXEC: c_short = 0o0100; +pub const S_IWRITE: c_short = 0o0200; +pub const S_IREAD: c_short = 0o0400; +pub const S_IFCHR: c_short = 0o2_0000; +pub const S_IFDIR: c_short = 0o4_0000; +pub const S_IFMT: c_short = 0o16_0000; +pub const S_IFIFO: c_short = 0o1_0000; +pub const S_IFBLK: c_short = 0o6_0000; +pub const S_IFREG: c_short = 0o10_0000; + +pub const LC_ALL: c_int = 0; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; +pub const LC_MESSAGES: c_int = 6; +pub const _LC_LAST: c_int = 7; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; + +pub const EDEADLOCK: c_int = EDEADLK; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EMULTIHOP: c_int = 72; +pub const EDOTDOT: c_int = 73; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; + +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; + +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; + +pub const ENOTSUP: c_int = 132; +pub const EFTYPE: c_int = 133; + +// signal codes +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGIOT: c_int = SIGABRT; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGURG: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGIO: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGINFO: c_int = 29; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGPWR: c_int = 32; + +extern_ty! { + pub enum FILE {} + pub enum fpos_t {} +} + +extern "C" { + // ctype.h + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + + // stdio.h + pub fn __get_stdio_file(fileno: c_int) -> *mut FILE; + pub fn clearerr(arg1: *mut FILE); + pub fn fclose(arg1: *mut FILE) -> c_int; + pub fn feof(arg1: *mut FILE) -> c_int; + pub fn ferror(arg1: *mut FILE) -> c_int; + pub fn fflush(arg1: *mut FILE) -> c_int; + pub fn fgetc(arg1: *mut FILE) -> c_int; + pub fn fgets(arg1: *mut c_char, arg2: c_int, arg3: *mut FILE) -> *mut c_char; + pub fn fopen(arg1: *const c_char, arg2: *const c_char) -> *mut FILE; + pub fn fprintf(arg1: *mut FILE, arg2: *const c_char, ...) -> c_int; + pub fn fputc(arg1: c_int, arg2: *mut FILE) -> c_int; + pub fn fputs(arg1: *const c_char, arg2: *mut FILE) -> c_int; + pub fn fread(arg1: *mut c_void, arg2: size_t, arg3: size_t, arg4: *mut FILE) -> size_t; + pub fn freopen(arg1: *const c_char, arg2: *const c_char, arg3: *mut FILE) -> *mut FILE; + pub fn fscanf(arg1: *mut FILE, arg2: *const c_char, ...) -> c_int; + pub fn fseek(arg1: *mut FILE, arg2: c_long, arg3: c_int) -> c_int; + pub fn ftell(arg1: *mut FILE) -> c_long; + pub fn fwrite(arg1: *const c_void, arg2: size_t, arg3: size_t, arg4: *mut FILE) -> size_t; + pub fn getc(arg1: *mut FILE) -> c_int; + pub fn getchar() -> c_int; + pub fn perror(arg1: *const c_char); + pub fn printf(arg1: *const c_char, ...) -> c_int; + pub fn putc(arg1: c_int, arg2: *mut FILE) -> c_int; + pub fn putchar(arg1: c_int) -> c_int; + pub fn puts(arg1: *const c_char) -> c_int; + pub fn remove(arg1: *const c_char) -> c_int; + pub fn rewind(arg1: *mut FILE); + pub fn scanf(arg1: *const c_char, ...) -> c_int; + pub fn setbuf(arg1: *mut FILE, arg2: *mut c_char); + pub fn setvbuf(arg1: *mut FILE, arg2: *mut c_char, arg3: c_int, arg4: size_t) -> c_int; + pub fn sscanf(arg1: *const c_char, arg2: *const c_char, ...) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn ungetc(arg1: c_int, arg2: *mut FILE) -> c_int; + pub fn vfprintf(arg1: *mut FILE, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn vprintf(arg1: *const c_char, arg2: __va_list) -> c_int; + pub fn gets(arg1: *mut c_char) -> *mut c_char; + pub fn sprintf(arg1: *mut c_char, arg2: *const c_char, ...) -> c_int; + pub fn tmpnam(arg1: *const c_char) -> *mut c_char; + pub fn vsprintf(arg1: *mut c_char, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn rename(arg1: *const c_char, arg2: *const c_char) -> c_int; + pub fn asiprintf(arg1: *mut *mut c_char, arg2: *const c_char, ...) -> c_int; + pub fn fiprintf(arg1: *mut FILE, arg2: *const c_char, ...) -> c_int; + pub fn fiscanf(arg1: *mut FILE, arg2: *const c_char, ...) -> c_int; + pub fn iprintf(arg1: *const c_char, ...) -> c_int; + pub fn iscanf(arg1: *const c_char, ...) -> c_int; + pub fn siprintf(arg1: *mut c_char, arg2: *const c_char, ...) -> c_int; + pub fn siscanf(arg1: *mut c_char, arg2: *const c_char, ...) -> c_int; + pub fn sniprintf(arg1: *mut c_char, arg2: size_t, arg3: *const c_char, ...) -> c_int; + pub fn vasiprintf(arg1: *mut *mut c_char, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn vfiprintf(arg1: *mut FILE, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn vfiscanf(arg1: *mut FILE, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn viprintf(arg1: *const c_char, arg2: __va_list) -> c_int; + pub fn viscanf(arg1: *const c_char, arg2: __va_list) -> c_int; + pub fn vsiprintf(arg1: *mut c_char, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn vsiscanf(arg1: *const c_char, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn vsniprintf( + arg1: *mut c_char, + arg2: size_t, + arg3: *const c_char, + arg4: __va_list, + ) -> c_int; + pub fn vdiprintf(arg1: c_int, arg2: *const c_char, arg3: __va_list) -> c_int; + pub fn diprintf(arg1: c_int, arg2: *const c_char, ...) -> c_int; + pub fn fgetpos(arg1: *mut FILE, arg2: *mut fpos_t) -> c_int; + pub fn fsetpos(arg1: *mut FILE, arg2: *const fpos_t) -> c_int; + pub fn fdopen(arg1: c_int, arg2: *const c_char) -> *mut FILE; + pub fn fileno(arg1: *mut FILE) -> c_int; + pub fn flockfile(arg1: *mut FILE); + pub fn ftrylockfile(arg1: *mut FILE) -> c_int; + pub fn funlockfile(arg1: *mut FILE); + pub fn getc_unlocked(arg1: *mut FILE) -> c_int; + pub fn getchar_unlocked() -> c_int; + pub fn putc_unlocked(arg1: c_int, arg2: *mut FILE) -> c_int; + pub fn putchar_unlocked(arg1: c_int) -> c_int; + pub fn snprintf(arg1: *mut c_char, arg2: size_t, arg3: *const c_char, ...) -> c_int; + pub fn vsnprintf( + arg1: *mut c_char, + arg2: size_t, + arg3: *const c_char, + arg4: __va_list, + ) -> c_int; + pub fn getw(arg1: *mut FILE) -> c_int; + pub fn putw(arg1: c_int, arg2: *mut FILE) -> c_int; + pub fn tempnam(arg1: *const c_char, arg2: *const c_char) -> *mut c_char; + pub fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> c_int; + pub fn ftello(stream: *mut FILE) -> off_t; + + // stdlib.h + pub fn atof(arg1: *const c_char) -> f64; + pub fn strtod(arg1: *const c_char, arg2: *mut *mut c_char) -> f64; + pub fn drand48() -> f64; + pub fn erand48(arg1: *mut c_ushort) -> f64; + pub fn strtof(arg1: *const c_char, arg2: *mut *mut c_char) -> f32; + pub fn strtold(arg1: *const c_char, arg2: *mut *mut c_char) -> f64; + pub fn strtod_l(arg1: *const c_char, arg2: *mut *mut c_char, arg3: locale_t) -> f64; + pub fn strtof_l(arg1: *const c_char, arg2: *mut *mut c_char, arg3: locale_t) -> f32; + pub fn strtold_l(arg1: *const c_char, arg2: *mut *mut c_char, arg3: locale_t) -> f64; + pub fn _Exit(arg1: c_int) -> !; + pub fn abort() -> !; + pub fn abs(arg1: c_int) -> c_int; + pub fn atexit(arg1: Option) -> c_int; + pub fn atoi(arg1: *const c_char) -> c_int; + pub fn atol(arg1: *const c_char) -> c_long; + pub fn itoa(arg1: c_int, arg2: *mut c_char, arg3: c_int) -> *mut c_char; + pub fn ltoa(arg1: c_long, arg2: *mut c_char, arg3: c_int) -> *mut c_char; + pub fn ultoa(arg1: c_ulong, arg2: *mut c_char, arg3: c_int) -> *mut c_char; + pub fn bsearch( + arg1: *const c_void, + arg2: *const c_void, + arg3: size_t, + arg4: size_t, + arg5: Option c_int>, + ) -> *mut c_void; + pub fn calloc(arg1: size_t, arg2: size_t) -> *mut c_void; + pub fn div(arg1: c_int, arg2: c_int) -> div_t; + pub fn exit(arg1: c_int) -> !; + pub fn free(arg1: *mut c_void); + pub fn getenv(arg1: *const c_char) -> *mut c_char; + pub fn labs(arg1: c_long) -> c_long; + pub fn ldiv(arg1: c_long, arg2: c_long) -> ldiv_t; + pub fn malloc(arg1: size_t) -> *mut c_void; + pub fn qsort( + arg1: *mut c_void, + arg2: size_t, + arg3: size_t, + arg4: Option c_int>, + ); + pub fn rand() -> c_int; + pub fn realloc(arg1: *mut c_void, arg2: size_t) -> *mut c_void; + pub fn srand(arg1: c_uint); + pub fn strtol(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_long; + pub fn strtoul(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_ulong; + pub fn mblen(arg1: *const c_char, arg2: size_t) -> c_int; + pub fn mbstowcs(arg1: *mut wchar_t, arg2: *const c_char, arg3: size_t) -> size_t; + pub fn wctomb(arg1: *mut c_char, arg2: wchar_t) -> c_int; + pub fn mbtowc(arg1: *mut wchar_t, arg2: *const c_char, arg3: size_t) -> c_int; + pub fn wcstombs(arg1: *mut c_char, arg2: *const wchar_t, arg3: size_t) -> size_t; + pub fn rand_r(arg1: *mut c_uint) -> c_int; + pub fn jrand48(arg1: *mut c_ushort) -> c_long; + pub fn lcong48(arg1: *mut c_ushort); + pub fn lrand48() -> c_long; + pub fn mrand48() -> c_long; + pub fn nrand48(arg1: *mut c_ushort) -> c_long; + pub fn seed48(arg1: *mut c_ushort) -> *mut c_ushort; + pub fn srand48(arg1: c_long); + pub fn putenv(arg1: *mut c_char) -> c_int; + pub fn a64l(arg1: *const c_char) -> c_long; + pub fn l64a(arg1: c_long) -> *mut c_char; + pub fn random() -> c_long; + pub fn setstate(arg1: *mut c_char) -> *mut c_char; + pub fn initstate(arg1: c_uint, arg2: *mut c_char, arg3: size_t) -> *mut c_char; + pub fn srandom(arg1: c_uint); + pub fn mkostemp(arg1: *mut c_char, arg2: c_int) -> c_int; + pub fn mkostemps(arg1: *mut c_char, arg2: c_int, arg3: c_int) -> c_int; + pub fn mkdtemp(arg1: *mut c_char) -> *mut c_char; + pub fn mkstemp(arg1: *mut c_char) -> c_int; + pub fn mktemp(arg1: *mut c_char) -> *mut c_char; + pub fn atoll(arg1: *const c_char) -> c_longlong; + pub fn llabs(arg1: c_longlong) -> c_longlong; + pub fn lldiv(arg1: c_longlong, arg2: c_longlong) -> lldiv_t; + pub fn strtoll(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_longlong; + pub fn strtoull(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_ulonglong; + pub fn aligned_alloc(arg1: size_t, arg2: size_t) -> *mut c_void; + pub fn at_quick_exit(arg1: Option) -> c_int; + pub fn quick_exit(arg1: c_int); + pub fn setenv(arg1: *const c_char, arg2: *const c_char, arg3: c_int) -> c_int; + pub fn unsetenv(arg1: *const c_char) -> c_int; + pub fn humanize_number( + arg1: *mut c_char, + arg2: size_t, + arg3: i64, + arg4: *const c_char, + arg5: c_int, + arg6: c_int, + ) -> c_int; + pub fn dehumanize_number(arg1: *const c_char, arg2: *mut i64) -> c_int; + pub fn getenv_r(arg1: *const c_char, arg2: *mut c_char, arg3: size_t) -> c_int; + pub fn heapsort( + arg1: *mut c_void, + arg2: size_t, + arg3: size_t, + arg4: Option c_int>, + ) -> c_int; + pub fn mergesort( + arg1: *mut c_void, + arg2: size_t, + arg3: size_t, + arg4: Option c_int>, + ) -> c_int; + pub fn radixsort( + arg1: *mut *const c_uchar, + arg2: c_int, + arg3: *const c_uchar, + arg4: c_uint, + ) -> c_int; + pub fn sradixsort( + arg1: *mut *const c_uchar, + arg2: c_int, + arg3: *const c_uchar, + arg4: c_uint, + ) -> c_int; + pub fn getprogname() -> *const c_char; + pub fn setprogname(arg1: *const c_char); + pub fn qabs(arg1: quad_t) -> quad_t; + pub fn strtoq(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> quad_t; + pub fn strtouq(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> u_quad_t; + pub fn strsuftoll( + arg1: *const c_char, + arg2: *const c_char, + arg3: c_longlong, + arg4: c_longlong, + ) -> c_longlong; + pub fn strsuftollx( + arg1: *const c_char, + arg2: *const c_char, + arg3: c_longlong, + arg4: c_longlong, + arg5: *mut c_char, + arg6: size_t, + ) -> c_longlong; + pub fn l64a_r(arg1: c_long, arg2: *mut c_char, arg3: c_int) -> c_int; + pub fn qdiv(arg1: quad_t, arg2: quad_t) -> qdiv_t; + pub fn strtol_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> c_long; + pub fn strtoul_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> c_ulong; + pub fn strtoll_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> c_longlong; + pub fn strtoull_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> c_ulonglong; + pub fn strtoq_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> quad_t; + pub fn strtouq_l( + arg1: *const c_char, + arg2: *mut *mut c_char, + arg3: c_int, + arg4: locale_t, + ) -> u_quad_t; + pub fn _mb_cur_max_l(arg1: locale_t) -> size_t; + pub fn mblen_l(arg1: *const c_char, arg2: size_t, arg3: locale_t) -> c_int; + pub fn mbstowcs_l( + arg1: *mut wchar_t, + arg2: *const c_char, + arg3: size_t, + arg4: locale_t, + ) -> size_t; + pub fn wctomb_l(arg1: *mut c_char, arg2: wchar_t, arg3: locale_t) -> c_int; + pub fn mbtowc_l(arg1: *mut wchar_t, arg2: *const c_char, arg3: size_t, arg4: locale_t) + -> c_int; + pub fn wcstombs_l( + arg1: *mut c_char, + arg2: *const wchar_t, + arg3: size_t, + arg4: locale_t, + ) -> size_t; + + // string.h + pub fn memchr(arg1: *const c_void, arg2: c_int, arg3: size_t) -> *mut c_void; + pub fn memcmp(arg1: *const c_void, arg2: *const c_void, arg3: size_t) -> c_int; + pub fn memcpy(arg1: *mut c_void, arg2: *const c_void, arg3: size_t) -> *mut c_void; + pub fn memmove(arg1: *mut c_void, arg2: *const c_void, arg3: size_t) -> *mut c_void; + pub fn memset(arg1: *mut c_void, arg2: c_int, arg3: size_t) -> *mut c_void; + pub fn strcat(arg1: *mut c_char, arg2: *const c_char) -> *mut c_char; + pub fn strchr(arg1: *const c_char, arg2: c_int) -> *mut c_char; + pub fn strcmp(arg1: *const c_char, arg2: *const c_char) -> c_int; + pub fn strcoll(arg1: *const c_char, arg2: *const c_char) -> c_int; + pub fn strcpy(arg1: *mut c_char, arg2: *const c_char) -> *mut c_char; + pub fn strcspn(arg1: *const c_char, arg2: *const c_char) -> size_t; + pub fn strerror(arg1: c_int) -> *mut c_char; + pub fn strlen(arg1: *const c_char) -> size_t; + pub fn strncat(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> *mut c_char; + pub fn strncmp(arg1: *const c_char, arg2: *const c_char, arg3: size_t) -> c_int; + pub fn strncpy(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> *mut c_char; + pub fn strpbrk(arg1: *const c_char, arg2: *const c_char) -> *mut c_char; + pub fn strrchr(arg1: *const c_char, arg2: c_int) -> *mut c_char; + pub fn strspn(arg1: *const c_char, arg2: *const c_char) -> size_t; + pub fn strstr(arg1: *const c_char, arg2: *const c_char) -> *mut c_char; + pub fn strtok(arg1: *mut c_char, arg2: *const c_char) -> *mut c_char; + pub fn strtok_r(arg1: *mut c_char, arg2: *const c_char, arg3: *mut *mut c_char) -> *mut c_char; + pub fn strerror_r(arg1: c_int, arg2: *mut c_char, arg3: size_t) -> c_int; + pub fn strxfrm(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> size_t; + pub fn memccpy( + arg1: *mut c_void, + arg2: *const c_void, + arg3: c_int, + arg4: size_t, + ) -> *mut c_void; + pub fn strdup(arg1: *const c_char) -> *mut c_char; + pub fn stpcpy(arg1: *mut c_char, arg2: *const c_char) -> *mut c_char; + pub fn stpncpy(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> *mut c_char; + pub fn strnlen(arg1: *const c_char, arg2: size_t) -> size_t; + pub fn memmem( + arg1: *const c_void, + arg2: size_t, + arg3: *const c_void, + arg4: size_t, + ) -> *mut c_void; + pub fn strcasestr(arg1: *const c_char, arg2: *const c_char) -> *mut c_char; + pub fn strlcat(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> size_t; + pub fn strlcpy(arg1: *mut c_char, arg2: *const c_char, arg3: size_t) -> size_t; + pub fn strsep(arg1: *mut *mut c_char, arg2: *const c_char) -> *mut c_char; + pub fn stresep(arg1: *mut *mut c_char, arg2: *const c_char, arg3: c_int) -> *mut c_char; + pub fn strndup(arg1: *const c_char, arg2: size_t) -> *mut c_char; + pub fn memrchr(arg1: *const c_void, arg2: c_int, arg3: size_t) -> *mut c_void; + pub fn explicit_memset(arg1: *mut c_void, arg2: c_int, arg3: size_t) -> *mut c_void; + pub fn consttime_memequal(arg1: *const c_void, arg2: *const c_void, arg3: size_t) -> c_int; + pub fn strcoll_l(arg1: *const c_char, arg2: *const c_char, arg3: locale_t) -> c_int; + pub fn strxfrm_l( + arg1: *mut c_char, + arg2: *const c_char, + arg3: size_t, + arg4: locale_t, + ) -> size_t; + pub fn strerror_l(arg1: c_int, arg2: locale_t) -> *mut c_char; + + // strings.h + pub fn bcmp(arg1: *const c_void, arg2: *const c_void, arg3: size_t) -> c_int; + pub fn bcopy(arg1: *const c_void, arg2: *mut c_void, arg3: size_t); + pub fn bzero(arg1: *mut c_void, arg2: size_t); + pub fn ffs(arg1: c_int) -> c_int; + pub fn popcount(arg1: c_uint) -> c_uint; + pub fn popcountl(arg1: c_ulong) -> c_uint; + pub fn popcountll(arg1: c_ulonglong) -> c_uint; + pub fn popcount32(arg1: u32) -> c_uint; + pub fn popcount64(arg1: u64) -> c_uint; + pub fn rindex(arg1: *const c_char, arg2: c_int) -> *mut c_char; + pub fn strcasecmp(arg1: *const c_char, arg2: *const c_char) -> c_int; + pub fn strncasecmp(arg1: *const c_char, arg2: *const c_char, arg3: size_t) -> c_int; + + // signal.h + pub fn signal(arg1: c_int, arg2: sighandler_t) -> sighandler_t; + pub fn raise(arg1: c_int) -> c_int; + + // time.h + pub fn asctime(arg1: *const tm) -> *mut c_char; + pub fn clock() -> clock_t; + pub fn ctime(arg1: *const time_t) -> *mut c_char; + pub fn difftime(arg1: time_t, arg2: time_t) -> f64; + pub fn gmtime(arg1: *const time_t) -> *mut tm; + pub fn localtime(arg1: *const time_t) -> *mut tm; + pub fn time(arg1: *mut time_t) -> time_t; + pub fn mktime(arg1: *mut tm) -> time_t; + pub fn strftime( + arg1: *mut c_char, + arg2: size_t, + arg3: *const c_char, + arg4: *const tm, + ) -> size_t; + pub fn utime(arg1: *const c_char, arg2: *mut time_t) -> c_int; + pub fn asctime_r(arg1: *const tm, arg2: *mut c_char) -> *mut c_char; + pub fn ctime_r(arg1: *const time_t, arg2: *mut c_char) -> *mut c_char; + pub fn gmtime_r(arg1: *const time_t, arg2: *mut tm) -> *mut tm; + pub fn localtime_r(arg1: *const time_t, arg2: *mut tm) -> *mut tm; + + // sys/stat.h + pub fn stat(arg1: *const c_char, arg2: *mut stat) -> c_int; + pub fn lstat(arg1: *const c_char, arg2: *mut stat) -> c_int; + pub fn fstat(arg1: c_int, arg2: *mut stat) -> c_int; + pub fn chmod(arg1: *const c_char, arg2: __mode_t) -> c_int; + pub fn mkdir(arg1: *const c_char, arg2: __mode_t) -> c_int; + + // fcntl.h + pub fn open(arg1: *const c_char, arg2: c_int, ...) -> c_int; + pub fn creat(arg1: *const c_char, arg2: c_int) -> c_int; + pub fn close(arg1: c_int) -> c_int; + pub fn read(arg1: c_int, arg2: *mut c_void, arg3: c_int) -> c_int; + pub fn write(arg1: c_int, arg2: *const c_void, arg3: c_int) -> c_int; + pub fn unlink(arg1: *const c_char) -> c_int; + pub fn tell(arg1: c_int) -> c_long; + pub fn dup(arg1: c_int) -> c_int; + pub fn dup2(arg1: c_int, arg2: c_int) -> c_int; + pub fn access(arg1: *const c_char, arg2: c_int) -> c_int; + pub fn rmdir(arg1: *const c_char) -> c_int; + pub fn chdir(arg1: *const c_char) -> c_int; + pub fn _exit(arg1: c_int); + pub fn getwd(arg1: *mut c_char) -> *mut c_char; + pub fn getcwd(arg1: *mut c_char, arg2: size_t) -> *mut c_char; + pub static mut optarg: *mut c_char; + pub static mut opterr: c_int; + pub static mut optind: c_int; + pub static mut optopt: c_int; + pub static mut optreset: c_int; + pub fn getopt(arg1: c_int, arg2: *mut *mut c_char, arg3: *const c_char) -> c_int; + pub static mut suboptarg: *mut c_char; + pub fn getsubopt( + arg1: *mut *mut c_char, + arg2: *const *mut c_char, + arg3: *mut *mut c_char, + ) -> c_int; + pub fn fcntl(arg1: c_int, arg2: c_int, ...) -> c_int; + pub fn getpid() -> pid_t; + pub fn sleep(arg1: c_uint) -> c_uint; + pub fn usleep(arg1: useconds_t) -> c_int; + + // locale.h + pub fn localeconv() -> *mut lconv; + pub fn setlocale(arg1: c_int, arg2: *const c_char) -> *mut c_char; + pub fn duplocale(arg1: locale_t) -> locale_t; + pub fn freelocale(arg1: locale_t); + pub fn localeconv_l(arg1: locale_t) -> *mut lconv; + pub fn newlocale(arg1: c_int, arg2: *const c_char, arg3: locale_t) -> locale_t; + + // langinfo.h + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + pub fn nl_langinfo_l(item: crate::nl_item, locale: locale_t) -> *mut c_char; + + // malloc.h + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + + // sys/types.h + pub fn lseek(arg1: c_int, arg2: __off_t, arg3: c_int) -> __off_t; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "arm"))] { + mod arm; + pub use self::arm::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/switch.rs b/deps/crates/vendor/libc/src/switch.rs new file mode 100644 index 00000000000000..2d202dd61fc5d1 --- /dev/null +++ b/deps/crates/vendor/libc/src/switch.rs @@ -0,0 +1,17 @@ +//! Switch C type definitions +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type off_t = i64; +pub type wchar_t = u32; + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; diff --git a/deps/crates/vendor/libc/src/teeos/mod.rs b/deps/crates/vendor/libc/src/teeos/mod.rs new file mode 100644 index 00000000000000..89a30a888a5b48 --- /dev/null +++ b/deps/crates/vendor/libc/src/teeos/mod.rs @@ -0,0 +1,1349 @@ +//! Libc bindings for teeos +//! +//! Apparently the loader just dynamically links it anyway, but fails +//! when linking is explicitly requested. +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use crate::prelude::*; + +pub type c_bool = i32; + +pub type intmax_t = i64; + +pub type uintmax_t = u64; + +pub type size_t = usize; + +pub type ptrdiff_t = isize; + +pub type intptr_t = isize; + +pub type uintptr_t = usize; + +pub type ssize_t = isize; + +pub type pid_t = c_int; + +pub type wchar_t = u32; + +// long double in C means A float point value, which has 128bit length. +// but some bit maybe not used, so the real length of long double could be 80(x86) or 128(power pc/IEEE) +// this is different from f128(not stable and not included default) in Rust, so we use u128 for FFI(Rust to C). +// this is unstable and will cause to memfault/data abort. +pub type c_longdouble = _CLongDouble; + +pub type pthread_t = c_ulong; + +pub type pthread_key_t = c_uint; + +pub type pthread_spinlock_t = c_int; + +pub type off_t = i64; + +pub type time_t = c_long; + +pub type clock_t = c_long; + +pub type clockid_t = c_int; + +pub type suseconds_t = c_long; + +pub type once_fn = extern "C" fn() -> c_void; + +pub type pthread_once_t = c_int; + +pub type va_list = *mut c_char; + +pub type wint_t = c_uint; + +pub type wctype_t = c_ulong; + +pub type cmpfunc = extern "C" fn(x: *const c_void, y: *const c_void) -> c_int; + +s_paren! { + #[repr(align(16))] + pub struct _CLongDouble(pub u128); +} + +s! { + #[repr(align(8))] + pub struct pthread_cond_t { + #[doc(hidden)] + size: [u8; __SIZEOF_PTHREAD_COND_T], + } + + #[repr(align(8))] + pub struct pthread_mutex_t { + #[doc(hidden)] + size: [u8; __SIZEOF_PTHREAD_MUTEX_T], + } + + #[repr(align(4))] + pub struct pthread_mutexattr_t { + #[doc(hidden)] + size: [u8; __SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + #[doc(hidden)] + size: [u8; __SIZEOF_PTHREAD_CONDATTR_T], + } + + pub struct pthread_attr_t { + __size: [u64; 7], + } + + pub struct cpu_set_t { + bits: [c_ulong; 128 / size_of::()], + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub __tm_gmtoff: c_long, + pub __tm_zone: *const c_char, + } + + pub struct mbstate_t { + pub __opaque1: c_uint, + pub __opaque2: c_uint, + } + + pub struct sem_t { + pub __val: [c_int; 4 * size_of::() / size_of::()], + } + + pub struct div_t { + pub quot: c_int, + pub rem: c_int, + } +} + +// fcntl +pub const O_CREAT: u32 = 0o100; + +pub const O_EXCL: u32 = 0o200; + +pub const O_NOCTTY: u32 = 0o400; + +pub const O_TRUNC: u32 = 0o1000; + +pub const O_APPEND: u32 = 0o2000; + +pub const O_NONBLOCK: u32 = 0o4000; + +pub const O_DSYNC: u32 = 0o10000; + +pub const O_SYNC: u32 = 0o4010000; + +pub const O_RSYNC: u32 = 0o4010000; + +pub const O_DIRECTORY: u32 = 0o200000; + +pub const O_NOFOLLOW: u32 = 0o400000; + +pub const O_CLOEXEC: u32 = 0o2000000; + +pub const O_ASYNC: u32 = 0o20000; + +pub const O_DIRECT: u32 = 0o40000; + +pub const O_LARGEFILE: u32 = 0o100000; + +pub const O_NOATIME: u32 = 0o1000000; + +pub const O_PATH: u32 = 0o10000000; + +pub const O_TMPFILE: u32 = 0o20200000; + +pub const O_NDELAY: u32 = O_NONBLOCK; + +pub const F_DUPFD: u32 = 0; + +pub const F_GETFD: u32 = 1; + +pub const F_SETFD: u32 = 2; + +pub const F_GETFL: u32 = 3; + +pub const F_SETFL: u32 = 4; + +pub const F_SETOWN: u32 = 8; + +pub const F_GETOWN: u32 = 9; + +pub const F_SETSIG: u32 = 10; + +pub const F_GETSIG: u32 = 11; + +pub const F_GETLK: u32 = 12; + +pub const F_SETLK: u32 = 13; + +pub const F_SETLKW: u32 = 14; + +pub const F_SETOWN_EX: u32 = 15; + +pub const F_GETOWN_EX: u32 = 16; + +pub const F_GETOWNER_UIDS: u32 = 17; + +// mman +pub const MAP_FAILED: u64 = 0xffffffffffffffff; + +pub const MAP_FIXED_NOREPLACE: u32 = 0x100000; + +pub const MAP_SHARED_VALIDATE: u32 = 0x03; + +pub const MAP_SHARED: u32 = 0x01; + +pub const MAP_PRIVATE: u32 = 0x02; + +pub const MAP_TYPE: u32 = 0x0f; + +pub const MAP_FIXED: u32 = 0x10; + +pub const MAP_ANON: u32 = 0x20; + +pub const MAP_ANONYMOUS: u32 = MAP_ANON; + +pub const MAP_NORESERVE: u32 = 0x4000; + +pub const MAP_GROWSDOWN: u32 = 0x0100; + +pub const MAP_DENYWRITE: u32 = 0x0800; + +pub const MAP_EXECUTABLE: u32 = 0x1000; + +pub const MAP_LOCKED: u32 = 0x2000; + +pub const MAP_POPULATE: u32 = 0x8000; + +pub const MAP_NONBLOCK: u32 = 0x10000; + +pub const MAP_STACK: u32 = 0x20000; + +pub const MAP_HUGETLB: u32 = 0x40000; + +pub const MAP_SYNC: u32 = 0x80000; + +pub const MAP_FILE: u32 = 0; + +pub const MAP_HUGE_SHIFT: u32 = 26; + +pub const MAP_HUGE_MASK: u32 = 0x3f; + +pub const MAP_HUGE_16KB: u32 = 14 << 26; + +pub const MAP_HUGE_64KB: u32 = 16 << 26; + +pub const MAP_HUGE_512KB: u32 = 19 << 26; + +pub const MAP_HUGE_1MB: u32 = 20 << 26; + +pub const MAP_HUGE_2MB: u32 = 21 << 26; + +pub const MAP_HUGE_8MB: u32 = 23 << 26; + +pub const MAP_HUGE_16MB: u32 = 24 << 26; + +pub const MAP_HUGE_32MB: u32 = 25 << 26; + +pub const MAP_HUGE_256MB: u32 = 28 << 26; + +pub const MAP_HUGE_512MB: u32 = 29 << 26; + +pub const MAP_HUGE_1GB: u32 = 30 << 26; + +pub const MAP_HUGE_2GB: u32 = 31 << 26; + +pub const MAP_HUGE_16GB: u32 = 34u32 << 26; + +pub const PROT_NONE: u32 = 0; + +pub const PROT_READ: u32 = 1; + +pub const PROT_WRITE: u32 = 2; + +pub const PROT_EXEC: u32 = 4; + +pub const PROT_GROWSDOWN: u32 = 0x01000000; + +pub const PROT_GROWSUP: u32 = 0x02000000; + +pub const MS_ASYNC: u32 = 1; + +pub const MS_INVALIDATE: u32 = 2; + +pub const MS_SYNC: u32 = 4; + +pub const MCL_CURRENT: u32 = 1; + +pub const MCL_FUTURE: u32 = 2; + +pub const MCL_ONFAULT: u32 = 4; + +pub const POSIX_MADV_NORMAL: u32 = 0; + +pub const POSIX_MADV_RANDOM: u32 = 1; + +pub const POSIX_MADV_SEQUENTIAL: u32 = 2; + +pub const POSIX_MADV_WILLNEED: u32 = 3; + +pub const POSIX_MADV_DONTNEED: u32 = 4; + +// wctype +pub const WCTYPE_ALNUM: u64 = 1; + +pub const WCTYPE_ALPHA: u64 = 2; + +pub const WCTYPE_BLANK: u64 = 3; + +pub const WCTYPE_CNTRL: u64 = 4; + +pub const WCTYPE_DIGIT: u64 = 5; + +pub const WCTYPE_GRAPH: u64 = 6; + +pub const WCTYPE_LOWER: u64 = 7; + +pub const WCTYPE_PRINT: u64 = 8; + +pub const WCTYPE_PUNCT: u64 = 9; + +pub const WCTYPE_SPACE: u64 = 10; + +pub const WCTYPE_UPPER: u64 = 11; + +pub const WCTYPE_XDIGIT: u64 = 12; + +// locale +pub const LC_CTYPE: i32 = 0; + +pub const LC_NUMERIC: i32 = 1; + +pub const LC_TIME: i32 = 2; + +pub const LC_COLLATE: i32 = 3; + +pub const LC_MONETARY: i32 = 4; + +pub const LC_MESSAGES: i32 = 5; + +pub const LC_ALL: i32 = 6; + +// pthread +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; + +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; + +// errno.h +pub const EPERM: c_int = 1; + +pub const ENOENT: c_int = 2; + +pub const ESRCH: c_int = 3; + +pub const EINTR: c_int = 4; + +pub const EIO: c_int = 5; + +pub const ENXIO: c_int = 6; + +pub const E2BIG: c_int = 7; + +pub const ENOEXEC: c_int = 8; + +pub const EBADF: c_int = 9; + +pub const ECHILD: c_int = 10; + +pub const EAGAIN: c_int = 11; + +pub const ENOMEM: c_int = 12; + +pub const EACCES: c_int = 13; + +pub const EFAULT: c_int = 14; + +pub const ENOTBLK: c_int = 15; + +pub const EBUSY: c_int = 16; + +pub const EEXIST: c_int = 17; + +pub const EXDEV: c_int = 18; + +pub const ENODEV: c_int = 19; + +pub const ENOTDIR: c_int = 20; + +pub const EISDIR: c_int = 21; + +pub const EINVAL: c_int = 22; + +pub const ENFILE: c_int = 23; + +pub const EMFILE: c_int = 24; + +pub const ENOTTY: c_int = 25; + +pub const ETXTBSY: c_int = 26; + +pub const EFBIG: c_int = 27; + +pub const ENOSPC: c_int = 28; + +pub const ESPIPE: c_int = 29; + +pub const EROFS: c_int = 30; + +pub const EMLINK: c_int = 31; + +pub const EPIPE: c_int = 32; + +pub const EDOM: c_int = 33; + +pub const ERANGE: c_int = 34; + +pub const EDEADLK: c_int = 35; + +pub const ENAMETOOLONG: c_int = 36; + +pub const ENOLCK: c_int = 37; + +pub const ENOSYS: c_int = 38; + +pub const ENOTEMPTY: c_int = 39; + +pub const ELOOP: c_int = 40; + +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const ENOMSG: c_int = 42; + +pub const EIDRM: c_int = 43; + +pub const ECHRNG: c_int = 44; + +pub const EL2NSYNC: c_int = 45; + +pub const EL3HLT: c_int = 46; + +pub const EL3RST: c_int = 47; + +pub const ELNRNG: c_int = 48; + +pub const EUNATCH: c_int = 49; + +pub const ENOCSI: c_int = 50; + +pub const EL2HLT: c_int = 51; + +pub const EBADE: c_int = 52; + +pub const EBADR: c_int = 53; + +pub const EXFULL: c_int = 54; + +pub const ENOANO: c_int = 55; + +pub const EBADRQC: c_int = 56; + +pub const EBADSLT: c_int = 57; + +pub const EDEADLOCK: c_int = EDEADLK; + +pub const EBFONT: c_int = 59; + +pub const ENOSTR: c_int = 60; + +pub const ENODATA: c_int = 61; + +pub const ETIME: c_int = 62; + +pub const ENOSR: c_int = 63; + +pub const ENONET: c_int = 64; + +pub const ENOPKG: c_int = 65; + +pub const EREMOTE: c_int = 66; + +pub const ENOLINK: c_int = 67; + +pub const EADV: c_int = 68; + +pub const ESRMNT: c_int = 69; + +pub const ECOMM: c_int = 70; + +pub const EPROTO: c_int = 71; + +pub const EMULTIHOP: c_int = 72; + +pub const EDOTDOT: c_int = 73; + +pub const EBADMSG: c_int = 74; + +pub const EOVERFLOW: c_int = 75; + +pub const ENOTUNIQ: c_int = 76; + +pub const EBADFD: c_int = 77; + +pub const EREMCHG: c_int = 78; + +pub const ELIBACC: c_int = 79; + +pub const ELIBBAD: c_int = 80; + +pub const ELIBSCN: c_int = 81; + +pub const ELIBMAX: c_int = 82; + +pub const ELIBEXEC: c_int = 83; + +pub const EILSEQ: c_int = 84; + +pub const ERESTART: c_int = 85; + +pub const ESTRPIPE: c_int = 86; + +pub const EUSERS: c_int = 87; + +pub const ENOTSOCK: c_int = 88; + +pub const EDESTADDRREQ: c_int = 89; + +pub const EMSGSIZE: c_int = 90; + +pub const EPROTOTYPE: c_int = 91; + +pub const ENOPROTOOPT: c_int = 92; + +pub const EPROTONOSUPPOR: c_int = 93; + +pub const ESOCKTNOSUPPOR: c_int = 94; + +pub const EOPNOTSUPP: c_int = 95; + +pub const ENOTSUP: c_int = EOPNOTSUPP; + +pub const EPFNOSUPPORT: c_int = 96; + +pub const EAFNOSUPPORT: c_int = 97; + +pub const EADDRINUSE: c_int = 98; + +pub const EADDRNOTAVAIL: c_int = 99; + +pub const ENETDOWN: c_int = 100; + +pub const ENETUNREACH: c_int = 101; + +pub const ENETRESET: c_int = 102; + +pub const ECONNABORTED: c_int = 103; + +pub const ECONNRESET: c_int = 104; + +pub const ENOBUFS: c_int = 105; + +pub const EISCONN: c_int = 106; + +pub const ENOTCONN: c_int = 107; + +pub const ESHUTDOWN: c_int = 108; + +pub const ETOOMANYREFS: c_int = 109; + +pub const ETIMEDOUT: c_int = 110; + +pub const ECONNREFUSED: c_int = 111; + +pub const EHOSTDOWN: c_int = 112; + +pub const EHOSTUNREACH: c_int = 113; + +pub const EALREADY: c_int = 114; + +pub const EINPROGRESS: c_int = 115; + +pub const ESTALE: c_int = 116; + +pub const EUCLEAN: c_int = 117; + +pub const ENOTNAM: c_int = 118; + +pub const ENAVAIL: c_int = 119; + +pub const EISNAM: c_int = 120; + +pub const EREMOTEIO: c_int = 121; + +pub const EDQUOT: c_int = 122; + +pub const ENOMEDIUM: c_int = 123; + +pub const EMEDIUMTYPE: c_int = 124; + +pub const ECANCELED: c_int = 125; + +pub const ENOKEY: c_int = 126; + +pub const EKEYEXPIRED: c_int = 127; + +pub const EKEYREVOKED: c_int = 128; + +pub const EKEYREJECTED: c_int = 129; + +pub const EOWNERDEAD: c_int = 130; + +pub const ENOTRECOVERABLE: c_int = 131; + +pub const ERFKILL: c_int = 132; + +pub const EHWPOISON: c_int = 133; + +// pthread_attr.h +pub const TEESMP_THREAD_ATTR_CA_WILDCARD: c_int = 0; + +pub const TEESMP_THREAD_ATTR_CA_INHERIT: c_int = -1; + +pub const TEESMP_THREAD_ATTR_TASK_ID_INHERIT: c_int = -1; + +pub const TEESMP_THREAD_ATTR_HAS_SHADOW: c_int = 0x1; + +pub const TEESMP_THREAD_ATTR_NO_SHADOW: c_int = 0x0; + +// unistd.h +pub const _SC_ARG_MAX: c_int = 0; + +pub const _SC_CHILD_MAX: c_int = 1; + +pub const _SC_CLK_TCK: c_int = 2; + +pub const _SC_NGROUPS_MAX: c_int = 3; + +pub const _SC_OPEN_MAX: c_int = 4; + +pub const _SC_STREAM_MAX: c_int = 5; + +pub const _SC_TZNAME_MAX: c_int = 6; + +pub const _SC_JOB_CONTROL: c_int = 7; + +pub const _SC_SAVED_IDS: c_int = 8; + +pub const _SC_REALTIME_SIGNALS: c_int = 9; + +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; + +pub const _SC_TIMERS: c_int = 11; + +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; + +pub const _SC_PRIORITIZED_IO: c_int = 13; + +pub const _SC_SYNCHRONIZED_IO: c_int = 14; + +pub const _SC_FSYNC: c_int = 15; + +pub const _SC_MAPPED_FILES: c_int = 16; + +pub const _SC_MEMLOCK: c_int = 17; + +pub const _SC_MEMLOCK_RANGE: c_int = 18; + +pub const _SC_MEMORY_PROTECTION: c_int = 19; + +pub const _SC_MESSAGE_PASSING: c_int = 20; + +pub const _SC_SEMAPHORES: c_int = 21; + +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; + +pub const _SC_AIO_LISTIO_MAX: c_int = 23; + +pub const _SC_AIO_MAX: c_int = 24; + +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; + +pub const _SC_DELAYTIMER_MAX: c_int = 26; + +pub const _SC_MQ_OPEN_MAX: c_int = 27; + +pub const _SC_MQ_PRIO_MAX: c_int = 28; + +pub const _SC_VERSION: c_int = 29; + +pub const _SC_PAGE_SIZE: c_int = 30; + +pub const _SC_PAGESIZE: c_int = 30; /* !! */ + +pub const _SC_RTSIG_MAX: c_int = 31; + +pub const _SC_SEM_NSEMS_MAX: c_int = 32; + +pub const _SC_SEM_VALUE_MAX: c_int = 33; + +pub const _SC_SIGQUEUE_MAX: c_int = 34; + +pub const _SC_TIMER_MAX: c_int = 35; + +pub const _SC_BC_BASE_MAX: c_int = 36; + +pub const _SC_BC_DIM_MAX: c_int = 37; + +pub const _SC_BC_SCALE_MAX: c_int = 38; + +pub const _SC_BC_STRING_MAX: c_int = 39; + +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; + +pub const _SC_EXPR_NEST_MAX: c_int = 42; + +pub const _SC_LINE_MAX: c_int = 43; + +pub const _SC_RE_DUP_MAX: c_int = 44; + +pub const _SC_2_VERSION: c_int = 46; + +pub const _SC_2_C_BIND: c_int = 47; + +pub const _SC_2_C_DEV: c_int = 48; + +pub const _SC_2_FORT_DEV: c_int = 49; + +pub const _SC_2_FORT_RUN: c_int = 50; + +pub const _SC_2_SW_DEV: c_int = 51; + +pub const _SC_2_LOCALEDEF: c_int = 52; + +pub const _SC_UIO_MAXIOV: c_int = 60; /* !! */ + +pub const _SC_IOV_MAX: c_int = 60; + +pub const _SC_THREADS: c_int = 67; + +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; + +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; + +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; + +pub const _SC_LOGIN_NAME_MAX: c_int = 71; + +pub const _SC_TTY_NAME_MAX: c_int = 72; + +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; + +pub const _SC_THREAD_KEYS_MAX: c_int = 74; + +pub const _SC_THREAD_STACK_MIN: c_int = 75; + +pub const _SC_THREAD_THREADS_MAX: c_int = 76; + +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; + +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; + +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; + +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; + +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; + +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; + +pub const _SC_NPROCESSORS_CONF: c_int = 83; + +pub const _SC_NPROCESSORS_ONLN: c_int = 84; + +pub const _SC_PHYS_PAGES: c_int = 85; + +pub const _SC_AVPHYS_PAGES: c_int = 86; + +pub const _SC_ATEXIT_MAX: c_int = 87; + +pub const _SC_PASS_MAX: c_int = 88; + +pub const _SC_XOPEN_VERSION: c_int = 89; + +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; + +pub const _SC_XOPEN_UNIX: c_int = 91; + +pub const _SC_XOPEN_CRYPT: c_int = 92; + +pub const _SC_XOPEN_ENH_I18N: c_int = 93; + +pub const _SC_XOPEN_SHM: c_int = 94; + +pub const _SC_2_CHAR_TERM: c_int = 95; + +pub const _SC_2_UPE: c_int = 97; + +pub const _SC_XOPEN_XPG2: c_int = 98; + +pub const _SC_XOPEN_XPG3: c_int = 99; + +pub const _SC_XOPEN_XPG4: c_int = 100; + +pub const _SC_NZERO: c_int = 109; + +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; + +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; + +pub const _SC_XBS5_LP64_OFF64: c_int = 127; + +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; + +pub const _SC_XOPEN_LEGACY: c_int = 129; + +pub const _SC_XOPEN_REALTIME: c_int = 130; + +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; + +pub const _SC_ADVISORY_INFO: c_int = 132; + +pub const _SC_BARRIERS: c_int = 133; + +pub const _SC_CLOCK_SELECTION: c_int = 137; + +pub const _SC_CPUTIME: c_int = 138; + +pub const _SC_THREAD_CPUTIME: c_int = 139; + +pub const _SC_MONOTONIC_CLOCK: c_int = 149; + +pub const _SC_READER_WRITER_LOCKS: c_int = 153; + +pub const _SC_SPIN_LOCKS: c_int = 154; + +pub const _SC_REGEXP: c_int = 155; + +pub const _SC_SHELL: c_int = 157; + +pub const _SC_SPAWN: c_int = 159; + +pub const _SC_SPORADIC_SERVER: c_int = 160; + +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; + +pub const _SC_TIMEOUTS: c_int = 164; + +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; + +pub const _SC_2_PBS: c_int = 168; + +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; + +pub const _SC_2_PBS_LOCATE: c_int = 170; + +pub const _SC_2_PBS_MESSAGE: c_int = 171; + +pub const _SC_2_PBS_TRACK: c_int = 172; + +pub const _SC_SYMLOOP_MAX: c_int = 173; + +pub const _SC_STREAMS: c_int = 174; + +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; + +pub const _SC_V6_ILP32_OFF32: c_int = 176; + +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; + +pub const _SC_V6_LP64_OFF64: c_int = 178; + +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; + +pub const _SC_HOST_NAME_MAX: c_int = 180; + +pub const _SC_TRACE: c_int = 181; + +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; + +pub const _SC_TRACE_INHERIT: c_int = 183; + +pub const _SC_TRACE_LOG: c_int = 184; + +pub const _SC_IPV6: c_int = 235; + +pub const _SC_RAW_SOCKETS: c_int = 236; + +pub const _SC_V7_ILP32_OFF32: c_int = 237; + +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; + +pub const _SC_V7_LP64_OFF64: c_int = 239; + +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; + +pub const _SC_SS_REPL_MAX: c_int = 241; + +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; + +pub const _SC_TRACE_NAME_MAX: c_int = 243; + +pub const _SC_TRACE_SYS_MAX: c_int = 244; + +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; + +pub const _SC_XOPEN_STREAMS: c_int = 246; + +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; + +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; + +// limits.h +pub const PTHREAD_KEYS_MAX: c_int = 128; + +pub const PTHREAD_STACK_MIN: c_int = 2048; + +pub const PTHREAD_DESTRUCTOR_ITERATIONS: c_int = 4; + +pub const SEM_VALUE_MAX: c_int = 0x7fffffff; + +pub const SEM_NSEMS_MAX: c_int = 256; + +pub const DELAYTIMER_MAX: c_int = 0x7fffffff; + +pub const MQ_PRIO_MAX: c_int = 32768; + +pub const LOGIN_NAME_MAX: c_int = 256; + +// time.h +pub const CLOCK_REALTIME: clockid_t = 0; + +pub const CLOCK_MONOTONIC: clockid_t = 1; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], +}; + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], +}; + +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; + +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; + +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; + +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; + +pub const PTHREAD_MUTEX_STALLED: c_int = 0; + +pub const PTHREAD_MUTEX_ROBUST: c_int = 1; + +extern "C" { + // ---- ALLOC ----------------------------------------------------------------------------- + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + + pub fn malloc(size: size_t) -> *mut c_void; + + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + + pub fn aligned_alloc(align: size_t, len: size_t) -> *mut c_void; + + pub fn free(p: *mut c_void); + + pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t; + + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + // ----- PTHREAD --------------------------------------------------------------------------- + pub fn pthread_self() -> pthread_t; + + pub fn pthread_join(native: pthread_t, value: *mut *mut c_void) -> c_int; + + // detach or pthread_attr_setdetachstate must not be called! + //pub fn pthread_detach(thread: pthread_t) -> c_int; + + pub fn pthread_exit(value: *mut c_void) -> !; + + pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; + + pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int; + + pub fn pthread_attr_getstack( + attr: *const pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + + pub fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stack_size: size_t) -> c_int; + + pub fn pthread_attr_getstacksize(attr: *const pthread_attr_t, size: *mut size_t) -> c_int; + + pub fn pthread_attr_settee( + attr: *mut pthread_attr_t, + ca: c_int, + task_id: c_int, + shadow: c_int, + ) -> c_int; + + // C-TA API do not include this interface, but TA can use. + pub fn sched_yield() -> c_int; + + pub fn pthread_key_create( + key: *mut pthread_key_t, + dtor: Option, + ) -> c_int; + + pub fn pthread_key_delete(key: pthread_key_t) -> c_int; + + pub fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; + + pub fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int; + + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutex_init( + lock: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t, + ) -> c_int; + + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; + + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; + + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: c_int) -> c_int; + + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int; + + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int; + + pub fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int; + + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int; + + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_cond_timedwait( + cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const timespec, + ) -> c_int; + + pub fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robustness: c_int) -> c_int; + + pub fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_setschedprio(native: pthread_t, priority: c_int) -> c_int; + + pub fn pthread_once(pot: *mut pthread_once_t, f: Option) -> c_int; + + pub fn pthread_equal(p1: pthread_t, p2: pthread_t) -> c_int; + + pub fn pthread_mutexattr_setprotocol(a: *mut pthread_mutexattr_t, protocol: c_int) -> c_int; + + pub fn pthread_attr_setstack( + attr: *mut pthread_attr_t, + stack: *mut c_void, + size: size_t, + ) -> c_int; + + pub fn pthread_setaffinity_np(td: pthread_t, size: size_t, set: *const cpu_set_t) -> c_int; + + pub fn pthread_getaffinity_np(td: pthread_t, size: size_t, set: *mut cpu_set_t) -> c_int; + + // stdio.h + pub fn printf(fmt: *const c_char, ...) -> c_int; + + pub fn scanf(fmt: *const c_char, ...) -> c_int; + + pub fn snprintf(s: *mut c_char, n: size_t, fmt: *const c_char, ...) -> c_int; + + pub fn sprintf(s: *mut c_char, fmt: *const c_char, ...) -> c_int; + + pub fn vsnprintf(s: *mut c_char, n: size_t, fmt: *const c_char, ap: va_list) -> c_int; + + pub fn vsprintf(s: *mut c_char, fmt: *const c_char, ap: va_list) -> c_int; + + // Not available. + //pub fn pthread_setname_np(thread: pthread_t, name: *const c_char) -> c_int; + + pub fn abort() -> !; + + // Not available. + //pub fn prctl(op: c_int, ...) -> c_int; + + pub fn sched_getaffinity(pid: pid_t, cpusetsize: size_t, cpuset: *mut cpu_set_t) -> c_int; + + pub fn sched_setaffinity(pid: pid_t, cpusetsize: size_t, cpuset: *const cpu_set_t) -> c_int; + + // sysconf is currently only implemented as a stub. + pub fn sysconf(name: c_int) -> c_long; + + // mman.h + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + + // errno.h + pub fn __errno_location() -> *mut c_int; + + pub fn strerror(e: c_int) -> *mut c_char; + + // time.h + pub fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int; + + // unistd + pub fn getpid() -> pid_t; + + // time + pub fn gettimeofday(tv: *mut timeval, tz: *mut c_void) -> c_int; + + pub fn strftime( + restrict: *mut c_char, + sz: size_t, + _restrict: *const c_char, + __restrict: *const tm, + ) -> size_t; + + pub fn time(t: *mut time_t) -> time_t; + + // sem + pub fn sem_close(sem: *mut sem_t) -> c_int; + + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + + pub fn sem_getvalue(sem: *mut sem_t, valp: *mut c_int) -> c_int; + + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn sem_open(name: *const c_char, flags: c_int, ...) -> *mut sem_t; + + pub fn sem_post(sem: *mut sem_t) -> c_int; + + pub fn sem_unlink(name: *const c_char) -> c_int; + + pub fn sem_wait(sem: *mut sem_t) -> c_int; + + // locale + pub fn setlocale(cat: c_int, name: *const c_char) -> *mut c_char; + + pub fn strcoll(l: *const c_char, r: *const c_char) -> c_int; + + pub fn strxfrm(dest: *mut c_char, src: *const c_char, n: size_t) -> size_t; + + pub fn strtod(s: *const c_char, p: *mut *mut c_char) -> c_double; + + // multibyte + pub fn mbrtowc(wc: *mut wchar_t, src: *const c_char, n: size_t, st: *mut mbstate_t) -> size_t; + + pub fn wcrtomb(s: *mut c_char, wc: wchar_t, st: *mut mbstate_t) -> size_t; + + pub fn wctob(c: wint_t) -> c_int; + + // prng + pub fn srandom(seed: c_uint); + + pub fn initstate(seed: c_uint, state: *mut c_char, size: size_t) -> *mut c_char; + + pub fn setstate(state: *mut c_char) -> *mut c_char; + + pub fn random() -> c_long; + + // string + pub fn strchr(s: *const c_char, c: c_int) -> *mut c_char; + + pub fn strlen(cs: *const c_char) -> size_t; + + pub fn strcmp(l: *const c_char, r: *const c_char) -> c_int; + + pub fn strcpy(dest: *mut c_char, src: *const c_char) -> *mut c_char; + + pub fn strncmp(_l: *const c_char, r: *const c_char, n: size_t) -> c_int; + + pub fn strncpy(dest: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + + pub fn strnlen(cs: *const c_char, n: size_t) -> size_t; + + pub fn strrchr(s: *const c_char, c: c_int) -> *mut c_char; + + pub fn strstr(h: *const c_char, n: *const c_char) -> *mut c_char; + + pub fn wcschr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t; + + pub fn wcslen(s: *const wchar_t) -> size_t; + + // ctype + pub fn isalpha(c: c_int) -> c_int; + + pub fn isascii(c: c_int) -> c_int; + + pub fn isdigit(c: c_int) -> c_int; + + pub fn islower(c: c_int) -> c_int; + + pub fn isprint(c: c_int) -> c_int; + + pub fn isspace(c: c_int) -> c_int; + + pub fn iswctype(wc: wint_t, ttype: wctype_t) -> c_int; + + pub fn iswdigit(wc: wint_t) -> c_int; + + pub fn iswlower(wc: wint_t) -> c_int; + + pub fn iswspace(wc: wint_t) -> c_int; + + pub fn iswupper(wc: wint_t) -> c_int; + + pub fn towupper(wc: wint_t) -> wint_t; + + pub fn towlower(wc: wint_t) -> wint_t; + + // cmath + pub fn atan(x: c_double) -> c_double; + + pub fn ceil(x: c_double) -> c_double; + + pub fn ceilf(x: c_float) -> c_float; + + pub fn exp(x: c_double) -> c_double; + + pub fn fabs(x: c_double) -> c_double; + + pub fn floor(x: c_double) -> c_double; + + pub fn frexp(x: c_double, e: *mut c_int) -> c_double; + + pub fn log(x: c_double) -> c_double; + + pub fn log2(x: c_double) -> c_double; + + pub fn pow(x: c_double, y: c_double) -> c_double; + + pub fn roundf(x: c_float) -> c_float; + + pub fn scalbn(x: c_double, n: c_int) -> c_double; + + pub fn sqrt(x: c_double) -> c_double; + + // stdlib + pub fn abs(x: c_int) -> c_int; + + pub fn atof(s: *const c_char) -> c_double; + + pub fn atoi(s: *const c_char) -> c_int; + + pub fn atol(s: *const c_char) -> c_long; + + pub fn atoll(s: *const c_char) -> c_longlong; + + pub fn bsearch( + key: *const c_void, + base: *const c_void, + nel: size_t, + width: size_t, + cmp: cmpfunc, + ) -> *mut c_void; + + pub fn div(num: c_int, den: c_int) -> div_t; + + pub fn ecvt(x: c_double, n: c_int, dp: *mut c_int, sign: *mut c_int) -> *mut c_char; + + pub fn imaxabs(a: intmax_t) -> intmax_t; + + pub fn llabs(a: c_longlong) -> c_longlong; + + pub fn qsort(base: *mut c_void, nel: size_t, width: size_t, cmp: cmpfunc); + + pub fn strtoul(s: *const c_char, p: *mut *mut c_char, base: c_int) -> c_ulong; + + pub fn strtol(s: *const c_char, p: *mut *mut c_char, base: c_int) -> c_long; + + pub fn wcstod(s: *const wchar_t, p: *mut *mut wchar_t) -> c_double; +} + +pub fn errno() -> c_int { + unsafe { *__errno_location() } +} + +pub fn CPU_COUNT_S(size: usize, cpuset: &cpu_set_t) -> c_int { + let mut s: u32 = 0; + let size_of_mask = size_of_val(&cpuset.bits[0]); + + for i in cpuset.bits[..(size / size_of_mask)].iter() { + s += i.count_ones(); + } + s as c_int +} + +pub fn CPU_COUNT(cpuset: &cpu_set_t) -> c_int { + CPU_COUNT_S(size_of::(), cpuset) +} diff --git a/deps/crates/vendor/libc/src/trusty.rs b/deps/crates/vendor/libc/src/trusty.rs new file mode 100644 index 00000000000000..2cb2d5e13766d6 --- /dev/null +++ b/deps/crates/vendor/libc/src/trusty.rs @@ -0,0 +1,73 @@ +use crate::prelude::*; +pub type size_t = usize; +pub type ssize_t = isize; + +pub type off_t = i64; + +pub type c_uint8_t = u8; +pub type c_uint16_t = u16; +pub type c_uint32_t = u32; +pub type c_uint64_t = u64; + +pub type c_int8_t = i8; +pub type c_int16_t = i16; +pub type c_int32_t = i32; +pub type c_int64_t = i64; + +pub type intptr_t = isize; +pub type uintptr_t = usize; + +pub type time_t = c_long; + +pub type clockid_t = c_int; + +s! { + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } +} + +pub const PROT_READ: i32 = 1; +pub const PROT_WRITE: i32 = 2; + +// Trusty only supports `CLOCK_BOOTTIME`. +pub const CLOCK_BOOTTIME: clockid_t = 7; + +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; + +pub const AT_PAGESZ: c_ulong = 6; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +extern "C" { + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn close(fd: c_int) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn getauxval(type_: c_ulong) -> c_ulong; + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn nanosleep(rqtp: *const crate::timespec, rmtp: *mut crate::timespec) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/types.rs b/deps/crates/vendor/libc/src/types.rs new file mode 100644 index 00000000000000..d786d2ccb8721e --- /dev/null +++ b/deps/crates/vendor/libc/src/types.rs @@ -0,0 +1,67 @@ +//! Platform-agnostic support types. + +#[cfg(feature = "extra_traits")] +use core::hash::Hash; +use core::mem::MaybeUninit; + +use crate::prelude::*; + +/// A transparent wrapper over `MaybeUninit` to represent uninitialized padding +/// while providing `Default`. +// This is restricted to `Copy` types since that's a loose indicator that zeros is actually +// a valid bitpattern. There is no technical reason this is required, though, so it could be +// lifted in the future if it becomes a problem. +#[allow(dead_code)] +#[repr(transparent)] +#[derive(Clone, Copy)] +pub(crate) struct Padding(MaybeUninit); + +impl Default for Padding { + fn default() -> Self { + Self(MaybeUninit::zeroed()) + } +} + +impl Padding { + /// Create a `Padding` initialized with the given value. + #[allow(dead_code)] + pub(crate) const fn new(val: T) -> Self { + Self(MaybeUninit::new(val)) + } +} + +impl fmt::Debug for Padding { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Taken from `MaybeUninit`'s debug implementation + // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("Padding<{..}>"). + let full_name = core::any::type_name::(); + let prefix_len = full_name.find("Padding").unwrap(); + f.pad(&full_name[prefix_len..]) + } +} + +/// Do nothing when hashing to ignore the existence of padding fields. +#[cfg(feature = "extra_traits")] +impl Hash for Padding { + fn hash(&self, _state: &mut H) {} +} + +/// Padding fields are all equal, regardless of what is inside them, so they do not affect anything. +#[cfg(feature = "extra_traits")] +impl PartialEq for Padding { + fn eq(&self, _other: &Self) -> bool { + true + } +} + +/// Mark that `Padding` implements `Eq` so that it can be used in types that implement it. +#[cfg(feature = "extra_traits")] +impl Eq for Padding {} + +/// The default repr type used for C style enums in Rust. +#[cfg(target_env = "msvc")] +#[allow(unused)] +pub(crate) type CEnumRepr = c_int; +#[cfg(not(target_env = "msvc"))] +#[allow(unused)] +pub(crate) type CEnumRepr = c_uint; diff --git a/deps/crates/vendor/libc/src/unix/aix/mod.rs b/deps/crates/vendor/libc/src/unix/aix/mod.rs new file mode 100644 index 00000000000000..71d041f7b52f76 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/aix/mod.rs @@ -0,0 +1,3363 @@ +use crate::prelude::*; +use crate::{ + in_addr_t, + in_port_t, +}; + +pub type caddr_t = *mut c_char; +pub type clockid_t = c_longlong; +pub type blkcnt_t = c_long; +pub type clock_t = c_int; +pub type daddr_t = c_long; +pub type dev_t = c_ulong; +pub type fpos64_t = c_longlong; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulong; +pub type key_t = c_int; +pub type mode_t = c_uint; +pub type nlink_t = c_short; +pub type rlim_t = c_ulong; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type time_t = c_long; +pub type time64_t = i64; +pub type timer_t = c_long; +pub type wchar_t = c_uint; +pub type nfds_t = c_uint; +pub type projid_t = c_int; +pub type id_t = c_uint; +pub type blksize64_t = c_ulonglong; +pub type blkcnt64_t = c_ulonglong; +pub type suseconds_t = c_int; +pub type useconds_t = c_uint; +pub type off_t = c_long; +pub type offset_t = c_longlong; +pub type off64_t = c_longlong; +pub type idtype_t = c_uint; + +pub type socklen_t = c_uint; +pub type sa_family_t = c_uchar; + +pub type signal_t = c_int; +pub type pthread_t = c_uint; +pub type pthread_key_t = c_uint; +pub type thread_t = pthread_t; +pub type blksize_t = c_long; +pub type nl_item = c_int; +pub type mqd_t = c_int; +pub type shmatt_t = c_ulong; +pub type regoff_t = c_long; +pub type rlim64_t = c_ulonglong; + +pub type sem_t = c_int; +pub type pollset_t = c_int; +pub type sctp_assoc_t = c_uint; + +pub type pthread_rwlockattr_t = *mut c_void; +pub type pthread_condattr_t = *mut c_void; +pub type pthread_mutexattr_t = *mut c_void; +pub type pthread_attr_t = *mut c_void; +pub type pthread_barrierattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_char; +pub type iconv_t = *mut c_void; + +e! { + #[repr(u32)] + pub enum uio_rw { + UIO_READ = 0, + UIO_WRITE, + UIO_READ_NO_MOVE, + UIO_WRITE_NO_MOVE, + UIO_PWRITE, + } + #[repr(u32)] + pub enum ACTION { + FIND = 0, + ENTER, + } +} + +s! { + pub struct fsid_t { + pub val: [c_uint; 2], + } + + pub struct fsid64_t { + pub val: [crate::uint64_t; 2], + } + + pub struct timezone { + pub tz_minuteswest: c_int, + pub tz_dsttime: c_int, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct dirent { + pub d_offset: c_ulong, + pub d_ino: crate::ino_t, + pub d_reclen: c_ushort, + pub d_namlen: c_ushort, + pub d_name: [c_char; 256], + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_sysid: c_uint, + pub l_pid: crate::pid_t, + pub l_vfs: c_int, + pub l_start: off64_t, + pub l_len: off64_t, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, + } + + pub struct statvfs64 { + pub f_bsize: crate::blksize64_t, + pub f_frsize: crate::blksize64_t, + pub f_blocks: crate::blkcnt64_t, + pub f_bfree: crate::blkcnt64_t, + pub f_bavail: crate::blkcnt64_t, + pub f_files: crate::blkcnt64_t, + pub f_ffree: crate::blkcnt64_t, + pub f_favail: crate::blkcnt64_t, + pub f_fsid: fsid64_t, + pub f_basetype: [c_char; 16], + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub f_fstr: [c_char; 32], + pub f_filler: [c_ulong; 16], + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub left_parenthesis: *mut c_char, + pub right_parenthesis: *mut c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: c_ulong, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + pub ai_eflags: c_int, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_sourceaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_len: c_uchar, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 120], + } + + pub struct sockaddr_in { + pub sin_len: c_uchar, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [c_uchar; 8], + } + + pub struct sockaddr_in6 { + pub sin6_len: c_uchar, + pub sin6_family: c_uchar, + pub sin6_port: crate::uint16_t, + pub sin6_flowinfo: crate::uint32_t, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: crate::uint32_t, + } + + pub struct sockaddr_storage { + pub __ss_len: c_uchar, + pub ss_family: sa_family_t, + __ss_pad1: Padding<[c_char; 6]>, + __ss_align: crate::int64_t, + __ss_pad2: Padding<[c_char; 1265]>, + } + + pub struct sockaddr_un { + pub sun_len: c_uchar, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 1023], + } + + pub struct st_timespec { + pub tv_sec: crate::time_t, + pub tv_nsec: c_int, + } + + pub struct statfs64 { + pub f_version: c_int, + pub f_type: c_int, + pub f_bsize: blksize64_t, + pub f_blocks: blkcnt64_t, + pub f_bfree: blkcnt64_t, + pub f_bavail: blkcnt64_t, + pub f_files: crate::uint64_t, + pub f_ffree: crate::uint64_t, + pub f_fsid: fsid64_t, + pub f_vfstype: c_int, + pub f_fsize: blksize64_t, + pub f_vfsnumber: c_int, + pub f_vfsoff: c_int, + pub f_vfslen: c_int, + pub f_vfsvers: c_int, + pub f_fname: [c_char; 32], + pub f_fpack: [c_char; 32], + pub f_name_max: c_int, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct utsname { + pub sysname: [c_char; 32], + pub nodename: [c_char; 32], + pub release: [c_char; 32], + pub version: [c_char; 32], + pub machine: [c_char; 32], + } + + pub struct xutsname { + pub nid: c_uint, + reserved: Padding, + pub longnid: c_ulonglong, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigevent { + pub sigev_value: crate::sigval, + pub sigev_signo: c_int, + pub sigev_notify: c_int, + pub sigev_notify_function: extern "C" fn(val: crate::sigval), + pub sigev_notify_attributes: *mut pthread_attr_t, + } + + pub struct osigevent { + pub sevt_value: *mut c_void, + pub sevt_signo: signal_t, + } + + pub struct poll_ctl { + pub cmd: c_short, + pub events: c_short, + pub fd: c_int, + } + + pub struct sf_parms { + pub header_data: *mut c_void, + pub header_length: c_uint, + pub file_descriptor: c_int, + pub file_size: crate::uint64_t, + pub file_offset: crate::uint64_t, + pub file_bytes: crate::int64_t, + pub trailer_data: *mut c_void, + pub trailer_length: c_uint, + pub bytes_sent: crate::uint64_t, + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } + + pub struct sched_param { + pub sched_priority: c_int, + pub sched_policy: c_int, + sched_reserved: Padding<[c_int; 6]>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + pub __pad: [c_int; 4], + } + + pub struct posix_spawnattr_t { + pub posix_attr_flags: c_short, + pub posix_attr_pgroup: crate::pid_t, + pub posix_attr_sigmask: crate::sigset_t, + pub posix_attr_sigdefault: crate::sigset_t, + pub posix_attr_schedpolicy: c_int, + pub posix_attr_schedparam: sched_param, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_padr: *mut c_void, + pub gl_ptx: *mut c_void, + } + + pub struct mallinfo { + pub arena: c_ulong, + pub ordblks: c_int, + pub smblks: c_int, + pub hblks: c_int, + pub hblkhd: c_int, + pub usmblks: c_ulong, + pub fsmblks: c_ulong, + pub uordblks: c_ulong, + pub fordblks: c_ulong, + pub keepcost: c_int, + } + + pub struct exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct utmp { + pub ut_user: [c_char; 256], + pub ut_id: [c_char; 14], + pub ut_line: [c_char; 64], + pub ut_pid: crate::pid_t, + pub ut_type: c_short, + pub ut_time: time64_t, + pub ut_exit: exit_status, + pub ut_host: [c_char; 256], + pub __dbl_word_pad: c_int, + pub __reservedA: [c_int; 2], + pub __reservedV: [c_int; 6], + } + + pub struct regmatch_t { + pub rm_so: regoff_t, + pub rm_eo: regoff_t, + } + + pub struct regex_t { + pub re_nsub: size_t, + pub re_comp: *mut c_void, + pub re_cflags: c_int, + pub re_erroff: size_t, + pub re_len: size_t, + pub re_ucoll: [crate::wchar_t; 2], + pub re_lsub: [*mut c_void; 24], + pub re_esub: [*mut c_void; 24], + pub re_map: *mut c_uchar, + pub __maxsub: c_int, + __unused: Padding<[*mut c_void; 34]>, + } + + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct shmid_ds { + pub shm_perm: ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: shmatt_t, + pub shm_cnattch: shmatt_t, + pub shm_atime: time_t, + pub shm_dtime: time_t, + pub shm_ctime: time_t, + pub shm_handle: crate::uint32_t, + pub shm_extshm: c_int, + pub shm_pagesize: crate::int64_t, + pub shm_lba: crate::uint64_t, + shm_reserved0: Padding, + shm_reserved1: Padding, + } + + pub struct stat64 { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_flag: c_ushort, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: dev_t, + pub st_ssize: c_int, + pub st_atim: st_timespec, + pub st_mtim: st_timespec, + pub st_ctim: st_timespec, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_vfstype: c_int, + pub st_vfs: c_uint, + pub st_type: c_uint, + pub st_gen: c_uint, + st_reserved: Padding<[c_uint; 10]>, + pub st_size: off64_t, + } + + pub struct mntent { + pub mnt_fsname: *mut c_char, + pub mnt_dir: *mut c_char, + pub mnt_type: *mut c_char, + pub mnt_opts: *mut c_char, + pub mnt_freq: c_int, + pub mnt_passno: c_int, + } + + pub struct ipc_perm { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + pub seq: c_ushort, + __reserved: Padding, + pub key: key_t, + } + + pub struct entry { + pub key: *mut c_char, + pub data: *mut c_void, + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, // FIXME(union): this field is actually a union + pub sa_mask: sigset_t, + pub sa_flags: c_int, + } + + pub struct poll_ctl_ext { + pub version: u8, + pub command: u8, + pub events: c_short, + pub fd: c_int, + pub u: __poll_ctl_ext_u, + reserved64: Padding<[u64; 6]>, + } +} + +s_no_extra_traits! { + pub union __poll_ctl_ext_u { + pub addr: *mut c_void, + pub data32: u32, + pub data: u64, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __poll_ctl_ext_u { + fn eq(&self, other: &__poll_ctl_ext_u) -> bool { + unsafe { + self.addr == other.addr + && self.data32 == other.data32 + && self.data == other.data + } + } + } + impl Eq for __poll_ctl_ext_u {} + impl hash::Hash for __poll_ctl_ext_u { + fn hash(&self, state: &mut H) { + unsafe { + self.addr.hash(state); + self.data32.hash(state); + self.data.hash(state); + } + } + } + } +} + +// dlfcn.h +pub const RTLD_LAZY: c_int = 0x4; +pub const RTLD_NOW: c_int = 0x2; +pub const RTLD_GLOBAL: c_int = 0x10000; +pub const RTLD_LOCAL: c_int = 0x80000; +pub const RTLD_MEMBER: c_int = 0x40000; +pub const RTLD_NOAUTODEFER: c_int = 0x20000; +pub const RTLD_DEFAULT: *mut c_void = -1isize as *mut c_void; +pub const RTLD_MYSELF: *mut c_void = -2isize as *mut c_void; +pub const RTLD_NEXT: *mut c_void = -3isize as *mut c_void; + +// fcntl.h +pub const O_RDONLY: c_int = 0x0; +pub const O_WRONLY: c_int = 0x1; +pub const O_RDWR: c_int = 0x2; +pub const O_NDELAY: c_int = 0x8000; +pub const O_APPEND: c_int = 0x8; +pub const O_DSYNC: c_int = 0x400000; +pub const O_CREAT: c_int = 0x100; +pub const O_EXCL: c_int = 0x400; +pub const O_NOCTTY: c_int = 0x800; +pub const O_TRUNC: c_int = 0x200; +pub const O_NOFOLLOW: c_int = 0x1000000; +pub const O_DIRECTORY: c_int = 0x80000; +pub const O_SEARCH: c_int = 0x20; +pub const O_EXEC: c_int = 0x20; +pub const O_CLOEXEC: c_int = 0x800000; +pub const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH; +pub const O_DIRECT: c_int = 0x8000000; +pub const O_TTY_INIT: c_int = 0; +pub const O_RSYNC: c_int = 0x200000; +pub const O_LARGEFILE: c_int = 0x4000000; +pub const F_DUPFD: c_int = 0; +pub const F_DUPFD_CLOEXEC: c_int = 16; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETLK: c_int = F_GETLK64; +pub const F_SETLK: c_int = F_SETLK64; +pub const F_SETLKW: c_int = F_SETLKW64; +pub const F_GETOWN: c_int = 8; +pub const F_SETOWN: c_int = 9; +pub const F_CLOSEM: c_int = 10; +pub const F_GETLK64: c_int = 11; +pub const F_SETLK64: c_int = 12; +pub const F_SETLKW64: c_int = 13; +pub const F_DUP2FD: c_int = 14; +pub const F_TSTLK: c_int = 15; +pub const AT_FDCWD: c_int = -2; +pub const AT_SYMLINK_NOFOLLOW: c_int = 1; +pub const AT_SYMLINK_FOLLOW: c_int = 2; +pub const AT_REMOVEDIR: c_int = 1; +pub const AT_EACCESS: c_int = 1; +pub const O_SYNC: c_int = 16; +pub const O_NONBLOCK: c_int = 4; +pub const FASYNC: c_int = 0x20000; +pub const POSIX_FADV_NORMAL: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_RANDOM: c_int = 3; +pub const POSIX_FADV_WILLNEED: c_int = 4; +pub const POSIX_FADV_DONTNEED: c_int = 5; +pub const POSIX_FADV_NOREUSE: c_int = 6; + +// glob.h +pub const GLOB_APPEND: c_int = 0x1; +pub const GLOB_DOOFFS: c_int = 0x2; +pub const GLOB_ERR: c_int = 0x4; +pub const GLOB_MARK: c_int = 0x8; +pub const GLOB_NOCHECK: c_int = 0x10; +pub const GLOB_NOSORT: c_int = 0x20; +pub const GLOB_NOESCAPE: c_int = 0x80; +pub const GLOB_NOSPACE: c_int = 0x2000; +pub const GLOB_ABORTED: c_int = 0x1000; +pub const GLOB_NOMATCH: c_int = 0x4000; +pub const GLOB_NOSYS: c_int = 0x8000; + +// langinfo.h +pub const DAY_1: crate::nl_item = 13; +pub const DAY_2: crate::nl_item = 14; +pub const DAY_3: crate::nl_item = 15; +pub const DAY_4: crate::nl_item = 16; +pub const DAY_5: crate::nl_item = 17; +pub const DAY_6: crate::nl_item = 18; +pub const DAY_7: crate::nl_item = 19; +pub const ABDAY_1: crate::nl_item = 6; +pub const ABDAY_2: crate::nl_item = 7; +pub const ABDAY_3: crate::nl_item = 8; +pub const ABDAY_4: crate::nl_item = 9; +pub const ABDAY_5: crate::nl_item = 10; +pub const ABDAY_6: crate::nl_item = 11; +pub const ABDAY_7: crate::nl_item = 12; +pub const MON_1: crate::nl_item = 32; +pub const MON_2: crate::nl_item = 33; +pub const MON_3: crate::nl_item = 34; +pub const MON_4: crate::nl_item = 35; +pub const MON_5: crate::nl_item = 36; +pub const MON_6: crate::nl_item = 37; +pub const MON_7: crate::nl_item = 38; +pub const MON_8: crate::nl_item = 39; +pub const MON_9: crate::nl_item = 40; +pub const MON_10: crate::nl_item = 41; +pub const MON_11: crate::nl_item = 42; +pub const MON_12: crate::nl_item = 43; +pub const ABMON_1: crate::nl_item = 20; +pub const ABMON_2: crate::nl_item = 21; +pub const ABMON_3: crate::nl_item = 22; +pub const ABMON_4: crate::nl_item = 23; +pub const ABMON_5: crate::nl_item = 24; +pub const ABMON_6: crate::nl_item = 25; +pub const ABMON_7: crate::nl_item = 26; +pub const ABMON_8: crate::nl_item = 27; +pub const ABMON_9: crate::nl_item = 28; +pub const ABMON_10: crate::nl_item = 29; +pub const ABMON_11: crate::nl_item = 30; +pub const ABMON_12: crate::nl_item = 31; +pub const RADIXCHAR: crate::nl_item = 44; +pub const THOUSEP: crate::nl_item = 45; +pub const YESSTR: crate::nl_item = 46; +pub const NOSTR: crate::nl_item = 47; +pub const CRNCYSTR: crate::nl_item = 48; +pub const D_T_FMT: crate::nl_item = 1; +pub const D_FMT: crate::nl_item = 2; +pub const T_FMT: crate::nl_item = 3; +pub const AM_STR: crate::nl_item = 4; +pub const PM_STR: crate::nl_item = 5; +pub const CODESET: crate::nl_item = 49; +pub const T_FMT_AMPM: crate::nl_item = 55; +pub const ERA: crate::nl_item = 56; +pub const ERA_D_FMT: crate::nl_item = 57; +pub const ERA_D_T_FMT: crate::nl_item = 58; +pub const ERA_T_FMT: crate::nl_item = 59; +pub const ALT_DIGITS: crate::nl_item = 60; +pub const YESEXPR: crate::nl_item = 61; +pub const NOEXPR: crate::nl_item = 62; + +// locale.h +pub const LC_GLOBAL_LOCALE: crate::locale_t = -1isize as crate::locale_t; +pub const LC_COLLATE: c_int = 0; +pub const LC_CTYPE: c_int = 1; +pub const LC_MONETARY: c_int = 2; +pub const LC_NUMERIC: c_int = 3; +pub const LC_TIME: c_int = 4; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = -1; +pub const LC_COLLATE_MASK: c_int = 1; +pub const LC_CTYPE_MASK: c_int = 2; +pub const LC_MESSAGES_MASK: c_int = 4; +pub const LC_MONETARY_MASK: c_int = 8; +pub const LC_NUMERIC_MASK: c_int = 16; +pub const LC_TIME_MASK: c_int = 32; +pub const LC_ALL_MASK: c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +// netdb.h +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const NI_MAXSERV: crate::socklen_t = 32; +pub const NI_NOFQDN: crate::socklen_t = 0x1; +pub const NI_NUMERICHOST: crate::socklen_t = 0x2; +pub const NI_NAMEREQD: crate::socklen_t = 0x4; +pub const NI_NUMERICSERV: crate::socklen_t = 0x8; +pub const NI_DGRAM: crate::socklen_t = 0x10; +pub const NI_NUMERICSCOPE: crate::socklen_t = 0x40; +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 13; +pub const AI_CANONNAME: c_int = 0x01; +pub const AI_PASSIVE: c_int = 0x02; +pub const AI_NUMERICHOST: c_int = 0x04; +pub const AI_ADDRCONFIG: c_int = 0x08; +pub const AI_V4MAPPED: c_int = 0x10; +pub const AI_ALL: c_int = 0x20; +pub const AI_NUMERICSERV: c_int = 0x40; +pub const AI_EXTFLAGS: c_int = 0x80; +pub const AI_DEFAULT: c_int = AI_V4MAPPED | AI_ADDRCONFIG; +pub const IPV6_ADDRFORM: c_int = 22; +pub const IPV6_ADDR_PREFERENCES: c_int = 74; +pub const IPV6_CHECKSUM: c_int = 39; +pub const IPV6_DONTFRAG: c_int = 45; +pub const IPV6_DSTOPTS: c_int = 54; +pub const IPV6_FLOWINFO_FLOWLABEL: c_int = 0x00ffffff; +pub const IPV6_FLOWINFO_PRIORITY: c_int = 0x0f000000; +pub const IPV6_FLOWINFO_PRIFLOW: c_int = 0x0fffffff; +pub const IPV6_FLOWINFO_SRFLAG: c_int = 0x10000000; +pub const IPV6_FLOWINFO_VERSION: c_int = 0xf0000000; +pub const IPV6_HOPLIMIT: c_int = 40; +pub const IPV6_HOPOPTS: c_int = 52; +pub const IPV6_NEXTHOP: c_int = 48; +pub const IPV6_PATHMTU: c_int = 46; +pub const IPV6_PKTINFO: c_int = 33; +pub const IPV6_PREFER_SRC_CGA: c_int = 16; +pub const IPV6_PREFER_SRC_COA: c_int = 2; +pub const IPV6_PREFER_SRC_HOME: c_int = 1; +pub const IPV6_PREFER_SRC_NONCGA: c_int = 32; +pub const IPV6_PREFER_SRC_PUBLIC: c_int = 4; +pub const IPV6_PREFER_SRC_TMP: c_int = 8; +pub const IPV6_RECVDSTOPTS: c_int = 56; +pub const IPV6_RECVHOPLIMIT: c_int = 41; +pub const IPV6_RECVHOPOPTS: c_int = 53; +pub const IPV6_RECVPATHMTU: c_int = 47; +pub const IPV6_RECVRTHDR: c_int = 51; +pub const IPV6_RECVTCLASS: c_int = 42; +pub const IPV6_RTHDR: c_int = 50; +pub const IPV6_RTHDRDSTOPTS: c_int = 55; +pub const IPV6_TCLASS: c_int = 43; + +// net/bpf.h +pub const DLT_NULL: c_int = 0x18; +pub const DLT_EN10MB: c_int = 0x6; +pub const DLT_EN3MB: c_int = 0x1a; +pub const DLT_AX25: c_int = 0x5; +pub const DLT_PRONET: c_int = 0xd; +pub const DLT_IEEE802: c_int = 0x7; +pub const DLT_ARCNET: c_int = 0x23; +pub const DLT_SLIP: c_int = 0x1c; +pub const DLT_PPP: c_int = 0x17; +pub const DLT_FDDI: c_int = 0xf; +pub const DLT_ATM: c_int = 0x25; +pub const DLT_IPOIB: c_int = 0xc7; +pub const BIOCSETF: c_int = 0x80104267; +pub const BIOCGRTIMEOUT: c_int = 0x4010426e; +pub const BIOCGBLEN: c_int = 0x40044266; +pub const BIOCSBLEN: c_int = 0xc0044266; +pub const BIOCFLUSH: c_int = 0x20004268; +pub const BIOCPROMISC: c_int = 0x20004269; +pub const BIOCGDLT: c_int = 0x4004426a; +pub const BIOCSRTIMEOUT: c_int = 0x8010426d; +pub const BIOCGSTATS: c_int = 0x4008426f; +pub const BIOCIMMEDIATE: c_int = 0x80044270; +pub const BIOCVERSION: c_int = 0x40044271; +pub const BIOCSDEVNO: c_int = 0x20004272; +pub const BIOCGETIF: c_int = 0x4020426b; +pub const BIOCSETIF: c_int = 0x8020426c; +pub const BPF_ABS: c_int = 32; +pub const BPF_ADD: c_int = 0; +pub const BPF_ALIGNMENT: c_ulong = 4; +pub const BPF_ALU: c_int = 4; +pub const BPF_AND: c_int = 80; +pub const BPF_B: c_int = 16; +pub const BPF_DIV: c_int = 48; +pub const BPF_H: c_int = 8; +pub const BPF_IMM: c_int = 0; +pub const BPF_IND: c_int = 64; +pub const BPF_JA: c_int = 0; +pub const BPF_JEQ: c_int = 16; +pub const BPF_JGE: c_int = 48; +pub const BPF_JGT: c_int = 32; +pub const BPF_JMP: c_int = 5; +pub const BPF_JSET: c_int = 64; +pub const BPF_K: c_int = 0; +pub const BPF_LD: c_int = 0; +pub const BPF_LDX: c_int = 1; +pub const BPF_LEN: c_int = 128; +pub const BPF_LSH: c_int = 96; +pub const BPF_MAXINSNS: c_int = 512; +pub const BPF_MEM: c_int = 96; +pub const BPF_MEMWORDS: c_int = 16; +pub const BPF_MISC: c_int = 7; +pub const BPF_MSH: c_int = 160; +pub const BPF_MUL: c_int = 32; +pub const BPF_NEG: c_int = 128; +pub const BPF_OR: c_int = 64; +pub const BPF_RET: c_int = 6; +pub const BPF_RSH: c_int = 112; +pub const BPF_ST: c_int = 2; +pub const BPF_STX: c_int = 3; +pub const BPF_SUB: c_int = 16; +pub const BPF_W: c_int = 0; +pub const BPF_X: c_int = 8; + +// net/if.h +pub const IFNET_SLOWHZ: c_int = 1; +pub const IFQ_MAXLEN: c_int = 50; +pub const IFF_UP: c_int = 0x1; +pub const IFF_BROADCAST: c_int = 0x2; +pub const IFF_DEBUG: c_int = 0x4; +pub const IFF_LOOPBACK: c_int = 0x8; +pub const IFF_POINTOPOINT: c_int = 0x10; +pub const IFF_NOTRAILERS: c_int = 0x20; +pub const IFF_RUNNING: c_int = 0x40; +pub const IFF_NOARP: c_int = 0x80; +pub const IFF_PROMISC: c_int = 0x100; +pub const IFF_ALLMULTI: c_int = 0x200; +pub const IFF_MULTICAST: c_int = 0x80000; +pub const IFF_LINK0: c_int = 0x100000; +pub const IFF_LINK1: c_int = 0x200000; +pub const IFF_LINK2: c_int = 0x400000; +pub const IFF_OACTIVE: c_int = 0x400; +pub const IFF_SIMPLEX: c_int = 0x800; + +// net/if_arp.h +pub const ARPHRD_ETHER: c_int = 1; +pub const ARPHRD_802_5: c_int = 6; +pub const ARPHRD_802_3: c_int = 6; +pub const ARPHRD_FDDI: c_int = 1; + +// net/route.h +pub const RTM_ADD: c_int = 0x1; +pub const RTM_DELETE: c_int = 0x2; +pub const RTM_CHANGE: c_int = 0x3; +pub const RTM_GET: c_int = 0x4; +pub const RTM_LOSING: c_int = 0x5; +pub const RTM_REDIRECT: c_int = 0x6; +pub const RTM_MISS: c_int = 0x7; +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_OLDADD: c_int = 0x9; +pub const RTM_OLDDEL: c_int = 0xa; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_EXPIRE: c_int = 0xf; +pub const RTM_RTLOST: c_int = 0x10; +pub const RTM_GETNEXT: c_int = 0x11; +pub const RTM_SAMEADDR: c_int = 0x12; +pub const RTM_SET: c_int = 0x13; +pub const RTV_MTU: c_int = 0x1; +pub const RTV_HOPCOUNT: c_int = 0x2; +pub const RTV_EXPIRE: c_int = 0x4; +pub const RTV_RPIPE: c_int = 0x8; +pub const RTV_SPIPE: c_int = 0x10; +pub const RTV_SSTHRESH: c_int = 0x20; +pub const RTV_RTT: c_int = 0x40; +pub const RTV_RTTVAR: c_int = 0x80; +pub const RTA_DST: c_int = 0x1; +pub const RTA_GATEWAY: c_int = 0x2; +pub const RTA_NETMASK: c_int = 0x4; +pub const RTA_GENMASK: c_int = 0x8; +pub const RTA_IFP: c_int = 0x10; +pub const RTA_IFA: c_int = 0x20; +pub const RTA_AUTHOR: c_int = 0x40; +pub const RTA_BRD: c_int = 0x80; +pub const RTA_DOWNSTREAM: c_int = 0x100; +pub const RTAX_DST: c_int = 0; +pub const RTAX_GATEWAY: c_int = 1; +pub const RTAX_NETMASK: c_int = 2; +pub const RTAX_GENMASK: c_int = 3; +pub const RTAX_IFP: c_int = 4; +pub const RTAX_IFA: c_int = 5; +pub const RTAX_AUTHOR: c_int = 6; +pub const RTAX_BRD: c_int = 7; +pub const RTAX_MAX: c_int = 8; +pub const RTF_UP: c_int = 0x1; +pub const RTF_GATEWAY: c_int = 0x2; +pub const RTF_HOST: c_int = 0x4; +pub const RTF_REJECT: c_int = 0x8; +pub const RTF_DYNAMIC: c_int = 0x10; +pub const RTF_MODIFIED: c_int = 0x20; +pub const RTF_DONE: c_int = 0x40; +pub const RTF_MASK: c_int = 0x80; +pub const RTF_CLONING: c_int = 0x100; +pub const RTF_XRESOLVE: c_int = 0x200; +pub const RTF_LLINFO: c_int = 0x400; +pub const RTF_STATIC: c_int = 0x800; +pub const RTF_BLACKHOLE: c_int = 0x1000; +pub const RTF_BUL: c_int = 0x2000; +pub const RTF_PROTO2: c_int = 0x4000; +pub const RTF_PROTO1: c_int = 0x8000; +pub const RTF_CLONE: c_int = 0x10000; +pub const RTF_CLONED: c_int = 0x20000; +pub const RTF_PROTO3: c_int = 0x40000; +pub const RTF_BCE: c_int = 0x80000; +pub const RTF_PINNED: c_int = 0x100000; +pub const RTF_LOCAL: c_int = 0x200000; +pub const RTF_BROADCAST: c_int = 0x400000; +pub const RTF_MULTICAST: c_int = 0x800000; +pub const RTF_ACTIVE_DGD: c_int = 0x1000000; +pub const RTF_STOPSRCH: c_int = 0x2000000; +pub const RTF_FREE_IN_PROG: c_int = 0x4000000; +pub const RTF_PERMANENT6: c_int = 0x8000000; +pub const RTF_UNREACHABLE: c_int = 0x10000000; +pub const RTF_CACHED: c_int = 0x20000000; +pub const RTF_SMALLMTU: c_int = 0x40000; + +// netinet/in.h +pub const IPPROTO_HOPOPTS: c_int = 0; +pub const IPPROTO_IGMP: c_int = 2; +pub const IPPROTO_GGP: c_int = 3; +pub const IPPROTO_IPIP: c_int = 4; +pub const IPPROTO_EGP: c_int = 8; +pub const IPPROTO_PUP: c_int = 12; +pub const IPPROTO_IDP: c_int = 22; +pub const IPPROTO_TP: c_int = 29; +pub const IPPROTO_ROUTING: c_int = 43; +pub const IPPROTO_FRAGMENT: c_int = 44; +pub const IPPROTO_QOS: c_int = 45; +pub const IPPROTO_RSVP: c_int = 46; +pub const IPPROTO_GRE: c_int = 47; +pub const IPPROTO_ESP: c_int = 50; +pub const IPPROTO_AH: c_int = 51; +pub const IPPROTO_NONE: c_int = 59; +pub const IPPROTO_DSTOPTS: c_int = 60; +pub const IPPROTO_LOCAL: c_int = 63; +pub const IPPROTO_EON: c_int = 80; +pub const IPPROTO_BIP: c_int = 0x53; +pub const IPPROTO_SCTP: c_int = 132; +pub const IPPROTO_MH: c_int = 135; +pub const IPPROTO_GIF: c_int = 140; +pub const IPPROTO_RAW: c_int = 255; +pub const IP_OPTIONS: c_int = 1; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_UNICAST_HOPS: c_int = 4; +pub const IP_RECVOPTS: c_int = 5; +pub const IP_RECVRETOPTS: c_int = 6; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_RETOPTS: c_int = 8; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_HOPS: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_RECVMACHDR: c_int = 14; +pub const IP_RECVIFINFO: c_int = 15; +pub const IP_BROADCAST_IF: c_int = 16; +pub const IP_DHCPMODE: c_int = 17; +pub const IP_RECVIF: c_int = 20; +pub const IP_ADDRFORM: c_int = 22; +pub const IP_DONTFRAG: c_int = 25; +pub const IP_FINDPMTU: c_int = 26; +pub const IP_PMTUAGE: c_int = 27; +pub const IP_RECVINTERFACE: c_int = 32; +pub const IP_RECVTTL: c_int = 34; +pub const IP_BLOCK_SOURCE: c_int = 58; +pub const IP_UNBLOCK_SOURCE: c_int = 59; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 60; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 61; +pub const IP_DEFAULT_MULTICAST_TTL: c_int = 1; +pub const IP_DEFAULT_MULTICAST_LOOP: c_int = 1; +pub const IP_INC_MEMBERSHIPS: c_int = 20; +pub const IP_INIT_MEMBERSHIP: c_int = 20; +pub const IPV6_UNICAST_HOPS: c_int = IP_TTL; +pub const IPV6_MULTICAST_IF: c_int = IP_MULTICAST_IF; +pub const IPV6_MULTICAST_HOPS: c_int = IP_MULTICAST_TTL; +pub const IPV6_MULTICAST_LOOP: c_int = IP_MULTICAST_LOOP; +pub const IPV6_RECVPKTINFO: c_int = 35; +pub const IPV6_V6ONLY: c_int = 37; +pub const IPV6_ADD_MEMBERSHIP: c_int = IP_ADD_MEMBERSHIP; +pub const IPV6_DROP_MEMBERSHIP: c_int = IP_DROP_MEMBERSHIP; +pub const IPV6_JOIN_GROUP: c_int = IP_ADD_MEMBERSHIP; +pub const IPV6_LEAVE_GROUP: c_int = IP_DROP_MEMBERSHIP; +pub const MCAST_BLOCK_SOURCE: c_int = 64; +pub const MCAST_EXCLUDE: c_int = 2; +pub const MCAST_INCLUDE: c_int = 1; +pub const MCAST_JOIN_GROUP: c_int = 62; +pub const MCAST_JOIN_SOURCE_GROUP: c_int = 66; +pub const MCAST_LEAVE_GROUP: c_int = 63; +pub const MCAST_LEAVE_SOURCE_GROUP: c_int = 67; +pub const MCAST_UNBLOCK_SOURCE: c_int = 65; + +// netinet/ip.h +pub const MAXTTL: c_int = 255; +pub const IPDEFTTL: c_int = 64; +pub const IPOPT_CONTROL: c_int = 0; +pub const IPOPT_EOL: c_int = 0; +pub const IPOPT_LSRR: c_int = 131; +pub const IPOPT_MINOFF: c_int = 4; +pub const IPOPT_NOP: c_int = 1; +pub const IPOPT_OFFSET: c_int = 2; +pub const IPOPT_OLEN: c_int = 1; +pub const IPOPT_OPTVAL: c_int = 0; +pub const IPOPT_RESERVED1: c_int = 0x20; +pub const IPOPT_RESERVED2: c_int = 0x60; +pub const IPOPT_RR: c_int = 7; +pub const IPOPT_SSRR: c_int = 137; +pub const IPOPT_TS: c_int = 68; +pub const IPOPT_TS_PRESPEC: c_int = 3; +pub const IPOPT_TS_TSANDADDR: c_int = 1; +pub const IPOPT_TS_TSONLY: c_int = 0; +pub const IPTOS_LOWDELAY: c_int = 16; +pub const IPTOS_PREC_CRITIC_ECP: c_int = 160; +pub const IPTOS_PREC_FLASH: c_int = 96; +pub const IPTOS_PREC_FLASHOVERRIDE: c_int = 128; +pub const IPTOS_PREC_IMMEDIATE: c_int = 64; +pub const IPTOS_PREC_INTERNETCONTROL: c_int = 192; +pub const IPTOS_PREC_NETCONTROL: c_int = 224; +pub const IPTOS_PREC_PRIORITY: c_int = 32; +pub const IPTOS_PREC_ROUTINE: c_int = 16; +pub const IPTOS_RELIABILITY: c_int = 4; +pub const IPTOS_THROUGHPUT: c_int = 8; +pub const IPVERSION: c_int = 4; + +// netinet/tcp.h +pub const TCP_NODELAY: c_int = 0x1; +pub const TCP_MAXSEG: c_int = 0x2; +pub const TCP_RFC1323: c_int = 0x4; +pub const TCP_KEEPALIVE: c_int = 0x8; +pub const TCP_KEEPIDLE: c_int = 0x11; +pub const TCP_KEEPINTVL: c_int = 0x12; +pub const TCP_KEEPCNT: c_int = 0x13; +pub const TCP_NODELAYACK: c_int = 0x14; + +// pthread.h +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = 2; +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; +pub const PTHREAD_PROCESS_SHARED: c_int = 0; +pub const PTHREAD_PROCESS_PRIVATE: c_ushort = 1; +pub const PTHREAD_STACK_MIN: size_t = PAGESIZE as size_t * 4; +pub const PTHREAD_MUTEX_NORMAL: c_int = 5; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 3; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 4; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_MUTEX_ROBUST: c_int = 1; +pub const PTHREAD_MUTEX_STALLED: c_int = 0; +pub const PTHREAD_PRIO_INHERIT: c_int = 3; +pub const PTHREAD_PRIO_NONE: c_int = 1; +pub const PTHREAD_PRIO_PROTECT: c_int = 2; + +// regex.h +pub const REG_EXTENDED: c_int = 1; +pub const REG_ICASE: c_int = 2; +pub const REG_NEWLINE: c_int = 4; +pub const REG_NOSUB: c_int = 8; +pub const REG_NOTBOL: c_int = 0x100; +pub const REG_NOTEOL: c_int = 0x200; +pub const REG_NOMATCH: c_int = 1; +pub const REG_BADPAT: c_int = 2; +pub const REG_ECOLLATE: c_int = 3; +pub const REG_ECTYPE: c_int = 4; +pub const REG_EESCAPE: c_int = 5; +pub const REG_ESUBREG: c_int = 6; +pub const REG_EBRACK: c_int = 7; +pub const REG_EPAREN: c_int = 8; +pub const REG_EBRACE: c_int = 9; +pub const REG_BADBR: c_int = 10; +pub const REG_ERANGE: c_int = 11; +pub const REG_ESPACE: c_int = 12; +pub const REG_BADRPT: c_int = 13; +pub const REG_ECHAR: c_int = 14; +pub const REG_EBOL: c_int = 15; +pub const REG_EEOL: c_int = 16; +pub const REG_ENOSYS: c_int = 17; + +// rpcsvc/mount.h +pub const NFSMNT_SOFT: c_int = 0x001; +pub const NFSMNT_WSIZE: c_int = 0x002; +pub const NFSMNT_RSIZE: c_int = 0x004; +pub const NFSMNT_TIMEO: c_int = 0x008; +pub const NFSMNT_RETRANS: c_int = 0x010; +pub const NFSMNT_HOSTNAME: c_int = 0x020; +pub const NFSMNT_INT: c_int = 0x040; +pub const NFSMNT_NOAC: c_int = 0x080; +pub const NFSMNT_ACREGMIN: c_int = 0x0100; +pub const NFSMNT_ACREGMAX: c_int = 0x0200; +pub const NFSMNT_ACDIRMIN: c_int = 0x0400; +pub const NFSMNT_ACDIRMAX: c_int = 0x0800; + +// rpcsvc/rstat.h +pub const CPUSTATES: c_int = 4; + +// semaphore.h +pub const SEM_FAILED: *mut sem_t = -1isize as *mut crate::sem_t; + +// spawn.h +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x1; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x2; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x4; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x8; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x10; +pub const POSIX_SPAWN_RESETIDS: c_int = 0x20; +pub const POSIX_SPAWN_FORK_HANDLERS: c_int = 0x1000; + +// stdio.h +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0o000; +pub const _IONBF: c_int = 0o004; +pub const _IOLBF: c_int = 0o100; +pub const BUFSIZ: c_uint = 4096; +pub const FOPEN_MAX: c_uint = 32767; +pub const FILENAME_MAX: c_uint = 255; +pub const L_tmpnam: c_uint = 21; +pub const TMP_MAX: c_uint = 16384; + +// stdlib.h +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 32767; + +// sys/access.h +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; + +// sys/aio.h +pub const LIO_NOP: c_int = 0; +pub const LIO_READ: c_int = 1; +pub const LIO_WRITE: c_int = 2; +pub const LIO_NOWAIT: c_int = 0; +pub const LIO_WAIT: c_int = 1; +pub const AIO_ALLDONE: c_int = 2; +pub const AIO_CANCELED: c_int = 0; +pub const AIO_NOTCANCELED: c_int = 1; + +// sys/errno.h +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EDEADLK: c_int = 45; +pub const ENOTREADY: c_int = 46; +pub const EWRPROTECT: c_int = 47; +pub const EFORMAT: c_int = 48; +pub const ENOLCK: c_int = 49; +pub const ENOCONNECT: c_int = 50; +pub const ESTALE: c_int = 52; +pub const EDIST: c_int = 53; +// POSIX allows EWOULDBLOCK to be the same value as EAGAIN. +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const EINPROGRESS: c_int = 55; +pub const EALREADY: c_int = 56; +pub const ENOTSOCK: c_int = 57; +pub const EDESTADDRREQ: c_int = 58; +pub const EMSGSIZE: c_int = 59; +pub const EPROTOTYPE: c_int = 60; +pub const ENOPROTOOPT: c_int = 61; +pub const EPROTONOSUPPORT: c_int = 62; +pub const ESOCKTNOSUPPORT: c_int = 63; +pub const EOPNOTSUPP: c_int = 64; +pub const EPFNOSUPPORT: c_int = 65; +pub const EAFNOSUPPORT: c_int = 66; +pub const EADDRINUSE: c_int = 67; +pub const EADDRNOTAVAIL: c_int = 68; +pub const ENETDOWN: c_int = 69; +pub const ENETUNREACH: c_int = 70; +pub const ENETRESET: c_int = 71; +pub const ECONNABORTED: c_int = 72; +pub const ECONNRESET: c_int = 73; +pub const ENOBUFS: c_int = 74; +pub const EISCONN: c_int = 75; +pub const ENOTCONN: c_int = 76; +pub const ESHUTDOWN: c_int = 77; +pub const ETIMEDOUT: c_int = 78; +pub const ECONNREFUSED: c_int = 79; +pub const EHOSTDOWN: c_int = 80; +pub const EHOSTUNREACH: c_int = 81; +pub const ERESTART: c_int = 82; +pub const EPROCLIM: c_int = 83; +pub const EUSERS: c_int = 84; +pub const ELOOP: c_int = 85; +pub const ENAMETOOLONG: c_int = 86; +pub const ENOTEMPTY: c_int = 87; +pub const EDQUOT: c_int = 88; +pub const ECORRUPT: c_int = 89; +pub const ESYSERROR: c_int = 90; +pub const EREMOTE: c_int = 93; +pub const ENOTRECOVERABLE: c_int = 94; +pub const EOWNERDEAD: c_int = 95; +// errnos 96-108 reserved for future use compatible with AIX PS/2 +pub const ENOSYS: c_int = 109; +pub const EMEDIA: c_int = 110; +pub const ESOFT: c_int = 111; +pub const ENOATTR: c_int = 112; +pub const ESAD: c_int = 113; +pub const ENOTRUST: c_int = 114; +pub const ETOOMANYREFS: c_int = 115; +pub const EILSEQ: c_int = 116; +pub const ECANCELED: c_int = 117; +pub const ENOSR: c_int = 118; +pub const ETIME: c_int = 119; +pub const EBADMSG: c_int = 120; +pub const EPROTO: c_int = 121; +pub const ENODATA: c_int = 122; +pub const ENOSTR: c_int = 123; +pub const ENOTSUP: c_int = 124; +pub const EMULTIHOP: c_int = 125; +pub const ENOLINK: c_int = 126; +pub const EOVERFLOW: c_int = 127; + +// sys/dr.h +pub const LPAR_INFO_FORMAT1: c_int = 1; +pub const LPAR_INFO_FORMAT2: c_int = 2; +pub const WPAR_INFO_FORMAT: c_int = 3; +pub const PROC_MODULE_INFO: c_int = 4; +pub const NUM_PROC_MODULE_TYPES: c_int = 5; +pub const LPAR_INFO_VRME_NUM_POOLS: c_int = 6; +pub const LPAR_INFO_VRME_POOLS: c_int = 7; +pub const LPAR_INFO_VRME_LPAR: c_int = 8; +pub const LPAR_INFO_VRME_RESET_HWMARKS: c_int = 9; +pub const LPAR_INFO_VRME_ALLOW_DESIRED: c_int = 10; +pub const EMTP_INFO_FORMAT: c_int = 11; +pub const LPAR_INFO_LPM_CAPABILITY: c_int = 12; +pub const ENERGYSCALE_INFO: c_int = 13; + +// sys/file.h +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +// sys/flock.h +pub const F_RDLCK: c_short = 0o01; +pub const F_WRLCK: c_short = 0o02; +pub const F_UNLCK: c_short = 0o03; + +// sys/fs/quota_common.h +pub const Q_QUOTAON: c_int = 0x100; +pub const Q_QUOTAOFF: c_int = 0x200; +pub const Q_SETUSE: c_int = 0x500; +pub const Q_SYNC: c_int = 0x600; +pub const Q_GETQUOTA: c_int = 0x300; +pub const Q_SETQLIM: c_int = 0x400; +pub const Q_SETQUOTA: c_int = 0x400; + +// sys/ioctl.h +pub const IOCPARM_MASK: c_int = 0x7f; +pub const IOC_VOID: c_int = 0x20000000; +pub const IOC_OUT: c_int = 0x40000000; +pub const IOC_IN: c_int = 0x40000000 << 1; +pub const IOC_INOUT: c_int = IOC_IN | IOC_OUT; +pub const FIOCLEX: c_int = 0x20006601; +pub const FIONCLEX: c_int = 0x20006602; +pub const FIONREAD: c_int = 0x4004667f; +pub const FIONBIO: c_int = 0x8004667e; +pub const FIOASYNC: c_int = 0x8004667d; +pub const FIOSETOWN: c_int = 0x8004667c; +pub const FIOGETOWN: c_int = 0x4004667b; +pub const TIOCGETD: c_int = 0x40047400; +pub const TIOCSETD: c_int = 0x80047401; +pub const TIOCHPCL: c_int = 0x20007402; +pub const TIOCMODG: c_int = 0x40047403; +pub const TIOCMODS: c_int = 0x80047404; +pub const TIOCM_LE: c_int = 0x1; +pub const TIOCM_DTR: c_int = 0x2; +pub const TIOCM_RTS: c_int = 0x4; +pub const TIOCM_ST: c_int = 0x8; +pub const TIOCM_SR: c_int = 0x10; +pub const TIOCM_CTS: c_int = 0x20; +pub const TIOCM_CAR: c_int = 0x40; +pub const TIOCM_CD: c_int = 0x40; +pub const TIOCM_RNG: c_int = 0x80; +pub const TIOCM_RI: c_int = 0x80; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCGETP: c_int = 0x40067408; +pub const TIOCSETP: c_int = 0x80067409; +pub const TIOCSETN: c_int = 0x8006740a; +pub const TIOCEXCL: c_int = 0x2000740d; +pub const TIOCNXCL: c_int = 0x2000740e; +pub const TIOCFLUSH: c_int = 0x80047410; +pub const TIOCSETC: c_int = 0x80067411; +pub const TIOCGETC: c_int = 0x40067412; +pub const TANDEM: c_int = 0x1; +pub const CBREAK: c_int = 0x2; +pub const LCASE: c_int = 0x4; +pub const MDMBUF: c_int = 0x800000; +pub const XTABS: c_int = 0xc00; +pub const SIOCADDMULTI: c_int = 0x80206931; +pub const SIOCADDRT: c_int = 0x8038720a; +pub const SIOCDARP: c_int = 0x804c6920; +pub const SIOCDELMULTI: c_int = 0x80206932; +pub const SIOCDELRT: c_int = 0x8038720b; +pub const SIOCDIFADDR: c_int = 0x80286919; +pub const SIOCGARP: c_int = 0xc04c6926; +pub const SIOCGIFADDR: c_int = 0xc0286921; +pub const SIOCGIFBRDADDR: c_int = 0xc0286923; +pub const SIOCGIFCONF: c_int = 0xc0106945; +pub const SIOCGIFDSTADDR: c_int = 0xc0286922; +pub const SIOCGIFFLAGS: c_int = 0xc0286911; +pub const SIOCGIFHWADDR: c_int = 0xc0546995; +pub const SIOCGIFMETRIC: c_int = 0xc0286917; +pub const SIOCGIFMTU: c_int = 0xc0286956; +pub const SIOCGIFNETMASK: c_int = 0xc0286925; +pub const SIOCSARP: c_int = 0x804c691e; +pub const SIOCSIFADDR: c_int = 0x8028690c; +pub const SIOCSIFBRDADDR: c_int = 0x80286913; +pub const SIOCSIFDSTADDR: c_int = 0x8028690e; +pub const SIOCSIFFLAGS: c_int = 0x80286910; +pub const SIOCSIFMETRIC: c_int = 0x80286918; +pub const SIOCSIFMTU: c_int = 0x80286958; +pub const SIOCSIFNETMASK: c_int = 0x80286916; +pub const TIOCUCNTL: c_int = 0x80047466; +pub const TIOCCONS: c_int = 0x80047462; +pub const TIOCPKT: c_int = 0x80047470; +pub const TIOCPKT_DATA: c_int = 0; +pub const TIOCPKT_FLUSHREAD: c_int = 1; +pub const TIOCPKT_FLUSHWRITE: c_int = 2; +pub const TIOCPKT_NOSTOP: c_int = 0x10; +pub const TIOCPKT_DOSTOP: c_int = 0x20; +pub const TIOCPKT_START: c_int = 8; +pub const TIOCPKT_STOP: c_int = 4; + +// sys/ipc.h +pub const IPC_ALLOC: c_int = 0o100000; +pub const IPC_CREAT: c_int = 0o020000; +pub const IPC_EXCL: c_int = 0o002000; +pub const IPC_NOWAIT: c_int = 0o004000; +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 101; +pub const IPC_R: c_int = 0o0400; +pub const IPC_W: c_int = 0o0200; +pub const IPC_O: c_int = 0o1000; +pub const IPC_NOERROR: c_int = 0o10000; +pub const IPC_STAT: c_int = 102; +pub const IPC_PRIVATE: crate::key_t = -1; +pub const SHM_LOCK: c_int = 201; +pub const SHM_UNLOCK: c_int = 202; + +// sys/ldr.h +pub const L_GETMESSAGES: c_int = 1; +pub const L_GETINFO: c_int = 2; +pub const L_GETLIBPATH: c_int = 3; +pub const L_GETKERNINFO: c_int = 4; +pub const L_GETLIB32INFO: c_int = 5; +pub const L_GETLIB64INFO: c_int = 6; +pub const L_GETPROCINFO: c_int = 7; +pub const L_GETXINFO: c_int = 8; + +// sys/limits.h +pub const PATH_MAX: c_int = 1023; +pub const PAGESIZE: c_int = 4096; +pub const IOV_MAX: c_int = 16; +pub const AIO_LISTIO_MAX: c_int = 4096; +pub const PIPE_BUF: usize = 32768; +pub const OPEN_MAX: c_int = 65534; +pub const MAX_INPUT: c_int = 512; +pub const MAX_CANON: c_int = 256; +pub const ARG_MAX: c_int = 1048576; +pub const BC_BASE_MAX: c_int = 99; +pub const BC_DIM_MAX: c_int = 0x800; +pub const BC_SCALE_MAX: c_int = 99; +pub const BC_STRING_MAX: c_int = 0x800; +pub const CHARCLASS_NAME_MAX: c_int = 14; +pub const CHILD_MAX: c_int = 128; +pub const COLL_WEIGHTS_MAX: c_int = 4; +pub const EXPR_NEST_MAX: c_int = 32; +pub const NZERO: c_int = 20; + +// sys/lockf.h +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +// sys/machine.h +pub const BIG_ENDIAN: c_int = 4321; +pub const LITTLE_ENDIAN: c_int = 1234; +pub const PDP_ENDIAN: c_int = 3412; + +// sys/mman.h +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; +pub const MAP_FILE: c_int = 0; +pub const MAP_SHARED: c_int = 1; +pub const MAP_PRIVATE: c_int = 2; +pub const MAP_FIXED: c_int = 0x100; +pub const MAP_ANON: c_int = 0x10; +pub const MAP_ANONYMOUS: c_int = 0x10; +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; +pub const MAP_TYPE: c_int = 0xf0; +pub const MCL_CURRENT: c_int = 0x100; +pub const MCL_FUTURE: c_int = 0x200; +pub const MS_SYNC: c_int = 0x20; +pub const MS_ASYNC: c_int = 0x10; +pub const MS_INVALIDATE: c_int = 0x40; +pub const POSIX_MADV_NORMAL: c_int = 1; +pub const POSIX_MADV_RANDOM: c_int = 3; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 4; +pub const POSIX_MADV_DONTNEED: c_int = 5; +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; + +// sys/mode.h +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; + +// sys/msg.h +pub const MSG_NOERROR: c_int = 0o10000; + +// sys/m_signal.h +pub const SIGSTKSZ: size_t = 4096; +pub const MINSIGSTKSZ: size_t = 1200; + +// sys/params.h +pub const MAXPATHLEN: c_int = PATH_MAX + 1; +pub const MAXSYMLINKS: c_int = 20; +pub const MAXHOSTNAMELEN: c_int = 256; +pub const MAXUPRC: c_int = 128; +pub const NGROUPS_MAX: c_ulong = 2048; +pub const NGROUPS: c_ulong = NGROUPS_MAX; +pub const NOFILE: c_int = OPEN_MAX; + +// sys/poll.h +pub const POLLIN: c_short = 0x0001; +pub const POLLPRI: c_short = 0x0004; +pub const POLLOUT: c_short = 0x0002; +pub const POLLERR: c_short = 0x4000; +pub const POLLHUP: c_short = 0x2000; +pub const POLLMSG: c_short = 0x0080; +pub const POLLSYNC: c_short = 0x8000; +pub const POLLNVAL: c_short = POLLSYNC; +pub const POLLNORM: c_short = POLLIN; +pub const POLLRDNORM: c_short = 0x0010; +pub const POLLWRNORM: c_short = POLLOUT; +pub const POLLRDBAND: c_short = 0x0020; +pub const POLLWRBAND: c_short = 0x0040; + +// sys/pollset.h +pub const PS_ADD: c_uchar = 0; +pub const PS_MOD: c_uchar = 1; +pub const PS_DELETE: c_uchar = 2; +pub const PS_REPLACE: c_uchar = 3; + +// sys/ptrace.h +pub const PT_TRACE_ME: c_int = 0; +pub const PT_READ_I: c_int = 1; +pub const PT_READ_D: c_int = 2; +pub const PT_WRITE_I: c_int = 4; +pub const PT_WRITE_D: c_int = 5; +pub const PT_CONTINUE: c_int = 7; +pub const PT_KILL: c_int = 8; +pub const PT_STEP: c_int = 9; +pub const PT_READ_GPR: c_int = 11; +pub const PT_READ_FPR: c_int = 12; +pub const PT_WRITE_GPR: c_int = 14; +pub const PT_WRITE_FPR: c_int = 15; +pub const PT_READ_BLOCK: c_int = 17; +pub const PT_WRITE_BLOCK: c_int = 19; +pub const PT_ATTACH: c_int = 30; +pub const PT_DETACH: c_int = 31; +pub const PT_REGSET: c_int = 32; +pub const PT_REATT: c_int = 33; +pub const PT_LDINFO: c_int = 34; +pub const PT_MULTI: c_int = 35; +pub const PT_NEXT: c_int = 36; +pub const PT_SET: c_int = 37; +pub const PT_CLEAR: c_int = 38; +pub const PT_LDXINFO: c_int = 39; +pub const PT_QUERY: c_int = 40; +pub const PT_WATCH: c_int = 41; +pub const PTT_CONTINUE: c_int = 50; +pub const PTT_STEP: c_int = 51; +pub const PTT_READ_SPRS: c_int = 52; +pub const PTT_WRITE_SPRS: c_int = 53; +pub const PTT_READ_GPRS: c_int = 54; +pub const PTT_WRITE_GPRS: c_int = 55; +pub const PTT_READ_FPRS: c_int = 56; +pub const PTT_WRITE_FPRS: c_int = 57; +pub const PTT_READ_VEC: c_int = 58; +pub const PTT_WRITE_VEC: c_int = 59; +pub const PTT_WATCH: c_int = 60; +pub const PTT_SET_TRAP: c_int = 61; +pub const PTT_CLEAR_TRAP: c_int = 62; +pub const PTT_READ_UKEYSET: c_int = 63; +pub const PT_GET_UKEY: c_int = 64; +pub const PTT_READ_FPSCR_HI: c_int = 65; +pub const PTT_WRITE_FPSCR_HI: c_int = 66; +pub const PTT_READ_VSX: c_int = 67; +pub const PTT_WRITE_VSX: c_int = 68; +pub const PTT_READ_TM: c_int = 69; +pub const PTRACE_ATTACH: c_int = 14; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_DETACH: c_int = 15; +pub const PTRACE_GETFPREGS: c_int = 12; +pub const PTRACE_GETREGS: c_int = 10; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKUSER: c_int = 3; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEUSER: c_int = 6; +pub const PTRACE_SETFPREGS: c_int = 13; +pub const PTRACE_SETREGS: c_int = 11; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_SYSCALL: c_int = 16; +pub const PTRACE_TRACEME: c_int = 0; + +// sys/resource.h +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_AS: c_int = 6; +pub const RLIMIT_NOFILE: c_int = 7; +pub const RLIMIT_THREADS: c_int = 8; +pub const RLIMIT_NPROC: c_int = 9; +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; +pub const RUSAGE_THREAD: c_int = 1; +pub const RLIM_SAVED_MAX: c_ulong = RLIM_INFINITY - 1; +pub const RLIM_SAVED_CUR: c_ulong = RLIM_INFINITY - 2; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 10; + +// sys/sched.h +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_LOCAL: c_int = 3; +pub const SCHED_GLOBAL: c_int = 4; +pub const SCHED_FIFO2: c_int = 5; +pub const SCHED_FIFO3: c_int = 6; +pub const SCHED_FIFO4: c_int = 7; + +// sys/sem.h +pub const SEM_UNDO: c_int = 0o10000; +pub const GETNCNT: c_int = 3; +pub const GETPID: c_int = 4; +pub const GETVAL: c_int = 5; +pub const GETALL: c_int = 6; +pub const GETZCNT: c_int = 7; +pub const SETVAL: c_int = 8; +pub const SETALL: c_int = 9; + +// sys/shm.h +pub const SHMLBA: c_int = 0x10000000; +pub const SHMLBA_EXTSHM: c_int = 0x1000; +pub const SHM_SHMAT: c_int = 0x80000000; +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_PIN: c_int = 0o4000; +pub const SHM_LGPAGE: c_int = 0o20000000000; +pub const SHM_MAP: c_int = 0o4000; +pub const SHM_FMAP: c_int = 0o2000; +pub const SHM_COPY: c_int = 0o40000; +pub const SHM_CLEAR: c_int = 0; +pub const SHM_HGSEG: c_int = 0o10000000000; +pub const SHM_R: c_int = IPC_R; +pub const SHM_W: c_int = IPC_W; +pub const SHM_DEST: c_int = 0o2000; + +// sys/signal.h +pub const SA_ONSTACK: c_int = 0x00000001; +pub const SA_RESETHAND: c_int = 0x00000002; +pub const SA_RESTART: c_int = 0x00000008; +pub const SA_SIGINFO: c_int = 0x00000100; +pub const SA_NODEFER: c_int = 0x00000200; +pub const SA_NOCLDWAIT: c_int = 0x00000400; +pub const SA_NOCLDSTOP: c_int = 0x00000004; +pub const SS_ONSTACK: c_int = 0x00000001; +pub const SS_DISABLE: c_int = 0x00000002; +pub const SIGCHLD: c_int = 20; +pub const SIGBUS: c_int = 10; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const SIG_SETMASK: c_int = 2; +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_SIGNAL: c_int = 2; +pub const SIGEV_THREAD: c_int = 3; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGPWR: c_int = 29; +pub const SIGWINCH: c_int = 28; +pub const SIGURG: c_int = 16; +pub const SIGPOLL: c_int = SIGIO; +pub const SIGIO: c_int = 23; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGVTALRM: c_int = 34; +pub const SIGPROF: c_int = 32; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGTRAP: c_int = 5; +pub const SIGCLD: c_int = 20; +pub const SIGRTMAX: c_int = 57; +pub const SIGRTMIN: c_int = 50; +pub const SI_USER: c_int = 0; +pub const SI_UNDEFINED: c_int = 8; +pub const SI_EMPTY: c_int = 9; +pub const BUS_ADRALN: c_int = 1; +pub const BUS_ADRERR: c_int = 2; +pub const BUS_OBJERR: c_int = 3; +pub const BUS_UEGARD: c_int = 4; +pub const CLD_EXITED: c_int = 10; +pub const CLD_KILLED: c_int = 11; +pub const CLD_DUMPED: c_int = 12; +pub const CLD_TRAPPED: c_int = 13; +pub const CLD_STOPPED: c_int = 14; +pub const CLD_CONTINUED: c_int = 15; +pub const FPE_INTDIV: c_int = 20; +pub const FPE_INTOVF: c_int = 21; +pub const FPE_FLTDIV: c_int = 22; +pub const FPE_FLTOVF: c_int = 23; +pub const FPE_FLTUND: c_int = 24; +pub const FPE_FLTRES: c_int = 25; +pub const FPE_FLTINV: c_int = 26; +pub const FPE_FLTSUB: c_int = 27; +pub const ILL_ILLOPC: c_int = 30; +pub const ILL_ILLOPN: c_int = 31; +pub const ILL_ILLADR: c_int = 32; +pub const ILL_ILLTRP: c_int = 33; +pub const ILL_PRVOPC: c_int = 34; +pub const ILL_PRVREG: c_int = 35; +pub const ILL_COPROC: c_int = 36; +pub const ILL_BADSTK: c_int = 37; +pub const ILL_TMBADTHING: c_int = 38; +pub const POLL_IN: c_int = 40; +pub const POLL_OUT: c_int = 41; +pub const POLL_MSG: c_int = -3; +pub const POLL_ERR: c_int = 43; +pub const POLL_PRI: c_int = 44; +pub const POLL_HUP: c_int = 45; +pub const SEGV_MAPERR: c_int = 50; +pub const SEGV_ACCERR: c_int = 51; +pub const SEGV_KEYERR: c_int = 52; +pub const TRAP_BRKPT: c_int = 60; +pub const TRAP_TRACE: c_int = 61; +pub const SI_QUEUE: c_int = 71; +pub const SI_TIMER: c_int = 72; +pub const SI_ASYNCIO: c_int = 73; +pub const SI_MESGQ: c_int = 74; + +// sys/socket.h +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const SO_TIMESTAMPNS: c_int = 0x100a; +pub const SOMAXCONN: c_int = 1024; +pub const AF_LOCAL: c_int = AF_UNIX; +pub const UIO_MAXIOV: c_int = 1024; +pub const pseudo_AF_XTP: c_int = 19; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_ROUTE: c_int = 17; +pub const AF_LINK: c_int = 18; +pub const AF_INET6: c_int = 24; +pub const AF_INTF: c_int = 20; +pub const AF_RIF: c_int = 21; +pub const AF_NDD: c_int = 23; +pub const AF_MAX: c_int = 30; +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_ISO; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_XTP: c_int = 19; +pub const PF_RIF: c_int = AF_RIF; +pub const PF_INTF: c_int = AF_INTF; +pub const PF_NDD: c_int = AF_NDD; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_MAX: c_int = AF_MAX; +pub const SF_CLOSE: c_int = 1; +pub const SF_REUSE: c_int = 2; +pub const SF_DONT_CACHE: c_int = 4; +pub const SF_SYNC_CACHE: c_int = 8; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 0x0001; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_USE_IFBUFS: c_int = 0x0400; +pub const SO_CKSUMRECV: c_int = 0x0800; +pub const SO_NOREUSEADDR: c_int = 0x1000; +pub const SO_KERNACCEPT: c_int = 0x2000; +pub const SO_NOMULTIPATH: c_int = 0x4000; +pub const SO_AUDIT: c_int = 0x8000; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SCM_RIGHTS: c_int = 0x01; +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_EOR: c_int = 0x8; +pub const MSG_TRUNC: c_int = 0x10; +pub const MSG_CTRUNC: c_int = 0x20; +pub const MSG_WAITALL: c_int = 0x40; +pub const MSG_MPEG2: c_int = 0x80; +pub const MSG_NOSIGNAL: c_int = 0x100; +pub const MSG_WAITFORONE: c_int = 0x200; +pub const MSG_ARGEXT: c_int = 0x400; +pub const MSG_NONBLOCK: c_int = 0x4000; +pub const MSG_COMPAT: c_int = 0x8000; +pub const MSG_MAXIOVLEN: c_int = 16; +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +// sys/stat.h +pub const UTIME_NOW: c_int = -2; +pub const UTIME_OMIT: c_int = -3; + +// sys/statvfs.h +pub const ST_RDONLY: c_ulong = 0x0001; +pub const ST_NOSUID: c_ulong = 0x0040; +pub const ST_NODEV: c_ulong = 0x0080; + +// sys/stropts.h +pub const I_NREAD: c_int = 0x20005301; +pub const I_PUSH: c_int = 0x20005302; +pub const I_POP: c_int = 0x20005303; +pub const I_LOOK: c_int = 0x20005304; +pub const I_FLUSH: c_int = 0x20005305; +pub const I_SRDOPT: c_int = 0x20005306; +pub const I_GRDOPT: c_int = 0x20005307; +pub const I_STR: c_int = 0x20005308; +pub const I_SETSIG: c_int = 0x20005309; +pub const I_GETSIG: c_int = 0x2000530a; +pub const I_FIND: c_int = 0x2000530b; +pub const I_LINK: c_int = 0x2000530c; +pub const I_UNLINK: c_int = 0x2000530d; +pub const I_PEEK: c_int = 0x2000530f; +pub const I_FDINSERT: c_int = 0x20005310; +pub const I_SENDFD: c_int = 0x20005311; +pub const I_RECVFD: c_int = 0x20005312; +pub const I_SWROPT: c_int = 0x20005314; +pub const I_GWROPT: c_int = 0x20005315; +pub const I_LIST: c_int = 0x20005316; +pub const I_PLINK: c_int = 0x2000531d; +pub const I_PUNLINK: c_int = 0x2000531e; +pub const I_FLUSHBAND: c_int = 0x20005313; +pub const I_CKBAND: c_int = 0x20005318; +pub const I_GETBAND: c_int = 0x20005319; +pub const I_ATMARK: c_int = 0x20005317; +pub const I_SETCLTIME: c_int = 0x2000531b; +pub const I_GETCLTIME: c_int = 0x2000531c; +pub const I_CANPUT: c_int = 0x2000531a; + +// sys/syslog.h +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_NFACILITIES: c_int = 24; +pub const LOG_PERROR: c_int = 0x20; + +// sys/systemcfg.h +pub const SC_ARCH: c_int = 1; +pub const SC_IMPL: c_int = 2; +pub const SC_VERS: c_int = 3; +pub const SC_WIDTH: c_int = 4; +pub const SC_NCPUS: c_int = 5; +pub const SC_L1C_ATTR: c_int = 6; +pub const SC_L1C_ISZ: c_int = 7; +pub const SC_L1C_DSZ: c_int = 8; +pub const SC_L1C_ICA: c_int = 9; +pub const SC_L1C_DCA: c_int = 10; +pub const SC_L1C_IBS: c_int = 11; +pub const SC_L1C_DBS: c_int = 12; +pub const SC_L1C_ILS: c_int = 13; +pub const SC_L1C_DLS: c_int = 14; +pub const SC_L2C_SZ: c_int = 15; +pub const SC_L2C_AS: c_int = 16; +pub const SC_TLB_ATTR: c_int = 17; +pub const SC_ITLB_SZ: c_int = 18; +pub const SC_DTLB_SZ: c_int = 19; +pub const SC_ITLB_ATT: c_int = 20; +pub const SC_DTLB_ATT: c_int = 21; +pub const SC_RESRV_SZ: c_int = 22; +pub const SC_PRI_LC: c_int = 23; +pub const SC_PRO_LC: c_int = 24; +pub const SC_RTC_TYPE: c_int = 25; +pub const SC_VIRT_AL: c_int = 26; +pub const SC_CAC_CONG: c_int = 27; +pub const SC_MOD_ARCH: c_int = 28; +pub const SC_MOD_IMPL: c_int = 29; +pub const SC_XINT: c_int = 30; +pub const SC_XFRAC: c_int = 31; +pub const SC_KRN_ATTR: c_int = 32; +pub const SC_PHYSMEM: c_int = 33; +pub const SC_SLB_ATTR: c_int = 34; +pub const SC_SLB_SZ: c_int = 35; +pub const SC_MAX_NCPUS: c_int = 37; +pub const SC_MAX_REALADDR: c_int = 38; +pub const SC_ORIG_ENT_CAP: c_int = 39; +pub const SC_ENT_CAP: c_int = 40; +pub const SC_DISP_WHE: c_int = 41; +pub const SC_CAPINC: c_int = 42; +pub const SC_VCAPW: c_int = 43; +pub const SC_SPLP_STAT: c_int = 44; +pub const SC_SMT_STAT: c_int = 45; +pub const SC_SMT_TC: c_int = 46; +pub const SC_VMX_VER: c_int = 47; +pub const SC_LMB_SZ: c_int = 48; +pub const SC_MAX_XCPU: c_int = 49; +pub const SC_EC_LVL: c_int = 50; +pub const SC_AME_STAT: c_int = 51; +pub const SC_ECO_STAT: c_int = 52; +pub const SC_DFP_VER: c_int = 53; +pub const SC_VRM_STAT: c_int = 54; +pub const SC_PHYS_IMP: c_int = 55; +pub const SC_PHYS_VER: c_int = 56; +pub const SC_SPCM_STATUS: c_int = 57; +pub const SC_SPCM_MAX: c_int = 58; +pub const SC_TM_VER: c_int = 59; +pub const SC_NX_CAP: c_int = 60; +pub const SC_PKS_STATE: c_int = 61; +pub const SC_MMA_VER: c_int = 62; +pub const POWER_RS: c_int = 1; +pub const POWER_PC: c_int = 2; +pub const IA64: c_int = 3; +pub const POWER_RS1: c_int = 0x1; +pub const POWER_RSC: c_int = 0x2; +pub const POWER_RS2: c_int = 0x4; +pub const POWER_601: c_int = 0x8; +pub const POWER_604: c_int = 0x10; +pub const POWER_603: c_int = 0x20; +pub const POWER_620: c_int = 0x40; +pub const POWER_630: c_int = 0x80; +pub const POWER_A35: c_int = 0x100; +pub const POWER_RS64II: c_int = 0x200; +pub const POWER_RS64III: c_int = 0x400; +pub const POWER_4: c_int = 0x800; +pub const POWER_RS64IV: c_int = POWER_4; +pub const POWER_MPC7450: c_int = 0x1000; +pub const POWER_5: c_int = 0x2000; +pub const POWER_6: c_int = 0x4000; +pub const POWER_7: c_int = 0x8000; +pub const POWER_8: c_int = 0x10000; +pub const POWER_9: c_int = 0x20000; + +// sys/time.h +pub const FD_SETSIZE: usize = 65534; +pub const TIMEOFDAY: c_int = 9; +pub const CLOCK_REALTIME: crate::clockid_t = TIMEOFDAY as clockid_t; +pub const CLOCK_MONOTONIC: crate::clockid_t = 10; +pub const TIMER_ABSTIME: c_int = 999; +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; +pub const ITIMER_VIRT: c_int = 3; +pub const ITIMER_REAL1: c_int = 20; +pub const ITIMER_REAL_TH: c_int = ITIMER_REAL1; +pub const DST_AUST: c_int = 2; +pub const DST_CAN: c_int = 6; +pub const DST_EET: c_int = 5; +pub const DST_MET: c_int = 4; +pub const DST_NONE: c_int = 0; +pub const DST_USA: c_int = 1; +pub const DST_WET: c_int = 3; + +// sys/termio.h +pub const CSTART: crate::tcflag_t = 0o21; +pub const CSTOP: crate::tcflag_t = 0o23; +pub const TCGETA: c_int = TIOC | 5; +pub const TCSETA: c_int = TIOC | 6; +pub const TCSETAW: c_int = TIOC | 7; +pub const TCSETAF: c_int = TIOC | 8; +pub const TCSBRK: c_int = TIOC | 9; +pub const TCXONC: c_int = TIOC | 11; +pub const TCFLSH: c_int = TIOC | 12; +pub const TCGETS: c_int = TIOC | 1; +pub const TCSETS: c_int = TIOC | 2; +pub const TCSANOW: c_int = 0; +pub const TCSETSW: c_int = TIOC | 3; +pub const TCSADRAIN: c_int = 1; +pub const TCSETSF: c_int = TIOC | 4; +pub const TCSAFLUSH: c_int = 2; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; +pub const TIOC: c_int = 0x5400; +pub const TIOCGWINSZ: c_int = 0x40087468; +pub const TIOCSWINSZ: c_int = 0x80087467; +pub const TIOCLBIS: c_int = 0x8004747f; +pub const TIOCLBIC: c_int = 0x8004747e; +pub const TIOCLSET: c_int = 0x8004747d; +pub const TIOCLGET: c_int = 0x4004747c; +pub const TIOCSBRK: c_int = 0x2000747b; +pub const TIOCCBRK: c_int = 0x2000747a; +pub const TIOCSDTR: c_int = 0x20007479; +pub const TIOCCDTR: c_int = 0x20007478; +pub const TIOCSLTC: c_int = 0x80067475; +pub const TIOCGLTC: c_int = 0x40067474; +pub const TIOCOUTQ: c_int = 0x40047473; +pub const TIOCNOTTY: c_int = 0x20007471; +pub const TIOCSTOP: c_int = 0x2000746f; +pub const TIOCSTART: c_int = 0x2000746e; +pub const TIOCGPGRP: c_int = 0x40047477; +pub const TIOCSPGRP: c_int = 0x80047476; +pub const TIOCGSID: c_int = 0x40047448; +pub const TIOCSTI: c_int = 0x80017472; +pub const TIOCMSET: c_int = 0x8004746d; +pub const TIOCMBIS: c_int = 0x8004746c; +pub const TIOCMBIC: c_int = 0x8004746b; +pub const TIOCMGET: c_int = 0x4004746a; +pub const TIOCREMOTE: c_int = 0x80047469; + +// sys/user.h +pub const MAXCOMLEN: c_int = 32; +pub const UF_SYSTEM: c_int = 0x1000; + +// sys/vattr.h +pub const AT_FLAGS: c_int = 0x80; +pub const AT_GID: c_int = 8; +pub const AT_UID: c_int = 4; + +// sys/wait.h +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; +pub const WNOHANG: c_int = 0x1; +pub const WUNTRACED: c_int = 0x2; +pub const WEXITED: c_int = 0x04; +pub const WCONTINUED: c_int = 0x01000000; +pub const WNOWAIT: c_int = 0x10; +pub const WSTOPPED: c_int = _W_STOPPED; +pub const _W_STOPPED: c_int = 0x00000040; +pub const _W_SLWTED: c_int = 0x0000007c; +pub const _W_SEWTED: c_int = 0x0000007d; +pub const _W_SFWTED: c_int = 0x0000007e; +pub const _W_STRC: c_int = 0x0000007f; + +// termios.h +pub const NCCS: usize = 16; +pub const OLCUC: crate::tcflag_t = 2; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS5: crate::tcflag_t = 0x00000000; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOCTL: crate::tcflag_t = 0x00020000; +pub const ECHOPRT: crate::tcflag_t = 0x00040000; +pub const ECHOKE: crate::tcflag_t = 0x00080000; +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNPAR: crate::tcflag_t = 0x00000004; +pub const PARMRK: crate::tcflag_t = 0x00000008; +pub const INPCK: crate::tcflag_t = 0x00000010; +pub const ISTRIP: crate::tcflag_t = 0x00000020; +pub const INLCR: crate::tcflag_t = 0x00000040; +pub const IGNCR: crate::tcflag_t = 0x00000080; +pub const ICRNL: crate::tcflag_t = 0x00000100; +pub const IXON: crate::tcflag_t = 0x00000200; +pub const IXOFF: crate::tcflag_t = 0x00000400; +pub const IXANY: crate::tcflag_t = 0x00001000; +pub const IMAXBEL: crate::tcflag_t = 0x00010000; +pub const OPOST: crate::tcflag_t = 0x00000001; +pub const ONLCR: crate::tcflag_t = 0x00000004; +pub const OCRNL: crate::tcflag_t = 0x00000008; +pub const ONOCR: crate::tcflag_t = 0x00000010; +pub const ONLRET: crate::tcflag_t = 0x00000020; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const IEXTEN: crate::tcflag_t = 0x00200000; +pub const TOSTOP: crate::tcflag_t = 0x00010000; +pub const FLUSHO: crate::tcflag_t = 0x00100000; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VEOL: usize = 5; +pub const VSTART: usize = 7; +pub const VSTOP: usize = 8; +pub const VSUSP: usize = 9; +pub const VMIN: usize = 4; +pub const VTIME: usize = 5; +pub const VEOL2: usize = 6; +pub const VDSUSP: usize = 10; +pub const VREPRINT: usize = 11; +pub const VDISCRD: usize = 12; +pub const VWERSE: usize = 13; +pub const VLNEXT: usize = 14; +pub const B0: crate::speed_t = 0x0; +pub const B50: crate::speed_t = 0x1; +pub const B75: crate::speed_t = 0x2; +pub const B110: crate::speed_t = 0x3; +pub const B134: crate::speed_t = 0x4; +pub const B150: crate::speed_t = 0x5; +pub const B200: crate::speed_t = 0x6; +pub const B300: crate::speed_t = 0x7; +pub const B600: crate::speed_t = 0x8; +pub const B1200: crate::speed_t = 0x9; +pub const B1800: crate::speed_t = 0xa; +pub const B2400: crate::speed_t = 0xb; +pub const B4800: crate::speed_t = 0xc; +pub const B9600: crate::speed_t = 0xd; +pub const B19200: crate::speed_t = 0xe; +pub const B38400: crate::speed_t = 0xf; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const IUCLC: crate::tcflag_t = 0x00000800; +pub const OFILL: crate::tcflag_t = 0x00000040; +pub const OFDEL: crate::tcflag_t = 0x00000080; +pub const CRDLY: crate::tcflag_t = 0x00000300; +pub const CR0: crate::tcflag_t = 0x00000000; +pub const CR1: crate::tcflag_t = 0x00000100; +pub const CR2: crate::tcflag_t = 0x00000200; +pub const CR3: crate::tcflag_t = 0x00000300; +pub const TABDLY: crate::tcflag_t = 0x00000c00; +pub const TAB0: crate::tcflag_t = 0x00000000; +pub const TAB1: crate::tcflag_t = 0x00000400; +pub const TAB2: crate::tcflag_t = 0x00000800; +pub const TAB3: crate::tcflag_t = 0x00000c00; +pub const BSDLY: crate::tcflag_t = 0x00001000; +pub const BS0: crate::tcflag_t = 0x00000000; +pub const BS1: crate::tcflag_t = 0x00001000; +pub const FFDLY: crate::tcflag_t = 0x00002000; +pub const FF0: crate::tcflag_t = 0x00000000; +pub const FF1: crate::tcflag_t = 0x00002000; +pub const NLDLY: crate::tcflag_t = 0x00004000; +pub const NL0: crate::tcflag_t = 0x00000000; +pub const NL1: crate::tcflag_t = 0x00004000; +pub const VTDLY: crate::tcflag_t = 0x00008000; +pub const VT0: crate::tcflag_t = 0x00000000; +pub const VT1: crate::tcflag_t = 0x00008000; +pub const OXTABS: crate::tcflag_t = 0x00040000; +pub const ONOEOT: crate::tcflag_t = 0x00080000; +pub const CBAUD: crate::tcflag_t = 0x0000000f; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const CIBAUD: crate::tcflag_t = 0x000f0000; +pub const IBSHIFT: crate::tcflag_t = 16; +pub const PAREXT: crate::tcflag_t = 0x00100000; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const XCASE: crate::tcflag_t = 0x00000004; +pub const ALTWERASE: crate::tcflag_t = 0x00400000; + +// time.h +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 11; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 12; + +// unistd.h +pub const _POSIX_VDISABLE: c_int = 0xff; +pub const _PC_LINK_MAX: c_int = 11; +pub const _PC_MAX_CANON: c_int = 12; +pub const _PC_MAX_INPUT: c_int = 13; +pub const _PC_NAME_MAX: c_int = 14; +pub const _PC_PATH_MAX: c_int = 16; +pub const _PC_PIPE_BUF: c_int = 17; +pub const _PC_NO_TRUNC: c_int = 15; +pub const _PC_VDISABLE: c_int = 18; +pub const _PC_CHOWN_RESTRICTED: c_int = 10; +pub const _PC_ASYNC_IO: c_int = 19; +pub const _PC_PRIO_IO: c_int = 21; +pub const _PC_SYNC_IO: c_int = 20; +pub const _PC_ALLOC_SIZE_MIN: c_int = 26; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 27; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 28; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 29; +pub const _PC_REC_XFER_ALIGN: c_int = 30; +pub const _PC_SYMLINK_MAX: c_int = 25; +pub const _PC_2_SYMLINKS: c_int = 31; +pub const _PC_TIMESTAMP_RESOLUTION: c_int = 32; +pub const _PC_FILESIZEBITS: c_int = 22; +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_VERSION: c_int = 9; +pub const _SC_PASS_MAX: c_int = 45; +pub const _SC_PAGESIZE: c_int = _SC_PAGE_SIZE; +pub const _SC_PAGE_SIZE: c_int = 48; +pub const _SC_XOPEN_VERSION: c_int = 46; +pub const _SC_NPROCESSORS_CONF: c_int = 71; +pub const _SC_NPROCESSORS_ONLN: c_int = 72; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_AIO_LISTIO_MAX: c_int = 75; +pub const _SC_AIO_MAX: c_int = 76; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 77; +pub const _SC_ASYNCHRONOUS_IO: c_int = 78; +pub const _SC_DELAYTIMER_MAX: c_int = 79; +pub const _SC_FSYNC: c_int = 80; +pub const _SC_MAPPED_FILES: c_int = 84; +pub const _SC_MEMLOCK: c_int = 85; +pub const _SC_MEMLOCK_RANGE: c_int = 86; +pub const _SC_MEMORY_PROTECTION: c_int = 87; +pub const _SC_MESSAGE_PASSING: c_int = 88; +pub const _SC_MQ_OPEN_MAX: c_int = 89; +pub const _SC_MQ_PRIO_MAX: c_int = 90; +pub const _SC_PRIORITIZED_IO: c_int = 91; +pub const _SC_PRIORITY_SCHEDULING: c_int = 92; +pub const _SC_REALTIME_SIGNALS: c_int = 93; +pub const _SC_RTSIG_MAX: c_int = 94; +pub const _SC_SEMAPHORES: c_int = 95; +pub const _SC_SEM_NSEMS_MAX: c_int = 96; +pub const _SC_SEM_VALUE_MAX: c_int = 97; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 98; +pub const _SC_SIGQUEUE_MAX: c_int = 99; +pub const _SC_SYNCHRONIZED_IO: c_int = 100; +pub const _SC_TIMERS: c_int = 102; +pub const _SC_TIMER_MAX: c_int = 103; +pub const _SC_2_C_BIND: c_int = 51; +pub const _SC_2_C_DEV: c_int = 32; +pub const _SC_2_C_VERSION: c_int = 52; +pub const _SC_2_FORT_DEV: c_int = 33; +pub const _SC_2_FORT_RUN: c_int = 34; +pub const _SC_2_LOCALEDEF: c_int = 35; +pub const _SC_2_SW_DEV: c_int = 36; +pub const _SC_2_UPE: c_int = 53; +pub const _SC_2_VERSION: c_int = 31; +pub const _SC_BC_BASE_MAX: c_int = 23; +pub const _SC_BC_DIM_MAX: c_int = 24; +pub const _SC_BC_SCALE_MAX: c_int = 25; +pub const _SC_BC_STRING_MAX: c_int = 26; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 50; +pub const _SC_EXPR_NEST_MAX: c_int = 28; +pub const _SC_LINE_MAX: c_int = 29; +pub const _SC_RE_DUP_MAX: c_int = 30; +pub const _SC_XOPEN_CRYPT: c_int = 56; +pub const _SC_XOPEN_ENH_I18N: c_int = 57; +pub const _SC_XOPEN_SHM: c_int = 55; +pub const _SC_2_CHAR_TERM: c_int = 54; +pub const _SC_XOPEN_XCU_VERSION: c_int = 109; +pub const _SC_ATEXIT_MAX: c_int = 47; +pub const _SC_IOV_MAX: c_int = 58; +pub const _SC_XOPEN_UNIX: c_int = 73; +pub const _SC_T_IOV_MAX: c_int = 0; +pub const _SC_PHYS_PAGES: c_int = 113; +pub const _SC_AVPHYS_PAGES: c_int = 114; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 101; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 81; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 82; +pub const _SC_LOGIN_NAME_MAX: c_int = 83; +pub const _SC_THREAD_KEYS_MAX: c_int = 68; +pub const _SC_THREAD_STACK_MIN: c_int = 69; +pub const _SC_THREAD_THREADS_MAX: c_int = 70; +pub const _SC_TTY_NAME_MAX: c_int = 104; +pub const _SC_THREADS: c_int = 60; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 61; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 62; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 64; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 65; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 66; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 59; +pub const _SC_XOPEN_LEGACY: c_int = 112; +pub const _SC_XOPEN_REALTIME: c_int = 110; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 111; +pub const _SC_XBS5_ILP32_OFF32: c_int = 105; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 106; +pub const _SC_XBS5_LP64_OFF64: c_int = 107; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 108; +pub const _SC_2_PBS: c_int = 132; +pub const _SC_2_PBS_ACCOUNTING: c_int = 133; +pub const _SC_2_PBS_CHECKPOINT: c_int = 134; +pub const _SC_2_PBS_LOCATE: c_int = 135; +pub const _SC_2_PBS_MESSAGE: c_int = 136; +pub const _SC_2_PBS_TRACK: c_int = 137; +pub const _SC_ADVISORY_INFO: c_int = 130; +pub const _SC_BARRIERS: c_int = 138; +pub const _SC_CLOCK_SELECTION: c_int = 139; +pub const _SC_CPUTIME: c_int = 140; +pub const _SC_HOST_NAME_MAX: c_int = 126; +pub const _SC_MONOTONIC_CLOCK: c_int = 141; +pub const _SC_READER_WRITER_LOCKS: c_int = 142; +pub const _SC_REGEXP: c_int = 127; +pub const _SC_SHELL: c_int = 128; +pub const _SC_SPAWN: c_int = 143; +pub const _SC_SPIN_LOCKS: c_int = 144; +pub const _SC_SPORADIC_SERVER: c_int = 145; +pub const _SC_SS_REPL_MAX: c_int = 156; +pub const _SC_SYMLOOP_MAX: c_int = 129; +pub const _SC_THREAD_CPUTIME: c_int = 146; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 147; +pub const _SC_TIMEOUTS: c_int = 148; +pub const _SC_TRACE: c_int = 149; +pub const _SC_TRACE_EVENT_FILTER: c_int = 150; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 157; +pub const _SC_TRACE_INHERIT: c_int = 151; +pub const _SC_TRACE_LOG: c_int = 152; +pub const _SC_TRACE_NAME_MAX: c_int = 158; +pub const _SC_TRACE_SYS_MAX: c_int = 159; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 160; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 153; +pub const _SC_V6_ILP32_OFF32: c_int = 121; +pub const _SC_V6_ILP32_OFFBIG: c_int = 122; +pub const _SC_V6_LP64_OFF64: c_int = 123; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 124; +pub const _SC_XOPEN_STREAMS: c_int = 125; +pub const _SC_IPV6: c_int = 154; +pub const _SC_RAW_SOCKETS: c_int = 155; + +// utmp.h +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const OLD_TIME: c_short = 3; +pub const NEW_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + CMSG_FIRSTHDR(mhdr) + } else { + if (cmsg as usize + (*cmsg).cmsg_len as usize + size_of::()) + > ((*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize) + { + core::ptr::null_mut::() + } else { + // AIX does not have any alignment/padding for ancillary data, so we don't need _CMSG_ALIGN here. + (cmsg as usize + (*cmsg).cmsg_len as usize) as *mut cmsghdr + } + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(size_of::() as isize) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + size_of::() as c_uint + length + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + size_of::() as c_uint + length + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of::() * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return; + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of::() * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let bits = size_of::() * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0; + } +} + +safe_f! { + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & _W_STOPPED) != 0 + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + if WIFSTOPPED(status) { + (((status as c_uint) >> 8) & 0xff) as c_int + } else { + -1 + } + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0xFF) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + if WIFEXITED(status) { + (((status as c_uint) >> 8) & 0xff) as c_int + } else { + -1 + } + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + !WIFEXITED(status) && !WIFSTOPPED(status) + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + if WIFSIGNALED(status) { + (((status as c_uint) >> 16) & 0xff) as c_int + } else { + -1 + } + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + (status & WCONTINUED) != 0 + } + + // AIX doesn't have native WCOREDUMP. + pub const fn WCOREDUMP(_status: c_int) -> bool { + false + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + let x = dev >> 16; + x as c_uint + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + let y = dev & 0xFFFF; + y as c_uint + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= major << 16; + dev |= minor; + dev + } +} + +#[link(name = "thread")] +extern "C" { + pub fn thr_kill(id: thread_t, sig: c_int) -> c_int; + pub fn thr_self() -> thread_t; +} + +#[link(name = "pthread")] +extern "C" { + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + + pub fn pthread_attr_getdetachstate( + attr: *const crate::pthread_attr_t, + detachstate: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + + pub fn pthread_attr_getinheritsched( + attr: *const crate::pthread_attr_t, + inheritsched: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_getschedparam( + attr: *const crate::pthread_attr_t, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_attr_getstackaddr( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + ) -> c_int; + + pub fn pthread_attr_getschedpolicy( + attr: *const crate::pthread_attr_t, + policy: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_getscope( + attr: *const crate::pthread_attr_t, + contentionscope: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + + pub fn pthread_attr_setinheritsched( + attr: *mut crate::pthread_attr_t, + inheritsched: c_int, + ) -> c_int; + + pub fn pthread_attr_setschedparam( + attr: *mut crate::pthread_attr_t, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_attr_setschedpolicy(attr: *mut crate::pthread_attr_t, policy: c_int) -> c_int; + + pub fn pthread_attr_setscope(attr: *mut crate::pthread_attr_t, contentionscope: c_int) + -> c_int; + + pub fn pthread_attr_setstack( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + stacksize: size_t, + ) -> c_int; + + pub fn pthread_attr_setstackaddr( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + ) -> c_int; + + pub fn pthread_barrierattr_destroy(attr: *mut crate::pthread_barrierattr_t) -> c_int; + + pub fn pthread_barrierattr_getpshared( + attr: *const crate::pthread_barrierattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_barrierattr_init(attr: *mut crate::pthread_barrierattr_t) -> c_int; + + pub fn pthread_barrierattr_setpshared( + attr: *mut crate::pthread_barrierattr_t, + pshared: c_int, + ) -> c_int; + + pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int; + + pub fn pthread_barrier_init( + barrier: *mut pthread_barrier_t, + attr: *const crate::pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + + pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int; + + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + + pub fn pthread_cleanup_pop(execute: c_int) -> c_void; + + pub fn pthread_cleanup_push( + routine: Option, + arg: *mut c_void, + ) -> c_void; + + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + + pub fn pthread_create( + thread: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + start_routine: extern "C" fn(*mut c_void) -> *mut c_void, + arg: *mut c_void, + ) -> c_int; + + pub fn pthread_getconcurrency() -> c_int; + + pub fn pthread_getcpuclockid( + thread_id: crate::pthread_t, + clock_id: *mut crate::clockid_t, + ) -> c_int; + + pub fn pthread_getschedparam( + thread: crate::pthread_t, + policy: *mut c_int, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + + pub fn pthread_mutexattr_getprioceiling( + attr: *const crate::pthread_mutexattr_t, + prioceiling: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_getprotocol( + attr: *const pthread_mutexattr_t, + protocol: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_getrobust( + attr: *const crate::pthread_mutexattr_t, + robust: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_gettype( + attr: *const crate::pthread_mutexattr_t, + _type: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_setprioceiling( + attr: *mut crate::pthread_mutexattr_t, + prioceiling: c_int, + ) -> c_int; + + pub fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int; + + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + + pub fn pthread_mutexattr_setrobust( + attr: *mut crate::pthread_mutexattr_t, + robust: c_int, + ) -> c_int; + + pub fn pthread_mutex_consistent(mutex: *mut crate::pthread_mutex_t) -> c_int; + + pub fn pthread_mutex_getprioceiling( + mutex: *const crate::pthread_mutex_t, + prioceiling: *mut c_int, + ) -> c_int; + + pub fn pthread_mutex_setprioceiling( + mutex: *mut crate::pthread_mutex_t, + prioceiling: c_int, + old_ceiling: *mut c_int, + ) -> c_int; + + pub fn pthread_mutex_timedlock( + mutex: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + + pub fn pthread_once( + once_control: *mut crate::pthread_once_t, + init_routine: Option, + ) -> c_int; + + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, pshared: c_int) -> c_int; + + pub fn pthread_rwlock_timedrdlock( + rwlock: *mut crate::pthread_rwlock_t, + abstime: *const crate::timespec, + ) -> c_int; + + pub fn pthread_rwlock_timedwrlock( + rwlock: *mut crate::pthread_rwlock_t, + abstime: *const crate::timespec, + ) -> c_int; + + pub fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int; + pub fn pthread_setcanceltype(_type: c_int, oldtype: *mut c_int) -> c_int; + + pub fn pthread_setconcurrency(new_level: c_int) -> c_int; + + pub fn pthread_setschedparam( + thread: crate::pthread_t, + policy: c_int, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_setschedprio(thread: crate::pthread_t, prio: c_int) -> c_int; + + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int; + + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_testcancel() -> c_void; +} + +#[link(name = "iconv")] +extern "C" { + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + pub fn iconv_close(cd: iconv_t) -> c_int; + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; +} + +extern "C" { + pub fn acct(filename: *mut c_char) -> c_int; + #[link_name = "_posix_aio_cancel"] + pub fn aio_cancel(fildes: c_int, aiocbp: *mut crate::aiocb) -> c_int; + #[link_name = "_posix_aio_error"] + pub fn aio_error(aiocbp: *const crate::aiocb) -> c_int; + #[link_name = "_posix_aio_fsync"] + pub fn aio_fsync(op: c_int, aiocbp: *mut crate::aiocb) -> c_int; + #[link_name = "_posix_aio_read"] + pub fn aio_read(aiocbp: *mut crate::aiocb) -> c_int; + #[link_name = "_posix_aio_return"] + pub fn aio_return(aiocbp: *mut crate::aiocb) -> ssize_t; + #[link_name = "_posix_aio_suspend"] + pub fn aio_suspend( + list: *const *const crate::aiocb, + nent: c_int, + timeout: *const crate::timespec, + ) -> c_int; + #[link_name = "_posix_aio_write"] + pub fn aio_write(aiocbp: *mut crate::aiocb) -> c_int; + pub fn basename(path: *mut c_char) -> *mut c_char; + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + pub fn brk(addr: *mut c_void) -> c_int; + pub fn clearenv() -> c_int; + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + pub fn clock_settime(clock_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn creat64(path: *const c_char, mode: mode_t) -> c_int; + pub fn ctermid(s: *mut c_char) -> *mut c_char; + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn drand48() -> c_double; + pub fn duplocale(arg1: crate::locale_t) -> crate::locale_t; + pub fn endgrent(); + pub fn endmntent(streamp: *mut crate::FILE) -> c_int; + pub fn endpwent(); + pub fn endutent(); + pub fn endutxent(); + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn fattach(fildes: c_int, path: *const c_char) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn ffs(value: c_int) -> c_int; + pub fn ffsl(value: c_long) -> c_int; + pub fn ffsll(value: c_longlong) -> c_int; + pub fn fgetgrent(file: *mut crate::FILE) -> *mut crate::group; + pub fn fgetpos64(stream: *mut crate::FILE, ptr: *mut fpos64_t) -> c_int; + pub fn fgetpwent(file: *mut crate::FILE) -> *mut crate::passwd; + pub fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn freelocale(loc: crate::locale_t); + pub fn freopen64( + filename: *const c_char, + mode: *const c_char, + file: *mut crate::FILE, + ) -> *mut crate::FILE; + pub fn fseeko64(stream: *mut crate::FILE, offset: off64_t, whence: c_int) -> c_int; + pub fn fsetpos64(stream: *mut crate::FILE, ptr: *const fpos64_t) -> c_int; + pub fn fstat64(fildes: c_int, buf: *mut stat64) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn fstatfs64(fd: c_int, buf: *mut statfs64) -> c_int; + pub fn fstatvfs64(fd: c_int, buf: *mut statvfs64) -> c_int; + pub fn ftello64(stream: *mut crate::FILE) -> off64_t; + pub fn ftok(path: *const c_char, id: c_int) -> crate::key_t; + pub fn ftruncate64(fd: c_int, length: off64_t) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn getcontext(ucp: *mut ucontext_t) -> c_int; + pub fn getdomainname(name: *mut c_char, len: c_int) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrent() -> *mut crate::group; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + #[link_name = "_posix_getgrgid_r"] + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + #[link_name = "_posix_getgrnam_r"] + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrset(user: *const c_char) -> *mut c_char; + pub fn gethostid() -> c_long; + pub fn getmntent(stream: *mut crate::FILE) -> *mut crate::mntent; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: size_t, + host: *mut c_char, + hostlen: size_t, + serv: *mut c_char, + servlen: size_t, + flags: c_int, + ) -> c_int; + pub fn getpagesize() -> c_int; + pub fn getpeereid(socket: c_int, euid: *mut crate::uid_t, egid: *mut crate::gid_t) -> c_int; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn getpwent() -> *mut crate::passwd; + #[link_name = "_posix_getpwnam_r"] + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + #[link_name = "_posix_getpwuid_r"] + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn getrlimit64(resource: c_int, rlim: *mut rlimit64) -> c_int; + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn getitimer(which: c_int, curr_value: *mut crate::itimerval) -> c_int; + pub fn getutent() -> *mut utmp; + pub fn getutid(u: *const utmp) -> *mut utmp; + pub fn getutline(u: *const utmp) -> *mut utmp; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + pub fn hasmntopt(mnt: *const crate::mntent, opt: *const c_char) -> *mut c_char; + pub fn hcreate(nelt: size_t) -> c_int; + pub fn hdestroy(); + pub fn hsearch(entry: entry, action: ACTION) -> *mut entry; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn if_nameindex() -> *mut if_nameindex; + pub fn initgroups(name: *const c_char, basegid: crate::gid_t) -> c_int; + pub fn ioctl(fildes: c_int, request: c_int, ...) -> c_int; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn lcong48(p: *mut c_ushort); + pub fn lfind( + key: *const c_void, + base: *const c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + #[link_name = "_posix_lio_listio"] + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nent: c_int, + sevp: *mut sigevent, + ) -> c_int; + pub fn loadquery(flags: c_int, buf: *mut c_void, buflen: c_uint, ...) -> c_int; + pub fn lpar_get_info(command: c_int, buf: *mut c_void, bufsize: size_t) -> c_int; + pub fn lpar_set_resources(id: c_int, resource: *mut c_void) -> c_int; + pub fn lrand48() -> c_long; + pub fn lsearch( + key: *const c_void, + base: *mut c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + pub fn lseek64(fd: c_int, offset: off64_t, whence: c_int) -> off64_t; + pub fn lstat64(path: *const c_char, buf: *mut stat64) -> c_int; + pub fn madvise(addr: caddr_t, len: size_t, advice: c_int) -> c_int; + pub fn makecontext(ucp: *mut crate::ucontext_t, func: extern "C" fn(), argc: c_int, ...); + pub fn mallinfo() -> crate::mallinfo; + pub fn mallopt(param: c_int, value: c_int) -> c_int; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn memset_s(s: *mut c_void, smax: size_t, c: c_int, n: size_t) -> c_int; + pub fn mincore(addr: caddr_t, len: size_t, vec: *mut c_char) -> c_int; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn mount(device: *const c_char, path: *const c_char, flags: c_int) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_notify(mqd: crate::mqd_t, notification: *const crate::sigevent) -> c_int; + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mrand48() -> c_long; + pub fn msgctl(msqid: c_int, cmd: c_int, buf: *mut msqid_ds) -> c_int; + pub fn msgget(key: crate::key_t, msgflg: c_int) -> c_int; + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + pub fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: size_t, msgflg: c_int) -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + pub fn nl_langinfo_l(item: crate::nl_item, loc: crate::locale_t) -> *mut c_char; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn open64(path: *const c_char, oflag: c_int, ...) -> c_int; + pub fn pollset_create(maxfd: c_int) -> pollset_t; + pub fn pollset_ctl(ps: pollset_t, pollctl_array: *mut poll_ctl, array_length: c_int) -> c_int; + pub fn pollset_destroy(ps: pollset_t) -> c_int; + pub fn pollset_poll( + ps: pollset_t, + polldata_array: *mut crate::pollfd, + array_length: c_int, + timeout: c_int, + ) -> c_int; + pub fn pollset_query(ps: pollset_t, pollfd_query: *mut crate::pollfd) -> c_int; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn posix_fadvise64(fd: c_int, offset: off64_t, len: off64_t, advise: c_int) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: off64_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: offset_t) -> ssize_t; + pub fn ptrace64( + request: c_int, + id: c_longlong, + addr: c_longlong, + data: c_int, + buff: *mut c_int, + ) -> c_int; + pub fn pututline(u: *const utmp) -> *mut utmp; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: off64_t) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: offset_t) + -> ssize_t; + pub fn quotactl(cmd: *mut c_char, special: c_int, id: c_int, data: caddr_t) -> c_int; + pub fn rand() -> c_int; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + // AIX header socket.h maps recvfrom() to nrecvfrom() + #[link_name = "nrecvfrom"] + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *mut crate::timespec, + ) -> c_int; + // AIX header socket.h maps recvmsg() to nrecvmsg(). + #[link_name = "nrecvmsg"] + pub fn recvmsg(sockfd: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t; + pub fn regcomp(preg: *mut regex_t, pattern: *const c_char, cflags: c_int) -> c_int; + pub fn regerror( + errcode: c_int, + preg: *const crate::regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + pub fn regexec( + preg: *const regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + pub fn regfree(preg: *mut regex_t); + pub fn sbrk(increment: intptr_t) -> *mut c_void; + pub fn sched_getparam(pid: crate::pid_t, param: *mut sched_param) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sctp_opt_info( + sd: c_int, + id: crate::sctp_assoc_t, + opt: c_int, + arg_size: *mut c_void, + size: *mut size_t, + ) -> c_int; + pub fn sctp_peeloff(s: c_int, id: *mut c_uint) -> c_int; + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + pub fn semget(key: crate::key_t, nsems: c_int, semflag: c_int) -> c_int; + pub fn semop(semid: c_int, sops: *mut sembuf, nsops: size_t) -> c_int; + pub fn send_file(socket: *mut c_int, iobuf: *mut sf_parms, flags: c_uint) -> ssize_t; + pub fn sendmmsg(sockfd: c_int, msgvec: *mut mmsghdr, vlen: c_uint, flags: c_int) -> c_int; + // AIX header socket.h maps sendmsg() to nsendmsg(). + #[link_name = "nsendmsg"] + pub fn sendmsg(sockfd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t; + pub fn setcontext(ucp: *const ucontext_t) -> c_int; + pub fn setdomainname(name: *const c_char, len: c_int) -> c_int; + pub fn setgroups(ngroups: c_int, ptr: *const crate::gid_t) -> c_int; + pub fn setgrent(); + pub fn sethostid(hostid: c_int) -> c_int; + pub fn sethostname(name: *const c_char, len: c_int) -> c_int; + pub fn setmntent(filename: *const c_char, ty: *const c_char) -> *mut crate::FILE; + pub fn setpriority(which: c_int, who: id_t, priority: c_int) -> c_int; + pub fn setpwent(); + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + pub fn setrlimit64(resource: c_int, rlim: *const rlimit64) -> c_int; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + pub fn setitimer( + which: c_int, + new_value: *const crate::itimerval, + old_value: *mut crate::itimerval, + ) -> c_int; + pub fn setutent(); + pub fn setutxent(); + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + pub fn shmget(key: key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + pub fn splice(socket1: c_int, socket2: c_int, flags: c_int) -> c_int; + pub fn srand(seed: c_uint); + pub fn srand48(seed: c_long); + pub fn stat64(path: *const c_char, buf: *mut stat64) -> c_int; + pub fn stat64at(dirfd: c_int, path: *const c_char, buf: *mut stat64, flags: c_int) -> c_int; + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn statfs64(path: *const c_char, buf: *mut statfs64) -> c_int; + pub fn statvfs64(path: *const c_char, buf: *mut statvfs64) -> c_int; + pub fn statx(path: *const c_char, buf: *mut stat, length: c_int, command: c_int) -> c_int; + pub fn strcasecmp_l( + string1: *const c_char, + string2: *const c_char, + locale: crate::locale_t, + ) -> c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn strftime( + arg1: *mut c_char, + arg2: size_t, + arg3: *const c_char, + arg4: *const tm, + ) -> size_t; + pub fn strncasecmp_l( + string1: *const c_char, + string2: *const c_char, + length: size_t, + locale: crate::locale_t, + ) -> c_int; + pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut crate::tm) -> *mut c_char; + pub fn strsep(string: *mut *mut c_char, delim: *const c_char) -> *mut c_char; + pub fn swapcontext(uocp: *mut ucontext_t, ucp: *const ucontext_t) -> c_int; + pub fn swapoff(path: *const c_char) -> c_int; + pub fn swapon(path: *const c_char) -> c_int; + pub fn sync(); + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn timer_create( + clockid: crate::clockid_t, + sevp: *mut crate::sigevent, + timerid: *mut crate::timer_t, + ) -> c_int; + pub fn timer_delete(timerid: timer_t) -> c_int; + pub fn timer_getoverrun(timerid: timer_t) -> c_int; + pub fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int; + pub fn timer_settime( + timerid: crate::timer_t, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + pub fn truncate64(path: *const c_char, length: off64_t) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn updwtmp(file: *const c_char, u: *const utmp); + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn utmpname(file: *const c_char) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + // Use AIX thread-safe version errno. + pub fn _Errno() -> *mut c_int; +} + +cfg_if! { + if #[cfg(target_arch = "powerpc64")] { + mod powerpc64; + pub use self::powerpc64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/aix/powerpc64.rs b/deps/crates/vendor/libc/src/unix/aix/powerpc64.rs new file mode 100644 index 00000000000000..0862cbf854d3c6 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/aix/powerpc64.rs @@ -0,0 +1,427 @@ +use crate::off_t; +use crate::prelude::*; + +// Define lock_data_instrumented as an empty enum +extern_ty! { + pub enum lock_data_instrumented {} +} + +s! { + pub struct sigset_t { + pub ss_set: [c_ulong; 4], + } + + pub struct fd_set { + pub fds_bits: [c_long; 1024], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_sysid: c_uint, + pub l_pid: crate::pid_t, + pub l_vfs: c_int, + pub l_start: off_t, + pub l_len: off_t, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_basetype: [c_char; 16], + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub f_fstr: [c_char; 32], + pub f_filler: [c_ulong; 16], + } + + pub struct pthread_rwlock_t { + __rw_word: [c_long; 10], + } + + pub struct pthread_cond_t { + __cv_word: [c_long; 6], + } + + pub struct pthread_mutex_t { + __mt_word: [c_long; 8], + } + + pub struct pthread_once_t { + __on_word: [c_long; 9], + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_flag: c_ushort, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_ssize: c_int, + pub st_atim: crate::st_timespec, + pub st_mtim: crate::st_timespec, + pub st_ctim: crate::st_timespec, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_vfstype: c_int, + pub st_vfs: c_uint, + pub st_type: c_uint, + pub st_gen: c_uint, + st_reserved: Padding<[c_uint; 9]>, + pub st_padto_ll: c_uint, + pub st_size: off_t, + } + + pub struct statfs { + pub f_version: c_int, + pub f_type: c_int, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsblkcnt_t, + pub f_ffree: crate::fsblkcnt_t, + pub f_fsid: crate::fsid64_t, + pub f_vfstype: c_int, + pub f_fsize: c_ulong, + pub f_vfsnumber: c_int, + pub f_vfsoff: c_int, + pub f_vfslen: c_int, + pub f_vfsvers: c_int, + pub f_fname: [c_char; 32], + pub f_fpack: [c_char; 32], + pub f_name_max: c_int, + } + + pub struct aiocb { + pub aio_lio_opcode: c_int, + pub aio_fildes: c_int, + pub aio_word1: c_int, + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_return: ssize_t, + pub aio_errno: c_int, + pub aio_nbytes: size_t, + pub aio_reqprio: c_int, + pub aio_sigevent: crate::sigevent, + pub aio_word2: c_int, + pub aio_fp: c_int, + pub aio_handle: *mut aiocb, + aio_reserved: Padding<[c_uint; 2]>, + pub aio_sigev_tid: c_long, + } + + pub struct __vmxreg_t { + __v: [c_uint; 4], + } + + pub struct __vmx_context_t { + pub __vr: [crate::__vmxreg_t; 32], + pub __pad1: [c_uint; 3], + pub __vscr: c_uint, + pub __vrsave: c_uint, + pub __pad2: [c_uint; 3], + } + + pub struct __vsx_context_t { + pub __vsr_dw1: [c_ulonglong; 32], + } + + pub struct __tm_context_t { + pub vmx: crate::__vmx_context_t, + pub vsx: crate::__vsx_context_t, + pub gpr: [c_ulonglong; 32], + pub lr: c_ulonglong, + pub ctr: c_ulonglong, + pub cr: c_uint, + pub xer: c_uint, + pub amr: c_ulonglong, + pub texasr: c_ulonglong, + pub tfiar: c_ulonglong, + pub tfhar: c_ulonglong, + pub ppr: c_ulonglong, + pub dscr: c_ulonglong, + pub tar: c_ulonglong, + pub fpscr: c_uint, + pub fpscrx: c_uint, + pub fpr: [fpreg_t; 32], + pub tmcontext: c_char, + pub tmstate: c_char, + pub prevowner: c_char, + pub pad: [c_char; 5], + } + + pub struct __context64 { + pub gpr: [c_ulonglong; 32], + pub msr: c_ulonglong, + pub iar: c_ulonglong, + pub lr: c_ulonglong, + pub ctr: c_ulonglong, + pub cr: c_uint, + pub xer: c_uint, + pub fpscr: c_uint, + pub fpscrx: c_uint, + pub except: [c_ulonglong; 1], + pub fpr: [fpreg_t; 32], + pub fpeu: c_char, + pub fpinfo: c_char, + pub fpscr24_31: c_char, + pub pad: [c_char; 1], + pub excp_type: c_int, + } + + pub struct mcontext_t { + pub jmp_context: __context64, + } + + pub struct __extctx_t { + pub __flags: c_uint, + pub __rsvd1: [c_uint; 3], + pub __vmx: crate::__vmx_context_t, + pub __ukeys: [c_uint; 2], + pub __vsx: crate::__vsx_context_t, + pub __tm: crate::__tm_context_t, + __reserved: Padding<[c_char; 1860]>, + pub __extctx_magic: c_int, + } + + pub struct ucontext_t { + pub __sc_onstack: c_int, + pub uc_sigmask: crate::sigset_t, + pub __sc_uerror: c_int, + pub uc_mcontext: crate::mcontext_t, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub __extctx: *mut crate::__extctx_t, + pub __extctx_magic: c_int, + pub __pad: [c_int; 1], + } + + pub struct utmpx { + pub ut_user: [c_char; 256], + pub ut_id: [c_char; 14], + pub ut_line: [c_char; 64], + pub ut_pid: crate::pid_t, + pub ut_type: c_short, + pub ut_tv: crate::timeval, + pub ut_host: [c_char; 256], + pub __dbl_word_pad: c_int, + pub __reservedA: [c_int; 2], + pub __reservedV: [c_int; 6], + } + + pub struct pthread_spinlock_t { + pub __sp_word: [c_long; 3], + } + + pub struct pthread_barrier_t { + pub __br_word: [c_long; 5], + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_first: c_uint, + pub msg_last: c_uint, + pub msg_cbytes: c_uint, + pub msg_qnum: c_uint, + pub msg_qbytes: c_ulong, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub msg_rwait: c_int, + pub msg_wwait: c_int, + pub msg_reqevents: c_ushort, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub si_pid: crate::pid_t, + pub si_uid: crate::uid_t, + pub si_status: c_int, + pub si_addr: *mut c_void, + pub si_band: c_long, + pub si_value: crate::sigval, + pub __si_flags: c_int, + pub __pad: [c_int; 3], + } + + pub struct pollfd_ext { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + pub data: __pollfd_ext_u, + } +} + +s_no_extra_traits! { + pub union _kernel_simple_lock { + pub _slock: c_long, + pub _slockp: *mut lock_data_instrumented, + } + + pub struct fileops_t { + pub fo_rw: Option< + extern "C" fn( + file: *mut file, + rw: crate::uio_rw, + io: *mut c_void, + ext: c_long, + secattr: *mut c_void, + ) -> c_int, + >, + pub fo_ioctl: Option< + extern "C" fn( + file: *mut file, + a: c_long, + b: crate::caddr_t, + c: c_long, + d: c_long, + ) -> c_int, + >, + pub fo_select: Option< + extern "C" fn(file: *mut file, a: c_int, b: *mut c_ushort, c: extern "C" fn()) -> c_int, + >, + pub fo_close: Option c_int>, + pub fo_fstat: Option c_int>, + } + + pub struct file { + pub f_flag: c_long, + pub f_count: c_int, + pub f_options: c_short, + pub f_type: c_short, + // Should be pointer to 'vnode' + pub f_data: *mut c_void, + pub f_offset: c_longlong, + pub f_dir_off: c_long, + // Should be pointer to 'cred' + pub f_cred: *mut c_void, + pub f_lock: _kernel_simple_lock, + pub f_offset_lock: _kernel_simple_lock, + pub f_vinfo: crate::caddr_t, + pub f_ops: *mut fileops_t, + pub f_parentp: crate::caddr_t, + pub f_fnamep: crate::caddr_t, + pub f_fdata: [c_char; 160], + } + + pub union __ld_info_file { + pub _ldinfo_fd: c_int, + pub _ldinfo_fp: *mut file, + pub _core_offset: c_long, + } + + pub struct ld_info { + pub ldinfo_next: c_uint, + pub ldinfo_flags: c_uint, + pub _file: __ld_info_file, + pub ldinfo_textorg: *mut c_void, + pub ldinfo_textsize: c_ulong, + pub ldinfo_dataorg: *mut c_void, + pub ldinfo_datasize: c_ulong, + pub ldinfo_filename: [c_char; 2], + } + + pub union __pollfd_ext_u { + pub addr: *mut c_void, + pub data32: u32, + pub data: u64, + } + + pub struct fpreg_t { + pub d: c_double, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + self.si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __pollfd_ext_u { + fn eq(&self, other: &__pollfd_ext_u) -> bool { + unsafe { + self.addr == other.addr + && self.data32 == other.data32 + && self.data == other.data + } + } + } + impl Eq for __pollfd_ext_u {} + impl hash::Hash for __pollfd_ext_u { + fn hash(&self, state: &mut H) { + unsafe { + self.addr.hash(state); + self.data.hash(state); + self.data32.hash(state); + } + } + } + + impl PartialEq for fpreg_t { + fn eq(&self, other: &fpreg_t) -> bool { + self.d == other.d + } + } + impl Eq for fpreg_t {} + impl hash::Hash for fpreg_t { + fn hash(&self, state: &mut H) { + let d: u64 = self.d.to_bits(); + d.hash(state); + } + } + } +} + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __mt_word: [0, 2, 0, 0, 0, 0, 0, 0], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __cv_word: [0, 0, 0, 0, 2, 0], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __rw_word: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0], +}; + +pub const PTHREAD_ONCE_INIT: pthread_once_t = pthread_once_t { + __on_word: [0, 0, 0, 0, 0, 2, 0, 0, 0], +}; + +pub const RLIM_INFINITY: c_ulong = 0x7fffffffffffffff; + +extern "C" { + pub fn getsystemcfg(label: c_int) -> c_ulong; +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/apple/b32/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/apple/b32/mod.rs new file mode 100644 index 00000000000000..ab0c94ef4c2c29 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/apple/b32/mod.rs @@ -0,0 +1,73 @@ +//! 32-bit specific Apple (ios/darwin) definitions + +use crate::prelude::*; + +pub type boolean_t = c_int; + +s! { + pub struct if_data { + pub ifi_type: c_uchar, + pub ifi_typelen: c_uchar, + pub ifi_physical: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_recvquota: c_uchar, + pub ifi_xmitquota: c_uchar, + pub ifi_unused1: c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_baudrate: u32, + pub ifi_ipackets: u32, + pub ifi_ierrors: u32, + pub ifi_opackets: u32, + pub ifi_oerrors: u32, + pub ifi_collisions: u32, + pub ifi_ibytes: u32, + pub ifi_obytes: u32, + pub ifi_imcasts: u32, + pub ifi_omcasts: u32, + pub ifi_iqdrops: u32, + pub ifi_noproto: u32, + pub ifi_recvtiming: u32, + pub ifi_xmittiming: u32, + pub ifi_lastchange: crate::timeval, + pub ifi_unused2: u32, + pub ifi_hwassist: u32, + pub ifi_reserved1: u32, + pub ifi_reserved2: u32, + } + + pub struct bpf_hdr { + pub bh_tstamp: crate::timeval, + pub bh_caplen: u32, + pub bh_datalen: u32, + pub bh_hdrlen: c_ushort, + } + + pub struct malloc_zone_t { + __private: [crate::uintptr_t; 18], // FIXME(macos): keeping private for now + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 2], + } +} + +#[doc(hidden)] +#[deprecated(since = "0.2.55")] +pub const NET_RT_MAXID: c_int = 10; + +pub const TIOCTIMESTAMP: c_ulong = 0x40087459; +pub const TIOCDCDTIMESTAMP: c_ulong = 0x40087458; + +pub const BIOCSETF: c_ulong = 0x80084267; +pub const BIOCSRTIMEOUT: c_ulong = 0x8008426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4008426e; +pub const BIOCSETFNR: c_ulong = 0x8008427e; + +extern "C" { + pub fn exchangedata(path1: *const c_char, path2: *const c_char, options: c_ulong) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/apple/b64/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/aarch64/mod.rs new file mode 100644 index 00000000000000..b5cbe8ff5175f1 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/aarch64/mod.rs @@ -0,0 +1,15 @@ +use crate::prelude::*; + +pub type boolean_t = c_int; + +s! { + pub struct malloc_zone_t { + __private: [crate::uintptr_t; 18], // FIXME(macos): needs arm64 auth pointers support + } +} + +s_no_extra_traits! { + pub struct max_align_t { + priv_: f64, + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/apple/b64/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/mod.rs new file mode 100644 index 00000000000000..5ccf65abb840eb --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/mod.rs @@ -0,0 +1,78 @@ +//! 64-bit specific Apple (ios/darwin) definitions + +use crate::prelude::*; + +s! { + #[derive(Default)] + pub struct timeval32 { + pub tv_sec: i32, + pub tv_usec: i32, + } + + pub struct if_data { + pub ifi_type: c_uchar, + pub ifi_typelen: c_uchar, + pub ifi_physical: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_recvquota: c_uchar, + pub ifi_xmitquota: c_uchar, + pub ifi_unused1: c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_baudrate: u32, + pub ifi_ipackets: u32, + pub ifi_ierrors: u32, + pub ifi_opackets: u32, + pub ifi_oerrors: u32, + pub ifi_collisions: u32, + pub ifi_ibytes: u32, + pub ifi_obytes: u32, + pub ifi_imcasts: u32, + pub ifi_omcasts: u32, + pub ifi_iqdrops: u32, + pub ifi_noproto: u32, + pub ifi_recvtiming: u32, + pub ifi_xmittiming: u32, + pub ifi_lastchange: timeval32, + pub ifi_unused2: u32, + pub ifi_hwassist: u32, + pub ifi_reserved1: u32, + pub ifi_reserved2: u32, + } + + pub struct bpf_hdr { + pub bh_tstamp: crate::timeval32, + pub bh_caplen: u32, + pub bh_datalen: u32, + pub bh_hdrlen: c_ushort, + } +} + +#[doc(hidden)] +#[deprecated(since = "0.2.55")] +pub const NET_RT_MAXID: c_int = 11; + +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; +pub const TIOCDCDTIMESTAMP: c_ulong = 0x40107458; + +pub const BIOCSETF: c_ulong = 0x80104267; +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; +pub const BIOCSETFNR: c_ulong = 0x8010427e; + +extern "C" { + pub fn exchangedata(path1: *const c_char, path2: *const c_char, options: c_uint) -> c_int; +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/apple/b64/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/x86_64/mod.rs new file mode 100644 index 00000000000000..dac8c9e3d336da --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/apple/b64/x86_64/mod.rs @@ -0,0 +1,77 @@ +use crate::prelude::*; + +pub type boolean_t = c_uint; + +s! { + pub struct malloc_introspection_t { + _private: [crate::uintptr_t; 16], // FIXME(macos): keeping private for now + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct malloc_zone_t { + _reserved1: Padding<*mut c_void>, + _reserved2: Padding<*mut c_void>, + pub size: + Option size_t>, + pub malloc: + Option *mut c_void>, + pub calloc: Option< + unsafe extern "C" fn( + zone: *mut malloc_zone_t, + num_items: size_t, + size: size_t, + ) -> *mut c_void, + >, + pub valloc: + Option *mut c_void>, + pub free: Option, + pub realloc: Option< + unsafe extern "C" fn( + zone: *mut malloc_zone_t, + ptr: *mut c_void, + size: size_t, + ) -> *mut c_void, + >, + pub destroy: Option, + pub zone_name: *const c_char, + pub batch_malloc: Option< + unsafe extern "C" fn( + zone: *mut malloc_zone_t, + size: size_t, + results: *mut *mut c_void, + num_requested: c_uint, + ) -> c_uint, + >, + pub batch_free: Option< + unsafe extern "C" fn( + zone: *mut malloc_zone_t, + to_be_freed: *mut *mut c_void, + num_to_be_freed: c_uint, + ), + >, + pub introspect: *mut malloc_introspection_t, + pub version: c_uint, + pub memalign: Option< + unsafe extern "C" fn( + zone: *mut malloc_zone_t, + alignment: size_t, + size: size_t, + ) -> *mut c_void, + >, + pub free_definite_size: + Option, + pub pressure_relief: + Option size_t>, + pub claimed_address: Option< + unsafe extern "C" fn(zone: *mut malloc_zone_t, ptr: *mut c_void) -> crate::boolean_t, + >, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 2], + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/apple/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/apple/mod.rs new file mode 100644 index 00000000000000..ff0e24a90a1d16 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/apple/mod.rs @@ -0,0 +1,5190 @@ +//! Apple (ios/darwin)-specific definitions +//! +//! This covers *-apple-* triples currently + +use crate::prelude::*; +use crate::{ + cmsghdr, + off_t, +}; + +pub type wchar_t = i32; +pub type clock_t = c_ulong; +pub type time_t = c_long; +pub type suseconds_t = i32; +pub type dev_t = i32; +pub type ino_t = u64; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type blksize_t = i32; +pub type rlim_t = u64; +pub type sigset_t = u32; +pub type clockid_t = c_uint; +pub type fsblkcnt_t = c_uint; +pub type fsfilcnt_t = c_uint; +pub type speed_t = c_ulong; +pub type tcflag_t = c_ulong; +pub type nl_item = c_int; +pub type id_t = c_uint; +pub type sem_t = c_int; +pub type idtype_t = c_uint; +pub type integer_t = c_int; +pub type cpu_type_t = integer_t; +pub type cpu_subtype_t = integer_t; +pub type natural_t = u32; +pub type mach_msg_type_number_t = natural_t; +pub type kern_return_t = c_int; +pub type uuid_t = [u8; 16]; +pub type task_info_t = *mut integer_t; +pub type host_info_t = *mut integer_t; +pub type task_flavor_t = natural_t; +pub type rusage_info_t = *mut c_void; +pub type vm_offset_t = crate::uintptr_t; +pub type vm_size_t = crate::uintptr_t; +pub type vm_address_t = vm_offset_t; +pub type quad_t = i64; +pub type u_quad_t = u64; + +pub type posix_spawnattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_void; +pub type key_t = c_int; +pub type shmatt_t = c_ushort; + +pub type sae_associd_t = u32; +pub type sae_connid_t = u32; + +pub type mach_port_t = c_uint; +pub type host_t = c_uint; +pub type host_flavor_t = integer_t; +pub type host_info64_t = *mut integer_t; +pub type processor_flavor_t = c_int; +pub type thread_flavor_t = natural_t; +pub type thread_inspect_t = crate::mach_port_t; +pub type thread_act_t = crate::mach_port_t; +pub type thread_act_array_t = *mut crate::thread_act_t; +pub type policy_t = c_int; +pub type mach_error_t = crate::kern_return_t; +pub type mach_vm_address_t = u64; +pub type mach_vm_offset_t = u64; +pub type mach_vm_size_t = u64; +pub type vm_map_t = crate::mach_port_t; +pub type mem_entry_name_port_t = crate::mach_port_t; +pub type memory_object_t = crate::mach_port_t; +pub type memory_object_offset_t = c_ulonglong; +pub type vm_inherit_t = c_uint; +pub type vm_prot_t = c_int; + +pub type ledger_t = crate::mach_port_t; +pub type ledger_array_t = *mut crate::ledger_t; + +pub type iconv_t = *mut c_void; + +// mach/host_info.h +pub type host_cpu_load_info_t = *mut host_cpu_load_info; +pub type host_cpu_load_info_data_t = host_cpu_load_info; + +// mach/processor_info.h +pub type processor_cpu_load_info_t = *mut processor_cpu_load_info; +pub type processor_cpu_load_info_data_t = processor_cpu_load_info; +pub type processor_basic_info_t = *mut processor_basic_info; +pub type processor_basic_info_data_t = processor_basic_info; +pub type processor_set_basic_info_data_t = processor_set_basic_info; +pub type processor_set_basic_info_t = *mut processor_set_basic_info; +pub type processor_set_load_info_data_t = processor_set_load_info; +pub type processor_set_load_info_t = *mut processor_set_load_info; +pub type processor_info_t = *mut integer_t; +pub type processor_info_array_t = *mut integer_t; + +pub type mach_task_basic_info_data_t = mach_task_basic_info; +pub type mach_task_basic_info_t = *mut mach_task_basic_info; +pub type task_thread_times_info_data_t = task_thread_times_info; +pub type task_thread_times_info_t = *mut task_thread_times_info; + +pub type thread_info_t = *mut integer_t; +pub type thread_basic_info_t = *mut thread_basic_info; +pub type thread_basic_info_data_t = thread_basic_info; +pub type thread_identifier_info_t = *mut thread_identifier_info; +pub type thread_identifier_info_data_t = thread_identifier_info; +pub type thread_extended_info_t = *mut thread_extended_info; +pub type thread_extended_info_data_t = thread_extended_info; + +pub type thread_t = crate::mach_port_t; +pub type thread_policy_flavor_t = natural_t; +pub type thread_policy_t = *mut integer_t; +pub type thread_latency_qos_t = integer_t; +pub type thread_throughput_qos_t = integer_t; +pub type thread_standard_policy_data_t = thread_standard_policy; +pub type thread_standard_policy_t = *mut thread_standard_policy; +pub type thread_extended_policy_data_t = thread_extended_policy; +pub type thread_extended_policy_t = *mut thread_extended_policy; +pub type thread_time_constraint_policy_data_t = thread_time_constraint_policy; +pub type thread_time_constraint_policy_t = *mut thread_time_constraint_policy; +pub type thread_precedence_policy_data_t = thread_precedence_policy; +pub type thread_precedence_policy_t = *mut thread_precedence_policy; +pub type thread_affinity_policy_data_t = thread_affinity_policy; +pub type thread_affinity_policy_t = *mut thread_affinity_policy; +pub type thread_background_policy_data_t = thread_background_policy; +pub type thread_background_policy_t = *mut thread_background_policy; +pub type thread_latency_qos_policy_data_t = thread_latency_qos_policy; +pub type thread_latency_qos_policy_t = *mut thread_latency_qos_policy; +pub type thread_throughput_qos_policy_data_t = thread_throughput_qos_policy; +pub type thread_throughput_qos_policy_t = *mut thread_throughput_qos_policy; + +pub type pthread_jit_write_callback_t = Option c_int>; + +pub type os_clockid_t = u32; + +pub type os_sync_wait_on_address_flags_t = u32; +pub type os_sync_wake_by_address_flags_t = u32; + +pub type os_unfair_lock = os_unfair_lock_s; +pub type os_unfair_lock_t = *mut os_unfair_lock; + +pub type os_log_t = *mut c_void; +pub type os_log_type_t = u8; +pub type os_signpost_id_t = u64; +pub type os_signpost_type_t = u8; + +pub type vm_statistics_t = *mut vm_statistics; +pub type vm_statistics_data_t = vm_statistics; +pub type vm_statistics64_t = *mut vm_statistics64; +pub type vm_statistics64_data_t = vm_statistics64; + +pub type task_t = crate::mach_port_t; +pub type task_inspect_t = crate::mach_port_t; + +pub type sysdir_search_path_enumeration_state = c_uint; + +pub type CCStatus = i32; +pub type CCCryptorStatus = i32; +pub type CCRNGStatus = crate::CCCryptorStatus; + +pub type copyfile_state_t = *mut c_void; +pub type copyfile_flags_t = u32; +pub type copyfile_callback_t = Option< + extern "C" fn( + c_int, + c_int, + copyfile_state_t, + *const c_char, + *const c_char, + *mut c_void, + ) -> c_int, +>; + +pub type attrgroup_t = u32; +pub type vol_capabilities_set_t = [u32; 4]; + +deprecated_mach! { + pub type mach_timebase_info_data_t = mach_timebase_info; +} + +extern_ty! { + pub enum timezone {} +} + +#[derive(Debug)] +#[repr(u32)] +pub enum sysdir_search_path_directory_t { + SYSDIR_DIRECTORY_APPLICATION = 1, + SYSDIR_DIRECTORY_DEMO_APPLICATION = 2, + SYSDIR_DIRECTORY_DEVELOPER_APPLICATION = 3, + SYSDIR_DIRECTORY_ADMIN_APPLICATION = 4, + SYSDIR_DIRECTORY_LIBRARY = 5, + SYSDIR_DIRECTORY_DEVELOPER = 6, + SYSDIR_DIRECTORY_USER = 7, + SYSDIR_DIRECTORY_DOCUMENTATION = 8, + SYSDIR_DIRECTORY_DOCUMENT = 9, + SYSDIR_DIRECTORY_CORESERVICE = 10, + SYSDIR_DIRECTORY_AUTOSAVED_INFORMATION = 11, + SYSDIR_DIRECTORY_DESKTOP = 12, + SYSDIR_DIRECTORY_CACHES = 13, + SYSDIR_DIRECTORY_APPLICATION_SUPPORT = 14, + SYSDIR_DIRECTORY_DOWNLOADS = 15, + SYSDIR_DIRECTORY_INPUT_METHODS = 16, + SYSDIR_DIRECTORY_MOVIES = 17, + SYSDIR_DIRECTORY_MUSIC = 18, + SYSDIR_DIRECTORY_PICTURES = 19, + SYSDIR_DIRECTORY_PRINTER_DESCRIPTION = 20, + SYSDIR_DIRECTORY_SHARED_PUBLIC = 21, + SYSDIR_DIRECTORY_PREFERENCE_PANES = 22, + SYSDIR_DIRECTORY_ALL_APPLICATIONS = 100, + SYSDIR_DIRECTORY_ALL_LIBRARIES = 101, +} +impl Copy for sysdir_search_path_directory_t {} +impl Clone for sysdir_search_path_directory_t { + fn clone(&self) -> sysdir_search_path_directory_t { + *self + } +} + +#[derive(Debug)] +#[repr(u32)] +pub enum sysdir_search_path_domain_mask_t { + SYSDIR_DOMAIN_MASK_USER = (1 << 0), + SYSDIR_DOMAIN_MASK_LOCAL = (1 << 1), + SYSDIR_DOMAIN_MASK_NETWORK = (1 << 2), + SYSDIR_DOMAIN_MASK_SYSTEM = (1 << 3), + SYSDIR_DOMAIN_MASK_ALL = 0x0ffff, +} +impl Copy for sysdir_search_path_domain_mask_t {} +impl Clone for sysdir_search_path_domain_mask_t { + fn clone(&self) -> sysdir_search_path_domain_mask_t { + *self + } +} + +s! { + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_sourceaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_reqprio: c_int, + pub aio_sigevent: sigevent, + pub aio_lio_opcode: c_int, + } + + pub struct glob_t { + pub gl_pathc: size_t, + __unused1: Padding, + pub gl_offs: size_t, + __unused2: Padding, + pub gl_pathv: *mut *mut c_char, + + __unused3: Padding<*mut c_void>, + + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + __unused6: Padding<*mut c_void>, + __unused7: Padding<*mut c_void>, + __unused8: Padding<*mut c_void>, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *mut c_char, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: crate::socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + } + + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub struct mach_timebase_info { + pub numer: u32, + pub denom: u32, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: ino_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: u32, + pub st_gen: u32, + pub st_lspare: i32, + pub st_qspare: [i64; 2], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub si_pid: crate::pid_t, + pub si_uid: crate::uid_t, + pub si_status: c_int, + pub si_addr: *mut c_void, + //Requires it to be union for tests + //pub si_value: crate::sigval, + _pad: Padding<[usize; 9]>, + } + + pub struct sigaction { + // FIXME(union): this field is actually a union + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: sigset_t, + pub sa_flags: c_int, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct fstore_t { + pub fst_flags: c_uint, + pub fst_posmode: c_int, + pub fst_offset: off_t, + pub fst_length: off_t, + pub fst_bytesalloc: off_t, + } + + pub struct fpunchhole_t { + pub fp_flags: c_uint, /* unused */ + pub reserved: c_uint, /* (to maintain 8-byte alignment) */ + pub fp_offset: off_t, /* IN: start of the region */ + pub fp_length: off_t, /* IN: size of the region */ + } + + pub struct ftrimactivefile_t { + pub fta_offset: off_t, + pub fta_length: off_t, + } + + pub struct fspecread_t { + pub fsr_flags: c_uint, + pub reserved: c_uint, + pub fsr_offset: off_t, + pub fsr_length: off_t, + } + + pub struct radvisory { + pub ra_offset: off_t, + pub ra_count: c_int, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct kevent64_s { + pub ident: u64, + pub filter: i16, + pub flags: u16, + pub fflags: u32, + pub data: i64, + pub udata: u64, + pub ext: [u64; 2], + } + + pub struct dqblk { + pub dqb_bhardlimit: u64, + pub dqb_bsoftlimit: u64, + pub dqb_curbytes: u64, + pub dqb_ihardlimit: u32, + pub dqb_isoftlimit: u32, + pub dqb_curinodes: u32, + pub dqb_btime: u32, + pub dqb_itime: u32, + pub dqb_id: u32, + pub dqb_spare: [u32; 4], + } + + pub struct if_msghdr { + pub ifm_msglen: c_ushort, + pub ifm_version: c_uchar, + pub ifm_type: c_uchar, + pub ifm_addrs: c_int, + pub ifm_flags: c_int, + pub ifm_index: c_ushort, + pub ifm_data: if_data, + } + + pub struct ifa_msghdr { + pub ifam_msglen: c_ushort, + pub ifam_version: c_uchar, + pub ifam_type: c_uchar, + pub ifam_addrs: c_int, + pub ifam_flags: c_int, + pub ifam_index: c_ushort, + pub ifam_metric: c_int, + } + + pub struct ifma_msghdr { + pub ifmam_msglen: c_ushort, + pub ifmam_version: c_uchar, + pub ifmam_type: c_uchar, + pub ifmam_addrs: c_int, + pub ifmam_flags: c_int, + pub ifmam_index: c_ushort, + } + + pub struct ifma_msghdr2 { + pub ifmam_msglen: c_ushort, + pub ifmam_version: c_uchar, + pub ifmam_type: c_uchar, + pub ifmam_addrs: c_int, + pub ifmam_flags: c_int, + pub ifmam_index: c_ushort, + pub ifmam_refcount: i32, + } + + pub struct rt_metrics { + pub rmx_locks: u32, + pub rmx_mtu: u32, + pub rmx_hopcount: u32, + pub rmx_expire: i32, + pub rmx_recvpipe: u32, + pub rmx_sendpipe: u32, + pub rmx_ssthresh: u32, + pub rmx_rtt: u32, + pub rmx_rttvar: u32, + pub rmx_pksent: u32, + /// This field does not exist anymore, the u32 is now part of a resized + /// `rmx_filler` array. + pub rmx_state: u32, + pub rmx_filler: [u32; 3], + } + + pub struct rt_msghdr { + pub rtm_msglen: c_ushort, + pub rtm_version: c_uchar, + pub rtm_type: c_uchar, + pub rtm_index: c_ushort, + pub rtm_flags: c_int, + pub rtm_addrs: c_int, + pub rtm_pid: crate::pid_t, + pub rtm_seq: c_int, + pub rtm_errno: c_int, + pub rtm_use: c_int, + pub rtm_inits: u32, + pub rtm_rmx: rt_metrics, + } + + pub struct rt_msghdr2 { + pub rtm_msglen: c_ushort, + pub rtm_version: c_uchar, + pub rtm_type: c_uchar, + pub rtm_index: c_ushort, + pub rtm_flags: c_int, + pub rtm_addrs: c_int, + pub rtm_refcnt: i32, + pub rtm_parentflags: c_int, + pub rtm_reserved: c_int, + pub rtm_use: c_int, + pub rtm_inits: u32, + pub rtm_rmx: rt_metrics, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct flock { + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + pub l_type: c_short, + pub l_whence: c_short, + } + + pub struct sf_hdtr { + pub headers: *mut crate::iovec, + pub hdr_cnt: c_int, + pub trailers: *mut crate::iovec, + pub trl_cnt: c_int, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_n_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct proc_taskinfo { + pub pti_virtual_size: u64, + pub pti_resident_size: u64, + pub pti_total_user: u64, + pub pti_total_system: u64, + pub pti_threads_user: u64, + pub pti_threads_system: u64, + pub pti_policy: i32, + pub pti_faults: i32, + pub pti_pageins: i32, + pub pti_cow_faults: i32, + pub pti_messages_sent: i32, + pub pti_messages_received: i32, + pub pti_syscalls_mach: i32, + pub pti_syscalls_unix: i32, + pub pti_csw: i32, + pub pti_threadnum: i32, + pub pti_numrunning: i32, + pub pti_priority: i32, + } + + pub struct proc_bsdinfo { + pub pbi_flags: u32, + pub pbi_status: u32, + pub pbi_xstatus: u32, + pub pbi_pid: u32, + pub pbi_ppid: u32, + pub pbi_uid: crate::uid_t, + pub pbi_gid: crate::gid_t, + pub pbi_ruid: crate::uid_t, + pub pbi_rgid: crate::gid_t, + pub pbi_svuid: crate::uid_t, + pub pbi_svgid: crate::gid_t, + pub rfu_1: u32, + pub pbi_comm: [c_char; MAXCOMLEN], + pub pbi_name: [c_char; 32], // MAXCOMLEN * 2, but macro isn't happy... + pub pbi_nfiles: u32, + pub pbi_pgid: u32, + pub pbi_pjobc: u32, + pub e_tdev: u32, + pub e_tpgid: u32, + pub pbi_nice: i32, + pub pbi_start_tvsec: u64, + pub pbi_start_tvusec: u64, + } + + pub struct proc_taskallinfo { + pub pbsd: proc_bsdinfo, + pub ptinfo: proc_taskinfo, + } + + pub struct xsw_usage { + pub xsu_total: u64, + pub xsu_avail: u64, + pub xsu_used: u64, + pub xsu_pagesize: u32, + pub xsu_encrypted: crate::boolean_t, + } + + pub struct xucred { + pub cr_version: c_uint, + pub cr_uid: crate::uid_t, + pub cr_ngroups: c_short, + pub cr_groups: [crate::gid_t; 16], + } + + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub struct mach_header { + pub magic: u32, + pub cputype: cpu_type_t, + pub cpusubtype: cpu_subtype_t, + pub filetype: u32, + pub ncmds: u32, + pub sizeofcmds: u32, + pub flags: u32, + } + + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub struct mach_header_64 { + pub magic: u32, + pub cputype: cpu_type_t, + pub cpusubtype: cpu_subtype_t, + pub filetype: u32, + pub ncmds: u32, + pub sizeofcmds: u32, + pub flags: u32, + pub reserved: u32, + } + + pub struct segment_command { + pub cmd: u32, + pub cmdsize: u32, + pub segname: [c_char; 16], + pub vmaddr: u32, + pub vmsize: u32, + pub fileoff: u32, + pub filesize: u32, + pub maxprot: vm_prot_t, + pub initprot: vm_prot_t, + pub nsects: u32, + pub flags: u32, + } + + pub struct segment_command_64 { + pub cmd: u32, + pub cmdsize: u32, + pub segname: [c_char; 16], + pub vmaddr: u64, + pub vmsize: u64, + pub fileoff: u64, + pub filesize: u64, + pub maxprot: vm_prot_t, + pub initprot: vm_prot_t, + pub nsects: u32, + pub flags: u32, + } + + pub struct load_command { + pub cmd: u32, + pub cmdsize: u32, + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 12], + } + + pub struct sockaddr_inarp { + pub sin_len: c_uchar, + pub sin_family: c_uchar, + pub sin_port: c_ushort, + pub sin_addr: crate::in_addr, + pub sin_srcaddr: crate::in_addr, + pub sin_tos: c_ushort, + pub sin_other: c_ushort, + } + + pub struct sockaddr_ctl { + pub sc_len: c_uchar, + pub sc_family: c_uchar, + pub ss_sysaddr: u16, + pub sc_id: u32, + pub sc_unit: u32, + pub sc_reserved: [u32; 5], + } + + pub struct in_pktinfo { + pub ipi_ifindex: c_uint, + pub ipi_spec_dst: crate::in_addr, + pub ipi_addr: crate::in_addr, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + // sys/ipc.h: + + pub struct ipc_perm { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + pub _seq: c_ushort, + pub _key: crate::key_t, + } + + // sys/sem.h + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + // sys/shm.h + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + // net/ndrv.h + pub struct sockaddr_ndrv { + pub snd_len: c_uchar, + pub snd_family: c_uchar, + pub snd_name: [c_uchar; crate::IFNAMSIZ], + } + + // sys/socket.h + + pub struct sa_endpoints_t { + pub sae_srcif: c_uint, // optional source interface + pub sae_srcaddr: *const crate::sockaddr, // optional source address + pub sae_srcaddrlen: crate::socklen_t, // size of source address + pub sae_dstaddr: *const crate::sockaddr, // destination address + pub sae_dstaddrlen: crate::socklen_t, // size of destination address + } + + pub struct timex { + pub modes: c_uint, + pub offset: c_long, + pub freq: c_long, + pub maxerror: c_long, + pub esterror: c_long, + pub status: c_int, + pub constant: c_long, + pub precision: c_long, + pub tolerance: c_long, + pub ppsfreq: c_long, + pub jitter: c_long, + pub shift: c_int, + pub stabil: c_long, + pub jitcnt: c_long, + pub calcnt: c_long, + pub errcnt: c_long, + pub stbcnt: c_long, + } + + pub struct ntptimeval { + pub time: crate::timespec, + pub maxerror: c_long, + pub esterror: c_long, + pub tai: c_long, + pub time_state: c_int, + } + + pub struct thread_standard_policy { + pub no_data: natural_t, + } + + pub struct thread_extended_policy { + pub timeshare: boolean_t, + } + + pub struct thread_time_constraint_policy { + pub period: u32, + pub computation: u32, + pub constraint: u32, + pub preemptible: boolean_t, + } + + pub struct thread_precedence_policy { + pub importance: integer_t, + } + + pub struct thread_affinity_policy { + pub affinity_tag: integer_t, + } + + pub struct thread_background_policy { + pub priority: integer_t, + } + + pub struct thread_latency_qos_policy { + pub thread_latency_qos_tier: thread_latency_qos_t, + } + + pub struct thread_throughput_qos_policy { + pub thread_throughput_qos_tier: thread_throughput_qos_t, + } + + // malloc/malloc.h + pub struct malloc_statistics_t { + pub blocks_in_use: c_uint, + pub size_in_use: size_t, + pub max_size_in_use: size_t, + pub size_allocated: size_t, + } + + pub struct mstats { + pub bytes_total: size_t, + pub chunks_used: size_t, + pub bytes_used: size_t, + pub chunks_free: size_t, + pub bytes_free: size_t, + } + + pub struct vm_range_t { + pub address: crate::vm_address_t, + pub size: crate::vm_size_t, + } + + pub struct vinfo_stat { + pub vst_dev: u32, + pub vst_mode: u16, + pub vst_nlink: u16, + pub vst_ino: u64, + pub vst_uid: crate::uid_t, + pub vst_gid: crate::gid_t, + pub vst_atime: i64, + pub vst_atimensec: i64, + pub vst_mtime: i64, + pub vst_mtimensec: i64, + pub vst_ctime: i64, + pub vst_ctimensec: i64, + pub vst_birthtime: i64, + pub vst_birthtimensec: i64, + pub vst_size: off_t, + pub vst_blocks: i64, + pub vst_blksize: i32, + pub vst_flags: u32, + pub vst_gen: u32, + pub vst_rdev: u32, + pub vst_qspare: [i64; 2], + } + + pub struct vnode_info { + pub vi_stat: vinfo_stat, + pub vi_type: c_int, + pub vi_pad: c_int, + pub vi_fsid: crate::fsid_t, + } + + pub struct vnode_info_path { + pub vip_vi: vnode_info, + // Normally it's `vip_path: [c_char; MAXPATHLEN]` but because libc supports an old rustc + // version, we go around this limitation like this. + pub vip_path: [[c_char; 32]; 32], + } + + pub struct proc_vnodepathinfo { + pub pvi_cdir: vnode_info_path, + pub pvi_rdir: vnode_info_path, + } + + pub struct vm_statistics { + pub free_count: natural_t, + pub active_count: natural_t, + pub inactive_count: natural_t, + pub wire_count: natural_t, + pub zero_fill_count: natural_t, + pub reactivations: natural_t, + pub pageins: natural_t, + pub pageouts: natural_t, + pub faults: natural_t, + pub cow_faults: natural_t, + pub lookups: natural_t, + pub hits: natural_t, + pub purgeable_count: natural_t, + pub purges: natural_t, + pub speculative_count: natural_t, + } + + pub struct task_thread_times_info { + pub user_time: time_value_t, + pub system_time: time_value_t, + } + + pub struct rusage_info_v0 { + pub ri_uuid: [u8; 16], + pub ri_user_time: u64, + pub ri_system_time: u64, + pub ri_pkg_idle_wkups: u64, + pub ri_interrupt_wkups: u64, + pub ri_pageins: u64, + pub ri_wired_size: u64, + pub ri_resident_size: u64, + pub ri_phys_footprint: u64, + pub ri_proc_start_abstime: u64, + pub ri_proc_exit_abstime: u64, + } + + pub struct rusage_info_v1 { + pub ri_uuid: [u8; 16], + pub ri_user_time: u64, + pub ri_system_time: u64, + pub ri_pkg_idle_wkups: u64, + pub ri_interrupt_wkups: u64, + pub ri_pageins: u64, + pub ri_wired_size: u64, + pub ri_resident_size: u64, + pub ri_phys_footprint: u64, + pub ri_proc_start_abstime: u64, + pub ri_proc_exit_abstime: u64, + pub ri_child_user_time: u64, + pub ri_child_system_time: u64, + pub ri_child_pkg_idle_wkups: u64, + pub ri_child_interrupt_wkups: u64, + pub ri_child_pageins: u64, + pub ri_child_elapsed_abstime: u64, + } + + pub struct rusage_info_v2 { + pub ri_uuid: [u8; 16], + pub ri_user_time: u64, + pub ri_system_time: u64, + pub ri_pkg_idle_wkups: u64, + pub ri_interrupt_wkups: u64, + pub ri_pageins: u64, + pub ri_wired_size: u64, + pub ri_resident_size: u64, + pub ri_phys_footprint: u64, + pub ri_proc_start_abstime: u64, + pub ri_proc_exit_abstime: u64, + pub ri_child_user_time: u64, + pub ri_child_system_time: u64, + pub ri_child_pkg_idle_wkups: u64, + pub ri_child_interrupt_wkups: u64, + pub ri_child_pageins: u64, + pub ri_child_elapsed_abstime: u64, + pub ri_diskio_bytesread: u64, + pub ri_diskio_byteswritten: u64, + } + + pub struct rusage_info_v3 { + pub ri_uuid: [u8; 16], + pub ri_user_time: u64, + pub ri_system_time: u64, + pub ri_pkg_idle_wkups: u64, + pub ri_interrupt_wkups: u64, + pub ri_pageins: u64, + pub ri_wired_size: u64, + pub ri_resident_size: u64, + pub ri_phys_footprint: u64, + pub ri_proc_start_abstime: u64, + pub ri_proc_exit_abstime: u64, + pub ri_child_user_time: u64, + pub ri_child_system_time: u64, + pub ri_child_pkg_idle_wkups: u64, + pub ri_child_interrupt_wkups: u64, + pub ri_child_pageins: u64, + pub ri_child_elapsed_abstime: u64, + pub ri_diskio_bytesread: u64, + pub ri_diskio_byteswritten: u64, + pub ri_cpu_time_qos_default: u64, + pub ri_cpu_time_qos_maintenance: u64, + pub ri_cpu_time_qos_background: u64, + pub ri_cpu_time_qos_utility: u64, + pub ri_cpu_time_qos_legacy: u64, + pub ri_cpu_time_qos_user_initiated: u64, + pub ri_cpu_time_qos_user_interactive: u64, + pub ri_billed_system_time: u64, + pub ri_serviced_system_time: u64, + } + + pub struct rusage_info_v4 { + pub ri_uuid: [u8; 16], + pub ri_user_time: u64, + pub ri_system_time: u64, + pub ri_pkg_idle_wkups: u64, + pub ri_interrupt_wkups: u64, + pub ri_pageins: u64, + pub ri_wired_size: u64, + pub ri_resident_size: u64, + pub ri_phys_footprint: u64, + pub ri_proc_start_abstime: u64, + pub ri_proc_exit_abstime: u64, + pub ri_child_user_time: u64, + pub ri_child_system_time: u64, + pub ri_child_pkg_idle_wkups: u64, + pub ri_child_interrupt_wkups: u64, + pub ri_child_pageins: u64, + pub ri_child_elapsed_abstime: u64, + pub ri_diskio_bytesread: u64, + pub ri_diskio_byteswritten: u64, + pub ri_cpu_time_qos_default: u64, + pub ri_cpu_time_qos_maintenance: u64, + pub ri_cpu_time_qos_background: u64, + pub ri_cpu_time_qos_utility: u64, + pub ri_cpu_time_qos_legacy: u64, + pub ri_cpu_time_qos_user_initiated: u64, + pub ri_cpu_time_qos_user_interactive: u64, + pub ri_billed_system_time: u64, + pub ri_serviced_system_time: u64, + pub ri_logical_writes: u64, + pub ri_lifetime_max_phys_footprint: u64, + pub ri_instructions: u64, + pub ri_cycles: u64, + pub ri_billed_energy: u64, + pub ri_serviced_energy: u64, + pub ri_interval_max_phys_footprint: u64, + pub ri_runnable_time: u64, + } + + pub struct image_offset { + pub uuid: crate::uuid_t, + pub offset: u32, + } + + pub struct attrlist { + pub bitmapcount: c_ushort, + pub reserved: u16, + pub commonattr: attrgroup_t, + pub volattr: attrgroup_t, + pub dirattr: attrgroup_t, + pub fileattr: attrgroup_t, + pub forkattr: attrgroup_t, + } + + pub struct attrreference_t { + pub attr_dataoffset: i32, + pub attr_length: u32, + } + + pub struct vol_capabilities_attr_t { + pub capabilities: vol_capabilities_set_t, + pub valid: vol_capabilities_set_t, + } + + pub struct attribute_set_t { + pub commonattr: attrgroup_t, + pub volattr: attrgroup_t, + pub dirattr: attrgroup_t, + pub fileattr: attrgroup_t, + pub forkattr: attrgroup_t, + } + + pub struct vol_attributes_attr_t { + pub validattr: attribute_set_t, + pub nativeattr: attribute_set_t, + } + + #[repr(align(8))] + pub struct tcp_connection_info { + pub tcpi_state: u8, + pub tcpi_snd_wscale: u8, + pub tcpi_rcv_wscale: u8, + __pad1: Padding, + pub tcpi_options: u32, + pub tcpi_flags: u32, + pub tcpi_rto: u32, + pub tcpi_maxseg: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub tcpi_snd_wnd: u32, + pub tcpi_snd_sbbytes: u32, + pub tcpi_rcv_wnd: u32, + pub tcpi_rttcur: u32, + pub tcpi_srtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_tfo_cookie_req: u32, + pub tcpi_tfo_cookie_rcv: u32, + pub tcpi_tfo_syn_loss: u32, + pub tcpi_tfo_syn_data_sent: u32, + pub tcpi_tfo_syn_data_acked: u32, + pub tcpi_tfo_syn_data_rcv: u32, + pub tcpi_tfo_cookie_req_rcv: u32, + pub tcpi_tfo_cookie_sent: u32, + pub tcpi_tfo_cookie_invalid: u32, + pub tcpi_tfo_cookie_wrong: u32, + pub tcpi_tfo_no_cookie_rcv: u32, + pub tcpi_tfo_heuristics_disable: u32, + pub tcpi_tfo_send_blackhole: u32, + pub tcpi_tfo_recv_blackhole: u32, + pub tcpi_tfo_onebyte_proxy: u32, + __pad2: Padding, + pub tcpi_txpackets: u64, + pub tcpi_txbytes: u64, + pub tcpi_txretransmitbytes: u64, + pub tcpi_rxpackets: u64, + pub tcpi_rxbytes: u64, + pub tcpi_rxoutoforderbytes: u64, + pub tcpi_rxretransmitpackets: u64, + } + + pub struct in6_addrlifetime { + pub ia6t_expire: time_t, + pub ia6t_preferred: time_t, + pub ia6t_vltime: u32, + pub ia6t_pltime: u32, + } + + pub struct in6_ifstat { + pub ifs6_in_receive: crate::u_quad_t, + pub ifs6_in_hdrerr: crate::u_quad_t, + pub ifs6_in_toobig: crate::u_quad_t, + pub ifs6_in_noroute: crate::u_quad_t, + pub ifs6_in_addrerr: crate::u_quad_t, + pub ifs6_in_protounknown: crate::u_quad_t, + pub ifs6_in_truncated: crate::u_quad_t, + pub ifs6_in_discard: crate::u_quad_t, + pub ifs6_in_deliver: crate::u_quad_t, + pub ifs6_out_forward: crate::u_quad_t, + pub ifs6_out_request: crate::u_quad_t, + pub ifs6_out_discard: crate::u_quad_t, + pub ifs6_out_fragok: crate::u_quad_t, + pub ifs6_out_fragfail: crate::u_quad_t, + pub ifs6_out_fragcreat: crate::u_quad_t, + pub ifs6_reass_reqd: crate::u_quad_t, + pub ifs6_reass_ok: crate::u_quad_t, + pub ifs6_atmfrag_rcvd: crate::u_quad_t, + pub ifs6_reass_fail: crate::u_quad_t, + pub ifs6_in_mcast: crate::u_quad_t, + pub ifs6_out_mcast: crate::u_quad_t, + pub ifs6_cantfoward_icmp6: crate::u_quad_t, + pub ifs6_addr_expiry_cnt: crate::u_quad_t, + pub ifs6_pfx_expiry_cnt: crate::u_quad_t, + pub ifs6_defrtr_expiry_cnt: crate::u_quad_t, + } + + pub struct icmp6_ifstat { + pub ifs6_in_msg: crate::u_quad_t, + pub ifs6_in_error: crate::u_quad_t, + pub ifs6_in_dstunreach: crate::u_quad_t, + pub ifs6_in_adminprohib: crate::u_quad_t, + pub ifs6_in_timeexceed: crate::u_quad_t, + pub ifs6_in_paramprob: crate::u_quad_t, + pub ifs6_in_pkttoobig: crate::u_quad_t, + pub ifs6_in_echo: crate::u_quad_t, + pub ifs6_in_echoreply: crate::u_quad_t, + pub ifs6_in_routersolicit: crate::u_quad_t, + pub ifs6_in_routeradvert: crate::u_quad_t, + pub ifs6_in_neighborsolicit: crate::u_quad_t, + pub ifs6_in_neighboradvert: crate::u_quad_t, + pub ifs6_in_redirect: crate::u_quad_t, + pub ifs6_in_mldquery: crate::u_quad_t, + pub ifs6_in_mldreport: crate::u_quad_t, + pub ifs6_in_mlddone: crate::u_quad_t, + pub ifs6_out_msg: crate::u_quad_t, + pub ifs6_out_error: crate::u_quad_t, + pub ifs6_out_dstunreach: crate::u_quad_t, + pub ifs6_out_adminprohib: crate::u_quad_t, + pub ifs6_out_timeexceed: crate::u_quad_t, + pub ifs6_out_paramprob: crate::u_quad_t, + pub ifs6_out_pkttoobig: crate::u_quad_t, + pub ifs6_out_echo: crate::u_quad_t, + pub ifs6_out_echoreply: crate::u_quad_t, + pub ifs6_out_routersolicit: crate::u_quad_t, + pub ifs6_out_routeradvert: crate::u_quad_t, + pub ifs6_out_neighborsolicit: crate::u_quad_t, + pub ifs6_out_neighboradvert: crate::u_quad_t, + pub ifs6_out_redirect: crate::u_quad_t, + pub ifs6_out_mldquery: crate::u_quad_t, + pub ifs6_out_mldreport: crate::u_quad_t, + pub ifs6_out_mlddone: crate::u_quad_t, + } + + // mach/host_info.h + pub struct host_cpu_load_info { + pub cpu_ticks: [crate::natural_t; CPU_STATE_MAX as usize], + } + + // net/if_mib.h + pub struct ifmibdata { + /// Name of interface + pub ifmd_name: [c_char; crate::IFNAMSIZ], + /// Number of promiscuous listeners + pub ifmd_pcount: c_uint, + /// Interface flags + pub ifmd_flags: c_uint, + /// Instantaneous length of send queue + pub ifmd_snd_len: c_uint, + /// Maximum length of send queue + pub ifmd_snd_maxlen: c_uint, + /// Number of drops in send queue + pub ifmd_snd_drops: c_uint, + /// For future expansion + pub ifmd_filler: [c_uint; 4], + /// Generic information and statistics + pub ifmd_data: if_data64, + } + + pub struct ifs_iso_8802_3 { + pub dot3StatsAlignmentErrors: u32, + pub dot3StatsFCSErrors: u32, + pub dot3StatsSingleCollisionFrames: u32, + pub dot3StatsMultipleCollisionFrames: u32, + pub dot3StatsSQETestErrors: u32, + pub dot3StatsDeferredTransmissions: u32, + pub dot3StatsLateCollisions: u32, + pub dot3StatsExcessiveCollisions: u32, + pub dot3StatsInternalMacTransmitErrors: u32, + pub dot3StatsCarrierSenseErrors: u32, + pub dot3StatsFrameTooLongs: u32, + pub dot3StatsInternalMacReceiveErrors: u32, + pub dot3StatsEtherChipSet: u32, + pub dot3StatsMissedFrames: u32, + pub dot3StatsCollFrequencies: [u32; 16], + pub dot3Compliance: u32, + } + + // kern_control.h + pub struct ctl_info { + pub ctl_id: u32, + pub ctl_name: [c_char; MAX_KCTL_NAME], + } + + // sys/proc_info.h + pub struct proc_fdinfo { + pub proc_fd: i32, + pub proc_fdtype: u32, + } + + #[repr(packed(4))] + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: i16, + pub flags: u16, + pub fflags: u32, + pub data: intptr_t, + pub udata: *mut c_void, + } + + #[repr(packed(4))] + pub struct semid_ds { + // Note the manpage shows different types than the system header. + pub sem_perm: ipc_perm, + pub sem_base: i32, + pub sem_nsems: c_ushort, + pub sem_otime: crate::time_t, + pub sem_pad1: i32, + pub sem_ctime: crate::time_t, + pub sem_pad2: i32, + pub sem_pad3: [i32; 4], + } + + #[repr(packed(4))] + pub struct shmid_ds { + pub shm_perm: ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, // FIXME(macos): 64-bit wrong align => wrong offset + pub shm_dtime: crate::time_t, // FIXME(macos): 64-bit wrong align => wrong offset + pub shm_ctime: crate::time_t, // FIXME(macos): 64-bit wrong align => wrong offset + // FIXME: 64-bit wrong align => wrong offset: + pub shm_internal: *mut c_void, + } + + pub struct proc_threadinfo { + pub pth_user_time: u64, + pub pth_system_time: u64, + pub pth_cpu_usage: i32, + pub pth_policy: i32, + pub pth_run_state: i32, + pub pth_flags: i32, + pub pth_sleep_time: i32, + pub pth_curpri: i32, + pub pth_priority: i32, + pub pth_maxpriority: i32, + pub pth_name: [c_char; MAXTHREADNAMESIZE], + } + + pub struct statfs { + pub f_bsize: u32, + pub f_iosize: i32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_owner: crate::uid_t, + pub f_type: u32, + pub f_flags: u32, + pub f_fssubtype: u32, + pub f_fstypename: [c_char; 16], + pub f_mntonname: [c_char; 1024], + pub f_mntfromname: [c_char; 1024], + pub f_flags_ext: u32, + pub f_reserved: [u32; 7], + } + + pub struct dirent { + pub d_ino: u64, + pub d_seekoff: u64, + pub d_reclen: u16, + pub d_namlen: u16, + pub d_type: u8, + pub d_name: [c_char; 1024], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[u8; 112]>, + } + + pub struct utmpx { + pub ut_user: [c_char; _UTX_USERSIZE], + pub ut_id: [c_char; _UTX_IDSIZE], + pub ut_line: [c_char; _UTX_LINESIZE], + pub ut_pid: crate::pid_t, + pub ut_type: c_short, + pub ut_tv: crate::timeval, + pub ut_host: [c_char; _UTX_HOSTSIZE], + ut_pad: Padding<[u32; 16]>, + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: crate::sigval, + __unused1: Padding<*mut c_void>, //actually a function pointer + pub sigev_notify_attributes: *mut crate::pthread_attr_t, + } + + pub struct processor_cpu_load_info { + pub cpu_ticks: [c_uint; CPU_STATE_MAX as usize], + } + + pub struct processor_basic_info { + pub cpu_type: cpu_type_t, + pub cpu_subtype: cpu_subtype_t, + pub running: crate::boolean_t, + pub slot_num: c_int, + pub is_master: crate::boolean_t, + } + + pub struct processor_set_basic_info { + pub processor_count: c_int, + pub default_policy: c_int, + } + + pub struct processor_set_load_info { + pub task_count: c_int, + pub thread_count: c_int, + pub load_average: integer_t, + pub mach_factor: integer_t, + } + + pub struct time_value_t { + pub seconds: integer_t, + pub microseconds: integer_t, + } + + pub struct thread_basic_info { + pub user_time: time_value_t, + pub system_time: time_value_t, + pub cpu_usage: crate::integer_t, + pub policy: crate::policy_t, + pub run_state: crate::integer_t, + pub flags: crate::integer_t, + pub suspend_count: crate::integer_t, + pub sleep_time: crate::integer_t, + } + + pub struct thread_identifier_info { + pub thread_id: u64, + pub thread_handle: u64, + pub dispatch_qaddr: u64, + } + + pub struct thread_extended_info { + pub pth_user_time: u64, + pub pth_system_time: u64, + pub pth_cpu_usage: i32, + pub pth_policy: i32, + pub pth_run_state: i32, + pub pth_flags: i32, + pub pth_sleep_time: i32, + pub pth_curpri: i32, + pub pth_priority: i32, + pub pth_maxpriority: i32, + pub pth_name: [c_char; MAXTHREADNAMESIZE], + } + + #[repr(packed(4))] + pub struct if_data64 { + pub ifi_type: c_uchar, + pub ifi_typelen: c_uchar, + pub ifi_physical: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_recvquota: c_uchar, + pub ifi_xmitquota: c_uchar, + pub ifi_unused1: c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_baudrate: u64, + pub ifi_ipackets: u64, + pub ifi_ierrors: u64, + pub ifi_opackets: u64, + pub ifi_oerrors: u64, + pub ifi_collisions: u64, + pub ifi_ibytes: u64, + pub ifi_obytes: u64, + pub ifi_imcasts: u64, + pub ifi_omcasts: u64, + pub ifi_iqdrops: u64, + pub ifi_noproto: u64, + pub ifi_recvtiming: u32, + pub ifi_xmittiming: u32, + #[cfg(target_pointer_width = "32")] + pub ifi_lastchange: crate::timeval, + #[cfg(not(target_pointer_width = "32"))] + pub ifi_lastchange: timeval32, + } + + #[repr(packed(4))] + pub struct if_msghdr2 { + pub ifm_msglen: c_ushort, + pub ifm_version: c_uchar, + pub ifm_type: c_uchar, + pub ifm_addrs: c_int, + pub ifm_flags: c_int, + pub ifm_index: c_ushort, + pub ifm_snd_len: c_int, + pub ifm_snd_maxlen: c_int, + pub ifm_snd_drops: c_int, + pub ifm_timer: c_int, + pub ifm_data: if_data64, + } + + #[repr(packed(8))] + pub struct vm_statistics64 { + pub free_count: natural_t, + pub active_count: natural_t, + pub inactive_count: natural_t, + pub wire_count: natural_t, + pub zero_fill_count: u64, + pub reactivations: u64, + pub pageins: u64, + pub pageouts: u64, + pub faults: u64, + pub cow_faults: u64, + pub lookups: u64, + pub hits: u64, + pub purges: u64, + pub purgeable_count: natural_t, + pub speculative_count: natural_t, + pub decompressions: u64, + pub compressions: u64, + pub swapins: u64, + pub swapouts: u64, + pub compressor_page_count: natural_t, + pub throttled_count: natural_t, + pub external_page_count: natural_t, + pub internal_page_count: natural_t, + pub total_uncompressed_pages_in_compressor: u64, + } + + #[repr(packed(4))] + pub struct mach_task_basic_info { + pub virtual_size: mach_vm_size_t, + pub resident_size: mach_vm_size_t, + pub resident_size_max: mach_vm_size_t, + pub user_time: time_value_t, + pub system_time: time_value_t, + pub policy: crate::policy_t, + pub suspend_count: integer_t, + } + + #[repr(packed(4))] + pub struct log2phys { + pub l2p_flags: c_uint, + pub l2p_contigbytes: off_t, + pub l2p_devoffset: off_t, + } + + pub struct os_unfair_lock_s { + _os_unfair_lock_opaque: u32, + } + + #[repr(packed(1))] + pub struct sockaddr_vm { + pub svm_len: c_uchar, + pub svm_family: crate::sa_family_t, + pub svm_reserved1: c_ushort, + pub svm_port: c_uint, + pub svm_cid: c_uint, + } + + pub struct ifdevmtu { + pub ifdm_current: c_int, + pub ifdm_min: c_int, + pub ifdm_max: c_int, + } + + #[repr(packed(4))] + pub struct ifkpi { + pub ifk_module_id: c_uint, + pub ifk_type: c_uint, + pub ifk_data: __c_anonymous_ifk_data, + } + + pub struct ifreq { + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub struct in6_ifreq { + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru6, + } +} + +s_no_extra_traits! { + #[repr(packed(4))] + pub struct ifconf { + pub ifc_len: c_int, + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } + pub union __c_anonymous_ifk_data { + pub ifk_ptr: *mut c_void, + pub ifk_value: c_int, + } + + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_flags: c_short, + pub ifru_metrics: c_int, + pub ifru_mtu: c_int, + pub ifru_phys: c_int, + pub ifru_media: c_int, + pub ifru_intval: c_int, + pub ifru_data: *mut c_char, + pub ifru_devmtu: ifdevmtu, + pub ifru_kpi: ifkpi, + pub ifru_wake_flags: u32, + pub ifru_route_refcnt: u32, + pub ifru_cap: [c_int; 2], + pub ifru_functional_type: u32, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: *mut c_char, + pub ifcu_req: *mut ifreq, + } + + pub union __c_anonymous_ifr_ifru6 { + pub ifru_addr: crate::sockaddr_in6, + pub ifru_dstaddr: crate::sockaddr_in6, + pub ifru_flags: c_int, + pub ifru_flags6: c_int, + pub ifru_metrics: c_int, + pub ifru_intval: c_int, + pub ifru_data: *mut c_char, + pub ifru_lifetime: in6_addrlifetime, + pub ifru_stat: in6_ifstat, + pub ifru_icmp6stat: icmp6_ifstat, + pub ifru_scope_id: [u32; SCOPE6_ID_MAX], + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_pid: crate::pid_t, + _si_uid: crate::uid_t, + _si_status: c_int, + _si_addr: *mut c_void, + si_value: crate::sigval, + } + + (*(self as *const siginfo_t).cast::()).si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +s_no_extra_traits! { + pub union semun { + pub val: c_int, + pub buf: *mut semid_ds, + pub array: *mut c_ushort, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for semun { + fn eq(&self, other: &semun) -> bool { + unsafe { self.val == other.val } + } + } + impl Eq for semun {} + impl hash::Hash for semun { + fn hash(&self, state: &mut H) { + unsafe { self.val.hash(state) }; + } + } + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for ifconf + where + Self: Copy, + { + fn eq(&self, other: &Self) -> bool { + let len_ptr1 = core::ptr::addr_of!(self.ifc_len); + let len_ptr2 = core::ptr::addr_of!(other.ifc_len); + let ifcu_ptr1 = core::ptr::addr_of!(self.ifc_ifcu); + let ifcu_ptr2 = core::ptr::addr_of!(other.ifc_ifcu); + + // SAFETY: `ifconf` implements `Copy` so the reads are valid + let len1 = unsafe { len_ptr1.read_unaligned() }; + let len2 = unsafe { len_ptr2.read_unaligned() }; + let ifcu1 = unsafe { ifcu_ptr1.read_unaligned() }; + let ifcu2 = unsafe { ifcu_ptr2.read_unaligned() }; + + len1 == len2 && ifcu1 == ifcu2 + } + } + impl Eq for ifconf {} + + impl PartialEq for __c_anonymous_ifk_data { + fn eq(&self, other: &__c_anonymous_ifk_data) -> bool { + unsafe { self.ifk_ptr == other.ifk_ptr && self.ifk_value == other.ifk_value } + } + } + + impl Eq for __c_anonymous_ifk_data {} + impl hash::Hash for __c_anonymous_ifk_data { + fn hash(&self, state: &mut H) { + unsafe { + self.ifk_ptr.hash(state); + self.ifk_value.hash(state); + } + } + } + + impl PartialEq for __c_anonymous_ifr_ifru { + fn eq(&self, other: &__c_anonymous_ifr_ifru) -> bool { + unsafe { + self.ifru_addr == other.ifru_addr + && self.ifru_dstaddr == other.ifru_dstaddr + && self.ifru_broadaddr == other.ifru_broadaddr + && self.ifru_flags == other.ifru_flags + && self.ifru_metrics == other.ifru_metrics + && self.ifru_mtu == other.ifru_mtu + && self.ifru_phys == other.ifru_phys + && self.ifru_media == other.ifru_media + && self.ifru_intval == other.ifru_intval + && self.ifru_data == other.ifru_data + && self.ifru_devmtu == other.ifru_devmtu + && self.ifru_kpi == other.ifru_kpi + && self.ifru_wake_flags == other.ifru_wake_flags + && self.ifru_route_refcnt == other.ifru_route_refcnt + && self + .ifru_cap + .iter() + .zip(other.ifru_cap.iter()) + .all(|(a, b)| a == b) + && self.ifru_functional_type == other.ifru_functional_type + } + } + } + + impl Eq for __c_anonymous_ifr_ifru {} + + impl hash::Hash for __c_anonymous_ifr_ifru { + fn hash(&self, state: &mut H) { + unsafe { + self.ifru_addr.hash(state); + self.ifru_dstaddr.hash(state); + self.ifru_broadaddr.hash(state); + self.ifru_flags.hash(state); + self.ifru_metrics.hash(state); + self.ifru_mtu.hash(state); + self.ifru_phys.hash(state); + self.ifru_media.hash(state); + self.ifru_intval.hash(state); + self.ifru_data.hash(state); + self.ifru_devmtu.hash(state); + self.ifru_kpi.hash(state); + self.ifru_wake_flags.hash(state); + self.ifru_route_refcnt.hash(state); + self.ifru_cap.hash(state); + self.ifru_functional_type.hash(state); + } + } + } + + impl Eq for __c_anonymous_ifc_ifcu {} + + impl PartialEq for __c_anonymous_ifc_ifcu { + fn eq(&self, other: &__c_anonymous_ifc_ifcu) -> bool { + unsafe { self.ifcu_buf == other.ifcu_buf && self.ifcu_req == other.ifcu_req } + } + } + + impl hash::Hash for __c_anonymous_ifc_ifcu { + fn hash(&self, state: &mut H) { + unsafe { self.ifcu_buf.hash(state) }; + unsafe { self.ifcu_req.hash(state) }; + } + } + + impl PartialEq for __c_anonymous_ifr_ifru6 { + fn eq(&self, other: &__c_anonymous_ifr_ifru6) -> bool { + unsafe { + self.ifru_addr == other.ifru_addr + && self.ifru_dstaddr == other.ifru_dstaddr + && self.ifru_flags == other.ifru_flags + && self.ifru_flags6 == other.ifru_flags6 + && self.ifru_metrics == other.ifru_metrics + && self.ifru_intval == other.ifru_intval + && self.ifru_data == other.ifru_data + && self + .ifru_scope_id + .iter() + .zip(other.ifru_scope_id.iter()) + .all(|(a, b)| a == b) + } + } + } + + impl Eq for __c_anonymous_ifr_ifru6 {} + + impl hash::Hash for __c_anonymous_ifr_ifru6 { + fn hash(&self, state: &mut H) { + unsafe { + self.ifru_addr.hash(state); + self.ifru_dstaddr.hash(state); + self.ifru_flags.hash(state); + self.ifru_flags6.hash(state); + self.ifru_metrics.hash(state); + self.ifru_intval.hash(state); + self.ifru_data.hash(state); + self.ifru_scope_id.hash(state); + } + } + } + } +} + +pub const _UTX_USERSIZE: usize = 256; +pub const _UTX_LINESIZE: usize = 32; +pub const _UTX_IDSIZE: usize = 4; +pub const _UTX_HOSTSIZE: usize = 256; + +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const OLD_TIME: c_short = 3; +pub const NEW_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; +pub const SIGNATURE: c_short = 10; +pub const SHUTDOWN_TIME: c_short = 11; + +pub const LC_COLLATE_MASK: c_int = 1 << 0; +pub const LC_CTYPE_MASK: c_int = 1 << 1; +pub const LC_MESSAGES_MASK: c_int = 1 << 2; +pub const LC_MONETARY_MASK: c_int = 1 << 3; +pub const LC_NUMERIC_MASK: c_int = 1 << 4; +pub const LC_TIME_MASK: c_int = 1 << 5; +pub const LC_ALL_MASK: c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const CODESET: crate::nl_item = 0; +pub const D_T_FMT: crate::nl_item = 1; +pub const D_FMT: crate::nl_item = 2; +pub const T_FMT: crate::nl_item = 3; +pub const T_FMT_AMPM: crate::nl_item = 4; +pub const AM_STR: crate::nl_item = 5; +pub const PM_STR: crate::nl_item = 6; + +pub const DAY_1: crate::nl_item = 7; +pub const DAY_2: crate::nl_item = 8; +pub const DAY_3: crate::nl_item = 9; +pub const DAY_4: crate::nl_item = 10; +pub const DAY_5: crate::nl_item = 11; +pub const DAY_6: crate::nl_item = 12; +pub const DAY_7: crate::nl_item = 13; + +pub const ABDAY_1: crate::nl_item = 14; +pub const ABDAY_2: crate::nl_item = 15; +pub const ABDAY_3: crate::nl_item = 16; +pub const ABDAY_4: crate::nl_item = 17; +pub const ABDAY_5: crate::nl_item = 18; +pub const ABDAY_6: crate::nl_item = 19; +pub const ABDAY_7: crate::nl_item = 20; + +pub const MON_1: crate::nl_item = 21; +pub const MON_2: crate::nl_item = 22; +pub const MON_3: crate::nl_item = 23; +pub const MON_4: crate::nl_item = 24; +pub const MON_5: crate::nl_item = 25; +pub const MON_6: crate::nl_item = 26; +pub const MON_7: crate::nl_item = 27; +pub const MON_8: crate::nl_item = 28; +pub const MON_9: crate::nl_item = 29; +pub const MON_10: crate::nl_item = 30; +pub const MON_11: crate::nl_item = 31; +pub const MON_12: crate::nl_item = 32; + +pub const ABMON_1: crate::nl_item = 33; +pub const ABMON_2: crate::nl_item = 34; +pub const ABMON_3: crate::nl_item = 35; +pub const ABMON_4: crate::nl_item = 36; +pub const ABMON_5: crate::nl_item = 37; +pub const ABMON_6: crate::nl_item = 38; +pub const ABMON_7: crate::nl_item = 39; +pub const ABMON_8: crate::nl_item = 40; +pub const ABMON_9: crate::nl_item = 41; +pub const ABMON_10: crate::nl_item = 42; +pub const ABMON_11: crate::nl_item = 43; +pub const ABMON_12: crate::nl_item = 44; + +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC_RAW: crate::clockid_t = 4; +pub const CLOCK_MONOTONIC_RAW_APPROX: crate::clockid_t = 5; +pub const CLOCK_MONOTONIC: crate::clockid_t = 6; +pub const CLOCK_UPTIME_RAW: crate::clockid_t = 8; +pub const CLOCK_UPTIME_RAW_APPROX: crate::clockid_t = 9; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 12; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 16; + +pub const ERA: crate::nl_item = 45; +pub const ERA_D_FMT: crate::nl_item = 46; +pub const ERA_D_T_FMT: crate::nl_item = 47; +pub const ERA_T_FMT: crate::nl_item = 48; +pub const ALT_DIGITS: crate::nl_item = 49; + +pub const RADIXCHAR: crate::nl_item = 50; +pub const THOUSEP: crate::nl_item = 51; + +pub const YESEXPR: crate::nl_item = 52; +pub const NOEXPR: crate::nl_item = 53; + +pub const YESSTR: crate::nl_item = 54; +pub const NOSTR: crate::nl_item = 55; + +pub const CRNCYSTR: crate::nl_item = 56; + +pub const D_MD_ORDER: crate::nl_item = 57; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const SEEK_HOLE: c_int = 3; +pub const SEEK_DATA: c_int = 4; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const BUFSIZ: c_uint = 1024; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 1024; +pub const L_tmpnam: c_uint = 1024; +pub const TMP_MAX: c_uint = 308915776; +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_CHOWN_RESTRICTED: c_int = 7; +pub const _PC_NO_TRUNC: c_int = 8; +pub const _PC_VDISABLE: c_int = 9; +pub const _PC_NAME_CHARS_MAX: c_int = 10; +pub const _PC_CASE_SENSITIVE: c_int = 11; +pub const _PC_CASE_PRESERVING: c_int = 12; +pub const _PC_EXTENDED_SECURITY_NP: c_int = 13; +pub const _PC_AUTH_OPAQUE_NP: c_int = 14; +pub const _PC_2_SYMLINKS: c_int = 15; +pub const _PC_ALLOC_SIZE_MIN: c_int = 16; +pub const _PC_ASYNC_IO: c_int = 17; +pub const _PC_FILESIZEBITS: c_int = 18; +pub const _PC_PRIO_IO: c_int = 19; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 20; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 21; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 22; +pub const _PC_REC_XFER_ALIGN: c_int = 23; +pub const _PC_SYMLINK_MAX: c_int = 24; +pub const _PC_SYNC_IO: c_int = 25; +pub const _PC_XATTR_SIZE_BITS: c_int = 26; +pub const _PC_MIN_HOLE_SIZE: c_int = 27; +pub const O_EVTONLY: c_int = 0x00008000; +pub const O_NOCTTY: c_int = 0x00020000; +pub const O_DIRECTORY: c_int = 0x00100000; +pub const O_SYMLINK: c_int = 0x00200000; +pub const O_DSYNC: c_int = 0x00400000; +pub const O_CLOEXEC: c_int = 0x01000000; +pub const O_NOFOLLOW_ANY: c_int = 0x20000000; +pub const O_EXEC: c_int = 0x40000000; +pub const O_SEARCH: c_int = O_EXEC | O_DIRECTORY; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const PT_TRACE_ME: c_int = 0; +pub const PT_READ_I: c_int = 1; +pub const PT_READ_D: c_int = 2; +pub const PT_READ_U: c_int = 3; +pub const PT_WRITE_I: c_int = 4; +pub const PT_WRITE_D: c_int = 5; +pub const PT_WRITE_U: c_int = 6; +pub const PT_CONTINUE: c_int = 7; +pub const PT_KILL: c_int = 8; +pub const PT_STEP: c_int = 9; +pub const PT_ATTACH: c_int = 10; +pub const PT_DETACH: c_int = 11; +pub const PT_SIGEXC: c_int = 12; +pub const PT_THUPDATE: c_int = 13; +pub const PT_ATTACHEXC: c_int = 14; + +pub const PT_FORCEQUOTA: c_int = 30; +pub const PT_DENY_ATTACH: c_int = 31; +pub const PT_FIRSTMACH: c_int = 32; + +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_ANON: c_int = 0x1000; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +pub const CPU_STATE_USER: c_int = 0; +pub const CPU_STATE_SYSTEM: c_int = 1; +pub const CPU_STATE_IDLE: c_int = 2; +pub const CPU_STATE_NICE: c_int = 3; +pub const CPU_STATE_MAX: c_int = 4; + +pub const PROCESSOR_BASIC_INFO: c_int = 1; +pub const PROCESSOR_CPU_LOAD_INFO: c_int = 2; +pub const PROCESSOR_PM_REGS_INFO: c_int = 0x10000001; +pub const PROCESSOR_TEMPERATURE: c_int = 0x10000002; +pub const PROCESSOR_SET_LOAD_INFO: c_int = 4; +pub const PROCESSOR_SET_BASIC_INFO: c_int = 5; + +deprecated_mach! { + pub const VM_FLAGS_FIXED: c_int = 0x0000; + pub const VM_FLAGS_ANYWHERE: c_int = 0x0001; + pub const VM_FLAGS_PURGABLE: c_int = 0x0002; + pub const VM_FLAGS_RANDOM_ADDR: c_int = 0x0008; + pub const VM_FLAGS_NO_CACHE: c_int = 0x0010; + pub const VM_FLAGS_RESILIENT_CODESIGN: c_int = 0x0020; + pub const VM_FLAGS_RESILIENT_MEDIA: c_int = 0x0040; + pub const VM_FLAGS_OVERWRITE: c_int = 0x4000; + pub const VM_FLAGS_SUPERPAGE_MASK: c_int = 0x70000; + pub const VM_FLAGS_RETURN_DATA_ADDR: c_int = 0x100000; + pub const VM_FLAGS_RETURN_4K_DATA_ADDR: c_int = 0x800000; + pub const VM_FLAGS_ALIAS_MASK: c_int = 0xFF000000; + pub const VM_FLAGS_USER_ALLOCATE: c_int = 0xff07401f; + pub const VM_FLAGS_USER_MAP: c_int = 0xff97401f; + pub const VM_FLAGS_USER_REMAP: c_int = VM_FLAGS_FIXED + | VM_FLAGS_ANYWHERE + | VM_FLAGS_RANDOM_ADDR + | VM_FLAGS_OVERWRITE + | VM_FLAGS_RETURN_DATA_ADDR + | VM_FLAGS_RESILIENT_CODESIGN; + + pub const VM_FLAGS_SUPERPAGE_SHIFT: c_int = 16; + pub const SUPERPAGE_NONE: c_int = 0; + pub const SUPERPAGE_SIZE_ANY: c_int = 1; + pub const VM_FLAGS_SUPERPAGE_NONE: c_int = SUPERPAGE_NONE << VM_FLAGS_SUPERPAGE_SHIFT; + pub const VM_FLAGS_SUPERPAGE_SIZE_ANY: c_int = SUPERPAGE_SIZE_ANY << VM_FLAGS_SUPERPAGE_SHIFT; + pub const SUPERPAGE_SIZE_2MB: c_int = 2; + pub const VM_FLAGS_SUPERPAGE_SIZE_2MB: c_int = SUPERPAGE_SIZE_2MB << VM_FLAGS_SUPERPAGE_SHIFT; + + pub const VM_MEMORY_MALLOC: c_int = 1; + pub const VM_MEMORY_MALLOC_SMALL: c_int = 2; + pub const VM_MEMORY_MALLOC_LARGE: c_int = 3; + pub const VM_MEMORY_MALLOC_HUGE: c_int = 4; + pub const VM_MEMORY_SBRK: c_int = 5; + pub const VM_MEMORY_REALLOC: c_int = 6; + pub const VM_MEMORY_MALLOC_TINY: c_int = 7; + pub const VM_MEMORY_MALLOC_LARGE_REUSABLE: c_int = 8; + pub const VM_MEMORY_MALLOC_LARGE_REUSED: c_int = 9; + pub const VM_MEMORY_ANALYSIS_TOOL: c_int = 10; + pub const VM_MEMORY_MALLOC_NANO: c_int = 11; + pub const VM_MEMORY_MACH_MSG: c_int = 20; + pub const VM_MEMORY_IOKIT: c_int = 21; + pub const VM_MEMORY_STACK: c_int = 30; + pub const VM_MEMORY_GUARD: c_int = 31; + pub const VM_MEMORY_SHARED_PMAP: c_int = 32; + pub const VM_MEMORY_DYLIB: c_int = 33; + pub const VM_MEMORY_OBJC_DISPATCHERS: c_int = 34; + pub const VM_MEMORY_UNSHARED_PMAP: c_int = 35; + pub const VM_MEMORY_APPKIT: c_int = 40; + pub const VM_MEMORY_FOUNDATION: c_int = 41; + pub const VM_MEMORY_COREGRAPHICS: c_int = 42; + pub const VM_MEMORY_CORESERVICES: c_int = 43; + pub const VM_MEMORY_CARBON: c_int = VM_MEMORY_CORESERVICES; + pub const VM_MEMORY_JAVA: c_int = 44; + pub const VM_MEMORY_COREDATA: c_int = 45; + pub const VM_MEMORY_COREDATA_OBJECTIDS: c_int = 46; + pub const VM_MEMORY_ATS: c_int = 50; + pub const VM_MEMORY_LAYERKIT: c_int = 51; + pub const VM_MEMORY_CGIMAGE: c_int = 52; + pub const VM_MEMORY_TCMALLOC: c_int = 53; + pub const VM_MEMORY_COREGRAPHICS_DATA: c_int = 54; + pub const VM_MEMORY_COREGRAPHICS_SHARED: c_int = 55; + pub const VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS: c_int = 56; + pub const VM_MEMORY_COREGRAPHICS_BACKINGSTORES: c_int = 57; + pub const VM_MEMORY_COREGRAPHICS_XALLOC: c_int = 58; + pub const VM_MEMORY_COREGRAPHICS_MISC: c_int = VM_MEMORY_COREGRAPHICS; + pub const VM_MEMORY_DYLD: c_int = 60; + pub const VM_MEMORY_DYLD_MALLOC: c_int = 61; + pub const VM_MEMORY_SQLITE: c_int = 62; + pub const VM_MEMORY_JAVASCRIPT_CORE: c_int = 63; + pub const VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR: c_int = 64; + pub const VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE: c_int = 65; + pub const VM_MEMORY_GLSL: c_int = 66; + pub const VM_MEMORY_OPENCL: c_int = 67; + pub const VM_MEMORY_COREIMAGE: c_int = 68; + pub const VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS: c_int = 69; + pub const VM_MEMORY_IMAGEIO: c_int = 70; + pub const VM_MEMORY_COREPROFILE: c_int = 71; + pub const VM_MEMORY_ASSETSD: c_int = 72; + pub const VM_MEMORY_OS_ALLOC_ONCE: c_int = 73; + pub const VM_MEMORY_LIBDISPATCH: c_int = 74; + pub const VM_MEMORY_ACCELERATE: c_int = 75; + pub const VM_MEMORY_COREUI: c_int = 76; + pub const VM_MEMORY_COREUIFILE: c_int = 77; + pub const VM_MEMORY_GENEALOGY: c_int = 78; + pub const VM_MEMORY_RAWCAMERA: c_int = 79; + pub const VM_MEMORY_CORPSEINFO: c_int = 80; + pub const VM_MEMORY_ASL: c_int = 81; + pub const VM_MEMORY_SWIFT_RUNTIME: c_int = 82; + pub const VM_MEMORY_SWIFT_METADATA: c_int = 83; + pub const VM_MEMORY_DHMM: c_int = 84; + pub const VM_MEMORY_SCENEKIT: c_int = 86; + pub const VM_MEMORY_SKYWALK: c_int = 87; + pub const VM_MEMORY_APPLICATION_SPECIFIC_1: c_int = 240; + pub const VM_MEMORY_APPLICATION_SPECIFIC_16: c_int = 255; +} + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; +pub const MS_SYNC: c_int = 0x0010; + +pub const MS_KILLPAGES: c_int = 0x0004; +pub const MS_DEACTIVATE: c_int = 0x0008; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EDEADLK: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EAGAIN: c_int = 35; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const EINPROGRESS: c_int = 36; +pub const EALREADY: c_int = 37; +pub const ENOTSOCK: c_int = 38; +pub const EDESTADDRREQ: c_int = 39; +pub const EMSGSIZE: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const ENOTSUP: c_int = 45; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENETDOWN: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const ELOOP: c_int = 62; +pub const ENAMETOOLONG: c_int = 63; +pub const EHOSTDOWN: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const ENOTEMPTY: c_int = 66; +pub const EPROCLIM: c_int = 67; +pub const EUSERS: c_int = 68; +pub const EDQUOT: c_int = 69; +pub const ESTALE: c_int = 70; +pub const EREMOTE: c_int = 71; +pub const EBADRPC: c_int = 72; +pub const ERPCMISMATCH: c_int = 73; +pub const EPROGUNAVAIL: c_int = 74; +pub const EPROGMISMATCH: c_int = 75; +pub const EPROCUNAVAIL: c_int = 76; +pub const ENOLCK: c_int = 77; +pub const ENOSYS: c_int = 78; +pub const EFTYPE: c_int = 79; +pub const EAUTH: c_int = 80; +pub const ENEEDAUTH: c_int = 81; +pub const EPWROFF: c_int = 82; +pub const EDEVERR: c_int = 83; +pub const EOVERFLOW: c_int = 84; +pub const EBADEXEC: c_int = 85; +pub const EBADARCH: c_int = 86; +pub const ESHLIBVERS: c_int = 87; +pub const EBADMACHO: c_int = 88; +pub const ECANCELED: c_int = 89; +pub const EIDRM: c_int = 90; +pub const ENOMSG: c_int = 91; +pub const EILSEQ: c_int = 92; +pub const ENOATTR: c_int = 93; +pub const EBADMSG: c_int = 94; +pub const EMULTIHOP: c_int = 95; +pub const ENODATA: c_int = 96; +pub const ENOLINK: c_int = 97; +pub const ENOSR: c_int = 98; +pub const ENOSTR: c_int = 99; +pub const EPROTO: c_int = 100; +pub const ETIME: c_int = 101; +pub const EOPNOTSUPP: c_int = 102; +pub const ENOPOLICY: c_int = 103; +pub const ENOTRECOVERABLE: c_int = 104; +pub const EOWNERDEAD: c_int = 105; +pub const EQFULL: c_int = 106; +pub const ELAST: c_int = 106; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const F_DUPFD: c_int = 0; +pub const F_DUPFD_CLOEXEC: c_int = 67; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_PREALLOCATE: c_int = 42; +pub const F_RDADVISE: c_int = 44; +pub const F_RDAHEAD: c_int = 45; +pub const F_NOCACHE: c_int = 48; +pub const F_LOG2PHYS: c_int = 49; +pub const F_GETPATH: c_int = 50; +pub const F_FULLFSYNC: c_int = 51; +pub const F_FREEZE_FS: c_int = 53; +pub const F_THAW_FS: c_int = 54; +pub const F_GLOBAL_NOCACHE: c_int = 55; +pub const F_NODIRECT: c_int = 62; +pub const F_LOG2PHYS_EXT: c_int = 65; +pub const F_BARRIERFSYNC: c_int = 85; +// See https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h +pub const F_OFD_SETLK: c_int = 90; /* Acquire or release open file description lock */ +pub const F_OFD_SETLKW: c_int = 91; /* (as F_OFD_SETLK but blocking if conflicting lock) */ +pub const F_OFD_GETLK: c_int = 92; /* Examine OFD lock */ +pub const F_PUNCHHOLE: c_int = 99; +pub const F_TRIM_ACTIVE_FILE: c_int = 100; +pub const F_SPECULATIVE_READ: c_int = 101; +pub const F_GETPATH_NOFIRMLINK: c_int = 102; +pub const F_TRANSFEREXTENTS: c_int = 110; + +pub const F_ALLOCATECONTIG: c_uint = 0x02; +pub const F_ALLOCATEALL: c_uint = 0x04; +pub const F_ALLOCATEPERSIST: c_uint = 0x08; + +pub const F_PEOFPOSMODE: c_int = 3; +pub const F_VOLPOSMODE: c_int = 4; + +pub const AT_FDCWD: c_int = -2; +pub const AT_EACCESS: c_int = 0x0010; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x0020; +pub const AT_SYMLINK_FOLLOW: c_int = 0x0040; +pub const AT_REMOVEDIR: c_int = 0x0080; + +pub const TIOCMODG: c_ulong = 0x40047403; +pub const TIOCMODS: c_ulong = 0x80047404; +pub const TIOCM_LE: c_int = 0x1; +pub const TIOCM_DTR: c_int = 0x2; +pub const TIOCM_RTS: c_int = 0x4; +pub const TIOCM_ST: c_int = 0x8; +pub const TIOCM_SR: c_int = 0x10; +pub const TIOCM_CTS: c_int = 0x20; +pub const TIOCM_CAR: c_int = 0x40; +pub const TIOCM_CD: c_int = 0x40; +pub const TIOCM_RNG: c_int = 0x80; +pub const TIOCM_RI: c_int = 0x80; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCEXCL: c_int = 0x2000740d; +pub const TIOCNXCL: c_int = 0x2000740e; +pub const TIOCFLUSH: c_ulong = 0x80047410; +pub const TIOCGETD: c_ulong = 0x4004741a; +pub const TIOCSETD: c_ulong = 0x8004741b; +pub const TIOCIXON: c_uint = 0x20007481; +pub const TIOCIXOFF: c_uint = 0x20007480; +pub const TIOCSDTR: c_uint = 0x20007479; +pub const TIOCCDTR: c_uint = 0x20007478; +pub const TIOCGPGRP: c_ulong = 0x40047477; +pub const TIOCSPGRP: c_ulong = 0x80047476; +pub const TIOCOUTQ: c_ulong = 0x40047473; +pub const TIOCSTI: c_ulong = 0x80017472; +pub const TIOCNOTTY: c_uint = 0x20007471; +pub const TIOCPKT: c_ulong = 0x80047470; +pub const TIOCPKT_DATA: c_int = 0x0; +pub const TIOCPKT_FLUSHREAD: c_int = 0x1; +pub const TIOCPKT_FLUSHWRITE: c_int = 0x2; +pub const TIOCPKT_STOP: c_int = 0x4; +pub const TIOCPKT_START: c_int = 0x8; +pub const TIOCPKT_NOSTOP: c_int = 0x10; +pub const TIOCPKT_DOSTOP: c_int = 0x20; +pub const TIOCPKT_IOCTL: c_int = 0x40; +pub const TIOCSTOP: c_uint = 0x2000746f; +pub const TIOCSTART: c_uint = 0x2000746e; +pub const TIOCMSET: c_ulong = 0x8004746d; +pub const TIOCMBIS: c_ulong = 0x8004746c; +pub const TIOCMBIC: c_ulong = 0x8004746b; +pub const TIOCMGET: c_ulong = 0x4004746a; +#[deprecated(since = "0.2.178", note = "Removed in MacOSX 12.0.1")] +pub const TIOCREMOTE: c_ulong = 0x80047469; +pub const TIOCGWINSZ: c_ulong = 0x40087468; +pub const TIOCSWINSZ: c_ulong = 0x80087467; +pub const TIOCUCNTL: c_ulong = 0x80047466; +pub const TIOCSTAT: c_uint = 0x20007465; +pub const TIOCSCONS: c_uint = 0x20007463; +pub const TIOCCONS: c_ulong = 0x80047462; +pub const TIOCSCTTY: c_uint = 0x20007461; +pub const TIOCEXT: c_ulong = 0x80047460; +pub const TIOCSIG: c_uint = 0x2000745f; +pub const TIOCDRAIN: c_uint = 0x2000745e; +pub const TIOCMSDTRWAIT: c_ulong = 0x8004745b; +pub const TIOCMGDTRWAIT: c_ulong = 0x4004745a; +pub const TIOCSDRAINWAIT: c_ulong = 0x80047457; +pub const TIOCGDRAINWAIT: c_ulong = 0x40047456; +pub const TIOCDSIMICROCODE: c_uint = 0x20007455; +pub const TIOCPTYGRANT: c_uint = 0x20007454; +pub const TIOCPTYGNAME: c_uint = 0x40807453; +pub const TIOCPTYUNLK: c_uint = 0x20007452; +pub const TIOCGETA: c_ulong = 0x40487413; +pub const TIOCSETA: c_ulong = 0x80487414; +pub const TIOCSETAW: c_ulong = 0x80487415; +pub const TIOCSETAF: c_ulong = 0x80487416; + +pub const BIOCGRSIG: c_ulong = 0x40044272; +pub const BIOCSRSIG: c_ulong = 0x80044273; +pub const BIOCSDLT: c_ulong = 0x80044278; +pub const BIOCGSEESENT: c_ulong = 0x40044276; +pub const BIOCSSEESENT: c_ulong = 0x80044277; +pub const BIOCGDLTLIST: c_ulong = 0xc00c4279; + +pub const FIODTYPE: c_ulong = 0x4004667a; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SIGTRAP: c_int = 5; + +pub const GLOB_APPEND: c_int = 0x0001; +pub const GLOB_DOOFFS: c_int = 0x0002; +pub const GLOB_ERR: c_int = 0x0004; +pub const GLOB_MARK: c_int = 0x0008; +pub const GLOB_NOCHECK: c_int = 0x0010; +pub const GLOB_NOSORT: c_int = 0x0020; +pub const GLOB_NOESCAPE: c_int = 0x2000; + +pub const GLOB_NOSPACE: c_int = -1; +pub const GLOB_ABORTED: c_int = -2; +pub const GLOB_NOMATCH: c_int = -3; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const _SC_IOV_MAX: c_int = 56; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 70; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 71; +pub const _SC_LOGIN_NAME_MAX: c_int = 73; +pub const _SC_MQ_PRIO_MAX: c_int = 75; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85; +pub const _SC_THREAD_KEYS_MAX: c_int = 86; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 87; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 88; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 90; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91; +pub const _SC_THREAD_STACK_MIN: c_int = 93; +pub const _SC_THREAD_THREADS_MAX: c_int = 94; +pub const _SC_THREADS: c_int = 96; +pub const _SC_TTY_NAME_MAX: c_int = 101; +pub const _SC_ATEXIT_MAX: c_int = 107; +pub const _SC_XOPEN_CRYPT: c_int = 108; +pub const _SC_XOPEN_ENH_I18N: c_int = 109; +pub const _SC_XOPEN_LEGACY: c_int = 110; +pub const _SC_XOPEN_REALTIME: c_int = 111; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112; +pub const _SC_XOPEN_SHM: c_int = 113; +pub const _SC_XOPEN_UNIX: c_int = 115; +pub const _SC_XOPEN_VERSION: c_int = 116; +pub const _SC_XOPEN_XCU_VERSION: c_int = 121; +pub const _SC_PHYS_PAGES: c_int = 200; + +#[cfg(target_arch = "aarch64")] +pub const PTHREAD_STACK_MIN: size_t = 16384; +#[cfg(not(target_arch = "aarch64"))] +pub const PTHREAD_STACK_MIN: size_t = 8192; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_AS: c_int = 5; +pub const RLIMIT_RSS: c_int = RLIMIT_AS; +pub const RLIMIT_MEMLOCK: c_int = 6; +pub const RLIMIT_NPROC: c_int = 7; +pub const RLIMIT_NOFILE: c_int = 8; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 9; +pub const _RLIMIT_POSIX_FLAG: c_int = 0x1000; + +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 5; +pub const MADV_ZERO_WIRED_PAGES: c_int = 6; +pub const MADV_FREE_REUSABLE: c_int = 7; +pub const MADV_FREE_REUSE: c_int = 8; +pub const MADV_CAN_REUSE: c_int = 9; +pub const MADV_ZERO: c_int = 11; + +pub const MINCORE_INCORE: c_int = 0x1; +pub const MINCORE_REFERENCED: c_int = 0x2; +pub const MINCORE_MODIFIED: c_int = 0x4; +pub const MINCORE_REFERENCED_OTHER: c_int = 0x8; +pub const MINCORE_MODIFIED_OTHER: c_int = 0x10; + +pub const CTLIOCGINFO: c_ulong = 0xc0644e03; + +// +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// gateway2 (deprecated) +pub const IPPROTO_GGP: c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: c_int = 11; +/// pup +pub const IPPROTO_PUP: c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: c_int = 21; +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: c_int = 30; +/// Network Services +pub const IPPROTO_NSP: c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: c_int = 32; +/// Sequential Exchange +pub const IPPROTO_SEP: c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: c_int = 35; +/// XTP +pub const IPPROTO_XTP: c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: c_int = 48; +/// BHA +pub const IPPROTO_BHA: c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: c_int = 54; +/* 55-57: Unassigned */ +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: c_int = 83; +/// TTP +pub const IPPROTO_TTP: c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: c_int = 86; +/// TCF +pub const IPPROTO_TCF: c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: c_int = 100; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: c_int = 103; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: c_int = 108; +/// PGM +pub const IPPROTO_PGM: c_int = 113; +/// SCTP +pub const IPPROTO_SCTP: c_int = 132; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: c_int = 254; +/// raw IP packet +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MAX: c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: c_int = 257; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_ROUTE: c_int = 17; +pub const AF_LINK: c_int = 18; +pub const pseudo_AF_XTP: c_int = 19; +pub const AF_COIP: c_int = 20; +pub const AF_CNT: c_int = 21; +pub const pseudo_AF_RTIP: c_int = 22; +pub const AF_IPX: c_int = 23; +pub const AF_SIP: c_int = 24; +pub const pseudo_AF_PIP: c_int = 25; +pub const AF_NDRV: c_int = 27; +pub const AF_ISDN: c_int = 28; +pub const AF_E164: c_int = AF_ISDN; +pub const pseudo_AF_KEY: c_int = 29; +pub const AF_INET6: c_int = 30; +pub const AF_NATM: c_int = 31; +pub const AF_SYSTEM: c_int = 32; +pub const AF_NETBIOS: c_int = 33; +pub const AF_PPP: c_int = 34; +pub const pseudo_AF_HDRCMPLT: c_int = 35; +pub const AF_IEEE80211: c_int = 37; +pub const AF_UTUN: c_int = 38; +pub const AF_VSOCK: c_int = 40; +pub const AF_SYS_CONTROL: c_int = 2; + +pub const SYSPROTO_EVENT: c_int = 1; +pub const SYSPROTO_CONTROL: c_int = 2; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_ISO; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_XTP: c_int = pseudo_AF_XTP; +pub const PF_COIP: c_int = AF_COIP; +pub const PF_CNT: c_int = AF_CNT; +pub const PF_SIP: c_int = AF_SIP; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_RTIP: c_int = pseudo_AF_RTIP; +pub const PF_PIP: c_int = pseudo_AF_PIP; +pub const PF_NDRV: c_int = AF_NDRV; +pub const PF_ISDN: c_int = AF_ISDN; +pub const PF_KEY: c_int = pseudo_AF_KEY; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_NATM: c_int = AF_NATM; +pub const PF_SYSTEM: c_int = AF_SYSTEM; +pub const PF_NETBIOS: c_int = AF_NETBIOS; +pub const PF_PPP: c_int = AF_PPP; +pub const PF_VSOCK: c_int = AF_VSOCK; + +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const NET_RT_IFLIST: c_int = 3; + +pub const SOMAXCONN: c_int = 128; + +pub const SOCK_MAXADDRLEN: c_int = 255; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const IP_TTL: c_int = 4; +pub const IP_HDRINCL: c_int = 2; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_RECVIF: c_int = 20; +pub const IP_RECVTTL: c_int = 24; +pub const IP_BOUND_IF: c_int = 25; +pub const IP_PKTINFO: c_int = 26; +pub const IP_RECVTOS: c_int = 27; +pub const IP_DONTFRAG: c_int = 28; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; +pub const IPV6_CHECKSUM: c_int = 26; +pub const IPV6_RECVTCLASS: c_int = 35; +pub const IPV6_TCLASS: c_int = 36; +pub const IPV6_RECVHOPLIMIT: c_int = 37; +pub const IPV6_PKTINFO: c_int = 46; +pub const IPV6_HOPLIMIT: c_int = 47; +pub const IPV6_RECVPKTINFO: c_int = 61; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 70; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 71; +pub const IP_BLOCK_SOURCE: c_int = 72; +pub const IP_UNBLOCK_SOURCE: c_int = 73; +pub const IPV6_BOUND_IF: c_int = 125; + +pub const TCP_NOPUSH: c_int = 4; +pub const TCP_NOOPT: c_int = 8; +pub const TCP_KEEPALIVE: c_int = 0x10; +pub const TCP_KEEPINTVL: c_int = 0x101; +pub const TCP_KEEPCNT: c_int = 0x102; +/// Enable/Disable TCP Fastopen on this socket +pub const TCP_FASTOPEN: c_int = 0x105; +pub const TCP_CONNECTION_INFO: c_int = 0x106; + +pub const SOL_LOCAL: c_int = 0; + +/// Retrieve peer credentials. +pub const LOCAL_PEERCRED: c_int = 0x001; +/// Retrieve peer PID. +pub const LOCAL_PEERPID: c_int = 0x002; +/// Retrieve effective peer PID. +pub const LOCAL_PEEREPID: c_int = 0x003; +/// Retrieve peer UUID. +pub const LOCAL_PEERUUID: c_int = 0x004; +/// Retrieve effective peer UUID. +pub const LOCAL_PEEREUUID: c_int = 0x005; +/// Retrieve peer audit token. +pub const LOCAL_PEERTOKEN: c_int = 0x006; + +pub const SOL_SOCKET: c_int = 0xffff; + +pub const SO_DEBUG: c_int = 0x01; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_TIMESTAMP: c_int = 0x0400; +pub const SO_TIMESTAMP_MONOTONIC: c_int = 0x0800; +pub const SO_DONTTRUNC: c_int = 0x2000; +pub const SO_WANTMORE: c_int = 0x4000; +pub const SO_WANTOOBFLAG: c_int = 0x8000; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_LABEL: c_int = 0x1010; +pub const SO_PEERLABEL: c_int = 0x1011; +pub const SO_NREAD: c_int = 0x1020; +pub const SO_NKE: c_int = 0x1021; +pub const SO_NOSIGPIPE: c_int = 0x1022; +pub const SO_NOADDRERR: c_int = 0x1023; +pub const SO_NWRITE: c_int = 0x1024; +pub const SO_REUSESHAREUID: c_int = 0x1025; +pub const SO_NOTIFYCONFLICT: c_int = 0x1026; +pub const SO_LINGER_SEC: c_int = 0x1080; +pub const SO_RANDOMPORT: c_int = 0x1082; +pub const SO_NP_EXTENSIONS: c_int = 0x1083; + +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_EOR: c_int = 0x8; +pub const MSG_TRUNC: c_int = 0x10; +pub const MSG_CTRUNC: c_int = 0x20; +pub const MSG_WAITALL: c_int = 0x40; +pub const MSG_DONTWAIT: c_int = 0x80; +pub const MSG_EOF: c_int = 0x100; +pub const MSG_FLUSH: c_int = 0x400; +pub const MSG_HOLD: c_int = 0x800; +pub const MSG_SEND: c_int = 0x1000; +pub const MSG_HAVEMORE: c_int = 0x2000; +pub const MSG_RCVMORE: c_int = 0x4000; +pub const MSG_NEEDSA: c_int = 0x10000; +pub const MSG_NOSIGNAL: c_int = 0x80000; + +pub const SCM_TIMESTAMP: c_int = 0x02; +pub const SCM_CREDS: c_int = 0x03; + +// https://github.com/aosm/xnu/blob/HEAD/bsd/net/if.h#L140-L156 +pub const IFF_UP: c_int = 0x1; // interface is up +pub const IFF_BROADCAST: c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x10; // interface is point-to-point link +pub const IFF_NOTRAILERS: c_int = 0x20; // obsolete: avoid use of trailers +pub const IFF_RUNNING: c_int = 0x40; // resources allocated +pub const IFF_NOARP: c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE: c_int = 0x400; // transmission in progress +pub const IFF_SIMPLEX: c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + +pub const SCOPE6_ID_MAX: size_t = 16; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const SAE_ASSOCID_ANY: crate::sae_associd_t = 0; +/// ((sae_associd_t)(-1ULL)) +pub const SAE_ASSOCID_ALL: crate::sae_associd_t = 0xffffffff; + +pub const SAE_CONNID_ANY: crate::sae_connid_t = 0; +/// ((sae_connid_t)(-1ULL)) +pub const SAE_CONNID_ALL: crate::sae_connid_t = 0xffffffff; + +// connectx() flag parameters + +/// resume connect() on read/write +pub const CONNECT_RESUME_ON_READ_WRITE: c_uint = 0x1; +/// data is idempotent +pub const CONNECT_DATA_IDEMPOTENT: c_uint = 0x2; +/// data includes security that replaces the TFO-cookie +pub const CONNECT_DATA_AUTHENTICATED: c_uint = 0x4; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const MAP_COPY: c_int = 0x0002; +pub const MAP_RENAME: c_int = 0x0020; +pub const MAP_NORESERVE: c_int = 0x0040; +pub const MAP_NOEXTEND: c_int = 0x0100; +pub const MAP_HASSEMAPHORE: c_int = 0x0200; +pub const MAP_NOCACHE: c_int = 0x0400; +pub const MAP_JIT: c_int = 0x0800; + +pub const _SC_ARG_MAX: c_int = 1; +pub const _SC_CHILD_MAX: c_int = 2; +pub const _SC_CLK_TCK: c_int = 3; +pub const _SC_NGROUPS_MAX: c_int = 4; +pub const _SC_OPEN_MAX: c_int = 5; +pub const _SC_JOB_CONTROL: c_int = 6; +pub const _SC_SAVED_IDS: c_int = 7; +pub const _SC_VERSION: c_int = 8; +pub const _SC_BC_BASE_MAX: c_int = 9; +pub const _SC_BC_DIM_MAX: c_int = 10; +pub const _SC_BC_SCALE_MAX: c_int = 11; +pub const _SC_BC_STRING_MAX: c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; +pub const _SC_EXPR_NEST_MAX: c_int = 14; +pub const _SC_LINE_MAX: c_int = 15; +pub const _SC_RE_DUP_MAX: c_int = 16; +pub const _SC_2_VERSION: c_int = 17; +pub const _SC_2_C_BIND: c_int = 18; +pub const _SC_2_C_DEV: c_int = 19; +pub const _SC_2_CHAR_TERM: c_int = 20; +pub const _SC_2_FORT_DEV: c_int = 21; +pub const _SC_2_FORT_RUN: c_int = 22; +pub const _SC_2_LOCALEDEF: c_int = 23; +pub const _SC_2_SW_DEV: c_int = 24; +pub const _SC_2_UPE: c_int = 25; +pub const _SC_STREAM_MAX: c_int = 26; +pub const _SC_TZNAME_MAX: c_int = 27; +pub const _SC_ASYNCHRONOUS_IO: c_int = 28; +pub const _SC_PAGESIZE: c_int = 29; +pub const _SC_MEMLOCK: c_int = 30; +pub const _SC_MEMLOCK_RANGE: c_int = 31; +pub const _SC_MEMORY_PROTECTION: c_int = 32; +pub const _SC_MESSAGE_PASSING: c_int = 33; +pub const _SC_PRIORITIZED_IO: c_int = 34; +pub const _SC_PRIORITY_SCHEDULING: c_int = 35; +pub const _SC_REALTIME_SIGNALS: c_int = 36; +pub const _SC_SEMAPHORES: c_int = 37; +pub const _SC_FSYNC: c_int = 38; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39; +pub const _SC_SYNCHRONIZED_IO: c_int = 40; +pub const _SC_TIMERS: c_int = 41; +pub const _SC_AIO_LISTIO_MAX: c_int = 42; +pub const _SC_AIO_MAX: c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; +pub const _SC_DELAYTIMER_MAX: c_int = 45; +pub const _SC_MQ_OPEN_MAX: c_int = 46; +pub const _SC_MAPPED_FILES: c_int = 47; +pub const _SC_RTSIG_MAX: c_int = 48; +pub const _SC_SEM_NSEMS_MAX: c_int = 49; +pub const _SC_SEM_VALUE_MAX: c_int = 50; +pub const _SC_SIGQUEUE_MAX: c_int = 51; +pub const _SC_TIMER_MAX: c_int = 52; +pub const _SC_NPROCESSORS_CONF: c_int = 57; +pub const _SC_NPROCESSORS_ONLN: c_int = 58; +pub const _SC_2_PBS: c_int = 59; +pub const _SC_2_PBS_ACCOUNTING: c_int = 60; +pub const _SC_2_PBS_CHECKPOINT: c_int = 61; +pub const _SC_2_PBS_LOCATE: c_int = 62; +pub const _SC_2_PBS_MESSAGE: c_int = 63; +pub const _SC_2_PBS_TRACK: c_int = 64; +pub const _SC_ADVISORY_INFO: c_int = 65; +pub const _SC_BARRIERS: c_int = 66; +pub const _SC_CLOCK_SELECTION: c_int = 67; +pub const _SC_CPUTIME: c_int = 68; +pub const _SC_FILE_LOCKING: c_int = 69; +pub const _SC_HOST_NAME_MAX: c_int = 72; +pub const _SC_MONOTONIC_CLOCK: c_int = 74; +pub const _SC_READER_WRITER_LOCKS: c_int = 76; +pub const _SC_REGEXP: c_int = 77; +pub const _SC_SHELL: c_int = 78; +pub const _SC_SPAWN: c_int = 79; +pub const _SC_SPIN_LOCKS: c_int = 80; +pub const _SC_SPORADIC_SERVER: c_int = 81; +pub const _SC_THREAD_CPUTIME: c_int = 84; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 92; +pub const _SC_TIMEOUTS: c_int = 95; +pub const _SC_TRACE: c_int = 97; +pub const _SC_TRACE_EVENT_FILTER: c_int = 98; +pub const _SC_TRACE_INHERIT: c_int = 99; +pub const _SC_TRACE_LOG: c_int = 100; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 102; +pub const _SC_V6_ILP32_OFF32: c_int = 103; +pub const _SC_V6_ILP32_OFFBIG: c_int = 104; +pub const _SC_V6_LP64_OFF64: c_int = 105; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 106; +pub const _SC_IPV6: c_int = 118; +pub const _SC_RAW_SOCKETS: c_int = 119; +pub const _SC_SYMLOOP_MAX: c_int = 120; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_XOPEN_STREAMS: c_int = 114; +pub const _SC_XBS5_ILP32_OFF32: c_int = 122; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 123; +pub const _SC_XBS5_LP64_OFF64: c_int = 124; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 125; +pub const _SC_SS_REPL_MAX: c_int = 126; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 127; +pub const _SC_TRACE_NAME_MAX: c_int = 128; +pub const _SC_TRACE_SYS_MAX: c_int = 129; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 130; +pub const _SC_PASS_MAX: c_int = 131; +// `confstr` keys (only the values guaranteed by `man confstr`). +pub const _CS_PATH: c_int = 1; +pub const _CS_DARWIN_USER_DIR: c_int = 65536; +pub const _CS_DARWIN_USER_TEMP_DIR: c_int = 65537; +pub const _CS_DARWIN_USER_CACHE_DIR: c_int = 65538; + +pub const OS_UNFAIR_LOCK_INIT: os_unfair_lock = os_unfair_lock { + _os_unfair_lock_opaque: 0, +}; + +pub const OS_LOG_TYPE_DEFAULT: crate::os_log_type_t = 0x00; +pub const OS_LOG_TYPE_INFO: crate::os_log_type_t = 0x01; +pub const OS_LOG_TYPE_DEBUG: crate::os_log_type_t = 0x02; +pub const OS_LOG_TYPE_ERROR: crate::os_log_type_t = 0x10; +pub const OS_LOG_TYPE_FAULT: crate::os_log_type_t = 0x11; + +pub const OS_SIGNPOST_EVENT: crate::os_signpost_type_t = 0x00; +pub const OS_SIGNPOST_INTERVAL_BEGIN: crate::os_signpost_type_t = 0x01; +pub const OS_SIGNPOST_INTERVAL_END: crate::os_signpost_type_t = 0x02; + +pub const MINSIGSTKSZ: size_t = 32768; +pub const SIGSTKSZ: size_t = 131072; + +pub const FD_SETSIZE: usize = 1024; + +pub const ST_NOSUID: c_ulong = 2; + +pub const EVFILT_READ: i16 = -1; +pub const EVFILT_WRITE: i16 = -2; +pub const EVFILT_AIO: i16 = -3; +pub const EVFILT_VNODE: i16 = -4; +pub const EVFILT_PROC: i16 = -5; +pub const EVFILT_SIGNAL: i16 = -6; +pub const EVFILT_TIMER: i16 = -7; +pub const EVFILT_MACHPORT: i16 = -8; +pub const EVFILT_FS: i16 = -9; +pub const EVFILT_USER: i16 = -10; +pub const EVFILT_VM: i16 = -12; + +pub const EV_ADD: u16 = 0x1; +pub const EV_DELETE: u16 = 0x2; +pub const EV_ENABLE: u16 = 0x4; +pub const EV_DISABLE: u16 = 0x8; +pub const EV_ONESHOT: u16 = 0x10; +pub const EV_CLEAR: u16 = 0x20; +pub const EV_RECEIPT: u16 = 0x40; +pub const EV_DISPATCH: u16 = 0x80; +pub const EV_FLAG0: u16 = 0x1000; +pub const EV_POLL: u16 = 0x1000; +pub const EV_FLAG1: u16 = 0x2000; +pub const EV_OOBAND: u16 = 0x2000; +pub const EV_ERROR: u16 = 0x4000; +pub const EV_EOF: u16 = 0x8000; +pub const EV_SYSFLAGS: u16 = 0xf000; + +pub const KEVENT_FLAG_NONE: c_uint = 0x000000; +pub const KEVENT_FLAG_IMMEDIATE: c_uint = 0x000001; +pub const KEVENT_FLAG_ERROR_EVENTS: c_uint = 0x000002; + +pub const NOTE_TRIGGER: u32 = 0x01000000; +pub const NOTE_FFNOP: u32 = 0x00000000; +pub const NOTE_FFAND: u32 = 0x40000000; +pub const NOTE_FFOR: u32 = 0x80000000; +pub const NOTE_FFCOPY: u32 = 0xc0000000; +pub const NOTE_FFCTRLMASK: u32 = 0xc0000000; +pub const NOTE_FFLAGSMASK: u32 = 0x00ffffff; +pub const NOTE_LOWAT: u32 = 0x00000001; +pub const NOTE_DELETE: u32 = 0x00000001; +pub const NOTE_WRITE: u32 = 0x00000002; +pub const NOTE_EXTEND: u32 = 0x00000004; +pub const NOTE_ATTRIB: u32 = 0x00000008; +pub const NOTE_LINK: u32 = 0x00000010; +pub const NOTE_RENAME: u32 = 0x00000020; +pub const NOTE_REVOKE: u32 = 0x00000040; +pub const NOTE_NONE: u32 = 0x00000080; +pub const NOTE_EXIT: u32 = 0x80000000; +pub const NOTE_FORK: u32 = 0x40000000; +pub const NOTE_EXEC: u32 = 0x20000000; +#[doc(hidden)] +#[deprecated(since = "0.2.49", note = "Deprecated since MacOSX 10.9")] +pub const NOTE_REAP: u32 = 0x10000000; +pub const NOTE_SIGNAL: u32 = 0x08000000; +pub const NOTE_EXITSTATUS: u32 = 0x04000000; +pub const NOTE_EXIT_DETAIL: u32 = 0x02000000; +pub const NOTE_PDATAMASK: u32 = 0x000fffff; +pub const NOTE_PCTRLMASK: u32 = 0xfff00000; +#[doc(hidden)] +#[deprecated(since = "0.2.49", note = "Deprecated since MacOSX 10.9")] +pub const NOTE_EXIT_REPARENTED: u32 = 0x00080000; +pub const NOTE_EXIT_DETAIL_MASK: u32 = 0x00070000; +pub const NOTE_EXIT_DECRYPTFAIL: u32 = 0x00010000; +pub const NOTE_EXIT_MEMORY: u32 = 0x00020000; +pub const NOTE_EXIT_CSERROR: u32 = 0x00040000; +pub const NOTE_VM_PRESSURE: u32 = 0x80000000; +pub const NOTE_VM_PRESSURE_TERMINATE: u32 = 0x40000000; +pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE: u32 = 0x20000000; +pub const NOTE_VM_ERROR: u32 = 0x10000000; +pub const NOTE_SECONDS: u32 = 0x00000001; +pub const NOTE_USECONDS: u32 = 0x00000002; +pub const NOTE_NSECONDS: u32 = 0x00000004; +pub const NOTE_ABSOLUTE: u32 = 0x00000008; +pub const NOTE_LEEWAY: u32 = 0x00000010; +pub const NOTE_CRITICAL: u32 = 0x00000020; +pub const NOTE_BACKGROUND: u32 = 0x00000040; +pub const NOTE_MACH_CONTINUOUS_TIME: u32 = 0x00000080; +pub const NOTE_MACHTIME: u32 = 0x00000100; +pub const NOTE_TRACK: u32 = 0x00000001; +pub const NOTE_TRACKERR: u32 = 0x00000002; +pub const NOTE_CHILD: u32 = 0x00000004; + +pub const OCRNL: crate::tcflag_t = 0x00000010; +pub const ONOCR: crate::tcflag_t = 0x00000020; +pub const ONLRET: crate::tcflag_t = 0x00000040; +pub const OFILL: crate::tcflag_t = 0x00000080; +pub const NLDLY: crate::tcflag_t = 0x00000300; +pub const TABDLY: crate::tcflag_t = 0x00000c04; +pub const CRDLY: crate::tcflag_t = 0x00003000; +pub const FFDLY: crate::tcflag_t = 0x00004000; +pub const BSDLY: crate::tcflag_t = 0x00008000; +pub const VTDLY: crate::tcflag_t = 0x00010000; +pub const OFDEL: crate::tcflag_t = 0x00020000; + +pub const NL0: crate::tcflag_t = 0x00000000; +pub const NL1: crate::tcflag_t = 0x00000100; +pub const TAB0: crate::tcflag_t = 0x00000000; +pub const TAB1: crate::tcflag_t = 0x00000400; +pub const TAB2: crate::tcflag_t = 0x00000800; +pub const CR0: crate::tcflag_t = 0x00000000; +pub const CR1: crate::tcflag_t = 0x00001000; +pub const CR2: crate::tcflag_t = 0x00002000; +pub const CR3: crate::tcflag_t = 0x00003000; +pub const FF0: crate::tcflag_t = 0x00000000; +pub const FF1: crate::tcflag_t = 0x00004000; +pub const BS0: crate::tcflag_t = 0x00000000; +pub const BS1: crate::tcflag_t = 0x00008000; +pub const TAB3: crate::tcflag_t = 0x00000004; +pub const VT0: crate::tcflag_t = 0x00000000; +pub const VT1: crate::tcflag_t = 0x00010000; +pub const IUTF8: crate::tcflag_t = 0x00004000; +pub const CRTSCTS: crate::tcflag_t = 0x00030000; + +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const NI_MAXSERV: crate::socklen_t = 32; +pub const NI_NOFQDN: c_int = 0x00000001; +pub const NI_NUMERICHOST: c_int = 0x00000002; +pub const NI_NAMEREQD: c_int = 0x00000004; +pub const NI_NUMERICSERV: c_int = 0x00000008; +pub const NI_NUMERICSCOPE: c_int = 0x00000100; +pub const NI_DGRAM: c_int = 0x00000010; + +pub const Q_GETQUOTA: c_int = 0x300; +pub const Q_SETQUOTA: c_int = 0x400; + +pub const RENAME_SWAP: c_uint = 0x00000002; +pub const RENAME_EXCL: c_uint = 0x00000004; + +pub const RTLD_LOCAL: c_int = 0x4; +pub const RTLD_FIRST: c_int = 0x100; +pub const RTLD_NODELETE: c_int = 0x80; +pub const RTLD_NOLOAD: c_int = 0x10; +pub const RTLD_GLOBAL: c_int = 0x8; +pub const RTLD_MAIN_ONLY: *mut c_void = -5isize as *mut c_void; + +pub const _WSTOPPED: c_int = 0o177; + +pub const LOG_NETINFO: c_int = 12 << 3; +pub const LOG_REMOTEAUTH: c_int = 13 << 3; +pub const LOG_INSTALL: c_int = 14 << 3; +pub const LOG_RAS: c_int = 15 << 3; +pub const LOG_LAUNCHD: c_int = 24 << 3; +pub const LOG_NFACILITIES: c_int = 25; + +pub const CTLTYPE: c_int = 0xf; +pub const CTLTYPE_NODE: c_int = 1; +pub const CTLTYPE_INT: c_int = 2; +pub const CTLTYPE_STRING: c_int = 3; +pub const CTLTYPE_QUAD: c_int = 4; +pub const CTLTYPE_OPAQUE: c_int = 5; +pub const CTLTYPE_STRUCT: c_int = CTLTYPE_OPAQUE; +pub const CTLFLAG_RD: c_int = 0x80000000; +pub const CTLFLAG_WR: c_int = 0x40000000; +pub const CTLFLAG_RW: c_int = CTLFLAG_RD | CTLFLAG_WR; +pub const CTLFLAG_NOLOCK: c_int = 0x20000000; +pub const CTLFLAG_ANYBODY: c_int = 0x10000000; +pub const CTLFLAG_SECURE: c_int = 0x08000000; +pub const CTLFLAG_MASKED: c_int = 0x04000000; +pub const CTLFLAG_NOAUTO: c_int = 0x02000000; +pub const CTLFLAG_KERN: c_int = 0x01000000; +pub const CTLFLAG_LOCKED: c_int = 0x00800000; +pub const CTLFLAG_OID2: c_int = 0x00400000; +pub const CTL_UNSPEC: c_int = 0; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_VFS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_USER: c_int = 8; +pub const CTL_MAXID: c_int = 9; +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_VNODE: c_int = 13; +pub const KERN_PROC: c_int = 14; +pub const KERN_FILE: c_int = 15; +pub const KERN_PROF: c_int = 16; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_BOOTTIME: c_int = 21; +pub const KERN_NISDOMAINNAME: c_int = 22; +pub const KERN_DOMAINNAME: c_int = KERN_NISDOMAINNAME; +pub const KERN_MAXPARTITIONS: c_int = 23; +pub const KERN_KDEBUG: c_int = 24; +pub const KERN_UPDATEINTERVAL: c_int = 25; +pub const KERN_OSRELDATE: c_int = 26; +pub const KERN_NTP_PLL: c_int = 27; +pub const KERN_BOOTFILE: c_int = 28; +pub const KERN_MAXFILESPERPROC: c_int = 29; +pub const KERN_MAXPROCPERUID: c_int = 30; +pub const KERN_DUMPDEV: c_int = 31; +pub const KERN_IPC: c_int = 32; +pub const KERN_DUMMY: c_int = 33; +pub const KERN_PS_STRINGS: c_int = 34; +pub const KERN_USRSTACK32: c_int = 35; +pub const KERN_LOGSIGEXIT: c_int = 36; +pub const KERN_SYMFILE: c_int = 37; +pub const KERN_PROCARGS: c_int = 38; +pub const KERN_NETBOOT: c_int = 40; +pub const KERN_SYSV: c_int = 42; +pub const KERN_AFFINITY: c_int = 43; +pub const KERN_TRANSLATE: c_int = 44; +pub const KERN_CLASSIC: c_int = KERN_TRANSLATE; +pub const KERN_EXEC: c_int = 45; +pub const KERN_CLASSICHANDLER: c_int = KERN_EXEC; +pub const KERN_AIOMAX: c_int = 46; +pub const KERN_AIOPROCMAX: c_int = 47; +pub const KERN_AIOTHREADS: c_int = 48; +pub const KERN_COREFILE: c_int = 50; +pub const KERN_COREDUMP: c_int = 51; +pub const KERN_SUGID_COREDUMP: c_int = 52; +pub const KERN_PROCDELAYTERM: c_int = 53; +pub const KERN_SHREG_PRIVATIZABLE: c_int = 54; +pub const KERN_LOW_PRI_WINDOW: c_int = 56; +pub const KERN_LOW_PRI_DELAY: c_int = 57; +pub const KERN_POSIX: c_int = 58; +pub const KERN_USRSTACK64: c_int = 59; +pub const KERN_NX_PROTECTION: c_int = 60; +pub const KERN_TFP: c_int = 61; +pub const KERN_PROCNAME: c_int = 62; +pub const KERN_THALTSTACK: c_int = 63; +pub const KERN_SPECULATIVE_READS: c_int = 64; +pub const KERN_OSVERSION: c_int = 65; +pub const KERN_SAFEBOOT: c_int = 66; +pub const KERN_RAGEVNODE: c_int = 68; +pub const KERN_TTY: c_int = 69; +pub const KERN_CHECKOPENEVT: c_int = 70; +pub const KERN_THREADNAME: c_int = 71; +pub const KERN_MAXID: c_int = 72; +pub const KERN_RAGE_PROC: c_int = 1; +pub const KERN_RAGE_THREAD: c_int = 2; +pub const KERN_UNRAGE_PROC: c_int = 3; +pub const KERN_UNRAGE_THREAD: c_int = 4; +pub const KERN_OPENEVT_PROC: c_int = 1; +pub const KERN_UNOPENEVT_PROC: c_int = 2; +pub const KERN_TFP_POLICY: c_int = 1; +pub const KERN_TFP_POLICY_DENY: c_int = 0; +pub const KERN_TFP_POLICY_DEFAULT: c_int = 2; +pub const KERN_KDEFLAGS: c_int = 1; +pub const KERN_KDDFLAGS: c_int = 2; +pub const KERN_KDENABLE: c_int = 3; +pub const KERN_KDSETBUF: c_int = 4; +pub const KERN_KDGETBUF: c_int = 5; +pub const KERN_KDSETUP: c_int = 6; +pub const KERN_KDREMOVE: c_int = 7; +pub const KERN_KDSETREG: c_int = 8; +pub const KERN_KDGETREG: c_int = 9; +pub const KERN_KDREADTR: c_int = 10; +pub const KERN_KDPIDTR: c_int = 11; +pub const KERN_KDTHRMAP: c_int = 12; +pub const KERN_KDPIDEX: c_int = 14; +pub const KERN_KDSETRTCDEC: c_int = 15; +pub const KERN_KDGETENTROPY: c_int = 16; +pub const KERN_KDWRITETR: c_int = 17; +pub const KERN_KDWRITEMAP: c_int = 18; +#[doc(hidden)] +#[deprecated(since = "0.2.49", note = "Removed in MacOSX 10.12")] +pub const KERN_KDENABLE_BG_TRACE: c_int = 19; +#[doc(hidden)] +#[deprecated(since = "0.2.49", note = "Removed in MacOSX 10.12")] +pub const KERN_KDDISABLE_BG_TRACE: c_int = 20; +pub const KERN_KDREADCURTHRMAP: c_int = 21; +pub const KERN_KDSET_TYPEFILTER: c_int = 22; +pub const KERN_KDBUFWAIT: c_int = 23; +pub const KERN_KDCPUMAP: c_int = 24; +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_LCID: c_int = 7; +pub const KERN_SUCCESS: c_int = 0; +pub const KERN_INVALID_ADDRESS: c_int = 1; +pub const KERN_PROTECTION_FAILURE: c_int = 2; +pub const KERN_NO_SPACE: c_int = 3; +pub const KERN_INVALID_ARGUMENT: c_int = 4; +pub const KERN_FAILURE: c_int = 5; +pub const KERN_RESOURCE_SHORTAGE: c_int = 6; +pub const KERN_NOT_RECEIVER: c_int = 7; +pub const KERN_NO_ACCESS: c_int = 8; +pub const KERN_MEMORY_FAILURE: c_int = 9; +pub const KERN_MEMORY_ERROR: c_int = 10; +pub const KERN_ALREADY_IN_SET: c_int = 11; +pub const KERN_NOT_IN_SET: c_int = 12; +pub const KERN_NAME_EXISTS: c_int = 13; +pub const KERN_ABORTED: c_int = 14; +pub const KERN_INVALID_NAME: c_int = 15; +pub const KERN_INVALID_TASK: c_int = 16; +pub const KERN_INVALID_RIGHT: c_int = 17; +pub const KERN_INVALID_VALUE: c_int = 18; +pub const KERN_UREFS_OVERFLOW: c_int = 19; +pub const KERN_INVALID_CAPABILITY: c_int = 20; +pub const KERN_RIGHT_EXISTS: c_int = 21; +pub const KERN_INVALID_HOST: c_int = 22; +pub const KERN_MEMORY_PRESENT: c_int = 23; +pub const KERN_MEMORY_DATA_MOVED: c_int = 24; +pub const KERN_MEMORY_RESTART_COPY: c_int = 25; +pub const KERN_INVALID_PROCESSOR_SET: c_int = 26; +pub const KERN_POLICY_LIMIT: c_int = 27; +pub const KERN_INVALID_POLICY: c_int = 28; +pub const KERN_INVALID_OBJECT: c_int = 29; +pub const KERN_ALREADY_WAITING: c_int = 30; +pub const KERN_DEFAULT_SET: c_int = 31; +pub const KERN_EXCEPTION_PROTECTED: c_int = 32; +pub const KERN_INVALID_LEDGER: c_int = 33; +pub const KERN_INVALID_MEMORY_CONTROL: c_int = 34; +pub const KERN_INVALID_SECURITY: c_int = 35; +pub const KERN_NOT_DEPRESSED: c_int = 36; +pub const KERN_TERMINATED: c_int = 37; +pub const KERN_LOCK_SET_DESTROYED: c_int = 38; +pub const KERN_LOCK_UNSTABLE: c_int = 39; +pub const KERN_LOCK_OWNED: c_int = 40; +pub const KERN_LOCK_OWNED_SELF: c_int = 41; +pub const KERN_SEMAPHORE_DESTROYED: c_int = 42; +pub const KERN_RPC_SERVER_TERMINATED: c_int = 43; +pub const KERN_RPC_TERMINATE_ORPHAN: c_int = 44; +pub const KERN_RPC_CONTINUE_ORPHAN: c_int = 45; +pub const KERN_NOT_SUPPORTED: c_int = 46; +pub const KERN_NODE_DOWN: c_int = 47; +pub const KERN_NOT_WAITING: c_int = 48; +pub const KERN_OPERATION_TIMED_OUT: c_int = 49; +pub const KERN_CODESIGN_ERROR: c_int = 50; +pub const KERN_POLICY_STATIC: c_int = 51; +pub const KERN_INSUFFICIENT_BUFFER_SIZE: c_int = 52; +pub const KIPC_MAXSOCKBUF: c_int = 1; +pub const KIPC_SOCKBUF_WASTE: c_int = 2; +pub const KIPC_SOMAXCONN: c_int = 3; +pub const KIPC_MAX_LINKHDR: c_int = 4; +pub const KIPC_MAX_PROTOHDR: c_int = 5; +pub const KIPC_MAX_HDR: c_int = 6; +pub const KIPC_MAX_DATALEN: c_int = 7; +pub const KIPC_MBSTAT: c_int = 8; +pub const KIPC_NMBCLUSTERS: c_int = 9; +pub const KIPC_SOQLIMITCOMPAT: c_int = 10; +pub const VM_METER: c_int = 1; +pub const VM_LOADAVG: c_int = 2; +pub const VM_MACHFACTOR: c_int = 4; +pub const VM_SWAPUSAGE: c_int = 5; +pub const VM_MAXID: c_int = 6; +pub const VM_PROT_NONE: crate::vm_prot_t = 0x00; +pub const VM_PROT_READ: crate::vm_prot_t = 0x01; +pub const VM_PROT_WRITE: crate::vm_prot_t = 0x02; +pub const VM_PROT_EXECUTE: crate::vm_prot_t = 0x04; +pub const MEMORY_OBJECT_NULL: crate::memory_object_t = 0; +pub const HW_MACHINE: c_int = 1; +pub const HW_MODEL: c_int = 2; +pub const HW_NCPU: c_int = 3; +pub const HW_BYTEORDER: c_int = 4; +pub const HW_PHYSMEM: c_int = 5; +pub const HW_USERMEM: c_int = 6; +pub const HW_PAGESIZE: c_int = 7; +pub const HW_DISKNAMES: c_int = 8; +pub const HW_DISKSTATS: c_int = 9; +pub const HW_EPOCH: c_int = 10; +pub const HW_FLOATINGPT: c_int = 11; +pub const HW_MACHINE_ARCH: c_int = 12; +pub const HW_VECTORUNIT: c_int = 13; +pub const HW_BUS_FREQ: c_int = 14; +pub const HW_CPU_FREQ: c_int = 15; +pub const HW_CACHELINE: c_int = 16; +pub const HW_L1ICACHESIZE: c_int = 17; +pub const HW_L1DCACHESIZE: c_int = 18; +pub const HW_L2SETTINGS: c_int = 19; +pub const HW_L2CACHESIZE: c_int = 20; +pub const HW_L3SETTINGS: c_int = 21; +pub const HW_L3CACHESIZE: c_int = 22; +pub const HW_TB_FREQ: c_int = 23; +pub const HW_MEMSIZE: c_int = 24; +pub const HW_AVAILCPU: c_int = 25; +pub const HW_TARGET: c_int = 26; +pub const HW_PRODUCT: c_int = 27; +pub const HW_MAXID: c_int = 28; +pub const USER_CS_PATH: c_int = 1; +pub const USER_BC_BASE_MAX: c_int = 2; +pub const USER_BC_DIM_MAX: c_int = 3; +pub const USER_BC_SCALE_MAX: c_int = 4; +pub const USER_BC_STRING_MAX: c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: c_int = 6; +pub const USER_EXPR_NEST_MAX: c_int = 7; +pub const USER_LINE_MAX: c_int = 8; +pub const USER_RE_DUP_MAX: c_int = 9; +pub const USER_POSIX2_VERSION: c_int = 10; +pub const USER_POSIX2_C_BIND: c_int = 11; +pub const USER_POSIX2_C_DEV: c_int = 12; +pub const USER_POSIX2_CHAR_TERM: c_int = 13; +pub const USER_POSIX2_FORT_DEV: c_int = 14; +pub const USER_POSIX2_FORT_RUN: c_int = 15; +pub const USER_POSIX2_LOCALEDEF: c_int = 16; +pub const USER_POSIX2_SW_DEV: c_int = 17; +pub const USER_POSIX2_UPE: c_int = 18; +pub const USER_STREAM_MAX: c_int = 19; +pub const USER_TZNAME_MAX: c_int = 20; +pub const USER_MAXID: c_int = 21; +pub const CTL_DEBUG_NAME: c_int = 0; +pub const CTL_DEBUG_VALUE: c_int = 1; +pub const CTL_DEBUG_MAXID: c_int = 20; + +pub const PRIO_DARWIN_THREAD: c_int = 3; +pub const PRIO_DARWIN_PROCESS: c_int = 4; +pub const PRIO_DARWIN_BG: c_int = 0x1000; +pub const PRIO_DARWIN_NONUI: c_int = 0x1001; + +pub const SEM_FAILED: *mut sem_t = -1isize as *mut crate::sem_t; + +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; +pub const AI_NUMERICSERV: c_int = 0x00001000; +pub const AI_MASK: c_int = + AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG; +pub const AI_ALL: c_int = 0x00000100; +pub const AI_V4MAPPED_CFG: c_int = 0x00000200; +pub const AI_ADDRCONFIG: c_int = 0x00000400; +pub const AI_V4MAPPED: c_int = 0x00000800; +pub const AI_DEFAULT: c_int = AI_V4MAPPED_CFG | AI_ADDRCONFIG; +pub const AI_UNUSABLE: c_int = 0x10000000; + +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 3; + +pub const AIO_CANCELED: c_int = 2; +pub const AIO_NOTCANCELED: c_int = 4; +pub const AIO_ALLDONE: c_int = 1; +#[deprecated( + since = "0.2.64", + note = "Can vary at runtime. Use sysconf(3) instead" +)] +pub const AIO_LISTIO_MAX: c_int = 16; +pub const LIO_NOP: c_int = 0; +pub const LIO_WRITE: c_int = 2; +pub const LIO_READ: c_int = 1; +pub const LIO_WAIT: c_int = 2; +pub const LIO_NOWAIT: c_int = 1; + +pub const WEXITED: c_int = 0x00000004; +pub const WSTOPPED: c_int = 0x00000008; +pub const WCONTINUED: c_int = 0x00000010; +pub const WNOWAIT: c_int = 0x00000020; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = -2; +pub const UTIME_NOW: c_long = -1; + +pub const XATTR_NOFOLLOW: c_int = 0x0001; +pub const XATTR_CREATE: c_int = 0x0002; +pub const XATTR_REPLACE: c_int = 0x0004; +pub const XATTR_NOSECURITY: c_int = 0x0008; +pub const XATTR_NODEFAULT: c_int = 0x0010; +pub const XATTR_SHOWCOMPRESSION: c_int = 0x0020; + +pub const NET_RT_IFLIST2: c_int = 0x0006; + +// net/route.h +pub const RTF_DELCLONE: c_int = 0x80; +pub const RTF_CLONING: c_int = 0x100; +pub const RTF_XRESOLVE: c_int = 0x200; +pub const RTF_LLINFO: c_int = 0x400; +pub const RTF_NOIFREF: c_int = 0x2000; +pub const RTF_PRCLONING: c_int = 0x10000; +pub const RTF_WASCLONED: c_int = 0x20000; +pub const RTF_PROTO3: c_int = 0x40000; +pub const RTF_PINNED: c_int = 0x100000; +pub const RTF_LOCAL: c_int = 0x200000; +pub const RTF_BROADCAST: c_int = 0x400000; +pub const RTF_MULTICAST: c_int = 0x800000; +pub const RTF_IFSCOPE: c_int = 0x1000000; +pub const RTF_CONDEMNED: c_int = 0x2000000; +pub const RTF_IFREF: c_int = 0x4000000; +pub const RTF_PROXY: c_int = 0x8000000; +pub const RTF_ROUTER: c_int = 0x10000000; +pub const RTF_DEAD: c_int = 0x20000000; +pub const RTF_GLOBAL: c_int = 0x40000000; + +pub const RTM_VERSION: c_int = 5; + +// Message types +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_OLDADD: c_int = 0x9; +pub const RTM_OLDDEL: c_int = 0xa; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_NEWMADDR: c_int = 0xf; +pub const RTM_DELMADDR: c_int = 0x10; +pub const RTM_IFINFO2: c_int = 0x12; +pub const RTM_NEWMADDR2: c_int = 0x13; +pub const RTM_GET2: c_int = 0x14; + +// Bitmask values for rtm_inits and rmx_locks. +pub const RTV_MTU: c_int = 0x1; +pub const RTV_HOPCOUNT: c_int = 0x2; +pub const RTV_EXPIRE: c_int = 0x4; +pub const RTV_RPIPE: c_int = 0x8; +pub const RTV_SPIPE: c_int = 0x10; +pub const RTV_SSTHRESH: c_int = 0x20; +pub const RTV_RTT: c_int = 0x40; +pub const RTV_RTTVAR: c_int = 0x80; + +pub const RTAX_MAX: c_int = 8; + +pub const KERN_PROCARGS2: c_int = 49; + +pub const PROC_PIDTASKALLINFO: c_int = 2; +pub const PROC_PIDTBSDINFO: c_int = 3; +pub const PROC_PIDTASKINFO: c_int = 4; +pub const PROC_PIDTHREADINFO: c_int = 5; +pub const PROC_PIDVNODEPATHINFO: c_int = 9; +pub const PROC_PIDPATHINFO_MAXSIZE: c_int = 4096; + +pub const PROC_PIDLISTFDS: c_int = 1; +pub const PROC_PIDLISTFD_SIZE: c_int = size_of::() as c_int; +pub const PROX_FDTYPE_ATALK: c_int = 0; +pub const PROX_FDTYPE_VNODE: c_int = 1; +pub const PROX_FDTYPE_SOCKET: c_int = 2; +pub const PROX_FDTYPE_PSHM: c_int = 3; +pub const PROX_FDTYPE_PSEM: c_int = 4; +pub const PROX_FDTYPE_KQUEUE: c_int = 5; +pub const PROX_FDTYPE_PIPE: c_int = 6; +pub const PROX_FDTYPE_FSEVENTS: c_int = 7; +pub const PROX_FDTYPE_NETPOLICY: c_int = 9; +pub const PROX_FDTYPE_CHANNEL: c_int = 10; +pub const PROX_FDTYPE_NEXUS: c_int = 11; + +pub const PROC_CSM_ALL: c_uint = 0x0001; +pub const PROC_CSM_NOSMT: c_uint = 0x0002; +pub const PROC_CSM_TECS: c_uint = 0x0004; +pub const MAXCOMLEN: usize = 16; +pub const MAXTHREADNAMESIZE: usize = 64; + +pub const XUCRED_VERSION: c_uint = 0; + +pub const LC_SEGMENT: u32 = 0x1; +pub const LC_SEGMENT_64: u32 = 0x19; + +pub const MH_MAGIC: u32 = 0xfeedface; +pub const MH_MAGIC_64: u32 = 0xfeedfacf; + +// net/if_utun.h +pub const UTUN_OPT_FLAGS: c_int = 1; +pub const UTUN_OPT_IFNAME: c_int = 2; + +// net/bpf.h +pub const DLT_NULL: c_uint = 0; // no link-layer encapsulation +pub const DLT_EN10MB: c_uint = 1; // Ethernet (10Mb) +pub const DLT_EN3MB: c_uint = 2; // Experimental Ethernet (3Mb) +pub const DLT_AX25: c_uint = 3; // Amateur Radio AX.25 +pub const DLT_PRONET: c_uint = 4; // Proteon ProNET Token Ring +pub const DLT_CHAOS: c_uint = 5; // Chaos +pub const DLT_IEEE802: c_uint = 6; // IEEE 802 Networks +pub const DLT_ARCNET: c_uint = 7; // ARCNET +pub const DLT_SLIP: c_uint = 8; // Serial Line IP +pub const DLT_PPP: c_uint = 9; // Point-to-point Protocol +pub const DLT_FDDI: c_uint = 10; // FDDI +pub const DLT_ATM_RFC1483: c_uint = 11; // LLC/SNAP encapsulated atm +pub const DLT_RAW: c_uint = 12; // raw IP +pub const DLT_LOOP: c_uint = 108; + +// https://github.com/apple/darwin-xnu/blob/HEAD/bsd/net/bpf.h#L100 +// sizeof(i32) +pub const BPF_ALIGNMENT: c_int = 4; + +// sys/mount.h +pub const MNT_NODEV: c_int = 0x00000010; +pub const MNT_UNION: c_int = 0x00000020; +pub const MNT_CPROTECT: c_int = 0x00000080; + +// MAC labeled / "quarantined" flag +pub const MNT_QUARANTINE: c_int = 0x00000400; + +// Flags set by internal operations. +pub const MNT_LOCAL: c_int = 0x00001000; +pub const MNT_QUOTA: c_int = 0x00002000; +pub const MNT_ROOTFS: c_int = 0x00004000; +pub const MNT_DOVOLFS: c_int = 0x00008000; + +pub const MNT_DONTBROWSE: c_int = 0x00100000; +pub const MNT_IGNORE_OWNERSHIP: c_int = 0x00200000; +pub const MNT_AUTOMOUNTED: c_int = 0x00400000; +pub const MNT_JOURNALED: c_int = 0x00800000; +pub const MNT_NOUSERXATTR: c_int = 0x01000000; +pub const MNT_DEFWRITE: c_int = 0x02000000; +pub const MNT_MULTILABEL: c_int = 0x04000000; +pub const MNT_NOATIME: c_int = 0x10000000; +pub const MNT_SNAPSHOT: c_int = 0x40000000; + +// External filesystem command modifier flags. +pub const MNT_NOBLOCK: c_int = 0x00020000; + +// sys/spawn.h: +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x0001; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x0002; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x0004; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x0008; +pub const POSIX_SPAWN_SETEXEC: c_int = 0x0040; +pub const POSIX_SPAWN_START_SUSPENDED: c_int = 0x0080; +pub const POSIX_SPAWN_CLOEXEC_DEFAULT: c_int = 0x4000; + +// sys/ipc.h: +pub const IPC_CREAT: c_int = 0x200; +pub const IPC_EXCL: c_int = 0x400; +pub const IPC_NOWAIT: c_int = 0x800; +pub const IPC_PRIVATE: key_t = 0; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; + +pub const IPC_R: c_int = 0x100; +pub const IPC_W: c_int = 0x80; +pub const IPC_M: c_int = 0x1000; + +// sys/sem.h +pub const SEM_UNDO: c_int = 0o10000; + +pub const GETNCNT: c_int = 3; +pub const GETPID: c_int = 4; +pub const GETVAL: c_int = 5; +pub const GETALL: c_int = 6; +pub const GETZCNT: c_int = 7; +pub const SETVAL: c_int = 8; +pub const SETALL: c_int = 9; + +// sys/shm.h +pub const SHM_RDONLY: c_int = 0x1000; +pub const SHM_RND: c_int = 0x2000; +#[cfg(target_arch = "aarch64")] +pub const SHMLBA: c_int = 16 * 1024; +#[cfg(not(target_arch = "aarch64"))] +pub const SHMLBA: c_int = 4096; +pub const SHM_R: c_int = IPC_R; +pub const SHM_W: c_int = IPC_W; + +// Flags for chflags(2) +pub const UF_SETTABLE: c_uint = 0x0000ffff; +pub const UF_NODUMP: c_uint = 0x00000001; +pub const UF_IMMUTABLE: c_uint = 0x00000002; +pub const UF_APPEND: c_uint = 0x00000004; +pub const UF_OPAQUE: c_uint = 0x00000008; +pub const UF_COMPRESSED: c_uint = 0x00000020; +pub const UF_TRACKED: c_uint = 0x00000040; +pub const SF_SETTABLE: c_uint = 0x3fff0000; +pub const SF_ARCHIVED: c_uint = 0x00010000; +pub const SF_IMMUTABLE: c_uint = 0x00020000; +pub const SF_APPEND: c_uint = 0x00040000; +pub const UF_HIDDEN: c_uint = 0x00008000; + +// +pub const NTP_API: c_int = 4; +pub const MAXPHASE: c_long = 500000000; +pub const MAXFREQ: c_long = 500000; +pub const MINSEC: c_int = 256; +pub const MAXSEC: c_int = 2048; +pub const NANOSECOND: c_long = 1000000000; +pub const SCALE_PPM: c_int = 65; +pub const MAXTC: c_int = 10; +pub const MOD_OFFSET: c_uint = 0x0001; +pub const MOD_FREQUENCY: c_uint = 0x0002; +pub const MOD_MAXERROR: c_uint = 0x0004; +pub const MOD_ESTERROR: c_uint = 0x0008; +pub const MOD_STATUS: c_uint = 0x0010; +pub const MOD_TIMECONST: c_uint = 0x0020; +pub const MOD_PPSMAX: c_uint = 0x0040; +pub const MOD_TAI: c_uint = 0x0080; +pub const MOD_MICRO: c_uint = 0x1000; +pub const MOD_NANO: c_uint = 0x2000; +pub const MOD_CLKB: c_uint = 0x4000; +pub const MOD_CLKA: c_uint = 0x8000; +pub const STA_PLL: c_int = 0x0001; +pub const STA_PPSFREQ: c_int = 0x0002; +pub const STA_PPSTIME: c_int = 0x0004; +pub const STA_FLL: c_int = 0x0008; +pub const STA_INS: c_int = 0x0010; +pub const STA_DEL: c_int = 0x0020; +pub const STA_UNSYNC: c_int = 0x0040; +pub const STA_FREQHOLD: c_int = 0x0080; +pub const STA_PPSSIGNAL: c_int = 0x0100; +pub const STA_PPSJITTER: c_int = 0x0200; +pub const STA_PPSWANDER: c_int = 0x0400; +pub const STA_PPSERROR: c_int = 0x0800; +pub const STA_CLOCKERR: c_int = 0x1000; +pub const STA_NANO: c_int = 0x2000; +pub const STA_MODE: c_int = 0x4000; +pub const STA_CLK: c_int = 0x8000; +pub const STA_RONLY: c_int = STA_PPSSIGNAL + | STA_PPSJITTER + | STA_PPSWANDER + | STA_PPSERROR + | STA_CLOCKERR + | STA_NANO + | STA_MODE + | STA_CLK; +pub const TIME_OK: c_int = 0; +pub const TIME_INS: c_int = 1; +pub const TIME_DEL: c_int = 2; +pub const TIME_OOP: c_int = 3; +pub const TIME_WAIT: c_int = 4; +pub const TIME_ERROR: c_int = 5; + +// +pub const MNT_WAIT: c_int = 1; +pub const MNT_NOWAIT: c_int = 2; + +// +pub const THREAD_STANDARD_POLICY: c_int = 1; +pub const THREAD_STANDARD_POLICY_COUNT: c_int = 0; +pub const THREAD_EXTENDED_POLICY: c_int = 1; +pub const THREAD_TIME_CONSTRAINT_POLICY: c_int = 2; +pub const THREAD_PRECEDENCE_POLICY: c_int = 3; +pub const THREAD_AFFINITY_POLICY: c_int = 4; +pub const THREAD_AFFINITY_TAG_NULL: c_int = 0; +pub const THREAD_BACKGROUND_POLICY: c_int = 5; +pub const THREAD_BACKGROUND_POLICY_DARWIN_BG: c_int = 0x1000; +pub const THREAD_LATENCY_QOS_POLICY: c_int = 7; +pub const THREAD_THROUGHPUT_QOS_POLICY: c_int = 8; + +// +pub const TH_STATE_RUNNING: c_int = 1; +pub const TH_STATE_STOPPED: c_int = 2; +pub const TH_STATE_WAITING: c_int = 3; +pub const TH_STATE_UNINTERRUPTIBLE: c_int = 4; +pub const TH_STATE_HALTED: c_int = 5; +pub const TH_FLAGS_SWAPPED: c_int = 0x1; +pub const TH_FLAGS_IDLE: c_int = 0x2; +pub const TH_FLAGS_GLOBAL_FORCED_IDLE: c_int = 0x4; +pub const THREAD_BASIC_INFO: c_int = 3; +pub const THREAD_IDENTIFIER_INFO: c_int = 4; +pub const THREAD_EXTENDED_INFO: c_int = 5; + +// CommonCrypto/CommonCryptoError.h +pub const kCCSuccess: i32 = 0; +pub const kCCParamError: i32 = -4300; +pub const kCCBufferTooSmall: i32 = -4301; +pub const kCCMemoryFailure: i32 = -4302; +pub const kCCAlignmentError: i32 = -4303; +pub const kCCDecodeError: i32 = -4304; +pub const kCCUnimplemented: i32 = -4305; +pub const kCCOverflow: i32 = -4306; +pub const kCCRNGFailure: i32 = -4307; +pub const kCCUnspecifiedError: i32 = -4308; +pub const kCCCallSequenceError: i32 = -4309; +pub const kCCKeySizeError: i32 = -4310; +pub const kCCInvalidKey: i32 = -4311; + +// mach/host_info.h +pub const HOST_LOAD_INFO: i32 = 1; +pub const HOST_VM_INFO: i32 = 2; +pub const HOST_CPU_LOAD_INFO: i32 = 3; +pub const HOST_VM_INFO64: i32 = 4; +pub const HOST_EXTMOD_INFO64: i32 = 5; +pub const HOST_EXPIRED_TASK_INFO: i32 = 6; + +// mach/vm_statistics.h +pub const VM_PAGE_QUERY_PAGE_PRESENT: i32 = 0x1; +pub const VM_PAGE_QUERY_PAGE_FICTITIOUS: i32 = 0x2; +pub const VM_PAGE_QUERY_PAGE_REF: i32 = 0x4; +pub const VM_PAGE_QUERY_PAGE_DIRTY: i32 = 0x8; +pub const VM_PAGE_QUERY_PAGE_PAGED_OUT: i32 = 0x10; +pub const VM_PAGE_QUERY_PAGE_COPIED: i32 = 0x20; +pub const VM_PAGE_QUERY_PAGE_SPECULATIVE: i32 = 0x40; +pub const VM_PAGE_QUERY_PAGE_EXTERNAL: i32 = 0x80; +pub const VM_PAGE_QUERY_PAGE_CS_VALIDATED: i32 = 0x100; +pub const VM_PAGE_QUERY_PAGE_CS_TAINTED: i32 = 0x200; +pub const VM_PAGE_QUERY_PAGE_CS_NX: i32 = 0x400; + +// mach/task_info.h +pub const TASK_THREAD_TIMES_INFO: u32 = 3; +pub const HOST_CPU_LOAD_INFO_COUNT: u32 = 4; +pub const MACH_TASK_BASIC_INFO: u32 = 20; + +pub const MACH_PORT_NULL: i32 = 0; + +pub const RUSAGE_INFO_V0: c_int = 0; +pub const RUSAGE_INFO_V1: c_int = 1; +pub const RUSAGE_INFO_V2: c_int = 2; +pub const RUSAGE_INFO_V3: c_int = 3; +pub const RUSAGE_INFO_V4: c_int = 4; + +// copyfile.h +pub const COPYFILE_ACL: crate::copyfile_flags_t = 1 << 0; +pub const COPYFILE_STAT: crate::copyfile_flags_t = 1 << 1; +pub const COPYFILE_XATTR: crate::copyfile_flags_t = 1 << 2; +pub const COPYFILE_DATA: crate::copyfile_flags_t = 1 << 3; +pub const COPYFILE_SECURITY: crate::copyfile_flags_t = COPYFILE_STAT | COPYFILE_ACL; +pub const COPYFILE_METADATA: crate::copyfile_flags_t = COPYFILE_SECURITY | COPYFILE_XATTR; +pub const COPYFILE_RECURSIVE: crate::copyfile_flags_t = 1 << 15; +pub const COPYFILE_CHECK: crate::copyfile_flags_t = 1 << 16; +pub const COPYFILE_EXCL: crate::copyfile_flags_t = 1 << 17; +pub const COPYFILE_NOFOLLOW_SRC: crate::copyfile_flags_t = 1 << 18; +pub const COPYFILE_NOFOLLOW_DST: crate::copyfile_flags_t = 1 << 19; +pub const COPYFILE_MOVE: crate::copyfile_flags_t = 1 << 20; +pub const COPYFILE_UNLINK: crate::copyfile_flags_t = 1 << 21; +pub const COPYFILE_NOFOLLOW: crate::copyfile_flags_t = + COPYFILE_NOFOLLOW_SRC | COPYFILE_NOFOLLOW_DST; +pub const COPYFILE_PACK: crate::copyfile_flags_t = 1 << 22; +pub const COPYFILE_UNPACK: crate::copyfile_flags_t = 1 << 23; +pub const COPYFILE_CLONE: crate::copyfile_flags_t = 1 << 24; +pub const COPYFILE_CLONE_FORCE: crate::copyfile_flags_t = 1 << 25; +pub const COPYFILE_RUN_IN_PLACE: crate::copyfile_flags_t = 1 << 26; +pub const COPYFILE_DATA_SPARSE: crate::copyfile_flags_t = 1 << 27; +pub const COPYFILE_PRESERVE_DST_TRACKED: crate::copyfile_flags_t = 1 << 28; +pub const COPYFILE_VERBOSE: crate::copyfile_flags_t = 1 << 30; +pub const COPYFILE_RECURSE_ERROR: c_int = 0; +pub const COPYFILE_RECURSE_FILE: c_int = 1; +pub const COPYFILE_RECURSE_DIR: c_int = 2; +pub const COPYFILE_RECURSE_DIR_CLEANUP: c_int = 3; +pub const COPYFILE_COPY_DATA: c_int = 4; +pub const COPYFILE_COPY_XATTR: c_int = 5; +pub const COPYFILE_START: c_int = 1; +pub const COPYFILE_FINISH: c_int = 2; +pub const COPYFILE_ERR: c_int = 3; +pub const COPYFILE_PROGRESS: c_int = 4; +pub const COPYFILE_CONTINUE: c_int = 0; +pub const COPYFILE_SKIP: c_int = 1; +pub const COPYFILE_QUIT: c_int = 2; +pub const COPYFILE_STATE_SRC_FD: c_int = 1; +pub const COPYFILE_STATE_SRC_FILENAME: c_int = 2; +pub const COPYFILE_STATE_DST_FD: c_int = 3; +pub const COPYFILE_STATE_DST_FILENAME: c_int = 4; +pub const COPYFILE_STATE_QUARANTINE: c_int = 5; +pub const COPYFILE_STATE_STATUS_CB: c_int = 6; +pub const COPYFILE_STATE_STATUS_CTX: c_int = 7; +pub const COPYFILE_STATE_COPIED: c_int = 8; +pub const COPYFILE_STATE_XATTRNAME: c_int = 9; +pub const COPYFILE_STATE_WAS_CLONED: c_int = 10; +pub const COPYFILE_STATE_SRC_BSIZE: c_int = 11; +pub const COPYFILE_STATE_DST_BSIZE: c_int = 12; +pub const COPYFILE_STATE_BSIZE: c_int = 13; + +// +pub const ATTR_BIT_MAP_COUNT: c_ushort = 5; +pub const FSOPT_NOFOLLOW: u32 = 0x1; +pub const FSOPT_NOFOLLOW_ANY: u32 = 0x800; +pub const FSOPT_REPORT_FULLSIZE: u32 = 0x4; +pub const FSOPT_PACK_INVAL_ATTRS: u32 = 0x8; +pub const FSOPT_ATTR_CMN_EXTENDED: u32 = 0x20; +pub const FSOPT_RETURN_REALDEV: u32 = 0x200; +pub const ATTR_CMN_NAME: attrgroup_t = 0x00000001; +pub const ATTR_CMN_DEVID: attrgroup_t = 0x00000002; +pub const ATTR_CMN_FSID: attrgroup_t = 0x00000004; +pub const ATTR_CMN_OBJTYPE: attrgroup_t = 0x00000008; +pub const ATTR_CMN_OBJTAG: attrgroup_t = 0x00000010; +pub const ATTR_CMN_OBJID: attrgroup_t = 0x00000020; +pub const ATTR_CMN_OBJPERMANENTID: attrgroup_t = 0x00000040; +pub const ATTR_CMN_PAROBJID: attrgroup_t = 0x00000080; +pub const ATTR_CMN_SCRIPT: attrgroup_t = 0x00000100; +pub const ATTR_CMN_CRTIME: attrgroup_t = 0x00000200; +pub const ATTR_CMN_MODTIME: attrgroup_t = 0x00000400; +pub const ATTR_CMN_CHGTIME: attrgroup_t = 0x00000800; +pub const ATTR_CMN_ACCTIME: attrgroup_t = 0x00001000; +pub const ATTR_CMN_BKUPTIME: attrgroup_t = 0x00002000; +pub const ATTR_CMN_FNDRINFO: attrgroup_t = 0x00004000; +pub const ATTR_CMN_OWNERID: attrgroup_t = 0x00008000; +pub const ATTR_CMN_GRPID: attrgroup_t = 0x00010000; +pub const ATTR_CMN_ACCESSMASK: attrgroup_t = 0x00020000; +pub const ATTR_CMN_FLAGS: attrgroup_t = 0x00040000; +pub const ATTR_CMN_GEN_COUNT: attrgroup_t = 0x00080000; +pub const ATTR_CMN_DOCUMENT_ID: attrgroup_t = 0x00100000; +pub const ATTR_CMN_USERACCESS: attrgroup_t = 0x00200000; +pub const ATTR_CMN_EXTENDED_SECURITY: attrgroup_t = 0x00400000; +pub const ATTR_CMN_UUID: attrgroup_t = 0x00800000; +pub const ATTR_CMN_GRPUUID: attrgroup_t = 0x01000000; +pub const ATTR_CMN_FILEID: attrgroup_t = 0x02000000; +pub const ATTR_CMN_PARENTID: attrgroup_t = 0x04000000; +pub const ATTR_CMN_FULLPATH: attrgroup_t = 0x08000000; +pub const ATTR_CMN_ADDEDTIME: attrgroup_t = 0x10000000; +pub const ATTR_CMN_DATA_PROTECT_FLAGS: attrgroup_t = 0x40000000; +pub const ATTR_CMN_RETURNED_ATTRS: attrgroup_t = 0x80000000; +pub const ATTR_VOL_FSTYPE: attrgroup_t = 0x00000001; +pub const ATTR_VOL_SIGNATURE: attrgroup_t = 0x00000002; +pub const ATTR_VOL_SIZE: attrgroup_t = 0x00000004; +pub const ATTR_VOL_SPACEFREE: attrgroup_t = 0x00000008; +pub const ATTR_VOL_SPACEAVAIL: attrgroup_t = 0x00000010; +pub const ATTR_VOL_MINALLOCATION: attrgroup_t = 0x00000020; +pub const ATTR_VOL_ALLOCATIONCLUMP: attrgroup_t = 0x00000040; +pub const ATTR_VOL_IOBLOCKSIZE: attrgroup_t = 0x00000080; +pub const ATTR_VOL_OBJCOUNT: attrgroup_t = 0x00000100; +pub const ATTR_VOL_FILECOUNT: attrgroup_t = 0x00000200; +pub const ATTR_VOL_DIRCOUNT: attrgroup_t = 0x00000400; +pub const ATTR_VOL_MAXOBJCOUNT: attrgroup_t = 0x00000800; +pub const ATTR_VOL_MOUNTPOINT: attrgroup_t = 0x00001000; +pub const ATTR_VOL_NAME: attrgroup_t = 0x00002000; +pub const ATTR_VOL_MOUNTFLAGS: attrgroup_t = 0x00004000; +pub const ATTR_VOL_MOUNTEDDEVICE: attrgroup_t = 0x00008000; +pub const ATTR_VOL_ENCODINGSUSED: attrgroup_t = 0x00010000; +pub const ATTR_VOL_CAPABILITIES: attrgroup_t = 0x00020000; +pub const ATTR_VOL_UUID: attrgroup_t = 0x00040000; +pub const ATTR_VOL_SPACEUSED: attrgroup_t = 0x00800000; +pub const ATTR_VOL_QUOTA_SIZE: attrgroup_t = 0x10000000; +pub const ATTR_VOL_RESERVED_SIZE: attrgroup_t = 0x20000000; +pub const ATTR_VOL_ATTRIBUTES: attrgroup_t = 0x40000000; +pub const ATTR_VOL_INFO: attrgroup_t = 0x80000000; +pub const ATTR_DIR_LINKCOUNT: attrgroup_t = 0x00000001; +pub const ATTR_DIR_ENTRYCOUNT: attrgroup_t = 0x00000002; +pub const ATTR_DIR_MOUNTSTATUS: attrgroup_t = 0x00000004; +pub const ATTR_DIR_ALLOCSIZE: attrgroup_t = 0x00000008; +pub const ATTR_DIR_IOBLOCKSIZE: attrgroup_t = 0x00000010; +pub const ATTR_DIR_DATALENGTH: attrgroup_t = 0x00000020; +pub const ATTR_FILE_LINKCOUNT: attrgroup_t = 0x00000001; +pub const ATTR_FILE_TOTALSIZE: attrgroup_t = 0x00000002; +pub const ATTR_FILE_ALLOCSIZE: attrgroup_t = 0x00000004; +pub const ATTR_FILE_IOBLOCKSIZE: attrgroup_t = 0x00000008; +pub const ATTR_FILE_DEVTYPE: attrgroup_t = 0x00000020; +pub const ATTR_FILE_FORKCOUNT: attrgroup_t = 0x00000080; +pub const ATTR_FILE_FORKLIST: attrgroup_t = 0x00000100; +pub const ATTR_FILE_DATALENGTH: attrgroup_t = 0x00000200; +pub const ATTR_FILE_DATAALLOCSIZE: attrgroup_t = 0x00000400; +pub const ATTR_FILE_RSRCLENGTH: attrgroup_t = 0x00001000; +pub const ATTR_FILE_RSRCALLOCSIZE: attrgroup_t = 0x00002000; +pub const ATTR_CMNEXT_RELPATH: attrgroup_t = 0x00000004; +pub const ATTR_CMNEXT_PRIVATESIZE: attrgroup_t = 0x00000008; +pub const ATTR_CMNEXT_LINKID: attrgroup_t = 0x00000010; +pub const ATTR_CMNEXT_NOFIRMLINKPATH: attrgroup_t = 0x00000020; +pub const ATTR_CMNEXT_REALDEVID: attrgroup_t = 0x00000040; +pub const ATTR_CMNEXT_REALFSID: attrgroup_t = 0x00000080; +pub const ATTR_CMNEXT_CLONEID: attrgroup_t = 0x00000100; +pub const ATTR_CMNEXT_EXT_FLAGS: attrgroup_t = 0x00000200; +pub const ATTR_CMNEXT_RECURSIVE_GENCOUNT: attrgroup_t = 0x00000400; +pub const DIR_MNTSTATUS_MNTPOINT: u32 = 0x1; +pub const VOL_CAPABILITIES_FORMAT: usize = 0; +pub const VOL_CAPABILITIES_INTERFACES: usize = 1; +pub const VOL_CAP_FMT_PERSISTENTOBJECTIDS: attrgroup_t = 0x00000001; +pub const VOL_CAP_FMT_SYMBOLICLINKS: attrgroup_t = 0x00000002; +pub const VOL_CAP_FMT_HARDLINKS: attrgroup_t = 0x00000004; +pub const VOL_CAP_FMT_JOURNAL: attrgroup_t = 0x00000008; +pub const VOL_CAP_FMT_JOURNAL_ACTIVE: attrgroup_t = 0x00000010; +pub const VOL_CAP_FMT_NO_ROOT_TIMES: attrgroup_t = 0x00000020; +pub const VOL_CAP_FMT_SPARSE_FILES: attrgroup_t = 0x00000040; +pub const VOL_CAP_FMT_ZERO_RUNS: attrgroup_t = 0x00000080; +pub const VOL_CAP_FMT_CASE_SENSITIVE: attrgroup_t = 0x00000100; +pub const VOL_CAP_FMT_CASE_PRESERVING: attrgroup_t = 0x00000200; +pub const VOL_CAP_FMT_FAST_STATFS: attrgroup_t = 0x00000400; +pub const VOL_CAP_FMT_2TB_FILESIZE: attrgroup_t = 0x00000800; +pub const VOL_CAP_FMT_OPENDENYMODES: attrgroup_t = 0x00001000; +pub const VOL_CAP_FMT_HIDDEN_FILES: attrgroup_t = 0x00002000; +pub const VOL_CAP_FMT_PATH_FROM_ID: attrgroup_t = 0x00004000; +pub const VOL_CAP_FMT_NO_VOLUME_SIZES: attrgroup_t = 0x00008000; +pub const VOL_CAP_FMT_DECMPFS_COMPRESSION: attrgroup_t = 0x00010000; +pub const VOL_CAP_FMT_64BIT_OBJECT_IDS: attrgroup_t = 0x00020000; +pub const VOL_CAP_FMT_DIR_HARDLINKS: attrgroup_t = 0x00040000; +pub const VOL_CAP_FMT_DOCUMENT_ID: attrgroup_t = 0x00080000; +pub const VOL_CAP_FMT_WRITE_GENERATION_COUNT: attrgroup_t = 0x00100000; +pub const VOL_CAP_FMT_NO_IMMUTABLE_FILES: attrgroup_t = 0x00200000; +pub const VOL_CAP_FMT_NO_PERMISSIONS: attrgroup_t = 0x00400000; +pub const VOL_CAP_FMT_SHARED_SPACE: attrgroup_t = 0x00800000; +pub const VOL_CAP_FMT_VOL_GROUPS: attrgroup_t = 0x01000000; +pub const VOL_CAP_FMT_SEALED: attrgroup_t = 0x02000000; +pub const VOL_CAP_INT_SEARCHFS: attrgroup_t = 0x00000001; +pub const VOL_CAP_INT_ATTRLIST: attrgroup_t = 0x00000002; +pub const VOL_CAP_INT_NFSEXPORT: attrgroup_t = 0x00000004; +pub const VOL_CAP_INT_READDIRATTR: attrgroup_t = 0x00000008; +pub const VOL_CAP_INT_EXCHANGEDATA: attrgroup_t = 0x00000010; +pub const VOL_CAP_INT_COPYFILE: attrgroup_t = 0x00000020; +pub const VOL_CAP_INT_ALLOCATE: attrgroup_t = 0x00000040; +pub const VOL_CAP_INT_VOL_RENAME: attrgroup_t = 0x00000080; +pub const VOL_CAP_INT_ADVLOCK: attrgroup_t = 0x00000100; +pub const VOL_CAP_INT_FLOCK: attrgroup_t = 0x00000200; +pub const VOL_CAP_INT_EXTENDED_SECURITY: attrgroup_t = 0x00000400; +pub const VOL_CAP_INT_USERACCESS: attrgroup_t = 0x00000800; +pub const VOL_CAP_INT_MANLOCK: attrgroup_t = 0x00001000; +pub const VOL_CAP_INT_NAMEDSTREAMS: attrgroup_t = 0x00002000; +pub const VOL_CAP_INT_EXTENDED_ATTR: attrgroup_t = 0x00004000; +pub const VOL_CAP_INT_CLONE: attrgroup_t = 0x00010000; +pub const VOL_CAP_INT_SNAPSHOT: attrgroup_t = 0x00020000; +pub const VOL_CAP_INT_RENAME_SWAP: attrgroup_t = 0x00040000; +pub const VOL_CAP_INT_RENAME_EXCL: attrgroup_t = 0x00080000; +pub const VOL_CAP_INT_RENAME_OPENFAIL: attrgroup_t = 0x00100000; + +// os/clock.h +pub const OS_CLOCK_MACH_ABSOLUTE_TIME: os_clockid_t = 32; + +// os/os_sync_wait_on_address.h +pub const OS_SYNC_WAIT_ON_ADDRESS_NONE: os_sync_wait_on_address_flags_t = 0x00000000; +pub const OS_SYNC_WAIT_ON_ADDRESS_SHARED: os_sync_wait_on_address_flags_t = 0x00000001; +pub const OS_SYNC_WAKE_BY_ADDRESS_NONE: os_sync_wake_by_address_flags_t = 0x00000000; +pub const OS_SYNC_WAKE_BY_ADDRESS_SHARED: os_sync_wake_by_address_flags_t = 0x00000001; + +// +/// Process being created by fork. +pub const SIDL: u32 = 1; +/// Currently runnable. +pub const SRUN: u32 = 2; +/// Sleeping on an address. +pub const SSLEEP: u32 = 3; +/// Process debugging or suspension. +pub const SSTOP: u32 = 4; +/// Awaiting collection by parent. +pub const SZOMB: u32 = 5; + +// sys/vsock.h +pub const VMADDR_CID_ANY: c_uint = 0xFFFFFFFF; +pub const VMADDR_CID_HYPERVISOR: c_uint = 0; +pub const VMADDR_CID_RESERVED: c_uint = 1; +pub const VMADDR_CID_HOST: c_uint = 2; +pub const VMADDR_PORT_ANY: c_uint = 0xFFFFFFFF; + +const fn __DARWIN_ALIGN32(p: usize) -> usize { + const __DARWIN_ALIGNBYTES32: usize = size_of::() - 1; + (p + __DARWIN_ALIGNBYTES32) & !__DARWIN_ALIGNBYTES32 +} + +pub const THREAD_EXTENDED_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; +pub const THREAD_TIME_CONSTRAINT_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) + as mach_msg_type_number_t; +pub const THREAD_PRECEDENCE_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) + as mach_msg_type_number_t; +pub const THREAD_AFFINITY_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; +pub const THREAD_BACKGROUND_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) + as mach_msg_type_number_t; +pub const THREAD_LATENCY_QOS_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) + as mach_msg_type_number_t; +pub const THREAD_THROUGHPUT_QOS_POLICY_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) + as mach_msg_type_number_t; +pub const THREAD_BASIC_INFO_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; +pub const THREAD_IDENTIFIER_INFO_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; +pub const THREAD_EXTENDED_INFO_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; + +pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = + (size_of::() / size_of::()) as u32; +pub const MACH_TASK_BASIC_INFO_COUNT: u32 = + (size_of::() / size_of::()) as u32; +pub const HOST_VM_INFO64_COUNT: mach_msg_type_number_t = + (size_of::() / size_of::()) as mach_msg_type_number_t; + +// bsd/net/if_mib.h +/// Non-interface-specific +pub const IFMIB_SYSTEM: c_int = 1; +/// Per-interface data table +pub const IFMIB_IFDATA: c_int = 2; +/// All interfaces data at once +pub const IFMIB_IFALLDATA: c_int = 3; + +/// Generic stats for all kinds of ifaces +pub const IFDATA_GENERAL: c_int = 1; +/// Specific to the type of interface +pub const IFDATA_LINKSPECIFIC: c_int = 2; +/// Addresses assigned to interface +pub const IFDATA_ADDRS: c_int = 3; +/// Multicast addresses assigned to interface +pub const IFDATA_MULTIADDRS: c_int = 4; + +/// Number of interfaces configured +pub const IFMIB_IFCOUNT: c_int = 1; + +/// Functions not specific to a type of iface +pub const NETLINK_GENERIC: c_int = 0; + +pub const DOT3COMPLIANCE_STATS: c_int = 1; +pub const DOT3COMPLIANCE_COLLS: c_int = 2; + +// kern_control.h +pub const MAX_KCTL_NAME: usize = 96; + +f! { + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let cmsg_len = (*cmsg).cmsg_len as usize; + let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next + __DARWIN_ALIGN32(size_of::()) > max { + core::ptr::null_mut() + } else { + next as *mut cmsghdr + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).add(__DARWIN_ALIGN32(size_of::())) + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (__DARWIN_ALIGN32(size_of::()) + __DARWIN_ALIGN32(length as usize)) as c_uint + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + (__DARWIN_ALIGN32(size_of::()) + length as usize) as c_uint + } + + pub const fn VM_MAKE_TAG(id: u8) -> u32 { + (id as u32) << 24u32 + } +} + +safe_f! { + pub const fn WSTOPSIG(status: c_int) -> c_int { + status >> 8 + } + + pub const fn _WSTATUS(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + _WSTATUS(status) == _WSTOPPED && WSTOPSIG(status) == 0x13 + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + _WSTATUS(status) != _WSTOPPED && _WSTATUS(status) != 0 + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + _WSTATUS(status) == _WSTOPPED && WSTOPSIG(status) != 0x13 + } + + pub const fn makedev(major: i32, minor: i32) -> dev_t { + (major << 24) | minor + } + + pub const fn major(dev: dev_t) -> i32 { + (dev >> 24) & 0xff + } + + pub const fn minor(dev: dev_t) -> i32 { + dev & 0xffffff + } +} + +extern "C" { + pub fn setgrent(); + #[doc(hidden)] + #[deprecated(since = "0.2.49", note = "Deprecated in MacOSX 10.5")] + #[cfg_attr(not(target_arch = "aarch64"), link_name = "daemon$1050")] + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + #[doc(hidden)] + #[deprecated(since = "0.2.49", note = "Deprecated in MacOSX 10.10")] + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + #[doc(hidden)] + #[deprecated(since = "0.2.49", note = "Deprecated in MacOSX 10.10")] + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "aio_suspend$UNIX2003" + )] + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn chflags(path: *const c_char, flags: c_uint) -> c_int; + pub fn fchflags(fd: c_int, flags: c_uint) -> c_int; + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut sigevent, + ) -> c_int; + + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + pub fn utmpxname(file: *const c_char) -> c_int; + + pub fn asctime(tm: *const crate::tm) -> *mut c_char; + pub fn ctime(clock: *const time_t) -> *mut c_char; + pub fn getdate(datestr: *const c_char) -> *mut crate::tm; + pub fn strptime( + buf: *const c_char, + format: *const c_char, + timeptr: *mut crate::tm, + ) -> *mut c_char; + pub fn asctime_r(tm: *const crate::tm, result: *mut c_char) -> *mut c_char; + pub fn ctime_r(clock: *const time_t, result: *mut c_char) -> *mut c_char; + + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn mincore(addr: *const c_void, len: size_t, vec: *mut c_char) -> c_int; + pub fn sysctlnametomib(name: *const c_char, mibp: *mut c_int, sizep: *mut size_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "mprotect$UNIX2003" + )] + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn semget(key: key_t, nsems: c_int, semflg: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "semctl$UNIX2003" + )] + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + pub fn semop(semid: c_int, sops: *mut sembuf, nsops: size_t) -> c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, ...) -> c_int; + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> key_t; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "shmctl$UNIX2003" + )] + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + pub fn shmget(key: key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn sysctl( + name: *mut c_int, + namelen: c_uint, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn sysctlbyname( + name: *const c_char, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn mach_absolute_time() -> u64; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + #[allow(deprecated)] + pub fn mach_timebase_info(info: *mut crate::mach_timebase_info) -> c_int; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn mach_host_self() -> mach_port_t; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn mach_thread_self() -> mach_port_t; + pub fn pthread_cond_timedwait_relative_np( + cond: *mut crate::pthread_cond_t, + lock: *mut crate::pthread_mutex_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn pthread_attr_getscope( + attr: *const crate::pthread_attr_t, + contentionscope: *mut c_int, + ) -> c_int; + pub fn pthread_attr_getstackaddr( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + ) -> c_int; + pub fn pthread_attr_getdetachstate( + attr: *const crate::pthread_attr_t, + detachstate: *mut c_int, + ) -> c_int; + pub fn pthread_attr_setscope(attr: *mut crate::pthread_attr_t, contentionscope: c_int) + -> c_int; + pub fn pthread_attr_setstackaddr( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + ) -> c_int; + pub fn pthread_setname_np(name: *const c_char) -> c_int; + pub fn pthread_getname_np(thread: crate::pthread_t, name: *mut c_char, len: size_t) -> c_int; + pub fn pthread_mach_thread_np(thread: crate::pthread_t) -> crate::mach_port_t; + pub fn pthread_from_mach_thread_np(port: crate::mach_port_t) -> crate::pthread_t; + pub fn pthread_get_stackaddr_np(thread: crate::pthread_t) -> *mut c_void; + pub fn pthread_get_stacksize_np(thread: crate::pthread_t) -> size_t; + pub fn pthread_main_np() -> c_int; + pub fn pthread_threadid_np(thread: crate::pthread_t, thread_id: *mut u64) -> c_int; + + pub fn pthread_jit_write_protect_np(enabled: c_int); + pub fn pthread_jit_write_protect_supported_np() -> c_int; + // An array of pthread_jit_write_with_callback_np must declare + // the list of callbacks e.g. + // #[link_section = "__DATA_CONST,__pth_jit_func"] + // static callbacks: [libc::pthread_jit_write_callback_t; 2] = [native_jit_write_cb, + // std::mem::transmute::(std::ptr::null())]; + // (a handy PTHREAD_JIT_WRITE_CALLBACK_NP macro for other languages). + pub fn pthread_jit_write_with_callback_np( + callback: crate::pthread_jit_write_callback_t, + ctx: *mut c_void, + ) -> c_int; + pub fn pthread_jit_write_freeze_callbacks_np(); + pub fn pthread_cpu_number_np(cpu_number_out: *mut size_t) -> c_int; + + // Available starting with macOS 14.4. + pub fn os_sync_wait_on_address( + addr: *mut c_void, + value: u64, + size: size_t, + flags: os_sync_wait_on_address_flags_t, + ) -> c_int; + pub fn os_sync_wait_on_address_with_deadline( + addr: *mut c_void, + value: u64, + size: size_t, + flags: os_sync_wait_on_address_flags_t, + clockid: os_clockid_t, + deadline: u64, + ) -> c_int; + pub fn os_sync_wait_on_address_with_timeout( + addr: *mut c_void, + value: u64, + size: size_t, + flags: os_sync_wait_on_address_flags_t, + clockid: os_clockid_t, + timeout_ns: u64, + ) -> c_int; + pub fn os_sync_wake_by_address_any( + addr: *mut c_void, + size: size_t, + flags: os_sync_wake_by_address_flags_t, + ) -> c_int; + pub fn os_sync_wake_by_address_all( + addr: *mut c_void, + size: size_t, + flags: os_sync_wake_by_address_flags_t, + ) -> c_int; + + pub fn os_unfair_lock_lock(lock: os_unfair_lock_t); + pub fn os_unfair_lock_trylock(lock: os_unfair_lock_t) -> bool; + pub fn os_unfair_lock_unlock(lock: os_unfair_lock_t); + pub fn os_unfair_lock_assert_owner(lock: os_unfair_lock_t); + pub fn os_unfair_lock_assert_not_owner(lock: os_unfair_lock_t); + + pub fn os_log_create(subsystem: *const c_char, category: *const c_char) -> crate::os_log_t; + pub fn os_log_type_enabled(oslog: crate::os_log_t, tpe: crate::os_log_type_t) -> bool; + pub fn os_signpost_id_make_with_pointer( + log: crate::os_log_t, + ptr: *const c_void, + ) -> crate::os_signpost_id_t; + pub fn os_signpost_id_generate(log: crate::os_log_t) -> crate::os_signpost_id_t; + pub fn os_signpost_enabled(log: crate::os_log_t) -> bool; + + pub fn thread_policy_set( + thread: thread_t, + flavor: thread_policy_flavor_t, + policy_info: thread_policy_t, + count: mach_msg_type_number_t, + ) -> kern_return_t; + pub fn thread_policy_get( + thread: thread_t, + flavor: thread_policy_flavor_t, + policy_info: thread_policy_t, + count: *mut mach_msg_type_number_t, + get_default: *mut boolean_t, + ) -> kern_return_t; + pub fn thread_info( + target_act: thread_inspect_t, + flavor: thread_flavor_t, + thread_info_out: thread_info_t, + thread_info_outCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + #[cfg_attr(doc, doc(alias = "__errno_location"))] + #[cfg_attr(doc, doc(alias = "errno"))] + pub fn __error() -> *mut c_int; + pub fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int; + pub fn backtrace_symbols(addrs: *const *mut c_void, sz: c_int) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(addrs: *const *mut c_void, sz: c_int, fd: c_int); + pub fn backtrace_from_fp(startfp: *mut c_void, array: *mut *mut c_void, size: c_int) -> c_int; + pub fn backtrace_image_offsets( + array: *const *mut c_void, + image_offsets: *mut image_offset, + size: c_int, + ); + pub fn backtrace_async(array: *mut *mut c_void, length: size_t, task_id: *mut u32) -> size_t; + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "statfs$INODE64" + )] + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "fstatfs$INODE64" + )] + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn kevent( + kq: c_int, + changelist: *const crate::kevent, + nchanges: c_int, + eventlist: *mut crate::kevent, + nevents: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn kevent64( + kq: c_int, + changelist: *const crate::kevent64_s, + nchanges: c_int, + eventlist: *mut crate::kevent64_s, + nevents: c_int, + flags: c_uint, + timeout: *const crate::timespec, + ) -> c_int; + pub fn mount( + src: *const c_char, + target: *const c_char, + flags: c_int, + data: *mut c_void, + ) -> c_int; + pub fn fmount(src: *const c_char, fd: c_int, flags: c_int, data: *mut c_void) -> c_int; + pub fn ptrace(request: c_int, pid: crate::pid_t, addr: *mut c_char, data: c_int) -> c_int; + pub fn quotactl(special: *const c_char, cmd: c_int, id: c_int, data: *mut c_char) -> c_int; + pub fn sethostname(name: *const c_char, len: c_int) -> c_int; + pub fn sendfile( + fd: c_int, + s: c_int, + offset: off_t, + len: *mut off_t, + hdtr: *mut crate::sf_hdtr, + flags: c_int, + ) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + pub fn login_tty(fd: c_int) -> c_int; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t) -> c_int; + pub fn localeconv_l(loc: crate::locale_t) -> *mut lconv; + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn querylocale(mask: c_int, loc: crate::locale_t) -> *const c_char; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + pub fn getdomainname(name: *mut c_char, len: c_int) -> c_int; + pub fn setdomainname(name: *const c_char, len: c_int) -> c_int; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn getxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + position: u32, + flags: c_int, + ) -> ssize_t; + pub fn fgetxattr( + filedes: c_int, + name: *const c_char, + value: *mut c_void, + size: size_t, + position: u32, + flags: c_int, + ) -> ssize_t; + pub fn setxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + position: u32, + flags: c_int, + ) -> c_int; + pub fn fsetxattr( + filedes: c_int, + name: *const c_char, + value: *const c_void, + size: size_t, + position: u32, + flags: c_int, + ) -> c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, size: size_t, flags: c_int) + -> ssize_t; + pub fn flistxattr(filedes: c_int, list: *mut c_char, size: size_t, flags: c_int) -> ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char, flags: c_int) -> c_int; + pub fn renamex_np(from: *const c_char, to: *const c_char, flags: c_uint) -> c_int; + pub fn renameatx_np( + fromfd: c_int, + from: *const c_char, + tofd: c_int, + to: *const c_char, + flags: c_uint, + ) -> c_int; + pub fn fremovexattr(filedes: c_int, name: *const c_char, flags: c_int) -> c_int; + + pub fn getgrouplist( + name: *const c_char, + basegid: c_int, + groups: *mut c_int, + ngroups: *mut c_int, + ) -> c_int; + pub fn initgroups(user: *const c_char, basegroup: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "waitid$UNIX2003" + )] + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + pub fn brk(addr: *const c_void) -> *mut c_void; + pub fn sbrk(increment: c_int) -> *mut c_void; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn _dyld_image_count() -> u32; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + #[allow(deprecated)] + pub fn _dyld_get_image_header(image_index: u32) -> *const mach_header; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn _dyld_get_image_vmaddr_slide(image_index: u32) -> intptr_t; + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn _dyld_get_image_name(image_index: u32) -> *const c_char; + + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_setarchpref_np( + attr: *mut posix_spawnattr_t, + count: size_t, + pref: *mut crate::cpu_type_t, + subpref: *mut crate::cpu_subtype_t, + ocount: *mut size_t, + ) -> c_int; + pub fn posix_spawnattr_getarchpref_np( + attr: *const posix_spawnattr_t, + count: size_t, + pref: *mut crate::cpu_type_t, + subpref: *mut crate::cpu_subtype_t, + ocount: *mut size_t, + ) -> c_int; + pub fn posix_spawnattr_getbinpref_np( + attr: *const posix_spawnattr_t, + count: size_t, + pref: *mut crate::cpu_type_t, + ocount: *mut size_t, + ) -> c_int; + pub fn posix_spawnattr_setbinpref_np( + attr: *mut posix_spawnattr_t, + count: size_t, + pref: *mut crate::cpu_type_t, + ocount: *mut size_t, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + + pub fn connectx( + socket: c_int, + endpoints: *const sa_endpoints_t, + associd: sae_associd_t, + flags: c_uint, + iov: *const crate::iovec, + iovcnt: c_uint, + len: *mut size_t, + connid: *mut sae_connid_t, + ) -> c_int; + pub fn disconnectx(socket: c_int, associd: sae_associd_t, connid: sae_connid_t) -> c_int; + + pub fn ntp_adjtime(buf: *mut timex) -> c_int; + pub fn ntp_gettime(buf: *mut ntptimeval) -> c_int; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "getmntinfo$INODE64" + )] + pub fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "getfsstat$INODE64" + )] + pub fn getfsstat(mntbufp: *mut statfs, bufsize: c_int, flags: c_int) -> c_int; + + // Copy-on-write functions. + // According to the man page `flags` is an `int` but in the header + // this is a `uint32_t`. + pub fn clonefile(src: *const c_char, dst: *const c_char, flags: u32) -> c_int; + pub fn clonefileat( + src_dirfd: c_int, + src: *const c_char, + dst_dirfd: c_int, + dst: *const c_char, + flags: u32, + ) -> c_int; + pub fn fclonefileat(srcfd: c_int, dst_dirfd: c_int, dst: *const c_char, flags: u32) -> c_int; + + pub fn copyfile( + from: *const c_char, + to: *const c_char, + state: copyfile_state_t, + flags: copyfile_flags_t, + ) -> c_int; + pub fn fcopyfile( + from: c_int, + to: c_int, + state: copyfile_state_t, + flags: copyfile_flags_t, + ) -> c_int; + pub fn copyfile_state_free(s: copyfile_state_t) -> c_int; + pub fn copyfile_state_alloc() -> copyfile_state_t; + pub fn copyfile_state_get(s: copyfile_state_t, flags: u32, dst: *mut c_void) -> c_int; + pub fn copyfile_state_set(s: copyfile_state_t, flags: u32, src: *const c_void) -> c_int; + + pub fn mach_error_string(error_value: crate::mach_error_t) -> *mut c_char; + + // Added in macOS 10.13 + // ISO/IEC 9899:2011 ("ISO C11") K.3.7.4.1 + pub fn memset_s(s: *mut c_void, smax: size_t, c: c_int, n: size_t) -> c_int; + // Added in macOS 10.5 + pub fn memset_pattern4(b: *mut c_void, pattern4: *const c_void, len: size_t); + pub fn memset_pattern8(b: *mut c_void, pattern8: *const c_void, len: size_t); + pub fn memset_pattern16(b: *mut c_void, pattern16: *const c_void, len: size_t); + + // Inherited from BSD but available from Big Sur only + pub fn strtonum( + __numstr: *const c_char, + __minval: c_longlong, + __maxval: c_longlong, + errstrp: *mut *const c_char, + ) -> c_longlong; + + pub fn mstats() -> mstats; + pub fn malloc_printf(format: *const c_char, ...); + pub fn malloc_zone_check(zone: *mut crate::malloc_zone_t) -> crate::boolean_t; + pub fn malloc_zone_print(zone: *mut crate::malloc_zone_t, verbose: crate::boolean_t); + pub fn malloc_zone_statistics(zone: *mut crate::malloc_zone_t, stats: *mut malloc_statistics_t); + pub fn malloc_zone_log(zone: *mut crate::malloc_zone_t, address: *mut c_void); + pub fn malloc_zone_print_ptr_info(ptr: *mut c_void); + pub fn malloc_default_zone() -> *mut crate::malloc_zone_t; + pub fn malloc_zone_from_ptr(ptr: *const c_void) -> *mut crate::malloc_zone_t; + pub fn malloc_zone_malloc(zone: *mut crate::malloc_zone_t, size: size_t) -> *mut c_void; + pub fn malloc_zone_valloc(zone: *mut crate::malloc_zone_t, size: size_t) -> *mut c_void; + pub fn malloc_zone_calloc( + zone: *mut crate::malloc_zone_t, + num_items: size_t, + size: size_t, + ) -> *mut c_void; + pub fn malloc_zone_realloc( + zone: *mut crate::malloc_zone_t, + ptr: *mut c_void, + size: size_t, + ) -> *mut c_void; + pub fn malloc_zone_free(zone: *mut crate::malloc_zone_t, ptr: *mut c_void); + + pub fn proc_listpids(t: u32, typeinfo: u32, buffer: *mut c_void, buffersize: c_int) -> c_int; + pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int; + pub fn proc_listpgrppids(pgrpid: crate::pid_t, buffer: *mut c_void, buffersize: c_int) + -> c_int; + pub fn proc_listchildpids(ppid: crate::pid_t, buffer: *mut c_void, buffersize: c_int) -> c_int; + pub fn proc_pidinfo( + pid: c_int, + flavor: c_int, + arg: u64, + buffer: *mut c_void, + buffersize: c_int, + ) -> c_int; + pub fn proc_pidfdinfo( + pid: c_int, + fd: c_int, + flavor: c_int, + buffer: *mut c_void, + buffersize: c_int, + ) -> c_int; + pub fn proc_pidfileportinfo( + pid: c_int, + fileport: u32, + flavor: c_int, + buffer: *mut c_void, + buffersize: c_int, + ) -> c_int; + pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; + pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; + pub fn proc_regionfilename( + pid: c_int, + address: u64, + buffer: *mut c_void, + buffersize: u32, + ) -> c_int; + pub fn proc_kmsgbuf(buffer: *mut c_void, buffersize: u32) -> c_int; + pub fn proc_libversion(major: *mut c_int, minor: *mut c_int) -> c_int; + pub fn proc_pid_rusage(pid: c_int, flavor: c_int, buffer: *mut rusage_info_t) -> c_int; + + // Available from Big Sur + pub fn proc_set_no_smt() -> c_int; + pub fn proc_setthread_no_smt() -> c_int; + pub fn proc_set_csm(flags: u32) -> c_int; + pub fn proc_setthread_csm(flags: u32) -> c_int; + /// # Notes + /// + /// `id` is of type [`uuid_t`]. + pub fn gethostuuid(id: *mut u8, timeout: *const crate::timespec) -> c_int; + + pub fn gethostid() -> c_long; + pub fn sethostid(hostid: c_long); + + pub fn CCRandomGenerateBytes(bytes: *mut c_void, size: size_t) -> crate::CCRNGStatus; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + // FIXME(1.0): should this actually be deprecated? + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32) -> c_int; + + // crt_externs.h + pub fn _NSGetArgv() -> *mut *mut *mut c_char; + pub fn _NSGetArgc() -> *mut c_int; + pub fn _NSGetEnviron() -> *mut *mut *mut c_char; + pub fn _NSGetProgname() -> *mut *mut c_char; + + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub fn mach_vm_map( + target_task: crate::vm_map_t, + address: *mut crate::mach_vm_address_t, + size: crate::mach_vm_size_t, + mask: crate::mach_vm_offset_t, + flags: c_int, + object: crate::mem_entry_name_port_t, + offset: crate::memory_object_offset_t, + copy: crate::boolean_t, + cur_protection: crate::vm_prot_t, + max_protection: crate::vm_prot_t, + inheritance: crate::vm_inherit_t, + ) -> crate::kern_return_t; + + pub fn vm_allocate( + target_task: vm_map_t, + address: *mut vm_address_t, + size: vm_size_t, + flags: c_int, + ) -> crate::kern_return_t; + + pub fn vm_deallocate( + target_task: vm_map_t, + address: vm_address_t, + size: vm_size_t, + ) -> crate::kern_return_t; + + pub fn host_statistics64( + host_priv: host_t, + flavor: host_flavor_t, + host_info64_out: host_info64_t, + host_info64_outCnt: *mut mach_msg_type_number_t, + ) -> crate::kern_return_t; + pub fn host_processor_info( + host: host_t, + flavor: processor_flavor_t, + out_processor_count: *mut natural_t, + out_processor_info: *mut processor_info_array_t, + out_processor_infoCnt: *mut mach_msg_type_number_t, + ) -> crate::kern_return_t; + + #[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] + pub static mut mach_task_self_: crate::mach_port_t; + pub fn task_for_pid( + host: crate::mach_port_t, + pid: crate::pid_t, + task: *mut crate::mach_port_t, + ) -> crate::kern_return_t; + pub fn task_info( + host: crate::mach_port_t, + flavor: task_flavor_t, + task_info_out: task_info_t, + task_info_count: *mut mach_msg_type_number_t, + ) -> crate::kern_return_t; + pub fn task_create( + target_task: crate::task_t, + ledgers: crate::ledger_array_t, + ledgersCnt: crate::mach_msg_type_number_t, + inherit_memory: crate::boolean_t, + child_task: *mut crate::task_t, + ) -> crate::kern_return_t; + pub fn task_terminate(target_task: crate::task_t) -> crate::kern_return_t; + pub fn task_threads( + target_task: crate::task_inspect_t, + act_list: *mut crate::thread_act_array_t, + act_listCnt: *mut crate::mach_msg_type_number_t, + ) -> crate::kern_return_t; + pub fn host_statistics( + host_priv: host_t, + flavor: host_flavor_t, + host_info_out: host_info_t, + host_info_outCnt: *mut mach_msg_type_number_t, + ) -> crate::kern_return_t; + + // sysdir.h + pub fn sysdir_start_search_path_enumeration( + dir: sysdir_search_path_directory_t, + domainMask: sysdir_search_path_domain_mask_t, + ) -> crate::sysdir_search_path_enumeration_state; + pub fn sysdir_get_next_search_path_enumeration( + state: crate::sysdir_search_path_enumeration_state, + path: *mut c_char, + ) -> crate::sysdir_search_path_enumeration_state; + + pub static vm_page_size: vm_size_t; + + pub fn getattrlist( + path: *const c_char, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u32, + ) -> c_int; + pub fn fgetattrlist( + fd: c_int, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u32, + ) -> c_int; + pub fn getattrlistat( + fd: c_int, + path: *const c_char, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: c_ulong, + ) -> c_int; + pub fn setattrlist( + path: *const c_char, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u32, + ) -> c_int; + pub fn fsetattrlist( + fd: c_int, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u32, + ) -> c_int; + pub fn setattrlistat( + dir_fd: c_int, + path: *const c_char, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u32, + ) -> c_int; + pub fn getattrlistbulk( + dirfd: c_int, + attrList: *mut c_void, + attrBuf: *mut c_void, + attrBufSize: size_t, + options: u64, + ) -> c_int; + + pub fn malloc_size(ptr: *const c_void) -> size_t; + pub fn malloc_good_size(size: size_t) -> size_t; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn freadlink(fd: c_int, buf: *mut c_char, size: size_t) -> c_int; + pub fn execvP( + file: *const c_char, + search_path: *const c_char, + argv: *const *mut c_char, + ) -> c_int; + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + arg: *mut c_void, + compar: Option c_int>, + ); +} + +#[allow(deprecated)] +#[deprecated(since = "0.2.55", note = "Use the `mach2` crate instead")] +pub unsafe fn mach_task_self() -> crate::mach_port_t { + mach_task_self_ +} + +cfg_if! { + if #[cfg(target_os = "macos")] { + extern "C" { + pub fn clock_settime(clock_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + } + } +} +cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "visionos" + ))] { + extern "C" { + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn task_set_info( + target_task: crate::task_t, + flavor: crate::task_flavor_t, + task_info_in: crate::task_info_t, + task_info_inCnt: crate::mach_msg_type_number_t, + ) -> crate::kern_return_t; + } + } +} + +// These require a dependency on `libiconv`, and including this when built as +// part of `std` means every Rust program gets it. Ideally we would have a link +// modifier to only include these if they are used, but we do not. +#[cfg_attr(not(feature = "rustc-dep-of-std"), link(name = "iconv"))] +extern "C" { + #[deprecated(note = "Will be removed in 1.0 to avoid the `iconv` dependency")] + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; + #[deprecated(note = "Will be removed in 1.0 to avoid the `iconv` dependency")] + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + #[deprecated(note = "Will be removed in 1.0 to avoid the `iconv` dependency")] + pub fn iconv_close(cd: iconv_t) -> c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod b32; + pub use self::b32::*; + } else if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs new file mode 100644 index 00000000000000..60e7989bbde36e --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs @@ -0,0 +1,1374 @@ +use crate::prelude::*; +use crate::{ + cmsghdr, + off_t, +}; + +pub type dev_t = u32; +pub type wchar_t = i32; +pub type clock_t = u64; +pub type ino_t = u64; +pub type lwpid_t = i32; +pub type nlink_t = u32; +pub type blksize_t = i64; +pub type clockid_t = c_ulong; + +pub type time_t = i64; +pub type suseconds_t = i64; + +pub type uuid_t = crate::uuid; + +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type idtype_t = c_uint; +pub type shmatt_t = c_uint; + +pub type mqd_t = c_int; +pub type sem_t = *mut sem; + +pub type cpuset_t = cpumask_t; +pub type cpu_set_t = cpumask_t; + +pub type register_t = c_long; +pub type umtx_t = c_int; +pub type pthread_barrierattr_t = c_int; +pub type pthread_barrier_t = crate::uintptr_t; +pub type pthread_spinlock_t = crate::uintptr_t; + +pub type segsz_t = usize; + +pub type vm_prot_t = u8; +pub type vm_maptype_t = u8; +pub type vm_inherit_t = i8; +pub type vm_subsys_t = c_int; +pub type vm_eflags_t = c_uint; + +pub type vm_map_t = *mut __c_anonymous_vm_map; +pub type vm_map_entry_t = *mut vm_map_entry; + +pub type pmap = __c_anonymous_pmap; + +extern_ty! { + pub enum sem {} +} + +e! { + #[repr(u32)] + pub enum lwpstat { + LSRUN = 1, + LSSTOP = 2, + LSSLEEP = 3, + } + + #[repr(u32)] + pub enum procstat { + SIDL = 1, + SACTIVE = 2, + SSTOP = 3, + SZOMB = 4, + SCORE = 5, + } +} + +s! { + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: intptr_t, + pub udata: *mut c_void, + } + + pub struct exit_status { + pub e_termination: u16, + pub e_exit: u16, + } + + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: sigevent, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + _aio_val: c_int, + _aio_err: c_int, + } + + pub struct uuid { + pub time_low: u32, + pub time_mid: u16, + pub time_hi_and_version: u16, + clock_seq_hi_and_reserved: Padding, + pub clock_seq_low: u8, + pub node: [u8; 6], + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub f_owner: crate::uid_t, + pub f_type: c_uint, + pub f_syncreads: u64, + pub f_syncwrites: u64, + pub f_asyncreads: u64, + pub f_asyncwrites: u64, + pub f_fsid_uuid: crate::uuid_t, + pub f_uid_uuid: crate::uuid_t, + } + + pub struct stat { + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_dev: crate::dev_t, + pub st_mode: crate::mode_t, + st_padding1: Padding, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: i64, + pub __old_st_blksize: u32, + pub st_flags: u32, + pub st_gen: u32, + pub st_lspare: i32, + pub st_blksize: i64, + pub st_qspare2: i64, + } + + pub struct if_data { + pub ifi_type: c_uchar, + pub ifi_physical: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_recvquota: c_uchar, + pub ifi_xmitquota: c_uchar, + pub ifi_mtu: c_ulong, + pub ifi_metric: c_ulong, + pub ifi_link_state: c_ulong, + pub ifi_baudrate: u64, + pub ifi_ipackets: c_ulong, + pub ifi_ierrors: c_ulong, + pub ifi_opackets: c_ulong, + pub ifi_oerrors: c_ulong, + pub ifi_collisions: c_ulong, + pub ifi_ibytes: c_ulong, + pub ifi_obytes: c_ulong, + pub ifi_imcasts: c_ulong, + pub ifi_omcasts: c_ulong, + pub ifi_iqdrops: c_ulong, + pub ifi_noproto: c_ulong, + pub ifi_hwassist: c_ulong, + pub ifi_oqdrops: c_ulong, + pub ifi_lastchange: crate::timeval, + } + + pub struct if_msghdr { + pub ifm_msglen: c_ushort, + pub ifm_version: c_uchar, + pub ifm_type: c_uchar, + pub ifm_addrs: c_int, + pub ifm_flags: c_int, + pub ifm_index: c_ushort, + pub ifm_data: if_data, + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 12], + pub sdl_rcf: c_ushort, + pub sdl_route: [c_ushort; 16], + } + + pub struct xucred { + pub cr_version: c_uint, + pub cr_uid: crate::uid_t, + pub cr_ngroups: c_short, + pub cr_groups: [crate::gid_t; 16], + __cr_unused1: Padding<*mut c_void>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct cpumask_t { + ary: [u64; 4], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + shm_internal: *mut c_void, + } + + pub struct kinfo_file { + pub f_size: size_t, + pub f_pid: crate::pid_t, + pub f_uid: crate::uid_t, + pub f_fd: c_int, + pub f_file: *mut c_void, + pub f_type: c_short, + pub f_count: c_int, + pub f_msgcount: c_int, + pub f_offset: off_t, + pub f_data: *mut c_void, + pub f_flag: c_uint, + } + + pub struct kinfo_cputime { + pub cp_user: u64, + pub cp_nice: u64, + pub cp_sys: u64, + pub cp_intr: u64, + pub cp_idel: u64, + cp_unused01: Padding, + cp_unused02: Padding, + pub cp_sample_pc: u64, + pub cp_sample_sp: u64, + pub cp_msg: [c_char; 32], + } + + pub struct kinfo_lwp { + pub kl_pid: crate::pid_t, + pub kl_tid: crate::lwpid_t, + pub kl_flags: c_int, + pub kl_stat: crate::lwpstat, + pub kl_lock: c_int, + pub kl_tdflags: c_int, + pub kl_mpcount: c_int, + pub kl_prio: c_int, + pub kl_tdprio: c_int, + pub kl_rtprio: crate::rtprio, + pub kl_uticks: u64, + pub kl_sticks: u64, + pub kl_iticks: u64, + pub kl_cpticks: u64, + pub kl_pctcpu: c_uint, + pub kl_slptime: c_uint, + pub kl_origcpu: c_int, + pub kl_estcpu: c_int, + pub kl_cpuid: c_int, + pub kl_ru: crate::rusage, + pub kl_siglist: crate::sigset_t, + pub kl_sigmask: crate::sigset_t, + pub kl_wchan: crate::uintptr_t, + pub kl_wmesg: [c_char; 9], + pub kl_comm: [c_char; MAXCOMLEN + 1], + } + + pub struct kinfo_proc { + pub kp_paddr: crate::uintptr_t, + pub kp_flags: c_int, + pub kp_stat: crate::procstat, + pub kp_lock: c_int, + pub kp_acflag: c_int, + pub kp_traceflag: c_int, + pub kp_fd: crate::uintptr_t, + pub kp_siglist: crate::sigset_t, + pub kp_sigignore: crate::sigset_t, + pub kp_sigcatch: crate::sigset_t, + pub kp_sigflag: c_int, + pub kp_start: crate::timeval, + pub kp_comm: [c_char; MAXCOMLEN + 1], + pub kp_uid: crate::uid_t, + pub kp_ngroups: c_short, + pub kp_groups: [crate::gid_t; NGROUPS], + pub kp_ruid: crate::uid_t, + pub kp_svuid: crate::uid_t, + pub kp_rgid: crate::gid_t, + pub kp_svgid: crate::gid_t, + pub kp_pid: crate::pid_t, + pub kp_ppid: crate::pid_t, + pub kp_pgid: crate::pid_t, + pub kp_jobc: c_int, + pub kp_sid: crate::pid_t, + pub kp_login: [c_char; 40], // MAXNAMELEN rounded up to the nearest sizeof(long) + pub kp_tdev: crate::dev_t, + pub kp_tpgid: crate::pid_t, + pub kp_tsid: crate::pid_t, + pub kp_exitstat: c_ushort, + pub kp_nthreads: c_int, + pub kp_nice: c_int, + pub kp_swtime: c_uint, + pub kp_vm_map_size: size_t, + pub kp_vm_rssize: crate::segsz_t, + pub kp_vm_swrss: crate::segsz_t, + pub kp_vm_tsize: crate::segsz_t, + pub kp_vm_dsize: crate::segsz_t, + pub kp_vm_ssize: crate::segsz_t, + pub kp_vm_prssize: c_uint, + pub kp_jailid: c_int, + pub kp_ru: crate::rusage, + pub kp_cru: crate::rusage, + pub kp_auxflags: c_int, + pub kp_lwp: crate::kinfo_lwp, + pub kp_ktaddr: crate::uintptr_t, + kp_spare: [c_int; 2], + } + + pub struct __c_anonymous_vm_map { + _priv: [crate::uintptr_t; 36], + } + + pub struct vm_map_entry { + _priv: [crate::uintptr_t; 15], + pub eflags: crate::vm_eflags_t, + pub maptype: crate::vm_maptype_t, + pub protection: crate::vm_prot_t, + pub max_protection: crate::vm_prot_t, + pub inheritance: crate::vm_inherit_t, + pub wired_count: c_int, + pub id: crate::vm_subsys_t, + } + + pub struct __c_anonymous_pmap { + _priv1: [crate::uintptr_t; 32], + _priv2: [crate::uintptr_t; 32], + _priv3: [crate::uintptr_t; 32], + _priv4: [crate::uintptr_t; 32], + _priv5: [crate::uintptr_t; 8], + } + + pub struct vmspace { + vm_map: __c_anonymous_vm_map, + vm_pmap: __c_anonymous_pmap, + pub vm_flags: c_int, + pub vm_shm: *mut c_char, + pub vm_rssize: crate::segsz_t, + pub vm_swrss: crate::segsz_t, + pub vm_tsize: crate::segsz_t, + pub vm_dsize: crate::segsz_t, + pub vm_ssize: crate::segsz_t, + pub vm_taddr: *mut c_char, + pub vm_daddr: *mut c_char, + pub vm_maxsaddr: *mut c_char, + pub vm_minsaddr: *mut c_char, + _unused1: Padding, + _unused2: Padding, + pub vm_pagesupply: c_int, + pub vm_holdcnt: c_uint, + pub vm_refcnt: c_uint, + } + + pub struct cpuctl_msr_args_t { + pub msr: c_int, + pub data: u64, + } + + pub struct cpuctl_cpuid_args_t { + pub level: c_int, + pub data: [u32; 4], + } + + pub struct cpuctl_cpuid_count_args_t { + pub level: c_int, + pub level_type: c_int, + pub data: [u32; 4], + } + + pub struct cpuctl_update_args_t { + pub data: *mut c_void, + pub size: size_t, + } + + pub struct utmpx { + pub ut_name: [c_char; 32], + pub ut_id: [c_char; 4], + + pub ut_line: [c_char; 32], + pub ut_host: [c_char; 256], + + ut_unused: Padding<[u8; 16]>, + pub ut_session: u16, + pub ut_type: u16, + pub ut_pid: crate::pid_t, + ut_exit: exit_status, + ut_ss: crate::sockaddr_storage, + pub ut_tv: crate::timeval, + ut_unused2: Padding<[u8; 16]>, + } + + pub struct lastlogx { + pub ll_tv: crate::timeval, + pub ll_line: [c_char; _UTX_LINESIZE], + pub ll_host: [c_char; _UTX_HOSTSIZE], + pub ll_ss: crate::sockaddr_storage, + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_namlen: u16, + pub d_type: u8, + __unused1: Padding, + __unused2: Padding, + pub d_name: [c_char; 256], + } + + pub struct statfs { + __spare2: c_long, + pub f_bsize: c_long, + pub f_iosize: c_long, + pub f_blocks: c_long, + pub f_bfree: c_long, + pub f_bavail: c_long, + pub f_files: c_long, + pub f_ffree: c_long, + pub f_fsid: crate::fsid_t, + pub f_owner: crate::uid_t, + pub f_type: c_int, + pub f_flags: c_int, + pub f_syncwrites: c_long, + pub f_asyncwrites: c_long, + pub f_fstypename: [c_char; 16], + pub f_mntonname: [c_char; 80], + pub f_syncreads: c_long, + pub f_asyncreads: c_long, + __spares1: c_short, + pub f_mntfromname: [c_char; 80], + __spares2: c_short, + __spare: [c_long; 2], + } + + pub struct sigevent { + pub sigev_notify: c_int, + // The union is 8-byte in size, so it is aligned at a 8-byte offset. + #[cfg(target_pointer_width = "64")] + __unused1: Padding, + pub sigev_signo: c_int, //actually a union + // pad the union + #[cfg(target_pointer_width = "64")] + __unused2: Padding, + pub sigev_value: crate::sigval, + __unused3: Padding<*mut c_void>, //actually a function pointer + } + + pub struct mcontext_t { + pub mc_onstack: register_t, + pub mc_rdi: register_t, + pub mc_rsi: register_t, + pub mc_rdx: register_t, + pub mc_rcx: register_t, + pub mc_r8: register_t, + pub mc_r9: register_t, + pub mc_rax: register_t, + pub mc_rbx: register_t, + pub mc_rbp: register_t, + pub mc_r10: register_t, + pub mc_r11: register_t, + pub mc_r12: register_t, + pub mc_r13: register_t, + pub mc_r14: register_t, + pub mc_r15: register_t, + pub mc_xflags: register_t, + pub mc_trapno: register_t, + pub mc_addr: register_t, + pub mc_flags: register_t, + pub mc_err: register_t, + pub mc_rip: register_t, + pub mc_cs: register_t, + pub mc_rflags: register_t, + pub mc_rsp: register_t, + pub mc_ss: register_t, + pub mc_len: c_uint, + pub mc_fpformat: c_uint, + pub mc_ownedfp: c_uint, + __reserved: Padding, + __unused: Padding<[c_uint; 8]>, + pub mc_fpregs: [c_uint; 256], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct ucontext_t { + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + pub uc_link: *mut ucontext_t, + pub uc_stack: stack_t, + pub uc_cofunc: Option, + pub uc_arg: *mut c_void, + __pad: Padding<[c_int; 4]>, + } +} + +pub const RAND_MAX: c_int = 0x7fff_ffff; +pub const PTHREAD_STACK_MIN: size_t = 16384; +pub const SIGSTKSZ: size_t = 40960; +pub const SIGCKPT: c_int = 33; +pub const SIGCKPTEXIT: c_int = 34; +pub const CKPT_FREEZE: c_int = 0x1; +pub const CKPT_THAW: c_int = 0x2; +pub const MADV_INVAL: c_int = 10; +pub const MADV_SETMAP: c_int = 11; +pub const O_CLOEXEC: c_int = 0x00020000; +pub const O_DIRECTORY: c_int = 0x08000000; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_GETPATH: c_int = 19; +pub const ENOMEDIUM: c_int = 93; +pub const ENOTRECOVERABLE: c_int = 94; +pub const EOWNERDEAD: c_int = 95; +pub const EASYNC: c_int = 99; +pub const ELAST: c_int = 99; +pub const RLIMIT_POSIXLOCKS: c_int = 11; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: crate::rlim_t = 12; + +pub const Q_GETQUOTA: c_int = 0x300; +pub const Q_SETQUOTA: c_int = 0x400; + +pub const CTL_UNSPEC: c_int = 0; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_VFS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_USER: c_int = 8; +pub const CTL_P1003_1B: c_int = 9; +pub const CTL_LWKT: c_int = 10; +pub const CTL_MAXID: c_int = 11; +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_VNODE: c_int = 13; +pub const KERN_PROC: c_int = 14; +pub const KERN_FILE: c_int = 15; +pub const KERN_PROF: c_int = 16; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_BOOTTIME: c_int = 21; +pub const KERN_NISDOMAINNAME: c_int = 22; +pub const KERN_UPDATEINTERVAL: c_int = 23; +pub const KERN_OSRELDATE: c_int = 24; +pub const KERN_NTP_PLL: c_int = 25; +pub const KERN_BOOTFILE: c_int = 26; +pub const KERN_MAXFILESPERPROC: c_int = 27; +pub const KERN_MAXPROCPERUID: c_int = 28; +pub const KERN_DUMPDEV: c_int = 29; +pub const KERN_IPC: c_int = 30; +pub const KERN_DUMMY: c_int = 31; +pub const KERN_PS_STRINGS: c_int = 32; +pub const KERN_USRSTACK: c_int = 33; +pub const KERN_LOGSIGEXIT: c_int = 34; +pub const KERN_IOV_MAX: c_int = 35; +pub const KERN_MAXPOSIXLOCKSPERUID: c_int = 36; +pub const KERN_MAXID: c_int = 37; +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_ARGS: c_int = 7; +pub const KERN_PROC_CWD: c_int = 8; +pub const KERN_PROC_PATHNAME: c_int = 9; +pub const KERN_PROC_FLAGMASK: c_int = 0x10; +pub const KERN_PROC_FLAG_LWP: c_int = 0x10; +pub const KIPC_MAXSOCKBUF: c_int = 1; +pub const KIPC_SOCKBUF_WASTE: c_int = 2; +pub const KIPC_SOMAXCONN: c_int = 3; +pub const KIPC_MAX_LINKHDR: c_int = 4; +pub const KIPC_MAX_PROTOHDR: c_int = 5; +pub const KIPC_MAX_HDR: c_int = 6; +pub const KIPC_MAX_DATALEN: c_int = 7; +pub const KIPC_MBSTAT: c_int = 8; +pub const KIPC_NMBCLUSTERS: c_int = 9; +pub const HW_MACHINE: c_int = 1; +pub const HW_MODEL: c_int = 2; +pub const HW_NCPU: c_int = 3; +pub const HW_BYTEORDER: c_int = 4; +pub const HW_PHYSMEM: c_int = 5; +pub const HW_USERMEM: c_int = 6; +pub const HW_PAGESIZE: c_int = 7; +pub const HW_DISKNAMES: c_int = 8; +pub const HW_DISKSTATS: c_int = 9; +pub const HW_FLOATINGPT: c_int = 10; +pub const HW_MACHINE_ARCH: c_int = 11; +pub const HW_MACHINE_PLATFORM: c_int = 12; +pub const HW_SENSORS: c_int = 13; +pub const HW_MAXID: c_int = 14; +pub const USER_CS_PATH: c_int = 1; +pub const USER_BC_BASE_MAX: c_int = 2; +pub const USER_BC_DIM_MAX: c_int = 3; +pub const USER_BC_SCALE_MAX: c_int = 4; +pub const USER_BC_STRING_MAX: c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: c_int = 6; +pub const USER_EXPR_NEST_MAX: c_int = 7; +pub const USER_LINE_MAX: c_int = 8; +pub const USER_RE_DUP_MAX: c_int = 9; +pub const USER_POSIX2_VERSION: c_int = 10; +pub const USER_POSIX2_C_BIND: c_int = 11; +pub const USER_POSIX2_C_DEV: c_int = 12; +pub const USER_POSIX2_CHAR_TERM: c_int = 13; +pub const USER_POSIX2_FORT_DEV: c_int = 14; +pub const USER_POSIX2_FORT_RUN: c_int = 15; +pub const USER_POSIX2_LOCALEDEF: c_int = 16; +pub const USER_POSIX2_SW_DEV: c_int = 17; +pub const USER_POSIX2_UPE: c_int = 18; +pub const USER_STREAM_MAX: c_int = 19; +pub const USER_TZNAME_MAX: c_int = 20; +pub const USER_MAXID: c_int = 21; +pub const CTL_P1003_1B_ASYNCHRONOUS_IO: c_int = 1; +pub const CTL_P1003_1B_MAPPED_FILES: c_int = 2; +pub const CTL_P1003_1B_MEMLOCK: c_int = 3; +pub const CTL_P1003_1B_MEMLOCK_RANGE: c_int = 4; +pub const CTL_P1003_1B_MEMORY_PROTECTION: c_int = 5; +pub const CTL_P1003_1B_MESSAGE_PASSING: c_int = 6; +pub const CTL_P1003_1B_PRIORITIZED_IO: c_int = 7; +pub const CTL_P1003_1B_PRIORITY_SCHEDULING: c_int = 8; +pub const CTL_P1003_1B_REALTIME_SIGNALS: c_int = 9; +pub const CTL_P1003_1B_SEMAPHORES: c_int = 10; +pub const CTL_P1003_1B_FSYNC: c_int = 11; +pub const CTL_P1003_1B_SHARED_MEMORY_OBJECTS: c_int = 12; +pub const CTL_P1003_1B_SYNCHRONIZED_IO: c_int = 13; +pub const CTL_P1003_1B_TIMERS: c_int = 14; +pub const CTL_P1003_1B_AIO_LISTIO_MAX: c_int = 15; +pub const CTL_P1003_1B_AIO_MAX: c_int = 16; +pub const CTL_P1003_1B_AIO_PRIO_DELTA_MAX: c_int = 17; +pub const CTL_P1003_1B_DELAYTIMER_MAX: c_int = 18; +pub const CTL_P1003_1B_UNUSED1: c_int = 19; +pub const CTL_P1003_1B_PAGESIZE: c_int = 20; +pub const CTL_P1003_1B_RTSIG_MAX: c_int = 21; +pub const CTL_P1003_1B_SEM_NSEMS_MAX: c_int = 22; +pub const CTL_P1003_1B_SEM_VALUE_MAX: c_int = 23; +pub const CTL_P1003_1B_SIGQUEUE_MAX: c_int = 24; +pub const CTL_P1003_1B_TIMER_MAX: c_int = 25; +pub const CTL_P1003_1B_MAXID: c_int = 26; + +pub const CPUCTL_RSMSR: c_int = 0xc0106301; +pub const CPUCTL_WRMSR: c_int = 0xc0106302; +pub const CPUCTL_CPUID: c_int = 0xc0106303; +pub const CPUCTL_UPDATE: c_int = 0xc0106304; +pub const CPUCTL_MSRSBIT: c_int = 0xc0106305; +pub const CPUCTL_MSRCBIT: c_int = 0xc0106306; +pub const CPUCTL_CPUID_COUNT: c_int = 0xc0106307; + +pub const CPU_SETSIZE: size_t = size_of::() * 8; + +pub const EVFILT_READ: i16 = -1; +pub const EVFILT_WRITE: i16 = -2; +pub const EVFILT_AIO: i16 = -3; +pub const EVFILT_VNODE: i16 = -4; +pub const EVFILT_PROC: i16 = -5; +pub const EVFILT_SIGNAL: i16 = -6; +pub const EVFILT_TIMER: i16 = -7; +pub const EVFILT_EXCEPT: i16 = -8; +pub const EVFILT_USER: i16 = -9; +pub const EVFILT_FS: i16 = -10; + +pub const EV_ADD: u16 = 0x1; +pub const EV_DELETE: u16 = 0x2; +pub const EV_ENABLE: u16 = 0x4; +pub const EV_DISABLE: u16 = 0x8; +pub const EV_ONESHOT: u16 = 0x10; +pub const EV_CLEAR: u16 = 0x20; +pub const EV_RECEIPT: u16 = 0x40; +pub const EV_DISPATCH: u16 = 0x80; +pub const EV_NODATA: u16 = 0x1000; +pub const EV_FLAG1: u16 = 0x2000; +pub const EV_ERROR: u16 = 0x4000; +pub const EV_EOF: u16 = 0x8000; +pub const EV_HUP: u16 = 0x8000; +pub const EV_SYSFLAGS: u16 = 0xf000; + +pub const FIODNAME: c_ulong = 0x80106678; + +pub const NOTE_TRIGGER: u32 = 0x01000000; +pub const NOTE_FFNOP: u32 = 0x00000000; +pub const NOTE_FFAND: u32 = 0x40000000; +pub const NOTE_FFOR: u32 = 0x80000000; +pub const NOTE_FFCOPY: u32 = 0xc0000000; +pub const NOTE_FFCTRLMASK: u32 = 0xc0000000; +pub const NOTE_FFLAGSMASK: u32 = 0x00ffffff; +pub const NOTE_LOWAT: u32 = 0x00000001; +pub const NOTE_OOB: u32 = 0x00000002; +pub const NOTE_DELETE: u32 = 0x00000001; +pub const NOTE_WRITE: u32 = 0x00000002; +pub const NOTE_EXTEND: u32 = 0x00000004; +pub const NOTE_ATTRIB: u32 = 0x00000008; +pub const NOTE_LINK: u32 = 0x00000010; +pub const NOTE_RENAME: u32 = 0x00000020; +pub const NOTE_REVOKE: u32 = 0x00000040; +pub const NOTE_EXIT: u32 = 0x80000000; +pub const NOTE_FORK: u32 = 0x40000000; +pub const NOTE_EXEC: u32 = 0x20000000; +pub const NOTE_PDATAMASK: u32 = 0x000fffff; +pub const NOTE_PCTRLMASK: u32 = 0xf0000000; +pub const NOTE_TRACK: u32 = 0x00000001; +pub const NOTE_TRACKERR: u32 = 0x00000002; +pub const NOTE_CHILD: u32 = 0x00000004; + +pub const SO_SNDSPACE: c_int = 0x100a; +pub const SO_CPUHINT: c_int = 0x1030; +pub const SO_PASSCRED: c_int = 0x4000; + +pub const PT_FIRSTMACH: c_int = 32; + +pub const PROC_REAP_ACQUIRE: c_int = 0x0001; +pub const PROC_REAP_RELEASE: c_int = 0x0002; +pub const PROC_REAP_STATUS: c_int = 0x0003; +pub const PROC_PDEATHSIG_CTL: c_int = 0x0004; +pub const PROC_PDEATHSIG_STATUS: c_int = 0x0005; + +// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/HEAD/sys/net/if.h#L101 +pub const IFF_UP: c_int = 0x1; // interface is up +pub const IFF_BROADCAST: c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x10; // interface is point-to-point link +pub const IFF_SMART: c_int = 0x20; // interface manages own routes +pub const IFF_RUNNING: c_int = 0x40; // resources allocated +pub const IFF_NOARP: c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE_COMPAT: c_int = 0x400; // was transmission in progress +pub const IFF_SIMPLEX: c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + // was interface is in polling mode +pub const IFF_POLLING_COMPAT: c_int = 0x10000; +pub const IFF_PPROMISC: c_int = 0x20000; // user-requested promisc mode +pub const IFF_MONITOR: c_int = 0x40000; // user-requested monitor mode +pub const IFF_STATICARP: c_int = 0x80000; // static ARP +pub const IFF_NPOLLING: c_int = 0x100000; // interface is in polling mode +pub const IFF_IDIRECT: c_int = 0x200000; // direct input + +// +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: c_int = 11; +/// pup +pub const IPPROTO_PUP: c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: c_int = 21; +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: c_int = 30; +/// Network Services +pub const IPPROTO_NSP: c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: c_int = 32; +/// Sequential Exchange +pub const IPPROTO_SEP: c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: c_int = 35; +/// XTP +pub const IPPROTO_XTP: c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: c_int = 48; +/// BHA +pub const IPPROTO_BHA: c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: c_int = 54; +/// IP Mobility +pub const IPPROTO_MOBILE: c_int = 55; +/// Transport Layer Security +pub const IPPROTO_TLSP: c_int = 56; +/// SKIP +pub const IPPROTO_SKIP: c_int = 57; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: c_int = 83; +/// TTP +pub const IPPROTO_TTP: c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: c_int = 86; +/// TCF +pub const IPPROTO_TCF: c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: c_int = 100; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: c_int = 108; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: c_int = 103; +/// CARP +pub const IPPROTO_CARP: c_int = 112; +/// PGM +pub const IPPROTO_PGM: c_int = 113; +/// PFSYNC +pub const IPPROTO_PFSYNC: c_int = 240; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion, no longer used */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: c_int = 254; +pub const IPPROTO_MAX: c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: c_int = 257; + +/// Used by RSS: the layer3 protocol is unknown +pub const IPPROTO_UNKNOWN: c_int = 258; + +// sys/netinet/tcp.h +pub const TCP_SIGNATURE_ENABLE: c_int = 16; +pub const TCP_KEEPINIT: c_int = 32; +pub const TCP_FASTKEEP: c_int = 128; + +pub const AF_BLUETOOTH: c_int = 33; +pub const AF_MPLS: c_int = 34; +pub const AF_IEEE80211: c_int = 35; + +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; + +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const NET_RT_IFLIST: c_int = 3; +pub const NET_RT_MAXID: c_int = 4; + +pub const SOMAXOPT_SIZE: c_int = 65536; + +pub const MSG_UNUSED09: c_int = 0x00000200; +pub const MSG_NOSIGNAL: c_int = 0x00000400; +pub const MSG_SYNC: c_int = 0x00000800; +pub const MSG_CMSG_CLOEXEC: c_int = 0x00001000; +pub const MSG_FBLOCKING: c_int = 0x00010000; +pub const MSG_FNONBLOCKING: c_int = 0x00020000; +pub const MSG_FMASK: c_int = 0xFFFF0000; + +// sys/mount.h +pub const MNT_NODEV: c_int = 0x00000010; +pub const MNT_AUTOMOUNTED: c_int = 0x00000020; +pub const MNT_TRIM: c_int = 0x01000000; +pub const MNT_LOCAL: c_int = 0x00001000; +pub const MNT_QUOTA: c_int = 0x00002000; +pub const MNT_ROOTFS: c_int = 0x00004000; +pub const MNT_USER: c_int = 0x00008000; +pub const MNT_IGNORE: c_int = 0x00800000; + +// utmpx entry types +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const OLD_TIME: c_short = 3; +pub const NEW_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; +pub const SIGNATURE: c_short = 10; +pub const DOWNTIME: c_short = 11; +// utmpx database types +pub const UTX_DB_UTMPX: c_uint = 0; +pub const UTX_DB_WTMPX: c_uint = 1; +pub const UTX_DB_LASTLOG: c_uint = 2; +pub const _UTX_LINESIZE: usize = 32; +pub const _UTX_USERSIZE: usize = 32; +pub const _UTX_IDSIZE: usize = 4; +pub const _UTX_HOSTSIZE: usize = 256; + +pub const LC_COLLATE_MASK: c_int = 1 << 0; +pub const LC_CTYPE_MASK: c_int = 1 << 1; +pub const LC_MONETARY_MASK: c_int = 1 << 2; +pub const LC_NUMERIC_MASK: c_int = 1 << 3; +pub const LC_TIME_MASK: c_int = 1 << 4; +pub const LC_MESSAGES_MASK: c_int = 1 << 5; +pub const LC_ALL_MASK: c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const TIOCSIG: c_ulong = 0x2000745f; +pub const BTUARTDISC: c_int = 0x7; +pub const TIOCDCDTIMESTAMP: c_ulong = 0x40107458; +pub const TIOCISPTMASTER: c_ulong = 0x20007455; +pub const TIOCMODG: c_ulong = 0x40047403; +pub const TIOCMODS: c_ulong = 0x80047404; +pub const TIOCREMOTE: c_ulong = 0x80047469; +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; + +// Constants used by "at" family of system calls. +pub const AT_FDCWD: c_int = 0xFFFAFDCD; // invalid file descriptor +pub const AT_SYMLINK_NOFOLLOW: c_int = 1; +pub const AT_REMOVEDIR: c_int = 2; +pub const AT_EACCESS: c_int = 4; +pub const AT_SYMLINK_FOLLOW: c_int = 8; + +pub const VCHECKPT: usize = 19; + +pub const _PC_2_SYMLINKS: c_int = 22; +pub const _PC_TIMESTAMP_RESOLUTION: c_int = 23; + +pub const _CS_PATH: c_int = 1; + +pub const _SC_V7_ILP32_OFF32: c_int = 122; +pub const _SC_V7_ILP32_OFFBIG: c_int = 123; +pub const _SC_V7_LP64_OFF64: c_int = 124; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 125; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 126; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 127; + +pub const WCONTINUED: c_int = 0x4; +pub const WSTOPPED: c_int = 0x2; +pub const WNOWAIT: c_int = 0x8; +pub const WEXITED: c_int = 0x10; +pub const WTRAPPED: c_int = 0x20; + +// Similar to FreeBSD, only the standardized ones are exposed. +// There are more. +pub const P_PID: idtype_t = 0; +pub const P_PGID: idtype_t = 2; +pub const P_ALL: idtype_t = 7; + +// Values for struct rtprio (type_ field) +pub const RTP_PRIO_REALTIME: c_ushort = 0; +pub const RTP_PRIO_NORMAL: c_ushort = 1; +pub const RTP_PRIO_IDLE: c_ushort = 2; +pub const RTP_PRIO_THREAD: c_ushort = 3; + +// Flags for chflags(2) +pub const UF_NOHISTORY: c_ulong = 0x00000040; +pub const UF_CACHE: c_ulong = 0x00000080; +pub const UF_XLINK: c_ulong = 0x00000100; +pub const SF_NOHISTORY: c_ulong = 0x00400000; +pub const SF_CACHE: c_ulong = 0x00800000; +pub const SF_XLINK: c_ulong = 0x01000000; + +// timespec constants +pub const UTIME_OMIT: c_long = -2; +pub const UTIME_NOW: c_long = -1; + +pub const MINCORE_SUPER: c_int = 0x20; + +// kinfo_proc constants +pub const MAXCOMLEN: usize = 16; +pub const MAXLOGNAME: usize = 33; +pub const NGROUPS: usize = 16; + +pub const RB_PAUSE: c_int = 0x40000; +pub const RB_VIDEO: c_int = 0x20000000; + +// net/route.h +pub const RTF_CLONING: c_int = 0x100; +pub const RTF_PRCLONING: c_int = 0x10000; +pub const RTF_WASCLONED: c_int = 0x20000; +pub const RTF_MPLSOPS: c_int = 0x1000000; + +pub const RTM_VERSION: c_int = 7; + +pub const RTAX_MPLS1: c_int = 8; +pub const RTAX_MPLS2: c_int = 9; +pub const RTAX_MPLS3: c_int = 10; +pub const RTAX_MAX: c_int = 11; + +const fn _CMSG_ALIGN(n: usize) -> usize { + (n + (size_of::() - 1)) & !(size_of::() - 1) +} + +f! { + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(_CMSG_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + (_CMSG_ALIGN(size_of::()) + length as usize) as c_uint + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + let next = cmsg as usize + + _CMSG_ALIGN((*cmsg).cmsg_len as usize) + + _CMSG_ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next <= max { + (cmsg as usize + _CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (_CMSG_ALIGN(size_of::()) + _CMSG_ALIGN(length as usize)) as c_uint + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.ary.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let (idx, offset) = ((cpu >> 6) & 3, cpu & 63); + cpuset.ary[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let (idx, offset) = ((cpu >> 6) & 3, cpu & 63); + cpuset.ary[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let (idx, offset) = ((cpu >> 6) & 3, cpu & 63); + 0 != cpuset.ary[idx] & (1 << offset) + } +} + +safe_f! { + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= major << 8; + dev |= minor; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + ((dev >> 8) & 0xff) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (dev & 0xffff00ff) as c_int + } +} + +extern "C" { + pub fn __errno_location() -> *mut c_int; + pub fn setgrent(); + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + + pub fn setutxdb(_type: c_uint, file: *mut c_char) -> c_int; + + pub fn aio_waitcomplete(iocbp: *mut *mut aiocb, timeout: *mut crate::timespec) -> c_int; + + pub fn devname_r( + dev: crate::dev_t, + mode: crate::mode_t, + buf: *mut c_char, + len: size_t, + ) -> *mut c_char; + + pub fn waitid( + idtype: idtype_t, + id: crate::id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + + pub fn freelocale(loc: crate::locale_t); + + pub fn lwp_rtprio( + function: c_int, + pid: crate::pid_t, + lwpid: lwpid_t, + rtp: *mut super::rtprio, + ) -> c_int; + + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn sched_getaffinity(pid: crate::pid_t, cpusetsize: size_t, mask: *mut cpu_set_t) -> c_int; + pub fn sched_setaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + mask: *const cpu_set_t, + ) -> c_int; + pub fn sched_getcpu() -> c_int; + pub fn setproctitle(fmt: *const c_char, ...); + + pub fn shmget(key: crate::key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + pub fn procctl( + idtype: crate::idtype_t, + id: crate::id_t, + cmd: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn updwtmpx(file: *const c_char, ut: *const utmpx) -> c_int; + pub fn getlastlogx(fname: *const c_char, uid: crate::uid_t, ll: *mut lastlogx) + -> *mut lastlogx; + pub fn updlastlogx(fname: *const c_char, uid: crate::uid_t, ll: *mut lastlogx) -> c_int; + pub fn getutxuser(name: *const c_char) -> utmpx; + pub fn utmpxname(file: *const c_char) -> c_int; + + pub fn sys_checkpoint(tpe: c_int, fd: c_int, pid: crate::pid_t, retval: c_int) -> c_int; + + pub fn umtx_sleep(ptr: *const c_int, value: c_int, timeout: c_int) -> c_int; + pub fn umtx_wakeup(ptr: *const c_int, count: c_int) -> c_int; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + pub fn getmntinfo(mntbufp: *mut *mut crate::statfs, flags: c_int) -> c_int; + pub fn getmntvinfo( + mntbufp: *mut *mut crate::statfs, + mntvbufp: *mut *mut crate::statvfs, + flags: c_int, + ) -> c_int; + + pub fn closefrom(lowfd: c_int) -> c_int; +} + +#[link(name = "rt")] +extern "C" { + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut sigevent, + ) -> c_int; + + pub fn reallocf(ptr: *mut c_void, size: size_t) -> *mut c_void; + pub fn freezero(ptr: *mut c_void, size: size_t); +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_vm_map_entry_first( + kvm: *mut crate::kvm_t, + map: vm_map_t, + entry: vm_map_entry_t, + ) -> vm_map_entry_t; + pub fn kvm_vm_map_entry_next( + kvm: *mut crate::kvm_t, + map: vm_map_entry_t, + entry: vm_map_entry_t, + ) -> vm_map_entry_t; +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs new file mode 100644 index 00000000000000..232770f6e00fae --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs @@ -0,0 +1,42 @@ +use crate::prelude::*; + +pub type clock_t = i32; +pub type wchar_t = u32; +pub type time_t = i64; +pub type suseconds_t = i64; +pub type register_t = i64; + +s! { + pub struct gpregs { + pub gp_x: [crate::register_t; 30], + pub gp_lr: crate::register_t, + pub gp_sp: crate::register_t, + pub gp_elr: crate::register_t, + pub gp_spsr: u32, + pub gp_pad: c_int, + } + + pub struct fpregs { + pub fp_q: u128, + pub fp_sr: u32, + pub fp_cr: u32, + pub fp_flags: c_int, + pub fp_pad: c_int, + } + + pub struct mcontext_t { + pub mc_gpregs: gpregs, + pub mc_fpregs: fpregs, + pub mc_flags: c_int, + pub mc_pad: c_int, + pub mc_spare: [u64; 8], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 4096; // 1024 * 4 +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs new file mode 100644 index 00000000000000..a0f51834d45dd0 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs @@ -0,0 +1,27 @@ +use crate::prelude::*; + +pub type clock_t = u32; +pub type wchar_t = u32; +pub type time_t = i64; +pub type suseconds_t = i32; +pub type register_t = i32; +pub type __greg_t = c_uint; +pub type __gregset_t = [crate::__greg_t; 17]; + +s! { + pub struct mcontext_t { + pub __gregs: crate::__gregset_t, + pub mc_vfp_size: usize, + pub mc_vfp_ptr: *mut c_void, + pub mc_spare: [c_uint; 33], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; + +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 4096; // 1024 * 4 +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs new file mode 100644 index 00000000000000..cd0c3e071012f5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs @@ -0,0 +1,29 @@ +use crate::off_t; +use crate::prelude::*; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u32, + pub st_lspare: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + __unused: Padding<[u8; 8]>, + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs new file mode 100644 index 00000000000000..9e80a792a8c7b3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs @@ -0,0 +1,28 @@ +use crate::off_t; +use crate::prelude::*; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u32, + pub st_lspare: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs new file mode 100644 index 00000000000000..e04fcc0cd82d3e --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs @@ -0,0 +1,330 @@ +use crate::prelude::*; + +// APIs that were changed after FreeBSD 11 + +// The type of `nlink_t` changed from `u16` to `u64` in FreeBSD 12: +pub type nlink_t = u16; +// Type of `dev_t` changed from `u32` to `u64` in FreeBSD 12: +pub type dev_t = u32; +// Type of `ino_t` changed from `__uint32_t` to `__uint64_t` in FreeBSD 12: +pub type ino_t = u32; + +s! { + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: intptr_t, + pub udata: *mut c_void, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + // Type of shm_nattc changed from `int` to `shmatt_t` (aka `unsigned + // int`) in FreeBSD 12: + pub shm_nattch: c_int, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + } + + pub struct kinfo_proc { + /// Size of this structure. + pub ki_structsize: c_int, + /// Reserved: layout identifier. + pub ki_layout: c_int, + /// Address of command arguments. + pub ki_args: *mut crate::pargs, + // This is normally "struct proc". + /// Address of proc. + pub ki_paddr: *mut c_void, + // This is normally "struct user". + /// Kernel virtual address of u-area. + pub ki_addr: *mut c_void, + // This is normally "struct vnode". + /// Pointer to trace file. + pub ki_tracep: *mut c_void, + // This is normally "struct vnode". + /// Pointer to executable file. + pub ki_textvp: *mut c_void, + /// Pointer to open file info. + pub ki_fd: *mut crate::filedesc, + // This is normally "struct vmspace". + /// Pointer to kernel vmspace struct. + pub ki_vmspace: *mut c_void, + /// Sleep address. + pub ki_wchan: *mut c_void, + /// Process identifier. + pub ki_pid: crate::pid_t, + /// Parent process ID. + pub ki_ppid: crate::pid_t, + /// Process group ID. + pub ki_pgid: crate::pid_t, + /// tty process group ID. + pub ki_tpgid: crate::pid_t, + /// Process session ID. + pub ki_sid: crate::pid_t, + /// Terminal session ID. + pub ki_tsid: crate::pid_t, + /// Job control counter. + pub ki_jobc: c_short, + /// Unused (just here for alignment). + pub ki_spare_short1: c_short, + /// Controlling tty dev. + pub ki_tdev: crate::dev_t, + /// Signals arrived but not delivered. + pub ki_siglist: crate::sigset_t, + /// Current signal mask. + pub ki_sigmask: crate::sigset_t, + /// Signals being ignored. + pub ki_sigignore: crate::sigset_t, + /// Signals being caught by user. + pub ki_sigcatch: crate::sigset_t, + /// Effective user ID. + pub ki_uid: crate::uid_t, + /// Real user ID. + pub ki_ruid: crate::uid_t, + /// Saved effective user ID. + pub ki_svuid: crate::uid_t, + /// Real group ID. + pub ki_rgid: crate::gid_t, + /// Saved effective group ID. + pub ki_svgid: crate::gid_t, + /// Number of groups. + pub ki_ngroups: c_short, + /// Unused (just here for alignment). + pub ki_spare_short2: c_short, + /// Groups. + pub ki_groups: [crate::gid_t; crate::KI_NGROUPS], + /// Virtual size. + pub ki_size: crate::vm_size_t, + /// Current resident set size in pages. + pub ki_rssize: crate::segsz_t, + /// Resident set size before last swap. + pub ki_swrss: crate::segsz_t, + /// Text size (pages) XXX. + pub ki_tsize: crate::segsz_t, + /// Data size (pages) XXX. + pub ki_dsize: crate::segsz_t, + /// Stack size (pages). + pub ki_ssize: crate::segsz_t, + /// Exit status for wait & stop signal. + pub ki_xstat: crate::u_short, + /// Accounting flags. + pub ki_acflag: crate::u_short, + /// %cpu for process during `ki_swtime`. + pub ki_pctcpu: crate::fixpt_t, + /// Time averaged value of `ki_cpticks`. + pub ki_estcpu: crate::u_int, + /// Time since last blocked. + pub ki_slptime: crate::u_int, + /// Time swapped in or out. + pub ki_swtime: crate::u_int, + /// Number of copy-on-write faults. + pub ki_cow: crate::u_int, + /// Real time in microsec. + pub ki_runtime: u64, + /// Starting time. + pub ki_start: crate::timeval, + /// Time used by process children. + pub ki_childtime: crate::timeval, + /// P_* flags. + pub ki_flag: c_long, + /// KI_* flags (below). + pub ki_kiflag: c_long, + /// Kernel trace points. + pub ki_traceflag: c_int, + /// S* process status. + pub ki_stat: c_char, + /// Process "nice" value. + pub ki_nice: i8, // signed char + /// Process lock (prevent swap) count. + pub ki_lock: c_char, + /// Run queue index. + pub ki_rqindex: c_char, + /// Which cpu we are on. + pub ki_oncpu_old: c_uchar, + /// Last cpu we were on. + pub ki_lastcpu_old: c_uchar, + /// Thread name. + pub ki_tdname: [c_char; crate::TDNAMLEN + 1], + /// Wchan message. + pub ki_wmesg: [c_char; crate::WMESGLEN + 1], + /// Setlogin name. + pub ki_login: [c_char; crate::LOGNAMELEN + 1], + /// Lock name. + pub ki_lockname: [c_char; crate::LOCKNAMELEN + 1], + /// Command name. + pub ki_comm: [c_char; crate::COMMLEN + 1], + /// Emulation name. + pub ki_emul: [c_char; crate::KI_EMULNAMELEN + 1], + /// Login class. + pub ki_loginclass: [c_char; crate::LOGINCLASSLEN + 1], + /// More thread name. + pub ki_moretdname: [c_char; crate::MAXCOMLEN - crate::TDNAMLEN + 1], + /// Spare string space. + pub ki_sparestrings: [[c_char; 23]; 2], // little hack to allow PartialEq + /// Spare room for growth. + pub ki_spareints: [c_int; crate::KI_NSPARE_INT], + /// Which cpu we are on. + pub ki_oncpu: c_int, + /// Last cpu we were on. + pub ki_lastcpu: c_int, + /// PID of tracing process. + pub ki_tracer: c_int, + /// P2_* flags. + pub ki_flag2: c_int, + /// Default FIB number. + pub ki_fibnum: c_int, + /// Credential flags. + pub ki_cr_flags: crate::u_int, + /// Process jail ID. + pub ki_jid: c_int, + /// Number of threads in total. + pub ki_numthreads: c_int, + /// Thread ID. + pub ki_tid: crate::lwpid_t, + /// Process priority. + pub ki_pri: crate::priority, + /// Process rusage statistics. + pub ki_rusage: crate::rusage, + /// rusage of children processes. + pub ki_rusage_ch: crate::rusage, + // This is normally "struct pcb". + /// Kernel virtual addr of pcb. + pub ki_pcb: *mut c_void, + /// Kernel virtual addr of stack. + pub ki_kstack: *mut c_void, + /// User convenience pointer. + pub ki_udata: *mut c_void, + // This is normally "struct thread". + pub ki_tdaddr: *mut c_void, + pub ki_spareptrs: [*mut c_void; crate::KI_NSPARE_PTR], + pub ki_sparelongs: [c_long; crate::KI_NSPARE_LONG], + /// PS_* flags. + pub ki_sflag: c_long, + /// kthread flag. + pub ki_tdflags: c_long, + } + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_reclen: u16, + pub d_type: u8, + // Type of `d_namlen` changed from `char` to `u16` in FreeBSD 12: + pub d_namlen: u8, + pub d_name: [c_char; 256], + } + + pub struct statfs { + pub f_version: u32, + pub f_type: u32, + pub f_flags: u64, + pub f_bsize: u64, + pub f_iosize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: i64, + pub f_syncwrites: u64, + pub f_asyncwrites: u64, + pub f_syncreads: u64, + pub f_asyncreads: u64, + f_spare: [u64; 10], + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_fsid: crate::fsid_t, + f_charspare: [c_char; 80], + pub f_fstypename: [c_char; 16], + // Array length changed from 88 to 1024 in FreeBSD 12: + pub f_mntfromname: [c_char; 88], + // Array length changed from 88 to 1024 in FreeBSD 12: + pub f_mntonname: [c_char; 88], + } + + pub struct vnstat { + pub vn_fileid: u64, + pub vn_size: u64, + pub vn_mntdir: *mut c_char, + pub vn_dev: u32, + pub vn_fsid: u32, + pub vn_type: c_int, + pub vn_mode: u16, + pub vn_devname: [c_char; crate::SPECNAMELEN as usize + 1], + } +} + +pub const ELAST: c_int = 96; +pub const RAND_MAX: c_int = 0x7fff_fffd; +pub const KI_NSPARE_PTR: usize = 6; +pub const MINCORE_SUPER: c_int = 0x20; +/// max length of devicename +pub const SPECNAMELEN: c_int = 63; + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + (major << 8) | minor + } + + pub const fn major(dev: crate::dev_t) -> c_int { + ((dev >> 8) & 0xff) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (dev & 0xffff00ff) as c_int + } +} + +extern "C" { + // Return type c_int was removed in FreeBSD 12 + pub fn setgrent() -> c_int; + + // Type of `addr` argument changed from `const void*` to `void*` + // in FreeBSD 12 + pub fn mprotect(addr: *const c_void, len: size_t, prot: c_int) -> c_int; + + // Return type c_int was removed in FreeBSD 12 + pub fn freelocale(loc: crate::locale_t) -> c_int; + + // Return type c_int changed to ssize_t in FreeBSD 12: + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> c_int; + + // Type of `path` argument changed from `const void*` to `void*` + // in FreeBSD 12 + pub fn dirname(path: *const c_char) -> *mut c_char; + pub fn basename(path: *const c_char) -> *mut c_char; + + // Argument order of the function pointer changed in FreeBSD 14. From 14 onwards the signature + // matches the POSIX specification by having the third argument be a mutable pointer, on + // earlier versions the first argument is the mutable pointer. + #[link_name = "qsort_r@FBSD_1.0"] + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + arg: *mut c_void, + compar: Option c_int>, + ); +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + mod b32; + pub use self::b32::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs new file mode 100644 index 00000000000000..34979f8884d790 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs @@ -0,0 +1,366 @@ +use crate::off_t; +use crate::prelude::*; + +// APIs in FreeBSD 12 that have changed since 11. + +pub type nlink_t = u64; +pub type dev_t = u64; +pub type ino_t = u64; +pub type shmatt_t = c_uint; + +s! { + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + pub ext: [u64; 4], + } + + pub struct kvm_page { + pub version: c_uint, + pub paddr: c_ulong, + pub kmap_vaddr: c_ulong, + pub dmap_vaddr: c_ulong, + pub prot: crate::vm_prot_t, + pub offset: crate::u_long, + pub len: size_t, + } + + pub struct kinfo_proc { + /// Size of this structure. + pub ki_structsize: c_int, + /// Reserved: layout identifier. + pub ki_layout: c_int, + /// Address of command arguments. + pub ki_args: *mut crate::pargs, + // This is normally "struct proc". + /// Address of proc. + pub ki_paddr: *mut c_void, + // This is normally "struct user". + /// Kernel virtual address of u-area. + pub ki_addr: *mut c_void, + // This is normally "struct vnode". + /// Pointer to trace file. + pub ki_tracep: *mut c_void, + // This is normally "struct vnode". + /// Pointer to executable file. + pub ki_textvp: *mut c_void, + /// Pointer to open file info. + pub ki_fd: *mut crate::filedesc, + // This is normally "struct vmspace". + /// Pointer to kernel vmspace struct. + pub ki_vmspace: *mut c_void, + /// Sleep address. + pub ki_wchan: *mut c_void, + /// Process identifier. + pub ki_pid: crate::pid_t, + /// Parent process ID. + pub ki_ppid: crate::pid_t, + /// Process group ID. + pub ki_pgid: crate::pid_t, + /// tty process group ID. + pub ki_tpgid: crate::pid_t, + /// Process session ID. + pub ki_sid: crate::pid_t, + /// Terminal session ID. + pub ki_tsid: crate::pid_t, + /// Job control counter. + pub ki_jobc: c_short, + /// Unused (just here for alignment). + pub ki_spare_short1: c_short, + /// Controlling tty dev. + pub ki_tdev_freebsd11: u32, + /// Signals arrived but not delivered. + pub ki_siglist: crate::sigset_t, + /// Current signal mask. + pub ki_sigmask: crate::sigset_t, + /// Signals being ignored. + pub ki_sigignore: crate::sigset_t, + /// Signals being caught by user. + pub ki_sigcatch: crate::sigset_t, + /// Effective user ID. + pub ki_uid: crate::uid_t, + /// Real user ID. + pub ki_ruid: crate::uid_t, + /// Saved effective user ID. + pub ki_svuid: crate::uid_t, + /// Real group ID. + pub ki_rgid: crate::gid_t, + /// Saved effective group ID. + pub ki_svgid: crate::gid_t, + /// Number of groups. + pub ki_ngroups: c_short, + /// Unused (just here for alignment). + pub ki_spare_short2: c_short, + /// Groups. + pub ki_groups: [crate::gid_t; crate::KI_NGROUPS], + /// Virtual size. + pub ki_size: crate::vm_size_t, + /// Current resident set size in pages. + pub ki_rssize: crate::segsz_t, + /// Resident set size before last swap. + pub ki_swrss: crate::segsz_t, + /// Text size (pages) XXX. + pub ki_tsize: crate::segsz_t, + /// Data size (pages) XXX. + pub ki_dsize: crate::segsz_t, + /// Stack size (pages). + pub ki_ssize: crate::segsz_t, + /// Exit status for wait & stop signal. + pub ki_xstat: crate::u_short, + /// Accounting flags. + pub ki_acflag: crate::u_short, + /// %cpu for process during `ki_swtime`. + pub ki_pctcpu: crate::fixpt_t, + /// Time averaged value of `ki_cpticks`. + pub ki_estcpu: crate::u_int, + /// Time since last blocked. + pub ki_slptime: crate::u_int, + /// Time swapped in or out. + pub ki_swtime: crate::u_int, + /// Number of copy-on-write faults. + pub ki_cow: crate::u_int, + /// Real time in microsec. + pub ki_runtime: u64, + /// Starting time. + pub ki_start: crate::timeval, + /// Time used by process children. + pub ki_childtime: crate::timeval, + /// P_* flags. + pub ki_flag: c_long, + /// KI_* flags (below). + pub ki_kiflag: c_long, + /// Kernel trace points. + pub ki_traceflag: c_int, + /// S* process status. + pub ki_stat: c_char, + /// Process "nice" value. + pub ki_nice: i8, // signed char + /// Process lock (prevent swap) count. + pub ki_lock: c_char, + /// Run queue index. + pub ki_rqindex: c_char, + /// Which cpu we are on. + pub ki_oncpu_old: c_uchar, + /// Last cpu we were on. + pub ki_lastcpu_old: c_uchar, + /// Thread name. + pub ki_tdname: [c_char; crate::TDNAMLEN + 1], + /// Wchan message. + pub ki_wmesg: [c_char; crate::WMESGLEN + 1], + /// Setlogin name. + pub ki_login: [c_char; crate::LOGNAMELEN + 1], + /// Lock name. + pub ki_lockname: [c_char; crate::LOCKNAMELEN + 1], + /// Command name. + pub ki_comm: [c_char; crate::COMMLEN + 1], + /// Emulation name. + pub ki_emul: [c_char; crate::KI_EMULNAMELEN + 1], + /// Login class. + pub ki_loginclass: [c_char; crate::LOGINCLASSLEN + 1], + /// More thread name. + pub ki_moretdname: [c_char; crate::MAXCOMLEN - crate::TDNAMLEN + 1], + /// Spare string space. + pub ki_sparestrings: [[c_char; 23]; 2], // little hack to allow PartialEq + /// Spare room for growth. + pub ki_spareints: [c_int; crate::KI_NSPARE_INT], + /// Controlling tty dev. + pub ki_tdev: crate::dev_t, + /// Which cpu we are on. + pub ki_oncpu: c_int, + /// Last cpu we were on. + pub ki_lastcpu: c_int, + /// PID of tracing process. + pub ki_tracer: c_int, + /// P2_* flags. + pub ki_flag2: c_int, + /// Default FIB number. + pub ki_fibnum: c_int, + /// Credential flags. + pub ki_cr_flags: crate::u_int, + /// Process jail ID. + pub ki_jid: c_int, + /// Number of threads in total. + pub ki_numthreads: c_int, + /// Thread ID. + pub ki_tid: crate::lwpid_t, + /// Process priority. + pub ki_pri: crate::priority, + /// Process rusage statistics. + pub ki_rusage: crate::rusage, + /// rusage of children processes. + pub ki_rusage_ch: crate::rusage, + // This is normally "struct pcb". + /// Kernel virtual addr of pcb. + pub ki_pcb: *mut c_void, + /// Kernel virtual addr of stack. + pub ki_kstack: *mut c_void, + /// User convenience pointer. + pub ki_udata: *mut c_void, + // This is normally "struct thread". + pub ki_tdaddr: *mut c_void, + pub ki_spareptrs: [*mut c_void; crate::KI_NSPARE_PTR], + pub ki_sparelongs: [c_long; crate::KI_NSPARE_LONG], + /// PS_* flags. + pub ki_sflag: c_long, + /// kthread flag. + pub ki_tdflags: c_long, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + st_padding0: Padding, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_padding1: Padding, + pub st_rdev: crate::dev_t, + #[cfg(target_arch = "x86")] + st_atim_ext: i32, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_mtim_ext: i32, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_ctim_ext: i32, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_btim_ext: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u64, + pub st_spare: [u64; 10], + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_type: u8, + d_pad0: Padding, + pub d_namlen: u16, + d_pad1: Padding, + pub d_name: [c_char; 256], + } + + pub struct statfs { + pub f_version: u32, + pub f_type: u32, + pub f_flags: u64, + pub f_bsize: u64, + pub f_iosize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: i64, + pub f_syncwrites: u64, + pub f_asyncwrites: u64, + pub f_syncreads: u64, + pub f_asyncreads: u64, + f_spare: [u64; 10], + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_fsid: crate::fsid_t, + f_charspare: [c_char; 80], + pub f_fstypename: [c_char; 16], + pub f_mntfromname: [c_char; 1024], + pub f_mntonname: [c_char; 1024], + } + + pub struct vnstat { + pub vn_fileid: u64, + pub vn_size: u64, + pub vn_dev: u64, + pub vn_fsid: u64, + pub vn_mntdir: *mut c_char, + pub vn_type: c_int, + pub vn_mode: u16, + pub vn_devname: [c_char; crate::SPECNAMELEN as usize + 1], + } +} + +pub const RAND_MAX: c_int = 0x7fff_fffd; +pub const ELAST: c_int = 97; + +/// max length of devicename +pub const SPECNAMELEN: c_int = 63; +pub const KI_NSPARE_PTR: usize = 6; + +pub const MINCORE_SUPER: c_int = 0x20; + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + (((dev >> 32) & 0xffffff00) | ((dev >> 8) & 0xff)) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (((dev >> 24) & 0xff00) | (dev & 0xffff00ff)) as c_int + } +} + +extern "C" { + pub fn setgrent(); + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn freelocale(loc: crate::locale_t); + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + #[link_name = "qsort_r@FBSD_1.0"] + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + arg: *mut c_void, + compar: Option c_int>, + ); +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs new file mode 100644 index 00000000000000..b29171cc509c51 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs @@ -0,0 +1,7 @@ +use crate::prelude::*; + +pub const PROC_KPTI_CTL: c_int = crate::PROC_PROCCTL_MD_MIN; +pub const PROC_KPTI_CTL_ENABLE_ON_EXEC: c_int = 1; +pub const PROC_KPTI_CTL_DISABLE_ON_EXEC: c_int = 2; +pub const PROC_KPTI_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 1; +pub const PROC_KPTI_STATUS_ACTIVE: c_int = 0x80000000; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs new file mode 100644 index 00000000000000..6ef62be3c0a2e5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs @@ -0,0 +1,410 @@ +use crate::off_t; +use crate::prelude::*; + +// APIs in FreeBSD 13 that have changed since 11. + +pub type nlink_t = u64; +pub type dev_t = u64; +pub type ino_t = u64; +pub type shmatt_t = c_uint; +pub type kpaddr_t = u64; +pub type kssize_t = i64; +pub type domainset_t = __c_anonymous_domainset; + +s! { + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + pub ext: [u64; 4], + } + + pub struct kvm_page { + pub kp_version: crate::u_int, + pub kp_paddr: crate::kpaddr_t, + pub kp_kmap_vaddr: crate::kvaddr_t, + pub kp_dmap_vaddr: crate::kvaddr_t, + pub kp_prot: crate::vm_prot_t, + pub kp_offset: off_t, + pub kp_len: size_t, + } + + pub struct __c_anonymous_domainset { + #[cfg(target_pointer_width = "64")] + _priv: [c_ulong; 4], + #[cfg(target_pointer_width = "32")] + _priv: [c_ulong; 8], + } + + pub struct kinfo_proc { + /// Size of this structure. + pub ki_structsize: c_int, + /// Reserved: layout identifier. + pub ki_layout: c_int, + /// Address of command arguments. + pub ki_args: *mut crate::pargs, + // This is normally "struct proc". + /// Address of proc. + pub ki_paddr: *mut c_void, + // This is normally "struct user". + /// Kernel virtual address of u-area. + pub ki_addr: *mut c_void, + // This is normally "struct vnode". + /// Pointer to trace file. + pub ki_tracep: *mut c_void, + // This is normally "struct vnode". + /// Pointer to executable file. + pub ki_textvp: *mut c_void, + /// Pointer to open file info. + pub ki_fd: *mut crate::filedesc, + // This is normally "struct vmspace". + /// Pointer to kernel vmspace struct. + pub ki_vmspace: *mut c_void, + /// Sleep address. + pub ki_wchan: *const c_void, + /// Process identifier. + pub ki_pid: crate::pid_t, + /// Parent process ID. + pub ki_ppid: crate::pid_t, + /// Process group ID. + pub ki_pgid: crate::pid_t, + /// tty process group ID. + pub ki_tpgid: crate::pid_t, + /// Process session ID. + pub ki_sid: crate::pid_t, + /// Terminal session ID. + pub ki_tsid: crate::pid_t, + /// Job control counter. + pub ki_jobc: c_short, + /// Unused (just here for alignment). + pub ki_spare_short1: c_short, + /// Controlling tty dev. + pub ki_tdev_freebsd11: u32, + /// Signals arrived but not delivered. + pub ki_siglist: crate::sigset_t, + /// Current signal mask. + pub ki_sigmask: crate::sigset_t, + /// Signals being ignored. + pub ki_sigignore: crate::sigset_t, + /// Signals being caught by user. + pub ki_sigcatch: crate::sigset_t, + /// Effective user ID. + pub ki_uid: crate::uid_t, + /// Real user ID. + pub ki_ruid: crate::uid_t, + /// Saved effective user ID. + pub ki_svuid: crate::uid_t, + /// Real group ID. + pub ki_rgid: crate::gid_t, + /// Saved effective group ID. + pub ki_svgid: crate::gid_t, + /// Number of groups. + pub ki_ngroups: c_short, + /// Unused (just here for alignment). + pub ki_spare_short2: c_short, + /// Groups. + pub ki_groups: [crate::gid_t; crate::KI_NGROUPS], + /// Virtual size. + pub ki_size: crate::vm_size_t, + /// Current resident set size in pages. + pub ki_rssize: crate::segsz_t, + /// Resident set size before last swap. + pub ki_swrss: crate::segsz_t, + /// Text size (pages) XXX. + pub ki_tsize: crate::segsz_t, + /// Data size (pages) XXX. + pub ki_dsize: crate::segsz_t, + /// Stack size (pages). + pub ki_ssize: crate::segsz_t, + /// Exit status for wait & stop signal. + pub ki_xstat: crate::u_short, + /// Accounting flags. + pub ki_acflag: crate::u_short, + /// %cpu for process during `ki_swtime`. + pub ki_pctcpu: crate::fixpt_t, + /// Time averaged value of `ki_cpticks`. + pub ki_estcpu: crate::u_int, + /// Time since last blocked. + pub ki_slptime: crate::u_int, + /// Time swapped in or out. + pub ki_swtime: crate::u_int, + /// Number of copy-on-write faults. + pub ki_cow: crate::u_int, + /// Real time in microsec. + pub ki_runtime: u64, + /// Starting time. + pub ki_start: crate::timeval, + /// Time used by process children. + pub ki_childtime: crate::timeval, + /// P_* flags. + pub ki_flag: c_long, + /// KI_* flags (below). + pub ki_kiflag: c_long, + /// Kernel trace points. + pub ki_traceflag: c_int, + /// S* process status. + pub ki_stat: c_char, + /// Process "nice" value. + pub ki_nice: i8, // signed char + /// Process lock (prevent swap) count. + pub ki_lock: c_char, + /// Run queue index. + pub ki_rqindex: c_char, + /// Which cpu we are on. + pub ki_oncpu_old: c_uchar, + /// Last cpu we were on. + pub ki_lastcpu_old: c_uchar, + /// Thread name. + pub ki_tdname: [c_char; crate::TDNAMLEN + 1], + /// Wchan message. + pub ki_wmesg: [c_char; crate::WMESGLEN + 1], + /// Setlogin name. + pub ki_login: [c_char; crate::LOGNAMELEN + 1], + /// Lock name. + pub ki_lockname: [c_char; crate::LOCKNAMELEN + 1], + /// Command name. + pub ki_comm: [c_char; crate::COMMLEN + 1], + /// Emulation name. + pub ki_emul: [c_char; crate::KI_EMULNAMELEN + 1], + /// Login class. + pub ki_loginclass: [c_char; crate::LOGINCLASSLEN + 1], + /// More thread name. + pub ki_moretdname: [c_char; crate::MAXCOMLEN - crate::TDNAMLEN + 1], + /// Spare string space. + pub ki_sparestrings: [[c_char; 23]; 2], // little hack to allow PartialEq + /// Spare room for growth. + pub ki_spareints: [c_int; crate::KI_NSPARE_INT], + /// Controlling tty dev. + pub ki_tdev: u64, + /// Which cpu we are on. + pub ki_oncpu: c_int, + /// Last cpu we were on. + pub ki_lastcpu: c_int, + /// PID of tracing process. + pub ki_tracer: c_int, + /// P2_* flags. + pub ki_flag2: c_int, + /// Default FIB number. + pub ki_fibnum: c_int, + /// Credential flags. + pub ki_cr_flags: crate::u_int, + /// Process jail ID. + pub ki_jid: c_int, + /// Number of threads in total. + pub ki_numthreads: c_int, + /// Thread ID. + pub ki_tid: crate::lwpid_t, + /// Process priority. + pub ki_pri: crate::priority, + /// Process rusage statistics. + pub ki_rusage: crate::rusage, + /// rusage of children processes. + pub ki_rusage_ch: crate::rusage, + // This is normally "struct pcb". + /// Kernel virtual addr of pcb. + pub ki_pcb: *mut c_void, + /// Kernel virtual addr of stack. + pub ki_kstack: *mut c_void, + /// User convenience pointer. + pub ki_udata: *mut c_void, + // This is normally "struct thread". + pub ki_tdaddr: *mut c_void, + // This is normally "struct pwddesc". + /// Pointer to process paths info. + pub ki_pd: *mut c_void, + pub ki_spareptrs: [*mut c_void; crate::KI_NSPARE_PTR], + pub ki_sparelongs: [c_long; crate::KI_NSPARE_LONG], + /// PS_* flags. + pub ki_sflag: c_long, + /// kthread flag. + pub ki_tdflags: c_long, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + st_padding0: Padding, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_padding1: Padding, + pub st_rdev: crate::dev_t, + #[cfg(target_arch = "x86")] + st_atim_ext: i32, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_mtim_ext: i32, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_ctim_ext: i32, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_btim_ext: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u64, + pub st_spare: [u64; 10], + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_type: u8, + d_pad0: Padding, + pub d_namlen: u16, + d_pad1: Padding, + pub d_name: [c_char; 256], + } + + pub struct statfs { + pub f_version: u32, + pub f_type: u32, + pub f_flags: u64, + pub f_bsize: u64, + pub f_iosize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: i64, + pub f_syncwrites: u64, + pub f_asyncwrites: u64, + pub f_syncreads: u64, + pub f_asyncreads: u64, + f_spare: [u64; 10], + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_fsid: crate::fsid_t, + f_charspare: [c_char; 80], + pub f_fstypename: [c_char; 16], + pub f_mntfromname: [c_char; 1024], + pub f_mntonname: [c_char; 1024], + } + + pub struct vnstat { + pub vn_fileid: u64, + pub vn_size: u64, + pub vn_dev: u64, + pub vn_fsid: u64, + pub vn_mntdir: *mut c_char, + pub vn_type: c_int, + pub vn_mode: u16, + pub vn_devname: [c_char; crate::SPECNAMELEN as usize + 1], + } +} + +pub const RAND_MAX: c_int = 0x7fff_ffff; +pub const ELAST: c_int = 97; + +pub const KF_TYPE_EVENTFD: c_int = 13; + +/// max length of devicename +pub const SPECNAMELEN: c_int = 255; +pub const KI_NSPARE_PTR: usize = 5; + +/// domainset policies +pub const DOMAINSET_POLICY_INVALID: c_int = 0; +pub const DOMAINSET_POLICY_ROUNDROBIN: c_int = 1; +pub const DOMAINSET_POLICY_FIRSTTOUCH: c_int = 2; +pub const DOMAINSET_POLICY_PREFER: c_int = 3; +pub const DOMAINSET_POLICY_INTERLEAVE: c_int = 4; + +pub const MINCORE_SUPER: c_int = 0x20; + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + (((dev >> 32) & 0xffffff00) | ((dev >> 8) & 0xff)) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (((dev >> 24) & 0xff00) | (dev & 0xffff00ff)) as c_int + } +} + +extern "C" { + pub fn setgrent(); + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn freelocale(loc: crate::locale_t); + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + + pub fn cpuset_getdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *mut crate::domainset_t, + policy: *mut c_int, + ) -> c_int; + pub fn cpuset_setdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *const crate::domainset_t, + policy: c_int, + ) -> c_int; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + #[link_name = "qsort_r@FBSD_1.0"] + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + arg: *mut c_void, + compar: Option c_int>, + ); +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_kerndisp(kd: *mut crate::kvm_t) -> crate::kssize_t; +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs new file mode 100644 index 00000000000000..b29171cc509c51 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs @@ -0,0 +1,7 @@ +use crate::prelude::*; + +pub const PROC_KPTI_CTL: c_int = crate::PROC_PROCCTL_MD_MIN; +pub const PROC_KPTI_CTL_ENABLE_ON_EXEC: c_int = 1; +pub const PROC_KPTI_CTL_DISABLE_ON_EXEC: c_int = 2; +pub const PROC_KPTI_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 1; +pub const PROC_KPTI_STATUS_ACTIVE: c_int = 0x80000000; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs new file mode 100644 index 00000000000000..f2753cebcec9f5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs @@ -0,0 +1,411 @@ +use crate::off_t; +use crate::prelude::*; + +// APIs in FreeBSD 14 that have changed since 11. + +pub type nlink_t = u64; +pub type dev_t = u64; +pub type ino_t = u64; +pub type shmatt_t = c_uint; +pub type kpaddr_t = u64; +pub type kssize_t = i64; +pub type domainset_t = __c_anonymous_domainset; + +s! { + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + pub ext: [u64; 4], + } + + pub struct kvm_page { + pub kp_version: crate::u_int, + pub kp_paddr: crate::kpaddr_t, + pub kp_kmap_vaddr: crate::kvaddr_t, + pub kp_dmap_vaddr: crate::kvaddr_t, + pub kp_prot: crate::vm_prot_t, + pub kp_offset: off_t, + pub kp_len: size_t, + } + + pub struct __c_anonymous_domainset { + #[cfg(target_pointer_width = "64")] + _priv: [c_ulong; 4], + #[cfg(target_pointer_width = "32")] + _priv: [c_ulong; 8], + } + + pub struct kinfo_proc { + /// Size of this structure. + pub ki_structsize: c_int, + /// Reserved: layout identifier. + pub ki_layout: c_int, + /// Address of command arguments. + pub ki_args: *mut crate::pargs, + // This is normally "struct proc". + /// Address of proc. + pub ki_paddr: *mut c_void, + // This is normally "struct user". + /// Kernel virtual address of u-area. + pub ki_addr: *mut c_void, + // This is normally "struct vnode". + /// Pointer to trace file. + pub ki_tracep: *mut c_void, + // This is normally "struct vnode". + /// Pointer to executable file. + pub ki_textvp: *mut c_void, + /// Pointer to open file info. + pub ki_fd: *mut crate::filedesc, + // This is normally "struct vmspace". + /// Pointer to kernel vmspace struct. + pub ki_vmspace: *mut c_void, + /// Sleep address. + pub ki_wchan: *const c_void, + /// Process identifier. + pub ki_pid: crate::pid_t, + /// Parent process ID. + pub ki_ppid: crate::pid_t, + /// Process group ID. + pub ki_pgid: crate::pid_t, + /// tty process group ID. + pub ki_tpgid: crate::pid_t, + /// Process session ID. + pub ki_sid: crate::pid_t, + /// Terminal session ID. + pub ki_tsid: crate::pid_t, + /// Job control counter. + pub ki_jobc: c_short, + /// Unused (just here for alignment). + pub ki_spare_short1: c_short, + /// Controlling tty dev. + pub ki_tdev_freebsd11: u32, + /// Signals arrived but not delivered. + pub ki_siglist: crate::sigset_t, + /// Current signal mask. + pub ki_sigmask: crate::sigset_t, + /// Signals being ignored. + pub ki_sigignore: crate::sigset_t, + /// Signals being caught by user. + pub ki_sigcatch: crate::sigset_t, + /// Effective user ID. + pub ki_uid: crate::uid_t, + /// Real user ID. + pub ki_ruid: crate::uid_t, + /// Saved effective user ID. + pub ki_svuid: crate::uid_t, + /// Real group ID. + pub ki_rgid: crate::gid_t, + /// Saved effective group ID. + pub ki_svgid: crate::gid_t, + /// Number of groups. + pub ki_ngroups: c_short, + /// Unused (just here for alignment). + pub ki_spare_short2: c_short, + /// Groups. + pub ki_groups: [crate::gid_t; crate::KI_NGROUPS], + /// Virtual size. + pub ki_size: crate::vm_size_t, + /// Current resident set size in pages. + pub ki_rssize: crate::segsz_t, + /// Resident set size before last swap. + pub ki_swrss: crate::segsz_t, + /// Text size (pages) XXX. + pub ki_tsize: crate::segsz_t, + /// Data size (pages) XXX. + pub ki_dsize: crate::segsz_t, + /// Stack size (pages). + pub ki_ssize: crate::segsz_t, + /// Exit status for wait & stop signal. + pub ki_xstat: crate::u_short, + /// Accounting flags. + pub ki_acflag: crate::u_short, + /// %cpu for process during `ki_swtime`. + pub ki_pctcpu: crate::fixpt_t, + /// Time averaged value of `ki_cpticks`. + pub ki_estcpu: crate::u_int, + /// Time since last blocked. + pub ki_slptime: crate::u_int, + /// Time swapped in or out. + pub ki_swtime: crate::u_int, + /// Number of copy-on-write faults. + pub ki_cow: crate::u_int, + /// Real time in microsec. + pub ki_runtime: u64, + /// Starting time. + pub ki_start: crate::timeval, + /// Time used by process children. + pub ki_childtime: crate::timeval, + /// P_* flags. + pub ki_flag: c_long, + /// KI_* flags (below). + pub ki_kiflag: c_long, + /// Kernel trace points. + pub ki_traceflag: c_int, + /// S* process status. + pub ki_stat: c_char, + /// Process "nice" value. + pub ki_nice: i8, // signed char + /// Process lock (prevent swap) count. + pub ki_lock: c_char, + /// Run queue index. + pub ki_rqindex: c_char, + /// Which cpu we are on. + pub ki_oncpu_old: c_uchar, + /// Last cpu we were on. + pub ki_lastcpu_old: c_uchar, + /// Thread name. + pub ki_tdname: [c_char; crate::TDNAMLEN + 1], + /// Wchan message. + pub ki_wmesg: [c_char; crate::WMESGLEN + 1], + /// Setlogin name. + pub ki_login: [c_char; crate::LOGNAMELEN + 1], + /// Lock name. + pub ki_lockname: [c_char; crate::LOCKNAMELEN + 1], + /// Command name. + pub ki_comm: [c_char; crate::COMMLEN + 1], + /// Emulation name. + pub ki_emul: [c_char; crate::KI_EMULNAMELEN + 1], + /// Login class. + pub ki_loginclass: [c_char; crate::LOGINCLASSLEN + 1], + /// More thread name. + pub ki_moretdname: [c_char; crate::MAXCOMLEN - crate::TDNAMLEN + 1], + /// Spare string space. + pub ki_sparestrings: [[c_char; 23]; 2], // little hack to allow PartialEq + /// Spare room for growth. + pub ki_spareints: [c_int; crate::KI_NSPARE_INT], + /// Controlling tty dev. + pub ki_tdev: u64, + /// Which cpu we are on. + pub ki_oncpu: c_int, + /// Last cpu we were on. + pub ki_lastcpu: c_int, + /// PID of tracing process. + pub ki_tracer: c_int, + /// P2_* flags. + pub ki_flag2: c_int, + /// Default FIB number. + pub ki_fibnum: c_int, + /// Credential flags. + pub ki_cr_flags: crate::u_int, + /// Process jail ID. + pub ki_jid: c_int, + /// Number of threads in total. + pub ki_numthreads: c_int, + /// Thread ID. + pub ki_tid: crate::lwpid_t, + /// Process priority. + pub ki_pri: crate::priority, + /// Process rusage statistics. + pub ki_rusage: crate::rusage, + /// rusage of children processes. + pub ki_rusage_ch: crate::rusage, + // This is normally "struct pcb". + /// Kernel virtual addr of pcb. + pub ki_pcb: *mut c_void, + /// Kernel virtual addr of stack. + pub ki_kstack: *mut c_void, + /// User convenience pointer. + pub ki_udata: *mut c_void, + // This is normally "struct thread". + pub ki_tdaddr: *mut c_void, + // This is normally "struct pwddesc". + /// Pointer to process paths info. + pub ki_pd: *mut c_void, + pub ki_spareptrs: [*mut c_void; crate::KI_NSPARE_PTR], + pub ki_sparelongs: [c_long; crate::KI_NSPARE_LONG], + /// PS_* flags. + pub ki_sflag: c_long, + /// kthread flag. + pub ki_tdflags: c_long, + } + + #[non_exhaustive] + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + st_padding0: Padding, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_padding1: Padding, + pub st_rdev: crate::dev_t, + #[cfg(target_arch = "x86")] + st_atim_ext: i32, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_mtim_ext: i32, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_ctim_ext: i32, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_btim_ext: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u64, + pub st_filerev: u64, + pub st_spare: [u64; 9], + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_type: u8, + d_pad0: Padding, + pub d_namlen: u16, + d_pad1: Padding, + pub d_name: [c_char; 256], + } + + pub struct statfs { + pub f_version: u32, + pub f_type: u32, + pub f_flags: u64, + pub f_bsize: u64, + pub f_iosize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: i64, + pub f_syncwrites: u64, + pub f_asyncwrites: u64, + pub f_syncreads: u64, + pub f_asyncreads: u64, + f_spare: [u64; 10], + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_fsid: crate::fsid_t, + f_charspare: [c_char; 80], + pub f_fstypename: [c_char; 16], + pub f_mntfromname: [c_char; 1024], + pub f_mntonname: [c_char; 1024], + } + + pub struct vnstat { + pub vn_fileid: u64, + pub vn_size: u64, + pub vn_dev: u64, + pub vn_fsid: u64, + pub vn_mntdir: *mut c_char, + pub vn_type: c_int, + pub vn_mode: u16, + pub vn_devname: [c_char; crate::SPECNAMELEN as usize + 1], + } +} + +pub const RAND_MAX: c_int = 0x7fff_ffff; +pub const ELAST: c_int = 97; + +pub const KF_TYPE_EVENTFD: c_int = 13; + +/// max length of devicename +pub const SPECNAMELEN: c_int = 255; +pub const KI_NSPARE_PTR: usize = 5; + +/// domainset policies +pub const DOMAINSET_POLICY_INVALID: c_int = 0; +pub const DOMAINSET_POLICY_ROUNDROBIN: c_int = 1; +pub const DOMAINSET_POLICY_FIRSTTOUCH: c_int = 2; +pub const DOMAINSET_POLICY_PREFER: c_int = 3; +pub const DOMAINSET_POLICY_INTERLEAVE: c_int = 4; + +pub const MINCORE_SUPER: c_int = 0x60; + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + (((dev >> 32) & 0xffffff00) | ((dev >> 8) & 0xff)) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (((dev >> 24) & 0xff00) | (dev & 0xffff00ff)) as c_int + } +} + +extern "C" { + pub fn setgrent(); + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn freelocale(loc: crate::locale_t); + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + + pub fn cpuset_getdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *mut crate::domainset_t, + policy: *mut c_int, + ) -> c_int; + pub fn cpuset_setdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *const crate::domainset_t, + policy: c_int, + ) -> c_int; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_kerndisp(kd: *mut crate::kvm_t) -> crate::kssize_t; +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs new file mode 100644 index 00000000000000..3e037471fbf68b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs @@ -0,0 +1,14 @@ +use crate::prelude::*; + +pub const PROC_KPTI_CTL: c_int = crate::PROC_PROCCTL_MD_MIN; +pub const PROC_KPTI_CTL_ENABLE_ON_EXEC: c_int = 1; +pub const PROC_KPTI_CTL_DISABLE_ON_EXEC: c_int = 2; +pub const PROC_KPTI_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 1; +pub const PROC_KPTI_STATUS_ACTIVE: c_int = 0x80000000; +pub const PROC_LA_CTL: c_int = crate::PROC_PROCCTL_MD_MIN + 2; +pub const PROC_LA_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 3; +pub const PROC_LA_CTL_LA48_ON_EXEC: c_int = 1; +pub const PROC_LA_CTL_LA57_ON_EXEC: c_int = 2; +pub const PROC_LA_CTL_DEFAULT_ON_EXEC: c_int = 3; +pub const PROC_LA_STATUS_LA48: c_int = 0x01000000; +pub const PROC_LA_STATUS_LA57: c_int = 0x02000000; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs new file mode 100644 index 00000000000000..d9d93687850c3b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs @@ -0,0 +1,413 @@ +use crate::off_t; +use crate::prelude::*; + +// APIs in FreeBSD 15 that have changed since 11. + +pub type nlink_t = u64; +pub type dev_t = u64; +pub type ino_t = u64; +pub type shmatt_t = c_uint; +pub type kpaddr_t = u64; +pub type kssize_t = i64; +pub type domainset_t = __c_anonymous_domainset; + +s! { + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + pub ext: [u64; 4], + } + + pub struct kvm_page { + pub kp_version: crate::u_int, + pub kp_paddr: crate::kpaddr_t, + pub kp_kmap_vaddr: crate::kvaddr_t, + pub kp_dmap_vaddr: crate::kvaddr_t, + pub kp_prot: crate::vm_prot_t, + pub kp_offset: off_t, + pub kp_len: size_t, + } + + pub struct __c_anonymous_domainset { + #[cfg(target_pointer_width = "64")] + _priv: [c_ulong; 4], + #[cfg(target_pointer_width = "32")] + _priv: [c_ulong; 8], + } + + #[non_exhaustive] + pub struct kinfo_proc { + /// Size of this structure. + pub ki_structsize: c_int, + /// Reserved: layout identifier. + pub ki_layout: c_int, + /// Address of command arguments. + pub ki_args: *mut crate::pargs, + // This is normally "struct proc". + /// Address of proc. + pub ki_paddr: *mut c_void, + // This is normally "struct user". + /// Kernel virtual address of u-area. + pub ki_addr: *mut c_void, + // This is normally "struct vnode". + /// Pointer to trace file. + pub ki_tracep: *mut c_void, + // This is normally "struct vnode". + /// Pointer to executable file. + pub ki_textvp: *mut c_void, + /// Pointer to open file info. + pub ki_fd: *mut crate::filedesc, + // This is normally "struct vmspace". + /// Pointer to kernel vmspace struct. + pub ki_vmspace: *mut c_void, + /// Sleep address. + pub ki_wchan: *const c_void, + /// Process identifier. + pub ki_pid: crate::pid_t, + /// Parent process ID. + pub ki_ppid: crate::pid_t, + /// Process group ID. + pub ki_pgid: crate::pid_t, + /// tty process group ID. + pub ki_tpgid: crate::pid_t, + /// Process session ID. + pub ki_sid: crate::pid_t, + /// Terminal session ID. + pub ki_tsid: crate::pid_t, + /// Job control counter. + pub ki_jobc: c_short, + /// Unused (just here for alignment). + pub ki_spare_short1: c_short, + /// Controlling tty dev. + pub ki_tdev_freebsd11: u32, + /// Signals arrived but not delivered. + pub ki_siglist: crate::sigset_t, + /// Current signal mask. + pub ki_sigmask: crate::sigset_t, + /// Signals being ignored. + pub ki_sigignore: crate::sigset_t, + /// Signals being caught by user. + pub ki_sigcatch: crate::sigset_t, + /// Effective user ID. + pub ki_uid: crate::uid_t, + /// Real user ID. + pub ki_ruid: crate::uid_t, + /// Saved effective user ID. + pub ki_svuid: crate::uid_t, + /// Real group ID. + pub ki_rgid: crate::gid_t, + /// Saved effective group ID. + pub ki_svgid: crate::gid_t, + /// Number of groups. + pub ki_ngroups: c_short, + /// Unused (just here for alignment). + pub ki_spare_short2: c_short, + /// Groups. + pub ki_groups: [crate::gid_t; crate::KI_NGROUPS], + /// Virtual size. + pub ki_size: crate::vm_size_t, + /// Current resident set size in pages. + pub ki_rssize: crate::segsz_t, + /// Resident set size before last swap. + pub ki_swrss: crate::segsz_t, + /// Text size (pages) XXX. + pub ki_tsize: crate::segsz_t, + /// Data size (pages) XXX. + pub ki_dsize: crate::segsz_t, + /// Stack size (pages). + pub ki_ssize: crate::segsz_t, + /// Exit status for wait & stop signal. + pub ki_xstat: crate::u_short, + /// Accounting flags. + pub ki_acflag: crate::u_short, + /// %cpu for process during `ki_swtime`. + pub ki_pctcpu: crate::fixpt_t, + /// Time averaged value of `ki_cpticks`. + pub ki_estcpu: crate::u_int, + /// Time since last blocked. + pub ki_slptime: crate::u_int, + /// Time swapped in or out. + pub ki_swtime: crate::u_int, + /// Number of copy-on-write faults. + pub ki_cow: crate::u_int, + /// Real time in microsec. + pub ki_runtime: u64, + /// Starting time. + pub ki_start: crate::timeval, + /// Time used by process children. + pub ki_childtime: crate::timeval, + /// P_* flags. + pub ki_flag: c_long, + /// KI_* flags (below). + pub ki_kiflag: c_long, + /// Kernel trace points. + pub ki_traceflag: c_int, + /// S* process status. + pub ki_stat: c_char, + /// Process "nice" value. + pub ki_nice: i8, // signed char + /// Process lock (prevent swap) count. + pub ki_lock: c_char, + /// Run queue index. + pub ki_rqindex: c_char, + /// Which cpu we are on. + pub ki_oncpu_old: c_uchar, + /// Last cpu we were on. + pub ki_lastcpu_old: c_uchar, + /// Thread name. + pub ki_tdname: [c_char; crate::TDNAMLEN + 1], + /// Wchan message. + pub ki_wmesg: [c_char; crate::WMESGLEN + 1], + /// Setlogin name. + pub ki_login: [c_char; crate::LOGNAMELEN + 1], + /// Lock name. + pub ki_lockname: [c_char; crate::LOCKNAMELEN + 1], + /// Command name. + pub ki_comm: [c_char; crate::COMMLEN + 1], + /// Emulation name. + pub ki_emul: [c_char; crate::KI_EMULNAMELEN + 1], + /// Login class. + pub ki_loginclass: [c_char; crate::LOGINCLASSLEN + 1], + /// More thread name. + pub ki_moretdname: [c_char; crate::MAXCOMLEN - crate::TDNAMLEN + 1], + /// Spare string space. + pub ki_sparestrings: [[c_char; 23]; 2], // little hack to allow PartialEq + /// Spare room for growth. + pub ki_spareints: [c_int; crate::KI_NSPARE_INT], + /// Controlling tty dev. + pub ki_tdev: u64, + /// Which cpu we are on. + pub ki_oncpu: c_int, + /// Last cpu we were on. + pub ki_lastcpu: c_int, + /// PID of tracing process. + pub ki_tracer: c_int, + /// P2_* flags. + pub ki_flag2: c_int, + /// Default FIB number. + pub ki_fibnum: c_int, + /// Credential flags. + pub ki_cr_flags: crate::u_int, + /// Process jail ID. + pub ki_jid: c_int, + /// Number of threads in total. + pub ki_numthreads: c_int, + /// Thread ID. + pub ki_tid: crate::lwpid_t, + /// Process priority. + pub ki_pri: crate::priority, + /// Process rusage statistics. + pub ki_rusage: crate::rusage, + /// rusage of children processes. + pub ki_rusage_ch: crate::rusage, + // This is normally "struct pcb". + /// Kernel virtual addr of pcb. + pub ki_pcb: *mut c_void, + /// Kernel virtual addr of stack. + pub ki_kstack: *mut c_void, + /// User convenience pointer. + pub ki_udata: *mut c_void, + // This is normally "struct thread". + pub ki_tdaddr: *mut c_void, + // This is normally "struct pwddesc". + /// Pointer to process paths info. + pub ki_pd: *mut c_void, + /// Address of the ext err msg place + pub ki_uerrmsg: *mut c_void, + pub ki_spareptrs: [*mut c_void; crate::KI_NSPARE_PTR], + pub ki_sparelongs: [c_long; crate::KI_NSPARE_LONG], + /// PS_* flags. + pub ki_sflag: c_long, + /// kthread flag. + pub ki_tdflags: c_long, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + st_padding0: Padding, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_padding1: Padding, + pub st_rdev: crate::dev_t, + #[cfg(target_arch = "x86")] + st_atim_ext: i32, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_mtim_ext: i32, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_ctim_ext: i32, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(target_arch = "x86")] + st_btim_ext: i32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: crate::fflags_t, + pub st_gen: u64, + pub st_filerev: u64, + pub st_spare: [u64; 9], + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_type: u8, + d_pad0: Padding, + pub d_namlen: u16, + d_pad1: Padding, + pub d_name: [c_char; 256], + } + + pub struct statfs { + pub f_version: u32, + pub f_type: u32, + pub f_flags: u64, + pub f_bsize: u64, + pub f_iosize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: i64, + pub f_syncwrites: u64, + pub f_asyncwrites: u64, + pub f_syncreads: u64, + pub f_asyncreads: u64, + f_spare: [u64; 10], + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_fsid: crate::fsid_t, + f_charspare: [c_char; 80], + pub f_fstypename: [c_char; 16], + pub f_mntfromname: [c_char; 1024], + pub f_mntonname: [c_char; 1024], + } + + pub struct vnstat { + pub vn_fileid: u64, + pub vn_size: u64, + pub vn_dev: u64, + pub vn_fsid: u64, + pub vn_mntdir: *mut c_char, + pub vn_type: c_int, + pub vn_mode: u16, + pub vn_devname: [c_char; crate::SPECNAMELEN as usize + 1], + } +} + +pub const RAND_MAX: c_int = 0x7fff_ffff; +pub const ELAST: c_int = 97; + +pub const KF_TYPE_EVENTFD: c_int = 13; + +/// max length of devicename +pub const SPECNAMELEN: c_int = 255; +pub const KI_NSPARE_PTR: usize = 4; + +/// domainset policies +pub const DOMAINSET_POLICY_INVALID: c_int = 0; +pub const DOMAINSET_POLICY_ROUNDROBIN: c_int = 1; +pub const DOMAINSET_POLICY_FIRSTTOUCH: c_int = 2; +pub const DOMAINSET_POLICY_PREFER: c_int = 3; +pub const DOMAINSET_POLICY_INTERLEAVE: c_int = 4; + +pub const MINCORE_SUPER: c_int = 0x60; + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + (((dev >> 32) & 0xffffff00) | ((dev >> 8) & 0xff)) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + (((dev >> 24) & 0xff00) | (dev & 0xffff00ff)) as c_int + } +} + +extern "C" { + pub fn setgrent(); + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn freelocale(loc: crate::locale_t); + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + + pub fn cpuset_getdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *mut crate::domainset_t, + policy: *mut c_int, + ) -> c_int; + pub fn cpuset_setdomain( + level: crate::cpulevel_t, + which: crate::cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *const crate::domainset_t, + policy: c_int, + ) -> c_int; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_kerndisp(kd: *mut crate::kvm_t) -> crate::kssize_t; +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs new file mode 100644 index 00000000000000..3e037471fbf68b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs @@ -0,0 +1,14 @@ +use crate::prelude::*; + +pub const PROC_KPTI_CTL: c_int = crate::PROC_PROCCTL_MD_MIN; +pub const PROC_KPTI_CTL_ENABLE_ON_EXEC: c_int = 1; +pub const PROC_KPTI_CTL_DISABLE_ON_EXEC: c_int = 2; +pub const PROC_KPTI_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 1; +pub const PROC_KPTI_STATUS_ACTIVE: c_int = 0x80000000; +pub const PROC_LA_CTL: c_int = crate::PROC_PROCCTL_MD_MIN + 2; +pub const PROC_LA_STATUS: c_int = crate::PROC_PROCCTL_MD_MIN + 3; +pub const PROC_LA_CTL_LA48_ON_EXEC: c_int = 1; +pub const PROC_LA_CTL_LA57_ON_EXEC: c_int = 2; +pub const PROC_LA_CTL_DEFAULT_ON_EXEC: c_int = 3; +pub const PROC_LA_STATUS_LA48: c_int = 0x01000000; +pub const PROC_LA_STATUS_LA57: c_int = 0x02000000; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs new file mode 100644 index 00000000000000..233026cc783721 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -0,0 +1,5189 @@ +use crate::prelude::*; +use crate::{ + cmsghdr, + off_t, +}; + +pub type fflags_t = u32; + +pub type vm_prot_t = u_char; +pub type kvaddr_t = u64; +pub type segsz_t = isize; +pub type __fixpt_t = u32; +pub type fixpt_t = __fixpt_t; +pub type __lwpid_t = i32; +pub type lwpid_t = __lwpid_t; +pub type blksize_t = i32; +pub type ksize_t = u64; +pub type inp_gen_t = u64; +pub type so_gen_t = u64; +pub type clockid_t = c_int; +pub type sem_t = _sem; +pub type timer_t = *mut __c_anonymous__timer; + +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type idtype_t = c_uint; + +pub type msglen_t = c_ulong; +pub type msgqnum_t = c_ulong; + +pub type cpulevel_t = c_int; +pub type cpuwhich_t = c_int; + +pub type mqd_t = *mut c_void; + +pub type pthread_spinlock_t = *mut __c_anonymous_pthread_spinlock; +pub type pthread_barrierattr_t = *mut __c_anonymous_pthread_barrierattr; +pub type pthread_barrier_t = *mut __c_anonymous_pthread_barrier; + +pub type uuid_t = crate::uuid; +pub type u_int = c_uint; +pub type u_char = c_uchar; +pub type u_long = c_ulong; +pub type u_short = c_ushort; + +pub type caddr_t = *mut c_char; + +pub type fhandle_t = fhandle; + +pub type au_id_t = crate::uid_t; +pub type au_asid_t = crate::pid_t; + +pub type cpusetid_t = c_int; + +pub type sctp_assoc_t = u32; + +pub type eventfd_t = u64; + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_support_flags { + DEVSTAT_ALL_SUPPORTED = 0x00, + DEVSTAT_NO_BLOCKSIZE = 0x01, + DEVSTAT_NO_ORDERED_TAGS = 0x02, + DEVSTAT_BS_UNAVAILABLE = 0x04, +} +impl Copy for devstat_support_flags {} +impl Clone for devstat_support_flags { + fn clone(&self) -> devstat_support_flags { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_trans_flags { + DEVSTAT_NO_DATA = 0x00, + DEVSTAT_READ = 0x01, + DEVSTAT_WRITE = 0x02, + DEVSTAT_FREE = 0x03, +} + +impl Copy for devstat_trans_flags {} +impl Clone for devstat_trans_flags { + fn clone(&self) -> devstat_trans_flags { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_tag_type { + DEVSTAT_TAG_SIMPLE = 0x00, + DEVSTAT_TAG_HEAD = 0x01, + DEVSTAT_TAG_ORDERED = 0x02, + DEVSTAT_TAG_NONE = 0x03, +} +impl Copy for devstat_tag_type {} +impl Clone for devstat_tag_type { + fn clone(&self) -> devstat_tag_type { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_match_flags { + DEVSTAT_MATCH_NONE = 0x00, + DEVSTAT_MATCH_TYPE = 0x01, + DEVSTAT_MATCH_IF = 0x02, + DEVSTAT_MATCH_PASS = 0x04, +} +impl Copy for devstat_match_flags {} +impl Clone for devstat_match_flags { + fn clone(&self) -> devstat_match_flags { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_priority { + DEVSTAT_PRIORITY_MIN = 0x000, + DEVSTAT_PRIORITY_OTHER = 0x020, + DEVSTAT_PRIORITY_PASS = 0x030, + DEVSTAT_PRIORITY_FD = 0x040, + DEVSTAT_PRIORITY_WFD = 0x050, + DEVSTAT_PRIORITY_TAPE = 0x060, + DEVSTAT_PRIORITY_CD = 0x090, + DEVSTAT_PRIORITY_DISK = 0x110, + DEVSTAT_PRIORITY_ARRAY = 0x120, + DEVSTAT_PRIORITY_MAX = 0xfff, +} +impl Copy for devstat_priority {} +impl Clone for devstat_priority { + fn clone(&self) -> devstat_priority { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_type_flags { + DEVSTAT_TYPE_DIRECT = 0x000, + DEVSTAT_TYPE_SEQUENTIAL = 0x001, + DEVSTAT_TYPE_PRINTER = 0x002, + DEVSTAT_TYPE_PROCESSOR = 0x003, + DEVSTAT_TYPE_WORM = 0x004, + DEVSTAT_TYPE_CDROM = 0x005, + DEVSTAT_TYPE_SCANNER = 0x006, + DEVSTAT_TYPE_OPTICAL = 0x007, + DEVSTAT_TYPE_CHANGER = 0x008, + DEVSTAT_TYPE_COMM = 0x009, + DEVSTAT_TYPE_ASC0 = 0x00a, + DEVSTAT_TYPE_ASC1 = 0x00b, + DEVSTAT_TYPE_STORARRAY = 0x00c, + DEVSTAT_TYPE_ENCLOSURE = 0x00d, + DEVSTAT_TYPE_FLOPPY = 0x00e, + DEVSTAT_TYPE_MASK = 0x00f, + DEVSTAT_TYPE_IF_SCSI = 0x010, + DEVSTAT_TYPE_IF_IDE = 0x020, + DEVSTAT_TYPE_IF_OTHER = 0x030, + DEVSTAT_TYPE_IF_MASK = 0x0f0, + DEVSTAT_TYPE_PASS = 0x100, +} +impl Copy for devstat_type_flags {} +impl Clone for devstat_type_flags { + fn clone(&self) -> devstat_type_flags { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_metric { + DSM_NONE, + DSM_TOTAL_BYTES, + DSM_TOTAL_BYTES_READ, + DSM_TOTAL_BYTES_WRITE, + DSM_TOTAL_TRANSFERS, + DSM_TOTAL_TRANSFERS_READ, + DSM_TOTAL_TRANSFERS_WRITE, + DSM_TOTAL_TRANSFERS_OTHER, + DSM_TOTAL_BLOCKS, + DSM_TOTAL_BLOCKS_READ, + DSM_TOTAL_BLOCKS_WRITE, + DSM_KB_PER_TRANSFER, + DSM_KB_PER_TRANSFER_READ, + DSM_KB_PER_TRANSFER_WRITE, + DSM_TRANSFERS_PER_SECOND, + DSM_TRANSFERS_PER_SECOND_READ, + DSM_TRANSFERS_PER_SECOND_WRITE, + DSM_TRANSFERS_PER_SECOND_OTHER, + DSM_MB_PER_SECOND, + DSM_MB_PER_SECOND_READ, + DSM_MB_PER_SECOND_WRITE, + DSM_BLOCKS_PER_SECOND, + DSM_BLOCKS_PER_SECOND_READ, + DSM_BLOCKS_PER_SECOND_WRITE, + DSM_MS_PER_TRANSACTION, + DSM_MS_PER_TRANSACTION_READ, + DSM_MS_PER_TRANSACTION_WRITE, + DSM_SKIP, + DSM_TOTAL_BYTES_FREE, + DSM_TOTAL_TRANSFERS_FREE, + DSM_TOTAL_BLOCKS_FREE, + DSM_KB_PER_TRANSFER_FREE, + DSM_MB_PER_SECOND_FREE, + DSM_TRANSFERS_PER_SECOND_FREE, + DSM_BLOCKS_PER_SECOND_FREE, + DSM_MS_PER_TRANSACTION_OTHER, + DSM_MS_PER_TRANSACTION_FREE, + DSM_BUSY_PCT, + DSM_QUEUE_LENGTH, + DSM_TOTAL_DURATION, + DSM_TOTAL_DURATION_READ, + DSM_TOTAL_DURATION_WRITE, + DSM_TOTAL_DURATION_FREE, + DSM_TOTAL_DURATION_OTHER, + DSM_TOTAL_BUSY_TIME, + DSM_MAX, +} +impl Copy for devstat_metric {} +impl Clone for devstat_metric { + fn clone(&self) -> devstat_metric { + *self + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "extra_traits", derive(Hash, PartialEq, Eq))] +#[repr(u32)] +pub enum devstat_select_mode { + DS_SELECT_ADD, + DS_SELECT_ONLY, + DS_SELECT_REMOVE, + DS_SELECT_ADDONLY, +} +impl Copy for devstat_select_mode {} +impl Clone for devstat_select_mode { + fn clone(&self) -> devstat_select_mode { + *self + } +} + +s! { + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + __unused1: [c_int; 2], + __unused2: *mut c_void, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + // unused 3 through 5 are the __aiocb_private structure + __unused3: c_long, + __unused4: c_long, + __unused5: *mut c_void, + pub aio_sigevent: sigevent, + } + + pub struct jail { + pub version: u32, + pub path: *mut c_char, + pub hostname: *mut c_char, + pub jailname: *mut c_char, + pub ip4s: c_uint, + pub ip6s: c_uint, + pub ip4: *mut crate::in_addr, + pub ip6: *mut crate::in6_addr, + } + + pub struct statvfs { + pub f_bavail: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_bsize: c_ulong, + pub f_flag: c_ulong, + pub f_frsize: c_ulong, + pub f_fsid: c_ulong, + pub f_namemax: c_ulong, + } + + // internal structure has changed over time + pub struct _sem { + data: [u32; 4], + } + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct input_event { + pub time: crate::timeval, + pub type_: crate::u_short, + pub code: crate::u_short, + pub value: i32, + } + + pub struct input_absinfo { + pub value: i32, + pub minimum: i32, + pub maximum: i32, + pub fuzz: i32, + pub flat: i32, + pub resolution: i32, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + pub msg_cbytes: crate::msglen_t, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: ssize_t, + } + + pub struct sockcred { + pub sc_uid: crate::uid_t, + pub sc_euid: crate::uid_t, + pub sc_gid: crate::gid_t, + pub sc_egid: crate::gid_t, + pub sc_ngroups: c_int, + pub sc_groups: [crate::gid_t; 1], + } + + pub struct ptrace_vm_entry { + pub pve_entry: c_int, + pub pve_timestamp: c_int, + pub pve_start: c_ulong, + pub pve_end: c_ulong, + pub pve_offset: c_ulong, + pub pve_prot: c_uint, + pub pve_pathlen: c_uint, + pub pve_fileid: c_long, + pub pve_fsid: u32, + pub pve_path: *mut c_char, + } + + pub struct ptrace_lwpinfo { + pub pl_lwpid: lwpid_t, + pub pl_event: c_int, + pub pl_flags: c_int, + pub pl_sigmask: crate::sigset_t, + pub pl_siglist: crate::sigset_t, + pub pl_siginfo: crate::siginfo_t, + pub pl_tdname: [c_char; crate::MAXCOMLEN as usize + 1], + pub pl_child_pid: crate::pid_t, + pub pl_syscall_code: c_uint, + pub pl_syscall_narg: c_uint, + } + + pub struct ptrace_sc_ret { + pub sr_retval: [crate::register_t; 2], + pub sr_error: c_int, + } + + pub struct ptrace_coredump { + pub pc_fd: c_int, + pub pc_flags: u32, + pub pc_limit: off_t, + } + + pub struct ptrace_sc_remote { + pub pscr_ret: ptrace_sc_ret, + pub pscr_syscall: c_uint, + pub pscr_nargs: c_uint, + pub pscr_args: *mut crate::register_t, + } + + pub struct cpuset_t { + #[cfg(all(any(freebsd15, freebsd14), target_pointer_width = "64"))] + __bits: [c_long; 16], + #[cfg(all(any(freebsd15, freebsd14), target_pointer_width = "32"))] + __bits: [c_long; 32], + #[cfg(all(not(any(freebsd15, freebsd14)), target_pointer_width = "64"))] + __bits: [c_long; 4], + #[cfg(all(not(any(freebsd15, freebsd14)), target_pointer_width = "32"))] + __bits: [c_long; 8], + } + + pub struct cap_rights_t { + cr_rights: [u64; 2], + } + + pub struct umutex { + m_owner: crate::lwpid_t, + m_flags: u32, + m_ceilings: [u32; 2], + m_rb_link: crate::uintptr_t, + #[cfg(target_pointer_width = "32")] + m_pad: Padding, + m_spare: [u32; 2], + } + + pub struct ucond { + c_has_waiters: u32, + c_flags: u32, + c_clockid: u32, + c_spare: [u32; 1], + } + + pub struct uuid { + pub time_low: u32, + pub time_mid: u16, + pub time_hi_and_version: u16, + clock_seq_hi_and_reserved: Padding, + pub clock_seq_low: u8, + pub node: [u8; _UUID_NODE_LEN], + } + + pub struct __c_anonymous_pthread_spinlock { + s_clock: umutex, + } + + pub struct __c_anonymous_pthread_barrierattr { + pshared: c_int, + } + + pub struct __c_anonymous_pthread_barrier { + b_lock: umutex, + b_cv: ucond, + b_cycle: i64, + b_count: c_int, + b_waiters: c_int, + b_refcount: c_int, + b_destroying: c_int, + } + + pub struct kinfo_vmentry { + pub kve_structsize: c_int, + pub kve_type: c_int, + pub kve_start: u64, + pub kve_end: u64, + pub kve_offset: u64, + pub kve_vn_fileid: u64, + #[cfg(not(freebsd11))] + pub kve_vn_fsid_freebsd11: u32, + #[cfg(freebsd11)] + pub kve_vn_fsid: u32, + pub kve_flags: c_int, + pub kve_resident: c_int, + pub kve_private_resident: c_int, + pub kve_protection: c_int, + pub kve_ref_count: c_int, + pub kve_shadow_count: c_int, + pub kve_vn_type: c_int, + pub kve_vn_size: u64, + #[cfg(not(freebsd11))] + pub kve_vn_rdev_freebsd11: u32, + #[cfg(freebsd11)] + pub kve_vn_rdev: u32, + pub kve_vn_mode: u16, + pub kve_status: u16, + #[cfg(not(freebsd11))] + pub kve_vn_fsid: u64, + #[cfg(not(freebsd11))] + pub kve_vn_rdev: u64, + #[cfg(not(freebsd11))] + _kve_is_spare: [c_int; 8], + #[cfg(freebsd11)] + _kve_is_spare: [c_int; 12], + pub kve_path: [[c_char; 32]; 32], + } + + pub struct __c_anonymous_filestat { + pub stqe_next: *mut filestat, + } + + pub struct filestat { + pub fs_type: c_int, + pub fs_flags: c_int, + pub fs_fflags: c_int, + pub fs_uflags: c_int, + pub fs_fd: c_int, + pub fs_ref_count: c_int, + pub fs_offset: off_t, + pub fs_typedep: *mut c_void, + pub fs_path: *mut c_char, + pub next: __c_anonymous_filestat, + pub fs_cap_rights: cap_rights_t, + } + + pub struct filestat_list { + pub stqh_first: *mut filestat, + pub stqh_last: *mut *mut filestat, + } + + pub struct procstat { + pub tpe: c_int, + pub kd: crate::uintptr_t, + pub vmentries: *mut c_void, + pub files: *mut c_void, + pub argv: *mut c_void, + pub envv: *mut c_void, + pub core: crate::uintptr_t, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct __c_anonymous__timer { + _priv: [c_int; 3], + } + + /// Used to hold a copy of the command line, if it had a sane length. + pub struct pargs { + /// Reference count. + pub ar_ref: u_int, + /// Length. + pub ar_length: u_int, + /// Arguments. + pub ar_args: [c_uchar; 1], + } + + pub struct priority { + /// Scheduling class. + pub pri_class: u_char, + /// Normal priority level. + pub pri_level: u_char, + /// Priority before propagation. + pub pri_native: u_char, + /// User priority based on p_cpu and p_nice. + pub pri_user: u_char, + } + + pub struct kvm_swap { + pub ksw_devname: [c_char; 32], + pub ksw_used: u_int, + pub ksw_total: u_int, + pub ksw_flags: c_int, + ksw_reserved1: Padding, + ksw_reserved2: Padding, + } + + pub struct nlist { + /// symbol name (in memory) + pub n_name: *const c_char, + /// type defines + pub n_type: c_uchar, + /// "type" and binding information + pub n_other: c_char, + /// used by stab entries + pub n_desc: c_short, + pub n_value: c_ulong, + } + + pub struct kvm_nlist { + pub n_name: *const c_char, + pub n_type: c_uchar, + pub n_value: crate::kvaddr_t, + } + + pub struct __c_anonymous_sem { + _priv: crate::uintptr_t, + } + + pub struct semid_ds { + pub sem_perm: crate::ipc_perm, + pub __sem_base: *mut __c_anonymous_sem, + pub sem_nsems: c_ushort, + pub sem_otime: crate::time_t, + pub sem_ctime: crate::time_t, + } + + pub struct vmtotal { + pub t_vm: u64, + pub t_avm: u64, + pub t_rm: u64, + pub t_arm: u64, + pub t_vmshr: u64, + pub t_avmshr: u64, + pub t_rmshr: u64, + pub t_armshr: u64, + pub t_free: u64, + pub t_rq: i16, + pub t_dw: i16, + pub t_pw: i16, + pub t_sl: i16, + pub t_sw: i16, + pub t_pad: [u16; 3], + } + + pub struct sockstat { + pub inp_ppcb: u64, + pub so_addr: u64, + pub so_pcb: u64, + pub unp_conn: u64, + pub dom_family: c_int, + pub proto: c_int, + pub so_rcv_sb_state: c_int, + pub so_snd_sb_state: c_int, + /// Socket address. + pub sa_local: crate::sockaddr_storage, + /// Peer address. + pub sa_peer: crate::sockaddr_storage, + pub type_: c_int, + pub dname: [c_char; 32], + #[cfg(any(freebsd12, freebsd13, freebsd14, freebsd15))] + pub sendq: c_uint, + #[cfg(any(freebsd12, freebsd13, freebsd14, freebsd15))] + pub recvq: c_uint, + } + + pub struct shmstat { + pub size: u64, + pub mode: u16, + } + + pub struct spacectl_range { + pub r_offset: off_t, + pub r_len: off_t, + } + + pub struct rusage_ext { + pub rux_runtime: u64, + pub rux_uticks: u64, + pub rux_sticks: u64, + pub rux_iticks: u64, + pub rux_uu: u64, + pub rux_su: u64, + pub rux_tu: u64, + } + + pub struct if_clonereq { + pub ifcr_total: c_int, + pub ifcr_count: c_int, + pub ifcr_buffer: *mut c_char, + } + + pub struct if_msghdr { + /// to skip over non-understood messages + pub ifm_msglen: c_ushort, + /// future binary compatibility + pub ifm_version: c_uchar, + /// message type + pub ifm_type: c_uchar, + /// like rtm_addrs + pub ifm_addrs: c_int, + /// value of if_flags + pub ifm_flags: c_int, + /// index for associated ifp + pub ifm_index: c_ushort, + pub _ifm_spare1: c_ushort, + /// statistics and other data about if + pub ifm_data: if_data, + } + + pub struct if_msghdrl { + /// to skip over non-understood messages + pub ifm_msglen: c_ushort, + /// future binary compatibility + pub ifm_version: c_uchar, + /// message type + pub ifm_type: c_uchar, + /// like rtm_addrs + pub ifm_addrs: c_int, + /// value of if_flags + pub ifm_flags: c_int, + /// index for associated ifp + pub ifm_index: c_ushort, + /// spare space to grow if_index, see if_var.h + pub _ifm_spare1: c_ushort, + /// length of if_msghdrl incl. if_data + pub ifm_len: c_ushort, + /// offset of if_data from beginning + pub ifm_data_off: c_ushort, + pub _ifm_spare2: c_int, + /// statistics and other data about if + pub ifm_data: if_data, + } + + pub struct ifa_msghdr { + /// to skip over non-understood messages + pub ifam_msglen: c_ushort, + /// future binary compatibility + pub ifam_version: c_uchar, + /// message type + pub ifam_type: c_uchar, + /// like rtm_addrs + pub ifam_addrs: c_int, + /// value of ifa_flags + pub ifam_flags: c_int, + /// index for associated ifp + pub ifam_index: c_ushort, + pub _ifam_spare1: c_ushort, + /// value of ifa_ifp->if_metric + pub ifam_metric: c_int, + } + + pub struct ifa_msghdrl { + /// to skip over non-understood messages + pub ifam_msglen: c_ushort, + /// future binary compatibility + pub ifam_version: c_uchar, + /// message type + pub ifam_type: c_uchar, + /// like rtm_addrs + pub ifam_addrs: c_int, + /// value of ifa_flags + pub ifam_flags: c_int, + /// index for associated ifp + pub ifam_index: c_ushort, + /// spare space to grow if_index, see if_var.h + pub _ifam_spare1: c_ushort, + /// length of ifa_msghdrl incl. if_data + pub ifam_len: c_ushort, + /// offset of if_data from beginning + pub ifam_data_off: c_ushort, + /// value of ifa_ifp->if_metric + pub ifam_metric: c_int, + /// statistics and other data about if or address + pub ifam_data: if_data, + } + + pub struct ifma_msghdr { + /// to skip over non-understood messages + pub ifmam_msglen: c_ushort, + /// future binary compatibility + pub ifmam_version: c_uchar, + /// message type + pub ifmam_type: c_uchar, + /// like rtm_addrs + pub ifmam_addrs: c_int, + /// value of ifa_flags + pub ifmam_flags: c_int, + /// index for associated ifp + pub ifmam_index: c_ushort, + pub _ifmam_spare1: c_ushort, + } + + pub struct if_announcemsghdr { + /// to skip over non-understood messages + pub ifan_msglen: c_ushort, + /// future binary compatibility + pub ifan_version: c_uchar, + /// message type + pub ifan_type: c_uchar, + /// index for associated ifp + pub ifan_index: c_ushort, + /// if name, e.g. "en0" + pub ifan_name: [c_char; crate::IFNAMSIZ as usize], + /// what type of announcement + pub ifan_what: c_ushort, + } + + pub struct ifreq_buffer { + pub length: size_t, + pub buffer: *mut c_void, + } + + pub struct ifaliasreq { + /// if name, e.g. "en0" + pub ifra_name: [c_char; crate::IFNAMSIZ as usize], + pub ifra_addr: crate::sockaddr, + pub ifra_broadaddr: crate::sockaddr, + pub ifra_mask: crate::sockaddr, + pub ifra_vhid: c_int, + } + + /// 9.x compat + pub struct oifaliasreq { + /// if name, e.g. "en0" + pub ifra_name: [c_char; crate::IFNAMSIZ as usize], + pub ifra_addr: crate::sockaddr, + pub ifra_broadaddr: crate::sockaddr, + pub ifra_mask: crate::sockaddr, + } + + pub struct ifmediareq { + /// if name, e.g. "en0" + pub ifm_name: [c_char; crate::IFNAMSIZ as usize], + /// current media options + pub ifm_current: c_int, + /// don't care mask + pub ifm_mask: c_int, + /// media status + pub ifm_status: c_int, + /// active options + pub ifm_active: c_int, + /// # entries in ifm_ulist array + pub ifm_count: c_int, + /// media words + pub ifm_ulist: *mut c_int, + } + + pub struct ifdrv { + /// if name, e.g. "en0" + pub ifd_name: [c_char; crate::IFNAMSIZ as usize], + pub ifd_cmd: c_ulong, + pub ifd_len: size_t, + pub ifd_data: *mut c_void, + } + + pub struct ifi2creq { + /// i2c address (0xA0, 0xA2) + pub dev_addr: u8, + /// read offset + pub offset: u8, + /// read length + pub len: u8, + pub spare0: u8, + pub spare1: u32, + /// read buffer + pub data: [u8; 8], + } + + pub struct ifrsshash { + /// if name, e.g. "en0" + pub ifrh_name: [c_char; crate::IFNAMSIZ as usize], + /// RSS_FUNC_ + pub ifrh_func: u8, + pub ifrh_spare0: u8, + pub ifrh_spare1: u16, + /// RSS_TYPE_ + pub ifrh_types: u32, + } + + pub struct ifmibdata { + /// name of interface + pub ifmd_name: [c_char; crate::IFNAMSIZ as usize], + /// number of promiscuous listeners + pub ifmd_pcount: c_int, + /// interface flags + pub ifmd_flags: c_int, + /// instantaneous length of send queue + pub ifmd_snd_len: c_int, + /// maximum length of send queue + pub ifmd_snd_maxlen: c_int, + /// number of drops in send queue + pub ifmd_snd_drops: c_int, + /// for future expansion + pub ifmd_filler: [c_int; 4], + /// generic information and statistics + pub ifmd_data: if_data, + } + + pub struct ifmib_iso_8802_3 { + pub dot3StatsAlignmentErrors: u32, + pub dot3StatsFCSErrors: u32, + pub dot3StatsSingleCollisionFrames: u32, + pub dot3StatsMultipleCollisionFrames: u32, + pub dot3StatsSQETestErrors: u32, + pub dot3StatsDeferredTransmissions: u32, + pub dot3StatsLateCollisions: u32, + pub dot3StatsExcessiveCollisions: u32, + pub dot3StatsInternalMacTransmitErrors: u32, + pub dot3StatsCarrierSenseErrors: u32, + pub dot3StatsFrameTooLongs: u32, + pub dot3StatsInternalMacReceiveErrors: u32, + pub dot3StatsEtherChipSet: u32, + pub dot3StatsMissedFrames: u32, + pub dot3StatsCollFrequencies: [u32; 16], + pub dot3Compliance: u32, + } + + pub struct __c_anonymous_ph { + pub ph1: u64, + pub ph2: u64, + } + + pub struct fid { + pub fid_len: c_ushort, + pub fid_data0: c_ushort, + pub fid_data: [c_char; crate::MAXFIDSZ as usize], + } + + pub struct fhandle { + pub fh_fsid: crate::fsid_t, + pub fh_fid: fid, + } + + pub struct bintime { + pub sec: crate::time_t, + pub frac: u64, + } + + pub struct clockinfo { + /// clock frequency + pub hz: c_int, + /// micro-seconds per hz tick + pub tick: c_int, + pub spare: c_int, + /// statistics clock frequency + pub stathz: c_int, + /// profiling clock frequency + pub profhz: c_int, + } + + pub struct __c_anonymous_stailq_entry_devstat { + pub stqe_next: *mut devstat, + } + + pub struct devstat { + /// Update sequence + pub sequence0: crate::u_int, + /// Allocated entry + pub allocated: c_int, + /// started ops + pub start_count: crate::u_int, + /// completed ops + pub end_count: crate::u_int, + /// busy time unaccounted for since this time + pub busy_from: bintime, + pub dev_links: __c_anonymous_stailq_entry_devstat, + /// Devstat device number. + pub device_number: u32, + pub device_name: [c_char; DEVSTAT_NAME_LEN as usize], + pub unit_number: c_int, + pub bytes: [u64; DEVSTAT_N_TRANS_FLAGS as usize], + pub operations: [u64; DEVSTAT_N_TRANS_FLAGS as usize], + pub duration: [bintime; DEVSTAT_N_TRANS_FLAGS as usize], + pub busy_time: bintime, + /// Time the device was created. + pub creation_time: bintime, + /// Block size, bytes + pub block_size: u32, + /// The number of simple, ordered, and head of queue tags sent. + pub tag_types: [u64; 3], + /// Which statistics are supported by a given device. + pub flags: devstat_support_flags, + /// Device type + pub device_type: devstat_type_flags, + /// Controls list pos. + pub priority: devstat_priority, + /// Identification for GEOM nodes + pub id: *const c_void, + /// Update sequence + pub sequence1: crate::u_int, + } + + pub struct devstat_match { + pub match_fields: devstat_match_flags, + pub device_type: devstat_type_flags, + pub num_match_categories: c_int, + } + + pub struct devstat_match_table { + pub match_str: *const c_char, + pub type_: devstat_type_flags, + pub match_field: devstat_match_flags, + } + + pub struct device_selection { + pub device_number: u32, + pub device_name: [c_char; DEVSTAT_NAME_LEN as usize], + pub unit_number: c_int, + pub selected: c_int, + pub bytes: u64, + pub position: c_int, + } + + pub struct devinfo { + pub devices: *mut devstat, + pub mem_ptr: *mut u8, + pub generation: c_long, + pub numdevs: c_int, + } + + pub struct sockcred2 { + pub sc_version: c_int, + pub sc_pid: crate::pid_t, + pub sc_uid: crate::uid_t, + pub sc_euid: crate::uid_t, + pub sc_gid: crate::gid_t, + pub sc_egid: crate::gid_t, + pub sc_ngroups: c_int, + pub sc_groups: [crate::gid_t; 1], + } + + pub struct ifconf { + pub ifc_len: c_int, + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } + + pub struct au_mask_t { + pub am_success: c_uint, + pub am_failure: c_uint, + } + + pub struct au_tid_t { + pub port: u32, + pub machine: u32, + } + + pub struct auditinfo_t { + pub ai_auid: crate::au_id_t, + pub ai_mask: crate::au_mask_t, + pub ai_termid: au_tid_t, + pub ai_asid: crate::au_asid_t, + } + + pub struct tcp_fastopen { + pub enable: c_int, + pub psk: [u8; crate::TCP_FASTOPEN_PSK_LEN as usize], + } + + pub struct tcp_function_set { + pub function_set_name: [c_char; crate::TCP_FUNCTION_NAME_LEN_MAX as usize], + pub pcbcnt: u32, + } + + // Note: this structure will change in a backwards-incompatible way in + // FreeBSD 15. + pub struct tcp_info { + pub tcpi_state: u8, + pub __tcpi_ca_state: u8, + pub __tcpi_retransmits: u8, + pub __tcpi_probes: u8, + pub __tcpi_backoff: u8, + pub tcpi_options: u8, + pub tcp_snd_wscale: u8, + pub tcp_rcv_wscale: u8, + pub tcpi_rto: u32, + pub __tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub __tcpi_unacked: u32, + pub __tcpi_sacked: u32, + pub __tcpi_lost: u32, + pub __tcpi_retrans: u32, + pub __tcpi_fackets: u32, + pub __tcpi_last_data_sent: u32, + pub __tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub __tcpi_last_ack_recv: u32, + pub __tcpi_pmtu: u32, + pub __tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub __tcpi_advmss: u32, + pub __tcpi_reordering: u32, + pub __tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_snd_wnd: u32, + pub tcpi_snd_bwnd: u32, + pub tcpi_snd_nxt: u32, + pub tcpi_rcv_nxt: u32, + pub tcpi_toe_tid: u32, + pub tcpi_snd_rexmitpack: u32, + pub tcpi_rcv_ooopack: u32, + pub tcpi_snd_zerowin: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_delivered_ce: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_received_ce: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_delivered_e1_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_delivered_e0_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_delivered_ce_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_received_e1_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_received_e0_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub __tcpi_received_ce_bytes: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_total_tlp: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_total_tlp_bytes: u64, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_snd_una: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_snd_max: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_rcv_numsacks: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_rcv_adv: u32, + #[cfg(any(freebsd15, freebsd14))] + pub tcpi_dupacks: u32, + #[cfg(freebsd14)] + pub __tcpi_pad: [u32; 10], + #[cfg(freebsd15)] + pub __tcpi_pad: [u32; 14], + #[cfg(not(any(freebsd15, freebsd14)))] + pub __tcpi_pad: [u32; 26], + } + + pub struct _umtx_time { + pub _timeout: crate::timespec, + pub _flags: u32, + pub _clockid: u32, + } + + pub struct shm_largepage_conf { + pub psind: c_int, + pub alloc_policy: c_int, + __pad: Padding<[c_int; 10]>, + } + + pub struct memory_type { + __priva: [crate::uintptr_t; 32], + __privb: [crate::uintptr_t; 26], + } + + pub struct memory_type_list { + __priv: [crate::uintptr_t; 2], + } + + pub struct pidfh { + __priva: [[crate::uintptr_t; 32]; 8], + __privb: [crate::uintptr_t; 2], + } + + pub struct sctp_event { + pub se_assoc_id: crate::sctp_assoc_t, + pub se_type: u16, + pub se_on: u8, + } + + pub struct sctp_event_subscribe { + pub sctp_data_io_event: u8, + pub sctp_association_event: u8, + pub sctp_address_event: u8, + pub sctp_send_failure_event: u8, + pub sctp_peer_error_event: u8, + pub sctp_shutdown_event: u8, + pub sctp_partial_delivery_event: u8, + pub sctp_adaptation_layer_event: u8, + pub sctp_authentication_event: u8, + pub sctp_sender_dry_event: u8, + pub sctp_stream_reset_event: u8, + } + + pub struct sctp_initmsg { + pub sinit_num_ostreams: u16, + pub sinit_max_instreams: u16, + pub sinit_max_attempts: u16, + pub sinit_max_init_timeo: u16, + } + + pub struct sctp_sndrcvinfo { + pub sinfo_stream: u16, + pub sinfo_ssn: u16, + pub sinfo_flags: u16, + pub sinfo_ppid: u32, + pub sinfo_context: u32, + pub sinfo_timetolive: u32, + pub sinfo_tsn: u32, + pub sinfo_cumtsn: u32, + pub sinfo_assoc_id: crate::sctp_assoc_t, + pub sinfo_keynumber: u16, + pub sinfo_keynumber_valid: u16, + pub __reserve_pad: [[u8; 23]; 4], + } + + pub struct sctp_extrcvinfo { + pub sinfo_stream: u16, + pub sinfo_ssn: u16, + pub sinfo_flags: u16, + pub sinfo_ppid: u32, + pub sinfo_context: u32, + pub sinfo_timetolive: u32, + pub sinfo_tsn: u32, + pub sinfo_cumtsn: u32, + pub sinfo_assoc_id: crate::sctp_assoc_t, + pub serinfo_next_flags: u16, + pub serinfo_next_stream: u16, + pub serinfo_next_aid: u32, + pub serinfo_next_length: u32, + pub serinfo_next_ppid: u32, + pub sinfo_keynumber: u16, + pub sinfo_keynumber_valid: u16, + pub __reserve_pad: [[u8; 19]; 4], + } + + pub struct sctp_sndinfo { + pub snd_sid: u16, + pub snd_flags: u16, + pub snd_ppid: u32, + pub snd_context: u32, + pub snd_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_prinfo { + pub pr_policy: u16, + pub pr_value: u32, + } + + pub struct sctp_default_prinfo { + pub pr_policy: u16, + pub pr_value: u32, + pub pr_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_authinfo { + pub auth_keynumber: u16, + } + + pub struct sctp_rcvinfo { + pub rcv_sid: u16, + pub rcv_ssn: u16, + pub rcv_flags: u16, + pub rcv_ppid: u32, + pub rcv_tsn: u32, + pub rcv_cumtsn: u32, + pub rcv_context: u32, + pub rcv_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_nxtinfo { + pub nxt_sid: u16, + pub nxt_flags: u16, + pub nxt_ppid: u32, + pub nxt_length: u32, + pub nxt_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_recvv_rn { + pub recvv_rcvinfo: sctp_rcvinfo, + pub recvv_nxtinfo: sctp_nxtinfo, + } + + pub struct sctp_sendv_spa { + pub sendv_flags: u32, + pub sendv_sndinfo: sctp_sndinfo, + pub sendv_prinfo: sctp_prinfo, + pub sendv_authinfo: sctp_authinfo, + } + + pub struct sctp_snd_all_completes { + pub sall_stream: u16, + pub sall_flags: u16, + pub sall_ppid: u32, + pub sall_context: u32, + pub sall_num_sent: u32, + pub sall_num_failed: u32, + } + + pub struct sctp_pcbinfo { + pub ep_count: u32, + pub asoc_count: u32, + pub laddr_count: u32, + pub raddr_count: u32, + pub chk_count: u32, + pub readq_count: u32, + pub free_chunks: u32, + pub stream_oque: u32, + } + + pub struct sctp_sockstat { + pub ss_assoc_id: crate::sctp_assoc_t, + pub ss_total_sndbuf: u32, + pub ss_total_recv_buf: u32, + } + + pub struct sctp_assoc_change { + pub sac_type: u16, + pub sac_flags: u16, + pub sac_length: u32, + pub sac_state: u16, + pub sac_error: u16, + pub sac_outbound_streams: u16, + pub sac_inbound_streams: u16, + pub sac_assoc_id: crate::sctp_assoc_t, + pub sac_info: [u8; 0], + } + + pub struct sctp_paddr_change { + pub spc_type: u16, + pub spc_flags: u16, + pub spc_length: u32, + pub spc_aaddr: crate::sockaddr_storage, + pub spc_state: u32, + pub spc_error: u32, + pub spc_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_remote_error { + pub sre_type: u16, + pub sre_flags: u16, + pub sre_length: u32, + pub sre_error: u16, + pub sre_assoc_id: crate::sctp_assoc_t, + pub sre_data: [u8; 0], + } + + pub struct sctp_send_failed_event { + pub ssfe_type: u16, + pub ssfe_flags: u16, + pub ssfe_length: u32, + pub ssfe_error: u32, + pub ssfe_info: sctp_sndinfo, + pub ssfe_assoc_id: crate::sctp_assoc_t, + pub ssfe_data: [u8; 0], + } + + pub struct sctp_shutdown_event { + pub sse_type: u16, + pub sse_flags: u16, + pub sse_length: u32, + pub sse_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_adaptation_event { + pub sai_type: u16, + pub sai_flags: u16, + pub sai_length: u32, + pub sai_adaptation_ind: u32, + pub sai_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_setadaptation { + pub ssb_adaptation_ind: u32, + } + + pub struct sctp_pdapi_event { + pub pdapi_type: u16, + pub pdapi_flags: u16, + pub pdapi_length: u32, + pub pdapi_indication: u32, + pub pdapi_stream: u16, + pub pdapi_seq: u16, + pub pdapi_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_sender_dry_event { + pub sender_dry_type: u16, + pub sender_dry_flags: u16, + pub sender_dry_length: u32, + pub sender_dry_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_stream_reset_event { + pub strreset_type: u16, + pub strreset_flags: u16, + pub strreset_length: u32, + pub strreset_assoc_id: crate::sctp_assoc_t, + pub strreset_stream_list: [u16; 0], + } + + pub struct sctp_stream_change_event { + pub strchange_type: u16, + pub strchange_flags: u16, + pub strchange_length: u32, + pub strchange_assoc_id: crate::sctp_assoc_t, + pub strchange_instrms: u16, + pub strchange_outstrms: u16, + } + + pub struct filedesc { + pub fd_files: *mut fdescenttbl, + pub fd_map: *mut c_ulong, + pub fd_freefile: c_int, + pub fd_refcnt: c_int, + pub fd_holdcnt: c_int, + fd_sx: sx, + fd_kqlist: kqlist, + pub fd_holdleaderscount: c_int, + pub fd_holdleaderswakeup: c_int, + } + + pub struct fdescenttbl { + pub fdt_nfiles: c_int, + fdt_ofiles: [*mut c_void; 0], + } + + // FIXME: Should be private. + #[doc(hidden)] + pub struct sx { + lock_object: lock_object, + sx_lock: crate::uintptr_t, + } + + // FIXME: Should be private. + #[doc(hidden)] + pub struct lock_object { + lo_name: *const c_char, + lo_flags: c_uint, + lo_data: c_uint, + // This is normally `struct witness`. + lo_witness: *mut c_void, + } + + // FIXME: Should be private. + #[doc(hidden)] + pub struct kqlist { + tqh_first: *mut c_void, + tqh_last: *mut *mut c_void, + } + + pub struct splice { + pub sp_fd: c_int, + pub sp_max: off_t, + pub sp_idle: crate::timeval, + } + + pub struct utmpx { + pub ut_type: c_short, + pub ut_tv: crate::timeval, + pub ut_id: [c_char; 8], + pub ut_pid: crate::pid_t, + pub ut_user: [c_char; 32], + pub ut_line: [c_char; 16], + pub ut_host: [c_char; 128], + pub __ut_spare: [c_char; 64], + } + + pub struct xucred { + pub cr_version: c_uint, + pub cr_uid: crate::uid_t, + pub cr_ngroups: c_short, + pub cr_groups: [crate::gid_t; 16], + pub cr_pid__c_anonymous_union: __c_anonymous_cr_pid, + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 46], + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + __reserved: Padding<[c_long; 4]>, + } + + pub struct ptsstat { + #[cfg(any(freebsd12, freebsd13, freebsd14, freebsd15))] + pub dev: u64, + #[cfg(not(any(freebsd12, freebsd13, freebsd14, freebsd15)))] + pub dev: u32, + pub devname: [c_char; SPECNAMELEN as usize + 1], + } + + pub struct Elf32_Auxinfo { + pub a_type: c_int, + pub a_un: __c_anonymous_elf32_auxv_union, + } + + pub struct ifreq { + /// if name, e.g. "en0" + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub struct if_data { + /// ethernet, tokenring, etc + pub ifi_type: u8, + /// e.g., AUI, Thinnet, 10base-T, etc + pub ifi_physical: u8, + /// media address length + pub ifi_addrlen: u8, + /// media header length + pub ifi_hdrlen: u8, + /// current link state + pub ifi_link_state: u8, + /// carp vhid + pub ifi_vhid: u8, + /// length of this data struct + pub ifi_datalen: u16, + /// maximum transmission unit + pub ifi_mtu: u32, + /// routing metric (external only) + pub ifi_metric: u32, + /// linespeed + pub ifi_baudrate: u64, + /// packets received on interface + pub ifi_ipackets: u64, + /// input errors on interface + pub ifi_ierrors: u64, + /// packets sent on interface + pub ifi_opackets: u64, + /// output errors on interface + pub ifi_oerrors: u64, + /// collisions on csma interfaces + pub ifi_collisions: u64, + /// total number of octets received + pub ifi_ibytes: u64, + /// total number of octets sent + pub ifi_obytes: u64, + /// packets received via multicast + pub ifi_imcasts: u64, + /// packets sent via multicast + pub ifi_omcasts: u64, + /// dropped on input + pub ifi_iqdrops: u64, + /// dropped on output + pub ifi_oqdrops: u64, + /// destined for unsupported protocol + pub ifi_noproto: u64, + /// HW offload capabilities, see IFCAP + pub ifi_hwassist: u64, + /// uptime at attach or stat reset + pub __ifi_epoch: __c_anonymous_ifi_epoch, + /// time of last administrative change + pub __ifi_lastchange: __c_anonymous_ifi_lastchange, + } + + pub struct ifstat { + /// if name, e.g. "en0" + pub ifs_name: [c_char; crate::IFNAMSIZ as usize], + pub ascii: [c_char; crate::IFSTATMAX as usize + 1], + } + + pub struct ifrsskey { + /// if name, e.g. "en0" + pub ifrk_name: [c_char; crate::IFNAMSIZ as usize], + /// RSS_FUNC_ + pub ifrk_func: u8, + pub ifrk_spare0: u8, + pub ifrk_keylen: u16, + pub ifrk_key: [u8; crate::RSS_KEYLEN as usize], + } + + pub struct ifdownreason { + pub ifdr_name: [c_char; crate::IFNAMSIZ as usize], + pub ifdr_reason: u32, + pub ifdr_vendor: u32, + pub ifdr_msg: [c_char; crate::IFDR_MSG_SIZE as usize], + } + + #[repr(packed)] + pub struct sctphdr { + pub src_port: u16, + pub dest_port: u16, + pub v_tag: u32, + pub checksum: u32, + } + + #[repr(packed)] + pub struct sctp_chunkhdr { + pub chunk_type: u8, + pub chunk_flags: u8, + pub chunk_length: u16, + } + + #[repr(packed)] + pub struct sctp_paramhdr { + pub param_type: u16, + pub param_length: u16, + } + + #[repr(packed)] + pub struct sctp_gen_error_cause { + pub code: u16, + pub length: u16, + pub info: [u8; 0], + } + + #[repr(packed)] + pub struct sctp_error_cause { + pub code: u16, + pub length: u16, + } + + #[repr(packed)] + pub struct sctp_error_invalid_stream { + pub cause: sctp_error_cause, + pub stream_id: u16, + __reserved: Padding, + } + + #[repr(packed)] + pub struct sctp_error_missing_param { + pub cause: sctp_error_cause, + pub num_missing_params: u32, + pub tpe: [u8; 0], + } + + #[repr(packed)] + pub struct sctp_error_stale_cookie { + pub cause: sctp_error_cause, + pub stale_time: u32, + } + + #[repr(packed)] + pub struct sctp_error_out_of_resource { + pub cause: sctp_error_cause, + } + + #[repr(packed)] + pub struct sctp_error_unresolv_addr { + pub cause: sctp_error_cause, + } + + #[repr(packed)] + pub struct sctp_error_unrecognized_chunk { + pub cause: sctp_error_cause, + pub ch: sctp_chunkhdr, + } + + #[repr(packed)] + pub struct sctp_error_no_user_data { + pub cause: sctp_error_cause, + pub tsn: u32, + } + + #[repr(packed)] + pub struct sctp_error_auth_invalid_hmac { + pub cause: sctp_error_cause, + pub hmac_id: u16, + } + + pub struct kinfo_file { + pub kf_structsize: c_int, + pub kf_type: c_int, + pub kf_fd: c_int, + pub kf_ref_count: c_int, + pub kf_flags: c_int, + _kf_pad0: Padding, + pub kf_offset: i64, + _priv: [u8; 304], // FIXME(freebsd): this is really a giant union + pub kf_status: u16, + _kf_pad1: Padding, + _kf_ispare0: c_int, + pub kf_cap_rights: crate::cap_rights_t, + _kf_cap_spare: u64, + pub kf_path: [c_char; crate::PATH_MAX as usize], + } +} + +s_no_extra_traits! { + pub union __c_anonymous_cr_pid { + __cr_unused: Padding<*mut c_void>, + pub cr_pid: crate::pid_t, + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: crate::sigval, + //The rest of the structure is actually a union. We expose only + //sigev_notify_thread_id because it's the most useful union member. + pub sigev_notify_thread_id: crate::lwpid_t, + #[cfg(target_pointer_width = "64")] + __unused1: c_int, + __unused2: [c_long; 7], + } + + pub union __c_anonymous_elf32_auxv_union { + pub a_val: c_int, + } + + pub union __c_anonymous_ifi_epoch { + pub tt: crate::time_t, + pub ph: u64, + } + + pub union __c_anonymous_ifi_lastchange { + pub tv: crate::timeval, + pub ph: __c_anonymous_ph, + } + + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_buffer: ifreq_buffer, + pub ifru_flags: [c_short; 2], + pub ifru_index: c_short, + pub ifru_jid: c_int, + pub ifru_metric: c_int, + pub ifru_mtu: c_int, + pub ifru_phys: c_int, + pub ifru_media: c_int, + pub ifru_data: crate::caddr_t, + pub ifru_cap: [c_int; 2], + pub ifru_fib: c_uint, + pub ifru_vlan_pcp: c_uchar, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: crate::caddr_t, + pub ifcu_req: *mut ifreq, + } + + pub struct ucontext_t { + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: crate::mcontext_t, + pub uc_link: *mut crate::ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_flags: c_int, + __spare__: [c_int; 4], + } + + #[repr(align(8))] + pub struct xinpgen { + pub xig_len: ksize_t, + pub xig_count: u32, + _xig_spare32: u32, + pub xig_gen: inp_gen_t, + pub xig_sogen: so_gen_t, + _xig_spare64: [u64; 4], + } + + pub struct in_addr_4in6 { + _ia46_pad32: Padding<[u32; 3]>, + pub ia46_addr4: crate::in_addr, + } + + pub union in_dependaddr { + pub id46_addr: crate::in_addr_4in6, + pub id6_addr: crate::in6_addr, + } + + pub struct in_endpoints { + pub ie_fport: u16, + pub ie_lport: u16, + pub ie_dependfaddr: crate::in_dependaddr, + pub ie_dependladdr: crate::in_dependaddr, + pub ie6_zoneid: u32, + } + + pub struct in_conninfo { + pub inc_flags: u8, + pub inc_len: u8, + pub inc_fibnum: u16, + pub inc_ie: crate::in_endpoints, + } + + pub struct xktls_session_onedir { + // Note: this field is called `gen` in upstream FreeBSD, but `gen` is + // reserved keyword in Rust since the 2024 Edition, hence `gennum`. + pub gennum: u64, + _rsrv1: [u64; 8], + _rsrv2: [u32; 8], + pub iv: [u8; 32], + pub cipher_algorithm: i32, + pub auth_algorithm: i32, + pub cipher_key_len: u16, + pub iv_len: u16, + pub auth_key_len: u16, + pub max_frame_len: u16, + pub tls_vmajor: u8, + pub tls_vminor: u8, + pub tls_hlen: u8, + pub tls_tlen: u8, + pub tls_bs: u8, + pub flags: u8, + pub drv_st_len: u16, + pub ifnet: [c_char; 16], + } + + pub struct xktls_session { + pub tsz: u32, + pub fsz: u32, + pub inp_gencnt: u64, + pub so_pcb: kvaddr_t, + pub coninf: crate::in_conninfo, + pub rx_vlan_id: c_ushort, + pub rcv: crate::xktls_session_onedir, + pub snd: crate::xktls_session_onedir, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_cr_pid { + fn eq(&self, other: &__c_anonymous_cr_pid) -> bool { + unsafe { self.cr_pid == other.cr_pid } + } + } + impl Eq for __c_anonymous_cr_pid {} + impl hash::Hash for __c_anonymous_cr_pid { + fn hash(&self, state: &mut H) { + unsafe { self.cr_pid.hash(state) }; + } + } + + impl PartialEq for sigevent { + fn eq(&self, other: &sigevent) -> bool { + self.sigev_notify == other.sigev_notify + && self.sigev_signo == other.sigev_signo + && self.sigev_value == other.sigev_value + && self.sigev_notify_thread_id == other.sigev_notify_thread_id + } + } + impl Eq for sigevent {} + impl hash::Hash for sigevent { + fn hash(&self, state: &mut H) { + self.sigev_notify.hash(state); + self.sigev_signo.hash(state); + self.sigev_value.hash(state); + self.sigev_notify_thread_id.hash(state); + } + } + + impl PartialEq for __c_anonymous_elf32_auxv_union { + fn eq(&self, other: &__c_anonymous_elf32_auxv_union) -> bool { + unsafe { self.a_val == other.a_val } + } + } + impl Eq for __c_anonymous_elf32_auxv_union {} + impl hash::Hash for __c_anonymous_elf32_auxv_union { + fn hash(&self, _state: &mut H) { + unimplemented!("traits"); + } + } + + impl PartialEq for __c_anonymous_ifr_ifru { + fn eq(&self, other: &__c_anonymous_ifr_ifru) -> bool { + unsafe { + self.ifru_addr == other.ifru_addr + && self.ifru_dstaddr == other.ifru_dstaddr + && self.ifru_broadaddr == other.ifru_broadaddr + && self.ifru_buffer == other.ifru_buffer + && self.ifru_flags == other.ifru_flags + && self.ifru_index == other.ifru_index + && self.ifru_jid == other.ifru_jid + && self.ifru_metric == other.ifru_metric + && self.ifru_mtu == other.ifru_mtu + && self.ifru_phys == other.ifru_phys + && self.ifru_media == other.ifru_media + && self.ifru_data == other.ifru_data + && self.ifru_cap == other.ifru_cap + && self.ifru_fib == other.ifru_fib + && self.ifru_vlan_pcp == other.ifru_vlan_pcp + } + } + } + impl Eq for __c_anonymous_ifr_ifru {} + impl hash::Hash for __c_anonymous_ifr_ifru { + fn hash(&self, state: &mut H) { + unsafe { self.ifru_addr.hash(state) }; + unsafe { self.ifru_dstaddr.hash(state) }; + unsafe { self.ifru_broadaddr.hash(state) }; + unsafe { self.ifru_buffer.hash(state) }; + unsafe { self.ifru_flags.hash(state) }; + unsafe { self.ifru_index.hash(state) }; + unsafe { self.ifru_jid.hash(state) }; + unsafe { self.ifru_metric.hash(state) }; + unsafe { self.ifru_mtu.hash(state) }; + unsafe { self.ifru_phys.hash(state) }; + unsafe { self.ifru_media.hash(state) }; + unsafe { self.ifru_data.hash(state) }; + unsafe { self.ifru_cap.hash(state) }; + unsafe { self.ifru_fib.hash(state) }; + unsafe { self.ifru_vlan_pcp.hash(state) }; + } + } + + impl PartialEq for __c_anonymous_ifc_ifcu { + fn eq(&self, other: &__c_anonymous_ifc_ifcu) -> bool { + unsafe { self.ifcu_buf == other.ifcu_buf && self.ifcu_req == other.ifcu_req } + } + } + impl Eq for __c_anonymous_ifc_ifcu {} + impl hash::Hash for __c_anonymous_ifc_ifcu { + fn hash(&self, state: &mut H) { + unsafe { self.ifcu_buf.hash(state) }; + unsafe { self.ifcu_req.hash(state) }; + } + } + + impl PartialEq for __c_anonymous_ifi_epoch { + fn eq(&self, other: &__c_anonymous_ifi_epoch) -> bool { + unsafe { self.tt == other.tt && self.ph == other.ph } + } + } + impl Eq for __c_anonymous_ifi_epoch {} + impl hash::Hash for __c_anonymous_ifi_epoch { + fn hash(&self, state: &mut H) { + unsafe { + self.tt.hash(state); + self.ph.hash(state); + } + } + } + + impl PartialEq for __c_anonymous_ifi_lastchange { + fn eq(&self, other: &__c_anonymous_ifi_lastchange) -> bool { + unsafe { self.tv == other.tv && self.ph == other.ph } + } + } + impl Eq for __c_anonymous_ifi_lastchange {} + impl hash::Hash for __c_anonymous_ifi_lastchange { + fn hash(&self, state: &mut H) { + unsafe { + self.tv.hash(state); + self.ph.hash(state); + } + } + } + } +} + +#[derive(Debug)] +#[repr(u32)] +pub enum dot3Vendors { + dot3VendorAMD = 1, + dot3VendorIntel = 2, + dot3VendorNational = 4, + dot3VendorFujitsu = 5, + dot3VendorDigital = 6, + dot3VendorWesternDigital = 7, +} +impl Copy for dot3Vendors {} +impl Clone for dot3Vendors { + fn clone(&self) -> dot3Vendors { + *self + } +} + +// aio.h +pub const LIO_VECTORED: c_int = 4; +pub const LIO_WRITEV: c_int = 5; +pub const LIO_READV: c_int = 6; + +// sys/caprights.h +pub const CAP_RIGHTS_VERSION_00: i32 = 0; +pub const CAP_RIGHTS_VERSION: i32 = CAP_RIGHTS_VERSION_00; + +// sys/capsicum.h +macro_rules! cap_right { + ($idx:expr, $bit:expr) => { + ((1u64 << (57 + ($idx))) | ($bit)) + }; +} +pub const CAP_READ: u64 = cap_right!(0, 0x0000000000000001u64); +pub const CAP_WRITE: u64 = cap_right!(0, 0x0000000000000002u64); +pub const CAP_SEEK_TELL: u64 = cap_right!(0, 0x0000000000000004u64); +pub const CAP_SEEK: u64 = CAP_SEEK_TELL | 0x0000000000000008u64; +pub const CAP_PREAD: u64 = CAP_SEEK | CAP_READ; +pub const CAP_PWRITE: u64 = CAP_SEEK | CAP_WRITE; +pub const CAP_MMAP: u64 = cap_right!(0, 0x0000000000000010u64); +pub const CAP_MMAP_R: u64 = CAP_MMAP | CAP_SEEK | CAP_READ; +pub const CAP_MMAP_W: u64 = CAP_MMAP | CAP_SEEK | CAP_WRITE; +pub const CAP_MMAP_X: u64 = CAP_MMAP | CAP_SEEK | 0x0000000000000020u64; +pub const CAP_MMAP_RW: u64 = CAP_MMAP_R | CAP_MMAP_W; +pub const CAP_MMAP_RX: u64 = CAP_MMAP_R | CAP_MMAP_X; +pub const CAP_MMAP_WX: u64 = CAP_MMAP_W | CAP_MMAP_X; +pub const CAP_MMAP_RWX: u64 = CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X; +pub const CAP_CREATE: u64 = cap_right!(0, 0x0000000000000040u64); +pub const CAP_FEXECVE: u64 = cap_right!(0, 0x0000000000000080u64); +pub const CAP_FSYNC: u64 = cap_right!(0, 0x0000000000000100u64); +pub const CAP_FTRUNCATE: u64 = cap_right!(0, 0x0000000000000200u64); +pub const CAP_LOOKUP: u64 = cap_right!(0, 0x0000000000000400u64); +pub const CAP_FCHDIR: u64 = cap_right!(0, 0x0000000000000800u64); +pub const CAP_FCHFLAGS: u64 = cap_right!(0, 0x0000000000001000u64); +pub const CAP_CHFLAGSAT: u64 = CAP_FCHFLAGS | CAP_LOOKUP; +pub const CAP_FCHMOD: u64 = cap_right!(0, 0x0000000000002000u64); +pub const CAP_FCHMODAT: u64 = CAP_FCHMOD | CAP_LOOKUP; +pub const CAP_FCHOWN: u64 = cap_right!(0, 0x0000000000004000u64); +pub const CAP_FCHOWNAT: u64 = CAP_FCHOWN | CAP_LOOKUP; +pub const CAP_FCNTL: u64 = cap_right!(0, 0x0000000000008000u64); +pub const CAP_FLOCK: u64 = cap_right!(0, 0x0000000000010000u64); +pub const CAP_FPATHCONF: u64 = cap_right!(0, 0x0000000000020000u64); +pub const CAP_FSCK: u64 = cap_right!(0, 0x0000000000040000u64); +pub const CAP_FSTAT: u64 = cap_right!(0, 0x0000000000080000u64); +pub const CAP_FSTATAT: u64 = CAP_FSTAT | CAP_LOOKUP; +pub const CAP_FSTATFS: u64 = cap_right!(0, 0x0000000000100000u64); +pub const CAP_FUTIMES: u64 = cap_right!(0, 0x0000000000200000u64); +pub const CAP_FUTIMESAT: u64 = CAP_FUTIMES | CAP_LOOKUP; +// Note: this was named CAP_LINKAT prior to FreeBSD 11.0. +pub const CAP_LINKAT_TARGET: u64 = CAP_LOOKUP | 0x0000000000400000u64; +pub const CAP_MKDIRAT: u64 = CAP_LOOKUP | 0x0000000000800000u64; +pub const CAP_MKFIFOAT: u64 = CAP_LOOKUP | 0x0000000001000000u64; +pub const CAP_MKNODAT: u64 = CAP_LOOKUP | 0x0000000002000000u64; +// Note: this was named CAP_RENAMEAT prior to FreeBSD 11.0. +pub const CAP_RENAMEAT_SOURCE: u64 = CAP_LOOKUP | 0x0000000004000000u64; +pub const CAP_SYMLINKAT: u64 = CAP_LOOKUP | 0x0000000008000000u64; +pub const CAP_UNLINKAT: u64 = CAP_LOOKUP | 0x0000000010000000u64; +pub const CAP_ACCEPT: u64 = cap_right!(0, 0x0000000020000000u64); +pub const CAP_BIND: u64 = cap_right!(0, 0x0000000040000000u64); +pub const CAP_CONNECT: u64 = cap_right!(0, 0x0000000080000000u64); +pub const CAP_GETPEERNAME: u64 = cap_right!(0, 0x0000000100000000u64); +pub const CAP_GETSOCKNAME: u64 = cap_right!(0, 0x0000000200000000u64); +pub const CAP_GETSOCKOPT: u64 = cap_right!(0, 0x0000000400000000u64); +pub const CAP_LISTEN: u64 = cap_right!(0, 0x0000000800000000u64); +pub const CAP_PEELOFF: u64 = cap_right!(0, 0x0000001000000000u64); +pub const CAP_RECV: u64 = CAP_READ; +pub const CAP_SEND: u64 = CAP_WRITE; +pub const CAP_SETSOCKOPT: u64 = cap_right!(0, 0x0000002000000000u64); +pub const CAP_SHUTDOWN: u64 = cap_right!(0, 0x0000004000000000u64); +pub const CAP_BINDAT: u64 = CAP_LOOKUP | 0x0000008000000000u64; +pub const CAP_CONNECTAT: u64 = CAP_LOOKUP | 0x0000010000000000u64; +pub const CAP_LINKAT_SOURCE: u64 = CAP_LOOKUP | 0x0000020000000000u64; +pub const CAP_RENAMEAT_TARGET: u64 = CAP_LOOKUP | 0x0000040000000000u64; +pub const CAP_SOCK_CLIENT: u64 = CAP_CONNECT + | CAP_GETPEERNAME + | CAP_GETSOCKNAME + | CAP_GETSOCKOPT + | CAP_PEELOFF + | CAP_RECV + | CAP_SEND + | CAP_SETSOCKOPT + | CAP_SHUTDOWN; +pub const CAP_SOCK_SERVER: u64 = CAP_ACCEPT + | CAP_BIND + | CAP_GETPEERNAME + | CAP_GETSOCKNAME + | CAP_GETSOCKOPT + | CAP_LISTEN + | CAP_PEELOFF + | CAP_RECV + | CAP_SEND + | CAP_SETSOCKOPT + | CAP_SHUTDOWN; +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_ALL0: u64 = cap_right!(0, 0x000007FFFFFFFFFFu64); +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_UNUSED0_44: u64 = cap_right!(0, 0x0000080000000000u64); +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_UNUSED0_57: u64 = cap_right!(0, 0x0100000000000000u64); +pub const CAP_MAC_GET: u64 = cap_right!(1, 0x0000000000000001u64); +pub const CAP_MAC_SET: u64 = cap_right!(1, 0x0000000000000002u64); +pub const CAP_SEM_GETVALUE: u64 = cap_right!(1, 0x0000000000000004u64); +pub const CAP_SEM_POST: u64 = cap_right!(1, 0x0000000000000008u64); +pub const CAP_SEM_WAIT: u64 = cap_right!(1, 0x0000000000000010u64); +pub const CAP_EVENT: u64 = cap_right!(1, 0x0000000000000020u64); +pub const CAP_KQUEUE_EVENT: u64 = cap_right!(1, 0x0000000000000040u64); +pub const CAP_IOCTL: u64 = cap_right!(1, 0x0000000000000080u64); +pub const CAP_TTYHOOK: u64 = cap_right!(1, 0x0000000000000100u64); +pub const CAP_PDGETPID: u64 = cap_right!(1, 0x0000000000000200u64); +pub const CAP_PDWAIT: u64 = cap_right!(1, 0x0000000000000400u64); +pub const CAP_PDKILL: u64 = cap_right!(1, 0x0000000000000800u64); +pub const CAP_EXTATTR_DELETE: u64 = cap_right!(1, 0x0000000000001000u64); +pub const CAP_EXTATTR_GET: u64 = cap_right!(1, 0x0000000000002000u64); +pub const CAP_EXTATTR_LIST: u64 = cap_right!(1, 0x0000000000004000u64); +pub const CAP_EXTATTR_SET: u64 = cap_right!(1, 0x0000000000008000u64); +pub const CAP_ACL_CHECK: u64 = cap_right!(1, 0x0000000000010000u64); +pub const CAP_ACL_DELETE: u64 = cap_right!(1, 0x0000000000020000u64); +pub const CAP_ACL_GET: u64 = cap_right!(1, 0x0000000000040000u64); +pub const CAP_ACL_SET: u64 = cap_right!(1, 0x0000000000080000u64); +pub const CAP_KQUEUE_CHANGE: u64 = cap_right!(1, 0x0000000000100000u64); +pub const CAP_KQUEUE: u64 = CAP_KQUEUE_EVENT | CAP_KQUEUE_CHANGE; +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_ALL1: u64 = cap_right!(1, 0x00000000001FFFFFu64); +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_UNUSED1_22: u64 = cap_right!(1, 0x0000000000200000u64); +#[deprecated(since = "0.2.165", note = "Not stable across OS versions")] +pub const CAP_UNUSED1_57: u64 = cap_right!(1, 0x0100000000000000u64); +pub const CAP_FCNTL_GETFL: u32 = 1 << 3; +pub const CAP_FCNTL_SETFL: u32 = 1 << 4; +pub const CAP_FCNTL_GETOWN: u32 = 1 << 5; +pub const CAP_FCNTL_SETOWN: u32 = 1 << 6; + +// sys/devicestat.h +pub const DEVSTAT_N_TRANS_FLAGS: c_int = 4; +pub const DEVSTAT_NAME_LEN: c_int = 16; + +// sys/cpuset.h +cfg_if! { + if #[cfg(any(freebsd15, freebsd14))] { + pub const CPU_SETSIZE: c_int = 1024; + } else { + pub const CPU_SETSIZE: c_int = 256; + } +} + +pub const SIGEV_THREAD_ID: c_int = 4; + +pub const EXTATTR_NAMESPACE_EMPTY: c_int = 0; +pub const EXTATTR_NAMESPACE_USER: c_int = 1; +pub const EXTATTR_NAMESPACE_SYSTEM: c_int = 2; + +pub const PTHREAD_STACK_MIN: size_t = MINSIGSTKSZ; +pub const PTHREAD_MUTEX_ADAPTIVE_NP: c_int = 4; +pub const PTHREAD_MUTEX_STALLED: c_int = 0; +pub const PTHREAD_MUTEX_ROBUST: c_int = 1; +pub const SIGSTKSZ: size_t = MINSIGSTKSZ + 32768; +pub const SF_NODISKIO: c_int = 0x00000001; +pub const SF_MNOWAIT: c_int = 0x00000002; +pub const SF_SYNC: c_int = 0x00000004; +pub const SF_USER_READAHEAD: c_int = 0x00000008; +pub const SF_NOCACHE: c_int = 0x00000010; +pub const O_CLOEXEC: c_int = 0x00100000; +pub const O_DIRECTORY: c_int = 0x00020000; +pub const O_DSYNC: c_int = 0x01000000; +pub const O_EMPTY_PATH: c_int = 0x02000000; +pub const O_EXEC: c_int = 0x00040000; +pub const O_PATH: c_int = 0x00400000; +pub const O_RESOLVE_BENEATH: c_int = 0x00800000; +pub const O_SEARCH: c_int = O_EXEC; +pub const O_TTY_INIT: c_int = 0x00080000; +pub const O_VERIFY: c_int = 0x00200000; +pub const F_GETLK: c_int = 11; +pub const F_SETLK: c_int = 12; +pub const F_SETLKW: c_int = 13; +pub const ENOTCAPABLE: c_int = 93; +pub const ECAPMODE: c_int = 94; +pub const ENOTRECOVERABLE: c_int = 95; +pub const EOWNERDEAD: c_int = 96; +pub const EINTEGRITY: c_int = 97; +pub const RLIMIT_NPTS: c_int = 11; +pub const RLIMIT_SWAP: c_int = 12; +pub const RLIMIT_KQUEUES: c_int = 13; +pub const RLIMIT_UMTXP: c_int = 14; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: crate::rlim_t = 15; +pub const RLIM_SAVED_MAX: crate::rlim_t = crate::RLIM_INFINITY; +pub const RLIM_SAVED_CUR: crate::rlim_t = crate::RLIM_INFINITY; + +pub const CP_USER: c_int = 0; +pub const CP_NICE: c_int = 1; +pub const CP_SYS: c_int = 2; +pub const CP_INTR: c_int = 3; +pub const CP_IDLE: c_int = 4; +pub const CPUSTATES: c_int = 5; + +pub const NI_NOFQDN: c_int = 0x00000001; +pub const NI_NUMERICHOST: c_int = 0x00000002; +pub const NI_NAMEREQD: c_int = 0x00000004; +pub const NI_NUMERICSERV: c_int = 0x00000008; +pub const NI_DGRAM: c_int = 0x00000010; +pub const NI_NUMERICSCOPE: c_int = 0x00000020; + +pub const XU_NGROUPS: c_int = 16; + +pub const Q_GETQUOTA: c_int = 0x700; +pub const Q_SETQUOTA: c_int = 0x800; + +pub const MAP_GUARD: c_int = 0x00002000; +pub const MAP_EXCL: c_int = 0x00004000; +pub const MAP_PREFAULT_READ: c_int = 0x00040000; +pub const MAP_ALIGNMENT_SHIFT: c_int = 24; +pub const MAP_ALIGNMENT_MASK: c_int = 0xff << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNED_SUPER: c_int = 1 << MAP_ALIGNMENT_SHIFT; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const POLLINIGNEOF: c_short = 0x2000; +pub const POLLRDHUP: c_short = 0x4000; + +pub const EVFILT_READ: i16 = -1; +pub const EVFILT_WRITE: i16 = -2; +pub const EVFILT_AIO: i16 = -3; +pub const EVFILT_VNODE: i16 = -4; +pub const EVFILT_PROC: i16 = -5; +pub const EVFILT_SIGNAL: i16 = -6; +pub const EVFILT_TIMER: i16 = -7; +pub const EVFILT_PROCDESC: i16 = -8; +pub const EVFILT_FS: i16 = -9; +pub const EVFILT_LIO: i16 = -10; +pub const EVFILT_USER: i16 = -11; +pub const EVFILT_SENDFILE: i16 = -12; +pub const EVFILT_EMPTY: i16 = -13; + +pub const EV_ADD: u16 = 0x1; +pub const EV_DELETE: u16 = 0x2; +pub const EV_ENABLE: u16 = 0x4; +pub const EV_DISABLE: u16 = 0x8; +pub const EV_FORCEONESHOT: u16 = 0x100; +pub const EV_KEEPUDATA: u16 = 0x200; + +pub const EV_ONESHOT: u16 = 0x10; +pub const EV_CLEAR: u16 = 0x20; +pub const EV_RECEIPT: u16 = 0x40; +pub const EV_DISPATCH: u16 = 0x80; +pub const EV_SYSFLAGS: u16 = 0xf000; +pub const EV_DROP: u16 = 0x1000; +pub const EV_FLAG1: u16 = 0x2000; +pub const EV_FLAG2: u16 = 0x4000; + +pub const EV_EOF: u16 = 0x8000; +pub const EV_ERROR: u16 = 0x4000; + +pub const NOTE_TRIGGER: u32 = 0x01000000; +pub const NOTE_FFNOP: u32 = 0x00000000; +pub const NOTE_FFAND: u32 = 0x40000000; +pub const NOTE_FFOR: u32 = 0x80000000; +pub const NOTE_FFCOPY: u32 = 0xc0000000; +pub const NOTE_FFCTRLMASK: u32 = 0xc0000000; +pub const NOTE_FFLAGSMASK: u32 = 0x00ffffff; +pub const NOTE_LOWAT: u32 = 0x00000001; +pub const NOTE_FILE_POLL: u32 = 0x00000002; +pub const NOTE_DELETE: u32 = 0x00000001; +pub const NOTE_WRITE: u32 = 0x00000002; +pub const NOTE_EXTEND: u32 = 0x00000004; +pub const NOTE_ATTRIB: u32 = 0x00000008; +pub const NOTE_LINK: u32 = 0x00000010; +pub const NOTE_RENAME: u32 = 0x00000020; +pub const NOTE_REVOKE: u32 = 0x00000040; +pub const NOTE_OPEN: u32 = 0x00000080; +pub const NOTE_CLOSE: u32 = 0x00000100; +pub const NOTE_CLOSE_WRITE: u32 = 0x00000200; +pub const NOTE_READ: u32 = 0x00000400; +pub const NOTE_EXIT: u32 = 0x80000000; +pub const NOTE_FORK: u32 = 0x40000000; +pub const NOTE_EXEC: u32 = 0x20000000; +pub const NOTE_PDATAMASK: u32 = 0x000fffff; +pub const NOTE_PCTRLMASK: u32 = 0xf0000000; +pub const NOTE_TRACK: u32 = 0x00000001; +pub const NOTE_TRACKERR: u32 = 0x00000002; +pub const NOTE_CHILD: u32 = 0x00000004; +pub const NOTE_SECONDS: u32 = 0x00000001; +pub const NOTE_MSECONDS: u32 = 0x00000002; +pub const NOTE_USECONDS: u32 = 0x00000004; +pub const NOTE_NSECONDS: u32 = 0x00000008; +pub const NOTE_ABSTIME: u32 = 0x00000010; + +pub const MADV_PROTECT: c_int = 10; + +#[doc(hidden)] +#[deprecated( + since = "0.2.72", + note = "CTL_UNSPEC is deprecated. Use CTL_SYSCTL instead" +)] +pub const CTL_UNSPEC: c_int = 0; +pub const CTL_SYSCTL: c_int = 0; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_VFS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_USER: c_int = 8; +pub const CTL_P1003_1B: c_int = 9; + +// sys/sysctl.h +pub const CTL_MAXNAME: c_int = 24; + +pub const CTLTYPE: c_int = 0xf; +pub const CTLTYPE_NODE: c_int = 1; +pub const CTLTYPE_INT: c_int = 2; +pub const CTLTYPE_STRING: c_int = 3; +pub const CTLTYPE_S64: c_int = 4; +pub const CTLTYPE_OPAQUE: c_int = 5; +pub const CTLTYPE_STRUCT: c_int = CTLTYPE_OPAQUE; +pub const CTLTYPE_UINT: c_int = 6; +pub const CTLTYPE_LONG: c_int = 7; +pub const CTLTYPE_ULONG: c_int = 8; +pub const CTLTYPE_U64: c_int = 9; +pub const CTLTYPE_U8: c_int = 0xa; +pub const CTLTYPE_U16: c_int = 0xb; +pub const CTLTYPE_S8: c_int = 0xc; +pub const CTLTYPE_S16: c_int = 0xd; +pub const CTLTYPE_S32: c_int = 0xe; +pub const CTLTYPE_U32: c_int = 0xf; + +pub const CTLFLAG_RD: c_int = 0x80000000; +pub const CTLFLAG_WR: c_int = 0x40000000; +pub const CTLFLAG_RW: c_int = CTLFLAG_RD | CTLFLAG_WR; +pub const CTLFLAG_DORMANT: c_int = 0x20000000; +pub const CTLFLAG_ANYBODY: c_int = 0x10000000; +pub const CTLFLAG_SECURE: c_int = 0x08000000; +pub const CTLFLAG_PRISON: c_int = 0x04000000; +pub const CTLFLAG_DYN: c_int = 0x02000000; +pub const CTLFLAG_SKIP: c_int = 0x01000000; +pub const CTLMASK_SECURE: c_int = 0x00F00000; +pub const CTLFLAG_TUN: c_int = 0x00080000; +pub const CTLFLAG_RDTUN: c_int = CTLFLAG_RD | CTLFLAG_TUN; +pub const CTLFLAG_RWTUN: c_int = CTLFLAG_RW | CTLFLAG_TUN; +pub const CTLFLAG_MPSAFE: c_int = 0x00040000; +pub const CTLFLAG_VNET: c_int = 0x00020000; +pub const CTLFLAG_DYING: c_int = 0x00010000; +pub const CTLFLAG_CAPRD: c_int = 0x00008000; +pub const CTLFLAG_CAPWR: c_int = 0x00004000; +pub const CTLFLAG_STATS: c_int = 0x00002000; +pub const CTLFLAG_NOFETCH: c_int = 0x00001000; +pub const CTLFLAG_CAPRW: c_int = CTLFLAG_CAPRD | CTLFLAG_CAPWR; +pub const CTLFLAG_NEEDGIANT: c_int = 0x00000800; + +pub const CTLSHIFT_SECURE: c_int = 20; +pub const CTLFLAG_SECURE1: c_int = CTLFLAG_SECURE | (0 << CTLSHIFT_SECURE); +pub const CTLFLAG_SECURE2: c_int = CTLFLAG_SECURE | (1 << CTLSHIFT_SECURE); +pub const CTLFLAG_SECURE3: c_int = CTLFLAG_SECURE | (2 << CTLSHIFT_SECURE); + +pub const OID_AUTO: c_int = -1; + +pub const CTL_SYSCTL_DEBUG: c_int = 0; +pub const CTL_SYSCTL_NAME: c_int = 1; +pub const CTL_SYSCTL_NEXT: c_int = 2; +pub const CTL_SYSCTL_NAME2OID: c_int = 3; +pub const CTL_SYSCTL_OIDFMT: c_int = 4; +pub const CTL_SYSCTL_OIDDESCR: c_int = 5; +pub const CTL_SYSCTL_OIDLABEL: c_int = 6; +pub const CTL_SYSCTL_NEXTNOSKIP: c_int = 7; + +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_VNODE: c_int = 13; +pub const KERN_PROC: c_int = 14; +pub const KERN_FILE: c_int = 15; +pub const KERN_PROF: c_int = 16; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_BOOTTIME: c_int = 21; +pub const KERN_NISDOMAINNAME: c_int = 22; +pub const KERN_UPDATEINTERVAL: c_int = 23; +pub const KERN_OSRELDATE: c_int = 24; +pub const KERN_NTP_PLL: c_int = 25; +pub const KERN_BOOTFILE: c_int = 26; +pub const KERN_MAXFILESPERPROC: c_int = 27; +pub const KERN_MAXPROCPERUID: c_int = 28; +pub const KERN_DUMPDEV: c_int = 29; +pub const KERN_IPC: c_int = 30; +pub const KERN_DUMMY: c_int = 31; +pub const KERN_PS_STRINGS: c_int = 32; +pub const KERN_USRSTACK: c_int = 33; +pub const KERN_LOGSIGEXIT: c_int = 34; +pub const KERN_IOV_MAX: c_int = 35; +pub const KERN_HOSTUUID: c_int = 36; +pub const KERN_ARND: c_int = 37; +pub const KERN_MAXPHYS: c_int = 38; + +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_ARGS: c_int = 7; +pub const KERN_PROC_PROC: c_int = 8; +pub const KERN_PROC_SV_NAME: c_int = 9; +pub const KERN_PROC_RGID: c_int = 10; +pub const KERN_PROC_GID: c_int = 11; +pub const KERN_PROC_PATHNAME: c_int = 12; +pub const KERN_PROC_OVMMAP: c_int = 13; +pub const KERN_PROC_OFILEDESC: c_int = 14; +pub const KERN_PROC_KSTACK: c_int = 15; +pub const KERN_PROC_INC_THREAD: c_int = 0x10; +pub const KERN_PROC_VMMAP: c_int = 32; +pub const KERN_PROC_FILEDESC: c_int = 33; +pub const KERN_PROC_GROUPS: c_int = 34; +pub const KERN_PROC_ENV: c_int = 35; +pub const KERN_PROC_AUXV: c_int = 36; +pub const KERN_PROC_RLIMIT: c_int = 37; +pub const KERN_PROC_PS_STRINGS: c_int = 38; +pub const KERN_PROC_UMASK: c_int = 39; +pub const KERN_PROC_OSREL: c_int = 40; +pub const KERN_PROC_SIGTRAMP: c_int = 41; +pub const KERN_PROC_CWD: c_int = 42; +pub const KERN_PROC_NFDS: c_int = 43; +pub const KERN_PROC_SIGFASTBLK: c_int = 44; + +pub const KIPC_MAXSOCKBUF: c_int = 1; +pub const KIPC_SOCKBUF_WASTE: c_int = 2; +pub const KIPC_SOMAXCONN: c_int = 3; +pub const KIPC_MAX_LINKHDR: c_int = 4; +pub const KIPC_MAX_PROTOHDR: c_int = 5; +pub const KIPC_MAX_HDR: c_int = 6; +pub const KIPC_MAX_DATALEN: c_int = 7; + +pub const HW_MACHINE: c_int = 1; +pub const HW_MODEL: c_int = 2; +pub const HW_NCPU: c_int = 3; +pub const HW_BYTEORDER: c_int = 4; +pub const HW_PHYSMEM: c_int = 5; +pub const HW_USERMEM: c_int = 6; +pub const HW_PAGESIZE: c_int = 7; +pub const HW_DISKNAMES: c_int = 8; +pub const HW_DISKSTATS: c_int = 9; +pub const HW_FLOATINGPT: c_int = 10; +pub const HW_MACHINE_ARCH: c_int = 11; +pub const HW_REALMEM: c_int = 12; + +pub const USER_CS_PATH: c_int = 1; +pub const USER_BC_BASE_MAX: c_int = 2; +pub const USER_BC_DIM_MAX: c_int = 3; +pub const USER_BC_SCALE_MAX: c_int = 4; +pub const USER_BC_STRING_MAX: c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: c_int = 6; +pub const USER_EXPR_NEST_MAX: c_int = 7; +pub const USER_LINE_MAX: c_int = 8; +pub const USER_RE_DUP_MAX: c_int = 9; +pub const USER_POSIX2_VERSION: c_int = 10; +pub const USER_POSIX2_C_BIND: c_int = 11; +pub const USER_POSIX2_C_DEV: c_int = 12; +pub const USER_POSIX2_CHAR_TERM: c_int = 13; +pub const USER_POSIX2_FORT_DEV: c_int = 14; +pub const USER_POSIX2_FORT_RUN: c_int = 15; +pub const USER_POSIX2_LOCALEDEF: c_int = 16; +pub const USER_POSIX2_SW_DEV: c_int = 17; +pub const USER_POSIX2_UPE: c_int = 18; +pub const USER_STREAM_MAX: c_int = 19; +pub const USER_TZNAME_MAX: c_int = 20; +pub const USER_LOCALBASE: c_int = 21; + +pub const CTL_P1003_1B_ASYNCHRONOUS_IO: c_int = 1; +pub const CTL_P1003_1B_MAPPED_FILES: c_int = 2; +pub const CTL_P1003_1B_MEMLOCK: c_int = 3; +pub const CTL_P1003_1B_MEMLOCK_RANGE: c_int = 4; +pub const CTL_P1003_1B_MEMORY_PROTECTION: c_int = 5; +pub const CTL_P1003_1B_MESSAGE_PASSING: c_int = 6; +pub const CTL_P1003_1B_PRIORITIZED_IO: c_int = 7; +pub const CTL_P1003_1B_PRIORITY_SCHEDULING: c_int = 8; +pub const CTL_P1003_1B_REALTIME_SIGNALS: c_int = 9; +pub const CTL_P1003_1B_SEMAPHORES: c_int = 10; +pub const CTL_P1003_1B_FSYNC: c_int = 11; +pub const CTL_P1003_1B_SHARED_MEMORY_OBJECTS: c_int = 12; +pub const CTL_P1003_1B_SYNCHRONIZED_IO: c_int = 13; +pub const CTL_P1003_1B_TIMERS: c_int = 14; +pub const CTL_P1003_1B_AIO_LISTIO_MAX: c_int = 15; +pub const CTL_P1003_1B_AIO_MAX: c_int = 16; +pub const CTL_P1003_1B_AIO_PRIO_DELTA_MAX: c_int = 17; +pub const CTL_P1003_1B_DELAYTIMER_MAX: c_int = 18; +pub const CTL_P1003_1B_MQ_OPEN_MAX: c_int = 19; +pub const CTL_P1003_1B_PAGESIZE: c_int = 20; +pub const CTL_P1003_1B_RTSIG_MAX: c_int = 21; +pub const CTL_P1003_1B_SEM_NSEMS_MAX: c_int = 22; +pub const CTL_P1003_1B_SEM_VALUE_MAX: c_int = 23; +pub const CTL_P1003_1B_SIGQUEUE_MAX: c_int = 24; +pub const CTL_P1003_1B_TIMER_MAX: c_int = 25; + +pub const TIOCGPTN: c_ulong = 0x4004740f; +pub const TIOCPTMASTER: c_ulong = 0x2000741c; +pub const TIOCSIG: c_ulong = 0x2004745f; +pub const TIOCM_DCD: c_int = 0x40; +pub const H4DISC: c_int = 0x7; + +pub const VM_TOTAL: c_int = 1; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const BIOCSETFNR: c_ulong = 0x80104282; + } else { + pub const BIOCSETFNR: c_ulong = 0x80084282; + } +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const FIODGNAME: c_ulong = 0x80106678; + } else { + pub const FIODGNAME: c_ulong = 0x80086678; + } +} + +pub const FIONWRITE: c_ulong = 0x40046677; +pub const FIONSPACE: c_ulong = 0x40046676; +pub const FIOSEEKDATA: c_ulong = 0xc0086661; +pub const FIOSEEKHOLE: c_ulong = 0xc0086662; +pub const FIOSSHMLPGCNF: c_ulong = 0x80306664; + +pub const JAIL_API_VERSION: u32 = 2; +pub const JAIL_CREATE: c_int = 0x01; +pub const JAIL_UPDATE: c_int = 0x02; +pub const JAIL_ATTACH: c_int = 0x04; +pub const JAIL_DYING: c_int = 0x08; +pub const JAIL_SYS_DISABLE: c_int = 0; +pub const JAIL_SYS_NEW: c_int = 1; +pub const JAIL_SYS_INHERIT: c_int = 2; + +pub const MNT_ACLS: c_int = 0x08000000; +pub const MNT_BYFSID: c_int = 0x08000000; +pub const MNT_GJOURNAL: c_int = 0x02000000; +pub const MNT_MULTILABEL: c_int = 0x04000000; +pub const MNT_NFS4ACLS: c_int = 0x00000010; +pub const MNT_SNAPSHOT: c_int = 0x01000000; +pub const MNT_UNION: c_int = 0x00000020; +pub const MNT_NONBUSY: c_int = 0x04000000; + +pub const SCM_BINTIME: c_int = 0x04; +pub const SCM_REALTIME: c_int = 0x05; +pub const SCM_MONOTONIC: c_int = 0x06; +pub const SCM_TIME_INFO: c_int = 0x07; +pub const SCM_CREDS2: c_int = 0x08; + +pub const SO_BINTIME: c_int = 0x2000; +pub const SO_NO_OFFLOAD: c_int = 0x4000; +pub const SO_NO_DDP: c_int = 0x8000; +pub const SO_REUSEPORT_LB: c_int = 0x10000; +pub const SO_LABEL: c_int = 0x1009; +pub const SO_PEERLABEL: c_int = 0x1010; +pub const SO_LISTENQLIMIT: c_int = 0x1011; +pub const SO_LISTENQLEN: c_int = 0x1012; +pub const SO_LISTENINCQLEN: c_int = 0x1013; +pub const SO_SETFIB: c_int = 0x1014; +pub const SO_USER_COOKIE: c_int = 0x1015; +pub const SO_PROTOCOL: c_int = 0x1016; +pub const SO_PROTOTYPE: c_int = SO_PROTOCOL; +pub const SO_TS_CLOCK: c_int = 0x1017; +pub const SO_DOMAIN: c_int = 0x1019; +pub const SO_SPLICE: c_int = 0x1023; +pub const SO_VENDOR: c_int = 0x80000000; + +pub const SO_TS_REALTIME_MICRO: c_int = 0; +pub const SO_TS_BINTIME: c_int = 1; +pub const SO_TS_REALTIME: c_int = 2; +pub const SO_TS_MONOTONIC: c_int = 3; +pub const SO_TS_DEFAULT: c_int = SO_TS_REALTIME_MICRO; +pub const SO_TS_CLOCK_MAX: c_int = SO_TS_MONOTONIC; + +pub const LOCAL_CREDS: c_int = 2; +pub const LOCAL_CREDS_PERSISTENT: c_int = 3; +pub const LOCAL_CONNWAIT: c_int = 4; +pub const LOCAL_VENDOR: c_int = SO_VENDOR; + +pub const PL_EVENT_NONE: c_int = 0; +pub const PL_EVENT_SIGNAL: c_int = 1; +pub const PL_FLAG_SA: c_int = 0x01; +pub const PL_FLAG_BOUND: c_int = 0x02; +pub const PL_FLAG_SCE: c_int = 0x04; +pub const PL_FLAG_SCX: c_int = 0x08; +pub const PL_FLAG_EXEC: c_int = 0x10; +pub const PL_FLAG_SI: c_int = 0x20; +pub const PL_FLAG_FORKED: c_int = 0x40; +pub const PL_FLAG_CHILD: c_int = 0x80; +pub const PL_FLAG_BORN: c_int = 0x100; +pub const PL_FLAG_EXITED: c_int = 0x200; +pub const PL_FLAG_VFORKED: c_int = 0x400; +pub const PL_FLAG_VFORK_DONE: c_int = 0x800; + +pub const PT_LWPINFO: c_int = 13; +pub const PT_GETNUMLWPS: c_int = 14; +pub const PT_GETLWPLIST: c_int = 15; +pub const PT_CLEARSTEP: c_int = 16; +pub const PT_SETSTEP: c_int = 17; +pub const PT_SUSPEND: c_int = 18; +pub const PT_RESUME: c_int = 19; +pub const PT_TO_SCE: c_int = 20; +pub const PT_TO_SCX: c_int = 21; +pub const PT_SYSCALL: c_int = 22; +pub const PT_FOLLOW_FORK: c_int = 23; +pub const PT_LWP_EVENTS: c_int = 24; +pub const PT_GET_EVENT_MASK: c_int = 25; +pub const PT_SET_EVENT_MASK: c_int = 26; +pub const PT_GET_SC_ARGS: c_int = 27; +pub const PT_GET_SC_RET: c_int = 28; +pub const PT_COREDUMP: c_int = 29; +pub const PT_GETREGS: c_int = 33; +pub const PT_SETREGS: c_int = 34; +pub const PT_GETFPREGS: c_int = 35; +pub const PT_SETFPREGS: c_int = 36; +pub const PT_GETDBREGS: c_int = 37; +pub const PT_SETDBREGS: c_int = 38; +pub const PT_VM_TIMESTAMP: c_int = 40; +pub const PT_VM_ENTRY: c_int = 41; +pub const PT_GETREGSET: c_int = 42; +pub const PT_SETREGSET: c_int = 43; +pub const PT_SC_REMOTE: c_int = 44; +pub const PT_FIRSTMACH: c_int = 64; + +pub const PTRACE_EXEC: c_int = 0x0001; +pub const PTRACE_SCE: c_int = 0x0002; +pub const PTRACE_SCX: c_int = 0x0004; +pub const PTRACE_SYSCALL: c_int = PTRACE_SCE | PTRACE_SCX; +pub const PTRACE_FORK: c_int = 0x0008; +pub const PTRACE_LWP: c_int = 0x0010; +pub const PTRACE_VFORK: c_int = 0x0020; +pub const PTRACE_DEFAULT: c_int = PTRACE_EXEC; + +pub const PC_COMPRESS: u32 = 0x00000001; +pub const PC_ALL: u32 = 0x00000002; + +pub const PROC_SPROTECT: c_int = 1; +pub const PROC_REAP_ACQUIRE: c_int = 2; +pub const PROC_REAP_RELEASE: c_int = 3; +pub const PROC_REAP_STATUS: c_int = 4; +pub const PROC_REAP_GETPIDS: c_int = 5; +pub const PROC_REAP_KILL: c_int = 6; +pub const PROC_TRACE_CTL: c_int = 7; +pub const PROC_TRACE_STATUS: c_int = 8; +pub const PROC_TRAPCAP_CTL: c_int = 9; +pub const PROC_TRAPCAP_STATUS: c_int = 10; +pub const PROC_PDEATHSIG_CTL: c_int = 11; +pub const PROC_PDEATHSIG_STATUS: c_int = 12; +pub const PROC_ASLR_CTL: c_int = 13; +pub const PROC_ASLR_STATUS: c_int = 14; +pub const PROC_PROTMAX_CTL: c_int = 15; +pub const PROC_PROTMAX_STATUS: c_int = 16; +pub const PROC_STACKGAP_CTL: c_int = 17; +pub const PROC_STACKGAP_STATUS: c_int = 18; +pub const PROC_NO_NEW_PRIVS_CTL: c_int = 19; +pub const PROC_NO_NEW_PRIVS_STATUS: c_int = 20; +pub const PROC_WXMAP_CTL: c_int = 21; +pub const PROC_WXMAP_STATUS: c_int = 22; +pub const PROC_PROCCTL_MD_MIN: c_int = 0x10000000; + +pub const PPROT_SET: c_int = 1; +pub const PPROT_CLEAR: c_int = 2; +pub const PPROT_DESCEND: c_int = 0x10; +pub const PPROT_INHERIT: c_int = 0x20; + +pub const PROC_TRACE_CTL_ENABLE: c_int = 1; +pub const PROC_TRACE_CTL_DISABLE: c_int = 2; +pub const PROC_TRACE_CTL_DISABLE_EXEC: c_int = 3; + +pub const PROC_TRAPCAP_CTL_ENABLE: c_int = 1; +pub const PROC_TRAPCAP_CTL_DISABLE: c_int = 2; + +pub const PROC_ASLR_FORCE_ENABLE: c_int = 1; +pub const PROC_ASLR_FORCE_DISABLE: c_int = 2; +pub const PROC_ASLR_NOFORCE: c_int = 3; +pub const PROC_ASLR_ACTIVE: c_int = 0x80000000; + +pub const PROC_PROTMAX_FORCE_ENABLE: c_int = 1; +pub const PROC_PROTMAX_FORCE_DISABLE: c_int = 2; +pub const PROC_PROTMAX_NOFORCE: c_int = 3; +pub const PROC_PROTMAX_ACTIVE: c_int = 0x80000000; + +pub const PROC_STACKGAP_ENABLE: c_int = 0x0001; +pub const PROC_STACKGAP_DISABLE: c_int = 0x0002; +pub const PROC_STACKGAP_ENABLE_EXEC: c_int = 0x0004; +pub const PROC_STACKGAP_DISABLE_EXEC: c_int = 0x0008; + +pub const PROC_NO_NEW_PRIVS_ENABLE: c_int = 1; +pub const PROC_NO_NEW_PRIVS_DISABLE: c_int = 2; + +pub const PROC_WX_MAPPINGS_PERMIT: c_int = 0x0001; +pub const PROC_WX_MAPPINGS_DISALLOW_EXEC: c_int = 0x0002; +pub const PROC_WXORX_ENFORCE: c_int = 0x80000000; + +pub const AF_SLOW: c_int = 33; +pub const AF_SCLUSTER: c_int = 34; +pub const AF_ARP: c_int = 35; +pub const AF_BLUETOOTH: c_int = 36; +pub const AF_IEEE80211: c_int = 37; +pub const AF_INET_SDP: c_int = 40; +pub const AF_INET6_SDP: c_int = 42; + +// sys/net/if.h +pub const IF_MAXUNIT: c_int = 0x7fff; +/// (n) interface is up +pub const IFF_UP: c_int = 0x1; +/// (i) broadcast address valid +pub const IFF_BROADCAST: c_int = 0x2; +/// (n) turn on debugging +pub const IFF_DEBUG: c_int = 0x4; +/// (i) is a loopback net +pub const IFF_LOOPBACK: c_int = 0x8; +/// (i) is a point-to-point link +pub const IFF_POINTOPOINT: c_int = 0x10; +/// (i) calls if_input in net epoch +#[deprecated(since = "0.2.149", note = "Removed in FreeBSD 14")] +pub const IFF_KNOWSEPOCH: c_int = 0x20; +/// (d) resources allocated +pub const IFF_RUNNING: c_int = 0x40; +#[doc(hidden)] +#[deprecated( + since = "0.2.54", + note = "IFF_DRV_RUNNING is deprecated. Use the portable IFF_RUNNING instead" +)] +/// (d) resources allocate +pub const IFF_DRV_RUNNING: c_int = 0x40; +/// (n) no address resolution protocol +pub const IFF_NOARP: c_int = 0x80; +/// (n) receive all packets +pub const IFF_PROMISC: c_int = 0x100; +/// (n) receive all multicast packets +pub const IFF_ALLMULTI: c_int = 0x200; +/// (d) tx hardware queue is full +pub const IFF_OACTIVE: c_int = 0x400; +#[doc(hidden)] +#[deprecated(since = "0.2.54", note = "Use the portable `IFF_OACTIVE` instead")] +/// (d) tx hardware queue is full +pub const IFF_DRV_OACTIVE: c_int = 0x400; +/// (i) can't hear own transmissions +pub const IFF_SIMPLEX: c_int = 0x800; +/// per link layer defined bit +pub const IFF_LINK0: c_int = 0x1000; +/// per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; +/// per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; +/// use alternate physical connection +pub const IFF_ALTPHYS: c_int = IFF_LINK2; +/// (i) supports multicast +pub const IFF_MULTICAST: c_int = 0x8000; +/// (i) unconfigurable using ioctl(2) +pub const IFF_CANTCONFIG: c_int = 0x10000; +/// (n) user-requested promisc mode +pub const IFF_PPROMISC: c_int = 0x20000; +/// (n) user-requested monitor mode +pub const IFF_MONITOR: c_int = 0x40000; +/// (n) static ARP +pub const IFF_STATICARP: c_int = 0x80000; +/// (n) interface is winding down +pub const IFF_DYING: c_int = 0x200000; +/// (n) interface is being renamed +pub const IFF_RENAMING: c_int = 0x400000; +/// interface is not part of any groups +#[deprecated(since = "0.2.149", note = "Removed in FreeBSD 14")] +pub const IFF_NOGROUP: c_int = 0x800000; + +/// link invalid/unknown +pub const LINK_STATE_UNKNOWN: c_int = 0; +/// link is down +pub const LINK_STATE_DOWN: c_int = 1; +/// link is up +pub const LINK_STATE_UP: c_int = 2; + +/// can offload checksum on RX +pub const IFCAP_RXCSUM: c_int = 0x00001; +/// can offload checksum on TX +pub const IFCAP_TXCSUM: c_int = 0x00002; +/// can be a network console +pub const IFCAP_NETCONS: c_int = 0x00004; +/// VLAN-compatible MTU +pub const IFCAP_VLAN_MTU: c_int = 0x00008; +/// hardware VLAN tag support +pub const IFCAP_VLAN_HWTAGGING: c_int = 0x00010; +/// 9000 byte MTU supported +pub const IFCAP_JUMBO_MTU: c_int = 0x00020; +/// driver supports polling +pub const IFCAP_POLLING: c_int = 0x00040; +/// can do IFCAP_HWCSUM on VLANs +pub const IFCAP_VLAN_HWCSUM: c_int = 0x00080; +/// can do TCP Segmentation Offload +pub const IFCAP_TSO4: c_int = 0x00100; +/// can do TCP6 Segmentation Offload +pub const IFCAP_TSO6: c_int = 0x00200; +/// can do Large Receive Offload +pub const IFCAP_LRO: c_int = 0x00400; +/// wake on any unicast frame +pub const IFCAP_WOL_UCAST: c_int = 0x00800; +/// wake on any multicast frame +pub const IFCAP_WOL_MCAST: c_int = 0x01000; +/// wake on any Magic Packet +pub const IFCAP_WOL_MAGIC: c_int = 0x02000; +/// interface can offload TCP +pub const IFCAP_TOE4: c_int = 0x04000; +/// interface can offload TCP6 +pub const IFCAP_TOE6: c_int = 0x08000; +/// interface hw can filter vlan tag +pub const IFCAP_VLAN_HWFILTER: c_int = 0x10000; +/// can do SIOCGIFCAPNV/SIOCSIFCAPNV +pub const IFCAP_NV: c_int = 0x20000; +/// can do IFCAP_TSO on VLANs +pub const IFCAP_VLAN_HWTSO: c_int = 0x40000; +/// the runtime link state is dynamic +pub const IFCAP_LINKSTATE: c_int = 0x80000; +/// netmap mode supported/enabled +pub const IFCAP_NETMAP: c_int = 0x100000; +/// can offload checksum on IPv6 RX +pub const IFCAP_RXCSUM_IPV6: c_int = 0x200000; +/// can offload checksum on IPv6 TX +pub const IFCAP_TXCSUM_IPV6: c_int = 0x400000; +/// manages counters internally +pub const IFCAP_HWSTATS: c_int = 0x800000; +/// hardware supports TX rate limiting +pub const IFCAP_TXRTLMT: c_int = 0x1000000; +/// hardware rx timestamping +pub const IFCAP_HWRXTSTMP: c_int = 0x2000000; +/// understands M_EXTPG mbufs +pub const IFCAP_MEXTPG: c_int = 0x4000000; +/// can do TLS encryption and segmentation for TCP +pub const IFCAP_TXTLS4: c_int = 0x8000000; +/// can do TLS encryption and segmentation for TCP6 +pub const IFCAP_TXTLS6: c_int = 0x10000000; +/// can do IFCAN_HWCSUM on VXLANs +pub const IFCAP_VXLAN_HWCSUM: c_int = 0x20000000; +/// can do IFCAP_TSO on VXLANs +pub const IFCAP_VXLAN_HWTSO: c_int = 0x40000000; +/// can do TLS with rate limiting +pub const IFCAP_TXTLS_RTLMT: c_int = 0x80000000; + +pub const IFCAP_HWCSUM_IPV6: c_int = IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6; +pub const IFCAP_HWCSUM: c_int = IFCAP_RXCSUM | IFCAP_TXCSUM; +pub const IFCAP_TSO: c_int = IFCAP_TSO4 | IFCAP_TSO6; +pub const IFCAP_WOL: c_int = IFCAP_WOL_UCAST | IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC; +pub const IFCAP_TOE: c_int = IFCAP_TOE4 | IFCAP_TOE6; +pub const IFCAP_TXTLS: c_int = IFCAP_TXTLS4 | IFCAP_TXTLS6; +pub const IFCAP_CANTCHANGE: c_int = IFCAP_NETMAP | IFCAP_NV; + +pub const IFQ_MAXLEN: c_int = 50; +pub const IFNET_SLOWHZ: c_int = 1; + +pub const IFAN_ARRIVAL: c_int = 0; +pub const IFAN_DEPARTURE: c_int = 1; + +pub const IFSTATMAX: c_int = 800; + +pub const RSS_FUNC_NONE: c_int = 0; +pub const RSS_FUNC_PRIVATE: c_int = 1; +pub const RSS_FUNC_TOEPLITZ: c_int = 2; + +pub const RSS_TYPE_IPV4: c_int = 0x00000001; +pub const RSS_TYPE_TCP_IPV4: c_int = 0x00000002; +pub const RSS_TYPE_IPV6: c_int = 0x00000004; +pub const RSS_TYPE_IPV6_EX: c_int = 0x00000008; +pub const RSS_TYPE_TCP_IPV6: c_int = 0x00000010; +pub const RSS_TYPE_TCP_IPV6_EX: c_int = 0x00000020; +pub const RSS_TYPE_UDP_IPV4: c_int = 0x00000040; +pub const RSS_TYPE_UDP_IPV6: c_int = 0x00000080; +pub const RSS_TYPE_UDP_IPV6_EX: c_int = 0x00000100; +pub const RSS_KEYLEN: c_int = 128; + +pub const IFNET_PCP_NONE: c_int = 0xff; +pub const IFDR_MSG_SIZE: c_int = 64; +pub const IFDR_REASON_MSG: c_int = 1; +pub const IFDR_REASON_VENDOR: c_int = 2; + +// sys/net/if_mib.h + +/// non-interface-specific +pub const IFMIB_SYSTEM: c_int = 1; +/// per-interface data table +pub const IFMIB_IFDATA: c_int = 2; + +/// generic stats for all kinds of ifaces +pub const IFDATA_GENERAL: c_int = 1; +/// specific to the type of interface +pub const IFDATA_LINKSPECIFIC: c_int = 2; +/// driver name and unit +pub const IFDATA_DRIVERNAME: c_int = 3; + +/// number of interfaces configured +pub const IFMIB_IFCOUNT: c_int = 1; + +/// functions not specific to a type of iface +pub const NETLINK_GENERIC: c_int = 0; + +pub const DOT3COMPLIANCE_STATS: c_int = 1; +pub const DOT3COMPLIANCE_COLLS: c_int = 2; + +pub const dot3ChipSetAMD7990: c_int = 1; +pub const dot3ChipSetAMD79900: c_int = 2; +pub const dot3ChipSetAMD79C940: c_int = 3; + +pub const dot3ChipSetIntel82586: c_int = 1; +pub const dot3ChipSetIntel82596: c_int = 2; +pub const dot3ChipSetIntel82557: c_int = 3; + +pub const dot3ChipSetNational8390: c_int = 1; +pub const dot3ChipSetNationalSonic: c_int = 2; + +pub const dot3ChipSetFujitsu86950: c_int = 1; + +pub const dot3ChipSetDigitalDC21040: c_int = 1; +pub const dot3ChipSetDigitalDC21140: c_int = 2; +pub const dot3ChipSetDigitalDC21041: c_int = 3; +pub const dot3ChipSetDigitalDC21140A: c_int = 4; +pub const dot3ChipSetDigitalDC21142: c_int = 5; + +pub const dot3ChipSetWesternDigital83C690: c_int = 1; +pub const dot3ChipSetWesternDigital83C790: c_int = 2; + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: c_int = 11; +/// pup +pub const IPPROTO_PUP: c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: c_int = 21; +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: c_int = 30; +/// Network Services +pub const IPPROTO_NSP: c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: c_int = 32; +#[doc(hidden)] +#[deprecated( + since = "0.2.72", + note = "IPPROTO_SEP is deprecated. Use IPPROTO_DCCP instead" +)] +pub const IPPROTO_SEP: c_int = 33; +/// Datagram Congestion Control Protocol +pub const IPPROTO_DCCP: c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: c_int = 35; +/// XTP +pub const IPPROTO_XTP: c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: c_int = 48; +/// BHA +pub const IPPROTO_BHA: c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: c_int = 54; +/// IP Mobility +pub const IPPROTO_MOBILE: c_int = 55; +/// Transport Layer Security +pub const IPPROTO_TLSP: c_int = 56; +/// SKIP +pub const IPPROTO_SKIP: c_int = 57; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: c_int = 83; +/// TTP +pub const IPPROTO_TTP: c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: c_int = 86; +/// TCF +pub const IPPROTO_TCF: c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: c_int = 100; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: c_int = 132; +/// IPv6 Mobility Header +pub const IPPROTO_MH: c_int = 135; +/// UDP-Lite +pub const IPPROTO_UDPLITE: c_int = 136; +/// IP6 Host Identity Protocol +pub const IPPROTO_HIP: c_int = 139; +/// IP6 Shim6 Protocol +pub const IPPROTO_SHIM6: c_int = 140; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: c_int = 103; +/// CARP +pub const IPPROTO_CARP: c_int = 112; +/// PGM +pub const IPPROTO_PGM: c_int = 113; +/// MPLS-in-IP +pub const IPPROTO_MPLS: c_int = 137; +/// PFSYNC +pub const IPPROTO_PFSYNC: c_int = 240; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion, no longer used */ +/// OLD divert pseudo-proto +pub const IPPROTO_OLD_DIVERT: c_int = 254; +pub const IPPROTO_MAX: c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: c_int = 257; + +/* Only used internally, so can be outside the range of valid IP protocols. */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: c_int = 258; +/// SeND pseudo-protocol +pub const IPPROTO_SEND: c_int = 259; + +// sys/netinet/TCP.h +pub const TCP_MD5SIG: c_int = 16; +pub const TCP_INFO: c_int = 32; +pub const TCP_CONGESTION: c_int = 64; +pub const TCP_CCALGOOPT: c_int = 65; +pub const TCP_MAXUNACKTIME: c_int = 68; +#[deprecated(since = "0.2.160", note = "Removed in FreeBSD 15")] +pub const TCP_MAXPEAKRATE: c_int = 69; +pub const TCP_IDLE_REDUCE: c_int = 70; +pub const TCP_REMOTE_UDP_ENCAPS_PORT: c_int = 71; +pub const TCP_DELACK: c_int = 72; +pub const TCP_FIN_IS_RST: c_int = 73; +pub const TCP_LOG_LIMIT: c_int = 74; +pub const TCP_SHARED_CWND_ALLOWED: c_int = 75; +pub const TCP_PROC_ACCOUNTING: c_int = 76; +pub const TCP_USE_CMP_ACKS: c_int = 77; +pub const TCP_PERF_INFO: c_int = 78; +pub const TCP_LRD: c_int = 79; +pub const TCP_KEEPINIT: c_int = 128; +pub const TCP_FASTOPEN: c_int = 1025; +#[deprecated(since = "0.2.171", note = "removed in FreeBSD 15")] +pub const TCP_PCAP_OUT: c_int = 2048; +#[deprecated(since = "0.2.171", note = "removed in FreeBSD 15")] +pub const TCP_PCAP_IN: c_int = 4096; +pub const TCP_FUNCTION_BLK: c_int = 8192; +pub const TCP_FUNCTION_ALIAS: c_int = 8193; +pub const TCP_FASTOPEN_PSK_LEN: c_int = 16; +pub const TCP_FUNCTION_NAME_LEN_MAX: c_int = 32; + +pub const TCP_REUSPORT_LB_NUMA: c_int = 1026; +pub const TCP_RACK_MBUF_QUEUE: c_int = 1050; +pub const TCP_RACK_TLP_REDUCE: c_int = 1052; +pub const TCP_RACK_PACE_MAX_SEG: c_int = 1054; +pub const TCP_RACK_PACE_ALWAYS: c_int = 1055; +pub const TCP_RACK_PRR_SENDALOT: c_int = 1057; +pub const TCP_RACK_MIN_TO: c_int = 1058; +pub const TCP_RACK_EARLY_SEG: c_int = 1060; +pub const TCP_RACK_REORD_THRESH: c_int = 1061; +pub const TCP_RACK_REORD_FADE: c_int = 1062; +pub const TCP_RACK_TLP_THRESH: c_int = 1063; +pub const TCP_RACK_PKT_DELAY: c_int = 1064; +pub const TCP_BBR_IWINTSO: c_int = 1067; +pub const TCP_BBR_STARTUP_PG: c_int = 1069; +pub const TCP_BBR_DRAIN_PG: c_int = 1070; +pub const TCP_BBR_PROBE_RTT_INT: c_int = 1072; +pub const TCP_BBR_STARTUP_LOSS_EXIT: c_int = 1074; +pub const TCP_BBR_TSLIMITS: c_int = 1076; +pub const TCP_BBR_PACE_OH: c_int = 1077; +pub const TCP_BBR_USEDEL_RATE: c_int = 1079; +pub const TCP_BBR_MIN_RTO: c_int = 1080; +pub const TCP_BBR_MAX_RTO: c_int = 1081; +pub const TCP_BBR_ALGORITHM: c_int = 1083; +pub const TCP_BBR_PACE_PER_SEC: c_int = 1086; +pub const TCP_BBR_PACE_DEL_TAR: c_int = 1087; +pub const TCP_BBR_PACE_SEG_MAX: c_int = 1088; +pub const TCP_BBR_PACE_SEG_MIN: c_int = 1089; +pub const TCP_BBR_PACE_CROSS: c_int = 1090; +pub const TCP_BBR_TMR_PACE_OH: c_int = 1096; +pub const TCP_BBR_RACK_RTT_USE: c_int = 1098; +pub const TCP_BBR_RETRAN_WTSO: c_int = 1099; +pub const TCP_BBR_PROBE_RTT_GAIN: c_int = 1101; +pub const TCP_BBR_PROBE_RTT_LEN: c_int = 1102; +pub const TCP_BBR_SEND_IWND_IN_TSO: c_int = 1103; +pub const TCP_BBR_USE_RACK_RR: c_int = 1104; +pub const TCP_BBR_HDWR_PACE: c_int = 1105; +pub const TCP_BBR_UTTER_MAX_TSO: c_int = 1106; +pub const TCP_BBR_EXTRA_STATE: c_int = 1107; +pub const TCP_BBR_FLOOR_MIN_TSO: c_int = 1108; +pub const TCP_BBR_MIN_TOPACEOUT: c_int = 1109; +pub const TCP_BBR_TSTMP_RAISES: c_int = 1110; +pub const TCP_BBR_POLICER_DETECT: c_int = 1111; +pub const TCP_BBR_RACK_INIT_RATE: c_int = 1112; + +pub const IP_BINDANY: c_int = 24; +pub const IP_BINDMULTI: c_int = 25; +pub const IP_RSS_LISTEN_BUCKET: c_int = 26; +pub const IP_ORIGDSTADDR: c_int = 27; +pub const IP_RECVORIGDSTADDR: c_int = IP_ORIGDSTADDR; + +pub const IP_DONTFRAG: c_int = 67; +pub const IP_RECVTOS: c_int = 68; + +pub const IPV6_BINDANY: c_int = 64; +pub const IPV6_ORIGDSTADDR: c_int = 72; +pub const IPV6_RECVORIGDSTADDR: c_int = IPV6_ORIGDSTADDR; + +pub const PF_SLOW: c_int = AF_SLOW; +pub const PF_SCLUSTER: c_int = AF_SCLUSTER; +pub const PF_ARP: c_int = AF_ARP; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_IEEE80211: c_int = AF_IEEE80211; +pub const PF_INET_SDP: c_int = AF_INET_SDP; +pub const PF_INET6_SDP: c_int = AF_INET6_SDP; + +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const NET_RT_IFLIST: c_int = 3; +pub const NET_RT_IFMALIST: c_int = 4; +pub const NET_RT_IFLISTL: c_int = 5; + +// System V IPC +pub const IPC_INFO: c_int = 3; +pub const MSG_NOERROR: c_int = 0o10000; +pub const SHM_LOCK: c_int = 11; +pub const SHM_UNLOCK: c_int = 12; +pub const SHM_STAT: c_int = 13; +pub const SHM_INFO: c_int = 14; +pub const SHM_ANON: *mut c_char = 1 as *mut c_char; + +// The *_MAXID constants never should've been used outside of the +// FreeBSD base system. And with the exception of CTL_P1003_1B_MAXID, +// they were all removed in svn r262489. They remain here for backwards +// compatibility only, and are scheduled to be removed in libc 1.0.0. +#[doc(hidden)] +#[deprecated(since = "0.2.54", note = "Removed in FreeBSD 11")] +pub const CTL_MAXID: c_int = 10; +#[doc(hidden)] +#[deprecated(since = "0.2.54", note = "Removed in FreeBSD 11")] +pub const KERN_MAXID: c_int = 38; +#[doc(hidden)] +#[deprecated(since = "0.2.54", note = "Removed in FreeBSD 11")] +pub const HW_MAXID: c_int = 13; +#[doc(hidden)] +#[deprecated(since = "0.2.54", note = "Removed in FreeBSD 11")] +pub const USER_MAXID: c_int = 21; +#[doc(hidden)] +#[deprecated(since = "0.2.74", note = "Removed in FreeBSD 13")] +pub const CTL_P1003_1B_MAXID: c_int = 26; + +pub const MSG_NOTIFICATION: c_int = 0x00002000; +pub const MSG_NBIO: c_int = 0x00004000; +pub const MSG_COMPAT: c_int = 0x00008000; +pub const MSG_CMSG_CLOEXEC: c_int = 0x00040000; +pub const MSG_NOSIGNAL: c_int = 0x20000; +pub const MSG_WAITFORONE: c_int = 0x00080000; + +// utmpx entry types +pub const EMPTY: c_short = 0; +pub const BOOT_TIME: c_short = 1; +pub const OLD_TIME: c_short = 2; +pub const NEW_TIME: c_short = 3; +pub const USER_PROCESS: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const DEAD_PROCESS: c_short = 7; +pub const SHUTDOWN_TIME: c_short = 8; +// utmp database types +pub const UTXDB_ACTIVE: c_int = 0; +pub const UTXDB_LASTLOGIN: c_int = 1; +pub const UTXDB_LOG: c_int = 2; + +pub const LC_COLLATE_MASK: c_int = 1 << 0; +pub const LC_CTYPE_MASK: c_int = 1 << 1; +pub const LC_MONETARY_MASK: c_int = 1 << 2; +pub const LC_NUMERIC_MASK: c_int = 1 << 3; +pub const LC_TIME_MASK: c_int = 1 << 4; +pub const LC_MESSAGES_MASK: c_int = 1 << 5; +pub const LC_ALL_MASK: c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const WSTOPPED: c_int = 2; // same as WUNTRACED +pub const WCONTINUED: c_int = 4; +pub const WNOWAIT: c_int = 8; +pub const WEXITED: c_int = 16; +pub const WTRAPPED: c_int = 32; + +// FreeBSD defines a great many more of these, we only expose the +// standardized ones. +pub const P_PID: idtype_t = 0; +pub const P_PGID: idtype_t = 2; +pub const P_ALL: idtype_t = 7; + +pub const UTIME_OMIT: c_long = -2; +pub const UTIME_NOW: c_long = -1; + +pub const B460800: crate::speed_t = 460800; +pub const B921600: crate::speed_t = 921600; + +pub const AT_FDCWD: c_int = -100; +pub const AT_EACCESS: c_int = 0x100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: c_int = 0x400; +pub const AT_REMOVEDIR: c_int = 0x800; +pub const AT_RESOLVE_BENEATH: c_int = 0x2000; +pub const AT_EMPTY_PATH: c_int = 0x4000; + +pub const AT_NULL: c_int = 0; +pub const AT_IGNORE: c_int = 1; +pub const AT_EXECFD: c_int = 2; +pub const AT_PHDR: c_int = 3; +pub const AT_PHENT: c_int = 4; +pub const AT_PHNUM: c_int = 5; +pub const AT_PAGESZ: c_int = 6; +pub const AT_BASE: c_int = 7; +pub const AT_FLAGS: c_int = 8; +pub const AT_ENTRY: c_int = 9; +pub const AT_NOTELF: c_int = 10; +pub const AT_UID: c_int = 11; +pub const AT_EUID: c_int = 12; +pub const AT_GID: c_int = 13; +pub const AT_EGID: c_int = 14; +pub const AT_EXECPATH: c_int = 15; +pub const AT_CANARY: c_int = 16; +pub const AT_OSRELDATE: c_int = 18; +pub const AT_NCPUS: c_int = 19; +pub const AT_PAGESIZES: c_int = 20; +pub const AT_TIMEKEEP: c_int = 22; +pub const AT_HWCAP: c_int = 25; +pub const AT_HWCAP2: c_int = 26; +pub const AT_USRSTACKBASE: c_int = 35; +pub const AT_USRSTACKLIM: c_int = 36; +pub const AT_HWCAP3: c_int = 38; +pub const AT_HWCAP4: c_int = 39; + +pub const TABDLY: crate::tcflag_t = 0x00000004; +pub const TAB0: crate::tcflag_t = 0x00000000; +pub const TAB3: crate::tcflag_t = 0x00000004; + +pub const _PC_ACL_NFS4: c_int = 64; + +pub const _SC_CPUSET_SIZE: c_int = 122; + +pub const _UUID_NODE_LEN: usize = 6; + +// Flags which can be passed to pdfork(2) +pub const PD_DAEMON: c_int = 0x00000001; +pub const PD_CLOEXEC: c_int = 0x00000002; +pub const PD_ALLOWED_AT_FORK: c_int = PD_DAEMON | PD_CLOEXEC; + +// Values for struct rtprio (type_ field) +pub const RTP_PRIO_REALTIME: c_ushort = 2; +pub const RTP_PRIO_NORMAL: c_ushort = 3; +pub const RTP_PRIO_IDLE: c_ushort = 4; + +// Flags for chflags(2) +pub const UF_SYSTEM: c_ulong = 0x00000080; +pub const UF_SPARSE: c_ulong = 0x00000100; +pub const UF_OFFLINE: c_ulong = 0x00000200; +pub const UF_REPARSE: c_ulong = 0x00000400; +pub const UF_ARCHIVE: c_ulong = 0x00000800; +pub const UF_READONLY: c_ulong = 0x00001000; +pub const UF_HIDDEN: c_ulong = 0x00008000; +pub const SF_SNAPSHOT: c_ulong = 0x00200000; + +// fcntl commands +pub const F_ADD_SEALS: c_int = 19; +pub const F_GET_SEALS: c_int = 20; +pub const F_OGETLK: c_int = 7; +pub const F_OSETLK: c_int = 8; +pub const F_OSETLKW: c_int = 9; +pub const F_RDAHEAD: c_int = 16; +pub const F_READAHEAD: c_int = 15; +pub const F_SETLK_REMOTE: c_int = 14; +pub const F_KINFO: c_int = 22; + +// for use with F_ADD_SEALS +pub const F_SEAL_GROW: c_int = 4; +pub const F_SEAL_SEAL: c_int = 1; +pub const F_SEAL_SHRINK: c_int = 2; +pub const F_SEAL_WRITE: c_int = 8; + +// for use with fspacectl +pub const SPACECTL_DEALLOC: c_int = 1; + +// For realhostname* api +pub const HOSTNAME_FOUND: c_int = 0; +pub const HOSTNAME_INCORRECTNAME: c_int = 1; +pub const HOSTNAME_INVALIDADDR: c_int = 2; +pub const HOSTNAME_INVALIDNAME: c_int = 3; + +// For rfork +pub const RFFDG: c_int = 4; +pub const RFPROC: c_int = 16; +pub const RFMEM: c_int = 32; +pub const RFNOWAIT: c_int = 64; +pub const RFCFDG: c_int = 4096; +pub const RFTHREAD: c_int = 8192; +pub const RFSIGSHARE: c_int = 16384; +pub const RFLINUXTHPN: c_int = 65536; +pub const RFTSIGZMB: c_int = 524288; +pub const RFSPAWN: c_int = 2147483648; + +// For eventfd +pub const EFD_SEMAPHORE: c_int = 0x1; +pub const EFD_NONBLOCK: c_int = 0x4; +pub const EFD_CLOEXEC: c_int = 0x100000; + +pub const MALLOCX_ZERO: c_int = 0x40; + +/// size of returned wchan message +pub const WMESGLEN: usize = 8; +/// size of returned lock name +pub const LOCKNAMELEN: usize = 8; +/// size of returned thread name +pub const TDNAMLEN: usize = 16; +/// size of returned ki_comm name +pub const COMMLEN: usize = 19; +/// size of returned ki_emul +pub const KI_EMULNAMELEN: usize = 16; +/// number of groups in ki_groups +pub const KI_NGROUPS: usize = 16; +cfg_if! { + if #[cfg(freebsd11)] { + pub const KI_NSPARE_INT: usize = 4; + } else { + pub const KI_NSPARE_INT: usize = 2; + } +} +pub const KI_NSPARE_LONG: usize = 12; +/// Flags for the process credential. +pub const KI_CRF_CAPABILITY_MODE: usize = 0x00000001; +/// Steal a bit from ki_cr_flags to indicate that the cred had more than +/// KI_NGROUPS groups. +pub const KI_CRF_GRP_OVERFLOW: usize = 0x80000000; +/// controlling tty vnode active +pub const KI_CTTY: usize = 0x00000001; +/// session leader +pub const KI_SLEADER: usize = 0x00000002; +/// proc blocked on lock ki_lockname +pub const KI_LOCKBLOCK: usize = 0x00000004; +/// size of returned ki_login +pub const LOGNAMELEN: usize = 17; +/// size of returned ki_loginclass +pub const LOGINCLASSLEN: usize = 17; + +pub const KF_ATTR_VALID: c_int = 0x0001; +pub const KF_TYPE_NONE: c_int = 0; +pub const KF_TYPE_VNODE: c_int = 1; +pub const KF_TYPE_SOCKET: c_int = 2; +pub const KF_TYPE_PIPE: c_int = 3; +pub const KF_TYPE_FIFO: c_int = 4; +pub const KF_TYPE_KQUEUE: c_int = 5; +pub const KF_TYPE_MQUEUE: c_int = 7; +pub const KF_TYPE_SHM: c_int = 8; +pub const KF_TYPE_SEM: c_int = 9; +pub const KF_TYPE_PTS: c_int = 10; +pub const KF_TYPE_PROCDESC: c_int = 11; +pub const KF_TYPE_DEV: c_int = 12; +pub const KF_TYPE_UNKNOWN: c_int = 255; + +pub const KF_VTYPE_VNON: c_int = 0; +pub const KF_VTYPE_VREG: c_int = 1; +pub const KF_VTYPE_VDIR: c_int = 2; +pub const KF_VTYPE_VBLK: c_int = 3; +pub const KF_VTYPE_VCHR: c_int = 4; +pub const KF_VTYPE_VLNK: c_int = 5; +pub const KF_VTYPE_VSOCK: c_int = 6; +pub const KF_VTYPE_VFIFO: c_int = 7; +pub const KF_VTYPE_VBAD: c_int = 8; +pub const KF_VTYPE_UNKNOWN: c_int = 255; + +/// Current working directory +pub const KF_FD_TYPE_CWD: c_int = -1; +/// Root directory +pub const KF_FD_TYPE_ROOT: c_int = -2; +/// Jail directory +pub const KF_FD_TYPE_JAIL: c_int = -3; +/// Ktrace vnode +pub const KF_FD_TYPE_TRACE: c_int = -4; +pub const KF_FD_TYPE_TEXT: c_int = -5; +/// Controlling terminal +pub const KF_FD_TYPE_CTTY: c_int = -6; +pub const KF_FLAG_READ: c_int = 0x00000001; +pub const KF_FLAG_WRITE: c_int = 0x00000002; +pub const KF_FLAG_APPEND: c_int = 0x00000004; +pub const KF_FLAG_ASYNC: c_int = 0x00000008; +pub const KF_FLAG_FSYNC: c_int = 0x00000010; +pub const KF_FLAG_NONBLOCK: c_int = 0x00000020; +pub const KF_FLAG_DIRECT: c_int = 0x00000040; +pub const KF_FLAG_HASLOCK: c_int = 0x00000080; +pub const KF_FLAG_SHLOCK: c_int = 0x00000100; +pub const KF_FLAG_EXLOCK: c_int = 0x00000200; +pub const KF_FLAG_NOFOLLOW: c_int = 0x00000400; +pub const KF_FLAG_CREAT: c_int = 0x00000800; +pub const KF_FLAG_TRUNC: c_int = 0x00001000; +pub const KF_FLAG_EXCL: c_int = 0x00002000; +pub const KF_FLAG_EXEC: c_int = 0x00004000; + +pub const KVME_TYPE_NONE: c_int = 0; +pub const KVME_TYPE_DEFAULT: c_int = 1; +pub const KVME_TYPE_VNODE: c_int = 2; +pub const KVME_TYPE_SWAP: c_int = 3; +pub const KVME_TYPE_DEVICE: c_int = 4; +pub const KVME_TYPE_PHYS: c_int = 5; +pub const KVME_TYPE_DEAD: c_int = 6; +pub const KVME_TYPE_SG: c_int = 7; +pub const KVME_TYPE_MGTDEVICE: c_int = 8; +// Present in `sys/user.h` but is undefined for whatever reason... +// pub const KVME_TYPE_GUARD: c_int = 9; +pub const KVME_TYPE_UNKNOWN: c_int = 255; +pub const KVME_PROT_READ: c_int = 0x00000001; +pub const KVME_PROT_WRITE: c_int = 0x00000002; +pub const KVME_PROT_EXEC: c_int = 0x00000004; +pub const KVME_FLAG_COW: c_int = 0x00000001; +pub const KVME_FLAG_NEEDS_COPY: c_int = 0x00000002; +pub const KVME_FLAG_NOCOREDUMP: c_int = 0x00000004; +pub const KVME_FLAG_SUPER: c_int = 0x00000008; +pub const KVME_FLAG_GROWS_UP: c_int = 0x00000010; +pub const KVME_FLAG_GROWS_DOWN: c_int = 0x00000020; +pub const KVME_FLAG_USER_WIRED: c_int = 0x00000040; + +pub const KKST_MAXLEN: c_int = 1024; +/// Stack is valid. +pub const KKST_STATE_STACKOK: c_int = 0; +/// Stack swapped out. +pub const KKST_STATE_SWAPPED: c_int = 1; +pub const KKST_STATE_RUNNING: c_int = 2; + +// Constants about priority. +pub const PRI_MIN: c_int = 0; +pub const PRI_MAX: c_int = 255; +pub const PRI_MIN_ITHD: c_int = PRI_MIN; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PRI_MAX_ITHD: c_int = PRI_MIN_REALTIME - 1; +pub const PI_REALTIME: c_int = PRI_MIN_ITHD + 0; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_AV: c_int = PRI_MIN_ITHD + 4; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_NET: c_int = PRI_MIN_ITHD + 8; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_DISK: c_int = PRI_MIN_ITHD + 12; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_TTY: c_int = PRI_MIN_ITHD + 16; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_DULL: c_int = PRI_MIN_ITHD + 20; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PI_SOFT: c_int = PRI_MIN_ITHD + 24; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PRI_MIN_REALTIME: c_int = 48; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PRI_MAX_REALTIME: c_int = PRI_MIN_KERN - 1; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PRI_MIN_KERN: c_int = 80; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PRI_MAX_KERN: c_int = PRI_MIN_TIMESHARE - 1; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PSWP: c_int = PRI_MIN_KERN + 0; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PVM: c_int = PRI_MIN_KERN + 4; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PINOD: c_int = PRI_MIN_KERN + 8; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PRIBIO: c_int = PRI_MIN_KERN + 12; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PVFS: c_int = PRI_MIN_KERN + 16; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PZERO: c_int = PRI_MIN_KERN + 20; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PSOCK: c_int = PRI_MIN_KERN + 24; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PWAIT: c_int = PRI_MIN_KERN + 28; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PLOCK: c_int = PRI_MIN_KERN + 32; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PPAUSE: c_int = PRI_MIN_KERN + 36; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const PRI_MIN_TIMESHARE: c_int = 120; +pub const PRI_MAX_TIMESHARE: c_int = PRI_MIN_IDLE - 1; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +#[allow(deprecated)] +pub const PUSER: c_int = PRI_MIN_TIMESHARE; +pub const PRI_MIN_IDLE: c_int = 224; +pub const PRI_MAX_IDLE: c_int = PRI_MAX; + +pub const NZERO: c_int = 0; + +// Resource utilization information. +pub const RUSAGE_THREAD: c_int = 1; + +cfg_if! { + if #[cfg(any(freebsd11, target_pointer_width = "32"))] { + pub const ARG_MAX: c_int = 256 * 1024; + } else { + pub const ARG_MAX: c_int = 2 * 256 * 1024; + } +} +pub const CHILD_MAX: c_int = 40; +/// max command name remembered +pub const MAXCOMLEN: usize = 19; +/// max interpreter file name length +pub const MAXINTERP: c_int = crate::PATH_MAX; +/// max login name length (incl. NUL) +pub const MAXLOGNAME: c_int = 33; +/// max simultaneous processes +pub const MAXUPRC: c_int = CHILD_MAX; +/// max bytes for an exec function +pub const NCARGS: c_int = ARG_MAX; +/// /* max number groups +pub const NGROUPS: c_int = NGROUPS_MAX + 1; +/// max open files per process +pub const NOFILE: c_int = OPEN_MAX; +/// marker for empty group set member +pub const NOGROUP: c_int = 65535; +/// max hostname size +pub const MAXHOSTNAMELEN: c_int = 256; +/// max bytes in term canon input line +pub const MAX_CANON: c_int = 255; +/// max bytes in terminal input +pub const MAX_INPUT: c_int = 255; +/// max bytes in a file name +pub const NAME_MAX: c_int = 255; +pub const MAXSYMLINKS: c_int = 32; +/// max supplemental group id's +pub const NGROUPS_MAX: c_int = 1023; +/// max open files per process +pub const OPEN_MAX: c_int = 64; + +pub const _POSIX_ARG_MAX: c_int = 4096; +pub const _POSIX_LINK_MAX: c_int = 8; +pub const _POSIX_MAX_CANON: c_int = 255; +pub const _POSIX_MAX_INPUT: c_int = 255; +pub const _POSIX_NAME_MAX: c_int = 14; +pub const _POSIX_PIPE_BUF: c_int = 512; +pub const _POSIX_SSIZE_MAX: c_int = 32767; +pub const _POSIX_STREAM_MAX: c_int = 8; + +/// max ibase/obase values in bc(1) +pub const BC_BASE_MAX: c_int = 99; +/// max array elements in bc(1) +pub const BC_DIM_MAX: c_int = 2048; +/// max scale value in bc(1) +pub const BC_SCALE_MAX: c_int = 99; +/// max const string length in bc(1) +pub const BC_STRING_MAX: c_int = 1000; +/// max character class name size +pub const CHARCLASS_NAME_MAX: c_int = 14; +/// max weights for order keyword +pub const COLL_WEIGHTS_MAX: c_int = 10; +/// max expressions nested in expr(1) +pub const EXPR_NEST_MAX: c_int = 32; +/// max bytes in an input line +pub const LINE_MAX: c_int = 2048; +/// max RE's in interval notation +pub const RE_DUP_MAX: c_int = 255; + +pub const _POSIX2_BC_BASE_MAX: c_int = 99; +pub const _POSIX2_BC_DIM_MAX: c_int = 2048; +pub const _POSIX2_BC_SCALE_MAX: c_int = 99; +pub const _POSIX2_BC_STRING_MAX: c_int = 1000; +pub const _POSIX2_CHARCLASS_NAME_MAX: c_int = 14; +pub const _POSIX2_COLL_WEIGHTS_MAX: c_int = 2; +pub const _POSIX2_EQUIV_CLASS_MAX: c_int = 2; +pub const _POSIX2_EXPR_NEST_MAX: c_int = 32; +pub const _POSIX2_LINE_MAX: c_int = 2048; +pub const _POSIX2_RE_DUP_MAX: c_int = 255; + +// sys/proc.h +pub const TDF_BORROWING: c_int = 0x00000001; +pub const TDF_INPANIC: c_int = 0x00000002; +pub const TDF_INMEM: c_int = 0x00000004; +pub const TDF_SINTR: c_int = 0x00000008; +pub const TDF_TIMEOUT: c_int = 0x00000010; +pub const TDF_IDLETD: c_int = 0x00000020; +pub const TDF_CANSWAP: c_int = 0x00000040; +pub const TDF_KTH_SUSP: c_int = 0x00000100; +pub const TDF_ALLPROCSUSP: c_int = 0x00000200; +pub const TDF_BOUNDARY: c_int = 0x00000400; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_ASTPENDING: c_int = 0x00000800; +pub const TDF_SBDRY: c_int = 0x00002000; +pub const TDF_UPIBLOCKED: c_int = 0x00004000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_NEEDSUSPCHK: c_int = 0x00008000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_NEEDRESCHED: c_int = 0x00010000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_NEEDSIGCHK: c_int = 0x00020000; +pub const TDF_NOLOAD: c_int = 0x00040000; +pub const TDF_SERESTART: c_int = 0x00080000; +pub const TDF_THRWAKEUP: c_int = 0x00100000; +pub const TDF_SEINTR: c_int = 0x00200000; +pub const TDF_SWAPINREQ: c_int = 0x00400000; +#[deprecated(since = "0.2.133", note = "Removed in FreeBSD 14")] +pub const TDF_UNUSED23: c_int = 0x00800000; +pub const TDF_SCHED0: c_int = 0x01000000; +pub const TDF_SCHED1: c_int = 0x02000000; +pub const TDF_SCHED2: c_int = 0x04000000; +pub const TDF_SCHED3: c_int = 0x08000000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_ALRMPEND: c_int = 0x10000000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_PROFPEND: c_int = 0x20000000; +#[deprecated(since = "0.2.133", note = "Not stable across OS versions")] +pub const TDF_MACPEND: c_int = 0x40000000; + +pub const TDB_SUSPEND: c_int = 0x00000001; +pub const TDB_XSIG: c_int = 0x00000002; +pub const TDB_USERWR: c_int = 0x00000004; +pub const TDB_SCE: c_int = 0x00000008; +pub const TDB_SCX: c_int = 0x00000010; +pub const TDB_EXEC: c_int = 0x00000020; +pub const TDB_FORK: c_int = 0x00000040; +pub const TDB_STOPATFORK: c_int = 0x00000080; +pub const TDB_CHILD: c_int = 0x00000100; +pub const TDB_BORN: c_int = 0x00000200; +pub const TDB_EXIT: c_int = 0x00000400; +pub const TDB_VFORK: c_int = 0x00000800; +pub const TDB_FSTP: c_int = 0x00001000; +pub const TDB_STEP: c_int = 0x00002000; + +pub const TDP_OLDMASK: c_int = 0x00000001; +pub const TDP_INKTR: c_int = 0x00000002; +pub const TDP_INKTRACE: c_int = 0x00000004; +pub const TDP_BUFNEED: c_int = 0x00000008; +pub const TDP_COWINPROGRESS: c_int = 0x00000010; +pub const TDP_ALTSTACK: c_int = 0x00000020; +pub const TDP_DEADLKTREAT: c_int = 0x00000040; +pub const TDP_NOFAULTING: c_int = 0x00000080; +pub const TDP_OWEUPC: c_int = 0x00000200; +pub const TDP_ITHREAD: c_int = 0x00000400; +pub const TDP_SYNCIO: c_int = 0x00000800; +pub const TDP_SCHED1: c_int = 0x00001000; +pub const TDP_SCHED2: c_int = 0x00002000; +pub const TDP_SCHED3: c_int = 0x00004000; +pub const TDP_SCHED4: c_int = 0x00008000; +pub const TDP_GEOM: c_int = 0x00010000; +pub const TDP_SOFTDEP: c_int = 0x00020000; +pub const TDP_NORUNNINGBUF: c_int = 0x00040000; +pub const TDP_WAKEUP: c_int = 0x00080000; +pub const TDP_INBDFLUSH: c_int = 0x00100000; +pub const TDP_KTHREAD: c_int = 0x00200000; +pub const TDP_CALLCHAIN: c_int = 0x00400000; +pub const TDP_IGNSUSP: c_int = 0x00800000; +pub const TDP_AUDITREC: c_int = 0x01000000; +pub const TDP_RFPPWAIT: c_int = 0x02000000; +pub const TDP_RESETSPUR: c_int = 0x04000000; +pub const TDP_NERRNO: c_int = 0x08000000; +pub const TDP_EXECVMSPC: c_int = 0x40000000; + +pub const TDI_SUSPENDED: c_int = 0x0001; +pub const TDI_SLEEPING: c_int = 0x0002; +pub const TDI_SWAPPED: c_int = 0x0004; +pub const TDI_LOCK: c_int = 0x0008; +pub const TDI_IWAIT: c_int = 0x0010; + +pub const P_ADVLOCK: c_int = 0x00000001; +pub const P_CONTROLT: c_int = 0x00000002; +pub const P_KPROC: c_int = 0x00000004; +#[deprecated(since = "1.0", note = "Replaced in FreeBSD 15 by P_IDLEPROC")] +pub const P_UNUSED3: c_int = 0x00000008; +#[cfg(freebsd15)] +pub const P_IDLEPROC: c_int = 0x00000008; +pub const P_PPWAIT: c_int = 0x00000010; +pub const P_PROFIL: c_int = 0x00000020; +pub const P_STOPPROF: c_int = 0x00000040; +pub const P_HADTHREADS: c_int = 0x00000080; +pub const P_SUGID: c_int = 0x00000100; +pub const P_SYSTEM: c_int = 0x00000200; +pub const P_SINGLE_EXIT: c_int = 0x00000400; +pub const P_TRACED: c_int = 0x00000800; +pub const P_WAITED: c_int = 0x00001000; +pub const P_WEXIT: c_int = 0x00002000; +pub const P_EXEC: c_int = 0x00004000; +pub const P_WKILLED: c_int = 0x00008000; +pub const P_CONTINUED: c_int = 0x00010000; +pub const P_STOPPED_SIG: c_int = 0x00020000; +pub const P_STOPPED_TRACE: c_int = 0x00040000; +pub const P_STOPPED_SINGLE: c_int = 0x00080000; +pub const P_PROTECTED: c_int = 0x00100000; +pub const P_SIGEVENT: c_int = 0x00200000; +pub const P_SINGLE_BOUNDARY: c_int = 0x00400000; +pub const P_HWPMC: c_int = 0x00800000; +pub const P_JAILED: c_int = 0x01000000; +pub const P_TOTAL_STOP: c_int = 0x02000000; +pub const P_INEXEC: c_int = 0x04000000; +pub const P_STATCHILD: c_int = 0x08000000; +pub const P_INMEM: c_int = 0x10000000; +pub const P_SWAPPINGOUT: c_int = 0x20000000; +pub const P_SWAPPINGIN: c_int = 0x40000000; +pub const P_PPTRACE: c_int = 0x80000000; +pub const P_STOPPED: c_int = P_STOPPED_SIG | P_STOPPED_SINGLE | P_STOPPED_TRACE; + +pub const P2_INHERIT_PROTECTED: c_int = 0x00000001; +pub const P2_NOTRACE: c_int = 0x00000002; +pub const P2_NOTRACE_EXEC: c_int = 0x00000004; +pub const P2_AST_SU: c_int = 0x00000008; +pub const P2_PTRACE_FSTP: c_int = 0x00000010; +pub const P2_TRAPCAP: c_int = 0x00000020; +pub const P2_STKGAP_DISABLE: c_int = 0x00000800; +pub const P2_STKGAP_DISABLE_EXEC: c_int = 0x00001000; + +pub const P_TREE_ORPHANED: c_int = 0x00000001; +pub const P_TREE_FIRST_ORPHAN: c_int = 0x00000002; +pub const P_TREE_REAPER: c_int = 0x00000004; + +pub const SIDL: c_char = 1; +pub const SRUN: c_char = 2; +pub const SSLEEP: c_char = 3; +pub const SSTOP: c_char = 4; +pub const SZOMB: c_char = 5; +pub const SWAIT: c_char = 6; +pub const SLOCK: c_char = 7; + +pub const P_MAGIC: c_int = 0xbeefface; + +pub const TDP_SIGFASTBLOCK: c_int = 0x00000100; +pub const TDP_UIOHELD: c_int = 0x10000000; +pub const TDP_SIGFASTPENDING: c_int = 0x80000000; +pub const TDP2_COMPAT32RB: c_int = 0x00000002; +pub const P2_PROTMAX_ENABLE: c_int = 0x00000200; +pub const P2_PROTMAX_DISABLE: c_int = 0x00000400; +pub const TDP2_SBPAGES: c_int = 0x00000001; +pub const P2_ASLR_ENABLE: c_int = 0x00000040; +pub const P2_ASLR_DISABLE: c_int = 0x00000080; +pub const P2_ASLR_IGNSTART: c_int = 0x00000100; +pub const P_TREE_GRPEXITED: c_int = 0x00000008; + +// libprocstat.h +pub const PS_FST_VTYPE_VNON: c_int = 1; +pub const PS_FST_VTYPE_VREG: c_int = 2; +pub const PS_FST_VTYPE_VDIR: c_int = 3; +pub const PS_FST_VTYPE_VBLK: c_int = 4; +pub const PS_FST_VTYPE_VCHR: c_int = 5; +pub const PS_FST_VTYPE_VLNK: c_int = 6; +pub const PS_FST_VTYPE_VSOCK: c_int = 7; +pub const PS_FST_VTYPE_VFIFO: c_int = 8; +pub const PS_FST_VTYPE_VBAD: c_int = 9; +pub const PS_FST_VTYPE_UNKNOWN: c_int = 255; + +pub const PS_FST_TYPE_VNODE: c_int = 1; +pub const PS_FST_TYPE_FIFO: c_int = 2; +pub const PS_FST_TYPE_SOCKET: c_int = 3; +pub const PS_FST_TYPE_PIPE: c_int = 4; +pub const PS_FST_TYPE_PTS: c_int = 5; +pub const PS_FST_TYPE_KQUEUE: c_int = 6; +pub const PS_FST_TYPE_MQUEUE: c_int = 8; +pub const PS_FST_TYPE_SHM: c_int = 9; +pub const PS_FST_TYPE_SEM: c_int = 10; +pub const PS_FST_TYPE_UNKNOWN: c_int = 11; +pub const PS_FST_TYPE_NONE: c_int = 12; +pub const PS_FST_TYPE_PROCDESC: c_int = 13; +pub const PS_FST_TYPE_DEV: c_int = 14; +pub const PS_FST_TYPE_EVENTFD: c_int = 15; + +pub const PS_FST_UFLAG_RDIR: c_int = 0x0001; +pub const PS_FST_UFLAG_CDIR: c_int = 0x0002; +pub const PS_FST_UFLAG_JAIL: c_int = 0x0004; +pub const PS_FST_UFLAG_TRACE: c_int = 0x0008; +pub const PS_FST_UFLAG_TEXT: c_int = 0x0010; +pub const PS_FST_UFLAG_MMAP: c_int = 0x0020; +pub const PS_FST_UFLAG_CTTY: c_int = 0x0040; + +pub const PS_FST_FFLAG_READ: c_int = 0x0001; +pub const PS_FST_FFLAG_WRITE: c_int = 0x0002; +pub const PS_FST_FFLAG_NONBLOCK: c_int = 0x0004; +pub const PS_FST_FFLAG_APPEND: c_int = 0x0008; +pub const PS_FST_FFLAG_SHLOCK: c_int = 0x0010; +pub const PS_FST_FFLAG_EXLOCK: c_int = 0x0020; +pub const PS_FST_FFLAG_ASYNC: c_int = 0x0040; +pub const PS_FST_FFLAG_SYNC: c_int = 0x0080; +pub const PS_FST_FFLAG_NOFOLLOW: c_int = 0x0100; +pub const PS_FST_FFLAG_CREAT: c_int = 0x0200; +pub const PS_FST_FFLAG_TRUNC: c_int = 0x0400; +pub const PS_FST_FFLAG_EXCL: c_int = 0x0800; +pub const PS_FST_FFLAG_DIRECT: c_int = 0x1000; +pub const PS_FST_FFLAG_EXEC: c_int = 0x2000; +pub const PS_FST_FFLAG_HASLOCK: c_int = 0x4000; + +// sys/mount.h + +/// File identifier. +/// These are unique per filesystem on a single machine. +/// +/// Note that the offset of fid_data is 4 bytes, so care must be taken to avoid +/// undefined behavior accessing unaligned fields within an embedded struct. +pub const MAXFIDSZ: c_int = 16; +/// Length of type name including null. +pub const MFSNAMELEN: c_int = 16; +cfg_if! { + if #[cfg(any(freebsd10, freebsd11))] { + /// Size of on/from name bufs. + pub const MNAMELEN: c_int = 88; + } else { + /// Size of on/from name bufs. + pub const MNAMELEN: c_int = 1024; + } +} + +/// Using journaled soft updates. +pub const MNT_SUJ: u64 = 0x100000000; +/// Mounted by automountd(8). +pub const MNT_AUTOMOUNTED: u64 = 0x200000000; +/// Filesys metadata untrusted. +pub const MNT_UNTRUSTED: u64 = 0x800000000; + +/// Require TLS. +pub const MNT_EXTLS: u64 = 0x4000000000; +/// Require TLS with client cert. +pub const MNT_EXTLSCERT: u64 = 0x8000000000; +/// Require TLS with user cert. +pub const MNT_EXTLSCERTUSER: u64 = 0x10000000000; + +/// Filesystem is stored locally. +pub const MNT_LOCAL: u64 = 0x000001000; +/// Quotas are enabled on fs. +pub const MNT_QUOTA: u64 = 0x000002000; +/// Identifies the root fs. +pub const MNT_ROOTFS: u64 = 0x000004000; +/// Mounted by a user. +pub const MNT_USER: u64 = 0x000008000; +/// Do not show entry in df. +pub const MNT_IGNORE: u64 = 0x000800000; +/// Filesystem is verified. +pub const MNT_VERIFIED: u64 = 0x400000000; + +/// Do not cover a mount point. +pub const MNT_NOCOVER: u64 = 0x001000000000; +/// Only mount on empty dir. +pub const MNT_EMPTYDIR: u64 = 0x002000000000; +/// Recursively unmount uppers. +pub const MNT_RECURSE: u64 = 0x100000000000; +/// Unmount in async context. +pub const MNT_DEFERRED: u64 = 0x200000000000; + +/// Get configured filesystems. +pub const VFS_VFSCONF: c_int = 0; +/// Generic filesystem information. +pub const VFS_GENERIC: c_int = 0; + +/// int: highest defined filesystem type. +pub const VFS_MAXTYPENUM: c_int = 1; +/// struct: vfsconf for filesystem given as next argument. +pub const VFS_CONF: c_int = 2; + +/// Synchronously wait for I/O to complete. +pub const MNT_WAIT: c_int = 1; +/// Start all I/O, but do not wait for it. +pub const MNT_NOWAIT: c_int = 2; +/// Push data not written by filesystem syncer. +pub const MNT_LAZY: c_int = 3; +/// Suspend file system after sync. +pub const MNT_SUSPEND: c_int = 4; + +pub const MAXSECFLAVORS: c_int = 5; + +/// Statically compiled into kernel. +pub const VFCF_STATIC: c_int = 0x00010000; +/// May get data over the network. +pub const VFCF_NETWORK: c_int = 0x00020000; +/// Writes are not implemented. +pub const VFCF_READONLY: c_int = 0x00040000; +/// Data does not represent real files. +pub const VFCF_SYNTHETIC: c_int = 0x00080000; +/// Aliases some other mounted FS. +pub const VFCF_LOOPBACK: c_int = 0x00100000; +/// Stores file names as Unicode. +pub const VFCF_UNICODE: c_int = 0x00200000; +/// Can be mounted from within a jail. +pub const VFCF_JAIL: c_int = 0x00400000; +/// Supports delegated administration. +pub const VFCF_DELEGADMIN: c_int = 0x00800000; +/// Stop at Boundary: defer stop requests to kernel->user (AST) transition. +pub const VFCF_SBDRY: c_int = 0x01000000; + +// time.h + +/// not on dst +pub const DST_NONE: c_int = 0; +/// USA style dst +pub const DST_USA: c_int = 1; +/// Australian style dst +pub const DST_AUST: c_int = 2; +/// Western European dst +pub const DST_WET: c_int = 3; +/// Middle European dst +pub const DST_MET: c_int = 4; +/// Eastern European dst +pub const DST_EET: c_int = 5; +/// Canada +pub const DST_CAN: c_int = 6; + +pub const CPUCLOCK_WHICH_PID: c_int = 0; +pub const CPUCLOCK_WHICH_TID: c_int = 1; + +pub const MFD_CLOEXEC: c_uint = 0x00000001; +pub const MFD_ALLOW_SEALING: c_uint = 0x00000002; +pub const MFD_HUGETLB: c_uint = 0x00000004; +pub const MFD_HUGE_MASK: c_uint = 0xFC000000; +pub const MFD_HUGE_64KB: c_uint = 16 << 26; +pub const MFD_HUGE_512KB: c_uint = 19 << 26; +pub const MFD_HUGE_1MB: c_uint = 20 << 26; +pub const MFD_HUGE_2MB: c_uint = 21 << 26; +pub const MFD_HUGE_8MB: c_uint = 23 << 26; +pub const MFD_HUGE_16MB: c_uint = 24 << 26; +pub const MFD_HUGE_32MB: c_uint = 25 << 26; +pub const MFD_HUGE_256MB: c_uint = 28 << 26; +pub const MFD_HUGE_512MB: c_uint = 29 << 26; +pub const MFD_HUGE_1GB: c_uint = 30 << 26; +pub const MFD_HUGE_2GB: c_uint = 31 << 26; +pub const MFD_HUGE_16GB: c_uint = 34 << 26; + +pub const SHM_LARGEPAGE_ALLOC_DEFAULT: c_int = 0; +pub const SHM_LARGEPAGE_ALLOC_NOWAIT: c_int = 1; +pub const SHM_LARGEPAGE_ALLOC_HARD: c_int = 2; +pub const SHM_RENAME_NOREPLACE: c_int = 1 << 0; +pub const SHM_RENAME_EXCHANGE: c_int = 1 << 1; + +// sys/umtx.h + +pub const UMTX_OP_WAIT: c_int = 2; +pub const UMTX_OP_WAKE: c_int = 3; +pub const UMTX_OP_MUTEX_TRYLOCK: c_int = 4; +pub const UMTX_OP_MUTEX_LOCK: c_int = 5; +pub const UMTX_OP_MUTEX_UNLOCK: c_int = 6; +pub const UMTX_OP_SET_CEILING: c_int = 7; +pub const UMTX_OP_CV_WAIT: c_int = 8; +pub const UMTX_OP_CV_SIGNAL: c_int = 9; +pub const UMTX_OP_CV_BROADCAST: c_int = 10; +pub const UMTX_OP_WAIT_UINT: c_int = 11; +pub const UMTX_OP_RW_RDLOCK: c_int = 12; +pub const UMTX_OP_RW_WRLOCK: c_int = 13; +pub const UMTX_OP_RW_UNLOCK: c_int = 14; +pub const UMTX_OP_WAIT_UINT_PRIVATE: c_int = 15; +pub const UMTX_OP_WAKE_PRIVATE: c_int = 16; +pub const UMTX_OP_MUTEX_WAIT: c_int = 17; +pub const UMTX_OP_NWAKE_PRIVATE: c_int = 21; +pub const UMTX_OP_MUTEX_WAKE2: c_int = 22; +pub const UMTX_OP_SEM2_WAIT: c_int = 23; +pub const UMTX_OP_SEM2_WAKE: c_int = 24; +pub const UMTX_OP_SHM: c_int = 25; +pub const UMTX_OP_ROBUST_LISTS: c_int = 26; + +pub const UMTX_ABSTIME: u32 = 1; + +pub const CPU_LEVEL_ROOT: c_int = 1; +pub const CPU_LEVEL_CPUSET: c_int = 2; +pub const CPU_LEVEL_WHICH: c_int = 3; + +pub const CPU_WHICH_TID: c_int = 1; +pub const CPU_WHICH_PID: c_int = 2; +pub const CPU_WHICH_CPUSET: c_int = 3; +pub const CPU_WHICH_IRQ: c_int = 4; +pub const CPU_WHICH_JAIL: c_int = 5; + +// net/route.h +pub const RTF_LLDATA: c_int = 0x400; +pub const RTF_FIXEDMTU: c_int = 0x80000; + +pub const RTM_VERSION: c_int = 5; + +pub const RTAX_MAX: c_int = 8; + +// sys/signal.h +pub const SIGTHR: c_int = 32; +pub const SIGLWP: c_int = SIGTHR; +pub const SIGLIBRT: c_int = 33; + +// netinet/sctp.h +pub const SCTP_FUTURE_ASSOC: c_int = 0; +pub const SCTP_CURRENT_ASSOC: c_int = 1; +pub const SCTP_ALL_ASSOC: c_int = 2; + +pub const SCTP_NO_NEXT_MSG: c_int = 0x0000; +pub const SCTP_NEXT_MSG_AVAIL: c_int = 0x0001; +pub const SCTP_NEXT_MSG_ISCOMPLETE: c_int = 0x0002; +pub const SCTP_NEXT_MSG_IS_UNORDERED: c_int = 0x0004; +pub const SCTP_NEXT_MSG_IS_NOTIFICATION: c_int = 0x0008; + +pub const SCTP_RECVV_NOINFO: c_int = 0; +pub const SCTP_RECVV_RCVINFO: c_int = 1; +pub const SCTP_RECVV_NXTINFO: c_int = 2; +pub const SCTP_RECVV_RN: c_int = 3; + +pub const SCTP_SENDV_NOINFO: c_int = 0; +pub const SCTP_SENDV_SNDINFO: c_int = 1; +pub const SCTP_SENDV_PRINFO: c_int = 2; +pub const SCTP_SENDV_AUTHINFO: c_int = 3; +pub const SCTP_SENDV_SPA: c_int = 4; + +pub const SCTP_SEND_SNDINFO_VALID: c_int = 0x00000001; +pub const SCTP_SEND_PRINFO_VALID: c_int = 0x00000002; +pub const SCTP_SEND_AUTHINFO_VALID: c_int = 0x00000004; + +pub const SCTP_NOTIFICATION: c_int = 0x0010; +pub const SCTP_COMPLETE: c_int = 0x0020; +pub const SCTP_EOF: c_int = 0x0100; +pub const SCTP_ABORT: c_int = 0x0200; +pub const SCTP_UNORDERED: c_int = 0x0400; +pub const SCTP_ADDR_OVER: c_int = 0x0800; +pub const SCTP_SENDALL: c_int = 0x1000; +pub const SCTP_EOR: c_int = 0x2000; +pub const SCTP_SACK_IMMEDIATELY: c_int = 0x4000; +pub const SCTP_PR_SCTP_NONE: c_int = 0x0000; +pub const SCTP_PR_SCTP_TTL: c_int = 0x0001; +pub const SCTP_PR_SCTP_PRIO: c_int = 0x0002; +pub const SCTP_PR_SCTP_BUF: c_int = SCTP_PR_SCTP_PRIO; +pub const SCTP_PR_SCTP_RTX: c_int = 0x0003; +pub const SCTP_PR_SCTP_MAX: c_int = SCTP_PR_SCTP_RTX; +pub const SCTP_PR_SCTP_ALL: c_int = 0x000f; + +pub const SCTP_INIT: c_int = 0x0001; +pub const SCTP_SNDRCV: c_int = 0x0002; +pub const SCTP_EXTRCV: c_int = 0x0003; +pub const SCTP_SNDINFO: c_int = 0x0004; +pub const SCTP_RCVINFO: c_int = 0x0005; +pub const SCTP_NXTINFO: c_int = 0x0006; +pub const SCTP_PRINFO: c_int = 0x0007; +pub const SCTP_AUTHINFO: c_int = 0x0008; +pub const SCTP_DSTADDRV4: c_int = 0x0009; +pub const SCTP_DSTADDRV6: c_int = 0x000a; + +pub const SCTP_RTOINFO: c_int = 0x00000001; +pub const SCTP_ASSOCINFO: c_int = 0x00000002; +pub const SCTP_INITMSG: c_int = 0x00000003; +pub const SCTP_NODELAY: c_int = 0x00000004; +pub const SCTP_AUTOCLOSE: c_int = 0x00000005; +pub const SCTP_SET_PEER_PRIMARY_ADDR: c_int = 0x00000006; +pub const SCTP_PRIMARY_ADDR: c_int = 0x00000007; +pub const SCTP_ADAPTATION_LAYER: c_int = 0x00000008; +pub const SCTP_ADAPTION_LAYER: c_int = 0x00000008; +pub const SCTP_DISABLE_FRAGMENTS: c_int = 0x00000009; +pub const SCTP_PEER_ADDR_PARAMS: c_int = 0x0000000a; +pub const SCTP_DEFAULT_SEND_PARAM: c_int = 0x0000000b; +pub const SCTP_EVENTS: c_int = 0x0000000c; +pub const SCTP_I_WANT_MAPPED_V4_ADDR: c_int = 0x0000000d; +pub const SCTP_MAXSEG: c_int = 0x0000000e; +pub const SCTP_DELAYED_SACK: c_int = 0x0000000f; +pub const SCTP_FRAGMENT_INTERLEAVE: c_int = 0x00000010; +pub const SCTP_PARTIAL_DELIVERY_POINT: c_int = 0x00000011; +pub const SCTP_AUTH_CHUNK: c_int = 0x00000012; +pub const SCTP_AUTH_KEY: c_int = 0x00000013; +pub const SCTP_HMAC_IDENT: c_int = 0x00000014; +pub const SCTP_AUTH_ACTIVE_KEY: c_int = 0x00000015; +pub const SCTP_AUTH_DELETE_KEY: c_int = 0x00000016; +pub const SCTP_USE_EXT_RCVINFO: c_int = 0x00000017; +pub const SCTP_AUTO_ASCONF: c_int = 0x00000018; +pub const SCTP_MAXBURST: c_int = 0x00000019; +pub const SCTP_MAX_BURST: c_int = 0x00000019; +pub const SCTP_CONTEXT: c_int = 0x0000001a; +pub const SCTP_EXPLICIT_EOR: c_int = 0x00000001b; +pub const SCTP_REUSE_PORT: c_int = 0x00000001c; +pub const SCTP_AUTH_DEACTIVATE_KEY: c_int = 0x00000001d; +pub const SCTP_EVENT: c_int = 0x0000001e; +pub const SCTP_RECVRCVINFO: c_int = 0x0000001f; +pub const SCTP_RECVNXTINFO: c_int = 0x00000020; +pub const SCTP_DEFAULT_SNDINFO: c_int = 0x00000021; +pub const SCTP_DEFAULT_PRINFO: c_int = 0x00000022; +pub const SCTP_PEER_ADDR_THLDS: c_int = 0x00000023; +pub const SCTP_REMOTE_UDP_ENCAPS_PORT: c_int = 0x00000024; +pub const SCTP_ECN_SUPPORTED: c_int = 0x00000025; +pub const SCTP_AUTH_SUPPORTED: c_int = 0x00000027; +pub const SCTP_ASCONF_SUPPORTED: c_int = 0x00000028; +pub const SCTP_RECONFIG_SUPPORTED: c_int = 0x00000029; +pub const SCTP_NRSACK_SUPPORTED: c_int = 0x00000030; +pub const SCTP_PKTDROP_SUPPORTED: c_int = 0x00000031; +pub const SCTP_MAX_CWND: c_int = 0x00000032; + +pub const SCTP_STATUS: c_int = 0x00000100; +pub const SCTP_GET_PEER_ADDR_INFO: c_int = 0x00000101; +pub const SCTP_PEER_AUTH_CHUNKS: c_int = 0x00000102; +pub const SCTP_LOCAL_AUTH_CHUNKS: c_int = 0x00000103; +pub const SCTP_GET_ASSOC_NUMBER: c_int = 0x00000104; +pub const SCTP_GET_ASSOC_ID_LIST: c_int = 0x00000105; +pub const SCTP_TIMEOUTS: c_int = 0x00000106; +pub const SCTP_PR_STREAM_STATUS: c_int = 0x00000107; +pub const SCTP_PR_ASSOC_STATUS: c_int = 0x00000108; + +pub const SCTP_COMM_UP: c_int = 0x0001; +pub const SCTP_COMM_LOST: c_int = 0x0002; +pub const SCTP_RESTART: c_int = 0x0003; +pub const SCTP_SHUTDOWN_COMP: c_int = 0x0004; +pub const SCTP_CANT_STR_ASSOC: c_int = 0x0005; + +pub const SCTP_ASSOC_SUPPORTS_PR: c_int = 0x01; +pub const SCTP_ASSOC_SUPPORTS_AUTH: c_int = 0x02; +pub const SCTP_ASSOC_SUPPORTS_ASCONF: c_int = 0x03; +pub const SCTP_ASSOC_SUPPORTS_MULTIBUF: c_int = 0x04; +pub const SCTP_ASSOC_SUPPORTS_RE_CONFIG: c_int = 0x05; +pub const SCTP_ASSOC_SUPPORTS_INTERLEAVING: c_int = 0x06; +pub const SCTP_ASSOC_SUPPORTS_MAX: c_int = 0x06; + +pub const SCTP_ADDR_AVAILABLE: c_int = 0x0001; +pub const SCTP_ADDR_UNREACHABLE: c_int = 0x0002; +pub const SCTP_ADDR_REMOVED: c_int = 0x0003; +pub const SCTP_ADDR_ADDED: c_int = 0x0004; +pub const SCTP_ADDR_MADE_PRIM: c_int = 0x0005; +pub const SCTP_ADDR_CONFIRMED: c_int = 0x0006; + +pub const SCTP_ACTIVE: c_int = 0x0001; +pub const SCTP_INACTIVE: c_int = 0x0002; +pub const SCTP_UNCONFIRMED: c_int = 0x0200; + +pub const SCTP_DATA_UNSENT: c_int = 0x0001; +pub const SCTP_DATA_SENT: c_int = 0x0002; + +pub const SCTP_PARTIAL_DELIVERY_ABORTED: c_int = 0x0001; + +pub const SCTP_AUTH_NEW_KEY: c_int = 0x0001; +pub const SCTP_AUTH_NEWKEY: c_int = SCTP_AUTH_NEW_KEY; +pub const SCTP_AUTH_NO_AUTH: c_int = 0x0002; +pub const SCTP_AUTH_FREE_KEY: c_int = 0x0003; + +pub const SCTP_STREAM_RESET_INCOMING_SSN: c_int = 0x0001; +pub const SCTP_STREAM_RESET_OUTGOING_SSN: c_int = 0x0002; +pub const SCTP_STREAM_RESET_DENIED: c_int = 0x0004; +pub const SCTP_STREAM_RESET_FAILED: c_int = 0x0008; + +pub const SCTP_ASSOC_RESET_DENIED: c_int = 0x0004; +pub const SCTP_ASSOC_RESET_FAILED: c_int = 0x0008; + +pub const SCTP_STREAM_CHANGE_DENIED: c_int = 0x0004; +pub const SCTP_STREAM_CHANGE_FAILED: c_int = 0x0008; + +pub const KENV_DUMP_LOADER: c_int = 4; +pub const KENV_DUMP_STATIC: c_int = 5; + +pub const RB_PAUSE: c_int = 0x100000; +pub const RB_REROOT: c_int = 0x200000; +pub const RB_POWERCYCLE: c_int = 0x400000; +pub const RB_PROBE: c_int = 0x10000000; +pub const RB_MULTIPLE: c_int = 0x20000000; + +// netinet/in_pcb.h +pub const INC_ISIPV6: c_uchar = 0x01; +pub const INC_IPV6MINMTU: c_uchar = 0x02; + +// sys/time.h +pub const CLOCK_BOOTTIME: crate::clockid_t = crate::CLOCK_UPTIME; +pub const CLOCK_REALTIME_COARSE: crate::clockid_t = crate::CLOCK_REALTIME_FAST; +pub const CLOCK_MONOTONIC_COARSE: crate::clockid_t = crate::CLOCK_MONOTONIC_FAST; + +// sys/timerfd.h + +pub const TFD_NONBLOCK: c_int = crate::O_NONBLOCK; +pub const TFD_CLOEXEC: c_int = O_CLOEXEC; +pub const TFD_TIMER_ABSTIME: c_int = 0x01; +pub const TFD_TIMER_CANCEL_ON_SET: c_int = 0x02; + +// sys/unistd.h + +pub const CLOSE_RANGE_CLOEXEC: c_uint = 1 << 2; + +pub const KCMP_FILE: c_int = 100; +pub const KCMP_FILEOBJ: c_int = 101; +pub const KCMP_FILES: c_int = 102; +pub const KCMP_SIGHAND: c_int = 103; +pub const KCMP_VM: c_int = 104; + +pub const fn MAP_ALIGNED(a: c_int) -> c_int { + a << 24 +} + +const fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).add(_ALIGN(size_of::())) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + _ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + _ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next > max { + core::ptr::null_mut::() + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (_ALIGN(size_of::()) + _ALIGN(length as usize)) as c_uint + } + + pub fn MALLOCX_ALIGN(lg: c_uint) -> c_int { + ffsl(lg as c_long - 1) + } + + pub const fn MALLOCX_TCACHE(tc: c_int) -> c_int { + (tc + 2) << 8 as c_int + } + + pub const fn MALLOCX_ARENA(a: c_int) -> c_int { + (a + 1) << 20 as c_int + } + + pub fn SOCKCREDSIZE(ngrps: usize) -> usize { + let ngrps = if ngrps > 0 { ngrps - 1 } else { 0 }; + size_of::() + size_of::() * ngrps + } + + pub fn uname(buf: *mut crate::utsname) -> c_int { + __xuname(256, buf as *mut c_void) + } + + pub fn CPU_ZERO(cpuset: &mut cpuset_t) -> () { + for slot in cpuset.__bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_FILL(cpuset: &mut cpuset_t) -> () { + for slot in cpuset.__bits.iter_mut() { + *slot = !0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpuset_t) -> () { + let bitset_bits = 8 * size_of::(); + let (idx, offset) = (cpu / bitset_bits, cpu % bitset_bits); + cpuset.__bits[idx] |= 1 << offset; + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpuset_t) -> () { + let bitset_bits = 8 * size_of::(); + let (idx, offset) = (cpu / bitset_bits, cpu % bitset_bits); + cpuset.__bits[idx] &= !(1 << offset); + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpuset_t) -> bool { + let bitset_bits = 8 * size_of::(); + let (idx, offset) = (cpu / bitset_bits, cpu % bitset_bits); + 0 != cpuset.__bits[idx] & (1 << offset) + } + + pub fn CPU_COUNT(cpuset: &cpuset_t) -> c_int { + let mut s: u32 = 0; + let cpuset_size = size_of::(); + let bitset_size = size_of::(); + + for i in cpuset.__bits[..(cpuset_size / bitset_size)].iter() { + s += i.count_ones(); + } + s as c_int + } + + pub fn SOCKCRED2SIZE(ngrps: usize) -> usize { + let ngrps = if ngrps > 0 { ngrps - 1 } else { 0 }; + size_of::() + size_of::() * ngrps + } + + pub fn PROT_MAX(x: c_int) -> c_int { + x << 16 + } + + pub fn PROT_MAX_EXTRACT(x: c_int) -> c_int { + (x >> 16) & (crate::PROT_READ | crate::PROT_WRITE | crate::PROT_EXEC) + } +} + +safe_f! { + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 && status != 0x13 + } + + pub const fn INVALID_SINFO_FLAG(x: c_int) -> bool { + (x) & 0xfffffff0 + & !(SCTP_EOF + | SCTP_ABORT + | SCTP_UNORDERED + | SCTP_ADDR_OVER + | SCTP_SENDALL + | SCTP_EOR + | SCTP_SACK_IMMEDIATELY) + != 0 + } + + pub const fn PR_SCTP_POLICY(x: c_int) -> c_int { + x & 0x0f + } + + pub const fn PR_SCTP_ENABLED(x: c_int) -> bool { + PR_SCTP_POLICY(x) != SCTP_PR_SCTP_NONE && PR_SCTP_POLICY(x) != SCTP_PR_SCTP_ALL + } + + pub const fn PR_SCTP_TTL_ENABLED(x: c_int) -> bool { + PR_SCTP_POLICY(x) == SCTP_PR_SCTP_TTL + } + + pub const fn PR_SCTP_BUF_ENABLED(x: c_int) -> bool { + PR_SCTP_POLICY(x) == SCTP_PR_SCTP_BUF + } + + pub const fn PR_SCTP_RTX_ENABLED(x: c_int) -> bool { + PR_SCTP_POLICY(x) == SCTP_PR_SCTP_RTX + } + + pub const fn PR_SCTP_INVALID_POLICY(x: c_int) -> bool { + PR_SCTP_POLICY(x) > SCTP_PR_SCTP_MAX + } + + pub const fn PR_SCTP_VALID_POLICY(x: c_int) -> bool { + PR_SCTP_POLICY(x) <= SCTP_PR_SCTP_MAX + } +} + +cfg_if! { + if #[cfg(not(any(freebsd10, freebsd11)))] { + extern "C" { + pub fn fhlink(fhp: *mut fhandle_t, to: *const c_char) -> c_int; + pub fn fhlinkat(fhp: *mut fhandle_t, tofd: c_int, to: *const c_char) -> c_int; + pub fn fhreadlink(fhp: *mut fhandle_t, buf: *mut c_char, bufsize: size_t) -> c_int; + pub fn getfhat(fd: c_int, path: *mut c_char, fhp: *mut fhandle, flag: c_int) -> c_int; + } + } +} + +extern "C" { + #[cfg_attr(doc, doc(alias = "__errno_location"))] + #[cfg_attr(doc, doc(alias = "errno"))] + pub fn __error() -> *mut c_int; + + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_readv(aiocbp: *mut crate::aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn aio_writev(aiocbp: *mut crate::aiocb) -> c_int; + + pub fn copy_file_range( + infd: c_int, + inoffp: *mut off_t, + outfd: c_int, + outoffp: *mut off_t, + len: size_t, + flags: c_uint, + ) -> ssize_t; + + pub fn devname_r( + dev: crate::dev_t, + mode: crate::mode_t, + buf: *mut c_char, + len: c_int, + ) -> *mut c_char; + + pub fn extattr_delete_fd(fd: c_int, attrnamespace: c_int, attrname: *const c_char) -> c_int; + pub fn extattr_delete_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + ) -> c_int; + pub fn extattr_delete_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + ) -> c_int; + pub fn extattr_get_fd( + fd: c_int, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_get_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_get_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_list_fd( + fd: c_int, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_list_file( + path: *const c_char, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_list_link( + path: *const c_char, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_set_fd( + fd: c_int, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_set_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_set_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> ssize_t; + + pub fn fspacectl( + fd: c_int, + cmd: c_int, + rqsr: *const spacectl_range, + flags: c_int, + rmsr: *mut spacectl_range, + ) -> c_int; + + pub fn jail(jail: *mut crate::jail) -> c_int; + pub fn jail_attach(jid: c_int) -> c_int; + pub fn jail_remove(jid: c_int) -> c_int; + pub fn jail_get(iov: *mut crate::iovec, niov: c_uint, flags: c_int) -> c_int; + pub fn jail_set(iov: *mut crate::iovec, niov: c_uint, flags: c_int) -> c_int; + + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut sigevent, + ) -> c_int; + + pub fn getutxuser(user: *const c_char) -> *mut utmpx; + pub fn setutxdb(_type: c_int, file: *const c_char) -> c_int; + + pub fn aio_waitcomplete(iocbp: *mut *mut aiocb, timeout: *mut crate::timespec) -> ssize_t; + pub fn mq_getfd_np(mqd: crate::mqd_t) -> c_int; + + pub fn waitid( + idtype: idtype_t, + id: crate::id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> crate::key_t; + pub fn shmget(key: crate::key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + pub fn semget(key: crate::key_t, nsems: c_int, semflg: c_int) -> c_int; + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + pub fn semop(semid: c_int, sops: *mut sembuf, nsops: size_t) -> c_int; + pub fn msgctl(msqid: c_int, cmd: c_int, buf: *mut crate::msqid_ds) -> c_int; + pub fn msgget(key: crate::key_t, msgflg: c_int) -> c_int; + pub fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: size_t, msgflg: c_int) -> c_int; + pub fn cfmakesane(termios: *mut crate::termios); + + pub fn pdfork(fdp: *mut c_int, flags: c_int) -> crate::pid_t; + pub fn pdgetpid(fd: c_int, pidp: *mut crate::pid_t) -> c_int; + pub fn pdkill(fd: c_int, signum: c_int) -> c_int; + + pub fn rtprio_thread(function: c_int, lwpid: crate::lwpid_t, rtp: *mut super::rtprio) -> c_int; + + pub fn uuidgen(store: *mut uuid, count: c_int) -> c_int; + + pub fn thr_kill(id: c_long, sig: c_int) -> c_int; + pub fn thr_kill2(pid: crate::pid_t, id: c_long, sig: c_int) -> c_int; + pub fn thr_self(tid: *mut c_long) -> c_int; + pub fn pthread_getthreadid_np() -> c_int; + pub fn pthread_getaffinity_np( + td: crate::pthread_t, + cpusetsize: size_t, + cpusetp: *mut cpuset_t, + ) -> c_int; + pub fn pthread_setaffinity_np( + td: crate::pthread_t, + cpusetsize: size_t, + cpusetp: *const cpuset_t, + ) -> c_int; + + // sched.h linux compatibility api + pub fn sched_getaffinity( + pid: crate::pid_t, + cpusetsz: size_t, + cpuset: *mut crate::cpuset_t, + ) -> c_int; + pub fn sched_setaffinity( + pid: crate::pid_t, + cpusetsz: size_t, + cpuset: *const crate::cpuset_t, + ) -> c_int; + pub fn sched_getcpu() -> c_int; + + pub fn pthread_mutex_consistent(mutex: *mut crate::pthread_mutex_t) -> c_int; + + pub fn pthread_mutexattr_getrobust( + attr: *mut crate::pthread_mutexattr_t, + robust: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setrobust( + attr: *mut crate::pthread_mutexattr_t, + robust: c_int, + ) -> c_int; + + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_timedjoin_np( + thread: crate::pthread_t, + retval: *mut *mut c_void, + abstime: *const crate::timespec, + ) -> c_int; + + #[cfg_attr(all(target_os = "freebsd", freebsd11), link_name = "statfs@FBSD_1.0")] + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + #[cfg_attr(all(target_os = "freebsd", freebsd11), link_name = "fstatfs@FBSD_1.0")] + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + + pub fn dup3(src: c_int, dst: c_int, flags: c_int) -> c_int; + pub fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; + + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: size_t, + flags: c_int, + ) -> ssize_t; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: size_t, + flags: c_int, + timeout: *const crate::timespec, + ) -> ssize_t; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + + pub fn fhopen(fhp: *const fhandle_t, flags: c_int) -> c_int; + pub fn fhstat(fhp: *const fhandle, buf: *mut crate::stat) -> c_int; + pub fn fhstatfs(fhp: *const fhandle_t, buf: *mut crate::statfs) -> c_int; + pub fn getfh(path: *const c_char, fhp: *mut fhandle_t) -> c_int; + pub fn lgetfh(path: *const c_char, fhp: *mut fhandle_t) -> c_int; + pub fn getfsstat(buf: *mut crate::statfs, bufsize: c_long, mode: c_int) -> c_int; + #[cfg_attr( + all(target_os = "freebsd", freebsd11), + link_name = "getmntinfo@FBSD_1.0" + )] + pub fn getmntinfo(mntbufp: *mut *mut crate::statfs, mode: c_int) -> c_int; + pub fn mount( + type_: *const c_char, + dir: *const c_char, + flags: c_int, + data: *mut c_void, + ) -> c_int; + pub fn nmount(iov: *mut crate::iovec, niov: c_uint, flags: c_int) -> c_int; + + pub fn setproctitle(fmt: *const c_char, ...); + pub fn rfork(flags: c_int) -> c_int; + pub fn cpuset_getaffinity( + level: cpulevel_t, + which: cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *mut cpuset_t, + ) -> c_int; + pub fn cpuset_setaffinity( + level: cpulevel_t, + which: cpuwhich_t, + id: crate::id_t, + setsize: size_t, + mask: *const cpuset_t, + ) -> c_int; + pub fn cpuset(setid: *mut crate::cpusetid_t) -> c_int; + pub fn cpuset_getid( + level: cpulevel_t, + which: cpuwhich_t, + id: crate::id_t, + setid: *mut crate::cpusetid_t, + ) -> c_int; + pub fn cpuset_setid(which: cpuwhich_t, id: crate::id_t, setid: crate::cpusetid_t) -> c_int; + pub fn cap_enter() -> c_int; + pub fn cap_getmode(modep: *mut c_uint) -> c_int; + pub fn cap_fcntls_get(fd: c_int, fcntlrightsp: *mut u32) -> c_int; + pub fn cap_fcntls_limit(fd: c_int, fcntlrights: u32) -> c_int; + pub fn cap_ioctls_get(fd: c_int, cmds: *mut u_long, maxcmds: usize) -> isize; + pub fn cap_ioctls_limit(fd: c_int, cmds: *const u_long, ncmds: usize) -> c_int; + pub fn __cap_rights_init(version: c_int, rights: *mut cap_rights_t, ...) -> *mut cap_rights_t; + pub fn __cap_rights_get(version: c_int, fd: c_int, rightsp: *mut cap_rights_t) -> c_int; + pub fn __cap_rights_set(rights: *mut cap_rights_t, ...) -> *mut cap_rights_t; + pub fn __cap_rights_clear(rights: *mut cap_rights_t, ...) -> *mut cap_rights_t; + pub fn __cap_rights_is_set(rights: *const cap_rights_t, ...) -> bool; + pub fn cap_rights_is_valid(rights: *const cap_rights_t) -> bool; + pub fn cap_rights_limit(fd: c_int, rights: *const cap_rights_t) -> c_int; + pub fn cap_rights_merge(dst: *mut cap_rights_t, src: *const cap_rights_t) -> *mut cap_rights_t; + pub fn cap_rights_remove(dst: *mut cap_rights_t, src: *const cap_rights_t) + -> *mut cap_rights_t; + pub fn cap_rights_contains(big: *const cap_rights_t, little: *const cap_rights_t) -> bool; + pub fn cap_sandboxed() -> bool; + + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + + pub fn ffs(value: c_int) -> c_int; + pub fn ffsl(value: c_long) -> c_int; + pub fn ffsll(value: c_longlong) -> c_int; + pub fn fls(value: c_int) -> c_int; + pub fn flsl(value: c_long) -> c_int; + pub fn flsll(value: c_longlong) -> c_int; + pub fn malloc_stats_print( + write_cb: unsafe extern "C" fn(*mut c_void, *const c_char), + cbopaque: *mut c_void, + opt: *const c_char, + ); + pub fn mallctl( + name: *const c_char, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn mallctlnametomib(name: *const c_char, mibp: *mut size_t, miplen: *mut size_t) -> c_int; + pub fn mallctlbymib( + mib: *const size_t, + mible: size_t, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn mallocx(size: size_t, flags: c_int) -> *mut c_void; + pub fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; + pub fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; + pub fn sallocx(ptr: *const c_void, flags: c_int) -> size_t; + pub fn dallocx(ptr: *mut c_void, flags: c_int); + pub fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); + pub fn nallocx(size: size_t, flags: c_int) -> size_t; + + pub fn procctl( + idtype: crate::idtype_t, + id: crate::id_t, + cmd: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn getpagesize() -> c_int; + pub fn getpagesizes(pagesize: *mut size_t, nelem: c_int) -> c_int; + + pub fn clock_getcpuclockid2(arg1: crate::id_t, arg2: c_int, arg3: *mut clockid_t) -> c_int; + pub fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char; + + pub fn shm_create_largepage( + path: *const c_char, + flags: c_int, + psind: c_int, + alloc_policy: c_int, + mode: crate::mode_t, + ) -> c_int; + pub fn shm_rename(path_from: *const c_char, path_to: *const c_char, flags: c_int) -> c_int; + pub fn memfd_create(name: *const c_char, flags: c_uint) -> c_int; + pub fn setaudit(auditinfo: *const auditinfo_t) -> c_int; + + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; + pub fn eventfd_read(fd: c_int, value: *mut eventfd_t) -> c_int; + pub fn eventfd_write(fd: c_int, value: eventfd_t) -> c_int; + + pub fn fdatasync(fd: c_int) -> c_int; + + pub fn elf_aux_info(aux: c_int, buf: *mut c_void, buflen: c_int) -> c_int; + pub fn setproctitle_fast(fmt: *const c_char, ...); + pub fn timingsafe_bcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + pub fn timingsafe_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + + pub fn _umtx_op( + obj: *mut c_void, + op: c_int, + val: c_ulong, + uaddr: *mut c_void, + uaddr2: *mut c_void, + ) -> c_int; + + pub fn sctp_peeloff(s: c_int, id: crate::sctp_assoc_t) -> c_int; + pub fn sctp_bindx(s: c_int, addrs: *mut crate::sockaddr, num: c_int, tpe: c_int) -> c_int; + pub fn sctp_connectx( + s: c_int, + addrs: *const crate::sockaddr, + addrcnt: c_int, + id: *mut crate::sctp_assoc_t, + ) -> c_int; + pub fn sctp_getaddrlen(family: crate::sa_family_t) -> c_int; + pub fn sctp_getpaddrs( + s: c_int, + asocid: crate::sctp_assoc_t, + addrs: *mut *mut crate::sockaddr, + ) -> c_int; + pub fn sctp_freepaddrs(addrs: *mut crate::sockaddr); + pub fn sctp_getladdrs( + s: c_int, + asocid: crate::sctp_assoc_t, + addrs: *mut *mut crate::sockaddr, + ) -> c_int; + pub fn sctp_freeladdrs(addrs: *mut crate::sockaddr); + pub fn sctp_opt_info( + s: c_int, + id: crate::sctp_assoc_t, + opt: c_int, + arg: *mut c_void, + size: *mut crate::socklen_t, + ) -> c_int; + pub fn sctp_sendv( + sd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + addrs: *mut crate::sockaddr, + addrcnt: c_int, + info: *mut c_void, + infolen: crate::socklen_t, + infotype: c_uint, + flags: c_int, + ) -> ssize_t; + pub fn sctp_recvv( + sd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + from: *mut crate::sockaddr, + fromlen: *mut crate::socklen_t, + info: *mut c_void, + infolen: *mut crate::socklen_t, + infotype: *mut c_uint, + flags: *mut c_int, + ) -> ssize_t; + + pub fn timerfd_create(clockid: c_int, flags: c_int) -> c_int; + pub fn timerfd_gettime(fd: c_int, curr_value: *mut itimerspec) -> c_int; + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec, + ) -> c_int; + pub fn closefrom(lowfd: c_int); + pub fn close_range(lowfd: c_uint, highfd: c_uint, flags: c_int) -> c_int; + + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + + pub fn kcmp( + pid1: crate::pid_t, + pid2: crate::pid_t, + type_: c_int, + idx1: c_ulong, + idx2: c_ulong, + ) -> c_int; + pub fn dlvsym( + handle: *mut c_void, + symbol: *const c_char, + version: *const c_char, + ) -> *mut c_void; +} + +#[link(name = "memstat")] +extern "C" { + pub fn memstat_strerror(error: c_int) -> *const c_char; + pub fn memstat_mtl_alloc() -> *mut memory_type_list; + pub fn memstat_mtl_first(list: *mut memory_type_list) -> *mut memory_type; + pub fn memstat_mtl_next(mtp: *mut memory_type) -> *mut memory_type; + pub fn memstat_mtl_find( + list: *mut memory_type_list, + allocator: c_int, + name: *const c_char, + ) -> *mut memory_type; + pub fn memstat_mtl_free(list: *mut memory_type_list); + pub fn memstat_mtl_geterror(list: *mut memory_type_list) -> c_int; + pub fn memstat_get_name(mtp: *const memory_type) -> *const c_char; +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_dpcpu_setcpu(kd: *mut crate::kvm_t, cpu: c_uint) -> c_int; + pub fn kvm_getargv( + kd: *mut crate::kvm_t, + p: *const kinfo_proc, + nchr: c_int, + ) -> *mut *mut c_char; + pub fn kvm_getcptime(kd: *mut crate::kvm_t, cp_time: *mut c_long) -> c_int; + pub fn kvm_getenvv( + kd: *mut crate::kvm_t, + p: *const kinfo_proc, + nchr: c_int, + ) -> *mut *mut c_char; + pub fn kvm_geterr(kd: *mut crate::kvm_t) -> *mut c_char; + pub fn kvm_getmaxcpu(kd: *mut crate::kvm_t) -> c_int; + pub fn kvm_getncpus(kd: *mut crate::kvm_t) -> c_int; + pub fn kvm_getpcpu(kd: *mut crate::kvm_t, cpu: c_int) -> *mut c_void; + pub fn kvm_counter_u64_fetch(kd: *mut crate::kvm_t, base: c_ulong) -> u64; + pub fn kvm_getswapinfo( + kd: *mut crate::kvm_t, + info: *mut kvm_swap, + maxswap: c_int, + flags: c_int, + ) -> c_int; + pub fn kvm_native(kd: *mut crate::kvm_t) -> c_int; + pub fn kvm_nlist(kd: *mut crate::kvm_t, nl: *mut nlist) -> c_int; + pub fn kvm_nlist2(kd: *mut crate::kvm_t, nl: *mut kvm_nlist) -> c_int; + pub fn kvm_read_zpcpu( + kd: *mut crate::kvm_t, + base: c_ulong, + buf: *mut c_void, + size: size_t, + cpu: c_int, + ) -> ssize_t; + pub fn kvm_read2( + kd: *mut crate::kvm_t, + addr: kvaddr_t, + buf: *mut c_void, + nbytes: size_t, + ) -> ssize_t; +} + +#[link(name = "util")] +extern "C" { + pub fn extattr_namespace_to_string(attrnamespace: c_int, string: *mut *mut c_char) -> c_int; + pub fn extattr_string_to_namespace(string: *const c_char, attrnamespace: *mut c_int) -> c_int; + pub fn realhostname(host: *mut c_char, hsize: size_t, ip: *const crate::in_addr) -> c_int; + pub fn realhostname_sa( + host: *mut c_char, + hsize: size_t, + addr: *mut crate::sockaddr, + addrlen: c_int, + ) -> c_int; + + pub fn kld_isloaded(name: *const c_char) -> c_int; + pub fn kld_load(name: *const c_char) -> c_int; + + pub fn kinfo_getvmmap(pid: crate::pid_t, cntp: *mut c_int) -> *mut kinfo_vmentry; + + pub fn hexdump(ptr: *const c_void, length: c_int, hdr: *const c_char, flags: c_int); + pub fn humanize_number( + buf: *mut c_char, + len: size_t, + number: i64, + suffix: *const c_char, + scale: c_int, + flags: c_int, + ) -> c_int; + + pub fn flopen(path: *const c_char, flags: c_int, ...) -> c_int; + pub fn flopenat(fd: c_int, path: *const c_char, flags: c_int, ...) -> c_int; + + pub fn getlocalbase() -> *const c_char; + + pub fn pidfile_open( + path: *const c_char, + mode: crate::mode_t, + pidptr: *mut crate::pid_t, + ) -> *mut crate::pidfh; + pub fn pidfile_write(path: *mut crate::pidfh) -> c_int; + pub fn pidfile_close(path: *mut crate::pidfh) -> c_int; + pub fn pidfile_remove(path: *mut crate::pidfh) -> c_int; + pub fn pidfile_fileno(path: *const crate::pidfh) -> c_int; + // FIXME(freebsd): pidfile_signal in due time (both manpage present and updated image snapshot) +} + +#[link(name = "procstat")] +extern "C" { + pub fn procstat_open_sysctl() -> *mut procstat; + pub fn procstat_getfiles( + procstat: *mut procstat, + kp: *mut kinfo_proc, + mmapped: c_int, + ) -> *mut filestat_list; + pub fn procstat_freefiles(procstat: *mut procstat, head: *mut filestat_list); + pub fn procstat_getprocs( + procstat: *mut procstat, + what: c_int, + arg: c_int, + count: *mut c_uint, + ) -> *mut kinfo_proc; + pub fn procstat_freeprocs(procstat: *mut procstat, p: *mut kinfo_proc); + pub fn procstat_getvmmap( + procstat: *mut procstat, + kp: *mut kinfo_proc, + count: *mut c_uint, + ) -> *mut kinfo_vmentry; + pub fn procstat_freevmmap(procstat: *mut procstat, vmmap: *mut kinfo_vmentry); + pub fn procstat_close(procstat: *mut procstat); + pub fn procstat_freeargv(procstat: *mut procstat); + pub fn procstat_freeenvv(procstat: *mut procstat); + pub fn procstat_freegroups(procstat: *mut procstat, groups: *mut crate::gid_t); + pub fn procstat_freeptlwpinfo(procstat: *mut procstat, pl: *mut ptrace_lwpinfo); + pub fn procstat_getargv( + procstat: *mut procstat, + kp: *mut kinfo_proc, + nchr: size_t, + ) -> *mut *mut c_char; + pub fn procstat_getenvv( + procstat: *mut procstat, + kp: *mut kinfo_proc, + nchr: size_t, + ) -> *mut *mut c_char; + pub fn procstat_getgroups( + procstat: *mut procstat, + kp: *mut kinfo_proc, + count: *mut c_uint, + ) -> *mut crate::gid_t; + pub fn procstat_getosrel( + procstat: *mut procstat, + kp: *mut kinfo_proc, + osrelp: *mut c_int, + ) -> c_int; + pub fn procstat_getpathname( + procstat: *mut procstat, + kp: *mut kinfo_proc, + pathname: *mut c_char, + maxlen: size_t, + ) -> c_int; + pub fn procstat_getrlimit( + procstat: *mut procstat, + kp: *mut kinfo_proc, + which: c_int, + rlimit: *mut crate::rlimit, + ) -> c_int; + pub fn procstat_getumask( + procstat: *mut procstat, + kp: *mut kinfo_proc, + maskp: *mut c_ushort, + ) -> c_int; + pub fn procstat_open_core(filename: *const c_char) -> *mut procstat; + pub fn procstat_open_kvm(nlistf: *const c_char, memf: *const c_char) -> *mut procstat; + pub fn procstat_get_socket_info( + proc_: *mut procstat, + fst: *mut filestat, + sock: *mut sockstat, + errbuf: *mut c_char, + ) -> c_int; + pub fn procstat_get_vnode_info( + proc_: *mut procstat, + fst: *mut filestat, + vn: *mut vnstat, + errbuf: *mut c_char, + ) -> c_int; + pub fn procstat_get_pts_info( + proc_: *mut procstat, + fst: *mut filestat, + pts: *mut ptsstat, + errbuf: *mut c_char, + ) -> c_int; + pub fn procstat_get_shm_info( + proc_: *mut procstat, + fst: *mut filestat, + shm: *mut shmstat, + errbuf: *mut c_char, + ) -> c_int; +} + +#[link(name = "rt")] +extern "C" { + pub fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> c_int; + pub fn timer_delete(timerid: timer_t) -> c_int; + pub fn timer_getoverrun(timerid: timer_t) -> c_int; + pub fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int; + pub fn timer_settime( + timerid: timer_t, + flags: c_int, + value: *const itimerspec, + ovalue: *mut itimerspec, + ) -> c_int; +} + +#[link(name = "devstat")] +extern "C" { + pub fn devstat_getnumdevs(kd: *mut crate::kvm_t) -> c_int; + pub fn devstat_getgeneration(kd: *mut crate::kvm_t) -> c_long; + pub fn devstat_getversion(kd: *mut crate::kvm_t) -> c_int; + pub fn devstat_checkversion(kd: *mut crate::kvm_t) -> c_int; + pub fn devstat_selectdevs( + dev_select: *mut *mut device_selection, + num_selected: *mut c_int, + num_selections: *mut c_int, + select_generation: *mut c_long, + current_generation: c_long, + devices: *mut devstat, + numdevs: c_int, + matches: *mut devstat_match, + num_matches: c_int, + dev_selections: *mut *mut c_char, + num_dev_selections: c_int, + select_mode: devstat_select_mode, + maxshowdevs: c_int, + perf_select: c_int, + ) -> c_int; + pub fn devstat_buildmatch( + match_str: *mut c_char, + matches: *mut *mut devstat_match, + num_matches: *mut c_int, + ) -> c_int; +} + +cfg_if! { + if #[cfg(freebsd15)] { + mod freebsd15; + pub use self::freebsd15::*; + } else if #[cfg(freebsd14)] { + mod freebsd14; + pub use self::freebsd14::*; + } else if #[cfg(freebsd13)] { + mod freebsd13; + pub use self::freebsd13::*; + } else if #[cfg(freebsd12)] { + mod freebsd12; + pub use self::freebsd12::*; + } else if #[cfg(any(freebsd10, freebsd11))] { + mod freebsd11; + pub use self::freebsd11::*; + } else { + // Unknown freebsd version + } +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "powerpc64")] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc.rs new file mode 100644 index 00000000000000..4c0e165af9d243 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc.rs @@ -0,0 +1,30 @@ +use crate::prelude::*; + +pub type clock_t = u32; +pub type wchar_t = i32; +pub type time_t = i64; +pub type suseconds_t = i32; +pub type register_t = i32; + +s! { + #[repr(align(16))] + pub struct mcontext_t { + pub mc_vers: c_int, + pub mc_flags: c_int, + pub mc_onstack: c_int, + pub mc_len: c_int, + pub mc_avec: [u64; 64], + pub mc_av: [u32; 2], + pub mc_frame: [crate::register_t; 42], + pub mc_fpreg: [u64; 33], + pub mc_vsxfpreg: [u64; 32], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 2048; // 512 * 4 +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs new file mode 100644 index 00000000000000..bfc6d5c2ccc2e6 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs @@ -0,0 +1,31 @@ +use crate::prelude::*; + +pub type clock_t = u32; +pub type wchar_t = i32; +pub type time_t = i64; +pub type suseconds_t = i64; +pub type register_t = i64; + +s! { + #[repr(align(16))] + pub struct mcontext_t { + pub mc_vers: c_int, + pub mc_flags: c_int, + pub mc_onstack: c_int, + pub mc_len: c_int, + pub mc_avec: [u64; 64], + pub mc_av: [u32; 2], + pub mc_frame: [crate::register_t; 42], + pub mc_fpreg: [u64; 33], + pub mc_vsxfpreg: [u64; 32], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; + +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 2048; // 512 * 4 +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/riscv64.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/riscv64.rs new file mode 100644 index 00000000000000..e2d7920541d9a9 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/riscv64.rs @@ -0,0 +1,44 @@ +use crate::prelude::*; + +pub type clock_t = i32; +pub type wchar_t = c_int; +pub type time_t = i64; +pub type suseconds_t = c_long; +pub type register_t = i64; + +s! { + pub struct gpregs { + pub gp_ra: crate::register_t, + pub gp_sp: crate::register_t, + pub gp_gp: crate::register_t, + pub gp_tp: crate::register_t, + pub gp_t: [crate::register_t; 7], + pub gp_s: [crate::register_t; 12], + pub gp_a: [crate::register_t; 8], + pub gp_sepc: crate::register_t, + pub gp_sstatus: crate::register_t, + } + + pub struct fpregs { + pub fp_x: [[u64; 2]; 32], + pub fp_fcsr: u64, + pub fp_flags: c_int, + pub pad: c_int, + } + + pub struct mcontext_t { + pub mc_gpregs: gpregs, + pub mc_fpregs: fpregs, + pub mc_flags: c_int, + pub mc_pad: c_int, + pub mc_spare: [u64; 8], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 4096; // 1024 * 4 +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs new file mode 100644 index 00000000000000..a95914d8a49a2c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs @@ -0,0 +1,52 @@ +use crate::prelude::*; + +pub type clock_t = c_ulong; +pub type wchar_t = i32; +pub type time_t = i32; +pub type suseconds_t = i32; +pub type register_t = i32; + +s! { + #[repr(align(16))] + pub struct mcontext_t { + pub mc_onstack: register_t, + pub mc_gs: register_t, + pub mc_fs: register_t, + pub mc_es: register_t, + pub mc_ds: register_t, + pub mc_edi: register_t, + pub mc_esi: register_t, + pub mc_ebp: register_t, + pub mc_isp: register_t, + pub mc_ebx: register_t, + pub mc_edx: register_t, + pub mc_ecx: register_t, + pub mc_eax: register_t, + pub mc_trapno: register_t, + pub mc_err: register_t, + pub mc_eip: register_t, + pub mc_cs: register_t, + pub mc_eflags: register_t, + pub mc_esp: register_t, + pub mc_ss: register_t, + pub mc_len: c_int, + pub mc_fpformat: c_int, + pub mc_ownedfp: c_int, + pub mc_flags: register_t, + pub mc_fpstate: [c_int; 128], + pub mc_fsbase: register_t, + pub mc_gsbase: register_t, + pub mc_xfpustate: register_t, + pub mc_xfpustate_len: register_t, + pub mc_spare2: [c_int; 4], + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const MINSIGSTKSZ: size_t = 2048; // 512 * 4 + +pub const BIOCSRTIMEOUT: c_ulong = 0x8008426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4008426e; +pub const KINFO_FILE_SIZE: c_int = 1392; +pub const TIOCTIMESTAMP: c_ulong = 0x40087459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs new file mode 100644 index 00000000000000..984854261d7644 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs @@ -0,0 +1,187 @@ +use crate::prelude::*; + +pub type clock_t = i32; +pub type wchar_t = i32; +pub type time_t = i64; +pub type suseconds_t = i64; +pub type register_t = i64; + +s! { + pub struct reg32 { + pub r_fs: u32, + pub r_es: u32, + pub r_ds: u32, + pub r_edi: u32, + pub r_esi: u32, + pub r_ebp: u32, + pub r_isp: u32, + pub r_ebx: u32, + pub r_edx: u32, + pub r_ecx: u32, + pub r_eax: u32, + pub r_trapno: u32, + pub r_err: u32, + pub r_eip: u32, + pub r_cs: u32, + pub r_eflags: u32, + pub r_esp: u32, + pub r_ss: u32, + pub r_gs: u32, + } + + pub struct reg { + pub r_r15: i64, + pub r_r14: i64, + pub r_r13: i64, + pub r_r12: i64, + pub r_r11: i64, + pub r_r10: i64, + pub r_r9: i64, + pub r_r8: i64, + pub r_rdi: i64, + pub r_rsi: i64, + pub r_rbp: i64, + pub r_rbx: i64, + pub r_rdx: i64, + pub r_rcx: i64, + pub r_rax: i64, + pub r_trapno: u32, + pub r_fs: u16, + pub r_gs: u16, + pub r_err: u32, + pub r_es: u16, + pub r_ds: u16, + pub r_rip: i64, + pub r_cs: i64, + pub r_rflags: i64, + pub r_rsp: i64, + pub r_ss: i64, + } + + pub struct fpreg32 { + pub fpr_env: [u32; 7], + pub fpr_acc: [[u8; 10]; 8], + pub fpr_ex_sw: u32, + pub fpr_pad: [u8; 64], + } + + pub struct fpreg { + pub fpr_env: [u64; 4], + pub fpr_acc: [[u8; 16]; 8], + pub fpr_xacc: [[u8; 16]; 16], + pub fpr_spare: [u64; 12], + } + + pub struct xmmreg { + pub xmm_env: [u32; 8], + pub xmm_acc: [[u8; 16]; 8], + pub xmm_reg: [[u8; 16]; 8], + pub xmm_pad: [u8; 224], + } + #[repr(align(16))] + #[cfg_attr(not(any(freebsd11, freebsd12, freebsd13, freebsd14)), non_exhaustive)] + pub struct mcontext_t { + pub mc_onstack: register_t, + pub mc_rdi: register_t, + pub mc_rsi: register_t, + pub mc_rdx: register_t, + pub mc_rcx: register_t, + pub mc_r8: register_t, + pub mc_r9: register_t, + pub mc_rax: register_t, + pub mc_rbx: register_t, + pub mc_rbp: register_t, + pub mc_r10: register_t, + pub mc_r11: register_t, + pub mc_r12: register_t, + pub mc_r13: register_t, + pub mc_r14: register_t, + pub mc_r15: register_t, + pub mc_trapno: u32, + pub mc_fs: u16, + pub mc_gs: u16, + pub mc_addr: register_t, + pub mc_flags: u32, + pub mc_es: u16, + pub mc_ds: u16, + pub mc_err: register_t, + pub mc_rip: register_t, + pub mc_cs: register_t, + pub mc_rflags: register_t, + pub mc_rsp: register_t, + pub mc_ss: register_t, + pub mc_len: c_long, + pub mc_fpformat: c_long, + pub mc_ownedfp: c_long, + pub mc_fpstate: [c_long; 64], + pub mc_fsbase: register_t, + pub mc_gsbase: register_t, + pub mc_xfpustate: register_t, + pub mc_xfpustate_len: register_t, + // freebsd < 15 + #[cfg(any(freebsd11, freebsd12, freebsd13))] + pub mc_spare: [c_long; 4], + // freebsd >= 15 + #[cfg(not(any(freebsd11, freebsd12, freebsd13)))] + pub mc_tlsbase: register_t, + #[cfg(not(any(freebsd11, freebsd12, freebsd13)))] + pub mc_spare: [c_long; 3], + } +} + +s_no_extra_traits! { + pub union __c_anonymous_elf64_auxv_union { + pub a_val: c_long, + pub a_ptr: *mut c_void, + pub a_fcn: extern "C" fn(), + } + + pub struct Elf64_Auxinfo { + pub a_type: c_long, + pub a_un: __c_anonymous_elf64_auxv_union, + } + + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + // FIXME(msrv): suggested method was added in 1.85 + #[allow(unpredictable_function_pointer_comparisons)] + impl PartialEq for __c_anonymous_elf64_auxv_union { + fn eq(&self, other: &__c_anonymous_elf64_auxv_union) -> bool { + unsafe { + self.a_val == other.a_val + || self.a_ptr == other.a_ptr + || self.a_fcn == other.a_fcn + } + } + } + impl Eq for __c_anonymous_elf64_auxv_union {} + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const BIOCSRTIMEOUT: c_ulong = 0x8010426d; +pub const BIOCGRTIMEOUT: c_ulong = 0x4010426e; + +pub const MAP_32BIT: c_int = 0x00080000; +pub const MINSIGSTKSZ: size_t = 2048; // 512 * 4 + +pub const _MC_HASSEGS: u32 = 0x1; +pub const _MC_HASBASES: u32 = 0x2; +pub const _MC_HASFPXSTATE: u32 = 0x4; + +pub const _MC_FPFMT_NODEV: c_long = 0x10000; +pub const _MC_FPFMT_XMM: c_long = 0x10002; +pub const _MC_FPOWNED_NONE: c_long = 0x20000; +pub const _MC_FPOWNED_FPU: c_long = 0x20001; +pub const _MC_FPOWNED_PCB: c_long = 0x20002; + +pub const KINFO_FILE_SIZE: c_int = 1392; + +pub const TIOCTIMESTAMP: c_ulong = 0x40107459; diff --git a/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/mod.rs new file mode 100644 index 00000000000000..38fe66a11b8ea4 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/freebsdlike/mod.rs @@ -0,0 +1,1986 @@ +use crate::off_t; +use crate::prelude::*; + +pub type mode_t = u16; +pub type pthread_attr_t = *mut c_void; +pub type rlim_t = i64; +pub type pthread_mutex_t = *mut c_void; +pub type pthread_mutexattr_t = *mut c_void; +pub type pthread_cond_t = *mut c_void; +pub type pthread_condattr_t = *mut c_void; +pub type pthread_rwlock_t = *mut c_void; +pub type pthread_rwlockattr_t = *mut c_void; +pub type pthread_key_t = c_int; +pub type tcflag_t = c_uint; +pub type speed_t = c_uint; +pub type nl_item = c_int; +pub type id_t = i64; +pub type vm_size_t = crate::uintptr_t; +pub type key_t = c_long; + +// elf.h + +pub type Elf32_Addr = u32; +pub type Elf32_Half = u16; +pub type Elf32_Lword = u64; +pub type Elf32_Off = u32; +pub type Elf32_Sword = i32; +pub type Elf32_Word = u32; + +pub type Elf64_Addr = u64; +pub type Elf64_Half = u16; +pub type Elf64_Lword = u64; +pub type Elf64_Off = u64; +pub type Elf64_Sword = i32; +pub type Elf64_Sxword = i64; +pub type Elf64_Word = u32; +pub type Elf64_Xword = u64; + +pub type iconv_t = *mut c_void; + +// It's an alias over "struct __kvm_t". However, its fields aren't supposed to be used directly, +// making the type definition system dependent. Better not bind it exactly. +pub type kvm_t = c_void; + +pub type posix_spawnattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_void; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + type Elf_Addr = Elf64_Addr; + type Elf_Half = Elf64_Half; + type Elf_Phdr = Elf64_Phdr; + } else if #[cfg(target_pointer_width = "32")] { + type Elf_Addr = Elf32_Addr; + type Elf_Half = Elf32_Half; + type Elf_Phdr = Elf32_Phdr; + } +} + +// link.h + +extern_ty! { + pub enum timezone {} +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + self.si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +s! { + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_sourceaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_matchc: size_t, + pub gl_offs: size_t, + pub gl_flags: c_int, + pub gl_pathv: *mut *mut c_char, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + __unused6: Padding<*mut c_void>, + __unused7: Padding<*mut c_void>, + __unused8: Padding<*mut c_void>, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *mut c_char, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: crate::socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct sigset_t { + bits: [u32; 4], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub si_pid: crate::pid_t, + pub si_uid: crate::uid_t, + pub si_status: c_int, + pub si_addr: *mut c_void, + pub si_value: crate::sigval, + _pad1: Padding, + _pad2: Padding<[c_int; 7]>, + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_flags: c_int, + pub sa_mask: sigset_t, + } + + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct flock { + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + pub l_type: c_short, + pub l_whence: c_short, + #[cfg(not(target_os = "dragonfly"))] + pub l_sysid: c_int, + } + + pub struct sf_hdtr { + pub headers: *mut crate::iovec, + pub hdr_cnt: c_int, + pub trailers: *mut crate::iovec, + pub trl_cnt: c_int, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_n_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct cmsgcred { + pub cmcred_pid: crate::pid_t, + pub cmcred_uid: crate::uid_t, + pub cmcred_euid: crate::uid_t, + pub cmcred_gid: crate::gid_t, + pub cmcred_ngroups: c_short, + pub cmcred_groups: [crate::gid_t; CMGROUP_MAX], + } + + pub struct rtprio { + pub type_: c_ushort, + pub prio: c_ushort, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct timex { + pub modes: c_uint, + pub offset: c_long, + pub freq: c_long, + pub maxerror: c_long, + pub esterror: c_long, + pub status: c_int, + pub constant: c_long, + pub precision: c_long, + pub tolerance: c_long, + pub ppsfreq: c_long, + pub jitter: c_long, + pub shift: c_int, + pub stabil: c_long, + pub jitcnt: c_long, + pub calcnt: c_long, + pub errcnt: c_long, + pub stbcnt: c_long, + } + + pub struct ntptimeval { + pub time: crate::timespec, + pub maxerror: c_long, + pub esterror: c_long, + pub tai: c_long, + pub time_state: c_int, + } + + pub struct accept_filter_arg { + pub af_name: [c_char; 16], + af_arg: [c_char; 256 - 16], + } + + pub struct ptrace_io_desc { + pub piod_op: c_int, + pub piod_offs: *mut c_void, + pub piod_addr: *mut c_void, + pub piod_len: size_t, + } + + // bpf.h + + pub struct bpf_program { + pub bf_len: c_uint, + pub bf_insns: *mut bpf_insn, + } + + pub struct bpf_stat { + pub bs_recv: c_uint, + pub bs_drop: c_uint, + } + + pub struct bpf_version { + pub bv_major: c_ushort, + pub bv_minor: c_ushort, + } + + pub struct bpf_hdr { + pub bh_tstamp: crate::timeval, + pub bh_caplen: u32, + pub bh_datalen: u32, + pub bh_hdrlen: c_ushort, + } + + pub struct bpf_insn { + pub code: c_ushort, + pub jt: c_uchar, + pub jf: c_uchar, + pub k: u32, + } + + pub struct bpf_dltlist { + bfl_len: c_uint, + bfl_list: *mut c_uint, + } + + // elf.h + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + // link.h + + pub struct dl_phdr_info { + pub dlpi_addr: Elf_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const Elf_Phdr, + pub dlpi_phnum: Elf_Half, + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: usize, + pub dlpi_tls_data: *mut c_void, + } + + pub struct ipc_perm { + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub mode: mode_t, + pub seq: c_ushort, + pub key: crate::key_t, + } + + pub struct eui64 { + pub octet: [u8; EUI64_LEN], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[u8; 112]>, + } +} + +// Non-public helper constant +const SIZEOF_LONG: usize = size_of::(); + +#[deprecated( + since = "0.2.64", + note = "Can vary at runtime. Use sysconf(3) instead" +)] +pub const AIO_LISTIO_MAX: c_int = 16; +pub const AIO_CANCELED: c_int = 1; +pub const AIO_NOTCANCELED: c_int = 2; +pub const AIO_ALLDONE: c_int = 3; +pub const LIO_NOP: c_int = 0; +pub const LIO_WRITE: c_int = 1; +pub const LIO_READ: c_int = 2; +pub const LIO_WAIT: c_int = 1; +pub const LIO_NOWAIT: c_int = 0; + +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; +pub const SIGEV_KEVENT: c_int = 3; + +pub const CODESET: crate::nl_item = 0; +pub const D_T_FMT: crate::nl_item = 1; +pub const D_FMT: crate::nl_item = 2; +pub const T_FMT: crate::nl_item = 3; +pub const T_FMT_AMPM: crate::nl_item = 4; +pub const AM_STR: crate::nl_item = 5; +pub const PM_STR: crate::nl_item = 6; + +pub const DAY_1: crate::nl_item = 7; +pub const DAY_2: crate::nl_item = 8; +pub const DAY_3: crate::nl_item = 9; +pub const DAY_4: crate::nl_item = 10; +pub const DAY_5: crate::nl_item = 11; +pub const DAY_6: crate::nl_item = 12; +pub const DAY_7: crate::nl_item = 13; + +pub const ABDAY_1: crate::nl_item = 14; +pub const ABDAY_2: crate::nl_item = 15; +pub const ABDAY_3: crate::nl_item = 16; +pub const ABDAY_4: crate::nl_item = 17; +pub const ABDAY_5: crate::nl_item = 18; +pub const ABDAY_6: crate::nl_item = 19; +pub const ABDAY_7: crate::nl_item = 20; + +pub const MON_1: crate::nl_item = 21; +pub const MON_2: crate::nl_item = 22; +pub const MON_3: crate::nl_item = 23; +pub const MON_4: crate::nl_item = 24; +pub const MON_5: crate::nl_item = 25; +pub const MON_6: crate::nl_item = 26; +pub const MON_7: crate::nl_item = 27; +pub const MON_8: crate::nl_item = 28; +pub const MON_9: crate::nl_item = 29; +pub const MON_10: crate::nl_item = 30; +pub const MON_11: crate::nl_item = 31; +pub const MON_12: crate::nl_item = 32; + +pub const ABMON_1: crate::nl_item = 33; +pub const ABMON_2: crate::nl_item = 34; +pub const ABMON_3: crate::nl_item = 35; +pub const ABMON_4: crate::nl_item = 36; +pub const ABMON_5: crate::nl_item = 37; +pub const ABMON_6: crate::nl_item = 38; +pub const ABMON_7: crate::nl_item = 39; +pub const ABMON_8: crate::nl_item = 40; +pub const ABMON_9: crate::nl_item = 41; +pub const ABMON_10: crate::nl_item = 42; +pub const ABMON_11: crate::nl_item = 43; +pub const ABMON_12: crate::nl_item = 44; + +pub const ERA: crate::nl_item = 45; +pub const ERA_D_FMT: crate::nl_item = 46; +pub const ERA_D_T_FMT: crate::nl_item = 47; +pub const ERA_T_FMT: crate::nl_item = 48; +pub const ALT_DIGITS: crate::nl_item = 49; + +pub const RADIXCHAR: crate::nl_item = 50; +pub const THOUSEP: crate::nl_item = 51; + +pub const YESEXPR: crate::nl_item = 52; +pub const NOEXPR: crate::nl_item = 53; + +pub const YESSTR: crate::nl_item = 54; +pub const NOSTR: crate::nl_item = 55; + +pub const CRNCYSTR: crate::nl_item = 56; + +pub const D_MD_ORDER: crate::nl_item = 57; + +pub const ALTMON_1: crate::nl_item = 58; +pub const ALTMON_2: crate::nl_item = 59; +pub const ALTMON_3: crate::nl_item = 60; +pub const ALTMON_4: crate::nl_item = 61; +pub const ALTMON_5: crate::nl_item = 62; +pub const ALTMON_6: crate::nl_item = 63; +pub const ALTMON_7: crate::nl_item = 64; +pub const ALTMON_8: crate::nl_item = 65; +pub const ALTMON_9: crate::nl_item = 66; +pub const ALTMON_10: crate::nl_item = 67; +pub const ALTMON_11: crate::nl_item = 68; +pub const ALTMON_12: crate::nl_item = 69; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const SEEK_DATA: c_int = 3; +pub const SEEK_HOLE: c_int = 4; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const BUFSIZ: c_uint = 1024; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 1024; +pub const L_tmpnam: c_uint = 1024; +pub const TMP_MAX: c_uint = 308915776; + +pub const O_NOCTTY: c_int = 32768; +pub const O_DIRECT: c_int = 0x00010000; + +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; +pub const F_DUPFD_CLOEXEC: c_int = 17; +pub const F_DUP2FD: c_int = 10; +pub const F_DUP2FD_CLOEXEC: c_int = 18; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_ANON: c_int = 0x1000; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const MNT_EXPUBLIC: c_int = 0x20000000; +pub const MNT_NOATIME: c_int = 0x10000000; +pub const MNT_NOCLUSTERR: c_int = 0x40000000; +pub const MNT_NOCLUSTERW: c_int = 0x80000000; +pub const MNT_NOSYMFOLLOW: c_int = 0x00400000; +pub const MNT_SOFTDEP: c_int = 0x00200000; +pub const MNT_SUIDDIR: c_int = 0x00100000; +pub const MNT_EXRDONLY: c_int = 0x00000080; +pub const MNT_DEFEXPORTED: c_int = 0x00000200; +pub const MNT_EXPORTANON: c_int = 0x00000400; +pub const MNT_EXKERB: c_int = 0x00000800; +pub const MNT_DELEXPORT: c_int = 0x00020000; + +pub const MS_SYNC: c_int = 0x0000; +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EDEADLK: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EAGAIN: c_int = 35; +pub const EWOULDBLOCK: c_int = 35; +pub const EINPROGRESS: c_int = 36; +pub const EALREADY: c_int = 37; +pub const ENOTSOCK: c_int = 38; +pub const EDESTADDRREQ: c_int = 39; +pub const EMSGSIZE: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const EOPNOTSUPP: c_int = 45; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENETDOWN: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const ELOOP: c_int = 62; +pub const ENAMETOOLONG: c_int = 63; +pub const EHOSTDOWN: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const ENOTEMPTY: c_int = 66; +pub const EPROCLIM: c_int = 67; +pub const EUSERS: c_int = 68; +pub const EDQUOT: c_int = 69; +pub const ESTALE: c_int = 70; +pub const EREMOTE: c_int = 71; +pub const EBADRPC: c_int = 72; +pub const ERPCMISMATCH: c_int = 73; +pub const EPROGUNAVAIL: c_int = 74; +pub const EPROGMISMATCH: c_int = 75; +pub const EPROCUNAVAIL: c_int = 76; +pub const ENOLCK: c_int = 77; +pub const ENOSYS: c_int = 78; +pub const EFTYPE: c_int = 79; +pub const EAUTH: c_int = 80; +pub const ENEEDAUTH: c_int = 81; +pub const EIDRM: c_int = 82; +pub const ENOMSG: c_int = 83; +pub const EOVERFLOW: c_int = 84; +pub const ECANCELED: c_int = 85; +pub const EILSEQ: c_int = 86; +pub const ENOATTR: c_int = 87; +pub const EDOOFUS: c_int = 88; +pub const EBADMSG: c_int = 89; +pub const EMULTIHOP: c_int = 90; +pub const ENOLINK: c_int = 91; +pub const EPROTO: c_int = 92; + +pub const POLLSTANDARD: c_short = crate::POLLIN + | crate::POLLPRI + | crate::POLLOUT + | crate::POLLRDNORM + | crate::POLLRDBAND + | crate::POLLWRBAND + | crate::POLLERR + | crate::POLLHUP + | crate::POLLNVAL; + +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; +pub const AI_NUMERICSERV: c_int = 0x00000008; +pub const AI_ALL: c_int = 0x00000100; +pub const AI_ADDRCONFIG: c_int = 0x00000400; +pub const AI_V4MAPPED: c_int = 0x00000800; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; + +pub const SIGTRAP: c_int = 5; + +pub const GLOB_APPEND: c_int = 0x0001; +pub const GLOB_DOOFFS: c_int = 0x0002; +pub const GLOB_ERR: c_int = 0x0004; +pub const GLOB_MARK: c_int = 0x0008; +pub const GLOB_NOCHECK: c_int = 0x0010; +pub const GLOB_NOSORT: c_int = 0x0020; +pub const GLOB_NOESCAPE: c_int = 0x2000; + +pub const GLOB_NOSPACE: c_int = -1; +pub const GLOB_ABORTED: c_int = -2; +pub const GLOB_NOMATCH: c_int = -3; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_MEMLOCK: c_int = 6; +pub const RLIMIT_NPROC: c_int = 7; +pub const RLIMIT_NOFILE: c_int = 8; +pub const RLIMIT_SBSIZE: c_int = 9; +pub const RLIMIT_VMEM: c_int = 10; +pub const RLIMIT_AS: c_int = RLIMIT_VMEM; +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_VIRTUAL: crate::clockid_t = 1; +pub const CLOCK_PROF: crate::clockid_t = 2; +pub const CLOCK_MONOTONIC: crate::clockid_t = 4; +pub const CLOCK_UPTIME: crate::clockid_t = 5; +pub const CLOCK_UPTIME_PRECISE: crate::clockid_t = 7; +pub const CLOCK_UPTIME_FAST: crate::clockid_t = 8; +pub const CLOCK_REALTIME_PRECISE: crate::clockid_t = 9; +pub const CLOCK_REALTIME_FAST: crate::clockid_t = 10; +pub const CLOCK_MONOTONIC_PRECISE: crate::clockid_t = 11; +pub const CLOCK_MONOTONIC_FAST: crate::clockid_t = 12; +pub const CLOCK_SECOND: crate::clockid_t = 13; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 14; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 15; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 5; +pub const MADV_NOSYNC: c_int = 6; +pub const MADV_AUTOSYNC: c_int = 7; +pub const MADV_NOCORE: c_int = 8; +pub const MADV_CORE: c_int = 9; + +pub const MINCORE_INCORE: c_int = 0x1; +pub const MINCORE_REFERENCED: c_int = 0x2; +pub const MINCORE_MODIFIED: c_int = 0x4; +pub const MINCORE_REFERENCED_OTHER: c_int = 0x8; +pub const MINCORE_MODIFIED_OTHER: c_int = 0x10; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NETBIOS: c_int = 6; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_ROUTE: c_int = 17; +pub const AF_LINK: c_int = 18; +pub const pseudo_AF_XTP: c_int = 19; +pub const AF_COIP: c_int = 20; +pub const AF_CNT: c_int = 21; +pub const pseudo_AF_RTIP: c_int = 22; +pub const AF_IPX: c_int = 23; +pub const AF_SIP: c_int = 24; +pub const pseudo_AF_PIP: c_int = 25; +pub const AF_ISDN: c_int = 26; +pub const AF_E164: c_int = AF_ISDN; +pub const pseudo_AF_KEY: c_int = 27; +pub const AF_INET6: c_int = 28; +pub const AF_NATM: c_int = 29; +pub const AF_ATM: c_int = 30; +pub const pseudo_AF_HDRCMPLT: c_int = 31; +pub const AF_NETGRAPH: c_int = 32; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NETBIOS: c_int = AF_NETBIOS; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_ISO; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_XTP: c_int = pseudo_AF_XTP; +pub const PF_COIP: c_int = AF_COIP; +pub const PF_CNT: c_int = AF_CNT; +pub const PF_SIP: c_int = AF_SIP; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_RTIP: c_int = pseudo_AF_RTIP; +pub const PF_PIP: c_int = pseudo_AF_PIP; +pub const PF_ISDN: c_int = AF_ISDN; +pub const PF_KEY: c_int = pseudo_AF_KEY; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_NATM: c_int = AF_NATM; +pub const PF_ATM: c_int = AF_ATM; +pub const PF_NETGRAPH: c_int = AF_NETGRAPH; + +pub const PIOD_READ_D: c_int = 1; +pub const PIOD_WRITE_D: c_int = 2; +pub const PIOD_READ_I: c_int = 3; +pub const PIOD_WRITE_I: c_int = 4; + +pub const PT_TRACE_ME: c_int = 0; +pub const PT_READ_I: c_int = 1; +pub const PT_READ_D: c_int = 2; +pub const PT_WRITE_I: c_int = 4; +pub const PT_WRITE_D: c_int = 5; +pub const PT_CONTINUE: c_int = 7; +pub const PT_KILL: c_int = 8; +pub const PT_STEP: c_int = 9; +pub const PT_ATTACH: c_int = 10; +pub const PT_DETACH: c_int = 11; +pub const PT_IO: c_int = 12; + +pub const SOMAXCONN: c_int = 128; + +pub const MSG_OOB: c_int = 0x00000001; +pub const MSG_PEEK: c_int = 0x00000002; +pub const MSG_DONTROUTE: c_int = 0x00000004; +pub const MSG_EOR: c_int = 0x00000008; +pub const MSG_TRUNC: c_int = 0x00000010; +pub const MSG_CTRUNC: c_int = 0x00000020; +pub const MSG_WAITALL: c_int = 0x00000040; +pub const MSG_DONTWAIT: c_int = 0x00000080; +pub const MSG_EOF: c_int = 0x00000100; + +pub const SCM_TIMESTAMP: c_int = 0x02; +pub const SCM_CREDS: c_int = 0x03; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_CLOEXEC: c_int = 0x10000000; +pub const SOCK_NONBLOCK: c_int = 0x20000000; +pub const SOCK_MAXADDRLEN: c_int = 255; +pub const IP_TTL: c_int = 4; +pub const IP_HDRINCL: c_int = 2; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_SENDSRCADDR: c_int = IP_RECVDSTADDR; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_RECVIF: c_int = 20; +pub const IP_RECVTTL: c_int = 65; +pub const IP_MINTTL: c_int = 66; +pub const IPV6_RECVHOPLIMIT: c_int = 37; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; +pub const IPV6_CHECKSUM: c_int = 26; +pub const IPV6_RECVPKTINFO: c_int = 36; +pub const IPV6_PKTINFO: c_int = 46; +pub const IPV6_HOPLIMIT: c_int = 47; +pub const IPV6_RECVTCLASS: c_int = 57; +pub const IPV6_TCLASS: c_int = 61; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 70; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 71; +pub const IP_BLOCK_SOURCE: c_int = 72; +pub const IP_UNBLOCK_SOURCE: c_int = 73; + +pub const TCP_NOPUSH: c_int = 4; +pub const TCP_NOOPT: c_int = 8; +pub const TCP_KEEPIDLE: c_int = 256; +pub const TCP_KEEPINTVL: c_int = 512; +pub const TCP_KEEPCNT: c_int = 1024; + +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 0x01; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_TIMESTAMP: c_int = 0x0400; +pub const SO_NOSIGPIPE: c_int = 0x0800; +pub const SO_ACCEPTFILTER: c_int = 0x1000; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; + +pub const LOCAL_PEERCRED: c_int = 1; + +// net/route.h +pub const RTF_XRESOLVE: c_int = 0x200; +pub const RTF_LLINFO: c_int = 0x400; +pub const RTF_PROTO3: c_int = 0x40000; +pub const RTF_PINNED: c_int = 0x100000; +pub const RTF_LOCAL: c_int = 0x200000; +pub const RTF_BROADCAST: c_int = 0x400000; +pub const RTF_MULTICAST: c_int = 0x800000; + +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_NEWMADDR: c_int = 0xf; +pub const RTM_DELMADDR: c_int = 0x10; +pub const RTM_IFANNOUNCE: c_int = 0x11; +pub const RTM_IEEE80211: c_int = 0x12; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const MAP_COPY: c_int = 0x0002; +#[doc(hidden)] +#[deprecated( + since = "0.2.54", + note = "Removed in FreeBSD 11, unused in DragonFlyBSD" +)] +pub const MAP_RENAME: c_int = 0x0020; +#[doc(hidden)] +#[deprecated( + since = "0.2.54", + note = "Removed in FreeBSD 11, unused in DragonFlyBSD" +)] +pub const MAP_NORESERVE: c_int = 0x0040; +pub const MAP_HASSEMAPHORE: c_int = 0x0200; +pub const MAP_STACK: c_int = 0x0400; +pub const MAP_NOSYNC: c_int = 0x0800; +pub const MAP_NOCORE: c_int = 0x020000; + +pub const IPPROTO_RAW: c_int = 255; + +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_CHOWN_RESTRICTED: c_int = 7; +pub const _PC_NO_TRUNC: c_int = 8; +pub const _PC_VDISABLE: c_int = 9; +pub const _PC_ALLOC_SIZE_MIN: c_int = 10; +pub const _PC_FILESIZEBITS: c_int = 12; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_SYMLINK_MAX: c_int = 18; +pub const _PC_MIN_HOLE_SIZE: c_int = 21; +pub const _PC_ASYNC_IO: c_int = 53; +pub const _PC_PRIO_IO: c_int = 54; +pub const _PC_SYNC_IO: c_int = 55; +pub const _PC_ACL_EXTENDED: c_int = 59; +pub const _PC_ACL_PATH_MAX: c_int = 60; +pub const _PC_CAP_PRESENT: c_int = 61; +pub const _PC_INF_PRESENT: c_int = 62; +pub const _PC_MAC_PRESENT: c_int = 63; + +pub const _SC_ARG_MAX: c_int = 1; +pub const _SC_CHILD_MAX: c_int = 2; +pub const _SC_CLK_TCK: c_int = 3; +pub const _SC_NGROUPS_MAX: c_int = 4; +pub const _SC_OPEN_MAX: c_int = 5; +pub const _SC_JOB_CONTROL: c_int = 6; +pub const _SC_SAVED_IDS: c_int = 7; +pub const _SC_VERSION: c_int = 8; +pub const _SC_BC_BASE_MAX: c_int = 9; +pub const _SC_BC_DIM_MAX: c_int = 10; +pub const _SC_BC_SCALE_MAX: c_int = 11; +pub const _SC_BC_STRING_MAX: c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; +pub const _SC_EXPR_NEST_MAX: c_int = 14; +pub const _SC_LINE_MAX: c_int = 15; +pub const _SC_RE_DUP_MAX: c_int = 16; +pub const _SC_2_VERSION: c_int = 17; +pub const _SC_2_C_BIND: c_int = 18; +pub const _SC_2_C_DEV: c_int = 19; +pub const _SC_2_CHAR_TERM: c_int = 20; +pub const _SC_2_FORT_DEV: c_int = 21; +pub const _SC_2_FORT_RUN: c_int = 22; +pub const _SC_2_LOCALEDEF: c_int = 23; +pub const _SC_2_SW_DEV: c_int = 24; +pub const _SC_2_UPE: c_int = 25; +pub const _SC_STREAM_MAX: c_int = 26; +pub const _SC_TZNAME_MAX: c_int = 27; +pub const _SC_ASYNCHRONOUS_IO: c_int = 28; +pub const _SC_MAPPED_FILES: c_int = 29; +pub const _SC_MEMLOCK: c_int = 30; +pub const _SC_MEMLOCK_RANGE: c_int = 31; +pub const _SC_MEMORY_PROTECTION: c_int = 32; +pub const _SC_MESSAGE_PASSING: c_int = 33; +pub const _SC_PRIORITIZED_IO: c_int = 34; +pub const _SC_PRIORITY_SCHEDULING: c_int = 35; +pub const _SC_REALTIME_SIGNALS: c_int = 36; +pub const _SC_SEMAPHORES: c_int = 37; +pub const _SC_FSYNC: c_int = 38; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39; +pub const _SC_SYNCHRONIZED_IO: c_int = 40; +pub const _SC_TIMERS: c_int = 41; +pub const _SC_AIO_LISTIO_MAX: c_int = 42; +pub const _SC_AIO_MAX: c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; +pub const _SC_DELAYTIMER_MAX: c_int = 45; +pub const _SC_MQ_OPEN_MAX: c_int = 46; +pub const _SC_PAGESIZE: c_int = 47; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 48; +pub const _SC_SEM_NSEMS_MAX: c_int = 49; +pub const _SC_SEM_VALUE_MAX: c_int = 50; +pub const _SC_SIGQUEUE_MAX: c_int = 51; +pub const _SC_TIMER_MAX: c_int = 52; +pub const _SC_IOV_MAX: c_int = 56; +pub const _SC_NPROCESSORS_CONF: c_int = 57; +pub const _SC_2_PBS: c_int = 59; +pub const _SC_2_PBS_ACCOUNTING: c_int = 60; +pub const _SC_2_PBS_CHECKPOINT: c_int = 61; +pub const _SC_2_PBS_LOCATE: c_int = 62; +pub const _SC_2_PBS_MESSAGE: c_int = 63; +pub const _SC_2_PBS_TRACK: c_int = 64; +pub const _SC_ADVISORY_INFO: c_int = 65; +pub const _SC_BARRIERS: c_int = 66; +pub const _SC_CLOCK_SELECTION: c_int = 67; +pub const _SC_CPUTIME: c_int = 68; +pub const _SC_FILE_LOCKING: c_int = 69; +pub const _SC_NPROCESSORS_ONLN: c_int = 58; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 70; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 71; +pub const _SC_HOST_NAME_MAX: c_int = 72; +pub const _SC_LOGIN_NAME_MAX: c_int = 73; +pub const _SC_MONOTONIC_CLOCK: c_int = 74; +pub const _SC_MQ_PRIO_MAX: c_int = 75; +pub const _SC_READER_WRITER_LOCKS: c_int = 76; +pub const _SC_REGEXP: c_int = 77; +pub const _SC_SHELL: c_int = 78; +pub const _SC_SPAWN: c_int = 79; +pub const _SC_SPIN_LOCKS: c_int = 80; +pub const _SC_SPORADIC_SERVER: c_int = 81; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85; +pub const _SC_THREAD_KEYS_MAX: c_int = 86; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 87; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 88; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 90; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 92; +pub const _SC_THREAD_STACK_MIN: c_int = 93; +pub const _SC_THREAD_THREADS_MAX: c_int = 94; +pub const _SC_TIMEOUTS: c_int = 95; +pub const _SC_THREADS: c_int = 96; +pub const _SC_TRACE: c_int = 97; +pub const _SC_TRACE_EVENT_FILTER: c_int = 98; +pub const _SC_TRACE_INHERIT: c_int = 99; +pub const _SC_TRACE_LOG: c_int = 100; +pub const _SC_TTY_NAME_MAX: c_int = 101; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 102; +pub const _SC_V6_ILP32_OFF32: c_int = 103; +pub const _SC_V6_ILP32_OFFBIG: c_int = 104; +pub const _SC_V6_LP64_OFF64: c_int = 105; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 106; +pub const _SC_ATEXIT_MAX: c_int = 107; +pub const _SC_XOPEN_CRYPT: c_int = 108; +pub const _SC_XOPEN_ENH_I18N: c_int = 109; +pub const _SC_XOPEN_LEGACY: c_int = 110; +pub const _SC_XOPEN_REALTIME: c_int = 111; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112; +pub const _SC_XOPEN_SHM: c_int = 113; +pub const _SC_XOPEN_STREAMS: c_int = 114; +pub const _SC_XOPEN_UNIX: c_int = 115; +pub const _SC_XOPEN_VERSION: c_int = 116; +pub const _SC_XOPEN_XCU_VERSION: c_int = 117; +pub const _SC_IPV6: c_int = 118; +pub const _SC_RAW_SOCKETS: c_int = 119; +pub const _SC_SYMLOOP_MAX: c_int = 120; +pub const _SC_PHYS_PAGES: c_int = 121; + +pub const _CS_PATH: c_int = 1; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = ptr::null_mut(); +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = ptr::null_mut(); +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = ptr::null_mut(); +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_NORMAL: c_int = 3; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_ERRORCHECK; + +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_OTHER: c_int = 2; +pub const SCHED_RR: c_int = 3; + +pub const FD_SETSIZE: usize = 1024; + +pub const ST_NOSUID: c_ulong = 2; + +pub const NI_MAXHOST: size_t = 1025; + +pub const XUCRED_VERSION: c_uint = 0; + +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_NOLOAD: c_int = 0x2000; +pub const RTLD_GLOBAL: c_int = 0x100; + +pub const LOG_NTP: c_int = 12 << 3; +pub const LOG_SECURITY: c_int = 13 << 3; +pub const LOG_CONSOLE: c_int = 14 << 3; +pub const LOG_NFACILITIES: c_int = 24; + +pub const TIOCEXCL: c_ulong = 0x2000740d; +pub const TIOCNXCL: c_ulong = 0x2000740e; +pub const TIOCFLUSH: c_ulong = 0x80047410; +pub const TIOCGETA: c_ulong = 0x402c7413; +pub const TIOCSETA: c_ulong = 0x802c7414; +pub const TIOCSETAW: c_ulong = 0x802c7415; +pub const TIOCSETAF: c_ulong = 0x802c7416; +pub const TIOCGETD: c_ulong = 0x4004741a; +pub const TIOCSETD: c_ulong = 0x8004741b; +pub const TIOCGDRAINWAIT: c_ulong = 0x40047456; +pub const TIOCSDRAINWAIT: c_ulong = 0x80047457; +#[cfg_attr( + not(target_os = "dragonfly"), + deprecated = "unused since FreeBSD 8, removed in FreeBSD 15" +)] +pub const TIOCMGDTRWAIT: c_ulong = 0x4004745a; +#[cfg_attr( + not(target_os = "dragonfly"), + deprecated = "unused since FreeBSD 8, removed in FreeBSD 15" +)] +pub const TIOCMSDTRWAIT: c_ulong = 0x8004745b; +pub const TIOCDRAIN: c_ulong = 0x2000745e; +pub const TIOCEXT: c_ulong = 0x80047460; +pub const TIOCSCTTY: c_ulong = 0x20007461; +pub const TIOCCONS: c_ulong = 0x80047462; +pub const TIOCGSID: c_ulong = 0x40047463; +pub const TIOCSTAT: c_ulong = 0x20007465; +pub const TIOCUCNTL: c_ulong = 0x80047466; +pub const TIOCSWINSZ: c_ulong = 0x80087467; +pub const TIOCGWINSZ: c_ulong = 0x40087468; +pub const TIOCMGET: c_ulong = 0x4004746a; +pub const TIOCM_LE: c_int = 0x1; +pub const TIOCM_DTR: c_int = 0x2; +pub const TIOCM_RTS: c_int = 0x4; +pub const TIOCM_ST: c_int = 0x8; +pub const TIOCM_SR: c_int = 0x10; +pub const TIOCM_CTS: c_int = 0x20; +pub const TIOCM_RI: c_int = 0x80; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCM_CD: c_int = 0x40; +pub const TIOCM_CAR: c_int = 0x40; +pub const TIOCM_RNG: c_int = 0x80; +pub const TIOCMBIC: c_ulong = 0x8004746b; +pub const TIOCMBIS: c_ulong = 0x8004746c; +pub const TIOCMSET: c_ulong = 0x8004746d; +pub const TIOCSTART: c_ulong = 0x2000746e; +pub const TIOCSTOP: c_ulong = 0x2000746f; +pub const TIOCPKT: c_ulong = 0x80047470; +pub const TIOCPKT_DATA: c_int = 0x0; +pub const TIOCPKT_FLUSHREAD: c_int = 0x1; +pub const TIOCPKT_FLUSHWRITE: c_int = 0x2; +pub const TIOCPKT_STOP: c_int = 0x4; +pub const TIOCPKT_START: c_int = 0x8; +pub const TIOCPKT_NOSTOP: c_int = 0x10; +pub const TIOCPKT_DOSTOP: c_int = 0x20; +pub const TIOCPKT_IOCTL: c_int = 0x40; +pub const TIOCNOTTY: c_ulong = 0x20007471; +pub const TIOCSTI: c_ulong = 0x80017472; +pub const TIOCOUTQ: c_ulong = 0x40047473; +pub const TIOCSPGRP: c_ulong = 0x80047476; +pub const TIOCGPGRP: c_ulong = 0x40047477; +pub const TIOCCDTR: c_ulong = 0x20007478; +pub const TIOCSDTR: c_ulong = 0x20007479; +pub const TTYDISC: c_int = 0x0; +pub const SLIPDISC: c_int = 0x4; +pub const PPPDISC: c_int = 0x5; +pub const NETGRAPHDISC: c_int = 0x6; + +pub const BIOCGRSIG: c_ulong = 0x40044272; +pub const BIOCSRSIG: c_ulong = 0x80044273; +pub const BIOCSDLT: c_ulong = 0x80044278; +pub const BIOCGSEESENT: c_ulong = 0x40044276; +pub const BIOCSSEESENT: c_ulong = 0x80044277; +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const BIOCGDLTLIST: c_ulong = 0xc0104279; + pub const BIOCSETF: c_ulong = 0x80104267; + } else if #[cfg(target_pointer_width = "32")] { + pub const BIOCGDLTLIST: c_ulong = 0xc0084279; + pub const BIOCSETF: c_ulong = 0x80084267; + } +} + +pub const FIODTYPE: c_ulong = 0x4004667a; +pub const FIOGETLBA: c_ulong = 0x40046679; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SEM_FAILED: *mut sem_t = ptr::null_mut(); + +pub const CRTSCTS: crate::tcflag_t = 0x00030000; +pub const CCTS_OFLOW: crate::tcflag_t = 0x00010000; +pub const CRTS_IFLOW: crate::tcflag_t = 0x00020000; +pub const CDTR_IFLOW: crate::tcflag_t = 0x00040000; +pub const CDSR_OFLOW: crate::tcflag_t = 0x00080000; +pub const CCAR_OFLOW: crate::tcflag_t = 0x00100000; +pub const VERASE2: usize = 7; +pub const OCRNL: crate::tcflag_t = 0x10; +pub const ONOCR: crate::tcflag_t = 0x20; +pub const ONLRET: crate::tcflag_t = 0x40; + +pub const CMGROUP_MAX: usize = 16; + +pub const EUI64_LEN: usize = 8; + +// https://github.com/freebsd/freebsd/blob/HEAD/sys/net/bpf.h +pub const BPF_ALIGNMENT: usize = SIZEOF_LONG; + +// Values for rtprio struct (prio field) and syscall (function argument) +pub const RTP_PRIO_MIN: c_ushort = 0; +pub const RTP_PRIO_MAX: c_ushort = 31; +pub const RTP_LOOKUP: c_int = 0; +pub const RTP_SET: c_int = 1; + +// Flags for chflags(2) +pub const UF_SETTABLE: c_ulong = 0x0000ffff; +pub const UF_NODUMP: c_ulong = 0x00000001; +pub const UF_IMMUTABLE: c_ulong = 0x00000002; +pub const UF_APPEND: c_ulong = 0x00000004; +pub const UF_OPAQUE: c_ulong = 0x00000008; +pub const UF_NOUNLINK: c_ulong = 0x00000010; +pub const SF_SETTABLE: c_ulong = 0xffff0000; +pub const SF_ARCHIVED: c_ulong = 0x00010000; +pub const SF_IMMUTABLE: c_ulong = 0x00020000; +pub const SF_APPEND: c_ulong = 0x00040000; +pub const SF_NOUNLINK: c_ulong = 0x00100000; + +pub const TIMER_ABSTIME: c_int = 1; + +// +pub const NTP_API: c_int = 4; +pub const MAXPHASE: c_long = 500000000; +pub const MAXFREQ: c_long = 500000; +pub const MINSEC: c_int = 256; +pub const MAXSEC: c_int = 2048; +pub const NANOSECOND: c_long = 1000000000; +pub const SCALE_PPM: c_int = 65; +pub const MAXTC: c_int = 10; +pub const MOD_OFFSET: c_uint = 0x0001; +pub const MOD_FREQUENCY: c_uint = 0x0002; +pub const MOD_MAXERROR: c_uint = 0x0004; +pub const MOD_ESTERROR: c_uint = 0x0008; +pub const MOD_STATUS: c_uint = 0x0010; +pub const MOD_TIMECONST: c_uint = 0x0020; +pub const MOD_PPSMAX: c_uint = 0x0040; +pub const MOD_TAI: c_uint = 0x0080; +pub const MOD_MICRO: c_uint = 0x1000; +pub const MOD_NANO: c_uint = 0x2000; +pub const MOD_CLKB: c_uint = 0x4000; +pub const MOD_CLKA: c_uint = 0x8000; +pub const STA_PLL: c_int = 0x0001; +pub const STA_PPSFREQ: c_int = 0x0002; +pub const STA_PPSTIME: c_int = 0x0004; +pub const STA_FLL: c_int = 0x0008; +pub const STA_INS: c_int = 0x0010; +pub const STA_DEL: c_int = 0x0020; +pub const STA_UNSYNC: c_int = 0x0040; +pub const STA_FREQHOLD: c_int = 0x0080; +pub const STA_PPSSIGNAL: c_int = 0x0100; +pub const STA_PPSJITTER: c_int = 0x0200; +pub const STA_PPSWANDER: c_int = 0x0400; +pub const STA_PPSERROR: c_int = 0x0800; +pub const STA_CLOCKERR: c_int = 0x1000; +pub const STA_NANO: c_int = 0x2000; +pub const STA_MODE: c_int = 0x4000; +pub const STA_CLK: c_int = 0x8000; +pub const STA_RONLY: c_int = STA_PPSSIGNAL + | STA_PPSJITTER + | STA_PPSWANDER + | STA_PPSERROR + | STA_CLOCKERR + | STA_NANO + | STA_MODE + | STA_CLK; +pub const TIME_OK: c_int = 0; +pub const TIME_INS: c_int = 1; +pub const TIME_DEL: c_int = 2; +pub const TIME_OOP: c_int = 3; +pub const TIME_WAIT: c_int = 4; +pub const TIME_ERROR: c_int = 5; + +pub const REG_ENOSYS: c_int = -1; +pub const REG_ILLSEQ: c_int = 17; + +pub const IPC_PRIVATE: crate::key_t = 0; +pub const IPC_CREAT: c_int = 0o1000; +pub const IPC_EXCL: c_int = 0o2000; +pub const IPC_NOWAIT: c_int = 0o4000; +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; +pub const IPC_R: c_int = 0o400; +pub const IPC_W: c_int = 0o200; +pub const IPC_M: c_int = 0o10000; + +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; + +pub const KENV_GET: c_int = 0; +pub const KENV_SET: c_int = 1; +pub const KENV_UNSET: c_int = 2; +pub const KENV_DUMP: c_int = 3; +pub const KENV_MNAMELEN: c_int = 128; +pub const KENV_MVALLEN: c_int = 128; + +pub const RB_ASKNAME: c_int = 0x001; +pub const RB_SINGLE: c_int = 0x002; +pub const RB_NOSYNC: c_int = 0x004; +pub const RB_HALT: c_int = 0x008; +pub const RB_INITNAME: c_int = 0x010; +pub const RB_DFLTROOT: c_int = 0x020; +pub const RB_KDB: c_int = 0x040; +pub const RB_RDONLY: c_int = 0x080; +pub const RB_DUMP: c_int = 0x100; +pub const RB_MINIROOT: c_int = 0x200; +pub const RB_VERBOSE: c_int = 0x800; +pub const RB_SERIAL: c_int = 0x1000; +pub const RB_CDROM: c_int = 0x2000; +pub const RB_POWEROFF: c_int = 0x4000; +pub const RB_GDB: c_int = 0x8000; +pub const RB_MUTE: c_int = 0x10000; +pub const RB_SELFTEST: c_int = 0x20000; + +// For getrandom() +pub const GRND_NONBLOCK: c_uint = 0x1; +pub const GRND_RANDOM: c_uint = 0x2; +pub const GRND_INSECURE: c_uint = 0x4; + +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x02; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x04; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x08; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x10; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x20; + +safe_f! { + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0x13 + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + status >> 8 + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0o177) == 0o177 + } +} + +extern "C" { + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn accept4( + s: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn chflags(path: *const c_char, flags: c_ulong) -> c_int; + pub fn chflagsat(fd: c_int, path: *const c_char, flags: c_ulong, atflag: c_int) -> c_int; + + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn pthread_getcpuclockid(thread: crate::pthread_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn endutxent(); + pub fn fchflags(fd: c_int, flags: c_ulong) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn getdomainname(name: *mut c_char, len: c_int) -> c_int; + pub fn getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getpwent_r( + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn getgrouplist( + name: *const c_char, + basegid: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: size_t, + serv: *mut c_char, + servlen: size_t, + flags: c_int, + ) -> c_int; + pub fn getpriority(which: c_int, who: c_int) -> c_int; + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn initgroups(name: *const c_char, basegid: crate::gid_t) -> c_int; + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "kevent@FBSD_1.0" + )] + pub fn kevent( + kq: c_int, + changelist: *const crate::kevent, + nchanges: c_int, + eventlist: *mut crate::kevent, + nevents: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn lchflags(path: *const c_char, flags: c_ulong) -> c_int; + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "mknodat@FBSD_1.1" + )] + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn malloc_usable_size(ptr: *const c_void) -> size_t; + pub fn mincore(addr: *const c_void, len: size_t, vec: *mut c_char) -> c_int; + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: crate::nfds_t, + timeout: *const crate::timespec, + sigmask: *const sigset_t, + ) -> c_int; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn pthread_attr_get_np(tid: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + pub fn pthread_main_np() -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, val: c_int) -> c_int; + pub fn pthread_barrierattr_init(attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_destroy(attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_getpshared( + attr: *const crate::pthread_barrierattr_t, + shared: *mut c_int, + ) -> c_int; + pub fn pthread_barrierattr_setpshared( + attr: *mut crate::pthread_barrierattr_t, + shared: c_int, + ) -> c_int; + pub fn pthread_barrier_init( + barrier: *mut pthread_barrier_t, + attr: *const crate::pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_get_name_np(tid: crate::pthread_t, name: *mut c_char, len: size_t); + pub fn pthread_set_name_np(tid: crate::pthread_t, name: *const c_char); + pub fn pthread_getname_np( + thread: crate::pthread_t, + buffer: *mut c_char, + length: size_t, + ) -> c_int; + pub fn pthread_setname_np(thread: crate::pthread_t, name: *const c_char) -> c_int; + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const sched_param, + ) -> c_int; + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut sched_param, + ) -> c_int; + pub fn ptrace(request: c_int, pid: crate::pid_t, addr: *mut c_char, data: c_int) -> c_int; + pub fn utrace(addr: *const c_void, len: size_t) -> c_int; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn querylocale(mask: c_int, loc: crate::locale_t) -> *const c_char; + pub fn rtprio(function: c_int, pid: crate::pid_t, rtp: *mut rtprio) -> c_int; + pub fn sched_rr_get_interval(pid: crate::pid_t, t: *mut crate::timespec) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut sched_param) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const sched_param) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sendfile( + fd: c_int, + s: c_int, + offset: off_t, + nbytes: size_t, + hdtr: *mut crate::sf_hdtr, + sbytes: *mut off_t, + flags: c_int, + ) -> c_int; + pub fn setdomainname(name: *const c_char, len: c_int) -> c_int; + pub fn sethostname(name: *const c_char, len: c_int) -> c_int; + pub fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + pub fn setutxent(); + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + pub fn sysctl( + name: *const c_int, + namelen: c_uint, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *const c_void, + newlen: size_t, + ) -> c_int; + pub fn sysctlbyname( + name: *const c_char, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *const c_void, + newlen: size_t, + ) -> c_int; + pub fn sysctlnametomib(name: *const c_char, mibp: *mut c_int, sizep: *mut size_t) -> c_int; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + + pub fn ntp_adjtime(buf: *mut timex) -> c_int; + pub fn ntp_gettime(buf: *mut ntptimeval) -> c_int; + + // #include + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + pub fn iconv_close(cd: iconv_t) -> c_int; + + // Added in `FreeBSD` 11.0 + // Added in `DragonFly BSD` 5.4 + pub fn explicit_bzero(s: *mut c_void, len: size_t); + // ISO/IEC 9899:2011 ("ISO C11") K.3.7.4.1 + pub fn memset_s(s: *mut c_void, smax: size_t, c: c_int, n: size_t) -> c_int; + pub fn gethostid() -> c_long; + pub fn sethostid(hostid: c_long); + + pub fn eui64_aton(a: *const c_char, e: *mut eui64) -> c_int; + pub fn eui64_ntoa(id: *const eui64, a: *mut c_char, len: size_t) -> c_int; + pub fn eui64_ntohost(hostname: *mut c_char, len: size_t, id: *const eui64) -> c_int; + pub fn eui64_hostton(hostname: *const c_char, id: *mut eui64) -> c_int; + + pub fn eaccess(path: *const c_char, mode: c_int) -> c_int; + + pub fn kenv(action: c_int, name: *const c_char, value: *mut c_char, len: c_int) -> c_int; + pub fn reboot(howto: c_int) -> c_int; + + pub fn exect(path: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int; + pub fn execvP( + file: *const c_char, + search_path: *const c_char, + argv: *const *mut c_char, + ) -> c_int; + + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; +} + +#[link(name = "rt")] +extern "C" { + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_notify(mqd: crate::mqd_t, notification: *const crate::sigevent) -> c_int; + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; +} + +#[link(name = "util")] +extern "C" { + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + pub fn login_tty(fd: c_int) -> c_int; + pub fn fparseln( + stream: *mut crate::FILE, + len: *mut size_t, + lineno: *mut size_t, + delim: *const c_char, + flags: c_int, + ) -> *mut c_char; +} + +#[link(name = "execinfo")] +extern "C" { + pub fn backtrace(addrlist: *mut *mut c_void, len: size_t) -> size_t; + pub fn backtrace_symbols(addrlist: *const *mut c_void, len: size_t) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(addrlist: *const *mut c_void, len: size_t, fd: c_int) -> c_int; +} + +#[link(name = "kvm")] +extern "C" { + pub fn kvm_open( + execfile: *const c_char, + corefile: *const c_char, + swapfile: *const c_char, + flags: c_int, + errstr: *const c_char, + ) -> *mut crate::kvm_t; + pub fn kvm_close(kd: *mut crate::kvm_t) -> c_int; + pub fn kvm_getprocs( + kd: *mut crate::kvm_t, + op: c_int, + arg: c_int, + cnt: *mut c_int, + ) -> *mut crate::kinfo_proc; + pub fn kvm_getloadavg(kd: *mut kvm_t, loadavg: *mut c_double, nelem: c_int) -> c_int; + pub fn kvm_openfiles( + execfile: *const c_char, + corefile: *const c_char, + swapfile: *const c_char, + flags: c_int, + errbuf: *mut c_char, + ) -> *mut crate::kvm_t; + pub fn kvm_read( + kd: *mut crate::kvm_t, + addr: c_ulong, + buf: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn kvm_write( + kd: *mut crate::kvm_t, + addr: c_ulong, + buf: *const c_void, + nbytes: size_t, + ) -> ssize_t; +} + +cfg_if! { + if #[cfg(target_os = "freebsd")] { + mod freebsd; + pub use self::freebsd::*; + } else if #[cfg(target_os = "dragonfly")] { + mod dragonfly; + pub use self::dragonfly::*; + } else { + // ... + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/mod.rs new file mode 100644 index 00000000000000..cb478173598699 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/mod.rs @@ -0,0 +1,897 @@ +use crate::prelude::*; + +pub type off_t = i64; +pub type useconds_t = u32; +pub type blkcnt_t = i64; +pub type socklen_t = u32; +pub type sa_family_t = u8; +pub type pthread_t = crate::uintptr_t; +pub type nfds_t = c_uint; +pub type regoff_t = off_t; + +s! { + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_change: crate::time_t, + pub pw_class: *mut c_char, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + pub pw_expire: crate::time_t, + + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos", + target_os = "netbsd", + target_os = "openbsd" + )))] + pub pw_fields: c_int, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_dstaddr: *mut crate::sockaddr, + pub ifa_data: *mut c_void, + #[cfg(target_os = "netbsd")] + pub ifa_addrflags: c_uint, + } + + pub struct fd_set { + #[cfg(all( + target_pointer_width = "64", + any(target_os = "freebsd", target_os = "dragonfly") + ))] + fds_bits: [i64; FD_SETSIZE as usize / 64], + #[cfg(not(all( + target_pointer_width = "64", + any(target_os = "freebsd", target_os = "dragonfly") + )))] + fds_bits: [i32; FD_SETSIZE as usize / 32], + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct fsid_t { + __fsid_val: [i32; 2], + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + pub struct regex_t { + __re_magic: c_int, + __re_nsub: size_t, + __re_endp: *const c_char, + __re_g: *mut c_void, + } + + pub struct regmatch_t { + pub rm_so: regoff_t, + pub rm_eo: regoff_t, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 104], + } + + pub struct utsname { + #[cfg(not(target_os = "dragonfly"))] + pub sysname: [c_char; 256], + #[cfg(target_os = "dragonfly")] + pub sysname: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub nodename: [c_char; 256], + #[cfg(target_os = "dragonfly")] + pub nodename: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub release: [c_char; 256], + #[cfg(target_os = "dragonfly")] + pub release: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub version: [c_char; 256], + #[cfg(target_os = "dragonfly")] + pub version: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub machine: [c_char; 256], + #[cfg(target_os = "dragonfly")] + pub machine: [c_char; 32], + } +} + +pub const LC_ALL: c_int = 0; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; +pub const LC_MESSAGES: c_int = 6; + +pub const FIOCLEX: c_ulong = 0x20006601; +pub const FIONCLEX: c_ulong = 0x20006602; +pub const FIONREAD: c_ulong = 0x4004667f; +pub const FIONBIO: c_ulong = 0x8004667e; +pub const FIOASYNC: c_ulong = 0x8004667d; +pub const FIOSETOWN: c_ulong = 0x8004667c; +pub const FIOGETOWN: c_ulong = 0x4004667b; + +pub const PATH_MAX: c_int = 1024; +pub const MAXPATHLEN: c_int = PATH_MAX; + +pub const IOV_MAX: c_int = 1024; + +pub const SA_ONSTACK: c_int = 0x0001; +pub const SA_SIGINFO: c_int = 0x0040; +pub const SA_RESTART: c_int = 0x0002; +pub const SA_RESETHAND: c_int = 0x0004; +pub const SA_NOCLDSTOP: c_int = 0x0008; +pub const SA_NODEFER: c_int = 0x0010; +pub const SA_NOCLDWAIT: c_int = 0x0020; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 4; + +pub const SIGCHLD: c_int = 20; +pub const SIGBUS: c_int = 10; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGCONT: c_int = 19; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGURG: c_int = 16; +pub const SIGIO: c_int = 23; +pub const SIGSYS: c_int = 12; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGINFO: c_int = 29; + +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 0x1; +pub const SIG_UNBLOCK: c_int = 0x2; + +pub const IP_TOS: c_int = 3; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; + +pub const IPV6_UNICAST_HOPS: c_int = 4; +pub const IPV6_MULTICAST_IF: c_int = 9; +pub const IPV6_MULTICAST_HOPS: c_int = 10; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IPV6_V6ONLY: c_int = 27; +pub const IPV6_DONTFRAG: c_int = 62; + +pub const IPTOS_ECN_NOTECT: u8 = 0x00; +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const ST_RDONLY: c_ulong = 1; + +pub const SCM_RIGHTS: c_int = 0x01; + +pub const NCCS: usize = 20; + +pub const O_ACCMODE: c_int = 0x3; +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 512; +pub const O_TRUNC: c_int = 1024; +pub const O_EXCL: c_int = 2048; +pub const O_ASYNC: c_int = 0x40; +pub const O_SYNC: c_int = 0x80; +pub const O_NONBLOCK: c_int = 0x4; +pub const O_NOFOLLOW: c_int = 0x100; +pub const O_SHLOCK: c_int = 0x10; +pub const O_EXLOCK: c_int = 0x20; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_NDELAY: c_int = O_NONBLOCK; + +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; + +pub const F_RDLCK: c_short = 1; +pub const F_UNLCK: c_short = 2; +pub const F_WRLCK: c_short = 3; + +pub const MNT_RDONLY: c_int = 0x00000001; +pub const MNT_SYNCHRONOUS: c_int = 0x00000002; +pub const MNT_NOEXEC: c_int = 0x00000004; +pub const MNT_NOSUID: c_int = 0x00000008; +pub const MNT_ASYNC: c_int = 0x00000040; +pub const MNT_EXPORTED: c_int = 0x00000100; +pub const MNT_UPDATE: c_int = 0x00010000; +pub const MNT_RELOAD: c_int = 0x00040000; +pub const MNT_FORCE: c_int = 0x00080000; + +pub const Q_SYNC: c_int = 0x600; +pub const Q_QUOTAON: c_int = 0x100; +pub const Q_QUOTAOFF: c_int = 0x200; + +pub const TCIOFF: c_int = 3; +pub const TCION: c_int = 4; +pub const TCOOFF: c_int = 1; +pub const TCOON: c_int = 2; +pub const TCIFLUSH: c_int = 1; +pub const TCOFLUSH: c_int = 2; +pub const TCIOFLUSH: c_int = 3; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; +pub const VEOF: usize = 0; +pub const VEOL: usize = 1; +pub const VEOL2: usize = 2; +pub const VERASE: usize = 3; +pub const VWERASE: usize = 4; +pub const VKILL: usize = 5; +pub const VREPRINT: usize = 6; +pub const VINTR: usize = 8; +pub const VQUIT: usize = 9; +pub const VSUSP: usize = 10; +pub const VDSUSP: usize = 11; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VLNEXT: usize = 14; +pub const VDISCARD: usize = 15; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; +pub const VSTATUS: usize = 18; +pub const _POSIX_VDISABLE: crate::cc_t = 0xff; +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNPAR: crate::tcflag_t = 0x00000004; +pub const PARMRK: crate::tcflag_t = 0x00000008; +pub const INPCK: crate::tcflag_t = 0x00000010; +pub const ISTRIP: crate::tcflag_t = 0x00000020; +pub const INLCR: crate::tcflag_t = 0x00000040; +pub const IGNCR: crate::tcflag_t = 0x00000080; +pub const ICRNL: crate::tcflag_t = 0x00000100; +pub const IXON: crate::tcflag_t = 0x00000200; +pub const IXOFF: crate::tcflag_t = 0x00000400; +pub const IXANY: crate::tcflag_t = 0x00000800; +pub const IMAXBEL: crate::tcflag_t = 0x00002000; +pub const OPOST: crate::tcflag_t = 0x1; +pub const ONLCR: crate::tcflag_t = 0x2; +pub const OXTABS: crate::tcflag_t = 0x4; +pub const ONOEOT: crate::tcflag_t = 0x8; +pub const CIGNORE: crate::tcflag_t = 0x00000001; +pub const CSIZE: crate::tcflag_t = 0x00000300; +pub const CS5: crate::tcflag_t = 0x00000000; +pub const CS6: crate::tcflag_t = 0x00000100; +pub const CS7: crate::tcflag_t = 0x00000200; +pub const CS8: crate::tcflag_t = 0x00000300; +pub const CSTOPB: crate::tcflag_t = 0x00000400; +pub const CREAD: crate::tcflag_t = 0x00000800; +pub const PARENB: crate::tcflag_t = 0x00001000; +pub const PARODD: crate::tcflag_t = 0x00002000; +pub const HUPCL: crate::tcflag_t = 0x00004000; +pub const CLOCAL: crate::tcflag_t = 0x00008000; +pub const ECHOKE: crate::tcflag_t = 0x00000001; +pub const ECHOE: crate::tcflag_t = 0x00000002; +pub const ECHOK: crate::tcflag_t = 0x00000004; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const ECHONL: crate::tcflag_t = 0x00000010; +pub const ECHOPRT: crate::tcflag_t = 0x00000020; +pub const ECHOCTL: crate::tcflag_t = 0x00000040; +pub const ISIG: crate::tcflag_t = 0x00000080; +pub const ICANON: crate::tcflag_t = 0x00000100; +pub const ALTWERASE: crate::tcflag_t = 0x00000200; +pub const IEXTEN: crate::tcflag_t = 0x00000400; +pub const EXTPROC: crate::tcflag_t = 0x00000800; +pub const TOSTOP: crate::tcflag_t = 0x00400000; +pub const FLUSHO: crate::tcflag_t = 0x00800000; +pub const NOKERNINFO: crate::tcflag_t = 0x02000000; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x80000000; +pub const MDMBUF: crate::tcflag_t = 0x00100000; + +pub const WNOHANG: c_int = 0x00000001; +pub const WUNTRACED: c_int = 0x00000002; + +pub const RTLD_LAZY: c_int = 0x1; +pub const RTLD_NOW: c_int = 0x2; +pub const RTLD_NEXT: *mut c_void = -1isize as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = -2isize as *mut c_void; +pub const RTLD_SELF: *mut c_void = -3isize as *mut c_void; + +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_FTP: c_int = 11 << 3; +pub const LOG_PERROR: c_int = 0x20; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; + +pub const PIPE_BUF: usize = 512; + +// si_code values for SIGBUS signal +pub const BUS_ADRALN: c_int = 1; +pub const BUS_ADRERR: c_int = 2; +pub const BUS_OBJERR: c_int = 3; + +// si_code values for SIGCHLD signal +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; +pub const POLLRDNORM: c_short = 0x040; +pub const POLLWRNORM: c_short = 0x004; +pub const POLLRDBAND: c_short = 0x080; +pub const POLLWRBAND: c_short = 0x100; + +cfg_if! { + // Not yet implemented on NetBSD + if #[cfg(not(any(target_os = "netbsd")))] { + pub const BIOCGBLEN: c_ulong = 0x40044266; + pub const BIOCSBLEN: c_ulong = 0xc0044266; + pub const BIOCFLUSH: c_uint = 0x20004268; + pub const BIOCPROMISC: c_uint = 0x20004269; + pub const BIOCGDLT: c_ulong = 0x4004426a; + pub const BIOCGETIF: c_ulong = 0x4020426b; + pub const BIOCSETIF: c_ulong = 0x8020426c; + pub const BIOCGSTATS: c_ulong = 0x4008426f; + pub const BIOCIMMEDIATE: c_ulong = 0x80044270; + pub const BIOCVERSION: c_ulong = 0x40044271; + pub const BIOCGHDRCMPLT: c_ulong = 0x40044274; + pub const BIOCSHDRCMPLT: c_ulong = 0x80044275; + pub const SIOCGIFADDR: c_ulong = 0xc0206921; + } +} + +pub const REG_BASIC: c_int = 0o0000; +pub const REG_EXTENDED: c_int = 0o0001; +pub const REG_ICASE: c_int = 0o0002; +pub const REG_NOSUB: c_int = 0o0004; +pub const REG_NEWLINE: c_int = 0o0010; +pub const REG_NOSPEC: c_int = 0o0020; +pub const REG_PEND: c_int = 0o0040; +pub const REG_DUMP: c_int = 0o0200; + +pub const REG_NOMATCH: c_int = 1; +pub const REG_BADPAT: c_int = 2; +pub const REG_ECOLLATE: c_int = 3; +pub const REG_ECTYPE: c_int = 4; +pub const REG_EESCAPE: c_int = 5; +pub const REG_ESUBREG: c_int = 6; +pub const REG_EBRACK: c_int = 7; +pub const REG_EPAREN: c_int = 8; +pub const REG_EBRACE: c_int = 9; +pub const REG_BADBR: c_int = 10; +pub const REG_ERANGE: c_int = 11; +pub const REG_ESPACE: c_int = 12; +pub const REG_BADRPT: c_int = 13; +pub const REG_EMPTY: c_int = 14; +pub const REG_ASSERT: c_int = 15; +pub const REG_INVARG: c_int = 16; +pub const REG_ATOI: c_int = 255; +pub const REG_ITOA: c_int = 0o0400; + +pub const REG_NOTBOL: c_int = 0o00001; +pub const REG_NOTEOL: c_int = 0o00002; +pub const REG_STARTEND: c_int = 0o00004; +pub const REG_TRACE: c_int = 0o00400; +pub const REG_LARGE: c_int = 0o01000; +pub const REG_BACKR: c_int = 0o02000; + +pub const TIOCCBRK: c_uint = 0x2000747a; +pub const TIOCSBRK: c_uint = 0x2000747b; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +// net/route.h + +pub const RTF_UP: c_int = 0x1; +pub const RTF_GATEWAY: c_int = 0x2; +pub const RTF_HOST: c_int = 0x4; +pub const RTF_REJECT: c_int = 0x8; +pub const RTF_DYNAMIC: c_int = 0x10; +pub const RTF_MODIFIED: c_int = 0x20; +pub const RTF_DONE: c_int = 0x40; +pub const RTF_STATIC: c_int = 0x800; +pub const RTF_BLACKHOLE: c_int = 0x1000; +pub const RTF_PROTO2: c_int = 0x4000; +pub const RTF_PROTO1: c_int = 0x8000; + +// Message types +pub const RTM_ADD: c_int = 0x1; +pub const RTM_DELETE: c_int = 0x2; +pub const RTM_CHANGE: c_int = 0x3; +pub const RTM_GET: c_int = 0x4; +pub const RTM_LOSING: c_int = 0x5; +pub const RTM_REDIRECT: c_int = 0x6; +pub const RTM_MISS: c_int = 0x7; + +// Bitmask values for rtm_addrs. +pub const RTA_DST: c_int = 0x1; +pub const RTA_GATEWAY: c_int = 0x2; +pub const RTA_NETMASK: c_int = 0x4; +pub const RTA_GENMASK: c_int = 0x8; +pub const RTA_IFP: c_int = 0x10; +pub const RTA_IFA: c_int = 0x20; +pub const RTA_AUTHOR: c_int = 0x40; +pub const RTA_BRD: c_int = 0x80; + +// Index offsets for sockaddr array for alternate internal encoding. +pub const RTAX_DST: c_int = 0; +pub const RTAX_GATEWAY: c_int = 1; +pub const RTAX_NETMASK: c_int = 2; +pub const RTAX_GENMASK: c_int = 3; +pub const RTAX_IFP: c_int = 4; +pub const RTAX_IFA: c_int = 5; +pub const RTAX_AUTHOR: c_int = 6; +pub const RTAX_BRD: c_int = 7; + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const crate::msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control.cast::() + } else { + core::ptr::null_mut() + } + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in &mut (*set).fds_bits { + *slot = 0; + } + } +} + +safe_f! { + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0o177 + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0o177) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0x00ff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0o200) != 0 + } + + pub const fn QCMD(cmd: c_int, type_: c_int) -> c_int { + (cmd << 8) | (type_ & 0x00ff) + } +} + +extern "C" { + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getrlimit$UNIX2003" + )] + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "setrlimit$UNIX2003" + )] + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + #[cfg_attr( + all(target_os = "freebsd", any(freebsd12, freebsd11, freebsd10)), + link_name = "rand@FBSD_1.0" + )] + pub fn rand() -> c_int; + #[cfg_attr( + all(target_os = "freebsd", any(freebsd12, freebsd11, freebsd10)), + link_name = "srand@FBSD_1.0" + )] + pub fn srand(seed: c_uint); + + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + pub fn setgroups(ngroups: c_int, ptr: *const crate::gid_t) -> c_int; + pub fn setlogin(name: *const c_char) -> c_int; + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; + pub fn kqueue() -> c_int; + pub fn unmount(target: *const c_char, arg: c_int) -> c_int; + pub fn syscall(num: c_int, ...) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwent50")] + pub fn getpwent() -> *mut passwd; + pub fn setpwent(); + pub fn endpwent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + + pub fn getprogname() -> *const c_char; + pub fn setprogname(name: *const c_char); + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn getpeereid(socket: c_int, euid: *mut crate::uid_t, egid: *mut crate::gid_t) -> c_int; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "glob$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__glob30")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "glob@FBSD_1.0" + )] + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__globfree30")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "globfree@FBSD_1.0" + )] + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn shm_unlink(name: *const c_char) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "seekdir$INODE64" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "seekdir$INODE64$UNIX2003" + )] + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "telldir$INODE64" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "telldir$INODE64$UNIX2003" + )] + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "msync$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__msync13")] + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "recvfrom$UNIX2003" + )] + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__futimes50")] + pub fn futimes(fd: c_int, times: *const crate::timeval) -> c_int; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "bind$UNIX2003" + )] + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "writev$UNIX2003" + )] + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "readv$UNIX2003" + )] + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sendmsg$UNIX2003" + )] + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "recvmsg$UNIX2003" + )] + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + + pub fn sync(); + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigsuspend14")] + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003" + )] + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cancel$UNIX2003" + )] + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sigwait$UNIX2003" + )] + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003" + )] + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn acct(filename: *const c_char) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "wait4$UNIX2003" + )] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd12, freebsd11, freebsd10)), + link_name = "wait4@FBSD_1.0" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__wait450")] + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getitimer$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__getitimer50")] + pub fn getitimer(which: c_int, curr_value: *mut crate::itimerval) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "setitimer$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__setitimer50")] + pub fn setitimer( + which: c_int, + new_value: *const crate::itimerval, + old_value: *mut crate::itimerval, + ) -> c_int; + + pub fn regcomp(preg: *mut regex_t, pattern: *const c_char, cflags: c_int) -> c_int; + + pub fn regexec( + preg: *const regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + + pub fn regerror( + errcode: c_int, + preg: *const regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + + pub fn regfree(preg: *mut regex_t); + + pub fn arc4random() -> u32; + pub fn arc4random_buf(buf: *mut c_void, size: size_t); + pub fn arc4random_uniform(l: u32) -> u32; + + pub fn drand48() -> c_double; + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn lrand48() -> c_long; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn mrand48() -> c_long; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn srand48(seed: c_long); + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn lcong48(p: *mut c_ushort); + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + + pub fn strftime( + buf: *mut c_char, + maxsize: size_t, + format: *const c_char, + timeptr: *const crate::tm, + ) -> size_t; + pub fn strftime_l( + buf: *mut c_char, + maxsize: size_t, + format: *const c_char, + timeptr: *const crate::tm, + locale: crate::locale_t, + ) -> size_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__devname50")] + pub fn devname(dev: crate::dev_t, mode_t: crate::mode_t) -> *mut c_char; + + pub fn issetugid() -> c_int; +} + +cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" + ))] { + mod apple; + pub use self::apple::*; + } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd"))] { + mod netbsdlike; + pub use self::netbsdlike::*; + } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + mod freebsdlike; + pub use self::freebsdlike::*; + } else { + // Unknown target_os + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/mod.rs new file mode 100644 index 00000000000000..ac0d91286b5b49 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/mod.rs @@ -0,0 +1,882 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type time_t = i64; +pub type mode_t = u32; +pub type nlink_t = u32; +pub type ino_t = u64; +pub type pthread_key_t = c_int; +pub type rlim_t = u64; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type nl_item = c_long; +pub type clockid_t = c_int; +pub type id_t = u32; +pub type sem_t = *mut sem; +pub type key_t = c_long; + +extern_ty! { + pub enum timezone {} + pub enum sem {} +} + +s! { + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: c_int, + pub c_ospeed: c_int, + } + + pub struct flock { + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + pub l_type: c_short, + pub l_whence: c_short, + } + + pub struct ptrace_io_desc { + pub piod_op: c_int, + pub piod_offs: *mut c_void, + pub piod_addr: *mut c_void, + pub piod_len: size_t, + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } +} + +pub const D_T_FMT: crate::nl_item = 0; +pub const D_FMT: crate::nl_item = 1; +pub const T_FMT: crate::nl_item = 2; +pub const T_FMT_AMPM: crate::nl_item = 3; +pub const AM_STR: crate::nl_item = 4; +pub const PM_STR: crate::nl_item = 5; + +pub const DAY_1: crate::nl_item = 6; +pub const DAY_2: crate::nl_item = 7; +pub const DAY_3: crate::nl_item = 8; +pub const DAY_4: crate::nl_item = 9; +pub const DAY_5: crate::nl_item = 10; +pub const DAY_6: crate::nl_item = 11; +pub const DAY_7: crate::nl_item = 12; + +pub const ABDAY_1: crate::nl_item = 13; +pub const ABDAY_2: crate::nl_item = 14; +pub const ABDAY_3: crate::nl_item = 15; +pub const ABDAY_4: crate::nl_item = 16; +pub const ABDAY_5: crate::nl_item = 17; +pub const ABDAY_6: crate::nl_item = 18; +pub const ABDAY_7: crate::nl_item = 19; + +pub const MON_1: crate::nl_item = 20; +pub const MON_2: crate::nl_item = 21; +pub const MON_3: crate::nl_item = 22; +pub const MON_4: crate::nl_item = 23; +pub const MON_5: crate::nl_item = 24; +pub const MON_6: crate::nl_item = 25; +pub const MON_7: crate::nl_item = 26; +pub const MON_8: crate::nl_item = 27; +pub const MON_9: crate::nl_item = 28; +pub const MON_10: crate::nl_item = 29; +pub const MON_11: crate::nl_item = 30; +pub const MON_12: crate::nl_item = 31; + +pub const ABMON_1: crate::nl_item = 32; +pub const ABMON_2: crate::nl_item = 33; +pub const ABMON_3: crate::nl_item = 34; +pub const ABMON_4: crate::nl_item = 35; +pub const ABMON_5: crate::nl_item = 36; +pub const ABMON_6: crate::nl_item = 37; +pub const ABMON_7: crate::nl_item = 38; +pub const ABMON_8: crate::nl_item = 39; +pub const ABMON_9: crate::nl_item = 40; +pub const ABMON_10: crate::nl_item = 41; +pub const ABMON_11: crate::nl_item = 42; +pub const ABMON_12: crate::nl_item = 43; + +pub const RADIXCHAR: crate::nl_item = 44; +pub const THOUSEP: crate::nl_item = 45; +pub const YESSTR: crate::nl_item = 46; +pub const YESEXPR: crate::nl_item = 47; +pub const NOSTR: crate::nl_item = 48; +pub const NOEXPR: crate::nl_item = 49; +pub const CRNCYSTR: crate::nl_item = 50; + +pub const CODESET: crate::nl_item = 51; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const BUFSIZ: c_uint = 1024; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 1024; +pub const L_tmpnam: c_uint = 1024; +pub const O_NOCTTY: c_int = 32768; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_ANON: c_int = 0x1000; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const IPC_CREAT: c_int = 0o001000; +pub const IPC_EXCL: c_int = 0o002000; +pub const IPC_NOWAIT: c_int = 0o004000; + +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; + +pub const IPC_R: c_int = 0o000400; +pub const IPC_W: c_int = 0o000200; +pub const IPC_M: c_int = 0o010000; + +pub const SHM_R: c_int = IPC_R; +pub const SHM_W: c_int = IPC_W; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const MS_ASYNC: c_int = 0x0001; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EDEADLK: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EAGAIN: c_int = 35; +pub const EWOULDBLOCK: c_int = 35; +pub const EINPROGRESS: c_int = 36; +pub const EALREADY: c_int = 37; +pub const ENOTSOCK: c_int = 38; +pub const EDESTADDRREQ: c_int = 39; +pub const EMSGSIZE: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const EOPNOTSUPP: c_int = 45; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENETDOWN: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const ELOOP: c_int = 62; +pub const ENAMETOOLONG: c_int = 63; +pub const EHOSTDOWN: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const ENOTEMPTY: c_int = 66; +pub const EPROCLIM: c_int = 67; +pub const EUSERS: c_int = 68; +pub const EDQUOT: c_int = 69; +pub const ESTALE: c_int = 70; +pub const EREMOTE: c_int = 71; +pub const EBADRPC: c_int = 72; +pub const ERPCMISMATCH: c_int = 73; +pub const EPROGUNAVAIL: c_int = 74; +pub const EPROGMISMATCH: c_int = 75; +pub const EPROCUNAVAIL: c_int = 76; +pub const ENOLCK: c_int = 77; +pub const ENOSYS: c_int = 78; +pub const EFTYPE: c_int = 79; +pub const EAUTH: c_int = 80; +pub const ENEEDAUTH: c_int = 81; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; + +pub const SIGTRAP: c_int = 5; + +pub const GLOB_APPEND: c_int = 0x0001; +pub const GLOB_DOOFFS: c_int = 0x0002; +pub const GLOB_ERR: c_int = 0x0004; +pub const GLOB_MARK: c_int = 0x0008; +pub const GLOB_NOCHECK: c_int = 0x0010; +pub const GLOB_NOSORT: c_int = 0x0020; +pub const GLOB_NOESCAPE: c_int = 0x1000; + +pub const GLOB_NOSPACE: c_int = -1; +pub const GLOB_ABORTED: c_int = -2; +pub const GLOB_NOMATCH: c_int = -3; +pub const GLOB_NOSYS: c_int = -4; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; + +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x02; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x04; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x08; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x10; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x20; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +pub const PIOD_READ_D: c_int = 1; +pub const PIOD_WRITE_D: c_int = 2; +pub const PIOD_READ_I: c_int = 3; +pub const PIOD_WRITE_I: c_int = 4; +pub const PIOD_READ_AUXV: c_int = 5; + +pub const PT_TRACE_ME: c_int = 0; +pub const PT_READ_I: c_int = 1; +pub const PT_READ_D: c_int = 2; +pub const PT_WRITE_I: c_int = 4; +pub const PT_WRITE_D: c_int = 5; +pub const PT_CONTINUE: c_int = 7; +pub const PT_KILL: c_int = 8; +pub const PT_ATTACH: c_int = 9; +pub const PT_DETACH: c_int = 10; +pub const PT_IO: c_int = 11; + +// http://man.openbsd.org/OpenBSD-current/man2/clock_getres.2 +// The man page says clock_gettime(3) can accept various values as clockid_t but +// http://fxr.watson.org/fxr/source/kern/kern_time.c?v=OPENBSD;im=excerpts#L161 +// the implementation rejects anything other than the below two +// +// http://netbsd.gw.com/cgi-bin/man-cgi?clock_gettime +// https://github.com/jsonn/src/blob/HEAD/sys/kern/subr_time.c#L222 +// Basically the same goes for NetBSD +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC: crate::clockid_t = 3; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_MEMLOCK: c_int = 6; +pub const RLIMIT_NPROC: c_int = 7; +pub const RLIMIT_NOFILE: c_int = 8; + +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; +pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 6; + +// sys/fstypes.h in NetBSD, or sys/mount.h in OpenBSD +pub const MNT_NODEV: c_int = 0x00000010; +pub const MNT_LOCAL: c_int = 0x00001000; +pub const MNT_QUOTA: c_int = 0x00002000; + +// sys/ioccom.h in NetBSD and OpenBSD +pub const IOCPARM_MASK: u32 = 0x1fff; + +pub const IOC_VOID: c_ulong = 0x20000000; +pub const IOC_OUT: c_ulong = 0x40000000; +pub const IOC_IN: c_ulong = 0x80000000; +pub const IOC_INOUT: c_ulong = IOC_IN | IOC_OUT; +pub const IOC_DIRMASK: c_ulong = 0xe0000000; + +pub const fn _IO(g: c_ulong, n: c_ulong) -> c_ulong { + _IOC(IOC_VOID, g, n, 0) +} + +/// Build an ioctl number for an read-only ioctl. +pub const fn _IOR(g: c_ulong, n: c_ulong) -> c_ulong { + _IOC(IOC_OUT, g, n, mem::size_of::() as c_ulong) +} + +/// Build an ioctl number for an write-only ioctl. +pub const fn _IOW(g: c_ulong, n: c_ulong) -> c_ulong { + _IOC(IOC_IN, g, n, mem::size_of::() as c_ulong) +} + +/// Build an ioctl number for a read-write ioctl. +pub const fn _IOWR(g: c_ulong, n: c_ulong) -> c_ulong { + _IOC(IOC_INOUT, g, n, mem::size_of::() as c_ulong) +} + +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_LINK: c_int = 18; +pub const pseudo_AF_XTP: c_int = 19; +pub const AF_COIP: c_int = 20; +pub const AF_CNT: c_int = 21; +pub const pseudo_AF_RTIP: c_int = 22; +pub const AF_IPX: c_int = 23; +pub const AF_INET6: c_int = 24; +pub const pseudo_AF_PIP: c_int = 25; +pub const AF_ISDN: c_int = 26; +pub const AF_E164: c_int = AF_ISDN; +pub const AF_NATM: c_int = 27; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_ISO; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_XTP: c_int = pseudo_AF_XTP; +pub const PF_COIP: c_int = AF_COIP; +pub const PF_CNT: c_int = AF_CNT; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_RTIP: c_int = pseudo_AF_RTIP; +pub const PF_PIP: c_int = pseudo_AF_PIP; +pub const PF_ISDN: c_int = AF_ISDN; +pub const PF_NATM: c_int = AF_NATM; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const IP_TTL: c_int = 4; +pub const IP_HDRINCL: c_int = 2; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IPV6_RECVPKTINFO: c_int = 36; +pub const IPV6_PKTINFO: c_int = 46; +pub const IPV6_RECVTCLASS: c_int = 57; +pub const IPV6_TCLASS: c_int = 61; + +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 0x01; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; + +pub const SOMAXCONN: c_int = 128; + +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_EOR: c_int = 0x8; +pub const MSG_TRUNC: c_int = 0x10; +pub const MSG_CTRUNC: c_int = 0x20; +pub const MSG_WAITALL: c_int = 0x40; +pub const MSG_DONTWAIT: c_int = 0x80; +pub const MSG_BCAST: c_int = 0x100; +pub const MSG_MCAST: c_int = 0x200; +pub const MSG_NOSIGNAL: c_int = 0x400; +pub const MSG_CMSG_CLOEXEC: c_int = 0x800; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const IPPROTO_RAW: c_int = 255; + +pub const _SC_ARG_MAX: c_int = 1; +pub const _SC_CHILD_MAX: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 4; +pub const _SC_OPEN_MAX: c_int = 5; +pub const _SC_JOB_CONTROL: c_int = 6; +pub const _SC_SAVED_IDS: c_int = 7; +pub const _SC_VERSION: c_int = 8; +pub const _SC_BC_BASE_MAX: c_int = 9; +pub const _SC_BC_DIM_MAX: c_int = 10; +pub const _SC_BC_SCALE_MAX: c_int = 11; +pub const _SC_BC_STRING_MAX: c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; +pub const _SC_EXPR_NEST_MAX: c_int = 14; +pub const _SC_LINE_MAX: c_int = 15; +pub const _SC_RE_DUP_MAX: c_int = 16; +pub const _SC_2_VERSION: c_int = 17; +pub const _SC_2_C_BIND: c_int = 18; +pub const _SC_2_C_DEV: c_int = 19; +pub const _SC_2_CHAR_TERM: c_int = 20; +pub const _SC_2_FORT_DEV: c_int = 21; +pub const _SC_2_FORT_RUN: c_int = 22; +pub const _SC_2_LOCALEDEF: c_int = 23; +pub const _SC_2_SW_DEV: c_int = 24; +pub const _SC_2_UPE: c_int = 25; +pub const _SC_STREAM_MAX: c_int = 26; +pub const _SC_TZNAME_MAX: c_int = 27; +pub const _SC_PAGESIZE: c_int = 28; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_FSYNC: c_int = 29; +pub const _SC_XOPEN_SHM: c_int = 30; + +pub const Q_GETQUOTA: c_int = 0x300; +pub const Q_SETQUOTA: c_int = 0x400; + +pub const RTLD_GLOBAL: c_int = 0x100; + +pub const LOG_NFACILITIES: c_int = 24; + +pub const HW_NCPU: c_int = 3; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SEM_FAILED: *mut sem_t = ptr::null_mut(); + +pub const CRTSCTS: crate::tcflag_t = 0x00010000; +pub const CRTS_IFLOW: crate::tcflag_t = CRTSCTS; +pub const CCTS_OFLOW: crate::tcflag_t = CRTSCTS; +pub const OCRNL: crate::tcflag_t = 0x10; + +pub const TIOCEXCL: c_ulong = 0x2000740d; +pub const TIOCNXCL: c_ulong = 0x2000740e; +pub const TIOCFLUSH: c_ulong = 0x80047410; +pub const TIOCGETA: c_ulong = 0x402c7413; +pub const TIOCSETA: c_ulong = 0x802c7414; +pub const TIOCSETAW: c_ulong = 0x802c7415; +pub const TIOCSETAF: c_ulong = 0x802c7416; +pub const TIOCGETD: c_ulong = 0x4004741a; +pub const TIOCSETD: c_ulong = 0x8004741b; +pub const TIOCMGET: c_ulong = 0x4004746a; +pub const TIOCMBIC: c_ulong = 0x8004746b; +pub const TIOCMBIS: c_ulong = 0x8004746c; +pub const TIOCMSET: c_ulong = 0x8004746d; +pub const TIOCSTART: c_ulong = 0x2000746e; +pub const TIOCSTOP: c_ulong = 0x2000746f; +pub const TIOCSCTTY: c_ulong = 0x20007461; +pub const TIOCGWINSZ: c_ulong = 0x40087468; +pub const TIOCSWINSZ: c_ulong = 0x80087467; +pub const TIOCM_LE: c_int = 0o0001; +pub const TIOCM_DTR: c_int = 0o0002; +pub const TIOCM_RTS: c_int = 0o0004; +pub const TIOCM_ST: c_int = 0o0010; +pub const TIOCM_SR: c_int = 0o0020; +pub const TIOCM_CTS: c_int = 0o0040; +pub const TIOCM_CAR: c_int = 0o0100; +pub const TIOCM_RNG: c_int = 0o0200; +pub const TIOCM_DSR: c_int = 0o0400; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RI: c_int = TIOCM_RNG; + +pub const TIMER_ABSTIME: c_int = 1; + +// sys/reboot.h + +pub const RB_AUTOBOOT: c_int = 0; + +pub const TCP_INFO: c_int = 9; + +#[link(name = "util")] +extern "C" { + pub fn setgrent(); + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn accept4( + s: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_char) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_getres50")] + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_gettime50")] + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_settime50")] + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn __errno() -> *mut c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + pub fn login_tty(fd: c_int) -> c_int; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: crate::dev_t) + -> c_int; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const sched_param, + ) -> c_int; + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut sched_param, + ) -> c_int; + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: crate::nfds_t, + ts: *const crate::timespec, + sigmask: *const crate::sigset_t, + ) -> c_int; + + pub fn getgrouplist( + name: *const c_char, + basegid: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn initgroups(name: *const c_char, basegid: crate::gid_t) -> c_int; + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + pub fn setdomainname(name: *const c_char, len: size_t) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + + pub fn shmget(key: crate::key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__shmctl50")] + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + + pub fn waitid( + idtype: idtype_t, + id: crate::id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; +} + +extern "C" { + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + pub fn gethostid() -> c_long; + pub fn sethostid(hostid: c_long) -> c_int; + pub fn ftok(path: *const c_char, id: c_int) -> crate::key_t; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + pub fn sendmmsg(sockfd: c_int, mmsg: *mut crate::mmsghdr, vlen: c_uint, flags: c_int) -> c_int; + pub fn recvmmsg( + sockfd: c_int, + mmsg: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *mut crate::timespec, + ) -> c_int; + + pub fn closefrom(lowfd: c_int) -> c_int; +} + +cfg_if! { + if #[cfg(target_os = "netbsd")] { + mod netbsd; + pub use self::netbsd::*; + } else if #[cfg(target_os = "openbsd")] { + mod openbsd; + pub use self::openbsd::*; + } else { + // Unknown target_os + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs new file mode 100644 index 00000000000000..e0206af04f8f1b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs @@ -0,0 +1,132 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type greg_t = u64; +pub type __cpu_simple_lock_nv_t = c_uchar; + +s! { + pub struct __fregset { + pub __qregs: [__c_anonymous__freg; 32], + pub __fpcr: u32, + pub __fpsr: u32, + } + + pub struct mcontext_t { + pub __gregs: [crate::greg_t; 32], + pub __fregs: __fregset, + __spare: [crate::greg_t; 8], + } + + pub struct ucontext_t { + pub uc_flags: c_uint, + pub uc_link: *mut ucontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub union __c_anonymous__freg { + pub __b8: [u8; 16], + pub __h16: [u16; 8], + pub __s32: [u32; 4], + pub __d64: [u64; 2], + pub __q128: [u128; 1], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous__freg { + fn eq(&self, other: &__c_anonymous__freg) -> bool { + unsafe { + self.__b8 == other.__b8 + || self.__h16 == other.__h16 + || self.__s32 == other.__s32 + || self.__d64 == other.__d64 + || self.__q128 == other.__q128 + } + } + } + impl Eq for __c_anonymous__freg {} + impl hash::Hash for __c_anonymous__freg { + fn hash(&self, state: &mut H) { + unsafe { + self.__b8.hash(state); + self.__h16.hash(state); + self.__s32.hash(state); + self.__d64.hash(state); + self.__q128.hash(state); + } + } + } + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 0; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 3; + +pub const _REG_R0: c_int = 0; +pub const _REG_R1: c_int = 1; +pub const _REG_R2: c_int = 2; +pub const _REG_R3: c_int = 3; +pub const _REG_R4: c_int = 4; +pub const _REG_R5: c_int = 5; +pub const _REG_R6: c_int = 6; +pub const _REG_R7: c_int = 7; +pub const _REG_R8: c_int = 8; +pub const _REG_R9: c_int = 9; +pub const _REG_R10: c_int = 10; +pub const _REG_R11: c_int = 11; +pub const _REG_R12: c_int = 12; +pub const _REG_R13: c_int = 13; +pub const _REG_R14: c_int = 14; +pub const _REG_R15: c_int = 15; +pub const _REG_CPSR: c_int = 16; +pub const _REG_X0: c_int = 0; +pub const _REG_X1: c_int = 1; +pub const _REG_X2: c_int = 2; +pub const _REG_X3: c_int = 3; +pub const _REG_X4: c_int = 4; +pub const _REG_X5: c_int = 5; +pub const _REG_X6: c_int = 6; +pub const _REG_X7: c_int = 7; +pub const _REG_X8: c_int = 8; +pub const _REG_X9: c_int = 9; +pub const _REG_X10: c_int = 10; +pub const _REG_X11: c_int = 11; +pub const _REG_X12: c_int = 12; +pub const _REG_X13: c_int = 13; +pub const _REG_X14: c_int = 14; +pub const _REG_X15: c_int = 15; +pub const _REG_X16: c_int = 16; +pub const _REG_X17: c_int = 17; +pub const _REG_X18: c_int = 18; +pub const _REG_X19: c_int = 19; +pub const _REG_X20: c_int = 20; +pub const _REG_X21: c_int = 21; +pub const _REG_X22: c_int = 22; +pub const _REG_X23: c_int = 23; +pub const _REG_X24: c_int = 24; +pub const _REG_X25: c_int = 25; +pub const _REG_X26: c_int = 26; +pub const _REG_X27: c_int = 27; +pub const _REG_X28: c_int = 28; +pub const _REG_X29: c_int = 29; +pub const _REG_X30: c_int = 30; +pub const _REG_X31: c_int = 31; +pub const _REG_ELR: c_int = 32; +pub const _REG_SPSR: c_int = 33; +pub const _REG_TIPDR: c_int = 34; + +pub const _REG_RV: c_int = _REG_X0; +pub const _REG_FP: c_int = _REG_X29; +pub const _REG_LR: c_int = _REG_X30; +pub const _REG_SP: c_int = _REG_X31; +pub const _REG_PC: c_int = _REG_ELR; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs new file mode 100644 index 00000000000000..1af255ea8ae63c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs @@ -0,0 +1,70 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type __cpu_simple_lock_nv_t = c_int; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 5; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 6; + +pub const _REG_R0: c_int = 0; +pub const _REG_R1: c_int = 1; +pub const _REG_R2: c_int = 2; +pub const _REG_R3: c_int = 3; +pub const _REG_R4: c_int = 4; +pub const _REG_R5: c_int = 5; +pub const _REG_R6: c_int = 6; +pub const _REG_R7: c_int = 7; +pub const _REG_R8: c_int = 8; +pub const _REG_R9: c_int = 9; +pub const _REG_R10: c_int = 10; +pub const _REG_R11: c_int = 11; +pub const _REG_R12: c_int = 12; +pub const _REG_R13: c_int = 13; +pub const _REG_R14: c_int = 14; +pub const _REG_R15: c_int = 15; +pub const _REG_CPSR: c_int = 16; +pub const _REG_X0: c_int = 0; +pub const _REG_X1: c_int = 1; +pub const _REG_X2: c_int = 2; +pub const _REG_X3: c_int = 3; +pub const _REG_X4: c_int = 4; +pub const _REG_X5: c_int = 5; +pub const _REG_X6: c_int = 6; +pub const _REG_X7: c_int = 7; +pub const _REG_X8: c_int = 8; +pub const _REG_X9: c_int = 9; +pub const _REG_X10: c_int = 10; +pub const _REG_X11: c_int = 11; +pub const _REG_X12: c_int = 12; +pub const _REG_X13: c_int = 13; +pub const _REG_X14: c_int = 14; +pub const _REG_X15: c_int = 15; +pub const _REG_X16: c_int = 16; +pub const _REG_X17: c_int = 17; +pub const _REG_X18: c_int = 18; +pub const _REG_X19: c_int = 19; +pub const _REG_X20: c_int = 20; +pub const _REG_X21: c_int = 21; +pub const _REG_X22: c_int = 22; +pub const _REG_X23: c_int = 23; +pub const _REG_X24: c_int = 24; +pub const _REG_X25: c_int = 25; +pub const _REG_X26: c_int = 26; +pub const _REG_X27: c_int = 27; +pub const _REG_X28: c_int = 28; +pub const _REG_X29: c_int = 29; +pub const _REG_X30: c_int = 30; +pub const _REG_X31: c_int = 31; +pub const _REG_ELR: c_int = 32; +pub const _REG_SPSR: c_int = 33; +pub const _REG_TPIDR: c_int = 34; + +pub const _REG_RV: c_int = _REG_R0; +pub const _REG_FP: c_int = _REG_R11; +pub const _REG_SP: c_int = _REG_R13; +pub const _REG_LR: c_int = _REG_R14; +pub const _REG_PC: c_int = _REG_R15; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mips.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mips.rs new file mode 100644 index 00000000000000..1b24b4f6e3159a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mips.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type __cpu_simple_lock_nv_t = c_int; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 4; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs new file mode 100644 index 00000000000000..f3d027ce343230 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs @@ -0,0 +1,2487 @@ +use crate::prelude::*; +use crate::{ + cmsghdr, + cpuid_t, + lwpid_t, + off_t, +}; + +pub type blksize_t = i32; +pub type eventfd_t = u64; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type idtype_t = c_int; +type __pthread_spin_t = __cpu_simple_lock_nv_t; +pub type shmatt_t = c_uint; +pub type cpuset_t = _cpuset; +pub type pthread_spin_t = __pthread_spin_t; + +// elf.h + +pub type Elf32_Addr = u32; +pub type Elf32_Half = u16; +pub type Elf32_Lword = u64; +pub type Elf32_Off = u32; +pub type Elf32_Sword = i32; +pub type Elf32_Word = u32; + +pub type Elf64_Addr = u64; +pub type Elf64_Half = u16; +pub type Elf64_Lword = u64; +pub type Elf64_Off = u64; +pub type Elf64_Sword = i32; +pub type Elf64_Sxword = i64; +pub type Elf64_Word = u32; +pub type Elf64_Xword = u64; + +pub type iconv_t = *mut c_void; + +e! { + #[repr(C)] + pub enum fae_action { + FAE_OPEN, + FAE_DUP2, + FAE_CLOSE, + } +} + +extern_ty! { + pub enum _cpuset {} +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + type Elf_Addr = Elf64_Addr; + type Elf_Half = Elf64_Half; + type Elf_Phdr = Elf64_Phdr; + } else if #[cfg(target_pointer_width = "32")] { + type Elf_Addr = Elf32_Addr; + type Elf_Half = Elf32_Half; + type Elf_Phdr = Elf32_Phdr; + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_code(&self) -> c_int { + self.si_code + } + + pub unsafe fn si_errno(&self) -> c_int { + self.si_errno + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + #[cfg(target_pointer_width = "64")] + __pad1: Padding, + _pid: crate::pid_t, + } + (*(self as *const siginfo_t as *const siginfo_timer))._pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + #[cfg(target_pointer_width = "64")] + __pad1: Padding, + _pid: crate::pid_t, + _uid: crate::uid_t, + } + (*(self as *const siginfo_t as *const siginfo_timer))._uid + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + #[cfg(target_pointer_width = "64")] + __pad1: Padding, + _pid: crate::pid_t, + _uid: crate::uid_t, + value: crate::sigval, + } + (*(self as *const siginfo_t as *const siginfo_timer)).value + } + + pub unsafe fn si_status(&self) -> c_int { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + #[cfg(target_pointer_width = "64")] + __pad1: Padding, + _pid: crate::pid_t, + _uid: crate::uid_t, + status: c_int, + } + (*(self as *const siginfo_t as *const siginfo_timer)).status + } +} + +s! { + pub struct aiocb { + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_fildes: c_int, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + pub aio_sigevent: crate::sigevent, + _state: c_int, + _errno: c_int, + _retval: ssize_t, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_matchc: size_t, + pub gl_offs: size_t, + pub gl_flags: c_int, + pub gl_pathv: *mut *mut c_char, + + __unused3: Padding<*mut c_void>, + + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + __unused6: Padding<*mut c_void>, + __unused7: Padding<*mut c_void>, + __unused8: Padding<*mut c_void>, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *mut c_char, + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + } + + pub struct sigset_t { + __bits: [u32; 4], + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_mode: crate::mode_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_atime: crate::time_t, + pub st_atimensec: c_long, + pub st_mtime: crate::time_t, + pub st_mtimensec: c_long, + pub st_ctime: crate::time_t, + pub st_ctimensec: c_long, + pub st_birthtime: crate::time_t, + pub st_birthtimensec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: u32, + pub st_gen: u32, + pub st_spare: [u32; 2], + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: crate::socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut crate::addrinfo, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + #[cfg(target_pointer_width = "64")] + __pad1: Padding, + pub si_addr: *mut c_void, + #[cfg(target_pointer_width = "64")] + __pad2: Padding<[u64; 13]>, + #[cfg(target_pointer_width = "32")] + __pad2: Padding<[u64; 14]>, + } + + pub struct pthread_attr_t { + pta_magic: c_uint, + pta_flags: c_int, + pta_private: *mut c_void, + } + + pub struct pthread_mutex_t { + ptm_magic: c_uint, + ptm_errorcheck: __pthread_spin_t, + #[cfg(any( + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "x86", + target_arch = "x86_64" + ))] + ptm_pad1: Padding<[u8; 3]>, + // actually a union with a non-unused, 0-initialized field + ptm_unused: Padding<__pthread_spin_t>, + #[cfg(any( + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "x86", + target_arch = "x86_64" + ))] + ptm_pad2: Padding<[u8; 3]>, + ptm_owner: crate::pthread_t, + ptm_waiters: *mut u8, + ptm_recursed: c_uint, + ptm_spare2: *mut c_void, + } + + pub struct pthread_mutexattr_t { + ptma_magic: c_uint, + ptma_private: *mut c_void, + } + + pub struct pthread_rwlockattr_t { + ptra_magic: c_uint, + ptra_private: *mut c_void, + } + + pub struct pthread_cond_t { + ptc_magic: c_uint, + ptc_lock: __pthread_spin_t, + ptc_waiters_first: *mut u8, + ptc_waiters_last: *mut u8, + ptc_mutex: *mut crate::pthread_mutex_t, + ptc_private: *mut c_void, + } + + pub struct pthread_condattr_t { + ptca_magic: c_uint, + ptca_private: *mut c_void, + } + + pub struct pthread_rwlock_t { + ptr_magic: c_uint, + ptr_interlock: __pthread_spin_t, + ptr_rblocked_first: *mut u8, + ptr_rblocked_last: *mut u8, + ptr_wblocked_first: *mut u8, + ptr_wblocked_last: *mut u8, + ptr_nreaders: c_uint, + ptr_owner: crate::pthread_t, + ptr_private: *mut c_void, + } + + pub struct pthread_spinlock_t { + pts_magic: c_uint, + pts_spin: crate::pthread_spin_t, + pts_flags: c_int, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: u32, + pub flags: u32, + pub fflags: u32, + pub data: i64, + pub udata: *mut c_void, + } + + pub struct dqblk { + pub dqb_bhardlimit: u32, + pub dqb_bsoftlimit: u32, + pub dqb_curblocks: u32, + pub dqb_ihardlimit: u32, + pub dqb_isoftlimit: u32, + pub dqb_curinodes: u32, + pub dqb_btime: i32, + pub dqb_itime: i32, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *const c_void, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_n_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct sockcred { + pub sc_pid: crate::pid_t, + pub sc_uid: crate::uid_t, + pub sc_euid: crate::uid_t, + pub sc_gid: crate::gid_t, + pub sc_egid: crate::gid_t, + pub sc_ngroups: c_int, + pub sc_groups: [crate::gid_t; 1], + } + + pub struct uucred { + cr_unused: Padding, + pub cr_uid: crate::uid_t, + pub cr_gid: crate::gid_t, + pub cr_ngroups: c_short, + pub cr_groups: [crate::gid_t; NGROUPS_MAX as usize], + } + + pub struct unpcbid { + pub unp_pid: crate::pid_t, + pub unp_euid: crate::uid_t, + pub unp_egid: crate::gid_t, + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: u8, + pub sdl_nlen: u8, + pub sdl_alen: u8, + pub sdl_slen: u8, + pub sdl_data: [c_char; 24], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + _shm_internal: *mut c_void, + } + + // elf.h + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct Aux32Info { + pub a_type: Elf32_Word, + pub a_v: Elf32_Word, + } + + pub struct Aux64Info { + pub a_type: Elf64_Word, + pub a_v: Elf64_Xword, + } + + // sys/sysctl.h + + pub struct kinfo_file { + pub ki_fileaddr: u64, + pub ki_flag: u32, + pub ki_iflags: u32, + pub ki_ftype: u32, + pub ki_count: u32, + pub ki_msgcount: u32, + pub ki_usecount: u32, + pub ki_fucred: u64, + pub ki_fuid: u32, + pub ki_fgid: u32, + pub ki_fops: u64, + pub ki_foffset: u64, + pub ki_fdata: u64, + pub ki_vun: u64, + pub ki_vsize: u64, + pub ki_vtype: u32, + pub ki_vtag: u32, + pub ki_vdata: u64, + pub ki_pid: u32, + pub ki_fd: i32, + pub ki_ofileflags: u32, + _ki_padto64bits: Padding, + } + + // link.h + + pub struct dl_phdr_info { + pub dlpi_addr: Elf_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const Elf_Phdr, + pub dlpi_phnum: Elf_Half, + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: usize, + pub dlpi_tls_data: *mut c_void, + } + + pub struct accept_filter_arg { + pub af_name: [c_char; 16], + af_arg: [c_char; 256 - 16], + } + + pub struct ki_sigset_t { + pub __bits: [u32; 4], + } + + pub struct kinfo_proc2 { + pub p_forw: u64, + pub p_back: u64, + pub p_paddr: u64, + pub p_addr: u64, + pub p_fd: u64, + pub p_cwdi: u64, + pub p_stats: u64, + pub p_limit: u64, + pub p_vmspace: u64, + pub p_sigacts: u64, + pub p_sess: u64, + pub p_tsess: u64, + pub p_ru: u64, + pub p_eflag: i32, + pub p_exitsig: i32, + pub p_flag: i32, + pub p_pid: i32, + pub p_ppid: i32, + pub p_sid: i32, + pub p__pgid: i32, + pub p_tpgid: i32, + pub p_uid: u32, + pub p_ruid: u32, + pub p_gid: u32, + pub p_rgid: u32, + pub p_groups: [u32; KI_NGROUPS as usize], + pub p_ngroups: i16, + pub p_jobc: i16, + pub p_tdev: u32, + pub p_estcpu: u32, + pub p_rtime_sec: u32, + pub p_rtime_usec: u32, + pub p_cpticks: i32, + pub p_pctcpu: u32, + pub p_swtime: u32, + pub p_slptime: u32, + pub p_schedflags: i32, + pub p_uticks: u64, + pub p_sticks: u64, + pub p_iticks: u64, + pub p_tracep: u64, + pub p_traceflag: i32, + pub p_holdcnt: i32, + pub p_siglist: ki_sigset_t, + pub p_sigmask: ki_sigset_t, + pub p_sigignore: ki_sigset_t, + pub p_sigcatch: ki_sigset_t, + pub p_stat: i8, + pub p_priority: u8, + pub p_usrpri: u8, + pub p_nice: u8, + pub p_xstat: u16, + pub p_acflag: u16, + pub p_comm: [c_char; KI_MAXCOMLEN as usize], + pub p_wmesg: [c_char; KI_WMESGLEN as usize], + pub p_wchan: u64, + pub p_login: [c_char; KI_MAXLOGNAME as usize], + pub p_vm_rssize: i32, + pub p_vm_tsize: i32, + pub p_vm_dsize: i32, + pub p_vm_ssize: i32, + pub p_uvalid: i64, + pub p_ustart_sec: u32, + pub p_ustart_usec: u32, + pub p_uutime_sec: u32, + pub p_uutime_usec: u32, + pub p_ustime_sec: u32, + pub p_ustime_usec: u32, + pub p_uru_maxrss: u64, + pub p_uru_ixrss: u64, + pub p_uru_idrss: u64, + pub p_uru_isrss: u64, + pub p_uru_minflt: u64, + pub p_uru_majflt: u64, + pub p_uru_nswap: u64, + pub p_uru_inblock: u64, + pub p_uru_oublock: u64, + pub p_uru_msgsnd: u64, + pub p_uru_msgrcv: u64, + pub p_uru_nsignals: u64, + pub p_uru_nvcsw: u64, + pub p_uru_nivcsw: u64, + pub p_uctime_sec: u32, + pub p_uctime_usec: u32, + pub p_cpuid: u64, + pub p_realflag: u64, + pub p_nlwps: u64, + pub p_nrlwps: u64, + pub p_realstat: u64, + pub p_svuid: u32, + pub p_svgid: u32, + pub p_ename: [c_char; KI_MAXEMULLEN as usize], + pub p_vm_vsize: i64, + pub p_vm_msize: i64, + } + + pub struct kinfo_lwp { + pub l_forw: u64, + pub l_back: u64, + pub l_laddr: u64, + pub l_addr: u64, + pub l_lid: i32, + pub l_flag: i32, + pub l_swtime: u32, + pub l_slptime: u32, + pub l_schedflags: i32, + pub l_holdcnt: i32, + pub l_priority: u8, + pub l_usrpri: u8, + pub l_stat: i8, + l_pad1: Padding, + l_pad2: Padding, + pub l_wmesg: [c_char; KI_WMESGLEN as usize], + pub l_wchan: u64, + pub l_cpuid: u64, + pub l_rtime_sec: u32, + pub l_rtime_usec: u32, + pub l_cpticks: u32, + pub l_pctcpu: u32, + pub l_pid: u32, + pub l_name: [c_char; KI_LNAMELEN as usize], + } + + pub struct kinfo_vmentry { + pub kve_start: u64, + pub kve_end: u64, + pub kve_offset: u64, + pub kve_type: u32, + pub kve_flags: u32, + pub kve_count: u32, + pub kve_wired_count: u32, + pub kve_advice: u32, + pub kve_attributes: u32, + pub kve_protection: u32, + pub kve_max_protection: u32, + pub kve_ref_count: u32, + pub kve_inheritance: u32, + pub kve_vn_fileid: u64, + pub kve_vn_size: u64, + pub kve_vn_fsid: u64, + pub kve_vn_rdev: u64, + pub kve_vn_type: u32, + pub kve_vn_mode: u32, + pub kve_path: [c_char; crate::PATH_MAX as usize], + } + + pub struct __c_anonymous_posix_spawn_fae_open { + pub path: *mut c_char, + pub oflag: c_int, + pub mode: crate::mode_t, + } + + pub struct __c_anonymous_posix_spawn_fae_dup2 { + pub newfildes: c_int, + } + + pub struct posix_spawnattr_t { + pub sa_flags: c_short, + pub sa_pgroup: crate::pid_t, + pub sa_schedparam: crate::sched_param, + pub sa_schedpolicy: c_int, + pub sa_sigdefault: sigset_t, + pub sa_sigmask: sigset_t, + } + + pub struct posix_spawn_file_actions_entry_t { + pub fae_action: fae_action, + pub fae_fildes: c_int, + pub fae_data: __c_anonymous_posix_spawn_fae, + } + + pub struct posix_spawn_file_actions_t { + pub size: c_uint, + pub len: c_uint, + pub fae: *mut posix_spawn_file_actions_entry_t, + } + + #[deprecated(since = "0.2.178", note = "obsolete upstream")] + pub struct ptrace_lwpinfo { + pub pl_lwpid: lwpid_t, + pub pl_event: c_int, + } + + pub struct ptrace_lwpstatus { + pub pl_lwpid: lwpid_t, + pub pl_sigpend: sigset_t, + pub pl_sigmask: sigset_t, + pub pl_name: [c_char; 20], + pub pl_private: *mut c_void, + } + + pub struct ptrace_siginfo { + pub psi_siginfo: siginfo_t, + pub psi_lwpid: lwpid_t, + } + + pub struct ptrace_event { + pub pe_set_event: c_int, + } + + pub struct sysctldesc { + pub descr_num: i32, + pub descr_ver: u32, + pub descr_len: u32, + pub descr_str: [c_char; 1], + } + + pub struct tcp_info { + pub tcpi_state: u8, + pub __tcpi_ca_state: u8, + pub __tcpi_retransmits: u8, + pub __tcpi_probes: u8, + pub __tcpi_backoff: u8, + pub tcpi_options: u8, + pub tcp_snd_wscale: u8, + pub tcp_rcv_wscale: u8, + pub tcpi_rto: u32, + pub __tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub __tcpi_unacked: u32, + pub __tcpi_sacked: u32, + pub __tcpi_lost: u32, + pub __tcpi_retrans: u32, + pub __tcpi_fackets: u32, + pub __tcpi_last_data_sent: u32, + pub __tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub __tcpi_last_ack_recv: u32, + pub __tcpi_pmtu: u32, + pub __tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub __tcpi_advmss: u32, + pub __tcpi_reordering: u32, + pub __tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_snd_wnd: u32, + pub tcpi_snd_bwnd: u32, + pub tcpi_snd_nxt: u32, + pub tcpi_rcv_nxt: u32, + pub tcpi_toe_tid: u32, + pub tcpi_snd_rexmitpack: u32, + pub tcpi_rcv_ooopack: u32, + pub tcpi_snd_zerowin: u32, + pub __tcpi_pad: [u32; 26], + } + + pub struct in_pktinfo { + pub ipi_addr: crate::in_addr, + pub ipi_ifindex: c_uint, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [i8; 8], + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_reclen: u16, + pub d_namlen: u16, + pub d_type: u8, + pub d_name: [c_char; 512], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_pad2: Padding, + __ss_pad3: Padding<[u8; 112]>, + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: crate::sigval, + __unused1: Padding<*mut c_void>, //actually a function pointer + pub sigev_notify_attributes: *mut c_void, + } +} + +s_no_extra_traits! { + pub union __c_anonymous_posix_spawn_fae { + pub open: __c_anonymous_posix_spawn_fae_open, + pub dup2: __c_anonymous_posix_spawn_fae_dup2, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl Eq for __c_anonymous_posix_spawn_fae {} + impl PartialEq for __c_anonymous_posix_spawn_fae { + fn eq(&self, other: &__c_anonymous_posix_spawn_fae) -> bool { + unsafe { self.open == other.open || self.dup2 == other.dup2 } + } + } + impl hash::Hash for __c_anonymous_posix_spawn_fae { + fn hash(&self, state: &mut H) { + unsafe { + self.open.hash(state); + self.dup2.hash(state); + } + } + } + } +} + +pub const AT_FDCWD: c_int = -100; +pub const AT_EACCESS: c_int = 0x100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: c_int = 0x400; +pub const AT_REMOVEDIR: c_int = 0x800; + +pub const AT_NULL: c_int = 0; +pub const AT_IGNORE: c_int = 1; +pub const AT_EXECFD: c_int = 2; +pub const AT_PHDR: c_int = 3; +pub const AT_PHENT: c_int = 4; +pub const AT_PHNUM: c_int = 5; +pub const AT_PAGESZ: c_int = 6; +pub const AT_BASE: c_int = 7; +pub const AT_FLAGS: c_int = 8; +pub const AT_ENTRY: c_int = 9; +pub const AT_DCACHEBSIZE: c_int = 10; +pub const AT_ICACHEBSIZE: c_int = 11; +pub const AT_UCACHEBSIZE: c_int = 12; +pub const AT_STACKBASE: c_int = 13; +pub const AT_EUID: c_int = 2000; +pub const AT_RUID: c_int = 2001; +pub const AT_EGID: c_int = 2002; +pub const AT_RGID: c_int = 2003; +pub const AT_SUN_LDELF: c_int = 2004; +pub const AT_SUN_LDSHDR: c_int = 2005; +pub const AT_SUN_LDNAME: c_int = 2006; +pub const AT_SUN_PLATFORM: c_int = 2008; +pub const AT_SUN_HWCAP: c_int = 2009; +pub const AT_SUN_IFLUSH: c_int = 2010; +pub const AT_SUN_CPU: c_int = 2011; +pub const AT_SUN_EMUL_ENTRY: c_int = 2012; +pub const AT_SUN_EMUL_EXECFD: c_int = 2013; +pub const AT_SUN_EXECNAME: c_int = 2014; + +pub const EXTATTR_NAMESPACE_USER: c_int = 1; +pub const EXTATTR_NAMESPACE_SYSTEM: c_int = 2; + +pub const LC_COLLATE_MASK: c_int = 1 << crate::LC_COLLATE; +pub const LC_CTYPE_MASK: c_int = 1 << crate::LC_CTYPE; +pub const LC_MONETARY_MASK: c_int = 1 << crate::LC_MONETARY; +pub const LC_NUMERIC_MASK: c_int = 1 << crate::LC_NUMERIC; +pub const LC_TIME_MASK: c_int = 1 << crate::LC_TIME; +pub const LC_MESSAGES_MASK: c_int = 1 << crate::LC_MESSAGES; +pub const LC_ALL_MASK: c_int = !0; + +pub const ERA: crate::nl_item = 52; +pub const ERA_D_FMT: crate::nl_item = 53; +pub const ERA_D_T_FMT: crate::nl_item = 54; +pub const ERA_T_FMT: crate::nl_item = 55; +pub const ALT_DIGITS: crate::nl_item = 56; + +pub const O_CLOEXEC: c_int = 0x400000; +pub const O_ALT_IO: c_int = 0x40000; +pub const O_NOSIGPIPE: c_int = 0x1000000; +pub const O_SEARCH: c_int = 0x800000; +pub const O_DIRECTORY: c_int = 0x200000; +pub const O_DIRECT: c_int = 0x00080000; +pub const O_RSYNC: c_int = 0x00020000; + +pub const MS_SYNC: c_int = 0x4; +pub const MS_INVALIDATE: c_int = 0x2; + +// Here because they are not present on OpenBSD +// (https://github.com/openbsd/src/blob/HEAD/sys/sys/resource.h) +pub const RLIMIT_SBSIZE: c_int = 9; +pub const RLIMIT_AS: c_int = 10; +pub const RLIMIT_NTHR: c_int = 11; + +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 12; + +pub const EIDRM: c_int = 82; +pub const ENOMSG: c_int = 83; +pub const EOVERFLOW: c_int = 84; +pub const EILSEQ: c_int = 85; +pub const ENOTSUP: c_int = 86; +pub const ECANCELED: c_int = 87; +pub const EBADMSG: c_int = 88; +pub const ENODATA: c_int = 89; +pub const ENOSR: c_int = 90; +pub const ENOSTR: c_int = 91; +pub const ETIME: c_int = 92; +pub const ENOATTR: c_int = 93; +pub const EMULTIHOP: c_int = 94; +pub const ENOLINK: c_int = 95; +pub const EPROTO: c_int = 96; +pub const EOWNERDEAD: c_int = 97; +pub const ENOTRECOVERABLE: c_int = 98; +#[deprecated( + since = "0.2.143", + note = "This value will always match the highest defined error number \ + and thus is not stable. \ + See #3040 for more info." +)] +pub const ELAST: c_int = 98; + +pub const F_DUPFD_CLOEXEC: c_int = 12; +pub const F_CLOSEM: c_int = 10; +pub const F_GETNOSIGPIPE: c_int = 13; +pub const F_SETNOSIGPIPE: c_int = 14; +pub const F_MAXFD: c_int = 11; +pub const F_GETPATH: c_int = 15; + +pub const FUTEX_WAIT: c_int = 0; +pub const FUTEX_WAKE: c_int = 1; +pub const FUTEX_FD: c_int = 2; +pub const FUTEX_REQUEUE: c_int = 3; +pub const FUTEX_CMP_REQUEUE: c_int = 4; +pub const FUTEX_WAKE_OP: c_int = 5; +pub const FUTEX_LOCK_PI: c_int = 6; +pub const FUTEX_UNLOCK_PI: c_int = 7; +pub const FUTEX_TRYLOCK_PI: c_int = 8; +pub const FUTEX_WAIT_BITSET: c_int = 9; +pub const FUTEX_WAKE_BITSET: c_int = 10; +pub const FUTEX_WAIT_REQUEUE_PI: c_int = 11; +pub const FUTEX_CMP_REQUEUE_PI: c_int = 12; +pub const FUTEX_PRIVATE_FLAG: c_int = 1 << 7; +pub const FUTEX_CLOCK_REALTIME: c_int = 1 << 8; +pub const FUTEX_CMD_MASK: c_int = !(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); +pub const FUTEX_WAITERS: u32 = 1 << 31; +pub const FUTEX_OWNER_DIED: u32 = 1 << 30; +pub const FUTEX_SYNCOBJ_1: u32 = 1 << 29; +pub const FUTEX_SYNCOBJ_0: u32 = 1 << 28; +pub const FUTEX_TID_MASK: u32 = (1 << 28) - 1; +pub const FUTEX_BITSET_MATCH_ANY: u32 = !0; + +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_SENDSRCADDR: c_int = IP_RECVDSTADDR; +pub const IP_RECVIF: c_int = 20; +pub const IP_PKTINFO: c_int = 25; +pub const IP_RECVPKTINFO: c_int = 26; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; + +pub const TCP_KEEPIDLE: c_int = 3; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; +pub const TCP_KEEPINIT: c_int = 7; +pub const TCP_MD5SIG: c_int = 0x10; +pub const TCP_CONGCTL: c_int = 0x20; + +pub const SOCK_CONN_DGRAM: c_int = 6; +pub const SOCK_DCCP: c_int = SOCK_CONN_DGRAM; +pub const SOCK_NOSIGPIPE: c_int = 0x40000000; +pub const SOCK_FLAGS_MASK: c_int = 0xf0000000; + +pub const SO_SNDTIMEO: c_int = 0x100b; +pub const SO_RCVTIMEO: c_int = 0x100c; +pub const SO_NOSIGPIPE: c_int = 0x0800; +pub const SO_ACCEPTFILTER: c_int = 0x1000; +pub const SO_TIMESTAMP: c_int = 0x2000; +pub const SO_OVERFLOWED: c_int = 0x1009; +pub const SO_NOHEADER: c_int = 0x100a; + +// http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/un.h?annotate +pub const LOCAL_OCREDS: c_int = 0x0001; // pass credentials to receiver +pub const LOCAL_CONNWAIT: c_int = 0x0002; // connects block until accepted +pub const LOCAL_PEEREID: c_int = 0x0003; // get peer identification +pub const LOCAL_CREDS: c_int = 0x0004; // pass credentials to receiver + +// https://github.com/NetBSD/src/blob/trunk/sys/net/if.h#L373 + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// pup +pub const IPPROTO_PUP: c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +/// IP Mobility RFC 2004 +pub const IPPROTO_MOBILE: c_int = 55; +/// IPv6 ICMP +pub const IPPROTO_IPV6_ICMP: c_int = 58; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +/// ISO cnlp +pub const IPPROTO_EON: c_int = 80; +/// Ethernet-in-IP +pub const IPPROTO_ETHERIP: c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_IPCOMP: c_int = 108; +/// VRRP RFC 2338 +pub const IPPROTO_VRRP: c_int = 112; +/// Common Address Resolution Protocol +pub const IPPROTO_CARP: c_int = 112; +/// L2TPv3 +pub const IPPROTO_L2TP: c_int = 115; +/// SCTP +pub const IPPROTO_SCTP: c_int = 132; +/// PFSYNC +pub const IPPROTO_PFSYNC: c_int = 240; +pub const IPPROTO_MAX: c_int = 256; + +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: c_int = 257; + +/// sysctl placeholder for (FAST_)IPSEC +pub const CTL_IPPROTO_IPSEC: c_int = 258; + +pub const AF_OROUTE: c_int = 17; +pub const AF_ARP: c_int = 28; +pub const pseudo_AF_KEY: c_int = 29; +pub const pseudo_AF_HDRCMPLT: c_int = 30; +pub const AF_BLUETOOTH: c_int = 31; +pub const AF_IEEE80211: c_int = 32; +pub const AF_MPLS: c_int = 33; +pub const AF_ROUTE: c_int = 34; +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const NET_RT_OOOIFLIST: c_int = 3; +pub const NET_RT_OOIFLIST: c_int = 4; +pub const NET_RT_OIFLIST: c_int = 5; +pub const NET_RT_IFLIST: c_int = 6; + +pub const PF_OROUTE: c_int = AF_OROUTE; +pub const PF_ARP: c_int = AF_ARP; +pub const PF_KEY: c_int = pseudo_AF_KEY; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_ROUTE: c_int = AF_ROUTE; + +pub const MSG_NBIO: c_int = 0x1000; +pub const MSG_WAITFORONE: c_int = 0x2000; +pub const MSG_NOTIFICATION: c_int = 0x4000; + +pub const SCM_TIMESTAMP: c_int = 0x08; +pub const SCM_CREDS: c_int = 0x10; + +pub const O_DSYNC: c_int = 0x10000; + +pub const MAP_RENAME: c_int = 0x20; +pub const MAP_NORESERVE: c_int = 0x40; +pub const MAP_HASSEMAPHORE: c_int = 0x200; +pub const MAP_TRYFIXED: c_int = 0x400; +pub const MAP_WIRED: c_int = 0x800; +pub const MAP_STACK: c_int = 0x2000; +// map alignment aliases for MAP_ALIGNED +pub const MAP_ALIGNMENT_SHIFT: c_int = 24; +pub const MAP_ALIGNMENT_MASK: c_int = 0xff << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_64KB: c_int = 16 << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_16MB: c_int = 24 << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_4GB: c_int = 32 << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_1TB: c_int = 40 << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_256TB: c_int = 48 << MAP_ALIGNMENT_SHIFT; +pub const MAP_ALIGNMENT_64PB: c_int = 56 << MAP_ALIGNMENT_SHIFT; +// mremap flag +pub const MAP_REMAPDUP: c_int = 0x004; + +pub const DCCP_TYPE_REQUEST: c_int = 0; +pub const DCCP_TYPE_RESPONSE: c_int = 1; +pub const DCCP_TYPE_DATA: c_int = 2; +pub const DCCP_TYPE_ACK: c_int = 3; +pub const DCCP_TYPE_DATAACK: c_int = 4; +pub const DCCP_TYPE_CLOSEREQ: c_int = 5; +pub const DCCP_TYPE_CLOSE: c_int = 6; +pub const DCCP_TYPE_RESET: c_int = 7; +pub const DCCP_TYPE_MOVE: c_int = 8; + +pub const DCCP_FEATURE_CC: c_int = 1; +pub const DCCP_FEATURE_ECN: c_int = 2; +pub const DCCP_FEATURE_ACKRATIO: c_int = 3; +pub const DCCP_FEATURE_ACKVECTOR: c_int = 4; +pub const DCCP_FEATURE_MOBILITY: c_int = 5; +pub const DCCP_FEATURE_LOSSWINDOW: c_int = 6; +pub const DCCP_FEATURE_CONN_NONCE: c_int = 8; +pub const DCCP_FEATURE_IDENTREG: c_int = 7; + +pub const DCCP_OPT_PADDING: c_int = 0; +pub const DCCP_OPT_DATA_DISCARD: c_int = 1; +pub const DCCP_OPT_SLOW_RECV: c_int = 2; +pub const DCCP_OPT_BUF_CLOSED: c_int = 3; +pub const DCCP_OPT_CHANGE_L: c_int = 32; +pub const DCCP_OPT_CONFIRM_L: c_int = 33; +pub const DCCP_OPT_CHANGE_R: c_int = 34; +pub const DCCP_OPT_CONFIRM_R: c_int = 35; +pub const DCCP_OPT_INIT_COOKIE: c_int = 36; +pub const DCCP_OPT_NDP_COUNT: c_int = 37; +pub const DCCP_OPT_ACK_VECTOR0: c_int = 38; +pub const DCCP_OPT_ACK_VECTOR1: c_int = 39; +pub const DCCP_OPT_RECV_BUF_DROPS: c_int = 40; +pub const DCCP_OPT_TIMESTAMP: c_int = 41; +pub const DCCP_OPT_TIMESTAMP_ECHO: c_int = 42; +pub const DCCP_OPT_ELAPSEDTIME: c_int = 43; +pub const DCCP_OPT_DATACHECKSUM: c_int = 44; + +pub const DCCP_REASON_UNSPEC: c_int = 0; +pub const DCCP_REASON_CLOSED: c_int = 1; +pub const DCCP_REASON_INVALID: c_int = 2; +pub const DCCP_REASON_OPTION_ERR: c_int = 3; +pub const DCCP_REASON_FEA_ERR: c_int = 4; +pub const DCCP_REASON_CONN_REF: c_int = 5; +pub const DCCP_REASON_BAD_SNAME: c_int = 6; +pub const DCCP_REASON_BAD_COOKIE: c_int = 7; +pub const DCCP_REASON_INV_MOVE: c_int = 8; +pub const DCCP_REASON_UNANSW_CH: c_int = 10; +pub const DCCP_REASON_FRUITLESS_NEG: c_int = 11; + +pub const DCCP_CCID: c_int = 1; +pub const DCCP_CSLEN: c_int = 2; +pub const DCCP_MAXSEG: c_int = 4; +pub const DCCP_SERVICE: c_int = 8; + +pub const DCCP_NDP_LIMIT: c_int = 16; +pub const DCCP_SEQ_NUM_LIMIT: c_int = 16777216; +pub const DCCP_MAX_OPTIONS: c_int = 32; +pub const DCCP_MAX_PKTS: c_int = 100; + +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_CHOWN_RESTRICTED: c_int = 7; +pub const _PC_NO_TRUNC: c_int = 8; +pub const _PC_VDISABLE: c_int = 9; +pub const _PC_SYNC_IO: c_int = 10; +pub const _PC_FILESIZEBITS: c_int = 11; +pub const _PC_SYMLINK_MAX: c_int = 12; +pub const _PC_2_SYMLINKS: c_int = 13; +pub const _PC_ACL_EXTENDED: c_int = 14; +pub const _PC_MIN_HOLE_SIZE: c_int = 15; + +pub const _CS_PATH: c_int = 1; + +pub const _SC_SYNCHRONIZED_IO: c_int = 31; +pub const _SC_IOV_MAX: c_int = 32; +pub const _SC_MAPPED_FILES: c_int = 33; +pub const _SC_MEMLOCK: c_int = 34; +pub const _SC_MEMLOCK_RANGE: c_int = 35; +pub const _SC_MEMORY_PROTECTION: c_int = 36; +pub const _SC_LOGIN_NAME_MAX: c_int = 37; +pub const _SC_MONOTONIC_CLOCK: c_int = 38; +pub const _SC_CLK_TCK: c_int = 39; +pub const _SC_ATEXIT_MAX: c_int = 40; +pub const _SC_THREADS: c_int = 41; +pub const _SC_SEMAPHORES: c_int = 42; +pub const _SC_BARRIERS: c_int = 43; +pub const _SC_TIMERS: c_int = 44; +pub const _SC_SPIN_LOCKS: c_int = 45; +pub const _SC_READER_WRITER_LOCKS: c_int = 46; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 47; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 48; +pub const _SC_CLOCK_SELECTION: c_int = 49; +pub const _SC_ASYNCHRONOUS_IO: c_int = 50; +pub const _SC_AIO_LISTIO_MAX: c_int = 51; +pub const _SC_AIO_MAX: c_int = 52; +pub const _SC_MESSAGE_PASSING: c_int = 53; +pub const _SC_MQ_OPEN_MAX: c_int = 54; +pub const _SC_MQ_PRIO_MAX: c_int = 55; +pub const _SC_PRIORITY_SCHEDULING: c_int = 56; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 57; +pub const _SC_THREAD_KEYS_MAX: c_int = 58; +pub const _SC_THREAD_STACK_MIN: c_int = 59; +pub const _SC_THREAD_THREADS_MAX: c_int = 60; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 61; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 62; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 63; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 64; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 65; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 66; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 67; +pub const _SC_TTY_NAME_MAX: c_int = 68; +pub const _SC_HOST_NAME_MAX: c_int = 69; +pub const _SC_PASS_MAX: c_int = 70; +pub const _SC_REGEXP: c_int = 71; +pub const _SC_SHELL: c_int = 72; +pub const _SC_SYMLOOP_MAX: c_int = 73; +pub const _SC_V6_ILP32_OFF32: c_int = 74; +pub const _SC_V6_ILP32_OFFBIG: c_int = 75; +pub const _SC_V6_LP64_OFF64: c_int = 76; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 77; +pub const _SC_2_PBS: c_int = 80; +pub const _SC_2_PBS_ACCOUNTING: c_int = 81; +pub const _SC_2_PBS_CHECKPOINT: c_int = 82; +pub const _SC_2_PBS_LOCATE: c_int = 83; +pub const _SC_2_PBS_MESSAGE: c_int = 84; +pub const _SC_2_PBS_TRACK: c_int = 85; +pub const _SC_SPAWN: c_int = 86; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 87; +pub const _SC_TIMER_MAX: c_int = 88; +pub const _SC_SEM_NSEMS_MAX: c_int = 89; +pub const _SC_CPUTIME: c_int = 90; +pub const _SC_THREAD_CPUTIME: c_int = 91; +pub const _SC_DELAYTIMER_MAX: c_int = 92; +// These two variables will be supported in NetBSD 8.0 +// pub const _SC_SIGQUEUE_MAX : c_int = 93; +// pub const _SC_REALTIME_SIGNALS : c_int = 94; +pub const _SC_PHYS_PAGES: c_int = 121; +pub const _SC_NPROCESSORS_CONF: c_int = 1001; +pub const _SC_NPROCESSORS_ONLN: c_int = 1002; +pub const _SC_SCHED_RT_TS: c_int = 2001; +pub const _SC_SCHED_PRI_MIN: c_int = 2002; +pub const _SC_SCHED_PRI_MAX: c_int = 2003; + +pub const FD_SETSIZE: usize = 0x100; + +pub const ST_NOSUID: c_ulong = 8; + +// +pub const MNT_UNION: c_int = 0x00000020; +pub const MNT_NOCOREDUMP: c_int = 0x00008000; +pub const MNT_RELATIME: c_int = 0x00020000; +pub const MNT_IGNORE: c_int = 0x00100000; +pub const MNT_NFS4ACLS: c_int = 0x00200000; +pub const MNT_DISCARD: c_int = 0x00800000; +pub const MNT_EXTATTR: c_int = 0x01000000; +pub const MNT_LOG: c_int = 0x02000000; +pub const MNT_NOATIME: c_int = 0x04000000; +pub const MNT_AUTOMOUNTED: c_int = 0x10000000; +pub const MNT_SYMPERM: c_int = 0x20000000; +pub const MNT_NODEVMTIME: c_int = 0x40000000; +pub const MNT_SOFTDEP: c_int = 0x80000000; +pub const MNT_POSIX1EACLS: c_int = 0x00000800; +pub const MNT_ACLS: c_int = MNT_POSIX1EACLS; +pub const MNT_WAIT: c_int = 1; +pub const MNT_NOWAIT: c_int = 2; +pub const MNT_LAZY: c_int = 3; + +// sys/ioccom.h +pub const IOCPARM_SHIFT: u32 = 16; +pub const IOCGROUP_SHIFT: u32 = 8; + +pub const fn IOCPARM_LEN(x: u32) -> u32 { + (x >> IOCPARM_SHIFT) & crate::IOCPARM_MASK +} + +pub const fn IOCBASECMD(x: u32) -> u32 { + x & (!(crate::IOCPARM_MASK << IOCPARM_SHIFT)) +} + +pub const fn IOCGROUP(x: u32) -> u32 { + (x >> IOCGROUP_SHIFT) & 0xff +} + +pub const fn _IOC(inout: c_ulong, group: c_ulong, num: c_ulong, len: c_ulong) -> c_ulong { + (inout) + | (((len) & crate::IOCPARM_MASK as c_ulong) << IOCPARM_SHIFT) + | ((group) << IOCGROUP_SHIFT) + | (num) +} + +pub const NTP_API: c_int = 4; + +pub const LITTLE_ENDIAN: c_int = 1234; +pub const BIG_ENDIAN: c_int = 4321; + +#[deprecated(since = "0.2.178", note = "obsolete upstream")] +pub const PL_EVENT_NONE: c_int = 0; +#[deprecated(since = "0.2.178", note = "obsolete upstream")] +pub const PL_EVENT_SIGNAL: c_int = 1; +#[deprecated(since = "0.2.178", note = "obsolete upstream")] +pub const PL_EVENT_SUSPENDED: c_int = 2; + +cfg_if! { + if #[cfg(any( + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "x86", + target_arch = "x86_64" + ))] { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + ptm_magic: 0x33330003, + ptm_errorcheck: 0, + ptm_pad1: Padding::new([0; 3]), + ptm_unused: Padding::new(0), + ptm_pad2: Padding::new([0; 3]), + ptm_waiters: 0 as *mut _, + ptm_owner: 0, + ptm_recursed: 0, + ptm_spare2: 0 as *mut _, + }; + } else { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + ptm_magic: 0x33330003, + ptm_errorcheck: 0, + ptm_unused: Padding::new(0), + ptm_waiters: 0 as *mut _, + ptm_owner: 0, + ptm_recursed: 0, + ptm_spare2: 0 as *mut _, + }; + } +} + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + ptc_magic: 0x55550005, + ptc_lock: 0, + ptc_waiters_first: 0 as *mut _, + ptc_waiters_last: 0 as *mut _, + ptc_mutex: 0 as *mut _, + ptc_private: 0 as *mut _, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + ptr_magic: 0x99990009, + ptr_interlock: 0, + ptr_rblocked_first: 0 as *mut _, + ptr_rblocked_last: 0 as *mut _, + ptr_wblocked_first: 0 as *mut _, + ptr_wblocked_last: 0 as *mut _, + ptr_nreaders: 0, + ptr_owner: 0, + ptr_private: 0 as *mut _, +}; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; + +pub const SCHED_NONE: c_int = -1; +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; + +pub const EVFILT_AIO: u32 = 2; +pub const EVFILT_PROC: u32 = 4; +pub const EVFILT_READ: u32 = 0; +pub const EVFILT_SIGNAL: u32 = 5; +pub const EVFILT_TIMER: u32 = 6; +pub const EVFILT_VNODE: u32 = 3; +pub const EVFILT_WRITE: u32 = 1; +pub const EVFILT_FS: u32 = 7; +pub const EVFILT_USER: u32 = 8; +pub const EVFILT_EMPTY: u32 = 9; + +pub const EV_ADD: u32 = 0x1; +pub const EV_DELETE: u32 = 0x2; +pub const EV_ENABLE: u32 = 0x4; +pub const EV_DISABLE: u32 = 0x8; +pub const EV_ONESHOT: u32 = 0x10; +pub const EV_CLEAR: u32 = 0x20; +pub const EV_RECEIPT: u32 = 0x40; +pub const EV_DISPATCH: u32 = 0x80; +pub const EV_FLAG1: u32 = 0x2000; +pub const EV_ERROR: u32 = 0x4000; +pub const EV_EOF: u32 = 0x8000; +pub const EV_SYSFLAGS: u32 = 0xf000; + +pub const NOTE_TRIGGER: u32 = 0x01000000; +pub const NOTE_FFNOP: u32 = 0x00000000; +pub const NOTE_FFAND: u32 = 0x40000000; +pub const NOTE_FFOR: u32 = 0x80000000; +pub const NOTE_FFCOPY: u32 = 0xc0000000; +pub const NOTE_FFCTRLMASK: u32 = 0xc0000000; +pub const NOTE_FFLAGSMASK: u32 = 0x00ffffff; +pub const NOTE_LOWAT: u32 = 0x00000001; +pub const NOTE_DELETE: u32 = 0x00000001; +pub const NOTE_WRITE: u32 = 0x00000002; +pub const NOTE_EXTEND: u32 = 0x00000004; +pub const NOTE_ATTRIB: u32 = 0x00000008; +pub const NOTE_LINK: u32 = 0x00000010; +pub const NOTE_RENAME: u32 = 0x00000020; +pub const NOTE_REVOKE: u32 = 0x00000040; +pub const NOTE_EXIT: u32 = 0x80000000; +pub const NOTE_FORK: u32 = 0x40000000; +pub const NOTE_EXEC: u32 = 0x20000000; +pub const NOTE_PDATAMASK: u32 = 0x000fffff; +pub const NOTE_PCTRLMASK: u32 = 0xf0000000; +pub const NOTE_TRACK: u32 = 0x00000001; +pub const NOTE_TRACKERR: u32 = 0x00000002; +pub const NOTE_CHILD: u32 = 0x00000004; +pub const NOTE_MSECONDS: u32 = 0x00000000; +pub const NOTE_SECONDS: u32 = 0x00000001; +pub const NOTE_USECONDS: u32 = 0x00000002; +pub const NOTE_NSECONDS: u32 = 0x00000003; +pub const NOTE_ABSTIME: u32 = 0x000000010; + +pub const TMP_MAX: c_uint = 308915776; + +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; +pub const AI_NUMERICSERV: c_int = 0x00000008; +pub const AI_ADDRCONFIG: c_int = 0x00000400; +pub const AI_SRV: c_int = 0x00000800; + +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const NI_MAXSERV: crate::socklen_t = 32; + +pub const NI_NOFQDN: c_int = 0x00000001; +pub const NI_NUMERICHOST: c_int = 0x000000002; +pub const NI_NAMEREQD: c_int = 0x000000004; +pub const NI_NUMERICSERV: c_int = 0x000000008; +pub const NI_DGRAM: c_int = 0x00000010; +pub const NI_WITHSCOPEID: c_int = 0x00000020; +pub const NI_NUMERICSCOPE: c_int = 0x00000040; + +pub const RTLD_NOLOAD: c_int = 0x2000; +pub const RTLD_LOCAL: c_int = 0x200; + +pub const CTL_MAXNAME: c_int = 12; +pub const SYSCTL_NAMELEN: c_int = 32; +pub const SYSCTL_DEFSIZE: c_int = 8; +pub const CTLTYPE_NODE: c_int = 1; +pub const CTLTYPE_INT: c_int = 2; +pub const CTLTYPE_STRING: c_int = 3; +pub const CTLTYPE_QUAD: c_int = 4; +pub const CTLTYPE_STRUCT: c_int = 5; +pub const CTLTYPE_BOOL: c_int = 6; +pub const CTLFLAG_READONLY: c_int = 0x00000000; +pub const CTLFLAG_READWRITE: c_int = 0x00000070; +pub const CTLFLAG_ANYWRITE: c_int = 0x00000080; +pub const CTLFLAG_PRIVATE: c_int = 0x00000100; +pub const CTLFLAG_PERMANENT: c_int = 0x00000200; +pub const CTLFLAG_OWNDATA: c_int = 0x00000400; +pub const CTLFLAG_IMMEDIATE: c_int = 0x00000800; +pub const CTLFLAG_HEX: c_int = 0x00001000; +pub const CTLFLAG_ROOT: c_int = 0x00002000; +pub const CTLFLAG_ANYNUMBER: c_int = 0x00004000; +pub const CTLFLAG_HIDDEN: c_int = 0x00008000; +pub const CTLFLAG_ALIAS: c_int = 0x00010000; +pub const CTLFLAG_MMAP: c_int = 0x00020000; +pub const CTLFLAG_OWNDESC: c_int = 0x00040000; +pub const CTLFLAG_UNSIGNED: c_int = 0x00080000; +pub const SYSCTL_VERS_MASK: c_int = 0xff000000; +pub const SYSCTL_VERS_0: c_int = 0x00000000; +pub const SYSCTL_VERS_1: c_int = 0x01000000; +pub const SYSCTL_VERSION: c_int = SYSCTL_VERS_1; +pub const CTL_EOL: c_int = -1; +pub const CTL_QUERY: c_int = -2; +pub const CTL_CREATE: c_int = -3; +pub const CTL_CREATESYM: c_int = -4; +pub const CTL_DESTROY: c_int = -5; +pub const CTL_MMAP: c_int = -6; +pub const CTL_DESCRIBE: c_int = -7; +pub const CTL_UNSPEC: c_int = 0; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_VFS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_USER: c_int = 8; +pub const CTL_DDB: c_int = 9; +pub const CTL_PROC: c_int = 10; +pub const CTL_VENDOR: c_int = 11; +pub const CTL_EMUL: c_int = 12; +pub const CTL_SECURITY: c_int = 13; +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_VNODE: c_int = 13; +pub const KERN_PROC: c_int = 14; +pub const KERN_FILE: c_int = 15; +pub const KERN_PROF: c_int = 16; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_OBOOTTIME: c_int = 21; +pub const KERN_DOMAINNAME: c_int = 22; +pub const KERN_MAXPARTITIONS: c_int = 23; +pub const KERN_RAWPARTITION: c_int = 24; +pub const KERN_NTPTIME: c_int = 25; +pub const KERN_TIMEX: c_int = 26; +pub const KERN_AUTONICETIME: c_int = 27; +pub const KERN_AUTONICEVAL: c_int = 28; +pub const KERN_RTC_OFFSET: c_int = 29; +pub const KERN_ROOT_DEVICE: c_int = 30; +pub const KERN_MSGBUFSIZE: c_int = 31; +pub const KERN_FSYNC: c_int = 32; +pub const KERN_OLDSYSVMSG: c_int = 33; +pub const KERN_OLDSYSVSEM: c_int = 34; +pub const KERN_OLDSYSVSHM: c_int = 35; +pub const KERN_OLDSHORTCORENAME: c_int = 36; +pub const KERN_SYNCHRONIZED_IO: c_int = 37; +pub const KERN_IOV_MAX: c_int = 38; +pub const KERN_MBUF: c_int = 39; +pub const KERN_MAPPED_FILES: c_int = 40; +pub const KERN_MEMLOCK: c_int = 41; +pub const KERN_MEMLOCK_RANGE: c_int = 42; +pub const KERN_MEMORY_PROTECTION: c_int = 43; +pub const KERN_LOGIN_NAME_MAX: c_int = 44; +pub const KERN_DEFCORENAME: c_int = 45; +pub const KERN_LOGSIGEXIT: c_int = 46; +pub const KERN_PROC2: c_int = 47; +pub const KERN_PROC_ARGS: c_int = 48; +pub const KERN_FSCALE: c_int = 49; +pub const KERN_CCPU: c_int = 50; +pub const KERN_CP_TIME: c_int = 51; +pub const KERN_OLDSYSVIPC_INFO: c_int = 52; +pub const KERN_MSGBUF: c_int = 53; +pub const KERN_CONSDEV: c_int = 54; +pub const KERN_MAXPTYS: c_int = 55; +pub const KERN_PIPE: c_int = 56; +pub const KERN_MAXPHYS: c_int = 57; +pub const KERN_SBMAX: c_int = 58; +pub const KERN_TKSTAT: c_int = 59; +pub const KERN_MONOTONIC_CLOCK: c_int = 60; +pub const KERN_URND: c_int = 61; +pub const KERN_LABELSECTOR: c_int = 62; +pub const KERN_LABELOFFSET: c_int = 63; +pub const KERN_LWP: c_int = 64; +pub const KERN_FORKFSLEEP: c_int = 65; +pub const KERN_POSIX_THREADS: c_int = 66; +pub const KERN_POSIX_SEMAPHORES: c_int = 67; +pub const KERN_POSIX_BARRIERS: c_int = 68; +pub const KERN_POSIX_TIMERS: c_int = 69; +pub const KERN_POSIX_SPIN_LOCKS: c_int = 70; +pub const KERN_POSIX_READER_WRITER_LOCKS: c_int = 71; +pub const KERN_DUMP_ON_PANIC: c_int = 72; +pub const KERN_SOMAXKVA: c_int = 73; +pub const KERN_ROOT_PARTITION: c_int = 74; +pub const KERN_DRIVERS: c_int = 75; +pub const KERN_BUF: c_int = 76; +pub const KERN_FILE2: c_int = 77; +pub const KERN_VERIEXEC: c_int = 78; +pub const KERN_CP_ID: c_int = 79; +pub const KERN_HARDCLOCK_TICKS: c_int = 80; +pub const KERN_ARND: c_int = 81; +pub const KERN_SYSVIPC: c_int = 82; +pub const KERN_BOOTTIME: c_int = 83; +pub const KERN_EVCNT: c_int = 84; +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_GID: c_int = 7; +pub const KERN_PROC_RGID: c_int = 8; +pub const KERN_PROC_ARGV: c_int = 1; +pub const KERN_PROC_NARGV: c_int = 2; +pub const KERN_PROC_ENV: c_int = 3; +pub const KERN_PROC_NENV: c_int = 4; +pub const KERN_PROC_PATHNAME: c_int = 5; +pub const VM_PROC: c_int = 16; +pub const VM_PROC_MAP: c_int = 1; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const AIO_CANCELED: c_int = 1; +pub const AIO_NOTCANCELED: c_int = 2; +pub const AIO_ALLDONE: c_int = 3; +pub const LIO_NOP: c_int = 0; +pub const LIO_WRITE: c_int = 1; +pub const LIO_READ: c_int = 2; +pub const LIO_WAIT: c_int = 1; +pub const LIO_NOWAIT: c_int = 0; + +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const WSTOPPED: c_int = 0x00000002; // same as WUNTRACED +pub const WCONTINUED: c_int = 0x00000010; +pub const WEXITED: c_int = 0x000000020; +pub const WNOWAIT: c_int = 0x00010000; + +pub const WALTSIG: c_int = 0x00000004; +pub const WALLSIG: c_int = 0x00000008; +pub const WTRAPPED: c_int = 0x00000040; +pub const WNOZOMBIE: c_int = 0x00020000; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 4; + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const B460800: crate::speed_t = 460800; +pub const B921600: crate::speed_t = 921600; + +pub const ONOCR: crate::tcflag_t = 0x20; +pub const ONLRET: crate::tcflag_t = 0x40; +pub const CDTRCTS: crate::tcflag_t = 0x00020000; +pub const CHWFLOW: crate::tcflag_t = crate::MDMBUF | crate::CRTSCTS | crate::CDTRCTS; + +pub const SOCK_CLOEXEC: c_int = 0x10000000; +pub const SOCK_NONBLOCK: c_int = 0x20000000; + +// Uncomment on next NetBSD release +// pub const FIOSEEKDATA: c_ulong = 0xc0086661; +// pub const FIOSEEKHOLE: c_ulong = 0xc0086662; +pub const OFIOGETBMAP: c_ulong = 0xc004667a; +pub const FIOGETBMAP: c_ulong = 0xc008667a; +pub const FIONWRITE: c_ulong = 0x40046679; +pub const FIONSPACE: c_ulong = 0x40046678; +pub const FIBMAP: c_ulong = 0xc008667a; + +pub const SIGSTKSZ: size_t = 40960; + +pub const REG_ILLSEQ: c_int = 17; + +pub const PT_DUMPCORE: c_int = 12; +#[deprecated(note = "obsolete operation")] +pub const PT_LWPINFO: c_int = 13; +pub const PT_SYSCALL: c_int = 14; +pub const PT_SYSCALLEMU: c_int = 15; +pub const PT_SET_EVENT_MASK: c_int = 16; +pub const PT_GET_EVENT_MASK: c_int = 17; +pub const PT_GET_PROCESS_STATE: c_int = 18; +pub const PT_SET_SIGINFO: c_int = 19; +pub const PT_GET_SIGINFO: c_int = 20; +pub const PT_RESUME: c_int = 21; +pub const PT_SUSPEND: c_int = 22; +pub const PT_STOP: c_int = 23; +pub const PT_LWPSTATUS: c_int = 24; +pub const PT_LWPNEXT: c_int = 25; +pub const PT_SET_SIGPASS: c_int = 26; +pub const PT_GET_SIGPASS: c_int = 27; +pub const PT_FIRSTMACH: c_int = 32; +pub const POSIX_SPAWN_RETURNERROR: c_int = 0x40; + +// Flags for chflags(2) +pub const SF_APPEND: c_ulong = 0x00040000; +pub const SF_ARCHIVED: c_ulong = 0x00010000; +pub const SF_IMMUTABLE: c_ulong = 0x00020000; +pub const SF_LOG: c_ulong = 0x00400000; +pub const SF_SETTABLE: c_ulong = 0xffff0000; +pub const SF_SNAPINVAL: c_ulong = 0x00800000; +pub const SF_SNAPSHOT: c_ulong = 0x00200000; +pub const UF_APPEND: c_ulong = 0x00000004; +pub const UF_IMMUTABLE: c_ulong = 0x00000002; +pub const UF_NODUMP: c_ulong = 0x00000001; +pub const UF_OPAQUE: c_ulong = 0x00000008; +pub const UF_SETTABLE: c_ulong = 0x0000ffff; + +// sys/sysctl.h +pub const KVME_PROT_READ: c_int = 0x00000001; +pub const KVME_PROT_WRITE: c_int = 0x00000002; +pub const KVME_PROT_EXEC: c_int = 0x00000004; + +pub const KVME_FLAG_COW: c_int = 0x00000001; +pub const KVME_FLAG_NEEDS_COPY: c_int = 0x00000002; +pub const KVME_FLAG_NOCOREDUMP: c_int = 0x000000004; +pub const KVME_FLAG_PAGEABLE: c_int = 0x000000008; +pub const KVME_FLAG_GROWS_UP: c_int = 0x000000010; +pub const KVME_FLAG_GROWS_DOWN: c_int = 0x000000020; + +pub const NGROUPS_MAX: c_int = 16; + +pub const KI_NGROUPS: c_int = 16; +pub const KI_MAXCOMLEN: c_int = 24; +pub const KI_WMESGLEN: c_int = 8; +pub const KI_MAXLOGNAME: c_int = 24; +pub const KI_MAXEMULLEN: c_int = 16; +pub const KI_LNAMELEN: c_int = 20; + +pub const KERN_FILE_BYFILE: c_int = 1; +pub const KERN_FILE_BYPID: c_int = 2; +pub const KERN_FILESLOP: c_int = 10; + +// sys/lwp.h +pub const LSIDL: c_int = 1; +pub const LSRUN: c_int = 2; +pub const LSSLEEP: c_int = 3; +pub const LSSTOP: c_int = 4; +pub const LSZOMB: c_int = 5; +pub const LSONPROC: c_int = 7; +pub const LSSUSPENDED: c_int = 8; + +// sys/xattr.h +pub const XATTR_CREATE: c_int = 0x01; +pub const XATTR_REPLACE: c_int = 0x02; +// sys/extattr.h +pub const EXTATTR_NAMESPACE_EMPTY: c_int = 0; + +// For getrandom() +pub const GRND_NONBLOCK: c_uint = 0x1; +pub const GRND_RANDOM: c_uint = 0x2; +pub const GRND_INSECURE: c_uint = 0x4; + +// sys/reboot.h +pub const RB_ASKNAME: c_int = 0x000000001; +pub const RB_SINGLE: c_int = 0x000000002; +pub const RB_NOSYNC: c_int = 0x000000004; +pub const RB_HALT: c_int = 0x000000008; +pub const RB_INITNAME: c_int = 0x000000010; +pub const RB_KDB: c_int = 0x000000040; +pub const RB_RDONLY: c_int = 0x000000080; +pub const RB_DUMP: c_int = 0x000000100; +pub const RB_MINIROOT: c_int = 0x000000200; +pub const RB_STRING: c_int = 0x000000400; +pub const RB_POWERDOWN: c_int = RB_HALT | 0x000000800; +pub const RB_USERCONF: c_int = 0x000001000; + +pub const fn MAP_ALIGNED(alignment: c_int) -> c_int { + alignment << MAP_ALIGNMENT_SHIFT +} + +// net/route.h +pub const RTF_MASK: c_int = 0x80; +pub const RTF_CONNECTED: c_int = 0x100; +pub const RTF_ANNOUNCE: c_int = 0x20000; +pub const RTF_SRC: c_int = 0x10000; +pub const RTF_LOCAL: c_int = 0x40000; +pub const RTF_BROADCAST: c_int = 0x80000; +pub const RTF_UPDATING: c_int = 0x100000; +pub const RTF_DONTCHANGEIFA: c_int = 0x200000; + +pub const RTM_VERSION: c_int = 4; +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_IFANNOUNCE: c_int = 0x10; +pub const RTM_IEEE80211: c_int = 0x11; +pub const RTM_SETGATE: c_int = 0x12; +pub const RTM_LLINFO_UPD: c_int = 0x13; +pub const RTM_IFINFO: c_int = 0x14; +pub const RTM_OCHGADDR: c_int = 0x15; +pub const RTM_NEWADDR: c_int = 0x16; +pub const RTM_DELADDR: c_int = 0x17; +pub const RTM_CHGADDR: c_int = 0x18; + +pub const RTA_TAG: c_int = 0x100; + +pub const RTAX_TAG: c_int = 8; +pub const RTAX_MAX: c_int = 9; + +// For eventfd +pub const EFD_SEMAPHORE: c_int = crate::O_RDWR; +pub const EFD_NONBLOCK: c_int = crate::O_NONBLOCK; +pub const EFD_CLOEXEC: c_int = crate::O_CLOEXEC; + +// sys/timerfd.h +pub const TFD_CLOEXEC: i32 = crate::O_CLOEXEC; +pub const TFD_NONBLOCK: i32 = crate::O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: i32 = crate::O_WRONLY; +pub const TFD_TIMER_CANCEL_ON_SET: i32 = crate::O_RDWR; + +const fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).add(_ALIGN(size_of::())) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + _ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + _ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next > max { + core::ptr::null_mut::() + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (_ALIGN(size_of::()) + _ALIGN(length as usize)) as c_uint + } + + // dirfd() is a macro on netbsd to access + // the first field of the struct where dirp points to: + // http://cvsweb.netbsd.org/bsdweb.cgi/src/include/dirent.h?rev=1.36 + pub fn dirfd(dirp: *mut crate::DIR) -> c_int { + *(dirp as *const c_int) + } + + pub fn SOCKCREDSIZE(ngrps: usize) -> usize { + let ngrps = if ngrps > 0 { ngrps - 1 } else { 0 }; + size_of::() + size_of::() * ngrps + } + + pub fn PROT_MPROTECT(x: c_int) -> c_int { + x << 3 + } + + pub fn PROT_MPROTECT_EXTRACT(x: c_int) -> c_int { + (x >> 3) & 0x7 + } +} + +safe_f! { + pub const fn WSTOPSIG(status: c_int) -> c_int { + status >> 8 + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0o177) == 0o177 + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major << 8) & 0x000ff00; + dev |= (minor << 12) & 0xfff00000; + dev |= minor & 0xff; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_int { + (((dev as u32) & 0x000fff00) >> 8) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + let mut res = 0; + res |= ((dev as u32) & 0xfff00000) >> 12; + res |= (dev as u32) & 0x000000ff; + res as c_int + } +} + +extern "C" { + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + + pub fn reallocarr(ptr: *mut c_void, number: size_t, size: size_t) -> c_int; + + pub fn chflags(path: *const c_char, flags: c_ulong) -> c_int; + pub fn fchflags(fd: c_int, flags: c_ulong) -> c_int; + pub fn lchflags(path: *const c_char, flags: c_ulong) -> c_int; + + pub fn extattr_list_fd( + fd: c_int, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_list_file( + path: *const c_char, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_list_link( + path: *const c_char, + attrnamespace: c_int, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_delete_fd(fd: c_int, attrnamespace: c_int, attrname: *const c_char) -> c_int; + pub fn extattr_delete_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + ) -> c_int; + pub fn extattr_delete_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + ) -> c_int; + pub fn extattr_get_fd( + fd: c_int, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_get_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_get_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *mut c_void, + nbytes: size_t, + ) -> ssize_t; + pub fn extattr_namespace_to_string(attrnamespace: c_int, string: *mut *mut c_char) -> c_int; + pub fn extattr_set_fd( + fd: c_int, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> c_int; + pub fn extattr_set_file( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> c_int; + pub fn extattr_set_link( + path: *const c_char, + attrnamespace: c_int, + attrname: *const c_char, + data: *const c_void, + nbytes: size_t, + ) -> c_int; + pub fn extattr_string_to_namespace(string: *const c_char, attrnamespace: *mut c_int) -> c_int; + + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut crate::termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut crate::termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + #[link_name = "__lutimes50"] + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + #[link_name = "__gettimeofday50"] + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn sysctl( + name: *const c_int, + namelen: c_uint, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *const c_void, + newlen: size_t, + ) -> c_int; + pub fn sysctlbyname( + name: *const c_char, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *const c_void, + newlen: size_t, + ) -> c_int; + pub fn sysctlnametomib(sname: *const c_char, name: *mut c_int, namelenp: *mut size_t) -> c_int; + #[link_name = "__kevent50"] + pub fn kevent( + kq: c_int, + changelist: *const crate::kevent, + nchanges: size_t, + eventlist: *mut crate::kevent, + nevents: size_t, + timeout: *const crate::timespec, + ) -> c_int; + #[link_name = "__mount50"] + pub fn mount( + src: *const c_char, + target: *const c_char, + flags: c_int, + data: *mut c_void, + size: size_t, + ) -> c_int; + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_notify(mqd: crate::mqd_t, notification: *const crate::sigevent) -> c_int; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + #[link_name = "__mq_timedreceive50"] + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + #[link_name = "__mq_timedsend50"] + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn ptrace(request: c_int, pid: crate::pid_t, addr: *mut c_void, data: c_int) -> c_int; + pub fn utrace(label: *const c_char, addr: *mut c_void, len: size_t) -> c_int; + pub fn pthread_getname_np(t: crate::pthread_t, name: *mut c_char, len: size_t) -> c_int; + pub fn pthread_setname_np( + t: crate::pthread_t, + name: *const c_char, + arg: *const c_void, + ) -> c_int; + pub fn pthread_attr_get_np(thread: crate::pthread_t, attr: *mut crate::pthread_attr_t) + -> c_int; + pub fn pthread_getattr_np(native: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_getaffinity_np( + thread: crate::pthread_t, + size: size_t, + set: *mut cpuset_t, + ) -> c_int; + pub fn pthread_setaffinity_np( + thread: crate::pthread_t, + size: size_t, + set: *mut cpuset_t, + ) -> c_int; + + pub fn _cpuset_create() -> *mut cpuset_t; + pub fn _cpuset_destroy(set: *mut cpuset_t); + pub fn _cpuset_clr(cpu: cpuid_t, set: *mut cpuset_t) -> c_int; + pub fn _cpuset_set(cpu: cpuid_t, set: *mut cpuset_t) -> c_int; + pub fn _cpuset_isset(cpu: cpuid_t, set: *const cpuset_t) -> c_int; + pub fn _cpuset_size(set: *const cpuset_t) -> size_t; + pub fn _cpuset_zero(set: *mut cpuset_t); + #[link_name = "__sigtimedwait50"] + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn localeconv_l(loc: crate::locale_t) -> *mut lconv; + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + #[link_name = "__settimeofday50"] + pub fn settimeofday(tv: *const crate::timeval, tz: *const c_void) -> c_int; + + pub fn dup3(src: c_int, dst: c_int, flags: c_int) -> c_int; + + pub fn kqueue1(flags: c_int) -> c_int; + + pub fn _lwp_self() -> lwpid_t; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + + // link.h + + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + // dlfcn.h + + pub fn _dlauxinfo() -> *mut c_void; + + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + pub fn iconv_close(cd: iconv_t) -> c_int; + + pub fn timer_create( + clockid: crate::clockid_t, + sevp: *mut crate::sigevent, + timerid: *mut crate::timer_t, + ) -> c_int; + pub fn timer_delete(timerid: crate::timer_t) -> c_int; + pub fn timer_getoverrun(timerid: crate::timer_t) -> c_int; + #[link_name = "__timer_gettime50"] + pub fn timer_gettime(timerid: crate::timer_t, curr_value: *mut crate::itimerspec) -> c_int; + #[link_name = "__timer_settime50"] + pub fn timer_settime( + timerid: crate::timer_t, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + pub fn dlvsym( + handle: *mut c_void, + symbol: *const c_char, + version: *const c_char, + ) -> *mut c_void; + + // Added in `NetBSD` 7.0 + pub fn explicit_memset(b: *mut c_void, c: c_int, len: size_t); + pub fn consttime_memequal(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + + pub fn setproctitle(fmt: *const c_char, ...); + pub fn mremap( + oldp: *mut c_void, + oldsize: size_t, + newp: *mut c_void, + newsize: size_t, + flags: c_int, + ) -> *mut c_void; + + #[link_name = "__sched_rr_get_interval50"] + pub fn sched_rr_get_interval(pid: crate::pid_t, t: *mut crate::timespec) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + #[link_name = "__pollts50"] + pub fn pollts( + fds: *mut crate::pollfd, + nfds: crate::nfds_t, + ts: *const crate::timespec, + sigmask: *const crate::sigset_t, + ) -> c_int; + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + pub fn reboot(mode: c_int, bootstr: *mut c_char) -> c_int; + + #[link_name = "___lwp_park60"] + pub fn _lwp_park( + clock: crate::clockid_t, + flags: c_int, + ts: *const crate::timespec, + unpark: crate::lwpid_t, + hint: *const c_void, + unparkhint: *mut c_void, + ) -> c_int; + pub fn _lwp_unpark(lwp: crate::lwpid_t, hint: *const c_void) -> c_int; + pub fn _lwp_unpark_all( + targets: *const crate::lwpid_t, + ntargets: size_t, + hint: *const c_void, + ) -> c_int; + pub fn getmntinfo(mntbufp: *mut *mut crate::statvfs, flags: c_int) -> c_int; + pub fn getvfsstat(buf: *mut crate::statvfs, bufsize: size_t, flags: c_int) -> c_int; + + pub fn eventfd(val: c_uint, flags: c_int) -> c_int; + pub fn eventfd_read(efd: c_int, valp: *mut eventfd_t) -> c_int; + pub fn eventfd_write(efd: c_int, val: eventfd_t) -> c_int; + + // Added in `NetBSD` 10.0 + pub fn timerfd_create(clockid: crate::clockid_t, flags: c_int) -> c_int; + pub fn timerfd_gettime(fd: c_int, curr_value: *mut crate::itimerspec) -> c_int; + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); +} + +#[link(name = "rt")] +extern "C" { + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + #[link_name = "__aio_suspend50"] + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut sigevent, + ) -> c_int; +} + +#[link(name = "util")] +extern "C" { + #[link_name = "__getpwent_r50"] + pub fn getpwent_r( + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + + pub fn efopen(p: *const c_char, m: *const c_char) -> crate::FILE; + pub fn emalloc(n: size_t) -> *mut c_void; + pub fn ecalloc(n: size_t, c: size_t) -> *mut c_void; + pub fn erealloc(p: *mut c_void, n: size_t) -> *mut c_void; + pub fn ereallocarr(p: *mut c_void, n: size_t, s: size_t); + pub fn estrdup(s: *const c_char) -> *mut c_char; + pub fn estrndup(s: *const c_char, len: size_t) -> *mut c_char; + pub fn estrlcpy(dst: *mut c_char, src: *const c_char, len: size_t) -> size_t; + pub fn estrlcat(dst: *mut c_char, src: *const c_char, len: size_t) -> size_t; + pub fn estrtoi( + nptr: *const c_char, + base: c_int, + lo: crate::intmax_t, + hi: crate::intmax_t, + ) -> crate::intmax_t; + pub fn estrtou( + nptr: *const c_char, + base: c_int, + lo: crate::uintmax_t, + hi: crate::uintmax_t, + ) -> crate::uintmax_t; + pub fn easprintf(string: *mut *mut c_char, fmt: *const c_char, ...) -> c_int; + pub fn evasprintf(string: *mut *mut c_char, fmt: *const c_char, ...) -> c_int; + pub fn esetfunc( + cb: Option, + ) -> Option; + pub fn secure_path(path: *const c_char) -> c_int; + pub fn snprintb(buf: *mut c_char, buflen: size_t, fmt: *const c_char, val: u64) -> c_int; + pub fn snprintb_m( + buf: *mut c_char, + buflen: size_t, + fmt: *const c_char, + val: u64, + max: size_t, + ) -> c_int; + + pub fn getbootfile() -> *const c_char; + pub fn getbyteorder() -> c_int; + pub fn getdiskrawname(buf: *mut c_char, buflen: size_t, name: *const c_char) -> *const c_char; + pub fn getdiskcookedname( + buf: *mut c_char, + buflen: size_t, + name: *const c_char, + ) -> *const c_char; + pub fn getfsspecname(buf: *mut c_char, buflen: size_t, spec: *const c_char) -> *const c_char; + + pub fn strpct( + buf: *mut c_char, + bufsiz: size_t, + numerator: crate::uintmax_t, + denominator: crate::uintmax_t, + precision: size_t, + ) -> *mut c_char; + pub fn strspct( + buf: *mut c_char, + bufsiz: size_t, + numerator: crate::intmax_t, + denominator: crate::intmax_t, + precision: size_t, + ) -> *mut c_char; + #[link_name = "__login50"] + pub fn login(ut: *const crate::utmp); + #[link_name = "__loginx50"] + pub fn loginx(ut: *const crate::utmpx); + pub fn logout(line: *const c_char); + pub fn logoutx(line: *const c_char, status: c_int, tpe: c_int); + pub fn logwtmp(line: *const c_char, name: *const c_char, host: *const c_char); + pub fn logwtmpx( + line: *const c_char, + name: *const c_char, + host: *const c_char, + status: c_int, + tpe: c_int, + ); + + pub fn getxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn lgetxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn fgetxattr( + filedes: c_int, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn setxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + ) -> c_int; + pub fn lsetxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + ) -> c_int; + pub fn fsetxattr( + filedes: c_int, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn flistxattr(filedes: c_int, list: *mut c_char, size: size_t) -> ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn fremovexattr(fd: c_int, path: *const c_char, name: *const c_char) -> c_int; + + pub fn string_to_flags( + string_p: *mut *mut c_char, + setp: *mut c_ulong, + clrp: *mut c_ulong, + ) -> c_int; + pub fn flags_to_string(flags: c_ulong, def: *const c_char) -> c_int; + + pub fn kinfo_getvmmap(pid: crate::pid_t, cntp: *mut size_t) -> *mut kinfo_vmentry; +} + +#[link(name = "execinfo")] +extern "C" { + pub fn backtrace(addrlist: *mut *mut c_void, len: size_t) -> size_t; + pub fn backtrace_symbols(addrlist: *const *mut c_void, len: size_t) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(addrlist: *const *mut c_void, len: size_t, fd: c_int) -> c_int; + pub fn backtrace_symbols_fmt( + addrlist: *const *mut c_void, + len: size_t, + fmt: *const c_char, + ) -> *mut *mut c_char; + pub fn backtrace_symbols_fd_fmt( + addrlist: *const *mut c_void, + len: size_t, + fd: c_int, + fmt: *const c_char, + ) -> c_int; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "sparc64")] { + mod sparc64; + pub use self::sparc64::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "mips")] { + mod mips; + pub use self::mips::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs new file mode 100644 index 00000000000000..f8f2d56c0d3742 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type __cpu_simple_lock_nv_t = c_int; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const PT_STEP: c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 2; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/riscv64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/riscv64.rs new file mode 100644 index 00000000000000..05c0cd55cb80d5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/riscv64.rs @@ -0,0 +1,97 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type __greg_t = u64; +pub type __cpu_simple_lock_nv_t = c_uint; +pub type __gregset_t = [__greg_t; _NGREG]; +pub type __fregset_t = [__fpreg; _NFREG]; + +s_no_extra_traits! { + pub union __fpreg { + pub u_u64: u64, + pub u_d: c_double, + } +} + +s! { + pub struct mcontext_t { + pub __gregs: __gregset_t, + pub __fregs: __fregset_t, + __spare: [crate::__greg_t; 7], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __fpreg { + fn eq(&self, other: &__fpreg) -> bool { + unsafe { self.u_u64 == other.u_u64 || self.u_d == other.u_d } + } + } + impl Eq for __fpreg {} + impl hash::Hash for __fpreg { + fn hash(&self, state: &mut H) { + unsafe { + self.u_u64.hash(state); + } + } + } + } +} + +// gcc for riscv64 defines `BIGGEST_ALIGNMENT`, but it's mesured in bits. +pub(crate) const __BIGGEST_ALIGNMENT_IN_BITS__: usize = 128; +// `_ALIGNBYTES` is measured in, well, bytes. +pub(crate) const _ALIGNBYTES: usize = (__BIGGEST_ALIGNMENT_IN_BITS__ / 8) - 1; + +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 0; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 3; + +pub const _NGREG: usize = 32; +pub const _NFREG: usize = 33; + +pub const _REG_X1: c_int = 0; +pub const _REG_X2: c_int = 1; +pub const _REG_X3: c_int = 2; +pub const _REG_X4: c_int = 3; +pub const _REG_X5: c_int = 4; +pub const _REG_X6: c_int = 5; +pub const _REG_X7: c_int = 6; +pub const _REG_X8: c_int = 7; +pub const _REG_X9: c_int = 8; +pub const _REG_X10: c_int = 9; +pub const _REG_X11: c_int = 10; +pub const _REG_X12: c_int = 11; +pub const _REG_X13: c_int = 12; +pub const _REG_X14: c_int = 13; +pub const _REG_X15: c_int = 14; +pub const _REG_X16: c_int = 15; +pub const _REG_X17: c_int = 16; +pub const _REG_X18: c_int = 17; +pub const _REG_X19: c_int = 18; +pub const _REG_X20: c_int = 19; +pub const _REG_X21: c_int = 20; +pub const _REG_X22: c_int = 21; +pub const _REG_X23: c_int = 22; +pub const _REG_X24: c_int = 23; +pub const _REG_X25: c_int = 24; +pub const _REG_X26: c_int = 25; +pub const _REG_X27: c_int = 26; +pub const _REG_X28: c_int = 27; +pub const _REG_X29: c_int = 28; +pub const _REG_X30: c_int = 29; +pub const _REG_X31: c_int = 30; +pub const _REG_PC: c_int = 31; + +pub const _REG_RA: c_int = _REG_X1; +pub const _REG_SP: c_int = _REG_X2; +pub const _REG_GP: c_int = _REG_X3; +pub const _REG_TP: c_int = _REG_X4; +pub const _REG_S0: c_int = _REG_X8; +pub const _REG_RV: c_int = _REG_X10; +pub const _REG_A0: c_int = _REG_X10; + +pub const _REG_F0: c_int = 0; +pub const _REG_FPCSR: c_int = 32; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs new file mode 100644 index 00000000000000..91622f7eea3fab --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs @@ -0,0 +1,7 @@ +use crate::prelude::*; + +pub type __cpu_simple_lock_nv_t = c_uchar; + +// should be pub(crate), but that requires Rust 1.18.0 +#[doc(hidden)] +pub const _ALIGNBYTES: usize = 0xf; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs new file mode 100644 index 00000000000000..95f55768973ca3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs @@ -0,0 +1,5 @@ +use crate::prelude::*; + +pub type __cpu_simple_lock_nv_t = c_uchar; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs new file mode 100644 index 00000000000000..801b326b70fa5d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs @@ -0,0 +1,59 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type c___greg_t = u64; +pub type __cpu_simple_lock_nv_t = c_uchar; + +// FIXME(alignment): Type is `__aligned(8)` +type __fpregset_t = [c_char; 512]; + +s! { + pub struct mcontext_t { + pub __gregs: [c___greg_t; 26], + pub _mc_tlsbase: c___greg_t, + pub __fpregs: __fpregset_t, + } + + pub struct ucontext_t { + pub uc_flags: c_uint, + pub uc_link: *mut crate::ucontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: crate::mcontext_t, + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const PT_STEP: c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 4; + +pub const _REG_RDI: c_int = 0; +pub const _REG_RSI: c_int = 1; +pub const _REG_RDX: c_int = 2; +pub const _REG_RCX: c_int = 3; +pub const _REG_R8: c_int = 4; +pub const _REG_R9: c_int = 5; +pub const _REG_R10: c_int = 6; +pub const _REG_R11: c_int = 7; +pub const _REG_R12: c_int = 8; +pub const _REG_R13: c_int = 9; +pub const _REG_R14: c_int = 10; +pub const _REG_R15: c_int = 11; +pub const _REG_RBP: c_int = 12; +pub const _REG_RBX: c_int = 13; +pub const _REG_RAX: c_int = 14; +pub const _REG_GS: c_int = 15; +pub const _REG_FS: c_int = 16; +pub const _REG_ES: c_int = 17; +pub const _REG_DS: c_int = 18; +pub const _REG_TRAPNO: c_int = 19; +pub const _REG_ERR: c_int = 20; +pub const _REG_RIP: c_int = 21; +pub const _REG_CS: c_int = 22; +pub const _REG_RFLAGS: c_int = 23; +pub const _REG_RSP: c_int = 24; +pub const _REG_SS: c_int = 25; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/aarch64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/aarch64.rs new file mode 100644 index 00000000000000..13142ea0f93662 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/aarch64.rs @@ -0,0 +1,20 @@ +use crate::prelude::*; + +pub type ucontext_t = sigcontext; + +s! { + pub struct sigcontext { + __sc_unused: Padding, + pub sc_mask: c_int, + pub sc_sp: c_ulong, + pub sc_lr: c_ulong, + pub sc_elr: c_ulong, + pub sc_spsr: c_ulong, + pub sc_x: [c_ulong; 30], + pub sc_cookie: c_long, + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/arm.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/arm.rs new file mode 100644 index 00000000000000..8b3f72139d86e9 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/arm.rs @@ -0,0 +1,5 @@ +use crate::prelude::*; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mips64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mips64.rs new file mode 100644 index 00000000000000..162ceda265df91 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mips64.rs @@ -0,0 +1,4 @@ +#[doc(hidden)] +pub const _ALIGNBYTES: usize = 7; + +pub const _MAX_PAGE_SHIFT: u32 = 14; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mod.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mod.rs new file mode 100644 index 00000000000000..b6e70f9871d4b3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/mod.rs @@ -0,0 +1,2105 @@ +use crate::prelude::*; +use crate::unix::bsd::O_SYNC; +use crate::{ + cmsghdr, + off_t, +}; + +pub type clock_t = i64; +pub type suseconds_t = c_long; +pub type dev_t = i32; +pub type sigset_t = c_uint; +pub type blksize_t = i32; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type idtype_t = c_uint; +pub type pthread_attr_t = *mut c_void; +pub type pthread_mutex_t = *mut c_void; +pub type pthread_mutexattr_t = *mut c_void; +pub type pthread_cond_t = *mut c_void; +pub type pthread_condattr_t = *mut c_void; +pub type pthread_rwlock_t = *mut c_void; +pub type pthread_rwlockattr_t = *mut c_void; +pub type pthread_spinlock_t = crate::uintptr_t; +pub type caddr_t = *mut c_char; + +// elf.h + +pub type Elf32_Addr = u32; +pub type Elf32_Half = u16; +pub type Elf32_Lword = u64; +pub type Elf32_Off = u32; +pub type Elf32_Sword = i32; +pub type Elf32_Word = u32; + +pub type Elf64_Addr = u64; +pub type Elf64_Half = u16; +pub type Elf64_Lword = u64; +pub type Elf64_Off = u64; +pub type Elf64_Sword = i32; +pub type Elf64_Sxword = i64; +pub type Elf64_Word = u32; +pub type Elf64_Xword = u64; + +// search.h + +pub type ENTRY = entry; +pub type ACTION = c_uint; + +// spawn.h +pub type posix_spawnattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_void; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + type Elf_Addr = Elf64_Addr; + type Elf_Half = Elf64_Half; + type Elf_Phdr = Elf64_Phdr; + } else if #[cfg(target_pointer_width = "32")] { + type Elf_Addr = Elf32_Addr; + type Elf_Half = Elf32_Half; + type Elf_Phdr = Elf32_Phdr; + } +} + +s! { + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_matchc: size_t, + pub gl_offs: size_t, + pub gl_flags: c_int, + pub gl_pathv: *mut *mut c_char, + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + __unused6: Padding<*mut c_void>, + __unused7: Padding<*mut c_void>, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct ufs_args { + pub fspec: *mut c_char, + pub export_info: export_args, + } + + pub struct mfs_args { + pub fspec: *mut c_char, + pub export_info: export_args, + // https://github.com/openbsd/src/blob/HEAD/sys/sys/types.h#L134 + pub base: *mut c_char, + pub size: c_ulong, + } + + pub struct iso_args { + pub fspec: *mut c_char, + pub export_info: export_args, + pub flags: c_int, + pub sess: c_int, + } + + pub struct nfs_args { + pub version: c_int, + pub addr: *mut crate::sockaddr, + pub addrlen: c_int, + pub sotype: c_int, + pub proto: c_int, + pub fh: *mut c_uchar, + pub fhsize: c_int, + pub flags: c_int, + pub wsize: c_int, + pub rsize: c_int, + pub readdirsize: c_int, + pub timeo: c_int, + pub retrans: c_int, + pub maxgrouplist: c_int, + pub readahead: c_int, + pub leaseterm: c_int, + pub deadthresh: c_int, + pub hostname: *mut c_char, + pub acregmin: c_int, + pub acregmax: c_int, + pub acdirmin: c_int, + pub acdirmax: c_int, + } + + pub struct msdosfs_args { + pub fspec: *mut c_char, + pub export_info: export_args, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub mask: crate::mode_t, + pub flags: c_int, + } + + pub struct ntfs_args { + pub fspec: *mut c_char, + pub export_info: export_args, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub mode: crate::mode_t, + pub flag: c_ulong, + } + + pub struct udf_args { + pub fspec: *mut c_char, + pub lastblock: u32, + } + + pub struct tmpfs_args { + pub ta_version: c_int, + pub ta_nodes_max: crate::ino_t, + pub ta_size_max: off_t, + pub ta_root_uid: crate::uid_t, + pub ta_root_gid: crate::gid_t, + pub ta_root_mode: crate::mode_t, + } + + pub struct fusefs_args { + pub name: *mut c_char, + pub fd: c_int, + pub max_read: c_int, + pub allow_other: c_int, + } + + pub struct xucred { + pub cr_uid: crate::uid_t, + pub cr_gid: crate::gid_t, + pub cr_ngroups: c_short, + //https://github.com/openbsd/src/blob/HEAD/sys/sys/syslimits.h#L44 + pub cr_groups: [crate::gid_t; 16], + } + + pub struct export_args { + pub ex_flags: c_int, + pub ex_root: crate::uid_t, + pub ex_anon: xucred, + pub ex_addr: *mut crate::sockaddr, + pub ex_addrlen: c_int, + pub ex_mask: *mut crate::sockaddr, + pub ex_masklen: c_int, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [i8; 8], + } + + pub struct splice { + pub sp_fd: c_int, + pub sp_max: off_t, + pub sp_idle: crate::timeval, + } + + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + } + + pub struct stat { + pub st_mode: crate::mode_t, + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: crate::blkcnt_t, + pub st_blksize: crate::blksize_t, + pub st_flags: u32, + pub st_gen: u32, + pub st_birthtime: crate::time_t, + pub st_birthtime_nsec: c_long, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: crate::socklen_t, + pub ai_addr: *mut crate::sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut crate::addrinfo, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct if_data { + pub ifi_type: c_uchar, + pub ifi_addrlen: c_uchar, + pub ifi_hdrlen: c_uchar, + pub ifi_link_state: c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_rdomain: u32, + pub ifi_baudrate: u64, + pub ifi_ipackets: u64, + pub ifi_ierrors: u64, + pub ifi_opackets: u64, + pub ifi_oerrors: u64, + pub ifi_collisions: u64, + pub ifi_ibytes: u64, + pub ifi_obytes: u64, + pub ifi_imcasts: u64, + pub ifi_omcasts: u64, + pub ifi_iqdrops: u64, + pub ifi_oqdrops: u64, + pub ifi_noproto: u64, + pub ifi_capabilities: u32, + pub ifi_lastchange: crate::timeval, + } + + pub struct if_msghdr { + pub ifm_msglen: c_ushort, + pub ifm_version: c_uchar, + pub ifm_type: c_uchar, + pub ifm_hdrlen: c_ushort, + pub ifm_index: c_ushort, + pub ifm_tableid: c_ushort, + pub ifm_pad1: c_uchar, + pub ifm_pad2: c_uchar, + pub ifm_addrs: c_int, + pub ifm_flags: c_int, + pub ifm_xflags: c_int, + pub ifm_data: if_data, + } + + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 24], + } + + pub struct sockpeercred { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub pid: crate::pid_t, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: c_int, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: c_short, + pub shm_atime: crate::time_t, + __shm_atimensec: c_long, + pub shm_dtime: crate::time_t, + __shm_dtimensec: c_long, + pub shm_ctime: crate::time_t, + __shm_ctimensec: c_long, + pub shm_internal: *mut c_void, + } + + // elf.h + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + // link.h + + pub struct dl_phdr_info { + pub dlpi_addr: Elf_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const Elf_Phdr, + pub dlpi_phnum: Elf_Half, + } + + // sys/sysctl.h + pub struct kinfo_proc { + pub p_forw: u64, + pub p_back: u64, + pub p_paddr: u64, + pub p_addr: u64, + pub p_fd: u64, + pub p_stats: u64, + pub p_limit: u64, + pub p_vmspace: u64, + pub p_sigacts: u64, + pub p_sess: u64, + pub p_tsess: u64, + pub p_ru: u64, + pub p_eflag: i32, + pub p_exitsig: i32, + pub p_flag: i32, + pub p_pid: i32, + pub p_ppid: i32, + pub p_sid: i32, + pub p__pgid: i32, + pub p_tpgid: i32, + pub p_uid: u32, + pub p_ruid: u32, + pub p_gid: u32, + pub p_rgid: u32, + pub p_groups: [u32; KI_NGROUPS as usize], + pub p_ngroups: i16, + pub p_jobc: i16, + pub p_tdev: u32, + pub p_estcpu: u32, + pub p_rtime_sec: u32, + pub p_rtime_usec: u32, + pub p_cpticks: i32, + pub p_pctcpu: u32, + pub p_swtime: u32, + pub p_slptime: u32, + pub p_schedflags: i32, + pub p_uticks: u64, + pub p_sticks: u64, + pub p_iticks: u64, + pub p_tracep: u64, + pub p_traceflag: i32, + pub p_holdcnt: i32, + pub p_siglist: i32, + pub p_sigmask: u32, + pub p_sigignore: u32, + pub p_sigcatch: u32, + pub p_stat: i8, + pub p_priority: u8, + pub p_usrpri: u8, + pub p_nice: u8, + pub p_xstat: u16, + pub p_spare: u16, + pub p_comm: [c_char; KI_MAXCOMLEN as usize], + pub p_wmesg: [c_char; KI_WMESGLEN as usize], + pub p_wchan: u64, + pub p_login: [c_char; KI_MAXLOGNAME as usize], + pub p_vm_rssize: i32, + pub p_vm_tsize: i32, + pub p_vm_dsize: i32, + pub p_vm_ssize: i32, + pub p_uvalid: i64, + pub p_ustart_sec: u64, + pub p_ustart_usec: u32, + pub p_uutime_sec: u32, + pub p_uutime_usec: u32, + pub p_ustime_sec: u32, + pub p_ustime_usec: u32, + pub p_uru_maxrss: u64, + pub p_uru_ixrss: u64, + pub p_uru_idrss: u64, + pub p_uru_isrss: u64, + pub p_uru_minflt: u64, + pub p_uru_majflt: u64, + pub p_uru_nswap: u64, + pub p_uru_inblock: u64, + pub p_uru_oublock: u64, + pub p_uru_msgsnd: u64, + pub p_uru_msgrcv: u64, + pub p_uru_nsignals: u64, + pub p_uru_nvcsw: u64, + pub p_uru_nivcsw: u64, + pub p_uctime_sec: u32, + pub p_uctime_usec: u32, + pub p_psflags: u32, + pub p_acflag: u32, + pub p_svuid: u32, + pub p_svgid: u32, + pub p_emul: [c_char; KI_EMULNAMELEN as usize], + pub p_rlim_rss_cur: u64, + pub p_cpuid: u64, + pub p_vm_map_size: u64, + pub p_tid: i32, + pub p_rtableid: u32, + pub p_pledge: u64, + pub p_name: [c_char; KI_MAXCOMLEN as usize], + } + + pub struct kinfo_file { + pub f_fileaddr: u64, + pub f_flag: u32, + pub f_iflags: u32, + pub f_type: u32, + pub f_count: u32, + pub f_msgcount: u32, + pub f_usecount: u32, + pub f_ucred: u64, + pub f_uid: u32, + pub f_gid: u32, + pub f_ops: u64, + pub f_offset: u64, + pub f_data: u64, + pub f_rxfer: u64, + pub f_rwfer: u64, + pub f_seek: u64, + pub f_rbytes: u64, + pub f_wbytes: u64, + pub v_un: u64, + pub v_type: u32, + pub v_tag: u32, + pub v_flag: u32, + pub va_rdev: u32, + pub v_data: u64, + pub v_mount: u64, + pub va_fileid: u64, + pub va_size: u64, + pub va_mode: u32, + pub va_fsid: u32, + pub f_mntonname: [c_char; KI_MNAMELEN as usize], + pub so_type: u32, + pub so_state: u32, + pub so_pcb: u64, + pub so_protocol: u32, + pub so_family: u32, + pub inp_ppcb: u64, + pub inp_lport: u32, + pub inp_laddru: [u32; 4], + pub inp_fport: u32, + pub inp_faddru: [u32; 4], + pub unp_conn: u64, + pub pipe_peer: u64, + pub pipe_state: u32, + pub kq_count: u32, + pub kq_state: u32, + __unused1: Padding, + pub p_pid: u32, + pub fd_fd: i32, + pub fd_ofileflags: u32, + pub p_uid: u32, + pub p_gid: u32, + pub p_tid: u32, + pub p_comm: [c_char; KI_MAXCOMLEN as usize], + pub inp_rtableid: u32, + pub so_splice: u64, + pub so_splicelen: i64, + pub so_rcv_cc: u64, + pub so_snd_cc: u64, + pub unp_refs: u64, + pub unp_nextref: u64, + pub unp_addr: u64, + pub unp_path: [c_char; KI_UNPPATHLEN as usize], + pub inp_proto: u32, + pub t_state: u32, + pub t_rcv_wnd: u64, + pub t_snd_wnd: u64, + pub t_snd_cwnd: u64, + pub va_nlink: u32, + } + + pub struct kinfo_vmentry { + pub kve_start: c_ulong, + pub kve_end: c_ulong, + pub kve_guard: c_ulong, + pub kve_fspace: c_ulong, + pub kve_fspace_augment: c_ulong, + pub kve_offset: u64, + pub kve_wired_count: c_int, + pub kve_etype: c_int, + pub kve_protection: c_int, + pub kve_max_protection: c_int, + pub kve_advice: c_int, + pub kve_inheritance: c_int, + pub kve_flags: u8, + } + + pub struct ptrace_state { + pub pe_report_event: c_int, + pub pe_other_pid: crate::pid_t, + pub pe_tid: crate::pid_t, + } + + pub struct ptrace_thread_state { + pub pts_tid: crate::pid_t, + pub pts_name: [c_char; PT_PTS_NAMELEN as usize], + } + + // search.h + pub struct entry { + pub key: *mut c_char, + pub data: *mut c_void, + } + + pub struct ifreq { + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub struct tcp_info { + pub tcpi_state: u8, + pub __tcpi_ca_state: u8, + pub __tcpi_retransmits: u8, + pub __tcpi_probes: u8, + pub __tcpi_backoff: u8, + pub tcpi_options: u8, + pub tcpi_snd_wscale: u8, + pub tcpi_rcv_wscale: u8, + pub tcpi_rto: u32, + pub __tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub __tcpi_unacked: u32, + pub __tcpi_sacked: u32, + pub __tcpi_lost: u32, + pub __tcpi_retrans: u32, + pub __tcpi_fackets: u32, + pub tcpi_last_data_sent: u32, + pub tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub tcpi_last_ack_recv: u32, + pub __tcpi_pmtu: u32, + pub __tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub __tcpi_advmss: u32, + pub __tcpi_reordering: u32, + pub __tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_snd_wnd: u32, + pub tcpi_snd_nxt: u32, + pub tcpi_rcv_nxt: u32, + pub tcpi_toe_tid: u32, + pub tcpi_snd_rexmitpack: u32, + pub tcpi_rcv_ooopack: u32, + pub tcpi_snd_zerowin: u32, + pub tcpi_rttmin: u32, + pub tcpi_max_sndwnd: u32, + pub tcpi_rcv_adv: u32, + pub tcpi_rcv_up: u32, + pub tcpi_snd_una: u32, + pub tcpi_snd_up: u32, + pub tcpi_snd_wl1: u32, + pub tcpi_snd_wl2: u32, + pub tcpi_snd_max: u32, + pub tcpi_ts_recent: u32, + pub tcpi_ts_recent_age: u32, + pub tcpi_rfbuf_cnt: u32, + pub tcpi_rfbuf_ts: u32, + pub tcpi_so_rcv_sb_cc: u32, + pub tcpi_so_rcv_sb_hiwat: u32, + pub tcpi_so_rcv_sb_lowat: u32, + pub tcpi_so_rcv_sb_wat: u32, + pub tcpi_so_snd_sb_cc: u32, + pub tcpi_so_snd_sb_hiwat: u32, + pub tcpi_so_snd_sb_lowat: u32, + pub tcpi_so_snd_sb_wat: u32, + } + + pub struct dirent { + pub d_fileno: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_type: u8, + pub d_namlen: u8, + __d_padding: Padding<[u8; 4]>, + pub d_name: [c_char; 256], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_pad2: Padding, + __ss_pad3: Padding<[u8; 240]>, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + pub si_addr: *mut c_char, + #[cfg(target_pointer_width = "32")] + __pad: Padding<[u8; 112]>, + #[cfg(target_pointer_width = "64")] + __pad: Padding<[u8; 108]>, + } + + pub struct lastlog { + ll_time: crate::time_t, + ll_line: [c_char; UT_LINESIZE], + ll_host: [c_char; UT_HOSTSIZE], + } + + pub struct utmp { + pub ut_line: [c_char; UT_LINESIZE], + pub ut_name: [c_char; UT_NAMESIZE], + pub ut_host: [c_char; UT_HOSTSIZE], + pub ut_time: crate::time_t, + } + + pub struct statfs { + pub f_flags: u32, + pub f_bsize: u32, + pub f_iosize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: i64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: i64, + pub f_syncwrites: u64, + pub f_syncreads: u64, + pub f_asyncwrites: u64, + pub f_asyncreads: u64, + pub f_fsid: crate::fsid_t, + pub f_namemax: u32, + pub f_owner: crate::uid_t, + pub f_ctime: u64, + pub f_fstypename: [c_char; 16], + pub f_mntonname: [c_char; 90], + pub f_mntfromname: [c_char; 90], + pub f_mntfromspec: [c_char; 90], + pub mount_info: mount_info, + } +} + +s_no_extra_traits! { + pub union mount_info { + pub ufs_args: ufs_args, + pub mfs_args: mfs_args, + pub nfs_args: nfs_args, + pub iso_args: iso_args, + pub msdosfs_args: msdosfs_args, + pub ntfs_args: ntfs_args, + pub tmpfs_args: tmpfs_args, + align: [c_char; 160], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for mount_info { + fn eq(&self, other: &mount_info) -> bool { + unsafe { + self.align + .iter() + .zip(other.align.iter()) + .all(|(a, b)| a == b) + } + } + } + + impl Eq for mount_info {} + + impl hash::Hash for mount_info { + fn hash(&self, state: &mut H) { + unsafe { self.align.hash(state) }; + } + } + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_char { + self.si_addr + } + + pub unsafe fn si_code(&self) -> c_int { + self.si_code + } + + pub unsafe fn si_errno(&self) -> c_int { + self.si_errno + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_code: c_int, + _si_errno: c_int, + _pad: Padding<[c_int; SI_PAD]>, + _pid: crate::pid_t, + } + (*(self as *const siginfo_t).cast::())._pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_code: c_int, + _si_errno: c_int, + _pad: Padding<[c_int; SI_PAD]>, + _pid: crate::pid_t, + _uid: crate::uid_t, + } + (*(self as *const siginfo_t).cast::())._uid + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_code: c_int, + _si_errno: c_int, + _pad: Padding<[c_int; SI_PAD]>, + _pid: crate::pid_t, + _uid: crate::uid_t, + value: crate::sigval, + } + (*(self as *const siginfo_t).cast::()).value + } + + pub unsafe fn si_status(&self) -> c_int { + #[repr(C)] + struct siginfo_proc { + _si_signo: c_int, + _si_code: c_int, + _si_errno: c_int, + _pad: Padding<[c_int; SI_PAD]>, + _pid: crate::pid_t, + _uid: crate::uid_t, + _utime: crate::clock_t, + _stime: crate::clock_t, + _status: crate::c_int, + } + (*(self as *const siginfo_t as *const siginfo_proc))._status + } +} + +s_no_extra_traits! { + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_flags: c_short, + pub ifru_metric: c_int, + pub ifru_vnetid: i64, + pub ifru_media: u64, + pub ifru_data: crate::caddr_t, + pub ifru_index: c_uint, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_ifr_ifru { + fn eq(&self, other: &__c_anonymous_ifr_ifru) -> bool { + unsafe { + self.ifru_addr == other.ifru_addr + && self.ifru_dstaddr == other.ifru_dstaddr + && self.ifru_broadaddr == other.ifru_broadaddr + && self.ifru_flags == other.ifru_flags + && self.ifru_metric == other.ifru_metric + && self.ifru_vnetid == other.ifru_vnetid + && self.ifru_media == other.ifru_media + && self.ifru_data == other.ifru_data + && self.ifru_index == other.ifru_index + } + } + } + + impl Eq for __c_anonymous_ifr_ifru {} + + impl hash::Hash for __c_anonymous_ifr_ifru { + fn hash(&self, state: &mut H) { + unsafe { + self.ifru_addr.hash(state); + self.ifru_dstaddr.hash(state); + self.ifru_broadaddr.hash(state); + self.ifru_flags.hash(state); + self.ifru_metric.hash(state); + self.ifru_vnetid.hash(state); + self.ifru_media.hash(state); + self.ifru_data.hash(state); + self.ifru_index.hash(state); + } + } + } + } +} + +pub const UT_NAMESIZE: usize = 32; +pub const UT_LINESIZE: usize = 8; +pub const UT_HOSTSIZE: usize = 256; + +pub const O_CLOEXEC: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x20000; +pub const O_RSYNC: c_int = O_SYNC; + +pub const MS_SYNC: c_int = 0x0002; +pub const MS_INVALIDATE: c_int = 0x0004; + +pub const POLLNORM: c_short = crate::POLLRDNORM; + +pub const ENOATTR: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const EOVERFLOW: c_int = 87; +pub const ECANCELED: c_int = 88; +pub const EIDRM: c_int = 89; +pub const ENOMSG: c_int = 90; +pub const ENOTSUP: c_int = 91; +pub const EBADMSG: c_int = 92; +pub const ENOTRECOVERABLE: c_int = 93; +pub const EOWNERDEAD: c_int = 94; +pub const EPROTO: c_int = 95; +pub const ELAST: c_int = 95; + +pub const F_DUPFD_CLOEXEC: c_int = 10; + +pub const UTIME_OMIT: c_long = -1; +pub const UTIME_NOW: c_long = -2; + +pub const AT_FDCWD: c_int = -100; +pub const AT_EACCESS: c_int = 0x01; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x02; +pub const AT_SYMLINK_FOLLOW: c_int = 0x04; +pub const AT_REMOVEDIR: c_int = 0x08; + +pub const AT_NULL: c_int = 0; +pub const AT_IGNORE: c_int = 1; +pub const AT_PAGESZ: c_int = 6; +pub const AT_HWCAP: c_int = 25; +pub const AT_HWCAP2: c_int = 26; + +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 9; + +pub const SO_TIMESTAMP: c_int = 0x0800; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_BINDANY: c_int = 0x1000; +pub const SO_NETPROC: c_int = 0x1020; +pub const SO_RTABLE: c_int = 0x1021; +pub const SO_PEERCRED: c_int = 0x1022; +pub const SO_SPLICE: c_int = 0x1023; +pub const SO_DOMAIN: c_int = 0x1024; +pub const SO_PROTOCOL: c_int = 0x1025; + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// pup +pub const IPPROTO_PUP: c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +/// IP Mobility RFC 2004 +pub const IPPROTO_MOBILE: c_int = 55; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +/// ISO cnlp +pub const IPPROTO_EON: c_int = 80; +/// Ethernet-in-IP +pub const IPPROTO_ETHERIP: c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_IPCOMP: c_int = 108; +/// CARP +pub const IPPROTO_CARP: c_int = 112; +/// unicast MPLS packet +pub const IPPROTO_MPLS: c_int = 137; +/// PFSYNC +pub const IPPROTO_PFSYNC: c_int = 240; +pub const IPPROTO_MAX: c_int = 256; + +// Only used internally, so it can be outside the range of valid IP protocols +pub const IPPROTO_DIVERT: c_int = 258; + +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_SENDSRCADDR: c_int = IP_RECVDSTADDR; +pub const IP_RECVIF: c_int = 30; + +// sys/netinet/in.h +pub const TCP_MD5SIG: c_int = 0x04; +pub const TCP_NOPUSH: c_int = 0x10; + +pub const MSG_WAITFORONE: c_int = 0x1000; + +pub const AF_ECMA: c_int = 8; +pub const AF_ROUTE: c_int = 17; +pub const AF_ENCAP: c_int = 28; +pub const AF_SIP: c_int = 29; +pub const AF_KEY: c_int = 30; +pub const pseudo_AF_HDRCMPLT: c_int = 31; +pub const AF_BLUETOOTH: c_int = 32; +pub const AF_MPLS: c_int = 33; +pub const pseudo_AF_PFLOW: c_int = 34; +pub const pseudo_AF_PIPEX: c_int = 35; +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const NET_RT_IFLIST: c_int = 3; +pub const NET_RT_STATS: c_int = 4; +pub const NET_RT_TABLE: c_int = 5; +pub const NET_RT_IFNAMES: c_int = 6; +#[doc(hidden)] +#[deprecated( + since = "0.2.95", + note = "Possibly increasing over the releases and might not be so used in the field" +)] +pub const NET_RT_MAXID: c_int = 7; + +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; + +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_ENCAP: c_int = AF_ENCAP; +pub const PF_SIP: c_int = AF_SIP; +pub const PF_KEY: c_int = AF_KEY; +pub const PF_BPF: c_int = pseudo_AF_HDRCMPLT; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_PFLOW: c_int = pseudo_AF_PFLOW; +pub const PF_PIPEX: c_int = pseudo_AF_PIPEX; + +pub const SCM_TIMESTAMP: c_int = 0x04; + +pub const O_DSYNC: c_int = 128; + +pub const MAP_RENAME: c_int = 0x0000; +pub const MAP_NORESERVE: c_int = 0x0000; +pub const MAP_HASSEMAPHORE: c_int = 0x0000; +pub const MAP_TRYFIXED: c_int = 0; + +pub const EIPSEC: c_int = 82; +pub const ENOMEDIUM: c_int = 85; +pub const EMEDIUMTYPE: c_int = 86; + +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_NODATA: c_int = -5; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_SYSTEM: c_int = -11; +pub const EAI_OVERFLOW: c_int = -14; + +pub const RUSAGE_THREAD: c_int = 1; + +pub const MAP_COPY: c_int = 0x0002; +pub const MAP_NOEXTEND: c_int = 0x0000; + +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_CHOWN_RESTRICTED: c_int = 7; +pub const _PC_NO_TRUNC: c_int = 8; +pub const _PC_VDISABLE: c_int = 9; +pub const _PC_2_SYMLINKS: c_int = 10; +pub const _PC_ALLOC_SIZE_MIN: c_int = 11; +pub const _PC_ASYNC_IO: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_PRIO_IO: c_int = 14; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 15; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 16; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 17; +pub const _PC_REC_XFER_ALIGN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_SYNC_IO: c_int = 20; +pub const _PC_TIMESTAMP_RESOLUTION: c_int = 21; + +pub const _CS_PATH: c_int = 1; + +pub const _SC_CLK_TCK: c_int = 3; +pub const _SC_SEM_NSEMS_MAX: c_int = 31; +pub const _SC_SEM_VALUE_MAX: c_int = 32; +pub const _SC_HOST_NAME_MAX: c_int = 33; +pub const _SC_MONOTONIC_CLOCK: c_int = 34; +pub const _SC_2_PBS: c_int = 35; +pub const _SC_2_PBS_ACCOUNTING: c_int = 36; +pub const _SC_2_PBS_CHECKPOINT: c_int = 37; +pub const _SC_2_PBS_LOCATE: c_int = 38; +pub const _SC_2_PBS_MESSAGE: c_int = 39; +pub const _SC_2_PBS_TRACK: c_int = 40; +pub const _SC_ADVISORY_INFO: c_int = 41; +pub const _SC_AIO_LISTIO_MAX: c_int = 42; +pub const _SC_AIO_MAX: c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; +pub const _SC_ASYNCHRONOUS_IO: c_int = 45; +pub const _SC_ATEXIT_MAX: c_int = 46; +pub const _SC_BARRIERS: c_int = 47; +pub const _SC_CLOCK_SELECTION: c_int = 48; +pub const _SC_CPUTIME: c_int = 49; +pub const _SC_DELAYTIMER_MAX: c_int = 50; +pub const _SC_IOV_MAX: c_int = 51; +pub const _SC_IPV6: c_int = 52; +pub const _SC_MAPPED_FILES: c_int = 53; +pub const _SC_MEMLOCK: c_int = 54; +pub const _SC_MEMLOCK_RANGE: c_int = 55; +pub const _SC_MEMORY_PROTECTION: c_int = 56; +pub const _SC_MESSAGE_PASSING: c_int = 57; +pub const _SC_MQ_OPEN_MAX: c_int = 58; +pub const _SC_MQ_PRIO_MAX: c_int = 59; +pub const _SC_PRIORITIZED_IO: c_int = 60; +pub const _SC_PRIORITY_SCHEDULING: c_int = 61; +pub const _SC_RAW_SOCKETS: c_int = 62; +pub const _SC_READER_WRITER_LOCKS: c_int = 63; +pub const _SC_REALTIME_SIGNALS: c_int = 64; +pub const _SC_REGEXP: c_int = 65; +pub const _SC_RTSIG_MAX: c_int = 66; +pub const _SC_SEMAPHORES: c_int = 67; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 68; +pub const _SC_SHELL: c_int = 69; +pub const _SC_SIGQUEUE_MAX: c_int = 70; +pub const _SC_SPAWN: c_int = 71; +pub const _SC_SPIN_LOCKS: c_int = 72; +pub const _SC_SPORADIC_SERVER: c_int = 73; +pub const _SC_SS_REPL_MAX: c_int = 74; +pub const _SC_SYNCHRONIZED_IO: c_int = 75; +pub const _SC_SYMLOOP_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_CPUTIME: c_int = 79; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 80; +pub const _SC_THREAD_KEYS_MAX: c_int = 81; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 82; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 83; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 84; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 85; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 86; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 87; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 88; +pub const _SC_THREAD_STACK_MIN: c_int = 89; +pub const _SC_THREAD_THREADS_MAX: c_int = 90; +pub const _SC_THREADS: c_int = 91; +pub const _SC_TIMEOUTS: c_int = 92; +pub const _SC_TIMER_MAX: c_int = 93; +pub const _SC_TIMERS: c_int = 94; +pub const _SC_TRACE: c_int = 95; +pub const _SC_TRACE_EVENT_FILTER: c_int = 96; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 97; +pub const _SC_TRACE_INHERIT: c_int = 98; +pub const _SC_TRACE_LOG: c_int = 99; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 100; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 101; +pub const _SC_LOGIN_NAME_MAX: c_int = 102; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 103; +pub const _SC_TRACE_NAME_MAX: c_int = 104; +pub const _SC_TRACE_SYS_MAX: c_int = 105; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 106; +pub const _SC_TTY_NAME_MAX: c_int = 107; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 108; +pub const _SC_V6_ILP32_OFF32: c_int = 109; +pub const _SC_V6_ILP32_OFFBIG: c_int = 110; +pub const _SC_V6_LP64_OFF64: c_int = 111; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 112; +pub const _SC_V7_ILP32_OFF32: c_int = 113; +pub const _SC_V7_ILP32_OFFBIG: c_int = 114; +pub const _SC_V7_LP64_OFF64: c_int = 115; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 116; +pub const _SC_XOPEN_CRYPT: c_int = 117; +pub const _SC_XOPEN_ENH_I18N: c_int = 118; +pub const _SC_XOPEN_LEGACY: c_int = 119; +pub const _SC_XOPEN_REALTIME: c_int = 120; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 121; +pub const _SC_XOPEN_STREAMS: c_int = 122; +pub const _SC_XOPEN_UNIX: c_int = 123; +pub const _SC_XOPEN_UUCP: c_int = 124; +pub const _SC_XOPEN_VERSION: c_int = 125; +pub const _SC_PHYS_PAGES: c_int = 500; +pub const _SC_AVPHYS_PAGES: c_int = 501; +pub const _SC_NPROCESSORS_CONF: c_int = 502; +pub const _SC_NPROCESSORS_ONLN: c_int = 503; + +pub const FD_SETSIZE: usize = 1024; + +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_OTHER: c_int = 2; +pub const SCHED_RR: c_int = 3; + +pub const ST_NOSUID: c_ulong = 2; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = ptr::null_mut(); +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = ptr::null_mut(); +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = ptr::null_mut(); + +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_NORMAL: c_int = 3; +pub const PTHREAD_MUTEX_STRICT_NP: c_int = 4; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_STRICT_NP; + +pub const EVFILT_READ: i16 = -1; +pub const EVFILT_WRITE: i16 = -2; +pub const EVFILT_AIO: i16 = -3; +pub const EVFILT_VNODE: i16 = -4; +pub const EVFILT_PROC: i16 = -5; +pub const EVFILT_SIGNAL: i16 = -6; +pub const EVFILT_TIMER: i16 = -7; +pub const EVFILT_DEVICE: i16 = -8; +pub const EVFILT_EXCEPT: i16 = -9; +pub const EVFILT_USER: i16 = -10; +pub const EV_ADD: u16 = 0x1; +pub const EV_DELETE: u16 = 0x2; +pub const EV_ENABLE: u16 = 0x4; +pub const EV_DISABLE: u16 = 0x8; +pub const EV_ONESHOT: u16 = 0x10; +pub const EV_CLEAR: u16 = 0x20; +pub const EV_RECEIPT: u16 = 0x40; +pub const EV_DISPATCH: u16 = 0x80; +pub const EV_FLAG1: u16 = 0x2000; +pub const EV_ERROR: u16 = 0x4000; +pub const EV_EOF: u16 = 0x8000; + +#[deprecated(since = "0.2.113", note = "Not stable across OS versions")] +pub const EV_SYSFLAGS: u16 = 0xf800; + +pub const NOTE_TRIGGER: u32 = 0x01000000; +pub const NOTE_FFNOP: u32 = 0x00000000; +pub const NOTE_FFAND: u32 = 0x40000000; +pub const NOTE_FFOR: u32 = 0x80000000; +pub const NOTE_FFCOPY: u32 = 0xc0000000; +pub const NOTE_FFCTRLMASK: u32 = 0xc0000000; +pub const NOTE_FFLAGSMASK: u32 = 0x00ffffff; +pub const NOTE_LOWAT: u32 = 0x00000001; +pub const NOTE_EOF: u32 = 0x00000002; +pub const NOTE_OOB: u32 = 0x00000004; +pub const NOTE_DELETE: u32 = 0x00000001; +pub const NOTE_WRITE: u32 = 0x00000002; +pub const NOTE_EXTEND: u32 = 0x00000004; +pub const NOTE_ATTRIB: u32 = 0x00000008; +pub const NOTE_LINK: u32 = 0x00000010; +pub const NOTE_RENAME: u32 = 0x00000020; +pub const NOTE_REVOKE: u32 = 0x00000040; +pub const NOTE_TRUNCATE: u32 = 0x00000080; +pub const NOTE_EXIT: u32 = 0x80000000; +pub const NOTE_FORK: u32 = 0x40000000; +pub const NOTE_EXEC: u32 = 0x20000000; +pub const NOTE_PDATAMASK: u32 = 0x000fffff; +pub const NOTE_PCTRLMASK: u32 = 0xf0000000; +pub const NOTE_TRACK: u32 = 0x00000001; +pub const NOTE_TRACKERR: u32 = 0x00000002; +pub const NOTE_CHILD: u32 = 0x00000004; +pub const NOTE_CHANGE: u32 = 0x00000001; + +pub const TMP_MAX: c_uint = 0x7fffffff; + +pub const AI_PASSIVE: c_int = 1; +pub const AI_CANONNAME: c_int = 2; +pub const AI_NUMERICHOST: c_int = 4; +pub const AI_EXT: c_int = 8; +pub const AI_NUMERICSERV: c_int = 16; +pub const AI_FQDN: c_int = 32; +pub const AI_ADDRCONFIG: c_int = 64; + +pub const NI_NUMERICHOST: c_int = 1; +pub const NI_NUMERICSERV: c_int = 2; +pub const NI_NOFQDN: c_int = 4; +pub const NI_NAMEREQD: c_int = 8; +pub const NI_DGRAM: c_int = 16; + +pub const NI_MAXHOST: size_t = 256; + +pub const RTLD_LOCAL: c_int = 0; + +pub const CTL_MAXNAME: c_int = 12; + +pub const CTLTYPE_NODE: c_int = 1; +pub const CTLTYPE_INT: c_int = 2; +pub const CTLTYPE_STRING: c_int = 3; +pub const CTLTYPE_QUAD: c_int = 4; +pub const CTLTYPE_STRUCT: c_int = 5; + +pub const CTL_UNSPEC: c_int = 0; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_FS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_DDB: c_int = 9; +pub const CTL_VFS: c_int = 10; +pub const CTL_MAXID: c_int = 11; + +pub const HW_NCPUONLINE: c_int = 25; + +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_PROF: c_int = 16; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_BOOTTIME: c_int = 21; +pub const KERN_DOMAINNAME: c_int = 22; +pub const KERN_MAXPARTITIONS: c_int = 23; +pub const KERN_RAWPARTITION: c_int = 24; +pub const KERN_MAXTHREAD: c_int = 25; +pub const KERN_NTHREADS: c_int = 26; +pub const KERN_OSVERSION: c_int = 27; +pub const KERN_SOMAXCONN: c_int = 28; +pub const KERN_SOMINCONN: c_int = 29; +#[deprecated(since = "0.2.71", note = "Removed in OpenBSD 6.0")] +pub const KERN_USERMOUNT: c_int = 30; +pub const KERN_NOSUIDCOREDUMP: c_int = 32; +pub const KERN_FSYNC: c_int = 33; +pub const KERN_SYSVMSG: c_int = 34; +pub const KERN_SYSVSEM: c_int = 35; +pub const KERN_SYSVSHM: c_int = 36; +#[deprecated(since = "0.2.71", note = "Removed in OpenBSD 6.0")] +pub const KERN_ARND: c_int = 37; +pub const KERN_MSGBUFSIZE: c_int = 38; +pub const KERN_MALLOCSTATS: c_int = 39; +pub const KERN_CPTIME: c_int = 40; +pub const KERN_NCHSTATS: c_int = 41; +pub const KERN_FORKSTAT: c_int = 42; +pub const KERN_NSELCOLL: c_int = 43; +pub const KERN_TTY: c_int = 44; +pub const KERN_CCPU: c_int = 45; +pub const KERN_FSCALE: c_int = 46; +pub const KERN_NPROCS: c_int = 47; +pub const KERN_MSGBUF: c_int = 48; +pub const KERN_POOL: c_int = 49; +pub const KERN_STACKGAPRANDOM: c_int = 50; +pub const KERN_SYSVIPC_INFO: c_int = 51; +pub const KERN_SPLASSERT: c_int = 54; +pub const KERN_PROC_ARGS: c_int = 55; +pub const KERN_NFILES: c_int = 56; +pub const KERN_TTYCOUNT: c_int = 57; +pub const KERN_NUMVNODES: c_int = 58; +pub const KERN_MBSTAT: c_int = 59; +pub const KERN_SEMINFO: c_int = 61; +pub const KERN_SHMINFO: c_int = 62; +pub const KERN_INTRCNT: c_int = 63; +pub const KERN_WATCHDOG: c_int = 64; +pub const KERN_PROC: c_int = 66; +pub const KERN_MAXCLUSTERS: c_int = 67; +pub const KERN_EVCOUNT: c_int = 68; +pub const KERN_TIMECOUNTER: c_int = 69; +pub const KERN_MAXLOCKSPERUID: c_int = 70; +pub const KERN_CPTIME2: c_int = 71; +pub const KERN_CACHEPCT: c_int = 72; +pub const KERN_FILE: c_int = 73; +pub const KERN_CONSDEV: c_int = 75; +pub const KERN_NETLIVELOCKS: c_int = 76; +pub const KERN_POOL_DEBUG: c_int = 77; +pub const KERN_PROC_CWD: c_int = 78; +pub const KERN_PROC_NOBROADCASTKILL: c_int = 79; +pub const KERN_PROC_VMMAP: c_int = 80; +pub const KERN_GLOBAL_PTRACE: c_int = 81; +pub const KERN_CONSBUFSIZE: c_int = 82; +pub const KERN_CONSBUF: c_int = 83; +pub const KERN_AUDIO: c_int = 84; +pub const KERN_CPUSTATS: c_int = 85; +pub const KERN_PFSTATUS: c_int = 86; +pub const KERN_TIMEOUT_STATS: c_int = 87; +#[deprecated( + since = "0.2.95", + note = "Possibly increasing over the releases and might not be so used in the field" +)] +pub const KERN_MAXID: c_int = 88; + +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_KTHREAD: c_int = 7; +pub const KERN_PROC_SHOW_THREADS: c_int = 0x40000000; + +pub const KERN_SYSVIPC_MSG_INFO: c_int = 1; +pub const KERN_SYSVIPC_SEM_INFO: c_int = 2; +pub const KERN_SYSVIPC_SHM_INFO: c_int = 3; + +pub const KERN_PROC_ARGV: c_int = 1; +pub const KERN_PROC_NARGV: c_int = 2; +pub const KERN_PROC_ENV: c_int = 3; +pub const KERN_PROC_NENV: c_int = 4; + +pub const KI_NGROUPS: c_int = 16; +pub const KI_MAXCOMLEN: c_int = 24; +pub const KI_WMESGLEN: c_int = 8; +pub const KI_MAXLOGNAME: c_int = 32; +pub const KI_EMULNAMELEN: c_int = 8; + +pub const KVE_ET_OBJ: c_int = 0x00000001; +pub const KVE_ET_SUBMAP: c_int = 0x00000002; +pub const KVE_ET_COPYONWRITE: c_int = 0x00000004; +pub const KVE_ET_NEEDSCOPY: c_int = 0x00000008; +pub const KVE_ET_HOLE: c_int = 0x00000010; +pub const KVE_ET_NOFAULT: c_int = 0x00000020; +pub const KVE_ET_STACK: c_int = 0x00000040; +pub const KVE_ET_WC: c_int = 0x000000080; +pub const KVE_ET_CONCEAL: c_int = 0x000000100; +pub const KVE_ET_SYSCALL: c_int = 0x000000200; +pub const KVE_ET_FREEMAPPED: c_int = 0x000000800; + +pub const KVE_PROT_NONE: c_int = 0x00000000; +pub const KVE_PROT_READ: c_int = 0x00000001; +pub const KVE_PROT_WRITE: c_int = 0x00000002; +pub const KVE_PROT_EXEC: c_int = 0x00000004; + +pub const KVE_ADV_NORMAL: c_int = 0x00000000; +pub const KVE_ADV_RANDOM: c_int = 0x00000001; +pub const KVE_ADV_SEQUENTIAL: c_int = 0x00000002; + +pub const KVE_INH_SHARE: c_int = 0x00000000; +pub const KVE_INH_COPY: c_int = 0x00000010; +pub const KVE_INH_NONE: c_int = 0x00000020; +pub const KVE_INH_ZERO: c_int = 0x00000030; + +pub const KVE_F_STATIC: c_int = 0x1; +pub const KVE_F_KMEM: c_int = 0x2; + +pub const KERN_FILE_BYFILE: c_int = 1; +pub const KERN_FILE_BYPID: c_int = 2; +pub const KERN_FILE_BYUID: c_int = 3; +pub const KERN_FILESLOP: c_int = 10; + +pub const KERN_FILE_TEXT: c_int = -1; +pub const KERN_FILE_CDIR: c_int = -2; +pub const KERN_FILE_RDIR: c_int = -3; +pub const KERN_FILE_TRACE: c_int = -4; + +pub const KI_MNAMELEN: c_int = 96; +pub const KI_UNPPATHLEN: c_int = 104; + +pub const CHWFLOW: crate::tcflag_t = crate::MDMBUF | crate::CRTSCTS; +pub const OLCUC: crate::tcflag_t = 0x20; +pub const ONOCR: crate::tcflag_t = 0x40; +pub const ONLRET: crate::tcflag_t = 0x80; + +//https://github.com/openbsd/src/blob/HEAD/sys/sys/mount.h +pub const ISOFSMNT_NORRIP: c_int = 0x1; // disable Rock Ridge Ext +pub const ISOFSMNT_GENS: c_int = 0x2; // enable generation numbers +pub const ISOFSMNT_EXTATT: c_int = 0x4; // enable extended attr +pub const ISOFSMNT_NOJOLIET: c_int = 0x8; // disable Joliet Ext +pub const ISOFSMNT_SESS: c_int = 0x10; // use iso_args.sess + +pub const NFS_ARGSVERSION: c_int = 4; // change when nfs_args changes + +pub const NFSMNT_RESVPORT: c_int = 0; // always use reserved ports +pub const NFSMNT_SOFT: c_int = 0x1; // soft mount (hard is default) +pub const NFSMNT_WSIZE: c_int = 0x2; // set write size +pub const NFSMNT_RSIZE: c_int = 0x4; // set read size +pub const NFSMNT_TIMEO: c_int = 0x8; // set initial timeout +pub const NFSMNT_RETRANS: c_int = 0x10; // set number of request retries +pub const NFSMNT_MAXGRPS: c_int = 0x20; // set maximum grouplist size +pub const NFSMNT_INT: c_int = 0x40; // allow interrupts on hard mount +pub const NFSMNT_NOCONN: c_int = 0x80; // Don't Connect the socket +pub const NFSMNT_NQNFS: c_int = 0x100; // Use Nqnfs protocol +pub const NFSMNT_NFSV3: c_int = 0x200; // Use NFS Version 3 protocol +pub const NFSMNT_KERB: c_int = 0x400; // Use Kerberos authentication +pub const NFSMNT_DUMBTIMR: c_int = 0x800; // Don't estimate rtt dynamically +pub const NFSMNT_LEASETERM: c_int = 0x1000; // set lease term (nqnfs) +pub const NFSMNT_READAHEAD: c_int = 0x2000; // set read ahead +pub const NFSMNT_DEADTHRESH: c_int = 0x4000; // set dead server retry thresh +pub const NFSMNT_NOAC: c_int = 0x8000; // disable attribute cache +pub const NFSMNT_RDIRPLUS: c_int = 0x10000; // Use Readdirplus for V3 +pub const NFSMNT_READDIRSIZE: c_int = 0x20000; // Set readdir size + +/* Flags valid only in mount syscall arguments */ +pub const NFSMNT_ACREGMIN: c_int = 0x40000; // acregmin field valid +pub const NFSMNT_ACREGMAX: c_int = 0x80000; // acregmax field valid +pub const NFSMNT_ACDIRMIN: c_int = 0x100000; // acdirmin field valid +pub const NFSMNT_ACDIRMAX: c_int = 0x200000; // acdirmax field valid + +/* Flags valid only in kernel */ +pub const NFSMNT_INTERNAL: c_int = 0xfffc0000; // Bits set internally +pub const NFSMNT_HASWRITEVERF: c_int = 0x40000; // Has write verifier for V3 +pub const NFSMNT_GOTPATHCONF: c_int = 0x80000; // Got the V3 pathconf info +pub const NFSMNT_GOTFSINFO: c_int = 0x100000; // Got the V3 fsinfo +pub const NFSMNT_MNTD: c_int = 0x200000; // Mnt server for mnt point +pub const NFSMNT_DISMINPROG: c_int = 0x400000; // Dismount in progress +pub const NFSMNT_DISMNT: c_int = 0x800000; // Dismounted +pub const NFSMNT_SNDLOCK: c_int = 0x1000000; // Send socket lock +pub const NFSMNT_WANTSND: c_int = 0x2000000; // Want above +pub const NFSMNT_RCVLOCK: c_int = 0x4000000; // Rcv socket lock +pub const NFSMNT_WANTRCV: c_int = 0x8000000; // Want above +pub const NFSMNT_WAITAUTH: c_int = 0x10000000; // Wait for authentication +pub const NFSMNT_HASAUTH: c_int = 0x20000000; // Has authenticator +pub const NFSMNT_WANTAUTH: c_int = 0x40000000; // Wants an authenticator +pub const NFSMNT_AUTHERR: c_int = 0x80000000; // Authentication error + +pub const MSDOSFSMNT_SHORTNAME: c_int = 0x1; // Force old DOS short names only +pub const MSDOSFSMNT_LONGNAME: c_int = 0x2; // Force Win'95 long names +pub const MSDOSFSMNT_NOWIN95: c_int = 0x4; // Completely ignore Win95 entries + +pub const NTFS_MFLAG_CASEINS: c_int = 0x1; +pub const NTFS_MFLAG_ALLNAMES: c_int = 0x2; + +pub const TMPFS_ARGS_VERSION: c_int = 1; + +const SI_MAXSZ: size_t = 128; +const SI_PAD: size_t = (SI_MAXSZ / size_of::()) - 3; + +pub const MAP_STACK: c_int = 0x4000; +pub const MAP_CONCEAL: c_int = 0x8000; + +// https://github.com/openbsd/src/blob/f8a2f73b6503213f5eb24ca315ac7e1f9421c0c9/sys/net/if.h#L135 +pub const LINK_STATE_UNKNOWN: c_int = 0; // link unknown +pub const LINK_STATE_INVALID: c_int = 1; // link invalid +pub const LINK_STATE_DOWN: c_int = 2; // link is down +pub const LINK_STATE_KALIVE_DOWN: c_int = 3; // keepalive reports down +pub const LINK_STATE_UP: c_int = 4; // link is up +pub const LINK_STATE_HALF_DUPLEX: c_int = 5; // link is up and half duplex +pub const LINK_STATE_FULL_DUPLEX: c_int = 6; // link is up and full duplex + +// https://github.com/openbsd/src/blob/HEAD/sys/net/if.h#L187 +pub const IFF_UP: c_int = 0x1; // interface is up +pub const IFF_BROADCAST: c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x10; // interface is point-to-point link +pub const IFF_STATICARP: c_int = 0x20; // only static ARP +pub const IFF_RUNNING: c_int = 0x40; // resources allocated +pub const IFF_NOARP: c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE: c_int = 0x400; // transmission in progress +pub const IFF_SIMPLEX: c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; // per link layer defined bit +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + +pub const PTHREAD_STACK_MIN: size_t = 1_usize << _MAX_PAGE_SHIFT; +pub const MINSIGSTKSZ: size_t = 3_usize << _MAX_PAGE_SHIFT; +pub const SIGSTKSZ: size_t = MINSIGSTKSZ + (1_usize << _MAX_PAGE_SHIFT) * 4; + +pub const PT_SET_EVENT_MASK: c_int = 12; +pub const PT_GET_EVENT_MASK: c_int = 13; +pub const PT_GET_PROCESS_STATE: c_int = 14; +pub const PT_GET_THREAD_FIRST: c_int = 15; +pub const PT_GET_THREAD_NEXT: c_int = 16; +pub const PT_FIRSTMACH: c_int = 32; + +pub const PT_PTS_NAMELEN: c_int = 32; + +pub const SOCK_CLOEXEC: c_int = 0x8000; +pub const SOCK_NONBLOCK: c_int = 0x4000; +pub const SOCK_DNS: c_int = 0x1000; + +pub const BIOCGRSIG: c_ulong = 0x40044273; +pub const BIOCSRSIG: c_ulong = 0x80044272; +pub const BIOCSDLT: c_ulong = 0x8004427a; + +pub const PTRACE_FORK: c_int = 0x0002; + +pub const WCONTINUED: c_int = 0x08; +pub const WEXITED: c_int = 0x04; +pub const WSTOPPED: c_int = 0x02; // same as WUNTRACED +pub const WNOWAIT: c_int = 0x10; +pub const WTRAPPED: c_int = 0x20; + +pub const P_ALL: crate::idtype_t = 0; +pub const P_PGID: crate::idtype_t = 1; +pub const P_PID: crate::idtype_t = 2; + +// search.h +pub const FIND: crate::ACTION = 0; +pub const ENTER: crate::ACTION = 1; + +// futex.h +pub const FUTEX_WAIT: c_int = 1; +pub const FUTEX_WAKE: c_int = 2; +pub const FUTEX_REQUEUE: c_int = 3; +pub const FUTEX_PRIVATE_FLAG: c_int = 128; + +// sys/file.h +pub const DTYPE_VNODE: c_int = 1; +pub const DTYPE_SOCKET: c_int = 2; +pub const DTYPE_PIPE: c_int = 3; +pub const DTYPE_KQUEUE: c_int = 4; +pub const DTYPE_DMABUF: c_int = 5; +pub const DTYPE_SYNC: c_int = 6; + +// sysctl.h, kinfo_proc p_eflag constants +pub const EPROC_CTTY: i32 = 0x01; // controlling tty vnode active +pub const EPROC_SLEADER: i32 = 0x02; // session leader +pub const EPROC_UNVEIL: i32 = 0x04; // has unveil settings +pub const EPROC_LKUNVEIL: i32 = 0x08; // unveil is locked + +// Flags for chflags(2) +pub const UF_SETTABLE: c_uint = 0x0000ffff; +pub const UF_NODUMP: c_uint = 0x00000001; +pub const UF_IMMUTABLE: c_uint = 0x00000002; +pub const UF_APPEND: c_uint = 0x00000004; +pub const UF_OPAQUE: c_uint = 0x00000008; +pub const SF_SETTABLE: c_uint = 0xffff0000; +pub const SF_ARCHIVED: c_uint = 0x00010000; +pub const SF_IMMUTABLE: c_uint = 0x00020000; +pub const SF_APPEND: c_uint = 0x00040000; + +// sys/exec_elf.h - Legal values for p_type (segment type). +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_HIOS: u32 = 0x6fffffff; +pub const PT_LOPROC: u32 = 0x70000000; +pub const PT_HIPROC: u32 = 0x7fffffff; + +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_RELRO: u32 = 0x6474e552; + +// sys/exec_elf.h - Legal values for p_flags (segment flags). +pub const PF_X: u32 = 0x1; +pub const PF_W: u32 = 0x2; +pub const PF_R: u32 = 0x4; +pub const PF_MASKOS: u32 = 0x0ff00000; +pub const PF_MASKPROC: u32 = 0xf0000000; + +// sys/ioccom.h +pub const fn IOCPARM_LEN(x: u32) -> u32 { + (x >> 16) & crate::IOCPARM_MASK +} + +pub const fn IOCBASECMD(x: u32) -> u32 { + x & (!(crate::IOCPARM_MASK << 16)) +} + +pub const fn IOCGROUP(x: u32) -> u32 { + (x >> 8) & 0xff +} + +pub const fn _IOC(inout: c_ulong, group: c_ulong, num: c_ulong, len: c_ulong) -> c_ulong { + (inout) | (((len) & crate::IOCPARM_MASK as c_ulong) << 16) | ((group) << 8) | (num) +} + +// sys/mount.h +pub const MNT_NOPERM: c_int = 0x00000020; +pub const MNT_WXALLOWED: c_int = 0x00000800; +pub const MNT_EXRDONLY: c_int = 0x00000080; +pub const MNT_DEFEXPORTED: c_int = 0x00000200; +pub const MNT_EXPORTANON: c_int = 0x00000400; +pub const MNT_ROOTFS: c_int = 0x00004000; +pub const MNT_NOATIME: c_int = 0x00008000; +pub const MNT_DELEXPORT: c_int = 0x00020000; +pub const MNT_STALLED: c_int = 0x00100000; +pub const MNT_SWAPPABLE: c_int = 0x00200000; +pub const MNT_WANTRDWR: c_int = 0x02000000; +pub const MNT_SOFTDEP: c_int = 0x04000000; +pub const MNT_DOOMED: c_int = 0x08000000; + +// For use with vfs_fsync and getfsstat +pub const MNT_WAIT: c_int = 1; +pub const MNT_NOWAIT: c_int = 2; +pub const MNT_LAZY: c_int = 3; + +// sys/_time.h +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 4; +pub const CLOCK_UPTIME: crate::clockid_t = 5; +pub const CLOCK_BOOTTIME: crate::clockid_t = 6; + +pub const LC_COLLATE_MASK: c_int = 1 << crate::LC_COLLATE; +pub const LC_CTYPE_MASK: c_int = 1 << crate::LC_CTYPE; +pub const LC_MONETARY_MASK: c_int = 1 << crate::LC_MONETARY; +pub const LC_NUMERIC_MASK: c_int = 1 << crate::LC_NUMERIC; +pub const LC_TIME_MASK: c_int = 1 << crate::LC_TIME; +pub const LC_MESSAGES_MASK: c_int = 1 << crate::LC_MESSAGES; + +const _LC_LAST: c_int = 7; +pub const LC_ALL_MASK: c_int = (1 << _LC_LAST) - 2; + +pub const LC_GLOBAL_LOCALE: crate::locale_t = -1isize as crate::locale_t; + +// sys/reboot.h +pub const RB_ASKNAME: c_int = 0x00001; +pub const RB_SINGLE: c_int = 0x00002; +pub const RB_NOSYNC: c_int = 0x00004; +pub const RB_HALT: c_int = 0x00008; +pub const RB_INITNAME: c_int = 0x00010; +pub const RB_KDB: c_int = 0x00040; +pub const RB_RDONLY: c_int = 0x00080; +pub const RB_DUMP: c_int = 0x00100; +pub const RB_MINIROOT: c_int = 0x00200; +pub const RB_CONFIG: c_int = 0x00400; +pub const RB_TIMEBAD: c_int = 0x00800; +pub const RB_POWERDOWN: c_int = 0x01000; +pub const RB_SERCONS: c_int = 0x02000; +pub const RB_USERREQ: c_int = 0x04000; +pub const RB_RESET: c_int = 0x08000; +pub const RB_GOODRANDOM: c_int = 0x10000; +pub const RB_UNHIBERNATE: c_int = 0x20000; + +// net/route.h +pub const RTF_CLONING: c_int = 0x100; +pub const RTF_MULTICAST: c_int = 0x200; +pub const RTF_LLINFO: c_int = 0x400; +pub const RTF_PROTO3: c_int = 0x2000; +pub const RTF_ANNOUNCE: c_int = crate::RTF_PROTO2; + +pub const RTF_CLONED: c_int = 0x10000; +pub const RTF_CACHED: c_int = 0x20000; +pub const RTF_MPATH: c_int = 0x40000; +pub const RTF_MPLS: c_int = 0x100000; +pub const RTF_LOCAL: c_int = 0x200000; +pub const RTF_BROADCAST: c_int = 0x400000; +pub const RTF_CONNECTED: c_int = 0x800000; +pub const RTF_BFD: c_int = 0x1000000; +pub const RTF_FMASK: c_int = crate::RTF_LLINFO + | crate::RTF_PROTO1 + | crate::RTF_PROTO2 + | crate::RTF_PROTO3 + | crate::RTF_BLACKHOLE + | crate::RTF_REJECT + | crate::RTF_STATIC + | crate::RTF_MPLS + | crate::RTF_BFD; + +pub const RTM_VERSION: c_int = 5; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_IFANNOUNCE: c_int = 0xf; +pub const RTM_DESYNC: c_int = 0x10; +pub const RTM_INVALIDATE: c_int = 0x11; +pub const RTM_BFD: c_int = 0x12; +pub const RTM_PROPOSAL: c_int = 0x13; +pub const RTM_CHGADDRATTR: c_int = 0x14; +pub const RTM_80211INFO: c_int = 0x15; +pub const RTM_SOURCE: c_int = 0x16; + +pub const RTA_SRC: c_int = 0x100; +pub const RTA_SRCMASK: c_int = 0x200; +pub const RTA_LABEL: c_int = 0x400; +pub const RTA_BFD: c_int = 0x800; +pub const RTA_DNS: c_int = 0x1000; +pub const RTA_STATIC: c_int = 0x2000; +pub const RTA_SEARCH: c_int = 0x4000; + +pub const RTAX_SRC: c_int = 8; +pub const RTAX_SRCMASK: c_int = 9; +pub const RTAX_LABEL: c_int = 10; +pub const RTAX_BFD: c_int = 11; +pub const RTAX_DNS: c_int = 12; +pub const RTAX_STATIC: c_int = 13; +pub const RTAX_SEARCH: c_int = 14; +pub const RTAX_MAX: c_int = 15; + +const fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + _ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + _ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next > max { + core::ptr::null_mut::() + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (_ALIGN(size_of::()) + _ALIGN(length as usize)) as c_uint + } +} + +safe_f! { + pub const fn WSTOPSIG(status: c_int) -> c_int { + status >> 8 + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0o177 + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + (status & 0o177777) == 0o177777 + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major & 0xff) << 8; + dev |= minor & 0xff; + dev |= (minor & 0xffff00) << 8; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + ((dev as c_uint) >> 8) & 0xff + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + let dev = dev as c_uint; + let mut res = 0; + res |= (dev) & 0xff; + res |= ((dev) & 0xffff0000) >> 8; + res + } +} + +extern "C" { + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn settimeofday(tp: *const crate::timeval, tz: *const crate::timezone) -> c_int; + pub fn pledge(promises: *const c_char, execpromises: *const c_char) -> c_int; + pub fn unveil(path: *const c_char, permissions: *const c_char) -> c_int; + pub fn strtonum( + nptr: *const c_char, + minval: c_longlong, + maxval: c_longlong, + errstr: *mut *const c_char, + ) -> c_longlong; + pub fn dup3(src: c_int, dst: c_int, flags: c_int) -> c_int; + pub fn chflags(path: *const c_char, flags: c_uint) -> c_int; + pub fn fchflags(fd: c_int, flags: c_uint) -> c_int; + pub fn chflagsat(fd: c_int, path: *const c_char, flags: c_uint, atflag: c_int) -> c_int; + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: size_t, + serv: *mut c_char, + servlen: size_t, + flags: c_int, + ) -> c_int; + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + pub fn kevent( + kq: c_int, + changelist: *const crate::kevent, + nchanges: c_int, + eventlist: *mut crate::kevent, + nevents: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn getthrid() -> crate::pid_t; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_main_np() -> c_int; + pub fn pthread_get_name_np(tid: crate::pthread_t, name: *mut c_char, len: size_t); + pub fn pthread_set_name_np(tid: crate::pthread_t, name: *const c_char); + pub fn pthread_stackseg_np(thread: crate::pthread_t, sinfo: *mut crate::stack_t) -> c_int; + + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *const crate::termios, + winp: *const crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *const crate::termios, + winp: *const crate::winsize, + ) -> crate::pid_t; + + pub fn sysctl( + name: *const c_int, + namelen: c_uint, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + pub fn ptrace(request: c_int, pid: crate::pid_t, addr: caddr_t, data: c_int) -> c_int; + pub fn utrace(label: *const c_char, addr: *const c_void, len: size_t) -> c_int; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + // #include + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + + // Added in `OpenBSD` 5.5 + pub fn explicit_bzero(s: *mut c_void, len: size_t); + + pub fn setproctitle(fmt: *const c_char, ...); + + pub fn freezero(ptr: *mut c_void, size: size_t); + pub fn malloc_conceal(size: size_t) -> *mut c_void; + pub fn calloc_conceal(nmemb: size_t, size: size_t) -> *mut c_void; + + pub fn srand48_deterministic(seed: c_long); + pub fn seed48_deterministic(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn lcong48_deterministic(p: *mut c_ushort); + + pub fn lsearch( + key: *const c_void, + base: *mut c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + pub fn lfind( + key: *const c_void, + base: *const c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + pub fn hcreate(nelt: size_t) -> c_int; + pub fn hdestroy(); + pub fn hsearch(entry: crate::ENTRY, action: crate::ACTION) -> *mut crate::ENTRY; + + // futex.h + pub fn futex( + uaddr: *mut u32, + op: c_int, + val: c_int, + timeout: *const crate::timespec, + uaddr2: *mut u32, + ) -> c_int; + + pub fn mimmutable(addr: *mut c_void, len: size_t) -> c_int; + + pub fn reboot(mode: c_int) -> c_int; + + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn getmntinfo(mntbufp: *mut *mut crate::statfs, flags: c_int) -> c_int; + pub fn getfsstat(buf: *mut statfs, bufsize: size_t, flags: c_int) -> c_int; + + pub fn elf_aux_info(aux: c_int, buf: *mut c_void, buflen: c_int) -> c_int; +} + +#[link(name = "execinfo")] +extern "C" { + pub fn backtrace(addrlist: *mut *mut c_void, len: size_t) -> size_t; + pub fn backtrace_symbols(addrlist: *const *mut c_void, len: size_t) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(addrlist: *const *mut c_void, len: size_t, fd: c_int) -> c_int; + pub fn backtrace_symbols_fmt( + addrlist: *const *mut c_void, + len: size_t, + fmt: *const c_char, + ) -> *mut *mut c_char; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "mips64")] { + mod mips64; + pub use self::mips64::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "powerpc64")] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } else if #[cfg(target_arch = "sparc64")] { + mod sparc64; + pub use self::sparc64::*; + } else if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc.rs new file mode 100644 index 00000000000000..8b3f72139d86e9 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc.rs @@ -0,0 +1,5 @@ +use crate::prelude::*; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc64.rs new file mode 100644 index 00000000000000..5ebe85741454ee --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/powerpc64.rs @@ -0,0 +1,5 @@ +use crate::prelude::*; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/riscv64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/riscv64.rs new file mode 100644 index 00000000000000..e0ecf2ac28b50c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/riscv64.rs @@ -0,0 +1,25 @@ +use crate::prelude::*; + +pub type ucontext_t = sigcontext; + +s! { + pub struct sigcontext { + __sc_unused: Padding, + pub sc_mask: c_int, + pub sc_ra: c_long, + pub sc_sp: c_long, + pub sc_gp: c_long, + pub sc_tp: c_long, + pub sc_t: [c_long; 7], + pub sc_s: [c_long; 12], + pub sc_a: [c_long; 8], + pub sc_sepc: c_long, + pub sc_f: [c_long; 32], + pub sc_fcsr: c_long, + pub sc_cookie: c_long, + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/sparc64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/sparc64.rs new file mode 100644 index 00000000000000..88481f4f014e81 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/sparc64.rs @@ -0,0 +1,4 @@ +#[doc(hidden)] +pub const _ALIGNBYTES: usize = 0xf; + +pub const _MAX_PAGE_SHIFT: u32 = 13; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86.rs new file mode 100644 index 00000000000000..97dc58327d2226 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86.rs @@ -0,0 +1,5 @@ +use crate::prelude::*; + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; diff --git a/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86_64.rs b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86_64.rs new file mode 100644 index 00000000000000..74889a743b9aac --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/bsd/netbsdlike/openbsd/x86_64.rs @@ -0,0 +1,65 @@ +use crate::prelude::*; +use crate::PT_FIRSTMACH; + +pub type ucontext_t = sigcontext; + +s! { + pub struct sigcontext { + pub sc_rdi: c_long, + pub sc_rsi: c_long, + pub sc_rdx: c_long, + pub sc_rcx: c_long, + pub sc_r8: c_long, + pub sc_r9: c_long, + pub sc_r10: c_long, + pub sc_r11: c_long, + pub sc_r12: c_long, + pub sc_r13: c_long, + pub sc_r14: c_long, + pub sc_r15: c_long, + pub sc_rbp: c_long, + pub sc_rbx: c_long, + pub sc_rax: c_long, + pub sc_gs: c_long, + pub sc_fs: c_long, + pub sc_es: c_long, + pub sc_ds: c_long, + pub sc_trapno: c_long, + pub sc_err: c_long, + pub sc_rip: c_long, + pub sc_cs: c_long, + pub sc_rflags: c_long, + pub sc_rsp: c_long, + pub sc_ss: c_long, + pub sc_fpstate: *mut fxsave64, + __sc_unused: Padding, + pub sc_mask: c_int, + pub sc_cookie: c_long, + } + + #[repr(packed)] + pub struct fxsave64 { + pub fx_fcw: u16, + pub fx_fsw: u16, + pub fx_ftw: u8, + __fx_unused1: Padding, + pub fx_fop: u16, + pub fx_rip: u64, + pub fx_rdp: u64, + pub fx_mxcsr: u32, + pub fx_mxcsr_mask: u32, + pub fx_st: [[u64; 2]; 8], + pub fx_xmm: [[u64; 2]; 16], + __fx_unused3: Padding<[u8; 96]>, + } +} + +pub(crate) const _ALIGNBYTES: usize = size_of::() - 1; + +pub const _MAX_PAGE_SHIFT: u32 = 12; + +pub const PT_STEP: c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: c_int = PT_FIRSTMACH + 4; diff --git a/deps/crates/vendor/libc/src/unix/cygwin/mod.rs b/deps/crates/vendor/libc/src/unix/cygwin/mod.rs new file mode 100644 index 00000000000000..0c093a4c17726f --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/cygwin/mod.rs @@ -0,0 +1,2389 @@ +use crate::prelude::*; +use crate::*; + +pub type wchar_t = c_ushort; + +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type dev_t = u32; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = u64; +pub type key_t = c_longlong; +pub type sa_family_t = u16; +pub type socklen_t = c_int; + +pub type off_t = c_long; +pub type id_t = u32; +pub type mode_t = u32; +pub type _off64_t = c_longlong; +pub type loff_t = _off64_t; +pub type iconv_t = *mut c_void; +pub type clock_t = c_ulong; +pub type time_t = c_long; +pub type clockid_t = c_ulong; +pub type timer_t = c_ulong; +pub type nl_item = c_int; +pub type nlink_t = c_ushort; +pub type suseconds_t = c_long; +pub type useconds_t = c_ulong; + +extern_ty! { + pub enum timezone {} +} + +pub type sigset_t = c_ulong; + +pub type fd_mask = c_ulong; + +pub type pthread_t = *mut c_void; +pub type pthread_mutex_t = *mut c_void; + +// Must be usize due to libstd/sys_common/thread_local.rs, +// should technically be *mut c_void +pub type pthread_key_t = usize; + +pub type pthread_attr_t = *mut c_void; +pub type pthread_mutexattr_t = *mut c_void; +pub type pthread_condattr_t = *mut c_void; +pub type pthread_cond_t = *mut c_void; + +// The following ones should be *mut c_void +pub type pthread_barrierattr_t = usize; +pub type pthread_barrier_t = usize; +pub type pthread_spinlock_t = usize; + +pub type pthread_rwlock_t = *mut c_void; +pub type pthread_rwlockattr_t = *mut c_void; + +pub type register_t = intptr_t; +pub type u_char = c_uchar; +pub type u_short = c_ushort; +pub type u_long = c_ulong; +pub type u_int = c_uint; +pub type caddr_t = *mut c_char; +pub type vm_size_t = c_ulong; + +pub type rlim_t = c_ulong; + +pub type nfds_t = c_uint; + +pub type sem_t = *mut sem; + +extern_ty! { + pub enum sem {} +} + +pub type tcflag_t = c_uint; +pub type speed_t = c_uint; + +pub type vm_offset_t = c_ulong; + +pub type posix_spawn_file_actions_t = *mut c_void; +pub type posix_spawnattr_t = *mut c_void; + +s! { + pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, + } + + pub struct cpu_set_t { + bits: [u64; 16], + } + + pub struct sigaction { + pub sa_sigaction: sighandler_t, + pub sa_mask: sigset_t, + pub sa_flags: c_int, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + pub struct bintime { + pub sec: time_t, + pub frac: u64, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: uid_t, + pub pw_gid: gid_t, + pub pw_comment: *mut c_char, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + pub struct ucred { + pub pid: pid_t, + pub uid: uid_t, + pub gid: gid_t, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct Dl_info { + pub dli_fname: [c_char; PATH_MAX as usize], + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct in6_pktinfo { + pub ipi6_addr: in6_addr, + pub ipi6_ifindex: u32, + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_sourceaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + } + + pub struct termios { + pub c_iflag: tcflag_t, + pub c_oflag: tcflag_t, + pub c_cflag: tcflag_t, + pub c_lflag: tcflag_t, + pub c_line: c_char, + pub c_cc: [cc_t; NCCS], + pub c_ispeed: speed_t, + pub c_ospeed: speed_t, + } + + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: pid_t, + } + + pub struct hostent { + pub h_name: *const c_char, + pub h_aliases: *mut *mut c_char, + pub h_addrtype: c_short, + pub h_length: c_short, + pub h_addr_list: *mut *mut c_char, + } + + pub struct linger { + pub l_onoff: c_ushort, + pub l_linger: c_ushort, + } + + pub struct fd_set { + fds_bits: [fd_mask; FD_SETSIZE / size_of::() / 8], + } + + pub struct _uc_fpxreg { + pub significand: [u16; 4], + pub exponent: u16, + padding: Padding<[u16; 3]>, + } + + pub struct _uc_xmmreg { + pub element: [u32; 4], + } + + pub struct _fpstate { + pub cwd: u16, + pub swd: u16, + pub ftw: u16, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcr_mask: u32, + pub st: [_uc_fpxreg; 8], + pub xmm: [_uc_xmmreg; 16], + padding: Padding<[u32; 24]>, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub p1home: u64, + pub p2home: u64, + pub p3home: u64, + pub p4home: u64, + pub p5home: u64, + pub p6home: u64, + pub ctxflags: u32, + pub mxcsr: u32, + pub cs: u16, + pub ds: u16, + pub es: u16, + pub fs: u16, + pub gs: u16, + pub ss: u16, + pub eflags: u32, + pub dr0: u64, + pub dr1: u64, + pub dr2: u64, + pub dr3: u64, + pub dr6: u64, + pub dr7: u64, + pub rax: u64, + pub rcx: u64, + pub rdx: u64, + pub rbx: u64, + pub rsp: u64, + pub rbp: u64, + pub rsi: u64, + pub rdi: u64, + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, + pub rip: u64, + pub fpregs: _fpstate, + pub vregs: [u64; 52], + pub vcx: u64, + pub dbc: u64, + pub btr: u64, + pub bfr: u64, + pub etr: u64, + pub efr: u64, + pub oldmask: u64, + pub cr2: u64, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigevent { + pub sigev_value: sigval, + pub sigev_signo: c_int, + pub sigev_notify: c_int, + pub sigev_notify_function: Option, + pub sigev_notify_attributes: *mut pthread_attr_t, + } + + #[repr(align(8))] + pub struct ucontext_t { + pub uc_mcontext: mcontext_t, + pub uc_link: *mut ucontext_t, + pub uc_sigmask: sigset_t, + pub uc_stack: stack_t, + pub uc_flags: c_ulong, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_pad1: Padding<[c_char; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[c_char; 112]>, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct in_pktinfo { + pub ipi_addr: in_addr, + pub ipi_ifindex: u32, + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [u8; 8], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: fsblkcnt_t, + pub f_bfree: fsblkcnt_t, + pub f_bavail: fsblkcnt_t, + pub f_files: fsfilcnt_t, + pub f_ffree: fsfilcnt_t, + pub f_favail: fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: c_long, + pub f_bfree: c_long, + pub f_bavail: c_long, + pub f_files: c_long, + pub f_ffree: c_long, + pub f_fsid: c_long, + pub f_namelen: c_long, + pub f_spare: [c_long; 6], + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct utsname { + pub sysname: [c_char; 66], + pub nodename: [c_char; 65], + pub release: [c_char; 65], + pub version: [c_char; 65], + pub machine: [c_char; 65], + pub domainname: [c_char; 65], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_pid: pid_t, + pub si_uid: uid_t, + pub si_errno: c_int, + __pad: Padding<[u32; 32]>, + } + + pub struct dirent { + __d_version: u32, + pub d_ino: ino_t, + pub d_type: c_uchar, + __d_unused1: Padding<[c_uchar; 3]>, + __d_internal1: u32, + pub d_name: [c_char; 256], + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } + + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: sockaddr, + pub ifru_broadaddr: sockaddr, + pub ifru_dstaddr: sockaddr, + pub ifru_netmask: sockaddr, + pub ifru_hwaddr: sockaddr, + pub ifru_flags: c_int, + pub ifru_metric: c_int, + pub ifru_mtu: c_int, + pub ifru_ifindex: c_int, + pub ifru_data: *mut c_char, + __ifru_pad: Padding<[c_char; 28]>, + } + + pub struct ifreq { + /// if name, e.g. "en0" + pub ifr_name: [c_char; IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: caddr_t, + pub ifcu_req: *mut ifreq, + } + + pub struct ifconf { + pub ifc_len: c_int, + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } + + pub struct utmpx { + pub ut_type: c_short, + pub ut_pid: pid_t, + pub ut_line: [c_char; UT_LINESIZE], + pub ut_id: [c_char; UT_IDLEN], + pub ut_time: time_t, + pub ut_user: [c_char; UT_NAMESIZE], + pub ut_host: [c_char; UT_HOSTSIZE], + pub ut_addr: c_long, + pub ut_tv: timeval, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_si_addr { + _si_signo: c_int, + _si_code: c_int, + _si_pid: pid_t, + _si_uid: uid_t, + _si_errno: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_si_addr)).si_addr + } + + pub unsafe fn si_status(&self) -> c_int { + #[repr(C)] + struct siginfo_sigchld { + _si_signo: c_int, + _si_code: c_int, + _si_pid: pid_t, + _si_uid: uid_t, + _si_errno: c_int, + si_status: c_int, + } + (*(self as *const siginfo_t as *const siginfo_sigchld)).si_status + } + + pub unsafe fn si_pid(&self) -> pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> uid_t { + self.si_uid + } + + pub unsafe fn si_value(&self) -> sigval { + #[repr(C)] + struct siginfo_si_value { + _si_signo: c_int, + _si_code: c_int, + _si_pid: pid_t, + _si_uid: uid_t, + _si_errno: c_int, + si_value: sigval, + } + (*(self as *const siginfo_t as *const siginfo_si_value)).si_value + } +} + +pub const FD_SETSIZE: usize = 1024; + +pub const CPU_SETSIZE: c_int = 0x400; + +// si_code values for SIGBUS signal +pub const BUS_ADRALN: c_int = 25; +pub const BUS_ADRERR: c_int = 26; +pub const BUS_OBJERR: c_int = 27; + +// si_code values for SIGCHLD signal +pub const CLD_EXITED: c_int = 28; +pub const CLD_KILLED: c_int = 29; +pub const CLD_DUMPED: c_int = 30; +pub const CLD_TRAPPED: c_int = 31; +pub const CLD_STOPPED: c_int = 32; +pub const CLD_CONTINUED: c_int = 33; + +pub const SIGEV_SIGNAL: c_int = 0; +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const SA_NOCLDSTOP: c_int = 0x00000001; +pub const SA_NOCLDWAIT: c_int = 0; // FIXME: does not exist on Cygwin! +pub const SA_SIGINFO: c_int = 0x00000002; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_ONSTACK: c_int = 0x20000000; +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const MINSIGSTKSZ: size_t = 8192; +pub const SIGSTKSZ: size_t = 32768; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGURG: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGIO: c_int = 23; +pub const SIGPOLL: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGPWR: c_int = 29; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; + +pub const SS_ONSTACK: c_int = 0x1; +pub const SS_DISABLE: c_int = 0x2; + +pub const SIG_SETMASK: c_int = 0; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; + +pub const TIMER_ABSTIME: c_int = 4; +pub const CLOCK_REALTIME_COARSE: clockid_t = 0; +pub const CLOCK_REALTIME: clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3; +pub const CLOCK_MONOTONIC: clockid_t = 4; +pub const CLOCK_MONOTONIC_RAW: clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: clockid_t = 6; +pub const CLOCK_BOOTTIME: clockid_t = 7; +pub const CLOCK_REALTIME_ALARM: clockid_t = 8; +pub const CLOCK_BOOTTIME_ALARM: clockid_t = 9; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_NOFILE: c_int = 5; +pub const RLIMIT_AS: c_int = 6; +pub const RLIM_NLIMITS: c_int = 7; +pub const RLIMIT_NLIMITS: c_int = RLIM_NLIMITS; +pub const RLIM_INFINITY: rlim_t = !0; +pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const IFF_UP: c_int = 0x1; // interface is up +pub const IFF_BROADCAST: c_int = 0x2; // broadcast address valid +pub const IFF_LOOPBACK: c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x10; // interface is point-to-point link +pub const IFF_NOTRAILERS: c_int = 0x20; // avoid use of trailers +pub const IFF_RUNNING: c_int = 0x40; // resources allocated +pub const IFF_NOARP: c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x100; // receive all packets +pub const IFF_MULTICAST: c_int = 0x1000; // supports multicast +pub const IFF_LOWER_UP: c_int = 0x10000; // driver signals L1 up +pub const IFF_DORMANT: c_int = 0x20000; // driver signals dormant + +pub const IF_NAMESIZE: size_t = 44; +pub const IFNAMSIZ: size_t = IF_NAMESIZE; + +pub const FIONREAD: c_int = 0x4008667f; +pub const FIONBIO: c_int = 0x8004667e; +pub const FIOASYNC: c_int = 0x8008667d; +pub const FIOCLEX: c_int = 0; // FIXME: does not exist on Cygwin! +pub const SIOCGIFCONF: c_ulong = 0x80107364; +pub const SIOCGIFFLAGS: c_ulong = 0x80507365; +pub const SIOCGIFADDR: c_ulong = 0x80507366; +pub const SIOCGIFBRDADDR: c_ulong = 0x80507367; +pub const SIOCGIFNETMASK: c_ulong = 0x80507368; +pub const SIOCGIFHWADDR: c_ulong = 0x80507369; +pub const SIOCGIFMETRIC: c_ulong = 0x8050736a; +pub const SIOCGIFMTU: c_ulong = 0x8050736b; +pub const SIOCGIFINDEX: c_ulong = 0x8050736c; +pub const SIOGIFINDEX: c_ulong = SIOCGIFINDEX; +pub const SIOCGIFDSTADDR: c_ulong = 0x8050736e; +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 1; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_PEERCRED: c_int = 0x0200; +pub const SO_PASSCRED: c_int = 0x0400; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; + +pub const SCM_RIGHTS: c_int = 0x01; +pub const SCM_CREDENTIALS: c_int = 0x02; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_NONBLOCK: c_int = 0x01000000; +pub const SOCK_CLOEXEC: c_int = 0x02000000; +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_NETBIOS: c_int = 17; +pub const AF_INET6: c_int = 23; +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_ISO; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_NETBIOS: c_int = AF_NETBIOS; +pub const PF_INET6: c_int = AF_INET6; +pub const SOMAXCONN: c_int = 0x7fffffff; +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_WAITALL: c_int = 0x8; +pub const MSG_DONTWAIT: c_int = 0x10; +pub const MSG_NOSIGNAL: c_int = 0x20; +pub const MSG_TRUNC: c_int = 0x0100; +pub const MSG_CTRUNC: c_int = 0x0200; +pub const MSG_BCAST: c_int = 0x0400; +pub const MSG_MCAST: c_int = 0x0800; +pub const MSG_CMSG_CLOEXEC: c_int = 0x1000; +pub const MSG_EOR: c_int = 0x8000; +pub const SOL_IP: c_int = 0; +pub const SOL_IPV6: c_int = 41; +pub const SOL_TCP: c_int = 6; +pub const SOL_UDP: c_int = 17; +pub const IPTOS_LOWDELAY: u8 = 0x10; +pub const IPTOS_THROUGHPUT: u8 = 0x08; +pub const IPTOS_RELIABILITY: u8 = 0x04; +pub const IPTOS_LOWCOST: u8 = 0x02; +pub const IPTOS_MINCOST: u8 = IPTOS_LOWCOST; +pub const IP_DEFAULT_MULTICAST_TTL: c_int = 1; +pub const IP_DEFAULT_MULTICAST_LOOP: c_int = 1; +pub const IP_OPTIONS: c_int = 1; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 15; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 16; +pub const IP_BLOCK_SOURCE: c_int = 17; +pub const IP_UNBLOCK_SOURCE: c_int = 18; +pub const IP_PKTINFO: c_int = 19; +pub const IP_RECVTTL: c_int = 21; +pub const IP_UNICAST_IF: c_int = 31; +pub const IP_RECVTOS: c_int = 40; +pub const IP_MTU_DISCOVER: c_int = 71; +pub const IP_MTU: c_int = 73; +pub const IP_RECVERR: c_int = 75; +pub const IP_PMTUDISC_WANT: c_int = 0; +pub const IP_PMTUDISC_DO: c_int = 1; +pub const IP_PMTUDISC_DONT: c_int = 2; +pub const IP_PMTUDISC_PROBE: c_int = 3; +pub const IPV6_HOPOPTS: c_int = 1; +pub const IPV6_HDRINCL: c_int = 2; +pub const IPV6_UNICAST_HOPS: c_int = 4; +pub const IPV6_MULTICAST_IF: c_int = 9; +pub const IPV6_MULTICAST_HOPS: c_int = 10; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IPV6_ADD_MEMBERSHIP: c_int = 12; +pub const IPV6_DROP_MEMBERSHIP: c_int = 13; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; +pub const IPV6_DONTFRAG: c_int = 14; +pub const IPV6_PKTINFO: c_int = 19; +pub const IPV6_HOPLIMIT: c_int = 21; +pub const IPV6_CHECKSUM: c_int = 26; +pub const IPV6_V6ONLY: c_int = 27; +pub const IPV6_UNICAST_IF: c_int = 31; +pub const IPV6_RTHDR: c_int = 32; +pub const IPV6_RECVRTHDR: c_int = 38; +pub const IPV6_TCLASS: c_int = 39; +pub const IPV6_RECVTCLASS: c_int = 40; +pub const IPV6_MTU_DISCOVER: c_int = 71; +pub const IPV6_MTU: c_int = 72; +pub const IPV6_RECVERR: c_int = 75; +pub const IPV6_PMTUDISC_WANT: c_int = 0; +pub const IPV6_PMTUDISC_DO: c_int = 1; +pub const IPV6_PMTUDISC_DONT: c_int = 2; +pub const IPV6_PMTUDISC_PROBE: c_int = 3; +pub const MCAST_JOIN_GROUP: c_int = 41; +pub const MCAST_LEAVE_GROUP: c_int = 42; +pub const MCAST_BLOCK_SOURCE: c_int = 43; +pub const MCAST_UNBLOCK_SOURCE: c_int = 44; +pub const MCAST_JOIN_SOURCE_GROUP: c_int = 45; +pub const MCAST_LEAVE_SOURCE_GROUP: c_int = 46; +pub const MCAST_INCLUDE: c_int = 0; +pub const MCAST_EXCLUDE: c_int = 1; +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const S_BLKSIZE: mode_t = 1024; +pub const S_IREAD: mode_t = 256; +pub const S_IWRITE: mode_t = 128; +pub const S_IEXEC: mode_t = 64; +pub const S_ENFMT: mode_t = 1024; +pub const S_IFMT: mode_t = 61440; +pub const S_IFDIR: mode_t = 16384; +pub const S_IFCHR: mode_t = 8192; +pub const S_IFBLK: mode_t = 24576; +pub const S_IFREG: mode_t = 32768; +pub const S_IFLNK: mode_t = 40960; +pub const S_IFSOCK: mode_t = 49152; +pub const S_IFIFO: mode_t = 4096; +pub const S_IRWXU: mode_t = 448; +pub const S_IRUSR: mode_t = 256; +pub const S_IWUSR: mode_t = 128; +pub const S_IXUSR: mode_t = 64; +pub const S_IRWXG: mode_t = 56; +pub const S_IRGRP: mode_t = 32; +pub const S_IWGRP: mode_t = 16; +pub const S_IXGRP: mode_t = 8; +pub const S_IRWXO: mode_t = 7; +pub const S_IROTH: mode_t = 4; +pub const S_IWOTH: mode_t = 2; +pub const S_IXOTH: mode_t = 1; +pub const UTIME_NOW: c_long = -2; +pub const UTIME_OMIT: c_long = -1; + +pub const ARG_MAX: c_int = 32000; +pub const CHILD_MAX: c_int = 256; +pub const IOV_MAX: c_int = 1024; +pub const PTHREAD_STACK_MIN: size_t = 65536; +pub const PATH_MAX: c_int = 4096; +pub const PIPE_BUF: usize = 4096; +pub const NGROUPS_MAX: c_int = 1024; + +pub const FILENAME_MAX: c_int = 4096; + +pub const FORK_RELOAD: c_int = 1; +pub const FORK_NO_RELOAD: c_int = 0; + +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_LAZY: c_int = 1; +pub const RTLD_NOW: c_int = 2; +pub const RTLD_GLOBAL: c_int = 4; +pub const RTLD_NODELETE: c_int = 8; +pub const RTLD_NOLOAD: c_int = 16; +pub const RTLD_DEEPBIND: c_int = 32; + +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: c_int = 0; + +/// gateway mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; + +/// IPIP tunnels (older KA9Q tunnels use 94) +pub const IPPROTO_IPIP: c_int = 4; + +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; + +/// pup +pub const IPPROTO_PUP: c_int = 12; + +/// xns idp +pub const IPPROTO_IDP: c_int = 22; + +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; + +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; + +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; + +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; + +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; + +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; + +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MAX: c_int = 256; + +pub const AI_PASSIVE: c_int = 0x1; +pub const AI_CANONNAME: c_int = 0x2; +pub const AI_NUMERICHOST: c_int = 0x4; +pub const AI_NUMERICSERV: c_int = 0x8; +pub const AI_ALL: c_int = 0x100; +pub const AI_ADDRCONFIG: c_int = 0x400; +pub const AI_V4MAPPED: c_int = 0x800; +pub const NI_NOFQDN: c_int = 0x1; +pub const NI_NUMERICHOST: c_int = 0x2; +pub const NI_NAMEREQD: c_int = 0x4; +pub const NI_NUMERICSERV: c_int = 0x8; +pub const NI_DGRAM: c_int = 0x10; +pub const NI_MAXHOST: c_int = 1025; +pub const NI_MAXSERV: c_int = 32; +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const UT_LINESIZE: usize = 16; +pub const UT_NAMESIZE: usize = 16; +pub const UT_HOSTSIZE: usize = 256; +pub const UT_IDLEN: usize = 2; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const NEW_TIME: c_short = 3; +pub const OLD_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; +pub const POLLRDNORM: c_short = 0x1; +pub const POLLRDBAND: c_short = 0x2; +pub const POLLWRNORM: c_short = 0x4; +pub const POLLWRBAND: c_short = 0x4; + +pub const LC_ALL: c_int = 0; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; +pub const LC_MESSAGES: c_int = 6; +pub const LC_ALL_MASK: c_int = 1 << 0; +pub const LC_COLLATE_MASK: c_int = 1 << 1; +pub const LC_CTYPE_MASK: c_int = 1 << 2; +pub const LC_MONETARY_MASK: c_int = 1 << 3; +pub const LC_NUMERIC_MASK: c_int = 1 << 4; +pub const LC_TIME_MASK: c_int = 1 << 5; +pub const LC_MESSAGES_MASK: c_int = 1 << 6; +pub const LC_GLOBAL_LOCALE: locale_t = -1isize as locale_t; + +pub const SEM_FAILED: *mut sem_t = core::ptr::null_mut(); + +pub const ST_RDONLY: c_ulong = 0x80000; +pub const ST_NOSUID: c_ulong = 0; + +pub const TIOCMGET: c_int = 0x5415; +pub const TIOCMBIS: c_int = 0x5416; +pub const TIOCMBIC: c_int = 0x5417; +pub const TIOCMSET: c_int = 0x5418; +pub const TIOCINQ: c_int = 0x541B; +pub const TIOCSCTTY: c_int = 0x540E; +pub const TIOCSBRK: c_int = 0x5427; +pub const TIOCCBRK: c_int = 0x5428; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; +pub const TCGETA: c_int = 5; +pub const TCSETA: c_int = 6; +pub const TCSETAW: c_int = 7; +pub const TCSETAF: c_int = 8; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const TCFLSH: c_int = 3; +pub const TCSAFLUSH: c_int = 1; +pub const TCSANOW: c_int = 2; +pub const TCSADRAIN: c_int = 3; +pub const TIOCPKT: c_int = 6; +pub const TIOCPKT_DATA: c_int = 0x0; +pub const TIOCPKT_FLUSHREAD: c_int = 0x1; +pub const TIOCPKT_FLUSHWRITE: c_int = 0x2; +pub const TIOCPKT_STOP: c_int = 0x4; +pub const TIOCPKT_START: c_int = 0x8; +pub const TIOCPKT_NOSTOP: c_int = 0x10; +pub const TIOCPKT_DOSTOP: c_int = 0x20; +pub const IGNBRK: tcflag_t = 0x00001; +pub const BRKINT: tcflag_t = 0x00002; +pub const IGNPAR: tcflag_t = 0x00004; +pub const IMAXBEL: tcflag_t = 0x00008; +pub const INPCK: tcflag_t = 0x00010; +pub const ISTRIP: tcflag_t = 0x00020; +pub const INLCR: tcflag_t = 0x00040; +pub const IGNCR: tcflag_t = 0x00080; +pub const ICRNL: tcflag_t = 0x00100; +pub const IXON: tcflag_t = 0x00400; +pub const IXOFF: tcflag_t = 0x01000; +pub const IUCLC: tcflag_t = 0x04000; +pub const IXANY: tcflag_t = 0x08000; +pub const PARMRK: tcflag_t = 0x10000; +pub const IUTF8: tcflag_t = 0x20000; +pub const OPOST: tcflag_t = 0x00001; +pub const OLCUC: tcflag_t = 0x00002; +pub const OCRNL: tcflag_t = 0x00004; +pub const ONLCR: tcflag_t = 0x00008; +pub const ONOCR: tcflag_t = 0x00010; +pub const ONLRET: tcflag_t = 0x00020; +pub const OFILL: tcflag_t = 0x00040; +pub const CRDLY: tcflag_t = 0x00180; +pub const CR0: tcflag_t = 0x00000; +pub const CR1: tcflag_t = 0x00080; +pub const CR2: tcflag_t = 0x00100; +pub const CR3: tcflag_t = 0x00180; +pub const NLDLY: tcflag_t = 0x00200; +pub const NL0: tcflag_t = 0x00000; +pub const NL1: tcflag_t = 0x00200; +pub const BSDLY: tcflag_t = 0x00400; +pub const BS0: tcflag_t = 0x00000; +pub const BS1: tcflag_t = 0x00400; +pub const TABDLY: tcflag_t = 0x01800; +pub const TAB0: tcflag_t = 0x00000; +pub const TAB1: tcflag_t = 0x00800; +pub const TAB2: tcflag_t = 0x01000; +pub const TAB3: tcflag_t = 0x01800; +pub const XTABS: tcflag_t = 0x01800; +pub const VTDLY: tcflag_t = 0x02000; +pub const VT0: tcflag_t = 0x00000; +pub const VT1: tcflag_t = 0x02000; +pub const FFDLY: tcflag_t = 0x04000; +pub const FF0: tcflag_t = 0x00000; +pub const FF1: tcflag_t = 0x04000; +pub const OFDEL: tcflag_t = 0x08000; +pub const CBAUD: tcflag_t = 0x0100f; +pub const B0: speed_t = 0x00000; +pub const B50: speed_t = 0x00001; +pub const B75: speed_t = 0x00002; +pub const B110: speed_t = 0x00003; +pub const B134: speed_t = 0x00004; +pub const B150: speed_t = 0x00005; +pub const B200: speed_t = 0x00006; +pub const B300: speed_t = 0x00007; +pub const B600: speed_t = 0x00008; +pub const B1200: speed_t = 0x00009; +pub const B1800: speed_t = 0x0000a; +pub const B2400: speed_t = 0x0000b; +pub const B4800: speed_t = 0x0000c; +pub const B9600: speed_t = 0x0000d; +pub const B19200: speed_t = 0x0000e; +pub const B38400: speed_t = 0x0000f; +pub const CSIZE: tcflag_t = 0x00030; +pub const CS5: tcflag_t = 0x00000; +pub const CS6: tcflag_t = 0x00010; +pub const CS7: tcflag_t = 0x00020; +pub const CS8: tcflag_t = 0x00030; +pub const CSTOPB: tcflag_t = 0x00040; +pub const CREAD: tcflag_t = 0x00080; +pub const PARENB: tcflag_t = 0x00100; +pub const PARODD: tcflag_t = 0x00200; +pub const HUPCL: tcflag_t = 0x00400; +pub const CLOCAL: tcflag_t = 0x00800; +pub const CBAUDEX: tcflag_t = 0x0100f; +pub const B57600: speed_t = 0x01001; +pub const B115200: speed_t = 0x01002; +pub const B230400: speed_t = 0x01004; +pub const B460800: speed_t = 0x01006; +pub const B500000: speed_t = 0x01007; +pub const B576000: speed_t = 0x01008; +pub const B921600: speed_t = 0x01009; +pub const B1000000: speed_t = 0x0100a; +pub const B1152000: speed_t = 0x0100b; +pub const B1500000: speed_t = 0x0100c; +pub const B2000000: speed_t = 0x0100d; +pub const B2500000: speed_t = 0x0100e; +pub const B3000000: speed_t = 0x0100f; +pub const CRTSCTS: tcflag_t = 0x08000; +pub const CMSPAR: tcflag_t = 0x40000000; +pub const ISIG: tcflag_t = 0x0001; +pub const ICANON: tcflag_t = 0x0002; +pub const ECHO: tcflag_t = 0x0004; +pub const ECHOE: tcflag_t = 0x0008; +pub const ECHOK: tcflag_t = 0x0010; +pub const ECHONL: tcflag_t = 0x0020; +pub const NOFLSH: tcflag_t = 0x0040; +pub const TOSTOP: tcflag_t = 0x0080; +pub const IEXTEN: tcflag_t = 0x0100; +pub const FLUSHO: tcflag_t = 0x0200; +pub const ECHOKE: tcflag_t = 0x0400; +pub const ECHOCTL: tcflag_t = 0x0800; +pub const VDISCARD: usize = 1; +pub const VEOL: usize = 2; +pub const VEOL2: usize = 3; +pub const VEOF: usize = 4; +pub const VERASE: usize = 5; +pub const VINTR: usize = 6; +pub const VKILL: usize = 7; +pub const VLNEXT: usize = 8; +pub const VMIN: usize = 9; +pub const VQUIT: usize = 10; +pub const VREPRINT: usize = 11; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VSUSP: usize = 14; +pub const VSWTC: usize = 15; +pub const VTIME: usize = 16; +pub const VWERASE: usize = 17; +pub const NCCS: usize = 18; + +pub const TIOCGWINSZ: c_int = 0x5401; +pub const TIOCSWINSZ: c_int = 0x5402; +pub const TIOCLINUX: c_int = 0x5403; +pub const TIOCGPGRP: c_int = 0x540f; +pub const TIOCSPGRP: c_int = 0x5410; + +pub const WNOHANG: c_int = 1; +pub const WUNTRACED: c_int = 2; +pub const WCONTINUED: c_int = 8; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; +pub const MAP_FILE: c_int = 0; +pub const MAP_SHARED: c_int = 1; +pub const MAP_PRIVATE: c_int = 2; +pub const MAP_TYPE: c_int = 0xf; +pub const MAP_FIXED: c_int = 0x10; +pub const MAP_ANON: c_int = 0x20; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; +pub const MAP_NORESERVE: c_int = 0x4000; +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; +pub const MS_ASYNC: c_int = 1; +pub const MS_SYNC: c_int = 2; +pub const MS_INVALIDATE: c_int = 4; +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_SEQUENTIAL: c_int = 1; +pub const POSIX_MADV_RANDOM: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; +pub const MADV_NORMAL: c_int = 0; +pub const MADV_SEQUENTIAL: c_int = 1; +pub const MADV_RANDOM: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; + +pub const F_ULOCK: c_int = 0; +pub const F_LOCK: c_int = 1; +pub const F_TLOCK: c_int = 2; +pub const F_TEST: c_int = 3; + +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_JOB_CONTROL: c_int = 5; +pub const _SC_SAVED_IDS: c_int = 6; +pub const _SC_VERSION: c_int = 7; +pub const _SC_PAGESIZE: c_int = 8; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_NPROCESSORS_CONF: c_int = 9; +pub const _SC_NPROCESSORS_ONLN: c_int = 10; +pub const _SC_PHYS_PAGES: c_int = 11; +pub const _SC_AVPHYS_PAGES: c_int = 12; +pub const _SC_MQ_OPEN_MAX: c_int = 13; +pub const _SC_MQ_PRIO_MAX: c_int = 14; +pub const _SC_RTSIG_MAX: c_int = 15; +pub const _SC_SEM_NSEMS_MAX: c_int = 16; +pub const _SC_SEM_VALUE_MAX: c_int = 17; +pub const _SC_SIGQUEUE_MAX: c_int = 18; +pub const _SC_TIMER_MAX: c_int = 19; +pub const _SC_TZNAME_MAX: c_int = 20; +pub const _SC_ASYNCHRONOUS_IO: c_int = 21; +pub const _SC_FSYNC: c_int = 22; +pub const _SC_MAPPED_FILES: c_int = 23; +pub const _SC_MEMLOCK: c_int = 24; +pub const _SC_MEMLOCK_RANGE: c_int = 25; +pub const _SC_MEMORY_PROTECTION: c_int = 26; +pub const _SC_MESSAGE_PASSING: c_int = 27; +pub const _SC_PRIORITIZED_IO: c_int = 28; +pub const _SC_REALTIME_SIGNALS: c_int = 29; +pub const _SC_SEMAPHORES: c_int = 30; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 31; +pub const _SC_SYNCHRONIZED_IO: c_int = 32; +pub const _SC_TIMERS: c_int = 33; +pub const _SC_AIO_LISTIO_MAX: c_int = 34; +pub const _SC_AIO_MAX: c_int = 35; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 36; +pub const _SC_DELAYTIMER_MAX: c_int = 37; +pub const _SC_THREAD_KEYS_MAX: c_int = 38; +pub const _SC_THREAD_STACK_MIN: c_int = 39; +pub const _SC_THREAD_THREADS_MAX: c_int = 40; +pub const _SC_TTY_NAME_MAX: c_int = 41; +pub const _SC_THREADS: c_int = 42; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 43; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 44; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 45; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 46; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 47; +pub const _SC_THREAD_PRIO_CEILING: c_int = _SC_THREAD_PRIO_PROTECT; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 48; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 49; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 50; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 51; +pub const _SC_LOGIN_NAME_MAX: c_int = 52; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 53; +pub const _SC_ADVISORY_INFO: c_int = 54; +pub const _SC_ATEXIT_MAX: c_int = 55; +pub const _SC_BARRIERS: c_int = 56; +pub const _SC_BC_BASE_MAX: c_int = 57; +pub const _SC_BC_DIM_MAX: c_int = 58; +pub const _SC_BC_SCALE_MAX: c_int = 59; +pub const _SC_BC_STRING_MAX: c_int = 60; +pub const _SC_CLOCK_SELECTION: c_int = 61; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 62; +pub const _SC_CPUTIME: c_int = 63; +pub const _SC_EXPR_NEST_MAX: c_int = 64; +pub const _SC_HOST_NAME_MAX: c_int = 65; +pub const _SC_IOV_MAX: c_int = 66; +pub const _SC_IPV6: c_int = 67; +pub const _SC_LINE_MAX: c_int = 68; +pub const _SC_MONOTONIC_CLOCK: c_int = 69; +pub const _SC_RAW_SOCKETS: c_int = 70; +pub const _SC_READER_WRITER_LOCKS: c_int = 71; +pub const _SC_REGEXP: c_int = 72; +pub const _SC_RE_DUP_MAX: c_int = 73; +pub const _SC_SHELL: c_int = 74; +pub const _SC_SPAWN: c_int = 75; +pub const _SC_SPIN_LOCKS: c_int = 76; +pub const _SC_SPORADIC_SERVER: c_int = 77; +pub const _SC_SS_REPL_MAX: c_int = 78; +pub const _SC_SYMLOOP_MAX: c_int = 79; +pub const _SC_THREAD_CPUTIME: c_int = 80; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 81; +pub const _SC_TIMEOUTS: c_int = 82; +pub const _SC_TRACE: c_int = 83; +pub const _SC_TRACE_EVENT_FILTER: c_int = 84; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 85; +pub const _SC_TRACE_INHERIT: c_int = 86; +pub const _SC_TRACE_LOG: c_int = 87; +pub const _SC_TRACE_NAME_MAX: c_int = 88; +pub const _SC_TRACE_SYS_MAX: c_int = 89; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 90; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 91; +pub const _SC_V7_ILP32_OFF32: c_int = 92; +pub const _SC_V6_ILP32_OFF32: c_int = _SC_V7_ILP32_OFF32; +pub const _SC_XBS5_ILP32_OFF32: c_int = _SC_V7_ILP32_OFF32; +pub const _SC_V7_ILP32_OFFBIG: c_int = 93; +pub const _SC_V6_ILP32_OFFBIG: c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_V7_LP64_OFF64: c_int = 94; +pub const _SC_V6_LP64_OFF64: c_int = _SC_V7_LP64_OFF64; +pub const _SC_XBS5_LP64_OFF64: c_int = _SC_V7_LP64_OFF64; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 95; +pub const _SC_V6_LPBIG_OFFBIG: c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XOPEN_CRYPT: c_int = 96; +pub const _SC_XOPEN_ENH_I18N: c_int = 97; +pub const _SC_XOPEN_LEGACY: c_int = 98; +pub const _SC_XOPEN_REALTIME: c_int = 99; +pub const _SC_STREAM_MAX: c_int = 100; +pub const _SC_PRIORITY_SCHEDULING: c_int = 101; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 102; +pub const _SC_XOPEN_SHM: c_int = 103; +pub const _SC_XOPEN_STREAMS: c_int = 104; +pub const _SC_XOPEN_UNIX: c_int = 105; +pub const _SC_XOPEN_VERSION: c_int = 106; +pub const _SC_2_CHAR_TERM: c_int = 107; +pub const _SC_2_C_BIND: c_int = 108; +pub const _SC_2_C_DEV: c_int = 109; +pub const _SC_2_FORT_DEV: c_int = 110; +pub const _SC_2_FORT_RUN: c_int = 111; +pub const _SC_2_LOCALEDEF: c_int = 112; +pub const _SC_2_PBS: c_int = 113; +pub const _SC_2_PBS_ACCOUNTING: c_int = 114; +pub const _SC_2_PBS_CHECKPOINT: c_int = 115; +pub const _SC_2_PBS_LOCATE: c_int = 116; +pub const _SC_2_PBS_MESSAGE: c_int = 117; +pub const _SC_2_PBS_TRACK: c_int = 118; +pub const _SC_2_SW_DEV: c_int = 119; +pub const _SC_2_UPE: c_int = 120; +pub const _SC_2_VERSION: c_int = 121; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 122; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 123; +pub const _SC_XOPEN_UUCP: c_int = 124; +pub const _SC_LEVEL1_ICACHE_SIZE: c_int = 125; +pub const _SC_LEVEL1_ICACHE_ASSOC: c_int = 126; +pub const _SC_LEVEL1_ICACHE_LINESIZE: c_int = 127; +pub const _SC_LEVEL1_DCACHE_SIZE: c_int = 128; +pub const _SC_LEVEL1_DCACHE_ASSOC: c_int = 129; +pub const _SC_LEVEL1_DCACHE_LINESIZE: c_int = 130; +pub const _SC_LEVEL2_CACHE_SIZE: c_int = 131; +pub const _SC_LEVEL2_CACHE_ASSOC: c_int = 132; +pub const _SC_LEVEL2_CACHE_LINESIZE: c_int = 133; +pub const _SC_LEVEL3_CACHE_SIZE: c_int = 134; +pub const _SC_LEVEL3_CACHE_ASSOC: c_int = 135; +pub const _SC_LEVEL3_CACHE_LINESIZE: c_int = 136; +pub const _SC_LEVEL4_CACHE_SIZE: c_int = 137; +pub const _SC_LEVEL4_CACHE_ASSOC: c_int = 138; +pub const _SC_LEVEL4_CACHE_LINESIZE: c_int = 139; +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_ASYNC_IO: c_int = 9; +pub const _PC_PRIO_IO: c_int = 10; +pub const _PC_SYNC_IO: c_int = 11; +pub const _PC_FILESIZEBITS: c_int = 12; +pub const _PC_2_SYMLINKS: c_int = 13; +pub const _PC_SYMLINK_MAX: c_int = 14; +pub const _PC_ALLOC_SIZE_MIN: c_int = 15; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 16; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 17; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 18; +pub const _PC_REC_XFER_ALIGN: c_int = 19; +pub const _PC_TIMESTAMP_RESOLUTION: c_int = 20; +pub const _CS_PATH: c_int = 0; + +pub const O_ACCMODE: c_int = 0x3; +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; +pub const O_APPEND: c_int = 0x0008; +pub const O_CREAT: c_int = 0x0200; +pub const O_TRUNC: c_int = 0x0400; +pub const O_EXCL: c_int = 0x0800; +pub const O_SYNC: c_int = 0x2000; +pub const O_NONBLOCK: c_int = 0x4000; +pub const O_NOCTTY: c_int = 0x8000; +pub const O_CLOEXEC: c_int = 0x40000; +pub const O_NOFOLLOW: c_int = 0x100000; +pub const O_DIRECTORY: c_int = 0x200000; +pub const O_EXEC: c_int = 0x400000; +pub const O_SEARCH: c_int = 0x400000; +pub const O_DIRECT: c_int = 0x80000; +pub const O_DSYNC: c_int = 0x2000; +pub const O_RSYNC: c_int = 0x2000; +pub const O_TMPFILE: c_int = 0x800000; +pub const O_NOATIME: c_int = 0x1000000; +pub const O_PATH: c_int = 0x2000000; +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_RGETLK: c_int = 10; +pub const F_RSETLK: c_int = 11; +pub const F_CNVT: c_int = 12; +pub const F_RSETLKW: c_int = 13; +pub const F_DUPFD_CLOEXEC: c_int = 14; +pub const F_RDLCK: c_int = 1; +pub const F_WRLCK: c_int = 2; +pub const F_UNLCK: c_int = 3; +pub const AT_FDCWD: c_int = -2; +pub const AT_EACCESS: c_int = 1; +pub const AT_SYMLINK_NOFOLLOW: c_int = 2; +pub const AT_SYMLINK_FOLLOW: c_int = 4; +pub const AT_REMOVEDIR: c_int = 8; +pub const AT_EMPTY_PATH: c_int = 16; +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EDEADLK: c_int = 45; +pub const ENOLCK: c_int = 46; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EBFONT: c_int = 57; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EMULTIHOP: c_int = 74; +pub const EDOTDOT: c_int = 76; +pub const EBADMSG: c_int = 77; +pub const EFTYPE: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const ENOSYS: c_int = 88; +pub const ENOTEMPTY: c_int = 90; +pub const ENAMETOOLONG: c_int = 91; +pub const ELOOP: c_int = 92; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EAFNOSUPPORT: c_int = 106; +pub const EPROTOTYPE: c_int = 107; +pub const ENOTSOCK: c_int = 108; +pub const ENOPROTOOPT: c_int = 109; +pub const ESHUTDOWN: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EADDRINUSE: c_int = 112; +pub const ECONNABORTED: c_int = 113; +pub const ENETUNREACH: c_int = 114; +pub const ENETDOWN: c_int = 115; +pub const ETIMEDOUT: c_int = 116; +pub const EHOSTDOWN: c_int = 117; +pub const EHOSTUNREACH: c_int = 118; +pub const EINPROGRESS: c_int = 119; +pub const EALREADY: c_int = 120; +pub const EDESTADDRREQ: c_int = 121; +pub const EMSGSIZE: c_int = 122; +pub const EPROTONOSUPPORT: c_int = 123; +pub const ESOCKTNOSUPPORT: c_int = 124; +pub const EADDRNOTAVAIL: c_int = 125; +pub const ENETRESET: c_int = 126; +pub const EISCONN: c_int = 127; +pub const ENOTCONN: c_int = 128; +pub const ETOOMANYREFS: c_int = 129; +pub const EPROCLIM: c_int = 130; +pub const EUSERS: c_int = 131; +pub const EDQUOT: c_int = 132; +pub const ESTALE: c_int = 133; +pub const ENOTSUP: c_int = 134; +pub const ENOMEDIUM: c_int = 135; +pub const EILSEQ: c_int = 138; +pub const EOVERFLOW: c_int = 139; +pub const ECANCELED: c_int = 140; +pub const ENOTRECOVERABLE: c_int = 141; +pub const EOWNERDEAD: c_int = 142; +pub const ESTRPIPE: c_int = 143; +pub const EWOULDBLOCK: c_int = EAGAIN; /* Operation would block */ + +pub const SCHED_OTHER: c_int = 3; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 21 as *mut _; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_NORMAL: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: pthread_mutex_t = 18 as *mut _; +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: pthread_mutex_t = 20 as *mut _; +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 19 as *mut _; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 22 as *mut _; + +pub const LITTLE_ENDIAN: c_int = 1234; +pub const BIG_ENDIAN: c_int = 4321; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_KEEPIDLE: c_int = 3; +pub const TCP_MAXSEG: c_int = 4; +pub const TCP_QUICKACK: c_int = 12; +pub const TCP_USER_TIMEOUT: c_int = 14; +pub const TCP_FASTOPEN: c_int = 15; +pub const TCP_KEEPCNT: c_int = 16; +pub const TCP_KEEPINTVL: c_int = 17; + +pub const WINDOWS_POST: c_int = 0; +pub const WINDOWS_SEND: c_int = 1; +pub const WINDOWS_HWND: c_int = 2; + +pub const MOUNT_TEXT: c_uint = 0x01; +pub const MOUNT_SYSTEM: c_uint = 0x08; +pub const MOUNT_EXEC: c_uint = 0x10; +pub const MOUNT_CYGDRIVE: c_uint = 0x20; +pub const MOUNT_CYGWIN_EXEC: c_uint = 0x40; +pub const MOUNT_SPARSE: c_uint = 0x80; +pub const MOUNT_NOTEXEC: c_uint = 0x100; +pub const MOUNT_DEVFS: c_uint = 0x200; +pub const MOUNT_PROC: c_uint = 0x400; +pub const MOUNT_RO: c_uint = 0x1000; +pub const MOUNT_NOACL: c_uint = 0x2000; +pub const MOUNT_NOPOSIX: c_uint = 0x4000; +pub const MOUNT_OVERRIDE: c_uint = 0x8000; +pub const MOUNT_IMMUTABLE: c_uint = 0x10000; +pub const MOUNT_AUTOMATIC: c_uint = 0x20000; +pub const MOUNT_DOS: c_uint = 0x40000; +pub const MOUNT_IHASH: c_uint = 0x80000; +pub const MOUNT_BIND: c_uint = 0x100000; +pub const MOUNT_USER_TEMP: c_uint = 0x200000; +pub const MOUNT_DONT_USE: c_uint = 0x80000000; + +pub const _POSIX_VDISABLE: cc_t = 0; + +pub const GRND_NONBLOCK: c_uint = 0x1; +pub const GRND_RANDOM: c_uint = 0x2; + +pub const _IOFBF: c_int = 0; +pub const _IOLBF: c_int = 1; +pub const _IONBF: c_int = 2; +pub const BUFSIZ: c_int = 1024; + +pub const POSIX_SPAWN_RESETIDS: c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x02; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x04; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x08; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x10; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x20; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_SEQUENTIAL: c_int = 1; +pub const POSIX_FADV_RANDOM: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const FALLOC_FL_PUNCH_HOLE: c_int = 0x0001; +pub const FALLOC_FL_ZERO_RANGE: c_int = 0x0002; +pub const FALLOC_FL_UNSHARE_RANGE: c_int = 0x0004; +pub const FALLOC_FL_COLLAPSE_RANGE: c_int = 0x0008; +pub const FALLOC_FL_INSERT_RANGE: c_int = 0x0010; +pub const FALLOC_FL_KEEP_SIZE: c_int = 0x1000; + +f! { + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0 + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_ALLOC_SIZE(count: c_int) -> size_t { + let _dummy: cpu_set_t = cpu_set_t { bits: [0; 16] }; + let size_in_bits = 8 * size_of_val(&_dummy.bits[0]); + ((count as size_t + size_in_bits - 1) / 8) as size_t + } + + pub fn CPU_COUNT_S(size: usize, cpuset: &cpu_set_t) -> c_int { + let mut s: u32 = 0; + let size_of_mask = size_of_val(&cpuset.bits[0]); + for i in cpuset.bits[..(size / size_of_mask)].iter() { + s += i.count_ones(); + } + s as c_int + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + if cpu < size_in_bits { + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + } + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + if cpu < size_in_bits { + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + } + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + if cpu < size_in_bits { + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } else { + false + } + } + + pub fn CPU_COUNT(cpuset: &cpu_set_t) -> c_int { + CPU_COUNT_S(size_of::(), cpuset) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn CMSG_LEN(length: c_uint) -> c_uint { + CMSG_ALIGN(size_of::()) as c_uint + length + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control.cast() + } else { + core::ptr::null_mut() + } + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + let next = (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next as usize + CMSG_ALIGN(size_of::()) as usize > max { + core::ptr::null_mut() + } else { + next + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + cmsg.offset(1).cast_mut().cast() + } +} + +safe_f! { + pub const fn makedev(ma: c_uint, mi: c_uint) -> dev_t { + let ma = ma as dev_t; + let mi = mi as dev_t; + (ma << 16) | (mi & 0xffff) + } + + pub const fn major(dev: dev_t) -> c_uint { + ((dev >> 16) & 0xffff) as c_uint + } + + pub const fn minor(dev: dev_t) -> c_uint { + (dev & 0xffff) as c_uint + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0xff) == 0 + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0o177 + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + (status & 0o177777) == 0o177777 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0o177 + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + WIFSIGNALED(status) && (status & 0x80) != 0 + } +} + +const fn CMSG_ALIGN(len: usize) -> usize { + len + size_of::() - 1 & !(size_of::() - 1) +} + +extern "C" { + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sigsuspend(mask: *const sigset_t) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn pthread_kill(thread: pthread_t, sig: c_int) -> c_int; + + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const timespec, + ) -> c_int; + + pub fn strftime(s: *mut c_char, max: size_t, format: *const c_char, tm: *const tm) -> size_t; + + pub fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char; + pub fn ctime_r(timep: *const time_t, buf: *mut c_char) -> *mut c_char; + pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut tm) -> *mut c_char; + pub fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> c_int; + pub fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int; + pub fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> c_int; + + pub fn timer_create(clockid: clockid_t, sevp: *mut sigevent, timerid: *mut timer_t) -> c_int; + + pub fn timer_delete(timerid: timer_t) -> c_int; + + pub fn timer_settime( + timerid: timer_t, + flags: c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec, + ) -> c_int; + + pub fn timer_gettime(timerid: timer_t, curr_value: *mut itimerspec) -> c_int; + pub fn timer_getoverrun(timerid: timer_t) -> c_int; + + pub fn clock_nanosleep( + clk_id: clockid_t, + flags: c_int, + rqtp: *const timespec, + rmtp: *mut timespec, + ) -> c_int; + + pub fn clock_getcpuclockid(pid: pid_t, clk_id: *mut clockid_t) -> c_int; + + pub fn futimes(fd: c_int, times: *const timeval) -> c_int; + pub fn lutimes(file: *const c_char, times: *const timeval) -> c_int; + pub fn settimeofday(tv: *const timeval, tz: *const timezone) -> c_int; + pub fn getitimer(which: c_int, curr_value: *mut itimerval) -> c_int; + + pub fn setitimer(which: c_int, new_value: *const itimerval, old_value: *mut itimerval) + -> c_int; + + pub fn gettimeofday(tp: *mut timeval, tz: *mut c_void) -> c_int; + pub fn futimesat(fd: c_int, path: *const c_char, times: *const timeval) -> c_int; + + pub fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const rlimit) -> c_int; + pub fn getpriority(which: c_int, who: id_t) -> c_int; + pub fn setpriority(which: c_int, who: id_t, prio: c_int) -> c_int; + + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + + pub fn getpwuid_r( + uid: uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + + pub fn getpwent() -> *mut passwd; + pub fn setpwent(); + pub fn endpwent(); + + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn readv(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t; + pub fn writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t; + + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const timespec, + flag: c_int, + ) -> c_int; + + pub fn futimens(fd: c_int, times: *const timespec) -> c_int; + + pub fn dlfork(val: c_int); + + pub fn accept4(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t, flags: c_int) -> c_int; + + pub fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t, + ) -> ssize_t; + + pub fn recvmsg(fd: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t; + pub fn sendmsg(fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t; + + pub fn getnameinfo( + sa: *const sockaddr, + salen: socklen_t, + host: *mut c_char, + hostlen: socklen_t, + serv: *mut c_char, + sevlen: socklen_t, + flags: c_int, + ) -> c_int; + + pub fn ppoll( + fds: *mut pollfd, + nfds: nfds_t, + timeout: *const timespec, + sigmask: *const sigset_t, + ) -> c_int; + + pub fn newlocale(mask: c_int, locale: *const c_char, base: locale_t) -> locale_t; + pub fn freelocale(loc: locale_t); + pub fn duplocale(base: locale_t) -> locale_t; + pub fn uselocale(loc: locale_t) -> locale_t; + + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + + pub fn clearenv() -> c_int; + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn getpt() -> c_int; + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn arc4random() -> u32; + pub fn arc4random_uniform(l: u32) -> u32; + pub fn arc4random_buf(buf: *mut c_void, size: size_t); + pub fn labs(i: c_long) -> c_long; + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn rand() -> c_int; + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + pub fn reallocf(ptr: *mut c_void, size: size_t) -> *mut c_void; + pub fn srand(seed: c_uint); + pub fn drand48() -> c_double; + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn lcong48(p: *mut c_ushort); + pub fn lrand48() -> c_long; + pub fn mrand48() -> c_long; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn srand48(seed: c_long); + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); + + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn explicit_bzero(s: *mut c_void, len: size_t); + pub fn ffs(value: c_int) -> c_int; + pub fn ffsl(value: c_long) -> c_int; + pub fn ffsll(value: c_longlong) -> c_int; + pub fn fls(value: c_int) -> c_int; + pub fn flsl(value: c_long) -> c_int; + pub fn flsll(value: c_longlong) -> c_int; + pub fn strcasecmp_l(s1: *const c_char, s2: *const c_char, loc: locale_t) -> c_int; + + pub fn strncasecmp_l(s1: *const c_char, s2: *const c_char, n: size_t, loc: locale_t) -> c_int; + + pub fn timingsafe_bcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + pub fn timingsafe_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + #[link_name = "__xpg_strerror_r"] + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn strsep(string: *mut *mut c_char, delim: *const c_char) -> *mut c_char; + + #[link_name = "__gnu_basename"] + pub fn basename(path: *const c_char) -> *mut c_char; + + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn dup3(src: c_int, dst: c_int, flags: c_int) -> c_int; + pub fn eaccess(pathname: *const c_char, mode: c_int) -> c_int; + pub fn euidaccess(pathname: *const c_char, mode: c_int) -> c_int; + + pub fn execvpe( + file: *const c_char, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + + pub fn fexecve(fd: c_int, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int; + + pub fn fdatasync(fd: c_int) -> c_int; + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + pub fn gethostid() -> c_long; + pub fn getpagesize() -> c_int; + pub fn getpeereid(socket: c_int, euid: *mut uid_t, egid: *mut gid_t) -> c_int; + + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + pub fn sbrk(increment: intptr_t) -> *mut c_void; + pub fn setgroups(ngroups: c_int, ptr: *const gid_t) -> c_int; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn vhangup() -> c_int; + pub fn getdtablesize() -> c_int; + pub fn sync(); + + pub fn __errno() -> *mut c_int; + + pub fn sched_setparam(pid: pid_t, param: *const sched_param) -> c_int; + pub fn sched_getparam(pid: pid_t, param: *mut sched_param) -> c_int; + + pub fn sched_setscheduler(pid: pid_t, policy: c_int, param: *const sched_param) -> c_int; + + pub fn sched_getscheduler(pid: pid_t) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sched_rr_get_interval(pid: pid_t, t: *mut timespec) -> c_int; + pub fn sched_getcpu() -> c_int; + pub fn sched_getaffinity(pid: pid_t, cpusetsize: size_t, mask: *mut cpu_set_t) -> c_int; + + pub fn sched_setaffinity(pid: pid_t, cpusetsize: size_t, cpuset: *const cpu_set_t) -> c_int; + + pub fn pthread_attr_getguardsize(attr: *const pthread_attr_t, guardsize: *mut size_t) -> c_int; + + pub fn pthread_attr_getschedparam( + attr: *const pthread_attr_t, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_attr_setschedparam( + attr: *mut pthread_attr_t, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_attr_getstack( + attr: *const pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + + pub fn pthread_cancel(thread: pthread_t) -> c_int; + + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clock_id: clockid_t) -> c_int; + + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + pub fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int; + + pub fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, shared: c_int) + -> c_int; + + pub fn pthread_barrierattr_getpshared( + attr: *const pthread_barrierattr_t, + shared: *mut c_int, + ) -> c_int; + + pub fn pthread_barrierattr_destroy(attr: *mut pthread_barrierattr_t) -> c_int; + + pub fn pthread_barrier_init( + barrier: *mut pthread_barrier_t, + attr: *const pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + + pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int; + + pub fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn pthread_getcpuclockid(thread: pthread_t, clk_id: *mut clockid_t) -> c_int; + + pub fn pthread_getschedparam( + native: pthread_t, + policy: *mut c_int, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, abstime: *const timespec) -> c_int; + + pub fn pthread_mutexattr_getprotocol( + attr: *const pthread_mutexattr_t, + protocol: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + + pub fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int; + + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, val: c_int) -> c_int; + + pub fn pthread_setschedparam( + native: pthread_t, + policy: c_int, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_setschedprio(native: pthread_t, priority: c_int) -> c_int; + + pub fn pthread_getaffinity_np( + thread: pthread_t, + cpusetsize: size_t, + cpuset: *mut cpu_set_t, + ) -> c_int; + + pub fn pthread_getattr_np(native: pthread_t, attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_getname_np(thread: pthread_t, name: *mut c_char, len: size_t) -> c_int; + + pub fn pthread_setaffinity_np( + thread: pthread_t, + cpusetsize: size_t, + cpuset: *const cpu_set_t, + ) -> c_int; + + pub fn pthread_setname_np(thread: pthread_t, name: *const c_char) -> c_int; + pub fn pthread_sigqueue(thread: pthread_t, sig: c_int, value: sigval) -> c_int; + + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + pub fn mount(src: *const c_char, target: *const c_char, flags: c_uint) -> c_int; + + pub fn umount(target: *const c_char) -> c_int; + pub fn cygwin_umount(target: *const c_char, flags: c_uint) -> c_int; + + pub fn dirfd(dirp: *mut DIR) -> c_int; + pub fn seekdir(dirp: *mut DIR, loc: c_long); + pub fn telldir(dirp: *mut DIR) -> c_long; + + pub fn uname(buf: *mut utsname) -> c_int; + + pub fn posix_spawn( + pid: *mut pid_t, + path: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + attrp: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut pid_t, + file: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + attrp: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup(attr: *const posix_spawnattr_t, flags: *mut pid_t) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_addchdir( + actions: *mut crate::posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + pub fn posix_spawn_file_actions_addfchdir( + actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_addchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + pub fn posix_spawn_file_actions_addfchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> crate::pid_t; + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> c_int; + + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t) -> c_int; + + pub fn endutxent(); + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(id: *const utmpx) -> *mut utmpx; + pub fn getutxline(line: *const utmpx) -> *mut utmpx; + pub fn pututxline(utmpx: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn utmpxname(file: *const c_char) -> c_int; + pub fn updwtmpx(file: *const c_char, utmpx: *const utmpx); +} diff --git a/deps/crates/vendor/libc/src/unix/haiku/b32.rs b/deps/crates/vendor/libc/src/unix/haiku/b32.rs new file mode 100644 index 00000000000000..1aa27e615ca4ea --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/b32.rs @@ -0,0 +1,18 @@ +pub type time_t = i32; + +pub type Elf_Addr = crate::Elf32_Addr; +pub type Elf_Half = crate::Elf32_Half; +pub type Elf_Phdr = crate::Elf32_Phdr; + +s! { + pub struct Elf32_Phdr { + pub p_type: crate::Elf32_Word, + pub p_offset: crate::Elf32_Off, + pub p_vaddr: crate::Elf32_Addr, + pub p_paddr: crate::Elf32_Addr, + pub p_filesz: crate::Elf32_Word, + pub p_memsz: crate::Elf32_Word, + pub p_flags: crate::Elf32_Word, + pub p_align: crate::Elf32_Word, + } +} diff --git a/deps/crates/vendor/libc/src/unix/haiku/b64.rs b/deps/crates/vendor/libc/src/unix/haiku/b64.rs new file mode 100644 index 00000000000000..3355241fdb7971 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/b64.rs @@ -0,0 +1,18 @@ +pub type time_t = i64; + +pub type Elf_Addr = crate::Elf64_Addr; +pub type Elf_Half = crate::Elf64_Half; +pub type Elf_Phdr = crate::Elf64_Phdr; + +s! { + pub struct Elf64_Phdr { + pub p_type: crate::Elf64_Word, + pub p_flags: crate::Elf64_Word, + pub p_offset: crate::Elf64_Off, + pub p_vaddr: crate::Elf64_Addr, + pub p_paddr: crate::Elf64_Addr, + pub p_filesz: crate::Elf64_Xword, + pub p_memsz: crate::Elf64_Xword, + pub p_align: crate::Elf64_Xword, + } +} diff --git a/deps/crates/vendor/libc/src/unix/haiku/bsd.rs b/deps/crates/vendor/libc/src/unix/haiku/bsd.rs new file mode 100644 index 00000000000000..1e3881e2c67ff5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/bsd.rs @@ -0,0 +1,151 @@ +//! This file contains the BSD APIs available in Haiku. It corresponds to the +//! header files in `headers/compatibility/bsd`. +//! +//! Note that Haiku's BSD compatibility is a combination of system APIs and +//! utility libraries. There should only be system APIs in `libc`. When you are +//! trying to determine whether something should be included in this file, the +//! best indicator is whether it also exists in the BSD-specific definitions in +//! this libc crate. + +use crate::prelude::*; + +// stringlist.h (utility library) +// Note: this is kept because it was previously introduced +pub type StringList = _stringlist; + +s! { + // stringlist.h (utility library) + // Note: this is kept because it was previously introduced + pub struct _stringlist { + pub sl_str: *mut *mut c_char, + pub sl_max: size_t, + pub sl_cur: size_t, + } + + // sys/event.h + pub struct kevent { + pub ident: crate::uintptr_t, + pub filter: c_short, + pub flags: c_ushort, + pub fflags: c_uint, + pub data: i64, + pub udata: *mut c_void, + pub ext: [u64; 4], + } + + // sys/link_elf.h + pub struct dl_phdr_info { + pub dlpi_addr: crate::Elf_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const crate::Elf_Phdr, + pub dlpi_phnum: crate::Elf_Half, + } +} + +// sys/event.h +pub const EVFILT_READ: i16 = -1; +pub const EVFILT_WRITE: i16 = -2; +pub const EVFILT_PROC: i16 = -5; +pub const EV_ADD: u16 = 0x0001; +pub const EV_DELETE: u16 = 0x0002; +pub const EV_ONESHOT: u16 = 0x0010; +pub const EV_CLEAR: u16 = 0x0020; +pub const EV_EOF: u16 = 0x8000; +pub const EV_ERROR: u16 = 0x4000; +pub const NOTE_EXIT: u32 = 0x80000000; + +// sys/ioccom.h +pub const IOC_VOID: c_ulong = 0x20000000; +pub const IOC_OUT: c_ulong = 0x40000000; +pub const IOC_IN: c_ulong = 0x80000000; +pub const IOC_INOUT: c_ulong = IOC_IN | IOC_OUT; +pub const IOC_DIRMASK: c_ulong = 0xe0000000; + +#[link(name = "bsd")] +extern "C" { + // stdlib.h + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn getprogname() -> *const c_char; + pub fn setprogname(progname: *const c_char); + pub fn arc4random() -> u32; + pub fn arc4random_uniform(upper_bound: u32) -> u32; + pub fn arc4random_buf(buf: *mut c_void, n: size_t); + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn strtonum( + nptr: *const c_char, + minval: c_longlong, + maxval: c_longlong, + errstr: *mut *const c_char, + ) -> c_longlong; + + // pty.h + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut crate::termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn login_tty(_fd: c_int) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut crate::termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + + // string.h + pub fn strsep(string: *mut *mut c_char, delimiters: *const c_char) -> *mut c_char; + pub fn explicit_bzero(buf: *mut c_void, len: size_t); + + // stringlist.h (utility library) + // Note: this is kept because it was previously introduced + pub fn sl_init() -> *mut StringList; + pub fn sl_add(sl: *mut StringList, n: *mut c_char) -> c_int; + pub fn sl_free(sl: *mut StringList, i: c_int); + pub fn sl_find(sl: *mut StringList, n: *mut c_char) -> *mut c_char; + + // sys/event.h + pub fn kqueue() -> c_int; + pub fn kevent( + kq: c_int, + changelist: *const kevent, + nchanges: c_int, + eventlist: *mut kevent, + nevents: c_int, + timeout: *const crate::timespec, + ) -> c_int; + + // sys/link_elf.h + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + // sys/time.h + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + + // sys/uov.h + pub fn preadv( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: crate::off_t, + ) -> ssize_t; + pub fn pwritev( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: crate::off_t, + ) -> ssize_t; + + // sys/wait.h + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; +} diff --git a/deps/crates/vendor/libc/src/unix/haiku/mod.rs b/deps/crates/vendor/libc/src/unix/haiku/mod.rs new file mode 100644 index 00000000000000..cbb6464ed84b09 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/mod.rs @@ -0,0 +1,1961 @@ +use crate::prelude::*; + +// This module contains bindings to the native Haiku API. The Haiku API +// originates from BeOS, and it was the original way to perform low level +// system and IO operations. The POSIX API was in that era was like a +// compatibility layer. In current Haiku development, both the POSIX API and +// the Haiku API are considered to be co-equal status. However, they are not +// integrated like they are on other UNIX platforms, which means that for many +// low level concepts there are two versions, like processes (POSIX) and +// teams (Haiku), or pthreads and native threads. +// +// Both the POSIX API and the Haiku API live in libroot.so, the library that is +// linked to any binary by default. Additionally, Haiku supports several +// non-POSIX APIs from BSD and GNU, which live in libbsd.so and libgnu.so. These +// modules are also supported. +// +// The module is comprised of the following files: +// - `mod.rs` (this file) implements the C11 and POSIX API found in +// `headers/posix` +// - `b32.rs`, `b64.rs` and `x86_64.rs` contain platform-specific definitions +// of the C11 and POSIX APIs +// - `native.rs` defines the native Haiku API that is implemented in +// `libroot.so` and that are found in `headers/os`. +// - `bsd.rs` defines the BSD customizations available on Haiku found in +// `headers/compatibility/bsd` + +pub type rlim_t = crate::uintptr_t; +pub type sa_family_t = u8; +pub type pthread_key_t = c_int; +pub type nfds_t = c_ulong; +pub type tcflag_t = c_uint; +pub type speed_t = c_uchar; +pub type clock_t = i32; +pub type clockid_t = i32; +pub type suseconds_t = i32; +pub type wchar_t = i32; +pub type off_t = i64; +pub type ino_t = i64; +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type dev_t = i32; +pub type mode_t = u32; +pub type nlink_t = i32; +pub type useconds_t = u32; +pub type socklen_t = u32; +pub type pthread_t = crate::uintptr_t; +pub type pthread_condattr_t = crate::uintptr_t; +pub type pthread_mutexattr_t = crate::uintptr_t; +pub type pthread_rwlockattr_t = crate::uintptr_t; +pub type sigset_t = u64; +pub type fsblkcnt_t = i64; +pub type fsfilcnt_t = i64; +pub type pthread_attr_t = *mut c_void; +pub type nl_item = c_int; +pub type id_t = i32; +pub type idtype_t = c_int; +pub type fd_mask = u32; +pub type regoff_t = c_int; +pub type key_t = i32; +pub type msgqnum_t = u32; +pub type msglen_t = u32; + +pub type Elf32_Addr = u32; +pub type Elf32_Half = u16; +pub type Elf32_Off = u32; +pub type Elf32_Sword = i32; +pub type Elf32_Word = u32; + +pub type Elf64_Addr = u64; +pub type Elf64_Half = u16; +pub type Elf64_Off = u64; +pub type Elf64_Sword = i32; +pub type Elf64_Sxword = i64; +pub type Elf64_Word = u32; +pub type Elf64_Xword = u64; + +pub type ENTRY = entry; +pub type ACTION = c_int; + +pub type posix_spawnattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_void; + +extern_ty! { + pub enum timezone {} +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +s! { + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [u8; 30], + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [i8; 24], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: u8, + pub sin6_port: u16, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *const c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_dstaddr: *mut crate::sockaddr, + pub ifa_data: *mut c_void, + } + + pub struct fd_set { + // size for 1024 bits, and a fd_mask with size u32 + fds_bits: [fd_mask; 32], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_int, + pub tm_zone: *mut c_char, + } + + pub struct utsname { + pub sysname: [c_char; 32], + pub nodename: [c_char; 32], + pub release: [c_char; 32], + pub version: [c_char; 32], + pub machine: [c_char; 32], + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: c_char, + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_size: off_t, + pub st_rdev: dev_t, + pub st_blksize: blksize_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_crtime: time_t, + pub st_crtime_nsec: c_long, + pub st_type: u32, + pub st_blocks: blkcnt_t, + } + + pub struct glob_t { + pub gl_pathc: size_t, + __unused1: Padding, + pub gl_offs: size_t, + __unused2: Padding, + pub gl_pathv: *mut *mut c_char, + + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + __unused6: Padding<*mut c_void>, + __unused7: Padding<*mut c_void>, + __unused8: Padding<*mut c_void>, + } + + pub struct pthread_mutex_t { + flags: u32, + lock: i32, + unused: Padding, + owner: i32, + owner_count: i32, + } + + pub struct pthread_cond_t { + flags: u32, + unused: Padding, + mutex: *mut c_void, + waiter_count: i32, + lock: i32, + } + + pub struct pthread_rwlock_t { + flags: u32, + owner: i32, + lock_sem: i32, // this is actually a union + lock_count: i32, + reader_count: i32, + writer_count: i32, + waiters: [*mut c_void; 2], + } + + pub struct pthread_spinlock_t { + lock: u32, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + pub pw_gecos: *mut c_char, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + pub si_pid: crate::pid_t, + pub si_uid: crate::uid_t, + pub si_addr: *mut c_void, + pub si_status: c_int, + pub si_band: c_long, + pub sigval: *mut c_void, + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, //actually a union with sa_handler + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + sa_userdata: *mut c_void, + } + + pub struct sem_t { + pub type_: i32, + pub named_sem_id: i32, // actually a union with unnamed_sem (i32) + padding: Padding<[i32; 2]>, + } + + pub struct ucred { + pub pid: crate::pid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } + + pub struct sockaddr_dl { + pub sdl_len: u8, + pub sdl_family: u8, + pub sdl_e_type: u16, + pub sdl_index: u32, + pub sdl_type: u8, + pub sdl_nlen: u8, + pub sdl_alen: u8, + pub sdl_slen: u8, + pub sdl_data: [u8; 46], + } + + pub struct spwd { + pub sp_namp: *mut c_char, + pub sp_pwdp: *mut c_char, + pub sp_lstchg: c_int, + pub sp_min: c_int, + pub sp_max: c_int, + pub sp_warn: c_int, + pub sp_inact: c_int, + pub sp_expire: c_int, + pub sp_flag: c_int, + } + + pub struct regex_t { + __buffer: *mut c_void, + __allocated: size_t, + __used: size_t, + __syntax: c_ulong, + __fastmap: *mut c_char, + __translate: *mut c_char, + __re_nsub: size_t, + __bitfield: u8, + } + + pub struct regmatch_t { + pub rm_so: regoff_t, + pub rm_eo: regoff_t, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + } + + pub struct ipc_perm { + pub key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct entry { + pub key: *mut c_char, + pub data: *mut c_void, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 126], + } + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_pad2: Padding, + __ss_pad3: Padding<[u8; 112]>, + } + pub struct dirent { + pub d_dev: dev_t, + pub d_pdev: dev_t, + pub d_ino: ino_t, + pub d_pino: i64, + pub d_reclen: c_ushort, + pub d_name: [c_char; 1024], // Max length is _POSIX_PATH_MAX + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: crate::sigval, + __unused1: Padding<*mut c_void>, // actually a function pointer + pub sigev_notify_attributes: *mut crate::pthread_attr_t, + } + + pub struct utmpx { + pub ut_type: c_short, + pub ut_tv: crate::timeval, + pub ut_id: [c_char; 8], + pub ut_pid: crate::pid_t, + pub ut_user: [c_char; 32], + pub ut_line: [c_char; 16], + pub ut_host: [c_char; 128], + __ut_reserved: Padding<[c_char; 64]>, + } +} + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const L_SET: c_int = SEEK_SET; +pub const L_INCR: c_int = SEEK_CUR; +pub const L_XTND: c_int = SEEK_END; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; + +pub const F_DUPFD: c_int = 0x0001; +pub const F_GETFD: c_int = 0x0002; +pub const F_SETFD: c_int = 0x0004; +pub const F_GETFL: c_int = 0x0008; +pub const F_SETFL: c_int = 0x0010; +pub const F_GETLK: c_int = 0x0020; +pub const F_SETLK: c_int = 0x0080; +pub const F_SETLKW: c_int = 0x0100; +pub const F_DUPFD_CLOEXEC: c_int = 0x0200; + +pub const F_RDLCK: c_int = 0x0040; +pub const F_UNLCK: c_int = 0x0200; +pub const F_WRLCK: c_int = 0x0400; + +pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x01; +pub const AT_SYMLINK_FOLLOW: c_int = 0x02; +pub const AT_REMOVEDIR: c_int = 0x04; +pub const AT_EACCESS: c_int = 0x08; + +pub const POLLIN: c_short = 0x0001; +pub const POLLOUT: c_short = 0x0002; +pub const POLLRDNORM: c_short = POLLIN; +pub const POLLWRNORM: c_short = POLLOUT; +pub const POLLRDBAND: c_short = 0x0008; +pub const POLLWRBAND: c_short = 0x0010; +pub const POLLPRI: c_short = 0x0020; +pub const POLLERR: c_short = 0x0004; +pub const POLLHUP: c_short = 0x0080; +pub const POLLNVAL: c_short = 0x1000; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +pub const CLOCK_REALTIME: c_int = -1; +pub const CLOCK_MONOTONIC: c_int = 0; +pub const CLOCK_PROCESS_CPUTIME_ID: c_int = -2; +pub const CLOCK_THREAD_CPUTIME_ID: c_int = -3; + +pub const RLIMIT_CORE: c_int = 0; +pub const RLIMIT_CPU: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_FSIZE: c_int = 3; +pub const RLIMIT_NOFILE: c_int = 4; +pub const RLIMIT_STACK: c_int = 5; +pub const RLIMIT_AS: c_int = 6; +pub const RLIM_INFINITY: crate::rlim_t = 0xffffffff; +// Haiku specific +pub const RLIMIT_NOVMON: c_int = 7; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 8; + +pub const RUSAGE_SELF: c_int = 0; + +pub const RTLD_LAZY: c_int = 0; + +pub const NCCS: usize = 11; + +pub const O_RDONLY: c_int = 0x0000; +pub const O_WRONLY: c_int = 0x0001; +pub const O_RDWR: c_int = 0x0002; +pub const O_ACCMODE: c_int = 0x0003; + +pub const O_EXCL: c_int = 0x0100; +pub const O_CREAT: c_int = 0x0200; +pub const O_TRUNC: c_int = 0x0400; +pub const O_NOCTTY: c_int = 0x1000; +pub const O_NOTRAVERSE: c_int = 0x2000; + +pub const O_CLOEXEC: c_int = 0x00000040; +pub const O_NONBLOCK: c_int = 0x00000080; +pub const O_APPEND: c_int = 0x00000800; +pub const O_SYNC: c_int = 0x00010000; +pub const O_RSYNC: c_int = 0x00020000; +pub const O_DSYNC: c_int = 0x00040000; +pub const O_NOFOLLOW: c_int = 0x00080000; +pub const O_NOCACHE: c_int = 0x00100000; +pub const O_DIRECTORY: c_int = 0x00200000; + +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; + +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; + +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; + +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGCHLD: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGPIPE: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSTOP: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGCONT: c_int = 12; +pub const SIGTSTP: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGTTIN: c_int = 16; +pub const SIGTTOU: c_int = 17; +pub const SIGUSR1: c_int = 18; +pub const SIGUSR2: c_int = 19; +pub const SIGWINCH: c_int = 20; +pub const SIGKILLTHR: c_int = 21; +pub const SIGTRAP: c_int = 22; +pub const SIGPOLL: c_int = 23; +pub const SIGPROF: c_int = 24; +pub const SIGSYS: c_int = 25; +pub const SIGURG: c_int = 26; +pub const SIGVTALRM: c_int = 27; +pub const SIGXCPU: c_int = 28; +pub const SIGXFSZ: c_int = 29; +pub const SIGBUS: c_int = 30; + +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 3; + +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const LC_ALL: c_int = 0; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; +pub const LC_MESSAGES: c_int = 6; + +// FIXME(haiku): Haiku does not have MAP_FILE, but library/std/os.rs requires it +pub const MAP_FILE: c_int = 0x00; +pub const MAP_SHARED: c_int = 0x01; +pub const MAP_PRIVATE: c_int = 0x02; +pub const MAP_FIXED: c_int = 0x04; +pub const MAP_ANONYMOUS: c_int = 0x08; +pub const MAP_NORESERVE: c_int = 0x10; +pub const MAP_ANON: c_int = MAP_ANONYMOUS; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const MS_ASYNC: c_int = 0x01; +pub const MS_INVALIDATE: c_int = 0x04; +pub const MS_SYNC: c_int = 0x02; + +pub const E2BIG: c_int = -2147454975; +pub const ECHILD: c_int = -2147454974; +pub const EDEADLK: c_int = -2147454973; +pub const EFBIG: c_int = -2147454972; +pub const EMLINK: c_int = -2147454971; +pub const ENFILE: c_int = -2147454970; +pub const ENODEV: c_int = -2147454969; +pub const ENOLCK: c_int = -2147454968; +pub const ENOSYS: c_int = -2147454967; +pub const ENOTTY: c_int = -2147454966; +pub const ENXIO: c_int = -2147454965; +pub const ESPIPE: c_int = -2147454964; +pub const ESRCH: c_int = -2147454963; +pub const EFPOS: c_int = -2147454962; +pub const ESIGPARM: c_int = -2147454961; +pub const EDOM: c_int = -2147454960; +pub const ERANGE: c_int = -2147454959; +pub const EPROTOTYPE: c_int = -2147454958; +pub const EPROTONOSUPPORT: c_int = -2147454957; +pub const EPFNOSUPPORT: c_int = -2147454956; +pub const EAFNOSUPPORT: c_int = -2147454955; +pub const EADDRINUSE: c_int = -2147454954; +pub const EADDRNOTAVAIL: c_int = -2147454953; +pub const ENETDOWN: c_int = -2147454952; +pub const ENETUNREACH: c_int = -2147454951; +pub const ENETRESET: c_int = -2147454950; +pub const ECONNABORTED: c_int = -2147454949; +pub const ECONNRESET: c_int = -2147454948; +pub const EISCONN: c_int = -2147454947; +pub const ENOTCONN: c_int = -2147454946; +pub const ESHUTDOWN: c_int = -2147454945; +pub const ECONNREFUSED: c_int = -2147454944; +pub const EHOSTUNREACH: c_int = -2147454943; +pub const ENOPROTOOPT: c_int = -2147454942; +pub const ENOBUFS: c_int = -2147454941; +pub const EINPROGRESS: c_int = -2147454940; +pub const EALREADY: c_int = -2147454939; +pub const EILSEQ: c_int = -2147454938; +pub const ENOMSG: c_int = -2147454937; +pub const ESTALE: c_int = -2147454936; +pub const EOVERFLOW: c_int = -2147454935; +pub const EMSGSIZE: c_int = -2147454934; +pub const EOPNOTSUPP: c_int = -2147454933; +pub const ENOTSOCK: c_int = -2147454932; +pub const EHOSTDOWN: c_int = -2147454931; +pub const EBADMSG: c_int = -2147454930; +pub const ECANCELED: c_int = -2147454929; +pub const EDESTADDRREQ: c_int = -2147454928; +pub const EDQUOT: c_int = -2147454927; +pub const EIDRM: c_int = -2147454926; +pub const EMULTIHOP: c_int = -2147454925; +pub const ENODATA: c_int = -2147454924; +pub const ENOLINK: c_int = -2147454923; +pub const ENOSR: c_int = -2147454922; +pub const ENOSTR: c_int = -2147454921; +pub const ENOTSUP: c_int = -2147454920; +pub const EPROTO: c_int = -2147454919; +pub const ETIME: c_int = -2147454918; +pub const ETXTBSY: c_int = -2147454917; +pub const ENOATTR: c_int = -2147454916; + +// INT_MIN +pub const ENOMEM: c_int = -2147483648; + +// POSIX errors that can be mapped to BeOS error codes +pub const EACCES: c_int = -2147483646; +pub const EINTR: c_int = -2147483638; +pub const EIO: c_int = -2147483647; +pub const EBUSY: c_int = -2147483634; +pub const EFAULT: c_int = -2147478783; +pub const ETIMEDOUT: c_int = -2147483639; +pub const EAGAIN: c_int = -2147483637; +pub const EWOULDBLOCK: c_int = -2147483637; +pub const EBADF: c_int = -2147459072; +pub const EEXIST: c_int = -2147459070; +pub const EINVAL: c_int = -2147483643; +pub const ENAMETOOLONG: c_int = -2147459068; +pub const ENOENT: c_int = -2147459069; +pub const EPERM: c_int = -2147483633; +pub const ENOTDIR: c_int = -2147459067; +pub const EISDIR: c_int = -2147459063; +pub const ENOTEMPTY: c_int = -2147459066; +pub const ENOSPC: c_int = -2147459065; +pub const EROFS: c_int = -2147459064; +pub const EMFILE: c_int = -2147459062; +pub const EXDEV: c_int = -2147459061; +pub const ELOOP: c_int = -2147459060; +pub const ENOEXEC: c_int = -2147478782; +pub const EPIPE: c_int = -2147459059; + +pub const IPPROTO_RAW: c_int = 255; + +// These are prefixed with POSIX_ on Haiku +pub const MADV_NORMAL: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_RANDOM: c_int = 3; +pub const MADV_WILLNEED: c_int = 4; +pub const MADV_DONTNEED: c_int = 5; +pub const MADV_FREE: c_int = 6; + +// https://github.com/haiku/haiku/blob/HEAD/headers/posix/net/if.h#L80 +pub const IFF_UP: c_int = 0x0001; +pub const IFF_BROADCAST: c_int = 0x0002; // valid broadcast address +pub const IFF_LOOPBACK: c_int = 0x0008; +pub const IFF_POINTOPOINT: c_int = 0x0010; // point-to-point link +pub const IFF_NOARP: c_int = 0x0040; // no address resolution +pub const IFF_AUTOUP: c_int = 0x0080; // auto dial +pub const IFF_PROMISC: c_int = 0x0100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x0200; // receive all multicast packets +pub const IFF_SIMPLEX: c_int = 0x0800; // doesn't receive own transmissions +pub const IFF_LINK: c_int = 0x1000; // has link +pub const IFF_AUTO_CONFIGURED: c_int = 0x2000; +pub const IFF_CONFIGURING: c_int = 0x4000; +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + +pub const AF_UNSPEC: c_int = 0; +pub const AF_INET: c_int = 1; +pub const AF_APPLETALK: c_int = 2; +pub const AF_ROUTE: c_int = 3; +pub const AF_LINK: c_int = 4; +pub const AF_INET6: c_int = 5; +pub const AF_DLI: c_int = 6; +pub const AF_IPX: c_int = 7; +pub const AF_NOTIFY: c_int = 8; +pub const AF_LOCAL: c_int = 9; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_BLUETOOTH: c_int = 10; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_INET: c_int = AF_INET; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; + +pub const IP_OPTIONS: c_int = 1; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_RECVOPTS: c_int = 5; +pub const IP_RECVRETOPTS: c_int = 6; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_RETOPTS: c_int = 8; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_BLOCK_SOURCE: c_int = 14; +pub const IP_UNBLOCK_SOURCE: c_int = 15; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 16; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 17; + +pub const TCP_NODELAY: c_int = 0x01; +pub const TCP_MAXSEG: c_int = 0x02; +pub const TCP_NOPUSH: c_int = 0x04; +pub const TCP_NOOPT: c_int = 0x08; + +pub const IF_NAMESIZE: size_t = 32; +pub const IFNAMSIZ: size_t = IF_NAMESIZE; + +pub const IPV6_MULTICAST_IF: c_int = 24; +pub const IPV6_MULTICAST_HOPS: c_int = 25; +pub const IPV6_MULTICAST_LOOP: c_int = 26; +pub const IPV6_UNICAST_HOPS: c_int = 27; +pub const IPV6_JOIN_GROUP: c_int = 28; +pub const IPV6_LEAVE_GROUP: c_int = 29; +pub const IPV6_V6ONLY: c_int = 30; +pub const IPV6_PKTINFO: c_int = 31; +pub const IPV6_RECVPKTINFO: c_int = 32; +pub const IPV6_HOPLIMIT: c_int = 33; +pub const IPV6_RECVHOPLIMIT: c_int = 34; +pub const IPV6_HOPOPTS: c_int = 35; +pub const IPV6_DSTOPTS: c_int = 36; +pub const IPV6_RTHDR: c_int = 37; + +pub const MSG_OOB: c_int = 0x0001; +pub const MSG_PEEK: c_int = 0x0002; +pub const MSG_DONTROUTE: c_int = 0x0004; +pub const MSG_EOR: c_int = 0x0008; +pub const MSG_TRUNC: c_int = 0x0010; +pub const MSG_CTRUNC: c_int = 0x0020; +pub const MSG_WAITALL: c_int = 0x0040; +pub const MSG_DONTWAIT: c_int = 0x0080; +pub const MSG_BCAST: c_int = 0x0100; +pub const MSG_MCAST: c_int = 0x0200; +pub const MSG_EOF: c_int = 0x0400; +pub const MSG_NOSIGNAL: c_int = 0x0800; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 0x01; +pub const LOCK_EX: c_int = 0x02; +pub const LOCK_NB: c_int = 0x04; +pub const LOCK_UN: c_int = 0x08; + +pub const MINSIGSTKSZ: size_t = 8192; +pub const SIGSTKSZ: size_t = 16384; + +pub const IOV_MAX: c_int = 1024; +pub const PATH_MAX: c_int = 1024; + +pub const SA_NOCLDSTOP: c_int = 0x01; +pub const SA_NOCLDWAIT: c_int = 0x02; +pub const SA_RESETHAND: c_int = 0x04; +pub const SA_NODEFER: c_int = 0x08; +pub const SA_RESTART: c_int = 0x10; +pub const SA_ONSTACK: c_int = 0x20; +pub const SA_SIGINFO: c_int = 0x40; +pub const SA_NOMASK: c_int = SA_NODEFER; +pub const SA_STACK: c_int = SA_ONSTACK; +pub const SA_ONESHOT: c_int = SA_RESETHAND; + +pub const SS_ONSTACK: c_int = 0x1; +pub const SS_DISABLE: c_int = 0x2; + +// DIFF(main): changed to `c_int` in 500365e1 +pub const FD_SETSIZE: usize = 1024; + +pub const RTLD_LOCAL: c_int = 0x0; +pub const RTLD_NOW: c_int = 0x1; +pub const RTLD_GLOBAL: c_int = 0x2; +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +pub const BUFSIZ: c_uint = 8192; +pub const FILENAME_MAX: c_uint = 256; +pub const FOPEN_MAX: c_uint = 128; +pub const L_tmpnam: c_uint = 512; +pub const TMP_MAX: c_uint = 32768; + +pub const _PC_CHOWN_RESTRICTED: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_NO_TRUNC: c_int = 5; +pub const _PC_PATH_MAX: c_int = 6; +pub const _PC_PIPE_BUF: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_LINK_MAX: c_int = 25; +pub const _PC_SYNC_IO: c_int = 26; +pub const _PC_ASYNC_IO: c_int = 27; +pub const _PC_PRIO_IO: c_int = 28; +pub const _PC_SOCK_MAXBUF: c_int = 29; +pub const _PC_FILESIZEBITS: c_int = 30; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 31; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 32; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 33; +pub const _PC_REC_XFER_ALIGN: c_int = 34; +pub const _PC_ALLOC_SIZE_MIN: c_int = 35; +pub const _PC_SYMLINK_MAX: c_int = 36; +pub const _PC_2_SYMLINKS: c_int = 37; +pub const _PC_XATTR_EXISTS: c_int = 38; +pub const _PC_XATTR_ENABLED: c_int = 39; + +pub const FIONBIO: c_ulong = 0xbe000000; +pub const FIONREAD: c_ulong = 0xbe000001; +pub const FIOSEEKDATA: c_ulong = 0xbe000002; +pub const FIOSEEKHOLE: c_ulong = 0xbe000003; + +pub const _SC_ARG_MAX: c_int = 15; +pub const _SC_CHILD_MAX: c_int = 16; +pub const _SC_CLK_TCK: c_int = 17; +pub const _SC_JOB_CONTROL: c_int = 18; +pub const _SC_NGROUPS_MAX: c_int = 19; +pub const _SC_OPEN_MAX: c_int = 20; +pub const _SC_SAVED_IDS: c_int = 21; +pub const _SC_STREAM_MAX: c_int = 22; +pub const _SC_TZNAME_MAX: c_int = 23; +pub const _SC_VERSION: c_int = 24; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 25; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 26; +pub const _SC_PAGESIZE: c_int = 27; +pub const _SC_PAGE_SIZE: c_int = 27; +pub const _SC_SEM_NSEMS_MAX: c_int = 28; +pub const _SC_SEM_VALUE_MAX: c_int = 29; +pub const _SC_SEMAPHORES: c_int = 30; +pub const _SC_THREADS: c_int = 31; +pub const _SC_IOV_MAX: c_int = 32; +pub const _SC_UIO_MAXIOV: c_int = 32; +pub const _SC_NPROCESSORS_CONF: c_int = 34; +pub const _SC_NPROCESSORS_ONLN: c_int = 35; +pub const _SC_ATEXIT_MAX: c_int = 37; +pub const _SC_PASS_MAX: c_int = 39; +pub const _SC_PHYS_PAGES: c_int = 40; +pub const _SC_AVPHYS_PAGES: c_int = 41; +pub const _SC_PIPE: c_int = 42; +pub const _SC_SELECT: c_int = 43; +pub const _SC_POLL: c_int = 44; +pub const _SC_MAPPED_FILES: c_int = 45; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 46; +pub const _SC_THREAD_STACK_MIN: c_int = 47; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 48; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 49; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 50; +pub const _SC_REALTIME_SIGNALS: c_int = 51; +pub const _SC_MEMORY_PROTECTION: c_int = 52; +pub const _SC_SIGQUEUE_MAX: c_int = 53; +pub const _SC_RTSIG_MAX: c_int = 54; +pub const _SC_MONOTONIC_CLOCK: c_int = 55; +pub const _SC_DELAYTIMER_MAX: c_int = 56; +pub const _SC_TIMER_MAX: c_int = 57; +pub const _SC_TIMERS: c_int = 58; +pub const _SC_CPUTIME: c_int = 59; +pub const _SC_THREAD_CPUTIME: c_int = 60; +pub const _SC_HOST_NAME_MAX: c_int = 61; +pub const _SC_REGEXP: c_int = 62; +pub const _SC_SYMLOOP_MAX: c_int = 63; +pub const _SC_SHELL: c_int = 64; +pub const _SC_TTY_NAME_MAX: c_int = 65; +pub const _SC_ADVISORY_INFO: c_int = 66; +pub const _SC_BARRIERS: c_int = 67; +pub const _SC_CLOCK_SELECTION: c_int = 68; +pub const _SC_FSYNC: c_int = 69; +pub const _SC_IPV6: c_int = 70; +pub const _SC_MEMLOCK: c_int = 71; +pub const _SC_MEMLOCK_RANGE: c_int = 72; +pub const _SC_MESSAGE_PASSING: c_int = 73; +pub const _SC_PRIORITIZED_IO: c_int = 74; +pub const _SC_PRIORITY_SCHEDULING: c_int = 75; +pub const _SC_READER_WRITER_LOCKS: c_int = 76; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 77; +pub const _SC_SPAWN: c_int = 78; +pub const _SC_SPIN_LOCKS: c_int = 79; +pub const _SC_SPORADIC_SERVER: c_int = 80; +pub const _SC_SYNCHRONIZED_IO: c_int = 81; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 82; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 83; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 84; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 85; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 86; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 87; +pub const _SC_TIMEOUTS: c_int = 88; +pub const _SC_TRACE: c_int = 89; +pub const _SC_TRACE_EVENT_FILTER: c_int = 90; +pub const _SC_TRACE_INHERIT: c_int = 91; +pub const _SC_TRACE_LOG: c_int = 92; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 93; +pub const _SC_V6_ILP32_OFF32: c_int = 94; +pub const _SC_V6_ILP32_OFFBIG: c_int = 95; +pub const _SC_V6_LP64_OFF64: c_int = 96; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 97; +pub const _SC_V7_ILP32_OFF32: c_int = 98; +pub const _SC_V7_ILP32_OFFBIG: c_int = 99; +pub const _SC_V7_LP64_OFF64: c_int = 100; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 101; +pub const _SC_2_C_BIND: c_int = 102; +pub const _SC_2_C_DEV: c_int = 103; +pub const _SC_2_CHAR_TERM: c_int = 104; +pub const _SC_2_FORT_DEV: c_int = 105; +pub const _SC_2_FORT_RUN: c_int = 106; +pub const _SC_2_LOCALEDEF: c_int = 107; +pub const _SC_2_PBS: c_int = 108; +pub const _SC_2_PBS_ACCOUNTING: c_int = 109; +pub const _SC_2_PBS_CHECKPOINT: c_int = 110; +pub const _SC_2_PBS_LOCATE: c_int = 111; +pub const _SC_2_PBS_MESSAGE: c_int = 112; +pub const _SC_2_PBS_TRACK: c_int = 113; +pub const _SC_2_SW_DEV: c_int = 114; +pub const _SC_2_UPE: c_int = 115; +pub const _SC_2_VERSION: c_int = 116; +pub const _SC_XOPEN_CRYPT: c_int = 117; +pub const _SC_XOPEN_ENH_I18N: c_int = 118; +pub const _SC_XOPEN_REALTIME: c_int = 119; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 120; +pub const _SC_XOPEN_SHM: c_int = 121; +pub const _SC_XOPEN_STREAMS: c_int = 122; +pub const _SC_XOPEN_UNIX: c_int = 123; +pub const _SC_XOPEN_UUCP: c_int = 124; +pub const _SC_XOPEN_VERSION: c_int = 125; +pub const _SC_BC_BASE_MAX: c_int = 129; +pub const _SC_BC_DIM_MAX: c_int = 130; +pub const _SC_BC_SCALE_MAX: c_int = 131; +pub const _SC_BC_STRING_MAX: c_int = 132; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 133; +pub const _SC_EXPR_NEST_MAX: c_int = 134; +pub const _SC_LINE_MAX: c_int = 135; +pub const _SC_LOGIN_NAME_MAX: c_int = 136; +pub const _SC_MQ_OPEN_MAX: c_int = 137; +pub const _SC_MQ_PRIO_MAX: c_int = 138; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 139; +pub const _SC_THREAD_KEYS_MAX: c_int = 140; +pub const _SC_THREAD_THREADS_MAX: c_int = 141; +pub const _SC_RE_DUP_MAX: c_int = 142; + +pub const PTHREAD_STACK_MIN: size_t = 8192; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + flags: 0, + lock: 0, + unused: Padding::new(0), + owner: -1, + owner_count: 0, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + flags: 0, + unused: Padding::new(0), + mutex: 0 as *mut _, + waiter_count: 0, + lock: 0, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + flags: 0, + owner: -1, + lock_sem: 0, + lock_count: 0, + reader_count: 0, + writer_count: 0, + waiters: [0 as *mut _; 2], +}; + +pub const PTHREAD_MUTEX_DEFAULT: c_int = 0; +pub const PTHREAD_MUTEX_NORMAL: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 3; + +pub const FIOCLEX: c_ulong = 0; // FIXME(haiku): does not exist on Haiku! + +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_NONBLOCK: c_int = 0x00040000; +pub const SOCK_CLOEXEC: c_int = 0x00080000; + +pub const SOL_SOCKET: c_int = -1; +pub const SO_ACCEPTCONN: c_int = 0x00000001; +pub const SO_BROADCAST: c_int = 0x00000002; +pub const SO_DEBUG: c_int = 0x00000004; +pub const SO_DONTROUTE: c_int = 0x00000008; +pub const SO_KEEPALIVE: c_int = 0x00000010; +pub const SO_OOBINLINE: c_int = 0x00000020; +pub const SO_REUSEADDR: c_int = 0x00000040; +pub const SO_REUSEPORT: c_int = 0x00000080; +pub const SO_USELOOPBACK: c_int = 0x00000100; +pub const SO_LINGER: c_int = 0x00000200; +pub const SO_SNDBUF: c_int = 0x40000001; +pub const SO_SNDLOWAT: c_int = 0x40000002; +pub const SO_SNDTIMEO: c_int = 0x40000003; +pub const SO_RCVBUF: c_int = 0x40000004; +pub const SO_RCVLOWAT: c_int = 0x40000005; +pub const SO_RCVTIMEO: c_int = 0x40000006; +pub const SO_ERROR: c_int = 0x40000007; +pub const SO_TYPE: c_int = 0x40000008; +pub const SO_NONBLOCK: c_int = 0x40000009; +pub const SO_BINDTODEVICE: c_int = 0x4000000a; +pub const SO_PEERCRED: c_int = 0x4000000b; + +pub const SCM_RIGHTS: c_int = 0x01; + +pub const SOMAXCONN: c_int = 32; + +pub const NI_MAXHOST: size_t = 1025; + +pub const WNOHANG: c_int = 0x01; +pub const WUNTRACED: c_int = 0x02; +pub const WCONTINUED: c_int = 0x04; +pub const WEXITED: c_int = 0x08; +pub const WSTOPPED: c_int = 0x10; +pub const WNOWAIT: c_int = 0x20; + +// si_code values for SIGBUS signal +pub const BUS_ADRALN: c_int = 40; +pub const BUS_ADRERR: c_int = 41; +pub const BUS_OBJERR: c_int = 42; + +// si_code values for SIGCHLD signal +pub const CLD_EXITED: c_int = 60; +pub const CLD_KILLED: c_int = 61; +pub const CLD_DUMPED: c_int = 62; +pub const CLD_TRAPPED: c_int = 63; +pub const CLD_STOPPED: c_int = 64; +pub const CLD_CONTINUED: c_int = 65; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = 1000000001; +pub const UTIME_NOW: c_long = 1000000000; + +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VEOL: usize = 5; +pub const VMIN: usize = 4; +pub const VTIME: usize = 5; +pub const VEOL2: usize = 6; +pub const VSWTCH: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; + +pub const IGNBRK: crate::tcflag_t = 0x01; +pub const BRKINT: crate::tcflag_t = 0x02; +pub const IGNPAR: crate::tcflag_t = 0x04; +pub const PARMRK: crate::tcflag_t = 0x08; +pub const INPCK: crate::tcflag_t = 0x10; +pub const ISTRIP: crate::tcflag_t = 0x20; +pub const INLCR: crate::tcflag_t = 0x40; +pub const IGNCR: crate::tcflag_t = 0x80; +pub const ICRNL: crate::tcflag_t = 0x100; +pub const IUCLC: crate::tcflag_t = 0x200; +pub const IXON: crate::tcflag_t = 0x400; +pub const IXANY: crate::tcflag_t = 0x800; +pub const IXOFF: crate::tcflag_t = 0x1000; + +pub const OPOST: crate::tcflag_t = 0x00000001; +pub const OLCUC: crate::tcflag_t = 0x00000002; +pub const ONLCR: crate::tcflag_t = 0x00000004; +pub const OCRNL: crate::tcflag_t = 0x00000008; +pub const ONOCR: crate::tcflag_t = 0x00000010; +pub const ONLRET: crate::tcflag_t = 0x00000020; +pub const OFILL: crate::tcflag_t = 0x00000040; +pub const OFDEL: crate::tcflag_t = 0x00000080; +pub const NLDLY: crate::tcflag_t = 0x00000100; +pub const NL0: crate::tcflag_t = 0x00000000; +pub const NL1: crate::tcflag_t = 0x00000100; +pub const CRDLY: crate::tcflag_t = 0x00000600; +pub const CR0: crate::tcflag_t = 0x00000000; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const TABDLY: crate::tcflag_t = 0x00001800; +pub const TAB0: crate::tcflag_t = 0x00000000; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const BSDLY: crate::tcflag_t = 0x00002000; +pub const BS0: crate::tcflag_t = 0x00000000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VTDLY: crate::tcflag_t = 0x00004000; +pub const VT0: crate::tcflag_t = 0x00000000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const FFDLY: crate::tcflag_t = 0x00008000; +pub const FF0: crate::tcflag_t = 0x00000000; +pub const FF1: crate::tcflag_t = 0x00008000; + +pub const CSIZE: crate::tcflag_t = 0x00000020; +pub const CS5: crate::tcflag_t = 0x00000000; +pub const CS6: crate::tcflag_t = 0x00000000; +pub const CS7: crate::tcflag_t = 0x00000000; +pub const CS8: crate::tcflag_t = 0x00000020; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const XLOBLK: crate::tcflag_t = 0x00001000; +pub const CTSFLOW: crate::tcflag_t = 0x00002000; +pub const RTSFLOW: crate::tcflag_t = 0x00004000; +pub const CRTSCTS: crate::tcflag_t = RTSFLOW | CTSFLOW; + +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const XCASE: crate::tcflag_t = 0x00000004; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const IEXTEN: crate::tcflag_t = 0x00000200; +pub const ECHOCTL: crate::tcflag_t = 0x00000400; +pub const ECHOPRT: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00001000; +pub const FLUSHO: crate::tcflag_t = 0x00002000; +pub const PENDIN: crate::tcflag_t = 0x00004000; + +pub const TCGB_CTS: c_int = 0x01; +pub const TCGB_DSR: c_int = 0x02; +pub const TCGB_RI: c_int = 0x04; +pub const TCGB_DCD: c_int = 0x08; +pub const TIOCM_CTS: c_int = TCGB_CTS; +pub const TIOCM_CD: c_int = TCGB_DCD; +pub const TIOCM_CAR: c_int = TCGB_DCD; +pub const TIOCM_RI: c_int = TCGB_RI; +pub const TIOCM_RNG: c_int = TCGB_RI; +pub const TIOCM_DSR: c_int = TCGB_DSR; +pub const TIOCM_DTR: c_int = 0x10; +pub const TIOCM_RTS: c_int = 0x20; + +pub const B0: speed_t = 0x00; +pub const B50: speed_t = 0x01; +pub const B75: speed_t = 0x02; +pub const B110: speed_t = 0x03; +pub const B134: speed_t = 0x04; +pub const B150: speed_t = 0x05; +pub const B200: speed_t = 0x06; +pub const B300: speed_t = 0x07; +pub const B600: speed_t = 0x08; +pub const B1200: speed_t = 0x09; +pub const B1800: speed_t = 0x0A; +pub const B2400: speed_t = 0x0B; +pub const B4800: speed_t = 0x0C; +pub const B9600: speed_t = 0x0D; +pub const B19200: speed_t = 0x0E; +pub const B38400: speed_t = 0x0F; +pub const B57600: speed_t = 0x10; +pub const B115200: speed_t = 0x11; +pub const B230400: speed_t = 0x12; +pub const B31250: speed_t = 0x13; + +pub const TCSANOW: c_int = 0x01; +pub const TCSADRAIN: c_int = 0x02; +pub const TCSAFLUSH: c_int = 0x04; + +pub const TCOOFF: c_int = 0x01; +pub const TCOON: c_int = 0x02; +pub const TCIOFF: c_int = 0x04; +pub const TCION: c_int = 0x08; + +pub const TCIFLUSH: c_int = 0x01; +pub const TCOFLUSH: c_int = 0x02; +pub const TCIOFLUSH: c_int = 0x03; + +pub const TCGETA: c_ulong = 0x8000; +pub const TCSETA: c_ulong = TCGETA + 1; +pub const TCSETAF: c_ulong = TCGETA + 2; +pub const TCSETAW: c_ulong = TCGETA + 3; +pub const TCSBRK: c_ulong = TCGETA + 5; +pub const TCFLSH: c_ulong = TCGETA + 6; +pub const TCXONC: c_ulong = TCGETA + 7; +pub const TCGETBITS: c_ulong = TCGETA + 9; +pub const TCSETDTR: c_ulong = TCGETA + 10; +pub const TCSETRTS: c_ulong = TCGETA + 11; +pub const TIOCGWINSZ: c_ulong = TCGETA + 12; +pub const TIOCSWINSZ: c_ulong = TCGETA + 13; +pub const TIOCGPGRP: c_ulong = TCGETA + 15; +pub const TIOCSPGRP: c_ulong = TCGETA + 16; +pub const TIOCSCTTY: c_ulong = TCGETA + 17; +pub const TIOCMGET: c_ulong = TCGETA + 18; +pub const TIOCMSET: c_ulong = TCGETA + 19; +pub const TIOCSBRK: c_ulong = TCGETA + 20; +pub const TIOCCBRK: c_ulong = TCGETA + 21; +pub const TIOCMBIS: c_ulong = TCGETA + 22; +pub const TIOCMBIC: c_ulong = TCGETA + 23; +pub const TIOCGSID: c_ulong = TCGETA + 24; +pub const TIOCOUTQ: c_ulong = TCGETA + 25; +pub const TIOCEXCL: c_ulong = TCGETA + 26; +pub const TIOCNXCL: c_ulong = TCGETA + 27; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +// utmpx entry types +pub const EMPTY: c_short = 0; +pub const BOOT_TIME: c_short = 1; +pub const OLD_TIME: c_short = 2; +pub const NEW_TIME: c_short = 3; +pub const USER_PROCESS: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const DEAD_PROCESS: c_short = 7; + +pub const LOG_PID: c_int = 1 << 12; +pub const LOG_CONS: c_int = 2 << 12; +pub const LOG_ODELAY: c_int = 4 << 12; +pub const LOG_NDELAY: c_int = 8 << 12; +pub const LOG_SERIAL: c_int = 16 << 12; +pub const LOG_PERROR: c_int = 32 << 12; +pub const LOG_NOWAIT: c_int = 64 << 12; + +// spawn.h +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x02; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x10; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x20; +pub const POSIX_SPAWN_SETSID: c_int = 0x40; + +const fn CMSG_ALIGN(len: usize) -> usize { + len + size_of::() - 1 & !(size_of::() - 1) +} + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(CMSG_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + CMSG_ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let next = cmsg as usize + + CMSG_ALIGN((*cmsg).cmsg_len as usize) + + CMSG_ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next > max { + core::ptr::null_mut::() + } else { + (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +safe_f! { + pub const fn WIFEXITED(status: c_int) -> bool { + (status & !0xff) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + status & 0xff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status >> 8) & 0xff) != 0 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + ((status >> 16) & 0xff) != 0 + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 16) & 0xff + } + + // actually WIFCORED, but this is used everywhere else + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x10000) != 0 + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + (status & 0x20000) != 0 + } +} + +extern "C" { + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + pub fn getpriority(which: c_int, who: id_t) -> c_int; + pub fn setpriority(which: c_int, who: id_t, priority: c_int) -> c_int; + + pub fn endusershell(); + pub fn getpass(prompt: *const c_char) -> *mut c_char; + pub fn getusershell() -> *mut c_char; + pub fn issetugid() -> c_int; + pub fn setusershell(); + + pub fn utimensat( + fd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn _errnop() -> *mut c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + pub fn ppoll( + fds: *mut crate::pollfd, + numfds: crate::nfds_t, + timeout: *const crate::timespec, + sigMask: *const sigset_t, + ) -> c_int; + + pub fn getspent() -> *mut spwd; + pub fn getspent_r( + pwd: *mut spwd, + buf: *mut c_char, + bufferSize: size_t, + res: *mut *mut spwd, + ) -> c_int; + pub fn setspent(); + pub fn endspent(); + pub fn getspnam(name: *const c_char) -> *mut spwd; + pub fn getspnam_r( + name: *const c_char, + spwd: *mut spwd, + buffer: *mut c_char, + bufferSize: size_t, + res: *mut *mut spwd, + ) -> c_int; + pub fn sgetspent(line: *const c_char) -> *mut spwd; + pub fn sgetspent_r( + line: *const c_char, + spwd: *mut spwd, + buffer: *mut c_char, + bufferSize: size_t, + res: *mut *mut spwd, + ) -> c_int; + pub fn fgetspent(file: *mut crate::FILE) -> *mut spwd; + pub fn fgetspent_r( + file: *mut crate::FILE, + spwd: *mut spwd, + buffer: *mut c_char, + bufferSize: size_t, + res: *mut *mut spwd, + ) -> c_int; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + pub fn pthread_create( + thread: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn valloc(numBytes: size_t) -> *mut c_void; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn setgroups(ngroups: c_int, ptr: *const crate::gid_t) -> c_int; + pub fn initgroups(name: *const c_char, basegid: crate::gid_t) -> c_int; + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_sigqueue(thread: crate::pthread_t, sig: c_int, value: crate::sigval) -> c_int; + pub fn pthread_spin_init(lock: *mut crate::pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advice: c_int) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + pub fn accept4( + socket: c_int, + address: *mut crate::sockaddr, + addressLength: *mut crate::socklen_t, + flags: c_int, + ) -> c_int; + + pub fn writev(fd: c_int, iov: *const crate::iovec, count: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, count: c_int) -> ssize_t; + + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + environment: *const *const c_char, + ) -> c_int; + + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrouplist( + user: *const c_char, + basegroup: crate::gid_t, + grouplist: *mut crate::gid_t, + groupcount: *mut c_int, + ) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwent() -> *mut passwd; + pub fn setpwent(); + pub fn endpwent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + pub fn setgrent(); + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + + pub fn getitimer(which: c_int, curr_value: *mut crate::itimerval) -> c_int; + pub fn setitimer( + which: c_int, + new_value: *const crate::itimerval, + old_value: *mut crate::itimerval, + ) -> c_int; + + pub fn regcomp(preg: *mut regex_t, pattern: *const c_char, cflags: c_int) -> c_int; + + pub fn regexec( + preg: *const regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + + pub fn regerror( + errcode: c_int, + preg: *const regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + + pub fn regfree(preg: *mut regex_t); + + pub fn msgctl(msqid: c_int, cmd: c_int, buf: *mut msqid_ds) -> c_int; + pub fn msgget(key: crate::key_t, msgflg: c_int) -> c_int; + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtype: c_long, + msgflg: c_int, + ) -> ssize_t; + pub fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: size_t, msgflg: c_int) -> c_int; + pub fn semget(key: crate::key_t, nsems: c_int, semflg: c_int) -> c_int; + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + pub fn semop(semid: c_int, sops: *mut sembuf, nsops: size_t) -> c_int; + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> crate::key_t; + + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn lsearch( + key: *const c_void, + base: *mut c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + pub fn lfind( + key: *const c_void, + base: *const c_void, + nelp: *mut size_t, + width: size_t, + compar: Option c_int>, + ) -> *mut c_void; + pub fn hcreate(nelt: size_t) -> c_int; + pub fn hdestroy(); + pub fn hsearch(entry: crate::ENTRY, action: crate::ACTION) -> *mut crate::ENTRY; + + pub fn drand48() -> c_double; + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn lrand48() -> c_long; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn mrand48() -> c_long; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn srand48(seed: c_long); + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn lcong48(p: *mut c_ushort); + + pub fn clearenv() -> c_int; + pub fn ctermid(s: *mut c_char) -> *mut c_char; + + pub fn sync(); + pub fn getpagesize() -> c_int; + + pub fn brk(addr: *mut c_void) -> c_int; + pub fn sbrk(increment: intptr_t) -> *mut c_void; + + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(file_actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(file_actions: *mut posix_spawn_file_actions_t) + -> c_int; + pub fn posix_spawn_file_actions_addopen( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + newfildes: c_int, + ) -> c_int; + + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, _flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + _pgroup: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, pgroup: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + sigdefault: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + sigdefault: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + _sigmask: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + sigmask: *const crate::sigset_t, + ) -> c_int; + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + pub fn strcasecmp_l( + string1: *const c_char, + string2: *const c_char, + locale: crate::locale_t, + ) -> c_int; + pub fn strncasecmp_l( + string1: *const c_char, + string2: *const c_char, + length: size_t, + locale: crate::locale_t, + ) -> c_int; + + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; +} + +#[link(name = "gnu")] +extern "C" { + pub fn memmem( + source: *const c_void, + sourceLength: size_t, + search: *const c_void, + searchLength: size_t, + ) -> *mut c_void; + + pub fn pthread_getattr_np(thread: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_getname_np( + thread: crate::pthread_t, + buffer: *mut c_char, + length: size_t, + ) -> c_int; + pub fn pthread_setname_np(thread: crate::pthread_t, name: *const c_char) -> c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + mod b32; + pub use self::b32::*; + } +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + // TODO + // mod x86; + // pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + // TODO + // mod aarch64; + // pub use self::aarch64::*; + } +} + +mod bsd; +pub use self::bsd::*; + +mod native; +pub use self::native::*; diff --git a/deps/crates/vendor/libc/src/unix/haiku/native.rs b/deps/crates/vendor/libc/src/unix/haiku/native.rs new file mode 100644 index 00000000000000..99ceab8a7519bf --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/native.rs @@ -0,0 +1,1390 @@ +use crate::off_t; +use crate::prelude::*; + +// This file follows the Haiku API for Haiku R1 beta 5. It is organized by the +// C/C++ header files in which the concepts can be found, while adhering to the +// style guide for this crate. + +// Helper macro to generate u32 constants. The Haiku API uses (non-standard) +// multi-character constants (like 'UPDA' or 'MSGM') to represent 32 bit +// integer constants. + +macro_rules! haiku_constant { + ($a:tt, $b:tt, $c:tt, $d:tt) => { + (($a as u32) << 24) + (($b as u32) << 16) + (($c as u32) << 8) + ($d as u32) + }; +} + +// support/SupportDefs.h +pub type status_t = i32; +pub type bigtime_t = i64; +pub type nanotime_t = i64; +pub type type_code = u32; +pub type perform_code = u32; + +// kernel/OS.h +pub type area_id = i32; +pub type port_id = i32; +pub type sem_id = i32; +pub type team_id = i32; +pub type thread_id = i32; + +pub type thread_func = extern "C" fn(*mut c_void) -> status_t; + +// kernel/image.h +pub type image_id = i32; + +c_enum! { + // kernel/OS.h + pub enum thread_state { + pub B_THREAD_RUNNING = 1, + pub B_THREAD_READY, + pub B_THREAD_RECEIVING, + pub B_THREAD_ASLEEP, + pub B_THREAD_SUSPENDED, + pub B_THREAD_WAITING, + } + + // kernel/image.h + pub enum image_type { + pub B_APP_IMAGE = 1, + pub B_LIBRARY_IMAGE, + pub B_ADD_ON_IMAGE, + pub B_SYSTEM_IMAGE, + } + + // kernel/scheduler.h + + pub enum be_task_flags { + pub B_DEFAULT_MEDIA_PRIORITY = 0x000, + pub B_OFFLINE_PROCESSING = 0x001, + pub B_STATUS_RENDERING = 0x002, + pub B_USER_INPUT_HANDLING = 0x004, + pub B_LIVE_VIDEO_MANIPULATION = 0x008, + pub B_VIDEO_PLAYBACK = 0x010, + pub B_VIDEO_RECORDING = 0x020, + pub B_LIVE_AUDIO_MANIPULATION = 0x040, + pub B_AUDIO_PLAYBACK = 0x080, + pub B_AUDIO_RECORDING = 0x100, + pub B_LIVE_3D_RENDERING = 0x200, + pub B_NUMBER_CRUNCHING = 0x400, + pub B_MIDI_PROCESSING = 0x800, + } + + pub enum schduler_mode { + pub SCHEDULER_MODE_LOW_LATENCY, + pub SCHEDULER_MODE_POWER_SAVING, + } + + // FindDirectory.h + pub enum path_base_directory { + pub B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY, + pub B_FIND_PATH_ADD_ONS_DIRECTORY, + pub B_FIND_PATH_APPS_DIRECTORY, + pub B_FIND_PATH_BIN_DIRECTORY, + pub B_FIND_PATH_BOOT_DIRECTORY, + pub B_FIND_PATH_CACHE_DIRECTORY, + pub B_FIND_PATH_DATA_DIRECTORY, + pub B_FIND_PATH_DEVELOP_DIRECTORY, + pub B_FIND_PATH_DEVELOP_LIB_DIRECTORY, + pub B_FIND_PATH_DOCUMENTATION_DIRECTORY, + pub B_FIND_PATH_ETC_DIRECTORY, + pub B_FIND_PATH_FONTS_DIRECTORY, + pub B_FIND_PATH_HEADERS_DIRECTORY, + pub B_FIND_PATH_LIB_DIRECTORY, + pub B_FIND_PATH_LOG_DIRECTORY, + pub B_FIND_PATH_MEDIA_NODES_DIRECTORY, + pub B_FIND_PATH_PACKAGES_DIRECTORY, + pub B_FIND_PATH_PREFERENCES_DIRECTORY, + pub B_FIND_PATH_SERVERS_DIRECTORY, + pub B_FIND_PATH_SETTINGS_DIRECTORY, + pub B_FIND_PATH_SOUNDS_DIRECTORY, + pub B_FIND_PATH_SPOOL_DIRECTORY, + pub B_FIND_PATH_TRANSLATORS_DIRECTORY, + pub B_FIND_PATH_VAR_DIRECTORY, + pub B_FIND_PATH_IMAGE_PATH = 1000, + pub B_FIND_PATH_PACKAGE_PATH, + } + + pub enum directory_which { + pub B_DESKTOP_DIRECTORY = 0, + pub B_TRASH_DIRECTORY, + pub B_SYSTEM_DIRECTORY = 1000, + pub B_SYSTEM_ADDONS_DIRECTORY = 1002, + pub B_SYSTEM_BOOT_DIRECTORY, + pub B_SYSTEM_FONTS_DIRECTORY, + pub B_SYSTEM_LIB_DIRECTORY, + pub B_SYSTEM_SERVERS_DIRECTORY, + pub B_SYSTEM_APPS_DIRECTORY, + pub B_SYSTEM_BIN_DIRECTORY, + pub B_SYSTEM_DOCUMENTATION_DIRECTORY = 1010, + pub B_SYSTEM_PREFERENCES_DIRECTORY, + pub B_SYSTEM_TRANSLATORS_DIRECTORY, + pub B_SYSTEM_MEDIA_NODES_DIRECTORY, + pub B_SYSTEM_SOUNDS_DIRECTORY, + pub B_SYSTEM_DATA_DIRECTORY, + pub B_SYSTEM_DEVELOP_DIRECTORY, + pub B_SYSTEM_PACKAGES_DIRECTORY, + pub B_SYSTEM_HEADERS_DIRECTORY, + pub B_SYSTEM_ETC_DIRECTORY = 2008, + pub B_SYSTEM_SETTINGS_DIRECTORY = 2010, + pub B_SYSTEM_LOG_DIRECTORY = 2012, + pub B_SYSTEM_SPOOL_DIRECTORY, + pub B_SYSTEM_TEMP_DIRECTORY, + pub B_SYSTEM_VAR_DIRECTORY, + pub B_SYSTEM_CACHE_DIRECTORY = 2020, + pub B_SYSTEM_NONPACKAGED_DIRECTORY = 2023, + pub B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_BIN_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_DATA_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_LIB_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY, + pub B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY, + pub B_USER_DIRECTORY = 3000, + pub B_USER_CONFIG_DIRECTORY, + pub B_USER_ADDONS_DIRECTORY, + pub B_USER_BOOT_DIRECTORY, + pub B_USER_FONTS_DIRECTORY, + pub B_USER_LIB_DIRECTORY, + pub B_USER_SETTINGS_DIRECTORY, + pub B_USER_DESKBAR_DIRECTORY, + pub B_USER_PRINTERS_DIRECTORY, + pub B_USER_TRANSLATORS_DIRECTORY, + pub B_USER_MEDIA_NODES_DIRECTORY, + pub B_USER_SOUNDS_DIRECTORY, + pub B_USER_DATA_DIRECTORY, + pub B_USER_CACHE_DIRECTORY, + pub B_USER_PACKAGES_DIRECTORY, + pub B_USER_HEADERS_DIRECTORY, + pub B_USER_NONPACKAGED_DIRECTORY, + pub B_USER_NONPACKAGED_ADDONS_DIRECTORY, + pub B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY, + pub B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY, + pub B_USER_NONPACKAGED_BIN_DIRECTORY, + pub B_USER_NONPACKAGED_DATA_DIRECTORY, + pub B_USER_NONPACKAGED_FONTS_DIRECTORY, + pub B_USER_NONPACKAGED_SOUNDS_DIRECTORY, + pub B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY, + pub B_USER_NONPACKAGED_LIB_DIRECTORY, + pub B_USER_NONPACKAGED_HEADERS_DIRECTORY, + pub B_USER_NONPACKAGED_DEVELOP_DIRECTORY, + pub B_USER_DEVELOP_DIRECTORY, + pub B_USER_DOCUMENTATION_DIRECTORY, + pub B_USER_SERVERS_DIRECTORY, + pub B_USER_APPS_DIRECTORY, + pub B_USER_BIN_DIRECTORY, + pub B_USER_PREFERENCES_DIRECTORY, + pub B_USER_ETC_DIRECTORY, + pub B_USER_LOG_DIRECTORY, + pub B_USER_SPOOL_DIRECTORY, + pub B_USER_VAR_DIRECTORY, + pub B_APPS_DIRECTORY = 4000, + pub B_PREFERENCES_DIRECTORY, + pub B_UTILITIES_DIRECTORY, + pub B_PACKAGE_LINKS_DIRECTORY, + } + + // kernel/OS.h + + pub enum topology_level_type { + pub B_TOPOLOGY_UNKNOWN, + pub B_TOPOLOGY_ROOT, + pub B_TOPOLOGY_SMT, + pub B_TOPOLOGY_CORE, + pub B_TOPOLOGY_PACKAGE, + } + + pub enum cpu_platform { + pub B_CPU_UNKNOWN, + pub B_CPU_x86, + pub B_CPU_x86_64, + pub B_CPU_PPC, + pub B_CPU_PPC_64, + pub B_CPU_M68K, + pub B_CPU_ARM, + pub B_CPU_ARM_64, + pub B_CPU_ALPHA, + pub B_CPU_MIPS, + pub B_CPU_SH, + pub B_CPU_SPARC, + pub B_CPU_RISC_V, + } + + pub enum cpu_vendor { + pub B_CPU_VENDOR_UNKNOWN, + pub B_CPU_VENDOR_AMD, + pub B_CPU_VENDOR_CYRIX, + pub B_CPU_VENDOR_IDT, + pub B_CPU_VENDOR_INTEL, + pub B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR, + pub B_CPU_VENDOR_RISE, + pub B_CPU_VENDOR_TRANSMETA, + pub B_CPU_VENDOR_VIA, + pub B_CPU_VENDOR_IBM, + pub B_CPU_VENDOR_MOTOROLA, + pub B_CPU_VENDOR_NEC, + pub B_CPU_VENDOR_HYGON, + pub B_CPU_VENDOR_SUN, + pub B_CPU_VENDOR_FUJITSU, + } +} + +s! { + // kernel/OS.h + pub struct area_info { + pub area: area_id, + pub name: [c_char; B_OS_NAME_LENGTH], + pub size: usize, + pub lock: u32, + pub protection: u32, + pub team: team_id, + pub ram_size: u32, + pub copy_count: u32, + pub in_count: u32, + pub out_count: u32, + pub address: *mut c_void, + } + + pub struct port_info { + pub port: port_id, + pub team: team_id, + pub name: [c_char; B_OS_NAME_LENGTH], + pub capacity: i32, + pub queue_count: i32, + pub total_count: i32, + } + + pub struct port_message_info { + pub size: size_t, + pub sender: crate::uid_t, + pub sender_group: crate::gid_t, + pub sender_team: crate::team_id, + } + + pub struct team_info { + pub team: team_id, + pub thread_count: i32, + pub image_count: i32, + pub area_count: i32, + pub debugger_nub_thread: thread_id, + pub debugger_nub_port: port_id, + pub argc: i32, + pub args: [c_char; 64], + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } + + pub struct sem_info { + pub sem: sem_id, + pub team: team_id, + pub name: [c_char; B_OS_NAME_LENGTH], + pub count: i32, + pub latest_holder: thread_id, + } + + pub struct team_usage_info { + pub user_time: bigtime_t, + pub kernel_time: bigtime_t, + } + + pub struct thread_info { + pub thread: thread_id, + pub team: team_id, + pub name: [c_char; B_OS_NAME_LENGTH], + pub state: thread_state, + pub priority: i32, + pub sem: sem_id, + pub user_time: bigtime_t, + pub kernel_time: bigtime_t, + pub stack_base: *mut c_void, + pub stack_end: *mut c_void, + } + + pub struct cpu_info { + pub active_time: bigtime_t, + pub enabled: bool, + pub current_frequency: u64, + } + + pub struct system_info { + pub boot_time: bigtime_t, + pub cpu_count: u32, + pub max_pages: u64, + pub used_pages: u64, + pub cached_pages: u64, + pub block_cache_pages: u64, + pub ignored_pages: u64, + pub needed_memory: u64, + pub free_memory: u64, + pub max_swap_pages: u64, + pub free_swap_pages: u64, + pub page_faults: u32, + pub max_sems: u32, + pub used_sems: u32, + pub max_ports: u32, + pub used_ports: u32, + pub max_threads: u32, + pub used_threads: u32, + pub max_teams: u32, + pub used_teams: u32, + pub kernel_name: [c_char; B_FILE_NAME_LENGTH], + pub kernel_build_date: [c_char; B_OS_NAME_LENGTH], + pub kernel_build_time: [c_char; B_OS_NAME_LENGTH], + pub kernel_version: i64, + pub abi: u32, + } + + pub struct object_wait_info { + pub object: i32, + pub type_: u16, + pub events: u16, + } + + pub struct cpu_topology_root_info { + pub platform: cpu_platform, + } + + pub struct cpu_topology_package_info { + pub vendor: cpu_vendor, + pub cache_line_size: u32, + } + + pub struct cpu_topology_core_info { + pub model: u32, + pub default_frequency: u64, + } + // kernel/fs_attr.h + pub struct attr_info { + pub type_: u32, + pub size: off_t, + } + + // kernel/fs_index.h + pub struct index_info { + pub type_: u32, + pub size: off_t, + pub modification_time: crate::time_t, + pub creation_time: crate::time_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } + + //kernel/fs_info.h + pub struct fs_info { + pub dev: crate::dev_t, + pub root: crate::ino_t, + pub flags: u32, + pub block_size: off_t, + pub io_size: off_t, + pub total_blocks: off_t, + pub free_blocks: off_t, + pub total_nodes: off_t, + pub free_nodes: off_t, + pub device_name: [c_char; 128], + pub volume_name: [c_char; B_FILE_NAME_LENGTH], + pub fsh_name: [c_char; B_OS_NAME_LENGTH], + } + + // kernel/image.h + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct image_info { + pub id: image_id, + pub image_type: c_int, + pub sequence: i32, + pub init_order: i32, + // FIXME(1.0): these should be made optional + pub init_routine: extern "C" fn(), + pub term_routine: extern "C" fn(), + pub device: crate::dev_t, + pub node: crate::ino_t, + pub name: [c_char; crate::PATH_MAX as usize], + pub text: *mut c_void, + pub data: *mut c_void, + pub text_size: i32, + pub data_size: i32, + pub api_version: i32, + pub abi: i32, + } + + pub struct __c_anonymous_eax_0 { + pub max_eax: u32, + pub vendor_id: [c_char; 12], + } + + pub struct __c_anonymous_eax_1 { + pub stepping: u32, + pub model: u32, + pub family: u32, + pub tpe: u32, + __reserved_0: Padding, + pub extended_model: u32, + pub extended_family: u32, + __reserved_1: Padding, + pub brand_index: u32, + pub clflush: u32, + pub logical_cpus: u32, + pub apic_id: u32, + pub features: u32, + pub extended_features: u32, + } + + pub struct __c_anonymous_eax_2 { + pub call_num: u8, + pub cache_descriptors: [u8; 15], + } + + pub struct __c_anonymous_eax_3 { + __reserved: Padding<[u32; 2]>, + pub serial_number_high: u32, + pub serial_number_low: u32, + } + + pub struct __c_anonymous_regs { + pub eax: u32, + pub ebx: u32, + pub edx: u32, + pub ecx: u32, + } + + pub struct cpu_topology_node_info { + pub id: u32, + pub type_: topology_level_type, + pub level: u32, + pub data: __c_anonymous_cpu_topology_info_data, + } +} + +s_no_extra_traits! { + pub union cpuid_info { + pub eax_0: __c_anonymous_eax_0, + pub eax_1: __c_anonymous_eax_1, + pub eax_2: __c_anonymous_eax_2, + pub eax_3: __c_anonymous_eax_3, + pub as_chars: [c_char; 16], + pub regs: __c_anonymous_regs, + } + + pub union __c_anonymous_cpu_topology_info_data { + pub root: cpu_topology_root_info, + pub package: cpu_topology_package_info, + pub core: cpu_topology_core_info, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for cpuid_info { + fn eq(&self, other: &cpuid_info) -> bool { + unsafe { + self.eax_0 == other.eax_0 + || self.eax_1 == other.eax_1 + || self.eax_2 == other.eax_2 + || self.eax_3 == other.eax_3 + || self.as_chars == other.as_chars + || self.regs == other.regs + } + } + } + impl Eq for cpuid_info {} + impl hash::Hash for cpuid_info { + fn hash(&self, _state: &mut H) { + unimplemented!("traits"); + } + } + + impl PartialEq for __c_anonymous_cpu_topology_info_data { + fn eq(&self, other: &__c_anonymous_cpu_topology_info_data) -> bool { + unsafe { + self.root == other.root + || self.package == other.package + || self.core == other.core + } + } + } + impl Eq for __c_anonymous_cpu_topology_info_data {} + impl hash::Hash for __c_anonymous_cpu_topology_info_data { + fn hash(&self, _state: &mut H) { + unimplemented!("traits"); + } + } + } +} + +// kernel/OS.h +pub const B_OS_NAME_LENGTH: usize = 32; +pub const B_PAGE_SIZE: usize = 4096; +pub const B_INFINITE_TIMEOUT: usize = 9223372036854775807; + +pub const B_RELATIVE_TIMEOUT: u32 = 0x8; +pub const B_ABSOLUTE_TIMEOUT: u32 = 0x10; +pub const B_TIMEOUT_REAL_TIME_BASE: u32 = 0x40; +pub const B_ABSOLUTE_REAL_TIME_TIMEOUT: u32 = B_ABSOLUTE_TIMEOUT | B_TIMEOUT_REAL_TIME_BASE; + +pub const B_NO_LOCK: u32 = 0; +pub const B_LAZY_LOCK: u32 = 1; +pub const B_FULL_LOCK: u32 = 2; +pub const B_CONTIGUOUS: u32 = 3; +pub const B_LOMEM: u32 = 4; +pub const B_32_BIT_FULL_LOCK: u32 = 5; +pub const B_32_BIT_CONTIGUOUS: u32 = 6; + +pub const B_ANY_ADDRESS: u32 = 0; +pub const B_EXACT_ADDRESS: u32 = 1; +pub const B_BASE_ADDRESS: u32 = 2; +pub const B_CLONE_ADDRESS: u32 = 3; +pub const B_ANY_KERNEL_ADDRESS: u32 = 4; +pub const B_RANDOMIZED_ANY_ADDRESS: u32 = 6; +pub const B_RANDOMIZED_BASE_ADDRESS: u32 = 7; + +pub const B_READ_AREA: u32 = 1 << 0; +pub const B_WRITE_AREA: u32 = 1 << 1; +pub const B_EXECUTE_AREA: u32 = 1 << 2; +pub const B_STACK_AREA: u32 = 1 << 3; +pub const B_CLONEABLE_AREA: u32 = 1 << 8; + +pub const B_CAN_INTERRUPT: u32 = 0x01; +pub const B_CHECK_PERMISSION: u32 = 0x04; +pub const B_KILL_CAN_INTERRUPT: u32 = 0x20; +pub const B_DO_NOT_RESCHEDULE: u32 = 0x02; +pub const B_RELEASE_ALL: u32 = 0x08; +pub const B_RELEASE_IF_WAITING_ONLY: u32 = 0x10; + +pub const B_CURRENT_TEAM: team_id = 0; +pub const B_SYSTEM_TEAM: team_id = 1; + +pub const B_TEAM_USAGE_SELF: i32 = 0; +pub const B_TEAM_USAGE_CHILDREN: i32 = -1; + +pub const B_IDLE_PRIORITY: i32 = 0; +pub const B_LOWEST_ACTIVE_PRIORITY: i32 = 1; +pub const B_LOW_PRIORITY: i32 = 5; +pub const B_NORMAL_PRIORITY: i32 = 10; +pub const B_DISPLAY_PRIORITY: i32 = 15; +pub const B_URGENT_DISPLAY_PRIORITY: i32 = 20; +pub const B_REAL_TIME_DISPLAY_PRIORITY: i32 = 100; +pub const B_URGENT_PRIORITY: i32 = 110; +pub const B_REAL_TIME_PRIORITY: i32 = 120; + +pub const B_SYSTEM_TIMEBASE: i32 = 0; +pub const B_FIRST_REAL_TIME_PRIORITY: i32 = B_REAL_TIME_DISPLAY_PRIORITY; + +pub const B_ONE_SHOT_ABSOLUTE_ALARM: u32 = 1; +pub const B_ONE_SHOT_RELATIVE_ALARM: u32 = 2; +pub const B_PERIODIC_ALARM: u32 = 3; + +pub const B_OBJECT_TYPE_FD: u16 = 0; +pub const B_OBJECT_TYPE_SEMAPHORE: u16 = 1; +pub const B_OBJECT_TYPE_PORT: u16 = 2; +pub const B_OBJECT_TYPE_THREAD: u16 = 3; + +pub const B_EVENT_READ: u16 = 0x0001; +pub const B_EVENT_WRITE: u16 = 0x0002; +pub const B_EVENT_ERROR: u16 = 0x0004; +pub const B_EVENT_PRIORITY_READ: u16 = 0x0008; +pub const B_EVENT_PRIORITY_WRITE: u16 = 0x0010; +pub const B_EVENT_HIGH_PRIORITY_READ: u16 = 0x0020; +pub const B_EVENT_HIGH_PRIORITY_WRITE: u16 = 0x0040; +pub const B_EVENT_DISCONNECTED: u16 = 0x0080; +pub const B_EVENT_ACQUIRE_SEMAPHORE: u16 = 0x0001; +pub const B_EVENT_INVALID: u16 = 0x1000; + +// kernel/fs_info.h +pub const B_FS_IS_READONLY: u32 = 0x00000001; +pub const B_FS_IS_REMOVABLE: u32 = 0x00000002; +pub const B_FS_IS_PERSISTENT: u32 = 0x00000004; +pub const B_FS_IS_SHARED: u32 = 0x00000008; +pub const B_FS_HAS_MIME: u32 = 0x00010000; +pub const B_FS_HAS_ATTR: u32 = 0x00020000; +pub const B_FS_HAS_QUERY: u32 = 0x00040000; +pub const B_FS_HAS_SELF_HEALING_LINKS: u32 = 0x00080000; +pub const B_FS_HAS_ALIASES: u32 = 0x00100000; +pub const B_FS_SUPPORTS_NODE_MONITORING: u32 = 0x00200000; +pub const B_FS_SUPPORTS_MONITOR_CHILDREN: u32 = 0x00400000; + +// kernel/fs_query.h +pub const B_LIVE_QUERY: u32 = 0x00000001; +pub const B_QUERY_NON_INDEXED: u32 = 0x00000002; + +// kernel/fs_volume.h +pub const B_MOUNT_READ_ONLY: u32 = 1; +pub const B_MOUNT_VIRTUAL_DEVICE: u32 = 2; +pub const B_FORCE_UNMOUNT: u32 = 1; + +// kernel/image.h +pub const B_FLUSH_DCACHE: u32 = 0x0001; +pub const B_FLUSH_ICACHE: u32 = 0x0004; +pub const B_INVALIDATE_DCACHE: u32 = 0x0002; +pub const B_INVALIDATE_ICACHE: u32 = 0x0008; + +pub const B_SYMBOL_TYPE_DATA: i32 = 0x1; +pub const B_SYMBOL_TYPE_TEXT: i32 = 0x2; +pub const B_SYMBOL_TYPE_ANY: i32 = 0x5; + +// storage/StorageDefs.h +pub const B_DEV_NAME_LENGTH: usize = 128; +pub const B_FILE_NAME_LENGTH: usize = crate::FILENAME_MAX as usize; +pub const B_PATH_NAME_LENGTH: usize = crate::PATH_MAX as usize; +pub const B_ATTR_NAME_LENGTH: usize = B_FILE_NAME_LENGTH - 1; +pub const B_MIME_TYPE_LENGTH: usize = B_ATTR_NAME_LENGTH - 15; +pub const B_MAX_SYMLINKS: usize = 16; + +// Haiku open modes in BFile are passed as u32 +pub const B_READ_ONLY: u32 = crate::O_RDONLY as u32; +pub const B_WRITE_ONLY: u32 = crate::O_WRONLY as u32; +pub const B_READ_WRITE: u32 = crate::O_RDWR as u32; + +pub const B_FAIL_IF_EXISTS: u32 = crate::O_EXCL as u32; +pub const B_CREATE_FILE: u32 = crate::O_CREAT as u32; +pub const B_ERASE_FILE: u32 = crate::O_TRUNC as u32; +pub const B_OPEN_AT_END: u32 = crate::O_APPEND as u32; + +pub const B_FILE_NODE: u32 = 0x01; +pub const B_SYMLINK_NODE: u32 = 0x02; +pub const B_DIRECTORY_NODE: u32 = 0x04; +pub const B_ANY_NODE: u32 = 0x07; + +// support/Errors.h +pub const B_GENERAL_ERROR_BASE: status_t = core::i32::MIN; +pub const B_OS_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x1000; +pub const B_APP_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x2000; +pub const B_INTERFACE_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x3000; +pub const B_MEDIA_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x4000; +pub const B_TRANSLATION_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x4800; +pub const B_MIDI_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x5000; +pub const B_STORAGE_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x6000; +pub const B_POSIX_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x7000; +pub const B_MAIL_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x8000; +pub const B_PRINT_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0x9000; +pub const B_DEVICE_ERROR_BASE: status_t = B_GENERAL_ERROR_BASE + 0xa000; +pub const B_ERRORS_END: status_t = B_GENERAL_ERROR_BASE + 0xffff; + +// General errors +pub const B_NO_MEMORY: status_t = B_GENERAL_ERROR_BASE + 0; +pub const B_IO_ERROR: status_t = B_GENERAL_ERROR_BASE + 1; +pub const B_PERMISSION_DENIED: status_t = B_GENERAL_ERROR_BASE + 2; +pub const B_BAD_INDEX: status_t = B_GENERAL_ERROR_BASE + 3; +pub const B_BAD_TYPE: status_t = B_GENERAL_ERROR_BASE + 4; +pub const B_BAD_VALUE: status_t = B_GENERAL_ERROR_BASE + 5; +pub const B_MISMATCHED_VALUES: status_t = B_GENERAL_ERROR_BASE + 6; +pub const B_NAME_NOT_FOUND: status_t = B_GENERAL_ERROR_BASE + 7; +pub const B_NAME_IN_USE: status_t = B_GENERAL_ERROR_BASE + 8; +pub const B_TIMED_OUT: status_t = B_GENERAL_ERROR_BASE + 9; +pub const B_INTERRUPTED: status_t = B_GENERAL_ERROR_BASE + 10; +pub const B_WOULD_BLOCK: status_t = B_GENERAL_ERROR_BASE + 11; +pub const B_CANCELED: status_t = B_GENERAL_ERROR_BASE + 12; +pub const B_NO_INIT: status_t = B_GENERAL_ERROR_BASE + 13; +pub const B_NOT_INITIALIZED: status_t = B_GENERAL_ERROR_BASE + 13; +pub const B_BUSY: status_t = B_GENERAL_ERROR_BASE + 14; +pub const B_NOT_ALLOWED: status_t = B_GENERAL_ERROR_BASE + 15; +pub const B_BAD_DATA: status_t = B_GENERAL_ERROR_BASE + 16; +pub const B_DONT_DO_THAT: status_t = B_GENERAL_ERROR_BASE + 17; + +pub const B_ERROR: status_t = -1; +pub const B_OK: status_t = 0; +pub const B_NO_ERROR: status_t = 0; + +// Kernel kit errors +pub const B_BAD_SEM_ID: status_t = B_OS_ERROR_BASE + 0; +pub const B_NO_MORE_SEMS: status_t = B_OS_ERROR_BASE + 1; + +pub const B_BAD_THREAD_ID: status_t = B_OS_ERROR_BASE + 0x100; +pub const B_NO_MORE_THREADS: status_t = B_OS_ERROR_BASE + 0x101; +pub const B_BAD_THREAD_STATE: status_t = B_OS_ERROR_BASE + 0x102; +pub const B_BAD_TEAM_ID: status_t = B_OS_ERROR_BASE + 0x103; +pub const B_NO_MORE_TEAMS: status_t = B_OS_ERROR_BASE + 0x104; + +pub const B_BAD_PORT_ID: status_t = B_OS_ERROR_BASE + 0x200; +pub const B_NO_MORE_PORTS: status_t = B_OS_ERROR_BASE + 0x201; + +pub const B_BAD_IMAGE_ID: status_t = B_OS_ERROR_BASE + 0x300; +pub const B_BAD_ADDRESS: status_t = B_OS_ERROR_BASE + 0x301; +pub const B_NOT_AN_EXECUTABLE: status_t = B_OS_ERROR_BASE + 0x302; +pub const B_MISSING_LIBRARY: status_t = B_OS_ERROR_BASE + 0x303; +pub const B_MISSING_SYMBOL: status_t = B_OS_ERROR_BASE + 0x304; +pub const B_UNKNOWN_EXECUTABLE: status_t = B_OS_ERROR_BASE + 0x305; +pub const B_LEGACY_EXECUTABLE: status_t = B_OS_ERROR_BASE + 0x306; + +pub const B_DEBUGGER_ALREADY_INSTALLED: status_t = B_OS_ERROR_BASE + 0x400; + +// Application kit errors +pub const B_BAD_REPLY: status_t = B_APP_ERROR_BASE + 0; +pub const B_DUPLICATE_REPLY: status_t = B_APP_ERROR_BASE + 1; +pub const B_MESSAGE_TO_SELF: status_t = B_APP_ERROR_BASE + 2; +pub const B_BAD_HANDLER: status_t = B_APP_ERROR_BASE + 3; +pub const B_ALREADY_RUNNING: status_t = B_APP_ERROR_BASE + 4; +pub const B_LAUNCH_FAILED: status_t = B_APP_ERROR_BASE + 5; +pub const B_AMBIGUOUS_APP_LAUNCH: status_t = B_APP_ERROR_BASE + 6; +pub const B_UNKNOWN_MIME_TYPE: status_t = B_APP_ERROR_BASE + 7; +pub const B_BAD_SCRIPT_SYNTAX: status_t = B_APP_ERROR_BASE + 8; +pub const B_LAUNCH_FAILED_NO_RESOLVE_LINK: status_t = B_APP_ERROR_BASE + 9; +pub const B_LAUNCH_FAILED_EXECUTABLE: status_t = B_APP_ERROR_BASE + 10; +pub const B_LAUNCH_FAILED_APP_NOT_FOUND: status_t = B_APP_ERROR_BASE + 11; +pub const B_LAUNCH_FAILED_APP_IN_TRASH: status_t = B_APP_ERROR_BASE + 12; +pub const B_LAUNCH_FAILED_NO_PREFERRED_APP: status_t = B_APP_ERROR_BASE + 13; +pub const B_LAUNCH_FAILED_FILES_APP_NOT_FOUND: status_t = B_APP_ERROR_BASE + 14; +pub const B_BAD_MIME_SNIFFER_RULE: status_t = B_APP_ERROR_BASE + 15; +pub const B_NOT_A_MESSAGE: status_t = B_APP_ERROR_BASE + 16; +pub const B_SHUTDOWN_CANCELLED: status_t = B_APP_ERROR_BASE + 17; +pub const B_SHUTTING_DOWN: status_t = B_APP_ERROR_BASE + 18; + +// Storage kit errors +pub const B_FILE_ERROR: status_t = B_STORAGE_ERROR_BASE + 0; +pub const B_FILE_EXISTS: status_t = B_STORAGE_ERROR_BASE + 2; +pub const B_ENTRY_NOT_FOUND: status_t = B_STORAGE_ERROR_BASE + 3; +pub const B_NAME_TOO_LONG: status_t = B_STORAGE_ERROR_BASE + 4; +pub const B_NOT_A_DIRECTORY: status_t = B_STORAGE_ERROR_BASE + 5; +pub const B_DIRECTORY_NOT_EMPTY: status_t = B_STORAGE_ERROR_BASE + 6; +pub const B_DEVICE_FULL: status_t = B_STORAGE_ERROR_BASE + 7; +pub const B_READ_ONLY_DEVICE: status_t = B_STORAGE_ERROR_BASE + 8; +pub const B_IS_A_DIRECTORY: status_t = B_STORAGE_ERROR_BASE + 9; +pub const B_NO_MORE_FDS: status_t = B_STORAGE_ERROR_BASE + 10; +pub const B_CROSS_DEVICE_LINK: status_t = B_STORAGE_ERROR_BASE + 11; +pub const B_LINK_LIMIT: status_t = B_STORAGE_ERROR_BASE + 12; +pub const B_BUSTED_PIPE: status_t = B_STORAGE_ERROR_BASE + 13; +pub const B_UNSUPPORTED: status_t = B_STORAGE_ERROR_BASE + 14; +pub const B_PARTITION_TOO_SMALL: status_t = B_STORAGE_ERROR_BASE + 15; +pub const B_PARTIAL_READ: status_t = B_STORAGE_ERROR_BASE + 16; +pub const B_PARTIAL_WRITE: status_t = B_STORAGE_ERROR_BASE + 17; + +// Mapped posix errors +pub const B_BUFFER_OVERFLOW: status_t = crate::EOVERFLOW; +pub const B_TOO_MANY_ARGS: status_t = crate::E2BIG; +pub const B_FILE_TOO_LARGE: status_t = crate::EFBIG; +pub const B_RESULT_NOT_REPRESENTABLE: status_t = crate::ERANGE; +pub const B_DEVICE_NOT_FOUND: status_t = crate::ENODEV; +pub const B_NOT_SUPPORTED: status_t = crate::EOPNOTSUPP; + +// Media kit errors +pub const B_STREAM_NOT_FOUND: status_t = B_MEDIA_ERROR_BASE + 0; +pub const B_SERVER_NOT_FOUND: status_t = B_MEDIA_ERROR_BASE + 1; +pub const B_RESOURCE_NOT_FOUND: status_t = B_MEDIA_ERROR_BASE + 2; +pub const B_RESOURCE_UNAVAILABLE: status_t = B_MEDIA_ERROR_BASE + 3; +pub const B_BAD_SUBSCRIBER: status_t = B_MEDIA_ERROR_BASE + 4; +pub const B_SUBSCRIBER_NOT_ENTERED: status_t = B_MEDIA_ERROR_BASE + 5; +pub const B_BUFFER_NOT_AVAILABLE: status_t = B_MEDIA_ERROR_BASE + 6; +pub const B_LAST_BUFFER_ERROR: status_t = B_MEDIA_ERROR_BASE + 7; + +pub const B_MEDIA_SYSTEM_FAILURE: status_t = B_MEDIA_ERROR_BASE + 100; +pub const B_MEDIA_BAD_NODE: status_t = B_MEDIA_ERROR_BASE + 101; +pub const B_MEDIA_NODE_BUSY: status_t = B_MEDIA_ERROR_BASE + 102; +pub const B_MEDIA_BAD_FORMAT: status_t = B_MEDIA_ERROR_BASE + 103; +pub const B_MEDIA_BAD_BUFFER: status_t = B_MEDIA_ERROR_BASE + 104; +pub const B_MEDIA_TOO_MANY_NODES: status_t = B_MEDIA_ERROR_BASE + 105; +pub const B_MEDIA_TOO_MANY_BUFFERS: status_t = B_MEDIA_ERROR_BASE + 106; +pub const B_MEDIA_NODE_ALREADY_EXISTS: status_t = B_MEDIA_ERROR_BASE + 107; +pub const B_MEDIA_BUFFER_ALREADY_EXISTS: status_t = B_MEDIA_ERROR_BASE + 108; +pub const B_MEDIA_CANNOT_SEEK: status_t = B_MEDIA_ERROR_BASE + 109; +pub const B_MEDIA_CANNOT_CHANGE_RUN_MODE: status_t = B_MEDIA_ERROR_BASE + 110; +pub const B_MEDIA_APP_ALREADY_REGISTERED: status_t = B_MEDIA_ERROR_BASE + 111; +pub const B_MEDIA_APP_NOT_REGISTERED: status_t = B_MEDIA_ERROR_BASE + 112; +pub const B_MEDIA_CANNOT_RECLAIM_BUFFERS: status_t = B_MEDIA_ERROR_BASE + 113; +pub const B_MEDIA_BUFFERS_NOT_RECLAIMED: status_t = B_MEDIA_ERROR_BASE + 114; +pub const B_MEDIA_TIME_SOURCE_STOPPED: status_t = B_MEDIA_ERROR_BASE + 115; +pub const B_MEDIA_TIME_SOURCE_BUSY: status_t = B_MEDIA_ERROR_BASE + 116; +pub const B_MEDIA_BAD_SOURCE: status_t = B_MEDIA_ERROR_BASE + 117; +pub const B_MEDIA_BAD_DESTINATION: status_t = B_MEDIA_ERROR_BASE + 118; +pub const B_MEDIA_ALREADY_CONNECTED: status_t = B_MEDIA_ERROR_BASE + 119; +pub const B_MEDIA_NOT_CONNECTED: status_t = B_MEDIA_ERROR_BASE + 120; +pub const B_MEDIA_BAD_CLIP_FORMAT: status_t = B_MEDIA_ERROR_BASE + 121; +pub const B_MEDIA_ADDON_FAILED: status_t = B_MEDIA_ERROR_BASE + 122; +pub const B_MEDIA_ADDON_DISABLED: status_t = B_MEDIA_ERROR_BASE + 123; +pub const B_MEDIA_CHANGE_IN_PROGRESS: status_t = B_MEDIA_ERROR_BASE + 124; +pub const B_MEDIA_STALE_CHANGE_COUNT: status_t = B_MEDIA_ERROR_BASE + 125; +pub const B_MEDIA_ADDON_RESTRICTED: status_t = B_MEDIA_ERROR_BASE + 126; +pub const B_MEDIA_NO_HANDLER: status_t = B_MEDIA_ERROR_BASE + 127; +pub const B_MEDIA_DUPLICATE_FORMAT: status_t = B_MEDIA_ERROR_BASE + 128; +pub const B_MEDIA_REALTIME_DISABLED: status_t = B_MEDIA_ERROR_BASE + 129; +pub const B_MEDIA_REALTIME_UNAVAILABLE: status_t = B_MEDIA_ERROR_BASE + 130; + +// Mail kit errors +pub const B_MAIL_NO_DAEMON: status_t = B_MAIL_ERROR_BASE + 0; +pub const B_MAIL_UNKNOWN_USER: status_t = B_MAIL_ERROR_BASE + 1; +pub const B_MAIL_WRONG_PASSWORD: status_t = B_MAIL_ERROR_BASE + 2; +pub const B_MAIL_UNKNOWN_HOST: status_t = B_MAIL_ERROR_BASE + 3; +pub const B_MAIL_ACCESS_ERROR: status_t = B_MAIL_ERROR_BASE + 4; +pub const B_MAIL_UNKNOWN_FIELD: status_t = B_MAIL_ERROR_BASE + 5; +pub const B_MAIL_NO_RECIPIENT: status_t = B_MAIL_ERROR_BASE + 6; +pub const B_MAIL_INVALID_MAIL: status_t = B_MAIL_ERROR_BASE + 7; + +// Print kit errors +pub const B_NO_PRINT_SERVER: status_t = B_PRINT_ERROR_BASE + 0; + +// Device kit errors +pub const B_DEV_INVALID_IOCTL: status_t = B_DEVICE_ERROR_BASE + 0; +pub const B_DEV_NO_MEMORY: status_t = B_DEVICE_ERROR_BASE + 1; +pub const B_DEV_BAD_DRIVE_NUM: status_t = B_DEVICE_ERROR_BASE + 2; +pub const B_DEV_NO_MEDIA: status_t = B_DEVICE_ERROR_BASE + 3; +pub const B_DEV_UNREADABLE: status_t = B_DEVICE_ERROR_BASE + 4; +pub const B_DEV_FORMAT_ERROR: status_t = B_DEVICE_ERROR_BASE + 5; +pub const B_DEV_TIMEOUT: status_t = B_DEVICE_ERROR_BASE + 6; +pub const B_DEV_RECALIBRATE_ERROR: status_t = B_DEVICE_ERROR_BASE + 7; +pub const B_DEV_SEEK_ERROR: status_t = B_DEVICE_ERROR_BASE + 8; +pub const B_DEV_ID_ERROR: status_t = B_DEVICE_ERROR_BASE + 9; +pub const B_DEV_READ_ERROR: status_t = B_DEVICE_ERROR_BASE + 10; +pub const B_DEV_WRITE_ERROR: status_t = B_DEVICE_ERROR_BASE + 11; +pub const B_DEV_NOT_READY: status_t = B_DEVICE_ERROR_BASE + 12; +pub const B_DEV_MEDIA_CHANGED: status_t = B_DEVICE_ERROR_BASE + 13; +pub const B_DEV_MEDIA_CHANGE_REQUESTED: status_t = B_DEVICE_ERROR_BASE + 14; +pub const B_DEV_RESOURCE_CONFLICT: status_t = B_DEVICE_ERROR_BASE + 15; +pub const B_DEV_CONFIGURATION_ERROR: status_t = B_DEVICE_ERROR_BASE + 16; +pub const B_DEV_DISABLED_BY_USER: status_t = B_DEVICE_ERROR_BASE + 17; +pub const B_DEV_DOOR_OPEN: status_t = B_DEVICE_ERROR_BASE + 18; + +pub const B_DEV_INVALID_PIPE: status_t = B_DEVICE_ERROR_BASE + 19; +pub const B_DEV_CRC_ERROR: status_t = B_DEVICE_ERROR_BASE + 20; +pub const B_DEV_STALLED: status_t = B_DEVICE_ERROR_BASE + 21; +pub const B_DEV_BAD_PID: status_t = B_DEVICE_ERROR_BASE + 22; +pub const B_DEV_UNEXPECTED_PID: status_t = B_DEVICE_ERROR_BASE + 23; +pub const B_DEV_DATA_OVERRUN: status_t = B_DEVICE_ERROR_BASE + 24; +pub const B_DEV_DATA_UNDERRUN: status_t = B_DEVICE_ERROR_BASE + 25; +pub const B_DEV_FIFO_OVERRUN: status_t = B_DEVICE_ERROR_BASE + 26; +pub const B_DEV_FIFO_UNDERRUN: status_t = B_DEVICE_ERROR_BASE + 27; +pub const B_DEV_PENDING: status_t = B_DEVICE_ERROR_BASE + 28; +pub const B_DEV_MULTIPLE_ERRORS: status_t = B_DEVICE_ERROR_BASE + 29; +pub const B_DEV_TOO_LATE: status_t = B_DEVICE_ERROR_BASE + 30; + +// translation kit errors +pub const B_TRANSLATION_BASE_ERROR: status_t = B_TRANSLATION_ERROR_BASE + 0; +pub const B_NO_TRANSLATOR: status_t = B_TRANSLATION_ERROR_BASE + 1; +pub const B_ILLEGAL_DATA: status_t = B_TRANSLATION_ERROR_BASE + 2; + +// support/TypeConstants.h +pub const B_AFFINE_TRANSFORM_TYPE: u32 = haiku_constant!('A', 'M', 'T', 'X'); +pub const B_ALIGNMENT_TYPE: u32 = haiku_constant!('A', 'L', 'G', 'N'); +pub const B_ANY_TYPE: u32 = haiku_constant!('A', 'N', 'Y', 'T'); +pub const B_ATOM_TYPE: u32 = haiku_constant!('A', 'T', 'O', 'M'); +pub const B_ATOMREF_TYPE: u32 = haiku_constant!('A', 'T', 'M', 'R'); +pub const B_BOOL_TYPE: u32 = haiku_constant!('B', 'O', 'O', 'L'); +pub const B_CHAR_TYPE: u32 = haiku_constant!('C', 'H', 'A', 'R'); +pub const B_COLOR_8_BIT_TYPE: u32 = haiku_constant!('C', 'L', 'R', 'B'); +pub const B_DOUBLE_TYPE: u32 = haiku_constant!('D', 'B', 'L', 'E'); +pub const B_FLOAT_TYPE: u32 = haiku_constant!('F', 'L', 'O', 'T'); +pub const B_GRAYSCALE_8_BIT_TYPE: u32 = haiku_constant!('G', 'R', 'Y', 'B'); +pub const B_INT16_TYPE: u32 = haiku_constant!('S', 'H', 'R', 'T'); +pub const B_INT32_TYPE: u32 = haiku_constant!('L', 'O', 'N', 'G'); +pub const B_INT64_TYPE: u32 = haiku_constant!('L', 'L', 'N', 'G'); +pub const B_INT8_TYPE: u32 = haiku_constant!('B', 'Y', 'T', 'E'); +pub const B_LARGE_ICON_TYPE: u32 = haiku_constant!('I', 'C', 'O', 'N'); +pub const B_MEDIA_PARAMETER_GROUP_TYPE: u32 = haiku_constant!('B', 'M', 'C', 'G'); +pub const B_MEDIA_PARAMETER_TYPE: u32 = haiku_constant!('B', 'M', 'C', 'T'); +pub const B_MEDIA_PARAMETER_WEB_TYPE: u32 = haiku_constant!('B', 'M', 'C', 'W'); +pub const B_MESSAGE_TYPE: u32 = haiku_constant!('M', 'S', 'G', 'G'); +pub const B_MESSENGER_TYPE: u32 = haiku_constant!('M', 'S', 'N', 'G'); +pub const B_MIME_TYPE: u32 = haiku_constant!('M', 'I', 'M', 'E'); +pub const B_MINI_ICON_TYPE: u32 = haiku_constant!('M', 'I', 'C', 'N'); +pub const B_MONOCHROME_1_BIT_TYPE: u32 = haiku_constant!('M', 'N', 'O', 'B'); +pub const B_OBJECT_TYPE: u32 = haiku_constant!('O', 'P', 'T', 'R'); +pub const B_OFF_T_TYPE: u32 = haiku_constant!('O', 'F', 'F', 'T'); +pub const B_PATTERN_TYPE: u32 = haiku_constant!('P', 'A', 'T', 'N'); +pub const B_POINTER_TYPE: u32 = haiku_constant!('P', 'N', 'T', 'R'); +pub const B_POINT_TYPE: u32 = haiku_constant!('B', 'P', 'N', 'T'); +pub const B_PROPERTY_INFO_TYPE: u32 = haiku_constant!('S', 'C', 'T', 'D'); +pub const B_RAW_TYPE: u32 = haiku_constant!('R', 'A', 'W', 'T'); +pub const B_RECT_TYPE: u32 = haiku_constant!('R', 'E', 'C', 'T'); +pub const B_REF_TYPE: u32 = haiku_constant!('R', 'R', 'E', 'F'); +pub const B_RGB_32_BIT_TYPE: u32 = haiku_constant!('R', 'G', 'B', 'B'); +pub const B_RGB_COLOR_TYPE: u32 = haiku_constant!('R', 'G', 'B', 'C'); +pub const B_SIZE_TYPE: u32 = haiku_constant!('S', 'I', 'Z', 'E'); +pub const B_SIZE_T_TYPE: u32 = haiku_constant!('S', 'I', 'Z', 'T'); +pub const B_SSIZE_T_TYPE: u32 = haiku_constant!('S', 'S', 'Z', 'T'); +pub const B_STRING_TYPE: u32 = haiku_constant!('C', 'S', 'T', 'R'); +pub const B_STRING_LIST_TYPE: u32 = haiku_constant!('S', 'T', 'R', 'L'); +pub const B_TIME_TYPE: u32 = haiku_constant!('T', 'I', 'M', 'E'); +pub const B_UINT16_TYPE: u32 = haiku_constant!('U', 'S', 'H', 'T'); +pub const B_UINT32_TYPE: u32 = haiku_constant!('U', 'L', 'N', 'G'); +pub const B_UINT64_TYPE: u32 = haiku_constant!('U', 'L', 'L', 'G'); +pub const B_UINT8_TYPE: u32 = haiku_constant!('U', 'B', 'Y', 'T'); +pub const B_VECTOR_ICON_TYPE: u32 = haiku_constant!('V', 'I', 'C', 'N'); +pub const B_XATTR_TYPE: u32 = haiku_constant!('X', 'A', 'T', 'R'); +pub const B_NETWORK_ADDRESS_TYPE: u32 = haiku_constant!('N', 'W', 'A', 'D'); +pub const B_MIME_STRING_TYPE: u32 = haiku_constant!('M', 'I', 'M', 'S'); +pub const B_ASCII_TYPE: u32 = haiku_constant!('T', 'E', 'X', 'T'); +pub const B_APP_IMAGE_SYMBOL: *const c_void = core::ptr::null(); + +extern "C" { + // kernel/OS.h + pub fn create_area( + name: *const c_char, + startAddress: *mut *mut c_void, + addressSpec: u32, + size: usize, + lock: u32, + protection: u32, + ) -> area_id; + pub fn clone_area( + name: *const c_char, + destAddress: *mut *mut c_void, + addressSpec: u32, + protection: u32, + source: area_id, + ) -> area_id; + pub fn find_area(name: *const c_char) -> area_id; + pub fn area_for(address: *mut c_void) -> area_id; + pub fn delete_area(id: area_id) -> status_t; + pub fn resize_area(id: area_id, newSize: usize) -> status_t; + pub fn set_area_protection(id: area_id, newProtection: u32) -> status_t; + pub fn _get_area_info(id: area_id, areaInfo: *mut area_info, size: usize) -> status_t; + pub fn _get_next_area_info( + team: team_id, + cookie: *mut isize, + areaInfo: *mut area_info, + size: usize, + ) -> status_t; + + pub fn create_port(capacity: i32, name: *const c_char) -> port_id; + pub fn find_port(name: *const c_char) -> port_id; + pub fn read_port( + port: port_id, + code: *mut i32, + buffer: *mut c_void, + bufferSize: size_t, + ) -> ssize_t; + pub fn read_port_etc( + port: port_id, + code: *mut i32, + buffer: *mut c_void, + bufferSize: size_t, + flags: u32, + timeout: bigtime_t, + ) -> ssize_t; + pub fn write_port( + port: port_id, + code: i32, + buffer: *const c_void, + bufferSize: size_t, + ) -> status_t; + pub fn write_port_etc( + port: port_id, + code: i32, + buffer: *const c_void, + bufferSize: size_t, + flags: u32, + timeout: bigtime_t, + ) -> status_t; + pub fn close_port(port: port_id) -> status_t; + pub fn delete_port(port: port_id) -> status_t; + pub fn port_buffer_size(port: port_id) -> ssize_t; + pub fn port_buffer_size_etc(port: port_id, flags: u32, timeout: bigtime_t) -> ssize_t; + pub fn port_count(port: port_id) -> ssize_t; + pub fn set_port_owner(port: port_id, team: team_id) -> status_t; + + pub fn _get_port_info(port: port_id, buf: *mut port_info, portInfoSize: size_t) -> status_t; + pub fn _get_next_port_info( + port: port_id, + cookie: *mut i32, + portInfo: *mut port_info, + portInfoSize: size_t, + ) -> status_t; + pub fn _get_port_message_info_etc( + port: port_id, + info: *mut port_message_info, + infoSize: size_t, + flags: u32, + timeout: bigtime_t, + ) -> status_t; + + pub fn create_sem(count: i32, name: *const c_char) -> sem_id; + pub fn delete_sem(id: sem_id) -> status_t; + pub fn acquire_sem(id: sem_id) -> status_t; + pub fn acquire_sem_etc(id: sem_id, count: i32, flags: u32, timeout: bigtime_t) -> status_t; + pub fn release_sem(id: sem_id) -> status_t; + pub fn release_sem_etc(id: sem_id, count: i32, flags: u32) -> status_t; + pub fn switch_sem(semToBeReleased: sem_id, id: sem_id) -> status_t; + pub fn switch_sem_etc( + semToBeReleased: sem_id, + id: sem_id, + count: i32, + flags: u32, + timeout: bigtime_t, + ) -> status_t; + pub fn get_sem_count(id: sem_id, threadCount: *mut i32) -> status_t; + pub fn set_sem_owner(id: sem_id, team: team_id) -> status_t; + pub fn _get_sem_info(id: sem_id, info: *mut sem_info, infoSize: size_t) -> status_t; + pub fn _get_next_sem_info( + team: team_id, + cookie: *mut i32, + info: *mut sem_info, + infoSize: size_t, + ) -> status_t; + + pub fn kill_team(team: team_id) -> status_t; + pub fn _get_team_info(team: team_id, info: *mut team_info, size: size_t) -> status_t; + pub fn _get_next_team_info(cookie: *mut i32, info: *mut team_info, size: size_t) -> status_t; + + pub fn spawn_thread( + func: thread_func, + name: *const c_char, + priority: i32, + data: *mut c_void, + ) -> thread_id; + pub fn kill_thread(thread: thread_id) -> status_t; + pub fn resume_thread(thread: thread_id) -> status_t; + pub fn suspend_thread(thread: thread_id) -> status_t; + + pub fn rename_thread(thread: thread_id, newName: *const c_char) -> status_t; + pub fn set_thread_priority(thread: thread_id, newPriority: i32) -> status_t; + pub fn suggest_thread_priority( + what: u32, + period: i32, + jitter: crate::bigtime_t, + length: crate::bigtime_t, + ) -> i32; + pub fn estimate_max_scheduling_latency(th: crate::thread_id) -> crate::bigtime_t; + pub fn exit_thread(status: status_t); + pub fn wait_for_thread(thread: thread_id, returnValue: *mut status_t) -> status_t; + pub fn on_exit_thread(callback: extern "C" fn(*mut c_void), data: *mut c_void) -> status_t; + + pub fn find_thread(name: *const c_char) -> thread_id; + + pub fn get_scheduler_mode() -> i32; + pub fn set_scheduler_mode(mode: i32) -> status_t; + + pub fn send_data( + thread: thread_id, + code: i32, + buffer: *const c_void, + bufferSize: size_t, + ) -> status_t; + pub fn receive_data(sender: *mut thread_id, buffer: *mut c_void, bufferSize: size_t) -> i32; + pub fn has_data(thread: thread_id) -> bool; + + pub fn snooze(amount: bigtime_t) -> status_t; + pub fn snooze_etc(amount: bigtime_t, timeBase: c_int, flags: u32) -> status_t; + pub fn snooze_until(time: bigtime_t, timeBase: c_int) -> status_t; + + pub fn _get_thread_info(id: thread_id, info: *mut thread_info, size: size_t) -> status_t; + pub fn _get_next_thread_info( + team: team_id, + cookie: *mut i32, + info: *mut thread_info, + size: size_t, + ) -> status_t; + + pub fn get_pthread_thread_id(thread: crate::pthread_t) -> thread_id; + + pub fn _get_team_usage_info( + team: team_id, + who: i32, + info: *mut team_usage_info, + size: size_t, + ) -> status_t; + + pub fn real_time_clock() -> c_ulong; + pub fn set_real_time_clock(secsSinceJan1st1970: c_ulong); + pub fn real_time_clock_usecs() -> bigtime_t; + pub fn system_time() -> bigtime_t; + pub fn system_time_nsecs() -> nanotime_t; + // set_timezone() is deprecated and a no-op + + pub fn set_alarm(when: bigtime_t, flags: u32) -> bigtime_t; + pub fn debugger(message: *const c_char); + pub fn disable_debugger(state: c_int) -> c_int; + + pub fn get_system_info(info: *mut system_info) -> status_t; + pub fn _get_cpu_info_etc( + firstCPU: u32, + cpuCount: u32, + info: *mut cpu_info, + size: size_t, + ) -> status_t; + pub fn get_cpu_topology_info( + topologyInfos: *mut cpu_topology_node_info, + topologyInfoCount: *mut u32, + ) -> status_t; + pub fn is_computer_on() -> i32; + pub fn is_computer_on_fire() -> c_double; + pub fn send_signal(threadID: thread_id, signal: c_uint) -> c_int; + pub fn set_signal_stack(base: *mut c_void, size: size_t); + + pub fn wait_for_objects(infos: *mut object_wait_info, numInfos: c_int) -> ssize_t; + pub fn wait_for_objects_etc( + infos: *mut object_wait_info, + numInfos: c_int, + flags: u32, + timeout: bigtime_t, + ) -> ssize_t; + + // kernel/fs_attr.h + pub fn fs_read_attr( + fd: c_int, + attribute: *const c_char, + type_: u32, + pos: off_t, + buffer: *mut c_void, + readBytes: size_t, + ) -> ssize_t; + pub fn fs_write_attr( + fd: c_int, + attribute: *const c_char, + type_: u32, + pos: off_t, + buffer: *const c_void, + writeBytes: size_t, + ) -> ssize_t; + pub fn fs_remove_attr(fd: c_int, attribute: *const c_char) -> c_int; + pub fn fs_stat_attr(fd: c_int, attribute: *const c_char, attrInfo: *mut attr_info) -> c_int; + + pub fn fs_open_attr( + path: *const c_char, + attribute: *const c_char, + type_: u32, + openMode: c_int, + ) -> c_int; + pub fn fs_fopen_attr(fd: c_int, attribute: *const c_char, type_: u32, openMode: c_int) + -> c_int; + pub fn fs_close_attr(fd: c_int) -> c_int; + + pub fn fs_open_attr_dir(path: *const c_char) -> *mut crate::DIR; + pub fn fs_lopen_attr_dir(path: *const c_char) -> *mut crate::DIR; + pub fn fs_fopen_attr_dir(fd: c_int) -> *mut crate::DIR; + pub fn fs_close_attr_dir(dir: *mut crate::DIR) -> c_int; + pub fn fs_read_attr_dir(dir: *mut crate::DIR) -> *mut crate::dirent; + pub fn fs_rewind_attr_dir(dir: *mut crate::DIR); + + // kernel/fs_image.h + pub fn fs_create_index( + device: crate::dev_t, + name: *const c_char, + type_: u32, + flags: u32, + ) -> c_int; + pub fn fs_remove_index(device: crate::dev_t, name: *const c_char) -> c_int; + pub fn fs_stat_index( + device: crate::dev_t, + name: *const c_char, + indexInfo: *mut index_info, + ) -> c_int; + + pub fn fs_open_index_dir(device: crate::dev_t) -> *mut crate::DIR; + pub fn fs_close_index_dir(indexDirectory: *mut crate::DIR) -> c_int; + pub fn fs_read_index_dir(indexDirectory: *mut crate::DIR) -> *mut crate::dirent; + pub fn fs_rewind_index_dir(indexDirectory: *mut crate::DIR); + + // kernel/fs_info.h + pub fn dev_for_path(path: *const c_char) -> crate::dev_t; + pub fn next_dev(pos: *mut i32) -> crate::dev_t; + pub fn fs_stat_dev(dev: crate::dev_t, info: *mut fs_info) -> c_int; + + // kernel/fs_query.h + pub fn fs_open_query(device: crate::dev_t, query: *const c_char, flags: u32) + -> *mut crate::DIR; + pub fn fs_open_live_query( + device: crate::dev_t, + query: *const c_char, + flags: u32, + port: port_id, + token: i32, + ) -> *mut crate::DIR; + pub fn fs_close_query(d: *mut crate::DIR) -> c_int; + pub fn fs_read_query(d: *mut crate::DIR) -> *mut crate::dirent; + pub fn get_path_for_dirent(dent: *mut crate::dirent, buf: *mut c_char, len: size_t) + -> status_t; + + // kernel/fs_volume.h + pub fn fs_mount_volume( + where_: *const c_char, + device: *const c_char, + filesystem: *const c_char, + flags: u32, + parameters: *const c_char, + ) -> crate::dev_t; + pub fn fs_unmount_volume(path: *const c_char, flags: u32) -> status_t; + + // kernel/image.h + pub fn load_image( + argc: i32, + argv: *mut *const c_char, + environ: *mut *const c_char, + ) -> thread_id; + pub fn load_add_on(path: *const c_char) -> image_id; + pub fn unload_add_on(image: image_id) -> status_t; + pub fn get_image_symbol( + image: image_id, + name: *const c_char, + symbolType: i32, + symbolLocation: *mut *mut c_void, + ) -> status_t; + pub fn get_nth_image_symbol( + image: image_id, + n: i32, + nameBuffer: *mut c_char, + nameLength: *mut i32, + symbolType: *mut i32, + symbolLocation: *mut *mut c_void, + ) -> status_t; + pub fn clear_caches(address: *mut c_void, length: size_t, flags: u32); + pub fn _get_image_info(image: image_id, info: *mut image_info, size: size_t) -> status_t; + pub fn _get_next_image_info( + team: team_id, + cookie: *mut i32, + info: *mut image_info, + size: size_t, + ) -> status_t; + pub fn find_path( + codePointer: *const c_void, + baseDirectory: path_base_directory, + subPath: *const c_char, + pathBuffer: *mut c_char, + bufferSize: usize, + ) -> status_t; + pub fn find_path_etc( + codePointer: *const c_void, + dependency: *const c_char, + architecture: *const c_char, + baseDirectory: path_base_directory, + subPath: *const c_char, + flags: u32, + pathBuffer: *mut c_char, + bufferSize: size_t, + ) -> status_t; + pub fn find_path_for_path( + path: *const c_char, + baseDirectory: path_base_directory, + subPath: *const c_char, + pathBuffer: *mut c_char, + bufferSize: size_t, + ) -> status_t; + pub fn find_path_for_path_etc( + path: *const c_char, + dependency: *const c_char, + architecture: *const c_char, + baseDirectory: path_base_directory, + subPath: *const c_char, + flags: u32, + pathBuffer: *mut c_char, + bufferSize: size_t, + ) -> status_t; + pub fn find_paths( + baseDirectory: path_base_directory, + subPath: *const c_char, + _paths: *mut *mut *mut c_char, + pathCount: *mut size_t, + ) -> status_t; + pub fn find_paths_etc( + architecture: *const c_char, + baseDirectory: path_base_directory, + subPath: *const c_char, + flags: u32, + _paths: *mut *mut *mut c_char, + pathCount: *mut size_t, + ) -> status_t; + pub fn find_directory( + which: directory_which, + volume: crate::dev_t, + createIt: bool, + pathString: *mut c_char, + length: i32, + ) -> status_t; + + pub fn get_cpuid(info: *mut cpuid_info, eaxRegister: u32, cpuNum: u32) -> status_t; +} + +// The following functions are defined as macros in C/C++ +#[inline] +pub unsafe fn get_cpu_info(firstCPU: u32, cpuCount: u32, info: *mut cpu_info) -> status_t { + _get_cpu_info_etc(firstCPU, cpuCount, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_area_info(id: area_id, info: *mut area_info) -> status_t { + _get_area_info(id, info, size_of::() as usize) +} + +#[inline] +pub unsafe fn get_next_area_info( + team: team_id, + cookie: *mut isize, + info: *mut area_info, +) -> status_t { + _get_next_area_info(team, cookie, info, size_of::() as usize) +} + +#[inline] +pub unsafe fn get_port_info(port: port_id, buf: *mut port_info) -> status_t { + _get_port_info(port, buf, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_next_port_info( + port: port_id, + cookie: *mut i32, + portInfo: *mut port_info, +) -> status_t { + _get_next_port_info(port, cookie, portInfo, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_port_message_info_etc( + port: port_id, + info: *mut port_message_info, + flags: u32, + timeout: bigtime_t, +) -> status_t { + _get_port_message_info_etc( + port, + info, + size_of::() as size_t, + flags, + timeout, + ) +} + +#[inline] +pub unsafe fn get_sem_info(id: sem_id, info: *mut sem_info) -> status_t { + _get_sem_info(id, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_next_sem_info(team: team_id, cookie: *mut i32, info: *mut sem_info) -> status_t { + _get_next_sem_info(team, cookie, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_team_info(team: team_id, info: *mut team_info) -> status_t { + _get_team_info(team, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_next_team_info(cookie: *mut i32, info: *mut team_info) -> status_t { + _get_next_team_info(cookie, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_team_usage_info(team: team_id, who: i32, info: *mut team_usage_info) -> status_t { + _get_team_usage_info(team, who, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_thread_info(id: thread_id, info: *mut thread_info) -> status_t { + _get_thread_info(id, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_next_thread_info( + team: team_id, + cookie: *mut i32, + info: *mut thread_info, +) -> status_t { + _get_next_thread_info(team, cookie, info, size_of::() as size_t) +} + +// kernel/image.h +#[inline] +pub unsafe fn get_image_info(image: image_id, info: *mut image_info) -> status_t { + _get_image_info(image, info, size_of::() as size_t) +} + +#[inline] +pub unsafe fn get_next_image_info( + team: team_id, + cookie: *mut i32, + info: *mut image_info, +) -> status_t { + _get_next_image_info(team, cookie, info, size_of::() as size_t) +} diff --git a/deps/crates/vendor/libc/src/unix/haiku/x86_64.rs b/deps/crates/vendor/libc/src/unix/haiku/x86_64.rs new file mode 100644 index 00000000000000..4a6921d8d711d6 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/haiku/x86_64.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +s! { + pub struct fpu_state { + pub control: c_ushort, + pub status: c_ushort, + pub tag: c_ushort, + pub opcode: c_ushort, + pub rip: c_ulong, + pub rdp: c_ulong, + pub mxcsr: c_uint, + pub mscsr_mask: c_uint, + pub _fpreg: [[c_uchar; 8]; 16], + pub _xmm: [[c_uchar; 16]; 16], + _reserved_416_511: Padding<[c_uchar; 96]>, + } + + pub struct xstate_hdr { + pub bv: c_ulong, + pub xcomp_bv: c_ulong, + _reserved: Padding<[c_uchar; 48]>, + } + + pub struct savefpu { + pub fp_fxsave: fpu_state, + pub fp_xstate: xstate_hdr, + pub _fp_ymm: [[c_uchar; 16]; 16], + } + + pub struct mcontext_t { + pub rax: c_ulong, + pub rbx: c_ulong, + pub rcx: c_ulong, + pub rdx: c_ulong, + pub rdi: c_ulong, + pub rsi: c_ulong, + pub rbp: c_ulong, + pub r8: c_ulong, + pub r9: c_ulong, + pub r10: c_ulong, + pub r11: c_ulong, + pub r12: c_ulong, + pub r13: c_ulong, + pub r14: c_ulong, + pub r15: c_ulong, + pub rsp: c_ulong, + pub rip: c_ulong, + pub rflags: c_ulong, + pub fpu: savefpu, + } + + pub struct ucontext_t { + pub uc_link: *mut ucontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + } +} diff --git a/deps/crates/vendor/libc/src/unix/hurd/b32.rs b/deps/crates/vendor/libc/src/unix/hurd/b32.rs new file mode 100644 index 00000000000000..e706789006dbaa --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/hurd/b32.rs @@ -0,0 +1,92 @@ +use crate::prelude::*; + +pub type __int64_t = c_longlong; +pub type __uint64_t = c_ulonglong; + +pub type int_fast16_t = c_int; +pub type int_fast32_t = c_int; +pub type int_fast64_t = c_longlong; +pub type uint_fast16_t = c_uint; +pub type uint_fast32_t = c_uint; +pub type uint_fast64_t = c_ulonglong; + +pub type __quad_t = c_longlong; +pub type __u_quad_t = c_ulonglong; +pub type __intmax_t = c_longlong; +pub type __uintmax_t = c_ulonglong; + +pub type __squad_type = crate::__int64_t; +pub type __uquad_type = crate::__uint64_t; +pub type __sword_type = c_int; +pub type __uword_type = c_uint; +pub type __slong32_type = c_long; +pub type __ulong32_type = c_ulong; +pub type __s64_type = crate::__int64_t; +pub type __u64_type = crate::__uint64_t; + +pub type __ipc_pid_t = c_ushort; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; +pub type Elf32_Section = u16; + +pub type Elf_Addr = crate::Elf32_Addr; +pub type Elf_Half = crate::Elf32_Half; +pub type Elf_Ehdr = crate::Elf32_Ehdr; +pub type Elf_Phdr = crate::Elf32_Phdr; +pub type Elf_Shdr = crate::Elf32_Shdr; +pub type Elf_Sym = crate::Elf32_Sym; + +s! { + pub struct Elf32_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf32_Half, + pub e_machine: Elf32_Half, + pub e_version: Elf32_Word, + pub e_entry: Elf32_Addr, + pub e_phoff: Elf32_Off, + pub e_shoff: Elf32_Off, + pub e_flags: Elf32_Word, + pub e_ehsize: Elf32_Half, + pub e_phentsize: Elf32_Half, + pub e_phnum: Elf32_Half, + pub e_shentsize: Elf32_Half, + pub e_shnum: Elf32_Half, + pub e_shstrndx: Elf32_Half, + } + + pub struct Elf32_Shdr { + pub sh_name: Elf32_Word, + pub sh_type: Elf32_Word, + pub sh_flags: Elf32_Word, + pub sh_addr: Elf32_Addr, + pub sh_offset: Elf32_Off, + pub sh_size: Elf32_Word, + pub sh_link: Elf32_Word, + pub sh_info: Elf32_Word, + pub sh_addralign: Elf32_Word, + pub sh_entsize: Elf32_Word, + } + + pub struct Elf32_Sym { + pub st_name: Elf32_Word, + pub st_value: Elf32_Addr, + pub st_size: Elf32_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf32_Section, + } + + pub struct Elf32_Phdr { + pub p_type: crate::Elf32_Word, + pub p_offset: crate::Elf32_Off, + pub p_vaddr: crate::Elf32_Addr, + pub p_paddr: crate::Elf32_Addr, + pub p_filesz: crate::Elf32_Word, + pub p_memsz: crate::Elf32_Word, + pub p_flags: crate::Elf32_Word, + pub p_align: crate::Elf32_Word, + } +} diff --git a/deps/crates/vendor/libc/src/unix/hurd/b64.rs b/deps/crates/vendor/libc/src/unix/hurd/b64.rs new file mode 100644 index 00000000000000..a44428c575adfc --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/hurd/b64.rs @@ -0,0 +1,94 @@ +use crate::prelude::*; + +pub type __int64_t = c_long; +pub type __uint64_t = c_ulong; + +pub type int_fast16_t = c_long; +pub type int_fast32_t = c_long; +pub type int_fast64_t = c_long; +pub type uint_fast16_t = c_ulong; +pub type uint_fast32_t = c_ulong; +pub type uint_fast64_t = c_ulong; + +pub type __quad_t = c_long; +pub type __u_quad_t = c_ulong; +pub type __intmax_t = c_long; +pub type __uintmax_t = c_ulong; + +pub type __squad_type = c_long; +pub type __uquad_type = c_ulong; +pub type __sword_type = c_long; +pub type __uword_type = c_ulong; +pub type __slong32_type = c_int; +pub type __ulong32_type = c_uint; +pub type __s64_type = c_long; +pub type __u64_type = c_ulong; + +pub type __ipc_pid_t = c_int; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; +pub type Elf64_Sxword = i64; +pub type Elf64_Section = u16; + +pub type Elf_Addr = crate::Elf64_Addr; +pub type Elf_Half = crate::Elf64_Half; +pub type Elf_Ehdr = crate::Elf64_Ehdr; +pub type Elf_Phdr = crate::Elf64_Phdr; +pub type Elf_Shdr = crate::Elf64_Shdr; +pub type Elf_Sym = crate::Elf64_Sym; + +s! { + pub struct Elf64_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf64_Half, + pub e_machine: Elf64_Half, + pub e_version: Elf64_Word, + pub e_entry: Elf64_Addr, + pub e_phoff: Elf64_Off, + pub e_shoff: Elf64_Off, + pub e_flags: Elf64_Word, + pub e_ehsize: Elf64_Half, + pub e_phentsize: Elf64_Half, + pub e_phnum: Elf64_Half, + pub e_shentsize: Elf64_Half, + pub e_shnum: Elf64_Half, + pub e_shstrndx: Elf64_Half, + } + + pub struct Elf64_Shdr { + pub sh_name: Elf64_Word, + pub sh_type: Elf64_Word, + pub sh_flags: Elf64_Xword, + pub sh_addr: Elf64_Addr, + pub sh_offset: Elf64_Off, + pub sh_size: Elf64_Xword, + pub sh_link: Elf64_Word, + pub sh_info: Elf64_Word, + pub sh_addralign: Elf64_Xword, + pub sh_entsize: Elf64_Xword, + } + + pub struct Elf64_Sym { + pub st_name: Elf64_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf64_Section, + pub st_value: Elf64_Addr, + pub st_size: Elf64_Xword, + } + + pub struct Elf64_Phdr { + pub p_type: crate::Elf64_Word, + pub p_flags: crate::Elf64_Word, + pub p_offset: crate::Elf64_Off, + pub p_vaddr: crate::Elf64_Addr, + pub p_paddr: crate::Elf64_Addr, + pub p_filesz: crate::Elf64_Xword, + pub p_memsz: crate::Elf64_Xword, + pub p_align: crate::Elf64_Xword, + } +} diff --git a/deps/crates/vendor/libc/src/unix/hurd/mod.rs b/deps/crates/vendor/libc/src/unix/hurd/mod.rs new file mode 100644 index 00000000000000..74b77d96f007e7 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/hurd/mod.rs @@ -0,0 +1,4564 @@ +#![allow(dead_code)] + +use crate::c_schar; +use crate::prelude::*; + +// types +pub type __s16_type = c_short; +pub type __u16_type = c_ushort; +pub type __s32_type = c_int; +pub type __u32_type = c_uint; +pub type __slongword_type = c_long; +pub type __ulongword_type = c_ulong; + +pub type __u_char = c_uchar; +pub type __u_short = c_ushort; +pub type __u_int = c_uint; +pub type __u_long = c_ulong; +pub type __int8_t = c_schar; +pub type __uint8_t = c_uchar; +pub type __int16_t = c_short; +pub type __uint16_t = c_ushort; +pub type __int32_t = c_int; +pub type __uint32_t = c_uint; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; + +pub type __dev_t = __uword_type; +pub type __uid_t = __u32_type; +pub type __gid_t = __u32_type; +pub type __ino_t = __ulongword_type; +pub type __ino64_t = __uquad_type; +pub type __mode_t = __u32_type; +pub type __nlink_t = __uword_type; +pub type __off_t = __slongword_type; +pub type __off64_t = __squad_type; +pub type __pid_t = __s32_type; +pub type __rlim_t = __ulongword_type; +pub type __rlim64_t = __uquad_type; +pub type __blkcnt_t = __slongword_type; +pub type __blkcnt64_t = __squad_type; +pub type __fsblkcnt_t = __ulongword_type; +pub type __fsblkcnt64_t = __uquad_type; +pub type __fsfilcnt_t = __ulongword_type; +pub type __fsfilcnt64_t = __uquad_type; +pub type __fsword_t = __sword_type; +pub type __id_t = __u32_type; +pub type __clock_t = __slongword_type; +pub type __time_t = __slongword_type; +pub type __useconds_t = __u32_type; +pub type __suseconds_t = __slongword_type; +pub type __suseconds64_t = __squad_type; +pub type __daddr_t = __s32_type; +pub type __key_t = __s32_type; +pub type __clockid_t = __s32_type; +pub type __timer_t = __uword_type; +pub type __blksize_t = __slongword_type; +pub type __fsid_t = __uquad_type; +pub type __ssize_t = __sword_type; +pub type __syscall_slong_t = __slongword_type; +pub type __syscall_ulong_t = __ulongword_type; +pub type __cpu_mask = __ulongword_type; + +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut c_char; +pub type __intptr_t = __sword_type; +pub type __ptrdiff_t = __sword_type; +pub type __socklen_t = __u32_type; +pub type __sig_atomic_t = c_int; +pub type __time64_t = __int64_t; +pub type wchar_t = c_int; +pub type wint_t = c_uint; +pub type gid_t = __gid_t; +pub type uid_t = __uid_t; +pub type off_t = __off_t; +pub type off64_t = __off64_t; +pub type useconds_t = __useconds_t; +pub type pid_t = __pid_t; +pub type socklen_t = __socklen_t; + +pub type in_addr_t = u32; + +pub type _Float32 = f32; +pub type _Float64 = f64; +pub type _Float32x = f64; +pub type _Float64x = f64; + +pub type __locale_t = *mut __locale_struct; +pub type locale_t = __locale_t; + +pub type u_char = __u_char; +pub type u_short = __u_short; +pub type u_int = __u_int; +pub type u_long = __u_long; +pub type quad_t = __quad_t; +pub type u_quad_t = __u_quad_t; +pub type fsid_t = __fsid_t; +pub type loff_t = __loff_t; +pub type ino_t = __ino_t; +pub type ino64_t = __ino64_t; +pub type dev_t = __dev_t; +pub type mode_t = __mode_t; +pub type nlink_t = __nlink_t; +pub type id_t = __id_t; +pub type daddr_t = __daddr_t; +pub type caddr_t = __caddr_t; +pub type key_t = __key_t; +pub type clock_t = __clock_t; +pub type clockid_t = __clockid_t; +pub type time_t = __time_t; +pub type timer_t = __timer_t; +pub type suseconds_t = __suseconds_t; +pub type ulong = c_ulong; +pub type ushort = c_ushort; +pub type uint = c_uint; +pub type u_int8_t = __uint8_t; +pub type u_int16_t = __uint16_t; +pub type u_int32_t = __uint32_t; +pub type u_int64_t = __uint64_t; +pub type register_t = c_int; +pub type __sigset_t = c_ulong; +pub type sigset_t = __sigset_t; + +pub type __fd_mask = c_long; +pub type fd_mask = __fd_mask; +pub type blksize_t = __blksize_t; +pub type blkcnt_t = __blkcnt_t; +pub type fsblkcnt_t = __fsblkcnt_t; +pub type fsfilcnt_t = __fsfilcnt_t; +pub type blkcnt64_t = __blkcnt64_t; +pub type fsblkcnt64_t = __fsblkcnt64_t; +pub type fsfilcnt64_t = __fsfilcnt64_t; + +pub type __pthread_spinlock_t = c_int; +pub type __tss_t = c_int; +pub type __thrd_t = c_long; +pub type __pthread_t = c_long; +pub type pthread_t = __pthread_t; +pub type __pthread_process_shared = c_uint; +pub type __pthread_inheritsched = c_uint; +pub type __pthread_contentionscope = c_uint; +pub type __pthread_detachstate = c_uint; +pub type pthread_attr_t = __pthread_attr; +pub type __pthread_mutex_protocol = c_uint; +pub type __pthread_mutex_type = c_uint; +pub type __pthread_mutex_robustness = c_uint; +pub type pthread_mutexattr_t = __pthread_mutexattr; +pub type pthread_mutex_t = __pthread_mutex; +pub type pthread_condattr_t = __pthread_condattr; +pub type pthread_cond_t = __pthread_cond; +pub type pthread_spinlock_t = __pthread_spinlock_t; +pub type pthread_rwlockattr_t = __pthread_rwlockattr; +pub type pthread_rwlock_t = __pthread_rwlock; +pub type pthread_barrierattr_t = __pthread_barrierattr; +pub type pthread_barrier_t = __pthread_barrier; +pub type __pthread_key = c_int; +pub type pthread_key_t = __pthread_key; +pub type pthread_once_t = __pthread_once; + +pub type __rlimit_resource = c_uint; +pub type __rlimit_resource_t = __rlimit_resource; +pub type rlim_t = __rlim_t; +pub type rlim64_t = __rlim64_t; + +pub type __rusage_who = c_int; + +pub type __priority_which = c_uint; + +pub type sa_family_t = c_uchar; + +pub type in_port_t = u16; + +pub type __sigval_t = crate::sigval; + +pub type sigevent_t = sigevent; + +pub type nfds_t = c_ulong; + +pub type tcflag_t = c_uint; +pub type cc_t = c_uchar; +pub type speed_t = c_int; + +pub type sigval_t = crate::sigval; + +pub type greg_t = c_int; +pub type gregset_t = [greg_t; 19usize]; + +pub type __ioctl_dir = c_uint; + +pub type __ioctl_datum = c_uint; + +pub type __error_t_codes = c_int; + +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = c_schar; +pub type uint_fast8_t = c_uchar; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; + +pub type tcp_seq = u32; + +pub type tcp_ca_state = c_uint; + +pub type idtype_t = c_uint; + +pub type mqd_t = c_int; + +pub type Lmid_t = c_long; + +pub type regoff_t = c_int; + +pub type nl_item = c_int; + +pub type iconv_t = *mut c_void; + +extern_ty! { + pub enum fpos64_t {} // FIXME(hurd): fill this out with a struct + pub enum timezone {} +} + +// structs +s! { + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + pub imr_sourceaddr: in_addr, + } + + pub struct sockaddr { + pub sa_len: c_uchar, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14usize], + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct sockaddr_in { + pub sin_len: c_uchar, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_uchar; 8usize], + } + + pub struct sockaddr_in6 { + pub sin6_len: c_uchar, + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_un { + pub sun_len: c_uchar, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108usize], + } + + pub struct sockaddr_storage { + pub ss_len: c_uchar, + pub ss_family: sa_family_t, + __ss_padding: Padding<[c_char; 122usize]>, + __ss_align: __uint32_t, + } + + pub struct sockaddr_at { + pub _address: u8, + } + + pub struct sockaddr_ax25 { + pub _address: u8, + } + + pub struct sockaddr_x25 { + pub _address: u8, + } + + pub struct sockaddr_dl { + pub _address: u8, + } + pub struct sockaddr_eon { + pub _address: u8, + } + pub struct sockaddr_inarp { + pub _address: u8, + } + + pub struct sockaddr_ipx { + pub _address: u8, + } + pub struct sockaddr_iso { + pub _address: u8, + } + + pub struct sockaddr_ns { + pub _address: u8, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: crate::socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct dirent { + pub d_ino: __ino_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_namlen: c_uchar, + pub d_name: [c_char; 1usize], + } + + pub struct dirent64 { + pub d_ino: __ino64_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_namlen: c_uchar, + pub d_name: [c_char; 1usize], + } + + pub struct fd_set { + pub fds_bits: [__fd_mask; 8usize], + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; 20usize], + pub __ispeed: crate::speed_t, + pub __ospeed: crate::speed_t, + } + + pub struct mallinfo { + pub arena: c_int, + pub ordblks: c_int, + pub smblks: c_int, + pub hblks: c_int, + pub hblkhd: c_int, + pub usmblks: c_int, + pub fsmblks: c_int, + pub uordblks: c_int, + pub fordblks: c_int, + pub keepcost: c_int, + } + + pub struct mallinfo2 { + pub arena: size_t, + pub ordblks: size_t, + pub smblks: size_t, + pub hblks: size_t, + pub hblkhd: size_t, + pub usmblks: size_t, + pub fsmblks: size_t, + pub uordblks: size_t, + pub fordblks: size_t, + pub keepcost: size_t, + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: __sigset_t, + pub sa_flags: c_int, + } + + pub struct sigevent { + pub sigev_value: crate::sigval, + pub sigev_signo: c_int, + pub sigev_notify: c_int, + __unused1: Padding<*mut c_void>, //actually a function pointer + pub sigev_notify_attributes: *mut pthread_attr_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub si_pid: __pid_t, + pub si_uid: __uid_t, + pub si_addr: *mut c_void, + pub si_status: c_int, + pub si_band: c_long, + pub si_value: crate::sigval, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: __time_t, + pub tv_nsec: __syscall_slong_t, + } + + pub struct __timeval { + pub tv_sec: i32, + pub tv_usec: i32, + } + + pub struct __locale_data { + pub _address: u8, + } + + pub struct stat { + pub st_fstype: c_int, + pub st_dev: __fsid_t, /* Actually st_fsid */ + pub st_ino: __ino_t, + pub st_gen: c_uint, + pub st_rdev: __dev_t, + pub st_mode: __mode_t, + pub st_nlink: __nlink_t, + pub st_uid: __uid_t, + pub st_gid: __gid_t, + pub st_size: __off_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + pub st_blksize: __blksize_t, + pub st_blocks: __blkcnt_t, + pub st_author: __uid_t, + pub st_flags: c_uint, + pub st_spare: [c_int; 11usize], + } + + pub struct stat64 { + pub st_fstype: c_int, + pub st_dev: __fsid_t, /* Actually st_fsid */ + pub st_ino: __ino64_t, + pub st_gen: c_uint, + pub st_rdev: __dev_t, + pub st_mode: __mode_t, + pub st_nlink: __nlink_t, + pub st_uid: __uid_t, + pub st_gid: __gid_t, + pub st_size: __off64_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + pub st_blksize: __blksize_t, + pub st_blocks: __blkcnt64_t, + pub st_author: __uid_t, + pub st_flags: c_uint, + pub st_spare: [c_int; 8usize], + } + + pub struct statx { + pub stx_mask: u32, + pub stx_blksize: u32, + pub stx_attributes: u64, + pub stx_nlink: u32, + pub stx_uid: u32, + pub stx_gid: u32, + pub stx_mode: u16, + __statx_pad1: Padding<[u16; 1]>, + pub stx_ino: u64, + pub stx_size: u64, + pub stx_blocks: u64, + pub stx_attributes_mask: u64, + pub stx_atime: crate::statx_timestamp, + pub stx_btime: crate::statx_timestamp, + pub stx_ctime: crate::statx_timestamp, + pub stx_mtime: crate::statx_timestamp, + pub stx_rdev_major: u32, + pub stx_rdev_minor: u32, + pub stx_dev_major: u32, + pub stx_dev_minor: u32, + __statx_pad2: Padding<[u64; 14]>, + } + + pub struct statx_timestamp { + pub tv_sec: i64, + pub tv_nsec: u32, + pub __statx_timestamp_pad1: [i32; 1], + } + + pub struct statfs { + pub f_type: c_uint, + pub f_bsize: c_ulong, + pub f_blocks: __fsblkcnt_t, + pub f_bfree: __fsblkcnt_t, + pub f_bavail: __fsblkcnt_t, + pub f_files: __fsblkcnt_t, + pub f_ffree: __fsblkcnt_t, + pub f_fsid: __fsid_t, + pub f_namelen: c_ulong, + pub f_favail: __fsfilcnt_t, + pub f_frsize: c_ulong, + pub f_flag: c_ulong, + pub f_spare: [c_uint; 3usize], + } + + pub struct statfs64 { + pub f_type: c_uint, + pub f_bsize: c_ulong, + pub f_blocks: __fsblkcnt64_t, + pub f_bfree: __fsblkcnt64_t, + pub f_bavail: __fsblkcnt64_t, + pub f_files: __fsblkcnt64_t, + pub f_ffree: __fsblkcnt64_t, + pub f_fsid: __fsid_t, + pub f_namelen: c_ulong, + pub f_favail: __fsfilcnt64_t, + pub f_frsize: c_ulong, + pub f_flag: c_ulong, + pub f_spare: [c_uint; 3usize], + } + + pub struct statvfs { + pub __f_type: c_uint, + pub f_bsize: c_ulong, + pub f_blocks: __fsblkcnt_t, + pub f_bfree: __fsblkcnt_t, + pub f_bavail: __fsblkcnt_t, + pub f_files: __fsfilcnt_t, + pub f_ffree: __fsfilcnt_t, + pub f_fsid: __fsid_t, + pub f_namemax: c_ulong, + pub f_favail: __fsfilcnt_t, + pub f_frsize: c_ulong, + pub f_flag: c_ulong, + pub f_spare: [c_uint; 3usize], + } + + pub struct statvfs64 { + pub __f_type: c_uint, + pub f_bsize: c_ulong, + pub f_blocks: __fsblkcnt64_t, + pub f_bfree: __fsblkcnt64_t, + pub f_bavail: __fsblkcnt64_t, + pub f_files: __fsfilcnt64_t, + pub f_ffree: __fsfilcnt64_t, + pub f_fsid: __fsid_t, + pub f_namemax: c_ulong, + pub f_favail: __fsfilcnt64_t, + pub f_frsize: c_ulong, + pub f_flag: c_ulong, + pub f_spare: [c_uint; 3usize], + } + + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: crate::sigevent, + __next_prio: *mut aiocb, + __abs_prio: c_int, + __policy: c_int, + __error_code: c_int, + __return_value: ssize_t, + pub aio_offset: off_t, + #[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))] + __unused1: Padding<[c_char; 4]>, + __glibc_reserved: Padding<[c_char; 32]>, + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + } + + pub struct __exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct sem_t { + __size: [c_char; 20usize], + } + + pub struct __pthread { + pub _address: u8, + } + + pub struct __pthread_mutexattr { + pub __prioceiling: c_int, + pub __protocol: __pthread_mutex_protocol, + pub __pshared: __pthread_process_shared, + pub __mutex_type: __pthread_mutex_type, + } + pub struct __pthread_mutex { + pub __lock: c_uint, + pub __owner_id: c_uint, + pub __cnt: c_uint, + pub __shpid: c_int, + pub __type: c_int, + pub __flags: c_int, + __reserved1: Padding, + __reserved2: Padding, + } + + pub struct __pthread_condattr { + pub __pshared: __pthread_process_shared, + pub __clock: __clockid_t, + } + + pub struct __pthread_rwlockattr { + pub __pshared: __pthread_process_shared, + } + + pub struct __pthread_barrierattr { + pub __pshared: __pthread_process_shared, + } + + pub struct __pthread_once { + pub __run: c_int, + pub __lock: __pthread_spinlock_t, + } + + pub struct __pthread_cond { + pub __lock: __pthread_spinlock_t, + pub __queue: *mut __pthread, + pub __attr: *mut __pthread_condattr, + pub __wrefs: c_uint, + pub __data: *mut c_void, + } + + pub struct __pthread_attr { + pub __schedparam: sched_param, + pub __stackaddr: *mut c_void, + pub __stacksize: size_t, + pub __guardsize: size_t, + pub __detachstate: __pthread_detachstate, + pub __inheritsched: __pthread_inheritsched, + pub __contentionscope: __pthread_contentionscope, + pub __schedpolicy: c_int, + } + + pub struct __pthread_rwlock { + pub __held: __pthread_spinlock_t, + pub __lock: __pthread_spinlock_t, + pub __readers: c_int, + pub __readerqueue: *mut __pthread, + pub __writerqueue: *mut __pthread, + pub __attr: *mut __pthread_rwlockattr, + pub __data: *mut c_void, + } + + pub struct __pthread_barrier { + pub __lock: __pthread_spinlock_t, + pub __queue: *mut __pthread, + pub __pending: c_uint, + pub __count: c_uint, + pub __attr: *mut __pthread_barrierattr, + pub __data: *mut c_void, + } + + pub struct seminfo { + pub semmap: c_int, + pub semmni: c_int, + pub semmns: c_int, + pub semmnu: c_int, + pub semmsl: c_int, + pub semopm: c_int, + pub semume: c_int, + pub semusz: c_int, + pub semvmx: c_int, + pub semaem: c_int, + } + + pub struct _IO_FILE { + _unused: Padding<[u8; 0]>, + } + + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: __uid_t, + pub pw_gid: __gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct spwd { + pub sp_namp: *mut c_char, + pub sp_pwdp: *mut c_char, + pub sp_lstchg: c_long, + pub sp_min: c_long, + pub sp_max: c_long, + pub sp_warn: c_long, + pub sp_inact: c_long, + pub sp_expire: c_long, + pub sp_flag: c_ulong, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_ifu: *mut crate::sockaddr, // FIXME(union) This should be a union + pub ifa_data: *mut c_void, + } + + pub struct arpreq { + pub arp_pa: crate::sockaddr, + pub arp_ha: crate::sockaddr, + pub arp_flags: c_int, + pub arp_netmask: crate::sockaddr, + pub arp_dev: [c_char; 16], + } + + pub struct arpreq_old { + pub arp_pa: crate::sockaddr, + pub arp_ha: crate::sockaddr, + pub arp_flags: c_int, + pub arp_netmask: crate::sockaddr, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct arpd_request { + pub req: c_ushort, + pub ip: u32, + pub dev: c_ulong, + pub stamp: c_ulong, + pub updated: c_ulong, + pub ha: [c_uchar; crate::MAX_ADDR_LEN], + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } + + pub struct ifreq { + /// interface name, e.g. "en0" + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: crate::sockaddr, + } + + pub struct __locale_struct { + pub __locales: [*mut __locale_data; 13usize], + pub __ctype_b: *const c_ushort, + pub __ctype_tolower: *const c_int, + pub __ctype_toupper: *const c_int, + pub __names: [*const c_char; 13usize], + } + + pub struct utsname { + pub sysname: [c_char; _UTSNAME_LENGTH], + pub nodename: [c_char; _UTSNAME_LENGTH], + pub release: [c_char; _UTSNAME_LENGTH], + pub version: [c_char; _UTSNAME_LENGTH], + pub machine: [c_char; _UTSNAME_LENGTH], + pub domainname: [c_char; _UTSNAME_LENGTH], + } + + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct dl_phdr_info { + pub dlpi_addr: Elf_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const Elf_Phdr, + pub dlpi_phnum: Elf_Half, + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: size_t, + pub dlpi_tls_data: *mut c_void, + } + + pub struct flock { + #[cfg(target_pointer_width = "32")] + pub l_type: c_int, + #[cfg(target_pointer_width = "32")] + pub l_whence: c_int, + #[cfg(target_pointer_width = "64")] + pub l_type: c_short, + #[cfg(target_pointer_width = "64")] + pub l_whence: c_short, + pub l_start: __off_t, + pub l_len: __off_t, + pub l_pid: __pid_t, + } + + pub struct flock64 { + #[cfg(target_pointer_width = "32")] + pub l_type: c_int, + #[cfg(target_pointer_width = "32")] + pub l_whence: c_int, + #[cfg(target_pointer_width = "64")] + pub l_type: c_short, + #[cfg(target_pointer_width = "64")] + pub l_whence: c_short, + pub l_start: __off_t, + pub l_len: __off64_t, + pub l_pid: __pid_t, + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct glob64_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct regex_t { + __buffer: *mut c_void, + __allocated: size_t, + __used: size_t, + __syntax: c_ulong, + __fastmap: *mut c_char, + __translate: *mut c_char, + __re_nsub: size_t, + __bitfield: u8, + } + + pub struct cpu_set_t { + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))] + bits: [u32; 32], + #[cfg(not(all(target_pointer_width = "32", not(target_arch = "x86_64"))))] + bits: [u64; 16], + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: c_int, + pub msgmap: c_int, + pub msgmax: c_int, + pub msgmnb: c_int, + pub msgmni: c_int, + pub msgssz: c_int, + pub msgtql: c_int, + pub msgseg: c_ushort, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct mntent { + pub mnt_fsname: *mut c_char, + pub mnt_dir: *mut c_char, + pub mnt_type: *mut c_char, + pub mnt_opts: *mut c_char, + pub mnt_freq: c_int, + pub mnt_passno: c_int, + } + + pub struct posix_spawn_file_actions_t { + __allocated: c_int, + __used: c_int, + __actions: *mut c_int, + __pad: Padding<[c_int; 16]>, + } + + pub struct posix_spawnattr_t { + __flags: c_short, + __pgrp: crate::pid_t, + __sd: crate::sigset_t, + __ss: crate::sigset_t, + __sp: crate::sched_param, + __policy: c_int, + __pad: Padding<[c_int; 16]>, + } + + pub struct regmatch_t { + pub rm_so: regoff_t, + pub rm_eo: regoff_t, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + + pub struct utmpx { + pub ut_type: c_short, + pub ut_pid: crate::pid_t, + pub ut_line: [c_char; __UT_LINESIZE], + pub ut_id: [c_char; 4], + + pub ut_user: [c_char; __UT_NAMESIZE], + pub ut_host: [c_char; __UT_HOSTSIZE], + pub ut_exit: __exit_status, + + #[cfg(any(all(target_pointer_width = "32", not(target_arch = "x86_64"))))] + pub ut_session: c_long, + #[cfg(any(all(target_pointer_width = "32", not(target_arch = "x86_64"))))] + pub ut_tv: crate::timeval, + + #[cfg(not(any(all(target_pointer_width = "32", not(target_arch = "x86_64")))))] + pub ut_session: i32, + #[cfg(not(any(all(target_pointer_width = "32", not(target_arch = "x86_64")))))] + pub ut_tv: __timeval, + + pub ut_addr_v6: [i32; 4], + __glibc_reserved: Padding<[c_char; 20]>, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + self.si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +// const + +// aio.h +pub const AIO_CANCELED: c_int = 0; +pub const AIO_NOTCANCELED: c_int = 1; +pub const AIO_ALLDONE: c_int = 2; +pub const LIO_READ: c_int = 0; +pub const LIO_WRITE: c_int = 1; +pub const LIO_NOP: c_int = 2; +pub const LIO_WAIT: c_int = 0; +pub const LIO_NOWAIT: c_int = 1; + +// glob.h +pub const GLOB_ERR: c_int = 1 << 0; +pub const GLOB_MARK: c_int = 1 << 1; +pub const GLOB_NOSORT: c_int = 1 << 2; +pub const GLOB_DOOFFS: c_int = 1 << 3; +pub const GLOB_NOCHECK: c_int = 1 << 4; +pub const GLOB_APPEND: c_int = 1 << 5; +pub const GLOB_NOESCAPE: c_int = 1 << 6; + +pub const GLOB_NOSPACE: c_int = 1; +pub const GLOB_ABORTED: c_int = 2; +pub const GLOB_NOMATCH: c_int = 3; + +pub const GLOB_PERIOD: c_int = 1 << 7; +pub const GLOB_ALTDIRFUNC: c_int = 1 << 9; +pub const GLOB_BRACE: c_int = 1 << 10; +pub const GLOB_NOMAGIC: c_int = 1 << 11; +pub const GLOB_TILDE: c_int = 1 << 12; +pub const GLOB_ONLYDIR: c_int = 1 << 13; +pub const GLOB_TILDE_CHECK: c_int = 1 << 14; + +// ipc.h +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_CREAT: c_int = 0o1000; +pub const IPC_EXCL: c_int = 0o2000; +pub const IPC_NOWAIT: c_int = 0o4000; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; +pub const IPC_INFO: c_int = 3; +pub const MSG_STAT: c_int = 11; +pub const MSG_INFO: c_int = 12; + +pub const MSG_NOERROR: c_int = 0o10000; +pub const MSG_EXCEPT: c_int = 0o20000; + +// shm.h +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; + +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_REMAP: c_int = 0o40000; + +pub const SHM_LOCK: c_int = 11; +pub const SHM_UNLOCK: c_int = 12; +// unistd.h +pub const __FD_SETSIZE: usize = 256; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const F_OK: c_int = 0; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const SEEK_DATA: c_int = 3; +pub const SEEK_HOLE: c_int = 4; +pub const L_SET: c_int = 0; +pub const L_INCR: c_int = 1; +pub const L_XTND: c_int = 2; +pub const F_ULOCK: c_int = 0; +pub const F_LOCK: c_int = 1; +pub const F_TLOCK: c_int = 2; +pub const F_TEST: c_int = 3; +pub const CLOSE_RANGE_CLOEXEC: c_int = 4; + +// stdio.h +pub const EOF: c_int = -1; + +// stdlib.h +pub const WNOHANG: c_int = 1; +pub const WUNTRACED: c_int = 2; +pub const WSTOPPED: c_int = 2; +pub const WCONTINUED: c_int = 4; +pub const WNOWAIT: c_int = 8; +pub const WEXITED: c_int = 16; +pub const __W_CONTINUED: c_int = 65535; +pub const __WCOREFLAG: c_int = 128; +pub const RAND_MAX: c_int = 2147483647; +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const __LITTLE_ENDIAN: usize = 1234; +pub const __BIG_ENDIAN: usize = 4321; +pub const __PDP_ENDIAN: usize = 3412; +pub const __BYTE_ORDER: usize = 1234; +pub const __FLOAT_WORD_ORDER: usize = 1234; +pub const LITTLE_ENDIAN: usize = 1234; +pub const BIG_ENDIAN: usize = 4321; +pub const PDP_ENDIAN: usize = 3412; +pub const BYTE_ORDER: usize = 1234; + +// sys/select.h +pub const FD_SETSIZE: usize = 256; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 32; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 28; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 24; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 16; +pub const __SIZEOF_PTHREAD_COND_T: usize = 20; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_ONCE_T: usize = 8; +pub const __PTHREAD_SPIN_LOCK_INITIALIZER: c_int = 0; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; + +// sys/resource.h +pub const RLIM_INFINITY: crate::rlim_t = 2147483647; +pub const RLIM64_INFINITY: crate::rlim64_t = 9223372036854775807; +pub const RLIM_SAVED_MAX: crate::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: crate::rlim_t = RLIM_INFINITY; +pub const PRIO_MIN: c_int = -20; +pub const PRIO_MAX: c_int = 20; + +// pwd.h +pub const NSS_BUFLEN_PASSWD: usize = 1024; + +// sys/socket.h +pub const SOCK_TYPE_MASK: usize = 15; +pub const PF_UNSPEC: c_int = 0; +pub const PF_LOCAL: c_int = 1; +pub const PF_UNIX: c_int = 1; +pub const PF_FILE: c_int = 1; +pub const PF_INET: c_int = 2; +pub const PF_IMPLINK: c_int = 3; +pub const PF_PUP: c_int = 4; +pub const PF_CHAOS: c_int = 5; +pub const PF_NS: c_int = 6; +pub const PF_ISO: c_int = 7; +pub const PF_OSI: c_int = 7; +pub const PF_ECMA: c_int = 8; +pub const PF_DATAKIT: c_int = 9; +pub const PF_CCITT: c_int = 10; +pub const PF_SNA: c_int = 11; +pub const PF_DECnet: c_int = 12; +pub const PF_DLI: c_int = 13; +pub const PF_LAT: c_int = 14; +pub const PF_HYLINK: c_int = 15; +pub const PF_APPLETALK: c_int = 16; +pub const PF_ROUTE: c_int = 17; +pub const PF_XTP: c_int = 19; +pub const PF_COIP: c_int = 20; +pub const PF_CNT: c_int = 21; +pub const PF_RTIP: c_int = 22; +pub const PF_IPX: c_int = 23; +pub const PF_SIP: c_int = 24; +pub const PF_PIP: c_int = 25; +pub const PF_INET6: c_int = 26; +pub const PF_MAX: c_int = 27; +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const AF_UNIX: c_int = 1; +pub const AF_FILE: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = 7; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_ROUTE: c_int = 17; +pub const pseudo_AF_XTP: c_int = 19; +pub const AF_COIP: c_int = 20; +pub const AF_CNT: c_int = 21; +pub const pseudo_AF_RTIP: c_int = 22; +pub const AF_IPX: c_int = 23; +pub const AF_SIP: c_int = 24; +pub const pseudo_AF_PIP: c_int = 25; +pub const AF_INET6: c_int = 26; +pub const AF_MAX: c_int = 27; +pub const SOMAXCONN: c_int = 4096; +pub const _SS_SIZE: usize = 128; +pub const CMGROUP_MAX: usize = 16; +pub const SOL_SOCKET: c_int = 65535; + +// sys/time.h +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +// netinet/in.h +pub const SOL_IP: c_int = 0; +pub const SOL_TCP: c_int = 6; +pub const SOL_UDP: c_int = 17; +pub const SOL_IPV6: c_int = 41; +pub const SOL_ICMPV6: c_int = 58; +pub const IP_OPTIONS: c_int = 1; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_RECVOPTS: c_int = 5; +pub const IP_RECVRETOPTS: c_int = 6; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_RETOPTS: c_int = 8; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IPV6_ADDRFORM: c_int = 1; +pub const IPV6_2292PKTINFO: c_int = 2; +pub const IPV6_2292HOPOPTS: c_int = 3; +pub const IPV6_2292DSTOPTS: c_int = 4; +pub const IPV6_2292RTHDR: c_int = 5; +pub const IPV6_2292PKTOPTIONS: c_int = 6; +pub const IPV6_CHECKSUM: c_int = 7; +pub const IPV6_2292HOPLIMIT: c_int = 8; +pub const IPV6_RXINFO: c_int = 2; +pub const IPV6_TXINFO: c_int = 2; +pub const SCM_SRCINFO: c_int = 2; +pub const IPV6_UNICAST_HOPS: c_int = 16; +pub const IPV6_MULTICAST_IF: c_int = 17; +pub const IPV6_MULTICAST_HOPS: c_int = 18; +pub const IPV6_MULTICAST_LOOP: c_int = 19; +pub const IPV6_JOIN_GROUP: c_int = 20; +pub const IPV6_LEAVE_GROUP: c_int = 21; +pub const IPV6_ROUTER_ALERT: c_int = 22; +pub const IPV6_MTU_DISCOVER: c_int = 23; +pub const IPV6_MTU: c_int = 24; +pub const IPV6_RECVERR: c_int = 25; +pub const IPV6_V6ONLY: c_int = 26; +pub const IPV6_JOIN_ANYCAST: c_int = 27; +pub const IPV6_LEAVE_ANYCAST: c_int = 28; +pub const IPV6_RECVPKTINFO: c_int = 49; +pub const IPV6_PKTINFO: c_int = 50; +pub const IPV6_RECVHOPLIMIT: c_int = 51; +pub const IPV6_HOPLIMIT: c_int = 52; +pub const IPV6_RECVHOPOPTS: c_int = 53; +pub const IPV6_HOPOPTS: c_int = 54; +pub const IPV6_RTHDRDSTOPTS: c_int = 55; +pub const IPV6_RECVRTHDR: c_int = 56; +pub const IPV6_RTHDR: c_int = 57; +pub const IPV6_RECVDSTOPTS: c_int = 58; +pub const IPV6_DSTOPTS: c_int = 59; +pub const IPV6_RECVPATHMTU: c_int = 60; +pub const IPV6_PATHMTU: c_int = 61; +pub const IPV6_DONTFRAG: c_int = 62; +pub const IPV6_RECVTCLASS: c_int = 66; +pub const IPV6_TCLASS: c_int = 67; +pub const IPV6_ADDR_PREFERENCES: c_int = 72; +pub const IPV6_MINHOPCOUNT: c_int = 73; +pub const IPV6_ADD_MEMBERSHIP: c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: c_int = 21; +pub const IPV6_RXHOPOPTS: c_int = 3; +pub const IPV6_RXDSTOPTS: c_int = 4; +pub const IPV6_RTHDR_LOOSE: c_int = 0; +pub const IPV6_RTHDR_STRICT: c_int = 1; +pub const IPV6_RTHDR_TYPE_0: c_int = 0; +pub const IN_CLASSA_NET: u32 = 4278190080; +pub const IN_CLASSA_NSHIFT: usize = 24; +pub const IN_CLASSA_HOST: u32 = 16777215; +pub const IN_CLASSA_MAX: u32 = 128; +pub const IN_CLASSB_NET: u32 = 4294901760; +pub const IN_CLASSB_NSHIFT: usize = 16; +pub const IN_CLASSB_HOST: u32 = 65535; +pub const IN_CLASSB_MAX: u32 = 65536; +pub const IN_CLASSC_NET: u32 = 4294967040; +pub const IN_CLASSC_NSHIFT: usize = 8; +pub const IN_CLASSC_HOST: u32 = 255; +pub const IN_LOOPBACKNET: u32 = 127; +pub const INET_ADDRSTRLEN: usize = 16; +pub const INET6_ADDRSTRLEN: usize = 46; + +// netinet/ip.h +pub const IPTOS_TOS_MASK: u8 = 0x1E; +pub const IPTOS_PREC_MASK: u8 = 0xE0; + +pub const IPTOS_ECN_NOT_ECT: u8 = 0x00; + +pub const IPTOS_LOWDELAY: u8 = 0x10; +pub const IPTOS_THROUGHPUT: u8 = 0x08; +pub const IPTOS_RELIABILITY: u8 = 0x04; +pub const IPTOS_MINCOST: u8 = 0x02; + +pub const IPTOS_PREC_NETCONTROL: u8 = 0xe0; +pub const IPTOS_PREC_INTERNETCONTROL: u8 = 0xc0; +pub const IPTOS_PREC_CRITIC_ECP: u8 = 0xa0; +pub const IPTOS_PREC_FLASHOVERRIDE: u8 = 0x80; +pub const IPTOS_PREC_FLASH: u8 = 0x60; +pub const IPTOS_PREC_IMMEDIATE: u8 = 0x40; +pub const IPTOS_PREC_PRIORITY: u8 = 0x20; +pub const IPTOS_PREC_ROUTINE: u8 = 0x00; + +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const IPOPT_COPY: u8 = 0x80; +pub const IPOPT_CLASS_MASK: u8 = 0x60; +pub const IPOPT_NUMBER_MASK: u8 = 0x1f; + +pub const IPOPT_CONTROL: u8 = 0x00; +pub const IPOPT_RESERVED1: u8 = 0x20; +pub const IPOPT_MEASUREMENT: u8 = 0x40; +pub const IPOPT_RESERVED2: u8 = 0x60; +pub const IPOPT_END: u8 = 0 | IPOPT_CONTROL; +pub const IPOPT_NOOP: u8 = 1 | IPOPT_CONTROL; +pub const IPOPT_SEC: u8 = 2 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_LSRR: u8 = 3 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_TIMESTAMP: u8 = 4 | IPOPT_MEASUREMENT; +pub const IPOPT_RR: u8 = 7 | IPOPT_CONTROL; +pub const IPOPT_SID: u8 = 8 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_SSRR: u8 = 9 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_RA: u8 = 20 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPVERSION: u8 = 4; +pub const MAXTTL: u8 = 255; +pub const IPDEFTTL: u8 = 64; +pub const IPOPT_OPTVAL: u8 = 0; +pub const IPOPT_OLEN: u8 = 1; +pub const IPOPT_OFFSET: u8 = 2; +pub const IPOPT_MINOFF: u8 = 4; +pub const MAX_IPOPTLEN: u8 = 40; +pub const IPOPT_NOP: u8 = IPOPT_NOOP; +pub const IPOPT_EOL: u8 = IPOPT_END; +pub const IPOPT_TS: u8 = IPOPT_TIMESTAMP; +pub const IPOPT_TS_TSONLY: u8 = 0; +pub const IPOPT_TS_TSANDADDR: u8 = 1; +pub const IPOPT_TS_PRESPEC: u8 = 3; + +// net/if_arp.h +pub const ARPOP_REQUEST: u16 = 1; +pub const ARPOP_REPLY: u16 = 2; +pub const ARPOP_RREQUEST: u16 = 3; +pub const ARPOP_RREPLY: u16 = 4; +pub const ARPOP_InREQUEST: u16 = 8; +pub const ARPOP_InREPLY: u16 = 9; +pub const ARPOP_NAK: u16 = 10; + +pub const MAX_ADDR_LEN: usize = 7; +pub const ARPD_UPDATE: c_ushort = 0x01; +pub const ARPD_LOOKUP: c_ushort = 0x02; +pub const ARPD_FLUSH: c_ushort = 0x03; +pub const ATF_MAGIC: c_int = 0x80; + +pub const ATF_NETMASK: c_int = 0x20; +pub const ATF_DONTPUB: c_int = 0x40; + +pub const ARPHRD_NETROM: u16 = 0; +pub const ARPHRD_ETHER: u16 = 1; +pub const ARPHRD_EETHER: u16 = 2; +pub const ARPHRD_AX25: u16 = 3; +pub const ARPHRD_PRONET: u16 = 4; +pub const ARPHRD_CHAOS: u16 = 5; +pub const ARPHRD_IEEE802: u16 = 6; +pub const ARPHRD_ARCNET: u16 = 7; +pub const ARPHRD_APPLETLK: u16 = 8; +pub const ARPHRD_DLCI: u16 = 15; +pub const ARPHRD_ATM: u16 = 19; +pub const ARPHRD_METRICOM: u16 = 23; +pub const ARPHRD_IEEE1394: u16 = 24; +pub const ARPHRD_EUI64: u16 = 27; +pub const ARPHRD_INFINIBAND: u16 = 32; + +pub const ARPHRD_SLIP: u16 = 256; +pub const ARPHRD_CSLIP: u16 = 257; +pub const ARPHRD_SLIP6: u16 = 258; +pub const ARPHRD_CSLIP6: u16 = 259; +pub const ARPHRD_RSRVD: u16 = 260; +pub const ARPHRD_ADAPT: u16 = 264; +pub const ARPHRD_ROSE: u16 = 270; +pub const ARPHRD_X25: u16 = 271; +pub const ARPHRD_HWX25: u16 = 272; +pub const ARPHRD_CAN: u16 = 280; +pub const ARPHRD_PPP: u16 = 512; +pub const ARPHRD_CISCO: u16 = 513; +pub const ARPHRD_HDLC: u16 = ARPHRD_CISCO; +pub const ARPHRD_LAPB: u16 = 516; +pub const ARPHRD_DDCMP: u16 = 517; +pub const ARPHRD_RAWHDLC: u16 = 518; + +pub const ARPHRD_TUNNEL: u16 = 768; +pub const ARPHRD_TUNNEL6: u16 = 769; +pub const ARPHRD_FRAD: u16 = 770; +pub const ARPHRD_SKIP: u16 = 771; +pub const ARPHRD_LOOPBACK: u16 = 772; +pub const ARPHRD_LOCALTLK: u16 = 773; +pub const ARPHRD_FDDI: u16 = 774; +pub const ARPHRD_BIF: u16 = 775; +pub const ARPHRD_SIT: u16 = 776; +pub const ARPHRD_IPDDP: u16 = 777; +pub const ARPHRD_IPGRE: u16 = 778; +pub const ARPHRD_PIMREG: u16 = 779; +pub const ARPHRD_HIPPI: u16 = 780; +pub const ARPHRD_ASH: u16 = 781; +pub const ARPHRD_ECONET: u16 = 782; +pub const ARPHRD_IRDA: u16 = 783; +pub const ARPHRD_FCPP: u16 = 784; +pub const ARPHRD_FCAL: u16 = 785; +pub const ARPHRD_FCPL: u16 = 786; +pub const ARPHRD_FCFABRIC: u16 = 787; +pub const ARPHRD_IEEE802_TR: u16 = 800; +pub const ARPHRD_IEEE80211: u16 = 801; +pub const ARPHRD_IEEE80211_PRISM: u16 = 802; +pub const ARPHRD_IEEE80211_RADIOTAP: u16 = 803; +pub const ARPHRD_IEEE802154: u16 = 804; + +pub const ARPHRD_VOID: u16 = 0xFFFF; +pub const ARPHRD_NONE: u16 = 0xFFFE; + +// bits/posix1_lim.h +pub const _POSIX_AIO_LISTIO_MAX: usize = 2; +pub const _POSIX_AIO_MAX: usize = 1; +pub const _POSIX_ARG_MAX: usize = 4096; +pub const _POSIX_CHILD_MAX: usize = 25; +pub const _POSIX_DELAYTIMER_MAX: usize = 32; +pub const _POSIX_HOST_NAME_MAX: usize = 255; +pub const _POSIX_LINK_MAX: usize = 8; +pub const _POSIX_LOGIN_NAME_MAX: usize = 9; +pub const _POSIX_MAX_CANON: usize = 255; +pub const _POSIX_MAX_INPUT: usize = 255; +pub const _POSIX_MQ_OPEN_MAX: usize = 8; +pub const _POSIX_MQ_PRIO_MAX: usize = 32; +pub const _POSIX_NAME_MAX: usize = 14; +pub const _POSIX_NGROUPS_MAX: usize = 8; +pub const _POSIX_OPEN_MAX: usize = 20; +pub const _POSIX_FD_SETSIZE: usize = 20; +pub const _POSIX_PATH_MAX: usize = 256; +pub const _POSIX_PIPE_BUF: usize = 512; +pub const _POSIX_RE_DUP_MAX: usize = 255; +pub const _POSIX_RTSIG_MAX: usize = 8; +pub const _POSIX_SEM_NSEMS_MAX: usize = 256; +pub const _POSIX_SEM_VALUE_MAX: usize = 32767; +pub const _POSIX_SIGQUEUE_MAX: usize = 32; +pub const _POSIX_SSIZE_MAX: usize = 32767; +pub const _POSIX_STREAM_MAX: usize = 8; +pub const _POSIX_SYMLINK_MAX: usize = 255; +pub const _POSIX_SYMLOOP_MAX: usize = 8; +pub const _POSIX_TIMER_MAX: usize = 32; +pub const _POSIX_TTY_NAME_MAX: usize = 9; +pub const _POSIX_TZNAME_MAX: usize = 6; +pub const _POSIX_QLIMIT: usize = 1; +pub const _POSIX_HIWAT: usize = 512; +pub const _POSIX_UIO_MAXIOV: usize = 16; +pub const _POSIX_CLOCKRES_MIN: usize = 20000000; +pub const NAME_MAX: usize = 255; +pub const NGROUPS_MAX: usize = 256; +pub const _POSIX_THREAD_KEYS_MAX: usize = 128; +pub const _POSIX_THREAD_DESTRUCTOR_ITERATIONS: usize = 4; +pub const _POSIX_THREAD_THREADS_MAX: usize = 64; +pub const SEM_VALUE_MAX: c_int = 2147483647; +pub const MAXNAMLEN: usize = 255; + +// netdb.h +pub const _PATH_HEQUIV: &[u8; 17usize] = b"/etc/hosts.equiv\0"; +pub const _PATH_HOSTS: &[u8; 11usize] = b"/etc/hosts\0"; +pub const _PATH_NETWORKS: &[u8; 14usize] = b"/etc/networks\0"; +pub const _PATH_NSSWITCH_CONF: &[u8; 19usize] = b"/etc/nsswitch.conf\0"; +pub const _PATH_PROTOCOLS: &[u8; 15usize] = b"/etc/protocols\0"; +pub const _PATH_SERVICES: &[u8; 14usize] = b"/etc/services\0"; +pub const HOST_NOT_FOUND: c_int = 1; +pub const TRY_AGAIN: c_int = 2; +pub const NO_RECOVERY: c_int = 3; +pub const NO_DATA: c_int = 4; +pub const NETDB_INTERNAL: c_int = -1; +pub const NETDB_SUCCESS: c_int = 0; +pub const NO_ADDRESS: c_int = 4; +pub const IPPORT_RESERVED: c_int = 1024; +pub const SCOPE_DELIMITER: u8 = 37u8; +pub const GAI_WAIT: c_int = 0; +pub const GAI_NOWAIT: c_int = 1; +pub const AI_PASSIVE: c_int = 1; +pub const AI_CANONNAME: c_int = 2; +pub const AI_NUMERICHOST: c_int = 4; +pub const AI_V4MAPPED: c_int = 8; +pub const AI_ALL: c_int = 16; +pub const AI_ADDRCONFIG: c_int = 32; +pub const AI_IDN: c_int = 64; +pub const AI_CANONIDN: c_int = 128; +pub const AI_NUMERICSERV: c_int = 1024; +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_SYSTEM: c_int = -11; +pub const EAI_OVERFLOW: c_int = -12; +pub const EAI_NODATA: c_int = -5; +pub const EAI_ADDRFAMILY: c_int = -9; +pub const EAI_INPROGRESS: c_int = -100; +pub const EAI_CANCELED: c_int = -101; +pub const EAI_NOTCANCELED: c_int = -102; +pub const EAI_ALLDONE: c_int = -103; +pub const EAI_INTR: c_int = -104; +pub const EAI_IDN_ENCODE: c_int = -105; +pub const NI_MAXHOST: usize = 1025; +pub const NI_MAXSERV: usize = 32; +pub const NI_NUMERICHOST: c_int = 1; +pub const NI_NUMERICSERV: c_int = 2; +pub const NI_NOFQDN: c_int = 4; +pub const NI_NAMEREQD: c_int = 8; +pub const NI_DGRAM: c_int = 16; +pub const NI_IDN: c_int = 32; + +// time.h +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC: crate::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 3; +pub const CLOCK_MONOTONIC_RAW: crate::clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: crate::clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: crate::clockid_t = 6; +pub const TIMER_ABSTIME: c_int = 1; +pub const TIME_UTC: c_int = 1; + +// sys/poll.h +pub const POLLIN: i16 = 1; +pub const POLLPRI: i16 = 2; +pub const POLLOUT: i16 = 4; +pub const POLLRDNORM: i16 = 1; +pub const POLLRDBAND: i16 = 2; +pub const POLLWRNORM: i16 = 4; +pub const POLLWRBAND: i16 = 4; +pub const POLLERR: i16 = 8; +pub const POLLHUP: i16 = 16; +pub const POLLNVAL: i16 = 32; + +// locale.h +pub const __LC_CTYPE: usize = 0; +pub const __LC_NUMERIC: usize = 1; +pub const __LC_TIME: usize = 2; +pub const __LC_COLLATE: usize = 3; +pub const __LC_MONETARY: usize = 4; +pub const __LC_MESSAGES: usize = 5; +pub const __LC_ALL: usize = 6; +pub const __LC_PAPER: usize = 7; +pub const __LC_NAME: usize = 8; +pub const __LC_ADDRESS: usize = 9; +pub const __LC_TELEPHONE: usize = 10; +pub const __LC_MEASUREMENT: usize = 11; +pub const __LC_IDENTIFICATION: usize = 12; +pub const LC_CTYPE: c_int = 0; +pub const LC_NUMERIC: c_int = 1; +pub const LC_TIME: c_int = 2; +pub const LC_COLLATE: c_int = 3; +pub const LC_MONETARY: c_int = 4; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = 6; +pub const LC_PAPER: c_int = 7; +pub const LC_NAME: c_int = 8; +pub const LC_ADDRESS: c_int = 9; +pub const LC_TELEPHONE: c_int = 10; +pub const LC_MEASUREMENT: c_int = 11; +pub const LC_IDENTIFICATION: c_int = 12; +pub const LC_CTYPE_MASK: c_int = 1; +pub const LC_NUMERIC_MASK: c_int = 2; +pub const LC_TIME_MASK: c_int = 4; +pub const LC_COLLATE_MASK: c_int = 8; +pub const LC_MONETARY_MASK: c_int = 16; +pub const LC_MESSAGES_MASK: c_int = 32; +pub const LC_PAPER_MASK: c_int = 128; +pub const LC_NAME_MASK: c_int = 256; +pub const LC_ADDRESS_MASK: c_int = 512; +pub const LC_TELEPHONE_MASK: c_int = 1024; +pub const LC_MEASUREMENT_MASK: c_int = 2048; +pub const LC_IDENTIFICATION_MASK: c_int = 4096; +pub const LC_ALL_MASK: c_int = 8127; + +pub const ABDAY_1: crate::nl_item = 0x20000; +pub const ABDAY_2: crate::nl_item = 0x20001; +pub const ABDAY_3: crate::nl_item = 0x20002; +pub const ABDAY_4: crate::nl_item = 0x20003; +pub const ABDAY_5: crate::nl_item = 0x20004; +pub const ABDAY_6: crate::nl_item = 0x20005; +pub const ABDAY_7: crate::nl_item = 0x20006; + +pub const DAY_1: crate::nl_item = 0x20007; +pub const DAY_2: crate::nl_item = 0x20008; +pub const DAY_3: crate::nl_item = 0x20009; +pub const DAY_4: crate::nl_item = 0x2000A; +pub const DAY_5: crate::nl_item = 0x2000B; +pub const DAY_6: crate::nl_item = 0x2000C; +pub const DAY_7: crate::nl_item = 0x2000D; + +pub const ABMON_1: crate::nl_item = 0x2000E; +pub const ABMON_2: crate::nl_item = 0x2000F; +pub const ABMON_3: crate::nl_item = 0x20010; +pub const ABMON_4: crate::nl_item = 0x20011; +pub const ABMON_5: crate::nl_item = 0x20012; +pub const ABMON_6: crate::nl_item = 0x20013; +pub const ABMON_7: crate::nl_item = 0x20014; +pub const ABMON_8: crate::nl_item = 0x20015; +pub const ABMON_9: crate::nl_item = 0x20016; +pub const ABMON_10: crate::nl_item = 0x20017; +pub const ABMON_11: crate::nl_item = 0x20018; +pub const ABMON_12: crate::nl_item = 0x20019; + +pub const MON_1: crate::nl_item = 0x2001A; +pub const MON_2: crate::nl_item = 0x2001B; +pub const MON_3: crate::nl_item = 0x2001C; +pub const MON_4: crate::nl_item = 0x2001D; +pub const MON_5: crate::nl_item = 0x2001E; +pub const MON_6: crate::nl_item = 0x2001F; +pub const MON_7: crate::nl_item = 0x20020; +pub const MON_8: crate::nl_item = 0x20021; +pub const MON_9: crate::nl_item = 0x20022; +pub const MON_10: crate::nl_item = 0x20023; +pub const MON_11: crate::nl_item = 0x20024; +pub const MON_12: crate::nl_item = 0x20025; + +pub const AM_STR: crate::nl_item = 0x20026; +pub const PM_STR: crate::nl_item = 0x20027; + +pub const D_T_FMT: crate::nl_item = 0x20028; +pub const D_FMT: crate::nl_item = 0x20029; +pub const T_FMT: crate::nl_item = 0x2002A; +pub const T_FMT_AMPM: crate::nl_item = 0x2002B; + +pub const ERA: crate::nl_item = 0x2002C; +pub const ERA_D_FMT: crate::nl_item = 0x2002E; +pub const ALT_DIGITS: crate::nl_item = 0x2002F; +pub const ERA_D_T_FMT: crate::nl_item = 0x20030; +pub const ERA_T_FMT: crate::nl_item = 0x20031; + +pub const CODESET: crate::nl_item = 14; +pub const CRNCYSTR: crate::nl_item = 0x4000F; +pub const RADIXCHAR: crate::nl_item = 0x10000; +pub const THOUSEP: crate::nl_item = 0x10001; +pub const YESEXPR: crate::nl_item = 0x50000; +pub const NOEXPR: crate::nl_item = 0x50001; +pub const YESSTR: crate::nl_item = 0x50002; +pub const NOSTR: crate::nl_item = 0x50003; + +// reboot.h +pub const RB_AUTOBOOT: c_int = 0x0; +pub const RB_ASKNAME: c_int = 0x1; +pub const RB_SINGLE: c_int = 0x2; +pub const RB_KBD: c_int = 0x4; +pub const RB_HALT: c_int = 0x8; +pub const RB_INITNAME: c_int = 0x10; +pub const RB_DFLTROOT: c_int = 0x20; +pub const RB_NOBOOTRC: c_int = 0x20; +pub const RB_ALTBOOT: c_int = 0x40; +pub const RB_UNIPROC: c_int = 0x80; +pub const RB_DEBUGGER: c_int = 0x1000; + +// semaphore.h +pub const __SIZEOF_SEM_T: usize = 20; +pub const SEM_FAILED: *mut crate::sem_t = ptr::null_mut(); + +// termios.h +pub const IGNBRK: crate::tcflag_t = 1; +pub const BRKINT: crate::tcflag_t = 2; +pub const IGNPAR: crate::tcflag_t = 4; +pub const PARMRK: crate::tcflag_t = 8; +pub const INPCK: crate::tcflag_t = 16; +pub const ISTRIP: crate::tcflag_t = 32; +pub const INLCR: crate::tcflag_t = 64; +pub const IGNCR: crate::tcflag_t = 128; +pub const ICRNL: crate::tcflag_t = 256; +pub const IXON: crate::tcflag_t = 512; +pub const IXOFF: crate::tcflag_t = 1024; +pub const IXANY: crate::tcflag_t = 2048; +pub const IMAXBEL: crate::tcflag_t = 8192; +pub const IUCLC: crate::tcflag_t = 16384; +pub const OPOST: crate::tcflag_t = 1; +pub const ONLCR: crate::tcflag_t = 2; +pub const ONOEOT: crate::tcflag_t = 8; +pub const OCRNL: crate::tcflag_t = 16; +pub const ONOCR: crate::tcflag_t = 32; +pub const ONLRET: crate::tcflag_t = 64; +pub const NLDLY: crate::tcflag_t = 768; +pub const NL0: crate::tcflag_t = 0; +pub const NL1: crate::tcflag_t = 256; +pub const TABDLY: crate::tcflag_t = 3076; +pub const TAB0: crate::tcflag_t = 0; +pub const TAB1: crate::tcflag_t = 1024; +pub const TAB2: crate::tcflag_t = 2048; +pub const TAB3: crate::tcflag_t = 4; +pub const CRDLY: crate::tcflag_t = 12288; +pub const CR0: crate::tcflag_t = 0; +pub const CR1: crate::tcflag_t = 4096; +pub const CR2: crate::tcflag_t = 8192; +pub const CR3: crate::tcflag_t = 12288; +pub const FFDLY: crate::tcflag_t = 16384; +pub const FF0: crate::tcflag_t = 0; +pub const FF1: crate::tcflag_t = 16384; +pub const BSDLY: crate::tcflag_t = 32768; +pub const BS0: crate::tcflag_t = 0; +pub const BS1: crate::tcflag_t = 32768; +pub const VTDLY: crate::tcflag_t = 65536; +pub const VT0: crate::tcflag_t = 0; +pub const VT1: crate::tcflag_t = 65536; +pub const OLCUC: crate::tcflag_t = 131072; +pub const OFILL: crate::tcflag_t = 262144; +pub const OFDEL: crate::tcflag_t = 524288; +pub const CIGNORE: crate::tcflag_t = 1; +pub const CSIZE: crate::tcflag_t = 768; +pub const CS5: crate::tcflag_t = 0; +pub const CS6: crate::tcflag_t = 256; +pub const CS7: crate::tcflag_t = 512; +pub const CS8: crate::tcflag_t = 768; +pub const CSTOPB: crate::tcflag_t = 1024; +pub const CREAD: crate::tcflag_t = 2048; +pub const PARENB: crate::tcflag_t = 4096; +pub const PARODD: crate::tcflag_t = 8192; +pub const HUPCL: crate::tcflag_t = 16384; +pub const CLOCAL: crate::tcflag_t = 32768; +pub const CRTSCTS: crate::tcflag_t = 65536; +pub const CRTS_IFLOW: crate::tcflag_t = 65536; +pub const CCTS_OFLOW: crate::tcflag_t = 65536; +pub const CDTRCTS: crate::tcflag_t = 131072; +pub const MDMBUF: crate::tcflag_t = 1048576; +pub const CHWFLOW: crate::tcflag_t = 1245184; +pub const ECHOKE: crate::tcflag_t = 1; +pub const _ECHOE: crate::tcflag_t = 2; +pub const ECHOE: crate::tcflag_t = 2; +pub const _ECHOK: crate::tcflag_t = 4; +pub const ECHOK: crate::tcflag_t = 4; +pub const _ECHO: crate::tcflag_t = 8; +pub const ECHO: crate::tcflag_t = 8; +pub const _ECHONL: crate::tcflag_t = 16; +pub const ECHONL: crate::tcflag_t = 16; +pub const ECHOPRT: crate::tcflag_t = 32; +pub const ECHOCTL: crate::tcflag_t = 64; +pub const _ISIG: crate::tcflag_t = 128; +pub const ISIG: crate::tcflag_t = 128; +pub const _ICANON: crate::tcflag_t = 256; +pub const ICANON: crate::tcflag_t = 256; +pub const ALTWERASE: crate::tcflag_t = 512; +pub const _IEXTEN: crate::tcflag_t = 1024; +pub const IEXTEN: crate::tcflag_t = 1024; +pub const EXTPROC: crate::tcflag_t = 2048; +pub const _TOSTOP: crate::tcflag_t = 4194304; +pub const TOSTOP: crate::tcflag_t = 4194304; +pub const FLUSHO: crate::tcflag_t = 8388608; +pub const NOKERNINFO: crate::tcflag_t = 33554432; +pub const PENDIN: crate::tcflag_t = 536870912; +pub const _NOFLSH: crate::tcflag_t = 2147483648; +pub const NOFLSH: crate::tcflag_t = 2147483648; +pub const VEOF: usize = 0; +pub const VEOL: usize = 1; +pub const VEOL2: usize = 2; +pub const VERASE: usize = 3; +pub const VWERASE: usize = 4; +pub const VKILL: usize = 5; +pub const VREPRINT: usize = 6; +pub const VINTR: usize = 8; +pub const VQUIT: usize = 9; +pub const VSUSP: usize = 10; +pub const VDSUSP: usize = 11; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VLNEXT: usize = 14; +pub const VDISCARD: usize = 15; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; +pub const VSTATUS: usize = 18; +pub const NCCS: usize = 20; +pub const B0: crate::speed_t = 0; +pub const B50: crate::speed_t = 50; +pub const B75: crate::speed_t = 75; +pub const B110: crate::speed_t = 110; +pub const B134: crate::speed_t = 134; +pub const B150: crate::speed_t = 150; +pub const B200: crate::speed_t = 200; +pub const B300: crate::speed_t = 300; +pub const B600: crate::speed_t = 600; +pub const B1200: crate::speed_t = 1200; +pub const B1800: crate::speed_t = 1800; +pub const B2400: crate::speed_t = 2400; +pub const B4800: crate::speed_t = 4800; +pub const B9600: crate::speed_t = 9600; +pub const B7200: crate::speed_t = 7200; +pub const B14400: crate::speed_t = 14400; +pub const B19200: crate::speed_t = 19200; +pub const B28800: crate::speed_t = 28800; +pub const B38400: crate::speed_t = 38400; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 57600; +pub const B76800: crate::speed_t = 76800; +pub const B115200: crate::speed_t = 115200; +pub const B230400: crate::speed_t = 230400; +pub const B460800: crate::speed_t = 460800; +pub const B500000: crate::speed_t = 500000; +pub const B576000: crate::speed_t = 576000; +pub const B921600: crate::speed_t = 921600; +pub const B1000000: crate::speed_t = 1000000; +pub const B1152000: crate::speed_t = 1152000; +pub const B1500000: crate::speed_t = 1500000; +pub const B2000000: crate::speed_t = 2000000; +pub const B2500000: crate::speed_t = 2500000; +pub const B3000000: crate::speed_t = 3000000; +pub const B3500000: crate::speed_t = 3500000; +pub const B4000000: crate::speed_t = 4000000; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; +pub const TCSASOFT: c_int = 16; +pub const TCIFLUSH: c_int = 1; +pub const TCOFLUSH: c_int = 2; +pub const TCIOFLUSH: c_int = 3; +pub const TCOOFF: c_int = 1; +pub const TCOON: c_int = 2; +pub const TCIOFF: c_int = 3; +pub const TCION: c_int = 4; +pub const TTYDEF_IFLAG: crate::tcflag_t = 11042; +pub const TTYDEF_LFLAG: crate::tcflag_t = 1483; +pub const TTYDEF_CFLAG: crate::tcflag_t = 23040; +pub const TTYDEF_SPEED: crate::tcflag_t = 9600; +pub const CEOL: u8 = 0u8; +pub const CERASE: u8 = 127; +pub const CMIN: u8 = 1; +pub const CQUIT: u8 = 28; +pub const CTIME: u8 = 0; +pub const CBRK: u8 = 0u8; + +// dlfcn.h +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +pub const RTLD_NEXT: *mut c_void = -1i64 as *mut c_void; +pub const RTLD_LAZY: c_int = 1; +pub const RTLD_NOW: c_int = 2; +pub const RTLD_BINDING_MASK: c_int = 3; +pub const RTLD_NOLOAD: c_int = 4; +pub const RTLD_DEEPBIND: c_int = 8; +pub const RTLD_GLOBAL: c_int = 256; +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_NODELETE: c_int = 4096; +pub const DLFO_STRUCT_HAS_EH_DBASE: usize = 1; +pub const DLFO_STRUCT_HAS_EH_COUNT: usize = 0; +pub const LM_ID_BASE: c_long = 0; +pub const LM_ID_NEWLM: c_long = -1; + +// bits/signum_generic.h +pub const SIGINT: c_int = 2; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGFPE: c_int = 8; +pub const SIGSEGV: c_int = 11; +pub const SIGTERM: c_int = 15; +pub const SIGHUP: c_int = 1; +pub const SIGQUIT: c_int = 3; +pub const SIGTRAP: c_int = 5; +pub const SIGKILL: c_int = 9; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGIOT: c_int = 6; +pub const SIGBUS: c_int = 10; +pub const SIGSYS: c_int = 12; +pub const SIGEMT: c_int = 7; +pub const SIGINFO: c_int = 29; +pub const SIGLOST: c_int = 32; +pub const SIGURG: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGPOLL: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGXFSZ: c_int = 25; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGWINCH: c_int = 28; +pub const SIGIO: c_int = 23; +pub const SIGCLD: c_int = 20; +pub const __SIGRTMIN: usize = 32; +pub const __SIGRTMAX: usize = 32; +pub const _NSIG: usize = 33; +pub const NSIG: usize = 33; + +// bits/sigaction.h +pub const SA_ONSTACK: c_int = 1; +pub const SA_RESTART: c_int = 2; +pub const SA_NODEFER: c_int = 16; +pub const SA_RESETHAND: c_int = 4; +pub const SA_NOCLDSTOP: c_int = 8; +pub const SA_SIGINFO: c_int = 64; +pub const SA_INTERRUPT: c_int = 0; +pub const SA_NOMASK: c_int = 16; +pub const SA_ONESHOT: c_int = 4; +pub const SA_STACK: c_int = 1; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 3; + +// bits/sigcontext.h +pub const FPC_IE: u16 = 1; +pub const FPC_IM: u16 = 1; +pub const FPC_DE: u16 = 2; +pub const FPC_DM: u16 = 2; +pub const FPC_ZE: u16 = 4; +pub const FPC_ZM: u16 = 4; +pub const FPC_OE: u16 = 8; +pub const FPC_OM: u16 = 8; +pub const FPC_UE: u16 = 16; +pub const FPC_PE: u16 = 32; +pub const FPC_PC: u16 = 768; +pub const FPC_PC_24: u16 = 0; +pub const FPC_PC_53: u16 = 512; +pub const FPC_PC_64: u16 = 768; +pub const FPC_RC: u16 = 3072; +pub const FPC_RC_RN: u16 = 0; +pub const FPC_RC_RD: u16 = 1024; +pub const FPC_RC_RU: u16 = 2048; +pub const FPC_RC_CHOP: u16 = 3072; +pub const FPC_IC: u16 = 4096; +pub const FPC_IC_PROJ: u16 = 0; +pub const FPC_IC_AFF: u16 = 4096; +pub const FPS_IE: u16 = 1; +pub const FPS_DE: u16 = 2; +pub const FPS_ZE: u16 = 4; +pub const FPS_OE: u16 = 8; +pub const FPS_UE: u16 = 16; +pub const FPS_PE: u16 = 32; +pub const FPS_SF: u16 = 64; +pub const FPS_ES: u16 = 128; +pub const FPS_C0: u16 = 256; +pub const FPS_C1: u16 = 512; +pub const FPS_C2: u16 = 1024; +pub const FPS_TOS: u16 = 14336; +pub const FPS_TOS_SHIFT: u16 = 11; +pub const FPS_C3: u16 = 16384; +pub const FPS_BUSY: u16 = 32768; +pub const FPE_INTOVF_TRAP: c_int = 1; +pub const FPE_INTDIV_FAULT: c_int = 2; +pub const FPE_FLTOVF_FAULT: c_int = 3; +pub const FPE_FLTDIV_FAULT: c_int = 4; +pub const FPE_FLTUND_FAULT: c_int = 5; +pub const FPE_SUBRNG_FAULT: c_int = 7; +pub const FPE_FLTDNR_FAULT: c_int = 8; +pub const FPE_FLTINX_FAULT: c_int = 9; +pub const FPE_EMERR_FAULT: c_int = 10; +pub const FPE_EMBND_FAULT: c_int = 11; +pub const ILL_INVOPR_FAULT: c_int = 1; +pub const ILL_STACK_FAULT: c_int = 2; +pub const ILL_FPEOPR_FAULT: c_int = 3; +pub const DBG_SINGLE_TRAP: c_int = 1; +pub const DBG_BRKPNT_FAULT: c_int = 2; +pub const __NGREG: usize = 19; +pub const NGREG: usize = 19; + +// bits/sigstack.h +pub const MINSIGSTKSZ: usize = 8192; +pub const SIGSTKSZ: usize = 40960; + +// sys/stat.h +pub const __S_IFMT: mode_t = 0o17_0000; +pub const __S_IFDIR: mode_t = 0o4_0000; +pub const __S_IFCHR: mode_t = 0o2_0000; +pub const __S_IFBLK: mode_t = 0o6_0000; +pub const __S_IFREG: mode_t = 0o10_0000; +pub const __S_IFLNK: mode_t = 0o12_0000; +pub const __S_IFSOCK: mode_t = 0o14_0000; +pub const __S_IFIFO: mode_t = 0o1_0000; +pub const __S_ISUID: mode_t = 0o4000; +pub const __S_ISGID: mode_t = 0o2000; +pub const __S_ISVTX: mode_t = 0o1000; +pub const __S_IREAD: mode_t = 0o0400; +pub const __S_IWRITE: mode_t = 0o0200; +pub const __S_IEXEC: mode_t = 0o0100; +pub const S_INOCACHE: mode_t = 0o20_0000; +pub const S_IUSEUNK: mode_t = 0o40_0000; +pub const S_IUNKNOWN: mode_t = 0o700_0000; +pub const S_IUNKSHIFT: mode_t = 0o0014; +pub const S_IPTRANS: mode_t = 0o1000_0000; +pub const S_IATRANS: mode_t = 0o2000_0000; +pub const S_IROOT: mode_t = 0o4000_0000; +pub const S_ITRANS: mode_t = 0o7000_0000; +pub const S_IMMAP0: mode_t = 0o10000_0000; +pub const CMASK: mode_t = 18; +pub const UF_SETTABLE: c_uint = 65535; +pub const UF_NODUMP: c_uint = 1; +pub const UF_IMMUTABLE: c_uint = 2; +pub const UF_APPEND: c_uint = 4; +pub const UF_OPAQUE: c_uint = 8; +pub const UF_NOUNLINK: c_uint = 16; +pub const SF_SETTABLE: c_uint = 4294901760; +pub const SF_ARCHIVED: c_uint = 65536; +pub const SF_IMMUTABLE: c_uint = 131072; +pub const SF_APPEND: c_uint = 262144; +pub const SF_NOUNLINK: c_uint = 1048576; +pub const SF_SNAPSHOT: c_uint = 2097152; +pub const UTIME_NOW: c_long = -1; +pub const UTIME_OMIT: c_long = -2; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_ISUID: mode_t = 0o4000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISVTX: mode_t = 0o1000; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IRWXO: mode_t = 0o0007; +pub const ACCESSPERMS: mode_t = 511; +pub const ALLPERMS: mode_t = 4095; +pub const DEFFILEMODE: mode_t = 438; +pub const S_BLKSIZE: usize = 512; +pub const STATX_TYPE: c_uint = 1; +pub const STATX_MODE: c_uint = 2; +pub const STATX_NLINK: c_uint = 4; +pub const STATX_UID: c_uint = 8; +pub const STATX_GID: c_uint = 16; +pub const STATX_ATIME: c_uint = 32; +pub const STATX_MTIME: c_uint = 64; +pub const STATX_CTIME: c_uint = 128; +pub const STATX_INO: c_uint = 256; +pub const STATX_SIZE: c_uint = 512; +pub const STATX_BLOCKS: c_uint = 1024; +pub const STATX_BASIC_STATS: c_uint = 2047; +pub const STATX_ALL: c_uint = 4095; +pub const STATX_BTIME: c_uint = 2048; +pub const STATX_MNT_ID: c_uint = 4096; +pub const STATX_DIOALIGN: c_uint = 8192; +pub const STATX__RESERVED: c_uint = 2147483648; +pub const STATX_ATTR_COMPRESSED: c_uint = 4; +pub const STATX_ATTR_IMMUTABLE: c_uint = 16; +pub const STATX_ATTR_APPEND: c_uint = 32; +pub const STATX_ATTR_NODUMP: c_uint = 64; +pub const STATX_ATTR_ENCRYPTED: c_uint = 2048; +pub const STATX_ATTR_AUTOMOUNT: c_uint = 4096; +pub const STATX_ATTR_MOUNT_ROOT: c_uint = 8192; +pub const STATX_ATTR_VERITY: c_uint = 1048576; +pub const STATX_ATTR_DAX: c_uint = 2097152; + +// sys/ioctl.h +pub const TIOCM_LE: c_int = 1; +pub const TIOCM_DTR: c_int = 2; +pub const TIOCM_RTS: c_int = 4; +pub const TIOCM_ST: c_int = 8; +pub const TIOCM_SR: c_int = 16; +pub const TIOCM_CTS: c_int = 32; +pub const TIOCM_CAR: c_int = 64; +pub const TIOCM_CD: c_int = 64; +pub const TIOCM_RNG: c_int = 128; +pub const TIOCM_RI: c_int = 128; +pub const TIOCM_DSR: c_int = 256; +pub const TIOCPKT_DATA: c_int = 0; +pub const TIOCPKT_FLUSHREAD: c_int = 1; +pub const TIOCPKT_FLUSHWRITE: c_int = 2; +pub const TIOCPKT_STOP: c_int = 4; +pub const TIOCPKT_START: c_int = 8; +pub const TIOCPKT_NOSTOP: c_int = 16; +pub const TIOCPKT_DOSTOP: c_int = 32; +pub const TIOCPKT_IOCTL: c_int = 64; +pub const TTYDISC: c_int = 0; +pub const TABLDISC: c_int = 3; +pub const SLIPDISC: c_int = 4; +pub const TANDEM: crate::tcflag_t = 1; +pub const CBREAK: crate::tcflag_t = 2; +pub const LCASE: crate::tcflag_t = 4; +pub const CRMOD: crate::tcflag_t = 16; +pub const RAW: crate::tcflag_t = 32; +pub const ODDP: crate::tcflag_t = 64; +pub const EVENP: crate::tcflag_t = 128; +pub const ANYP: crate::tcflag_t = 192; +pub const NLDELAY: crate::tcflag_t = 768; +pub const NL2: crate::tcflag_t = 512; +pub const NL3: crate::tcflag_t = 768; +pub const TBDELAY: crate::tcflag_t = 3072; +pub const XTABS: crate::tcflag_t = 3072; +pub const CRDELAY: crate::tcflag_t = 12288; +pub const VTDELAY: crate::tcflag_t = 16384; +pub const BSDELAY: crate::tcflag_t = 32768; +pub const ALLDELAY: crate::tcflag_t = 65280; +pub const CRTBS: crate::tcflag_t = 65536; +pub const PRTERA: crate::tcflag_t = 131072; +pub const CRTERA: crate::tcflag_t = 262144; +pub const TILDE: crate::tcflag_t = 524288; +pub const LITOUT: crate::tcflag_t = 2097152; +pub const NOHANG: crate::tcflag_t = 16777216; +pub const L001000: crate::tcflag_t = 33554432; +pub const CRTKIL: crate::tcflag_t = 67108864; +pub const PASS8: crate::tcflag_t = 134217728; +pub const CTLECH: crate::tcflag_t = 268435456; +pub const DECCTQ: crate::tcflag_t = 1073741824; + +pub const FIONBIO: c_ulong = 0xa008007e; +pub const FIONREAD: c_ulong = 0x6008007f; +pub const TIOCSWINSZ: c_ulong = 0x90200767; +pub const TIOCGWINSZ: c_ulong = 0x50200768; +pub const TIOCEXCL: c_ulong = 0x70d; +pub const TIOCNXCL: c_ulong = 0x70e; +pub const TIOCSCTTY: c_ulong = 0x761; + +pub const FIOCLEX: c_ulong = 1; + +// fcntl.h +pub const O_EXEC: c_int = 4; +pub const O_NORW: c_int = 0; +pub const O_RDONLY: c_int = 1; +pub const O_WRONLY: c_int = 2; +pub const O_RDWR: c_int = 3; +pub const O_ACCMODE: c_int = 3; +pub const O_LARGEFILE: c_int = 0; +pub const O_CREAT: c_int = 16; +pub const O_EXCL: c_int = 32; +pub const O_NOLINK: c_int = 64; +pub const O_NOTRANS: c_int = 128; +pub const O_NOFOLLOW: c_int = 1048576; +pub const O_DIRECTORY: c_int = 2097152; +pub const O_APPEND: c_int = 256; +pub const O_ASYNC: c_int = 512; +pub const O_FSYNC: c_int = 1024; +pub const O_SYNC: c_int = 1024; +pub const O_NOATIME: c_int = 2048; +pub const O_SHLOCK: c_int = 131072; +pub const O_EXLOCK: c_int = 262144; +pub const O_DSYNC: c_int = 1024; +pub const O_RSYNC: c_int = 1024; +pub const O_NONBLOCK: c_int = 8; +pub const O_NDELAY: c_int = 8; +pub const O_HURD: c_int = 458751; +pub const O_TRUNC: c_int = 65536; +pub const O_CLOEXEC: c_int = 4194304; +pub const O_IGNORE_CTTY: c_int = 524288; +pub const O_TMPFILE: c_int = 8388608; +pub const O_NOCTTY: c_int = 0; +pub const FREAD: c_int = 1; +pub const FWRITE: c_int = 2; +pub const FASYNC: c_int = 512; +pub const FCREAT: c_int = 16; +pub const FEXCL: c_int = 32; +pub const FTRUNC: c_int = 65536; +pub const FNOCTTY: c_int = 0; +pub const FFSYNC: c_int = 1024; +pub const FSYNC: c_int = 1024; +pub const FAPPEND: c_int = 256; +pub const FNONBLOCK: c_int = 8; +pub const FNDELAY: c_int = 8; +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_GETLK64: c_int = 10; +pub const F_SETLK64: c_int = 11; +pub const F_SETLKW64: c_int = 12; +pub const F_DUPFD_CLOEXEC: c_int = 1030; +pub const FD_CLOEXEC: c_int = 1; +pub const F_RDLCK: c_int = 1; +pub const F_WRLCK: c_int = 2; +pub const F_UNLCK: c_int = 3; +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; +pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 256; +pub const AT_REMOVEDIR: c_int = 512; +pub const AT_SYMLINK_FOLLOW: c_int = 1024; +pub const AT_NO_AUTOMOUNT: c_int = 2048; +pub const AT_EMPTY_PATH: c_int = 4096; +pub const AT_STATX_SYNC_TYPE: c_int = 24576; +pub const AT_STATX_SYNC_AS_STAT: c_int = 0; +pub const AT_STATX_FORCE_SYNC: c_int = 8192; +pub const AT_STATX_DONT_SYNC: c_int = 16384; +pub const AT_RECURSIVE: c_int = 32768; +pub const AT_EACCESS: c_int = 512; + +// sys/uio.h +pub const RWF_HIPRI: c_int = 1; +pub const RWF_DSYNC: c_int = 2; +pub const RWF_SYNC: c_int = 4; +pub const RWF_NOWAIT: c_int = 8; +pub const RWF_APPEND: c_int = 16; + +// errno.h +pub const EPERM: c_int = 1073741825; +pub const ENOENT: c_int = 1073741826; +pub const ESRCH: c_int = 1073741827; +pub const EINTR: c_int = 1073741828; +pub const EIO: c_int = 1073741829; +pub const ENXIO: c_int = 1073741830; +pub const E2BIG: c_int = 1073741831; +pub const ENOEXEC: c_int = 1073741832; +pub const EBADF: c_int = 1073741833; +pub const ECHILD: c_int = 1073741834; +pub const EDEADLK: c_int = 1073741835; +pub const ENOMEM: c_int = 1073741836; +pub const EACCES: c_int = 1073741837; +pub const EFAULT: c_int = 1073741838; +pub const ENOTBLK: c_int = 1073741839; +pub const EBUSY: c_int = 1073741840; +pub const EEXIST: c_int = 1073741841; +pub const EXDEV: c_int = 1073741842; +pub const ENODEV: c_int = 1073741843; +pub const ENOTDIR: c_int = 1073741844; +pub const EISDIR: c_int = 1073741845; +pub const EINVAL: c_int = 1073741846; +pub const EMFILE: c_int = 1073741848; +pub const ENFILE: c_int = 1073741847; +pub const ENOTTY: c_int = 1073741849; +pub const ETXTBSY: c_int = 1073741850; +pub const EFBIG: c_int = 1073741851; +pub const ENOSPC: c_int = 1073741852; +pub const ESPIPE: c_int = 1073741853; +pub const EROFS: c_int = 1073741854; +pub const EMLINK: c_int = 1073741855; +pub const EPIPE: c_int = 1073741856; +pub const EDOM: c_int = 1073741857; +pub const ERANGE: c_int = 1073741858; +pub const EAGAIN: c_int = 1073741859; +pub const EWOULDBLOCK: c_int = 1073741859; +pub const EINPROGRESS: c_int = 1073741860; +pub const EALREADY: c_int = 1073741861; +pub const ENOTSOCK: c_int = 1073741862; +pub const EMSGSIZE: c_int = 1073741864; +pub const EPROTOTYPE: c_int = 1073741865; +pub const ENOPROTOOPT: c_int = 1073741866; +pub const EPROTONOSUPPORT: c_int = 1073741867; +pub const ESOCKTNOSUPPORT: c_int = 1073741868; +pub const EOPNOTSUPP: c_int = 1073741869; +pub const EPFNOSUPPORT: c_int = 1073741870; +pub const EAFNOSUPPORT: c_int = 1073741871; +pub const EADDRINUSE: c_int = 1073741872; +pub const EADDRNOTAVAIL: c_int = 1073741873; +pub const ENETDOWN: c_int = 1073741874; +pub const ENETUNREACH: c_int = 1073741875; +pub const ENETRESET: c_int = 1073741876; +pub const ECONNABORTED: c_int = 1073741877; +pub const ECONNRESET: c_int = 1073741878; +pub const ENOBUFS: c_int = 1073741879; +pub const EISCONN: c_int = 1073741880; +pub const ENOTCONN: c_int = 1073741881; +pub const EDESTADDRREQ: c_int = 1073741863; +pub const ESHUTDOWN: c_int = 1073741882; +pub const ETOOMANYREFS: c_int = 1073741883; +pub const ETIMEDOUT: c_int = 1073741884; +pub const ECONNREFUSED: c_int = 1073741885; +pub const ELOOP: c_int = 1073741886; +pub const ENAMETOOLONG: c_int = 1073741887; +pub const EHOSTDOWN: c_int = 1073741888; +pub const EHOSTUNREACH: c_int = 1073741889; +pub const ENOTEMPTY: c_int = 1073741890; +pub const EPROCLIM: c_int = 1073741891; +pub const EUSERS: c_int = 1073741892; +pub const EDQUOT: c_int = 1073741893; +pub const ESTALE: c_int = 1073741894; +pub const EREMOTE: c_int = 1073741895; +pub const EBADRPC: c_int = 1073741896; +pub const ERPCMISMATCH: c_int = 1073741897; +pub const EPROGUNAVAIL: c_int = 1073741898; +pub const EPROGMISMATCH: c_int = 1073741899; +pub const EPROCUNAVAIL: c_int = 1073741900; +pub const ENOLCK: c_int = 1073741901; +pub const EFTYPE: c_int = 1073741903; +pub const EAUTH: c_int = 1073741904; +pub const ENEEDAUTH: c_int = 1073741905; +pub const ENOSYS: c_int = 1073741902; +pub const ELIBEXEC: c_int = 1073741907; +pub const ENOTSUP: c_int = 1073741942; +pub const EILSEQ: c_int = 1073741930; +pub const EBACKGROUND: c_int = 1073741924; +pub const EDIED: c_int = 1073741925; +pub const EGREGIOUS: c_int = 1073741927; +pub const EIEIO: c_int = 1073741928; +pub const EGRATUITOUS: c_int = 1073741929; +pub const EBADMSG: c_int = 1073741931; +pub const EIDRM: c_int = 1073741932; +pub const EMULTIHOP: c_int = 1073741933; +pub const ENODATA: c_int = 1073741934; +pub const ENOLINK: c_int = 1073741935; +pub const ENOMSG: c_int = 1073741936; +pub const ENOSR: c_int = 1073741937; +pub const ENOSTR: c_int = 1073741938; +pub const EOVERFLOW: c_int = 1073741939; +pub const EPROTO: c_int = 1073741940; +pub const ETIME: c_int = 1073741941; +pub const ECANCELED: c_int = 1073741943; +pub const EOWNERDEAD: c_int = 1073741944; +pub const ENOTRECOVERABLE: c_int = 1073741945; +pub const EMACH_SEND_IN_PROGRESS: c_int = 268435457; +pub const EMACH_SEND_INVALID_DATA: c_int = 268435458; +pub const EMACH_SEND_INVALID_DEST: c_int = 268435459; +pub const EMACH_SEND_TIMED_OUT: c_int = 268435460; +pub const EMACH_SEND_WILL_NOTIFY: c_int = 268435461; +pub const EMACH_SEND_NOTIFY_IN_PROGRESS: c_int = 268435462; +pub const EMACH_SEND_INTERRUPTED: c_int = 268435463; +pub const EMACH_SEND_MSG_TOO_SMALL: c_int = 268435464; +pub const EMACH_SEND_INVALID_REPLY: c_int = 268435465; +pub const EMACH_SEND_INVALID_RIGHT: c_int = 268435466; +pub const EMACH_SEND_INVALID_NOTIFY: c_int = 268435467; +pub const EMACH_SEND_INVALID_MEMORY: c_int = 268435468; +pub const EMACH_SEND_NO_BUFFER: c_int = 268435469; +pub const EMACH_SEND_NO_NOTIFY: c_int = 268435470; +pub const EMACH_SEND_INVALID_TYPE: c_int = 268435471; +pub const EMACH_SEND_INVALID_HEADER: c_int = 268435472; +pub const EMACH_RCV_IN_PROGRESS: c_int = 268451841; +pub const EMACH_RCV_INVALID_NAME: c_int = 268451842; +pub const EMACH_RCV_TIMED_OUT: c_int = 268451843; +pub const EMACH_RCV_TOO_LARGE: c_int = 268451844; +pub const EMACH_RCV_INTERRUPTED: c_int = 268451845; +pub const EMACH_RCV_PORT_CHANGED: c_int = 268451846; +pub const EMACH_RCV_INVALID_NOTIFY: c_int = 268451847; +pub const EMACH_RCV_INVALID_DATA: c_int = 268451848; +pub const EMACH_RCV_PORT_DIED: c_int = 268451849; +pub const EMACH_RCV_IN_SET: c_int = 268451850; +pub const EMACH_RCV_HEADER_ERROR: c_int = 268451851; +pub const EMACH_RCV_BODY_ERROR: c_int = 268451852; +pub const EKERN_INVALID_ADDRESS: c_int = 1; +pub const EKERN_PROTECTION_FAILURE: c_int = 2; +pub const EKERN_NO_SPACE: c_int = 3; +pub const EKERN_INVALID_ARGUMENT: c_int = 4; +pub const EKERN_FAILURE: c_int = 5; +pub const EKERN_RESOURCE_SHORTAGE: c_int = 6; +pub const EKERN_NOT_RECEIVER: c_int = 7; +pub const EKERN_NO_ACCESS: c_int = 8; +pub const EKERN_MEMORY_FAILURE: c_int = 9; +pub const EKERN_MEMORY_ERROR: c_int = 10; +pub const EKERN_NOT_IN_SET: c_int = 12; +pub const EKERN_NAME_EXISTS: c_int = 13; +pub const EKERN_ABORTED: c_int = 14; +pub const EKERN_INVALID_NAME: c_int = 15; +pub const EKERN_INVALID_TASK: c_int = 16; +pub const EKERN_INVALID_RIGHT: c_int = 17; +pub const EKERN_INVALID_VALUE: c_int = 18; +pub const EKERN_UREFS_OVERFLOW: c_int = 19; +pub const EKERN_INVALID_CAPABILITY: c_int = 20; +pub const EKERN_RIGHT_EXISTS: c_int = 21; +pub const EKERN_INVALID_HOST: c_int = 22; +pub const EKERN_MEMORY_PRESENT: c_int = 23; +pub const EKERN_WRITE_PROTECTION_FAILURE: c_int = 24; +pub const EKERN_TERMINATED: c_int = 26; +pub const EKERN_TIMEDOUT: c_int = 27; +pub const EKERN_INTERRUPTED: c_int = 28; +pub const EMIG_TYPE_ERROR: c_int = -300; +pub const EMIG_REPLY_MISMATCH: c_int = -301; +pub const EMIG_REMOTE_ERROR: c_int = -302; +pub const EMIG_BAD_ID: c_int = -303; +pub const EMIG_BAD_ARGUMENTS: c_int = -304; +pub const EMIG_NO_REPLY: c_int = -305; +pub const EMIG_EXCEPTION: c_int = -306; +pub const EMIG_ARRAY_TOO_LARGE: c_int = -307; +pub const EMIG_SERVER_DIED: c_int = -308; +pub const EMIG_DESTROY_REQUEST: c_int = -309; +pub const ED_IO_ERROR: c_int = 2500; +pub const ED_WOULD_BLOCK: c_int = 2501; +pub const ED_NO_SUCH_DEVICE: c_int = 2502; +pub const ED_ALREADY_OPEN: c_int = 2503; +pub const ED_DEVICE_DOWN: c_int = 2504; +pub const ED_INVALID_OPERATION: c_int = 2505; +pub const ED_INVALID_RECNUM: c_int = 2506; +pub const ED_INVALID_SIZE: c_int = 2507; +pub const ED_NO_MEMORY: c_int = 2508; +pub const ED_READ_ONLY: c_int = 2509; +pub const _HURD_ERRNOS: usize = 122; + +// sched.h +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const _BITS_TYPES_STRUCT_SCHED_PARAM: usize = 1; +pub const __CPU_SETSIZE: usize = 1024; +pub const CPU_SETSIZE: usize = 1024; + +// pthread.h +pub const PTHREAD_SPINLOCK_INITIALIZER: c_int = 0; +pub const PTHREAD_CANCEL_DISABLE: c_int = 0; +pub const PTHREAD_CANCEL_ENABLE: c_int = 1; +pub const PTHREAD_CANCEL_DEFERRED: c_int = 0; +pub const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 1; +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1; + +// netinet/tcp.h +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; +pub const TCP_CORK: c_int = 3; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; +pub const TCP_SYNCNT: c_int = 7; +pub const TCP_LINGER2: c_int = 8; +pub const TCP_DEFER_ACCEPT: c_int = 9; +pub const TCP_WINDOW_CLAMP: c_int = 10; +pub const TCP_INFO: c_int = 11; +pub const TCP_QUICKACK: c_int = 12; +pub const TCP_CONGESTION: c_int = 13; +pub const TCP_MD5SIG: c_int = 14; +pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16; +pub const TCP_THIN_DUPACK: c_int = 17; +pub const TCP_USER_TIMEOUT: c_int = 18; +pub const TCP_REPAIR: c_int = 19; +pub const TCP_REPAIR_QUEUE: c_int = 20; +pub const TCP_QUEUE_SEQ: c_int = 21; +pub const TCP_REPAIR_OPTIONS: c_int = 22; +pub const TCP_FASTOPEN: c_int = 23; +pub const TCP_TIMESTAMP: c_int = 24; +pub const TCP_NOTSENT_LOWAT: c_int = 25; +pub const TCP_CC_INFO: c_int = 26; +pub const TCP_SAVE_SYN: c_int = 27; +pub const TCP_SAVED_SYN: c_int = 28; +pub const TCP_REPAIR_WINDOW: c_int = 29; +pub const TCP_FASTOPEN_CONNECT: c_int = 30; +pub const TCP_ULP: c_int = 31; +pub const TCP_MD5SIG_EXT: c_int = 32; +pub const TCP_FASTOPEN_KEY: c_int = 33; +pub const TCP_FASTOPEN_NO_COOKIE: c_int = 34; +pub const TCP_ZEROCOPY_RECEIVE: c_int = 35; +pub const TCP_INQ: c_int = 36; +pub const TCP_CM_INQ: c_int = 36; +pub const TCP_TX_DELAY: c_int = 37; +pub const TCP_REPAIR_ON: c_int = 1; +pub const TCP_REPAIR_OFF: c_int = 0; +pub const TCP_REPAIR_OFF_NO_WP: c_int = -1; + +// stdint.h +pub const INT8_MIN: i8 = -128; +pub const INT16_MIN: i16 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: i8 = 127; +pub const INT16_MAX: i16 = 32767; +pub const INT32_MAX: i32 = 2147483647; +pub const UINT8_MAX: u8 = 255; +pub const UINT16_MAX: u16 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: int_least8_t = -128; +pub const INT_LEAST16_MIN: int_least16_t = -32768; +pub const INT_LEAST32_MIN: int_least32_t = -2147483648; +pub const INT_LEAST8_MAX: int_least8_t = 127; +pub const INT_LEAST16_MAX: int_least16_t = 32767; +pub const INT_LEAST32_MAX: int_least32_t = 2147483647; +pub const UINT_LEAST8_MAX: uint_least8_t = 255; +pub const UINT_LEAST16_MAX: uint_least16_t = 65535; +pub const UINT_LEAST32_MAX: uint_least32_t = 4294967295; +pub const INT_FAST8_MIN: int_fast8_t = -128; +pub const INT_FAST16_MIN: int_fast16_t = -2147483648; +pub const INT_FAST32_MIN: int_fast32_t = -2147483648; +pub const INT_FAST8_MAX: int_fast8_t = 127; +pub const INT_FAST16_MAX: int_fast16_t = 2147483647; +pub const INT_FAST32_MAX: int_fast32_t = 2147483647; +pub const UINT_FAST8_MAX: uint_fast8_t = 255; +pub const UINT_FAST16_MAX: uint_fast16_t = 4294967295; +pub const UINT_FAST32_MAX: uint_fast32_t = 4294967295; +pub const INTPTR_MIN: __intptr_t = -2147483648; +pub const INTPTR_MAX: __intptr_t = 2147483647; +pub const UINTPTR_MAX: usize = 4294967295; +pub const PTRDIFF_MIN: __ptrdiff_t = -2147483648; +pub const PTRDIFF_MAX: __ptrdiff_t = 2147483647; +pub const SIG_ATOMIC_MIN: __sig_atomic_t = -2147483648; +pub const SIG_ATOMIC_MAX: __sig_atomic_t = 2147483647; +pub const SIZE_MAX: usize = 4294967295; +pub const WINT_MIN: wint_t = 0; +pub const WINT_MAX: wint_t = 4294967295; +pub const INT8_WIDTH: usize = 8; +pub const UINT8_WIDTH: usize = 8; +pub const INT16_WIDTH: usize = 16; +pub const UINT16_WIDTH: usize = 16; +pub const INT32_WIDTH: usize = 32; +pub const UINT32_WIDTH: usize = 32; +pub const INT64_WIDTH: usize = 64; +pub const UINT64_WIDTH: usize = 64; +pub const INT_LEAST8_WIDTH: usize = 8; +pub const UINT_LEAST8_WIDTH: usize = 8; +pub const INT_LEAST16_WIDTH: usize = 16; +pub const UINT_LEAST16_WIDTH: usize = 16; +pub const INT_LEAST32_WIDTH: usize = 32; +pub const UINT_LEAST32_WIDTH: usize = 32; +pub const INT_LEAST64_WIDTH: usize = 64; +pub const UINT_LEAST64_WIDTH: usize = 64; +pub const INT_FAST8_WIDTH: usize = 8; +pub const UINT_FAST8_WIDTH: usize = 8; +pub const INT_FAST16_WIDTH: usize = 32; +pub const UINT_FAST16_WIDTH: usize = 32; +pub const INT_FAST32_WIDTH: usize = 32; +pub const UINT_FAST32_WIDTH: usize = 32; +pub const INT_FAST64_WIDTH: usize = 64; +pub const UINT_FAST64_WIDTH: usize = 64; +pub const INTPTR_WIDTH: usize = 32; +pub const UINTPTR_WIDTH: usize = 32; +pub const INTMAX_WIDTH: usize = 64; +pub const UINTMAX_WIDTH: usize = 64; +pub const PTRDIFF_WIDTH: usize = 32; +pub const SIG_ATOMIC_WIDTH: usize = 32; +pub const SIZE_WIDTH: usize = 32; +pub const WCHAR_WIDTH: usize = 32; +pub const WINT_WIDTH: usize = 32; + +pub const TH_FIN: u8 = 1; +pub const TH_SYN: u8 = 2; +pub const TH_RST: u8 = 4; +pub const TH_PUSH: u8 = 8; +pub const TH_ACK: u8 = 16; +pub const TH_URG: u8 = 32; +pub const TCPOPT_EOL: u8 = 0; +pub const TCPOPT_NOP: u8 = 1; +pub const TCPOPT_MAXSEG: u8 = 2; +pub const TCPOLEN_MAXSEG: u8 = 4; +pub const TCPOPT_WINDOW: u8 = 3; +pub const TCPOLEN_WINDOW: u8 = 3; +pub const TCPOPT_SACK_PERMITTED: u8 = 4; +pub const TCPOLEN_SACK_PERMITTED: u8 = 2; +pub const TCPOPT_SACK: u8 = 5; +pub const TCPOPT_TIMESTAMP: u8 = 8; +pub const TCPOLEN_TIMESTAMP: u8 = 10; +pub const TCPOLEN_TSTAMP_APPA: u8 = 12; +pub const TCPOPT_TSTAMP_HDR: u32 = 16844810; +pub const TCP_MSS: usize = 512; +pub const TCP_MAXWIN: usize = 65535; +pub const TCP_MAX_WINSHIFT: usize = 14; +pub const TCPI_OPT_TIMESTAMPS: u8 = 1; +pub const TCPI_OPT_SACK: u8 = 2; +pub const TCPI_OPT_WSCALE: u8 = 4; +pub const TCPI_OPT_ECN: u8 = 8; +pub const TCPI_OPT_ECN_SEEN: u8 = 16; +pub const TCPI_OPT_SYN_DATA: u8 = 32; +pub const TCP_MD5SIG_MAXKEYLEN: usize = 80; +pub const TCP_MD5SIG_FLAG_PREFIX: usize = 1; +pub const TCP_COOKIE_MIN: usize = 8; +pub const TCP_COOKIE_MAX: usize = 16; +pub const TCP_COOKIE_PAIR_SIZE: usize = 32; +pub const TCP_COOKIE_IN_ALWAYS: c_int = 1; +pub const TCP_COOKIE_OUT_NEVER: c_int = 2; +pub const TCP_S_DATA_IN: c_int = 4; +pub const TCP_S_DATA_OUT: c_int = 8; +pub const TCP_MSS_DEFAULT: usize = 536; +pub const TCP_MSS_DESIRED: usize = 1220; + +// sys/wait.h +pub const WCOREFLAG: c_int = 128; +pub const WAIT_ANY: pid_t = -1; +pub const WAIT_MYPGRP: pid_t = 0; + +// sys/file.h +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_UN: c_int = 8; +pub const LOCK_NB: c_int = 4; + +// sys/mman.h +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 4; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 1; +pub const MAP_FILE: c_int = 1; +pub const MAP_ANON: c_int = 2; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; +pub const MAP_TYPE: c_int = 15; +pub const MAP_COPY: c_int = 32; +pub const MAP_SHARED: c_int = 16; +pub const MAP_PRIVATE: c_int = 0; +pub const MAP_FIXED: c_int = 256; +pub const MAP_NOEXTEND: c_int = 512; +pub const MAP_HASSEMAPHORE: c_int = 1024; +pub const MAP_INHERIT: c_int = 2048; +pub const MAP_32BIT: c_int = 4096; +pub const MAP_EXCL: c_int = 16384; +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_WONTNEED: c_int = 4; + +pub const MS_ASYNC: c_int = 1; +pub const MS_SYNC: c_int = 0; +pub const MS_INVALIDATE: c_int = 2; +pub const MREMAP_MAYMOVE: c_int = 1; +pub const MREMAP_FIXED: c_int = 2; +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +// sys/xattr.h +pub const XATTR_CREATE: c_int = 0x1; +pub const XATTR_REPLACE: c_int = 0x2; + +// spawn.h +pub const POSIX_SPAWN_USEVFORK: c_int = 64; +pub const POSIX_SPAWN_SETSID: c_int = 128; + +// sys/syslog.h +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_FTP: c_int = 11 << 3; +pub const LOG_PERROR: c_int = 0x20; + +// net/if.h +pub const IFF_UP: c_int = 0x1; +pub const IFF_BROADCAST: c_int = 0x2; +pub const IFF_DEBUG: c_int = 0x4; +pub const IFF_LOOPBACK: c_int = 0x8; +pub const IFF_POINTOPOINT: c_int = 0x10; +pub const IFF_NOTRAILERS: c_int = 0x20; +pub const IFF_RUNNING: c_int = 0x40; +pub const IFF_NOARP: c_int = 0x80; +pub const IFF_PROMISC: c_int = 0x100; +pub const IFF_ALLMULTI: c_int = 0x200; +pub const IFF_MASTER: c_int = 0x400; +pub const IFF_SLAVE: c_int = 0x800; +pub const IFF_MULTICAST: c_int = 0x1000; +pub const IFF_PORTSEL: c_int = 0x2000; +pub const IFF_AUTOMEDIA: c_int = 0x4000; +pub const IFF_DYNAMIC: c_int = 0x8000; + +// random.h +pub const GRND_NONBLOCK: c_uint = 1; +pub const GRND_RANDOM: c_uint = 2; +pub const GRND_INSECURE: c_uint = 4; + +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = 30; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EQUIV_CLASS_MAX: c_int = 41; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_CHARCLASS_NAME_MAX: c_int = 45; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_PII: c_int = 53; +pub const _SC_PII_XTI: c_int = 54; +pub const _SC_PII_SOCKET: c_int = 55; +pub const _SC_PII_INTERNET: c_int = 56; +pub const _SC_PII_OSI: c_int = 57; +pub const _SC_POLL: c_int = 58; +pub const _SC_SELECT: c_int = 59; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = 60; +pub const _SC_PII_INTERNET_STREAM: c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: c_int = 62; +pub const _SC_PII_OSI_COTS: c_int = 63; +pub const _SC_PII_OSI_CLTS: c_int = 64; +pub const _SC_PII_OSI_M: c_int = 65; +pub const _SC_T_IOV_MAX: c_int = 66; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_C_VERSION: c_int = 96; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_CHAR_BIT: c_int = 101; +pub const _SC_CHAR_MAX: c_int = 102; +pub const _SC_CHAR_MIN: c_int = 103; +pub const _SC_INT_MAX: c_int = 104; +pub const _SC_INT_MIN: c_int = 105; +pub const _SC_LONG_BIT: c_int = 106; +pub const _SC_WORD_BIT: c_int = 107; +pub const _SC_MB_LEN_MAX: c_int = 108; +pub const _SC_NZERO: c_int = 109; +pub const _SC_SSIZE_MAX: c_int = 110; +pub const _SC_SCHAR_MAX: c_int = 111; +pub const _SC_SCHAR_MIN: c_int = 112; +pub const _SC_SHRT_MAX: c_int = 113; +pub const _SC_SHRT_MIN: c_int = 114; +pub const _SC_UCHAR_MAX: c_int = 115; +pub const _SC_UINT_MAX: c_int = 116; +pub const _SC_ULONG_MAX: c_int = 117; +pub const _SC_USHRT_MAX: c_int = 118; +pub const _SC_NL_ARGMAX: c_int = 119; +pub const _SC_NL_LANGMAX: c_int = 120; +pub const _SC_NL_MSGMAX: c_int = 121; +pub const _SC_NL_NMAX: c_int = 122; +pub const _SC_NL_SETMAX: c_int = 123; +pub const _SC_NL_TEXTMAX: c_int = 124; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_BASE: c_int = 134; +pub const _SC_C_LANG_SUPPORT: c_int = 135; +pub const _SC_C_LANG_SUPPORT_R: c_int = 136; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_DEVICE_IO: c_int = 140; +pub const _SC_DEVICE_SPECIFIC: c_int = 141; +pub const _SC_DEVICE_SPECIFIC_R: c_int = 142; +pub const _SC_FD_MGMT: c_int = 143; +pub const _SC_FIFO: c_int = 144; +pub const _SC_PIPE: c_int = 145; +pub const _SC_FILE_ATTRIBUTES: c_int = 146; +pub const _SC_FILE_LOCKING: c_int = 147; +pub const _SC_FILE_SYSTEM: c_int = 148; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_MULTI_PROCESS: c_int = 150; +pub const _SC_SINGLE_PROCESS: c_int = 151; +pub const _SC_NETWORKING: c_int = 152; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_REGEX_VERSION: c_int = 156; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SIGNALS: c_int = 158; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_SYSTEM_DATABASE: c_int = 162; +pub const _SC_SYSTEM_DATABASE_R: c_int = 163; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_USER_GROUPS: c_int = 166; +pub const _SC_USER_GROUPS_R: c_int = 167; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_STREAMS: c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_LEVEL1_ICACHE_SIZE: c_int = 185; +pub const _SC_LEVEL1_ICACHE_ASSOC: c_int = 186; +pub const _SC_LEVEL1_ICACHE_LINESIZE: c_int = 187; +pub const _SC_LEVEL1_DCACHE_SIZE: c_int = 188; +pub const _SC_LEVEL1_DCACHE_ASSOC: c_int = 189; +pub const _SC_LEVEL1_DCACHE_LINESIZE: c_int = 190; +pub const _SC_LEVEL2_CACHE_SIZE: c_int = 191; +pub const _SC_LEVEL2_CACHE_ASSOC: c_int = 192; +pub const _SC_LEVEL2_CACHE_LINESIZE: c_int = 193; +pub const _SC_LEVEL3_CACHE_SIZE: c_int = 194; +pub const _SC_LEVEL3_CACHE_ASSOC: c_int = 195; +pub const _SC_LEVEL3_CACHE_LINESIZE: c_int = 196; +pub const _SC_LEVEL4_CACHE_SIZE: c_int = 197; +pub const _SC_LEVEL4_CACHE_ASSOC: c_int = 198; +pub const _SC_LEVEL4_CACHE_LINESIZE: c_int = 199; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; +pub const _SC_MINSIGSTKSZ: c_int = 249; +pub const _SC_SIGSTKSZ: c_int = 250; + +pub const _CS_PATH: c_int = 0; +pub const _CS_V6_WIDTH_RESTRICTED_ENVS: c_int = 1; +pub const _CS_GNU_LIBC_VERSION: c_int = 2; +pub const _CS_GNU_LIBPTHREAD_VERSION: c_int = 3; +pub const _CS_V5_WIDTH_RESTRICTED_ENVS: c_int = 4; +pub const _CS_V7_WIDTH_RESTRICTED_ENVS: c_int = 5; +pub const _CS_LFS_CFLAGS: c_int = 1000; +pub const _CS_LFS_LDFLAGS: c_int = 1001; +pub const _CS_LFS_LIBS: c_int = 1002; +pub const _CS_LFS_LINTFLAGS: c_int = 1003; +pub const _CS_LFS64_CFLAGS: c_int = 1004; +pub const _CS_LFS64_LDFLAGS: c_int = 1005; +pub const _CS_LFS64_LIBS: c_int = 1006; +pub const _CS_LFS64_LINTFLAGS: c_int = 1007; +pub const _CS_XBS5_ILP32_OFF32_CFLAGS: c_int = 1100; +pub const _CS_XBS5_ILP32_OFF32_LDFLAGS: c_int = 1101; +pub const _CS_XBS5_ILP32_OFF32_LIBS: c_int = 1102; +pub const _CS_XBS5_ILP32_OFF32_LINTFLAGS: c_int = 1103; +pub const _CS_XBS5_ILP32_OFFBIG_CFLAGS: c_int = 1104; +pub const _CS_XBS5_ILP32_OFFBIG_LDFLAGS: c_int = 1105; +pub const _CS_XBS5_ILP32_OFFBIG_LIBS: c_int = 1106; +pub const _CS_XBS5_ILP32_OFFBIG_LINTFLAGS: c_int = 1107; +pub const _CS_XBS5_LP64_OFF64_CFLAGS: c_int = 1108; +pub const _CS_XBS5_LP64_OFF64_LDFLAGS: c_int = 1109; +pub const _CS_XBS5_LP64_OFF64_LIBS: c_int = 1110; +pub const _CS_XBS5_LP64_OFF64_LINTFLAGS: c_int = 1111; +pub const _CS_XBS5_LPBIG_OFFBIG_CFLAGS: c_int = 1112; +pub const _CS_XBS5_LPBIG_OFFBIG_LDFLAGS: c_int = 1113; +pub const _CS_XBS5_LPBIG_OFFBIG_LIBS: c_int = 1114; +pub const _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS: c_int = 1115; +pub const _CS_POSIX_V6_ILP32_OFF32_CFLAGS: c_int = 1116; +pub const _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: c_int = 1117; +pub const _CS_POSIX_V6_ILP32_OFF32_LIBS: c_int = 1118; +pub const _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS: c_int = 1119; +pub const _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: c_int = 1120; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: c_int = 1121; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LIBS: c_int = 1122; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS: c_int = 1123; +pub const _CS_POSIX_V6_LP64_OFF64_CFLAGS: c_int = 1124; +pub const _CS_POSIX_V6_LP64_OFF64_LDFLAGS: c_int = 1125; +pub const _CS_POSIX_V6_LP64_OFF64_LIBS: c_int = 1126; +pub const _CS_POSIX_V6_LP64_OFF64_LINTFLAGS: c_int = 1127; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: c_int = 1128; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: c_int = 1129; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: c_int = 1130; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS: c_int = 1131; +pub const _CS_POSIX_V7_ILP32_OFF32_CFLAGS: c_int = 1132; +pub const _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: c_int = 1133; +pub const _CS_POSIX_V7_ILP32_OFF32_LIBS: c_int = 1134; +pub const _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: c_int = 1135; +pub const _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: c_int = 1136; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: c_int = 1137; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LIBS: c_int = 1138; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: c_int = 1139; +pub const _CS_POSIX_V7_LP64_OFF64_CFLAGS: c_int = 1140; +pub const _CS_POSIX_V7_LP64_OFF64_LDFLAGS: c_int = 1141; +pub const _CS_POSIX_V7_LP64_OFF64_LIBS: c_int = 1142; +pub const _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: c_int = 1143; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: c_int = 1144; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: c_int = 1145; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: c_int = 1146; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS: c_int = 1147; +pub const _CS_V6_ENV: c_int = 1148; +pub const _CS_V7_ENV: c_int = 1149; + +pub const PTHREAD_PROCESS_PRIVATE: __pthread_process_shared = 0; +pub const PTHREAD_PROCESS_SHARED: __pthread_process_shared = 1; + +pub const PTHREAD_EXPLICIT_SCHED: __pthread_inheritsched = 0; +pub const PTHREAD_INHERIT_SCHED: __pthread_inheritsched = 1; + +pub const PTHREAD_SCOPE_SYSTEM: __pthread_contentionscope = 0; +pub const PTHREAD_SCOPE_PROCESS: __pthread_contentionscope = 1; + +pub const PTHREAD_CREATE_JOINABLE: __pthread_detachstate = 0; +pub const PTHREAD_CREATE_DETACHED: __pthread_detachstate = 1; + +pub const PTHREAD_PRIO_NONE: __pthread_mutex_protocol = 0; +pub const PTHREAD_PRIO_INHERIT: __pthread_mutex_protocol = 1; +pub const PTHREAD_PRIO_PROTECT: __pthread_mutex_protocol = 2; + +pub const PTHREAD_MUTEX_TIMED: __pthread_mutex_type = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: __pthread_mutex_type = 1; +pub const PTHREAD_MUTEX_RECURSIVE: __pthread_mutex_type = 2; + +pub const PTHREAD_MUTEX_STALLED: __pthread_mutex_robustness = 0; +pub const PTHREAD_MUTEX_ROBUST: __pthread_mutex_robustness = 256; + +pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; +pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; +pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; +pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; +pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; +pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; +pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 6; +pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 7; +pub const RLIMIT_OFILE: crate::__rlimit_resource_t = 8; +pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 8; +pub const RLIMIT_SBSIZE: crate::__rlimit_resource_t = 9; +pub const RLIMIT_AS: crate::__rlimit_resource_t = 10; +pub const RLIMIT_VMEM: crate::__rlimit_resource_t = 10; +pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = 11; +pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 11; + +pub const RUSAGE_SELF: __rusage_who = 0; +pub const RUSAGE_CHILDREN: __rusage_who = -1; + +pub const PRIO_PROCESS: __priority_which = 0; +pub const PRIO_PGRP: __priority_which = 1; +pub const PRIO_USER: __priority_which = 2; + +pub const __UT_LINESIZE: usize = 32; +pub const __UT_NAMESIZE: usize = 32; +pub const __UT_HOSTSIZE: usize = 256; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_CLOEXEC: c_int = 4194304; +pub const SOCK_NONBLOCK: c_int = 2048; + +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTROUTE: c_int = 4; +pub const MSG_EOR: c_int = 8; +pub const MSG_TRUNC: c_int = 16; +pub const MSG_CTRUNC: c_int = 32; +pub const MSG_WAITALL: c_int = 64; +pub const MSG_DONTWAIT: c_int = 128; +pub const MSG_NOSIGNAL: c_int = 1024; +pub const MSG_CMSG_CLOEXEC: c_int = 0x40000000; + +pub const SCM_RIGHTS: c_int = 1; +pub const SCM_TIMESTAMP: c_int = 2; +pub const SCM_CREDS: c_int = 3; + +pub const SO_DEBUG: c_int = 1; +pub const SO_ACCEPTCONN: c_int = 2; +pub const SO_REUSEADDR: c_int = 4; +pub const SO_KEEPALIVE: c_int = 8; +pub const SO_DONTROUTE: c_int = 16; +pub const SO_BROADCAST: c_int = 32; +pub const SO_USELOOPBACK: c_int = 64; +pub const SO_LINGER: c_int = 128; +pub const SO_OOBINLINE: c_int = 256; +pub const SO_REUSEPORT: c_int = 512; +pub const SO_SNDBUF: c_int = 4097; +pub const SO_RCVBUF: c_int = 4098; +pub const SO_SNDLOWAT: c_int = 4099; +pub const SO_RCVLOWAT: c_int = 4100; +pub const SO_SNDTIMEO: c_int = 4101; +pub const SO_RCVTIMEO: c_int = 4102; +pub const SO_ERROR: c_int = 4103; +pub const SO_STYLE: c_int = 4104; +pub const SO_TYPE: c_int = 4104; + +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_ICMP: c_int = 1; +pub const IPPROTO_IGMP: c_int = 2; +pub const IPPROTO_IPIP: c_int = 4; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_EGP: c_int = 8; +pub const IPPROTO_PUP: c_int = 12; +pub const IPPROTO_UDP: c_int = 17; +pub const IPPROTO_IDP: c_int = 22; +pub const IPPROTO_TP: c_int = 29; +pub const IPPROTO_DCCP: c_int = 33; +pub const IPPROTO_IPV6: c_int = 41; +pub const IPPROTO_RSVP: c_int = 46; +pub const IPPROTO_GRE: c_int = 47; +pub const IPPROTO_ESP: c_int = 50; +pub const IPPROTO_AH: c_int = 51; +pub const IPPROTO_MTP: c_int = 92; +pub const IPPROTO_BEETPH: c_int = 94; +pub const IPPROTO_ENCAP: c_int = 98; +pub const IPPROTO_PIM: c_int = 103; +pub const IPPROTO_COMP: c_int = 108; +pub const IPPROTO_L2TP: c_int = 115; +pub const IPPROTO_SCTP: c_int = 132; +pub const IPPROTO_UDPLITE: c_int = 136; +pub const IPPROTO_MPLS: c_int = 137; +pub const IPPROTO_ETHERNET: c_int = 143; +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MPTCP: c_int = 262; +pub const IPPROTO_MAX: c_int = 263; + +pub const IPPROTO_HOPOPTS: c_int = 0; +pub const IPPROTO_ROUTING: c_int = 43; +pub const IPPROTO_FRAGMENT: c_int = 44; +pub const IPPROTO_ICMPV6: c_int = 58; +pub const IPPROTO_NONE: c_int = 59; +pub const IPPROTO_DSTOPTS: c_int = 60; +pub const IPPROTO_MH: c_int = 135; + +pub const IPPORT_ECHO: in_port_t = 7; +pub const IPPORT_DISCARD: in_port_t = 9; +pub const IPPORT_SYSTAT: in_port_t = 11; +pub const IPPORT_DAYTIME: in_port_t = 13; +pub const IPPORT_NETSTAT: in_port_t = 15; +pub const IPPORT_FTP: in_port_t = 21; +pub const IPPORT_TELNET: in_port_t = 23; +pub const IPPORT_SMTP: in_port_t = 25; +pub const IPPORT_TIMESERVER: in_port_t = 37; +pub const IPPORT_NAMESERVER: in_port_t = 42; +pub const IPPORT_WHOIS: in_port_t = 43; +pub const IPPORT_MTP: in_port_t = 57; +pub const IPPORT_TFTP: in_port_t = 69; +pub const IPPORT_RJE: in_port_t = 77; +pub const IPPORT_FINGER: in_port_t = 79; +pub const IPPORT_TTYLINK: in_port_t = 87; +pub const IPPORT_SUPDUP: in_port_t = 95; +pub const IPPORT_EXECSERVER: in_port_t = 512; +pub const IPPORT_LOGINSERVER: in_port_t = 513; +pub const IPPORT_CMDSERVER: in_port_t = 514; +pub const IPPORT_EFSSERVER: in_port_t = 520; +pub const IPPORT_BIFFUDP: in_port_t = 512; +pub const IPPORT_WHOSERVER: in_port_t = 513; +pub const IPPORT_ROUTESERVER: in_port_t = 520; +pub const IPPORT_USERRESERVED: in_port_t = 5000; + +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; +pub const DT_WHT: c_uchar = 14; + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; +pub const ST_NOEXEC: c_ulong = 8; +pub const ST_SYNCHRONOUS: c_ulong = 16; +pub const ST_NOATIME: c_ulong = 32; +pub const ST_RELATIME: c_ulong = 64; + +pub const RTLD_DI_LMID: c_int = 1; +pub const RTLD_DI_LINKMAP: c_int = 2; +pub const RTLD_DI_CONFIGADDR: c_int = 3; +pub const RTLD_DI_SERINFO: c_int = 4; +pub const RTLD_DI_SERINFOSIZE: c_int = 5; +pub const RTLD_DI_ORIGIN: c_int = 6; +pub const RTLD_DI_PROFILENAME: c_int = 7; +pub const RTLD_DI_PROFILEOUT: c_int = 8; +pub const RTLD_DI_TLS_MODID: c_int = 9; +pub const RTLD_DI_TLS_DATA: c_int = 10; +pub const RTLD_DI_PHDR: c_int = 11; +pub const RTLD_DI_MAX: c_int = 11; + +pub const SI_ASYNCIO: c_int = -4; +pub const SI_MESGQ: c_int = -3; +pub const SI_TIMER: c_int = -2; +pub const SI_QUEUE: c_int = -1; +pub const SI_USER: c_int = 0; + +pub const ILL_ILLOPC: c_int = 1; +pub const ILL_ILLOPN: c_int = 2; +pub const ILL_ILLADR: c_int = 3; +pub const ILL_ILLTRP: c_int = 4; +pub const ILL_PRVOPC: c_int = 5; +pub const ILL_PRVREG: c_int = 6; +pub const ILL_COPROC: c_int = 7; +pub const ILL_BADSTK: c_int = 8; + +pub const FPE_INTDIV: c_int = 1; +pub const FPE_INTOVF: c_int = 2; +pub const FPE_FLTDIV: c_int = 3; +pub const FPE_FLTOVF: c_int = 4; +pub const FPE_FLTUND: c_int = 5; +pub const FPE_FLTRES: c_int = 6; +pub const FPE_FLTINV: c_int = 7; +pub const FPE_FLTSUB: c_int = 8; + +pub const SEGV_MAPERR: c_int = 1; +pub const SEGV_ACCERR: c_int = 2; + +pub const BUS_ADRALN: c_int = 1; +pub const BUS_ADRERR: c_int = 2; +pub const BUS_OBJERR: c_int = 3; + +pub const TRAP_BRKPT: c_int = 1; +pub const TRAP_TRACE: c_int = 2; + +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const POLL_IN: c_int = 1; +pub const POLL_OUT: c_int = 2; +pub const POLL_MSG: c_int = 3; +pub const POLL_ERR: c_int = 4; +pub const POLL_PRI: c_int = 5; +pub const POLL_HUP: c_int = 6; + +pub const SIGEV_SIGNAL: c_int = 0; +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const REG_GS: c_uint = 0; +pub const REG_FS: c_uint = 1; +pub const REG_ES: c_uint = 2; +pub const REG_DS: c_uint = 3; +pub const REG_EDI: c_uint = 4; +pub const REG_ESI: c_uint = 5; +pub const REG_EBP: c_uint = 6; +pub const REG_ESP: c_uint = 7; +pub const REG_EBX: c_uint = 8; +pub const REG_EDX: c_uint = 9; +pub const REG_ECX: c_uint = 10; +pub const REG_EAX: c_uint = 11; +pub const REG_TRAPNO: c_uint = 12; +pub const REG_ERR: c_uint = 13; +pub const REG_EIP: c_uint = 14; +pub const REG_CS: c_uint = 15; +pub const REG_EFL: c_uint = 16; +pub const REG_UESP: c_uint = 17; +pub const REG_SS: c_uint = 18; + +pub const IOC_VOID: __ioctl_dir = 0; +pub const IOC_OUT: __ioctl_dir = 1; +pub const IOC_IN: __ioctl_dir = 2; +pub const IOC_INOUT: __ioctl_dir = 3; + +pub const IOC_8: __ioctl_datum = 0; +pub const IOC_16: __ioctl_datum = 1; +pub const IOC_32: __ioctl_datum = 2; +pub const IOC_64: __ioctl_datum = 3; + +pub const TCP_ESTABLISHED: c_uint = 1; +pub const TCP_SYN_SENT: c_uint = 2; +pub const TCP_SYN_RECV: c_uint = 3; +pub const TCP_FIN_WAIT1: c_uint = 4; +pub const TCP_FIN_WAIT2: c_uint = 5; +pub const TCP_TIME_WAIT: c_uint = 6; +pub const TCP_CLOSE: c_uint = 7; +pub const TCP_CLOSE_WAIT: c_uint = 8; +pub const TCP_LAST_ACK: c_uint = 9; +pub const TCP_LISTEN: c_uint = 10; +pub const TCP_CLOSING: c_uint = 11; + +pub const TCP_CA_Open: tcp_ca_state = 0; +pub const TCP_CA_Disorder: tcp_ca_state = 1; +pub const TCP_CA_CWR: tcp_ca_state = 2; +pub const TCP_CA_Recovery: tcp_ca_state = 3; +pub const TCP_CA_Loss: tcp_ca_state = 4; + +pub const TCP_NO_QUEUE: c_uint = 0; +pub const TCP_RECV_QUEUE: c_uint = 1; +pub const TCP_SEND_QUEUE: c_uint = 2; +pub const TCP_QUEUES_NR: c_uint = 3; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 4; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __lock: 0, + __owner_id: 0, + __cnt: 0, + __shpid: 0, + __type: PTHREAD_MUTEX_TIMED as c_int, + __flags: 0, + __reserved1: Padding::new(0), + __reserved2: Padding::new(0), +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __lock: __PTHREAD_SPIN_LOCK_INITIALIZER, + __queue: 0i64 as *mut __pthread, + __attr: 0i64 as *mut __pthread_condattr, + __wrefs: 0, + __data: 0i64 as *mut c_void, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __held: __PTHREAD_SPIN_LOCK_INITIALIZER, + __lock: __PTHREAD_SPIN_LOCK_INITIALIZER, + __readers: 0, + __readerqueue: 0i64 as *mut __pthread, + __writerqueue: 0i64 as *mut __pthread, + __attr: 0i64 as *mut __pthread_rwlockattr, + __data: 0i64 as *mut c_void, +}; +pub const PTHREAD_STACK_MIN: size_t = 0; + +// Non-public helper constants +const _UTSNAME_LENGTH: usize = 1024; + +const fn CMSG_ALIGN(len: usize) -> usize { + (len + size_of::() - 1) & !(size_of::() - 1) +} + +// functions +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control.cast::() + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(CMSG_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + CMSG_ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < size_of::() { + return core::ptr::null_mut::(); + } + let next = (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max + || next as usize + CMSG_ALIGN((*next).cmsg_len as usize) > max + { + core::ptr::null_mut::() + } else { + next.cast::() + } + } + + pub fn CPU_ALLOC_SIZE(count: c_int) -> size_t { + let _dummy: cpu_set_t = mem::zeroed(); + let size_in_bits = 8 * size_of_val(&_dummy.bits[0]); + ((count as size_t + size_in_bits - 1) / 8) as size_t + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_COUNT_S(size: usize, cpuset: &cpu_set_t) -> c_int { + let mut s: u32 = 0; + let size_of_mask = size_of_val(&cpuset.bits[0]); + for i in cpuset.bits[..(size / size_of_mask)].iter() { + s += i.count_ones(); + } + s as c_int + } + + pub fn CPU_COUNT(cpuset: &cpu_set_t) -> c_int { + CPU_COUNT_S(size_of::(), cpuset) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn IPTOS_TOS(tos: u8) -> u8 { + tos & IPTOS_TOS_MASK + } + + pub fn IPTOS_PREC(tos: u8) -> u8 { + tos & IPTOS_PREC_MASK + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +extern "C" { + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + + pub fn futimes(fd: c_int, times: *const crate::timeval) -> c_int; + pub fn futimens(__fd: c_int, __times: *const crate::timespec) -> c_int; + + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + + pub fn mkfifoat(__fd: c_int, __path: *const c_char, __mode: __mode_t) -> c_int; + + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + + pub fn __libc_current_sigrtmin() -> c_int; + + pub fn __libc_current_sigrtmax() -> c_int; + + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; + + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + + pub fn sigwait(__set: *const sigset_t, __sig: *mut c_int) -> c_int; + + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + + pub fn ioctl(__fd: c_int, __request: c_ulong, ...) -> c_int; + + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + + pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int; + + pub fn pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: off64_t) -> ssize_t; + pub fn pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: off64_t) -> ssize_t; + + pub fn readv(__fd: c_int, __iovec: *const crate::iovec, __count: c_int) -> ssize_t; + pub fn writev(__fd: c_int, __iovec: *const crate::iovec, __count: c_int) -> ssize_t; + + pub fn preadv( + __fd: c_int, + __iovec: *const crate::iovec, + __count: c_int, + __offset: __off_t, + ) -> ssize_t; + pub fn pwritev( + __fd: c_int, + __iovec: *const crate::iovec, + __count: c_int, + __offset: __off_t, + ) -> ssize_t; + + pub fn preadv64(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off64_t) + -> ssize_t; + pub fn pwritev64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, + ) -> ssize_t; + + pub fn fread_unlocked( + buf: *mut c_void, + size: size_t, + nobj: size_t, + stream: *mut crate::FILE, + ) -> size_t; + + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut crate::sigevent, + ) -> c_int; + + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + + pub fn lseek64(__fd: c_int, __offset: __off64_t, __whence: c_int) -> __off64_t; + + pub fn lseek(__fd: c_int, __offset: __off_t, __whence: c_int) -> __off_t; + + pub fn fgetpos64(stream: *mut crate::FILE, ptr: *mut fpos64_t) -> c_int; + pub fn fseeko64(stream: *mut crate::FILE, offset: off64_t, whence: c_int) -> c_int; + pub fn fsetpos64(stream: *mut crate::FILE, ptr: *const fpos64_t) -> c_int; + pub fn ftello64(stream: *mut crate::FILE) -> off64_t; + + pub fn bind(__fd: c_int, __addr: *const sockaddr, __len: crate::socklen_t) -> c_int; + + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int; + + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: nfds_t, + timeout: *const crate::timespec, + sigmask: *const sigset_t, + ) -> c_int; + + pub fn recvmsg(__fd: c_int, __message: *mut msghdr, __flags: c_int) -> ssize_t; + + pub fn sendmsg(__fd: c_int, __message: *const msghdr, __flags: c_int) -> ssize_t; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + + pub fn sendfile(out_fd: c_int, in_fd: c_int, offset: *mut off_t, count: size_t) -> ssize_t; + pub fn sendfile64(out_fd: c_int, in_fd: c_int, offset: *mut off64_t, count: size_t) -> ssize_t; + + pub fn shutdown(__fd: c_int, __how: c_int) -> c_int; + + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + pub fn setdomainname(name: *const c_char, len: size_t) -> c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + + pub fn uname(buf: *mut crate::utsname) -> c_int; + + pub fn gethostid() -> c_long; + pub fn sethostid(hostid: c_long) -> c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + pub fn setspent(); + pub fn endspent(); + pub fn getspent() -> *mut spwd; + + pub fn getspnam(name: *const c_char) -> *mut spwd; + + pub fn getpwent_r( + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn fgetpwent_r( + stream: *mut crate::FILE, + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn fgetgrent_r( + stream: *mut crate::FILE, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + + pub fn putpwent(p: *const crate::passwd, stream: *mut crate::FILE) -> c_int; + pub fn putgrent(grp: *const crate::group, stream: *mut crate::FILE) -> c_int; + + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + + pub fn fgetspent_r( + fp: *mut crate::FILE, + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + pub fn sgetspent_r( + s: *const c_char, + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + pub fn getspent_r( + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + + pub fn getspnam_r( + name: *const c_char, + spbuf: *mut spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut spwd, + ) -> c_int; + + // mntent.h + pub fn getmntent_r( + stream: *mut crate::FILE, + mntbuf: *mut crate::mntent, + buf: *mut c_char, + buflen: c_int, + ) -> *mut crate::mntent; + + pub fn utmpname(file: *const c_char) -> c_int; + pub fn utmpxname(file: *const c_char) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + + pub fn setgroups(ngroups: size_t, ptr: *const crate::gid_t) -> c_int; + + pub fn acct(filename: *const c_char) -> c_int; + + pub fn setmntent(filename: *const c_char, ty: *const c_char) -> *mut crate::FILE; + pub fn getmntent(stream: *mut crate::FILE) -> *mut crate::mntent; + pub fn addmntent(stream: *mut crate::FILE, mnt: *const crate::mntent) -> c_int; + pub fn endmntent(streamp: *mut crate::FILE) -> c_int; + pub fn hasmntopt(mnt: *const crate::mntent, opt: *const c_char) -> *mut c_char; + + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn pthread_kill(__threadid: crate::pthread_t, __signo: c_int) -> c_int; + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + pub fn __pthread_equal(__t1: __pthread_t, __t2: __pthread_t) -> c_int; + + pub fn pthread_getattr_np(__thr: crate::pthread_t, __attr: *mut pthread_attr_t) -> c_int; + + pub fn pthread_attr_getguardsize( + __attr: *const pthread_attr_t, + __guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + + pub fn pthread_attr_getstack( + __attr: *const pthread_attr_t, + __stackaddr: *mut *mut c_void, + __stacksize: *mut size_t, + ) -> c_int; + + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, val: c_int) -> c_int; + + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setclock( + __attr: *mut pthread_condattr_t, + __clock_id: __clockid_t, + ) -> c_int; + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + + pub fn pthread_once(control: *mut pthread_once_t, routine: extern "C" fn()) -> c_int; + + pub fn pthread_barrierattr_init(attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_destroy(attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_getpshared( + attr: *const crate::pthread_barrierattr_t, + shared: *mut c_int, + ) -> c_int; + pub fn pthread_barrierattr_setpshared( + attr: *mut crate::pthread_barrierattr_t, + shared: c_int, + ) -> c_int; + pub fn pthread_barrier_init( + barrier: *mut pthread_barrier_t, + attr: *const crate::pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_spin_init(lock: *mut crate::pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + + pub fn pthread_sigmask( + __how: c_int, + __newmask: *const __sigset_t, + __oldmask: *mut __sigset_t, + ) -> c_int; + + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + pub fn pthread_getcpuclockid(thread: crate::pthread_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + + pub fn clock_getres(__clock_id: clockid_t, __res: *mut crate::timespec) -> c_int; + pub fn clock_gettime(__clock_id: clockid_t, __tp: *mut crate::timespec) -> c_int; + pub fn clock_settime(__clock_id: clockid_t, __tp: *const crate::timespec) -> c_int; + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + + pub fn asctime_r(tm: *const crate::tm, buf: *mut c_char) -> *mut c_char; + pub fn ctime_r(timep: *const time_t, buf: *mut c_char) -> *mut c_char; + + pub fn strftime( + s: *mut c_char, + max: size_t, + format: *const c_char, + tm: *const crate::tm, + ) -> size_t; + pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut crate::tm) -> *mut c_char; + + pub fn timer_create( + clockid: crate::clockid_t, + sevp: *mut crate::sigevent, + timerid: *mut crate::timer_t, + ) -> c_int; + pub fn timer_delete(timerid: crate::timer_t) -> c_int; + pub fn timer_getoverrun(timerid: crate::timer_t) -> c_int; + pub fn timer_gettime(timerid: crate::timer_t, curr_value: *mut crate::itimerspec) -> c_int; + pub fn timer_settime( + timerid: crate::timer_t, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + + pub fn fstat(__fd: c_int, __buf: *mut stat) -> c_int; + pub fn fstat64(__fd: c_int, __buf: *mut stat64) -> c_int; + + pub fn fstatat(__fd: c_int, __file: *const c_char, __buf: *mut stat, __flag: c_int) -> c_int; + pub fn fstatat64( + __fd: c_int, + __file: *const c_char, + __buf: *mut stat64, + __flag: c_int, + ) -> c_int; + + pub fn statx( + dirfd: c_int, + pathname: *const c_char, + flags: c_int, + mask: c_uint, + statxbuf: *mut statx, + ) -> c_int; + + pub fn ftruncate(__fd: c_int, __length: __off_t) -> c_int; + pub fn ftruncate64(__fd: c_int, __length: __off64_t) -> c_int; + pub fn truncate64(__file: *const c_char, __length: __off64_t) -> c_int; + + pub fn lstat(__file: *const c_char, __buf: *mut stat) -> c_int; + pub fn lstat64(__file: *const c_char, __buf: *mut stat64) -> c_int; + + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn statfs64(__file: *const c_char, __buf: *mut statfs64) -> c_int; + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn fstatfs64(__fildes: c_int, __buf: *mut statfs64) -> c_int; + + pub fn statvfs(__file: *const c_char, __buf: *mut statvfs) -> c_int; + pub fn statvfs64(__file: *const c_char, __buf: *mut statvfs64) -> c_int; + pub fn fstatvfs(__fildes: c_int, __buf: *mut statvfs) -> c_int; + pub fn fstatvfs64(__fildes: c_int, __buf: *mut statvfs64) -> c_int; + + pub fn open(__file: *const c_char, __oflag: c_int, ...) -> c_int; + pub fn open64(__file: *const c_char, __oflag: c_int, ...) -> c_int; + + pub fn openat(__fd: c_int, __file: *const c_char, __oflag: c_int, ...) -> c_int; + pub fn openat64(__fd: c_int, __file: *const c_char, __oflag: c_int, ...) -> c_int; + + pub fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn freopen64( + filename: *const c_char, + mode: *const c_char, + file: *mut crate::FILE, + ) -> *mut crate::FILE; + + pub fn creat64(path: *const c_char, mode: mode_t) -> c_int; + + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn tmpfile64() -> *mut crate::FILE; + + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + + pub fn getdtablesize() -> c_int; + + // Added in `glibc` 2.34 + pub fn close_range(first: c_uint, last: c_uint, flags: c_int) -> c_int; + + pub fn openpty( + __amaster: *mut c_int, + __aslave: *mut c_int, + __name: *mut c_char, + __termp: *const termios, + __winp: *const crate::winsize, + ) -> c_int; + + pub fn forkpty( + __amaster: *mut c_int, + __name: *mut c_char, + __termp: *const termios, + __winp: *const crate::winsize, + ) -> crate::pid_t; + + pub fn getpt() -> c_int; + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn login_tty(fd: c_int) -> c_int; + + pub fn ctermid(s: *mut c_char) -> *mut c_char; + + pub fn clearenv() -> c_int; + + pub fn execveat( + dirfd: c_int, + pathname: *const c_char, + argv: *const *mut c_char, + envp: *const *mut c_char, + flags: c_int, + ) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + + // posix/spawn.h + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + + // Added in `glibc` 2.29 + pub fn posix_spawn_file_actions_addchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + // Added in `glibc` 2.29 + pub fn posix_spawn_file_actions_addfchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + // Added in `glibc` 2.34 + pub fn posix_spawn_file_actions_addclosefrom_np( + actions: *mut crate::posix_spawn_file_actions_t, + from: c_int, + ) -> c_int; + // Added in `glibc` 2.35 + pub fn posix_spawn_file_actions_addtcsetpgrp_np( + actions: *mut crate::posix_spawn_file_actions_t, + tcfd: c_int, + ) -> c_int; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn euidaccess(pathname: *const c_char, mode: c_int) -> c_int; + pub fn eaccess(pathname: *const c_char, mode: c_int) -> c_int; + + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + + pub fn stat(__file: *const c_char, __buf: *mut stat) -> c_int; + pub fn stat64(__file: *const c_char, __buf: *mut stat64) -> c_int; + + pub fn readdir(dirp: *mut crate::DIR) -> *mut crate::dirent; + pub fn readdir64(dirp: *mut crate::DIR) -> *mut crate::dirent64; + pub fn readdir_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent, + result: *mut *mut crate::dirent, + ) -> c_int; + pub fn readdir64_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent64, + result: *mut *mut crate::dirent64, + ) -> c_int; + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + #[link_name = "__xpg_strerror_r"] + pub fn strerror_r(__errnum: c_int, __buf: *mut c_char, __buflen: size_t) -> c_int; + + pub fn __errno_location() -> *mut c_int; + + pub fn mmap64( + __addr: *mut c_void, + __len: size_t, + __prot: c_int, + __flags: c_int, + __fd: c_int, + __offset: __off64_t, + ) -> *mut c_void; + + pub fn mremap( + addr: *mut c_void, + len: size_t, + new_len: size_t, + flags: c_int, + ... + ) -> *mut c_void; + + pub fn mprotect(__addr: *mut c_void, __len: size_t, __prot: c_int) -> c_int; + + pub fn msync(__addr: *mut c_void, __len: size_t, __flags: c_int) -> c_int; + pub fn sync(); + pub fn syncfs(fd: c_int) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + + pub fn fallocate64(fd: c_int, mode: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int; + + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + + pub fn posix_fadvise64(fd: c_int, offset: off64_t, len: off64_t, advise: c_int) -> c_int; + + pub fn madvise(__addr: *mut c_void, __len: size_t, __advice: c_int) -> c_int; + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn getrlimit(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit) -> c_int; + pub fn getrlimit64(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit64) -> c_int; + pub fn setrlimit(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit) -> c_int; + pub fn setrlimit64(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit64) + -> c_int; + + pub fn getpriority(which: crate::__priority_which, who: crate::id_t) -> c_int; + pub fn setpriority(which: crate::__priority_which, who: crate::id_t, prio: c_int) -> c_int; + + pub fn getrandom(__buffer: *mut c_void, __length: size_t, __flags: c_uint) -> ssize_t; + pub fn getentropy(__buffer: *mut c_void, __length: size_t) -> c_int; + + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn drand48() -> c_double; + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn lrand48() -> c_long; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn mrand48() -> c_long; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn srand48(seed: c_long); + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn lcong48(p: *mut c_ushort); + + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); + + pub fn brk(addr: *mut c_void) -> c_int; + pub fn sbrk(increment: intptr_t) -> *mut c_void; + + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn mallopt(param: c_int, value: c_int) -> c_int; + + pub fn mallinfo() -> crate::mallinfo; + pub fn mallinfo2() -> crate::mallinfo2; + pub fn malloc_info(options: c_int, stream: *mut crate::FILE) -> c_int; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + pub fn malloc_trim(__pad: size_t) -> c_int; + + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + pub fn iconv_close(cd: iconv_t) -> c_int; + + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + + pub fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int; + + pub fn reboot(how_to: c_int) -> c_int; + + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + + pub fn regexec( + preg: *const crate::regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + + pub fn regerror( + errcode: c_int, + preg: *const crate::regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + + pub fn regfree(preg: *mut crate::regex_t); + + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn glob64( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut glob64_t, + ) -> c_int; + pub fn globfree64(pglob: *mut glob64_t); + + pub fn getxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn lgetxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn fgetxattr( + filedes: c_int, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn setxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn lsetxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn fsetxattr( + filedes: c_int, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn flistxattr(filedes: c_int, list: *mut c_char, size: size_t) -> ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn fremovexattr(filedes: c_int, name: *const c_char) -> c_int; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + /// POSIX version of `basename(3)`, defined in `libgen.h`. + #[link_name = "__xpg_basename"] + pub fn posix_basename(path: *mut c_char) -> *mut c_char; + /// GNU version of `basename(3)`, defined in `string.h`. + #[link_name = "basename"] + pub fn gnu_basename(path: *const c_char) -> *mut c_char; + + pub fn dlmopen(lmid: Lmid_t, filename: *const c_char, flag: c_int) -> *mut c_void; + pub fn dlinfo(handle: *mut c_void, request: c_int, info: *mut c_void) -> c_int; + pub fn dladdr1( + addr: *const c_void, + info: *mut crate::Dl_info, + extra_info: *mut *mut c_void, + flags: c_int, + ) -> c_int; + + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn( + info: *mut crate::dl_phdr_info, + size: size_t, + data: *mut c_void, + ) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + pub fn gnu_get_libc_release() -> *const c_char; + pub fn gnu_get_libc_version() -> *const c_char; +} + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= major << 8; + dev |= minor; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + ((dev >> 8) & 0xff) as c_uint + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + (dev & 0xffff00ff) as c_uint + } + + pub fn SIGRTMAX() -> c_int { + unsafe { __libc_current_sigrtmax() } + } + + pub fn SIGRTMIN() -> c_int { + unsafe { __libc_current_sigrtmin() } + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0x7f) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn W_EXITCODE(ret: c_int, sig: c_int) -> c_int { + (ret << 8) | sig + } + + pub const fn W_STOPCODE(sig: c_int) -> c_int { + (sig << 8) | 0x7f + } + + pub const fn QCMD(cmd: c_int, type_: c_int) -> c_int { + (cmd << 8) | (type_ & 0x00ff) + } + + pub const fn IPOPT_COPIED(o: u8) -> u8 { + o & IPOPT_COPY + } + + pub const fn IPOPT_CLASS(o: u8) -> u8 { + o & IPOPT_CLASS_MASK + } + + pub const fn IPOPT_NUMBER(o: u8) -> u8 { + o & IPOPT_NUMBER_MASK + } + + pub const fn IPTOS_ECN(x: u8) -> u8 { + x & crate::IPTOS_ECN_MASK + } +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + mod b32; + pub use self::b32::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b32/arm.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/arm.rs new file mode 100644 index 00000000000000..66375876e7760f --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/arm.rs @@ -0,0 +1,494 @@ +use crate::prelude::*; + +pub type wchar_t = u32; +pub type greg_t = i32; +pub type mcontext_t = sigcontext; + +s! { + pub struct sigcontext { + pub trap_no: c_ulong, + pub error_code: c_ulong, + pub oldmask: c_ulong, + pub arm_r0: c_ulong, + pub arm_r1: c_ulong, + pub arm_r2: c_ulong, + pub arm_r3: c_ulong, + pub arm_r4: c_ulong, + pub arm_r5: c_ulong, + pub arm_r6: c_ulong, + pub arm_r7: c_ulong, + pub arm_r8: c_ulong, + pub arm_r9: c_ulong, + pub arm_r10: c_ulong, + pub arm_fp: c_ulong, + pub arm_ip: c_ulong, + pub arm_sp: c_ulong, + pub arm_lr: c_ulong, + pub arm_pc: c_ulong, + pub arm_cpsr: c_ulong, + pub fault_address: c_ulong, + } + + pub struct __c_anonymous_uc_sigmask_with_padding { + pub uc_sigmask: crate::sigset_t, + /* Android has a wrong (smaller) sigset_t on x86. */ + __padding_rt_sigset: Padding, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask__c_anonymous_union: __c_anonymous_uc_sigmask, + /* The kernel adds extra padding after uc_sigmask to match + * glibc sigset_t on ARM. */ + __padding: Padding<[c_char; 120]>, + __align: [c_longlong; 0], + uc_regspace: [c_ulong; 128], + } +} + +s_no_extra_traits! { + pub union __c_anonymous_uc_sigmask { + uc_sigmask: __c_anonymous_uc_sigmask_with_padding, + uc_sigmask64: crate::sigset64_t, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_uc_sigmask { + fn eq(&self, other: &__c_anonymous_uc_sigmask) -> bool { + unsafe { self.uc_sigmask == other.uc_sigmask } + } + } + impl Eq for __c_anonymous_uc_sigmask {} + impl hash::Hash for __c_anonymous_uc_sigmask { + fn hash(&self, state: &mut H) { + unsafe { self.uc_sigmask.hash(state) } + } + } + } +} + +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_LARGEFILE: c_int = 0o400000; + +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_ptrace: c_long = 26; +pub const SYS_pause: c_long = 29; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_vhangup: c_long = 111; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS_getdents: c_long = 141; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_pivot_root: c_long = 218; +pub const SYS_mincore: c_long = 219; +pub const SYS_madvise: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_lookup_dcookie: c_long = 249; +pub const SYS_epoll_create: c_long = 250; +pub const SYS_epoll_ctl: c_long = 251; +pub const SYS_epoll_wait: c_long = 252; +pub const SYS_remap_file_pages: c_long = 253; +pub const SYS_set_tid_address: c_long = 256; +pub const SYS_timer_create: c_long = 257; +pub const SYS_timer_settime: c_long = 258; +pub const SYS_timer_gettime: c_long = 259; +pub const SYS_timer_getoverrun: c_long = 260; +pub const SYS_timer_delete: c_long = 261; +pub const SYS_clock_settime: c_long = 262; +pub const SYS_clock_gettime: c_long = 263; +pub const SYS_clock_getres: c_long = 264; +pub const SYS_clock_nanosleep: c_long = 265; +pub const SYS_statfs64: c_long = 266; +pub const SYS_fstatfs64: c_long = 267; +pub const SYS_tgkill: c_long = 268; +pub const SYS_utimes: c_long = 269; +pub const SYS_arm_fadvise64_64: c_long = 270; +pub const SYS_pciconfig_iobase: c_long = 271; +pub const SYS_pciconfig_read: c_long = 272; +pub const SYS_pciconfig_write: c_long = 273; +pub const SYS_mq_open: c_long = 274; +pub const SYS_mq_unlink: c_long = 275; +pub const SYS_mq_timedsend: c_long = 276; +pub const SYS_mq_timedreceive: c_long = 277; +pub const SYS_mq_notify: c_long = 278; +pub const SYS_mq_getsetattr: c_long = 279; +pub const SYS_waitid: c_long = 280; +pub const SYS_socket: c_long = 281; +pub const SYS_bind: c_long = 282; +pub const SYS_connect: c_long = 283; +pub const SYS_listen: c_long = 284; +pub const SYS_accept: c_long = 285; +pub const SYS_getsockname: c_long = 286; +pub const SYS_getpeername: c_long = 287; +pub const SYS_socketpair: c_long = 288; +pub const SYS_send: c_long = 289; +pub const SYS_sendto: c_long = 290; +pub const SYS_recv: c_long = 291; +pub const SYS_recvfrom: c_long = 292; +pub const SYS_shutdown: c_long = 293; +pub const SYS_setsockopt: c_long = 294; +pub const SYS_getsockopt: c_long = 295; +pub const SYS_sendmsg: c_long = 296; +pub const SYS_recvmsg: c_long = 297; +pub const SYS_semop: c_long = 298; +pub const SYS_semget: c_long = 299; +pub const SYS_semctl: c_long = 300; +pub const SYS_msgsnd: c_long = 301; +pub const SYS_msgrcv: c_long = 302; +pub const SYS_msgget: c_long = 303; +pub const SYS_msgctl: c_long = 304; +pub const SYS_shmat: c_long = 305; +pub const SYS_shmdt: c_long = 306; +pub const SYS_shmget: c_long = 307; +pub const SYS_shmctl: c_long = 308; +pub const SYS_add_key: c_long = 309; +pub const SYS_request_key: c_long = 310; +pub const SYS_keyctl: c_long = 311; +pub const SYS_semtimedop: c_long = 312; +pub const SYS_vserver: c_long = 313; +pub const SYS_ioprio_set: c_long = 314; +pub const SYS_ioprio_get: c_long = 315; +pub const SYS_inotify_init: c_long = 316; +pub const SYS_inotify_add_watch: c_long = 317; +pub const SYS_inotify_rm_watch: c_long = 318; +pub const SYS_mbind: c_long = 319; +pub const SYS_get_mempolicy: c_long = 320; +pub const SYS_set_mempolicy: c_long = 321; +pub const SYS_openat: c_long = 322; +pub const SYS_mkdirat: c_long = 323; +pub const SYS_mknodat: c_long = 324; +pub const SYS_fchownat: c_long = 325; +pub const SYS_futimesat: c_long = 326; +pub const SYS_fstatat64: c_long = 327; +pub const SYS_unlinkat: c_long = 328; +pub const SYS_renameat: c_long = 329; +pub const SYS_linkat: c_long = 330; +pub const SYS_symlinkat: c_long = 331; +pub const SYS_readlinkat: c_long = 332; +pub const SYS_fchmodat: c_long = 333; +pub const SYS_faccessat: c_long = 334; +pub const SYS_pselect6: c_long = 335; +pub const SYS_ppoll: c_long = 336; +pub const SYS_unshare: c_long = 337; +pub const SYS_set_robust_list: c_long = 338; +pub const SYS_get_robust_list: c_long = 339; +pub const SYS_splice: c_long = 340; +pub const SYS_arm_sync_file_range: c_long = 341; +pub const SYS_tee: c_long = 342; +pub const SYS_vmsplice: c_long = 343; +pub const SYS_move_pages: c_long = 344; +pub const SYS_getcpu: c_long = 345; +pub const SYS_epoll_pwait: c_long = 346; +pub const SYS_kexec_load: c_long = 347; +pub const SYS_utimensat: c_long = 348; +pub const SYS_signalfd: c_long = 349; +pub const SYS_timerfd_create: c_long = 350; +pub const SYS_eventfd: c_long = 351; +pub const SYS_fallocate: c_long = 352; +pub const SYS_timerfd_settime: c_long = 353; +pub const SYS_timerfd_gettime: c_long = 354; +pub const SYS_signalfd4: c_long = 355; +pub const SYS_eventfd2: c_long = 356; +pub const SYS_epoll_create1: c_long = 357; +pub const SYS_dup3: c_long = 358; +pub const SYS_pipe2: c_long = 359; +pub const SYS_inotify_init1: c_long = 360; +pub const SYS_preadv: c_long = 361; +pub const SYS_pwritev: c_long = 362; +pub const SYS_rt_tgsigqueueinfo: c_long = 363; +pub const SYS_perf_event_open: c_long = 364; +pub const SYS_recvmmsg: c_long = 365; +pub const SYS_accept4: c_long = 366; +pub const SYS_fanotify_init: c_long = 367; +pub const SYS_fanotify_mark: c_long = 368; +pub const SYS_prlimit64: c_long = 369; +pub const SYS_name_to_handle_at: c_long = 370; +pub const SYS_open_by_handle_at: c_long = 371; +pub const SYS_clock_adjtime: c_long = 372; +pub const SYS_syncfs: c_long = 373; +pub const SYS_sendmmsg: c_long = 374; +pub const SYS_setns: c_long = 375; +pub const SYS_process_vm_readv: c_long = 376; +pub const SYS_process_vm_writev: c_long = 377; +pub const SYS_kcmp: c_long = 378; +pub const SYS_finit_module: c_long = 379; +pub const SYS_sched_setattr: c_long = 380; +pub const SYS_sched_getattr: c_long = 381; +pub const SYS_renameat2: c_long = 382; +pub const SYS_seccomp: c_long = 383; +pub const SYS_getrandom: c_long = 384; +pub const SYS_memfd_create: c_long = 385; +pub const SYS_bpf: c_long = 386; +pub const SYS_execveat: c_long = 387; +pub const SYS_userfaultfd: c_long = 388; +pub const SYS_membarrier: c_long = 389; +pub const SYS_mlock2: c_long = 390; +pub const SYS_copy_file_range: c_long = 391; +pub const SYS_preadv2: c_long = 392; +pub const SYS_pwritev2: c_long = 393; +pub const SYS_pkey_mprotect: c_long = 394; +pub const SYS_pkey_alloc: c_long = 395; +pub const SYS_pkey_free: c_long = 396; +pub const SYS_statx: c_long = 397; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_R0: c_int = 0; +pub const REG_R1: c_int = 1; +pub const REG_R2: c_int = 2; +pub const REG_R3: c_int = 3; +pub const REG_R4: c_int = 4; +pub const REG_R5: c_int = 5; +pub const REG_R6: c_int = 6; +pub const REG_R7: c_int = 7; +pub const REG_R8: c_int = 8; +pub const REG_R9: c_int = 9; +pub const REG_R10: c_int = 10; +pub const REG_R11: c_int = 11; +pub const REG_R12: c_int = 12; +pub const REG_R13: c_int = 13; +pub const REG_R14: c_int = 14; +pub const REG_R15: c_int = 15; + +pub const NGREG: c_int = 18; + +// From NDK's asm/auxvec.h +pub const AT_SYSINFO_EHDR: c_ulong = 33; + +f! { + // Sadly, Android before 5.0 (API level 21), the accept4 syscall is not + // exposed by the libc. As work-around, we implement it through `syscall` + // directly. This workaround can be removed if the minimum version of + // Android is bumped. When the workaround is removed, `accept4` can be + // moved back to `linux_like/mod.rs` + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int { + crate::syscall(SYS_accept4, fd, addr, len, flg) as c_int + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/mod.rs new file mode 100644 index 00000000000000..d0c2349b98c626 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/mod.rs @@ -0,0 +1,239 @@ +use crate::prelude::*; + +// The following definitions are correct for arm and i686, +// but may be wrong for mips + +pub type mode_t = u16; +pub type off64_t = c_longlong; +pub type sigset_t = c_ulong; +pub type socklen_t = i32; +pub type time64_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct rlimit64 { + pub rlim_cur: u64, + pub rlim_max: u64, + } + + pub struct stat { + pub st_dev: c_ulonglong, + __pad0: Padding<[c_uchar; 4]>, + __st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulonglong, + __pad3: Padding<[c_uchar; 4]>, + pub st_size: c_longlong, + pub st_blksize: crate::blksize_t, + pub st_blocks: c_ulonglong, + pub st_atime: c_long, + pub st_atime_nsec: c_long, + pub st_mtime: c_long, + pub st_mtime_nsec: c_long, + pub st_ctime: c_long, + pub st_ctime_nsec: c_long, + pub st_ino: c_ulonglong, + } + + pub struct stat64 { + pub st_dev: c_ulonglong, + __pad0: Padding<[c_uchar; 4]>, + __st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulonglong, + __pad3: Padding<[c_uchar; 4]>, + pub st_size: c_longlong, + pub st_blksize: crate::blksize_t, + pub st_blocks: c_ulonglong, + pub st_atime: c_long, + pub st_atime_nsec: c_long, + pub st_mtime: c_long, + pub st_mtime_nsec: c_long, + pub st_ctime: c_long, + pub st_ctime_nsec: c_long, + pub st_ino: c_ulonglong, + } + + pub struct statfs64 { + pub f_type: u32, + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::__fsid_t, + pub f_namelen: u32, + pub f_frsize: u32, + pub f_flags: u32, + pub f_spare: [u32; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: c_ulong, + pub f_bfree: c_ulong, + pub f_bavail: c_ulong, + pub f_files: c_ulong, + pub f_ffree: c_ulong, + pub f_favail: c_ulong, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct pthread_attr_t { + pub flags: u32, + pub stack_base: *mut c_void, + pub stack_size: size_t, + pub guard_size: size_t, + pub sched_policy: i32, + pub sched_priority: i32, + } + + pub struct pthread_mutex_t { + value: c_int, + } + + pub struct pthread_cond_t { + value: c_int, + } + + pub struct pthread_rwlock_t { + lock: pthread_mutex_t, + cond: pthread_cond_t, + numLocks: c_int, + writerThreadId: c_int, + pendingReaders: c_int, + pendingWriters: c_int, + attr: i32, + __reserved: Padding<[c_char; 12]>, + } + + pub struct pthread_barrier_t { + __private: [i32; 8], + } + + pub struct pthread_spinlock_t { + __private: [i32; 2], + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct statfs { + pub f_type: u32, + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::__fsid_t, + pub f_namelen: u32, + pub f_frsize: u32, + pub f_flags: u32, + pub f_spare: [u32; 4], + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 8], + } +} + +s_no_extra_traits! { + pub struct sigset64_t { + __bits: [c_ulong; 2], + } +} + +// These constants must be of the same type of sigaction.sa_flags +pub const SA_NOCLDSTOP: c_int = 0x00000001; +pub const SA_NOCLDWAIT: c_int = 0x00000002; +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_SIGINFO: c_int = 0x00000004; + +pub const RTLD_GLOBAL: c_int = 2; +pub const RTLD_NOW: c_int = 0; +pub const RTLD_DEFAULT: *mut c_void = -1isize as *mut c_void; + +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { value: 0 }; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { value: 0 }; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + lock: PTHREAD_MUTEX_INITIALIZER, + cond: PTHREAD_COND_INITIALIZER, + numLocks: 0, + writerThreadId: 0, + pendingReaders: 0, + pendingWriters: 0, + attr: 0, + __reserved: Padding::new([0; 12]), +}; +pub const PTHREAD_STACK_MIN: size_t = 4096 * 2; +pub const CPU_SETSIZE: size_t = 32; +pub const __CPU_BITS: size_t = 32; + +pub const UT_LINESIZE: usize = 8; +pub const UT_NAMESIZE: usize = 8; +pub const UT_HOSTSIZE: usize = 16; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +extern "C" { + pub fn timegm64(tm: *const crate::tm) -> crate::time64_t; +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b32/x86/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/x86/mod.rs new file mode 100644 index 00000000000000..7266cf2c313630 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b32/x86/mod.rs @@ -0,0 +1,568 @@ +use crate::prelude::*; + +pub type wchar_t = i32; +pub type greg_t = i32; + +s! { + pub struct _libc_fpreg { + pub significand: [u16; 4], + pub exponent: u16, + } + + pub struct _libc_fpstate { + pub cw: c_ulong, + pub sw: c_ulong, + pub tag: c_ulong, + pub ipoff: c_ulong, + pub cssel: c_ulong, + pub dataoff: c_ulong, + pub datasel: c_ulong, + pub _st: [_libc_fpreg; 8], + pub status: c_ulong, + } + + pub struct mcontext_t { + pub gregs: [greg_t; 19], + pub fpregs: *mut _libc_fpstate, + pub oldmask: c_ulong, + pub cr2: c_ulong, + } + + pub struct __c_anonymous_uc_sigmask_with_padding { + pub uc_sigmask: crate::sigset_t, + /* Android has a wrong (smaller) sigset_t on x86. */ + __padding_rt_sigset: Padding, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask__c_anonymous_union: __c_anonymous_uc_sigmask, + __padding_rt_sigset: Padding, + __fpregs_mem: _libc_fpstate, + } +} + +s_no_extra_traits! { + pub union __c_anonymous_uc_sigmask { + uc_sigmask: __c_anonymous_uc_sigmask_with_padding, + uc_sigmask64: crate::sigset64_t, + } + + #[repr(align(8))] + pub struct max_align_t { + priv_: [f64; 2], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_uc_sigmask { + fn eq(&self, other: &__c_anonymous_uc_sigmask) -> bool { + unsafe { self.uc_sigmask == other.uc_sigmask } + } + } + impl Eq for __c_anonymous_uc_sigmask {} + impl hash::Hash for __c_anonymous_uc_sigmask { + fn hash(&self, state: &mut H) { + unsafe { self.uc_sigmask.hash(state) } + } + } + } +} + +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_LARGEFILE: c_int = 0o0100000; + +pub const MAP_32BIT: c_int = 0x40; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86old: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +// FIXME(android): SYS__llseek is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +// FIXME(android): SYS__newselect is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +// FIXME(android): SYS__llseek is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_vm86: c_long = 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_mincore: c_long = 218; +pub const SYS_madvise: c_long = 219; +pub const SYS_getdents64: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_set_thread_area: c_long = 243; +pub const SYS_get_thread_area: c_long = 244; +pub const SYS_io_setup: c_long = 245; +pub const SYS_io_destroy: c_long = 246; +pub const SYS_io_getevents: c_long = 247; +pub const SYS_io_submit: c_long = 248; +pub const SYS_io_cancel: c_long = 249; +pub const SYS_fadvise64: c_long = 250; +pub const SYS_exit_group: c_long = 252; +pub const SYS_lookup_dcookie: c_long = 253; +pub const SYS_epoll_create: c_long = 254; +pub const SYS_epoll_ctl: c_long = 255; +pub const SYS_epoll_wait: c_long = 256; +pub const SYS_remap_file_pages: c_long = 257; +pub const SYS_set_tid_address: c_long = 258; +pub const SYS_timer_create: c_long = 259; +pub const SYS_timer_settime: c_long = 260; +pub const SYS_timer_gettime: c_long = 261; +pub const SYS_timer_getoverrun: c_long = 262; +pub const SYS_timer_delete: c_long = 263; +pub const SYS_clock_settime: c_long = 264; +pub const SYS_clock_gettime: c_long = 265; +pub const SYS_clock_getres: c_long = 266; +pub const SYS_clock_nanosleep: c_long = 267; +pub const SYS_statfs64: c_long = 268; +pub const SYS_fstatfs64: c_long = 269; +pub const SYS_tgkill: c_long = 270; +pub const SYS_utimes: c_long = 271; +pub const SYS_fadvise64_64: c_long = 272; +pub const SYS_vserver: c_long = 273; +pub const SYS_mbind: c_long = 274; +pub const SYS_get_mempolicy: c_long = 275; +pub const SYS_set_mempolicy: c_long = 276; +pub const SYS_mq_open: c_long = 277; +pub const SYS_mq_unlink: c_long = 278; +pub const SYS_mq_timedsend: c_long = 279; +pub const SYS_mq_timedreceive: c_long = 280; +pub const SYS_mq_notify: c_long = 281; +pub const SYS_mq_getsetattr: c_long = 282; +pub const SYS_kexec_load: c_long = 283; +pub const SYS_waitid: c_long = 284; +pub const SYS_add_key: c_long = 286; +pub const SYS_request_key: c_long = 287; +pub const SYS_keyctl: c_long = 288; +pub const SYS_ioprio_set: c_long = 289; +pub const SYS_ioprio_get: c_long = 290; +pub const SYS_inotify_init: c_long = 291; +pub const SYS_inotify_add_watch: c_long = 292; +pub const SYS_inotify_rm_watch: c_long = 293; +pub const SYS_migrate_pages: c_long = 294; +pub const SYS_openat: c_long = 295; +pub const SYS_mkdirat: c_long = 296; +pub const SYS_mknodat: c_long = 297; +pub const SYS_fchownat: c_long = 298; +pub const SYS_futimesat: c_long = 299; +pub const SYS_fstatat64: c_long = 300; +pub const SYS_unlinkat: c_long = 301; +pub const SYS_renameat: c_long = 302; +pub const SYS_linkat: c_long = 303; +pub const SYS_symlinkat: c_long = 304; +pub const SYS_readlinkat: c_long = 305; +pub const SYS_fchmodat: c_long = 306; +pub const SYS_faccessat: c_long = 307; +pub const SYS_pselect6: c_long = 308; +pub const SYS_ppoll: c_long = 309; +pub const SYS_unshare: c_long = 310; +pub const SYS_set_robust_list: c_long = 311; +pub const SYS_get_robust_list: c_long = 312; +pub const SYS_splice: c_long = 313; +pub const SYS_sync_file_range: c_long = 314; +pub const SYS_tee: c_long = 315; +pub const SYS_vmsplice: c_long = 316; +pub const SYS_move_pages: c_long = 317; +pub const SYS_getcpu: c_long = 318; +pub const SYS_epoll_pwait: c_long = 319; +pub const SYS_utimensat: c_long = 320; +pub const SYS_signalfd: c_long = 321; +pub const SYS_timerfd_create: c_long = 322; +pub const SYS_eventfd: c_long = 323; +pub const SYS_fallocate: c_long = 324; +pub const SYS_timerfd_settime: c_long = 325; +pub const SYS_timerfd_gettime: c_long = 326; +pub const SYS_signalfd4: c_long = 327; +pub const SYS_eventfd2: c_long = 328; +pub const SYS_epoll_create1: c_long = 329; +pub const SYS_dup3: c_long = 330; +pub const SYS_pipe2: c_long = 331; +pub const SYS_inotify_init1: c_long = 332; +pub const SYS_preadv: c_long = 333; +pub const SYS_pwritev: c_long = 334; +pub const SYS_rt_tgsigqueueinfo: c_long = 335; +pub const SYS_perf_event_open: c_long = 336; +pub const SYS_recvmmsg: c_long = 337; +pub const SYS_fanotify_init: c_long = 338; +pub const SYS_fanotify_mark: c_long = 339; +pub const SYS_prlimit64: c_long = 340; +pub const SYS_name_to_handle_at: c_long = 341; +pub const SYS_open_by_handle_at: c_long = 342; +pub const SYS_clock_adjtime: c_long = 343; +pub const SYS_syncfs: c_long = 344; +pub const SYS_sendmmsg: c_long = 345; +pub const SYS_setns: c_long = 346; +pub const SYS_process_vm_readv: c_long = 347; +pub const SYS_process_vm_writev: c_long = 348; +pub const SYS_kcmp: c_long = 349; +pub const SYS_finit_module: c_long = 350; +pub const SYS_sched_setattr: c_long = 351; +pub const SYS_sched_getattr: c_long = 352; +pub const SYS_renameat2: c_long = 353; +pub const SYS_seccomp: c_long = 354; +pub const SYS_getrandom: c_long = 355; +pub const SYS_memfd_create: c_long = 356; +pub const SYS_bpf: c_long = 357; +pub const SYS_execveat: c_long = 358; +pub const SYS_socket: c_long = 359; +pub const SYS_socketpair: c_long = 360; +pub const SYS_bind: c_long = 361; +pub const SYS_connect: c_long = 362; +pub const SYS_listen: c_long = 363; +pub const SYS_accept4: c_long = 364; +pub const SYS_getsockopt: c_long = 365; +pub const SYS_setsockopt: c_long = 366; +pub const SYS_getsockname: c_long = 367; +pub const SYS_getpeername: c_long = 368; +pub const SYS_sendto: c_long = 369; +pub const SYS_sendmsg: c_long = 370; +pub const SYS_recvfrom: c_long = 371; +pub const SYS_recvmsg: c_long = 372; +pub const SYS_shutdown: c_long = 373; +pub const SYS_userfaultfd: c_long = 374; +pub const SYS_membarrier: c_long = 375; +pub const SYS_mlock2: c_long = 376; +pub const SYS_copy_file_range: c_long = 377; +pub const SYS_preadv2: c_long = 378; +pub const SYS_pwritev2: c_long = 379; +pub const SYS_pkey_mprotect: c_long = 380; +pub const SYS_pkey_alloc: c_long = 381; +pub const SYS_pkey_free: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: c_int = 0; +pub const ECX: c_int = 1; +pub const EDX: c_int = 2; +pub const ESI: c_int = 3; +pub const EDI: c_int = 4; +pub const EBP: c_int = 5; +pub const EAX: c_int = 6; +pub const DS: c_int = 7; +pub const ES: c_int = 8; +pub const FS: c_int = 9; +pub const GS: c_int = 10; +pub const ORIG_EAX: c_int = 11; +pub const EIP: c_int = 12; +pub const CS: c_int = 13; +pub const EFL: c_int = 14; +pub const UESP: c_int = 15; +pub const SS: c_int = 16; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_GS: c_int = 0; +pub const REG_FS: c_int = 1; +pub const REG_ES: c_int = 2; +pub const REG_DS: c_int = 3; +pub const REG_EDI: c_int = 4; +pub const REG_ESI: c_int = 5; +pub const REG_EBP: c_int = 6; +pub const REG_ESP: c_int = 7; +pub const REG_EBX: c_int = 8; +pub const REG_EDX: c_int = 9; +pub const REG_ECX: c_int = 10; +pub const REG_EAX: c_int = 11; +pub const REG_TRAPNO: c_int = 12; +pub const REG_ERR: c_int = 13; +pub const REG_EIP: c_int = 14; +pub const REG_CS: c_int = 15; +pub const REG_EFL: c_int = 16; +pub const REG_UESP: c_int = 17; +pub const REG_SS: c_int = 18; + +// From NDK's asm/auxvec.h +pub const AT_SYSINFO: c_ulong = 32; +pub const AT_SYSINFO_EHDR: c_ulong = 33; +pub const AT_VECTOR_SIZE_ARCH: c_ulong = 3; + +// socketcall values from linux/net.h (only the needed ones, and not public) +const SYS_ACCEPT4: c_int = 18; + +f! { + // Sadly, Android before 5.0 (API level 21), the accept4 syscall is not + // exposed by the libc. As work-around, we implement it as raw syscall. + // Note that for x86, the `accept4` syscall is not available either, + // and we must use the `socketcall` syscall instead. + // This workaround can be removed if the minimum Android version is bumped. + // When the workaround is removed, `accept4` can be moved back + // to `linux_like/mod.rs` + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int { + // Arguments are passed as array of `long int` + // (which is big enough on x86 for a pointer). + let mut args = [fd as c_long, addr as c_long, len as c_long, flg as c_long]; + crate::syscall(SYS_socketcall, SYS_ACCEPT4, args[..].as_mut_ptr()) + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b64/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/aarch64/mod.rs new file mode 100644 index 00000000000000..3cc6fc837693e2 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/aarch64/mod.rs @@ -0,0 +1,473 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type wchar_t = u32; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off64_t, + pub st_blksize: c_int, + __pad2: Padding, + pub st_blocks: c_long, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused4: Padding, + __unused5: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off64_t, + pub st_blksize: c_int, + __pad2: Padding, + pub st_blocks: c_long, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused4: Padding, + __unused5: Padding, + } + + pub struct user_regs_struct { + pub regs: [u64; 31], + pub sp: u64, + pub pc: u64, + pub pstate: u64, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub fault_address: c_ulonglong, + pub regs: [c_ulonglong; 31], + pub sp: c_ulonglong, + pub pc: c_ulonglong, + pub pstate: c_ulonglong, + __reserved: Padding<[u64; 512]>, + } + + pub struct user_fpsimd_struct { + pub vregs: [u128; 32], + pub fpsr: u32, + pub fpcr: u32, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f32; 8], + } +} + +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_LARGEFILE: c_int = 0o400000; + +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 5120; + +// From NDK's asm/hwcap.h +pub const HWCAP_FP: c_ulong = 1 << 0; +pub const HWCAP_ASIMD: c_ulong = 1 << 1; +pub const HWCAP_EVTSTRM: c_ulong = 1 << 2; +pub const HWCAP_AES: c_ulong = 1 << 3; +pub const HWCAP_PMULL: c_ulong = 1 << 4; +pub const HWCAP_SHA1: c_ulong = 1 << 5; +pub const HWCAP_SHA2: c_ulong = 1 << 6; +pub const HWCAP_CRC32: c_ulong = 1 << 7; +pub const HWCAP_ATOMICS: c_ulong = 1 << 8; +pub const HWCAP_FPHP: c_ulong = 1 << 9; +pub const HWCAP_ASIMDHP: c_ulong = 1 << 10; +pub const HWCAP_CPUID: c_ulong = 1 << 11; +pub const HWCAP_ASIMDRDM: c_ulong = 1 << 12; +pub const HWCAP_JSCVT: c_ulong = 1 << 13; +pub const HWCAP_FCMA: c_ulong = 1 << 14; +pub const HWCAP_LRCPC: c_ulong = 1 << 15; +pub const HWCAP_DCPOP: c_ulong = 1 << 16; +pub const HWCAP_SHA3: c_ulong = 1 << 17; +pub const HWCAP_SM3: c_ulong = 1 << 18; +pub const HWCAP_SM4: c_ulong = 1 << 19; +pub const HWCAP_ASIMDDP: c_ulong = 1 << 20; +pub const HWCAP_SHA512: c_ulong = 1 << 21; +pub const HWCAP_SVE: c_ulong = 1 << 22; +pub const HWCAP_ASIMDFHM: c_ulong = 1 << 23; +pub const HWCAP_DIT: c_ulong = 1 << 24; +pub const HWCAP_USCAT: c_ulong = 1 << 25; +pub const HWCAP_ILRCPC: c_ulong = 1 << 26; +pub const HWCAP_FLAGM: c_ulong = 1 << 27; +pub const HWCAP_SSBS: c_ulong = 1 << 28; +pub const HWCAP_SB: c_ulong = 1 << 29; +pub const HWCAP_PACA: c_ulong = 1 << 30; +pub const HWCAP_PACG: c_ulong = 1 << 31; +pub const HWCAP2_DCPODP: c_ulong = 1 << 0; +pub const HWCAP2_SVE2: c_ulong = 1 << 1; +pub const HWCAP2_SVEAES: c_ulong = 1 << 2; +pub const HWCAP2_SVEPMULL: c_ulong = 1 << 3; +pub const HWCAP2_SVEBITPERM: c_ulong = 1 << 4; +pub const HWCAP2_SVESHA3: c_ulong = 1 << 5; +pub const HWCAP2_SVESM4: c_ulong = 1 << 6; +pub const HWCAP2_FLAGM2: c_ulong = 1 << 7; +pub const HWCAP2_FRINT: c_ulong = 1 << 8; +pub const HWCAP2_SVEI8MM: c_ulong = 1 << 9; +pub const HWCAP2_SVEF32MM: c_ulong = 1 << 10; +pub const HWCAP2_SVEF64MM: c_ulong = 1 << 11; +pub const HWCAP2_SVEBF16: c_ulong = 1 << 12; +pub const HWCAP2_I8MM: c_ulong = 1 << 13; +pub const HWCAP2_BF16: c_ulong = 1 << 14; +pub const HWCAP2_DGH: c_ulong = 1 << 15; +pub const HWCAP2_RNG: c_ulong = 1 << 16; +pub const HWCAP2_BTI: c_ulong = 1 << 17; +pub const HWCAP2_MTE: c_ulong = 1 << 18; +pub const HWCAP2_ECV: c_ulong = 1 << 19; +pub const HWCAP2_AFP: c_ulong = 1 << 20; +pub const HWCAP2_RPRES: c_ulong = 1 << 21; +pub const HWCAP2_MTE3: c_ulong = 1 << 22; +pub const HWCAP2_SME: c_ulong = 1 << 23; +pub const HWCAP2_SME_I16I64: c_ulong = 1 << 24; +pub const HWCAP2_SME_F64F64: c_ulong = 1 << 25; +pub const HWCAP2_SME_I8I32: c_ulong = 1 << 26; +pub const HWCAP2_SME_F16F32: c_ulong = 1 << 27; +pub const HWCAP2_SME_B16F32: c_ulong = 1 << 28; +pub const HWCAP2_SME_F32F32: c_ulong = 1 << 29; +pub const HWCAP2_SME_FA64: c_ulong = 1 << 30; +pub const HWCAP2_WFXT: c_ulong = 1 << 31; +pub const HWCAP2_EBF16: c_ulong = 1 << 32; +pub const HWCAP2_SVE_EBF16: c_ulong = 1 << 33; + +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_fcntl: c_long = 25; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +pub const SYS_renameat: c_long = 38; +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_lseek: c_long = 62; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_mmap: c_long = 222; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_arch_specific_syscall: c_long = 244; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_syscalls: c_long = 451; + +pub const PROT_BTI: c_int = 0x10; +pub const PROT_MTE: c_int = 0x20; + +// From NDK's asm/auxvec.h +pub const AT_SYSINFO_EHDR: c_ulong = 33; +pub const AT_VECTOR_SIZE_ARCH: c_ulong = 2; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/mod.rs new file mode 100644 index 00000000000000..84c35a57f674ad --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/mod.rs @@ -0,0 +1,218 @@ +use crate::prelude::*; + +// The following definitions are correct for aarch64 and x86_64, +// but may be wrong for mips64 + +pub type mode_t = u32; +pub type off64_t = i64; +pub type socklen_t = u32; + +s! { + pub struct sigset_t { + __val: [c_ulong; 1], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_flags: c_int, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_restorer: Option, + } + + pub struct rlimit64 { + pub rlim_cur: c_ulonglong, + pub rlim_max: c_ulonglong, + } + + pub struct pthread_attr_t { + pub flags: u32, + pub stack_base: *mut c_void, + pub stack_size: size_t, + pub guard_size: size_t, + pub sched_policy: i32, + pub sched_priority: i32, + __reserved: Padding<[c_char; 16]>, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct statfs { + pub f_type: u64, + pub f_bsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::__fsid_t, + pub f_namelen: u64, + pub f_frsize: u64, + pub f_flags: u64, + pub f_spare: [u64; 4], + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 0], + } + + pub struct statfs64 { + pub f_type: u64, + pub f_bsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::__fsid_t, + pub f_namelen: u64, + pub f_frsize: u64, + pub f_flags: u64, + pub f_spare: [u64; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_barrier_t { + __private: [i64; 4], + } + + pub struct pthread_spinlock_t { + __private: i64, + } + + pub struct pthread_mutex_t { + value: c_int, + __reserved: Padding<[c_char; 36]>, + } + + pub struct pthread_cond_t { + value: c_int, + __reserved: Padding<[c_char; 44]>, + } + + pub struct pthread_rwlock_t { + numLocks: c_int, + writerThreadId: c_int, + pendingReaders: c_int, + pendingWriters: c_int, + attr: i32, + __reserved: Padding<[c_char; 36]>, + } + + pub struct sigset64_t { + __bits: [c_ulong; 1], + } +} + +// These constants must be of the same type of sigaction.sa_flags +pub const SA_NOCLDSTOP: c_int = 0x00000001; +pub const SA_NOCLDWAIT: c_int = 0x00000002; +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_SIGINFO: c_int = 0x00000004; + +pub const RTLD_GLOBAL: c_int = 0x00100; +pub const RTLD_NOW: c_int = 2; +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + value: 0, + __reserved: Padding::new([0; 36]), +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + value: 0, + __reserved: Padding::new([0; 44]), +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + numLocks: 0, + writerThreadId: 0, + pendingReaders: 0, + pendingWriters: 0, + attr: 0, + __reserved: Padding::new([0; 36]), +}; +pub const PTHREAD_STACK_MIN: size_t = 4096 * 4; +pub const CPU_SETSIZE: size_t = 1024; +pub const __CPU_BITS: size_t = 64; + +pub const UT_LINESIZE: usize = 32; +pub const UT_NAMESIZE: usize = 32; +pub const UT_HOSTSIZE: usize = 256; + +f! { + // Sadly, Android before 5.0 (API level 21), the accept4 syscall is not + // exposed by the libc. As work-around, we implement it through `syscall` + // directly. This workaround can be removed if the minimum version of + // Android is bumped. When the workaround is removed, `accept4` can be + // moved back to `linux_like/mod.rs` + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int { + crate::syscall(SYS_accept4, fd, addr, len, flg) as c_int + } +} + +extern "C" { + pub fn __system_property_wait( + pi: *const crate::prop_info, + __old_serial: u32, + __new_serial_ptr: *mut u32, + __relative_timeout: *const crate::timespec, + ) -> bool; +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b64/riscv64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/riscv64/mod.rs new file mode 100644 index 00000000000000..dded1292b393f9 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/riscv64/mod.rs @@ -0,0 +1,384 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type wchar_t = u32; +pub type greg_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: c_uint, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off64_t, + pub st_blksize: c_int, + __pad2: Padding, + pub st_blocks: c_long, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused4: Padding, + __unused5: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: c_uint, + pub st_nlink: c_uint, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off64_t, + pub st_blksize: c_int, + __pad2: Padding, + pub st_blocks: c_long, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused4: Padding, + __unused5: Padding, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f32; 8], + } +} + +pub const O_DIRECT: c_int = 0x40000; +pub const O_DIRECTORY: c_int = 0x200000; +pub const O_NOFOLLOW: c_int = 0x400000; +pub const O_LARGEFILE: c_int = 0x100000; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +// From NDK's asm/hwcap.h +pub const COMPAT_HWCAP_ISA_I: c_ulong = 1 << (b'I' - b'A'); +pub const COMPAT_HWCAP_ISA_M: c_ulong = 1 << (b'M' - b'A'); +pub const COMPAT_HWCAP_ISA_A: c_ulong = 1 << (b'A' - b'A'); +pub const COMPAT_HWCAP_ISA_F: c_ulong = 1 << (b'F' - b'A'); +pub const COMPAT_HWCAP_ISA_D: c_ulong = 1 << (b'D' - b'A'); +pub const COMPAT_HWCAP_ISA_C: c_ulong = 1 << (b'C' - b'A'); + +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +pub const SYS_renameat: c_long = 38; +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_arch_specific_syscall: c_long = 244; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +// From NDK's asm/auxvec.h +pub const AT_SYSINFO_EHDR: c_ulong = 33; +pub const AT_L1I_CACHESIZE: c_ulong = 40; +pub const AT_L1I_CACHEGEOMETRY: c_ulong = 41; +pub const AT_L1D_CACHESIZE: c_ulong = 42; +pub const AT_L1D_CACHEGEOMETRY: c_ulong = 43; +pub const AT_L2_CACHESIZE: c_ulong = 44; +pub const AT_L2_CACHEGEOMETRY: c_ulong = 45; +pub const AT_L3_CACHESIZE: c_ulong = 46; +pub const AT_L3_CACHEGEOMETRY: c_ulong = 47; +pub const AT_VECTOR_SIZE_ARCH: c_ulong = 9; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/b64/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/x86_64/mod.rs new file mode 100644 index 00000000000000..0f3b74131449ac --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/b64/x86_64/mod.rs @@ -0,0 +1,620 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type greg_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: c_ulong, + pub st_mode: c_uint, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: c_long, + pub st_blocks: c_long, + pub st_atime: c_long, + pub st_atime_nsec: c_long, + pub st_mtime: c_long, + pub st_mtime_nsec: c_long, + pub st_ctime: c_long, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: c_ulong, + pub st_mode: c_uint, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: c_long, + pub st_blocks: c_long, + pub st_atime: c_long, + pub st_atime_nsec: c_long, + pub st_mtime: c_long, + pub st_mtime_nsec: c_long, + pub st_ctime: c_long, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct _libc_xmmreg { + pub element: [u32; 4], + } + + pub struct user_regs_struct { + pub r15: c_ulong, + pub r14: c_ulong, + pub r13: c_ulong, + pub r12: c_ulong, + pub rbp: c_ulong, + pub rbx: c_ulong, + pub r11: c_ulong, + pub r10: c_ulong, + pub r9: c_ulong, + pub r8: c_ulong, + pub rax: c_ulong, + pub rcx: c_ulong, + pub rdx: c_ulong, + pub rsi: c_ulong, + pub rdi: c_ulong, + pub orig_rax: c_ulong, + pub rip: c_ulong, + pub cs: c_ulong, + pub eflags: c_ulong, + pub rsp: c_ulong, + pub ss: c_ulong, + pub fs_base: c_ulong, + pub gs_base: c_ulong, + pub ds: c_ulong, + pub es: c_ulong, + pub fs: c_ulong, + pub gs: c_ulong, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: c_int, + pub i387: user_fpregs_struct, + pub u_tsize: c_ulong, + pub u_dsize: c_ulong, + pub u_ssize: c_ulong, + pub start_code: c_ulong, + pub start_stack: c_ulong, + pub signal: c_long, + __reserved: Padding, + #[cfg(target_pointer_width = "32")] + __pad1: Padding, + pub u_ar0: *mut user_regs_struct, + #[cfg(target_pointer_width = "32")] + __pad2: Padding, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: c_ulong, + pub u_comm: [c_char; 32], + pub u_debugreg: [c_ulong; 8], + pub error_code: c_ulong, + pub fault_address: c_ulong, + } + + pub struct _libc_fpxreg { + pub significand: [u16; 4], + pub exponent: u16, + __padding: Padding<[u16; 3]>, + } + + pub struct _libc_fpstate { + pub cwd: u16, + pub swd: u16, + pub ftw: u16, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcr_mask: u32, + pub _st: [_libc_fpxreg; 8], + pub _xmm: [_libc_xmmreg; 16], + __private: [u32; 24], + } + + pub struct mcontext_t { + pub gregs: [greg_t; 23], + pub fpregs: *mut _libc_fpstate, + __private: [u64; 8], + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask64: __c_anonymous_uc_sigmask, + __fpregs_mem: _libc_fpstate, + } + + pub struct user_fpregs_struct { + pub cwd: c_ushort, + pub swd: c_ushort, + pub ftw: c_ushort, + pub fop: c_ushort, + pub rip: c_ulong, + pub rdp: c_ulong, + pub mxcsr: c_uint, + pub mxcr_mask: c_uint, + pub st_space: [c_uint; 32], + pub xmm_space: [c_uint; 64], + padding: Padding<[c_uint; 24]>, + } +} + +s_no_extra_traits! { + pub union __c_anonymous_uc_sigmask { + uc_sigmask: crate::sigset_t, + uc_sigmask64: crate::sigset64_t, + } + + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_uc_sigmask { + fn eq(&self, other: &__c_anonymous_uc_sigmask) -> bool { + unsafe { self.uc_sigmask == other.uc_sigmask } + } + } + impl Eq for __c_anonymous_uc_sigmask {} + impl hash::Hash for __c_anonymous_uc_sigmask { + fn hash(&self, state: &mut H) { + unsafe { self.uc_sigmask.hash(state) } + } + } + } +} + +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_LARGEFILE: c_int = 0o0100000; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const MAP_32BIT: c_int = 0x40; + +// Syscall table + +pub const SYS_read: c_long = 0; +pub const SYS_write: c_long = 1; +pub const SYS_open: c_long = 2; +pub const SYS_close: c_long = 3; +pub const SYS_stat: c_long = 4; +pub const SYS_fstat: c_long = 5; +pub const SYS_lstat: c_long = 6; +pub const SYS_poll: c_long = 7; +pub const SYS_lseek: c_long = 8; +pub const SYS_mmap: c_long = 9; +pub const SYS_mprotect: c_long = 10; +pub const SYS_munmap: c_long = 11; +pub const SYS_brk: c_long = 12; +pub const SYS_rt_sigaction: c_long = 13; +pub const SYS_rt_sigprocmask: c_long = 14; +pub const SYS_rt_sigreturn: c_long = 15; +pub const SYS_ioctl: c_long = 16; +pub const SYS_pread64: c_long = 17; +pub const SYS_pwrite64: c_long = 18; +pub const SYS_readv: c_long = 19; +pub const SYS_writev: c_long = 20; +pub const SYS_access: c_long = 21; +pub const SYS_pipe: c_long = 22; +pub const SYS_select: c_long = 23; +pub const SYS_sched_yield: c_long = 24; +pub const SYS_mremap: c_long = 25; +pub const SYS_msync: c_long = 26; +pub const SYS_mincore: c_long = 27; +pub const SYS_madvise: c_long = 28; +pub const SYS_shmget: c_long = 29; +pub const SYS_shmat: c_long = 30; +pub const SYS_shmctl: c_long = 31; +pub const SYS_dup: c_long = 32; +pub const SYS_dup2: c_long = 33; +pub const SYS_pause: c_long = 34; +pub const SYS_nanosleep: c_long = 35; +pub const SYS_getitimer: c_long = 36; +pub const SYS_alarm: c_long = 37; +pub const SYS_setitimer: c_long = 38; +pub const SYS_getpid: c_long = 39; +pub const SYS_sendfile: c_long = 40; +pub const SYS_socket: c_long = 41; +pub const SYS_connect: c_long = 42; +pub const SYS_accept: c_long = 43; +pub const SYS_sendto: c_long = 44; +pub const SYS_recvfrom: c_long = 45; +pub const SYS_sendmsg: c_long = 46; +pub const SYS_recvmsg: c_long = 47; +pub const SYS_shutdown: c_long = 48; +pub const SYS_bind: c_long = 49; +pub const SYS_listen: c_long = 50; +pub const SYS_getsockname: c_long = 51; +pub const SYS_getpeername: c_long = 52; +pub const SYS_socketpair: c_long = 53; +pub const SYS_setsockopt: c_long = 54; +pub const SYS_getsockopt: c_long = 55; +pub const SYS_clone: c_long = 56; +pub const SYS_fork: c_long = 57; +pub const SYS_vfork: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_exit: c_long = 60; +pub const SYS_wait4: c_long = 61; +pub const SYS_kill: c_long = 62; +pub const SYS_uname: c_long = 63; +pub const SYS_semget: c_long = 64; +pub const SYS_semop: c_long = 65; +pub const SYS_semctl: c_long = 66; +pub const SYS_shmdt: c_long = 67; +pub const SYS_msgget: c_long = 68; +pub const SYS_msgsnd: c_long = 69; +pub const SYS_msgrcv: c_long = 70; +pub const SYS_msgctl: c_long = 71; +pub const SYS_fcntl: c_long = 72; +pub const SYS_flock: c_long = 73; +pub const SYS_fsync: c_long = 74; +pub const SYS_fdatasync: c_long = 75; +pub const SYS_truncate: c_long = 76; +pub const SYS_ftruncate: c_long = 77; +pub const SYS_getdents: c_long = 78; +pub const SYS_getcwd: c_long = 79; +pub const SYS_chdir: c_long = 80; +pub const SYS_fchdir: c_long = 81; +pub const SYS_rename: c_long = 82; +pub const SYS_mkdir: c_long = 83; +pub const SYS_rmdir: c_long = 84; +pub const SYS_creat: c_long = 85; +pub const SYS_link: c_long = 86; +pub const SYS_unlink: c_long = 87; +pub const SYS_symlink: c_long = 88; +pub const SYS_readlink: c_long = 89; +pub const SYS_chmod: c_long = 90; +pub const SYS_fchmod: c_long = 91; +pub const SYS_chown: c_long = 92; +pub const SYS_fchown: c_long = 93; +pub const SYS_lchown: c_long = 94; +pub const SYS_umask: c_long = 95; +pub const SYS_gettimeofday: c_long = 96; +pub const SYS_getrlimit: c_long = 97; +pub const SYS_getrusage: c_long = 98; +pub const SYS_sysinfo: c_long = 99; +pub const SYS_times: c_long = 100; +pub const SYS_ptrace: c_long = 101; +pub const SYS_getuid: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_getgid: c_long = 104; +pub const SYS_setuid: c_long = 105; +pub const SYS_setgid: c_long = 106; +pub const SYS_geteuid: c_long = 107; +pub const SYS_getegid: c_long = 108; +pub const SYS_setpgid: c_long = 109; +pub const SYS_getppid: c_long = 110; +pub const SYS_getpgrp: c_long = 111; +pub const SYS_setsid: c_long = 112; +pub const SYS_setreuid: c_long = 113; +pub const SYS_setregid: c_long = 114; +pub const SYS_getgroups: c_long = 115; +pub const SYS_setgroups: c_long = 116; +pub const SYS_setresuid: c_long = 117; +pub const SYS_getresuid: c_long = 118; +pub const SYS_setresgid: c_long = 119; +pub const SYS_getresgid: c_long = 120; +pub const SYS_getpgid: c_long = 121; +pub const SYS_setfsuid: c_long = 122; +pub const SYS_setfsgid: c_long = 123; +pub const SYS_getsid: c_long = 124; +pub const SYS_capget: c_long = 125; +pub const SYS_capset: c_long = 126; +pub const SYS_rt_sigpending: c_long = 127; +pub const SYS_rt_sigtimedwait: c_long = 128; +pub const SYS_rt_sigqueueinfo: c_long = 129; +pub const SYS_rt_sigsuspend: c_long = 130; +pub const SYS_sigaltstack: c_long = 131; +pub const SYS_utime: c_long = 132; +pub const SYS_mknod: c_long = 133; +pub const SYS_uselib: c_long = 134; +pub const SYS_personality: c_long = 135; +pub const SYS_ustat: c_long = 136; +pub const SYS_statfs: c_long = 137; +pub const SYS_fstatfs: c_long = 138; +pub const SYS_sysfs: c_long = 139; +pub const SYS_getpriority: c_long = 140; +pub const SYS_setpriority: c_long = 141; +pub const SYS_sched_setparam: c_long = 142; +pub const SYS_sched_getparam: c_long = 143; +pub const SYS_sched_setscheduler: c_long = 144; +pub const SYS_sched_getscheduler: c_long = 145; +pub const SYS_sched_get_priority_max: c_long = 146; +pub const SYS_sched_get_priority_min: c_long = 147; +pub const SYS_sched_rr_get_interval: c_long = 148; +pub const SYS_mlock: c_long = 149; +pub const SYS_munlock: c_long = 150; +pub const SYS_mlockall: c_long = 151; +pub const SYS_munlockall: c_long = 152; +pub const SYS_vhangup: c_long = 153; +pub const SYS_modify_ldt: c_long = 154; +pub const SYS_pivot_root: c_long = 155; +// FIXME(android): SYS__sysctl is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__sysctl: c_long = 156; +pub const SYS_prctl: c_long = 157; +pub const SYS_arch_prctl: c_long = 158; +pub const SYS_adjtimex: c_long = 159; +pub const SYS_setrlimit: c_long = 160; +pub const SYS_chroot: c_long = 161; +pub const SYS_sync: c_long = 162; +pub const SYS_acct: c_long = 163; +pub const SYS_settimeofday: c_long = 164; +pub const SYS_mount: c_long = 165; +pub const SYS_umount2: c_long = 166; +pub const SYS_swapon: c_long = 167; +pub const SYS_swapoff: c_long = 168; +pub const SYS_reboot: c_long = 169; +pub const SYS_sethostname: c_long = 170; +pub const SYS_setdomainname: c_long = 171; +pub const SYS_iopl: c_long = 172; +pub const SYS_ioperm: c_long = 173; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 174; +pub const SYS_init_module: c_long = 175; +pub const SYS_delete_module: c_long = 176; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 177; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 178; +pub const SYS_quotactl: c_long = 179; +pub const SYS_nfsservctl: c_long = 180; +pub const SYS_getpmsg: c_long = 181; +pub const SYS_putpmsg: c_long = 182; +pub const SYS_afs_syscall: c_long = 183; +pub const SYS_tuxcall: c_long = 184; +pub const SYS_security: c_long = 185; +pub const SYS_gettid: c_long = 186; +pub const SYS_readahead: c_long = 187; +pub const SYS_setxattr: c_long = 188; +pub const SYS_lsetxattr: c_long = 189; +pub const SYS_fsetxattr: c_long = 190; +pub const SYS_getxattr: c_long = 191; +pub const SYS_lgetxattr: c_long = 192; +pub const SYS_fgetxattr: c_long = 193; +pub const SYS_listxattr: c_long = 194; +pub const SYS_llistxattr: c_long = 195; +pub const SYS_flistxattr: c_long = 196; +pub const SYS_removexattr: c_long = 197; +pub const SYS_lremovexattr: c_long = 198; +pub const SYS_fremovexattr: c_long = 199; +pub const SYS_tkill: c_long = 200; +pub const SYS_time: c_long = 201; +pub const SYS_futex: c_long = 202; +pub const SYS_sched_setaffinity: c_long = 203; +pub const SYS_sched_getaffinity: c_long = 204; +pub const SYS_set_thread_area: c_long = 205; +pub const SYS_io_setup: c_long = 206; +pub const SYS_io_destroy: c_long = 207; +pub const SYS_io_getevents: c_long = 208; +pub const SYS_io_submit: c_long = 209; +pub const SYS_io_cancel: c_long = 210; +pub const SYS_get_thread_area: c_long = 211; +pub const SYS_lookup_dcookie: c_long = 212; +pub const SYS_epoll_create: c_long = 213; +pub const SYS_epoll_ctl_old: c_long = 214; +pub const SYS_epoll_wait_old: c_long = 215; +pub const SYS_remap_file_pages: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_set_tid_address: c_long = 218; +pub const SYS_restart_syscall: c_long = 219; +pub const SYS_semtimedop: c_long = 220; +pub const SYS_fadvise64: c_long = 221; +pub const SYS_timer_create: c_long = 222; +pub const SYS_timer_settime: c_long = 223; +pub const SYS_timer_gettime: c_long = 224; +pub const SYS_timer_getoverrun: c_long = 225; +pub const SYS_timer_delete: c_long = 226; +pub const SYS_clock_settime: c_long = 227; +pub const SYS_clock_gettime: c_long = 228; +pub const SYS_clock_getres: c_long = 229; +pub const SYS_clock_nanosleep: c_long = 230; +pub const SYS_exit_group: c_long = 231; +pub const SYS_epoll_wait: c_long = 232; +pub const SYS_epoll_ctl: c_long = 233; +pub const SYS_tgkill: c_long = 234; +pub const SYS_utimes: c_long = 235; +pub const SYS_vserver: c_long = 236; +pub const SYS_mbind: c_long = 237; +pub const SYS_set_mempolicy: c_long = 238; +pub const SYS_get_mempolicy: c_long = 239; +pub const SYS_mq_open: c_long = 240; +pub const SYS_mq_unlink: c_long = 241; +pub const SYS_mq_timedsend: c_long = 242; +pub const SYS_mq_timedreceive: c_long = 243; +pub const SYS_mq_notify: c_long = 244; +pub const SYS_mq_getsetattr: c_long = 245; +pub const SYS_kexec_load: c_long = 246; +pub const SYS_waitid: c_long = 247; +pub const SYS_add_key: c_long = 248; +pub const SYS_request_key: c_long = 249; +pub const SYS_keyctl: c_long = 250; +pub const SYS_ioprio_set: c_long = 251; +pub const SYS_ioprio_get: c_long = 252; +pub const SYS_inotify_init: c_long = 253; +pub const SYS_inotify_add_watch: c_long = 254; +pub const SYS_inotify_rm_watch: c_long = 255; +pub const SYS_migrate_pages: c_long = 256; +pub const SYS_openat: c_long = 257; +pub const SYS_mkdirat: c_long = 258; +pub const SYS_mknodat: c_long = 259; +pub const SYS_fchownat: c_long = 260; +pub const SYS_futimesat: c_long = 261; +pub const SYS_newfstatat: c_long = 262; +pub const SYS_unlinkat: c_long = 263; +pub const SYS_renameat: c_long = 264; +pub const SYS_linkat: c_long = 265; +pub const SYS_symlinkat: c_long = 266; +pub const SYS_readlinkat: c_long = 267; +pub const SYS_fchmodat: c_long = 268; +pub const SYS_faccessat: c_long = 269; +pub const SYS_pselect6: c_long = 270; +pub const SYS_ppoll: c_long = 271; +pub const SYS_unshare: c_long = 272; +pub const SYS_set_robust_list: c_long = 273; +pub const SYS_get_robust_list: c_long = 274; +pub const SYS_splice: c_long = 275; +pub const SYS_tee: c_long = 276; +pub const SYS_sync_file_range: c_long = 277; +pub const SYS_vmsplice: c_long = 278; +pub const SYS_move_pages: c_long = 279; +pub const SYS_utimensat: c_long = 280; +pub const SYS_epoll_pwait: c_long = 281; +pub const SYS_signalfd: c_long = 282; +pub const SYS_timerfd_create: c_long = 283; +pub const SYS_eventfd: c_long = 284; +pub const SYS_fallocate: c_long = 285; +pub const SYS_timerfd_settime: c_long = 286; +pub const SYS_timerfd_gettime: c_long = 287; +pub const SYS_accept4: c_long = 288; +pub const SYS_signalfd4: c_long = 289; +pub const SYS_eventfd2: c_long = 290; +pub const SYS_epoll_create1: c_long = 291; +pub const SYS_dup3: c_long = 292; +pub const SYS_pipe2: c_long = 293; +pub const SYS_inotify_init1: c_long = 294; +pub const SYS_preadv: c_long = 295; +pub const SYS_pwritev: c_long = 296; +pub const SYS_rt_tgsigqueueinfo: c_long = 297; +pub const SYS_perf_event_open: c_long = 298; +pub const SYS_recvmmsg: c_long = 299; +pub const SYS_fanotify_init: c_long = 300; +pub const SYS_fanotify_mark: c_long = 301; +pub const SYS_prlimit64: c_long = 302; +pub const SYS_name_to_handle_at: c_long = 303; +pub const SYS_open_by_handle_at: c_long = 304; +pub const SYS_clock_adjtime: c_long = 305; +pub const SYS_syncfs: c_long = 306; +pub const SYS_sendmmsg: c_long = 307; +pub const SYS_setns: c_long = 308; +pub const SYS_getcpu: c_long = 309; +pub const SYS_process_vm_readv: c_long = 310; +pub const SYS_process_vm_writev: c_long = 311; +pub const SYS_kcmp: c_long = 312; +pub const SYS_finit_module: c_long = 313; +pub const SYS_sched_setattr: c_long = 314; +pub const SYS_sched_getattr: c_long = 315; +pub const SYS_renameat2: c_long = 316; +pub const SYS_seccomp: c_long = 317; +pub const SYS_getrandom: c_long = 318; +pub const SYS_memfd_create: c_long = 319; +pub const SYS_kexec_file_load: c_long = 320; +pub const SYS_bpf: c_long = 321; +pub const SYS_execveat: c_long = 322; +pub const SYS_userfaultfd: c_long = 323; +pub const SYS_membarrier: c_long = 324; +pub const SYS_mlock2: c_long = 325; +pub const SYS_copy_file_range: c_long = 326; +pub const SYS_preadv2: c_long = 327; +pub const SYS_pwritev2: c_long = 328; +pub const SYS_pkey_mprotect: c_long = 329; +pub const SYS_pkey_alloc: c_long = 330; +pub const SYS_pkey_free: c_long = 331; +pub const SYS_statx: c_long = 332; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: c_int = 0; +pub const R14: c_int = 1; +pub const R13: c_int = 2; +pub const R12: c_int = 3; +pub const RBP: c_int = 4; +pub const RBX: c_int = 5; +pub const R11: c_int = 6; +pub const R10: c_int = 7; +pub const R9: c_int = 8; +pub const R8: c_int = 9; +pub const RAX: c_int = 10; +pub const RCX: c_int = 11; +pub const RDX: c_int = 12; +pub const RSI: c_int = 13; +pub const RDI: c_int = 14; +pub const ORIG_RAX: c_int = 15; +pub const RIP: c_int = 16; +pub const CS: c_int = 17; +pub const EFLAGS: c_int = 18; +pub const RSP: c_int = 19; +pub const SS: c_int = 20; +pub const FS_BASE: c_int = 21; +pub const GS_BASE: c_int = 22; +pub const DS: c_int = 23; +pub const ES: c_int = 24; +pub const FS: c_int = 25; +pub const GS: c_int = 26; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_R8: c_int = 0; +pub const REG_R9: c_int = 1; +pub const REG_R10: c_int = 2; +pub const REG_R11: c_int = 3; +pub const REG_R12: c_int = 4; +pub const REG_R13: c_int = 5; +pub const REG_R14: c_int = 6; +pub const REG_R15: c_int = 7; +pub const REG_RDI: c_int = 8; +pub const REG_RSI: c_int = 9; +pub const REG_RBP: c_int = 10; +pub const REG_RBX: c_int = 11; +pub const REG_RDX: c_int = 12; +pub const REG_RAX: c_int = 13; +pub const REG_RCX: c_int = 14; +pub const REG_RSP: c_int = 15; +pub const REG_RIP: c_int = 16; +pub const REG_EFL: c_int = 17; +pub const REG_CSGSFS: c_int = 18; +pub const REG_ERR: c_int = 19; +pub const REG_TRAPNO: c_int = 20; +pub const REG_OLDMASK: c_int = 21; +pub const REG_CR2: c_int = 22; + +// From NDK's asm/auxvec.h +pub const AT_SYSINFO_EHDR: c_ulong = 33; +pub const AT_VECTOR_SIZE_ARCH: c_ulong = 3; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/android/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/android/mod.rs new file mode 100644 index 00000000000000..31d1dba3ecf1b2 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/android/mod.rs @@ -0,0 +1,3832 @@ +//! Android-specific definitions for linux-like values + +use crate::prelude::*; +use crate::{ + cmsghdr, + msghdr, +}; + +cfg_if! { + if #[cfg(doc)] { + pub(crate) type Ioctl = c_int; + } else { + #[doc(hidden)] + pub type Ioctl = c_int; + } +} + +pub type clock_t = c_long; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type off_t = c_long; +pub type blkcnt_t = c_ulong; +pub type blksize_t = c_ulong; +pub type nlink_t = u32; +pub type pthread_t = c_long; +pub type pthread_mutexattr_t = c_long; +pub type pthread_rwlockattr_t = c_long; +pub type pthread_barrierattr_t = c_int; +pub type pthread_condattr_t = c_long; +pub type pthread_key_t = c_int; +pub type fsfilcnt_t = c_ulong; +pub type fsblkcnt_t = c_ulong; +pub type nfds_t = c_uint; +pub type rlim_t = c_ulong; +pub type dev_t = c_ulong; +pub type ino_t = c_ulong; +pub type ino64_t = u64; +pub type __CPU_BITTYPE = c_ulong; +pub type idtype_t = c_int; +pub type loff_t = c_longlong; +pub type __kernel_loff_t = c_longlong; +pub type __kernel_pid_t = c_int; + +pub type __u8 = c_uchar; +pub type __u16 = c_ushort; +pub type __s16 = c_short; +pub type __u32 = c_uint; +pub type __s32 = c_int; +pub type __be16 = __u16; + +// linux/elf.h + +pub type Elf32_Addr = u32; +pub type Elf32_Half = u16; +pub type Elf32_Off = u32; +pub type Elf32_Word = u32; + +pub type Elf64_Addr = u64; +pub type Elf64_Half = u16; +pub type Elf64_Off = u64; +pub type Elf64_Word = u32; +pub type Elf64_Xword = u64; + +pub type eventfd_t = u64; + +// these structs sit behind a heap allocation on Android +pub type posix_spawn_file_actions_t = *mut c_void; +pub type posix_spawnattr_t = *mut c_void; + +s! { + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct __fsid_t { + __val: [c_int; 2], + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct termios2 { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; 19], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct mallinfo { + pub arena: size_t, + pub ordblks: size_t, + pub smblks: size_t, + pub hblks: size_t, + pub hblkhd: size_t, + pub usmblks: size_t, + pub fsmblks: size_t, + pub uordblks: size_t, + pub fordblks: size_t, + pub keepcost: size_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: crate::__kernel_loff_t, + pub l_len: crate::__kernel_loff_t, + pub l_pid: crate::__kernel_pid_t, + } + + pub struct cpu_set_t { + #[cfg(target_pointer_width = "64")] + __bits: [__CPU_BITTYPE; 16], + #[cfg(target_pointer_width = "32")] + __bits: [__CPU_BITTYPE; 1], + } + + pub struct sem_t { + count: c_uint, + #[cfg(target_pointer_width = "64")] + __reserved: Padding<[c_int; 3]>, + } + + pub struct exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + #[cfg(target_pointer_width = "64")] + __f_reserved: Padding<[u32; 6]>, + } + + pub struct signalfd_siginfo { + pub ssi_signo: u32, + pub ssi_errno: i32, + pub ssi_code: i32, + pub ssi_pid: u32, + pub ssi_uid: u32, + pub ssi_fd: i32, + pub ssi_tid: u32, + pub ssi_band: u32, + pub ssi_overrun: u32, + pub ssi_trapno: u32, + pub ssi_status: i32, + pub ssi_int: i32, + pub ssi_ptr: c_ulonglong, + pub ssi_utime: c_ulonglong, + pub ssi_stime: c_ulonglong, + pub ssi_addr: c_ulonglong, + pub ssi_addr_lsb: u16, + _pad2: Padding, + pub ssi_syscall: i32, + pub ssi_call_addr: u64, + pub ssi_arch: u32, + _pad: Padding<[u8; 28]>, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct genlmsghdr { + pub cmd: u8, + pub version: u8, + pub reserved: u16, + } + + pub struct nlmsghdr { + pub nlmsg_len: u32, + pub nlmsg_type: u16, + pub nlmsg_flags: u16, + pub nlmsg_seq: u32, + pub nlmsg_pid: u32, + } + + pub struct nlmsgerr { + pub error: c_int, + pub msg: nlmsghdr, + } + + pub struct nl_pktinfo { + pub group: u32, + } + + pub struct nl_mmap_req { + pub nm_block_size: c_uint, + pub nm_block_nr: c_uint, + pub nm_frame_size: c_uint, + pub nm_frame_nr: c_uint, + } + + pub struct nl_mmap_hdr { + pub nm_status: c_uint, + pub nm_len: c_uint, + pub nm_group: u32, + pub nm_pid: u32, + pub nm_uid: u32, + pub nm_gid: u32, + } + + pub struct nlattr { + pub nla_len: u16, + pub nla_type: u16, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_int, + } + + pub struct inotify_event { + pub wd: c_int, + pub mask: u32, + pub cookie: u32, + pub len: u32, + } + + pub struct sock_extended_err { + pub ee_errno: u32, + pub ee_origin: u8, + pub ee_type: u8, + pub ee_code: u8, + pub ee_pad: u8, + pub ee_info: u32, + pub ee_data: u32, + } + + pub struct regex_t { + re_magic: c_int, + re_nsub: size_t, + re_endp: *const c_char, + re_guts: *mut c_void, + } + + pub struct regmatch_t { + pub rm_so: ssize_t, + pub rm_eo: ssize_t, + } + + pub struct sockaddr_vm { + pub svm_family: crate::sa_family_t, + pub svm_reserved1: c_ushort, + pub svm_port: c_uint, + pub svm_cid: c_uint, + pub svm_zero: [u8; 4], + } + + // linux/elf.h + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + // link.h + + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + // These fields were added in Android R + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: size_t, + pub dlpi_tls_data: *mut c_void, + } + + // linux/seccomp.h + pub struct seccomp_data { + pub nr: c_int, + pub arch: crate::__u32, + pub instruction_pointer: crate::__u64, + pub args: [crate::__u64; 6], + } + + pub struct seccomp_metadata { + pub filter_off: crate::__u64, + pub flags: crate::__u64, + } + + pub struct ptrace_peeksiginfo_args { + pub off: crate::__u64, + pub flags: crate::__u32, + pub nr: crate::__s32, + } + + // linux/input.h + pub struct input_event { + pub time: crate::timeval, + pub type_: crate::__u16, + pub code: crate::__u16, + pub value: crate::__s32, + } + + pub struct input_id { + pub bustype: crate::__u16, + pub vendor: crate::__u16, + pub product: crate::__u16, + pub version: crate::__u16, + } + + pub struct input_absinfo { + pub value: crate::__s32, + pub minimum: crate::__s32, + pub maximum: crate::__s32, + pub fuzz: crate::__s32, + pub flat: crate::__s32, + pub resolution: crate::__s32, + } + + pub struct input_keymap_entry { + pub flags: crate::__u8, + pub len: crate::__u8, + pub index: crate::__u16, + pub keycode: crate::__u32, + pub scancode: [crate::__u8; 32], + } + + pub struct input_mask { + pub type_: crate::__u32, + pub codes_size: crate::__u32, + pub codes_ptr: crate::__u64, + } + + pub struct ff_replay { + pub length: crate::__u16, + pub delay: crate::__u16, + } + + pub struct ff_trigger { + pub button: crate::__u16, + pub interval: crate::__u16, + } + + pub struct ff_envelope { + pub attack_length: crate::__u16, + pub attack_level: crate::__u16, + pub fade_length: crate::__u16, + pub fade_level: crate::__u16, + } + + pub struct ff_constant_effect { + pub level: crate::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_ramp_effect { + pub start_level: crate::__s16, + pub end_level: crate::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_condition_effect { + pub right_saturation: crate::__u16, + pub left_saturation: crate::__u16, + + pub right_coeff: crate::__s16, + pub left_coeff: crate::__s16, + + pub deadband: crate::__u16, + pub center: crate::__s16, + } + + pub struct ff_periodic_effect { + pub waveform: crate::__u16, + pub period: crate::__u16, + pub magnitude: crate::__s16, + pub offset: crate::__s16, + pub phase: crate::__u16, + + pub envelope: ff_envelope, + + pub custom_len: crate::__u32, + pub custom_data: *mut crate::__s16, + } + + pub struct ff_rumble_effect { + pub strong_magnitude: crate::__u16, + pub weak_magnitude: crate::__u16, + } + + pub struct ff_effect { + pub type_: crate::__u16, + pub id: crate::__s16, + pub direction: crate::__u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + // FIXME(1.0): this is actually a union + #[cfg(target_pointer_width = "64")] + pub u: [u64; 4], + #[cfg(target_pointer_width = "32")] + pub u: [u32; 7], + } + + // linux/uinput.h + pub struct uinput_ff_upload { + pub request_id: crate::__u32, + pub retval: crate::__s32, + pub effect: ff_effect, + pub old: ff_effect, + } + + pub struct uinput_ff_erase { + pub request_id: crate::__u32, + pub retval: crate::__s32, + pub effect_id: crate::__u32, + } + + pub struct uinput_abs_setup { + pub code: crate::__u16, + pub absinfo: input_absinfo, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + + pub struct __c_anonymous_ifru_map { + pub mem_start: c_ulong, + pub mem_end: c_ulong, + pub base_addr: c_ushort, + pub irq: c_uchar, + pub dma: c_uchar, + pub port: c_uchar, + } + + pub struct in6_ifreq { + pub ifr6_addr: crate::in6_addr, + pub ifr6_prefixlen: u32, + pub ifr6_ifindex: c_int, + } + + pub struct sockaddr_nl { + pub nl_family: crate::sa_family_t, + nl_pad: Padding, + pub nl_pid: u32, + pub nl_groups: u32, + } + + pub struct dirent { + pub d_ino: u64, + pub d_off: i64, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct dirent64 { + pub d_ino: u64, + pub d_off: i64, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct lastlog { + ll_time: crate::time_t, + ll_line: [c_char; UT_LINESIZE], + ll_host: [c_char; UT_HOSTSIZE], + } + + pub struct utmp { + pub ut_type: c_short, + pub ut_pid: crate::pid_t, + pub ut_line: [c_char; UT_LINESIZE], + pub ut_id: [c_char; 4], + pub ut_user: [c_char; UT_NAMESIZE], + pub ut_host: [c_char; UT_HOSTSIZE], + pub ut_exit: exit_status, + pub ut_session: c_long, + pub ut_tv: crate::timeval, + pub ut_addr_v6: [i32; 4], + unused: Padding<[c_char; 20]>, + } + + pub struct sockaddr_alg { + pub salg_family: crate::sa_family_t, + pub salg_type: [c_uchar; 14], + pub salg_feat: u32, + pub salg_mask: u32, + pub salg_name: [c_uchar; 64], + } + + pub struct uinput_setup { + pub id: input_id, + pub name: [c_char; UINPUT_MAX_NAME_SIZE], + pub ff_effects_max: crate::__u32, + } + + pub struct uinput_user_dev { + pub name: [c_char; UINPUT_MAX_NAME_SIZE], + pub id: input_id, + pub ff_effects_max: crate::__u32, + pub absmax: [crate::__s32; ABS_CNT], + pub absmin: [crate::__s32; ABS_CNT], + pub absfuzz: [crate::__s32; ABS_CNT], + pub absflat: [crate::__s32; ABS_CNT], + } + + pub struct prop_info { + __name: [c_char; 32], + __serial: c_uint, + __value: [c_char; 92], + } +} + +s_no_extra_traits! { + /// WARNING: The `PartialEq`, `Eq` and `Hash` implementations of this + /// type are unsound and will be removed in the future. + #[deprecated( + note = "this struct has unsafe trait implementations that will be \ + removed in the future", + since = "0.2.80" + )] + pub struct af_alg_iv { + pub ivlen: u32, + pub iv: [c_uchar; 0], + } + + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_netmask: crate::sockaddr, + pub ifru_hwaddr: crate::sockaddr, + pub ifru_flags: c_short, + pub ifru_ifindex: c_int, + pub ifru_metric: c_int, + pub ifru_mtu: c_int, + pub ifru_map: __c_anonymous_ifru_map, + pub ifru_slave: [c_char; crate::IFNAMSIZ], + pub ifru_newname: [c_char; crate::IFNAMSIZ], + pub ifru_data: *mut c_char, + } + + pub struct ifreq { + /// interface name, e.g. "en0" + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: *mut c_char, + pub ifcu_req: *mut crate::ifreq, + } + + /* Structure used in SIOCGIFCONF request. Used to retrieve interface + configuration for machine (useful for programs which must know all + networks accessible). */ + pub struct ifconf { + pub ifc_len: c_int, /* Size of buffer. */ + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } + + // linux/if_ether.h + + #[repr(C, packed)] + pub struct ethhdr { + pub h_dest: [c_uchar; crate::ETH_ALEN as usize], + pub h_source: [c_uchar; crate::ETH_ALEN as usize], + pub h_proto: crate::__be16, + } + + // Internal, for casts to access union fields + struct sifields_sigchld { + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: c_long, + si_stime: c_long, + } + + // Internal, for casts to access union fields + union sifields { + _align_pointer: *mut c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + struct siginfo_f { + _siginfo_base: [c_int; 3], + sifields: sifields, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + #[allow(deprecated)] + impl af_alg_iv { + fn as_slice(&self) -> &[u8] { + unsafe { ::core::slice::from_raw_parts(self.iv.as_ptr(), self.ivlen as usize) } + } + } + + #[allow(deprecated)] + impl PartialEq for af_alg_iv { + fn eq(&self, other: &af_alg_iv) -> bool { + *self.as_slice() == *other.as_slice() + } + } + + #[allow(deprecated)] + impl Eq for af_alg_iv {} + + #[allow(deprecated)] + impl hash::Hash for af_alg_iv { + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } + } + } +} + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MS_NOUSER: c_ulong = 0xffffffff80000000; +pub const MS_RMT_MASK: c_ulong = 0x02800051; + +pub const O_TRUNC: c_int = 512; +pub const O_CLOEXEC: c_int = 0x80000; +pub const O_PATH: c_int = 0o10000000; +pub const O_NOATIME: c_int = 0o1000000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +// sys/eventfd.h +pub const EFD_SEMAPHORE: c_int = 0x1; +pub const EFD_CLOEXEC: c_int = O_CLOEXEC; +pub const EFD_NONBLOCK: c_int = O_NONBLOCK; + +// sys/timerfd.h +pub const TFD_CLOEXEC: c_int = O_CLOEXEC; +pub const TFD_NONBLOCK: c_int = O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: c_int = 1; +pub const TFD_TIMER_CANCEL_ON_SET: c_int = 2; + +pub const USER_PROCESS: c_short = 7; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +// linux/falloc.h +pub const FALLOC_FL_KEEP_SIZE: c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: c_int = 0x02; +pub const FALLOC_FL_NO_HIDE_STALE: c_int = 0x04; +pub const FALLOC_FL_COLLAPSE_RANGE: c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: c_int = 0x40; + +pub const BUFSIZ: c_uint = 1024; +pub const FILENAME_MAX: c_uint = 4096; +pub const FOPEN_MAX: c_uint = 20; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; +pub const L_tmpnam: c_uint = 4096; +pub const TMP_MAX: c_uint = 308915776; +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_2_SYMLINKS: c_int = 7; +pub const _PC_ALLOC_SIZE_MIN: c_int = 8; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 9; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 10; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 11; +pub const _PC_REC_XFER_ALIGN: c_int = 12; +pub const _PC_SYMLINK_MAX: c_int = 13; +pub const _PC_CHOWN_RESTRICTED: c_int = 14; +pub const _PC_NO_TRUNC: c_int = 15; +pub const _PC_VDISABLE: c_int = 16; +pub const _PC_ASYNC_IO: c_int = 17; +pub const _PC_PRIO_IO: c_int = 18; +pub const _PC_SYNC_IO: c_int = 19; + +pub const FIONBIO: c_int = 0x5421; + +pub const _SC_ARG_MAX: c_int = 0x0000; +pub const _SC_BC_BASE_MAX: c_int = 0x0001; +pub const _SC_BC_DIM_MAX: c_int = 0x0002; +pub const _SC_BC_SCALE_MAX: c_int = 0x0003; +pub const _SC_BC_STRING_MAX: c_int = 0x0004; +pub const _SC_CHILD_MAX: c_int = 0x0005; +pub const _SC_CLK_TCK: c_int = 0x0006; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 0x0007; +pub const _SC_EXPR_NEST_MAX: c_int = 0x0008; +pub const _SC_LINE_MAX: c_int = 0x0009; +pub const _SC_NGROUPS_MAX: c_int = 0x000a; +pub const _SC_OPEN_MAX: c_int = 0x000b; +pub const _SC_PASS_MAX: c_int = 0x000c; +pub const _SC_2_C_BIND: c_int = 0x000d; +pub const _SC_2_C_DEV: c_int = 0x000e; +pub const _SC_2_C_VERSION: c_int = 0x000f; +pub const _SC_2_CHAR_TERM: c_int = 0x0010; +pub const _SC_2_FORT_DEV: c_int = 0x0011; +pub const _SC_2_FORT_RUN: c_int = 0x0012; +pub const _SC_2_LOCALEDEF: c_int = 0x0013; +pub const _SC_2_SW_DEV: c_int = 0x0014; +pub const _SC_2_UPE: c_int = 0x0015; +pub const _SC_2_VERSION: c_int = 0x0016; +pub const _SC_JOB_CONTROL: c_int = 0x0017; +pub const _SC_SAVED_IDS: c_int = 0x0018; +pub const _SC_VERSION: c_int = 0x0019; +pub const _SC_RE_DUP_MAX: c_int = 0x001a; +pub const _SC_STREAM_MAX: c_int = 0x001b; +pub const _SC_TZNAME_MAX: c_int = 0x001c; +pub const _SC_XOPEN_CRYPT: c_int = 0x001d; +pub const _SC_XOPEN_ENH_I18N: c_int = 0x001e; +pub const _SC_XOPEN_SHM: c_int = 0x001f; +pub const _SC_XOPEN_VERSION: c_int = 0x0020; +pub const _SC_XOPEN_XCU_VERSION: c_int = 0x0021; +pub const _SC_XOPEN_REALTIME: c_int = 0x0022; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 0x0023; +pub const _SC_XOPEN_LEGACY: c_int = 0x0024; +pub const _SC_ATEXIT_MAX: c_int = 0x0025; +pub const _SC_IOV_MAX: c_int = 0x0026; +pub const _SC_UIO_MAXIOV: c_int = _SC_IOV_MAX; +pub const _SC_PAGESIZE: c_int = 0x0027; +pub const _SC_PAGE_SIZE: c_int = 0x0028; +pub const _SC_XOPEN_UNIX: c_int = 0x0029; +pub const _SC_XBS5_ILP32_OFF32: c_int = 0x002a; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 0x002b; +pub const _SC_XBS5_LP64_OFF64: c_int = 0x002c; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 0x002d; +pub const _SC_AIO_LISTIO_MAX: c_int = 0x002e; +pub const _SC_AIO_MAX: c_int = 0x002f; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 0x0030; +pub const _SC_DELAYTIMER_MAX: c_int = 0x0031; +pub const _SC_MQ_OPEN_MAX: c_int = 0x0032; +pub const _SC_MQ_PRIO_MAX: c_int = 0x0033; +pub const _SC_RTSIG_MAX: c_int = 0x0034; +pub const _SC_SEM_NSEMS_MAX: c_int = 0x0035; +pub const _SC_SEM_VALUE_MAX: c_int = 0x0036; +pub const _SC_SIGQUEUE_MAX: c_int = 0x0037; +pub const _SC_TIMER_MAX: c_int = 0x0038; +pub const _SC_ASYNCHRONOUS_IO: c_int = 0x0039; +pub const _SC_FSYNC: c_int = 0x003a; +pub const _SC_MAPPED_FILES: c_int = 0x003b; +pub const _SC_MEMLOCK: c_int = 0x003c; +pub const _SC_MEMLOCK_RANGE: c_int = 0x003d; +pub const _SC_MEMORY_PROTECTION: c_int = 0x003e; +pub const _SC_MESSAGE_PASSING: c_int = 0x003f; +pub const _SC_PRIORITIZED_IO: c_int = 0x0040; +pub const _SC_PRIORITY_SCHEDULING: c_int = 0x0041; +pub const _SC_REALTIME_SIGNALS: c_int = 0x0042; +pub const _SC_SEMAPHORES: c_int = 0x0043; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 0x0044; +pub const _SC_SYNCHRONIZED_IO: c_int = 0x0045; +pub const _SC_TIMERS: c_int = 0x0046; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 0x0047; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 0x0048; +pub const _SC_LOGIN_NAME_MAX: c_int = 0x0049; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 0x004a; +pub const _SC_THREAD_KEYS_MAX: c_int = 0x004b; +pub const _SC_THREAD_STACK_MIN: c_int = 0x004c; +pub const _SC_THREAD_THREADS_MAX: c_int = 0x004d; +pub const _SC_TTY_NAME_MAX: c_int = 0x004e; +pub const _SC_THREADS: c_int = 0x004f; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 0x0050; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 0x0051; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 0x0052; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 0x0053; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 0x0054; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 0x0055; +pub const _SC_NPROCESSORS_CONF: c_int = 0x0060; +pub const _SC_NPROCESSORS_ONLN: c_int = 0x0061; +pub const _SC_PHYS_PAGES: c_int = 0x0062; +pub const _SC_AVPHYS_PAGES: c_int = 0x0063; +pub const _SC_MONOTONIC_CLOCK: c_int = 0x0064; +pub const _SC_2_PBS: c_int = 0x0065; +pub const _SC_2_PBS_ACCOUNTING: c_int = 0x0066; +pub const _SC_2_PBS_CHECKPOINT: c_int = 0x0067; +pub const _SC_2_PBS_LOCATE: c_int = 0x0068; +pub const _SC_2_PBS_MESSAGE: c_int = 0x0069; +pub const _SC_2_PBS_TRACK: c_int = 0x006a; +pub const _SC_ADVISORY_INFO: c_int = 0x006b; +pub const _SC_BARRIERS: c_int = 0x006c; +pub const _SC_CLOCK_SELECTION: c_int = 0x006d; +pub const _SC_CPUTIME: c_int = 0x006e; +pub const _SC_HOST_NAME_MAX: c_int = 0x006f; +pub const _SC_IPV6: c_int = 0x0070; +pub const _SC_RAW_SOCKETS: c_int = 0x0071; +pub const _SC_READER_WRITER_LOCKS: c_int = 0x0072; +pub const _SC_REGEXP: c_int = 0x0073; +pub const _SC_SHELL: c_int = 0x0074; +pub const _SC_SPAWN: c_int = 0x0075; +pub const _SC_SPIN_LOCKS: c_int = 0x0076; +pub const _SC_SPORADIC_SERVER: c_int = 0x0077; +pub const _SC_SS_REPL_MAX: c_int = 0x0078; +pub const _SC_SYMLOOP_MAX: c_int = 0x0079; +pub const _SC_THREAD_CPUTIME: c_int = 0x007a; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 0x007b; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 0x007c; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 0x007d; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 0x007e; +pub const _SC_TIMEOUTS: c_int = 0x007f; +pub const _SC_TRACE: c_int = 0x0080; +pub const _SC_TRACE_EVENT_FILTER: c_int = 0x0081; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 0x0082; +pub const _SC_TRACE_INHERIT: c_int = 0x0083; +pub const _SC_TRACE_LOG: c_int = 0x0084; +pub const _SC_TRACE_NAME_MAX: c_int = 0x0085; +pub const _SC_TRACE_SYS_MAX: c_int = 0x0086; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 0x0087; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 0x0088; +pub const _SC_V7_ILP32_OFF32: c_int = 0x0089; +pub const _SC_V7_ILP32_OFFBIG: c_int = 0x008a; +pub const _SC_V7_LP64_OFF64: c_int = 0x008b; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 0x008c; +pub const _SC_XOPEN_STREAMS: c_int = 0x008d; +pub const _SC_XOPEN_UUCP: c_int = 0x008e; +pub const _SC_LEVEL1_ICACHE_SIZE: c_int = 0x008f; +pub const _SC_LEVEL1_ICACHE_ASSOC: c_int = 0x0090; +pub const _SC_LEVEL1_ICACHE_LINESIZE: c_int = 0x0091; +pub const _SC_LEVEL1_DCACHE_SIZE: c_int = 0x0092; +pub const _SC_LEVEL1_DCACHE_ASSOC: c_int = 0x0093; +pub const _SC_LEVEL1_DCACHE_LINESIZE: c_int = 0x0094; +pub const _SC_LEVEL2_CACHE_SIZE: c_int = 0x0095; +pub const _SC_LEVEL2_CACHE_ASSOC: c_int = 0x0096; +pub const _SC_LEVEL2_CACHE_LINESIZE: c_int = 0x0097; +pub const _SC_LEVEL3_CACHE_SIZE: c_int = 0x0098; +pub const _SC_LEVEL3_CACHE_ASSOC: c_int = 0x0099; +pub const _SC_LEVEL3_CACHE_LINESIZE: c_int = 0x009a; +pub const _SC_LEVEL4_CACHE_SIZE: c_int = 0x009b; +pub const _SC_LEVEL4_CACHE_ASSOC: c_int = 0x009c; +pub const _SC_LEVEL4_CACHE_LINESIZE: c_int = 0x009d; + +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +pub const F_SEAL_FUTURE_WRITE: c_int = 0x0010; +pub const F_SEAL_EXEC: c_int = 0x0020; + +pub const IFF_LOWER_UP: c_int = 0x10000; +pub const IFF_DORMANT: c_int = 0x20000; +pub const IFF_ECHO: c_int = 0x40000; + +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; + +pub const PTHREAD_EXPLICIT_SCHED: c_int = 0; +pub const PTHREAD_INHERIT_SCHED: c_int = 1; + +// stdio.h +pub const RENAME_NOREPLACE: c_int = 1; +pub const RENAME_EXCHANGE: c_int = 2; +pub const RENAME_WHITEOUT: c_int = 4; + +pub const FIOCLEX: c_int = 0x5451; +pub const FIONCLEX: c_int = 0x5450; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const LC_PAPER: c_int = 7; +pub const LC_NAME: c_int = 8; +pub const LC_ADDRESS: c_int = 9; +pub const LC_TELEPHONE: c_int = 10; +pub const LC_MEASUREMENT: c_int = 11; +pub const LC_IDENTIFICATION: c_int = 12; +pub const LC_PAPER_MASK: c_int = 1 << LC_PAPER; +pub const LC_NAME_MASK: c_int = 1 << LC_NAME; +pub const LC_ADDRESS_MASK: c_int = 1 << LC_ADDRESS; +pub const LC_TELEPHONE_MASK: c_int = 1 << LC_TELEPHONE; +pub const LC_MEASUREMENT_MASK: c_int = 1 << LC_MEASUREMENT; +pub const LC_IDENTIFICATION_MASK: c_int = 1 << LC_IDENTIFICATION; +pub const LC_ALL_MASK: c_int = crate::LC_CTYPE_MASK + | crate::LC_NUMERIC_MASK + | crate::LC_TIME_MASK + | crate::LC_COLLATE_MASK + | crate::LC_MONETARY_MASK + | crate::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; + +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_DCCP: c_int = 6; +#[deprecated(since = "0.2.70", note = "AF_PACKET must be used instead")] +pub const SOCK_PACKET: c_int = 10; + +pub const IPPROTO_MAX: c_int = 256; + +pub const SOL_SOCKET: c_int = 1; +pub const SOL_SCTP: c_int = 132; +pub const SOL_IPX: c_int = 256; +pub const SOL_AX25: c_int = 257; +pub const SOL_ATALK: c_int = 258; +pub const SOL_NETROM: c_int = 259; +pub const SOL_ROSE: c_int = 260; + +/* UDP socket options */ +// include/uapi/linux/udp.h +pub const UDP_CORK: c_int = 1; +pub const UDP_ENCAP: c_int = 100; +pub const UDP_NO_CHECK6_TX: c_int = 101; +pub const UDP_NO_CHECK6_RX: c_int = 102; +pub const UDP_SEGMENT: c_int = 103; +pub const UDP_GRO: c_int = 104; + +/* DCCP socket options */ +pub const DCCP_SOCKOPT_PACKET_SIZE: c_int = 1; +pub const DCCP_SOCKOPT_SERVICE: c_int = 2; +pub const DCCP_SOCKOPT_CHANGE_L: c_int = 3; +pub const DCCP_SOCKOPT_CHANGE_R: c_int = 4; +pub const DCCP_SOCKOPT_GET_CUR_MPS: c_int = 5; +pub const DCCP_SOCKOPT_SERVER_TIMEWAIT: c_int = 6; +pub const DCCP_SOCKOPT_SEND_CSCOV: c_int = 10; +pub const DCCP_SOCKOPT_RECV_CSCOV: c_int = 11; +pub const DCCP_SOCKOPT_AVAILABLE_CCIDS: c_int = 12; +pub const DCCP_SOCKOPT_CCID: c_int = 13; +pub const DCCP_SOCKOPT_TX_CCID: c_int = 14; +pub const DCCP_SOCKOPT_RX_CCID: c_int = 15; +pub const DCCP_SOCKOPT_QPOLICY_ID: c_int = 16; +pub const DCCP_SOCKOPT_QPOLICY_TXQLEN: c_int = 17; +pub const DCCP_SOCKOPT_CCID_RX_INFO: c_int = 128; +pub const DCCP_SOCKOPT_CCID_TX_INFO: c_int = 192; + +/// maximum number of services provided on the same listening port +pub const DCCP_SERVICE_LIST_MAX_LEN: c_int = 32; + +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 20; +pub const SO_SNDTIMEO: c_int = 21; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_ATTACH_FILTER: c_int = 26; +pub const SO_DETACH_FILTER: c_int = 27; +pub const SO_GET_FILTER: c_int = SO_ATTACH_FILTER; +pub const SO_TIMESTAMP: c_int = 29; +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PASSSEC: c_int = 34; +pub const SO_TIMESTAMPNS: c_int = 35; +// pub const SO_TIMESTAMPNS_OLD: c_int = 35; +pub const SO_MARK: c_int = 36; +pub const SO_TIMESTAMPING: c_int = 37; +// pub const SO_TIMESTAMPING_OLD: c_int = 37; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_BUSY_POLL: c_int = 46; +pub const SCM_TIMESTAMPING_OPT_STATS: c_int = 54; +pub const SCM_TIMESTAMPING_PKTINFO: c_int = 58; +pub const SO_BINDTOIFINDEX: c_int = 62; +pub const SO_TIMESTAMP_NEW: c_int = 63; +pub const SO_TIMESTAMPNS_NEW: c_int = 64; +pub const SO_TIMESTAMPING_NEW: c_int = 65; + +// Defined in unix/linux_like/mod.rs +// pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; +pub const SCM_TIMESTAMPNS: c_int = SO_TIMESTAMPNS; +pub const SCM_TIMESTAMPING: c_int = SO_TIMESTAMPING; + +pub const IPTOS_ECN_NOTECT: u8 = 0x00; + +pub const O_ACCMODE: c_int = 3; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; +pub const O_DSYNC: c_int = 4096; +pub const O_RSYNC: c_int = O_SYNC; + +pub const NI_MAXHOST: size_t = 1025; +pub const NI_MAXSERV: size_t = 32; + +pub const NI_NOFQDN: c_int = 0x00000001; +pub const NI_NUMERICHOST: c_int = 0x00000002; +pub const NI_NAMEREQD: c_int = 0x00000004; +pub const NI_NUMERICSERV: c_int = 0x00000008; +pub const NI_DGRAM: c_int = 0x00000010; + +pub const NCCS: usize = 19; +pub const TCSBRKP: c_int = 0x5425; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 0x1; +pub const TCSAFLUSH: c_int = 0x2; +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0o200000; + +pub const MAP_HUGETLB: c_int = 0x040000; + +pub const PTRACE_TRACEME: c_int = 0; +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_PEEKUSER: c_int = 3; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_POKEUSER: c_int = 6; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; +pub const PTRACE_SYSCALL: c_int = 24; +pub const PTRACE_SETOPTIONS: c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: c_int = 0x4201; +pub const PTRACE_GETSIGINFO: c_int = 0x4202; +pub const PTRACE_SETSIGINFO: c_int = 0x4203; +pub const PTRACE_GETREGSET: c_int = 0x4204; +pub const PTRACE_SETREGSET: c_int = 0x4205; +pub const PTRACE_SECCOMP_GET_METADATA: c_int = 0x420d; + +pub const PTRACE_EVENT_STOP: c_int = 128; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_NPROC: c_int = 6; +pub const RLIMIT_NOFILE: c_int = 7; +pub const RLIMIT_MEMLOCK: c_int = 8; +pub const RLIMIT_AS: c_int = 9; +pub const RLIMIT_LOCKS: c_int = 10; +pub const RLIMIT_SIGPENDING: c_int = 11; +pub const RLIMIT_MSGQUEUE: c_int = 12; +pub const RLIMIT_NICE: c_int = 13; +pub const RLIMIT_RTPRIO: c_int = 14; + +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 16; +pub const RLIM_INFINITY: crate::rlim_t = !0; + +pub const TCGETS: c_int = 0x5401; +pub const TCSETS: c_int = 0x5402; +pub const TCSETSW: c_int = 0x5403; +pub const TCSETSF: c_int = 0x5404; +pub const TCGETS2: c_int = 0x802c542a; +pub const TCSETS2: c_int = 0x402c542b; +pub const TCSETSW2: c_int = 0x402c542c; +pub const TCSETSF2: c_int = 0x402c542d; +pub const TCGETA: c_int = 0x5405; +pub const TCSETA: c_int = 0x5406; +pub const TCSETAW: c_int = 0x5407; +pub const TCSETAF: c_int = 0x5408; +pub const TCSBRK: c_int = 0x5409; +pub const TCXONC: c_int = 0x540A; +pub const TCFLSH: c_int = 0x540B; +pub const TIOCGSOFTCAR: c_int = 0x5419; +pub const TIOCSSOFTCAR: c_int = 0x541A; +pub const TIOCINQ: c_int = 0x541B; +pub const TIOCLINUX: c_int = 0x541C; +pub const TIOCGSERIAL: c_int = 0x541E; +pub const TIOCEXCL: c_int = 0x540C; +pub const TIOCNXCL: c_int = 0x540D; +pub const TIOCSCTTY: c_int = 0x540E; +pub const TIOCGPGRP: c_int = 0x540F; +pub const TIOCSPGRP: c_int = 0x5410; +pub const TIOCOUTQ: c_int = 0x5411; +pub const TIOCSTI: c_int = 0x5412; +pub const TIOCGWINSZ: c_int = 0x5413; +pub const TIOCSWINSZ: c_int = 0x5414; +pub const TIOCMGET: c_int = 0x5415; +pub const TIOCMBIS: c_int = 0x5416; +pub const TIOCMBIC: c_int = 0x5417; +pub const TIOCMSET: c_int = 0x5418; +pub const FIONREAD: c_int = 0x541B; +pub const TIOCCONS: c_int = 0x541D; +pub const TIOCSBRK: c_int = 0x5427; +pub const TIOCCBRK: c_int = 0x5428; + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; +pub const ST_NODEV: c_ulong = 4; +pub const ST_NOEXEC: c_ulong = 8; +pub const ST_SYNCHRONOUS: c_ulong = 16; +pub const ST_MANDLOCK: c_ulong = 64; +pub const ST_NOATIME: c_ulong = 1024; +pub const ST_NODIRATIME: c_ulong = 2048; +pub const ST_RELATIME: c_ulong = 4096; + +pub const RTLD_NOLOAD: c_int = 0x4; +pub const RTLD_NODELETE: c_int = 0x1000; + +pub const SEM_FAILED: *mut sem_t = ptr::null_mut(); + +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; +pub const AI_NUMERICSERV: c_int = 0x00000008; +pub const AI_MASK: c_int = + AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG; +pub const AI_ALL: c_int = 0x00000100; +pub const AI_V4MAPPED_CFG: c_int = 0x00000200; +pub const AI_ADDRCONFIG: c_int = 0x00000400; +pub const AI_V4MAPPED: c_int = 0x00000800; +pub const AI_DEFAULT: c_int = AI_V4MAPPED_CFG | AI_ADDRCONFIG; + +// linux/kexec.h +pub const KEXEC_ON_CRASH: c_int = 0x00000001; +pub const KEXEC_PRESERVE_CONTEXT: c_int = 0x00000002; +pub const KEXEC_ARCH_MASK: c_int = 0xffff0000; +pub const KEXEC_FILE_UNLOAD: c_int = 0x00000001; +pub const KEXEC_FILE_ON_CRASH: c_int = 0x00000002; +pub const KEXEC_FILE_NO_INITRAMFS: c_int = 0x00000004; + +pub const LINUX_REBOOT_MAGIC1: c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: c_int = 0x45584543; + +pub const REG_BASIC: c_int = 0; +pub const REG_EXTENDED: c_int = 1; +pub const REG_ICASE: c_int = 2; +pub const REG_NOSUB: c_int = 4; +pub const REG_NEWLINE: c_int = 8; +pub const REG_NOSPEC: c_int = 16; +pub const REG_PEND: c_int = 32; +pub const REG_DUMP: c_int = 128; + +pub const REG_NOMATCH: c_int = 1; +pub const REG_BADPAT: c_int = 2; +pub const REG_ECOLLATE: c_int = 3; +pub const REG_ECTYPE: c_int = 4; +pub const REG_EESCAPE: c_int = 5; +pub const REG_ESUBREG: c_int = 6; +pub const REG_EBRACK: c_int = 7; +pub const REG_EPAREN: c_int = 8; +pub const REG_EBRACE: c_int = 9; +pub const REG_BADBR: c_int = 10; +pub const REG_ERANGE: c_int = 11; +pub const REG_ESPACE: c_int = 12; +pub const REG_BADRPT: c_int = 13; +pub const REG_EMPTY: c_int = 14; +pub const REG_ASSERT: c_int = 15; +pub const REG_INVARG: c_int = 16; +pub const REG_ATOI: c_int = 255; +pub const REG_ITOA: c_int = 256; + +pub const REG_NOTBOL: c_int = 1; +pub const REG_NOTEOL: c_int = 2; +pub const REG_STARTEND: c_int = 4; +pub const REG_TRACE: c_int = 256; +pub const REG_LARGE: c_int = 512; +pub const REG_BACKR: c_int = 1024; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IUCLC: crate::tcflag_t = 0x00000200; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XCASE: crate::tcflag_t = 0o000004; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const BOTHER: crate::speed_t = 0o010000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; +pub const IBSHIFT: crate::tcflag_t = 16; + +pub const BLKIOMIN: c_int = 0x1278; +pub const BLKIOOPT: c_int = 0x1279; +pub const BLKSSZGET: c_int = 0x1268; +pub const BLKPBSZGET: c_int = 0x127B; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const NETLINK_ROUTE: c_int = 0; +pub const NETLINK_UNUSED: c_int = 1; +pub const NETLINK_USERSOCK: c_int = 2; +pub const NETLINK_FIREWALL: c_int = 3; +pub const NETLINK_SOCK_DIAG: c_int = 4; +pub const NETLINK_NFLOG: c_int = 5; +pub const NETLINK_XFRM: c_int = 6; +pub const NETLINK_SELINUX: c_int = 7; +pub const NETLINK_ISCSI: c_int = 8; +pub const NETLINK_AUDIT: c_int = 9; +pub const NETLINK_FIB_LOOKUP: c_int = 10; +pub const NETLINK_CONNECTOR: c_int = 11; +pub const NETLINK_NETFILTER: c_int = 12; +pub const NETLINK_IP6_FW: c_int = 13; +pub const NETLINK_DNRTMSG: c_int = 14; +pub const NETLINK_KOBJECT_UEVENT: c_int = 15; +pub const NETLINK_GENERIC: c_int = 16; +pub const NETLINK_SCSITRANSPORT: c_int = 18; +pub const NETLINK_ECRYPTFS: c_int = 19; +pub const NETLINK_RDMA: c_int = 20; +pub const NETLINK_CRYPTO: c_int = 21; +pub const NETLINK_INET_DIAG: c_int = NETLINK_SOCK_DIAG; + +pub const MAX_LINKS: c_int = 32; + +pub const NLM_F_REQUEST: c_int = 1; +pub const NLM_F_MULTI: c_int = 2; +pub const NLM_F_ACK: c_int = 4; +pub const NLM_F_ECHO: c_int = 8; +pub const NLM_F_DUMP_INTR: c_int = 16; +pub const NLM_F_DUMP_FILTERED: c_int = 32; + +pub const NLM_F_ROOT: c_int = 0x100; +pub const NLM_F_MATCH: c_int = 0x200; +pub const NLM_F_ATOMIC: c_int = 0x400; +pub const NLM_F_DUMP: c_int = NLM_F_ROOT | NLM_F_MATCH; + +pub const NLM_F_REPLACE: c_int = 0x100; +pub const NLM_F_EXCL: c_int = 0x200; +pub const NLM_F_CREATE: c_int = 0x400; +pub const NLM_F_APPEND: c_int = 0x800; + +pub const NLM_F_NONREC: c_int = 0x100; +pub const NLM_F_BULK: c_int = 0x200; + +pub const NLM_F_CAPPED: c_int = 0x100; +pub const NLM_F_ACK_TLVS: c_int = 0x200; + +pub const NLMSG_NOOP: c_int = 0x1; +pub const NLMSG_ERROR: c_int = 0x2; +pub const NLMSG_DONE: c_int = 0x3; +pub const NLMSG_OVERRUN: c_int = 0x4; +pub const NLMSG_MIN_TYPE: c_int = 0x10; + +// linux/netfilter/nfnetlink.h +pub const NFNLGRP_NONE: c_int = 0; +pub const NFNLGRP_CONNTRACK_NEW: c_int = 1; +pub const NFNLGRP_CONNTRACK_UPDATE: c_int = 2; +pub const NFNLGRP_CONNTRACK_DESTROY: c_int = 3; +pub const NFNLGRP_CONNTRACK_EXP_NEW: c_int = 4; +pub const NFNLGRP_CONNTRACK_EXP_UPDATE: c_int = 5; +pub const NFNLGRP_CONNTRACK_EXP_DESTROY: c_int = 6; +pub const NFNLGRP_NFTABLES: c_int = 7; +pub const NFNLGRP_ACCT_QUOTA: c_int = 8; + +pub const NFNETLINK_V0: c_int = 0; + +pub const NFNL_SUBSYS_NONE: c_int = 0; +pub const NFNL_SUBSYS_CTNETLINK: c_int = 1; +pub const NFNL_SUBSYS_CTNETLINK_EXP: c_int = 2; +pub const NFNL_SUBSYS_QUEUE: c_int = 3; +pub const NFNL_SUBSYS_ULOG: c_int = 4; +pub const NFNL_SUBSYS_OSF: c_int = 5; +pub const NFNL_SUBSYS_IPSET: c_int = 6; +pub const NFNL_SUBSYS_ACCT: c_int = 7; +pub const NFNL_SUBSYS_CTNETLINK_TIMEOUT: c_int = 8; +pub const NFNL_SUBSYS_CTHELPER: c_int = 9; +pub const NFNL_SUBSYS_NFTABLES: c_int = 10; +pub const NFNL_SUBSYS_NFT_COMPAT: c_int = 11; +pub const NFNL_SUBSYS_COUNT: c_int = 12; + +pub const NFNL_MSG_BATCH_BEGIN: c_int = NLMSG_MIN_TYPE; +pub const NFNL_MSG_BATCH_END: c_int = NLMSG_MIN_TYPE + 1; + +// linux/netfilter/nfnetlink_log.h +pub const NFULNL_MSG_PACKET: c_int = 0; +pub const NFULNL_MSG_CONFIG: c_int = 1; + +pub const NFULA_UNSPEC: c_int = 0; +pub const NFULA_PACKET_HDR: c_int = 1; +pub const NFULA_MARK: c_int = 2; +pub const NFULA_TIMESTAMP: c_int = 3; +pub const NFULA_IFINDEX_INDEV: c_int = 4; +pub const NFULA_IFINDEX_OUTDEV: c_int = 5; +pub const NFULA_IFINDEX_PHYSINDEV: c_int = 6; +pub const NFULA_IFINDEX_PHYSOUTDEV: c_int = 7; +pub const NFULA_HWADDR: c_int = 8; +pub const NFULA_PAYLOAD: c_int = 9; +pub const NFULA_PREFIX: c_int = 10; +pub const NFULA_UID: c_int = 11; +pub const NFULA_SEQ: c_int = 12; +pub const NFULA_SEQ_GLOBAL: c_int = 13; +pub const NFULA_GID: c_int = 14; +pub const NFULA_HWTYPE: c_int = 15; +pub const NFULA_HWHEADER: c_int = 16; +pub const NFULA_HWLEN: c_int = 17; +pub const NFULA_CT: c_int = 18; +pub const NFULA_CT_INFO: c_int = 19; + +pub const NFULNL_CFG_CMD_NONE: c_int = 0; +pub const NFULNL_CFG_CMD_BIND: c_int = 1; +pub const NFULNL_CFG_CMD_UNBIND: c_int = 2; +pub const NFULNL_CFG_CMD_PF_BIND: c_int = 3; +pub const NFULNL_CFG_CMD_PF_UNBIND: c_int = 4; + +pub const NFULA_CFG_UNSPEC: c_int = 0; +pub const NFULA_CFG_CMD: c_int = 1; +pub const NFULA_CFG_MODE: c_int = 2; +pub const NFULA_CFG_NLBUFSIZ: c_int = 3; +pub const NFULA_CFG_TIMEOUT: c_int = 4; +pub const NFULA_CFG_QTHRESH: c_int = 5; +pub const NFULA_CFG_FLAGS: c_int = 6; + +pub const NFULNL_COPY_NONE: c_int = 0x00; +pub const NFULNL_COPY_META: c_int = 0x01; +pub const NFULNL_COPY_PACKET: c_int = 0x02; + +pub const NFULNL_CFG_F_SEQ: c_int = 0x0001; +pub const NFULNL_CFG_F_SEQ_GLOBAL: c_int = 0x0002; +pub const NFULNL_CFG_F_CONNTRACK: c_int = 0x0004; + +// linux/netfilter/nfnetlink_log.h +pub const NFQNL_MSG_PACKET: c_int = 0; +pub const NFQNL_MSG_VERDICT: c_int = 1; +pub const NFQNL_MSG_CONFIG: c_int = 2; +pub const NFQNL_MSG_VERDICT_BATCH: c_int = 3; + +pub const NFQA_UNSPEC: c_int = 0; +pub const NFQA_PACKET_HDR: c_int = 1; +pub const NFQA_VERDICT_HDR: c_int = 2; +pub const NFQA_MARK: c_int = 3; +pub const NFQA_TIMESTAMP: c_int = 4; +pub const NFQA_IFINDEX_INDEV: c_int = 5; +pub const NFQA_IFINDEX_OUTDEV: c_int = 6; +pub const NFQA_IFINDEX_PHYSINDEV: c_int = 7; +pub const NFQA_IFINDEX_PHYSOUTDEV: c_int = 8; +pub const NFQA_HWADDR: c_int = 9; +pub const NFQA_PAYLOAD: c_int = 10; +pub const NFQA_CT: c_int = 11; +pub const NFQA_CT_INFO: c_int = 12; +pub const NFQA_CAP_LEN: c_int = 13; +pub const NFQA_SKB_INFO: c_int = 14; +pub const NFQA_EXP: c_int = 15; +pub const NFQA_UID: c_int = 16; +pub const NFQA_GID: c_int = 17; +pub const NFQA_SECCTX: c_int = 18; +/* + FIXME: These are not yet available in musl sanitized kernel headers and + make the tests fail. Enable them once musl has them. + + See https://github.com/rust-lang/libc/pull/1628 for more details. +pub const NFQA_VLAN: c_int = 19; +pub const NFQA_L2HDR: c_int = 20; + +pub const NFQA_VLAN_UNSPEC: c_int = 0; +pub const NFQA_VLAN_PROTO: c_int = 1; +pub const NFQA_VLAN_TCI: c_int = 2; +*/ + +pub const NFQNL_CFG_CMD_NONE: c_int = 0; +pub const NFQNL_CFG_CMD_BIND: c_int = 1; +pub const NFQNL_CFG_CMD_UNBIND: c_int = 2; +pub const NFQNL_CFG_CMD_PF_BIND: c_int = 3; +pub const NFQNL_CFG_CMD_PF_UNBIND: c_int = 4; + +pub const NFQNL_COPY_NONE: c_int = 0; +pub const NFQNL_COPY_META: c_int = 1; +pub const NFQNL_COPY_PACKET: c_int = 2; + +pub const NFQA_CFG_UNSPEC: c_int = 0; +pub const NFQA_CFG_CMD: c_int = 1; +pub const NFQA_CFG_PARAMS: c_int = 2; +pub const NFQA_CFG_QUEUE_MAXLEN: c_int = 3; +pub const NFQA_CFG_MASK: c_int = 4; +pub const NFQA_CFG_FLAGS: c_int = 5; + +pub const NFQA_CFG_F_FAIL_OPEN: c_int = 0x0001; +pub const NFQA_CFG_F_CONNTRACK: c_int = 0x0002; +pub const NFQA_CFG_F_GSO: c_int = 0x0004; +pub const NFQA_CFG_F_UID_GID: c_int = 0x0008; +pub const NFQA_CFG_F_SECCTX: c_int = 0x0010; +pub const NFQA_CFG_F_MAX: c_int = 0x0020; + +pub const NFQA_SKB_CSUMNOTREADY: c_int = 0x0001; +pub const NFQA_SKB_GSO: c_int = 0x0002; +pub const NFQA_SKB_CSUM_NOTVERIFIED: c_int = 0x0004; + +pub const GENL_NAMSIZ: c_int = 16; + +pub const GENL_MIN_ID: c_int = NLMSG_MIN_TYPE; +pub const GENL_MAX_ID: c_int = 1023; + +pub const GENL_ADMIN_PERM: c_int = 0x01; +pub const GENL_CMD_CAP_DO: c_int = 0x02; +pub const GENL_CMD_CAP_DUMP: c_int = 0x04; +pub const GENL_CMD_CAP_HASPOL: c_int = 0x08; +pub const GENL_UNS_ADMIN_PERM: c_int = 0x10; + +pub const GENL_ID_CTRL: c_int = NLMSG_MIN_TYPE; +pub const GENL_ID_VFS_DQUOT: c_int = NLMSG_MIN_TYPE + 1; +pub const GENL_ID_PMCRAID: c_int = NLMSG_MIN_TYPE + 2; + +pub const CTRL_CMD_UNSPEC: c_int = 0; +pub const CTRL_CMD_NEWFAMILY: c_int = 1; +pub const CTRL_CMD_DELFAMILY: c_int = 2; +pub const CTRL_CMD_GETFAMILY: c_int = 3; +pub const CTRL_CMD_NEWOPS: c_int = 4; +pub const CTRL_CMD_DELOPS: c_int = 5; +pub const CTRL_CMD_GETOPS: c_int = 6; +pub const CTRL_CMD_NEWMCAST_GRP: c_int = 7; +pub const CTRL_CMD_DELMCAST_GRP: c_int = 8; +pub const CTRL_CMD_GETMCAST_GRP: c_int = 9; + +pub const CTRL_ATTR_UNSPEC: c_int = 0; +pub const CTRL_ATTR_FAMILY_ID: c_int = 1; +pub const CTRL_ATTR_FAMILY_NAME: c_int = 2; +pub const CTRL_ATTR_VERSION: c_int = 3; +pub const CTRL_ATTR_HDRSIZE: c_int = 4; +pub const CTRL_ATTR_MAXATTR: c_int = 5; +pub const CTRL_ATTR_OPS: c_int = 6; +pub const CTRL_ATTR_MCAST_GROUPS: c_int = 7; + +pub const CTRL_ATTR_OP_UNSPEC: c_int = 0; +pub const CTRL_ATTR_OP_ID: c_int = 1; +pub const CTRL_ATTR_OP_FLAGS: c_int = 2; + +pub const CTRL_ATTR_MCAST_GRP_UNSPEC: c_int = 0; +pub const CTRL_ATTR_MCAST_GRP_NAME: c_int = 1; +pub const CTRL_ATTR_MCAST_GRP_ID: c_int = 2; + +pub const NETLINK_ADD_MEMBERSHIP: c_int = 1; +pub const NETLINK_DROP_MEMBERSHIP: c_int = 2; +pub const NETLINK_PKTINFO: c_int = 3; +pub const NETLINK_BROADCAST_ERROR: c_int = 4; +pub const NETLINK_NO_ENOBUFS: c_int = 5; +pub const NETLINK_RX_RING: c_int = 6; +pub const NETLINK_TX_RING: c_int = 7; +pub const NETLINK_LISTEN_ALL_NSID: c_int = 8; +pub const NETLINK_LIST_MEMBERSHIPS: c_int = 9; +pub const NETLINK_CAP_ACK: c_int = 10; +pub const NETLINK_EXT_ACK: c_int = 11; +pub const NETLINK_GET_STRICT_CHK: c_int = 12; + +pub const GRND_NONBLOCK: c_uint = 0x0001; +pub const GRND_RANDOM: c_uint = 0x0002; +pub const GRND_INSECURE: c_uint = 0x0004; + +// +pub const SECCOMP_MODE_DISABLED: c_uint = 0; +pub const SECCOMP_MODE_STRICT: c_uint = 1; +pub const SECCOMP_MODE_FILTER: c_uint = 2; + +pub const SECCOMP_SET_MODE_STRICT: c_uint = 0; +pub const SECCOMP_SET_MODE_FILTER: c_uint = 1; +pub const SECCOMP_GET_ACTION_AVAIL: c_uint = 2; +pub const SECCOMP_GET_NOTIF_SIZES: c_uint = 3; + +pub const SECCOMP_FILTER_FLAG_TSYNC: c_ulong = 1 << 0; +pub const SECCOMP_FILTER_FLAG_LOG: c_ulong = 1 << 1; +pub const SECCOMP_FILTER_FLAG_SPEC_ALLOW: c_ulong = 1 << 2; +pub const SECCOMP_FILTER_FLAG_NEW_LISTENER: c_ulong = 1 << 3; +pub const SECCOMP_FILTER_FLAG_TSYNC_ESRCH: c_ulong = 1 << 4; +pub const SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV: c_ulong = 1 << 5; + +pub const SECCOMP_RET_KILL_PROCESS: c_uint = 0x80000000; +pub const SECCOMP_RET_KILL_THREAD: c_uint = 0x00000000; +pub const SECCOMP_RET_KILL: c_uint = SECCOMP_RET_KILL_THREAD; +pub const SECCOMP_RET_TRAP: c_uint = 0x00030000; +pub const SECCOMP_RET_ERRNO: c_uint = 0x00050000; +pub const SECCOMP_RET_USER_NOTIF: c_uint = 0x7fc00000; +pub const SECCOMP_RET_TRACE: c_uint = 0x7ff00000; +pub const SECCOMP_RET_LOG: c_uint = 0x7ffc0000; +pub const SECCOMP_RET_ALLOW: c_uint = 0x7fff0000; + +pub const SECCOMP_RET_ACTION_FULL: c_uint = 0xffff0000; +pub const SECCOMP_RET_ACTION: c_uint = 0x7fff0000; +pub const SECCOMP_RET_DATA: c_uint = 0x0000ffff; + +pub const SECCOMP_USER_NOTIF_FLAG_CONTINUE: c_ulong = 1; + +pub const SECCOMP_ADDFD_FLAG_SETFD: c_ulong = 1; +pub const SECCOMP_ADDFD_FLAG_SEND: c_ulong = 2; + +pub const NLA_F_NESTED: c_int = 1 << 15; +pub const NLA_F_NET_BYTEORDER: c_int = 1 << 14; +pub const NLA_TYPE_MASK: c_int = !(NLA_F_NESTED | NLA_F_NET_BYTEORDER); + +pub const NLA_ALIGNTO: c_int = 4; + +pub const SIGEV_THREAD_ID: c_int = 4; + +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RI: c_int = TIOCM_RNG; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const SFD_CLOEXEC: c_int = O_CLOEXEC; +pub const SFD_NONBLOCK: c_int = O_NONBLOCK; + +pub const SOCK_NONBLOCK: c_int = O_NONBLOCK; + +pub const SO_ORIGINAL_DST: c_int = 80; + +pub const IP_RECVFRAGSIZE: c_int = 25; + +pub const IPV6_FLOWINFO: c_int = 11; +pub const IPV6_MULTICAST_ALL: c_int = 29; +pub const IPV6_ROUTER_ALERT_ISOLATE: c_int = 30; +pub const IPV6_FLOWLABEL_MGR: c_int = 32; +pub const IPV6_FLOWINFO_SEND: c_int = 33; +pub const IPV6_RECVFRAGSIZE: c_int = 77; +pub const IPV6_FREEBIND: c_int = 78; +pub const IPV6_FLOWINFO_FLOWLABEL: c_int = 0x000fffff; +pub const IPV6_FLOWINFO_PRIORITY: c_int = 0x0ff00000; + +pub const IUTF8: crate::tcflag_t = 0x00004000; +pub const CMSPAR: crate::tcflag_t = 0o10000000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const MFD_CLOEXEC: c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: c_uint = 0x0002; +pub const MFD_HUGETLB: c_uint = 0x0004; +pub const MFD_NOEXEC_SEAL: c_uint = 0x0008; +pub const MFD_EXEC: c_uint = 0x0010; +pub const MFD_HUGE_64KB: c_uint = 0x40000000; +pub const MFD_HUGE_512KB: c_uint = 0x4c000000; +pub const MFD_HUGE_1MB: c_uint = 0x50000000; +pub const MFD_HUGE_2MB: c_uint = 0x54000000; +pub const MFD_HUGE_8MB: c_uint = 0x5c000000; +pub const MFD_HUGE_16MB: c_uint = 0x60000000; +pub const MFD_HUGE_32MB: c_uint = 0x64000000; +pub const MFD_HUGE_256MB: c_uint = 0x70000000; +pub const MFD_HUGE_512MB: c_uint = 0x74000000; +pub const MFD_HUGE_1GB: c_uint = 0x78000000; +pub const MFD_HUGE_2GB: c_uint = 0x7c000000; +pub const MFD_HUGE_16GB: c_uint = 0x88000000; +pub const MFD_HUGE_MASK: c_uint = 63; +pub const MFD_HUGE_SHIFT: c_uint = 26; + +// these are used in the p_type field of Elf32_Phdr and Elf64_Phdr, which has +// the type Elf32Word and Elf64Word respectively. Luckily, both of those are u32 +// so we can use that type here to avoid having to cast. +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_STACK: u32 = 0x6474e551; +pub const PT_GNU_RELRO: u32 = 0x6474e552; +pub const PT_HIOS: u32 = 0x6fffffff; +pub const PT_LOPROC: u32 = 0x70000000; +pub const PT_HIPROC: u32 = 0x7fffffff; + +// uapi/linux/mount.h +pub const OPEN_TREE_CLONE: c_uint = 0x01; +pub const OPEN_TREE_CLOEXEC: c_uint = O_CLOEXEC as c_uint; + +// linux/netfilter.h +pub const NF_DROP: c_int = 0; +pub const NF_ACCEPT: c_int = 1; +pub const NF_STOLEN: c_int = 2; +pub const NF_QUEUE: c_int = 3; +pub const NF_REPEAT: c_int = 4; +pub const NF_STOP: c_int = 5; +pub const NF_MAX_VERDICT: c_int = NF_STOP; + +pub const NF_VERDICT_MASK: c_int = 0x000000ff; +pub const NF_VERDICT_FLAG_QUEUE_BYPASS: c_int = 0x00008000; + +pub const NF_VERDICT_QMASK: c_int = 0xffff0000; +pub const NF_VERDICT_QBITS: c_int = 16; + +pub const NF_VERDICT_BITS: c_int = 16; + +pub const NF_INET_PRE_ROUTING: c_int = 0; +pub const NF_INET_LOCAL_IN: c_int = 1; +pub const NF_INET_FORWARD: c_int = 2; +pub const NF_INET_LOCAL_OUT: c_int = 3; +pub const NF_INET_POST_ROUTING: c_int = 4; +pub const NF_INET_NUMHOOKS: c_int = 5; +pub const NF_INET_INGRESS: c_int = NF_INET_NUMHOOKS; + +pub const NF_NETDEV_INGRESS: c_int = 0; +pub const NF_NETDEV_EGRESS: c_int = 1; +pub const NF_NETDEV_NUMHOOKS: c_int = 2; + +pub const NFPROTO_UNSPEC: c_int = 0; +pub const NFPROTO_INET: c_int = 1; +pub const NFPROTO_IPV4: c_int = 2; +pub const NFPROTO_ARP: c_int = 3; +pub const NFPROTO_NETDEV: c_int = 5; +pub const NFPROTO_BRIDGE: c_int = 7; +pub const NFPROTO_IPV6: c_int = 10; +pub const NFPROTO_DECNET: c_int = 12; +pub const NFPROTO_NUMPROTO: c_int = 13; + +// linux/netfilter_arp.h +pub const NF_ARP: c_int = 0; +pub const NF_ARP_IN: c_int = 0; +pub const NF_ARP_OUT: c_int = 1; +pub const NF_ARP_FORWARD: c_int = 2; +pub const NF_ARP_NUMHOOKS: c_int = 3; + +// linux/netfilter_bridge.h +pub const NF_BR_PRE_ROUTING: c_int = 0; +pub const NF_BR_LOCAL_IN: c_int = 1; +pub const NF_BR_FORWARD: c_int = 2; +pub const NF_BR_LOCAL_OUT: c_int = 3; +pub const NF_BR_POST_ROUTING: c_int = 4; +pub const NF_BR_BROUTING: c_int = 5; +pub const NF_BR_NUMHOOKS: c_int = 6; + +pub const NF_BR_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_BR_PRI_NAT_DST_BRIDGED: c_int = -300; +pub const NF_BR_PRI_FILTER_BRIDGED: c_int = -200; +pub const NF_BR_PRI_BRNF: c_int = 0; +pub const NF_BR_PRI_NAT_DST_OTHER: c_int = 100; +pub const NF_BR_PRI_FILTER_OTHER: c_int = 200; +pub const NF_BR_PRI_NAT_SRC: c_int = 300; +pub const NF_BR_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv4.h +pub const NF_IP_PRE_ROUTING: c_int = 0; +pub const NF_IP_LOCAL_IN: c_int = 1; +pub const NF_IP_FORWARD: c_int = 2; +pub const NF_IP_LOCAL_OUT: c_int = 3; +pub const NF_IP_POST_ROUTING: c_int = 4; +pub const NF_IP_NUMHOOKS: c_int = 5; + +pub const NF_IP_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_IP_PRI_RAW_BEFORE_DEFRAG: c_int = -450; +pub const NF_IP_PRI_CONNTRACK_DEFRAG: c_int = -400; +pub const NF_IP_PRI_RAW: c_int = -300; +pub const NF_IP_PRI_SELINUX_FIRST: c_int = -225; +pub const NF_IP_PRI_CONNTRACK: c_int = -200; +pub const NF_IP_PRI_MANGLE: c_int = -150; +pub const NF_IP_PRI_NAT_DST: c_int = -100; +pub const NF_IP_PRI_FILTER: c_int = 0; +pub const NF_IP_PRI_SECURITY: c_int = 50; +pub const NF_IP_PRI_NAT_SRC: c_int = 100; +pub const NF_IP_PRI_SELINUX_LAST: c_int = 225; +pub const NF_IP_PRI_CONNTRACK_HELPER: c_int = 300; +pub const NF_IP_PRI_CONNTRACK_CONFIRM: c_int = crate::INT_MAX; +pub const NF_IP_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv6.h +pub const NF_IP6_PRE_ROUTING: c_int = 0; +pub const NF_IP6_LOCAL_IN: c_int = 1; +pub const NF_IP6_FORWARD: c_int = 2; +pub const NF_IP6_LOCAL_OUT: c_int = 3; +pub const NF_IP6_POST_ROUTING: c_int = 4; +pub const NF_IP6_NUMHOOKS: c_int = 5; + +pub const NF_IP6_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_IP6_PRI_RAW_BEFORE_DEFRAG: c_int = -450; +pub const NF_IP6_PRI_CONNTRACK_DEFRAG: c_int = -400; +pub const NF_IP6_PRI_RAW: c_int = -300; +pub const NF_IP6_PRI_SELINUX_FIRST: c_int = -225; +pub const NF_IP6_PRI_CONNTRACK: c_int = -200; +pub const NF_IP6_PRI_MANGLE: c_int = -150; +pub const NF_IP6_PRI_NAT_DST: c_int = -100; +pub const NF_IP6_PRI_FILTER: c_int = 0; +pub const NF_IP6_PRI_SECURITY: c_int = 50; +pub const NF_IP6_PRI_NAT_SRC: c_int = 100; +pub const NF_IP6_PRI_SELINUX_LAST: c_int = 225; +pub const NF_IP6_PRI_CONNTRACK_HELPER: c_int = 300; +pub const NF_IP6_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv6/ip6_tables.h +pub const IP6T_SO_ORIGINAL_DST: c_int = 80; + +// linux/netfilter/nf_tables.h +pub const NFT_TABLE_MAXNAMELEN: c_int = 256; +pub const NFT_CHAIN_MAXNAMELEN: c_int = 256; +pub const NFT_SET_MAXNAMELEN: c_int = 256; +pub const NFT_OBJ_MAXNAMELEN: c_int = 256; +pub const NFT_USERDATA_MAXLEN: c_int = 256; + +pub const NFT_REG_VERDICT: c_int = 0; +pub const NFT_REG_1: c_int = 1; +pub const NFT_REG_2: c_int = 2; +pub const NFT_REG_3: c_int = 3; +pub const NFT_REG_4: c_int = 4; +pub const __NFT_REG_MAX: c_int = 5; +pub const NFT_REG32_00: c_int = 8; +pub const NFT_REG32_01: c_int = 9; +pub const NFT_REG32_02: c_int = 10; +pub const NFT_REG32_03: c_int = 11; +pub const NFT_REG32_04: c_int = 12; +pub const NFT_REG32_05: c_int = 13; +pub const NFT_REG32_06: c_int = 14; +pub const NFT_REG32_07: c_int = 15; +pub const NFT_REG32_08: c_int = 16; +pub const NFT_REG32_09: c_int = 17; +pub const NFT_REG32_10: c_int = 18; +pub const NFT_REG32_11: c_int = 19; +pub const NFT_REG32_12: c_int = 20; +pub const NFT_REG32_13: c_int = 21; +pub const NFT_REG32_14: c_int = 22; +pub const NFT_REG32_15: c_int = 23; + +pub const NFT_REG_SIZE: c_int = 16; +pub const NFT_REG32_SIZE: c_int = 4; + +pub const NFT_CONTINUE: c_int = -1; +pub const NFT_BREAK: c_int = -2; +pub const NFT_JUMP: c_int = -3; +pub const NFT_GOTO: c_int = -4; +pub const NFT_RETURN: c_int = -5; + +pub const NFT_MSG_NEWTABLE: c_int = 0; +pub const NFT_MSG_GETTABLE: c_int = 1; +pub const NFT_MSG_DELTABLE: c_int = 2; +pub const NFT_MSG_NEWCHAIN: c_int = 3; +pub const NFT_MSG_GETCHAIN: c_int = 4; +pub const NFT_MSG_DELCHAIN: c_int = 5; +pub const NFT_MSG_NEWRULE: c_int = 6; +pub const NFT_MSG_GETRULE: c_int = 7; +pub const NFT_MSG_DELRULE: c_int = 8; +pub const NFT_MSG_NEWSET: c_int = 9; +pub const NFT_MSG_GETSET: c_int = 10; +pub const NFT_MSG_DELSET: c_int = 11; +pub const NFT_MSG_NEWSETELEM: c_int = 12; +pub const NFT_MSG_GETSETELEM: c_int = 13; +pub const NFT_MSG_DELSETELEM: c_int = 14; +pub const NFT_MSG_NEWGEN: c_int = 15; +pub const NFT_MSG_GETGEN: c_int = 16; +pub const NFT_MSG_TRACE: c_int = 17; +pub const NFT_MSG_NEWOBJ: c_int = 18; +pub const NFT_MSG_GETOBJ: c_int = 19; +pub const NFT_MSG_DELOBJ: c_int = 20; +pub const NFT_MSG_GETOBJ_RESET: c_int = 21; +pub const NFT_MSG_MAX: c_int = 25; + +pub const NFT_SET_ANONYMOUS: c_int = 0x1; +pub const NFT_SET_CONSTANT: c_int = 0x2; +pub const NFT_SET_INTERVAL: c_int = 0x4; +pub const NFT_SET_MAP: c_int = 0x8; +pub const NFT_SET_TIMEOUT: c_int = 0x10; +pub const NFT_SET_EVAL: c_int = 0x20; + +pub const NFT_SET_POL_PERFORMANCE: c_int = 0; +pub const NFT_SET_POL_MEMORY: c_int = 1; + +pub const NFT_SET_ELEM_INTERVAL_END: c_int = 0x1; + +pub const NFT_DATA_VALUE: c_uint = 0; +pub const NFT_DATA_VERDICT: c_uint = 0xffffff00; + +pub const NFT_DATA_RESERVED_MASK: c_uint = 0xffffff00; + +pub const NFT_DATA_VALUE_MAXLEN: c_int = 64; + +pub const NFT_BYTEORDER_NTOH: c_int = 0; +pub const NFT_BYTEORDER_HTON: c_int = 1; + +pub const NFT_CMP_EQ: c_int = 0; +pub const NFT_CMP_NEQ: c_int = 1; +pub const NFT_CMP_LT: c_int = 2; +pub const NFT_CMP_LTE: c_int = 3; +pub const NFT_CMP_GT: c_int = 4; +pub const NFT_CMP_GTE: c_int = 5; + +pub const NFT_RANGE_EQ: c_int = 0; +pub const NFT_RANGE_NEQ: c_int = 1; + +pub const NFT_LOOKUP_F_INV: c_int = 1 << 0; + +pub const NFT_DYNSET_OP_ADD: c_int = 0; +pub const NFT_DYNSET_OP_UPDATE: c_int = 1; + +pub const NFT_DYNSET_F_INV: c_int = 1 << 0; + +pub const NFT_PAYLOAD_LL_HEADER: c_int = 0; +pub const NFT_PAYLOAD_NETWORK_HEADER: c_int = 1; +pub const NFT_PAYLOAD_TRANSPORT_HEADER: c_int = 2; + +pub const NFT_PAYLOAD_CSUM_NONE: c_int = 0; +pub const NFT_PAYLOAD_CSUM_INET: c_int = 1; + +pub const NFT_META_LEN: c_int = 0; +pub const NFT_META_PROTOCOL: c_int = 1; +pub const NFT_META_PRIORITY: c_int = 2; +pub const NFT_META_MARK: c_int = 3; +pub const NFT_META_IIF: c_int = 4; +pub const NFT_META_OIF: c_int = 5; +pub const NFT_META_IIFNAME: c_int = 6; +pub const NFT_META_OIFNAME: c_int = 7; +pub const NFT_META_IIFTYPE: c_int = 8; +pub const NFT_META_OIFTYPE: c_int = 9; +pub const NFT_META_SKUID: c_int = 10; +pub const NFT_META_SKGID: c_int = 11; +pub const NFT_META_NFTRACE: c_int = 12; +pub const NFT_META_RTCLASSID: c_int = 13; +pub const NFT_META_SECMARK: c_int = 14; +pub const NFT_META_NFPROTO: c_int = 15; +pub const NFT_META_L4PROTO: c_int = 16; +pub const NFT_META_BRI_IIFNAME: c_int = 17; +pub const NFT_META_BRI_OIFNAME: c_int = 18; +pub const NFT_META_PKTTYPE: c_int = 19; +pub const NFT_META_CPU: c_int = 20; +pub const NFT_META_IIFGROUP: c_int = 21; +pub const NFT_META_OIFGROUP: c_int = 22; +pub const NFT_META_CGROUP: c_int = 23; +pub const NFT_META_PRANDOM: c_int = 24; + +pub const NFT_CT_STATE: c_int = 0; +pub const NFT_CT_DIRECTION: c_int = 1; +pub const NFT_CT_STATUS: c_int = 2; +pub const NFT_CT_MARK: c_int = 3; +pub const NFT_CT_SECMARK: c_int = 4; +pub const NFT_CT_EXPIRATION: c_int = 5; +pub const NFT_CT_HELPER: c_int = 6; +pub const NFT_CT_L3PROTOCOL: c_int = 7; +pub const NFT_CT_SRC: c_int = 8; +pub const NFT_CT_DST: c_int = 9; +pub const NFT_CT_PROTOCOL: c_int = 10; +pub const NFT_CT_PROTO_SRC: c_int = 11; +pub const NFT_CT_PROTO_DST: c_int = 12; +pub const NFT_CT_LABELS: c_int = 13; +pub const NFT_CT_PKTS: c_int = 14; +pub const NFT_CT_BYTES: c_int = 15; +pub const NFT_CT_AVGPKT: c_int = 16; +pub const NFT_CT_ZONE: c_int = 17; +pub const NFT_CT_EVENTMASK: c_int = 18; +pub const NFT_CT_SRC_IP: c_int = 19; +pub const NFT_CT_DST_IP: c_int = 20; +pub const NFT_CT_SRC_IP6: c_int = 21; +pub const NFT_CT_DST_IP6: c_int = 22; +pub const NFT_CT_ID: c_int = 23; + +pub const NFT_LIMIT_PKTS: c_int = 0; +pub const NFT_LIMIT_PKT_BYTES: c_int = 1; + +pub const NFT_LIMIT_F_INV: c_int = 1 << 0; + +pub const NFT_QUEUE_FLAG_BYPASS: c_int = 0x01; +pub const NFT_QUEUE_FLAG_CPU_FANOUT: c_int = 0x02; +pub const NFT_QUEUE_FLAG_MASK: c_int = 0x03; + +pub const NFT_QUOTA_F_INV: c_int = 1 << 0; + +pub const NFT_REJECT_ICMP_UNREACH: c_int = 0; +pub const NFT_REJECT_TCP_RST: c_int = 1; +pub const NFT_REJECT_ICMPX_UNREACH: c_int = 2; + +pub const NFT_REJECT_ICMPX_NO_ROUTE: c_int = 0; +pub const NFT_REJECT_ICMPX_PORT_UNREACH: c_int = 1; +pub const NFT_REJECT_ICMPX_HOST_UNREACH: c_int = 2; +pub const NFT_REJECT_ICMPX_ADMIN_PROHIBITED: c_int = 3; + +pub const NFT_NAT_SNAT: c_int = 0; +pub const NFT_NAT_DNAT: c_int = 1; + +pub const NFT_TRACETYPE_UNSPEC: c_int = 0; +pub const NFT_TRACETYPE_POLICY: c_int = 1; +pub const NFT_TRACETYPE_RETURN: c_int = 2; +pub const NFT_TRACETYPE_RULE: c_int = 3; + +pub const NFT_NG_INCREMENTAL: c_int = 0; +pub const NFT_NG_RANDOM: c_int = 1; + +// linux/input.h +pub const FF_MAX: crate::__u16 = 0x7f; +pub const FF_CNT: usize = FF_MAX as usize + 1; + +// linux/input-event-codes.h +pub const INPUT_PROP_MAX: crate::__u16 = 0x1f; +pub const INPUT_PROP_CNT: usize = INPUT_PROP_MAX as usize + 1; +pub const EV_MAX: crate::__u16 = 0x1f; +pub const EV_CNT: usize = EV_MAX as usize + 1; +pub const SYN_MAX: crate::__u16 = 0xf; +pub const SYN_CNT: usize = SYN_MAX as usize + 1; +pub const KEY_MAX: crate::__u16 = 0x2ff; +pub const KEY_CNT: usize = KEY_MAX as usize + 1; +pub const REL_MAX: crate::__u16 = 0x0f; +pub const REL_CNT: usize = REL_MAX as usize + 1; +pub const ABS_MAX: crate::__u16 = 0x3f; +pub const ABS_CNT: usize = ABS_MAX as usize + 1; +pub const SW_MAX: crate::__u16 = 0x0f; +pub const SW_CNT: usize = SW_MAX as usize + 1; +pub const MSC_MAX: crate::__u16 = 0x07; +pub const MSC_CNT: usize = MSC_MAX as usize + 1; +pub const LED_MAX: crate::__u16 = 0x0f; +pub const LED_CNT: usize = LED_MAX as usize + 1; +pub const REP_MAX: crate::__u16 = 0x01; +pub const REP_CNT: usize = REP_MAX as usize + 1; +pub const SND_MAX: crate::__u16 = 0x07; +pub const SND_CNT: usize = SND_MAX as usize + 1; + +// linux/uinput.h +pub const UINPUT_VERSION: c_uint = 5; +pub const UINPUT_MAX_NAME_SIZE: usize = 80; + +// start android/platform/bionic/libc/kernel/uapi/linux/if_ether.h +// from https://android.googlesource.com/platform/bionic/+/HEAD/libc/kernel/uapi/linux/if_ether.h +pub const ETH_ALEN: c_int = 6; +pub const ETH_HLEN: c_int = 14; +pub const ETH_ZLEN: c_int = 60; +pub const ETH_DATA_LEN: c_int = 1500; +pub const ETH_FRAME_LEN: c_int = 1514; +pub const ETH_FCS_LEN: c_int = 4; +pub const ETH_MIN_MTU: c_int = 68; +pub const ETH_MAX_MTU: c_int = 0xFFFF; +pub const ETH_P_LOOP: c_int = 0x0060; +pub const ETH_P_PUP: c_int = 0x0200; +pub const ETH_P_PUPAT: c_int = 0x0201; +pub const ETH_P_TSN: c_int = 0x22F0; +pub const ETH_P_IP: c_int = 0x0800; +pub const ETH_P_X25: c_int = 0x0805; +pub const ETH_P_ARP: c_int = 0x0806; +pub const ETH_P_BPQ: c_int = 0x08FF; +pub const ETH_P_IEEEPUP: c_int = 0x0a00; +pub const ETH_P_IEEEPUPAT: c_int = 0x0a01; +pub const ETH_P_BATMAN: c_int = 0x4305; +pub const ETH_P_DEC: c_int = 0x6000; +pub const ETH_P_DNA_DL: c_int = 0x6001; +pub const ETH_P_DNA_RC: c_int = 0x6002; +pub const ETH_P_DNA_RT: c_int = 0x6003; +pub const ETH_P_LAT: c_int = 0x6004; +pub const ETH_P_DIAG: c_int = 0x6005; +pub const ETH_P_CUST: c_int = 0x6006; +pub const ETH_P_SCA: c_int = 0x6007; +pub const ETH_P_TEB: c_int = 0x6558; +pub const ETH_P_RARP: c_int = 0x8035; +pub const ETH_P_ATALK: c_int = 0x809B; +pub const ETH_P_AARP: c_int = 0x80F3; +pub const ETH_P_8021Q: c_int = 0x8100; +/* see rust-lang/libc#924 pub const ETH_P_ERSPAN: c_int = 0x88BE;*/ +pub const ETH_P_IPX: c_int = 0x8137; +pub const ETH_P_IPV6: c_int = 0x86DD; +pub const ETH_P_PAUSE: c_int = 0x8808; +pub const ETH_P_SLOW: c_int = 0x8809; +pub const ETH_P_WCCP: c_int = 0x883E; +pub const ETH_P_MPLS_UC: c_int = 0x8847; +pub const ETH_P_MPLS_MC: c_int = 0x8848; +pub const ETH_P_ATMMPOA: c_int = 0x884c; +pub const ETH_P_PPP_DISC: c_int = 0x8863; +pub const ETH_P_PPP_SES: c_int = 0x8864; +pub const ETH_P_LINK_CTL: c_int = 0x886c; +pub const ETH_P_ATMFATE: c_int = 0x8884; +pub const ETH_P_PAE: c_int = 0x888E; +pub const ETH_P_AOE: c_int = 0x88A2; +pub const ETH_P_8021AD: c_int = 0x88A8; +pub const ETH_P_802_EX1: c_int = 0x88B5; +pub const ETH_P_TIPC: c_int = 0x88CA; +pub const ETH_P_MACSEC: c_int = 0x88E5; +pub const ETH_P_8021AH: c_int = 0x88E7; +pub const ETH_P_MVRP: c_int = 0x88F5; +pub const ETH_P_1588: c_int = 0x88F7; +pub const ETH_P_NCSI: c_int = 0x88F8; +pub const ETH_P_PRP: c_int = 0x88FB; +pub const ETH_P_FCOE: c_int = 0x8906; +/* see rust-lang/libc#924 pub const ETH_P_IBOE: c_int = 0x8915;*/ +pub const ETH_P_TDLS: c_int = 0x890D; +pub const ETH_P_FIP: c_int = 0x8914; +pub const ETH_P_80221: c_int = 0x8917; +pub const ETH_P_HSR: c_int = 0x892F; +/* see rust-lang/libc#924 pub const ETH_P_NSH: c_int = 0x894F;*/ +pub const ETH_P_LOOPBACK: c_int = 0x9000; +pub const ETH_P_QINQ1: c_int = 0x9100; +pub const ETH_P_QINQ2: c_int = 0x9200; +pub const ETH_P_QINQ3: c_int = 0x9300; +pub const ETH_P_EDSA: c_int = 0xDADA; +/* see rust-lang/libc#924 pub const ETH_P_IFE: c_int = 0xED3E;*/ +pub const ETH_P_AF_IUCV: c_int = 0xFBFB; +pub const ETH_P_802_3_MIN: c_int = 0x0600; +pub const ETH_P_802_3: c_int = 0x0001; +pub const ETH_P_AX25: c_int = 0x0002; +pub const ETH_P_ALL: c_int = 0x0003; +pub const ETH_P_802_2: c_int = 0x0004; +pub const ETH_P_SNAP: c_int = 0x0005; +pub const ETH_P_DDCMP: c_int = 0x0006; +pub const ETH_P_WAN_PPP: c_int = 0x0007; +pub const ETH_P_PPP_MP: c_int = 0x0008; +pub const ETH_P_LOCALTALK: c_int = 0x0009; +pub const ETH_P_CAN: c_int = 0x000C; +pub const ETH_P_CANFD: c_int = 0x000D; +pub const ETH_P_PPPTALK: c_int = 0x0010; +pub const ETH_P_TR_802_2: c_int = 0x0011; +pub const ETH_P_MOBITEX: c_int = 0x0015; +pub const ETH_P_CONTROL: c_int = 0x0016; +pub const ETH_P_IRDA: c_int = 0x0017; +pub const ETH_P_ECONET: c_int = 0x0018; +pub const ETH_P_HDLC: c_int = 0x0019; +pub const ETH_P_ARCNET: c_int = 0x001A; +pub const ETH_P_DSA: c_int = 0x001B; +pub const ETH_P_TRAILER: c_int = 0x001C; +pub const ETH_P_PHONET: c_int = 0x00F5; +pub const ETH_P_IEEE802154: c_int = 0x00F6; +pub const ETH_P_CAIF: c_int = 0x00F7; +pub const ETH_P_XDSA: c_int = 0x00F8; +/* see rust-lang/libc#924 pub const ETH_P_MAP: c_int = 0x00F9;*/ +// end android/platform/bionic/libc/kernel/uapi/linux/if_ether.h + +// start android/platform/bionic/libc/kernel/uapi/linux/neighbour.h +pub const NDA_UNSPEC: c_ushort = 0; +pub const NDA_DST: c_ushort = 1; +pub const NDA_LLADDR: c_ushort = 2; +pub const NDA_CACHEINFO: c_ushort = 3; +pub const NDA_PROBES: c_ushort = 4; +pub const NDA_VLAN: c_ushort = 5; +pub const NDA_PORT: c_ushort = 6; +pub const NDA_VNI: c_ushort = 7; +pub const NDA_IFINDEX: c_ushort = 8; +pub const NDA_MASTER: c_ushort = 9; +pub const NDA_LINK_NETNSID: c_ushort = 10; +pub const NDA_SRC_VNI: c_ushort = 11; +pub const NDA_PROTOCOL: c_ushort = 12; +pub const NDA_NH_ID: c_ushort = 13; +pub const NDA_FDB_EXT_ATTRS: c_ushort = 14; +pub const NDA_FLAGS_EXT: c_ushort = 15; +pub const NDA_NDM_STATE_MASK: c_ushort = 16; +pub const NDA_NDM_FLAGS_MASK: c_ushort = 17; + +pub const NTF_USE: u8 = 0x01; +pub const NTF_SELF: u8 = 0x02; +pub const NTF_MASTER: u8 = 0x04; +pub const NTF_PROXY: u8 = 0x08; +pub const NTF_EXT_LEARNED: u8 = 0x10; +pub const NTF_OFFLOADED: u8 = 0x20; +pub const NTF_STICKY: u8 = 0x40; +pub const NTF_ROUTER: u8 = 0x80; + +pub const NTF_EXT_MANAGED: u8 = 0x01; +pub const NTF_EXT_LOCKED: u8 = 0x02; + +pub const NUD_NONE: u16 = 0x00; +pub const NUD_INCOMPLETE: u16 = 0x01; +pub const NUD_REACHABLE: u16 = 0x02; +pub const NUD_STALE: u16 = 0x04; +pub const NUD_DELAY: u16 = 0x08; +pub const NUD_PROBE: u16 = 0x10; +pub const NUD_FAILED: u16 = 0x20; +pub const NUD_NOARP: u16 = 0x40; +pub const NUD_PERMANENT: u16 = 0x80; + +pub const NDTPA_UNSPEC: c_ushort = 0; +pub const NDTPA_IFINDEX: c_ushort = 1; +pub const NDTPA_REFCNT: c_ushort = 2; +pub const NDTPA_REACHABLE_TIME: c_ushort = 3; +pub const NDTPA_BASE_REACHABLE_TIME: c_ushort = 4; +pub const NDTPA_RETRANS_TIME: c_ushort = 5; +pub const NDTPA_GC_STALETIME: c_ushort = 6; +pub const NDTPA_DELAY_PROBE_TIME: c_ushort = 7; +pub const NDTPA_QUEUE_LEN: c_ushort = 8; +pub const NDTPA_APP_PROBES: c_ushort = 9; +pub const NDTPA_UCAST_PROBES: c_ushort = 10; +pub const NDTPA_MCAST_PROBES: c_ushort = 11; +pub const NDTPA_ANYCAST_DELAY: c_ushort = 12; +pub const NDTPA_PROXY_DELAY: c_ushort = 13; +pub const NDTPA_PROXY_QLEN: c_ushort = 14; +pub const NDTPA_LOCKTIME: c_ushort = 15; +pub const NDTPA_QUEUE_LENBYTES: c_ushort = 16; +pub const NDTPA_MCAST_REPROBES: c_ushort = 17; +pub const NDTPA_PAD: c_ushort = 18; +pub const NDTPA_INTERVAL_PROBE_TIME_MS: c_ushort = 19; + +pub const NDTA_UNSPEC: c_ushort = 0; +pub const NDTA_NAME: c_ushort = 1; +pub const NDTA_THRESH1: c_ushort = 2; +pub const NDTA_THRESH2: c_ushort = 3; +pub const NDTA_THRESH3: c_ushort = 4; +pub const NDTA_CONFIG: c_ushort = 5; +pub const NDTA_PARMS: c_ushort = 6; +pub const NDTA_STATS: c_ushort = 7; +pub const NDTA_GC_INTERVAL: c_ushort = 8; +pub const NDTA_PAD: c_ushort = 9; + +pub const FDB_NOTIFY_BIT: u16 = 0x01; +pub const FDB_NOTIFY_INACTIVE_BIT: u16 = 0x02; + +pub const NFEA_UNSPEC: c_ushort = 0; +pub const NFEA_ACTIVITY_NOTIFY: c_ushort = 1; +pub const NFEA_DONT_REFRESH: c_ushort = 2; +// end android/platform/bionic/libc/kernel/uapi/linux/neighbour.h + +pub const SIOCADDRT: c_ulong = 0x0000890B; +pub const SIOCDELRT: c_ulong = 0x0000890C; +pub const SIOCRTMSG: c_ulong = 0x0000890D; +pub const SIOCGIFNAME: c_ulong = 0x00008910; +pub const SIOCSIFLINK: c_ulong = 0x00008911; +pub const SIOCGIFCONF: c_ulong = 0x00008912; +pub const SIOCGIFFLAGS: c_ulong = 0x00008913; +pub const SIOCSIFFLAGS: c_ulong = 0x00008914; +pub const SIOCGIFADDR: c_ulong = 0x00008915; +pub const SIOCSIFADDR: c_ulong = 0x00008916; +pub const SIOCGIFDSTADDR: c_ulong = 0x00008917; +pub const SIOCSIFDSTADDR: c_ulong = 0x00008918; +pub const SIOCGIFBRDADDR: c_ulong = 0x00008919; +pub const SIOCSIFBRDADDR: c_ulong = 0x0000891A; +pub const SIOCGIFNETMASK: c_ulong = 0x0000891B; +pub const SIOCSIFNETMASK: c_ulong = 0x0000891C; +pub const SIOCGIFMETRIC: c_ulong = 0x0000891D; +pub const SIOCSIFMETRIC: c_ulong = 0x0000891E; +pub const SIOCGIFMEM: c_ulong = 0x0000891F; +pub const SIOCSIFMEM: c_ulong = 0x00008920; +pub const SIOCGIFMTU: c_ulong = 0x00008921; +pub const SIOCSIFMTU: c_ulong = 0x00008922; +pub const SIOCSIFNAME: c_ulong = 0x00008923; +pub const SIOCSIFHWADDR: c_ulong = 0x00008924; +pub const SIOCGIFENCAP: c_ulong = 0x00008925; +pub const SIOCSIFENCAP: c_ulong = 0x00008926; +pub const SIOCGIFHWADDR: c_ulong = 0x00008927; +pub const SIOCGIFSLAVE: c_ulong = 0x00008929; +pub const SIOCSIFSLAVE: c_ulong = 0x00008930; +pub const SIOCADDMULTI: c_ulong = 0x00008931; +pub const SIOCDELMULTI: c_ulong = 0x00008932; +pub const SIOCGIFINDEX: c_ulong = 0x00008933; +pub const SIOGIFINDEX: c_ulong = SIOCGIFINDEX; +pub const SIOCSIFPFLAGS: c_ulong = 0x00008934; +pub const SIOCGIFPFLAGS: c_ulong = 0x00008935; +pub const SIOCDIFADDR: c_ulong = 0x00008936; +pub const SIOCSIFHWBROADCAST: c_ulong = 0x00008937; +pub const SIOCGIFCOUNT: c_ulong = 0x00008938; +pub const SIOCGIFBR: c_ulong = 0x00008940; +pub const SIOCSIFBR: c_ulong = 0x00008941; +pub const SIOCGIFTXQLEN: c_ulong = 0x00008942; +pub const SIOCSIFTXQLEN: c_ulong = 0x00008943; +pub const SIOCETHTOOL: c_ulong = 0x00008946; +pub const SIOCGMIIPHY: c_ulong = 0x00008947; +pub const SIOCGMIIREG: c_ulong = 0x00008948; +pub const SIOCSMIIREG: c_ulong = 0x00008949; +pub const SIOCWANDEV: c_ulong = 0x0000894A; +pub const SIOCOUTQNSD: c_ulong = 0x0000894B; +pub const SIOCGSKNS: c_ulong = 0x0000894C; +pub const SIOCDARP: c_ulong = 0x00008953; +pub const SIOCGARP: c_ulong = 0x00008954; +pub const SIOCSARP: c_ulong = 0x00008955; +pub const SIOCDRARP: c_ulong = 0x00008960; +pub const SIOCGRARP: c_ulong = 0x00008961; +pub const SIOCSRARP: c_ulong = 0x00008962; +pub const SIOCGIFMAP: c_ulong = 0x00008970; +pub const SIOCSIFMAP: c_ulong = 0x00008971; +pub const SIOCADDDLCI: c_ulong = 0x00008980; +pub const SIOCDELDLCI: c_ulong = 0x00008981; +pub const SIOCGIFVLAN: c_ulong = 0x00008982; +pub const SIOCSIFVLAN: c_ulong = 0x00008983; +pub const SIOCBONDENSLAVE: c_ulong = 0x00008990; +pub const SIOCBONDRELEASE: c_ulong = 0x00008991; +pub const SIOCBONDSETHWADDR: c_ulong = 0x00008992; +pub const SIOCBONDSLAVEINFOQUERY: c_ulong = 0x00008993; +pub const SIOCBONDINFOQUERY: c_ulong = 0x00008994; +pub const SIOCBONDCHANGEACTIVE: c_ulong = 0x00008995; +pub const SIOCBRADDBR: c_ulong = 0x000089a0; +pub const SIOCBRDELBR: c_ulong = 0x000089a1; +pub const SIOCBRADDIF: c_ulong = 0x000089a2; +pub const SIOCBRDELIF: c_ulong = 0x000089a3; +pub const SIOCSHWTSTAMP: c_ulong = 0x000089b0; +pub const SIOCGHWTSTAMP: c_ulong = 0x000089b1; +pub const SIOCDEVPRIVATE: c_ulong = 0x000089F0; +pub const SIOCPROTOPRIVATE: c_ulong = 0x000089E0; + +// linux/module.h +pub const MODULE_INIT_IGNORE_MODVERSIONS: c_uint = 0x0001; +pub const MODULE_INIT_IGNORE_VERMAGIC: c_uint = 0x0002; + +// linux/net_tstamp.h +pub const SOF_TIMESTAMPING_TX_HARDWARE: c_uint = 1 << 0; +pub const SOF_TIMESTAMPING_TX_SOFTWARE: c_uint = 1 << 1; +pub const SOF_TIMESTAMPING_RX_HARDWARE: c_uint = 1 << 2; +pub const SOF_TIMESTAMPING_RX_SOFTWARE: c_uint = 1 << 3; +pub const SOF_TIMESTAMPING_SOFTWARE: c_uint = 1 << 4; +pub const SOF_TIMESTAMPING_SYS_HARDWARE: c_uint = 1 << 5; +pub const SOF_TIMESTAMPING_RAW_HARDWARE: c_uint = 1 << 6; +pub const SOF_TIMESTAMPING_OPT_ID: c_uint = 1 << 7; +pub const SOF_TIMESTAMPING_TX_SCHED: c_uint = 1 << 8; +pub const SOF_TIMESTAMPING_TX_ACK: c_uint = 1 << 9; +pub const SOF_TIMESTAMPING_OPT_CMSG: c_uint = 1 << 10; +pub const SOF_TIMESTAMPING_OPT_TSONLY: c_uint = 1 << 11; +pub const SOF_TIMESTAMPING_OPT_STATS: c_uint = 1 << 12; +pub const SOF_TIMESTAMPING_OPT_PKTINFO: c_uint = 1 << 13; +pub const SOF_TIMESTAMPING_OPT_TX_SWHW: c_uint = 1 << 14; +pub const SOF_TIMESTAMPING_BIND_PHC: c_uint = 1 << 15; +pub const SOF_TIMESTAMPING_OPT_ID_TCP: c_uint = 1 << 16; +pub const SOF_TIMESTAMPING_OPT_RX_FILTER: c_uint = 1 << 17; + +#[deprecated( + since = "0.2.55", + note = "ENOATTR is not available on Android; use ENODATA instead" +)] +pub const ENOATTR: c_int = crate::ENODATA; + +// linux/if_alg.h +pub const ALG_SET_KEY: c_int = 1; +pub const ALG_SET_IV: c_int = 2; +pub const ALG_SET_OP: c_int = 3; +pub const ALG_SET_AEAD_ASSOCLEN: c_int = 4; +pub const ALG_SET_AEAD_AUTHSIZE: c_int = 5; +pub const ALG_SET_DRBG_ENTROPY: c_int = 6; + +pub const ALG_OP_DECRYPT: c_int = 0; +pub const ALG_OP_ENCRYPT: c_int = 1; + +// sys/mman.h +pub const MLOCK_ONFAULT: c_int = 0x01; + +// uapi/linux/vm_sockets.h +pub const VMADDR_CID_ANY: c_uint = 0xFFFFFFFF; +pub const VMADDR_CID_HYPERVISOR: c_uint = 0; +pub const VMADDR_CID_LOCAL: c_uint = 1; +pub const VMADDR_CID_HOST: c_uint = 2; +pub const VMADDR_PORT_ANY: c_uint = 0xFFFFFFFF; + +// uapi/linux/inotify.h +pub const IN_ACCESS: u32 = 0x0000_0001; +pub const IN_MODIFY: u32 = 0x0000_0002; +pub const IN_ATTRIB: u32 = 0x0000_0004; +pub const IN_CLOSE_WRITE: u32 = 0x0000_0008; +pub const IN_CLOSE_NOWRITE: u32 = 0x0000_0010; +pub const IN_CLOSE: u32 = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE; +pub const IN_OPEN: u32 = 0x0000_0020; +pub const IN_MOVED_FROM: u32 = 0x0000_0040; +pub const IN_MOVED_TO: u32 = 0x0000_0080; +pub const IN_MOVE: u32 = IN_MOVED_FROM | IN_MOVED_TO; +pub const IN_CREATE: u32 = 0x0000_0100; +pub const IN_DELETE: u32 = 0x0000_0200; +pub const IN_DELETE_SELF: u32 = 0x0000_0400; +pub const IN_MOVE_SELF: u32 = 0x0000_0800; +pub const IN_UNMOUNT: u32 = 0x0000_2000; +pub const IN_Q_OVERFLOW: u32 = 0x0000_4000; +pub const IN_IGNORED: u32 = 0x0000_8000; +pub const IN_ONLYDIR: u32 = 0x0100_0000; +pub const IN_DONT_FOLLOW: u32 = 0x0200_0000; +pub const IN_EXCL_UNLINK: u32 = 0x0400_0000; + +pub const IN_MASK_CREATE: u32 = 0x1000_0000; +pub const IN_MASK_ADD: u32 = 0x2000_0000; +pub const IN_ISDIR: u32 = 0x4000_0000; +pub const IN_ONESHOT: u32 = 0x8000_0000; + +pub const IN_ALL_EVENTS: u32 = IN_ACCESS + | IN_MODIFY + | IN_ATTRIB + | IN_CLOSE_WRITE + | IN_CLOSE_NOWRITE + | IN_OPEN + | IN_MOVED_FROM + | IN_MOVED_TO + | IN_DELETE + | IN_CREATE + | IN_DELETE_SELF + | IN_MOVE_SELF; + +pub const IN_CLOEXEC: c_int = O_CLOEXEC; +pub const IN_NONBLOCK: c_int = O_NONBLOCK; + +pub const FUTEX_WAIT: c_int = 0; +pub const FUTEX_WAKE: c_int = 1; +pub const FUTEX_FD: c_int = 2; +pub const FUTEX_REQUEUE: c_int = 3; +pub const FUTEX_CMP_REQUEUE: c_int = 4; +pub const FUTEX_WAKE_OP: c_int = 5; +pub const FUTEX_LOCK_PI: c_int = 6; +pub const FUTEX_UNLOCK_PI: c_int = 7; +pub const FUTEX_TRYLOCK_PI: c_int = 8; +pub const FUTEX_WAIT_BITSET: c_int = 9; +pub const FUTEX_WAKE_BITSET: c_int = 10; +pub const FUTEX_WAIT_REQUEUE_PI: c_int = 11; +pub const FUTEX_CMP_REQUEUE_PI: c_int = 12; +pub const FUTEX_LOCK_PI2: c_int = 13; + +pub const FUTEX_PRIVATE_FLAG: c_int = 128; +pub const FUTEX_CLOCK_REALTIME: c_int = 256; +pub const FUTEX_CMD_MASK: c_int = !(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); + +// linux/errqueue.h +pub const SO_EE_ORIGIN_NONE: u8 = 0; +pub const SO_EE_ORIGIN_LOCAL: u8 = 1; +pub const SO_EE_ORIGIN_ICMP: u8 = 2; +pub const SO_EE_ORIGIN_ICMP6: u8 = 3; +pub const SO_EE_ORIGIN_TXSTATUS: u8 = 4; +pub const SO_EE_ORIGIN_TIMESTAMPING: u8 = SO_EE_ORIGIN_TXSTATUS; + +// errno.h +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +// linux/sched.h +pub const SCHED_NORMAL: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_BATCH: c_int = 3; +pub const SCHED_IDLE: c_int = 5; +pub const SCHED_DEADLINE: c_int = 6; + +pub const SCHED_RESET_ON_FORK: c_int = 0x40000000; + +pub const CLONE_PIDFD: c_int = 0x1000; +pub const CLONE_CLEAR_SIGHAND: c_ulonglong = 0x100000000; +pub const CLONE_INTO_CGROUP: c_ulonglong = 0x200000000; + +// linux/membarrier.h +pub const MEMBARRIER_CMD_QUERY: c_int = 0; +pub const MEMBARRIER_CMD_GLOBAL: c_int = 1 << 0; +pub const MEMBARRIER_CMD_GLOBAL_EXPEDITED: c_int = 1 << 1; +pub const MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED: c_int = 1 << 2; +pub const MEMBARRIER_CMD_PRIVATE_EXPEDITED: c_int = 1 << 3; +pub const MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED: c_int = 1 << 4; +pub const MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE: c_int = 1 << 5; +pub const MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE: c_int = 1 << 6; +pub const MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ: c_int = 1 << 7; +pub const MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ: c_int = 1 << 8; + +// linux/mempolicy.h +pub const MPOL_DEFAULT: c_int = 0; +pub const MPOL_PREFERRED: c_int = 1; +pub const MPOL_BIND: c_int = 2; +pub const MPOL_INTERLEAVE: c_int = 3; +pub const MPOL_LOCAL: c_int = 4; +pub const MPOL_F_NUMA_BALANCING: c_int = 1 << 13; +pub const MPOL_F_RELATIVE_NODES: c_int = 1 << 14; +pub const MPOL_F_STATIC_NODES: c_int = 1 << 15; + +// bits/seek_constants.h +pub const SEEK_DATA: c_int = 3; +pub const SEEK_HOLE: c_int = 4; + +// sys/socket.h +pub const AF_NFC: c_int = 39; +pub const AF_VSOCK: c_int = 40; +pub const PF_NFC: c_int = AF_NFC; +pub const PF_VSOCK: c_int = AF_VSOCK; + +pub const SOMAXCONN: c_int = 128; + +// sys/system_properties.h +pub const PROP_VALUE_MAX: c_int = 92; +pub const PROP_NAME_MAX: c_int = 32; + +// sys/prctl.h +pub const PR_SET_PDEATHSIG: c_int = 1; +pub const PR_GET_PDEATHSIG: c_int = 2; +pub const PR_GET_DUMPABLE: c_int = 3; +pub const PR_SET_DUMPABLE: c_int = 4; +pub const PR_GET_UNALIGN: c_int = 5; +pub const PR_SET_UNALIGN: c_int = 6; +pub const PR_UNALIGN_NOPRINT: c_int = 1; +pub const PR_UNALIGN_SIGBUS: c_int = 2; +pub const PR_GET_KEEPCAPS: c_int = 7; +pub const PR_SET_KEEPCAPS: c_int = 8; +pub const PR_GET_FPEMU: c_int = 9; +pub const PR_SET_FPEMU: c_int = 10; +pub const PR_FPEMU_NOPRINT: c_int = 1; +pub const PR_FPEMU_SIGFPE: c_int = 2; +pub const PR_GET_FPEXC: c_int = 11; +pub const PR_SET_FPEXC: c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: c_int = 0x80; +pub const PR_FP_EXC_DIV: c_int = 0x010000; +pub const PR_FP_EXC_OVF: c_int = 0x020000; +pub const PR_FP_EXC_UND: c_int = 0x040000; +pub const PR_FP_EXC_RES: c_int = 0x080000; +pub const PR_FP_EXC_INV: c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: c_int = 0; +pub const PR_FP_EXC_NONRECOV: c_int = 1; +pub const PR_FP_EXC_ASYNC: c_int = 2; +pub const PR_FP_EXC_PRECISE: c_int = 3; +pub const PR_GET_TIMING: c_int = 13; +pub const PR_SET_TIMING: c_int = 14; +pub const PR_TIMING_STATISTICAL: c_int = 0; +pub const PR_TIMING_TIMESTAMP: c_int = 1; +pub const PR_SET_NAME: c_int = 15; +pub const PR_GET_NAME: c_int = 16; +pub const PR_GET_ENDIAN: c_int = 19; +pub const PR_SET_ENDIAN: c_int = 20; +pub const PR_ENDIAN_BIG: c_int = 0; +pub const PR_ENDIAN_LITTLE: c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: c_int = 2; +pub const PR_GET_SECCOMP: c_int = 21; +pub const PR_SET_SECCOMP: c_int = 22; +pub const PR_CAPBSET_READ: c_int = 23; +pub const PR_CAPBSET_DROP: c_int = 24; +pub const PR_GET_TSC: c_int = 25; +pub const PR_SET_TSC: c_int = 26; +pub const PR_TSC_ENABLE: c_int = 1; +pub const PR_TSC_SIGSEGV: c_int = 2; +pub const PR_GET_SECUREBITS: c_int = 27; +pub const PR_SET_SECUREBITS: c_int = 28; +pub const PR_SET_TIMERSLACK: c_int = 29; +pub const PR_GET_TIMERSLACK: c_int = 30; +pub const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; +pub const PR_MCE_KILL: c_int = 33; +pub const PR_MCE_KILL_CLEAR: c_int = 0; +pub const PR_MCE_KILL_SET: c_int = 1; +pub const PR_MCE_KILL_LATE: c_int = 0; +pub const PR_MCE_KILL_EARLY: c_int = 1; +pub const PR_MCE_KILL_DEFAULT: c_int = 2; +pub const PR_MCE_KILL_GET: c_int = 34; +pub const PR_SET_MM: c_int = 35; +pub const PR_SET_MM_START_CODE: c_int = 1; +pub const PR_SET_MM_END_CODE: c_int = 2; +pub const PR_SET_MM_START_DATA: c_int = 3; +pub const PR_SET_MM_END_DATA: c_int = 4; +pub const PR_SET_MM_START_STACK: c_int = 5; +pub const PR_SET_MM_START_BRK: c_int = 6; +pub const PR_SET_MM_BRK: c_int = 7; +pub const PR_SET_MM_ARG_START: c_int = 8; +pub const PR_SET_MM_ARG_END: c_int = 9; +pub const PR_SET_MM_ENV_START: c_int = 10; +pub const PR_SET_MM_ENV_END: c_int = 11; +pub const PR_SET_MM_AUXV: c_int = 12; +pub const PR_SET_MM_EXE_FILE: c_int = 13; +pub const PR_SET_MM_MAP: c_int = 14; +pub const PR_SET_MM_MAP_SIZE: c_int = 15; +pub const PR_SET_PTRACER: c_int = 0x59616d61; +pub const PR_SET_PTRACER_ANY: c_ulong = 0xffffffffffffffff; +pub const PR_SET_CHILD_SUBREAPER: c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: c_int = 37; +pub const PR_SET_NO_NEW_PRIVS: c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: c_int = 39; +pub const PR_GET_TID_ADDRESS: c_int = 40; +pub const PR_SET_THP_DISABLE: c_int = 41; +pub const PR_GET_THP_DISABLE: c_int = 42; +pub const PR_MPX_ENABLE_MANAGEMENT: c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: c_int = 44; +pub const PR_SET_FP_MODE: c_int = 45; +pub const PR_GET_FP_MODE: c_int = 46; +pub const PR_FP_MODE_FR: c_int = 1 << 0; +pub const PR_FP_MODE_FRE: c_int = 1 << 1; +pub const PR_CAP_AMBIENT: c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: c_int = 4; +pub const PR_SVE_SET_VL: c_int = 50; +pub const PR_SVE_SET_VL_ONEXEC: c_int = 1 << 18; +pub const PR_SVE_GET_VL: c_int = 51; +pub const PR_SVE_VL_LEN_MASK: c_int = 0xffff; +pub const PR_SVE_VL_INHERIT: c_int = 1 << 17; +pub const PR_GET_SPECULATION_CTRL: c_int = 52; +pub const PR_SET_SPECULATION_CTRL: c_int = 53; +pub const PR_SPEC_STORE_BYPASS: c_int = 0; +pub const PR_SPEC_INDIRECT_BRANCH: c_int = 1; +pub const PR_SPEC_L1D_FLUSH: c_int = 2; +pub const PR_SPEC_NOT_AFFECTED: c_int = 0; +pub const PR_SPEC_PRCTL: c_ulong = 1 << 0; +pub const PR_SPEC_ENABLE: c_ulong = 1 << 1; +pub const PR_SPEC_DISABLE: c_ulong = 1 << 2; +pub const PR_SPEC_FORCE_DISABLE: c_ulong = 1 << 3; +pub const PR_SPEC_DISABLE_NOEXEC: c_ulong = 1 << 4; +pub const PR_PAC_RESET_KEYS: c_int = 54; +pub const PR_PAC_APIAKEY: c_ulong = 1 << 0; +pub const PR_PAC_APIBKEY: c_ulong = 1 << 1; +pub const PR_PAC_APDAKEY: c_ulong = 1 << 2; +pub const PR_PAC_APDBKEY: c_ulong = 1 << 3; +pub const PR_PAC_APGAKEY: c_ulong = 1 << 4; +pub const PR_SET_TAGGED_ADDR_CTRL: c_int = 55; +pub const PR_GET_TAGGED_ADDR_CTRL: c_int = 56; +pub const PR_TAGGED_ADDR_ENABLE: c_ulong = 1 << 0; +pub const PR_MTE_TCF_NONE: c_ulong = 0; +pub const PR_MTE_TCF_SYNC: c_ulong = 1 << 1; +pub const PR_MTE_TCF_ASYNC: c_ulong = 1 << 2; +pub const PR_MTE_TCF_MASK: c_ulong = PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC; +pub const PR_MTE_TAG_SHIFT: c_ulong = 3; +pub const PR_MTE_TAG_MASK: c_ulong = 0xffff << PR_MTE_TAG_SHIFT; +pub const PR_MTE_TCF_SHIFT: c_ulong = 1; +pub const PR_SET_IO_FLUSHER: c_int = 57; +pub const PR_GET_IO_FLUSHER: c_int = 58; +pub const PR_SET_SYSCALL_USER_DISPATCH: c_int = 59; +pub const PR_SYS_DISPATCH_OFF: c_int = 0; +pub const PR_SYS_DISPATCH_ON: c_int = 1; +pub const SYSCALL_DISPATCH_FILTER_ALLOW: c_int = 0; +pub const SYSCALL_DISPATCH_FILTER_BLOCK: c_int = 1; +pub const PR_PAC_SET_ENABLED_KEYS: c_int = 60; +pub const PR_PAC_GET_ENABLED_KEYS: c_int = 61; +pub const PR_SCHED_CORE: c_int = 62; +pub const PR_SCHED_CORE_GET: c_int = 0; +pub const PR_SCHED_CORE_CREATE: c_int = 1; +pub const PR_SCHED_CORE_SHARE_TO: c_int = 2; +pub const PR_SCHED_CORE_SHARE_FROM: c_int = 3; +pub const PR_SCHED_CORE_MAX: c_int = 4; +pub const PR_SCHED_CORE_SCOPE_THREAD: c_int = 0; +pub const PR_SCHED_CORE_SCOPE_THREAD_GROUP: c_int = 1; +pub const PR_SCHED_CORE_SCOPE_PROCESS_GROUP: c_int = 2; +pub const PR_SME_SET_VL: c_int = 63; +pub const PR_SME_SET_VL_ONEXEC: c_int = 1 << 18; +pub const PR_SME_GET_VL: c_int = 64; +pub const PR_SME_VL_LEN_MASK: c_int = 0xffff; +pub const PR_SME_VL_INHERIT: c_int = 1 << 17; +pub const PR_SET_MDWE: c_int = 65; +pub const PR_MDWE_REFUSE_EXEC_GAIN: c_ulong = 1 << 0; +pub const PR_MDWE_NO_INHERIT: c_ulong = 1 << 1; +pub const PR_GET_MDWE: c_int = 66; +pub const PR_SET_VMA: c_int = 0x53564d41; +pub const PR_SET_VMA_ANON_NAME: c_int = 0; +pub const PR_GET_AUXV: c_int = 0x41555856; +pub const PR_SET_MEMORY_MERGE: c_int = 67; +pub const PR_GET_MEMORY_MERGE: c_int = 68; +pub const PR_RISCV_V_SET_CONTROL: c_int = 69; +pub const PR_RISCV_V_GET_CONTROL: c_int = 70; +pub const PR_RISCV_V_VSTATE_CTRL_DEFAULT: c_int = 0; +pub const PR_RISCV_V_VSTATE_CTRL_OFF: c_int = 1; +pub const PR_RISCV_V_VSTATE_CTRL_ON: c_int = 2; +pub const PR_RISCV_V_VSTATE_CTRL_INHERIT: c_int = 1 << 4; +pub const PR_RISCV_V_VSTATE_CTRL_CUR_MASK: c_int = 0x3; +pub const PR_RISCV_V_VSTATE_CTRL_NEXT_MASK: c_int = 0xc; +pub const PR_RISCV_V_VSTATE_CTRL_MASK: c_int = 0x1f; + +// linux/if_addr.h +pub const IFA_UNSPEC: c_ushort = 0; +pub const IFA_ADDRESS: c_ushort = 1; +pub const IFA_LOCAL: c_ushort = 2; +pub const IFA_LABEL: c_ushort = 3; +pub const IFA_BROADCAST: c_ushort = 4; +pub const IFA_ANYCAST: c_ushort = 5; +pub const IFA_CACHEINFO: c_ushort = 6; +pub const IFA_MULTICAST: c_ushort = 7; + +pub const IFA_F_SECONDARY: u32 = 0x01; +pub const IFA_F_TEMPORARY: u32 = 0x01; +pub const IFA_F_NODAD: u32 = 0x02; +pub const IFA_F_OPTIMISTIC: u32 = 0x04; +pub const IFA_F_DADFAILED: u32 = 0x08; +pub const IFA_F_HOMEADDRESS: u32 = 0x10; +pub const IFA_F_DEPRECATED: u32 = 0x20; +pub const IFA_F_TENTATIVE: u32 = 0x40; +pub const IFA_F_PERMANENT: u32 = 0x80; + +// linux/if_link.h +pub const IFLA_UNSPEC: c_ushort = 0; +pub const IFLA_ADDRESS: c_ushort = 1; +pub const IFLA_BROADCAST: c_ushort = 2; +pub const IFLA_IFNAME: c_ushort = 3; +pub const IFLA_MTU: c_ushort = 4; +pub const IFLA_LINK: c_ushort = 5; +pub const IFLA_QDISC: c_ushort = 6; +pub const IFLA_STATS: c_ushort = 7; +pub const IFLA_COST: c_ushort = 8; +pub const IFLA_PRIORITY: c_ushort = 9; +pub const IFLA_MASTER: c_ushort = 10; +pub const IFLA_WIRELESS: c_ushort = 11; +pub const IFLA_PROTINFO: c_ushort = 12; +pub const IFLA_TXQLEN: c_ushort = 13; +pub const IFLA_MAP: c_ushort = 14; +pub const IFLA_WEIGHT: c_ushort = 15; +pub const IFLA_OPERSTATE: c_ushort = 16; +pub const IFLA_LINKMODE: c_ushort = 17; +pub const IFLA_LINKINFO: c_ushort = 18; +pub const IFLA_NET_NS_PID: c_ushort = 19; +pub const IFLA_IFALIAS: c_ushort = 20; +pub const IFLA_NUM_VF: c_ushort = 21; +pub const IFLA_VFINFO_LIST: c_ushort = 22; +pub const IFLA_STATS64: c_ushort = 23; +pub const IFLA_VF_PORTS: c_ushort = 24; +pub const IFLA_PORT_SELF: c_ushort = 25; +pub const IFLA_AF_SPEC: c_ushort = 26; +pub const IFLA_GROUP: c_ushort = 27; +pub const IFLA_NET_NS_FD: c_ushort = 28; +pub const IFLA_EXT_MASK: c_ushort = 29; +pub const IFLA_PROMISCUITY: c_ushort = 30; +pub const IFLA_NUM_TX_QUEUES: c_ushort = 31; +pub const IFLA_NUM_RX_QUEUES: c_ushort = 32; +pub const IFLA_CARRIER: c_ushort = 33; +pub const IFLA_PHYS_PORT_ID: c_ushort = 34; +pub const IFLA_CARRIER_CHANGES: c_ushort = 35; +pub const IFLA_PHYS_SWITCH_ID: c_ushort = 36; +pub const IFLA_LINK_NETNSID: c_ushort = 37; +pub const IFLA_PHYS_PORT_NAME: c_ushort = 38; +pub const IFLA_PROTO_DOWN: c_ushort = 39; +pub const IFLA_GSO_MAX_SEGS: c_ushort = 40; +pub const IFLA_GSO_MAX_SIZE: c_ushort = 41; +pub const IFLA_PAD: c_ushort = 42; +pub const IFLA_XDP: c_ushort = 43; +pub const IFLA_EVENT: c_ushort = 44; +pub const IFLA_NEW_NETNSID: c_ushort = 45; +pub const IFLA_IF_NETNSID: c_ushort = 46; +pub const IFLA_TARGET_NETNSID: c_ushort = IFLA_IF_NETNSID; +pub const IFLA_CARRIER_UP_COUNT: c_ushort = 47; +pub const IFLA_CARRIER_DOWN_COUNT: c_ushort = 48; +pub const IFLA_NEW_IFINDEX: c_ushort = 49; +pub const IFLA_MIN_MTU: c_ushort = 50; +pub const IFLA_MAX_MTU: c_ushort = 51; +pub const IFLA_PROP_LIST: c_ushort = 52; +pub const IFLA_ALT_IFNAME: c_ushort = 53; +pub const IFLA_PERM_ADDRESS: c_ushort = 54; +pub const IFLA_PROTO_DOWN_REASON: c_ushort = 55; +pub const IFLA_PARENT_DEV_NAME: c_ushort = 56; +pub const IFLA_PARENT_DEV_BUS_NAME: c_ushort = 57; +pub const IFLA_GRO_MAX_SIZE: c_ushort = 58; +pub const IFLA_TSO_MAX_SIZE: c_ushort = 59; +pub const IFLA_TSO_MAX_SEGS: c_ushort = 60; +pub const IFLA_ALLMULTI: c_ushort = 61; +pub const IFLA_DEVLINK_PORT: c_ushort = 62; +pub const IFLA_GSO_IPV4_MAX_SIZE: c_ushort = 63; +pub const IFLA_GRO_IPV4_MAX_SIZE: c_ushort = 64; + +pub const IFLA_INFO_UNSPEC: c_ushort = 0; +pub const IFLA_INFO_KIND: c_ushort = 1; +pub const IFLA_INFO_DATA: c_ushort = 2; +pub const IFLA_INFO_XSTATS: c_ushort = 3; +pub const IFLA_INFO_SLAVE_KIND: c_ushort = 4; +pub const IFLA_INFO_SLAVE_DATA: c_ushort = 5; + +// linux/rtnetlink.h +pub const TCA_UNSPEC: c_ushort = 0; +pub const TCA_KIND: c_ushort = 1; +pub const TCA_OPTIONS: c_ushort = 2; +pub const TCA_STATS: c_ushort = 3; +pub const TCA_XSTATS: c_ushort = 4; +pub const TCA_RATE: c_ushort = 5; +pub const TCA_FCNT: c_ushort = 6; +pub const TCA_STATS2: c_ushort = 7; +pub const TCA_STAB: c_ushort = 8; + +pub const RTM_NEWLINK: u16 = 16; +pub const RTM_DELLINK: u16 = 17; +pub const RTM_GETLINK: u16 = 18; +pub const RTM_SETLINK: u16 = 19; +pub const RTM_NEWADDR: u16 = 20; +pub const RTM_DELADDR: u16 = 21; +pub const RTM_GETADDR: u16 = 22; +pub const RTM_NEWROUTE: u16 = 24; +pub const RTM_DELROUTE: u16 = 25; +pub const RTM_GETROUTE: u16 = 26; +pub const RTM_NEWNEIGH: u16 = 28; +pub const RTM_DELNEIGH: u16 = 29; +pub const RTM_GETNEIGH: u16 = 30; +pub const RTM_NEWRULE: u16 = 32; +pub const RTM_DELRULE: u16 = 33; +pub const RTM_GETRULE: u16 = 34; +pub const RTM_NEWQDISC: u16 = 36; +pub const RTM_DELQDISC: u16 = 37; +pub const RTM_GETQDISC: u16 = 38; +pub const RTM_NEWTCLASS: u16 = 40; +pub const RTM_DELTCLASS: u16 = 41; +pub const RTM_GETTCLASS: u16 = 42; +pub const RTM_NEWTFILTER: u16 = 44; +pub const RTM_DELTFILTER: u16 = 45; +pub const RTM_GETTFILTER: u16 = 46; +pub const RTM_NEWACTION: u16 = 48; +pub const RTM_DELACTION: u16 = 49; +pub const RTM_GETACTION: u16 = 50; +pub const RTM_NEWPREFIX: u16 = 52; +pub const RTM_GETMULTICAST: u16 = 58; +pub const RTM_GETANYCAST: u16 = 62; +pub const RTM_NEWNEIGHTBL: u16 = 64; +pub const RTM_GETNEIGHTBL: u16 = 66; +pub const RTM_SETNEIGHTBL: u16 = 67; +pub const RTM_NEWNDUSEROPT: u16 = 68; +pub const RTM_NEWADDRLABEL: u16 = 72; +pub const RTM_DELADDRLABEL: u16 = 73; +pub const RTM_GETADDRLABEL: u16 = 74; +pub const RTM_GETDCB: u16 = 78; +pub const RTM_SETDCB: u16 = 79; +pub const RTM_NEWNETCONF: u16 = 80; +pub const RTM_GETNETCONF: u16 = 82; +pub const RTM_NEWMDB: u16 = 84; +pub const RTM_DELMDB: u16 = 85; +pub const RTM_GETMDB: u16 = 86; +pub const RTM_NEWNSID: u16 = 88; +pub const RTM_DELNSID: u16 = 89; +pub const RTM_GETNSID: u16 = 90; + +pub const RTM_F_NOTIFY: c_uint = 0x100; +pub const RTM_F_CLONED: c_uint = 0x200; +pub const RTM_F_EQUALIZE: c_uint = 0x400; +pub const RTM_F_PREFIX: c_uint = 0x800; + +pub const RTA_UNSPEC: c_ushort = 0; +pub const RTA_DST: c_ushort = 1; +pub const RTA_SRC: c_ushort = 2; +pub const RTA_IIF: c_ushort = 3; +pub const RTA_OIF: c_ushort = 4; +pub const RTA_GATEWAY: c_ushort = 5; +pub const RTA_PRIORITY: c_ushort = 6; +pub const RTA_PREFSRC: c_ushort = 7; +pub const RTA_METRICS: c_ushort = 8; +pub const RTA_MULTIPATH: c_ushort = 9; +pub const RTA_PROTOINFO: c_ushort = 10; // No longer used +pub const RTA_FLOW: c_ushort = 11; +pub const RTA_CACHEINFO: c_ushort = 12; +pub const RTA_SESSION: c_ushort = 13; // No longer used +pub const RTA_MP_ALGO: c_ushort = 14; // No longer used +pub const RTA_TABLE: c_ushort = 15; +pub const RTA_MARK: c_ushort = 16; +pub const RTA_MFC_STATS: c_ushort = 17; + +pub const RTN_UNSPEC: c_uchar = 0; +pub const RTN_UNICAST: c_uchar = 1; +pub const RTN_LOCAL: c_uchar = 2; +pub const RTN_BROADCAST: c_uchar = 3; +pub const RTN_ANYCAST: c_uchar = 4; +pub const RTN_MULTICAST: c_uchar = 5; +pub const RTN_BLACKHOLE: c_uchar = 6; +pub const RTN_UNREACHABLE: c_uchar = 7; +pub const RTN_PROHIBIT: c_uchar = 8; +pub const RTN_THROW: c_uchar = 9; +pub const RTN_NAT: c_uchar = 10; +pub const RTN_XRESOLVE: c_uchar = 11; + +pub const RTPROT_UNSPEC: c_uchar = 0; +pub const RTPROT_REDIRECT: c_uchar = 1; +pub const RTPROT_KERNEL: c_uchar = 2; +pub const RTPROT_BOOT: c_uchar = 3; +pub const RTPROT_STATIC: c_uchar = 4; + +pub const RT_SCOPE_UNIVERSE: c_uchar = 0; +pub const RT_SCOPE_SITE: c_uchar = 200; +pub const RT_SCOPE_LINK: c_uchar = 253; +pub const RT_SCOPE_HOST: c_uchar = 254; +pub const RT_SCOPE_NOWHERE: c_uchar = 255; + +pub const RT_TABLE_UNSPEC: c_uchar = 0; +pub const RT_TABLE_COMPAT: c_uchar = 252; +pub const RT_TABLE_DEFAULT: c_uchar = 253; +pub const RT_TABLE_MAIN: c_uchar = 254; +pub const RT_TABLE_LOCAL: c_uchar = 255; + +pub const RTMSG_NEWDEVICE: u32 = 0x11; +pub const RTMSG_DELDEVICE: u32 = 0x12; +pub const RTMSG_NEWROUTE: u32 = 0x21; +pub const RTMSG_DELROUTE: u32 = 0x22; + +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_NET: c_int = 3; +pub const CTL_FS: c_int = 5; +pub const CTL_DEBUG: c_int = 6; +pub const CTL_DEV: c_int = 7; +pub const CTL_BUS: c_int = 8; +pub const CTL_ABI: c_int = 9; +pub const CTL_CPU: c_int = 10; + +pub const CTL_BUS_ISA: c_int = 1; + +pub const INOTIFY_MAX_USER_INSTANCES: c_int = 1; +pub const INOTIFY_MAX_USER_WATCHES: c_int = 2; +pub const INOTIFY_MAX_QUEUED_EVENTS: c_int = 3; + +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_SECUREMASK: c_int = 5; +pub const KERN_PROF: c_int = 6; +pub const KERN_NODENAME: c_int = 7; +pub const KERN_DOMAINNAME: c_int = 8; +pub const KERN_PANIC: c_int = 15; +pub const KERN_REALROOTDEV: c_int = 16; +pub const KERN_SPARC_REBOOT: c_int = 21; +pub const KERN_CTLALTDEL: c_int = 22; +pub const KERN_PRINTK: c_int = 23; +pub const KERN_NAMETRANS: c_int = 24; +pub const KERN_PPC_HTABRECLAIM: c_int = 25; +pub const KERN_PPC_ZEROPAGED: c_int = 26; +pub const KERN_PPC_POWERSAVE_NAP: c_int = 27; +pub const KERN_MODPROBE: c_int = 28; +pub const KERN_SG_BIG_BUFF: c_int = 29; +pub const KERN_ACCT: c_int = 30; +pub const KERN_PPC_L2CR: c_int = 31; +pub const KERN_RTSIGNR: c_int = 32; +pub const KERN_RTSIGMAX: c_int = 33; +pub const KERN_SHMMAX: c_int = 34; +pub const KERN_MSGMAX: c_int = 35; +pub const KERN_MSGMNB: c_int = 36; +pub const KERN_MSGPOOL: c_int = 37; +pub const KERN_SYSRQ: c_int = 38; +pub const KERN_MAX_THREADS: c_int = 39; +pub const KERN_RANDOM: c_int = 40; +pub const KERN_SHMALL: c_int = 41; +pub const KERN_MSGMNI: c_int = 42; +pub const KERN_SEM: c_int = 43; +pub const KERN_SPARC_STOP_A: c_int = 44; +pub const KERN_SHMMNI: c_int = 45; +pub const KERN_OVERFLOWUID: c_int = 46; +pub const KERN_OVERFLOWGID: c_int = 47; +pub const KERN_SHMPATH: c_int = 48; +pub const KERN_HOTPLUG: c_int = 49; +pub const KERN_IEEE_EMULATION_WARNINGS: c_int = 50; +pub const KERN_S390_USER_DEBUG_LOGGING: c_int = 51; +pub const KERN_CORE_USES_PID: c_int = 52; +pub const KERN_TAINTED: c_int = 53; +pub const KERN_CADPID: c_int = 54; +pub const KERN_PIDMAX: c_int = 55; +pub const KERN_CORE_PATTERN: c_int = 56; +pub const KERN_PANIC_ON_OOPS: c_int = 57; +pub const KERN_HPPA_PWRSW: c_int = 58; +pub const KERN_HPPA_UNALIGNED: c_int = 59; +pub const KERN_PRINTK_RATELIMIT: c_int = 60; +pub const KERN_PRINTK_RATELIMIT_BURST: c_int = 61; +pub const KERN_PTY: c_int = 62; +pub const KERN_NGROUPS_MAX: c_int = 63; +pub const KERN_SPARC_SCONS_PWROFF: c_int = 64; +pub const KERN_HZ_TIMER: c_int = 65; +pub const KERN_UNKNOWN_NMI_PANIC: c_int = 66; +pub const KERN_BOOTLOADER_TYPE: c_int = 67; +pub const KERN_RANDOMIZE: c_int = 68; +pub const KERN_SETUID_DUMPABLE: c_int = 69; +pub const KERN_SPIN_RETRY: c_int = 70; +pub const KERN_ACPI_VIDEO_FLAGS: c_int = 71; +pub const KERN_IA64_UNALIGNED: c_int = 72; +pub const KERN_COMPAT_LOG: c_int = 73; +pub const KERN_MAX_LOCK_DEPTH: c_int = 74; + +pub const VM_OVERCOMMIT_MEMORY: c_int = 5; +pub const VM_PAGE_CLUSTER: c_int = 10; +pub const VM_DIRTY_BACKGROUND: c_int = 11; +pub const VM_DIRTY_RATIO: c_int = 12; +pub const VM_DIRTY_WB_CS: c_int = 13; +pub const VM_DIRTY_EXPIRE_CS: c_int = 14; +pub const VM_NR_PDFLUSH_THREADS: c_int = 15; +pub const VM_OVERCOMMIT_RATIO: c_int = 16; +pub const VM_PAGEBUF: c_int = 17; +pub const VM_HUGETLB_PAGES: c_int = 18; +pub const VM_SWAPPINESS: c_int = 19; +pub const VM_LOWMEM_RESERVE_RATIO: c_int = 20; +pub const VM_MIN_FREE_KBYTES: c_int = 21; +pub const VM_MAX_MAP_COUNT: c_int = 22; +pub const VM_LAPTOP_MODE: c_int = 23; +pub const VM_BLOCK_DUMP: c_int = 24; +pub const VM_HUGETLB_GROUP: c_int = 25; +pub const VM_VFS_CACHE_PRESSURE: c_int = 26; +pub const VM_LEGACY_VA_LAYOUT: c_int = 27; +pub const VM_SWAP_TOKEN_TIMEOUT: c_int = 28; +pub const VM_DROP_PAGECACHE: c_int = 29; +pub const VM_PERCPU_PAGELIST_FRACTION: c_int = 30; +pub const VM_ZONE_RECLAIM_MODE: c_int = 31; +pub const VM_MIN_UNMAPPED: c_int = 32; +pub const VM_PANIC_ON_OOM: c_int = 33; +pub const VM_VDSO_ENABLED: c_int = 34; + +pub const NET_CORE: c_int = 1; +pub const NET_ETHER: c_int = 2; +pub const NET_802: c_int = 3; +pub const NET_UNIX: c_int = 4; +pub const NET_IPV4: c_int = 5; +pub const NET_IPX: c_int = 6; +pub const NET_ATALK: c_int = 7; +pub const NET_NETROM: c_int = 8; +pub const NET_AX25: c_int = 9; +pub const NET_BRIDGE: c_int = 10; +pub const NET_ROSE: c_int = 11; +pub const NET_IPV6: c_int = 12; +pub const NET_X25: c_int = 13; +pub const NET_TR: c_int = 14; +pub const NET_DECNET: c_int = 15; +pub const NET_ECONET: c_int = 16; +pub const NET_SCTP: c_int = 17; +pub const NET_LLC: c_int = 18; +pub const NET_NETFILTER: c_int = 19; +pub const NET_DCCP: c_int = 20; +pub const HUGETLB_FLAG_ENCODE_SHIFT: c_int = 26; +pub const MAP_HUGE_SHIFT: c_int = HUGETLB_FLAG_ENCODE_SHIFT; + +// include/linux/sched.h +pub const PF_VCPU: c_int = 0x00000001; +pub const PF_IDLE: c_int = 0x00000002; +pub const PF_EXITING: c_int = 0x00000004; +pub const PF_POSTCOREDUMP: c_int = 0x00000008; +pub const PF_IO_WORKER: c_int = 0x00000010; +pub const PF_WQ_WORKER: c_int = 0x00000020; +pub const PF_FORKNOEXEC: c_int = 0x00000040; +pub const PF_MCE_PROCESS: c_int = 0x00000080; +pub const PF_SUPERPRIV: c_int = 0x00000100; +pub const PF_DUMPCORE: c_int = 0x00000200; +pub const PF_SIGNALED: c_int = 0x00000400; +pub const PF_MEMALLOC: c_int = 0x00000800; +pub const PF_NPROC_EXCEEDED: c_int = 0x00001000; +pub const PF_USED_MATH: c_int = 0x00002000; +pub const PF_USER_WORKER: c_int = 0x00004000; +pub const PF_NOFREEZE: c_int = 0x00008000; + +pub const PF_KSWAPD: c_int = 0x00020000; +pub const PF_MEMALLOC_NOFS: c_int = 0x00040000; +pub const PF_MEMALLOC_NOIO: c_int = 0x00080000; +pub const PF_LOCAL_THROTTLE: c_int = 0x00100000; +pub const PF_KTHREAD: c_int = 0x00200000; +pub const PF_RANDOMIZE: c_int = 0x00400000; + +pub const PF_NO_SETAFFINITY: c_int = 0x04000000; +pub const PF_MCE_EARLY: c_int = 0x08000000; +pub const PF_MEMALLOC_PIN: c_int = 0x10000000; + +pub const PF_SUSPEND_TASK: c_int = 0x80000000; + +pub const KLOG_CLOSE: c_int = 0; +pub const KLOG_OPEN: c_int = 1; +pub const KLOG_READ: c_int = 2; +pub const KLOG_READ_ALL: c_int = 3; +pub const KLOG_READ_CLEAR: c_int = 4; +pub const KLOG_CLEAR: c_int = 5; +pub const KLOG_CONSOLE_OFF: c_int = 6; +pub const KLOG_CONSOLE_ON: c_int = 7; +pub const KLOG_CONSOLE_LEVEL: c_int = 8; +pub const KLOG_SIZE_UNREAD: c_int = 9; +pub const KLOG_SIZE_BUFFER: c_int = 10; + +// From NDK's linux/auxvec.h +pub const AT_NULL: c_ulong = 0; +pub const AT_IGNORE: c_ulong = 1; +pub const AT_EXECFD: c_ulong = 2; +pub const AT_PHDR: c_ulong = 3; +pub const AT_PHENT: c_ulong = 4; +pub const AT_PHNUM: c_ulong = 5; +pub const AT_PAGESZ: c_ulong = 6; +pub const AT_BASE: c_ulong = 7; +pub const AT_FLAGS: c_ulong = 8; +pub const AT_ENTRY: c_ulong = 9; +pub const AT_NOTELF: c_ulong = 10; +pub const AT_UID: c_ulong = 11; +pub const AT_EUID: c_ulong = 12; +pub const AT_GID: c_ulong = 13; +pub const AT_EGID: c_ulong = 14; +pub const AT_PLATFORM: c_ulong = 15; +pub const AT_HWCAP: c_ulong = 16; +pub const AT_CLKTCK: c_ulong = 17; +pub const AT_SECURE: c_ulong = 23; +pub const AT_BASE_PLATFORM: c_ulong = 24; +pub const AT_RANDOM: c_ulong = 25; +pub const AT_HWCAP2: c_ulong = 26; +pub const AT_RSEQ_FEATURE_SIZE: c_ulong = 27; +pub const AT_RSEQ_ALIGN: c_ulong = 28; +pub const AT_HWCAP3: c_ulong = 29; +pub const AT_HWCAP4: c_ulong = 30; +pub const AT_EXECFN: c_ulong = 31; +pub const AT_MINSIGSTKSZ: c_ulong = 51; + +// siginfo.h +pub const SI_DETHREAD: c_int = -7; +pub const TRAP_PERF: c_int = 6; + +// Most `*_SUPER_MAGIC` constants are defined at the `linux_like` level; the +// following are only available on newer Linux versions than the versions +// currently used in CI in some configurations, so we define them here. +cfg_if! { + if #[cfg(not(target_arch = "s390x"))] { + pub const XFS_SUPER_MAGIC: c_long = 0x58465342; + } else if #[cfg(target_arch = "s390x")] { + pub const XFS_SUPER_MAGIC: c_uint = 0x58465342; + } +} + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + let next = (cmsg as usize + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max { + core::ptr::null_mut::() + } else { + next as *mut cmsghdr + } + } + + pub fn CPU_ALLOC_SIZE(count: c_int) -> size_t { + let _dummy: cpu_set_t = mem::zeroed(); + let size_in_bits = 8 * size_of_val(&_dummy.__bits[0]); + ((count as size_t + size_in_bits - 1) / 8) as size_t + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.__bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.__bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.__bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.__bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.__bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.__bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.__bits[idx] & (1 << offset)) + } + + pub fn CPU_COUNT_S(size: usize, cpuset: &cpu_set_t) -> c_int { + let mut s: u32 = 0; + let size_of_mask = size_of_val(&cpuset.__bits[0]); + for i in cpuset.__bits[..(size / size_of_mask)].iter() { + s += i.count_ones(); + } + s as c_int + } + + pub fn CPU_COUNT(cpuset: &cpu_set_t) -> c_int { + CPU_COUNT_S(size_of::(), cpuset) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.__bits == set2.__bits + } + + pub fn NLA_ALIGN(len: c_int) -> c_int { + return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1); + } + + pub fn SO_EE_OFFENDER(ee: *const crate::sock_extended_err) -> *mut crate::sockaddr { + ee.offset(1) as *mut crate::sockaddr + } +} + +safe_f! { + pub const fn makedev(ma: c_uint, mi: c_uint) -> crate::dev_t { + let ma = ma as crate::dev_t; + let mi = mi as crate::dev_t; + ((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12) + } + + pub const fn major(dev: crate::dev_t) -> c_int { + ((dev >> 8) & 0xfff) as c_int + } + + pub const fn minor(dev: crate::dev_t) -> c_int { + ((dev & 0xff) | ((dev >> 12) & 0xfff00)) as c_int + } +} + +extern "C" { + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + pub fn getrlimit64(resource: c_int, rlim: *mut rlimit64) -> c_int; + pub fn setrlimit64(resource: c_int, rlim: *const rlimit64) -> c_int; + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + pub fn prlimit( + pid: crate::pid_t, + resource: c_int, + new_limit: *const crate::rlimit, + old_limit: *mut crate::rlimit, + ) -> c_int; + pub fn prlimit64( + pid: crate::pid_t, + resource: c_int, + new_limit: *const crate::rlimit64, + old_limit: *mut crate::rlimit64, + ) -> c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn mlock2(addr: *const c_void, len: size_t, flags: c_int) -> c_int; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: size_t, + serv: *mut c_char, + servlen: size_t, + flags: c_int, + ) -> c_int; + pub fn preadv(fd: c_int, iov: *const crate::iovec, count: c_int, offset: off_t) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, count: c_int, offset: off_t) -> ssize_t; + pub fn process_vm_readv( + pid: crate::pid_t, + local_iov: *const crate::iovec, + local_iov_count: c_ulong, + remote_iov: *const crate::iovec, + remote_iov_count: c_ulong, + flags: c_ulong, + ) -> ssize_t; + pub fn process_vm_writev( + pid: crate::pid_t, + local_iov: *const crate::iovec, + local_iov_count: c_ulong, + remote_iov: *const crate::iovec, + remote_iov_count: c_ulong, + flags: c_ulong, + ) -> ssize_t; + pub fn ptrace(request: c_int, ...) -> c_long; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + pub fn __sched_cpualloc(count: size_t) -> *mut crate::cpu_set_t; + pub fn __sched_cpufree(set: *mut crate::cpu_set_t); + pub fn __sched_cpucount(setsize: size_t, set: *const cpu_set_t) -> c_int; + pub fn sched_getcpu() -> c_int; + pub fn mallinfo() -> crate::mallinfo; + // available from API 23 + pub fn malloc_info(options: c_int, stream: *mut crate::FILE) -> c_int; + + pub fn malloc_usable_size(ptr: *const c_void) -> size_t; + + pub fn utmpname(name: *const c_char) -> c_int; + pub fn setutent(); + pub fn getutent() -> *mut utmp; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t) -> c_int; + pub fn fallocate64(fd: c_int, mode: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn getxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn lgetxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn fgetxattr( + filedes: c_int, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn setxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn lsetxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn fsetxattr( + filedes: c_int, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn flistxattr(filedes: c_int, list: *mut c_char, size: size_t) -> ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn fremovexattr(filedes: c_int, name: *const c_char) -> c_int; + pub fn signalfd(fd: c_int, mask: *const crate::sigset_t, flags: c_int) -> c_int; + pub fn timerfd_create(clock: crate::clockid_t, flags: c_int) -> c_int; + pub fn timerfd_gettime(fd: c_int, current_value: *mut itimerspec) -> c_int; + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec, + ) -> c_int; + pub fn syscall(num: c_long, ...) -> c_long; + pub fn sched_getaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *mut cpu_set_t, + ) -> c_int; + pub fn sched_setaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *const cpu_set_t, + ) -> c_int; + pub fn epoll_create(size: c_int) -> c_int; + pub fn epoll_create1(flags: c_int) -> c_int; + pub fn epoll_wait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + ) -> c_int; + pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut crate::epoll_event) -> c_int; + pub fn unshare(flags: c_int) -> c_int; + pub fn umount(target: *const c_char) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn tee(fd_in: c_int, fd_out: c_int, len: size_t, flags: c_uint) -> ssize_t; + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + pub fn splice( + fd_in: c_int, + off_in: *mut crate::loff_t, + fd_out: c_int, + off_out: *mut crate::loff_t, + len: size_t, + flags: c_uint, + ) -> ssize_t; + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; + pub fn eventfd_read(fd: c_int, value: *mut eventfd_t) -> c_int; + pub fn eventfd_write(fd: c_int, value: eventfd_t) -> c_int; + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn setns(fd: c_int, nstype: c_int) -> c_int; + pub fn swapoff(puath: *const c_char) -> c_int; + pub fn vmsplice(fd: c_int, iov: *const crate::iovec, nr_segs: size_t, flags: c_uint) + -> ssize_t; + pub fn mount( + src: *const c_char, + target: *const c_char, + fstype: *const c_char, + flags: c_ulong, + data: *const c_void, + ) -> c_int; + pub fn personality(persona: c_uint) -> c_int; + pub fn prctl(option: c_int, ...) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: nfds_t, + timeout: *const crate::timespec, + sigmask: *const sigset_t, + ) -> c_int; + + pub fn clone( + cb: extern "C" fn(*mut c_void) -> c_int, + child_stack: *mut c_void, + flags: c_int, + arg: *mut c_void, + ... + ) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sysinfo(info: *mut crate::sysinfo) -> c_int; + pub fn umount2(target: *const c_char, flags: c_int) -> c_int; + pub fn swapon(path: *const c_char, swapflags: c_int) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sendfile(out_fd: c_int, in_fd: c_int, offset: *mut off_t, count: size_t) -> ssize_t; + pub fn sendfile64(out_fd: c_int, in_fd: c_int, offset: *mut off64_t, count: size_t) -> ssize_t; + pub fn setfsgid(gid: crate::gid_t) -> c_int; + pub fn setfsuid(uid: crate::uid_t) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn __errno() -> *mut c_int; + pub fn inotify_rm_watch(fd: c_int, wd: u32) -> c_int; + pub fn inotify_init() -> c_int; + pub fn inotify_init1(flags: c_int) -> c_int; + pub fn inotify_add_watch(fd: c_int, path: *const c_char, mask: u32) -> c_int; + + pub fn regcomp(preg: *mut crate::regex_t, pattern: *const c_char, cflags: c_int) -> c_int; + + pub fn regexec( + preg: *const crate::regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + + pub fn regerror( + errcode: c_int, + preg: *const crate::regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + + pub fn regfree(preg: *mut crate::regex_t); + + pub fn android_set_abort_message(msg: *const c_char); + + pub fn gettid() -> crate::pid_t; + + pub fn tgkill(tgid: crate::pid_t, tid: crate::pid_t, sig: c_int) -> c_int; + + pub fn getauxval(type_: c_ulong) -> c_ulong; + + /// Only available in API Version 28+ + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + pub fn __system_property_set(__name: *const c_char, __value: *const c_char) -> c_int; + pub fn __system_property_get(__name: *const c_char, __value: *mut c_char) -> c_int; + pub fn __system_property_find(__name: *const c_char) -> *const prop_info; + pub fn __system_property_find_nth(__n: c_uint) -> *const prop_info; + pub fn __system_property_foreach( + __callback: unsafe extern "C" fn(__pi: *const prop_info, __cookie: *mut c_void), + __cookie: *mut c_void, + ) -> c_int; + + // #include + /// Only available in API Version 21+ + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + pub fn arc4random() -> u32; + pub fn arc4random_uniform(__upper_bound: u32) -> u32; + pub fn arc4random_buf(__buf: *mut c_void, __n: size_t); + + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + + pub fn dirname(path: *const c_char) -> *mut c_char; + pub fn basename(path: *const c_char) -> *mut c_char; + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + + pub fn sync(); + pub fn syncfs(fd: c_int) -> c_int; + + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn fread_unlocked( + buf: *mut c_void, + size: size_t, + nobj: size_t, + stream: *mut crate::FILE, + ) -> size_t; + pub fn fwrite_unlocked( + buf: *const c_void, + size: size_t, + nobj: size_t, + stream: *mut crate::FILE, + ) -> size_t; + pub fn fflush_unlocked(stream: *mut crate::FILE) -> c_int; + pub fn fgets_unlocked(buf: *mut c_char, size: c_int, stream: *mut crate::FILE) -> *mut c_char; + + pub fn klogctl(syslog_type: c_int, bufp: *mut c_char, len: c_int) -> c_int; + + pub fn memfd_create(name: *const c_char, flags: c_uint) -> c_int; + pub fn renameat2( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_uint, + ) -> c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod b32; + pub use self::b32::*; + } else if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_pointer_width + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_tid: c_int, + _si_overrun: c_int, + si_sigval: crate::sigval, + } + (*(self as *const siginfo_t as *const siginfo_timer)).si_sigval + } +} + +impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*(self as *const siginfo_t as *const siginfo_f)).sifields + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> c_long { + self.sifields().sigchld.si_stime + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/emscripten/lfs64.rs b/deps/crates/vendor/libc/src/unix/linux_like/emscripten/lfs64.rs new file mode 100644 index 00000000000000..501540943889f2 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/emscripten/lfs64.rs @@ -0,0 +1,214 @@ +use crate::off64_t; +use crate::prelude::*; + +// In-sync with ../linux/musl/lfs64.rs except for fallocate64, prlimit64 and sendfile64 + +#[inline] +pub unsafe extern "C" fn creat64(path: *const c_char, mode: crate::mode_t) -> c_int { + crate::creat(path, mode) +} + +#[inline] +pub unsafe extern "C" fn fgetpos64(stream: *mut crate::FILE, pos: *mut crate::fpos64_t) -> c_int { + crate::fgetpos(stream, pos as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fopen64(pathname: *const c_char, mode: *const c_char) -> *mut crate::FILE { + crate::fopen(pathname, mode) +} + +#[inline] +pub unsafe extern "C" fn freopen64( + pathname: *const c_char, + mode: *const c_char, + stream: *mut crate::FILE, +) -> *mut crate::FILE { + crate::freopen(pathname, mode, stream) +} + +#[inline] +pub unsafe extern "C" fn fseeko64( + stream: *mut crate::FILE, + offset: off64_t, + whence: c_int, +) -> c_int { + crate::fseeko(stream, offset, whence) +} + +#[inline] +pub unsafe extern "C" fn fsetpos64(stream: *mut crate::FILE, pos: *const crate::fpos64_t) -> c_int { + crate::fsetpos(stream, pos as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstat64(fildes: c_int, buf: *mut crate::stat64) -> c_int { + crate::fstat(fildes, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstatat64( + fd: c_int, + path: *const c_char, + buf: *mut crate::stat64, + flag: c_int, +) -> c_int { + crate::fstatat(fd, path, buf as *mut _, flag) +} + +#[inline] +pub unsafe extern "C" fn fstatfs64(fd: c_int, buf: *mut crate::statfs64) -> c_int { + crate::fstatfs(fd, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstatvfs64(fd: c_int, buf: *mut crate::statvfs64) -> c_int { + crate::fstatvfs(fd, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn ftello64(stream: *mut crate::FILE) -> off64_t { + crate::ftello(stream) +} + +#[inline] +pub unsafe extern "C" fn ftruncate64(fd: c_int, length: off64_t) -> c_int { + crate::ftruncate(fd, length) +} + +#[inline] +pub unsafe extern "C" fn getrlimit64(resource: c_int, rlim: *mut crate::rlimit64) -> c_int { + crate::getrlimit(resource, rlim as *mut _) +} + +#[inline] +pub unsafe extern "C" fn lseek64(fd: c_int, offset: off64_t, whence: c_int) -> off64_t { + crate::lseek(fd, offset, whence) +} + +#[inline] +pub unsafe extern "C" fn lstat64(path: *const c_char, buf: *mut crate::stat64) -> c_int { + crate::lstat(path, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn mmap64( + addr: *mut c_void, + length: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off64_t, +) -> *mut c_void { + crate::mmap(addr, length, prot, flags, fd, offset) +} + +// These functions are variadic in the C ABI since the `mode` argument is "optional". Variadic +// `extern "C"` functions are unstable in Rust so we cannot write a shim function for these +// entrypoints. See https://github.com/rust-lang/rust/issues/44930. +// +// These aliases are mostly fine though, neither function takes a LFS64-namespaced type as an +// argument, nor do their names clash with any declared types. +pub use crate::{ + open as open64, + openat as openat64, +}; + +#[inline] +pub unsafe extern "C" fn posix_fadvise64( + fd: c_int, + offset: off64_t, + len: off64_t, + advice: c_int, +) -> c_int { + crate::posix_fadvise(fd, offset, len, advice) +} + +#[inline] +pub unsafe extern "C" fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int { + crate::posix_fallocate(fd, offset, len) +} + +#[inline] +pub unsafe extern "C" fn pread64( + fd: c_int, + buf: *mut c_void, + count: size_t, + offset: off64_t, +) -> ssize_t { + crate::pread(fd, buf, count, offset) +} + +#[inline] +pub unsafe extern "C" fn preadv64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, +) -> ssize_t { + crate::preadv(fd, iov, iovcnt, offset) +} + +#[inline] +pub unsafe extern "C" fn pwrite64( + fd: c_int, + buf: *const c_void, + count: size_t, + offset: off64_t, +) -> ssize_t { + crate::pwrite(fd, buf, count, offset) +} + +#[inline] +pub unsafe extern "C" fn pwritev64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, +) -> ssize_t { + crate::pwritev(fd, iov, iovcnt, offset) +} + +#[inline] +pub unsafe extern "C" fn readdir64(dirp: *mut crate::DIR) -> *mut crate::dirent64 { + crate::readdir(dirp) as *mut _ +} + +#[inline] +pub unsafe extern "C" fn readdir64_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent64, + result: *mut *mut crate::dirent64, +) -> c_int { + crate::readdir_r(dirp, entry as *mut _, result as *mut _) +} + +#[inline] +pub unsafe extern "C" fn setrlimit64(resource: c_int, rlim: *const crate::rlimit64) -> c_int { + crate::setrlimit(resource, rlim as *mut _) +} + +#[inline] +pub unsafe extern "C" fn stat64(pathname: *const c_char, statbuf: *mut crate::stat64) -> c_int { + crate::stat(pathname, statbuf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn statfs64(pathname: *const c_char, buf: *mut crate::statfs64) -> c_int { + crate::statfs(pathname, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn statvfs64(path: *const c_char, buf: *mut crate::statvfs64) -> c_int { + crate::statvfs(path, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn tmpfile64() -> *mut crate::FILE { + crate::tmpfile() +} + +#[inline] +pub unsafe extern "C" fn truncate64(path: *const c_char, length: off64_t) -> c_int { + crate::truncate(path, length) +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/emscripten/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/emscripten/mod.rs new file mode 100644 index 00000000000000..711ed8f8b4c371 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/emscripten/mod.rs @@ -0,0 +1,1455 @@ +use crate::prelude::*; + +pub type wchar_t = i32; +pub type dev_t = u32; +pub type socklen_t = u32; +pub type pthread_t = c_ulong; +pub type mode_t = u32; +pub type shmatt_t = c_ulong; +pub type mqd_t = c_int; +pub type msgqnum_t = c_ulong; +pub type msglen_t = c_ulong; +pub type nfds_t = c_ulong; +pub type nl_item = c_int; +pub type idtype_t = c_uint; +pub type loff_t = i64; +pub type pthread_key_t = c_uint; + +pub type clock_t = c_long; +pub type time_t = i64; +pub type suseconds_t = c_long; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i32; + +pub type blksize_t = c_long; +pub type fsblkcnt_t = u32; +pub type fsfilcnt_t = u32; +pub type rlim_t = u64; +pub type nlink_t = u32; + +pub type ino64_t = crate::ino_t; +pub type off64_t = off_t; +pub type blkcnt64_t = crate::blkcnt_t; +pub type rlim64_t = crate::rlim_t; + +pub type rlimit64 = crate::rlimit; +pub type flock64 = crate::flock; +pub type stat64 = crate::stat; +pub type statfs64 = crate::statfs; +pub type statvfs64 = crate::statvfs; +pub type dirent64 = crate::dirent; + +extern_ty! { + pub enum fpos64_t {} // FIXME(emscripten): fill this out with a struct +} + +s! { + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct spwd { + pub sp_namp: *mut c_char, + pub sp_pwdp: *mut c_char, + pub sp_lstchg: c_long, + pub sp_min: c_long, + pub sp_max: c_long, + pub sp_warn: c_long, + pub sp_inact: c_long, + pub sp_expire: c_long, + pub sp_flag: c_ulong, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct signalfd_siginfo { + pub ssi_signo: u32, + pub ssi_errno: i32, + pub ssi_code: i32, + pub ssi_pid: u32, + pub ssi_uid: u32, + pub ssi_fd: i32, + pub ssi_tid: u32, + pub ssi_band: u32, + pub ssi_overrun: u32, + pub ssi_trapno: u32, + pub ssi_status: i32, + pub ssi_int: i32, + pub ssi_ptr: u64, + pub ssi_utime: u64, + pub ssi_stime: u64, + pub ssi_addr: u64, + pub ssi_addr_lsb: u16, + _pad2: Padding, + pub ssi_syscall: i32, + pub ssi_call_addr: u64, + pub ssi_arch: u32, + _pad: Padding<[u8; 28]>, + } + + pub struct fsid_t { + __val: [c_int; 2], + } + + pub struct cpu_set_t { + bits: [u32; 32], + } + + // System V IPC + pub struct msginfo { + pub msgpool: c_int, + pub msgmap: c_int, + pub msgmax: c_int, + pub msgmnb: c_int, + pub msgmni: c_int, + pub msgssz: c_int, + pub msgtql: c_int, + pub msgseg: c_ushort, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct ipc_perm { + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub __c_ispeed: crate::speed_t, + pub __c_ospeed: crate::speed_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct pthread_attr_t { + __size: [u32; 11], + } + + pub struct sigset_t { + __val: [c_ulong; 32], + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct sem_t { + __val: [c_int; 4], + } + pub struct stat { + pub st_dev: crate::dev_t, + #[cfg(emscripten_old_stat_abi)] + __st_dev_padding: Padding, + #[cfg(emscripten_old_stat_abi)] + __st_ino_truncated: c_long, + pub st_mode: mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + #[cfg(emscripten_old_stat_abi)] + __st_rdev_padding: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_ino: crate::ino_t, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } + + pub struct statfs { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_frsize: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct arpd_request { + pub req: c_ushort, + pub ip: u32, + pub dev: c_ulong, + pub stamp: c_ulong, + pub updated: c_ulong, + pub ha: [c_uchar; crate::MAX_ADDR_LEN], + } + + #[repr(align(4))] + pub struct pthread_mutex_t { + size: [u8; crate::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[repr(align(4))] + pub struct pthread_rwlock_t { + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[repr(align(4))] + pub struct pthread_mutexattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_rwlockattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_CONDATTR_T], + } + + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_off: off_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct sysinfo { + pub uptime: c_ulong, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub __reserved: [c_char; 256], + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + pad: Padding<[c_long; 4]>, + } + + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct pthread_cond_t { + size: [u8; crate::__SIZEOF_PTHREAD_COND_T], + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [f64; 3], + } +} + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MS_NOUSER: c_ulong = 0x80000000; +pub const MS_RMT_MASK: c_ulong = 0x02800051; + +pub const ABDAY_1: crate::nl_item = 0x20000; +pub const ABDAY_2: crate::nl_item = 0x20001; +pub const ABDAY_3: crate::nl_item = 0x20002; +pub const ABDAY_4: crate::nl_item = 0x20003; +pub const ABDAY_5: crate::nl_item = 0x20004; +pub const ABDAY_6: crate::nl_item = 0x20005; +pub const ABDAY_7: crate::nl_item = 0x20006; + +pub const DAY_1: crate::nl_item = 0x20007; +pub const DAY_2: crate::nl_item = 0x20008; +pub const DAY_3: crate::nl_item = 0x20009; +pub const DAY_4: crate::nl_item = 0x2000A; +pub const DAY_5: crate::nl_item = 0x2000B; +pub const DAY_6: crate::nl_item = 0x2000C; +pub const DAY_7: crate::nl_item = 0x2000D; + +pub const ABMON_1: crate::nl_item = 0x2000E; +pub const ABMON_2: crate::nl_item = 0x2000F; +pub const ABMON_3: crate::nl_item = 0x20010; +pub const ABMON_4: crate::nl_item = 0x20011; +pub const ABMON_5: crate::nl_item = 0x20012; +pub const ABMON_6: crate::nl_item = 0x20013; +pub const ABMON_7: crate::nl_item = 0x20014; +pub const ABMON_8: crate::nl_item = 0x20015; +pub const ABMON_9: crate::nl_item = 0x20016; +pub const ABMON_10: crate::nl_item = 0x20017; +pub const ABMON_11: crate::nl_item = 0x20018; +pub const ABMON_12: crate::nl_item = 0x20019; + +pub const MON_1: crate::nl_item = 0x2001A; +pub const MON_2: crate::nl_item = 0x2001B; +pub const MON_3: crate::nl_item = 0x2001C; +pub const MON_4: crate::nl_item = 0x2001D; +pub const MON_5: crate::nl_item = 0x2001E; +pub const MON_6: crate::nl_item = 0x2001F; +pub const MON_7: crate::nl_item = 0x20020; +pub const MON_8: crate::nl_item = 0x20021; +pub const MON_9: crate::nl_item = 0x20022; +pub const MON_10: crate::nl_item = 0x20023; +pub const MON_11: crate::nl_item = 0x20024; +pub const MON_12: crate::nl_item = 0x20025; + +pub const AM_STR: crate::nl_item = 0x20026; +pub const PM_STR: crate::nl_item = 0x20027; + +pub const D_T_FMT: crate::nl_item = 0x20028; +pub const D_FMT: crate::nl_item = 0x20029; +pub const T_FMT: crate::nl_item = 0x2002A; +pub const T_FMT_AMPM: crate::nl_item = 0x2002B; + +pub const ERA: crate::nl_item = 0x2002C; +pub const ERA_D_FMT: crate::nl_item = 0x2002E; +pub const ALT_DIGITS: crate::nl_item = 0x2002F; +pub const ERA_D_T_FMT: crate::nl_item = 0x20030; +pub const ERA_T_FMT: crate::nl_item = 0x20031; + +pub const CODESET: crate::nl_item = 14; + +pub const CRNCYSTR: crate::nl_item = 0x4000F; + +pub const RUSAGE_THREAD: c_int = 1; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const RADIXCHAR: crate::nl_item = 0x10000; +pub const THOUSEP: crate::nl_item = 0x10001; + +pub const YESEXPR: crate::nl_item = 0x50000; +pub const NOEXPR: crate::nl_item = 0x50001; +pub const YESSTR: crate::nl_item = 0x50002; +pub const NOSTR: crate::nl_item = 0x50003; + +pub const FILENAME_MAX: c_uint = 4096; +pub const L_tmpnam: c_uint = 20; +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; + +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = 60; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_NZERO: c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_STREAMS: c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; + +pub const RLIM_SAVED_MAX: crate::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: crate::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: c_int = 1 << 0; +pub const GLOB_MARK: c_int = 1 << 1; +pub const GLOB_NOSORT: c_int = 1 << 2; +pub const GLOB_DOOFFS: c_int = 1 << 3; +pub const GLOB_NOCHECK: c_int = 1 << 4; +pub const GLOB_APPEND: c_int = 1 << 5; +pub const GLOB_NOESCAPE: c_int = 1 << 6; + +pub const GLOB_NOSPACE: c_int = 1; +pub const GLOB_ABORTED: c_int = 2; +pub const GLOB_NOMATCH: c_int = 3; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; + +pub const AT_EACCESS: c_int = 0x200; + +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; + +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; +pub const ST_NODEV: c_ulong = 4; +pub const ST_NOEXEC: c_ulong = 8; +pub const ST_SYNCHRONOUS: c_ulong = 16; +pub const ST_MANDLOCK: c_ulong = 64; +pub const ST_WRITE: c_ulong = 128; +pub const ST_APPEND: c_ulong = 256; +pub const ST_IMMUTABLE: c_ulong = 512; +pub const ST_NOATIME: c_ulong = 1024; +pub const ST_NODIRATIME: c_ulong = 2048; + +pub const RTLD_NEXT: *mut c_void = -1i64 as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_NOW: c_int = 0x2; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], +}; + +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_BATCH: c_int = 3; +pub const SCHED_IDLE: c_int = 5; + +pub const AF_IB: c_int = 27; +pub const AF_MPLS: c_int = 28; +pub const AF_NFC: c_int = 39; +pub const AF_VSOCK: c_int = 40; +pub const PF_IB: c_int = AF_IB; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_NFC: c_int = AF_NFC; +pub const PF_VSOCK: c_int = AF_VSOCK; + +// System V IPC +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_CREAT: c_int = 0o1000; +pub const IPC_EXCL: c_int = 0o2000; +pub const IPC_NOWAIT: c_int = 0o4000; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; +pub const IPC_INFO: c_int = 3; +pub const MSG_STAT: c_int = 11; +pub const MSG_INFO: c_int = 12; + +pub const MSG_NOERROR: c_int = 0o10000; +pub const MSG_EXCEPT: c_int = 0o20000; + +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; + +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_REMAP: c_int = 0o40000; +pub const SHM_EXEC: c_int = 0o100000; + +pub const SHM_LOCK: c_int = 11; +pub const SHM_UNLOCK: c_int = 12; + +pub const SHM_HUGETLB: c_int = 0o4000; +pub const SHM_NORESERVE: c_int = 0o10000; + +pub const LOG_NFACILITIES: c_int = 24; + +pub const SEM_FAILED: *mut crate::sem_t = ptr::null_mut(); + +pub const AI_PASSIVE: c_int = 0x0001; +pub const AI_CANONNAME: c_int = 0x0002; +pub const AI_NUMERICHOST: c_int = 0x0004; +pub const AI_V4MAPPED: c_int = 0x0008; +pub const AI_ALL: c_int = 0x0010; +pub const AI_ADDRCONFIG: c_int = 0x0020; + +pub const AI_NUMERICSERV: c_int = 0x0400; + +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_OVERFLOW: c_int = -12; + +pub const NI_NUMERICHOST: c_int = 1; +pub const NI_NUMERICSERV: c_int = 2; +pub const NI_NOFQDN: c_int = 4; +pub const NI_NAMEREQD: c_int = 8; +pub const NI_DGRAM: c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: c_uint = 4; + +pub const EAI_SYSTEM: c_int = -11; + +pub const MREMAP_MAYMOVE: c_int = 1; +pub const MREMAP_FIXED: c_int = 2; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +pub const FALLOC_FL_KEEP_SIZE: c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: c_int = 0x02; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_CLOEXEC: c_int = 0x80000; + +// Defined as wasi value. +pub const EPERM: c_int = 63; +pub const ENOENT: c_int = 44; +pub const ESRCH: c_int = 71; +pub const EINTR: c_int = 27; +pub const EIO: c_int = 29; +pub const ENXIO: c_int = 60; +pub const E2BIG: c_int = 1; +pub const ENOEXEC: c_int = 45; +pub const EBADF: c_int = 8; +pub const ECHILD: c_int = 12; +pub const EAGAIN: c_int = 6; +pub const ENOMEM: c_int = 48; +pub const EACCES: c_int = 2; +pub const EFAULT: c_int = 21; +pub const ENOTBLK: c_int = 105; +pub const EBUSY: c_int = 10; +pub const EEXIST: c_int = 20; +pub const EXDEV: c_int = 75; +pub const ENODEV: c_int = 43; +pub const ENOTDIR: c_int = 54; +pub const EISDIR: c_int = 31; +pub const EINVAL: c_int = 28; +pub const ENFILE: c_int = 41; +pub const EMFILE: c_int = 33; +pub const ENOTTY: c_int = 59; +pub const ETXTBSY: c_int = 74; +pub const EFBIG: c_int = 22; +pub const ENOSPC: c_int = 51; +pub const ESPIPE: c_int = 70; +pub const EROFS: c_int = 69; +pub const EMLINK: c_int = 34; +pub const EPIPE: c_int = 64; +pub const EDOM: c_int = 18; +pub const ERANGE: c_int = 68; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const ENOLINK: c_int = 47; +pub const EPROTO: c_int = 65; +pub const EDEADLK: c_int = 16; +pub const EDEADLOCK: c_int = EDEADLK; +pub const ENAMETOOLONG: c_int = 37; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 52; +pub const ENOTEMPTY: c_int = 55; +pub const ELOOP: c_int = 32; +pub const ENOMSG: c_int = 49; +pub const EIDRM: c_int = 24; +pub const EMULTIHOP: c_int = 36; +pub const EBADMSG: c_int = 9; +pub const EOVERFLOW: c_int = 61; +pub const EILSEQ: c_int = 25; +pub const ENOTSOCK: c_int = 57; +pub const EDESTADDRREQ: c_int = 17; +pub const EMSGSIZE: c_int = 35; +pub const EPROTOTYPE: c_int = 67; +pub const ENOPROTOOPT: c_int = 50; +pub const EPROTONOSUPPORT: c_int = 66; +pub const EAFNOSUPPORT: c_int = 5; +pub const EADDRINUSE: c_int = 3; +pub const EADDRNOTAVAIL: c_int = 4; +pub const ENETDOWN: c_int = 38; +pub const ENETUNREACH: c_int = 40; +pub const ENETRESET: c_int = 39; +pub const ECONNABORTED: c_int = 13; +pub const ECONNRESET: c_int = 15; +pub const ENOBUFS: c_int = 42; +pub const EISCONN: c_int = 30; +pub const ENOTCONN: c_int = 53; +pub const ETIMEDOUT: c_int = 73; +pub const ECONNREFUSED: c_int = 14; +pub const EHOSTUNREACH: c_int = 23; +pub const EALREADY: c_int = 7; +pub const EINPROGRESS: c_int = 26; +pub const ESTALE: c_int = 72; +pub const EDQUOT: c_int = 19; +pub const ECANCELED: c_int = 11; +pub const EOWNERDEAD: c_int = 62; +pub const ENOTRECOVERABLE: c_int = 56; + +pub const ENOSTR: c_int = 100; +pub const EBFONT: c_int = 101; +pub const EBADSLT: c_int = 102; +pub const EBADRQC: c_int = 103; +pub const ENOANO: c_int = 104; +pub const ECHRNG: c_int = 106; +pub const EL3HLT: c_int = 107; +pub const EL3RST: c_int = 108; +pub const ELNRNG: c_int = 109; +pub const EUNATCH: c_int = 110; +pub const ENOCSI: c_int = 111; +pub const EL2HLT: c_int = 112; +pub const EBADE: c_int = 113; +pub const EBADR: c_int = 114; +pub const EXFULL: c_int = 115; +pub const ENODATA: c_int = 116; +pub const ETIME: c_int = 117; +pub const ENOSR: c_int = 118; +pub const ENONET: c_int = 119; +pub const ENOPKG: c_int = 120; +pub const EREMOTE: c_int = 121; +pub const EADV: c_int = 122; +pub const ESRMNT: c_int = 123; +pub const ECOMM: c_int = 124; +pub const EDOTDOT: c_int = 125; +pub const ENOTUNIQ: c_int = 126; +pub const EBADFD: c_int = 127; +pub const EREMCHG: c_int = 128; +pub const ELIBACC: c_int = 129; +pub const ELIBBAD: c_int = 130; +pub const ELIBSCN: c_int = 131; +pub const ELIBMAX: c_int = 132; +pub const ELIBEXEC: c_int = 133; +pub const ERESTART: c_int = 134; +pub const ESTRPIPE: c_int = 135; +pub const EUSERS: c_int = 136; +pub const ESOCKTNOSUPPORT: c_int = 137; +pub const EOPNOTSUPP: c_int = 138; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 139; +pub const ESHUTDOWN: c_int = 140; +pub const ETOOMANYREFS: c_int = 141; +pub const EHOSTDOWN: c_int = 142; +pub const EUCLEAN: c_int = 143; +pub const ENOTNAM: c_int = 144; +pub const ENAVAIL: c_int = 145; +pub const EISNAM: c_int = 146; +pub const EREMOTEIO: c_int = 147; +pub const ENOMEDIUM: c_int = 148; +pub const EMEDIUMTYPE: c_int = 149; +pub const ENOKEY: c_int = 150; +pub const EKEYEXPIRED: c_int = 151; +pub const EKEYREVOKED: c_int = 152; +pub const EKEYREJECTED: c_int = 153; +pub const ERFKILL: c_int = 154; +pub const EHWPOISON: c_int = 155; +pub const EL2NSYNC: c_int = 156; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const BUFSIZ: c_uint = 1024; +pub const TMP_MAX: c_uint = 10000; +pub const FOPEN_MAX: c_uint = 1000; +pub const O_PATH: c_int = 0o10000000; +pub const O_EXEC: c_int = 0o10000000; +pub const O_SEARCH: c_int = 0o10000000; +pub const O_ACCMODE: c_int = 0o10000003; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const NI_MAXHOST: crate::socklen_t = 255; +pub const PTHREAD_STACK_MIN: size_t = 2048; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const RLIM_INFINITY: crate::rlim_t = !0; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIMIT_NLIMITS: c_int = 16; +#[allow(deprecated)] +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = RLIMIT_NLIMITS; + +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +#[doc(hidden)] +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = crate::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const CPU_SETSIZE: c_int = 1024; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const TIOCINQ: c_int = crate::FIONREAD; + +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const CLOCK_SGI_CYCLE: crate::clockid_t = 10; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_TIMESTAMP: c_int = 63; +pub const SO_MARK: c_int = 36; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_BUSY_POLL: c_int = 46; + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; + +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_ASYNC: c_int = 0x2000; + +pub const FIOCLEX: c_int = 0x5451; +pub const FIONBIO: c_int = 0x5421; + +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_NOFILE: c_int = 7; +pub const RLIMIT_AS: c_int = 9; +pub const RLIMIT_NPROC: c_int = 6; +pub const RLIMIT_MEMLOCK: c_int = 8; +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_LOCKS: c_int = 10; +pub const RLIMIT_SIGPENDING: c_int = 11; +pub const RLIMIT_MSGQUEUE: c_int = 12; +pub const RLIMIT_NICE: c_int = 13; +pub const RLIMIT_RTPRIO: c_int = 14; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; + +pub const SOCK_NONBLOCK: c_int = 2048; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_SEQPACKET: c_int = 5; + +pub const IPPROTO_MAX: c_int = 263; + +pub const SOL_SOCKET: c_int = 1; + +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_LINGER: c_int = 13; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 66; +pub const SO_SNDTIMEO: c_int = 67; +pub const SO_ACCEPTCONN: c_int = 30; + +pub const IPV6_RTHDR_LOOSE: c_int = 0; +pub const IPV6_RTHDR_STRICT: c_int = 1; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: c_int = 0x040000; + +pub const F_GETLK: c_int = 12; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; +pub const F_SETOWN: c_int = 8; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const TCGETS: c_int = 0x5401; +pub const TCSETS: c_int = 0x5402; +pub const TCSETSW: c_int = 0x5403; +pub const TCSETSF: c_int = 0x5404; +pub const TCGETA: c_int = 0x5405; +pub const TCSETA: c_int = 0x5406; +pub const TCSETAW: c_int = 0x5407; +pub const TCSETAF: c_int = 0x5408; +pub const TCSBRK: c_int = 0x5409; +pub const TCXONC: c_int = 0x540A; +pub const TCFLSH: c_int = 0x540B; +pub const TIOCGSOFTCAR: c_int = 0x5419; +pub const TIOCSSOFTCAR: c_int = 0x541A; +pub const TIOCLINUX: c_int = 0x541C; +pub const TIOCGSERIAL: c_int = 0x541E; +pub const TIOCEXCL: c_int = 0x540C; +pub const TIOCNXCL: c_int = 0x540D; +pub const TIOCSCTTY: c_int = 0x540E; +pub const TIOCGPGRP: c_int = 0x540F; +pub const TIOCSPGRP: c_int = 0x5410; +pub const TIOCOUTQ: c_int = 0x5411; +pub const TIOCSTI: c_int = 0x5412; +pub const TIOCGWINSZ: c_int = 0x5413; +pub const TIOCSWINSZ: c_int = 0x5414; +pub const TIOCMGET: c_int = 0x5415; +pub const TIOCMBIS: c_int = 0x5416; +pub const TIOCMBIC: c_int = 0x5417; +pub const TIOCMSET: c_int = 0x5418; +pub const FIONREAD: c_int = 0x541B; +pub const TIOCCONS: c_int = 0x541D; + +pub const SYS_gettid: c_long = 224; // Valid for arm (32-bit) and x86 (32-bit) + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const O_TMPFILE: c_int = 0x410000; + +pub const MAX_ADDR_LEN: usize = 7; +pub const ARPD_UPDATE: c_ushort = 0x01; +pub const ARPD_LOOKUP: c_ushort = 0x02; +pub const ARPD_FLUSH: c_ushort = 0x03; +pub const ATF_MAGIC: c_int = 0x80; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const SOMAXCONN: c_int = 128; + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < size_of::() { + return core::ptr::null_mut::(); + } + let next = (cmsg as usize + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize >= max { + core::ptr::null_mut::() + } else { + next as *mut cmsghdr + } + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } +} + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major & 0xfffff000) << 31 << 1; + dev |= (major & 0x00000fff) << 8; + dev |= (minor & 0xffffff00) << 12; + dev |= minor & 0x000000ff; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + // see + // https://github.com/emscripten-core/emscripten/blob/ + // main/system/lib/libc/musl/include/sys/sysmacros.h + let mut major = 0; + major |= (dev >> 31 >> 1) & 0xfffff000; + major |= (dev >> 8) & 0x00000fff; + major as c_uint + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + // see + // https://github.com/emscripten-core/emscripten/blob/ + // main/system/lib/libc/musl/include/sys/sysmacros.h + let mut minor = 0; + minor |= (dev >> 12) & 0xffffff00; + minor |= dev & 0x000000ff; + minor as c_uint + } +} + +extern "C" { + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn __errno_location() -> *mut c_int; + + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + pub fn accept4( + fd: c_int, + addr: *mut crate::sockaddr, + len: *mut crate::socklen_t, + flg: c_int, + ) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + + pub fn mremap( + addr: *mut c_void, + len: size_t, + new_len: size_t, + flags: c_int, + ... + ) -> *mut c_void; + + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + ) -> c_int; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + timeout: *mut crate::timespec, + ) -> c_int; + pub fn sync(); + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + // grp.h + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; +} + +// Alias to 64 to mimic glibc's LFS64 support +mod lfs64; +pub use self::lfs64::*; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/l4re/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/l4re/mod.rs new file mode 100644 index 00000000000000..5ac4868f7d1c2b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/l4re/mod.rs @@ -0,0 +1,204 @@ +///! L4Re specifics +///! This module contains definitions required by various L4Re libc backends. +///! Some of them are formally not part of the libc, but are a dependency of the +///! libc and hence we should provide them here. +use crate::prelude::*; + +pub type l4_umword_t = c_ulong; // Unsigned machine word. +pub type pthread_t = *mut c_void; + +pub type dev_t = u64; +pub type socklen_t = u32; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type nfds_t = c_ulong; +pub type nl_item = c_int; +pub type idtype_t = c_uint; +pub type loff_t = c_longlong; +pub type pthread_key_t = c_uint; +pub type pthread_once_t = c_int; +pub type pthread_spinlock_t = c_int; + +s! { + /// CPU sets. + pub struct l4_sched_cpu_set_t { + // from the L4Re docs + /// Combination of granularity and offset. + /// + /// The granularity defines how many CPUs each bit in map describes. + /// The offset is the number of the first CPU described by the first + /// bit in the bitmap. + /// offset must be a multiple of 2^graularity. + /// + /// | MSB | LSB | + /// | ---------------- | ------------------- | + /// | 8bit granularity | 24bit offset .. | + gran_offset: l4_umword_t, + /// Bitmap of CPUs. + map: l4_umword_t, + } + + pub struct pthread_attr_t { + __detachstate: c_int, + __schedpolicy: c_int, + __schedparam: super::__sched_param, + __inheritsched: c_int, + __scope: c_int, + __guardsize: size_t, + __stackaddr_set: c_int, + __stackaddr: *mut c_void, // better don't use it + __stacksize: size_t, + // L4Re specifics + pub affinity: l4_sched_cpu_set_t, + pub create_flags: c_uint, + } +} + +// L4Re requires a min stack size of 64k; that isn't defined in uClibc, but +// somewhere in the core libraries. uClibc wants 16k, but that's not enough. +pub const PTHREAD_STACK_MIN: usize = 65536; + +pub const BOTHER: crate::speed_t = 0o010000; + +pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; +pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; +pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; +pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; +pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; +pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; +pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 6; +pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 7; +pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 8; +pub const RLIMIT_AS: crate::__rlimit_resource_t = 9; +pub const RLIMIT_LOCKS: crate::__rlimit_resource_t = 10; +pub const RLIMIT_SIGPENDING: crate::__rlimit_resource_t = 11; +pub const RLIMIT_MSGQUEUE: crate::__rlimit_resource_t = 12; +pub const RLIMIT_NICE: crate::__rlimit_resource_t = 13; +pub const RLIMIT_RTPRIO: crate::__rlimit_resource_t = 14; +pub const RLIMIT_RTTIME: crate::__rlimit_resource_t = 15; +pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = RLIM_NLIMITS; +pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 16; + +pub const SOL_SOCKET: c_int = 1; + +// pub const SO_DEBUG: c_int = 1; +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 20; +pub const SO_SNDTIMEO: c_int = 21; +pub const SO_SECURITY_AUTHENTICATION: c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: c_int = 24; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_ATTACH_FILTER: c_int = 26; +pub const SO_DETACH_FILTER: c_int = 27; +pub const SO_PEERNAME: c_int = 28; + +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; + +pub const TCGETS: Ioctl = 0x5401; +pub const TCSETS: Ioctl = 0x5402; +pub const TCSETSW: Ioctl = 0x5403; +pub const TCSETSF: Ioctl = 0x5404; +pub const TCGETA: Ioctl = 0x5405; +pub const TCSETA: Ioctl = 0x5406; +pub const TCSETAW: Ioctl = 0x5407; +pub const TCSETAF: Ioctl = 0x5408; +pub const TCSBRK: Ioctl = 0x5409; +pub const TCXONC: Ioctl = 0x540A; +pub const TCFLSH: Ioctl = 0x540B; +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0x100; +pub const TIOCEXCL: Ioctl = 0x540C; +pub const TIOCNXCL: Ioctl = 0x540D; +pub const TIOCSCTTY: Ioctl = 0x540E; +pub const TIOCGPGRP: Ioctl = 0x540F; +pub const TIOCSPGRP: Ioctl = 0x5410; +pub const TIOCOUTQ: Ioctl = 0x5411; +pub const TIOCSTI: Ioctl = 0x5412; +pub const TIOCGWINSZ: Ioctl = 0x5413; +pub const TIOCSWINSZ: Ioctl = 0x5414; +pub const TIOCMGET: Ioctl = 0x5415; +pub const TIOCMBIS: Ioctl = 0x5416; +pub const TIOCMBIC: Ioctl = 0x5417; +pub const TIOCMSET: Ioctl = 0x5418; +pub const TIOCGSOFTCAR: Ioctl = 0x5419; +pub const TIOCSSOFTCAR: Ioctl = 0x541A; +pub const FIONREAD: Ioctl = 0x541B; +pub const TIOCINQ: Ioctl = FIONREAD; +pub const TIOCLINUX: Ioctl = 0x541C; +pub const TIOCCONS: Ioctl = 0x541D; +pub const TIOCGSERIAL: Ioctl = 0x541E; +pub const TIOCSSERIAL: Ioctl = 0x541F; +pub const TIOCPKT: Ioctl = 0x5420; +pub const FIONBIO: Ioctl = 0x5421; +pub const TIOCNOTTY: Ioctl = 0x5422; +pub const TIOCSETD: Ioctl = 0x5423; +pub const TIOCGETD: Ioctl = 0x5424; +pub const TCSBRKP: Ioctl = 0x5425; +pub const TIOCSBRK: Ioctl = 0x5427; +pub const TIOCCBRK: Ioctl = 0x5428; +pub const TIOCGSID: Ioctl = 0x5429; +pub const TIOCGPTN: Ioctl = 0x80045430; +pub const TIOCSPTLCK: Ioctl = 0x40045431; +pub const FIONCLEX: Ioctl = 0x5450; +pub const FIOCLEX: Ioctl = 0x5451; +pub const FIOASYNC: Ioctl = 0x5452; +pub const TIOCSERCONFIG: Ioctl = 0x5453; +pub const TIOCSERGWILD: Ioctl = 0x5454; +pub const TIOCSERSWILD: Ioctl = 0x5455; +pub const TIOCGLCKTRMIOS: Ioctl = 0x5456; +pub const TIOCSLCKTRMIOS: Ioctl = 0x5457; +pub const TIOCSERGSTRUCT: Ioctl = 0x5458; +pub const TIOCSERGETLSR: Ioctl = 0x5459; +pub const TIOCSERGETMULTI: Ioctl = 0x545A; +pub const TIOCSERSETMULTI: Ioctl = 0x545B; +pub const TIOCMIWAIT: Ioctl = 0x545C; +pub const TIOCGICOUNT: Ioctl = 0x545D; + +pub const BLKSSZGET: Ioctl = 0x1268; + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + pub const NLMSG_NOOP: c_int = 0x1; + pub const NLMSG_ERROR: c_int = 0x2; + pub const NLMSG_DONE: c_int = 0x3; + pub const NLMSG_OVERRUN: c_int = 0x4; + pub const NLMSG_MIN_TYPE: c_int = 0x10; + } +} + +cfg_if! { + if #[cfg(target_env = "uclibc")] { + mod uclibc; + pub use self::uclibc::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/aarch64/mod.rs new file mode 100644 index 00000000000000..3a471700f64375 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/aarch64/mod.rs @@ -0,0 +1,414 @@ +use crate::prelude::*; + +pub type wchar_t = c_uint; +pub type time_t = c_long; + +pub type clock_t = c_long; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulong; +pub type nlink_t = c_ulong; +pub type off_t = c_long; +pub type fsword_t = c_long; +pub type suseconds_t = c_long; + +pub type blksize_t = c_long; +pub type blkcnt_t = c_long; + +pub type fsblkcnt64_t = c_ulong; +pub type fsfilcnt64_t = c_ulong; +pub type __u64 = c_ulong; + +s! { + pub struct stat { + pub st_dev: c_ulong, + pub __pad1: c_ushort, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + pub __pad2: c_ushort, + pub st_size: crate::off64_t, + pub st_blksize: blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + pub __uclibc_unused4: c_ulong, + pub __uclibc_unused5: c_ulong, + } + + pub struct stat64 { + pub st_dev: c_ulong, + pub __pad1: c_uint, + pub __st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + pub __pad2: c_uint, + pub st_size: crate::off64_t, + pub st_blksize: blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + pub st_ino: crate::ino64_t, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: crate::size_t, + pub shm_atime: crate::time_t, + __unused1: c_ulong, + pub shm_dtime: crate::time_t, + __unused2: c_ulong, + pub shm_ctime: crate::time_t, + __unused3: c_ulong, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: c_ulong, + __unused5: c_ulong, + } + + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_handler: crate::sighandler_t, + pub sa_flags: c_ulong, + pub sa_restorer: Option, + pub sa_mask: sigset_t, + } + + pub struct sigset_t { + __val: [c_ulong; 1], + } + + #[repr(align(8))] + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 28], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: crate::size_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } +} + +s_no_extra_traits! { + pub union sem_t { + __size: [c_char; 32], + __align: c_longlong, + } +} + +pub const O_CLOEXEC: c_int = 0o2000000; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 36; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; +pub const __SIZEOF_PTHREAD_COND_COMPAT_T: usize = 12; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +pub const NCCS: usize = 32; + +pub const FIOQSIZE: crate::Ioctl = 0x545E; + +// I wasn't able to find those constants +// in uclibc build environment for armv7 +pub const MAP_HUGETLB: c_int = 0x040000; // from linux/other/mod.rs + +// autogenerated constants with hand tuned types +pub const B0: crate::speed_t = 0; +pub const B1000000: crate::speed_t = 0x1008; +pub const B110: crate::speed_t = 0x3; +pub const B115200: crate::speed_t = 0x1002; +pub const B1152000: crate::speed_t = 0x1009; +pub const B1200: crate::speed_t = 0x9; +pub const B134: crate::speed_t = 0x4; +pub const B150: crate::speed_t = 0x5; +pub const B1500000: crate::speed_t = 0x100a; +pub const B1800: crate::speed_t = 0xa; +pub const B19200: crate::speed_t = 0xe; +pub const B200: crate::speed_t = 0x6; +pub const B2000000: crate::speed_t = 0x100b; +pub const B230400: crate::speed_t = 0x1003; +pub const B2400: crate::speed_t = 0xb; +pub const B2500000: crate::speed_t = 0x100c; +pub const B300: crate::speed_t = 0x7; +pub const B3000000: crate::speed_t = 0x100d; +pub const B3500000: crate::speed_t = 0x100e; +pub const B38400: crate::speed_t = 0xf; +pub const B4000000: crate::speed_t = 0x100f; +pub const B460800: crate::speed_t = 0x1004; +pub const B4800: crate::speed_t = 0xc; +pub const B50: crate::speed_t = 0x1; +pub const B500000: crate::speed_t = 0x1005; +pub const B57600: crate::speed_t = 0x1001; +pub const B576000: crate::speed_t = 0x1006; +pub const B600: crate::speed_t = 0x8; +pub const B75: crate::speed_t = 0x2; +pub const B921600: crate::speed_t = 0x1007; +pub const B9600: crate::speed_t = 0xd; +pub const BS1: c_int = 0x2000; +pub const BSDLY: c_int = 0x2000; +pub const CBAUD: crate::tcflag_t = 0x100f; +pub const CBAUDEX: crate::tcflag_t = 0x1000; +pub const CIBAUD: crate::tcflag_t = 0x100f0000; +pub const CLOCAL: crate::tcflag_t = 0x800; +pub const CPU_SETSIZE: c_int = 0x400; +pub const CR1: c_int = 0x200; +pub const CR2: c_int = 0x400; +pub const CR3: c_int = 0x600; +pub const CRDLY: c_int = 0x600; +pub const CREAD: crate::tcflag_t = 0x80; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSIZE: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x40; +pub const EADDRINUSE: c_int = 0x62; +pub const EADDRNOTAVAIL: c_int = 0x63; +pub const EADV: c_int = 0x44; +pub const EAFNOSUPPORT: c_int = 0x61; +pub const EALREADY: c_int = 0x72; +pub const EBADE: c_int = 0x34; +pub const EBADFD: c_int = 0x4d; +pub const EBADMSG: c_int = 0x4a; +pub const EBADR: c_int = 0x35; +pub const EBADRQC: c_int = 0x38; +pub const EBADSLT: c_int = 0x39; +pub const EBFONT: c_int = 0x3b; +pub const ECANCELED: c_int = 0x7d; +pub const ECHOCTL: crate::tcflag_t = 0x200; +pub const ECHOE: crate::tcflag_t = 0x10; +pub const ECHOK: crate::tcflag_t = 0x20; +pub const ECHOKE: crate::tcflag_t = 0x800; +pub const ECHONL: crate::tcflag_t = 0x40; +pub const ECHOPRT: crate::tcflag_t = 0x400; +pub const ECHRNG: c_int = 0x2c; +pub const ECOMM: c_int = 0x46; +pub const ECONNABORTED: c_int = 0x67; +pub const ECONNREFUSED: c_int = 0x6f; +pub const ECONNRESET: c_int = 0x68; +pub const EDESTADDRREQ: c_int = 0x59; +pub const EDOTDOT: c_int = 0x49; +pub const EDQUOT: c_int = 0x7a; +pub const EHOSTDOWN: c_int = 0x70; +pub const EHOSTUNREACH: c_int = 0x71; +pub const EIDRM: c_int = 0x2b; +pub const EILSEQ: c_int = 0x54; +pub const EINPROGRESS: c_int = 0x73; +pub const EISCONN: c_int = 0x6a; +pub const EISNAM: c_int = 0x78; +pub const EKEYEXPIRED: c_int = 0x7f; +pub const EKEYREJECTED: c_int = 0x81; +pub const EKEYREVOKED: c_int = 0x80; +pub const EL2HLT: c_int = 0x33; +pub const EL2NSYNC: c_int = 0x2d; +pub const EL3HLT: c_int = 0x2e; +pub const EL3RST: c_int = 0x2f; +pub const ELIBACC: c_int = 0x4f; +pub const ELIBBAD: c_int = 0x50; +pub const ELIBEXEC: c_int = 0x53; +pub const ELIBMAX: c_int = 0x52; +pub const ELIBSCN: c_int = 0x51; +pub const ELNRNG: c_int = 0x30; +pub const ELOOP: c_int = 0x28; +pub const EMEDIUMTYPE: c_int = 0x7c; +pub const EMSGSIZE: c_int = 0x5a; +pub const EMULTIHOP: c_int = 0x48; +pub const ENAMETOOLONG: c_int = 0x24; +pub const ENAVAIL: c_int = 0x77; +pub const ENETDOWN: c_int = 0x64; +pub const ENETRESET: c_int = 0x66; +pub const ENETUNREACH: c_int = 0x65; +pub const ENOANO: c_int = 0x37; +pub const ENOBUFS: c_int = 0x69; +pub const ENOCSI: c_int = 0x32; +pub const ENODATA: c_int = 0x3d; +pub const ENOKEY: c_int = 0x7e; +pub const ENOLCK: c_int = 0x25; +pub const ENOLINK: c_int = 0x43; +pub const ENOMEDIUM: c_int = 0x7b; +pub const ENOMSG: c_int = 0x2a; +pub const ENONET: c_int = 0x40; +pub const ENOPKG: c_int = 0x41; +pub const ENOPROTOOPT: c_int = 0x5c; +pub const ENOSR: c_int = 0x3f; +pub const ENOSTR: c_int = 0x3c; +pub const ENOSYS: c_int = 0x26; +pub const ENOTCONN: c_int = 0x6b; +pub const ENOTEMPTY: c_int = 0x27; +pub const ENOTNAM: c_int = 0x76; +pub const ENOTRECOVERABLE: c_int = 0x83; +pub const ENOTSOCK: c_int = 0x58; +pub const ENOTUNIQ: c_int = 0x4c; +pub const EOPNOTSUPP: c_int = 0x5f; +pub const EOVERFLOW: c_int = 0x4b; +pub const EOWNERDEAD: c_int = 0x82; +pub const EPFNOSUPPORT: c_int = 0x60; +pub const EPOLL_CLOEXEC: c_int = 0x80000; +pub const EPROTO: c_int = 0x47; +pub const EPROTONOSUPPORT: c_int = 0x5d; +pub const EPROTOTYPE: c_int = 0x5b; +pub const EREMCHG: c_int = 0x4e; +pub const EREMOTE: c_int = 0x42; +pub const EREMOTEIO: c_int = 0x79; +pub const ERESTART: c_int = 0x55; +pub const ESHUTDOWN: c_int = 0x6c; +pub const ESOCKTNOSUPPORT: c_int = 0x5e; +pub const ESRMNT: c_int = 0x45; +pub const ESTALE: c_int = 0x74; +pub const ESTRPIPE: c_int = 0x56; +pub const ETIME: c_int = 0x3e; +pub const ETIMEDOUT: c_int = 0x6e; +pub const ETOOMANYREFS: c_int = 0x6d; +pub const EUCLEAN: c_int = 0x75; +pub const EUNATCH: c_int = 0x31; +pub const EUSERS: c_int = 0x57; +pub const EXFULL: c_int = 0x36; +pub const FF1: c_int = 0x8000; +pub const FFDLY: c_int = 0x8000; +pub const FLUSHO: crate::tcflag_t = 0x1000; +pub const F_GETLK: c_int = 0x5; +pub const F_SETLK: c_int = 0x6; +pub const F_SETLKW: c_int = 0x7; +pub const HUPCL: crate::tcflag_t = 0x400; +pub const ICANON: crate::tcflag_t = 0x2; +pub const IEXTEN: crate::tcflag_t = 0x8000; +pub const ISIG: crate::tcflag_t = 0x1; +pub const IXOFF: crate::tcflag_t = 0x1000; +pub const IXON: crate::tcflag_t = 0x400; +pub const MAP_ANON: c_int = 0x20; +pub const MAP_ANONYMOUS: c_int = 0x20; +pub const MAP_DENYWRITE: c_int = 0x800; +pub const MAP_EXECUTABLE: c_int = 0x1000; +pub const MAP_GROWSDOWN: c_int = 0x100; +pub const MAP_LOCKED: c_int = 0x2000; +pub const MAP_NONBLOCK: c_int = 0x10000; +pub const MAP_NORESERVE: c_int = 0x4000; +pub const MAP_POPULATE: c_int = 0x8000; +pub const MAP_STACK: c_int = 0x20000; +pub const MINSIGSTKSZ: c_int = 5120; +pub const NLDLY: crate::tcflag_t = 0x100; +pub const NOFLSH: crate::tcflag_t = 0x80; +pub const OLCUC: crate::tcflag_t = 0x2; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const O_ACCMODE: c_int = 0x3; +pub const O_APPEND: c_int = 0x400; +pub const O_ASYNC: c_int = 0o20000; +pub const O_CREAT: c_int = 0x40; +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_DSYNC: c_int = O_SYNC; +pub const O_EXCL: c_int = 0x80; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_LARGEFILE: c_int = 0o400000; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_NOCTTY: c_int = 0x100; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_NONBLOCK: c_int = 0x800; +pub const O_PATH: c_int = 0o10000000; +pub const O_RSYNC: c_int = O_SYNC; +pub const O_SYNC: c_int = 0o10000; +pub const O_TRUNC: c_int = 0x200; +pub const PARENB: crate::tcflag_t = 0x100; +pub const PARODD: crate::tcflag_t = 0x200; +pub const PENDIN: crate::tcflag_t = 0x4000; +pub const POLLWRBAND: c_short = 0x200; +pub const POLLWRNORM: c_short = 0x100; +pub const RTLD_GLOBAL: c_int = 0x00100; + +// These are typed unsigned to match sigaction +pub const SA_NOCLDSTOP: c_ulong = 0x1; +pub const SA_NOCLDWAIT: c_ulong = 0x2; +pub const SA_SIGINFO: c_ulong = 0x4; +pub const SA_NODEFER: c_ulong = 0x40000000; +pub const SA_ONSTACK: c_ulong = 0x8000000; +pub const SA_RESETHAND: c_ulong = 0x80000000; +pub const SA_RESTART: c_ulong = 0x10000000; + +pub const SIGBUS: c_int = 0x7; +pub const SIGCHLD: c_int = 0x11; +pub const SIGCONT: c_int = 0x12; +pub const SIGIO: c_int = 0x1d; +pub const SIGPOLL: c_int = SIGIO; +pub const SIGPROF: c_int = 0x1b; +pub const SIGPWR: c_int = 0x1e; +pub const SIGSTKFLT: c_int = 0x10; +pub const SIGSTKSZ: c_int = 16384; +pub const SIGSTOP: c_int = 0x13; +pub const SIGSYS: c_int = 0x1f; +pub const SIGTSTP: c_int = 0x14; +pub const SIGTTIN: c_int = 0x15; +pub const SIGTTOU: c_int = 0x16; +pub const SIGURG: c_int = 0x17; +pub const SIGUSR1: c_int = 0xa; +pub const SIGUSR2: c_int = 0xc; +pub const SIGVTALRM: c_int = 0x1a; +pub const SIGWINCH: c_int = 0x1c; +pub const SIGXCPU: c_int = 0x18; +pub const SIGXFSZ: c_int = 0x19; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 0x1; +pub const SIG_SETMASK: c_int = 0x2; +pub const SOCK_DGRAM: c_int = 0x2; +pub const SOCK_NONBLOCK: c_int = 0o0004000; +pub const SOCK_SEQPACKET: c_int = 0x5; +pub const SOCK_STREAM: c_int = 0x1; + +pub const TAB1: c_int = 0x800; +pub const TAB2: c_int = 0x1000; +pub const TAB3: c_int = 0x1800; +pub const TABDLY: c_int = 0x1800; +pub const TCSADRAIN: c_int = 0x1; +pub const TCSAFLUSH: c_int = 0x2; +pub const TCSANOW: c_int = 0; +pub const TOSTOP: crate::tcflag_t = 0x100; +pub const VDISCARD: usize = 0xd; +pub const VEOF: usize = 0x4; +pub const VEOL: usize = 0xb; +pub const VEOL2: usize = 0x10; +pub const VMIN: usize = 0x6; +pub const VREPRINT: usize = 0xc; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VSUSP: usize = 0xa; +pub const VSWTC: usize = 0x7; +pub const VT1: c_int = 0x4000; +pub const VTDLY: c_int = 0x4000; +pub const VTIME: usize = 0x5; +pub const VWERASE: usize = 0xe; +pub const XTABS: crate::tcflag_t = 0x1800; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/mod.rs new file mode 100644 index 00000000000000..e593ad76d4fc2a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/mod.rs @@ -0,0 +1,538 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type shmatt_t = c_ulong; +pub type regoff_t = c_int; +pub type rlim_t = c_ulong; +pub type __rlimit_resource_t = c_int; +pub type __priority_which_t = c_uint; + +pub type _pthread_descr = *mut c_void; +pub type __pthread_cond_align_t = c_long; + +cfg_if! { + if #[cfg(doc)] { + // Used in `linux::arch` to define ioctl constants. + pub(crate) type Ioctl = c_ulong; + } else { + #[doc(hidden)] + pub type Ioctl = c_ulong; + } +} + +s! { + pub struct cmsghdr { + pub cmsg_len: crate::size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + #[cfg(target_pointer_width = "32")] + pub msg_iovlen: c_int, + #[cfg(target_pointer_width = "64")] + pub msg_iovlen: crate::size_t, + pub msg_control: *mut c_void, + #[cfg(target_pointer_width = "32")] + pub msg_controllen: crate::socklen_t, + #[cfg(target_pointer_width = "64")] + pub msg_controllen: crate::size_t, + pub msg_flags: c_int, + } + + pub struct statfs { + pub f_type: fsword_t, + pub f_bsize: fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: fsword_t, + pub f_frsize: fsword_t, + pub f_flags: fsword_t, + pub f_spare: [fsword_t; 4], + } + + pub struct statfs64 { + pub f_type: fsword_t, + pub f_bsize: fsword_t, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: fsword_t, + pub f_frsize: fsword_t, + pub f_flags: fsword_t, + pub f_spare: [fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsfilcnt64_t, + pub f_bfree: crate::fsfilcnt64_t, + pub f_bavail: crate::fsfilcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_favail: crate::fsfilcnt64_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub __f_spare: [c_int; 6], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + #[cfg(target_pointer_width = "32")] + pub mode: c_ushort, + #[cfg(target_pointer_width = "64")] + pub mode: c_uint, + #[cfg(target_pointer_width = "32")] + __pad1: c_ushort, + pub __seq: c_ushort, + __pad2: c_ushort, + __unused1: c_ulong, + __unused2: c_ulong, + } + + pub struct statvfs { + // Different than GNU! + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: c_ulong, + #[cfg(target_pointer_width = "32")] + __f_unused: c_int, + #[cfg(target_endian = "big")] + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + #[cfg(target_pointer_width = "32")] + pub _f: [c_char; 8], + #[cfg(target_pointer_width = "64")] + pub _f: [c_char; 0], + } + + pub struct regex_t { + __buffer: *mut c_void, + __allocated: size_t, + __used: size_t, + __syntax: c_ulong, + __fastmap: *mut c_char, + __translate: *mut c_char, + __re_nsub: size_t, + __bitfield: u8, + } + + pub struct rtentry { + pub rt_pad1: c_ulong, + pub rt_dst: crate::sockaddr, + pub rt_gateway: crate::sockaddr, + pub rt_genmask: crate::sockaddr, + pub rt_flags: c_ushort, + pub rt_pad2: c_short, + pub rt_pad3: c_ulong, + pub rt_tos: c_uchar, + pub rt_class: c_uchar, + #[cfg(target_pointer_width = "64")] + pub rt_pad4: [c_short; 3usize], + #[cfg(not(target_pointer_width = "64"))] + pub rt_pad4: c_short, + pub rt_metric: c_short, + pub rt_dev: *mut c_char, + pub rt_mtu: c_ulong, + pub rt_window: c_ulong, + pub rt_irtt: c_ushort, + } + + pub struct __exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct tcp_info { + pub tcpi_state: u8, + pub tcpi_ca_state: u8, + pub tcpi_retransmits: u8, + pub tcpi_probes: u8, + pub tcpi_backoff: u8, + pub tcpi_options: u8, + /// This contains the bitfields `tcpi_snd_wscale` and `tcpi_rcv_wscale`. + /// Each is 4 bits. + pub tcpi_snd_rcv_wscale: u8, + pub tcpi_rto: u32, + pub tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub tcpi_unacked: u32, + pub tcpi_sacked: u32, + pub tcpi_lost: u32, + pub tcpi_retrans: u32, + pub tcpi_fackets: u32, + pub tcpi_last_data_sent: u32, + pub tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub tcpi_last_ack_recv: u32, + pub tcpi_pmtu: u32, + pub tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub tcpi_advmss: u32, + pub tcpi_reordering: u32, + pub tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_total_retrans: u32, + } + + pub struct __sched_param { + __sched_priority: c_int, + } + + pub struct _pthread_fastlock { + __status: c_long, + __spinlock: c_int, + } + + pub struct pthread_cond_t { + __c_lock: _pthread_fastlock, + __c_waiting: _pthread_descr, + __padding: [u8; PTHREAD_COND_PADDING_SIZE], + __align: __pthread_cond_align_t, + } + + pub struct pthread_condattr_t { + __dummy: c_int, + } + + pub struct pthread_mutex_t { + __m_reserved: c_int, + __m_count: c_int, + __m_owner: _pthread_descr, + __m_kind: c_int, + __m_lock: _pthread_fastlock, + } + + pub struct pthread_mutexattr_t { + __mutexkind: c_int, + } + + pub struct pthread_rwlock_t { + __rw_lock: _pthread_fastlock, + __rw_readers: c_int, + __rw_writer: _pthread_descr, + __rw_read_waiting: _pthread_descr, + __rw_write_waiting: _pthread_descr, + __rw_kind: c_int, + __rw_pshared: c_int, + } + + pub struct pthread_rwlockattr_t { + __lockkind: c_int, + __pshared: c_int, + } + + pub struct pthread_barrier_t { + __ba_lock: _pthread_fastlock, + __ba_required: c_int, + __ba_present: c_int, + __ba_waiting: _pthread_descr, + } + + pub struct pthread_barrierattr_t { + __pshared: c_int, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*core::ptr::from_ref(self).cast::()).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_si_value { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_timerid: c_int, + _si_overrun: c_int, + si_value: crate::sigval, + } + (*core::ptr::from_ref(self).cast::()).si_value + } +} + +s_no_extra_traits! { + // Internal, for casts to access union fields + struct sifields_sigchld { + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: c_long, + si_stime: c_long, + } + + // Internal, for casts to access union fields + union sifields { + _align_pointer: *mut c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + struct siginfo_f { + _siginfo_base: [c_int; 3], + sifields: sifields, + } +} + +impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*core::ptr::from_ref(self).cast::()).sifields + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> c_long { + self.sifields().sigchld.si_stime + } +} + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGEV_THREAD_ID: c_int = 4; + +pub const AF_VSOCK: c_int = 40; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +// These are different than GNU! +pub const LC_CTYPE: c_int = 0; +pub const LC_NUMERIC: c_int = 1; +pub const LC_TIME: c_int = 3; +pub const LC_COLLATE: c_int = 4; +pub const LC_MONETARY: c_int = 2; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = 6; +// end different section + +// MS_ flags for mount(2) +pub const MS_RMT_MASK: c_ulong = + crate::MS_RDONLY | crate::MS_SYNCHRONOUS | crate::MS_MANDLOCK | crate::MS_I_VERSION; + +pub const ENOTSUP: c_int = EOPNOTSUPP; + +pub const IPV6_JOIN_GROUP: c_int = 20; +pub const IPV6_LEAVE_GROUP: c_int = 21; + +// Different than Gnu. +pub const FILENAME_MAX: c_uint = 4095; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const SOMAXCONN: c_int = 128; + +pub const ST_RELATIME: c_ulong = 4096; + +pub const SO_TIMESTAMP: c_int = 29; + +pub const RLIM_INFINITY: crate::rlim_t = !0; + +pub const AF_NFC: c_int = PF_NFC; +pub const BUFSIZ: c_int = 256; +pub const EDEADLK: c_int = 0x23; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EXTA: c_uint = B19200; +pub const EXTB: c_uint = B38400; +pub const EXTPROC: crate::tcflag_t = 0o200000; +pub const FOPEN_MAX: c_int = 16; +pub const F_GETOWN: c_int = 9; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; +pub const F_RDLCK: c_int = 0; +pub const F_SETOWN: c_int = 8; +pub const F_UNLCK: c_int = 2; +pub const F_WRLCK: c_int = 1; +pub const IPV6_MULTICAST_ALL: c_int = 29; +pub const IPV6_ROUTER_ALERT_ISOLATE: c_int = 30; +pub const MAP_HUGE_SHIFT: c_int = 26; +pub const MAP_HUGE_MASK: c_int = 0x3f; +pub const MSG_COPY: c_int = 0o40000; +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; +pub const PACKET_MR_UNICAST: c_int = 3; +pub const PF_NFC: c_int = 39; +pub const PF_VSOCK: c_int = 40; +pub const RTLD_NOLOAD: c_int = 0x00004; +pub const RUSAGE_THREAD: c_int = 1; +pub const SHM_EXEC: c_int = 0o100000; +pub const SOCK_DCCP: c_int = 6; +pub const SOCK_PACKET: c_int = 10; +pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; +pub const UDP_GRO: c_int = 104; +pub const UDP_SEGMENT: c_int = 103; + +pub const PTHREAD_RWLOCK_PREFER_READER_NP: c_int = 0; +pub const PTHREAD_RWLOCK_PREFER_WRITER_NP: c_int = 1; +pub const PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP: c_int = 2; +pub const PTHREAD_RWLOCK_DEFAULT_NP: c_int = PTHREAD_RWLOCK_PREFER_WRITER_NP; + +pub const PTHREAD_MUTEX_TIMED_NP: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE_NP: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK_NP: c_int = 2; +pub const PTHREAD_MUTEX_ADAPTIVE_NP: c_int = 3; + +pub const __LT_SPINLOCK_INIT: c_int = 0; + +pub const __LOCK_INITIALIZER: _pthread_fastlock = _pthread_fastlock { + __status: 0, + __spinlock: __LT_SPINLOCK_INIT, +}; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __m_reserved: 0, + __m_count: 0, + __m_owner: core::ptr::null_mut(), + __m_kind: PTHREAD_MUTEX_TIMED_NP, + __m_lock: __LOCK_INITIALIZER, +}; + +const PTHREAD_COND_PADDING_SIZE: usize = 48 + - size_of::<_pthread_fastlock>() + - size_of::<_pthread_descr>() + - size_of::<__pthread_cond_align_t>(); + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __c_lock: __LOCK_INITIALIZER, + __c_waiting: core::ptr::null_mut(), + __padding: [0; PTHREAD_COND_PADDING_SIZE], + __align: 0, +}; + +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __rw_lock: __LOCK_INITIALIZER, + __rw_readers: 0, + __rw_writer: core::ptr::null_mut(), + __rw_read_waiting: core::ptr::null_mut(), + __rw_write_waiting: core::ptr::null_mut(), + __rw_kind: PTHREAD_RWLOCK_DEFAULT_NP, + __rw_pshared: crate::PTHREAD_PROCESS_PRIVATE, +}; + +extern "C" { + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + + pub fn pthread_rwlockattr_getkind_np( + attr: *const crate::pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setkind_np( + attr: *mut crate::pthread_rwlockattr_t, + val: c_int, + ) -> c_int; + + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off64_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off64_t) -> ssize_t; + + pub fn getrlimit64(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit64) -> c_int; + pub fn setrlimit64(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit64) + -> c_int; + pub fn getrlimit(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit) -> c_int; + pub fn getauxval(type_: c_ulong) -> c_ulong; + +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + // unsupported target + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/x86_64/mod.rs new file mode 100644 index 00000000000000..bb4b2ed4a6fea3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/l4re/uclibc/x86_64/mod.rs @@ -0,0 +1,416 @@ +//! Definitions for uclibc on 64bit systems + +use crate::prelude::*; + +pub type wchar_t = c_int; +pub type time_t = c_long; + +pub type clock_t = c_long; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulong; +pub type nlink_t = c_ulong; +pub type off_t = c_long; +pub type fsword_t = c_long; +pub type suseconds_t = c_long; + +pub type blksize_t = c_long; +pub type blkcnt_t = c_long; + +pub type fsblkcnt64_t = c_ulong; +pub type fsfilcnt64_t = c_ulong; + +pub type __u32 = c_uint; +pub type __u64 = c_ulong; + +s! { + pub struct stat { + pub st_dev: c_ulong, + pub st_ino: crate::ino_t, + // According to uclibc/libc/sysdeps/linux/x86_64/bits/stat.h, order of + // nlink and mode are swapped on 64 bit systems. + pub st_nlink: nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: c_int, + pub st_rdev: c_ulong, + pub st_size: crate::off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + __uclibc_unused: [c_long; 3], + } + + pub struct stat64 { + pub st_dev: c_ulong, + pub st_ino: crate::ino_t, + pub st_nlink: nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: c_int, + pub st_rdev: c_ulong, + pub st_size: crate::off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + st_pad4: [c_long; 3], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: crate::size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: c_ulong, + __unused5: c_ulong, + } + + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_handler: crate::sighandler_t, + pub sa_flags: c_ulong, + pub sa_restorer: Option, + pub sa_mask: sigset_t, + } + + pub struct sigset_t { + __val: [c_ulong; 1], + } + + #[repr(align(8))] + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 28], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: crate::size_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } +} + +s_no_extra_traits! { + pub union sem_t { + #[cfg(target_pointer_width = "32")] + __size: [c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [c_char; 32], + __align: [c_long; 0], + } +} + +pub const O_CLOEXEC: c_int = 0o2000000; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 36; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; +pub const __SIZEOF_PTHREAD_COND_COMPAT_T: usize = 12; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +pub const NCCS: usize = 32; + +pub const FIOQSIZE: crate::Ioctl = 0x5460; + +// I wasn't able to find those constants +// in uclibc build environment for armv7 +pub const MAP_HUGETLB: c_int = 0x040000; // from linux/other/mod.rs + +// autogenerated constants with hand tuned types +pub const B0: crate::speed_t = 0; +pub const B1000000: crate::speed_t = 0x1008; +pub const B110: crate::speed_t = 0x3; +pub const B115200: crate::speed_t = 0x1002; +pub const B1152000: crate::speed_t = 0x1009; +pub const B1200: crate::speed_t = 0x9; +pub const B134: crate::speed_t = 0x4; +pub const B150: crate::speed_t = 0x5; +pub const B1500000: crate::speed_t = 0x100a; +pub const B1800: crate::speed_t = 0xa; +pub const B19200: crate::speed_t = 0xe; +pub const B200: crate::speed_t = 0x6; +pub const B2000000: crate::speed_t = 0x100b; +pub const B230400: crate::speed_t = 0x1003; +pub const B2400: crate::speed_t = 0xb; +pub const B2500000: crate::speed_t = 0x100c; +pub const B300: crate::speed_t = 0x7; +pub const B3000000: crate::speed_t = 0x100d; +pub const B3500000: crate::speed_t = 0x100e; +pub const B38400: crate::speed_t = 0xf; +pub const B4000000: crate::speed_t = 0x100f; +pub const B460800: crate::speed_t = 0x1004; +pub const B4800: crate::speed_t = 0xc; +pub const B50: crate::speed_t = 0x1; +pub const B500000: crate::speed_t = 0x1005; +pub const B57600: crate::speed_t = 0x1001; +pub const B576000: crate::speed_t = 0x1006; +pub const B600: crate::speed_t = 0x8; +pub const B75: crate::speed_t = 0x2; +pub const B921600: crate::speed_t = 0x1007; +pub const B9600: crate::speed_t = 0xd; +pub const BS1: c_int = 0x2000; +pub const BSDLY: c_int = 0x2000; +pub const CBAUD: crate::tcflag_t = 0x100f; +pub const CBAUDEX: crate::tcflag_t = 0x1000; +pub const CIBAUD: crate::tcflag_t = 0x100f0000; +pub const CLOCAL: crate::tcflag_t = 0x800; +pub const CPU_SETSIZE: c_int = 0x400; +pub const CR1: c_int = 0x200; +pub const CR2: c_int = 0x400; +pub const CR3: c_int = 0x600; +pub const CRDLY: c_int = 0x600; +pub const CREAD: crate::tcflag_t = 0x80; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSIZE: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x40; +pub const EADDRINUSE: c_int = 0x62; +pub const EADDRNOTAVAIL: c_int = 0x63; +pub const EADV: c_int = 0x44; +pub const EAFNOSUPPORT: c_int = 0x61; +pub const EALREADY: c_int = 0x72; +pub const EBADE: c_int = 0x34; +pub const EBADFD: c_int = 0x4d; +pub const EBADMSG: c_int = 0x4a; +pub const EBADR: c_int = 0x35; +pub const EBADRQC: c_int = 0x38; +pub const EBADSLT: c_int = 0x39; +pub const EBFONT: c_int = 0x3b; +pub const ECANCELED: c_int = 0x7d; +pub const ECHOCTL: crate::tcflag_t = 0x200; +pub const ECHOE: crate::tcflag_t = 0x10; +pub const ECHOK: crate::tcflag_t = 0x20; +pub const ECHOKE: crate::tcflag_t = 0x800; +pub const ECHONL: crate::tcflag_t = 0x40; +pub const ECHOPRT: crate::tcflag_t = 0x400; +pub const ECHRNG: c_int = 0x2c; +pub const ECOMM: c_int = 0x46; +pub const ECONNABORTED: c_int = 0x67; +pub const ECONNREFUSED: c_int = 0x6f; +pub const ECONNRESET: c_int = 0x68; +pub const EDESTADDRREQ: c_int = 0x59; +pub const EDOTDOT: c_int = 0x49; +pub const EDQUOT: c_int = 0x7a; +pub const EHOSTDOWN: c_int = 0x70; +pub const EHOSTUNREACH: c_int = 0x71; +pub const EIDRM: c_int = 0x2b; +pub const EILSEQ: c_int = 0x54; +pub const EINPROGRESS: c_int = 0x73; +pub const EISCONN: c_int = 0x6a; +pub const EISNAM: c_int = 0x78; +pub const EKEYEXPIRED: c_int = 0x7f; +pub const EKEYREJECTED: c_int = 0x81; +pub const EKEYREVOKED: c_int = 0x80; +pub const EL2HLT: c_int = 0x33; +pub const EL2NSYNC: c_int = 0x2d; +pub const EL3HLT: c_int = 0x2e; +pub const EL3RST: c_int = 0x2f; +pub const ELIBACC: c_int = 0x4f; +pub const ELIBBAD: c_int = 0x50; +pub const ELIBEXEC: c_int = 0x53; +pub const ELIBMAX: c_int = 0x52; +pub const ELIBSCN: c_int = 0x51; +pub const ELNRNG: c_int = 0x30; +pub const ELOOP: c_int = 0x28; +pub const EMEDIUMTYPE: c_int = 0x7c; +pub const EMSGSIZE: c_int = 0x5a; +pub const EMULTIHOP: c_int = 0x48; +pub const ENAMETOOLONG: c_int = 0x24; +pub const ENAVAIL: c_int = 0x77; +pub const ENETDOWN: c_int = 0x64; +pub const ENETRESET: c_int = 0x66; +pub const ENETUNREACH: c_int = 0x65; +pub const ENOANO: c_int = 0x37; +pub const ENOBUFS: c_int = 0x69; +pub const ENOCSI: c_int = 0x32; +pub const ENODATA: c_int = 0x3d; +pub const ENOKEY: c_int = 0x7e; +pub const ENOLCK: c_int = 0x25; +pub const ENOLINK: c_int = 0x43; +pub const ENOMEDIUM: c_int = 0x7b; +pub const ENOMSG: c_int = 0x2a; +pub const ENONET: c_int = 0x40; +pub const ENOPKG: c_int = 0x41; +pub const ENOPROTOOPT: c_int = 0x5c; +pub const ENOSR: c_int = 0x3f; +pub const ENOSTR: c_int = 0x3c; +pub const ENOSYS: c_int = 0x26; +pub const ENOTCONN: c_int = 0x6b; +pub const ENOTEMPTY: c_int = 0x27; +pub const ENOTNAM: c_int = 0x76; +pub const ENOTRECOVERABLE: c_int = 0x83; +pub const ENOTSOCK: c_int = 0x58; +pub const ENOTUNIQ: c_int = 0x4c; +pub const EOPNOTSUPP: c_int = 0x5f; +pub const EOVERFLOW: c_int = 0x4b; +pub const EOWNERDEAD: c_int = 0x82; +pub const EPFNOSUPPORT: c_int = 0x60; +pub const EPOLL_CLOEXEC: c_int = 0x80000; +pub const EPROTO: c_int = 0x47; +pub const EPROTONOSUPPORT: c_int = 0x5d; +pub const EPROTOTYPE: c_int = 0x5b; +pub const EREMCHG: c_int = 0x4e; +pub const EREMOTE: c_int = 0x42; +pub const EREMOTEIO: c_int = 0x79; +pub const ERESTART: c_int = 0x55; +pub const ESHUTDOWN: c_int = 0x6c; +pub const ESOCKTNOSUPPORT: c_int = 0x5e; +pub const ESRMNT: c_int = 0x45; +pub const ESTALE: c_int = 0x74; +pub const ESTRPIPE: c_int = 0x56; +pub const ETIME: c_int = 0x3e; +pub const ETIMEDOUT: c_int = 0x6e; +pub const ETOOMANYREFS: c_int = 0x6d; +pub const EUCLEAN: c_int = 0x75; +pub const EUNATCH: c_int = 0x31; +pub const EUSERS: c_int = 0x57; +pub const EXFULL: c_int = 0x36; +pub const FF1: c_int = 0x8000; +pub const FFDLY: c_int = 0x8000; +pub const FLUSHO: crate::tcflag_t = 0x1000; +pub const F_GETLK: c_int = 0x5; +pub const F_SETLK: c_int = 0x6; +pub const F_SETLKW: c_int = 0x7; +pub const HUPCL: crate::tcflag_t = 0x400; +pub const ICANON: crate::tcflag_t = 0x2; +pub const IEXTEN: crate::tcflag_t = 0x8000; +pub const ISIG: crate::tcflag_t = 0x1; +pub const IXOFF: crate::tcflag_t = 0x1000; +pub const IXON: crate::tcflag_t = 0x400; +pub const MAP_ANON: c_int = 0x20; +pub const MAP_ANONYMOUS: c_int = 0x20; +pub const MAP_DENYWRITE: c_int = 0x800; +pub const MAP_EXECUTABLE: c_int = 0x1000; +pub const MAP_GROWSDOWN: c_int = 0x100; +pub const MAP_LOCKED: c_int = 0x2000; +pub const MAP_NONBLOCK: c_int = 0x10000; +pub const MAP_NORESERVE: c_int = 0x4000; +pub const MAP_POPULATE: c_int = 0x8000; +pub const MAP_STACK: c_int = 0x20000; +pub const MINSIGSTKSZ: c_int = 2048; +pub const NLDLY: crate::tcflag_t = 0x100; +pub const NOFLSH: crate::tcflag_t = 0x80; +pub const OLCUC: crate::tcflag_t = 0x2; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const O_ACCMODE: c_int = 0x3; +pub const O_APPEND: c_int = 0x400; +pub const O_ASYNC: c_int = 0o20000; +pub const O_CREAT: c_int = 0x40; +pub const O_DIRECT: c_int = 0o40000; +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_DSYNC: c_int = O_SYNC; +pub const O_EXCL: c_int = 0x80; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_LARGEFILE: c_int = 0; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_NOCTTY: c_int = 0x100; +pub const O_NOFOLLOW: c_int = 0o400000; +pub const O_NONBLOCK: c_int = 0x800; +pub const O_PATH: c_int = 0o10000000; +pub const O_RSYNC: c_int = O_SYNC; +pub const O_SYNC: c_int = 0o10000; +pub const O_TRUNC: c_int = 0x200; +pub const PARENB: crate::tcflag_t = 0x100; +pub const PARODD: crate::tcflag_t = 0x200; +pub const PENDIN: crate::tcflag_t = 0x4000; +pub const POLLWRBAND: c_short = 0x200; +pub const POLLWRNORM: c_short = 0x100; +pub const RTLD_GLOBAL: c_int = 0x00100; + +// These are typed unsigned to match sigaction +pub const SA_NOCLDSTOP: c_ulong = 0x1; +pub const SA_NOCLDWAIT: c_ulong = 0x2; +pub const SA_SIGINFO: c_ulong = 0x4; +pub const SA_NODEFER: c_ulong = 0x40000000; +pub const SA_ONSTACK: c_ulong = 0x8000000; +pub const SA_RESETHAND: c_ulong = 0x80000000; +pub const SA_RESTART: c_ulong = 0x10000000; + +pub const SIGBUS: c_int = 0x7; +pub const SIGCHLD: c_int = 0x11; +pub const SIGCONT: c_int = 0x12; +pub const SIGIO: c_int = 0x1d; +pub const SIGPOLL: c_int = SIGIO; +pub const SIGPROF: c_int = 0x1b; +pub const SIGPWR: c_int = 0x1e; +pub const SIGSTKFLT: c_int = 0x10; +pub const SIGSTKSZ: c_int = 8192; +pub const SIGSTOP: c_int = 0x13; +pub const SIGSYS: c_int = 0x1f; +pub const SIGTSTP: c_int = 0x14; +pub const SIGTTIN: c_int = 0x15; +pub const SIGTTOU: c_int = 0x16; +pub const SIGURG: c_int = 0x17; +pub const SIGUSR1: c_int = 0xa; +pub const SIGUSR2: c_int = 0xc; +pub const SIGVTALRM: c_int = 0x1a; +pub const SIGWINCH: c_int = 0x1c; +pub const SIGXCPU: c_int = 0x18; +pub const SIGXFSZ: c_int = 0x19; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 0x1; +pub const SIG_SETMASK: c_int = 0x2; +pub const SOCK_DGRAM: c_int = 0x2; +pub const SOCK_NONBLOCK: c_int = 0o0004000; +pub const SOCK_SEQPACKET: c_int = 0x5; +pub const SOCK_STREAM: c_int = 0x1; +pub const TAB1: c_int = 0x800; +pub const TAB2: c_int = 0x1000; +pub const TAB3: c_int = 0x1800; +pub const TABDLY: c_int = 0x1800; +pub const TCSADRAIN: c_int = 0x1; +pub const TCSAFLUSH: c_int = 0x2; +pub const TCSANOW: c_int = 0; +pub const TOSTOP: crate::tcflag_t = 0x100; +pub const VDISCARD: usize = 0xd; +pub const VEOF: usize = 0x4; +pub const VEOL: usize = 0xb; +pub const VEOL2: usize = 0x10; +pub const VMIN: usize = 0x6; +pub const VREPRINT: usize = 0xc; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VSUSP: usize = 0xa; +pub const VSWTC: usize = 0x7; +pub const VT1: c_int = 0x4000; +pub const VTDLY: c_int = 0x4000; +pub const VTIME: usize = 0x5; +pub const VWERASE: usize = 0xe; +pub const XTABS: crate::tcflag_t = 0x1800; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/generic/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/generic/mod.rs new file mode 100644 index 00000000000000..37b751715e4477 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/generic/mod.rs @@ -0,0 +1,336 @@ +use crate::prelude::*; +use crate::Ioctl; + +s! { + pub struct termios2 { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; 19], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } +} + +// include/uapi/asm-generic/socket.h +// arch/alpha/include/uapi/asm/socket.h +// tools/include/uapi/asm-generic/socket.h +// arch/mips/include/uapi/asm/socket.h +pub const SOL_SOCKET: c_int = 1; + +// Defined in unix/linux_like/mod.rs +// pub const SO_DEBUG: c_int = 1; +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_SECURITY_AUTHENTICATION: c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: c_int = 24; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_ATTACH_FILTER: c_int = 26; +pub const SO_DETACH_FILTER: c_int = 27; +pub const SO_GET_FILTER: c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: c_int = 28; + +cfg_if! { + if #[cfg(all( + linux_time_bits64, + any(target_arch = "arm", target_arch = "x86"), + not(any(target_env = "musl", target_env = "ohos")) + ))] { + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_NEW; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_NEW; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_NEW; + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_NEW; + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_NEW; + } else if #[cfg(all( + linux_time_bits64, + any(target_arch = "arm", target_arch = "x86"), + any(target_env = "musl", target_env = "ohos") + ))] { + pub const SO_TIMESTAMP: c_int = 63; + pub const SO_TIMESTAMPNS: c_int = 64; + pub const SO_TIMESTAMPING: c_int = 65; + pub const SO_RCVTIMEO: c_int = 66; + pub const SO_SNDTIMEO: c_int = 67; + } else { + const SO_TIMESTAMP_OLD: c_int = 29; + const SO_TIMESTAMPNS_OLD: c_int = 35; + const SO_TIMESTAMPING_OLD: c_int = 37; + const SO_RCVTIMEO_OLD: c_int = 20; + const SO_SNDTIMEO_OLD: c_int = 21; + + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_OLD; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_OLD; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_OLD; + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_OLD; + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_OLD; + } +} + +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PASSSEC: c_int = 34; +pub const SO_MARK: c_int = 36; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_WIFI_STATUS: c_int = 41; +pub const SCM_WIFI_STATUS: c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_NOFCS: c_int = 43; +pub const SO_LOCK_FILTER: c_int = 44; +pub const SO_SELECT_ERR_QUEUE: c_int = 45; +pub const SO_BUSY_POLL: c_int = 46; +pub const SO_MAX_PACING_RATE: c_int = 47; +pub const SO_BPF_EXTENSIONS: c_int = 48; +pub const SO_INCOMING_CPU: c_int = 49; +pub const SO_ATTACH_BPF: c_int = 50; +pub const SO_DETACH_BPF: c_int = SO_DETACH_FILTER; +pub const SO_ATTACH_REUSEPORT_CBPF: c_int = 51; +pub const SO_ATTACH_REUSEPORT_EBPF: c_int = 52; +pub const SO_CNX_ADVICE: c_int = 53; +pub const SCM_TIMESTAMPING_OPT_STATS: c_int = 54; +pub const SO_MEMINFO: c_int = 55; +pub const SO_INCOMING_NAPI_ID: c_int = 56; +pub const SO_COOKIE: c_int = 57; +pub const SCM_TIMESTAMPING_PKTINFO: c_int = 58; +pub const SO_PEERGROUPS: c_int = 59; +pub const SO_ZEROCOPY: c_int = 60; +pub const SO_TXTIME: c_int = 61; +pub const SCM_TXTIME: c_int = SO_TXTIME; +pub const SO_BINDTOIFINDEX: c_int = 62; +cfg_if! { + // Some of these platforms in CI already have these constants. + // But they may still not have those _OLD ones. + if #[cfg(all( + any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "csky", + target_arch = "loongarch64" + ), + // FIXME(musl): + // Musl hardcodes the SO_* constants instead + // of inheriting them from the kernel headers. + // For new constants you might need consider updating + // musl in the CI as well. + not(any(target_env = "musl", target_env = "ohos")) + ))] { + pub const SO_TIMESTAMP_NEW: c_int = 63; + pub const SO_TIMESTAMPNS_NEW: c_int = 64; + pub const SO_TIMESTAMPING_NEW: c_int = 65; + pub const SO_RCVTIMEO_NEW: c_int = 66; + pub const SO_SNDTIMEO_NEW: c_int = 67; + pub const SO_DETACH_REUSEPORT_BPF: c_int = 68; + } +} +pub const SO_PREFER_BUSY_POLL: c_int = 69; +pub const SO_BUSY_POLL_BUDGET: c_int = 70; +pub const SO_NETNS_COOKIE: c_int = 71; +pub const SO_BUF_LOCK: c_int = 72; +pub const SO_RESERVE_MEM: c_int = 73; +pub const SO_TXREHASH: c_int = 74; +pub const SO_RCVMARK: c_int = 75; +pub const SO_PASSPIDFD: c_int = 76; +pub const SO_PEERPIDFD: c_int = 77; +pub const SO_DEVMEM_LINEAR: c_int = 78; +pub const SO_DEVMEM_DMABUF: c_int = 79; +pub const SO_DEVMEM_DONTNEED: c_int = 80; + +// Defined in unix/linux_like/mod.rs +// pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; +pub const SCM_TIMESTAMPNS: c_int = SO_TIMESTAMPNS; +pub const SCM_TIMESTAMPING: c_int = SO_TIMESTAMPING; + +pub const SCM_DEVMEM_LINEAR: c_int = SO_DEVMEM_LINEAR; +pub const SCM_DEVMEM_DMABUF: c_int = SO_DEVMEM_DMABUF; + +// Ioctl Constants + +pub const TCGETS: Ioctl = 0x5401; +pub const TCSETS: Ioctl = 0x5402; +pub const TCSETSW: Ioctl = 0x5403; +pub const TCSETSF: Ioctl = 0x5404; +pub const TCGETA: Ioctl = 0x5405; +pub const TCSETA: Ioctl = 0x5406; +pub const TCSETAW: Ioctl = 0x5407; +pub const TCSETAF: Ioctl = 0x5408; +pub const TCSBRK: Ioctl = 0x5409; +pub const TCXONC: Ioctl = 0x540A; +pub const TCFLSH: Ioctl = 0x540B; +pub const TIOCEXCL: Ioctl = 0x540C; +pub const TIOCNXCL: Ioctl = 0x540D; +pub const TIOCSCTTY: Ioctl = 0x540E; +pub const TIOCGPGRP: Ioctl = 0x540F; +pub const TIOCSPGRP: Ioctl = 0x5410; +pub const TIOCOUTQ: Ioctl = 0x5411; +pub const TIOCSTI: Ioctl = 0x5412; +pub const TIOCGWINSZ: Ioctl = 0x5413; +pub const TIOCSWINSZ: Ioctl = 0x5414; +pub const TIOCMGET: Ioctl = 0x5415; +pub const TIOCMBIS: Ioctl = 0x5416; +pub const TIOCMBIC: Ioctl = 0x5417; +pub const TIOCMSET: Ioctl = 0x5418; +pub const TIOCGSOFTCAR: Ioctl = 0x5419; +pub const TIOCSSOFTCAR: Ioctl = 0x541A; +pub const FIONREAD: Ioctl = 0x541B; +pub const TIOCINQ: Ioctl = FIONREAD; +pub const TIOCLINUX: Ioctl = 0x541C; +pub const TIOCCONS: Ioctl = 0x541D; +pub const TIOCGSERIAL: Ioctl = 0x541E; +pub const TIOCSSERIAL: Ioctl = 0x541F; +pub const TIOCPKT: Ioctl = 0x5420; +pub const FIONBIO: Ioctl = 0x5421; +pub const TIOCNOTTY: Ioctl = 0x5422; +pub const TIOCSETD: Ioctl = 0x5423; +pub const TIOCGETD: Ioctl = 0x5424; +pub const TCSBRKP: Ioctl = 0x5425; +pub const TIOCSBRK: Ioctl = 0x5427; +pub const TIOCCBRK: Ioctl = 0x5428; +pub const TIOCGSID: Ioctl = 0x5429; +pub const TCGETS2: Ioctl = 0x802c542a; +pub const TCSETS2: Ioctl = 0x402c542b; +pub const TCSETSW2: Ioctl = 0x402c542c; +pub const TCSETSF2: Ioctl = 0x402c542d; +pub const TIOCGRS485: Ioctl = 0x542E; +pub const TIOCSRS485: Ioctl = 0x542F; +pub const TIOCGPTN: Ioctl = 0x80045430; +pub const TIOCSPTLCK: Ioctl = 0x40045431; +pub const TIOCGDEV: Ioctl = 0x80045432; +pub const TCGETX: Ioctl = 0x5432; +pub const TCSETX: Ioctl = 0x5433; +pub const TCSETXF: Ioctl = 0x5434; +pub const TCSETXW: Ioctl = 0x5435; +pub const TIOCSIG: Ioctl = 0x40045436; +pub const TIOCVHANGUP: Ioctl = 0x5437; +pub const TIOCGPKT: Ioctl = 0x80045438; +pub const TIOCGPTLCK: Ioctl = 0x80045439; +pub const TIOCGEXCL: Ioctl = 0x80045440; +pub const TIOCGPTPEER: Ioctl = 0x5441; +// pub const TIOCGISO7816: Ioctl = 0x80285442; +// pub const TIOCSISO7816: Ioctl = 0xc0285443; +pub const FIONCLEX: Ioctl = 0x5450; +pub const FIOCLEX: Ioctl = 0x5451; +pub const FIOASYNC: Ioctl = 0x5452; +pub const TIOCSERCONFIG: Ioctl = 0x5453; +pub const TIOCSERGWILD: Ioctl = 0x5454; +pub const TIOCSERSWILD: Ioctl = 0x5455; +pub const TIOCGLCKTRMIOS: Ioctl = 0x5456; +pub const TIOCSLCKTRMIOS: Ioctl = 0x5457; +pub const TIOCSERGSTRUCT: Ioctl = 0x5458; +pub const TIOCSERGETLSR: Ioctl = 0x5459; +pub const TIOCSERGETMULTI: Ioctl = 0x545A; +pub const TIOCSERSETMULTI: Ioctl = 0x545B; +pub const TIOCMIWAIT: Ioctl = 0x545C; +pub const TIOCGICOUNT: Ioctl = 0x545D; +pub const BLKIOMIN: Ioctl = 0x1278; +pub const BLKIOOPT: Ioctl = 0x1279; +pub const BLKSSZGET: Ioctl = 0x1268; +pub const BLKPBSZGET: Ioctl = 0x127B; + +cfg_if! { + if #[cfg(any(target_arch = "arm", target_arch = "s390x"))] { + pub const FIOQSIZE: Ioctl = 0x545E; + } else { + pub const FIOQSIZE: Ioctl = 0x5460; + } +} + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0x100; + +pub const BOTHER: crate::speed_t = 0o010000; +pub const IBSHIFT: crate::tcflag_t = 16; +pub const IUCLC: crate::tcflag_t = 0o0001000; +pub const XCASE: crate::tcflag_t = 0o0000004; + +// RLIMIT Constants + +cfg_if! { + if #[cfg(any(target_env = "gnu", target_env = "uclibc"))] { + pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; + pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; + pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; + pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; + pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; + pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; + pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 6; + pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 7; + pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 8; + pub const RLIMIT_AS: crate::__rlimit_resource_t = 9; + pub const RLIMIT_LOCKS: crate::__rlimit_resource_t = 10; + pub const RLIMIT_SIGPENDING: crate::__rlimit_resource_t = 11; + pub const RLIMIT_MSGQUEUE: crate::__rlimit_resource_t = 12; + pub const RLIMIT_NICE: crate::__rlimit_resource_t = 13; + pub const RLIMIT_RTPRIO: crate::__rlimit_resource_t = 14; + pub const RLIMIT_RTTIME: crate::__rlimit_resource_t = 15; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = RLIM_NLIMITS; + } else if #[cfg(any(target_env = "musl", target_env = "ohos"))] { + pub const RLIMIT_CPU: c_int = 0; + pub const RLIMIT_FSIZE: c_int = 1; + pub const RLIMIT_DATA: c_int = 2; + pub const RLIMIT_STACK: c_int = 3; + pub const RLIMIT_CORE: c_int = 4; + pub const RLIMIT_RSS: c_int = 5; + pub const RLIMIT_NPROC: c_int = 6; + pub const RLIMIT_NOFILE: c_int = 7; + pub const RLIMIT_MEMLOCK: c_int = 8; + pub const RLIMIT_AS: c_int = 9; + pub const RLIMIT_LOCKS: c_int = 10; + pub const RLIMIT_SIGPENDING: c_int = 11; + pub const RLIMIT_MSGQUEUE: c_int = 12; + pub const RLIMIT_NICE: c_int = 13; + pub const RLIMIT_RTPRIO: c_int = 14; + pub const RLIMIT_RTTIME: c_int = 15; + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: c_int = 16; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: c_int = RLIM_NLIMITS; + } +} + +cfg_if! { + if #[cfg(target_env = "gnu")] { + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 16; + } else if #[cfg(target_env = "uclibc")] { + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 15; + } +} + +pub const RLIM_INFINITY: crate::rlim_t = !0; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mips/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mips/mod.rs new file mode 100644 index 00000000000000..78eec0ff55ac29 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mips/mod.rs @@ -0,0 +1,335 @@ +use crate::prelude::*; +use crate::Ioctl; + +s! { + pub struct termios2 { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; 23], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } +} + +// arch/mips/include/uapi/asm/socket.h +pub const SOL_SOCKET: c_int = 0xffff; + +// Defined in unix/linux_like/mod.rs +// pub const SO_DEBUG: c_int = 0x0001; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_TYPE: c_int = 0x1008; +// pub const SO_STYLE: c_int = SO_TYPE; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +cfg_if! { + if #[cfg(linux_time_bits64)] { + const SO_RCVTIMEO_NEW: c_int = 66; + const SO_SNDTIMEO_NEW: c_int = 67; + + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_NEW; + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_NEW; + } else { + const SO_SNDTIMEO_OLD: c_int = 0x1005; + const SO_RCVTIMEO_OLD: c_int = 0x1006; + + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_OLD; + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_OLD; + } +} +pub const SO_ACCEPTCONN: c_int = 0x1009; +pub const SO_PROTOCOL: c_int = 0x1028; +pub const SO_DOMAIN: c_int = 0x1029; + +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_PASSCRED: c_int = 17; +pub const SO_PEERCRED: c_int = 18; +pub const SO_SECURITY_AUTHENTICATION: c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: c_int = 24; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_ATTACH_FILTER: c_int = 26; +pub const SO_DETACH_FILTER: c_int = 27; +pub const SO_GET_FILTER: c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: c_int = 28; +pub const SO_PEERSEC: c_int = 30; +pub const SO_SNDBUFFORCE: c_int = 31; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PASSSEC: c_int = 34; +pub const SO_MARK: c_int = 36; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_WIFI_STATUS: c_int = 41; +pub const SCM_WIFI_STATUS: c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_NOFCS: c_int = 43; +pub const SO_LOCK_FILTER: c_int = 44; +pub const SO_SELECT_ERR_QUEUE: c_int = 45; +pub const SO_BUSY_POLL: c_int = 46; +pub const SO_MAX_PACING_RATE: c_int = 47; +pub const SO_BPF_EXTENSIONS: c_int = 48; +pub const SO_INCOMING_CPU: c_int = 49; +pub const SO_ATTACH_BPF: c_int = 50; +pub const SO_DETACH_BPF: c_int = SO_DETACH_FILTER; +pub const SO_ATTACH_REUSEPORT_CBPF: c_int = 51; +pub const SO_ATTACH_REUSEPORT_EBPF: c_int = 52; +pub const SO_CNX_ADVICE: c_int = 53; +pub const SCM_TIMESTAMPING_OPT_STATS: c_int = 54; +pub const SO_MEMINFO: c_int = 55; +pub const SO_INCOMING_NAPI_ID: c_int = 56; +pub const SO_COOKIE: c_int = 57; +pub const SCM_TIMESTAMPING_PKTINFO: c_int = 58; +pub const SO_PEERGROUPS: c_int = 59; +pub const SO_ZEROCOPY: c_int = 60; +pub const SO_TXTIME: c_int = 61; +pub const SCM_TXTIME: c_int = SO_TXTIME; +pub const SO_BINDTOIFINDEX: c_int = 62; + +cfg_if! { + if #[cfg(linux_time_bits64)] { + const SO_TIMESTAMP_NEW: c_int = 63; + const SO_TIMESTAMPNS_NEW: c_int = 64; + const SO_TIMESTAMPING_NEW: c_int = 65; + + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_NEW; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_NEW; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_NEW; + } else { + const SO_TIMESTAMP_OLD: c_int = 29; + const SO_TIMESTAMPNS_OLD: c_int = 35; + const SO_TIMESTAMPING_OLD: c_int = 37; + + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_OLD; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_OLD; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_OLD; + } +} + +// pub const SO_DETACH_REUSEPORT_BPF: c_int = 68; +pub const SO_PREFER_BUSY_POLL: c_int = 69; +pub const SO_BUSY_POLL_BUDGET: c_int = 70; +pub const SO_NETNS_COOKIE: c_int = 71; +pub const SO_BUF_LOCK: c_int = 72; +pub const SO_RESERVE_MEM: c_int = 73; +pub const SO_TXREHASH: c_int = 74; +pub const SO_RCVMARK: c_int = 75; +pub const SO_PASSPIDFD: c_int = 76; +pub const SO_PEERPIDFD: c_int = 77; +pub const SO_DEVMEM_LINEAR: c_int = 78; +pub const SO_DEVMEM_DMABUF: c_int = 79; +pub const SO_DEVMEM_DONTNEED: c_int = 80; + +// Defined in unix/linux_like/mod.rs +// pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; +pub const SCM_TIMESTAMPNS: c_int = SO_TIMESTAMPNS; +pub const SCM_TIMESTAMPING: c_int = SO_TIMESTAMPING; + +pub const SCM_DEVMEM_LINEAR: c_int = SO_DEVMEM_LINEAR; +pub const SCM_DEVMEM_DMABUF: c_int = SO_DEVMEM_DMABUF; + +// Ioctl Constants + +pub const TCGETS: Ioctl = 0x540d; +pub const TCSETS: Ioctl = 0x540e; +pub const TCSETSW: Ioctl = 0x540f; +pub const TCSETSF: Ioctl = 0x5410; +pub const TCGETA: Ioctl = 0x5401; +pub const TCSETA: Ioctl = 0x5402; +pub const TCSETAW: Ioctl = 0x5403; +pub const TCSETAF: Ioctl = 0x5404; +pub const TCSBRK: Ioctl = 0x5405; +pub const TCXONC: Ioctl = 0x5406; +pub const TCFLSH: Ioctl = 0x5407; +pub const TIOCEXCL: Ioctl = 0x740d; +pub const TIOCNXCL: Ioctl = 0x740e; +pub const TIOCSCTTY: Ioctl = 0x5480; +pub const TIOCGPGRP: Ioctl = 0x40047477; +pub const TIOCSPGRP: Ioctl = 0x80047476; +pub const TIOCOUTQ: Ioctl = 0x7472; +pub const TIOCSTI: Ioctl = 0x5472; +pub const TIOCGWINSZ: Ioctl = 0x40087468; +pub const TIOCSWINSZ: Ioctl = 0x80087467; +pub const TIOCMGET: Ioctl = 0x741d; +pub const TIOCMBIS: Ioctl = 0x741b; +pub const TIOCMBIC: Ioctl = 0x741c; +pub const TIOCMSET: Ioctl = 0x741a; +pub const TIOCGSOFTCAR: Ioctl = 0x5481; +pub const TIOCSSOFTCAR: Ioctl = 0x5482; +pub const FIONREAD: Ioctl = 0x467f; +pub const TIOCINQ: Ioctl = FIONREAD; +pub const TIOCLINUX: Ioctl = 0x5483; +pub const TIOCCONS: Ioctl = 0x80047478; +pub const TIOCGSERIAL: Ioctl = 0x5484; +pub const TIOCSSERIAL: Ioctl = 0x5485; +pub const TIOCPKT: Ioctl = 0x5470; +pub const FIONBIO: Ioctl = 0x667e; +pub const TIOCNOTTY: Ioctl = 0x5471; +pub const TIOCSETD: Ioctl = 0x7401; +pub const TIOCGETD: Ioctl = 0x7400; +pub const TCSBRKP: Ioctl = 0x5486; +pub const TIOCSBRK: Ioctl = 0x5427; +pub const TIOCCBRK: Ioctl = 0x5428; +pub const TIOCGSID: Ioctl = 0x7416; +pub const TCGETS2: Ioctl = 0x4030542a; +pub const TCSETS2: Ioctl = 0x8030542b; +pub const TCSETSW2: Ioctl = 0x8030542c; +pub const TCSETSF2: Ioctl = 0x8030542d; +pub const TIOCGPTN: Ioctl = 0x40045430; +pub const TIOCSPTLCK: Ioctl = 0x80045431; +pub const TIOCGDEV: Ioctl = 0x40045432; +pub const TIOCSIG: Ioctl = 0x80045436; +pub const TIOCVHANGUP: Ioctl = 0x5437; +pub const TIOCGPKT: Ioctl = 0x40045438; +pub const TIOCGPTLCK: Ioctl = 0x40045439; +pub const TIOCGEXCL: Ioctl = 0x40045440; +pub const TIOCGPTPEER: Ioctl = 0x20005441; +//pub const TIOCGISO7816: Ioctl = 0x40285442; +//pub const TIOCSISO7816: Ioctl = 0xc0285443; +pub const FIONCLEX: Ioctl = 0x6602; +pub const FIOCLEX: Ioctl = 0x6601; +pub const FIOASYNC: Ioctl = 0x667d; +pub const TIOCSERCONFIG: Ioctl = 0x5488; +pub const TIOCSERGWILD: Ioctl = 0x5489; +pub const TIOCSERSWILD: Ioctl = 0x548a; +pub const TIOCGLCKTRMIOS: Ioctl = 0x548b; +pub const TIOCSLCKTRMIOS: Ioctl = 0x548c; +pub const TIOCSERGSTRUCT: Ioctl = 0x548d; +pub const TIOCSERGETLSR: Ioctl = 0x548e; +pub const TIOCSERGETMULTI: Ioctl = 0x548f; +pub const TIOCSERSETMULTI: Ioctl = 0x5490; +pub const TIOCMIWAIT: Ioctl = 0x5491; +pub const TIOCGICOUNT: Ioctl = 0x5492; +pub const FIOQSIZE: Ioctl = 0x667f; +pub const TIOCSLTC: Ioctl = 0x7475; +pub const TIOCGETP: Ioctl = 0x7408; +pub const TIOCSETP: Ioctl = 0x7409; +pub const TIOCSETN: Ioctl = 0x740a; +pub const BLKIOMIN: Ioctl = 0x20001278; +pub const BLKIOOPT: Ioctl = 0x20001279; +pub const BLKSSZGET: Ioctl = 0x20001268; +pub const BLKPBSZGET: Ioctl = 0x2000127B; + +cfg_if! { + if #[cfg(target_env = "musl")] { + pub const TIOCGRS485: Ioctl = 0x4020542e; + pub const TIOCSRS485: Ioctl = 0xc020542f; + } +} + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x010; +pub const TIOCM_SR: c_int = 0x020; +pub const TIOCM_CTS: c_int = 0x040; +pub const TIOCM_CAR: c_int = 0x100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0x200; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0x400; + +pub const BOTHER: crate::speed_t = 0o010000; +pub const IBSHIFT: crate::tcflag_t = 16; +pub const IUCLC: crate::tcflag_t = 0o0001000; +pub const XCASE: crate::tcflag_t = 0o0000004; + +// RLIMIT Constants + +cfg_if! { + if #[cfg(any(target_env = "gnu", target_env = "uclibc"))] { + pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; + pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; + pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; + pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; + pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; + pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 5; + pub const RLIMIT_AS: crate::__rlimit_resource_t = 6; + pub const RLIMIT_RSS: crate::__rlimit_resource_t = 7; + pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 8; + pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 9; + pub const RLIMIT_LOCKS: crate::__rlimit_resource_t = 10; + pub const RLIMIT_SIGPENDING: crate::__rlimit_resource_t = 11; + pub const RLIMIT_MSGQUEUE: crate::__rlimit_resource_t = 12; + pub const RLIMIT_NICE: crate::__rlimit_resource_t = 13; + pub const RLIMIT_RTPRIO: crate::__rlimit_resource_t = 14; + pub const RLIMIT_RTTIME: crate::__rlimit_resource_t = 15; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = RLIM_NLIMITS; + } else if #[cfg(target_env = "musl")] { + pub const RLIMIT_CPU: c_int = 0; + pub const RLIMIT_FSIZE: c_int = 1; + pub const RLIMIT_DATA: c_int = 2; + pub const RLIMIT_STACK: c_int = 3; + pub const RLIMIT_CORE: c_int = 4; + pub const RLIMIT_NOFILE: c_int = 5; + pub const RLIMIT_AS: c_int = 6; + pub const RLIMIT_RSS: c_int = 7; + pub const RLIMIT_NPROC: c_int = 8; + pub const RLIMIT_MEMLOCK: c_int = 9; + pub const RLIMIT_LOCKS: c_int = 10; + pub const RLIMIT_SIGPENDING: c_int = 11; + pub const RLIMIT_MSGQUEUE: c_int = 12; + pub const RLIMIT_NICE: c_int = 13; + pub const RLIMIT_RTPRIO: c_int = 14; + pub const RLIMIT_RTTIME: c_int = 15; + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: c_int = 16; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: c_int = RLIM_NLIMITS; + pub const RLIM_INFINITY: crate::rlim_t = !0; + } +} + +cfg_if! { + if #[cfg(target_env = "gnu")] { + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 16; + } else if #[cfg(target_env = "uclibc")] { + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 15; + } +} + +cfg_if! { + if #[cfg( + any(target_arch = "mips64", target_arch = "mips64r6"), + any(target_env = "gnu", target_env = "uclibc") + )] { + pub const RLIM_INFINITY: crate::rlim_t = !0; + } +} + +cfg_if! { + if #[cfg(all( + any(target_arch = "mips", target_arch = "mips32r6"), + any( + all(target_env = "uclibc", linux_time_bits64), + all( + target_env = "gnu", + any(linux_time_bits64, gnu_file_offset_bits64) + ) + ) + ))] { + pub const RLIM_INFINITY: crate::rlim_t = !0; + } else if #[cfg(all( + any(target_arch = "mips", target_arch = "mips32r6"), + any(target_env = "uclibc", target_env = "gnu"), + not(linux_time_bits64) + ))] { + pub const RLIM_INFINITY: crate::rlim_t = 0x7fffffff; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mod.rs new file mode 100644 index 00000000000000..00914a43ac1646 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/mod.rs @@ -0,0 +1,20 @@ +cfg_if! { + if #[cfg(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + ))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + mod sparc; + pub use self::sparc::*; + } else { + mod generic; + pub use self::generic::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/powerpc/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/powerpc/mod.rs new file mode 100644 index 00000000000000..b5a3557a705bc7 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/powerpc/mod.rs @@ -0,0 +1,282 @@ +use crate::prelude::*; +use crate::Ioctl; + +// arch/powerpc/include/uapi/asm/socket.h + +pub const SOL_SOCKET: c_int = 1; + +// Defined in unix/linux_like/mod.rs +// pub const SO_DEBUG: c_int = 1; +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +// powerpc only differs in these +pub const SO_RCVLOWAT: c_int = 16; +pub const SO_SNDLOWAT: c_int = 17; + +cfg_if! { + if #[cfg(linux_time_bits64)] { + const SO_RCVTIMEO_NEW: c_int = 66; + const SO_SNDTIMEO_NEW: c_int = 67; + + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_NEW; + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_NEW; + } else { + const SO_RCVTIMEO_OLD: c_int = 18; + const SO_SNDTIMEO_OLD: c_int = 19; + + pub const SO_RCVTIMEO: c_int = SO_RCVTIMEO_OLD; + pub const SO_SNDTIMEO: c_int = SO_SNDTIMEO_OLD; + } +} + +pub const SO_PASSCRED: c_int = 20; +pub const SO_PEERCRED: c_int = 21; +// end +pub const SO_SECURITY_AUTHENTICATION: c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: c_int = 24; +pub const SO_BINDTODEVICE: c_int = 25; +pub const SO_ATTACH_FILTER: c_int = 26; +pub const SO_DETACH_FILTER: c_int = 27; +pub const SO_GET_FILTER: c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: c_int = 28; +cfg_if! { + if #[cfg(linux_time_bits64)] { + const SO_TIMESTAMP_NEW: c_int = 63; + const SO_TIMESTAMPNS_NEW: c_int = 64; + const SO_TIMESTAMPING_NEW: c_int = 65; + + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_NEW; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_NEW; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_NEW; + } else { + const SO_TIMESTAMP_OLD: c_int = 29; + const SO_TIMESTAMPNS_OLD: c_int = 35; + const SO_TIMESTAMPING_OLD: c_int = 37; + + pub const SO_TIMESTAMP: c_int = SO_TIMESTAMP_OLD; + pub const SO_TIMESTAMPNS: c_int = SO_TIMESTAMPNS_OLD; + pub const SO_TIMESTAMPING: c_int = SO_TIMESTAMPING_OLD; + } +} +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PASSSEC: c_int = 34; +pub const SO_MARK: c_int = 36; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SO_RXQ_OVFL: c_int = 40; +pub const SO_WIFI_STATUS: c_int = 41; +pub const SCM_WIFI_STATUS: c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: c_int = 42; +pub const SO_NOFCS: c_int = 43; +pub const SO_LOCK_FILTER: c_int = 44; +pub const SO_SELECT_ERR_QUEUE: c_int = 45; +pub const SO_BUSY_POLL: c_int = 46; +pub const SO_MAX_PACING_RATE: c_int = 47; +pub const SO_BPF_EXTENSIONS: c_int = 48; +pub const SO_INCOMING_CPU: c_int = 49; +pub const SO_ATTACH_BPF: c_int = 50; +pub const SO_DETACH_BPF: c_int = SO_DETACH_FILTER; +pub const SO_ATTACH_REUSEPORT_CBPF: c_int = 51; +pub const SO_ATTACH_REUSEPORT_EBPF: c_int = 52; +pub const SO_CNX_ADVICE: c_int = 53; +pub const SCM_TIMESTAMPING_OPT_STATS: c_int = 54; +pub const SO_MEMINFO: c_int = 55; +pub const SO_INCOMING_NAPI_ID: c_int = 56; +pub const SO_COOKIE: c_int = 57; +pub const SCM_TIMESTAMPING_PKTINFO: c_int = 58; +pub const SO_PEERGROUPS: c_int = 59; +pub const SO_ZEROCOPY: c_int = 60; +pub const SO_TXTIME: c_int = 61; +pub const SCM_TXTIME: c_int = SO_TXTIME; +pub const SO_BINDTOIFINDEX: c_int = 62; +// pub const SO_DETACH_REUSEPORT_BPF: c_int = 68; +pub const SO_PREFER_BUSY_POLL: c_int = 69; +pub const SO_BUSY_POLL_BUDGET: c_int = 70; +pub const SO_NETNS_COOKIE: c_int = 71; +pub const SO_BUF_LOCK: c_int = 72; +pub const SO_RESERVE_MEM: c_int = 73; +pub const SO_TXREHASH: c_int = 74; +pub const SO_RCVMARK: c_int = 75; +pub const SO_PASSPIDFD: c_int = 76; +pub const SO_PEERPIDFD: c_int = 77; +pub const SO_DEVMEM_LINEAR: c_int = 78; +pub const SO_DEVMEM_DMABUF: c_int = 79; +pub const SO_DEVMEM_DONTNEED: c_int = 80; + +// Defined in unix/linux_like/mod.rs +// pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; +pub const SCM_TIMESTAMPNS: c_int = SO_TIMESTAMPNS; +pub const SCM_TIMESTAMPING: c_int = SO_TIMESTAMPING; + +pub const SCM_DEVMEM_LINEAR: c_int = SO_DEVMEM_LINEAR; +pub const SCM_DEVMEM_DMABUF: c_int = SO_DEVMEM_DMABUF; + +// Ioctl Constants + +cfg_if! { + if #[cfg(target_env = "gnu")] { + pub const TCGETS: Ioctl = 0x403c7413; + pub const TCSETS: Ioctl = 0x803c7414; + pub const TCSETSW: Ioctl = 0x803c7415; + pub const TCSETSF: Ioctl = 0x803c7416; + } else if #[cfg(target_env = "musl")] { + pub const TCGETS: Ioctl = 0x402c7413; + pub const TCSETS: Ioctl = 0x802c7414; + pub const TCSETSW: Ioctl = 0x802c7415; + pub const TCSETSF: Ioctl = 0x802c7416; + } +} + +pub const TCGETA: Ioctl = 0x40147417; +pub const TCSETA: Ioctl = 0x80147418; +pub const TCSETAW: Ioctl = 0x80147419; +pub const TCSETAF: Ioctl = 0x8014741C; +pub const TCSBRK: Ioctl = 0x2000741D; +pub const TCXONC: Ioctl = 0x2000741E; +pub const TCFLSH: Ioctl = 0x2000741F; +pub const TIOCEXCL: Ioctl = 0x540C; +pub const TIOCNXCL: Ioctl = 0x540D; +pub const TIOCSCTTY: Ioctl = 0x540E; +pub const TIOCGPGRP: Ioctl = 0x40047477; +pub const TIOCSPGRP: Ioctl = 0x80047476; +pub const TIOCOUTQ: Ioctl = 0x40047473; +pub const TIOCSTI: Ioctl = 0x5412; +pub const TIOCGWINSZ: Ioctl = 0x40087468; +pub const TIOCSWINSZ: Ioctl = 0x80087467; +pub const TIOCMGET: Ioctl = 0x5415; +pub const TIOCMBIS: Ioctl = 0x5416; +pub const TIOCMBIC: Ioctl = 0x5417; +pub const TIOCMSET: Ioctl = 0x5418; +pub const TIOCGSOFTCAR: Ioctl = 0x5419; +pub const TIOCSSOFTCAR: Ioctl = 0x541A; +pub const FIONREAD: Ioctl = 0x4004667F; +pub const TIOCINQ: Ioctl = FIONREAD; +pub const TIOCLINUX: Ioctl = 0x541C; +pub const TIOCCONS: Ioctl = 0x541D; +pub const TIOCGSERIAL: Ioctl = 0x541E; +pub const TIOCSSERIAL: Ioctl = 0x541F; +pub const TIOCPKT: Ioctl = 0x5420; +pub const FIONBIO: Ioctl = 0x8004667e; +pub const TIOCNOTTY: Ioctl = 0x5422; +pub const TIOCSETD: Ioctl = 0x5423; +pub const TIOCGETD: Ioctl = 0x5424; +pub const TCSBRKP: Ioctl = 0x5425; +pub const TIOCSBRK: Ioctl = 0x5427; +pub const TIOCCBRK: Ioctl = 0x5428; +pub const TIOCGSID: Ioctl = 0x5429; +pub const TIOCGRS485: Ioctl = 0x542e; +pub const TIOCSRS485: Ioctl = 0x542f; +pub const TIOCGPTN: Ioctl = 0x40045430; +pub const TIOCSPTLCK: Ioctl = 0x80045431; +pub const TIOCGDEV: Ioctl = 0x40045432; +pub const TIOCSIG: Ioctl = 0x80045436; +pub const TIOCVHANGUP: Ioctl = 0x5437; +pub const TIOCGPKT: Ioctl = 0x40045438; +pub const TIOCGPTLCK: Ioctl = 0x40045439; +pub const TIOCGEXCL: Ioctl = 0x40045440; +pub const TIOCGPTPEER: Ioctl = 0x20005441; +//pub const TIOCGISO7816: Ioctl = 0x40285442; +//pub const TIOCSISO7816: Ioctl = 0xc0285443; +pub const FIONCLEX: Ioctl = 0x20006602; +pub const FIOCLEX: Ioctl = 0x20006601; +pub const FIOASYNC: Ioctl = 0x8004667d; +pub const TIOCSERCONFIG: Ioctl = 0x5453; +pub const TIOCSERGWILD: Ioctl = 0x5454; +pub const TIOCSERSWILD: Ioctl = 0x5455; +pub const TIOCGLCKTRMIOS: Ioctl = 0x5456; +pub const TIOCSLCKTRMIOS: Ioctl = 0x5457; +pub const TIOCSERGSTRUCT: Ioctl = 0x5458; +pub const TIOCSERGETLSR: Ioctl = 0x5459; +pub const TIOCSERGETMULTI: Ioctl = 0x545A; +pub const TIOCSERSETMULTI: Ioctl = 0x545B; +pub const TIOCMIWAIT: Ioctl = 0x545C; +pub const TIOCGICOUNT: Ioctl = 0x545D; +pub const BLKIOMIN: Ioctl = 0x20001278; +pub const BLKIOOPT: Ioctl = 0x20001279; +pub const BLKSSZGET: Ioctl = 0x20001268; +pub const BLKPBSZGET: Ioctl = 0x2000127B; +//pub const FIOQSIZE: Ioctl = 0x40086680; + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0x100; + +pub const BOTHER: crate::speed_t = 0o0037; +pub const IBSHIFT: crate::tcflag_t = 16; +pub const IUCLC: crate::tcflag_t = 0o0010000; +pub const XCASE: crate::tcflag_t = 0o0040000; + +// RLIMIT Constants + +cfg_if! { + if #[cfg(target_env = "gnu")] { + pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; + pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; + pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; + pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; + pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; + pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; + pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 6; + pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 7; + pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 8; + pub const RLIMIT_AS: crate::__rlimit_resource_t = 9; + pub const RLIMIT_LOCKS: crate::__rlimit_resource_t = 10; + pub const RLIMIT_SIGPENDING: crate::__rlimit_resource_t = 11; + pub const RLIMIT_MSGQUEUE: crate::__rlimit_resource_t = 12; + pub const RLIMIT_NICE: crate::__rlimit_resource_t = 13; + pub const RLIMIT_RTPRIO: crate::__rlimit_resource_t = 14; + pub const RLIMIT_RTTIME: crate::__rlimit_resource_t = 15; + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 16; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = RLIM_NLIMITS; + } else if #[cfg(target_env = "musl")] { + pub const RLIMIT_CPU: c_int = 0; + pub const RLIMIT_FSIZE: c_int = 1; + pub const RLIMIT_DATA: c_int = 2; + pub const RLIMIT_STACK: c_int = 3; + pub const RLIMIT_CORE: c_int = 4; + pub const RLIMIT_RSS: c_int = 5; + pub const RLIMIT_NPROC: c_int = 6; + pub const RLIMIT_NOFILE: c_int = 7; + pub const RLIMIT_MEMLOCK: c_int = 8; + pub const RLIMIT_AS: c_int = 9; + pub const RLIMIT_LOCKS: c_int = 10; + pub const RLIMIT_SIGPENDING: c_int = 11; + pub const RLIMIT_MSGQUEUE: c_int = 12; + pub const RLIMIT_NICE: c_int = 13; + pub const RLIMIT_RTPRIO: c_int = 14; + pub const RLIMIT_RTTIME: c_int = 15; + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIM_NLIMITS: c_int = 16; + #[allow(deprecated)] + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] + pub const RLIMIT_NLIMITS: c_int = RLIM_NLIMITS; + } +} +pub const RLIM_INFINITY: crate::rlim_t = !0; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/sparc/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/sparc/mod.rs new file mode 100644 index 00000000000000..006156ee0c0ea8 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/arch/sparc/mod.rs @@ -0,0 +1,249 @@ +use crate::prelude::*; +use crate::Ioctl; + +s! { + pub struct termios2 { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; 19], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } +} + +// arch/sparc/include/uapi/asm/socket.h +pub const SOL_SOCKET: c_int = 0xffff; + +// Defined in unix/linux_like/mod.rs +// pub const SO_DEBUG: c_int = 0x0001; +pub const SO_PASSCRED: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_PEERCRED: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_BSDCOMPAT: c_int = 0x0400; +pub const SO_RCVLOWAT: c_int = 0x0800; +pub const SO_SNDLOWAT: c_int = 0x1000; +pub const SO_RCVTIMEO: c_int = 0x2000; +pub const SO_SNDTIMEO: c_int = 0x4000; +// pub const SO_RCVTIMEO_OLD: c_int = 0x2000; +// pub const SO_SNDTIMEO_OLD: c_int = 0x4000; +pub const SO_ACCEPTCONN: c_int = 0x8000; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDBUFFORCE: c_int = 0x100a; +pub const SO_RCVBUFFORCE: c_int = 0x100b; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_PROTOCOL: c_int = 0x1028; +pub const SO_DOMAIN: c_int = 0x1029; +pub const SO_NO_CHECK: c_int = 0x000b; +pub const SO_PRIORITY: c_int = 0x000c; +pub const SO_BINDTODEVICE: c_int = 0x000d; +pub const SO_ATTACH_FILTER: c_int = 0x001a; +pub const SO_DETACH_FILTER: c_int = 0x001b; +pub const SO_GET_FILTER: c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: c_int = 0x001c; +pub const SO_PEERSEC: c_int = 0x001e; +pub const SO_PASSSEC: c_int = 0x001f; +pub const SO_MARK: c_int = 0x0022; +pub const SO_RXQ_OVFL: c_int = 0x0024; +pub const SO_WIFI_STATUS: c_int = 0x0025; +pub const SCM_WIFI_STATUS: c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: c_int = 0x0026; +pub const SO_NOFCS: c_int = 0x0027; +pub const SO_LOCK_FILTER: c_int = 0x0028; +pub const SO_SELECT_ERR_QUEUE: c_int = 0x0029; +pub const SO_BUSY_POLL: c_int = 0x0030; +pub const SO_MAX_PACING_RATE: c_int = 0x0031; +pub const SO_BPF_EXTENSIONS: c_int = 0x0032; +pub const SO_INCOMING_CPU: c_int = 0x0033; +pub const SO_ATTACH_BPF: c_int = 0x0034; +pub const SO_DETACH_BPF: c_int = SO_DETACH_FILTER; +pub const SO_ATTACH_REUSEPORT_CBPF: c_int = 0x0035; +pub const SO_ATTACH_REUSEPORT_EBPF: c_int = 0x0036; +pub const SO_CNX_ADVICE: c_int = 0x0037; +pub const SCM_TIMESTAMPING_OPT_STATS: c_int = 0x0038; +pub const SO_MEMINFO: c_int = 0x0039; +pub const SO_INCOMING_NAPI_ID: c_int = 0x003a; +pub const SO_COOKIE: c_int = 0x003b; +pub const SCM_TIMESTAMPING_PKTINFO: c_int = 0x003c; +pub const SO_PEERGROUPS: c_int = 0x003d; +pub const SO_ZEROCOPY: c_int = 0x003e; +pub const SO_TXTIME: c_int = 0x003f; +pub const SCM_TXTIME: c_int = SO_TXTIME; +pub const SO_BINDTOIFINDEX: c_int = 0x0041; +pub const SO_SECURITY_AUTHENTICATION: c_int = 0x5001; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: c_int = 0x5002; +pub const SO_SECURITY_ENCRYPTION_NETWORK: c_int = 0x5004; +pub const SO_TIMESTAMP: c_int = 0x001d; +pub const SO_TIMESTAMPNS: c_int = 0x0021; +pub const SO_TIMESTAMPING: c_int = 0x0023; +// pub const SO_TIMESTAMP_OLD: c_int = 0x001d; +// pub const SO_TIMESTAMPNS_OLD: c_int = 0x0021; +// pub const SO_TIMESTAMPING_OLD: c_int = 0x0023; +// pub const SO_TIMESTAMP_NEW: c_int = 0x0046; +// pub const SO_TIMESTAMPNS_NEW: c_int = 0x0042; +// pub const SO_TIMESTAMPING_NEW: c_int = 0x0043; +// pub const SO_RCVTIMEO_NEW: c_int = 0x0044; +// pub const SO_SNDTIMEO_NEW: c_int = 0x0045; +// pub const SO_DETACH_REUSEPORT_BPF: c_int = 0x0047; +pub const SO_PREFER_BUSY_POLL: c_int = 0x0048; +pub const SO_BUSY_POLL_BUDGET: c_int = 0x0049; +pub const SO_NETNS_COOKIE: c_int = 0x0050; +pub const SO_BUF_LOCK: c_int = 0x0051; +pub const SO_RESERVE_MEM: c_int = 0x0052; +pub const SO_TXREHASH: c_int = 0x0053; +pub const SO_RCVMARK: c_int = 0x0054; +pub const SO_PASSPIDFD: c_int = 0x0055; +pub const SO_PEERPIDFD: c_int = 0x0056; +pub const SO_DEVMEM_LINEAR: c_int = 0x0057; +pub const SO_DEVMEM_DMABUF: c_int = 0x0058; +pub const SO_DEVMEM_DONTNEED: c_int = 0x0059; + +// Defined in unix/linux_like/mod.rs +// pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; +pub const SCM_TIMESTAMPNS: c_int = SO_TIMESTAMPNS; +pub const SCM_TIMESTAMPING: c_int = SO_TIMESTAMPING; + +pub const SCM_DEVMEM_LINEAR: c_int = SO_DEVMEM_LINEAR; +pub const SCM_DEVMEM_DMABUF: c_int = SO_DEVMEM_DMABUF; + +// Ioctl Constants + +pub const TCGETS: Ioctl = 0x40245408; +pub const TCSETS: Ioctl = 0x80245409; +pub const TCSETSW: Ioctl = 0x8024540a; +pub const TCSETSF: Ioctl = 0x8024540b; +pub const TCGETA: Ioctl = 0x40125401; +pub const TCSETA: Ioctl = 0x80125402; +pub const TCSETAW: Ioctl = 0x80125403; +pub const TCSETAF: Ioctl = 0x80125404; +pub const TCSBRK: Ioctl = 0x20005405; +pub const TCXONC: Ioctl = 0x20005406; +pub const TCFLSH: Ioctl = 0x20005407; +pub const TIOCEXCL: Ioctl = 0x2000740d; +pub const TIOCNXCL: Ioctl = 0x2000740e; +pub const TIOCSCTTY: Ioctl = 0x20007484; +pub const TIOCGPGRP: Ioctl = 0x40047483; +pub const TIOCSPGRP: Ioctl = 0x80047482; +pub const TIOCOUTQ: Ioctl = 0x40047473; +pub const TIOCSTI: Ioctl = 0x80017472; +pub const TIOCGWINSZ: Ioctl = 0x40087468; +pub const TIOCSWINSZ: Ioctl = 0x80087467; +pub const TIOCMGET: Ioctl = 0x4004746a; +pub const TIOCMBIS: Ioctl = 0x8004746c; +pub const TIOCMBIC: Ioctl = 0x8004746b; +pub const TIOCMSET: Ioctl = 0x8004746d; +pub const TIOCGSOFTCAR: Ioctl = 0x40047464; +pub const TIOCSSOFTCAR: Ioctl = 0x80047465; +pub const FIONREAD: Ioctl = 0x4004667f; +pub const TIOCINQ: Ioctl = FIONREAD; +pub const TIOCLINUX: Ioctl = 0x541C; +pub const TIOCCONS: Ioctl = 0x20007424; +pub const TIOCGSERIAL: Ioctl = 0x541E; +pub const TIOCSSERIAL: Ioctl = 0x541F; +pub const TIOCPKT: Ioctl = 0x80047470; +pub const FIONBIO: Ioctl = 0x8004667e; +pub const TIOCNOTTY: Ioctl = 0x20007471; +pub const TIOCSETD: Ioctl = 0x80047401; +pub const TIOCGETD: Ioctl = 0x40047400; +pub const TCSBRKP: Ioctl = 0x5425; +pub const TIOCSBRK: Ioctl = 0x2000747b; +pub const TIOCCBRK: Ioctl = 0x2000747a; +pub const TIOCGSID: Ioctl = 0x40047485; +pub const TCGETS2: Ioctl = 0x402c540c; +pub const TCSETS2: Ioctl = 0x802c540d; +pub const TCSETSW2: Ioctl = 0x802c540e; +pub const TCSETSF2: Ioctl = 0x802c540f; +pub const TIOCGPTN: Ioctl = 0x40047486; +pub const TIOCSPTLCK: Ioctl = 0x80047487; +pub const TIOCGDEV: Ioctl = 0x40045432; +pub const TIOCSIG: Ioctl = 0x80047488; +pub const TIOCVHANGUP: Ioctl = 0x20005437; +pub const TIOCGPKT: Ioctl = 0x40045438; +pub const TIOCGPTLCK: Ioctl = 0x40045439; +pub const TIOCGEXCL: Ioctl = 0x40045440; +pub const TIOCGPTPEER: Ioctl = 0x20007489; +pub const FIONCLEX: Ioctl = 0x20006602; +pub const FIOCLEX: Ioctl = 0x20006601; +pub const TIOCSERCONFIG: Ioctl = 0x5453; +pub const TIOCSERGWILD: Ioctl = 0x5454; +pub const TIOCSERSWILD: Ioctl = 0x5455; +pub const TIOCGLCKTRMIOS: Ioctl = 0x5456; +pub const TIOCSLCKTRMIOS: Ioctl = 0x5457; +pub const TIOCSERGSTRUCT: Ioctl = 0x5458; +pub const TIOCSERGETLSR: Ioctl = 0x5459; +pub const TIOCSERGETMULTI: Ioctl = 0x545A; +pub const TIOCSERSETMULTI: Ioctl = 0x545B; +pub const TIOCMIWAIT: Ioctl = 0x545C; +pub const TIOCGICOUNT: Ioctl = 0x545D; +pub const TIOCSTART: Ioctl = 0x2000746e; +pub const TIOCSTOP: Ioctl = 0x2000746f; +pub const BLKIOMIN: Ioctl = 0x20001278; +pub const BLKIOOPT: Ioctl = 0x20001279; +pub const BLKSSZGET: Ioctl = 0x20001268; +pub const BLKPBSZGET: Ioctl = 0x2000127B; + +//pub const FIOASYNC: Ioctl = 0x4004667d; +//pub const FIOQSIZE: Ioctl = ; +//pub const TIOCGISO7816: Ioctl = 0x40285443; +//pub const TIOCSISO7816: Ioctl = 0xc0285444; +//pub const TIOCGRS485: Ioctl = 0x40205441; +//pub const TIOCSRS485: Ioctl = 0xc0205442; + +pub const TIOCM_LE: c_int = 0x001; +pub const TIOCM_DTR: c_int = 0x002; +pub const TIOCM_RTS: c_int = 0x004; +pub const TIOCM_ST: c_int = 0x008; +pub const TIOCM_SR: c_int = 0x010; +pub const TIOCM_CTS: c_int = 0x020; +pub const TIOCM_CAR: c_int = 0x040; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0x080; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0x100; + +pub const BOTHER: crate::speed_t = 0x1000; +pub const IBSHIFT: crate::tcflag_t = 16; +pub const IUCLC: crate::tcflag_t = 0o0001000; +pub const XCASE: crate::tcflag_t = 0o0000004; + +// RLIMIT Constants + +pub const RLIMIT_CPU: crate::__rlimit_resource_t = 0; +pub const RLIMIT_FSIZE: crate::__rlimit_resource_t = 1; +pub const RLIMIT_DATA: crate::__rlimit_resource_t = 2; +pub const RLIMIT_STACK: crate::__rlimit_resource_t = 3; +pub const RLIMIT_CORE: crate::__rlimit_resource_t = 4; +pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; +pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 6; +pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 7; +pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 8; +pub const RLIMIT_AS: crate::__rlimit_resource_t = 9; +pub const RLIMIT_LOCKS: crate::__rlimit_resource_t = 10; +pub const RLIMIT_SIGPENDING: crate::__rlimit_resource_t = 11; +pub const RLIMIT_MSGQUEUE: crate::__rlimit_resource_t = 12; +pub const RLIMIT_NICE: crate::__rlimit_resource_t = 13; +pub const RLIMIT_RTPRIO: crate::__rlimit_resource_t = 14; +pub const RLIMIT_RTTIME: crate::__rlimit_resource_t = 15; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: crate::__rlimit_resource_t = 16; +#[allow(deprecated)] +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIMIT_NLIMITS: crate::__rlimit_resource_t = RLIM_NLIMITS; + +cfg_if! { + if #[cfg(target_arch = "sparc64")] { + pub const RLIM_INFINITY: crate::rlim_t = !0; + } else if #[cfg(target_arch = "sparc")] { + pub const RLIM_INFINITY: crate::rlim_t = 0x7fffffff; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/arm/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/arm/mod.rs new file mode 100644 index 00000000000000..d05bccf3811ace --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/arm/mod.rs @@ -0,0 +1,907 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = u32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + f_spare: [crate::__fsword_t; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad1: Padding, + #[cfg(not(gnu_time_bits64))] + __st_ino: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + #[cfg(not(gnu_time_bits64))] + pub st_ino: crate::ino64_t, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused1: Padding, + pub shm_dtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused2: Padding, + pub shm_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved1: Padding, + pub msg_rtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved2: Padding, + pub msg_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct mcontext_t { + pub trap_no: c_ulong, + pub error_code: c_ulong, + pub oldmask: c_ulong, + pub arm_r0: c_ulong, + pub arm_r1: c_ulong, + pub arm_r2: c_ulong, + pub arm_r3: c_ulong, + pub arm_r4: c_ulong, + pub arm_r5: c_ulong, + pub arm_r6: c_ulong, + pub arm_r7: c_ulong, + pub arm_r8: c_ulong, + pub arm_r9: c_ulong, + pub arm_r10: c_ulong, + pub arm_fp: c_ulong, + pub arm_ip: c_ulong, + pub arm_sp: c_ulong, + pub arm_lr: c_ulong, + pub arm_pc: c_ulong, + pub arm_cpsr: c_ulong, + pub fault_address: c_ulong, + } + + pub struct user_regs { + pub arm_r0: c_ulong, + pub arm_r1: c_ulong, + pub arm_r2: c_ulong, + pub arm_r3: c_ulong, + pub arm_r4: c_ulong, + pub arm_r5: c_ulong, + pub arm_r6: c_ulong, + pub arm_r7: c_ulong, + pub arm_r8: c_ulong, + pub arm_r9: c_ulong, + pub arm_r10: c_ulong, + pub arm_fp: c_ulong, + pub arm_ip: c_ulong, + pub arm_sp: c_ulong, + pub arm_lr: c_ulong, + pub arm_pc: c_ulong, + pub arm_cpsr: c_ulong, + pub arm_orig_r0: c_ulong, + } + + #[repr(align(8))] + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: crate::mcontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_regspace: [c_ulong; 128], + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [i64; 2], + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_LARGEFILE: c_int = 0o400000; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +cfg_if! { + if #[cfg(gnu_file_offset_bits64)] { + pub const F_GETLK: c_int = 12; + } else { + pub const F_GETLK: c_int = 5; + } +} +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; + +pub const EFD_NONBLOCK: c_int = 0x800; +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_ptrace: c_long = 26; +pub const SYS_pause: c_long = 29; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_vhangup: c_long = 111; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_pivot_root: c_long = 218; +pub const SYS_mincore: c_long = 219; +pub const SYS_madvise: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_lookup_dcookie: c_long = 249; +pub const SYS_epoll_create: c_long = 250; +pub const SYS_epoll_ctl: c_long = 251; +pub const SYS_epoll_wait: c_long = 252; +pub const SYS_remap_file_pages: c_long = 253; +pub const SYS_set_tid_address: c_long = 256; +pub const SYS_timer_create: c_long = 257; +pub const SYS_timer_settime: c_long = 258; +pub const SYS_timer_gettime: c_long = 259; +pub const SYS_timer_getoverrun: c_long = 260; +pub const SYS_timer_delete: c_long = 261; +pub const SYS_clock_settime: c_long = 262; +pub const SYS_clock_gettime: c_long = 263; +pub const SYS_clock_getres: c_long = 264; +pub const SYS_clock_nanosleep: c_long = 265; +pub const SYS_statfs64: c_long = 266; +pub const SYS_fstatfs64: c_long = 267; +pub const SYS_tgkill: c_long = 268; +pub const SYS_utimes: c_long = 269; +pub const SYS_arm_fadvise64_64: c_long = 270; +pub const SYS_pciconfig_iobase: c_long = 271; +pub const SYS_pciconfig_read: c_long = 272; +pub const SYS_pciconfig_write: c_long = 273; +pub const SYS_mq_open: c_long = 274; +pub const SYS_mq_unlink: c_long = 275; +pub const SYS_mq_timedsend: c_long = 276; +pub const SYS_mq_timedreceive: c_long = 277; +pub const SYS_mq_notify: c_long = 278; +pub const SYS_mq_getsetattr: c_long = 279; +pub const SYS_waitid: c_long = 280; +pub const SYS_socket: c_long = 281; +pub const SYS_bind: c_long = 282; +pub const SYS_connect: c_long = 283; +pub const SYS_listen: c_long = 284; +pub const SYS_accept: c_long = 285; +pub const SYS_getsockname: c_long = 286; +pub const SYS_getpeername: c_long = 287; +pub const SYS_socketpair: c_long = 288; +pub const SYS_send: c_long = 289; +pub const SYS_sendto: c_long = 290; +pub const SYS_recv: c_long = 291; +pub const SYS_recvfrom: c_long = 292; +pub const SYS_shutdown: c_long = 293; +pub const SYS_setsockopt: c_long = 294; +pub const SYS_getsockopt: c_long = 295; +pub const SYS_sendmsg: c_long = 296; +pub const SYS_recvmsg: c_long = 297; +pub const SYS_semop: c_long = 298; +pub const SYS_semget: c_long = 299; +pub const SYS_semctl: c_long = 300; +pub const SYS_msgsnd: c_long = 301; +pub const SYS_msgrcv: c_long = 302; +pub const SYS_msgget: c_long = 303; +pub const SYS_msgctl: c_long = 304; +pub const SYS_shmat: c_long = 305; +pub const SYS_shmdt: c_long = 306; +pub const SYS_shmget: c_long = 307; +pub const SYS_shmctl: c_long = 308; +pub const SYS_add_key: c_long = 309; +pub const SYS_request_key: c_long = 310; +pub const SYS_keyctl: c_long = 311; +pub const SYS_semtimedop: c_long = 312; +pub const SYS_vserver: c_long = 313; +pub const SYS_ioprio_set: c_long = 314; +pub const SYS_ioprio_get: c_long = 315; +pub const SYS_inotify_init: c_long = 316; +pub const SYS_inotify_add_watch: c_long = 317; +pub const SYS_inotify_rm_watch: c_long = 318; +pub const SYS_mbind: c_long = 319; +pub const SYS_get_mempolicy: c_long = 320; +pub const SYS_set_mempolicy: c_long = 321; +pub const SYS_openat: c_long = 322; +pub const SYS_mkdirat: c_long = 323; +pub const SYS_mknodat: c_long = 324; +pub const SYS_fchownat: c_long = 325; +pub const SYS_futimesat: c_long = 326; +pub const SYS_fstatat64: c_long = 327; +pub const SYS_unlinkat: c_long = 328; +pub const SYS_renameat: c_long = 329; +pub const SYS_linkat: c_long = 330; +pub const SYS_symlinkat: c_long = 331; +pub const SYS_readlinkat: c_long = 332; +pub const SYS_fchmodat: c_long = 333; +pub const SYS_faccessat: c_long = 334; +pub const SYS_pselect6: c_long = 335; +pub const SYS_ppoll: c_long = 336; +pub const SYS_unshare: c_long = 337; +pub const SYS_set_robust_list: c_long = 338; +pub const SYS_get_robust_list: c_long = 339; +pub const SYS_splice: c_long = 340; +pub const SYS_arm_sync_file_range: c_long = 341; +pub const SYS_tee: c_long = 342; +pub const SYS_vmsplice: c_long = 343; +pub const SYS_move_pages: c_long = 344; +pub const SYS_getcpu: c_long = 345; +pub const SYS_epoll_pwait: c_long = 346; +pub const SYS_kexec_load: c_long = 347; +pub const SYS_utimensat: c_long = 348; +pub const SYS_signalfd: c_long = 349; +pub const SYS_timerfd_create: c_long = 350; +pub const SYS_eventfd: c_long = 351; +pub const SYS_fallocate: c_long = 352; +pub const SYS_timerfd_settime: c_long = 353; +pub const SYS_timerfd_gettime: c_long = 354; +pub const SYS_signalfd4: c_long = 355; +pub const SYS_eventfd2: c_long = 356; +pub const SYS_epoll_create1: c_long = 357; +pub const SYS_dup3: c_long = 358; +pub const SYS_pipe2: c_long = 359; +pub const SYS_inotify_init1: c_long = 360; +pub const SYS_preadv: c_long = 361; +pub const SYS_pwritev: c_long = 362; +pub const SYS_rt_tgsigqueueinfo: c_long = 363; +pub const SYS_perf_event_open: c_long = 364; +pub const SYS_recvmmsg: c_long = 365; +pub const SYS_accept4: c_long = 366; +pub const SYS_fanotify_init: c_long = 367; +pub const SYS_fanotify_mark: c_long = 368; +pub const SYS_prlimit64: c_long = 369; +pub const SYS_name_to_handle_at: c_long = 370; +pub const SYS_open_by_handle_at: c_long = 371; +pub const SYS_clock_adjtime: c_long = 372; +pub const SYS_syncfs: c_long = 373; +pub const SYS_sendmmsg: c_long = 374; +pub const SYS_setns: c_long = 375; +pub const SYS_process_vm_readv: c_long = 376; +pub const SYS_process_vm_writev: c_long = 377; +pub const SYS_kcmp: c_long = 378; +pub const SYS_finit_module: c_long = 379; +pub const SYS_sched_setattr: c_long = 380; +pub const SYS_sched_getattr: c_long = 381; +pub const SYS_renameat2: c_long = 382; +pub const SYS_seccomp: c_long = 383; +pub const SYS_getrandom: c_long = 384; +pub const SYS_memfd_create: c_long = 385; +pub const SYS_bpf: c_long = 386; +pub const SYS_execveat: c_long = 387; +pub const SYS_userfaultfd: c_long = 388; +pub const SYS_membarrier: c_long = 389; +pub const SYS_mlock2: c_long = 390; +pub const SYS_copy_file_range: c_long = 391; +pub const SYS_preadv2: c_long = 392; +pub const SYS_pwritev2: c_long = 393; +pub const SYS_pkey_mprotect: c_long = 394; +pub const SYS_pkey_alloc: c_long = 395; +pub const SYS_pkey_free: c_long = 396; +pub const SYS_statx: c_long = 397; +pub const SYS_rseq: c_long = 398; +pub const SYS_kexec_file_load: c_long = 401; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/csky/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/csky/mod.rs new file mode 100644 index 00000000000000..dc88c635f1168f --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/csky/mod.rs @@ -0,0 +1,748 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = u32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + f_spare: [crate::__fsword_t; 5], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + __pad1: Padding, + __st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_ino: crate::ino64_t, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + __unused1: Padding, + pub shm_dtime: crate::time_t, + __unused2: Padding, + pub shm_ctime: crate::time_t, + __unused3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + __glibc_reserved1: Padding, + pub msg_rtime: crate::time_t, + __glibc_reserved2: Padding, + pub msg_ctime: crate::time_t, + __glibc_reserved3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [i64; 2], + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_LARGEFILE: c_int = 0o100000; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; + +pub const EFD_NONBLOCK: c_int = 0x800; +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +// Syscall table +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_close: c_long = 57; +pub const SYS_fstat: c_long = 80; +pub const SYS_lseek: c_long = 62; +pub const SYS_mmap: c_long = 222; +pub const SYS_mprotect: c_long = 226; +pub const SYS_munmap: c_long = 215; +pub const SYS_brk: c_long = 214; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_ioctl: c_long = 29; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_mremap: c_long = 216; +pub const SYS_msync: c_long = 227; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmctl: c_long = 195; +pub const SYS_dup: c_long = 23; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_getpid: c_long = 172; +pub const SYS_sendfile: c_long = 71; +pub const SYS_socket: c_long = 198; +pub const SYS_connect: c_long = 203; +pub const SYS_accept: c_long = 202; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_shutdown: c_long = 210; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_socketpair: c_long = 199; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_exit: c_long = 93; +pub const SYS_wait4: c_long = 260; +pub const SYS_kill: c_long = 129; +pub const SYS_uname: c_long = 160; +pub const SYS_semget: c_long = 190; +pub const SYS_semop: c_long = 193; +pub const SYS_semctl: c_long = 191; +pub const SYS_shmdt: c_long = 197; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgctl: c_long = 187; +pub const SYS_fcntl: c_long = 25; +pub const SYS_flock: c_long = 32; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_getcwd: c_long = 17; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchown: c_long = 55; +pub const SYS_umask: c_long = 166; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_getrusage: c_long = 165; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_times: c_long = 153; +pub const SYS_ptrace: c_long = 117; +pub const SYS_getuid: c_long = 174; +pub const SYS_syslog: c_long = 116; +pub const SYS_getgid: c_long = 176; +pub const SYS_setuid: c_long = 146; +pub const SYS_setgid: c_long = 144; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getegid: c_long = 177; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getppid: c_long = 173; +pub const SYS_setsid: c_long = 157; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setregid: c_long = 143; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_getpgid: c_long = 155; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_getsid: c_long = 156; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_personality: c_long = 92; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_getpriority: c_long = 141; +pub const SYS_setpriority: c_long = 140; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_prctl: c_long = 167; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_chroot: c_long = 51; +pub const SYS_sync: c_long = 81; +pub const SYS_acct: c_long = 89; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_mount: c_long = 40; +pub const SYS_umount2: c_long = 39; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_reboot: c_long = 142; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_quotactl: c_long = 60; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_gettid: c_long = 178; +pub const SYS_readahead: c_long = 213; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_tkill: c_long = 130; +pub const SYS_futex: c_long = 98; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_getdents64: c_long = 61; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_exit_group: c_long = 94; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_tgkill: c_long = 131; +pub const SYS_mbind: c_long = 235; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_waitid: c_long = 95; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_openat: c_long = 56; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_mknodat: c_long = 33; +pub const SYS_fchownat: c_long = 54; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_linkat: c_long = 37; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_faccessat: c_long = 48; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_unshare: c_long = 97; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_move_pages: c_long = 239; +pub const SYS_utimensat: c_long = 88; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_fallocate: c_long = 47; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_accept4: c_long = 242; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_dup3: c_long = 24; +pub const SYS_pipe2: c_long = 59; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_setns: c_long = 268; +pub const SYS_getcpu: c_long = 168; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_rseq: c_long = 293; +pub const SYS_syscall: c_long = 294; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/m68k/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/m68k/mod.rs new file mode 100644 index 00000000000000..2d91f986b76a0a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/m68k/mod.rs @@ -0,0 +1,885 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + f_spare: [crate::__fsword_t; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct ipc_perm { + __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + __seq: c_ushort, + __pad1: Padding, + __glibc_reserved1: Padding, + __glibc_reserved2: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + __pad1: Padding, + pub __st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_ulong, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_ulong, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_ulong, + pub st_ino: crate::ino64_t, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsblkcnt64_t, + pub f_ffree: crate::fsblkcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsblkcnt64_t, + pub f_ffree: crate::fsblkcnt64_t, + pub f_favail: crate::fsblkcnt64_t, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + __glibc_reserved1: Padding, + pub shm_dtime: crate::time_t, + __glibc_reserved2: Padding, + pub shm_ctime: crate::time_t, + __glibc_reserved3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __glibc_reserved5: Padding, + __glibc_reserved6: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + __glibc_reserved1: Padding, + pub msg_rtime: crate::time_t, + __glibc_reserved2: Padding, + pub msg_ctime: crate::time_t, + __glibc_reserved3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + _pad: Padding<[c_int; 29]>, + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } +} + +s_no_extra_traits! { + #[repr(align(2))] + pub struct max_align_t { + priv_: [i8; 20], + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_LARGEFILE: c_int = 0x20000; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; + +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_SYSEMU: c_uint = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_uint = 32; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const EFD_NONBLOCK: c_int = 0x800; +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time32: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_chown16: c_long = 16; +pub const SYS_stat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_oldumount: c_long = 22; +pub const SYS_setuid16: c_long = 23; +pub const SYS_getuid16: c_long = 24; +pub const SYS_stime32: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_fstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime32: c_long = 30; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid16: c_long = 46; +pub const SYS_getgid16: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid16: c_long = 49; +pub const SYS_getegid16: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid16: c_long = 70; +pub const SYS_setregid16: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_old_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups16: c_long = 80; +pub const SYS_setgroups16: c_long = 81; +pub const SYS_old_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_lstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_old_readdir: c_long = 89; +pub const SYS_old_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown16: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_newstat: c_long = 106; +pub const SYS_newlstat: c_long = 107; +pub const SYS_newfstat: c_long = 108; +pub const SYS_vhangup: c_long = 111; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_newuname: c_long = 122; +pub const SYS_cacheflush: c_long = 123; +pub const SYS_adjtimex_time32: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_setfsuid16: c_long = 138; +pub const SYS_setfsgid16: c_long = 139; +pub const SYS_llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS_select: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval_time32: c_long = 161; +pub const SYS_nanosleep_time32: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid16: c_long = 164; +pub const SYS_getresuid16: c_long = 165; +pub const SYS_getpagesize: c_long = 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid16: c_long = 170; +pub const SYS_getresgid16: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait_time32: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_lchown16: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_getrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_chown: c_long = 198; +pub const SYS_getuid: c_long = 199; +pub const SYS_getgid: c_long = 200; +pub const SYS_geteuid: c_long = 201; +pub const SYS_getegid: c_long = 202; +pub const SYS_setreuid: c_long = 203; +pub const SYS_setregid: c_long = 204; +pub const SYS_getgroups: c_long = 205; +pub const SYS_setgroups: c_long = 206; +pub const SYS_fchown: c_long = 207; +pub const SYS_setresuid: c_long = 208; +pub const SYS_getresuid: c_long = 209; +pub const SYS_setresgid: c_long = 210; +pub const SYS_getresgid: c_long = 211; +pub const SYS_lchown: c_long = 212; +pub const SYS_setuid: c_long = 213; +pub const SYS_setgid: c_long = 214; +pub const SYS_setfsuid: c_long = 215; +pub const SYS_setfsgid: c_long = 216; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_getdents64: c_long = 220; +pub const SYS_gettid: c_long = 221; +pub const SYS_tkill: c_long = 222; +pub const SYS_setxattr: c_long = 223; +pub const SYS_lsetxattr: c_long = 224; +pub const SYS_fsetxattr: c_long = 225; +pub const SYS_getxattr: c_long = 226; +pub const SYS_lgetxattr: c_long = 227; +pub const SYS_fgetxattr: c_long = 228; +pub const SYS_listxattr: c_long = 229; +pub const SYS_llistxattr: c_long = 230; +pub const SYS_flistxattr: c_long = 231; +pub const SYS_removexattr: c_long = 232; +pub const SYS_lremovexattr: c_long = 233; +pub const SYS_fremovexattr: c_long = 234; +pub const SYS_futex_time32: c_long = 235; +pub const SYS_sendfile64: c_long = 236; +pub const SYS_mincore: c_long = 237; +pub const SYS_madvise: c_long = 238; +pub const SYS_fcntl64: c_long = 239; +pub const SYS_readahead: c_long = 240; +pub const SYS_io_setup: c_long = 241; +pub const SYS_io_destroy: c_long = 242; +pub const SYS_io_getevents_time32: c_long = 243; +pub const SYS_io_submit: c_long = 244; +pub const SYS_io_cancel: c_long = 245; +pub const SYS_fadvise64: c_long = 246; +pub const SYS_exit_group: c_long = 247; +pub const SYS_lookup_dcookie: c_long = 248; +pub const SYS_epoll_create: c_long = 249; +pub const SYS_epoll_ctl: c_long = 250; +pub const SYS_epoll_wait: c_long = 251; +pub const SYS_remap_file_pages: c_long = 252; +pub const SYS_set_tid_address: c_long = 253; +pub const SYS_timer_create: c_long = 254; +pub const SYS_timer_settime32: c_long = 255; +pub const SYS_timer_gettime32: c_long = 256; +pub const SYS_timer_getoverrun: c_long = 257; +pub const SYS_timer_delete: c_long = 258; +pub const SYS_clock_settime32: c_long = 259; +pub const SYS_clock_gettime32: c_long = 260; +pub const SYS_clock_getres_time32: c_long = 261; +pub const SYS_clock_nanosleep_time32: c_long = 262; +pub const SYS_statfs64: c_long = 263; +pub const SYS_fstatfs64: c_long = 264; +pub const SYS_tgkill: c_long = 265; +pub const SYS_utimes_time32: c_long = 266; +pub const SYS_fadvise64_64: c_long = 267; +pub const SYS_mbind: c_long = 268; +pub const SYS_get_mempolicy: c_long = 269; +pub const SYS_set_mempolicy: c_long = 270; +pub const SYS_mq_open: c_long = 271; +pub const SYS_mq_unlink: c_long = 272; +pub const SYS_mq_timedsend_time32: c_long = 273; +pub const SYS_mq_timedreceive_time32: c_long = 274; +pub const SYS_mq_notify: c_long = 275; +pub const SYS_mq_getsetattr: c_long = 276; +pub const SYS_waitid: c_long = 277; +pub const SYS_add_key: c_long = 279; +pub const SYS_request_key: c_long = 280; +pub const SYS_keyctl: c_long = 281; +pub const SYS_ioprio_set: c_long = 282; +pub const SYS_ioprio_get: c_long = 283; +pub const SYS_inotify_init: c_long = 284; +pub const SYS_inotify_add_watch: c_long = 285; +pub const SYS_inotify_rm_watch: c_long = 286; +pub const SYS_migrate_pages: c_long = 287; +pub const SYS_openat: c_long = 288; +pub const SYS_mkdirat: c_long = 289; +pub const SYS_mknodat: c_long = 290; +pub const SYS_fchownat: c_long = 291; +pub const SYS_futimesat_time32: c_long = 292; +pub const SYS_fstatat64: c_long = 293; +pub const SYS_unlinkat: c_long = 294; +pub const SYS_renameat: c_long = 295; +pub const SYS_linkat: c_long = 296; +pub const SYS_symlinkat: c_long = 297; +pub const SYS_readlinkat: c_long = 298; +pub const SYS_fchmodat: c_long = 299; +pub const SYS_faccessat: c_long = 300; +pub const SYS_pselect6_time32: c_long = 301; +pub const SYS_ppoll_time32: c_long = 302; +pub const SYS_unshare: c_long = 303; +pub const SYS_set_robust_list: c_long = 304; +pub const SYS_get_robust_list: c_long = 305; +pub const SYS_splice: c_long = 306; +pub const SYS_sync_file_range: c_long = 307; +pub const SYS_tee: c_long = 308; +pub const SYS_vmsplice: c_long = 309; +pub const SYS_move_pages: c_long = 310; +pub const SYS_sched_setaffinity: c_long = 311; +pub const SYS_sched_getaffinity: c_long = 312; +pub const SYS_kexec_load: c_long = 313; +pub const SYS_getcpu: c_long = 314; +pub const SYS_epoll_pwait: c_long = 315; +pub const SYS_utimensat_time32: c_long = 316; +pub const SYS_signalfd: c_long = 317; +pub const SYS_timerfd_create: c_long = 318; +pub const SYS_eventfd: c_long = 319; +pub const SYS_fallocate: c_long = 320; +pub const SYS_timerfd_settime32: c_long = 321; +pub const SYS_timerfd_gettime32: c_long = 322; +pub const SYS_signalfd4: c_long = 323; +pub const SYS_eventfd2: c_long = 324; +pub const SYS_epoll_create1: c_long = 325; +pub const SYS_dup3: c_long = 326; +pub const SYS_pipe2: c_long = 327; +pub const SYS_inotify_init1: c_long = 328; +pub const SYS_preadv: c_long = 329; +pub const SYS_pwritev: c_long = 330; +pub const SYS_rt_tgsigqueueinfo: c_long = 331; +pub const SYS_perf_event_open: c_long = 332; +pub const SYS_get_thread_area: c_long = 333; +pub const SYS_set_thread_area: c_long = 334; +pub const SYS_atomic_cmpxchg_32: c_long = 335; +pub const SYS_atomic_barrier: c_long = 336; +pub const SYS_fanotify_init: c_long = 337; +pub const SYS_fanotify_mark: c_long = 338; +pub const SYS_prlimit64: c_long = 339; +pub const SYS_name_to_handle_at: c_long = 340; +pub const SYS_open_by_handle_at: c_long = 341; +pub const SYS_clock_adjtime32: c_long = 342; +pub const SYS_syncfs: c_long = 343; +pub const SYS_setns: c_long = 344; +pub const SYS_process_vm_readv: c_long = 345; +pub const SYS_process_vm_writev: c_long = 346; +pub const SYS_kcmp: c_long = 347; +pub const SYS_finit_module: c_long = 348; +pub const SYS_sched_setattr: c_long = 349; +pub const SYS_sched_getattr: c_long = 350; +pub const SYS_renameat2: c_long = 351; +pub const SYS_getrandom: c_long = 352; +pub const SYS_memfd_create: c_long = 353; +pub const SYS_bpf: c_long = 354; +pub const SYS_execveat: c_long = 355; +pub const SYS_socket: c_long = 356; +pub const SYS_socketpair: c_long = 357; +pub const SYS_bind: c_long = 358; +pub const SYS_connect: c_long = 359; +pub const SYS_listen: c_long = 360; +pub const SYS_accept4: c_long = 361; +pub const SYS_getsockopt: c_long = 362; +pub const SYS_setsockopt: c_long = 363; +pub const SYS_getsockname: c_long = 364; +pub const SYS_getpeername: c_long = 365; +pub const SYS_sendto: c_long = 366; +pub const SYS_sendmsg: c_long = 367; +pub const SYS_recvfrom: c_long = 368; +pub const SYS_recvmsg: c_long = 369; +pub const SYS_shutdown: c_long = 370; +pub const SYS_recvmmsg_time32: c_long = 371; +pub const SYS_sendmmsg: c_long = 372; +pub const SYS_userfaultfd: c_long = 373; +pub const SYS_membarrier: c_long = 374; +pub const SYS_mlock2: c_long = 375; +pub const SYS_copy_file_range: c_long = 376; +pub const SYS_preadv2: c_long = 377; +pub const SYS_pwritev2: c_long = 378; +pub const SYS_statx: c_long = 379; +pub const SYS_seccomp: c_long = 380; +pub const SYS_pkey_mprotect: c_long = 381; +pub const SYS_pkey_alloc: c_long = 382; +pub const SYS_pkey_free: c_long = 383; +pub const SYS_rseq: c_long = 384; +pub const SYS_semget: c_long = 393; +pub const SYS_semctl: c_long = 394; +pub const SYS_shmget: c_long = 395; +pub const SYS_shmctl: c_long = 396; +pub const SYS_shmat: c_long = 397; +pub const SYS_shmdt: c_long = 398; +pub const SYS_msgget: c_long = 399; +pub const SYS_msgsnd: c_long = 400; +pub const SYS_msgrcv: c_long = 401; +pub const SYS_msgctl: c_long = 402; +pub const SYS_clock_gettime: c_long = 403; +pub const SYS_clock_settime: c_long = 404; +pub const SYS_clock_adjtime: c_long = 405; +pub const SYS_clock_getres: c_long = 406; +pub const SYS_clock_nanosleep: c_long = 407; +pub const SYS_timer_gettime: c_long = 408; +pub const SYS_timer_settime: c_long = 409; +pub const SYS_timerfd_gettime: c_long = 410; +pub const SYS_timerfd_settime: c_long = 411; +pub const SYS_utimensat: c_long = 412; +pub const SYS_pselect6: c_long = 413; +pub const SYS_ppoll: c_long = 414; +pub const SYS_io_pgetevents: c_long = 416; +pub const SYS_recvmmsg: c_long = 417; +pub const SYS_mq_timedsend: c_long = 418; +pub const SYS_mq_timedreceive: c_long = 419; +pub const SYS_semtimedop: c_long = 420; +pub const SYS_rt_sigtimedwait: c_long = 421; +pub const SYS_futex: c_long = 422; +pub const SYS_sched_rr_get_interval: c_long = 423; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_cachestat: c_long = 451; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_map_shadow_stack: c_long = 453; +pub const SYS_futex_wake: c_long = 454; +pub const SYS_futex_wait: c_long = 455; +pub const SYS_futex_requeue: c_long = 456; +pub const SYS_statmount: c_long = 457; +pub const SYS_listmount: c_long = 458; +pub const SYS_lsm_get_self_attr: c_long = 459; +pub const SYS_lsm_set_self_attr: c_long = 460; +pub const SYS_lsm_list_modules: c_long = 461; +pub const SYS_mseal: c_long = 462; +pub const SYS_setxattrat: c_long = 463; +pub const SYS_getxattrat: c_long = 464; +pub const SYS_listxattrat: c_long = 465; +pub const SYS_removexattrat: c_long = 466; +pub const SYS_open_tree_attr: c_long = 467; +pub const SYS_file_get_attr: c_long = 468; +pub const SYS_file_set_attr: c_long = 469; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mips/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mips/mod.rs new file mode 100644 index 00000000000000..18bb1933925f01 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mips/mod.rs @@ -0,0 +1,928 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; + +s! { + pub struct stat { + #[cfg(not(gnu_time_bits64))] + pub st_dev: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_dev: crate::dev_t, + + #[cfg(not(gnu_time_bits64))] + st_pad1: Padding<[c_long; 3]>, + + pub st_ino: crate::ino_t, + + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + + #[cfg(not(gnu_time_bits64))] + pub st_rdev: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_rdev: crate::dev_t, + + #[cfg(not(gnu_file_offset_bits64))] + st_pad2: Padding<[c_long; 2]>, + #[cfg(all(not(gnu_time_bits64), gnu_file_offset_bits64))] + st_pad2: Padding<[c_long; 3]>, + + pub st_size: off_t, + + #[cfg(not(gnu_file_offset_bits64))] + st_pad3: Padding, + + #[cfg(gnu_time_bits64)] + pub st_blksize: crate::blksize_t, + #[cfg(gnu_time_bits64)] + pub st_blocks: crate::blkcnt_t, + + pub st_atime: crate::time_t, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + pub st_ctime_nsec: c_long, + + #[cfg(not(gnu_time_bits64))] + pub st_blksize: crate::blksize_t, + #[cfg(all(not(gnu_time_bits64), gnu_file_offset_bits64))] + st_pad4: Padding, + #[cfg(not(gnu_time_bits64))] + pub st_blocks: crate::blkcnt_t, + #[cfg(not(gnu_time_bits64))] + st_pad5: Padding<[c_long; 14]>, + } + + pub struct stat64 { + #[cfg(not(gnu_time_bits64))] + pub st_dev: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_dev: crate::dev_t, + + #[cfg(not(gnu_time_bits64))] + st_pad1: Padding<[c_long; 3]>, + + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + + #[cfg(not(gnu_time_bits64))] + pub st_rdev: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_rdev: crate::dev_t, + + #[cfg(not(gnu_time_bits64))] + st_pad2: Padding<[c_long; 3]>, + + pub st_size: off64_t, + + #[cfg(gnu_time_bits64)] + pub st_blksize: crate::blksize_t, + #[cfg(gnu_time_bits64)] + pub st_blocks: crate::blkcnt_t, + + pub st_atime: crate::time_t, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + pub st_ctime_nsec: c_long, + + #[cfg(not(gnu_time_bits64))] + pub st_blksize: crate::blksize_t, + #[cfg(not(gnu_time_bits64))] + st_pad3: Padding, + #[cfg(not(gnu_time_bits64))] + pub st_blocks: crate::blkcnt64_t, + #[cfg(not(gnu_time_bits64))] + st_pad5: Padding<[c_long; 14]>, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsblkcnt_t, + pub f_ffree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: c_long, + pub f_flags: c_long, + f_spare: [c_long; 5], + } + + pub struct statfs64 { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_bavail: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 5], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_flags: c_int, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_restorer: Option, + _resv: [c_int; 1], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + pub _pad: [c_int; 29], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + #[cfg(all(not(gnu_time_bits64), target_endian = "big"))] + __glibc_reserved1: Padding, + pub msg_stime: crate::time_t, + #[cfg(all(not(gnu_time_bits64), target_endian = "little"))] + __glibc_reserved1: Padding, + #[cfg(all(not(gnu_time_bits64), target_endian = "big"))] + __glibc_reserved2: Padding, + pub msg_rtime: crate::time_t, + #[cfg(all(not(gnu_time_bits64), target_endian = "little"))] + __glibc_reserved2: Padding, + #[cfg(all(not(gnu_time_bits64), target_endian = "big"))] + __glibc_reserved3: Padding, + pub msg_ctime: crate::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved3: Padding, + __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + #[cfg(not(gnu_file_offset_bits64))] + pub l_sysid: c_long, + pub l_pid: crate::pid_t, + #[cfg(not(gnu_file_offset_bits64))] + __glibc_reserved0: Padding<[c_long; 4]>, + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [f32; 4], + } +} + +pub const O_LARGEFILE: c_int = 0x2000; + +pub const SYS_syscall: c_long = 4000 + 0; +pub const SYS_exit: c_long = 4000 + 1; +pub const SYS_fork: c_long = 4000 + 2; +pub const SYS_read: c_long = 4000 + 3; +pub const SYS_write: c_long = 4000 + 4; +pub const SYS_open: c_long = 4000 + 5; +pub const SYS_close: c_long = 4000 + 6; +pub const SYS_waitpid: c_long = 4000 + 7; +pub const SYS_creat: c_long = 4000 + 8; +pub const SYS_link: c_long = 4000 + 9; +pub const SYS_unlink: c_long = 4000 + 10; +pub const SYS_execve: c_long = 4000 + 11; +pub const SYS_chdir: c_long = 4000 + 12; +pub const SYS_time: c_long = 4000 + 13; +pub const SYS_mknod: c_long = 4000 + 14; +pub const SYS_chmod: c_long = 4000 + 15; +pub const SYS_lchown: c_long = 4000 + 16; +pub const SYS_break: c_long = 4000 + 17; +pub const SYS_lseek: c_long = 4000 + 19; +pub const SYS_getpid: c_long = 4000 + 20; +pub const SYS_mount: c_long = 4000 + 21; +pub const SYS_umount: c_long = 4000 + 22; +pub const SYS_setuid: c_long = 4000 + 23; +pub const SYS_getuid: c_long = 4000 + 24; +pub const SYS_stime: c_long = 4000 + 25; +pub const SYS_ptrace: c_long = 4000 + 26; +pub const SYS_alarm: c_long = 4000 + 27; +pub const SYS_pause: c_long = 4000 + 29; +pub const SYS_utime: c_long = 4000 + 30; +pub const SYS_stty: c_long = 4000 + 31; +pub const SYS_gtty: c_long = 4000 + 32; +pub const SYS_access: c_long = 4000 + 33; +pub const SYS_nice: c_long = 4000 + 34; +pub const SYS_ftime: c_long = 4000 + 35; +pub const SYS_sync: c_long = 4000 + 36; +pub const SYS_kill: c_long = 4000 + 37; +pub const SYS_rename: c_long = 4000 + 38; +pub const SYS_mkdir: c_long = 4000 + 39; +pub const SYS_rmdir: c_long = 4000 + 40; +pub const SYS_dup: c_long = 4000 + 41; +pub const SYS_pipe: c_long = 4000 + 42; +pub const SYS_times: c_long = 4000 + 43; +pub const SYS_prof: c_long = 4000 + 44; +pub const SYS_brk: c_long = 4000 + 45; +pub const SYS_setgid: c_long = 4000 + 46; +pub const SYS_getgid: c_long = 4000 + 47; +pub const SYS_signal: c_long = 4000 + 48; +pub const SYS_geteuid: c_long = 4000 + 49; +pub const SYS_getegid: c_long = 4000 + 50; +pub const SYS_acct: c_long = 4000 + 51; +pub const SYS_umount2: c_long = 4000 + 52; +pub const SYS_lock: c_long = 4000 + 53; +pub const SYS_ioctl: c_long = 4000 + 54; +pub const SYS_fcntl: c_long = 4000 + 55; +pub const SYS_mpx: c_long = 4000 + 56; +pub const SYS_setpgid: c_long = 4000 + 57; +pub const SYS_ulimit: c_long = 4000 + 58; +pub const SYS_umask: c_long = 4000 + 60; +pub const SYS_chroot: c_long = 4000 + 61; +pub const SYS_ustat: c_long = 4000 + 62; +pub const SYS_dup2: c_long = 4000 + 63; +pub const SYS_getppid: c_long = 4000 + 64; +pub const SYS_getpgrp: c_long = 4000 + 65; +pub const SYS_setsid: c_long = 4000 + 66; +pub const SYS_sigaction: c_long = 4000 + 67; +pub const SYS_sgetmask: c_long = 4000 + 68; +pub const SYS_ssetmask: c_long = 4000 + 69; +pub const SYS_setreuid: c_long = 4000 + 70; +pub const SYS_setregid: c_long = 4000 + 71; +pub const SYS_sigsuspend: c_long = 4000 + 72; +pub const SYS_sigpending: c_long = 4000 + 73; +pub const SYS_sethostname: c_long = 4000 + 74; +pub const SYS_setrlimit: c_long = 4000 + 75; +pub const SYS_getrlimit: c_long = 4000 + 76; +pub const SYS_getrusage: c_long = 4000 + 77; +pub const SYS_gettimeofday: c_long = 4000 + 78; +pub const SYS_settimeofday: c_long = 4000 + 79; +pub const SYS_getgroups: c_long = 4000 + 80; +pub const SYS_setgroups: c_long = 4000 + 81; +pub const SYS_symlink: c_long = 4000 + 83; +pub const SYS_readlink: c_long = 4000 + 85; +pub const SYS_uselib: c_long = 4000 + 86; +pub const SYS_swapon: c_long = 4000 + 87; +pub const SYS_reboot: c_long = 4000 + 88; +pub const SYS_readdir: c_long = 4000 + 89; +pub const SYS_mmap: c_long = 4000 + 90; +pub const SYS_munmap: c_long = 4000 + 91; +pub const SYS_truncate: c_long = 4000 + 92; +pub const SYS_ftruncate: c_long = 4000 + 93; +pub const SYS_fchmod: c_long = 4000 + 94; +pub const SYS_fchown: c_long = 4000 + 95; +pub const SYS_getpriority: c_long = 4000 + 96; +pub const SYS_setpriority: c_long = 4000 + 97; +pub const SYS_profil: c_long = 4000 + 98; +pub const SYS_statfs: c_long = 4000 + 99; +pub const SYS_fstatfs: c_long = 4000 + 100; +pub const SYS_ioperm: c_long = 4000 + 101; +pub const SYS_socketcall: c_long = 4000 + 102; +pub const SYS_syslog: c_long = 4000 + 103; +pub const SYS_setitimer: c_long = 4000 + 104; +pub const SYS_getitimer: c_long = 4000 + 105; +pub const SYS_stat: c_long = 4000 + 106; +pub const SYS_lstat: c_long = 4000 + 107; +pub const SYS_fstat: c_long = 4000 + 108; +pub const SYS_iopl: c_long = 4000 + 110; +pub const SYS_vhangup: c_long = 4000 + 111; +pub const SYS_idle: c_long = 4000 + 112; +pub const SYS_vm86: c_long = 4000 + 113; +pub const SYS_wait4: c_long = 4000 + 114; +pub const SYS_swapoff: c_long = 4000 + 115; +pub const SYS_sysinfo: c_long = 4000 + 116; +pub const SYS_ipc: c_long = 4000 + 117; +pub const SYS_fsync: c_long = 4000 + 118; +pub const SYS_sigreturn: c_long = 4000 + 119; +pub const SYS_clone: c_long = 4000 + 120; +pub const SYS_setdomainname: c_long = 4000 + 121; +pub const SYS_uname: c_long = 4000 + 122; +pub const SYS_modify_ldt: c_long = 4000 + 123; +pub const SYS_adjtimex: c_long = 4000 + 124; +pub const SYS_mprotect: c_long = 4000 + 125; +pub const SYS_sigprocmask: c_long = 4000 + 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 4000 + 127; +pub const SYS_init_module: c_long = 4000 + 128; +pub const SYS_delete_module: c_long = 4000 + 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 4000 + 130; +pub const SYS_quotactl: c_long = 4000 + 131; +pub const SYS_getpgid: c_long = 4000 + 132; +pub const SYS_fchdir: c_long = 4000 + 133; +pub const SYS_bdflush: c_long = 4000 + 134; +pub const SYS_sysfs: c_long = 4000 + 135; +pub const SYS_personality: c_long = 4000 + 136; +pub const SYS_afs_syscall: c_long = 4000 + 137; +pub const SYS_setfsuid: c_long = 4000 + 138; +pub const SYS_setfsgid: c_long = 4000 + 139; +pub const SYS__llseek: c_long = 4000 + 140; +pub const SYS_getdents: c_long = 4000 + 141; +pub const SYS__newselect: c_long = 4000 + 142; +pub const SYS_flock: c_long = 4000 + 143; +pub const SYS_msync: c_long = 4000 + 144; +pub const SYS_readv: c_long = 4000 + 145; +pub const SYS_writev: c_long = 4000 + 146; +pub const SYS_cacheflush: c_long = 4000 + 147; +pub const SYS_cachectl: c_long = 4000 + 148; +pub const SYS_sysmips: c_long = 4000 + 149; +pub const SYS_getsid: c_long = 4000 + 151; +pub const SYS_fdatasync: c_long = 4000 + 152; +pub const SYS__sysctl: c_long = 4000 + 153; +pub const SYS_mlock: c_long = 4000 + 154; +pub const SYS_munlock: c_long = 4000 + 155; +pub const SYS_mlockall: c_long = 4000 + 156; +pub const SYS_munlockall: c_long = 4000 + 157; +pub const SYS_sched_setparam: c_long = 4000 + 158; +pub const SYS_sched_getparam: c_long = 4000 + 159; +pub const SYS_sched_setscheduler: c_long = 4000 + 160; +pub const SYS_sched_getscheduler: c_long = 4000 + 161; +pub const SYS_sched_yield: c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: c_long = 4000 + 165; +pub const SYS_nanosleep: c_long = 4000 + 166; +pub const SYS_mremap: c_long = 4000 + 167; +pub const SYS_accept: c_long = 4000 + 168; +pub const SYS_bind: c_long = 4000 + 169; +pub const SYS_connect: c_long = 4000 + 170; +pub const SYS_getpeername: c_long = 4000 + 171; +pub const SYS_getsockname: c_long = 4000 + 172; +pub const SYS_getsockopt: c_long = 4000 + 173; +pub const SYS_listen: c_long = 4000 + 174; +pub const SYS_recv: c_long = 4000 + 175; +pub const SYS_recvfrom: c_long = 4000 + 176; +pub const SYS_recvmsg: c_long = 4000 + 177; +pub const SYS_send: c_long = 4000 + 178; +pub const SYS_sendmsg: c_long = 4000 + 179; +pub const SYS_sendto: c_long = 4000 + 180; +pub const SYS_setsockopt: c_long = 4000 + 181; +pub const SYS_shutdown: c_long = 4000 + 182; +pub const SYS_socket: c_long = 4000 + 183; +pub const SYS_socketpair: c_long = 4000 + 184; +pub const SYS_setresuid: c_long = 4000 + 185; +pub const SYS_getresuid: c_long = 4000 + 186; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 4000 + 187; +pub const SYS_poll: c_long = 4000 + 188; +pub const SYS_nfsservctl: c_long = 4000 + 189; +pub const SYS_setresgid: c_long = 4000 + 190; +pub const SYS_getresgid: c_long = 4000 + 191; +pub const SYS_prctl: c_long = 4000 + 192; +pub const SYS_rt_sigreturn: c_long = 4000 + 193; +pub const SYS_rt_sigaction: c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: c_long = 4000 + 195; +pub const SYS_rt_sigpending: c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: c_long = 4000 + 199; +pub const SYS_pread64: c_long = 4000 + 200; +pub const SYS_pwrite64: c_long = 4000 + 201; +pub const SYS_chown: c_long = 4000 + 202; +pub const SYS_getcwd: c_long = 4000 + 203; +pub const SYS_capget: c_long = 4000 + 204; +pub const SYS_capset: c_long = 4000 + 205; +pub const SYS_sigaltstack: c_long = 4000 + 206; +pub const SYS_sendfile: c_long = 4000 + 207; +pub const SYS_getpmsg: c_long = 4000 + 208; +pub const SYS_putpmsg: c_long = 4000 + 209; +pub const SYS_mmap2: c_long = 4000 + 210; +pub const SYS_truncate64: c_long = 4000 + 211; +pub const SYS_ftruncate64: c_long = 4000 + 212; +pub const SYS_stat64: c_long = 4000 + 213; +pub const SYS_lstat64: c_long = 4000 + 214; +pub const SYS_fstat64: c_long = 4000 + 215; +pub const SYS_pivot_root: c_long = 4000 + 216; +pub const SYS_mincore: c_long = 4000 + 217; +pub const SYS_madvise: c_long = 4000 + 218; +pub const SYS_getdents64: c_long = 4000 + 219; +pub const SYS_fcntl64: c_long = 4000 + 220; +pub const SYS_gettid: c_long = 4000 + 222; +pub const SYS_readahead: c_long = 4000 + 223; +pub const SYS_setxattr: c_long = 4000 + 224; +pub const SYS_lsetxattr: c_long = 4000 + 225; +pub const SYS_fsetxattr: c_long = 4000 + 226; +pub const SYS_getxattr: c_long = 4000 + 227; +pub const SYS_lgetxattr: c_long = 4000 + 228; +pub const SYS_fgetxattr: c_long = 4000 + 229; +pub const SYS_listxattr: c_long = 4000 + 230; +pub const SYS_llistxattr: c_long = 4000 + 231; +pub const SYS_flistxattr: c_long = 4000 + 232; +pub const SYS_removexattr: c_long = 4000 + 233; +pub const SYS_lremovexattr: c_long = 4000 + 234; +pub const SYS_fremovexattr: c_long = 4000 + 235; +pub const SYS_tkill: c_long = 4000 + 236; +pub const SYS_sendfile64: c_long = 4000 + 237; +pub const SYS_futex: c_long = 4000 + 238; +pub const SYS_sched_setaffinity: c_long = 4000 + 239; +pub const SYS_sched_getaffinity: c_long = 4000 + 240; +pub const SYS_io_setup: c_long = 4000 + 241; +pub const SYS_io_destroy: c_long = 4000 + 242; +pub const SYS_io_getevents: c_long = 4000 + 243; +pub const SYS_io_submit: c_long = 4000 + 244; +pub const SYS_io_cancel: c_long = 4000 + 245; +pub const SYS_exit_group: c_long = 4000 + 246; +pub const SYS_lookup_dcookie: c_long = 4000 + 247; +pub const SYS_epoll_create: c_long = 4000 + 248; +pub const SYS_epoll_ctl: c_long = 4000 + 249; +pub const SYS_epoll_wait: c_long = 4000 + 250; +pub const SYS_remap_file_pages: c_long = 4000 + 251; +pub const SYS_set_tid_address: c_long = 4000 + 252; +pub const SYS_restart_syscall: c_long = 4000 + 253; +pub const SYS_fadvise64: c_long = 4000 + 254; +pub const SYS_statfs64: c_long = 4000 + 255; +pub const SYS_fstatfs64: c_long = 4000 + 256; +pub const SYS_timer_create: c_long = 4000 + 257; +pub const SYS_timer_settime: c_long = 4000 + 258; +pub const SYS_timer_gettime: c_long = 4000 + 259; +pub const SYS_timer_getoverrun: c_long = 4000 + 260; +pub const SYS_timer_delete: c_long = 4000 + 261; +pub const SYS_clock_settime: c_long = 4000 + 262; +pub const SYS_clock_gettime: c_long = 4000 + 263; +pub const SYS_clock_getres: c_long = 4000 + 264; +pub const SYS_clock_nanosleep: c_long = 4000 + 265; +pub const SYS_tgkill: c_long = 4000 + 266; +pub const SYS_utimes: c_long = 4000 + 267; +pub const SYS_mbind: c_long = 4000 + 268; +pub const SYS_get_mempolicy: c_long = 4000 + 269; +pub const SYS_set_mempolicy: c_long = 4000 + 270; +pub const SYS_mq_open: c_long = 4000 + 271; +pub const SYS_mq_unlink: c_long = 4000 + 272; +pub const SYS_mq_timedsend: c_long = 4000 + 273; +pub const SYS_mq_timedreceive: c_long = 4000 + 274; +pub const SYS_mq_notify: c_long = 4000 + 275; +pub const SYS_mq_getsetattr: c_long = 4000 + 276; +pub const SYS_vserver: c_long = 4000 + 277; +pub const SYS_waitid: c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: c_long = 4000 + 279; */ +pub const SYS_add_key: c_long = 4000 + 280; +pub const SYS_request_key: c_long = 4000 + 281; +pub const SYS_keyctl: c_long = 4000 + 282; +pub const SYS_set_thread_area: c_long = 4000 + 283; +pub const SYS_inotify_init: c_long = 4000 + 284; +pub const SYS_inotify_add_watch: c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: c_long = 4000 + 286; +pub const SYS_migrate_pages: c_long = 4000 + 287; +pub const SYS_openat: c_long = 4000 + 288; +pub const SYS_mkdirat: c_long = 4000 + 289; +pub const SYS_mknodat: c_long = 4000 + 290; +pub const SYS_fchownat: c_long = 4000 + 291; +pub const SYS_futimesat: c_long = 4000 + 292; +pub const SYS_fstatat64: c_long = 4000 + 293; +pub const SYS_unlinkat: c_long = 4000 + 294; +pub const SYS_renameat: c_long = 4000 + 295; +pub const SYS_linkat: c_long = 4000 + 296; +pub const SYS_symlinkat: c_long = 4000 + 297; +pub const SYS_readlinkat: c_long = 4000 + 298; +pub const SYS_fchmodat: c_long = 4000 + 299; +pub const SYS_faccessat: c_long = 4000 + 300; +pub const SYS_pselect6: c_long = 4000 + 301; +pub const SYS_ppoll: c_long = 4000 + 302; +pub const SYS_unshare: c_long = 4000 + 303; +pub const SYS_splice: c_long = 4000 + 304; +pub const SYS_sync_file_range: c_long = 4000 + 305; +pub const SYS_tee: c_long = 4000 + 306; +pub const SYS_vmsplice: c_long = 4000 + 307; +pub const SYS_move_pages: c_long = 4000 + 308; +pub const SYS_set_robust_list: c_long = 4000 + 309; +pub const SYS_get_robust_list: c_long = 4000 + 310; +pub const SYS_kexec_load: c_long = 4000 + 311; +pub const SYS_getcpu: c_long = 4000 + 312; +pub const SYS_epoll_pwait: c_long = 4000 + 313; +pub const SYS_ioprio_set: c_long = 4000 + 314; +pub const SYS_ioprio_get: c_long = 4000 + 315; +pub const SYS_utimensat: c_long = 4000 + 316; +pub const SYS_signalfd: c_long = 4000 + 317; +pub const SYS_timerfd: c_long = 4000 + 318; +pub const SYS_eventfd: c_long = 4000 + 319; +pub const SYS_fallocate: c_long = 4000 + 320; +pub const SYS_timerfd_create: c_long = 4000 + 321; +pub const SYS_timerfd_gettime: c_long = 4000 + 322; +pub const SYS_timerfd_settime: c_long = 4000 + 323; +pub const SYS_signalfd4: c_long = 4000 + 324; +pub const SYS_eventfd2: c_long = 4000 + 325; +pub const SYS_epoll_create1: c_long = 4000 + 326; +pub const SYS_dup3: c_long = 4000 + 327; +pub const SYS_pipe2: c_long = 4000 + 328; +pub const SYS_inotify_init1: c_long = 4000 + 329; +pub const SYS_preadv: c_long = 4000 + 330; +pub const SYS_pwritev: c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: c_long = 4000 + 332; +pub const SYS_perf_event_open: c_long = 4000 + 333; +pub const SYS_accept4: c_long = 4000 + 334; +pub const SYS_recvmmsg: c_long = 4000 + 335; +pub const SYS_fanotify_init: c_long = 4000 + 336; +pub const SYS_fanotify_mark: c_long = 4000 + 337; +pub const SYS_prlimit64: c_long = 4000 + 338; +pub const SYS_name_to_handle_at: c_long = 4000 + 339; +pub const SYS_open_by_handle_at: c_long = 4000 + 340; +pub const SYS_clock_adjtime: c_long = 4000 + 341; +pub const SYS_syncfs: c_long = 4000 + 342; +pub const SYS_sendmmsg: c_long = 4000 + 343; +pub const SYS_setns: c_long = 4000 + 344; +pub const SYS_process_vm_readv: c_long = 4000 + 345; +pub const SYS_process_vm_writev: c_long = 4000 + 346; +pub const SYS_kcmp: c_long = 4000 + 347; +pub const SYS_finit_module: c_long = 4000 + 348; +pub const SYS_sched_setattr: c_long = 4000 + 349; +pub const SYS_sched_getattr: c_long = 4000 + 350; +pub const SYS_renameat2: c_long = 4000 + 351; +pub const SYS_seccomp: c_long = 4000 + 352; +pub const SYS_getrandom: c_long = 4000 + 353; +pub const SYS_memfd_create: c_long = 4000 + 354; +pub const SYS_bpf: c_long = 4000 + 355; +pub const SYS_execveat: c_long = 4000 + 356; +pub const SYS_userfaultfd: c_long = 4000 + 357; +pub const SYS_membarrier: c_long = 4000 + 358; +pub const SYS_mlock2: c_long = 4000 + 359; +pub const SYS_copy_file_range: c_long = 4000 + 360; +pub const SYS_preadv2: c_long = 4000 + 361; +pub const SYS_pwritev2: c_long = 4000 + 362; +pub const SYS_pkey_mprotect: c_long = 4000 + 363; +pub const SYS_pkey_alloc: c_long = 4000 + 364; +pub const SYS_pkey_free: c_long = 4000 + 365; +pub const SYS_statx: c_long = 4000 + 366; +pub const SYS_rseq: c_long = 4000 + 367; +pub const SYS_pidfd_send_signal: c_long = 4000 + 424; +pub const SYS_io_uring_setup: c_long = 4000 + 425; +pub const SYS_io_uring_enter: c_long = 4000 + 426; +pub const SYS_io_uring_register: c_long = 4000 + 427; +pub const SYS_open_tree: c_long = 4000 + 428; +pub const SYS_move_mount: c_long = 4000 + 429; +pub const SYS_fsopen: c_long = 4000 + 430; +pub const SYS_fsconfig: c_long = 4000 + 431; +pub const SYS_fsmount: c_long = 4000 + 432; +pub const SYS_fspick: c_long = 4000 + 433; +pub const SYS_pidfd_open: c_long = 4000 + 434; +pub const SYS_clone3: c_long = 4000 + 435; +pub const SYS_close_range: c_long = 4000 + 436; +pub const SYS_openat2: c_long = 4000 + 437; +pub const SYS_pidfd_getfd: c_long = 4000 + 438; +pub const SYS_faccessat2: c_long = 4000 + 439; +pub const SYS_process_madvise: c_long = 4000 + 440; +pub const SYS_epoll_pwait2: c_long = 4000 + 441; +pub const SYS_mount_setattr: c_long = 4000 + 442; +pub const SYS_quotactl_fd: c_long = 4000 + 443; +pub const SYS_landlock_create_ruleset: c_long = 4000 + 444; +pub const SYS_landlock_add_rule: c_long = 4000 + 445; +pub const SYS_landlock_restrict_self: c_long = 4000 + 446; +pub const SYS_memfd_secret: c_long = 4000 + 447; +pub const SYS_process_mrelease: c_long = 4000 + 448; +pub const SYS_futex_waitv: c_long = 4000 + 449; +pub const SYS_set_mempolicy_home_node: c_long = 4000 + 450; + +pub const O_DIRECT: c_int = 0x8000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 256; +pub const O_EXCL: c_int = 1024; +pub const O_NOCTTY: c_int = 2048; +pub const O_NONBLOCK: c_int = 128; +pub const O_SYNC: c_int = 0x4010; +pub const O_RSYNC: c_int = 0x4010; +pub const O_DSYNC: c_int = 0x10; +pub const O_FSYNC: c_int = 0x4010; +pub const O_ASYNC: c_int = 0x1000; +pub const O_NDELAY: c_int = 0x80; + +pub const EDEADLK: c_int = 45; +pub const ENAMETOOLONG: c_int = 78; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 89; +pub const ENOTEMPTY: c_int = 93; +pub const ELOOP: c_int = 90; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EMULTIHOP: c_int = 74; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EBADMSG: c_int = 77; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; +pub const EUCLEAN: c_int = 135; +pub const ENOTNAM: c_int = 137; +pub const ENAVAIL: c_int = 138; +pub const EISNAM: c_int = 139; +pub const EREMOTEIO: c_int = 140; +pub const EDQUOT: c_int = 1133; +pub const ENOMEDIUM: c_int = 159; +pub const EMEDIUMTYPE: c_int = 160; +pub const ECANCELED: c_int = 158; +pub const ENOKEY: c_int = 161; +pub const EKEYEXPIRED: c_int = 162; +pub const EKEYREVOKED: c_int = 163; +pub const EKEYREJECTED: c_int = 164; +pub const EOWNERDEAD: c_int = 165; +pub const ENOTRECOVERABLE: c_int = 166; +pub const ERFKILL: c_int = 167; + +pub const MAP_NORESERVE: c_int = 0x400; +pub const MAP_ANON: c_int = 0x800; +pub const MAP_ANONYMOUS: c_int = 0x800; +pub const MAP_GROWSDOWN: c_int = 0x1000; +pub const MAP_DENYWRITE: c_int = 0x2000; +pub const MAP_EXECUTABLE: c_int = 0x4000; +pub const MAP_LOCKED: c_int = 0x8000; +pub const MAP_POPULATE: c_int = 0x10000; +pub const MAP_NONBLOCK: c_int = 0x20000; +pub const MAP_STACK: c_int = 0x40000; + +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_DGRAM: c_int = 1; + +pub const SA_SIGINFO: c_int = 0x00000008; +pub const SA_NOCLDWAIT: c_int = 0x00010000; + +pub const SIGEMT: c_int = 7; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = 22; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 22; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 0x1; +pub const SIG_UNBLOCK: c_int = 0x2; + +pub const POLLWRNORM: c_short = 0x004; +pub const POLLWRBAND: c_short = 0x100; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x00000100; +pub const TOSTOP: crate::tcflag_t = 0x00008000; +pub const FLUSHO: crate::tcflag_t = 0x00002000; +pub const EXTPROC: crate::tcflag_t = 0o200000; +pub const TCSANOW: c_int = 0x540e; +pub const TCSADRAIN: c_int = 0x540f; +pub const TCSAFLUSH: c_int = 0x5410; + +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; + +pub const MAP_HUGETLB: c_int = 0x080000; + +pub const EFD_NONBLOCK: c_int = 0x80; + +cfg_if! { + if #[cfg(gnu_file_offset_bits64)] { + pub const F_GETLK: c_int = 33; + } else { + pub const F_GETLK: c_int = 14; + } +} +pub const F_GETOWN: c_int = 23; +pub const F_SETOWN: c_int = 24; + +pub const SFD_NONBLOCK: c_int = 0x80; + +pub const RTLD_DEEPBIND: c_int = 0x10; +pub const RTLD_GLOBAL: c_int = 0x4; +pub const RTLD_NOLOAD: c_int = 0x8; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EHWPOISON: c_int = 168; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs new file mode 100644 index 00000000000000..d9aebbe0efda85 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs @@ -0,0 +1,491 @@ +//! 32-bit specific definitions for linux-like values + +use crate::prelude::*; +use crate::pthread_mutex_t; + +pub type clock_t = i32; + +pub type shmatt_t = c_ulong; +pub type msgqnum_t = c_ulong; +pub type msglen_t = c_ulong; +pub type nlink_t = u32; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; +pub type __fsword_t = i32; +pub type fsblkcnt64_t = u64; +pub type fsfilcnt64_t = u64; +pub type __syscall_ulong_t = c_ulong; +pub type __suseconds64_t = i64; + +cfg_if! { + if #[cfg(target_arch = "riscv32")] { + pub type time_t = i64; + pub type suseconds_t = i64; + type __ino_t = c_ulong; + type __ino64_t = u64; + pub type ino_t = __ino64_t; + pub type off_t = i64; + pub type blkcnt_t = i64; + pub type fsblkcnt_t = u64; + pub type fsfilcnt_t = u64; + pub type rlim_t = u64; + pub type blksize_t = i64; + } else if #[cfg(gnu_time_bits64)] { + pub type time_t = i64; + pub type suseconds_t = i32; + type __ino_t = c_ulong; + type __ino64_t = u64; + pub type ino_t = __ino64_t; + pub type off_t = i64; + pub type blkcnt_t = i64; + pub type fsblkcnt_t = u64; + pub type fsfilcnt_t = u64; + pub type rlim_t = u64; + pub type blksize_t = i32; + } else if #[cfg(gnu_file_offset_bits64)] { + pub type time_t = i32; + pub type suseconds_t = i32; + type __ino_t = c_ulong; + type __ino64_t = u64; + pub type ino_t = __ino64_t; + pub type off_t = i64; + pub type blkcnt_t = i64; + pub type fsblkcnt_t = u64; + pub type fsfilcnt_t = u64; + pub type rlim_t = u64; + pub type blksize_t = i32; + } else { + pub type time_t = i32; + pub type suseconds_t = i32; + type __ino_t = c_ulong; + type __ino64_t = u64; + pub type ino_t = __ino_t; + pub type off_t = i32; + pub type blkcnt_t = i32; + pub type fsblkcnt_t = c_ulong; + pub type fsfilcnt_t = c_ulong; + pub type rlim_t = c_ulong; + pub type blksize_t = i32; + } +} + +cfg_if! { + if #[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "powerpc", + target_arch = "sparc" + )))] { + s! { + pub struct stat { + pub st_dev: crate::dev_t, + + #[cfg(not(gnu_time_bits64))] + __pad1: Padding, + + #[cfg(any(gnu_time_bits64, not(gnu_file_offset_bits64)))] + pub st_ino: crate::ino_t, + #[cfg(all(not(gnu_time_bits64), gnu_file_offset_bits64))] + __st_ino: __ino_t, + + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + + pub st_rdev: crate::dev_t, + + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + + pub st_size: off_t, + + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + + #[cfg(not(gnu_file_offset_bits64))] + __glibc_reserved4: Padding, + #[cfg(not(gnu_file_offset_bits64))] + __glibc_reserved5: Padding, + #[cfg(all(not(gnu_time_bits64), gnu_file_offset_bits64))] + pub st_ino: crate::ino_t, + } + } + } +} + +s! { + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u32; 9], + } + + pub struct sigset_t { + __val: [c_ulong; 32], + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + #[deprecated( + since = "0.2.58", + note = "This padding field might become private in the future" + )] + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 8], + } + + pub struct semid_ds { + pub sem_perm: ipc_perm, + #[cfg(all(not(gnu_time_bits64), target_arch = "powerpc"))] + __reserved: Padding, + pub sem_otime: crate::time_t, + #[cfg(not(any( + gnu_time_bits64, + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "powerpc" + )))] + __reserved: Padding, + #[cfg(all(not(gnu_time_bits64), target_arch = "powerpc"))] + __reserved2: Padding, + pub sem_ctime: crate::time_t, + #[cfg(not(any( + gnu_time_bits64, + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "powerpc" + )))] + __reserved2: Padding, + pub sem_nsems: crate::__syscall_ulong_t, + #[cfg(all( + gnu_time_bits64, + not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "powerpc", + target_arch = "arm", + target_arch = "x86" + )) + ))] + __reserved2: Padding, + __glibc_reserved3: Padding, + __glibc_reserved4: Padding, + } + + #[cfg(gnu_time_bits64)] + pub struct timex { + pub modes: c_uint, + _pad1: Padding, + pub offset: c_longlong, + pub freq: c_longlong, + pub maxerror: c_longlong, + pub esterror: c_longlong, + pub status: c_int, + _pad2: Padding, + pub constant: c_longlong, + pub precision: c_longlong, + pub tolerance: c_longlong, + pub time: crate::timeval, + pub tick: c_longlong, + pub ppsfreq: c_longlong, + pub jitter: c_longlong, + pub shift: c_int, + _pad3: Padding, + pub stabil: c_longlong, + pub jitcnt: c_longlong, + pub calcnt: c_longlong, + pub errcnt: c_longlong, + pub stbcnt: c_longlong, + pub tai: c_int, + pub __unused1: i32, + pub __unused2: i32, + pub __unused3: i32, + pub __unused4: i32, + pub __unused5: i32, + pub __unused6: i32, + pub __unused7: i32, + pub __unused8: i32, + pub __unused9: i32, + pub __unused10: i32, + pub __unused11: i32, + } + + #[cfg(not(gnu_time_bits64))] + pub struct timex { + pub modes: c_uint, + pub offset: c_long, + pub freq: c_long, + pub maxerror: c_long, + pub esterror: c_long, + pub status: c_int, + pub constant: c_long, + pub precision: c_long, + pub tolerance: c_long, + pub time: crate::timeval, + pub tick: c_long, + pub ppsfreq: c_long, + pub jitter: c_long, + pub shift: c_int, + pub stabil: c_long, + pub jitcnt: c_long, + pub calcnt: c_long, + pub errcnt: c_long, + pub stbcnt: c_long, + pub tai: c_int, + pub __unused1: i32, + pub __unused2: i32, + pub __unused3: i32, + pub __unused4: i32, + pub __unused5: i32, + pub __unused6: i32, + pub __unused7: i32, + pub __unused8: i32, + pub __unused9: i32, + pub __unused10: i32, + pub __unused11: i32, + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +cfg_if! { + if #[cfg(target_arch = "sparc")] { + pub const O_NOATIME: c_int = 0x200000; + pub const O_PATH: c_int = 0x1000000; + pub const O_TMPFILE: c_int = 0x2000000 | O_DIRECTORY; + + pub const SA_ONSTACK: c_int = 1; + + pub const PTRACE_DETACH: c_uint = 11; + + pub const F_RDLCK: c_int = 1; + pub const F_WRLCK: c_int = 2; + pub const F_UNLCK: c_int = 3; + + pub const SFD_CLOEXEC: c_int = 0x400000; + + pub const NCCS: usize = 17; + + pub const O_TRUNC: c_int = 0x400; + pub const O_CLOEXEC: c_int = 0x400000; + + pub const EBFONT: c_int = 109; + pub const ENOSTR: c_int = 72; + pub const ENODATA: c_int = 111; + pub const ETIME: c_int = 73; + pub const ENOSR: c_int = 74; + pub const ENONET: c_int = 80; + pub const ENOPKG: c_int = 113; + pub const EREMOTE: c_int = 71; + pub const ENOLINK: c_int = 82; + pub const EADV: c_int = 83; + pub const ESRMNT: c_int = 84; + pub const ECOMM: c_int = 85; + pub const EPROTO: c_int = 86; + pub const EDOTDOT: c_int = 88; + + pub const SA_NODEFER: c_int = 0x20; + pub const SA_RESETHAND: c_int = 0x4; + pub const SA_RESTART: c_int = 0x2; + pub const SA_NOCLDSTOP: c_int = 0x00000008; + + pub const EPOLL_CLOEXEC: c_int = 0x400000; + + pub const EFD_CLOEXEC: c_int = 0x400000; + } else { + pub const O_NOATIME: c_int = 0o1000000; + pub const O_PATH: c_int = 0o10000000; + pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + + pub const SA_ONSTACK: c_int = 0x08000000; + + pub const PTRACE_DETACH: c_uint = 17; + + pub const F_RDLCK: c_int = 0; + pub const F_WRLCK: c_int = 1; + pub const F_UNLCK: c_int = 2; + + pub const SFD_CLOEXEC: c_int = 0x080000; + + pub const NCCS: usize = 32; + + pub const O_TRUNC: c_int = 512; + pub const O_CLOEXEC: c_int = 0x80000; + pub const EBFONT: c_int = 59; + pub const ENOSTR: c_int = 60; + pub const ENODATA: c_int = 61; + pub const ETIME: c_int = 62; + pub const ENOSR: c_int = 63; + pub const ENONET: c_int = 64; + pub const ENOPKG: c_int = 65; + pub const EREMOTE: c_int = 66; + pub const ENOLINK: c_int = 67; + pub const EADV: c_int = 68; + pub const ESRMNT: c_int = 69; + pub const ECOMM: c_int = 70; + pub const EPROTO: c_int = 71; + pub const EDOTDOT: c_int = 73; + + pub const SA_NODEFER: c_int = 0x40000000; + pub const SA_RESETHAND: c_int = 0x80000000; + pub const SA_RESTART: c_int = 0x10000000; + pub const SA_NOCLDSTOP: c_int = 0x00000001; + + pub const EPOLL_CLOEXEC: c_int = 0x80000; + + pub const EFD_CLOEXEC: c_int = 0x80000; + } +} +cfg_if! { + if #[cfg(target_arch = "sparc")] { + pub const F_SETLK: c_int = 8; + pub const F_SETLKW: c_int = 9; + } else if #[cfg(all( + gnu_file_offset_bits64, + any(target_arch = "mips", target_arch = "mips32r6") + ))] { + pub const F_SETLK: c_int = 34; + pub const F_SETLKW: c_int = 35; + } else if #[cfg(gnu_file_offset_bits64)] { + pub const F_SETLK: c_int = 13; + pub const F_SETLKW: c_int = 14; + } else { + pub const F_SETLK: c_int = 6; + pub const F_SETLKW: c_int = 7; + } +} + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const PTRACE_GETFPREGS: c_uint = 14; +pub const PTRACE_SETFPREGS: c_uint = 15; +pub const PTRACE_GETREGS: c_uint = 12; +pub const PTRACE_SETREGS: c_uint = 13; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(target_arch = "m68k")] { + mod m68k; + pub use self::m68k::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "sparc")] { + mod sparc; + pub use self::sparc::*; + } else if #[cfg(target_arch = "riscv32")] { + mod riscv32; + pub use self::riscv32::*; + } else if #[cfg(target_arch = "csky")] { + mod csky; + pub use self::csky::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/powerpc.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/powerpc.rs new file mode 100644 index 00000000000000..b5d3631a6fcf24 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/powerpc.rs @@ -0,0 +1,895 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + f_spare: [crate::__fsword_t; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct ipc_perm { + __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + __seq: u32, + __pad1: Padding, + __glibc_reserved1: Padding, + __glibc_reserved2: Padding, + } + + pub struct stat { + pub st_dev: crate::dev_t, + #[cfg(not(gnu_file_offset_bits64))] + __pad1: Padding, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + pub st_ctime_nsec: c_long, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved4: Padding, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved5: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + pub st_ctime_nsec: c_long, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved4: Padding, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved5: Padding, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + #[cfg(gnu_time_bits64)] + pub shm_segsz: size_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved1: Padding, + pub shm_atime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved2: Padding, + pub shm_dtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved3: Padding, + pub shm_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved4: Padding, + #[cfg(not(gnu_time_bits64))] + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __glibc_reserved5: Padding, + __glibc_reserved6: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved1: Padding, + pub msg_stime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved2: Padding, + pub msg_rtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved3: Padding, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_DIRECT: c_int = 0x20000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_LARGEFILE: c_int = 0o200000; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_LOCKED: c_int = 0x00080; +pub const MAP_NORESERVE: c_int = 0x00040; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 58; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +cfg_if! { + if #[cfg(gnu_file_offset_bits64)] { + pub const F_GETLK: c_int = 12; + } else { + pub const F_GETLK: c_int = 5; + } +} +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; + +pub const EFD_NONBLOCK: c_int = 0x800; +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGSTKSZ: size_t = 0x4000; +pub const MINSIGSTKSZ: size_t = 4096; +pub const CBAUD: crate::tcflag_t = 0xff; +pub const TAB1: crate::tcflag_t = 0x400; +pub const TAB2: crate::tcflag_t = 0x800; +pub const TAB3: crate::tcflag_t = 0xc00; +pub const CR1: crate::tcflag_t = 0x1000; +pub const CR2: crate::tcflag_t = 0x2000; +pub const CR3: crate::tcflag_t = 0x3000; +pub const FF1: crate::tcflag_t = 0x4000; +pub const BS1: crate::tcflag_t = 0x8000; +pub const VT1: crate::tcflag_t = 0x10000; +pub const VWERASE: usize = 0xa; +pub const VREPRINT: usize = 0xb; +pub const VSUSP: usize = 0xc; +pub const VSTART: usize = 0xd; +pub const VSTOP: usize = 0xe; +pub const VDISCARD: usize = 0x10; +pub const VTIME: usize = 0x7; +pub const IXON: crate::tcflag_t = 0x200; +pub const IXOFF: crate::tcflag_t = 0x400; +pub const ONLCR: crate::tcflag_t = 0x2; +pub const CSIZE: crate::tcflag_t = 0x300; +pub const CS6: crate::tcflag_t = 0x100; +pub const CS7: crate::tcflag_t = 0x200; +pub const CS8: crate::tcflag_t = 0x300; +pub const CSTOPB: crate::tcflag_t = 0x400; +pub const CREAD: crate::tcflag_t = 0x800; +pub const PARENB: crate::tcflag_t = 0x1000; +pub const PARODD: crate::tcflag_t = 0x2000; +pub const HUPCL: crate::tcflag_t = 0x4000; +pub const CLOCAL: crate::tcflag_t = 0x8000; +pub const ECHOKE: crate::tcflag_t = 0x1; +pub const ECHOE: crate::tcflag_t = 0x2; +pub const ECHOK: crate::tcflag_t = 0x4; +pub const ECHONL: crate::tcflag_t = 0x10; +pub const ECHOPRT: crate::tcflag_t = 0x20; +pub const ECHOCTL: crate::tcflag_t = 0x40; +pub const ISIG: crate::tcflag_t = 0x80; +pub const ICANON: crate::tcflag_t = 0x100; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x80000000; +pub const VSWTC: usize = 9; +pub const OLCUC: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o001400; +pub const CRDLY: crate::tcflag_t = 0o030000; +pub const TABDLY: crate::tcflag_t = 0o006000; +pub const BSDLY: crate::tcflag_t = 0o100000; +pub const FFDLY: crate::tcflag_t = 0o040000; +pub const VTDLY: crate::tcflag_t = 0o200000; +pub const XTABS: crate::tcflag_t = 0o006000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const CBAUDEX: crate::speed_t = 0o000020; +pub const B57600: crate::speed_t = 0o0020; +pub const B115200: crate::speed_t = 0o0021; +pub const B230400: crate::speed_t = 0o0022; +pub const B460800: crate::speed_t = 0o0023; +pub const B500000: crate::speed_t = 0o0024; +pub const B576000: crate::speed_t = 0o0025; +pub const B921600: crate::speed_t = 0o0026; +pub const B1000000: crate::speed_t = 0o0027; +pub const B1152000: crate::speed_t = 0o0030; +pub const B1500000: crate::speed_t = 0o0031; +pub const B2000000: crate::speed_t = 0o0032; +pub const B2500000: crate::speed_t = 0o0033; +pub const B3000000: crate::speed_t = 0o0034; +pub const B3500000: crate::speed_t = 0o0035; +pub const B4000000: crate::speed_t = 0o0036; + +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: crate::tcflag_t = 0x400; +pub const TOSTOP: crate::tcflag_t = 0x400000; +pub const FLUSHO: crate::tcflag_t = 0x800000; +pub const EXTPROC: crate::tcflag_t = 0x10000000; + +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 166; +pub const SYS_poll: c_long = 167; +pub const SYS_nfsservctl: c_long = 168; +pub const SYS_setresgid: c_long = 169; +pub const SYS_getresgid: c_long = 170; +pub const SYS_prctl: c_long = 171; +pub const SYS_rt_sigreturn: c_long = 172; +pub const SYS_rt_sigaction: c_long = 173; +pub const SYS_rt_sigprocmask: c_long = 174; +pub const SYS_rt_sigpending: c_long = 175; +pub const SYS_rt_sigtimedwait: c_long = 176; +pub const SYS_rt_sigqueueinfo: c_long = 177; +pub const SYS_rt_sigsuspend: c_long = 178; +pub const SYS_pread64: c_long = 179; +pub const SYS_pwrite64: c_long = 180; +pub const SYS_chown: c_long = 181; +pub const SYS_getcwd: c_long = 182; +pub const SYS_capget: c_long = 183; +pub const SYS_capset: c_long = 184; +pub const SYS_sigaltstack: c_long = 185; +pub const SYS_sendfile: c_long = 186; +pub const SYS_getpmsg: c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: c_long = 189; +pub const SYS_ugetrlimit: c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_pciconfig_read: c_long = 198; +pub const SYS_pciconfig_write: c_long = 199; +pub const SYS_pciconfig_iobase: c_long = 200; +pub const SYS_multiplexer: c_long = 201; +pub const SYS_getdents64: c_long = 202; +pub const SYS_pivot_root: c_long = 203; +pub const SYS_fcntl64: c_long = 204; +pub const SYS_madvise: c_long = 205; +pub const SYS_mincore: c_long = 206; +pub const SYS_gettid: c_long = 207; +pub const SYS_tkill: c_long = 208; +pub const SYS_setxattr: c_long = 209; +pub const SYS_lsetxattr: c_long = 210; +pub const SYS_fsetxattr: c_long = 211; +pub const SYS_getxattr: c_long = 212; +pub const SYS_lgetxattr: c_long = 213; +pub const SYS_fgetxattr: c_long = 214; +pub const SYS_listxattr: c_long = 215; +pub const SYS_llistxattr: c_long = 216; +pub const SYS_flistxattr: c_long = 217; +pub const SYS_removexattr: c_long = 218; +pub const SYS_lremovexattr: c_long = 219; +pub const SYS_fremovexattr: c_long = 220; +pub const SYS_futex: c_long = 221; +pub const SYS_sched_setaffinity: c_long = 222; +pub const SYS_sched_getaffinity: c_long = 223; +pub const SYS_tuxcall: c_long = 225; +pub const SYS_sendfile64: c_long = 226; +pub const SYS_io_setup: c_long = 227; +pub const SYS_io_destroy: c_long = 228; +pub const SYS_io_getevents: c_long = 229; +pub const SYS_io_submit: c_long = 230; +pub const SYS_io_cancel: c_long = 231; +pub const SYS_set_tid_address: c_long = 232; +pub const SYS_fadvise64: c_long = 233; +pub const SYS_exit_group: c_long = 234; +pub const SYS_lookup_dcookie: c_long = 235; +pub const SYS_epoll_create: c_long = 236; +pub const SYS_epoll_ctl: c_long = 237; +pub const SYS_epoll_wait: c_long = 238; +pub const SYS_remap_file_pages: c_long = 239; +pub const SYS_timer_create: c_long = 240; +pub const SYS_timer_settime: c_long = 241; +pub const SYS_timer_gettime: c_long = 242; +pub const SYS_timer_getoverrun: c_long = 243; +pub const SYS_timer_delete: c_long = 244; +pub const SYS_clock_settime: c_long = 245; +pub const SYS_clock_gettime: c_long = 246; +pub const SYS_clock_getres: c_long = 247; +pub const SYS_clock_nanosleep: c_long = 248; +pub const SYS_swapcontext: c_long = 249; +pub const SYS_tgkill: c_long = 250; +pub const SYS_utimes: c_long = 251; +pub const SYS_statfs64: c_long = 252; +pub const SYS_fstatfs64: c_long = 253; +pub const SYS_fadvise64_64: c_long = 254; +pub const SYS_rtas: c_long = 255; +pub const SYS_sys_debug_setcontext: c_long = 256; +pub const SYS_migrate_pages: c_long = 258; +pub const SYS_mbind: c_long = 259; +pub const SYS_get_mempolicy: c_long = 260; +pub const SYS_set_mempolicy: c_long = 261; +pub const SYS_mq_open: c_long = 262; +pub const SYS_mq_unlink: c_long = 263; +pub const SYS_mq_timedsend: c_long = 264; +pub const SYS_mq_timedreceive: c_long = 265; +pub const SYS_mq_notify: c_long = 266; +pub const SYS_mq_getsetattr: c_long = 267; +pub const SYS_kexec_load: c_long = 268; +pub const SYS_add_key: c_long = 269; +pub const SYS_request_key: c_long = 270; +pub const SYS_keyctl: c_long = 271; +pub const SYS_waitid: c_long = 272; +pub const SYS_ioprio_set: c_long = 273; +pub const SYS_ioprio_get: c_long = 274; +pub const SYS_inotify_init: c_long = 275; +pub const SYS_inotify_add_watch: c_long = 276; +pub const SYS_inotify_rm_watch: c_long = 277; +pub const SYS_spu_run: c_long = 278; +pub const SYS_spu_create: c_long = 279; +pub const SYS_pselect6: c_long = 280; +pub const SYS_ppoll: c_long = 281; +pub const SYS_unshare: c_long = 282; +pub const SYS_splice: c_long = 283; +pub const SYS_tee: c_long = 284; +pub const SYS_vmsplice: c_long = 285; +pub const SYS_openat: c_long = 286; +pub const SYS_mkdirat: c_long = 287; +pub const SYS_mknodat: c_long = 288; +pub const SYS_fchownat: c_long = 289; +pub const SYS_futimesat: c_long = 290; +pub const SYS_fstatat64: c_long = 291; +pub const SYS_unlinkat: c_long = 292; +pub const SYS_renameat: c_long = 293; +pub const SYS_linkat: c_long = 294; +pub const SYS_symlinkat: c_long = 295; +pub const SYS_readlinkat: c_long = 296; +pub const SYS_fchmodat: c_long = 297; +pub const SYS_faccessat: c_long = 298; +pub const SYS_get_robust_list: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_move_pages: c_long = 301; +pub const SYS_getcpu: c_long = 302; +pub const SYS_epoll_pwait: c_long = 303; +pub const SYS_utimensat: c_long = 304; +pub const SYS_signalfd: c_long = 305; +pub const SYS_timerfd_create: c_long = 306; +pub const SYS_eventfd: c_long = 307; +pub const SYS_sync_file_range2: c_long = 308; +pub const SYS_fallocate: c_long = 309; +pub const SYS_subpage_prot: c_long = 310; +pub const SYS_timerfd_settime: c_long = 311; +pub const SYS_timerfd_gettime: c_long = 312; +pub const SYS_signalfd4: c_long = 313; +pub const SYS_eventfd2: c_long = 314; +pub const SYS_epoll_create1: c_long = 315; +pub const SYS_dup3: c_long = 316; +pub const SYS_pipe2: c_long = 317; +pub const SYS_inotify_init1: c_long = 318; +pub const SYS_perf_event_open: c_long = 319; +pub const SYS_preadv: c_long = 320; +pub const SYS_pwritev: c_long = 321; +pub const SYS_rt_tgsigqueueinfo: c_long = 322; +pub const SYS_fanotify_init: c_long = 323; +pub const SYS_fanotify_mark: c_long = 324; +pub const SYS_prlimit64: c_long = 325; +pub const SYS_socket: c_long = 326; +pub const SYS_bind: c_long = 327; +pub const SYS_connect: c_long = 328; +pub const SYS_listen: c_long = 329; +pub const SYS_accept: c_long = 330; +pub const SYS_getsockname: c_long = 331; +pub const SYS_getpeername: c_long = 332; +pub const SYS_socketpair: c_long = 333; +pub const SYS_send: c_long = 334; +pub const SYS_sendto: c_long = 335; +pub const SYS_recv: c_long = 336; +pub const SYS_recvfrom: c_long = 337; +pub const SYS_shutdown: c_long = 338; +pub const SYS_setsockopt: c_long = 339; +pub const SYS_getsockopt: c_long = 340; +pub const SYS_sendmsg: c_long = 341; +pub const SYS_recvmsg: c_long = 342; +pub const SYS_recvmmsg: c_long = 343; +pub const SYS_accept4: c_long = 344; +pub const SYS_name_to_handle_at: c_long = 345; +pub const SYS_open_by_handle_at: c_long = 346; +pub const SYS_clock_adjtime: c_long = 347; +pub const SYS_syncfs: c_long = 348; +pub const SYS_sendmmsg: c_long = 349; +pub const SYS_setns: c_long = 350; +pub const SYS_process_vm_readv: c_long = 351; +pub const SYS_process_vm_writev: c_long = 352; +pub const SYS_finit_module: c_long = 353; +pub const SYS_kcmp: c_long = 354; +pub const SYS_sched_setattr: c_long = 355; +pub const SYS_sched_getattr: c_long = 356; +pub const SYS_renameat2: c_long = 357; +pub const SYS_seccomp: c_long = 358; +pub const SYS_getrandom: c_long = 359; +pub const SYS_memfd_create: c_long = 360; +pub const SYS_bpf: c_long = 361; +pub const SYS_execveat: c_long = 362; +pub const SYS_switch_endian: c_long = 363; +pub const SYS_userfaultfd: c_long = 364; +pub const SYS_membarrier: c_long = 365; +pub const SYS_mlock2: c_long = 378; +pub const SYS_copy_file_range: c_long = 379; +pub const SYS_preadv2: c_long = 380; +pub const SYS_pwritev2: c_long = 381; +pub const SYS_kexec_file_load: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_rseq: c_long = 387; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs new file mode 100644 index 00000000000000..5484a68bd1ec18 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs @@ -0,0 +1,811 @@ +//! RISC-V-specific definitions for 32-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = c_int; + +s! { + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub __pad1: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub __pad2: c_int, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_frsize: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 4], + } + + pub struct statfs64 { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_frsize: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_favail: crate::fsfilcnt64_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub __f_spare: [c_int; 6], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [u64; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused5: Padding, + __unused6: Padding, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct user_regs_struct { + pub pc: c_ulong, + pub ra: c_ulong, + pub sp: c_ulong, + pub gp: c_ulong, + pub tp: c_ulong, + pub t0: c_ulong, + pub t1: c_ulong, + pub t2: c_ulong, + pub s0: c_ulong, + pub s1: c_ulong, + pub a0: c_ulong, + pub a1: c_ulong, + pub a2: c_ulong, + pub a3: c_ulong, + pub a4: c_ulong, + pub a5: c_ulong, + pub a6: c_ulong, + pub a7: c_ulong, + pub s2: c_ulong, + pub s3: c_ulong, + pub s4: c_ulong, + pub s5: c_ulong, + pub s6: c_ulong, + pub s7: c_ulong, + pub s8: c_ulong, + pub s9: c_ulong, + pub s10: c_ulong, + pub s11: c_ulong, + pub t3: c_ulong, + pub t4: c_ulong, + pub t5: c_ulong, + pub t6: c_ulong, + } +} + +s_no_extra_traits! { + pub struct ucontext_t { + pub __uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub __gregs: [c_ulong; 32], + pub __fpregs: __riscv_mc_fp_state, + } + + pub union __riscv_mc_fp_state { + pub __f: __riscv_mc_f_ext_state, + pub __d: __riscv_mc_d_ext_state, + pub __q: __riscv_mc_q_ext_state, + } + + pub struct __riscv_mc_f_ext_state { + pub __f: [c_uint; 32], + pub __fcsr: c_uint, + } + + pub struct __riscv_mc_d_ext_state { + pub __f: [c_ulonglong; 32], + pub __fcsr: c_uint, + } + + #[repr(align(16))] + pub struct __riscv_mc_q_ext_state { + pub __f: [c_ulonglong; 64], + pub __fcsr: c_uint, + pub __glibc_reserved: [c_uint; 3], + } +} + +pub const O_LARGEFILE: c_int = 0; +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 1052672; +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 256; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SA_SIGINFO: c_int = 4; +pub const SA_NOCLDWAIT: c_int = 2; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const POLLWRNORM: c_short = 256; +pub const POLLWRBAND: c_short = 512; +pub const O_ASYNC: c_int = 8192; +pub const O_NDELAY: c_int = 2048; +pub const EFD_NONBLOCK: c_int = 2048; +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const SFD_NONBLOCK: c_int = 2048; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const O_DIRECT: c_int = 16384; +pub const O_DIRECTORY: c_int = 65536; +pub const O_NOFOLLOW: c_int = 131072; +pub const MAP_HUGETLB: c_int = 262144; +pub const MAP_LOCKED: c_int = 8192; +pub const MAP_NORESERVE: c_int = 16384; +pub const MAP_ANON: c_int = 32; +pub const MAP_ANONYMOUS: c_int = 32; +pub const MAP_DENYWRITE: c_int = 2048; +pub const MAP_EXECUTABLE: c_int = 4096; +pub const MAP_POPULATE: c_int = 32768; +pub const MAP_NONBLOCK: c_int = 65536; +pub const MAP_STACK: c_int = 131072; +pub const MAP_SYNC: c_int = 0x080000; +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const MCL_CURRENT: c_int = 1; +pub const MCL_FUTURE: c_int = 2; +pub const MCL_ONFAULT: c_int = 4; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 4111; +pub const TAB1: crate::tcflag_t = 2048; +pub const TAB2: crate::tcflag_t = 4096; +pub const TAB3: crate::tcflag_t = 6144; +pub const CR1: crate::tcflag_t = 512; +pub const CR2: crate::tcflag_t = 1024; +pub const CR3: crate::tcflag_t = 1536; +pub const FF1: crate::tcflag_t = 32768; +pub const BS1: crate::tcflag_t = 8192; +pub const VT1: crate::tcflag_t = 16384; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 1024; +pub const IXOFF: crate::tcflag_t = 4096; +pub const ONLCR: crate::tcflag_t = 4; +pub const CSIZE: crate::tcflag_t = 48; +pub const CS6: crate::tcflag_t = 16; +pub const CS7: crate::tcflag_t = 32; +pub const CS8: crate::tcflag_t = 48; +pub const CSTOPB: crate::tcflag_t = 64; +pub const CREAD: crate::tcflag_t = 128; +pub const PARENB: crate::tcflag_t = 256; +pub const PARODD: crate::tcflag_t = 512; +pub const HUPCL: crate::tcflag_t = 1024; +pub const CLOCAL: crate::tcflag_t = 2048; +pub const ECHOKE: crate::tcflag_t = 2048; +pub const ECHOE: crate::tcflag_t = 16; +pub const ECHOK: crate::tcflag_t = 32; +pub const ECHONL: crate::tcflag_t = 64; +pub const ECHOPRT: crate::tcflag_t = 1024; +pub const ECHOCTL: crate::tcflag_t = 512; +pub const ISIG: crate::tcflag_t = 1; +pub const ICANON: crate::tcflag_t = 2; +pub const PENDIN: crate::tcflag_t = 16384; +pub const NOFLSH: crate::tcflag_t = 128; +pub const CIBAUD: crate::tcflag_t = 269418496; +pub const CBAUDEX: crate::tcflag_t = 4096; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 2; +pub const NLDLY: crate::tcflag_t = 256; +pub const CRDLY: crate::tcflag_t = 1536; +pub const TABDLY: crate::tcflag_t = 6144; +pub const BSDLY: crate::tcflag_t = 8192; +pub const FFDLY: crate::tcflag_t = 32768; +pub const VTDLY: crate::tcflag_t = 16384; +pub const XTABS: crate::tcflag_t = 6144; +pub const B0: crate::speed_t = 0; +pub const B50: crate::speed_t = 1; +pub const B75: crate::speed_t = 2; +pub const B110: crate::speed_t = 3; +pub const B134: crate::speed_t = 4; +pub const B150: crate::speed_t = 5; +pub const B200: crate::speed_t = 6; +pub const B300: crate::speed_t = 7; +pub const B600: crate::speed_t = 8; +pub const B1200: crate::speed_t = 9; +pub const B1800: crate::speed_t = 10; +pub const B2400: crate::speed_t = 11; +pub const B4800: crate::speed_t = 12; +pub const B9600: crate::speed_t = 13; +pub const B19200: crate::speed_t = 14; +pub const B38400: crate::speed_t = 15; +pub const EXTA: crate::speed_t = 14; +pub const EXTB: crate::speed_t = 15; +pub const B57600: crate::speed_t = 4097; +pub const B115200: crate::speed_t = 4098; +pub const B230400: crate::speed_t = 4099; +pub const B460800: crate::speed_t = 4100; +pub const B500000: crate::speed_t = 4101; +pub const B576000: crate::speed_t = 4102; +pub const B921600: crate::speed_t = 4103; +pub const B1000000: crate::speed_t = 4104; +pub const B1152000: crate::speed_t = 4105; +pub const B1500000: crate::speed_t = 4106; +pub const B2000000: crate::speed_t = 4107; +pub const B2500000: crate::speed_t = 4108; +pub const B3000000: crate::speed_t = 4109; +pub const B3500000: crate::speed_t = 4110; +pub const B4000000: crate::speed_t = 4111; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 32768; +pub const TOSTOP: crate::tcflag_t = 256; +pub const FLUSHO: crate::tcflag_t = 4096; +pub const EXTPROC: crate::tcflag_t = 65536; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const NGREG: usize = 32; +pub const REG_PC: usize = 0; +pub const REG_RA: usize = 1; +pub const REG_SP: usize = 2; +pub const REG_TP: usize = 4; +pub const REG_S0: usize = 8; +pub const REG_S1: usize = 9; +pub const REG_A0: usize = 10; +pub const REG_S2: usize = 18; +pub const REG_NARGS: usize = 8; + +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_close: c_long = 57; +pub const SYS_fstat: c_long = 80; +pub const SYS_lseek: c_long = 62; +pub const SYS_mmap: c_long = 222; +pub const SYS_mprotect: c_long = 226; +pub const SYS_munmap: c_long = 215; +pub const SYS_brk: c_long = 214; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_ioctl: c_long = 29; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_mremap: c_long = 216; +pub const SYS_msync: c_long = 227; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmctl: c_long = 195; +pub const SYS_dup: c_long = 23; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_getpid: c_long = 172; +pub const SYS_sendfile: c_long = 71; +pub const SYS_socket: c_long = 198; +pub const SYS_connect: c_long = 203; +pub const SYS_accept: c_long = 202; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_shutdown: c_long = 210; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_socketpair: c_long = 199; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_exit: c_long = 93; +pub const SYS_wait4: c_long = 260; +pub const SYS_kill: c_long = 129; +pub const SYS_uname: c_long = 160; +pub const SYS_semget: c_long = 190; +pub const SYS_semop: c_long = 193; +pub const SYS_semctl: c_long = 191; +pub const SYS_shmdt: c_long = 197; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgctl: c_long = 187; +pub const SYS_fcntl: c_long = 25; +pub const SYS_flock: c_long = 32; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_getcwd: c_long = 17; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchown: c_long = 55; +pub const SYS_umask: c_long = 166; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_getrusage: c_long = 165; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_times: c_long = 153; +pub const SYS_ptrace: c_long = 117; +pub const SYS_getuid: c_long = 174; +pub const SYS_syslog: c_long = 116; +pub const SYS_getgid: c_long = 176; +pub const SYS_setuid: c_long = 146; +pub const SYS_setgid: c_long = 144; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getegid: c_long = 177; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getppid: c_long = 173; +pub const SYS_setsid: c_long = 157; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setregid: c_long = 143; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_getpgid: c_long = 155; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_getsid: c_long = 156; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_personality: c_long = 92; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_getpriority: c_long = 141; +pub const SYS_setpriority: c_long = 140; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_prctl: c_long = 167; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_chroot: c_long = 51; +pub const SYS_sync: c_long = 81; +pub const SYS_acct: c_long = 89; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_mount: c_long = 40; +pub const SYS_umount2: c_long = 39; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_reboot: c_long = 142; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_quotactl: c_long = 60; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_gettid: c_long = 178; +pub const SYS_readahead: c_long = 213; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_tkill: c_long = 130; +pub const SYS_futex: c_long = 98; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_getdents64: c_long = 61; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_exit_group: c_long = 94; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_tgkill: c_long = 131; +pub const SYS_mbind: c_long = 235; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_waitid: c_long = 95; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_openat: c_long = 56; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_mknodat: c_long = 33; +pub const SYS_fchownat: c_long = 54; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_linkat: c_long = 37; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_faccessat: c_long = 48; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_unshare: c_long = 97; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_move_pages: c_long = 239; +pub const SYS_utimensat: c_long = 88; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_fallocate: c_long = 47; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_accept4: c_long = 242; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_dup3: c_long = 24; +pub const SYS_pipe2: c_long = 59; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_setns: c_long = 268; +pub const SYS_getcpu: c_long = 168; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_rseq: c_long = 293; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs new file mode 100644 index 00000000000000..75fefcd9401a8b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs @@ -0,0 +1,868 @@ +//! SPARC-specific definitions for 32-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + f_spare: [crate::__fsword_t; 4], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + _pad: Padding<[c_int; 29]>, + _align: [usize; 0], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + __reserved: Padding, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + #[cfg(not(gnu_file_offset_bits64))] + __pad1: Padding, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + __pad1: Padding, + pub mode: c_ushort, + __pad2: Padding, + pub __seq: c_ushort, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + #[cfg(gnu_time_bits64)] + pub shm_segsz: size_t, + #[cfg(not(gnu_time_bits64))] + __pad1: Padding, + pub shm_atime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub shm_dtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __pad3: Padding, + pub shm_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __reserved1: Padding, + __reserved2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + #[cfg(not(gnu_time_bits64))] + __pad1: Padding, + pub msg_stime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub msg_rtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __pad3: Padding, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [i64; 3], + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const O_APPEND: c_int = 0x8; +pub const O_CREAT: c_int = 0x200; +pub const O_EXCL: c_int = 0x800; +pub const O_NOCTTY: c_int = 0x8000; +pub const O_NONBLOCK: c_int = 0x4000; +pub const O_SYNC: c_int = 0x802000; +pub const O_RSYNC: c_int = 0x802000; +pub const O_DSYNC: c_int = 0x2000; +pub const O_FSYNC: c_int = 0x802000; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0200; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLK: c_int = 78; +pub const ENAMETOOLONG: c_int = 63; +pub const ENOLCK: c_int = 79; +pub const ENOSYS: c_int = 90; +pub const ENOTEMPTY: c_int = 66; +pub const ELOOP: c_int = 62; +pub const ENOMSG: c_int = 75; +pub const EIDRM: c_int = 77; +pub const ECHRNG: c_int = 94; +pub const EL2NSYNC: c_int = 95; +pub const EL3HLT: c_int = 96; +pub const EL3RST: c_int = 97; +pub const ELNRNG: c_int = 98; +pub const EUNATCH: c_int = 99; +pub const ENOCSI: c_int = 100; +pub const EL2HLT: c_int = 101; +pub const EBADE: c_int = 102; +pub const EBADR: c_int = 103; +pub const EXFULL: c_int = 104; +pub const ENOANO: c_int = 105; +pub const EBADRQC: c_int = 106; +pub const EBADSLT: c_int = 107; +pub const EMULTIHOP: c_int = 87; +pub const EOVERFLOW: c_int = 92; +pub const ENOTUNIQ: c_int = 115; +pub const EBADFD: c_int = 93; +pub const EBADMSG: c_int = 76; +pub const EREMCHG: c_int = 89; +pub const ELIBACC: c_int = 114; +pub const ELIBBAD: c_int = 112; +pub const ELIBSCN: c_int = 124; +pub const ELIBMAX: c_int = 123; +pub const ELIBEXEC: c_int = 110; +pub const EILSEQ: c_int = 122; +pub const ERESTART: c_int = 116; +pub const ESTRPIPE: c_int = 91; +pub const EUSERS: c_int = 68; +pub const ENOTSOCK: c_int = 38; +pub const EDESTADDRREQ: c_int = 39; +pub const EMSGSIZE: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const EOPNOTSUPP: c_int = 45; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENETDOWN: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const EHOSTDOWN: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const EALREADY: c_int = 37; +pub const EINPROGRESS: c_int = 36; +pub const ESTALE: c_int = 70; +pub const EDQUOT: c_int = 69; +pub const ENOMEDIUM: c_int = 125; +pub const EMEDIUMTYPE: c_int = 126; +pub const ECANCELED: c_int = 127; +pub const ENOKEY: c_int = 128; +pub const EKEYEXPIRED: c_int = 129; +pub const EKEYREVOKED: c_int = 130; +pub const EKEYREJECTED: c_int = 131; +pub const EOWNERDEAD: c_int = 132; +pub const ENOTRECOVERABLE: c_int = 133; +pub const EHWPOISON: c_int = 135; +pub const ERFKILL: c_int = 134; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SA_SIGINFO: c_int = 0x200; +pub const SA_NOCLDWAIT: c_int = 0x100; + +pub const SIGEMT: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 20; +pub const SIGBUS: c_int = 10; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGCONT: c_int = 19; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGURG: c_int = 16; +pub const SIGIO: c_int = 23; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 23; +pub const SIGPWR: c_int = 29; +pub const SIG_SETMASK: c_int = 4; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; + +pub const POLLWRNORM: c_short = 4; +pub const POLLWRBAND: c_short = 0x100; + +pub const O_ASYNC: c_int = 0x40; +pub const O_NDELAY: c_int = 0x4004; + +pub const EFD_NONBLOCK: c_int = 0x4000; + +pub const F_GETLK: c_int = 7; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; + +pub const SFD_NONBLOCK: c_int = 0x4000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_NOFOLLOW: c_int = 0o400000; +pub const O_LARGEFILE: c_int = 0x40000; +pub const O_DIRECT: c_int = 0x100000; + +pub const MAP_LOCKED: c_int = 0x0100; +pub const MAP_NORESERVE: c_int = 0x00040; + +pub const EDEADLOCK: c_int = 108; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; + +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 4096; +pub const CBAUD: crate::tcflag_t = 0x0000100f; +pub const TAB1: crate::tcflag_t = 0x800; +pub const TAB2: crate::tcflag_t = 0x1000; +pub const TAB3: crate::tcflag_t = 0x1800; +pub const CR1: crate::tcflag_t = 0x200; +pub const CR2: crate::tcflag_t = 0x400; +pub const CR3: crate::tcflag_t = 0x600; +pub const FF1: crate::tcflag_t = 0x8000; +pub const BS1: crate::tcflag_t = 0x2000; +pub const VT1: crate::tcflag_t = 0x4000; +pub const VWERASE: usize = 0xe; +pub const VREPRINT: usize = 0xc; +pub const VSUSP: usize = 0xa; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VDISCARD: usize = 0xd; +pub const VTIME: usize = 0x5; +pub const IXON: crate::tcflag_t = 0x400; +pub const IXOFF: crate::tcflag_t = 0x1000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x30; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x40; +pub const CREAD: crate::tcflag_t = 0x80; +pub const PARENB: crate::tcflag_t = 0x100; +pub const PARODD: crate::tcflag_t = 0x200; +pub const HUPCL: crate::tcflag_t = 0x400; +pub const CLOCAL: crate::tcflag_t = 0x800; +pub const ECHOKE: crate::tcflag_t = 0x800; +pub const ECHOE: crate::tcflag_t = 0x10; +pub const ECHOK: crate::tcflag_t = 0x20; +pub const ECHONL: crate::tcflag_t = 0x40; +pub const ECHOPRT: crate::tcflag_t = 0x400; +pub const ECHOCTL: crate::tcflag_t = 0x200; +pub const ISIG: crate::tcflag_t = 0x1; +pub const ICANON: crate::tcflag_t = 0x2; +pub const PENDIN: crate::tcflag_t = 0x4000; +pub const NOFLSH: crate::tcflag_t = 0x80; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0x00001000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0x1001; +pub const B115200: crate::speed_t = 0x1002; +pub const B230400: crate::speed_t = 0x1003; +pub const B460800: crate::speed_t = 0x1004; +pub const B76800: crate::speed_t = 0x1005; +pub const B153600: crate::speed_t = 0x1006; +pub const B307200: crate::speed_t = 0x1007; +pub const B614400: crate::speed_t = 0x1008; +pub const B921600: crate::speed_t = 0x1009; +pub const B500000: crate::speed_t = 0x100a; +pub const B576000: crate::speed_t = 0x100b; +pub const B1000000: crate::speed_t = 0x100c; +pub const B1152000: crate::speed_t = 0x100d; +pub const B1500000: crate::speed_t = 0x100e; +pub const B2000000: crate::speed_t = 0x100f; + +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x8000; +pub const TOSTOP: crate::tcflag_t = 0x100; +pub const FLUSHO: crate::tcflag_t = 0x1000; +pub const EXTPROC: crate::tcflag_t = 0x10000; + +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_wait4: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execv: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_chown: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_brk: c_long = 17; +pub const SYS_perfctr: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_capget: c_long = 21; +pub const SYS_capset: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_vmsplice: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_sigaltstack: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_lchown32: c_long = 31; +pub const SYS_fchown32: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_chown32: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_stat: c_long = 38; +pub const SYS_sendfile: c_long = 39; +pub const SYS_lstat: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_getuid32: c_long = 44; +pub const SYS_umount2: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_getgid32: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_reboot: c_long = 55; +pub const SYS_mmap2: c_long = 56; +pub const SYS_symlink: c_long = 57; +pub const SYS_readlink: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_fstat: c_long = 62; +pub const SYS_fstat64: c_long = 63; +pub const SYS_getpagesize: c_long = 64; +pub const SYS_msync: c_long = 65; +pub const SYS_vfork: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_geteuid32: c_long = 69; +pub const SYS_getegid32: c_long = 70; +pub const SYS_mmap: c_long = 71; +pub const SYS_setreuid32: c_long = 72; +pub const SYS_munmap: c_long = 73; +pub const SYS_mprotect: c_long = 74; +pub const SYS_madvise: c_long = 75; +pub const SYS_vhangup: c_long = 76; +pub const SYS_truncate64: c_long = 77; +pub const SYS_mincore: c_long = 78; +pub const SYS_getgroups: c_long = 79; +pub const SYS_setgroups: c_long = 80; +pub const SYS_getpgrp: c_long = 81; +pub const SYS_setgroups32: c_long = 82; +pub const SYS_setitimer: c_long = 83; +pub const SYS_ftruncate64: c_long = 84; +pub const SYS_swapon: c_long = 85; +pub const SYS_getitimer: c_long = 86; +pub const SYS_setuid32: c_long = 87; +pub const SYS_sethostname: c_long = 88; +pub const SYS_setgid32: c_long = 89; +pub const SYS_dup2: c_long = 90; +pub const SYS_setfsuid32: c_long = 91; +pub const SYS_fcntl: c_long = 92; +pub const SYS_select: c_long = 93; +pub const SYS_setfsgid32: c_long = 94; +pub const SYS_fsync: c_long = 95; +pub const SYS_setpriority: c_long = 96; +pub const SYS_socket: c_long = 97; +pub const SYS_connect: c_long = 98; +pub const SYS_accept: c_long = 99; +pub const SYS_getpriority: c_long = 100; +pub const SYS_rt_sigreturn: c_long = 101; +pub const SYS_rt_sigaction: c_long = 102; +pub const SYS_rt_sigprocmask: c_long = 103; +pub const SYS_rt_sigpending: c_long = 104; +pub const SYS_rt_sigtimedwait: c_long = 105; +pub const SYS_rt_sigqueueinfo: c_long = 106; +pub const SYS_rt_sigsuspend: c_long = 107; +pub const SYS_setresuid32: c_long = 108; +pub const SYS_getresuid32: c_long = 109; +pub const SYS_setresgid32: c_long = 110; +pub const SYS_getresgid32: c_long = 111; +pub const SYS_setregid32: c_long = 112; +pub const SYS_recvmsg: c_long = 113; +pub const SYS_sendmsg: c_long = 114; +pub const SYS_getgroups32: c_long = 115; +pub const SYS_gettimeofday: c_long = 116; +pub const SYS_getrusage: c_long = 117; +pub const SYS_getsockopt: c_long = 118; +pub const SYS_getcwd: c_long = 119; +pub const SYS_readv: c_long = 120; +pub const SYS_writev: c_long = 121; +pub const SYS_settimeofday: c_long = 122; +pub const SYS_fchown: c_long = 123; +pub const SYS_fchmod: c_long = 124; +pub const SYS_recvfrom: c_long = 125; +pub const SYS_setreuid: c_long = 126; +pub const SYS_setregid: c_long = 127; +pub const SYS_rename: c_long = 128; +pub const SYS_truncate: c_long = 129; +pub const SYS_ftruncate: c_long = 130; +pub const SYS_flock: c_long = 131; +pub const SYS_lstat64: c_long = 132; +pub const SYS_sendto: c_long = 133; +pub const SYS_shutdown: c_long = 134; +pub const SYS_socketpair: c_long = 135; +pub const SYS_mkdir: c_long = 136; +pub const SYS_rmdir: c_long = 137; +pub const SYS_utimes: c_long = 138; +pub const SYS_stat64: c_long = 139; +pub const SYS_sendfile64: c_long = 140; +pub const SYS_getpeername: c_long = 141; +pub const SYS_futex: c_long = 142; +pub const SYS_gettid: c_long = 143; +pub const SYS_getrlimit: c_long = 144; +pub const SYS_setrlimit: c_long = 145; +pub const SYS_pivot_root: c_long = 146; +pub const SYS_prctl: c_long = 147; +pub const SYS_pciconfig_read: c_long = 148; +pub const SYS_pciconfig_write: c_long = 149; +pub const SYS_getsockname: c_long = 150; +pub const SYS_inotify_init: c_long = 151; +pub const SYS_inotify_add_watch: c_long = 152; +pub const SYS_poll: c_long = 153; +pub const SYS_getdents64: c_long = 154; +pub const SYS_fcntl64: c_long = 155; +pub const SYS_inotify_rm_watch: c_long = 156; +pub const SYS_statfs: c_long = 157; +pub const SYS_fstatfs: c_long = 158; +pub const SYS_umount: c_long = 159; +pub const SYS_sched_set_affinity: c_long = 160; +pub const SYS_sched_get_affinity: c_long = 161; +pub const SYS_getdomainname: c_long = 162; +pub const SYS_setdomainname: c_long = 163; +pub const SYS_quotactl: c_long = 165; +pub const SYS_set_tid_address: c_long = 166; +pub const SYS_mount: c_long = 167; +pub const SYS_ustat: c_long = 168; +pub const SYS_setxattr: c_long = 169; +pub const SYS_lsetxattr: c_long = 170; +pub const SYS_fsetxattr: c_long = 171; +pub const SYS_getxattr: c_long = 172; +pub const SYS_lgetxattr: c_long = 173; +pub const SYS_getdents: c_long = 174; +pub const SYS_setsid: c_long = 175; +pub const SYS_fchdir: c_long = 176; +pub const SYS_fgetxattr: c_long = 177; +pub const SYS_listxattr: c_long = 178; +pub const SYS_llistxattr: c_long = 179; +pub const SYS_flistxattr: c_long = 180; +pub const SYS_removexattr: c_long = 181; +pub const SYS_lremovexattr: c_long = 182; +pub const SYS_sigpending: c_long = 183; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 184; +pub const SYS_setpgid: c_long = 185; +pub const SYS_fremovexattr: c_long = 186; +pub const SYS_tkill: c_long = 187; +pub const SYS_exit_group: c_long = 188; +pub const SYS_uname: c_long = 189; +pub const SYS_init_module: c_long = 190; +pub const SYS_personality: c_long = 191; +pub const SYS_remap_file_pages: c_long = 192; +pub const SYS_epoll_create: c_long = 193; +pub const SYS_epoll_ctl: c_long = 194; +pub const SYS_epoll_wait: c_long = 195; +pub const SYS_ioprio_set: c_long = 196; +pub const SYS_getppid: c_long = 197; +pub const SYS_sigaction: c_long = 198; +pub const SYS_sgetmask: c_long = 199; +pub const SYS_ssetmask: c_long = 200; +pub const SYS_sigsuspend: c_long = 201; +pub const SYS_oldlstat: c_long = 202; +pub const SYS_uselib: c_long = 203; +pub const SYS_readdir: c_long = 204; +pub const SYS_readahead: c_long = 205; +pub const SYS_socketcall: c_long = 206; +pub const SYS_syslog: c_long = 207; +pub const SYS_lookup_dcookie: c_long = 208; +pub const SYS_fadvise64: c_long = 209; +pub const SYS_fadvise64_64: c_long = 210; +pub const SYS_tgkill: c_long = 211; +pub const SYS_waitpid: c_long = 212; +pub const SYS_swapoff: c_long = 213; +pub const SYS_sysinfo: c_long = 214; +pub const SYS_ipc: c_long = 215; +pub const SYS_sigreturn: c_long = 216; +pub const SYS_clone: c_long = 217; +pub const SYS_ioprio_get: c_long = 218; +pub const SYS_adjtimex: c_long = 219; +pub const SYS_sigprocmask: c_long = 220; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 221; +pub const SYS_delete_module: c_long = 222; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 223; +pub const SYS_getpgid: c_long = 224; +pub const SYS_bdflush: c_long = 225; +pub const SYS_sysfs: c_long = 226; +pub const SYS_afs_syscall: c_long = 227; +pub const SYS_setfsuid: c_long = 228; +pub const SYS_setfsgid: c_long = 229; +pub const SYS__newselect: c_long = 230; +pub const SYS_time: c_long = 231; +pub const SYS_splice: c_long = 232; +pub const SYS_stime: c_long = 233; +pub const SYS_statfs64: c_long = 234; +pub const SYS_fstatfs64: c_long = 235; +pub const SYS__llseek: c_long = 236; +pub const SYS_mlock: c_long = 237; +pub const SYS_munlock: c_long = 238; +pub const SYS_mlockall: c_long = 239; +pub const SYS_munlockall: c_long = 240; +pub const SYS_sched_setparam: c_long = 241; +pub const SYS_sched_getparam: c_long = 242; +pub const SYS_sched_setscheduler: c_long = 243; +pub const SYS_sched_getscheduler: c_long = 244; +pub const SYS_sched_yield: c_long = 245; +pub const SYS_sched_get_priority_max: c_long = 246; +pub const SYS_sched_get_priority_min: c_long = 247; +pub const SYS_sched_rr_get_interval: c_long = 248; +pub const SYS_nanosleep: c_long = 249; +pub const SYS_mremap: c_long = 250; +pub const SYS__sysctl: c_long = 251; +pub const SYS_getsid: c_long = 252; +pub const SYS_fdatasync: c_long = 253; +pub const SYS_nfsservctl: c_long = 254; +pub const SYS_sync_file_range: c_long = 255; +pub const SYS_clock_settime: c_long = 256; +pub const SYS_clock_gettime: c_long = 257; +pub const SYS_clock_getres: c_long = 258; +pub const SYS_clock_nanosleep: c_long = 259; +pub const SYS_sched_getaffinity: c_long = 260; +pub const SYS_sched_setaffinity: c_long = 261; +pub const SYS_timer_settime: c_long = 262; +pub const SYS_timer_gettime: c_long = 263; +pub const SYS_timer_getoverrun: c_long = 264; +pub const SYS_timer_delete: c_long = 265; +pub const SYS_timer_create: c_long = 266; +pub const SYS_io_setup: c_long = 268; +pub const SYS_io_destroy: c_long = 269; +pub const SYS_io_submit: c_long = 270; +pub const SYS_io_cancel: c_long = 271; +pub const SYS_io_getevents: c_long = 272; +pub const SYS_mq_open: c_long = 273; +pub const SYS_mq_unlink: c_long = 274; +pub const SYS_mq_timedsend: c_long = 275; +pub const SYS_mq_timedreceive: c_long = 276; +pub const SYS_mq_notify: c_long = 277; +pub const SYS_mq_getsetattr: c_long = 278; +pub const SYS_waitid: c_long = 279; +pub const SYS_tee: c_long = 280; +pub const SYS_add_key: c_long = 281; +pub const SYS_request_key: c_long = 282; +pub const SYS_keyctl: c_long = 283; +pub const SYS_openat: c_long = 284; +pub const SYS_mkdirat: c_long = 285; +pub const SYS_mknodat: c_long = 286; +pub const SYS_fchownat: c_long = 287; +pub const SYS_futimesat: c_long = 288; +pub const SYS_fstatat64: c_long = 289; +pub const SYS_unlinkat: c_long = 290; +pub const SYS_renameat: c_long = 291; +pub const SYS_linkat: c_long = 292; +pub const SYS_symlinkat: c_long = 293; +pub const SYS_readlinkat: c_long = 294; +pub const SYS_fchmodat: c_long = 295; +pub const SYS_faccessat: c_long = 296; +pub const SYS_pselect6: c_long = 297; +pub const SYS_ppoll: c_long = 298; +pub const SYS_unshare: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_get_robust_list: c_long = 301; +pub const SYS_migrate_pages: c_long = 302; +pub const SYS_mbind: c_long = 303; +pub const SYS_get_mempolicy: c_long = 304; +pub const SYS_set_mempolicy: c_long = 305; +pub const SYS_kexec_load: c_long = 306; +pub const SYS_move_pages: c_long = 307; +pub const SYS_getcpu: c_long = 308; +pub const SYS_epoll_pwait: c_long = 309; +pub const SYS_utimensat: c_long = 310; +pub const SYS_signalfd: c_long = 311; +pub const SYS_timerfd_create: c_long = 312; +pub const SYS_eventfd: c_long = 313; +pub const SYS_fallocate: c_long = 314; +pub const SYS_timerfd_settime: c_long = 315; +pub const SYS_timerfd_gettime: c_long = 316; +pub const SYS_signalfd4: c_long = 317; +pub const SYS_eventfd2: c_long = 318; +pub const SYS_epoll_create1: c_long = 319; +pub const SYS_dup3: c_long = 320; +pub const SYS_pipe2: c_long = 321; +pub const SYS_inotify_init1: c_long = 322; +pub const SYS_accept4: c_long = 323; +pub const SYS_preadv: c_long = 324; +pub const SYS_pwritev: c_long = 325; +pub const SYS_rt_tgsigqueueinfo: c_long = 326; +pub const SYS_perf_event_open: c_long = 327; +pub const SYS_recvmmsg: c_long = 328; +pub const SYS_fanotify_init: c_long = 329; +pub const SYS_fanotify_mark: c_long = 330; +pub const SYS_prlimit64: c_long = 331; +pub const SYS_name_to_handle_at: c_long = 332; +pub const SYS_open_by_handle_at: c_long = 333; +pub const SYS_clock_adjtime: c_long = 334; +pub const SYS_syncfs: c_long = 335; +pub const SYS_sendmmsg: c_long = 336; +pub const SYS_setns: c_long = 337; +pub const SYS_process_vm_readv: c_long = 338; +pub const SYS_process_vm_writev: c_long = 339; +pub const SYS_kern_features: c_long = 340; +pub const SYS_kcmp: c_long = 341; +pub const SYS_finit_module: c_long = 342; +pub const SYS_sched_setattr: c_long = 343; +pub const SYS_sched_getattr: c_long = 344; +pub const SYS_renameat2: c_long = 345; +pub const SYS_seccomp: c_long = 346; +pub const SYS_getrandom: c_long = 347; +pub const SYS_memfd_create: c_long = 348; +pub const SYS_bpf: c_long = 349; +pub const SYS_execveat: c_long = 350; +pub const SYS_membarrier: c_long = 351; +pub const SYS_userfaultfd: c_long = 352; +pub const SYS_bind: c_long = 353; +pub const SYS_listen: c_long = 354; +pub const SYS_setsockopt: c_long = 355; +pub const SYS_mlock2: c_long = 356; +pub const SYS_copy_file_range: c_long = 357; +pub const SYS_preadv2: c_long = 358; +pub const SYS_pwritev2: c_long = 359; +pub const SYS_statx: c_long = 360; +pub const SYS_rseq: c_long = 365; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +// Reserved in the kernel, but not actually implemented yet +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/x86/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/x86/mod.rs new file mode 100644 index 00000000000000..97429dad64285a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b32/x86/mod.rs @@ -0,0 +1,1035 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; +pub type greg_t = i32; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + f_spare: [crate::__fsword_t; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct _libc_fpreg { + pub significand: [u16; 4], + pub exponent: u16, + } + + pub struct _libc_fpstate { + pub cw: c_ulong, + pub sw: c_ulong, + pub tag: c_ulong, + pub ipoff: c_ulong, + pub cssel: c_ulong, + pub dataoff: c_ulong, + pub datasel: c_ulong, + pub _st: [_libc_fpreg; 8], + pub status: c_ulong, + } + + pub struct user_fpregs_struct { + pub cwd: c_long, + pub swd: c_long, + pub twd: c_long, + pub fip: c_long, + pub fcs: c_long, + pub foo: c_long, + pub fos: c_long, + pub st_space: [c_long; 20], + } + + pub struct user_regs_struct { + pub ebx: c_long, + pub ecx: c_long, + pub edx: c_long, + pub esi: c_long, + pub edi: c_long, + pub ebp: c_long, + pub eax: c_long, + pub xds: c_long, + pub xes: c_long, + pub xfs: c_long, + pub xgs: c_long, + pub orig_eax: c_long, + pub eip: c_long, + pub xcs: c_long, + pub eflags: c_long, + pub esp: c_long, + pub xss: c_long, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: c_int, + pub i387: user_fpregs_struct, + pub u_tsize: c_ulong, + pub u_dsize: c_ulong, + pub u_ssize: c_ulong, + pub start_code: c_ulong, + pub start_stack: c_ulong, + pub signal: c_long, + __reserved: Padding, + pub u_ar0: *mut user_regs_struct, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: c_ulong, + pub u_comm: [c_char; 32], + pub u_debugreg: [c_int; 8], + } + + pub struct mcontext_t { + pub gregs: [greg_t; 19], + pub fpregs: *mut _libc_fpstate, + pub oldmask: c_ulong, + pub cr2: c_ulong, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad1: Padding, + #[cfg(not(gnu_time_bits64))] + __st_ino: c_ulong, + #[cfg(gnu_time_bits64)] + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + #[cfg(not(gnu_time_bits64))] + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _atime_pad: Padding, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _mtime_pad: Padding, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(gnu_time_bits64)] + _ctime_pad: Padding, + #[cfg(not(gnu_time_bits64))] + pub st_ino: crate::ino64_t, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused1: Padding, + pub shm_dtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused2: Padding, + pub shm_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __unused3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved1: Padding, + pub msg_rtime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved2: Padding, + pub msg_ctime: crate::time_t, + #[cfg(not(gnu_time_bits64))] + __glibc_reserved3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct user_fpxregs_struct { + pub cwd: c_ushort, + pub swd: c_ushort, + pub twd: c_ushort, + pub fop: c_ushort, + pub fip: c_long, + pub fcs: c_long, + pub foo: c_long, + pub fos: c_long, + pub mxcsr: c_long, + __reserved: Padding, + pub st_space: [c_long; 32], + pub xmm_space: [c_long; 32], + padding: Padding<[c_long; 56]>, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + __private: [u8; 112], + __ssp: [c_ulong; 4], + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 6], + } +} + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_LARGEFILE: c_int = 0o0100000; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_32BIT: c_int = 0x0040; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +cfg_if! { + if #[cfg(gnu_file_offset_bits64)] { + pub const F_GETLK: c_int = 12; + } else { + pub const F_GETLK: c_int = 5; + } +} +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; + +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_SYSEMU: c_uint = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_uint = 32; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const EFD_NONBLOCK: c_int = 0x800; +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86old: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_vm86: c_long = 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_mincore: c_long = 218; +pub const SYS_madvise: c_long = 219; +pub const SYS_getdents64: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_set_thread_area: c_long = 243; +pub const SYS_get_thread_area: c_long = 244; +pub const SYS_io_setup: c_long = 245; +pub const SYS_io_destroy: c_long = 246; +pub const SYS_io_getevents: c_long = 247; +pub const SYS_io_submit: c_long = 248; +pub const SYS_io_cancel: c_long = 249; +pub const SYS_fadvise64: c_long = 250; +pub const SYS_exit_group: c_long = 252; +pub const SYS_lookup_dcookie: c_long = 253; +pub const SYS_epoll_create: c_long = 254; +pub const SYS_epoll_ctl: c_long = 255; +pub const SYS_epoll_wait: c_long = 256; +pub const SYS_remap_file_pages: c_long = 257; +pub const SYS_set_tid_address: c_long = 258; +pub const SYS_timer_create: c_long = 259; +pub const SYS_timer_settime: c_long = 260; +pub const SYS_timer_gettime: c_long = 261; +pub const SYS_timer_getoverrun: c_long = 262; +pub const SYS_timer_delete: c_long = 263; +pub const SYS_clock_settime: c_long = 264; +pub const SYS_clock_gettime: c_long = 265; +pub const SYS_clock_getres: c_long = 266; +pub const SYS_clock_nanosleep: c_long = 267; +pub const SYS_statfs64: c_long = 268; +pub const SYS_fstatfs64: c_long = 269; +pub const SYS_tgkill: c_long = 270; +pub const SYS_utimes: c_long = 271; +pub const SYS_fadvise64_64: c_long = 272; +pub const SYS_vserver: c_long = 273; +pub const SYS_mbind: c_long = 274; +pub const SYS_get_mempolicy: c_long = 275; +pub const SYS_set_mempolicy: c_long = 276; +pub const SYS_mq_open: c_long = 277; +pub const SYS_mq_unlink: c_long = 278; +pub const SYS_mq_timedsend: c_long = 279; +pub const SYS_mq_timedreceive: c_long = 280; +pub const SYS_mq_notify: c_long = 281; +pub const SYS_mq_getsetattr: c_long = 282; +pub const SYS_kexec_load: c_long = 283; +pub const SYS_waitid: c_long = 284; +pub const SYS_add_key: c_long = 286; +pub const SYS_request_key: c_long = 287; +pub const SYS_keyctl: c_long = 288; +pub const SYS_ioprio_set: c_long = 289; +pub const SYS_ioprio_get: c_long = 290; +pub const SYS_inotify_init: c_long = 291; +pub const SYS_inotify_add_watch: c_long = 292; +pub const SYS_inotify_rm_watch: c_long = 293; +pub const SYS_migrate_pages: c_long = 294; +pub const SYS_openat: c_long = 295; +pub const SYS_mkdirat: c_long = 296; +pub const SYS_mknodat: c_long = 297; +pub const SYS_fchownat: c_long = 298; +pub const SYS_futimesat: c_long = 299; +pub const SYS_fstatat64: c_long = 300; +pub const SYS_unlinkat: c_long = 301; +pub const SYS_renameat: c_long = 302; +pub const SYS_linkat: c_long = 303; +pub const SYS_symlinkat: c_long = 304; +pub const SYS_readlinkat: c_long = 305; +pub const SYS_fchmodat: c_long = 306; +pub const SYS_faccessat: c_long = 307; +pub const SYS_pselect6: c_long = 308; +pub const SYS_ppoll: c_long = 309; +pub const SYS_unshare: c_long = 310; +pub const SYS_set_robust_list: c_long = 311; +pub const SYS_get_robust_list: c_long = 312; +pub const SYS_splice: c_long = 313; +pub const SYS_sync_file_range: c_long = 314; +pub const SYS_tee: c_long = 315; +pub const SYS_vmsplice: c_long = 316; +pub const SYS_move_pages: c_long = 317; +pub const SYS_getcpu: c_long = 318; +pub const SYS_epoll_pwait: c_long = 319; +pub const SYS_utimensat: c_long = 320; +pub const SYS_signalfd: c_long = 321; +pub const SYS_timerfd_create: c_long = 322; +pub const SYS_eventfd: c_long = 323; +pub const SYS_fallocate: c_long = 324; +pub const SYS_timerfd_settime: c_long = 325; +pub const SYS_timerfd_gettime: c_long = 326; +pub const SYS_signalfd4: c_long = 327; +pub const SYS_eventfd2: c_long = 328; +pub const SYS_epoll_create1: c_long = 329; +pub const SYS_dup3: c_long = 330; +pub const SYS_pipe2: c_long = 331; +pub const SYS_inotify_init1: c_long = 332; +pub const SYS_preadv: c_long = 333; +pub const SYS_pwritev: c_long = 334; +pub const SYS_rt_tgsigqueueinfo: c_long = 335; +pub const SYS_perf_event_open: c_long = 336; +pub const SYS_recvmmsg: c_long = 337; +pub const SYS_fanotify_init: c_long = 338; +pub const SYS_fanotify_mark: c_long = 339; +pub const SYS_prlimit64: c_long = 340; +pub const SYS_name_to_handle_at: c_long = 341; +pub const SYS_open_by_handle_at: c_long = 342; +pub const SYS_clock_adjtime: c_long = 343; +pub const SYS_syncfs: c_long = 344; +pub const SYS_sendmmsg: c_long = 345; +pub const SYS_setns: c_long = 346; +pub const SYS_process_vm_readv: c_long = 347; +pub const SYS_process_vm_writev: c_long = 348; +pub const SYS_kcmp: c_long = 349; +pub const SYS_finit_module: c_long = 350; +pub const SYS_sched_setattr: c_long = 351; +pub const SYS_sched_getattr: c_long = 352; +pub const SYS_renameat2: c_long = 353; +pub const SYS_seccomp: c_long = 354; +pub const SYS_getrandom: c_long = 355; +pub const SYS_memfd_create: c_long = 356; +pub const SYS_bpf: c_long = 357; +pub const SYS_execveat: c_long = 358; +pub const SYS_socket: c_long = 359; +pub const SYS_socketpair: c_long = 360; +pub const SYS_bind: c_long = 361; +pub const SYS_connect: c_long = 362; +pub const SYS_listen: c_long = 363; +pub const SYS_accept4: c_long = 364; +pub const SYS_getsockopt: c_long = 365; +pub const SYS_setsockopt: c_long = 366; +pub const SYS_getsockname: c_long = 367; +pub const SYS_getpeername: c_long = 368; +pub const SYS_sendto: c_long = 369; +pub const SYS_sendmsg: c_long = 370; +pub const SYS_recvfrom: c_long = 371; +pub const SYS_recvmsg: c_long = 372; +pub const SYS_shutdown: c_long = 373; +pub const SYS_userfaultfd: c_long = 374; +pub const SYS_membarrier: c_long = 375; +pub const SYS_mlock2: c_long = 376; +pub const SYS_copy_file_range: c_long = 377; +pub const SYS_preadv2: c_long = 378; +pub const SYS_pwritev2: c_long = 379; +pub const SYS_pkey_mprotect: c_long = 380; +pub const SYS_pkey_alloc: c_long = 381; +pub const SYS_pkey_free: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_rseq: c_long = 386; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_mseal: c_long = 462; + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: c_int = 0; +pub const ECX: c_int = 1; +pub const EDX: c_int = 2; +pub const ESI: c_int = 3; +pub const EDI: c_int = 4; +pub const EBP: c_int = 5; +pub const EAX: c_int = 6; +pub const DS: c_int = 7; +pub const ES: c_int = 8; +pub const FS: c_int = 9; +pub const GS: c_int = 10; +pub const ORIG_EAX: c_int = 11; +pub const EIP: c_int = 12; +pub const CS: c_int = 13; +pub const EFL: c_int = 14; +pub const UESP: c_int = 15; +pub const SS: c_int = 16; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_GS: c_int = 0; +pub const REG_FS: c_int = 1; +pub const REG_ES: c_int = 2; +pub const REG_DS: c_int = 3; +pub const REG_EDI: c_int = 4; +pub const REG_ESI: c_int = 5; +pub const REG_EBP: c_int = 6; +pub const REG_ESP: c_int = 7; +pub const REG_EBX: c_int = 8; +pub const REG_EDX: c_int = 9; +pub const REG_ECX: c_int = 10; +pub const REG_EAX: c_int = 11; +pub const REG_TRAPNO: c_int = 12; +pub const REG_ERR: c_int = 13; +pub const REG_EIP: c_int = 14; +pub const REG_CS: c_int = 15; +pub const REG_EFL: c_int = 16; +pub const REG_UESP: c_int = 17; +pub const REG_SS: c_int = 18; + +extern "C" { + pub fn getcontext(ucp: *mut ucontext_t) -> c_int; + pub fn setcontext(ucp: *const ucontext_t) -> c_int; + pub fn makecontext(ucp: *mut ucontext_t, func: extern "C" fn(), argc: c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, ucp: *const ucontext_t) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs new file mode 100644 index 00000000000000..f808ff31f8cca5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs @@ -0,0 +1,54 @@ +use crate::prelude::*; +use crate::pthread_mutex_t; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 48; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; + +pub const SYS_sync_file_range2: c_long = 84; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs new file mode 100644 index 00000000000000..960e5127806b34 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs @@ -0,0 +1,57 @@ +use crate::prelude::*; +use crate::pthread_mutex_t; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 48; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const SYS_renameat: c_long = 38; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_setrlimit: c_long = 164; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs new file mode 100644 index 00000000000000..b8c55dc33c89f3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs @@ -0,0 +1,976 @@ +//! AArch64-specific definitions for 64-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = u32; +pub type nlink_t = u32; +pub type blksize_t = i32; +pub type suseconds_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + #[cfg(target_arch = "sparc64")] + __reserved0: Padding, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + f_spare: [crate::__fsword_t; 5], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad2: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + __pad2: Padding, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [usize; 8], + } + + pub struct user_regs_struct { + pub regs: [c_ulonglong; 31], + pub sp: c_ulonglong, + pub pc: c_ulonglong, + pub pstate: c_ulonglong, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub fault_address: c_ulonglong, + pub regs: [c_ulonglong; 31], + pub sp: c_ulonglong, + pub pc: c_ulonglong, + pub pstate: c_ulonglong, + __reserved: Padding<[u64; 512]>, + } + + pub struct user_fpsimd_struct { + pub vregs: [u128; 32], + pub fpsr: c_uint, + pub fpcr: c_uint, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f32; 8], + } +} + +pub const VEOF: usize = 4; + +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0100; + +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const PTRACE_DETACH: c_uint = 17; + +pub const EFD_NONBLOCK: c_int = 0x800; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; + +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; + +pub const O_CLOEXEC: c_int = 0x80000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; + +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 5120; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +// sys/auxv.h +pub const HWCAP_FP: c_ulong = 1 << 0; +pub const HWCAP_ASIMD: c_ulong = 1 << 1; +pub const HWCAP_EVTSTRM: c_ulong = 1 << 2; +pub const HWCAP_AES: c_ulong = 1 << 3; +pub const HWCAP_PMULL: c_ulong = 1 << 4; +pub const HWCAP_SHA1: c_ulong = 1 << 5; +pub const HWCAP_SHA2: c_ulong = 1 << 6; +pub const HWCAP_CRC32: c_ulong = 1 << 7; +pub const HWCAP_ATOMICS: c_ulong = 1 << 8; +pub const HWCAP_FPHP: c_ulong = 1 << 9; +pub const HWCAP_ASIMDHP: c_ulong = 1 << 10; +pub const HWCAP_CPUID: c_ulong = 1 << 11; +pub const HWCAP_ASIMDRDM: c_ulong = 1 << 12; +pub const HWCAP_JSCVT: c_ulong = 1 << 13; +pub const HWCAP_FCMA: c_ulong = 1 << 14; +pub const HWCAP_LRCPC: c_ulong = 1 << 15; +pub const HWCAP_DCPOP: c_ulong = 1 << 16; +pub const HWCAP_SHA3: c_ulong = 1 << 17; +pub const HWCAP_SM3: c_ulong = 1 << 18; +pub const HWCAP_SM4: c_ulong = 1 << 19; +pub const HWCAP_ASIMDDP: c_ulong = 1 << 20; +pub const HWCAP_SHA512: c_ulong = 1 << 21; +pub const HWCAP_SVE: c_ulong = 1 << 22; +pub const HWCAP_ASIMDFHM: c_ulong = 1 << 23; +pub const HWCAP_DIT: c_ulong = 1 << 24; +pub const HWCAP_USCAT: c_ulong = 1 << 25; +pub const HWCAP_ILRCPC: c_ulong = 1 << 26; +pub const HWCAP_FLAGM: c_ulong = 1 << 27; +pub const HWCAP_SSBS: c_ulong = 1 << 28; +pub const HWCAP_SB: c_ulong = 1 << 29; +pub const HWCAP_PACA: c_ulong = 1 << 30; +pub const HWCAP_PACG: c_ulong = 1 << 31; +// FIXME(linux): enable these again once linux-api-headers are up to date enough on CI. +// See discussion in https://github.com/rust-lang/libc/pull/1638 +//pub const HWCAP2_DCPODP: c_ulong = 1 << 0; +//pub const HWCAP2_SVE2: c_ulong = 1 << 1; +//pub const HWCAP2_SVEAES: c_ulong = 1 << 2; +//pub const HWCAP2_SVEPMULL: c_ulong = 1 << 3; +//pub const HWCAP2_SVEBITPERM: c_ulong = 1 << 4; +//pub const HWCAP2_SVESHA3: c_ulong = 1 << 5; +//pub const HWCAP2_SVESM4: c_ulong = 1 << 6; +//pub const HWCAP2_FLAGM2: c_ulong = 1 << 7; +//pub const HWCAP2_FRINT: c_ulong = 1 << 8; +//pub const HWCAP2_MTE: c_ulong = 1 << 18; + +// linux/prctl.h +pub const PR_PAC_RESET_KEYS: c_int = 54; +pub const PR_SET_TAGGED_ADDR_CTRL: c_int = 55; +pub const PR_GET_TAGGED_ADDR_CTRL: c_int = 56; +pub const PR_PAC_SET_ENABLED_KEYS: c_int = 60; +pub const PR_PAC_GET_ENABLED_KEYS: c_int = 61; + +pub const PR_TAGGED_ADDR_ENABLE: c_ulong = 1; + +pub const PR_PAC_APIAKEY: c_ulong = 1 << 0; +pub const PR_PAC_APIBKEY: c_ulong = 1 << 1; +pub const PR_PAC_APDAKEY: c_ulong = 1 << 2; +pub const PR_PAC_APDBKEY: c_ulong = 1 << 3; +pub const PR_PAC_APGAKEY: c_ulong = 1 << 4; + +pub const PR_SME_SET_VL: c_int = 63; +pub const PR_SME_GET_VL: c_int = 64; +pub const PR_SME_VL_LEN_MAX: c_int = 0xffff; + +pub const PR_SME_SET_VL_INHERIT: c_ulong = 1 << 17; +pub const PR_SME_SET_VL_ONE_EXEC: c_ulong = 1 << 18; + +// Syscall table +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_fcntl: c_long = 25; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +// 38 is renameat only on LP64 +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_lseek: c_long = 62; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_fstat: c_long = 80; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +// 84 sync_file_range on LP64 and sync_file_range2 on ILP32 +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +// 163 is getrlimit only on LP64 +// 164 is setrlimit only on LP64 +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_mmap: c_long = 222; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_rseq: c_long = 293; +pub const SYS_kexec_file_load: c_long = 294; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; + +pub const PROT_BTI: c_int = 0x10; +pub const PROT_MTE: c_int = 0x20; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + + pub fn getcontext(ucp: *mut ucontext_t) -> c_int; + pub fn setcontext(ucp: *const ucontext_t) -> c_int; + pub fn makecontext(ucp: *mut ucontext_t, func: extern "C" fn(), argc: c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, ucp: *const ucontext_t) -> c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod ilp32; + pub use self::ilp32::*; + } else { + mod lp64; + pub use self::lp64::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs new file mode 100644 index 00000000000000..3f01da8c0b989b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs @@ -0,0 +1,925 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, + pthread_mutex_t, +}; + +pub type wchar_t = i32; + +pub type blksize_t = i32; +pub type nlink_t = u32; +pub type suseconds_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad2: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub __pad1: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub __pad2: c_int, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [c_ulong; 7], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [u64; 0], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct user_regs_struct { + pub regs: [u64; 32], + pub orig_a0: u64, + pub csr_era: u64, + pub csr_badv: u64, + pub reserved: [u64; 10], + } + + pub struct user_fp_struct { + pub fpr: [u64; 32], + pub fcc: u64, + pub fcsr: u32, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub __pc: c_ulonglong, + pub __gregs: [c_ulonglong; 32], + pub __flags: c_uint, + pub __extcontext: [c_ulonglong; 0], + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const HWCAP_LOONGARCH_CPUCFG: c_ulong = 1 << 0; +pub const HWCAP_LOONGARCH_LAM: c_ulong = 1 << 1; +pub const HWCAP_LOONGARCH_UAL: c_ulong = 1 << 2; +pub const HWCAP_LOONGARCH_FPU: c_ulong = 1 << 3; +pub const HWCAP_LOONGARCH_LSX: c_ulong = 1 << 4; +pub const HWCAP_LOONGARCH_LASX: c_ulong = 1 << 5; +pub const HWCAP_LOONGARCH_CRC32: c_ulong = 1 << 6; +pub const HWCAP_LOONGARCH_COMPLEX: c_ulong = 1 << 7; +pub const HWCAP_LOONGARCH_CRYPTO: c_ulong = 1 << 8; +pub const HWCAP_LOONGARCH_LVZ: c_ulong = 1 << 9; +pub const HWCAP_LOONGARCH_LBT_X86: c_ulong = 1 << 10; +pub const HWCAP_LOONGARCH_LBT_ARM: c_ulong = 1 << 11; +pub const HWCAP_LOONGARCH_LBT_MIPS: c_ulong = 1 << 12; +pub const HWCAP_LOONGARCH_PTW: c_ulong = 1 << 13; + +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_fcntl: c_long = 25; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_lseek: c_long = 62; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_sendfile: c_long = 71; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_mmap: c_long = 222; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +//pub const SYS_arch_specific_syscall: c_long = 244; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_io_pgetevents: c_long = 292; +pub const SYS_rseq: c_long = 293; +pub const SYS_kexec_file_load: c_long = 294; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; +pub const O_DIRECT: c_int = 0o00040000; +pub const O_DIRECTORY: c_int = 0o00200000; +pub const O_NOFOLLOW: c_int = 0o00400000; +pub const O_TRUNC: c_int = 0o00001000; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_CLOEXEC: c_int = 0o02000000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; +pub const O_APPEND: c_int = 0o00002000; +pub const O_CREAT: c_int = 0o00000100; +pub const O_EXCL: c_int = 0o00000200; +pub const O_NOCTTY: c_int = 0o00000400; +pub const O_NONBLOCK: c_int = 0o00004000; +pub const FASYNC: c_int = 0o00020000; +pub const O_SYNC: c_int = 0o04010000; +pub const O_RSYNC: c_int = 0o04010000; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_ASYNC: c_int = 0o00020000; +pub const O_DSYNC: c_int = 0o00010000; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; +pub const F_GETLK: c_int = 5; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; +pub const F_GETOWN: c_int = 9; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const MADV_SOFT_OFFLINE: c_int = 101; + +pub const MAP_NORESERVE: c_int = 0x4000; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x1000; +pub const MAP_LOCKED: c_int = 0x2000; +pub const MAP_POPULATE: c_int = 0x8000; +pub const MAP_NONBLOCK: c_int = 0x10000; +pub const MAP_STACK: c_int = 0x20000; +pub const MAP_HUGETLB: c_int = 0x40000; +pub const MAP_SYNC: c_int = 0x080000; +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SFD_NONBLOCK: c_int = 0x800; +pub const SFD_CLOEXEC: c_int = 0x080000; +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const SIG_SETMASK: c_int = 2; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGSTKFLT: c_int = 16; +pub const SIGCHLD: c_int = 17; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGURG: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGIO: c_int = 29; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIGSYS: c_int = 31; +pub const SIGUNUSED: c_int = 31; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const PTRACE_GETFPREGS: c_uint = 14; +pub const PTRACE_SETFPREGS: c_uint = 15; +pub const PTRACE_DETACH: c_uint = 17; +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_GETREGS: c_uint = 12; +pub const PTRACE_SETREGS: c_uint = 13; +pub const PTRACE_SYSEMU: c_uint = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_uint = 32; + +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const VEOF: usize = 4; +pub const VTIME: usize = 5; +pub const VMIN: usize = 6; +pub const VSWTC: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VEOL: usize = 11; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const VEOL2: usize = 16; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 4096; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; + +pub const NCCS: usize = 32; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; +pub const EFD_NONBLOCK: c_int = 0x800; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mips64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mips64/mod.rs new file mode 100644 index 00000000000000..dfec9203361d0b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mips64/mod.rs @@ -0,0 +1,934 @@ +use crate::prelude::*; +use crate::{ + off64_t, + off_t, + pthread_mutex_t, +}; + +pub type blksize_t = i64; +pub type nlink_t = u64; +pub type suseconds_t = i64; +pub type wchar_t = i32; +pub type __u64 = c_ulong; +pub type __s64 = c_long; + +s! { + pub struct stat { + pub st_dev: c_ulong, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + st_pad2: Padding<[c_ulong; 1]>, + pub st_size: off_t, + st_pad3: Padding, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + st_pad4: Padding, + pub st_blocks: crate::blkcnt_t, + st_pad5: Padding<[c_long; 7]>, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsblkcnt_t, + pub f_ffree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: c_long, + f_spare: [c_long; 6], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct stat64 { + pub st_dev: c_ulong, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + st_pad2: Padding<[c_long; 2]>, + pub st_size: off64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + st_pad3: Padding, + pub st_blocks: crate::blkcnt64_t, + st_pad5: Padding<[c_long; 7]>, + } + + pub struct statfs64 { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_bavail: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 5], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [c_ulong; 7], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_flags: c_int, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_restorer: Option, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + _pad: Padding, + _pad2: Padding<[c_long; 14]>, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const SYS_read: c_long = 5000 + 0; +pub const SYS_write: c_long = 5000 + 1; +pub const SYS_open: c_long = 5000 + 2; +pub const SYS_close: c_long = 5000 + 3; +pub const SYS_stat: c_long = 5000 + 4; +pub const SYS_fstat: c_long = 5000 + 5; +pub const SYS_lstat: c_long = 5000 + 6; +pub const SYS_poll: c_long = 5000 + 7; +pub const SYS_lseek: c_long = 5000 + 8; +pub const SYS_mmap: c_long = 5000 + 9; +pub const SYS_mprotect: c_long = 5000 + 10; +pub const SYS_munmap: c_long = 5000 + 11; +pub const SYS_brk: c_long = 5000 + 12; +pub const SYS_rt_sigaction: c_long = 5000 + 13; +pub const SYS_rt_sigprocmask: c_long = 5000 + 14; +pub const SYS_ioctl: c_long = 5000 + 15; +pub const SYS_pread64: c_long = 5000 + 16; +pub const SYS_pwrite64: c_long = 5000 + 17; +pub const SYS_readv: c_long = 5000 + 18; +pub const SYS_writev: c_long = 5000 + 19; +pub const SYS_access: c_long = 5000 + 20; +pub const SYS_pipe: c_long = 5000 + 21; +pub const SYS__newselect: c_long = 5000 + 22; +pub const SYS_sched_yield: c_long = 5000 + 23; +pub const SYS_mremap: c_long = 5000 + 24; +pub const SYS_msync: c_long = 5000 + 25; +pub const SYS_mincore: c_long = 5000 + 26; +pub const SYS_madvise: c_long = 5000 + 27; +pub const SYS_shmget: c_long = 5000 + 28; +pub const SYS_shmat: c_long = 5000 + 29; +pub const SYS_shmctl: c_long = 5000 + 30; +pub const SYS_dup: c_long = 5000 + 31; +pub const SYS_dup2: c_long = 5000 + 32; +pub const SYS_pause: c_long = 5000 + 33; +pub const SYS_nanosleep: c_long = 5000 + 34; +pub const SYS_getitimer: c_long = 5000 + 35; +pub const SYS_setitimer: c_long = 5000 + 36; +pub const SYS_alarm: c_long = 5000 + 37; +pub const SYS_getpid: c_long = 5000 + 38; +pub const SYS_sendfile: c_long = 5000 + 39; +pub const SYS_socket: c_long = 5000 + 40; +pub const SYS_connect: c_long = 5000 + 41; +pub const SYS_accept: c_long = 5000 + 42; +pub const SYS_sendto: c_long = 5000 + 43; +pub const SYS_recvfrom: c_long = 5000 + 44; +pub const SYS_sendmsg: c_long = 5000 + 45; +pub const SYS_recvmsg: c_long = 5000 + 46; +pub const SYS_shutdown: c_long = 5000 + 47; +pub const SYS_bind: c_long = 5000 + 48; +pub const SYS_listen: c_long = 5000 + 49; +pub const SYS_getsockname: c_long = 5000 + 50; +pub const SYS_getpeername: c_long = 5000 + 51; +pub const SYS_socketpair: c_long = 5000 + 52; +pub const SYS_setsockopt: c_long = 5000 + 53; +pub const SYS_getsockopt: c_long = 5000 + 54; +pub const SYS_clone: c_long = 5000 + 55; +pub const SYS_fork: c_long = 5000 + 56; +pub const SYS_execve: c_long = 5000 + 57; +pub const SYS_exit: c_long = 5000 + 58; +pub const SYS_wait4: c_long = 5000 + 59; +pub const SYS_kill: c_long = 5000 + 60; +pub const SYS_uname: c_long = 5000 + 61; +pub const SYS_semget: c_long = 5000 + 62; +pub const SYS_semop: c_long = 5000 + 63; +pub const SYS_semctl: c_long = 5000 + 64; +pub const SYS_shmdt: c_long = 5000 + 65; +pub const SYS_msgget: c_long = 5000 + 66; +pub const SYS_msgsnd: c_long = 5000 + 67; +pub const SYS_msgrcv: c_long = 5000 + 68; +pub const SYS_msgctl: c_long = 5000 + 69; +pub const SYS_fcntl: c_long = 5000 + 70; +pub const SYS_flock: c_long = 5000 + 71; +pub const SYS_fsync: c_long = 5000 + 72; +pub const SYS_fdatasync: c_long = 5000 + 73; +pub const SYS_truncate: c_long = 5000 + 74; +pub const SYS_ftruncate: c_long = 5000 + 75; +pub const SYS_getdents: c_long = 5000 + 76; +pub const SYS_getcwd: c_long = 5000 + 77; +pub const SYS_chdir: c_long = 5000 + 78; +pub const SYS_fchdir: c_long = 5000 + 79; +pub const SYS_rename: c_long = 5000 + 80; +pub const SYS_mkdir: c_long = 5000 + 81; +pub const SYS_rmdir: c_long = 5000 + 82; +pub const SYS_creat: c_long = 5000 + 83; +pub const SYS_link: c_long = 5000 + 84; +pub const SYS_unlink: c_long = 5000 + 85; +pub const SYS_symlink: c_long = 5000 + 86; +pub const SYS_readlink: c_long = 5000 + 87; +pub const SYS_chmod: c_long = 5000 + 88; +pub const SYS_fchmod: c_long = 5000 + 89; +pub const SYS_chown: c_long = 5000 + 90; +pub const SYS_fchown: c_long = 5000 + 91; +pub const SYS_lchown: c_long = 5000 + 92; +pub const SYS_umask: c_long = 5000 + 93; +pub const SYS_gettimeofday: c_long = 5000 + 94; +pub const SYS_getrlimit: c_long = 5000 + 95; +pub const SYS_getrusage: c_long = 5000 + 96; +pub const SYS_sysinfo: c_long = 5000 + 97; +pub const SYS_times: c_long = 5000 + 98; +pub const SYS_ptrace: c_long = 5000 + 99; +pub const SYS_getuid: c_long = 5000 + 100; +pub const SYS_syslog: c_long = 5000 + 101; +pub const SYS_getgid: c_long = 5000 + 102; +pub const SYS_setuid: c_long = 5000 + 103; +pub const SYS_setgid: c_long = 5000 + 104; +pub const SYS_geteuid: c_long = 5000 + 105; +pub const SYS_getegid: c_long = 5000 + 106; +pub const SYS_setpgid: c_long = 5000 + 107; +pub const SYS_getppid: c_long = 5000 + 108; +pub const SYS_getpgrp: c_long = 5000 + 109; +pub const SYS_setsid: c_long = 5000 + 110; +pub const SYS_setreuid: c_long = 5000 + 111; +pub const SYS_setregid: c_long = 5000 + 112; +pub const SYS_getgroups: c_long = 5000 + 113; +pub const SYS_setgroups: c_long = 5000 + 114; +pub const SYS_setresuid: c_long = 5000 + 115; +pub const SYS_getresuid: c_long = 5000 + 116; +pub const SYS_setresgid: c_long = 5000 + 117; +pub const SYS_getresgid: c_long = 5000 + 118; +pub const SYS_getpgid: c_long = 5000 + 119; +pub const SYS_setfsuid: c_long = 5000 + 120; +pub const SYS_setfsgid: c_long = 5000 + 121; +pub const SYS_getsid: c_long = 5000 + 122; +pub const SYS_capget: c_long = 5000 + 123; +pub const SYS_capset: c_long = 5000 + 124; +pub const SYS_rt_sigpending: c_long = 5000 + 125; +pub const SYS_rt_sigtimedwait: c_long = 5000 + 126; +pub const SYS_rt_sigqueueinfo: c_long = 5000 + 127; +pub const SYS_rt_sigsuspend: c_long = 5000 + 128; +pub const SYS_sigaltstack: c_long = 5000 + 129; +pub const SYS_utime: c_long = 5000 + 130; +pub const SYS_mknod: c_long = 5000 + 131; +pub const SYS_personality: c_long = 5000 + 132; +pub const SYS_ustat: c_long = 5000 + 133; +pub const SYS_statfs: c_long = 5000 + 134; +pub const SYS_fstatfs: c_long = 5000 + 135; +pub const SYS_sysfs: c_long = 5000 + 136; +pub const SYS_getpriority: c_long = 5000 + 137; +pub const SYS_setpriority: c_long = 5000 + 138; +pub const SYS_sched_setparam: c_long = 5000 + 139; +pub const SYS_sched_getparam: c_long = 5000 + 140; +pub const SYS_sched_setscheduler: c_long = 5000 + 141; +pub const SYS_sched_getscheduler: c_long = 5000 + 142; +pub const SYS_sched_get_priority_max: c_long = 5000 + 143; +pub const SYS_sched_get_priority_min: c_long = 5000 + 144; +pub const SYS_sched_rr_get_interval: c_long = 5000 + 145; +pub const SYS_mlock: c_long = 5000 + 146; +pub const SYS_munlock: c_long = 5000 + 147; +pub const SYS_mlockall: c_long = 5000 + 148; +pub const SYS_munlockall: c_long = 5000 + 149; +pub const SYS_vhangup: c_long = 5000 + 150; +pub const SYS_pivot_root: c_long = 5000 + 151; +pub const SYS__sysctl: c_long = 5000 + 152; +pub const SYS_prctl: c_long = 5000 + 153; +pub const SYS_adjtimex: c_long = 5000 + 154; +pub const SYS_setrlimit: c_long = 5000 + 155; +pub const SYS_chroot: c_long = 5000 + 156; +pub const SYS_sync: c_long = 5000 + 157; +pub const SYS_acct: c_long = 5000 + 158; +pub const SYS_settimeofday: c_long = 5000 + 159; +pub const SYS_mount: c_long = 5000 + 160; +pub const SYS_umount2: c_long = 5000 + 161; +pub const SYS_swapon: c_long = 5000 + 162; +pub const SYS_swapoff: c_long = 5000 + 163; +pub const SYS_reboot: c_long = 5000 + 164; +pub const SYS_sethostname: c_long = 5000 + 165; +pub const SYS_setdomainname: c_long = 5000 + 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 5000 + 167; +pub const SYS_init_module: c_long = 5000 + 168; +pub const SYS_delete_module: c_long = 5000 + 169; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 5000 + 170; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 5000 + 171; +pub const SYS_quotactl: c_long = 5000 + 172; +pub const SYS_nfsservctl: c_long = 5000 + 173; +pub const SYS_getpmsg: c_long = 5000 + 174; +pub const SYS_putpmsg: c_long = 5000 + 175; +pub const SYS_afs_syscall: c_long = 5000 + 176; +pub const SYS_gettid: c_long = 5000 + 178; +pub const SYS_readahead: c_long = 5000 + 179; +pub const SYS_setxattr: c_long = 5000 + 180; +pub const SYS_lsetxattr: c_long = 5000 + 181; +pub const SYS_fsetxattr: c_long = 5000 + 182; +pub const SYS_getxattr: c_long = 5000 + 183; +pub const SYS_lgetxattr: c_long = 5000 + 184; +pub const SYS_fgetxattr: c_long = 5000 + 185; +pub const SYS_listxattr: c_long = 5000 + 186; +pub const SYS_llistxattr: c_long = 5000 + 187; +pub const SYS_flistxattr: c_long = 5000 + 188; +pub const SYS_removexattr: c_long = 5000 + 189; +pub const SYS_lremovexattr: c_long = 5000 + 190; +pub const SYS_fremovexattr: c_long = 5000 + 191; +pub const SYS_tkill: c_long = 5000 + 192; +pub const SYS_futex: c_long = 5000 + 194; +pub const SYS_sched_setaffinity: c_long = 5000 + 195; +pub const SYS_sched_getaffinity: c_long = 5000 + 196; +pub const SYS_cacheflush: c_long = 5000 + 197; +pub const SYS_cachectl: c_long = 5000 + 198; +pub const SYS_sysmips: c_long = 5000 + 199; +pub const SYS_io_setup: c_long = 5000 + 200; +pub const SYS_io_destroy: c_long = 5000 + 201; +pub const SYS_io_getevents: c_long = 5000 + 202; +pub const SYS_io_submit: c_long = 5000 + 203; +pub const SYS_io_cancel: c_long = 5000 + 204; +pub const SYS_exit_group: c_long = 5000 + 205; +pub const SYS_lookup_dcookie: c_long = 5000 + 206; +pub const SYS_epoll_create: c_long = 5000 + 207; +pub const SYS_epoll_ctl: c_long = 5000 + 208; +pub const SYS_epoll_wait: c_long = 5000 + 209; +pub const SYS_remap_file_pages: c_long = 5000 + 210; +pub const SYS_rt_sigreturn: c_long = 5000 + 211; +pub const SYS_set_tid_address: c_long = 5000 + 212; +pub const SYS_restart_syscall: c_long = 5000 + 213; +pub const SYS_semtimedop: c_long = 5000 + 214; +pub const SYS_fadvise64: c_long = 5000 + 215; +pub const SYS_timer_create: c_long = 5000 + 216; +pub const SYS_timer_settime: c_long = 5000 + 217; +pub const SYS_timer_gettime: c_long = 5000 + 218; +pub const SYS_timer_getoverrun: c_long = 5000 + 219; +pub const SYS_timer_delete: c_long = 5000 + 220; +pub const SYS_clock_settime: c_long = 5000 + 221; +pub const SYS_clock_gettime: c_long = 5000 + 222; +pub const SYS_clock_getres: c_long = 5000 + 223; +pub const SYS_clock_nanosleep: c_long = 5000 + 224; +pub const SYS_tgkill: c_long = 5000 + 225; +pub const SYS_utimes: c_long = 5000 + 226; +pub const SYS_mbind: c_long = 5000 + 227; +pub const SYS_get_mempolicy: c_long = 5000 + 228; +pub const SYS_set_mempolicy: c_long = 5000 + 229; +pub const SYS_mq_open: c_long = 5000 + 230; +pub const SYS_mq_unlink: c_long = 5000 + 231; +pub const SYS_mq_timedsend: c_long = 5000 + 232; +pub const SYS_mq_timedreceive: c_long = 5000 + 233; +pub const SYS_mq_notify: c_long = 5000 + 234; +pub const SYS_mq_getsetattr: c_long = 5000 + 235; +pub const SYS_vserver: c_long = 5000 + 236; +pub const SYS_waitid: c_long = 5000 + 237; +/* pub const SYS_sys_setaltroot: c_long = 5000 + 238; */ +pub const SYS_add_key: c_long = 5000 + 239; +pub const SYS_request_key: c_long = 5000 + 240; +pub const SYS_keyctl: c_long = 5000 + 241; +pub const SYS_set_thread_area: c_long = 5000 + 242; +pub const SYS_inotify_init: c_long = 5000 + 243; +pub const SYS_inotify_add_watch: c_long = 5000 + 244; +pub const SYS_inotify_rm_watch: c_long = 5000 + 245; +pub const SYS_migrate_pages: c_long = 5000 + 246; +pub const SYS_openat: c_long = 5000 + 247; +pub const SYS_mkdirat: c_long = 5000 + 248; +pub const SYS_mknodat: c_long = 5000 + 249; +pub const SYS_fchownat: c_long = 5000 + 250; +pub const SYS_futimesat: c_long = 5000 + 251; +pub const SYS_newfstatat: c_long = 5000 + 252; +pub const SYS_unlinkat: c_long = 5000 + 253; +pub const SYS_renameat: c_long = 5000 + 254; +pub const SYS_linkat: c_long = 5000 + 255; +pub const SYS_symlinkat: c_long = 5000 + 256; +pub const SYS_readlinkat: c_long = 5000 + 257; +pub const SYS_fchmodat: c_long = 5000 + 258; +pub const SYS_faccessat: c_long = 5000 + 259; +pub const SYS_pselect6: c_long = 5000 + 260; +pub const SYS_ppoll: c_long = 5000 + 261; +pub const SYS_unshare: c_long = 5000 + 262; +pub const SYS_splice: c_long = 5000 + 263; +pub const SYS_sync_file_range: c_long = 5000 + 264; +pub const SYS_tee: c_long = 5000 + 265; +pub const SYS_vmsplice: c_long = 5000 + 266; +pub const SYS_move_pages: c_long = 5000 + 267; +pub const SYS_set_robust_list: c_long = 5000 + 268; +pub const SYS_get_robust_list: c_long = 5000 + 269; +pub const SYS_kexec_load: c_long = 5000 + 270; +pub const SYS_getcpu: c_long = 5000 + 271; +pub const SYS_epoll_pwait: c_long = 5000 + 272; +pub const SYS_ioprio_set: c_long = 5000 + 273; +pub const SYS_ioprio_get: c_long = 5000 + 274; +pub const SYS_utimensat: c_long = 5000 + 275; +pub const SYS_signalfd: c_long = 5000 + 276; +pub const SYS_timerfd: c_long = 5000 + 277; +pub const SYS_eventfd: c_long = 5000 + 278; +pub const SYS_fallocate: c_long = 5000 + 279; +pub const SYS_timerfd_create: c_long = 5000 + 280; +pub const SYS_timerfd_gettime: c_long = 5000 + 281; +pub const SYS_timerfd_settime: c_long = 5000 + 282; +pub const SYS_signalfd4: c_long = 5000 + 283; +pub const SYS_eventfd2: c_long = 5000 + 284; +pub const SYS_epoll_create1: c_long = 5000 + 285; +pub const SYS_dup3: c_long = 5000 + 286; +pub const SYS_pipe2: c_long = 5000 + 287; +pub const SYS_inotify_init1: c_long = 5000 + 288; +pub const SYS_preadv: c_long = 5000 + 289; +pub const SYS_pwritev: c_long = 5000 + 290; +pub const SYS_rt_tgsigqueueinfo: c_long = 5000 + 291; +pub const SYS_perf_event_open: c_long = 5000 + 292; +pub const SYS_accept4: c_long = 5000 + 293; +pub const SYS_recvmmsg: c_long = 5000 + 294; +pub const SYS_fanotify_init: c_long = 5000 + 295; +pub const SYS_fanotify_mark: c_long = 5000 + 296; +pub const SYS_prlimit64: c_long = 5000 + 297; +pub const SYS_name_to_handle_at: c_long = 5000 + 298; +pub const SYS_open_by_handle_at: c_long = 5000 + 299; +pub const SYS_clock_adjtime: c_long = 5000 + 300; +pub const SYS_syncfs: c_long = 5000 + 301; +pub const SYS_sendmmsg: c_long = 5000 + 302; +pub const SYS_setns: c_long = 5000 + 303; +pub const SYS_process_vm_readv: c_long = 5000 + 304; +pub const SYS_process_vm_writev: c_long = 5000 + 305; +pub const SYS_kcmp: c_long = 5000 + 306; +pub const SYS_finit_module: c_long = 5000 + 307; +pub const SYS_getdents64: c_long = 5000 + 308; +pub const SYS_sched_setattr: c_long = 5000 + 309; +pub const SYS_sched_getattr: c_long = 5000 + 310; +pub const SYS_renameat2: c_long = 5000 + 311; +pub const SYS_seccomp: c_long = 5000 + 312; +pub const SYS_getrandom: c_long = 5000 + 313; +pub const SYS_memfd_create: c_long = 5000 + 314; +pub const SYS_bpf: c_long = 5000 + 315; +pub const SYS_execveat: c_long = 5000 + 316; +pub const SYS_userfaultfd: c_long = 5000 + 317; +pub const SYS_membarrier: c_long = 5000 + 318; +pub const SYS_mlock2: c_long = 5000 + 319; +pub const SYS_copy_file_range: c_long = 5000 + 320; +pub const SYS_preadv2: c_long = 5000 + 321; +pub const SYS_pwritev2: c_long = 5000 + 322; +pub const SYS_pkey_mprotect: c_long = 5000 + 323; +pub const SYS_pkey_alloc: c_long = 5000 + 324; +pub const SYS_pkey_free: c_long = 5000 + 325; +pub const SYS_statx: c_long = 5000 + 326; +pub const SYS_rseq: c_long = 5000 + 327; +pub const SYS_pidfd_send_signal: c_long = 5000 + 424; +pub const SYS_io_uring_setup: c_long = 5000 + 425; +pub const SYS_io_uring_enter: c_long = 5000 + 426; +pub const SYS_io_uring_register: c_long = 5000 + 427; +pub const SYS_open_tree: c_long = 5000 + 428; +pub const SYS_move_mount: c_long = 5000 + 429; +pub const SYS_fsopen: c_long = 5000 + 430; +pub const SYS_fsconfig: c_long = 5000 + 431; +pub const SYS_fsmount: c_long = 5000 + 432; +pub const SYS_fspick: c_long = 5000 + 433; +pub const SYS_pidfd_open: c_long = 5000 + 434; +pub const SYS_clone3: c_long = 5000 + 435; +pub const SYS_close_range: c_long = 5000 + 436; +pub const SYS_openat2: c_long = 5000 + 437; +pub const SYS_pidfd_getfd: c_long = 5000 + 438; +pub const SYS_faccessat2: c_long = 5000 + 439; +pub const SYS_process_madvise: c_long = 5000 + 440; +pub const SYS_epoll_pwait2: c_long = 5000 + 441; +pub const SYS_mount_setattr: c_long = 5000 + 442; +pub const SYS_quotactl_fd: c_long = 5000 + 443; +pub const SYS_landlock_create_ruleset: c_long = 5000 + 444; +pub const SYS_landlock_add_rule: c_long = 5000 + 445; +pub const SYS_landlock_restrict_self: c_long = 5000 + 446; +pub const SYS_memfd_secret: c_long = 5000 + 447; +pub const SYS_process_mrelease: c_long = 5000 + 448; +pub const SYS_futex_waitv: c_long = 5000 + 449; +pub const SYS_set_mempolicy_home_node: c_long = 5000 + 450; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; + +pub const O_NOATIME: c_int = 0o1000000; +pub const O_CLOEXEC: c_int = 0x80000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const O_DIRECT: c_int = 0x8000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 256; +pub const O_EXCL: c_int = 1024; +pub const O_NOCTTY: c_int = 2048; +pub const O_NONBLOCK: c_int = 128; +pub const O_SYNC: c_int = 0x4010; +pub const O_RSYNC: c_int = 0x4010; +pub const O_DSYNC: c_int = 0x10; +pub const O_FSYNC: c_int = 0x4010; +pub const O_ASYNC: c_int = 0x1000; +pub const O_NDELAY: c_int = 0x80; + +pub const EDEADLK: c_int = 45; +pub const ENAMETOOLONG: c_int = 78; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 89; +pub const ENOTEMPTY: c_int = 93; +pub const ELOOP: c_int = 90; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EMULTIHOP: c_int = 74; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EBADMSG: c_int = 77; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; +pub const EUCLEAN: c_int = 135; +pub const ENOTNAM: c_int = 137; +pub const ENAVAIL: c_int = 138; +pub const EISNAM: c_int = 139; +pub const EREMOTEIO: c_int = 140; +pub const EDQUOT: c_int = 1133; +pub const ENOMEDIUM: c_int = 159; +pub const EMEDIUMTYPE: c_int = 160; +pub const ECANCELED: c_int = 158; +pub const ENOKEY: c_int = 161; +pub const EKEYEXPIRED: c_int = 162; +pub const EKEYREVOKED: c_int = 163; +pub const EKEYREJECTED: c_int = 164; +pub const EOWNERDEAD: c_int = 165; +pub const ENOTRECOVERABLE: c_int = 166; +pub const ERFKILL: c_int = 167; + +pub const MAP_NORESERVE: c_int = 0x400; +pub const MAP_ANON: c_int = 0x800; +pub const MAP_ANONYMOUS: c_int = 0x800; +pub const MAP_GROWSDOWN: c_int = 0x1000; +pub const MAP_DENYWRITE: c_int = 0x2000; +pub const MAP_EXECUTABLE: c_int = 0x4000; +pub const MAP_LOCKED: c_int = 0x8000; +pub const MAP_POPULATE: c_int = 0x10000; +pub const MAP_NONBLOCK: c_int = 0x20000; +pub const MAP_STACK: c_int = 0x40000; +pub const MAP_HUGETLB: c_int = 0x080000; + +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_DGRAM: c_int = 1; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000008; +pub const SA_NOCLDWAIT: c_int = 0x00010000; + +pub const SIGEMT: c_int = 7; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = 22; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 22; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 0x1; +pub const SIG_UNBLOCK: c_int = 0x2; + +pub const POLLWRNORM: c_short = 0x004; +pub const POLLWRBAND: c_short = 0x100; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x00000100; +pub const TOSTOP: crate::tcflag_t = 0x00008000; +pub const FLUSHO: crate::tcflag_t = 0x00002000; +pub const EXTPROC: crate::tcflag_t = 0o200000; +pub const TCSANOW: c_int = 0x540e; +pub const TCSADRAIN: c_int = 0x540f; +pub const TCSAFLUSH: c_int = 0x5410; + +pub const PTRACE_GETFPREGS: c_uint = 14; +pub const PTRACE_SETFPREGS: c_uint = 15; +pub const PTRACE_DETACH: c_uint = 17; +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_GETREGS: c_uint = 12; +pub const PTRACE_SETREGS: c_uint = 13; + +pub const EFD_NONBLOCK: c_int = 0x80; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; +pub const F_GETLK: c_int = 14; +pub const F_GETOWN: c_int = 23; +pub const F_SETOWN: c_int = 24; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const SFD_NONBLOCK: c_int = 0x80; + +pub const RTLD_DEEPBIND: c_int = 0x10; +pub const RTLD_GLOBAL: c_int = 0x4; +pub const RTLD_NOLOAD: c_int = 0x8; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EHWPOISON: c_int = 168; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mod.rs new file mode 100644 index 00000000000000..3d442a6d8129de --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/mod.rs @@ -0,0 +1,213 @@ +//! 64-bit specific definitions for linux-like values + +use crate::prelude::*; + +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; +pub type shmatt_t = u64; +pub type msgqnum_t = u64; +pub type msglen_t = u64; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type rlim_t = u64; +#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +pub type __syscall_ulong_t = c_ulonglong; +#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +pub type __syscall_ulong_t = c_ulong; + +cfg_if! { + if #[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))] { + pub type clock_t = i32; + pub type time_t = i32; + pub type __fsword_t = i32; + } else { + pub type __fsword_t = i64; + pub type clock_t = i64; + pub type time_t = i64; + } +} + +s! { + pub struct sigset_t { + #[cfg(target_pointer_width = "32")] + __val: [u32; 32], + #[cfg(target_pointer_width = "64")] + __val: [u64; 16], + } + + pub struct sysinfo { + pub uptime: i64, + pub loads: [u64; 3], + pub totalram: u64, + pub freeram: u64, + pub sharedram: u64, + pub bufferram: u64, + pub totalswap: u64, + pub freeswap: u64, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: u64, + pub freehigh: u64, + pub mem_unit: c_uint, + pub _f: [c_char; 0], + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: u64, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct semid_ds { + pub sem_perm: ipc_perm, + pub sem_otime: crate::time_t, + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "loongarch64", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "sparc64", + target_arch = "s390x", + )))] + __reserved: Padding, + pub sem_ctime: crate::time_t, + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "loongarch64", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "sparc64", + target_arch = "s390x", + )))] + __reserved2: Padding, + pub sem_nsems: crate::__syscall_ulong_t, + __glibc_reserved3: Padding, + __glibc_reserved4: Padding, + } + + pub struct timex { + pub modes: c_uint, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub offset: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub offset: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub freq: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub freq: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub maxerror: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub maxerror: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub esterror: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub esterror: c_long, + pub status: c_int, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub constant: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub constant: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub precision: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub precision: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub tolerance: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub tolerance: c_long, + pub time: crate::timeval, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub tick: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub tick: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub ppsfreq: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub ppsfreq: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub jitter: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub jitter: c_long, + pub shift: c_int, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub stabil: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub stabil: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub jitcnt: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub jitcnt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub calcnt: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub calcnt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub errcnt: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub errcnt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub stbcnt: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub stbcnt: c_long, + pub tai: c_int, + pub __unused1: i32, + pub __unused2: i32, + pub __unused3: i32, + pub __unused4: i32, + pub __unused5: i32, + pub __unused6: i32, + pub __unused7: i32, + pub __unused8: i32, + pub __unused9: i32, + pub __unused10: i32, + pub __unused11: i32, + } +} + +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const O_LARGEFILE: c_int = 0; + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "powerpc64"))] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(any(target_arch = "sparc64"))] { + mod sparc64; + pub use self::sparc64::*; + } else if #[cfg(any(target_arch = "mips64", target_arch = "mips64r6"))] { + mod mips64; + pub use self::mips64::*; + } else if #[cfg(any(target_arch = "s390x"))] { + mod s390x; + pub use self::s390x::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(any(target_arch = "riscv64"))] { + mod riscv64; + pub use self::riscv64::*; + } else if #[cfg(any(target_arch = "loongarch64"))] { + mod loongarch64; + pub use self::loongarch64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs new file mode 100644 index 00000000000000..ee2cd21dec7834 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs @@ -0,0 +1,1062 @@ +//! PowerPC64-specific definitions for 64-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, + pthread_mutex_t, +}; + +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = i64; +pub type suseconds_t = i64; +pub type __u64 = c_ulong; +pub type __s64 = c_long; +pub type gregset_t = [c_ulong; __NGREG]; +pub type fpregset_t = [c_ulong; __NFPREG]; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + #[cfg(target_arch = "sparc64")] + __reserved0: Padding, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + f_spare: [crate::__fsword_t; 5], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __reserved: Padding<[c_long; 3]>, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u64; 7], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: u32, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [i64; 4], + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + pub struct pt_regs { + pub gpr: [c_ulong; 32], + pub nip: c_ulong, + pub msr: c_ulong, + pub orig_gpr3: c_ulong, + pub ctr: c_ulong, + pub link: c_ulong, + pub xer: c_ulong, + pub ccr: c_ulong, + pub softe: c_ulong, + pub trap: c_ulong, + pub dar: c_ulong, + pub dsisr: c_ulong, + pub result: c_ulong, + } + + pub struct mcontext_t { + __glibc_reserved: Padding<[c_ulong; 4]>, + pub signal: c_int, + __pad0: Padding, + pub handler: c_ulong, + pub oldmask: c_ulong, + pub regs: *mut pt_regs, + pub gp_regs: crate::gregset_t, + pub fp_regs: crate::fpregset_t, + pub v_regs: *mut vrregset_t, + pub vmx_reserve: [c_long; __NVRREG + __NVRREG + 1], + } + + #[repr(align(16))] + pub struct vrregset_t { + pub vrregs: [[c_uint; 4]; 32], + pub vscr: vscr_t, + pub vrsave: c_uint, + __pad: Padding<[c_uint; 3]>, + } + + #[repr(align(4))] + pub struct vscr_t { + #[cfg(target_endian = "big")] + __pad: Padding<[c_uint; 3]>, + #[cfg(target_endian = "big")] + pub vscr_word: c_uint, + + #[cfg(target_endian = "little")] + pub vscr_word: c_uint, + #[cfg(target_endian = "little")] + __pad: Padding<[c_uint; 3]>, + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const VEOF: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +pub const __NGREG: usize = 48; +pub const __NFPREG: usize = 33; +pub const __NVRREG: usize = 34; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const PTRACE_DETACH: c_uint = 17; + +pub const EFD_NONBLOCK: c_int = 0x800; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; + +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; + +pub const O_CLOEXEC: c_int = 0x80000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_DIRECT: c_int = 0x20000; + +pub const MAP_LOCKED: c_int = 0x00080; +pub const MAP_NORESERVE: c_int = 0x00040; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 58; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; + +pub const SIGSTKSZ: size_t = 0x4000; +pub const MINSIGSTKSZ: size_t = 4096; +pub const CBAUD: crate::tcflag_t = 0xff; +pub const TAB1: crate::tcflag_t = 0x400; +pub const TAB2: crate::tcflag_t = 0x800; +pub const TAB3: crate::tcflag_t = 0xc00; +pub const CR1: crate::tcflag_t = 0x1000; +pub const CR2: crate::tcflag_t = 0x2000; +pub const CR3: crate::tcflag_t = 0x3000; +pub const FF1: crate::tcflag_t = 0x4000; +pub const BS1: crate::tcflag_t = 0x8000; +pub const VT1: crate::tcflag_t = 0x10000; +pub const VWERASE: usize = 0xa; +pub const VREPRINT: usize = 0xb; +pub const VSUSP: usize = 0xc; +pub const VSTART: usize = 0xd; +pub const VSTOP: usize = 0xe; +pub const VDISCARD: usize = 0x10; +pub const VTIME: usize = 0x7; +pub const IXON: crate::tcflag_t = 0x200; +pub const IXOFF: crate::tcflag_t = 0x400; +pub const ONLCR: crate::tcflag_t = 0x2; +pub const CSIZE: crate::tcflag_t = 0x300; +pub const CS6: crate::tcflag_t = 0x100; +pub const CS7: crate::tcflag_t = 0x200; +pub const CS8: crate::tcflag_t = 0x300; +pub const CSTOPB: crate::tcflag_t = 0x400; +pub const CREAD: crate::tcflag_t = 0x800; +pub const PARENB: crate::tcflag_t = 0x1000; +pub const PARODD: crate::tcflag_t = 0x2000; +pub const HUPCL: crate::tcflag_t = 0x4000; +pub const CLOCAL: crate::tcflag_t = 0x8000; +pub const ECHOKE: crate::tcflag_t = 0x1; +pub const ECHOE: crate::tcflag_t = 0x2; +pub const ECHOK: crate::tcflag_t = 0x4; +pub const ECHONL: crate::tcflag_t = 0x10; +pub const ECHOPRT: crate::tcflag_t = 0x20; +pub const ECHOCTL: crate::tcflag_t = 0x40; +pub const ISIG: crate::tcflag_t = 0x80; +pub const ICANON: crate::tcflag_t = 0x100; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x80000000; +pub const VSWTC: usize = 9; +pub const OLCUC: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o001400; +pub const CRDLY: crate::tcflag_t = 0o030000; +pub const TABDLY: crate::tcflag_t = 0o006000; +pub const BSDLY: crate::tcflag_t = 0o100000; +pub const FFDLY: crate::tcflag_t = 0o040000; +pub const VTDLY: crate::tcflag_t = 0o200000; +pub const XTABS: crate::tcflag_t = 0o006000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const CBAUDEX: crate::speed_t = 0o000020; +pub const B57600: crate::speed_t = 0o0020; +pub const B115200: crate::speed_t = 0o0021; +pub const B230400: crate::speed_t = 0o0022; +pub const B460800: crate::speed_t = 0o0023; +pub const B500000: crate::speed_t = 0o0024; +pub const B576000: crate::speed_t = 0o0025; +pub const B921600: crate::speed_t = 0o0026; +pub const B1000000: crate::speed_t = 0o0027; +pub const B1152000: crate::speed_t = 0o0030; +pub const B1500000: crate::speed_t = 0o0031; +pub const B2000000: crate::speed_t = 0o0032; +pub const B2500000: crate::speed_t = 0o0033; +pub const B3000000: crate::speed_t = 0o0034; +pub const B3500000: crate::speed_t = 0o0035; +pub const B4000000: crate::speed_t = 0o0036; + +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: crate::tcflag_t = 0x400; +pub const TOSTOP: crate::tcflag_t = 0x400000; +pub const FLUSHO: crate::tcflag_t = 0x800000; +pub const EXTPROC: crate::tcflag_t = 0x10000000; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 166; +pub const SYS_poll: c_long = 167; +pub const SYS_nfsservctl: c_long = 168; +pub const SYS_setresgid: c_long = 169; +pub const SYS_getresgid: c_long = 170; +pub const SYS_prctl: c_long = 171; +pub const SYS_rt_sigreturn: c_long = 172; +pub const SYS_rt_sigaction: c_long = 173; +pub const SYS_rt_sigprocmask: c_long = 174; +pub const SYS_rt_sigpending: c_long = 175; +pub const SYS_rt_sigtimedwait: c_long = 176; +pub const SYS_rt_sigqueueinfo: c_long = 177; +pub const SYS_rt_sigsuspend: c_long = 178; +pub const SYS_pread64: c_long = 179; +pub const SYS_pwrite64: c_long = 180; +pub const SYS_chown: c_long = 181; +pub const SYS_getcwd: c_long = 182; +pub const SYS_capget: c_long = 183; +pub const SYS_capset: c_long = 184; +pub const SYS_sigaltstack: c_long = 185; +pub const SYS_sendfile: c_long = 186; +pub const SYS_getpmsg: c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: c_long = 189; +pub const SYS_ugetrlimit: c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: c_long = 191; +pub const SYS_pciconfig_read: c_long = 198; +pub const SYS_pciconfig_write: c_long = 199; +pub const SYS_pciconfig_iobase: c_long = 200; +pub const SYS_multiplexer: c_long = 201; +pub const SYS_getdents64: c_long = 202; +pub const SYS_pivot_root: c_long = 203; +pub const SYS_madvise: c_long = 205; +pub const SYS_mincore: c_long = 206; +pub const SYS_gettid: c_long = 207; +pub const SYS_tkill: c_long = 208; +pub const SYS_setxattr: c_long = 209; +pub const SYS_lsetxattr: c_long = 210; +pub const SYS_fsetxattr: c_long = 211; +pub const SYS_getxattr: c_long = 212; +pub const SYS_lgetxattr: c_long = 213; +pub const SYS_fgetxattr: c_long = 214; +pub const SYS_listxattr: c_long = 215; +pub const SYS_llistxattr: c_long = 216; +pub const SYS_flistxattr: c_long = 217; +pub const SYS_removexattr: c_long = 218; +pub const SYS_lremovexattr: c_long = 219; +pub const SYS_fremovexattr: c_long = 220; +pub const SYS_futex: c_long = 221; +pub const SYS_sched_setaffinity: c_long = 222; +pub const SYS_sched_getaffinity: c_long = 223; +pub const SYS_tuxcall: c_long = 225; +pub const SYS_io_setup: c_long = 227; +pub const SYS_io_destroy: c_long = 228; +pub const SYS_io_getevents: c_long = 229; +pub const SYS_io_submit: c_long = 230; +pub const SYS_io_cancel: c_long = 231; +pub const SYS_set_tid_address: c_long = 232; +pub const SYS_exit_group: c_long = 234; +pub const SYS_lookup_dcookie: c_long = 235; +pub const SYS_epoll_create: c_long = 236; +pub const SYS_epoll_ctl: c_long = 237; +pub const SYS_epoll_wait: c_long = 238; +pub const SYS_remap_file_pages: c_long = 239; +pub const SYS_timer_create: c_long = 240; +pub const SYS_timer_settime: c_long = 241; +pub const SYS_timer_gettime: c_long = 242; +pub const SYS_timer_getoverrun: c_long = 243; +pub const SYS_timer_delete: c_long = 244; +pub const SYS_clock_settime: c_long = 245; +pub const SYS_clock_gettime: c_long = 246; +pub const SYS_clock_getres: c_long = 247; +pub const SYS_clock_nanosleep: c_long = 248; +pub const SYS_swapcontext: c_long = 249; +pub const SYS_tgkill: c_long = 250; +pub const SYS_utimes: c_long = 251; +pub const SYS_statfs64: c_long = 252; +pub const SYS_fstatfs64: c_long = 253; +pub const SYS_rtas: c_long = 255; +pub const SYS_sys_debug_setcontext: c_long = 256; +pub const SYS_migrate_pages: c_long = 258; +pub const SYS_mbind: c_long = 259; +pub const SYS_get_mempolicy: c_long = 260; +pub const SYS_set_mempolicy: c_long = 261; +pub const SYS_mq_open: c_long = 262; +pub const SYS_mq_unlink: c_long = 263; +pub const SYS_mq_timedsend: c_long = 264; +pub const SYS_mq_timedreceive: c_long = 265; +pub const SYS_mq_notify: c_long = 266; +pub const SYS_mq_getsetattr: c_long = 267; +pub const SYS_kexec_load: c_long = 268; +pub const SYS_add_key: c_long = 269; +pub const SYS_request_key: c_long = 270; +pub const SYS_keyctl: c_long = 271; +pub const SYS_waitid: c_long = 272; +pub const SYS_ioprio_set: c_long = 273; +pub const SYS_ioprio_get: c_long = 274; +pub const SYS_inotify_init: c_long = 275; +pub const SYS_inotify_add_watch: c_long = 276; +pub const SYS_inotify_rm_watch: c_long = 277; +pub const SYS_spu_run: c_long = 278; +pub const SYS_spu_create: c_long = 279; +pub const SYS_pselect6: c_long = 280; +pub const SYS_ppoll: c_long = 281; +pub const SYS_unshare: c_long = 282; +pub const SYS_splice: c_long = 283; +pub const SYS_tee: c_long = 284; +pub const SYS_vmsplice: c_long = 285; +pub const SYS_openat: c_long = 286; +pub const SYS_mkdirat: c_long = 287; +pub const SYS_mknodat: c_long = 288; +pub const SYS_fchownat: c_long = 289; +pub const SYS_futimesat: c_long = 290; +pub const SYS_newfstatat: c_long = 291; +pub const SYS_unlinkat: c_long = 292; +pub const SYS_renameat: c_long = 293; +pub const SYS_linkat: c_long = 294; +pub const SYS_symlinkat: c_long = 295; +pub const SYS_readlinkat: c_long = 296; +pub const SYS_fchmodat: c_long = 297; +pub const SYS_faccessat: c_long = 298; +pub const SYS_get_robust_list: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_move_pages: c_long = 301; +pub const SYS_getcpu: c_long = 302; +pub const SYS_epoll_pwait: c_long = 303; +pub const SYS_utimensat: c_long = 304; +pub const SYS_signalfd: c_long = 305; +pub const SYS_timerfd_create: c_long = 306; +pub const SYS_eventfd: c_long = 307; +pub const SYS_sync_file_range2: c_long = 308; +pub const SYS_fallocate: c_long = 309; +pub const SYS_subpage_prot: c_long = 310; +pub const SYS_timerfd_settime: c_long = 311; +pub const SYS_timerfd_gettime: c_long = 312; +pub const SYS_signalfd4: c_long = 313; +pub const SYS_eventfd2: c_long = 314; +pub const SYS_epoll_create1: c_long = 315; +pub const SYS_dup3: c_long = 316; +pub const SYS_pipe2: c_long = 317; +pub const SYS_inotify_init1: c_long = 318; +pub const SYS_perf_event_open: c_long = 319; +pub const SYS_preadv: c_long = 320; +pub const SYS_pwritev: c_long = 321; +pub const SYS_rt_tgsigqueueinfo: c_long = 322; +pub const SYS_fanotify_init: c_long = 323; +pub const SYS_fanotify_mark: c_long = 324; +pub const SYS_prlimit64: c_long = 325; +pub const SYS_socket: c_long = 326; +pub const SYS_bind: c_long = 327; +pub const SYS_connect: c_long = 328; +pub const SYS_listen: c_long = 329; +pub const SYS_accept: c_long = 330; +pub const SYS_getsockname: c_long = 331; +pub const SYS_getpeername: c_long = 332; +pub const SYS_socketpair: c_long = 333; +pub const SYS_send: c_long = 334; +pub const SYS_sendto: c_long = 335; +pub const SYS_recv: c_long = 336; +pub const SYS_recvfrom: c_long = 337; +pub const SYS_shutdown: c_long = 338; +pub const SYS_setsockopt: c_long = 339; +pub const SYS_getsockopt: c_long = 340; +pub const SYS_sendmsg: c_long = 341; +pub const SYS_recvmsg: c_long = 342; +pub const SYS_recvmmsg: c_long = 343; +pub const SYS_accept4: c_long = 344; +pub const SYS_name_to_handle_at: c_long = 345; +pub const SYS_open_by_handle_at: c_long = 346; +pub const SYS_clock_adjtime: c_long = 347; +pub const SYS_syncfs: c_long = 348; +pub const SYS_sendmmsg: c_long = 349; +pub const SYS_setns: c_long = 350; +pub const SYS_process_vm_readv: c_long = 351; +pub const SYS_process_vm_writev: c_long = 352; +pub const SYS_finit_module: c_long = 353; +pub const SYS_kcmp: c_long = 354; +pub const SYS_sched_setattr: c_long = 355; +pub const SYS_sched_getattr: c_long = 356; +pub const SYS_renameat2: c_long = 357; +pub const SYS_seccomp: c_long = 358; +pub const SYS_getrandom: c_long = 359; +pub const SYS_memfd_create: c_long = 360; +pub const SYS_bpf: c_long = 361; +pub const SYS_execveat: c_long = 362; +pub const SYS_switch_endian: c_long = 363; +pub const SYS_userfaultfd: c_long = 364; +pub const SYS_membarrier: c_long = 365; +pub const SYS_mlock2: c_long = 378; +pub const SYS_copy_file_range: c_long = 379; +pub const SYS_preadv2: c_long = 380; +pub const SYS_pwritev2: c_long = 381; +pub const SYS_kexec_file_load: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_rseq: c_long = 387; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + + pub fn getcontext(ucp: *mut ucontext_t) -> c_int; + pub fn setcontext(ucp: *const ucontext_t) -> c_int; + pub fn swapcontext(oucp: *mut ucontext_t, ucp: *const ucontext_t) -> c_int; + pub fn makecontext(ucp: *mut ucontext_t, func: extern "C" fn(), argc: c_int, ...); +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs new file mode 100644 index 00000000000000..cbb1502ebcc012 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs @@ -0,0 +1,918 @@ +//! RISC-V-specific definitions for 64-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = c_int; + +pub type nlink_t = c_uint; +pub type blksize_t = c_int; +pub type fsblkcnt64_t = c_ulong; +pub type fsfilcnt64_t = c_ulong; +pub type suseconds_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct pthread_attr_t { + __size: [c_ulong; 7], + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub __pad1: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub __pad2: c_int, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2usize]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub __pad1: crate::dev_t, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub __pad2: c_int, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2]>, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_frsize: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 4], + } + + pub struct statfs64 { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_frsize: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 4], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_favail: crate::fsfilcnt64_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub __f_spare: [c_int; 6], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [u64; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused5: Padding, + __unused6: Padding, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct user_regs_struct { + pub pc: c_ulong, + pub ra: c_ulong, + pub sp: c_ulong, + pub gp: c_ulong, + pub tp: c_ulong, + pub t0: c_ulong, + pub t1: c_ulong, + pub t2: c_ulong, + pub s0: c_ulong, + pub s1: c_ulong, + pub a0: c_ulong, + pub a1: c_ulong, + pub a2: c_ulong, + pub a3: c_ulong, + pub a4: c_ulong, + pub a5: c_ulong, + pub a6: c_ulong, + pub a7: c_ulong, + pub s2: c_ulong, + pub s3: c_ulong, + pub s4: c_ulong, + pub s5: c_ulong, + pub s6: c_ulong, + pub s7: c_ulong, + pub s8: c_ulong, + pub s9: c_ulong, + pub s10: c_ulong, + pub s11: c_ulong, + pub t3: c_ulong, + pub t4: c_ulong, + pub t5: c_ulong, + pub t6: c_ulong, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + pub struct ucontext_t { + pub __uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub __gregs: [c_ulong; 32], + pub __fpregs: __riscv_mc_fp_state, + } + + pub union __riscv_mc_fp_state { + pub __f: __riscv_mc_f_ext_state, + pub __d: __riscv_mc_d_ext_state, + pub __q: __riscv_mc_q_ext_state, + } + + pub struct __riscv_mc_f_ext_state { + pub __f: [c_uint; 32], + pub __fcsr: c_uint, + } + + pub struct __riscv_mc_d_ext_state { + pub __f: [c_ulonglong; 32], + pub __fcsr: c_uint, + } + + #[repr(align(16))] + pub struct __riscv_mc_q_ext_state { + pub __f: [c_ulonglong; 64], + pub __fcsr: c_uint, + pub __glibc_reserved: [c_uint; 3], + } + + #[repr(align(16))] + pub struct max_align_t { + priv_: [f32; 8], + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 1052672; +pub const O_NOATIME: c_int = 262144; +pub const O_PATH: c_int = 2097152; +pub const O_TMPFILE: c_int = 4259840; +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 256; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SA_ONSTACK: c_int = 134217728; +pub const SA_SIGINFO: c_int = 4; +pub const SA_NOCLDWAIT: c_int = 2; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const POLLWRNORM: c_short = 256; +pub const POLLWRBAND: c_short = 512; +pub const O_ASYNC: c_int = 8192; +pub const O_NDELAY: c_int = 2048; +pub const PTRACE_DETACH: c_uint = 17; +pub const EFD_NONBLOCK: c_int = 2048; +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; +pub const SFD_NONBLOCK: c_int = 2048; +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; +pub const SFD_CLOEXEC: c_int = 524288; +pub const NCCS: usize = 32; +pub const O_TRUNC: c_int = 512; +pub const O_CLOEXEC: c_int = 524288; +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; +pub const SA_NODEFER: c_int = 1073741824; +pub const SA_RESETHAND: c_int = -2147483648; +pub const SA_RESTART: c_int = 268435456; +pub const SA_NOCLDSTOP: c_int = 1; +pub const EPOLL_CLOEXEC: c_int = 524288; +pub const EFD_CLOEXEC: c_int = 524288; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const O_DIRECT: c_int = 16384; +pub const O_DIRECTORY: c_int = 65536; +pub const O_NOFOLLOW: c_int = 131072; +pub const MAP_HUGETLB: c_int = 262144; +pub const MAP_LOCKED: c_int = 8192; +pub const MAP_NORESERVE: c_int = 16384; +pub const MAP_ANON: c_int = 32; +pub const MAP_ANONYMOUS: c_int = 32; +pub const MAP_DENYWRITE: c_int = 2048; +pub const MAP_EXECUTABLE: c_int = 4096; +pub const MAP_POPULATE: c_int = 32768; +pub const MAP_NONBLOCK: c_int = 65536; +pub const MAP_STACK: c_int = 131072; +pub const MAP_SYNC: c_int = 0x080000; +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const PTRACE_GETFPREGS: c_uint = 14; +pub const PTRACE_SETFPREGS: c_uint = 15; +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_GETREGS: c_uint = 12; +pub const PTRACE_SETREGS: c_uint = 13; +pub const MCL_CURRENT: c_int = 1; +pub const MCL_FUTURE: c_int = 2; +pub const MCL_ONFAULT: c_int = 4; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 4111; +pub const TAB1: crate::tcflag_t = 2048; +pub const TAB2: crate::tcflag_t = 4096; +pub const TAB3: crate::tcflag_t = 6144; +pub const CR1: crate::tcflag_t = 512; +pub const CR2: crate::tcflag_t = 1024; +pub const CR3: crate::tcflag_t = 1536; +pub const FF1: crate::tcflag_t = 32768; +pub const BS1: crate::tcflag_t = 8192; +pub const VT1: crate::tcflag_t = 16384; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 1024; +pub const IXOFF: crate::tcflag_t = 4096; +pub const ONLCR: crate::tcflag_t = 4; +pub const CSIZE: crate::tcflag_t = 48; +pub const CS6: crate::tcflag_t = 16; +pub const CS7: crate::tcflag_t = 32; +pub const CS8: crate::tcflag_t = 48; +pub const CSTOPB: crate::tcflag_t = 64; +pub const CREAD: crate::tcflag_t = 128; +pub const PARENB: crate::tcflag_t = 256; +pub const PARODD: crate::tcflag_t = 512; +pub const HUPCL: crate::tcflag_t = 1024; +pub const CLOCAL: crate::tcflag_t = 2048; +pub const ECHOKE: crate::tcflag_t = 2048; +pub const ECHOE: crate::tcflag_t = 16; +pub const ECHOK: crate::tcflag_t = 32; +pub const ECHONL: crate::tcflag_t = 64; +pub const ECHOPRT: crate::tcflag_t = 1024; +pub const ECHOCTL: crate::tcflag_t = 512; +pub const ISIG: crate::tcflag_t = 1; +pub const ICANON: crate::tcflag_t = 2; +pub const PENDIN: crate::tcflag_t = 16384; +pub const NOFLSH: crate::tcflag_t = 128; +pub const CIBAUD: crate::tcflag_t = 269418496; +pub const CBAUDEX: crate::tcflag_t = 4096; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 2; +pub const NLDLY: crate::tcflag_t = 256; +pub const CRDLY: crate::tcflag_t = 1536; +pub const TABDLY: crate::tcflag_t = 6144; +pub const BSDLY: crate::tcflag_t = 8192; +pub const FFDLY: crate::tcflag_t = 32768; +pub const VTDLY: crate::tcflag_t = 16384; +pub const XTABS: crate::tcflag_t = 6144; +pub const B0: crate::speed_t = 0; +pub const B50: crate::speed_t = 1; +pub const B75: crate::speed_t = 2; +pub const B110: crate::speed_t = 3; +pub const B134: crate::speed_t = 4; +pub const B150: crate::speed_t = 5; +pub const B200: crate::speed_t = 6; +pub const B300: crate::speed_t = 7; +pub const B600: crate::speed_t = 8; +pub const B1200: crate::speed_t = 9; +pub const B1800: crate::speed_t = 10; +pub const B2400: crate::speed_t = 11; +pub const B4800: crate::speed_t = 12; +pub const B9600: crate::speed_t = 13; +pub const B19200: crate::speed_t = 14; +pub const B38400: crate::speed_t = 15; +pub const EXTA: crate::speed_t = 14; +pub const EXTB: crate::speed_t = 15; +pub const B57600: crate::speed_t = 4097; +pub const B115200: crate::speed_t = 4098; +pub const B230400: crate::speed_t = 4099; +pub const B460800: crate::speed_t = 4100; +pub const B500000: crate::speed_t = 4101; +pub const B576000: crate::speed_t = 4102; +pub const B921600: crate::speed_t = 4103; +pub const B1000000: crate::speed_t = 4104; +pub const B1152000: crate::speed_t = 4105; +pub const B1500000: crate::speed_t = 4106; +pub const B2000000: crate::speed_t = 4107; +pub const B2500000: crate::speed_t = 4108; +pub const B3000000: crate::speed_t = 4109; +pub const B3500000: crate::speed_t = 4110; +pub const B4000000: crate::speed_t = 4111; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 32768; +pub const TOSTOP: crate::tcflag_t = 256; +pub const FLUSHO: crate::tcflag_t = 4096; +pub const EXTPROC: crate::tcflag_t = 65536; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const NGREG: usize = 32; +pub const REG_PC: usize = 0; +pub const REG_RA: usize = 1; +pub const REG_SP: usize = 2; +pub const REG_TP: usize = 4; +pub const REG_S0: usize = 8; +pub const REG_S1: usize = 9; +pub const REG_A0: usize = 10; +pub const REG_S2: usize = 18; +pub const REG_NARGS: usize = 8; + +pub const COMPAT_HWCAP_ISA_I: c_ulong = 1 << (b'I' - b'A'); +pub const COMPAT_HWCAP_ISA_M: c_ulong = 1 << (b'M' - b'A'); +#[allow(clippy::eq_op)] +pub const COMPAT_HWCAP_ISA_A: c_ulong = 1 << (b'A' - b'A'); +pub const COMPAT_HWCAP_ISA_F: c_ulong = 1 << (b'F' - b'A'); +pub const COMPAT_HWCAP_ISA_D: c_ulong = 1 << (b'D' - b'A'); +pub const COMPAT_HWCAP_ISA_C: c_ulong = 1 << (b'C' - b'A'); +pub const COMPAT_HWCAP_ISA_V: c_ulong = 1 << (b'V' - b'A'); + +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_close: c_long = 57; +pub const SYS_fstat: c_long = 80; +pub const SYS_lseek: c_long = 62; +pub const SYS_mmap: c_long = 222; +pub const SYS_mprotect: c_long = 226; +pub const SYS_munmap: c_long = 215; +pub const SYS_brk: c_long = 214; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_ioctl: c_long = 29; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_mremap: c_long = 216; +pub const SYS_msync: c_long = 227; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmctl: c_long = 195; +pub const SYS_dup: c_long = 23; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_getpid: c_long = 172; +pub const SYS_sendfile: c_long = 71; +pub const SYS_socket: c_long = 198; +pub const SYS_connect: c_long = 203; +pub const SYS_accept: c_long = 202; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_shutdown: c_long = 210; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_socketpair: c_long = 199; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_exit: c_long = 93; +pub const SYS_wait4: c_long = 260; +pub const SYS_kill: c_long = 129; +pub const SYS_uname: c_long = 160; +pub const SYS_semget: c_long = 190; +pub const SYS_semop: c_long = 193; +pub const SYS_semctl: c_long = 191; +pub const SYS_shmdt: c_long = 197; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgctl: c_long = 187; +pub const SYS_fcntl: c_long = 25; +pub const SYS_flock: c_long = 32; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_getcwd: c_long = 17; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchown: c_long = 55; +pub const SYS_umask: c_long = 166; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_getrusage: c_long = 165; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_times: c_long = 153; +pub const SYS_ptrace: c_long = 117; +pub const SYS_getuid: c_long = 174; +pub const SYS_syslog: c_long = 116; +pub const SYS_getgid: c_long = 176; +pub const SYS_setuid: c_long = 146; +pub const SYS_setgid: c_long = 144; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getegid: c_long = 177; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getppid: c_long = 173; +pub const SYS_setsid: c_long = 157; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setregid: c_long = 143; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_getpgid: c_long = 155; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_getsid: c_long = 156; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_personality: c_long = 92; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_getpriority: c_long = 141; +pub const SYS_setpriority: c_long = 140; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_prctl: c_long = 167; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_chroot: c_long = 51; +pub const SYS_sync: c_long = 81; +pub const SYS_acct: c_long = 89; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_mount: c_long = 40; +pub const SYS_umount2: c_long = 39; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_reboot: c_long = 142; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_quotactl: c_long = 60; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_gettid: c_long = 178; +pub const SYS_readahead: c_long = 213; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_tkill: c_long = 130; +pub const SYS_futex: c_long = 98; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_getdents64: c_long = 61; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_exit_group: c_long = 94; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_tgkill: c_long = 131; +pub const SYS_mbind: c_long = 235; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_waitid: c_long = 95; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_openat: c_long = 56; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_mknodat: c_long = 33; +pub const SYS_fchownat: c_long = 54; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_linkat: c_long = 37; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_faccessat: c_long = 48; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_unshare: c_long = 97; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_move_pages: c_long = 239; +pub const SYS_utimensat: c_long = 88; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_fallocate: c_long = 47; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_accept4: c_long = 242; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_dup3: c_long = 24; +pub const SYS_pipe2: c_long = 59; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_setns: c_long = 268; +pub const SYS_getcpu: c_long = 168; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_rseq: c_long = 293; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/s390x.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/s390x.rs new file mode 100644 index 00000000000000..28e02c4f279202 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/s390x.rs @@ -0,0 +1,958 @@ +//! s390x + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, + pthread_mutex_t, +}; + +pub type blksize_t = i64; +pub type nlink_t = u64; +pub type suseconds_t = i64; +pub type wchar_t = i32; +pub type greg_t = u64; +pub type __u64 = u64; +pub type __s64 = i64; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + __glibc_reserved0: Padding, + pub sa_flags: c_int, + pub sa_restorer: Option, + pub sa_mask: crate::sigset_t, + } + + pub struct statfs { + pub f_type: c_uint, + pub f_bsize: c_uint, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_uint, + pub f_frsize: c_uint, + pub f_flags: c_uint, + f_spare: [c_uint; 4], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + _pad: Padding, + _pad2: Padding<[c_long; 14]>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + __glibc_reserved: Padding<[c_long; 3]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + st_pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + __glibc_reserved: Padding<[c_long; 3]>, + } + + pub struct pthread_attr_t { + __size: [c_ulong; 7], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct __psw_t { + pub mask: u64, + pub addr: u64, + } + + pub struct fpregset_t { + pub fpc: u32, + __pad: Padding, + pub fprs: [fpreg_t; 16], + } + + pub struct mcontext_t { + pub psw: __psw_t, + pub gregs: [u64; 16], + pub aregs: [u32; 16], + pub fpregs: fpregset_t, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + } + + pub struct statfs64 { + pub f_type: c_uint, + pub f_bsize: c_uint, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_uint, + pub f_frsize: c_uint, + pub f_flags: c_uint, + pub f_spare: [c_uint; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } +} + +s_no_extra_traits! { + // FIXME(union): This is actually a union. + pub struct fpreg_t { + pub d: c_double, + // f: c_float, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for fpreg_t { + fn eq(&self, other: &fpreg_t) -> bool { + self.d == other.d + } + } + + impl Eq for fpreg_t {} + + impl hash::Hash for fpreg_t { + fn hash(&self, state: &mut H) { + let d: u64 = self.d.to_bits(); + d.hash(state); + } + } + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 6; +pub const POSIX_FADV_NOREUSE: c_int = 7; + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_CLOEXEC: c_int = 0x80000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ECONNABORTED: c_int = 103; +pub const ECONNREFUSED: c_int = 111; +pub const ECONNRESET: c_int = 104; +pub const EDEADLK: c_int = 35; +pub const ENOSYS: c_int = 38; +pub const ENOTCONN: c_int = 107; +pub const ETIMEDOUT: c_int = 110; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NONBLOCK: c_int = 2048; +pub const SA_NOCLDWAIT: c_int = 2; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 4; +pub const SIGBUS: c_int = 7; +pub const SIGSTKSZ: size_t = 0x2000; +pub const MINSIGSTKSZ: size_t = 2048; +pub const SIG_SETMASK: c_int = 2; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const O_NOCTTY: c_int = 256; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const PTRACE_DETACH: c_uint = 17; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const EFD_NONBLOCK: c_int = 0x800; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const VTIME: usize = 5; +pub const VSWTC: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const ONLCR: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const CBAUD: crate::speed_t = 0o010017; +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const CSIZE: crate::tcflag_t = 0o000060; +pub const CS6: crate::tcflag_t = 0o000020; +pub const CS7: crate::tcflag_t = 0o000040; +pub const CS8: crate::tcflag_t = 0o000060; +pub const CSTOPB: crate::tcflag_t = 0o000100; +pub const CREAD: crate::tcflag_t = 0o000200; +pub const PARENB: crate::tcflag_t = 0o000400; +pub const PARODD: crate::tcflag_t = 0o001000; +pub const HUPCL: crate::tcflag_t = 0o002000; +pub const CLOCAL: crate::tcflag_t = 0o004000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; + +pub const ISIG: crate::tcflag_t = 0o000001; +pub const ICANON: crate::tcflag_t = 0o000002; +pub const ECHOE: crate::tcflag_t = 0o000020; +pub const ECHOK: crate::tcflag_t = 0o000040; +pub const ECHONL: crate::tcflag_t = 0o000100; +pub const NOFLSH: crate::tcflag_t = 0o000200; +pub const ECHOCTL: crate::tcflag_t = 0o001000; +pub const ECHOPRT: crate::tcflag_t = 0o002000; +pub const ECHOKE: crate::tcflag_t = 0o004000; +pub const PENDIN: crate::tcflag_t = 0o040000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const IXON: crate::tcflag_t = 0o002000; +pub const IXOFF: crate::tcflag_t = 0o010000; + +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_restart_syscall: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_signal: c_long = 48; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_lookup_dcookie: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_getdents: c_long = 141; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_mincore: c_long = 218; +pub const SYS_madvise: c_long = 219; +pub const SYS_getdents64: c_long = 220; +pub const SYS_readahead: c_long = 222; +pub const SYS_setxattr: c_long = 224; +pub const SYS_lsetxattr: c_long = 225; +pub const SYS_fsetxattr: c_long = 226; +pub const SYS_getxattr: c_long = 227; +pub const SYS_lgetxattr: c_long = 228; +pub const SYS_fgetxattr: c_long = 229; +pub const SYS_listxattr: c_long = 230; +pub const SYS_llistxattr: c_long = 231; +pub const SYS_flistxattr: c_long = 232; +pub const SYS_removexattr: c_long = 233; +pub const SYS_lremovexattr: c_long = 234; +pub const SYS_fremovexattr: c_long = 235; +pub const SYS_gettid: c_long = 236; +pub const SYS_tkill: c_long = 237; +pub const SYS_futex: c_long = 238; +pub const SYS_sched_setaffinity: c_long = 239; +pub const SYS_sched_getaffinity: c_long = 240; +pub const SYS_tgkill: c_long = 241; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_epoll_create: c_long = 249; +pub const SYS_epoll_ctl: c_long = 250; +pub const SYS_epoll_wait: c_long = 251; +pub const SYS_set_tid_address: c_long = 252; +pub const SYS_fadvise64: c_long = 253; +pub const SYS_timer_create: c_long = 254; +pub const SYS_timer_settime: c_long = 255; +pub const SYS_timer_gettime: c_long = 256; +pub const SYS_timer_getoverrun: c_long = 257; +pub const SYS_timer_delete: c_long = 258; +pub const SYS_clock_settime: c_long = 259; +pub const SYS_clock_gettime: c_long = 260; +pub const SYS_clock_getres: c_long = 261; +pub const SYS_clock_nanosleep: c_long = 262; +pub const SYS_statfs64: c_long = 265; +pub const SYS_fstatfs64: c_long = 266; +pub const SYS_remap_file_pages: c_long = 267; +pub const SYS_mbind: c_long = 268; +pub const SYS_get_mempolicy: c_long = 269; +pub const SYS_set_mempolicy: c_long = 270; +pub const SYS_mq_open: c_long = 271; +pub const SYS_mq_unlink: c_long = 272; +pub const SYS_mq_timedsend: c_long = 273; +pub const SYS_mq_timedreceive: c_long = 274; +pub const SYS_mq_notify: c_long = 275; +pub const SYS_mq_getsetattr: c_long = 276; +pub const SYS_kexec_load: c_long = 277; +pub const SYS_add_key: c_long = 278; +pub const SYS_request_key: c_long = 279; +pub const SYS_keyctl: c_long = 280; +pub const SYS_waitid: c_long = 281; +pub const SYS_ioprio_set: c_long = 282; +pub const SYS_ioprio_get: c_long = 283; +pub const SYS_inotify_init: c_long = 284; +pub const SYS_inotify_add_watch: c_long = 285; +pub const SYS_inotify_rm_watch: c_long = 286; +pub const SYS_migrate_pages: c_long = 287; +pub const SYS_openat: c_long = 288; +pub const SYS_mkdirat: c_long = 289; +pub const SYS_mknodat: c_long = 290; +pub const SYS_fchownat: c_long = 291; +pub const SYS_futimesat: c_long = 292; +pub const SYS_unlinkat: c_long = 294; +pub const SYS_renameat: c_long = 295; +pub const SYS_linkat: c_long = 296; +pub const SYS_symlinkat: c_long = 297; +pub const SYS_readlinkat: c_long = 298; +pub const SYS_fchmodat: c_long = 299; +pub const SYS_faccessat: c_long = 300; +pub const SYS_pselect6: c_long = 301; +pub const SYS_ppoll: c_long = 302; +pub const SYS_unshare: c_long = 303; +pub const SYS_set_robust_list: c_long = 304; +pub const SYS_get_robust_list: c_long = 305; +pub const SYS_splice: c_long = 306; +pub const SYS_sync_file_range: c_long = 307; +pub const SYS_tee: c_long = 308; +pub const SYS_vmsplice: c_long = 309; +pub const SYS_move_pages: c_long = 310; +pub const SYS_getcpu: c_long = 311; +pub const SYS_epoll_pwait: c_long = 312; +pub const SYS_utimes: c_long = 313; +pub const SYS_fallocate: c_long = 314; +pub const SYS_utimensat: c_long = 315; +pub const SYS_signalfd: c_long = 316; +pub const SYS_timerfd: c_long = 317; +pub const SYS_eventfd: c_long = 318; +pub const SYS_timerfd_create: c_long = 319; +pub const SYS_timerfd_settime: c_long = 320; +pub const SYS_timerfd_gettime: c_long = 321; +pub const SYS_signalfd4: c_long = 322; +pub const SYS_eventfd2: c_long = 323; +pub const SYS_inotify_init1: c_long = 324; +pub const SYS_pipe2: c_long = 325; +pub const SYS_dup3: c_long = 326; +pub const SYS_epoll_create1: c_long = 327; +pub const SYS_preadv: c_long = 328; +pub const SYS_pwritev: c_long = 329; +pub const SYS_rt_tgsigqueueinfo: c_long = 330; +pub const SYS_perf_event_open: c_long = 331; +pub const SYS_fanotify_init: c_long = 332; +pub const SYS_fanotify_mark: c_long = 333; +pub const SYS_prlimit64: c_long = 334; +pub const SYS_name_to_handle_at: c_long = 335; +pub const SYS_open_by_handle_at: c_long = 336; +pub const SYS_clock_adjtime: c_long = 337; +pub const SYS_syncfs: c_long = 338; +pub const SYS_setns: c_long = 339; +pub const SYS_process_vm_readv: c_long = 340; +pub const SYS_process_vm_writev: c_long = 341; +pub const SYS_s390_runtime_instr: c_long = 342; +pub const SYS_kcmp: c_long = 343; +pub const SYS_finit_module: c_long = 344; +pub const SYS_sched_setattr: c_long = 345; +pub const SYS_sched_getattr: c_long = 346; +pub const SYS_renameat2: c_long = 347; +pub const SYS_seccomp: c_long = 348; +pub const SYS_getrandom: c_long = 349; +pub const SYS_memfd_create: c_long = 350; +pub const SYS_bpf: c_long = 351; +pub const SYS_s390_pci_mmio_write: c_long = 352; +pub const SYS_s390_pci_mmio_read: c_long = 353; +pub const SYS_execveat: c_long = 354; +pub const SYS_userfaultfd: c_long = 355; +pub const SYS_membarrier: c_long = 356; +pub const SYS_recvmmsg: c_long = 357; +pub const SYS_sendmmsg: c_long = 358; +pub const SYS_socket: c_long = 359; +pub const SYS_socketpair: c_long = 360; +pub const SYS_bind: c_long = 361; +pub const SYS_connect: c_long = 362; +pub const SYS_listen: c_long = 363; +pub const SYS_accept4: c_long = 364; +pub const SYS_getsockopt: c_long = 365; +pub const SYS_setsockopt: c_long = 366; +pub const SYS_getsockname: c_long = 367; +pub const SYS_getpeername: c_long = 368; +pub const SYS_sendto: c_long = 369; +pub const SYS_sendmsg: c_long = 370; +pub const SYS_recvfrom: c_long = 371; +pub const SYS_recvmsg: c_long = 372; +pub const SYS_shutdown: c_long = 373; +pub const SYS_mlock2: c_long = 374; +pub const SYS_copy_file_range: c_long = 375; +pub const SYS_preadv2: c_long = 376; +pub const SYS_pwritev2: c_long = 377; +pub const SYS_lchown: c_long = 198; +pub const SYS_setuid: c_long = 213; +pub const SYS_getuid: c_long = 199; +pub const SYS_setgid: c_long = 214; +pub const SYS_getgid: c_long = 200; +pub const SYS_geteuid: c_long = 201; +pub const SYS_setreuid: c_long = 203; +pub const SYS_setregid: c_long = 204; +pub const SYS_getrlimit: c_long = 191; +pub const SYS_getgroups: c_long = 205; +pub const SYS_fchown: c_long = 207; +pub const SYS_setresuid: c_long = 208; +pub const SYS_setresgid: c_long = 210; +pub const SYS_getresgid: c_long = 211; +pub const SYS_select: c_long = 142; +pub const SYS_getegid: c_long = 202; +pub const SYS_setgroups: c_long = 206; +pub const SYS_getresuid: c_long = 209; +pub const SYS_chown: c_long = 212; +pub const SYS_setfsuid: c_long = 215; +pub const SYS_setfsgid: c_long = 216; +pub const SYS_newfstatat: c_long = 293; +pub const SYS_statx: c_long = 379; +pub const SYS_rseq: c_long = 383; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; + +extern "C" { + + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn getcontext(ucp: *mut crate::ucontext_t) -> c_int; + pub fn setcontext(ucp: *const crate::ucontext_t) -> c_int; + pub fn makecontext(ucp: *mut crate::ucontext_t, func: extern "C" fn(), argc: c_int, ...); + pub fn swapcontext(uocp: *mut crate::ucontext_t, ucp: *const crate::ucontext_t) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs new file mode 100644 index 00000000000000..0b325623396907 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs @@ -0,0 +1,934 @@ +//! SPARC64-specific definitions for 64-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, + pthread_mutex_t, +}; + +pub type wchar_t = i32; +pub type nlink_t = u32; +pub type blksize_t = i64; +pub type suseconds_t = i32; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + #[cfg(target_arch = "sparc64")] + __reserved0: Padding, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + f_spare: [crate::__fsword_t; 5], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + __reserved: Padding, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + __pad0: Padding, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 2]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + __pad0: Padding, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __reserved: Padding<[c_long; 2]>, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u64; 7], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + __pad0: Padding, + pub __seq: c_ushort, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __reserved1: Padding, + __reserved2: Padding, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [i64; 4], + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +pub const O_APPEND: c_int = 0x8; +pub const O_CREAT: c_int = 0x200; +pub const O_EXCL: c_int = 0x800; +pub const O_NOCTTY: c_int = 0x8000; +pub const O_NONBLOCK: c_int = 0x4000; +pub const O_SYNC: c_int = 0x802000; +pub const O_RSYNC: c_int = 0x802000; +pub const O_DSYNC: c_int = 0x2000; +pub const O_FSYNC: c_int = 0x802000; +pub const O_NOATIME: c_int = 0x200000; +pub const O_PATH: c_int = 0x1000000; +pub const O_TMPFILE: c_int = 0x2000000 | O_DIRECTORY; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0200; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLK: c_int = 78; +pub const ENAMETOOLONG: c_int = 63; +pub const ENOLCK: c_int = 79; +pub const ENOSYS: c_int = 90; +pub const ENOTEMPTY: c_int = 66; +pub const ELOOP: c_int = 62; +pub const ENOMSG: c_int = 75; +pub const EIDRM: c_int = 77; +pub const ECHRNG: c_int = 94; +pub const EL2NSYNC: c_int = 95; +pub const EL3HLT: c_int = 96; +pub const EL3RST: c_int = 97; +pub const ELNRNG: c_int = 98; +pub const EUNATCH: c_int = 99; +pub const ENOCSI: c_int = 100; +pub const EL2HLT: c_int = 101; +pub const EBADE: c_int = 102; +pub const EBADR: c_int = 103; +pub const EXFULL: c_int = 104; +pub const ENOANO: c_int = 105; +pub const EBADRQC: c_int = 106; +pub const EBADSLT: c_int = 107; +pub const EMULTIHOP: c_int = 87; +pub const EOVERFLOW: c_int = 92; +pub const ENOTUNIQ: c_int = 115; +pub const EBADFD: c_int = 93; +pub const EBADMSG: c_int = 76; +pub const EREMCHG: c_int = 89; +pub const ELIBACC: c_int = 114; +pub const ELIBBAD: c_int = 112; +pub const ELIBSCN: c_int = 124; +pub const ELIBMAX: c_int = 123; +pub const ELIBEXEC: c_int = 110; +pub const EILSEQ: c_int = 122; +pub const ERESTART: c_int = 116; +pub const ESTRPIPE: c_int = 91; +pub const EUSERS: c_int = 68; +pub const ENOTSOCK: c_int = 38; +pub const EDESTADDRREQ: c_int = 39; +pub const EMSGSIZE: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const EOPNOTSUPP: c_int = 45; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENETDOWN: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const EHOSTDOWN: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const EALREADY: c_int = 37; +pub const EINPROGRESS: c_int = 36; +pub const ESTALE: c_int = 70; +pub const EDQUOT: c_int = 69; +pub const ENOMEDIUM: c_int = 125; +pub const EMEDIUMTYPE: c_int = 126; +pub const ECANCELED: c_int = 127; +pub const ENOKEY: c_int = 128; +pub const EKEYEXPIRED: c_int = 129; +pub const EKEYREVOKED: c_int = 130; +pub const EKEYREJECTED: c_int = 131; +pub const EOWNERDEAD: c_int = 132; +pub const ENOTRECOVERABLE: c_int = 133; +pub const EHWPOISON: c_int = 135; +pub const ERFKILL: c_int = 134; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SA_ONSTACK: c_int = 1; +pub const SA_SIGINFO: c_int = 0x200; +pub const SA_NOCLDWAIT: c_int = 0x100; + +pub const SIGEMT: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 20; +pub const SIGBUS: c_int = 10; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGCONT: c_int = 19; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGURG: c_int = 16; +pub const SIGIO: c_int = 23; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 23; +pub const SIGPWR: c_int = 29; +pub const SIG_SETMASK: c_int = 4; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; + +pub const POLLWRNORM: c_short = 4; +pub const POLLWRBAND: c_short = 0x100; + +pub const O_ASYNC: c_int = 0x40; +pub const O_NDELAY: c_int = 0x4004; + +pub const PTRACE_DETACH: c_uint = 17; + +pub const EFD_NONBLOCK: c_int = 0x4000; + +pub const F_GETLK: c_int = 7; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const F_RDLCK: c_int = 1; +pub const F_WRLCK: c_int = 2; +pub const F_UNLCK: c_int = 3; + +pub const SFD_NONBLOCK: c_int = 0x4000; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const SFD_CLOEXEC: c_int = 0x400000; + +pub const NCCS: usize = 17; +pub const O_TRUNC: c_int = 0x400; + +pub const O_CLOEXEC: c_int = 0x400000; + +pub const EBFONT: c_int = 109; +pub const ENOSTR: c_int = 72; +pub const ENODATA: c_int = 111; +pub const ETIME: c_int = 73; +pub const ENOSR: c_int = 74; +pub const ENONET: c_int = 80; +pub const ENOPKG: c_int = 113; +pub const EREMOTE: c_int = 71; +pub const ENOLINK: c_int = 82; +pub const EADV: c_int = 83; +pub const ESRMNT: c_int = 84; +pub const ECOMM: c_int = 85; +pub const EPROTO: c_int = 86; +pub const EDOTDOT: c_int = 88; + +pub const SA_NODEFER: c_int = 0x20; +pub const SA_RESETHAND: c_int = 0x4; +pub const SA_RESTART: c_int = 0x2; +pub const SA_NOCLDSTOP: c_int = 0x00000008; + +pub const EPOLL_CLOEXEC: c_int = 0x400000; + +pub const EFD_CLOEXEC: c_int = 0x400000; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_NOFOLLOW: c_int = 0o400000; +pub const O_DIRECT: c_int = 0x100000; + +pub const MAP_LOCKED: c_int = 0x0100; +pub const MAP_NORESERVE: c_int = 0x00040; + +pub const EDEADLOCK: c_int = 108; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; + +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 4096; +pub const CBAUD: crate::tcflag_t = 0x0000100f; +pub const TAB1: crate::tcflag_t = 0x800; +pub const TAB2: crate::tcflag_t = 0x1000; +pub const TAB3: crate::tcflag_t = 0x1800; +pub const CR1: crate::tcflag_t = 0x200; +pub const CR2: crate::tcflag_t = 0x400; +pub const CR3: crate::tcflag_t = 0x600; +pub const FF1: crate::tcflag_t = 0x8000; +pub const BS1: crate::tcflag_t = 0x2000; +pub const VT1: crate::tcflag_t = 0x4000; +pub const VWERASE: usize = 0xe; +pub const VREPRINT: usize = 0xc; +pub const VSUSP: usize = 0xa; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VDISCARD: usize = 0xd; +pub const VTIME: usize = 0x5; +pub const IXON: crate::tcflag_t = 0x400; +pub const IXOFF: crate::tcflag_t = 0x1000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x30; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x40; +pub const CREAD: crate::tcflag_t = 0x80; +pub const PARENB: crate::tcflag_t = 0x100; +pub const PARODD: crate::tcflag_t = 0x200; +pub const HUPCL: crate::tcflag_t = 0x400; +pub const CLOCAL: crate::tcflag_t = 0x800; +pub const ECHOKE: crate::tcflag_t = 0x800; +pub const ECHOE: crate::tcflag_t = 0x10; +pub const ECHOK: crate::tcflag_t = 0x20; +pub const ECHONL: crate::tcflag_t = 0x40; +pub const ECHOPRT: crate::tcflag_t = 0x400; +pub const ECHOCTL: crate::tcflag_t = 0x200; +pub const ISIG: crate::tcflag_t = 0x1; +pub const ICANON: crate::tcflag_t = 0x2; +pub const PENDIN: crate::tcflag_t = 0x4000; +pub const NOFLSH: crate::tcflag_t = 0x80; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0x00001000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0x1001; +pub const B115200: crate::speed_t = 0x1002; +pub const B230400: crate::speed_t = 0x1003; +pub const B460800: crate::speed_t = 0x1004; +pub const B76800: crate::speed_t = 0x1005; +pub const B153600: crate::speed_t = 0x1006; +pub const B307200: crate::speed_t = 0x1007; +pub const B614400: crate::speed_t = 0x1008; +pub const B921600: crate::speed_t = 0x1009; +pub const B500000: crate::speed_t = 0x100a; +pub const B576000: crate::speed_t = 0x100b; +pub const B1000000: crate::speed_t = 0x100c; +pub const B1152000: crate::speed_t = 0x100d; +pub const B1500000: crate::speed_t = 0x100e; +pub const B2000000: crate::speed_t = 0x100f; + +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x8000; +pub const TOSTOP: crate::tcflag_t = 0x100; +pub const FLUSHO: crate::tcflag_t = 0x1000; +pub const EXTPROC: crate::tcflag_t = 0x10000; + +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_wait4: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execv: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_chown: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_brk: c_long = 17; +pub const SYS_perfctr: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_capget: c_long = 21; +pub const SYS_capset: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_vmsplice: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_sigaltstack: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_stat: c_long = 38; +pub const SYS_sendfile: c_long = 39; +pub const SYS_lstat: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_umount2: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_memory_ordering: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_reboot: c_long = 55; +pub const SYS_symlink: c_long = 57; +pub const SYS_readlink: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_fstat: c_long = 62; +pub const SYS_fstat64: c_long = 63; +pub const SYS_getpagesize: c_long = 64; +pub const SYS_msync: c_long = 65; +pub const SYS_vfork: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_mmap: c_long = 71; +pub const SYS_munmap: c_long = 73; +pub const SYS_mprotect: c_long = 74; +pub const SYS_madvise: c_long = 75; +pub const SYS_vhangup: c_long = 76; +pub const SYS_mincore: c_long = 78; +pub const SYS_getgroups: c_long = 79; +pub const SYS_setgroups: c_long = 80; +pub const SYS_getpgrp: c_long = 81; +pub const SYS_setitimer: c_long = 83; +pub const SYS_swapon: c_long = 85; +pub const SYS_getitimer: c_long = 86; +pub const SYS_sethostname: c_long = 88; +pub const SYS_dup2: c_long = 90; +pub const SYS_fcntl: c_long = 92; +pub const SYS_select: c_long = 93; +pub const SYS_fsync: c_long = 95; +pub const SYS_setpriority: c_long = 96; +pub const SYS_socket: c_long = 97; +pub const SYS_connect: c_long = 98; +pub const SYS_accept: c_long = 99; +pub const SYS_getpriority: c_long = 100; +pub const SYS_rt_sigreturn: c_long = 101; +pub const SYS_rt_sigaction: c_long = 102; +pub const SYS_rt_sigprocmask: c_long = 103; +pub const SYS_rt_sigpending: c_long = 104; +pub const SYS_rt_sigtimedwait: c_long = 105; +pub const SYS_rt_sigqueueinfo: c_long = 106; +pub const SYS_rt_sigsuspend: c_long = 107; +pub const SYS_setresuid: c_long = 108; +pub const SYS_getresuid: c_long = 109; +pub const SYS_setresgid: c_long = 110; +pub const SYS_getresgid: c_long = 111; +pub const SYS_recvmsg: c_long = 113; +pub const SYS_sendmsg: c_long = 114; +pub const SYS_gettimeofday: c_long = 116; +pub const SYS_getrusage: c_long = 117; +pub const SYS_getsockopt: c_long = 118; +pub const SYS_getcwd: c_long = 119; +pub const SYS_readv: c_long = 120; +pub const SYS_writev: c_long = 121; +pub const SYS_settimeofday: c_long = 122; +pub const SYS_fchown: c_long = 123; +pub const SYS_fchmod: c_long = 124; +pub const SYS_recvfrom: c_long = 125; +pub const SYS_setreuid: c_long = 126; +pub const SYS_setregid: c_long = 127; +pub const SYS_rename: c_long = 128; +pub const SYS_truncate: c_long = 129; +pub const SYS_ftruncate: c_long = 130; +pub const SYS_flock: c_long = 131; +pub const SYS_lstat64: c_long = 132; +pub const SYS_sendto: c_long = 133; +pub const SYS_shutdown: c_long = 134; +pub const SYS_socketpair: c_long = 135; +pub const SYS_mkdir: c_long = 136; +pub const SYS_rmdir: c_long = 137; +pub const SYS_utimes: c_long = 138; +pub const SYS_stat64: c_long = 139; +pub const SYS_sendfile64: c_long = 140; +pub const SYS_getpeername: c_long = 141; +pub const SYS_futex: c_long = 142; +pub const SYS_gettid: c_long = 143; +pub const SYS_getrlimit: c_long = 144; +pub const SYS_setrlimit: c_long = 145; +pub const SYS_pivot_root: c_long = 146; +pub const SYS_prctl: c_long = 147; +pub const SYS_pciconfig_read: c_long = 148; +pub const SYS_pciconfig_write: c_long = 149; +pub const SYS_getsockname: c_long = 150; +pub const SYS_inotify_init: c_long = 151; +pub const SYS_inotify_add_watch: c_long = 152; +pub const SYS_poll: c_long = 153; +pub const SYS_getdents64: c_long = 154; +pub const SYS_inotify_rm_watch: c_long = 156; +pub const SYS_statfs: c_long = 157; +pub const SYS_fstatfs: c_long = 158; +pub const SYS_umount: c_long = 159; +pub const SYS_sched_set_affinity: c_long = 160; +pub const SYS_sched_get_affinity: c_long = 161; +pub const SYS_getdomainname: c_long = 162; +pub const SYS_setdomainname: c_long = 163; +pub const SYS_utrap_install: c_long = 164; +pub const SYS_quotactl: c_long = 165; +pub const SYS_set_tid_address: c_long = 166; +pub const SYS_mount: c_long = 167; +pub const SYS_ustat: c_long = 168; +pub const SYS_setxattr: c_long = 169; +pub const SYS_lsetxattr: c_long = 170; +pub const SYS_fsetxattr: c_long = 171; +pub const SYS_getxattr: c_long = 172; +pub const SYS_lgetxattr: c_long = 173; +pub const SYS_getdents: c_long = 174; +pub const SYS_setsid: c_long = 175; +pub const SYS_fchdir: c_long = 176; +pub const SYS_fgetxattr: c_long = 177; +pub const SYS_listxattr: c_long = 178; +pub const SYS_llistxattr: c_long = 179; +pub const SYS_flistxattr: c_long = 180; +pub const SYS_removexattr: c_long = 181; +pub const SYS_lremovexattr: c_long = 182; +pub const SYS_sigpending: c_long = 183; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 184; +pub const SYS_setpgid: c_long = 185; +pub const SYS_fremovexattr: c_long = 186; +pub const SYS_tkill: c_long = 187; +pub const SYS_exit_group: c_long = 188; +pub const SYS_uname: c_long = 189; +pub const SYS_init_module: c_long = 190; +pub const SYS_personality: c_long = 191; +pub const SYS_remap_file_pages: c_long = 192; +pub const SYS_epoll_create: c_long = 193; +pub const SYS_epoll_ctl: c_long = 194; +pub const SYS_epoll_wait: c_long = 195; +pub const SYS_ioprio_set: c_long = 196; +pub const SYS_getppid: c_long = 197; +pub const SYS_sigaction: c_long = 198; +pub const SYS_sgetmask: c_long = 199; +pub const SYS_ssetmask: c_long = 200; +pub const SYS_sigsuspend: c_long = 201; +pub const SYS_oldlstat: c_long = 202; +pub const SYS_uselib: c_long = 203; +pub const SYS_readdir: c_long = 204; +pub const SYS_readahead: c_long = 205; +pub const SYS_socketcall: c_long = 206; +pub const SYS_syslog: c_long = 207; +pub const SYS_lookup_dcookie: c_long = 208; +pub const SYS_fadvise64: c_long = 209; +pub const SYS_fadvise64_64: c_long = 210; +pub const SYS_tgkill: c_long = 211; +pub const SYS_waitpid: c_long = 212; +pub const SYS_swapoff: c_long = 213; +pub const SYS_sysinfo: c_long = 214; +pub const SYS_ipc: c_long = 215; +pub const SYS_sigreturn: c_long = 216; +pub const SYS_clone: c_long = 217; +pub const SYS_ioprio_get: c_long = 218; +pub const SYS_adjtimex: c_long = 219; +pub const SYS_sigprocmask: c_long = 220; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 221; +pub const SYS_delete_module: c_long = 222; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 223; +pub const SYS_getpgid: c_long = 224; +pub const SYS_bdflush: c_long = 225; +pub const SYS_sysfs: c_long = 226; +pub const SYS_afs_syscall: c_long = 227; +pub const SYS_setfsuid: c_long = 228; +pub const SYS_setfsgid: c_long = 229; +pub const SYS__newselect: c_long = 230; +pub const SYS_splice: c_long = 232; +pub const SYS_stime: c_long = 233; +pub const SYS_statfs64: c_long = 234; +pub const SYS_fstatfs64: c_long = 235; +pub const SYS__llseek: c_long = 236; +pub const SYS_mlock: c_long = 237; +pub const SYS_munlock: c_long = 238; +pub const SYS_mlockall: c_long = 239; +pub const SYS_munlockall: c_long = 240; +pub const SYS_sched_setparam: c_long = 241; +pub const SYS_sched_getparam: c_long = 242; +pub const SYS_sched_setscheduler: c_long = 243; +pub const SYS_sched_getscheduler: c_long = 244; +pub const SYS_sched_yield: c_long = 245; +pub const SYS_sched_get_priority_max: c_long = 246; +pub const SYS_sched_get_priority_min: c_long = 247; +pub const SYS_sched_rr_get_interval: c_long = 248; +pub const SYS_nanosleep: c_long = 249; +pub const SYS_mremap: c_long = 250; +pub const SYS__sysctl: c_long = 251; +pub const SYS_getsid: c_long = 252; +pub const SYS_fdatasync: c_long = 253; +pub const SYS_nfsservctl: c_long = 254; +pub const SYS_sync_file_range: c_long = 255; +pub const SYS_clock_settime: c_long = 256; +pub const SYS_clock_gettime: c_long = 257; +pub const SYS_clock_getres: c_long = 258; +pub const SYS_clock_nanosleep: c_long = 259; +pub const SYS_sched_getaffinity: c_long = 260; +pub const SYS_sched_setaffinity: c_long = 261; +pub const SYS_timer_settime: c_long = 262; +pub const SYS_timer_gettime: c_long = 263; +pub const SYS_timer_getoverrun: c_long = 264; +pub const SYS_timer_delete: c_long = 265; +pub const SYS_timer_create: c_long = 266; +pub const SYS_io_setup: c_long = 268; +pub const SYS_io_destroy: c_long = 269; +pub const SYS_io_submit: c_long = 270; +pub const SYS_io_cancel: c_long = 271; +pub const SYS_io_getevents: c_long = 272; +pub const SYS_mq_open: c_long = 273; +pub const SYS_mq_unlink: c_long = 274; +pub const SYS_mq_timedsend: c_long = 275; +pub const SYS_mq_timedreceive: c_long = 276; +pub const SYS_mq_notify: c_long = 277; +pub const SYS_mq_getsetattr: c_long = 278; +pub const SYS_waitid: c_long = 279; +pub const SYS_tee: c_long = 280; +pub const SYS_add_key: c_long = 281; +pub const SYS_request_key: c_long = 282; +pub const SYS_keyctl: c_long = 283; +pub const SYS_openat: c_long = 284; +pub const SYS_mkdirat: c_long = 285; +pub const SYS_mknodat: c_long = 286; +pub const SYS_fchownat: c_long = 287; +pub const SYS_futimesat: c_long = 288; +pub const SYS_fstatat64: c_long = 289; +pub const SYS_unlinkat: c_long = 290; +pub const SYS_renameat: c_long = 291; +pub const SYS_linkat: c_long = 292; +pub const SYS_symlinkat: c_long = 293; +pub const SYS_readlinkat: c_long = 294; +pub const SYS_fchmodat: c_long = 295; +pub const SYS_faccessat: c_long = 296; +pub const SYS_pselect6: c_long = 297; +pub const SYS_ppoll: c_long = 298; +pub const SYS_unshare: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_get_robust_list: c_long = 301; +pub const SYS_migrate_pages: c_long = 302; +pub const SYS_mbind: c_long = 303; +pub const SYS_get_mempolicy: c_long = 304; +pub const SYS_set_mempolicy: c_long = 305; +pub const SYS_kexec_load: c_long = 306; +pub const SYS_move_pages: c_long = 307; +pub const SYS_getcpu: c_long = 308; +pub const SYS_epoll_pwait: c_long = 309; +pub const SYS_utimensat: c_long = 310; +pub const SYS_signalfd: c_long = 311; +pub const SYS_timerfd_create: c_long = 312; +pub const SYS_eventfd: c_long = 313; +pub const SYS_fallocate: c_long = 314; +pub const SYS_timerfd_settime: c_long = 315; +pub const SYS_timerfd_gettime: c_long = 316; +pub const SYS_signalfd4: c_long = 317; +pub const SYS_eventfd2: c_long = 318; +pub const SYS_epoll_create1: c_long = 319; +pub const SYS_dup3: c_long = 320; +pub const SYS_pipe2: c_long = 321; +pub const SYS_inotify_init1: c_long = 322; +pub const SYS_accept4: c_long = 323; +pub const SYS_preadv: c_long = 324; +pub const SYS_pwritev: c_long = 325; +pub const SYS_rt_tgsigqueueinfo: c_long = 326; +pub const SYS_perf_event_open: c_long = 327; +pub const SYS_recvmmsg: c_long = 328; +pub const SYS_fanotify_init: c_long = 329; +pub const SYS_fanotify_mark: c_long = 330; +pub const SYS_prlimit64: c_long = 331; +pub const SYS_name_to_handle_at: c_long = 332; +pub const SYS_open_by_handle_at: c_long = 333; +pub const SYS_clock_adjtime: c_long = 334; +pub const SYS_syncfs: c_long = 335; +pub const SYS_sendmmsg: c_long = 336; +pub const SYS_setns: c_long = 337; +pub const SYS_process_vm_readv: c_long = 338; +pub const SYS_process_vm_writev: c_long = 339; +pub const SYS_kern_features: c_long = 340; +pub const SYS_kcmp: c_long = 341; +pub const SYS_finit_module: c_long = 342; +pub const SYS_sched_setattr: c_long = 343; +pub const SYS_sched_getattr: c_long = 344; +pub const SYS_renameat2: c_long = 345; +pub const SYS_seccomp: c_long = 346; +pub const SYS_getrandom: c_long = 347; +pub const SYS_memfd_create: c_long = 348; +pub const SYS_bpf: c_long = 349; +pub const SYS_execveat: c_long = 350; +pub const SYS_membarrier: c_long = 351; +pub const SYS_userfaultfd: c_long = 352; +pub const SYS_bind: c_long = 353; +pub const SYS_listen: c_long = 354; +pub const SYS_setsockopt: c_long = 355; +pub const SYS_mlock2: c_long = 356; +pub const SYS_copy_file_range: c_long = 357; +pub const SYS_preadv2: c_long = 358; +pub const SYS_pwritev2: c_long = 359; +pub const SYS_statx: c_long = 360; +pub const SYS_rseq: c_long = 365; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +// Reserved in the kernel, but not actually implemented yet +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs new file mode 100644 index 00000000000000..7edd7c56640013 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs @@ -0,0 +1,743 @@ +//! x86_64-specific definitions for 64-bit linux-like values + +use crate::prelude::*; +use crate::{ + off64_t, + off_t, +}; + +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = i64; +pub type greg_t = i64; +pub type suseconds_t = i64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + #[cfg(target_arch = "sparc64")] + __reserved0: Padding, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + pub struct statfs { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + f_spare: [crate::__fsword_t; 5], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [c_int; 29], + _align: [u64; 0], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: i64, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: i64, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: i64, + __unused: Padding<[i64; 3]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino64_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: i64, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: i64, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: i64, + __reserved: Padding<[i64; 3]>, + } + + pub struct statfs64 { + pub f_type: crate::__fsword_t, + pub f_bsize: crate::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: crate::fsid_t, + pub f_namelen: crate::__fsword_t, + pub f_frsize: crate::__fsword_t, + pub f_flags: crate::__fsword_t, + pub f_spare: [crate::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + #[cfg(target_pointer_width = "32")] + __size: [u32; 8], + #[cfg(target_pointer_width = "64")] + __size: [u64; 7], + } + + pub struct _libc_fpxreg { + pub significand: [u16; 4], + pub exponent: u16, + __private: [u16; 3], + } + + pub struct _libc_xmmreg { + pub element: [u32; 4], + } + + pub struct _libc_fpstate { + pub cwd: u16, + pub swd: u16, + pub ftw: u16, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcr_mask: u32, + pub _st: [_libc_fpxreg; 8], + pub _xmm: [_libc_xmmreg; 16], + __private: [u64; 12], + } + + pub struct user_regs_struct { + pub r15: c_ulonglong, + pub r14: c_ulonglong, + pub r13: c_ulonglong, + pub r12: c_ulonglong, + pub rbp: c_ulonglong, + pub rbx: c_ulonglong, + pub r11: c_ulonglong, + pub r10: c_ulonglong, + pub r9: c_ulonglong, + pub r8: c_ulonglong, + pub rax: c_ulonglong, + pub rcx: c_ulonglong, + pub rdx: c_ulonglong, + pub rsi: c_ulonglong, + pub rdi: c_ulonglong, + pub orig_rax: c_ulonglong, + pub rip: c_ulonglong, + pub cs: c_ulonglong, + pub eflags: c_ulonglong, + pub rsp: c_ulonglong, + pub ss: c_ulonglong, + pub fs_base: c_ulonglong, + pub gs_base: c_ulonglong, + pub ds: c_ulonglong, + pub es: c_ulonglong, + pub fs: c_ulonglong, + pub gs: c_ulonglong, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: c_int, + pub i387: user_fpregs_struct, + pub u_tsize: c_ulonglong, + pub u_dsize: c_ulonglong, + pub u_ssize: c_ulonglong, + pub start_code: c_ulonglong, + pub start_stack: c_ulonglong, + pub signal: c_longlong, + __reserved: Padding, + #[cfg(target_pointer_width = "32")] + __pad1: Padding, + pub u_ar0: *mut user_regs_struct, + #[cfg(target_pointer_width = "32")] + __pad2: Padding, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: c_ulonglong, + pub u_comm: [c_char; 32], + pub u_debugreg: [c_ulonglong; 8], + } + + pub struct mcontext_t { + pub gregs: [greg_t; 23], + pub fpregs: *mut _libc_fpstate, + __private: [u64; 8], + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct ptrace_rseq_configuration { + pub rseq_abi_pointer: crate::__u64, + pub rseq_abi_size: crate::__u32, + pub signature: crate::__u32, + pub flags: crate::__u32, + pub pad: crate::__u32, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } + + pub struct user_fpregs_struct { + pub cwd: c_ushort, + pub swd: c_ushort, + pub ftw: c_ushort, + pub fop: c_ushort, + pub rip: c_ulonglong, + pub rdp: c_ulonglong, + pub mxcsr: c_uint, + pub mxcr_mask: c_uint, + pub st_space: [c_uint; 32], + pub xmm_space: [c_uint; 64], + padding: Padding<[c_uint; 24]>, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + __private: [u8; 512], + __ssp: [c_ulonglong; 4], + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const VEOF: usize = 4; +pub const RTLD_DEEPBIND: c_int = 0x8; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_FSYNC: c_int = 0x101000; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_PATH: c_int = 0o10000000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0100; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = 31; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const O_ASYNC: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x800; + +pub const PTRACE_DETACH: c_uint = 17; +pub const PTRACE_GET_RSEQ_CONFIGURATION: c_uint = 0x420f; + +pub const EFD_NONBLOCK: c_int = 0x800; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; + +pub const SFD_NONBLOCK: c_int = 0x0800; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; + +pub const O_CLOEXEC: c_int = 0x80000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_32BIT: c_int = 0x0040; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; + +pub const PTRACE_GETFPREGS: c_uint = 14; +pub const PTRACE_SETFPREGS: c_uint = 15; +pub const PTRACE_GETFPXREGS: c_uint = 18; +pub const PTRACE_SETFPXREGS: c_uint = 19; +pub const PTRACE_GETREGS: c_uint = 12; +pub const PTRACE_SETREGS: c_uint = 13; +pub const PTRACE_PEEKSIGINFO_SHARED: c_uint = 1; +pub const PTRACE_SYSEMU: c_uint = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_uint = 32; + +pub const PR_GET_SPECULATION_CTRL: c_int = 52; +pub const PR_SET_SPECULATION_CTRL: c_int = 53; +pub const PR_SPEC_NOT_AFFECTED: c_uint = 0; +pub const PR_SPEC_PRCTL: c_uint = 1 << 0; +pub const PR_SPEC_ENABLE: c_uint = 1 << 1; +pub const PR_SPEC_DISABLE: c_uint = 1 << 2; +pub const PR_SPEC_FORCE_DISABLE: c_uint = 1 << 3; +pub const PR_SPEC_DISABLE_NOEXEC: c_uint = 1 << 4; +pub const PR_SPEC_STORE_BYPASS: c_int = 0; +pub const PR_SPEC_INDIRECT_BRANCH: c_int = 1; +// FIXME(linux): perharps for later +//pub const PR_SPEC_L1D_FLUSH: c_int = 2; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: c_int = 0; +pub const R14: c_int = 1; +pub const R13: c_int = 2; +pub const R12: c_int = 3; +pub const RBP: c_int = 4; +pub const RBX: c_int = 5; +pub const R11: c_int = 6; +pub const R10: c_int = 7; +pub const R9: c_int = 8; +pub const R8: c_int = 9; +pub const RAX: c_int = 10; +pub const RCX: c_int = 11; +pub const RDX: c_int = 12; +pub const RSI: c_int = 13; +pub const RDI: c_int = 14; +pub const ORIG_RAX: c_int = 15; +pub const RIP: c_int = 16; +pub const CS: c_int = 17; +pub const EFLAGS: c_int = 18; +pub const RSP: c_int = 19; +pub const SS: c_int = 20; +pub const FS_BASE: c_int = 21; +pub const GS_BASE: c_int = 22; +pub const DS: c_int = 23; +pub const ES: c_int = 24; +pub const FS: c_int = 25; +pub const GS: c_int = 26; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_R8: c_int = 0; +pub const REG_R9: c_int = 1; +pub const REG_R10: c_int = 2; +pub const REG_R11: c_int = 3; +pub const REG_R12: c_int = 4; +pub const REG_R13: c_int = 5; +pub const REG_R14: c_int = 6; +pub const REG_R15: c_int = 7; +pub const REG_RDI: c_int = 8; +pub const REG_RSI: c_int = 9; +pub const REG_RBP: c_int = 10; +pub const REG_RBX: c_int = 11; +pub const REG_RDX: c_int = 12; +pub const REG_RAX: c_int = 13; +pub const REG_RCX: c_int = 14; +pub const REG_RSP: c_int = 15; +pub const REG_RIP: c_int = 16; +pub const REG_EFL: c_int = 17; +pub const REG_CSGSFS: c_int = 18; +pub const REG_ERR: c_int = 19; +pub const REG_TRAPNO: c_int = 20; +pub const REG_OLDMASK: c_int = 21; +pub const REG_CR2: c_int = 22; + +extern "C" { + pub fn getcontext(ucp: *mut ucontext_t) -> c_int; + pub fn setcontext(ucp: *const ucontext_t) -> c_int; + pub fn makecontext(ucp: *mut ucontext_t, func: extern "C" fn(), argc: c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, ucp: *const ucontext_t) -> c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod x32; + pub use self::x32::*; + } else { + mod not_x32; + pub use self::not_x32::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs new file mode 100644 index 00000000000000..27b96a60aabd83 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs @@ -0,0 +1,446 @@ +use crate::prelude::*; +use crate::pthread_mutex_t; + +s! { + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } +} + +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +#[cfg(target_endian = "little")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "little")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; +#[cfg(target_endian = "big")] +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], +}; + +// Syscall table + +pub const SYS_read: c_long = 0; +pub const SYS_write: c_long = 1; +pub const SYS_open: c_long = 2; +pub const SYS_close: c_long = 3; +pub const SYS_stat: c_long = 4; +pub const SYS_fstat: c_long = 5; +pub const SYS_lstat: c_long = 6; +pub const SYS_poll: c_long = 7; +pub const SYS_lseek: c_long = 8; +pub const SYS_mmap: c_long = 9; +pub const SYS_mprotect: c_long = 10; +pub const SYS_munmap: c_long = 11; +pub const SYS_brk: c_long = 12; +pub const SYS_rt_sigaction: c_long = 13; +pub const SYS_rt_sigprocmask: c_long = 14; +pub const SYS_rt_sigreturn: c_long = 15; +pub const SYS_ioctl: c_long = 16; +pub const SYS_pread64: c_long = 17; +pub const SYS_pwrite64: c_long = 18; +pub const SYS_readv: c_long = 19; +pub const SYS_writev: c_long = 20; +pub const SYS_access: c_long = 21; +pub const SYS_pipe: c_long = 22; +pub const SYS_select: c_long = 23; +pub const SYS_sched_yield: c_long = 24; +pub const SYS_mremap: c_long = 25; +pub const SYS_msync: c_long = 26; +pub const SYS_mincore: c_long = 27; +pub const SYS_madvise: c_long = 28; +pub const SYS_shmget: c_long = 29; +pub const SYS_shmat: c_long = 30; +pub const SYS_shmctl: c_long = 31; +pub const SYS_dup: c_long = 32; +pub const SYS_dup2: c_long = 33; +pub const SYS_pause: c_long = 34; +pub const SYS_nanosleep: c_long = 35; +pub const SYS_getitimer: c_long = 36; +pub const SYS_alarm: c_long = 37; +pub const SYS_setitimer: c_long = 38; +pub const SYS_getpid: c_long = 39; +pub const SYS_sendfile: c_long = 40; +pub const SYS_socket: c_long = 41; +pub const SYS_connect: c_long = 42; +pub const SYS_accept: c_long = 43; +pub const SYS_sendto: c_long = 44; +pub const SYS_recvfrom: c_long = 45; +pub const SYS_sendmsg: c_long = 46; +pub const SYS_recvmsg: c_long = 47; +pub const SYS_shutdown: c_long = 48; +pub const SYS_bind: c_long = 49; +pub const SYS_listen: c_long = 50; +pub const SYS_getsockname: c_long = 51; +pub const SYS_getpeername: c_long = 52; +pub const SYS_socketpair: c_long = 53; +pub const SYS_setsockopt: c_long = 54; +pub const SYS_getsockopt: c_long = 55; +pub const SYS_clone: c_long = 56; +pub const SYS_fork: c_long = 57; +pub const SYS_vfork: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_exit: c_long = 60; +pub const SYS_wait4: c_long = 61; +pub const SYS_kill: c_long = 62; +pub const SYS_uname: c_long = 63; +pub const SYS_semget: c_long = 64; +pub const SYS_semop: c_long = 65; +pub const SYS_semctl: c_long = 66; +pub const SYS_shmdt: c_long = 67; +pub const SYS_msgget: c_long = 68; +pub const SYS_msgsnd: c_long = 69; +pub const SYS_msgrcv: c_long = 70; +pub const SYS_msgctl: c_long = 71; +pub const SYS_fcntl: c_long = 72; +pub const SYS_flock: c_long = 73; +pub const SYS_fsync: c_long = 74; +pub const SYS_fdatasync: c_long = 75; +pub const SYS_truncate: c_long = 76; +pub const SYS_ftruncate: c_long = 77; +pub const SYS_getdents: c_long = 78; +pub const SYS_getcwd: c_long = 79; +pub const SYS_chdir: c_long = 80; +pub const SYS_fchdir: c_long = 81; +pub const SYS_rename: c_long = 82; +pub const SYS_mkdir: c_long = 83; +pub const SYS_rmdir: c_long = 84; +pub const SYS_creat: c_long = 85; +pub const SYS_link: c_long = 86; +pub const SYS_unlink: c_long = 87; +pub const SYS_symlink: c_long = 88; +pub const SYS_readlink: c_long = 89; +pub const SYS_chmod: c_long = 90; +pub const SYS_fchmod: c_long = 91; +pub const SYS_chown: c_long = 92; +pub const SYS_fchown: c_long = 93; +pub const SYS_lchown: c_long = 94; +pub const SYS_umask: c_long = 95; +pub const SYS_gettimeofday: c_long = 96; +pub const SYS_getrlimit: c_long = 97; +pub const SYS_getrusage: c_long = 98; +pub const SYS_sysinfo: c_long = 99; +pub const SYS_times: c_long = 100; +pub const SYS_ptrace: c_long = 101; +pub const SYS_getuid: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_getgid: c_long = 104; +pub const SYS_setuid: c_long = 105; +pub const SYS_setgid: c_long = 106; +pub const SYS_geteuid: c_long = 107; +pub const SYS_getegid: c_long = 108; +pub const SYS_setpgid: c_long = 109; +pub const SYS_getppid: c_long = 110; +pub const SYS_getpgrp: c_long = 111; +pub const SYS_setsid: c_long = 112; +pub const SYS_setreuid: c_long = 113; +pub const SYS_setregid: c_long = 114; +pub const SYS_getgroups: c_long = 115; +pub const SYS_setgroups: c_long = 116; +pub const SYS_setresuid: c_long = 117; +pub const SYS_getresuid: c_long = 118; +pub const SYS_setresgid: c_long = 119; +pub const SYS_getresgid: c_long = 120; +pub const SYS_getpgid: c_long = 121; +pub const SYS_setfsuid: c_long = 122; +pub const SYS_setfsgid: c_long = 123; +pub const SYS_getsid: c_long = 124; +pub const SYS_capget: c_long = 125; +pub const SYS_capset: c_long = 126; +pub const SYS_rt_sigpending: c_long = 127; +pub const SYS_rt_sigtimedwait: c_long = 128; +pub const SYS_rt_sigqueueinfo: c_long = 129; +pub const SYS_rt_sigsuspend: c_long = 130; +pub const SYS_sigaltstack: c_long = 131; +pub const SYS_utime: c_long = 132; +pub const SYS_mknod: c_long = 133; +pub const SYS_uselib: c_long = 134; +pub const SYS_personality: c_long = 135; +pub const SYS_ustat: c_long = 136; +pub const SYS_statfs: c_long = 137; +pub const SYS_fstatfs: c_long = 138; +pub const SYS_sysfs: c_long = 139; +pub const SYS_getpriority: c_long = 140; +pub const SYS_setpriority: c_long = 141; +pub const SYS_sched_setparam: c_long = 142; +pub const SYS_sched_getparam: c_long = 143; +pub const SYS_sched_setscheduler: c_long = 144; +pub const SYS_sched_getscheduler: c_long = 145; +pub const SYS_sched_get_priority_max: c_long = 146; +pub const SYS_sched_get_priority_min: c_long = 147; +pub const SYS_sched_rr_get_interval: c_long = 148; +pub const SYS_mlock: c_long = 149; +pub const SYS_munlock: c_long = 150; +pub const SYS_mlockall: c_long = 151; +pub const SYS_munlockall: c_long = 152; +pub const SYS_vhangup: c_long = 153; +pub const SYS_modify_ldt: c_long = 154; +pub const SYS_pivot_root: c_long = 155; +pub const SYS__sysctl: c_long = 156; +pub const SYS_prctl: c_long = 157; +pub const SYS_arch_prctl: c_long = 158; +pub const SYS_adjtimex: c_long = 159; +pub const SYS_setrlimit: c_long = 160; +pub const SYS_chroot: c_long = 161; +pub const SYS_sync: c_long = 162; +pub const SYS_acct: c_long = 163; +pub const SYS_settimeofday: c_long = 164; +pub const SYS_mount: c_long = 165; +pub const SYS_umount2: c_long = 166; +pub const SYS_swapon: c_long = 167; +pub const SYS_swapoff: c_long = 168; +pub const SYS_reboot: c_long = 169; +pub const SYS_sethostname: c_long = 170; +pub const SYS_setdomainname: c_long = 171; +pub const SYS_iopl: c_long = 172; +pub const SYS_ioperm: c_long = 173; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 174; +pub const SYS_init_module: c_long = 175; +pub const SYS_delete_module: c_long = 176; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 177; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 178; +pub const SYS_quotactl: c_long = 179; +pub const SYS_nfsservctl: c_long = 180; +pub const SYS_getpmsg: c_long = 181; +pub const SYS_putpmsg: c_long = 182; +pub const SYS_afs_syscall: c_long = 183; +pub const SYS_tuxcall: c_long = 184; +pub const SYS_security: c_long = 185; +pub const SYS_gettid: c_long = 186; +pub const SYS_readahead: c_long = 187; +pub const SYS_setxattr: c_long = 188; +pub const SYS_lsetxattr: c_long = 189; +pub const SYS_fsetxattr: c_long = 190; +pub const SYS_getxattr: c_long = 191; +pub const SYS_lgetxattr: c_long = 192; +pub const SYS_fgetxattr: c_long = 193; +pub const SYS_listxattr: c_long = 194; +pub const SYS_llistxattr: c_long = 195; +pub const SYS_flistxattr: c_long = 196; +pub const SYS_removexattr: c_long = 197; +pub const SYS_lremovexattr: c_long = 198; +pub const SYS_fremovexattr: c_long = 199; +pub const SYS_tkill: c_long = 200; +pub const SYS_time: c_long = 201; +pub const SYS_futex: c_long = 202; +pub const SYS_sched_setaffinity: c_long = 203; +pub const SYS_sched_getaffinity: c_long = 204; +pub const SYS_set_thread_area: c_long = 205; +pub const SYS_io_setup: c_long = 206; +pub const SYS_io_destroy: c_long = 207; +pub const SYS_io_getevents: c_long = 208; +pub const SYS_io_submit: c_long = 209; +pub const SYS_io_cancel: c_long = 210; +pub const SYS_get_thread_area: c_long = 211; +pub const SYS_lookup_dcookie: c_long = 212; +pub const SYS_epoll_create: c_long = 213; +pub const SYS_epoll_ctl_old: c_long = 214; +pub const SYS_epoll_wait_old: c_long = 215; +pub const SYS_remap_file_pages: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_set_tid_address: c_long = 218; +pub const SYS_restart_syscall: c_long = 219; +pub const SYS_semtimedop: c_long = 220; +pub const SYS_fadvise64: c_long = 221; +pub const SYS_timer_create: c_long = 222; +pub const SYS_timer_settime: c_long = 223; +pub const SYS_timer_gettime: c_long = 224; +pub const SYS_timer_getoverrun: c_long = 225; +pub const SYS_timer_delete: c_long = 226; +pub const SYS_clock_settime: c_long = 227; +pub const SYS_clock_gettime: c_long = 228; +pub const SYS_clock_getres: c_long = 229; +pub const SYS_clock_nanosleep: c_long = 230; +pub const SYS_exit_group: c_long = 231; +pub const SYS_epoll_wait: c_long = 232; +pub const SYS_epoll_ctl: c_long = 233; +pub const SYS_tgkill: c_long = 234; +pub const SYS_utimes: c_long = 235; +pub const SYS_vserver: c_long = 236; +pub const SYS_mbind: c_long = 237; +pub const SYS_set_mempolicy: c_long = 238; +pub const SYS_get_mempolicy: c_long = 239; +pub const SYS_mq_open: c_long = 240; +pub const SYS_mq_unlink: c_long = 241; +pub const SYS_mq_timedsend: c_long = 242; +pub const SYS_mq_timedreceive: c_long = 243; +pub const SYS_mq_notify: c_long = 244; +pub const SYS_mq_getsetattr: c_long = 245; +pub const SYS_kexec_load: c_long = 246; +pub const SYS_waitid: c_long = 247; +pub const SYS_add_key: c_long = 248; +pub const SYS_request_key: c_long = 249; +pub const SYS_keyctl: c_long = 250; +pub const SYS_ioprio_set: c_long = 251; +pub const SYS_ioprio_get: c_long = 252; +pub const SYS_inotify_init: c_long = 253; +pub const SYS_inotify_add_watch: c_long = 254; +pub const SYS_inotify_rm_watch: c_long = 255; +pub const SYS_migrate_pages: c_long = 256; +pub const SYS_openat: c_long = 257; +pub const SYS_mkdirat: c_long = 258; +pub const SYS_mknodat: c_long = 259; +pub const SYS_fchownat: c_long = 260; +pub const SYS_futimesat: c_long = 261; +pub const SYS_newfstatat: c_long = 262; +pub const SYS_unlinkat: c_long = 263; +pub const SYS_renameat: c_long = 264; +pub const SYS_linkat: c_long = 265; +pub const SYS_symlinkat: c_long = 266; +pub const SYS_readlinkat: c_long = 267; +pub const SYS_fchmodat: c_long = 268; +pub const SYS_faccessat: c_long = 269; +pub const SYS_pselect6: c_long = 270; +pub const SYS_ppoll: c_long = 271; +pub const SYS_unshare: c_long = 272; +pub const SYS_set_robust_list: c_long = 273; +pub const SYS_get_robust_list: c_long = 274; +pub const SYS_splice: c_long = 275; +pub const SYS_tee: c_long = 276; +pub const SYS_sync_file_range: c_long = 277; +pub const SYS_vmsplice: c_long = 278; +pub const SYS_move_pages: c_long = 279; +pub const SYS_utimensat: c_long = 280; +pub const SYS_epoll_pwait: c_long = 281; +pub const SYS_signalfd: c_long = 282; +pub const SYS_timerfd_create: c_long = 283; +pub const SYS_eventfd: c_long = 284; +pub const SYS_fallocate: c_long = 285; +pub const SYS_timerfd_settime: c_long = 286; +pub const SYS_timerfd_gettime: c_long = 287; +pub const SYS_accept4: c_long = 288; +pub const SYS_signalfd4: c_long = 289; +pub const SYS_eventfd2: c_long = 290; +pub const SYS_epoll_create1: c_long = 291; +pub const SYS_dup3: c_long = 292; +pub const SYS_pipe2: c_long = 293; +pub const SYS_inotify_init1: c_long = 294; +pub const SYS_preadv: c_long = 295; +pub const SYS_pwritev: c_long = 296; +pub const SYS_rt_tgsigqueueinfo: c_long = 297; +pub const SYS_perf_event_open: c_long = 298; +pub const SYS_recvmmsg: c_long = 299; +pub const SYS_fanotify_init: c_long = 300; +pub const SYS_fanotify_mark: c_long = 301; +pub const SYS_prlimit64: c_long = 302; +pub const SYS_name_to_handle_at: c_long = 303; +pub const SYS_open_by_handle_at: c_long = 304; +pub const SYS_clock_adjtime: c_long = 305; +pub const SYS_syncfs: c_long = 306; +pub const SYS_sendmmsg: c_long = 307; +pub const SYS_setns: c_long = 308; +pub const SYS_getcpu: c_long = 309; +pub const SYS_process_vm_readv: c_long = 310; +pub const SYS_process_vm_writev: c_long = 311; +pub const SYS_kcmp: c_long = 312; +pub const SYS_finit_module: c_long = 313; +pub const SYS_sched_setattr: c_long = 314; +pub const SYS_sched_getattr: c_long = 315; +pub const SYS_renameat2: c_long = 316; +pub const SYS_seccomp: c_long = 317; +pub const SYS_getrandom: c_long = 318; +pub const SYS_memfd_create: c_long = 319; +pub const SYS_kexec_file_load: c_long = 320; +pub const SYS_bpf: c_long = 321; +pub const SYS_execveat: c_long = 322; +pub const SYS_userfaultfd: c_long = 323; +pub const SYS_membarrier: c_long = 324; +pub const SYS_mlock2: c_long = 325; +pub const SYS_copy_file_range: c_long = 326; +pub const SYS_preadv2: c_long = 327; +pub const SYS_pwritev2: c_long = 328; +pub const SYS_pkey_mprotect: c_long = 329; +pub const SYS_pkey_alloc: c_long = 330; +pub const SYS_pkey_free: c_long = 331; +pub const SYS_statx: c_long = 332; +pub const SYS_rseq: c_long = 334; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_mseal: c_long = 462; + +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs new file mode 100644 index 00000000000000..1a1cd34be035f7 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs @@ -0,0 +1,398 @@ +use crate::prelude::*; +use crate::pthread_mutex_t; + +s! { + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } +} + +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 44; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; + +pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; +pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: crate::pthread_mutex_t = pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], +}; + +// Syscall table + +pub const __X32_SYSCALL_BIT: c_long = 0x40000000; + +pub const SYS_read: c_long = __X32_SYSCALL_BIT + 0; +pub const SYS_write: c_long = __X32_SYSCALL_BIT + 1; +pub const SYS_open: c_long = __X32_SYSCALL_BIT + 2; +pub const SYS_close: c_long = __X32_SYSCALL_BIT + 3; +pub const SYS_stat: c_long = __X32_SYSCALL_BIT + 4; +pub const SYS_fstat: c_long = __X32_SYSCALL_BIT + 5; +pub const SYS_lstat: c_long = __X32_SYSCALL_BIT + 6; +pub const SYS_poll: c_long = __X32_SYSCALL_BIT + 7; +pub const SYS_lseek: c_long = __X32_SYSCALL_BIT + 8; +pub const SYS_mmap: c_long = __X32_SYSCALL_BIT + 9; +pub const SYS_mprotect: c_long = __X32_SYSCALL_BIT + 10; +pub const SYS_munmap: c_long = __X32_SYSCALL_BIT + 11; +pub const SYS_brk: c_long = __X32_SYSCALL_BIT + 12; +pub const SYS_rt_sigprocmask: c_long = __X32_SYSCALL_BIT + 14; +pub const SYS_pread64: c_long = __X32_SYSCALL_BIT + 17; +pub const SYS_pwrite64: c_long = __X32_SYSCALL_BIT + 18; +pub const SYS_access: c_long = __X32_SYSCALL_BIT + 21; +pub const SYS_pipe: c_long = __X32_SYSCALL_BIT + 22; +pub const SYS_select: c_long = __X32_SYSCALL_BIT + 23; +pub const SYS_sched_yield: c_long = __X32_SYSCALL_BIT + 24; +pub const SYS_mremap: c_long = __X32_SYSCALL_BIT + 25; +pub const SYS_msync: c_long = __X32_SYSCALL_BIT + 26; +pub const SYS_mincore: c_long = __X32_SYSCALL_BIT + 27; +pub const SYS_madvise: c_long = __X32_SYSCALL_BIT + 28; +pub const SYS_shmget: c_long = __X32_SYSCALL_BIT + 29; +pub const SYS_shmat: c_long = __X32_SYSCALL_BIT + 30; +pub const SYS_shmctl: c_long = __X32_SYSCALL_BIT + 31; +pub const SYS_dup: c_long = __X32_SYSCALL_BIT + 32; +pub const SYS_dup2: c_long = __X32_SYSCALL_BIT + 33; +pub const SYS_pause: c_long = __X32_SYSCALL_BIT + 34; +pub const SYS_nanosleep: c_long = __X32_SYSCALL_BIT + 35; +pub const SYS_getitimer: c_long = __X32_SYSCALL_BIT + 36; +pub const SYS_alarm: c_long = __X32_SYSCALL_BIT + 37; +pub const SYS_setitimer: c_long = __X32_SYSCALL_BIT + 38; +pub const SYS_getpid: c_long = __X32_SYSCALL_BIT + 39; +pub const SYS_sendfile: c_long = __X32_SYSCALL_BIT + 40; +pub const SYS_socket: c_long = __X32_SYSCALL_BIT + 41; +pub const SYS_connect: c_long = __X32_SYSCALL_BIT + 42; +pub const SYS_accept: c_long = __X32_SYSCALL_BIT + 43; +pub const SYS_sendto: c_long = __X32_SYSCALL_BIT + 44; +pub const SYS_shutdown: c_long = __X32_SYSCALL_BIT + 48; +pub const SYS_bind: c_long = __X32_SYSCALL_BIT + 49; +pub const SYS_listen: c_long = __X32_SYSCALL_BIT + 50; +pub const SYS_getsockname: c_long = __X32_SYSCALL_BIT + 51; +pub const SYS_getpeername: c_long = __X32_SYSCALL_BIT + 52; +pub const SYS_socketpair: c_long = __X32_SYSCALL_BIT + 53; +pub const SYS_clone: c_long = __X32_SYSCALL_BIT + 56; +pub const SYS_fork: c_long = __X32_SYSCALL_BIT + 57; +pub const SYS_vfork: c_long = __X32_SYSCALL_BIT + 58; +pub const SYS_exit: c_long = __X32_SYSCALL_BIT + 60; +pub const SYS_wait4: c_long = __X32_SYSCALL_BIT + 61; +pub const SYS_kill: c_long = __X32_SYSCALL_BIT + 62; +pub const SYS_uname: c_long = __X32_SYSCALL_BIT + 63; +pub const SYS_semget: c_long = __X32_SYSCALL_BIT + 64; +pub const SYS_semop: c_long = __X32_SYSCALL_BIT + 65; +pub const SYS_semctl: c_long = __X32_SYSCALL_BIT + 66; +pub const SYS_shmdt: c_long = __X32_SYSCALL_BIT + 67; +pub const SYS_msgget: c_long = __X32_SYSCALL_BIT + 68; +pub const SYS_msgsnd: c_long = __X32_SYSCALL_BIT + 69; +pub const SYS_msgrcv: c_long = __X32_SYSCALL_BIT + 70; +pub const SYS_msgctl: c_long = __X32_SYSCALL_BIT + 71; +pub const SYS_fcntl: c_long = __X32_SYSCALL_BIT + 72; +pub const SYS_flock: c_long = __X32_SYSCALL_BIT + 73; +pub const SYS_fsync: c_long = __X32_SYSCALL_BIT + 74; +pub const SYS_fdatasync: c_long = __X32_SYSCALL_BIT + 75; +pub const SYS_truncate: c_long = __X32_SYSCALL_BIT + 76; +pub const SYS_ftruncate: c_long = __X32_SYSCALL_BIT + 77; +pub const SYS_getdents: c_long = __X32_SYSCALL_BIT + 78; +pub const SYS_getcwd: c_long = __X32_SYSCALL_BIT + 79; +pub const SYS_chdir: c_long = __X32_SYSCALL_BIT + 80; +pub const SYS_fchdir: c_long = __X32_SYSCALL_BIT + 81; +pub const SYS_rename: c_long = __X32_SYSCALL_BIT + 82; +pub const SYS_mkdir: c_long = __X32_SYSCALL_BIT + 83; +pub const SYS_rmdir: c_long = __X32_SYSCALL_BIT + 84; +pub const SYS_creat: c_long = __X32_SYSCALL_BIT + 85; +pub const SYS_link: c_long = __X32_SYSCALL_BIT + 86; +pub const SYS_unlink: c_long = __X32_SYSCALL_BIT + 87; +pub const SYS_symlink: c_long = __X32_SYSCALL_BIT + 88; +pub const SYS_readlink: c_long = __X32_SYSCALL_BIT + 89; +pub const SYS_chmod: c_long = __X32_SYSCALL_BIT + 90; +pub const SYS_fchmod: c_long = __X32_SYSCALL_BIT + 91; +pub const SYS_chown: c_long = __X32_SYSCALL_BIT + 92; +pub const SYS_fchown: c_long = __X32_SYSCALL_BIT + 93; +pub const SYS_lchown: c_long = __X32_SYSCALL_BIT + 94; +pub const SYS_umask: c_long = __X32_SYSCALL_BIT + 95; +pub const SYS_gettimeofday: c_long = __X32_SYSCALL_BIT + 96; +pub const SYS_getrlimit: c_long = __X32_SYSCALL_BIT + 97; +pub const SYS_getrusage: c_long = __X32_SYSCALL_BIT + 98; +pub const SYS_sysinfo: c_long = __X32_SYSCALL_BIT + 99; +pub const SYS_times: c_long = __X32_SYSCALL_BIT + 100; +pub const SYS_getuid: c_long = __X32_SYSCALL_BIT + 102; +pub const SYS_syslog: c_long = __X32_SYSCALL_BIT + 103; +pub const SYS_getgid: c_long = __X32_SYSCALL_BIT + 104; +pub const SYS_setuid: c_long = __X32_SYSCALL_BIT + 105; +pub const SYS_setgid: c_long = __X32_SYSCALL_BIT + 106; +pub const SYS_geteuid: c_long = __X32_SYSCALL_BIT + 107; +pub const SYS_getegid: c_long = __X32_SYSCALL_BIT + 108; +pub const SYS_setpgid: c_long = __X32_SYSCALL_BIT + 109; +pub const SYS_getppid: c_long = __X32_SYSCALL_BIT + 110; +pub const SYS_getpgrp: c_long = __X32_SYSCALL_BIT + 111; +pub const SYS_setsid: c_long = __X32_SYSCALL_BIT + 112; +pub const SYS_setreuid: c_long = __X32_SYSCALL_BIT + 113; +pub const SYS_setregid: c_long = __X32_SYSCALL_BIT + 114; +pub const SYS_getgroups: c_long = __X32_SYSCALL_BIT + 115; +pub const SYS_setgroups: c_long = __X32_SYSCALL_BIT + 116; +pub const SYS_setresuid: c_long = __X32_SYSCALL_BIT + 117; +pub const SYS_getresuid: c_long = __X32_SYSCALL_BIT + 118; +pub const SYS_setresgid: c_long = __X32_SYSCALL_BIT + 119; +pub const SYS_getresgid: c_long = __X32_SYSCALL_BIT + 120; +pub const SYS_getpgid: c_long = __X32_SYSCALL_BIT + 121; +pub const SYS_setfsuid: c_long = __X32_SYSCALL_BIT + 122; +pub const SYS_setfsgid: c_long = __X32_SYSCALL_BIT + 123; +pub const SYS_getsid: c_long = __X32_SYSCALL_BIT + 124; +pub const SYS_capget: c_long = __X32_SYSCALL_BIT + 125; +pub const SYS_capset: c_long = __X32_SYSCALL_BIT + 126; +pub const SYS_rt_sigsuspend: c_long = __X32_SYSCALL_BIT + 130; +pub const SYS_utime: c_long = __X32_SYSCALL_BIT + 132; +pub const SYS_mknod: c_long = __X32_SYSCALL_BIT + 133; +pub const SYS_personality: c_long = __X32_SYSCALL_BIT + 135; +pub const SYS_ustat: c_long = __X32_SYSCALL_BIT + 136; +pub const SYS_statfs: c_long = __X32_SYSCALL_BIT + 137; +pub const SYS_fstatfs: c_long = __X32_SYSCALL_BIT + 138; +pub const SYS_sysfs: c_long = __X32_SYSCALL_BIT + 139; +pub const SYS_getpriority: c_long = __X32_SYSCALL_BIT + 140; +pub const SYS_setpriority: c_long = __X32_SYSCALL_BIT + 141; +pub const SYS_sched_setparam: c_long = __X32_SYSCALL_BIT + 142; +pub const SYS_sched_getparam: c_long = __X32_SYSCALL_BIT + 143; +pub const SYS_sched_setscheduler: c_long = __X32_SYSCALL_BIT + 144; +pub const SYS_sched_getscheduler: c_long = __X32_SYSCALL_BIT + 145; +pub const SYS_sched_get_priority_max: c_long = __X32_SYSCALL_BIT + 146; +pub const SYS_sched_get_priority_min: c_long = __X32_SYSCALL_BIT + 147; +pub const SYS_sched_rr_get_interval: c_long = __X32_SYSCALL_BIT + 148; +pub const SYS_mlock: c_long = __X32_SYSCALL_BIT + 149; +pub const SYS_munlock: c_long = __X32_SYSCALL_BIT + 150; +pub const SYS_mlockall: c_long = __X32_SYSCALL_BIT + 151; +pub const SYS_munlockall: c_long = __X32_SYSCALL_BIT + 152; +pub const SYS_vhangup: c_long = __X32_SYSCALL_BIT + 153; +pub const SYS_modify_ldt: c_long = __X32_SYSCALL_BIT + 154; +pub const SYS_pivot_root: c_long = __X32_SYSCALL_BIT + 155; +pub const SYS_prctl: c_long = __X32_SYSCALL_BIT + 157; +pub const SYS_arch_prctl: c_long = __X32_SYSCALL_BIT + 158; +pub const SYS_adjtimex: c_long = __X32_SYSCALL_BIT + 159; +pub const SYS_setrlimit: c_long = __X32_SYSCALL_BIT + 160; +pub const SYS_chroot: c_long = __X32_SYSCALL_BIT + 161; +pub const SYS_sync: c_long = __X32_SYSCALL_BIT + 162; +pub const SYS_acct: c_long = __X32_SYSCALL_BIT + 163; +pub const SYS_settimeofday: c_long = __X32_SYSCALL_BIT + 164; +pub const SYS_mount: c_long = __X32_SYSCALL_BIT + 165; +pub const SYS_umount2: c_long = __X32_SYSCALL_BIT + 166; +pub const SYS_swapon: c_long = __X32_SYSCALL_BIT + 167; +pub const SYS_swapoff: c_long = __X32_SYSCALL_BIT + 168; +pub const SYS_reboot: c_long = __X32_SYSCALL_BIT + 169; +pub const SYS_sethostname: c_long = __X32_SYSCALL_BIT + 170; +pub const SYS_setdomainname: c_long = __X32_SYSCALL_BIT + 171; +pub const SYS_iopl: c_long = __X32_SYSCALL_BIT + 172; +pub const SYS_ioperm: c_long = __X32_SYSCALL_BIT + 173; +pub const SYS_init_module: c_long = __X32_SYSCALL_BIT + 175; +pub const SYS_delete_module: c_long = __X32_SYSCALL_BIT + 176; +pub const SYS_quotactl: c_long = __X32_SYSCALL_BIT + 179; +pub const SYS_getpmsg: c_long = __X32_SYSCALL_BIT + 181; +pub const SYS_putpmsg: c_long = __X32_SYSCALL_BIT + 182; +pub const SYS_afs_syscall: c_long = __X32_SYSCALL_BIT + 183; +pub const SYS_tuxcall: c_long = __X32_SYSCALL_BIT + 184; +pub const SYS_security: c_long = __X32_SYSCALL_BIT + 185; +pub const SYS_gettid: c_long = __X32_SYSCALL_BIT + 186; +pub const SYS_readahead: c_long = __X32_SYSCALL_BIT + 187; +pub const SYS_setxattr: c_long = __X32_SYSCALL_BIT + 188; +pub const SYS_lsetxattr: c_long = __X32_SYSCALL_BIT + 189; +pub const SYS_fsetxattr: c_long = __X32_SYSCALL_BIT + 190; +pub const SYS_getxattr: c_long = __X32_SYSCALL_BIT + 191; +pub const SYS_lgetxattr: c_long = __X32_SYSCALL_BIT + 192; +pub const SYS_fgetxattr: c_long = __X32_SYSCALL_BIT + 193; +pub const SYS_listxattr: c_long = __X32_SYSCALL_BIT + 194; +pub const SYS_llistxattr: c_long = __X32_SYSCALL_BIT + 195; +pub const SYS_flistxattr: c_long = __X32_SYSCALL_BIT + 196; +pub const SYS_removexattr: c_long = __X32_SYSCALL_BIT + 197; +pub const SYS_lremovexattr: c_long = __X32_SYSCALL_BIT + 198; +pub const SYS_fremovexattr: c_long = __X32_SYSCALL_BIT + 199; +pub const SYS_tkill: c_long = __X32_SYSCALL_BIT + 200; +pub const SYS_time: c_long = __X32_SYSCALL_BIT + 201; +pub const SYS_futex: c_long = __X32_SYSCALL_BIT + 202; +pub const SYS_sched_setaffinity: c_long = __X32_SYSCALL_BIT + 203; +pub const SYS_sched_getaffinity: c_long = __X32_SYSCALL_BIT + 204; +pub const SYS_io_destroy: c_long = __X32_SYSCALL_BIT + 207; +pub const SYS_io_getevents: c_long = __X32_SYSCALL_BIT + 208; +pub const SYS_io_cancel: c_long = __X32_SYSCALL_BIT + 210; +pub const SYS_lookup_dcookie: c_long = __X32_SYSCALL_BIT + 212; +pub const SYS_epoll_create: c_long = __X32_SYSCALL_BIT + 213; +pub const SYS_remap_file_pages: c_long = __X32_SYSCALL_BIT + 216; +pub const SYS_getdents64: c_long = __X32_SYSCALL_BIT + 217; +pub const SYS_set_tid_address: c_long = __X32_SYSCALL_BIT + 218; +pub const SYS_restart_syscall: c_long = __X32_SYSCALL_BIT + 219; +pub const SYS_semtimedop: c_long = __X32_SYSCALL_BIT + 220; +pub const SYS_fadvise64: c_long = __X32_SYSCALL_BIT + 221; +pub const SYS_timer_settime: c_long = __X32_SYSCALL_BIT + 223; +pub const SYS_timer_gettime: c_long = __X32_SYSCALL_BIT + 224; +pub const SYS_timer_getoverrun: c_long = __X32_SYSCALL_BIT + 225; +pub const SYS_timer_delete: c_long = __X32_SYSCALL_BIT + 226; +pub const SYS_clock_settime: c_long = __X32_SYSCALL_BIT + 227; +pub const SYS_clock_gettime: c_long = __X32_SYSCALL_BIT + 228; +pub const SYS_clock_getres: c_long = __X32_SYSCALL_BIT + 229; +pub const SYS_clock_nanosleep: c_long = __X32_SYSCALL_BIT + 230; +pub const SYS_exit_group: c_long = __X32_SYSCALL_BIT + 231; +pub const SYS_epoll_wait: c_long = __X32_SYSCALL_BIT + 232; +pub const SYS_epoll_ctl: c_long = __X32_SYSCALL_BIT + 233; +pub const SYS_tgkill: c_long = __X32_SYSCALL_BIT + 234; +pub const SYS_utimes: c_long = __X32_SYSCALL_BIT + 235; +pub const SYS_mbind: c_long = __X32_SYSCALL_BIT + 237; +pub const SYS_set_mempolicy: c_long = __X32_SYSCALL_BIT + 238; +pub const SYS_get_mempolicy: c_long = __X32_SYSCALL_BIT + 239; +pub const SYS_mq_open: c_long = __X32_SYSCALL_BIT + 240; +pub const SYS_mq_unlink: c_long = __X32_SYSCALL_BIT + 241; +pub const SYS_mq_timedsend: c_long = __X32_SYSCALL_BIT + 242; +pub const SYS_mq_timedreceive: c_long = __X32_SYSCALL_BIT + 243; +pub const SYS_mq_getsetattr: c_long = __X32_SYSCALL_BIT + 245; +pub const SYS_add_key: c_long = __X32_SYSCALL_BIT + 248; +pub const SYS_request_key: c_long = __X32_SYSCALL_BIT + 249; +pub const SYS_keyctl: c_long = __X32_SYSCALL_BIT + 250; +pub const SYS_ioprio_set: c_long = __X32_SYSCALL_BIT + 251; +pub const SYS_ioprio_get: c_long = __X32_SYSCALL_BIT + 252; +pub const SYS_inotify_init: c_long = __X32_SYSCALL_BIT + 253; +pub const SYS_inotify_add_watch: c_long = __X32_SYSCALL_BIT + 254; +pub const SYS_inotify_rm_watch: c_long = __X32_SYSCALL_BIT + 255; +pub const SYS_migrate_pages: c_long = __X32_SYSCALL_BIT + 256; +pub const SYS_openat: c_long = __X32_SYSCALL_BIT + 257; +pub const SYS_mkdirat: c_long = __X32_SYSCALL_BIT + 258; +pub const SYS_mknodat: c_long = __X32_SYSCALL_BIT + 259; +pub const SYS_fchownat: c_long = __X32_SYSCALL_BIT + 260; +pub const SYS_futimesat: c_long = __X32_SYSCALL_BIT + 261; +pub const SYS_newfstatat: c_long = __X32_SYSCALL_BIT + 262; +pub const SYS_unlinkat: c_long = __X32_SYSCALL_BIT + 263; +pub const SYS_renameat: c_long = __X32_SYSCALL_BIT + 264; +pub const SYS_linkat: c_long = __X32_SYSCALL_BIT + 265; +pub const SYS_symlinkat: c_long = __X32_SYSCALL_BIT + 266; +pub const SYS_readlinkat: c_long = __X32_SYSCALL_BIT + 267; +pub const SYS_fchmodat: c_long = __X32_SYSCALL_BIT + 268; +pub const SYS_faccessat: c_long = __X32_SYSCALL_BIT + 269; +pub const SYS_pselect6: c_long = __X32_SYSCALL_BIT + 270; +pub const SYS_ppoll: c_long = __X32_SYSCALL_BIT + 271; +pub const SYS_unshare: c_long = __X32_SYSCALL_BIT + 272; +pub const SYS_splice: c_long = __X32_SYSCALL_BIT + 275; +pub const SYS_tee: c_long = __X32_SYSCALL_BIT + 276; +pub const SYS_sync_file_range: c_long = __X32_SYSCALL_BIT + 277; +pub const SYS_utimensat: c_long = __X32_SYSCALL_BIT + 280; +pub const SYS_epoll_pwait: c_long = __X32_SYSCALL_BIT + 281; +pub const SYS_signalfd: c_long = __X32_SYSCALL_BIT + 282; +pub const SYS_timerfd_create: c_long = __X32_SYSCALL_BIT + 283; +pub const SYS_eventfd: c_long = __X32_SYSCALL_BIT + 284; +pub const SYS_fallocate: c_long = __X32_SYSCALL_BIT + 285; +pub const SYS_timerfd_settime: c_long = __X32_SYSCALL_BIT + 286; +pub const SYS_timerfd_gettime: c_long = __X32_SYSCALL_BIT + 287; +pub const SYS_accept4: c_long = __X32_SYSCALL_BIT + 288; +pub const SYS_signalfd4: c_long = __X32_SYSCALL_BIT + 289; +pub const SYS_eventfd2: c_long = __X32_SYSCALL_BIT + 290; +pub const SYS_epoll_create1: c_long = __X32_SYSCALL_BIT + 291; +pub const SYS_dup3: c_long = __X32_SYSCALL_BIT + 292; +pub const SYS_pipe2: c_long = __X32_SYSCALL_BIT + 293; +pub const SYS_inotify_init1: c_long = __X32_SYSCALL_BIT + 294; +pub const SYS_perf_event_open: c_long = __X32_SYSCALL_BIT + 298; +pub const SYS_fanotify_init: c_long = __X32_SYSCALL_BIT + 300; +pub const SYS_fanotify_mark: c_long = __X32_SYSCALL_BIT + 301; +pub const SYS_prlimit64: c_long = __X32_SYSCALL_BIT + 302; +pub const SYS_name_to_handle_at: c_long = __X32_SYSCALL_BIT + 303; +pub const SYS_open_by_handle_at: c_long = __X32_SYSCALL_BIT + 304; +pub const SYS_clock_adjtime: c_long = __X32_SYSCALL_BIT + 305; +pub const SYS_syncfs: c_long = __X32_SYSCALL_BIT + 306; +pub const SYS_setns: c_long = __X32_SYSCALL_BIT + 308; +pub const SYS_getcpu: c_long = __X32_SYSCALL_BIT + 309; +pub const SYS_kcmp: c_long = __X32_SYSCALL_BIT + 312; +pub const SYS_finit_module: c_long = __X32_SYSCALL_BIT + 313; +pub const SYS_sched_setattr: c_long = __X32_SYSCALL_BIT + 314; +pub const SYS_sched_getattr: c_long = __X32_SYSCALL_BIT + 315; +pub const SYS_renameat2: c_long = __X32_SYSCALL_BIT + 316; +pub const SYS_seccomp: c_long = __X32_SYSCALL_BIT + 317; +pub const SYS_getrandom: c_long = __X32_SYSCALL_BIT + 318; +pub const SYS_memfd_create: c_long = __X32_SYSCALL_BIT + 319; +pub const SYS_kexec_file_load: c_long = __X32_SYSCALL_BIT + 320; +pub const SYS_bpf: c_long = __X32_SYSCALL_BIT + 321; +pub const SYS_userfaultfd: c_long = __X32_SYSCALL_BIT + 323; +pub const SYS_membarrier: c_long = __X32_SYSCALL_BIT + 324; +pub const SYS_mlock2: c_long = __X32_SYSCALL_BIT + 325; +pub const SYS_copy_file_range: c_long = __X32_SYSCALL_BIT + 326; +pub const SYS_pkey_mprotect: c_long = __X32_SYSCALL_BIT + 329; +pub const SYS_pkey_alloc: c_long = __X32_SYSCALL_BIT + 330; +pub const SYS_pkey_free: c_long = __X32_SYSCALL_BIT + 331; +pub const SYS_statx: c_long = __X32_SYSCALL_BIT + 332; +pub const SYS_rseq: c_long = __X32_SYSCALL_BIT + 334; +pub const SYS_pidfd_send_signal: c_long = __X32_SYSCALL_BIT + 424; +pub const SYS_io_uring_setup: c_long = __X32_SYSCALL_BIT + 425; +pub const SYS_io_uring_enter: c_long = __X32_SYSCALL_BIT + 426; +pub const SYS_io_uring_register: c_long = __X32_SYSCALL_BIT + 427; +pub const SYS_open_tree: c_long = __X32_SYSCALL_BIT + 428; +pub const SYS_move_mount: c_long = __X32_SYSCALL_BIT + 429; +pub const SYS_fsopen: c_long = __X32_SYSCALL_BIT + 430; +pub const SYS_fsconfig: c_long = __X32_SYSCALL_BIT + 431; +pub const SYS_fsmount: c_long = __X32_SYSCALL_BIT + 432; +pub const SYS_fspick: c_long = __X32_SYSCALL_BIT + 433; +pub const SYS_pidfd_open: c_long = __X32_SYSCALL_BIT + 434; +pub const SYS_clone3: c_long = __X32_SYSCALL_BIT + 435; +pub const SYS_close_range: c_long = __X32_SYSCALL_BIT + 436; +pub const SYS_openat2: c_long = __X32_SYSCALL_BIT + 437; +pub const SYS_pidfd_getfd: c_long = __X32_SYSCALL_BIT + 438; +pub const SYS_faccessat2: c_long = __X32_SYSCALL_BIT + 439; +pub const SYS_process_madvise: c_long = __X32_SYSCALL_BIT + 440; +pub const SYS_epoll_pwait2: c_long = __X32_SYSCALL_BIT + 441; +pub const SYS_mount_setattr: c_long = __X32_SYSCALL_BIT + 442; +pub const SYS_quotactl_fd: c_long = __X32_SYSCALL_BIT + 443; +pub const SYS_landlock_create_ruleset: c_long = __X32_SYSCALL_BIT + 444; +pub const SYS_landlock_add_rule: c_long = __X32_SYSCALL_BIT + 445; +pub const SYS_landlock_restrict_self: c_long = __X32_SYSCALL_BIT + 446; +pub const SYS_memfd_secret: c_long = __X32_SYSCALL_BIT + 447; +pub const SYS_process_mrelease: c_long = __X32_SYSCALL_BIT + 448; +pub const SYS_futex_waitv: c_long = __X32_SYSCALL_BIT + 449; +pub const SYS_set_mempolicy_home_node: c_long = __X32_SYSCALL_BIT + 450; +pub const SYS_fchmodat2: c_long = __X32_SYSCALL_BIT + 452; +pub const SYS_rt_sigaction: c_long = __X32_SYSCALL_BIT + 512; +pub const SYS_rt_sigreturn: c_long = __X32_SYSCALL_BIT + 513; +pub const SYS_ioctl: c_long = __X32_SYSCALL_BIT + 514; +pub const SYS_readv: c_long = __X32_SYSCALL_BIT + 515; +pub const SYS_writev: c_long = __X32_SYSCALL_BIT + 516; +pub const SYS_recvfrom: c_long = __X32_SYSCALL_BIT + 517; +pub const SYS_sendmsg: c_long = __X32_SYSCALL_BIT + 518; +pub const SYS_recvmsg: c_long = __X32_SYSCALL_BIT + 519; +pub const SYS_execve: c_long = __X32_SYSCALL_BIT + 520; +pub const SYS_ptrace: c_long = __X32_SYSCALL_BIT + 521; +pub const SYS_rt_sigpending: c_long = __X32_SYSCALL_BIT + 522; +pub const SYS_rt_sigtimedwait: c_long = __X32_SYSCALL_BIT + 523; +pub const SYS_rt_sigqueueinfo: c_long = __X32_SYSCALL_BIT + 524; +pub const SYS_sigaltstack: c_long = __X32_SYSCALL_BIT + 525; +pub const SYS_timer_create: c_long = __X32_SYSCALL_BIT + 526; +pub const SYS_mq_notify: c_long = __X32_SYSCALL_BIT + 527; +pub const SYS_kexec_load: c_long = __X32_SYSCALL_BIT + 528; +pub const SYS_waitid: c_long = __X32_SYSCALL_BIT + 529; +pub const SYS_set_robust_list: c_long = __X32_SYSCALL_BIT + 530; +pub const SYS_get_robust_list: c_long = __X32_SYSCALL_BIT + 531; +pub const SYS_vmsplice: c_long = __X32_SYSCALL_BIT + 532; +pub const SYS_move_pages: c_long = __X32_SYSCALL_BIT + 533; +pub const SYS_preadv: c_long = __X32_SYSCALL_BIT + 534; +pub const SYS_pwritev: c_long = __X32_SYSCALL_BIT + 535; +pub const SYS_rt_tgsigqueueinfo: c_long = __X32_SYSCALL_BIT + 536; +pub const SYS_recvmmsg: c_long = __X32_SYSCALL_BIT + 537; +pub const SYS_sendmmsg: c_long = __X32_SYSCALL_BIT + 538; +pub const SYS_process_vm_readv: c_long = __X32_SYSCALL_BIT + 539; +pub const SYS_process_vm_writev: c_long = __X32_SYSCALL_BIT + 540; +pub const SYS_setsockopt: c_long = __X32_SYSCALL_BIT + 541; +pub const SYS_getsockopt: c_long = __X32_SYSCALL_BIT + 542; +pub const SYS_io_setup: c_long = __X32_SYSCALL_BIT + 543; +pub const SYS_io_submit: c_long = __X32_SYSCALL_BIT + 544; +pub const SYS_execveat: c_long = __X32_SYSCALL_BIT + 545; +pub const SYS_preadv2: c_long = __X32_SYSCALL_BIT + 546; +pub const SYS_pwritev2: c_long = __X32_SYSCALL_BIT + 547; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs new file mode 100644 index 00000000000000..65e94a19a517bd --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs @@ -0,0 +1,1283 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type pthread_t = c_ulong; +pub type __priority_which_t = c_uint; +pub type __rlimit_resource_t = c_uint; +pub type Lmid_t = c_long; +pub type regoff_t = c_int; +pub type __kernel_rwf_t = c_int; +pub type __be16 = crate::__u16; + +cfg_if! { + if #[cfg(doc)] { + // Used in `linux::arch` to define ioctl constants. + pub(crate) type Ioctl = c_ulong; + } else { + #[doc(hidden)] + pub type Ioctl = c_ulong; + } +} + +s! { + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: crate::sigevent, + __next_prio: *mut aiocb, + __abs_prio: c_int, + __policy: c_int, + __error_code: c_int, + __return_value: ssize_t, + pub aio_offset: off_t, + #[cfg(all( + not(gnu_file_offset_bits64), + not(target_arch = "x86_64"), + target_pointer_width = "32" + ))] + __unused1: Padding<[c_char; 4]>, + __glibc_reserved: Padding<[c_char; 32]>, + } + + pub struct __exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct __timeval { + pub tv_sec: i32, + pub tv_usec: i32, + } + + pub struct glob64_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: size_t, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + )))] + pub c_ispeed: crate::speed_t, + #[cfg(not(any( + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + )))] + pub c_ospeed: crate::speed_t, + } + + pub struct mallinfo { + pub arena: c_int, + pub ordblks: c_int, + pub smblks: c_int, + pub hblks: c_int, + pub hblkhd: c_int, + pub usmblks: c_int, + pub fsmblks: c_int, + pub uordblks: c_int, + pub fordblks: c_int, + pub keepcost: c_int, + } + + pub struct mallinfo2 { + pub arena: size_t, + pub ordblks: size_t, + pub smblks: size_t, + pub hblks: size_t, + pub hblkhd: size_t, + pub usmblks: size_t, + pub fsmblks: size_t, + pub uordblks: size_t, + pub fordblks: size_t, + pub keepcost: size_t, + } + + pub struct ntptimeval { + pub time: crate::timeval, + pub maxerror: c_long, + pub esterror: c_long, + pub tai: c_long, + pub __glibc_reserved1: c_long, + pub __glibc_reserved2: c_long, + pub __glibc_reserved3: c_long, + pub __glibc_reserved4: c_long, + } + + pub struct regex_t { + __buffer: *mut c_void, + __allocated: size_t, + __used: size_t, + __syntax: c_ulong, + __fastmap: *mut c_char, + __translate: *mut c_char, + __re_nsub: size_t, + __bitfield: u8, + } + + pub struct Elf64_Chdr { + pub ch_type: crate::Elf64_Word, + pub ch_reserved: crate::Elf64_Word, + pub ch_size: crate::Elf64_Xword, + pub ch_addralign: crate::Elf64_Xword, + } + + pub struct Elf32_Chdr { + pub ch_type: crate::Elf32_Word, + pub ch_size: crate::Elf32_Word, + pub ch_addralign: crate::Elf32_Word, + } + + pub struct seminfo { + pub semmap: c_int, + pub semmni: c_int, + pub semmns: c_int, + pub semmnu: c_int, + pub semmsl: c_int, + pub semopm: c_int, + pub semume: c_int, + pub semusz: c_int, + pub semvmx: c_int, + pub semaem: c_int, + } + + pub struct ptrace_peeksiginfo_args { + pub off: crate::__u64, + pub flags: crate::__u32, + pub nr: crate::__s32, + } + + pub struct __c_anonymous_ptrace_syscall_info_entry { + pub nr: crate::__u64, + pub args: [crate::__u64; 6], + } + + pub struct __c_anonymous_ptrace_syscall_info_exit { + pub sval: crate::__s64, + pub is_error: crate::__u8, + } + + pub struct __c_anonymous_ptrace_syscall_info_seccomp { + pub nr: crate::__u64, + pub args: [crate::__u64; 6], + pub ret_data: crate::__u32, + reserved2: Padding, + } + + pub struct ptrace_syscall_info { + pub op: crate::__u8, + reserved: Padding, + pub flags: crate::__u16, + pub arch: crate::__u32, + pub instruction_pointer: crate::__u64, + pub stack_pointer: crate::__u64, + pub u: __c_anonymous_ptrace_syscall_info_data, + } + + pub struct ptrace_sud_config { + pub mode: crate::__u64, + pub selector: crate::__u64, + pub offset: crate::__u64, + pub len: crate::__u64, + } + + pub struct iocb { + pub aio_data: crate::__u64, + #[cfg(target_endian = "little")] + pub aio_key: crate::__u32, + #[cfg(target_endian = "little")] + pub aio_rw_flags: crate::__kernel_rwf_t, + #[cfg(target_endian = "big")] + pub aio_rw_flags: crate::__kernel_rwf_t, + #[cfg(target_endian = "big")] + pub aio_key: crate::__u32, + pub aio_lio_opcode: crate::__u16, + pub aio_reqprio: crate::__s16, + pub aio_fildes: crate::__u32, + pub aio_buf: crate::__u64, + pub aio_nbytes: crate::__u64, + pub aio_offset: crate::__s64, + aio_reserved2: Padding, + pub aio_flags: crate::__u32, + pub aio_resfd: crate::__u32, + } + + // netinet/tcp.h + + pub struct tcp_info { + pub tcpi_state: u8, + pub tcpi_ca_state: u8, + pub tcpi_retransmits: u8, + pub tcpi_probes: u8, + pub tcpi_backoff: u8, + pub tcpi_options: u8, + /// This contains the bitfields `tcpi_snd_wscale` and `tcpi_rcv_wscale`. + /// Each is 4 bits. + pub tcpi_snd_rcv_wscale: u8, + pub tcpi_rto: u32, + pub tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub tcpi_unacked: u32, + pub tcpi_sacked: u32, + pub tcpi_lost: u32, + pub tcpi_retrans: u32, + pub tcpi_fackets: u32, + pub tcpi_last_data_sent: u32, + pub tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub tcpi_last_ack_recv: u32, + pub tcpi_pmtu: u32, + pub tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub tcpi_advmss: u32, + pub tcpi_reordering: u32, + pub tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_total_retrans: u32, + } + + pub struct fanotify_event_info_pidfd { + pub hdr: crate::fanotify_event_info_header, + pub pidfd: crate::__s32, + } + + pub struct fanotify_event_info_error { + pub hdr: crate::fanotify_event_info_header, + pub error: crate::__s32, + pub error_count: crate::__u32, + } + + // FIXME(1.0) this is actually a union + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [c_char; 32], + } + + pub struct mbstate_t { + __count: c_int, + __wchb: [c_char; 4], + } + + pub struct fpos64_t { + __pos: off64_t, + __state: crate::mbstate_t, + } + + pub struct fpos_t { + #[cfg(not(gnu_file_offset_bits64))] + __pos: off_t, + #[cfg(gnu_file_offset_bits64)] + __pos: off64_t, + __state: crate::mbstate_t, + } + + // linux x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + #[cfg(all(gnu_time_bits64, target_endian = "big"))] + __pad: Padding, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub tv_nsec: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub tv_nsec: i64, + #[cfg(all(gnu_time_bits64, target_endian = "little"))] + __pad: Padding, + } + + pub struct utmpx { + pub ut_type: c_short, + pub ut_pid: crate::pid_t, + pub ut_line: [c_char; __UT_LINESIZE], + pub ut_id: [c_char; 4], + + pub ut_user: [c_char; __UT_NAMESIZE], + pub ut_host: [c_char; __UT_HOSTSIZE], + pub ut_exit: __exit_status, + + #[cfg(any( + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "loongarch64", + all(target_pointer_width = "32", not(target_arch = "x86_64")) + ))] + pub ut_session: c_long, + #[cfg(any( + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "loongarch64", + all(target_pointer_width = "32", not(target_arch = "x86_64")) + ))] + pub ut_tv: crate::timeval, + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "loongarch64", + all(target_pointer_width = "32", not(target_arch = "x86_64")) + )))] + pub ut_session: i32, + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "loongarch64", + all(target_pointer_width = "32", not(target_arch = "x86_64")) + )))] + pub ut_tv: __timeval, + + pub ut_addr_v6: [i32; 4], + __glibc_reserved: Padding<[c_char; 20]>, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t).cast::()).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_timer { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_tid: c_int, + _si_overrun: c_int, + si_sigval: crate::sigval, + } + (*(self as *const siginfo_t).cast::()).si_sigval + } +} + +s_no_extra_traits! { + // linux/if_ether.h + + #[repr(C, packed)] + pub struct ethhdr { + pub h_dest: [c_uchar; crate::ETH_ALEN as usize], + pub h_source: [c_uchar; crate::ETH_ALEN as usize], + pub h_proto: crate::__be16, + } + + // Internal, for casts to access union fields + struct sifields_sigchld { + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: c_long, + si_stime: c_long, + } + + // Internal, for casts to access union fields + union sifields { + _align_pointer: *mut c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + struct siginfo_f { + _siginfo_base: [c_int; 3], + sifields: sifields, + } +} + +impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*(self as *const siginfo_t).cast::()).sifields + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> c_long { + self.sifields().sigchld.si_stime + } +} + +s_no_extra_traits! { + pub union __c_anonymous_ptrace_syscall_info_data { + pub entry: __c_anonymous_ptrace_syscall_info_entry, + pub exit: __c_anonymous_ptrace_syscall_info_exit, + pub seccomp: __c_anonymous_ptrace_syscall_info_seccomp, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_ptrace_syscall_info_data { + fn eq(&self, other: &__c_anonymous_ptrace_syscall_info_data) -> bool { + unsafe { + self.entry == other.entry + || self.exit == other.exit + || self.seccomp == other.seccomp + } + } + } + + impl Eq for __c_anonymous_ptrace_syscall_info_data {} + + impl hash::Hash for __c_anonymous_ptrace_syscall_info_data { + fn hash(&self, state: &mut H) { + unsafe { + self.entry.hash(state); + self.exit.hash(state); + self.seccomp.hash(state); + } + } + } + } +} + +// include/uapi/asm-generic/hugetlb_encode.h +pub const HUGETLB_FLAG_ENCODE_SHIFT: c_int = 26; +pub const HUGETLB_FLAG_ENCODE_MASK: c_int = 0x3f; + +pub const HUGETLB_FLAG_ENCODE_64KB: c_int = 16 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_512KB: c_int = 19 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_1MB: c_int = 20 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_2MB: c_int = 21 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_8MB: c_int = 23 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_16MB: c_int = 24 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_32MB: c_int = 25 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_256MB: c_int = 28 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_512MB: c_int = 29 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_1GB: c_int = 30 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_2GB: c_int = 31 << HUGETLB_FLAG_ENCODE_SHIFT; +pub const HUGETLB_FLAG_ENCODE_16GB: c_int = 34 << HUGETLB_FLAG_ENCODE_SHIFT; + +// include/uapi/linux/mman.h +/* + * Huge page size encoding when MAP_HUGETLB is specified, and a huge page + * size other than the default is desired. See hugetlb_encode.h. + * All known huge page size encodings are provided here. It is the + * responsibility of the application to know which sizes are supported on + * the running system. See mmap(2) man page for details. + */ +pub const MAP_HUGE_SHIFT: c_int = HUGETLB_FLAG_ENCODE_SHIFT; +pub const MAP_HUGE_MASK: c_int = HUGETLB_FLAG_ENCODE_MASK; + +pub const MAP_HUGE_64KB: c_int = HUGETLB_FLAG_ENCODE_64KB; +pub const MAP_HUGE_512KB: c_int = HUGETLB_FLAG_ENCODE_512KB; +pub const MAP_HUGE_1MB: c_int = HUGETLB_FLAG_ENCODE_1MB; +pub const MAP_HUGE_2MB: c_int = HUGETLB_FLAG_ENCODE_2MB; +pub const MAP_HUGE_8MB: c_int = HUGETLB_FLAG_ENCODE_8MB; +pub const MAP_HUGE_16MB: c_int = HUGETLB_FLAG_ENCODE_16MB; +pub const MAP_HUGE_32MB: c_int = HUGETLB_FLAG_ENCODE_32MB; +pub const MAP_HUGE_256MB: c_int = HUGETLB_FLAG_ENCODE_256MB; +pub const MAP_HUGE_512MB: c_int = HUGETLB_FLAG_ENCODE_512MB; +pub const MAP_HUGE_1GB: c_int = HUGETLB_FLAG_ENCODE_1GB; +pub const MAP_HUGE_2GB: c_int = HUGETLB_FLAG_ENCODE_2GB; +pub const MAP_HUGE_16GB: c_int = HUGETLB_FLAG_ENCODE_16GB; + +pub const PRIO_PROCESS: crate::__priority_which_t = 0; +pub const PRIO_PGRP: crate::__priority_which_t = 1; +pub const PRIO_USER: crate::__priority_which_t = 2; + +pub const MS_RMT_MASK: c_ulong = 0x02800051; + +pub const __UT_LINESIZE: usize = 32; +pub const __UT_NAMESIZE: usize = 32; +pub const __UT_HOSTSIZE: usize = 256; +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const NEW_TIME: c_short = 3; +pub const OLD_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; + +// dlfcn.h +pub const LM_ID_BASE: c_long = 0; +pub const LM_ID_NEWLM: c_long = -1; + +pub const RTLD_DI_LMID: c_int = 1; +pub const RTLD_DI_LINKMAP: c_int = 2; +pub const RTLD_DI_CONFIGADDR: c_int = 3; +pub const RTLD_DI_SERINFO: c_int = 4; +pub const RTLD_DI_SERINFOSIZE: c_int = 5; +pub const RTLD_DI_ORIGIN: c_int = 6; +pub const RTLD_DI_PROFILENAME: c_int = 7; +pub const RTLD_DI_PROFILEOUT: c_int = 8; +pub const RTLD_DI_TLS_MODID: c_int = 9; +pub const RTLD_DI_TLS_DATA: c_int = 10; + +pub const SOCK_NONBLOCK: c_int = O_NONBLOCK; + +pub const SOL_RXRPC: c_int = 272; +pub const SOL_PPPOL2TP: c_int = 273; +pub const SOL_PNPIPE: c_int = 275; +pub const SOL_RDS: c_int = 276; +pub const SOL_IUCV: c_int = 277; +pub const SOL_CAIF: c_int = 278; +pub const SOL_NFC: c_int = 280; + +pub const MSG_TRYHARD: c_int = 4; + +pub const LC_PAPER: c_int = 7; +pub const LC_NAME: c_int = 8; +pub const LC_ADDRESS: c_int = 9; +pub const LC_TELEPHONE: c_int = 10; +pub const LC_MEASUREMENT: c_int = 11; +pub const LC_IDENTIFICATION: c_int = 12; +pub const LC_PAPER_MASK: c_int = 1 << LC_PAPER; +pub const LC_NAME_MASK: c_int = 1 << LC_NAME; +pub const LC_ADDRESS_MASK: c_int = 1 << LC_ADDRESS; +pub const LC_TELEPHONE_MASK: c_int = 1 << LC_TELEPHONE; +pub const LC_MEASUREMENT_MASK: c_int = 1 << LC_MEASUREMENT; +pub const LC_IDENTIFICATION_MASK: c_int = 1 << LC_IDENTIFICATION; +pub const LC_ALL_MASK: c_int = crate::LC_CTYPE_MASK + | crate::LC_NUMERIC_MASK + | crate::LC_TIME_MASK + | crate::LC_COLLATE_MASK + | crate::LC_MONETARY_MASK + | crate::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const ENOTSUP: c_int = EOPNOTSUPP; + +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_DCCP: c_int = 6; +#[deprecated(since = "0.2.70", note = "AF_PACKET must be used instead")] +pub const SOCK_PACKET: c_int = 10; + +pub const AF_IB: c_int = 27; +pub const AF_MPLS: c_int = 28; +pub const AF_NFC: c_int = 39; +pub const AF_VSOCK: c_int = 40; +pub const AF_XDP: c_int = 44; +pub const PF_IB: c_int = AF_IB; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_NFC: c_int = AF_NFC; +pub const PF_VSOCK: c_int = AF_VSOCK; +pub const PF_XDP: c_int = AF_XDP; + +pub const SIGEV_THREAD_ID: c_int = 4; + +pub const BUFSIZ: c_uint = 8192; +pub const TMP_MAX: c_uint = 238328; +pub const FOPEN_MAX: c_uint = 16; +pub const FILENAME_MAX: c_uint = 4096; +pub const _CS_GNU_LIBC_VERSION: c_int = 2; +pub const _CS_GNU_LIBPTHREAD_VERSION: c_int = 3; +pub const _CS_V6_ENV: c_int = 1148; +pub const _CS_V7_ENV: c_int = 1149; +pub const _SC_EQUIV_CLASS_MAX: c_int = 41; +pub const _SC_CHARCLASS_NAME_MAX: c_int = 45; +pub const _SC_PII: c_int = 53; +pub const _SC_PII_XTI: c_int = 54; +pub const _SC_PII_SOCKET: c_int = 55; +pub const _SC_PII_INTERNET: c_int = 56; +pub const _SC_PII_OSI: c_int = 57; +pub const _SC_POLL: c_int = 58; +pub const _SC_SELECT: c_int = 59; +pub const _SC_PII_INTERNET_STREAM: c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: c_int = 62; +pub const _SC_PII_OSI_COTS: c_int = 63; +pub const _SC_PII_OSI_CLTS: c_int = 64; +pub const _SC_PII_OSI_M: c_int = 65; +pub const _SC_T_IOV_MAX: c_int = 66; +pub const _SC_2_C_VERSION: c_int = 96; +pub const _SC_CHAR_BIT: c_int = 101; +pub const _SC_CHAR_MAX: c_int = 102; +pub const _SC_CHAR_MIN: c_int = 103; +pub const _SC_INT_MAX: c_int = 104; +pub const _SC_INT_MIN: c_int = 105; +pub const _SC_LONG_BIT: c_int = 106; +pub const _SC_WORD_BIT: c_int = 107; +pub const _SC_MB_LEN_MAX: c_int = 108; +pub const _SC_SSIZE_MAX: c_int = 110; +pub const _SC_SCHAR_MAX: c_int = 111; +pub const _SC_SCHAR_MIN: c_int = 112; +pub const _SC_SHRT_MAX: c_int = 113; +pub const _SC_SHRT_MIN: c_int = 114; +pub const _SC_UCHAR_MAX: c_int = 115; +pub const _SC_UINT_MAX: c_int = 116; +pub const _SC_ULONG_MAX: c_int = 117; +pub const _SC_USHRT_MAX: c_int = 118; +pub const _SC_NL_ARGMAX: c_int = 119; +pub const _SC_NL_LANGMAX: c_int = 120; +pub const _SC_NL_MSGMAX: c_int = 121; +pub const _SC_NL_NMAX: c_int = 122; +pub const _SC_NL_SETMAX: c_int = 123; +pub const _SC_NL_TEXTMAX: c_int = 124; +pub const _SC_BASE: c_int = 134; +pub const _SC_C_LANG_SUPPORT: c_int = 135; +pub const _SC_C_LANG_SUPPORT_R: c_int = 136; +pub const _SC_DEVICE_IO: c_int = 140; +pub const _SC_DEVICE_SPECIFIC: c_int = 141; +pub const _SC_DEVICE_SPECIFIC_R: c_int = 142; +pub const _SC_FD_MGMT: c_int = 143; +pub const _SC_FIFO: c_int = 144; +pub const _SC_PIPE: c_int = 145; +pub const _SC_FILE_ATTRIBUTES: c_int = 146; +pub const _SC_FILE_LOCKING: c_int = 147; +pub const _SC_FILE_SYSTEM: c_int = 148; +pub const _SC_MULTI_PROCESS: c_int = 150; +pub const _SC_SINGLE_PROCESS: c_int = 151; +pub const _SC_NETWORKING: c_int = 152; +pub const _SC_REGEX_VERSION: c_int = 156; +pub const _SC_SIGNALS: c_int = 158; +pub const _SC_SYSTEM_DATABASE: c_int = 162; +pub const _SC_SYSTEM_DATABASE_R: c_int = 163; +pub const _SC_USER_GROUPS: c_int = 166; +pub const _SC_USER_GROUPS_R: c_int = 167; +pub const _SC_LEVEL1_ICACHE_SIZE: c_int = 185; +pub const _SC_LEVEL1_ICACHE_ASSOC: c_int = 186; +pub const _SC_LEVEL1_ICACHE_LINESIZE: c_int = 187; +pub const _SC_LEVEL1_DCACHE_SIZE: c_int = 188; +pub const _SC_LEVEL1_DCACHE_ASSOC: c_int = 189; +pub const _SC_LEVEL1_DCACHE_LINESIZE: c_int = 190; +pub const _SC_LEVEL2_CACHE_SIZE: c_int = 191; +pub const _SC_LEVEL2_CACHE_ASSOC: c_int = 192; +pub const _SC_LEVEL2_CACHE_LINESIZE: c_int = 193; +pub const _SC_LEVEL3_CACHE_SIZE: c_int = 194; +pub const _SC_LEVEL3_CACHE_ASSOC: c_int = 195; +pub const _SC_LEVEL3_CACHE_LINESIZE: c_int = 196; +pub const _SC_LEVEL4_CACHE_SIZE: c_int = 197; +pub const _SC_LEVEL4_CACHE_ASSOC: c_int = 198; +pub const _SC_LEVEL4_CACHE_LINESIZE: c_int = 199; +pub const O_ACCMODE: c_int = 3; +pub const ST_RELATIME: c_ulong = 4096; +pub const NI_MAXHOST: crate::socklen_t = 1025; + +// Most `*_SUPER_MAGIC` constants are defined at the `linux_like` level; the +// following are only available on newer Linux versions than the versions +// currently used in CI in some configurations, so we define them here. +cfg_if! { + if #[cfg(not(target_arch = "s390x"))] { + pub const BINDERFS_SUPER_MAGIC: c_long = 0x6c6f6f70; + pub const XFS_SUPER_MAGIC: c_long = 0x58465342; + } else if #[cfg(target_arch = "s390x")] { + pub const BINDERFS_SUPER_MAGIC: c_uint = 0x6c6f6f70; + pub const XFS_SUPER_MAGIC: c_uint = 0x58465342; + } +} + +pub const CPU_SETSIZE: c_int = 0x400; + +pub const PTRACE_TRACEME: c_uint = 0; +pub const PTRACE_PEEKTEXT: c_uint = 1; +pub const PTRACE_PEEKDATA: c_uint = 2; +pub const PTRACE_PEEKUSER: c_uint = 3; +pub const PTRACE_POKETEXT: c_uint = 4; +pub const PTRACE_POKEDATA: c_uint = 5; +pub const PTRACE_POKEUSER: c_uint = 6; +pub const PTRACE_CONT: c_uint = 7; +pub const PTRACE_KILL: c_uint = 8; +pub const PTRACE_SINGLESTEP: c_uint = 9; +pub const PTRACE_ATTACH: c_uint = 16; +pub const PTRACE_SYSCALL: c_uint = 24; +pub const PTRACE_SETOPTIONS: c_uint = 0x4200; +pub const PTRACE_GETEVENTMSG: c_uint = 0x4201; +pub const PTRACE_GETSIGINFO: c_uint = 0x4202; +pub const PTRACE_SETSIGINFO: c_uint = 0x4203; +pub const PTRACE_GETREGSET: c_uint = 0x4204; +pub const PTRACE_SETREGSET: c_uint = 0x4205; +pub const PTRACE_SEIZE: c_uint = 0x4206; +pub const PTRACE_INTERRUPT: c_uint = 0x4207; +pub const PTRACE_LISTEN: c_uint = 0x4208; +pub const PTRACE_PEEKSIGINFO: c_uint = 0x4209; +pub const PTRACE_GETSIGMASK: c_uint = 0x420a; +pub const PTRACE_SETSIGMASK: c_uint = 0x420b; +pub const PTRACE_GET_SYSCALL_INFO: c_uint = 0x420e; +pub const PTRACE_SET_SYSCALL_INFO: c_uint = 0x4212; +pub const PTRACE_SYSCALL_INFO_NONE: crate::__u8 = 0; +pub const PTRACE_SYSCALL_INFO_ENTRY: crate::__u8 = 1; +pub const PTRACE_SYSCALL_INFO_EXIT: crate::__u8 = 2; +pub const PTRACE_SYSCALL_INFO_SECCOMP: crate::__u8 = 3; +pub const PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG: crate::__u8 = 0x4210; +pub const PTRACE_GET_SYSCALL_USER_DISPATCH_CONFIG: crate::__u8 = 0x4211; + +// linux/rtnetlink.h +pub const TCA_PAD: c_ushort = 9; +pub const TCA_DUMP_INVISIBLE: c_ushort = 10; +pub const TCA_CHAIN: c_ushort = 11; +pub const TCA_HW_OFFLOAD: c_ushort = 12; + +pub const RTM_DELNETCONF: u16 = 81; +pub const RTM_NEWSTATS: u16 = 92; +pub const RTM_GETSTATS: u16 = 94; +pub const RTM_NEWCACHEREPORT: u16 = 96; + +pub const RTM_F_LOOKUP_TABLE: c_uint = 0x1000; +pub const RTM_F_FIB_MATCH: c_uint = 0x2000; + +pub const RTA_VIA: c_ushort = 18; +pub const RTA_NEWDST: c_ushort = 19; +pub const RTA_PREF: c_ushort = 20; +pub const RTA_ENCAP_TYPE: c_ushort = 21; +pub const RTA_ENCAP: c_ushort = 22; +pub const RTA_EXPIRES: c_ushort = 23; +pub const RTA_PAD: c_ushort = 24; +pub const RTA_UID: c_ushort = 25; +pub const RTA_TTL_PROPAGATE: c_ushort = 26; + +// linux/neighbor.h +pub const NTF_EXT_LEARNED: u8 = 0x10; +pub const NTF_OFFLOADED: u8 = 0x20; + +pub const NDA_MASTER: c_ushort = 9; +pub const NDA_LINK_NETNSID: c_ushort = 10; +pub const NDA_SRC_VNI: c_ushort = 11; + +// linux/personality.h +pub const UNAME26: c_int = 0x0020000; +pub const FDPIC_FUNCPTRS: c_int = 0x0080000; + +pub const GENL_UNS_ADMIN_PERM: c_int = 0x10; + +pub const GENL_ID_VFS_DQUOT: c_int = crate::NLMSG_MIN_TYPE + 1; +pub const GENL_ID_PMCRAID: c_int = crate::NLMSG_MIN_TYPE + 2; + +pub const ELFOSABI_ARM_AEABI: u8 = 64; + +// linux/sched.h +pub const CLONE_NEWTIME: c_int = 0x80; +// DIFF(main): changed to `c_ulonglong` in e9abac9ac2 +pub const CLONE_CLEAR_SIGHAND: c_int = 0x100000000; +pub const CLONE_INTO_CGROUP: c_int = 0x200000000; + +pub const M_MXFAST: c_int = 1; +pub const M_NLBLKS: c_int = 2; +pub const M_GRAIN: c_int = 3; +pub const M_KEEP: c_int = 4; +pub const M_TRIM_THRESHOLD: c_int = -1; +pub const M_TOP_PAD: c_int = -2; +pub const M_MMAP_THRESHOLD: c_int = -3; +pub const M_MMAP_MAX: c_int = -4; +pub const M_CHECK_ACTION: c_int = -5; +pub const M_PERTURB: c_int = -6; +pub const M_ARENA_TEST: c_int = -7; +pub const M_ARENA_MAX: c_int = -8; + +pub const SOMAXCONN: c_int = 4096; + +// linux/mount.h +pub const MOVE_MOUNT_F_SYMLINKS: c_uint = 0x00000001; +pub const MOVE_MOUNT_F_AUTOMOUNTS: c_uint = 0x00000002; +pub const MOVE_MOUNT_F_EMPTY_PATH: c_uint = 0x00000004; +pub const MOVE_MOUNT_T_SYMLINKS: c_uint = 0x00000010; +pub const MOVE_MOUNT_T_AUTOMOUNTS: c_uint = 0x00000020; +pub const MOVE_MOUNT_T_EMPTY_PATH: c_uint = 0x00000040; +pub const MOVE_MOUNT_SET_GROUP: c_uint = 0x00000100; +pub const MOVE_MOUNT_BENEATH: c_uint = 0x00000200; + +// sys/timex.h +pub const ADJ_OFFSET: c_uint = 0x0001; +pub const ADJ_FREQUENCY: c_uint = 0x0002; +pub const ADJ_MAXERROR: c_uint = 0x0004; +pub const ADJ_ESTERROR: c_uint = 0x0008; +pub const ADJ_STATUS: c_uint = 0x0010; +pub const ADJ_TIMECONST: c_uint = 0x0020; +pub const ADJ_TAI: c_uint = 0x0080; +pub const ADJ_SETOFFSET: c_uint = 0x0100; +pub const ADJ_MICRO: c_uint = 0x1000; +pub const ADJ_NANO: c_uint = 0x2000; +pub const ADJ_TICK: c_uint = 0x4000; +pub const ADJ_OFFSET_SINGLESHOT: c_uint = 0x8001; +pub const ADJ_OFFSET_SS_READ: c_uint = 0xa001; +pub const MOD_OFFSET: c_uint = ADJ_OFFSET; +pub const MOD_FREQUENCY: c_uint = ADJ_FREQUENCY; +pub const MOD_MAXERROR: c_uint = ADJ_MAXERROR; +pub const MOD_ESTERROR: c_uint = ADJ_ESTERROR; +pub const MOD_STATUS: c_uint = ADJ_STATUS; +pub const MOD_TIMECONST: c_uint = ADJ_TIMECONST; +pub const MOD_CLKB: c_uint = ADJ_TICK; +pub const MOD_CLKA: c_uint = ADJ_OFFSET_SINGLESHOT; +pub const MOD_TAI: c_uint = ADJ_TAI; +pub const MOD_MICRO: c_uint = ADJ_MICRO; +pub const MOD_NANO: c_uint = ADJ_NANO; +pub const STA_PLL: c_int = 0x0001; +pub const STA_PPSFREQ: c_int = 0x0002; +pub const STA_PPSTIME: c_int = 0x0004; +pub const STA_FLL: c_int = 0x0008; +pub const STA_INS: c_int = 0x0010; +pub const STA_DEL: c_int = 0x0020; +pub const STA_UNSYNC: c_int = 0x0040; +pub const STA_FREQHOLD: c_int = 0x0080; +pub const STA_PPSSIGNAL: c_int = 0x0100; +pub const STA_PPSJITTER: c_int = 0x0200; +pub const STA_PPSWANDER: c_int = 0x0400; +pub const STA_PPSERROR: c_int = 0x0800; +pub const STA_CLOCKERR: c_int = 0x1000; +pub const STA_NANO: c_int = 0x2000; +pub const STA_MODE: c_int = 0x4000; +pub const STA_CLK: c_int = 0x8000; +pub const STA_RONLY: c_int = STA_PPSSIGNAL + | STA_PPSJITTER + | STA_PPSWANDER + | STA_PPSERROR + | STA_CLOCKERR + | STA_NANO + | STA_MODE + | STA_CLK; +pub const NTP_API: c_int = 4; +pub const TIME_OK: c_int = 0; +pub const TIME_INS: c_int = 1; +pub const TIME_DEL: c_int = 2; +pub const TIME_OOP: c_int = 3; +pub const TIME_WAIT: c_int = 4; +pub const TIME_ERROR: c_int = 5; +pub const TIME_BAD: c_int = TIME_ERROR; +pub const MAXTC: c_long = 6; + +// Portable GLOB_* flags are defined at the `linux_like` level. +// The following are GNU extensions. +pub const GLOB_PERIOD: c_int = 1 << 7; +pub const GLOB_ALTDIRFUNC: c_int = 1 << 9; +pub const GLOB_BRACE: c_int = 1 << 10; +pub const GLOB_NOMAGIC: c_int = 1 << 11; +pub const GLOB_TILDE: c_int = 1 << 12; +pub const GLOB_ONLYDIR: c_int = 1 << 13; +pub const GLOB_TILDE_CHECK: c_int = 1 << 14; + +pub const MADV_COLLAPSE: c_int = 25; + +cfg_if! { + if #[cfg(any( + target_arch = "arm", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "s390x", + target_arch = "riscv64", + target_arch = "riscv32" + ))] { + pub const PTHREAD_STACK_MIN: size_t = 16384; + } else if #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + pub const PTHREAD_STACK_MIN: size_t = 0x6000; + } else { + pub const PTHREAD_STACK_MIN: size_t = 131072; + } +} +pub const PTHREAD_MUTEX_ADAPTIVE_NP: c_int = 3; + +pub const REG_STARTEND: c_int = 4; + +pub const REG_EEND: c_int = 14; +pub const REG_ESIZE: c_int = 15; +pub const REG_ERPAREN: c_int = 16; + +extern "C" { + pub fn fgetspent_r( + fp: *mut crate::FILE, + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + pub fn sgetspent_r( + s: *const c_char, + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + pub fn getspent_r( + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + pub fn qsort_r( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); + #[cfg_attr(gnu_time_bits64, link_name = "__sendmmsg64")] + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + ) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__recvmmsg64")] + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *mut crate::timespec, + ) -> c_int; + + pub fn getrlimit64(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit64) -> c_int; + pub fn setrlimit64(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit64) + -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "getrlimit64")] + pub fn getrlimit(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "setrlimit64")] + pub fn setrlimit(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "prlimit64")] + pub fn prlimit( + pid: crate::pid_t, + resource: crate::__rlimit_resource_t, + new_limit: *const crate::rlimit, + old_limit: *mut crate::rlimit, + ) -> c_int; + pub fn prlimit64( + pid: crate::pid_t, + resource: crate::__rlimit_resource_t, + new_limit: *const crate::rlimit64, + old_limit: *mut crate::rlimit64, + ) -> c_int; + pub fn utmpname(file: *const c_char) -> c_int; + pub fn utmpxname(file: *const c_char) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + pub fn getpt() -> c_int; + pub fn mallopt(param: c_int, value: c_int) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__gettimeofday64")] + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + pub fn getauxval(type_: c_ulong) -> c_ulong; + + #[cfg_attr(gnu_time_bits64, link_name = "___adjtimex64")] + pub fn adjtimex(buf: *mut timex) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "___adjtimex64")] + pub fn ntp_adjtime(buf: *mut timex) -> c_int; + #[cfg_attr(not(gnu_time_bits64), link_name = "ntp_gettimex")] + #[cfg_attr(gnu_time_bits64, link_name = "__ntp_gettime64")] + pub fn ntp_gettime(buf: *mut ntptimeval) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__clock_adjtime64")] + pub fn clock_adjtime(clk_id: crate::clockid_t, buf: *mut crate::timex) -> c_int; + + pub fn fanotify_mark( + fd: c_int, + flags: c_uint, + mask: u64, + dirfd: c_int, + path: *const c_char, + ) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "preadv64v2")] + pub fn preadv2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, + ) -> ssize_t; + #[cfg_attr(gnu_file_offset_bits64, link_name = "pwritev64v2")] + pub fn pwritev2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, + ) -> ssize_t; + pub fn preadv64v2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, + flags: c_int, + ) -> ssize_t; + pub fn pwritev64v2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, + flags: c_int, + ) -> ssize_t; + pub fn renameat2( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_uint, + ) -> c_int; + + // Added in `glibc` 2.25 + pub fn explicit_bzero(s: *mut c_void, len: size_t); + // Added in `glibc` 2.29 + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + + pub fn ctermid(s: *mut c_char) -> *mut c_char; + pub fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int; + pub fn backtrace_symbols(buffer: *const *mut c_void, len: c_int) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(buffer: *const *mut c_void, len: c_int, fd: c_int); + #[cfg_attr(gnu_time_bits64, link_name = "__glob64_time64")] + pub fn glob64( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut glob64_t, + ) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__globfree64_time64")] + pub fn globfree64(pglob: *mut glob64_t); + pub fn ptrace(request: c_uint, ...) -> c_long; + pub fn pthread_attr_getaffinity_np( + attr: *const crate::pthread_attr_t, + cpusetsize: size_t, + cpuset: *mut crate::cpu_set_t, + ) -> c_int; + pub fn pthread_attr_setaffinity_np( + attr: *mut crate::pthread_attr_t, + cpusetsize: size_t, + cpuset: *const crate::cpu_set_t, + ) -> c_int; + pub fn getpriority(which: crate::__priority_which_t, who: crate::id_t) -> c_int; + pub fn setpriority(which: crate::__priority_which_t, who: crate::id_t, prio: c_int) -> c_int; + pub fn pthread_rwlockattr_getkind_np( + attr: *const crate::pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setkind_np( + attr: *mut crate::pthread_rwlockattr_t, + val: c_int, + ) -> c_int; + pub fn pthread_sigqueue(thread: crate::pthread_t, sig: c_int, value: crate::sigval) -> c_int; + pub fn pthread_tryjoin_np(thread: crate::pthread_t, retval: *mut *mut c_void) -> c_int; + #[cfg_attr( + all(target_pointer_width = "32", gnu_time_bits64), + link_name = "__pthread_timedjoin_np64" + )] + pub fn pthread_timedjoin_np( + thread: crate::pthread_t, + retval: *mut *mut c_void, + abstime: *const crate::timespec, + ) -> c_int; + pub fn mallinfo() -> crate::mallinfo; + pub fn mallinfo2() -> crate::mallinfo2; + pub fn malloc_stats(); + pub fn malloc_info(options: c_int, stream: *mut crate::FILE) -> c_int; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + pub fn getpwent_r( + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn fgetpwent_r( + stream: *mut crate::FILE, + pwd: *mut crate::passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::passwd, + ) -> c_int; + pub fn fgetgrent_r( + stream: *mut crate::FILE, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + + pub fn putpwent(p: *const crate::passwd, stream: *mut crate::FILE) -> c_int; + pub fn putgrent(grp: *const crate::group, stream: *mut crate::FILE) -> c_int; + + pub fn sethostid(hostid: c_long) -> c_int; + + pub fn memfd_create(name: *const c_char, flags: c_uint) -> c_int; + pub fn mlock2(addr: *const c_void, len: size_t, flags: c_uint) -> c_int; + + pub fn euidaccess(pathname: *const c_char, mode: c_int) -> c_int; + pub fn eaccess(pathname: *const c_char, mode: c_int) -> c_int; + + pub fn asctime_r(tm: *const crate::tm, buf: *mut c_char) -> *mut c_char; + #[cfg_attr(gnu_time_bits64, link_name = "__ctime64_r")] + pub fn ctime_r(timep: *const time_t, buf: *mut c_char) -> *mut c_char; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + /// POSIX version of `basename(3)`, defined in `libgen.h`. + #[link_name = "__xpg_basename"] + pub fn posix_basename(path: *mut c_char) -> *mut c_char; + /// GNU version of `basename(3)`, defined in `string.h`. + #[link_name = "basename"] + pub fn gnu_basename(path: *const c_char) -> *mut c_char; + pub fn dlmopen(lmid: Lmid_t, filename: *const c_char, flag: c_int) -> *mut c_void; + pub fn dlinfo(handle: *mut c_void, request: c_int, info: *mut c_void) -> c_int; + pub fn dladdr1( + addr: *const c_void, + info: *mut crate::Dl_info, + extra_info: *mut *mut c_void, + flags: c_int, + ) -> c_int; + pub fn dlvsym( + handle: *mut c_void, + symbol: *const c_char, + version: *const c_char, + ) -> *mut c_void; + pub fn malloc_trim(__pad: size_t) -> c_int; + pub fn gnu_get_libc_release() -> *const c_char; + pub fn gnu_get_libc_version() -> *const c_char; + + // posix/spawn.h + // Added in `glibc` 2.29 + pub fn posix_spawn_file_actions_addchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + // Added in `glibc` 2.29 + pub fn posix_spawn_file_actions_addfchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + // Added in `glibc` 2.34 + pub fn posix_spawn_file_actions_addclosefrom_np( + actions: *mut crate::posix_spawn_file_actions_t, + from: c_int, + ) -> c_int; + // Added in `glibc` 2.35 + pub fn posix_spawn_file_actions_addtcsetpgrp_np( + actions: *mut crate::posix_spawn_file_actions_t, + tcfd: c_int, + ) -> c_int; + + // mntent.h + pub fn getmntent_r( + stream: *mut crate::FILE, + mntbuf: *mut crate::mntent, + buf: *mut c_char, + buflen: c_int, + ) -> *mut crate::mntent; + + pub fn execveat( + dirfd: c_int, + pathname: *const c_char, + argv: *const *mut c_char, + envp: *const *mut c_char, + flags: c_int, + ) -> c_int; + + // Added in `glibc` 2.34 + pub fn close_range(first: c_uint, last: c_uint, flags: c_int) -> c_int; + + pub fn mq_notify(mqdes: crate::mqd_t, sevp: *const crate::sigevent) -> c_int; + + #[cfg_attr(gnu_time_bits64, link_name = "__epoll_pwait2_time64")] + pub fn epoll_pwait2( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: *const crate::timespec, + sigmask: *const crate::sigset_t, + ) -> c_int; + + pub fn mempcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + + pub fn tgkill(tgid: crate::pid_t, tid: crate::pid_t, sig: c_int) -> c_int; +} + +cfg_if! { + if #[cfg(any( + target_arch = "x86", + target_arch = "arm", + target_arch = "m68k", + target_arch = "csky", + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "riscv32" + ))] { + mod b32; + pub use self::b32::*; + } else if #[cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "riscv64", + target_arch = "loongarch64" + ))] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/mod.rs new file mode 100644 index 00000000000000..e58849b4e08f53 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/mod.rs @@ -0,0 +1,4436 @@ +//! Linux-specific definitions for linux-like values +use crate::prelude::*; +use crate::{ + sock_filter, + _IO, + _IOR, + _IOW, + _IOWR, +}; + +pub type dev_t = u64; +pub type socklen_t = u32; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type mqd_t = c_int; +pub type nfds_t = c_ulong; +pub type nl_item = c_int; +pub type idtype_t = c_uint; +pub type loff_t = c_longlong; +pub type pthread_key_t = c_uint; +pub type pthread_once_t = c_int; +pub type pthread_spinlock_t = c_int; +pub type __kernel_fsid_t = __c_anonymous__kernel_fsid_t; +pub type __kernel_clockid_t = c_int; + +pub type __u8 = c_uchar; +pub type __u16 = c_ushort; +pub type __s16 = c_short; +pub type __u32 = c_uint; +pub type __s32 = c_int; + +// linux/sctp.h +pub type sctp_assoc_t = __s32; + +pub type eventfd_t = u64; + +e! { + #[repr(u32)] + pub enum tpacket_versions { + TPACKET_V1, + TPACKET_V2, + TPACKET_V3, + } +} + +c_enum! { + pub enum pid_type { + pub PIDTYPE_PID, + pub PIDTYPE_TGID, + pub PIDTYPE_PGID, + pub PIDTYPE_SID, + pub PIDTYPE_MAX, + } +} + +s! { + pub struct dqblk { + pub dqb_bhardlimit: u64, + pub dqb_bsoftlimit: u64, + pub dqb_curspace: u64, + pub dqb_ihardlimit: u64, + pub dqb_isoftlimit: u64, + pub dqb_curinodes: u64, + pub dqb_btime: u64, + pub dqb_itime: u64, + pub dqb_valid: u32, + } + + pub struct signalfd_siginfo { + pub ssi_signo: u32, + pub ssi_errno: i32, + pub ssi_code: i32, + pub ssi_pid: u32, + pub ssi_uid: u32, + pub ssi_fd: i32, + pub ssi_tid: u32, + pub ssi_band: u32, + pub ssi_overrun: u32, + pub ssi_trapno: u32, + pub ssi_status: i32, + pub ssi_int: i32, + pub ssi_ptr: u64, + pub ssi_utime: u64, + pub ssi_stime: u64, + pub ssi_addr: u64, + pub ssi_addr_lsb: u16, + _pad2: Padding, + pub ssi_syscall: i32, + pub ssi_call_addr: u64, + pub ssi_arch: u32, + _pad: Padding<[u8; 28]>, + } + + pub struct fanout_args { + #[cfg(target_endian = "little")] + pub id: __u16, + pub type_flags: __u16, + #[cfg(target_endian = "big")] + pub id: __u16, + pub max_num_members: __u32, + } + + #[deprecated(since = "0.2.70", note = "sockaddr_ll type must be used instead")] + pub struct sockaddr_pkt { + pub spkt_family: c_ushort, + pub spkt_device: [c_uchar; 14], + pub spkt_protocol: c_ushort, + } + + pub struct tpacket_auxdata { + pub tp_status: __u32, + pub tp_len: __u32, + pub tp_snaplen: __u32, + pub tp_mac: __u16, + pub tp_net: __u16, + pub tp_vlan_tci: __u16, + pub tp_vlan_tpid: __u16, + } + + pub struct tpacket_hdr { + pub tp_status: c_ulong, + pub tp_len: c_uint, + pub tp_snaplen: c_uint, + pub tp_mac: c_ushort, + pub tp_net: c_ushort, + pub tp_sec: c_uint, + pub tp_usec: c_uint, + } + + pub struct tpacket_hdr_variant1 { + pub tp_rxhash: __u32, + pub tp_vlan_tci: __u32, + pub tp_vlan_tpid: __u16, + pub tp_padding: __u16, + } + + pub struct tpacket2_hdr { + pub tp_status: __u32, + pub tp_len: __u32, + pub tp_snaplen: __u32, + pub tp_mac: __u16, + pub tp_net: __u16, + pub tp_sec: __u32, + pub tp_nsec: __u32, + pub tp_vlan_tci: __u16, + pub tp_vlan_tpid: __u16, + pub tp_padding: [__u8; 4], + } + + pub struct tpacket_req { + pub tp_block_size: c_uint, + pub tp_block_nr: c_uint, + pub tp_frame_size: c_uint, + pub tp_frame_nr: c_uint, + } + + pub struct tpacket_req3 { + pub tp_block_size: c_uint, + pub tp_block_nr: c_uint, + pub tp_frame_size: c_uint, + pub tp_frame_nr: c_uint, + pub tp_retire_blk_tov: c_uint, + pub tp_sizeof_priv: c_uint, + pub tp_feature_req_word: c_uint, + } + + #[repr(align(8))] + pub struct tpacket_rollover_stats { + pub tp_all: crate::__u64, + pub tp_huge: crate::__u64, + pub tp_failed: crate::__u64, + } + + pub struct tpacket_stats { + pub tp_packets: c_uint, + pub tp_drops: c_uint, + } + + pub struct tpacket_stats_v3 { + pub tp_packets: c_uint, + pub tp_drops: c_uint, + pub tp_freeze_q_cnt: c_uint, + } + + pub struct tpacket3_hdr { + pub tp_next_offset: __u32, + pub tp_sec: __u32, + pub tp_nsec: __u32, + pub tp_snaplen: __u32, + pub tp_len: __u32, + pub tp_status: __u32, + pub tp_mac: __u16, + pub tp_net: __u16, + pub hv1: crate::tpacket_hdr_variant1, + pub tp_padding: [__u8; 8], + } + + pub struct tpacket_bd_ts { + pub ts_sec: c_uint, + pub ts_usec: c_uint, + } + + #[repr(align(8))] + pub struct tpacket_hdr_v1 { + pub block_status: __u32, + pub num_pkts: __u32, + pub offset_to_first_pkt: __u32, + pub blk_len: __u32, + pub seq_num: crate::__u64, + pub ts_first_pkt: crate::tpacket_bd_ts, + pub ts_last_pkt: crate::tpacket_bd_ts, + } + + // System V IPC + pub struct msginfo { + pub msgpool: c_int, + pub msgmap: c_int, + pub msgmax: c_int, + pub msgmnb: c_int, + pub msgmni: c_int, + pub msgssz: c_int, + pub msgtql: c_int, + pub msgseg: c_ushort, + } + + pub struct input_event { + // FIXME(1.0): Change to the commented variant, see https://github.com/rust-lang/libc/pull/4148#discussion_r1857511742 + #[cfg(any(target_pointer_width = "64", not(linux_time_bits64)))] + pub time: crate::timeval, + // #[cfg(any(target_pointer_width = "64", not(linux_time_bits64)))] + // pub input_event_sec: time_t, + // #[cfg(any(target_pointer_width = "64", not(linux_time_bits64)))] + // pub input_event_usec: suseconds_t, + // #[cfg(target_arch = "sparc64")] + // _pad1: c_int, + #[cfg(all(target_pointer_width = "32", linux_time_bits64))] + pub input_event_sec: c_ulong, + + #[cfg(all(target_pointer_width = "32", linux_time_bits64))] + pub input_event_usec: c_ulong, + + pub type_: __u16, + pub code: __u16, + pub value: __s32, + } + + pub struct input_id { + pub bustype: __u16, + pub vendor: __u16, + pub product: __u16, + pub version: __u16, + } + + pub struct input_absinfo { + pub value: __s32, + pub minimum: __s32, + pub maximum: __s32, + pub fuzz: __s32, + pub flat: __s32, + pub resolution: __s32, + } + + pub struct input_keymap_entry { + pub flags: __u8, + pub len: __u8, + pub index: __u16, + pub keycode: __u32, + pub scancode: [__u8; 32], + } + + pub struct input_mask { + pub type_: __u32, + pub codes_size: __u32, + pub codes_ptr: crate::__u64, + } + + pub struct ff_replay { + pub length: __u16, + pub delay: __u16, + } + + pub struct ff_trigger { + pub button: __u16, + pub interval: __u16, + } + + pub struct ff_envelope { + pub attack_length: __u16, + pub attack_level: __u16, + pub fade_length: __u16, + pub fade_level: __u16, + } + + pub struct ff_constant_effect { + pub level: __s16, + pub envelope: ff_envelope, + } + + pub struct ff_ramp_effect { + pub start_level: __s16, + pub end_level: __s16, + pub envelope: ff_envelope, + } + + pub struct ff_condition_effect { + pub right_saturation: __u16, + pub left_saturation: __u16, + + pub right_coeff: __s16, + pub left_coeff: __s16, + + pub deadband: __u16, + pub center: __s16, + } + + pub struct ff_periodic_effect { + pub waveform: __u16, + pub period: __u16, + pub magnitude: __s16, + pub offset: __s16, + pub phase: __u16, + + pub envelope: ff_envelope, + + pub custom_len: __u32, + pub custom_data: *mut __s16, + } + + pub struct ff_rumble_effect { + pub strong_magnitude: __u16, + pub weak_magnitude: __u16, + } + + pub struct ff_effect { + pub type_: __u16, + pub id: __s16, + pub direction: __u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + // FIXME(1.0): this is actually a union + #[cfg(target_pointer_width = "64")] + pub u: [u64; 4], + #[cfg(target_pointer_width = "32")] + pub u: [u32; 7], + } + + pub struct uinput_ff_upload { + pub request_id: __u32, + pub retval: __s32, + pub effect: ff_effect, + pub old: ff_effect, + } + + pub struct uinput_ff_erase { + pub request_id: __u32, + pub retval: __s32, + pub effect_id: __u32, + } + + pub struct uinput_abs_setup { + pub code: __u16, + pub absinfo: input_absinfo, + } + + pub struct __c_anonymous__kernel_fsid_t { + pub val: [c_int; 2], + } + + pub struct posix_spawn_file_actions_t { + __allocated: c_int, + __used: c_int, + __actions: *mut c_int, + __pad: Padding<[c_int; 16]>, + } + + pub struct posix_spawnattr_t { + __flags: c_short, + __pgrp: crate::pid_t, + __sd: crate::sigset_t, + __ss: crate::sigset_t, + #[cfg(any(target_env = "musl", target_env = "ohos"))] + __prio: c_int, + #[cfg(not(any(target_env = "musl", target_env = "ohos")))] + __sp: crate::sched_param, + __policy: c_int, + __pad: Padding<[c_int; 16]>, + } + + pub struct genlmsghdr { + pub cmd: u8, + pub version: u8, + pub reserved: u16, + } + + pub struct inotify_event { + pub wd: c_int, + pub mask: u32, + pub cookie: u32, + pub len: u32, + } + + pub struct fanotify_response { + pub fd: c_int, + pub response: __u32, + } + + pub struct fanotify_event_info_header { + pub info_type: __u8, + pub pad: __u8, + pub len: __u16, + } + + pub struct fanotify_event_info_fid { + pub hdr: fanotify_event_info_header, + pub fsid: __kernel_fsid_t, + pub handle: [c_uchar; 0], + } + + pub struct sockaddr_vm { + pub svm_family: crate::sa_family_t, + pub svm_reserved1: c_ushort, + pub svm_port: c_uint, + pub svm_cid: c_uint, + pub svm_zero: [u8; 4], + } + + pub struct sock_extended_err { + pub ee_errno: u32, + pub ee_origin: u8, + pub ee_type: u8, + pub ee_code: u8, + pub ee_pad: u8, + pub ee_info: u32, + pub ee_data: u32, + } + + // linux/seccomp.h + pub struct seccomp_data { + pub nr: c_int, + pub arch: __u32, + pub instruction_pointer: crate::__u64, + pub args: [crate::__u64; 6], + } + + pub struct seccomp_notif_sizes { + pub seccomp_notif: __u16, + pub seccomp_notif_resp: __u16, + pub seccomp_data: __u16, + } + + pub struct seccomp_notif { + pub id: crate::__u64, + pub pid: __u32, + pub flags: __u32, + pub data: seccomp_data, + } + + pub struct seccomp_notif_resp { + pub id: crate::__u64, + pub val: crate::__s64, + pub error: __s32, + pub flags: __u32, + } + + pub struct seccomp_notif_addfd { + pub id: crate::__u64, + pub flags: __u32, + pub srcfd: __u32, + pub newfd: __u32, + pub newfd_flags: __u32, + } + + pub struct in6_ifreq { + pub ifr6_addr: crate::in6_addr, + pub ifr6_prefixlen: u32, + pub ifr6_ifindex: c_int, + } + + // linux/openat2.h + #[non_exhaustive] + pub struct open_how { + pub flags: crate::__u64, + pub mode: crate::__u64, + pub resolve: crate::__u64, + } + + // linux/ptp_clock.h + pub struct ptp_clock_time { + pub sec: crate::__s64, + pub nsec: __u32, + pub reserved: __u32, + } + + pub struct ptp_extts_request { + pub index: c_uint, + pub flags: c_uint, + pub rsv: [c_uint; 2], + } + + pub struct ptp_sys_offset_extended { + pub n_samples: c_uint, + pub clockid: __kernel_clockid_t, + pub rsv: [c_uint; 2], + pub ts: [[ptp_clock_time; 3]; PTP_MAX_SAMPLES as usize], + } + + pub struct ptp_sys_offset_precise { + pub device: ptp_clock_time, + pub sys_realtime: ptp_clock_time, + pub sys_monoraw: ptp_clock_time, + pub rsv: [c_uint; 4], + } + + pub struct ptp_extts_event { + pub t: ptp_clock_time, + index: c_uint, + flags: c_uint, + rsv: [c_uint; 2], + } + + // linux/sctp.h + + pub struct sctp_initmsg { + pub sinit_num_ostreams: __u16, + pub sinit_max_instreams: __u16, + pub sinit_max_attempts: __u16, + pub sinit_max_init_timeo: __u16, + } + + pub struct sctp_sndrcvinfo { + pub sinfo_stream: __u16, + pub sinfo_ssn: __u16, + pub sinfo_flags: __u16, + pub sinfo_ppid: __u32, + pub sinfo_context: __u32, + pub sinfo_timetolive: __u32, + pub sinfo_tsn: __u32, + pub sinfo_cumtsn: __u32, + pub sinfo_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_sndinfo { + pub snd_sid: __u16, + pub snd_flags: __u16, + pub snd_ppid: __u32, + pub snd_context: __u32, + pub snd_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_rcvinfo { + pub rcv_sid: __u16, + pub rcv_ssn: __u16, + pub rcv_flags: __u16, + pub rcv_ppid: __u32, + pub rcv_tsn: __u32, + pub rcv_cumtsn: __u32, + pub rcv_context: __u32, + pub rcv_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_nxtinfo { + pub nxt_sid: __u16, + pub nxt_flags: __u16, + pub nxt_ppid: __u32, + pub nxt_length: __u32, + pub nxt_assoc_id: crate::sctp_assoc_t, + } + + pub struct sctp_prinfo { + pub pr_policy: __u16, + pub pr_value: __u32, + } + + pub struct sctp_authinfo { + pub auth_keynumber: __u16, + } + + // linux/tls.h + + pub struct tls_crypto_info { + pub version: __u16, + pub cipher_type: __u16, + } + + pub struct tls12_crypto_info_aes_gcm_128 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_AES_GCM_128_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_AES_GCM_128_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_AES_GCM_128_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_aes_gcm_256 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_AES_GCM_256_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_AES_GCM_256_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_AES_GCM_256_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_aes_ccm_128 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_AES_CCM_128_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_AES_CCM_128_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_AES_CCM_128_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_chacha20_poly1305 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_sm4_gcm { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_SM4_GCM_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_SM4_GCM_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_SM4_GCM_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_sm4_ccm { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_SM4_CCM_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_SM4_CCM_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_SM4_CCM_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_aria_gcm_128 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_ARIA_GCM_128_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_ARIA_GCM_128_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_ARIA_GCM_128_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_ARIA_GCM_128_REC_SEQ_SIZE], + } + + pub struct tls12_crypto_info_aria_gcm_256 { + pub info: tls_crypto_info, + pub iv: [c_uchar; TLS_CIPHER_ARIA_GCM_256_IV_SIZE], + pub key: [c_uchar; TLS_CIPHER_ARIA_GCM_256_KEY_SIZE], + pub salt: [c_uchar; TLS_CIPHER_ARIA_GCM_256_SALT_SIZE], + pub rec_seq: [c_uchar; TLS_CIPHER_ARIA_GCM_256_REC_SEQ_SIZE], + } + + // linux/wireless.h + + pub struct iw_param { + pub value: __s32, + pub fixed: __u8, + pub disabled: __u8, + pub flags: __u16, + } + + pub struct iw_point { + pub pointer: *mut c_void, + pub length: __u16, + pub flags: __u16, + } + + pub struct iw_freq { + pub m: __s32, + pub e: __s16, + pub i: __u8, + pub flags: __u8, + } + + pub struct iw_quality { + pub qual: __u8, + pub level: __u8, + pub noise: __u8, + pub updated: __u8, + } + + pub struct iw_discarded { + pub nwid: __u32, + pub code: __u32, + pub fragment: __u32, + pub retries: __u32, + pubmisc: __u32, + } + + pub struct iw_missed { + pub beacon: __u32, + } + + pub struct iw_scan_req { + pub scan_type: __u8, + pub essid_len: __u8, + pub num_channels: __u8, + pub flags: __u8, + pub bssid: crate::sockaddr, + pub essid: [__u8; IW_ESSID_MAX_SIZE], + pub min_channel_time: __u32, + pub max_channel_time: __u32, + pub channel_list: [iw_freq; IW_MAX_FREQUENCIES], + } + + pub struct iw_encode_ext { + pub ext_flags: __u32, + pub tx_seq: [__u8; IW_ENCODE_SEQ_MAX_SIZE], + pub rx_seq: [__u8; IW_ENCODE_SEQ_MAX_SIZE], + pub addr: crate::sockaddr, + pub alg: __u16, + pub key_len: __u16, + pub key: [__u8; 0], + } + + pub struct iw_pmksa { + pub cmd: __u32, + pub bssid: crate::sockaddr, + pub pmkid: [__u8; IW_PMKID_LEN], + } + + pub struct iw_pmkid_cand { + pub flags: __u32, + pub index: __u32, + pub bssid: crate::sockaddr, + } + + pub struct iw_statistics { + pub status: __u16, + pub qual: iw_quality, + pub discard: iw_discarded, + pub miss: iw_missed, + } + + pub struct iw_range { + pub throughput: __u32, + pub min_nwid: __u32, + pub max_nwid: __u32, + pub old_num_channels: __u16, + pub old_num_frequency: __u8, + pub scan_capa: __u8, + pub event_capa: [__u32; 6], + pub sensitivity: __s32, + pub max_qual: iw_quality, + pub avg_qual: iw_quality, + pub num_bitrates: __u8, + pub bitrate: [__s32; IW_MAX_BITRATES], + pub min_rts: __s32, + pub max_rts: __s32, + pub min_frag: __s32, + pub max_frag: __s32, + pub min_pmp: __s32, + pub max_pmp: __s32, + pub min_pmt: __s32, + pub max_pmt: __s32, + pub pmp_flags: __u16, + pub pmt_flags: __u16, + pub pm_capa: __u16, + pub encoding_size: [__u16; IW_MAX_ENCODING_SIZES], + pub num_encoding_sizes: __u8, + pub max_encoding_tokens: __u8, + pub encoding_login_index: __u8, + pub txpower_capa: __u16, + pub num_txpower: __u8, + pub txpower: [__s32; IW_MAX_TXPOWER], + pub we_version_compiled: __u8, + pub we_version_source: __u8, + pub retry_capa: __u16, + pub retry_flags: __u16, + pub r_time_flags: __u16, + pub min_retry: __s32, + pub max_retry: __s32, + pub min_r_time: __s32, + pub max_r_time: __s32, + pub num_channels: __u16, + pub num_frequency: __u8, + pub freq: [iw_freq; IW_MAX_FREQUENCIES], + pub enc_capa: __u32, + } + + pub struct iw_priv_args { + pub cmd: __u32, + pub set_args: __u16, + pub get_args: __u16, + pub name: [c_char; crate::IFNAMSIZ], + } + + // #include + + pub struct epoll_params { + pub busy_poll_usecs: u32, + pub busy_poll_budget: u16, + pub prefer_busy_poll: u8, + pub __pad: u8, // Must be zero + } + + #[cfg_attr( + any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "aarch64", + target_arch = "riscv64", + target_arch = "riscv32", + target_arch = "loongarch64" + ), + repr(align(4)) + )] + #[cfg_attr( + not(any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "aarch64", + target_arch = "riscv64", + target_arch = "riscv32", + target_arch = "loongarch64" + )), + repr(align(8)) + )] + pub struct pthread_mutexattr_t { + #[doc(hidden)] + size: [u8; crate::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[cfg_attr( + any( + target_env = "musl", + target_env = "ohos", + target_env = "uclibc", + target_pointer_width = "32" + ), + repr(align(4)) + )] + #[cfg_attr( + all( + not(target_env = "musl"), + not(target_env = "ohos"), + not(target_env = "uclibc"), + target_pointer_width = "64" + ), + repr(align(8)) + )] + pub struct pthread_rwlockattr_t { + #[doc(hidden)] + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + #[doc(hidden)] + size: [u8; crate::__SIZEOF_PTHREAD_CONDATTR_T], + } + + #[repr(align(4))] + pub struct pthread_barrierattr_t { + #[doc(hidden)] + size: [u8; crate::__SIZEOF_PTHREAD_BARRIERATTR_T], + } + + #[cfg(not(any(target_env = "musl", target_env = "ohos")))] + #[repr(align(8))] + pub struct fanotify_event_metadata { + pub event_len: __u32, + pub vers: __u8, + pub reserved: __u8, + pub metadata_len: __u16, + pub mask: __u64, + pub fd: c_int, + pub pid: c_int, + } + + // linux/ptp_clock.h + + pub struct ptp_sys_offset { + pub n_samples: c_uint, + pub rsv: [c_uint; 3], + // FIXME(garando): replace length with `2 * PTP_MAX_SAMPLES + 1` when supported + pub ts: [ptp_clock_time; 51], + } + + pub struct ptp_pin_desc { + pub name: [c_char; 64], + pub index: c_uint, + pub func: c_uint, + pub chan: c_uint, + pub rsv: [c_uint; 5], + } + + pub struct ptp_clock_caps { + pub max_adj: c_int, + pub n_alarm: c_int, + pub n_ext_ts: c_int, + pub n_per_out: c_int, + pub pps: c_int, + pub n_pins: c_int, + pub cross_timestamping: c_int, + pub adjust_phase: c_int, + pub max_phase_adj: c_int, + pub rsv: [c_int; 11], + } + + // linux/if_xdp.h + + pub struct sockaddr_xdp { + pub sxdp_family: crate::__u16, + pub sxdp_flags: crate::__u16, + pub sxdp_ifindex: crate::__u32, + pub sxdp_queue_id: crate::__u32, + pub sxdp_shared_umem_fd: crate::__u32, + } + + pub struct xdp_ring_offset { + pub producer: crate::__u64, + pub consumer: crate::__u64, + pub desc: crate::__u64, + pub flags: crate::__u64, + } + + pub struct xdp_mmap_offsets { + pub rx: xdp_ring_offset, + pub tx: xdp_ring_offset, + pub fr: xdp_ring_offset, + pub cr: xdp_ring_offset, + } + + pub struct xdp_ring_offset_v1 { + pub producer: crate::__u64, + pub consumer: crate::__u64, + pub desc: crate::__u64, + } + + pub struct xdp_mmap_offsets_v1 { + pub rx: xdp_ring_offset_v1, + pub tx: xdp_ring_offset_v1, + pub fr: xdp_ring_offset_v1, + pub cr: xdp_ring_offset_v1, + } + + pub struct xdp_umem_reg { + pub addr: crate::__u64, + pub len: crate::__u64, + pub chunk_size: crate::__u32, + pub headroom: crate::__u32, + pub flags: crate::__u32, + pub tx_metadata_len: crate::__u32, + } + + pub struct xdp_umem_reg_v1 { + pub addr: crate::__u64, + pub len: crate::__u64, + pub chunk_size: crate::__u32, + pub headroom: crate::__u32, + } + + pub struct xdp_statistics { + pub rx_dropped: crate::__u64, + pub rx_invalid_descs: crate::__u64, + pub tx_invalid_descs: crate::__u64, + pub rx_ring_full: crate::__u64, + pub rx_fill_ring_empty_descs: crate::__u64, + pub tx_ring_empty_descs: crate::__u64, + } + + pub struct xdp_statistics_v1 { + pub rx_dropped: crate::__u64, + pub rx_invalid_descs: crate::__u64, + pub tx_invalid_descs: crate::__u64, + } + + pub struct xdp_options { + pub flags: crate::__u32, + } + + pub struct xdp_desc { + pub addr: crate::__u64, + pub len: crate::__u32, + pub options: crate::__u32, + } + + pub struct xsk_tx_metadata_completion { + pub tx_timestamp: crate::__u64, + } + + pub struct xsk_tx_metadata_request { + pub csum_start: __u16, + pub csum_offset: __u16, + } + + // linux/mount.h + + pub struct mount_attr { + pub attr_set: crate::__u64, + pub attr_clr: crate::__u64, + pub propagation: crate::__u64, + pub userns_fd: crate::__u64, + } + + // linux/nsfs.h + pub struct mnt_ns_info { + pub size: crate::__u32, + pub nr_mounts: crate::__u32, + pub mnt_ns_id: crate::__u64, + } + + // linux/pidfd.h + + // linux/uio.h + + pub struct dmabuf_cmsg { + pub frag_offset: crate::__u64, + pub frag_size: crate::__u32, + pub frag_token: crate::__u32, + pub dmabuf_id: crate::__u32, + pub flags: crate::__u32, + } + + pub struct dmabuf_token { + pub token_start: crate::__u32, + pub token_count: crate::__u32, + } + + pub struct sockaddr_alg { + pub salg_family: crate::sa_family_t, + pub salg_type: [c_uchar; 14], + pub salg_feat: u32, + pub salg_mask: u32, + pub salg_name: [c_uchar; 64], + } + + #[cfg_attr( + all( + any(target_env = "musl", target_env = "ohos"), + target_pointer_width = "32" + ), + repr(align(4)) + )] + #[cfg_attr( + all( + any(target_env = "musl", target_env = "ohos"), + target_pointer_width = "64" + ), + repr(align(8)) + )] + #[cfg_attr( + all( + not(any(target_env = "musl", target_env = "ohos")), + target_arch = "x86" + ), + repr(align(4)) + )] + #[cfg_attr( + all( + not(any(target_env = "musl", target_env = "ohos")), + not(target_arch = "x86") + ), + repr(align(8)) + )] + pub struct pthread_cond_t { + #[doc(hidden)] + size: [u8; crate::__SIZEOF_PTHREAD_COND_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "csky", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86", + ) + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "csky", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86", + )) + ), + repr(align(8)) + )] + pub struct pthread_mutex_t { + #[doc(hidden)] + size: [c_char; crate::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "csky", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86" + ) + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86" + )) + ), + repr(align(8)) + )] + pub struct pthread_rwlock_t { + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "csky", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86" + ) + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "m68k", + target_arch = "csky", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "x86_64", + target_arch = "x86" + )) + ), + repr(align(8)) + )] + pub struct pthread_barrier_t { + size: [u8; crate::__SIZEOF_PTHREAD_BARRIER_T], + } + + pub struct uinput_setup { + pub id: input_id, + pub name: [c_char; UINPUT_MAX_NAME_SIZE], + pub ff_effects_max: __u32, + } + + pub struct uinput_user_dev { + pub name: [c_char; UINPUT_MAX_NAME_SIZE], + pub id: input_id, + pub ff_effects_max: __u32, + pub absmax: [__s32; ABS_CNT], + pub absmin: [__s32; ABS_CNT], + pub absfuzz: [__s32; ABS_CNT], + pub absflat: [__s32; ABS_CNT], + } + + // x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 + pub struct mq_attr { + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_flags: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_maxmsg: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_msgsize: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_curmsgs: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pad: Padding<[i64; 4]>, + + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_flags: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_maxmsg: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_msgsize: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_curmsgs: c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pad: Padding<[c_long; 4]>, + } + + pub struct hwtstamp_config { + pub flags: c_int, + pub tx_type: c_int, + pub rx_filter: c_int, + } + + pub struct sched_attr { + pub size: __u32, + pub sched_policy: __u32, + pub sched_flags: crate::__u64, + pub sched_nice: __s32, + pub sched_priority: __u32, + pub sched_runtime: crate::__u64, + pub sched_deadline: crate::__u64, + pub sched_period: crate::__u64, + } + + // linux/fcntl.h + + pub struct file_handle { + pub handle_bytes: c_uint, + pub handle_type: c_int, + pub f_handle: [c_uchar; 0], + } + + // include/uapi/linux/rtnetlink.h + pub struct ifinfomsg { + pub ifi_family: c_uchar, + __ifi_pad: Padding, + pub ifi_type: c_ushort, + pub ifi_index: c_int, + pub ifi_flags: c_uint, + pub ifi_change: c_uint, + } +} + +cfg_if! { + if #[cfg(not(target_arch = "sparc64"))] { + s! { + pub struct iw_thrspy { + pub addr: crate::sockaddr, + pub qual: iw_quality, + pub low: iw_quality, + pub high: iw_quality, + } + + pub struct iw_mlme { + pub cmd: __u16, + pub reason_code: __u16, + pub addr: crate::sockaddr, + } + + pub struct iw_michaelmicfailure { + pub flags: __u32, + pub src_addr: crate::sockaddr, + pub tsc: [__u8; IW_ENCODE_SEQ_MAX_SIZE], + } + } + } +} + +s_no_extra_traits! { + /// WARNING: The `PartialEq`, `Eq` and `Hash` implementations of this + /// type are unsound and will be removed in the future. + #[deprecated( + note = "this struct has unsafe trait implementations that will be \ + removed in the future", + since = "0.2.80" + )] + pub struct af_alg_iv { + pub ivlen: u32, + pub iv: [c_uchar; 0], + } + + pub union tpacket_req_u { + pub req: crate::tpacket_req, + pub req3: crate::tpacket_req3, + } + + pub union tpacket_bd_header_u { + pub bh1: crate::tpacket_hdr_v1, + } + + pub struct tpacket_block_desc { + pub version: __u32, + pub offset_to_priv: __u32, + pub hdr: crate::tpacket_bd_header_u, + } + + // linux/net_tstamp.h + pub struct sock_txtime { + pub clockid: crate::clockid_t, + pub flags: __u32, + } + + // linux/wireless.h + pub union iwreq_data { + pub name: [c_char; crate::IFNAMSIZ], + pub essid: iw_point, + pub nwid: iw_param, + pub freq: iw_freq, + pub sens: iw_param, + pub bitrate: iw_param, + pub txpower: iw_param, + pub rts: iw_param, + pub frag: iw_param, + pub mode: __u32, + pub retry: iw_param, + pub encoding: iw_point, + pub power: iw_param, + pub qual: iw_quality, + pub ap_addr: crate::sockaddr, + pub addr: crate::sockaddr, + pub param: iw_param, + pub data: iw_point, + } + + pub struct iw_event { + pub len: __u16, + pub cmd: __u16, + pub u: iwreq_data, + } + + pub union __c_anonymous_iwreq { + pub ifrn_name: [c_char; crate::IFNAMSIZ], + } + + pub struct iwreq { + pub ifr_ifrn: __c_anonymous_iwreq, + pub u: iwreq_data, + } + + // linux/ptp_clock.h + pub union __c_anonymous_ptp_perout_request_1 { + pub start: ptp_clock_time, + pub phase: ptp_clock_time, + } + + pub union __c_anonymous_ptp_perout_request_2 { + pub on: ptp_clock_time, + pub rsv: [c_uint; 4], + } + + pub struct ptp_perout_request { + pub anonymous_1: __c_anonymous_ptp_perout_request_1, + pub period: ptp_clock_time, + pub index: c_uint, + pub flags: c_uint, + pub anonymous_2: __c_anonymous_ptp_perout_request_2, + } + + // linux/if_xdp.h + pub struct xsk_tx_metadata { + pub flags: crate::__u64, + pub xsk_tx_metadata_union: __c_anonymous_xsk_tx_metadata_union, + } + + pub union __c_anonymous_xsk_tx_metadata_union { + pub request: xsk_tx_metadata_request, + pub completion: xsk_tx_metadata_completion, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + #[allow(deprecated)] + impl af_alg_iv { + fn as_slice(&self) -> &[u8] { + unsafe { ::core::slice::from_raw_parts(self.iv.as_ptr(), self.ivlen as usize) } + } + } + + #[allow(deprecated)] + impl PartialEq for af_alg_iv { + fn eq(&self, other: &af_alg_iv) -> bool { + *self.as_slice() == *other.as_slice() + } + } + + #[allow(deprecated)] + impl Eq for af_alg_iv {} + + #[allow(deprecated)] + impl hash::Hash for af_alg_iv { + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } + } + } +} + +pub const POSIX_SPAWN_USEVFORK: c_int = 64; +pub const POSIX_SPAWN_SETSID: c_int = 128; + +pub const F_SEAL_FUTURE_WRITE: c_int = 0x0010; +pub const F_SEAL_EXEC: c_int = 0x0020; + +pub const IFF_LOWER_UP: c_int = 0x10000; +pub const IFF_DORMANT: c_int = 0x20000; +pub const IFF_ECHO: c_int = 0x40000; + +// linux/fcntl.h +pub const AT_EXECVE_CHECK: c_int = 0x10000; + +pub const MAX_HANDLE_SZ: c_int = 128; +pub const AT_HANDLE_FID: c_int = 0x200; +pub const AT_HANDLE_MNT_ID_UNIQUE: c_int = 0x001; +pub const AT_HANDLE_CONNECTABLE: c_int = 0x002; + +// linux/if_addr.h +pub const IFA_UNSPEC: c_ushort = 0; +pub const IFA_ADDRESS: c_ushort = 1; +pub const IFA_LOCAL: c_ushort = 2; +pub const IFA_LABEL: c_ushort = 3; +pub const IFA_BROADCAST: c_ushort = 4; +pub const IFA_ANYCAST: c_ushort = 5; +pub const IFA_CACHEINFO: c_ushort = 6; +pub const IFA_MULTICAST: c_ushort = 7; +pub const IFA_FLAGS: c_ushort = 8; + +pub const IFA_F_SECONDARY: u32 = 0x01; +pub const IFA_F_TEMPORARY: u32 = 0x01; +pub const IFA_F_NODAD: u32 = 0x02; +pub const IFA_F_OPTIMISTIC: u32 = 0x04; +pub const IFA_F_DADFAILED: u32 = 0x08; +pub const IFA_F_HOMEADDRESS: u32 = 0x10; +pub const IFA_F_DEPRECATED: u32 = 0x20; +pub const IFA_F_TENTATIVE: u32 = 0x40; +pub const IFA_F_PERMANENT: u32 = 0x80; +pub const IFA_F_MANAGETEMPADDR: u32 = 0x100; +pub const IFA_F_NOPREFIXROUTE: u32 = 0x200; +pub const IFA_F_MCAUTOJOIN: u32 = 0x400; +pub const IFA_F_STABLE_PRIVACY: u32 = 0x800; + +// linux/fs.h + +// Flags for preadv2/pwritev2 +pub const RWF_HIPRI: c_int = 0x00000001; +pub const RWF_DSYNC: c_int = 0x00000002; +pub const RWF_SYNC: c_int = 0x00000004; +pub const RWF_NOWAIT: c_int = 0x00000008; +pub const RWF_APPEND: c_int = 0x00000010; +pub const RWF_NOAPPEND: c_int = 0x00000020; +pub const RWF_ATOMIC: c_int = 0x00000040; +pub const RWF_DONTCACHE: c_int = 0x00000080; + +// linux/if_link.h +pub const IFLA_UNSPEC: c_ushort = 0; +pub const IFLA_ADDRESS: c_ushort = 1; +pub const IFLA_BROADCAST: c_ushort = 2; +pub const IFLA_IFNAME: c_ushort = 3; +pub const IFLA_MTU: c_ushort = 4; +pub const IFLA_LINK: c_ushort = 5; +pub const IFLA_QDISC: c_ushort = 6; +pub const IFLA_STATS: c_ushort = 7; +pub const IFLA_COST: c_ushort = 8; +pub const IFLA_PRIORITY: c_ushort = 9; +pub const IFLA_MASTER: c_ushort = 10; +pub const IFLA_WIRELESS: c_ushort = 11; +pub const IFLA_PROTINFO: c_ushort = 12; +pub const IFLA_TXQLEN: c_ushort = 13; +pub const IFLA_MAP: c_ushort = 14; +pub const IFLA_WEIGHT: c_ushort = 15; +pub const IFLA_OPERSTATE: c_ushort = 16; +pub const IFLA_LINKMODE: c_ushort = 17; +pub const IFLA_LINKINFO: c_ushort = 18; +pub const IFLA_NET_NS_PID: c_ushort = 19; +pub const IFLA_IFALIAS: c_ushort = 20; +pub const IFLA_NUM_VF: c_ushort = 21; +pub const IFLA_VFINFO_LIST: c_ushort = 22; +pub const IFLA_STATS64: c_ushort = 23; +pub const IFLA_VF_PORTS: c_ushort = 24; +pub const IFLA_PORT_SELF: c_ushort = 25; +pub const IFLA_AF_SPEC: c_ushort = 26; +pub const IFLA_GROUP: c_ushort = 27; +pub const IFLA_NET_NS_FD: c_ushort = 28; +pub const IFLA_EXT_MASK: c_ushort = 29; +pub const IFLA_PROMISCUITY: c_ushort = 30; +pub const IFLA_NUM_TX_QUEUES: c_ushort = 31; +pub const IFLA_NUM_RX_QUEUES: c_ushort = 32; +pub const IFLA_CARRIER: c_ushort = 33; +pub const IFLA_PHYS_PORT_ID: c_ushort = 34; +pub const IFLA_CARRIER_CHANGES: c_ushort = 35; +pub const IFLA_PHYS_SWITCH_ID: c_ushort = 36; +pub const IFLA_LINK_NETNSID: c_ushort = 37; +pub const IFLA_PHYS_PORT_NAME: c_ushort = 38; +pub const IFLA_PROTO_DOWN: c_ushort = 39; +pub const IFLA_GSO_MAX_SEGS: c_ushort = 40; +pub const IFLA_GSO_MAX_SIZE: c_ushort = 41; +pub const IFLA_PAD: c_ushort = 42; +pub const IFLA_XDP: c_ushort = 43; +pub const IFLA_EVENT: c_ushort = 44; +pub const IFLA_NEW_NETNSID: c_ushort = 45; +pub const IFLA_IF_NETNSID: c_ushort = 46; +pub const IFLA_TARGET_NETNSID: c_ushort = IFLA_IF_NETNSID; +pub const IFLA_CARRIER_UP_COUNT: c_ushort = 47; +pub const IFLA_CARRIER_DOWN_COUNT: c_ushort = 48; +pub const IFLA_NEW_IFINDEX: c_ushort = 49; +pub const IFLA_MIN_MTU: c_ushort = 50; +pub const IFLA_MAX_MTU: c_ushort = 51; +pub const IFLA_PROP_LIST: c_ushort = 52; +pub const IFLA_ALT_IFNAME: c_ushort = 53; +pub const IFLA_PERM_ADDRESS: c_ushort = 54; +pub const IFLA_PROTO_DOWN_REASON: c_ushort = 55; +pub const IFLA_PARENT_DEV_NAME: c_ushort = 56; +pub const IFLA_PARENT_DEV_BUS_NAME: c_ushort = 57; +pub const IFLA_GRO_MAX_SIZE: c_ushort = 58; +pub const IFLA_TSO_MAX_SIZE: c_ushort = 59; +pub const IFLA_TSO_MAX_SEGS: c_ushort = 60; +pub const IFLA_ALLMULTI: c_ushort = 61; + +pub const IFLA_INFO_UNSPEC: c_ushort = 0; +pub const IFLA_INFO_KIND: c_ushort = 1; +pub const IFLA_INFO_DATA: c_ushort = 2; +pub const IFLA_INFO_XSTATS: c_ushort = 3; +pub const IFLA_INFO_SLAVE_KIND: c_ushort = 4; +pub const IFLA_INFO_SLAVE_DATA: c_ushort = 5; + +// Since Linux 3.1 +pub const SEEK_DATA: c_int = 3; +pub const SEEK_HOLE: c_int = 4; + +// linux/mempolicy.h +pub const MPOL_DEFAULT: c_int = 0; +pub const MPOL_PREFERRED: c_int = 1; +pub const MPOL_BIND: c_int = 2; +pub const MPOL_INTERLEAVE: c_int = 3; +pub const MPOL_LOCAL: c_int = 4; +pub const MPOL_F_NUMA_BALANCING: c_int = 1 << 13; +pub const MPOL_F_RELATIVE_NODES: c_int = 1 << 14; +pub const MPOL_F_STATIC_NODES: c_int = 1 << 15; + +pub const PTHREAD_MUTEX_INITIALIZER: crate::pthread_mutex_t = crate::pthread_mutex_t { + size: [0; crate::__SIZEOF_PTHREAD_MUTEX_T], +}; +pub const PTHREAD_COND_INITIALIZER: crate::pthread_cond_t = crate::pthread_cond_t { + size: [0; crate::__SIZEOF_PTHREAD_COND_T], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: crate::pthread_rwlock_t = crate::pthread_rwlock_t { + size: [0; crate::__SIZEOF_PTHREAD_RWLOCK_T], +}; + +pub const RENAME_NOREPLACE: c_uint = 1; +pub const RENAME_EXCHANGE: c_uint = 2; +pub const RENAME_WHITEOUT: c_uint = 4; + +pub const MSG_STAT: c_int = 11 | (crate::IPC_STAT & 0x100); +pub const MSG_INFO: c_int = 12; +pub const MSG_NOTIFICATION: c_int = 0x8000; + +pub const MSG_NOERROR: c_int = 0o10000; +pub const MSG_EXCEPT: c_int = 0o20000; +pub const MSG_ZEROCOPY: c_int = 0x4000000; + +pub const SEM_UNDO: c_int = 0x1000; + +pub const GETPID: c_int = 11; +pub const GETVAL: c_int = 12; +pub const GETALL: c_int = 13; +pub const GETNCNT: c_int = 14; +pub const GETZCNT: c_int = 15; +pub const SETVAL: c_int = 16; +pub const SETALL: c_int = 17; +pub const SEM_STAT: c_int = 18 | (crate::IPC_STAT & 0x100); +pub const SEM_INFO: c_int = 19; +pub const SEM_STAT_ANY: c_int = 20 | (crate::IPC_STAT & 0x100); + +pub const QFMT_VFS_OLD: c_int = 1; +pub const QFMT_VFS_V0: c_int = 2; +pub const QFMT_VFS_V1: c_int = 4; + +pub const EFD_SEMAPHORE: c_int = 0x1; + +pub const RB_AUTOBOOT: c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: c_int = 0x4321fedcu32 as i32; +pub const RB_SW_SUSPEND: c_int = 0xd000fce2u32 as i32; +pub const RB_KEXEC: c_int = 0x45584543u32 as i32; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: c_uint = 4; + +pub const MREMAP_MAYMOVE: c_int = 1; +pub const MREMAP_FIXED: c_int = 2; +pub const MREMAP_DONTUNMAP: c_int = 4; + +// linux/nsfs.h +const NSIO: c_uint = 0xb7; + +pub const NS_GET_USERNS: Ioctl = _IO(NSIO, 0x1); +pub const NS_GET_PARENT: Ioctl = _IO(NSIO, 0x2); +pub const NS_GET_NSTYPE: Ioctl = _IO(NSIO, 0x3); +pub const NS_GET_OWNER_UID: Ioctl = _IO(NSIO, 0x4); + +pub const NS_GET_MNTNS_ID: Ioctl = _IOR::<__u64>(NSIO, 0x5); + +pub const NS_GET_PID_FROM_PIDNS: Ioctl = _IOR::(NSIO, 0x6); +pub const NS_GET_TGID_FROM_PIDNS: Ioctl = _IOR::(NSIO, 0x7); +pub const NS_GET_PID_IN_PIDNS: Ioctl = _IOR::(NSIO, 0x8); +pub const NS_GET_TGID_IN_PIDNS: Ioctl = _IOR::(NSIO, 0x9); + +pub const MNT_NS_INFO_SIZE_VER0: Ioctl = 16; + +pub const NS_MNT_GET_INFO: Ioctl = _IOR::(NSIO, 10); +pub const NS_MNT_GET_NEXT: Ioctl = _IOR::(NSIO, 11); +pub const NS_MNT_GET_PREV: Ioctl = _IOR::(NSIO, 12); + +pub const PR_SET_MDWE: c_int = 65; +pub const PR_GET_MDWE: c_int = 66; +pub const PR_MDWE_REFUSE_EXEC_GAIN: c_uint = 1 << 0; +pub const PR_MDWE_NO_INHERIT: c_uint = 1 << 1; +pub const PR_SET_MEMORY_MERGE: c_int = 67; +pub const PR_GET_MEMORY_MERGE: c_int = 68; + +pub const GRND_NONBLOCK: c_uint = 0x0001; +pub const GRND_RANDOM: c_uint = 0x0002; +pub const GRND_INSECURE: c_uint = 0x0004; + +// +pub const SECCOMP_MODE_DISABLED: c_uint = 0; +pub const SECCOMP_MODE_STRICT: c_uint = 1; +pub const SECCOMP_MODE_FILTER: c_uint = 2; + +pub const SECCOMP_SET_MODE_STRICT: c_uint = 0; +pub const SECCOMP_SET_MODE_FILTER: c_uint = 1; +pub const SECCOMP_GET_ACTION_AVAIL: c_uint = 2; +pub const SECCOMP_GET_NOTIF_SIZES: c_uint = 3; + +pub const SECCOMP_FILTER_FLAG_TSYNC: c_ulong = 1 << 0; +pub const SECCOMP_FILTER_FLAG_LOG: c_ulong = 1 << 1; +pub const SECCOMP_FILTER_FLAG_SPEC_ALLOW: c_ulong = 1 << 2; +pub const SECCOMP_FILTER_FLAG_NEW_LISTENER: c_ulong = 1 << 3; +pub const SECCOMP_FILTER_FLAG_TSYNC_ESRCH: c_ulong = 1 << 4; +pub const SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV: c_ulong = 1 << 5; + +pub const SECCOMP_RET_KILL_PROCESS: c_uint = 0x80000000; +pub const SECCOMP_RET_KILL_THREAD: c_uint = 0x00000000; +pub const SECCOMP_RET_KILL: c_uint = SECCOMP_RET_KILL_THREAD; +pub const SECCOMP_RET_TRAP: c_uint = 0x00030000; +pub const SECCOMP_RET_ERRNO: c_uint = 0x00050000; +pub const SECCOMP_RET_USER_NOTIF: c_uint = 0x7fc00000; +pub const SECCOMP_RET_TRACE: c_uint = 0x7ff00000; +pub const SECCOMP_RET_LOG: c_uint = 0x7ffc0000; +pub const SECCOMP_RET_ALLOW: c_uint = 0x7fff0000; + +pub const SECCOMP_RET_ACTION_FULL: c_uint = 0xffff0000; +pub const SECCOMP_RET_ACTION: c_uint = 0x7fff0000; +pub const SECCOMP_RET_DATA: c_uint = 0x0000ffff; + +pub const SECCOMP_USER_NOTIF_FLAG_CONTINUE: c_ulong = 1; + +pub const SECCOMP_ADDFD_FLAG_SETFD: c_ulong = 1; +pub const SECCOMP_ADDFD_FLAG_SEND: c_ulong = 2; + +pub const TFD_CLOEXEC: c_int = O_CLOEXEC; +pub const TFD_NONBLOCK: c_int = O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: c_int = 1; +pub const TFD_TIMER_CANCEL_ON_SET: c_int = 2; + +pub const FALLOC_FL_KEEP_SIZE: c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: c_int = 0x02; +pub const FALLOC_FL_COLLAPSE_RANGE: c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: c_int = 0x40; + +#[deprecated( + since = "0.2.55", + note = "ENOATTR is not available on Linux; use ENODATA instead" +)] +pub const ENOATTR: c_int = crate::ENODATA; + +pub const SO_ORIGINAL_DST: c_int = 80; + +pub const IP_RECVFRAGSIZE: c_int = 25; + +pub const IPV6_FLOWINFO: c_int = 11; +pub const IPV6_FLOWLABEL_MGR: c_int = 32; +pub const IPV6_FLOWINFO_SEND: c_int = 33; +pub const IPV6_RECVFRAGSIZE: c_int = 77; +pub const IPV6_FREEBIND: c_int = 78; +pub const IPV6_FLOWINFO_FLOWLABEL: c_int = 0x000fffff; +pub const IPV6_FLOWINFO_PRIORITY: c_int = 0x0ff00000; + +// SO_MEMINFO offsets +pub const SK_MEMINFO_RMEM_ALLOC: c_int = 0; +pub const SK_MEMINFO_RCVBUF: c_int = 1; +pub const SK_MEMINFO_WMEM_ALLOC: c_int = 2; +pub const SK_MEMINFO_SNDBUF: c_int = 3; +pub const SK_MEMINFO_FWD_ALLOC: c_int = 4; +pub const SK_MEMINFO_WMEM_QUEUED: c_int = 5; +pub const SK_MEMINFO_OPTMEM: c_int = 6; +pub const SK_MEMINFO_BACKLOG: c_int = 7; +pub const SK_MEMINFO_DROPS: c_int = 8; + +// linux/close_range.h +pub const CLOSE_RANGE_UNSHARE: c_uint = 1 << 1; +pub const CLOSE_RANGE_CLOEXEC: c_uint = 1 << 2; + +// linux/filter.h +pub const SKF_AD_OFF: c_int = -0x1000; +pub const SKF_AD_PROTOCOL: c_int = 0; +pub const SKF_AD_PKTTYPE: c_int = 4; +pub const SKF_AD_IFINDEX: c_int = 8; +pub const SKF_AD_NLATTR: c_int = 12; +pub const SKF_AD_NLATTR_NEST: c_int = 16; +pub const SKF_AD_MARK: c_int = 20; +pub const SKF_AD_QUEUE: c_int = 24; +pub const SKF_AD_HATYPE: c_int = 28; +pub const SKF_AD_RXHASH: c_int = 32; +pub const SKF_AD_CPU: c_int = 36; +pub const SKF_AD_ALU_XOR_X: c_int = 40; +pub const SKF_AD_VLAN_TAG: c_int = 44; +pub const SKF_AD_VLAN_TAG_PRESENT: c_int = 48; +pub const SKF_AD_PAY_OFFSET: c_int = 52; +pub const SKF_AD_RANDOM: c_int = 56; +pub const SKF_AD_VLAN_TPID: c_int = 60; +pub const SKF_AD_MAX: c_int = 64; +pub const SKF_NET_OFF: c_int = -0x100000; +pub const SKF_LL_OFF: c_int = -0x200000; +pub const BPF_NET_OFF: c_int = SKF_NET_OFF; +pub const BPF_LL_OFF: c_int = SKF_LL_OFF; +pub const BPF_MEMWORDS: c_int = 16; +pub const BPF_MAXINSNS: c_int = 4096; + +// linux/bpf_common.h +pub const BPF_LD: __u32 = 0x00; +pub const BPF_LDX: __u32 = 0x01; +pub const BPF_ST: __u32 = 0x02; +pub const BPF_STX: __u32 = 0x03; +pub const BPF_ALU: __u32 = 0x04; +pub const BPF_JMP: __u32 = 0x05; +pub const BPF_RET: __u32 = 0x06; +pub const BPF_MISC: __u32 = 0x07; +pub const BPF_W: __u32 = 0x00; +pub const BPF_H: __u32 = 0x08; +pub const BPF_B: __u32 = 0x10; +pub const BPF_IMM: __u32 = 0x00; +pub const BPF_ABS: __u32 = 0x20; +pub const BPF_IND: __u32 = 0x40; +pub const BPF_MEM: __u32 = 0x60; +pub const BPF_LEN: __u32 = 0x80; +pub const BPF_MSH: __u32 = 0xa0; +pub const BPF_ADD: __u32 = 0x00; +pub const BPF_SUB: __u32 = 0x10; +pub const BPF_MUL: __u32 = 0x20; +pub const BPF_DIV: __u32 = 0x30; +pub const BPF_OR: __u32 = 0x40; +pub const BPF_AND: __u32 = 0x50; +pub const BPF_LSH: __u32 = 0x60; +pub const BPF_RSH: __u32 = 0x70; +pub const BPF_NEG: __u32 = 0x80; +pub const BPF_MOD: __u32 = 0x90; +pub const BPF_XOR: __u32 = 0xa0; +pub const BPF_JA: __u32 = 0x00; +pub const BPF_JEQ: __u32 = 0x10; +pub const BPF_JGT: __u32 = 0x20; +pub const BPF_JGE: __u32 = 0x30; +pub const BPF_JSET: __u32 = 0x40; +pub const BPF_K: __u32 = 0x00; +pub const BPF_X: __u32 = 0x08; + +// linux/filter.h + +pub const BPF_A: __u32 = 0x10; +pub const BPF_TAX: __u32 = 0x00; +pub const BPF_TXA: __u32 = 0x80; + +// linux/openat2.h +pub const RESOLVE_NO_XDEV: crate::__u64 = 0x01; +pub const RESOLVE_NO_MAGICLINKS: crate::__u64 = 0x02; +pub const RESOLVE_NO_SYMLINKS: crate::__u64 = 0x04; +pub const RESOLVE_BENEATH: crate::__u64 = 0x08; +pub const RESOLVE_IN_ROOT: crate::__u64 = 0x10; +pub const RESOLVE_CACHED: crate::__u64 = 0x20; + +// linux/if_ether.h +pub const ETH_ALEN: c_int = 6; +pub const ETH_HLEN: c_int = 14; +pub const ETH_ZLEN: c_int = 60; +pub const ETH_DATA_LEN: c_int = 1500; +pub const ETH_FRAME_LEN: c_int = 1514; +pub const ETH_FCS_LEN: c_int = 4; + +// These are the defined Ethernet Protocol ID's. +pub const ETH_P_LOOP: c_int = 0x0060; +pub const ETH_P_PUP: c_int = 0x0200; +pub const ETH_P_PUPAT: c_int = 0x0201; +pub const ETH_P_IP: c_int = 0x0800; +pub const ETH_P_X25: c_int = 0x0805; +pub const ETH_P_ARP: c_int = 0x0806; +pub const ETH_P_BPQ: c_int = 0x08FF; +pub const ETH_P_IEEEPUP: c_int = 0x0a00; +pub const ETH_P_IEEEPUPAT: c_int = 0x0a01; +pub const ETH_P_BATMAN: c_int = 0x4305; +pub const ETH_P_DEC: c_int = 0x6000; +pub const ETH_P_DNA_DL: c_int = 0x6001; +pub const ETH_P_DNA_RC: c_int = 0x6002; +pub const ETH_P_DNA_RT: c_int = 0x6003; +pub const ETH_P_LAT: c_int = 0x6004; +pub const ETH_P_DIAG: c_int = 0x6005; +pub const ETH_P_CUST: c_int = 0x6006; +pub const ETH_P_SCA: c_int = 0x6007; +pub const ETH_P_TEB: c_int = 0x6558; +pub const ETH_P_RARP: c_int = 0x8035; +pub const ETH_P_ATALK: c_int = 0x809B; +pub const ETH_P_AARP: c_int = 0x80F3; +pub const ETH_P_8021Q: c_int = 0x8100; +pub const ETH_P_IPX: c_int = 0x8137; +pub const ETH_P_IPV6: c_int = 0x86DD; +pub const ETH_P_PAUSE: c_int = 0x8808; +pub const ETH_P_SLOW: c_int = 0x8809; +pub const ETH_P_WCCP: c_int = 0x883E; +pub const ETH_P_MPLS_UC: c_int = 0x8847; +pub const ETH_P_MPLS_MC: c_int = 0x8848; +pub const ETH_P_ATMMPOA: c_int = 0x884c; +pub const ETH_P_PPP_DISC: c_int = 0x8863; +pub const ETH_P_PPP_SES: c_int = 0x8864; +pub const ETH_P_LINK_CTL: c_int = 0x886c; +pub const ETH_P_ATMFATE: c_int = 0x8884; +pub const ETH_P_PAE: c_int = 0x888E; +pub const ETH_P_AOE: c_int = 0x88A2; +pub const ETH_P_8021AD: c_int = 0x88A8; +pub const ETH_P_802_EX1: c_int = 0x88B5; +pub const ETH_P_TIPC: c_int = 0x88CA; +pub const ETH_P_MACSEC: c_int = 0x88E5; +pub const ETH_P_8021AH: c_int = 0x88E7; +pub const ETH_P_MVRP: c_int = 0x88F5; +pub const ETH_P_1588: c_int = 0x88F7; +pub const ETH_P_PRP: c_int = 0x88FB; +pub const ETH_P_FCOE: c_int = 0x8906; +pub const ETH_P_TDLS: c_int = 0x890D; +pub const ETH_P_FIP: c_int = 0x8914; +pub const ETH_P_80221: c_int = 0x8917; +pub const ETH_P_LOOPBACK: c_int = 0x9000; +pub const ETH_P_QINQ1: c_int = 0x9100; +pub const ETH_P_QINQ2: c_int = 0x9200; +pub const ETH_P_QINQ3: c_int = 0x9300; +pub const ETH_P_EDSA: c_int = 0xDADA; +pub const ETH_P_AF_IUCV: c_int = 0xFBFB; + +pub const ETH_P_802_3_MIN: c_int = 0x0600; + +// Non DIX types. Won't clash for 1500 types. +pub const ETH_P_802_3: c_int = 0x0001; +pub const ETH_P_AX25: c_int = 0x0002; +pub const ETH_P_ALL: c_int = 0x0003; +pub const ETH_P_802_2: c_int = 0x0004; +pub const ETH_P_SNAP: c_int = 0x0005; +pub const ETH_P_DDCMP: c_int = 0x0006; +pub const ETH_P_WAN_PPP: c_int = 0x0007; +pub const ETH_P_PPP_MP: c_int = 0x0008; +pub const ETH_P_LOCALTALK: c_int = 0x0009; +pub const ETH_P_CANFD: c_int = 0x000D; +pub const ETH_P_PPPTALK: c_int = 0x0010; +pub const ETH_P_TR_802_2: c_int = 0x0011; +pub const ETH_P_MOBITEX: c_int = 0x0015; +pub const ETH_P_CONTROL: c_int = 0x0016; +pub const ETH_P_IRDA: c_int = 0x0017; +pub const ETH_P_ECONET: c_int = 0x0018; +pub const ETH_P_HDLC: c_int = 0x0019; +pub const ETH_P_ARCNET: c_int = 0x001A; +pub const ETH_P_DSA: c_int = 0x001B; +pub const ETH_P_TRAILER: c_int = 0x001C; +pub const ETH_P_PHONET: c_int = 0x00F5; +pub const ETH_P_IEEE802154: c_int = 0x00F6; +pub const ETH_P_CAIF: c_int = 0x00F7; + +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x02; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x04; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x08; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x10; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x20; + +// linux/netfilter/nfnetlink.h +pub const NFNLGRP_NONE: c_int = 0; +pub const NFNLGRP_CONNTRACK_NEW: c_int = 1; +pub const NFNLGRP_CONNTRACK_UPDATE: c_int = 2; +pub const NFNLGRP_CONNTRACK_DESTROY: c_int = 3; +pub const NFNLGRP_CONNTRACK_EXP_NEW: c_int = 4; +pub const NFNLGRP_CONNTRACK_EXP_UPDATE: c_int = 5; +pub const NFNLGRP_CONNTRACK_EXP_DESTROY: c_int = 6; +pub const NFNLGRP_NFTABLES: c_int = 7; +pub const NFNLGRP_ACCT_QUOTA: c_int = 8; +pub const NFNLGRP_NFTRACE: c_int = 9; + +pub const NFNETLINK_V0: c_int = 0; + +pub const NFNL_SUBSYS_NONE: c_int = 0; +pub const NFNL_SUBSYS_CTNETLINK: c_int = 1; +pub const NFNL_SUBSYS_CTNETLINK_EXP: c_int = 2; +pub const NFNL_SUBSYS_QUEUE: c_int = 3; +pub const NFNL_SUBSYS_ULOG: c_int = 4; +pub const NFNL_SUBSYS_OSF: c_int = 5; +pub const NFNL_SUBSYS_IPSET: c_int = 6; +pub const NFNL_SUBSYS_ACCT: c_int = 7; +pub const NFNL_SUBSYS_CTNETLINK_TIMEOUT: c_int = 8; +pub const NFNL_SUBSYS_CTHELPER: c_int = 9; +pub const NFNL_SUBSYS_NFTABLES: c_int = 10; +pub const NFNL_SUBSYS_NFT_COMPAT: c_int = 11; +pub const NFNL_SUBSYS_HOOK: c_int = 12; +pub const NFNL_SUBSYS_COUNT: c_int = 13; + +pub const NFNL_MSG_BATCH_BEGIN: c_int = crate::NLMSG_MIN_TYPE; +pub const NFNL_MSG_BATCH_END: c_int = crate::NLMSG_MIN_TYPE + 1; + +pub const NFNL_BATCH_UNSPEC: c_int = 0; +pub const NFNL_BATCH_GENID: c_int = 1; + +// linux/netfilter/nfnetlink_log.h +pub const NFULNL_MSG_PACKET: c_int = 0; +pub const NFULNL_MSG_CONFIG: c_int = 1; + +pub const NFULA_VLAN_UNSPEC: c_int = 0; +pub const NFULA_VLAN_PROTO: c_int = 1; +pub const NFULA_VLAN_TCI: c_int = 2; + +pub const NFULA_UNSPEC: c_int = 0; +pub const NFULA_PACKET_HDR: c_int = 1; +pub const NFULA_MARK: c_int = 2; +pub const NFULA_TIMESTAMP: c_int = 3; +pub const NFULA_IFINDEX_INDEV: c_int = 4; +pub const NFULA_IFINDEX_OUTDEV: c_int = 5; +pub const NFULA_IFINDEX_PHYSINDEV: c_int = 6; +pub const NFULA_IFINDEX_PHYSOUTDEV: c_int = 7; +pub const NFULA_HWADDR: c_int = 8; +pub const NFULA_PAYLOAD: c_int = 9; +pub const NFULA_PREFIX: c_int = 10; +pub const NFULA_UID: c_int = 11; +pub const NFULA_SEQ: c_int = 12; +pub const NFULA_SEQ_GLOBAL: c_int = 13; +pub const NFULA_GID: c_int = 14; +pub const NFULA_HWTYPE: c_int = 15; +pub const NFULA_HWHEADER: c_int = 16; +pub const NFULA_HWLEN: c_int = 17; +pub const NFULA_CT: c_int = 18; +pub const NFULA_CT_INFO: c_int = 19; +pub const NFULA_VLAN: c_int = 20; +pub const NFULA_L2HDR: c_int = 21; + +pub const NFULNL_CFG_CMD_NONE: c_int = 0; +pub const NFULNL_CFG_CMD_BIND: c_int = 1; +pub const NFULNL_CFG_CMD_UNBIND: c_int = 2; +pub const NFULNL_CFG_CMD_PF_BIND: c_int = 3; +pub const NFULNL_CFG_CMD_PF_UNBIND: c_int = 4; + +pub const NFULA_CFG_UNSPEC: c_int = 0; +pub const NFULA_CFG_CMD: c_int = 1; +pub const NFULA_CFG_MODE: c_int = 2; +pub const NFULA_CFG_NLBUFSIZ: c_int = 3; +pub const NFULA_CFG_TIMEOUT: c_int = 4; +pub const NFULA_CFG_QTHRESH: c_int = 5; +pub const NFULA_CFG_FLAGS: c_int = 6; + +pub const NFULNL_COPY_NONE: c_int = 0x00; +pub const NFULNL_COPY_META: c_int = 0x01; +pub const NFULNL_COPY_PACKET: c_int = 0x02; + +pub const NFULNL_CFG_F_SEQ: c_int = 0x0001; +pub const NFULNL_CFG_F_SEQ_GLOBAL: c_int = 0x0002; +pub const NFULNL_CFG_F_CONNTRACK: c_int = 0x0004; + +// linux/netfilter/nfnetlink_queue.h +pub const NFQNL_MSG_PACKET: c_int = 0; +pub const NFQNL_MSG_VERDICT: c_int = 1; +pub const NFQNL_MSG_CONFIG: c_int = 2; +pub const NFQNL_MSG_VERDICT_BATCH: c_int = 3; + +pub const NFQA_UNSPEC: c_int = 0; +pub const NFQA_PACKET_HDR: c_int = 1; +pub const NFQA_VERDICT_HDR: c_int = 2; +pub const NFQA_MARK: c_int = 3; +pub const NFQA_TIMESTAMP: c_int = 4; +pub const NFQA_IFINDEX_INDEV: c_int = 5; +pub const NFQA_IFINDEX_OUTDEV: c_int = 6; +pub const NFQA_IFINDEX_PHYSINDEV: c_int = 7; +pub const NFQA_IFINDEX_PHYSOUTDEV: c_int = 8; +pub const NFQA_HWADDR: c_int = 9; +pub const NFQA_PAYLOAD: c_int = 10; +pub const NFQA_CT: c_int = 11; +pub const NFQA_CT_INFO: c_int = 12; +pub const NFQA_CAP_LEN: c_int = 13; +pub const NFQA_SKB_INFO: c_int = 14; +pub const NFQA_EXP: c_int = 15; +pub const NFQA_UID: c_int = 16; +pub const NFQA_GID: c_int = 17; +pub const NFQA_SECCTX: c_int = 18; +pub const NFQA_VLAN: c_int = 19; +pub const NFQA_L2HDR: c_int = 20; +pub const NFQA_PRIORITY: c_int = 21; + +pub const NFQA_VLAN_UNSPEC: c_int = 0; +pub const NFQA_VLAN_PROTO: c_int = 1; +pub const NFQA_VLAN_TCI: c_int = 2; + +pub const NFQNL_CFG_CMD_NONE: c_int = 0; +pub const NFQNL_CFG_CMD_BIND: c_int = 1; +pub const NFQNL_CFG_CMD_UNBIND: c_int = 2; +pub const NFQNL_CFG_CMD_PF_BIND: c_int = 3; +pub const NFQNL_CFG_CMD_PF_UNBIND: c_int = 4; + +pub const NFQNL_COPY_NONE: c_int = 0; +pub const NFQNL_COPY_META: c_int = 1; +pub const NFQNL_COPY_PACKET: c_int = 2; + +pub const NFQA_CFG_UNSPEC: c_int = 0; +pub const NFQA_CFG_CMD: c_int = 1; +pub const NFQA_CFG_PARAMS: c_int = 2; +pub const NFQA_CFG_QUEUE_MAXLEN: c_int = 3; +pub const NFQA_CFG_MASK: c_int = 4; +pub const NFQA_CFG_FLAGS: c_int = 5; + +pub const NFQA_CFG_F_FAIL_OPEN: c_int = 0x0001; +pub const NFQA_CFG_F_CONNTRACK: c_int = 0x0002; +pub const NFQA_CFG_F_GSO: c_int = 0x0004; +pub const NFQA_CFG_F_UID_GID: c_int = 0x0008; +pub const NFQA_CFG_F_SECCTX: c_int = 0x0010; +pub const NFQA_CFG_F_MAX: c_int = 0x0020; + +pub const NFQA_SKB_CSUMNOTREADY: c_int = 0x0001; +pub const NFQA_SKB_GSO: c_int = 0x0002; +pub const NFQA_SKB_CSUM_NOTVERIFIED: c_int = 0x0004; + +// linux/genetlink.h + +pub const GENL_NAMSIZ: c_int = 16; + +pub const GENL_MIN_ID: c_int = crate::NLMSG_MIN_TYPE; +pub const GENL_MAX_ID: c_int = 1023; + +pub const GENL_ADMIN_PERM: c_int = 0x01; +pub const GENL_CMD_CAP_DO: c_int = 0x02; +pub const GENL_CMD_CAP_DUMP: c_int = 0x04; +pub const GENL_CMD_CAP_HASPOL: c_int = 0x08; + +pub const GENL_ID_CTRL: c_int = crate::NLMSG_MIN_TYPE; + +pub const CTRL_CMD_UNSPEC: c_int = 0; +pub const CTRL_CMD_NEWFAMILY: c_int = 1; +pub const CTRL_CMD_DELFAMILY: c_int = 2; +pub const CTRL_CMD_GETFAMILY: c_int = 3; +pub const CTRL_CMD_NEWOPS: c_int = 4; +pub const CTRL_CMD_DELOPS: c_int = 5; +pub const CTRL_CMD_GETOPS: c_int = 6; +pub const CTRL_CMD_NEWMCAST_GRP: c_int = 7; +pub const CTRL_CMD_DELMCAST_GRP: c_int = 8; +pub const CTRL_CMD_GETMCAST_GRP: c_int = 9; + +pub const CTRL_ATTR_UNSPEC: c_int = 0; +pub const CTRL_ATTR_FAMILY_ID: c_int = 1; +pub const CTRL_ATTR_FAMILY_NAME: c_int = 2; +pub const CTRL_ATTR_VERSION: c_int = 3; +pub const CTRL_ATTR_HDRSIZE: c_int = 4; +pub const CTRL_ATTR_MAXATTR: c_int = 5; +pub const CTRL_ATTR_OPS: c_int = 6; +pub const CTRL_ATTR_MCAST_GROUPS: c_int = 7; + +pub const CTRL_ATTR_OP_UNSPEC: c_int = 0; +pub const CTRL_ATTR_OP_ID: c_int = 1; +pub const CTRL_ATTR_OP_FLAGS: c_int = 2; + +pub const CTRL_ATTR_MCAST_GRP_UNSPEC: c_int = 0; +pub const CTRL_ATTR_MCAST_GRP_NAME: c_int = 1; +pub const CTRL_ATTR_MCAST_GRP_ID: c_int = 2; + +pub const PACKET_FANOUT: c_int = 18; +pub const PACKET_TX_HAS_OFF: c_int = 19; +pub const PACKET_QDISC_BYPASS: c_int = 20; +pub const PACKET_ROLLOVER_STATS: c_int = 21; +pub const PACKET_FANOUT_DATA: c_int = 22; +pub const PACKET_IGNORE_OUTGOING: c_int = 23; +pub const PACKET_VNET_HDR_SZ: c_int = 24; + +pub const PACKET_FANOUT_HASH: c_uint = 0; +pub const PACKET_FANOUT_LB: c_uint = 1; +pub const PACKET_FANOUT_CPU: c_uint = 2; +pub const PACKET_FANOUT_ROLLOVER: c_uint = 3; +pub const PACKET_FANOUT_RND: c_uint = 4; +pub const PACKET_FANOUT_QM: c_uint = 5; +pub const PACKET_FANOUT_CBPF: c_uint = 6; +pub const PACKET_FANOUT_EBPF: c_uint = 7; +pub const PACKET_FANOUT_FLAG_ROLLOVER: c_uint = 0x1000; +pub const PACKET_FANOUT_FLAG_UNIQUEID: c_uint = 0x2000; +pub const PACKET_FANOUT_FLAG_IGNORE_OUTGOING: c_uint = 0x4000; +pub const PACKET_FANOUT_FLAG_DEFRAG: c_uint = 0x8000; + +pub const TP_STATUS_KERNEL: __u32 = 0; +pub const TP_STATUS_USER: __u32 = 1 << 0; +pub const TP_STATUS_COPY: __u32 = 1 << 1; +pub const TP_STATUS_LOSING: __u32 = 1 << 2; +pub const TP_STATUS_CSUMNOTREADY: __u32 = 1 << 3; +pub const TP_STATUS_VLAN_VALID: __u32 = 1 << 4; +pub const TP_STATUS_BLK_TMO: __u32 = 1 << 5; +pub const TP_STATUS_VLAN_TPID_VALID: __u32 = 1 << 6; +pub const TP_STATUS_CSUM_VALID: __u32 = 1 << 7; + +pub const TP_STATUS_AVAILABLE: __u32 = 0; +pub const TP_STATUS_SEND_REQUEST: __u32 = 1 << 0; +pub const TP_STATUS_SENDING: __u32 = 1 << 1; +pub const TP_STATUS_WRONG_FORMAT: __u32 = 1 << 2; + +pub const TP_STATUS_TS_SOFTWARE: __u32 = 1 << 29; +pub const TP_STATUS_TS_SYS_HARDWARE: __u32 = 1 << 30; +pub const TP_STATUS_TS_RAW_HARDWARE: __u32 = 1 << 31; + +pub const TP_FT_REQ_FILL_RXHASH: __u32 = 1; + +pub const TPACKET_ALIGNMENT: usize = 16; + +pub const TPACKET_HDRLEN: usize = ((size_of::() + TPACKET_ALIGNMENT - 1) + & !(TPACKET_ALIGNMENT - 1)) + + size_of::(); +pub const TPACKET2_HDRLEN: usize = ((size_of::() + TPACKET_ALIGNMENT - 1) + & !(TPACKET_ALIGNMENT - 1)) + + size_of::(); +pub const TPACKET3_HDRLEN: usize = ((size_of::() + TPACKET_ALIGNMENT - 1) + & !(TPACKET_ALIGNMENT - 1)) + + size_of::(); + +// linux/netfilter.h +pub const NF_DROP: c_int = 0; +pub const NF_ACCEPT: c_int = 1; +pub const NF_STOLEN: c_int = 2; +pub const NF_QUEUE: c_int = 3; +pub const NF_REPEAT: c_int = 4; +pub const NF_STOP: c_int = 5; +pub const NF_MAX_VERDICT: c_int = NF_STOP; + +pub const NF_VERDICT_MASK: c_int = 0x000000ff; +pub const NF_VERDICT_FLAG_QUEUE_BYPASS: c_int = 0x00008000; + +pub const NF_VERDICT_QMASK: c_int = 0xffff0000; +pub const NF_VERDICT_QBITS: c_int = 16; + +pub const NF_VERDICT_BITS: c_int = 16; + +pub const NF_INET_PRE_ROUTING: c_int = 0; +pub const NF_INET_LOCAL_IN: c_int = 1; +pub const NF_INET_FORWARD: c_int = 2; +pub const NF_INET_LOCAL_OUT: c_int = 3; +pub const NF_INET_POST_ROUTING: c_int = 4; +pub const NF_INET_NUMHOOKS: c_int = 5; +pub const NF_INET_INGRESS: c_int = NF_INET_NUMHOOKS; + +pub const NF_NETDEV_INGRESS: c_int = 0; +pub const NF_NETDEV_EGRESS: c_int = 1; +pub const NF_NETDEV_NUMHOOKS: c_int = 2; + +// Some NFPROTO are not compatible with musl and are defined in submodules. +pub const NFPROTO_UNSPEC: c_int = 0; +pub const NFPROTO_INET: c_int = 1; +pub const NFPROTO_IPV4: c_int = 2; +pub const NFPROTO_ARP: c_int = 3; +pub const NFPROTO_NETDEV: c_int = 5; +pub const NFPROTO_BRIDGE: c_int = 7; +pub const NFPROTO_IPV6: c_int = 10; +pub const NFPROTO_DECNET: c_int = 12; +pub const NFPROTO_NUMPROTO: c_int = 13; + +// linux/netfilter_arp.h +pub const NF_ARP: c_int = 0; +pub const NF_ARP_IN: c_int = 0; +pub const NF_ARP_OUT: c_int = 1; +pub const NF_ARP_FORWARD: c_int = 2; +pub const NF_ARP_NUMHOOKS: c_int = 3; + +// linux/netfilter_bridge.h +pub const NF_BR_PRE_ROUTING: c_int = 0; +pub const NF_BR_LOCAL_IN: c_int = 1; +pub const NF_BR_FORWARD: c_int = 2; +pub const NF_BR_LOCAL_OUT: c_int = 3; +pub const NF_BR_POST_ROUTING: c_int = 4; +pub const NF_BR_BROUTING: c_int = 5; +pub const NF_BR_NUMHOOKS: c_int = 6; + +pub const NF_BR_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_BR_PRI_NAT_DST_BRIDGED: c_int = -300; +pub const NF_BR_PRI_FILTER_BRIDGED: c_int = -200; +pub const NF_BR_PRI_BRNF: c_int = 0; +pub const NF_BR_PRI_NAT_DST_OTHER: c_int = 100; +pub const NF_BR_PRI_FILTER_OTHER: c_int = 200; +pub const NF_BR_PRI_NAT_SRC: c_int = 300; +pub const NF_BR_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv4.h +pub const NF_IP_PRE_ROUTING: c_int = 0; +pub const NF_IP_LOCAL_IN: c_int = 1; +pub const NF_IP_FORWARD: c_int = 2; +pub const NF_IP_LOCAL_OUT: c_int = 3; +pub const NF_IP_POST_ROUTING: c_int = 4; +pub const NF_IP_NUMHOOKS: c_int = 5; + +pub const NF_IP_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_IP_PRI_RAW_BEFORE_DEFRAG: c_int = -450; +pub const NF_IP_PRI_CONNTRACK_DEFRAG: c_int = -400; +pub const NF_IP_PRI_RAW: c_int = -300; +pub const NF_IP_PRI_SELINUX_FIRST: c_int = -225; +pub const NF_IP_PRI_CONNTRACK: c_int = -200; +pub const NF_IP_PRI_MANGLE: c_int = -150; +pub const NF_IP_PRI_NAT_DST: c_int = -100; +pub const NF_IP_PRI_FILTER: c_int = 0; +pub const NF_IP_PRI_SECURITY: c_int = 50; +pub const NF_IP_PRI_NAT_SRC: c_int = 100; +pub const NF_IP_PRI_SELINUX_LAST: c_int = 225; +pub const NF_IP_PRI_CONNTRACK_HELPER: c_int = 300; +pub const NF_IP_PRI_CONNTRACK_CONFIRM: c_int = crate::INT_MAX; +pub const NF_IP_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv6.h +pub const NF_IP6_PRE_ROUTING: c_int = 0; +pub const NF_IP6_LOCAL_IN: c_int = 1; +pub const NF_IP6_FORWARD: c_int = 2; +pub const NF_IP6_LOCAL_OUT: c_int = 3; +pub const NF_IP6_POST_ROUTING: c_int = 4; +pub const NF_IP6_NUMHOOKS: c_int = 5; + +pub const NF_IP6_PRI_FIRST: c_int = crate::INT_MIN; +pub const NF_IP6_PRI_RAW_BEFORE_DEFRAG: c_int = -450; +pub const NF_IP6_PRI_CONNTRACK_DEFRAG: c_int = -400; +pub const NF_IP6_PRI_RAW: c_int = -300; +pub const NF_IP6_PRI_SELINUX_FIRST: c_int = -225; +pub const NF_IP6_PRI_CONNTRACK: c_int = -200; +pub const NF_IP6_PRI_MANGLE: c_int = -150; +pub const NF_IP6_PRI_NAT_DST: c_int = -100; +pub const NF_IP6_PRI_FILTER: c_int = 0; +pub const NF_IP6_PRI_SECURITY: c_int = 50; +pub const NF_IP6_PRI_NAT_SRC: c_int = 100; +pub const NF_IP6_PRI_SELINUX_LAST: c_int = 225; +pub const NF_IP6_PRI_CONNTRACK_HELPER: c_int = 300; +pub const NF_IP6_PRI_LAST: c_int = crate::INT_MAX; + +// linux/netfilter_ipv6/ip6_tables.h +pub const IP6T_SO_ORIGINAL_DST: c_int = 80; + +pub const SIOCSHWTSTAMP: c_ulong = 0x000089b0; +pub const SIOCGHWTSTAMP: c_ulong = 0x000089b1; + +// wireless.h +pub const WIRELESS_EXT: c_ulong = 0x16; + +pub const SIOCSIWCOMMIT: c_ulong = 0x8B00; +pub const SIOCGIWNAME: c_ulong = 0x8B01; + +pub const SIOCSIWNWID: c_ulong = 0x8B02; +pub const SIOCGIWNWID: c_ulong = 0x8B03; +pub const SIOCSIWFREQ: c_ulong = 0x8B04; +pub const SIOCGIWFREQ: c_ulong = 0x8B05; +pub const SIOCSIWMODE: c_ulong = 0x8B06; +pub const SIOCGIWMODE: c_ulong = 0x8B07; +pub const SIOCSIWSENS: c_ulong = 0x8B08; +pub const SIOCGIWSENS: c_ulong = 0x8B09; + +pub const SIOCSIWRANGE: c_ulong = 0x8B0A; +pub const SIOCGIWRANGE: c_ulong = 0x8B0B; +pub const SIOCSIWPRIV: c_ulong = 0x8B0C; +pub const SIOCGIWPRIV: c_ulong = 0x8B0D; +pub const SIOCSIWSTATS: c_ulong = 0x8B0E; +pub const SIOCGIWSTATS: c_ulong = 0x8B0F; + +pub const SIOCSIWSPY: c_ulong = 0x8B10; +pub const SIOCGIWSPY: c_ulong = 0x8B11; +pub const SIOCSIWTHRSPY: c_ulong = 0x8B12; +pub const SIOCGIWTHRSPY: c_ulong = 0x8B13; + +pub const SIOCSIWAP: c_ulong = 0x8B14; +pub const SIOCGIWAP: c_ulong = 0x8B15; +pub const SIOCGIWAPLIST: c_ulong = 0x8B17; +pub const SIOCSIWSCAN: c_ulong = 0x8B18; +pub const SIOCGIWSCAN: c_ulong = 0x8B19; + +pub const SIOCSIWESSID: c_ulong = 0x8B1A; +pub const SIOCGIWESSID: c_ulong = 0x8B1B; +pub const SIOCSIWNICKN: c_ulong = 0x8B1C; +pub const SIOCGIWNICKN: c_ulong = 0x8B1D; + +pub const SIOCSIWRATE: c_ulong = 0x8B20; +pub const SIOCGIWRATE: c_ulong = 0x8B21; +pub const SIOCSIWRTS: c_ulong = 0x8B22; +pub const SIOCGIWRTS: c_ulong = 0x8B23; +pub const SIOCSIWFRAG: c_ulong = 0x8B24; +pub const SIOCGIWFRAG: c_ulong = 0x8B25; +pub const SIOCSIWTXPOW: c_ulong = 0x8B26; +pub const SIOCGIWTXPOW: c_ulong = 0x8B27; +pub const SIOCSIWRETRY: c_ulong = 0x8B28; +pub const SIOCGIWRETRY: c_ulong = 0x8B29; + +pub const SIOCSIWENCODE: c_ulong = 0x8B2A; +pub const SIOCGIWENCODE: c_ulong = 0x8B2B; + +pub const SIOCSIWPOWER: c_ulong = 0x8B2C; +pub const SIOCGIWPOWER: c_ulong = 0x8B2D; + +pub const SIOCSIWGENIE: c_ulong = 0x8B30; +pub const SIOCGIWGENIE: c_ulong = 0x8B31; + +pub const SIOCSIWMLME: c_ulong = 0x8B16; + +pub const SIOCSIWAUTH: c_ulong = 0x8B32; +pub const SIOCGIWAUTH: c_ulong = 0x8B33; + +pub const SIOCSIWENCODEEXT: c_ulong = 0x8B34; +pub const SIOCGIWENCODEEXT: c_ulong = 0x8B35; + +pub const SIOCSIWPMKSA: c_ulong = 0x8B36; + +pub const SIOCIWFIRSTPRIV: c_ulong = 0x8BE0; +pub const SIOCIWLASTPRIV: c_ulong = 0x8BFF; + +pub const SIOCIWFIRST: c_ulong = 0x8B00; +pub const SIOCIWLAST: c_ulong = SIOCIWLASTPRIV; + +pub const IWEVTXDROP: c_ulong = 0x8C00; +pub const IWEVQUAL: c_ulong = 0x8C01; +pub const IWEVCUSTOM: c_ulong = 0x8C02; +pub const IWEVREGISTERED: c_ulong = 0x8C03; +pub const IWEVEXPIRED: c_ulong = 0x8C04; +pub const IWEVGENIE: c_ulong = 0x8C05; +pub const IWEVMICHAELMICFAILURE: c_ulong = 0x8C06; +pub const IWEVASSOCREQIE: c_ulong = 0x8C07; +pub const IWEVASSOCRESPIE: c_ulong = 0x8C08; +pub const IWEVPMKIDCAND: c_ulong = 0x8C09; +pub const IWEVFIRST: c_ulong = 0x8C00; + +pub const IW_PRIV_TYPE_MASK: c_ulong = 0x7000; +pub const IW_PRIV_TYPE_NONE: c_ulong = 0x0000; +pub const IW_PRIV_TYPE_BYTE: c_ulong = 0x1000; +pub const IW_PRIV_TYPE_CHAR: c_ulong = 0x2000; +pub const IW_PRIV_TYPE_INT: c_ulong = 0x4000; +pub const IW_PRIV_TYPE_FLOAT: c_ulong = 0x5000; +pub const IW_PRIV_TYPE_ADDR: c_ulong = 0x6000; + +pub const IW_PRIV_SIZE_FIXED: c_ulong = 0x0800; + +pub const IW_PRIV_SIZE_MASK: c_ulong = 0x07FF; + +pub const IW_MAX_FREQUENCIES: usize = 32; +pub const IW_MAX_BITRATES: usize = 32; +pub const IW_MAX_TXPOWER: usize = 8; +pub const IW_MAX_SPY: usize = 8; +pub const IW_MAX_AP: usize = 64; +pub const IW_ESSID_MAX_SIZE: usize = 32; + +pub const IW_MODE_AUTO: usize = 0; +pub const IW_MODE_ADHOC: usize = 1; +pub const IW_MODE_INFRA: usize = 2; +pub const IW_MODE_MASTER: usize = 3; +pub const IW_MODE_REPEAT: usize = 4; +pub const IW_MODE_SECOND: usize = 5; +pub const IW_MODE_MONITOR: usize = 6; +pub const IW_MODE_MESH: usize = 7; + +pub const IW_QUAL_QUAL_UPDATED: c_ulong = 0x01; +pub const IW_QUAL_LEVEL_UPDATED: c_ulong = 0x02; +pub const IW_QUAL_NOISE_UPDATED: c_ulong = 0x04; +pub const IW_QUAL_ALL_UPDATED: c_ulong = 0x07; +pub const IW_QUAL_DBM: c_ulong = 0x08; +pub const IW_QUAL_QUAL_INVALID: c_ulong = 0x10; +pub const IW_QUAL_LEVEL_INVALID: c_ulong = 0x20; +pub const IW_QUAL_NOISE_INVALID: c_ulong = 0x40; +pub const IW_QUAL_RCPI: c_ulong = 0x80; +pub const IW_QUAL_ALL_INVALID: c_ulong = 0x70; + +pub const IW_FREQ_AUTO: c_ulong = 0x00; +pub const IW_FREQ_FIXED: c_ulong = 0x01; + +pub const IW_MAX_ENCODING_SIZES: usize = 8; +pub const IW_ENCODING_TOKEN_MAX: usize = 64; + +pub const IW_ENCODE_INDEX: c_ulong = 0x00FF; +pub const IW_ENCODE_FLAGS: c_ulong = 0xFF00; +pub const IW_ENCODE_MODE: c_ulong = 0xF000; +pub const IW_ENCODE_DISABLED: c_ulong = 0x8000; +pub const IW_ENCODE_ENABLED: c_ulong = 0x0000; +pub const IW_ENCODE_RESTRICTED: c_ulong = 0x4000; +pub const IW_ENCODE_OPEN: c_ulong = 0x2000; +pub const IW_ENCODE_NOKEY: c_ulong = 0x0800; +pub const IW_ENCODE_TEMP: c_ulong = 0x0400; + +pub const IW_POWER_ON: c_ulong = 0x0000; +pub const IW_POWER_TYPE: c_ulong = 0xF000; +pub const IW_POWER_PERIOD: c_ulong = 0x1000; +pub const IW_POWER_TIMEOUT: c_ulong = 0x2000; +pub const IW_POWER_MODE: c_ulong = 0x0F00; +pub const IW_POWER_UNICAST_R: c_ulong = 0x0100; +pub const IW_POWER_MULTICAST_R: c_ulong = 0x0200; +pub const IW_POWER_ALL_R: c_ulong = 0x0300; +pub const IW_POWER_FORCE_S: c_ulong = 0x0400; +pub const IW_POWER_REPEATER: c_ulong = 0x0800; +pub const IW_POWER_MODIFIER: c_ulong = 0x000F; +pub const IW_POWER_MIN: c_ulong = 0x0001; +pub const IW_POWER_MAX: c_ulong = 0x0002; +pub const IW_POWER_RELATIVE: c_ulong = 0x0004; + +pub const IW_TXPOW_TYPE: c_ulong = 0x00FF; +pub const IW_TXPOW_DBM: c_ulong = 0x0000; +pub const IW_TXPOW_MWATT: c_ulong = 0x0001; +pub const IW_TXPOW_RELATIVE: c_ulong = 0x0002; +pub const IW_TXPOW_RANGE: c_ulong = 0x1000; + +pub const IW_RETRY_ON: c_ulong = 0x0000; +pub const IW_RETRY_TYPE: c_ulong = 0xF000; +pub const IW_RETRY_LIMIT: c_ulong = 0x1000; +pub const IW_RETRY_LIFETIME: c_ulong = 0x2000; +pub const IW_RETRY_MODIFIER: c_ulong = 0x00FF; +pub const IW_RETRY_MIN: c_ulong = 0x0001; +pub const IW_RETRY_MAX: c_ulong = 0x0002; +pub const IW_RETRY_RELATIVE: c_ulong = 0x0004; +pub const IW_RETRY_SHORT: c_ulong = 0x0010; +pub const IW_RETRY_LONG: c_ulong = 0x0020; + +pub const IW_SCAN_DEFAULT: c_ulong = 0x0000; +pub const IW_SCAN_ALL_ESSID: c_ulong = 0x0001; +pub const IW_SCAN_THIS_ESSID: c_ulong = 0x0002; +pub const IW_SCAN_ALL_FREQ: c_ulong = 0x0004; +pub const IW_SCAN_THIS_FREQ: c_ulong = 0x0008; +pub const IW_SCAN_ALL_MODE: c_ulong = 0x0010; +pub const IW_SCAN_THIS_MODE: c_ulong = 0x0020; +pub const IW_SCAN_ALL_RATE: c_ulong = 0x0040; +pub const IW_SCAN_THIS_RATE: c_ulong = 0x0080; + +pub const IW_SCAN_TYPE_ACTIVE: usize = 0; +pub const IW_SCAN_TYPE_PASSIVE: usize = 1; + +pub const IW_SCAN_MAX_DATA: usize = 4096; + +pub const IW_SCAN_CAPA_NONE: c_ulong = 0x00; +pub const IW_SCAN_CAPA_ESSID: c_ulong = 0x01; +pub const IW_SCAN_CAPA_BSSID: c_ulong = 0x02; +pub const IW_SCAN_CAPA_CHANNEL: c_ulong = 0x04; +pub const IW_SCAN_CAPA_MODE: c_ulong = 0x08; +pub const IW_SCAN_CAPA_RATE: c_ulong = 0x10; +pub const IW_SCAN_CAPA_TYPE: c_ulong = 0x20; +pub const IW_SCAN_CAPA_TIME: c_ulong = 0x40; + +pub const IW_CUSTOM_MAX: c_ulong = 256; + +pub const IW_GENERIC_IE_MAX: c_ulong = 1024; + +pub const IW_MLME_DEAUTH: c_ulong = 0; +pub const IW_MLME_DISASSOC: c_ulong = 1; +pub const IW_MLME_AUTH: c_ulong = 2; +pub const IW_MLME_ASSOC: c_ulong = 3; + +pub const IW_AUTH_INDEX: c_ulong = 0x0FFF; +pub const IW_AUTH_FLAGS: c_ulong = 0xF000; + +pub const IW_AUTH_WPA_VERSION: usize = 0; +pub const IW_AUTH_CIPHER_PAIRWISE: usize = 1; +pub const IW_AUTH_CIPHER_GROUP: usize = 2; +pub const IW_AUTH_KEY_MGMT: usize = 3; +pub const IW_AUTH_TKIP_COUNTERMEASURES: usize = 4; +pub const IW_AUTH_DROP_UNENCRYPTED: usize = 5; +pub const IW_AUTH_80211_AUTH_ALG: usize = 6; +pub const IW_AUTH_WPA_ENABLED: usize = 7; +pub const IW_AUTH_RX_UNENCRYPTED_EAPOL: usize = 8; +pub const IW_AUTH_ROAMING_CONTROL: usize = 9; +pub const IW_AUTH_PRIVACY_INVOKED: usize = 10; +pub const IW_AUTH_CIPHER_GROUP_MGMT: usize = 11; +pub const IW_AUTH_MFP: usize = 12; + +pub const IW_AUTH_WPA_VERSION_DISABLED: c_ulong = 0x00000001; +pub const IW_AUTH_WPA_VERSION_WPA: c_ulong = 0x00000002; +pub const IW_AUTH_WPA_VERSION_WPA2: c_ulong = 0x00000004; + +pub const IW_AUTH_CIPHER_NONE: c_ulong = 0x00000001; +pub const IW_AUTH_CIPHER_WEP40: c_ulong = 0x00000002; +pub const IW_AUTH_CIPHER_TKIP: c_ulong = 0x00000004; +pub const IW_AUTH_CIPHER_CCMP: c_ulong = 0x00000008; +pub const IW_AUTH_CIPHER_WEP104: c_ulong = 0x00000010; +pub const IW_AUTH_CIPHER_AES_CMAC: c_ulong = 0x00000020; + +pub const IW_AUTH_KEY_MGMT_802_1X: usize = 1; +pub const IW_AUTH_KEY_MGMT_PSK: usize = 2; + +pub const IW_AUTH_ALG_OPEN_SYSTEM: c_ulong = 0x00000001; +pub const IW_AUTH_ALG_SHARED_KEY: c_ulong = 0x00000002; +pub const IW_AUTH_ALG_LEAP: c_ulong = 0x00000004; + +pub const IW_AUTH_ROAMING_ENABLE: usize = 0; +pub const IW_AUTH_ROAMING_DISABLE: usize = 1; + +pub const IW_AUTH_MFP_DISABLED: usize = 0; +pub const IW_AUTH_MFP_OPTIONAL: usize = 1; +pub const IW_AUTH_MFP_REQUIRED: usize = 2; + +pub const IW_ENCODE_SEQ_MAX_SIZE: usize = 8; + +pub const IW_ENCODE_ALG_NONE: usize = 0; +pub const IW_ENCODE_ALG_WEP: usize = 1; +pub const IW_ENCODE_ALG_TKIP: usize = 2; +pub const IW_ENCODE_ALG_CCMP: usize = 3; +pub const IW_ENCODE_ALG_PMK: usize = 4; +pub const IW_ENCODE_ALG_AES_CMAC: usize = 5; + +pub const IW_ENCODE_EXT_TX_SEQ_VALID: c_ulong = 0x00000001; +pub const IW_ENCODE_EXT_RX_SEQ_VALID: c_ulong = 0x00000002; +pub const IW_ENCODE_EXT_GROUP_KEY: c_ulong = 0x00000004; +pub const IW_ENCODE_EXT_SET_TX_KEY: c_ulong = 0x00000008; + +pub const IW_MICFAILURE_KEY_ID: c_ulong = 0x00000003; +pub const IW_MICFAILURE_GROUP: c_ulong = 0x00000004; +pub const IW_MICFAILURE_PAIRWISE: c_ulong = 0x00000008; +pub const IW_MICFAILURE_STAKEY: c_ulong = 0x00000010; +pub const IW_MICFAILURE_COUNT: c_ulong = 0x00000060; + +pub const IW_ENC_CAPA_WPA: c_ulong = 0x00000001; +pub const IW_ENC_CAPA_WPA2: c_ulong = 0x00000002; +pub const IW_ENC_CAPA_CIPHER_TKIP: c_ulong = 0x00000004; +pub const IW_ENC_CAPA_CIPHER_CCMP: c_ulong = 0x00000008; +pub const IW_ENC_CAPA_4WAY_HANDSHAKE: c_ulong = 0x00000010; + +pub const IW_EVENT_CAPA_K_0: c_ulong = 0x4000050; // IW_EVENT_CAPA_MASK(0x8B04) | IW_EVENT_CAPA_MASK(0x8B06) | IW_EVENT_CAPA_MASK(0x8B1A); +pub const IW_EVENT_CAPA_K_1: c_ulong = 0x400; // W_EVENT_CAPA_MASK(0x8B2A); + +pub const IW_PMKSA_ADD: usize = 1; +pub const IW_PMKSA_REMOVE: usize = 2; +pub const IW_PMKSA_FLUSH: usize = 3; + +pub const IW_PMKID_LEN: usize = 16; + +pub const IW_PMKID_CAND_PREAUTH: c_ulong = 0x00000001; + +pub const IW_EV_LCP_PK_LEN: usize = 4; + +pub const IW_EV_CHAR_PK_LEN: usize = 20; // IW_EV_LCP_PK_LEN + crate::IFNAMSIZ; +pub const IW_EV_UINT_PK_LEN: usize = 8; // IW_EV_LCP_PK_LEN + size_of::(); +pub const IW_EV_FREQ_PK_LEN: usize = 12; // IW_EV_LCP_PK_LEN + size_of::(); +pub const IW_EV_PARAM_PK_LEN: usize = 12; // IW_EV_LCP_PK_LEN + size_of::(); +pub const IW_EV_ADDR_PK_LEN: usize = 20; // IW_EV_LCP_PK_LEN + size_of::(); +pub const IW_EV_QUAL_PK_LEN: usize = 8; // IW_EV_LCP_PK_LEN + size_of::(); +pub const IW_EV_POINT_PK_LEN: usize = 8; // IW_EV_LCP_PK_LEN + 4; + +// linux/neighbor.h +pub const NUD_NONE: u16 = 0x00; +pub const NUD_INCOMPLETE: u16 = 0x01; +pub const NUD_REACHABLE: u16 = 0x02; +pub const NUD_STALE: u16 = 0x04; +pub const NUD_DELAY: u16 = 0x08; +pub const NUD_PROBE: u16 = 0x10; +pub const NUD_FAILED: u16 = 0x20; +pub const NUD_NOARP: u16 = 0x40; +pub const NUD_PERMANENT: u16 = 0x80; + +pub const NTF_USE: u8 = 0x01; +pub const NTF_SELF: u8 = 0x02; +pub const NTF_MASTER: u8 = 0x04; +pub const NTF_PROXY: u8 = 0x08; +pub const NTF_ROUTER: u8 = 0x80; + +pub const NDA_UNSPEC: c_ushort = 0; +pub const NDA_DST: c_ushort = 1; +pub const NDA_LLADDR: c_ushort = 2; +pub const NDA_CACHEINFO: c_ushort = 3; +pub const NDA_PROBES: c_ushort = 4; +pub const NDA_VLAN: c_ushort = 5; +pub const NDA_PORT: c_ushort = 6; +pub const NDA_VNI: c_ushort = 7; +pub const NDA_IFINDEX: c_ushort = 8; + +// linux/netlink.h + +pub const NLM_F_BULK: c_int = 0x200; + +// linux/rtnetlink.h +pub const TCA_UNSPEC: c_ushort = 0; +pub const TCA_KIND: c_ushort = 1; +pub const TCA_OPTIONS: c_ushort = 2; +pub const TCA_STATS: c_ushort = 3; +pub const TCA_XSTATS: c_ushort = 4; +pub const TCA_RATE: c_ushort = 5; +pub const TCA_FCNT: c_ushort = 6; +pub const TCA_STATS2: c_ushort = 7; +pub const TCA_STAB: c_ushort = 8; + +pub const RTM_NEWLINK: u16 = 16; +pub const RTM_DELLINK: u16 = 17; +pub const RTM_GETLINK: u16 = 18; +pub const RTM_SETLINK: u16 = 19; +pub const RTM_NEWADDR: u16 = 20; +pub const RTM_DELADDR: u16 = 21; +pub const RTM_GETADDR: u16 = 22; +pub const RTM_NEWROUTE: u16 = 24; +pub const RTM_DELROUTE: u16 = 25; +pub const RTM_GETROUTE: u16 = 26; +pub const RTM_NEWNEIGH: u16 = 28; +pub const RTM_DELNEIGH: u16 = 29; +pub const RTM_GETNEIGH: u16 = 30; +pub const RTM_NEWRULE: u16 = 32; +pub const RTM_DELRULE: u16 = 33; +pub const RTM_GETRULE: u16 = 34; +pub const RTM_NEWQDISC: u16 = 36; +pub const RTM_DELQDISC: u16 = 37; +pub const RTM_GETQDISC: u16 = 38; +pub const RTM_NEWTCLASS: u16 = 40; +pub const RTM_DELTCLASS: u16 = 41; +pub const RTM_GETTCLASS: u16 = 42; +pub const RTM_NEWTFILTER: u16 = 44; +pub const RTM_DELTFILTER: u16 = 45; +pub const RTM_GETTFILTER: u16 = 46; +pub const RTM_NEWACTION: u16 = 48; +pub const RTM_DELACTION: u16 = 49; +pub const RTM_GETACTION: u16 = 50; +pub const RTM_NEWPREFIX: u16 = 52; +pub const RTM_GETMULTICAST: u16 = 58; +pub const RTM_GETANYCAST: u16 = 62; +pub const RTM_NEWNEIGHTBL: u16 = 64; +pub const RTM_GETNEIGHTBL: u16 = 66; +pub const RTM_SETNEIGHTBL: u16 = 67; +pub const RTM_NEWNDUSEROPT: u16 = 68; +pub const RTM_NEWADDRLABEL: u16 = 72; +pub const RTM_DELADDRLABEL: u16 = 73; +pub const RTM_GETADDRLABEL: u16 = 74; +pub const RTM_GETDCB: u16 = 78; +pub const RTM_SETDCB: u16 = 79; +pub const RTM_NEWNETCONF: u16 = 80; +pub const RTM_GETNETCONF: u16 = 82; +pub const RTM_NEWMDB: u16 = 84; +pub const RTM_DELMDB: u16 = 85; +pub const RTM_GETMDB: u16 = 86; +pub const RTM_NEWNSID: u16 = 88; +pub const RTM_DELNSID: u16 = 89; +pub const RTM_GETNSID: u16 = 90; + +pub const RTM_F_NOTIFY: c_uint = 0x100; +pub const RTM_F_CLONED: c_uint = 0x200; +pub const RTM_F_EQUALIZE: c_uint = 0x400; +pub const RTM_F_PREFIX: c_uint = 0x800; + +pub const RTA_UNSPEC: c_ushort = 0; +pub const RTA_DST: c_ushort = 1; +pub const RTA_SRC: c_ushort = 2; +pub const RTA_IIF: c_ushort = 3; +pub const RTA_OIF: c_ushort = 4; +pub const RTA_GATEWAY: c_ushort = 5; +pub const RTA_PRIORITY: c_ushort = 6; +pub const RTA_PREFSRC: c_ushort = 7; +pub const RTA_METRICS: c_ushort = 8; +pub const RTA_MULTIPATH: c_ushort = 9; +pub const RTA_PROTOINFO: c_ushort = 10; // No longer used +pub const RTA_FLOW: c_ushort = 11; +pub const RTA_CACHEINFO: c_ushort = 12; +pub const RTA_SESSION: c_ushort = 13; // No longer used +pub const RTA_MP_ALGO: c_ushort = 14; // No longer used +pub const RTA_TABLE: c_ushort = 15; +pub const RTA_MARK: c_ushort = 16; +pub const RTA_MFC_STATS: c_ushort = 17; + +pub const RTN_UNSPEC: c_uchar = 0; +pub const RTN_UNICAST: c_uchar = 1; +pub const RTN_LOCAL: c_uchar = 2; +pub const RTN_BROADCAST: c_uchar = 3; +pub const RTN_ANYCAST: c_uchar = 4; +pub const RTN_MULTICAST: c_uchar = 5; +pub const RTN_BLACKHOLE: c_uchar = 6; +pub const RTN_UNREACHABLE: c_uchar = 7; +pub const RTN_PROHIBIT: c_uchar = 8; +pub const RTN_THROW: c_uchar = 9; +pub const RTN_NAT: c_uchar = 10; +pub const RTN_XRESOLVE: c_uchar = 11; + +pub const RTPROT_UNSPEC: c_uchar = 0; +pub const RTPROT_REDIRECT: c_uchar = 1; +pub const RTPROT_KERNEL: c_uchar = 2; +pub const RTPROT_BOOT: c_uchar = 3; +pub const RTPROT_STATIC: c_uchar = 4; + +pub const RT_SCOPE_UNIVERSE: c_uchar = 0; +pub const RT_SCOPE_SITE: c_uchar = 200; +pub const RT_SCOPE_LINK: c_uchar = 253; +pub const RT_SCOPE_HOST: c_uchar = 254; +pub const RT_SCOPE_NOWHERE: c_uchar = 255; + +pub const RT_TABLE_UNSPEC: c_uchar = 0; +pub const RT_TABLE_COMPAT: c_uchar = 252; +pub const RT_TABLE_DEFAULT: c_uchar = 253; +pub const RT_TABLE_MAIN: c_uchar = 254; +pub const RT_TABLE_LOCAL: c_uchar = 255; + +pub const RTMSG_OVERRUN: u32 = crate::NLMSG_OVERRUN as u32; +pub const RTMSG_NEWDEVICE: u32 = 0x11; +pub const RTMSG_DELDEVICE: u32 = 0x12; +pub const RTMSG_NEWROUTE: u32 = 0x21; +pub const RTMSG_DELROUTE: u32 = 0x22; +pub const RTMSG_NEWRULE: u32 = 0x31; +pub const RTMSG_DELRULE: u32 = 0x32; +pub const RTMSG_CONTROL: u32 = 0x40; +pub const RTMSG_AR_FAILED: u32 = 0x51; + +pub const RTEXT_FILTER_VF: c_int = 1 << 0; +pub const RTEXT_FILTER_BRVLAN: c_int = 1 << 1; +pub const RTEXT_FILTER_BRVLAN_COMPRESSED: c_int = 1 << 2; +pub const RTEXT_FILTER_SKIP_STATS: c_int = 1 << 3; +pub const RTEXT_FILTER_MRP: c_int = 1 << 4; +pub const RTEXT_FILTER_CFM_CONFIG: c_int = 1 << 5; +pub const RTEXT_FILTER_CFM_STATUS: c_int = 1 << 6; + +// userspace compat definitions for RTNLGRP_* +pub const RTMGRP_LINK: c_int = 0x00001; +pub const RTMGRP_NOTIFY: c_int = 0x00002; +pub const RTMGRP_NEIGH: c_int = 0x00004; +pub const RTMGRP_TC: c_int = 0x00008; +pub const RTMGRP_IPV4_IFADDR: c_int = 0x00010; +pub const RTMGRP_IPV4_MROUTE: c_int = 0x00020; +pub const RTMGRP_IPV4_ROUTE: c_int = 0x00040; +pub const RTMGRP_IPV4_RULE: c_int = 0x00080; +pub const RTMGRP_IPV6_IFADDR: c_int = 0x00100; +pub const RTMGRP_IPV6_MROUTE: c_int = 0x00200; +pub const RTMGRP_IPV6_ROUTE: c_int = 0x00400; +pub const RTMGRP_IPV6_IFINFO: c_int = 0x00800; +pub const RTMGRP_DECnet_IFADDR: c_int = 0x01000; +pub const RTMGRP_DECnet_ROUTE: c_int = 0x04000; +pub const RTMGRP_IPV6_PREFIX: c_int = 0x20000; + +// enum rtnetlink_groups +pub const RTNLGRP_NONE: c_uint = 0x00; +pub const RTNLGRP_LINK: c_uint = 0x01; +pub const RTNLGRP_NOTIFY: c_uint = 0x02; +pub const RTNLGRP_NEIGH: c_uint = 0x03; +pub const RTNLGRP_TC: c_uint = 0x04; +pub const RTNLGRP_IPV4_IFADDR: c_uint = 0x05; +pub const RTNLGRP_IPV4_MROUTE: c_uint = 0x06; +pub const RTNLGRP_IPV4_ROUTE: c_uint = 0x07; +pub const RTNLGRP_IPV4_RULE: c_uint = 0x08; +pub const RTNLGRP_IPV6_IFADDR: c_uint = 0x09; +pub const RTNLGRP_IPV6_MROUTE: c_uint = 0x0a; +pub const RTNLGRP_IPV6_ROUTE: c_uint = 0x0b; +pub const RTNLGRP_IPV6_IFINFO: c_uint = 0x0c; +pub const RTNLGRP_DECnet_IFADDR: c_uint = 0x0d; +pub const RTNLGRP_NOP2: c_uint = 0x0e; +pub const RTNLGRP_DECnet_ROUTE: c_uint = 0x0f; +pub const RTNLGRP_DECnet_RULE: c_uint = 0x10; +pub const RTNLGRP_NOP4: c_uint = 0x11; +pub const RTNLGRP_IPV6_PREFIX: c_uint = 0x12; +pub const RTNLGRP_IPV6_RULE: c_uint = 0x13; +pub const RTNLGRP_ND_USEROPT: c_uint = 0x14; +pub const RTNLGRP_PHONET_IFADDR: c_uint = 0x15; +pub const RTNLGRP_PHONET_ROUTE: c_uint = 0x16; +pub const RTNLGRP_DCB: c_uint = 0x17; +pub const RTNLGRP_IPV4_NETCONF: c_uint = 0x18; +pub const RTNLGRP_IPV6_NETCONF: c_uint = 0x19; +pub const RTNLGRP_MDB: c_uint = 0x1a; +pub const RTNLGRP_MPLS_ROUTE: c_uint = 0x1b; +pub const RTNLGRP_NSID: c_uint = 0x1c; +pub const RTNLGRP_MPLS_NETCONF: c_uint = 0x1d; +pub const RTNLGRP_IPV4_MROUTE_R: c_uint = 0x1e; +pub const RTNLGRP_IPV6_MROUTE_R: c_uint = 0x1f; +pub const RTNLGRP_NEXTHOP: c_uint = 0x20; +pub const RTNLGRP_BRVLAN: c_uint = 0x21; +pub const RTNLGRP_MCTP_IFADDR: c_uint = 0x22; +pub const RTNLGRP_TUNNEL: c_uint = 0x23; +pub const RTNLGRP_STATS: c_uint = 0x24; + +// linux/cn_proc.h +c_enum! { + pub enum proc_cn_mcast_op { + pub PROC_CN_MCAST_LISTEN = 1, + pub PROC_CN_MCAST_IGNORE = 2, + } + + pub enum proc_cn_event { + pub PROC_EVENT_NONE = 0x00000000, + pub PROC_EVENT_FORK = 0x00000001, + pub PROC_EVENT_EXEC = 0x00000002, + pub PROC_EVENT_UID = 0x00000004, + pub PROC_EVENT_GID = 0x00000040, + pub PROC_EVENT_SID = 0x00000080, + pub PROC_EVENT_PTRACE = 0x00000100, + pub PROC_EVENT_COMM = 0x00000200, + pub PROC_EVENT_NONZERO_EXIT = 0x20000000, + pub PROC_EVENT_COREDUMP = 0x40000000, + pub PROC_EVENT_EXIT = 0x80000000, + } +} + +// linux/connector.h +pub const CN_IDX_PROC: c_uint = 0x1; +pub const CN_VAL_PROC: c_uint = 0x1; +pub const CN_IDX_CIFS: c_uint = 0x2; +pub const CN_VAL_CIFS: c_uint = 0x1; +pub const CN_W1_IDX: c_uint = 0x3; +pub const CN_W1_VAL: c_uint = 0x1; +pub const CN_IDX_V86D: c_uint = 0x4; +pub const CN_VAL_V86D_UVESAFB: c_uint = 0x1; +pub const CN_IDX_BB: c_uint = 0x5; +pub const CN_DST_IDX: c_uint = 0x6; +pub const CN_DST_VAL: c_uint = 0x1; +pub const CN_IDX_DM: c_uint = 0x7; +pub const CN_VAL_DM_USERSPACE_LOG: c_uint = 0x1; +pub const CN_IDX_DRBD: c_uint = 0x8; +pub const CN_VAL_DRBD: c_uint = 0x1; +pub const CN_KVP_IDX: c_uint = 0x9; +pub const CN_KVP_VAL: c_uint = 0x1; +pub const CN_VSS_IDX: c_uint = 0xA; +pub const CN_VSS_VAL: c_uint = 0x1; + +// linux/module.h +pub const MODULE_INIT_IGNORE_MODVERSIONS: c_uint = 0x0001; +pub const MODULE_INIT_IGNORE_VERMAGIC: c_uint = 0x0002; + +// linux/net_tstamp.h +pub const SOF_TIMESTAMPING_TX_HARDWARE: c_uint = 1 << 0; +pub const SOF_TIMESTAMPING_TX_SOFTWARE: c_uint = 1 << 1; +pub const SOF_TIMESTAMPING_RX_HARDWARE: c_uint = 1 << 2; +pub const SOF_TIMESTAMPING_RX_SOFTWARE: c_uint = 1 << 3; +pub const SOF_TIMESTAMPING_SOFTWARE: c_uint = 1 << 4; +pub const SOF_TIMESTAMPING_SYS_HARDWARE: c_uint = 1 << 5; +pub const SOF_TIMESTAMPING_RAW_HARDWARE: c_uint = 1 << 6; +pub const SOF_TIMESTAMPING_OPT_ID: c_uint = 1 << 7; +pub const SOF_TIMESTAMPING_TX_SCHED: c_uint = 1 << 8; +pub const SOF_TIMESTAMPING_TX_ACK: c_uint = 1 << 9; +pub const SOF_TIMESTAMPING_OPT_CMSG: c_uint = 1 << 10; +pub const SOF_TIMESTAMPING_OPT_TSONLY: c_uint = 1 << 11; +pub const SOF_TIMESTAMPING_OPT_STATS: c_uint = 1 << 12; +pub const SOF_TIMESTAMPING_OPT_PKTINFO: c_uint = 1 << 13; +pub const SOF_TIMESTAMPING_OPT_TX_SWHW: c_uint = 1 << 14; +pub const SOF_TIMESTAMPING_BIND_PHC: c_uint = 1 << 15; +pub const SOF_TIMESTAMPING_OPT_ID_TCP: c_uint = 1 << 16; +pub const SOF_TIMESTAMPING_OPT_RX_FILTER: c_uint = 1 << 17; +pub const SOF_TXTIME_DEADLINE_MODE: u32 = 1 << 0; +pub const SOF_TXTIME_REPORT_ERRORS: u32 = 1 << 1; + +pub const HWTSTAMP_TX_OFF: c_uint = 0; +pub const HWTSTAMP_TX_ON: c_uint = 1; +pub const HWTSTAMP_TX_ONESTEP_SYNC: c_uint = 2; +pub const HWTSTAMP_TX_ONESTEP_P2P: c_uint = 3; + +pub const HWTSTAMP_FILTER_NONE: c_uint = 0; +pub const HWTSTAMP_FILTER_ALL: c_uint = 1; +pub const HWTSTAMP_FILTER_SOME: c_uint = 2; +pub const HWTSTAMP_FILTER_PTP_V1_L4_EVENT: c_uint = 3; +pub const HWTSTAMP_FILTER_PTP_V1_L4_SYNC: c_uint = 4; +pub const HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: c_uint = 5; +pub const HWTSTAMP_FILTER_PTP_V2_L4_EVENT: c_uint = 6; +pub const HWTSTAMP_FILTER_PTP_V2_L4_SYNC: c_uint = 7; +pub const HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: c_uint = 8; +pub const HWTSTAMP_FILTER_PTP_V2_L2_EVENT: c_uint = 9; +pub const HWTSTAMP_FILTER_PTP_V2_L2_SYNC: c_uint = 10; +pub const HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: c_uint = 11; +pub const HWTSTAMP_FILTER_PTP_V2_EVENT: c_uint = 12; +pub const HWTSTAMP_FILTER_PTP_V2_SYNC: c_uint = 13; +pub const HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: c_uint = 14; +pub const HWTSTAMP_FILTER_NTP_ALL: c_uint = 15; + +// linux/ptp_clock.h +pub const PTP_MAX_SAMPLES: c_uint = 25; // Maximum allowed offset measurement samples. + +const PTP_CLK_MAGIC: u32 = b'=' as u32; + +pub const PTP_CLOCK_GETCAPS: Ioctl = _IOR::(PTP_CLK_MAGIC, 1); +pub const PTP_EXTTS_REQUEST: Ioctl = _IOW::(PTP_CLK_MAGIC, 2); +pub const PTP_PEROUT_REQUEST: Ioctl = _IOW::(PTP_CLK_MAGIC, 3); +pub const PTP_ENABLE_PPS: Ioctl = _IOW::(PTP_CLK_MAGIC, 4); +pub const PTP_SYS_OFFSET: Ioctl = _IOW::(PTP_CLK_MAGIC, 5); +pub const PTP_PIN_GETFUNC: Ioctl = _IOWR::(PTP_CLK_MAGIC, 6); +pub const PTP_PIN_SETFUNC: Ioctl = _IOW::(PTP_CLK_MAGIC, 7); +pub const PTP_SYS_OFFSET_PRECISE: Ioctl = _IOWR::(PTP_CLK_MAGIC, 8); +pub const PTP_SYS_OFFSET_EXTENDED: Ioctl = _IOWR::(PTP_CLK_MAGIC, 9); + +pub const PTP_CLOCK_GETCAPS2: Ioctl = _IOR::(PTP_CLK_MAGIC, 10); +pub const PTP_EXTTS_REQUEST2: Ioctl = _IOW::(PTP_CLK_MAGIC, 11); +pub const PTP_PEROUT_REQUEST2: Ioctl = _IOW::(PTP_CLK_MAGIC, 12); +pub const PTP_ENABLE_PPS2: Ioctl = _IOW::(PTP_CLK_MAGIC, 13); +pub const PTP_SYS_OFFSET2: Ioctl = _IOW::(PTP_CLK_MAGIC, 14); +pub const PTP_PIN_GETFUNC2: Ioctl = _IOWR::(PTP_CLK_MAGIC, 15); +pub const PTP_PIN_SETFUNC2: Ioctl = _IOW::(PTP_CLK_MAGIC, 16); +pub const PTP_SYS_OFFSET_PRECISE2: Ioctl = _IOWR::(PTP_CLK_MAGIC, 17); +pub const PTP_SYS_OFFSET_EXTENDED2: Ioctl = _IOWR::(PTP_CLK_MAGIC, 18); + +// enum ptp_pin_function +pub const PTP_PF_NONE: c_uint = 0; +pub const PTP_PF_EXTTS: c_uint = 1; +pub const PTP_PF_PEROUT: c_uint = 2; +pub const PTP_PF_PHYSYNC: c_uint = 3; + +// linux/tls.h +pub const TLS_TX: c_int = 1; +pub const TLS_RX: c_int = 2; + +pub const TLS_TX_ZEROCOPY_RO: c_int = 3; +pub const TLS_RX_EXPECT_NO_PAD: c_int = 4; + +pub const TLS_1_2_VERSION_MAJOR: __u8 = 0x3; +pub const TLS_1_2_VERSION_MINOR: __u8 = 0x3; +pub const TLS_1_2_VERSION: __u16 = + ((TLS_1_2_VERSION_MAJOR as __u16) << 8) | (TLS_1_2_VERSION_MINOR as __u16); + +pub const TLS_1_3_VERSION_MAJOR: __u8 = 0x3; +pub const TLS_1_3_VERSION_MINOR: __u8 = 0x4; +pub const TLS_1_3_VERSION: __u16 = + ((TLS_1_3_VERSION_MAJOR as __u16) << 8) | (TLS_1_3_VERSION_MINOR as __u16); + +pub const TLS_CIPHER_AES_GCM_128: __u16 = 51; +pub const TLS_CIPHER_AES_GCM_128_IV_SIZE: usize = 8; +pub const TLS_CIPHER_AES_GCM_128_KEY_SIZE: usize = 16; +pub const TLS_CIPHER_AES_GCM_128_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_AES_GCM_128_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_AES_GCM_256: __u16 = 52; +pub const TLS_CIPHER_AES_GCM_256_IV_SIZE: usize = 8; +pub const TLS_CIPHER_AES_GCM_256_KEY_SIZE: usize = 32; +pub const TLS_CIPHER_AES_GCM_256_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_AES_GCM_256_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_AES_CCM_128: __u16 = 53; +pub const TLS_CIPHER_AES_CCM_128_IV_SIZE: usize = 8; +pub const TLS_CIPHER_AES_CCM_128_KEY_SIZE: usize = 16; +pub const TLS_CIPHER_AES_CCM_128_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_AES_CCM_128_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_CHACHA20_POLY1305: __u16 = 54; +pub const TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE: usize = 12; +pub const TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE: usize = 32; +pub const TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE: usize = 0; +pub const TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_SM4_GCM: __u16 = 55; +pub const TLS_CIPHER_SM4_GCM_IV_SIZE: usize = 8; +pub const TLS_CIPHER_SM4_GCM_KEY_SIZE: usize = 16; +pub const TLS_CIPHER_SM4_GCM_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_SM4_GCM_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_SM4_CCM: __u16 = 56; +pub const TLS_CIPHER_SM4_CCM_IV_SIZE: usize = 8; +pub const TLS_CIPHER_SM4_CCM_KEY_SIZE: usize = 16; +pub const TLS_CIPHER_SM4_CCM_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_SM4_CCM_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_ARIA_GCM_128: __u16 = 57; +pub const TLS_CIPHER_ARIA_GCM_128_IV_SIZE: usize = 8; +pub const TLS_CIPHER_ARIA_GCM_128_KEY_SIZE: usize = 16; +pub const TLS_CIPHER_ARIA_GCM_128_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_ARIA_GCM_128_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_ARIA_GCM_128_REC_SEQ_SIZE: usize = 8; + +pub const TLS_CIPHER_ARIA_GCM_256: __u16 = 58; +pub const TLS_CIPHER_ARIA_GCM_256_IV_SIZE: usize = 8; +pub const TLS_CIPHER_ARIA_GCM_256_KEY_SIZE: usize = 32; +pub const TLS_CIPHER_ARIA_GCM_256_SALT_SIZE: usize = 4; +pub const TLS_CIPHER_ARIA_GCM_256_TAG_SIZE: usize = 16; +pub const TLS_CIPHER_ARIA_GCM_256_REC_SEQ_SIZE: usize = 8; + +pub const TLS_SET_RECORD_TYPE: c_int = 1; +pub const TLS_GET_RECORD_TYPE: c_int = 2; + +pub const SOL_TLS: c_int = 282; + +// enum +pub const TLS_INFO_UNSPEC: c_int = 0x00; +pub const TLS_INFO_VERSION: c_int = 0x01; +pub const TLS_INFO_CIPHER: c_int = 0x02; +pub const TLS_INFO_TXCONF: c_int = 0x03; +pub const TLS_INFO_RXCONF: c_int = 0x04; +pub const TLS_INFO_ZC_RO_TX: c_int = 0x05; +pub const TLS_INFO_RX_NO_PAD: c_int = 0x06; + +pub const TLS_CONF_BASE: c_int = 1; +pub const TLS_CONF_SW: c_int = 2; +pub const TLS_CONF_HW: c_int = 3; +pub const TLS_CONF_HW_RECORD: c_int = 4; + +// linux/if_alg.h +pub const ALG_SET_KEY: c_int = 1; +pub const ALG_SET_IV: c_int = 2; +pub const ALG_SET_OP: c_int = 3; +pub const ALG_SET_AEAD_ASSOCLEN: c_int = 4; +pub const ALG_SET_AEAD_AUTHSIZE: c_int = 5; +pub const ALG_SET_DRBG_ENTROPY: c_int = 6; +pub const ALG_SET_KEY_BY_KEY_SERIAL: c_int = 7; + +pub const ALG_OP_DECRYPT: c_int = 0; +pub const ALG_OP_ENCRYPT: c_int = 1; + +// include/uapi/linux/if.h +pub const IF_OPER_UNKNOWN: c_int = 0; +pub const IF_OPER_NOTPRESENT: c_int = 1; +pub const IF_OPER_DOWN: c_int = 2; +pub const IF_OPER_LOWERLAYERDOWN: c_int = 3; +pub const IF_OPER_TESTING: c_int = 4; +pub const IF_OPER_DORMANT: c_int = 5; +pub const IF_OPER_UP: c_int = 6; + +pub const IF_LINK_MODE_DEFAULT: c_int = 0; +pub const IF_LINK_MODE_DORMANT: c_int = 1; +pub const IF_LINK_MODE_TESTING: c_int = 2; + +// include/uapi/linux/mman.h +pub const MAP_SHARED_VALIDATE: c_int = 0x3; +pub const MAP_DROPPABLE: c_int = 0x8; + +// uapi/linux/vm_sockets.h +pub const VMADDR_CID_ANY: c_uint = 0xFFFFFFFF; +pub const VMADDR_CID_HYPERVISOR: c_uint = 0; +#[deprecated( + since = "0.2.74", + note = "VMADDR_CID_RESERVED is removed since Linux v5.6 and \ + replaced with VMADDR_CID_LOCAL" +)] +pub const VMADDR_CID_RESERVED: c_uint = 1; +pub const VMADDR_CID_LOCAL: c_uint = 1; +pub const VMADDR_CID_HOST: c_uint = 2; +pub const VMADDR_PORT_ANY: c_uint = 0xFFFFFFFF; + +// uapi/linux/inotify.h +pub const IN_ACCESS: u32 = 0x0000_0001; +pub const IN_MODIFY: u32 = 0x0000_0002; +pub const IN_ATTRIB: u32 = 0x0000_0004; +pub const IN_CLOSE_WRITE: u32 = 0x0000_0008; +pub const IN_CLOSE_NOWRITE: u32 = 0x0000_0010; +pub const IN_CLOSE: u32 = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE; +pub const IN_OPEN: u32 = 0x0000_0020; +pub const IN_MOVED_FROM: u32 = 0x0000_0040; +pub const IN_MOVED_TO: u32 = 0x0000_0080; +pub const IN_MOVE: u32 = IN_MOVED_FROM | IN_MOVED_TO; +pub const IN_CREATE: u32 = 0x0000_0100; +pub const IN_DELETE: u32 = 0x0000_0200; +pub const IN_DELETE_SELF: u32 = 0x0000_0400; +pub const IN_MOVE_SELF: u32 = 0x0000_0800; +pub const IN_UNMOUNT: u32 = 0x0000_2000; +pub const IN_Q_OVERFLOW: u32 = 0x0000_4000; +pub const IN_IGNORED: u32 = 0x0000_8000; +pub const IN_ONLYDIR: u32 = 0x0100_0000; +pub const IN_DONT_FOLLOW: u32 = 0x0200_0000; +pub const IN_EXCL_UNLINK: u32 = 0x0400_0000; + +// uapi/linux/securebits.h +const SECURE_NOROOT: c_int = 0; +const SECURE_NOROOT_LOCKED: c_int = 1; + +pub const SECBIT_NOROOT: c_int = issecure_mask(SECURE_NOROOT); +pub const SECBIT_NOROOT_LOCKED: c_int = issecure_mask(SECURE_NOROOT_LOCKED); + +const SECURE_NO_SETUID_FIXUP: c_int = 2; +const SECURE_NO_SETUID_FIXUP_LOCKED: c_int = 3; + +pub const SECBIT_NO_SETUID_FIXUP: c_int = issecure_mask(SECURE_NO_SETUID_FIXUP); +pub const SECBIT_NO_SETUID_FIXUP_LOCKED: c_int = issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED); + +const SECURE_KEEP_CAPS: c_int = 4; +const SECURE_KEEP_CAPS_LOCKED: c_int = 5; + +pub const SECBIT_KEEP_CAPS: c_int = issecure_mask(SECURE_KEEP_CAPS); +pub const SECBIT_KEEP_CAPS_LOCKED: c_int = issecure_mask(SECURE_KEEP_CAPS_LOCKED); + +const SECURE_NO_CAP_AMBIENT_RAISE: c_int = 6; +const SECURE_NO_CAP_AMBIENT_RAISE_LOCKED: c_int = 7; + +pub const SECBIT_NO_CAP_AMBIENT_RAISE: c_int = issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE); +pub const SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED: c_int = + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED); + +const SECURE_EXEC_RESTRICT_FILE: c_int = 8; +const SECURE_EXEC_RESTRICT_FILE_LOCKED: c_int = 9; + +pub const SECBIT_EXEC_RESTRICT_FILE: c_int = issecure_mask(SECURE_EXEC_RESTRICT_FILE); +pub const SECBIT_EXEC_RESTRICT_FILE_LOCKED: c_int = issecure_mask(SECURE_EXEC_RESTRICT_FILE_LOCKED); + +const SECURE_EXEC_DENY_INTERACTIVE: c_int = 10; +const SECURE_EXEC_DENY_INTERACTIVE_LOCKED: c_int = 11; + +pub const SECBIT_EXEC_DENY_INTERACTIVE: c_int = issecure_mask(SECURE_EXEC_DENY_INTERACTIVE); +pub const SECBIT_EXEC_DENY_INTERACTIVE_LOCKED: c_int = + issecure_mask(SECURE_EXEC_DENY_INTERACTIVE_LOCKED); + +pub const SECUREBITS_DEFAULT: c_int = 0x00000000; +pub const SECURE_ALL_BITS: c_int = SECBIT_NOROOT + | SECBIT_NO_SETUID_FIXUP + | SECBIT_KEEP_CAPS + | SECBIT_NO_CAP_AMBIENT_RAISE + | SECBIT_EXEC_RESTRICT_FILE + | SECBIT_EXEC_DENY_INTERACTIVE; +pub const SECURE_ALL_LOCKS: c_int = SECURE_ALL_BITS << 1; + +pub const SECURE_ALL_UNPRIVILEGED: c_int = + issecure_mask(SECURE_EXEC_RESTRICT_FILE) | issecure_mask(SECURE_EXEC_DENY_INTERACTIVE); + +const fn issecure_mask(x: c_int) -> c_int { + 1 << x +} + +pub const IN_MASK_CREATE: u32 = 0x1000_0000; +pub const IN_MASK_ADD: u32 = 0x2000_0000; +pub const IN_ISDIR: u32 = 0x4000_0000; +pub const IN_ONESHOT: u32 = 0x8000_0000; + +pub const IN_ALL_EVENTS: u32 = IN_ACCESS + | IN_MODIFY + | IN_ATTRIB + | IN_CLOSE_WRITE + | IN_CLOSE_NOWRITE + | IN_OPEN + | IN_MOVED_FROM + | IN_MOVED_TO + | IN_DELETE + | IN_CREATE + | IN_DELETE_SELF + | IN_MOVE_SELF; + +pub const IN_CLOEXEC: c_int = O_CLOEXEC; +pub const IN_NONBLOCK: c_int = O_NONBLOCK; + +// uapi/linux/mount.h +pub const OPEN_TREE_CLONE: c_uint = 0x01; +pub const OPEN_TREE_CLOEXEC: c_uint = O_CLOEXEC as c_uint; + +// uapi/linux/netfilter/nf_tables.h +pub const NFT_TABLE_MAXNAMELEN: c_int = 256; +pub const NFT_CHAIN_MAXNAMELEN: c_int = 256; +pub const NFT_SET_MAXNAMELEN: c_int = 256; +pub const NFT_OBJ_MAXNAMELEN: c_int = 256; +pub const NFT_USERDATA_MAXLEN: c_int = 256; + +pub const NFT_REG_VERDICT: c_int = 0; +pub const NFT_REG_1: c_int = 1; +pub const NFT_REG_2: c_int = 2; +pub const NFT_REG_3: c_int = 3; +pub const NFT_REG_4: c_int = 4; +pub const __NFT_REG_MAX: c_int = 5; +pub const NFT_REG32_00: c_int = 8; +pub const NFT_REG32_01: c_int = 9; +pub const NFT_REG32_02: c_int = 10; +pub const NFT_REG32_03: c_int = 11; +pub const NFT_REG32_04: c_int = 12; +pub const NFT_REG32_05: c_int = 13; +pub const NFT_REG32_06: c_int = 14; +pub const NFT_REG32_07: c_int = 15; +pub const NFT_REG32_08: c_int = 16; +pub const NFT_REG32_09: c_int = 17; +pub const NFT_REG32_10: c_int = 18; +pub const NFT_REG32_11: c_int = 19; +pub const NFT_REG32_12: c_int = 20; +pub const NFT_REG32_13: c_int = 21; +pub const NFT_REG32_14: c_int = 22; +pub const NFT_REG32_15: c_int = 23; + +pub const NFT_REG_SIZE: c_int = 16; +pub const NFT_REG32_SIZE: c_int = 4; + +pub const NFT_CONTINUE: c_int = -1; +pub const NFT_BREAK: c_int = -2; +pub const NFT_JUMP: c_int = -3; +pub const NFT_GOTO: c_int = -4; +pub const NFT_RETURN: c_int = -5; + +pub const NFT_MSG_NEWTABLE: c_int = 0; +pub const NFT_MSG_GETTABLE: c_int = 1; +pub const NFT_MSG_DELTABLE: c_int = 2; +pub const NFT_MSG_NEWCHAIN: c_int = 3; +pub const NFT_MSG_GETCHAIN: c_int = 4; +pub const NFT_MSG_DELCHAIN: c_int = 5; +pub const NFT_MSG_NEWRULE: c_int = 6; +pub const NFT_MSG_GETRULE: c_int = 7; +pub const NFT_MSG_DELRULE: c_int = 8; +pub const NFT_MSG_NEWSET: c_int = 9; +pub const NFT_MSG_GETSET: c_int = 10; +pub const NFT_MSG_DELSET: c_int = 11; +pub const NFT_MSG_NEWSETELEM: c_int = 12; +pub const NFT_MSG_GETSETELEM: c_int = 13; +pub const NFT_MSG_DELSETELEM: c_int = 14; +pub const NFT_MSG_NEWGEN: c_int = 15; +pub const NFT_MSG_GETGEN: c_int = 16; +pub const NFT_MSG_TRACE: c_int = 17; +cfg_if! { + if #[cfg(not(target_arch = "sparc64"))] { + pub const NFT_MSG_NEWOBJ: c_int = 18; + pub const NFT_MSG_GETOBJ: c_int = 19; + pub const NFT_MSG_DELOBJ: c_int = 20; + pub const NFT_MSG_GETOBJ_RESET: c_int = 21; + } +} + +pub const NFT_MSG_MAX: c_int = 34; + +pub const NFT_SET_ANONYMOUS: c_int = 0x1; +pub const NFT_SET_CONSTANT: c_int = 0x2; +pub const NFT_SET_INTERVAL: c_int = 0x4; +pub const NFT_SET_MAP: c_int = 0x8; +pub const NFT_SET_TIMEOUT: c_int = 0x10; +pub const NFT_SET_EVAL: c_int = 0x20; + +pub const NFT_SET_POL_PERFORMANCE: c_int = 0; +pub const NFT_SET_POL_MEMORY: c_int = 1; + +pub const NFT_SET_ELEM_INTERVAL_END: c_int = 0x1; + +pub const NFT_DATA_VALUE: c_uint = 0; +pub const NFT_DATA_VERDICT: c_uint = 0xffffff00; + +pub const NFT_DATA_RESERVED_MASK: c_uint = 0xffffff00; + +pub const NFT_DATA_VALUE_MAXLEN: c_int = 64; + +pub const NFT_BYTEORDER_NTOH: c_int = 0; +pub const NFT_BYTEORDER_HTON: c_int = 1; + +pub const NFT_CMP_EQ: c_int = 0; +pub const NFT_CMP_NEQ: c_int = 1; +pub const NFT_CMP_LT: c_int = 2; +pub const NFT_CMP_LTE: c_int = 3; +pub const NFT_CMP_GT: c_int = 4; +pub const NFT_CMP_GTE: c_int = 5; + +pub const NFT_RANGE_EQ: c_int = 0; +pub const NFT_RANGE_NEQ: c_int = 1; + +pub const NFT_LOOKUP_F_INV: c_int = 1 << 0; + +pub const NFT_DYNSET_OP_ADD: c_int = 0; +pub const NFT_DYNSET_OP_UPDATE: c_int = 1; + +pub const NFT_DYNSET_F_INV: c_int = 1 << 0; + +pub const NFT_PAYLOAD_LL_HEADER: c_int = 0; +pub const NFT_PAYLOAD_NETWORK_HEADER: c_int = 1; +pub const NFT_PAYLOAD_TRANSPORT_HEADER: c_int = 2; + +pub const NFT_PAYLOAD_CSUM_NONE: c_int = 0; +pub const NFT_PAYLOAD_CSUM_INET: c_int = 1; + +pub const NFT_META_LEN: c_int = 0; +pub const NFT_META_PROTOCOL: c_int = 1; +pub const NFT_META_PRIORITY: c_int = 2; +pub const NFT_META_MARK: c_int = 3; +pub const NFT_META_IIF: c_int = 4; +pub const NFT_META_OIF: c_int = 5; +pub const NFT_META_IIFNAME: c_int = 6; +pub const NFT_META_OIFNAME: c_int = 7; +pub const NFT_META_IIFTYPE: c_int = 8; +pub const NFT_META_OIFTYPE: c_int = 9; +pub const NFT_META_SKUID: c_int = 10; +pub const NFT_META_SKGID: c_int = 11; +pub const NFT_META_NFTRACE: c_int = 12; +pub const NFT_META_RTCLASSID: c_int = 13; +pub const NFT_META_SECMARK: c_int = 14; +pub const NFT_META_NFPROTO: c_int = 15; +pub const NFT_META_L4PROTO: c_int = 16; +pub const NFT_META_BRI_IIFNAME: c_int = 17; +pub const NFT_META_BRI_OIFNAME: c_int = 18; +pub const NFT_META_PKTTYPE: c_int = 19; +pub const NFT_META_CPU: c_int = 20; +pub const NFT_META_IIFGROUP: c_int = 21; +pub const NFT_META_OIFGROUP: c_int = 22; +pub const NFT_META_CGROUP: c_int = 23; +pub const NFT_META_PRANDOM: c_int = 24; + +pub const NFT_CT_STATE: c_int = 0; +pub const NFT_CT_DIRECTION: c_int = 1; +pub const NFT_CT_STATUS: c_int = 2; +pub const NFT_CT_MARK: c_int = 3; +pub const NFT_CT_SECMARK: c_int = 4; +pub const NFT_CT_EXPIRATION: c_int = 5; +pub const NFT_CT_HELPER: c_int = 6; +pub const NFT_CT_L3PROTOCOL: c_int = 7; +pub const NFT_CT_SRC: c_int = 8; +pub const NFT_CT_DST: c_int = 9; +pub const NFT_CT_PROTOCOL: c_int = 10; +pub const NFT_CT_PROTO_SRC: c_int = 11; +pub const NFT_CT_PROTO_DST: c_int = 12; +pub const NFT_CT_LABELS: c_int = 13; +pub const NFT_CT_PKTS: c_int = 14; +pub const NFT_CT_BYTES: c_int = 15; +pub const NFT_CT_AVGPKT: c_int = 16; +pub const NFT_CT_ZONE: c_int = 17; +pub const NFT_CT_EVENTMASK: c_int = 18; +pub const NFT_CT_SRC_IP: c_int = 19; +pub const NFT_CT_DST_IP: c_int = 20; +pub const NFT_CT_SRC_IP6: c_int = 21; +pub const NFT_CT_DST_IP6: c_int = 22; + +pub const NFT_LIMIT_PKTS: c_int = 0; +pub const NFT_LIMIT_PKT_BYTES: c_int = 1; + +pub const NFT_LIMIT_F_INV: c_int = 1 << 0; + +pub const NFT_QUEUE_FLAG_BYPASS: c_int = 0x01; +pub const NFT_QUEUE_FLAG_CPU_FANOUT: c_int = 0x02; +pub const NFT_QUEUE_FLAG_MASK: c_int = 0x03; + +pub const NFT_QUOTA_F_INV: c_int = 1 << 0; + +pub const NFT_REJECT_ICMP_UNREACH: c_int = 0; +pub const NFT_REJECT_TCP_RST: c_int = 1; +pub const NFT_REJECT_ICMPX_UNREACH: c_int = 2; + +pub const NFT_REJECT_ICMPX_NO_ROUTE: c_int = 0; +pub const NFT_REJECT_ICMPX_PORT_UNREACH: c_int = 1; +pub const NFT_REJECT_ICMPX_HOST_UNREACH: c_int = 2; +pub const NFT_REJECT_ICMPX_ADMIN_PROHIBITED: c_int = 3; + +pub const NFT_NAT_SNAT: c_int = 0; +pub const NFT_NAT_DNAT: c_int = 1; + +pub const NFT_TRACETYPE_UNSPEC: c_int = 0; +pub const NFT_TRACETYPE_POLICY: c_int = 1; +pub const NFT_TRACETYPE_RETURN: c_int = 2; +pub const NFT_TRACETYPE_RULE: c_int = 3; + +pub const NFT_NG_INCREMENTAL: c_int = 0; +pub const NFT_NG_RANDOM: c_int = 1; + +// linux/input.h +pub const FF_MAX: __u16 = 0x7f; +pub const FF_CNT: usize = FF_MAX as usize + 1; + +// linux/input-event-codes.h +pub const INPUT_PROP_POINTER: __u16 = 0x00; +pub const INPUT_PROP_DIRECT: __u16 = 0x01; +pub const INPUT_PROP_BUTTONPAD: __u16 = 0x02; +pub const INPUT_PROP_SEMI_MT: __u16 = 0x03; +pub const INPUT_PROP_TOPBUTTONPAD: __u16 = 0x04; +pub const INPUT_PROP_POINTING_STICK: __u16 = 0x05; +pub const INPUT_PROP_ACCELEROMETER: __u16 = 0x06; +pub const INPUT_PROP_MAX: __u16 = 0x1f; +pub const INPUT_PROP_CNT: usize = INPUT_PROP_MAX as usize + 1; +pub const EV_MAX: __u16 = 0x1f; +pub const EV_CNT: usize = EV_MAX as usize + 1; +pub const SYN_MAX: __u16 = 0xf; +pub const SYN_CNT: usize = SYN_MAX as usize + 1; +pub const KEY_MAX: __u16 = 0x2ff; +pub const KEY_CNT: usize = KEY_MAX as usize + 1; +pub const REL_MAX: __u16 = 0x0f; +pub const REL_CNT: usize = REL_MAX as usize + 1; +pub const ABS_MAX: __u16 = 0x3f; +pub const ABS_CNT: usize = ABS_MAX as usize + 1; +pub const SW_MAX: __u16 = 0x10; +pub const SW_CNT: usize = SW_MAX as usize + 1; +pub const MSC_MAX: __u16 = 0x07; +pub const MSC_CNT: usize = MSC_MAX as usize + 1; +pub const LED_MAX: __u16 = 0x0f; +pub const LED_CNT: usize = LED_MAX as usize + 1; +pub const REP_MAX: __u16 = 0x01; +pub const REP_CNT: usize = REP_MAX as usize + 1; +pub const SND_MAX: __u16 = 0x07; +pub const SND_CNT: usize = SND_MAX as usize + 1; + +// linux/uinput.h +pub const UINPUT_VERSION: c_uint = 5; +pub const UINPUT_MAX_NAME_SIZE: usize = 80; + +// uapi/linux/fanotify.h +pub const FAN_ACCESS: u64 = 0x0000_0001; +pub const FAN_MODIFY: u64 = 0x0000_0002; +pub const FAN_ATTRIB: u64 = 0x0000_0004; +pub const FAN_CLOSE_WRITE: u64 = 0x0000_0008; +pub const FAN_CLOSE_NOWRITE: u64 = 0x0000_0010; +pub const FAN_OPEN: u64 = 0x0000_0020; +pub const FAN_MOVED_FROM: u64 = 0x0000_0040; +pub const FAN_MOVED_TO: u64 = 0x0000_0080; +pub const FAN_CREATE: u64 = 0x0000_0100; +pub const FAN_DELETE: u64 = 0x0000_0200; +pub const FAN_DELETE_SELF: u64 = 0x0000_0400; +pub const FAN_MOVE_SELF: u64 = 0x0000_0800; +pub const FAN_OPEN_EXEC: u64 = 0x0000_1000; + +pub const FAN_Q_OVERFLOW: u64 = 0x0000_4000; +pub const FAN_FS_ERROR: u64 = 0x0000_8000; + +pub const FAN_OPEN_PERM: u64 = 0x0001_0000; +pub const FAN_ACCESS_PERM: u64 = 0x0002_0000; +pub const FAN_OPEN_EXEC_PERM: u64 = 0x0004_0000; + +pub const FAN_EVENT_ON_CHILD: u64 = 0x0800_0000; + +pub const FAN_RENAME: u64 = 0x1000_0000; + +pub const FAN_ONDIR: u64 = 0x4000_0000; + +pub const FAN_CLOSE: u64 = FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE; +pub const FAN_MOVE: u64 = FAN_MOVED_FROM | FAN_MOVED_TO; + +pub const FAN_CLOEXEC: c_uint = 0x0000_0001; +pub const FAN_NONBLOCK: c_uint = 0x0000_0002; + +pub const FAN_CLASS_NOTIF: c_uint = 0x0000_0000; +pub const FAN_CLASS_CONTENT: c_uint = 0x0000_0004; +pub const FAN_CLASS_PRE_CONTENT: c_uint = 0x0000_0008; + +pub const FAN_UNLIMITED_QUEUE: c_uint = 0x0000_0010; +pub const FAN_UNLIMITED_MARKS: c_uint = 0x0000_0020; +pub const FAN_ENABLE_AUDIT: c_uint = 0x0000_0040; + +pub const FAN_REPORT_PIDFD: c_uint = 0x0000_0080; +pub const FAN_REPORT_TID: c_uint = 0x0000_0100; +pub const FAN_REPORT_FID: c_uint = 0x0000_0200; +pub const FAN_REPORT_DIR_FID: c_uint = 0x0000_0400; +pub const FAN_REPORT_NAME: c_uint = 0x0000_0800; +pub const FAN_REPORT_TARGET_FID: c_uint = 0x0000_1000; + +pub const FAN_REPORT_DFID_NAME: c_uint = FAN_REPORT_DIR_FID | FAN_REPORT_NAME; +pub const FAN_REPORT_DFID_NAME_TARGET: c_uint = + FAN_REPORT_DFID_NAME | FAN_REPORT_FID | FAN_REPORT_TARGET_FID; + +pub const FAN_MARK_ADD: c_uint = 0x0000_0001; +pub const FAN_MARK_REMOVE: c_uint = 0x0000_0002; +pub const FAN_MARK_DONT_FOLLOW: c_uint = 0x0000_0004; +pub const FAN_MARK_ONLYDIR: c_uint = 0x0000_0008; +pub const FAN_MARK_IGNORED_MASK: c_uint = 0x0000_0020; +pub const FAN_MARK_IGNORED_SURV_MODIFY: c_uint = 0x0000_0040; +pub const FAN_MARK_FLUSH: c_uint = 0x0000_0080; +pub const FAN_MARK_EVICTABLE: c_uint = 0x0000_0200; +pub const FAN_MARK_IGNORE: c_uint = 0x0000_0400; + +pub const FAN_MARK_INODE: c_uint = 0x0000_0000; +pub const FAN_MARK_MOUNT: c_uint = 0x0000_0010; +pub const FAN_MARK_FILESYSTEM: c_uint = 0x0000_0100; + +pub const FAN_MARK_IGNORE_SURV: c_uint = FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY; + +pub const FANOTIFY_METADATA_VERSION: u8 = 3; + +pub const FAN_EVENT_INFO_TYPE_FID: u8 = 1; +pub const FAN_EVENT_INFO_TYPE_DFID_NAME: u8 = 2; +pub const FAN_EVENT_INFO_TYPE_DFID: u8 = 3; +pub const FAN_EVENT_INFO_TYPE_PIDFD: u8 = 4; +pub const FAN_EVENT_INFO_TYPE_ERROR: u8 = 5; + +pub const FAN_EVENT_INFO_TYPE_OLD_DFID_NAME: u8 = 10; +pub const FAN_EVENT_INFO_TYPE_NEW_DFID_NAME: u8 = 12; + +pub const FAN_RESPONSE_INFO_NONE: u8 = 0; +pub const FAN_RESPONSE_INFO_AUDIT_RULE: u8 = 1; + +pub const FAN_ALLOW: u32 = 0x01; +pub const FAN_DENY: u32 = 0x02; +pub const FAN_AUDIT: u32 = 0x10; +pub const FAN_INFO: u32 = 0x20; + +pub const FAN_NOFD: c_int = -1; +pub const FAN_NOPIDFD: c_int = FAN_NOFD; +pub const FAN_EPIDFD: c_int = -2; + +// linux/futex.h +pub const FUTEX_WAIT: c_int = 0; +pub const FUTEX_WAKE: c_int = 1; +pub const FUTEX_FD: c_int = 2; +pub const FUTEX_REQUEUE: c_int = 3; +pub const FUTEX_CMP_REQUEUE: c_int = 4; +pub const FUTEX_WAKE_OP: c_int = 5; +pub const FUTEX_LOCK_PI: c_int = 6; +pub const FUTEX_UNLOCK_PI: c_int = 7; +pub const FUTEX_TRYLOCK_PI: c_int = 8; +pub const FUTEX_WAIT_BITSET: c_int = 9; +pub const FUTEX_WAKE_BITSET: c_int = 10; +pub const FUTEX_WAIT_REQUEUE_PI: c_int = 11; +pub const FUTEX_CMP_REQUEUE_PI: c_int = 12; +pub const FUTEX_LOCK_PI2: c_int = 13; + +pub const FUTEX_PRIVATE_FLAG: c_int = 128; +pub const FUTEX_CLOCK_REALTIME: c_int = 256; +pub const FUTEX_CMD_MASK: c_int = !(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); + +pub const FUTEX_WAITERS: u32 = 0x80000000; +pub const FUTEX_OWNER_DIED: u32 = 0x40000000; +pub const FUTEX_TID_MASK: u32 = 0x3fffffff; + +pub const FUTEX_BITSET_MATCH_ANY: c_int = 0xffffffff; + +pub const FUTEX_OP_SET: c_int = 0; +pub const FUTEX_OP_ADD: c_int = 1; +pub const FUTEX_OP_OR: c_int = 2; +pub const FUTEX_OP_ANDN: c_int = 3; +pub const FUTEX_OP_XOR: c_int = 4; + +pub const FUTEX_OP_OPARG_SHIFT: c_int = 8; + +pub const FUTEX_OP_CMP_EQ: c_int = 0; +pub const FUTEX_OP_CMP_NE: c_int = 1; +pub const FUTEX_OP_CMP_LT: c_int = 2; +pub const FUTEX_OP_CMP_LE: c_int = 3; +pub const FUTEX_OP_CMP_GT: c_int = 4; +pub const FUTEX_OP_CMP_GE: c_int = 5; + +pub fn FUTEX_OP(op: c_int, oparg: c_int, cmp: c_int, cmparg: c_int) -> c_int { + ((op & 0xf) << 28) | ((cmp & 0xf) << 24) | ((oparg & 0xfff) << 12) | (cmparg & 0xfff) +} + +// linux/kexec.h +pub const KEXEC_ON_CRASH: c_int = 0x00000001; +pub const KEXEC_PRESERVE_CONTEXT: c_int = 0x00000002; +pub const KEXEC_ARCH_MASK: c_int = 0xffff0000; +pub const KEXEC_FILE_UNLOAD: c_int = 0x00000001; +pub const KEXEC_FILE_ON_CRASH: c_int = 0x00000002; +pub const KEXEC_FILE_NO_INITRAMFS: c_int = 0x00000004; + +// linux/reboot.h +pub const LINUX_REBOOT_MAGIC1: c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: c_int = 0x45584543; + +// linux/errqueue.h +pub const SO_EE_ORIGIN_NONE: u8 = 0; +pub const SO_EE_ORIGIN_LOCAL: u8 = 1; +pub const SO_EE_ORIGIN_ICMP: u8 = 2; +pub const SO_EE_ORIGIN_ICMP6: u8 = 3; +pub const SO_EE_ORIGIN_TXSTATUS: u8 = 4; +pub const SO_EE_ORIGIN_TIMESTAMPING: u8 = SO_EE_ORIGIN_TXSTATUS; + +// linux/sctp.h +pub const SCTP_FUTURE_ASSOC: c_int = 0; +pub const SCTP_CURRENT_ASSOC: c_int = 1; +pub const SCTP_ALL_ASSOC: c_int = 2; +pub const SCTP_RTOINFO: c_int = 0; +pub const SCTP_ASSOCINFO: c_int = 1; +pub const SCTP_INITMSG: c_int = 2; +pub const SCTP_NODELAY: c_int = 3; +pub const SCTP_AUTOCLOSE: c_int = 4; +pub const SCTP_SET_PEER_PRIMARY_ADDR: c_int = 5; +pub const SCTP_PRIMARY_ADDR: c_int = 6; +pub const SCTP_ADAPTATION_LAYER: c_int = 7; +pub const SCTP_DISABLE_FRAGMENTS: c_int = 8; +pub const SCTP_PEER_ADDR_PARAMS: c_int = 9; +pub const SCTP_DEFAULT_SEND_PARAM: c_int = 10; +pub const SCTP_EVENTS: c_int = 11; +pub const SCTP_I_WANT_MAPPED_V4_ADDR: c_int = 12; +pub const SCTP_MAXSEG: c_int = 13; +pub const SCTP_STATUS: c_int = 14; +pub const SCTP_GET_PEER_ADDR_INFO: c_int = 15; +pub const SCTP_DELAYED_ACK_TIME: c_int = 16; +pub const SCTP_DELAYED_ACK: c_int = SCTP_DELAYED_ACK_TIME; +pub const SCTP_DELAYED_SACK: c_int = SCTP_DELAYED_ACK_TIME; +pub const SCTP_CONTEXT: c_int = 17; +pub const SCTP_FRAGMENT_INTERLEAVE: c_int = 18; +pub const SCTP_PARTIAL_DELIVERY_POINT: c_int = 19; +pub const SCTP_MAX_BURST: c_int = 20; +pub const SCTP_AUTH_CHUNK: c_int = 21; +pub const SCTP_HMAC_IDENT: c_int = 22; +pub const SCTP_AUTH_KEY: c_int = 23; +pub const SCTP_AUTH_ACTIVE_KEY: c_int = 24; +pub const SCTP_AUTH_DELETE_KEY: c_int = 25; +pub const SCTP_PEER_AUTH_CHUNKS: c_int = 26; +pub const SCTP_LOCAL_AUTH_CHUNKS: c_int = 27; +pub const SCTP_GET_ASSOC_NUMBER: c_int = 28; +pub const SCTP_GET_ASSOC_ID_LIST: c_int = 29; +pub const SCTP_AUTO_ASCONF: c_int = 30; +pub const SCTP_PEER_ADDR_THLDS: c_int = 31; +pub const SCTP_RECVRCVINFO: c_int = 32; +pub const SCTP_RECVNXTINFO: c_int = 33; +pub const SCTP_DEFAULT_SNDINFO: c_int = 34; +pub const SCTP_AUTH_DEACTIVATE_KEY: c_int = 35; +pub const SCTP_REUSE_PORT: c_int = 36; +pub const SCTP_PEER_ADDR_THLDS_V2: c_int = 37; +pub const SCTP_PR_SCTP_NONE: c_int = 0x0000; +pub const SCTP_PR_SCTP_TTL: c_int = 0x0010; +pub const SCTP_PR_SCTP_RTX: c_int = 0x0020; +pub const SCTP_PR_SCTP_PRIO: c_int = 0x0030; +pub const SCTP_PR_SCTP_MAX: c_int = SCTP_PR_SCTP_PRIO; +pub const SCTP_PR_SCTP_MASK: c_int = 0x0030; +pub const SCTP_ENABLE_RESET_STREAM_REQ: c_int = 0x01; +pub const SCTP_ENABLE_RESET_ASSOC_REQ: c_int = 0x02; +pub const SCTP_ENABLE_CHANGE_ASSOC_REQ: c_int = 0x04; +pub const SCTP_ENABLE_STRRESET_MASK: c_int = 0x07; +pub const SCTP_STREAM_RESET_INCOMING: c_int = 0x01; +pub const SCTP_STREAM_RESET_OUTGOING: c_int = 0x02; + +pub const SCTP_INIT: c_int = 0; +pub const SCTP_SNDRCV: c_int = 1; +pub const SCTP_SNDINFO: c_int = 2; +pub const SCTP_RCVINFO: c_int = 3; +pub const SCTP_NXTINFO: c_int = 4; +pub const SCTP_PRINFO: c_int = 5; +pub const SCTP_AUTHINFO: c_int = 6; +pub const SCTP_DSTADDRV4: c_int = 7; +pub const SCTP_DSTADDRV6: c_int = 8; + +pub const SCTP_UNORDERED: c_int = 1 << 0; +pub const SCTP_ADDR_OVER: c_int = 1 << 1; +pub const SCTP_ABORT: c_int = 1 << 2; +pub const SCTP_SACK_IMMEDIATELY: c_int = 1 << 3; +pub const SCTP_SENDALL: c_int = 1 << 6; +pub const SCTP_PR_SCTP_ALL: c_int = 1 << 7; +pub const SCTP_NOTIFICATION: c_int = MSG_NOTIFICATION; +pub const SCTP_EOF: c_int = crate::MSG_FIN; + +/* DCCP socket options */ +pub const DCCP_SOCKOPT_PACKET_SIZE: c_int = 1; +pub const DCCP_SOCKOPT_SERVICE: c_int = 2; +pub const DCCP_SOCKOPT_CHANGE_L: c_int = 3; +pub const DCCP_SOCKOPT_CHANGE_R: c_int = 4; +pub const DCCP_SOCKOPT_GET_CUR_MPS: c_int = 5; +pub const DCCP_SOCKOPT_SERVER_TIMEWAIT: c_int = 6; +pub const DCCP_SOCKOPT_SEND_CSCOV: c_int = 10; +pub const DCCP_SOCKOPT_RECV_CSCOV: c_int = 11; +pub const DCCP_SOCKOPT_AVAILABLE_CCIDS: c_int = 12; +pub const DCCP_SOCKOPT_CCID: c_int = 13; +pub const DCCP_SOCKOPT_TX_CCID: c_int = 14; +pub const DCCP_SOCKOPT_RX_CCID: c_int = 15; +pub const DCCP_SOCKOPT_QPOLICY_ID: c_int = 16; +pub const DCCP_SOCKOPT_QPOLICY_TXQLEN: c_int = 17; +pub const DCCP_SOCKOPT_CCID_RX_INFO: c_int = 128; +pub const DCCP_SOCKOPT_CCID_TX_INFO: c_int = 192; + +/// maximum number of services provided on the same listening port +pub const DCCP_SERVICE_LIST_MAX_LEN: c_int = 32; + +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_NET: c_int = 3; +pub const CTL_FS: c_int = 5; +pub const CTL_DEBUG: c_int = 6; +pub const CTL_DEV: c_int = 7; +pub const CTL_BUS: c_int = 8; +pub const CTL_ABI: c_int = 9; +pub const CTL_CPU: c_int = 10; + +pub const CTL_BUS_ISA: c_int = 1; + +pub const INOTIFY_MAX_USER_INSTANCES: c_int = 1; +pub const INOTIFY_MAX_USER_WATCHES: c_int = 2; +pub const INOTIFY_MAX_QUEUED_EVENTS: c_int = 3; + +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_VERSION: c_int = 4; +pub const KERN_SECUREMASK: c_int = 5; +pub const KERN_PROF: c_int = 6; +pub const KERN_NODENAME: c_int = 7; +pub const KERN_DOMAINNAME: c_int = 8; +pub const KERN_PANIC: c_int = 15; +pub const KERN_REALROOTDEV: c_int = 16; +pub const KERN_SPARC_REBOOT: c_int = 21; +pub const KERN_CTLALTDEL: c_int = 22; +pub const KERN_PRINTK: c_int = 23; +pub const KERN_NAMETRANS: c_int = 24; +pub const KERN_PPC_HTABRECLAIM: c_int = 25; +pub const KERN_PPC_ZEROPAGED: c_int = 26; +pub const KERN_PPC_POWERSAVE_NAP: c_int = 27; +pub const KERN_MODPROBE: c_int = 28; +pub const KERN_SG_BIG_BUFF: c_int = 29; +pub const KERN_ACCT: c_int = 30; +pub const KERN_PPC_L2CR: c_int = 31; +pub const KERN_RTSIGNR: c_int = 32; +pub const KERN_RTSIGMAX: c_int = 33; +pub const KERN_SHMMAX: c_int = 34; +pub const KERN_MSGMAX: c_int = 35; +pub const KERN_MSGMNB: c_int = 36; +pub const KERN_MSGPOOL: c_int = 37; +pub const KERN_SYSRQ: c_int = 38; +pub const KERN_MAX_THREADS: c_int = 39; +pub const KERN_RANDOM: c_int = 40; +pub const KERN_SHMALL: c_int = 41; +pub const KERN_MSGMNI: c_int = 42; +pub const KERN_SEM: c_int = 43; +pub const KERN_SPARC_STOP_A: c_int = 44; +pub const KERN_SHMMNI: c_int = 45; +pub const KERN_OVERFLOWUID: c_int = 46; +pub const KERN_OVERFLOWGID: c_int = 47; +pub const KERN_SHMPATH: c_int = 48; +pub const KERN_HOTPLUG: c_int = 49; +pub const KERN_IEEE_EMULATION_WARNINGS: c_int = 50; +pub const KERN_S390_USER_DEBUG_LOGGING: c_int = 51; +pub const KERN_CORE_USES_PID: c_int = 52; +pub const KERN_TAINTED: c_int = 53; +pub const KERN_CADPID: c_int = 54; +pub const KERN_PIDMAX: c_int = 55; +pub const KERN_CORE_PATTERN: c_int = 56; +pub const KERN_PANIC_ON_OOPS: c_int = 57; +pub const KERN_HPPA_PWRSW: c_int = 58; +pub const KERN_HPPA_UNALIGNED: c_int = 59; +pub const KERN_PRINTK_RATELIMIT: c_int = 60; +pub const KERN_PRINTK_RATELIMIT_BURST: c_int = 61; +pub const KERN_PTY: c_int = 62; +pub const KERN_NGROUPS_MAX: c_int = 63; +pub const KERN_SPARC_SCONS_PWROFF: c_int = 64; +pub const KERN_HZ_TIMER: c_int = 65; +pub const KERN_UNKNOWN_NMI_PANIC: c_int = 66; +pub const KERN_BOOTLOADER_TYPE: c_int = 67; +pub const KERN_RANDOMIZE: c_int = 68; +pub const KERN_SETUID_DUMPABLE: c_int = 69; +pub const KERN_SPIN_RETRY: c_int = 70; +pub const KERN_ACPI_VIDEO_FLAGS: c_int = 71; +pub const KERN_IA64_UNALIGNED: c_int = 72; +pub const KERN_COMPAT_LOG: c_int = 73; +pub const KERN_MAX_LOCK_DEPTH: c_int = 74; +pub const KERN_NMI_WATCHDOG: c_int = 75; +pub const KERN_PANIC_ON_NMI: c_int = 76; + +pub const VM_OVERCOMMIT_MEMORY: c_int = 5; +pub const VM_PAGE_CLUSTER: c_int = 10; +pub const VM_DIRTY_BACKGROUND: c_int = 11; +pub const VM_DIRTY_RATIO: c_int = 12; +pub const VM_DIRTY_WB_CS: c_int = 13; +pub const VM_DIRTY_EXPIRE_CS: c_int = 14; +pub const VM_NR_PDFLUSH_THREADS: c_int = 15; +pub const VM_OVERCOMMIT_RATIO: c_int = 16; +pub const VM_PAGEBUF: c_int = 17; +pub const VM_HUGETLB_PAGES: c_int = 18; +pub const VM_SWAPPINESS: c_int = 19; +pub const VM_LOWMEM_RESERVE_RATIO: c_int = 20; +pub const VM_MIN_FREE_KBYTES: c_int = 21; +pub const VM_MAX_MAP_COUNT: c_int = 22; +pub const VM_LAPTOP_MODE: c_int = 23; +pub const VM_BLOCK_DUMP: c_int = 24; +pub const VM_HUGETLB_GROUP: c_int = 25; +pub const VM_VFS_CACHE_PRESSURE: c_int = 26; +pub const VM_LEGACY_VA_LAYOUT: c_int = 27; +pub const VM_SWAP_TOKEN_TIMEOUT: c_int = 28; +pub const VM_DROP_PAGECACHE: c_int = 29; +pub const VM_PERCPU_PAGELIST_FRACTION: c_int = 30; +pub const VM_ZONE_RECLAIM_MODE: c_int = 31; +pub const VM_MIN_UNMAPPED: c_int = 32; +pub const VM_PANIC_ON_OOM: c_int = 33; +pub const VM_VDSO_ENABLED: c_int = 34; +pub const VM_MIN_SLAB: c_int = 35; + +pub const NET_CORE: c_int = 1; +pub const NET_ETHER: c_int = 2; +pub const NET_802: c_int = 3; +pub const NET_UNIX: c_int = 4; +pub const NET_IPV4: c_int = 5; +pub const NET_IPX: c_int = 6; +pub const NET_ATALK: c_int = 7; +pub const NET_NETROM: c_int = 8; +pub const NET_AX25: c_int = 9; +pub const NET_BRIDGE: c_int = 10; +pub const NET_ROSE: c_int = 11; +pub const NET_IPV6: c_int = 12; +pub const NET_X25: c_int = 13; +pub const NET_TR: c_int = 14; +pub const NET_DECNET: c_int = 15; +pub const NET_ECONET: c_int = 16; +pub const NET_SCTP: c_int = 17; +pub const NET_LLC: c_int = 18; +pub const NET_NETFILTER: c_int = 19; +pub const NET_DCCP: c_int = 20; +pub const NET_IRDA: c_int = 412; + +// include/linux/sched.h +/// I'm a virtual CPU. +pub const PF_VCPU: c_int = 0x00000001; +/// I am an IDLE thread. +pub const PF_IDLE: c_int = 0x00000002; +/// Getting shut down. +pub const PF_EXITING: c_int = 0x00000004; +/// Coredumps should ignore this task. +pub const PF_POSTCOREDUMP: c_int = 0x00000008; +/// Task is an IO worker. +pub const PF_IO_WORKER: c_int = 0x00000010; +/// I'm a workqueue worker. +pub const PF_WQ_WORKER: c_int = 0x00000020; +/// Forked but didn't exec. +pub const PF_FORKNOEXEC: c_int = 0x00000040; +/// Process policy on mce errors. +pub const PF_MCE_PROCESS: c_int = 0x00000080; +/// Used super-user privileges. +pub const PF_SUPERPRIV: c_int = 0x00000100; +/// Dumped core. +pub const PF_DUMPCORE: c_int = 0x00000200; +/// Killed by a signal. +pub const PF_SIGNALED: c_int = 0x00000400; +/// Allocating memory to free memory. +/// +/// See `memalloc_noreclaim_save()`. +pub const PF_MEMALLOC: c_int = 0x00000800; +/// `set_user()` noticed that `RLIMIT_NPROC` was exceeded. +pub const PF_NPROC_EXCEEDED: c_int = 0x00001000; +/// If unset the fpu must be initialized before use. +pub const PF_USED_MATH: c_int = 0x00002000; +/// Kernel thread cloned from userspace thread. +pub const PF_USER_WORKER: c_int = 0x00004000; +/// This thread should not be frozen. +pub const PF_NOFREEZE: c_int = 0x00008000; +/// I am `kswapd`. +pub const PF_KSWAPD: c_int = 0x00020000; +/// All allocations inherit `GFP_NOFS`. +/// +/// See `memalloc_nfs_save()`. +pub const PF_MEMALLOC_NOFS: c_int = 0x00040000; +/// All allocations inherit `GFP_NOIO`. +/// +/// See `memalloc_noio_save()`. +pub const PF_MEMALLOC_NOIO: c_int = 0x00080000; +/// Throttle writes only against the bdi I write to, I am cleaning +/// dirty pages from some other bdi. +pub const PF_LOCAL_THROTTLE: c_int = 0x00100000; +/// I am a kernel thread. +pub const PF_KTHREAD: c_int = 0x00200000; +/// Randomize virtual address space. +pub const PF_RANDOMIZE: c_int = 0x00400000; +/// Userland is not allowed to meddle with `cpus_mask`. +pub const PF_NO_SETAFFINITY: c_int = 0x04000000; +/// Early kill for mce process policy. +pub const PF_MCE_EARLY: c_int = 0x08000000; +/// Allocations constrained to zones which allow long term pinning. +/// +/// See `memalloc_pin_save()`. +pub const PF_MEMALLOC_PIN: c_int = 0x10000000; +/// Plug has ts that needs updating. +pub const PF_BLOCK_TS: c_int = 0x20000000; +/// This thread called `freeze_processes()` and should not be frozen. +pub const PF_SUSPEND_TASK: c_int = PF_SUSPEND_TASK_UINT as _; +// The used value is the highest possible bit fitting on 32 bits, so directly +// defining it as a signed integer causes the compiler to report an overflow. +// Use instead a private intermediary that assuringly has the correct type and +// cast it where necessary to the wanted final type, which preserves the +// desired information as-is in terms of integer representation. +const PF_SUSPEND_TASK_UINT: c_uint = 0x80000000; + +pub const CLONE_PIDFD: c_int = 0x1000; + +pub const SCHED_FLAG_RESET_ON_FORK: c_int = 0x01; +pub const SCHED_FLAG_RECLAIM: c_int = 0x02; +pub const SCHED_FLAG_DL_OVERRUN: c_int = 0x04; +pub const SCHED_FLAG_KEEP_POLICY: c_int = 0x08; +pub const SCHED_FLAG_KEEP_PARAMS: c_int = 0x10; +pub const SCHED_FLAG_UTIL_CLAMP_MIN: c_int = 0x20; +pub const SCHED_FLAG_UTIL_CLAMP_MAX: c_int = 0x40; + +// linux/if_xdp.h +pub const XDP_SHARED_UMEM: crate::__u16 = 1 << 0; +pub const XDP_COPY: crate::__u16 = 1 << 1; +pub const XDP_ZEROCOPY: crate::__u16 = 1 << 2; +pub const XDP_USE_NEED_WAKEUP: crate::__u16 = 1 << 3; +pub const XDP_USE_SG: crate::__u16 = 1 << 4; + +pub const XDP_UMEM_UNALIGNED_CHUNK_FLAG: crate::__u32 = 1 << 0; + +pub const XDP_RING_NEED_WAKEUP: crate::__u32 = 1 << 0; + +pub const XDP_MMAP_OFFSETS: c_int = 1; +pub const XDP_RX_RING: c_int = 2; +pub const XDP_TX_RING: c_int = 3; +pub const XDP_UMEM_REG: c_int = 4; +pub const XDP_UMEM_FILL_RING: c_int = 5; +pub const XDP_UMEM_COMPLETION_RING: c_int = 6; +pub const XDP_STATISTICS: c_int = 7; +pub const XDP_OPTIONS: c_int = 8; + +pub const XDP_OPTIONS_ZEROCOPY: crate::__u32 = 1 << 0; + +pub const XDP_PGOFF_RX_RING: crate::off_t = 0; +pub const XDP_PGOFF_TX_RING: crate::off_t = 0x80000000; +pub const XDP_UMEM_PGOFF_FILL_RING: crate::c_ulonglong = 0x100000000; +pub const XDP_UMEM_PGOFF_COMPLETION_RING: crate::c_ulonglong = 0x180000000; + +pub const XSK_UNALIGNED_BUF_OFFSET_SHIFT: crate::c_int = 48; +pub const XSK_UNALIGNED_BUF_ADDR_MASK: crate::c_ulonglong = + (1 << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1; + +pub const XDP_PKT_CONTD: crate::__u32 = 1 << 0; + +pub const XDP_UMEM_TX_SW_CSUM: crate::__u32 = 1 << 1; +pub const XDP_UMEM_TX_METADATA_LEN: crate::__u32 = 1 << 2; + +pub const XDP_TXMD_FLAGS_TIMESTAMP: crate::__u32 = 1 << 0; +pub const XDP_TXMD_FLAGS_CHECKSUM: crate::__u32 = 1 << 1; + +pub const XDP_TX_METADATA: crate::__u32 = 1 << 1; + +pub const SOL_XDP: c_int = 283; + +// linux/mount.h +pub const MOUNT_ATTR_RDONLY: crate::__u64 = 0x00000001; +pub const MOUNT_ATTR_NOSUID: crate::__u64 = 0x00000002; +pub const MOUNT_ATTR_NODEV: crate::__u64 = 0x00000004; +pub const MOUNT_ATTR_NOEXEC: crate::__u64 = 0x00000008; +pub const MOUNT_ATTR__ATIME: crate::__u64 = 0x00000070; +pub const MOUNT_ATTR_RELATIME: crate::__u64 = 0x00000000; +pub const MOUNT_ATTR_NOATIME: crate::__u64 = 0x00000010; +pub const MOUNT_ATTR_STRICTATIME: crate::__u64 = 0x00000020; +pub const MOUNT_ATTR_NODIRATIME: crate::__u64 = 0x00000080; +pub const MOUNT_ATTR_IDMAP: crate::__u64 = 0x00100000; +pub const MOUNT_ATTR_NOSYMFOLLOW: crate::__u64 = 0x00200000; + +pub const MOUNT_ATTR_SIZE_VER0: c_int = 32; + +pub const SCHED_FLAG_KEEP_ALL: c_int = SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS; + +pub const SCHED_FLAG_UTIL_CLAMP: c_int = SCHED_FLAG_UTIL_CLAMP_MIN | SCHED_FLAG_UTIL_CLAMP_MAX; + +pub const SCHED_FLAG_ALL: c_int = SCHED_FLAG_RESET_ON_FORK + | SCHED_FLAG_RECLAIM + | SCHED_FLAG_DL_OVERRUN + | SCHED_FLAG_KEEP_ALL + | SCHED_FLAG_UTIL_CLAMP; + +// ioctl_eventpoll: added in Linux 6.9 +pub const EPIOCSPARAMS: Ioctl = 0x40088a01; +pub const EPIOCGPARAMS: Ioctl = 0x80088a02; + +// siginfo.h +pub const SI_DETHREAD: c_int = -7; +pub const TRAP_PERF: c_int = 6; + +f! { + pub fn SCTP_PR_INDEX(policy: c_int) -> c_int { + policy >> (4 - 1) + } + + pub fn SCTP_PR_POLICY(policy: c_int) -> c_int { + policy & SCTP_PR_SCTP_MASK + } + + pub fn SCTP_PR_SET_POLICY(flags: &mut c_int, policy: c_int) -> () { + *flags &= !SCTP_PR_SCTP_MASK; + *flags |= policy; + } + + pub fn SO_EE_OFFENDER(ee: *const crate::sock_extended_err) -> *mut crate::sockaddr { + ee.offset(1) as *mut crate::sockaddr + } + + pub fn TPACKET_ALIGN(x: usize) -> usize { + (x + TPACKET_ALIGNMENT - 1) & !(TPACKET_ALIGNMENT - 1) + } + + pub fn BPF_CLASS(code: __u32) -> __u32 { + code & 0x07 + } + + pub fn BPF_SIZE(code: __u32) -> __u32 { + code & 0x18 + } + + pub fn BPF_MODE(code: __u32) -> __u32 { + code & 0xe0 + } + + pub fn BPF_OP(code: __u32) -> __u32 { + code & 0xf0 + } + + pub fn BPF_SRC(code: __u32) -> __u32 { + code & 0x08 + } + + pub fn BPF_RVAL(code: __u32) -> __u32 { + code & 0x18 + } + + pub fn BPF_MISCOP(code: __u32) -> __u32 { + code & 0xf8 + } + + pub fn BPF_STMT(code: __u16, k: __u32) -> sock_filter { + sock_filter { + code, + jt: 0, + jf: 0, + k, + } + } + + pub fn BPF_JUMP(code: __u16, k: __u32, jt: __u8, jf: __u8) -> sock_filter { + sock_filter { code, jt, jf, k } + } + + #[cfg(target_env = "gnu")] + pub fn SUN_LEN(s: crate::sockaddr_un) -> usize { + offset_of!(crate::sockaddr_un, sun_path) + crate::strlen(s.sun_path.as_ptr()) + } + + #[cfg(target_env = "musl")] + pub fn SUN_LEN(s: crate::sockaddr_un) -> usize { + 2 * crate::strlen(s.sun_path.as_ptr()) + } +} + +safe_f! { + pub const fn SCTP_PR_TTL_ENABLED(policy: c_int) -> bool { + policy == SCTP_PR_SCTP_TTL + } + + pub const fn SCTP_PR_RTX_ENABLED(policy: c_int) -> bool { + policy == SCTP_PR_SCTP_RTX + } + + pub const fn SCTP_PR_PRIO_ENABLED(policy: c_int) -> bool { + policy == SCTP_PR_SCTP_PRIO + } +} + +// These functions are not available on OpenHarmony +cfg_if! { + if #[cfg(not(target_env = "ohos"))] { + extern "C" { + // Only `getspnam_r` is implemented for musl, out of all of the reenterant + // functions from `shadow.h`. + // https://git.musl-libc.org/cgit/musl/tree/include/shadow.h + pub fn getspnam_r( + name: *const c_char, + spbuf: *mut crate::spwd, + buf: *mut c_char, + buflen: size_t, + spbufp: *mut *mut crate::spwd, + ) -> c_int; + + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> mqd_t; + pub fn mq_close(mqd: mqd_t) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mq_receive( + mqd: mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__mq_timedreceive_time64" + )] + pub fn mq_timedreceive( + mqd: mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_send( + mqd: mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__mq_timedsend_time64" + )] + pub fn mq_timedsend( + mqd: mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_getattr(mqd: mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_setattr( + mqd: mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + } + } +} + +extern "C" { + pub fn mrand48() -> c_long; + pub fn seed48(xseed: *mut c_ushort) -> *mut c_ushort; + pub fn lcong48(p: *mut c_ushort); + + #[cfg_attr(gnu_time_bits64, link_name = "__lutimes64")] + #[cfg_attr(musl_redir_time64, link_name = "__lutimes_time64")] + pub fn lutimes(file: *const c_char, times: *const crate::timeval) -> c_int; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + // System V IPC + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> crate::key_t; + pub fn semget(key: crate::key_t, nsems: c_int, semflag: c_int) -> c_int; + pub fn semop(semid: c_int, sops: *mut crate::sembuf, nsops: size_t) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__semctl64")] + pub fn semctl(semid: c_int, semnum: c_int, cmd: c_int, ...) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__msgctl64")] + pub fn msgctl(msqid: c_int, cmd: c_int, buf: *mut msqid_ds) -> c_int; + pub fn msgget(key: crate::key_t, msgflg: c_int) -> c_int; + pub fn msgrcv( + msqid: c_int, + msgp: *mut c_void, + msgsz: size_t, + msgtyp: c_long, + msgflg: c_int, + ) -> ssize_t; + pub fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: size_t, msgflg: c_int) -> c_int; + + #[cfg_attr(gnu_file_offset_bits64, link_name = "fallocate64")] + pub fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "posix_fallocate64")] + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn readahead(fd: c_int, offset: off64_t, count: size_t) -> ssize_t; + pub fn getxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn lgetxattr( + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn fgetxattr( + filedes: c_int, + name: *const c_char, + value: *mut c_void, + size: size_t, + ) -> ssize_t; + pub fn setxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn lsetxattr( + path: *const c_char, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn fsetxattr( + filedes: c_int, + name: *const c_char, + value: *const c_void, + size: size_t, + flags: c_int, + ) -> c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t; + pub fn flistxattr(filedes: c_int, list: *mut c_char, size: size_t) -> ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> c_int; + pub fn fremovexattr(filedes: c_int, name: *const c_char) -> c_int; + pub fn signalfd(fd: c_int, mask: *const crate::sigset_t, flags: c_int) -> c_int; + pub fn timerfd_create(clockid: crate::clockid_t, flags: c_int) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__timerfd_gettime64" + )] + pub fn timerfd_gettime(fd: c_int, curr_value: *mut crate::itimerspec) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__timerfd_settime64" + )] + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + pub fn quotactl(cmd: c_int, special: *const c_char, id: c_int, data: *mut c_char) -> c_int; + pub fn epoll_pwait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + sigmask: *const crate::sigset_t, + ) -> c_int; + pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__sigtimedwait64")] + #[cfg_attr(musl_redir_time64, link_name = "__sigtimedwait_time64")] + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + pub fn accept4(fd: c_int, addr: *mut crate::sockaddr, len: *mut socklen_t, flg: c_int) + -> c_int; + pub fn reboot(how_to: c_int) -> c_int; + pub fn setfsgid(gid: crate::gid_t) -> c_int; + pub fn setfsuid(uid: crate::uid_t) -> c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn sync_file_range(fd: c_int, offset: off64_t, nbytes: off64_t, flags: c_uint) -> c_int; + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn remap_file_pages( + addr: *mut c_void, + size: size_t, + prot: c_int, + pgoff: size_t, + flags: c_int, + ) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "mkstemps64")] + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + + pub fn vhangup() -> c_int; + pub fn sync(); + pub fn syncfs(fd: c_int) -> c_int; + pub fn syscall(num: c_long, ...) -> c_long; + pub fn sched_setaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *const crate::cpu_set_t, + ) -> c_int; + pub fn epoll_create(size: c_int) -> c_int; + pub fn epoll_create1(flags: c_int) -> c_int; + pub fn epoll_wait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + ) -> c_int; + pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut crate::epoll_event) -> c_int; + pub fn unshare(flags: c_int) -> c_int; + pub fn umount(target: *const c_char) -> c_int; + pub fn tee(fd_in: c_int, fd_out: c_int, len: size_t, flags: c_uint) -> ssize_t; + pub fn splice( + fd_in: c_int, + off_in: *mut loff_t, + fd_out: c_int, + off_out: *mut loff_t, + len: size_t, + flags: c_uint, + ) -> ssize_t; + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; + pub fn eventfd_read(fd: c_int, value: *mut eventfd_t) -> c_int; + pub fn eventfd_write(fd: c_int, value: eventfd_t) -> c_int; + + #[cfg_attr(gnu_time_bits64, link_name = "__sched_rr_get_interval64")] + #[cfg_attr(musl_redir_time64, link_name = "__sched_rr_get_interval_time64")] + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn setns(fd: c_int, nstype: c_int) -> c_int; + pub fn swapoff(path: *const c_char) -> c_int; + pub fn vmsplice(fd: c_int, iov: *const crate::iovec, nr_segs: size_t, flags: c_uint) + -> ssize_t; + pub fn personality(persona: c_ulong) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn clone( + cb: extern "C" fn(*mut c_void) -> c_int, + child_stack: *mut c_void, + flags: c_int, + arg: *mut c_void, + ... + ) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__clock_nanosleep_time64" + )] + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + pub fn umount2(target: *const c_char, flags: c_int) -> c_int; + pub fn swapon(path: *const c_char, swapflags: c_int) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "sendfile64")] + pub fn sendfile(out_fd: c_int, in_fd: c_int, offset: *mut off_t, count: size_t) -> ssize_t; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + pub fn fread_unlocked( + buf: *mut c_void, + size: size_t, + nobj: size_t, + stream: *mut crate::FILE, + ) -> size_t; + pub fn inotify_rm_watch(fd: c_int, wd: c_int) -> c_int; + pub fn inotify_init() -> c_int; + pub fn inotify_init1(flags: c_int) -> c_int; + pub fn inotify_add_watch(fd: c_int, path: *const c_char, mask: u32) -> c_int; + pub fn fanotify_init(flags: c_uint, event_f_flags: c_uint) -> c_int; + + pub fn gethostid() -> c_long; + + pub fn klogctl(syslog_type: c_int, bufp: *mut c_char, len: c_int) -> c_int; + + pub fn name_to_handle_at( + dirfd: c_int, + path: *const c_char, + handle: *mut file_handle, + mount_id: *mut c_int, + flags: c_int, + ) -> c_int; + pub fn open_by_handle_at(mount_fd: c_int, handle: *mut file_handle, flags: c_int) -> c_int; +} + +// LFS64 extensions +// +// * musl has 64-bit versions only so aliases the LFS64 symbols to the standard ones +cfg_if! { + if #[cfg(not(any(target_env = "musl", target_env = "ohos")))] { + extern "C" { + pub fn fallocate64(fd: c_int, mode: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn fgetpos64(stream: *mut crate::FILE, ptr: *mut crate::fpos64_t) -> c_int; + pub fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int; + pub fn sendfile64( + out_fd: c_int, + in_fd: c_int, + offset: *mut off64_t, + count: size_t, + ) -> ssize_t; + pub fn tmpfile64() -> *mut crate::FILE; + } + } +} + +cfg_if! { + if #[cfg(target_env = "uclibc")] { + mod uclibc; + pub use self::uclibc::*; + } else if #[cfg(any(target_env = "musl", target_env = "ohos"))] { + mod musl; + pub use self::musl::*; + } else if #[cfg(target_env = "gnu")] { + mod gnu; + pub use self::gnu::*; + } +} + +mod arch; +pub use self::arch::*; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/arm/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/arm/mod.rs new file mode 100644 index 00000000000000..26d3380eb7ba54 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/arm/mod.rs @@ -0,0 +1,832 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = u32; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + __st_dev_padding: Padding, + __st_ino_truncated: c_long, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __st_rdev_padding: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + + #[cfg(musl32_time64)] + __st_atim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_mtim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_ctim32: Padding<__c_anonymous_timespec32>, + + #[cfg(musl_v1_2_3)] + pub st_ino: crate::ino_t, + + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + pub st_atime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad1: Padding, + pub st_mtime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad1: Padding, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad2: Padding, + pub st_ctime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad2: Padding, + + #[cfg(not(musl_v1_2_3))] + pub st_ino: crate::ino_t, + } + + struct __c_anonymous_timespec32 { + __tv_sec: c_long, + __tv_nsec: c_long, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + + #[cfg(musl32_time64)] + __shm_atime_lo: Padding, + #[cfg(musl32_time64)] + __shm_atime_hi: Padding, + #[cfg(musl32_time64)] + __shm_dtime_lo: Padding, + #[cfg(musl32_time64)] + __shm_dtime_hi: Padding, + #[cfg(musl32_time64)] + __msg_ctime_lo: Padding, + #[cfg(musl32_time64)] + __msg_ctime_hi: Padding, + + #[cfg(not(musl32_time64))] + pub shm_atime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub shm_dtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub shm_ctime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + __pad3: c_ulong, + #[cfg(musl32_time64)] + shm_atime: crate::time_t, + #[cfg(musl32_time64)] + shm_dtime: crate::time_t, + #[cfg(musl32_time64)] + shm_ctime: crate::time_t, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + + #[cfg(musl32_time64)] + __msg_stime_lo: Padding, + #[cfg(musl32_time64)] + __msg_stime_hi: Padding, + #[cfg(musl32_time64)] + __msg_rtime_lo: Padding, + #[cfg(musl32_time64)] + __msg_rtime_hi: Padding, + #[cfg(musl32_time64)] + __msg_ctime_lo: Padding, + #[cfg(musl32_time64)] + __msg_ctime_hi: Padding, + + #[cfg(not(musl32_time64))] + pub msg_stime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub msg_rtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub msg_ctime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + pub msg_stime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_rtime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_ctime: crate::time_t, + } + + pub struct mcontext_t { + pub trap_no: c_ulong, + pub error_code: c_ulong, + pub oldmask: c_ulong, + pub arm_r0: c_ulong, + pub arm_r1: c_ulong, + pub arm_r2: c_ulong, + pub arm_r3: c_ulong, + pub arm_r4: c_ulong, + pub arm_r5: c_ulong, + pub arm_r6: c_ulong, + pub arm_r7: c_ulong, + pub arm_r8: c_ulong, + pub arm_r9: c_ulong, + pub arm_r10: c_ulong, + pub arm_fp: c_ulong, + pub arm_ip: c_ulong, + pub arm_sp: c_ulong, + pub arm_lr: c_ulong, + pub arm_pc: c_ulong, + pub arm_cpsr: c_ulong, + pub fault_address: c_ulong, + } + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_regspace: [c_ulonglong; 64], + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: (i64, i64), + } +} + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_LARGEFILE: c_int = 0o400000; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: c_int = 0x040000; + +pub const F_GETLK: c_int = 12; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_ptrace: c_long = 26; +pub const SYS_pause: c_long = 29; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_vhangup: c_long = 111; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_pivot_root: c_long = 218; +pub const SYS_mincore: c_long = 219; +pub const SYS_madvise: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_lookup_dcookie: c_long = 249; +pub const SYS_epoll_create: c_long = 250; +pub const SYS_epoll_ctl: c_long = 251; +pub const SYS_epoll_wait: c_long = 252; +pub const SYS_remap_file_pages: c_long = 253; +pub const SYS_set_tid_address: c_long = 256; +pub const SYS_timer_create: c_long = 257; +pub const SYS_timer_settime: c_long = 258; +pub const SYS_timer_gettime: c_long = 259; +pub const SYS_timer_getoverrun: c_long = 260; +pub const SYS_timer_delete: c_long = 261; +pub const SYS_clock_settime: c_long = 262; +pub const SYS_clock_gettime: c_long = 263; +pub const SYS_clock_getres: c_long = 264; +pub const SYS_clock_nanosleep: c_long = 265; +pub const SYS_statfs64: c_long = 266; +pub const SYS_fstatfs64: c_long = 267; +pub const SYS_tgkill: c_long = 268; +pub const SYS_utimes: c_long = 269; +pub const SYS_pciconfig_iobase: c_long = 271; +pub const SYS_pciconfig_read: c_long = 272; +pub const SYS_pciconfig_write: c_long = 273; +pub const SYS_mq_open: c_long = 274; +pub const SYS_mq_unlink: c_long = 275; +pub const SYS_mq_timedsend: c_long = 276; +pub const SYS_mq_timedreceive: c_long = 277; +pub const SYS_mq_notify: c_long = 278; +pub const SYS_mq_getsetattr: c_long = 279; +pub const SYS_waitid: c_long = 280; +pub const SYS_socket: c_long = 281; +pub const SYS_bind: c_long = 282; +pub const SYS_connect: c_long = 283; +pub const SYS_listen: c_long = 284; +pub const SYS_accept: c_long = 285; +pub const SYS_getsockname: c_long = 286; +pub const SYS_getpeername: c_long = 287; +pub const SYS_socketpair: c_long = 288; +pub const SYS_send: c_long = 289; +pub const SYS_sendto: c_long = 290; +pub const SYS_recv: c_long = 291; +pub const SYS_recvfrom: c_long = 292; +pub const SYS_shutdown: c_long = 293; +pub const SYS_setsockopt: c_long = 294; +pub const SYS_getsockopt: c_long = 295; +pub const SYS_sendmsg: c_long = 296; +pub const SYS_recvmsg: c_long = 297; +pub const SYS_semop: c_long = 298; +pub const SYS_semget: c_long = 299; +pub const SYS_semctl: c_long = 300; +pub const SYS_msgsnd: c_long = 301; +pub const SYS_msgrcv: c_long = 302; +pub const SYS_msgget: c_long = 303; +pub const SYS_msgctl: c_long = 304; +pub const SYS_shmat: c_long = 305; +pub const SYS_shmdt: c_long = 306; +pub const SYS_shmget: c_long = 307; +pub const SYS_shmctl: c_long = 308; +pub const SYS_add_key: c_long = 309; +pub const SYS_request_key: c_long = 310; +pub const SYS_keyctl: c_long = 311; +pub const SYS_semtimedop: c_long = 312; +pub const SYS_vserver: c_long = 313; +pub const SYS_ioprio_set: c_long = 314; +pub const SYS_ioprio_get: c_long = 315; +pub const SYS_inotify_init: c_long = 316; +pub const SYS_inotify_add_watch: c_long = 317; +pub const SYS_inotify_rm_watch: c_long = 318; +pub const SYS_mbind: c_long = 319; +pub const SYS_get_mempolicy: c_long = 320; +pub const SYS_set_mempolicy: c_long = 321; +pub const SYS_openat: c_long = 322; +pub const SYS_mkdirat: c_long = 323; +pub const SYS_mknodat: c_long = 324; +pub const SYS_fchownat: c_long = 325; +pub const SYS_futimesat: c_long = 326; +pub const SYS_fstatat64: c_long = 327; +pub const SYS_unlinkat: c_long = 328; +pub const SYS_renameat: c_long = 329; +pub const SYS_linkat: c_long = 330; +pub const SYS_symlinkat: c_long = 331; +pub const SYS_readlinkat: c_long = 332; +pub const SYS_fchmodat: c_long = 333; +pub const SYS_faccessat: c_long = 334; +pub const SYS_pselect6: c_long = 335; +pub const SYS_ppoll: c_long = 336; +pub const SYS_unshare: c_long = 337; +pub const SYS_set_robust_list: c_long = 338; +pub const SYS_get_robust_list: c_long = 339; +pub const SYS_splice: c_long = 340; +pub const SYS_tee: c_long = 342; +pub const SYS_vmsplice: c_long = 343; +pub const SYS_move_pages: c_long = 344; +pub const SYS_getcpu: c_long = 345; +pub const SYS_epoll_pwait: c_long = 346; +pub const SYS_kexec_load: c_long = 347; +pub const SYS_utimensat: c_long = 348; +pub const SYS_signalfd: c_long = 349; +pub const SYS_timerfd_create: c_long = 350; +pub const SYS_eventfd: c_long = 351; +pub const SYS_fallocate: c_long = 352; +pub const SYS_timerfd_settime: c_long = 353; +pub const SYS_timerfd_gettime: c_long = 354; +pub const SYS_signalfd4: c_long = 355; +pub const SYS_eventfd2: c_long = 356; +pub const SYS_epoll_create1: c_long = 357; +pub const SYS_dup3: c_long = 358; +pub const SYS_pipe2: c_long = 359; +pub const SYS_inotify_init1: c_long = 360; +pub const SYS_preadv: c_long = 361; +pub const SYS_pwritev: c_long = 362; +pub const SYS_rt_tgsigqueueinfo: c_long = 363; +pub const SYS_perf_event_open: c_long = 364; +pub const SYS_recvmmsg: c_long = 365; +pub const SYS_accept4: c_long = 366; +pub const SYS_fanotify_init: c_long = 367; +pub const SYS_fanotify_mark: c_long = 368; +pub const SYS_prlimit64: c_long = 369; +pub const SYS_name_to_handle_at: c_long = 370; +pub const SYS_open_by_handle_at: c_long = 371; +pub const SYS_clock_adjtime: c_long = 372; +pub const SYS_syncfs: c_long = 373; +pub const SYS_sendmmsg: c_long = 374; +pub const SYS_setns: c_long = 375; +pub const SYS_process_vm_readv: c_long = 376; +pub const SYS_process_vm_writev: c_long = 377; +pub const SYS_kcmp: c_long = 378; +pub const SYS_finit_module: c_long = 379; +pub const SYS_sched_setattr: c_long = 380; +pub const SYS_sched_getattr: c_long = 381; +pub const SYS_renameat2: c_long = 382; +pub const SYS_seccomp: c_long = 383; +pub const SYS_getrandom: c_long = 384; +pub const SYS_memfd_create: c_long = 385; +pub const SYS_bpf: c_long = 386; +pub const SYS_execveat: c_long = 387; +pub const SYS_userfaultfd: c_long = 388; +pub const SYS_membarrier: c_long = 389; +pub const SYS_mlock2: c_long = 390; +pub const SYS_copy_file_range: c_long = 391; +pub const SYS_preadv2: c_long = 392; +pub const SYS_pwritev2: c_long = 393; +pub const SYS_pkey_mprotect: c_long = 394; +pub const SYS_pkey_alloc: c_long = 395; +pub const SYS_pkey_free: c_long = 396; +pub const SYS_statx: c_long = 397; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/hexagon.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/hexagon.rs new file mode 100644 index 00000000000000..fa5ebf36357712 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/hexagon.rs @@ -0,0 +1,719 @@ +use crate::prelude::*; + +pub type wchar_t = u32; +pub type stat64 = crate::stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: c_ulonglong, + pub st_mode: c_uint, + pub st_nlink: c_uint, + pub st_uid: c_uint, + pub st_gid: c_uint, + pub st_rdev: c_ulonglong, + __st_rdev_padding: Padding, + pub st_size: c_longlong, + pub st_blksize: crate::blksize_t, + __st_blksize_padding: Padding, + pub st_blocks: crate::blkcnt_t, + + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + pub st_atime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad1: Padding, + pub st_mtime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad1: Padding, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad2: Padding, + pub st_ctime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad2: Padding, + + __unused: Padding<[c_int; 2]>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release" + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __pad1: Padding, + __pad2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + __unused1: Padding, + pub shm_dtime: crate::time_t, + __unused2: Padding, + pub shm_ctime: crate::time_t, + __unused3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + __unused1: Padding, + pub msg_rtime: crate::time_t, + __unused2: Padding, + pub msg_ctime: crate::time_t, + __unused3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } +} + +pub const AF_FILE: c_int = 1; +pub const AF_KCM: c_int = 41; +pub const AF_MAX: c_int = 43; +pub const AF_QIPCRTR: c_int = 42; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const EAFNOSUPPORT: c_int = 97; +pub const EALREADY: c_int = 114; +pub const EBADE: c_int = 52; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EBADR: c_int = 53; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const ECANCELED: c_int = 125; +pub const ECHRNG: c_int = 44; +pub const ECONNABORTED: c_int = 103; +pub const ECONNREFUSED: c_int = 111; +pub const ECONNRESET: c_int = 104; +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = 35; +pub const EDESTADDRREQ: c_int = 89; +pub const EDQUOT: c_int = 122; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EHWPOISON: c_int = 133; +pub const EIDRM: c_int = 43; +pub const EILSEQ: c_int = 84; +pub const EINPROGRESS: c_int = 115; +pub const EISCONN: c_int = 106; +pub const EISNAM: c_int = 120; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREJECTED: c_int = 129; +pub const EKEYREVOKED: c_int = 128; +pub const EL2HLT: c_int = 51; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBEXEC: c_int = 83; +pub const ELIBMAX: c_int = 82; +pub const ELIBSCN: c_int = 81; +pub const ELNRNG: c_int = 48; +pub const ELOOP: c_int = 40; +pub const EMEDIUMTYPE: c_int = 124; +pub const EMSGSIZE: c_int = 90; +pub const EMULTIHOP: c_int = 72; +pub const ENAMETOOLONG: c_int = 36; +pub const ENAVAIL: c_int = 119; +pub const ENETDOWN: c_int = 100; +pub const ENETRESET: c_int = 102; +pub const ENETUNREACH: c_int = 101; +pub const ENOANO: c_int = 55; +pub const ENOBUFS: c_int = 105; +pub const ENOCSI: c_int = 50; +pub const ENOKEY: c_int = 126; +pub const ENOLCK: c_int = 37; +pub const ENOMEDIUM: c_int = 123; +pub const ENOMSG: c_int = 42; +pub const ENOPROTOOPT: c_int = 92; +pub const ENOSYS: c_int = 38; +pub const ENOTCONN: c_int = 107; +pub const ENOTEMPTY: c_int = 39; +pub const ENOTNAM: c_int = 118; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ENOTSOCK: c_int = 88; +pub const ENOTSUP: c_int = 95; +pub const ENOTUNIQ: c_int = 76; +pub const EOPNOTSUPP: c_int = 95; +pub const EOVERFLOW: c_int = 75; +pub const EOWNERDEAD: c_int = 130; +pub const EPFNOSUPPORT: c_int = 96; +pub const EPROTOTYPE: c_int = 91; +pub const EPROTONOSUPPORT: c_int = 93; +pub const EREMCHG: c_int = 78; +pub const ERESTART: c_int = 85; +pub const EREMOTEIO: c_int = 121; +pub const ERFKILL: c_int = 132; +pub const ESHUTDOWN: c_int = 108; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const ESTALE: c_int = 116; +pub const ESTRPIPE: c_int = 86; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const EUCLEAN: c_int = 117; +pub const EUNATCH: c_int = 49; +pub const EUSERS: c_int = 87; +pub const EXFULL: c_int = 54; +pub const EXTPROC: crate::tcflag_t = 65536; +pub const F_EXLCK: c_int = 4; +pub const F_GETLK: c_int = 12; +pub const F_GETOWN: c_int = 9; +pub const F_GETOWNER_UIDS: c_int = 17; +pub const F_GETOWN_EX: c_int = 16; +pub const F_GETSIG: c_int = 11; +pub const F_LINUX_SPECIFIC_BASE: c_int = 1024; +pub const FLUSHO: crate::tcflag_t = 4096; +pub const F_OWNER_PGRP: c_int = 2; +pub const F_OWNER_PID: c_int = 1; +pub const F_OWNER_TID: c_int = 0; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; +pub const F_SETOWN: c_int = 8; +pub const F_SETOWN_EX: c_int = 15; +pub const F_SETSIG: c_int = 10; +pub const F_SHLCK: c_int = 8; +pub const IEXTEN: crate::tcflag_t = 32768; +pub const MAP_ANON: c_int = 32; +pub const MAP_DENYWRITE: c_int = 2048; +pub const MAP_EXECUTABLE: c_int = 4096; +pub const MAP_GROWSDOWN: c_int = 256; +pub const MAP_HUGETLB: c_int = 262144; +pub const MAP_LOCKED: c_int = 8192; +pub const MAP_NONBLOCK: c_int = 65536; +pub const MAP_NORESERVE: c_int = 16384; +pub const MAP_POPULATE: c_int = 32768; +pub const MAP_STACK: c_int = 131072; +pub const MAP_SYNC: c_int = 0x080000; +pub const MAP_UNINITIALIZED: c_int = 0; +pub const O_APPEND: c_int = 1024; +pub const O_ASYNC: c_int = 8192; +pub const O_CREAT: c_int = 64; +pub const O_DIRECT: c_int = 16384; +pub const O_DIRECTORY: c_int = 65536; +pub const O_DSYNC: c_int = 4096; +pub const O_EXCL: c_int = 128; +pub const O_LARGEFILE: c_int = 32768; +pub const O_NOCTTY: c_int = 256; +pub const O_NOFOLLOW: c_int = 131072; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const PF_FILE: c_int = 1; +pub const PF_KCM: c_int = 41; +pub const PF_MAX: c_int = 43; +pub const PF_QIPCRTR: c_int = 42; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; +pub const SIGBUS: c_int = 7; +pub const SIGCHLD: c_int = 17; +pub const SIGCONT: c_int = 18; +pub const SIGIO: c_int = 29; +pub const SIGPOLL: c_int = 29; +pub const SIGPROF: c_int = 27; +pub const SIGPWR: c_int = 30; +pub const SIGSTKFLT: c_int = 16; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const SIGSTOP: c_int = 19; +pub const SIGSYS: c_int = 31; +pub const SIGTSTP: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGURG: c_int = 23; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGVTALRM: c_int = 26; +pub const SIGWINCH: c_int = 28; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIG_SETMASK: c_int = 2; // FIXME(musl) check these +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; +pub const SOL_CAIF: c_int = 278; +pub const SOL_IUCV: c_int = 277; +pub const SOL_KCM: c_int = 281; +pub const SOL_NFC: c_int = 280; +pub const SOL_PNPIPE: c_int = 275; +pub const SOL_PPPOL2TP: c_int = 273; +pub const SOL_RDS: c_int = 276; +pub const SOL_RXRPC: c_int = 272; +pub const POLLWRNORM: c_short = 256; +pub const POLLWRBAND: c_short = 512; +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MCL_CURRENT: c_int = 1; +pub const MCL_FUTURE: c_int = 2; +pub const MCL_ONFAULT: c_int = 4; + +pub const SYS3264_fadvise64: c_int = 223; +pub const SYS3264_fcntl: c_int = 25; +pub const SYS3264_fstatat: c_int = 79; +pub const SYS3264_fstat: c_int = 80; +pub const SYS3264_fstatfs: c_int = 44; +pub const SYS3264_ftruncate: c_int = 46; +pub const SYS3264_lseek: c_int = 62; +pub const SYS3264_lstat: c_int = 1039; +pub const SYS3264_mmap: c_int = 222; +pub const SYS3264_sendfile: c_int = 71; +pub const SYS3264_stat: c_int = 1038; +pub const SYS3264_statfs: c_int = 43; +pub const SYS3264_truncate: c_int = 45; +pub const SYS_accept4: c_int = 242; +pub const SYS_accept: c_int = 202; +pub const SYS_access: c_int = 1033; +pub const SYS_acct: c_int = 89; +pub const SYS_add_key: c_int = 217; +pub const SYS_adjtimex: c_int = 171; +pub const SYS_alarm: c_int = 1059; +pub const SYS_arch_specific_syscall: c_int = 244; +pub const SYS_bdflush: c_int = 1075; +pub const SYS_bind: c_int = 200; +pub const SYS_bpf: c_int = 280; +pub const SYS_brk: c_int = 214; +pub const SYS_capget: c_int = 90; +pub const SYS_capset: c_int = 91; +pub const SYS_chdir: c_int = 49; +pub const SYS_chmod: c_int = 1028; +pub const SYS_chown: c_int = 1029; +pub const SYS_chroot: c_int = 51; +pub const SYS_clock_adjtime: c_int = 266; +pub const SYS_clock_getres: c_int = 114; +pub const SYS_clock_gettime: c_int = 113; +pub const SYS_clock_nanosleep: c_int = 115; +pub const SYS_clock_settime: c_int = 112; +pub const SYS_clone: c_int = 220; +pub const SYS_close: c_int = 57; +pub const SYS_connect: c_int = 203; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_creat: c_int = 1064; +pub const SYS_delete_module: c_int = 106; +pub const SYS_dup2: c_int = 1041; +pub const SYS_dup3: c_int = 24; +pub const SYS_dup: c_int = 23; +pub const SYS_epoll_create1: c_int = 20; +pub const SYS_epoll_create: c_int = 1042; +pub const SYS_epoll_ctl: c_int = 21; +pub const SYS_epoll_pwait: c_int = 22; +pub const SYS_epoll_wait: c_int = 1069; +pub const SYS_eventfd2: c_int = 19; +pub const SYS_eventfd: c_int = 1044; +pub const SYS_execveat: c_int = 281; +pub const SYS_execve: c_int = 221; +pub const SYS_exit: c_int = 93; +pub const SYS_exit_group: c_int = 94; +pub const SYS_faccessat: c_int = 48; +pub const SYS_fadvise64_64: c_int = 223; +pub const SYS_fallocate: c_int = 47; +pub const SYS_fanotify_init: c_int = 262; +pub const SYS_fanotify_mark: c_int = 263; +pub const SYS_fchdir: c_int = 50; +pub const SYS_fchmodat: c_int = 53; +pub const SYS_fchmod: c_int = 52; +pub const SYS_fchownat: c_int = 54; +pub const SYS_fchown: c_int = 55; +pub const SYS_fcntl64: c_int = 25; +pub const SYS_fcntl: c_int = 25; +pub const SYS_fdatasync: c_int = 83; +pub const SYS_fgetxattr: c_int = 10; +pub const SYS_finit_module: c_int = 273; +pub const SYS_flistxattr: c_int = 13; +pub const SYS_flock: c_int = 32; +pub const SYS_fork: c_int = 1079; +pub const SYS_fremovexattr: c_int = 16; +pub const SYS_fsetxattr: c_int = 7; +pub const SYS_fstat64: c_int = 80; +pub const SYS_fstatat64: c_int = 79; +pub const SYS_fstatfs64: c_int = 44; +pub const SYS_fstatfs: c_int = 44; +pub const SYS_fsync: c_int = 82; +pub const SYS_ftruncate64: c_int = 46; +pub const SYS_ftruncate: c_int = 46; +pub const SYS_futex: c_int = 98; +pub const SYS_futimesat: c_int = 1066; +pub const SYS_getcpu: c_int = 168; +pub const SYS_getcwd: c_int = 17; +pub const SYS_getdents64: c_int = 61; +pub const SYS_getdents: c_int = 1065; +pub const SYS_getegid: c_int = 177; +pub const SYS_geteuid: c_int = 175; +pub const SYS_getgid: c_int = 176; +pub const SYS_getgroups: c_int = 158; +pub const SYS_getitimer: c_int = 102; +pub const SYS_get_mempolicy: c_int = 236; +pub const SYS_getpeername: c_int = 205; +pub const SYS_getpgid: c_int = 155; +pub const SYS_getpgrp: c_int = 1060; +pub const SYS_getpid: c_int = 172; +pub const SYS_getppid: c_int = 173; +pub const SYS_getpriority: c_int = 141; +pub const SYS_getrandom: c_int = 278; +pub const SYS_getresgid: c_int = 150; +pub const SYS_getresuid: c_int = 148; +pub const SYS_getrlimit: c_int = 163; +pub const SYS_get_robust_list: c_int = 100; +pub const SYS_getrusage: c_int = 165; +pub const SYS_getsid: c_int = 156; +pub const SYS_getsockname: c_int = 204; +pub const SYS_getsockopt: c_int = 209; +pub const SYS_gettid: c_int = 178; +pub const SYS_gettimeofday: c_int = 169; +pub const SYS_getuid: c_int = 174; +pub const SYS_getxattr: c_int = 8; +pub const SYS_init_module: c_int = 105; +pub const SYS_inotify_add_watch: c_int = 27; +pub const SYS_inotify_init1: c_int = 26; +pub const SYS_inotify_init: c_int = 1043; +pub const SYS_inotify_rm_watch: c_int = 28; +pub const SYS_io_cancel: c_int = 3; +pub const SYS_ioctl: c_int = 29; +pub const SYS_io_destroy: c_int = 1; +pub const SYS_io_getevents: c_int = 4; +pub const SYS_ioprio_get: c_int = 31; +pub const SYS_ioprio_set: c_int = 30; +pub const SYS_io_setup: c_int = 0; +pub const SYS_io_submit: c_int = 2; +pub const SYS_kcmp: c_int = 272; +pub const SYS_kexec_load: c_int = 104; +pub const SYS_keyctl: c_int = 219; +pub const SYS_kill: c_int = 129; +pub const SYS_lchown: c_int = 1032; +pub const SYS_lgetxattr: c_int = 9; +pub const SYS_linkat: c_int = 37; +pub const SYS_link: c_int = 1025; +pub const SYS_listen: c_int = 201; +pub const SYS_listxattr: c_int = 11; +pub const SYS_llistxattr: c_int = 12; +pub const SYS__llseek: c_int = 62; +pub const SYS_lookup_dcookie: c_int = 18; +pub const SYS_lremovexattr: c_int = 15; +pub const SYS_lseek: c_int = 62; +pub const SYS_lsetxattr: c_int = 6; +pub const SYS_lstat64: c_int = 1039; +pub const SYS_lstat: c_int = 1039; +pub const SYS_madvise: c_int = 233; +pub const SYS_mbind: c_int = 235; +pub const SYS_memfd_create: c_int = 279; +pub const SYS_migrate_pages: c_int = 238; +pub const SYS_mincore: c_int = 232; +pub const SYS_mkdirat: c_int = 34; +pub const SYS_mkdir: c_int = 1030; +pub const SYS_mknodat: c_int = 33; +pub const SYS_mknod: c_int = 1027; +pub const SYS_mlockall: c_int = 230; +pub const SYS_mlock: c_int = 228; +pub const SYS_mmap2: c_int = 222; +pub const SYS_mount: c_int = 40; +pub const SYS_move_pages: c_int = 239; +pub const SYS_mprotect: c_int = 226; +pub const SYS_mq_getsetattr: c_int = 185; +pub const SYS_mq_notify: c_int = 184; +pub const SYS_mq_open: c_int = 180; +pub const SYS_mq_timedreceive: c_int = 183; +pub const SYS_mq_timedsend: c_int = 182; +pub const SYS_mq_unlink: c_int = 181; +pub const SYS_mremap: c_int = 216; +pub const SYS_msgctl: c_int = 187; +pub const SYS_msgget: c_int = 186; +pub const SYS_msgrcv: c_int = 188; +pub const SYS_msgsnd: c_int = 189; +pub const SYS_msync: c_int = 227; +pub const SYS_munlockall: c_int = 231; +pub const SYS_munlock: c_int = 229; +pub const SYS_munmap: c_int = 215; +pub const SYS_name_to_handle_at: c_int = 264; +pub const SYS_nanosleep: c_int = 101; +pub const SYS_newfstatat: c_int = 79; +pub const SYS_nfsservctl: c_int = 42; +pub const SYS_oldwait4: c_int = 1072; +pub const SYS_openat: c_int = 56; +pub const SYS_open_by_handle_at: c_int = 265; +pub const SYS_open: c_int = 1024; +pub const SYS_pause: c_int = 1061; +pub const SYS_perf_event_open: c_int = 241; +pub const SYS_personality: c_int = 92; +pub const SYS_pipe2: c_int = 59; +pub const SYS_pipe: c_int = 1040; +pub const SYS_pivot_root: c_int = 41; +pub const SYS_poll: c_int = 1068; +pub const SYS_ppoll: c_int = 73; +pub const SYS_prctl: c_int = 167; +pub const SYS_pread64: c_int = 67; +pub const SYS_preadv: c_int = 69; +pub const SYS_prlimit64: c_int = 261; +pub const SYS_process_vm_readv: c_int = 270; +pub const SYS_process_vm_writev: c_int = 271; +pub const SYS_pselect6: c_int = 72; +pub const SYS_ptrace: c_int = 117; +pub const SYS_pwrite64: c_int = 68; +pub const SYS_pwritev: c_int = 70; +pub const SYS_quotactl: c_int = 60; +pub const SYS_readahead: c_int = 213; +pub const SYS_read: c_int = 63; +pub const SYS_readlinkat: c_int = 78; +pub const SYS_readlink: c_int = 1035; +pub const SYS_readv: c_int = 65; +pub const SYS_reboot: c_int = 142; +pub const SYS_recv: c_int = 1073; +pub const SYS_recvfrom: c_int = 207; +pub const SYS_recvmmsg: c_int = 243; +pub const SYS_recvmsg: c_int = 212; +pub const SYS_remap_file_pages: c_int = 234; +pub const SYS_removexattr: c_int = 14; +pub const SYS_renameat2: c_int = 276; +pub const SYS_renameat: c_int = 38; +pub const SYS_rename: c_int = 1034; +pub const SYS_request_key: c_int = 218; +pub const SYS_restart_syscall: c_int = 128; +pub const SYS_rmdir: c_int = 1031; +pub const SYS_rt_sigaction: c_int = 134; +pub const SYS_rt_sigpending: c_int = 136; +pub const SYS_rt_sigprocmask: c_int = 135; +pub const SYS_rt_sigqueueinfo: c_int = 138; +pub const SYS_rt_sigreturn: c_int = 139; +pub const SYS_rt_sigsuspend: c_int = 133; +pub const SYS_rt_sigtimedwait: c_int = 137; +pub const SYS_rt_tgsigqueueinfo: c_int = 240; +pub const SYS_sched_getaffinity: c_int = 123; +pub const SYS_sched_getattr: c_int = 275; +pub const SYS_sched_getparam: c_int = 121; +pub const SYS_sched_get_priority_max: c_int = 125; +pub const SYS_sched_get_priority_min: c_int = 126; +pub const SYS_sched_getscheduler: c_int = 120; +pub const SYS_sched_rr_get_interval: c_int = 127; +pub const SYS_sched_setaffinity: c_int = 122; +pub const SYS_sched_setattr: c_int = 274; +pub const SYS_sched_setparam: c_int = 118; +pub const SYS_sched_setscheduler: c_int = 119; +pub const SYS_sched_yield: c_int = 124; +pub const SYS_seccomp: c_int = 277; +pub const SYS_select: c_int = 1067; +pub const SYS_semctl: c_int = 191; +pub const SYS_semget: c_int = 190; +pub const SYS_semop: c_int = 193; +pub const SYS_semtimedop: c_int = 192; +pub const SYS_send: c_int = 1074; +pub const SYS_sendfile64: c_int = 71; +pub const SYS_sendfile: c_int = 71; +pub const SYS_sendmmsg: c_int = 269; +pub const SYS_sendmsg: c_int = 211; +pub const SYS_sendto: c_int = 206; +pub const SYS_setdomainname: c_int = 162; +pub const SYS_setfsgid: c_int = 152; +pub const SYS_setfsuid: c_int = 151; +pub const SYS_setgid: c_int = 144; +pub const SYS_setgroups: c_int = 159; +pub const SYS_sethostname: c_int = 161; +pub const SYS_setitimer: c_int = 103; +pub const SYS_set_mempolicy: c_int = 237; +pub const SYS_setns: c_int = 268; +pub const SYS_setpgid: c_int = 154; +pub const SYS_setpriority: c_int = 140; +pub const SYS_setregid: c_int = 143; +pub const SYS_setresgid: c_int = 149; +pub const SYS_setresuid: c_int = 147; +pub const SYS_setreuid: c_int = 145; +pub const SYS_setrlimit: c_int = 164; +pub const SYS_set_robust_list: c_int = 99; +pub const SYS_setsid: c_int = 157; +pub const SYS_setsockopt: c_int = 208; +pub const SYS_set_tid_address: c_int = 96; +pub const SYS_settimeofday: c_int = 170; +pub const SYS_setuid: c_int = 146; +pub const SYS_setxattr: c_int = 5; +pub const SYS_shmat: c_int = 196; +pub const SYS_shmctl: c_int = 195; +pub const SYS_shmdt: c_int = 197; +pub const SYS_shmget: c_int = 194; +pub const SYS_shutdown: c_int = 210; +pub const SYS_sigaltstack: c_int = 132; +pub const SYS_signalfd4: c_int = 74; +pub const SYS_signalfd: c_int = 1045; +pub const SYS_socket: c_int = 198; +pub const SYS_socketpair: c_int = 199; +pub const SYS_splice: c_int = 76; +pub const SYS_stat64: c_int = 1038; +pub const SYS_stat: c_int = 1038; +pub const SYS_statfs64: c_int = 43; +pub const SYS_statfs: c_int = 43; +pub const SYS_swapoff: c_int = 225; +pub const SYS_swapon: c_int = 224; +pub const SYS_symlinkat: c_int = 36; +pub const SYS_symlink: c_int = 1036; +pub const SYS_sync: c_int = 81; +pub const SYS_sync_file_range2: c_int = 84; +pub const SYS_sync_file_range: c_int = 84; +pub const SYS_syncfs: c_int = 267; +pub const SYS_syscalls: c_int = 1080; +pub const SYS__sysctl: c_int = 1078; +pub const SYS_sysinfo: c_int = 179; +pub const SYS_syslog: c_int = 116; +pub const SYS_tee: c_int = 77; +pub const SYS_tgkill: c_int = 131; +pub const SYS_time: c_int = 1062; +pub const SYS_timer_create: c_int = 107; +pub const SYS_timer_delete: c_int = 111; +pub const SYS_timerfd_create: c_int = 85; +pub const SYS_timerfd_gettime: c_int = 87; +pub const SYS_timerfd_settime: c_int = 86; +pub const SYS_timer_getoverrun: c_int = 109; +pub const SYS_timer_gettime: c_int = 108; +pub const SYS_timer_settime: c_int = 110; +pub const SYS_times: c_int = 153; +pub const SYS_tkill: c_int = 130; +pub const SYS_truncate64: c_int = 45; +pub const SYS_truncate: c_int = 45; +pub const SYS_umask: c_int = 166; +pub const SYS_umount2: c_int = 39; +pub const SYS_umount: c_int = 1076; +pub const SYS_uname: c_int = 160; +pub const SYS_unlinkat: c_int = 35; +pub const SYS_unlink: c_int = 1026; +pub const SYS_unshare: c_int = 97; +pub const SYS_uselib: c_int = 1077; +pub const SYS_ustat: c_int = 1070; +pub const SYS_utime: c_int = 1063; +pub const SYS_utimensat: c_int = 88; +pub const SYS_utimes: c_int = 1037; +pub const SYS_vfork: c_int = 1071; +pub const SYS_vhangup: c_int = 58; +pub const SYS_vmsplice: c_int = 75; +pub const SYS_wait4: c_int = 260; +pub const SYS_waitid: c_int = 95; +pub const SYS_write: c_int = 64; +pub const SYS_writev: c_int = 66; +pub const SYS_statx: c_int = 291; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_futex_waitv: c_long = 449; +pub const TIOCM_LOOP: c_int = 32768; +pub const TIOCM_OUT1: c_int = 8192; +pub const TIOCM_OUT2: c_int = 16384; +pub const TIOCSER_TEMT: c_int = 1; +pub const TOSTOP: crate::tcflag_t = 256; +pub const VEOF: c_int = 4; +pub const VEOL2: c_int = 16; +pub const VEOL: c_int = 11; +pub const VMIN: c_int = 6; +pub const CBAUD: crate::tcflag_t = 4111; +pub const CIBAUD: crate::tcflag_t = 269418496; +pub const CLOCAL: crate::tcflag_t = 2048; +pub const CREAD: crate::tcflag_t = 128; +pub const CS6: crate::tcflag_t = 16; +pub const CS7: crate::tcflag_t = 32; +pub const CS8: crate::tcflag_t = 48; +pub const CSIZE: crate::tcflag_t = 48; +pub const CSTOPB: crate::tcflag_t = 64; +pub const HUPCL: crate::tcflag_t = 1024; +pub const PARENB: crate::tcflag_t = 256; +pub const PARODD: crate::tcflag_t = 512; +pub const ECHOCTL: crate::tcflag_t = 512; +pub const ECHOE: crate::tcflag_t = 16; +pub const ECHOK: crate::tcflag_t = 32; +pub const ECHOKE: crate::tcflag_t = 2048; +pub const ECHONL: crate::tcflag_t = 64; +pub const ECHOPRT: crate::tcflag_t = 1024; +pub const ICANON: crate::tcflag_t = 2; +pub const ISIG: crate::tcflag_t = 1; +pub const IXOFF: crate::tcflag_t = 4096; +pub const IXON: crate::tcflag_t = 1024; +pub const NOFLSH: crate::tcflag_t = 128; +pub const PENDIN: crate::tcflag_t = 16384; +pub const BSDLY: crate::tcflag_t = 8192; +pub const CRDLY: crate::tcflag_t = 1536; +pub const FFDLY: crate::tcflag_t = 32768; +pub const NLDLY: crate::tcflag_t = 256; +pub const OLCUC: crate::tcflag_t = 2; +pub const ONLCR: crate::tcflag_t = 4; +pub const TABDLY: crate::tcflag_t = 6144; +pub const VTDLY: crate::tcflag_t = 16384; +pub const XTABS: crate::tcflag_t = 6144; +pub const BS1: crate::tcflag_t = 8192; +pub const CBAUDEX: crate::tcflag_t = 4096; +pub const CR1: crate::tcflag_t = 512; +pub const CR2: crate::tcflag_t = 1024; +pub const CR3: crate::tcflag_t = 1536; +pub const FF1: crate::tcflag_t = 32768; +pub const TAB1: crate::tcflag_t = 2048; +pub const TAB2: crate::tcflag_t = 4096; +pub const TAB3: crate::tcflag_t = 6144; +pub const VT1: crate::tcflag_t = 16384; +pub const VDISCARD: usize = 13; +pub const VREPRINT: usize = 12; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VSWTC: usize = 7; +pub const VTIME: usize = 5; +pub const VWERASE: usize = 14; +pub const B57600: crate::speed_t = 4097; +pub const B115200: crate::speed_t = 4098; +pub const B230400: crate::speed_t = 4099; +pub const B460800: crate::speed_t = 4100; +pub const B500000: crate::speed_t = 4101; +pub const B576000: crate::speed_t = 4102; +pub const B921600: crate::speed_t = 4103; +pub const B1000000: crate::speed_t = 4104; +pub const B1152000: crate::speed_t = 4105; +pub const B1500000: crate::speed_t = 4106; +pub const B2000000: crate::speed_t = 4107; +pub const B2500000: crate::speed_t = 4108; +pub const B3000000: crate::speed_t = 4109; +pub const B3500000: crate::speed_t = 4110; +pub const B4000000: crate::speed_t = 4111; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mips/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mips/mod.rs new file mode 100644 index 00000000000000..7edcf573d2790d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mips/mod.rs @@ -0,0 +1,878 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = c_int; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + __st_padding1: Padding<[c_long; 2]>, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __st_padding2: Padding<[c_long; 2]>, + pub st_size: off_t, + + #[cfg(musl32_time64)] + __st_atim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_mtim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_ctim32: Padding<__c_anonymous_timespec32>, + + #[cfg(musl_v1_2_3)] + pub st_blksize: crate::blksize_t, + #[cfg(musl_v1_2_3)] + __st_padding3: Padding, + #[cfg(musl_v1_2_3)] + pub st_blocks: crate::blkcnt_t, + + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + pub st_atime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad1: Padding, + pub st_mtime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad1: Padding, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad2: Padding, + pub st_ctime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad2: Padding, + + #[cfg(not(musl_v1_2_3))] + pub st_blksize: crate::blksize_t, + #[cfg(not(musl_v1_2_3))] + __st_padding3: Padding, + #[cfg(not(musl_v1_2_3))] + pub st_blocks: crate::blkcnt_t, + + #[cfg(not(musl_v1_2_3))] + __st_padding4: Padding<[c_long; 14]>, + #[cfg(musl_v1_2_3)] + __st_padding4: Padding<[c_long; 2]>, + } + + struct __c_anonymous_timespec32 { + __tv_sec: c_long, + __tv_nsec: c_long, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + #[cfg(not(musl32_time64))] + pub shm_atime: crate::time_t, + #[cfg(not(musl32_time64))] + pub shm_dtime: crate::time_t, + #[cfg(not(musl32_time64))] + pub shm_ctime: crate::time_t, + #[cfg(musl32_time64)] + __shm_atime_lo: Padding, + #[cfg(musl32_time64)] + __shm_dtime_lo: Padding, + #[cfg(musl32_time64)] + __shm_ctime_lo: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + #[cfg(not(musl32_time64))] + __pad1: Padding, + #[cfg(not(musl32_time64))] + __pad2: Padding, + + #[cfg(musl32_time64)] + __shm_atime_hi: Padding, + #[cfg(musl32_time64)] + __shm_dtime_hi: Padding, + #[cfg(musl32_time64)] + __shm_ctime_hi: Padding, + #[cfg(musl32_time64)] + __pad1: Padding, + #[cfg(musl32_time64)] + pub shm_atime: crate::time_t, + #[cfg(musl32_time64)] + pub shm_dtime: crate::time_t, + #[cfg(musl32_time64)] + pub shm_ctime: crate::time_t, + } + + pub struct statfs { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 5], + } + + pub struct statfs64 { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 5], + } +} + +cfg_if! { + if #[cfg(musl32_time64)] { + s! { + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + + #[cfg(target_endian = "big")] + __msg_stime_hi: Padding, + #[cfg(target_endian = "big")] + __msg_stime_lo: Padding, + #[cfg(target_endian = "big")] + __msg_rtime_hi: Padding, + #[cfg(target_endian = "big")] + __msg_rtime_lo: Padding, + #[cfg(target_endian = "big")] + __msg_ctime_hi: Padding, + #[cfg(target_endian = "big")] + __msg_ctime_lo: Padding, + + #[cfg(target_endian = "little")] + __msg_stime_lo: Padding, + #[cfg(target_endian = "little")] + __msg_stime_hi: Padding, + #[cfg(target_endian = "little")] + __msg_rtime_lo: Padding, + #[cfg(target_endian = "little")] + __msg_rtime_hi: Padding, + #[cfg(target_endian = "little")] + __msg_ctime_lo: Padding, + #[cfg(target_endian = "little")] + __msg_ctime_hi: Padding, + + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + } + } + } else { + s! { + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + + #[cfg(target_endian = "big")] + __unused1: Padding, + #[cfg(target_endian = "big")] + pub msg_stime: crate::time_t, + #[cfg(target_endian = "big")] + __unused2: Padding, + #[cfg(target_endian = "big")] + pub msg_rtime: crate::time_t, + #[cfg(target_endian = "big")] + __unused3: Padding, + #[cfg(target_endian = "big")] + pub msg_ctime: crate::time_t, + + #[cfg(target_endian = "little")] + pub msg_stime: crate::time_t, + #[cfg(target_endian = "little")] + __unused1: Padding, + #[cfg(target_endian = "little")] + pub msg_rtime: crate::time_t, + #[cfg(target_endian = "little")] + __unused2: Padding, + #[cfg(target_endian = "little")] + pub msg_ctime: crate::time_t, + #[cfg(target_endian = "little")] + __unused3: Padding, + + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } + } + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [f32; 4], + } +} + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const O_DIRECT: c_int = 0o100000; +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_NOFOLLOW: c_int = 0o400000; +pub const O_ASYNC: c_int = 0o10000; +pub const O_LARGEFILE: c_int = 0x2000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const O_APPEND: c_int = 0o010; +pub const O_CREAT: c_int = 0o400; +pub const O_EXCL: c_int = 0o2000; +pub const O_NOCTTY: c_int = 0o4000; +pub const O_NONBLOCK: c_int = 0o200; +pub const O_SYNC: c_int = 0o40020; +pub const O_RSYNC: c_int = 0o40020; +pub const O_DSYNC: c_int = 0o020; + +pub const MAP_ANON: c_int = 0x800; +pub const MAP_GROWSDOWN: c_int = 0x1000; +pub const MAP_DENYWRITE: c_int = 0x2000; +pub const MAP_EXECUTABLE: c_int = 0x4000; +pub const MAP_LOCKED: c_int = 0x8000; +pub const MAP_NORESERVE: c_int = 0x0400; +pub const MAP_POPULATE: c_int = 0x10000; +pub const MAP_NONBLOCK: c_int = 0x20000; +pub const MAP_STACK: c_int = 0x40000; +pub const MAP_HUGETLB: c_int = 0x80000; + +pub const EDEADLK: c_int = 45; +pub const ENAMETOOLONG: c_int = 78; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 89; +pub const ENOTEMPTY: c_int = 93; +pub const ELOOP: c_int = 90; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EMULTIHOP: c_int = 74; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EBADMSG: c_int = 77; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; +pub const EUCLEAN: c_int = 135; +pub const ENOTNAM: c_int = 137; +pub const ENAVAIL: c_int = 138; +pub const EISNAM: c_int = 139; +pub const EREMOTEIO: c_int = 140; +pub const EDQUOT: c_int = 1133; +pub const ENOMEDIUM: c_int = 159; +pub const EMEDIUMTYPE: c_int = 160; +pub const ECANCELED: c_int = 158; +pub const ENOKEY: c_int = 161; +pub const EKEYEXPIRED: c_int = 162; +pub const EKEYREVOKED: c_int = 163; +pub const EKEYREJECTED: c_int = 164; +pub const EOWNERDEAD: c_int = 165; +pub const ENOTRECOVERABLE: c_int = 166; +pub const EHWPOISON: c_int = 168; +pub const ERFKILL: c_int = 167; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 8; +pub const SA_NOCLDWAIT: c_int = 0x10000; + +pub const SIGEMT: c_int = 7; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = 22; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = crate::SIGIO; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; + +pub const EXTPROC: crate::tcflag_t = 0o200000; + +pub const F_GETLK: c_int = 33; +pub const F_GETOWN: c_int = 23; +pub const F_SETLK: c_int = 34; +pub const F_SETLKW: c_int = 35; +pub const F_SETOWN: c_int = 24; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0o000400; +pub const TOSTOP: crate::tcflag_t = 0o100000; +pub const FLUSHO: crate::tcflag_t = 0o020000; + +pub const POLLWRNORM: c_short = 0x4; +pub const POLLWRBAND: c_short = 0x100; + +pub const SYS_syscall: c_long = 4000 + 0; +pub const SYS_exit: c_long = 4000 + 1; +pub const SYS_fork: c_long = 4000 + 2; +pub const SYS_read: c_long = 4000 + 3; +pub const SYS_write: c_long = 4000 + 4; +pub const SYS_open: c_long = 4000 + 5; +pub const SYS_close: c_long = 4000 + 6; +pub const SYS_waitpid: c_long = 4000 + 7; +pub const SYS_creat: c_long = 4000 + 8; +pub const SYS_link: c_long = 4000 + 9; +pub const SYS_unlink: c_long = 4000 + 10; +pub const SYS_execve: c_long = 4000 + 11; +pub const SYS_chdir: c_long = 4000 + 12; +pub const SYS_time: c_long = 4000 + 13; +pub const SYS_mknod: c_long = 4000 + 14; +pub const SYS_chmod: c_long = 4000 + 15; +pub const SYS_lchown: c_long = 4000 + 16; +pub const SYS_break: c_long = 4000 + 17; +pub const SYS_lseek: c_long = 4000 + 19; +pub const SYS_getpid: c_long = 4000 + 20; +pub const SYS_mount: c_long = 4000 + 21; +pub const SYS_umount: c_long = 4000 + 22; +pub const SYS_setuid: c_long = 4000 + 23; +pub const SYS_getuid: c_long = 4000 + 24; +pub const SYS_stime: c_long = 4000 + 25; +pub const SYS_ptrace: c_long = 4000 + 26; +pub const SYS_alarm: c_long = 4000 + 27; +pub const SYS_pause: c_long = 4000 + 29; +pub const SYS_utime: c_long = 4000 + 30; +pub const SYS_stty: c_long = 4000 + 31; +pub const SYS_gtty: c_long = 4000 + 32; +pub const SYS_access: c_long = 4000 + 33; +pub const SYS_nice: c_long = 4000 + 34; +pub const SYS_ftime: c_long = 4000 + 35; +pub const SYS_sync: c_long = 4000 + 36; +pub const SYS_kill: c_long = 4000 + 37; +pub const SYS_rename: c_long = 4000 + 38; +pub const SYS_mkdir: c_long = 4000 + 39; +pub const SYS_rmdir: c_long = 4000 + 40; +pub const SYS_dup: c_long = 4000 + 41; +pub const SYS_pipe: c_long = 4000 + 42; +pub const SYS_times: c_long = 4000 + 43; +pub const SYS_prof: c_long = 4000 + 44; +pub const SYS_brk: c_long = 4000 + 45; +pub const SYS_setgid: c_long = 4000 + 46; +pub const SYS_getgid: c_long = 4000 + 47; +pub const SYS_signal: c_long = 4000 + 48; +pub const SYS_geteuid: c_long = 4000 + 49; +pub const SYS_getegid: c_long = 4000 + 50; +pub const SYS_acct: c_long = 4000 + 51; +pub const SYS_umount2: c_long = 4000 + 52; +pub const SYS_lock: c_long = 4000 + 53; +pub const SYS_ioctl: c_long = 4000 + 54; +pub const SYS_fcntl: c_long = 4000 + 55; +pub const SYS_mpx: c_long = 4000 + 56; +pub const SYS_setpgid: c_long = 4000 + 57; +pub const SYS_ulimit: c_long = 4000 + 58; +pub const SYS_umask: c_long = 4000 + 60; +pub const SYS_chroot: c_long = 4000 + 61; +pub const SYS_ustat: c_long = 4000 + 62; +pub const SYS_dup2: c_long = 4000 + 63; +pub const SYS_getppid: c_long = 4000 + 64; +pub const SYS_getpgrp: c_long = 4000 + 65; +pub const SYS_setsid: c_long = 4000 + 66; +pub const SYS_sigaction: c_long = 4000 + 67; +pub const SYS_sgetmask: c_long = 4000 + 68; +pub const SYS_ssetmask: c_long = 4000 + 69; +pub const SYS_setreuid: c_long = 4000 + 70; +pub const SYS_setregid: c_long = 4000 + 71; +pub const SYS_sigsuspend: c_long = 4000 + 72; +pub const SYS_sigpending: c_long = 4000 + 73; +pub const SYS_sethostname: c_long = 4000 + 74; +pub const SYS_setrlimit: c_long = 4000 + 75; +pub const SYS_getrlimit: c_long = 4000 + 76; +pub const SYS_getrusage: c_long = 4000 + 77; +pub const SYS_gettimeofday: c_long = 4000 + 78; +pub const SYS_settimeofday: c_long = 4000 + 79; +pub const SYS_getgroups: c_long = 4000 + 80; +pub const SYS_setgroups: c_long = 4000 + 81; +pub const SYS_symlink: c_long = 4000 + 83; +pub const SYS_readlink: c_long = 4000 + 85; +pub const SYS_uselib: c_long = 4000 + 86; +pub const SYS_swapon: c_long = 4000 + 87; +pub const SYS_reboot: c_long = 4000 + 88; +pub const SYS_readdir: c_long = 4000 + 89; +pub const SYS_mmap: c_long = 4000 + 90; +pub const SYS_munmap: c_long = 4000 + 91; +pub const SYS_truncate: c_long = 4000 + 92; +pub const SYS_ftruncate: c_long = 4000 + 93; +pub const SYS_fchmod: c_long = 4000 + 94; +pub const SYS_fchown: c_long = 4000 + 95; +pub const SYS_getpriority: c_long = 4000 + 96; +pub const SYS_setpriority: c_long = 4000 + 97; +pub const SYS_profil: c_long = 4000 + 98; +pub const SYS_statfs: c_long = 4000 + 99; +pub const SYS_fstatfs: c_long = 4000 + 100; +pub const SYS_ioperm: c_long = 4000 + 101; +pub const SYS_socketcall: c_long = 4000 + 102; +pub const SYS_syslog: c_long = 4000 + 103; +pub const SYS_setitimer: c_long = 4000 + 104; +pub const SYS_getitimer: c_long = 4000 + 105; +pub const SYS_stat: c_long = 4000 + 106; +pub const SYS_lstat: c_long = 4000 + 107; +pub const SYS_fstat: c_long = 4000 + 108; +pub const SYS_iopl: c_long = 4000 + 110; +pub const SYS_vhangup: c_long = 4000 + 111; +pub const SYS_idle: c_long = 4000 + 112; +pub const SYS_vm86: c_long = 4000 + 113; +pub const SYS_wait4: c_long = 4000 + 114; +pub const SYS_swapoff: c_long = 4000 + 115; +pub const SYS_sysinfo: c_long = 4000 + 116; +pub const SYS_ipc: c_long = 4000 + 117; +pub const SYS_fsync: c_long = 4000 + 118; +pub const SYS_sigreturn: c_long = 4000 + 119; +pub const SYS_clone: c_long = 4000 + 120; +pub const SYS_setdomainname: c_long = 4000 + 121; +pub const SYS_uname: c_long = 4000 + 122; +pub const SYS_modify_ldt: c_long = 4000 + 123; +pub const SYS_adjtimex: c_long = 4000 + 124; +pub const SYS_mprotect: c_long = 4000 + 125; +pub const SYS_sigprocmask: c_long = 4000 + 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 4000 + 127; +pub const SYS_init_module: c_long = 4000 + 128; +pub const SYS_delete_module: c_long = 4000 + 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 4000 + 130; +pub const SYS_quotactl: c_long = 4000 + 131; +pub const SYS_getpgid: c_long = 4000 + 132; +pub const SYS_fchdir: c_long = 4000 + 133; +pub const SYS_bdflush: c_long = 4000 + 134; +pub const SYS_sysfs: c_long = 4000 + 135; +pub const SYS_personality: c_long = 4000 + 136; +pub const SYS_afs_syscall: c_long = 4000 + 137; +pub const SYS_setfsuid: c_long = 4000 + 138; +pub const SYS_setfsgid: c_long = 4000 + 139; +pub const SYS__llseek: c_long = 4000 + 140; +pub const SYS_getdents: c_long = 4000 + 141; +pub const SYS_flock: c_long = 4000 + 143; +pub const SYS_msync: c_long = 4000 + 144; +pub const SYS_readv: c_long = 4000 + 145; +pub const SYS_writev: c_long = 4000 + 146; +pub const SYS_cacheflush: c_long = 4000 + 147; +pub const SYS_cachectl: c_long = 4000 + 148; +pub const SYS_sysmips: c_long = 4000 + 149; +pub const SYS_getsid: c_long = 4000 + 151; +pub const SYS_fdatasync: c_long = 4000 + 152; +pub const SYS__sysctl: c_long = 4000 + 153; +pub const SYS_mlock: c_long = 4000 + 154; +pub const SYS_munlock: c_long = 4000 + 155; +pub const SYS_mlockall: c_long = 4000 + 156; +pub const SYS_munlockall: c_long = 4000 + 157; +pub const SYS_sched_setparam: c_long = 4000 + 158; +pub const SYS_sched_getparam: c_long = 4000 + 159; +pub const SYS_sched_setscheduler: c_long = 4000 + 160; +pub const SYS_sched_getscheduler: c_long = 4000 + 161; +pub const SYS_sched_yield: c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: c_long = 4000 + 165; +pub const SYS_nanosleep: c_long = 4000 + 166; +pub const SYS_mremap: c_long = 4000 + 167; +pub const SYS_accept: c_long = 4000 + 168; +pub const SYS_bind: c_long = 4000 + 169; +pub const SYS_connect: c_long = 4000 + 170; +pub const SYS_getpeername: c_long = 4000 + 171; +pub const SYS_getsockname: c_long = 4000 + 172; +pub const SYS_getsockopt: c_long = 4000 + 173; +pub const SYS_listen: c_long = 4000 + 174; +pub const SYS_recv: c_long = 4000 + 175; +pub const SYS_recvfrom: c_long = 4000 + 176; +pub const SYS_recvmsg: c_long = 4000 + 177; +pub const SYS_send: c_long = 4000 + 178; +pub const SYS_sendmsg: c_long = 4000 + 179; +pub const SYS_sendto: c_long = 4000 + 180; +pub const SYS_setsockopt: c_long = 4000 + 181; +pub const SYS_shutdown: c_long = 4000 + 182; +pub const SYS_socket: c_long = 4000 + 183; +pub const SYS_socketpair: c_long = 4000 + 184; +pub const SYS_setresuid: c_long = 4000 + 185; +pub const SYS_getresuid: c_long = 4000 + 186; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 4000 + 187; +pub const SYS_poll: c_long = 4000 + 188; +pub const SYS_nfsservctl: c_long = 4000 + 189; +pub const SYS_setresgid: c_long = 4000 + 190; +pub const SYS_getresgid: c_long = 4000 + 191; +pub const SYS_prctl: c_long = 4000 + 192; +pub const SYS_rt_sigreturn: c_long = 4000 + 193; +pub const SYS_rt_sigaction: c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: c_long = 4000 + 195; +pub const SYS_rt_sigpending: c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: c_long = 4000 + 199; +pub const SYS_chown: c_long = 4000 + 202; +pub const SYS_getcwd: c_long = 4000 + 203; +pub const SYS_capget: c_long = 4000 + 204; +pub const SYS_capset: c_long = 4000 + 205; +pub const SYS_sigaltstack: c_long = 4000 + 206; +pub const SYS_sendfile: c_long = 4000 + 207; +pub const SYS_getpmsg: c_long = 4000 + 208; +pub const SYS_putpmsg: c_long = 4000 + 209; +pub const SYS_mmap2: c_long = 4000 + 210; +pub const SYS_truncate64: c_long = 4000 + 211; +pub const SYS_ftruncate64: c_long = 4000 + 212; +pub const SYS_stat64: c_long = 4000 + 213; +pub const SYS_lstat64: c_long = 4000 + 214; +pub const SYS_fstat64: c_long = 4000 + 215; +pub const SYS_pivot_root: c_long = 4000 + 216; +pub const SYS_mincore: c_long = 4000 + 217; +pub const SYS_madvise: c_long = 4000 + 218; +pub const SYS_getdents64: c_long = 4000 + 219; +pub const SYS_fcntl64: c_long = 4000 + 220; +pub const SYS_gettid: c_long = 4000 + 222; +pub const SYS_readahead: c_long = 4000 + 223; +pub const SYS_setxattr: c_long = 4000 + 224; +pub const SYS_lsetxattr: c_long = 4000 + 225; +pub const SYS_fsetxattr: c_long = 4000 + 226; +pub const SYS_getxattr: c_long = 4000 + 227; +pub const SYS_lgetxattr: c_long = 4000 + 228; +pub const SYS_fgetxattr: c_long = 4000 + 229; +pub const SYS_listxattr: c_long = 4000 + 230; +pub const SYS_llistxattr: c_long = 4000 + 231; +pub const SYS_flistxattr: c_long = 4000 + 232; +pub const SYS_removexattr: c_long = 4000 + 233; +pub const SYS_lremovexattr: c_long = 4000 + 234; +pub const SYS_fremovexattr: c_long = 4000 + 235; +pub const SYS_tkill: c_long = 4000 + 236; +pub const SYS_sendfile64: c_long = 4000 + 237; +pub const SYS_futex: c_long = 4000 + 238; +pub const SYS_sched_setaffinity: c_long = 4000 + 239; +pub const SYS_sched_getaffinity: c_long = 4000 + 240; +pub const SYS_io_setup: c_long = 4000 + 241; +pub const SYS_io_destroy: c_long = 4000 + 242; +pub const SYS_io_getevents: c_long = 4000 + 243; +pub const SYS_io_submit: c_long = 4000 + 244; +pub const SYS_io_cancel: c_long = 4000 + 245; +pub const SYS_exit_group: c_long = 4000 + 246; +pub const SYS_lookup_dcookie: c_long = 4000 + 247; +pub const SYS_epoll_create: c_long = 4000 + 248; +pub const SYS_epoll_ctl: c_long = 4000 + 249; +pub const SYS_epoll_wait: c_long = 4000 + 250; +pub const SYS_remap_file_pages: c_long = 4000 + 251; +pub const SYS_set_tid_address: c_long = 4000 + 252; +pub const SYS_restart_syscall: c_long = 4000 + 253; +pub const SYS_statfs64: c_long = 4000 + 255; +pub const SYS_fstatfs64: c_long = 4000 + 256; +pub const SYS_timer_create: c_long = 4000 + 257; +pub const SYS_timer_settime: c_long = 4000 + 258; +pub const SYS_timer_gettime: c_long = 4000 + 259; +pub const SYS_timer_getoverrun: c_long = 4000 + 260; +pub const SYS_timer_delete: c_long = 4000 + 261; +pub const SYS_clock_settime: c_long = 4000 + 262; +pub const SYS_clock_gettime: c_long = 4000 + 263; +pub const SYS_clock_getres: c_long = 4000 + 264; +pub const SYS_clock_nanosleep: c_long = 4000 + 265; +pub const SYS_tgkill: c_long = 4000 + 266; +pub const SYS_utimes: c_long = 4000 + 267; +pub const SYS_mbind: c_long = 4000 + 268; +pub const SYS_get_mempolicy: c_long = 4000 + 269; +pub const SYS_set_mempolicy: c_long = 4000 + 270; +pub const SYS_mq_open: c_long = 4000 + 271; +pub const SYS_mq_unlink: c_long = 4000 + 272; +pub const SYS_mq_timedsend: c_long = 4000 + 273; +pub const SYS_mq_timedreceive: c_long = 4000 + 274; +pub const SYS_mq_notify: c_long = 4000 + 275; +pub const SYS_mq_getsetattr: c_long = 4000 + 276; +pub const SYS_vserver: c_long = 4000 + 277; +pub const SYS_waitid: c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: c_long = 4000 + 279; */ +pub const SYS_add_key: c_long = 4000 + 280; +pub const SYS_request_key: c_long = 4000 + 281; +pub const SYS_keyctl: c_long = 4000 + 282; +pub const SYS_set_thread_area: c_long = 4000 + 283; +pub const SYS_inotify_init: c_long = 4000 + 284; +pub const SYS_inotify_add_watch: c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: c_long = 4000 + 286; +pub const SYS_migrate_pages: c_long = 4000 + 287; +pub const SYS_openat: c_long = 4000 + 288; +pub const SYS_mkdirat: c_long = 4000 + 289; +pub const SYS_mknodat: c_long = 4000 + 290; +pub const SYS_fchownat: c_long = 4000 + 291; +pub const SYS_futimesat: c_long = 4000 + 292; +pub const SYS_unlinkat: c_long = 4000 + 294; +pub const SYS_renameat: c_long = 4000 + 295; +pub const SYS_linkat: c_long = 4000 + 296; +pub const SYS_symlinkat: c_long = 4000 + 297; +pub const SYS_readlinkat: c_long = 4000 + 298; +pub const SYS_fchmodat: c_long = 4000 + 299; +pub const SYS_faccessat: c_long = 4000 + 300; +pub const SYS_pselect6: c_long = 4000 + 301; +pub const SYS_ppoll: c_long = 4000 + 302; +pub const SYS_unshare: c_long = 4000 + 303; +pub const SYS_splice: c_long = 4000 + 304; +pub const SYS_sync_file_range: c_long = 4000 + 305; +pub const SYS_tee: c_long = 4000 + 306; +pub const SYS_vmsplice: c_long = 4000 + 307; +pub const SYS_move_pages: c_long = 4000 + 308; +pub const SYS_set_robust_list: c_long = 4000 + 309; +pub const SYS_get_robust_list: c_long = 4000 + 310; +pub const SYS_kexec_load: c_long = 4000 + 311; +pub const SYS_getcpu: c_long = 4000 + 312; +pub const SYS_epoll_pwait: c_long = 4000 + 313; +pub const SYS_ioprio_set: c_long = 4000 + 314; +pub const SYS_ioprio_get: c_long = 4000 + 315; +pub const SYS_utimensat: c_long = 4000 + 316; +pub const SYS_signalfd: c_long = 4000 + 317; +pub const SYS_timerfd: c_long = 4000 + 318; +pub const SYS_eventfd: c_long = 4000 + 319; +pub const SYS_fallocate: c_long = 4000 + 320; +pub const SYS_timerfd_create: c_long = 4000 + 321; +pub const SYS_timerfd_gettime: c_long = 4000 + 322; +pub const SYS_timerfd_settime: c_long = 4000 + 323; +pub const SYS_signalfd4: c_long = 4000 + 324; +pub const SYS_eventfd2: c_long = 4000 + 325; +pub const SYS_epoll_create1: c_long = 4000 + 326; +pub const SYS_dup3: c_long = 4000 + 327; +pub const SYS_pipe2: c_long = 4000 + 328; +pub const SYS_inotify_init1: c_long = 4000 + 329; +pub const SYS_preadv: c_long = 4000 + 330; +pub const SYS_pwritev: c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: c_long = 4000 + 332; +pub const SYS_perf_event_open: c_long = 4000 + 333; +pub const SYS_accept4: c_long = 4000 + 334; +pub const SYS_recvmmsg: c_long = 4000 + 335; +pub const SYS_fanotify_init: c_long = 4000 + 336; +pub const SYS_fanotify_mark: c_long = 4000 + 337; +pub const SYS_prlimit64: c_long = 4000 + 338; +pub const SYS_name_to_handle_at: c_long = 4000 + 339; +pub const SYS_open_by_handle_at: c_long = 4000 + 340; +pub const SYS_clock_adjtime: c_long = 4000 + 341; +pub const SYS_syncfs: c_long = 4000 + 342; +pub const SYS_sendmmsg: c_long = 4000 + 343; +pub const SYS_setns: c_long = 4000 + 344; +pub const SYS_process_vm_readv: c_long = 4000 + 345; +pub const SYS_process_vm_writev: c_long = 4000 + 346; +pub const SYS_kcmp: c_long = 4000 + 347; +pub const SYS_finit_module: c_long = 4000 + 348; +pub const SYS_sched_setattr: c_long = 4000 + 349; +pub const SYS_sched_getattr: c_long = 4000 + 350; +pub const SYS_renameat2: c_long = 4000 + 351; +pub const SYS_seccomp: c_long = 4000 + 352; +pub const SYS_getrandom: c_long = 4000 + 353; +pub const SYS_memfd_create: c_long = 4000 + 354; +pub const SYS_bpf: c_long = 4000 + 355; +pub const SYS_execveat: c_long = 4000 + 356; +pub const SYS_userfaultfd: c_long = 4000 + 357; +pub const SYS_membarrier: c_long = 4000 + 358; +pub const SYS_mlock2: c_long = 4000 + 359; +pub const SYS_copy_file_range: c_long = 4000 + 360; +pub const SYS_preadv2: c_long = 4000 + 361; +pub const SYS_pwritev2: c_long = 4000 + 362; +pub const SYS_pkey_mprotect: c_long = 4000 + 363; +pub const SYS_pkey_alloc: c_long = 4000 + 364; +pub const SYS_pkey_free: c_long = 4000 + 365; +pub const SYS_statx: c_long = 4000 + 366; +pub const SYS_pidfd_send_signal: c_long = 4000 + 424; +pub const SYS_io_uring_setup: c_long = 4000 + 425; +pub const SYS_io_uring_enter: c_long = 4000 + 426; +pub const SYS_io_uring_register: c_long = 4000 + 427; +pub const SYS_open_tree: c_long = 4000 + 428; +pub const SYS_move_mount: c_long = 4000 + 429; +pub const SYS_fsopen: c_long = 4000 + 430; +pub const SYS_fsconfig: c_long = 4000 + 431; +pub const SYS_fsmount: c_long = 4000 + 432; +pub const SYS_fspick: c_long = 4000 + 433; +pub const SYS_pidfd_open: c_long = 4000 + 434; +pub const SYS_clone3: c_long = 4000 + 435; +pub const SYS_close_range: c_long = 4000 + 436; +pub const SYS_openat2: c_long = 4000 + 437; +pub const SYS_pidfd_getfd: c_long = 4000 + 438; +pub const SYS_faccessat2: c_long = 4000 + 439; +pub const SYS_process_madvise: c_long = 4000 + 440; +pub const SYS_epoll_pwait2: c_long = 4000 + 441; +pub const SYS_mount_setattr: c_long = 4000 + 442; +pub const SYS_quotactl_fd: c_long = 4000 + 443; +pub const SYS_landlock_create_ruleset: c_long = 4000 + 444; +pub const SYS_landlock_add_rule: c_long = 4000 + 445; +pub const SYS_landlock_restrict_self: c_long = 4000 + 446; +pub const SYS_memfd_secret: c_long = 4000 + 447; +pub const SYS_process_mrelease: c_long = 4000 + 448; +pub const SYS_futex_waitv: c_long = 4000 + 449; +pub const SYS_set_mempolicy_home_node: c_long = 4000 + 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mod.rs new file mode 100644 index 00000000000000..ac76d3c6597003 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/mod.rs @@ -0,0 +1,49 @@ +use crate::prelude::*; + +pub type nlink_t = u32; +pub type blksize_t = c_long; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; +pub type regoff_t = c_int; + +s! { + pub struct pthread_attr_t { + __size: [u32; 9], + } + + pub struct sigset_t { + __val: [c_ulong; 32], + } + + pub struct sem_t { + __val: [c_int; 4], + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; + +cfg_if! { + if #[cfg(any(target_arch = "x86"))] { + mod x86; + pub use self::x86::*; + } else if #[cfg(any(target_arch = "mips"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(any(target_arch = "arm"))] { + mod arm; + pub use self::arm::*; + } else if #[cfg(any(target_arch = "powerpc"))] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(any(target_arch = "hexagon"))] { + mod hexagon; + pub use self::hexagon::*; + } else if #[cfg(any(target_arch = "riscv32"))] { + mod riscv32; + pub use self::riscv32::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/powerpc.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/powerpc.rs new file mode 100644 index 00000000000000..f0d92c0e936e77 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/powerpc.rs @@ -0,0 +1,835 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; + +pub type stat64 = stat; + +s! { + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_line: crate::cc_t, + pub __c_ispeed: crate::speed_t, + pub __c_ospeed: crate::speed_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __st_rdev_padding: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + + #[cfg(musl32_time64)] + __st_atim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_mtim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_ctim32: Padding<__c_anonymous_timespec32>, + + #[cfg(musl_v1_2_3)] + __unused: Padding<[c_long; 2]>, + + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + pub st_atime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad1: Padding, + pub st_mtime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad1: Padding, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad2: Padding, + pub st_ctime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad2: Padding, + + #[cfg(not(musl_v1_2_3))] + __unused: Padding<[c_long; 2]>, + } + + struct __c_anonymous_timespec32 { + __tv_sec: c_long, + __tv_nsec: c_long, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __pad1: Padding, + __pad2: Padding, + __pad3: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + + #[cfg(musl32_time64)] + __shm_atime_hi: Padding, + #[cfg(musl32_time64)] + __shm_atime_lo: Padding, + #[cfg(musl32_time64)] + __shm_dtime_hi: Padding, + #[cfg(musl32_time64)] + __shm_dtime_lo: Padding, + #[cfg(musl32_time64)] + __shm_ctime_hi: Padding, + #[cfg(musl32_time64)] + __shm_ctime_lo: Padding, + + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub shm_atime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub shm_dtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + #[cfg(not(musl32_time64))] + pub shm_ctime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused4: Padding, + + #[cfg(musl32_time64)] + __pad1: Padding, + + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + #[cfg(not(musl32_time64))] + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + pub shm_atime: crate::time_t, + #[cfg(musl32_time64)] + pub shm_dtime: crate::time_t, + #[cfg(musl32_time64)] + pub shm_ctime: crate::time_t, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + + #[cfg(musl32_time64)] + __msg_stime_hi: Padding, + #[cfg(musl32_time64)] + __msg_stime_lo: Padding, + #[cfg(musl32_time64)] + __msg_rtime_hi: Padding, + #[cfg(musl32_time64)] + __msg_rtime_lo: Padding, + #[cfg(musl32_time64)] + __msg_ctime_hi: Padding, + #[cfg(musl32_time64)] + __msg_ctime_lo: Padding, + + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub msg_stime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub msg_rtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + #[cfg(not(musl32_time64))] + pub msg_ctime: crate::time_t, + + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + pub msg_stime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_rtime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_ctime: crate::time_t, + } +} + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const SIGSTKSZ: size_t = 10240; +pub const MINSIGSTKSZ: size_t = 4096; + +pub const O_DIRECT: c_int = 0x20000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_LARGEFILE: c_int = 0x10000; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; +pub const CBAUD: crate::tcflag_t = 0o0000377; +pub const TAB1: c_int = 0x00000400; +pub const TAB2: c_int = 0x00000800; +pub const TAB3: c_int = 0x00000C00; +pub const CR1: c_int = 0x00001000; +pub const CR2: c_int = 0x00002000; +pub const CR3: c_int = 0x00003000; +pub const FF1: c_int = 0x00004000; +pub const BS1: c_int = 0x00008000; +pub const VT1: c_int = 0x00010000; +pub const VWERASE: usize = 10; +pub const VREPRINT: usize = 11; +pub const VSUSP: usize = 12; +pub const VSTART: usize = 13; +pub const VSTOP: usize = 14; +pub const VDISCARD: usize = 16; +pub const VTIME: usize = 7; +pub const IXON: crate::tcflag_t = 0x00000200; +pub const IXOFF: crate::tcflag_t = 0x00000400; +pub const ONLCR: crate::tcflag_t = 0x00000002; +pub const CSIZE: crate::tcflag_t = 0x00000300; +pub const CS6: crate::tcflag_t = 0x00000100; +pub const CS7: crate::tcflag_t = 0x00000200; +pub const CS8: crate::tcflag_t = 0x00000300; +pub const CSTOPB: crate::tcflag_t = 0x00000400; +pub const CREAD: crate::tcflag_t = 0x00000800; +pub const PARENB: crate::tcflag_t = 0x00001000; +pub const PARODD: crate::tcflag_t = 0x00002000; +pub const HUPCL: crate::tcflag_t = 0x00004000; +pub const CLOCAL: crate::tcflag_t = 0x00008000; +pub const ECHOKE: crate::tcflag_t = 0x00000001; +pub const ECHOE: crate::tcflag_t = 0x00000002; +pub const ECHOK: crate::tcflag_t = 0x00000004; +pub const ECHONL: crate::tcflag_t = 0x00000010; +pub const ECHOPRT: crate::tcflag_t = 0x00000020; +pub const ECHOCTL: crate::tcflag_t = 0x00000040; +pub const ISIG: crate::tcflag_t = 0x00000080; +pub const ICANON: crate::tcflag_t = 0x00000100; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x80000000; +pub const CIBAUD: crate::tcflag_t = 0o00077600000; +pub const CBAUDEX: crate::tcflag_t = 0o000020; +pub const VSWTC: usize = 9; +pub const OLCUC: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o001400; +pub const CRDLY: crate::tcflag_t = 0o030000; +pub const TABDLY: crate::tcflag_t = 0o006000; +pub const BSDLY: crate::tcflag_t = 0o100000; +pub const FFDLY: crate::tcflag_t = 0o040000; +pub const VTDLY: crate::tcflag_t = 0o200000; +pub const XTABS: crate::tcflag_t = 0o006000; +pub const B57600: crate::speed_t = 0o000020; +pub const B115200: crate::speed_t = 0o000021; +pub const B230400: crate::speed_t = 0o000022; +pub const B460800: crate::speed_t = 0o000023; +pub const B500000: crate::speed_t = 0o000024; +pub const B576000: crate::speed_t = 0o000025; +pub const B921600: crate::speed_t = 0o000026; +pub const B1000000: crate::speed_t = 0o000027; +pub const B1152000: crate::speed_t = 0o000030; +pub const B1500000: crate::speed_t = 0o000031; +pub const B2000000: crate::speed_t = 0o000032; +pub const B2500000: crate::speed_t = 0o000033; +pub const B3000000: crate::speed_t = 0o000034; +pub const B3500000: crate::speed_t = 0o000035; +pub const B4000000: crate::speed_t = 0o000036; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x00080; +pub const MAP_NORESERVE: c_int = 0x00040; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const PTRACE_SYSEMU: c_int = 0x1d; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 0x1e; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EDEADLOCK: c_int = 58; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const EXTPROC: crate::tcflag_t = 0x10000000; + +pub const F_GETLK: c_int = 12; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: crate::tcflag_t = 0x00000400; +pub const TOSTOP: crate::tcflag_t = 0x00400000; +pub const FLUSHO: crate::tcflag_t = 0x00800000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 166; +pub const SYS_poll: c_long = 167; +pub const SYS_nfsservctl: c_long = 168; +pub const SYS_setresgid: c_long = 169; +pub const SYS_getresgid: c_long = 170; +pub const SYS_prctl: c_long = 171; +pub const SYS_rt_sigreturn: c_long = 172; +pub const SYS_rt_sigaction: c_long = 173; +pub const SYS_rt_sigprocmask: c_long = 174; +pub const SYS_rt_sigpending: c_long = 175; +pub const SYS_rt_sigtimedwait: c_long = 176; +pub const SYS_rt_sigqueueinfo: c_long = 177; +pub const SYS_rt_sigsuspend: c_long = 178; +pub const SYS_pread64: c_long = 179; +pub const SYS_pwrite64: c_long = 180; +pub const SYS_chown: c_long = 181; +pub const SYS_getcwd: c_long = 182; +pub const SYS_capget: c_long = 183; +pub const SYS_capset: c_long = 184; +pub const SYS_sigaltstack: c_long = 185; +pub const SYS_sendfile: c_long = 186; +pub const SYS_getpmsg: c_long = 187; +pub const SYS_putpmsg: c_long = 188; +pub const SYS_vfork: c_long = 189; +pub const SYS_ugetrlimit: c_long = 190; +pub const SYS_readahead: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_pciconfig_read: c_long = 198; +pub const SYS_pciconfig_write: c_long = 199; +pub const SYS_pciconfig_iobase: c_long = 200; +pub const SYS_multiplexer: c_long = 201; +pub const SYS_getdents64: c_long = 202; +pub const SYS_pivot_root: c_long = 203; +pub const SYS_fcntl64: c_long = 204; +pub const SYS_madvise: c_long = 205; +pub const SYS_mincore: c_long = 206; +pub const SYS_gettid: c_long = 207; +pub const SYS_tkill: c_long = 208; +pub const SYS_setxattr: c_long = 209; +pub const SYS_lsetxattr: c_long = 210; +pub const SYS_fsetxattr: c_long = 211; +pub const SYS_getxattr: c_long = 212; +pub const SYS_lgetxattr: c_long = 213; +pub const SYS_fgetxattr: c_long = 214; +pub const SYS_listxattr: c_long = 215; +pub const SYS_llistxattr: c_long = 216; +pub const SYS_flistxattr: c_long = 217; +pub const SYS_removexattr: c_long = 218; +pub const SYS_lremovexattr: c_long = 219; +pub const SYS_fremovexattr: c_long = 220; +pub const SYS_futex: c_long = 221; +pub const SYS_sched_setaffinity: c_long = 222; +pub const SYS_sched_getaffinity: c_long = 223; +pub const SYS_tuxcall: c_long = 225; +pub const SYS_sendfile64: c_long = 226; +pub const SYS_io_setup: c_long = 227; +pub const SYS_io_destroy: c_long = 228; +pub const SYS_io_getevents: c_long = 229; +pub const SYS_io_submit: c_long = 230; +pub const SYS_io_cancel: c_long = 231; +pub const SYS_set_tid_address: c_long = 232; +pub const SYS_fadvise64: c_long = 233; +pub const SYS_exit_group: c_long = 234; +pub const SYS_lookup_dcookie: c_long = 235; +pub const SYS_epoll_create: c_long = 236; +pub const SYS_epoll_ctl: c_long = 237; +pub const SYS_epoll_wait: c_long = 238; +pub const SYS_remap_file_pages: c_long = 239; +pub const SYS_timer_create: c_long = 240; +pub const SYS_timer_settime: c_long = 241; +pub const SYS_timer_gettime: c_long = 242; +pub const SYS_timer_getoverrun: c_long = 243; +pub const SYS_timer_delete: c_long = 244; +pub const SYS_clock_settime: c_long = 245; +pub const SYS_clock_gettime: c_long = 246; +pub const SYS_clock_getres: c_long = 247; +pub const SYS_clock_nanosleep: c_long = 248; +pub const SYS_swapcontext: c_long = 249; +pub const SYS_tgkill: c_long = 250; +pub const SYS_utimes: c_long = 251; +pub const SYS_statfs64: c_long = 252; +pub const SYS_fstatfs64: c_long = 253; +pub const SYS_fadvise64_64: c_long = 254; +pub const SYS_rtas: c_long = 255; +pub const SYS_sys_debug_setcontext: c_long = 256; +pub const SYS_migrate_pages: c_long = 258; +pub const SYS_mbind: c_long = 259; +pub const SYS_get_mempolicy: c_long = 260; +pub const SYS_set_mempolicy: c_long = 261; +pub const SYS_mq_open: c_long = 262; +pub const SYS_mq_unlink: c_long = 263; +pub const SYS_mq_timedsend: c_long = 264; +pub const SYS_mq_timedreceive: c_long = 265; +pub const SYS_mq_notify: c_long = 266; +pub const SYS_mq_getsetattr: c_long = 267; +pub const SYS_kexec_load: c_long = 268; +pub const SYS_add_key: c_long = 269; +pub const SYS_request_key: c_long = 270; +pub const SYS_keyctl: c_long = 271; +pub const SYS_waitid: c_long = 272; +pub const SYS_ioprio_set: c_long = 273; +pub const SYS_ioprio_get: c_long = 274; +pub const SYS_inotify_init: c_long = 275; +pub const SYS_inotify_add_watch: c_long = 276; +pub const SYS_inotify_rm_watch: c_long = 277; +pub const SYS_spu_run: c_long = 278; +pub const SYS_spu_create: c_long = 279; +pub const SYS_pselect6: c_long = 280; +pub const SYS_ppoll: c_long = 281; +pub const SYS_unshare: c_long = 282; +pub const SYS_splice: c_long = 283; +pub const SYS_tee: c_long = 284; +pub const SYS_vmsplice: c_long = 285; +pub const SYS_openat: c_long = 286; +pub const SYS_mkdirat: c_long = 287; +pub const SYS_mknodat: c_long = 288; +pub const SYS_fchownat: c_long = 289; +pub const SYS_futimesat: c_long = 290; +pub const SYS_fstatat64: c_long = 291; +pub const SYS_unlinkat: c_long = 292; +pub const SYS_renameat: c_long = 293; +pub const SYS_linkat: c_long = 294; +pub const SYS_symlinkat: c_long = 295; +pub const SYS_readlinkat: c_long = 296; +pub const SYS_fchmodat: c_long = 297; +pub const SYS_faccessat: c_long = 298; +pub const SYS_get_robust_list: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_move_pages: c_long = 301; +pub const SYS_getcpu: c_long = 302; +pub const SYS_epoll_pwait: c_long = 303; +pub const SYS_utimensat: c_long = 304; +pub const SYS_signalfd: c_long = 305; +pub const SYS_timerfd_create: c_long = 306; +pub const SYS_eventfd: c_long = 307; +pub const SYS_sync_file_range2: c_long = 308; +pub const SYS_fallocate: c_long = 309; +pub const SYS_subpage_prot: c_long = 310; +pub const SYS_timerfd_settime: c_long = 311; +pub const SYS_timerfd_gettime: c_long = 312; +pub const SYS_signalfd4: c_long = 313; +pub const SYS_eventfd2: c_long = 314; +pub const SYS_epoll_create1: c_long = 315; +pub const SYS_dup3: c_long = 316; +pub const SYS_pipe2: c_long = 317; +pub const SYS_inotify_init1: c_long = 318; +pub const SYS_perf_event_open: c_long = 319; +pub const SYS_preadv: c_long = 320; +pub const SYS_pwritev: c_long = 321; +pub const SYS_rt_tgsigqueueinfo: c_long = 322; +pub const SYS_fanotify_init: c_long = 323; +pub const SYS_fanotify_mark: c_long = 324; +pub const SYS_prlimit64: c_long = 325; +pub const SYS_socket: c_long = 326; +pub const SYS_bind: c_long = 327; +pub const SYS_connect: c_long = 328; +pub const SYS_listen: c_long = 329; +pub const SYS_accept: c_long = 330; +pub const SYS_getsockname: c_long = 331; +pub const SYS_getpeername: c_long = 332; +pub const SYS_socketpair: c_long = 333; +pub const SYS_send: c_long = 334; +pub const SYS_sendto: c_long = 335; +pub const SYS_recv: c_long = 336; +pub const SYS_recvfrom: c_long = 337; +pub const SYS_shutdown: c_long = 338; +pub const SYS_setsockopt: c_long = 339; +pub const SYS_getsockopt: c_long = 340; +pub const SYS_sendmsg: c_long = 341; +pub const SYS_recvmsg: c_long = 342; +pub const SYS_recvmmsg: c_long = 343; +pub const SYS_accept4: c_long = 344; +pub const SYS_name_to_handle_at: c_long = 345; +pub const SYS_open_by_handle_at: c_long = 346; +pub const SYS_clock_adjtime: c_long = 347; +pub const SYS_syncfs: c_long = 348; +pub const SYS_sendmmsg: c_long = 349; +pub const SYS_setns: c_long = 350; +pub const SYS_process_vm_readv: c_long = 351; +pub const SYS_process_vm_writev: c_long = 352; +pub const SYS_finit_module: c_long = 353; +pub const SYS_kcmp: c_long = 354; +pub const SYS_sched_setattr: c_long = 355; +pub const SYS_sched_getattr: c_long = 356; +pub const SYS_renameat2: c_long = 357; +pub const SYS_seccomp: c_long = 358; +pub const SYS_getrandom: c_long = 359; +pub const SYS_memfd_create: c_long = 360; +pub const SYS_bpf: c_long = 361; +pub const SYS_execveat: c_long = 362; +pub const SYS_switch_endian: c_long = 363; +pub const SYS_userfaultfd: c_long = 364; +pub const SYS_membarrier: c_long = 365; +pub const SYS_mlock2: c_long = 378; +pub const SYS_copy_file_range: c_long = 379; +pub const SYS_preadv2: c_long = 380; +pub const SYS_pwritev2: c_long = 381; +pub const SYS_kexec_file_load: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_pkey_alloc: c_long = 384; +pub const SYS_pkey_free: c_long = 385; +pub const SYS_pkey_mprotect: c_long = 386; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/riscv32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/riscv32/mod.rs new file mode 100644 index 00000000000000..8589e4692335ca --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/riscv32/mod.rs @@ -0,0 +1,645 @@ +//! RISC-V-specific definitions for 32-bit linux-like values + +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = c_int; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub __pad1: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub __pad2: c_int, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + pub st_atime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad1: Padding, + pub st_mtime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad1: Padding, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad2: Padding, + pub st_ctime_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad2: Padding, + __unused: Padding<[c_int; 2usize]>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused5: Padding, + __unused6: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + __unused1: Padding, + pub msg_rtime: crate::time_t, + __unused2: Padding, + pub msg_ctime: crate::time_t, + __unused3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: (i64, f64), + } +} + +//pub const RLIM_INFINITY: crate::rlim_t = !0; +pub const VEOF: usize = 4; +//pub const RLIMIT_RSS: crate::__rlimit_resource_t = 5; +//pub const RLIMIT_AS: crate::__rlimit_resource_t = 9; +//pub const RLIMIT_MEMLOCK: crate::__rlimit_resource_t = 8; +//pub const RLIMIT_NOFILE: crate::__rlimit_resource_t = 7; +//pub const RLIMIT_NPROC: crate::__rlimit_resource_t = 6; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const MAP_GROWSDOWN: c_int = 256; +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 4; +pub const SA_NOCLDWAIT: c_int = 2; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const POLLWRNORM: c_short = 256; +pub const POLLWRBAND: c_short = 512; +pub const O_ASYNC: c_int = 8192; +pub const F_SETOWN: c_int = 8; +pub const F_GETOWN: c_int = 9; +pub const F_GETLK: c_int = 12; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; + +pub const O_DIRECT: c_int = 16384; +pub const O_DIRECTORY: c_int = 65536; +pub const O_LARGEFILE: c_int = 0o0100000; +pub const O_NOFOLLOW: c_int = 131072; +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_HUGETLB: c_int = 262144; +pub const MAP_LOCKED: c_int = 8192; +pub const MAP_NORESERVE: c_int = 16384; +pub const MAP_ANON: c_int = 32; +pub const MAP_DENYWRITE: c_int = 2048; +pub const MAP_EXECUTABLE: c_int = 4096; +pub const MAP_POPULATE: c_int = 32768; +pub const MAP_NONBLOCK: c_int = 65536; +pub const MAP_STACK: c_int = 131072; +pub const MAP_SYNC: c_int = 0x080000; +pub const EDEADLOCK: c_int = 35; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const MCL_CURRENT: c_int = 1; +pub const MCL_FUTURE: c_int = 2; +pub const MCL_ONFAULT: c_int = 4; +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; +pub const CBAUD: crate::tcflag_t = 4111; +pub const TAB1: crate::tcflag_t = 2048; +pub const TAB2: crate::tcflag_t = 4096; +pub const TAB3: crate::tcflag_t = 6144; +pub const CR1: crate::tcflag_t = 512; +pub const CR2: crate::tcflag_t = 1024; +pub const CR3: crate::tcflag_t = 1536; +pub const FF1: crate::tcflag_t = 32768; +pub const BS1: crate::tcflag_t = 8192; +pub const VT1: crate::tcflag_t = 16384; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 1024; +pub const IXOFF: crate::tcflag_t = 4096; +pub const ONLCR: crate::tcflag_t = 4; +pub const CSIZE: crate::tcflag_t = 48; +pub const CS6: crate::tcflag_t = 16; +pub const CS7: crate::tcflag_t = 32; +pub const CS8: crate::tcflag_t = 48; +pub const CSTOPB: crate::tcflag_t = 64; +pub const CREAD: crate::tcflag_t = 128; +pub const PARENB: crate::tcflag_t = 256; +pub const PARODD: crate::tcflag_t = 512; +pub const HUPCL: crate::tcflag_t = 1024; +pub const CLOCAL: crate::tcflag_t = 2048; +pub const ECHOKE: crate::tcflag_t = 2048; +pub const ECHOE: crate::tcflag_t = 16; +pub const ECHOK: crate::tcflag_t = 32; +pub const ECHONL: crate::tcflag_t = 64; +pub const ECHOPRT: crate::tcflag_t = 1024; +pub const ECHOCTL: crate::tcflag_t = 512; +pub const ISIG: crate::tcflag_t = 1; +pub const ICANON: crate::tcflag_t = 2; +pub const PENDIN: crate::tcflag_t = 16384; +pub const NOFLSH: crate::tcflag_t = 128; +pub const CIBAUD: crate::tcflag_t = 269418496; +pub const CBAUDEX: crate::tcflag_t = 4096; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 2; +pub const NLDLY: crate::tcflag_t = 256; +pub const CRDLY: crate::tcflag_t = 1536; +pub const TABDLY: crate::tcflag_t = 6144; +pub const BSDLY: crate::tcflag_t = 8192; +pub const FFDLY: crate::tcflag_t = 32768; +pub const VTDLY: crate::tcflag_t = 16384; +pub const XTABS: crate::tcflag_t = 6144; +pub const B57600: crate::speed_t = 4097; +pub const B115200: crate::speed_t = 4098; +pub const B230400: crate::speed_t = 4099; +pub const B460800: crate::speed_t = 4100; +pub const B500000: crate::speed_t = 4101; +pub const B576000: crate::speed_t = 4102; +pub const B921600: crate::speed_t = 4103; +pub const B1000000: crate::speed_t = 4104; +pub const B1152000: crate::speed_t = 4105; +pub const B1500000: crate::speed_t = 4106; +pub const B2000000: crate::speed_t = 4107; +pub const B2500000: crate::speed_t = 4108; +pub const B3000000: crate::speed_t = 4109; +pub const B3500000: crate::speed_t = 4110; +pub const B4000000: crate::speed_t = 4111; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 32768; +pub const TOSTOP: crate::tcflag_t = 256; +pub const FLUSHO: crate::tcflag_t = 4096; +pub const EXTPROC: crate::tcflag_t = 65536; + +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_close: c_long = 57; +// RISC-V don't have SYS_fstat, use statx instead. +pub const SYS_lseek: c_long = 62; +pub const SYS_mmap: c_long = 222; +pub const SYS_mprotect: c_long = 226; +pub const SYS_munmap: c_long = 215; +pub const SYS_brk: c_long = 214; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_ioctl: c_long = 29; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_mremap: c_long = 216; +pub const SYS_msync: c_long = 227; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmctl: c_long = 195; +pub const SYS_dup: c_long = 23; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_getpid: c_long = 172; +pub const SYS_sendfile: c_long = 71; +pub const SYS_socket: c_long = 198; +pub const SYS_connect: c_long = 203; +pub const SYS_accept: c_long = 202; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_shutdown: c_long = 210; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_socketpair: c_long = 199; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_exit: c_long = 93; +// RISC-V don't have wait4, use waitid instead. +pub const SYS_kill: c_long = 129; +pub const SYS_uname: c_long = 160; +pub const SYS_semget: c_long = 190; +pub const SYS_semop: c_long = 193; +pub const SYS_semctl: c_long = 191; +pub const SYS_shmdt: c_long = 197; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgctl: c_long = 187; +pub const SYS_fcntl: c_long = 25; +pub const SYS_flock: c_long = 32; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_getcwd: c_long = 17; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchown: c_long = 55; +pub const SYS_umask: c_long = 166; +// RISC-V don't have gettimeofday, use clock_gettime64 instead. +// RISC-V don't have getrlimit, use prlimit64 instead. +pub const SYS_getrusage: c_long = 165; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_times: c_long = 153; +pub const SYS_ptrace: c_long = 117; +pub const SYS_getuid: c_long = 174; +pub const SYS_syslog: c_long = 116; +pub const SYS_getgid: c_long = 176; +pub const SYS_setuid: c_long = 146; +pub const SYS_setgid: c_long = 144; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getegid: c_long = 177; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getppid: c_long = 173; +pub const SYS_setsid: c_long = 157; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setregid: c_long = 143; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_getpgid: c_long = 155; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_getsid: c_long = 156; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait_time64: c_long = 421; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_personality: c_long = 92; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_getpriority: c_long = 141; +pub const SYS_setpriority: c_long = 140; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval_time64: c_long = 423; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_prctl: c_long = 167; +// RISC-V don't have setrlimit, use prlimit64 instead. +pub const SYS_chroot: c_long = 51; +pub const SYS_sync: c_long = 81; +pub const SYS_acct: c_long = 89; +// RISC-V don't have settimeofday, use clock_settime64 instead. +pub const SYS_mount: c_long = 40; +pub const SYS_umount2: c_long = 39; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_reboot: c_long = 142; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_quotactl: c_long = 60; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_gettid: c_long = 178; +pub const SYS_readahead: c_long = 213; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_tkill: c_long = 130; +pub const SYS_futex_time64: c_long = 422; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_pgetevents_time64: c_long = 416; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_getdents64: c_long = 61; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_semtimedop_time64: c_long = 420; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_settime64: c_long = 409; +pub const SYS_timer_gettime64: c_long = 408; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime64: c_long = 404; +pub const SYS_clock_gettime64: c_long = 403; +pub const SYS_clock_getres_time64: c_long = 406; +pub const SYS_clock_nanosleep_time64: c_long = 407; +pub const SYS_exit_group: c_long = 94; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_tgkill: c_long = 131; +pub const SYS_mbind: c_long = 235; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend_time64: c_long = 418; +pub const SYS_mq_timedreceive_time64: c_long = 419; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_waitid: c_long = 95; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_openat: c_long = 56; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_mknodat: c_long = 33; +pub const SYS_fchownat: c_long = 54; +// RISC-V don't have newfstatat, use statx instead. +pub const SYS_unlinkat: c_long = 35; +pub const SYS_linkat: c_long = 37; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_faccessat: c_long = 48; +pub const SYS_pselect6_time64: c_long = 413; +pub const SYS_ppoll_time64: c_long = 414; +pub const SYS_unshare: c_long = 97; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_move_pages: c_long = 239; +pub const SYS_utimensat_time64: c_long = 412; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_fallocate: c_long = 47; +pub const SYS_timerfd_settime64: c_long = 411; +pub const SYS_timerfd_gettime64: c_long = 410; +pub const SYS_accept4: c_long = 242; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_dup3: c_long = 24; +pub const SYS_pipe2: c_long = 59; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_recvmmsg_time64: c_long = 417; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime64: c_long = 405; +pub const SYS_syncfs: c_long = 267; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_setns: c_long = 268; +pub const SYS_getcpu: c_long = 168; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; + +// Plain syscalls aliased to their time64 variants +pub const SYS_clock_gettime: c_long = SYS_clock_gettime64; +pub const SYS_clock_settime: c_long = SYS_clock_settime64; +pub const SYS_clock_adjtime: c_long = SYS_clock_adjtime64; +pub const SYS_clock_getres: c_long = SYS_clock_getres_time64; +pub const SYS_clock_nanosleep: c_long = SYS_clock_nanosleep_time64; +pub const SYS_timer_gettime: c_long = SYS_timer_gettime64; +pub const SYS_timer_settime: c_long = SYS_timer_settime64; +pub const SYS_timerfd_gettime: c_long = SYS_timerfd_gettime64; +pub const SYS_timerfd_settime: c_long = SYS_timerfd_settime64; +pub const SYS_utimensat: c_long = SYS_utimensat_time64; +pub const SYS_pselect6: c_long = SYS_pselect6_time64; +pub const SYS_ppoll: c_long = SYS_ppoll_time64; +pub const SYS_recvmmsg: c_long = SYS_recvmmsg_time64; +pub const SYS_mq_timedsend: c_long = SYS_mq_timedsend_time64; +pub const SYS_mq_timedreceive: c_long = SYS_mq_timedreceive_time64; +pub const SYS_rt_sigtimedwait: c_long = SYS_rt_sigtimedwait_time64; +pub const SYS_futex: c_long = SYS_futex_time64; +pub const SYS_sched_rr_get_interval: c_long = SYS_sched_rr_get_interval_time64; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/x86/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/x86/mod.rs new file mode 100644 index 00000000000000..1a348078764f01 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b32/x86/mod.rs @@ -0,0 +1,878 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + __st_dev_padding: Padding, + __st_ino_truncated: c_long, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __st_rdev_padding: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + + #[cfg(musl32_time64)] + __st_atim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_mtim32: Padding<__c_anonymous_timespec32>, + #[cfg(musl32_time64)] + __st_ctim32: Padding<__c_anonymous_timespec32>, + + #[cfg(musl_v1_2_3)] + pub st_ino: crate::ino_t, + + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + #[cfg(musl32_time64)] + __pad0: Padding, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + #[cfg(musl32_time64)] + __pad1: Padding, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + #[cfg(musl32_time64)] + __pad2: Padding, + + #[cfg(not(musl_v1_2_3))] + pub st_ino: crate::ino_t, + } + + struct __c_anonymous_timespec32 { + __tv_sec: c_long, + __tv_nsec: c_long, + } + + pub struct mcontext_t { + __private: [u32; 22], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + + #[cfg(musl32_time64)] + __shm_atime_lo: c_ulong, + #[cfg(musl32_time64)] + __shm_atime_hi: c_ulong, + #[cfg(musl32_time64)] + __shm_dtime_lo: c_ulong, + #[cfg(musl32_time64)] + __shm_dtime_hi: c_ulong, + #[cfg(musl32_time64)] + __msg_ctime_lo: c_ulong, + #[cfg(musl32_time64)] + __msg_ctime_hi: c_ulong, + + #[cfg(not(musl32_time64))] + pub shm_atime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub shm_dtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub shm_ctime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + __pad3: c_ulong, + #[cfg(musl32_time64)] + shm_atime: crate::time_t, + #[cfg(musl32_time64)] + shm_dtime: crate::time_t, + #[cfg(musl32_time64)] + shm_ctime: crate::time_t, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + + #[cfg(musl32_time64)] + __msg_stime_lo: c_ulong, + #[cfg(musl32_time64)] + __msg_stime_hi: c_ulong, + #[cfg(musl32_time64)] + __msg_rtime_lo: c_ulong, + #[cfg(musl32_time64)] + __msg_rtime_hi: c_ulong, + #[cfg(musl32_time64)] + __msg_ctime_lo: c_ulong, + #[cfg(musl32_time64)] + __msg_ctime_hi: c_ulong, + + #[cfg(not(musl32_time64))] + pub msg_stime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused1: Padding, + #[cfg(not(musl32_time64))] + pub msg_rtime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused2: Padding, + #[cfg(not(musl32_time64))] + pub msg_ctime: crate::time_t, + #[cfg(not(musl32_time64))] + __unused3: Padding, + + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + + #[cfg(musl32_time64)] + pub msg_stime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_rtime: crate::time_t, + #[cfg(musl32_time64)] + pub msg_ctime: crate::time_t, + } + + pub struct user_fpxregs_struct { + pub cwd: c_ushort, + pub swd: c_ushort, + pub twd: c_ushort, + pub fop: c_ushort, + pub fip: c_long, + pub fcs: c_long, + pub foo: c_long, + pub fos: c_long, + pub mxcsr: c_long, + __reserved: Padding, + pub st_space: [c_long; 32], + pub xmm_space: [c_long; 32], + padding: Padding<[c_long; 56]>, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + __private: [u8; 112], + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [f64; 3], + } +} + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_ASYNC: c_int = 0x2000; +pub const O_LARGEFILE: c_int = 0o0100000; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const EDEADLK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_32BIT: c_int = 0x0040; + +pub const F_GETLK: c_int = 12; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 13; +pub const F_SETLKW: c_int = 14; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const PTRACE_SYSEMU: c_int = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 32; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86old: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_vm86: c_long = 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_mincore: c_long = 218; +pub const SYS_madvise: c_long = 219; +pub const SYS_getdents64: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_set_thread_area: c_long = 243; +pub const SYS_get_thread_area: c_long = 244; +pub const SYS_io_setup: c_long = 245; +pub const SYS_io_destroy: c_long = 246; +pub const SYS_io_getevents: c_long = 247; +pub const SYS_io_submit: c_long = 248; +pub const SYS_io_cancel: c_long = 249; +pub const SYS_fadvise64: c_long = 250; +pub const SYS_exit_group: c_long = 252; +pub const SYS_lookup_dcookie: c_long = 253; +pub const SYS_epoll_create: c_long = 254; +pub const SYS_epoll_ctl: c_long = 255; +pub const SYS_epoll_wait: c_long = 256; +pub const SYS_remap_file_pages: c_long = 257; +pub const SYS_set_tid_address: c_long = 258; +pub const SYS_timer_create: c_long = 259; +pub const SYS_timer_settime: c_long = 260; +pub const SYS_timer_gettime: c_long = 261; +pub const SYS_timer_getoverrun: c_long = 262; +pub const SYS_timer_delete: c_long = 263; +pub const SYS_clock_settime: c_long = 264; +pub const SYS_clock_gettime: c_long = 265; +pub const SYS_clock_getres: c_long = 266; +pub const SYS_clock_nanosleep: c_long = 267; +pub const SYS_statfs64: c_long = 268; +pub const SYS_fstatfs64: c_long = 269; +pub const SYS_tgkill: c_long = 270; +pub const SYS_utimes: c_long = 271; +pub const SYS_fadvise64_64: c_long = 272; +pub const SYS_vserver: c_long = 273; +pub const SYS_mbind: c_long = 274; +pub const SYS_get_mempolicy: c_long = 275; +pub const SYS_set_mempolicy: c_long = 276; +pub const SYS_mq_open: c_long = 277; +pub const SYS_mq_unlink: c_long = 278; +pub const SYS_mq_timedsend: c_long = 279; +pub const SYS_mq_timedreceive: c_long = 280; +pub const SYS_mq_notify: c_long = 281; +pub const SYS_mq_getsetattr: c_long = 282; +pub const SYS_kexec_load: c_long = 283; +pub const SYS_waitid: c_long = 284; +pub const SYS_add_key: c_long = 286; +pub const SYS_request_key: c_long = 287; +pub const SYS_keyctl: c_long = 288; +pub const SYS_ioprio_set: c_long = 289; +pub const SYS_ioprio_get: c_long = 290; +pub const SYS_inotify_init: c_long = 291; +pub const SYS_inotify_add_watch: c_long = 292; +pub const SYS_inotify_rm_watch: c_long = 293; +pub const SYS_migrate_pages: c_long = 294; +pub const SYS_openat: c_long = 295; +pub const SYS_mkdirat: c_long = 296; +pub const SYS_mknodat: c_long = 297; +pub const SYS_fchownat: c_long = 298; +pub const SYS_futimesat: c_long = 299; +pub const SYS_fstatat64: c_long = 300; +pub const SYS_unlinkat: c_long = 301; +pub const SYS_renameat: c_long = 302; +pub const SYS_linkat: c_long = 303; +pub const SYS_symlinkat: c_long = 304; +pub const SYS_readlinkat: c_long = 305; +pub const SYS_fchmodat: c_long = 306; +pub const SYS_faccessat: c_long = 307; +pub const SYS_pselect6: c_long = 308; +pub const SYS_ppoll: c_long = 309; +pub const SYS_unshare: c_long = 310; +pub const SYS_set_robust_list: c_long = 311; +pub const SYS_get_robust_list: c_long = 312; +pub const SYS_splice: c_long = 313; +pub const SYS_sync_file_range: c_long = 314; +pub const SYS_tee: c_long = 315; +pub const SYS_vmsplice: c_long = 316; +pub const SYS_move_pages: c_long = 317; +pub const SYS_getcpu: c_long = 318; +pub const SYS_epoll_pwait: c_long = 319; +pub const SYS_utimensat: c_long = 320; +pub const SYS_signalfd: c_long = 321; +pub const SYS_timerfd_create: c_long = 322; +pub const SYS_eventfd: c_long = 323; +pub const SYS_fallocate: c_long = 324; +pub const SYS_timerfd_settime: c_long = 325; +pub const SYS_timerfd_gettime: c_long = 326; +pub const SYS_signalfd4: c_long = 327; +pub const SYS_eventfd2: c_long = 328; +pub const SYS_epoll_create1: c_long = 329; +pub const SYS_dup3: c_long = 330; +pub const SYS_pipe2: c_long = 331; +pub const SYS_inotify_init1: c_long = 332; +pub const SYS_preadv: c_long = 333; +pub const SYS_pwritev: c_long = 334; +pub const SYS_rt_tgsigqueueinfo: c_long = 335; +pub const SYS_perf_event_open: c_long = 336; +pub const SYS_recvmmsg: c_long = 337; +pub const SYS_fanotify_init: c_long = 338; +pub const SYS_fanotify_mark: c_long = 339; +pub const SYS_prlimit64: c_long = 340; +pub const SYS_name_to_handle_at: c_long = 341; +pub const SYS_open_by_handle_at: c_long = 342; +pub const SYS_clock_adjtime: c_long = 343; +pub const SYS_syncfs: c_long = 344; +pub const SYS_sendmmsg: c_long = 345; +pub const SYS_setns: c_long = 346; +pub const SYS_process_vm_readv: c_long = 347; +pub const SYS_process_vm_writev: c_long = 348; +pub const SYS_kcmp: c_long = 349; +pub const SYS_finit_module: c_long = 350; +pub const SYS_sched_setattr: c_long = 351; +pub const SYS_sched_getattr: c_long = 352; +pub const SYS_renameat2: c_long = 353; +pub const SYS_seccomp: c_long = 354; +pub const SYS_getrandom: c_long = 355; +pub const SYS_memfd_create: c_long = 356; +pub const SYS_bpf: c_long = 357; +pub const SYS_execveat: c_long = 358; +pub const SYS_socket: c_long = 359; +pub const SYS_socketpair: c_long = 360; +pub const SYS_bind: c_long = 361; +pub const SYS_connect: c_long = 362; +pub const SYS_listen: c_long = 363; +pub const SYS_accept4: c_long = 364; +pub const SYS_getsockopt: c_long = 365; +pub const SYS_setsockopt: c_long = 366; +pub const SYS_getsockname: c_long = 367; +pub const SYS_getpeername: c_long = 368; +pub const SYS_sendto: c_long = 369; +pub const SYS_sendmsg: c_long = 370; +pub const SYS_recvfrom: c_long = 371; +pub const SYS_recvmsg: c_long = 372; +pub const SYS_shutdown: c_long = 373; +pub const SYS_userfaultfd: c_long = 374; +pub const SYS_membarrier: c_long = 375; +pub const SYS_mlock2: c_long = 376; +pub const SYS_copy_file_range: c_long = 377; +pub const SYS_preadv2: c_long = 378; +pub const SYS_pwritev2: c_long = 379; +pub const SYS_pkey_mprotect: c_long = 380; +pub const SYS_pkey_alloc: c_long = 381; +pub const SYS_pkey_free: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_fchmodat2: c_long = 452; + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: c_int = 0; +pub const ECX: c_int = 1; +pub const EDX: c_int = 2; +pub const ESI: c_int = 3; +pub const EDI: c_int = 4; +pub const EBP: c_int = 5; +pub const EAX: c_int = 6; +pub const DS: c_int = 7; +pub const ES: c_int = 8; +pub const FS: c_int = 9; +pub const GS: c_int = 10; +pub const ORIG_EAX: c_int = 11; +pub const EIP: c_int = 12; +pub const CS: c_int = 13; +pub const EFL: c_int = 14; +pub const UESP: c_int = 15; +pub const SS: c_int = 16; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs new file mode 100644 index 00000000000000..82df29bf43a1f1 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs @@ -0,0 +1,689 @@ +use crate::off_t; +use crate::prelude::*; + +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; +pub type wchar_t = u32; +pub type nlink_t = u32; +pub type blksize_t = c_int; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad0: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad1: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_uint; 2]>, + } + + pub struct user_regs_struct { + pub regs: [c_ulonglong; 31], + pub sp: c_ulonglong, + pub pc: c_ulonglong, + pub pstate: c_ulonglong, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + + #[cfg(musl_v1_2_3)] + pub __seq: c_int, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "The type of this field has changed from c_ushort to c_int, + we'll follow that change in the future release." + )] + pub __seq: c_ushort, + __unused1: Padding, + __unused2: Padding, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub fault_address: c_ulong, + pub regs: [c_ulong; 31], + pub sp: c_ulong, + pub pc: c_ulong, + pub pstate: c_ulong, + __reserved: Padding<[u64; 512]>, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } + + pub struct user_fpsimd_struct { + pub vregs: [u128; 32], + pub fpsr: u32, + pub fpcr: u32, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f32; 8], + } +} + +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_LARGEFILE: c_int = 0x20000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0x2000; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +// bits/hwcap.h +pub const HWCAP_FP: c_ulong = 1 << 0; +pub const HWCAP_ASIMD: c_ulong = 1 << 1; +pub const HWCAP_EVTSTRM: c_ulong = 1 << 2; +pub const HWCAP_AES: c_ulong = 1 << 3; +pub const HWCAP_PMULL: c_ulong = 1 << 4; +pub const HWCAP_SHA1: c_ulong = 1 << 5; +pub const HWCAP_SHA2: c_ulong = 1 << 6; +pub const HWCAP_CRC32: c_ulong = 1 << 7; +pub const HWCAP_ATOMICS: c_ulong = 1 << 8; +pub const HWCAP_FPHP: c_ulong = 1 << 9; +pub const HWCAP_ASIMDHP: c_ulong = 1 << 10; +pub const HWCAP_CPUID: c_ulong = 1 << 11; +pub const HWCAP_ASIMDRDM: c_ulong = 1 << 12; +pub const HWCAP_JSCVT: c_ulong = 1 << 13; +pub const HWCAP_FCMA: c_ulong = 1 << 14; +pub const HWCAP_LRCPC: c_ulong = 1 << 15; +pub const HWCAP_DCPOP: c_ulong = 1 << 16; +pub const HWCAP_SHA3: c_ulong = 1 << 17; +pub const HWCAP_SM3: c_ulong = 1 << 18; +pub const HWCAP_SM4: c_ulong = 1 << 19; +pub const HWCAP_ASIMDDP: c_ulong = 1 << 20; +pub const HWCAP_SHA512: c_ulong = 1 << 21; +pub const HWCAP_SVE: c_ulong = 1 << 22; +pub const HWCAP_ASIMDFHM: c_ulong = 1 << 23; +pub const HWCAP_DIT: c_ulong = 1 << 24; +pub const HWCAP_USCAT: c_ulong = 1 << 25; +pub const HWCAP_ILRCPC: c_ulong = 1 << 26; +pub const HWCAP_FLAGM: c_ulong = 1 << 27; +pub const HWCAP_SSBS: c_ulong = 1 << 28; +pub const HWCAP_SB: c_ulong = 1 << 29; +pub const HWCAP_PACA: c_ulong = 1 << 30; +pub const HWCAP_PACG: c_ulong = 1 << 31; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const MINSIGSTKSZ: size_t = 6144; +pub const SIGSTKSZ: size_t = 12288; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_fcntl: c_long = 25; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +pub const SYS_renameat: c_long = 38; +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_lseek: c_long = 62; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_fstat: c_long = 80; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_mmap: c_long = 222; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_io_pgetevents: c_long = 292; +pub const SYS_rseq: c_long = 293; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_mseal: c_long = 462; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = EDEADLK; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs new file mode 100644 index 00000000000000..8e890be51848f3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs @@ -0,0 +1,643 @@ +//! LoongArch-specific definitions for 64-bit linux-like values + +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = c_int; + +pub type nlink_t = c_uint; +pub type blksize_t = c_int; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad2: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2usize]>, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + pub struct user_regs_struct { + pub regs: [u64; 32], + pub orig_a0: u64, + pub csr_era: u64, + pub csr_badv: u64, + pub reserved: [u64; 10], + } + + pub struct user_fp_struct { + pub fpr: [u64; 32], + pub fcc: u64, + pub fcsr: u32, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub __pc: c_ulong, + pub __gregs: [c_ulong; 32], + pub __flags: c_uint, + pub __extcontext: [c_ulong; 0], + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_getcwd: c_long = 17; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_dup: c_long = 23; +pub const SYS_dup3: c_long = 24; +pub const SYS_fcntl: c_long = 25; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_ioctl: c_long = 29; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_flock: c_long = 32; +pub const SYS_mknodat: c_long = 33; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_linkat: c_long = 37; +pub const SYS_umount2: c_long = 39; +pub const SYS_mount: c_long = 40; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_fallocate: c_long = 47; +pub const SYS_faccessat: c_long = 48; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_chroot: c_long = 51; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_fchownat: c_long = 54; +pub const SYS_fchown: c_long = 55; +pub const SYS_openat: c_long = 56; +pub const SYS_close: c_long = 57; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pipe2: c_long = 59; +pub const SYS_quotactl: c_long = 60; +pub const SYS_getdents64: c_long = 61; +pub const SYS_lseek: c_long = 62; +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_sendfile: c_long = 71; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_sync: c_long = 81; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_utimensat: c_long = 88; +pub const SYS_acct: c_long = 89; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_personality: c_long = 92; +pub const SYS_exit: c_long = 93; +pub const SYS_exit_group: c_long = 94; +pub const SYS_waitid: c_long = 95; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_unshare: c_long = 97; +pub const SYS_futex: c_long = 98; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_syslog: c_long = 116; +pub const SYS_ptrace: c_long = 117; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_kill: c_long = 129; +pub const SYS_tkill: c_long = 130; +pub const SYS_tgkill: c_long = 131; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_setpriority: c_long = 140; +pub const SYS_getpriority: c_long = 141; +pub const SYS_reboot: c_long = 142; +pub const SYS_setregid: c_long = 143; +pub const SYS_setgid: c_long = 144; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setuid: c_long = 146; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_times: c_long = 153; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getpgid: c_long = 155; +pub const SYS_getsid: c_long = 156; +pub const SYS_setsid: c_long = 157; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_uname: c_long = 160; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_getrusage: c_long = 165; +pub const SYS_umask: c_long = 166; +pub const SYS_prctl: c_long = 167; +pub const SYS_getcpu: c_long = 168; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_getpid: c_long = 172; +pub const SYS_getppid: c_long = 173; +pub const SYS_getuid: c_long = 174; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getgid: c_long = 176; +pub const SYS_getegid: c_long = 177; +pub const SYS_gettid: c_long = 178; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgctl: c_long = 187; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_semget: c_long = 190; +pub const SYS_semctl: c_long = 191; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_semop: c_long = 193; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmctl: c_long = 195; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmdt: c_long = 197; +pub const SYS_socket: c_long = 198; +pub const SYS_socketpair: c_long = 199; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_accept: c_long = 202; +pub const SYS_connect: c_long = 203; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_shutdown: c_long = 210; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_readahead: c_long = 213; +pub const SYS_brk: c_long = 214; +pub const SYS_munmap: c_long = 215; +pub const SYS_mremap: c_long = 216; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_mmap: c_long = 222; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_mprotect: c_long = 226; +pub const SYS_msync: c_long = 227; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_mbind: c_long = 235; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_move_pages: c_long = 239; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_accept4: c_long = 242; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_arch_specific_syscall: c_long = 244; +pub const SYS_wait4: c_long = 260; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_setns: c_long = 268; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_io_pgetevents: c_long = 292; +pub const SYS_rseq: c_long = 293; +pub const SYS_kexec_file_load: c_long = 294; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_cachestat: c_long = 451; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_map_shadow_stack: c_long = 453; +pub const SYS_futex_wake: c_long = 454; +pub const SYS_futex_wait: c_long = 455; +pub const SYS_futex_requeue: c_long = 456; + +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_LARGEFILE: c_int = 0o0100000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0o20000; + +pub const SIGSTKSZ: size_t = 16384; +pub const MINSIGSTKSZ: size_t = 4096; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const MADV_SOFT_OFFLINE: c_int = 101; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mips64.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mips64.rs new file mode 100644 index 00000000000000..1fb8618c30c0bc --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mips64.rs @@ -0,0 +1,683 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type __u64 = c_ulong; +pub type __s64 = c_long; +pub type nlink_t = c_uint; +pub type blksize_t = i64; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + __pad1: Padding<[c_int; 3]>, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad2: Padding<[c_uint; 2]>, + pub st_size: off_t, + __pad3: Padding, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + __pad4: Padding, + pub st_blocks: crate::blkcnt_t, + __pad5: Padding<[c_int; 14]>, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct statfs { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 5], + } + + pub struct statfs64 { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 5], + } +} + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const SYS_read: c_long = 5000 + 0; +pub const SYS_write: c_long = 5000 + 1; +pub const SYS_open: c_long = 5000 + 2; +pub const SYS_close: c_long = 5000 + 3; +pub const SYS_stat: c_long = 5000 + 4; +pub const SYS_fstat: c_long = 5000 + 5; +pub const SYS_lstat: c_long = 5000 + 6; +pub const SYS_poll: c_long = 5000 + 7; +pub const SYS_lseek: c_long = 5000 + 8; +pub const SYS_mmap: c_long = 5000 + 9; +pub const SYS_mprotect: c_long = 5000 + 10; +pub const SYS_munmap: c_long = 5000 + 11; +pub const SYS_brk: c_long = 5000 + 12; +pub const SYS_rt_sigaction: c_long = 5000 + 13; +pub const SYS_rt_sigprocmask: c_long = 5000 + 14; +pub const SYS_ioctl: c_long = 5000 + 15; +pub const SYS_pread64: c_long = 5000 + 16; +pub const SYS_pwrite64: c_long = 5000 + 17; +pub const SYS_readv: c_long = 5000 + 18; +pub const SYS_writev: c_long = 5000 + 19; +pub const SYS_access: c_long = 5000 + 20; +pub const SYS_pipe: c_long = 5000 + 21; +pub const SYS__newselect: c_long = 5000 + 22; +pub const SYS_sched_yield: c_long = 5000 + 23; +pub const SYS_mremap: c_long = 5000 + 24; +pub const SYS_msync: c_long = 5000 + 25; +pub const SYS_mincore: c_long = 5000 + 26; +pub const SYS_madvise: c_long = 5000 + 27; +pub const SYS_shmget: c_long = 5000 + 28; +pub const SYS_shmat: c_long = 5000 + 29; +pub const SYS_shmctl: c_long = 5000 + 30; +pub const SYS_dup: c_long = 5000 + 31; +pub const SYS_dup2: c_long = 5000 + 32; +pub const SYS_pause: c_long = 5000 + 33; +pub const SYS_nanosleep: c_long = 5000 + 34; +pub const SYS_getitimer: c_long = 5000 + 35; +pub const SYS_setitimer: c_long = 5000 + 36; +pub const SYS_alarm: c_long = 5000 + 37; +pub const SYS_getpid: c_long = 5000 + 38; +pub const SYS_sendfile: c_long = 5000 + 39; +pub const SYS_socket: c_long = 5000 + 40; +pub const SYS_connect: c_long = 5000 + 41; +pub const SYS_accept: c_long = 5000 + 42; +pub const SYS_sendto: c_long = 5000 + 43; +pub const SYS_recvfrom: c_long = 5000 + 44; +pub const SYS_sendmsg: c_long = 5000 + 45; +pub const SYS_recvmsg: c_long = 5000 + 46; +pub const SYS_shutdown: c_long = 5000 + 47; +pub const SYS_bind: c_long = 5000 + 48; +pub const SYS_listen: c_long = 5000 + 49; +pub const SYS_getsockname: c_long = 5000 + 50; +pub const SYS_getpeername: c_long = 5000 + 51; +pub const SYS_socketpair: c_long = 5000 + 52; +pub const SYS_setsockopt: c_long = 5000 + 53; +pub const SYS_getsockopt: c_long = 5000 + 54; +pub const SYS_clone: c_long = 5000 + 55; +pub const SYS_fork: c_long = 5000 + 56; +pub const SYS_execve: c_long = 5000 + 57; +pub const SYS_exit: c_long = 5000 + 58; +pub const SYS_wait4: c_long = 5000 + 59; +pub const SYS_kill: c_long = 5000 + 60; +pub const SYS_uname: c_long = 5000 + 61; +pub const SYS_semget: c_long = 5000 + 62; +pub const SYS_semop: c_long = 5000 + 63; +pub const SYS_semctl: c_long = 5000 + 64; +pub const SYS_shmdt: c_long = 5000 + 65; +pub const SYS_msgget: c_long = 5000 + 66; +pub const SYS_msgsnd: c_long = 5000 + 67; +pub const SYS_msgrcv: c_long = 5000 + 68; +pub const SYS_msgctl: c_long = 5000 + 69; +pub const SYS_fcntl: c_long = 5000 + 70; +pub const SYS_flock: c_long = 5000 + 71; +pub const SYS_fsync: c_long = 5000 + 72; +pub const SYS_fdatasync: c_long = 5000 + 73; +pub const SYS_truncate: c_long = 5000 + 74; +pub const SYS_ftruncate: c_long = 5000 + 75; +pub const SYS_getdents: c_long = 5000 + 76; +pub const SYS_getcwd: c_long = 5000 + 77; +pub const SYS_chdir: c_long = 5000 + 78; +pub const SYS_fchdir: c_long = 5000 + 79; +pub const SYS_rename: c_long = 5000 + 80; +pub const SYS_mkdir: c_long = 5000 + 81; +pub const SYS_rmdir: c_long = 5000 + 82; +pub const SYS_creat: c_long = 5000 + 83; +pub const SYS_link: c_long = 5000 + 84; +pub const SYS_unlink: c_long = 5000 + 85; +pub const SYS_symlink: c_long = 5000 + 86; +pub const SYS_readlink: c_long = 5000 + 87; +pub const SYS_chmod: c_long = 5000 + 88; +pub const SYS_fchmod: c_long = 5000 + 89; +pub const SYS_chown: c_long = 5000 + 90; +pub const SYS_fchown: c_long = 5000 + 91; +pub const SYS_lchown: c_long = 5000 + 92; +pub const SYS_umask: c_long = 5000 + 93; +pub const SYS_gettimeofday: c_long = 5000 + 94; +pub const SYS_getrlimit: c_long = 5000 + 95; +pub const SYS_getrusage: c_long = 5000 + 96; +pub const SYS_sysinfo: c_long = 5000 + 97; +pub const SYS_times: c_long = 5000 + 98; +pub const SYS_ptrace: c_long = 5000 + 99; +pub const SYS_getuid: c_long = 5000 + 100; +pub const SYS_syslog: c_long = 5000 + 101; +pub const SYS_getgid: c_long = 5000 + 102; +pub const SYS_setuid: c_long = 5000 + 103; +pub const SYS_setgid: c_long = 5000 + 104; +pub const SYS_geteuid: c_long = 5000 + 105; +pub const SYS_getegid: c_long = 5000 + 106; +pub const SYS_setpgid: c_long = 5000 + 107; +pub const SYS_getppid: c_long = 5000 + 108; +pub const SYS_getpgrp: c_long = 5000 + 109; +pub const SYS_setsid: c_long = 5000 + 110; +pub const SYS_setreuid: c_long = 5000 + 111; +pub const SYS_setregid: c_long = 5000 + 112; +pub const SYS_getgroups: c_long = 5000 + 113; +pub const SYS_setgroups: c_long = 5000 + 114; +pub const SYS_setresuid: c_long = 5000 + 115; +pub const SYS_getresuid: c_long = 5000 + 116; +pub const SYS_setresgid: c_long = 5000 + 117; +pub const SYS_getresgid: c_long = 5000 + 118; +pub const SYS_getpgid: c_long = 5000 + 119; +pub const SYS_setfsuid: c_long = 5000 + 120; +pub const SYS_setfsgid: c_long = 5000 + 121; +pub const SYS_getsid: c_long = 5000 + 122; +pub const SYS_capget: c_long = 5000 + 123; +pub const SYS_capset: c_long = 5000 + 124; +pub const SYS_rt_sigpending: c_long = 5000 + 125; +pub const SYS_rt_sigtimedwait: c_long = 5000 + 126; +pub const SYS_rt_sigqueueinfo: c_long = 5000 + 127; +pub const SYS_rt_sigsuspend: c_long = 5000 + 128; +pub const SYS_sigaltstack: c_long = 5000 + 129; +pub const SYS_utime: c_long = 5000 + 130; +pub const SYS_mknod: c_long = 5000 + 131; +pub const SYS_personality: c_long = 5000 + 132; +pub const SYS_ustat: c_long = 5000 + 133; +pub const SYS_statfs: c_long = 5000 + 134; +pub const SYS_fstatfs: c_long = 5000 + 135; +pub const SYS_sysfs: c_long = 5000 + 136; +pub const SYS_getpriority: c_long = 5000 + 137; +pub const SYS_setpriority: c_long = 5000 + 138; +pub const SYS_sched_setparam: c_long = 5000 + 139; +pub const SYS_sched_getparam: c_long = 5000 + 140; +pub const SYS_sched_setscheduler: c_long = 5000 + 141; +pub const SYS_sched_getscheduler: c_long = 5000 + 142; +pub const SYS_sched_get_priority_max: c_long = 5000 + 143; +pub const SYS_sched_get_priority_min: c_long = 5000 + 144; +pub const SYS_sched_rr_get_interval: c_long = 5000 + 145; +pub const SYS_mlock: c_long = 5000 + 146; +pub const SYS_munlock: c_long = 5000 + 147; +pub const SYS_mlockall: c_long = 5000 + 148; +pub const SYS_munlockall: c_long = 5000 + 149; +pub const SYS_vhangup: c_long = 5000 + 150; +pub const SYS_pivot_root: c_long = 5000 + 151; +pub const SYS__sysctl: c_long = 5000 + 152; +pub const SYS_prctl: c_long = 5000 + 153; +pub const SYS_adjtimex: c_long = 5000 + 154; +pub const SYS_setrlimit: c_long = 5000 + 155; +pub const SYS_chroot: c_long = 5000 + 156; +pub const SYS_sync: c_long = 5000 + 157; +pub const SYS_acct: c_long = 5000 + 158; +pub const SYS_settimeofday: c_long = 5000 + 159; +pub const SYS_mount: c_long = 5000 + 160; +pub const SYS_umount2: c_long = 5000 + 161; +pub const SYS_swapon: c_long = 5000 + 162; +pub const SYS_swapoff: c_long = 5000 + 163; +pub const SYS_reboot: c_long = 5000 + 164; +pub const SYS_sethostname: c_long = 5000 + 165; +pub const SYS_setdomainname: c_long = 5000 + 166; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 5000 + 167; +pub const SYS_init_module: c_long = 5000 + 168; +pub const SYS_delete_module: c_long = 5000 + 169; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 5000 + 170; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 5000 + 171; +pub const SYS_quotactl: c_long = 5000 + 172; +pub const SYS_nfsservctl: c_long = 5000 + 173; +pub const SYS_getpmsg: c_long = 5000 + 174; +pub const SYS_putpmsg: c_long = 5000 + 175; +pub const SYS_afs_syscall: c_long = 5000 + 176; +pub const SYS_gettid: c_long = 5000 + 178; +pub const SYS_readahead: c_long = 5000 + 179; +pub const SYS_setxattr: c_long = 5000 + 180; +pub const SYS_lsetxattr: c_long = 5000 + 181; +pub const SYS_fsetxattr: c_long = 5000 + 182; +pub const SYS_getxattr: c_long = 5000 + 183; +pub const SYS_lgetxattr: c_long = 5000 + 184; +pub const SYS_fgetxattr: c_long = 5000 + 185; +pub const SYS_listxattr: c_long = 5000 + 186; +pub const SYS_llistxattr: c_long = 5000 + 187; +pub const SYS_flistxattr: c_long = 5000 + 188; +pub const SYS_removexattr: c_long = 5000 + 189; +pub const SYS_lremovexattr: c_long = 5000 + 190; +pub const SYS_fremovexattr: c_long = 5000 + 191; +pub const SYS_tkill: c_long = 5000 + 192; +pub const SYS_futex: c_long = 5000 + 194; +pub const SYS_sched_setaffinity: c_long = 5000 + 195; +pub const SYS_sched_getaffinity: c_long = 5000 + 196; +pub const SYS_cacheflush: c_long = 5000 + 197; +pub const SYS_cachectl: c_long = 5000 + 198; +pub const SYS_sysmips: c_long = 5000 + 199; +pub const SYS_io_setup: c_long = 5000 + 200; +pub const SYS_io_destroy: c_long = 5000 + 201; +pub const SYS_io_getevents: c_long = 5000 + 202; +pub const SYS_io_submit: c_long = 5000 + 203; +pub const SYS_io_cancel: c_long = 5000 + 204; +pub const SYS_exit_group: c_long = 5000 + 205; +pub const SYS_lookup_dcookie: c_long = 5000 + 206; +pub const SYS_epoll_create: c_long = 5000 + 207; +pub const SYS_epoll_ctl: c_long = 5000 + 208; +pub const SYS_epoll_wait: c_long = 5000 + 209; +pub const SYS_remap_file_pages: c_long = 5000 + 210; +pub const SYS_rt_sigreturn: c_long = 5000 + 211; +pub const SYS_set_tid_address: c_long = 5000 + 212; +pub const SYS_restart_syscall: c_long = 5000 + 213; +pub const SYS_semtimedop: c_long = 5000 + 214; +pub const SYS_fadvise64: c_long = 5000 + 215; +pub const SYS_timer_create: c_long = 5000 + 216; +pub const SYS_timer_settime: c_long = 5000 + 217; +pub const SYS_timer_gettime: c_long = 5000 + 218; +pub const SYS_timer_getoverrun: c_long = 5000 + 219; +pub const SYS_timer_delete: c_long = 5000 + 220; +pub const SYS_clock_settime: c_long = 5000 + 221; +pub const SYS_clock_gettime: c_long = 5000 + 222; +pub const SYS_clock_getres: c_long = 5000 + 223; +pub const SYS_clock_nanosleep: c_long = 5000 + 224; +pub const SYS_tgkill: c_long = 5000 + 225; +pub const SYS_utimes: c_long = 5000 + 226; +pub const SYS_mbind: c_long = 5000 + 227; +pub const SYS_get_mempolicy: c_long = 5000 + 228; +pub const SYS_set_mempolicy: c_long = 5000 + 229; +pub const SYS_mq_open: c_long = 5000 + 230; +pub const SYS_mq_unlink: c_long = 5000 + 231; +pub const SYS_mq_timedsend: c_long = 5000 + 232; +pub const SYS_mq_timedreceive: c_long = 5000 + 233; +pub const SYS_mq_notify: c_long = 5000 + 234; +pub const SYS_mq_getsetattr: c_long = 5000 + 235; +pub const SYS_vserver: c_long = 5000 + 236; +pub const SYS_waitid: c_long = 5000 + 237; +/* pub const SYS_sys_setaltroot: c_long = 5000 + 238; */ +pub const SYS_add_key: c_long = 5000 + 239; +pub const SYS_request_key: c_long = 5000 + 240; +pub const SYS_keyctl: c_long = 5000 + 241; +pub const SYS_set_thread_area: c_long = 5000 + 242; +pub const SYS_inotify_init: c_long = 5000 + 243; +pub const SYS_inotify_add_watch: c_long = 5000 + 244; +pub const SYS_inotify_rm_watch: c_long = 5000 + 245; +pub const SYS_migrate_pages: c_long = 5000 + 246; +pub const SYS_openat: c_long = 5000 + 247; +pub const SYS_mkdirat: c_long = 5000 + 248; +pub const SYS_mknodat: c_long = 5000 + 249; +pub const SYS_fchownat: c_long = 5000 + 250; +pub const SYS_futimesat: c_long = 5000 + 251; +pub const SYS_newfstatat: c_long = 5000 + 252; +pub const SYS_unlinkat: c_long = 5000 + 253; +pub const SYS_renameat: c_long = 5000 + 254; +pub const SYS_linkat: c_long = 5000 + 255; +pub const SYS_symlinkat: c_long = 5000 + 256; +pub const SYS_readlinkat: c_long = 5000 + 257; +pub const SYS_fchmodat: c_long = 5000 + 258; +pub const SYS_faccessat: c_long = 5000 + 259; +pub const SYS_pselect6: c_long = 5000 + 260; +pub const SYS_ppoll: c_long = 5000 + 261; +pub const SYS_unshare: c_long = 5000 + 262; +pub const SYS_splice: c_long = 5000 + 263; +pub const SYS_sync_file_range: c_long = 5000 + 264; +pub const SYS_tee: c_long = 5000 + 265; +pub const SYS_vmsplice: c_long = 5000 + 266; +pub const SYS_move_pages: c_long = 5000 + 267; +pub const SYS_set_robust_list: c_long = 5000 + 268; +pub const SYS_get_robust_list: c_long = 5000 + 269; +pub const SYS_kexec_load: c_long = 5000 + 270; +pub const SYS_getcpu: c_long = 5000 + 271; +pub const SYS_epoll_pwait: c_long = 5000 + 272; +pub const SYS_ioprio_set: c_long = 5000 + 273; +pub const SYS_ioprio_get: c_long = 5000 + 274; +pub const SYS_utimensat: c_long = 5000 + 275; +pub const SYS_signalfd: c_long = 5000 + 276; +pub const SYS_timerfd: c_long = 5000 + 277; +pub const SYS_eventfd: c_long = 5000 + 278; +pub const SYS_fallocate: c_long = 5000 + 279; +pub const SYS_timerfd_create: c_long = 5000 + 280; +pub const SYS_timerfd_gettime: c_long = 5000 + 281; +pub const SYS_timerfd_settime: c_long = 5000 + 282; +pub const SYS_signalfd4: c_long = 5000 + 283; +pub const SYS_eventfd2: c_long = 5000 + 284; +pub const SYS_epoll_create1: c_long = 5000 + 285; +pub const SYS_dup3: c_long = 5000 + 286; +pub const SYS_pipe2: c_long = 5000 + 287; +pub const SYS_inotify_init1: c_long = 5000 + 288; +pub const SYS_preadv: c_long = 5000 + 289; +pub const SYS_pwritev: c_long = 5000 + 290; +pub const SYS_rt_tgsigqueueinfo: c_long = 5000 + 291; +pub const SYS_perf_event_open: c_long = 5000 + 292; +pub const SYS_accept4: c_long = 5000 + 293; +pub const SYS_recvmmsg: c_long = 5000 + 294; +pub const SYS_fanotify_init: c_long = 5000 + 295; +pub const SYS_fanotify_mark: c_long = 5000 + 296; +pub const SYS_prlimit64: c_long = 5000 + 297; +pub const SYS_name_to_handle_at: c_long = 5000 + 298; +pub const SYS_open_by_handle_at: c_long = 5000 + 299; +pub const SYS_clock_adjtime: c_long = 5000 + 300; +pub const SYS_syncfs: c_long = 5000 + 301; +pub const SYS_sendmmsg: c_long = 5000 + 302; +pub const SYS_setns: c_long = 5000 + 303; +pub const SYS_process_vm_readv: c_long = 5000 + 304; +pub const SYS_process_vm_writev: c_long = 5000 + 305; +pub const SYS_kcmp: c_long = 5000 + 306; +pub const SYS_finit_module: c_long = 5000 + 307; +pub const SYS_getdents64: c_long = 5000 + 308; +pub const SYS_sched_setattr: c_long = 5000 + 309; +pub const SYS_sched_getattr: c_long = 5000 + 310; +pub const SYS_renameat2: c_long = 5000 + 311; +pub const SYS_seccomp: c_long = 5000 + 312; +pub const SYS_getrandom: c_long = 5000 + 313; +pub const SYS_memfd_create: c_long = 5000 + 314; +pub const SYS_bpf: c_long = 5000 + 315; +pub const SYS_execveat: c_long = 5000 + 316; +pub const SYS_userfaultfd: c_long = 5000 + 317; +pub const SYS_membarrier: c_long = 5000 + 318; +pub const SYS_mlock2: c_long = 5000 + 319; +pub const SYS_copy_file_range: c_long = 5000 + 320; +pub const SYS_preadv2: c_long = 5000 + 321; +pub const SYS_pwritev2: c_long = 5000 + 322; +pub const SYS_pkey_mprotect: c_long = 5000 + 323; +pub const SYS_pkey_alloc: c_long = 5000 + 324; +pub const SYS_pkey_free: c_long = 5000 + 325; +pub const SYS_statx: c_long = 5000 + 326; +pub const SYS_pidfd_send_signal: c_long = 5000 + 424; +pub const SYS_io_uring_setup: c_long = 5000 + 425; +pub const SYS_io_uring_enter: c_long = 5000 + 426; +pub const SYS_io_uring_register: c_long = 5000 + 427; +pub const SYS_open_tree: c_long = 5000 + 428; +pub const SYS_move_mount: c_long = 5000 + 429; +pub const SYS_fsopen: c_long = 5000 + 430; +pub const SYS_fsconfig: c_long = 5000 + 431; +pub const SYS_fsmount: c_long = 5000 + 432; +pub const SYS_fspick: c_long = 5000 + 433; +pub const SYS_pidfd_open: c_long = 5000 + 434; +pub const SYS_clone3: c_long = 5000 + 435; +pub const SYS_close_range: c_long = 5000 + 436; +pub const SYS_openat2: c_long = 5000 + 437; +pub const SYS_pidfd_getfd: c_long = 5000 + 438; +pub const SYS_faccessat2: c_long = 5000 + 439; +pub const SYS_process_madvise: c_long = 5000 + 440; +pub const SYS_epoll_pwait2: c_long = 5000 + 441; +pub const SYS_mount_setattr: c_long = 5000 + 442; +pub const SYS_quotactl_fd: c_long = 5000 + 443; +pub const SYS_landlock_create_ruleset: c_long = 5000 + 444; +pub const SYS_landlock_add_rule: c_long = 5000 + 445; +pub const SYS_landlock_restrict_self: c_long = 5000 + 446; +pub const SYS_memfd_secret: c_long = 5000 + 447; +pub const SYS_process_mrelease: c_long = 5000 + 448; +pub const SYS_futex_waitv: c_long = 5000 + 449; +pub const SYS_set_mempolicy_home_node: c_long = 5000 + 450; + +pub const O_DIRECT: c_int = 0x8000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 256; +pub const O_EXCL: c_int = 1024; +pub const O_NOCTTY: c_int = 2048; +pub const O_NONBLOCK: c_int = 128; +pub const O_SYNC: c_int = 0x4010; +pub const O_RSYNC: c_int = 0x4010; +pub const O_DSYNC: c_int = 0x10; +pub const O_ASYNC: c_int = 0x1000; +pub const O_LARGEFILE: c_int = 0x2000; + +pub const EDEADLK: c_int = 45; +pub const ENAMETOOLONG: c_int = 78; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 89; +pub const ENOTEMPTY: c_int = 93; +pub const ELOOP: c_int = 90; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EMULTIHOP: c_int = 74; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EBADMSG: c_int = 77; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; +pub const EUCLEAN: c_int = 135; +pub const ENOTNAM: c_int = 137; +pub const ENAVAIL: c_int = 138; +pub const EISNAM: c_int = 139; +pub const EREMOTEIO: c_int = 140; +pub const EDQUOT: c_int = 1133; +pub const ENOMEDIUM: c_int = 159; +pub const EMEDIUMTYPE: c_int = 160; +pub const ECANCELED: c_int = 158; +pub const ENOKEY: c_int = 161; +pub const EKEYEXPIRED: c_int = 162; +pub const EKEYREVOKED: c_int = 163; +pub const EKEYREJECTED: c_int = 164; +pub const EOWNERDEAD: c_int = 165; +pub const ENOTRECOVERABLE: c_int = 166; +pub const ERFKILL: c_int = 167; + +pub const MAP_ANON: c_int = 0x800; +pub const MAP_GROWSDOWN: c_int = 0x1000; +pub const MAP_DENYWRITE: c_int = 0x2000; +pub const MAP_EXECUTABLE: c_int = 0x4000; +pub const MAP_LOCKED: c_int = 0x8000; +pub const MAP_NORESERVE: c_int = 0x400; +pub const MAP_POPULATE: c_int = 0x10000; +pub const MAP_NONBLOCK: c_int = 0x20000; +pub const MAP_STACK: c_int = 0x40000; +pub const MAP_HUGETLB: c_int = 0x080000; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000008; +pub const SA_NOCLDWAIT: c_int = 0x00010000; + +pub const SIGEMT: c_int = 7; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = 22; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 22; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 0x1; +pub const SIG_UNBLOCK: c_int = 0x2; + +pub const POLLWRNORM: c_short = 0x004; +pub const POLLWRBAND: c_short = 0x100; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x00000100; +pub const TOSTOP: crate::tcflag_t = 0x00008000; +pub const FLUSHO: crate::tcflag_t = 0x00002000; +pub const EXTPROC: crate::tcflag_t = 0o200000; + +pub const F_GETLK: c_int = 14; +pub const F_GETOWN: c_int = 23; +pub const F_SETOWN: c_int = 24; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EHWPOISON: c_int = 168; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mod.rs new file mode 100644 index 00000000000000..6365dbece45788 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/mod.rs @@ -0,0 +1,88 @@ +use crate::prelude::*; + +pub type regoff_t = c_long; + +s! { + // MIPS implementation is special, see the subfolder. + #[cfg(not(target_arch = "mips64"))] + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct pthread_attr_t { + __size: [u64; 7], + } + + pub struct sigset_t { + __val: [c_ulong; 16], + } + + // PowerPC implementation is special, see the subfolder. + #[cfg(not(target_arch = "powerpc64"))] + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __pad1: Padding, + __pad2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __pad1: Padding, + __pad2: Padding, + } + + pub struct sem_t { + __val: [c_int; 8], + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "mips64")] { + mod mips64; + pub use self::mips64::*; + } else if #[cfg(any(target_arch = "powerpc64"))] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(any(target_arch = "s390x"))] { + mod s390x; + pub use self::s390x::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(any(target_arch = "riscv64"))] { + mod riscv64; + pub use self::riscv64::*; + } else if #[cfg(any(target_arch = "loongarch64"))] { + mod loongarch64; + pub use self::loongarch64::*; + } else if #[cfg(any(target_arch = "wasm32"))] { + mod wasm32; + pub use self::wasm32::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/powerpc64.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/powerpc64.rs new file mode 100644 index 00000000000000..4885ea2f0e1822 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/powerpc64.rs @@ -0,0 +1,730 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type __u64 = c_ulong; +pub type __s64 = c_long; +pub type nlink_t = u64; +pub type blksize_t = c_long; + +pub type stat64 = stat; + +s! { + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_line: crate::cc_t, + pub __c_ispeed: crate::speed_t, + pub __c_ospeed: crate::speed_t, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_segsz: size_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: c_ulong, + __unused: Padding<[c_ulong; 2]>, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } +} + +pub const MADV_SOFT_OFFLINE: c_int = 101; +#[deprecated( + since = "0.2.175", + note = "Linux does not define MAP_32BIT on any architectures \ + other than x86 and x86_64, this constant will be removed in the future" +)] +pub const MAP_32BIT: c_int = 0x0040; +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x20000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_LARGEFILE: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0x2000; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x80; +pub const MAP_NORESERVE: c_int = 0x40; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const PTRACE_SYSEMU: c_int = 0x1d; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 0x1e; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const SIGSTKSZ: size_t = 10240; +pub const MINSIGSTKSZ: size_t = 4096; + +// Syscall table +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_waitpid: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_time: c_long = 13; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_break: c_long = 17; +pub const SYS_oldstat: c_long = 18; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_stime: c_long = 25; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_oldfstat: c_long = 28; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_stty: c_long = 31; +pub const SYS_gtty: c_long = 32; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_ftime: c_long = 35; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_prof: c_long = 44; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_signal: c_long = 48; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_lock: c_long = 53; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_mpx: c_long = 56; +pub const SYS_setpgid: c_long = 57; +pub const SYS_ulimit: c_long = 58; +pub const SYS_oldolduname: c_long = 59; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sgetmask: c_long = 68; +pub const SYS_ssetmask: c_long = 69; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrlimit: c_long = 76; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_select: c_long = 82; +pub const SYS_symlink: c_long = 83; +pub const SYS_oldlstat: c_long = 84; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_profil: c_long = 98; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_ioperm: c_long = 101; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_olduname: c_long = 109; +pub const SYS_iopl: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_vm86: c_long = 113; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_modify_ldt: c_long = 123; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 166; +pub const SYS_poll: c_long = 167; +pub const SYS_nfsservctl: c_long = 168; +pub const SYS_setresgid: c_long = 169; +pub const SYS_getresgid: c_long = 170; +pub const SYS_prctl: c_long = 171; +pub const SYS_rt_sigreturn: c_long = 172; +pub const SYS_rt_sigaction: c_long = 173; +pub const SYS_rt_sigprocmask: c_long = 174; +pub const SYS_rt_sigpending: c_long = 175; +pub const SYS_rt_sigtimedwait: c_long = 176; +pub const SYS_rt_sigqueueinfo: c_long = 177; +pub const SYS_rt_sigsuspend: c_long = 178; +pub const SYS_pread64: c_long = 179; +pub const SYS_pwrite64: c_long = 180; +pub const SYS_chown: c_long = 181; +pub const SYS_getcwd: c_long = 182; +pub const SYS_capget: c_long = 183; +pub const SYS_capset: c_long = 184; +pub const SYS_sigaltstack: c_long = 185; +pub const SYS_sendfile: c_long = 186; +pub const SYS_getpmsg: c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: c_long = 189; +pub const SYS_ugetrlimit: c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: c_long = 191; +pub const SYS_pciconfig_read: c_long = 198; +pub const SYS_pciconfig_write: c_long = 199; +pub const SYS_pciconfig_iobase: c_long = 200; +pub const SYS_multiplexer: c_long = 201; +pub const SYS_getdents64: c_long = 202; +pub const SYS_pivot_root: c_long = 203; +pub const SYS_madvise: c_long = 205; +pub const SYS_mincore: c_long = 206; +pub const SYS_gettid: c_long = 207; +pub const SYS_tkill: c_long = 208; +pub const SYS_setxattr: c_long = 209; +pub const SYS_lsetxattr: c_long = 210; +pub const SYS_fsetxattr: c_long = 211; +pub const SYS_getxattr: c_long = 212; +pub const SYS_lgetxattr: c_long = 213; +pub const SYS_fgetxattr: c_long = 214; +pub const SYS_listxattr: c_long = 215; +pub const SYS_llistxattr: c_long = 216; +pub const SYS_flistxattr: c_long = 217; +pub const SYS_removexattr: c_long = 218; +pub const SYS_lremovexattr: c_long = 219; +pub const SYS_fremovexattr: c_long = 220; +pub const SYS_futex: c_long = 221; +pub const SYS_sched_setaffinity: c_long = 222; +pub const SYS_sched_getaffinity: c_long = 223; +pub const SYS_tuxcall: c_long = 225; +pub const SYS_io_setup: c_long = 227; +pub const SYS_io_destroy: c_long = 228; +pub const SYS_io_getevents: c_long = 229; +pub const SYS_io_submit: c_long = 230; +pub const SYS_io_cancel: c_long = 231; +pub const SYS_set_tid_address: c_long = 232; +pub const SYS_exit_group: c_long = 234; +pub const SYS_lookup_dcookie: c_long = 235; +pub const SYS_epoll_create: c_long = 236; +pub const SYS_epoll_ctl: c_long = 237; +pub const SYS_epoll_wait: c_long = 238; +pub const SYS_remap_file_pages: c_long = 239; +pub const SYS_timer_create: c_long = 240; +pub const SYS_timer_settime: c_long = 241; +pub const SYS_timer_gettime: c_long = 242; +pub const SYS_timer_getoverrun: c_long = 243; +pub const SYS_timer_delete: c_long = 244; +pub const SYS_clock_settime: c_long = 245; +pub const SYS_clock_gettime: c_long = 246; +pub const SYS_clock_getres: c_long = 247; +pub const SYS_clock_nanosleep: c_long = 248; +pub const SYS_swapcontext: c_long = 249; +pub const SYS_tgkill: c_long = 250; +pub const SYS_utimes: c_long = 251; +pub const SYS_statfs64: c_long = 252; +pub const SYS_fstatfs64: c_long = 253; +pub const SYS_rtas: c_long = 255; +pub const SYS_sys_debug_setcontext: c_long = 256; +pub const SYS_migrate_pages: c_long = 258; +pub const SYS_mbind: c_long = 259; +pub const SYS_get_mempolicy: c_long = 260; +pub const SYS_set_mempolicy: c_long = 261; +pub const SYS_mq_open: c_long = 262; +pub const SYS_mq_unlink: c_long = 263; +pub const SYS_mq_timedsend: c_long = 264; +pub const SYS_mq_timedreceive: c_long = 265; +pub const SYS_mq_notify: c_long = 266; +pub const SYS_mq_getsetattr: c_long = 267; +pub const SYS_kexec_load: c_long = 268; +pub const SYS_add_key: c_long = 269; +pub const SYS_request_key: c_long = 270; +pub const SYS_keyctl: c_long = 271; +pub const SYS_waitid: c_long = 272; +pub const SYS_ioprio_set: c_long = 273; +pub const SYS_ioprio_get: c_long = 274; +pub const SYS_inotify_init: c_long = 275; +pub const SYS_inotify_add_watch: c_long = 276; +pub const SYS_inotify_rm_watch: c_long = 277; +pub const SYS_spu_run: c_long = 278; +pub const SYS_spu_create: c_long = 279; +pub const SYS_pselect6: c_long = 280; +pub const SYS_ppoll: c_long = 281; +pub const SYS_unshare: c_long = 282; +pub const SYS_splice: c_long = 283; +pub const SYS_tee: c_long = 284; +pub const SYS_vmsplice: c_long = 285; +pub const SYS_openat: c_long = 286; +pub const SYS_mkdirat: c_long = 287; +pub const SYS_mknodat: c_long = 288; +pub const SYS_fchownat: c_long = 289; +pub const SYS_futimesat: c_long = 290; +pub const SYS_newfstatat: c_long = 291; +pub const SYS_unlinkat: c_long = 292; +pub const SYS_renameat: c_long = 293; +pub const SYS_linkat: c_long = 294; +pub const SYS_symlinkat: c_long = 295; +pub const SYS_readlinkat: c_long = 296; +pub const SYS_fchmodat: c_long = 297; +pub const SYS_faccessat: c_long = 298; +pub const SYS_get_robust_list: c_long = 299; +pub const SYS_set_robust_list: c_long = 300; +pub const SYS_move_pages: c_long = 301; +pub const SYS_getcpu: c_long = 302; +pub const SYS_epoll_pwait: c_long = 303; +pub const SYS_utimensat: c_long = 304; +pub const SYS_signalfd: c_long = 305; +pub const SYS_timerfd_create: c_long = 306; +pub const SYS_eventfd: c_long = 307; +pub const SYS_sync_file_range2: c_long = 308; +pub const SYS_fallocate: c_long = 309; +pub const SYS_subpage_prot: c_long = 310; +pub const SYS_timerfd_settime: c_long = 311; +pub const SYS_timerfd_gettime: c_long = 312; +pub const SYS_signalfd4: c_long = 313; +pub const SYS_eventfd2: c_long = 314; +pub const SYS_epoll_create1: c_long = 315; +pub const SYS_dup3: c_long = 316; +pub const SYS_pipe2: c_long = 317; +pub const SYS_inotify_init1: c_long = 318; +pub const SYS_perf_event_open: c_long = 319; +pub const SYS_preadv: c_long = 320; +pub const SYS_pwritev: c_long = 321; +pub const SYS_rt_tgsigqueueinfo: c_long = 322; +pub const SYS_fanotify_init: c_long = 323; +pub const SYS_fanotify_mark: c_long = 324; +pub const SYS_prlimit64: c_long = 325; +pub const SYS_socket: c_long = 326; +pub const SYS_bind: c_long = 327; +pub const SYS_connect: c_long = 328; +pub const SYS_listen: c_long = 329; +pub const SYS_accept: c_long = 330; +pub const SYS_getsockname: c_long = 331; +pub const SYS_getpeername: c_long = 332; +pub const SYS_socketpair: c_long = 333; +pub const SYS_send: c_long = 334; +pub const SYS_sendto: c_long = 335; +pub const SYS_recv: c_long = 336; +pub const SYS_recvfrom: c_long = 337; +pub const SYS_shutdown: c_long = 338; +pub const SYS_setsockopt: c_long = 339; +pub const SYS_getsockopt: c_long = 340; +pub const SYS_sendmsg: c_long = 341; +pub const SYS_recvmsg: c_long = 342; +pub const SYS_recvmmsg: c_long = 343; +pub const SYS_accept4: c_long = 344; +pub const SYS_name_to_handle_at: c_long = 345; +pub const SYS_open_by_handle_at: c_long = 346; +pub const SYS_clock_adjtime: c_long = 347; +pub const SYS_syncfs: c_long = 348; +pub const SYS_sendmmsg: c_long = 349; +pub const SYS_setns: c_long = 350; +pub const SYS_process_vm_readv: c_long = 351; +pub const SYS_process_vm_writev: c_long = 352; +pub const SYS_finit_module: c_long = 353; +pub const SYS_kcmp: c_long = 354; +pub const SYS_sched_setattr: c_long = 355; +pub const SYS_sched_getattr: c_long = 356; +pub const SYS_renameat2: c_long = 357; +pub const SYS_seccomp: c_long = 358; +pub const SYS_getrandom: c_long = 359; +pub const SYS_memfd_create: c_long = 360; +pub const SYS_bpf: c_long = 361; +pub const SYS_execveat: c_long = 362; +pub const SYS_switch_endian: c_long = 363; +pub const SYS_userfaultfd: c_long = 364; +pub const SYS_membarrier: c_long = 365; +pub const SYS_mlock2: c_long = 378; +pub const SYS_copy_file_range: c_long = 379; +pub const SYS_preadv2: c_long = 380; +pub const SYS_pwritev2: c_long = 381; +pub const SYS_kexec_file_load: c_long = 382; +pub const SYS_statx: c_long = 383; +pub const SYS_pkey_alloc: c_long = 384; +pub const SYS_pkey_free: c_long = 385; +pub const SYS_pkey_mprotect: c_long = 386; +pub const SYS_rseq: c_long = 387; +pub const SYS_io_pgetevents: c_long = 388; +pub const SYS_semtimedop: c_long = 392; +pub const SYS_semget: c_long = 393; +pub const SYS_semctl: c_long = 394; +pub const SYS_shmget: c_long = 395; +pub const SYS_shmctl: c_long = 396; +pub const SYS_shmat: c_long = 397; +pub const SYS_shmdt: c_long = 398; +pub const SYS_msgget: c_long = 399; +pub const SYS_msgsnd: c_long = 400; +pub const SYS_msgrcv: c_long = 401; +pub const SYS_msgctl: c_long = 402; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = 58; + +pub const EXTPROC: crate::tcflag_t = 0x10000000; +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: crate::tcflag_t = 0x00000400; +pub const TOSTOP: crate::tcflag_t = 0x00400000; +pub const FLUSHO: crate::tcflag_t = 0x00800000; + +pub const MCL_CURRENT: c_int = 0x2000; +pub const MCL_FUTURE: c_int = 0x4000; +pub const MCL_ONFAULT: c_int = 0x8000; +pub const CBAUD: crate::tcflag_t = 0xff; +pub const TAB1: c_int = 0x400; +pub const TAB2: c_int = 0x800; +pub const TAB3: c_int = 0xc00; +pub const CR1: c_int = 0x1000; +pub const CR2: c_int = 0x2000; +pub const CR3: c_int = 0x3000; +pub const FF1: c_int = 0x4000; +pub const BS1: c_int = 0x8000; +pub const VT1: c_int = 0x10000; +pub const VWERASE: usize = 10; +pub const VREPRINT: usize = 11; +pub const VSUSP: usize = 12; +pub const VSTART: usize = 13; +pub const VSTOP: usize = 14; +pub const VDISCARD: usize = 16; +pub const VTIME: usize = 7; +pub const IXON: crate::tcflag_t = 0x00000200; +pub const IXOFF: crate::tcflag_t = 0x00000400; +pub const ONLCR: crate::tcflag_t = 0x2; +pub const CSIZE: crate::tcflag_t = 0x00000300; + +pub const CS6: crate::tcflag_t = 0x00000100; +pub const CS7: crate::tcflag_t = 0x00000200; +pub const CS8: crate::tcflag_t = 0x00000300; +pub const CSTOPB: crate::tcflag_t = 0x00000400; +pub const CREAD: crate::tcflag_t = 0x00000800; +pub const PARENB: crate::tcflag_t = 0x00001000; +pub const PARODD: crate::tcflag_t = 0x00002000; +pub const HUPCL: crate::tcflag_t = 0x00004000; +pub const CLOCAL: crate::tcflag_t = 0x00008000; +pub const ECHOKE: crate::tcflag_t = 0x00000001; +pub const ECHOE: crate::tcflag_t = 0x00000002; +pub const ECHOK: crate::tcflag_t = 0x00000004; +pub const ECHONL: crate::tcflag_t = 0x00000010; +pub const ECHOPRT: crate::tcflag_t = 0x00000020; +pub const ECHOCTL: crate::tcflag_t = 0x00000040; +pub const ISIG: crate::tcflag_t = 0x00000080; +pub const ICANON: crate::tcflag_t = 0x00000100; +pub const PENDIN: crate::tcflag_t = 0x20000000; +pub const NOFLSH: crate::tcflag_t = 0x80000000; + +pub const CIBAUD: crate::tcflag_t = 0o77600000; +pub const CBAUDEX: crate::tcflag_t = 0o0000020; +pub const VSWTC: usize = 9; +pub const OLCUC: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o0001400; +pub const CRDLY: crate::tcflag_t = 0o0030000; +pub const TABDLY: crate::tcflag_t = 0o0006000; +pub const BSDLY: crate::tcflag_t = 0o0100000; +pub const FFDLY: crate::tcflag_t = 0o0040000; +pub const VTDLY: crate::tcflag_t = 0o0200000; +pub const XTABS: crate::tcflag_t = 0o00006000; + +pub const B57600: crate::speed_t = 0o00020; +pub const B115200: crate::speed_t = 0o00021; +pub const B230400: crate::speed_t = 0o00022; +pub const B460800: crate::speed_t = 0o00023; +pub const B500000: crate::speed_t = 0o00024; +pub const B576000: crate::speed_t = 0o00025; +pub const B921600: crate::speed_t = 0o00026; +pub const B1000000: crate::speed_t = 0o00027; +pub const B1152000: crate::speed_t = 0o00030; +pub const B1500000: crate::speed_t = 0o00031; +pub const B2000000: crate::speed_t = 0o00032; +pub const B2500000: crate::speed_t = 0o00033; +pub const B3000000: crate::speed_t = 0o00034; +pub const B3500000: crate::speed_t = 0o00035; +pub const B4000000: crate::speed_t = 0o00036; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/riscv64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/riscv64/mod.rs new file mode 100644 index 00000000000000..bd395e49cefc19 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/riscv64/mod.rs @@ -0,0 +1,649 @@ +//! RISC-V-specific definitions for 64-bit linux-like values + +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = c_int; + +pub type nlink_t = c_uint; +pub type blksize_t = c_int; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + __pad1: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + __pad2: Padding, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_int; 2usize]>, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } +} + +s_no_extra_traits! { + pub struct ucontext_t { + pub __uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_sigmask: crate::sigset_t, + pub uc_mcontext: mcontext_t, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub __gregs: [c_ulong; 32], + pub __fpregs: __riscv_mc_fp_state, + } + + pub union __riscv_mc_fp_state { + pub __f: __riscv_mc_f_ext_state, + pub __d: __riscv_mc_d_ext_state, + pub __q: __riscv_mc_q_ext_state, + } + + pub struct __riscv_mc_f_ext_state { + pub __f: [c_uint; 32], + pub __fcsr: c_uint, + } + + pub struct __riscv_mc_d_ext_state { + pub __f: [c_ulonglong; 32], + pub __fcsr: c_uint, + } + + #[repr(align(16))] + pub struct __riscv_mc_q_ext_state { + pub __f: [c_ulonglong; 64], + pub __fcsr: c_uint, + pub __glibc_reserved: [c_uint; 3], + } +} + +pub const SYS_read: c_long = 63; +pub const SYS_write: c_long = 64; +pub const SYS_close: c_long = 57; +pub const SYS_fstat: c_long = 80; +pub const SYS_lseek: c_long = 62; +pub const SYS_mmap: c_long = 222; +pub const SYS_mprotect: c_long = 226; +pub const SYS_munmap: c_long = 215; +pub const SYS_brk: c_long = 214; +pub const SYS_rt_sigaction: c_long = 134; +pub const SYS_rt_sigprocmask: c_long = 135; +pub const SYS_rt_sigreturn: c_long = 139; +pub const SYS_ioctl: c_long = 29; +pub const SYS_pread64: c_long = 67; +pub const SYS_pwrite64: c_long = 68; +pub const SYS_readv: c_long = 65; +pub const SYS_writev: c_long = 66; +pub const SYS_sched_yield: c_long = 124; +pub const SYS_mremap: c_long = 216; +pub const SYS_msync: c_long = 227; +pub const SYS_mincore: c_long = 232; +pub const SYS_madvise: c_long = 233; +pub const SYS_shmget: c_long = 194; +pub const SYS_shmat: c_long = 196; +pub const SYS_shmctl: c_long = 195; +pub const SYS_dup: c_long = 23; +pub const SYS_nanosleep: c_long = 101; +pub const SYS_getitimer: c_long = 102; +pub const SYS_setitimer: c_long = 103; +pub const SYS_getpid: c_long = 172; +pub const SYS_sendfile: c_long = 71; +pub const SYS_socket: c_long = 198; +pub const SYS_connect: c_long = 203; +pub const SYS_accept: c_long = 202; +pub const SYS_sendto: c_long = 206; +pub const SYS_recvfrom: c_long = 207; +pub const SYS_sendmsg: c_long = 211; +pub const SYS_recvmsg: c_long = 212; +pub const SYS_shutdown: c_long = 210; +pub const SYS_bind: c_long = 200; +pub const SYS_listen: c_long = 201; +pub const SYS_getsockname: c_long = 204; +pub const SYS_getpeername: c_long = 205; +pub const SYS_socketpair: c_long = 199; +pub const SYS_setsockopt: c_long = 208; +pub const SYS_getsockopt: c_long = 209; +pub const SYS_clone: c_long = 220; +pub const SYS_execve: c_long = 221; +pub const SYS_exit: c_long = 93; +pub const SYS_wait4: c_long = 260; +pub const SYS_kill: c_long = 129; +pub const SYS_uname: c_long = 160; +pub const SYS_semget: c_long = 190; +pub const SYS_semop: c_long = 193; +pub const SYS_semctl: c_long = 191; +pub const SYS_shmdt: c_long = 197; +pub const SYS_msgget: c_long = 186; +pub const SYS_msgsnd: c_long = 189; +pub const SYS_msgrcv: c_long = 188; +pub const SYS_msgctl: c_long = 187; +pub const SYS_fcntl: c_long = 25; +pub const SYS_flock: c_long = 32; +pub const SYS_fsync: c_long = 82; +pub const SYS_fdatasync: c_long = 83; +pub const SYS_truncate: c_long = 45; +pub const SYS_ftruncate: c_long = 46; +pub const SYS_getcwd: c_long = 17; +pub const SYS_chdir: c_long = 49; +pub const SYS_fchdir: c_long = 50; +pub const SYS_fchmod: c_long = 52; +pub const SYS_fchown: c_long = 55; +pub const SYS_umask: c_long = 166; +pub const SYS_gettimeofday: c_long = 169; +pub const SYS_getrlimit: c_long = 163; +pub const SYS_getrusage: c_long = 165; +pub const SYS_sysinfo: c_long = 179; +pub const SYS_times: c_long = 153; +pub const SYS_ptrace: c_long = 117; +pub const SYS_getuid: c_long = 174; +pub const SYS_syslog: c_long = 116; +pub const SYS_getgid: c_long = 176; +pub const SYS_setuid: c_long = 146; +pub const SYS_setgid: c_long = 144; +pub const SYS_geteuid: c_long = 175; +pub const SYS_getegid: c_long = 177; +pub const SYS_setpgid: c_long = 154; +pub const SYS_getppid: c_long = 173; +pub const SYS_setsid: c_long = 157; +pub const SYS_setreuid: c_long = 145; +pub const SYS_setregid: c_long = 143; +pub const SYS_getgroups: c_long = 158; +pub const SYS_setgroups: c_long = 159; +pub const SYS_setresuid: c_long = 147; +pub const SYS_getresuid: c_long = 148; +pub const SYS_setresgid: c_long = 149; +pub const SYS_getresgid: c_long = 150; +pub const SYS_getpgid: c_long = 155; +pub const SYS_setfsuid: c_long = 151; +pub const SYS_setfsgid: c_long = 152; +pub const SYS_getsid: c_long = 156; +pub const SYS_capget: c_long = 90; +pub const SYS_capset: c_long = 91; +pub const SYS_rt_sigpending: c_long = 136; +pub const SYS_rt_sigtimedwait: c_long = 137; +pub const SYS_rt_sigqueueinfo: c_long = 138; +pub const SYS_rt_sigsuspend: c_long = 133; +pub const SYS_sigaltstack: c_long = 132; +pub const SYS_personality: c_long = 92; +pub const SYS_statfs: c_long = 43; +pub const SYS_fstatfs: c_long = 44; +pub const SYS_getpriority: c_long = 141; +pub const SYS_setpriority: c_long = 140; +pub const SYS_sched_setparam: c_long = 118; +pub const SYS_sched_getparam: c_long = 121; +pub const SYS_sched_setscheduler: c_long = 119; +pub const SYS_sched_getscheduler: c_long = 120; +pub const SYS_sched_get_priority_max: c_long = 125; +pub const SYS_sched_get_priority_min: c_long = 126; +pub const SYS_sched_rr_get_interval: c_long = 127; +pub const SYS_mlock: c_long = 228; +pub const SYS_munlock: c_long = 229; +pub const SYS_mlockall: c_long = 230; +pub const SYS_munlockall: c_long = 231; +pub const SYS_vhangup: c_long = 58; +pub const SYS_pivot_root: c_long = 41; +pub const SYS_prctl: c_long = 167; +pub const SYS_adjtimex: c_long = 171; +pub const SYS_setrlimit: c_long = 164; +pub const SYS_chroot: c_long = 51; +pub const SYS_sync: c_long = 81; +pub const SYS_acct: c_long = 89; +pub const SYS_settimeofday: c_long = 170; +pub const SYS_mount: c_long = 40; +pub const SYS_umount2: c_long = 39; +pub const SYS_swapon: c_long = 224; +pub const SYS_swapoff: c_long = 225; +pub const SYS_reboot: c_long = 142; +pub const SYS_sethostname: c_long = 161; +pub const SYS_setdomainname: c_long = 162; +pub const SYS_init_module: c_long = 105; +pub const SYS_delete_module: c_long = 106; +pub const SYS_quotactl: c_long = 60; +pub const SYS_nfsservctl: c_long = 42; +pub const SYS_gettid: c_long = 178; +pub const SYS_readahead: c_long = 213; +pub const SYS_setxattr: c_long = 5; +pub const SYS_lsetxattr: c_long = 6; +pub const SYS_fsetxattr: c_long = 7; +pub const SYS_getxattr: c_long = 8; +pub const SYS_lgetxattr: c_long = 9; +pub const SYS_fgetxattr: c_long = 10; +pub const SYS_listxattr: c_long = 11; +pub const SYS_llistxattr: c_long = 12; +pub const SYS_flistxattr: c_long = 13; +pub const SYS_removexattr: c_long = 14; +pub const SYS_lremovexattr: c_long = 15; +pub const SYS_fremovexattr: c_long = 16; +pub const SYS_tkill: c_long = 130; +pub const SYS_futex: c_long = 98; +pub const SYS_sched_setaffinity: c_long = 122; +pub const SYS_sched_getaffinity: c_long = 123; +pub const SYS_io_setup: c_long = 0; +pub const SYS_io_destroy: c_long = 1; +pub const SYS_io_getevents: c_long = 4; +pub const SYS_io_submit: c_long = 2; +pub const SYS_io_cancel: c_long = 3; +pub const SYS_lookup_dcookie: c_long = 18; +pub const SYS_remap_file_pages: c_long = 234; +pub const SYS_getdents64: c_long = 61; +pub const SYS_set_tid_address: c_long = 96; +pub const SYS_restart_syscall: c_long = 128; +pub const SYS_semtimedop: c_long = 192; +pub const SYS_fadvise64: c_long = 223; +pub const SYS_timer_create: c_long = 107; +pub const SYS_timer_settime: c_long = 110; +pub const SYS_timer_gettime: c_long = 108; +pub const SYS_timer_getoverrun: c_long = 109; +pub const SYS_timer_delete: c_long = 111; +pub const SYS_clock_settime: c_long = 112; +pub const SYS_clock_gettime: c_long = 113; +pub const SYS_clock_getres: c_long = 114; +pub const SYS_clock_nanosleep: c_long = 115; +pub const SYS_exit_group: c_long = 94; +pub const SYS_epoll_ctl: c_long = 21; +pub const SYS_tgkill: c_long = 131; +pub const SYS_mbind: c_long = 235; +pub const SYS_set_mempolicy: c_long = 237; +pub const SYS_get_mempolicy: c_long = 236; +pub const SYS_mq_open: c_long = 180; +pub const SYS_mq_unlink: c_long = 181; +pub const SYS_mq_timedsend: c_long = 182; +pub const SYS_mq_timedreceive: c_long = 183; +pub const SYS_mq_notify: c_long = 184; +pub const SYS_mq_getsetattr: c_long = 185; +pub const SYS_kexec_load: c_long = 104; +pub const SYS_waitid: c_long = 95; +pub const SYS_add_key: c_long = 217; +pub const SYS_request_key: c_long = 218; +pub const SYS_keyctl: c_long = 219; +pub const SYS_ioprio_set: c_long = 30; +pub const SYS_ioprio_get: c_long = 31; +pub const SYS_inotify_add_watch: c_long = 27; +pub const SYS_inotify_rm_watch: c_long = 28; +pub const SYS_migrate_pages: c_long = 238; +pub const SYS_openat: c_long = 56; +pub const SYS_mkdirat: c_long = 34; +pub const SYS_mknodat: c_long = 33; +pub const SYS_fchownat: c_long = 54; +pub const SYS_newfstatat: c_long = 79; +pub const SYS_unlinkat: c_long = 35; +pub const SYS_linkat: c_long = 37; +pub const SYS_symlinkat: c_long = 36; +pub const SYS_readlinkat: c_long = 78; +pub const SYS_fchmodat: c_long = 53; +pub const SYS_faccessat: c_long = 48; +pub const SYS_pselect6: c_long = 72; +pub const SYS_ppoll: c_long = 73; +pub const SYS_unshare: c_long = 97; +pub const SYS_set_robust_list: c_long = 99; +pub const SYS_get_robust_list: c_long = 100; +pub const SYS_splice: c_long = 76; +pub const SYS_tee: c_long = 77; +pub const SYS_sync_file_range: c_long = 84; +pub const SYS_vmsplice: c_long = 75; +pub const SYS_move_pages: c_long = 239; +pub const SYS_utimensat: c_long = 88; +pub const SYS_epoll_pwait: c_long = 22; +pub const SYS_timerfd_create: c_long = 85; +pub const SYS_fallocate: c_long = 47; +pub const SYS_timerfd_settime: c_long = 86; +pub const SYS_timerfd_gettime: c_long = 87; +pub const SYS_accept4: c_long = 242; +pub const SYS_signalfd4: c_long = 74; +pub const SYS_eventfd2: c_long = 19; +pub const SYS_epoll_create1: c_long = 20; +pub const SYS_dup3: c_long = 24; +pub const SYS_pipe2: c_long = 59; +pub const SYS_inotify_init1: c_long = 26; +pub const SYS_preadv: c_long = 69; +pub const SYS_pwritev: c_long = 70; +pub const SYS_rt_tgsigqueueinfo: c_long = 240; +pub const SYS_perf_event_open: c_long = 241; +pub const SYS_recvmmsg: c_long = 243; +pub const SYS_fanotify_init: c_long = 262; +pub const SYS_fanotify_mark: c_long = 263; +pub const SYS_prlimit64: c_long = 261; +pub const SYS_name_to_handle_at: c_long = 264; +pub const SYS_open_by_handle_at: c_long = 265; +pub const SYS_clock_adjtime: c_long = 266; +pub const SYS_syncfs: c_long = 267; +pub const SYS_sendmmsg: c_long = 269; +pub const SYS_setns: c_long = 268; +pub const SYS_getcpu: c_long = 168; +pub const SYS_process_vm_readv: c_long = 270; +pub const SYS_process_vm_writev: c_long = 271; +pub const SYS_kcmp: c_long = 272; +pub const SYS_finit_module: c_long = 273; +pub const SYS_sched_setattr: c_long = 274; +pub const SYS_sched_getattr: c_long = 275; +pub const SYS_renameat2: c_long = 276; +pub const SYS_seccomp: c_long = 277; +pub const SYS_getrandom: c_long = 278; +pub const SYS_memfd_create: c_long = 279; +pub const SYS_bpf: c_long = 280; +pub const SYS_execveat: c_long = 281; +pub const SYS_userfaultfd: c_long = 282; +pub const SYS_membarrier: c_long = 283; +pub const SYS_mlock2: c_long = 284; +pub const SYS_copy_file_range: c_long = 285; +pub const SYS_preadv2: c_long = 286; +pub const SYS_pwritev2: c_long = 287; +pub const SYS_pkey_mprotect: c_long = 288; +pub const SYS_pkey_alloc: c_long = 289; +pub const SYS_pkey_free: c_long = 290; +pub const SYS_statx: c_long = 291; +pub const SYS_io_pgetevents: c_long = 292; +pub const SYS_rseq: c_long = 293; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; + +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_LARGEFILE: c_int = 0o100000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0x2000; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const NGREG: usize = 32; +pub const REG_PC: usize = 0; +pub const REG_RA: usize = 1; +pub const REG_SP: usize = 2; +pub const REG_TP: usize = 4; +pub const REG_S0: usize = 8; +pub const REG_S1: usize = 9; +pub const REG_A0: usize = 10; +pub const REG_S2: usize = 18; +pub const REG_NARGS: usize = 8; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/s390x.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/s390x.rs new file mode 100644 index 00000000000000..0ee6c11c6a1e62 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/s390x.rs @@ -0,0 +1,734 @@ +use crate::off_t; +use crate::prelude::*; + +pub type blksize_t = i64; +pub type nlink_t = u64; +pub type wchar_t = i32; +pub type greg_t = u64; +pub type __u64 = u64; +pub type __s64 = i64; +pub type statfs64 = statfs; +pub type stat64 = stat; + +s! { + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __pad1: Padding, + __pad2: Padding, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + __unused: Padding<[c_long; 3]>, + } + + pub struct statfs { + pub f_type: c_uint, + pub f_bsize: c_uint, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_uint, + pub f_frsize: c_uint, + pub f_flags: c_uint, + pub f_spare: [c_uint; 4], + } + + pub struct __psw_t { + pub mask: c_ulong, + pub addr: c_ulong, + } + + pub struct fpregset_t { + pub fpc: c_uint, + pub fprs: [fpreg_t; 16], + } + + pub struct mcontext_t { + pub psw: __psw_t, + pub gregs: [c_ulong; 16], + pub aregs: [c_uint; 16], + pub fpregs: fpregset_t, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + } +} + +s_no_extra_traits! { + pub union fpreg_t { + pub d: c_double, + pub f: c_float, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for fpreg_t { + fn eq(&self, _other: &fpreg_t) -> bool { + unimplemented!("traits") + } + } + + impl Eq for fpreg_t {} + + impl hash::Hash for fpreg_t { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") + } + } + } +} + +pub const VEOF: usize = 4; + +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ECONNABORTED: c_int = 103; +pub const ECONNREFUSED: c_int = 111; +pub const ECONNRESET: c_int = 104; +pub const EDEADLK: c_int = 35; +pub const ENOSYS: c_int = 38; +pub const ENOTCONN: c_int = 107; +pub const ETIMEDOUT: c_int = 110; +pub const O_APPEND: c_int = 1024; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_LARGEFILE: c_int = 0x8000; +pub const O_NONBLOCK: c_int = 2048; +pub const SA_NOCLDWAIT: c_int = 2; +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 4; +pub const SIGBUS: c_int = 7; +pub const SIGSTKSZ: size_t = 10240; +pub const MINSIGSTKSZ: size_t = 4096; +pub const SIG_SETMASK: c_int = 2; + +pub const O_NOCTTY: c_int = 256; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const PTRACE_SYSEMU: c_int = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 32; + +pub const EDEADLOCK: c_int = 35; +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EBADMSG: c_int = 74; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const EHWPOISON: c_int = 133; +pub const ERFKILL: c_int = 132; + +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGCHLD: c_int = 17; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const O_ASYNC: c_int = 0x2000; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETOWN: c_int = 8; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; + +pub const VTIME: usize = 5; +pub const VSWTC: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const ONLCR: crate::tcflag_t = 0o000004; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const XTABS: crate::tcflag_t = 0o014000; + +pub const CBAUD: crate::speed_t = 0o010017; +pub const CSIZE: crate::tcflag_t = 0o000060; +pub const CS6: crate::tcflag_t = 0o000020; +pub const CS7: crate::tcflag_t = 0o000040; +pub const CS8: crate::tcflag_t = 0o000060; +pub const CSTOPB: crate::tcflag_t = 0o000100; +pub const CREAD: crate::tcflag_t = 0o000200; +pub const PARENB: crate::tcflag_t = 0o000400; +pub const PARODD: crate::tcflag_t = 0o001000; +pub const HUPCL: crate::tcflag_t = 0o002000; +pub const CLOCAL: crate::tcflag_t = 0o004000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; + +pub const ISIG: crate::tcflag_t = 0o000001; +pub const ICANON: crate::tcflag_t = 0o000002; +pub const ECHOE: crate::tcflag_t = 0o000020; +pub const ECHOK: crate::tcflag_t = 0o000040; +pub const ECHONL: crate::tcflag_t = 0o000100; +pub const NOFLSH: crate::tcflag_t = 0o000200; +pub const ECHOCTL: crate::tcflag_t = 0o001000; +pub const ECHOPRT: crate::tcflag_t = 0o002000; +pub const ECHOKE: crate::tcflag_t = 0o004000; +pub const PENDIN: crate::tcflag_t = 0o040000; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const IXON: crate::tcflag_t = 0o002000; +pub const IXOFF: crate::tcflag_t = 0o010000; + +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_restart_syscall: c_long = 7; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_umount: c_long = 22; +pub const SYS_ptrace: c_long = 26; +pub const SYS_alarm: c_long = 27; +pub const SYS_pause: c_long = 29; +pub const SYS_utime: c_long = 30; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_signal: c_long = 48; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_readdir: c_long = 89; +pub const SYS_mmap: c_long = 90; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_socketcall: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_lookup_dcookie: c_long = 110; +pub const SYS_vhangup: c_long = 111; +pub const SYS_idle: c_long = 112; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_ipc: c_long = 117; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 127; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 130; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_afs_syscall: c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_getdents: c_long = 141; +pub const SYS_select: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 167; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_getpmsg: c_long = 188; +pub const SYS_putpmsg: c_long = 189; +pub const SYS_vfork: c_long = 190; +pub const SYS_getrlimit: c_long = 191; +pub const SYS_lchown: c_long = 198; +pub const SYS_getuid: c_long = 199; +pub const SYS_getgid: c_long = 200; +pub const SYS_geteuid: c_long = 201; +pub const SYS_getegid: c_long = 202; +pub const SYS_setreuid: c_long = 203; +pub const SYS_setregid: c_long = 204; +pub const SYS_getgroups: c_long = 205; +pub const SYS_setgroups: c_long = 206; +pub const SYS_fchown: c_long = 207; +pub const SYS_setresuid: c_long = 208; +pub const SYS_getresuid: c_long = 209; +pub const SYS_setresgid: c_long = 210; +pub const SYS_getresgid: c_long = 211; +pub const SYS_chown: c_long = 212; +pub const SYS_setuid: c_long = 213; +pub const SYS_setgid: c_long = 214; +pub const SYS_setfsuid: c_long = 215; +pub const SYS_setfsgid: c_long = 216; +pub const SYS_pivot_root: c_long = 217; +pub const SYS_mincore: c_long = 218; +pub const SYS_madvise: c_long = 219; +pub const SYS_getdents64: c_long = 220; +pub const SYS_readahead: c_long = 222; +pub const SYS_setxattr: c_long = 224; +pub const SYS_lsetxattr: c_long = 225; +pub const SYS_fsetxattr: c_long = 226; +pub const SYS_getxattr: c_long = 227; +pub const SYS_lgetxattr: c_long = 228; +pub const SYS_fgetxattr: c_long = 229; +pub const SYS_listxattr: c_long = 230; +pub const SYS_llistxattr: c_long = 231; +pub const SYS_flistxattr: c_long = 232; +pub const SYS_removexattr: c_long = 233; +pub const SYS_lremovexattr: c_long = 234; +pub const SYS_fremovexattr: c_long = 235; +pub const SYS_gettid: c_long = 236; +pub const SYS_tkill: c_long = 237; +pub const SYS_futex: c_long = 238; +pub const SYS_sched_setaffinity: c_long = 239; +pub const SYS_sched_getaffinity: c_long = 240; +pub const SYS_tgkill: c_long = 241; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_epoll_create: c_long = 249; +pub const SYS_epoll_ctl: c_long = 250; +pub const SYS_epoll_wait: c_long = 251; +pub const SYS_set_tid_address: c_long = 252; +pub const SYS_fadvise64: c_long = 253; +pub const SYS_timer_create: c_long = 254; +pub const SYS_timer_settime: c_long = 255; +pub const SYS_timer_gettime: c_long = 256; +pub const SYS_timer_getoverrun: c_long = 257; +pub const SYS_timer_delete: c_long = 258; +pub const SYS_clock_settime: c_long = 259; +pub const SYS_clock_gettime: c_long = 260; +pub const SYS_clock_getres: c_long = 261; +pub const SYS_clock_nanosleep: c_long = 262; +pub const SYS_statfs64: c_long = 265; +pub const SYS_fstatfs64: c_long = 266; +pub const SYS_remap_file_pages: c_long = 267; +pub const SYS_mbind: c_long = 268; +pub const SYS_get_mempolicy: c_long = 269; +pub const SYS_set_mempolicy: c_long = 270; +pub const SYS_mq_open: c_long = 271; +pub const SYS_mq_unlink: c_long = 272; +pub const SYS_mq_timedsend: c_long = 273; +pub const SYS_mq_timedreceive: c_long = 274; +pub const SYS_mq_notify: c_long = 275; +pub const SYS_mq_getsetattr: c_long = 276; +pub const SYS_kexec_load: c_long = 277; +pub const SYS_add_key: c_long = 278; +pub const SYS_request_key: c_long = 279; +pub const SYS_keyctl: c_long = 280; +pub const SYS_waitid: c_long = 281; +pub const SYS_ioprio_set: c_long = 282; +pub const SYS_ioprio_get: c_long = 283; +pub const SYS_inotify_init: c_long = 284; +pub const SYS_inotify_add_watch: c_long = 285; +pub const SYS_inotify_rm_watch: c_long = 286; +pub const SYS_migrate_pages: c_long = 287; +pub const SYS_openat: c_long = 288; +pub const SYS_mkdirat: c_long = 289; +pub const SYS_mknodat: c_long = 290; +pub const SYS_fchownat: c_long = 291; +pub const SYS_futimesat: c_long = 292; +pub const SYS_newfstatat: c_long = 293; +pub const SYS_unlinkat: c_long = 294; +pub const SYS_renameat: c_long = 295; +pub const SYS_linkat: c_long = 296; +pub const SYS_symlinkat: c_long = 297; +pub const SYS_readlinkat: c_long = 298; +pub const SYS_fchmodat: c_long = 299; +pub const SYS_faccessat: c_long = 300; +pub const SYS_pselect6: c_long = 301; +pub const SYS_ppoll: c_long = 302; +pub const SYS_unshare: c_long = 303; +pub const SYS_set_robust_list: c_long = 304; +pub const SYS_get_robust_list: c_long = 305; +pub const SYS_splice: c_long = 306; +pub const SYS_sync_file_range: c_long = 307; +pub const SYS_tee: c_long = 308; +pub const SYS_vmsplice: c_long = 309; +pub const SYS_move_pages: c_long = 310; +pub const SYS_getcpu: c_long = 311; +pub const SYS_epoll_pwait: c_long = 312; +pub const SYS_utimes: c_long = 313; +pub const SYS_fallocate: c_long = 314; +pub const SYS_utimensat: c_long = 315; +pub const SYS_signalfd: c_long = 316; +pub const SYS_timerfd: c_long = 317; +pub const SYS_eventfd: c_long = 318; +pub const SYS_timerfd_create: c_long = 319; +pub const SYS_timerfd_settime: c_long = 320; +pub const SYS_timerfd_gettime: c_long = 321; +pub const SYS_signalfd4: c_long = 322; +pub const SYS_eventfd2: c_long = 323; +pub const SYS_inotify_init1: c_long = 324; +pub const SYS_pipe2: c_long = 325; +pub const SYS_dup3: c_long = 326; +pub const SYS_epoll_create1: c_long = 327; +pub const SYS_preadv: c_long = 328; +pub const SYS_pwritev: c_long = 329; +pub const SYS_rt_tgsigqueueinfo: c_long = 330; +pub const SYS_perf_event_open: c_long = 331; +pub const SYS_fanotify_init: c_long = 332; +pub const SYS_fanotify_mark: c_long = 333; +pub const SYS_prlimit64: c_long = 334; +pub const SYS_name_to_handle_at: c_long = 335; +pub const SYS_open_by_handle_at: c_long = 336; +pub const SYS_clock_adjtime: c_long = 337; +pub const SYS_syncfs: c_long = 338; +pub const SYS_setns: c_long = 339; +pub const SYS_process_vm_readv: c_long = 340; +pub const SYS_process_vm_writev: c_long = 341; +pub const SYS_s390_runtime_instr: c_long = 342; +pub const SYS_kcmp: c_long = 343; +pub const SYS_finit_module: c_long = 344; +pub const SYS_sched_setattr: c_long = 345; +pub const SYS_sched_getattr: c_long = 346; +pub const SYS_renameat2: c_long = 347; +pub const SYS_seccomp: c_long = 348; +pub const SYS_getrandom: c_long = 349; +pub const SYS_memfd_create: c_long = 350; +pub const SYS_bpf: c_long = 351; +pub const SYS_s390_pci_mmio_write: c_long = 352; +pub const SYS_s390_pci_mmio_read: c_long = 353; +pub const SYS_execveat: c_long = 354; +pub const SYS_userfaultfd: c_long = 355; +pub const SYS_membarrier: c_long = 356; +pub const SYS_recvmmsg: c_long = 357; +pub const SYS_sendmmsg: c_long = 358; +pub const SYS_socket: c_long = 359; +pub const SYS_socketpair: c_long = 360; +pub const SYS_bind: c_long = 361; +pub const SYS_connect: c_long = 362; +pub const SYS_listen: c_long = 363; +pub const SYS_accept4: c_long = 364; +pub const SYS_getsockopt: c_long = 365; +pub const SYS_setsockopt: c_long = 366; +pub const SYS_getsockname: c_long = 367; +pub const SYS_getpeername: c_long = 368; +pub const SYS_sendto: c_long = 369; +pub const SYS_sendmsg: c_long = 370; +pub const SYS_recvfrom: c_long = 371; +pub const SYS_recvmsg: c_long = 372; +pub const SYS_shutdown: c_long = 373; +pub const SYS_mlock2: c_long = 374; +pub const SYS_copy_file_range: c_long = 375; +pub const SYS_preadv2: c_long = 376; +pub const SYS_pwritev2: c_long = 377; +pub const SYS_s390_guarded_storage: c_long = 378; +pub const SYS_statx: c_long = 379; +pub const SYS_s390_sthyi: c_long = 380; +pub const SYS_kexec_file_load: c_long = 381; +pub const SYS_io_pgetevents: c_long = 382; +pub const SYS_rseq: c_long = 383; +pub const SYS_pkey_mprotect: c_long = 384; +pub const SYS_pkey_alloc: c_long = 385; +pub const SYS_pkey_free: c_long = 386; +pub const SYS_semtimedop: c_long = 392; +pub const SYS_semget: c_long = 393; +pub const SYS_semctl: c_long = 394; +pub const SYS_shmget: c_long = 395; +pub const SYS_shmctl: c_long = 396; +pub const SYS_shmat: c_long = 397; +pub const SYS_shmdt: c_long = 398; +pub const SYS_msgget: c_long = 399; +pub const SYS_msgsnd: c_long = 400; +pub const SYS_msgrcv: c_long = 401; +pub const SYS_msgctl: c_long = 402; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_cachestat: c_long = 451; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_mseal: c_long = 462; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/mod.rs new file mode 100644 index 00000000000000..1a4d89632dcc98 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/mod.rs @@ -0,0 +1,666 @@ +//! Wasm32 definitions conforming to the WALI ABI. +//! The WALI ABI closely mirrors `x86_64` Linux and is thus implemented within the `b64` module as opposed to `b32` +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = c_long; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } +} + +// Syscall table +pub const SYS_read: c_long = 0; +pub const SYS_write: c_long = 1; +pub const SYS_open: c_long = 2; +pub const SYS_close: c_long = 3; +pub const SYS_stat: c_long = 4; +pub const SYS_fstat: c_long = 5; +pub const SYS_lstat: c_long = 6; +pub const SYS_poll: c_long = 7; +pub const SYS_lseek: c_long = 8; +pub const SYS_mmap: c_long = 9; +pub const SYS_mprotect: c_long = 10; +pub const SYS_munmap: c_long = 11; +pub const SYS_brk: c_long = 12; +pub const SYS_rt_sigaction: c_long = 13; +pub const SYS_rt_sigprocmask: c_long = 14; +pub const SYS_rt_sigreturn: c_long = 15; +pub const SYS_ioctl: c_long = 16; +pub const SYS_pread64: c_long = 17; +pub const SYS_pwrite64: c_long = 18; +pub const SYS_readv: c_long = 19; +pub const SYS_writev: c_long = 20; +pub const SYS_access: c_long = 21; +pub const SYS_pipe: c_long = 22; +pub const SYS_select: c_long = 23; +pub const SYS_sched_yield: c_long = 24; +pub const SYS_mremap: c_long = 25; +pub const SYS_msync: c_long = 26; +pub const SYS_mincore: c_long = 27; +pub const SYS_madvise: c_long = 28; +pub const SYS_shmget: c_long = 29; +pub const SYS_shmat: c_long = 30; +pub const SYS_shmctl: c_long = 31; +pub const SYS_dup: c_long = 32; +pub const SYS_dup2: c_long = 33; +pub const SYS_pause: c_long = 34; +pub const SYS_nanosleep: c_long = 35; +pub const SYS_getitimer: c_long = 36; +pub const SYS_alarm: c_long = 37; +pub const SYS_setitimer: c_long = 38; +pub const SYS_getpid: c_long = 39; +pub const SYS_sendfile: c_long = 40; +pub const SYS_socket: c_long = 41; +pub const SYS_connect: c_long = 42; +pub const SYS_accept: c_long = 43; +pub const SYS_sendto: c_long = 44; +pub const SYS_recvfrom: c_long = 45; +pub const SYS_sendmsg: c_long = 46; +pub const SYS_recvmsg: c_long = 47; +pub const SYS_shutdown: c_long = 48; +pub const SYS_bind: c_long = 49; +pub const SYS_listen: c_long = 50; +pub const SYS_getsockname: c_long = 51; +pub const SYS_getpeername: c_long = 52; +pub const SYS_socketpair: c_long = 53; +pub const SYS_setsockopt: c_long = 54; +pub const SYS_getsockopt: c_long = 55; +pub const SYS_clone: c_long = 56; +pub const SYS_fork: c_long = 57; +pub const SYS_vfork: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_exit: c_long = 60; +pub const SYS_wait4: c_long = 61; +pub const SYS_kill: c_long = 62; +pub const SYS_uname: c_long = 63; +pub const SYS_semget: c_long = 64; +pub const SYS_semop: c_long = 65; +pub const SYS_semctl: c_long = 66; +pub const SYS_shmdt: c_long = 67; +pub const SYS_msgget: c_long = 68; +pub const SYS_msgsnd: c_long = 69; +pub const SYS_msgrcv: c_long = 70; +pub const SYS_msgctl: c_long = 71; +pub const SYS_fcntl: c_long = 72; +pub const SYS_flock: c_long = 73; +pub const SYS_fsync: c_long = 74; +pub const SYS_fdatasync: c_long = 75; +pub const SYS_truncate: c_long = 76; +pub const SYS_ftruncate: c_long = 77; +pub const SYS_getdents: c_long = 78; +pub const SYS_getcwd: c_long = 79; +pub const SYS_chdir: c_long = 80; +pub const SYS_fchdir: c_long = 81; +pub const SYS_rename: c_long = 82; +pub const SYS_mkdir: c_long = 83; +pub const SYS_rmdir: c_long = 84; +pub const SYS_creat: c_long = 85; +pub const SYS_link: c_long = 86; +pub const SYS_unlink: c_long = 87; +pub const SYS_symlink: c_long = 88; +pub const SYS_readlink: c_long = 89; +pub const SYS_chmod: c_long = 90; +pub const SYS_fchmod: c_long = 91; +pub const SYS_chown: c_long = 92; +pub const SYS_fchown: c_long = 93; +pub const SYS_lchown: c_long = 94; +pub const SYS_umask: c_long = 95; +pub const SYS_gettimeofday: c_long = 96; +pub const SYS_getrlimit: c_long = 97; +pub const SYS_getrusage: c_long = 98; +pub const SYS_sysinfo: c_long = 99; +pub const SYS_times: c_long = 100; +pub const SYS_ptrace: c_long = 101; +pub const SYS_getuid: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_getgid: c_long = 104; +pub const SYS_setuid: c_long = 105; +pub const SYS_setgid: c_long = 106; +pub const SYS_geteuid: c_long = 107; +pub const SYS_getegid: c_long = 108; +pub const SYS_setpgid: c_long = 109; +pub const SYS_getppid: c_long = 110; +pub const SYS_getpgrp: c_long = 111; +pub const SYS_setsid: c_long = 112; +pub const SYS_setreuid: c_long = 113; +pub const SYS_setregid: c_long = 114; +pub const SYS_getgroups: c_long = 115; +pub const SYS_setgroups: c_long = 116; +pub const SYS_setresuid: c_long = 117; +pub const SYS_getresuid: c_long = 118; +pub const SYS_setresgid: c_long = 119; +pub const SYS_getresgid: c_long = 120; +pub const SYS_getpgid: c_long = 121; +pub const SYS_setfsuid: c_long = 122; +pub const SYS_setfsgid: c_long = 123; +pub const SYS_getsid: c_long = 124; +pub const SYS_capget: c_long = 125; +pub const SYS_capset: c_long = 126; +pub const SYS_rt_sigpending: c_long = 127; +pub const SYS_rt_sigtimedwait: c_long = 128; +pub const SYS_rt_sigqueueinfo: c_long = 129; +pub const SYS_rt_sigsuspend: c_long = 130; +pub const SYS_sigaltstack: c_long = 131; +pub const SYS_utime: c_long = 132; +pub const SYS_mknod: c_long = 133; +pub const SYS_uselib: c_long = 134; +pub const SYS_personality: c_long = 135; +pub const SYS_ustat: c_long = 136; +pub const SYS_statfs: c_long = 137; +pub const SYS_fstatfs: c_long = 138; +pub const SYS_sysfs: c_long = 139; +pub const SYS_getpriority: c_long = 140; +pub const SYS_setpriority: c_long = 141; +pub const SYS_sched_setparam: c_long = 142; +pub const SYS_sched_getparam: c_long = 143; +pub const SYS_sched_setscheduler: c_long = 144; +pub const SYS_sched_getscheduler: c_long = 145; +pub const SYS_sched_get_priority_max: c_long = 146; +pub const SYS_sched_get_priority_min: c_long = 147; +pub const SYS_sched_rr_get_interval: c_long = 148; +pub const SYS_mlock: c_long = 149; +pub const SYS_munlock: c_long = 150; +pub const SYS_mlockall: c_long = 151; +pub const SYS_munlockall: c_long = 152; +pub const SYS_vhangup: c_long = 153; +pub const SYS_modify_ldt: c_long = 154; +pub const SYS_pivot_root: c_long = 155; +pub const SYS__sysctl: c_long = 156; +pub const SYS_prctl: c_long = 157; +pub const SYS_arch_prctl: c_long = 158; +pub const SYS_adjtimex: c_long = 159; +pub const SYS_setrlimit: c_long = 160; +pub const SYS_chroot: c_long = 161; +pub const SYS_sync: c_long = 162; +pub const SYS_acct: c_long = 163; +pub const SYS_settimeofday: c_long = 164; +pub const SYS_mount: c_long = 165; +pub const SYS_umount2: c_long = 166; +pub const SYS_swapon: c_long = 167; +pub const SYS_swapoff: c_long = 168; +pub const SYS_reboot: c_long = 169; +pub const SYS_sethostname: c_long = 170; +pub const SYS_setdomainname: c_long = 171; +pub const SYS_iopl: c_long = 172; +pub const SYS_ioperm: c_long = 173; +pub const SYS_create_module: c_long = 174; +pub const SYS_init_module: c_long = 175; +pub const SYS_delete_module: c_long = 176; +pub const SYS_get_kernel_syms: c_long = 177; +pub const SYS_query_module: c_long = 178; +pub const SYS_quotactl: c_long = 179; +pub const SYS_nfsservctl: c_long = 180; +pub const SYS_getpmsg: c_long = 181; +pub const SYS_putpmsg: c_long = 182; +pub const SYS_afs_syscall: c_long = 183; +pub const SYS_tuxcall: c_long = 184; +pub const SYS_security: c_long = 185; +pub const SYS_gettid: c_long = 186; +pub const SYS_readahead: c_long = 187; +pub const SYS_setxattr: c_long = 188; +pub const SYS_lsetxattr: c_long = 189; +pub const SYS_fsetxattr: c_long = 190; +pub const SYS_getxattr: c_long = 191; +pub const SYS_lgetxattr: c_long = 192; +pub const SYS_fgetxattr: c_long = 193; +pub const SYS_listxattr: c_long = 194; +pub const SYS_llistxattr: c_long = 195; +pub const SYS_flistxattr: c_long = 196; +pub const SYS_removexattr: c_long = 197; +pub const SYS_lremovexattr: c_long = 198; +pub const SYS_fremovexattr: c_long = 199; +pub const SYS_tkill: c_long = 200; +pub const SYS_time: c_long = 201; +pub const SYS_futex: c_long = 202; +pub const SYS_sched_setaffinity: c_long = 203; +pub const SYS_sched_getaffinity: c_long = 204; +pub const SYS_set_thread_area: c_long = 205; +pub const SYS_io_setup: c_long = 206; +pub const SYS_io_destroy: c_long = 207; +pub const SYS_io_getevents: c_long = 208; +pub const SYS_io_submit: c_long = 209; +pub const SYS_io_cancel: c_long = 210; +pub const SYS_get_thread_area: c_long = 211; +pub const SYS_lookup_dcookie: c_long = 212; +pub const SYS_epoll_create: c_long = 213; +pub const SYS_epoll_ctl_old: c_long = 214; +pub const SYS_epoll_wait_old: c_long = 215; +pub const SYS_remap_file_pages: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_set_tid_address: c_long = 218; +pub const SYS_restart_syscall: c_long = 219; +pub const SYS_semtimedop: c_long = 220; +pub const SYS_fadvise64: c_long = 221; +pub const SYS_timer_create: c_long = 222; +pub const SYS_timer_settime: c_long = 223; +pub const SYS_timer_gettime: c_long = 224; +pub const SYS_timer_getoverrun: c_long = 225; +pub const SYS_timer_delete: c_long = 226; +pub const SYS_clock_settime: c_long = 227; +pub const SYS_clock_gettime: c_long = 228; +pub const SYS_clock_getres: c_long = 229; +pub const SYS_clock_nanosleep: c_long = 230; +pub const SYS_exit_group: c_long = 231; +pub const SYS_epoll_wait: c_long = 232; +pub const SYS_epoll_ctl: c_long = 233; +pub const SYS_tgkill: c_long = 234; +pub const SYS_utimes: c_long = 235; +pub const SYS_vserver: c_long = 236; +pub const SYS_mbind: c_long = 237; +pub const SYS_set_mempolicy: c_long = 238; +pub const SYS_get_mempolicy: c_long = 239; +pub const SYS_mq_open: c_long = 240; +pub const SYS_mq_unlink: c_long = 241; +pub const SYS_mq_timedsend: c_long = 242; +pub const SYS_mq_timedreceive: c_long = 243; +pub const SYS_mq_notify: c_long = 244; +pub const SYS_mq_getsetattr: c_long = 245; +pub const SYS_kexec_load: c_long = 246; +pub const SYS_waitid: c_long = 247; +pub const SYS_add_key: c_long = 248; +pub const SYS_request_key: c_long = 249; +pub const SYS_keyctl: c_long = 250; +pub const SYS_ioprio_set: c_long = 251; +pub const SYS_ioprio_get: c_long = 252; +pub const SYS_inotify_init: c_long = 253; +pub const SYS_inotify_add_watch: c_long = 254; +pub const SYS_inotify_rm_watch: c_long = 255; +pub const SYS_migrate_pages: c_long = 256; +pub const SYS_openat: c_long = 257; +pub const SYS_mkdirat: c_long = 258; +pub const SYS_mknodat: c_long = 259; +pub const SYS_fchownat: c_long = 260; +pub const SYS_futimesat: c_long = 261; +pub const SYS_newfstatat: c_long = 262; +pub const SYS_unlinkat: c_long = 263; +pub const SYS_renameat: c_long = 264; +pub const SYS_linkat: c_long = 265; +pub const SYS_symlinkat: c_long = 266; +pub const SYS_readlinkat: c_long = 267; +pub const SYS_fchmodat: c_long = 268; +pub const SYS_faccessat: c_long = 269; +pub const SYS_pselect6: c_long = 270; +pub const SYS_ppoll: c_long = 271; +pub const SYS_unshare: c_long = 272; +pub const SYS_set_robust_list: c_long = 273; +pub const SYS_get_robust_list: c_long = 274; +pub const SYS_splice: c_long = 275; +pub const SYS_tee: c_long = 276; +pub const SYS_sync_file_range: c_long = 277; +pub const SYS_vmsplice: c_long = 278; +pub const SYS_move_pages: c_long = 279; +pub const SYS_utimensat: c_long = 280; +pub const SYS_epoll_pwait: c_long = 281; +pub const SYS_signalfd: c_long = 282; +pub const SYS_timerfd_create: c_long = 283; +pub const SYS_eventfd: c_long = 284; +pub const SYS_fallocate: c_long = 285; +pub const SYS_timerfd_settime: c_long = 286; +pub const SYS_timerfd_gettime: c_long = 287; +pub const SYS_accept4: c_long = 288; +pub const SYS_signalfd4: c_long = 289; +pub const SYS_eventfd2: c_long = 290; +pub const SYS_epoll_create1: c_long = 291; +pub const SYS_dup3: c_long = 292; +pub const SYS_pipe2: c_long = 293; +pub const SYS_inotify_init1: c_long = 294; +pub const SYS_preadv: c_long = 295; +pub const SYS_pwritev: c_long = 296; +pub const SYS_rt_tgsigqueueinfo: c_long = 297; +pub const SYS_perf_event_open: c_long = 298; +pub const SYS_recvmmsg: c_long = 299; +pub const SYS_fanotify_init: c_long = 300; +pub const SYS_fanotify_mark: c_long = 301; +pub const SYS_prlimit64: c_long = 302; +pub const SYS_name_to_handle_at: c_long = 303; +pub const SYS_open_by_handle_at: c_long = 304; +pub const SYS_clock_adjtime: c_long = 305; +pub const SYS_syncfs: c_long = 306; +pub const SYS_sendmmsg: c_long = 307; +pub const SYS_setns: c_long = 308; +pub const SYS_getcpu: c_long = 309; +pub const SYS_process_vm_readv: c_long = 310; +pub const SYS_process_vm_writev: c_long = 311; +pub const SYS_kcmp: c_long = 312; +pub const SYS_finit_module: c_long = 313; +pub const SYS_sched_setattr: c_long = 314; +pub const SYS_sched_getattr: c_long = 315; +pub const SYS_renameat2: c_long = 316; +pub const SYS_seccomp: c_long = 317; +pub const SYS_getrandom: c_long = 318; +pub const SYS_memfd_create: c_long = 319; +pub const SYS_kexec_file_load: c_long = 320; +pub const SYS_bpf: c_long = 321; +pub const SYS_execveat: c_long = 322; +pub const SYS_userfaultfd: c_long = 323; +pub const SYS_membarrier: c_long = 324; +pub const SYS_mlock2: c_long = 325; +pub const SYS_copy_file_range: c_long = 326; +pub const SYS_preadv2: c_long = 327; +pub const SYS_pwritev2: c_long = 328; +pub const SYS_pkey_mprotect: c_long = 329; +pub const SYS_pkey_alloc: c_long = 330; +pub const SYS_pkey_free: c_long = 331; +pub const SYS_statx: c_long = 332; +pub const SYS_io_pgetevents: c_long = 333; +pub const SYS_rseq: c_long = 334; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; + +// Syscall aliases for WALI +pub const SYS_fadvise: c_long = SYS_fadvise64; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_LARGEFILE: c_int = 0; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0x2000; + +pub const PTRACE_SYSEMU: c_int = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 32; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = EDEADLK; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; + +cfg_if! { + if #[cfg(all(target_family = "wasm", target_env = "musl"))] { + mod wali; + pub use self::wali::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/wali.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/wali.rs new file mode 100644 index 00000000000000..f347e8a69ddd02 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/wasm32/wali.rs @@ -0,0 +1,441 @@ +//! WebAssembly Linux Interface syscall specification + +use crate::prelude::*; + +// --- Autogenerated from WALI/scripts/autogen.py --- +#[link(wasm_import_module = "wali")] +extern "C" { + /* 0 */ + #[link_name = "SYS_read"] + pub fn __syscall_SYS_read(a1: i32, a2: i32, a3: u32) -> c_long; + /* 1 */ + #[link_name = "SYS_write"] + pub fn __syscall_SYS_write(a1: i32, a2: i32, a3: u32) -> c_long; + /* 2 */ + #[link_name = "SYS_open"] + pub fn __syscall_SYS_open(a1: i32, a2: i32, a3: i32) -> c_long; + /* 3 */ + #[link_name = "SYS_close"] + pub fn __syscall_SYS_close(a1: i32) -> c_long; + /* 4 */ + #[link_name = "SYS_stat"] + pub fn __syscall_SYS_stat(a1: i32, a2: i32) -> c_long; + /* 5 */ + #[link_name = "SYS_fstat"] + pub fn __syscall_SYS_fstat(a1: i32, a2: i32) -> c_long; + /* 6 */ + #[link_name = "SYS_lstat"] + pub fn __syscall_SYS_lstat(a1: i32, a2: i32) -> c_long; + /* 7 */ + #[link_name = "SYS_poll"] + pub fn __syscall_SYS_poll(a1: i32, a2: u32, a3: i32) -> c_long; + /* 8 */ + #[link_name = "SYS_lseek"] + pub fn __syscall_SYS_lseek(a1: i32, a2: i64, a3: i32) -> c_long; + /* 9 */ + #[link_name = "SYS_mmap"] + pub fn __syscall_SYS_mmap(a1: i32, a2: u32, a3: i32, a4: i32, a5: i32, a6: i64) -> c_long; + /* 10 */ + #[link_name = "SYS_mprotect"] + pub fn __syscall_SYS_mprotect(a1: i32, a2: u32, a3: i32) -> c_long; + /* 11 */ + #[link_name = "SYS_munmap"] + pub fn __syscall_SYS_munmap(a1: i32, a2: u32) -> c_long; + /* 12 */ + #[link_name = "SYS_brk"] + pub fn __syscall_SYS_brk(a1: i32) -> c_long; + /* 13 */ + #[link_name = "SYS_rt_sigaction"] + pub fn __syscall_SYS_rt_sigaction(a1: i32, a2: i32, a3: i32, a4: u32) -> c_long; + /* 14 */ + #[link_name = "SYS_rt_sigprocmask"] + pub fn __syscall_SYS_rt_sigprocmask(a1: i32, a2: i32, a3: i32, a4: u32) -> c_long; + /* 15 */ + #[link_name = "SYS_rt_sigreturn"] + pub fn __syscall_SYS_rt_sigreturn(a1: i64) -> c_long; + /* 16 */ + #[link_name = "SYS_ioctl"] + pub fn __syscall_SYS_ioctl(a1: i32, a2: i32, a3: i32) -> c_long; + /* 17 */ + #[link_name = "SYS_pread64"] + pub fn __syscall_SYS_pread64(a1: i32, a2: i32, a3: u32, a4: i64) -> c_long; + /* 18 */ + #[link_name = "SYS_pwrite64"] + pub fn __syscall_SYS_pwrite64(a1: i32, a2: i32, a3: u32, a4: i64) -> c_long; + /* 19 */ + #[link_name = "SYS_readv"] + pub fn __syscall_SYS_readv(a1: i32, a2: i32, a3: i32) -> c_long; + /* 20 */ + #[link_name = "SYS_writev"] + pub fn __syscall_SYS_writev(a1: i32, a2: i32, a3: i32) -> c_long; + /* 21 */ + #[link_name = "SYS_access"] + pub fn __syscall_SYS_access(a1: i32, a2: i32) -> c_long; + /* 22 */ + #[link_name = "SYS_pipe"] + pub fn __syscall_SYS_pipe(a1: i32) -> c_long; + /* 23 */ + #[link_name = "SYS_select"] + pub fn __syscall_SYS_select(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 24 */ + #[link_name = "SYS_sched_yield"] + pub fn __syscall_SYS_sched_yield() -> c_long; + /* 25 */ + #[link_name = "SYS_mremap"] + pub fn __syscall_SYS_mremap(a1: i32, a2: u32, a3: u32, a4: i32, a5: i32) -> c_long; + /* 26 */ + #[link_name = "SYS_msync"] + pub fn __syscall_SYS_msync(a1: i32, a2: u32, a3: i32) -> c_long; + /* 28 */ + #[link_name = "SYS_madvise"] + pub fn __syscall_SYS_madvise(a1: i32, a2: u32, a3: i32) -> c_long; + /* 32 */ + #[link_name = "SYS_dup"] + pub fn __syscall_SYS_dup(a1: i32) -> c_long; + /* 33 */ + #[link_name = "SYS_dup2"] + pub fn __syscall_SYS_dup2(a1: i32, a2: i32) -> c_long; + /* 35 */ + #[link_name = "SYS_nanosleep"] + pub fn __syscall_SYS_nanosleep(a1: i32, a2: i32) -> c_long; + /* 37 */ + #[link_name = "SYS_alarm"] + pub fn __syscall_SYS_alarm(a1: i32) -> c_long; + /* 38 */ + #[link_name = "SYS_setitimer"] + pub fn __syscall_SYS_setitimer(a1: i32, a2: i32, a3: i32) -> c_long; + /* 39 */ + #[link_name = "SYS_getpid"] + pub fn __syscall_SYS_getpid() -> c_long; + /* 41 */ + #[link_name = "SYS_socket"] + pub fn __syscall_SYS_socket(a1: i32, a2: i32, a3: i32) -> c_long; + /* 42 */ + #[link_name = "SYS_connect"] + pub fn __syscall_SYS_connect(a1: i32, a2: i32, a3: u32) -> c_long; + /* 43 */ + #[link_name = "SYS_accept"] + pub fn __syscall_SYS_accept(a1: i32, a2: i32, a3: i32) -> c_long; + /* 44 */ + #[link_name = "SYS_sendto"] + pub fn __syscall_SYS_sendto(a1: i32, a2: i32, a3: u32, a4: i32, a5: i32, a6: u32) -> c_long; + /* 45 */ + #[link_name = "SYS_recvfrom"] + pub fn __syscall_SYS_recvfrom(a1: i32, a2: i32, a3: u32, a4: i32, a5: i32, a6: i32) -> c_long; + /* 46 */ + #[link_name = "SYS_sendmsg"] + pub fn __syscall_SYS_sendmsg(a1: i32, a2: i32, a3: i32) -> c_long; + /* 47 */ + #[link_name = "SYS_recvmsg"] + pub fn __syscall_SYS_recvmsg(a1: i32, a2: i32, a3: i32) -> c_long; + /* 48 */ + #[link_name = "SYS_shutdown"] + pub fn __syscall_SYS_shutdown(a1: i32, a2: i32) -> c_long; + /* 49 */ + #[link_name = "SYS_bind"] + pub fn __syscall_SYS_bind(a1: i32, a2: i32, a3: u32) -> c_long; + /* 50 */ + #[link_name = "SYS_listen"] + pub fn __syscall_SYS_listen(a1: i32, a2: i32) -> c_long; + /* 51 */ + #[link_name = "SYS_getsockname"] + pub fn __syscall_SYS_getsockname(a1: i32, a2: i32, a3: i32) -> c_long; + /* 52 */ + #[link_name = "SYS_getpeername"] + pub fn __syscall_SYS_getpeername(a1: i32, a2: i32, a3: i32) -> c_long; + /* 53 */ + #[link_name = "SYS_socketpair"] + pub fn __syscall_SYS_socketpair(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 54 */ + #[link_name = "SYS_setsockopt"] + pub fn __syscall_SYS_setsockopt(a1: i32, a2: i32, a3: i32, a4: i32, a5: u32) -> c_long; + /* 55 */ + #[link_name = "SYS_getsockopt"] + pub fn __syscall_SYS_getsockopt(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 57 */ + #[link_name = "SYS_fork"] + pub fn __syscall_SYS_fork() -> c_long; + /* 59 */ + #[link_name = "SYS_execve"] + pub fn __syscall_SYS_execve(a1: i32, a2: i32, a3: i32) -> c_long; + /* 60 */ + #[link_name = "SYS_exit"] + pub fn __syscall_SYS_exit(a1: i32) -> c_long; + /* 61 */ + #[link_name = "SYS_wait4"] + pub fn __syscall_SYS_wait4(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 62 */ + #[link_name = "SYS_kill"] + pub fn __syscall_SYS_kill(a1: i32, a2: i32) -> c_long; + /* 63 */ + #[link_name = "SYS_uname"] + pub fn __syscall_SYS_uname(a1: i32) -> c_long; + /* 72 */ + #[link_name = "SYS_fcntl"] + pub fn __syscall_SYS_fcntl(a1: i32, a2: i32, a3: i32) -> c_long; + /* 73 */ + #[link_name = "SYS_flock"] + pub fn __syscall_SYS_flock(a1: i32, a2: i32) -> c_long; + /* 74 */ + #[link_name = "SYS_fsync"] + pub fn __syscall_SYS_fsync(a1: i32) -> c_long; + /* 75 */ + #[link_name = "SYS_fdatasync"] + pub fn __syscall_SYS_fdatasync(a1: i32) -> c_long; + /* 77 */ + #[link_name = "SYS_ftruncate"] + pub fn __syscall_SYS_ftruncate(a1: i32, a2: i64) -> c_long; + /* 78 */ + #[link_name = "SYS_getdents"] + pub fn __syscall_SYS_getdents(a1: i32, a2: i32, a3: i32) -> c_long; + /* 79 */ + #[link_name = "SYS_getcwd"] + pub fn __syscall_SYS_getcwd(a1: i32, a2: u32) -> c_long; + /* 80 */ + #[link_name = "SYS_chdir"] + pub fn __syscall_SYS_chdir(a1: i32) -> c_long; + /* 81 */ + #[link_name = "SYS_fchdir"] + pub fn __syscall_SYS_fchdir(a1: i32) -> c_long; + /* 82 */ + #[link_name = "SYS_rename"] + pub fn __syscall_SYS_rename(a1: i32, a2: i32) -> c_long; + /* 83 */ + #[link_name = "SYS_mkdir"] + pub fn __syscall_SYS_mkdir(a1: i32, a2: i32) -> c_long; + /* 84 */ + #[link_name = "SYS_rmdir"] + pub fn __syscall_SYS_rmdir(a1: i32) -> c_long; + /* 86 */ + #[link_name = "SYS_link"] + pub fn __syscall_SYS_link(a1: i32, a2: i32) -> c_long; + /* 87 */ + #[link_name = "SYS_unlink"] + pub fn __syscall_SYS_unlink(a1: i32) -> c_long; + /* 88 */ + #[link_name = "SYS_symlink"] + pub fn __syscall_SYS_symlink(a1: i32, a2: i32) -> c_long; + /* 89 */ + #[link_name = "SYS_readlink"] + pub fn __syscall_SYS_readlink(a1: i32, a2: i32, a3: u32) -> c_long; + /* 90 */ + #[link_name = "SYS_chmod"] + pub fn __syscall_SYS_chmod(a1: i32, a2: i32) -> c_long; + /* 91 */ + #[link_name = "SYS_fchmod"] + pub fn __syscall_SYS_fchmod(a1: i32, a2: i32) -> c_long; + /* 92 */ + #[link_name = "SYS_chown"] + pub fn __syscall_SYS_chown(a1: i32, a2: i32, a3: i32) -> c_long; + /* 93 */ + #[link_name = "SYS_fchown"] + pub fn __syscall_SYS_fchown(a1: i32, a2: i32, a3: i32) -> c_long; + /* 95 */ + #[link_name = "SYS_umask"] + pub fn __syscall_SYS_umask(a1: i32) -> c_long; + /* 97 */ + #[link_name = "SYS_getrlimit"] + pub fn __syscall_SYS_getrlimit(a1: i32, a2: i32) -> c_long; + /* 98 */ + #[link_name = "SYS_getrusage"] + pub fn __syscall_SYS_getrusage(a1: i32, a2: i32) -> c_long; + /* 99 */ + #[link_name = "SYS_sysinfo"] + pub fn __syscall_SYS_sysinfo(a1: i32) -> c_long; + /* 102 */ + #[link_name = "SYS_getuid"] + pub fn __syscall_SYS_getuid() -> c_long; + /* 104 */ + #[link_name = "SYS_getgid"] + pub fn __syscall_SYS_getgid() -> c_long; + /* 105 */ + #[link_name = "SYS_setuid"] + pub fn __syscall_SYS_setuid(a1: i32) -> c_long; + /* 106 */ + #[link_name = "SYS_setgid"] + pub fn __syscall_SYS_setgid(a1: i32) -> c_long; + /* 107 */ + #[link_name = "SYS_geteuid"] + pub fn __syscall_SYS_geteuid() -> c_long; + /* 108 */ + #[link_name = "SYS_getegid"] + pub fn __syscall_SYS_getegid() -> c_long; + /* 109 */ + #[link_name = "SYS_setpgid"] + pub fn __syscall_SYS_setpgid(a1: i32, a2: i32) -> c_long; + /* 110 */ + #[link_name = "SYS_getppid"] + pub fn __syscall_SYS_getppid() -> c_long; + /* 112 */ + #[link_name = "SYS_setsid"] + pub fn __syscall_SYS_setsid() -> c_long; + /* 113 */ + #[link_name = "SYS_setreuid"] + pub fn __syscall_SYS_setreuid(a1: i32, a2: i32) -> c_long; + /* 114 */ + #[link_name = "SYS_setregid"] + pub fn __syscall_SYS_setregid(a1: i32, a2: i32) -> c_long; + /* 115 */ + #[link_name = "SYS_getgroups"] + pub fn __syscall_SYS_getgroups(a1: u32, a2: i32) -> c_long; + /* 116 */ + #[link_name = "SYS_setgroups"] + pub fn __syscall_SYS_setgroups(a1: u32, a2: i32) -> c_long; + /* 117 */ + #[link_name = "SYS_setresuid"] + pub fn __syscall_SYS_setresuid(a1: i32, a2: i32, a3: i32) -> c_long; + /* 119 */ + #[link_name = "SYS_setresgid"] + pub fn __syscall_SYS_setresgid(a1: i32, a2: i32, a3: i32) -> c_long; + /* 121 */ + #[link_name = "SYS_getpgid"] + pub fn __syscall_SYS_getpgid(a1: i32) -> c_long; + /* 124 */ + #[link_name = "SYS_getsid"] + pub fn __syscall_SYS_getsid(a1: i32) -> c_long; + /* 127 */ + #[link_name = "SYS_rt_sigpending"] + pub fn __syscall_SYS_rt_sigpending(a1: i32, a2: u32) -> c_long; + /* 130 */ + #[link_name = "SYS_rt_sigsuspend"] + pub fn __syscall_SYS_rt_sigsuspend(a1: i32, a2: u32) -> c_long; + /* 131 */ + #[link_name = "SYS_sigaltstack"] + pub fn __syscall_SYS_sigaltstack(a1: i32, a2: i32) -> c_long; + /* 132 */ + #[link_name = "SYS_utime"] + pub fn __syscall_SYS_utime(a1: i32, a2: i32) -> c_long; + /* 137 */ + #[link_name = "SYS_statfs"] + pub fn __syscall_SYS_statfs(a1: i32, a2: i32) -> c_long; + /* 138 */ + #[link_name = "SYS_fstatfs"] + pub fn __syscall_SYS_fstatfs(a1: i32, a2: i32) -> c_long; + /* 157 */ + #[link_name = "SYS_prctl"] + pub fn __syscall_SYS_prctl(a1: i32, a2: u64, a3: u64, a4: u64, a5: u64) -> c_long; + /* 160 */ + #[link_name = "SYS_setrlimit"] + pub fn __syscall_SYS_setrlimit(a1: i32, a2: i32) -> c_long; + /* 161 */ + #[link_name = "SYS_chroot"] + pub fn __syscall_SYS_chroot(a1: i32) -> c_long; + /* 186 */ + #[link_name = "SYS_gettid"] + pub fn __syscall_SYS_gettid() -> c_long; + /* 200 */ + #[link_name = "SYS_tkill"] + pub fn __syscall_SYS_tkill(a1: i32, a2: i32) -> c_long; + /* 202 */ + #[link_name = "SYS_futex"] + pub fn __syscall_SYS_futex(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32, a6: i32) -> c_long; + /* 204 */ + #[link_name = "SYS_sched_getaffinity"] + pub fn __syscall_SYS_sched_getaffinity(a1: i32, a2: u32, a3: i32) -> c_long; + /* 217 */ + #[link_name = "SYS_getdents64"] + pub fn __syscall_SYS_getdents64(a1: i32, a2: i32, a3: i32) -> c_long; + /* 218 */ + #[link_name = "SYS_set_tid_address"] + pub fn __syscall_SYS_set_tid_address(a1: i32) -> c_long; + /* 221 */ + #[link_name = "SYS_fadvise"] + pub fn __syscall_SYS_fadvise(a1: i32, a2: i64, a3: i64, a4: i32) -> c_long; + /* 228 */ + #[link_name = "SYS_clock_gettime"] + pub fn __syscall_SYS_clock_gettime(a1: i32, a2: i32) -> c_long; + /* 229 */ + #[link_name = "SYS_clock_getres"] + pub fn __syscall_SYS_clock_getres(a1: i32, a2: i32) -> c_long; + /* 230 */ + #[link_name = "SYS_clock_nanosleep"] + pub fn __syscall_SYS_clock_nanosleep(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 231 */ + #[link_name = "SYS_exit_group"] + pub fn __syscall_SYS_exit_group(a1: i32) -> c_long; + /* 233 */ + #[link_name = "SYS_epoll_ctl"] + pub fn __syscall_SYS_epoll_ctl(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 257 */ + #[link_name = "SYS_openat"] + pub fn __syscall_SYS_openat(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 258 */ + #[link_name = "SYS_mkdirat"] + pub fn __syscall_SYS_mkdirat(a1: i32, a2: i32, a3: i32) -> c_long; + /* 260 */ + #[link_name = "SYS_fchownat"] + pub fn __syscall_SYS_fchownat(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 262 */ + #[link_name = "SYS_fstatat"] + pub fn __syscall_SYS_fstatat(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 263 */ + #[link_name = "SYS_unlinkat"] + pub fn __syscall_SYS_unlinkat(a1: i32, a2: i32, a3: i32) -> c_long; + /* 265 */ + #[link_name = "SYS_linkat"] + pub fn __syscall_SYS_linkat(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 266 */ + #[link_name = "SYS_symlinkat"] + pub fn __syscall_SYS_symlinkat(a1: i32, a2: i32, a3: i32) -> c_long; + /* 267 */ + #[link_name = "SYS_readlinkat"] + pub fn __syscall_SYS_readlinkat(a1: i32, a2: i32, a3: i32, a4: u32) -> c_long; + /* 268 */ + #[link_name = "SYS_fchmodat"] + pub fn __syscall_SYS_fchmodat(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 269 */ + #[link_name = "SYS_faccessat"] + pub fn __syscall_SYS_faccessat(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 270 */ + #[link_name = "SYS_pselect6"] + pub fn __syscall_SYS_pselect6(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32, a6: i32) -> c_long; + /* 271 */ + #[link_name = "SYS_ppoll"] + pub fn __syscall_SYS_ppoll(a1: i32, a2: u32, a3: i32, a4: i32, a5: u32) -> c_long; + /* 280 */ + #[link_name = "SYS_utimensat"] + pub fn __syscall_SYS_utimensat(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 281 */ + #[link_name = "SYS_epoll_pwait"] + pub fn __syscall_SYS_epoll_pwait( + a1: i32, + a2: i32, + a3: i32, + a4: i32, + a5: i32, + a6: u32, + ) -> c_long; + /* 284 */ + #[link_name = "SYS_eventfd"] + pub fn __syscall_SYS_eventfd(a1: i32) -> c_long; + /* 288 */ + #[link_name = "SYS_accept4"] + pub fn __syscall_SYS_accept4(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 290 */ + #[link_name = "SYS_eventfd2"] + pub fn __syscall_SYS_eventfd2(a1: i32, a2: i32) -> c_long; + /* 291 */ + #[link_name = "SYS_epoll_create1"] + pub fn __syscall_SYS_epoll_create1(a1: i32) -> c_long; + /* 292 */ + #[link_name = "SYS_dup3"] + pub fn __syscall_SYS_dup3(a1: i32, a2: i32, a3: i32) -> c_long; + /* 293 */ + #[link_name = "SYS_pipe2"] + pub fn __syscall_SYS_pipe2(a1: i32, a2: i32) -> c_long; + /* 302 */ + #[link_name = "SYS_prlimit64"] + pub fn __syscall_SYS_prlimit64(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; + /* 316 */ + #[link_name = "SYS_renameat2"] + pub fn __syscall_SYS_renameat2(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 318 */ + #[link_name = "SYS_getrandom"] + pub fn __syscall_SYS_getrandom(a1: i32, a2: u32, a3: i32) -> c_long; + /* 332 */ + #[link_name = "SYS_statx"] + pub fn __syscall_SYS_statx(a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> c_long; + /* 439 */ + #[link_name = "SYS_faccessat2"] + pub fn __syscall_SYS_faccessat2(a1: i32, a2: i32, a3: i32, a4: i32) -> c_long; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/x86_64/mod.rs new file mode 100644 index 00000000000000..39daf548d4ccfe --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/b64/x86_64/mod.rs @@ -0,0 +1,833 @@ +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = c_long; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; +pub type greg_t = i64; + +pub type stat64 = stat; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + __pad0: Padding, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + #[cfg(all(musl32_time64, target_pointer_width = "32"))] + pub st_atime_nsec: i64, + #[cfg(not(all(musl32_time64, target_pointer_width = "32")))] + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + #[cfg(all(musl32_time64, target_pointer_width = "32"))] + pub st_mtime_nsec: i64, + #[cfg(not(all(musl32_time64, target_pointer_width = "32")))] + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + #[cfg(all(musl32_time64, target_pointer_width = "32"))] + pub st_ctime_nsec: i64, + #[cfg(not(all(musl32_time64, target_pointer_width = "32")))] + pub st_ctime_nsec: c_long, + __unused: Padding<[c_long; 3]>, + } + + pub struct user_regs_struct { + pub r15: c_ulong, + pub r14: c_ulong, + pub r13: c_ulong, + pub r12: c_ulong, + pub rbp: c_ulong, + pub rbx: c_ulong, + pub r11: c_ulong, + pub r10: c_ulong, + pub r9: c_ulong, + pub r8: c_ulong, + pub rax: c_ulong, + pub rcx: c_ulong, + pub rdx: c_ulong, + pub rsi: c_ulong, + pub rdi: c_ulong, + pub orig_rax: c_ulong, + pub rip: c_ulong, + pub cs: c_ulong, + pub eflags: c_ulong, + pub rsp: c_ulong, + pub ss: c_ulong, + pub fs_base: c_ulong, + pub gs_base: c_ulong, + pub ds: c_ulong, + pub es: c_ulong, + pub fs: c_ulong, + pub gs: c_ulong, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: c_int, + pub i387: user_fpregs_struct, + pub u_tsize: c_ulong, + pub u_dsize: c_ulong, + pub u_ssize: c_ulong, + pub start_code: c_ulong, + pub start_stack: c_ulong, + pub signal: c_long, + __reserved: Padding, + #[cfg(target_pointer_width = "32")] + __pad1: Padding, + pub u_ar0: *mut user_regs_struct, + #[cfg(target_pointer_width = "32")] + __pad2: Padding, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: c_ulong, + pub u_comm: [c_char; 32], + pub u_debugreg: [c_ulong; 8], + } + + // GitHub repo: ifduyue/musl/ + // commit: b4b1e10364c8737a632be61582e05a8d3acf5690 + // file: arch/x86_64/bits/signal.h#L80-L84 + pub struct mcontext_t { + pub gregs: [greg_t; 23], + __private: [u64; 9], + } + + pub struct ipc_perm { + #[cfg(musl_v1_2_3)] + pub __key: crate::key_t, + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "This field is incorrectly named and will be changed + to __key in a future release." + )] + pub __ipc_perm_key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: crate::mode_t, + pub __seq: c_int, + __unused1: Padding, + __unused2: Padding, + } + + #[repr(align(8))] + pub struct clone_args { + pub flags: c_ulonglong, + pub pidfd: c_ulonglong, + pub child_tid: c_ulonglong, + pub parent_tid: c_ulonglong, + pub exit_signal: c_ulonglong, + pub stack: c_ulonglong, + pub stack_size: c_ulonglong, + pub tls: c_ulonglong, + pub set_tid: c_ulonglong, + pub set_tid_size: c_ulonglong, + pub cgroup: c_ulonglong, + } + + pub struct user_fpregs_struct { + pub cwd: c_ushort, + pub swd: c_ushort, + pub ftw: c_ushort, + pub fop: c_ushort, + pub rip: c_ulong, + pub rdp: c_ulong, + pub mxcsr: c_uint, + pub mxcr_mask: c_uint, + pub st_space: [c_uint; 32], + pub xmm_space: [c_uint; 64], + padding: Padding<[c_uint; 24]>, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: crate::sigset_t, + __private: [u8; 512], + } +} + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +// Syscall table + +pub const SYS_read: c_long = 0; +pub const SYS_write: c_long = 1; +pub const SYS_open: c_long = 2; +pub const SYS_close: c_long = 3; +pub const SYS_stat: c_long = 4; +pub const SYS_fstat: c_long = 5; +pub const SYS_lstat: c_long = 6; +pub const SYS_poll: c_long = 7; +pub const SYS_lseek: c_long = 8; +pub const SYS_mmap: c_long = 9; +pub const SYS_mprotect: c_long = 10; +pub const SYS_munmap: c_long = 11; +pub const SYS_brk: c_long = 12; +pub const SYS_rt_sigaction: c_long = 13; +pub const SYS_rt_sigprocmask: c_long = 14; +pub const SYS_rt_sigreturn: c_long = 15; +pub const SYS_ioctl: c_long = 16; +pub const SYS_pread64: c_long = 17; +pub const SYS_pwrite64: c_long = 18; +pub const SYS_readv: c_long = 19; +pub const SYS_writev: c_long = 20; +pub const SYS_access: c_long = 21; +pub const SYS_pipe: c_long = 22; +pub const SYS_select: c_long = 23; +pub const SYS_sched_yield: c_long = 24; +pub const SYS_mremap: c_long = 25; +pub const SYS_msync: c_long = 26; +pub const SYS_mincore: c_long = 27; +pub const SYS_madvise: c_long = 28; +pub const SYS_shmget: c_long = 29; +pub const SYS_shmat: c_long = 30; +pub const SYS_shmctl: c_long = 31; +pub const SYS_dup: c_long = 32; +pub const SYS_dup2: c_long = 33; +pub const SYS_pause: c_long = 34; +pub const SYS_nanosleep: c_long = 35; +pub const SYS_getitimer: c_long = 36; +pub const SYS_alarm: c_long = 37; +pub const SYS_setitimer: c_long = 38; +pub const SYS_getpid: c_long = 39; +pub const SYS_sendfile: c_long = 40; +pub const SYS_socket: c_long = 41; +pub const SYS_connect: c_long = 42; +pub const SYS_accept: c_long = 43; +pub const SYS_sendto: c_long = 44; +pub const SYS_recvfrom: c_long = 45; +pub const SYS_sendmsg: c_long = 46; +pub const SYS_recvmsg: c_long = 47; +pub const SYS_shutdown: c_long = 48; +pub const SYS_bind: c_long = 49; +pub const SYS_listen: c_long = 50; +pub const SYS_getsockname: c_long = 51; +pub const SYS_getpeername: c_long = 52; +pub const SYS_socketpair: c_long = 53; +pub const SYS_setsockopt: c_long = 54; +pub const SYS_getsockopt: c_long = 55; +pub const SYS_clone: c_long = 56; +pub const SYS_fork: c_long = 57; +pub const SYS_vfork: c_long = 58; +pub const SYS_execve: c_long = 59; +pub const SYS_exit: c_long = 60; +pub const SYS_wait4: c_long = 61; +pub const SYS_kill: c_long = 62; +pub const SYS_uname: c_long = 63; +pub const SYS_semget: c_long = 64; +pub const SYS_semop: c_long = 65; +pub const SYS_semctl: c_long = 66; +pub const SYS_shmdt: c_long = 67; +pub const SYS_msgget: c_long = 68; +pub const SYS_msgsnd: c_long = 69; +pub const SYS_msgrcv: c_long = 70; +pub const SYS_msgctl: c_long = 71; +pub const SYS_fcntl: c_long = 72; +pub const SYS_flock: c_long = 73; +pub const SYS_fsync: c_long = 74; +pub const SYS_fdatasync: c_long = 75; +pub const SYS_truncate: c_long = 76; +pub const SYS_ftruncate: c_long = 77; +pub const SYS_getdents: c_long = 78; +pub const SYS_getcwd: c_long = 79; +pub const SYS_chdir: c_long = 80; +pub const SYS_fchdir: c_long = 81; +pub const SYS_rename: c_long = 82; +pub const SYS_mkdir: c_long = 83; +pub const SYS_rmdir: c_long = 84; +pub const SYS_creat: c_long = 85; +pub const SYS_link: c_long = 86; +pub const SYS_unlink: c_long = 87; +pub const SYS_symlink: c_long = 88; +pub const SYS_readlink: c_long = 89; +pub const SYS_chmod: c_long = 90; +pub const SYS_fchmod: c_long = 91; +pub const SYS_chown: c_long = 92; +pub const SYS_fchown: c_long = 93; +pub const SYS_lchown: c_long = 94; +pub const SYS_umask: c_long = 95; +pub const SYS_gettimeofday: c_long = 96; +pub const SYS_getrlimit: c_long = 97; +pub const SYS_getrusage: c_long = 98; +pub const SYS_sysinfo: c_long = 99; +pub const SYS_times: c_long = 100; +pub const SYS_ptrace: c_long = 101; +pub const SYS_getuid: c_long = 102; +pub const SYS_syslog: c_long = 103; +pub const SYS_getgid: c_long = 104; +pub const SYS_setuid: c_long = 105; +pub const SYS_setgid: c_long = 106; +pub const SYS_geteuid: c_long = 107; +pub const SYS_getegid: c_long = 108; +pub const SYS_setpgid: c_long = 109; +pub const SYS_getppid: c_long = 110; +pub const SYS_getpgrp: c_long = 111; +pub const SYS_setsid: c_long = 112; +pub const SYS_setreuid: c_long = 113; +pub const SYS_setregid: c_long = 114; +pub const SYS_getgroups: c_long = 115; +pub const SYS_setgroups: c_long = 116; +pub const SYS_setresuid: c_long = 117; +pub const SYS_getresuid: c_long = 118; +pub const SYS_setresgid: c_long = 119; +pub const SYS_getresgid: c_long = 120; +pub const SYS_getpgid: c_long = 121; +pub const SYS_setfsuid: c_long = 122; +pub const SYS_setfsgid: c_long = 123; +pub const SYS_getsid: c_long = 124; +pub const SYS_capget: c_long = 125; +pub const SYS_capset: c_long = 126; +pub const SYS_rt_sigpending: c_long = 127; +pub const SYS_rt_sigtimedwait: c_long = 128; +pub const SYS_rt_sigqueueinfo: c_long = 129; +pub const SYS_rt_sigsuspend: c_long = 130; +pub const SYS_sigaltstack: c_long = 131; +pub const SYS_utime: c_long = 132; +pub const SYS_mknod: c_long = 133; +pub const SYS_uselib: c_long = 134; +pub const SYS_personality: c_long = 135; +pub const SYS_ustat: c_long = 136; +pub const SYS_statfs: c_long = 137; +pub const SYS_fstatfs: c_long = 138; +pub const SYS_sysfs: c_long = 139; +pub const SYS_getpriority: c_long = 140; +pub const SYS_setpriority: c_long = 141; +pub const SYS_sched_setparam: c_long = 142; +pub const SYS_sched_getparam: c_long = 143; +pub const SYS_sched_setscheduler: c_long = 144; +pub const SYS_sched_getscheduler: c_long = 145; +pub const SYS_sched_get_priority_max: c_long = 146; +pub const SYS_sched_get_priority_min: c_long = 147; +pub const SYS_sched_rr_get_interval: c_long = 148; +pub const SYS_mlock: c_long = 149; +pub const SYS_munlock: c_long = 150; +pub const SYS_mlockall: c_long = 151; +pub const SYS_munlockall: c_long = 152; +pub const SYS_vhangup: c_long = 153; +pub const SYS_modify_ldt: c_long = 154; +pub const SYS_pivot_root: c_long = 155; +pub const SYS__sysctl: c_long = 156; +pub const SYS_prctl: c_long = 157; +pub const SYS_arch_prctl: c_long = 158; +pub const SYS_adjtimex: c_long = 159; +pub const SYS_setrlimit: c_long = 160; +pub const SYS_chroot: c_long = 161; +pub const SYS_sync: c_long = 162; +pub const SYS_acct: c_long = 163; +pub const SYS_settimeofday: c_long = 164; +pub const SYS_mount: c_long = 165; +pub const SYS_umount2: c_long = 166; +pub const SYS_swapon: c_long = 167; +pub const SYS_swapoff: c_long = 168; +pub const SYS_reboot: c_long = 169; +pub const SYS_sethostname: c_long = 170; +pub const SYS_setdomainname: c_long = 171; +pub const SYS_iopl: c_long = 172; +pub const SYS_ioperm: c_long = 173; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 174; +pub const SYS_init_module: c_long = 175; +pub const SYS_delete_module: c_long = 176; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 177; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 178; +pub const SYS_quotactl: c_long = 179; +pub const SYS_nfsservctl: c_long = 180; +pub const SYS_getpmsg: c_long = 181; +pub const SYS_putpmsg: c_long = 182; +pub const SYS_afs_syscall: c_long = 183; +pub const SYS_tuxcall: c_long = 184; +pub const SYS_security: c_long = 185; +pub const SYS_gettid: c_long = 186; +pub const SYS_readahead: c_long = 187; +pub const SYS_setxattr: c_long = 188; +pub const SYS_lsetxattr: c_long = 189; +pub const SYS_fsetxattr: c_long = 190; +pub const SYS_getxattr: c_long = 191; +pub const SYS_lgetxattr: c_long = 192; +pub const SYS_fgetxattr: c_long = 193; +pub const SYS_listxattr: c_long = 194; +pub const SYS_llistxattr: c_long = 195; +pub const SYS_flistxattr: c_long = 196; +pub const SYS_removexattr: c_long = 197; +pub const SYS_lremovexattr: c_long = 198; +pub const SYS_fremovexattr: c_long = 199; +pub const SYS_tkill: c_long = 200; +pub const SYS_time: c_long = 201; +pub const SYS_futex: c_long = 202; +pub const SYS_sched_setaffinity: c_long = 203; +pub const SYS_sched_getaffinity: c_long = 204; +pub const SYS_set_thread_area: c_long = 205; +pub const SYS_io_setup: c_long = 206; +pub const SYS_io_destroy: c_long = 207; +pub const SYS_io_getevents: c_long = 208; +pub const SYS_io_submit: c_long = 209; +pub const SYS_io_cancel: c_long = 210; +pub const SYS_get_thread_area: c_long = 211; +pub const SYS_lookup_dcookie: c_long = 212; +pub const SYS_epoll_create: c_long = 213; +pub const SYS_epoll_ctl_old: c_long = 214; +pub const SYS_epoll_wait_old: c_long = 215; +pub const SYS_remap_file_pages: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_set_tid_address: c_long = 218; +pub const SYS_restart_syscall: c_long = 219; +pub const SYS_semtimedop: c_long = 220; +pub const SYS_fadvise64: c_long = 221; +pub const SYS_timer_create: c_long = 222; +pub const SYS_timer_settime: c_long = 223; +pub const SYS_timer_gettime: c_long = 224; +pub const SYS_timer_getoverrun: c_long = 225; +pub const SYS_timer_delete: c_long = 226; +pub const SYS_clock_settime: c_long = 227; +pub const SYS_clock_gettime: c_long = 228; +pub const SYS_clock_getres: c_long = 229; +pub const SYS_clock_nanosleep: c_long = 230; +pub const SYS_exit_group: c_long = 231; +pub const SYS_epoll_wait: c_long = 232; +pub const SYS_epoll_ctl: c_long = 233; +pub const SYS_tgkill: c_long = 234; +pub const SYS_utimes: c_long = 235; +pub const SYS_vserver: c_long = 236; +pub const SYS_mbind: c_long = 237; +pub const SYS_set_mempolicy: c_long = 238; +pub const SYS_get_mempolicy: c_long = 239; +pub const SYS_mq_open: c_long = 240; +pub const SYS_mq_unlink: c_long = 241; +pub const SYS_mq_timedsend: c_long = 242; +pub const SYS_mq_timedreceive: c_long = 243; +pub const SYS_mq_notify: c_long = 244; +pub const SYS_mq_getsetattr: c_long = 245; +pub const SYS_kexec_load: c_long = 246; +pub const SYS_waitid: c_long = 247; +pub const SYS_add_key: c_long = 248; +pub const SYS_request_key: c_long = 249; +pub const SYS_keyctl: c_long = 250; +pub const SYS_ioprio_set: c_long = 251; +pub const SYS_ioprio_get: c_long = 252; +pub const SYS_inotify_init: c_long = 253; +pub const SYS_inotify_add_watch: c_long = 254; +pub const SYS_inotify_rm_watch: c_long = 255; +pub const SYS_migrate_pages: c_long = 256; +pub const SYS_openat: c_long = 257; +pub const SYS_mkdirat: c_long = 258; +pub const SYS_mknodat: c_long = 259; +pub const SYS_fchownat: c_long = 260; +pub const SYS_futimesat: c_long = 261; +pub const SYS_newfstatat: c_long = 262; +pub const SYS_unlinkat: c_long = 263; +pub const SYS_renameat: c_long = 264; +pub const SYS_linkat: c_long = 265; +pub const SYS_symlinkat: c_long = 266; +pub const SYS_readlinkat: c_long = 267; +pub const SYS_fchmodat: c_long = 268; +pub const SYS_faccessat: c_long = 269; +pub const SYS_pselect6: c_long = 270; +pub const SYS_ppoll: c_long = 271; +pub const SYS_unshare: c_long = 272; +pub const SYS_set_robust_list: c_long = 273; +pub const SYS_get_robust_list: c_long = 274; +pub const SYS_splice: c_long = 275; +pub const SYS_tee: c_long = 276; +pub const SYS_sync_file_range: c_long = 277; +pub const SYS_vmsplice: c_long = 278; +pub const SYS_move_pages: c_long = 279; +pub const SYS_utimensat: c_long = 280; +pub const SYS_epoll_pwait: c_long = 281; +pub const SYS_signalfd: c_long = 282; +pub const SYS_timerfd_create: c_long = 283; +pub const SYS_eventfd: c_long = 284; +pub const SYS_fallocate: c_long = 285; +pub const SYS_timerfd_settime: c_long = 286; +pub const SYS_timerfd_gettime: c_long = 287; +pub const SYS_accept4: c_long = 288; +pub const SYS_signalfd4: c_long = 289; +pub const SYS_eventfd2: c_long = 290; +pub const SYS_epoll_create1: c_long = 291; +pub const SYS_dup3: c_long = 292; +pub const SYS_pipe2: c_long = 293; +pub const SYS_inotify_init1: c_long = 294; +pub const SYS_preadv: c_long = 295; +pub const SYS_pwritev: c_long = 296; +pub const SYS_rt_tgsigqueueinfo: c_long = 297; +pub const SYS_perf_event_open: c_long = 298; +pub const SYS_recvmmsg: c_long = 299; +pub const SYS_fanotify_init: c_long = 300; +pub const SYS_fanotify_mark: c_long = 301; +pub const SYS_prlimit64: c_long = 302; +pub const SYS_name_to_handle_at: c_long = 303; +pub const SYS_open_by_handle_at: c_long = 304; +pub const SYS_clock_adjtime: c_long = 305; +pub const SYS_syncfs: c_long = 306; +pub const SYS_sendmmsg: c_long = 307; +pub const SYS_setns: c_long = 308; +pub const SYS_getcpu: c_long = 309; +pub const SYS_process_vm_readv: c_long = 310; +pub const SYS_process_vm_writev: c_long = 311; +pub const SYS_kcmp: c_long = 312; +pub const SYS_finit_module: c_long = 313; +pub const SYS_sched_setattr: c_long = 314; +pub const SYS_sched_getattr: c_long = 315; +pub const SYS_renameat2: c_long = 316; +pub const SYS_seccomp: c_long = 317; +pub const SYS_getrandom: c_long = 318; +pub const SYS_memfd_create: c_long = 319; +pub const SYS_kexec_file_load: c_long = 320; +pub const SYS_bpf: c_long = 321; +pub const SYS_execveat: c_long = 322; +pub const SYS_userfaultfd: c_long = 323; +pub const SYS_membarrier: c_long = 324; +pub const SYS_mlock2: c_long = 325; +pub const SYS_copy_file_range: c_long = 326; +pub const SYS_preadv2: c_long = 327; +pub const SYS_pwritev2: c_long = 328; +pub const SYS_pkey_mprotect: c_long = 329; +pub const SYS_pkey_alloc: c_long = 330; +pub const SYS_pkey_free: c_long = 331; +pub const SYS_statx: c_long = 332; +pub const SYS_io_pgetevents: c_long = 333; +pub const SYS_rseq: c_long = 334; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; +pub const SYS_fchmodat2: c_long = 452; +pub const SYS_mseal: c_long = 462; + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: c_int = 0; +pub const R14: c_int = 1; +pub const R13: c_int = 2; +pub const R12: c_int = 3; +pub const RBP: c_int = 4; +pub const RBX: c_int = 5; +pub const R11: c_int = 6; +pub const R10: c_int = 7; +pub const R9: c_int = 8; +pub const R8: c_int = 9; +pub const RAX: c_int = 10; +pub const RCX: c_int = 11; +pub const RDX: c_int = 12; +pub const RSI: c_int = 13; +pub const RDI: c_int = 14; +pub const ORIG_RAX: c_int = 15; +pub const RIP: c_int = 16; +pub const CS: c_int = 17; +pub const EFLAGS: c_int = 18; +pub const RSP: c_int = 19; +pub const SS: c_int = 20; +pub const FS_BASE: c_int = 21; +pub const GS_BASE: c_int = 22; +pub const DS: c_int = 23; +pub const ES: c_int = 24; +pub const FS: c_int = 25; +pub const GS: c_int = 26; + +// offsets in mcontext_t.gregs from bits/signal.h +// GitHub repo: ifduyue/musl/ +// commit: b4b1e10364c8737a632be61582e05a8d3acf5690 +// file: arch/x86_64/bits/signal.h#L9-L56 +pub const REG_R8: c_int = 0; +pub const REG_R9: c_int = 1; +pub const REG_R10: c_int = 2; +pub const REG_R11: c_int = 3; +pub const REG_R12: c_int = 4; +pub const REG_R13: c_int = 5; +pub const REG_R14: c_int = 6; +pub const REG_R15: c_int = 7; +pub const REG_RDI: c_int = 8; +pub const REG_RSI: c_int = 9; +pub const REG_RBP: c_int = 10; +pub const REG_RBX: c_int = 11; +pub const REG_RDX: c_int = 12; +pub const REG_RAX: c_int = 13; +pub const REG_RCX: c_int = 14; +pub const REG_RSP: c_int = 15; +pub const REG_RIP: c_int = 16; +pub const REG_EFL: c_int = 17; +pub const REG_CSGSFS: c_int = 18; +pub const REG_ERR: c_int = 19; +pub const REG_TRAPNO: c_int = 20; +pub const REG_OLDMASK: c_int = 21; +pub const REG_CR2: c_int = 22; + +pub const MADV_SOFT_OFFLINE: c_int = 101; +pub const MAP_32BIT: c_int = 0x0040; +pub const O_APPEND: c_int = 1024; +pub const O_DIRECT: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_LARGEFILE: c_int = 0o0100000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_CREAT: c_int = 64; +pub const O_EXCL: c_int = 128; +pub const O_NOCTTY: c_int = 256; +pub const O_NONBLOCK: c_int = 2048; +pub const O_SYNC: c_int = 1052672; +pub const O_RSYNC: c_int = 1052672; +pub const O_DSYNC: c_int = 4096; +pub const O_ASYNC: c_int = 0x2000; + +pub const PTRACE_SYSEMU: c_int = 31; +pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 32; + +pub const SIGSTKSZ: size_t = 8192; +pub const MINSIGSTKSZ: size_t = 2048; + +pub const ENAMETOOLONG: c_int = 36; +pub const ENOLCK: c_int = 37; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENOMSG: c_int = 42; +pub const EIDRM: c_int = 43; +pub const ECHRNG: c_int = 44; +pub const EL2NSYNC: c_int = 45; +pub const EL3HLT: c_int = 46; +pub const EL3RST: c_int = 47; +pub const ELNRNG: c_int = 48; +pub const EUNATCH: c_int = 49; +pub const ENOCSI: c_int = 50; +pub const EL2HLT: c_int = 51; +pub const EBADE: c_int = 52; +pub const EBADR: c_int = 53; +pub const EXFULL: c_int = 54; +pub const ENOANO: c_int = 55; +pub const EBADRQC: c_int = 56; +pub const EBADSLT: c_int = 57; +pub const EMULTIHOP: c_int = 72; +pub const EBADMSG: c_int = 74; +pub const EOVERFLOW: c_int = 75; +pub const ENOTUNIQ: c_int = 76; +pub const EBADFD: c_int = 77; +pub const EREMCHG: c_int = 78; +pub const ELIBACC: c_int = 79; +pub const ELIBBAD: c_int = 80; +pub const ELIBSCN: c_int = 81; +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; +pub const EILSEQ: c_int = 84; +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; +pub const EUSERS: c_int = 87; +pub const ENOTSOCK: c_int = 88; +pub const EDESTADDRREQ: c_int = 89; +pub const EMSGSIZE: c_int = 90; +pub const EPROTOTYPE: c_int = 91; +pub const ENOPROTOOPT: c_int = 92; +pub const EPROTONOSUPPORT: c_int = 93; +pub const ESOCKTNOSUPPORT: c_int = 94; +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; +pub const EADDRNOTAVAIL: c_int = 99; +pub const ENETDOWN: c_int = 100; +pub const ENETUNREACH: c_int = 101; +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EISCONN: c_int = 106; +pub const ENOTCONN: c_int = 107; +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; +pub const ETIMEDOUT: c_int = 110; +pub const ECONNREFUSED: c_int = 111; +pub const EHOSTDOWN: c_int = 112; +pub const EHOSTUNREACH: c_int = 113; +pub const EALREADY: c_int = 114; +pub const EINPROGRESS: c_int = 115; +pub const ESTALE: c_int = 116; +pub const EUCLEAN: c_int = 117; +pub const ENOTNAM: c_int = 118; +pub const ENAVAIL: c_int = 119; +pub const EISNAM: c_int = 120; +pub const EREMOTEIO: c_int = 121; +pub const EDQUOT: c_int = 122; +pub const ENOMEDIUM: c_int = 123; +pub const EMEDIUMTYPE: c_int = 124; +pub const ECANCELED: c_int = 125; +pub const ENOKEY: c_int = 126; +pub const EKEYEXPIRED: c_int = 127; +pub const EKEYREVOKED: c_int = 128; +pub const EKEYREJECTED: c_int = 129; +pub const EOWNERDEAD: c_int = 130; +pub const ENOTRECOVERABLE: c_int = 131; +pub const ERFKILL: c_int = 132; +pub const EHWPOISON: c_int = 133; + +pub const SA_ONSTACK: c_int = 0x08000000; +pub const SA_SIGINFO: c_int = 0x00000004; +pub const SA_NOCLDWAIT: c_int = 0x00000002; + +pub const SIGCHLD: c_int = 17; +pub const SIGBUS: c_int = 7; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGUSR1: c_int = 10; +pub const SIGUSR2: c_int = 12; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGURG: c_int = 23; +pub const SIGIO: c_int = 29; +pub const SIGSYS: c_int = 31; +pub const SIGSTKFLT: c_int = 16; +pub const SIGPOLL: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0x000000; +pub const SIG_UNBLOCK: c_int = 0x01; + +pub const F_GETLK: c_int = 5; +pub const F_GETOWN: c_int = 9; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_SETOWN: c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_GROWSDOWN: c_int = 0x0100; +pub const MAP_DENYWRITE: c_int = 0x0800; +pub const MAP_EXECUTABLE: c_int = 0x01000; +pub const MAP_LOCKED: c_int = 0x02000; +pub const MAP_NORESERVE: c_int = 0x04000; +pub const MAP_POPULATE: c_int = 0x08000; +pub const MAP_NONBLOCK: c_int = 0x010000; +pub const MAP_STACK: c_int = 0x020000; +pub const MAP_HUGETLB: c_int = 0x040000; +pub const MAP_SYNC: c_int = 0x080000; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const TAB1: c_int = 0x00000800; +pub const TAB2: c_int = 0x00001000; +pub const TAB3: c_int = 0x00001800; +pub const CR1: c_int = 0x00000200; +pub const CR2: c_int = 0x00000400; +pub const CR3: c_int = 0x00000600; +pub const FF1: c_int = 0x00008000; +pub const BS1: c_int = 0x00002000; +pub const VT1: c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const CIBAUD: crate::tcflag_t = 0o02003600000; +pub const CBAUDEX: crate::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const NLDLY: crate::tcflag_t = 0o000400; +pub const CRDLY: crate::tcflag_t = 0o003000; +pub const TABDLY: crate::tcflag_t = 0o014000; +pub const BSDLY: crate::tcflag_t = 0o020000; +pub const FFDLY: crate::tcflag_t = 0o100000; +pub const VTDLY: crate::tcflag_t = 0o040000; +pub const XTABS: crate::tcflag_t = 0o014000; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +pub const EDEADLK: c_int = 35; +pub const EDEADLOCK: c_int = EDEADLK; + +pub const EXTPROC: crate::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; +pub const FLUSHO: crate::tcflag_t = 0x00001000; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/lfs64.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/lfs64.rs new file mode 100644 index 00000000000000..4d595fc42d72f1 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/lfs64.rs @@ -0,0 +1,242 @@ +use crate::off64_t; +use crate::prelude::*; + +#[inline] +pub unsafe extern "C" fn creat64(path: *const c_char, mode: crate::mode_t) -> c_int { + crate::creat(path, mode) +} + +#[inline] +pub unsafe extern "C" fn fallocate64( + fd: c_int, + mode: c_int, + offset: off64_t, + len: off64_t, +) -> c_int { + crate::fallocate(fd, mode, offset, len) +} + +#[inline] +pub unsafe extern "C" fn fgetpos64(stream: *mut crate::FILE, pos: *mut crate::fpos64_t) -> c_int { + crate::fgetpos(stream, pos as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fopen64(pathname: *const c_char, mode: *const c_char) -> *mut crate::FILE { + crate::fopen(pathname, mode) +} + +#[inline] +pub unsafe extern "C" fn freopen64( + pathname: *const c_char, + mode: *const c_char, + stream: *mut crate::FILE, +) -> *mut crate::FILE { + crate::freopen(pathname, mode, stream) +} + +#[inline] +pub unsafe extern "C" fn fseeko64( + stream: *mut crate::FILE, + offset: off64_t, + whence: c_int, +) -> c_int { + crate::fseeko(stream, offset, whence) +} + +#[inline] +pub unsafe extern "C" fn fsetpos64(stream: *mut crate::FILE, pos: *const crate::fpos64_t) -> c_int { + crate::fsetpos(stream, pos as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstat64(fildes: c_int, buf: *mut crate::stat64) -> c_int { + crate::fstat(fildes, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstatat64( + fd: c_int, + path: *const c_char, + buf: *mut crate::stat64, + flag: c_int, +) -> c_int { + crate::fstatat(fd, path, buf as *mut _, flag) +} + +#[inline] +pub unsafe extern "C" fn fstatfs64(fd: c_int, buf: *mut crate::statfs64) -> c_int { + crate::fstatfs(fd, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn fstatvfs64(fd: c_int, buf: *mut crate::statvfs64) -> c_int { + crate::fstatvfs(fd, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn ftello64(stream: *mut crate::FILE) -> off64_t { + crate::ftello(stream) +} + +#[inline] +pub unsafe extern "C" fn ftruncate64(fd: c_int, length: off64_t) -> c_int { + crate::ftruncate(fd, length) +} + +#[inline] +pub unsafe extern "C" fn getrlimit64(resource: c_int, rlim: *mut crate::rlimit64) -> c_int { + crate::getrlimit(resource, rlim as *mut _) +} + +#[inline] +pub unsafe extern "C" fn lseek64(fd: c_int, offset: off64_t, whence: c_int) -> off64_t { + crate::lseek(fd, offset, whence) +} + +#[inline] +pub unsafe extern "C" fn lstat64(path: *const c_char, buf: *mut crate::stat64) -> c_int { + crate::lstat(path, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn mmap64( + addr: *mut c_void, + length: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off64_t, +) -> *mut c_void { + crate::mmap(addr, length, prot, flags, fd, offset) +} + +// These functions are variadic in the C ABI since the `mode` argument is "optional". Variadic +// `extern "C"` functions are unstable in Rust so we cannot write a shim function for these +// entrypoints. See https://github.com/rust-lang/rust/issues/44930. +// +// These aliases are mostly fine though, neither function takes a LFS64-namespaced type as an +// argument, nor do their names clash with any declared types. +pub use crate::{ + open as open64, + openat as openat64, +}; + +#[inline] +pub unsafe extern "C" fn posix_fadvise64( + fd: c_int, + offset: off64_t, + len: off64_t, + advice: c_int, +) -> c_int { + crate::posix_fadvise(fd, offset, len, advice) +} + +#[inline] +pub unsafe extern "C" fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int { + crate::posix_fallocate(fd, offset, len) +} + +#[inline] +pub unsafe extern "C" fn pread64( + fd: c_int, + buf: *mut c_void, + count: size_t, + offset: off64_t, +) -> ssize_t { + crate::pread(fd, buf, count, offset) +} + +#[inline] +pub unsafe extern "C" fn preadv64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, +) -> ssize_t { + crate::preadv(fd, iov, iovcnt, offset) +} + +#[inline] +pub unsafe extern "C" fn prlimit64( + pid: crate::pid_t, + resource: c_int, + new_limit: *const crate::rlimit64, + old_limit: *mut crate::rlimit64, +) -> c_int { + crate::prlimit(pid, resource, new_limit as *mut _, old_limit as *mut _) +} + +#[inline] +pub unsafe extern "C" fn pwrite64( + fd: c_int, + buf: *const c_void, + count: size_t, + offset: off64_t, +) -> ssize_t { + crate::pwrite(fd, buf, count, offset) +} + +#[inline] +pub unsafe extern "C" fn pwritev64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, +) -> ssize_t { + crate::pwritev(fd, iov, iovcnt, offset) +} + +#[inline] +pub unsafe extern "C" fn readdir64(dirp: *mut crate::DIR) -> *mut crate::dirent64 { + crate::readdir(dirp) as *mut _ +} + +#[inline] +pub unsafe extern "C" fn readdir64_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent64, + result: *mut *mut crate::dirent64, +) -> c_int { + crate::readdir_r(dirp, entry as *mut _, result as *mut _) +} + +#[inline] +pub unsafe extern "C" fn sendfile64( + out_fd: c_int, + in_fd: c_int, + offset: *mut off64_t, + count: size_t, +) -> ssize_t { + crate::sendfile(out_fd, in_fd, offset, count) +} + +#[inline] +pub unsafe extern "C" fn setrlimit64(resource: c_int, rlim: *const crate::rlimit64) -> c_int { + crate::setrlimit(resource, rlim as *mut _) +} + +#[inline] +pub unsafe extern "C" fn stat64(pathname: *const c_char, statbuf: *mut crate::stat64) -> c_int { + crate::stat(pathname, statbuf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn statfs64(pathname: *const c_char, buf: *mut crate::statfs64) -> c_int { + crate::statfs(pathname, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn statvfs64(path: *const c_char, buf: *mut crate::statvfs64) -> c_int { + crate::statvfs(path, buf as *mut _) +} + +#[inline] +pub unsafe extern "C" fn tmpfile64() -> *mut crate::FILE { + crate::tmpfile() +} + +#[inline] +pub unsafe extern "C" fn truncate64(path: *const c_char, length: off64_t) -> c_int { + crate::truncate(path, length) +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/mod.rs new file mode 100644 index 00000000000000..9d3009cba8809c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/musl/mod.rs @@ -0,0 +1,914 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type pthread_t = *mut c_void; +pub type clock_t = c_long; +#[cfg(musl32_time64)] +pub type time_t = i64; +#[cfg(not(musl32_time64))] +#[cfg_attr( + not(feature = "rustc-dep-of-std"), + deprecated( + since = "0.2.80", + note = "This type is changed to 64-bit in musl 1.2.0, \ + we'll follow that change in the future release. \ + See #1848 for more info." + ) +)] +pub type time_t = c_long; +#[cfg(musl32_time64)] +pub type suseconds_t = i64; +#[cfg(not(musl32_time64))] +#[cfg_attr( + not(feature = "rustc-dep-of-std"), + deprecated( + since = "0.2.80", + note = "This type is changed to 64-bit in musl 1.2.0, \ + we'll follow that change in the future release. \ + See #1848 for more info." + ) +)] +pub type suseconds_t = c_long; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; + +pub type shmatt_t = c_ulong; +pub type msgqnum_t = c_ulong; +pub type msglen_t = c_ulong; +pub type fsblkcnt_t = c_ulonglong; +pub type fsblkcnt64_t = c_ulonglong; +pub type fsfilcnt_t = c_ulonglong; +pub type fsfilcnt64_t = c_ulonglong; +pub type rlim_t = c_ulonglong; + +cfg_if! { + if #[cfg(doc)] { + // Used in `linux::arch` to define ioctl constants. + pub(crate) type Ioctl = c_int; + } else { + #[doc(hidden)] + pub type Ioctl = c_int; + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_si_value { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_timerid: c_int, + _si_overrun: c_int, + si_value: crate::sigval, + } + (*(self as *const siginfo_t as *const siginfo_si_value)).si_value + } +} + +s_no_extra_traits! { + // Internal, for casts to access union fields + struct sifields_sigchld { + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: c_long, + si_stime: c_long, + } + + // Internal, for casts to access union fields + union sifields { + _align_pointer: *mut c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + struct siginfo_f { + _siginfo_base: [c_int; 3], + sifields: sifields, + } +} + +impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*(self as *const siginfo_t as *const siginfo_f)).sifields + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> c_long { + self.sifields().sigchld.si_stime + } +} + +s! { + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_lio_opcode: c_int, + pub aio_reqprio: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: crate::sigevent, + __td: *mut c_void, + __lock: [c_int; 2], + __err: c_int, + __ret: ssize_t, + pub aio_offset: off_t, + __next: *mut c_void, + __prev: *mut c_void, + __dummy4: [c_char; 32 - 2 * size_of::<*const ()>()], + } + + #[repr(align(8))] + pub struct fanotify_event_metadata { + pub event_len: c_uint, + pub vers: c_uchar, + pub reserved: c_uchar, + pub metadata_len: c_ushort, + pub mask: c_ulonglong, + pub fd: c_int, + pub pid: c_int, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + } + + // `mips*` targets swap the `s_errno` and `s_code` fields otherwise this struct is + // target-agnostic (see https://www.openwall.com/lists/musl/2016/01/27/1/2) + // + // FIXME(union): C implementation uses unions + pub struct siginfo_t { + pub si_signo: c_int, + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + pub si_errno: c_int, + pub si_code: c_int, + #[cfg(any(target_arch = "mips", target_arch = "mips64"))] + pub si_errno: c_int, + #[doc(hidden)] + #[deprecated( + since = "0.2.54", + note = "Please leave a comment on https://github.com/rust-lang/libc/pull/1316 \ + if you're using this field" + )] + pub _pad: [c_int; 29], + _align: [usize; 0], + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: c_ulong, + #[cfg(target_pointer_width = "32")] + __pad: Padding, + #[cfg(target_endian = "big")] + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_reserved: Padding<[c_int; 6]>, + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_favail: crate::fsfilcnt64_t, + #[cfg(target_endian = "little")] + pub f_fsid: c_ulong, + #[cfg(target_pointer_width = "32")] + __pad: Padding, + #[cfg(target_endian = "big")] + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_reserved: Padding<[c_int; 6]>, + } + + // PowerPC implementations are special, see the subfolders + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub __c_ispeed: crate::speed_t, + pub __c_ospeed: crate::speed_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct flock64 { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off64_t, + pub l_len: off64_t, + pub l_pid: crate::pid_t, + } + + pub struct regex_t { + __re_nsub: size_t, + __opaque: *mut c_void, + __padding: Padding<[*mut c_void; 4usize]>, + __nsub2: size_t, + __padding2: Padding, + } + + pub struct rtentry { + pub rt_pad1: c_ulong, + pub rt_dst: crate::sockaddr, + pub rt_gateway: crate::sockaddr, + pub rt_genmask: crate::sockaddr, + pub rt_flags: c_ushort, + pub rt_pad2: c_short, + pub rt_pad3: c_ulong, + pub rt_tos: c_uchar, + pub rt_class: c_uchar, + #[cfg(target_pointer_width = "64")] + pub rt_pad4: [c_short; 3usize], + #[cfg(not(target_pointer_width = "64"))] + pub rt_pad4: [c_short; 1usize], + pub rt_metric: c_short, + pub rt_dev: *mut c_char, + pub rt_mtu: c_ulong, + pub rt_window: c_ulong, + pub rt_irtt: c_ushort, + } + + pub struct __exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct Elf64_Chdr { + pub ch_type: crate::Elf64_Word, + pub ch_reserved: crate::Elf64_Word, + pub ch_size: crate::Elf64_Xword, + pub ch_addralign: crate::Elf64_Xword, + } + + pub struct Elf32_Chdr { + pub ch_type: crate::Elf32_Word, + pub ch_size: crate::Elf32_Word, + pub ch_addralign: crate::Elf32_Word, + } + + pub struct timex { + pub modes: c_uint, + pub offset: c_long, + pub freq: c_long, + pub maxerror: c_long, + pub esterror: c_long, + pub status: c_int, + pub constant: c_long, + pub precision: c_long, + pub tolerance: c_long, + pub time: crate::timeval, + pub tick: c_long, + pub ppsfreq: c_long, + pub jitter: c_long, + pub shift: c_int, + pub stabil: c_long, + pub jitcnt: c_long, + pub calcnt: c_long, + pub errcnt: c_long, + pub stbcnt: c_long, + pub tai: c_int, + pub __padding: [c_int; 11], + } + + pub struct ntptimeval { + pub time: crate::timeval, + pub maxerror: c_long, + pub esterror: c_long, + } + + // netinet/tcp.h + + pub struct tcp_info { + pub tcpi_state: u8, + pub tcpi_ca_state: u8, + pub tcpi_retransmits: u8, + pub tcpi_probes: u8, + pub tcpi_backoff: u8, + pub tcpi_options: u8, + /// This contains the bitfields `tcpi_snd_wscale` and `tcpi_rcv_wscale`. + /// Each is 4 bits. + pub tcpi_snd_rcv_wscale: u8, + /// This contains the bitfields `tcpi_delivery_rate_app_limited` (1 bit) and + /// `tcpi_fastopen_client_fail` (2 bits). + pub tcpi_delivery_fastopen_bitfields: u8, + pub tcpi_rto: u32, + pub tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub tcpi_unacked: u32, + pub tcpi_sacked: u32, + pub tcpi_lost: u32, + pub tcpi_retrans: u32, + pub tcpi_fackets: u32, + pub tcpi_last_data_sent: u32, + pub tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub tcpi_last_ack_recv: u32, + pub tcpi_pmtu: u32, + pub tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub tcpi_advmss: u32, + pub tcpi_reordering: u32, + pub tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_total_retrans: u32, + pub tcpi_pacing_rate: u64, + pub tcpi_max_pacing_rate: u64, + pub tcpi_bytes_acked: u64, + pub tcpi_bytes_received: u64, + pub tcpi_segs_out: u32, + pub tcpi_segs_in: u32, + pub tcpi_notsent_bytes: u32, + pub tcpi_min_rtt: u32, + pub tcpi_data_segs_in: u32, + pub tcpi_data_segs_out: u32, + pub tcpi_delivery_rate: u64, + pub tcpi_busy_time: u64, + pub tcpi_rwnd_limited: u64, + pub tcpi_sndbuf_limited: u64, + pub tcpi_delivered: u32, + pub tcpi_delivered_ce: u32, + pub tcpi_bytes_sent: u64, + pub tcpi_bytes_retrans: u64, + pub tcpi_dsack_dups: u32, + pub tcpi_reord_seen: u32, + pub tcpi_rcv_ooopack: u32, + pub tcpi_snd_wnd: u32, + } + + // MIPS/s390x implementation is special (see arch folders) + #[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "s390x")))] + pub struct statfs { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_frsize: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 4], + } + + // MIPS/s390x implementation is special (see arch folders) + #[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "s390x")))] + pub struct statfs64 { + pub f_type: c_ulong, + pub f_bsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_ulong, + pub f_frsize: c_ulong, + pub f_flags: c_ulong, + pub f_spare: [c_ulong; 4], + } + + pub struct sysinfo { + pub uptime: c_ulong, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub __reserved: [c_char; 256], + } + + pub struct utmpx { + pub ut_type: c_short, + __ut_pad1: Padding, + pub ut_pid: crate::pid_t, + pub ut_line: [c_char; 32], + pub ut_id: [c_char; 4], + pub ut_user: [c_char; 32], + pub ut_host: [c_char; 256], + pub ut_exit: __exit_status, + + #[cfg(not(musl_v1_2_3))] + #[deprecated( + since = "0.2.173", + note = "The ABI of this field has changed from c_long to c_int with padding, \ + we'll follow that change in the future release. See #4443 for more info." + )] + pub ut_session: c_long, + + #[cfg(musl_v1_2_3)] + #[cfg(not(target_endian = "little"))] + __ut_pad2: Padding, + + #[cfg(musl_v1_2_3)] + pub ut_session: c_int, + + #[cfg(musl_v1_2_3)] + #[cfg(target_endian = "little")] + __ut_pad2: Padding, + + pub ut_tv: crate::timeval, + pub ut_addr_v6: [c_uint; 4], + __unused: Padding<[c_char; 20]>, + } +} + +// include/sys/mman.h +/* + * Huge page size encoding when MAP_HUGETLB is specified, and a huge page + * size other than the default is desired. See hugetlb_encode.h. + * All known huge page size encodings are provided here. It is the + * responsibility of the application to know which sizes are supported on + * the running system. See mmap(2) man page for details. + */ +pub const MAP_HUGE_SHIFT: c_int = 26; +pub const MAP_HUGE_MASK: c_int = 0x3f; + +pub const MAP_HUGE_64KB: c_int = 16 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_512KB: c_int = 19 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_1MB: c_int = 20 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_2MB: c_int = 21 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_8MB: c_int = 23 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_16MB: c_int = 24 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_32MB: c_int = 25 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_256MB: c_int = 28 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_512MB: c_int = 29 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_1GB: c_int = 30 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_2GB: c_int = 31 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_16GB: c_int = 34 << MAP_HUGE_SHIFT; + +pub const MS_RMT_MASK: c_ulong = 0x02800051; + +// include/utmpx.h +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const NEW_TIME: c_short = 3; +pub const OLD_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +pub const NCCS: usize = 32; +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pub const NCCS: usize = 19; + +pub const O_TRUNC: c_int = 512; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_CLOEXEC: c_int = 0x80000; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; + +pub const F_RDLCK: c_int = 0; +pub const F_WRLCK: c_int = 1; +pub const F_UNLCK: c_int = 2; + +pub const SA_NODEFER: c_int = 0x40000000; +pub const SA_RESETHAND: c_int = 0x80000000; +pub const SA_RESTART: c_int = 0x10000000; +pub const SA_NOCLDSTOP: c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const BUFSIZ: c_uint = 1024; +pub const TMP_MAX: c_uint = 10000; +pub const FOPEN_MAX: c_uint = 1000; +pub const FILENAME_MAX: c_uint = 4096; +pub const O_PATH: c_int = 0o10000000; +pub const O_EXEC: c_int = 0o10000000; +pub const O_SEARCH: c_int = 0o10000000; +pub const O_ACCMODE: c_int = 0o10000003; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const NI_MAXHOST: crate::socklen_t = 255; +pub const PTHREAD_STACK_MIN: size_t = 2048; + +pub const MAP_ANONYMOUS: c_int = MAP_ANON; + +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_DCCP: c_int = 6; +pub const SOCK_NONBLOCK: c_int = O_NONBLOCK; +#[deprecated(since = "0.2.70", note = "AF_PACKET must be used instead")] +pub const SOCK_PACKET: c_int = 10; + +pub const SOMAXCONN: c_int = 128; + +#[deprecated(since = "0.2.55", note = "Use SIGSYS instead")] +pub const SIGUNUSED: c_int = crate::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +// Value was changed in 1.2.4 +pub const CPU_SETSIZE: c_int = if cfg!(musl_v1_2_3) { 1024 } else { 128 }; + +pub const PTRACE_TRACEME: c_int = 0; +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_PEEKUSER: c_int = 3; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_POKEUSER: c_int = 6; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; +pub const PTRACE_GETFPXREGS: c_int = 18; +pub const PTRACE_SETFPXREGS: c_int = 19; +pub const PTRACE_SYSCALL: c_int = 24; +pub const PTRACE_SETOPTIONS: c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: c_int = 0x4201; +pub const PTRACE_GETSIGINFO: c_int = 0x4202; +pub const PTRACE_SETSIGINFO: c_int = 0x4203; +pub const PTRACE_GETREGSET: c_int = 0x4204; +pub const PTRACE_SETREGSET: c_int = 0x4205; +pub const PTRACE_SEIZE: c_int = 0x4206; +pub const PTRACE_INTERRUPT: c_int = 0x4207; +pub const PTRACE_LISTEN: c_int = 0x4208; +pub const PTRACE_PEEKSIGINFO: c_int = 0x4209; +pub const PTRACE_GETSIGMASK: c_uint = 0x420a; +pub const PTRACE_SETSIGMASK: c_uint = 0x420b; + +pub const AF_IB: c_int = 27; +pub const AF_MPLS: c_int = 28; +pub const AF_NFC: c_int = 39; +pub const AF_VSOCK: c_int = 40; +pub const AF_XDP: c_int = 44; +pub const PF_IB: c_int = AF_IB; +pub const PF_MPLS: c_int = AF_MPLS; +pub const PF_NFC: c_int = AF_NFC; +pub const PF_VSOCK: c_int = AF_VSOCK; +pub const PF_XDP: c_int = AF_XDP; + +pub const EFD_NONBLOCK: c_int = crate::O_NONBLOCK; + +pub const SFD_NONBLOCK: c_int = crate::O_NONBLOCK; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_NOLOAD: c_int = 0x4; + +pub const CLOCK_SGI_CYCLE: crate::clockid_t = 10; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const EXTA: crate::speed_t = B19200; +pub const EXTB: crate::speed_t = B38400; + +pub const REG_OK: c_int = 0; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const ADJ_OFFSET: c_uint = 0x0001; +pub const ADJ_FREQUENCY: c_uint = 0x0002; +pub const ADJ_MAXERROR: c_uint = 0x0004; +pub const ADJ_ESTERROR: c_uint = 0x0008; +pub const ADJ_STATUS: c_uint = 0x0010; +pub const ADJ_TIMECONST: c_uint = 0x0020; +pub const ADJ_TAI: c_uint = 0x0080; +pub const ADJ_SETOFFSET: c_uint = 0x0100; +pub const ADJ_MICRO: c_uint = 0x1000; +pub const ADJ_NANO: c_uint = 0x2000; +pub const ADJ_TICK: c_uint = 0x4000; +pub const ADJ_OFFSET_SINGLESHOT: c_uint = 0x8001; +pub const ADJ_OFFSET_SS_READ: c_uint = 0xa001; +pub const MOD_OFFSET: c_uint = ADJ_OFFSET; +pub const MOD_FREQUENCY: c_uint = ADJ_FREQUENCY; +pub const MOD_MAXERROR: c_uint = ADJ_MAXERROR; +pub const MOD_ESTERROR: c_uint = ADJ_ESTERROR; +pub const MOD_STATUS: c_uint = ADJ_STATUS; +pub const MOD_TIMECONST: c_uint = ADJ_TIMECONST; +pub const MOD_CLKB: c_uint = ADJ_TICK; +pub const MOD_CLKA: c_uint = ADJ_OFFSET_SINGLESHOT; +pub const MOD_TAI: c_uint = ADJ_TAI; +pub const MOD_MICRO: c_uint = ADJ_MICRO; +pub const MOD_NANO: c_uint = ADJ_NANO; +pub const STA_PLL: c_int = 0x0001; +pub const STA_PPSFREQ: c_int = 0x0002; +pub const STA_PPSTIME: c_int = 0x0004; +pub const STA_FLL: c_int = 0x0008; +pub const STA_INS: c_int = 0x0010; +pub const STA_DEL: c_int = 0x0020; +pub const STA_UNSYNC: c_int = 0x0040; +pub const STA_FREQHOLD: c_int = 0x0080; +pub const STA_PPSSIGNAL: c_int = 0x0100; +pub const STA_PPSJITTER: c_int = 0x0200; +pub const STA_PPSWANDER: c_int = 0x0400; +pub const STA_PPSERROR: c_int = 0x0800; +pub const STA_CLOCKERR: c_int = 0x1000; +pub const STA_NANO: c_int = 0x2000; +pub const STA_MODE: c_int = 0x4000; +pub const STA_CLK: c_int = 0x8000; +pub const STA_RONLY: c_int = STA_PPSSIGNAL + | STA_PPSJITTER + | STA_PPSWANDER + | STA_PPSERROR + | STA_CLOCKERR + | STA_NANO + | STA_MODE + | STA_CLK; + +pub const TIME_OK: c_int = 0; +pub const TIME_INS: c_int = 1; +pub const TIME_DEL: c_int = 2; +pub const TIME_OOP: c_int = 3; +pub const TIME_WAIT: c_int = 4; +pub const TIME_ERROR: c_int = 5; +pub const TIME_BAD: c_int = TIME_ERROR; +pub const MAXTC: c_long = 6; + +pub const _CS_V6_ENV: c_int = 1148; +pub const _CS_V7_ENV: c_int = 1149; + +pub const CLONE_NEWTIME: c_int = 0x80; + +pub const UT_HOSTSIZE: usize = 256; +pub const UT_LINESIZE: usize = 32; +pub const UT_NAMESIZE: usize = 32; + +cfg_if! { + if #[cfg(target_arch = "s390x")] { + pub const POSIX_FADV_DONTNEED: c_int = 6; + pub const POSIX_FADV_NOREUSE: c_int = 7; + } else { + pub const POSIX_FADV_DONTNEED: c_int = 4; + pub const POSIX_FADV_NOREUSE: c_int = 5; + } +} + +extern "C" { + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + pub fn prlimit( + pid: crate::pid_t, + resource: c_int, + new_limit: *const crate::rlimit, + old_limit: *mut crate::rlimit, + ) -> c_int; + #[cfg_attr(musl_redir_time64, link_name = "__gettimeofday_time64")] + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn ptrace(request: c_int, ...) -> c_long; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + // Musl targets need the `mask` argument of `fanotify_mark` be specified + // `c_ulonglong` instead of `u64` or there will be a type mismatch between + // `long long unsigned int` and the expected `uint64_t`. + pub fn fanotify_mark( + fd: c_int, + flags: c_uint, + mask: c_ulonglong, + dirfd: c_int, + path: *const c_char, + ) -> c_int; + pub fn preadv2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, + ) -> ssize_t; + pub fn pwritev2( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, + ) -> ssize_t; + pub fn getauxval(type_: c_ulong) -> c_ulong; + + // Added in `musl` 1.1.20 + pub fn explicit_bzero(s: *mut c_void, len: size_t); + // Added in `musl` 1.2.2 + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + + #[cfg_attr(musl_redir_time64, link_name = "__adjtimex_time64")] + pub fn adjtimex(buf: *mut crate::timex) -> c_int; + #[cfg_attr(musl_redir_time64, link_name = "__clock_adjtime64")] + pub fn clock_adjtime(clk_id: crate::clockid_t, buf: *mut crate::timex) -> c_int; + + pub fn ctermid(s: *mut c_char) -> *mut c_char; + + pub fn memfd_create(name: *const c_char, flags: c_uint) -> c_int; + pub fn mlock2(addr: *const c_void, len: size_t, flags: c_uint) -> c_int; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + + pub fn euidaccess(pathname: *const c_char, mode: c_int) -> c_int; + pub fn eaccess(pathname: *const c_char, mode: c_int) -> c_int; + + pub fn asctime_r(tm: *const crate::tm, buf: *mut c_char) -> *mut c_char; + + pub fn dirname(path: *mut c_char) -> *mut c_char; + pub fn basename(path: *mut c_char) -> *mut c_char; + + // Added in `musl` 1.1.20 + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + // Added in `musl` 1.1.24 + pub fn posix_spawn_file_actions_addchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + // Added in `musl` 1.1.24 + pub fn posix_spawn_file_actions_addfchdir_np( + actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn getutxent() -> *mut utmpx; + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn setutxent(); + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn endutxent(); + #[deprecated( + since = "0.2.172", + note = "musl provides `utmp` as stubs and an alternative should be preferred; see https://wiki.musl-libc.org/faq.html" + )] + pub fn utmpxname(file: *const c_char) -> c_int; + pub fn pthread_tryjoin_np(thread: crate::pthread_t, retval: *mut *mut c_void) -> c_int; + #[cfg_attr( + all(musl_redir_time64, target_pointer_width = "32"), + link_name = "__pthread_timedjoin_np_time64" + )] + pub fn pthread_timedjoin_np( + thread: crate::pthread_t, + retval: *mut *mut c_void, + abstime: *const crate::timespec, + ) -> c_int; +} + +// Alias to 64 to mimic glibc's LFS64 support +mod lfs64; +pub use self::lfs64::*; + +cfg_if! { + if #[cfg(any( + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "riscv64", + target_arch = "loongarch64", + // musl-linux ABI for wasm32 follows b64 convention + target_arch = "wasm32", + ))] { + mod b64; + pub use self::b64::*; + } else if #[cfg(any( + target_arch = "x86", + target_arch = "mips", + target_arch = "powerpc", + target_arch = "hexagon", + target_arch = "riscv32", + target_arch = "arm" + ))] { + mod b32; + pub use self::b32::*; + } else { + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/arm/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/arm/mod.rs new file mode 100644 index 00000000000000..26dd49b24465bd --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/arm/mod.rs @@ -0,0 +1,925 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type wchar_t = c_uint; +pub type time_t = c_long; + +pub type clock_t = c_long; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulong; +pub type off_t = c_long; +pub type pthread_t = c_ulong; +pub type suseconds_t = c_long; + +pub type nlink_t = c_uint; +pub type blksize_t = c_long; +pub type blkcnt_t = c_long; + +pub type fsblkcnt64_t = u64; +pub type fsfilcnt64_t = u64; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +s! { + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct pthread_attr_t { + __size: [c_long; 9], + } + + pub struct stat { + pub st_dev: c_ulonglong, + __pad1: Padding, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulonglong, + __pad2: Padding, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + __unused4: Padding, + __unused5: Padding, + } + + pub struct stat64 { + pub st_dev: c_ulonglong, + pub __pad1: c_uint, + pub __st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulonglong, + pub __pad2: c_uint, + pub st_size: off64_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_ino: crate::ino64_t, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 8], + } + + pub struct statfs { + pub f_type: c_int, + pub f_bsize: c_int, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + + pub f_fsid: crate::fsid_t, + pub f_namelen: c_int, + pub f_frsize: c_int, + pub f_flags: c_int, + pub f_spare: [c_int; 4], + } + + pub struct statfs64 { + pub f_type: c_int, + pub f_bsize: c_int, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_int, + pub f_frsize: c_int, + pub f_flags: c_int, + pub f_spare: [c_int; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct sigset_t { + __val: [c_ulong; 2], + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_flags: c_ulong, + pub sa_restorer: Option, + pub sa_mask: sigset_t, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + pub _pad: [c_int; 29], + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + __unused1: Padding, + pub msg_rtime: crate::time_t, + __unused2: Padding, + pub msg_ctime: crate::time_t, + __unused3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + __unused1: Padding, + pub shm_dtime: crate::time_t, + __unused2: Padding, + pub shm_ctime: crate::time_t, + __unused3: Padding, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + // FIXME(1.0) this is actually a union + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [c_char; 32], + } +} + +pub const O_CLOEXEC: c_int = 0o2000000; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 36; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_COND_COMPAT_T: usize = 12; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const NCCS: usize = 32; + +// I wasn't able to find those constants +// in uclibc build environment for armv7 +pub const MAP_HUGETLB: c_int = 0x040000; // from linux/other/mod.rs + +// autogenerated constants with hand tuned types +pub const B0: crate::speed_t = 0; +pub const B1000000: crate::speed_t = 0x1008; +pub const B110: crate::speed_t = 0x3; +pub const B115200: crate::speed_t = 0x1002; +pub const B1152000: crate::speed_t = 0x1009; +pub const B1200: crate::speed_t = 0x9; +pub const B134: crate::speed_t = 0x4; +pub const B150: crate::speed_t = 0x5; +pub const B1500000: crate::speed_t = 0x100a; +pub const B1800: crate::speed_t = 0xa; +pub const B19200: crate::speed_t = 0xe; +pub const B200: crate::speed_t = 0x6; +pub const B2000000: crate::speed_t = 0x100b; +pub const B230400: crate::speed_t = 0x1003; +pub const B2400: crate::speed_t = 0xb; +pub const B2500000: crate::speed_t = 0x100c; +pub const B300: crate::speed_t = 0x7; +pub const B3000000: crate::speed_t = 0x100d; +pub const B3500000: crate::speed_t = 0x100e; +pub const B38400: crate::speed_t = 0xf; +pub const B4000000: crate::speed_t = 0x100f; +pub const B460800: crate::speed_t = 0x1004; +pub const B4800: crate::speed_t = 0xc; +pub const B50: crate::speed_t = 0x1; +pub const B500000: crate::speed_t = 0x1005; +pub const B57600: crate::speed_t = 0x1001; +pub const B576000: crate::speed_t = 0x1006; +pub const B600: crate::speed_t = 0x8; +pub const B75: crate::speed_t = 0x2; +pub const B921600: crate::speed_t = 0x1007; +pub const B9600: crate::speed_t = 0xd; +pub const BS1: c_int = 0x2000; +pub const BSDLY: c_int = 0x2000; +pub const CBAUD: crate::tcflag_t = 0x100f; +pub const CBAUDEX: crate::tcflag_t = 0x1000; +pub const CIBAUD: crate::tcflag_t = 0x100f0000; +pub const CLOCAL: crate::tcflag_t = 0x800; +pub const CPU_SETSIZE: c_int = 0x400; +pub const CR1: c_int = 0x200; +pub const CR2: c_int = 0x400; +pub const CR3: c_int = 0x600; +pub const CRDLY: c_int = 0x600; +pub const CREAD: crate::tcflag_t = 0x80; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSIZE: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x40; +pub const EADDRINUSE: c_int = 0x62; +pub const EADDRNOTAVAIL: c_int = 0x63; +pub const EADV: c_int = 0x44; +pub const EAFNOSUPPORT: c_int = 0x61; +pub const EALREADY: c_int = 0x72; +pub const EBADE: c_int = 0x34; +pub const EBADFD: c_int = 0x4d; +pub const EBADMSG: c_int = 0x4a; +pub const EBADR: c_int = 0x35; +pub const EBADRQC: c_int = 0x38; +pub const EBADSLT: c_int = 0x39; +pub const EBFONT: c_int = 0x3b; +pub const ECANCELED: c_int = 0x7d; +pub const ECHOCTL: crate::tcflag_t = 0x200; +pub const ECHOE: crate::tcflag_t = 0x10; +pub const ECHOK: crate::tcflag_t = 0x20; +pub const ECHOKE: crate::tcflag_t = 0x800; +pub const ECHONL: crate::tcflag_t = 0x40; +pub const ECHOPRT: crate::tcflag_t = 0x400; +pub const ECHRNG: c_int = 0x2c; +pub const ECOMM: c_int = 0x46; +pub const ECONNABORTED: c_int = 0x67; +pub const ECONNREFUSED: c_int = 0x6f; +pub const ECONNRESET: c_int = 0x68; +pub const EDEADLK: c_int = 0x23; +pub const EDESTADDRREQ: c_int = 0x59; +pub const EDOTDOT: c_int = 0x49; +pub const EDQUOT: c_int = 0x7a; +pub const EFD_CLOEXEC: c_int = 0x80000; +pub const EFD_NONBLOCK: c_int = 0x800; +pub const EHOSTDOWN: c_int = 0x70; +pub const EHOSTUNREACH: c_int = 0x71; +pub const EHWPOISON: c_int = 0x85; +pub const EIDRM: c_int = 0x2b; +pub const EILSEQ: c_int = 0x54; +pub const EINPROGRESS: c_int = 0x73; +pub const EISCONN: c_int = 0x6a; +pub const EISNAM: c_int = 0x78; +pub const EKEYEXPIRED: c_int = 0x7f; +pub const EKEYREJECTED: c_int = 0x81; +pub const EKEYREVOKED: c_int = 0x80; +pub const EL2HLT: c_int = 0x33; +pub const EL2NSYNC: c_int = 0x2d; +pub const EL3HLT: c_int = 0x2e; +pub const EL3RST: c_int = 0x2f; +pub const ELIBACC: c_int = 0x4f; +pub const ELIBBAD: c_int = 0x50; +pub const ELIBEXEC: c_int = 0x53; +pub const ELIBMAX: c_int = 0x52; +pub const ELIBSCN: c_int = 0x51; +pub const ELNRNG: c_int = 0x30; +pub const ELOOP: c_int = 0x28; +pub const EMEDIUMTYPE: c_int = 0x7c; +pub const EMSGSIZE: c_int = 0x5a; +pub const EMULTIHOP: c_int = 0x48; +pub const ENAMETOOLONG: c_int = 0x24; +pub const ENAVAIL: c_int = 0x77; +pub const ENETDOWN: c_int = 0x64; +pub const ENETRESET: c_int = 0x66; +pub const ENETUNREACH: c_int = 0x65; +pub const ENOANO: c_int = 0x37; +pub const ENOBUFS: c_int = 0x69; +pub const ENOCSI: c_int = 0x32; +pub const ENODATA: c_int = 0x3d; +pub const ENOKEY: c_int = 0x7e; +pub const ENOLCK: c_int = 0x25; +pub const ENOLINK: c_int = 0x43; +pub const ENOMEDIUM: c_int = 0x7b; +pub const ENOMSG: c_int = 0x2a; +pub const ENONET: c_int = 0x40; +pub const ENOPKG: c_int = 0x41; +pub const ENOPROTOOPT: c_int = 0x5c; +pub const ENOSR: c_int = 0x3f; +pub const ENOSTR: c_int = 0x3c; +pub const ENOSYS: c_int = 0x26; +pub const ENOTCONN: c_int = 0x6b; +pub const ENOTEMPTY: c_int = 0x27; +pub const ENOTNAM: c_int = 0x76; +pub const ENOTRECOVERABLE: c_int = 0x83; +pub const ENOTSOCK: c_int = 0x58; +pub const ENOTUNIQ: c_int = 0x4c; +pub const EOPNOTSUPP: c_int = 0x5f; +pub const EOVERFLOW: c_int = 0x4b; +pub const EOWNERDEAD: c_int = 0x82; +pub const EPFNOSUPPORT: c_int = 0x60; +pub const EPOLL_CLOEXEC: c_int = 0x80000; +pub const EPROTO: c_int = 0x47; +pub const EPROTONOSUPPORT: c_int = 0x5d; +pub const EPROTOTYPE: c_int = 0x5b; +pub const EREMCHG: c_int = 0x4e; +pub const EREMOTE: c_int = 0x42; +pub const EREMOTEIO: c_int = 0x79; +pub const ERESTART: c_int = 0x55; +pub const ERFKILL: c_int = 0x84; +pub const ESHUTDOWN: c_int = 0x6c; +pub const ESOCKTNOSUPPORT: c_int = 0x5e; +pub const ESRMNT: c_int = 0x45; +pub const ESTALE: c_int = 0x74; +pub const ESTRPIPE: c_int = 0x56; +pub const ETIME: c_int = 0x3e; +pub const ETIMEDOUT: c_int = 0x6e; +pub const ETOOMANYREFS: c_int = 0x6d; +pub const EUCLEAN: c_int = 0x75; +pub const EUNATCH: c_int = 0x31; +pub const EUSERS: c_int = 0x57; +pub const EXFULL: c_int = 0x36; +pub const FF1: c_int = 0x8000; +pub const FFDLY: c_int = 0x8000; +pub const FLUSHO: crate::tcflag_t = 0x1000; +pub const F_GETLK: c_int = 0x5; +pub const F_SETLK: c_int = 0x6; +pub const F_SETLKW: c_int = 0x7; +pub const HUPCL: crate::tcflag_t = 0x400; +pub const ICANON: crate::tcflag_t = 0x2; +pub const IEXTEN: crate::tcflag_t = 0x8000; +pub const ISIG: crate::tcflag_t = 0x1; +pub const IXOFF: crate::tcflag_t = 0x1000; +pub const IXON: crate::tcflag_t = 0x400; +pub const MAP_ANON: c_int = 0x20; +pub const MAP_ANONYMOUS: c_int = 0x20; +pub const MAP_DENYWRITE: c_int = 0x800; +pub const MAP_EXECUTABLE: c_int = 0x1000; +pub const MAP_GROWSDOWN: c_int = 0x100; +pub const MAP_LOCKED: c_int = 0x2000; +pub const MAP_NONBLOCK: c_int = 0x10000; +pub const MAP_NORESERVE: c_int = 0x4000; +pub const MAP_POPULATE: c_int = 0x8000; +pub const MAP_STACK: c_int = 0x20000; +pub const NLDLY: crate::tcflag_t = 0x100; +pub const NOFLSH: crate::tcflag_t = 0x80; +pub const OLCUC: crate::tcflag_t = 0x2; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const O_ACCMODE: c_int = 0x3; +pub const O_APPEND: c_int = 0x400; +pub const O_ASYNC: c_int = 0o20000; +pub const O_CREAT: c_int = 0x40; +pub const O_DIRECT: c_int = 0x10000; +pub const O_DIRECTORY: c_int = 0x4000; +pub const O_DSYNC: c_int = O_SYNC; +pub const O_EXCL: c_int = 0x80; +pub const O_FSYNC: c_int = O_SYNC; +pub const O_LARGEFILE: c_int = 0o400000; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const O_NOATIME: c_int = 0o1000000; +pub const O_NOCTTY: c_int = 0x100; +pub const O_NOFOLLOW: c_int = 0x8000; +pub const O_NONBLOCK: c_int = 0x800; +pub const O_PATH: c_int = 0o10000000; +pub const O_RSYNC: c_int = O_SYNC; +pub const O_SYNC: c_int = 0o10000; +pub const O_TRUNC: c_int = 0x200; +pub const PARENB: crate::tcflag_t = 0x100; +pub const PARODD: crate::tcflag_t = 0x200; +pub const PENDIN: crate::tcflag_t = 0x4000; +pub const POLLWRBAND: c_short = 0x200; +pub const POLLWRNORM: c_short = 0x100; +pub const PTHREAD_STACK_MIN: size_t = 16384; +pub const RTLD_GLOBAL: c_int = 0x00100; + +// These are typed unsigned to match sigaction +pub const SA_NOCLDSTOP: c_ulong = 0x1; +pub const SA_NOCLDWAIT: c_ulong = 0x2; +pub const SA_SIGINFO: c_ulong = 0x4; +pub const SA_NODEFER: c_ulong = 0x40000000; +pub const SA_ONSTACK: c_ulong = 0x8000000; +pub const SA_RESETHAND: c_ulong = 0x80000000; +pub const SA_RESTART: c_ulong = 0x10000000; + +pub const SFD_CLOEXEC: c_int = 0x80000; +pub const SFD_NONBLOCK: c_int = 0x800; +pub const SIGBUS: c_int = 0x7; +pub const SIGCHLD: c_int = 0x11; +pub const SIGCONT: c_int = 0x12; +pub const SIGIO: c_int = 0x1d; +pub const SIGPROF: c_int = 0x1b; +pub const SIGPWR: c_int = 0x1e; +pub const SIGSTKFLT: c_int = 0x10; +pub const SIGSTKSZ: size_t = 8192; +pub const SIGSTOP: c_int = 0x13; +pub const SIGSYS: c_int = 0x1f; +pub const SIGTSTP: c_int = 0x14; +pub const SIGTTIN: c_int = 0x15; +pub const SIGTTOU: c_int = 0x16; +pub const SIGURG: c_int = 0x17; +pub const SIGUSR1: c_int = 0xa; +pub const SIGUSR2: c_int = 0xc; +pub const SIGVTALRM: c_int = 0x1a; +pub const SIGWINCH: c_int = 0x1c; +pub const SIGXCPU: c_int = 0x18; +pub const SIGXFSZ: c_int = 0x19; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_SETMASK: c_int = 0x2; +pub const SIG_UNBLOCK: c_int = 0x1; +pub const SOCK_DGRAM: c_int = 0x2; +pub const SOCK_NONBLOCK: c_int = 0o0004000; +pub const SOCK_SEQPACKET: c_int = 0x5; +pub const SOCK_STREAM: c_int = 0x1; + +pub const TAB1: c_int = 0x800; +pub const TAB2: c_int = 0x1000; +pub const TAB3: c_int = 0x1800; +pub const TABDLY: c_int = 0x1800; +pub const TCSADRAIN: c_int = 0x1; +pub const TCSAFLUSH: c_int = 0x2; +pub const TCSANOW: c_int = 0; +pub const TOSTOP: crate::tcflag_t = 0x100; +pub const VDISCARD: usize = 0xd; +pub const VEOF: usize = 0x4; +pub const VEOL: usize = 0xb; +pub const VEOL2: usize = 0x10; +pub const VMIN: usize = 0x6; +pub const VREPRINT: usize = 0xc; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VSUSP: usize = 0xa; +pub const VSWTC: usize = 0x7; +pub const VT1: c_int = 0x4000; +pub const VTDLY: c_int = 0x4000; +pub const VTIME: usize = 0x5; +pub const VWERASE: usize = 0xe; +pub const XTABS: crate::tcflag_t = 0x1800; + +pub const MADV_SOFT_OFFLINE: c_int = 101; + +// Syscall table is copied from src/unix/notbsd/linux/musl/b32/arm.rs +pub const SYS_restart_syscall: c_long = 0; +pub const SYS_exit: c_long = 1; +pub const SYS_fork: c_long = 2; +pub const SYS_read: c_long = 3; +pub const SYS_write: c_long = 4; +pub const SYS_open: c_long = 5; +pub const SYS_close: c_long = 6; +pub const SYS_creat: c_long = 8; +pub const SYS_link: c_long = 9; +pub const SYS_unlink: c_long = 10; +pub const SYS_execve: c_long = 11; +pub const SYS_chdir: c_long = 12; +pub const SYS_mknod: c_long = 14; +pub const SYS_chmod: c_long = 15; +pub const SYS_lchown: c_long = 16; +pub const SYS_lseek: c_long = 19; +pub const SYS_getpid: c_long = 20; +pub const SYS_mount: c_long = 21; +pub const SYS_setuid: c_long = 23; +pub const SYS_getuid: c_long = 24; +pub const SYS_ptrace: c_long = 26; +pub const SYS_pause: c_long = 29; +pub const SYS_access: c_long = 33; +pub const SYS_nice: c_long = 34; +pub const SYS_sync: c_long = 36; +pub const SYS_kill: c_long = 37; +pub const SYS_rename: c_long = 38; +pub const SYS_mkdir: c_long = 39; +pub const SYS_rmdir: c_long = 40; +pub const SYS_dup: c_long = 41; +pub const SYS_pipe: c_long = 42; +pub const SYS_times: c_long = 43; +pub const SYS_brk: c_long = 45; +pub const SYS_setgid: c_long = 46; +pub const SYS_getgid: c_long = 47; +pub const SYS_geteuid: c_long = 49; +pub const SYS_getegid: c_long = 50; +pub const SYS_acct: c_long = 51; +pub const SYS_umount2: c_long = 52; +pub const SYS_ioctl: c_long = 54; +pub const SYS_fcntl: c_long = 55; +pub const SYS_setpgid: c_long = 57; +pub const SYS_umask: c_long = 60; +pub const SYS_chroot: c_long = 61; +pub const SYS_ustat: c_long = 62; +pub const SYS_dup2: c_long = 63; +pub const SYS_getppid: c_long = 64; +pub const SYS_getpgrp: c_long = 65; +pub const SYS_setsid: c_long = 66; +pub const SYS_sigaction: c_long = 67; +pub const SYS_setreuid: c_long = 70; +pub const SYS_setregid: c_long = 71; +pub const SYS_sigsuspend: c_long = 72; +pub const SYS_sigpending: c_long = 73; +pub const SYS_sethostname: c_long = 74; +pub const SYS_setrlimit: c_long = 75; +pub const SYS_getrusage: c_long = 77; +pub const SYS_gettimeofday: c_long = 78; +pub const SYS_settimeofday: c_long = 79; +pub const SYS_getgroups: c_long = 80; +pub const SYS_setgroups: c_long = 81; +pub const SYS_symlink: c_long = 83; +pub const SYS_readlink: c_long = 85; +pub const SYS_uselib: c_long = 86; +pub const SYS_swapon: c_long = 87; +pub const SYS_reboot: c_long = 88; +pub const SYS_munmap: c_long = 91; +pub const SYS_truncate: c_long = 92; +pub const SYS_ftruncate: c_long = 93; +pub const SYS_fchmod: c_long = 94; +pub const SYS_fchown: c_long = 95; +pub const SYS_getpriority: c_long = 96; +pub const SYS_setpriority: c_long = 97; +pub const SYS_statfs: c_long = 99; +pub const SYS_fstatfs: c_long = 100; +pub const SYS_syslog: c_long = 103; +pub const SYS_setitimer: c_long = 104; +pub const SYS_getitimer: c_long = 105; +pub const SYS_stat: c_long = 106; +pub const SYS_lstat: c_long = 107; +pub const SYS_fstat: c_long = 108; +pub const SYS_vhangup: c_long = 111; +pub const SYS_wait4: c_long = 114; +pub const SYS_swapoff: c_long = 115; +pub const SYS_sysinfo: c_long = 116; +pub const SYS_fsync: c_long = 118; +pub const SYS_sigreturn: c_long = 119; +pub const SYS_clone: c_long = 120; +pub const SYS_setdomainname: c_long = 121; +pub const SYS_uname: c_long = 122; +pub const SYS_adjtimex: c_long = 124; +pub const SYS_mprotect: c_long = 125; +pub const SYS_sigprocmask: c_long = 126; +pub const SYS_init_module: c_long = 128; +pub const SYS_delete_module: c_long = 129; +pub const SYS_quotactl: c_long = 131; +pub const SYS_getpgid: c_long = 132; +pub const SYS_fchdir: c_long = 133; +pub const SYS_bdflush: c_long = 134; +pub const SYS_sysfs: c_long = 135; +pub const SYS_personality: c_long = 136; +pub const SYS_setfsuid: c_long = 138; +pub const SYS_setfsgid: c_long = 139; +pub const SYS__llseek: c_long = 140; +pub const SYS_getdents: c_long = 141; +pub const SYS__newselect: c_long = 142; +pub const SYS_flock: c_long = 143; +pub const SYS_msync: c_long = 144; +pub const SYS_readv: c_long = 145; +pub const SYS_writev: c_long = 146; +pub const SYS_getsid: c_long = 147; +pub const SYS_fdatasync: c_long = 148; +pub const SYS__sysctl: c_long = 149; +pub const SYS_mlock: c_long = 150; +pub const SYS_munlock: c_long = 151; +pub const SYS_mlockall: c_long = 152; +pub const SYS_munlockall: c_long = 153; +pub const SYS_sched_setparam: c_long = 154; +pub const SYS_sched_getparam: c_long = 155; +pub const SYS_sched_setscheduler: c_long = 156; +pub const SYS_sched_getscheduler: c_long = 157; +pub const SYS_sched_yield: c_long = 158; +pub const SYS_sched_get_priority_max: c_long = 159; +pub const SYS_sched_get_priority_min: c_long = 160; +pub const SYS_sched_rr_get_interval: c_long = 161; +pub const SYS_nanosleep: c_long = 162; +pub const SYS_mremap: c_long = 163; +pub const SYS_setresuid: c_long = 164; +pub const SYS_getresuid: c_long = 165; +pub const SYS_poll: c_long = 168; +pub const SYS_nfsservctl: c_long = 169; +pub const SYS_setresgid: c_long = 170; +pub const SYS_getresgid: c_long = 171; +pub const SYS_prctl: c_long = 172; +pub const SYS_rt_sigreturn: c_long = 173; +pub const SYS_rt_sigaction: c_long = 174; +pub const SYS_rt_sigprocmask: c_long = 175; +pub const SYS_rt_sigpending: c_long = 176; +pub const SYS_rt_sigtimedwait: c_long = 177; +pub const SYS_rt_sigqueueinfo: c_long = 178; +pub const SYS_rt_sigsuspend: c_long = 179; +pub const SYS_pread64: c_long = 180; +pub const SYS_pwrite64: c_long = 181; +pub const SYS_chown: c_long = 182; +pub const SYS_getcwd: c_long = 183; +pub const SYS_capget: c_long = 184; +pub const SYS_capset: c_long = 185; +pub const SYS_sigaltstack: c_long = 186; +pub const SYS_sendfile: c_long = 187; +pub const SYS_vfork: c_long = 190; +pub const SYS_ugetrlimit: c_long = 191; +pub const SYS_mmap2: c_long = 192; +pub const SYS_truncate64: c_long = 193; +pub const SYS_ftruncate64: c_long = 194; +pub const SYS_stat64: c_long = 195; +pub const SYS_lstat64: c_long = 196; +pub const SYS_fstat64: c_long = 197; +pub const SYS_lchown32: c_long = 198; +pub const SYS_getuid32: c_long = 199; +pub const SYS_getgid32: c_long = 200; +pub const SYS_geteuid32: c_long = 201; +pub const SYS_getegid32: c_long = 202; +pub const SYS_setreuid32: c_long = 203; +pub const SYS_setregid32: c_long = 204; +pub const SYS_getgroups32: c_long = 205; +pub const SYS_setgroups32: c_long = 206; +pub const SYS_fchown32: c_long = 207; +pub const SYS_setresuid32: c_long = 208; +pub const SYS_getresuid32: c_long = 209; +pub const SYS_setresgid32: c_long = 210; +pub const SYS_getresgid32: c_long = 211; +pub const SYS_chown32: c_long = 212; +pub const SYS_setuid32: c_long = 213; +pub const SYS_setgid32: c_long = 214; +pub const SYS_setfsuid32: c_long = 215; +pub const SYS_setfsgid32: c_long = 216; +pub const SYS_getdents64: c_long = 217; +pub const SYS_pivot_root: c_long = 218; +pub const SYS_mincore: c_long = 219; +pub const SYS_madvise: c_long = 220; +pub const SYS_fcntl64: c_long = 221; +pub const SYS_gettid: c_long = 224; +pub const SYS_readahead: c_long = 225; +pub const SYS_setxattr: c_long = 226; +pub const SYS_lsetxattr: c_long = 227; +pub const SYS_fsetxattr: c_long = 228; +pub const SYS_getxattr: c_long = 229; +pub const SYS_lgetxattr: c_long = 230; +pub const SYS_fgetxattr: c_long = 231; +pub const SYS_listxattr: c_long = 232; +pub const SYS_llistxattr: c_long = 233; +pub const SYS_flistxattr: c_long = 234; +pub const SYS_removexattr: c_long = 235; +pub const SYS_lremovexattr: c_long = 236; +pub const SYS_fremovexattr: c_long = 237; +pub const SYS_tkill: c_long = 238; +pub const SYS_sendfile64: c_long = 239; +pub const SYS_futex: c_long = 240; +pub const SYS_sched_setaffinity: c_long = 241; +pub const SYS_sched_getaffinity: c_long = 242; +pub const SYS_io_setup: c_long = 243; +pub const SYS_io_destroy: c_long = 244; +pub const SYS_io_getevents: c_long = 245; +pub const SYS_io_submit: c_long = 246; +pub const SYS_io_cancel: c_long = 247; +pub const SYS_exit_group: c_long = 248; +pub const SYS_lookup_dcookie: c_long = 249; +pub const SYS_epoll_create: c_long = 250; +pub const SYS_epoll_ctl: c_long = 251; +pub const SYS_epoll_wait: c_long = 252; +pub const SYS_remap_file_pages: c_long = 253; +pub const SYS_set_tid_address: c_long = 256; +pub const SYS_timer_create: c_long = 257; +pub const SYS_timer_settime: c_long = 258; +pub const SYS_timer_gettime: c_long = 259; +pub const SYS_timer_getoverrun: c_long = 260; +pub const SYS_timer_delete: c_long = 261; +pub const SYS_clock_settime: c_long = 262; +pub const SYS_clock_gettime: c_long = 263; +pub const SYS_clock_getres: c_long = 264; +pub const SYS_clock_nanosleep: c_long = 265; +pub const SYS_statfs64: c_long = 266; +pub const SYS_fstatfs64: c_long = 267; +pub const SYS_tgkill: c_long = 268; +pub const SYS_utimes: c_long = 269; +pub const SYS_pciconfig_iobase: c_long = 271; +pub const SYS_pciconfig_read: c_long = 272; +pub const SYS_pciconfig_write: c_long = 273; +pub const SYS_mq_open: c_long = 274; +pub const SYS_mq_unlink: c_long = 275; +pub const SYS_mq_timedsend: c_long = 276; +pub const SYS_mq_timedreceive: c_long = 277; +pub const SYS_mq_notify: c_long = 278; +pub const SYS_mq_getsetattr: c_long = 279; +pub const SYS_waitid: c_long = 280; +pub const SYS_socket: c_long = 281; +pub const SYS_bind: c_long = 282; +pub const SYS_connect: c_long = 283; +pub const SYS_listen: c_long = 284; +pub const SYS_accept: c_long = 285; +pub const SYS_getsockname: c_long = 286; +pub const SYS_getpeername: c_long = 287; +pub const SYS_socketpair: c_long = 288; +pub const SYS_send: c_long = 289; +pub const SYS_sendto: c_long = 290; +pub const SYS_recv: c_long = 291; +pub const SYS_recvfrom: c_long = 292; +pub const SYS_shutdown: c_long = 293; +pub const SYS_setsockopt: c_long = 294; +pub const SYS_getsockopt: c_long = 295; +pub const SYS_sendmsg: c_long = 296; +pub const SYS_recvmsg: c_long = 297; +pub const SYS_semop: c_long = 298; +pub const SYS_semget: c_long = 299; +pub const SYS_semctl: c_long = 300; +pub const SYS_msgsnd: c_long = 301; +pub const SYS_msgrcv: c_long = 302; +pub const SYS_msgget: c_long = 303; +pub const SYS_msgctl: c_long = 304; +pub const SYS_shmat: c_long = 305; +pub const SYS_shmdt: c_long = 306; +pub const SYS_shmget: c_long = 307; +pub const SYS_shmctl: c_long = 308; +pub const SYS_add_key: c_long = 309; +pub const SYS_request_key: c_long = 310; +pub const SYS_keyctl: c_long = 311; +pub const SYS_semtimedop: c_long = 312; +pub const SYS_vserver: c_long = 313; +pub const SYS_ioprio_set: c_long = 314; +pub const SYS_ioprio_get: c_long = 315; +pub const SYS_inotify_init: c_long = 316; +pub const SYS_inotify_add_watch: c_long = 317; +pub const SYS_inotify_rm_watch: c_long = 318; +pub const SYS_mbind: c_long = 319; +pub const SYS_get_mempolicy: c_long = 320; +pub const SYS_set_mempolicy: c_long = 321; +pub const SYS_openat: c_long = 322; +pub const SYS_mkdirat: c_long = 323; +pub const SYS_mknodat: c_long = 324; +pub const SYS_fchownat: c_long = 325; +pub const SYS_futimesat: c_long = 326; +pub const SYS_fstatat64: c_long = 327; +pub const SYS_unlinkat: c_long = 328; +pub const SYS_renameat: c_long = 329; +pub const SYS_linkat: c_long = 330; +pub const SYS_symlinkat: c_long = 331; +pub const SYS_readlinkat: c_long = 332; +pub const SYS_fchmodat: c_long = 333; +pub const SYS_faccessat: c_long = 334; +pub const SYS_pselect6: c_long = 335; +pub const SYS_ppoll: c_long = 336; +pub const SYS_unshare: c_long = 337; +pub const SYS_set_robust_list: c_long = 338; +pub const SYS_get_robust_list: c_long = 339; +pub const SYS_splice: c_long = 340; +pub const SYS_tee: c_long = 342; +pub const SYS_vmsplice: c_long = 343; +pub const SYS_move_pages: c_long = 344; +pub const SYS_getcpu: c_long = 345; +pub const SYS_epoll_pwait: c_long = 346; +pub const SYS_kexec_load: c_long = 347; +pub const SYS_utimensat: c_long = 348; +pub const SYS_signalfd: c_long = 349; +pub const SYS_timerfd_create: c_long = 350; +pub const SYS_eventfd: c_long = 351; +pub const SYS_fallocate: c_long = 352; +pub const SYS_timerfd_settime: c_long = 353; +pub const SYS_timerfd_gettime: c_long = 354; +pub const SYS_signalfd4: c_long = 355; +pub const SYS_eventfd2: c_long = 356; +pub const SYS_epoll_create1: c_long = 357; +pub const SYS_dup3: c_long = 358; +pub const SYS_pipe2: c_long = 359; +pub const SYS_inotify_init1: c_long = 360; +pub const SYS_preadv: c_long = 361; +pub const SYS_pwritev: c_long = 362; +pub const SYS_rt_tgsigqueueinfo: c_long = 363; +pub const SYS_perf_event_open: c_long = 364; +pub const SYS_recvmmsg: c_long = 365; +pub const SYS_accept4: c_long = 366; +pub const SYS_fanotify_init: c_long = 367; +pub const SYS_fanotify_mark: c_long = 368; +pub const SYS_prlimit64: c_long = 369; +pub const SYS_name_to_handle_at: c_long = 370; +pub const SYS_open_by_handle_at: c_long = 371; +pub const SYS_clock_adjtime: c_long = 372; +pub const SYS_syncfs: c_long = 373; +pub const SYS_sendmmsg: c_long = 374; +pub const SYS_setns: c_long = 375; +pub const SYS_process_vm_readv: c_long = 376; +pub const SYS_process_vm_writev: c_long = 377; +pub const SYS_kcmp: c_long = 378; +pub const SYS_finit_module: c_long = 379; +pub const SYS_sched_setattr: c_long = 380; +pub const SYS_sched_getattr: c_long = 381; +pub const SYS_renameat2: c_long = 382; +pub const SYS_seccomp: c_long = 383; +pub const SYS_getrandom: c_long = 384; +pub const SYS_memfd_create: c_long = 385; +pub const SYS_bpf: c_long = 386; +pub const SYS_execveat: c_long = 387; +pub const SYS_userfaultfd: c_long = 388; +pub const SYS_membarrier: c_long = 389; +pub const SYS_mlock2: c_long = 390; +pub const SYS_copy_file_range: c_long = 391; +pub const SYS_preadv2: c_long = 392; +pub const SYS_pwritev2: c_long = 393; +pub const SYS_pkey_mprotect: c_long = 394; +pub const SYS_pkey_alloc: c_long = 395; +pub const SYS_pkey_free: c_long = 396; +// FIXME(linux): should be a `c_long` too, but a bug slipped in. +pub const SYS_statx: c_int = 397; +pub const SYS_pidfd_send_signal: c_long = 424; +pub const SYS_io_uring_setup: c_long = 425; +pub const SYS_io_uring_enter: c_long = 426; +pub const SYS_io_uring_register: c_long = 427; +pub const SYS_open_tree: c_long = 428; +pub const SYS_move_mount: c_long = 429; +pub const SYS_fsopen: c_long = 430; +pub const SYS_fsconfig: c_long = 431; +pub const SYS_fsmount: c_long = 432; +pub const SYS_fspick: c_long = 433; +pub const SYS_pidfd_open: c_long = 434; +pub const SYS_clone3: c_long = 435; +pub const SYS_close_range: c_long = 436; +pub const SYS_openat2: c_long = 437; +pub const SYS_pidfd_getfd: c_long = 438; +pub const SYS_faccessat2: c_long = 439; +pub const SYS_process_madvise: c_long = 440; +pub const SYS_epoll_pwait2: c_long = 441; +pub const SYS_mount_setattr: c_long = 442; +pub const SYS_quotactl_fd: c_long = 443; +pub const SYS_landlock_create_ruleset: c_long = 444; +pub const SYS_landlock_add_rule: c_long = 445; +pub const SYS_landlock_restrict_self: c_long = 446; +pub const SYS_memfd_secret: c_long = 447; +pub const SYS_process_mrelease: c_long = 448; +pub const SYS_futex_waitv: c_long = 449; +pub const SYS_set_mempolicy_home_node: c_long = 450; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs new file mode 100644 index 00000000000000..93ed7ab213335d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs @@ -0,0 +1,695 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type clock_t = i32; +pub type time_t = i32; +pub type suseconds_t = i32; +pub type wchar_t = i32; +pub type off_t = i32; +pub type ino_t = u32; +pub type blkcnt_t = i32; +pub type blksize_t = i32; +pub type nlink_t = u32; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; +pub type fsblkcnt64_t = u64; +pub type fsfilcnt64_t = u64; + +s! { + pub struct stat { + pub st_dev: crate::dev_t, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_pad2: [c_long; 1], + pub st_size: off_t, + st_pad3: Padding, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + st_pad5: Padding<[c_long; 14]>, + } + + pub struct stat64 { + pub st_dev: crate::dev_t, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + st_pad2: Padding<[c_long; 2]>, + pub st_size: off64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + st_pad3: Padding, + pub st_blocks: crate::blkcnt64_t, + st_pad5: Padding<[c_long; 14]>, + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_favail: crate::fsfilcnt64_t, + pub f_fsid: c_ulong, + pub __f_unused: c_int, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub __f_spare: [c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u32; 9], + } + + pub struct sigaction { + pub sa_flags: c_uint, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: sigset_t, + _restorer: *mut c_void, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct sigset_t { + __val: [c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + pub _pad: [c_int; 29], + } + + pub struct glob64_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + #[cfg(target_endian = "big")] + __glibc_reserved1: Padding, + pub msg_stime: crate::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved1: Padding, + #[cfg(target_endian = "big")] + __glibc_reserved2: Padding, + pub msg_rtime: crate::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved2: Padding, + #[cfg(target_endian = "big")] + __glibc_reserved3: Padding, + pub msg_ctime: crate::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved3: Padding, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsblkcnt_t, + pub f_ffree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: c_long, + f_spare: [c_long; 6], + } + + pub struct statfs64 { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_files: crate::fsblkcnt64_t, + pub f_ffree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_long, + pub f_flags: c_long, + pub f_spare: [c_long; 5], + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_sysid: c_long, + pub l_pid: crate::pid_t, + pad: Padding<[c_long; 4]>, + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 8], + } + + // FIXME(1.0): this is actually a union + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [c_char; 32], + } +} + +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 36; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; + +pub const SYS_syscall: c_long = 4000 + 0; +pub const SYS_exit: c_long = 4000 + 1; +pub const SYS_fork: c_long = 4000 + 2; +pub const SYS_read: c_long = 4000 + 3; +pub const SYS_write: c_long = 4000 + 4; +pub const SYS_open: c_long = 4000 + 5; +pub const SYS_close: c_long = 4000 + 6; +pub const SYS_waitpid: c_long = 4000 + 7; +pub const SYS_creat: c_long = 4000 + 8; +pub const SYS_link: c_long = 4000 + 9; +pub const SYS_unlink: c_long = 4000 + 10; +pub const SYS_execve: c_long = 4000 + 11; +pub const SYS_chdir: c_long = 4000 + 12; +pub const SYS_time: c_long = 4000 + 13; +pub const SYS_mknod: c_long = 4000 + 14; +pub const SYS_chmod: c_long = 4000 + 15; +pub const SYS_lchown: c_long = 4000 + 16; +pub const SYS_break: c_long = 4000 + 17; +pub const SYS_lseek: c_long = 4000 + 19; +pub const SYS_getpid: c_long = 4000 + 20; +pub const SYS_mount: c_long = 4000 + 21; +pub const SYS_umount: c_long = 4000 + 22; +pub const SYS_setuid: c_long = 4000 + 23; +pub const SYS_getuid: c_long = 4000 + 24; +pub const SYS_stime: c_long = 4000 + 25; +pub const SYS_ptrace: c_long = 4000 + 26; +pub const SYS_alarm: c_long = 4000 + 27; +pub const SYS_pause: c_long = 4000 + 29; +pub const SYS_utime: c_long = 4000 + 30; +pub const SYS_stty: c_long = 4000 + 31; +pub const SYS_gtty: c_long = 4000 + 32; +pub const SYS_access: c_long = 4000 + 33; +pub const SYS_nice: c_long = 4000 + 34; +pub const SYS_ftime: c_long = 4000 + 35; +pub const SYS_sync: c_long = 4000 + 36; +pub const SYS_kill: c_long = 4000 + 37; +pub const SYS_rename: c_long = 4000 + 38; +pub const SYS_mkdir: c_long = 4000 + 39; +pub const SYS_rmdir: c_long = 4000 + 40; +pub const SYS_dup: c_long = 4000 + 41; +pub const SYS_pipe: c_long = 4000 + 42; +pub const SYS_times: c_long = 4000 + 43; +pub const SYS_prof: c_long = 4000 + 44; +pub const SYS_brk: c_long = 4000 + 45; +pub const SYS_setgid: c_long = 4000 + 46; +pub const SYS_getgid: c_long = 4000 + 47; +pub const SYS_signal: c_long = 4000 + 48; +pub const SYS_geteuid: c_long = 4000 + 49; +pub const SYS_getegid: c_long = 4000 + 50; +pub const SYS_acct: c_long = 4000 + 51; +pub const SYS_umount2: c_long = 4000 + 52; +pub const SYS_lock: c_long = 4000 + 53; +pub const SYS_ioctl: c_long = 4000 + 54; +pub const SYS_fcntl: c_long = 4000 + 55; +pub const SYS_mpx: c_long = 4000 + 56; +pub const SYS_setpgid: c_long = 4000 + 57; +pub const SYS_ulimit: c_long = 4000 + 58; +pub const SYS_umask: c_long = 4000 + 60; +pub const SYS_chroot: c_long = 4000 + 61; +pub const SYS_ustat: c_long = 4000 + 62; +pub const SYS_dup2: c_long = 4000 + 63; +pub const SYS_getppid: c_long = 4000 + 64; +pub const SYS_getpgrp: c_long = 4000 + 65; +pub const SYS_setsid: c_long = 4000 + 66; +pub const SYS_sigaction: c_long = 4000 + 67; +pub const SYS_sgetmask: c_long = 4000 + 68; +pub const SYS_ssetmask: c_long = 4000 + 69; +pub const SYS_setreuid: c_long = 4000 + 70; +pub const SYS_setregid: c_long = 4000 + 71; +pub const SYS_sigsuspend: c_long = 4000 + 72; +pub const SYS_sigpending: c_long = 4000 + 73; +pub const SYS_sethostname: c_long = 4000 + 74; +pub const SYS_setrlimit: c_long = 4000 + 75; +pub const SYS_getrlimit: c_long = 4000 + 76; +pub const SYS_getrusage: c_long = 4000 + 77; +pub const SYS_gettimeofday: c_long = 4000 + 78; +pub const SYS_settimeofday: c_long = 4000 + 79; +pub const SYS_getgroups: c_long = 4000 + 80; +pub const SYS_setgroups: c_long = 4000 + 81; +pub const SYS_symlink: c_long = 4000 + 83; +pub const SYS_readlink: c_long = 4000 + 85; +pub const SYS_uselib: c_long = 4000 + 86; +pub const SYS_swapon: c_long = 4000 + 87; +pub const SYS_reboot: c_long = 4000 + 88; +pub const SYS_readdir: c_long = 4000 + 89; +pub const SYS_mmap: c_long = 4000 + 90; +pub const SYS_munmap: c_long = 4000 + 91; +pub const SYS_truncate: c_long = 4000 + 92; +pub const SYS_ftruncate: c_long = 4000 + 93; +pub const SYS_fchmod: c_long = 4000 + 94; +pub const SYS_fchown: c_long = 4000 + 95; +pub const SYS_getpriority: c_long = 4000 + 96; +pub const SYS_setpriority: c_long = 4000 + 97; +pub const SYS_profil: c_long = 4000 + 98; +pub const SYS_statfs: c_long = 4000 + 99; +pub const SYS_fstatfs: c_long = 4000 + 100; +pub const SYS_ioperm: c_long = 4000 + 101; +pub const SYS_socketcall: c_long = 4000 + 102; +pub const SYS_syslog: c_long = 4000 + 103; +pub const SYS_setitimer: c_long = 4000 + 104; +pub const SYS_getitimer: c_long = 4000 + 105; +pub const SYS_stat: c_long = 4000 + 106; +pub const SYS_lstat: c_long = 4000 + 107; +pub const SYS_fstat: c_long = 4000 + 108; +pub const SYS_iopl: c_long = 4000 + 110; +pub const SYS_vhangup: c_long = 4000 + 111; +pub const SYS_idle: c_long = 4000 + 112; +pub const SYS_vm86: c_long = 4000 + 113; +pub const SYS_wait4: c_long = 4000 + 114; +pub const SYS_swapoff: c_long = 4000 + 115; +pub const SYS_sysinfo: c_long = 4000 + 116; +pub const SYS_ipc: c_long = 4000 + 117; +pub const SYS_fsync: c_long = 4000 + 118; +pub const SYS_sigreturn: c_long = 4000 + 119; +pub const SYS_clone: c_long = 4000 + 120; +pub const SYS_setdomainname: c_long = 4000 + 121; +pub const SYS_uname: c_long = 4000 + 122; +pub const SYS_modify_ldt: c_long = 4000 + 123; +pub const SYS_adjtimex: c_long = 4000 + 124; +pub const SYS_mprotect: c_long = 4000 + 125; +pub const SYS_sigprocmask: c_long = 4000 + 126; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_create_module: c_long = 4000 + 127; +pub const SYS_init_module: c_long = 4000 + 128; +pub const SYS_delete_module: c_long = 4000 + 129; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_get_kernel_syms: c_long = 4000 + 130; +pub const SYS_quotactl: c_long = 4000 + 131; +pub const SYS_getpgid: c_long = 4000 + 132; +pub const SYS_fchdir: c_long = 4000 + 133; +pub const SYS_bdflush: c_long = 4000 + 134; +pub const SYS_sysfs: c_long = 4000 + 135; +pub const SYS_personality: c_long = 4000 + 136; +pub const SYS_afs_syscall: c_long = 4000 + 137; +pub const SYS_setfsuid: c_long = 4000 + 138; +pub const SYS_setfsgid: c_long = 4000 + 139; +pub const SYS__llseek: c_long = 4000 + 140; +pub const SYS_getdents: c_long = 4000 + 141; +pub const SYS__newselect: c_long = 4000 + 142; +pub const SYS_flock: c_long = 4000 + 143; +pub const SYS_msync: c_long = 4000 + 144; +pub const SYS_readv: c_long = 4000 + 145; +pub const SYS_writev: c_long = 4000 + 146; +pub const SYS_cacheflush: c_long = 4000 + 147; +pub const SYS_cachectl: c_long = 4000 + 148; +pub const SYS_sysmips: c_long = 4000 + 149; +pub const SYS_getsid: c_long = 4000 + 151; +pub const SYS_fdatasync: c_long = 4000 + 152; +pub const SYS__sysctl: c_long = 4000 + 153; +pub const SYS_mlock: c_long = 4000 + 154; +pub const SYS_munlock: c_long = 4000 + 155; +pub const SYS_mlockall: c_long = 4000 + 156; +pub const SYS_munlockall: c_long = 4000 + 157; +pub const SYS_sched_setparam: c_long = 4000 + 158; +pub const SYS_sched_getparam: c_long = 4000 + 159; +pub const SYS_sched_setscheduler: c_long = 4000 + 160; +pub const SYS_sched_getscheduler: c_long = 4000 + 161; +pub const SYS_sched_yield: c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: c_long = 4000 + 165; +pub const SYS_nanosleep: c_long = 4000 + 166; +pub const SYS_mremap: c_long = 4000 + 167; +pub const SYS_accept: c_long = 4000 + 168; +pub const SYS_bind: c_long = 4000 + 169; +pub const SYS_connect: c_long = 4000 + 170; +pub const SYS_getpeername: c_long = 4000 + 171; +pub const SYS_getsockname: c_long = 4000 + 172; +pub const SYS_getsockopt: c_long = 4000 + 173; +pub const SYS_listen: c_long = 4000 + 174; +pub const SYS_recv: c_long = 4000 + 175; +pub const SYS_recvfrom: c_long = 4000 + 176; +pub const SYS_recvmsg: c_long = 4000 + 177; +pub const SYS_send: c_long = 4000 + 178; +pub const SYS_sendmsg: c_long = 4000 + 179; +pub const SYS_sendto: c_long = 4000 + 180; +pub const SYS_setsockopt: c_long = 4000 + 181; +pub const SYS_shutdown: c_long = 4000 + 182; +pub const SYS_socket: c_long = 4000 + 183; +pub const SYS_socketpair: c_long = 4000 + 184; +pub const SYS_setresuid: c_long = 4000 + 185; +pub const SYS_getresuid: c_long = 4000 + 186; +#[deprecated(since = "0.2.70", note = "Functional up to 2.6 kernel")] +pub const SYS_query_module: c_long = 4000 + 187; +pub const SYS_poll: c_long = 4000 + 188; +pub const SYS_nfsservctl: c_long = 4000 + 189; +pub const SYS_setresgid: c_long = 4000 + 190; +pub const SYS_getresgid: c_long = 4000 + 191; +pub const SYS_prctl: c_long = 4000 + 192; +pub const SYS_rt_sigreturn: c_long = 4000 + 193; +pub const SYS_rt_sigaction: c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: c_long = 4000 + 195; +pub const SYS_rt_sigpending: c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: c_long = 4000 + 199; +pub const SYS_pread64: c_long = 4000 + 200; +pub const SYS_pwrite64: c_long = 4000 + 201; +pub const SYS_chown: c_long = 4000 + 202; +pub const SYS_getcwd: c_long = 4000 + 203; +pub const SYS_capget: c_long = 4000 + 204; +pub const SYS_capset: c_long = 4000 + 205; +pub const SYS_sigaltstack: c_long = 4000 + 206; +pub const SYS_sendfile: c_long = 4000 + 207; +pub const SYS_getpmsg: c_long = 4000 + 208; +pub const SYS_putpmsg: c_long = 4000 + 209; +pub const SYS_mmap2: c_long = 4000 + 210; +pub const SYS_truncate64: c_long = 4000 + 211; +pub const SYS_ftruncate64: c_long = 4000 + 212; +pub const SYS_stat64: c_long = 4000 + 213; +pub const SYS_lstat64: c_long = 4000 + 214; +pub const SYS_fstat64: c_long = 4000 + 215; +pub const SYS_pivot_root: c_long = 4000 + 216; +pub const SYS_mincore: c_long = 4000 + 217; +pub const SYS_madvise: c_long = 4000 + 218; +pub const SYS_getdents64: c_long = 4000 + 219; +pub const SYS_fcntl64: c_long = 4000 + 220; +pub const SYS_gettid: c_long = 4000 + 222; +pub const SYS_readahead: c_long = 4000 + 223; +pub const SYS_setxattr: c_long = 4000 + 224; +pub const SYS_lsetxattr: c_long = 4000 + 225; +pub const SYS_fsetxattr: c_long = 4000 + 226; +pub const SYS_getxattr: c_long = 4000 + 227; +pub const SYS_lgetxattr: c_long = 4000 + 228; +pub const SYS_fgetxattr: c_long = 4000 + 229; +pub const SYS_listxattr: c_long = 4000 + 230; +pub const SYS_llistxattr: c_long = 4000 + 231; +pub const SYS_flistxattr: c_long = 4000 + 232; +pub const SYS_removexattr: c_long = 4000 + 233; +pub const SYS_lremovexattr: c_long = 4000 + 234; +pub const SYS_fremovexattr: c_long = 4000 + 235; +pub const SYS_tkill: c_long = 4000 + 236; +pub const SYS_sendfile64: c_long = 4000 + 237; +pub const SYS_futex: c_long = 4000 + 238; +pub const SYS_sched_setaffinity: c_long = 4000 + 239; +pub const SYS_sched_getaffinity: c_long = 4000 + 240; +pub const SYS_io_setup: c_long = 4000 + 241; +pub const SYS_io_destroy: c_long = 4000 + 242; +pub const SYS_io_getevents: c_long = 4000 + 243; +pub const SYS_io_submit: c_long = 4000 + 244; +pub const SYS_io_cancel: c_long = 4000 + 245; +pub const SYS_exit_group: c_long = 4000 + 246; +pub const SYS_lookup_dcookie: c_long = 4000 + 247; +pub const SYS_epoll_create: c_long = 4000 + 248; +pub const SYS_epoll_ctl: c_long = 4000 + 249; +pub const SYS_epoll_wait: c_long = 4000 + 250; +pub const SYS_remap_file_pages: c_long = 4000 + 251; +pub const SYS_set_tid_address: c_long = 4000 + 252; +pub const SYS_restart_syscall: c_long = 4000 + 253; +pub const SYS_fadvise64: c_long = 4000 + 254; +pub const SYS_statfs64: c_long = 4000 + 255; +pub const SYS_fstatfs64: c_long = 4000 + 256; +pub const SYS_timer_create: c_long = 4000 + 257; +pub const SYS_timer_settime: c_long = 4000 + 258; +pub const SYS_timer_gettime: c_long = 4000 + 259; +pub const SYS_timer_getoverrun: c_long = 4000 + 260; +pub const SYS_timer_delete: c_long = 4000 + 261; +pub const SYS_clock_settime: c_long = 4000 + 262; +pub const SYS_clock_gettime: c_long = 4000 + 263; +pub const SYS_clock_getres: c_long = 4000 + 264; +pub const SYS_clock_nanosleep: c_long = 4000 + 265; +pub const SYS_tgkill: c_long = 4000 + 266; +pub const SYS_utimes: c_long = 4000 + 267; +pub const SYS_mbind: c_long = 4000 + 268; +pub const SYS_get_mempolicy: c_long = 4000 + 269; +pub const SYS_set_mempolicy: c_long = 4000 + 270; +pub const SYS_mq_open: c_long = 4000 + 271; +pub const SYS_mq_unlink: c_long = 4000 + 272; +pub const SYS_mq_timedsend: c_long = 4000 + 273; +pub const SYS_mq_timedreceive: c_long = 4000 + 274; +pub const SYS_mq_notify: c_long = 4000 + 275; +pub const SYS_mq_getsetattr: c_long = 4000 + 276; +pub const SYS_vserver: c_long = 4000 + 277; +pub const SYS_waitid: c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: c_long = 4000 + 279; */ +pub const SYS_add_key: c_long = 4000 + 280; +pub const SYS_request_key: c_long = 4000 + 281; +pub const SYS_keyctl: c_long = 4000 + 282; +pub const SYS_set_thread_area: c_long = 4000 + 283; +pub const SYS_inotify_init: c_long = 4000 + 284; +pub const SYS_inotify_add_watch: c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: c_long = 4000 + 286; +pub const SYS_migrate_pages: c_long = 4000 + 287; +pub const SYS_openat: c_long = 4000 + 288; +pub const SYS_mkdirat: c_long = 4000 + 289; +pub const SYS_mknodat: c_long = 4000 + 290; +pub const SYS_fchownat: c_long = 4000 + 291; +pub const SYS_futimesat: c_long = 4000 + 292; +pub const SYS_fstatat64: c_long = 4000 + 293; +pub const SYS_unlinkat: c_long = 4000 + 294; +pub const SYS_renameat: c_long = 4000 + 295; +pub const SYS_linkat: c_long = 4000 + 296; +pub const SYS_symlinkat: c_long = 4000 + 297; +pub const SYS_readlinkat: c_long = 4000 + 298; +pub const SYS_fchmodat: c_long = 4000 + 299; +pub const SYS_faccessat: c_long = 4000 + 300; +pub const SYS_pselect6: c_long = 4000 + 301; +pub const SYS_ppoll: c_long = 4000 + 302; +pub const SYS_unshare: c_long = 4000 + 303; +pub const SYS_splice: c_long = 4000 + 304; +pub const SYS_sync_file_range: c_long = 4000 + 305; +pub const SYS_tee: c_long = 4000 + 306; +pub const SYS_vmsplice: c_long = 4000 + 307; +pub const SYS_move_pages: c_long = 4000 + 308; +pub const SYS_set_robust_list: c_long = 4000 + 309; +pub const SYS_get_robust_list: c_long = 4000 + 310; +pub const SYS_kexec_load: c_long = 4000 + 311; +pub const SYS_getcpu: c_long = 4000 + 312; +pub const SYS_epoll_pwait: c_long = 4000 + 313; +pub const SYS_ioprio_set: c_long = 4000 + 314; +pub const SYS_ioprio_get: c_long = 4000 + 315; +pub const SYS_utimensat: c_long = 4000 + 316; +pub const SYS_signalfd: c_long = 4000 + 317; +pub const SYS_timerfd: c_long = 4000 + 318; +pub const SYS_eventfd: c_long = 4000 + 319; +pub const SYS_fallocate: c_long = 4000 + 320; +pub const SYS_timerfd_create: c_long = 4000 + 321; +pub const SYS_timerfd_gettime: c_long = 4000 + 322; +pub const SYS_timerfd_settime: c_long = 4000 + 323; +pub const SYS_signalfd4: c_long = 4000 + 324; +pub const SYS_eventfd2: c_long = 4000 + 325; +pub const SYS_epoll_create1: c_long = 4000 + 326; +pub const SYS_dup3: c_long = 4000 + 327; +pub const SYS_pipe2: c_long = 4000 + 328; +pub const SYS_inotify_init1: c_long = 4000 + 329; +pub const SYS_preadv: c_long = 4000 + 330; +pub const SYS_pwritev: c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: c_long = 4000 + 332; +pub const SYS_perf_event_open: c_long = 4000 + 333; +pub const SYS_accept4: c_long = 4000 + 334; +pub const SYS_recvmmsg: c_long = 4000 + 335; +pub const SYS_fanotify_init: c_long = 4000 + 336; +pub const SYS_fanotify_mark: c_long = 4000 + 337; +pub const SYS_prlimit64: c_long = 4000 + 338; +pub const SYS_name_to_handle_at: c_long = 4000 + 339; +pub const SYS_open_by_handle_at: c_long = 4000 + 340; +pub const SYS_clock_adjtime: c_long = 4000 + 341; +pub const SYS_syncfs: c_long = 4000 + 342; +pub const SYS_sendmmsg: c_long = 4000 + 343; +pub const SYS_setns: c_long = 4000 + 344; +pub const SYS_process_vm_readv: c_long = 4000 + 345; +pub const SYS_process_vm_writev: c_long = 4000 + 346; +pub const SYS_kcmp: c_long = 4000 + 347; +pub const SYS_finit_module: c_long = 4000 + 348; +pub const SYS_sched_setattr: c_long = 4000 + 349; +pub const SYS_sched_getattr: c_long = 4000 + 350; +pub const SYS_renameat2: c_long = 4000 + 351; +pub const SYS_seccomp: c_long = 4000 + 352; +pub const SYS_getrandom: c_long = 4000 + 353; +pub const SYS_memfd_create: c_long = 4000 + 354; +pub const SYS_bpf: c_long = 4000 + 355; +pub const SYS_execveat: c_long = 4000 + 356; +pub const SYS_userfaultfd: c_long = 4000 + 357; +pub const SYS_membarrier: c_long = 4000 + 358; +pub const SYS_mlock2: c_long = 4000 + 359; +pub const SYS_copy_file_range: c_long = 4000 + 360; +pub const SYS_preadv2: c_long = 4000 + 361; +pub const SYS_pwritev2: c_long = 4000 + 362; +pub const SYS_pkey_mprotect: c_long = 4000 + 363; +pub const SYS_pkey_alloc: c_long = 4000 + 364; +pub const SYS_pkey_free: c_long = 4000 + 365; +pub const SYS_statx: c_long = 4000 + 366; +pub const SYS_pidfd_send_signal: c_long = 4000 + 424; +pub const SYS_io_uring_setup: c_long = 4000 + 425; +pub const SYS_io_uring_enter: c_long = 4000 + 426; +pub const SYS_io_uring_register: c_long = 4000 + 427; +pub const SYS_open_tree: c_long = 4000 + 428; +pub const SYS_move_mount: c_long = 4000 + 429; +pub const SYS_fsopen: c_long = 4000 + 430; +pub const SYS_fsconfig: c_long = 4000 + 431; +pub const SYS_fsmount: c_long = 4000 + 432; +pub const SYS_fspick: c_long = 4000 + 433; +pub const SYS_pidfd_open: c_long = 4000 + 434; +pub const SYS_clone3: c_long = 4000 + 435; +pub const SYS_close_range: c_long = 4000 + 436; +pub const SYS_openat2: c_long = 4000 + 437; +pub const SYS_pidfd_getfd: c_long = 4000 + 438; +pub const SYS_faccessat2: c_long = 4000 + 439; +pub const SYS_process_madvise: c_long = 4000 + 440; +pub const SYS_epoll_pwait2: c_long = 4000 + 441; +pub const SYS_mount_setattr: c_long = 4000 + 442; +pub const SYS_quotactl_fd: c_long = 4000 + 443; +pub const SYS_landlock_create_ruleset: c_long = 4000 + 444; +pub const SYS_landlock_add_rule: c_long = 4000 + 445; +pub const SYS_landlock_restrict_self: c_long = 4000 + 446; +pub const SYS_memfd_secret: c_long = 4000 + 447; +pub const SYS_process_mrelease: c_long = 4000 + 448; +pub const SYS_futex_waitv: c_long = 4000 + 449; +pub const SYS_set_mempolicy_home_node: c_long = 4000 + 450; + +#[link(name = "util")] +extern "C" { + pub fn sysctl( + name: *mut c_int, + namelen: c_int, + oldp: *mut c_void, + oldlenp: *mut size_t, + newp: *mut c_void, + newlen: size_t, + ) -> c_int; + pub fn glob64( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut glob64_t, + ) -> c_int; + pub fn globfree64(pglob: *mut glob64_t); + pub fn pthread_attr_getaffinity_np( + attr: *const crate::pthread_attr_t, + cpusetsize: size_t, + cpuset: *mut crate::cpu_set_t, + ) -> c_int; + pub fn pthread_attr_setaffinity_np( + attr: *mut crate::pthread_attr_t, + cpusetsize: size_t, + cpuset: *const crate::cpu_set_t, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs new file mode 100644 index 00000000000000..4495181400d489 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs @@ -0,0 +1,204 @@ +use crate::off64_t; +use crate::prelude::*; + +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = u64; +pub type nlink_t = u64; +pub type off_t = i64; +pub type suseconds_t = i64; +pub type time_t = i64; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: c_ulong, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + st_pad2: Padding<[c_ulong; 1]>, + pub st_size: off_t, + st_pad3: Padding, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + st_pad4: Padding, + pub st_blocks: crate::blkcnt_t, + st_pad5: Padding<[c_long; 7]>, + } + + pub struct stat64 { + pub st_dev: c_ulong, + st_pad1: Padding<[c_long; 2]>, + pub st_ino: crate::ino64_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, + st_pad2: Padding<[c_long; 2]>, + pub st_size: off64_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + st_pad3: Padding, + pub st_blocks: crate::blkcnt64_t, + st_pad5: Padding<[c_long; 7]>, + } + + pub struct pthread_attr_t { + __size: [c_ulong; 7], + } + + pub struct sigaction { + pub sa_flags: c_int, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: sigset_t, + _restorer: *mut c_void, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct sigset_t { + __size: [c_ulong; 16], + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + _pad: Padding, + _pad2: Padding<[c_long; 14]>, + } + + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_uint, + pub __seq: c_ushort, + __pad1: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused4: Padding, + __unused5: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __glibc_reserved4: Padding, + __glibc_reserved5: Padding, + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_frsize: c_long, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_files: crate::fsblkcnt_t, + pub f_ffree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_fsid: crate::fsid_t, + + pub f_namelen: c_long, + f_spare: [c_long; 6], + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: size_t, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct sysinfo { + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 0], + } + + // FIXME(1.0): this is actually a union + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct sem_t { + __size: [c_char; 32], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + +pub const SYS_gettid: c_long = 5178; // Valid for n64 diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mod.rs new file mode 100644 index 00000000000000..8d17aa8e98e9aa --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mips/mod.rs @@ -0,0 +1,312 @@ +use crate::prelude::*; + +pub type pthread_t = c_ulong; + +pub const SFD_CLOEXEC: c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: c_int = 512; + +pub const O_CLOEXEC: c_int = 0x80000; + +pub const EBFONT: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EDOTDOT: c_int = 73; + +pub const SA_NODEFER: c_uint = 0x40000000; +pub const SA_RESETHAND: c_uint = 0x80000000; +pub const SA_RESTART: c_uint = 0x10000000; +pub const SA_NOCLDSTOP: c_uint = 0x00000001; + +pub const EPOLL_CLOEXEC: c_int = 0x80000; + +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const TMP_MAX: c_uint = 238328; +pub const _SC_2_C_VERSION: c_int = 96; +pub const O_ACCMODE: c_int = 3; +pub const O_DIRECT: c_int = 0x8000; +pub const O_DIRECTORY: c_int = 0x10000; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_NOATIME: c_int = 0x40000; +pub const O_PATH: c_int = 0o010000000; + +pub const O_APPEND: c_int = 8; +pub const O_CREAT: c_int = 256; +pub const O_EXCL: c_int = 1024; +pub const O_NOCTTY: c_int = 2048; +pub const O_NONBLOCK: c_int = 128; +pub const O_SYNC: c_int = 0x10; +pub const O_RSYNC: c_int = 0x10; +pub const O_DSYNC: c_int = 0x10; +pub const O_FSYNC: c_int = 0x10; +pub const O_ASYNC: c_int = 0x1000; +pub const O_LARGEFILE: c_int = 0x2000; +pub const O_NDELAY: c_int = 0x80; + +pub const SOCK_NONBLOCK: c_int = 128; + +pub const EDEADLK: c_int = 45; +pub const ENAMETOOLONG: c_int = 78; +pub const ENOLCK: c_int = 46; +pub const ENOSYS: c_int = 89; +pub const ENOTEMPTY: c_int = 93; +pub const ELOOP: c_int = 90; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const FFDLY: c_int = 0o0100000; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EMULTIHOP: c_int = 74; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EBADMSG: c_int = 77; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; +pub const EUCLEAN: c_int = 135; +pub const ENOTNAM: c_int = 137; +pub const ENAVAIL: c_int = 138; +pub const EISNAM: c_int = 139; +pub const EREMOTEIO: c_int = 140; +pub const EDQUOT: c_int = 1133; +pub const ENOMEDIUM: c_int = 159; +pub const EMEDIUMTYPE: c_int = 160; +pub const ECANCELED: c_int = 158; +pub const ENOKEY: c_int = 161; +pub const EKEYEXPIRED: c_int = 162; +pub const EKEYREVOKED: c_int = 163; +pub const EKEYREJECTED: c_int = 164; +pub const EOWNERDEAD: c_int = 165; +pub const ENOTRECOVERABLE: c_int = 166; +pub const ERFKILL: c_int = 167; + +pub const MAP_NORESERVE: c_int = 0x400; +pub const MAP_ANON: c_int = 0x800; +pub const MAP_ANONYMOUS: c_int = 0x800; +pub const MAP_GROWSDOWN: c_int = 0x1000; +pub const MAP_DENYWRITE: c_int = 0x2000; +pub const MAP_EXECUTABLE: c_int = 0x4000; +pub const MAP_LOCKED: c_int = 0x8000; +pub const MAP_POPULATE: c_int = 0x10000; +pub const MAP_NONBLOCK: c_int = 0x20000; +pub const MAP_STACK: c_int = 0x40000; + +pub const NLDLY: crate::tcflag_t = 0o0000400; + +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_DGRAM: c_int = 1; +pub const SOCK_SEQPACKET: c_int = 5; + +pub const SA_ONSTACK: c_uint = 0x08000000; +pub const SA_SIGINFO: c_uint = 0x00000008; +pub const SA_NOCLDWAIT: c_int = 0x00010000; + +pub const SIGEMT: c_int = 7; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = 22; +pub const SIGSYS: c_int = 12; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 3; +pub const SIG_BLOCK: c_int = 0x1; +pub const SIG_UNBLOCK: c_int = 0x2; + +pub const POLLWRNORM: c_short = 0x004; +pub const POLLWRBAND: c_short = 0x100; + +pub const PTHREAD_STACK_MIN: size_t = 16384; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: crate::tcflag_t = 0x00000100; +pub const TOSTOP: crate::tcflag_t = 0x00008000; +pub const FLUSHO: crate::tcflag_t = 0x00002000; +pub const TCSANOW: c_int = 0x540e; +pub const TCSADRAIN: c_int = 0x540f; +pub const TCSAFLUSH: c_int = 0x5410; + +pub const CPU_SETSIZE: c_int = 0x400; + +pub const EFD_NONBLOCK: c_int = 0x80; + +pub const F_GETLK: c_int = 14; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; + +pub const SFD_NONBLOCK: c_int = 0x80; + +pub const RTLD_GLOBAL: c_int = 0x4; + +pub const SIGSTKSZ: size_t = 8192; +pub const CBAUD: crate::tcflag_t = 0o0010017; +pub const CBAUDEX: crate::tcflag_t = 0o0010000; +pub const CIBAUD: crate::tcflag_t = 0o002003600000; +pub const TAB1: crate::tcflag_t = 0x00000800; +pub const TAB2: crate::tcflag_t = 0x00001000; +pub const TAB3: crate::tcflag_t = 0x00001800; +pub const TABDLY: crate::tcflag_t = 0o0014000; +pub const CR1: crate::tcflag_t = 0x00000200; +pub const CR2: crate::tcflag_t = 0x00000400; +pub const CR3: crate::tcflag_t = 0x00000600; +pub const FF1: crate::tcflag_t = 0x00008000; +pub const BS1: crate::tcflag_t = 0x00002000; +pub const BSDLY: crate::tcflag_t = 0o0020000; +pub const VT1: crate::tcflag_t = 0x00004000; +pub const VWERASE: usize = 14; +pub const XTABS: crate::tcflag_t = 0o0014000; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSWTC: usize = 7; +pub const VTDLY: c_int = 0o0040000; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const OLCUC: crate::tcflag_t = 0o0000002; +pub const ONLCR: crate::tcflag_t = 0x4; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x00000010; +pub const CS7: crate::tcflag_t = 0x00000020; +pub const CS8: crate::tcflag_t = 0x00000030; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CRDLY: c_int = 0o0003000; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOPRT: crate::tcflag_t = 0x00000400; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const PENDIN: crate::tcflag_t = 0x00004000; +pub const NOFLSH: crate::tcflag_t = 0x00000080; + +pub const MAP_HUGETLB: c_int = 0x80000; + +pub const B0: crate::speed_t = 0o000000; +pub const B50: crate::speed_t = 0o000001; +pub const B75: crate::speed_t = 0o000002; +pub const B110: crate::speed_t = 0o000003; +pub const B134: crate::speed_t = 0o000004; +pub const B150: crate::speed_t = 0o000005; +pub const B200: crate::speed_t = 0o000006; +pub const B300: crate::speed_t = 0o000007; +pub const B600: crate::speed_t = 0o000010; +pub const B1200: crate::speed_t = 0o000011; +pub const B1800: crate::speed_t = 0o000012; +pub const B2400: crate::speed_t = 0o000013; +pub const B4800: crate::speed_t = 0o000014; +pub const B9600: crate::speed_t = 0o000015; +pub const B19200: crate::speed_t = 0o000016; +pub const B38400: crate::speed_t = 0o000017; +pub const B57600: crate::speed_t = 0o010001; +pub const B115200: crate::speed_t = 0o010002; +pub const B230400: crate::speed_t = 0o010003; +pub const B460800: crate::speed_t = 0o010004; +pub const B500000: crate::speed_t = 0o010005; +pub const B576000: crate::speed_t = 0o010006; +pub const B921600: crate::speed_t = 0o010007; +pub const B1000000: crate::speed_t = 0o010010; +pub const B1152000: crate::speed_t = 0o010011; +pub const B1500000: crate::speed_t = 0o010012; +pub const B2000000: crate::speed_t = 0o010013; +pub const B2500000: crate::speed_t = 0o010014; +pub const B3000000: crate::speed_t = 0o010015; +pub const B3500000: crate::speed_t = 0o010016; +pub const B4000000: crate::speed_t = 0o010017; + +cfg_if! { + if #[cfg(target_arch = "mips")] { + mod mips32; + pub use self::mips32::*; + } else if #[cfg(target_arch = "mips64")] { + mod mips64; + pub use self::mips64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mod.rs new file mode 100644 index 00000000000000..f70e0c41aeed1d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/mod.rs @@ -0,0 +1,509 @@ +// FIXME(ulibc): this module has definitions that are redundant with the parent +#![allow(dead_code)] + +use crate::off64_t; +use crate::prelude::*; + +pub type shmatt_t = c_ulong; +pub type msgqnum_t = c_ulong; +pub type msglen_t = c_ulong; +pub type regoff_t = c_int; +pub type rlim_t = c_ulong; +pub type __rlimit_resource_t = c_ulong; +pub type __priority_which_t = c_uint; + +cfg_if! { + if #[cfg(doc)] { + // Used in `linux::arch` to define ioctl constants. + pub(crate) type Ioctl = c_ulong; + } else { + #[doc(hidden)] + pub type Ioctl = c_ulong; + } +} + +s! { + pub struct statvfs { + // Different than GNU! + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: c_ulong, + #[cfg(target_pointer_width = "32")] + __f_unused: Padding, + #[cfg(target_endian = "big")] + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct regex_t { + __buffer: *mut c_void, + __allocated: size_t, + __used: size_t, + __syntax: c_ulong, + __fastmap: *mut c_char, + __translate: *mut c_char, + __re_nsub: size_t, + __bitfield: u8, + } + + pub struct rtentry { + pub rt_pad1: c_ulong, + pub rt_dst: crate::sockaddr, + pub rt_gateway: crate::sockaddr, + pub rt_genmask: crate::sockaddr, + pub rt_flags: c_ushort, + pub rt_pad2: c_short, + pub rt_pad3: c_ulong, + pub rt_tos: c_uchar, + pub rt_class: c_uchar, + #[cfg(target_pointer_width = "64")] + pub rt_pad4: [c_short; 3usize], + #[cfg(not(target_pointer_width = "64"))] + pub rt_pad4: c_short, + pub rt_metric: c_short, + pub rt_dev: *mut c_char, + pub rt_mtu: c_ulong, + pub rt_window: c_ulong, + pub rt_irtt: c_ushort, + } + + pub struct __exit_status { + pub e_termination: c_short, + pub e_exit: c_short, + } + + pub struct ptrace_peeksiginfo_args { + pub off: crate::__u64, + pub flags: crate::__u32, + pub nr: crate::__s32, + } + + #[cfg_attr( + any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64" + ), + repr(align(4)) + )] + #[cfg_attr( + not(any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64" + )), + repr(align(8)) + )] + pub struct pthread_mutexattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; crate::__SIZEOF_PTHREAD_CONDATTR_T], + } + + pub struct tcp_info { + pub tcpi_state: u8, + pub tcpi_ca_state: u8, + pub tcpi_retransmits: u8, + pub tcpi_probes: u8, + pub tcpi_backoff: u8, + pub tcpi_options: u8, + /// This contains the bitfields `tcpi_snd_wscale` and `tcpi_rcv_wscale`. + /// Each is 4 bits. + pub tcpi_snd_rcv_wscale: u8, + pub tcpi_rto: u32, + pub tcpi_ato: u32, + pub tcpi_snd_mss: u32, + pub tcpi_rcv_mss: u32, + pub tcpi_unacked: u32, + pub tcpi_sacked: u32, + pub tcpi_lost: u32, + pub tcpi_retrans: u32, + pub tcpi_fackets: u32, + pub tcpi_last_data_sent: u32, + pub tcpi_last_ack_sent: u32, + pub tcpi_last_data_recv: u32, + pub tcpi_last_ack_recv: u32, + pub tcpi_pmtu: u32, + pub tcpi_rcv_ssthresh: u32, + pub tcpi_rtt: u32, + pub tcpi_rttvar: u32, + pub tcpi_snd_ssthresh: u32, + pub tcpi_snd_cwnd: u32, + pub tcpi_advmss: u32, + pub tcpi_reordering: u32, + pub tcpi_rcv_rtt: u32, + pub tcpi_rcv_space: u32, + pub tcpi_total_retrans: u32, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_si_value { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + _si_timerid: c_int, + _si_overrun: c_int, + si_value: crate::sigval, + } + (*(self as *const siginfo_t as *const siginfo_si_value)).si_value + } +} + +s_no_extra_traits! { + // Internal, for casts to access union fields + struct sifields_sigchld { + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: c_long, + si_stime: c_long, + } + + // Internal, for casts to access union fields + union sifields { + _align_pointer: *mut c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + struct siginfo_f { + _siginfo_base: [c_int; 3], + sifields: sifields, + } +} + +impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*(self as *const siginfo_t as *const siginfo_f)).sifields + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> c_long { + self.sifields().sigchld.si_stime + } +} + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; +pub const MCL_ONFAULT: c_int = 0x0004; + +pub const SIGEV_THREAD_ID: c_int = 4; + +pub const AF_VSOCK: c_int = 40; + +// Most `*_SUPER_MAGIC` constants are defined at the `linux_like` level; the +// following are only available on newer Linux versions than the versions +// currently used in CI in some configurations, so we define them here. +pub const BINDERFS_SUPER_MAGIC: c_long = 0x6c6f6f70; +pub const XFS_SUPER_MAGIC: c_long = 0x58465342; + +pub const PTRACE_TRACEME: c_int = 0; +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_PEEKUSER: c_int = 3; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_POKEUSER: c_int = 6; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; +pub const PTRACE_GETFPXREGS: c_int = 18; +pub const PTRACE_SETFPXREGS: c_int = 19; +pub const PTRACE_SYSCALL: c_int = 24; +pub const PTRACE_SETOPTIONS: c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: c_int = 0x4201; +pub const PTRACE_GETSIGINFO: c_int = 0x4202; +pub const PTRACE_SETSIGINFO: c_int = 0x4203; +pub const PTRACE_GETREGSET: c_int = 0x4204; +pub const PTRACE_SETREGSET: c_int = 0x4205; +pub const PTRACE_SEIZE: c_int = 0x4206; +pub const PTRACE_INTERRUPT: c_int = 0x4207; +pub const PTRACE_LISTEN: c_int = 0x4208; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +// These are different than GNU! +pub const LC_CTYPE: c_int = 0; +pub const LC_NUMERIC: c_int = 1; +pub const LC_TIME: c_int = 3; +pub const LC_COLLATE: c_int = 4; +pub const LC_MONETARY: c_int = 2; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = 6; +// end different section + +// MS_ flags for mount(2) +pub const MS_RMT_MASK: c_ulong = + crate::MS_RDONLY | crate::MS_SYNCHRONOUS | crate::MS_MANDLOCK | crate::MS_I_VERSION; + +pub const ENOTSUP: c_int = EOPNOTSUPP; + +pub const IPV6_JOIN_GROUP: c_int = 20; +pub const IPV6_LEAVE_GROUP: c_int = 21; + +// These are different from GNU +pub const ABDAY_1: crate::nl_item = 0x300; +pub const ABDAY_2: crate::nl_item = 0x301; +pub const ABDAY_3: crate::nl_item = 0x302; +pub const ABDAY_4: crate::nl_item = 0x303; +pub const ABDAY_5: crate::nl_item = 0x304; +pub const ABDAY_6: crate::nl_item = 0x305; +pub const ABDAY_7: crate::nl_item = 0x306; +pub const DAY_1: crate::nl_item = 0x307; +pub const DAY_2: crate::nl_item = 0x308; +pub const DAY_3: crate::nl_item = 0x309; +pub const DAY_4: crate::nl_item = 0x30A; +pub const DAY_5: crate::nl_item = 0x30B; +pub const DAY_6: crate::nl_item = 0x30C; +pub const DAY_7: crate::nl_item = 0x30D; +pub const ABMON_1: crate::nl_item = 0x30E; +pub const ABMON_2: crate::nl_item = 0x30F; +pub const ABMON_3: crate::nl_item = 0x310; +pub const ABMON_4: crate::nl_item = 0x311; +pub const ABMON_5: crate::nl_item = 0x312; +pub const ABMON_6: crate::nl_item = 0x313; +pub const ABMON_7: crate::nl_item = 0x314; +pub const ABMON_8: crate::nl_item = 0x315; +pub const ABMON_9: crate::nl_item = 0x316; +pub const ABMON_10: crate::nl_item = 0x317; +pub const ABMON_11: crate::nl_item = 0x318; +pub const ABMON_12: crate::nl_item = 0x319; +pub const MON_1: crate::nl_item = 0x31A; +pub const MON_2: crate::nl_item = 0x31B; +pub const MON_3: crate::nl_item = 0x31C; +pub const MON_4: crate::nl_item = 0x31D; +pub const MON_5: crate::nl_item = 0x31E; +pub const MON_6: crate::nl_item = 0x31F; +pub const MON_7: crate::nl_item = 0x320; +pub const MON_8: crate::nl_item = 0x321; +pub const MON_9: crate::nl_item = 0x322; +pub const MON_10: crate::nl_item = 0x323; +pub const MON_11: crate::nl_item = 0x324; +pub const MON_12: crate::nl_item = 0x325; +pub const AM_STR: crate::nl_item = 0x326; +pub const PM_STR: crate::nl_item = 0x327; +pub const D_T_FMT: crate::nl_item = 0x328; +pub const D_FMT: crate::nl_item = 0x329; +pub const T_FMT: crate::nl_item = 0x32A; +pub const T_FMT_AMPM: crate::nl_item = 0x32B; +pub const ERA: crate::nl_item = 0x32C; +pub const ERA_D_FMT: crate::nl_item = 0x32E; +pub const ALT_DIGITS: crate::nl_item = 0x32F; +pub const ERA_D_T_FMT: crate::nl_item = 0x330; +pub const ERA_T_FMT: crate::nl_item = 0x331; +pub const CODESET: crate::nl_item = 10; +pub const CRNCYSTR: crate::nl_item = 0x215; +pub const RADIXCHAR: crate::nl_item = 0x100; +pub const THOUSEP: crate::nl_item = 0x101; +pub const NOEXPR: crate::nl_item = 0x501; +pub const YESSTR: crate::nl_item = 0x502; +pub const NOSTR: crate::nl_item = 0x503; + +// Different than Gnu. +pub const FILENAME_MAX: c_uint = 4095; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const SOMAXCONN: c_int = 128; + +pub const ST_RELATIME: c_ulong = 4096; + +pub const AF_NFC: c_int = PF_NFC; +pub const BUFSIZ: c_int = 4096; +pub const EDEADLOCK: c_int = EDEADLK; +pub const EXTA: c_uint = B19200; +pub const EXTB: c_uint = B38400; +pub const EXTPROC: crate::tcflag_t = 0o200000; +pub const FOPEN_MAX: c_int = 16; +pub const F_GETOWN: c_int = 9; +pub const F_OFD_GETLK: c_int = 36; +pub const F_OFD_SETLK: c_int = 37; +pub const F_OFD_SETLKW: c_int = 38; +pub const F_RDLCK: c_int = 0; +pub const F_SETOWN: c_int = 8; +pub const F_UNLCK: c_int = 2; +pub const F_WRLCK: c_int = 1; +pub const IPV6_MULTICAST_ALL: c_int = 29; +pub const IPV6_ROUTER_ALERT_ISOLATE: c_int = 30; +pub const MAP_HUGE_SHIFT: c_int = 26; +pub const MAP_HUGE_MASK: c_int = 0x3f; +pub const MAP_HUGE_64KB: c_int = 16 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_512KB: c_int = 19 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_1MB: c_int = 20 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_2MB: c_int = 21 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_8MB: c_int = 23 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_16MB: c_int = 24 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_32MB: c_int = 25 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_256MB: c_int = 28 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_512MB: c_int = 29 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_1GB: c_int = 30 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_2GB: c_int = 31 << MAP_HUGE_SHIFT; +pub const MAP_HUGE_16GB: c_int = 34 << MAP_HUGE_SHIFT; +pub const MINSIGSTKSZ: c_int = 2048; +pub const MSG_COPY: c_int = 0o40000; +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const O_TMPFILE: c_int = 0o20000000 | O_DIRECTORY; +pub const PACKET_MR_UNICAST: c_int = 3; +pub const PF_NFC: c_int = 39; +pub const PF_VSOCK: c_int = 40; +pub const PTRACE_EVENT_STOP: c_int = 128; +pub const PTRACE_GETSIGMASK: c_uint = 0x420a; +pub const PTRACE_PEEKSIGINFO: c_int = 0x4209; +pub const PTRACE_SETSIGMASK: c_uint = 0x420b; +pub const RTLD_NOLOAD: c_int = 0x00004; +pub const RUSAGE_THREAD: c_int = 1; +pub const SHM_EXEC: c_int = 0o100000; +pub const SIGPOLL: c_int = SIGIO; +pub const SOCK_DCCP: c_int = 6; +#[deprecated(since = "0.2.70", note = "AF_PACKET must be used instead")] +pub const SOCK_PACKET: c_int = 10; +pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; +pub const UDP_GRO: c_int = 104; +pub const UDP_SEGMENT: c_int = 103; +pub const YESEXPR: c_int = ((5) << 8) | (0); + +extern "C" { + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + + pub fn pthread_rwlockattr_getkind_np( + attr: *const crate::pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setkind_np( + attr: *mut crate::pthread_rwlockattr_t, + val: c_int, + ) -> c_int; + + pub fn ptrace(request: c_uint, ...) -> c_long; + + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + ) -> c_int; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_int, + timeout: *mut crate::timespec, + ) -> c_int; + + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off64_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off64_t) -> ssize_t; + + pub fn sethostid(hostid: c_long) -> c_int; + pub fn fanotify_mark( + fd: c_int, + flags: c_uint, + mask: u64, + dirfd: c_int, + path: *const c_char, + ) -> c_int; + pub fn getrlimit64(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit64) -> c_int; + pub fn setrlimit64(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit64) + -> c_int; + pub fn getrlimit(resource: crate::__rlimit_resource_t, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: crate::__rlimit_resource_t, rlim: *const crate::rlimit) -> c_int; + pub fn getpriority(which: crate::__priority_which_t, who: crate::id_t) -> c_int; + pub fn setpriority(which: crate::__priority_which_t, who: crate::id_t, prio: c_int) -> c_int; + pub fn getauxval(type_: c_ulong) -> c_ulong; +} + +cfg_if! { + if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else { + pub use unsupported_target; + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/x86_64/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/x86_64/mod.rs new file mode 100644 index 00000000000000..30e6772388d1c5 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux/uclibc/x86_64/mod.rs @@ -0,0 +1,346 @@ +//! Definitions for uclibc on 64bit systems + +use crate::off64_t; +use crate::prelude::*; + +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type clock_t = i64; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type fsword_t = c_long; +pub type ino_t = c_ulong; +pub type nlink_t = c_uint; +pub type off_t = c_long; +// [uClibc docs] Note stat64 has the same shape as stat for x86-64. +pub type stat64 = stat; +pub type suseconds_t = c_long; +pub type time_t = c_int; +pub type wchar_t = c_int; +pub type pthread_t = c_ulong; + +pub type fsblkcnt64_t = u64; +pub type fsfilcnt64_t = u64; +pub type __u64 = c_ulong; +pub type __s64 = c_long; + +s! { + pub struct ipc_perm { + pub __key: crate::key_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: c_ushort, // read / write + __pad1: Padding, + pub __seq: c_ushort, + __pad2: Padding, + __unused1: Padding, + __unused2: Padding, + } + + pub struct pthread_attr_t { + __detachstate: c_int, + __schedpolicy: c_int, + __schedparam: __sched_param, + __inheritsched: c_int, + __scope: c_int, + __guardsize: size_t, + __stackaddr_set: c_int, + __stackaddr: *mut c_void, // better don't use it + __stacksize: size_t, + } + + pub struct __sched_param { + __sched_priority: c_int, + } + + pub struct siginfo_t { + si_signo: c_int, // signal number + si_errno: c_int, // if not zero: error value of signal, see errno.h + si_code: c_int, // signal code + pub _pad: [c_int; 28], // unported union + _align: [usize; 0], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, // segment size in bytes + pub shm_atime: crate::time_t, // time of last shmat() + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_cpid: crate::pid_t, + pub shm_lpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + __unused1: Padding, + __unused2: Padding, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_stime: crate::time_t, + pub msg_rtime: crate::time_t, + pub msg_ctime: crate::time_t, + pub __msg_cbytes: c_ulong, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + __ignored1: c_ulong, + __ignored2: c_ulong, + } + + pub struct sockaddr { + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + /* ------------------------------------------------------------ + * definitions below are *unverified* and might **break** the software + */ + + // pub struct in_addr { + // pub s_addr: in_addr_t, + // } + // + // pub struct in6_addr { + // pub s6_addr: [u8; 16], + // } + + pub struct stat { + pub st_dev: c_ulong, + pub st_ino: crate::ino_t, + // According to uclibc/libc/sysdeps/linux/x86_64/bits/stat.h, order of + // nlink and mode are swapped on 64 bit systems. + pub st_nlink: crate::nlink_t, + pub st_mode: crate::mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: c_ulong, // dev_t + pub st_size: off_t, // file size + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_ulong, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_ulong, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_ulong, + st_pad4: Padding<[c_long; 3]>, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_handler: crate::sighandler_t, + pub sa_flags: c_ulong, + pub sa_restorer: Option, + pub sa_mask: crate::sigset_t, + } + + pub struct stack_t { + // FIXME(ulibc) + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: size_t, + } + + pub struct statfs { + // FIXME(ulibc) + pub f_type: fsword_t, + pub f_bsize: fsword_t, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: fsword_t, + pub f_frsize: fsword_t, + f_spare: [fsword_t; 5], + } + + pub struct statfs64 { + pub f_type: c_int, + pub f_bsize: c_int, + pub f_blocks: crate::fsblkcnt64_t, + pub f_bfree: crate::fsblkcnt64_t, + pub f_bavail: crate::fsblkcnt64_t, + pub f_files: crate::fsfilcnt64_t, + pub f_ffree: crate::fsfilcnt64_t, + pub f_fsid: crate::fsid_t, + pub f_namelen: c_int, + pub f_frsize: c_int, + pub f_flags: c_int, + pub f_spare: [c_int; 4], + } + + pub struct statvfs64 { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: c_ulong, + __f_unused: Padding, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + __f_spare: [c_int; 6], + } + + pub struct msghdr { + // FIXME(ulibc) + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: size_t, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct termios { + // FIXME(ulibc) + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct sigset_t { + // FIXME(ulibc) + __val: [c_ulong; 16], + } + + pub struct sysinfo { + // FIXME(ulibc) + pub uptime: c_long, + pub loads: [c_ulong; 3], + pub totalram: c_ulong, + pub freeram: c_ulong, + pub sharedram: c_ulong, + pub bufferram: c_ulong, + pub totalswap: c_ulong, + pub freeswap: c_ulong, + pub procs: c_ushort, + pub pad: c_ushort, + pub totalhigh: c_ulong, + pub freehigh: c_ulong, + pub mem_unit: c_uint, + pub _f: [c_char; 0], + } + + pub struct glob_t { + // FIXME(ulibc) + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct cpu_set_t { + // FIXME(ulibc) + #[cfg(target_pointer_width = "32")] + bits: [u32; 32], + #[cfg(target_pointer_width = "64")] + bits: [u64; 16], + } + + pub struct fsid_t { + // FIXME(ulibc) + __val: [c_int; 2], + } + + // FIXME(1.0): this is actually a union + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [c_char; 32], + __align: [c_long; 0], + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } +} + +s_no_extra_traits! { + pub struct dirent { + pub d_ino: crate::ino64_t, + pub d_off: off64_t, + pub d_reclen: u16, + pub d_type: u8, + pub d_name: [c_char; 256], + } +} + +// constants +pub const ENAMETOOLONG: c_int = 36; // File name too long +pub const ENOTEMPTY: c_int = 39; // Directory not empty +pub const ELOOP: c_int = 40; // Too many symbolic links encountered +pub const EADDRINUSE: c_int = 98; // Address already in use +pub const EADDRNOTAVAIL: c_int = 99; // Cannot assign requested address +pub const ENETDOWN: c_int = 100; // Network is down +pub const ENETUNREACH: c_int = 101; // Network is unreachable +pub const ECONNABORTED: c_int = 103; // Software caused connection abort +pub const ECONNREFUSED: c_int = 111; // Connection refused +pub const ECONNRESET: c_int = 104; // Connection reset by peer +pub const EDEADLK: c_int = 35; // Resource deadlock would occur +pub const ENOSYS: c_int = 38; // Function not implemented +pub const ENOTCONN: c_int = 107; // Transport endpoint is not connected +pub const ETIMEDOUT: c_int = 110; // connection timed out +pub const ESTALE: c_int = 116; // Stale file handle +pub const EHOSTUNREACH: c_int = 113; // No route to host +pub const EDQUOT: c_int = 122; // Quota exceeded +pub const EOPNOTSUPP: c_int = 0x5f; +pub const ENODATA: c_int = 0x3d; +pub const O_APPEND: c_int = 0o2000; +pub const O_ACCMODE: c_int = 0o003; +pub const O_CLOEXEC: c_int = 0x80000; +pub const O_CREAT: c_int = 0100; +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_EXCL: c_int = 0o200; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_NONBLOCK: c_int = 0o4000; +pub const O_TRUNC: c_int = 0o1000; +pub const NCCS: usize = 32; +pub const SIG_SETMASK: c_int = 2; // Set the set of blocked signals +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const SOCK_DGRAM: c_int = 2; // connectionless, unreliable datagrams +pub const SOCK_STREAM: c_int = 1; // …/common/bits/socket_type.h +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const PTHREAD_STACK_MIN: usize = 16384; diff --git a/deps/crates/vendor/libc/src/unix/linux_like/linux_l4re_shared.rs b/deps/crates/vendor/libc/src/unix/linux_like/linux_l4re_shared.rs new file mode 100644 index 00000000000000..cf76b3966ffac7 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/linux_l4re_shared.rs @@ -0,0 +1,1997 @@ +use crate::prelude::*; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; +pub type Elf32_Xword = u64; +pub type Elf32_Sword = i32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; +pub type Elf64_Sxword = i64; +pub type Elf64_Sword = i32; + +pub type Elf32_Section = u16; +pub type Elf64_Section = u16; + +pub type Elf32_Relr = Elf32_Word; +pub type Elf64_Relr = Elf32_Xword; +pub type Elf32_Rel = __c_anonymous_elf32_rel; +pub type Elf64_Rel = __c_anonymous_elf64_rel; + +cfg_if! { + if #[cfg(not(target_arch = "sparc64"))] { + pub type Elf32_Rela = __c_anonymous_elf32_rela; + pub type Elf64_Rela = __c_anonymous_elf64_rela; + } +} + +pub type iconv_t = *mut c_void; + +cfg_if! { + if #[cfg(not(target_env = "gnu"))] { + extern_ty! { + pub enum fpos64_t {} // FIXME(linux): fill this out with a struct + } + } +} + +s! { + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct spwd { + pub sp_namp: *mut c_char, + pub sp_pwdp: *mut c_char, + pub sp_lstchg: c_long, + pub sp_min: c_long, + pub sp_max: c_long, + pub sp_warn: c_long, + pub sp_inact: c_long, + pub sp_expire: c_long, + pub sp_flag: c_ulong, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct fsid_t { + __val: [c_int; 2], + } + + pub struct packet_mreq { + pub mr_ifindex: c_int, + pub mr_type: c_ushort, + pub mr_alen: c_ushort, + pub mr_address: [c_uchar; 8], + } + + pub struct cpu_set_t { + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))] + bits: [u32; 32], + #[cfg(not(all(target_pointer_width = "32", not(target_arch = "x86_64"))))] + bits: [u64; 16], + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + // As of uClibc 1.0.36, the following fields are + // gated behind a "#if 0" block which always evaluates + // to false. So I'm just removing these, and if uClibc changes + // the #if block in the future to include the following fields, these + // will probably need including here. tsidea, skrap + // QNX (NTO) platform does not define these fields + #[cfg(not(any(target_env = "uclibc", target_os = "nto")))] + pub dlpi_adds: c_ulonglong, + #[cfg(not(any(target_env = "uclibc", target_os = "nto")))] + pub dlpi_subs: c_ulonglong, + #[cfg(not(any(target_env = "uclibc", target_os = "nto")))] + pub dlpi_tls_modid: size_t, + #[cfg(not(any(target_env = "uclibc", target_os = "nto")))] + pub dlpi_tls_data: *mut c_void, + } + + pub struct Elf32_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf32_Half, + pub e_machine: Elf32_Half, + pub e_version: Elf32_Word, + pub e_entry: Elf32_Addr, + pub e_phoff: Elf32_Off, + pub e_shoff: Elf32_Off, + pub e_flags: Elf32_Word, + pub e_ehsize: Elf32_Half, + pub e_phentsize: Elf32_Half, + pub e_phnum: Elf32_Half, + pub e_shentsize: Elf32_Half, + pub e_shnum: Elf32_Half, + pub e_shstrndx: Elf32_Half, + } + + pub struct Elf64_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf64_Half, + pub e_machine: Elf64_Half, + pub e_version: Elf64_Word, + pub e_entry: Elf64_Addr, + pub e_phoff: Elf64_Off, + pub e_shoff: Elf64_Off, + pub e_flags: Elf64_Word, + pub e_ehsize: Elf64_Half, + pub e_phentsize: Elf64_Half, + pub e_phnum: Elf64_Half, + pub e_shentsize: Elf64_Half, + pub e_shnum: Elf64_Half, + pub e_shstrndx: Elf64_Half, + } + + pub struct Elf32_Sym { + pub st_name: Elf32_Word, + pub st_value: Elf32_Addr, + pub st_size: Elf32_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf32_Section, + } + + pub struct Elf64_Sym { + pub st_name: Elf64_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf64_Section, + pub st_value: Elf64_Addr, + pub st_size: Elf64_Xword, + } + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct Elf32_Shdr { + pub sh_name: Elf32_Word, + pub sh_type: Elf32_Word, + pub sh_flags: Elf32_Word, + pub sh_addr: Elf32_Addr, + pub sh_offset: Elf32_Off, + pub sh_size: Elf32_Word, + pub sh_link: Elf32_Word, + pub sh_info: Elf32_Word, + pub sh_addralign: Elf32_Word, + pub sh_entsize: Elf32_Word, + } + + pub struct Elf64_Shdr { + pub sh_name: Elf64_Word, + pub sh_type: Elf64_Word, + pub sh_flags: Elf64_Xword, + pub sh_addr: Elf64_Addr, + pub sh_offset: Elf64_Off, + pub sh_size: Elf64_Xword, + pub sh_link: Elf64_Word, + pub sh_info: Elf64_Word, + pub sh_addralign: Elf64_Xword, + pub sh_entsize: Elf64_Xword, + } + + pub struct __c_anonymous_elf32_rel { + pub r_offset: Elf32_Addr, + pub r_info: Elf32_Word, + } + + pub struct __c_anonymous_elf64_rel { + pub r_offset: Elf64_Addr, + pub r_info: Elf64_Xword, + } + + pub struct ucred { + pub pid: crate::pid_t, + pub uid: crate::uid_t, + pub gid: crate::gid_t, + } + + pub struct mntent { + pub mnt_fsname: *mut c_char, + pub mnt_dir: *mut c_char, + pub mnt_type: *mut c_char, + pub mnt_opts: *mut c_char, + pub mnt_freq: c_int, + pub mnt_passno: c_int, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + pub struct arpd_request { + pub req: c_ushort, + pub ip: u32, + pub dev: c_ulong, + pub stamp: c_ulong, + pub updated: c_ulong, + pub ha: [c_uchar; crate::MAX_ADDR_LEN], + } + + pub struct regmatch_t { + pub rm_so: crate::regoff_t, + pub rm_eo: crate::regoff_t, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + + pub struct rlimit64 { + pub rlim_cur: crate::rlim64_t, + pub rlim_max: crate::rlim64_t, + } + + pub struct __c_anonymous_ifru_map { + pub mem_start: c_ulong, + pub mem_end: c_ulong, + pub base_addr: c_ushort, + pub irq: c_uchar, + pub dma: c_uchar, + pub port: c_uchar, + } + + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_off: crate::off_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct dirent64 { + pub d_ino: crate::ino64_t, + pub d_off: crate::off64_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } +} + +cfg_if! { + if #[cfg(not(target_arch = "sparc64"))] { + s! { + pub struct __c_anonymous_elf32_rela { + pub r_offset: crate::Elf32_Addr, + pub r_info: crate::Elf32_Word, + pub r_addend: crate::Elf32_Sword, + } + + pub struct __c_anonymous_elf64_rela { + pub r_offset: crate::Elf64_Addr, + pub r_info: crate::Elf64_Xword, + pub r_addend: crate::Elf64_Sxword, + } + } + } +} + +s_no_extra_traits! { + pub union __c_anonymous_ifr_ifru { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_netmask: crate::sockaddr, + pub ifru_hwaddr: crate::sockaddr, + pub ifru_flags: c_short, + pub ifru_ifindex: c_int, + pub ifru_metric: c_int, + pub ifru_mtu: c_int, + pub ifru_map: __c_anonymous_ifru_map, + pub ifru_slave: [c_char; crate::IFNAMSIZ], + pub ifru_newname: [c_char; crate::IFNAMSIZ], + pub ifru_data: *mut c_char, + } + + pub struct ifreq { + /// interface name, e.g. "en0" + pub ifr_name: [c_char; crate::IFNAMSIZ], + pub ifr_ifru: __c_anonymous_ifr_ifru, + } + + pub union __c_anonymous_ifc_ifcu { + pub ifcu_buf: *mut c_char, + pub ifcu_req: *mut crate::ifreq, + } + + /// Structure used in SIOCGIFCONF request. Used to retrieve interface configuration for + /// machine (useful for programs which must know all networks accessible). + pub struct ifconf { + /// Size of buffer + pub ifc_len: c_int, + pub ifc_ifcu: __c_anonymous_ifc_ifcu, + } +} + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + const DATE_BASE: crate::nl_item = 0x20000; + } else { + const DATE_BASE: crate::nl_item = 768; + } +} + +pub const ABDAY_1: crate::nl_item = DATE_BASE; +pub const ABDAY_2: crate::nl_item = DATE_BASE + 0x1; +pub const ABDAY_3: crate::nl_item = DATE_BASE + 0x2; +pub const ABDAY_4: crate::nl_item = DATE_BASE + 0x3; +pub const ABDAY_5: crate::nl_item = DATE_BASE + 0x4; +pub const ABDAY_6: crate::nl_item = DATE_BASE + 0x5; +pub const ABDAY_7: crate::nl_item = DATE_BASE + 0x6; + +pub const DAY_1: crate::nl_item = DATE_BASE + 0x7; +pub const DAY_2: crate::nl_item = DATE_BASE + 0x8; +pub const DAY_3: crate::nl_item = DATE_BASE + 0x9; +pub const DAY_4: crate::nl_item = DATE_BASE + 0xA; +pub const DAY_5: crate::nl_item = DATE_BASE + 0xB; +pub const DAY_6: crate::nl_item = DATE_BASE + 0xC; +pub const DAY_7: crate::nl_item = DATE_BASE + 0xD; + +pub const ABMON_1: crate::nl_item = DATE_BASE + 0xE; +pub const ABMON_2: crate::nl_item = DATE_BASE + 0xF; +pub const ABMON_3: crate::nl_item = DATE_BASE + 0x10; +pub const ABMON_4: crate::nl_item = DATE_BASE + 0x11; +pub const ABMON_5: crate::nl_item = DATE_BASE + 0x12; +pub const ABMON_6: crate::nl_item = DATE_BASE + 0x13; +pub const ABMON_7: crate::nl_item = DATE_BASE + 0x14; +pub const ABMON_8: crate::nl_item = DATE_BASE + 0x15; +pub const ABMON_9: crate::nl_item = DATE_BASE + 0x16; +pub const ABMON_10: crate::nl_item = DATE_BASE + 0x17; +pub const ABMON_11: crate::nl_item = DATE_BASE + 0x18; +pub const ABMON_12: crate::nl_item = DATE_BASE + 0x19; + +pub const MON_1: crate::nl_item = DATE_BASE + 0x1A; +pub const MON_2: crate::nl_item = DATE_BASE + 0x1B; +pub const MON_3: crate::nl_item = DATE_BASE + 0x1C; +pub const MON_4: crate::nl_item = DATE_BASE + 0x1D; +pub const MON_5: crate::nl_item = DATE_BASE + 0x1E; +pub const MON_6: crate::nl_item = DATE_BASE + 0x1F; +pub const MON_7: crate::nl_item = DATE_BASE + 0x20; +pub const MON_8: crate::nl_item = DATE_BASE + 0x21; +pub const MON_9: crate::nl_item = DATE_BASE + 0x22; +pub const MON_10: crate::nl_item = DATE_BASE + 0x23; +pub const MON_11: crate::nl_item = DATE_BASE + 0x24; +pub const MON_12: crate::nl_item = DATE_BASE + 0x25; + +pub const AM_STR: crate::nl_item = DATE_BASE + 0x26; +pub const PM_STR: crate::nl_item = DATE_BASE + 0x27; + +pub const D_T_FMT: crate::nl_item = DATE_BASE + 0x28; +pub const D_FMT: crate::nl_item = DATE_BASE + 0x29; +pub const T_FMT: crate::nl_item = DATE_BASE + 0x2A; +pub const T_FMT_AMPM: crate::nl_item = DATE_BASE + 0x2B; + +pub const ERA: crate::nl_item = DATE_BASE + 0x2C; +pub const ERA_D_FMT: crate::nl_item = DATE_BASE + 0x2E; +pub const ALT_DIGITS: crate::nl_item = DATE_BASE + 0x2F; +pub const ERA_D_T_FMT: crate::nl_item = DATE_BASE + 0x30; +pub const ERA_T_FMT: crate::nl_item = DATE_BASE + 0x31; + +cfg_if! { + if #[cfg(any( + target_env = "gnu", + target_env = "musl", + target_env = "ohos" + ))] { + pub const CODESET: crate::nl_item = 14; + pub const CRNCYSTR: crate::nl_item = 0x4000F; + pub const RADIXCHAR: crate::nl_item = 0x10000; + pub const THOUSEP: crate::nl_item = 0x10001; + pub const YESEXPR: crate::nl_item = 0x50000; + pub const NOEXPR: crate::nl_item = 0x50001; + pub const YESSTR: crate::nl_item = 0x50002; + pub const NOSTR: crate::nl_item = 0x50003; + } else if #[cfg(target_env = "uclibc")] { + pub const CODESET: crate::nl_item = 10; + pub const CRNCYSTR: crate::nl_item = 0x215; + pub const RADIXCHAR: crate::nl_item = 0x100; + pub const THOUSEP: crate::nl_item = 0x101; + pub const YESEXPR: crate::nl_item = 0x500; + pub const NOEXPR: crate::nl_item = 0x501; + pub const YESSTR: crate::nl_item = 0x502; + pub const NOSTR: crate::nl_item = 0x503; + } +} + +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const L_tmpnam: c_uint = 20; +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; + +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = 60; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_NZERO: c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_STREAMS: c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; + +pub const _CS_PATH: c_int = 0; +pub const _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS: c_int = 1; +pub const _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS: c_int = 4; +pub const _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS: c_int = 5; +pub const _CS_POSIX_V6_ILP32_OFF32_CFLAGS: c_int = 1116; +pub const _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: c_int = 1117; +pub const _CS_POSIX_V6_ILP32_OFF32_LIBS: c_int = 1118; +pub const _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS: c_int = 1119; +pub const _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: c_int = 1120; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: c_int = 1121; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LIBS: c_int = 1122; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS: c_int = 1123; +pub const _CS_POSIX_V6_LP64_OFF64_CFLAGS: c_int = 1124; +pub const _CS_POSIX_V6_LP64_OFF64_LDFLAGS: c_int = 1125; +pub const _CS_POSIX_V6_LP64_OFF64_LIBS: c_int = 1126; +pub const _CS_POSIX_V6_LP64_OFF64_LINTFLAGS: c_int = 1127; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: c_int = 1128; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: c_int = 1129; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: c_int = 1130; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS: c_int = 1131; +pub const _CS_POSIX_V7_ILP32_OFF32_CFLAGS: c_int = 1132; +pub const _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: c_int = 1133; +pub const _CS_POSIX_V7_ILP32_OFF32_LIBS: c_int = 1134; +pub const _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: c_int = 1135; +pub const _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: c_int = 1136; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: c_int = 1137; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LIBS: c_int = 1138; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: c_int = 1139; +pub const _CS_POSIX_V7_LP64_OFF64_CFLAGS: c_int = 1140; +pub const _CS_POSIX_V7_LP64_OFF64_LDFLAGS: c_int = 1141; +pub const _CS_POSIX_V7_LP64_OFF64_LIBS: c_int = 1142; +pub const _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: c_int = 1143; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: c_int = 1144; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: c_int = 1145; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: c_int = 1146; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS: c_int = 1147; + +pub const RLIM_SAVED_MAX: crate::rlim_t = crate::RLIM_INFINITY; +pub const RLIM_SAVED_CUR: crate::rlim_t = crate::RLIM_INFINITY; + +// elf.h - Fields in the e_ident array. +pub const EI_NIDENT: usize = 16; + +pub const EI_MAG0: usize = 0; +pub const ELFMAG0: u8 = 0x7f; +pub const EI_MAG1: usize = 1; +pub const ELFMAG1: u8 = b'E'; +pub const EI_MAG2: usize = 2; +pub const ELFMAG2: u8 = b'L'; +pub const EI_MAG3: usize = 3; +pub const ELFMAG3: u8 = b'F'; +pub const SELFMAG: usize = 4; + +pub const EI_CLASS: usize = 4; +pub const ELFCLASSNONE: u8 = 0; +pub const ELFCLASS32: u8 = 1; +pub const ELFCLASS64: u8 = 2; +pub const ELFCLASSNUM: usize = 3; + +pub const EI_DATA: usize = 5; +pub const ELFDATANONE: u8 = 0; +pub const ELFDATA2LSB: u8 = 1; +pub const ELFDATA2MSB: u8 = 2; +pub const ELFDATANUM: usize = 3; + +pub const EI_VERSION: usize = 6; + +pub const EI_OSABI: usize = 7; +pub const ELFOSABI_NONE: u8 = 0; +pub const ELFOSABI_SYSV: u8 = 0; +pub const ELFOSABI_HPUX: u8 = 1; +pub const ELFOSABI_NETBSD: u8 = 2; +pub const ELFOSABI_GNU: u8 = 3; +pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU; +pub const ELFOSABI_SOLARIS: u8 = 6; +pub const ELFOSABI_AIX: u8 = 7; +pub const ELFOSABI_IRIX: u8 = 8; +pub const ELFOSABI_FREEBSD: u8 = 9; +pub const ELFOSABI_TRU64: u8 = 10; +pub const ELFOSABI_MODESTO: u8 = 11; +pub const ELFOSABI_OPENBSD: u8 = 12; +pub const ELFOSABI_ARM: u8 = 97; +pub const ELFOSABI_STANDALONE: u8 = 255; + +pub const EI_ABIVERSION: usize = 8; + +pub const EI_PAD: usize = 9; + +// elf.h - Legal values for e_type (object file type). +pub const ET_NONE: u16 = 0; +pub const ET_REL: u16 = 1; +pub const ET_EXEC: u16 = 2; +pub const ET_DYN: u16 = 3; +pub const ET_CORE: u16 = 4; +pub const ET_NUM: u16 = 5; +pub const ET_LOOS: u16 = 0xfe00; +pub const ET_HIOS: u16 = 0xfeff; +pub const ET_LOPROC: u16 = 0xff00; +pub const ET_HIPROC: u16 = 0xffff; + +// elf.h - Legal values for e_machine (architecture). +pub const EM_NONE: u16 = 0; +pub const EM_M32: u16 = 1; +pub const EM_SPARC: u16 = 2; +pub const EM_386: u16 = 3; +pub const EM_68K: u16 = 4; +pub const EM_88K: u16 = 5; +pub const EM_860: u16 = 7; +pub const EM_MIPS: u16 = 8; +pub const EM_S370: u16 = 9; +pub const EM_MIPS_RS3_LE: u16 = 10; +pub const EM_PARISC: u16 = 15; +pub const EM_VPP500: u16 = 17; +pub const EM_SPARC32PLUS: u16 = 18; +pub const EM_960: u16 = 19; +pub const EM_PPC: u16 = 20; +pub const EM_PPC64: u16 = 21; +pub const EM_S390: u16 = 22; +pub const EM_V800: u16 = 36; +pub const EM_FR20: u16 = 37; +pub const EM_RH32: u16 = 38; +pub const EM_RCE: u16 = 39; +pub const EM_ARM: u16 = 40; +pub const EM_FAKE_ALPHA: u16 = 41; +pub const EM_SH: u16 = 42; +pub const EM_SPARCV9: u16 = 43; +pub const EM_TRICORE: u16 = 44; +pub const EM_ARC: u16 = 45; +pub const EM_H8_300: u16 = 46; +pub const EM_H8_300H: u16 = 47; +pub const EM_H8S: u16 = 48; +pub const EM_H8_500: u16 = 49; +pub const EM_IA_64: u16 = 50; +pub const EM_MIPS_X: u16 = 51; +pub const EM_COLDFIRE: u16 = 52; +pub const EM_68HC12: u16 = 53; +pub const EM_MMA: u16 = 54; +pub const EM_PCP: u16 = 55; +pub const EM_NCPU: u16 = 56; +pub const EM_NDR1: u16 = 57; +pub const EM_STARCORE: u16 = 58; +pub const EM_ME16: u16 = 59; +pub const EM_ST100: u16 = 60; +pub const EM_TINYJ: u16 = 61; +pub const EM_X86_64: u16 = 62; +pub const EM_PDSP: u16 = 63; +pub const EM_FX66: u16 = 66; +pub const EM_ST9PLUS: u16 = 67; +pub const EM_ST7: u16 = 68; +pub const EM_68HC16: u16 = 69; +pub const EM_68HC11: u16 = 70; +pub const EM_68HC08: u16 = 71; +pub const EM_68HC05: u16 = 72; +pub const EM_SVX: u16 = 73; +pub const EM_ST19: u16 = 74; +pub const EM_VAX: u16 = 75; +pub const EM_CRIS: u16 = 76; +pub const EM_JAVELIN: u16 = 77; +pub const EM_FIREPATH: u16 = 78; +pub const EM_ZSP: u16 = 79; +pub const EM_MMIX: u16 = 80; +pub const EM_HUANY: u16 = 81; +pub const EM_PRISM: u16 = 82; +pub const EM_AVR: u16 = 83; +pub const EM_FR30: u16 = 84; +pub const EM_D10V: u16 = 85; +pub const EM_D30V: u16 = 86; +pub const EM_V850: u16 = 87; +pub const EM_M32R: u16 = 88; +pub const EM_MN10300: u16 = 89; +pub const EM_MN10200: u16 = 90; +pub const EM_PJ: u16 = 91; +#[cfg(not(target_env = "uclibc"))] +pub const EM_OPENRISC: u16 = 92; +#[cfg(target_env = "uclibc")] +pub const EM_OR1K: u16 = 92; +#[cfg(not(target_env = "uclibc"))] +pub const EM_ARC_A5: u16 = 93; +pub const EM_XTENSA: u16 = 94; +pub const EM_AARCH64: u16 = 183; +pub const EM_TILEPRO: u16 = 188; +pub const EM_TILEGX: u16 = 191; +pub const EM_RISCV: u16 = 243; +pub const EM_ALPHA: u16 = 0x9026; + +// elf.h - Legal values for e_version (version). +pub const EV_NONE: u32 = 0; +pub const EV_CURRENT: u32 = 1; +pub const EV_NUM: u32 = 2; + +// elf.h - Legal values for p_type (segment type). +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_NUM: u32 = 8; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_STACK: u32 = 0x6474e551; +pub const PT_GNU_RELRO: u32 = 0x6474e552; +pub const PT_LOSUNW: u32 = 0x6ffffffa; +pub const PT_SUNWBSS: u32 = 0x6ffffffa; +pub const PT_SUNWSTACK: u32 = 0x6ffffffb; +pub const PT_HISUNW: u32 = 0x6fffffff; +pub const PT_HIOS: u32 = 0x6fffffff; +pub const PT_LOPROC: u32 = 0x70000000; +pub const PT_HIPROC: u32 = 0x7fffffff; + +// Legal values for p_flags (segment flags). +pub const PF_X: u32 = 1 << 0; +pub const PF_W: u32 = 1 << 1; +pub const PF_R: u32 = 1 << 2; +pub const PF_MASKOS: u32 = 0x0ff00000; +pub const PF_MASKPROC: u32 = 0xf0000000; + +// elf.h - Legal values for a_type (entry type). +pub const AT_NULL: c_ulong = 0; +pub const AT_IGNORE: c_ulong = 1; +pub const AT_EXECFD: c_ulong = 2; +pub const AT_PHDR: c_ulong = 3; +pub const AT_PHENT: c_ulong = 4; +pub const AT_PHNUM: c_ulong = 5; +pub const AT_PAGESZ: c_ulong = 6; +pub const AT_BASE: c_ulong = 7; +pub const AT_FLAGS: c_ulong = 8; +pub const AT_ENTRY: c_ulong = 9; +pub const AT_NOTELF: c_ulong = 10; +pub const AT_UID: c_ulong = 11; +pub const AT_EUID: c_ulong = 12; +pub const AT_GID: c_ulong = 13; +pub const AT_EGID: c_ulong = 14; +pub const AT_PLATFORM: c_ulong = 15; +pub const AT_HWCAP: c_ulong = 16; +pub const AT_CLKTCK: c_ulong = 17; + +pub const AT_SECURE: c_ulong = 23; +pub const AT_BASE_PLATFORM: c_ulong = 24; +pub const AT_RANDOM: c_ulong = 25; +pub const AT_HWCAP2: c_ulong = 26; + +pub const AT_HWCAP3: c_ulong = 29; +pub const AT_HWCAP4: c_ulong = 30; +pub const AT_EXECFN: c_ulong = 31; + +// defined in arch//include/uapi/asm/auxvec.h but has the same value +// wherever it is defined. +pub const AT_SYSINFO_EHDR: c_ulong = 33; +#[cfg(not(target_env = "uclibc"))] +pub const AT_MINSIGSTKSZ: c_ulong = 51; + +pub const GLOB_ERR: c_int = 1 << 0; +pub const GLOB_MARK: c_int = 1 << 1; +pub const GLOB_NOSORT: c_int = 1 << 2; +pub const GLOB_DOOFFS: c_int = 1 << 3; +pub const GLOB_NOCHECK: c_int = 1 << 4; +pub const GLOB_APPEND: c_int = 1 << 5; +pub const GLOB_NOESCAPE: c_int = 1 << 6; + +pub const GLOB_NOSPACE: c_int = 1; +pub const GLOB_ABORTED: c_int = 2; +pub const GLOB_NOMATCH: c_int = 3; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const S_IEXEC: crate::mode_t = 0o0100; +pub const S_IWRITE: crate::mode_t = 0o0200; +pub const S_IREAD: crate::mode_t = 0o0400; + +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; +pub const ST_NODEV: c_ulong = 4; +pub const ST_NOEXEC: c_ulong = 8; +pub const ST_SYNCHRONOUS: c_ulong = 16; +pub const ST_MANDLOCK: c_ulong = 64; +pub const ST_WRITE: c_ulong = 128; +pub const ST_APPEND: c_ulong = 256; +pub const ST_IMMUTABLE: c_ulong = 512; +pub const ST_NOATIME: c_ulong = 1024; +pub const ST_NODIRATIME: c_ulong = 2048; + +pub const RTLD_NEXT: *mut c_void = -1i64 as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_NOW: c_int = 0x2; + +pub const AT_EACCESS: c_int = 0x200; + +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1; +pub const PTHREAD_ONCE_INIT: crate::pthread_once_t = 0; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +#[cfg(not(target_env = "uclibc"))] +pub const PTHREAD_MUTEX_STALLED: c_int = 0; +#[cfg(not(target_env = "uclibc"))] +pub const PTHREAD_MUTEX_ROBUST: c_int = 1; +#[cfg(not(target_env = "uclibc"))] +pub const PTHREAD_PRIO_NONE: c_int = 0; +#[cfg(not(target_env = "uclibc"))] +pub const PTHREAD_PRIO_INHERIT: c_int = 1; +#[cfg(not(target_env = "uclibc"))] +pub const PTHREAD_PRIO_PROTECT: c_int = 2; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const PTHREAD_INHERIT_SCHED: c_int = 0; +pub const PTHREAD_EXPLICIT_SCHED: c_int = 1; +#[cfg(not(all(target_os = "l4re", target_env = "uclibc")))] +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +// netinet/in.h +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +#[deprecated( + since = "0.2.80", + note = "This value was increased in the newer kernel \ + and we'll change this following upstream in the future release. \ + See #1896 for more info." +)] +pub const IPPROTO_MAX: c_int = 256; + +// System V IPC +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_CREAT: c_int = 0o1000; +pub const IPC_EXCL: c_int = 0o2000; +pub const IPC_NOWAIT: c_int = 0o4000; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = if cfg!(musl_redir_time64) { 0x102 } else { 2 }; +pub const IPC_INFO: c_int = 3; + +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; + +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_REMAP: c_int = 0o40000; +pub const SHM_LOCK: c_int = 11; +pub const SHM_UNLOCK: c_int = 12; +pub const SHM_HUGETLB: c_int = 0o4000; +#[cfg(not(all(target_env = "uclibc", target_arch = "mips")))] +pub const SHM_NORESERVE: c_int = 0o10000; + +pub const LOG_NFACILITIES: c_int = 24; + +pub const SEM_FAILED: *mut crate::sem_t = ptr::null_mut(); + +pub const AI_PASSIVE: c_int = 0x0001; +pub const AI_CANONNAME: c_int = 0x0002; +pub const AI_NUMERICHOST: c_int = 0x0004; +pub const AI_V4MAPPED: c_int = 0x0008; +pub const AI_ALL: c_int = 0x0010; +pub const AI_ADDRCONFIG: c_int = 0x0020; + +pub const AI_NUMERICSERV: c_int = 0x0400; + +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_NODATA: c_int = -5; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_SYSTEM: c_int = -11; +pub const EAI_OVERFLOW: c_int = -12; + +pub const NI_NUMERICHOST: c_int = 1; +pub const NI_NUMERICSERV: c_int = 2; +pub const NI_NOFQDN: c_int = 4; +pub const NI_NAMEREQD: c_int = 8; +pub const NI_DGRAM: c_int = 16; +#[cfg(not(target_env = "uclibc"))] +pub const NI_IDN: c_int = 32; + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + pub const AIO_CANCELED: c_int = 0; + pub const AIO_NOTCANCELED: c_int = 1; + pub const AIO_ALLDONE: c_int = 2; + pub const LIO_READ: c_int = 0; + pub const LIO_WRITE: c_int = 1; + pub const LIO_NOP: c_int = 2; + pub const LIO_WAIT: c_int = 0; + pub const LIO_NOWAIT: c_int = 1; + pub const RUSAGE_THREAD: c_int = 1; + pub const MSG_COPY: c_int = 0o40000; + pub const SHM_EXEC: c_int = 0o100000; + pub const IPV6_MULTICAST_ALL: c_int = 29; + pub const IPV6_ROUTER_ALERT_ISOLATE: c_int = 30; + pub const PACKET_MR_UNICAST: c_int = 3; + pub const PTRACE_EVENT_STOP: c_int = 128; + pub const UDP_SEGMENT: c_int = 103; + pub const UDP_GRO: c_int = 104; + } +} + +pub const PR_SET_PDEATHSIG: c_int = 1; +pub const PR_GET_PDEATHSIG: c_int = 2; + +pub const PR_GET_DUMPABLE: c_int = 3; +pub const PR_SET_DUMPABLE: c_int = 4; + +pub const PR_GET_UNALIGN: c_int = 5; +pub const PR_SET_UNALIGN: c_int = 6; +pub const PR_UNALIGN_NOPRINT: c_int = 1; +pub const PR_UNALIGN_SIGBUS: c_int = 2; + +pub const PR_GET_KEEPCAPS: c_int = 7; +pub const PR_SET_KEEPCAPS: c_int = 8; + +pub const PR_GET_FPEMU: c_int = 9; +pub const PR_SET_FPEMU: c_int = 10; +pub const PR_FPEMU_NOPRINT: c_int = 1; +pub const PR_FPEMU_SIGFPE: c_int = 2; + +pub const PR_GET_FPEXC: c_int = 11; +pub const PR_SET_FPEXC: c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: c_int = 0x80; +pub const PR_FP_EXC_DIV: c_int = 0x010000; +pub const PR_FP_EXC_OVF: c_int = 0x020000; +pub const PR_FP_EXC_UND: c_int = 0x040000; +pub const PR_FP_EXC_RES: c_int = 0x080000; +pub const PR_FP_EXC_INV: c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: c_int = 0; +pub const PR_FP_EXC_NONRECOV: c_int = 1; +pub const PR_FP_EXC_ASYNC: c_int = 2; +pub const PR_FP_EXC_PRECISE: c_int = 3; + +pub const PR_GET_TIMING: c_int = 13; +pub const PR_SET_TIMING: c_int = 14; +pub const PR_TIMING_STATISTICAL: c_int = 0; +pub const PR_TIMING_TIMESTAMP: c_int = 1; + +pub const PR_SET_NAME: c_int = 15; +pub const PR_GET_NAME: c_int = 16; + +pub const PR_GET_ENDIAN: c_int = 19; +pub const PR_SET_ENDIAN: c_int = 20; +pub const PR_ENDIAN_BIG: c_int = 0; +pub const PR_ENDIAN_LITTLE: c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: c_int = 2; + +pub const PR_GET_SECCOMP: c_int = 21; +pub const PR_SET_SECCOMP: c_int = 22; + +pub const PR_CAPBSET_READ: c_int = 23; +pub const PR_CAPBSET_DROP: c_int = 24; + +pub const PR_GET_TSC: c_int = 25; +pub const PR_SET_TSC: c_int = 26; +pub const PR_TSC_ENABLE: c_int = 1; +pub const PR_TSC_SIGSEGV: c_int = 2; + +pub const PR_GET_SECUREBITS: c_int = 27; +pub const PR_SET_SECUREBITS: c_int = 28; + +pub const PR_SET_TIMERSLACK: c_int = 29; +pub const PR_GET_TIMERSLACK: c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; + +pub const PR_MCE_KILL: c_int = 33; +pub const PR_MCE_KILL_CLEAR: c_int = 0; +pub const PR_MCE_KILL_SET: c_int = 1; + +pub const PR_MCE_KILL_LATE: c_int = 0; +pub const PR_MCE_KILL_EARLY: c_int = 1; +pub const PR_MCE_KILL_DEFAULT: c_int = 2; + +pub const PR_MCE_KILL_GET: c_int = 34; + +pub const PR_SET_MM: c_int = 35; +pub const PR_SET_MM_START_CODE: c_int = 1; +pub const PR_SET_MM_END_CODE: c_int = 2; +pub const PR_SET_MM_START_DATA: c_int = 3; +pub const PR_SET_MM_END_DATA: c_int = 4; +pub const PR_SET_MM_START_STACK: c_int = 5; +pub const PR_SET_MM_START_BRK: c_int = 6; +pub const PR_SET_MM_BRK: c_int = 7; +pub const PR_SET_MM_ARG_START: c_int = 8; +pub const PR_SET_MM_ARG_END: c_int = 9; +pub const PR_SET_MM_ENV_START: c_int = 10; +pub const PR_SET_MM_ENV_END: c_int = 11; +pub const PR_SET_MM_AUXV: c_int = 12; +pub const PR_SET_MM_EXE_FILE: c_int = 13; +pub const PR_SET_MM_MAP: c_int = 14; +pub const PR_SET_MM_MAP_SIZE: c_int = 15; + +pub const PR_SET_PTRACER: c_int = 0x59616d61; +pub const PR_SET_PTRACER_ANY: c_ulong = 0xffffffffffffffff; + +pub const PR_SET_CHILD_SUBREAPER: c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: c_int = 39; + +pub const PR_GET_TID_ADDRESS: c_int = 40; + +pub const PR_SET_THP_DISABLE: c_int = 41; +pub const PR_GET_THP_DISABLE: c_int = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT: c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: c_int = 44; + +pub const PR_SET_FP_MODE: c_int = 45; +pub const PR_GET_FP_MODE: c_int = 46; +pub const PR_FP_MODE_FR: c_int = 1 << 0; +pub const PR_FP_MODE_FRE: c_int = 1 << 1; + +pub const PR_CAP_AMBIENT: c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: c_int = 4; + +pub const PR_SET_VMA: c_int = 0x53564d41; +pub const PR_SET_VMA_ANON_NAME: c_int = 0; + +pub const PR_SCHED_CORE: c_int = 62; +pub const PR_SCHED_CORE_GET: c_int = 0; +pub const PR_SCHED_CORE_CREATE: c_int = 1; +pub const PR_SCHED_CORE_SHARE_TO: c_int = 2; +pub const PR_SCHED_CORE_SHARE_FROM: c_int = 3; +pub const PR_SCHED_CORE_MAX: c_int = 4; +pub const PR_SCHED_CORE_SCOPE_THREAD: c_int = 0; +pub const PR_SCHED_CORE_SCOPE_THREAD_GROUP: c_int = 1; +pub const PR_SCHED_CORE_SCOPE_PROCESS_GROUP: c_int = 2; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +pub const IPV6_RTHDR_LOOSE: c_int = 0; +pub const IPV6_RTHDR_STRICT: c_int = 1; + +pub const IUTF8: crate::tcflag_t = 0x00004000; +#[cfg(not(all(target_env = "uclibc", target_arch = "mips")))] +pub const CMSPAR: crate::tcflag_t = 0o10000000000; + +pub const MFD_CLOEXEC: c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: c_uint = 0x0002; +pub const MFD_HUGETLB: c_uint = 0x0004; +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + pub const MFD_NOEXEC_SEAL: c_uint = 0x0008; + pub const MFD_EXEC: c_uint = 0x0010; + pub const MFD_HUGE_64KB: c_uint = 0x40000000; + pub const MFD_HUGE_512KB: c_uint = 0x4c000000; + pub const MFD_HUGE_1MB: c_uint = 0x50000000; + pub const MFD_HUGE_2MB: c_uint = 0x54000000; + pub const MFD_HUGE_8MB: c_uint = 0x5c000000; + pub const MFD_HUGE_16MB: c_uint = 0x60000000; + pub const MFD_HUGE_32MB: c_uint = 0x64000000; + pub const MFD_HUGE_256MB: c_uint = 0x70000000; + pub const MFD_HUGE_512MB: c_uint = 0x74000000; + pub const MFD_HUGE_1GB: c_uint = 0x78000000; + pub const MFD_HUGE_2GB: c_uint = 0x7c000000; + pub const MFD_HUGE_16GB: c_uint = 0x88000000; + pub const MFD_HUGE_MASK: c_uint = 63; + pub const MFD_HUGE_SHIFT: c_uint = 26; + } +} + +// linux/if_packet.h +pub const PACKET_HOST: c_uchar = 0; +pub const PACKET_BROADCAST: c_uchar = 1; +pub const PACKET_MULTICAST: c_uchar = 2; +pub const PACKET_OTHERHOST: c_uchar = 3; +pub const PACKET_OUTGOING: c_uchar = 4; +pub const PACKET_LOOPBACK: c_uchar = 5; +#[cfg(not(target_os = "l4re"))] +pub const PACKET_USER: c_uchar = 6; +#[cfg(not(target_os = "l4re"))] +pub const PACKET_KERNEL: c_uchar = 7; + +pub const PACKET_ADD_MEMBERSHIP: c_int = 1; +pub const PACKET_DROP_MEMBERSHIP: c_int = 2; +pub const PACKET_RECV_OUTPUT: c_int = 3; +pub const PACKET_RX_RING: c_int = 5; +pub const PACKET_STATISTICS: c_int = 6; +cfg_if! { + if #[cfg(not(target_os = "l4re"))] { + pub const PACKET_COPY_THRESH: c_int = 7; + pub const PACKET_AUXDATA: c_int = 8; + pub const PACKET_ORIGDEV: c_int = 9; + pub const PACKET_VERSION: c_int = 10; + pub const PACKET_HDRLEN: c_int = 11; + pub const PACKET_RESERVE: c_int = 12; + pub const PACKET_TX_RING: c_int = 13; + pub const PACKET_LOSS: c_int = 14; + pub const PACKET_VNET_HDR: c_int = 15; + pub const PACKET_TX_TIMESTAMP: c_int = 16; + pub const PACKET_TIMESTAMP: c_int = 17; + } +} + +pub const PACKET_MR_MULTICAST: c_int = 0; +pub const PACKET_MR_PROMISC: c_int = 1; +pub const PACKET_MR_ALLMULTI: c_int = 2; + +pub const SIOCADDRT: c_ulong = 0x0000890B; +pub const SIOCDELRT: c_ulong = 0x0000890C; +pub const SIOCGIFNAME: c_ulong = 0x00008910; +pub const SIOCSIFLINK: c_ulong = 0x00008911; +pub const SIOCGIFCONF: c_ulong = 0x00008912; +pub const SIOCGIFFLAGS: c_ulong = 0x00008913; +pub const SIOCSIFFLAGS: c_ulong = 0x00008914; +pub const SIOCGIFADDR: c_ulong = 0x00008915; +pub const SIOCSIFADDR: c_ulong = 0x00008916; +pub const SIOCGIFDSTADDR: c_ulong = 0x00008917; +pub const SIOCSIFDSTADDR: c_ulong = 0x00008918; +pub const SIOCGIFBRDADDR: c_ulong = 0x00008919; +pub const SIOCSIFBRDADDR: c_ulong = 0x0000891A; +pub const SIOCGIFNETMASK: c_ulong = 0x0000891B; +pub const SIOCSIFNETMASK: c_ulong = 0x0000891C; +pub const SIOCGIFMETRIC: c_ulong = 0x0000891D; +pub const SIOCSIFMETRIC: c_ulong = 0x0000891E; +pub const SIOCGIFMEM: c_ulong = 0x0000891F; +pub const SIOCSIFMEM: c_ulong = 0x00008920; +pub const SIOCGIFMTU: c_ulong = 0x00008921; +pub const SIOCSIFMTU: c_ulong = 0x00008922; +pub const SIOCSIFNAME: c_ulong = 0x00008923; +pub const SIOCSIFHWADDR: c_ulong = 0x00008924; +pub const SIOCGIFENCAP: c_ulong = 0x00008925; +pub const SIOCSIFENCAP: c_ulong = 0x00008926; +pub const SIOCGIFHWADDR: c_ulong = 0x00008927; +pub const SIOCGIFSLAVE: c_ulong = 0x00008929; +pub const SIOCSIFSLAVE: c_ulong = 0x00008930; +pub const SIOCADDMULTI: c_ulong = 0x00008931; +pub const SIOCDELMULTI: c_ulong = 0x00008932; +pub const SIOCGIFINDEX: c_ulong = 0x00008933; +pub const SIOGIFINDEX: c_ulong = SIOCGIFINDEX; +pub const SIOCSIFPFLAGS: c_ulong = 0x00008934; +pub const SIOCGIFPFLAGS: c_ulong = 0x00008935; +pub const SIOCDIFADDR: c_ulong = 0x00008936; +pub const SIOCSIFHWBROADCAST: c_ulong = 0x00008937; +pub const SIOCGIFCOUNT: c_ulong = 0x00008938; +pub const SIOCGIFBR: c_ulong = 0x00008940; +pub const SIOCSIFBR: c_ulong = 0x00008941; +pub const SIOCGIFTXQLEN: c_ulong = 0x00008942; +pub const SIOCSIFTXQLEN: c_ulong = 0x00008943; +cfg_if! { + if #[cfg(not(target_os = "l4re"))] { + pub const SIOCETHTOOL: c_ulong = 0x00008946; + pub const SIOCGMIIPHY: c_ulong = 0x00008947; + pub const SIOCGMIIREG: c_ulong = 0x00008948; + pub const SIOCSMIIREG: c_ulong = 0x00008949; + pub const SIOCWANDEV: c_ulong = 0x0000894A; + pub const SIOCOUTQNSD: c_ulong = 0x0000894B; + pub const SIOCGSKNS: c_ulong = 0x0000894C; + } +} +pub const SIOCDARP: c_ulong = 0x00008953; +pub const SIOCGARP: c_ulong = 0x00008954; +pub const SIOCSARP: c_ulong = 0x00008955; +pub const SIOCDRARP: c_ulong = 0x00008960; +pub const SIOCGRARP: c_ulong = 0x00008961; +pub const SIOCSRARP: c_ulong = 0x00008962; +pub const SIOCGIFMAP: c_ulong = 0x00008970; +pub const SIOCSIFMAP: c_ulong = 0x00008971; + +pub const IPTOS_TOS_MASK: u8 = 0x1E; +pub const IPTOS_PREC_MASK: u8 = 0xE0; + +pub const IPTOS_ECN_NOT_ECT: u8 = 0x00; + +pub const RTF_UP: c_ushort = 0x0001; +pub const RTF_GATEWAY: c_ushort = 0x0002; + +pub const RTF_HOST: c_ushort = 0x0004; +pub const RTF_REINSTATE: c_ushort = 0x0008; +pub const RTF_DYNAMIC: c_ushort = 0x0010; +pub const RTF_MODIFIED: c_ushort = 0x0020; +pub const RTF_MTU: c_ushort = 0x0040; +pub const RTF_MSS: c_ushort = RTF_MTU; +pub const RTF_WINDOW: c_ushort = 0x0080; +pub const RTF_IRTT: c_ushort = 0x0100; +pub const RTF_REJECT: c_ushort = 0x0200; +pub const RTF_STATIC: c_ushort = 0x0400; +pub const RTF_XRESOLVE: c_ushort = 0x0800; +pub const RTF_NOFORWARD: c_ushort = 0x1000; +pub const RTF_THROW: c_ushort = 0x2000; +pub const RTF_NOPMTUDISC: c_ushort = 0x4000; + +pub const RTF_DEFAULT: u32 = 0x00010000; +pub const RTF_ALLONLINK: u32 = 0x00020000; +pub const RTF_ADDRCONF: u32 = 0x00040000; +pub const RTF_LINKRT: u32 = 0x00100000; +pub const RTF_NONEXTHOP: u32 = 0x00200000; +pub const RTF_CACHE: u32 = 0x01000000; +pub const RTF_FLOW: u32 = 0x02000000; +pub const RTF_POLICY: u32 = 0x04000000; + +pub const RTCF_VALVE: u32 = 0x00200000; +pub const RTCF_MASQ: u32 = 0x00400000; +pub const RTCF_NAT: u32 = 0x00800000; +pub const RTCF_DOREDIRECT: u32 = 0x01000000; +pub const RTCF_LOG: u32 = 0x02000000; +pub const RTCF_DIRECTSRC: u32 = 0x04000000; + +pub const RTF_LOCAL: u32 = 0x80000000; +pub const RTF_INTERFACE: u32 = 0x40000000; +pub const RTF_MULTICAST: u32 = 0x20000000; +pub const RTF_BROADCAST: u32 = 0x10000000; +pub const RTF_NAT: u32 = 0x08000000; +pub const RTF_ADDRCLASSMASK: u32 = 0xF8000000; + +pub const RT_CLASS_UNSPEC: u8 = 0; +pub const RT_CLASS_DEFAULT: u8 = 253; +pub const RT_CLASS_MAIN: u8 = 254; +pub const RT_CLASS_LOCAL: u8 = 255; +pub const RT_CLASS_MAX: u8 = 255; + +pub const MAX_ADDR_LEN: usize = 7; +pub const ARPD_UPDATE: c_ushort = 0x01; +pub const ARPD_LOOKUP: c_ushort = 0x02; +pub const ARPD_FLUSH: c_ushort = 0x03; +pub const ATF_MAGIC: c_int = 0x80; + +// include/uapi/linux/udp.h +pub const UDP_CORK: c_int = 1; +pub const UDP_ENCAP: c_int = 100; +pub const UDP_NO_CHECK6_TX: c_int = 101; +pub const UDP_NO_CHECK6_RX: c_int = 102; + +// include/uapi/asm-generic/mman-common.h +pub const MAP_FIXED_NOREPLACE: c_int = 0x100000; +pub const MLOCK_ONFAULT: c_uint = 0x01; + +pub const REG_EXTENDED: c_int = 1; +pub const REG_ICASE: c_int = 2; +pub const REG_NEWLINE: c_int = 4; +pub const REG_NOSUB: c_int = 8; + +pub const REG_NOTBOL: c_int = 1; +pub const REG_NOTEOL: c_int = 2; + +pub const REG_ENOSYS: c_int = -1; +pub const REG_NOMATCH: c_int = 1; +pub const REG_BADPAT: c_int = 2; +pub const REG_ECOLLATE: c_int = 3; +pub const REG_ECTYPE: c_int = 4; +pub const REG_EESCAPE: c_int = 5; +pub const REG_ESUBREG: c_int = 6; +pub const REG_EBRACK: c_int = 7; +pub const REG_EPAREN: c_int = 8; +pub const REG_EBRACE: c_int = 9; +pub const REG_BADBR: c_int = 10; +pub const REG_ERANGE: c_int = 11; +pub const REG_ESPACE: c_int = 12; +pub const REG_BADRPT: c_int = 13; + +// errno.h +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const CSIGNAL: c_int = 0x000000ff; + +#[cfg(not(target_os = "l4re"))] +pub const SCHED_NORMAL: c_int = 0; +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_BATCH: c_int = 3; +pub const SCHED_IDLE: c_int = 5; +pub const SCHED_DEADLINE: c_int = 6; + +pub const SCHED_RESET_ON_FORK: c_int = 0x40000000; + +// elf.h +pub const NT_PRSTATUS: c_int = 1; +#[cfg(not(target_os = "l4re"))] +pub const NT_PRFPREG: c_int = 2; +pub const NT_FPREGSET: c_int = 2; +pub const NT_PRPSINFO: c_int = 3; +#[cfg(not(target_os = "l4re"))] +pub const NT_PRXREG: c_int = 4; +pub const NT_TASKSTRUCT: c_int = 4; +pub const NT_PLATFORM: c_int = 5; +pub const NT_AUXV: c_int = 6; +pub const NT_GWINDOWS: c_int = 7; +pub const NT_ASRS: c_int = 8; +pub const NT_PSTATUS: c_int = 10; +pub const NT_PSINFO: c_int = 13; +pub const NT_PRCRED: c_int = 14; +pub const NT_UTSNAME: c_int = 15; +pub const NT_LWPSTATUS: c_int = 16; +pub const NT_LWPSINFO: c_int = 17; +pub const NT_PRFPXREG: c_int = 20; + +pub const MS_NOUSER: c_ulong = 0xffffffff80000000; + +f! { + pub fn CMSG_NXTHDR( + mhdr: *const crate::msghdr, + cmsg: *const crate::cmsghdr, + ) -> *mut crate::cmsghdr { + if ((*cmsg).cmsg_len as usize) < size_of::() { + return core::ptr::null_mut::(); + } + + // FIXME(msrv): `.wrapping_byte_add()` stabilized in 1.75 + let next_cmsg = cmsg + .cast::() + .wrapping_add(super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) + .cast::(); + + // In case the addition wrapped. `next_addr > max_addr` + // would otherwise not work as intended. + if (next_cmsg as usize) < (cmsg as usize) { + return core::ptr::null_mut(); + } + + let mut max_addr = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + + if cfg!(any(target_env = "musl", target_env = "ohos")) { + // musl and some of its descendants do `>= max_addr` + // comparisons in the if statement below. + // https://www.openwall.com/lists/musl/2025/12/27/1 + max_addr -= 1; + } + + if next_cmsg as usize + size_of::() > max_addr { + core::ptr::null_mut::() + } else { + next_cmsg as *mut crate::cmsghdr + } + } + + pub fn CPU_ALLOC_SIZE(count: c_int) -> size_t { + let _dummy: cpu_set_t = mem::zeroed(); + let size_in_bits = 8 * size_of_val(&_dummy.bits[0]); + ((count as size_t + size_in_bits - 1) / 8) as size_t + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in &mut cpuset.bits { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_COUNT_S(size: usize, cpuset: &cpu_set_t) -> c_int { + let mut s: u32 = 0; + let size_of_mask = size_of_val(&cpuset.bits[0]); + for i in &cpuset.bits[..(size / size_of_mask)] { + s += i.count_ones(); + } + s as c_int + } + + pub fn CPU_COUNT(cpuset: &cpu_set_t) -> c_int { + CPU_COUNT_S(size_of::(), cpuset) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn IPTOS_TOS(tos: u8) -> u8 { + tos & IPTOS_TOS_MASK + } + + pub fn IPTOS_PREC(tos: u8) -> u8 { + tos & IPTOS_PREC_MASK + } + + pub fn RT_TOS(tos: u8) -> u8 { + tos & crate::IPTOS_TOS_MASK + } + + pub fn RT_ADDRCLASS(flags: u32) -> u32 { + flags >> 23 + } + + pub fn RT_LOCALADDR(flags: u32) -> bool { + (flags & RTF_ADDRCLASSMASK) == (RTF_LOCAL | RTF_INTERFACE) + } + + pub fn ELF32_R_SYM(val: Elf32_Word) -> Elf32_Word { + val >> 8 + } + + pub fn ELF32_R_TYPE(val: Elf32_Word) -> Elf32_Word { + val & 0xff + } + + pub fn ELF32_R_INFO(sym: Elf32_Word, t: Elf32_Word) -> Elf32_Word { + sym << (8 + t) & 0xff + } + + pub fn ELF64_R_SYM(val: Elf64_Xword) -> Elf64_Xword { + val >> 32 + } + + pub fn ELF64_R_TYPE(val: Elf64_Xword) -> Elf64_Xword { + val & 0xffffffff + } + + pub fn ELF64_R_INFO(sym: Elf64_Xword, t: Elf64_Xword) -> Elf64_Xword { + sym << (32 + t) + } +} + +safe_f! { + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as c_uint + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as c_uint + } +} + +cfg_if! { + if #[cfg(all( + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + any(target_arch = "x86_64", target_arch = "x86") + ))] { + extern "C" { + pub fn iopl(level: c_int) -> c_int; + pub fn ioperm(from: c_ulong, num: c_ulong, turn_on: c_int) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(all(not(target_env = "uclibc"), not(target_env = "ohos")))] { + extern "C" { + #[cfg_attr(gnu_file_offset_bits64, link_name = "aio_read64")] + pub fn aio_read(aiocbp: *mut crate::aiocb) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "aio_write64")] + pub fn aio_write(aiocbp: *mut crate::aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut crate::aiocb) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "aio_error64")] + pub fn aio_error(aiocbp: *const crate::aiocb) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "aio_return64")] + pub fn aio_return(aiocbp: *mut crate::aiocb) -> ssize_t; + #[cfg_attr( + any(musl_redir_time64, gnu_time_bits64), + link_name = "__aio_suspend_time64" + )] + pub fn aio_suspend( + aiocb_list: *const *const crate::aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "aio_cancel64")] + pub fn aio_cancel(fd: c_int, aiocbp: *mut crate::aiocb) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "lio_listio64")] + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut crate::aiocb, + nitems: c_int, + sevp: *mut crate::sigevent, + ) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + extern "C" { + #[cfg_attr(gnu_file_offset_bits64, link_name = "pwritev64")] + pub fn pwritev( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: crate::off_t, + ) -> ssize_t; + #[cfg_attr(gnu_file_offset_bits64, link_name = "preadv64")] + pub fn preadv( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: crate::off_t, + ) -> ssize_t; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + pub fn process_vm_readv( + pid: crate::pid_t, + local_iov: *const crate::iovec, + liovcnt: c_ulong, + remote_iov: *const crate::iovec, + riovcnt: c_ulong, + flags: c_ulong, + ) -> isize; + pub fn process_vm_writev( + pid: crate::pid_t, + local_iov: *const crate::iovec, + liovcnt: c_ulong, + remote_iov: *const crate::iovec, + riovcnt: c_ulong, + flags: c_ulong, + ) -> isize; + #[cfg_attr(gnu_time_bits64, link_name = "__futimes64")] + #[cfg_attr(musl_redir_time64, link_name = "__futimes_time64")] + pub fn futimes(fd: c_int, times: *const crate::timeval) -> c_int; + } + } +} + +extern "C" { + #[cfg_attr( + not(any(target_env = "musl", target_env = "ohos")), + link_name = "__xpg_strerror_r" + )] + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn drand48() -> c_double; + pub fn erand48(xseed: *mut c_ushort) -> c_double; + pub fn lrand48() -> c_long; + pub fn nrand48(xseed: *mut c_ushort) -> c_long; + pub fn jrand48(xseed: *mut c_ushort) -> c_long; + pub fn srand48(seed: c_long); + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + #[cfg(not(target_os = "l4re"))] + pub fn setspent(); + #[cfg(not(target_os = "l4re"))] + pub fn endspent(); + #[cfg(not(target_os = "l4re"))] + pub fn getspent() -> *mut spwd; + + pub fn getspnam(name: *const c_char) -> *mut spwd; + + // System V IPC + pub fn shmget(key: crate::key_t, size: size_t, shmflg: c_int) -> c_int; + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + pub fn shmdt(shmaddr: *const c_void) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__shmctl64")] + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn __errno_location() -> *mut c_int; + + // Not available now on Android + pub fn mremap( + addr: *mut c_void, + len: size_t, + new_len: size_t, + flags: c_int, + ... + ) -> *mut c_void; + + #[cfg_attr(gnu_time_bits64, link_name = "__glob64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "glob64" + )] + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__globfree64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "globfree64" + )] + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + + pub fn sched_getaffinity( + pid: crate::pid_t, + cpusetsize: size_t, + cpuset: *mut cpu_set_t, + ) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__settimeofday64")] + #[cfg_attr(musl_redir_time64, link_name = "__settimeofday_time64")] + pub fn settimeofday(tv: *const crate::timeval, tz: *const crate::timezone) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__sem_timedwait64")] + #[cfg_attr(musl_redir_time64, link_name = "__sem_timedwait_time64")] + pub fn sem_timedwait(sem: *mut crate::sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut crate::sem_t, sval: *mut c_int) -> c_int; + pub fn mount( + src: *const c_char, + target: *const c_char, + fstype: *const c_char, + flags: c_ulong, + data: *const c_void, + ) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__prctl_time64")] + pub fn prctl(option: c_int, ...) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__ppoll64")] + #[cfg_attr(musl_redir_time64, link_name = "__ppoll_time64")] + pub fn ppoll( + fds: *mut crate::pollfd, + nfds: crate::nfds_t, + timeout: *const crate::timespec, + sigmask: *const crate::sigset_t, + ) -> c_int; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sysinfo(info: *mut crate::sysinfo) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sem_close(sem: *mut crate::sem_t) -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut crate::sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn sigwait(set: *const crate::sigset_t, sig: *mut c_int) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn( + info: *mut crate::dl_phdr_info, + size: size_t, + data: *mut c_void, + ) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + pub fn setmntent(filename: *const c_char, ty: *const c_char) -> *mut crate::FILE; + pub fn getmntent(stream: *mut crate::FILE) -> *mut crate::mntent; + pub fn addmntent(stream: *mut crate::FILE, mnt: *const crate::mntent) -> c_int; + pub fn endmntent(streamp: *mut crate::FILE) -> c_int; + pub fn hasmntopt(mnt: *const crate::mntent, opt: *const c_char) -> *mut c_char; + + pub fn regcomp(preg: *mut crate::regex_t, pattern: *const c_char, cflags: c_int) -> c_int; + + pub fn regexec( + preg: *const crate::regex_t, + input: *const c_char, + nmatch: size_t, + pmatch: *mut regmatch_t, + eflags: c_int, + ) -> c_int; + + pub fn regerror( + errcode: c_int, + preg: *const crate::regex_t, + errbuf: *mut c_char, + errbuf_size: size_t, + ) -> size_t; + + pub fn regfree(preg: *mut crate::regex_t); + + pub fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> iconv_t; + pub fn iconv( + cd: iconv_t, + inbuf: *mut *mut c_char, + inbytesleft: *mut size_t, + outbuf: *mut *mut c_char, + outbytesleft: *mut size_t, + ) -> size_t; + pub fn iconv_close(cd: iconv_t) -> c_int; + + pub fn gettid() -> crate::pid_t; + + pub fn timer_create( + clockid: crate::clockid_t, + sevp: *mut crate::sigevent, + timerid: *mut crate::timer_t, + ) -> c_int; + pub fn timer_delete(timerid: crate::timer_t) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn timer_getoverrun(timerid: crate::timer_t) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__timer_gettime64" + )] + pub fn timer_gettime(timerid: crate::timer_t, curr_value: *mut crate::itimerspec) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__timer_settime64" + )] + pub fn timer_settime( + timerid: crate::timer_t, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; + + pub fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, + ) -> *mut c_void; + pub fn sched_getcpu() -> c_int; + + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + + #[cfg(not(target_env = "uclibc"))] + pub fn copy_file_range( + fd_in: c_int, + off_in: *mut crate::off64_t, + fd_out: c_int, + off_out: *mut crate::off64_t, + len: size_t, + flags: c_uint, + ) -> ssize_t; +} + +cfg_if! { + if #[cfg(not(any(target_env = "musl", target_env = "ohos")))] { + extern "C" { + pub fn freopen64( + filename: *const c_char, + mode: *const c_char, + file: *mut crate::FILE, + ) -> *mut crate::FILE; + pub fn fseeko64( + stream: *mut crate::FILE, + offset: crate::off64_t, + whence: c_int, + ) -> c_int; + pub fn fsetpos64(stream: *mut crate::FILE, ptr: *const crate::fpos64_t) -> c_int; + pub fn ftello64(stream: *mut crate::FILE) -> crate::off64_t; + } + } +} diff --git a/deps/crates/vendor/libc/src/unix/linux_like/mod.rs b/deps/crates/vendor/libc/src/unix/linux_like/mod.rs new file mode 100644 index 00000000000000..59e16a0f3c4b4d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/linux_like/mod.rs @@ -0,0 +1,2211 @@ +use crate::prelude::*; + +pub type sa_family_t = u16; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type clockid_t = c_int; +pub type timer_t = *mut c_void; +pub type useconds_t = u32; +pub type key_t = c_int; +pub type id_t = c_uint; + +extern_ty! { + pub enum timezone {} +} + +s! { + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreqn { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + pub imr_ifindex: c_int, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + pub imr_sourceaddr: in_addr, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + // The order of the `ai_addr` field in this struct is crucial + // for converting between the Rust and C types. + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + + #[cfg(not(target_os = "android"))] + pub ai_addr: *mut crate::sockaddr, + + pub ai_canonname: *mut c_char, + + #[cfg(target_os = "android")] + pub ai_addr: *mut crate::sockaddr, + + pub ai_next: *mut addrinfo, + } + + pub struct sockaddr_ll { + pub sll_family: c_ushort, + pub sll_protocol: c_ushort, + pub sll_ifindex: c_int, + pub sll_hatype: c_ushort, + pub sll_pkttype: c_uchar, + pub sll_halen: c_uchar, + pub sll_addr: [c_uchar; 8], + } + + pub struct fd_set { + fds_bits: [c_ulong; FD_SETSIZE as usize / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + #[cfg(not(any(target_env = "musl", target_os = "emscripten", target_env = "ohos")))] + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct in_pktinfo { + pub ipi_ifindex: c_int, + pub ipi_spec_dst: crate::in_addr, + pub ipi_addr: crate::in_addr, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_ifu: *mut crate::sockaddr, // FIXME(union) This should be a union + pub ifa_data: *mut c_void, + } + + pub struct in6_rtmsg { + rtmsg_dst: crate::in6_addr, + rtmsg_src: crate::in6_addr, + rtmsg_gateway: crate::in6_addr, + rtmsg_type: u32, + rtmsg_dst_len: u16, + rtmsg_src_len: u16, + rtmsg_metric: u32, + rtmsg_info: c_ulong, + rtmsg_flags: u32, + rtmsg_ifindex: c_int, + } + + pub struct arpreq { + pub arp_pa: crate::sockaddr, + pub arp_ha: crate::sockaddr, + pub arp_flags: c_int, + pub arp_netmask: crate::sockaddr, + pub arp_dev: [c_char; 16], + } + + pub struct arpreq_old { + pub arp_pa: crate::sockaddr, + pub arp_ha: crate::sockaddr, + pub arp_flags: c_int, + pub arp_netmask: crate::sockaddr, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + #[cfg(target_pointer_width = "32")] + __ss_pad2: Padding<[u8; 128 - 2 - 4]>, + #[cfg(target_pointer_width = "64")] + __ss_pad2: Padding<[u8; 128 - 2 - 8]>, + __ss_align: size_t, + } + + pub struct utsname { + pub sysname: [c_char; 65], + pub nodename: [c_char; 65], + pub release: [c_char; 65], + pub version: [c_char; 65], + pub machine: [c_char; 65], + pub domainname: [c_char; 65], + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } +} + +cfg_if! { + if #[cfg(not(any(target_os = "emscripten", target_os = "l4re")))] { + s! { + pub struct file_clone_range { + pub src_fd: crate::__s64, + pub src_offset: crate::__u64, + pub src_length: crate::__u64, + pub dest_offset: crate::__u64, + } + + // linux/filter.h + pub struct sock_filter { + pub code: __u16, + pub jt: __u8, + pub jf: __u8, + pub k: __u32, + } + + pub struct sock_fprog { + pub len: c_ushort, + pub filter: *mut sock_filter, + } + } + } +} + +cfg_if! { + if #[cfg(any( + target_env = "gnu", + target_os = "android", + all(target_env = "musl", musl_v1_2_3) + ))] { + s! { + pub struct statx { + pub stx_mask: crate::__u32, + pub stx_blksize: crate::__u32, + pub stx_attributes: crate::__u64, + pub stx_nlink: crate::__u32, + pub stx_uid: crate::__u32, + pub stx_gid: crate::__u32, + pub stx_mode: crate::__u16, + __statx_pad1: Padding<[crate::__u16; 1]>, + pub stx_ino: crate::__u64, + pub stx_size: crate::__u64, + pub stx_blocks: crate::__u64, + pub stx_attributes_mask: crate::__u64, + pub stx_atime: statx_timestamp, + pub stx_btime: statx_timestamp, + pub stx_ctime: statx_timestamp, + pub stx_mtime: statx_timestamp, + pub stx_rdev_major: crate::__u32, + pub stx_rdev_minor: crate::__u32, + pub stx_dev_major: crate::__u32, + pub stx_dev_minor: crate::__u32, + pub stx_mnt_id: crate::__u64, + pub stx_dio_mem_align: crate::__u32, + pub stx_dio_offset_align: crate::__u32, + __statx_pad3: Padding<[crate::__u64; 12]>, + } + + pub struct statx_timestamp { + pub tv_sec: crate::__s64, + pub tv_nsec: crate::__u32, + __statx_timestamp_pad1: Padding<[crate::__s32; 1]>, + } + } + } +} + +s_no_extra_traits! { + #[cfg_attr( + any(target_arch = "x86_64", all(target_arch = "x86", target_env = "gnu")), + repr(packed) + )] + pub struct epoll_event { + pub events: u32, + pub u64: u64, + } + + pub struct sigevent { + pub sigev_value: crate::sigval, + pub sigev_signo: c_int, + pub sigev_notify: c_int, + // Actually a union. We only expose sigev_notify_thread_id because it's + // the most useful member + pub sigev_notify_thread_id: c_int, + #[cfg(target_pointer_width = "64")] + __unused1: Padding<[c_int; 11]>, + #[cfg(target_pointer_width = "32")] + __unused1: Padding<[c_int; 12]>, + } +} + +cfg_if! { + if #[cfg(all(feature = "extra_traits", not(target_os = "l4re")))] { + impl PartialEq for epoll_event { + fn eq(&self, other: &epoll_event) -> bool { + self.events == other.events && self.u64 == other.u64 + } + } + impl Eq for epoll_event {} + impl hash::Hash for epoll_event { + fn hash(&self, state: &mut H) { + let events = self.events; + let u64 = self.u64; + events.hash(state); + u64.hash(state); + } + } + + impl PartialEq for sigevent { + fn eq(&self, other: &sigevent) -> bool { + self.sigev_value == other.sigev_value + && self.sigev_signo == other.sigev_signo + && self.sigev_notify == other.sigev_notify + && self.sigev_notify_thread_id == other.sigev_notify_thread_id + } + } + impl Eq for sigevent {} + impl hash::Hash for sigevent { + fn hash(&self, state: &mut H) { + self.sigev_value.hash(state); + self.sigev_signo.hash(state); + self.sigev_notify.hash(state); + self.sigev_notify_thread_id.hash(state); + } + } + } +} + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; + +// Linux-specific fcntls +pub const F_SETLEASE: c_int = 1024; +pub const F_GETLEASE: c_int = 1025; +pub const F_NOTIFY: c_int = 1026; +pub const F_CANCELLK: c_int = 1029; +pub const F_DUPFD_CLOEXEC: c_int = 1030; +pub const F_SETPIPE_SZ: c_int = 1031; +pub const F_GETPIPE_SZ: c_int = 1032; +pub const F_ADD_SEALS: c_int = 1033; +pub const F_GET_SEALS: c_int = 1034; + +pub const F_SEAL_SEAL: c_int = 0x0001; +pub const F_SEAL_SHRINK: c_int = 0x0002; +pub const F_SEAL_GROW: c_int = 0x0004; +pub const F_SEAL_WRITE: c_int = 0x0008; + +// FIXME(#235): Include file sealing fcntls once we have a way to verify them. + +pub const SIGTRAP: c_int = 5; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 1; + +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC: crate::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 3; +pub const CLOCK_MONOTONIC_RAW: crate::clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: crate::clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: crate::clockid_t = 6; +pub const CLOCK_BOOTTIME: crate::clockid_t = 7; +pub const CLOCK_REALTIME_ALARM: crate::clockid_t = 8; +pub const CLOCK_BOOTTIME_ALARM: crate::clockid_t = 9; +pub const CLOCK_TAI: crate::clockid_t = 11; +pub const TIMER_ABSTIME: c_int = 1; + +pub const RUSAGE_SELF: c_int = 0; + +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; + +pub const SOCK_CLOEXEC: c_int = O_CLOEXEC; + +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +#[cfg(not(target_os = "l4re"))] +pub const XATTR_CREATE: c_int = 0x1; +#[cfg(not(target_os = "l4re"))] +pub const XATTR_REPLACE: c_int = 0x2; + +cfg_if! { + if #[cfg(target_os = "android")] { + pub const RLIM64_INFINITY: c_ulonglong = !0; + } else { + pub const RLIM64_INFINITY: crate::rlim64_t = !0; + } +} + +cfg_if! { + if #[cfg(target_env = "ohos")] { + pub const LC_CTYPE: c_int = 0; + pub const LC_NUMERIC: c_int = 1; + pub const LC_TIME: c_int = 2; + pub const LC_COLLATE: c_int = 3; + pub const LC_MONETARY: c_int = 4; + pub const LC_MESSAGES: c_int = 5; + pub const LC_PAPER: c_int = 6; + pub const LC_NAME: c_int = 7; + pub const LC_ADDRESS: c_int = 8; + pub const LC_TELEPHONE: c_int = 9; + pub const LC_MEASUREMENT: c_int = 10; + pub const LC_IDENTIFICATION: c_int = 11; + pub const LC_ALL: c_int = 12; + } else if #[cfg(not(target_env = "uclibc"))] { + pub const LC_CTYPE: c_int = 0; + pub const LC_NUMERIC: c_int = 1; + pub const LC_TIME: c_int = 2; + pub const LC_COLLATE: c_int = 3; + pub const LC_MONETARY: c_int = 4; + pub const LC_MESSAGES: c_int = 5; + pub const LC_ALL: c_int = 6; + } +} + +pub const LC_CTYPE_MASK: c_int = 1 << LC_CTYPE; +pub const LC_NUMERIC_MASK: c_int = 1 << LC_NUMERIC; +pub const LC_TIME_MASK: c_int = 1 << LC_TIME; +pub const LC_COLLATE_MASK: c_int = 1 << LC_COLLATE; +pub const LC_MONETARY_MASK: c_int = 1 << LC_MONETARY; +pub const LC_MESSAGES_MASK: c_int = 1 << LC_MESSAGES; +// LC_ALL_MASK defined per platform + +pub const MAP_FILE: c_int = 0x0000; +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +// MS_ flags for msync(2) +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; +pub const MS_SYNC: c_int = 0x0004; + +// MS_ flags for mount(2) +pub const MS_RDONLY: c_ulong = 0x01; +pub const MS_NOSUID: c_ulong = 0x02; +pub const MS_NODEV: c_ulong = 0x04; +pub const MS_NOEXEC: c_ulong = 0x08; +pub const MS_SYNCHRONOUS: c_ulong = 0x10; +pub const MS_REMOUNT: c_ulong = 0x20; +pub const MS_MANDLOCK: c_ulong = 0x40; +pub const MS_DIRSYNC: c_ulong = 0x80; +pub const MS_NOSYMFOLLOW: c_ulong = 0x100; +pub const MS_NOATIME: c_ulong = 0x0400; +pub const MS_NODIRATIME: c_ulong = 0x0800; +pub const MS_BIND: c_ulong = 0x1000; +pub const MS_MOVE: c_ulong = 0x2000; +pub const MS_REC: c_ulong = 0x4000; +pub const MS_SILENT: c_ulong = 0x8000; +pub const MS_POSIXACL: c_ulong = 0x010000; +pub const MS_UNBINDABLE: c_ulong = 0x020000; +pub const MS_PRIVATE: c_ulong = 0x040000; +pub const MS_SLAVE: c_ulong = 0x080000; +pub const MS_SHARED: c_ulong = 0x100000; +pub const MS_RELATIME: c_ulong = 0x200000; +pub const MS_KERNMOUNT: c_ulong = 0x400000; +pub const MS_I_VERSION: c_ulong = 0x800000; +pub const MS_STRICTATIME: c_ulong = 0x1000000; +pub const MS_LAZYTIME: c_ulong = 0x2000000; +pub const MS_ACTIVE: c_ulong = 0x40000000; +pub const MS_MGC_VAL: c_ulong = 0xc0ed0000; +pub const MS_MGC_MSK: c_ulong = 0xffff0000; + +pub const SCM_RIGHTS: c_int = 0x01; +pub const SCM_CREDENTIALS: c_int = 0x02; + +pub const PROT_GROWSDOWN: c_int = 0x1000000; +pub const PROT_GROWSUP: c_int = 0x2000000; + +pub const MAP_TYPE: c_int = 0x000f; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 8; +pub const MADV_REMOVE: c_int = 9; +pub const MADV_DONTFORK: c_int = 10; +pub const MADV_DOFORK: c_int = 11; +pub const MADV_MERGEABLE: c_int = 12; +pub const MADV_UNMERGEABLE: c_int = 13; +pub const MADV_HUGEPAGE: c_int = 14; +pub const MADV_NOHUGEPAGE: c_int = 15; +pub const MADV_DONTDUMP: c_int = 16; +pub const MADV_DODUMP: c_int = 17; +pub const MADV_WIPEONFORK: c_int = 18; +pub const MADV_KEEPONFORK: c_int = 19; +#[cfg(not(target_os = "l4re"))] +pub const MADV_COLD: c_int = 20; +#[cfg(not(target_os = "l4re"))] +pub const MADV_PAGEOUT: c_int = 21; +pub const MADV_HWPOISON: c_int = 100; +cfg_if! { + if #[cfg(not(any(target_os = "emscripten", target_os = "l4re")))] { + pub const MADV_POPULATE_READ: c_int = 22; + pub const MADV_POPULATE_WRITE: c_int = 23; + pub const MADV_DONTNEED_LOCKED: c_int = 24; + } +} + +pub const IFF_UP: c_int = 0x1; +pub const IFF_BROADCAST: c_int = 0x2; +pub const IFF_DEBUG: c_int = 0x4; +pub const IFF_LOOPBACK: c_int = 0x8; +pub const IFF_POINTOPOINT: c_int = 0x10; +pub const IFF_NOTRAILERS: c_int = 0x20; +pub const IFF_RUNNING: c_int = 0x40; +pub const IFF_NOARP: c_int = 0x80; +pub const IFF_PROMISC: c_int = 0x100; +pub const IFF_ALLMULTI: c_int = 0x200; +pub const IFF_MASTER: c_int = 0x400; +pub const IFF_SLAVE: c_int = 0x800; +pub const IFF_MULTICAST: c_int = 0x1000; +pub const IFF_PORTSEL: c_int = 0x2000; +pub const IFF_AUTOMEDIA: c_int = 0x4000; +pub const IFF_DYNAMIC: c_int = 0x8000; + +pub const SOL_IP: c_int = 0; +pub const SOL_TCP: c_int = 6; +pub const SOL_UDP: c_int = 17; +pub const SOL_IPV6: c_int = 41; +pub const SOL_ICMPV6: c_int = 58; +pub const SOL_RAW: c_int = 255; +pub const SOL_DECNET: c_int = 261; +pub const SOL_X25: c_int = 262; +pub const SOL_PACKET: c_int = 263; +pub const SOL_ATM: c_int = 264; +pub const SOL_AAL: c_int = 265; +pub const SOL_IRDA: c_int = 266; +pub const SOL_NETBEUI: c_int = 267; +pub const SOL_LLC: c_int = 268; +pub const SOL_DCCP: c_int = 269; +pub const SOL_NETLINK: c_int = 270; +pub const SOL_TIPC: c_int = 271; +pub const SOL_BLUETOOTH: c_int = 274; +pub const SOL_ALG: c_int = 279; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = 1; +pub const AF_LOCAL: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_AX25: c_int = 3; +pub const AF_IPX: c_int = 4; +pub const AF_APPLETALK: c_int = 5; +pub const AF_NETROM: c_int = 6; +pub const AF_BRIDGE: c_int = 7; +pub const AF_ATMPVC: c_int = 8; +pub const AF_X25: c_int = 9; +pub const AF_INET6: c_int = 10; +pub const AF_ROSE: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_NETBEUI: c_int = 13; +pub const AF_SECURITY: c_int = 14; +pub const AF_KEY: c_int = 15; +pub const AF_NETLINK: c_int = 16; +pub const AF_ROUTE: c_int = AF_NETLINK; +pub const AF_PACKET: c_int = 17; +pub const AF_ASH: c_int = 18; +pub const AF_ECONET: c_int = 19; +pub const AF_ATMSVC: c_int = 20; +pub const AF_RDS: c_int = 21; +pub const AF_SNA: c_int = 22; +pub const AF_IRDA: c_int = 23; +pub const AF_PPPOX: c_int = 24; +pub const AF_WANPIPE: c_int = 25; +pub const AF_LLC: c_int = 26; +pub const AF_CAN: c_int = 29; +pub const AF_TIPC: c_int = 30; +pub const AF_BLUETOOTH: c_int = 31; +pub const AF_IUCV: c_int = 32; +pub const AF_RXRPC: c_int = 33; +pub const AF_ISDN: c_int = 34; +pub const AF_PHONET: c_int = 35; +pub const AF_IEEE802154: c_int = 36; +pub const AF_CAIF: c_int = 37; +pub const AF_ALG: c_int = 38; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_AX25: c_int = AF_AX25; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_NETROM: c_int = AF_NETROM; +pub const PF_BRIDGE: c_int = AF_BRIDGE; +pub const PF_ATMPVC: c_int = AF_ATMPVC; +pub const PF_X25: c_int = AF_X25; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_ROSE: c_int = AF_ROSE; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_NETBEUI: c_int = AF_NETBEUI; +pub const PF_SECURITY: c_int = AF_SECURITY; +pub const PF_KEY: c_int = AF_KEY; +pub const PF_NETLINK: c_int = AF_NETLINK; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_PACKET: c_int = AF_PACKET; +pub const PF_ASH: c_int = AF_ASH; +pub const PF_ECONET: c_int = AF_ECONET; +pub const PF_ATMSVC: c_int = AF_ATMSVC; +pub const PF_RDS: c_int = AF_RDS; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_IRDA: c_int = AF_IRDA; +pub const PF_PPPOX: c_int = AF_PPPOX; +pub const PF_WANPIPE: c_int = AF_WANPIPE; +pub const PF_LLC: c_int = AF_LLC; +pub const PF_CAN: c_int = AF_CAN; +pub const PF_TIPC: c_int = AF_TIPC; +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_IUCV: c_int = AF_IUCV; +pub const PF_RXRPC: c_int = AF_RXRPC; +pub const PF_ISDN: c_int = AF_ISDN; +pub const PF_PHONET: c_int = AF_PHONET; +pub const PF_IEEE802154: c_int = AF_IEEE802154; +pub const PF_CAIF: c_int = AF_CAIF; +pub const PF_ALG: c_int = AF_ALG; + +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTROUTE: c_int = 4; +pub const MSG_CTRUNC: c_int = 8; +pub const MSG_TRUNC: c_int = 0x20; +pub const MSG_DONTWAIT: c_int = 0x40; +pub const MSG_EOR: c_int = 0x80; +pub const MSG_WAITALL: c_int = 0x100; +pub const MSG_FIN: c_int = 0x200; +pub const MSG_SYN: c_int = 0x400; +pub const MSG_CONFIRM: c_int = 0x800; +pub const MSG_RST: c_int = 0x1000; +pub const MSG_ERRQUEUE: c_int = 0x2000; +pub const MSG_NOSIGNAL: c_int = 0x4000; +pub const MSG_MORE: c_int = 0x8000; +pub const MSG_WAITFORONE: c_int = 0x10000; +pub const MSG_FASTOPEN: c_int = 0x20000000; +pub const MSG_CMSG_CLOEXEC: c_int = 0x40000000; + +pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; + +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const IP_TOS: c_int = 1; +pub const IP_TTL: c_int = 2; +pub const IP_HDRINCL: c_int = 3; +pub const IP_OPTIONS: c_int = 4; +pub const IP_ROUTER_ALERT: c_int = 5; +pub const IP_RECVOPTS: c_int = 6; +pub const IP_RETOPTS: c_int = 7; +pub const IP_PKTINFO: c_int = 8; +pub const IP_PKTOPTIONS: c_int = 9; +pub const IP_MTU_DISCOVER: c_int = 10; +pub const IP_RECVERR: c_int = 11; +pub const IP_RECVTTL: c_int = 12; +pub const IP_RECVTOS: c_int = 13; +pub const IP_MTU: c_int = 14; +pub const IP_FREEBIND: c_int = 15; +pub const IP_IPSEC_POLICY: c_int = 16; +pub const IP_XFRM_POLICY: c_int = 17; +pub const IP_PASSSEC: c_int = 18; +pub const IP_TRANSPARENT: c_int = 19; +pub const IP_ORIGDSTADDR: c_int = 20; +pub const IP_RECVORIGDSTADDR: c_int = IP_ORIGDSTADDR; +pub const IP_MINTTL: c_int = 21; +#[cfg(not(target_env = "uclibc"))] +pub const IP_NODEFRAG: c_int = 22; +#[cfg(not(target_env = "uclibc"))] +pub const IP_CHECKSUM: c_int = 23; +#[cfg(not(target_env = "uclibc"))] +pub const IP_BIND_ADDRESS_NO_PORT: c_int = 24; +pub const IP_MULTICAST_IF: c_int = 32; +pub const IP_MULTICAST_TTL: c_int = 33; +pub const IP_MULTICAST_LOOP: c_int = 34; +pub const IP_ADD_MEMBERSHIP: c_int = 35; +pub const IP_DROP_MEMBERSHIP: c_int = 36; +pub const IP_UNBLOCK_SOURCE: c_int = 37; +pub const IP_BLOCK_SOURCE: c_int = 38; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 39; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 40; +pub const IP_MSFILTER: c_int = 41; +pub const IP_MULTICAST_ALL: c_int = 49; +pub const IP_UNICAST_IF: c_int = 50; + +pub const IP_DEFAULT_MULTICAST_TTL: c_int = 1; +pub const IP_DEFAULT_MULTICAST_LOOP: c_int = 1; + +pub const IP_PMTUDISC_DONT: c_int = 0; +pub const IP_PMTUDISC_WANT: c_int = 1; +pub const IP_PMTUDISC_DO: c_int = 2; +pub const IP_PMTUDISC_PROBE: c_int = 3; +#[cfg(not(target_env = "uclibc"))] +pub const IP_PMTUDISC_INTERFACE: c_int = 4; +#[cfg(not(target_env = "uclibc"))] +pub const IP_PMTUDISC_OMIT: c_int = 5; + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: c_int = 2; +/// for compatibility +pub const IPPROTO_IPIP: c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: c_int = 8; +/// pup +pub const IPPROTO_PUP: c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: c_int = 51; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: c_int = 60; +pub const IPPROTO_MTP: c_int = 92; +/// encapsulation header +pub const IPPROTO_ENCAP: c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_COMP: c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: c_int = 132; +pub const IPPROTO_MH: c_int = 135; +pub const IPPROTO_UDPLITE: c_int = 136; +/// raw IP packet +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_BEETPH: c_int = 94; +pub const IPPROTO_MPLS: c_int = 137; +/// Multipath TCP +#[cfg(not(target_os = "l4re"))] +pub const IPPROTO_MPTCP: c_int = 262; +/// Ethernet-within-IPv6 encapsulation. +#[cfg(not(target_os = "l4re"))] +pub const IPPROTO_ETHERNET: c_int = 143; + +pub const MCAST_EXCLUDE: c_int = 0; +pub const MCAST_INCLUDE: c_int = 1; +pub const MCAST_JOIN_GROUP: c_int = 42; +pub const MCAST_BLOCK_SOURCE: c_int = 43; +pub const MCAST_UNBLOCK_SOURCE: c_int = 44; +pub const MCAST_LEAVE_GROUP: c_int = 45; +pub const MCAST_JOIN_SOURCE_GROUP: c_int = 46; +pub const MCAST_LEAVE_SOURCE_GROUP: c_int = 47; +pub const MCAST_MSFILTER: c_int = 48; + +pub const IPV6_ADDRFORM: c_int = 1; +pub const IPV6_2292PKTINFO: c_int = 2; +pub const IPV6_2292HOPOPTS: c_int = 3; +pub const IPV6_2292DSTOPTS: c_int = 4; +pub const IPV6_2292RTHDR: c_int = 5; +pub const IPV6_2292PKTOPTIONS: c_int = 6; +pub const IPV6_CHECKSUM: c_int = 7; +pub const IPV6_2292HOPLIMIT: c_int = 8; +pub const IPV6_NEXTHOP: c_int = 9; +pub const IPV6_AUTHHDR: c_int = 10; +pub const IPV6_UNICAST_HOPS: c_int = 16; +pub const IPV6_MULTICAST_IF: c_int = 17; +pub const IPV6_MULTICAST_HOPS: c_int = 18; +pub const IPV6_MULTICAST_LOOP: c_int = 19; +pub const IPV6_ADD_MEMBERSHIP: c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: c_int = 21; +pub const IPV6_ROUTER_ALERT: c_int = 22; +pub const IPV6_MTU_DISCOVER: c_int = 23; +pub const IPV6_MTU: c_int = 24; +pub const IPV6_RECVERR: c_int = 25; +pub const IPV6_V6ONLY: c_int = 26; +pub const IPV6_JOIN_ANYCAST: c_int = 27; +pub const IPV6_LEAVE_ANYCAST: c_int = 28; +pub const IPV6_IPSEC_POLICY: c_int = 34; +pub const IPV6_XFRM_POLICY: c_int = 35; +pub const IPV6_HDRINCL: c_int = 36; +pub const IPV6_RECVPKTINFO: c_int = 49; +pub const IPV6_PKTINFO: c_int = 50; +pub const IPV6_RECVHOPLIMIT: c_int = 51; +pub const IPV6_HOPLIMIT: c_int = 52; +pub const IPV6_RECVHOPOPTS: c_int = 53; +pub const IPV6_HOPOPTS: c_int = 54; +pub const IPV6_RTHDRDSTOPTS: c_int = 55; +pub const IPV6_RECVRTHDR: c_int = 56; +pub const IPV6_RTHDR: c_int = 57; +pub const IPV6_RECVDSTOPTS: c_int = 58; +pub const IPV6_DSTOPTS: c_int = 59; +#[cfg(not(target_env = "uclibc"))] +pub const IPV6_RECVPATHMTU: c_int = 60; +#[cfg(not(target_env = "uclibc"))] +pub const IPV6_PATHMTU: c_int = 61; +#[cfg(not(target_env = "uclibc"))] +pub const IPV6_DONTFRAG: c_int = 62; +pub const IPV6_RECVTCLASS: c_int = 66; +pub const IPV6_TCLASS: c_int = 67; +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + pub const IPV6_AUTOFLOWLABEL: c_int = 70; + pub const IPV6_ADDR_PREFERENCES: c_int = 72; + pub const IPV6_MINHOPCOUNT: c_int = 73; + pub const IPV6_ORIGDSTADDR: c_int = 74; + pub const IPV6_RECVORIGDSTADDR: c_int = IPV6_ORIGDSTADDR; + pub const IPV6_TRANSPARENT: c_int = 75; + pub const IPV6_UNICAST_IF: c_int = 76; + pub const IPV6_PREFER_SRC_TMP: c_int = 0x0001; + pub const IPV6_PREFER_SRC_PUBLIC: c_int = 0x0002; + pub const IPV6_PREFER_SRC_PUBTMP_DEFAULT: c_int = 0x0100; + pub const IPV6_PREFER_SRC_COA: c_int = 0x0004; + pub const IPV6_PREFER_SRC_HOME: c_int = 0x0400; + pub const IPV6_PREFER_SRC_CGA: c_int = 0x0008; + pub const IPV6_PREFER_SRC_NONCGA: c_int = 0x0800; + } +} + +pub const IPV6_PMTUDISC_DONT: c_int = 0; +pub const IPV6_PMTUDISC_WANT: c_int = 1; +pub const IPV6_PMTUDISC_DO: c_int = 2; +pub const IPV6_PMTUDISC_PROBE: c_int = 3; +pub const IPV6_PMTUDISC_INTERFACE: c_int = 4; +pub const IPV6_PMTUDISC_OMIT: c_int = 5; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; +pub const TCP_CORK: c_int = 3; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; +pub const TCP_SYNCNT: c_int = 7; +pub const TCP_LINGER2: c_int = 8; +pub const TCP_DEFER_ACCEPT: c_int = 9; +pub const TCP_WINDOW_CLAMP: c_int = 10; +pub const TCP_INFO: c_int = 11; +pub const TCP_QUICKACK: c_int = 12; +pub const TCP_CONGESTION: c_int = 13; +pub const TCP_MD5SIG: c_int = 14; +cfg_if! { + if #[cfg(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos") + ))] { + // WARN: deprecated + pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; + } +} +pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16; +pub const TCP_THIN_DUPACK: c_int = 17; +pub const TCP_USER_TIMEOUT: c_int = 18; +pub const TCP_REPAIR: c_int = 19; +pub const TCP_REPAIR_QUEUE: c_int = 20; +pub const TCP_QUEUE_SEQ: c_int = 21; +pub const TCP_REPAIR_OPTIONS: c_int = 22; +pub const TCP_FASTOPEN: c_int = 23; +pub const TCP_TIMESTAMP: c_int = 24; +pub const TCP_NOTSENT_LOWAT: c_int = 25; +pub const TCP_CC_INFO: c_int = 26; +pub const TCP_SAVE_SYN: c_int = 27; +pub const TCP_SAVED_SYN: c_int = 28; +cfg_if! { + if #[cfg(not(target_os = "emscripten"))] { + // NOTE: emscripten doesn't support these options yet. + + pub const TCP_REPAIR_WINDOW: c_int = 29; + pub const TCP_FASTOPEN_CONNECT: c_int = 30; + pub const TCP_ULP: c_int = 31; + pub const TCP_MD5SIG_EXT: c_int = 32; + pub const TCP_FASTOPEN_KEY: c_int = 33; + pub const TCP_FASTOPEN_NO_COOKIE: c_int = 34; + pub const TCP_ZEROCOPY_RECEIVE: c_int = 35; + pub const TCP_INQ: c_int = 36; + pub const TCP_CM_INQ: c_int = TCP_INQ; + // NOTE: Some CI images doesn't have this option yet. + // pub const TCP_TX_DELAY: c_int = 37; + pub const TCP_MD5SIG_MAXKEYLEN: usize = 80; + } +} + +pub const SO_DEBUG: c_int = 1; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 2; + +pub const NAME_MAX: c_int = 255; +pub const PATH_MAX: c_int = 4096; + +pub const UIO_MAXIOV: c_int = 1024; + +pub const FD_SETSIZE: usize = 1024; + +pub const EPOLLIN: c_int = 0x1; +pub const EPOLLPRI: c_int = 0x2; +pub const EPOLLOUT: c_int = 0x4; +pub const EPOLLERR: c_int = 0x8; +pub const EPOLLHUP: c_int = 0x10; +pub const EPOLLRDNORM: c_int = 0x40; +pub const EPOLLRDBAND: c_int = 0x80; +pub const EPOLLWRNORM: c_int = 0x100; +pub const EPOLLWRBAND: c_int = 0x200; +pub const EPOLLMSG: c_int = 0x400; +pub const EPOLLRDHUP: c_int = 0x2000; +pub const EPOLLEXCLUSIVE: c_int = 0x10000000; +pub const EPOLLWAKEUP: c_int = 0x20000000; +pub const EPOLLONESHOT: c_int = 0x40000000; +pub const EPOLLET: c_int = 0x80000000; + +pub const EPOLL_CTL_ADD: c_int = 1; +pub const EPOLL_CTL_MOD: c_int = 3; +pub const EPOLL_CTL_DEL: c_int = 2; + +pub const MNT_FORCE: c_int = 0x1; +pub const MNT_DETACH: c_int = 0x2; +pub const MNT_EXPIRE: c_int = 0x4; +pub const UMOUNT_NOFOLLOW: c_int = 0x8; + +cfg_if! { + if #[cfg(not(target_os = "l4re"))] { + pub const Q_GETFMT: c_int = 0x800004; + pub const Q_GETINFO: c_int = 0x800005; + pub const Q_SETINFO: c_int = 0x800006; + pub const QIF_BLIMITS: u32 = 1; + pub const QIF_SPACE: u32 = 2; + pub const QIF_ILIMITS: u32 = 4; + pub const QIF_INODES: u32 = 8; + pub const QIF_BTIME: u32 = 16; + pub const QIF_ITIME: u32 = 32; + pub const QIF_LIMITS: u32 = 5; + pub const QIF_USAGE: u32 = 10; + pub const QIF_TIMES: u32 = 48; + pub const QIF_ALL: u32 = 63; + + pub const Q_SYNC: c_int = 0x800001; + pub const Q_QUOTAON: c_int = 0x800002; + pub const Q_QUOTAOFF: c_int = 0x800003; + pub const Q_GETQUOTA: c_int = 0x800007; + pub const Q_SETQUOTA: c_int = 0x800008; + } +} + +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const NL0: crate::tcflag_t = 0x00000000; +pub const NL1: crate::tcflag_t = 0x00000100; +pub const TAB0: crate::tcflag_t = 0x00000000; +pub const CR0: crate::tcflag_t = 0x00000000; +pub const FF0: crate::tcflag_t = 0x00000000; +pub const BS0: crate::tcflag_t = 0x00000000; +pub const VT0: crate::tcflag_t = 0x00000000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNPAR: crate::tcflag_t = 0x00000004; +pub const PARMRK: crate::tcflag_t = 0x00000008; +pub const INPCK: crate::tcflag_t = 0x00000010; +pub const ISTRIP: crate::tcflag_t = 0x00000020; +pub const INLCR: crate::tcflag_t = 0x00000040; +pub const IGNCR: crate::tcflag_t = 0x00000080; +pub const ICRNL: crate::tcflag_t = 0x00000100; +pub const IXANY: crate::tcflag_t = 0x00000800; +pub const IMAXBEL: crate::tcflag_t = 0x00002000; +pub const OPOST: crate::tcflag_t = 0x1; +pub const CS5: crate::tcflag_t = 0x00000000; +pub const CRTSCTS: crate::tcflag_t = 0x80000000; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const OCRNL: crate::tcflag_t = 0o000010; +pub const ONOCR: crate::tcflag_t = 0o000020; +pub const ONLRET: crate::tcflag_t = 0o000040; +pub const OFILL: crate::tcflag_t = 0o000100; +pub const OFDEL: crate::tcflag_t = 0o000200; + +pub const CLONE_VM: c_int = 0x100; +pub const CLONE_FS: c_int = 0x200; +pub const CLONE_FILES: c_int = 0x400; +pub const CLONE_SIGHAND: c_int = 0x800; +pub const CLONE_PTRACE: c_int = 0x2000; +pub const CLONE_VFORK: c_int = 0x4000; +pub const CLONE_PARENT: c_int = 0x8000; +pub const CLONE_THREAD: c_int = 0x10000; +pub const CLONE_NEWNS: c_int = 0x20000; +pub const CLONE_SYSVSEM: c_int = 0x40000; +pub const CLONE_SETTLS: c_int = 0x80000; +pub const CLONE_PARENT_SETTID: c_int = 0x100000; +pub const CLONE_CHILD_CLEARTID: c_int = 0x200000; +pub const CLONE_DETACHED: c_int = 0x400000; +pub const CLONE_UNTRACED: c_int = 0x800000; +pub const CLONE_CHILD_SETTID: c_int = 0x01000000; +#[cfg(not(target_os = "l4re"))] +pub const CLONE_NEWCGROUP: c_int = 0x02000000; +pub const CLONE_NEWUTS: c_int = 0x04000000; +pub const CLONE_NEWIPC: c_int = 0x08000000; +pub const CLONE_NEWUSER: c_int = 0x10000000; +pub const CLONE_NEWPID: c_int = 0x20000000; +pub const CLONE_NEWNET: c_int = 0x40000000; +pub const CLONE_IO: c_int = 0x80000000; + +pub const WNOHANG: c_int = 0x00000001; +pub const WUNTRACED: c_int = 0x00000002; +pub const WSTOPPED: c_int = WUNTRACED; +pub const WEXITED: c_int = 0x00000004; +pub const WCONTINUED: c_int = 0x00000008; +pub const WNOWAIT: c_int = 0x01000000; + +cfg_if! { + if #[cfg(not(target_os = "l4re"))] { + // Options for personality(2). + pub const ADDR_NO_RANDOMIZE: c_int = 0x0040000; + pub const MMAP_PAGE_ZERO: c_int = 0x0100000; + pub const ADDR_COMPAT_LAYOUT: c_int = 0x0200000; + pub const READ_IMPLIES_EXEC: c_int = 0x0400000; + pub const ADDR_LIMIT_32BIT: c_int = 0x0800000; + pub const SHORT_INODE: c_int = 0x1000000; + pub const WHOLE_SECONDS: c_int = 0x2000000; + pub const STICKY_TIMEOUTS: c_int = 0x4000000; + pub const ADDR_LIMIT_3GB: c_int = 0x8000000; + + // Options set using PTRACE_SETOPTIONS. + pub const PTRACE_O_TRACESYSGOOD: c_int = 0x00000001; + pub const PTRACE_O_TRACEFORK: c_int = 0x00000002; + pub const PTRACE_O_TRACEVFORK: c_int = 0x00000004; + pub const PTRACE_O_TRACECLONE: c_int = 0x00000008; + pub const PTRACE_O_TRACEEXEC: c_int = 0x00000010; + pub const PTRACE_O_TRACEVFORKDONE: c_int = 0x00000020; + pub const PTRACE_O_TRACEEXIT: c_int = 0x00000040; + pub const PTRACE_O_TRACESECCOMP: c_int = 0x00000080; + pub const PTRACE_O_SUSPEND_SECCOMP: c_int = 0x00200000; + pub const PTRACE_O_EXITKILL: c_int = 0x00100000; + pub const PTRACE_O_MASK: c_int = 0x003000ff; + + // Wait extended result codes for the above trace options. + pub const PTRACE_EVENT_FORK: c_int = 1; + pub const PTRACE_EVENT_VFORK: c_int = 2; + pub const PTRACE_EVENT_CLONE: c_int = 3; + pub const PTRACE_EVENT_EXEC: c_int = 4; + pub const PTRACE_EVENT_VFORK_DONE: c_int = 5; + pub const PTRACE_EVENT_EXIT: c_int = 6; + pub const PTRACE_EVENT_SECCOMP: c_int = 7; + } +} + +pub const __WNOTHREAD: c_int = 0x20000000; +pub const __WALL: c_int = 0x40000000; +pub const __WCLONE: c_int = 0x80000000; + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + pub const SPLICE_F_MOVE: c_uint = 0x01; + pub const SPLICE_F_NONBLOCK: c_uint = 0x02; + pub const SPLICE_F_MORE: c_uint = 0x04; + pub const SPLICE_F_GIFT: c_uint = 0x08; + } +} + +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_LAZY: c_int = 1; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; + +pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x100; +pub const AT_REMOVEDIR: c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: c_int = 0x400; +pub const AT_NO_AUTOMOUNT: c_int = 0x800; +pub const AT_EMPTY_PATH: c_int = 0x1000; +pub const AT_RECURSIVE: c_int = 0x8000; + +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_FTP: c_int = 11 << 3; +pub const LOG_PERROR: c_int = 0x20; + +#[cfg(not(target_os = "l4re"))] +pub const PIPE_BUF: usize = 4096; + +pub const SI_LOAD_SHIFT: c_uint = 16; + +// si_code values +pub const SI_USER: c_int = 0; +pub const SI_KERNEL: c_int = 0x80; +pub const SI_QUEUE: c_int = -1; +cfg_if! { + if #[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64" + )))] { + pub const SI_TIMER: c_int = -2; + pub const SI_MESGQ: c_int = -3; + pub const SI_ASYNCIO: c_int = -4; + } else { + pub const SI_TIMER: c_int = -3; + pub const SI_MESGQ: c_int = -4; + pub const SI_ASYNCIO: c_int = -2; + } +} +pub const SI_SIGIO: c_int = -5; +pub const SI_TKILL: c_int = -6; +pub const SI_ASYNCNL: c_int = -60; + +// si_code values for SIGBUS signal +pub const BUS_ADRALN: c_int = 1; +pub const BUS_ADRERR: c_int = 2; +pub const BUS_OBJERR: c_int = 3; +// Linux-specific si_code values for SIGBUS signal +#[cfg(not(target_os = "l4re"))] +pub const BUS_MCEERR_AR: c_int = 4; +#[cfg(not(target_os = "l4re"))] +pub const BUS_MCEERR_AO: c_int = 5; + +// si_code values for SIGTRAP +pub const TRAP_BRKPT: c_int = 1; +pub const TRAP_TRACE: c_int = 2; +#[cfg(not(target_os = "l4re"))] +pub const TRAP_BRANCH: c_int = 3; +#[cfg(not(target_os = "l4re"))] +pub const TRAP_HWBKPT: c_int = 4; +#[cfg(not(target_os = "l4re"))] +pub const TRAP_UNK: c_int = 5; + +// si_code values for SIGCHLD signal +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const SIGEV_SIGNAL: c_int = 0; +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; +cfg_if! { + if #[cfg(not(target_os = "emscripten"))] { + pub const P_PIDFD: idtype_t = 3; + } +} + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; +pub const POLLRDNORM: c_short = 0x040; +pub const POLLRDBAND: c_short = 0x080; +#[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +pub const POLLRDHUP: c_short = 0x2000; +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] +pub const POLLRDHUP: c_short = 0x800; + +pub const IPTOS_LOWDELAY: u8 = 0x10; +pub const IPTOS_THROUGHPUT: u8 = 0x08; +pub const IPTOS_RELIABILITY: u8 = 0x04; +pub const IPTOS_MINCOST: u8 = 0x02; + +pub const IPTOS_PREC_NETCONTROL: u8 = 0xe0; +pub const IPTOS_PREC_INTERNETCONTROL: u8 = 0xc0; +pub const IPTOS_PREC_CRITIC_ECP: u8 = 0xa0; +pub const IPTOS_PREC_FLASHOVERRIDE: u8 = 0x80; +pub const IPTOS_PREC_FLASH: u8 = 0x60; +pub const IPTOS_PREC_IMMEDIATE: u8 = 0x40; +pub const IPTOS_PREC_PRIORITY: u8 = 0x20; +pub const IPTOS_PREC_ROUTINE: u8 = 0x00; + +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const IPOPT_COPY: u8 = 0x80; +pub const IPOPT_CLASS_MASK: u8 = 0x60; +pub const IPOPT_NUMBER_MASK: u8 = 0x1f; + +pub const IPOPT_CONTROL: u8 = 0x00; +pub const IPOPT_RESERVED1: u8 = 0x20; +pub const IPOPT_MEASUREMENT: u8 = 0x40; +pub const IPOPT_RESERVED2: u8 = 0x60; +pub const IPOPT_END: u8 = 0 | IPOPT_CONTROL; +pub const IPOPT_NOOP: u8 = 1 | IPOPT_CONTROL; +pub const IPOPT_SEC: u8 = 2 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_LSRR: u8 = 3 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_TIMESTAMP: u8 = 4 | IPOPT_MEASUREMENT; +pub const IPOPT_RR: u8 = 7 | IPOPT_CONTROL; +pub const IPOPT_SID: u8 = 8 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_SSRR: u8 = 9 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPOPT_RA: u8 = 20 | IPOPT_CONTROL | IPOPT_COPY; +pub const IPVERSION: u8 = 4; +pub const MAXTTL: u8 = 255; +pub const IPDEFTTL: u8 = 64; +pub const IPOPT_OPTVAL: u8 = 0; +pub const IPOPT_OLEN: u8 = 1; +pub const IPOPT_OFFSET: u8 = 2; +pub const IPOPT_MINOFF: u8 = 4; +pub const MAX_IPOPTLEN: u8 = 40; +pub const IPOPT_NOP: u8 = IPOPT_NOOP; +pub const IPOPT_EOL: u8 = IPOPT_END; +pub const IPOPT_TS: u8 = IPOPT_TIMESTAMP; +pub const IPOPT_TS_TSONLY: u8 = 0; +pub const IPOPT_TS_TSANDADDR: u8 = 1; +pub const IPOPT_TS_PRESPEC: u8 = 3; + +pub const ARPOP_RREQUEST: u16 = 3; +pub const ARPOP_RREPLY: u16 = 4; +pub const ARPOP_InREQUEST: u16 = 8; +pub const ARPOP_InREPLY: u16 = 9; +pub const ARPOP_NAK: u16 = 10; + +pub const ATF_NETMASK: c_int = 0x20; +pub const ATF_DONTPUB: c_int = 0x40; + +pub const ARPHRD_NETROM: u16 = 0; +pub const ARPHRD_ETHER: u16 = 1; +pub const ARPHRD_EETHER: u16 = 2; +pub const ARPHRD_AX25: u16 = 3; +pub const ARPHRD_PRONET: u16 = 4; +pub const ARPHRD_CHAOS: u16 = 5; +pub const ARPHRD_IEEE802: u16 = 6; +pub const ARPHRD_ARCNET: u16 = 7; +pub const ARPHRD_APPLETLK: u16 = 8; +pub const ARPHRD_DLCI: u16 = 15; +pub const ARPHRD_ATM: u16 = 19; +pub const ARPHRD_METRICOM: u16 = 23; +pub const ARPHRD_IEEE1394: u16 = 24; +pub const ARPHRD_EUI64: u16 = 27; +pub const ARPHRD_INFINIBAND: u16 = 32; + +pub const ARPHRD_SLIP: u16 = 256; +pub const ARPHRD_CSLIP: u16 = 257; +pub const ARPHRD_SLIP6: u16 = 258; +pub const ARPHRD_CSLIP6: u16 = 259; +pub const ARPHRD_RSRVD: u16 = 260; +pub const ARPHRD_ADAPT: u16 = 264; +pub const ARPHRD_ROSE: u16 = 270; +pub const ARPHRD_X25: u16 = 271; +pub const ARPHRD_HWX25: u16 = 272; +pub const ARPHRD_CAN: u16 = 280; +pub const ARPHRD_PPP: u16 = 512; +pub const ARPHRD_CISCO: u16 = 513; +pub const ARPHRD_HDLC: u16 = ARPHRD_CISCO; +pub const ARPHRD_LAPB: u16 = 516; +pub const ARPHRD_DDCMP: u16 = 517; +pub const ARPHRD_RAWHDLC: u16 = 518; + +pub const ARPHRD_TUNNEL: u16 = 768; +pub const ARPHRD_TUNNEL6: u16 = 769; +pub const ARPHRD_FRAD: u16 = 770; +pub const ARPHRD_SKIP: u16 = 771; +pub const ARPHRD_LOOPBACK: u16 = 772; +pub const ARPHRD_LOCALTLK: u16 = 773; +pub const ARPHRD_FDDI: u16 = 774; +pub const ARPHRD_BIF: u16 = 775; +pub const ARPHRD_SIT: u16 = 776; +pub const ARPHRD_IPDDP: u16 = 777; +pub const ARPHRD_IPGRE: u16 = 778; +pub const ARPHRD_PIMREG: u16 = 779; +pub const ARPHRD_HIPPI: u16 = 780; +pub const ARPHRD_ASH: u16 = 781; +pub const ARPHRD_ECONET: u16 = 782; +pub const ARPHRD_IRDA: u16 = 783; +pub const ARPHRD_FCPP: u16 = 784; +pub const ARPHRD_FCAL: u16 = 785; +pub const ARPHRD_FCPL: u16 = 786; +pub const ARPHRD_FCFABRIC: u16 = 787; +pub const ARPHRD_IEEE802_TR: u16 = 800; +pub const ARPHRD_IEEE80211: u16 = 801; +pub const ARPHRD_IEEE80211_PRISM: u16 = 802; +pub const ARPHRD_IEEE80211_RADIOTAP: u16 = 803; +pub const ARPHRD_IEEE802154: u16 = 804; + +pub const ARPHRD_VOID: u16 = 0xFFFF; +pub const ARPHRD_NONE: u16 = 0xFFFE; + +cfg_if! { + if #[cfg(not(any(target_os = "emscripten", target_os = "l4re")))] { + // linux/if_tun.h + /* TUNSETIFF ifr flags */ + pub const IFF_TUN: c_int = 0x0001; + pub const IFF_TAP: c_int = 0x0002; + pub const IFF_NAPI: c_int = 0x0010; + pub const IFF_NAPI_FRAGS: c_int = 0x0020; + // Used in TUNSETIFF to bring up tun/tap without carrier + pub const IFF_NO_CARRIER: c_int = 0x0040; + pub const IFF_NO_PI: c_int = 0x1000; + // Read queue size + pub const TUN_READQ_SIZE: c_short = 500; + // TUN device type flags: deprecated. Use IFF_TUN/IFF_TAP instead. + pub const TUN_TUN_DEV: c_short = crate::IFF_TUN as c_short; + pub const TUN_TAP_DEV: c_short = crate::IFF_TAP as c_short; + pub const TUN_TYPE_MASK: c_short = 0x000f; + // This flag has no real effect + pub const IFF_ONE_QUEUE: c_int = 0x2000; + pub const IFF_VNET_HDR: c_int = 0x4000; + pub const IFF_TUN_EXCL: c_int = 0x8000; + pub const IFF_MULTI_QUEUE: c_int = 0x0100; + pub const IFF_ATTACH_QUEUE: c_int = 0x0200; + pub const IFF_DETACH_QUEUE: c_int = 0x0400; + // read-only flag + pub const IFF_PERSIST: c_int = 0x0800; + pub const IFF_NOFILTER: c_int = 0x1000; + // Socket options + pub const TUN_TX_TIMESTAMP: c_int = 1; + // Features for GSO (TUNSETOFFLOAD) + pub const TUN_F_CSUM: c_uint = 0x01; + pub const TUN_F_TSO4: c_uint = 0x02; + pub const TUN_F_TSO6: c_uint = 0x04; + pub const TUN_F_TSO_ECN: c_uint = 0x08; + pub const TUN_F_UFO: c_uint = 0x10; + pub const TUN_F_USO4: c_uint = 0x20; + pub const TUN_F_USO6: c_uint = 0x40; + // Protocol info prepended to the packets (when IFF_NO_PI is not set) + pub const TUN_PKT_STRIP: c_int = 0x0001; + // Accept all multicast packets + pub const TUN_FLT_ALLMULTI: c_int = 0x0001; + // Ioctl operation codes + const T_TYPE: u32 = b'T' as u32; + pub const TUNSETNOCSUM: Ioctl = _IOW::(T_TYPE, 200); + pub const TUNSETDEBUG: Ioctl = _IOW::(T_TYPE, 201); + pub const TUNSETIFF: Ioctl = _IOW::(T_TYPE, 202); + pub const TUNSETPERSIST: Ioctl = _IOW::(T_TYPE, 203); + pub const TUNSETOWNER: Ioctl = _IOW::(T_TYPE, 204); + pub const TUNSETLINK: Ioctl = _IOW::(T_TYPE, 205); + pub const TUNSETGROUP: Ioctl = _IOW::(T_TYPE, 206); + pub const TUNGETFEATURES: Ioctl = _IOR::(T_TYPE, 207); + pub const TUNSETOFFLOAD: Ioctl = _IOW::(T_TYPE, 208); + pub const TUNSETTXFILTER: Ioctl = _IOW::(T_TYPE, 209); + pub const TUNGETIFF: Ioctl = _IOR::(T_TYPE, 210); + pub const TUNGETSNDBUF: Ioctl = _IOR::(T_TYPE, 211); + pub const TUNSETSNDBUF: Ioctl = _IOW::(T_TYPE, 212); + pub const TUNATTACHFILTER: Ioctl = _IOW::(T_TYPE, 213); + pub const TUNDETACHFILTER: Ioctl = _IOW::(T_TYPE, 214); + pub const TUNGETVNETHDRSZ: Ioctl = _IOR::(T_TYPE, 215); + pub const TUNSETVNETHDRSZ: Ioctl = _IOW::(T_TYPE, 216); + pub const TUNSETQUEUE: Ioctl = _IOW::(T_TYPE, 217); + pub const TUNSETIFINDEX: Ioctl = _IOW::(T_TYPE, 218); + pub const TUNGETFILTER: Ioctl = _IOR::(T_TYPE, 219); + pub const TUNSETVNETLE: Ioctl = _IOW::(T_TYPE, 220); + pub const TUNGETVNETLE: Ioctl = _IOR::(T_TYPE, 221); + pub const TUNSETVNETBE: Ioctl = _IOW::(T_TYPE, 222); + pub const TUNGETVNETBE: Ioctl = _IOR::(T_TYPE, 223); + pub const TUNSETSTEERINGEBPF: Ioctl = _IOR::(T_TYPE, 224); + pub const TUNSETFILTEREBPF: Ioctl = _IOR::(T_TYPE, 225); + pub const TUNSETCARRIER: Ioctl = _IOW::(T_TYPE, 226); + pub const TUNGETDEVNETNS: Ioctl = _IO(T_TYPE, 227); + + // linux/fs.h + pub const FS_IOC_GETFLAGS: Ioctl = _IOR::('f' as u32, 1); + pub const FS_IOC_SETFLAGS: Ioctl = _IOW::('f' as u32, 2); + pub const FS_IOC_GETVERSION: Ioctl = _IOR::('v' as u32, 1); + pub const FS_IOC_SETVERSION: Ioctl = _IOW::('v' as u32, 2); + pub const FS_IOC32_GETFLAGS: Ioctl = _IOR::('f' as u32, 1); + pub const FS_IOC32_SETFLAGS: Ioctl = _IOW::('f' as u32, 2); + pub const FS_IOC32_GETVERSION: Ioctl = _IOR::('v' as u32, 1); + pub const FS_IOC32_SETVERSION: Ioctl = _IOW::('v' as u32, 2); + + pub const FICLONE: Ioctl = _IOW::(0x94, 9); + pub const FICLONERANGE: Ioctl = _IOW::(0x94, 13); + } +} + +cfg_if! { + if #[cfg(any(target_os = "emscripten", target_os = "l4re"))] { + // Emscripten does not define any `*_SUPER_MAGIC` constants. + } else if #[cfg(not(target_arch = "s390x"))] { + pub const ADFS_SUPER_MAGIC: c_long = 0x0000adf5; + pub const AFFS_SUPER_MAGIC: c_long = 0x0000adff; + pub const AFS_SUPER_MAGIC: c_long = 0x5346414f; + pub const AUTOFS_SUPER_MAGIC: c_long = 0x0187; + pub const BPF_FS_MAGIC: c_long = 0xcafe4a11; + pub const BTRFS_SUPER_MAGIC: c_long = 0x9123683e; + pub const CGROUP2_SUPER_MAGIC: c_long = 0x63677270; + pub const CGROUP_SUPER_MAGIC: c_long = 0x27e0eb; + pub const CODA_SUPER_MAGIC: c_long = 0x73757245; + pub const CRAMFS_MAGIC: c_long = 0x28cd3d45; + pub const DEBUGFS_MAGIC: c_long = 0x64626720; + pub const DEVPTS_SUPER_MAGIC: c_long = 0x1cd1; + pub const ECRYPTFS_SUPER_MAGIC: c_long = 0xf15f; + pub const EFS_SUPER_MAGIC: c_long = 0x00414a53; + pub const EXT2_SUPER_MAGIC: c_long = 0x0000ef53; + pub const EXT3_SUPER_MAGIC: c_long = 0x0000ef53; + pub const EXT4_SUPER_MAGIC: c_long = 0x0000ef53; + pub const F2FS_SUPER_MAGIC: c_long = 0xf2f52010; + pub const FUSE_SUPER_MAGIC: c_long = 0x65735546; + pub const FUTEXFS_SUPER_MAGIC: c_long = 0xbad1dea; + pub const HOSTFS_SUPER_MAGIC: c_long = 0x00c0ffee; + pub const HPFS_SUPER_MAGIC: c_long = 0xf995e849; + pub const HUGETLBFS_MAGIC: c_long = 0x958458f6; + pub const ISOFS_SUPER_MAGIC: c_long = 0x00009660; + pub const JFFS2_SUPER_MAGIC: c_long = 0x000072b6; + pub const MINIX2_SUPER_MAGIC2: c_long = 0x00002478; + pub const MINIX2_SUPER_MAGIC: c_long = 0x00002468; + pub const MINIX3_SUPER_MAGIC: c_long = 0x4d5a; + pub const MINIX_SUPER_MAGIC2: c_long = 0x0000138f; + pub const MINIX_SUPER_MAGIC: c_long = 0x0000137f; + pub const MSDOS_SUPER_MAGIC: c_long = 0x00004d44; + pub const NCP_SUPER_MAGIC: c_long = 0x0000564c; + pub const NFS_SUPER_MAGIC: c_long = 0x00006969; + pub const NILFS_SUPER_MAGIC: c_long = 0x3434; + pub const OCFS2_SUPER_MAGIC: c_long = 0x7461636f; + pub const OPENPROM_SUPER_MAGIC: c_long = 0x00009fa1; + pub const OVERLAYFS_SUPER_MAGIC: c_long = 0x794c7630; + pub const PROC_SUPER_MAGIC: c_long = 0x00009fa0; + pub const QNX4_SUPER_MAGIC: c_long = 0x0000002f; + pub const QNX6_SUPER_MAGIC: c_long = 0x68191122; + pub const RDTGROUP_SUPER_MAGIC: c_long = 0x7655821; + pub const REISERFS_SUPER_MAGIC: c_long = 0x52654973; + pub const SECURITYFS_MAGIC: c_long = 0x73636673; + pub const SELINUX_MAGIC: c_long = 0xf97cff8c; + pub const SMACK_MAGIC: c_long = 0x43415d53; + pub const SMB_SUPER_MAGIC: c_long = 0x0000517b; + pub const SYSFS_MAGIC: c_long = 0x62656572; + pub const TMPFS_MAGIC: c_long = 0x01021994; + pub const TRACEFS_MAGIC: c_long = 0x74726163; + pub const UDF_SUPER_MAGIC: c_long = 0x15013346; + pub const USBDEVICE_SUPER_MAGIC: c_long = 0x00009fa2; + pub const XENFS_SUPER_MAGIC: c_long = 0xabba1974; + pub const NSFS_MAGIC: c_long = 0x6e736673; + } else if #[cfg(target_arch = "s390x")] { + pub const ADFS_SUPER_MAGIC: c_uint = 0x0000adf5; + pub const AFFS_SUPER_MAGIC: c_uint = 0x0000adff; + pub const AFS_SUPER_MAGIC: c_uint = 0x5346414f; + pub const AUTOFS_SUPER_MAGIC: c_uint = 0x0187; + pub const BPF_FS_MAGIC: c_uint = 0xcafe4a11; + pub const BTRFS_SUPER_MAGIC: c_uint = 0x9123683e; + pub const CGROUP2_SUPER_MAGIC: c_uint = 0x63677270; + pub const CGROUP_SUPER_MAGIC: c_uint = 0x27e0eb; + pub const CODA_SUPER_MAGIC: c_uint = 0x73757245; + pub const CRAMFS_MAGIC: c_uint = 0x28cd3d45; + pub const DEBUGFS_MAGIC: c_uint = 0x64626720; + pub const DEVPTS_SUPER_MAGIC: c_uint = 0x1cd1; + pub const ECRYPTFS_SUPER_MAGIC: c_uint = 0xf15f; + pub const EFS_SUPER_MAGIC: c_uint = 0x00414a53; + pub const EXT2_SUPER_MAGIC: c_uint = 0x0000ef53; + pub const EXT3_SUPER_MAGIC: c_uint = 0x0000ef53; + pub const EXT4_SUPER_MAGIC: c_uint = 0x0000ef53; + pub const F2FS_SUPER_MAGIC: c_uint = 0xf2f52010; + pub const FUSE_SUPER_MAGIC: c_uint = 0x65735546; + pub const FUTEXFS_SUPER_MAGIC: c_uint = 0xbad1dea; + pub const HOSTFS_SUPER_MAGIC: c_uint = 0x00c0ffee; + pub const HPFS_SUPER_MAGIC: c_uint = 0xf995e849; + pub const HUGETLBFS_MAGIC: c_uint = 0x958458f6; + pub const ISOFS_SUPER_MAGIC: c_uint = 0x00009660; + pub const JFFS2_SUPER_MAGIC: c_uint = 0x000072b6; + pub const MINIX2_SUPER_MAGIC2: c_uint = 0x00002478; + pub const MINIX2_SUPER_MAGIC: c_uint = 0x00002468; + pub const MINIX3_SUPER_MAGIC: c_uint = 0x4d5a; + pub const MINIX_SUPER_MAGIC2: c_uint = 0x0000138f; + pub const MINIX_SUPER_MAGIC: c_uint = 0x0000137f; + pub const MSDOS_SUPER_MAGIC: c_uint = 0x00004d44; + pub const NCP_SUPER_MAGIC: c_uint = 0x0000564c; + pub const NFS_SUPER_MAGIC: c_uint = 0x00006969; + pub const NILFS_SUPER_MAGIC: c_uint = 0x3434; + pub const OCFS2_SUPER_MAGIC: c_uint = 0x7461636f; + pub const OPENPROM_SUPER_MAGIC: c_uint = 0x00009fa1; + pub const OVERLAYFS_SUPER_MAGIC: c_uint = 0x794c7630; + pub const PROC_SUPER_MAGIC: c_uint = 0x00009fa0; + pub const QNX4_SUPER_MAGIC: c_uint = 0x0000002f; + pub const QNX6_SUPER_MAGIC: c_uint = 0x68191122; + pub const RDTGROUP_SUPER_MAGIC: c_uint = 0x7655821; + pub const REISERFS_SUPER_MAGIC: c_uint = 0x52654973; + pub const SECURITYFS_MAGIC: c_uint = 0x73636673; + pub const SELINUX_MAGIC: c_uint = 0xf97cff8c; + pub const SMACK_MAGIC: c_uint = 0x43415d53; + pub const SMB_SUPER_MAGIC: c_uint = 0x0000517b; + pub const SYSFS_MAGIC: c_uint = 0x62656572; + pub const TMPFS_MAGIC: c_uint = 0x01021994; + pub const TRACEFS_MAGIC: c_uint = 0x74726163; + pub const UDF_SUPER_MAGIC: c_uint = 0x15013346; + pub const USBDEVICE_SUPER_MAGIC: c_uint = 0x00009fa2; + pub const XENFS_SUPER_MAGIC: c_uint = 0xabba1974; + pub const NSFS_MAGIC: c_uint = 0x6e736673; + } +} + +cfg_if! { + if #[cfg(any( + target_env = "gnu", + target_os = "android", + all(target_env = "musl", musl_v1_2_3), + target_os = "l4re" + ))] { + pub const AT_STATX_SYNC_TYPE: c_int = 0x6000; + pub const AT_STATX_SYNC_AS_STAT: c_int = 0x0000; + pub const AT_STATX_FORCE_SYNC: c_int = 0x2000; + pub const AT_STATX_DONT_SYNC: c_int = 0x4000; + pub const STATX_TYPE: c_uint = 0x0001; + pub const STATX_MODE: c_uint = 0x0002; + pub const STATX_NLINK: c_uint = 0x0004; + pub const STATX_UID: c_uint = 0x0008; + pub const STATX_GID: c_uint = 0x0010; + pub const STATX_ATIME: c_uint = 0x0020; + pub const STATX_MTIME: c_uint = 0x0040; + pub const STATX_CTIME: c_uint = 0x0080; + pub const STATX_INO: c_uint = 0x0100; + pub const STATX_SIZE: c_uint = 0x0200; + pub const STATX_BLOCKS: c_uint = 0x0400; + pub const STATX_BASIC_STATS: c_uint = 0x07ff; + pub const STATX_BTIME: c_uint = 0x0800; + pub const STATX_ALL: c_uint = 0x0fff; + pub const STATX_MNT_ID: c_uint = 0x1000; + pub const STATX_DIOALIGN: c_uint = 0x2000; + pub const STATX__RESERVED: c_int = 0x80000000; + pub const STATX_ATTR_COMPRESSED: c_int = 0x0004; + pub const STATX_ATTR_IMMUTABLE: c_int = 0x0010; + pub const STATX_ATTR_APPEND: c_int = 0x0020; + pub const STATX_ATTR_NODUMP: c_int = 0x0040; + pub const STATX_ATTR_ENCRYPTED: c_int = 0x0800; + pub const STATX_ATTR_AUTOMOUNT: c_int = 0x1000; + pub const STATX_ATTR_MOUNT_ROOT: c_int = 0x2000; + pub const STATX_ATTR_VERITY: c_int = 0x100000; + pub const STATX_ATTR_DAX: c_int = 0x200000; + } +} + +// https://github.com/search?q=repo%3Atorvalds%2Flinux+%22%23define+_IOC_NONE%22&type=code +cfg_if! { + if #[cfg(not(target_os = "emscripten"))] { + const _IOC_NRBITS: u32 = 8; + const _IOC_TYPEBITS: u32 = 8; + + cfg_if! { + if #[cfg(any( + any(target_arch = "powerpc", target_arch = "powerpc64"), + any(target_arch = "sparc", target_arch = "sparc64"), + any(target_arch = "mips", target_arch = "mips64"), + ))] { + // https://github.com/torvalds/linux/blob/b311c1b497e51a628aa89e7cb954481e5f9dced2/arch/powerpc/include/uapi/asm/ioctl.h + // https://github.com/torvalds/linux/blob/b311c1b497e51a628aa89e7cb954481e5f9dced2/arch/sparc/include/uapi/asm/ioctl.h + // https://github.com/torvalds/linux/blob/b311c1b497e51a628aa89e7cb954481e5f9dced2/arch/mips/include/uapi/asm/ioctl.h + + const _IOC_SIZEBITS: u32 = 13; + const _IOC_DIRBITS: u32 = 3; + + const _IOC_NONE: u32 = 1; + const _IOC_READ: u32 = 2; + const _IOC_WRITE: u32 = 4; + } else { + // https://github.com/torvalds/linux/blob/b311c1b497e51a628aa89e7cb954481e5f9dced2/include/uapi/asm-generic/ioctl.h + + const _IOC_SIZEBITS: u32 = 14; + const _IOC_DIRBITS: u32 = 2; + + const _IOC_NONE: u32 = 0; + const _IOC_WRITE: u32 = 1; + const _IOC_READ: u32 = 2; + } + } + const _IOC_NRMASK: u32 = (1 << _IOC_NRBITS) - 1; + const _IOC_TYPEMASK: u32 = (1 << _IOC_TYPEBITS) - 1; + const _IOC_SIZEMASK: u32 = (1 << _IOC_SIZEBITS) - 1; + const _IOC_DIRMASK: u32 = (1 << _IOC_DIRBITS) - 1; + + const _IOC_NRSHIFT: u32 = 0; + const _IOC_TYPESHIFT: u32 = _IOC_NRSHIFT + _IOC_NRBITS; + const _IOC_SIZESHIFT: u32 = _IOC_TYPESHIFT + _IOC_TYPEBITS; + const _IOC_DIRSHIFT: u32 = _IOC_SIZESHIFT + _IOC_SIZEBITS; + + // adapted from https://github.com/torvalds/linux/blob/8a696a29c6905594e4abf78eaafcb62165ac61f1/rust/kernel/ioctl.rs + + /// Build an ioctl number, analogous to the C macro of the same name. + const fn _IOC(dir: u32, ty: u32, nr: u32, size: usize) -> Ioctl { + core::debug_assert!(dir <= _IOC_DIRMASK); + core::debug_assert!(ty <= _IOC_TYPEMASK); + core::debug_assert!(nr <= _IOC_NRMASK); + core::debug_assert!(size <= (_IOC_SIZEMASK as usize)); + + ((dir << _IOC_DIRSHIFT) + | (ty << _IOC_TYPESHIFT) + | (nr << _IOC_NRSHIFT) + | ((size as u32) << _IOC_SIZESHIFT)) as Ioctl + } + + /// Build an ioctl number for an argumentless ioctl. + pub const fn _IO(ty: u32, nr: u32) -> Ioctl { + _IOC(_IOC_NONE, ty, nr, 0) + } + + /// Build an ioctl number for an read-only ioctl. + pub const fn _IOR(ty: u32, nr: u32) -> Ioctl { + _IOC(_IOC_READ, ty, nr, size_of::()) + } + + /// Build an ioctl number for an write-only ioctl. + pub const fn _IOW(ty: u32, nr: u32) -> Ioctl { + _IOC(_IOC_WRITE, ty, nr, size_of::()) + } + + /// Build an ioctl number for a read-write ioctl. + pub const fn _IOWR(ty: u32, nr: u32) -> Ioctl { + _IOC(_IOC_READ | _IOC_WRITE, ty, nr, size_of::()) + } + + extern "C" { + #[cfg_attr(gnu_time_bits64, link_name = "__ioctl_time64")] + pub fn ioctl(fd: c_int, request: Ioctl, ...) -> c_int; + } + } +} + +const fn CMSG_ALIGN(len: usize) -> usize { + (len + size_of::() - 1) & !(size_of::() - 1) +} + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const crate::msghdr) -> *mut crate::cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control.cast::() + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_DATA(cmsg: *const crate::cmsghdr) -> *mut c_uchar { + cmsg.offset(1) as *mut c_uchar + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + CMSG_ALIGN(size_of::()) as c_uint + length + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in &mut (*set).fds_bits { + *slot = 0; + } + } +} + +safe_f! { + pub fn SIGRTMAX() -> c_int { + unsafe { __libc_current_sigrtmax() } + } + + pub fn SIGRTMIN() -> c_int { + unsafe { __libc_current_sigrtmin() } + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0x7f) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn W_EXITCODE(ret: c_int, sig: c_int) -> c_int { + (ret << 8) | sig + } + + pub const fn W_STOPCODE(sig: c_int) -> c_int { + (sig << 8) | 0x7f + } + + pub const fn QCMD(cmd: c_int, type_: c_int) -> c_int { + (cmd << 8) | (type_ & 0x00ff) + } + + pub const fn IPOPT_COPIED(o: u8) -> u8 { + o & IPOPT_COPY + } + + pub const fn IPOPT_CLASS(o: u8) -> u8 { + o & IPOPT_CLASS_MASK + } + + pub const fn IPOPT_NUMBER(o: u8) -> u8 { + o & IPOPT_NUMBER_MASK + } + + pub const fn IPTOS_ECN(x: u8) -> u8 { + x & crate::IPTOS_ECN_MASK + } + + #[allow(ellipsis_inclusive_range_patterns)] + pub const fn KERNEL_VERSION(a: u32, b: u32, c: u32) -> u32 { + ((a << 16) + (b << 8)) + if c > 255 { 255 } else { c } + } +} + +extern "C" { + #[doc(hidden)] + pub fn __libc_current_sigrtmax() -> c_int; + #[doc(hidden)] + pub fn __libc_current_sigrtmin() -> c_int; + + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int; + + #[cfg_attr(gnu_time_bits64, link_name = "__clock_getres64")] + #[cfg_attr(musl_redir_time64, link_name = "__clock_getres_time64")] + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__clock_gettime64" + )] + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + #[cfg_attr( + any(gnu_time_bits64, musl_redir_time64), + link_name = "__clock_settime64" + )] + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + + #[cfg_attr(gnu_time_bits64, link_name = "__getitimer64")] + #[cfg_attr(musl_redir_time64, link_name = "__getitimer_time64")] + pub fn getitimer(which: c_int, curr_value: *mut crate::itimerval) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__setitimer64")] + #[cfg_attr(musl_redir_time64, link_name = "__setitimer_time64")] + pub fn setitimer( + which: c_int, + new_value: *const crate::itimerval, + old_value: *mut crate::itimerval, + ) -> c_int; + + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn setgroups(ngroups: size_t, ptr: *const crate::gid_t) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "statfs64")] + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "fstatfs64")] + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + #[cfg_attr(gnu_file_offset_bits64, link_name = "posix_fadvise64")] + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__futimens64")] + #[cfg_attr(musl_redir_time64, link_name = "__futimens_time64")] + #[cfg(not(target_os = "l4re"))] + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__utimensat64")] + #[cfg_attr(musl_redir_time64, link_name = "__utimensat_time64")] + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + #[cfg(not(target_os = "l4re"))] + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + + #[cfg(not(target_os = "l4re"))] + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn clearenv() -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn acct(filename: *const c_char) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn brk(addr: *mut c_void) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn sbrk(increment: intptr_t) -> *mut c_void; + #[deprecated( + since = "0.2.66", + note = "causes memory corruption, see rust-lang/libc#1596" + )] + pub fn vfork() -> crate::pid_t; + #[cfg(not(target_os = "l4re"))] + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__wait4_time64")] + #[cfg(not(target_os = "l4re"))] + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; + #[cfg(not(target_os = "l4re"))] + pub fn login_tty(fd: c_int) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + #[cfg(not(target_os = "l4re"))] + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + #[cfg_attr(gnu_time_bits64, link_name = "__sendmsg64")] + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + #[cfg_attr(gnu_time_bits64, link_name = "__recvmsg64")] + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + pub fn uname(buf: *mut crate::utsname) -> c_int; + + pub fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char; + + pub fn strftime( + s: *mut c_char, + max: size_t, + format: *const c_char, + tm: *const crate::tm, + ) -> size_t; + pub fn strftime_l( + s: *mut c_char, + max: size_t, + format: *const c_char, + tm: *const crate::tm, + locale: crate::locale_t, + ) -> size_t; + pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut crate::tm) -> *mut c_char; + + #[cfg_attr(gnu_file_offset_bits64, link_name = "mkostemp64")] + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "mkostemps64")] + #[cfg(not(target_os = "l4re"))] + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + + #[cfg(not(target_os = "l4re"))] + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn setdomainname(name: *const c_char, len: size_t) -> c_int; + + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; +} + +// LFS64 extensions +// +// * musl and Emscripten has 64-bit versions only so aliases the LFS64 symbols to the standard ones +// * ulibc doesn't have preadv64/pwritev64 +cfg_if! { + if #[cfg(not(any( + target_env = "musl", + target_env = "ohos", + target_os = "emscripten", + )))] { + extern "C" { + pub fn fstatfs64(fd: c_int, buf: *mut statfs64) -> c_int; + pub fn statvfs64(path: *const c_char, buf: *mut statvfs64) -> c_int; + pub fn fstatvfs64(fd: c_int, buf: *mut statvfs64) -> c_int; + pub fn statfs64(path: *const c_char, buf: *mut statfs64) -> c_int; + pub fn creat64(path: *const c_char, mode: mode_t) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__fstat64_time64")] + pub fn fstat64(fildes: c_int, buf: *mut stat64) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__fstatat64_time64")] + #[cfg(not(target_os = "l4re"))] + pub fn fstatat64( + dirfd: c_int, + pathname: *const c_char, + buf: *mut stat64, + flags: c_int, + ) -> c_int; + pub fn ftruncate64(fd: c_int, length: off64_t) -> c_int; + pub fn lseek64(fd: c_int, offset: off64_t, whence: c_int) -> off64_t; + #[cfg_attr(gnu_time_bits64, link_name = "__lstat64_time64")] + #[cfg(not(target_os = "l4re"))] + pub fn lstat64(path: *const c_char, buf: *mut stat64) -> c_int; + pub fn mmap64( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off64_t, + ) -> *mut c_void; + pub fn open64(path: *const c_char, oflag: c_int, ...) -> c_int; + pub fn openat64(fd: c_int, path: *const c_char, oflag: c_int, ...) -> c_int; + pub fn posix_fadvise64( + fd: c_int, + offset: off64_t, + len: off64_t, + advise: c_int, + ) -> c_int; + pub fn pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: off64_t) -> ssize_t; + pub fn pwrite64( + fd: c_int, + buf: *const c_void, + count: size_t, + offset: off64_t, + ) -> ssize_t; + pub fn readdir64(dirp: *mut crate::DIR) -> *mut crate::dirent64; + pub fn readdir64_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent64, + result: *mut *mut crate::dirent64, + ) -> c_int; + #[cfg_attr(gnu_time_bits64, link_name = "__stat64_time64")] + #[cfg(not(target_os = "l4re"))] + pub fn stat64(path: *const c_char, buf: *mut stat64) -> c_int; + pub fn truncate64(path: *const c_char, length: off64_t) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(any( + target_env = "uclibc", + target_env = "musl", + target_env = "ohos", + target_os = "emscripten", + )))] { + extern "C" { + pub fn preadv64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, + ) -> ssize_t; + pub fn pwritev64( + fd: c_int, + iov: *const crate::iovec, + iovcnt: c_int, + offset: off64_t, + ) -> ssize_t; + } + } +} + +cfg_if! { + if #[cfg(not(target_env = "uclibc"))] { + extern "C" { + // uclibc has separate non-const version of this function + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> crate::pid_t; + // uclibc has separate non-const version of this function + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> c_int; + } + } +} + +// The statx syscall, available on some libcs. +cfg_if! { + if #[cfg(any( + target_env = "gnu", + target_os = "android", + all(target_env = "musl", musl_v1_2_3) + ))] { + extern "C" { + pub fn statx( + dirfd: c_int, + pathname: *const c_char, + flags: c_int, + mask: c_uint, + statxbuf: *mut statx, + ) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(target_os = "emscripten")] { + mod emscripten; + pub use self::emscripten::*; + } else if #[cfg(target_os = "linux")] { + mod linux; + pub use self::linux::*; + mod linux_l4re_shared; + pub use self::linux_l4re_shared::*; + } else if #[cfg(target_os = "l4re")] { + mod l4re; + pub use self::l4re::*; + mod linux_l4re_shared; + pub use self::linux_l4re_shared::*; + } else if #[cfg(target_os = "android")] { + mod android; + pub use self::android::*; + } else { + // Unknown target_os + } +} diff --git a/deps/crates/vendor/libc/src/unix/mod.rs b/deps/crates/vendor/libc/src/unix/mod.rs new file mode 100644 index 00000000000000..207c36b82d55f0 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/mod.rs @@ -0,0 +1,2500 @@ +//! Definitions found commonly among almost all Unix derivatives +//! +//! More functions and definitions can be found in the more specific modules +//! according to the platform in question. + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type pid_t = i32; +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type sighandler_t = size_t; +pub type cc_t = c_uchar; + +cfg_if! { + if #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita" + ))] { + pub type uid_t = c_ushort; + pub type gid_t = c_ushort; + } else if #[cfg(target_os = "nto")] { + pub type uid_t = i32; + pub type gid_t = i32; + } else { + pub type uid_t = u32; + pub type gid_t = u32; + } +} + +extern_ty! { + pub enum DIR {} +} + +#[cfg(not(target_os = "nuttx"))] +pub type locale_t = *mut c_void; + +s! { + pub struct group { + pub gr_name: *mut c_char, + pub gr_passwd: *mut c_char, + pub gr_gid: crate::gid_t, + pub gr_mem: *mut *mut c_char, + } + + pub struct utimbuf { + pub actime: time_t, + pub modtime: time_t, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: time_t, + #[cfg(not(gnu_time_bits64))] + pub tv_usec: crate::suseconds_t, + // For 64 bit time on 32 bit linux glibc, suseconds_t is still + // a 32 bit type. Use __suseconds64_t instead + #[cfg(gnu_time_bits64)] + pub tv_usec: __suseconds64_t, + } + + // linux x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 + #[derive(Default)] + #[cfg(not(target_env = "gnu"))] + pub struct timespec { + pub tv_sec: time_t, + #[cfg(all(musl32_time64, target_endian = "big"))] + __pad0: Padding, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub tv_nsec: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub tv_nsec: c_long, + #[cfg(all(musl32_time64, target_endian = "little"))] + __pad0: Padding, + } + + pub struct rlimit { + pub rlim_cur: rlim_t, + pub rlim_max: rlim_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad1: Padding, + pub ru_ixrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad2: Padding, + pub ru_idrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad3: Padding, + pub ru_isrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad4: Padding, + pub ru_minflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad5: Padding, + pub ru_majflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad6: Padding, + pub ru_nswap: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad7: Padding, + pub ru_inblock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad8: Padding, + pub ru_oublock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad9: Padding, + pub ru_msgsnd: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad10: Padding, + pub ru_msgrcv: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad11: Padding, + pub ru_nsignals: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad12: Padding, + pub ru_nvcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad13: Padding, + pub ru_nivcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad14: Padding, + + #[cfg(any(target_env = "musl", target_env = "ohos", target_os = "emscripten"))] + __reserved: Padding<[c_long; 16]>, + } + + #[cfg(not(target_os = "nuttx"))] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + #[cfg(target_os = "android")] + pub ipv6mr_interface: c_int, + #[cfg(not(target_os = "android"))] + pub ipv6mr_interface: c_uint, + } + + #[cfg(all(not(target_os = "cygwin"), not(target_os = "horizon")))] + pub struct hostent { + pub h_name: *mut c_char, + pub h_aliases: *mut *mut c_char, + pub h_addrtype: c_int, + pub h_length: c_int, + pub h_addr_list: *mut *mut c_char, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + #[cfg(not(target_os = "horizon"))] + pub struct pollfd { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + } + + pub struct winsize { + pub ws_row: c_ushort, + pub ws_col: c_ushort, + pub ws_xpixel: c_ushort, + pub ws_ypixel: c_ushort, + } + + #[cfg(not(target_os = "cygwin"))] + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + pub struct sigval { + // Actually a union of an int and a void* + pub sival_ptr: *mut c_void, + } + + // + pub struct itimerval { + pub it_interval: crate::timeval, + pub it_value: crate::timeval, + } + + // + pub struct tms { + pub tms_utime: crate::clock_t, + pub tms_stime: crate::clock_t, + pub tms_cutime: crate::clock_t, + pub tms_cstime: crate::clock_t, + } + + pub struct servent { + pub s_name: *mut c_char, + pub s_aliases: *mut *mut c_char, + #[cfg(target_os = "cygwin")] + pub s_port: c_short, + #[cfg(not(target_os = "cygwin"))] + pub s_port: c_int, + pub s_proto: *mut c_char, + } + + pub struct protoent { + pub p_name: *mut c_char, + pub p_aliases: *mut *mut c_char, + #[cfg(not(target_os = "cygwin"))] + pub p_proto: c_int, + #[cfg(target_os = "cygwin")] + pub p_proto: c_short, + } + + #[repr(align(4))] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = !0 as sighandler_t; + +cfg_if! { + if #[cfg(all( + not(target_os = "nto"), + not(target_os = "aix"), + not(target_os = "espidf") + ))] { + pub const DT_UNKNOWN: u8 = 0; + pub const DT_FIFO: u8 = 1; + pub const DT_CHR: u8 = 2; + pub const DT_DIR: u8 = 4; + pub const DT_BLK: u8 = 6; + pub const DT_REG: u8 = 8; + pub const DT_LNK: u8 = 10; + pub const DT_SOCK: u8 = 12; + } +} +cfg_if! { + if #[cfg(not(target_os = "redox"))] { + pub const FD_CLOEXEC: c_int = 0x1; + } +} + +cfg_if! { + if #[cfg(not(any(target_os = "nto", target_os = "l4re")))] { + pub const USRQUOTA: c_int = 0; + pub const GRPQUOTA: c_int = 1; + } +} +pub const SIGIOT: c_int = 6; + +pub const S_ISUID: mode_t = 0o4000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISVTX: mode_t = 0o1000; + +cfg_if! { + if #[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "solaris", + target_os = "cygwin" + )))] { + pub const IF_NAMESIZE: size_t = 16; + pub const IFNAMSIZ: size_t = IF_NAMESIZE; + } +} + +pub const LOG_EMERG: c_int = 0; +pub const LOG_ALERT: c_int = 1; +pub const LOG_CRIT: c_int = 2; +pub const LOG_ERR: c_int = 3; +pub const LOG_WARNING: c_int = 4; +pub const LOG_NOTICE: c_int = 5; +pub const LOG_INFO: c_int = 6; +pub const LOG_DEBUG: c_int = 7; + +pub const LOG_KERN: c_int = 0; +pub const LOG_USER: c_int = 1 << 3; +pub const LOG_MAIL: c_int = 2 << 3; +pub const LOG_DAEMON: c_int = 3 << 3; +pub const LOG_AUTH: c_int = 4 << 3; +pub const LOG_SYSLOG: c_int = 5 << 3; +pub const LOG_LPR: c_int = 6 << 3; +pub const LOG_NEWS: c_int = 7 << 3; +pub const LOG_UUCP: c_int = 8 << 3; +pub const LOG_LOCAL0: c_int = 16 << 3; +pub const LOG_LOCAL1: c_int = 17 << 3; +pub const LOG_LOCAL2: c_int = 18 << 3; +pub const LOG_LOCAL3: c_int = 19 << 3; +pub const LOG_LOCAL4: c_int = 20 << 3; +pub const LOG_LOCAL5: c_int = 21 << 3; +pub const LOG_LOCAL6: c_int = 22 << 3; +pub const LOG_LOCAL7: c_int = 23 << 3; + +cfg_if! { + if #[cfg(not(target_os = "haiku"))] { + pub const LOG_PID: c_int = 0x01; + pub const LOG_CONS: c_int = 0x02; + pub const LOG_ODELAY: c_int = 0x04; + pub const LOG_NDELAY: c_int = 0x08; + pub const LOG_NOWAIT: c_int = 0x10; + } +} +pub const LOG_PRIMASK: c_int = 7; +pub const LOG_FACMASK: c_int = 0x3f8; + +cfg_if! { + if #[cfg(not(target_os = "nto"))] { + pub const PRIO_MIN: c_int = -20; + pub const PRIO_MAX: c_int = 20; + } +} +pub const IPPROTO_ICMP: c_int = 1; +pub const IPPROTO_ICMPV6: c_int = 58; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_UDP: c_int = 17; +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_IPV6: c_int = 41; + +pub const INADDR_LOOPBACK: in_addr_t = 2130706433; +pub const INADDR_ANY: in_addr_t = 0; +pub const INADDR_BROADCAST: in_addr_t = 4294967295; +pub const INADDR_NONE: in_addr_t = 4294967295; + +pub const IN6ADDR_LOOPBACK_INIT: in6_addr = in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], +}; + +pub const IN6ADDR_ANY_INIT: in6_addr = in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +}; + +pub const ARPOP_REQUEST: u16 = 1; +pub const ARPOP_REPLY: u16 = 2; + +pub const ATF_COM: c_int = 0x02; +pub const ATF_PERM: c_int = 0x04; +pub const ATF_PUBL: c_int = 0x08; +pub const ATF_USETRAILERS: c_int = 0x10; + +cfg_if! { + if #[cfg(any(target_os = "nto", target_os = "aix"))] { + pub const FNM_PERIOD: c_int = 1 << 1; + } else { + pub const FNM_PERIOD: c_int = 1 << 2; + } +} +pub const FNM_NOMATCH: c_int = 1; + +cfg_if! { + if #[cfg(any( + target_os = "illumos", + target_os = "solaris", + target_os = "netbsd" + ))] { + pub const FNM_CASEFOLD: c_int = 1 << 3; + } else if #[cfg(not(target_os = "aix"))] { + pub const FNM_CASEFOLD: c_int = 1 << 4; + } +} + +cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "android", + target_os = "openbsd", + target_os = "cygwin", + target_os = "netbsd", + ))] { + pub const FNM_PATHNAME: c_int = 1 << 1; + } else { + pub const FNM_PATHNAME: c_int = 1 << 0; + } +} + +cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "android", + target_os = "openbsd", + target_os = "netbsd", + target_os = "cygwin", + ))] { + pub const FNM_NOESCAPE: c_int = 1 << 0; + } else if #[cfg(target_os = "nto")] { + pub const FNM_NOESCAPE: c_int = 1 << 2; + } else if #[cfg(target_os = "aix")] { + pub const FNM_NOESCAPE: c_int = 1 << 3; + } else { + pub const FNM_NOESCAPE: c_int = 1 << 1; + } +} + +extern "C" { + pub static in6addr_loopback: in6_addr; + pub static in6addr_any: in6_addr; +} + +cfg_if! { + if #[cfg(any( + target_os = "l4re", + target_os = "espidf", + target_os = "nuttx" + ))] { + // required libraries are linked externally for these platforms: + // * L4Re + // * ESP-IDF + // * NuttX + } else if #[cfg(feature = "std")] { + // cargo build, don't pull in anything extra as the std dep + // already pulls in all libs. + } else if #[cfg(all( + any( + all( + target_os = "linux", + any(target_env = "gnu", target_env = "uclibc") + ), + target_os = "cygwin" + ), + feature = "rustc-dep-of-std" + ))] { + #[link( + name = "util", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "rt", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "pthread", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "m", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "dl", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "gcc_eh", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "gcc", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link(name = "util", cfg(not(target_feature = "crt-static")))] + #[link(name = "rt", cfg(not(target_feature = "crt-static")))] + #[link(name = "pthread", cfg(not(target_feature = "crt-static")))] + #[link(name = "m", cfg(not(target_feature = "crt-static")))] + #[link(name = "dl", cfg(not(target_feature = "crt-static")))] + #[link(name = "c", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } else if #[cfg(any(target_env = "musl", target_env = "ohos"))] { + #[cfg_attr( + feature = "rustc-dep-of-std", + link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + ) + )] + #[cfg_attr( + feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))) + )] + extern "C" {} + } else if #[cfg(target_os = "emscripten")] { + // Don't pass -lc to Emscripten, it breaks. See: + // https://github.com/emscripten-core/emscripten/issues/22758 + } else if #[cfg(all(target_os = "android", feature = "rustc-dep-of-std"))] { + #[link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link( + name = "m", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + )] + #[link(name = "m", cfg(not(target_feature = "crt-static")))] + #[link(name = "c", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos", + target_os = "android", + target_os = "openbsd", + target_os = "nto", + ))] { + #[link(name = "c")] + #[link(name = "m")] + extern "C" {} + } else if #[cfg(target_os = "haiku")] { + #[link(name = "root")] + #[link(name = "network")] + extern "C" {} + } else if #[cfg(target_env = "newlib")] { + #[link(name = "c")] + #[link(name = "m")] + extern "C" {} + } else if #[cfg(target_env = "illumos")] { + #[link(name = "c")] + #[link(name = "m")] + extern "C" {} + } else if #[cfg(target_os = "redox")] { + #[cfg_attr( + feature = "rustc-dep-of-std", + link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + ) + )] + #[cfg_attr( + feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))) + )] + extern "C" {} + } else if #[cfg(target_os = "aix")] { + #[link(name = "c")] + #[link(name = "m")] + #[link(name = "bsd")] + #[link(name = "pthread")] + extern "C" {} + } else { + #[link(name = "c")] + #[link(name = "m")] + #[link(name = "rt")] + #[link(name = "pthread")] + extern "C" {} + } +} + +cfg_if! { + if #[cfg(not(all(target_os = "linux", target_env = "gnu")))] { + extern_ty! { + pub enum fpos_t {} // FIXME(unix): fill this out with a struct + } + } +} + +extern_ty! { + pub enum FILE {} +} + +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn qsort( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + ); + pub fn bsearch( + key: *const c_void, + base: *const c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + ) -> *mut c_void; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fopen$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "fopen64")] + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "freopen$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "freopen64")] + pub fn freopen(filename: *const c_char, mode: *const c_char, file: *mut FILE) -> *mut FILE; + + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "tmpfile64")] + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fputs$UNIX2003" + )] + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fwrite$UNIX2003" + )] + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + #[cfg_attr(target_os = "netbsd", link_name = "__fgetpos50")] + #[cfg_attr(gnu_file_offset_bits64, link_name = "fgetpos64")] + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__fsetpos50")] + #[cfg_attr(gnu_file_offset_bits64, link_name = "fsetpos64")] + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn clearerr(stream: *mut FILE); + pub fn perror(s: *const c_char); + pub fn atof(s: *const c_char) -> c_double; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atol(s: *const c_char) -> c_long; + pub fn atoll(s: *const c_char) -> c_longlong; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "strtod$UNIX2003" + )] + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtof(s: *const c_char, endp: *mut *mut c_char) -> c_float; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoll(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoull(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulonglong; + #[cfg_attr(target_os = "aix", link_name = "vec_calloc")] + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + #[cfg_attr(target_os = "aix", link_name = "vec_malloc")] + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "system$UNIX2003" + )] + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn stpcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strndup(cs: *const c_char, n: size_t) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "strerror$UNIX2003" + )] + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strtok_r(s: *mut c_char, t: *const c_char, p: *mut *mut c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn strsignal(sig: c_int) -> *mut c_char; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memccpy(dest: *mut c_void, src: *const c_void, c: c_int, n: size_t) -> *mut c_void; +} + +extern "C" { + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam50")] + pub fn getpwnam(name: *const c_char) -> *mut passwd; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid50")] + pub fn getpwuid(uid: crate::uid_t) -> *mut passwd; + + pub fn fprintf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn snprintf(s: *mut c_char, n: size_t, format: *const c_char, ...) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + #[cfg_attr( + all(target_os = "linux", not(target_env = "uclibc")), + link_name = "__isoc99_fscanf" + )] + pub fn fscanf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + #[cfg_attr( + all(target_os = "linux", not(target_env = "uclibc")), + link_name = "__isoc99_scanf" + )] + pub fn scanf(format: *const c_char, ...) -> c_int; + #[cfg_attr( + all(target_os = "linux", not(target_env = "uclibc")), + link_name = "__isoc99_sscanf" + )] + pub fn sscanf(s: *const c_char, format: *const c_char, ...) -> c_int; + pub fn getchar_unlocked() -> c_int; + pub fn putchar_unlocked(c: c_int) -> c_int; + + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr(target_os = "netbsd", link_name = "__socket30")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_socket")] + #[cfg_attr(target_os = "solaris", link_name = "__xnet7_socket")] + #[cfg_attr(target_os = "espidf", link_name = "lwip_socket")] + pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "connect$UNIX2003" + )] + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__xnet_connect" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_connect")] + pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "listen$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_listen")] + pub fn listen(socket: c_int, backlog: c_int) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "accept$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_accept")] + #[cfg_attr(target_os = "aix", link_name = "naccept")] + pub fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getpeername$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_getpeername")] + #[cfg_attr(target_os = "aix", link_name = "ngetpeername")] + pub fn getpeername(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) + -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getsockname$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_getsockname")] + #[cfg_attr(target_os = "aix", link_name = "ngetsockname")] + pub fn getsockname(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) + -> c_int; + #[cfg_attr(target_os = "espidf", link_name = "lwip_setsockopt")] + #[cfg_attr(gnu_time_bits64, link_name = "__setsockopt64")] + pub fn setsockopt( + socket: c_int, + level: c_int, + name: c_int, + value: *const c_void, + option_len: socklen_t, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "socketpair$UNIX2003" + )] + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__xnet_socketpair" + )] + pub fn socketpair( + domain: c_int, + type_: c_int, + protocol: c_int, + socket_vector: *mut c_int, + ) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sendto$UNIX2003" + )] + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__xnet_sendto" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_sendto")] + pub fn sendto( + socket: c_int, + buf: *const c_void, + len: size_t, + flags: c_int, + addr: *const sockaddr, + addrlen: socklen_t, + ) -> ssize_t; + #[cfg_attr(target_os = "espidf", link_name = "lwip_shutdown")] + pub fn shutdown(socket: c_int, how: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "chmod$UNIX2003" + )] + pub fn chmod(path: *const c_char, mode: mode_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fchmod$UNIX2003" + )] + pub fn fchmod(fd: c_int, mode: mode_t) -> c_int; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "fstat$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__fstat50")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "fstat@FBSD_1.0" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__fstat64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "fstat64" + )] + #[cfg_attr(musl_redir_time64, link_name = "__fstat_time64")] + pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; + + pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "stat$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__stat50")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "stat@FBSD_1.0" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__stat64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "stat64" + )] + #[cfg_attr(musl_redir_time64, link_name = "__stat_time64")] + pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; + + pub fn pclose(stream: *mut crate::FILE) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fdopen$UNIX2003" + )] + pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut crate::FILE; + pub fn fileno(stream: *mut crate::FILE) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "open$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "open64")] + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "creat$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "creat64")] + pub fn creat(path: *const c_char, mode: mode_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fcntl$UNIX2003" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__fcntl_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "__fcntl_time64" + )] + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "opendir$INODE64" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "opendir$INODE64$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__opendir30")] + pub fn opendir(dirname: *const c_char) -> *mut crate::DIR; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "readdir$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__readdir30")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "readdir@FBSD_1.0" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "readdir64")] + pub fn readdir(dirp: *mut crate::DIR) -> *mut crate::dirent; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "closedir$UNIX2003" + )] + pub fn closedir(dirp: *mut crate::DIR) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "rewinddir$INODE64" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "rewinddir$INODE64$UNIX2003" + )] + pub fn rewinddir(dirp: *mut crate::DIR); + + pub fn fchmodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, flags: c_int) -> c_int; + pub fn fchown(fd: c_int, owner: crate::uid_t, group: crate::gid_t) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn fchownat( + dirfd: c_int, + pathname: *const c_char, + owner: crate::uid_t, + group: crate::gid_t, + flags: c_int, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "fstatat$INODE64" + )] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "fstatat@FBSD_1.1" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__fstatat64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "fstatat64" + )] + #[cfg(not(target_os = "l4re"))] + #[cfg_attr(musl_redir_time64, link_name = "__fstatat_time64")] + pub fn fstatat(dirfd: c_int, pathname: *const c_char, buf: *mut stat, flags: c_int) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn linkat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn renameat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + ) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn symlinkat(target: *const c_char, newdirfd: c_int, linkpath: *const c_char) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int; + + pub fn access(path: *const c_char, amode: c_int) -> c_int; + pub fn alarm(seconds: c_uint) -> c_uint; + pub fn chdir(dir: *const c_char) -> c_int; + pub fn fchdir(dirfd: c_int) -> c_int; + pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "lchown$UNIX2003" + )] + pub fn lchown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "close$NOCANCEL$UNIX2003" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "close$NOCANCEL" + )] + pub fn close(fd: c_int) -> c_int; + pub fn dup(fd: c_int) -> c_int; + pub fn dup2(src: c_int, dst: c_int) -> c_int; + + pub fn execl(path: *const c_char, arg0: *const c_char, ...) -> c_int; + pub fn execle(path: *const c_char, arg0: *const c_char, ...) -> c_int; + pub fn execlp(file: *const c_char, arg0: *const c_char, ...) -> c_int; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int; + pub fn execve( + prog: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; + + pub fn fork() -> pid_t; + pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + pub fn getegid() -> gid_t; + pub fn geteuid() -> uid_t; + pub fn getgid() -> gid_t; + pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; + #[cfg_attr(target_os = "illumos", link_name = "getloginx")] + pub fn getlogin() -> *mut c_char; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getopt$UNIX2003" + )] + pub fn getopt(argc: c_int, argv: *const *mut c_char, optstr: *const c_char) -> c_int; + pub fn getpgid(pid: pid_t) -> pid_t; + pub fn getpgrp() -> pid_t; + pub fn getpid() -> pid_t; + pub fn getppid() -> pid_t; + pub fn getuid() -> uid_t; + pub fn isatty(fd: c_int) -> c_int; + #[cfg_attr(target_os = "solaris", link_name = "__link_xpg4")] + pub fn link(src: *const c_char, dst: *const c_char) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "lseek64")] + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: c_int) -> c_long; + pub fn pipe(fds: *mut c_int) -> c_int; + pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; + pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "read$UNIX2003" + )] + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; + pub fn rmdir(path: *const c_char) -> c_int; + pub fn seteuid(uid: uid_t) -> c_int; + pub fn setegid(gid: gid_t) -> c_int; + pub fn setgid(gid: gid_t) -> c_int; + pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int; + pub fn setsid() -> pid_t; + pub fn setuid(uid: uid_t) -> c_int; + pub fn setreuid(ruid: uid_t, euid: uid_t) -> c_int; + pub fn setregid(rgid: gid_t, egid: gid_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sleep$UNIX2003" + )] + pub fn sleep(secs: c_uint) -> c_uint; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "nanosleep$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__nanosleep50")] + #[cfg_attr(gnu_time_bits64, link_name = "__nanosleep64")] + #[cfg_attr(musl_redir_time64, link_name = "__nanosleep_time64")] + pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int; + pub fn tcgetpgrp(fd: c_int) -> pid_t; + pub fn tcsetpgrp(fd: c_int, pgrp: crate::pid_t) -> c_int; + pub fn ttyname(fd: c_int) -> *mut c_char; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "ttyname_r$UNIX2003" + )] + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__posix_ttyname_r" + )] + pub fn ttyname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + pub fn unlink(c: *const c_char) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "wait$UNIX2003" + )] + pub fn wait(status: *mut c_int) -> pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "waitpid$UNIX2003" + )] + pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "write$UNIX2003" + )] + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pread$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "pread64")] + pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pwrite$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "pwrite64")] + pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn umask(mask: mode_t) -> mode_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__utime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__utime64")] + pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "kill$UNIX2003" + )] + pub fn kill(pid: pid_t, sig: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "killpg$UNIX2003" + )] + pub fn killpg(pgrp: pid_t, sig: c_int) -> c_int; + + pub fn mlock(addr: *const c_void, len: size_t) -> c_int; + pub fn munlock(addr: *const c_void, len: size_t) -> c_int; + pub fn mlockall(flags: c_int) -> c_int; + pub fn munlockall() -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "mmap$UNIX2003" + )] + #[cfg_attr(gnu_file_offset_bits64, link_name = "mmap64")] + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "munmap$UNIX2003" + )] + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + + pub fn if_nametoindex(ifname: *const c_char) -> c_uint; + pub fn if_indextoname(ifindex: c_uint, ifname: *mut c_char) -> *mut c_char; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "lstat$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__lstat50")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "lstat@FBSD_1.0" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__lstat64_time64")] + #[cfg_attr( + all(not(gnu_time_bits64), gnu_file_offset_bits64), + link_name = "lstat64" + )] + #[cfg_attr(musl_redir_time64, link_name = "__lstat_time64")] + pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fsync$UNIX2003" + )] + pub fn fsync(fd: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "setenv$UNIX2003" + )] + pub fn setenv(name: *const c_char, val: *const c_char, overwrite: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "unsetenv$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__unsetenv13")] + pub fn unsetenv(name: *const c_char) -> c_int; + + pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int; + + #[cfg_attr(gnu_file_offset_bits64, link_name = "truncate64")] + pub fn truncate(path: *const c_char, length: off_t) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "ftruncate64")] + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__getrusage50")] + #[cfg_attr(gnu_time_bits64, link_name = "__getrusage64")] + #[cfg_attr(musl_redir_time64, link_name = "__getrusage_time64")] + pub fn getrusage(resource: c_int, usage: *mut rusage) -> c_int; + + #[cfg_attr( + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" + ), + link_name = "realpath$DARWIN_EXTSN" + )] + pub fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char; + + #[cfg_attr(target_os = "netbsd", link_name = "__times13")] + pub fn times(buf: *mut crate::tms) -> crate::clock_t; + + pub fn pthread_self() -> crate::pthread_t; + pub fn pthread_equal(t1: crate::pthread_t, t2: crate::pthread_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_join$UNIX2003" + )] + pub fn pthread_join(native: crate::pthread_t, value: *mut *mut c_void) -> c_int; + pub fn pthread_exit(value: *mut c_void) -> !; + pub fn pthread_attr_init(attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_destroy(attr: *mut crate::pthread_attr_t) -> c_int; + pub fn pthread_attr_getstacksize( + attr: *const crate::pthread_attr_t, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setstacksize(attr: *mut crate::pthread_attr_t, stack_size: size_t) + -> c_int; + pub fn pthread_attr_setdetachstate(attr: *mut crate::pthread_attr_t, state: c_int) -> c_int; + pub fn pthread_detach(thread: crate::pthread_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__libc_thr_yield")] + pub fn sched_yield() -> c_int; + pub fn pthread_key_create( + key: *mut crate::pthread_key_t, + dtor: Option, + ) -> c_int; + pub fn pthread_key_delete(key: crate::pthread_key_t) -> c_int; + pub fn pthread_getspecific(key: crate::pthread_key_t) -> *mut c_void; + pub fn pthread_setspecific(key: crate::pthread_key_t, value: *const c_void) -> c_int; + pub fn pthread_mutex_init( + lock: *mut crate::pthread_mutex_t, + attr: *const crate::pthread_mutexattr_t, + ) -> c_int; + pub fn pthread_mutex_destroy(lock: *mut crate::pthread_mutex_t) -> c_int; + pub fn pthread_mutex_lock(lock: *mut crate::pthread_mutex_t) -> c_int; + pub fn pthread_mutex_trylock(lock: *mut crate::pthread_mutex_t) -> c_int; + pub fn pthread_mutex_unlock(lock: *mut crate::pthread_mutex_t) -> c_int; + + pub fn pthread_mutexattr_init(attr: *mut crate::pthread_mutexattr_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_mutexattr_destroy$UNIX2003" + )] + pub fn pthread_mutexattr_destroy(attr: *mut crate::pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_settype(attr: *mut crate::pthread_mutexattr_t, _type: c_int) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_init$UNIX2003" + )] + pub fn pthread_cond_init( + cond: *mut crate::pthread_cond_t, + attr: *const crate::pthread_condattr_t, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_wait$UNIX2003" + )] + pub fn pthread_cond_wait( + cond: *mut crate::pthread_cond_t, + lock: *mut crate::pthread_mutex_t, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_timedwait$UNIX2003" + )] + #[cfg_attr(gnu_time_bits64, link_name = "__pthread_cond_timedwait64")] + #[cfg_attr(musl_redir_time64, link_name = "__pthread_cond_timedwait_time64")] + pub fn pthread_cond_timedwait( + cond: *mut crate::pthread_cond_t, + lock: *mut crate::pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_cond_signal(cond: *mut crate::pthread_cond_t) -> c_int; + pub fn pthread_cond_broadcast(cond: *mut crate::pthread_cond_t) -> c_int; + pub fn pthread_cond_destroy(cond: *mut crate::pthread_cond_t) -> c_int; + pub fn pthread_condattr_init(attr: *mut crate::pthread_condattr_t) -> c_int; + pub fn pthread_condattr_destroy(attr: *mut crate::pthread_condattr_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_init$UNIX2003" + )] + pub fn pthread_rwlock_init( + lock: *mut crate::pthread_rwlock_t, + attr: *const crate::pthread_rwlockattr_t, + ) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_destroy$UNIX2003" + )] + pub fn pthread_rwlock_destroy(lock: *mut crate::pthread_rwlock_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_rdlock$UNIX2003" + )] + pub fn pthread_rwlock_rdlock(lock: *mut crate::pthread_rwlock_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_tryrdlock$UNIX2003" + )] + pub fn pthread_rwlock_tryrdlock(lock: *mut crate::pthread_rwlock_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_wrlock$UNIX2003" + )] + pub fn pthread_rwlock_wrlock(lock: *mut crate::pthread_rwlock_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_trywrlock$UNIX2003" + )] + pub fn pthread_rwlock_trywrlock(lock: *mut crate::pthread_rwlock_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_unlock$UNIX2003" + )] + pub fn pthread_rwlock_unlock(lock: *mut crate::pthread_rwlock_t) -> c_int; + pub fn pthread_rwlockattr_init(attr: *mut crate::pthread_rwlockattr_t) -> c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut crate::pthread_rwlockattr_t) -> c_int; + + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__xnet_getsockopt" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_getsockopt")] + #[cfg_attr(gnu_time_bits64, link_name = "__getsockopt64")] + pub fn getsockopt( + sockfd: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut crate::socklen_t, + ) -> c_int; + pub fn raise(signum: c_int) -> c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__utimes50")] + #[cfg_attr(gnu_time_bits64, link_name = "__utimes64")] + #[cfg_attr(musl_redir_time64, link_name = "__utimes_time64")] + pub fn utimes(filename: *const c_char, times: *const crate::timeval) -> c_int; + pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void; + pub fn dlerror() -> *mut c_char; + #[cfg_attr(musl_redir_time64, link_name = "__dlsym_time64")] + pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; + pub fn dlclose(handle: *mut c_void) -> c_int; + + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr( + any(target_os = "illumos", target_os = "solaris"), + link_name = "__xnet_getaddrinfo" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_getaddrinfo")] + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr(target_os = "espidf", link_name = "lwip_freeaddrinfo")] + pub fn freeaddrinfo(res: *mut addrinfo); + pub fn hstrerror(errcode: c_int) -> *const c_char; + pub fn gai_strerror(errcode: c_int) -> *const c_char; + #[cfg_attr( + any( + all( + target_os = "linux", + not(any(target_env = "musl", target_env = "ohos")) + ), + target_os = "freebsd", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "haiku" + ), + link_name = "__res_init" + )] + #[cfg_attr( + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" + ), + link_name = "res_9_init" + )] + #[cfg_attr(target_os = "aix", link_name = "_res_init")] + #[cfg(not(target_os = "l4re"))] + pub fn res_init() -> c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__gmtime_r50")] + #[cfg_attr(gnu_time_bits64, link_name = "__gmtime64_r")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + #[cfg_attr(musl_redir_time64, link_name = "__gmtime64_r")] + pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__localtime_r50")] + #[cfg_attr(gnu_time_bits64, link_name = "__localtime64_r")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + #[cfg_attr(musl_redir_time64, link_name = "__localtime64_r")] + pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "mktime$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__mktime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__mktime64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + pub fn mktime(tm: *mut tm) -> time_t; + #[cfg_attr(target_os = "netbsd", link_name = "__time50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__time64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + pub fn time(time: *mut time_t) -> time_t; + #[cfg_attr(target_os = "netbsd", link_name = "__gmtime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__gmtime64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + pub fn gmtime(time_p: *const time_t) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__locatime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__localtime64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + pub fn localtime(time_p: *const time_t) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__difftime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__difftime64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + pub fn difftime(time1: time_t, time0: time_t) -> c_double; + #[cfg(not(target_os = "aix"))] + #[cfg_attr(target_os = "netbsd", link_name = "__timegm50")] + #[cfg_attr(gnu_time_bits64, link_name = "__timegm64")] + #[cfg_attr(not(musl32_time64), allow(deprecated))] + #[cfg_attr(musl_redir_time64, link_name = "__timegm_time64")] + pub fn timegm(tm: *mut crate::tm) -> time_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__mknod50")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "mknod@FBSD_1.0" + )] + pub fn mknod(pathname: *const c_char, mode: mode_t, dev: crate::dev_t) -> c_int; + #[cfg(not(target_os = "espidf"))] + pub fn gethostname(name: *mut c_char, len: size_t) -> c_int; + pub fn endservent(); + pub fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut servent; + pub fn getservbyport(port: c_int, proto: *const c_char) -> *mut servent; + pub fn getservent() -> *mut servent; + pub fn setservent(stayopen: c_int); + pub fn getprotobyname(name: *const c_char) -> *mut protoent; + pub fn getprotobynumber(proto: c_int) -> *mut protoent; + pub fn chroot(name: *const c_char) -> c_int; + #[cfg(target_os = "cygwin")] + pub fn usleep(secs: useconds_t) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "usleep$UNIX2003" + )] + #[cfg(not(target_os = "cygwin"))] + pub fn usleep(secs: c_uint) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "send$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_send")] + pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "recv$UNIX2003" + )] + #[cfg_attr(target_os = "espidf", link_name = "lwip_recv")] + pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "putenv$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__putenv50")] + pub fn putenv(string: *mut c_char) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "poll$UNIX2003" + )] + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "select$1050" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "select$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__select50")] + #[cfg_attr(target_os = "aix", link_name = "__fd_select")] + #[cfg_attr(gnu_time_bits64, link_name = "__select64")] + #[cfg_attr(musl_redir_time64, link_name = "__select_time64")] + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__setlocale50")] + pub fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char; + pub fn localeconv() -> *mut lconv; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "sem_wait$UNIX2003" + )] + pub fn sem_wait(sem: *mut sem_t) -> c_int; + pub fn sem_trywait(sem: *mut sem_t) -> c_int; + pub fn sem_post(sem: *mut sem_t) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "statvfs64")] + pub fn statvfs(path: *const c_char, buf: *mut crate::statvfs) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "fstatvfs64")] + pub fn fstatvfs(fd: c_int, buf: *mut crate::statvfs) -> c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + pub fn sigemptyset(set: *mut sigset_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] + pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigfillset14")] + pub fn sigfillset(set: *mut sigset_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigdelset14")] + pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigismember14")] + pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__sigprocmask14")] + pub fn sigprocmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigpending14")] + pub fn sigpending(set: *mut sigset_t) -> c_int; + + #[cfg_attr(target_os = "solaris", link_name = "__sysconf_xpg7")] + pub fn sysconf(name: c_int) -> c_long; + + pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int; + + #[cfg_attr(gnu_file_offset_bits64, link_name = "fseeko64")] + pub fn fseeko(stream: *mut crate::FILE, offset: off_t, whence: c_int) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "ftello64")] + pub fn ftello(stream: *mut crate::FILE) -> off_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "tcdrain$UNIX2003" + )] + pub fn tcdrain(fd: c_int) -> c_int; + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "arm"), + link_name = "cfgetispeed@GLIBC_2.4" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "csky"), + link_name = "cfgetispeed@GLIBC_2.29" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "m68k"), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", target_arch = "mips32r6") + ), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "powerpc"), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"), + link_name = "cfgetispeed@GLIBC_2.33" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc"), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "x86"), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "aarch64"), + link_name = "cfgetispeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "loongarch64"), + link_name = "cfgetispeed@GLIBC_2.36" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips64", target_arch = "mips64r6") + ), + link_name = "cfgetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "big" + ), + link_name = "cfgetispeed@GLIBC_2.3" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "little" + ), + link_name = "cfgetispeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv64"), + link_name = "cfgetispeed@GLIBC_2.27" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "s390x"), + link_name = "cfgetispeed@GLIBC_2.2" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "cfgetispeed@GLIBC_2.2" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "64" + ), + link_name = "cfgetispeed@GLIBC_2.2.5" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "32" + ), + link_name = "cfgetispeed@GLIBC_2.16" + )] + pub fn cfgetispeed(termios: *const crate::termios) -> crate::speed_t; + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "arm"), + link_name = "cfgetospeed@GLIBC_2.4" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "csky"), + link_name = "cfgetospeed@GLIBC_2.29" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "m68k"), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", target_arch = "mips32r6") + ), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "powerpc"), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"), + link_name = "cfgetospeed@GLIBC_2.33" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc"), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "x86"), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "aarch64"), + link_name = "cfgetospeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "loongarch64"), + link_name = "cfgetospeed@GLIBC_2.36" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips64", target_arch = "mips64r6") + ), + link_name = "cfgetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "big" + ), + link_name = "cfgetospeed@GLIBC_2.3" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "little" + ), + link_name = "cfgetospeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv64"), + link_name = "cfgetospeed@GLIBC_2.27" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "s390x"), + link_name = "cfgetospeed@GLIBC_2.2" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "cfgetospeed@GLIBC_2.2" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "64" + ), + link_name = "cfgetospeed@GLIBC_2.2.5" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "32" + ), + link_name = "cfgetospeed@GLIBC_2.16" + )] + pub fn cfgetospeed(termios: *const crate::termios) -> crate::speed_t; + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "arm"), + link_name = "cfsetispeed@GLIBC_2.4" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "csky"), + link_name = "cfsetispeed@GLIBC_2.29" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "m68k"), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", target_arch = "mips32r6") + ), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "powerpc"), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"), + link_name = "cfsetispeed@GLIBC_2.33" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc"), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "x86"), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "aarch64"), + link_name = "cfsetispeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "loongarch64"), + link_name = "cfsetispeed@GLIBC_2.36" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips64", target_arch = "mips64r6") + ), + link_name = "cfsetispeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "big" + ), + link_name = "cfsetispeed@GLIBC_2.3" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "little" + ), + link_name = "cfsetispeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv64"), + link_name = "cfsetispeed@GLIBC_2.27" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "s390x"), + link_name = "cfsetispeed@GLIBC_2.2" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "cfsetispeed@GLIBC_2.2" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "64" + ), + link_name = "cfsetispeed@GLIBC_2.2.5" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "32" + ), + link_name = "cfsetispeed@GLIBC_2.16" + )] + pub fn cfsetispeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "arm"), + link_name = "cfsetospeed@GLIBC_2.4" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "csky"), + link_name = "cfsetospeed@GLIBC_2.29" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "m68k"), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", target_arch = "mips32r6") + ), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "powerpc"), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"), + link_name = "cfsetospeed@GLIBC_2.33" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc"), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "x86"), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "aarch64"), + link_name = "cfsetospeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "loongarch64"), + link_name = "cfsetospeed@GLIBC_2.36" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips64", target_arch = "mips64r6") + ), + link_name = "cfsetospeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "big" + ), + link_name = "cfsetospeed@GLIBC_2.3" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "little" + ), + link_name = "cfsetospeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv64"), + link_name = "cfsetospeed@GLIBC_2.27" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "s390x"), + link_name = "cfsetospeed@GLIBC_2.2" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "cfsetospeed@GLIBC_2.2" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "64" + ), + link_name = "cfsetospeed@GLIBC_2.2.5" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "32" + ), + link_name = "cfsetospeed@GLIBC_2.16" + )] + pub fn cfsetospeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "sparc" + ), + ), + link_name = "tcgetattr@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "tcgetattr@GLIBC_2.2" + )] + pub fn tcgetattr(fd: c_int, termios: *mut crate::termios) -> c_int; + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "sparc" + ), + ), + link_name = "tcsetattr@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "tcsetattr@GLIBC_2.2" + )] + pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *const crate::termios) -> c_int; + pub fn tcflow(fd: c_int, action: c_int) -> c_int; + pub fn tcflush(fd: c_int, action: c_int) -> c_int; + pub fn tcgetsid(fd: c_int) -> crate::pid_t; + pub fn tcsendbreak(fd: c_int, duration: c_int) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "mkstemp64")] + pub fn mkstemp(template: *mut c_char) -> c_int; + pub fn mkdtemp(template: *mut c_char) -> *mut c_char; + + pub fn tmpnam(ptr: *mut c_char) -> *mut c_char; + + pub fn openlog(ident: *const c_char, logopt: c_int, facility: c_int); + pub fn closelog(); + pub fn setlogmask(maskpri: c_int) -> c_int; + #[cfg_attr(target_os = "macos", link_name = "syslog$DARWIN_EXTSN")] + pub fn syslog(priority: c_int, message: *const c_char, ...); + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "nice$UNIX2003" + )] + pub fn nice(incr: c_int) -> c_int; + + #[cfg(not(target_os = "l4re"))] + pub fn grantpt(fd: c_int) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn posix_openpt(flags: c_int) -> c_int; + #[cfg(not(target_os = "l4re"))] + pub fn ptsname(fd: c_int) -> *mut c_char; + #[cfg(not(target_os = "l4re"))] + pub fn unlockpt(fd: c_int) -> c_int; + + #[cfg(not(target_os = "aix"))] + pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn getline(lineptr: *mut *mut c_char, n: *mut size_t, stream: *mut FILE) -> ssize_t; + + #[cfg_attr(gnu_file_offset_bits64, link_name = "lockf64")] + pub fn lockf(fd: c_int, cmd: c_int, len: off_t) -> c_int; + +} + +safe_f! { + // It seems htonl, etc are macros on macOS. So we have to reimplement them. So let's + // reimplement them for all UNIX platforms + pub const fn htonl(hostlong: u32) -> u32 { + u32::to_be(hostlong) + } + pub const fn htons(hostshort: u16) -> u16 { + u16::to_be(hostshort) + } + pub const fn ntohl(netlong: u32) -> u32 { + u32::from_be(netlong) + } + pub const fn ntohs(netshort: u16) -> u16 { + u16::from_be(netshort) + } +} + +cfg_if! { + if #[cfg(not(any( + target_os = "emscripten", + target_os = "android", + target_os = "haiku", + target_os = "nto", + target_os = "solaris", + target_os = "cygwin", + target_os = "aix", + target_os = "l4re", + )))] { + extern "C" { + #[cfg_attr(target_os = "netbsd", link_name = "__adjtime50")] + #[cfg_attr(any(gnu_time_bits64, musl_redir_time64), link_name = "__adjtime64")] + pub fn adjtime(delta: *const timeval, olddelta: *mut timeval) -> c_int; + } + } else if #[cfg(target_os = "solaris")] { + extern "C" { + pub fn adjtime(delta: *mut timeval, olddelta: *mut timeval) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(any( + target_os = "emscripten", + target_os = "android", + target_os = "nto" + )))] { + extern "C" { + pub fn stpncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + } + } +} + +cfg_if! { + if #[cfg(not(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "hurd", + target_os = "macos", + target_os = "openbsd", + target_os = "l4re", + )))] { + extern "C" { + pub fn sigqueue(pid: pid_t, sig: c_int, value: crate::sigval) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(target_os = "android"))] { + extern "C" { + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "confstr$UNIX2003" + )] + #[cfg_attr(target_os = "solaris", link_name = "__confstr_xpg7")] + pub fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t; + } + } +} + +cfg_if! { + if #[cfg(not(target_os = "aix"))] { + extern "C" { + pub fn dladdr(addr: *const c_void, info: *mut Dl_info) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(target_os = "solaris"))] { + extern "C" { + pub fn flock(fd: c_int, operation: c_int) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(any(target_env = "uclibc", target_os = "nto")))] { + extern "C" { + pub fn open_wmemstream(ptr: *mut *mut wchar_t, sizeloc: *mut size_t) -> *mut FILE; + } + } +} + +cfg_if! { + if #[cfg(not(target_os = "redox"))] { + extern "C" { + pub fn getsid(pid: pid_t) -> pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pause$UNIX2003" + )] + pub fn pause() -> c_int; + + #[cfg(not(target_os = "l4re"))] + pub fn mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + #[cfg_attr(gnu_file_offset_bits64, link_name = "openat64")] + pub fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int, ...) -> c_int; + + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "fdopendir$INODE64" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fdopendir$INODE64$UNIX2003" + )] + pub fn fdopendir(fd: c_int) -> *mut crate::DIR; + + #[cfg_attr( + all(target_os = "macos", not(target_arch = "aarch64")), + link_name = "readdir_r$INODE64" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__readdir_r30")] + #[cfg_attr( + all(target_os = "freebsd", any(freebsd11, freebsd10)), + link_name = "readdir_r@FBSD_1.0" + )] + #[cfg_attr( + all(target_os = "freebsd", not(any(freebsd11, freebsd10))), + link_name = "readdir_r@FBSD_1.5" + )] + #[allow(non_autolinks)] // FIXME(docs): `<>` breaks line length limit. + /// The 64-bit libc on Solaris and illumos only has readdir_r. If a + /// 32-bit Solaris or illumos target is ever created, it should use + /// __posix_readdir_r. See libc(3LIB) on Solaris or illumos: + /// https://illumos.org/man/3lib/libc + /// https://docs.oracle.com/cd/E36784_01/html/E36873/libc-3lib.html + /// https://www.unix.com/man-page/opensolaris/3LIB/libc/ + #[cfg_attr(gnu_file_offset_bits64, link_name = "readdir64_r")] + pub fn readdir_r( + dirp: *mut crate::DIR, + entry: *mut crate::dirent, + result: *mut *mut crate::dirent, + ) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(target_os = "nto")] { + extern "C" { + pub fn readlinkat( + dirfd: c_int, + pathname: *const c_char, + buf: *mut c_char, + bufsiz: size_t, + ) -> c_int; + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> c_int; + pub fn pselect( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timespec, + sigmask: *const sigset_t, + ) -> c_int; + pub fn sigaction(signum: c_int, act: *const sigaction, oldact: *mut sigaction) + -> c_int; + } + } else { + extern "C" { + #[cfg(not(target_os = "l4re"))] + pub fn readlinkat( + dirfd: c_int, + pathname: *const c_char, + buf: *mut c_char, + bufsiz: size_t, + ) -> ssize_t; + #[cfg(not(target_os = "l4re"))] + pub fn fmemopen(buf: *mut c_void, size: size_t, mode: *const c_char) -> *mut FILE; + #[cfg(not(target_os = "l4re"))] + pub fn open_memstream(ptr: *mut *mut c_char, sizeloc: *mut size_t) -> *mut FILE; + pub fn atexit(cb: extern "C" fn()) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaction14")] + pub fn sigaction(signum: c_int, act: *const sigaction, oldact: *mut sigaction) + -> c_int; + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> ssize_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86_64"), + link_name = "pselect$1050" + )] + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "pselect$UNIX2003" + )] + #[cfg_attr(target_os = "netbsd", link_name = "__pselect50")] + #[cfg_attr(gnu_time_bits64, link_name = "__pselect64")] + #[cfg_attr(musl_redir_time64, link_name = "__pselect_time64")] + pub fn pselect( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timespec, + sigmask: *const sigset_t, + ) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(any(target_os = "aix", target_os = "nto"))] { + extern "C" { + pub fn cfmakeraw(termios: *mut crate::termios) -> c_int; + } + } else if #[cfg(not(any(target_os = "solaris", target_os = "illumos",)))] { + extern "C" { + pub fn cfmakeraw(termios: *mut crate::termios); + } + } +} + +cfg_if! { + if #[cfg(any( + target_os = "aix", + all(target_os = "nto", target_env = "nto80") + ))] { + extern "C" { + pub fn cfsetspeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + } + } else if #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "nto" + )))] { + extern "C" { + #[cfg(not(target_os = "l4re"))] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "arm"), + link_name = "cfsetspeed@GLIBC_2.4" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "csky"), + link_name = "cfsetspeed@GLIBC_2.29" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "m68k"), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", target_arch = "mips32r6") + ), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "powerpc"), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"), + link_name = "cfsetspeed@GLIBC_2.33" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc"), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "x86"), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "aarch64"), + link_name = "cfsetspeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "loongarch64"), + link_name = "cfsetspeed@GLIBC_2.36" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "mips64", target_arch = "mips64r6") + ), + link_name = "cfsetspeed@GLIBC_2.0" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "big" + ), + link_name = "cfsetspeed@GLIBC_2.3" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "powerpc64", + target_endian = "little" + ), + link_name = "cfsetspeed@GLIBC_2.17" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "riscv64"), + link_name = "cfsetspeed@GLIBC_2.27" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "s390x"), + link_name = "cfsetspeed@GLIBC_2.2" + )] + #[cfg_attr( + all(target_os = "linux", target_env = "gnu", target_arch = "sparc64"), + link_name = "cfsetspeed@GLIBC_2.2" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "64" + ), + link_name = "cfsetspeed@GLIBC_2.2.5" + )] + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_arch = "x86_64", + target_pointer_width = "32" + ), + link_name = "cfsetspeed@GLIBC_2.16" + )] + pub fn cfsetspeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + } + } +} + +extern "C" { + pub fn fnmatch(pattern: *const c_char, name: *const c_char, flags: c_int) -> c_int; +} + +cfg_if! { + if #[cfg(target_env = "newlib")] { + mod newlib; + pub use self::newlib::*; + } else if #[cfg(any( + target_os = "linux", + target_os = "l4re", + target_os = "android", + target_os = "emscripten" + ))] { + mod linux_like; + pub use self::linux_like::*; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd" + ))] { + mod bsd; + pub use self::bsd::*; + } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { + mod solarish; + pub use self::solarish::*; + } else if #[cfg(target_os = "haiku")] { + mod haiku; + pub use self::haiku::*; + } else if #[cfg(target_os = "redox")] { + mod redox; + pub use self::redox::*; + } else if #[cfg(target_os = "cygwin")] { + mod cygwin; + pub use self::cygwin::*; + } else if #[cfg(target_os = "nto")] { + mod nto; + pub use self::nto::*; + } else if #[cfg(target_os = "aix")] { + mod aix; + pub use self::aix::*; + } else if #[cfg(target_os = "hurd")] { + mod hurd; + pub use self::hurd::*; + } else if #[cfg(target_os = "nuttx")] { + mod nuttx; + pub use self::nuttx::*; + } else { + // Unknown target_os + } +} diff --git a/deps/crates/vendor/libc/src/unix/newlib/aarch64/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/aarch64/mod.rs new file mode 100644 index 00000000000000..56c268fc5f2bbd --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/aarch64/mod.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +pub type clock_t = c_long; +pub type wchar_t = u32; + +s! { + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } +} + +pub const AF_INET6: c_int = 23; + +pub const FIONBIO: c_ulong = 1; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; + +pub const SOL_SOCKET: c_int = 65535; + +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTWAIT: c_int = 4; +pub const MSG_DONTROUTE: c_int = 0; +pub const MSG_WAITALL: c_int = 0; +pub const MSG_MORE: c_int = 0; +pub const MSG_NOSIGNAL: c_int = 0; + +pub use crate::unix::newlib::generic::{ + dirent, + sigset_t, + stat, +}; diff --git a/deps/crates/vendor/libc/src/unix/newlib/arm/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/arm/mod.rs new file mode 100644 index 00000000000000..9b5978fc538c38 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/arm/mod.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +pub type clock_t = c_long; +pub type wchar_t = u32; + +s! { + pub struct sockaddr { + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_in { + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_storage { + pub ss_family: crate::sa_family_t, + __ss_padding: Padding<[u8; 26]>, + } +} + +pub const AF_INET6: c_int = 23; + +pub const FIONBIO: c_ulong = 1; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLHUP: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLOUT: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; + +pub const SOL_SOCKET: c_int = 65535; + +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTWAIT: c_int = 4; +pub const MSG_DONTROUTE: c_int = 0; +pub const MSG_WAITALL: c_int = 0; +pub const MSG_MORE: c_int = 0; +pub const MSG_NOSIGNAL: c_int = 0; + +pub use crate::unix::newlib::generic::{ + dirent, + sigset_t, + stat, +}; diff --git a/deps/crates/vendor/libc/src/unix/newlib/espidf/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/espidf/mod.rs new file mode 100644 index 00000000000000..b791bbe265368d --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/espidf/mod.rs @@ -0,0 +1,137 @@ +use crate::prelude::*; + +pub type clock_t = c_ulong; +pub type wchar_t = u32; + +s! { + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct sockaddr_un { + pub sun_family: crate::sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_storage { + pub s2_len: u8, + pub ss_family: crate::sa_family_t, + pub s2_data1: [c_char; 2], + pub s2_data2: [u32; 3], + pub s2_data3: [u32; 3], + } +} + +pub const AF_UNIX: c_int = 1; +pub const AF_INET6: c_int = 10; + +pub const FIONBIO: c_ulong = 2147772030; + +pub const POLLIN: c_short = 1 << 0; +pub const POLLRDNORM: c_short = 1 << 1; +pub const POLLRDBAND: c_short = 1 << 2; +pub const POLLPRI: c_short = POLLRDBAND; +pub const POLLOUT: c_short = 1 << 3; +pub const POLLWRNORM: c_short = POLLOUT; +pub const POLLWRBAND: c_short = 1 << 4; +pub const POLLERR: c_short = 1 << 5; +pub const POLLHUP: c_short = 1 << 6; + +pub const SOL_SOCKET: c_int = 0xfff; + +pub const MSG_OOB: c_int = 0x04; +pub const MSG_PEEK: c_int = 0x01; +pub const MSG_DONTWAIT: c_int = 0x08; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_WAITALL: c_int = 0x02; +pub const MSG_MORE: c_int = 0x10; +pub const MSG_NOSIGNAL: c_int = 0x20; +pub const MSG_TRUNC: c_int = 0x04; +pub const MSG_CTRUNC: c_int = 0x08; +pub const MSG_EOR: c_int = 0x08; + +pub const PTHREAD_STACK_MIN: size_t = 768; + +pub const SIGABRT: c_int = 6; +pub const SIGFPE: c_int = 8; +pub const SIGILL: c_int = 4; +pub const SIGINT: c_int = 2; +pub const SIGSEGV: c_int = 11; +pub const SIGTERM: c_int = 15; +pub const SIGHUP: c_int = 1; +pub const SIGQUIT: c_int = 3; +pub const NSIG: size_t = 32; + +pub const SOMAXCONN: c_int = 128; + +pub const DT_UNKNOWN: u8 = 0; +pub const DT_REG: u8 = 1; +pub const DT_DIR: u8 = 2; +// Not used by esp-idf, but still defined in headers. +pub const DT_CHR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_FIFO: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; +pub const DT_WHT: u8 = 14; + +extern "C" { + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + pub fn gethostname(name: *mut c_char, namelen: ssize_t); + + #[link_name = "lwip_sendmsg"] + pub fn sendmsg(s: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + #[link_name = "lwip_recvmsg"] + pub fn recvmsg(s: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; +} + +pub use crate::unix::newlib::generic::{ + dirent, + sigset_t, + stat, +}; diff --git a/deps/crates/vendor/libc/src/unix/newlib/generic.rs b/deps/crates/vendor/libc/src/unix/newlib/generic.rs new file mode 100644 index 00000000000000..303de806b653f6 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/generic.rs @@ -0,0 +1,39 @@ +//! Common types used by most newlib platforms + +#[allow(unused_imports)] // needed for platforms that don't use the prelude here +use crate::prelude::*; + +s! { + #[cfg(all(not(target_os = "vita"), not(target_os = "horizon")))] + pub struct sigset_t { + __val: u32, + } + + #[cfg(all(not(target_os = "vita"), not(target_os = "horizon")))] + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: crate::off_t, + pub st_atime: crate::time_t, + pub st_spare1: c_long, + pub st_mtime: crate::time_t, + pub st_spare2: c_long, + pub st_ctime: crate::time_t, + pub st_spare3: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_spare4: [c_long; 2usize], + } + + #[cfg(not(target_os = "vita"))] + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_type: c_uchar, + pub d_name: [c_char; 256usize], + } +} diff --git a/deps/crates/vendor/libc/src/unix/newlib/horizon/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/horizon/mod.rs new file mode 100644 index 00000000000000..e94a0bb1c13d85 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/horizon/mod.rs @@ -0,0 +1,281 @@ +//! ARMv6K Nintendo 3DS C Newlib definitions + +use crate::off_t; +use crate::prelude::*; + +pub type wchar_t = c_uint; + +pub type u_register_t = c_uint; +pub type u_char = c_uchar; +pub type u_short = c_ushort; +pub type u_int = c_uint; +pub type u_long = c_ulong; +pub type ushort = c_ushort; +pub type uint = c_uint; +pub type ulong = c_ulong; +pub type clock_t = c_ulong; +pub type daddr_t = c_long; +pub type caddr_t = *mut c_char; +pub type sbintime_t = c_longlong; +pub type sigset_t = c_ulong; + +s! { + pub struct hostent { + pub h_name: *mut c_char, + pub h_aliases: *mut *mut c_char, + pub h_addrtype: u16, + pub h_length: u16, + pub h_addr_list: *mut *mut c_char, + } + + pub struct pollfd { + pub fd: c_int, + pub events: c_int, + pub revents: c_int, + } + + pub struct sockaddr { + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 26usize], + } + + pub struct sockaddr_storage { + pub ss_family: crate::sa_family_t, + __ss_padding: Padding<[c_char; 26usize]>, + } + + pub struct sockaddr_in { + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_un { + pub sun_len: c_uchar, + pub sun_family: crate::sa_family_t, + pub sun_path: [c_char; 104usize], + } + + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atim: crate::timespec, + pub st_mtim: crate::timespec, + pub st_ctim: crate::timespec, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_spare4: [c_long; 2usize], + } +} + +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_SIGNAL: c_int = 2; +pub const SIGEV_THREAD: c_int = 3; +pub const SA_NOCLDSTOP: c_int = 1; +pub const MINSIGSTKSZ: c_int = 2048; +pub const SIGSTKSZ: c_int = 8192; +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 2; +pub const SIG_SETMASK: c_int = 0; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGURG: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGCLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGIO: c_int = 23; +pub const SIGPOLL: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGLOST: c_int = 29; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const NSIG: c_int = 32; +pub const CLOCK_ENABLED: c_uint = 1; +pub const CLOCK_DISABLED: c_uint = 0; +pub const CLOCK_ALLOWED: c_uint = 1; +pub const CLOCK_DISALLOWED: c_uint = 0; +pub const TIMER_ABSTIME: c_uint = 4; +pub const SOL_SOCKET: c_int = 65535; +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_DONTWAIT: c_int = 4; +pub const MSG_DONTROUTE: c_int = 0; +pub const MSG_WAITALL: c_int = 0; +pub const MSG_MORE: c_int = 0; +pub const MSG_NOSIGNAL: c_int = 0; +pub const SOL_CONFIG: c_uint = 65534; + +pub const PTHREAD_STACK_MIN: size_t = 4096; +pub const WNOHANG: c_int = 1; + +pub const POLLIN: c_int = 0x0001; +pub const POLLPRI: c_int = 0x0002; +pub const POLLOUT: c_int = 0x0004; +pub const POLLRDNORM: c_int = 0x0040; +pub const POLLWRNORM: c_int = POLLOUT; +pub const POLLRDBAND: c_int = 0x0080; +pub const POLLWRBAND: c_int = 0x0100; +pub const POLLERR: c_int = 0x0008; +pub const POLLHUP: c_int = 0x0010; +pub const POLLNVAL: c_int = 0x0020; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_BADHINTS: c_int = 12; +pub const EAI_PROTOCOL: c_int = 13; +pub const EAI_OVERFLOW: c_int = 14; +pub const EAI_MAX: c_int = 15; + +pub const AF_UNIX: c_int = 1; +pub const AF_INET6: c_int = 23; + +pub const FIONBIO: c_ulong = 1; + +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +// For pthread get/setschedparam +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; + +// For getrandom() +pub const GRND_NONBLOCK: c_uint = 0x1; +pub const GRND_RANDOM: c_uint = 0x2; + +// Horizon OS works doesn't or can't hold any of this information +safe_f! { + pub const fn WIFSTOPPED(_status: c_int) -> bool { + false + } + + pub const fn WSTOPSIG(_status: c_int) -> c_int { + 0 + } + + pub const fn WIFCONTINUED(_status: c_int) -> bool { + true + } + + pub const fn WIFSIGNALED(_status: c_int) -> bool { + false + } + + pub const fn WTERMSIG(_status: c_int) -> c_int { + 0 + } + + pub const fn WIFEXITED(_status: c_int) -> bool { + true + } + + pub const fn WEXITSTATUS(_status: c_int) -> c_int { + 0 + } + + pub const fn WCOREDUMP(_status: c_int) -> bool { + false + } +} + +extern "C" { + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn pthread_attr_getschedparam( + attr: *const crate::pthread_attr_t, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_attr_setschedparam( + attr: *mut crate::pthread_attr_t, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_attr_getprocessorid_np( + attr: *const crate::pthread_attr_t, + processor_id: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_setprocessorid_np( + attr: *mut crate::pthread_attr_t, + processor_id: c_int, + ) -> c_int; + + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + pub fn pthread_condattr_getclock( + attr: *const crate::pthread_condattr_t, + clock_id: *mut crate::clockid_t, + ) -> c_int; + + pub fn pthread_condattr_setclock( + attr: *mut crate::pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + pub fn pthread_getprocessorid_np() -> c_int; + + pub fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + pub fn gethostid() -> c_long; +} + +pub use crate::unix::newlib::generic::dirent; diff --git a/deps/crates/vendor/libc/src/unix/newlib/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/mod.rs new file mode 100644 index 00000000000000..9e7df163e62e2b --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/mod.rs @@ -0,0 +1,977 @@ +use crate::prelude::*; + +pub type blkcnt_t = i32; +pub type blksize_t = i32; + +pub type clockid_t = c_ulong; + +cfg_if! { + if #[cfg(any(target_os = "espidf"))] { + pub type dev_t = c_short; + pub type ino_t = c_ushort; + pub type off_t = c_long; + } else if #[cfg(any(target_os = "vita"))] { + pub type dev_t = c_short; + pub type ino_t = c_ushort; + pub type off_t = c_int; + } else { + pub type dev_t = u32; + pub type ino_t = u32; + pub type off_t = i64; + } +} + +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u32; +pub type id_t = u32; +pub type key_t = c_int; +pub type loff_t = c_longlong; +pub type mode_t = c_uint; +pub type nfds_t = u32; +pub type nlink_t = c_ushort; +pub type pthread_t = c_ulong; +pub type pthread_key_t = c_uint; +pub type rlim_t = u32; + +cfg_if! { + if #[cfg(target_os = "horizon")] { + pub type sa_family_t = u16; + } else { + pub type sa_family_t = u8; + } +} + +pub type socklen_t = u32; +pub type speed_t = u32; +pub type suseconds_t = i32; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub type tcflag_t = u16; + } else { + pub type tcflag_t = c_uint; + } +} +pub type useconds_t = u32; + +cfg_if! { + if #[cfg(any( + target_os = "horizon", + all(target_os = "espidf", not(espidf_time32)) + ))] { + pub type time_t = c_longlong; + } else { + pub type time_t = i32; + } +} + +s! { + // The order of the `ai_addr` field in this struct is crucial + // for converting between the Rust and C types. + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + + #[cfg(target_os = "espidf")] + pub ai_addr: *mut sockaddr, + + pub ai_canonname: *mut c_char, + + #[cfg(not(any( + target_os = "espidf", + all(target_arch = "powerpc", target_vendor = "nintendo") + )))] + pub ai_addr: *mut sockaddr, + + pub ai_next: *mut addrinfo, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: fsblkcnt_t, + pub f_bfree: fsblkcnt_t, + pub f_bavail: fsblkcnt_t, + pub f_files: fsfilcnt_t, + pub f_ffree: fsfilcnt_t, + pub f_favail: fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_handler: extern "C" fn(arg1: c_int), + pub sa_mask: sigset_t, + pub sa_flags: c_int, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_flags: c_int, + pub ss_size: usize, + } + + pub struct fd_set { + // Unverified + fds_bits: [c_ulong; FD_SETSIZE as usize / ULONG_SIZE], + } + + pub struct passwd { + // Unverified + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct termios { + // Unverified + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + #[cfg(target_os = "espidf")] + pub c_ispeed: u32, + #[cfg(target_os = "espidf")] + pub c_ospeed: u32, + } + + pub struct sem_t { + // Unverified + __size: [c_char; 16], + } + + pub struct Dl_info { + // Unverified + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct utsname { + // Unverified + pub sysname: [c_char; 65], + pub nodename: [c_char; 65], + pub release: [c_char; 65], + pub version: [c_char; 65], + pub machine: [c_char; 65], + pub domainname: [c_char; 65], + } + + pub struct cpu_set_t { + // Unverified + bits: [u32; 32], + } + + pub struct pthread_attr_t { + // Unverified + #[cfg(not(target_os = "espidf"))] + __size: [u8; __SIZEOF_PTHREAD_ATTR_T], + #[cfg(target_os = "espidf")] + pub is_initialized: i32, + #[cfg(target_os = "espidf")] + pub stackaddr: *mut c_void, + #[cfg(target_os = "espidf")] + pub stacksize: i32, + #[cfg(target_os = "espidf")] + pub contentionscope: i32, + #[cfg(target_os = "espidf")] + pub inheritsched: i32, + #[cfg(target_os = "espidf")] + pub schedpolicy: i32, + #[cfg(target_os = "espidf")] + pub schedparam: i32, + #[cfg(target_os = "espidf")] + pub detachstate: i32, + } + + pub struct pthread_rwlockattr_t { + // Unverified + __size: [u8; __SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any(target_arch = "mips", target_arch = "arm", target_arch = "powerpc") + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any(target_arch = "mips", target_arch = "arm", target_arch = "powerpc")) + ), + repr(align(8)) + )] + pub struct pthread_mutex_t { + // Unverified + size: [u8; crate::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr( + all( + target_pointer_width = "32", + any(target_arch = "mips", target_arch = "arm", target_arch = "powerpc") + ), + repr(align(4)) + )] + #[cfg_attr( + any( + target_pointer_width = "64", + not(any(target_arch = "mips", target_arch = "arm", target_arch = "powerpc")) + ), + repr(align(8)) + )] + pub struct pthread_rwlock_t { + // Unverified + size: [u8; crate::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[cfg_attr( + any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64" + ), + repr(align(4)) + )] + #[cfg_attr( + not(any( + target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64" + )), + repr(align(8)) + )] + pub struct pthread_mutexattr_t { + // Unverified + size: [u8; crate::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(8))] + pub struct pthread_cond_t { + // Unverified + size: [u8; crate::__SIZEOF_PTHREAD_COND_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + // Unverified + size: [u8; crate::__SIZEOF_PTHREAD_CONDATTR_T], + } +} + +// unverified constants +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [__PTHREAD_INITIALIZER_BYTE; __SIZEOF_PTHREAD_MUTEX_T], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [__PTHREAD_INITIALIZER_BYTE; __SIZEOF_PTHREAD_COND_T], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [__PTHREAD_INITIALIZER_BYTE; __SIZEOF_PTHREAD_RWLOCK_T], +}; + +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const NCCS: usize = 11; + } else { + pub const NCCS: usize = 32; + } +} + +cfg_if! { + if #[cfg(target_os = "espidf")] { + const __PTHREAD_INITIALIZER_BYTE: u8 = 0xff; + pub const __SIZEOF_PTHREAD_ATTR_T: usize = 32; + pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 4; + pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 12; + pub const __SIZEOF_PTHREAD_COND_T: usize = 4; + pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 8; + pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 4; + pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 12; + pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + } else if #[cfg(target_os = "vita")] { + const __PTHREAD_INITIALIZER_BYTE: u8 = 0xff; + pub const __SIZEOF_PTHREAD_ATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 4; + pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_COND_T: usize = 4; + pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 4; + pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 4; + } else if #[cfg(target_os = "rtems")] { + const __PTHREAD_INITIALIZER_BYTE: u8 = 0x00; + pub const __SIZEOF_PTHREAD_ATTR_T: usize = 96; + pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 64; + pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 24; + pub const __SIZEOF_PTHREAD_COND_T: usize = 28; + pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 24; + pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; + pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + } else { + const __PTHREAD_INITIALIZER_BYTE: u8 = 0; + pub const __SIZEOF_PTHREAD_ATTR_T: usize = 56; + pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; + pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; + pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; + } +} + +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __PTHREAD_MUTEX_HAVE_PREV: usize = 1; +pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: usize = 1; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; + +cfg_if! { + if #[cfg(any(target_os = "horizon", target_os = "espidf"))] { + pub const FD_SETSIZE: usize = 64; + } else if #[cfg(target_os = "vita")] { + pub const FD_SETSIZE: usize = 256; + } else { + pub const FD_SETSIZE: usize = 1024; + } +} +// intentionally not public, only used for fd_set +const ULONG_SIZE: usize = 32; + +// Other constants +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const EDEADLK: c_int = 45; +pub const ENOLCK: c_int = 46; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENOLINK: c_int = 67; +pub const EPROTO: c_int = 71; +pub const EMULTIHOP: c_int = 74; +pub const EBADMSG: c_int = 77; +pub const EFTYPE: c_int = 79; +pub const ENOSYS: c_int = 88; +pub const ENOTEMPTY: c_int = 90; +pub const ENAMETOOLONG: c_int = 91; +pub const ELOOP: c_int = 92; +pub const EOPNOTSUPP: c_int = 95; +pub const EPFNOSUPPORT: c_int = 96; +pub const ECONNRESET: c_int = 104; +pub const ENOBUFS: c_int = 105; +pub const EAFNOSUPPORT: c_int = 106; +pub const EPROTOTYPE: c_int = 107; +pub const ENOTSOCK: c_int = 108; +pub const ENOPROTOOPT: c_int = 109; +pub const ECONNREFUSED: c_int = 111; +pub const EADDRINUSE: c_int = 112; +pub const ECONNABORTED: c_int = 113; +pub const ENETUNREACH: c_int = 114; +pub const ENETDOWN: c_int = 115; +pub const ETIMEDOUT: c_int = 116; +pub const EHOSTDOWN: c_int = 117; +pub const EHOSTUNREACH: c_int = 118; +pub const EINPROGRESS: c_int = 119; +pub const EALREADY: c_int = 120; +pub const EDESTADDRREQ: c_int = 121; +pub const EMSGSIZE: c_int = 122; +pub const EPROTONOSUPPORT: c_int = 123; +pub const EADDRNOTAVAIL: c_int = 125; +pub const ENETRESET: c_int = 126; +pub const EISCONN: c_int = 127; +pub const ENOTCONN: c_int = 128; +pub const ETOOMANYREFS: c_int = 129; +pub const EDQUOT: c_int = 132; +pub const ESTALE: c_int = 133; +pub const ENOTSUP: c_int = 134; +pub const EILSEQ: c_int = 138; +pub const EOVERFLOW: c_int = 139; +pub const ECANCELED: c_int = 140; +pub const ENOTRECOVERABLE: c_int = 141; +pub const EOWNERDEAD: c_int = 142; +pub const EWOULDBLOCK: c_int = 11; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_RGETLK: c_int = 10; +pub const F_RSETLK: c_int = 11; +pub const F_CNVT: c_int = 12; +pub const F_RSETLKW: c_int = 13; +pub const F_DUPFD_CLOEXEC: c_int = 14; + +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; +cfg_if! { + if #[cfg(espidf_picolibc)] { + pub const O_APPEND: c_int = 1024; + pub const O_CREAT: c_int = 64; + pub const O_TRUNC: c_int = 512; + } else { + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 512; + pub const O_TRUNC: c_int = 1024; + } +} +pub const O_EXCL: c_int = 2048; +pub const O_SYNC: c_int = 8192; +pub const O_NONBLOCK: c_int = 16384; + +pub const O_ACCMODE: c_int = 3; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const O_CLOEXEC: c_int = 0x40000; + } else { + pub const O_CLOEXEC: c_int = 0x80000; + } +} + +pub const RTLD_LAZY: c_int = 0x1; + +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; + +pub const FIOCLEX: c_ulong = 0x20006601; +pub const FIONCLEX: c_ulong = 0x20006602; + +pub const S_BLKSIZE: mode_t = 1024; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_ENFMT: mode_t = 0o2000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IXOTH: mode_t = 0o0001; + +pub const SOL_TCP: c_int = 6; + +pub const PF_UNSPEC: c_int = 0; +pub const PF_INET: c_int = 2; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const PF_INET6: c_int = 10; + } else { + pub const PF_INET6: c_int = 23; + } +} + +pub const AF_UNSPEC: c_int = 0; +pub const AF_INET: c_int = 2; + +pub const CLOCK_REALTIME: crate::clockid_t = 1; +pub const CLOCK_MONOTONIC: crate::clockid_t = 4; +pub const CLOCK_BOOTTIME: crate::clockid_t = 4; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const SO_BINTIME: c_int = 0x2000; +pub const SO_NO_OFFLOAD: c_int = 0x4000; +pub const SO_NO_DDP: c_int = 0x8000; +pub const SO_REUSEPORT_LB: c_int = 0x10000; +pub const SO_LABEL: c_int = 0x1009; +pub const SO_PEERLABEL: c_int = 0x1010; +pub const SO_LISTENQLIMIT: c_int = 0x1011; +pub const SO_LISTENQLEN: c_int = 0x1012; +pub const SO_LISTENINCQLEN: c_int = 0x1013; +pub const SO_SETFIB: c_int = 0x1014; +pub const SO_USER_COOKIE: c_int = 0x1015; +pub const SO_PROTOCOL: c_int = 0x1016; +pub const SO_PROTOTYPE: c_int = SO_PROTOCOL; +pub const SO_VENDOR: c_int = 0x80000000; +pub const SO_DEBUG: c_int = 0x01; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_TIMESTAMP: c_int = 0x0400; +pub const SO_NOSIGPIPE: c_int = 0x0800; +pub const SO_ACCEPTFILTER: c_int = 0x1000; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +cfg_if! { + if #[cfg(target_os = "horizon")] { + pub const SO_ERROR: c_int = 0x1009; + } else { + pub const SO_ERROR: c_int = 0x1007; + } +} +pub const SO_TYPE: c_int = 0x1008; + +pub const SOCK_CLOEXEC: c_int = O_CLOEXEC; + +pub const INET_ADDRSTRLEN: c_int = 16; + +// https://github.com/bminor/newlib/blob/HEAD/newlib/libc/sys/linux/include/net/if.h#L121 +pub const IFF_UP: c_int = 0x1; // interface is up +pub const IFF_BROADCAST: c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: c_int = 0x10; // interface is point-to-point link +pub const IFF_NOTRAILERS: c_int = 0x20; // avoid use of trailers +pub const IFF_RUNNING: c_int = 0x40; // resources allocated +pub const IFF_NOARP: c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE: c_int = 0x400; // transmission in progress +pub const IFF_SIMPLEX: c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: c_int = 0x8000; // supports multicast + +cfg_if! { + if #[cfg(target_os = "vita")] { + pub const TCP_NODELAY: c_int = 1; + pub const TCP_MAXSEG: c_int = 2; + } else if #[cfg(target_os = "espidf")] { + pub const TCP_NODELAY: c_int = 1; + pub const TCP_MAXSEG: c_int = 8194; + } else { + pub const TCP_NODELAY: c_int = 8193; + pub const TCP_MAXSEG: c_int = 8194; + } +} + +pub const TCP_NOPUSH: c_int = 4; +pub const TCP_NOOPT: c_int = 8; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const TCP_KEEPIDLE: c_int = 3; + pub const TCP_KEEPINTVL: c_int = 4; + pub const TCP_KEEPCNT: c_int = 5; + } else { + pub const TCP_KEEPIDLE: c_int = 256; + pub const TCP_KEEPINTVL: c_int = 512; + pub const TCP_KEEPCNT: c_int = 1024; + } +} + +cfg_if! { + if #[cfg(target_os = "horizon")] { + pub const IP_TOS: c_int = 7; + } else if #[cfg(target_os = "espidf")] { + pub const IP_TOS: c_int = 1; + } else { + pub const IP_TOS: c_int = 3; + } +} +cfg_if! { + if #[cfg(target_os = "vita")] { + pub const IP_TTL: c_int = 4; + } else if #[cfg(target_os = "espidf")] { + pub const IP_TTL: c_int = 2; + } else { + pub const IP_TTL: c_int = 8; + } +} + +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const IP_MULTICAST_IF: c_int = 6; + pub const IP_MULTICAST_TTL: c_int = 5; + pub const IP_MULTICAST_LOOP: c_int = 7; + } else { + pub const IP_MULTICAST_IF: c_int = 9; + pub const IP_MULTICAST_TTL: c_int = 10; + pub const IP_MULTICAST_LOOP: c_int = 11; + } +} + +cfg_if! { + if #[cfg(target_os = "vita")] { + pub const IP_ADD_MEMBERSHIP: c_int = 12; + pub const IP_DROP_MEMBERSHIP: c_int = 13; + } else if #[cfg(target_os = "espidf")] { + pub const IP_ADD_MEMBERSHIP: c_int = 3; + pub const IP_DROP_MEMBERSHIP: c_int = 4; + } else { + pub const IP_ADD_MEMBERSHIP: c_int = 11; + pub const IP_DROP_MEMBERSHIP: c_int = 12; + } +} +pub const IPV6_UNICAST_HOPS: c_int = 4; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const IPV6_MULTICAST_IF: c_int = 768; + pub const IPV6_MULTICAST_HOPS: c_int = 769; + pub const IPV6_MULTICAST_LOOP: c_int = 770; + } else { + pub const IPV6_MULTICAST_IF: c_int = 9; + pub const IPV6_MULTICAST_HOPS: c_int = 10; + pub const IPV6_MULTICAST_LOOP: c_int = 11; + } +} +pub const IPV6_V6ONLY: c_int = 27; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; +pub const IPV6_ADD_MEMBERSHIP: c_int = 12; +pub const IPV6_DROP_MEMBERSHIP: c_int = 13; + +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const HOST_NOT_FOUND: c_int = 210; + pub const NO_DATA: c_int = 211; + pub const NO_RECOVERY: c_int = 212; + pub const TRY_AGAIN: c_int = 213; + } else { + pub const HOST_NOT_FOUND: c_int = 1; + pub const NO_DATA: c_int = 2; + pub const NO_RECOVERY: c_int = 3; + pub const TRY_AGAIN: c_int = 4; + } +} +pub const NO_ADDRESS: c_int = 2; + +pub const AI_PASSIVE: c_int = 1; +pub const AI_CANONNAME: c_int = 2; +pub const AI_NUMERICHOST: c_int = 4; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const AI_NUMERICSERV: c_int = 8; + pub const AI_ADDRCONFIG: c_int = 64; + } else { + pub const AI_NUMERICSERV: c_int = 0; + pub const AI_ADDRCONFIG: c_int = 0; + } +} + +pub const NI_MAXHOST: c_int = 1025; +pub const NI_MAXSERV: c_int = 32; +pub const NI_NOFQDN: c_int = 1; +pub const NI_NUMERICHOST: c_int = 2; +pub const NI_NAMEREQD: c_int = 4; +cfg_if! { + if #[cfg(target_os = "espidf")] { + pub const NI_NUMERICSERV: c_int = 8; + pub const NI_DGRAM: c_int = 16; + } else { + pub const NI_NUMERICSERV: c_int = 0; + pub const NI_DGRAM: c_int = 0; + } +} + +cfg_if! { + // Defined in vita/mod.rs for "vita" + if #[cfg(target_os = "espidf")] { + pub const EAI_FAMILY: c_int = 204; + pub const EAI_MEMORY: c_int = 203; + pub const EAI_NONAME: c_int = 200; + pub const EAI_SOCKTYPE: c_int = 10; + } else if #[cfg(not(target_os = "vita"))] { + pub const EAI_FAMILY: c_int = -303; + pub const EAI_MEMORY: c_int = -304; + pub const EAI_NONAME: c_int = -305; + pub const EAI_SOCKTYPE: c_int = -307; + } +} + +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +f! { + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +extern "C" { + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + + #[cfg_attr(target_os = "linux", link_name = "__xpg_strerror_r")] + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr(target_os = "espidf", link_name = "lwip_bind")] + pub fn bind(fd: c_int, addr: *const sockaddr, len: socklen_t) -> c_int; + pub fn clock_settime(clock_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn clock_gettime(clock_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_getres(clock_id: crate::clockid_t, res: *mut crate::timespec) -> c_int; + #[cfg_attr(target_os = "espidf", link_name = "lwip_close")] + pub fn closesocket(sockfd: c_int) -> c_int; + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + #[cfg_attr(target_os = "espidf", link_name = "lwip_recvfrom")] + pub fn recvfrom( + fd: c_int, + buf: *mut c_void, + n: usize, + flags: c_int, + addr: *mut sockaddr, + addr_len: *mut socklen_t, + ) -> isize; + #[cfg(not(all(target_arch = "powerpc", target_vendor = "nintendo")))] + pub fn getnameinfo( + sa: *const sockaddr, + salen: socklen_t, + host: *mut c_char, + hostlen: socklen_t, + serv: *mut c_char, + servlen: socklen_t, + flags: c_int, + ) -> c_int; + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn uname(buf: *mut crate::utsname) -> c_int; +} + +mod generic; + +cfg_if! { + if #[cfg(target_os = "espidf")] { + mod espidf; + pub use self::espidf::*; + } else if #[cfg(target_os = "horizon")] { + mod horizon; + pub use self::horizon::*; + } else if #[cfg(target_os = "vita")] { + mod vita; + pub use self::vita::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else { + // Only tested on ARM so far. Other platforms might have different + // definitions for types and constants. + pub use target_arch_not_implemented; + } +} + +cfg_if! { + if #[cfg(target_os = "rtems")] { + mod rtems; + pub use self::rtems::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/newlib/powerpc/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/powerpc/mod.rs new file mode 100644 index 00000000000000..f51a1b2cbe602c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/powerpc/mod.rs @@ -0,0 +1,18 @@ +use crate::prelude::*; + +pub type clock_t = c_ulong; +pub type wchar_t = c_int; + +pub use crate::unix::newlib::generic::{ + dirent, + sigset_t, + stat, +}; + +// the newlib shipped with devkitPPC does not support the following components: +// - sockaddr +// - AF_INET6 +// - FIONBIO +// - POLL* +// - SOL_SOCKET +// - MSG_* diff --git a/deps/crates/vendor/libc/src/unix/newlib/rtems/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/rtems/mod.rs new file mode 100644 index 00000000000000..ec4534e32a11f3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/rtems/mod.rs @@ -0,0 +1,144 @@ +// defined in architecture specific module + +use crate::prelude::*; + +s! { + pub struct sockaddr_un { + pub sun_family: crate::sa_family_t, + pub sun_path: [c_char; 108usize], + } +} + +pub const AF_UNIX: c_int = 1; + +pub const RTLD_DEFAULT: *mut c_void = -2isize as *mut c_void; + +pub const UTIME_OMIT: c_long = -1; +pub const AT_FDCWD: c_int = -2; + +pub const O_DIRECTORY: c_int = 0x200000; +pub const O_NOFOLLOW: c_int = 0x100000; + +pub const AT_EACCESS: c_int = 1; +pub const AT_SYMLINK_NOFOLLOW: c_int = 2; +pub const AT_SYMLINK_FOLLOW: c_int = 4; +pub const AT_REMOVEDIR: c_int = 8; + +// signal.h +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 0; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGURG: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGCLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGIO: c_int = 23; +pub const SIGWINCH: c_int = 24; +pub const SIGUSR1: c_int = 25; +pub const SIGUSR2: c_int = 26; +pub const SIGRTMIN: c_int = 27; +pub const SIGRTMAX: c_int = 31; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; + +pub const SA_NOCLDSTOP: c_ulong = 0x00000001; +pub const SA_SIGINFO: c_ulong = 0x00000002; +pub const SA_ONSTACK: c_ulong = 0x00000004; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const PTHREAD_STACK_MIN: size_t = 0; + +// sys/wait.h +pub const WNOHANG: c_int = 1; +pub const WUNTRACED: c_int = 2; + +// sys/socket.h +pub const SOMAXCONN: c_int = 128; + +safe_f! { + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + // (status >> 8) & 0xff + WEXITSTATUS(status) + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) > 0) && ((status & 0x7f) < 0x7f) + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0xff) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + // RTEMS doesn't have native WIFCONTINUED. + pub const fn WIFCONTINUED(_status: c_int) -> bool { + true + } + + // RTEMS doesn't have native WCOREDUMP. + pub const fn WCOREDUMP(_status: c_int) -> bool { + false + } +} + +extern "C" { + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn pthread_condattr_setclock( + attr: *mut crate::pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + pub fn arc4random_buf(buf: *mut core::ffi::c_void, nbytes: size_t); + + pub fn setgroups(ngroups: c_int, grouplist: *const crate::gid_t) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/newlib/vita/mod.rs b/deps/crates/vendor/libc/src/unix/newlib/vita/mod.rs new file mode 100644 index 00000000000000..95abf9076a05fb --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/newlib/vita/mod.rs @@ -0,0 +1,233 @@ +use crate::off_t; +use crate::prelude::*; + +pub type clock_t = c_long; + +pub type wchar_t = u32; + +pub type sigset_t = c_ulong; + +s! { + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_vport: crate::in_port_t, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_vport: crate::in_port_t, + pub sin_zero: [u8; 6], + } + + pub struct sockaddr_un { + pub ss_len: u8, + pub sun_family: crate::sa_family_t, + pub sun_path: [c_char; 108usize], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 2]>, + __ss_align: i64, + __ss_pad2: Padding<[u8; 116]>, + } + + pub struct sched_param { + pub sched_priority: c_int, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: crate::mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atime: crate::time_t, + pub st_mtime: crate::time_t, + pub st_ctime: crate::time_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_spare4: [c_long; 2usize], + } + + #[repr(align(8))] + pub struct dirent { + __offset: [u8; 88], + pub d_name: [c_char; 256usize], + __pad: Padding<[u8; 8]>, + } +} + +pub const AF_UNIX: c_int = 1; +pub const AF_INET6: c_int = 24; + +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; + +pub const SOMAXCONN: c_int = 128; + +pub const FIONBIO: c_ulong = 1; + +pub const POLLIN: c_short = 0x0001; +pub const POLLPRI: c_short = POLLIN; +pub const POLLOUT: c_short = 0x0004; +pub const POLLRDNORM: c_short = POLLIN; +pub const POLLRDBAND: c_short = POLLIN; +pub const POLLWRNORM: c_short = POLLOUT; +pub const POLLWRBAND: c_short = POLLOUT; +pub const POLLERR: c_short = 0x0008; +pub const POLLHUP: c_short = 0x0010; +pub const POLLNVAL: c_short = 0x0020; + +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_NONBLOCK: c_int = 0x1100; + +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_EOR: c_int = 0x8; +pub const MSG_TRUNC: c_int = 0x10; +pub const MSG_CTRUNC: c_int = 0x20; +pub const MSG_WAITALL: c_int = 0x40; +pub const MSG_DONTWAIT: c_int = 0x80; +pub const MSG_BCAST: c_int = 0x100; +pub const MSG_MCAST: c_int = 0x200; + +pub const UTIME_OMIT: c_long = -1; +pub const AT_FDCWD: c_int = -2; + +pub const O_DIRECTORY: c_int = 0x200000; +pub const O_NOFOLLOW: c_int = 0x100000; + +pub const AT_EACCESS: c_int = 1; +pub const AT_SYMLINK_NOFOLLOW: c_int = 2; +pub const AT_SYMLINK_FOLLOW: c_int = 4; +pub const AT_REMOVEDIR: c_int = 8; + +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_NODATA: c_int = -5; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_ADDRFAMILY: c_int = -9; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_SYSTEM: c_int = -11; +pub const EAI_OVERFLOW: c_int = -12; + +pub const PTHREAD_STACK_MIN: size_t = 32 * 1024; + +pub const IP_HDRINCL: c_int = 2; + +extern "C" { + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + pub fn sendmsg(s: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + pub fn recvmsg(s: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + pub fn pthread_attr_getschedparam( + attr: *const crate::pthread_attr_t, + param: *mut sched_param, + ) -> c_int; + + pub fn pthread_attr_setschedparam( + attr: *mut crate::pthread_attr_t, + param: *const sched_param, + ) -> c_int; + + pub fn pthread_attr_getprocessorid_np( + attr: *const crate::pthread_attr_t, + processor_id: *mut c_int, + ) -> c_int; + + pub fn pthread_attr_setprocessorid_np( + attr: *mut crate::pthread_attr_t, + processor_id: c_int, + ) -> c_int; + + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + pub fn pthread_condattr_getclock( + attr: *const crate::pthread_condattr_t, + clock_id: *mut crate::clockid_t, + ) -> c_int; + + pub fn pthread_condattr_setclock( + attr: *mut crate::pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + pub fn pthread_getprocessorid_np() -> c_int; + + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/nto/aarch64.rs b/deps/crates/vendor/libc/src/unix/nto/aarch64.rs new file mode 100644 index 00000000000000..559ab6e49a45dc --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/nto/aarch64.rs @@ -0,0 +1,35 @@ +use crate::prelude::*; + +pub type wchar_t = u32; +pub type time_t = i64; + +s! { + pub struct aarch64_qreg_t { + pub qlo: u64, + pub qhi: u64, + } + + pub struct aarch64_fpu_registers { + pub reg: [crate::aarch64_qreg_t; 32], + pub fpsr: u32, + pub fpcr: u32, + } + + pub struct aarch64_cpu_registers { + pub gpr: [u64; 32], + pub elr: u64, + pub pstate: u64, + } + + #[repr(align(16))] + pub struct mcontext_t { + pub cpu: crate::aarch64_cpu_registers, + pub fpu: crate::aarch64_fpu_registers, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } +} diff --git a/deps/crates/vendor/libc/src/unix/nto/mod.rs b/deps/crates/vendor/libc/src/unix/nto/mod.rs new file mode 100644 index 00000000000000..022fb0be1f7868 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/nto/mod.rs @@ -0,0 +1,3216 @@ +use crate::prelude::*; + +pub type clock_t = u32; + +pub type sa_family_t = u8; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type clockid_t = c_int; +pub type timer_t = c_int; +pub type key_t = c_uint; +pub type id_t = c_int; + +pub type useconds_t = u32; +pub type dev_t = u32; +pub type socklen_t = u32; +pub type mode_t = u32; +pub type rlim64_t = u64; +pub type mqd_t = c_int; +pub type nfds_t = c_uint; +pub type idtype_t = c_uint; +pub type errno_t = c_int; +pub type rsize_t = c_ulong; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; +pub type Elf32_Lword = u64; +pub type Elf32_Sword = i32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; +pub type Elf64_Sxword = i64; +pub type Elf64_Lword = u64; +pub type Elf64_Sword = i32; + +pub type Elf32_Section = u16; +pub type Elf64_Section = u16; + +pub type _Time32t = u32; + +pub type pthread_t = c_int; +pub type regoff_t = ssize_t; + +pub type nlink_t = u32; +pub type blksize_t = u32; +pub type suseconds_t = i32; + +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = u64; +pub type msgqnum_t = u64; +pub type msglen_t = u64; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type rlim_t = u64; +pub type posix_spawn_file_actions_t = *mut c_void; +pub type posix_spawnattr_t = crate::uintptr_t; + +pub type pthread_mutex_t = crate::sync_t; +pub type pthread_mutexattr_t = crate::_sync_attr; +pub type pthread_cond_t = crate::sync_t; +pub type pthread_condattr_t = crate::_sync_attr; +pub type pthread_rwlockattr_t = crate::_sync_attr; +pub type pthread_key_t = c_int; +pub type pthread_spinlock_t = sync_t; +pub type pthread_barrierattr_t = _sync_attr; +pub type sem_t = sync_t; + +pub type nl_item = c_int; + +extern_ty! { + pub enum timezone {} +} + +s! { + pub struct dirent_extra { + pub d_datalen: u16, + pub d_type: u16, + d_reserved: Padding, + } + + pub struct stat { + pub st_ino: crate::ino_t, + pub st_size: off_t, + pub st_dev: crate::dev_t, + pub st_rdev: crate::dev_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub __old_st_mtime: crate::_Time32t, + pub __old_st_atime: crate::_Time32t, + pub __old_st_ctime: crate::_Time32t, + pub st_mode: mode_t, + pub st_nlink: crate::nlink_t, + pub st_blocksize: crate::blksize_t, + pub st_nblocks: i32, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_mtim: crate::timespec, + pub st_atim: crate::timespec, + pub st_ctim: crate::timespec, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + #[cfg_attr(any(target_env = "nto71", target_env = "nto70"), repr(packed))] + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + #[cfg(not(target_env = "nto71_iosock"))] + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [i8; 8], + } + + #[cfg(target_env = "nto71_iosock")] + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + // The order of the `ai_addr` field in this struct is crucial + // for converting between the Rust and C types. + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct fd_set { + fds_bits: [c_uint; 2 * FD_SETSIZE as usize / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + #[repr(align(8))] + pub struct sched_param { + pub sched_priority: c_int, + pub sched_curpriority: c_int, + reserved: Padding<[c_int; 10]>, + } + + #[repr(align(8))] + pub struct __sched_param { + pub __sched_priority: c_int, + pub __sched_curpriority: c_int, + reserved: Padding<[c_int; 10]>, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct lconv { + pub currency_symbol: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_grouping: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub negative_sign: *mut c_char, + pub positive_sign: *mut c_char, + pub frac_digits: c_char, + pub int_frac_digits: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub n_sign_posn: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub p_sign_posn: c_char, + + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + + pub decimal_point: *mut c_char, + pub grouping: *mut c_char, + pub thousands_sep: *mut c_char, + + pub _Frac_grouping: *mut c_char, + pub _Frac_sep: *mut c_char, + pub _False: *mut c_char, + pub _True: *mut c_char, + + pub _No: *mut c_char, + pub _Yes: *mut c_char, + pub _Nostr: *mut c_char, + pub _Yesstr: *mut c_char, + _Reserved: Padding<[*mut c_char; 8]>, + } + + // Does not exist in io-sock + #[cfg(not(target_env = "nto71_iosock"))] + pub struct in_pktinfo { + pub ipi_addr: crate::in_addr, + pub ipi_ifindex: c_uint, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: c_uint, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_dstaddr: *mut crate::sockaddr, + pub ifa_data: *mut c_void, + } + + pub struct arpreq { + pub arp_pa: crate::sockaddr, + pub arp_ha: crate::sockaddr, + pub arp_flags: c_int, + } + + #[cfg_attr(any(target_env = "nto71", target_env = "nto70"), repr(packed))] + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + #[cfg(not(target_env = "nto71_iosock"))] + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: c_uint, + } + + #[cfg(target_env = "nto71_iosock")] + pub struct mmsghdr { + pub msg_hdr: crate::msghdr, + pub msg_len: ssize_t, + } + + #[repr(align(8))] + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + __data: [u8; 36], // union + } + + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_flags: c_int, + pub sa_mask: crate::sigset_t, + } + + pub struct _sync { + _union: c_uint, + __owner: c_uint, + } + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_matchc: c_int, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + pub gl_flags: c_int, + pub gl_errfunc: extern "C" fn(*const c_char, c_int) -> c_int, + + __unused1: Padding<*mut c_void>, + __unused2: Padding<*mut c_void>, + __unused3: Padding<*mut c_void>, + __unused4: Padding<*mut c_void>, + __unused5: Padding<*mut c_void>, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_age: *mut c_char, + pub pw_comment: *mut c_char, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + pub struct sembuf { + pub sem_num: c_ushort, + pub sem_op: c_short, + pub sem_flg: c_short, + } + + pub struct Elf32_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf32_Half, + pub e_machine: Elf32_Half, + pub e_version: Elf32_Word, + pub e_entry: Elf32_Addr, + pub e_phoff: Elf32_Off, + pub e_shoff: Elf32_Off, + pub e_flags: Elf32_Word, + pub e_ehsize: Elf32_Half, + pub e_phentsize: Elf32_Half, + pub e_phnum: Elf32_Half, + pub e_shentsize: Elf32_Half, + pub e_shnum: Elf32_Half, + pub e_shstrndx: Elf32_Half, + } + + pub struct Elf64_Ehdr { + pub e_ident: [c_uchar; 16], + pub e_type: Elf64_Half, + pub e_machine: Elf64_Half, + pub e_version: Elf64_Word, + pub e_entry: Elf64_Addr, + pub e_phoff: Elf64_Off, + pub e_shoff: Elf64_Off, + pub e_flags: Elf64_Word, + pub e_ehsize: Elf64_Half, + pub e_phentsize: Elf64_Half, + pub e_phnum: Elf64_Half, + pub e_shentsize: Elf64_Half, + pub e_shnum: Elf64_Half, + pub e_shstrndx: Elf64_Half, + } + + pub struct Elf32_Sym { + pub st_name: Elf32_Word, + pub st_value: Elf32_Addr, + pub st_size: Elf32_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf32_Section, + } + + pub struct Elf64_Sym { + pub st_name: Elf64_Word, + pub st_info: c_uchar, + pub st_other: c_uchar, + pub st_shndx: Elf64_Section, + pub st_value: Elf64_Addr, + pub st_size: Elf64_Xword, + } + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct Elf32_Shdr { + pub sh_name: Elf32_Word, + pub sh_type: Elf32_Word, + pub sh_flags: Elf32_Word, + pub sh_addr: Elf32_Addr, + pub sh_offset: Elf32_Off, + pub sh_size: Elf32_Word, + pub sh_link: Elf32_Word, + pub sh_info: Elf32_Word, + pub sh_addralign: Elf32_Word, + pub sh_entsize: Elf32_Word, + } + + pub struct Elf64_Shdr { + pub sh_name: Elf64_Word, + pub sh_type: Elf64_Word, + pub sh_flags: Elf64_Xword, + pub sh_addr: Elf64_Addr, + pub sh_offset: Elf64_Off, + pub sh_size: Elf64_Xword, + pub sh_link: Elf64_Word, + pub sh_info: Elf64_Word, + pub sh_addralign: Elf64_Xword, + pub sh_entsize: Elf64_Xword, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + pub struct inotify_event { + pub wd: c_int, + pub mask: u32, + pub cookie: u32, + pub len: u32, + } + + pub struct regmatch_t { + pub rm_so: regoff_t, + pub rm_eo: regoff_t, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + __reserved: Padding<[c_uint; 3]>, + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct mallinfo { + pub arena: c_int, + pub ordblks: c_int, + pub smblks: c_int, + pub hblks: c_int, + pub hblkhd: c_int, + pub usmblks: c_int, + pub fsmblks: c_int, + pub uordblks: c_int, + pub fordblks: c_int, + pub keepcost: c_int, + } + + pub struct flock { + pub l_type: i16, + pub l_whence: i16, + pub l_zero1: i32, + pub l_start: off_t, + pub l_len: off_t, + pub l_pid: crate::pid_t, + pub l_sysid: u32, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_basetype: [c_char; 16], + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + f_filler: [c_uint; 21], + } + + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_reqprio: c_int, + pub aio_offset: off_t, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_sigevent: crate::sigevent, + pub aio_lio_opcode: c_int, + pub _aio_lio_state: *mut c_void, + _aio_pad: Padding<[c_int; 3]>, + pub _aio_next: *mut crate::aiocb, + pub _aio_flag: c_uint, + pub _aio_iotype: c_uint, + pub _aio_result: ssize_t, + pub _aio_error: c_uint, + pub _aio_suspend: *mut c_void, + pub _aio_plist: *mut c_void, + pub _aio_policy: c_int, + pub _aio_param: crate::__sched_param, + } + + pub struct pthread_attr_t { + __data1: c_long, + __data2: [u8; 96], + } + + pub struct ipc_perm { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + pub seq: c_uint, + pub key: crate::key_t, + _reserved: Padding<[c_int; 4]>, + } + + pub struct regex_t { + re_magic: c_int, + re_nsub: size_t, + re_endp: *const c_char, + re_g: *mut c_void, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct _thread_attr { + pub __flags: c_int, + pub __stacksize: size_t, + pub __stackaddr: *mut c_void, + pub __exitfunc: Option, + pub __policy: c_int, + pub __param: crate::__sched_param, + pub __guardsize: c_uint, + pub __prealloc: c_uint, + __spare: [c_int; 2], + } + + pub struct _sync_attr { + pub __protocol: c_int, + pub __flags: c_int, + pub __prioceiling: c_int, + pub __clockid: c_int, + pub __count: c_int, + __reserved: Padding<[c_int; 3]>, + } + + pub struct sockcred { + pub sc_uid: crate::uid_t, + pub sc_euid: crate::uid_t, + pub sc_gid: crate::gid_t, + pub sc_egid: crate::gid_t, + pub sc_ngroups: c_int, + pub sc_groups: [crate::gid_t; 1], + } + + pub struct bpf_program { + pub bf_len: c_uint, + pub bf_insns: *mut crate::bpf_insn, + } + + #[cfg(not(target_env = "nto71_iosock"))] + pub struct bpf_stat { + pub bs_recv: u64, + pub bs_drop: u64, + pub bs_capt: u64, + bs_padding: Padding<[u64; 13]>, + } + + #[cfg(target_env = "nto71_iosock")] + pub struct bpf_stat { + pub bs_recv: c_uint, + pub bs_drop: c_uint, + } + + pub struct bpf_version { + pub bv_major: c_ushort, + pub bv_minor: c_ushort, + } + + pub struct bpf_hdr { + pub bh_tstamp: crate::timeval, + pub bh_caplen: u32, + pub bh_datalen: u32, + pub bh_hdrlen: u16, + } + + pub struct bpf_insn { + pub code: u16, + pub jt: c_uchar, + pub jf: c_uchar, + pub k: u32, + } + + pub struct bpf_dltlist { + pub bfl_len: c_uint, + pub bfl_list: *mut c_uint, + } + + // Does not exist in io-sock + #[cfg(not(target_env = "nto71_iosock"))] + pub struct unpcbid { + pub unp_pid: crate::pid_t, + pub unp_euid: crate::uid_t, + pub unp_egid: crate::gid_t, + } + + pub struct dl_phdr_info { + pub dlpi_addr: crate::Elf64_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const crate::Elf64_Phdr, + pub dlpi_phnum: crate::Elf64_Half, + } + + #[repr(align(8))] + pub struct ucontext_t { + pub uc_link: *mut ucontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: stack_t, + pub uc_mcontext: mcontext_t, + } + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 104], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: sa_family_t, + __ss_pad1: Padding<[c_char; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[c_char; 112]>, + } + + pub struct utsname { + pub sysname: [c_char; _SYSNAME_SIZE], + pub nodename: [c_char; _SYSNAME_SIZE], + pub release: [c_char; _SYSNAME_SIZE], + pub version: [c_char; _SYSNAME_SIZE], + pub machine: [c_char; _SYSNAME_SIZE], + } + + pub struct sigevent { + pub sigev_notify: c_int, + __padding1: Padding, + pub sigev_signo: c_int, // union + __padding2: Padding, + pub sigev_value: crate::sigval, + __sigev_un2: usize, // union + } + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_offset: off_t, + pub d_reclen: c_short, + pub d_namelen: c_short, + pub d_name: [c_char; 1], // flex array + } + + pub struct sigset_t { + __val: [u32; 2], + } + + pub struct mq_attr { + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_flags: c_long, + pub mq_curmsgs: c_long, + pub mq_sendwait: c_long, + pub mq_recvwait: c_long, + } + + #[cfg(not(target_env = "nto71_iosock"))] + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: crate::sa_family_t, + pub sdl_index: u16, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 12], + } + + #[cfg(target_env = "nto71_iosock")] + pub struct sockaddr_dl { + pub sdl_len: c_uchar, + pub sdl_family: c_uchar, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 46], + } +} + +s_no_extra_traits! { + pub struct msg { + pub msg_next: *mut crate::msg, + pub msg_type: c_long, + pub msg_ts: c_ushort, + pub msg_spot: c_short, + _pad: Padding<[u8; 4]>, + } + + pub struct msqid_ds { + pub msg_perm: crate::ipc_perm, + pub msg_first: *mut crate::msg, + pub msg_last: *mut crate::msg, + pub msg_cbytes: crate::msglen_t, + pub msg_qnum: crate::msgqnum_t, + pub msg_qbytes: crate::msglen_t, + pub msg_lspid: crate::pid_t, + pub msg_lrpid: crate::pid_t, + pub msg_stime: crate::time_t, + msg_pad1: Padding, + pub msg_rtime: crate::time_t, + msg_pad2: Padding, + pub msg_ctime: crate::time_t, + msg_pad3: Padding, + msg_pad4: Padding<[c_long; 4]>, + } + + pub struct sync_t { + __u: c_uint, // union + pub __owner: c_uint, + } + + #[repr(align(4))] + pub struct pthread_barrier_t { + // union + __pad: Padding<[u8; 28]>, // union + } + + pub struct pthread_rwlock_t { + pub __active: c_int, + pub __blockedwriters: c_int, + pub __blockedreaders: c_int, + pub __heavy: c_int, + pub __lock: crate::pthread_mutex_t, // union + pub __rcond: crate::pthread_cond_t, // union + pub __wcond: crate::pthread_cond_t, // union + pub __owner: c_uint, + pub __spare: c_uint, + } + + // There is no canonical definition of c_longdouble in Rust. For both AArch64 and x86_64, + // however, the size and alignment properties are that of the gcc __int128 which corresponds (at + // least on rustc 1.78+ with LLVM 18, see + // https://blog.rust-lang.org/2024/03/30/i128-layout-update/) to i128. Use this instead until we + // get native f128 support. + // + // The definition was taken from the definition of the _Maxalignt struct in the QNX SDK. + // However, on QNX7, there is a different definition of std::max_align_t (the C++ version of + // this type). In practice, this doesn't make a difference for the _alignment_ properties of the + // type - however, it changes the size, so using in in any other form than the zero-sized array + // form would be bogus and it would potentially change the size of the data type. On QNX8, this + // got fixed and both C and C++ are using the same definition. + pub struct max_align_t { + _ll: crate::c_longlong, + _ld: i128, + } +} + +pub const _SYSNAME_SIZE: usize = 256 + 1; +pub const RLIM_INFINITY: crate::rlim_t = 0xfffffffffffffffd; +pub const O_LARGEFILE: c_int = 0o0100000; + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 32767; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; + +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; + +pub const F_DUPFD_CLOEXEC: c_int = 5; + +pub const SIGTRAP: c_int = 5; + +pub const CLOCK_REALTIME: crate::clockid_t = 0; +pub const CLOCK_MONOTONIC: crate::clockid_t = 2; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 3; +pub const CLOCK_THREAD_CPUTIME_ID: crate::clockid_t = 4; +pub const TIMER_ABSTIME: c_uint = 0x80000000; + +pub const RUSAGE_SELF: c_int = 0; + +pub const F_OK: c_int = 0; +pub const X_OK: c_int = 1; +pub const W_OK: c_int = 2; +pub const R_OK: c_int = 4; + +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; + +pub const PROT_NONE: c_int = 0x00000000; +pub const PROT_READ: c_int = 0x00000100; +pub const PROT_WRITE: c_int = 0x00000200; +pub const PROT_EXEC: c_int = 0x00000400; + +pub const MAP_FILE: c_int = 0; +pub const MAP_SHARED: c_int = 1; +pub const MAP_PRIVATE: c_int = 2; +pub const MAP_FIXED: c_int = 0x10; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const MS_ASYNC: c_int = 1; +pub const MS_INVALIDATE: c_int = 4; +pub const MS_SYNC: c_int = 2; + +pub const SCM_RIGHTS: c_int = 0x01; +pub const SCM_TIMESTAMP: c_int = 0x02; + +// QNX Network Stack Versioning: +// +// The `if` block targets the legacy `io-pkt` stack. +// - target_env = "nto70": QNX 7.0 +// - target_env = "nto71": Standard QNX 7.1 (default legacy stack) +// +// The `else` block targets the modern `io-sock` stack. +// - target_env = "nto71_iosock": QNX 7.1 with the optional new stack +// - target_env = "nto80": QNX 8.0 +cfg_if! { + if #[cfg(any(target_env = "nto70", target_env = "nto71"))] { + pub const SCM_CREDS: c_int = 0x04; + pub const IFF_NOTRAILERS: c_int = 0x00000020; + pub const AF_INET6: c_int = 24; + pub const AF_BLUETOOTH: c_int = 31; + pub const pseudo_AF_KEY: c_int = 29; + pub const MSG_NOSIGNAL: c_int = 0x0800; + pub const MSG_WAITFORONE: c_int = 0x2000; + pub const IP_IPSEC_POLICY_COMPAT: c_int = 22; + pub const IP_PKTINFO: c_int = 25; + pub const IPPROTO_DIVERT: c_int = 259; + pub const IPV6_IPSEC_POLICY_COMPAT: c_int = 28; + pub const TCP_KEEPALIVE: c_int = 0x04; + pub const ARPHRD_ARCNET: u16 = 7; + pub const SO_BINDTODEVICE: c_int = 0x0800; + pub const EAI_NODATA: c_int = 7; + pub const IPTOS_ECN_NOT_ECT: u8 = 0x00; + pub const RTF_BROADCAST: u32 = 0x80000; + pub const UDP_ENCAP: c_int = 100; + pub const HW_IOSTATS: c_int = 9; + pub const HW_MACHINE_ARCH: c_int = 10; + pub const HW_ALIGNBYTES: c_int = 11; + pub const HW_CNMAGIC: c_int = 12; + pub const HW_PHYSMEM64: c_int = 13; + pub const HW_USERMEM64: c_int = 14; + pub const HW_IOSTATNAMES: c_int = 15; + pub const HW_MAXID: c_int = 15; + pub const CTL_UNSPEC: c_int = 0; + pub const CTL_QNX: c_int = 9; + pub const CTL_PROC: c_int = 10; + pub const CTL_VENDOR: c_int = 11; + pub const CTL_EMUL: c_int = 12; + pub const CTL_SECURITY: c_int = 13; + pub const CTL_MAXID: c_int = 14; + pub const AF_ARP: c_int = 28; + pub const AF_IEEE80211: c_int = 32; + pub const AF_NATM: c_int = 27; + pub const AF_NS: c_int = 6; + pub const BIOCGDLTLIST: c_int = -1072676233; + pub const BIOCGETIF: c_int = 1083196011; + pub const BIOCGSEESENT: c_int = 1074020984; + pub const BIOCGSTATS: c_int = 1082147439; + pub const BIOCSDLT: c_int = -2147204490; + pub const BIOCSETIF: c_int = -2138029460; + pub const BIOCSSEESENT: c_int = -2147204487; + pub const FIONSPACE: c_int = 1074030200; + pub const FIONWRITE: c_int = 1074030201; + pub const IFF_ACCEPTRTADV: c_int = 0x40000000; + pub const IFF_IP6FORWARDING: c_int = 0x20000000; + pub const IFF_SHIM: c_int = 0x80000000; + pub const KERN_ARND: c_int = 81; + pub const KERN_IOV_MAX: c_int = 38; + pub const KERN_LOGSIGEXIT: c_int = 46; + pub const KERN_MAXID: c_int = 83; + pub const KERN_PROC_ARGS: c_int = 48; + pub const KERN_PROC_ENV: c_int = 3; + pub const KERN_PROC_GID: c_int = 7; + pub const KERN_PROC_RGID: c_int = 8; + pub const LOCAL_CONNWAIT: c_int = 0x0002; + pub const LOCAL_CREDS: c_int = 0x0001; + pub const LOCAL_PEEREID: c_int = 0x0003; + pub const MSG_NOTIFICATION: c_int = 0x0400; + pub const NET_RT_IFLIST: c_int = 4; + pub const NI_NUMERICSCOPE: c_int = 0x00000040; + pub const PF_ARP: c_int = 28; + pub const PF_NATM: c_int = 27; + pub const pseudo_AF_HDRCMPLT: c_int = 30; + pub const SIOCGIFADDR: c_int = -1064277727; + pub const SO_FIB: c_int = 0x100a; + pub const SO_TXPRIO: c_int = 0x100b; + pub const SO_SETFIB: c_int = 0x100a; + pub const SO_VLANPRIO: c_int = 0x100c; + pub const USER_ATEXIT_MAX: c_int = 21; + pub const USER_MAXID: c_int = 22; + pub const SO_OVERFLOWED: c_int = 0x1009; + } else { + pub const SCM_CREDS: c_int = 0x03; + pub const AF_INET6: c_int = 28; + pub const AF_BLUETOOTH: c_int = 36; + pub const pseudo_AF_KEY: c_int = 27; + pub const MSG_NOSIGNAL: c_int = 0x20000; + pub const MSG_WAITFORONE: c_int = 0x00080000; + pub const IPPROTO_DIVERT: c_int = 258; + pub const RTF_BROADCAST: u32 = 0x400000; + pub const UDP_ENCAP: c_int = 1; + pub const HW_MACHINE_ARCH: c_int = 11; + pub const AF_ARP: c_int = 35; + pub const AF_IEEE80211: c_int = 37; + pub const AF_NATM: c_int = 29; + pub const BIOCGDLTLIST: c_ulong = 0xffffffffc0104279; + pub const BIOCGETIF: c_int = 0x4020426b; + pub const BIOCGSEESENT: c_int = 0x40044276; + pub const BIOCGSTATS: c_int = 0x4008426f; + pub const BIOCSDLT: c_int = 0x80044278; + pub const BIOCSETIF: c_int = 0x8020426c; + pub const BIOCSSEESENT: c_int = 0x80044277; + pub const KERN_ARND: c_int = 37; + pub const KERN_IOV_MAX: c_int = 35; + pub const KERN_LOGSIGEXIT: c_int = 34; + pub const KERN_PROC_ARGS: c_int = 7; + pub const KERN_PROC_ENV: c_int = 35; + pub const KERN_PROC_GID: c_int = 11; + pub const KERN_PROC_RGID: c_int = 10; + pub const LOCAL_CONNWAIT: c_int = 4; + pub const LOCAL_CREDS: c_int = 2; + pub const MSG_NOTIFICATION: c_int = 0x00002000; + pub const NET_RT_IFLIST: c_int = 3; + pub const NI_NUMERICSCOPE: c_int = 0x00000020; + pub const PF_ARP: c_int = AF_ARP; + pub const PF_NATM: c_int = AF_NATM; + pub const pseudo_AF_HDRCMPLT: c_int = 31; + pub const SIOCGIFADDR: c_int = 0xc0206921; + pub const SO_SETFIB: c_int = 0x1014; + } +} + +pub const MAP_TYPE: c_int = 0x3; + +pub const IFF_UP: c_int = 0x00000001; +pub const IFF_BROADCAST: c_int = 0x00000002; +pub const IFF_DEBUG: c_int = 0x00000004; +pub const IFF_LOOPBACK: c_int = 0x00000008; +pub const IFF_POINTOPOINT: c_int = 0x00000010; +pub const IFF_RUNNING: c_int = 0x00000040; +pub const IFF_NOARP: c_int = 0x00000080; +pub const IFF_PROMISC: c_int = 0x00000100; +pub const IFF_ALLMULTI: c_int = 0x00000200; +pub const IFF_MULTICAST: c_int = 0x00008000; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_LOCAL: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_IPX: c_int = 23; +pub const AF_APPLETALK: c_int = 16; +pub const AF_ROUTE: c_int = 17; +pub const AF_SNA: c_int = 11; + +pub const AF_ISDN: c_int = 26; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_INET: c_int = AF_INET; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_KEY: c_int = pseudo_AF_KEY; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_SNA: c_int = AF_SNA; + +pub const PF_BLUETOOTH: c_int = AF_BLUETOOTH; +pub const PF_ISDN: c_int = AF_ISDN; + +pub const SOMAXCONN: c_int = 128; + +pub const MSG_OOB: c_int = 0x0001; +pub const MSG_PEEK: c_int = 0x0002; +pub const MSG_DONTROUTE: c_int = 0x0004; +pub const MSG_CTRUNC: c_int = 0x0020; +pub const MSG_TRUNC: c_int = 0x0010; +pub const MSG_DONTWAIT: c_int = 0x0080; +pub const MSG_EOR: c_int = 0x0008; +pub const MSG_WAITALL: c_int = 0x0040; + +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_HDRINCL: c_int = 2; +pub const IP_OPTIONS: c_int = 1; +pub const IP_RECVOPTS: c_int = 5; +pub const IP_RETOPTS: c_int = 8; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_DEFAULT_MULTICAST_TTL: c_int = 1; +pub const IP_DEFAULT_MULTICAST_LOOP: c_int = 1; + +pub const IPPROTO_HOPOPTS: c_int = 0; +pub const IPPROTO_IGMP: c_int = 2; +pub const IPPROTO_IPIP: c_int = 4; +pub const IPPROTO_EGP: c_int = 8; +pub const IPPROTO_PUP: c_int = 12; +pub const IPPROTO_IDP: c_int = 22; +pub const IPPROTO_TP: c_int = 29; +pub const IPPROTO_ROUTING: c_int = 43; +pub const IPPROTO_FRAGMENT: c_int = 44; +pub const IPPROTO_RSVP: c_int = 46; +pub const IPPROTO_GRE: c_int = 47; +pub const IPPROTO_ESP: c_int = 50; +pub const IPPROTO_AH: c_int = 51; +pub const IPPROTO_NONE: c_int = 59; +pub const IPPROTO_DSTOPTS: c_int = 60; +pub const IPPROTO_ENCAP: c_int = 98; +pub const IPPROTO_PIM: c_int = 103; +pub const IPPROTO_SCTP: c_int = 132; +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MAX: c_int = 256; +pub const IPPROTO_CARP: c_int = 112; +pub const IPPROTO_DONE: c_int = 257; +pub const IPPROTO_EON: c_int = 80; +pub const IPPROTO_ETHERIP: c_int = 97; +pub const IPPROTO_GGP: c_int = 3; +pub const IPPROTO_IPCOMP: c_int = 108; +pub const IPPROTO_MOBILE: c_int = 55; + +pub const IPV6_RTHDR_LOOSE: c_int = 0; +pub const IPV6_RTHDR_STRICT: c_int = 1; +pub const IPV6_UNICAST_HOPS: c_int = 4; +pub const IPV6_MULTICAST_IF: c_int = 9; +pub const IPV6_MULTICAST_HOPS: c_int = 10; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IPV6_JOIN_GROUP: c_int = 12; +pub const IPV6_LEAVE_GROUP: c_int = 13; +pub const IPV6_CHECKSUM: c_int = 26; +pub const IPV6_V6ONLY: c_int = 27; +pub const IPV6_RTHDRDSTOPTS: c_int = 35; +pub const IPV6_RECVPKTINFO: c_int = 36; +pub const IPV6_RECVHOPLIMIT: c_int = 37; +pub const IPV6_RECVRTHDR: c_int = 38; +pub const IPV6_RECVHOPOPTS: c_int = 39; +pub const IPV6_RECVDSTOPTS: c_int = 40; +pub const IPV6_RECVPATHMTU: c_int = 43; +pub const IPV6_PATHMTU: c_int = 44; +pub const IPV6_PKTINFO: c_int = 46; +pub const IPV6_HOPLIMIT: c_int = 47; +pub const IPV6_NEXTHOP: c_int = 48; +pub const IPV6_HOPOPTS: c_int = 49; +pub const IPV6_DSTOPTS: c_int = 50; +pub const IPV6_RECVTCLASS: c_int = 57; +pub const IPV6_TCLASS: c_int = 61; +pub const IPV6_DONTFRAG: c_int = 62; + +pub const TCP_NODELAY: c_int = 0x01; +pub const TCP_MAXSEG: c_int = 0x02; +pub const TCP_MD5SIG: c_int = 0x10; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const LOCK_SH: c_int = 0x1; +pub const LOCK_EX: c_int = 0x2; +pub const LOCK_NB: c_int = 0x4; +pub const LOCK_UN: c_int = 0x8; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 2; + +pub const PATH_MAX: c_int = 1024; + +pub const UIO_MAXIOV: c_int = 1024; + +pub const FD_SETSIZE: usize = 256; + +pub const TCIOFF: c_int = 0x0002; +pub const TCION: c_int = 0x0003; +pub const TCOOFF: c_int = 0x0000; +pub const TCOON: c_int = 0x0001; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const NL0: crate::tcflag_t = 0x000; +pub const NL1: crate::tcflag_t = 0x100; +pub const TAB0: crate::tcflag_t = 0x0000; +pub const CR0: crate::tcflag_t = 0x000; +pub const FF0: crate::tcflag_t = 0x0000; +pub const BS0: crate::tcflag_t = 0x0000; +pub const VT0: crate::tcflag_t = 0x0000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNPAR: crate::tcflag_t = 0x00000004; +pub const PARMRK: crate::tcflag_t = 0x00000008; +pub const INPCK: crate::tcflag_t = 0x00000010; +pub const ISTRIP: crate::tcflag_t = 0x00000020; +pub const INLCR: crate::tcflag_t = 0x00000040; +pub const IGNCR: crate::tcflag_t = 0x00000080; +pub const ICRNL: crate::tcflag_t = 0x00000100; +pub const IXANY: crate::tcflag_t = 0x00000800; +pub const IMAXBEL: crate::tcflag_t = 0x00002000; +pub const OPOST: crate::tcflag_t = 0x00000001; +pub const CS5: crate::tcflag_t = 0x00; +pub const ECHO: crate::tcflag_t = 0x00000008; +pub const OCRNL: crate::tcflag_t = 0x00000008; +pub const ONOCR: crate::tcflag_t = 0x00000010; +pub const ONLRET: crate::tcflag_t = 0x00000020; +pub const OFILL: crate::tcflag_t = 0x00000040; +pub const OFDEL: crate::tcflag_t = 0x00000080; + +pub const WNOHANG: c_int = 0x0040; +pub const WUNTRACED: c_int = 0x0004; +pub const WSTOPPED: c_int = WUNTRACED; +pub const WEXITED: c_int = 0x0001; +pub const WCONTINUED: c_int = 0x0008; +pub const WNOWAIT: c_int = 0x0080; +pub const WTRAPPED: c_int = 0x0002; + +pub const RTLD_LOCAL: c_int = 0x0200; +pub const RTLD_LAZY: c_int = 0x0001; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 2; +pub const POSIX_FADV_SEQUENTIAL: c_int = 1; +pub const POSIX_FADV_WILLNEED: c_int = 3; + +pub const AT_FDCWD: c_int = -100; +pub const AT_EACCESS: c_int = 0x0001; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x0002; +pub const AT_SYMLINK_FOLLOW: c_int = 0x0004; +pub const AT_REMOVEDIR: c_int = 0x0008; + +pub const LOG_CRON: c_int = 9 << 3; +pub const LOG_AUTHPRIV: c_int = 10 << 3; +pub const LOG_FTP: c_int = 11 << 3; +pub const LOG_PERROR: c_int = 0x20; + +pub const PIPE_BUF: usize = 5120; + +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const UTIME_OMIT: c_long = 0x40000002; +pub const UTIME_NOW: c_long = 0x40000001; + +pub const POLLIN: c_short = POLLRDNORM | POLLRDBAND; +pub const POLLPRI: c_short = 0x0008; +pub const POLLOUT: c_short = 0x0002; +pub const POLLERR: c_short = 0x0020; +pub const POLLHUP: c_short = 0x0040; +pub const POLLNVAL: c_short = 0x1000; +pub const POLLRDNORM: c_short = 0x0001; +pub const POLLRDBAND: c_short = 0x0004; + +pub const IPTOS_LOWDELAY: u8 = 0x10; +pub const IPTOS_THROUGHPUT: u8 = 0x08; +pub const IPTOS_RELIABILITY: u8 = 0x04; +pub const IPTOS_MINCOST: u8 = 0x02; + +pub const IPTOS_PREC_NETCONTROL: u8 = 0xe0; +pub const IPTOS_PREC_INTERNETCONTROL: u8 = 0xc0; +pub const IPTOS_PREC_CRITIC_ECP: u8 = 0xa0; +pub const IPTOS_PREC_FLASHOVERRIDE: u8 = 0x80; +pub const IPTOS_PREC_FLASH: u8 = 0x60; +pub const IPTOS_PREC_IMMEDIATE: u8 = 0x40; +pub const IPTOS_PREC_PRIORITY: u8 = 0x20; +pub const IPTOS_PREC_ROUTINE: u8 = 0x00; + +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const IPOPT_CONTROL: u8 = 0x00; +pub const IPOPT_RESERVED1: u8 = 0x20; +pub const IPOPT_RESERVED2: u8 = 0x60; +pub const IPOPT_LSRR: u8 = 131; +pub const IPOPT_RR: u8 = 7; +pub const IPOPT_SSRR: u8 = 137; +pub const IPDEFTTL: u8 = 64; +pub const IPOPT_OPTVAL: u8 = 0; +pub const IPOPT_OLEN: u8 = 1; +pub const IPOPT_OFFSET: u8 = 2; +pub const IPOPT_MINOFF: u8 = 4; +pub const IPOPT_NOP: u8 = 1; +pub const IPOPT_EOL: u8 = 0; +pub const IPOPT_TS: u8 = 68; +pub const IPOPT_TS_TSONLY: u8 = 0; +pub const IPOPT_TS_TSANDADDR: u8 = 1; +pub const IPOPT_TS_PRESPEC: u8 = 3; + +pub const MAX_IPOPTLEN: u8 = 40; +pub const IPVERSION: u8 = 4; +pub const MAXTTL: u8 = 255; + +pub const ARPHRD_ETHER: u16 = 1; +pub const ARPHRD_IEEE802: u16 = 6; +pub const ARPHRD_IEEE1394: u16 = 24; + +pub const SOL_SOCKET: c_int = 0xffff; + +pub const SO_DEBUG: c_int = 0x0001; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_REUSEPORT: c_int = 0x0200; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_TIMESTAMP: c_int = 0x0400; +pub const SO_ACCEPTCONN: c_int = 0x0002; + +pub const TIOCM_LE: c_int = 0x0100; +pub const TIOCM_DTR: c_int = 0x0001; +pub const TIOCM_RTS: c_int = 0x0002; +pub const TIOCM_ST: c_int = 0x0200; +pub const TIOCM_SR: c_int = 0x0400; +pub const TIOCM_CTS: c_int = 0x1000; +pub const TIOCM_CAR: c_int = TIOCM_CD; +pub const TIOCM_CD: c_int = 0x8000; +pub const TIOCM_RNG: c_int = TIOCM_RI; +pub const TIOCM_RI: c_int = 0x4000; +pub const TIOCM_DSR: c_int = 0x2000; + +pub const SCHED_OTHER: c_int = 3; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; + +pub const IPC_PRIVATE: crate::key_t = 0; + +pub const IPC_CREAT: c_int = 0o001000; +pub const IPC_EXCL: c_int = 0o002000; +pub const IPC_NOWAIT: c_int = 0o004000; + +pub const IPC_RMID: c_int = 0; +pub const IPC_SET: c_int = 1; +pub const IPC_STAT: c_int = 2; + +pub const MSG_NOERROR: c_int = 0o010000; + +pub const LOG_NFACILITIES: c_int = 24; + +pub const SEM_FAILED: *mut crate::sem_t = 0xFFFFFFFFFFFFFFFF as *mut sem_t; + +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; + +pub const AI_NUMERICSERV: c_int = 0x00000008; + +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_NONAME: c_int = 8; +pub const EAI_AGAIN: c_int = 2; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 14; + +pub const NI_NUMERICHOST: c_int = 0x00000002; +pub const NI_NUMERICSERV: c_int = 0x00000008; +pub const NI_NOFQDN: c_int = 0x00000001; +pub const NI_NAMEREQD: c_int = 0x00000004; +pub const NI_DGRAM: c_int = 0x00000010; + +pub const AIO_CANCELED: c_int = 0; +pub const AIO_NOTCANCELED: c_int = 2; +pub const AIO_ALLDONE: c_int = 1; +pub const LIO_READ: c_int = 1; +pub const LIO_WRITE: c_int = 2; +pub const LIO_NOP: c_int = 0; +pub const LIO_WAIT: c_int = 1; +pub const LIO_NOWAIT: c_int = 0; + +pub const ITIMER_REAL: c_int = 0; +pub const ITIMER_VIRTUAL: c_int = 1; +pub const ITIMER_PROF: c_int = 2; + +// DIFF(main): changed to `c_short` in f62eb023ab +pub const POSIX_SPAWN_RESETIDS: c_int = 0x00000010; +pub const POSIX_SPAWN_SETPGROUP: c_int = 0x00000001; +pub const POSIX_SPAWN_SETSIGDEF: c_int = 0x00000004; +pub const POSIX_SPAWN_SETSIGMASK: c_int = 0x00000002; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 0x00000400; +pub const POSIX_SPAWN_SETSCHEDULER: c_int = 0x00000040; + +pub const RTF_UP: c_ushort = 0x0001; +pub const RTF_GATEWAY: c_ushort = 0x0002; + +pub const RTF_HOST: c_ushort = 0x0004; +pub const RTF_DYNAMIC: c_ushort = 0x0010; +pub const RTF_MODIFIED: c_ushort = 0x0020; +pub const RTF_REJECT: c_ushort = 0x0008; +pub const RTF_STATIC: c_ushort = 0x0800; +pub const RTF_XRESOLVE: c_ushort = 0x0200; +pub const RTM_NEWADDR: u16 = 0xc; +pub const RTM_DELADDR: u16 = 0xd; +pub const RTA_DST: c_ushort = 0x1; +pub const RTA_GATEWAY: c_ushort = 0x2; + +pub const IN_ACCESS: u32 = 0x00000001; +pub const IN_MODIFY: u32 = 0x00000002; +pub const IN_ATTRIB: u32 = 0x00000004; +pub const IN_CLOSE_WRITE: u32 = 0x00000008; +pub const IN_CLOSE_NOWRITE: u32 = 0x00000010; +pub const IN_CLOSE: u32 = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE; +pub const IN_OPEN: u32 = 0x00000020; +pub const IN_MOVED_FROM: u32 = 0x00000040; +pub const IN_MOVED_TO: u32 = 0x00000080; +pub const IN_MOVE: u32 = IN_MOVED_FROM | IN_MOVED_TO; +pub const IN_CREATE: u32 = 0x00000100; +pub const IN_DELETE: u32 = 0x00000200; +pub const IN_DELETE_SELF: u32 = 0x00000400; +pub const IN_MOVE_SELF: u32 = 0x00000800; +pub const IN_UNMOUNT: u32 = 0x00002000; +pub const IN_Q_OVERFLOW: u32 = 0x00004000; +pub const IN_IGNORED: u32 = 0x00008000; +pub const IN_ONLYDIR: u32 = 0x01000000; +pub const IN_DONT_FOLLOW: u32 = 0x02000000; + +pub const IN_ISDIR: u32 = 0x40000000; +pub const IN_ONESHOT: u32 = 0x80000000; + +pub const REG_EXTENDED: c_int = 0o0001; +pub const REG_ICASE: c_int = 0o0002; +pub const REG_NEWLINE: c_int = 0o0010; +pub const REG_NOSUB: c_int = 0o0004; + +pub const REG_NOTBOL: c_int = 0o00001; +pub const REG_NOTEOL: c_int = 0o00002; + +pub const REG_ENOSYS: c_int = 17; +pub const REG_NOMATCH: c_int = 1; +pub const REG_BADPAT: c_int = 2; +pub const REG_ECOLLATE: c_int = 3; +pub const REG_ECTYPE: c_int = 4; +pub const REG_EESCAPE: c_int = 5; +pub const REG_ESUBREG: c_int = 6; +pub const REG_EBRACK: c_int = 7; +pub const REG_EPAREN: c_int = 8; +pub const REG_EBRACE: c_int = 9; +pub const REG_BADBR: c_int = 10; +pub const REG_ERANGE: c_int = 11; +pub const REG_ESPACE: c_int = 12; +pub const REG_BADRPT: c_int = 13; + +// errno.h +pub const EOK: c_int = 0; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EDEADLK: c_int = 45; +pub const ENOLCK: c_int = 46; +pub const ECANCELED: c_int = 47; +pub const EDQUOT: c_int = 49; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EBFONT: c_int = 57; +pub const EOWNERDEAD: c_int = 58; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const EMULTIHOP: c_int = 74; +pub const EBADMSG: c_int = 77; +pub const ENAMETOOLONG: c_int = 78; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ENOSYS: c_int = 89; +pub const ELOOP: c_int = 90; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const ENOTEMPTY: c_int = 93; +pub const EUSERS: c_int = 94; +pub const ENOTRECOVERABLE: c_int = 95; +pub const EOPNOTSUPP: c_int = 103; +pub const EFPOS: c_int = 110; +pub const ESTALE: c_int = 122; +pub const EINPROGRESS: c_int = 236; +pub const EALREADY: c_int = 237; +pub const ENOTSOCK: c_int = 238; +pub const EDESTADDRREQ: c_int = 239; +pub const EMSGSIZE: c_int = 240; +pub const EPROTOTYPE: c_int = 241; +pub const ENOPROTOOPT: c_int = 242; +pub const EPROTONOSUPPORT: c_int = 243; +pub const ESOCKTNOSUPPORT: c_int = 244; +pub const EPFNOSUPPORT: c_int = 246; +pub const EAFNOSUPPORT: c_int = 247; +pub const EADDRINUSE: c_int = 248; +pub const EADDRNOTAVAIL: c_int = 249; +pub const ENETDOWN: c_int = 250; +pub const ENETUNREACH: c_int = 251; +pub const ENETRESET: c_int = 252; +pub const ECONNABORTED: c_int = 253; +pub const ECONNRESET: c_int = 254; +pub const ENOBUFS: c_int = 255; +pub const EISCONN: c_int = 256; +pub const ENOTCONN: c_int = 257; +pub const ESHUTDOWN: c_int = 258; +pub const ETOOMANYREFS: c_int = 259; +pub const ETIMEDOUT: c_int = 260; +pub const ECONNREFUSED: c_int = 261; +pub const EHOSTDOWN: c_int = 264; +pub const EHOSTUNREACH: c_int = 265; +pub const EBADRPC: c_int = 272; +pub const ERPCMISMATCH: c_int = 273; +pub const EPROGUNAVAIL: c_int = 274; +pub const EPROGMISMATCH: c_int = 275; +pub const EPROCUNAVAIL: c_int = 276; +pub const ENOREMOTE: c_int = 300; +pub const ENONDP: c_int = 301; +pub const EBADFSYS: c_int = 302; +pub const EMORE: c_int = 309; +pub const ECTRLTERM: c_int = 310; +pub const ENOLIC: c_int = 311; +pub const ESRVRFAULT: c_int = 312; +pub const EENDIAN: c_int = 313; +pub const ESECTYPEINVAL: c_int = 314; + +pub const RUSAGE_CHILDREN: c_int = -1; +pub const L_tmpnam: c_uint = 255; + +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_CHOWN_RESTRICTED: c_int = 9; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 14; +pub const _PC_ASYNC_IO: c_int = 12; +pub const _PC_PRIO_IO: c_int = 13; +pub const _PC_SOCK_MAXBUF: c_int = 15; +pub const _PC_FILESIZEBITS: c_int = 16; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 22; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 23; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 24; +pub const _PC_REC_XFER_ALIGN: c_int = 25; +pub const _PC_ALLOC_SIZE_MIN: c_int = 21; +pub const _PC_SYMLINK_MAX: c_int = 17; +pub const _PC_2_SYMLINKS: c_int = 20; + +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_ARG_MAX: c_int = 1; +pub const _SC_CHILD_MAX: c_int = 2; +pub const _SC_CLK_TCK: c_int = 3; +pub const _SC_NGROUPS_MAX: c_int = 4; +pub const _SC_OPEN_MAX: c_int = 5; +pub const _SC_JOB_CONTROL: c_int = 6; +pub const _SC_SAVED_IDS: c_int = 7; +pub const _SC_VERSION: c_int = 8; +pub const _SC_PASS_MAX: c_int = 9; +pub const _SC_PAGESIZE: c_int = 11; +pub const _SC_XOPEN_VERSION: c_int = 12; +pub const _SC_STREAM_MAX: c_int = 13; +pub const _SC_TZNAME_MAX: c_int = 14; +pub const _SC_AIO_LISTIO_MAX: c_int = 15; +pub const _SC_AIO_MAX: c_int = 16; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 17; +pub const _SC_DELAYTIMER_MAX: c_int = 18; +pub const _SC_MQ_OPEN_MAX: c_int = 19; +pub const _SC_MQ_PRIO_MAX: c_int = 20; +pub const _SC_RTSIG_MAX: c_int = 21; +pub const _SC_SEM_NSEMS_MAX: c_int = 22; +pub const _SC_SEM_VALUE_MAX: c_int = 23; +pub const _SC_SIGQUEUE_MAX: c_int = 24; +pub const _SC_TIMER_MAX: c_int = 25; +pub const _SC_ASYNCHRONOUS_IO: c_int = 26; +pub const _SC_FSYNC: c_int = 27; +pub const _SC_MAPPED_FILES: c_int = 28; +pub const _SC_MEMLOCK: c_int = 29; +pub const _SC_MEMLOCK_RANGE: c_int = 30; +pub const _SC_MEMORY_PROTECTION: c_int = 31; +pub const _SC_MESSAGE_PASSING: c_int = 32; +pub const _SC_PRIORITIZED_IO: c_int = 33; +pub const _SC_PRIORITY_SCHEDULING: c_int = 34; +pub const _SC_REALTIME_SIGNALS: c_int = 35; +pub const _SC_SEMAPHORES: c_int = 36; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 37; +pub const _SC_SYNCHRONIZED_IO: c_int = 38; +pub const _SC_TIMERS: c_int = 39; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 40; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 41; +pub const _SC_LOGIN_NAME_MAX: c_int = 42; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 43; +pub const _SC_THREAD_KEYS_MAX: c_int = 44; +pub const _SC_THREAD_STACK_MIN: c_int = 45; +pub const _SC_THREAD_THREADS_MAX: c_int = 46; +pub const _SC_TTY_NAME_MAX: c_int = 47; +pub const _SC_THREADS: c_int = 48; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 49; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 50; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 51; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 52; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 53; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 54; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 55; +pub const _SC_2_CHAR_TERM: c_int = 56; +pub const _SC_2_C_BIND: c_int = 57; +pub const _SC_2_C_DEV: c_int = 58; +pub const _SC_2_C_VERSION: c_int = 59; +pub const _SC_2_FORT_DEV: c_int = 60; +pub const _SC_2_FORT_RUN: c_int = 61; +pub const _SC_2_LOCALEDEF: c_int = 62; +pub const _SC_2_SW_DEV: c_int = 63; +pub const _SC_2_UPE: c_int = 64; +pub const _SC_2_VERSION: c_int = 65; +pub const _SC_ATEXIT_MAX: c_int = 66; +pub const _SC_AVPHYS_PAGES: c_int = 67; +pub const _SC_BC_BASE_MAX: c_int = 68; +pub const _SC_BC_DIM_MAX: c_int = 69; +pub const _SC_BC_SCALE_MAX: c_int = 70; +pub const _SC_BC_STRING_MAX: c_int = 71; +pub const _SC_CHARCLASS_NAME_MAX: c_int = 72; +pub const _SC_CHAR_BIT: c_int = 73; +pub const _SC_CHAR_MAX: c_int = 74; +pub const _SC_CHAR_MIN: c_int = 75; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 76; +pub const _SC_EQUIV_CLASS_MAX: c_int = 77; +pub const _SC_EXPR_NEST_MAX: c_int = 78; +pub const _SC_INT_MAX: c_int = 79; +pub const _SC_INT_MIN: c_int = 80; +pub const _SC_LINE_MAX: c_int = 81; +pub const _SC_LONG_BIT: c_int = 82; +pub const _SC_MB_LEN_MAX: c_int = 83; +pub const _SC_NL_ARGMAX: c_int = 84; +pub const _SC_NL_LANGMAX: c_int = 85; +pub const _SC_NL_MSGMAX: c_int = 86; +pub const _SC_NL_NMAX: c_int = 87; +pub const _SC_NL_SETMAX: c_int = 88; +pub const _SC_NL_TEXTMAX: c_int = 89; +pub const _SC_NPROCESSORS_CONF: c_int = 90; +pub const _SC_NPROCESSORS_ONLN: c_int = 91; +pub const _SC_NZERO: c_int = 92; +pub const _SC_PHYS_PAGES: c_int = 93; +pub const _SC_PII: c_int = 94; +pub const _SC_PII_INTERNET: c_int = 95; +pub const _SC_PII_INTERNET_DGRAM: c_int = 96; +pub const _SC_PII_INTERNET_STREAM: c_int = 97; +pub const _SC_PII_OSI: c_int = 98; +pub const _SC_PII_OSI_CLTS: c_int = 99; +pub const _SC_PII_OSI_COTS: c_int = 100; +pub const _SC_PII_OSI_M: c_int = 101; +pub const _SC_PII_SOCKET: c_int = 102; +pub const _SC_PII_XTI: c_int = 103; +pub const _SC_POLL: c_int = 104; +pub const _SC_RE_DUP_MAX: c_int = 105; +pub const _SC_SCHAR_MAX: c_int = 106; +pub const _SC_SCHAR_MIN: c_int = 107; +pub const _SC_SELECT: c_int = 108; +pub const _SC_SHRT_MAX: c_int = 109; +pub const _SC_SHRT_MIN: c_int = 110; +pub const _SC_SSIZE_MAX: c_int = 111; +pub const _SC_T_IOV_MAX: c_int = 112; +pub const _SC_UCHAR_MAX: c_int = 113; +pub const _SC_UINT_MAX: c_int = 114; +pub const _SC_UIO_MAXIOV: c_int = 115; +pub const _SC_ULONG_MAX: c_int = 116; +pub const _SC_USHRT_MAX: c_int = 117; +pub const _SC_WORD_BIT: c_int = 118; +pub const _SC_XOPEN_CRYPT: c_int = 119; +pub const _SC_XOPEN_ENH_I18N: c_int = 120; +pub const _SC_XOPEN_SHM: c_int = 121; +pub const _SC_XOPEN_UNIX: c_int = 122; +pub const _SC_XOPEN_XCU_VERSION: c_int = 123; +pub const _SC_XOPEN_XPG2: c_int = 124; +pub const _SC_XOPEN_XPG3: c_int = 125; +pub const _SC_XOPEN_XPG4: c_int = 126; +pub const _SC_XBS5_ILP32_OFF32: c_int = 127; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 128; +pub const _SC_XBS5_LP64_OFF64: c_int = 129; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 130; +pub const _SC_ADVISORY_INFO: c_int = 131; +pub const _SC_CPUTIME: c_int = 132; +pub const _SC_SPAWN: c_int = 133; +pub const _SC_SPORADIC_SERVER: c_int = 134; +pub const _SC_THREAD_CPUTIME: c_int = 135; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 136; +pub const _SC_TIMEOUTS: c_int = 137; +pub const _SC_BARRIERS: c_int = 138; +pub const _SC_CLOCK_SELECTION: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 140; +pub const _SC_READER_WRITER_LOCKS: c_int = 141; +pub const _SC_SPIN_LOCKS: c_int = 142; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 143; +pub const _SC_TRACE_EVENT_FILTER: c_int = 144; +pub const _SC_TRACE: c_int = 145; +pub const _SC_TRACE_INHERIT: c_int = 146; +pub const _SC_TRACE_LOG: c_int = 147; +pub const _SC_2_PBS: c_int = 148; +pub const _SC_2_PBS_ACCOUNTING: c_int = 149; +pub const _SC_2_PBS_CHECKPOINT: c_int = 150; +pub const _SC_2_PBS_LOCATE: c_int = 151; +pub const _SC_2_PBS_MESSAGE: c_int = 152; +pub const _SC_2_PBS_TRACK: c_int = 153; +pub const _SC_HOST_NAME_MAX: c_int = 154; +pub const _SC_IOV_MAX: c_int = 155; +pub const _SC_IPV6: c_int = 156; +pub const _SC_RAW_SOCKETS: c_int = 157; +pub const _SC_REGEXP: c_int = 158; +pub const _SC_SHELL: c_int = 159; +pub const _SC_SS_REPL_MAX: c_int = 160; +pub const _SC_SYMLOOP_MAX: c_int = 161; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 162; +pub const _SC_TRACE_NAME_MAX: c_int = 163; +pub const _SC_TRACE_SYS_MAX: c_int = 164; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 165; +pub const _SC_V6_ILP32_OFF32: c_int = 166; +pub const _SC_V6_ILP32_OFFBIG: c_int = 167; +pub const _SC_V6_LP64_OFF64: c_int = 168; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 169; +pub const _SC_XOPEN_REALTIME: c_int = 170; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 171; +pub const _SC_XOPEN_LEGACY: c_int = 172; +pub const _SC_XOPEN_STREAMS: c_int = 173; +pub const _SC_V7_ILP32_OFF32: c_int = 176; +pub const _SC_V7_ILP32_OFFBIG: c_int = 177; +pub const _SC_V7_LP64_OFF64: c_int = 178; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 179; + +pub const GLOB_ERR: c_int = 0x0001; +pub const GLOB_MARK: c_int = 0x0002; +pub const GLOB_NOSORT: c_int = 0x0004; +pub const GLOB_DOOFFS: c_int = 0x0008; +pub const GLOB_NOCHECK: c_int = 0x0010; +pub const GLOB_APPEND: c_int = 0x0020; +pub const GLOB_NOESCAPE: c_int = 0x0040; + +pub const GLOB_NOSPACE: c_int = 1; +pub const GLOB_ABORTED: c_int = 2; +pub const GLOB_NOMATCH: c_int = 3; + +pub const S_IEXEC: mode_t = crate::S_IXUSR; +pub const S_IWRITE: mode_t = crate::S_IWUSR; +pub const S_IREAD: mode_t = crate::S_IRUSR; + +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; + +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXU: mode_t = 0o0700; + +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; + +pub const ST_RDONLY: c_ulong = 0x01; +pub const ST_NOSUID: c_ulong = 0x04; +pub const ST_NOEXEC: c_ulong = 0x02; +pub const ST_NOATIME: c_ulong = 0x20; + +pub const RTLD_NEXT: *mut c_void = -3i64 as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = -2i64 as *mut c_void; +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_NOW: c_int = 0x0002; + +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const NEW_TIME: c_short = 4; +pub const OLD_TIME: c_short = 3; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; + +pub const ENOTSUP: c_int = 48; + +pub const BUFSIZ: c_uint = 1024; +pub const TMP_MAX: c_uint = 26 * 26 * 26; +pub const FOPEN_MAX: c_uint = 16; +pub const FILENAME_MAX: c_uint = 255; + +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const M_KEEP: c_int = 4; +pub const REG_STARTEND: c_int = 0o00004; +pub const VEOF: usize = 4; + +pub const RTLD_GLOBAL: c_int = 0x0100; +pub const RTLD_NOLOAD: c_int = 0x0004; + +pub const O_RDONLY: c_int = 0o000000; +pub const O_WRONLY: c_int = 0o000001; +pub const O_RDWR: c_int = 0o000002; + +pub const O_EXEC: c_int = 0o00003; +pub const O_ASYNC: c_int = 0o0200000; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const O_TRUNC: c_int = 0o001000; +pub const O_CLOEXEC: c_int = 0o020000; +pub const O_DIRECTORY: c_int = 0o4000000; +pub const O_ACCMODE: c_int = 0o000007; +pub const O_APPEND: c_int = 0o000010; +pub const O_CREAT: c_int = 0o000400; +pub const O_EXCL: c_int = 0o002000; +pub const O_NOCTTY: c_int = 0o004000; +pub const O_NONBLOCK: c_int = 0o000200; +pub const O_SYNC: c_int = 0o000040; +pub const O_RSYNC: c_int = 0o000100; +pub const O_DSYNC: c_int = 0o000020; +pub const O_NOFOLLOW: c_int = 0o010000; + +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_CLOEXEC: c_int = 0x10000000; + +pub const SA_SIGINFO: c_int = 0x0002; +pub const SA_NOCLDWAIT: c_int = 0x0020; +pub const SA_NODEFER: c_int = 0x0010; +pub const SA_RESETHAND: c_int = 0x0004; +pub const SA_NOCLDSTOP: c_int = 0x0001; + +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGWINCH: c_int = 20; +pub const SIGCHLD: c_int = 18; +pub const SIGBUS: c_int = 10; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGCONT: c_int = 25; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGURG: c_int = 21; +pub const SIGIO: c_int = SIGPOLL; +pub const SIGSYS: c_int = 12; +pub const SIGPOLL: c_int = 22; +pub const SIGPWR: c_int = 19; +pub const SIG_SETMASK: c_int = 2; +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; + +pub const POLLWRNORM: c_short = crate::POLLOUT; +pub const POLLWRBAND: c_short = 0x0010; + +pub const F_SETLK: c_int = 106; +pub const F_SETLKW: c_int = 107; +pub const F_ALLOCSP: c_int = 110; +pub const F_FREESP: c_int = 111; +pub const F_GETLK: c_int = 114; + +pub const F_RDLCK: c_int = 1; +pub const F_WRLCK: c_int = 2; +pub const F_UNLCK: c_int = 3; + +pub const NCCS: usize = 40; + +pub const MAP_ANON: c_int = MAP_ANONYMOUS; +pub const MAP_ANONYMOUS: c_int = 0x00080000; + +pub const MCL_CURRENT: c_int = 0x000000001; +pub const MCL_FUTURE: c_int = 0x000000002; + +pub const _TIO_CBAUD: crate::tcflag_t = 15; +pub const CBAUD: crate::tcflag_t = _TIO_CBAUD; +pub const TAB1: crate::tcflag_t = 0x0800; +pub const TAB2: crate::tcflag_t = 0x1000; +pub const TAB3: crate::tcflag_t = 0x1800; +pub const CR1: crate::tcflag_t = 0x200; +pub const CR2: crate::tcflag_t = 0x400; +pub const CR3: crate::tcflag_t = 0x600; +pub const FF1: crate::tcflag_t = 0x8000; +pub const BS1: crate::tcflag_t = 0x2000; +pub const VT1: crate::tcflag_t = 0x4000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 17; +pub const IXON: crate::tcflag_t = 0x00000400; +pub const IXOFF: crate::tcflag_t = 0x00001000; +pub const ONLCR: crate::tcflag_t = 0x00000004; +pub const CSIZE: crate::tcflag_t = 0x00000030; +pub const CS6: crate::tcflag_t = 0x10; +pub const CS7: crate::tcflag_t = 0x20; +pub const CS8: crate::tcflag_t = 0x30; +pub const CSTOPB: crate::tcflag_t = 0x00000040; +pub const CREAD: crate::tcflag_t = 0x00000080; +pub const PARENB: crate::tcflag_t = 0x00000100; +pub const PARODD: crate::tcflag_t = 0x00000200; +pub const HUPCL: crate::tcflag_t = 0x00000400; +pub const CLOCAL: crate::tcflag_t = 0x00000800; +pub const ECHOKE: crate::tcflag_t = 0x00000800; +pub const ECHOE: crate::tcflag_t = 0x00000010; +pub const ECHOK: crate::tcflag_t = 0x00000020; +pub const ECHONL: crate::tcflag_t = 0x00000040; +pub const ECHOCTL: crate::tcflag_t = 0x00000200; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const NOFLSH: crate::tcflag_t = 0x00000080; +pub const OLCUC: crate::tcflag_t = 0x00000002; +pub const NLDLY: crate::tcflag_t = 0x00000100; +pub const CRDLY: crate::tcflag_t = 0x00000600; +pub const TABDLY: crate::tcflag_t = 0x00001800; +pub const BSDLY: crate::tcflag_t = 0x00002000; +pub const FFDLY: crate::tcflag_t = 0x00008000; +pub const VTDLY: crate::tcflag_t = 0x00004000; +pub const XTABS: crate::tcflag_t = 0x1800; + +pub const B0: crate::speed_t = 0; +pub const B50: crate::speed_t = 1; +pub const B75: crate::speed_t = 2; +pub const B110: crate::speed_t = 3; +pub const B134: crate::speed_t = 4; +pub const B150: crate::speed_t = 5; +pub const B200: crate::speed_t = 6; +pub const B300: crate::speed_t = 7; +pub const B600: crate::speed_t = 8; +pub const B1200: crate::speed_t = 9; +pub const B1800: crate::speed_t = 10; +pub const B2400: crate::speed_t = 11; +pub const B4800: crate::speed_t = 12; +pub const B9600: crate::speed_t = 13; +pub const B19200: crate::speed_t = 14; +pub const B38400: crate::speed_t = 15; +pub const EXTA: crate::speed_t = 14; +pub const EXTB: crate::speed_t = 15; +pub const B57600: crate::speed_t = 57600; +pub const B115200: crate::speed_t = 115200; + +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 16; +pub const IEXTEN: crate::tcflag_t = 0x00008000; +pub const TOSTOP: crate::tcflag_t = 0x00000100; + +pub const TCSANOW: c_int = 0x0001; +pub const TCSADRAIN: c_int = 0x0002; +pub const TCSAFLUSH: c_int = 0x0004; + +pub const HW_MACHINE: c_int = 1; +pub const HW_MODEL: c_int = 2; +pub const HW_NCPU: c_int = 3; +pub const HW_BYTEORDER: c_int = 4; +pub const HW_PHYSMEM: c_int = 5; +pub const HW_USERMEM: c_int = 6; +pub const HW_PAGESIZE: c_int = 7; +pub const HW_DISKNAMES: c_int = 8; +pub const CTL_KERN: c_int = 1; +pub const CTL_VM: c_int = 2; +pub const CTL_VFS: c_int = 3; +pub const CTL_NET: c_int = 4; +pub const CTL_DEBUG: c_int = 5; +pub const CTL_HW: c_int = 6; +pub const CTL_MACHDEP: c_int = 7; +pub const CTL_USER: c_int = 8; + +pub const DAY_1: crate::nl_item = 8; +pub const DAY_2: crate::nl_item = 9; +pub const DAY_3: crate::nl_item = 10; +pub const DAY_4: crate::nl_item = 11; +pub const DAY_5: crate::nl_item = 12; +pub const DAY_6: crate::nl_item = 13; +pub const DAY_7: crate::nl_item = 14; + +pub const MON_1: crate::nl_item = 22; +pub const MON_2: crate::nl_item = 23; +pub const MON_3: crate::nl_item = 24; +pub const MON_4: crate::nl_item = 25; +pub const MON_5: crate::nl_item = 26; +pub const MON_6: crate::nl_item = 27; +pub const MON_7: crate::nl_item = 28; +pub const MON_8: crate::nl_item = 29; +pub const MON_9: crate::nl_item = 30; +pub const MON_10: crate::nl_item = 31; +pub const MON_11: crate::nl_item = 32; +pub const MON_12: crate::nl_item = 33; + +pub const ABDAY_1: crate::nl_item = 15; +pub const ABDAY_2: crate::nl_item = 16; +pub const ABDAY_3: crate::nl_item = 17; +pub const ABDAY_4: crate::nl_item = 18; +pub const ABDAY_5: crate::nl_item = 19; +pub const ABDAY_6: crate::nl_item = 20; +pub const ABDAY_7: crate::nl_item = 21; + +pub const ABMON_1: crate::nl_item = 34; +pub const ABMON_2: crate::nl_item = 35; +pub const ABMON_3: crate::nl_item = 36; +pub const ABMON_4: crate::nl_item = 37; +pub const ABMON_5: crate::nl_item = 38; +pub const ABMON_6: crate::nl_item = 39; +pub const ABMON_7: crate::nl_item = 40; +pub const ABMON_8: crate::nl_item = 41; +pub const ABMON_9: crate::nl_item = 42; +pub const ABMON_10: crate::nl_item = 43; +pub const ABMON_11: crate::nl_item = 44; +pub const ABMON_12: crate::nl_item = 45; + +pub const AF_CCITT: c_int = 10; +pub const AF_CHAOS: c_int = 5; +pub const AF_CNT: c_int = 21; +pub const AF_COIP: c_int = 20; +pub const AF_DATAKIT: c_int = 9; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_E164: c_int = 26; +pub const AF_ECMA: c_int = 8; +pub const AF_HYLINK: c_int = 15; +pub const AF_IMPLINK: c_int = 3; +pub const AF_ISO: c_int = 7; +pub const AF_LAT: c_int = 14; +pub const AF_LINK: c_int = 18; +pub const AF_OSI: c_int = 7; +pub const AF_PUP: c_int = 4; +pub const ALT_DIGITS: crate::nl_item = 50; +pub const AM_STR: crate::nl_item = 6; +pub const B76800: crate::speed_t = 76800; + +pub const BIOCFLUSH: c_int = 17000; +pub const BIOCGBLEN: c_int = 1074020966; +pub const BIOCGDLT: c_int = 1074020970; +pub const BIOCGHDRCMPLT: c_int = 1074020980; +pub const BIOCGRTIMEOUT: c_int = 1074807406; +pub const BIOCIMMEDIATE: c_int = -2147204496; +pub const BIOCPROMISC: c_int = 17001; +pub const BIOCSBLEN: c_int = -1073462682; +pub const BIOCSETF: c_int = -2146418073; +pub const BIOCSHDRCMPLT: c_int = -2147204491; +pub const BIOCSRTIMEOUT: c_int = -2146418067; +pub const BIOCVERSION: c_int = 1074020977; + +pub const BPF_ALIGNMENT: usize = size_of::(); +pub const CHAR_BIT: usize = 8; +pub const CODESET: crate::nl_item = 1; +pub const CRNCYSTR: crate::nl_item = 55; + +pub const D_FLAG_FILTER: c_int = 0x00000001; +pub const D_FLAG_STAT: c_int = 0x00000002; +pub const D_FLAG_STAT_FORM_MASK: c_int = 0x000000f0; +pub const D_FLAG_STAT_FORM_T32_2001: c_int = 0x00000010; +pub const D_FLAG_STAT_FORM_T32_2008: c_int = 0x00000020; +pub const D_FLAG_STAT_FORM_T64_2008: c_int = 0x00000030; +pub const D_FLAG_STAT_FORM_UNSET: c_int = 0x00000000; + +pub const D_FMT: crate::nl_item = 3; +pub const D_GETFLAG: c_int = 1; +pub const D_SETFLAG: c_int = 2; +pub const D_T_FMT: crate::nl_item = 2; +pub const ERA: crate::nl_item = 46; +pub const ERA_D_FMT: crate::nl_item = 47; +pub const ERA_D_T_FMT: crate::nl_item = 48; +pub const ERA_T_FMT: crate::nl_item = 49; +pub const RADIXCHAR: crate::nl_item = 51; +pub const THOUSEP: crate::nl_item = 52; +pub const YESEXPR: crate::nl_item = 53; +pub const NOEXPR: crate::nl_item = 54; +pub const F_GETOWN: c_int = 35; + +pub const FIONBIO: c_int = -2147195266; +pub const FIOASYNC: c_int = -2147195267; +pub const FIOCLEX: c_int = 26113; +pub const FIOGETOWN: c_int = 1074030203; +pub const FIONCLEX: c_int = 26114; +pub const FIONREAD: c_int = 1074030207; +pub const FIOSETOWN: c_int = -2147195268; + +pub const F_SETOWN: c_int = 36; +pub const IFF_LINK0: c_int = 0x00001000; +pub const IFF_LINK1: c_int = 0x00002000; +pub const IFF_LINK2: c_int = 0x00004000; +pub const IFF_OACTIVE: c_int = 0x00000400; +pub const IFF_SIMPLEX: c_int = 0x00000800; +pub const IHFLOW: tcflag_t = 0x00000001; +pub const IIDLE: tcflag_t = 0x00000008; +pub const IP_RECVDSTADDR: c_int = 7; +pub const IP_RECVIF: c_int = 20; +pub const IPTOS_ECN_NOTECT: u8 = 0x00; +pub const IUCLC: tcflag_t = 0x00000200; +pub const IUTF8: tcflag_t = 0x0004000; + +pub const KERN_ARGMAX: c_int = 8; +pub const KERN_BOOTTIME: c_int = 21; +pub const KERN_CLOCKRATE: c_int = 12; +pub const KERN_FILE: c_int = 15; +pub const KERN_HOSTID: c_int = 11; +pub const KERN_HOSTNAME: c_int = 10; +pub const KERN_JOB_CONTROL: c_int = 19; +pub const KERN_MAXFILES: c_int = 7; +pub const KERN_MAXPROC: c_int = 6; +pub const KERN_MAXVNODES: c_int = 5; +pub const KERN_NGROUPS: c_int = 18; +pub const KERN_OSRELEASE: c_int = 2; +pub const KERN_OSREV: c_int = 3; +pub const KERN_OSTYPE: c_int = 1; +pub const KERN_POSIX1: c_int = 17; +pub const KERN_PROC: c_int = 14; +pub const KERN_PROC_ALL: c_int = 0; +pub const KERN_PROC_PGRP: c_int = 2; +pub const KERN_PROC_PID: c_int = 1; +pub const KERN_PROC_RUID: c_int = 6; +pub const KERN_PROC_SESSION: c_int = 3; +pub const KERN_PROC_TTY: c_int = 4; +pub const KERN_PROC_UID: c_int = 5; +pub const KERN_PROF: c_int = 16; +pub const KERN_SAVED_IDS: c_int = 20; +pub const KERN_SECURELVL: c_int = 9; +pub const KERN_VERSION: c_int = 4; +pub const KERN_VNODE: c_int = 13; + +pub const LC_ALL: c_int = 63; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MESSAGES: c_int = 32; +pub const LC_MONETARY: c_int = 4; +pub const LC_NUMERIC: c_int = 8; +pub const LC_TIME: c_int = 16; + +pub const MAP_STACK: c_int = 0x00001000; +pub const MNT_NOEXEC: c_int = 0x02; +pub const MNT_NOSUID: c_int = 0x04; +pub const MNT_RDONLY: c_int = 0x01; + +pub const NET_RT_DUMP: c_int = 1; +pub const NET_RT_FLAGS: c_int = 2; +pub const OHFLOW: tcflag_t = 0x00000002; +pub const P_ALL: idtype_t = 0; +pub const PARSTK: tcflag_t = 0x00000004; +pub const PF_CCITT: c_int = 10; +pub const PF_CHAOS: c_int = 5; +pub const PF_CNT: c_int = 21; +pub const PF_COIP: c_int = 20; +pub const PF_DATAKIT: c_int = 9; +pub const PF_DECnet: c_int = 12; +pub const PF_DLI: c_int = 13; +pub const PF_ECMA: c_int = 8; +pub const PF_HYLINK: c_int = 15; +pub const PF_IMPLINK: c_int = 3; +pub const PF_ISO: c_int = 7; +pub const PF_LAT: c_int = 14; +pub const PF_LINK: c_int = 18; +pub const PF_OSI: c_int = 7; +pub const PF_PIP: c_int = 25; +pub const PF_PUP: c_int = 4; +pub const PF_RTIP: c_int = 22; +pub const PF_XTP: c_int = 19; +pub const PM_STR: crate::nl_item = 7; +pub const POSIX_MADV_DONTNEED: c_int = 4; +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 2; +pub const POSIX_MADV_SEQUENTIAL: c_int = 1; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const _POSIX_VDISABLE: c_int = 0; +pub const P_PGID: idtype_t = 2; +pub const P_PID: idtype_t = 1; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_USER: c_int = 2; +pub const pseudo_AF_PIP: c_int = 25; +pub const pseudo_AF_RTIP: c_int = 22; +pub const pseudo_AF_XTP: c_int = 19; +pub const REG_ASSERT: c_int = 15; +pub const REG_ATOI: c_int = 255; +pub const REG_BACKR: c_int = 0x400; +pub const REG_BASIC: c_int = 0x00; +pub const REG_DUMP: c_int = 0x80; +pub const REG_EMPTY: c_int = 14; +pub const REG_INVARG: c_int = 16; +pub const REG_ITOA: c_int = 0o400; +pub const REG_LARGE: c_int = 0x200; +pub const REG_NOSPEC: c_int = 0x10; +pub const REG_OK: c_int = 0; +pub const REG_PEND: c_int = 0x20; +pub const REG_TRACE: c_int = 0x100; + +pub const RLIMIT_AS: c_int = 6; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_MEMLOCK: c_int = 7; +pub const RLIMIT_NOFILE: c_int = 5; +pub const RLIMIT_NPROC: c_int = 8; +pub const RLIMIT_RSS: c_int = 6; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_VMEM: c_int = 6; +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: c_int = 14; + +pub const SCHED_ADJTOHEAD: c_int = 5; +pub const SCHED_ADJTOTAIL: c_int = 6; +pub const SCHED_MAXPOLICY: c_int = 7; +pub const SCHED_SETPRIO: c_int = 7; +pub const SCHED_SPORADIC: c_int = 4; + +pub const SHM_ANON: *mut c_char = -1isize as *mut c_char; +pub const SIGCLD: c_int = SIGCHLD; +pub const SIGDEADLK: c_int = 7; +pub const SIGEMT: c_int = 7; +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 129; +pub const SIGEV_THREAD: c_int = 135; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const _SS_ALIGNSIZE: usize = size_of::(); +pub const _SS_MAXSIZE: usize = 128; +pub const _SS_PAD1SIZE: usize = _SS_ALIGNSIZE - 2; +pub const _SS_PAD2SIZE: usize = _SS_MAXSIZE - 2 - _SS_PAD1SIZE - _SS_ALIGNSIZE; +pub const TC_CPOSIX: tcflag_t = CLOCAL | CREAD | CSIZE | CSTOPB | HUPCL | PARENB | PARODD; +pub const TCGETS: c_int = 0x404c540d; +pub const TC_IPOSIX: tcflag_t = + BRKINT | ICRNL | IGNBRK | IGNPAR | INLCR | INPCK | ISTRIP | IXOFF | IXON | PARMRK; +pub const TC_LPOSIX: tcflag_t = + ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN | ISIG | NOFLSH | TOSTOP; +pub const TC_OPOSIX: tcflag_t = OPOST; +pub const T_FMT_AMPM: crate::nl_item = 5; + +pub const TIOCCBRK: c_int = 29818; +pub const TIOCCDTR: c_int = 29816; +pub const TIOCDRAIN: c_int = 29790; +pub const TIOCEXCL: c_int = 29709; +pub const TIOCFLUSH: c_int = -2147191792; +pub const TIOCGETA: c_int = 1078752275; +pub const TIOCGPGRP: c_int = 1074033783; +pub const TIOCGWINSZ: c_int = 1074295912; +pub const TIOCMBIC: c_int = -2147191701; +pub const TIOCMBIS: c_int = -2147191700; +pub const TIOCMGET: c_int = 1074033770; +pub const TIOCMSET: c_int = -2147191699; +pub const TIOCNOTTY: c_int = 29809; +pub const TIOCNXCL: c_int = 29710; +pub const TIOCOUTQ: c_int = 1074033779; +pub const TIOCPKT: c_int = -2147191696; +pub const TIOCPKT_DATA: c_int = 0x00; +pub const TIOCPKT_DOSTOP: c_int = 0x20; +pub const TIOCPKT_FLUSHREAD: c_int = 0x01; +pub const TIOCPKT_FLUSHWRITE: c_int = 0x02; +pub const TIOCPKT_IOCTL: c_int = 0x40; +pub const TIOCPKT_NOSTOP: c_int = 0x10; +pub const TIOCPKT_START: c_int = 0x08; +pub const TIOCPKT_STOP: c_int = 0x04; +pub const TIOCSBRK: c_int = 29819; +pub const TIOCSCTTY: c_int = 29793; +pub const TIOCSDTR: c_int = 29817; +pub const TIOCSETA: c_int = -2142473196; +pub const TIOCSETAF: c_int = -2142473194; +pub const TIOCSETAW: c_int = -2142473195; +pub const TIOCSPGRP: c_int = -2147191690; +pub const TIOCSTART: c_int = 29806; +pub const TIOCSTI: c_int = -2147388302; +pub const TIOCSTOP: c_int = 29807; +pub const TIOCSWINSZ: c_int = -2146929561; + +pub const USER_CS_PATH: c_int = 1; +pub const USER_BC_BASE_MAX: c_int = 2; +pub const USER_BC_DIM_MAX: c_int = 3; +pub const USER_BC_SCALE_MAX: c_int = 4; +pub const USER_BC_STRING_MAX: c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: c_int = 6; +pub const USER_EXPR_NEST_MAX: c_int = 7; +pub const USER_LINE_MAX: c_int = 8; +pub const USER_RE_DUP_MAX: c_int = 9; +pub const USER_POSIX2_VERSION: c_int = 10; +pub const USER_POSIX2_C_BIND: c_int = 11; +pub const USER_POSIX2_C_DEV: c_int = 12; +pub const USER_POSIX2_CHAR_TERM: c_int = 13; +pub const USER_POSIX2_FORT_DEV: c_int = 14; +pub const USER_POSIX2_FORT_RUN: c_int = 15; +pub const USER_POSIX2_LOCALEDEF: c_int = 16; +pub const USER_POSIX2_SW_DEV: c_int = 17; +pub const USER_POSIX2_UPE: c_int = 18; +pub const USER_STREAM_MAX: c_int = 19; +pub const USER_TZNAME_MAX: c_int = 20; + +pub const VDOWN: usize = 31; +pub const VINS: usize = 32; +pub const VDEL: usize = 33; +pub const VRUB: usize = 34; +pub const VCAN: usize = 35; +pub const VHOME: usize = 36; +pub const VEND: usize = 37; +pub const VSPARE3: usize = 38; +pub const VSPARE4: usize = 39; +pub const VSWTCH: usize = 7; +pub const VDSUSP: usize = 11; +pub const VFWD: usize = 18; +pub const VLOGIN: usize = 19; +pub const VPREFIX: usize = 20; +pub const VSUFFIX: usize = 24; +pub const VLEFT: usize = 28; +pub const VRIGHT: usize = 29; +pub const VUP: usize = 30; +pub const XCASE: tcflag_t = 0x00000004; + +pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1; +pub const PTHREAD_CREATE_JOINABLE: c_int = 0x00; +pub const PTHREAD_CREATE_DETACHED: c_int = 0x01; + +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_NORMAL: c_int = 3; +pub const PTHREAD_STACK_MIN: size_t = 256; +pub const PTHREAD_MUTEX_DEFAULT: c_int = 0; +pub const PTHREAD_MUTEX_STALLED: c_int = 0x00; +pub const PTHREAD_MUTEX_ROBUST: c_int = 0x10; +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0x00; +pub const PTHREAD_PROCESS_SHARED: c_int = 0x01; + +pub const PTHREAD_KEYS_MAX: usize = 128; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __u: 0x80000000, + __owner: 0xffffffff, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __u: CLOCK_REALTIME as u32, + __owner: 0xfffffffb, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __active: 0, + __blockedwriters: 0, + __blockedreaders: 0, + __heavy: 0, + __lock: PTHREAD_MUTEX_INITIALIZER, + __rcond: PTHREAD_COND_INITIALIZER, + __wcond: PTHREAD_COND_INITIALIZER, + __owner: -2i32 as c_uint, + __spare: 0, +}; + +const fn _CMSG_ALIGN(len: usize) -> usize { + len + size_of::() - 1 & !(size_of::() - 1) +} + +const fn _ALIGN(p: usize, b: usize) -> usize { + (p + b - 1) & !(b - 1) +} + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= size_of::() { + (*mhdr).msg_control as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + let msg = _CMSG_ALIGN((*cmsg).cmsg_len as usize); + let next = cmsg as usize + msg + _CMSG_ALIGN(size_of::()); + if next > (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize { + core::ptr::null_mut::() + } else { + (cmsg as usize + msg) as *mut cmsghdr + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(_CMSG_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + _CMSG_ALIGN(size_of::()) as c_uint + length + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (_CMSG_ALIGN(size_of::()) + _CMSG_ALIGN(length as usize)) as c_uint + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn _DEXTRA_FIRST(_d: *const dirent) -> *mut crate::dirent_extra { + let _f = &((*(_d)).d_name) as *const _; + let _s = _d as usize; + + _ALIGN(_s + _f as usize - _s + (*_d).d_namelen as usize + 1, 8) as *mut crate::dirent_extra + } + + pub fn _DEXTRA_VALID(_x: *const crate::dirent_extra, _d: *const dirent) -> bool { + let sz = _x as usize - _d as usize + size_of::(); + let rsz = (*_d).d_reclen as usize; + + if sz > rsz || sz + (*_x).d_datalen as usize > rsz { + false + } else { + true + } + } + + pub fn _DEXTRA_NEXT(_x: *const crate::dirent_extra) -> *mut crate::dirent_extra { + _ALIGN( + _x as usize + size_of::() + (*_x).d_datalen as usize, + 8, + ) as *mut crate::dirent_extra + } + + pub fn SOCKCREDSIZE(ngrps: usize) -> usize { + let ngrps = if ngrps > 0 { ngrps - 1 } else { 0 }; + size_of::() + size_of::() * ngrps + } +} + +safe_f! { + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0x7f) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn IPTOS_ECN(x: u8) -> u8 { + x & crate::IPTOS_ECN_MASK + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + ((major << 10) | (minor)) as crate::dev_t + } + + pub const fn major(dev: crate::dev_t) -> c_uint { + ((dev as c_uint) >> 10) & 0x3f + } + + pub const fn minor(dev: crate::dev_t) -> c_uint { + (dev as c_uint) & 0x3ff + } +} + +cfg_if! { + if #[cfg(not(target_env = "nto71_iosock"))] { + extern "C" { + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + ) -> c_int; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: c_uint, + flags: c_uint, + timeout: *mut crate::timespec, + ) -> c_int; + } + } else { + extern "C" { + pub fn sendmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: size_t, + flags: c_int, + ) -> ssize_t; + pub fn recvmmsg( + sockfd: c_int, + msgvec: *mut crate::mmsghdr, + vlen: size_t, + flags: c_int, + timeout: *const crate::timespec, + ) -> ssize_t; + } + } +} + +// Network related functions are provided by libsocket and regex +// functions are provided by libregex. +// In QNX <=7.0, libregex functions were included in libc itself. +#[link(name = "socket")] +#[cfg_attr(not(target_env = "nto70"), link(name = "regex"))] +extern "C" { + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn mknodat(__fd: c_int, pathname: *const c_char, mode: mode_t, dev: crate::dev_t) -> c_int; + + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn clock_getcpuclockid(pid: crate::pid_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + pub fn setgroups(ngroups: c_int, ptr: *const crate::gid_t) -> c_int; + + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + val: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, val: c_int) -> c_int; + pub fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> *mut c_char; + pub fn clearenv() -> c_int; + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + pub fn wait4( + pid: crate::pid_t, + status: *mut c_int, + options: c_int, + rusage: *mut crate::rusage, + ) -> crate::pid_t; + + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn execvpe( + file: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + pub fn forkpty( + amaster: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; + pub fn login_tty(fd: c_int) -> c_int; + + pub fn uname(buf: *mut crate::utsname) -> c_int; + + pub fn getpeereid(socket: c_int, euid: *mut crate::uid_t, egid: *mut crate::gid_t) -> c_int; + + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + pub fn setspent(); + pub fn endspent(); + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + + pub fn ftok(pathname: *const c_char, proj_id: c_int) -> crate::key_t; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwaitinfo(set: *const sigset_t, info: *mut siginfo_t) -> c_int; + pub fn pthread_setschedprio(native: crate::pthread_t, priority: c_int) -> c_int; + + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + + pub fn getdomainname(name: *mut c_char, len: size_t) -> c_int; + pub fn setdomainname(name: *const c_char, len: size_t) -> c_int; + pub fn sync(); + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + pub fn umount(target: *const c_char, flags: c_int) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn settimeofday(tv: *const crate::timeval, tz: *const c_void) -> c_int; + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + pub fn mount( + special_device: *const c_char, + mount_directory: *const c_char, + flags: c_int, + mount_type: *const c_char, + mount_data: *const c_void, + mount_datalen: c_int, + ) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + pub fn pthread_mutex_consistent(mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_spin_init(lock: *mut crate::pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut crate::pthread_spinlock_t) -> c_int; + pub fn pthread_barrierattr_init(__attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_destroy(__attr: *mut crate::pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_getpshared( + __attr: *const crate::pthread_barrierattr_t, + __pshared: *mut c_int, + ) -> c_int; + pub fn pthread_barrierattr_setpshared( + __attr: *mut crate::pthread_barrierattr_t, + __pshared: c_int, + ) -> c_int; + pub fn pthread_barrier_init( + __barrier: *mut crate::pthread_barrier_t, + __attr: *const crate::pthread_barrierattr_t, + __count: c_uint, + ) -> c_int; + pub fn pthread_barrier_destroy(__barrier: *mut crate::pthread_barrier_t) -> c_int; + pub fn pthread_barrier_wait(__barrier: *mut crate::pthread_barrier_t) -> c_int; + + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + pub fn pthread_attr_getguardsize( + attr: *const crate::pthread_attr_t, + guardsize: *mut size_t, + ) -> c_int; + pub fn pthread_attr_setguardsize(attr: *mut crate::pthread_attr_t, guardsize: size_t) -> c_int; + pub fn sethostname(name: *const c_char, len: size_t) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn initgroups(user: *const c_char, group: crate::gid_t) -> c_int; + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_getrobust( + attr: *const pthread_mutexattr_t, + robustness: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robustness: c_int) -> c_int; + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn getitimer(which: c_int, curr_value: *mut crate::itimerval) -> c_int; + pub fn setitimer( + which: c_int, + value: *const crate::itimerval, + ovalue: *mut crate::itimerval, + ) -> c_int; + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const crate::posix_spawn_file_actions_t, + attrp: *const crate::posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + default: *mut crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + default: *const crate::sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + flags: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, flags: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + flags: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, flags: c_int) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: c_int, + newfd: c_int, + ) -> c_int; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn inotify_rm_watch(fd: c_int, wd: c_int) -> c_int; + pub fn inotify_init() -> c_int; + pub fn inotify_add_watch(fd: c_int, path: *const c_char, mask: u32) -> c_int; + + pub fn gettid() -> crate::pid_t; + + pub fn pthread_getcpuclockid(thread: crate::pthread_t, clk_id: *mut crate::clockid_t) -> c_int; + + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + + pub fn mallopt(param: c_int, value: i64) -> c_int; + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + + pub fn ctermid(s: *mut c_char) -> *mut c_char; + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + + pub fn mallinfo() -> crate::mallinfo; + pub fn getpwent_r( + pwd: *mut crate::passwd, + buf: *mut c_char, + __bufsize: c_int, + __result: *mut *mut crate::passwd, + ) -> c_int; + pub fn pthread_getname_np(thread: crate::pthread_t, name: *mut c_char, len: c_int) -> c_int; + pub fn pthread_setname_np(thread: crate::pthread_t, name: *const c_char) -> c_int; + + pub fn sysctl( + _: *const c_int, + _: c_uint, + _: *mut c_void, + _: *mut size_t, + _: *const c_void, + _: size_t, + ) -> c_int; + + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlp: *const crate::rlimit) -> c_int; + + pub fn lio_listio( + __mode: c_int, + __list: *const *mut aiocb, + __nent: c_int, + __sig: *mut sigevent, + ) -> c_int; + + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn( + // The original .h file declares this as *const, but for consistency with other platforms, + // changing this to *mut to make it easier to use. + // Maybe in v0.3 all platforms should use this as a *const. + info: *mut dl_phdr_info, + size: size_t, + data: *mut c_void, + ) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + + pub fn memset_s(s: *mut c_void, smax: size_t, c: c_int, n: size_t) -> c_int; + + pub fn regcomp(__preg: *mut crate::regex_t, __pattern: *const c_char, __cflags: c_int) + -> c_int; + pub fn regexec( + __preg: *const crate::regex_t, + __str: *const c_char, + __nmatch: size_t, + __pmatch: *mut crate::regmatch_t, + __eflags: c_int, + ) -> c_int; + pub fn regerror( + __errcode: c_int, + __preg: *const crate::regex_t, + __errbuf: *mut c_char, + __errbuf_size: size_t, + ) -> size_t; + pub fn regfree(__preg: *mut crate::regex_t); + pub fn dirfd(__dirp: *mut crate::DIR) -> c_int; + pub fn dircntl(dir: *mut crate::DIR, cmd: c_int, ...) -> c_int; + + pub fn aio_cancel(__fd: c_int, __aiocbp: *mut crate::aiocb) -> c_int; + pub fn aio_error(__aiocbp: *const crate::aiocb) -> c_int; + pub fn aio_fsync(__operation: c_int, __aiocbp: *mut crate::aiocb) -> c_int; + pub fn aio_read(__aiocbp: *mut crate::aiocb) -> c_int; + pub fn aio_return(__aiocpb: *mut crate::aiocb) -> ssize_t; + pub fn aio_suspend( + __list: *const *const crate::aiocb, + __nent: c_int, + __timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_write(__aiocpb: *mut crate::aiocb) -> c_int; + + pub fn mq_close(__mqdes: crate::mqd_t) -> c_int; + pub fn mq_getattr(__mqdes: crate::mqd_t, __mqstat: *mut crate::mq_attr) -> c_int; + pub fn mq_notify(__mqdes: crate::mqd_t, __notification: *const crate::sigevent) -> c_int; + pub fn mq_open(__name: *const c_char, __oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_receive( + __mqdes: crate::mqd_t, + __msg_ptr: *mut c_char, + __msg_len: size_t, + __msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_send( + __mqdes: crate::mqd_t, + __msg_ptr: *const c_char, + __msg_len: size_t, + __msg_prio: c_uint, + ) -> c_int; + pub fn mq_setattr( + __mqdes: crate::mqd_t, + __mqstat: *const mq_attr, + __omqstat: *mut mq_attr, + ) -> c_int; + pub fn mq_timedreceive( + __mqdes: crate::mqd_t, + __msg_ptr: *mut c_char, + __msg_len: size_t, + __msg_prio: *mut c_uint, + __abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_timedsend( + __mqdes: crate::mqd_t, + __msg_ptr: *const c_char, + __msg_len: size_t, + __msg_prio: c_uint, + __abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_unlink(__name: *const c_char) -> c_int; + pub fn __get_errno_ptr() -> *mut c_int; + + // System page, see https://www.qnx.com/developers/docs/7.1#com.qnx.doc.neutrino.building/topic/syspage/syspage_about.html + pub static mut _syspage_ptr: *mut syspage_entry; + + // Function on the stack after a call to pthread_create(). This is used + // as a sentinel to work around an infitnite loop in the unwinding code. + pub fn __my_thread_exit(value_ptr: *mut *const c_void); +} + +// Models the implementation in stdlib.h. Ctest will fail if trying to use the +// default symbol from libc +pub unsafe fn atexit(cb: extern "C" fn()) -> c_int { + extern "C" { + static __dso_handle: *mut c_void; + pub fn __cxa_atexit(cb: extern "C" fn(), __arg: *mut c_void, __dso: *mut c_void) -> c_int; + } + __cxa_atexit(cb, 0 as *mut c_void, __dso_handle) +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_si_addr { + _pad: Padding<[u8; 32]>, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_si_addr)).si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + #[repr(C)] + struct siginfo_si_value { + _pad: Padding<[u8; 32]>, + si_value: crate::sigval, + } + (*(self as *const siginfo_t as *const siginfo_si_value)).si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + #[repr(C)] + struct siginfo_si_pid { + _pad: Padding<[u8; 16]>, + si_pid: crate::pid_t, + } + (*(self as *const siginfo_t as *const siginfo_si_pid)).si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + #[repr(C)] + struct siginfo_si_uid { + _pad: Padding<[u8; 24]>, + si_uid: crate::uid_t, + } + (*(self as *const siginfo_t as *const siginfo_si_uid)).si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + #[repr(C)] + struct siginfo_si_status { + _pad: Padding<[u8; 28]>, + si_status: c_int, + } + (*(self as *const siginfo_t as *const siginfo_si_status)).si_status + } +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + panic!("Unsupported arch"); + } +} + +mod neutrino; +pub use self::neutrino::*; diff --git a/deps/crates/vendor/libc/src/unix/nto/neutrino.rs b/deps/crates/vendor/libc/src/unix/nto/neutrino.rs new file mode 100644 index 00000000000000..4c3fca1431f5d9 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/nto/neutrino.rs @@ -0,0 +1,1270 @@ +use crate::prelude::*; + +pub type nto_job_t = crate::sync_t; + +s! { + pub struct syspage_entry_info { + pub entry_off: u16, + pub entry_size: u16, + } + pub struct syspage_array_info { + entry_off: u16, + entry_size: u16, + element_size: u16, + } + + pub struct intrspin { + pub value: c_uint, // volatile + } + + pub struct iov_t { + pub iov_base: *mut c_void, // union + pub iov_len: size_t, + } + + pub struct _itimer { + pub nsec: u64, + pub interval_nsec: u64, + } + + pub struct _msg_info64 { + pub nd: u32, + pub srcnd: u32, + pub pid: crate::pid_t, + pub tid: i32, + pub chid: i32, + pub scoid: i32, + pub coid: i32, + pub priority: i16, + pub flags: i16, + pub msglen: isize, + pub srcmsglen: isize, + pub dstmsglen: isize, + pub type_id: u32, + reserved: Padding, + } + + pub struct _cred_info { + pub ruid: crate::uid_t, + pub euid: crate::uid_t, + pub suid: crate::uid_t, + pub rgid: crate::gid_t, + pub egid: crate::gid_t, + pub sgid: crate::gid_t, + pub ngroups: u32, + pub grouplist: [crate::gid_t; 8], + } + + pub struct _client_info { + pub nd: u32, + pub pid: crate::pid_t, + pub sid: crate::pid_t, + pub flags: u32, + pub cred: crate::_cred_info, + } + + pub struct _client_able { + pub ability: u32, + pub flags: u32, + pub range_lo: u64, + pub range_hi: u64, + } + + pub struct nto_channel_config { + pub event: crate::sigevent, + pub num_pulses: c_uint, + pub rearm_threshold: c_uint, + pub options: c_uint, + reserved: Padding<[c_uint; 3]>, + } + + // TODO: The following structures are defined in a header file which doesn't + // appear as part of the default headers found in a standard installation + // of Neutrino 7.1 SDP. Commented out for now. + //pub struct _asyncmsg_put_header { + // pub err: c_int, + // pub iov: *mut crate::iov_t, + // pub parts: c_int, + // pub handle: c_uint, + // pub cb: Option< + // unsafe extern "C" fn( + // err: c_int, + // buf: *mut c_void, + // handle: c_uint, + // ) -> c_int>, + // pub put_hdr_flags: c_uint, + //} + + //pub struct _asyncmsg_connection_attr { + // pub call_back: Option< + // unsafe extern "C" fn( + // err: c_int, + // buff: *mut c_void, + // handle: c_uint, + // ) -> c_int>, + // pub buffer_size: size_t, + // pub max_num_buffer: c_uint, + // pub trigger_num_msg: c_uint, + // pub trigger_time: crate::_itimer, + // reserve: Padding, + //} + + //pub struct _asyncmsg_connection_descriptor { + // pub flags: c_uint, + // pub sendq_size: c_uint, + // pub sendq_head: c_uint, + // pub sendq_tail: c_uint, + // pub sendq_free: c_uint, + // pub err: c_int, + // pub ev: crate::sigevent, + // pub num_curmsg: c_uint, + // pub ttimer: crate::timer_t, + // pub block_con: crate::pthread_cond_t, + // pub mu: crate::pthread_mutex_t, + // reserved: Padding, + // pub attr: crate::_asyncmsg_connection_attr, + // reserves: Padding<[c_uint; 3]>, + // pub sendq: [crate::_asyncmsg_put_header; 1], // flexarray + //} + + pub struct __c_anonymous_struct_ev { + pub event: crate::sigevent, + pub coid: c_int, + } + + pub struct _channel_connect_attr { + // union + pub ev: crate::__c_anonymous_struct_ev, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct _sighandler_info { + pub siginfo: crate::siginfo_t, + pub handler: Option, + pub context: *mut c_void, + } + + pub struct __c_anonymous_struct_time { + pub length: c_uint, + pub scale: c_uint, + } + + pub struct _idle_hook { + pub hook_size: c_uint, + pub cmd: c_uint, + pub mode: c_uint, + pub latency: c_uint, + pub next_fire: u64, + pub curr_time: u64, + pub tod_adjust: u64, + pub resp: c_uint, + pub time: __c_anonymous_struct_time, + pub trigger: crate::sigevent, + pub intrs: *mut c_uint, + pub block_stack_size: c_uint, + } + + pub struct _clockadjust { + pub tick_count: u32, + pub tick_nsec_inc: i32, + } + + pub struct qtime_entry { + pub cycles_per_sec: u64, + pub nsec_tod_adjust: u64, // volatile + pub nsec: u64, // volatile + pub nsec_inc: u32, + pub boot_time: u32, + pub adjust: _clockadjust, + pub timer_rate: u32, + pub timer_scale: i32, + pub timer_load: u32, + pub intr: i32, + pub epoch: u32, + pub flags: u32, + pub rr_interval_mul: u32, + pub timer_load_hi: u32, + pub nsec_stable: u64, // volatile + pub timer_load_max: u64, + pub timer_prog_time: u32, + spare: [u32; 7], + } + + pub struct _sched_info { + pub priority_min: c_int, + pub priority_max: c_int, + pub interval: u64, + pub priority_priv: c_int, + reserved: Padding<[c_int; 11]>, + } + + pub struct _timer_info { + pub itime: crate::_itimer, + pub otime: crate::_itimer, + pub flags: u32, + pub tid: i32, + pub notify: i32, + pub clockid: crate::clockid_t, + pub overruns: u32, + pub event: crate::sigevent, // union + } + + pub struct _clockperiod { + pub nsec: u32, + pub fract: i32, + } +} + +s_no_extra_traits! { + #[repr(align(8))] + pub struct syspage_entry { + pub size: u16, + pub total_size: u16, + pub type_: u16, + pub num_cpu: u16, + pub system_private: syspage_entry_info, + pub old_asinfo: syspage_entry_info, + pub __mangle_name_to_cause_compilation_errs_meminfo: syspage_entry_info, + pub hwinfo: syspage_entry_info, + pub old_cpuinfo: syspage_entry_info, + pub old_cacheattr: syspage_entry_info, + pub qtime: syspage_entry_info, + pub callout: syspage_entry_info, + pub callin: syspage_entry_info, + pub typed_strings: syspage_entry_info, + pub strings: syspage_entry_info, + pub old_intrinfo: syspage_entry_info, + pub smp: syspage_entry_info, + pub pminfo: syspage_entry_info, + pub old_mdriver: syspage_entry_info, + spare0: [u32; 1], + __reserved: Padding<[u8; 160]>, // anonymous union with architecture dependent structs + pub new_asinfo: syspage_array_info, + pub new_cpuinfo: syspage_array_info, + pub new_cacheattr: syspage_array_info, + pub new_intrinfo: syspage_array_info, + pub new_mdriver: syspage_array_info, + } +} + +pub const SYSMGR_PID: u32 = 1; +pub const SYSMGR_CHID: u32 = 1; +pub const SYSMGR_COID: u32 = _NTO_SIDE_CHANNEL; +pub const SYSMGR_HANDLE: u32 = 0; + +pub const STATE_DEAD: c_int = 0x00; +pub const STATE_RUNNING: c_int = 0x01; +pub const STATE_READY: c_int = 0x02; +pub const STATE_STOPPED: c_int = 0x03; +pub const STATE_SEND: c_int = 0x04; +pub const STATE_RECEIVE: c_int = 0x05; +pub const STATE_REPLY: c_int = 0x06; +pub const STATE_STACK: c_int = 0x07; +pub const STATE_WAITTHREAD: c_int = 0x08; +pub const STATE_WAITPAGE: c_int = 0x09; +pub const STATE_SIGSUSPEND: c_int = 0x0a; +pub const STATE_SIGWAITINFO: c_int = 0x0b; +pub const STATE_NANOSLEEP: c_int = 0x0c; +pub const STATE_MUTEX: c_int = 0x0d; +pub const STATE_CONDVAR: c_int = 0x0e; +pub const STATE_JOIN: c_int = 0x0f; +pub const STATE_INTR: c_int = 0x10; +pub const STATE_SEM: c_int = 0x11; +pub const STATE_WAITCTX: c_int = 0x12; +pub const STATE_NET_SEND: c_int = 0x13; +pub const STATE_NET_REPLY: c_int = 0x14; +pub const STATE_MAX: c_int = 0x18; + +pub const _NTO_TIMEOUT_RECEIVE: i32 = 1 << STATE_RECEIVE; +pub const _NTO_TIMEOUT_SEND: i32 = 1 << STATE_SEND; +pub const _NTO_TIMEOUT_REPLY: i32 = 1 << STATE_REPLY; +pub const _NTO_TIMEOUT_SIGSUSPEND: i32 = 1 << STATE_SIGSUSPEND; +pub const _NTO_TIMEOUT_SIGWAITINFO: i32 = 1 << STATE_SIGWAITINFO; +pub const _NTO_TIMEOUT_NANOSLEEP: i32 = 1 << STATE_NANOSLEEP; +pub const _NTO_TIMEOUT_MUTEX: i32 = 1 << STATE_MUTEX; +pub const _NTO_TIMEOUT_CONDVAR: i32 = 1 << STATE_CONDVAR; +pub const _NTO_TIMEOUT_JOIN: i32 = 1 << STATE_JOIN; +pub const _NTO_TIMEOUT_INTR: i32 = 1 << STATE_INTR; +pub const _NTO_TIMEOUT_SEM: i32 = 1 << STATE_SEM; + +pub const _NTO_MI_ENDIAN_BIG: u32 = 1; +pub const _NTO_MI_ENDIAN_DIFF: u32 = 2; +pub const _NTO_MI_UNBLOCK_REQ: u32 = 256; +pub const _NTO_MI_NET_CRED_DIRTY: u32 = 512; +pub const _NTO_MI_CONSTRAINED: u32 = 1024; +pub const _NTO_MI_CHROOT: u32 = 2048; +pub const _NTO_MI_BITS_64: u32 = 4096; +pub const _NTO_MI_BITS_DIFF: u32 = 8192; +pub const _NTO_MI_SANDBOX: u32 = 16384; + +pub const _NTO_CI_ENDIAN_BIG: u32 = 1; +pub const _NTO_CI_BKGND_PGRP: u32 = 4; +pub const _NTO_CI_ORPHAN_PGRP: u32 = 8; +pub const _NTO_CI_STOPPED: u32 = 128; +pub const _NTO_CI_UNABLE: u32 = 256; +pub const _NTO_CI_TYPE_ID: u32 = 512; +pub const _NTO_CI_CHROOT: u32 = 2048; +pub const _NTO_CI_BITS_64: u32 = 4096; +pub const _NTO_CI_SANDBOX: u32 = 16384; +pub const _NTO_CI_LOADER: u32 = 32768; +pub const _NTO_CI_FULL_GROUPS: u32 = 2147483648; + +pub const _NTO_TI_ACTIVE: u32 = 1; +pub const _NTO_TI_ABSOLUTE: u32 = 2; +pub const _NTO_TI_EXPIRED: u32 = 4; +pub const _NTO_TI_TOD_BASED: u32 = 8; +pub const _NTO_TI_TARGET_PROCESS: u32 = 16; +pub const _NTO_TI_REPORT_TOLERANCE: u32 = 32; +pub const _NTO_TI_PRECISE: u32 = 64; +pub const _NTO_TI_TOLERANT: u32 = 128; +pub const _NTO_TI_WAKEUP: u32 = 256; +pub const _NTO_TI_PROCESS_TOLERANT: u32 = 512; +pub const _NTO_TI_HIGH_RESOLUTION: u32 = 1024; + +pub const _PULSE_TYPE: u32 = 0; +pub const _PULSE_SUBTYPE: u32 = 0; +pub const _PULSE_CODE_UNBLOCK: i32 = -32; +pub const _PULSE_CODE_DISCONNECT: i32 = -33; +pub const _PULSE_CODE_THREADDEATH: i32 = -34; +pub const _PULSE_CODE_COIDDEATH: i32 = -35; +pub const _PULSE_CODE_NET_ACK: i32 = -36; +pub const _PULSE_CODE_NET_UNBLOCK: i32 = -37; +pub const _PULSE_CODE_NET_DETACH: i32 = -38; +pub const _PULSE_CODE_RESTART: i32 = -39; +pub const _PULSE_CODE_NORESTART: i32 = -40; +pub const _PULSE_CODE_UNBLOCK_RESTART: i32 = -41; +pub const _PULSE_CODE_UNBLOCK_TIMER: i32 = -42; +pub const _PULSE_CODE_MINAVAIL: u32 = 0; +pub const _PULSE_CODE_MAXAVAIL: u32 = 127; + +pub const _NTO_HARD_FLAGS_END: u32 = 1; + +pub const _NTO_PULSE_IF_UNIQUE: u32 = 4096; +pub const _NTO_PULSE_REPLACE: u32 = 8192; + +pub const _NTO_PF_NOCLDSTOP: u32 = 1; +pub const _NTO_PF_LOADING: u32 = 2; +pub const _NTO_PF_TERMING: u32 = 4; +pub const _NTO_PF_ZOMBIE: u32 = 8; +pub const _NTO_PF_NOZOMBIE: u32 = 16; +pub const _NTO_PF_FORKED: u32 = 32; +pub const _NTO_PF_ORPHAN_PGRP: u32 = 64; +pub const _NTO_PF_STOPPED: u32 = 128; +pub const _NTO_PF_DEBUG_STOPPED: u32 = 256; +pub const _NTO_PF_BKGND_PGRP: u32 = 512; +pub const _NTO_PF_NOISYNC: u32 = 1024; +pub const _NTO_PF_CONTINUED: u32 = 2048; +pub const _NTO_PF_CHECK_INTR: u32 = 4096; +pub const _NTO_PF_COREDUMP: u32 = 8192; +pub const _NTO_PF_RING0: u32 = 32768; +pub const _NTO_PF_SLEADER: u32 = 65536; +pub const _NTO_PF_WAITINFO: u32 = 131072; +pub const _NTO_PF_DESTROYALL: u32 = 524288; +pub const _NTO_PF_NOCOREDUMP: u32 = 1048576; +pub const _NTO_PF_WAITDONE: u32 = 4194304; +pub const _NTO_PF_TERM_WAITING: u32 = 8388608; +pub const _NTO_PF_ASLR: u32 = 16777216; +pub const _NTO_PF_EXECED: u32 = 33554432; +pub const _NTO_PF_APP_STOPPED: u32 = 67108864; +pub const _NTO_PF_64BIT: u32 = 134217728; +pub const _NTO_PF_NET: u32 = 268435456; +pub const _NTO_PF_NOLAZYSTACK: u32 = 536870912; +pub const _NTO_PF_NOEXEC_STACK: u32 = 1073741824; +pub const _NTO_PF_LOADER_PERMS: u32 = 2147483648; + +pub const _NTO_TF_INTR_PENDING: u32 = 65536; +pub const _NTO_TF_DETACHED: u32 = 131072; +pub const _NTO_TF_SHR_MUTEX: u32 = 262144; +pub const _NTO_TF_SHR_MUTEX_EUID: u32 = 524288; +pub const _NTO_TF_THREADS_HOLD: u32 = 1048576; +pub const _NTO_TF_UNBLOCK_REQ: u32 = 4194304; +pub const _NTO_TF_ALIGN_FAULT: u32 = 16777216; +pub const _NTO_TF_SSTEP: u32 = 33554432; +pub const _NTO_TF_ALLOCED_STACK: u32 = 67108864; +pub const _NTO_TF_NOMULTISIG: u32 = 134217728; +pub const _NTO_TF_LOW_LATENCY: u32 = 268435456; +pub const _NTO_TF_IOPRIV: u32 = 2147483648; + +pub const _NTO_TCTL_IO_PRIV: u32 = 1; +pub const _NTO_TCTL_THREADS_HOLD: u32 = 2; +pub const _NTO_TCTL_THREADS_CONT: u32 = 3; +pub const _NTO_TCTL_RUNMASK: u32 = 4; +pub const _NTO_TCTL_ALIGN_FAULT: u32 = 5; +pub const _NTO_TCTL_RUNMASK_GET_AND_SET: u32 = 6; +pub const _NTO_TCTL_PERFCOUNT: u32 = 7; +pub const _NTO_TCTL_ONE_THREAD_HOLD: u32 = 8; +pub const _NTO_TCTL_ONE_THREAD_CONT: u32 = 9; +pub const _NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT: u32 = 10; +pub const _NTO_TCTL_NAME: u32 = 11; +pub const _NTO_TCTL_RCM_GET_AND_SET: u32 = 12; +pub const _NTO_TCTL_SHR_MUTEX: u32 = 13; +pub const _NTO_TCTL_IO: u32 = 14; +pub const _NTO_TCTL_NET_KIF_GET_AND_SET: u32 = 15; +pub const _NTO_TCTL_LOW_LATENCY: u32 = 16; +pub const _NTO_TCTL_ADD_EXIT_EVENT: u32 = 17; +pub const _NTO_TCTL_DEL_EXIT_EVENT: u32 = 18; +pub const _NTO_TCTL_IO_LEVEL: u32 = 19; +pub const _NTO_TCTL_RESERVED: u32 = 2147483648; +pub const _NTO_TCTL_IO_LEVEL_INHERIT: u32 = 1073741824; +pub const _NTO_IO_LEVEL_NONE: u32 = 1; +pub const _NTO_IO_LEVEL_1: u32 = 2; +pub const _NTO_IO_LEVEL_2: u32 = 3; + +pub const _NTO_THREAD_NAME_MAX: u32 = 100; + +pub const _NTO_CHF_FIXED_PRIORITY: u32 = 1; +pub const _NTO_CHF_UNBLOCK: u32 = 2; +pub const _NTO_CHF_THREAD_DEATH: u32 = 4; +pub const _NTO_CHF_DISCONNECT: u32 = 8; +pub const _NTO_CHF_NET_MSG: u32 = 16; +pub const _NTO_CHF_SENDER_LEN: u32 = 32; +pub const _NTO_CHF_COID_DISCONNECT: u32 = 64; +pub const _NTO_CHF_REPLY_LEN: u32 = 128; +pub const _NTO_CHF_PULSE_POOL: u32 = 256; +pub const _NTO_CHF_ASYNC_NONBLOCK: u32 = 512; +pub const _NTO_CHF_ASYNC: u32 = 1024; +pub const _NTO_CHF_GLOBAL: u32 = 2048; +pub const _NTO_CHF_PRIVATE: u32 = 4096; +pub const _NTO_CHF_MSG_PAUSING: u32 = 8192; +pub const _NTO_CHF_INHERIT_RUNMASK: u32 = 16384; +pub const _NTO_CHF_UNBLOCK_TIMER: u32 = 32768; + +pub const _NTO_CHO_CUSTOM_EVENT: u32 = 1; + +pub const _NTO_COF_CLOEXEC: u32 = 1; +pub const _NTO_COF_DEAD: u32 = 2; +pub const _NTO_COF_NOSHARE: u32 = 64; +pub const _NTO_COF_NETCON: u32 = 128; +pub const _NTO_COF_NONBLOCK: u32 = 256; +pub const _NTO_COF_ASYNC: u32 = 512; +pub const _NTO_COF_GLOBAL: u32 = 1024; +pub const _NTO_COF_NOEVENT: u32 = 2048; +pub const _NTO_COF_INSECURE: u32 = 4096; +pub const _NTO_COF_REG_EVENTS: u32 = 8192; +pub const _NTO_COF_UNREG_EVENTS: u32 = 16384; +pub const _NTO_COF_MASK: u32 = 65535; + +pub const _NTO_SIDE_CHANNEL: u32 = 1073741824; + +pub const _NTO_CONNECTION_SCOID: u32 = 65536; +pub const _NTO_GLOBAL_CHANNEL: u32 = 1073741824; + +pub const _NTO_TIMEOUT_MASK: u32 = (1 << STATE_MAX) - 1; +pub const _NTO_TIMEOUT_ACTIVE: u32 = 1 << STATE_MAX; +pub const _NTO_TIMEOUT_IMMEDIATE: u32 = 1 << (STATE_MAX + 1); + +pub const _NTO_IC_LATENCY: u32 = 0; + +pub const _NTO_INTR_FLAGS_END: u32 = 1; +pub const _NTO_INTR_FLAGS_NO_UNMASK: u32 = 2; +pub const _NTO_INTR_FLAGS_PROCESS: u32 = 4; +pub const _NTO_INTR_FLAGS_TRK_MSK: u32 = 8; +pub const _NTO_INTR_FLAGS_ARRAY: u32 = 16; +pub const _NTO_INTR_FLAGS_EXCLUSIVE: u32 = 32; +pub const _NTO_INTR_FLAGS_FPU: u32 = 64; + +pub const _NTO_INTR_CLASS_EXTERNAL: u32 = 0; +pub const _NTO_INTR_CLASS_SYNTHETIC: u32 = 2147418112; + +pub const _NTO_INTR_SPARE: u32 = 2147483647; + +pub const _NTO_HOOK_IDLE: u32 = 2147418113; +pub const _NTO_HOOK_OVERDRIVE: u32 = 2147418114; +pub const _NTO_HOOK_LAST: u32 = 2147418114; +pub const _NTO_HOOK_IDLE2_FLAG: u32 = 32768; + +pub const _NTO_IH_CMD_SLEEP_SETUP: u32 = 1; +pub const _NTO_IH_CMD_SLEEP_BLOCK: u32 = 2; +pub const _NTO_IH_CMD_SLEEP_WAKEUP: u32 = 4; +pub const _NTO_IH_CMD_SLEEP_ONLINE: u32 = 8; +pub const _NTO_IH_RESP_NEEDS_BLOCK: u32 = 1; +pub const _NTO_IH_RESP_NEEDS_WAKEUP: u32 = 2; +pub const _NTO_IH_RESP_NEEDS_ONLINE: u32 = 4; +pub const _NTO_IH_RESP_SYNC_TIME: u32 = 16; +pub const _NTO_IH_RESP_SYNC_TLB: u32 = 32; +pub const _NTO_IH_RESP_SUGGEST_OFFLINE: u32 = 256; +pub const _NTO_IH_RESP_SLEEP_MODE_REACHED: u32 = 512; +pub const _NTO_IH_RESP_DELIVER_INTRS: u32 = 1024; + +pub const _NTO_READIOV_SEND: u32 = 0; +pub const _NTO_READIOV_REPLY: u32 = 1; + +pub const _NTO_KEYDATA_VTID: u32 = 2147483648; + +pub const _NTO_KEYDATA_PATHSIGN: u32 = 32768; +pub const _NTO_KEYDATA_OP_MASK: u32 = 255; +pub const _NTO_KEYDATA_VERIFY: u32 = 0; +pub const _NTO_KEYDATA_CALCULATE: u32 = 1; +pub const _NTO_KEYDATA_CALCULATE_REUSE: u32 = 2; +pub const _NTO_KEYDATA_PATHSIGN_VERIFY: u32 = 32768; +pub const _NTO_KEYDATA_PATHSIGN_CALCULATE: u32 = 32769; +pub const _NTO_KEYDATA_PATHSIGN_CALCULATE_REUSE: u32 = 32770; + +pub const _NTO_SCTL_SETPRIOCEILING: u32 = 1; +pub const _NTO_SCTL_GETPRIOCEILING: u32 = 2; +pub const _NTO_SCTL_SETEVENT: u32 = 3; +pub const _NTO_SCTL_MUTEX_WAKEUP: u32 = 4; +pub const _NTO_SCTL_MUTEX_CONSISTENT: u32 = 5; +pub const _NTO_SCTL_SEM_VALUE: u32 = 6; + +pub const _NTO_CLIENTINFO_GETGROUPS: u32 = 1; +pub const _NTO_CLIENTINFO_GETTYPEID: u32 = 2; + +extern "C" { + pub fn ChannelCreate(__flags: c_uint) -> c_int; + pub fn ChannelCreate_r(__flags: c_uint) -> c_int; + pub fn ChannelCreatePulsePool(__flags: c_uint, __config: *const nto_channel_config) -> c_int; + pub fn ChannelCreateExt( + __flags: c_uint, + __mode: crate::mode_t, + __bufsize: usize, + __maxnumbuf: c_uint, + __ev: *const crate::sigevent, + __cred: *mut _cred_info, + ) -> c_int; + pub fn ChannelDestroy(__chid: c_int) -> c_int; + pub fn ChannelDestroy_r(__chid: c_int) -> c_int; + pub fn ConnectAttach( + __nd: u32, + __pid: crate::pid_t, + __chid: c_int, + __index: c_uint, + __flags: c_int, + ) -> c_int; + pub fn ConnectAttach_r( + __nd: u32, + __pid: crate::pid_t, + __chid: c_int, + __index: c_uint, + __flags: c_int, + ) -> c_int; + + // TODO: The following function uses a structure defined in a header file + // which doesn't appear as part of the default headers found in a + // standard installation of Neutrino 7.1 SDP. Commented out for now. + //pub fn ConnectAttachExt( + // __nd: u32, + // __pid: crate::pid_t, + // __chid: c_int, + // __index: c_uint, + // __flags: c_int, + // __cd: *mut _asyncmsg_connection_descriptor, + //) -> c_int; + pub fn ConnectDetach(__coid: c_int) -> c_int; + pub fn ConnectDetach_r(__coid: c_int) -> c_int; + pub fn ConnectServerInfo(__pid: crate::pid_t, __coid: c_int, __info: *mut _msg_info64) + -> c_int; + pub fn ConnectServerInfo_r( + __pid: crate::pid_t, + __coid: c_int, + __info: *mut _msg_info64, + ) -> c_int; + pub fn ConnectClientInfoExtraArgs( + __scoid: c_int, + __info_pp: *mut _client_info, + __ngroups: c_int, + __abilities: *mut _client_able, + __nable: c_int, + __type_id: *mut c_uint, + ) -> c_int; + pub fn ConnectClientInfoExtraArgs_r( + __scoid: c_int, + __info_pp: *mut _client_info, + __ngroups: c_int, + __abilities: *mut _client_able, + __nable: c_int, + __type_id: *mut c_uint, + ) -> c_int; + pub fn ConnectClientInfo(__scoid: c_int, __info: *mut _client_info, __ngroups: c_int) -> c_int; + pub fn ConnectClientInfo_r( + __scoid: c_int, + __info: *mut _client_info, + __ngroups: c_int, + ) -> c_int; + pub fn ConnectClientInfoExt( + __scoid: c_int, + __info_pp: *mut *mut _client_info, + flags: c_int, + ) -> c_int; + pub fn ClientInfoExtFree(__info_pp: *mut *mut _client_info) -> c_int; + pub fn ConnectClientInfoAble( + __scoid: c_int, + __info_pp: *mut *mut _client_info, + flags: c_int, + abilities: *mut _client_able, + nable: c_int, + ) -> c_int; + pub fn ConnectFlags( + __pid: crate::pid_t, + __coid: c_int, + __mask: c_uint, + __bits: c_uint, + ) -> c_int; + pub fn ConnectFlags_r( + __pid: crate::pid_t, + __coid: c_int, + __mask: c_uint, + __bits: c_uint, + ) -> c_int; + pub fn ChannelConnectAttr( + __id: c_uint, + __old_attr: *mut _channel_connect_attr, + __new_attr: *mut _channel_connect_attr, + __flags: c_uint, + ) -> c_int; + pub fn MsgSend( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSend_r( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendnc( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendnc_r( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendsv( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendsv_r( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendsvnc( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendsvnc_r( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendvs( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendvs_r( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendvsnc( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendvsnc_r( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __rmsg: *mut c_void, + __rbytes: usize, + ) -> c_long; + pub fn MsgSendv( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendv_r( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendvnc( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgSendvnc_r( + __coid: c_int, + __siov: *const crate::iovec, + __sparts: usize, + __riov: *const crate::iovec, + __rparts: usize, + ) -> c_long; + pub fn MsgReceive( + __chid: c_int, + __msg: *mut c_void, + __bytes: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceive_r( + __chid: c_int, + __msg: *mut c_void, + __bytes: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivev( + __chid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivev_r( + __chid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivePulse( + __chid: c_int, + __pulse: *mut c_void, + __bytes: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivePulse_r( + __chid: c_int, + __pulse: *mut c_void, + __bytes: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivePulsev( + __chid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReceivePulsev_r( + __chid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __info: *mut _msg_info64, + ) -> c_int; + pub fn MsgReply( + __rcvid: c_int, + __status: c_long, + __msg: *const c_void, + __bytes: usize, + ) -> c_int; + pub fn MsgReply_r( + __rcvid: c_int, + __status: c_long, + __msg: *const c_void, + __bytes: usize, + ) -> c_int; + pub fn MsgReplyv( + __rcvid: c_int, + __status: c_long, + __iov: *const crate::iovec, + __parts: usize, + ) -> c_int; + pub fn MsgReplyv_r( + __rcvid: c_int, + __status: c_long, + __iov: *const crate::iovec, + __parts: usize, + ) -> c_int; + pub fn MsgReadiov( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + __flags: c_int, + ) -> isize; + pub fn MsgReadiov_r( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + __flags: c_int, + ) -> isize; + pub fn MsgRead(__rcvid: c_int, __msg: *mut c_void, __bytes: usize, __offset: usize) -> isize; + pub fn MsgRead_r(__rcvid: c_int, __msg: *mut c_void, __bytes: usize, __offset: usize) -> isize; + pub fn MsgReadv( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + ) -> isize; + pub fn MsgReadv_r( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + ) -> isize; + pub fn MsgWrite(__rcvid: c_int, __msg: *const c_void, __bytes: usize, __offset: usize) + -> isize; + pub fn MsgWrite_r( + __rcvid: c_int, + __msg: *const c_void, + __bytes: usize, + __offset: usize, + ) -> isize; + pub fn MsgWritev( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + ) -> isize; + pub fn MsgWritev_r( + __rcvid: c_int, + __iov: *const crate::iovec, + __parts: usize, + __offset: usize, + ) -> isize; + pub fn MsgSendPulse(__coid: c_int, __priority: c_int, __code: c_int, __value: c_int) -> c_int; + pub fn MsgSendPulse_r(__coid: c_int, __priority: c_int, __code: c_int, __value: c_int) + -> c_int; + pub fn MsgSendPulsePtr( + __coid: c_int, + __priority: c_int, + __code: c_int, + __value: *mut c_void, + ) -> c_int; + pub fn MsgSendPulsePtr_r( + __coid: c_int, + __priority: c_int, + __code: c_int, + __value: *mut c_void, + ) -> c_int; + pub fn MsgDeliverEvent(__rcvid: c_int, __event: *const crate::sigevent) -> c_int; + pub fn MsgDeliverEvent_r(__rcvid: c_int, __event: *const crate::sigevent) -> c_int; + pub fn MsgVerifyEvent(__rcvid: c_int, __event: *const crate::sigevent) -> c_int; + pub fn MsgVerifyEvent_r(__rcvid: c_int, __event: *const crate::sigevent) -> c_int; + pub fn MsgRegisterEvent(__event: *mut crate::sigevent, __coid: c_int) -> c_int; + pub fn MsgRegisterEvent_r(__event: *mut crate::sigevent, __coid: c_int) -> c_int; + pub fn MsgUnregisterEvent(__event: *const crate::sigevent) -> c_int; + pub fn MsgUnregisterEvent_r(__event: *const crate::sigevent) -> c_int; + pub fn MsgInfo(__rcvid: c_int, __info: *mut _msg_info64) -> c_int; + pub fn MsgInfo_r(__rcvid: c_int, __info: *mut _msg_info64) -> c_int; + pub fn MsgKeyData( + __rcvid: c_int, + __oper: c_int, + __key: u32, + __newkey: *mut u32, + __iov: *const crate::iovec, + __parts: c_int, + ) -> c_int; + pub fn MsgKeyData_r( + __rcvid: c_int, + __oper: c_int, + __key: u32, + __newkey: *mut u32, + __iov: *const crate::iovec, + __parts: c_int, + ) -> c_int; + pub fn MsgError(__rcvid: c_int, __err: c_int) -> c_int; + pub fn MsgError_r(__rcvid: c_int, __err: c_int) -> c_int; + pub fn MsgCurrent(__rcvid: c_int) -> c_int; + pub fn MsgCurrent_r(__rcvid: c_int) -> c_int; + pub fn MsgSendAsyncGbl( + __coid: c_int, + __smsg: *const c_void, + __sbytes: usize, + __msg_prio: c_uint, + ) -> c_int; + pub fn MsgSendAsync(__coid: c_int) -> c_int; + pub fn MsgReceiveAsyncGbl( + __chid: c_int, + __rmsg: *mut c_void, + __rbytes: usize, + __info: *mut _msg_info64, + __coid: c_int, + ) -> c_int; + pub fn MsgReceiveAsync(__chid: c_int, __iov: *const crate::iovec, __parts: c_uint) -> c_int; + pub fn MsgPause(__rcvid: c_int, __cookie: c_uint) -> c_int; + pub fn MsgPause_r(__rcvid: c_int, __cookie: c_uint) -> c_int; + + pub fn SignalKill( + __nd: u32, + __pid: crate::pid_t, + __tid: c_int, + __signo: c_int, + __code: c_int, + __value: c_int, + ) -> c_int; + pub fn SignalKill_r( + __nd: u32, + __pid: crate::pid_t, + __tid: c_int, + __signo: c_int, + __code: c_int, + __value: c_int, + ) -> c_int; + pub fn SignalKillSigval( + __nd: u32, + __pid: crate::pid_t, + __tid: c_int, + __signo: c_int, + __code: c_int, + __value: *const crate::sigval, + ) -> c_int; + pub fn SignalKillSigval_r( + __nd: u32, + __pid: crate::pid_t, + __tid: c_int, + __signo: c_int, + __code: c_int, + __value: *const crate::sigval, + ) -> c_int; + pub fn SignalReturn(__info: *mut _sighandler_info) -> c_int; + pub fn SignalFault(__sigcode: c_uint, __regs: *mut c_void, __refaddr: usize) -> c_int; + pub fn SignalAction( + __pid: crate::pid_t, + __sigstub: unsafe extern "C" fn(), + __signo: c_int, + __act: *const crate::sigaction, + __oact: *mut crate::sigaction, + ) -> c_int; + pub fn SignalAction_r( + __pid: crate::pid_t, + __sigstub: unsafe extern "C" fn(), + __signo: c_int, + __act: *const crate::sigaction, + __oact: *mut crate::sigaction, + ) -> c_int; + pub fn SignalProcmask( + __pid: crate::pid_t, + __tid: c_int, + __how: c_int, + __set: *const crate::sigset_t, + __oldset: *mut crate::sigset_t, + ) -> c_int; + pub fn SignalProcmask_r( + __pid: crate::pid_t, + __tid: c_int, + __how: c_int, + __set: *const crate::sigset_t, + __oldset: *mut crate::sigset_t, + ) -> c_int; + pub fn SignalSuspend(__set: *const crate::sigset_t) -> c_int; + pub fn SignalSuspend_r(__set: *const crate::sigset_t) -> c_int; + pub fn SignalWaitinfo(__set: *const crate::sigset_t, __info: *mut crate::siginfo_t) -> c_int; + pub fn SignalWaitinfo_r(__set: *const crate::sigset_t, __info: *mut crate::siginfo_t) -> c_int; + pub fn SignalWaitinfoMask( + __set: *const crate::sigset_t, + __info: *mut crate::siginfo_t, + __mask: *const crate::sigset_t, + ) -> c_int; + pub fn SignalWaitinfoMask_r( + __set: *const crate::sigset_t, + __info: *mut crate::siginfo_t, + __mask: *const crate::sigset_t, + ) -> c_int; + pub fn ThreadCreate( + __pid: crate::pid_t, + __func: unsafe extern "C" fn(__arg: *mut c_void) -> *mut c_void, + __arg: *mut c_void, + __attr: *const crate::_thread_attr, + ) -> c_int; + pub fn ThreadCreate_r( + __pid: crate::pid_t, + __func: unsafe extern "C" fn(__arg: *mut c_void) -> *mut c_void, + __arg: *mut c_void, + __attr: *const crate::_thread_attr, + ) -> c_int; + + pub fn ThreadDestroy(__tid: c_int, __priority: c_int, __status: *mut c_void) -> c_int; + pub fn ThreadDestroy_r(__tid: c_int, __priority: c_int, __status: *mut c_void) -> c_int; + pub fn ThreadDetach(__tid: c_int) -> c_int; + pub fn ThreadDetach_r(__tid: c_int) -> c_int; + pub fn ThreadJoin(__tid: c_int, __status: *mut *mut c_void) -> c_int; + pub fn ThreadJoin_r(__tid: c_int, __status: *mut *mut c_void) -> c_int; + pub fn ThreadCancel(__tid: c_int, __canstub: unsafe extern "C" fn()) -> c_int; + pub fn ThreadCancel_r(__tid: c_int, __canstub: unsafe extern "C" fn()) -> c_int; + pub fn ThreadCtl(__cmd: c_int, __data: *mut c_void) -> c_int; + pub fn ThreadCtl_r(__cmd: c_int, __data: *mut c_void) -> c_int; + pub fn ThreadCtlExt( + __pid: crate::pid_t, + __tid: c_int, + __cmd: c_int, + __data: *mut c_void, + ) -> c_int; + pub fn ThreadCtlExt_r( + __pid: crate::pid_t, + __tid: c_int, + __cmd: c_int, + __data: *mut c_void, + ) -> c_int; + + pub fn InterruptHookTrace( + __handler: Option *const crate::sigevent>, + __flags: c_uint, + ) -> c_int; + pub fn InterruptHookIdle( + __handler: Option, + __flags: c_uint, + ) -> c_int; + pub fn InterruptHookIdle2( + __handler: Option< + unsafe extern "C" fn(arg1: c_uint, arg2: *mut syspage_entry, arg3: *mut _idle_hook), + >, + __flags: c_uint, + ) -> c_int; + pub fn InterruptHookOverdriveEvent(__event: *const crate::sigevent, __flags: c_uint) -> c_int; + pub fn InterruptAttachEvent( + __intr: c_int, + __event: *const crate::sigevent, + __flags: c_uint, + ) -> c_int; + pub fn InterruptAttachEvent_r( + __intr: c_int, + __event: *const crate::sigevent, + __flags: c_uint, + ) -> c_int; + pub fn InterruptAttach( + __intr: c_int, + __handler: Option< + unsafe extern "C" fn(__area: *mut c_void, __id: c_int) -> *const crate::sigevent, + >, + __area: *const c_void, + __size: c_int, + __flags: c_uint, + ) -> c_int; + pub fn InterruptAttach_r( + __intr: c_int, + __handler: Option< + unsafe extern "C" fn(__area: *mut c_void, __id: c_int) -> *const crate::sigevent, + >, + __area: *const c_void, + __size: c_int, + __flags: c_uint, + ) -> c_int; + pub fn InterruptAttachArray( + __intr: c_int, + __handler: Option< + unsafe extern "C" fn(__area: *mut c_void, __id: c_int) -> *const *const crate::sigevent, + >, + __area: *const c_void, + __size: c_int, + __flags: c_uint, + ) -> c_int; + pub fn InterruptAttachArray_r( + __intr: c_int, + __handler: Option< + unsafe extern "C" fn(__area: *mut c_void, __id: c_int) -> *const *const crate::sigevent, + >, + __area: *const c_void, + __size: c_int, + __flags: c_uint, + ) -> c_int; + pub fn InterruptDetach(__id: c_int) -> c_int; + pub fn InterruptDetach_r(__id: c_int) -> c_int; + pub fn InterruptWait(__flags: c_int, __timeout: *const u64) -> c_int; + pub fn InterruptWait_r(__flags: c_int, __timeout: *const u64) -> c_int; + pub fn InterruptCharacteristic( + __type: c_int, + __id: c_int, + __new: *mut c_uint, + __old: *mut c_uint, + ) -> c_int; + pub fn InterruptCharacteristic_r( + __type: c_int, + __id: c_int, + __new: *mut c_uint, + __old: *mut c_uint, + ) -> c_int; + + pub fn SchedGet(__pid: crate::pid_t, __tid: c_int, __param: *mut crate::sched_param) -> c_int; + pub fn SchedGet_r(__pid: crate::pid_t, __tid: c_int, __param: *mut crate::sched_param) + -> c_int; + pub fn SchedGetCpuNum() -> c_uint; + pub fn SchedSet( + __pid: crate::pid_t, + __tid: c_int, + __algorithm: c_int, + __param: *const crate::sched_param, + ) -> c_int; + pub fn SchedSet_r( + __pid: crate::pid_t, + __tid: c_int, + __algorithm: c_int, + __param: *const crate::sched_param, + ) -> c_int; + pub fn SchedInfo( + __pid: crate::pid_t, + __algorithm: c_int, + __info: *mut crate::_sched_info, + ) -> c_int; + pub fn SchedInfo_r( + __pid: crate::pid_t, + __algorithm: c_int, + __info: *mut crate::_sched_info, + ) -> c_int; + pub fn SchedYield() -> c_int; + pub fn SchedYield_r() -> c_int; + pub fn SchedCtl(__cmd: c_int, __data: *mut c_void, __length: usize) -> c_int; + pub fn SchedCtl_r(__cmd: c_int, __data: *mut c_void, __length: usize) -> c_int; + pub fn SchedJobCreate(__job: *mut nto_job_t) -> c_int; + pub fn SchedJobCreate_r(__job: *mut nto_job_t) -> c_int; + pub fn SchedJobDestroy(__job: *mut nto_job_t) -> c_int; + pub fn SchedJobDestroy_r(__job: *mut nto_job_t) -> c_int; + pub fn SchedWaypoint( + __job: *mut nto_job_t, + __new: *const i64, + __max: *const i64, + __old: *mut i64, + ) -> c_int; + pub fn SchedWaypoint_r( + __job: *mut nto_job_t, + __new: *const i64, + __max: *const i64, + __old: *mut i64, + ) -> c_int; + + pub fn TimerCreate(__id: crate::clockid_t, __notify: *const crate::sigevent) -> c_int; + pub fn TimerCreate_r(__id: crate::clockid_t, __notify: *const crate::sigevent) -> c_int; + pub fn TimerDestroy(__id: crate::timer_t) -> c_int; + pub fn TimerDestroy_r(__id: crate::timer_t) -> c_int; + pub fn TimerSettime( + __id: crate::timer_t, + __flags: c_int, + __itime: *const crate::_itimer, + __oitime: *mut crate::_itimer, + ) -> c_int; + pub fn TimerSettime_r( + __id: crate::timer_t, + __flags: c_int, + __itime: *const crate::_itimer, + __oitime: *mut crate::_itimer, + ) -> c_int; + pub fn TimerInfo( + __pid: crate::pid_t, + __id: crate::timer_t, + __flags: c_int, + __info: *mut crate::_timer_info, + ) -> c_int; + pub fn TimerInfo_r( + __pid: crate::pid_t, + __id: crate::timer_t, + __flags: c_int, + __info: *mut crate::_timer_info, + ) -> c_int; + pub fn TimerAlarm( + __id: crate::clockid_t, + __itime: *const crate::_itimer, + __otime: *mut crate::_itimer, + ) -> c_int; + pub fn TimerAlarm_r( + __id: crate::clockid_t, + __itime: *const crate::_itimer, + __otime: *mut crate::_itimer, + ) -> c_int; + pub fn TimerTimeout( + __id: crate::clockid_t, + __flags: c_int, + __notify: *const crate::sigevent, + __ntime: *const u64, + __otime: *mut u64, + ) -> c_int; + pub fn TimerTimeout_r( + __id: crate::clockid_t, + __flags: c_int, + __notify: *const crate::sigevent, + __ntime: *const u64, + __otime: *mut u64, + ) -> c_int; + + pub fn SyncTypeCreate( + __type: c_uint, + __sync: *mut crate::sync_t, + __attr: *const crate::_sync_attr, + ) -> c_int; + pub fn SyncTypeCreate_r( + __type: c_uint, + __sync: *mut crate::sync_t, + __attr: *const crate::_sync_attr, + ) -> c_int; + pub fn SyncDestroy(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncDestroy_r(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncCtl(__cmd: c_int, __sync: *mut crate::sync_t, __data: *mut c_void) -> c_int; + pub fn SyncCtl_r(__cmd: c_int, __sync: *mut crate::sync_t, __data: *mut c_void) -> c_int; + pub fn SyncMutexEvent(__sync: *mut crate::sync_t, event: *const crate::sigevent) -> c_int; + pub fn SyncMutexEvent_r(__sync: *mut crate::sync_t, event: *const crate::sigevent) -> c_int; + pub fn SyncMutexLock(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncMutexLock_r(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncMutexUnlock(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncMutexUnlock_r(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncMutexRevive(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncMutexRevive_r(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncCondvarWait(__sync: *mut crate::sync_t, __mutex: *mut crate::sync_t) -> c_int; + pub fn SyncCondvarWait_r(__sync: *mut crate::sync_t, __mutex: *mut crate::sync_t) -> c_int; + pub fn SyncCondvarSignal(__sync: *mut crate::sync_t, __all: c_int) -> c_int; + pub fn SyncCondvarSignal_r(__sync: *mut crate::sync_t, __all: c_int) -> c_int; + pub fn SyncSemPost(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncSemPost_r(__sync: *mut crate::sync_t) -> c_int; + pub fn SyncSemWait(__sync: *mut crate::sync_t, __tryto: c_int) -> c_int; + pub fn SyncSemWait_r(__sync: *mut crate::sync_t, __tryto: c_int) -> c_int; + + pub fn ClockTime(__id: crate::clockid_t, _new: *const u64, __old: *mut u64) -> c_int; + pub fn ClockTime_r(__id: crate::clockid_t, _new: *const u64, __old: *mut u64) -> c_int; + pub fn ClockAdjust( + __id: crate::clockid_t, + _new: *const crate::_clockadjust, + __old: *mut crate::_clockadjust, + ) -> c_int; + pub fn ClockAdjust_r( + __id: crate::clockid_t, + _new: *const crate::_clockadjust, + __old: *mut crate::_clockadjust, + ) -> c_int; + pub fn ClockPeriod( + __id: crate::clockid_t, + _new: *const crate::_clockperiod, + __old: *mut crate::_clockperiod, + __reserved: c_int, + ) -> c_int; + pub fn ClockPeriod_r( + __id: crate::clockid_t, + _new: *const crate::_clockperiod, + __old: *mut crate::_clockperiod, + __reserved: c_int, + ) -> c_int; + pub fn ClockId(__pid: crate::pid_t, __tid: c_int) -> c_int; + pub fn ClockId_r(__pid: crate::pid_t, __tid: c_int) -> c_int; + + // + //TODO: The following commented out functions are implemented in assembly. + // We can implmement them either via a C stub or rust's inline assembly. + // + //pub fn InterruptEnable(); + //pub fn InterruptDisable(); + pub fn InterruptMask(__intr: c_int, __id: c_int) -> c_int; + pub fn InterruptUnmask(__intr: c_int, __id: c_int) -> c_int; + //pub fn InterruptLock(__spin: *mut intrspin); + //pub fn InterruptUnlock(__spin: *mut intrspin); + //pub fn InterruptStatus() -> c_uint; +} diff --git a/deps/crates/vendor/libc/src/unix/nto/x86_64.rs b/deps/crates/vendor/libc/src/unix/nto/x86_64.rs new file mode 100644 index 00000000000000..b8e0b221363dc3 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/nto/x86_64.rs @@ -0,0 +1,111 @@ +use crate::prelude::*; + +pub type wchar_t = u32; +pub type time_t = i64; + +s! { + #[repr(align(8))] + pub struct x86_64_cpu_registers { + pub rdi: u64, + pub rsi: u64, + pub rdx: u64, + pub r10: u64, + pub r8: u64, + pub r9: u64, + pub rax: u64, + pub rbx: u64, + pub rbp: u64, + pub rcx: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, + pub rip: u64, + pub cs: u32, + rsvd1: Padding, + pub rflags: u64, + pub rsp: u64, + pub ss: u32, + rsvd2: Padding, + } + + #[repr(align(8))] + pub struct mcontext_t { + pub cpu: x86_64_cpu_registers, + pub fpu: x86_64_fpu_registers, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct fsave_area_64 { + pub fpu_control_word: u32, + pub fpu_status_word: u32, + pub fpu_tag_word: u32, + pub fpu_ip: u32, + pub fpu_cs: u32, + pub fpu_op: u32, + pub fpu_ds: u32, + pub st_regs: [u8; 80], + } + + pub struct fxsave_area_64 { + pub fpu_control_word: u16, + pub fpu_status_word: u16, + pub fpu_tag_word: u16, + pub fpu_operand: u16, + pub fpu_rip: u64, + pub fpu_rdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st_regs: [u8; 128], + pub xmm_regs: [u8; 128], + reserved2: Padding<[u8; 224]>, + } + + pub struct fpu_extention_savearea_64 { + pub other: [u8; 512], + pub xstate_bv: u64, + pub xstate_undef: [u64; 7], + pub xstate_info: [u8; 224], + } +} + +s_no_extra_traits! { + pub union x86_64_fpu_registers { + pub fsave_area: fsave_area_64, + pub fxsave_area: fxsave_area_64, + pub xsave_area: fpu_extention_savearea_64, + pub data: [u8; 1024], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl Eq for x86_64_fpu_registers {} + + impl PartialEq for x86_64_fpu_registers { + fn eq(&self, other: &x86_64_fpu_registers) -> bool { + unsafe { + self.fsave_area == other.fsave_area + || self.fxsave_area == other.fxsave_area + || self.xsave_area == other.xsave_area + } + } + } + + impl hash::Hash for x86_64_fpu_registers { + fn hash(&self, state: &mut H) { + unsafe { + self.fsave_area.hash(state); + self.fxsave_area.hash(state); + self.xsave_area.hash(state); + } + } + } + } +} diff --git a/deps/crates/vendor/libc/src/unix/nuttx/mod.rs b/deps/crates/vendor/libc/src/unix/nuttx/mod.rs new file mode 100644 index 00000000000000..150dc43557d293 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/nuttx/mod.rs @@ -0,0 +1,594 @@ +use crate::prelude::*; +use crate::{ + in6_addr, + in_addr_t, + timespec, + DIR, +}; + +pub type nlink_t = u16; +pub type ino_t = u16; +pub type blkcnt_t = u64; +pub type blksize_t = i16; +pub type cc_t = u8; +pub type clock_t = i64; +pub type dev_t = i32; +pub type fsblkcnt_t = u64; +pub type locale_t = *mut i8; +pub type mode_t = u32; +pub type nfds_t = u32; +pub type off_t = i64; +pub type pthread_key_t = i32; +pub type pthread_mutexattr_t = u8; +pub type pthread_rwlockattr_t = i32; +pub type pthread_t = i32; +pub type rlim_t = i64; +pub type sa_family_t = u16; +pub type socklen_t = u32; +pub type speed_t = usize; +pub type suseconds_t = i32; +pub type tcflag_t = u32; +pub type clockid_t = i32; +pub type time_t = i64; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: u32, + pub st_gid: u32, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atim: timespec, + pub st_mtim: timespec, + pub st_ctim: timespec, + pub st_blksize: blksize_t, + pub st_blocks: i64, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [u8; 14], + } + + pub struct passwd { + pub pw_name: *const c_char, + pub pw_passwd: *const c_char, + pub pw_uid: u32, + pub pw_gid: u32, + pub pw_gecos: *const c_char, + pub pw_dir: *const c_char, + pub pw_shell: *const c_char, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct sem_t { + __val: [usize; __SEM_SIZE__], + } + + pub struct pthread_attr_t { + __val: [usize; __PTHREAD_ATTR_SIZE__], + } + + pub struct pthread_mutex_t { + __val: [usize; __PTHREAD_MUTEX_SIZE__], + } + + pub struct pthread_cond_t { + __val: [usize; __PTHREAD_COND_SIZE__], + } + + pub struct pthread_condattr_t { + __val: [usize; __PTHREAD_CONDATTR_SIZE__], + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct lconv { + pub decimal_point: *const c_char, + pub thousands_sep: *const c_char, + pub grouping: *const c_char, + pub int_curr_symbol: *const c_char, + pub currency_symbol: *const c_char, + pub mon_decimal_point: *const c_char, + pub mon_thousands_sep: *const c_char, + pub mon_grouping: *const c_char, + pub positive_sign: *const c_char, + pub negative_sign: *const c_char, + pub int_frac_digits: i8, + pub frac_digits: i8, + pub p_cs_precedes: i8, + pub p_sep_by_space: i8, + pub n_cs_precedes: i8, + pub n_sep_by_space: i8, + pub p_sign_posn: i8, + pub n_sign_posn: i8, + pub int_n_cs_precedes: i8, + pub int_n_sep_by_space: i8, + pub int_n_sign_posn: i8, + pub int_p_cs_precedes: i8, + pub int_p_sep_by_space: i8, + pub int_p_sign_posn: i8, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct tm { + pub tm_sec: i32, + pub tm_min: i32, + pub tm_hour: i32, + pub tm_mday: i32, + pub tm_mon: i32, + pub tm_year: i32, + pub tm_wday: i32, + pub tm_yday: i32, + pub tm_isdst: i32, + pub tm_gmtoff: isize, + pub tm_zone: *const c_char, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct addrinfo { + pub ai_flags: i32, + pub ai_family: i32, + pub ai_socktype: i32, + pub ai_protocol: i32, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct pthread_rwlock_t { + __val: [usize; __PTHREAD_RWLOCK_SIZE__], + } + + pub struct statvfs { + pub f_bsize: usize, + pub f_frsize: usize, + pub f_blocks: fsblkcnt_t, + pub f_bfree: fsblkcnt_t, + pub f_bavail: fsblkcnt_t, + pub f_files: fsblkcnt_t, + pub f_ffree: fsblkcnt_t, + pub f_favail: fsblkcnt_t, + pub f_fsid: usize, + pub f_flag: usize, + pub f_namemax: usize, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct dirent { + pub d_type: u8, + pub d_name: [c_char; __NAME_MAX__ + 1], + } + + pub struct fd_set { + __val: [u32; __FDSET_SIZE__], + } + + pub struct sigset_t { + __val: [u32; __SIGSET_SIZE__], + } + + pub struct sigaction { + pub sa_handler: usize, + pub sa_mask: sigset_t, + pub sa_flags: i32, + pub sa_user: usize, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct termios { + pub c_iflag: tcflag_t, + pub c_oflag: tcflag_t, + pub c_cflag: tcflag_t, + pub c_lflag: tcflag_t, + pub c_cc: [cc_t; 12], + pub c_speed: speed_t, + __reserved: Padding<[usize; __DEFAULT_RESERVED_SIZE__]>, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + ss_data: [u32; __SOCKADDR_STORAGE_SIZE__], + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: u32, + } +} + +// Reserved two pointer size for reserved area for some structures. +// This ensures that the size of these structures is large enough +// if more fields are added in the NuttX side. +// +// These structures are that defined by POSIX but only necessary fields are included, +// for example, struct passwd, https://pubs.opengroup.org/onlinepubs/009695399/basedefs/pwd.h.html, +// POSIX only defines following fields in struct passwd: +// char *pw_name User's login name. +// char *pw_passwd Encrypted password. +// uid_t pw_uid Numerical user ID. +// gid_t pw_gid Numerical group ID. +// char *pw_dir Initial working directory. +// char *pw_shell Program to use as shell. +// Other fields can be different depending on the implementation. + +const __DEFAULT_RESERVED_SIZE__: usize = 2; + +const __SOCKADDR_STORAGE_SIZE__: usize = 36; +const __PTHREAD_ATTR_SIZE__: usize = 5; +const __PTHREAD_MUTEX_SIZE__: usize = 9; +const __PTHREAD_COND_SIZE__: usize = 7; +const __PTHREAD_CONDATTR_SIZE__: usize = 5; +const __PTHREAD_RWLOCK_SIZE__: usize = 17; +const __SEM_SIZE__: usize = 6; +const __NAME_MAX__: usize = 64; +const __FDSET_SIZE__: usize = 10; +const __SIGSET_SIZE__: usize = 8; + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __val: [0; __PTHREAD_COND_SIZE__], +}; +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __val: [0; __PTHREAD_MUTEX_SIZE__], +}; + +// dlfcn.h +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +// stdlib.h +pub const EXIT_SUCCESS: i32 = 0; +pub const EXIT_FAILURE: i32 = 1; + +// time.h +pub const CLOCK_REALTIME: i32 = 0; +pub const CLOCK_MONOTONIC: i32 = 1; + +// errno.h +pub const EPERM: i32 = 1; +pub const ENOENT: i32 = 2; +pub const ESRCH: i32 = 3; +pub const EINTR: i32 = 4; +pub const EIO: i32 = 5; +pub const ENXIO: i32 = 6; +pub const E2BIG: i32 = 7; +pub const ENOEXEC: i32 = 8; +pub const EBADF: i32 = 9; +pub const ECHILD: i32 = 10; +pub const EAGAIN: i32 = 11; +pub const ENOMEM: i32 = 12; +pub const EACCES: i32 = 13; +pub const EFAULT: i32 = 14; +pub const ENOTBLK: i32 = 15; +pub const EBUSY: i32 = 16; +pub const EEXIST: i32 = 17; +pub const EXDEV: i32 = 18; +pub const ENODEV: i32 = 19; +pub const ENOTDIR: i32 = 20; +pub const EISDIR: i32 = 21; +pub const EINVAL: i32 = 22; +pub const ENFILE: i32 = 23; +pub const EMFILE: i32 = 24; +pub const ENOTTY: i32 = 25; +pub const ETXTBSY: i32 = 26; +pub const EFBIG: i32 = 27; +pub const ENOSPC: i32 = 28; +pub const ESPIPE: i32 = 29; +pub const EROFS: i32 = 30; +pub const EMLINK: i32 = 31; +pub const EPIPE: i32 = 32; +pub const EDOM: i32 = 33; +pub const ERANGE: i32 = 34; +pub const EDEADLK: i32 = 35; +pub const ENAMETOOLONG: i32 = 36; +pub const ENOLCK: i32 = 37; +pub const ENOSYS: i32 = 38; +pub const ENOTEMPTY: i32 = 39; +pub const ELOOP: i32 = 40; +pub const EWOULDBLOCK: i32 = EAGAIN; +pub const ENOMSG: i32 = 42; +pub const EIDRM: i32 = 43; +pub const ECHRNG: i32 = 44; +pub const EL2NSYNC: i32 = 45; +pub const EL3HLT: i32 = 46; +pub const EL3RST: i32 = 47; +pub const ELNRNG: i32 = 48; +pub const EUNATCH: i32 = 49; +pub const ENOCSI: i32 = 50; +pub const EL2HLT: i32 = 51; +pub const EBADE: i32 = 52; +pub const EBADR: i32 = 53; +pub const EXFULL: i32 = 54; +pub const ENOANO: i32 = 55; +pub const EBADRQC: i32 = 56; +pub const EBADSLT: i32 = 57; +pub const EDEADLOCK: i32 = EDEADLK; +pub const EBFONT: i32 = 59; +pub const ENOSTR: i32 = 60; +pub const ENODATA: i32 = 61; +pub const ETIME: i32 = 62; +pub const ENOSR: i32 = 63; +pub const ENONET: i32 = 64; +pub const ENOPKG: i32 = 65; +pub const EREMOTE: i32 = 66; +pub const ENOLINK: i32 = 67; +pub const EADV: i32 = 68; +pub const ESRMNT: i32 = 69; +pub const ECOMM: i32 = 70; +pub const EPROTO: i32 = 71; +pub const EMULTIHOP: i32 = 72; +pub const EDOTDOT: i32 = 73; +pub const EBADMSG: i32 = 74; +pub const EOVERFLOW: i32 = 75; +pub const ENOTUNIQ: i32 = 76; +pub const EBADFD: i32 = 77; +pub const EREMCHG: i32 = 78; +pub const ELIBACC: i32 = 79; +pub const ELIBBAD: i32 = 80; +pub const ELIBSCN: i32 = 81; +pub const ELIBMAX: i32 = 82; +pub const ELIBEXEC: i32 = 83; +pub const EILSEQ: i32 = 84; +pub const ERESTART: i32 = 85; +pub const ESTRPIPE: i32 = 86; +pub const EUSERS: i32 = 87; +pub const ENOTSOCK: i32 = 88; +pub const EDESTADDRREQ: i32 = 89; +pub const EMSGSIZE: i32 = 90; +pub const EPROTOTYPE: i32 = 91; +pub const ENOPROTOOPT: i32 = 92; +pub const EPROTONOSUPPORT: i32 = 93; +pub const ESOCKTNOSUPPORT: i32 = 94; +pub const EOPNOTSUPP: i32 = 95; +pub const EPFNOSUPPORT: i32 = 96; +pub const EAFNOSUPPORT: i32 = 97; +pub const EADDRINUSE: i32 = 98; +pub const EADDRNOTAVAIL: i32 = 99; +pub const ENETDOWN: i32 = 100; +pub const ENETUNREACH: i32 = 101; +pub const ENETRESET: i32 = 102; +pub const ECONNABORTED: i32 = 103; +pub const ECONNRESET: i32 = 104; +pub const ENOBUFS: i32 = 105; +pub const EISCONN: i32 = 106; +pub const ENOTCONN: i32 = 107; +pub const ESHUTDOWN: i32 = 108; +pub const ETOOMANYREFS: i32 = 109; +pub const ETIMEDOUT: i32 = 110; +pub const ECONNREFUSED: i32 = 111; +pub const EHOSTDOWN: i32 = 112; +pub const EHOSTUNREACH: i32 = 113; +pub const EALREADY: i32 = 114; +pub const EINPROGRESS: i32 = 115; +pub const ESTALE: i32 = 116; +pub const EUCLEAN: i32 = 117; +pub const ENOTNAM: i32 = 118; +pub const ENAVAIL: i32 = 119; +pub const EISNAM: i32 = 120; +pub const EREMOTEIO: i32 = 121; +pub const EDQUOT: i32 = 122; +pub const ENOMEDIUM: i32 = 123; +pub const EMEDIUMTYPE: i32 = 124; +pub const ECANCELED: i32 = 125; +pub const ENOKEY: i32 = 126; +pub const EKEYEXPIRED: i32 = 127; +pub const EKEYREVOKED: i32 = 128; +pub const EKEYREJECTED: i32 = 129; +pub const EOWNERDEAD: i32 = 130; +pub const ENOTRECOVERABLE: i32 = 131; +pub const ERFKILL: i32 = 132; +pub const EHWPOISON: i32 = 133; +pub const ELBIN: i32 = 134; +pub const EFTYPE: i32 = 135; +pub const ENMFILE: i32 = 136; +pub const EPROCLIM: i32 = 137; +pub const ENOTSUP: i32 = 138; +pub const ENOSHARE: i32 = 139; +pub const ECASECLASH: i32 = 140; + +// fcntl.h +pub const FIOCLEX: i32 = 0x30b; +pub const F_SETFL: i32 = 0x9; +pub const F_DUPFD_CLOEXEC: i32 = 0x12; +pub const F_GETFD: i32 = 0x1; +pub const F_GETFL: i32 = 0x2; +pub const O_RDONLY: i32 = 0x1; +pub const O_WRONLY: i32 = 0x2; +pub const O_RDWR: i32 = 0x3; +pub const O_CREAT: i32 = 0x4; +pub const O_EXCL: i32 = 0x8; +pub const O_NOCTTY: i32 = 0x0; +pub const O_TRUNC: i32 = 0x20; +pub const O_APPEND: i32 = 0x10; +pub const O_NONBLOCK: i32 = 0x40; +pub const O_DSYNC: i32 = 0x80; +pub const O_DIRECT: i32 = 0x200; +pub const O_LARGEFILE: i32 = 0x2000; +pub const O_DIRECTORY: i32 = 0x800; +pub const O_NOFOLLOW: i32 = 0x1000; +pub const O_NOATIME: i32 = 0x40000; +pub const O_CLOEXEC: i32 = 0x400; +pub const O_ACCMODE: i32 = 0x0003; +pub const AT_FDCWD: i32 = -100; +pub const AT_REMOVEDIR: i32 = 0x200; + +// sys/types.h +pub const SEEK_SET: i32 = 0; +pub const SEEK_CUR: i32 = 1; +pub const SEEK_END: i32 = 2; + +// sys/stat.h +pub const S_IFDIR: u32 = 0x4000; +pub const S_IFLNK: u32 = 0xA000; +pub const S_IFREG: u32 = 0x8000; +pub const S_IFMT: u32 = 0xF000; +pub const S_IFIFO: u32 = 0x1000; +pub const S_IFSOCK: u32 = 0xc000; +pub const S_IFBLK: u32 = 0x6000; +pub const S_IFCHR: u32 = 0x2000; +pub const S_IRUSR: u32 = 0x100; +pub const S_IWUSR: u32 = 0x80; +pub const S_IXUSR: u32 = 0x40; +pub const S_IRGRP: u32 = 0x20; +pub const S_IWGRP: u32 = 0x10; +pub const S_IXGRP: u32 = 0x8; +pub const S_IROTH: u32 = 0x004; +pub const S_IWOTH: u32 = 0x002; +pub const S_IXOTH: u32 = 0x001; + +// sys/poll.h +pub const POLLIN: i16 = 0x01; +pub const POLLOUT: i16 = 0x04; +pub const POLLHUP: i16 = 0x10; +pub const POLLERR: i16 = 0x08; +pub const POLLNVAL: i16 = 0x20; + +// sys/socket.h +pub const AF_UNIX: i32 = 1; +pub const SOCK_DGRAM: i32 = 2; +pub const SOCK_STREAM: i32 = 1; +pub const AF_INET: i32 = 2; +pub const AF_INET6: i32 = 10; +pub const MSG_PEEK: i32 = 0x02; +pub const SOL_SOCKET: i32 = 1; +pub const SHUT_WR: i32 = 2; +pub const SHUT_RD: i32 = 1; +pub const SHUT_RDWR: i32 = 3; +pub const SO_ERROR: i32 = 4; +pub const SO_REUSEADDR: i32 = 11; +pub const SOMAXCONN: i32 = 8; +pub const SO_LINGER: i32 = 6; +pub const SO_RCVTIMEO: i32 = 0xa; +pub const SO_SNDTIMEO: i32 = 0xe; +pub const SO_BROADCAST: i32 = 1; + +// netinet/tcp.h +pub const TCP_NODELAY: i32 = 0x10; + +// nuttx/fs/ioctl.h +pub const FIONBIO: i32 = 0x30a; + +// unistd.h +pub const _SC_PAGESIZE: i32 = 0x36; +pub const _SC_THREAD_STACK_MIN: i32 = 0x58; +pub const _SC_GETPW_R_SIZE_MAX: i32 = 0x25; +pub const _SC_HOST_NAME_MAX: i32 = 0x26; + +// signal.h +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGBUS: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGUSR1: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGUSR2: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGSTKFLT: c_int = 16; +pub const SIGCHLD: c_int = 17; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGURG: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGIO: c_int = 29; +pub const SIGPOLL: c_int = SIGIO; +pub const SIGPWR: c_int = 30; +pub const SIGSYS: c_int = 31; + +// pthread.h +pub const PTHREAD_MUTEX_NORMAL: i32 = 0; + +// netinet/in.h +pub const IP_TTL: i32 = 0x1e; +pub const IPV6_V6ONLY: i32 = 0x17; +pub const IPV6_JOIN_GROUP: i32 = 0x11; +pub const IPV6_LEAVE_GROUP: i32 = 0x12; +pub const IP_MULTICAST_LOOP: i32 = 0x13; +pub const IPV6_MULTICAST_LOOP: i32 = 0x15; +pub const IP_MULTICAST_TTL: i32 = 0x12; +pub const IP_ADD_MEMBERSHIP: i32 = 0x14; +pub const IP_DROP_MEMBERSHIP: i32 = 0x15; + +extern "C" { + pub fn __errno() -> *mut c_int; + pub fn bind(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32; + pub fn ioctl(fd: i32, request: i32, ...) -> i32; + pub fn dirfd(dirp: *mut DIR) -> i32; + pub fn recvfrom( + sockfd: i32, + buf: *mut c_void, + len: usize, + flags: i32, + src_addr: *mut sockaddr, + addrlen: *mut socklen_t, + ) -> i32; + + pub fn pthread_create( + thread: *mut pthread_t, + attr: *const pthread_attr_t, + start_routine: extern "C" fn(*mut c_void) -> *mut c_void, + arg: *mut c_void, + ) -> i32; + + pub fn clock_gettime(clockid: clockid_t, tp: *mut timespec) -> i32; + pub fn futimens(fd: i32, times: *const timespec) -> i32; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clock_id: clockid_t) -> i32; + pub fn pthread_setname_np(thread: pthread_t, name: *const c_char) -> i32; + pub fn pthread_getname_np(thread: pthread_t, name: *mut c_char, len: usize) -> i32; + pub fn getrandom(buf: *mut c_void, buflen: usize, flags: u32) -> isize; + pub fn arc4random() -> u32; + pub fn arc4random_buf(bytes: *mut c_void, nbytes: usize); +} diff --git a/deps/crates/vendor/libc/src/unix/redox/mod.rs b/deps/crates/vendor/libc/src/unix/redox/mod.rs new file mode 100644 index 00000000000000..691fe5c5fced1a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/redox/mod.rs @@ -0,0 +1,1433 @@ +use crate::prelude::*; + +pub type wchar_t = i32; + +pub type blkcnt_t = c_longlong; +pub type blksize_t = c_long; +pub type clock_t = c_long; +pub type clockid_t = c_int; +pub type dev_t = c_ulonglong; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulonglong; +pub type mode_t = c_int; +pub type nfds_t = c_ulong; +pub type nlink_t = c_ulong; +pub type off_t = c_longlong; +pub type pthread_t = *mut c_void; +// Must be usize due to library/std/sys_common/thread_local.rs, +// should technically be *mut c_void +pub type pthread_key_t = usize; +pub type rlim_t = c_ulonglong; +pub type sa_family_t = u16; +pub type sem_t = *mut c_void; +pub type sigset_t = c_ulonglong; +pub type socklen_t = u32; +pub type speed_t = u32; +pub type suseconds_t = c_int; +pub type tcflag_t = u32; +pub type time_t = c_longlong; +pub type id_t = c_uint; +pub type uid_t = c_int; +pub type gid_t = c_int; + +extern_ty! { + pub enum timezone {} +} + +s! { + #[repr(C)] + pub struct utsname { + pub sysname: [c_char; UTSLENGTH], + pub nodename: [c_char; UTSLENGTH], + pub release: [c_char; UTSLENGTH], + pub version: [c_char; UTSLENGTH], + pub machine: [c_char; UTSLENGTH], + pub domainname: [c_char; UTSLENGTH], + } + + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_off: off_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], + } + + pub struct sockaddr_un { + pub sun_family: crate::sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct sockaddr_storage { + pub ss_family: crate::sa_family_t, + __ss_padding: Padding<[u8; 128 - size_of::() - size_of::()]>, + __ss_align: c_ulong, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: size_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut crate::addrinfo, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct epoll_event { + pub events: u32, + pub u64: u64, + pub _pad: u64, + } + + pub struct fd_set { + fds_bits: [c_ulong; crate::FD_SETSIZE as usize / ULONG_SIZE], + } + + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: crate::in_addr, + pub imr_interface: crate::in_addr, + } + + pub struct lconv { + pub currency_symbol: *const c_char, + pub decimal_point: *const c_char, + pub frac_digits: c_char, + pub grouping: *const c_char, + pub int_curr_symbol: *const c_char, + pub int_frac_digits: c_char, + pub mon_decimal_point: *const c_char, + pub mon_grouping: *const c_char, + pub mon_thousands_sep: *const c_char, + pub negative_sign: *const c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub n_sign_posn: c_char, + pub positive_sign: *const c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub thousands_sep: *const c_char, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: size_t, + pub msg_control: *mut c_void, + pub msg_controllen: size_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: size_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + // FIXME(1.0): This should not implement `PartialEq` + #[allow(unpredictable_function_pointer_comparisons)] + pub struct sigaction { + pub sa_sigaction: crate::sighandler_t, + pub sa_flags: c_int, + pub sa_restorer: Option, + pub sa_mask: crate::sigset_t, + } + + pub struct siginfo_t { + pub si_signo: c_int, + pub si_errno: c_int, + pub si_code: c_int, + _pad: Padding<[c_int; 29]>, + _align: [usize; 0], + } + + pub struct sockaddr { + pub sa_family: crate::sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: crate::sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: crate::sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_nlink: crate::nlink_t, + pub st_mode: mode_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + _pad: Padding<[c_char; 24]>, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_line: crate::cc_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub tm_gmtoff: c_long, + pub tm_zone: *const c_char, + } + + pub struct ucred { + pub pid: crate::pid_t, + pub uid: uid_t, + pub gid: gid_t, + } + + #[cfg_attr(target_pointer_width = "32", repr(C, align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(C, align(8)))] + pub struct pthread_attr_t { + bytes: [u8; _PTHREAD_ATTR_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_barrier_t { + bytes: [u8; _PTHREAD_BARRIER_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_barrierattr_t { + bytes: [u8; _PTHREAD_BARRIERATTR_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_mutex_t { + bytes: [u8; _PTHREAD_MUTEX_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_rwlock_t { + bytes: [u8; _PTHREAD_RWLOCK_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_mutexattr_t { + bytes: [u8; _PTHREAD_MUTEXATTR_SIZE], + } + #[repr(C)] + #[repr(align(1))] + pub struct pthread_rwlockattr_t { + bytes: [u8; _PTHREAD_RWLOCKATTR_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_cond_t { + bytes: [u8; _PTHREAD_COND_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_condattr_t { + bytes: [u8; _PTHREAD_CONDATTR_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_once_t { + bytes: [u8; _PTHREAD_ONCE_SIZE], + } + #[repr(C)] + #[repr(align(4))] + pub struct pthread_spinlock_t { + bytes: [u8; _PTHREAD_SPINLOCK_SIZE], + } +} +const _PTHREAD_ATTR_SIZE: usize = 32; +const _PTHREAD_RWLOCKATTR_SIZE: usize = 1; +const _PTHREAD_RWLOCK_SIZE: usize = 4; +const _PTHREAD_BARRIER_SIZE: usize = 24; +const _PTHREAD_BARRIERATTR_SIZE: usize = 4; +const _PTHREAD_CONDATTR_SIZE: usize = 8; +const _PTHREAD_COND_SIZE: usize = 8; +const _PTHREAD_MUTEX_SIZE: usize = 12; +const _PTHREAD_MUTEXATTR_SIZE: usize = 20; +const _PTHREAD_ONCE_SIZE: usize = 4; +const _PTHREAD_SPINLOCK_SIZE: usize = 4; + +pub const UTSLENGTH: usize = 65; + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +// limits.h +pub const PATH_MAX: c_int = 4096; + +// fcntl.h +pub const F_GETLK: c_int = 5; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_ULOCK: c_int = 0; +pub const F_LOCK: c_int = 1; +pub const F_TLOCK: c_int = 2; +pub const F_TEST: c_int = 3; + +pub const AT_FDCWD: c_int = -100; + +// FIXME(redox): relibc { +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); +// } + +// dlfcn.h +pub const RTLD_LAZY: c_int = 0x0001; +pub const RTLD_NOW: c_int = 0x0002; +pub const RTLD_NOLOAD: c_int = 0x0004; +pub const RTLD_GLOBAL: c_int = 0x0100; +pub const RTLD_LOCAL: c_int = 0x0000; + +// errno.h +pub const EPERM: c_int = 1; /* Operation not permitted */ +pub const ENOENT: c_int = 2; /* No such file or directory */ +pub const ESRCH: c_int = 3; /* No such process */ +pub const EINTR: c_int = 4; /* Interrupted system call */ +pub const EIO: c_int = 5; /* I/O error */ +pub const ENXIO: c_int = 6; /* No such device or address */ +pub const E2BIG: c_int = 7; /* Argument list too long */ +pub const ENOEXEC: c_int = 8; /* Exec format error */ +pub const EBADF: c_int = 9; /* Bad file number */ +pub const ECHILD: c_int = 10; /* No child processes */ +pub const EAGAIN: c_int = 11; /* Try again */ +pub const ENOMEM: c_int = 12; /* Out of memory */ +pub const EACCES: c_int = 13; /* Permission denied */ +pub const EFAULT: c_int = 14; /* Bad address */ +pub const ENOTBLK: c_int = 15; /* Block device required */ +pub const EBUSY: c_int = 16; /* Device or resource busy */ +pub const EEXIST: c_int = 17; /* File exists */ +pub const EXDEV: c_int = 18; /* Cross-device link */ +pub const ENODEV: c_int = 19; /* No such device */ +pub const ENOTDIR: c_int = 20; /* Not a directory */ +pub const EISDIR: c_int = 21; /* Is a directory */ +pub const EINVAL: c_int = 22; /* Invalid argument */ +pub const ENFILE: c_int = 23; /* File table overflow */ +pub const EMFILE: c_int = 24; /* Too many open files */ +pub const ENOTTY: c_int = 25; /* Not a typewriter */ +pub const ETXTBSY: c_int = 26; /* Text file busy */ +pub const EFBIG: c_int = 27; /* File too large */ +pub const ENOSPC: c_int = 28; /* No space left on device */ +pub const ESPIPE: c_int = 29; /* Illegal seek */ +pub const EROFS: c_int = 30; /* Read-only file system */ +pub const EMLINK: c_int = 31; /* Too many links */ +pub const EPIPE: c_int = 32; /* Broken pipe */ +pub const EDOM: c_int = 33; /* Math argument out of domain of func */ +pub const ERANGE: c_int = 34; /* Math result not representable */ +pub const EDEADLK: c_int = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: c_int = 36; /* File name too long */ +pub const ENOLCK: c_int = 37; /* No record locks available */ +pub const ENOSYS: c_int = 38; /* Function not implemented */ +pub const ENOTEMPTY: c_int = 39; /* Directory not empty */ +pub const ELOOP: c_int = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: c_int = 41; /* Operation would block */ +pub const ENOMSG: c_int = 42; /* No message of desired type */ +pub const EIDRM: c_int = 43; /* Identifier removed */ +pub const ECHRNG: c_int = 44; /* Channel number out of range */ +pub const EL2NSYNC: c_int = 45; /* Level 2 not synchronized */ +pub const EL3HLT: c_int = 46; /* Level 3 halted */ +pub const EL3RST: c_int = 47; /* Level 3 reset */ +pub const ELNRNG: c_int = 48; /* Link number out of range */ +pub const EUNATCH: c_int = 49; /* Protocol driver not attached */ +pub const ENOCSI: c_int = 50; /* No CSI structure available */ +pub const EL2HLT: c_int = 51; /* Level 2 halted */ +pub const EBADE: c_int = 52; /* Invalid exchange */ +pub const EBADR: c_int = 53; /* Invalid request descriptor */ +pub const EXFULL: c_int = 54; /* Exchange full */ +pub const ENOANO: c_int = 55; /* No anode */ +pub const EBADRQC: c_int = 56; /* Invalid request code */ +pub const EBADSLT: c_int = 57; /* Invalid slot */ +pub const EDEADLOCK: c_int = 58; /* Resource deadlock would occur */ +pub const EBFONT: c_int = 59; /* Bad font file format */ +pub const ENOSTR: c_int = 60; /* Device not a stream */ +pub const ENODATA: c_int = 61; /* No data available */ +pub const ETIME: c_int = 62; /* Timer expired */ +pub const ENOSR: c_int = 63; /* Out of streams resources */ +pub const ENONET: c_int = 64; /* Machine is not on the network */ +pub const ENOPKG: c_int = 65; /* Package not installed */ +pub const EREMOTE: c_int = 66; /* Object is remote */ +pub const ENOLINK: c_int = 67; /* Link has been severed */ +pub const EADV: c_int = 68; /* Advertise error */ +pub const ESRMNT: c_int = 69; /* Srmount error */ +pub const ECOMM: c_int = 70; /* Communication error on send */ +pub const EPROTO: c_int = 71; /* Protocol error */ +pub const EMULTIHOP: c_int = 72; /* Multihop attempted */ +pub const EDOTDOT: c_int = 73; /* RFS specific error */ +pub const EBADMSG: c_int = 74; /* Not a data message */ +pub const EOVERFLOW: c_int = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: c_int = 76; /* Name not unique on network */ +pub const EBADFD: c_int = 77; /* File descriptor in bad state */ +pub const EREMCHG: c_int = 78; /* Remote address changed */ +pub const ELIBACC: c_int = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: c_int = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: c_int = 81; /* .lib section in a.out corrupted */ +/* Attempting to link in too many shared libraries */ +pub const ELIBMAX: c_int = 82; +pub const ELIBEXEC: c_int = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: c_int = 84; /* Illegal byte sequence */ +/* Interrupted system call should be restarted */ +pub const ERESTART: c_int = 85; +pub const ESTRPIPE: c_int = 86; /* Streams pipe error */ +pub const EUSERS: c_int = 87; /* Too many users */ +pub const ENOTSOCK: c_int = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: c_int = 89; /* Destination address required */ +pub const EMSGSIZE: c_int = 90; /* Message too long */ +pub const EPROTOTYPE: c_int = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: c_int = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: c_int = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: c_int = 94; /* Socket type not supported */ +/* Operation not supported on transport endpoint */ +pub const EOPNOTSUPP: c_int = 95; +pub const ENOTSUP: c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: c_int = 96; /* Protocol family not supported */ +/* Address family not supported by protocol */ +pub const EAFNOSUPPORT: c_int = 97; +pub const EADDRINUSE: c_int = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: c_int = 99; /* Cannot assign requested address */ +pub const ENETDOWN: c_int = 100; /* Network is down */ +pub const ENETUNREACH: c_int = 101; /* Network is unreachable */ +/* Network dropped connection because of reset */ +pub const ENETRESET: c_int = 102; +pub const ECONNABORTED: c_int = 103; /* Software caused connection abort */ +pub const ECONNRESET: c_int = 104; /* Connection reset by peer */ +pub const ENOBUFS: c_int = 105; /* No buffer space available */ +pub const EISCONN: c_int = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: c_int = 107; /* Transport endpoint is not connected */ +/* Cannot send after transport endpoint shutdown */ +pub const ESHUTDOWN: c_int = 108; +pub const ETOOMANYREFS: c_int = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: c_int = 110; /* Connection timed out */ +pub const ECONNREFUSED: c_int = 111; /* Connection refused */ +pub const EHOSTDOWN: c_int = 112; /* Host is down */ +pub const EHOSTUNREACH: c_int = 113; /* No route to host */ +pub const EALREADY: c_int = 114; /* Operation already in progress */ +pub const EINPROGRESS: c_int = 115; /* Operation now in progress */ +pub const ESTALE: c_int = 116; /* Stale NFS file handle */ +pub const EUCLEAN: c_int = 117; /* Structure needs cleaning */ +pub const ENOTNAM: c_int = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: c_int = 119; /* No XENIX semaphores available */ +pub const EISNAM: c_int = 120; /* Is a named type file */ +pub const EREMOTEIO: c_int = 121; /* Remote I/O error */ +pub const EDQUOT: c_int = 122; /* Quota exceeded */ +pub const ENOMEDIUM: c_int = 123; /* No medium found */ +pub const EMEDIUMTYPE: c_int = 124; /* Wrong medium type */ +pub const ECANCELED: c_int = 125; /* Operation Canceled */ +pub const ENOKEY: c_int = 126; /* Required key not available */ +pub const EKEYEXPIRED: c_int = 127; /* Key has expired */ +pub const EKEYREVOKED: c_int = 128; /* Key has been revoked */ +pub const EKEYREJECTED: c_int = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: c_int = 130; /* Owner died */ +pub const ENOTRECOVERABLE: c_int = 131; /* State not recoverable */ + +// fcntl.h +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_DUPFD_CLOEXEC: c_int = 1030; +pub const FD_CLOEXEC: c_int = 0x0100_0000; +pub const O_RDONLY: c_int = 0x0001_0000; +pub const O_WRONLY: c_int = 0x0002_0000; +pub const O_RDWR: c_int = 0x0003_0000; +pub const O_ACCMODE: c_int = 0x0003_0000; +pub const O_NONBLOCK: c_int = 0x0004_0000; +pub const O_NDELAY: c_int = O_NONBLOCK; +pub const O_APPEND: c_int = 0x0008_0000; +pub const O_SHLOCK: c_int = 0x0010_0000; +pub const O_EXLOCK: c_int = 0x0020_0000; +pub const O_ASYNC: c_int = 0x0040_0000; +pub const O_FSYNC: c_int = 0x0080_0000; +pub const O_CLOEXEC: c_int = 0x0100_0000; +pub const O_CREAT: c_int = 0x0200_0000; +pub const O_TRUNC: c_int = 0x0400_0000; +pub const O_EXCL: c_int = 0x0800_0000; +pub const O_DIRECTORY: c_int = 0x1000_0000; +pub const O_PATH: c_int = 0x2000_0000; +pub const O_SYMLINK: c_int = 0x4000_0000; +// Negative to allow it to be used as int +// FIXME(redox): Fix negative values missing from includes +pub const O_NOFOLLOW: c_int = -0x8000_0000; +pub const O_NOCTTY: c_int = 0x00000200; + +// locale.h +pub const LC_COLLATE: c_int = 0; +pub const LC_CTYPE: c_int = 1; +pub const LC_MESSAGES: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; +pub const LC_ALL: c_int = 6; + +// netdb.h +pub const AI_PASSIVE: c_int = 0x0001; +pub const AI_CANONNAME: c_int = 0x0002; +pub const AI_NUMERICHOST: c_int = 0x0004; +pub const AI_V4MAPPED: c_int = 0x0008; +pub const AI_ALL: c_int = 0x0010; +pub const AI_ADDRCONFIG: c_int = 0x0020; +pub const AI_NUMERICSERV: c_int = 0x0400; +pub const EAI_BADFLAGS: c_int = -1; +pub const EAI_NONAME: c_int = -2; +pub const EAI_AGAIN: c_int = -3; +pub const EAI_FAIL: c_int = -4; +pub const EAI_NODATA: c_int = -5; +pub const EAI_FAMILY: c_int = -6; +pub const EAI_SOCKTYPE: c_int = -7; +pub const EAI_SERVICE: c_int = -8; +pub const EAI_ADDRFAMILY: c_int = -9; +pub const EAI_MEMORY: c_int = -10; +pub const EAI_SYSTEM: c_int = -11; +pub const EAI_OVERFLOW: c_int = -12; +pub const NI_MAXHOST: c_int = 1025; +pub const NI_MAXSERV: c_int = 32; +pub const NI_NUMERICHOST: c_int = 0x0001; +pub const NI_NUMERICSERV: c_int = 0x0002; +pub const NI_NOFQDN: c_int = 0x0004; +pub const NI_NAMEREQD: c_int = 0x0008; +pub const NI_DGRAM: c_int = 0x0010; + +// netinet/in.h +// FIXME(redox): relibc { +pub const IP_TTL: c_int = 2; +pub const IPV6_UNICAST_HOPS: c_int = 16; +pub const IPV6_MULTICAST_IF: c_int = 17; +pub const IPV6_MULTICAST_HOPS: c_int = 18; +pub const IPV6_MULTICAST_LOOP: c_int = 19; +pub const IPV6_ADD_MEMBERSHIP: c_int = 20; +pub const IPV6_JOIN_GROUP: c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: c_int = 21; +pub const IPV6_LEAVE_GROUP: c_int = 21; +pub const IPV6_V6ONLY: c_int = 26; +pub const IP_MULTICAST_IF: c_int = 32; +pub const IP_MULTICAST_TTL: c_int = 33; +pub const IP_MULTICAST_LOOP: c_int = 34; +pub const IP_ADD_MEMBERSHIP: c_int = 35; +pub const IP_DROP_MEMBERSHIP: c_int = 36; +pub const IP_TOS: c_int = 1; +pub const IP_RECVTOS: c_int = 13; +pub const IPPROTO_IGMP: c_int = 2; +pub const IPPROTO_PUP: c_int = 12; +pub const IPPROTO_IDP: c_int = 22; +pub const IPPROTO_RAW: c_int = 255; +pub const IPPROTO_MAX: c_int = 255; +// } + +// netinet/tcp.h +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; + +// poll.h +pub const POLLIN: c_short = 0x001; +pub const POLLPRI: c_short = 0x002; +pub const POLLOUT: c_short = 0x004; +pub const POLLERR: c_short = 0x008; +pub const POLLHUP: c_short = 0x010; +pub const POLLNVAL: c_short = 0x020; +pub const POLLRDNORM: c_short = 0x040; +pub const POLLRDBAND: c_short = 0x080; +pub const POLLWRNORM: c_short = 0x100; +pub const POLLWRBAND: c_short = 0x200; + +// pthread.h +pub const PTHREAD_MUTEX_DEFAULT: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_NORMAL: c_int = 2; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 3; + +pub const PTHREAD_MUTEX_ROBUST: c_int = 0; +pub const PTHREAD_MUTEX_STALLED: c_int = 1; + +pub const PTHREAD_MUTEX_INITIALIZER: crate::pthread_mutex_t = crate::pthread_mutex_t { + bytes: [0; _PTHREAD_MUTEX_SIZE], +}; +pub const PTHREAD_COND_INITIALIZER: crate::pthread_cond_t = crate::pthread_cond_t { + bytes: [0; _PTHREAD_COND_SIZE], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: crate::pthread_rwlock_t = crate::pthread_rwlock_t { + bytes: [0; _PTHREAD_RWLOCK_SIZE], +}; +pub const PTHREAD_STACK_MIN: size_t = 4096; + +// signal.h +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const SIG_SETMASK: c_int = 2; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGBUS: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGUSR1: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGUSR2: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGSTKFLT: c_int = 16; +pub const SIGCHLD: c_int = 17; +pub const SIGCONT: c_int = 18; +pub const SIGSTOP: c_int = 19; +pub const SIGTSTP: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGURG: c_int = 23; +pub const SIGXCPU: c_int = 24; +pub const SIGXFSZ: c_int = 25; +pub const SIGVTALRM: c_int = 26; +pub const SIGPROF: c_int = 27; +pub const SIGWINCH: c_int = 28; +pub const SIGIO: c_int = 29; +pub const SIGPWR: c_int = 30; +pub const SIGSYS: c_int = 31; +pub const NSIG: c_int = 32; + +pub const SA_NOCLDWAIT: c_int = 0x0000_0002; +pub const SA_RESTORER: c_int = 0x0000_0004; // FIXME(redox): remove after relibc removes it +pub const SA_SIGINFO: c_int = 0x0200_0000; +pub const SA_ONSTACK: c_int = 0x0400_0000; +pub const SA_RESTART: c_int = 0x0800_0000; +pub const SA_NODEFER: c_int = 0x1000_0000; +pub const SA_RESETHAND: c_int = 0x2000_0000; +pub const SA_NOCLDSTOP: c_int = 0x4000_0000; + +// sys/file.h +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +// sys/epoll.h +pub const EPOLL_CLOEXEC: c_int = 0x0100_0000; +pub const EPOLL_CTL_ADD: c_int = 1; +pub const EPOLL_CTL_DEL: c_int = 2; +pub const EPOLL_CTL_MOD: c_int = 3; +pub const EPOLLIN: c_int = 0x001; +pub const EPOLLPRI: c_int = 0x002; +pub const EPOLLOUT: c_int = 0x004; +pub const EPOLLERR: c_int = 0x008; +pub const EPOLLHUP: c_int = 0x010; +pub const EPOLLNVAL: c_int = 0x020; +pub const EPOLLRDNORM: c_int = 0x040; +pub const EPOLLRDBAND: c_int = 0x080; +pub const EPOLLWRNORM: c_int = 0x100; +pub const EPOLLWRBAND: c_int = 0x200; +pub const EPOLLMSG: c_int = 0x400; +pub const EPOLLRDHUP: c_int = 0x2000; +pub const EPOLLEXCLUSIVE: c_int = 1 << 28; +pub const EPOLLWAKEUP: c_int = 1 << 29; +pub const EPOLLONESHOT: c_int = 1 << 30; +pub const EPOLLET: c_int = 1 << 31; + +// sys/stat.h +pub const S_IFMT: c_int = 0o17_0000; +pub const S_IFDIR: c_int = 0o4_0000; +pub const S_IFCHR: c_int = 0o2_0000; +pub const S_IFBLK: c_int = 0o6_0000; +pub const S_IFREG: c_int = 0o10_0000; +pub const S_IFIFO: c_int = 0o1_0000; +pub const S_IFLNK: c_int = 0o12_0000; +pub const S_IFSOCK: c_int = 0o14_0000; +pub const S_IRWXU: c_int = 0o0700; +pub const S_IRUSR: c_int = 0o0400; +pub const S_IWUSR: c_int = 0o0200; +pub const S_IXUSR: c_int = 0o0100; +pub const S_IRWXG: c_int = 0o0070; +pub const S_IRGRP: c_int = 0o0040; +pub const S_IWGRP: c_int = 0o0020; +pub const S_IXGRP: c_int = 0o0010; +pub const S_IRWXO: c_int = 0o0007; +pub const S_IROTH: c_int = 0o0004; +pub const S_IWOTH: c_int = 0o0002; +pub const S_IXOTH: c_int = 0o0001; + +// stdlib.h +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; + +// sys/ioctl.h +// FIXME(redox): relibc { +pub const FIONREAD: c_ulong = 0x541B; +pub const FIONBIO: c_ulong = 0x5421; +pub const FIOCLEX: c_ulong = 0x5451; +// } +pub const TCGETS: c_ulong = 0x5401; +pub const TCSETS: c_ulong = 0x5402; +pub const TCFLSH: c_ulong = 0x540B; +pub const TIOCSCTTY: c_ulong = 0x540E; +pub const TIOCGPGRP: c_ulong = 0x540F; +pub const TIOCSPGRP: c_ulong = 0x5410; +pub const TIOCGWINSZ: c_ulong = 0x5413; +pub const TIOCSWINSZ: c_ulong = 0x5414; + +// sys/mman.h +pub const PROT_NONE: c_int = 0x0000; +pub const PROT_READ: c_int = 0x0004; +pub const PROT_WRITE: c_int = 0x0002; +pub const PROT_EXEC: c_int = 0x0001; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; + +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_ANON: c_int = 0x0020; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; +pub const MAP_FIXED: c_int = 0x0004; +pub const MAP_FAILED: *mut c_void = !0 as _; + +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; +pub const MS_SYNC: c_int = 0x0004; + +// sys/resource.h +pub const RLIM_INFINITY: rlim_t = !0; +pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY; +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_RSS: c_int = 5; +pub const RLIMIT_NPROC: c_int = 6; +pub const RLIMIT_NOFILE: c_int = 7; +pub const RLIMIT_MEMLOCK: c_int = 8; +pub const RLIMIT_AS: c_int = 9; +pub const RLIMIT_LOCKS: c_int = 10; +pub const RLIMIT_SIGPENDING: c_int = 11; +pub const RLIMIT_MSGQUEUE: c_int = 12; +pub const RLIMIT_NICE: c_int = 13; +pub const RLIMIT_RTPRIO: c_int = 14; +pub const RLIMIT_NLIMITS: c_int = 15; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; +pub const RUSAGE_BOTH: c_int = -2; +pub const RUSAGE_THREAD: c_int = 1; + +// sys/select.h +pub const FD_SETSIZE: usize = 1024; + +// sys/socket.h +pub const AF_INET: c_int = 2; +pub const AF_INET6: c_int = 10; +pub const AF_UNIX: c_int = 1; +pub const AF_UNSPEC: c_int = 0; +pub const PF_INET: c_int = 2; +pub const PF_INET6: c_int = 10; +pub const PF_UNIX: c_int = 1; +pub const PF_UNSPEC: c_int = 0; +pub const MSG_CTRUNC: c_int = 8; +pub const MSG_DONTROUTE: c_int = 4; +pub const MSG_EOR: c_int = 128; +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 2; +pub const MSG_TRUNC: c_int = 32; +pub const MSG_DONTWAIT: c_int = 64; +pub const MSG_WAITALL: c_int = 256; +pub const SCM_RIGHTS: c_int = 1; +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; +pub const SO_DEBUG: c_int = 1; +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 20; +pub const SO_SNDTIMEO: c_int = 21; +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_NONBLOCK: c_int = 0o4_000; +pub const SOCK_CLOEXEC: c_int = 0o2_000_000; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOL_SOCKET: c_int = 1; +pub const SOMAXCONN: c_int = 128; + +// sys/termios.h +pub const VEOF: usize = 0; +pub const VEOL: usize = 1; +pub const VEOL2: usize = 2; +pub const VERASE: usize = 3; +pub const VWERASE: usize = 4; +pub const VKILL: usize = 5; +pub const VREPRINT: usize = 6; +pub const VSWTC: usize = 7; +pub const VINTR: usize = 8; +pub const VQUIT: usize = 9; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VLNEXT: usize = 14; +pub const VDISCARD: usize = 15; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; +pub const NCCS: usize = 32; + +pub const IGNBRK: crate::tcflag_t = 0o000_001; +pub const BRKINT: crate::tcflag_t = 0o000_002; +pub const IGNPAR: crate::tcflag_t = 0o000_004; +pub const PARMRK: crate::tcflag_t = 0o000_010; +pub const INPCK: crate::tcflag_t = 0o000_020; +pub const ISTRIP: crate::tcflag_t = 0o000_040; +pub const INLCR: crate::tcflag_t = 0o000_100; +pub const IGNCR: crate::tcflag_t = 0o000_200; +pub const ICRNL: crate::tcflag_t = 0o000_400; +pub const IXON: crate::tcflag_t = 0o001_000; +pub const IXOFF: crate::tcflag_t = 0o002_000; + +pub const OPOST: crate::tcflag_t = 0o000_001; +pub const ONLCR: crate::tcflag_t = 0o000_002; +pub const OLCUC: crate::tcflag_t = 0o000_004; +pub const OCRNL: crate::tcflag_t = 0o000_010; +pub const ONOCR: crate::tcflag_t = 0o000_020; +pub const ONLRET: crate::tcflag_t = 0o000_040; +pub const OFILL: crate::tcflag_t = 0o0000_100; +pub const OFDEL: crate::tcflag_t = 0o0000_200; + +pub const B0: speed_t = 0o000_000; +pub const B50: speed_t = 0o000_001; +pub const B75: speed_t = 0o000_002; +pub const B110: speed_t = 0o000_003; +pub const B134: speed_t = 0o000_004; +pub const B150: speed_t = 0o000_005; +pub const B200: speed_t = 0o000_006; +pub const B300: speed_t = 0o000_007; +pub const B600: speed_t = 0o000_010; +pub const B1200: speed_t = 0o000_011; +pub const B1800: speed_t = 0o000_012; +pub const B2400: speed_t = 0o000_013; +pub const B4800: speed_t = 0o000_014; +pub const B9600: speed_t = 0o000_015; +pub const B19200: speed_t = 0o000_016; +pub const B38400: speed_t = 0o000_017; + +pub const B57600: speed_t = 0o0_020; +pub const B115200: speed_t = 0o0_021; +pub const B230400: speed_t = 0o0_022; +pub const B460800: speed_t = 0o0_023; +pub const B500000: speed_t = 0o0_024; +pub const B576000: speed_t = 0o0_025; +pub const B921600: speed_t = 0o0_026; +pub const B1000000: speed_t = 0o0_027; +pub const B1152000: speed_t = 0o0_030; +pub const B1500000: speed_t = 0o0_031; +pub const B2000000: speed_t = 0o0_032; +pub const B2500000: speed_t = 0o0_033; +pub const B3000000: speed_t = 0o0_034; +pub const B3500000: speed_t = 0o0_035; +pub const B4000000: speed_t = 0o0_036; + +pub const CSIZE: crate::tcflag_t = 0o001_400; +pub const CS5: crate::tcflag_t = 0o000_000; +pub const CS6: crate::tcflag_t = 0o000_400; +pub const CS7: crate::tcflag_t = 0o001_000; +pub const CS8: crate::tcflag_t = 0o001_400; + +pub const CSTOPB: crate::tcflag_t = 0o002_000; +pub const CREAD: crate::tcflag_t = 0o004_000; +pub const PARENB: crate::tcflag_t = 0o010_000; +pub const PARODD: crate::tcflag_t = 0o020_000; +pub const HUPCL: crate::tcflag_t = 0o040_000; + +pub const CLOCAL: crate::tcflag_t = 0o0100000; + +pub const ISIG: crate::tcflag_t = 0x0000_0080; +pub const ICANON: crate::tcflag_t = 0x0000_0100; +pub const ECHO: crate::tcflag_t = 0x0000_0008; +pub const ECHOE: crate::tcflag_t = 0x0000_0002; +pub const ECHOK: crate::tcflag_t = 0x0000_0004; +pub const ECHONL: crate::tcflag_t = 0x0000_0010; +pub const NOFLSH: crate::tcflag_t = 0x8000_0000; +pub const TOSTOP: crate::tcflag_t = 0x0040_0000; +pub const IEXTEN: crate::tcflag_t = 0x0000_0400; + +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; + +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +// sys/wait.h +pub const WNOHANG: c_int = 1; +pub const WUNTRACED: c_int = 2; + +pub const WSTOPPED: c_int = 2; +pub const WEXITED: c_int = 4; +pub const WCONTINUED: c_int = 8; +pub const WNOWAIT: c_int = 0x0100_0000; + +pub const __WNOTHREAD: c_int = 0x2000_0000; +pub const __WALL: c_int = 0x4000_0000; +#[allow(overflowing_literals)] +pub const __WCLONE: c_int = 0x8000_0000; + +// time.h +pub const CLOCK_REALTIME: c_int = 1; +pub const CLOCK_MONOTONIC: c_int = 4; +pub const CLOCK_PROCESS_CPUTIME_ID: crate::clockid_t = 2; +pub const CLOCKS_PER_SEC: crate::clock_t = 1_000_000; + +// unistd.h +// POSIX.1 { +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +// ... +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = 30; +// ... +pub const _SC_RE_DUP_MAX: c_int = 44; + +pub const _SC_NPROCESSORS_CONF: c_int = 57; +pub const _SC_NPROCESSORS_ONLN: c_int = 58; + +// ... +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +// ... +pub const _SC_SYMLOOP_MAX: c_int = 173; +// ... +pub const _SC_HOST_NAME_MAX: c_int = 180; +// ... +pub const _SC_SIGQUEUE_MAX: c_int = 190; +pub const _SC_REALTIME_SIGNALS: c_int = 191; +// } POSIX.1 + +// confstr +pub const _CS_PATH: c_int = 0; +pub const _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS: c_int = 1; +pub const _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS: c_int = 4; +pub const _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS: c_int = 5; +pub const _CS_POSIX_V6_ILP32_OFF32_CFLAGS: c_int = 1116; +pub const _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: c_int = 1117; +pub const _CS_POSIX_V6_ILP32_OFF32_LIBS: c_int = 1118; +pub const _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS: c_int = 1119; +pub const _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: c_int = 1120; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: c_int = 1121; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LIBS: c_int = 1122; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS: c_int = 1123; +pub const _CS_POSIX_V6_LP64_OFF64_CFLAGS: c_int = 1124; +pub const _CS_POSIX_V6_LP64_OFF64_LDFLAGS: c_int = 1125; +pub const _CS_POSIX_V6_LP64_OFF64_LIBS: c_int = 1126; +pub const _CS_POSIX_V6_LP64_OFF64_LINTFLAGS: c_int = 1127; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: c_int = 1128; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: c_int = 1129; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: c_int = 1130; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS: c_int = 1131; +pub const _CS_POSIX_V7_ILP32_OFF32_CFLAGS: c_int = 1132; +pub const _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: c_int = 1133; +pub const _CS_POSIX_V7_ILP32_OFF32_LIBS: c_int = 1134; +pub const _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: c_int = 1135; +pub const _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: c_int = 1136; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: c_int = 1137; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LIBS: c_int = 1138; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: c_int = 1139; +pub const _CS_POSIX_V7_LP64_OFF64_CFLAGS: c_int = 1140; +pub const _CS_POSIX_V7_LP64_OFF64_LDFLAGS: c_int = 1141; +pub const _CS_POSIX_V7_LP64_OFF64_LIBS: c_int = 1142; +pub const _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: c_int = 1143; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: c_int = 1144; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: c_int = 1145; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: c_int = 1146; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS: c_int = 1147; + +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; + +// stdio.h +pub const BUFSIZ: c_uint = 1024; +pub const _IOFBF: c_int = 0; +pub const _IOLBF: c_int = 1; +pub const _IONBF: c_int = 2; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; + +pub const _PC_LINK_MAX: c_int = 0; +pub const _PC_MAX_CANON: c_int = 1; +pub const _PC_MAX_INPUT: c_int = 2; +pub const _PC_NAME_MAX: c_int = 3; +pub const _PC_PATH_MAX: c_int = 4; +pub const _PC_PIPE_BUF: c_int = 5; +pub const _PC_CHOWN_RESTRICTED: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_SYNC_IO: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SOCK_MAXBUF: c_int = 12; +pub const _PC_FILESIZEBITS: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: c_int = 18; +pub const _PC_SYMLINK_MAX: c_int = 19; +pub const _PC_2_SYMLINKS: c_int = 20; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const RENAME_NOREPLACE: c_uint = 1; + +f! { + //sys/socket.h + pub const fn CMSG_ALIGN(len: size_t) -> size_t { + (len + size_of::() - 1) & !(size_of::() - 1) + } + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + (CMSG_ALIGN(size_of::()) + length as usize) as c_uint + } + pub const fn CMSG_SPACE(len: c_uint) -> c_uint { + (CMSG_ALIGN(len as size_t) + CMSG_ALIGN(size_of::())) as c_uint + } + + // wait.h + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +safe_f! { + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + status == 0xffff + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7f + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0x7f) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xff + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn makedev(major: c_uint, minor: c_uint) -> dev_t { + let major = major as dev_t; + let minor = minor as dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } + + pub const fn major(dev: dev_t) -> c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as c_uint + } + + pub const fn minor(dev: dev_t) -> c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as c_uint + } +} + +extern "C" { + // errno.h + pub fn __errno_location() -> *mut c_int; + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + // dirent.h + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + // unistd.h + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + pub fn getdtablesize() -> c_int; + pub fn getresgid( + rgid: *mut crate::gid_t, + egid: *mut crate::gid_t, + sgid: *mut crate::gid_t, + ) -> c_int; + pub fn getresuid( + ruid: *mut crate::uid_t, + euid: *mut crate::uid_t, + suid: *mut crate::uid_t, + ) -> c_int; + pub fn setresgid(rgid: crate::gid_t, egid: crate::gid_t, sgid: crate::gid_t) -> c_int; + pub fn setresuid(ruid: crate::uid_t, euid: crate::uid_t, suid: crate::uid_t) -> c_int; + + // grp.h + pub fn getgrent() -> *mut crate::group; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn getgrouplist( + user: *const c_char, + group: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + + // malloc.h + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + + // netdb.h + pub fn getnameinfo( + addr: *const crate::sockaddr, + addrlen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + + // pthread.h + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn pthread_create( + tid: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + start: extern "C" fn(*mut c_void) -> *mut c_void, + arg: *mut c_void, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + + //pty.h + pub fn openpty( + amaster: *mut c_int, + aslave: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, + ) -> c_int; + + // pwd.h + pub fn getpwent() -> *mut passwd; + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + + // semaphore.h + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + pub fn sem_clockwait( + sem: *mut sem_t, + clock_id: clockid_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + + // signal.h + pub fn pthread_sigmask( + how: c_int, + set: *const crate::sigset_t, + oldset: *mut crate::sigset_t, + ) -> c_int; + pub fn pthread_cancel(thread: crate::pthread_t) -> c_int; + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sigtimedwait( + set: *const sigset_t, + sig: *mut siginfo_t, + timeout: *const crate::timespec, + ) -> c_int; + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + + // stdlib.h + pub fn getsubopt( + optionp: *mut *mut c_char, + tokens: *const *mut c_char, + valuep: *mut *mut c_char, + ) -> c_int; + pub fn mkostemp(template: *mut c_char, flags: c_int) -> c_int; + pub fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int; + pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void; + + // stdio.h + pub fn renameat2( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_uint, + ) -> c_int; + + // string.h + pub fn explicit_bzero(p: *mut c_void, len: size_t); + pub fn strlcat(dst: *mut c_char, src: *const c_char, siz: size_t) -> size_t; + pub fn strlcpy(dst: *mut c_char, src: *const c_char, siz: size_t) -> size_t; + + // sys/epoll.h + pub fn epoll_create(size: c_int) -> c_int; + pub fn epoll_create1(flags: c_int) -> c_int; + pub fn epoll_wait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + ) -> c_int; + pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut crate::epoll_event) -> c_int; + + // sys/ioctl.h + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; + + // sys/mman.h + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + // sys/resource.h + pub fn getpriority(which: c_int, who: crate::id_t) -> c_int; + pub fn setpriority(which: c_int, who: crate::id_t, prio: c_int) -> c_int; + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + + // sys/socket.h + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar; + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr; + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr; + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn recvmsg(socket: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t; + pub fn sendmsg(socket: c_int, msg: *const msghdr, flags: c_int) -> ssize_t; + + // sys/stat.h + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + + // sys/uio.h + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + // sys/utsname.h + pub fn uname(utsname: *mut utsname) -> c_int; + + // time.h + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut crate::timezone) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn strftime( + s: *mut c_char, + max: size_t, + format: *const c_char, + tm: *const crate::tm, + ) -> size_t; + + // utmp.h + pub fn login_tty(fd: c_int) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/compat.rs b/deps/crates/vendor/libc/src/unix/solarish/compat.rs new file mode 100644 index 00000000000000..6876a9d8fd3193 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/compat.rs @@ -0,0 +1,222 @@ +// Common functions that are unfortunately missing on illumos and +// Solaris, but often needed by other crates. +use core::cmp::min; + +use crate::unix::solarish::*; +use crate::{ + c_char, + c_int, + size_t, +}; + +pub unsafe fn cfmakeraw(termios: *mut crate::termios) { + (*termios).c_iflag &= + !(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + (*termios).c_oflag &= !OPOST; + (*termios).c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + (*termios).c_cflag &= !(CSIZE | PARENB); + (*termios).c_cflag |= CS8; + + // By default, most software expects a pending read to block until at + // least one byte becomes available. As per termio(7I), this requires + // setting the MIN and TIME parameters appropriately. + // + // As a somewhat unfortunate artefact of history, the MIN and TIME slots + // in the control character array overlap with the EOF and EOL slots used + // for canonical mode processing. Because the EOF character needs to be + // the ASCII EOT value (aka Control-D), it has the byte value 4. When + // switching to raw mode, this is interpreted as a MIN value of 4; i.e., + // reads will block until at least four bytes have been input. + // + // Other platforms with a distinct MIN slot like Linux and FreeBSD appear + // to default to a MIN value of 1, so we'll force that value here: + (*termios).c_cc[VMIN] = 1; + (*termios).c_cc[VTIME] = 0; +} + +pub unsafe fn cfsetspeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int { + // Neither of these functions on illumos or Solaris actually ever + // return an error + crate::cfsetispeed(termios, speed); + crate::cfsetospeed(termios, speed); + 0 +} + +#[cfg(target_os = "illumos")] +unsafe fn bail(fdm: c_int, fds: c_int) -> c_int { + let e = *___errno(); + if fds >= 0 { + crate::close(fds); + } + if fdm >= 0 { + crate::close(fdm); + } + *___errno() = e; + -1 +} + +#[cfg(target_os = "illumos")] +pub unsafe fn openpty( + amain: *mut c_int, + asubord: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, +) -> c_int { + const PTEM: &[u8] = b"ptem\0"; + const LDTERM: &[u8] = b"ldterm\0"; + + // Open the main pseudo-terminal device, making sure not to set it as the + // controlling terminal for this process: + let fdm = crate::posix_openpt(O_RDWR | O_NOCTTY); + if fdm < 0 { + return -1; + } + + // Set permissions and ownership on the subordinate device and unlock it: + if crate::grantpt(fdm) < 0 || crate::unlockpt(fdm) < 0 { + return bail(fdm, -1); + } + + // Get the path name of the subordinate device: + let subordpath = crate::ptsname(fdm); + if subordpath.is_null() { + return bail(fdm, -1); + } + + // Open the subordinate device without setting it as the controlling + // terminal for this process: + let fds = crate::open(subordpath, O_RDWR | O_NOCTTY); + if fds < 0 { + return bail(fdm, -1); + } + + // Check if the STREAMS modules are already pushed: + let setup = crate::ioctl(fds, I_FIND, LDTERM.as_ptr()); + if setup < 0 { + return bail(fdm, fds); + } else if setup == 0 { + // The line discipline is not present, so push the appropriate STREAMS + // modules for the subordinate device: + if crate::ioctl(fds, I_PUSH, PTEM.as_ptr()) < 0 + || crate::ioctl(fds, I_PUSH, LDTERM.as_ptr()) < 0 + { + return bail(fdm, fds); + } + } + + // If provided, set the terminal parameters: + if !termp.is_null() && crate::tcsetattr(fds, TCSAFLUSH, termp) != 0 { + return bail(fdm, fds); + } + + // If provided, set the window size: + if !winp.is_null() && crate::ioctl(fds, TIOCSWINSZ, winp) < 0 { + return bail(fdm, fds); + } + + // If the caller wants the name of the subordinate device, copy it out. + // + // Note that this is a terrible interface: there appears to be no standard + // upper bound on the copy length for this pointer. Nobody should pass + // anything but NULL here, preferring instead to use ptsname(3C) directly. + if !name.is_null() { + crate::strcpy(name, subordpath); + } + + *amain = fdm; + *asubord = fds; + 0 +} + +#[cfg(target_os = "illumos")] +pub unsafe fn forkpty( + amain: *mut c_int, + name: *mut c_char, + termp: *const termios, + winp: *const crate::winsize, +) -> crate::pid_t { + let mut fds = -1; + + if openpty(amain, &mut fds, name, termp, winp) != 0 { + return -1; + } + + let pid = crate::fork(); + if pid < 0 { + return bail(*amain, fds); + } else if pid > 0 { + // In the parent process, we close the subordinate device and return the + // process ID of the new child: + crate::close(fds); + return pid; + } + + // The rest of this function executes in the child process. + + // Close the main side of the pseudo-terminal pair: + crate::close(*amain); + + // Use TIOCSCTTY to set the subordinate device as our controlling + // terminal. This will fail (with ENOTTY) if we are not the leader in + // our own session, so we call setsid() first. Finally, arrange for + // the pseudo-terminal to occupy the standard I/O descriptors. + if crate::setsid() < 0 + || crate::ioctl(fds, TIOCSCTTY, 0) < 0 + || crate::dup2(fds, 0) < 0 + || crate::dup2(fds, 1) < 0 + || crate::dup2(fds, 2) < 0 + { + // At this stage there are no particularly good ways to handle failure. + // Exit as abruptly as possible, using _exit() to avoid messing with any + // state still shared with the parent process. + crate::_exit(EXIT_FAILURE); + } + // Close the inherited descriptor, taking care to avoid closing the standard + // descriptors by mistake: + if fds > 2 { + crate::close(fds); + } + + 0 +} + +pub unsafe fn getpwent_r( + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, +) -> c_int { + let old_errno = *crate::___errno(); + *crate::___errno() = 0; + *result = native_getpwent_r(pwd, buf, min(buflen, c_int::MAX as size_t) as c_int); + + let ret = if (*result).is_null() { + *crate::___errno() + } else { + 0 + }; + *crate::___errno() = old_errno; + + ret +} + +pub unsafe fn getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, +) -> c_int { + let old_errno = *crate::___errno(); + *crate::___errno() = 0; + *result = native_getgrent_r(grp, buf, min(buflen, c_int::MAX as size_t) as c_int); + + let ret = if (*result).is_null() { + *crate::___errno() + } else { + 0 + }; + *crate::___errno() = old_errno; + + ret +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/illumos.rs b/deps/crates/vendor/libc/src/unix/solarish/illumos.rs new file mode 100644 index 00000000000000..50e6302e7c9e75 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/illumos.rs @@ -0,0 +1,292 @@ +use crate::prelude::*; +use crate::{ + exit_status, + off_t, + NET_MAC_AWARE, + NET_MAC_AWARE_INHERIT, + PRIV_AWARE_RESET, + PRIV_DEBUG, + PRIV_PFEXEC, + PRIV_XPOLICY, +}; + +pub type lgrp_rsrc_t = c_int; +pub type lgrp_affinity_t = c_int; + +s! { + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_offset: off_t, + pub aio_reqprio: c_int, + pub aio_sigevent: crate::sigevent, + pub aio_lio_opcode: c_int, + pub aio_resultp: crate::aio_result_t, + pub aio_state: c_int, + pub aio__pad: [c_int; 1], + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_amp: *mut c_void, + pub shm_lkcnt: c_ushort, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_cnattch: c_ulong, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_pad4: [i64; 4], + } + + pub struct fil_info { + pub fi_flags: c_int, + pub fi_pos: c_int, + pub fi_name: [c_char; crate::FILNAME_MAX as usize], + } + + #[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed(4)))] + pub struct epoll_event { + pub events: u32, + pub u64: u64, + } + + pub struct utmpx { + pub ut_user: [c_char; _UTX_USERSIZE], + pub ut_id: [c_char; _UTX_IDSIZE], + pub ut_line: [c_char; _UTX_LINESIZE], + pub ut_pid: crate::pid_t, + pub ut_type: c_short, + pub ut_exit: exit_status, + pub ut_tv: crate::timeval, + pub ut_session: c_int, + pub ut_pad: [c_int; _UTX_PADSIZE], + pub ut_syslen: c_short, + pub ut_host: [c_char; _UTX_HOSTSIZE], + } +} + +pub const _UTX_USERSIZE: usize = 32; +pub const _UTX_LINESIZE: usize = 32; +pub const _UTX_PADSIZE: usize = 5; +pub const _UTX_IDSIZE: usize = 4; +pub const _UTX_HOSTSIZE: usize = 257; + +pub const AF_LOCAL: c_int = 1; // AF_UNIX +pub const AF_FILE: c_int = 1; // AF_UNIX + +pub const EFD_SEMAPHORE: c_int = 0x1; +pub const EFD_NONBLOCK: c_int = 0x800; +pub const EFD_CLOEXEC: c_int = 0x80000; + +pub const POLLRDHUP: c_short = 0x4000; + +pub const TCP_KEEPIDLE: c_int = 34; +pub const TCP_KEEPCNT: c_int = 35; +pub const TCP_KEEPINTVL: c_int = 36; +pub const TCP_CONGESTION: c_int = 37; + +// These constants are correct for 64-bit programs or 32-bit programs that are +// not using large-file mode. If Rust ever supports anything other than 64-bit +// compilation on illumos, this may require adjustment: +pub const F_OFD_GETLK: c_int = 47; +pub const F_OFD_SETLK: c_int = 48; +pub const F_OFD_SETLKW: c_int = 49; +pub const F_FLOCK: c_int = 53; +pub const F_FLOCKW: c_int = 54; + +pub const F_DUPFD_CLOEXEC: c_int = 37; +pub const F_DUPFD_CLOFORK: c_int = 58; +pub const F_DUP2FD_CLOEXEC: c_int = 36; +pub const F_DUP2FD_CLOFORK: c_int = 57; +pub const F_DUP3FD: c_int = 59; + +pub const FD_CLOFORK: c_int = 2; + +pub const FIL_ATTACH: c_int = 0x1; +pub const FIL_DETACH: c_int = 0x2; +pub const FIL_LIST: c_int = 0x3; +pub const FILNAME_MAX: c_int = 32; +pub const FILF_PROG: c_int = 0x1; +pub const FILF_AUTO: c_int = 0x2; +pub const FILF_BYPASS: c_int = 0x4; +pub const SOL_FILTER: c_int = 0xfffc; + +pub const MADV_PURGE: c_int = 9; + +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: c_int = 2; +pub const POSIX_FADV_WILLNEED: c_int = 3; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; + +pub const POSIX_SPAWN_SETSID: c_short = 0x40; + +pub const SIGINFO: c_int = 41; + +pub const O_DIRECT: c_int = 0x2000000; +pub const O_CLOFORK: c_int = 0x4000000; + +pub const MSG_CMSG_CLOEXEC: c_int = 0x1000; +pub const MSG_CMSG_CLOFORK: c_int = 0x2000; + +pub const PBIND_HARD: crate::processorid_t = -3; +pub const PBIND_SOFT: crate::processorid_t = -4; + +pub const PS_SYSTEM: c_int = 1; + +pub const MAP_FILE: c_int = 0; + +pub const MAP_32BIT: c_int = 0x80; + +pub const AF_NCA: c_int = 28; + +pub const PF_NCA: c_int = AF_NCA; + +pub const LOCK_SH: c_int = 1; +pub const LOCK_EX: c_int = 2; +pub const LOCK_NB: c_int = 4; +pub const LOCK_UN: c_int = 8; + +pub const _PC_LAST: c_int = 101; + +pub const _CS_PATH: c_int = 65; + +pub const VSTATUS: usize = 16; +pub const VERASE2: usize = 17; + +pub const EPOLLIN: c_int = 0x1; +pub const EPOLLPRI: c_int = 0x2; +pub const EPOLLOUT: c_int = 0x4; +pub const EPOLLRDNORM: c_int = 0x40; +pub const EPOLLRDBAND: c_int = 0x80; +pub const EPOLLWRNORM: c_int = 0x100; +pub const EPOLLWRBAND: c_int = 0x200; +pub const EPOLLMSG: c_int = 0x400; +pub const EPOLLERR: c_int = 0x8; +pub const EPOLLHUP: c_int = 0x10; +pub const EPOLLET: c_int = 0x80000000; +pub const EPOLLRDHUP: c_int = 0x2000; +pub const EPOLLONESHOT: c_int = 0x40000000; +pub const EPOLLWAKEUP: c_int = 0x20000000; +pub const EPOLLEXCLUSIVE: c_int = 0x10000000; +pub const EPOLL_CLOEXEC: c_int = 0x80000; +pub const EPOLL_CTL_ADD: c_int = 1; +pub const EPOLL_CTL_MOD: c_int = 3; +pub const EPOLL_CTL_DEL: c_int = 2; + +pub const PRIV_USER: c_uint = PRIV_DEBUG + | NET_MAC_AWARE + | NET_MAC_AWARE_INHERIT + | PRIV_XPOLICY + | PRIV_AWARE_RESET + | PRIV_PFEXEC; + +pub const LGRP_RSRC_COUNT: crate::lgrp_rsrc_t = 2; +pub const LGRP_RSRC_CPU: crate::lgrp_rsrc_t = 0; +pub const LGRP_RSRC_MEM: crate::lgrp_rsrc_t = 1; + +pub const P_DISABLED: c_int = 0x008; + +pub const AT_SUN_HWCAP2: c_uint = 2023; +pub const AT_SUN_FPTYPE: c_uint = 2027; + +pub const B1000000: crate::speed_t = 24; +pub const B1152000: crate::speed_t = 25; +pub const B1500000: crate::speed_t = 26; +pub const B2000000: crate::speed_t = 27; +pub const B2500000: crate::speed_t = 28; +pub const B3000000: crate::speed_t = 29; +pub const B3500000: crate::speed_t = 30; +pub const B4000000: crate::speed_t = 31; + +// sys/systeminfo.h +pub const SI_ADDRESS_WIDTH: c_int = 520; + +// sys/timerfd.h +pub const TFD_CLOEXEC: i32 = 0o2000000; +pub const TFD_NONBLOCK: i32 = 0o4000; +pub const TFD_TIMER_ABSTIME: i32 = 1 << 0; +pub const TFD_TIMER_CANCEL_ON_SET: i32 = 1 << 1; + +extern "C" { + pub fn eventfd(initval: c_uint, flags: c_int) -> c_int; + + pub fn epoll_pwait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + sigmask: *const crate::sigset_t, + ) -> c_int; + pub fn epoll_create(size: c_int) -> c_int; + pub fn epoll_create1(flags: c_int) -> c_int; + pub fn epoll_wait( + epfd: c_int, + events: *mut crate::epoll_event, + maxevents: c_int, + timeout: c_int, + ) -> c_int; + pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut crate::epoll_event) -> c_int; + + pub fn mincore(addr: crate::caddr_t, len: size_t, vec: *mut c_char) -> c_int; + + pub fn pset_bind_lwp( + pset: crate::psetid_t, + id: crate::id_t, + pid: crate::pid_t, + opset: *mut crate::psetid_t, + ) -> c_int; + pub fn pset_getloadavg(pset: crate::psetid_t, load: *mut c_double, num: c_int) -> c_int; + + pub fn pthread_attr_get_np(thread: crate::pthread_t, attr: *mut crate::pthread_attr_t) + -> c_int; + pub fn pthread_attr_getstackaddr( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + ) -> c_int; + pub fn pthread_attr_setstack( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + stacksize: size_t, + ) -> c_int; + pub fn pthread_attr_setstackaddr( + attr: *mut crate::pthread_attr_t, + stackaddr: *mut c_void, + ) -> c_int; + + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advice: c_int) -> c_int; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn getpagesizes2(pagesize: *mut size_t, nelem: c_int) -> c_int; + + pub fn posix_spawn_file_actions_addfchdir_np( + file_actions: *mut crate::posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + + pub fn ptsname_r(fildes: c_int, name: *mut c_char, namelen: size_t) -> c_int; + + pub fn syncfs(fd: c_int) -> c_int; + + pub fn strcasecmp_l(s1: *const c_char, s2: *const c_char, loc: crate::locale_t) -> c_int; + pub fn strncasecmp_l( + s1: *const c_char, + s2: *const c_char, + n: size_t, + loc: crate::locale_t, + ) -> c_int; + + pub fn timerfd_create(clockid: c_int, flags: c_int) -> c_int; + pub fn timerfd_gettime(fd: c_int, curr_value: *mut crate::itimerspec) -> c_int; + pub fn timerfd_settime( + fd: c_int, + flags: c_int, + new_value: *const crate::itimerspec, + old_value: *mut crate::itimerspec, + ) -> c_int; +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/mod.rs b/deps/crates/vendor/libc/src/unix/solarish/mod.rs new file mode 100644 index 00000000000000..494ecdb7d95cf7 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/mod.rs @@ -0,0 +1,3049 @@ +use crate::prelude::*; + +pub type caddr_t = *mut c_char; + +pub type clockid_t = c_int; +pub type blkcnt_t = c_long; +pub type clock_t = c_long; +pub type daddr_t = c_long; +pub type dev_t = c_ulong; +pub type fsblkcnt_t = c_ulong; +pub type fsfilcnt_t = c_ulong; +pub type ino_t = c_ulong; +pub type key_t = c_int; +pub type major_t = c_uint; +pub type minor_t = c_uint; +pub type mode_t = c_uint; +pub type nlink_t = c_uint; +pub type rlim_t = c_ulong; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type time_t = c_long; +pub type timer_t = c_int; +pub type wchar_t = c_int; +pub type nfds_t = c_ulong; +pub type projid_t = c_int; +pub type zoneid_t = c_int; +pub type psetid_t = c_int; +pub type processorid_t = c_int; +pub type chipid_t = c_int; +pub type ctid_t = crate::id_t; + +pub type suseconds_t = c_long; +pub type off_t = c_long; +pub type useconds_t = c_uint; +pub type socklen_t = c_uint; +pub type sa_family_t = u16; +pub type pthread_t = c_uint; +pub type pthread_key_t = c_uint; +pub type thread_t = c_uint; +pub type blksize_t = c_int; +pub type nl_item = c_int; +pub type mqd_t = *mut c_void; +pub type id_t = c_int; +pub type idtype_t = c_uint; +pub type shmatt_t = c_ulong; + +pub type lgrp_id_t = crate::id_t; +pub type lgrp_mem_size_t = c_longlong; +pub type lgrp_cookie_t = crate::uintptr_t; +pub type lgrp_content_t = c_uint; +pub type lgrp_lat_between_t = c_uint; +pub type lgrp_mem_size_flag_t = c_uint; +pub type lgrp_view_t = c_uint; + +pub type posix_spawnattr_t = *mut c_void; +pub type posix_spawn_file_actions_t = *mut c_void; + +extern_ty! { + pub enum timezone {} + pub enum ucred_t {} +} + +s! { + pub struct in_addr { + pub s_addr: crate::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_sourceaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ipc_perm { + pub uid: crate::uid_t, + pub gid: crate::gid_t, + pub cuid: crate::uid_t, + pub cgid: crate::gid_t, + pub mode: mode_t, + pub seq: c_uint, + pub key: crate::key_t, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: crate::in_port_t, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: crate::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + pub __sin6_src_id: u32, + } + + pub struct in_pktinfo { + pub ipi_ifindex: c_uint, + pub ipi_spec_dst: crate::in_addr, + pub ipi_addr: crate::in_addr, + } + + pub struct in6_pktinfo { + pub ipi6_addr: crate::in6_addr, + pub ipi6_ifindex: c_uint, + } + + pub struct passwd { + pub pw_name: *mut c_char, + pub pw_passwd: *mut c_char, + pub pw_uid: crate::uid_t, + pub pw_gid: crate::gid_t, + pub pw_age: *mut c_char, + pub pw_comment: *mut c_char, + pub pw_gecos: *mut c_char, + pub pw_dir: *mut c_char, + pub pw_shell: *mut c_char, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: u64, + pub ifa_addr: *mut crate::sockaddr, + pub ifa_netmask: *mut crate::sockaddr, + pub ifa_dstaddr: *mut crate::sockaddr, + pub ifa_data: *mut c_void, + } + + pub struct itimerspec { + pub it_interval: crate::timespec, + pub it_value: crate::timespec, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: crate::socklen_t, + pub msg_iov: *mut crate::iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: crate::socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: crate::socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + pub struct pthread_attr_t { + __pthread_attrp: *mut c_void, + } + + pub struct pthread_mutex_t { + __pthread_mutex_flag1: u16, + __pthread_mutex_flag2: u8, + __pthread_mutex_ceiling: u8, + __pthread_mutex_type: u16, + __pthread_mutex_magic: u16, + __pthread_mutex_lock: u64, + __pthread_mutex_data: u64, + } + + pub struct pthread_mutexattr_t { + __pthread_mutexattrp: *mut c_void, + } + + pub struct pthread_cond_t { + __pthread_cond_flag: [u8; 4], + __pthread_cond_type: u16, + __pthread_cond_magic: u16, + __pthread_cond_data: u64, + } + + pub struct pthread_condattr_t { + __pthread_condattrp: *mut c_void, + } + + pub struct pthread_rwlock_t { + __pthread_rwlock_readers: i32, + __pthread_rwlock_type: u16, + __pthread_rwlock_magic: u16, + __pthread_rwlock_mutex: crate::pthread_mutex_t, + __pthread_rwlock_readercv: crate::pthread_cond_t, + __pthread_rwlock_writercv: crate::pthread_cond_t, + } + + pub struct pthread_rwlockattr_t { + __pthread_rwlockattrp: *mut c_void, + } + + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_off: off_t, + pub d_reclen: u16, + pub d_name: [c_char; 3], + } + + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: size_t, + __unused1: Padding<*mut c_void>, + __unused2: Padding, + #[cfg(target_os = "illumos")] + __unused3: Padding, + #[cfg(target_os = "illumos")] + __unused4: Padding, + #[cfg(target_os = "illumos")] + __unused5: Padding<*mut c_void>, + #[cfg(target_os = "illumos")] + __unused6: Padding<*mut c_void>, + #[cfg(target_os = "illumos")] + __unused7: Padding<*mut c_void>, + #[cfg(target_os = "illumos")] + __unused8: Padding<*mut c_void>, + #[cfg(target_os = "illumos")] + __unused9: Padding<*mut c_void>, + #[cfg(target_os = "illumos")] + __unused10: Padding<*mut c_void>, + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + #[cfg(target_arch = "sparc64")] + __sparcv9_pad: Padding, + pub ai_addrlen: crate::socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct sigset_t { + bits: [u32; 4], + } + + pub struct sigaction { + pub sa_flags: c_int, + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: sigset_t, + } + + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: crate::fsblkcnt_t, + pub f_bfree: crate::fsblkcnt_t, + pub f_bavail: crate::fsblkcnt_t, + pub f_files: crate::fsfilcnt_t, + pub f_ffree: crate::fsfilcnt_t, + pub f_favail: crate::fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_basetype: [c_char; 16], + pub f_flag: c_ulong, + pub f_namemax: c_ulong, + pub f_fstr: [c_char; 32], + } + + pub struct sendfilevec_t { + pub sfv_fd: c_int, + pub sfv_flag: c_uint, + pub sfv_off: off_t, + pub sfv_len: size_t, + } + + pub struct sched_param { + pub sched_priority: c_int, + sched_pad: Padding<[c_int; 8]>, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + pub st_atime: crate::time_t, + pub st_atime_nsec: c_long, + pub st_mtime: crate::time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: crate::time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_fstype: [c_char; _ST_FSTYPSZ as usize], + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct sem_t { + pub sem_count: u32, + pub sem_type: u16, + pub sem_magic: u16, + pub sem_pad1: [u64; 3], + pub sem_pad2: [u64; 2], + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: off_t, + pub l_len: off_t, + pub l_sysid: c_int, + pub l_pid: crate::pid_t, + pub l_pad: [c_long; 4], + } + + pub struct if_nameindex { + pub if_index: c_uint, + pub if_name: *mut c_char, + } + + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + _pad: Padding<[c_int; 12]>, + } + + pub struct port_event { + pub portev_events: c_int, + pub portev_source: c_ushort, + pub portev_pad: c_ushort, + pub portev_object: crate::uintptr_t, + pub portev_user: *mut c_void, + } + + pub struct port_notify { + pub portnfy_port: c_int, + pub portnfy_user: *mut c_void, + } + + pub struct aio_result_t { + pub aio_return: ssize_t, + pub aio_errno: c_int, + } + + pub struct exit_status { + e_termination: c_short, + e_exit: c_short, + } + + pub struct utmp { + pub ut_user: [c_char; 8], + pub ut_id: [c_char; 4], + pub ut_line: [c_char; 12], + pub ut_pid: c_short, + pub ut_type: c_short, + pub ut_exit: exit_status, + pub ut_time: crate::time_t, + } + + pub struct timex { + pub modes: u32, + pub offset: i32, + pub freq: i32, + pub maxerror: i32, + pub esterror: i32, + pub status: i32, + pub constant: i32, + pub precision: i32, + pub tolerance: i32, + pub ppsfreq: i32, + pub jitter: i32, + pub shift: i32, + pub stabil: i32, + pub jitcnt: i32, + pub calcnt: i32, + pub errcnt: i32, + pub stbcnt: i32, + } + + pub struct ntptimeval { + pub time: crate::timeval, + pub maxerror: i32, + pub esterror: i32, + } + + pub struct mmapobj_result_t { + pub mr_addr: crate::caddr_t, + pub mr_msize: size_t, + pub mr_fsize: size_t, + pub mr_offset: size_t, + pub mr_prot: c_uint, + pub mr_flags: c_uint, + } + + pub struct lgrp_affinity_args_t { + pub idtype: crate::idtype_t, + pub id: crate::id_t, + pub lgrp: crate::lgrp_id_t, + pub aff: crate::lgrp_affinity_t, + } + + pub struct processor_info_t { + pub pi_state: c_int, + pub pi_processor_type: [c_char; PI_TYPELEN as usize], + pub pi_fputypes: [c_char; PI_FPUTYPE as usize], + pub pi_clock: c_int, + } + + pub struct option { + pub name: *const c_char, + pub has_arg: c_int, + pub flag: *mut c_int, + pub val: c_int, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], + } + + pub struct utsname { + pub sysname: [c_char; 257], + pub nodename: [c_char; 257], + pub release: [c_char; 257], + pub version: [c_char; 257], + pub machine: [c_char; 257], + } + + pub struct fd_set { + #[cfg(target_pointer_width = "64")] + fds_bits: [i64; FD_SETSIZE as usize / 64], + #[cfg(target_pointer_width = "32")] + fds_bits: [i32; FD_SETSIZE as usize / 32], + } + + pub struct sockaddr_storage { + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[u8; 6]>, + __ss_align: i64, + __ss_pad2: Padding<[u8; 240]>, + } + + pub struct sockaddr_dl { + pub sdl_family: c_ushort, + pub sdl_index: c_ushort, + pub sdl_type: c_uchar, + pub sdl_nlen: c_uchar, + pub sdl_alen: c_uchar, + pub sdl_slen: c_uchar, + pub sdl_data: [c_char; 244], + } + + pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: crate::sigval, + pub ss_sp: *mut c_void, + pub sigev_notify_attributes: *const crate::pthread_attr_t, + __sigev_pad2: Padding, + } +} + +s_no_extra_traits! { + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + #[cfg(target_pointer_width = "64")] + pub si_pad: c_int, + + __data_pad: [c_int; SIGINFO_DATA_SIZE], + } + + #[repr(align(16))] + pub union pad128_t { + // pub _q in this structure would be a "long double", of 16 bytes + pub _l: [i32; 4], + } + + #[repr(align(16))] + pub union upad128_t { + // pub _q in this structure would be a "long double", of 16 bytes + pub _l: [u32; 4], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl siginfo_t { + /// The siginfo_t will have differing contents based on the delivered signal. Based on + /// `si_signo`, this determines how many of the `c_int` pad fields contain valid data + /// exposed by the C unions. + /// + /// It is not yet exhausitive for the OS-defined types, and defaults to assuming the + /// entire data pad area is "valid" for otherwise unrecognized signal numbers. + fn data_field_count(&self) -> usize { + match self.si_signo { + SIGSEGV | SIGBUS | SIGILL | SIGTRAP | SIGFPE => { + size_of::() / size_of::() + } + SIGCLD => size_of::() / size_of::(), + SIGHUP + | SIGINT + | SIGQUIT + | SIGABRT + | SIGSYS + | SIGPIPE + | SIGALRM + | SIGTERM + | crate::SIGUSR1 + | crate::SIGUSR2 + | SIGPWR + | SIGWINCH + | SIGURG => size_of::() / size_of::(), + _ => SIGINFO_DATA_SIZE, + } + } + } + impl PartialEq for siginfo_t { + fn eq(&self, other: &siginfo_t) -> bool { + if self.si_signo == other.si_signo + && self.si_code == other.si_code + && self.si_errno == other.si_errno + { + // FIXME(solarish): The `si_pad` field in the 64-bit version of the struct is ignored + // (for now) when doing comparisons. + + let field_count = self.data_field_count(); + self.__data_pad[..field_count] + .iter() + .zip(other.__data_pad[..field_count].iter()) + .all(|(a, b)| a == b) + } else { + false + } + } + } + impl Eq for siginfo_t {} + impl hash::Hash for siginfo_t { + fn hash(&self, state: &mut H) { + self.si_signo.hash(state); + self.si_code.hash(state); + self.si_errno.hash(state); + + // FIXME(solarish): The `si_pad` field in the 64-bit version of the struct is ignored + // (for now) when doing hashing. + + let field_count = self.data_field_count(); + self.__data_pad[..field_count].hash(state) + } + } + + impl PartialEq for pad128_t { + fn eq(&self, other: &pad128_t) -> bool { + unsafe { + // FIXME(solarish): self._q == other._q || + self._l == other._l + } + } + } + impl Eq for pad128_t {} + impl hash::Hash for pad128_t { + fn hash(&self, state: &mut H) { + unsafe { + // FIXME(solarish): state.write_i64(self._q as i64); + self._l.hash(state); + } + } + } + impl PartialEq for upad128_t { + fn eq(&self, other: &upad128_t) -> bool { + unsafe { + // FIXME(solarish): self._q == other._q || + self._l == other._l + } + } + } + impl Eq for upad128_t {} + impl hash::Hash for upad128_t { + fn hash(&self, state: &mut H) { + unsafe { + // FIXME(solarish): state.write_i64(self._q as i64); + self._l.hash(state); + } + } + } + } +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + const SIGINFO_DATA_SIZE: usize = 60; + } else { + const SIGINFO_DATA_SIZE: usize = 29; + } +} + +s_no_extra_traits! { + struct siginfo_fault { + addr: *mut c_void, + trapno: c_int, + pc: *mut crate::caddr_t, + } + + struct siginfo_cldval { + utime: crate::clock_t, + status: c_int, + stime: crate::clock_t, + } + + struct siginfo_killval { + uid: crate::uid_t, + value: crate::sigval, + // Pad out to match the SIGCLD value size + _pad: Padding<*mut c_void>, + } + + struct siginfo_sigcld { + pid: crate::pid_t, + val: siginfo_cldval, + ctid: crate::ctid_t, + zoneid: crate::zoneid_t, + } + + struct siginfo_kill { + pid: crate::pid_t, + val: siginfo_killval, + ctid: crate::ctid_t, + zoneid: crate::zoneid_t, + } +} + +impl siginfo_t { + unsafe fn sidata(&self) -> T { + *((&self.__data_pad) as *const c_int as *const T) + } + pub unsafe fn si_addr(&self) -> *mut c_void { + let sifault: siginfo_fault = self.sidata(); + sifault.addr + } + pub unsafe fn si_uid(&self) -> crate::uid_t { + let kill: siginfo_kill = self.sidata(); + kill.val.uid + } + pub unsafe fn si_value(&self) -> crate::sigval { + let kill: siginfo_kill = self.sidata(); + kill.val.value + } + pub unsafe fn si_pid(&self) -> crate::pid_t { + let sigcld: siginfo_sigcld = self.sidata(); + sigcld.pid + } + pub unsafe fn si_status(&self) -> c_int { + let sigcld: siginfo_sigcld = self.sidata(); + sigcld.val.status + } + pub unsafe fn si_utime(&self) -> c_long { + let sigcld: siginfo_sigcld = self.sidata(); + sigcld.val.utime + } + pub unsafe fn si_stime(&self) -> c_long { + let sigcld: siginfo_sigcld = self.sidata(); + sigcld.val.stime + } +} + +pub const LC_CTYPE: c_int = 0; +pub const LC_NUMERIC: c_int = 1; +pub const LC_TIME: c_int = 2; +pub const LC_COLLATE: c_int = 3; +pub const LC_MONETARY: c_int = 4; +pub const LC_MESSAGES: c_int = 5; +pub const LC_ALL: c_int = 6; +pub const LC_CTYPE_MASK: c_int = 1 << LC_CTYPE; +pub const LC_NUMERIC_MASK: c_int = 1 << LC_NUMERIC; +pub const LC_TIME_MASK: c_int = 1 << LC_TIME; +pub const LC_COLLATE_MASK: c_int = 1 << LC_COLLATE; +pub const LC_MONETARY_MASK: c_int = 1 << LC_MONETARY; +pub const LC_MESSAGES_MASK: c_int = 1 << LC_MESSAGES; +pub const LC_ALL_MASK: c_int = LC_CTYPE_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK + | LC_COLLATE_MASK + | LC_MONETARY_MASK + | LC_MESSAGES_MASK; + +pub const DAY_1: crate::nl_item = 1; +pub const DAY_2: crate::nl_item = 2; +pub const DAY_3: crate::nl_item = 3; +pub const DAY_4: crate::nl_item = 4; +pub const DAY_5: crate::nl_item = 5; +pub const DAY_6: crate::nl_item = 6; +pub const DAY_7: crate::nl_item = 7; + +pub const ABDAY_1: crate::nl_item = 8; +pub const ABDAY_2: crate::nl_item = 9; +pub const ABDAY_3: crate::nl_item = 10; +pub const ABDAY_4: crate::nl_item = 11; +pub const ABDAY_5: crate::nl_item = 12; +pub const ABDAY_6: crate::nl_item = 13; +pub const ABDAY_7: crate::nl_item = 14; + +pub const MON_1: crate::nl_item = 15; +pub const MON_2: crate::nl_item = 16; +pub const MON_3: crate::nl_item = 17; +pub const MON_4: crate::nl_item = 18; +pub const MON_5: crate::nl_item = 19; +pub const MON_6: crate::nl_item = 20; +pub const MON_7: crate::nl_item = 21; +pub const MON_8: crate::nl_item = 22; +pub const MON_9: crate::nl_item = 23; +pub const MON_10: crate::nl_item = 24; +pub const MON_11: crate::nl_item = 25; +pub const MON_12: crate::nl_item = 26; + +pub const ABMON_1: crate::nl_item = 27; +pub const ABMON_2: crate::nl_item = 28; +pub const ABMON_3: crate::nl_item = 29; +pub const ABMON_4: crate::nl_item = 30; +pub const ABMON_5: crate::nl_item = 31; +pub const ABMON_6: crate::nl_item = 32; +pub const ABMON_7: crate::nl_item = 33; +pub const ABMON_8: crate::nl_item = 34; +pub const ABMON_9: crate::nl_item = 35; +pub const ABMON_10: crate::nl_item = 36; +pub const ABMON_11: crate::nl_item = 37; +pub const ABMON_12: crate::nl_item = 38; + +pub const RADIXCHAR: crate::nl_item = 39; +pub const THOUSEP: crate::nl_item = 40; +pub const YESSTR: crate::nl_item = 41; +pub const NOSTR: crate::nl_item = 42; +pub const CRNCYSTR: crate::nl_item = 43; + +pub const D_T_FMT: crate::nl_item = 44; +pub const D_FMT: crate::nl_item = 45; +pub const T_FMT: crate::nl_item = 46; +pub const AM_STR: crate::nl_item = 47; +pub const PM_STR: crate::nl_item = 48; + +pub const CODESET: crate::nl_item = 49; +pub const T_FMT_AMPM: crate::nl_item = 50; +pub const ERA: crate::nl_item = 51; +pub const ERA_D_FMT: crate::nl_item = 52; +pub const ERA_D_T_FMT: crate::nl_item = 53; +pub const ERA_T_FMT: crate::nl_item = 54; +pub const ALT_DIGITS: crate::nl_item = 55; +pub const YESEXPR: crate::nl_item = 56; +pub const NOEXPR: crate::nl_item = 57; +pub const _DATE_FMT: crate::nl_item = 58; +pub const MAXSTRMSG: crate::nl_item = 58; + +pub const PATH_MAX: c_int = 1024; + +pub const SA_ONSTACK: c_int = 0x00000001; +pub const SA_RESETHAND: c_int = 0x00000002; +pub const SA_RESTART: c_int = 0x00000004; +pub const SA_SIGINFO: c_int = 0x00000008; +pub const SA_NODEFER: c_int = 0x00000010; +pub const SA_NOCLDWAIT: c_int = 0x00010000; +pub const SA_NOCLDSTOP: c_int = 0x00020000; + +pub const SS_ONSTACK: c_int = 1; +pub const SS_DISABLE: c_int = 2; + +pub const FIOCLEX: c_int = 0x20006601; +pub const FIONCLEX: c_int = 0x20006602; +pub const FIONREAD: c_int = 0x4004667f; +pub const FIONBIO: c_int = 0x8004667e; +pub const FIOASYNC: c_int = 0x8004667d; +pub const FIOSETOWN: c_int = 0x8004667c; +pub const FIOGETOWN: c_int = 0x4004667b; + +pub const SIGCHLD: c_int = 18; +pub const SIGCLD: c_int = SIGCHLD; +pub const SIGBUS: c_int = 10; +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 3; + +pub const AIO_CANCELED: c_int = 0; +pub const AIO_ALLDONE: c_int = 1; +pub const AIO_NOTCANCELED: c_int = 2; +pub const LIO_NOP: c_int = 0; +pub const LIO_READ: c_int = 1; +pub const LIO_WRITE: c_int = 2; +pub const LIO_NOWAIT: c_int = 0; +pub const LIO_WAIT: c_int = 1; + +pub const SIGEV_NONE: c_int = 1; +pub const SIGEV_SIGNAL: c_int = 2; +pub const SIGEV_THREAD: c_int = 3; +pub const SIGEV_PORT: c_int = 4; + +pub const CLD_EXITED: c_int = 1; +pub const CLD_KILLED: c_int = 2; +pub const CLD_DUMPED: c_int = 3; +pub const CLD_TRAPPED: c_int = 4; +pub const CLD_STOPPED: c_int = 5; +pub const CLD_CONTINUED: c_int = 6; + +pub const IP_RECVDSTADDR: c_int = 0x7; +pub const IP_PKTINFO: c_int = 0x1a; +pub const IP_DONTFRAG: c_int = 0x1b; +pub const IP_SEC_OPT: c_int = 0x22; + +pub const IPV6_UNICAST_HOPS: c_int = 0x5; +pub const IPV6_MULTICAST_IF: c_int = 0x6; +pub const IPV6_MULTICAST_HOPS: c_int = 0x7; +pub const IPV6_MULTICAST_LOOP: c_int = 0x8; +pub const IPV6_PKTINFO: c_int = 0xb; +pub const IPV6_RECVPKTINFO: c_int = 0x12; +pub const IPV6_RECVTCLASS: c_int = 0x19; +pub const IPV6_DONTFRAG: c_int = 0x21; +pub const IPV6_SEC_OPT: c_int = 0x22; +pub const IPV6_TCLASS: c_int = 0x26; +pub const IPV6_V6ONLY: c_int = 0x27; +pub const IPV6_BOUND_IF: c_int = 0x41; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const FD_SETSIZE: usize = 65536; + } else { + pub const FD_SETSIZE: usize = 1024; + } +} + +pub const ST_RDONLY: c_ulong = 1; +pub const ST_NOSUID: c_ulong = 2; + +pub const NI_MAXHOST: crate::socklen_t = 1025; +pub const NI_MAXSERV: crate::socklen_t = 32; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 32767; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const SEEK_DATA: c_int = 3; +pub const SEEK_HOLE: c_int = 4; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 4; +pub const _IOLBF: c_int = 64; +pub const BUFSIZ: c_uint = 1024; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 1024; +pub const L_tmpnam: c_uint = 25; +pub const TMP_MAX: c_uint = 17576; +pub const PIPE_BUF: c_int = 5120; + +pub const GRND_NONBLOCK: c_uint = 0x0001; +pub const GRND_RANDOM: c_uint = 0x0002; + +pub const O_RDONLY: c_int = 0; +pub const O_WRONLY: c_int = 1; +pub const O_RDWR: c_int = 2; +pub const O_NDELAY: c_int = 0x04; +pub const O_APPEND: c_int = 8; +pub const O_DSYNC: c_int = 0x40; +pub const O_RSYNC: c_int = 0x8000; +pub const O_CREAT: c_int = 256; +pub const O_EXCL: c_int = 1024; +pub const O_NOCTTY: c_int = 2048; +pub const O_TRUNC: c_int = 512; +pub const O_NOFOLLOW: c_int = 0x20000; +pub const O_SEARCH: c_int = 0x200000; +pub const O_EXEC: c_int = 0x400000; +pub const O_CLOEXEC: c_int = 0x800000; +pub const O_ACCMODE: c_int = 0x600003; +pub const O_XATTR: c_int = 0x4000; +pub const O_DIRECTORY: c_int = 0x1000000; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IEXEC: mode_t = 0o0100; +pub const S_IWRITE: mode_t = 0o0200; +pub const S_IREAD: mode_t = 0o0400; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const F_LOCK: c_int = 1; +pub const F_TEST: c_int = 3; +pub const F_TLOCK: c_int = 2; +pub const F_ULOCK: c_int = 0; +pub const F_SETLK: c_int = 6; +pub const F_SETLKW: c_int = 7; +pub const F_GETLK: c_int = 14; +pub const F_ALLOCSP: c_int = 10; +pub const F_FREESP: c_int = 11; +pub const F_BLOCKS: c_int = 18; +pub const F_BLKSIZE: c_int = 19; +pub const F_SHARE: c_int = 40; +pub const F_UNSHARE: c_int = 41; +pub const F_ISSTREAM: c_int = 13; +pub const F_PRIV: c_int = 15; +pub const F_NPRIV: c_int = 16; +pub const F_QUOTACTL: c_int = 17; +pub const F_GETOWN: c_int = 23; +pub const F_SETOWN: c_int = 24; +pub const F_REVOKE: c_int = 25; +pub const F_HASREMOTELOCKS: c_int = 26; +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGSEGV: c_int = 11; +pub const SIGSYS: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGUSR1: c_int = 16; +pub const SIGUSR2: c_int = 17; +pub const SIGPWR: c_int = 19; +pub const SIGWINCH: c_int = 20; +pub const SIGURG: c_int = 21; +pub const SIGPOLL: c_int = 22; +pub const SIGIO: c_int = SIGPOLL; +pub const SIGSTOP: c_int = 23; +pub const SIGTSTP: c_int = 24; +pub const SIGCONT: c_int = 25; +pub const SIGTTIN: c_int = 26; +pub const SIGTTOU: c_int = 27; +pub const SIGVTALRM: c_int = 28; +pub const SIGPROF: c_int = 29; +pub const SIGXCPU: c_int = 30; +pub const SIGXFSZ: c_int = 31; + +pub const WNOHANG: c_int = 0x40; +pub const WUNTRACED: c_int = 0x04; + +pub const WEXITED: c_int = 0x01; +pub const WTRAPPED: c_int = 0x02; +pub const WSTOPPED: c_int = WUNTRACED; +pub const WCONTINUED: c_int = 0x08; +pub const WNOWAIT: c_int = 0x80; + +pub const AT_FDCWD: c_int = 0xffd19553; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x1000; +pub const AT_SYMLINK_FOLLOW: c_int = 0x2000; +pub const AT_REMOVEDIR: c_int = 0x1; +pub const _AT_TRIGGER: c_int = 0x2; +pub const AT_EACCESS: c_int = 0x4; + +pub const P_PID: idtype_t = 0; +pub const P_PPID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; +pub const P_SID: idtype_t = 3; +pub const P_CID: idtype_t = 4; +pub const P_UID: idtype_t = 5; +pub const P_GID: idtype_t = 6; +pub const P_ALL: idtype_t = 7; +pub const P_LWPID: idtype_t = 8; +pub const P_TASKID: idtype_t = 9; +pub const P_PROJID: idtype_t = 10; +pub const P_POOLID: idtype_t = 11; +pub const P_ZONEID: idtype_t = 12; +pub const P_CTID: idtype_t = 13; +pub const P_CPUID: idtype_t = 14; +pub const P_PSETID: idtype_t = 15; + +pub const PBIND_NONE: crate::processorid_t = -1; +pub const PBIND_QUERY: crate::processorid_t = -2; + +pub const PS_NONE: c_int = -1; +pub const PS_QUERY: c_int = -2; +pub const PS_MYID: c_int = -3; +pub const PS_SOFT: c_int = -4; +pub const PS_HARD: c_int = -5; +pub const PS_QUERY_TYPE: c_int = -6; +pub const PS_PRIVATE: c_int = 2; + +pub const UTIME_OMIT: c_long = -2; +pub const UTIME_NOW: c_long = -1; + +pub const PROT_NONE: c_int = 0; +pub const PROT_READ: c_int = 1; +pub const PROT_WRITE: c_int = 2; +pub const PROT_EXEC: c_int = 4; + +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_NORESERVE: c_int = 0x40; +pub const MAP_ANON: c_int = 0x0100; +pub const MAP_ANONYMOUS: c_int = 0x0100; +pub const MAP_RENAME: c_int = 0x20; +pub const MAP_ALIGN: c_int = 0x200; +pub const MAP_TEXT: c_int = 0x400; +pub const MAP_INITDATA: c_int = 0x800; +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +pub const MCL_CURRENT: c_int = 0x0001; +pub const MCL_FUTURE: c_int = 0x0002; + +pub const MS_SYNC: c_int = 0x0004; +pub const MS_ASYNC: c_int = 0x0001; +pub const MS_INVALIDATE: c_int = 0x0002; + +pub const MMOBJ_PADDING: c_uint = 0x10000; +pub const MMOBJ_INTERPRET: c_uint = 0x20000; +pub const MR_PADDING: c_uint = 0x1; +pub const MR_HDR_ELF: c_uint = 0x2; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOMSG: c_int = 35; +pub const EIDRM: c_int = 36; +pub const ECHRNG: c_int = 37; +pub const EL2NSYNC: c_int = 38; +pub const EL3HLT: c_int = 39; +pub const EL3RST: c_int = 40; +pub const ELNRNG: c_int = 41; +pub const EUNATCH: c_int = 42; +pub const ENOCSI: c_int = 43; +pub const EL2HLT: c_int = 44; +pub const EDEADLK: c_int = 45; +pub const ENOLCK: c_int = 46; +pub const ECANCELED: c_int = 47; +pub const ENOTSUP: c_int = 48; +pub const EDQUOT: c_int = 49; +pub const EBADE: c_int = 50; +pub const EBADR: c_int = 51; +pub const EXFULL: c_int = 52; +pub const ENOANO: c_int = 53; +pub const EBADRQC: c_int = 54; +pub const EBADSLT: c_int = 55; +pub const EDEADLOCK: c_int = 56; +pub const EBFONT: c_int = 57; +pub const EOWNERDEAD: c_int = 58; +pub const ENOTRECOVERABLE: c_int = 59; +pub const ENOSTR: c_int = 60; +pub const ENODATA: c_int = 61; +pub const ETIME: c_int = 62; +pub const ENOSR: c_int = 63; +pub const ENONET: c_int = 64; +pub const ENOPKG: c_int = 65; +pub const EREMOTE: c_int = 66; +pub const ENOLINK: c_int = 67; +pub const EADV: c_int = 68; +pub const ESRMNT: c_int = 69; +pub const ECOMM: c_int = 70; +pub const EPROTO: c_int = 71; +pub const ELOCKUNMAPPED: c_int = 72; +pub const ENOTACTIVE: c_int = 73; +pub const EMULTIHOP: c_int = 74; +pub const EADI: c_int = 75; +pub const EBADMSG: c_int = 77; +pub const ENAMETOOLONG: c_int = 78; +pub const EOVERFLOW: c_int = 79; +pub const ENOTUNIQ: c_int = 80; +pub const EBADFD: c_int = 81; +pub const EREMCHG: c_int = 82; +pub const ELIBACC: c_int = 83; +pub const ELIBBAD: c_int = 84; +pub const ELIBSCN: c_int = 85; +pub const ELIBMAX: c_int = 86; +pub const ELIBEXEC: c_int = 87; +pub const EILSEQ: c_int = 88; +pub const ENOSYS: c_int = 89; +pub const ELOOP: c_int = 90; +pub const ERESTART: c_int = 91; +pub const ESTRPIPE: c_int = 92; +pub const ENOTEMPTY: c_int = 93; +pub const EUSERS: c_int = 94; +pub const ENOTSOCK: c_int = 95; +pub const EDESTADDRREQ: c_int = 96; +pub const EMSGSIZE: c_int = 97; +pub const EPROTOTYPE: c_int = 98; +pub const ENOPROTOOPT: c_int = 99; +pub const EPROTONOSUPPORT: c_int = 120; +pub const ESOCKTNOSUPPORT: c_int = 121; +pub const EOPNOTSUPP: c_int = 122; +pub const EPFNOSUPPORT: c_int = 123; +pub const EAFNOSUPPORT: c_int = 124; +pub const EADDRINUSE: c_int = 125; +pub const EADDRNOTAVAIL: c_int = 126; +pub const ENETDOWN: c_int = 127; +pub const ENETUNREACH: c_int = 128; +pub const ENETRESET: c_int = 129; +pub const ECONNABORTED: c_int = 130; +pub const ECONNRESET: c_int = 131; +pub const ENOBUFS: c_int = 132; +pub const EISCONN: c_int = 133; +pub const ENOTCONN: c_int = 134; +pub const ESHUTDOWN: c_int = 143; +pub const ETOOMANYREFS: c_int = 144; +pub const ETIMEDOUT: c_int = 145; +pub const ECONNREFUSED: c_int = 146; +pub const EHOSTDOWN: c_int = 147; +pub const EHOSTUNREACH: c_int = 148; +pub const EWOULDBLOCK: c_int = EAGAIN; +pub const EALREADY: c_int = 149; +pub const EINPROGRESS: c_int = 150; +pub const ESTALE: c_int = 151; + +pub const EAI_AGAIN: c_int = 2; +pub const EAI_BADFLAGS: c_int = 3; +pub const EAI_FAIL: c_int = 4; +pub const EAI_FAMILY: c_int = 5; +pub const EAI_MEMORY: c_int = 6; +pub const EAI_NODATA: c_int = 7; +pub const EAI_NONAME: c_int = 8; +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; +pub const EAI_OVERFLOW: c_int = 12; + +pub const NI_NOFQDN: c_uint = 0x0001; +pub const NI_NUMERICHOST: c_uint = 0x0002; +pub const NI_NAMEREQD: c_uint = 0x0004; +pub const NI_NUMERICSERV: c_uint = 0x0008; +pub const NI_DGRAM: c_uint = 0x0010; +pub const NI_WITHSCOPEID: c_uint = 0x0020; +pub const NI_NUMERICSCOPE: c_uint = 0x0040; + +pub const F_DUPFD: c_int = 0; +pub const F_DUP2FD: c_int = 9; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETXFL: c_int = 45; + +pub const SIGTRAP: c_int = 5; + +pub const GLOB_APPEND: c_int = 32; +pub const GLOB_DOOFFS: c_int = 16; +pub const GLOB_ERR: c_int = 1; +pub const GLOB_MARK: c_int = 2; +pub const GLOB_NOCHECK: c_int = 8; +pub const GLOB_NOSORT: c_int = 4; +pub const GLOB_NOESCAPE: c_int = 64; + +pub const GLOB_NOSPACE: c_int = -2; +pub const GLOB_ABORTED: c_int = -1; +pub const GLOB_NOMATCH: c_int = -3; + +pub const POLLIN: c_short = 0x1; +pub const POLLPRI: c_short = 0x2; +pub const POLLOUT: c_short = 0x4; +pub const POLLERR: c_short = 0x8; +pub const POLLHUP: c_short = 0x10; +pub const POLLNVAL: c_short = 0x20; +pub const POLLNORM: c_short = 0x0040; +pub const POLLRDNORM: c_short = 0x0040; +pub const POLLWRNORM: c_short = 0x4; /* POLLOUT */ +pub const POLLRDBAND: c_short = 0x0080; +pub const POLLWRBAND: c_short = 0x0100; + +pub const POSIX_MADV_NORMAL: c_int = 0; +pub const POSIX_MADV_RANDOM: c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: c_int = 2; +pub const POSIX_MADV_WILLNEED: c_int = 3; +pub const POSIX_MADV_DONTNEED: c_int = 4; + +pub const POSIX_SPAWN_RESETIDS: c_short = 0x1; +pub const POSIX_SPAWN_SETPGROUP: c_short = 0x2; +pub const POSIX_SPAWN_SETSIGDEF: c_short = 0x4; +pub const POSIX_SPAWN_SETSIGMASK: c_short = 0x8; +pub const POSIX_SPAWN_SETSCHEDPARAM: c_short = 0x10; +pub const POSIX_SPAWN_SETSCHEDULER: c_short = 0x20; +pub const POSIX_SPAWN_SETSIGIGN_NP: c_short = 0x800; +pub const POSIX_SPAWN_NOSIGCHLD_NP: c_short = 0x1000; +pub const POSIX_SPAWN_WAITPID_NP: c_short = 0x2000; +pub const POSIX_SPAWN_NOEXECERR_NP: c_short = 0x4000; + +pub const PTHREAD_CREATE_JOINABLE: c_int = 0; +pub const PTHREAD_CREATE_DETACHED: c_int = 0x40; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; +pub const PTHREAD_PROCESS_PRIVATE: c_ushort = 0; +pub const PTHREAD_STACK_MIN: size_t = 4096; + +pub const SIGSTKSZ: size_t = 8192; + +// https://illumos.org/man/3c/clock_gettime +// https://github.com/illumos/illumos-gate/ +// blob/HEAD/usr/src/lib/libc/amd64/sys/__clock_gettime.s +// clock_gettime(3c) doesn't seem to accept anything other than CLOCK_REALTIME +// or __CLOCK_REALTIME0 +// +// https://github.com/illumos/illumos-gate/ +// blob/HEAD/usr/src/uts/common/sys/time_impl.h +// Confusing! CLOCK_HIGHRES==CLOCK_MONOTONIC==4 +// __CLOCK_REALTIME0==0 is an obsoleted version of CLOCK_REALTIME==3 +pub const CLOCK_REALTIME: crate::clockid_t = 3; +pub const CLOCK_MONOTONIC: crate::clockid_t = 4; +pub const TIMER_RELTIME: c_int = 0; +pub const TIMER_ABSTIME: c_int = 1; + +pub const RLIMIT_CPU: c_int = 0; +pub const RLIMIT_FSIZE: c_int = 1; +pub const RLIMIT_DATA: c_int = 2; +pub const RLIMIT_STACK: c_int = 3; +pub const RLIMIT_CORE: c_int = 4; +pub const RLIMIT_NOFILE: c_int = 5; +pub const RLIMIT_VMEM: c_int = 6; +pub const RLIMIT_AS: c_int = RLIMIT_VMEM; + +#[deprecated(since = "0.2.64", note = "Not stable across OS versions")] +pub const RLIM_NLIMITS: rlim_t = 7; +pub const RLIM_INFINITY: rlim_t = 0xfffffffffffffffd; + +pub const RUSAGE_SELF: c_int = 0; +pub const RUSAGE_CHILDREN: c_int = -1; + +pub const MADV_NORMAL: c_int = 0; +pub const MADV_RANDOM: c_int = 1; +pub const MADV_SEQUENTIAL: c_int = 2; +pub const MADV_WILLNEED: c_int = 3; +pub const MADV_DONTNEED: c_int = 4; +pub const MADV_FREE: c_int = 5; +pub const MADV_ACCESS_DEFAULT: c_int = 6; +pub const MADV_ACCESS_LWP: c_int = 7; +pub const MADV_ACCESS_MANY: c_int = 8; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_NBS: c_int = 7; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_NIT: c_int = 17; +pub const AF_802: c_int = 18; +pub const AF_OSI: c_int = 19; +pub const AF_X25: c_int = 20; +pub const AF_OSINET: c_int = 21; +pub const AF_GOSIP: c_int = 22; +pub const AF_IPX: c_int = 23; +pub const AF_ROUTE: c_int = 24; +pub const AF_LINK: c_int = 25; +pub const AF_INET6: c_int = 26; +pub const AF_KEY: c_int = 27; +pub const AF_POLICY: c_int = 29; +pub const AF_INET_OFFLOAD: c_int = 30; +pub const AF_TRILL: c_int = 31; +pub const AF_PACKET: c_int = 32; + +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_LOCAL: c_int = PF_UNIX; +pub const PF_FILE: c_int = PF_UNIX; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_NBS: c_int = AF_NBS; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_NIT: c_int = AF_NIT; +pub const PF_802: c_int = AF_802; +pub const PF_OSI: c_int = AF_OSI; +pub const PF_X25: c_int = AF_X25; +pub const PF_OSINET: c_int = AF_OSINET; +pub const PF_GOSIP: c_int = AF_GOSIP; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_ROUTE: c_int = AF_ROUTE; +pub const PF_LINK: c_int = AF_LINK; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_KEY: c_int = AF_KEY; +pub const PF_POLICY: c_int = AF_POLICY; +pub const PF_INET_OFFLOAD: c_int = AF_INET_OFFLOAD; +pub const PF_TRILL: c_int = AF_TRILL; +pub const PF_PACKET: c_int = AF_PACKET; + +pub const SOCK_DGRAM: c_int = 1; +pub const SOCK_STREAM: c_int = 2; +pub const SOCK_RAW: c_int = 4; +pub const SOCK_RDM: c_int = 5; +pub const SOCK_SEQPACKET: c_int = 6; +pub const IP_MULTICAST_IF: c_int = 16; +pub const IP_MULTICAST_TTL: c_int = 17; +pub const IP_MULTICAST_LOOP: c_int = 18; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_ADD_MEMBERSHIP: c_int = 19; +pub const IP_DROP_MEMBERSHIP: c_int = 20; +pub const IPV6_JOIN_GROUP: c_int = 9; +pub const IPV6_LEAVE_GROUP: c_int = 10; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 23; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 24; +pub const IP_BLOCK_SOURCE: c_int = 21; +pub const IP_UNBLOCK_SOURCE: c_int = 22; +pub const IP_BOUND_IF: c_int = 0x41; + +// These TCP socket options are common between illumos and Solaris, while higher +// numbers have generally diverged: +pub const TCP_NODELAY: c_int = 0x1; +pub const TCP_MAXSEG: c_int = 0x2; +pub const TCP_KEEPALIVE: c_int = 0x8; +pub const TCP_NOTIFY_THRESHOLD: c_int = 0x10; +pub const TCP_ABORT_THRESHOLD: c_int = 0x11; +pub const TCP_CONN_NOTIFY_THRESHOLD: c_int = 0x12; +pub const TCP_CONN_ABORT_THRESHOLD: c_int = 0x13; +pub const TCP_RECVDSTADDR: c_int = 0x14; +pub const TCP_INIT_CWND: c_int = 0x15; +pub const TCP_KEEPALIVE_THRESHOLD: c_int = 0x16; +pub const TCP_KEEPALIVE_ABORT_THRESHOLD: c_int = 0x17; +pub const TCP_CORK: c_int = 0x18; +pub const TCP_RTO_INITIAL: c_int = 0x19; +pub const TCP_RTO_MIN: c_int = 0x1a; +pub const TCP_RTO_MAX: c_int = 0x1b; +pub const TCP_LINGER2: c_int = 0x1c; + +pub const UDP_NAT_T_ENDPOINT: c_int = 0x0103; + +pub const SOMAXCONN: c_int = 128; + +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 0x01; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_PROTOTYPE: c_int = 0x1009; +pub const SO_DOMAIN: c_int = 0x100c; +pub const SO_TIMESTAMP: c_int = 0x1013; +pub const SO_EXCLBIND: c_int = 0x1015; + +pub const SCM_RIGHTS: c_int = 0x1010; +pub const SCM_UCRED: c_int = 0x1012; +pub const SCM_TIMESTAMP: c_int = SO_TIMESTAMP; + +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_EOR: c_int = 0x8; +pub const MSG_CTRUNC: c_int = 0x10; +pub const MSG_TRUNC: c_int = 0x20; +pub const MSG_WAITALL: c_int = 0x40; +pub const MSG_DONTWAIT: c_int = 0x80; +pub const MSG_NOTIFICATION: c_int = 0x100; +pub const MSG_NOSIGNAL: c_int = 0x200; +pub const MSG_DUPCTRL: c_int = 0x800; +pub const MSG_XPG4_2: c_int = 0x8000; +pub const MSG_MAXIOVLEN: c_int = 16; + +pub const IF_NAMESIZE: size_t = 32; +pub const IFNAMSIZ: size_t = 16; + +// https://docs.oracle.com/cd/E23824_01/html/821-1475/if-7p.html +pub const IFF_UP: c_int = 0x0000000001; // Address is up +pub const IFF_BROADCAST: c_int = 0x0000000002; // Broadcast address valid +pub const IFF_DEBUG: c_int = 0x0000000004; // Turn on debugging +pub const IFF_LOOPBACK: c_int = 0x0000000008; // Loopback net +pub const IFF_POINTOPOINT: c_int = 0x0000000010; // Interface is p-to-p +pub const IFF_NOTRAILERS: c_int = 0x0000000020; // Avoid use of trailers +pub const IFF_RUNNING: c_int = 0x0000000040; // Resources allocated +pub const IFF_NOARP: c_int = 0x0000000080; // No address res. protocol +pub const IFF_PROMISC: c_int = 0x0000000100; // Receive all packets +pub const IFF_ALLMULTI: c_int = 0x0000000200; // Receive all multicast pkts +pub const IFF_INTELLIGENT: c_int = 0x0000000400; // Protocol code on board +pub const IFF_MULTICAST: c_int = 0x0000000800; // Supports multicast + +// Multicast using broadcst. add. +pub const IFF_MULTI_BCAST: c_int = 0x0000001000; +pub const IFF_UNNUMBERED: c_int = 0x0000002000; // Non-unique address +pub const IFF_DHCPRUNNING: c_int = 0x0000004000; // DHCP controls interface +pub const IFF_PRIVATE: c_int = 0x0000008000; // Do not advertise +pub const IFF_NOXMIT: c_int = 0x0000010000; // Do not transmit pkts + +// No address - just on-link subnet +pub const IFF_NOLOCAL: c_int = 0x0000020000; +pub const IFF_DEPRECATED: c_int = 0x0000040000; // Address is deprecated +pub const IFF_ADDRCONF: c_int = 0x0000080000; // Addr. from stateless addrconf +pub const IFF_ROUTER: c_int = 0x0000100000; // Router on interface +pub const IFF_NONUD: c_int = 0x0000200000; // No NUD on interface +pub const IFF_ANYCAST: c_int = 0x0000400000; // Anycast address +pub const IFF_NORTEXCH: c_int = 0x0000800000; // Don't xchange rout. info +pub const IFF_IPV4: c_int = 0x0001000000; // IPv4 interface +pub const IFF_IPV6: c_int = 0x0002000000; // IPv6 interface +pub const IFF_NOFAILOVER: c_int = 0x0008000000; // in.mpathd test address +pub const IFF_FAILED: c_int = 0x0010000000; // Interface has failed +pub const IFF_STANDBY: c_int = 0x0020000000; // Interface is a hot-spare +pub const IFF_INACTIVE: c_int = 0x0040000000; // Functioning but not used +pub const IFF_OFFLINE: c_int = 0x0080000000; // Interface is offline + // If CoS marking is supported +pub const IFF_COS_ENABLED: c_longlong = 0x0200000000; +pub const IFF_PREFERRED: c_longlong = 0x0400000000; // Prefer as source addr. +pub const IFF_TEMPORARY: c_longlong = 0x0800000000; // RFC3041 +pub const IFF_FIXEDMTU: c_longlong = 0x1000000000; // MTU set with SIOCSLIFMTU +pub const IFF_VIRTUAL: c_longlong = 0x2000000000; // Cannot send/receive pkts +pub const IFF_DUPLICATE: c_longlong = 0x4000000000; // Local address in use +pub const IFF_IPMP: c_longlong = 0x8000000000; // IPMP IP interface + +// sys/ipc.h: +pub const IPC_ALLOC: c_int = 0x8000; +pub const IPC_CREAT: c_int = 0x200; +pub const IPC_EXCL: c_int = 0x400; +pub const IPC_NOWAIT: c_int = 0x800; +pub const IPC_PRIVATE: key_t = 0; +pub const IPC_RMID: c_int = 10; +pub const IPC_SET: c_int = 11; +pub const IPC_SEAT: c_int = 12; + +// sys/shm.h +pub const SHM_R: c_int = 0o400; +pub const SHM_W: c_int = 0o200; +pub const SHM_RDONLY: c_int = 0o10000; +pub const SHM_RND: c_int = 0o20000; +pub const SHM_SHARE_MMU: c_int = 0o40000; +pub const SHM_PAGEABLE: c_int = 0o100000; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const F_RDLCK: c_short = 1; +pub const F_WRLCK: c_short = 2; +pub const F_UNLCK: c_short = 3; + +pub const O_SYNC: c_int = 16; +pub const O_NONBLOCK: c_int = 128; + +pub const IPPROTO_RAW: c_int = 255; + +pub const _PC_LINK_MAX: c_int = 1; +pub const _PC_MAX_CANON: c_int = 2; +pub const _PC_MAX_INPUT: c_int = 3; +pub const _PC_NAME_MAX: c_int = 4; +pub const _PC_PATH_MAX: c_int = 5; +pub const _PC_PIPE_BUF: c_int = 6; +pub const _PC_NO_TRUNC: c_int = 7; +pub const _PC_VDISABLE: c_int = 8; +pub const _PC_CHOWN_RESTRICTED: c_int = 9; +pub const _PC_ASYNC_IO: c_int = 10; +pub const _PC_PRIO_IO: c_int = 11; +pub const _PC_SYNC_IO: c_int = 12; +pub const _PC_ALLOC_SIZE_MIN: c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: c_int = 16; +pub const _PC_REC_XFER_ALIGN: c_int = 17; +pub const _PC_SYMLINK_MAX: c_int = 18; +pub const _PC_2_SYMLINKS: c_int = 19; +pub const _PC_ACL_ENABLED: c_int = 20; +pub const _PC_MIN_HOLE_SIZE: c_int = 21; +pub const _PC_CASE_BEHAVIOR: c_int = 22; +pub const _PC_SATTR_ENABLED: c_int = 23; +pub const _PC_SATTR_EXISTS: c_int = 24; +pub const _PC_ACCESS_FILTERING: c_int = 25; +pub const _PC_TIMESTAMP_RESOLUTION: c_int = 26; +pub const _PC_FILESIZEBITS: c_int = 67; +pub const _PC_XATTR_ENABLED: c_int = 100; +pub const _PC_XATTR_EXISTS: c_int = 101; + +pub const _POSIX_VDISABLE: crate::cc_t = 0; + +pub const _SC_ARG_MAX: c_int = 1; +pub const _SC_CHILD_MAX: c_int = 2; +pub const _SC_CLK_TCK: c_int = 3; +pub const _SC_NGROUPS_MAX: c_int = 4; +pub const _SC_OPEN_MAX: c_int = 5; +pub const _SC_JOB_CONTROL: c_int = 6; +pub const _SC_SAVED_IDS: c_int = 7; +pub const _SC_VERSION: c_int = 8; +pub const _SC_PASS_MAX: c_int = 9; +pub const _SC_LOGNAME_MAX: c_int = 10; +pub const _SC_PAGESIZE: c_int = 11; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_XOPEN_VERSION: c_int = 12; +pub const _SC_NPROCESSORS_CONF: c_int = 14; +pub const _SC_NPROCESSORS_ONLN: c_int = 15; +pub const _SC_STREAM_MAX: c_int = 16; +pub const _SC_TZNAME_MAX: c_int = 17; +pub const _SC_AIO_LISTIO_MAX: c_int = 18; +pub const _SC_AIO_MAX: c_int = 19; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 20; +pub const _SC_ASYNCHRONOUS_IO: c_int = 21; +pub const _SC_DELAYTIMER_MAX: c_int = 22; +pub const _SC_FSYNC: c_int = 23; +pub const _SC_MAPPED_FILES: c_int = 24; +pub const _SC_MEMLOCK: c_int = 25; +pub const _SC_MEMLOCK_RANGE: c_int = 26; +pub const _SC_MEMORY_PROTECTION: c_int = 27; +pub const _SC_MESSAGE_PASSING: c_int = 28; +pub const _SC_MQ_OPEN_MAX: c_int = 29; +pub const _SC_MQ_PRIO_MAX: c_int = 30; +pub const _SC_PRIORITIZED_IO: c_int = 31; +pub const _SC_PRIORITY_SCHEDULING: c_int = 32; +pub const _SC_REALTIME_SIGNALS: c_int = 33; +pub const _SC_RTSIG_MAX: c_int = 34; +pub const _SC_SEMAPHORES: c_int = 35; +pub const _SC_SEM_NSEMS_MAX: c_int = 36; +pub const _SC_SEM_VALUE_MAX: c_int = 37; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 38; +pub const _SC_SIGQUEUE_MAX: c_int = 39; +pub const _SC_SIGRT_MIN: c_int = 40; +pub const _SC_SIGRT_MAX: c_int = 41; +pub const _SC_SYNCHRONIZED_IO: c_int = 42; +pub const _SC_TIMERS: c_int = 43; +pub const _SC_TIMER_MAX: c_int = 44; +pub const _SC_2_C_BIND: c_int = 45; +pub const _SC_2_C_DEV: c_int = 46; +pub const _SC_2_C_VERSION: c_int = 47; +pub const _SC_2_FORT_DEV: c_int = 48; +pub const _SC_2_FORT_RUN: c_int = 49; +pub const _SC_2_LOCALEDEF: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_UPE: c_int = 52; +pub const _SC_2_VERSION: c_int = 53; +pub const _SC_BC_BASE_MAX: c_int = 54; +pub const _SC_BC_DIM_MAX: c_int = 55; +pub const _SC_BC_SCALE_MAX: c_int = 56; +pub const _SC_BC_STRING_MAX: c_int = 57; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 58; +pub const _SC_EXPR_NEST_MAX: c_int = 59; +pub const _SC_LINE_MAX: c_int = 60; +pub const _SC_RE_DUP_MAX: c_int = 61; +pub const _SC_XOPEN_CRYPT: c_int = 62; +pub const _SC_XOPEN_ENH_I18N: c_int = 63; +pub const _SC_XOPEN_SHM: c_int = 64; +pub const _SC_2_CHAR_TERM: c_int = 66; +pub const _SC_XOPEN_XCU_VERSION: c_int = 67; +pub const _SC_ATEXIT_MAX: c_int = 76; +pub const _SC_IOV_MAX: c_int = 77; +pub const _SC_XOPEN_UNIX: c_int = 78; +pub const _SC_T_IOV_MAX: c_int = 79; +pub const _SC_PHYS_PAGES: c_int = 500; +pub const _SC_AVPHYS_PAGES: c_int = 501; +pub const _SC_COHER_BLKSZ: c_int = 503; +pub const _SC_SPLIT_CACHE: c_int = 504; +pub const _SC_ICACHE_SZ: c_int = 505; +pub const _SC_DCACHE_SZ: c_int = 506; +pub const _SC_ICACHE_LINESZ: c_int = 507; +pub const _SC_DCACHE_LINESZ: c_int = 508; +pub const _SC_ICACHE_BLKSZ: c_int = 509; +pub const _SC_DCACHE_BLKSZ: c_int = 510; +pub const _SC_DCACHE_TBLKSZ: c_int = 511; +pub const _SC_ICACHE_ASSOC: c_int = 512; +pub const _SC_DCACHE_ASSOC: c_int = 513; +pub const _SC_MAXPID: c_int = 514; +pub const _SC_STACK_PROT: c_int = 515; +pub const _SC_NPROCESSORS_MAX: c_int = 516; +pub const _SC_CPUID_MAX: c_int = 517; +pub const _SC_EPHID_MAX: c_int = 518; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 568; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 569; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 570; +pub const _SC_LOGIN_NAME_MAX: c_int = 571; +pub const _SC_THREAD_KEYS_MAX: c_int = 572; +pub const _SC_THREAD_STACK_MIN: c_int = 573; +pub const _SC_THREAD_THREADS_MAX: c_int = 574; +pub const _SC_TTY_NAME_MAX: c_int = 575; +pub const _SC_THREADS: c_int = 576; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 577; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 578; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 579; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 580; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 581; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 582; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 583; +pub const _SC_XOPEN_LEGACY: c_int = 717; +pub const _SC_XOPEN_REALTIME: c_int = 718; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 719; +pub const _SC_XBS5_ILP32_OFF32: c_int = 720; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 721; +pub const _SC_XBS5_LP64_OFF64: c_int = 722; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 723; +pub const _SC_2_PBS: c_int = 724; +pub const _SC_2_PBS_ACCOUNTING: c_int = 725; +pub const _SC_2_PBS_CHECKPOINT: c_int = 726; +pub const _SC_2_PBS_LOCATE: c_int = 728; +pub const _SC_2_PBS_MESSAGE: c_int = 729; +pub const _SC_2_PBS_TRACK: c_int = 730; +pub const _SC_ADVISORY_INFO: c_int = 731; +pub const _SC_BARRIERS: c_int = 732; +pub const _SC_CLOCK_SELECTION: c_int = 733; +pub const _SC_CPUTIME: c_int = 734; +pub const _SC_HOST_NAME_MAX: c_int = 735; +pub const _SC_MONOTONIC_CLOCK: c_int = 736; +pub const _SC_READER_WRITER_LOCKS: c_int = 737; +pub const _SC_REGEXP: c_int = 738; +pub const _SC_SHELL: c_int = 739; +pub const _SC_SPAWN: c_int = 740; +pub const _SC_SPIN_LOCKS: c_int = 741; +pub const _SC_SPORADIC_SERVER: c_int = 742; +pub const _SC_SS_REPL_MAX: c_int = 743; +pub const _SC_SYMLOOP_MAX: c_int = 744; +pub const _SC_THREAD_CPUTIME: c_int = 745; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 746; +pub const _SC_TIMEOUTS: c_int = 747; +pub const _SC_TRACE: c_int = 748; +pub const _SC_TRACE_EVENT_FILTER: c_int = 749; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 750; +pub const _SC_TRACE_INHERIT: c_int = 751; +pub const _SC_TRACE_LOG: c_int = 752; +pub const _SC_TRACE_NAME_MAX: c_int = 753; +pub const _SC_TRACE_SYS_MAX: c_int = 754; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 755; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 756; +pub const _SC_V6_ILP32_OFF32: c_int = 757; +pub const _SC_V6_ILP32_OFFBIG: c_int = 758; +pub const _SC_V6_LP64_OFF64: c_int = 759; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 760; +pub const _SC_XOPEN_STREAMS: c_int = 761; +pub const _SC_IPV6: c_int = 762; +pub const _SC_RAW_SOCKETS: c_int = 763; + +pub const _ST_FSTYPSZ: c_int = 16; + +pub const _MUTEX_MAGIC: u16 = 0x4d58; // MX +pub const _COND_MAGIC: u16 = 0x4356; // CV +pub const _RWL_MAGIC: u16 = 0x5257; // RW + +pub const NCCS: usize = 19; + +pub const LOG_CRON: c_int = 15 << 3; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __pthread_mutex_flag1: 0, + __pthread_mutex_flag2: 0, + __pthread_mutex_ceiling: 0, + __pthread_mutex_type: PTHREAD_PROCESS_PRIVATE, + __pthread_mutex_magic: _MUTEX_MAGIC, + __pthread_mutex_lock: 0, + __pthread_mutex_data: 0, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __pthread_cond_flag: [0; 4], + __pthread_cond_type: PTHREAD_PROCESS_PRIVATE, + __pthread_cond_magic: _COND_MAGIC, + __pthread_cond_data: 0, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __pthread_rwlock_readers: 0, + __pthread_rwlock_type: PTHREAD_PROCESS_PRIVATE, + __pthread_rwlock_magic: _RWL_MAGIC, + __pthread_rwlock_mutex: PTHREAD_MUTEX_INITIALIZER, + __pthread_rwlock_readercv: PTHREAD_COND_INITIALIZER, + __pthread_rwlock_writercv: PTHREAD_COND_INITIALIZER, +}; +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 4; +pub const PTHREAD_MUTEX_DEFAULT: c_int = crate::PTHREAD_MUTEX_NORMAL; + +pub const RTLD_NEXT: *mut c_void = -1isize as *mut c_void; +pub const RTLD_DEFAULT: *mut c_void = -2isize as *mut c_void; +pub const RTLD_SELF: *mut c_void = -3isize as *mut c_void; +pub const RTLD_PROBE: *mut c_void = -4isize as *mut c_void; + +pub const RTLD_LAZY: c_int = 0x1; +pub const RTLD_NOW: c_int = 0x2; +pub const RTLD_NOLOAD: c_int = 0x4; +pub const RTLD_GLOBAL: c_int = 0x100; +pub const RTLD_LOCAL: c_int = 0x0; +pub const RTLD_PARENT: c_int = 0x200; +pub const RTLD_GROUP: c_int = 0x400; +pub const RTLD_WORLD: c_int = 0x800; +pub const RTLD_NODELETE: c_int = 0x1000; +pub const RTLD_FIRST: c_int = 0x2000; +pub const RTLD_CONFGEN: c_int = 0x10000; + +pub const PORT_SOURCE_AIO: c_int = 1; +pub const PORT_SOURCE_TIMER: c_int = 2; +pub const PORT_SOURCE_USER: c_int = 3; +pub const PORT_SOURCE_FD: c_int = 4; +pub const PORT_SOURCE_ALERT: c_int = 5; +pub const PORT_SOURCE_MQ: c_int = 6; +pub const PORT_SOURCE_FILE: c_int = 7; + +pub const NONROOT_USR: c_short = 2; + +pub const EMPTY: c_short = 0; +pub const RUN_LVL: c_short = 1; +pub const BOOT_TIME: c_short = 2; +pub const OLD_TIME: c_short = 3; +pub const NEW_TIME: c_short = 4; +pub const INIT_PROCESS: c_short = 5; +pub const LOGIN_PROCESS: c_short = 6; +pub const USER_PROCESS: c_short = 7; +pub const DEAD_PROCESS: c_short = 8; +pub const ACCOUNTING: c_short = 9; +pub const DOWN_TIME: c_short = 10; + +const _TIOC: c_int = ('T' as i32) << 8; +const tIOC: c_int = ('t' as i32) << 8; +pub const TCGETA: c_int = _TIOC | 1; +pub const TCSETA: c_int = _TIOC | 2; +pub const TCSETAW: c_int = _TIOC | 3; +pub const TCSETAF: c_int = _TIOC | 4; +pub const TCSBRK: c_int = _TIOC | 5; +pub const TCXONC: c_int = _TIOC | 6; +pub const TCFLSH: c_int = _TIOC | 7; +pub const TCDSET: c_int = _TIOC | 32; +pub const TCGETS: c_int = _TIOC | 13; +pub const TCSETS: c_int = _TIOC | 14; +pub const TCSANOW: c_int = _TIOC | 14; +pub const TCSETSW: c_int = _TIOC | 15; +pub const TCSADRAIN: c_int = _TIOC | 15; +pub const TCSETSF: c_int = _TIOC | 16; +pub const TCSAFLUSH: c_int = _TIOC | 16; +pub const TCIFLUSH: c_int = 0; +pub const TCOFLUSH: c_int = 1; +pub const TCIOFLUSH: c_int = 2; +pub const TCOOFF: c_int = 0; +pub const TCOON: c_int = 1; +pub const TCIOFF: c_int = 2; +pub const TCION: c_int = 3; +pub const TIOC: c_int = _TIOC; +pub const TIOCKBON: c_int = _TIOC | 8; +pub const TIOCKBOF: c_int = _TIOC | 9; +pub const TIOCGWINSZ: c_int = _TIOC | 104; +pub const TIOCSWINSZ: c_int = _TIOC | 103; +pub const TIOCGSOFTCAR: c_int = _TIOC | 105; +pub const TIOCSSOFTCAR: c_int = _TIOC | 106; +pub const TIOCGPPS: c_int = _TIOC | 125; +pub const TIOCSPPS: c_int = _TIOC | 126; +pub const TIOCGPPSEV: c_int = _TIOC | 127; +pub const TIOCGETD: c_int = tIOC | 0; +pub const TIOCSETD: c_int = tIOC | 1; +pub const TIOCHPCL: c_int = tIOC | 2; +pub const TIOCGETP: c_int = tIOC | 8; +pub const TIOCSETP: c_int = tIOC | 9; +pub const TIOCSETN: c_int = tIOC | 10; +pub const TIOCEXCL: c_int = tIOC | 13; +pub const TIOCNXCL: c_int = tIOC | 14; +pub const TIOCFLUSH: c_int = tIOC | 16; +pub const TIOCSETC: c_int = tIOC | 17; +pub const TIOCGETC: c_int = tIOC | 18; +pub const TIOCLBIS: c_int = tIOC | 127; +pub const TIOCLBIC: c_int = tIOC | 126; +pub const TIOCLSET: c_int = tIOC | 125; +pub const TIOCLGET: c_int = tIOC | 124; +pub const TIOCSBRK: c_int = tIOC | 123; +pub const TIOCCBRK: c_int = tIOC | 122; +pub const TIOCSDTR: c_int = tIOC | 121; +pub const TIOCCDTR: c_int = tIOC | 120; +pub const TIOCSLTC: c_int = tIOC | 117; +pub const TIOCGLTC: c_int = tIOC | 116; +pub const TIOCOUTQ: c_int = tIOC | 115; +pub const TIOCNOTTY: c_int = tIOC | 113; +pub const TIOCSCTTY: c_int = tIOC | 132; +pub const TIOCSTOP: c_int = tIOC | 111; +pub const TIOCSTART: c_int = tIOC | 110; +pub const TIOCSILOOP: c_int = tIOC | 109; +pub const TIOCCILOOP: c_int = tIOC | 108; +pub const TIOCGPGRP: c_int = tIOC | 20; +pub const TIOCSPGRP: c_int = tIOC | 21; +pub const TIOCGSID: c_int = tIOC | 22; +pub const TIOCSTI: c_int = tIOC | 23; +pub const TIOCMSET: c_int = tIOC | 26; +pub const TIOCMBIS: c_int = tIOC | 27; +pub const TIOCMBIC: c_int = tIOC | 28; +pub const TIOCMGET: c_int = tIOC | 29; +pub const TIOCREMOTE: c_int = tIOC | 30; +pub const TIOCSIGNAL: c_int = tIOC | 31; + +pub const TIOCM_LE: c_int = 0o0001; +pub const TIOCM_DTR: c_int = 0o0002; +pub const TIOCM_RTS: c_int = 0o0004; +pub const TIOCM_ST: c_int = 0o0010; +pub const TIOCM_SR: c_int = 0o0020; +pub const TIOCM_CTS: c_int = 0o0040; +pub const TIOCM_CAR: c_int = 0o0100; +pub const TIOCM_CD: c_int = TIOCM_CAR; +pub const TIOCM_RNG: c_int = 0o0200; +pub const TIOCM_RI: c_int = TIOCM_RNG; +pub const TIOCM_DSR: c_int = 0o0400; + +/* termios */ +pub const B0: speed_t = 0; +pub const B50: speed_t = 1; +pub const B75: speed_t = 2; +pub const B110: speed_t = 3; +pub const B134: speed_t = 4; +pub const B150: speed_t = 5; +pub const B200: speed_t = 6; +pub const B300: speed_t = 7; +pub const B600: speed_t = 8; +pub const B1200: speed_t = 9; +pub const B1800: speed_t = 10; +pub const B2400: speed_t = 11; +pub const B4800: speed_t = 12; +pub const B9600: speed_t = 13; +pub const B19200: speed_t = 14; +pub const B38400: speed_t = 15; +pub const B57600: speed_t = 16; +pub const B76800: speed_t = 17; +pub const B115200: speed_t = 18; +pub const B153600: speed_t = 19; +pub const B230400: speed_t = 20; +pub const B307200: speed_t = 21; +pub const B460800: speed_t = 22; +pub const B921600: speed_t = 23; +pub const CSTART: crate::tcflag_t = 0o21; +pub const CSTOP: crate::tcflag_t = 0o23; +pub const CSWTCH: crate::tcflag_t = 0o32; +pub const CBAUD: crate::tcflag_t = 0o17; +pub const CIBAUD: crate::tcflag_t = 0o3600000; +pub const CBAUDEXT: crate::tcflag_t = 0o10000000; +pub const CIBAUDEXT: crate::tcflag_t = 0o20000000; +pub const CSIZE: crate::tcflag_t = 0o000060; +pub const CS5: crate::tcflag_t = 0; +pub const CS6: crate::tcflag_t = 0o000020; +pub const CS7: crate::tcflag_t = 0o000040; +pub const CS8: crate::tcflag_t = 0o000060; +pub const CSTOPB: crate::tcflag_t = 0o000100; +pub const ECHO: crate::tcflag_t = 0o000010; +pub const ECHOE: crate::tcflag_t = 0o000020; +pub const ECHOK: crate::tcflag_t = 0o000040; +pub const ECHONL: crate::tcflag_t = 0o000100; +pub const ECHOCTL: crate::tcflag_t = 0o001000; +pub const ECHOPRT: crate::tcflag_t = 0o002000; +pub const ECHOKE: crate::tcflag_t = 0o004000; +pub const EXTPROC: crate::tcflag_t = 0o200000; +pub const IGNBRK: crate::tcflag_t = 0o000001; +pub const BRKINT: crate::tcflag_t = 0o000002; +pub const IGNPAR: crate::tcflag_t = 0o000004; +pub const PARMRK: crate::tcflag_t = 0o000010; +pub const INPCK: crate::tcflag_t = 0o000020; +pub const ISTRIP: crate::tcflag_t = 0o000040; +pub const INLCR: crate::tcflag_t = 0o000100; +pub const IGNCR: crate::tcflag_t = 0o000200; +pub const ICRNL: crate::tcflag_t = 0o000400; +pub const IUCLC: crate::tcflag_t = 0o001000; +pub const IXON: crate::tcflag_t = 0o002000; +pub const IXOFF: crate::tcflag_t = 0o010000; +pub const IXANY: crate::tcflag_t = 0o004000; +pub const IMAXBEL: crate::tcflag_t = 0o020000; +pub const DOSMODE: crate::tcflag_t = 0o100000; +pub const OPOST: crate::tcflag_t = 0o000001; +pub const OLCUC: crate::tcflag_t = 0o000002; +pub const ONLCR: crate::tcflag_t = 0o000004; +pub const OCRNL: crate::tcflag_t = 0o000010; +pub const ONOCR: crate::tcflag_t = 0o000020; +pub const ONLRET: crate::tcflag_t = 0o000040; +pub const OFILL: crate::tcflag_t = 0o0000100; +pub const OFDEL: crate::tcflag_t = 0o0000200; +pub const CREAD: crate::tcflag_t = 0o000200; +pub const PARENB: crate::tcflag_t = 0o000400; +pub const PARODD: crate::tcflag_t = 0o001000; +pub const HUPCL: crate::tcflag_t = 0o002000; +pub const CLOCAL: crate::tcflag_t = 0o004000; +pub const CRTSXOFF: crate::tcflag_t = 0o10000000000; +pub const CRTSCTS: crate::tcflag_t = 0o20000000000; +pub const ISIG: crate::tcflag_t = 0o000001; +pub const ICANON: crate::tcflag_t = 0o000002; +pub const IEXTEN: crate::tcflag_t = 0o100000; +pub const TOSTOP: crate::tcflag_t = 0o000400; +pub const FLUSHO: crate::tcflag_t = 0o020000; +pub const PENDIN: crate::tcflag_t = 0o040000; +pub const NOFLSH: crate::tcflag_t = 0o000200; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const VTIME: usize = 5; +pub const VSWTCH: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VDSUSP: usize = 11; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const VLNEXT: usize = 15; + +// +const STR: c_int = (b'S' as c_int) << 8; +pub const I_NREAD: c_int = STR | 0o1; +pub const I_PUSH: c_int = STR | 0o2; +pub const I_POP: c_int = STR | 0o3; +pub const I_LOOK: c_int = STR | 0o4; +pub const I_FLUSH: c_int = STR | 0o5; +pub const I_SRDOPT: c_int = STR | 0o6; +pub const I_GRDOPT: c_int = STR | 0o7; +pub const I_STR: c_int = STR | 0o10; +pub const I_SETSIG: c_int = STR | 0o11; +pub const I_GETSIG: c_int = STR | 0o12; +pub const I_FIND: c_int = STR | 0o13; +pub const I_LINK: c_int = STR | 0o14; +pub const I_UNLINK: c_int = STR | 0o15; +pub const I_PEEK: c_int = STR | 0o17; +pub const I_FDINSERT: c_int = STR | 0o20; +pub const I_SENDFD: c_int = STR | 0o21; +pub const I_RECVFD: c_int = STR | 0o16; +pub const I_SWROPT: c_int = STR | 0o23; +pub const I_GWROPT: c_int = STR | 0o24; +pub const I_LIST: c_int = STR | 0o25; +pub const I_PLINK: c_int = STR | 0o26; +pub const I_PUNLINK: c_int = STR | 0o27; +pub const I_ANCHOR: c_int = STR | 0o30; +pub const I_FLUSHBAND: c_int = STR | 0o34; +pub const I_CKBAND: c_int = STR | 0o35; +pub const I_GETBAND: c_int = STR | 0o36; +pub const I_ATMARK: c_int = STR | 0o37; +pub const I_SETCLTIME: c_int = STR | 0o40; +pub const I_GETCLTIME: c_int = STR | 0o41; +pub const I_CANPUT: c_int = STR | 0o42; +pub const I_SERROPT: c_int = STR | 0o43; +pub const I_GERROPT: c_int = STR | 0o44; +pub const I_ESETSIG: c_int = STR | 0o45; +pub const I_EGETSIG: c_int = STR | 0o46; +pub const __I_PUSH_NOCTTY: c_int = STR | 0o47; + +// 3SOCKET flags +pub const SOCK_CLOEXEC: c_int = 0x080000; +pub const SOCK_NONBLOCK: c_int = 0x100000; +pub const SOCK_NDELAY: c_int = 0x200000; + +// +pub const SCALE_KG: c_int = 1 << 6; +pub const SCALE_KF: c_int = 1 << 16; +pub const SCALE_KH: c_int = 1 << 2; +pub const MAXTC: c_int = 1 << 6; +pub const SCALE_PHASE: c_int = 1 << 22; +pub const SCALE_USEC: c_int = 1 << 16; +pub const SCALE_UPDATE: c_int = SCALE_KG * MAXTC; +pub const FINEUSEC: c_int = 1 << 22; +pub const MAXPHASE: c_int = 512000; +pub const MAXFREQ: c_int = 512 * SCALE_USEC; +pub const MAXTIME: c_int = 200 << PPS_AVG; +pub const MINSEC: c_int = 16; +pub const MAXSEC: c_int = 1200; +pub const PPS_AVG: c_int = 2; +pub const PPS_SHIFT: c_int = 2; +pub const PPS_SHIFTMAX: c_int = 8; +pub const PPS_VALID: c_int = 120; +pub const MAXGLITCH: c_int = 30; +pub const MOD_OFFSET: u32 = 0x0001; +pub const MOD_FREQUENCY: u32 = 0x0002; +pub const MOD_MAXERROR: u32 = 0x0004; +pub const MOD_ESTERROR: u32 = 0x0008; +pub const MOD_STATUS: u32 = 0x0010; +pub const MOD_TIMECONST: u32 = 0x0020; +pub const MOD_CLKB: u32 = 0x4000; +pub const MOD_CLKA: u32 = 0x8000; +pub const STA_PLL: u32 = 0x0001; +pub const STA_PPSFREQ: i32 = 0x0002; +pub const STA_PPSTIME: i32 = 0x0004; +pub const STA_FLL: i32 = 0x0008; +pub const STA_INS: i32 = 0x0010; +pub const STA_DEL: i32 = 0x0020; +pub const STA_UNSYNC: i32 = 0x0040; +pub const STA_FREQHOLD: i32 = 0x0080; +pub const STA_PPSSIGNAL: i32 = 0x0100; +pub const STA_PPSJITTER: i32 = 0x0200; +pub const STA_PPSWANDER: i32 = 0x0400; +pub const STA_PPSERROR: i32 = 0x0800; +pub const STA_CLOCKERR: i32 = 0x1000; +pub const STA_RONLY: i32 = + STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR | STA_CLOCKERR; +pub const TIME_OK: i32 = 0; +pub const TIME_INS: i32 = 1; +pub const TIME_DEL: i32 = 2; +pub const TIME_OOP: i32 = 3; +pub const TIME_WAIT: i32 = 4; +pub const TIME_ERROR: i32 = 5; + +pub const PRIO_PROCESS: c_int = 0; +pub const PRIO_PGRP: c_int = 1; +pub const PRIO_USER: c_int = 2; + +pub const SCHED_OTHER: c_int = 0; +pub const SCHED_FIFO: c_int = 1; +pub const SCHED_RR: c_int = 2; +pub const SCHED_SYS: c_int = 3; +pub const SCHED_IA: c_int = 4; +pub const SCHED_FSS: c_int = 5; +pub const SCHED_FX: c_int = 6; + +// sys/priv.h +pub const PRIV_DEBUG: c_uint = 0x0001; +pub const PRIV_AWARE: c_uint = 0x0002; +pub const PRIV_AWARE_INHERIT: c_uint = 0x0004; +pub const __PROC_PROTECT: c_uint = 0x0008; +pub const NET_MAC_AWARE: c_uint = 0x0010; +pub const NET_MAC_AWARE_INHERIT: c_uint = 0x0020; +pub const PRIV_AWARE_RESET: c_uint = 0x0040; +pub const PRIV_XPOLICY: c_uint = 0x0080; +pub const PRIV_PFEXEC: c_uint = 0x0100; + +// sys/systeminfo.h +pub const SI_SYSNAME: c_int = 1; +pub const SI_HOSTNAME: c_int = 2; +pub const SI_RELEASE: c_int = 3; +pub const SI_VERSION: c_int = 4; +pub const SI_MACHINE: c_int = 5; +pub const SI_ARCHITECTURE: c_int = 6; +pub const SI_HW_SERIAL: c_int = 7; +pub const SI_HW_PROVIDER: c_int = 8; +pub const SI_SET_HOSTNAME: c_int = 258; +pub const SI_SET_SRPC_DOMAIN: c_int = 265; +pub const SI_PLATFORM: c_int = 513; +pub const SI_ISALIST: c_int = 514; +pub const SI_DHCP_CACHE: c_int = 515; +pub const SI_ARCHITECTURE_32: c_int = 516; +pub const SI_ARCHITECTURE_64: c_int = 517; +pub const SI_ARCHITECTURE_K: c_int = 518; +pub const SI_ARCHITECTURE_NATIVE: c_int = 519; + +// sys/lgrp_user.h +pub const LGRP_COOKIE_NONE: crate::lgrp_cookie_t = 0; +pub const LGRP_AFF_NONE: crate::lgrp_affinity_t = 0x0; +pub const LGRP_AFF_WEAK: crate::lgrp_affinity_t = 0x10; +pub const LGRP_AFF_STRONG: crate::lgrp_affinity_t = 0x100; +pub const LGRP_CONTENT_ALL: crate::lgrp_content_t = 0; +pub const LGRP_CONTENT_HIERARCHY: crate::lgrp_content_t = LGRP_CONTENT_ALL; +pub const LGRP_CONTENT_DIRECT: crate::lgrp_content_t = 1; +pub const LGRP_LAT_CPU_TO_MEM: crate::lgrp_lat_between_t = 0; +pub const LGRP_MEM_SZ_FREE: crate::lgrp_mem_size_flag_t = 0; +pub const LGRP_MEM_SZ_INSTALLED: crate::lgrp_mem_size_flag_t = 1; +pub const LGRP_VIEW_CALLER: crate::lgrp_view_t = 0; +pub const LGRP_VIEW_OS: crate::lgrp_view_t = 1; + +// sys/processor.h + +pub const P_OFFLINE: c_int = 0x001; +pub const P_ONLINE: c_int = 0x002; +pub const P_STATUS: c_int = 0x003; +pub const P_FAULTED: c_int = 0x004; +pub const P_POWEROFF: c_int = 0x005; +pub const P_NOINTR: c_int = 0x006; +pub const P_SPARE: c_int = 0x007; +pub const P_FORCED: c_int = 0x10000000; +pub const PI_TYPELEN: c_int = 16; +pub const PI_FPUTYPE: c_int = 32; + +// sys/auxv.h +pub const AT_SUN_HWCAP: c_uint = 2009; + +// As per sys/socket.h, header alignment must be 8 bytes on SPARC +// and 4 bytes everywhere else: +#[cfg(target_arch = "sparc64")] +const _CMSG_HDR_ALIGNMENT: usize = 8; +#[cfg(not(target_arch = "sparc64"))] +const _CMSG_HDR_ALIGNMENT: usize = 4; + +const _CMSG_DATA_ALIGNMENT: usize = size_of::(); + +const NEWDEV: c_int = 1; + +// sys/sendfile.h +pub const SFV_FD_SELF: c_int = -2; + +const fn _CMSG_HDR_ALIGN(p: usize) -> usize { + (p + _CMSG_HDR_ALIGNMENT - 1) & !(_CMSG_HDR_ALIGNMENT - 1) +} + +const fn _CMSG_DATA_ALIGN(p: usize) -> usize { + (p + _CMSG_DATA_ALIGNMENT - 1) & !(_CMSG_DATA_ALIGNMENT - 1) +} + +f! { + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + _CMSG_DATA_ALIGN(cmsg.offset(1) as usize) as *mut c_uchar + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + _CMSG_DATA_ALIGN(size_of::()) as c_uint + length + } + + pub fn CMSG_FIRSTHDR(mhdr: *const crate::msghdr) -> *mut cmsghdr { + if ((*mhdr).msg_controllen as usize) < size_of::() { + core::ptr::null_mut::() + } else { + (*mhdr).msg_control as *mut cmsghdr + } + } + + pub fn CMSG_NXTHDR(mhdr: *const crate::msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if cmsg.is_null() { + return crate::CMSG_FIRSTHDR(mhdr); + } + let next = + _CMSG_HDR_ALIGN(cmsg as usize + (*cmsg).cmsg_len as usize + size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next > max { + core::ptr::null_mut::() + } else { + _CMSG_HDR_ALIGN(cmsg as usize + (*cmsg).cmsg_len as usize) as *mut cmsghdr + } + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + _CMSG_HDR_ALIGN(size_of::() as usize + length as usize) as c_uint + } + + pub fn FD_CLR(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return; + } + + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0; + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let bits = size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return; + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +safe_f! { + pub fn SIGRTMAX() -> c_int { + unsafe { crate::sysconf(_SC_SIGRT_MAX) as c_int } + } + + pub fn SIGRTMIN() -> c_int { + unsafe { crate::sysconf(_SC_SIGRT_MIN) as c_int } + } + + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0xFF) == 0 + } + + pub const fn WEXITSTATUS(status: c_int) -> c_int { + (status >> 8) & 0xFF + } + + pub const fn WTERMSIG(status: c_int) -> c_int { + status & 0x7F + } + + pub const fn WIFCONTINUED(status: c_int) -> bool { + (status & 0xffff) == 0xffff + } + + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status & 0xff00) >> 8 + } + + pub const fn WIFSIGNALED(status: c_int) -> bool { + ((status & 0xff) > 0) && (status & 0xff00 == 0) + } + + pub const fn WIFSTOPPED(status: c_int) -> bool { + ((status & 0xff) == 0x7f) && ((status & 0xff00) != 0) + } + + pub const fn WCOREDUMP(status: c_int) -> bool { + (status & 0x80) != 0 + } + + pub const fn MR_GET_TYPE(flags: c_uint) -> c_uint { + flags & 0x0000ffff + } +} + +extern "C" { + pub fn getrlimit(resource: c_int, rlim: *mut crate::rlimit) -> c_int; + pub fn setrlimit(resource: c_int, rlim: *const crate::rlimit) -> c_int; + + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn sem_destroy(sem: *mut sem_t) -> c_int; + pub fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int; + + pub fn abs(i: c_int) -> c_int; + pub fn acct(filename: *const c_char) -> c_int; + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + pub fn getrandom(bbuf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn settimeofday(tp: *const crate::timeval, tz: *const c_void) -> c_int; + pub fn getifaddrs(ifap: *mut *mut crate::ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *mut crate::ifaddrs); + + pub fn stack_getbounds(sp: *mut crate::stack_t) -> c_int; + pub fn getgrouplist( + name: *const c_char, + basegid: crate::gid_t, + groups: *mut crate::gid_t, + ngroups: *mut c_int, + ) -> c_int; + pub fn initgroups(name: *const c_char, basegid: crate::gid_t) -> c_int; + pub fn setgroups(ngroups: c_int, ptr: *const crate::gid_t) -> c_int; + pub fn ioctl(fildes: c_int, request: c_int, ...) -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn ___errno() -> *mut c_int; + pub fn clock_getres(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_gettime(clk_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + pub fn clock_nanosleep( + clk_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + pub fn clock_settime(clk_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + pub fn getnameinfo( + sa: *const crate::sockaddr, + salen: crate::socklen_t, + host: *mut c_char, + hostlen: crate::socklen_t, + serv: *mut c_char, + servlen: crate::socklen_t, + flags: c_int, + ) -> c_int; + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn fdatasync(fd: c_int) -> c_int; + pub fn nl_langinfo_l(item: crate::nl_item, locale: crate::locale_t) -> *mut c_char; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn getprogname() -> *const c_char; + pub fn setprogname(name: *const c_char); + pub fn getloadavg(loadavg: *mut c_double, nelem: c_int) -> c_int; + pub fn getpriority(which: c_int, who: c_int) -> c_int; + pub fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; + + pub fn mknodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int; + pub fn mkfifoat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn sethostname(name: *const c_char, len: c_int) -> c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn pthread_create( + native: *mut crate::pthread_t, + attr: *const crate::pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn pthread_attr_getstack( + attr: *const crate::pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setclock( + attr: *mut pthread_condattr_t, + clock_id: crate::clockid_t, + ) -> c_int; + pub fn sem_timedwait(sem: *mut sem_t, abstime: *const crate::timespec) -> c_int; + pub fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int; + pub fn pthread_mutex_timedlock( + lock: *mut pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + pub fn pthread_getname_np(tid: crate::pthread_t, name: *mut c_char, len: size_t) -> c_int; + pub fn pthread_setname_np(tid: crate::pthread_t, name: *const c_char) -> c_int; + pub fn waitid( + idtype: idtype_t, + id: id_t, + infop: *mut crate::siginfo_t, + options: c_int, + ) -> c_int; + + #[cfg_attr(target_os = "illumos", link_name = "_glob_ext")] + pub fn glob( + pattern: *const c_char, + flags: c_int, + errfunc: Option c_int>, + pglob: *mut crate::glob_t, + ) -> c_int; + + #[cfg_attr(target_os = "illumos", link_name = "_globfree_ext")] + pub fn globfree(pglob: *mut crate::glob_t); + + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn posix_spawn( + pid: *mut crate::pid_t, + path: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + attrp: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + pub fn posix_spawnp( + pid: *mut crate::pid_t, + file: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + attrp: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> c_int; + + pub fn posix_spawn_file_actions_init(file_actions: *mut posix_spawn_file_actions_t) -> c_int; + pub fn posix_spawn_file_actions_destroy(file_actions: *mut posix_spawn_file_actions_t) + -> c_int; + pub fn posix_spawn_file_actions_addopen( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + path: *const c_char, + oflag: c_int, + mode: mode_t, + ) -> c_int; + pub fn posix_spawn_file_actions_addclose( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_adddup2( + file_actions: *mut posix_spawn_file_actions_t, + fildes: c_int, + newfildes: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_addclosefrom_np( + file_actions: *mut posix_spawn_file_actions_t, + lowfiledes: c_int, + ) -> c_int; + pub fn posix_spawn_file_actions_addchdir( + file_actions: *mut posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + pub fn posix_spawn_file_actions_addchdir_np( + file_actions: *mut posix_spawn_file_actions_t, + path: *const c_char, + ) -> c_int; + pub fn posix_spawn_file_actions_addfchdir( + file_actions: *mut posix_spawn_file_actions_t, + fd: c_int, + ) -> c_int; + + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, flags: c_short) -> c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *mut c_short) -> c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, pgroup: crate::pid_t) -> c_int; + pub fn posix_spawnattr_getpgroup( + attr: *const posix_spawnattr_t, + _pgroup: *mut crate::pid_t, + ) -> c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut crate::sched_param, + ) -> c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, policy: c_int) -> c_int; + pub fn posix_spawnattr_getschedpolicy( + attr: *const posix_spawnattr_t, + _policy: *mut c_int, + ) -> c_int; + pub fn posix_spawnattr_setsigdefault( + attr: *mut posix_spawnattr_t, + sigdefault: *const sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigdefault( + attr: *const posix_spawnattr_t, + sigdefault: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigignore_np( + attr: *mut posix_spawnattr_t, + sigignore: *const sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigignore_np( + attr: *const posix_spawnattr_t, + sigignore: *mut sigset_t, + ) -> c_int; + pub fn posix_spawnattr_setsigmask( + attr: *mut posix_spawnattr_t, + sigmask: *const sigset_t, + ) -> c_int; + pub fn posix_spawnattr_getsigmask( + attr: *const posix_spawnattr_t, + sigmask: *mut sigset_t, + ) -> c_int; + + pub fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void; + + pub fn shmctl(shmid: c_int, cmd: c_int, buf: *mut crate::shmid_ds) -> c_int; + + pub fn shmdt(shmaddr: *const c_void) -> c_int; + + pub fn shmget(key: key_t, size: size_t, shmflg: c_int) -> c_int; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn memalign(align: size_t, size: size_t) -> *mut c_void; + + pub fn recvfrom( + socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut crate::sockaddr, + addrlen: *mut crate::socklen_t, + ) -> ssize_t; + pub fn mkstemps(template: *mut c_char, suffixlen: c_int) -> c_int; + pub fn futimesat(fd: c_int, path: *const c_char, times: *const crate::timeval) -> c_int; + pub fn futimens(dirfd: c_int, times: *const crate::timespec) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + + #[link_name = "__xnet_bind"] + pub fn bind( + socket: c_int, + address: *const crate::sockaddr, + address_len: crate::socklen_t, + ) -> c_int; + + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + #[link_name = "__xnet_sendmsg"] + pub fn sendmsg(fd: c_int, msg: *const crate::msghdr, flags: c_int) -> ssize_t; + #[link_name = "__xnet_recvmsg"] + pub fn recvmsg(fd: c_int, msg: *mut crate::msghdr, flags: c_int) -> ssize_t; + pub fn accept4( + fd: c_int, + address: *mut sockaddr, + address_len: *mut socklen_t, + flags: c_int, + ) -> c_int; + + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + pub fn port_create() -> c_int; + pub fn port_associate( + port: c_int, + source: c_int, + object: crate::uintptr_t, + events: c_int, + user: *mut c_void, + ) -> c_int; + pub fn port_dissociate(port: c_int, source: c_int, object: crate::uintptr_t) -> c_int; + pub fn port_get(port: c_int, pe: *mut port_event, timeout: *mut crate::timespec) -> c_int; + pub fn port_getn( + port: c_int, + pe_list: *mut port_event, + max: c_uint, + nget: *mut c_uint, + timeout: *mut crate::timespec, + ) -> c_int; + pub fn port_send(port: c_int, events: c_int, user: *mut c_void) -> c_int; + pub fn port_sendn( + port_list: *mut c_int, + error_list: *mut c_int, + nent: c_uint, + events: c_int, + user: *mut c_void, + ) -> c_int; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getgrgid_r" + )] + pub fn getgrgid_r( + gid: crate::gid_t, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn sigaltstack(ss: *const stack_t, oss: *mut stack_t) -> c_int; + pub fn sigsuspend(mask: *const crate::sigset_t) -> c_int; + pub fn sem_close(sem: *mut sem_t) -> c_int; + pub fn getdtablesize() -> c_int; + + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getgrnam_r" + )] + pub fn getgrnam_r( + name: *const c_char, + grp: *mut crate::group, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut crate::group, + ) -> c_int; + pub fn thr_self() -> crate::thread_t; + pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sem_open(name: *const c_char, oflag: c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const c_char) -> *mut crate::group; + #[cfg_attr(target_os = "solaris", link_name = "__pthread_kill_xpg7")] + pub fn pthread_kill(thread: crate::pthread_t, sig: c_int) -> c_int; + pub fn sched_get_priority_min(policy: c_int) -> c_int; + pub fn sched_get_priority_max(policy: c_int) -> c_int; + pub fn sched_getparam(pid: crate::pid_t, param: *mut sched_param) -> c_int; + pub fn sched_setparam(pid: crate::pid_t, param: *const sched_param) -> c_int; + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + pub fn sem_unlink(name: *const c_char) -> c_int; + pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getpwnam_r" + )] + pub fn getpwnam_r( + name: *const c_char, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getpwuid_r" + )] + pub fn getpwuid_r( + uid: crate::uid_t, + pwd: *mut passwd, + buf: *mut c_char, + buflen: size_t, + result: *mut *mut passwd, + ) -> c_int; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "getpwent_r" + )] + fn native_getpwent_r(pwd: *mut passwd, buf: *mut c_char, buflen: c_int) -> *mut passwd; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "getgrent_r" + )] + fn native_getgrent_r( + grp: *mut crate::group, + buf: *mut c_char, + buflen: c_int, + ) -> *mut crate::group; + #[cfg_attr( + any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_sigwait" + )] + pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + pub fn getgrgid(gid: crate::gid_t) -> *mut crate::group; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut crate::group; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + + pub fn dup3(src: c_int, dst: c_int, flags: c_int) -> c_int; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn pipe2(fds: *mut c_int, flags: c_int) -> c_int; + + pub fn makeutx(ux: *const utmpx) -> *mut utmpx; + pub fn modutx(ux: *const utmpx) -> *mut utmpx; + pub fn updwtmpx(file: *const c_char, ut: *mut utmpx); + pub fn utmpxname(file: *const c_char) -> c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + + pub fn endutent(); + pub fn getutent() -> *mut utmp; + pub fn getutid(u: *const utmp) -> *mut utmp; + pub fn getutline(u: *const utmp) -> *mut utmp; + pub fn pututline(u: *const utmp) -> *mut utmp; + pub fn setutent(); + pub fn utmpname(file: *const c_char) -> c_int; + + pub fn getutmp(ux: *const utmpx, u: *mut utmp); + pub fn getutmpx(u: *const utmp, ux: *mut utmpx); + pub fn updwtmp(file: *const c_char, u: *mut utmp); + + pub fn ntp_adjtime(buf: *mut timex) -> c_int; + pub fn ntp_gettime(buf: *mut ntptimeval) -> c_int; + + pub fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> c_int; + pub fn timer_delete(timerid: timer_t) -> c_int; + pub fn timer_getoverrun(timerid: timer_t) -> c_int; + pub fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int; + pub fn timer_settime( + timerid: timer_t, + flags: c_int, + value: *const itimerspec, + ovalue: *mut itimerspec, + ) -> c_int; + + pub fn ucred_get(pid: crate::pid_t) -> *mut ucred_t; + pub fn getpeerucred(fd: c_int, ucred: *mut *mut ucred_t) -> c_int; + + pub fn ucred_free(ucred: *mut ucred_t); + + pub fn ucred_geteuid(ucred: *const ucred_t) -> crate::uid_t; + pub fn ucred_getruid(ucred: *const ucred_t) -> crate::uid_t; + pub fn ucred_getsuid(ucred: *const ucred_t) -> crate::uid_t; + pub fn ucred_getegid(ucred: *const ucred_t) -> crate::gid_t; + pub fn ucred_getrgid(ucred: *const ucred_t) -> crate::gid_t; + pub fn ucred_getsgid(ucred: *const ucred_t) -> crate::gid_t; + pub fn ucred_getgroups(ucred: *const ucred_t, groups: *mut *const crate::gid_t) -> c_int; + pub fn ucred_getpid(ucred: *const ucred_t) -> crate::pid_t; + pub fn ucred_getprojid(ucred: *const ucred_t) -> projid_t; + pub fn ucred_getzoneid(ucred: *const ucred_t) -> zoneid_t; + pub fn ucred_getpflags(ucred: *const ucred_t, flags: c_uint) -> c_uint; + + pub fn ucred_size() -> size_t; + + pub fn pset_create(newpset: *mut crate::psetid_t) -> c_int; + pub fn pset_destroy(pset: crate::psetid_t) -> c_int; + pub fn pset_assign( + pset: crate::psetid_t, + cpu: crate::processorid_t, + opset: *mut psetid_t, + ) -> c_int; + pub fn pset_info( + pset: crate::psetid_t, + tpe: *mut c_int, + numcpus: *mut c_uint, + cpulist: *mut processorid_t, + ) -> c_int; + pub fn pset_bind( + pset: crate::psetid_t, + idtype: crate::idtype_t, + id: crate::id_t, + opset: *mut psetid_t, + ) -> c_int; + pub fn pset_list(pset: *mut psetid_t, numpsets: *mut c_uint) -> c_int; + pub fn pset_setattr(pset: psetid_t, attr: c_uint) -> c_int; + pub fn pset_getattr(pset: psetid_t, attr: *mut c_uint) -> c_int; + pub fn processor_bind( + idtype: crate::idtype_t, + id: crate::id_t, + new_binding: crate::processorid_t, + old_binding: *mut processorid_t, + ) -> c_int; + pub fn p_online(processorid: crate::processorid_t, flag: c_int) -> c_int; + pub fn processor_info(processorid: crate::processorid_t, infop: *mut processor_info_t) + -> c_int; + + pub fn getexecname() -> *const c_char; + + pub fn gethostid() -> c_long; + + pub fn getpflags(flags: c_uint) -> c_uint; + pub fn setpflags(flags: c_uint, value: c_uint) -> c_int; + + pub fn sysinfo(command: c_int, buf: *mut c_char, count: c_long) -> c_int; + + pub fn faccessat(fd: c_int, path: *const c_char, amode: c_int, flag: c_int) -> c_int; + + // #include + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn dl_iterate_phdr( + callback: Option< + unsafe extern "C" fn(info: *mut dl_phdr_info, size: usize, data: *mut c_void) -> c_int, + >, + data: *mut c_void, + ) -> c_int; + pub fn getpagesize() -> c_int; + pub fn getpagesizes(pagesize: *mut size_t, nelem: c_int) -> c_int; + pub fn mmapobj( + fd: c_int, + flags: c_uint, + storage: *mut mmapobj_result_t, + elements: *mut c_uint, + arg: *mut c_void, + ) -> c_int; + pub fn meminfo( + inaddr: *const u64, + addr_count: c_int, + info_req: *const c_uint, + info_count: c_int, + outdata: *mut u64, + validity: *mut c_uint, + ) -> c_int; + + pub fn strsep(string: *mut *mut c_char, delim: *const c_char) -> *mut c_char; + + pub fn getisax(array: *mut u32, n: c_uint) -> c_uint; + + pub fn backtrace(buffer: *mut *mut c_void, size: c_int) -> c_int; + pub fn backtrace_symbols(buffer: *const *mut c_void, size: c_int) -> *mut *mut c_char; + pub fn backtrace_symbols_fd(buffer: *const *mut c_void, size: c_int, fd: c_int); + + pub fn getopt_long( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, + longopts: *const option, + longindex: *mut c_int, + ) -> c_int; + + pub fn sync(); + + pub fn aio_cancel(fd: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_error(aiocbp: *const aiocb) -> c_int; + pub fn aio_fsync(op: c_int, aiocbp: *mut aiocb) -> c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ssize_t; + pub fn aio_suspend( + aiocb_list: *const *const aiocb, + nitems: c_int, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_waitn( + aiocb_list: *mut *mut aiocb, + nent: c_uint, + nwait: *mut c_uint, + timeout: *const crate::timespec, + ) -> c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> c_int; + pub fn lio_listio( + mode: c_int, + aiocb_list: *const *mut aiocb, + nitems: c_int, + sevp: *mut sigevent, + ) -> c_int; + + pub fn __major(version: c_int, devnum: crate::dev_t) -> crate::major_t; + pub fn __minor(version: c_int, devnum: crate::dev_t) -> crate::minor_t; + pub fn __makedev( + version: c_int, + majdev: crate::major_t, + mindev: crate::minor_t, + ) -> crate::dev_t; + + pub fn arc4random() -> u32; + pub fn arc4random_buf(buf: *mut c_void, nbytes: size_t); + pub fn arc4random_uniform(upper_bound: u32) -> u32; + + pub fn secure_getenv(name: *const c_char) -> *mut c_char; + + #[cfg_attr(target_os = "solaris", link_name = "__strftime_xpg7")] + pub fn strftime( + s: *mut c_char, + maxsize: size_t, + format: *const c_char, + timeptr: *const crate::tm, + ) -> size_t; + pub fn strftime_l( + s: *mut c_char, + maxsize: size_t, + format: *const c_char, + timeptr: *const crate::tm, + loc: crate::locale_t, + ) -> size_t; +} + +#[link(name = "sendfile")] +extern "C" { + pub fn sendfile(out_fd: c_int, in_fd: c_int, off: *mut off_t, len: size_t) -> ssize_t; + pub fn sendfilev( + fildes: c_int, + vec: *const sendfilevec_t, + sfvcnt: c_int, + xferred: *mut size_t, + ) -> ssize_t; +} + +#[link(name = "lgrp")] +extern "C" { + pub fn lgrp_init(view: lgrp_view_t) -> lgrp_cookie_t; + pub fn lgrp_fini(cookie: lgrp_cookie_t) -> c_int; + pub fn lgrp_affinity_get( + idtype: crate::idtype_t, + id: crate::id_t, + lgrp: crate::lgrp_id_t, + ) -> crate::lgrp_affinity_t; + pub fn lgrp_affinity_set( + idtype: crate::idtype_t, + id: crate::id_t, + lgrp: crate::lgrp_id_t, + aff: lgrp_affinity_t, + ) -> c_int; + pub fn lgrp_cpus( + cookie: crate::lgrp_cookie_t, + lgrp: crate::lgrp_id_t, + cpuids: *mut crate::processorid_t, + count: c_uint, + content: crate::lgrp_content_t, + ) -> c_int; + pub fn lgrp_mem_size( + cookie: crate::lgrp_cookie_t, + lgrp: crate::lgrp_id_t, + tpe: crate::lgrp_mem_size_flag_t, + content: crate::lgrp_content_t, + ) -> crate::lgrp_mem_size_t; + pub fn lgrp_nlgrps(cookie: crate::lgrp_cookie_t) -> c_int; + pub fn lgrp_view(cookie: crate::lgrp_cookie_t) -> crate::lgrp_view_t; + pub fn lgrp_home(idtype: crate::idtype_t, id: crate::id_t) -> crate::lgrp_id_t; + pub fn lgrp_version(version: c_int) -> c_int; + pub fn lgrp_resources( + cookie: crate::lgrp_cookie_t, + lgrp: crate::lgrp_id_t, + lgrps: *mut crate::lgrp_id_t, + count: c_uint, + tpe: crate::lgrp_rsrc_t, + ) -> c_int; + pub fn lgrp_root(cookie: crate::lgrp_cookie_t) -> crate::lgrp_id_t; +} + +pub unsafe fn major(device: crate::dev_t) -> crate::major_t { + __major(NEWDEV, device) +} + +pub unsafe fn minor(device: crate::dev_t) -> crate::minor_t { + __minor(NEWDEV, device) +} + +pub unsafe fn makedev(maj: crate::major_t, min: crate::minor_t) -> crate::dev_t { + __makedev(NEWDEV, maj, min) +} + +mod compat; +pub use self::compat::*; + +cfg_if! { + if #[cfg(target_os = "illumos")] { + mod illumos; + pub use self::illumos::*; + } else if #[cfg(target_os = "solaris")] { + mod solaris; + pub use self::solaris::*; + } else { + // Unknown target_os + } +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + mod x86_common; + pub use self::x86_64::*; + pub use self::x86_common::*; + } else if #[cfg(target_arch = "x86")] { + mod x86; + mod x86_common; + pub use self::x86::*; + pub use self::x86_common::*; + } +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/solaris.rs b/deps/crates/vendor/libc/src/unix/solarish/solaris.rs new file mode 100644 index 00000000000000..2b9ace5e9c4905 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/solaris.rs @@ -0,0 +1,204 @@ +use crate::prelude::*; +use crate::{ + exit_status, + off_t, + termios, + NET_MAC_AWARE, + NET_MAC_AWARE_INHERIT, + PRIV_AWARE_RESET, + PRIV_DEBUG, + PRIV_PFEXEC, + PRIV_XPOLICY, +}; + +pub type door_attr_t = c_uint; +pub type door_id_t = c_ulonglong; +pub type lgrp_affinity_t = c_uint; + +e! { + #[repr(u32)] + pub enum lgrp_rsrc_t { + LGRP_RSRC_CPU = 0, + LGRP_RSRC_MEM = 1, + LGRP_RSRC_TYPES = 2, + } +} + +s! { + pub struct aiocb { + pub aio_fildes: c_int, + pub aio_buf: *mut c_void, + pub aio_nbytes: size_t, + pub aio_offset: off_t, + pub aio_reqprio: c_int, + pub aio_sigevent: crate::sigevent, + pub aio_lio_opcode: c_int, + pub aio_resultp: crate::aio_result_t, + pub aio_state: c_char, + pub aio_returned: c_char, + pub aio__pad1: [c_char; 2], + pub aio_flags: c_int, + } + + pub struct shmid_ds { + pub shm_perm: crate::ipc_perm, + pub shm_segsz: size_t, + pub shm_flags: crate::uintptr_t, + pub shm_lkcnt: c_ushort, + pub shm_lpid: crate::pid_t, + pub shm_cpid: crate::pid_t, + pub shm_nattch: crate::shmatt_t, + pub shm_cnattch: c_ulong, + pub shm_atime: crate::time_t, + pub shm_dtime: crate::time_t, + pub shm_ctime: crate::time_t, + pub shm_amp: *mut c_void, + pub shm_gransize: u64, + pub shm_allocated: u64, + pub shm_pad4: [i64; 1], + } + + pub struct xrs_t { + pub xrs_id: c_ulong, + pub xrs_ptr: *mut c_char, + } + + pub struct utmpx { + pub ut_user: [c_char; _UTMP_USER_LEN], + pub ut_id: [c_char; _UTMP_ID_LEN], + pub ut_line: [c_char; _UTMP_LINE_LEN], + pub ut_pid: crate::pid_t, + pub ut_type: c_short, + pub ut_exit: exit_status, + pub ut_tv: crate::timeval, + pub ut_session: c_int, + pub pad: [c_int; 5], + pub ut_syslen: c_short, + pub ut_host: [c_char; 257], + } +} + +s_no_extra_traits! { + #[repr(packed)] + pub struct door_desc_t__d_data__d_desc { + pub d_descriptor: c_int, + pub d_id: crate::door_id_t, + } + + pub union door_desc_t__d_data { + pub d_desc: door_desc_t__d_data__d_desc, + d_resv: [c_int; 5], /* Check out /usr/include/sys/door.h */ + } + + pub struct door_desc_t { + pub d_attributes: door_attr_t, + pub d_data: door_desc_t__d_data, + } + + pub struct door_arg_t { + pub data_ptr: *const c_char, + pub data_size: size_t, + pub desc_ptr: *const door_desc_t, + pub dec_num: c_uint, + pub rbuf: *const c_char, + pub rsize: size_t, + } +} + +// FIXME(solaris): O_DIRECT and SIGINFO are NOT available on Solaris. +// But in past they were defined here and thus other crates expected them. +// Latest version v0.29.0 of Nix crate still expects this. Since last +// version of Nix crate is almost one year ago let's define these two +// temporarily before new Nix version is released. +pub const O_DIRECT: c_int = 0x2000000; +pub const SIGINFO: c_int = 41; + +pub const _UTMP_USER_LEN: usize = 32; +pub const _UTMP_LINE_LEN: usize = 32; +pub const _UTMP_ID_LEN: usize = 4; + +pub const PORT_SOURCE_POSTWAIT: c_int = 8; +pub const PORT_SOURCE_SIGNAL: c_int = 9; + +pub const AF_LOCAL: c_int = 1; // AF_UNIX +pub const AF_FILE: c_int = 1; // AF_UNIX + +pub const TCP_KEEPIDLE: c_int = 0x1d; +pub const TCP_KEEPINTVL: c_int = 0x1e; +pub const TCP_KEEPCNT: c_int = 0x1f; + +pub const F_DUPFD_CLOEXEC: c_int = 47; +pub const F_DUPFD_CLOFORK: c_int = 49; +pub const F_DUP2FD_CLOEXEC: c_int = 48; +pub const F_DUP2FD_CLOFORK: c_int = 50; + +pub const _PC_LAST: c_int = 102; + +pub const PRIV_PROC_SENSITIVE: c_uint = 0x0008; +pub const PRIV_PFEXEC_AUTH: c_uint = 0x0200; +pub const PRIV_PROC_TPD: c_uint = 0x0400; +pub const PRIV_TPD_UNSAFE: c_uint = 0x0800; +pub const PRIV_PROC_TPD_RESET: c_uint = 0x1000; +pub const PRIV_TPD_KILLABLE: c_uint = 0x2000; + +pub const POSIX_SPAWN_SETSID: c_short = 0x400; + +pub const PRIV_USER: c_uint = PRIV_DEBUG + | PRIV_PROC_SENSITIVE + | NET_MAC_AWARE + | NET_MAC_AWARE_INHERIT + | PRIV_XPOLICY + | PRIV_AWARE_RESET + | PRIV_PFEXEC + | PRIV_PFEXEC_AUTH + | PRIV_PROC_TPD + | PRIV_TPD_UNSAFE + | PRIV_TPD_KILLABLE + | PRIV_PROC_TPD_RESET; + +extern "C" { + // DIFF(main): changed to `*const *mut` in e77f551de9 + pub fn fexecve(fd: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; + + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_char) -> c_int; + + pub fn door_call(d: c_int, params: *mut door_arg_t) -> c_int; + pub fn door_return( + data_ptr: *mut c_char, + data_size: size_t, + desc_ptr: *mut door_desc_t, + num_desc: c_uint, + ) -> c_int; + pub fn door_create( + server_procedure: extern "C" fn( + cookie: *mut c_void, + argp: *mut c_char, + arg_size: size_t, + dp: *mut door_desc_t, + n_desc: c_uint, + ), + cookie: *mut c_void, + attributes: door_attr_t, + ) -> c_int; + + pub fn fattach(fildes: c_int, path: *const c_char) -> c_int; + + pub fn pthread_getattr_np(thread: crate::pthread_t, attr: *mut crate::pthread_attr_t) -> c_int; + + pub fn euidaccess(path: *const c_char, amode: c_int) -> c_int; + + pub fn openpty( + amain: *mut c_int, + asubord: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> c_int; + + pub fn forkpty( + amain: *mut c_int, + name: *mut c_char, + termp: *mut termios, + winp: *mut crate::winsize, + ) -> crate::pid_t; +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/x86.rs b/deps/crates/vendor/libc/src/unix/solarish/x86.rs new file mode 100644 index 00000000000000..a37ed3d74e978c --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/x86.rs @@ -0,0 +1,31 @@ +use crate::prelude::*; + +pub type Elf32_Addr = c_ulong; +pub type Elf32_Half = c_ushort; +pub type Elf32_Off = c_ulong; +pub type Elf32_Sword = c_long; +pub type Elf32_Word = c_ulong; +pub type Elf32_Lword = c_ulonglong; +pub type Elf32_Phdr = __c_anonymous_Elf32_Phdr; + +s! { + pub struct __c_anonymous_Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct dl_phdr_info { + pub dlpi_addr: Elf32_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const Elf32_Phdr, + pub dlpi_phnum: Elf32_Half, + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + } +} diff --git a/deps/crates/vendor/libc/src/unix/solarish/x86_64.rs b/deps/crates/vendor/libc/src/unix/solarish/x86_64.rs new file mode 100644 index 00000000000000..a4c48064aaaa9a --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/x86_64.rs @@ -0,0 +1,154 @@ +use crate::prelude::*; + +cfg_if! { + if #[cfg(target_os = "solaris")] { + use crate::unix::solarish::solaris; + } +} + +pub type greg_t = c_long; + +pub type Elf64_Addr = c_ulong; +pub type Elf64_Half = c_ushort; +pub type Elf64_Off = c_ulong; +pub type Elf64_Sword = c_int; +pub type Elf64_Sxword = c_long; +pub type Elf64_Word = c_uint; +pub type Elf64_Xword = c_ulong; +pub type Elf64_Lword = c_ulong; +pub type Elf64_Phdr = __c_anonymous_Elf64_Phdr; + +s! { + pub struct __c_anonymous_fpchip_state { + pub cw: u16, + pub sw: u16, + pub fctw: u8, + pub __fx_rsvd: u8, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st: [crate::upad128_t; 8], + pub xmm: [crate::upad128_t; 16], + pub __fx_ign: [crate::upad128_t; 6], + pub status: u32, + pub xstatus: u32, + } + + pub struct __c_anonymous_Elf64_Phdr { + pub p_type: crate::Elf64_Word, + pub p_flags: crate::Elf64_Word, + pub p_offset: crate::Elf64_Off, + pub p_vaddr: crate::Elf64_Addr, + pub p_paddr: crate::Elf64_Addr, + pub p_filesz: crate::Elf64_Xword, + pub p_memsz: crate::Elf64_Xword, + pub p_align: crate::Elf64_Xword, + } + + pub struct dl_phdr_info { + pub dlpi_addr: crate::Elf64_Addr, + pub dlpi_name: *const c_char, + pub dlpi_phdr: *const crate::Elf64_Phdr, + pub dlpi_phnum: crate::Elf64_Half, + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + #[cfg(target_os = "solaris")] + pub dlpi_tls_modid: c_ulong, + #[cfg(target_os = "solaris")] + pub dlpi_tls_data: *mut c_void, + } + + pub struct fpregset_t { + pub fp_reg_set: __c_anonymous_fp_reg_set, + } + + pub struct mcontext_t { + pub gregs: [crate::greg_t; 28], + pub fpregs: fpregset_t, + } + + pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_sigmask: crate::sigset_t, + pub uc_stack: crate::stack_t, + pub uc_mcontext: mcontext_t, + #[cfg(target_os = "illumos")] + pub uc_brand_data: [*mut c_void; 3], + #[cfg(target_os = "illumos")] + pub uc_xsave: c_long, + #[cfg(target_os = "illumos")] + pub uc_filler: c_long, + #[cfg(target_os = "solaris")] + pub uc_xrs: solaris::xrs_t, + #[cfg(target_os = "solaris")] + pub uc_lwpid: c_uint, + #[cfg(target_os = "solaris")] + pub uc_filler: [c_long; 2], + } +} + +s_no_extra_traits! { + pub union __c_anonymous_fp_reg_set { + pub fpchip_state: __c_anonymous_fpchip_state, + pub f_fpregs: [[u32; 13]; 10], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for __c_anonymous_fp_reg_set { + fn eq(&self, other: &__c_anonymous_fp_reg_set) -> bool { + unsafe { + self.fpchip_state == other.fpchip_state + || self + .f_fpregs + .iter() + .zip(other.f_fpregs.iter()) + .all(|(a, b)| a == b) + } + } + } + impl Eq for __c_anonymous_fp_reg_set {} + impl hash::Hash for __c_anonymous_fp_reg_set { + fn hash(&self, state: &mut H) { + unsafe { + self.f_fpregs.hash(state); + } + } + } + } +} + +// sys/regset.h + +pub const REG_GSBASE: c_int = 27; +pub const REG_FSBASE: c_int = 26; +pub const REG_DS: c_int = 25; +pub const REG_ES: c_int = 24; +pub const REG_GS: c_int = 23; +pub const REG_FS: c_int = 22; +pub const REG_SS: c_int = 21; +pub const REG_RSP: c_int = 20; +pub const REG_RFL: c_int = 19; +pub const REG_CS: c_int = 18; +pub const REG_RIP: c_int = 17; +pub const REG_ERR: c_int = 16; +pub const REG_TRAPNO: c_int = 15; +pub const REG_RAX: c_int = 14; +pub const REG_RCX: c_int = 13; +pub const REG_RDX: c_int = 12; +pub const REG_RBX: c_int = 11; +pub const REG_RBP: c_int = 10; +pub const REG_RSI: c_int = 9; +pub const REG_RDI: c_int = 8; +pub const REG_R8: c_int = 7; +pub const REG_R9: c_int = 6; +pub const REG_R10: c_int = 5; +pub const REG_R11: c_int = 4; +pub const REG_R12: c_int = 3; +pub const REG_R13: c_int = 2; +pub const REG_R14: c_int = 1; +pub const REG_R15: c_int = 0; diff --git a/deps/crates/vendor/libc/src/unix/solarish/x86_common.rs b/deps/crates/vendor/libc/src/unix/solarish/x86_common.rs new file mode 100644 index 00000000000000..e72a22a83b4178 --- /dev/null +++ b/deps/crates/vendor/libc/src/unix/solarish/x86_common.rs @@ -0,0 +1,69 @@ +// AT_SUN_HWCAP +pub const AV_386_FPU: u32 = 0x00001; +pub const AV_386_TSC: u32 = 0x00002; +pub const AV_386_CX8: u32 = 0x00004; +pub const AV_386_SEP: u32 = 0x00008; +pub const AV_386_AMD_SYSC: u32 = 0x00010; +pub const AV_386_CMOV: u32 = 0x00020; +pub const AV_386_MMX: u32 = 0x00040; +pub const AV_386_AMD_MMX: u32 = 0x00080; +pub const AV_386_AMD_3DNow: u32 = 0x00100; +pub const AV_386_AMD_3DNowx: u32 = 0x00200; +pub const AV_386_FXSR: u32 = 0x00400; +pub const AV_386_SSE: u32 = 0x00800; +pub const AV_386_SSE2: u32 = 0x01000; +pub const AV_386_CX16: u32 = 0x10000; +pub const AV_386_AHF: u32 = 0x20000; +pub const AV_386_TSCP: u32 = 0x40000; +pub const AV_386_AMD_SSE4A: u32 = 0x80000; +pub const AV_386_POPCNT: u32 = 0x100000; +pub const AV_386_AMD_LZCNT: u32 = 0x200000; +pub const AV_386_SSSE3: u32 = 0x400000; +pub const AV_386_SSE4_1: u32 = 0x800000; +pub const AV_386_SSE4_2: u32 = 0x1000000; +pub const AV_386_MOVBE: u32 = 0x2000000; +pub const AV_386_AES: u32 = 0x4000000; +pub const AV_386_PCLMULQDQ: u32 = 0x8000000; +pub const AV_386_XSAVE: u32 = 0x10000000; +pub const AV_386_AVX: u32 = 0x20000000; +cfg_if! { + if #[cfg(target_os = "illumos")] { + pub const AV_386_VMX: u32 = 0x40000000; + pub const AV_386_AMD_SVM: u32 = 0x80000000; + // AT_SUN_HWCAP2 + pub const AV_386_2_F16C: u32 = 0x00000001; + pub const AV_386_2_RDRAND: u32 = 0x00000002; + pub const AV_386_2_BMI1: u32 = 0x00000004; + pub const AV_386_2_BMI2: u32 = 0x00000008; + pub const AV_386_2_FMA: u32 = 0x00000010; + pub const AV_386_2_AVX2: u32 = 0x00000020; + pub const AV_386_2_ADX: u32 = 0x00000040; + pub const AV_386_2_RDSEED: u32 = 0x00000080; + pub const AV_386_2_AVX512F: u32 = 0x00000100; + pub const AV_386_2_AVX512DQ: u32 = 0x00000200; + pub const AV_386_2_AVX512IFMA: u32 = 0x00000400; + pub const AV_386_2_AVX512PF: u32 = 0x00000800; + pub const AV_386_2_AVX512ER: u32 = 0x00001000; + pub const AV_386_2_AVX512CD: u32 = 0x00002000; + pub const AV_386_2_AVX512BW: u32 = 0x00004000; + pub const AV_386_2_AVX512VL: u32 = 0x00008000; + pub const AV_386_2_AVX512VBMI: u32 = 0x00010000; + pub const AV_386_2_AVX512VPOPCDQ: u32 = 0x00020000; + pub const AV_386_2_AVX512_4NNIW: u32 = 0x00040000; + pub const AV_386_2_AVX512_4FMAPS: u32 = 0x00080000; + pub const AV_386_2_SHA: u32 = 0x00100000; + pub const AV_386_2_FSGSBASE: u32 = 0x00200000; + pub const AV_386_2_CLFLUSHOPT: u32 = 0x00400000; + pub const AV_386_2_CLWB: u32 = 0x00800000; + pub const AV_386_2_MONITORX: u32 = 0x01000000; + pub const AV_386_2_CLZERO: u32 = 0x02000000; + pub const AV_386_2_AVX512_VNNI: u32 = 0x04000000; + pub const AV_386_2_VPCLMULQDQ: u32 = 0x08000000; + pub const AV_386_2_VAES: u32 = 0x10000000; + // AT_SUN_FPTYPE + pub const AT_386_FPINFO_NONE: u32 = 0; + pub const AT_386_FPINFO_FXSAVE: u32 = 1; + pub const AT_386_FPINFO_XSAVE: u32 = 2; + pub const AT_386_FPINFO_XSAVE_AMD: u32 = 3; + } +} diff --git a/deps/crates/vendor/libc/src/vxworks/aarch64.rs b/deps/crates/vendor/libc/src/vxworks/aarch64.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/aarch64.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/vxworks/arm.rs b/deps/crates/vendor/libc/src/vxworks/arm.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/arm.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/vxworks/mod.rs b/deps/crates/vendor/libc/src/vxworks/mod.rs new file mode 100644 index 00000000000000..bc4d536896473f --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/mod.rs @@ -0,0 +1,2477 @@ +//! Interface to VxWorks C library + +use core::ptr::null_mut; + +use crate::prelude::*; + +extern_ty! { + pub enum DIR {} +} + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type uintptr_t = usize; +pub type intptr_t = isize; +pub type ptrdiff_t = isize; +pub type size_t = crate::uintptr_t; +pub type ssize_t = intptr_t; +pub type speed_t = c_uint; +pub type tcflag_t = c_uint; +pub type clock_t = c_long; +pub type cc_t = c_uchar; + +pub type pid_t = c_int; +pub type in_addr_t = u32; +pub type sighandler_t = size_t; +pub type cpuset_t = u32; + +pub type blkcnt_t = c_long; +pub type blksize_t = c_long; +pub type ino_t = c_ulong; + +pub type rlim_t = c_ulong; +pub type suseconds_t = c_long; +pub type time_t = c_longlong; + +pub type errno_t = c_int; + +pub type useconds_t = c_ulong; + +pub type socklen_t = c_uint; + +pub type pthread_t = c_ulong; + +pub type clockid_t = c_int; + +//defined for the structs +pub type dev_t = c_ulong; +pub type mode_t = c_int; +pub type nlink_t = c_ulong; +pub type uid_t = c_ushort; +pub type gid_t = c_ushort; +pub type sigset_t = c_ulonglong; +pub type key_t = c_long; + +pub type nfds_t = c_uint; +pub type stat64 = crate::stat; + +pub type pthread_key_t = c_ulong; + +// From b_off_t.h +pub type off_t = c_longlong; +pub type off64_t = off_t; + +// From b_BOOL.h +pub type BOOL = c_int; + +// From vxWind.h .. +pub type _Vx_OBJ_HANDLE = c_int; +pub type _Vx_TASK_ID = crate::_Vx_OBJ_HANDLE; +pub type _Vx_MSG_Q_ID = crate::_Vx_OBJ_HANDLE; +pub type _Vx_SEM_ID_KERNEL = crate::_Vx_OBJ_HANDLE; +pub type _Vx_RTP_ID = crate::_Vx_OBJ_HANDLE; +pub type _Vx_SD_ID = crate::_Vx_OBJ_HANDLE; +pub type _Vx_CONDVAR_ID = crate::_Vx_OBJ_HANDLE; +pub type _Vx_SEM_ID = *mut crate::_Vx_semaphore; +pub type OBJ_HANDLE = crate::_Vx_OBJ_HANDLE; +pub type TASK_ID = crate::OBJ_HANDLE; +pub type MSG_Q_ID = crate::OBJ_HANDLE; +pub type SEM_ID_KERNEL = crate::OBJ_HANDLE; +pub type RTP_ID = crate::OBJ_HANDLE; +pub type SD_ID = crate::OBJ_HANDLE; +pub type CONDVAR_ID = crate::OBJ_HANDLE; +pub type STATUS = crate::OBJ_HANDLE; + +// From vxTypes.h +pub type _Vx_usr_arg_t = isize; +pub type _Vx_exit_code_t = isize; +pub type _Vx_ticks_t = c_uint; +pub type _Vx_ticks64_t = c_ulonglong; + +pub type sa_family_t = c_uchar; + +// mqueue.h +pub type mqd_t = c_int; + +extern_ty! { + pub enum _Vx_semaphore {} +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut c_void { + self.si_addr + } + + pub unsafe fn si_value(&self) -> crate::sigval { + self.si_value + } + + pub unsafe fn si_pid(&self) -> crate::pid_t { + self.si_pid + } + + pub unsafe fn si_uid(&self) -> crate::uid_t { + self.si_uid + } + + pub unsafe fn si_status(&self) -> c_int { + self.si_status + } +} + +s! { + // b_pthread_condattr_t.h + pub struct pthread_condattr_t { + pub condAttrStatus: c_int, + pub condAttrPshared: c_int, + pub condAttrClockId: crate::clockid_t, + } + + // b_pthread_cond_t.h + pub struct pthread_cond_t { + pub condSemId: crate::_Vx_SEM_ID, + pub condValid: c_int, + pub condInitted: c_int, + pub condRefCount: c_int, + pub condMutex: *mut crate::pthread_mutex_t, + pub condAttr: crate::pthread_condattr_t, + pub condSemName: [c_char; _PTHREAD_SHARED_SEM_NAME_MAX], + } + + // b_pthread_rwlockattr_t.h + pub struct pthread_rwlockattr_t { + pub rwlockAttrStatus: c_int, + pub rwlockAttrPshared: c_int, + pub rwlockAttrMaxReaders: c_uint, + pub rwlockAttrConformOpt: c_uint, + } + + // b_pthread_rwlock_t.h + pub struct pthread_rwlock_t { + pub rwlockSemId: crate::_Vx_SEM_ID, + pub rwlockReadersRefCount: c_uint, + pub rwlockValid: c_int, + pub rwlockInitted: c_int, + pub rwlockAttr: crate::pthread_rwlockattr_t, + pub rwlockSemName: [c_char; _PTHREAD_SHARED_SEM_NAME_MAX], + } + + // b_struct_timeval.h + #[derive(Default)] + pub struct timeval { + pub tv_sec: crate::time_t, + pub tv_usec: crate::suseconds_t, + } + + // socket.h + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + pub struct sockaddr { + pub sa_len: c_uchar, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, + } + + pub struct cmsghdr { + pub cmsg_len: socklen_t, + pub cmsg_level: c_int, + pub cmsg_type: c_int, + } + + // poll.h + pub struct pollfd { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + } + + // resource.h + pub struct rlimit { + pub rlim_cur: crate::rlim_t, + pub rlim_max: crate::rlim_t, + } + + // stat.h + pub struct stat { + pub st_dev: crate::dev_t, + pub st_ino: crate::ino_t, + pub st_mode: mode_t, + pub st_nlink: crate::nlink_t, + pub st_uid: crate::uid_t, + pub st_gid: crate::gid_t, + pub st_rdev: crate::dev_t, + pub st_size: off_t, + #[cfg(not(vxworks_lt_25_09))] + pub st_atim: timespec, + #[cfg(vxworks_lt_25_09)] + pub st_atime: crate::time_t, + #[cfg(not(vxworks_lt_25_09))] + pub st_mtim: timespec, + #[cfg(vxworks_lt_25_09)] + pub st_mtime: crate::time_t, + #[cfg(not(vxworks_lt_25_09))] + pub st_ctim: timespec, + #[cfg(vxworks_lt_25_09)] + pub st_ctime: crate::time_t, + pub st_blksize: crate::blksize_t, + pub st_blocks: crate::blkcnt_t, + pub st_attrib: c_uchar, + st_reserved1: Padding, + st_reserved2: Padding, + st_reserved3: Padding, + st_reserved4: Padding, + } + + pub struct fsid_t { + val: [c_long; 2], + } + + pub struct statfs { + pub f_type: c_long, + pub f_bsize: c_long, + pub f_blocks: c_long, + pub f_bfree: c_long, + pub f_bavail: c_long, + pub f_files: c_long, + pub f_ffree: c_long, + pub f_fsid: crate::fsid_t, + f_spare: Padding<[c_long; 7]>, + } + + //b_struct__Timespec.h + pub struct _Timespec { + pub tv_sec: crate::time_t, + pub tv_nsec: c_long, + } + + // b_struct__Sched_param.h + pub struct sched_param { + pub sched_priority: c_int, /* scheduling priority */ + pub sched_ss_low_priority: c_int, /* low scheduling priority */ + pub sched_ss_repl_period: crate::timespec, /* replenishment period */ + pub sched_ss_init_budget: crate::timespec, /* initial budget */ + pub sched_ss_max_repl: c_int, /* max pending replenishment */ + } + + // b_struct__Sched_param.h + pub struct _Sched_param { + pub sched_priority: c_int, /* scheduling priority */ + pub sched_ss_low_priority: c_int, /* low scheduling priority */ + pub sched_ss_repl_period: crate::_Timespec, /* replenishment period */ + pub sched_ss_init_budget: crate::_Timespec, /* initial budget */ + pub sched_ss_max_repl: c_int, /* max pending replenishment */ + } + + // b_pthread_attr_t.h + pub struct pthread_attr_t { + pub threadAttrStatus: c_int, + pub threadAttrStacksize: size_t, + pub threadAttrStackaddr: *mut c_void, + pub threadAttrGuardsize: size_t, + pub threadAttrDetachstate: c_int, + pub threadAttrContentionscope: c_int, + pub threadAttrInheritsched: c_int, + pub threadAttrSchedpolicy: c_int, + pub threadAttrName: *mut c_char, + pub threadAttrOptions: c_int, + pub threadAttrSchedparam: crate::_Sched_param, + } + + // signal.h + + pub struct sigaction { + #[cfg(vxworks_lt_25_09)] + pub sa_u: crate::sa_u_t, + #[cfg(not(vxworks_lt_25_09))] + pub sa_sigaction: crate::sighandler_t, + pub sa_mask: crate::sigset_t, + pub sa_flags: c_int, + } + + // b_stack_t.h + pub struct stack_t { + pub ss_sp: *mut c_void, + pub ss_size: size_t, + pub ss_flags: c_int, + } + + // signal.h + pub struct siginfo_t { + pub si_signo: c_int, + pub si_code: c_int, + pub si_value: crate::sigval, + pub si_errno: c_int, + pub si_status: c_int, + pub si_addr: *mut c_void, + pub si_uid: crate::uid_t, + pub si_pid: crate::pid_t, + } + + // pthread.h (krnl) + // b_pthread_mutexattr_t.h (usr) + pub struct pthread_mutexattr_t { + mutexAttrStatus: c_int, + mutexAttrPshared: c_int, + mutexAttrProtocol: c_int, + mutexAttrPrioceiling: c_int, + mutexAttrType: c_int, + } + + // pthread.h (krnl) + // b_pthread_mutex_t.h (usr) + pub struct pthread_mutex_t { + pub mutexSemId: crate::_Vx_SEM_ID, /*_Vx_SEM_ID ..*/ + pub mutexValid: c_int, + pub mutexInitted: c_int, + pub mutexCondRefCount: c_int, + pub mutexSavPriority: c_int, + pub mutexAttr: crate::pthread_mutexattr_t, + pub mutexSemName: [c_char; _PTHREAD_SHARED_SEM_NAME_MAX], + } + + // b_struct_timespec.h + #[derive(Default)] + pub struct timespec { + pub tv_sec: crate::time_t, + pub tv_nsec: c_long, + } + + // time.h + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + // sys/times.h + pub struct tms { + pub tms_utime: crate::clock_t, + pub tms_stime: crate::clock_t, + pub tms_cutime: crate::clock_t, + pub tms_cstime: crate::clock_t, + } + + // utime.h + pub struct utimbuf { + pub actime: time_t, + pub modtime: time_t, + } + + // in.h + pub struct in_addr { + pub s_addr: in_addr_t, + } + + // in.h + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + // in6.h + #[repr(align(4))] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + // in6.h + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + // netdb.h + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: size_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut crate::sockaddr, + pub ai_next: *mut crate::addrinfo, + } + + // netdb.h + pub struct servent { + pub s_name: *mut c_char, + pub s_aliases: *mut *mut c_char, + pub s_port: c_int, + pub s_proto: *mut c_char, + } + + // netdb.h + pub struct protoent { + pub p_name: *mut c_char, + pub p_aliases: *mut *mut c_char, + pub p_proto: c_int, + } + + // netdb.h + pub struct hostent { + pub h_name: *mut c_char, + pub h_aliases: *mut *mut c_char, + pub h_addrtype: c_int, + pub h_length: c_int, + pub h_addr_list: *mut *mut c_char, + } + + // in.h + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: u8, + pub sin_port: u16, + pub sin_addr: crate::in_addr, + pub sin_zero: [c_char; 8], + } + + // in6.h + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: u8, + pub sin6_port: u16, + pub sin6_flowinfo: u32, + pub sin6_addr: crate::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct Dl_info { + pub dli_fname: *const c_char, + pub dli_fbase: *mut c_void, + pub dli_sname: *const c_char, + pub dli_saddr: *mut c_void, + } + + pub struct mq_attr { + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_flags: c_long, + pub mq_curmsgs: c_long, + } + + pub struct flock { + pub l_type: c_short, + pub l_whence: c_short, + pub l_start: c_longlong, + pub l_len: c_longlong, + pub l_pid: c_long, + } + + pub struct winsize { + pub ws_row: c_ushort, + pub ws_col: c_ushort, + pub ws_xpixel: c_ushort, + pub ws_ypixel: c_ushort, + } + + pub struct termios { + pub c_iflag: crate::tcflag_t, + pub c_oflag: crate::tcflag_t, + pub c_cflag: crate::tcflag_t, + pub c_lflag: crate::tcflag_t, + pub c_cc: [crate::cc_t; crate::NCCS], + pub c_ispeed: crate::speed_t, + pub c_ospeed: crate::speed_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + pub ru_ixrss: c_long, + pub ru_idrss: c_long, + pub ru_isrss: c_long, + pub ru_minflt: c_long, + pub ru_majflt: c_long, + pub ru_nswap: c_long, + pub ru_inblock: c_long, + pub ru_oublock: c_long, + pub ru_msgsnd: c_long, + pub ru_msgrcv: c_long, + pub ru_nsignals: c_long, + pub ru_nvcsw: c_long, + pub ru_nivcsw: c_long, + } + + pub struct lconv { + pub currency_symbol: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_grouping: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub negative_sign: *mut c_char, + pub positive_sign: *mut c_char, + pub frac_digits: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub n_sign_posn: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub int_frac_digits: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub decimal_point: *mut c_char, + pub grouping: *mut c_char, + pub thousands_sep: *mut c_char, + pub _Frac_grouping: *mut c_char, + pub _Frac_sep: *mut c_char, + pub _False: *mut c_char, + pub _True: *mut c_char, + + pub _No: *mut c_char, + pub _Yes: *mut c_char, + } + + // grp.h + pub struct group { + pub gr_name: *mut c_char, + pub gr_passwd: *mut c_char, + pub gr_gid: c_int, + pub gr_mem: *mut *mut c_char, + } + + pub struct utsname { + pub sysname: [c_char; 80], + pub nodename: [c_char; 256], + pub release: [c_char; 80], + pub version: [c_char; 256], + pub machine: [c_char; 256], + pub endian: [c_char; 80], + pub kernelversion: [c_char; 80], + pub releaseversion: [c_char; 80], + pub processor: [c_char; 80], + pub bsprevision: [c_char; 80], + pub builddate: [c_char; 80], + } +} + +s_no_extra_traits! { + // dirent.h + pub struct dirent { + pub d_ino: crate::ino_t, + pub d_name: [c_char; _PARM_NAME_MAX as usize + 1], + pub d_type: c_uchar, + } + + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 104], + } + + // rtpLibCommon.h + pub struct RTP_DESC { + pub status: c_int, + pub options: u32, + pub entrAddr: *mut c_void, + pub initTaskId: crate::TASK_ID, + pub parentId: crate::RTP_ID, + pub pathName: [c_char; VX_RTP_NAME_LENGTH as usize + 1], + pub taskCnt: c_int, + pub textStart: *mut c_void, + pub textEnd: *mut c_void, + } + // socket.h + pub struct sockaddr_storage { + pub ss_len: c_uchar, + pub ss_family: crate::sa_family_t, + __ss_pad1: Padding<[c_char; _SS_PAD1SIZE]>, + __ss_align: i32, + __ss_pad2: Padding<[c_char; _SS_PAD2SIZE]>, + } + + pub union sa_u_t { + pub sa_handler: Option !>, + pub sa_sigaction: + Option !>, + } + + pub union sigval { + pub sival_int: c_int, + pub sival_ptr: *mut c_void, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sa_u_t { + fn eq(&self, other: &sa_u_t) -> bool { + unsafe { + let h1 = match self.sa_handler { + Some(handler) => handler as usize, + None => 0 as usize, + }; + let h2 = match other.sa_handler { + Some(handler) => handler as usize, + None => 0 as usize, + }; + h1 == h2 + } + } + } + impl Eq for sa_u_t {} + impl hash::Hash for sa_u_t { + fn hash(&self, state: &mut H) { + unsafe { + let h = match self.sa_handler { + Some(handler) => handler as usize, + None => 0 as usize, + }; + h.hash(state) + } + } + } + + impl PartialEq for sigval { + fn eq(&self, other: &sigval) -> bool { + unsafe { self.sival_ptr as usize == other.sival_ptr as usize } + } + } + impl Eq for sigval {} + impl hash::Hash for sigval { + fn hash(&self, state: &mut H) { + unsafe { (self.sival_ptr as usize).hash(state) }; + } + } + } +} + +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; + +pub const EAI_SERVICE: c_int = 9; +pub const EAI_SOCKTYPE: c_int = 10; +pub const EAI_SYSTEM: c_int = 11; + +pub const INT_MAX: c_int = 0x7fffffff; +pub const INT_MIN: c_int = -INT_MAX - 1; + +// FIXME(vxworks): This is not defined in vxWorks, but we have to define it here +// to make the building pass for getrandom and std +pub const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); + +//Clock Lib Stuff +pub const CLOCK_REALTIME: c_int = 0x0; +pub const CLOCK_MONOTONIC: c_int = 0x1; +pub const CLOCK_PROCESS_CPUTIME_ID: c_int = 0x2; +pub const CLOCK_THREAD_CPUTIME_ID: c_int = 0x3; +pub const TIMER_ABSTIME: c_int = 0x1; +pub const TIMER_RELTIME: c_int = 0x0; + +// PTHREAD STUFF +pub const PTHREAD_INITIALIZED_OBJ: c_int = 0xF70990EF; +pub const PTHREAD_DESTROYED_OBJ: c_int = -1; +pub const PTHREAD_VALID_OBJ: c_int = 0xEC542A37; +pub const PTHREAD_INVALID_OBJ: c_int = -1; +pub const PTHREAD_UNUSED_YET_OBJ: c_int = -1; + +pub const PTHREAD_PRIO_NONE: c_int = 0; +pub const PTHREAD_PRIO_INHERIT: c_int = 1; +pub const PTHREAD_PRIO_PROTECT: c_int = 2; + +pub const PTHREAD_MUTEX_NORMAL: c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_STACK_MIN: usize = 4096; +pub const _PTHREAD_SHARED_SEM_NAME_MAX: usize = 30; + +//sched.h +pub const SCHED_FIFO: c_int = 0x01; +pub const SCHED_RR: c_int = 0x02; +pub const SCHED_OTHER: c_int = 0x04; +pub const SCHED_SPORADIC: c_int = 0x08; +pub const PRIO_PROCESS: c_uint = 0; +pub const SCHED_FIFO_HIGH_PRI: c_int = 255; +pub const SCHED_FIFO_LOW_PRI: c_int = 0; +pub const SCHED_RR_HIGH_PRI: c_int = 255; +pub const SCHED_RR_LOW_PRI: c_int = 0; +pub const SCHED_SPORADIC_HIGH_PRI: c_int = 255; +pub const SCHED_SPORADIC_LOW_PRI: c_int = 0; + +// ERRNO STUFF +pub const ERROR: c_int = -1; +pub const OK: c_int = 0; +pub const EPERM: c_int = 1; /* Not owner */ +pub const ENOENT: c_int = 2; /* No such file or directory */ +pub const ESRCH: c_int = 3; /* No such process */ +pub const EINTR: c_int = 4; /* Interrupted system call */ +pub const EIO: c_int = 5; /* I/O error */ +pub const ENXIO: c_int = 6; /* No such device or address */ +pub const E2BIG: c_int = 7; /* Arg list too long */ +pub const ENOEXEC: c_int = 8; /* Exec format error */ +pub const EBADF: c_int = 9; /* Bad file number */ +pub const ECHILD: c_int = 10; /* No children */ +pub const EAGAIN: c_int = 11; /* No more processes */ +pub const ENOMEM: c_int = 12; /* Not enough core */ +pub const EACCES: c_int = 13; /* Permission denied */ +pub const EFAULT: c_int = 14; +pub const ENOTEMPTY: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ENAMETOOLONG: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDEADLK: c_int = 33; +pub const ENOLCK: c_int = 34; +pub const ENOTSUP: c_int = 35; +pub const EMSGSIZE: c_int = 36; +pub const EDOM: c_int = 37; +pub const ERANGE: c_int = 38; +pub const EDOOM: c_int = 39; +pub const EDESTADDRREQ: c_int = 40; +pub const EPROTOTYPE: c_int = 41; +pub const ENOPROTOOPT: c_int = 42; +pub const EPROTONOSUPPORT: c_int = 43; +pub const ESOCKTNOSUPPORT: c_int = 44; +pub const EOPNOTSUPP: c_int = 45; +pub const EPFNOSUPPORT: c_int = 46; +pub const EAFNOSUPPORT: c_int = 47; +pub const EADDRINUSE: c_int = 48; +pub const EADDRNOTAVAIL: c_int = 49; +pub const ENOTSOCK: c_int = 50; +pub const ENETUNREACH: c_int = 51; +pub const ENETRESET: c_int = 52; +pub const ECONNABORTED: c_int = 53; +pub const ECONNRESET: c_int = 54; +pub const ENOBUFS: c_int = 55; +pub const EISCONN: c_int = 56; +pub const ENOTCONN: c_int = 57; +pub const ESHUTDOWN: c_int = 58; +pub const ETOOMANYREFS: c_int = 59; +pub const ETIMEDOUT: c_int = 60; +pub const ECONNREFUSED: c_int = 61; +pub const ENETDOWN: c_int = 62; +pub const ETXTBSY: c_int = 63; +pub const ELOOP: c_int = 64; +pub const EHOSTUNREACH: c_int = 65; +pub const ENOTBLK: c_int = 66; +pub const EHOSTDOWN: c_int = 67; +pub const EINPROGRESS: c_int = 68; +pub const EALREADY: c_int = 69; +pub const EWOULDBLOCK: c_int = 70; +pub const ENOSYS: c_int = 71; +pub const ECANCELED: c_int = 72; +pub const ENOSR: c_int = 74; +pub const ENOSTR: c_int = 75; +pub const EPROTO: c_int = 76; +pub const EBADMSG: c_int = 77; +pub const ENODATA: c_int = 78; +pub const ETIME: c_int = 79; +pub const ENOMSG: c_int = 80; +pub const EFPOS: c_int = 81; +pub const EILSEQ: c_int = 82; +pub const EDQUOT: c_int = 83; +pub const EIDRM: c_int = 84; +pub const EOVERFLOW: c_int = 85; +pub const EMULTIHOP: c_int = 86; +pub const ENOLINK: c_int = 87; +pub const ESTALE: c_int = 88; +pub const EOWNERDEAD: c_int = 89; +pub const ENOTRECOVERABLE: c_int = 90; + +// NFS errnos: Refer to pkgs_v2/storage/fs/nfs/h/nfs/nfsCommon.h +const M_nfsStat: c_int = 48 << 16; +enum nfsstat { + NFSERR_REMOTE = 71, + NFSERR_WFLUSH = 99, + NFSERR_BADHANDLE = 10001, + NFSERR_NOT_SYNC = 10002, + NFSERR_BAD_COOKIE = 10003, + NFSERR_TOOSMALL = 10005, + NFSERR_BADTYPE = 10007, + NFSERR_JUKEBOX = 10008, +} + +pub const S_nfsLib_NFS_OK: c_int = OK; +pub const S_nfsLib_NFSERR_PERM: c_int = EPERM; +pub const S_nfsLib_NFSERR_NOENT: c_int = ENOENT; +pub const S_nfsLib_NFSERR_IO: c_int = EIO; +pub const S_nfsLib_NFSERR_NXIO: c_int = ENXIO; +pub const S_nfsLib_NFSERR_ACCESS: c_int = EACCES; +pub const S_nfsLib_NFSERR_EXIST: c_int = EEXIST; +pub const S_nfsLib_NFSERR_ENODEV: c_int = ENODEV; +pub const S_nfsLib_NFSERR_NOTDIR: c_int = ENOTDIR; +pub const S_nfsLib_NFSERR_ISDIR: c_int = EISDIR; +pub const S_nfsLib_NFSERR_INVAL: c_int = EINVAL; +pub const S_nfsLib_NFSERR_FBIG: c_int = EFBIG; +pub const S_nfsLib_NFSERR_NOSPC: c_int = ENOSPC; +pub const S_nfsLib_NFSERR_ROFS: c_int = EROFS; +pub const S_nfsLib_NFSERR_NAMETOOLONG: c_int = ENAMETOOLONG; +pub const S_nfsLib_NFSERR_NOTEMPTY: c_int = ENOTEMPTY; +pub const S_nfsLib_NFSERR_DQUOT: c_int = EDQUOT; +pub const S_nfsLib_NFSERR_STALE: c_int = ESTALE; +pub const S_nfsLib_NFSERR_WFLUSH: c_int = M_nfsStat | nfsstat::NFSERR_WFLUSH as c_int; +pub const S_nfsLib_NFSERR_REMOTE: c_int = M_nfsStat | nfsstat::NFSERR_REMOTE as c_int; +pub const S_nfsLib_NFSERR_BADHANDLE: c_int = M_nfsStat | nfsstat::NFSERR_BADHANDLE as c_int; +pub const S_nfsLib_NFSERR_NOT_SYNC: c_int = M_nfsStat | nfsstat::NFSERR_NOT_SYNC as c_int; +pub const S_nfsLib_NFSERR_BAD_COOKIE: c_int = M_nfsStat | nfsstat::NFSERR_BAD_COOKIE as c_int; +pub const S_nfsLib_NFSERR_NOTSUPP: c_int = EOPNOTSUPP; +pub const S_nfsLib_NFSERR_TOOSMALL: c_int = M_nfsStat | nfsstat::NFSERR_TOOSMALL as c_int; +pub const S_nfsLib_NFSERR_SERVERFAULT: c_int = EIO; +pub const S_nfsLib_NFSERR_BADTYPE: c_int = M_nfsStat | nfsstat::NFSERR_BADTYPE as c_int; +pub const S_nfsLib_NFSERR_JUKEBOX: c_int = M_nfsStat | nfsstat::NFSERR_JUKEBOX as c_int; + +// internal offset values for below constants +const taskErrorBase: c_int = 0x00030000; +const semErrorBase: c_int = 0x00160000; +const objErrorBase: c_int = 0x003d0000; + +// taskLibCommon.h +pub const S_taskLib_NAME_NOT_FOUND: c_int = taskErrorBase + 0x0065; +pub const S_taskLib_TASK_HOOK_TABLE_FULL: c_int = taskErrorBase + 0x0066; +pub const S_taskLib_TASK_HOOK_NOT_FOUND: c_int = taskErrorBase + 0x0067; +pub const S_taskLib_ILLEGAL_PRIORITY: c_int = taskErrorBase + 0x006D; + +// FIXME(vxworks): could also be useful for TASK_DESC type +pub const VX_TASK_NAME_LENGTH: c_int = 31; +pub const VX_TASK_RENAME_LENGTH: c_int = 16; + +pub const TCIFLUSH: c_int = 0; + +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; + +// semLibCommon.h +pub const S_semLib_INVALID_STATE: c_int = semErrorBase + 0x0065; +pub const S_semLib_INVALID_OPTION: c_int = semErrorBase + 0x0066; +pub const S_semLib_INVALID_QUEUE_TYPE: c_int = semErrorBase + 0x0067; +pub const S_semLib_INVALID_OPERATION: c_int = semErrorBase + 0x0068; + +// objLibCommon.h +pub const S_objLib_OBJ_ID_ERROR: c_int = objErrorBase + 0x0001; +pub const S_objLib_OBJ_UNAVAILABLE: c_int = objErrorBase + 0x0002; +pub const S_objLib_OBJ_DELETED: c_int = objErrorBase + 0x0003; +pub const S_objLib_OBJ_TIMEOUT: c_int = objErrorBase + 0x0004; +pub const S_objLib_OBJ_NO_METHOD: c_int = objErrorBase + 0x0005; + +// netinet/in.h +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_ICMP: c_int = 1; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_IPV6: c_int = 41; +pub const IPPROTO_ICMPV6: c_int = 58; + +pub const INADDR_ANY: in_addr_t = 0; +pub const INADDR_LOOPBACK: in_addr_t = 2130706433; +pub const INADDR_BROADCAST: in_addr_t = 4294967295; +pub const INADDR_NONE: in_addr_t = 4294967295; + +// netinet6/in6.h +pub const IN6ADDR_LOOPBACK_INIT: in6_addr = in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], +}; +pub const IN6ADDR_ANY_INIT: in6_addr = in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +}; + +// udp.h +pub const IPPROTO_UDP: c_int = 17; + +pub const IP_TTL: c_int = 4; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; + +// netdb.h +pub const NI_MAXHOST: c_int = 1025; + +// in6.h +pub const IPV6_V6ONLY: c_int = 1; +pub const IPV6_UNICAST_HOPS: c_int = 4; +pub const IPV6_MULTICAST_IF: c_int = 9; +pub const IPV6_MULTICAST_HOPS: c_int = 10; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IPV6_ADD_MEMBERSHIP: c_int = 12; +pub const IPV6_DROP_MEMBERSHIP: c_int = 13; + +// STAT Stuff +pub const S_IFMT: c_int = 0o17_0000; +pub const S_IFIFO: c_int = 0o1_0000; +pub const S_IFCHR: c_int = 0o2_0000; +pub const S_IFDIR: c_int = 0o4_0000; +pub const S_IFBLK: c_int = 0o6_0000; +pub const S_IFREG: c_int = 0o10_0000; +pub const S_IFLNK: c_int = 0o12_0000; +pub const S_IFSHM: c_int = 0o13_0000; +pub const S_IFSOCK: c_int = 0o14_0000; +pub const S_ISUID: c_int = 0o4000; +pub const S_ISGID: c_int = 0o2000; +pub const S_ISTXT: c_int = 0o1000; +pub const S_ISVTX: c_int = 0o1000; +pub const S_IRUSR: c_int = 0o0400; +pub const S_IWUSR: c_int = 0o0200; +pub const S_IXUSR: c_int = 0o0100; +pub const S_IRWXU: c_int = 0o0700; +pub const S_IRGRP: c_int = 0o0040; +pub const S_IWGRP: c_int = 0o0020; +pub const S_IXGRP: c_int = 0o0010; +pub const S_IRWXG: c_int = 0o0070; +pub const S_IROTH: c_int = 0o0004; +pub const S_IWOTH: c_int = 0o0002; +pub const S_IXOTH: c_int = 0o0001; +pub const S_IRWXO: c_int = 0o0007; + +pub const UTIME_OMIT: c_long = 0x3ffffffe; +pub const UTIME_NOW: c_long = 0x3fffffff; + +// socket.h +pub const SOL_SOCKET: c_int = 0xffff; +pub const SOMAXCONN: c_int = 128; + +pub const SO_DEBUG: c_int = 0x0001; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_RCVLOWAT: c_int = 0x0012; +pub const SO_SNDLOWAT: c_int = 0x0013; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_ACCEPTCONN: c_int = 0x001e; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_REUSEPORT: c_int = 0x0200; + +pub const SO_VLAN: c_int = 0x8000; + +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_BINDTODEVICE: c_int = 0x1010; +pub const SO_OOBINLINE: c_int = 0x1011; +pub const SO_CONNTIMEO: c_int = 0x100a; + +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOCK_PACKET: c_int = 10; + +pub const _SS_MAXSIZE: usize = 128; +pub const _SS_ALIGNSIZE: usize = size_of::(); +pub const _SS_PAD1SIZE: usize = + _SS_ALIGNSIZE - size_of::() - size_of::(); +pub const _SS_PAD2SIZE: usize = _SS_MAXSIZE + - size_of::() + - size_of::() + - _SS_PAD1SIZE + - _SS_ALIGNSIZE; + +pub const MSG_OOB: c_int = 0x0001; +pub const MSG_PEEK: c_int = 0x0002; +pub const MSG_DONTROUTE: c_int = 0x0004; +pub const MSG_EOR: c_int = 0x0008; +pub const MSG_TRUNC: c_int = 0x0010; +pub const MSG_CTRUNC: c_int = 0x0020; +pub const MSG_WAITALL: c_int = 0x0040; +pub const MSG_DONTWAIT: c_int = 0x0080; +pub const MSG_EOF: c_int = 0x0100; +pub const MSG_EXP: c_int = 0x0200; +pub const MSG_MBUF: c_int = 0x0400; +pub const MSG_NOTIFICATION: c_int = 0x0800; +pub const MSG_COMPAT: c_int = 0x8000; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_LOCAL: c_int = 1; +pub const PF_LOCAL: c_int = AF_LOCAL; +pub const PF_UNIX: c_int = PF_LOCAL; +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const AF_UNIX: c_int = AF_LOCAL; +pub const AF_INET: c_int = 2; +pub const PF_INET: c_int = AF_INET; +pub const AF_NETLINK: c_int = 16; +pub const AF_ROUTE: c_int = 17; +pub const AF_LINK: c_int = 18; +pub const AF_PACKET: c_int = 19; +pub const pseudo_AF_KEY: c_int = 27; +pub const AF_KEY: c_int = pseudo_AF_KEY; +pub const AF_INET6: c_int = 28; +pub const PF_INET6: c_int = AF_INET6; +pub const AF_SOCKDEV: c_int = 31; +pub const AF_TIPC: c_int = 33; +pub const AF_MIPC: c_int = 34; +pub const AF_MIPC_SAFE: c_int = 35; +pub const AF_MAX: c_int = 39; + +// termios.h +pub const B0: crate::speed_t = 0; +pub const B50: crate::speed_t = 50; +pub const B75: crate::speed_t = 75; +pub const B110: crate::speed_t = 110; +pub const B134: crate::speed_t = 134; +pub const B150: crate::speed_t = 150; +pub const B200: crate::speed_t = 200; +pub const B300: crate::speed_t = 300; +pub const B600: crate::speed_t = 600; +pub const B1200: crate::speed_t = 1200; +pub const B1800: crate::speed_t = 1800; +pub const B2400: crate::speed_t = 2400; +pub const B4800: crate::speed_t = 4800; +pub const B9600: crate::speed_t = 9600; +pub const B19200: crate::speed_t = 19200; +pub const B38400: crate::speed_t = 38400; +pub const B57600: crate::speed_t = 57600; +pub const B115200: crate::speed_t = 115200; +pub const B230400: crate::speed_t = 230400; + +pub const IGNBRK: crate::tcflag_t = 0x00000001; +pub const BRKINT: crate::tcflag_t = 0x00000002; +pub const IGNCR: crate::tcflag_t = 0x00000200; +pub const IGNPAR: crate::tcflag_t = 0x00000000; +pub const INPCK: crate::tcflag_t = 0x00000020; +pub const ISTRIP: crate::tcflag_t = 0x00000040; +pub const INLCR: crate::tcflag_t = 0x00000100; +pub const ISIG: crate::tcflag_t = 0x00000001; +pub const IXOFF: crate::tcflag_t = 0x00010000; +pub const IXON: crate::tcflag_t = 0x00002000; +pub const PARMRK: crate::tcflag_t = 0x00000000; +pub const NOFLSH: crate::tcflag_t = 0x00000000; +pub const NCCS: usize = 20; + +pub const OPOST: crate::tcflag_t = 0x00000001; +pub const ONLCR: crate::tcflag_t = 0x00000004; +pub const ECHO: crate::tcflag_t = 0x00000010; +pub const OCRNL: crate::tcflag_t = 0x00000010; +pub const ECHOE: crate::tcflag_t = 0x00000020; +pub const ECHOK: crate::tcflag_t = 0x00000040; +pub const ECHONL: crate::tcflag_t = 0x00000100; + +// net/if.h +pub const IFNAMSIZ: size_t = 16; +pub const IF_NAMESIZE: size_t = IFNAMSIZ; + +// sioLibCommon.h +pub const CLOCAL: crate::tcflag_t = 0x1; +pub const CREAD: crate::tcflag_t = 0x2; +pub const CS5: crate::tcflag_t = 0x0; +pub const CS6: crate::tcflag_t = 0x4; +pub const CS7: crate::tcflag_t = 0x8; +pub const CS8: crate::tcflag_t = 0xc; +pub const CSTOPB: crate::tcflag_t = 0x20; +pub const CSIZE: crate::tcflag_t = 0xc; + +pub const PARODD: crate::tcflag_t = 0x80; +pub const PARENB: crate::tcflag_t = 0x40; + +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; + +pub const FNM_NOMATCH: c_int = 1; +pub const FNM_NOESCAPE: c_int = 1; +pub const FNM_PATHNAME: c_int = 2; +pub const FNM_PERIOD: c_int = 4; +pub const FNM_CASEFOLD: c_int = 16; + +pub const F_OK: c_int = 0; +pub const X_OK: c_int = 1; +pub const W_OK: c_int = 2; + +pub const _PC_CHOWN_RESTRICTED: c_int = 4; +pub const _PC_LINK_MAX: c_int = 6; +pub const _PC_MAX_CANON: c_int = 7; +pub const _PC_MAX_INPUT: c_int = 8; +pub const _PC_NAME_MAX: c_int = 9; +pub const _PC_NO_TRUNC: c_int = 10; +pub const _PC_PATH_MAX: c_int = 11; +pub const _PC_PIPE_BUF: c_int = 12; +pub const _PC_VDISABLE: c_int = 20; + +pub const HUPCL: crate::tcflag_t = 0x10; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_WR: c_int = 1; +pub const SHUT_RDWR: c_int = 2; + +pub const ICANON: crate::tcflag_t = 0x00000002; +pub const ICRNL: crate::tcflag_t = 0x00000400; +pub const IEXTEN: crate::tcflag_t = 0x00000000; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_MAXSEG: c_int = 2; +pub const TCP_NOPUSH: c_int = 3; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; + +pub const TCSANOW: c_int = 0; +pub const TCSADRAIN: c_int = 1; +pub const TCSAFLUSH: c_int = 2; + +// ioLib.h +pub const FIONREAD: c_int = 0x40040001; +pub const FIOFLUSH: c_int = 2; +pub const FIOOPTIONS: c_int = 3; +pub const FIOBAUDRATE: c_int = 4; +pub const FIODISKFORMAT: c_int = 5; +pub const FIODISKINIT: c_int = 6; +pub const FIOSEEK: c_int = 7; +pub const FIOWHERE: c_int = 8; +pub const FIODIRENTRY: c_int = 9; +pub const FIORENAME: c_int = 10; +pub const FIOREADYCHANGE: c_int = 11; +pub const FIODISKCHANGE: c_int = 13; +pub const FIOCANCEL: c_int = 14; +pub const FIOSQUEEZE: c_int = 15; +pub const FIOGETNAME: c_int = 18; +pub const FIONBIO: c_int = 0x90040010; + +// limits.h +pub const PATH_MAX: c_int = _PARM_PATH_MAX; +pub const _POSIX_PATH_MAX: c_int = 256; + +// Some poll stuff +pub const POLLIN: c_short = 0x0001; +pub const POLLPRI: c_short = 0x0002; +pub const POLLOUT: c_short = 0x0004; +pub const POLLRDNORM: c_short = 0x0040; +pub const POLLWRNORM: c_short = POLLOUT; +pub const POLLRDBAND: c_short = 0x0080; +pub const POLLWRBAND: c_short = 0x0100; +pub const POLLERR: c_short = 0x0008; +pub const POLLHUP: c_short = 0x0010; +pub const POLLNVAL: c_short = 0x0020; + +// fnctlcom.h +pub const FD_CLOEXEC: c_int = 1; +pub const F_DUPFD: c_int = 0; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const F_GETOWN: c_int = 5; +pub const F_SETOWN: c_int = 6; +pub const F_GETLK: c_int = 7; +pub const F_SETLK: c_int = 8; +pub const F_SETLKW: c_int = 9; +pub const F_DUPFD_CLOEXEC: c_int = 14; +pub const F_RDLCK: c_int = 1; +pub const F_WRLCK: c_int = 2; +pub const F_UNLCK: c_int = 3; + +pub const LOG_EMERG: c_int = 0; +pub const LOG_ALERT: c_int = 1; +pub const LOG_CRIT: c_int = 2; +pub const LOG_ERR: c_int = 3; +pub const LOG_WARNING: c_int = 4; +pub const LOG_NOTICE: c_int = 5; +pub const LOG_INFO: c_int = 6; +pub const LOG_DEBUG: c_int = 7; + +pub const LOG_KERN: c_int = 0 << 3; +pub const LOG_USER: c_int = 1 << 3; +pub const LOG_MAIL: c_int = 2 << 3; +pub const LOG_DAEMON: c_int = 3 << 3; +pub const LOG_AUTH: c_int = 4 << 3; +pub const LOG_SYSLOG: c_int = 5 << 3; +pub const LOG_LPR: c_int = 6 << 3; +pub const LOG_NEWS: c_int = 7 << 3; +pub const LOG_UUCP: c_int = 8 << 3; +pub const LOG_LOCAL0: c_int = 16 << 3; +pub const LOG_LOCAL1: c_int = 17 << 3; +pub const LOG_LOCAL2: c_int = 18 << 3; +pub const LOG_LOCAL3: c_int = 19 << 3; +pub const LOG_LOCAL4: c_int = 20 << 3; +pub const LOG_LOCAL5: c_int = 21 << 3; +pub const LOG_LOCAL6: c_int = 22 << 3; +pub const LOG_LOCAL7: c_int = 23 << 3; + +pub const LOG_PID: c_int = 0x01; +pub const LOG_CONS: c_int = 0x02; +pub const LOG_ODELAY: c_int = 0x04; +pub const LOG_NDELAY: c_int = 0x08; +pub const LOG_NOWAIT: c_int = 0x10; + +pub const LOG_PRIMASK: c_int = 0x7; +pub const LOG_FACMASK: c_int = 0x3f8; + +// dlfcn.h +pub const RTLD_LOCAL: c_int = 0; +pub const RTLD_LAZY: c_int = 1; +pub const RTLD_NOW: c_int = 2; +pub const RTLD_GLOBAL: c_int = 256; + +// signal.h +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = -1 as isize as sighandler_t; + +pub const SIGHUP: c_int = 1; +pub const SIGINT: c_int = 2; +pub const SIGQUIT: c_int = 3; +pub const SIGILL: c_int = 4; +pub const SIGTRAP: c_int = 5; +pub const SIGABRT: c_int = 6; +pub const SIGEMT: c_int = 7; +pub const SIGFPE: c_int = 8; +pub const SIGKILL: c_int = 9; +pub const SIGBUS: c_int = 10; +pub const SIGSEGV: c_int = 11; +pub const SIGFMT: c_int = 12; +pub const SIGPIPE: c_int = 13; +pub const SIGALRM: c_int = 14; +pub const SIGTERM: c_int = 15; +pub const SIGCNCL: c_int = 16; +pub const SIGSTOP: c_int = 17; +pub const SIGTSTP: c_int = 18; +pub const SIGCONT: c_int = 19; +pub const SIGCHLD: c_int = 20; +pub const SIGTTIN: c_int = 21; +pub const SIGTTOU: c_int = 22; +pub const SIGUSR1: c_int = 30; +pub const SIGUSR2: c_int = 31; +pub const SIGPOLL: c_int = 32; +pub const SIGPROF: c_int = 33; +pub const SIGSYS: c_int = 34; +pub const SIGURG: c_int = 35; +pub const SIGVTALRM: c_int = 36; +pub const SIGXCPU: c_int = 37; +pub const SIGXFSZ: c_int = 38; +pub const SIGRTMIN: c_int = 48; + +pub const SIGIO: c_int = SIGRTMIN; +pub const SIGWINCH: c_int = SIGRTMIN + 5; +pub const SIGLOST: c_int = SIGRTMIN + 6; + +pub const SIG_BLOCK: c_int = 1; +pub const SIG_UNBLOCK: c_int = 2; +pub const SIG_SETMASK: c_int = 3; + +pub const SA_NOCLDSTOP: c_int = 0x0001; +pub const SA_SIGINFO: c_int = 0x0002; +pub const SA_ONSTACK: c_int = 0x0004; +pub const SA_INTERRUPT: c_int = 0x0008; +pub const SA_RESETHAND: c_int = 0x0010; +pub const SA_RESTART: c_int = 0x0020; +pub const SA_NODEFER: c_int = 0x0040; +pub const SA_NOCLDWAIT: c_int = 0x0080; + +pub const SI_SYNC: c_int = 0; +pub const SI_USER: c_int = -1; +pub const SI_QUEUE: c_int = -2; +pub const SI_TIMER: c_int = -3; +pub const SI_ASYNCIO: c_int = -4; +pub const SI_MESGQ: c_int = -5; +pub const SI_CHILD: c_int = -6; +pub const SI_KILL: c_int = SI_USER; + +pub const AT_FDCWD: c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x100; +pub const AT_REMOVEDIR: c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: c_int = 0x400; + +// vxParams.h definitions +pub const _PARM_NAME_MAX: c_int = 255; +pub const _PARM_PATH_MAX: c_int = 1024; + +// WAIT STUFF +pub const WNOHANG: c_int = 0x01; +pub const WUNTRACED: c_int = 0x02; +pub const WCONTINUED: c_int = 0x04; + +const PTHREAD_MUTEXATTR_INITIALIZER: pthread_mutexattr_t = pthread_mutexattr_t { + mutexAttrStatus: PTHREAD_INITIALIZED_OBJ, + mutexAttrProtocol: PTHREAD_PRIO_NONE, + mutexAttrPrioceiling: 0, + mutexAttrType: PTHREAD_MUTEX_DEFAULT, + mutexAttrPshared: 1, +}; +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + mutexSemId: null_mut(), + mutexValid: PTHREAD_VALID_OBJ, + mutexInitted: PTHREAD_UNUSED_YET_OBJ, + mutexCondRefCount: 0, + mutexSavPriority: -1, + mutexAttr: PTHREAD_MUTEXATTR_INITIALIZER, + mutexSemName: [0; _PTHREAD_SHARED_SEM_NAME_MAX], +}; + +const PTHREAD_CONDATTR_INITIALIZER: pthread_condattr_t = pthread_condattr_t { + condAttrStatus: 0xf70990ef, + condAttrPshared: 1, + condAttrClockId: CLOCK_REALTIME, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + condSemId: null_mut(), + condValid: PTHREAD_VALID_OBJ, + condInitted: PTHREAD_UNUSED_YET_OBJ, + condRefCount: 0, + condMutex: null_mut(), + condAttr: PTHREAD_CONDATTR_INITIALIZER, + condSemName: [0; _PTHREAD_SHARED_SEM_NAME_MAX], +}; + +const PTHREAD_RWLOCKATTR_INITIALIZER: pthread_rwlockattr_t = pthread_rwlockattr_t { + rwlockAttrStatus: PTHREAD_INITIALIZED_OBJ, + rwlockAttrPshared: 1, + rwlockAttrMaxReaders: 0, + rwlockAttrConformOpt: 1, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + rwlockSemId: null_mut(), + rwlockReadersRefCount: 0, + rwlockValid: PTHREAD_VALID_OBJ, + rwlockInitted: PTHREAD_UNUSED_YET_OBJ, + rwlockAttr: PTHREAD_RWLOCKATTR_INITIALIZER, + rwlockSemName: [0; _PTHREAD_SHARED_SEM_NAME_MAX], +}; + +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; + +// rtpLibCommon.h +pub const VX_RTP_NAME_LENGTH: c_int = 255; +pub const RTP_ID_ERROR: crate::RTP_ID = -1; + +// h/public/unistd.h +// h/public/unistd.h +pub const R_OK: c_int = 4; +pub const _SC_ARG_MAX: c_int = 4; // Via unistd.h +pub const _SC_CHILD_MAX: c_int = 12; +pub const _SC_CLK_TCK: c_int = 13; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 21; +pub const _SC_HOST_NAME_MAX: c_int = 22; +pub const _SC_NGROUPS_MAX: c_int = 36; +pub const _SC_OPEN_MAX: c_int = 37; +pub const _SC_PAGE_SIZE: c_int = 38; +pub const _SC_PAGESIZE: c_int = 39; +pub const _SC_STREAM_MAX: c_int = 59; +pub const _SC_SYMLOOP_MAX: c_int = 60; +pub const _SC_TTY_NAME_MAX: c_int = 87; +pub const _SC_TZNAME_MAX: c_int = 89; +pub const _SC_VERSION: c_int = 94; +pub const O_ACCMODE: c_int = 3; +pub const O_CLOEXEC: c_int = 0x100000; // fcntlcom +pub const O_EXCL: c_int = 0x0800; +pub const O_CREAT: c_int = 0x0200; +pub const O_SYNC: c_int = 0x2000; +pub const O_ASYNC: c_int = 0x0040; +pub const O_DSYNC: c_int = 0x10000; +pub const O_TRUNC: c_int = 0x0400; +pub const O_APPEND: c_int = 0x0008; +pub const O_RDWR: c_int = 0x0002; +pub const O_WRONLY: c_int = 0x0001; +pub const O_RDONLY: c_int = 0; +pub const O_NONBLOCK: c_int = 0x4000; + +// mman.h +pub const PROT_NONE: c_int = 0x0000; +pub const PROT_READ: c_int = 0x0001; +pub const PROT_WRITE: c_int = 0x0002; +pub const PROT_EXEC: c_int = 0x0004; + +pub const MAP_SHARED: c_int = 0x0001; +pub const MAP_PRIVATE: c_int = 0x0002; +pub const MAP_ANON: c_int = 0x0004; +pub const MAP_ANONYMOUS: c_int = MAP_ANON; +pub const MAP_FIXED: c_int = 0x0010; +pub const MAP_CONTIG: c_int = 0x0020; + +pub const MS_SYNC: c_int = 0x0001; +pub const MS_ASYNC: c_int = 0x0002; +pub const MS_INVALIDATE: c_int = 0x0004; + +pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + +// sys/ttycom.h +pub const TIOCGWINSZ: c_int = 0x1740087468; +pub const TIOCSWINSZ: c_int = -0x7ff78b99; + +extern_ty! { + pub enum FILE {} + pub enum fpos_t {} // FIXME(vxworks): fill this out with a struct +} + +f! { + pub const fn CMSG_ALIGN(len: usize) -> usize { + len + size_of::() - 1 & !(size_of::() - 1) + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + let next = cmsg as usize + + CMSG_ALIGN((*cmsg).cmsg_len as usize) + + CMSG_ALIGN(size_of::()); + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if next <= max { + (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize > 0 { + (*mhdr).msg_control as *mut cmsghdr + } else { + core::ptr::null_mut::() + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { + (cmsg as *mut c_uchar).offset(CMSG_ALIGN(size_of::()) as isize) + } + + pub const fn CMSG_SPACE(length: c_uint) -> c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(size_of::())) as c_uint + } + + pub const fn CMSG_LEN(length: c_uint) -> c_uint { + CMSG_ALIGN(size_of::()) as c_uint + length + } +} + +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atof(s: *const c_char) -> c_double; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atol(s: *const c_char) -> c_long; + pub fn atoll(s: *const c_char) -> c_longlong; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtof(s: *const c_char, endp: *mut *mut c_char) -> c_float; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoll(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoull(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulonglong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn atexit(cb: extern "C" fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn cfgetospeed(termios: *const crate::termios) -> crate::speed_t; + pub fn cfmakeraw(termios: *mut crate::termios) -> c_int; + pub fn cfsetispeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + pub fn cfsetospeed(termios: *mut crate::termios, speed: crate::speed_t) -> c_int; + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, n: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memccpy(dest: *mut c_void, src: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void; + pub fn uname(buf: *mut crate::utsname) -> c_int; + pub fn times(buf: *mut crate::tms) -> crate::clock_t; + pub fn tcflush(fd: c_int, action: c_int) -> c_int; + pub fn pclose(stream: *mut crate::FILE) -> c_int; + pub fn mkdtemp(template: *mut c_char) -> *mut c_char; + + pub fn linkat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + + pub fn mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + + pub fn readlinkat( + dirfd: c_int, + pathname: *const c_char, + buf: *mut c_char, + bufsiz: size_t, + ) -> ssize_t; + + pub fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int; + + // netdb.h + pub fn getprotobyname(name: *const c_char) -> *mut protoent; + pub fn getprotobynumber(proto: c_int) -> *mut protoent; + pub fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut servent; + + pub fn fchownat( + dirfd: c_int, + pathname: *const c_char, + owner: crate::uid_t, + group: crate::gid_t, + flags: c_int, + ) -> c_int; +} + +extern "C" { + pub fn fprintf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn snprintf(s: *mut c_char, n: size_t, format: *const c_char, ...) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + pub fn fscanf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn scanf(format: *const c_char, ...) -> c_int; + pub fn sscanf(s: *const c_char, format: *const c_char, ...) -> c_int; + pub fn getchar_unlocked() -> c_int; + pub fn putchar_unlocked(c: c_int) -> c_int; + pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; + pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut crate::FILE; + pub fn fileno(stream: *mut crate::FILE) -> c_int; + pub fn creat(path: *const c_char, mode: mode_t) -> c_int; + pub fn rewinddir(dirp: *mut crate::DIR); + pub fn fchown(fd: c_int, owner: crate::uid_t, group: crate::gid_t) -> c_int; + pub fn access(path: *const c_char, amode: c_int) -> c_int; + pub fn alarm(seconds: c_uint) -> c_uint; + pub fn fchdir(dirfd: c_int) -> c_int; + pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; + pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; + pub fn getegid() -> gid_t; + pub fn geteuid() -> uid_t; + pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; + pub fn getlogin() -> *mut c_char; + pub fn getopt(argc: c_int, argv: *const *mut c_char, optstr: *const c_char) -> c_int; + pub fn pathconf(path: *const c_char, name: c_int) -> c_long; + pub fn pause() -> c_int; + pub fn seteuid(uid: uid_t) -> c_int; + pub fn setegid(gid: gid_t) -> c_int; + pub fn statfs(path: *const c_char, buf: *mut statfs) -> c_int; + pub fn sleep(secs: c_uint) -> c_uint; + pub fn ttyname(fd: c_int) -> *mut c_char; + pub fn wait(status: *mut c_int) -> pid_t; + pub fn umask(mask: mode_t) -> mode_t; + pub fn mlock(addr: *const c_void, len: size_t) -> c_int; + pub fn mlockall(flags: c_int) -> c_int; + pub fn munlock(addr: *const c_void, len: size_t) -> c_int; + pub fn munlockall() -> c_int; + + pub fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; + + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn truncate(path: *const c_char, length: off_t) -> c_int; + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; + pub fn shm_unlink(name: *const c_char) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn pthread_exit(value: *mut c_void) -> !; + pub fn pthread_attr_setdetachstate(attr: *mut crate::pthread_attr_t, state: c_int) -> c_int; + pub fn pthread_equal(t1: crate::pthread_t, t2: crate::pthread_t) -> c_int; + + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int; + + pub fn sigaction(signum: c_int, act: *const sigaction, oldact: *mut sigaction) -> c_int; + + pub fn utimes(filename: *const c_char, times: *const crate::timeval) -> c_int; + + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + + #[link_name = "_rtld_dlopen"] + pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void; + + #[link_name = "_rtld_dlerror"] + pub fn dlerror() -> *mut c_char; + + #[link_name = "_rtld_dlsym"] + pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; + + #[link_name = "_rtld_dlclose"] + pub fn dlclose(handle: *mut c_void) -> c_int; + + #[link_name = "_rtld_dladdr"] + pub fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int; + + // time.h + pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn mktime(tm: *mut tm) -> time_t; + pub fn time(time: *mut time_t) -> time_t; + pub fn gmtime(time_p: *const time_t) -> *mut tm; + pub fn localtime(time_p: *const time_t) -> *mut tm; + pub fn timegm(tm: *mut tm) -> time_t; + pub fn difftime(time1: time_t, time0: time_t) -> c_double; + pub fn gethostname(name: *mut c_char, len: size_t) -> c_int; + pub fn usleep(secs: crate::useconds_t) -> c_int; + pub fn putenv(string: *mut c_char) -> c_int; + pub fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char; + pub fn localeconv() -> *mut lconv; + + pub fn sigprocmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; + pub fn sigpending(set: *mut sigset_t) -> c_int; + + pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int; + + pub fn fseeko(stream: *mut crate::FILE, offset: off_t, whence: c_int) -> c_int; + pub fn ftello(stream: *mut crate::FILE) -> off_t; + pub fn mkstemp(template: *mut c_char) -> c_int; + + pub fn tmpnam(ptr: *mut c_char) -> *mut c_char; + + pub fn openlog(ident: *const c_char, logopt: c_int, facility: c_int); + pub fn closelog(); + pub fn setlogmask(maskpri: c_int) -> c_int; + pub fn syslog(priority: c_int, message: *const c_char, ...); + pub fn getline(lineptr: *mut *mut c_char, n: *mut size_t, stream: *mut FILE) -> ssize_t; + pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *const crate::termios) -> c_int; + pub fn tcgetattr(fd: c_int, termios: *mut crate::termios) -> c_int; + pub fn tcsendbreak(fd: c_int, duration: c_int) -> c_int; + pub fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t; + pub fn fnmatch(pattern: *const c_char, name: *const c_char, flags: c_int) -> c_int; + + pub fn symlinkat(target: *const c_char, newdirfd: c_int, linkpath: *const c_char) -> c_int; + + // sys/stat.h + pub fn fchmodat(dirfd: c_int, pathname: *const c_char, mode: mode_t, flags: c_int) -> c_int; + + // utime.h + pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int; +} + +extern "C" { + // stdlib.h + pub fn memalign(block_size: size_t, size_arg: size_t) -> *mut c_void; + + // ioLib.h + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + + // ioLib.h + pub fn chdir(attr: *const c_char) -> c_int; + + // pthread.h + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; + + // pthread.h + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; + + // pthread.h + pub fn pthread_mutexattr_settype(pAttr: *mut crate::pthread_mutexattr_t, pType: c_int) + -> c_int; + + // pthread.h + pub fn pthread_mutex_init( + mutex: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t, + ) -> c_int; + + // pthread.h + pub fn pthread_mutex_destroy(mutex: *mut pthread_mutex_t) -> c_int; + + // pthread.h + pub fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int; + + // pthread.h + pub fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int; + + // pthread.h + pub fn pthread_mutex_timedlock(attr: *mut pthread_mutex_t, spec: *const timespec) -> c_int; + + // pthread.h + pub fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int; + + // pthread.h + pub fn pthread_attr_setname(pAttr: *mut crate::pthread_attr_t, name: *mut c_char) -> c_int; + + // pthread.h + pub fn pthread_attr_setstacksize(attr: *mut crate::pthread_attr_t, stacksize: size_t) -> c_int; + + // pthread.h + pub fn pthread_attr_getstacksize( + attr: *const crate::pthread_attr_t, + size: *mut size_t, + ) -> c_int; + + // pthread.h + pub fn pthread_attr_init(attr: *mut crate::pthread_attr_t) -> c_int; + + // pthread.h + pub fn pthread_create( + pThread: *mut crate::pthread_t, + pAttr: *const crate::pthread_attr_t, + start_routine: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + + //pthread.h + pub fn pthread_setschedparam( + native: crate::pthread_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + //pthread.h + pub fn pthread_getschedparam( + native: crate::pthread_t, + policy: *mut c_int, + param: *mut crate::sched_param, + ) -> c_int; + + //pthread.h + pub fn pthread_attr_setinheritsched( + attr: *mut crate::pthread_attr_t, + inheritsched: c_int, + ) -> c_int; + + //pthread.h + pub fn pthread_attr_setschedpolicy(attr: *mut crate::pthread_attr_t, policy: c_int) -> c_int; + + // pthread.h + pub fn pthread_attr_destroy(thread: *mut crate::pthread_attr_t) -> c_int; + + // pthread.h + pub fn pthread_detach(thread: crate::pthread_t) -> c_int; + + // int pthread_atfork (void (*)(void), void (*)(void), void (*)(void)); + pub fn pthread_atfork( + prepare: Option, + parent: Option, + child: Option, + ) -> c_int; + + // stat.h + pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; + + // sys/statfs.h + pub fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int; + + // stat.h + pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; + + // unistd.h + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + + // dirent.h + pub fn readdir_r( + pDir: *mut crate::DIR, + entry: *mut crate::dirent, + result: *mut *mut crate::dirent, + ) -> c_int; + + // dirent.h + pub fn readdir(pDir: *mut crate::DIR) -> *mut crate::dirent; + + // dirent.h + pub fn fdopendir(fd: c_int) -> *mut crate::DIR; + + // dirent.h + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + + // fcntl.h or + // ioLib.h + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + + // fcntl.h + pub fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int, ...) -> c_int; + + // poll.h + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int; + + // pthread.h + pub fn pthread_condattr_init(attr: *mut crate::pthread_condattr_t) -> c_int; + + // pthread.h + pub fn pthread_condattr_destroy(attr: *mut crate::pthread_condattr_t) -> c_int; + + // pthread.h + pub fn pthread_condattr_getclock( + pAttr: *const crate::pthread_condattr_t, + pClockId: *mut crate::clockid_t, + ) -> c_int; + + // pthread.h + pub fn pthread_condattr_setclock( + pAttr: *mut crate::pthread_condattr_t, + clockId: crate::clockid_t, + ) -> c_int; + + // pthread.h + pub fn pthread_cond_init( + cond: *mut crate::pthread_cond_t, + attr: *const crate::pthread_condattr_t, + ) -> c_int; + + // pthread.h + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int; + + // pthread.h + pub fn pthread_cond_signal(cond: *mut crate::pthread_cond_t) -> c_int; + + // pthread.h + pub fn pthread_cond_broadcast(cond: *mut crate::pthread_cond_t) -> c_int; + + // pthread.h + pub fn pthread_cond_wait( + cond: *mut crate::pthread_cond_t, + mutex: *mut crate::pthread_mutex_t, + ) -> c_int; + + // pthread.h + pub fn pthread_rwlockattr_init(attr: *mut crate::pthread_rwlockattr_t) -> c_int; + + // pthread.h + pub fn pthread_rwlockattr_destroy(attr: *mut crate::pthread_rwlockattr_t) -> c_int; + + // pthread.h + pub fn pthread_rwlockattr_setmaxreaders( + attr: *mut crate::pthread_rwlockattr_t, + attr2: c_uint, + ) -> c_int; + + // pthread.h + pub fn pthread_rwlock_init( + attr: *mut crate::pthread_rwlock_t, + host: *const crate::pthread_rwlockattr_t, + ) -> c_int; + + // pthread.h + pub fn pthread_rwlock_destroy(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_rwlock_rdlock(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_rwlock_tryrdlock(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_rwlock_timedrdlock( + attr: *mut crate::pthread_rwlock_t, + host: *const crate::timespec, + ) -> c_int; + + // pthread.h + pub fn pthread_rwlock_wrlock(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_rwlock_trywrlock(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_rwlock_timedwrlock( + attr: *mut crate::pthread_rwlock_t, + host: *const crate::timespec, + ) -> c_int; + + // pthread.h + pub fn pthread_rwlock_unlock(attr: *mut crate::pthread_rwlock_t) -> c_int; + + // pthread.h + pub fn pthread_key_create( + key: *mut crate::pthread_key_t, + dtor: Option, + ) -> c_int; + + // pthread.h + pub fn pthread_key_delete(key: crate::pthread_key_t) -> c_int; + + // pthread.h + pub fn pthread_setspecific(key: crate::pthread_key_t, value: *const c_void) -> c_int; + + // pthread.h + pub fn pthread_getspecific(key: crate::pthread_key_t) -> *mut c_void; + + // pthread.h + pub fn pthread_cond_timedwait( + cond: *mut crate::pthread_cond_t, + mutex: *mut crate::pthread_mutex_t, + abstime: *const crate::timespec, + ) -> c_int; + + // pthread.h + pub fn pthread_attr_getname(attr: *mut crate::pthread_attr_t, name: *mut *mut c_char) -> c_int; + + // pthread.h + pub fn pthread_join(thread: crate::pthread_t, status: *mut *mut c_void) -> c_int; + + // pthread.h + pub fn pthread_self() -> crate::pthread_t; + + // clockLib.h + pub fn clock_gettime(clock_id: crate::clockid_t, tp: *mut crate::timespec) -> c_int; + + // clockLib.h + pub fn clock_settime(clock_id: crate::clockid_t, tp: *const crate::timespec) -> c_int; + + // clockLib.h + pub fn clock_getres(clock_id: crate::clockid_t, res: *mut crate::timespec) -> c_int; + + // clockLib.h + pub fn clock_nanosleep( + clock_id: crate::clockid_t, + flags: c_int, + rqtp: *const crate::timespec, + rmtp: *mut crate::timespec, + ) -> c_int; + + // timerLib.h + pub fn nanosleep(rqtp: *const crate::timespec, rmtp: *mut crate::timespec) -> c_int; + + // socket.h + pub fn accept(s: c_int, addr: *mut crate::sockaddr, addrlen: *mut crate::socklen_t) -> c_int; + + // socket.h + pub fn bind(fd: c_int, addr: *const sockaddr, len: socklen_t) -> c_int; + + // socket.h + pub fn connect(s: c_int, name: *const crate::sockaddr, namelen: crate::socklen_t) -> c_int; + + // socket.h + pub fn getpeername( + s: c_int, + name: *mut crate::sockaddr, + namelen: *mut crate::socklen_t, + ) -> c_int; + + // socket.h + pub fn getsockname(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) + -> c_int; + + // socket.h + pub fn getsockopt( + sockfd: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut crate::socklen_t, + ) -> c_int; + + // socket.h + pub fn listen(socket: c_int, backlog: c_int) -> c_int; + + // socket.h + pub fn recv(s: c_int, buf: *mut c_void, bufLen: size_t, flags: c_int) -> ssize_t; + + // socket.h + pub fn recvfrom( + s: c_int, + buf: *mut c_void, + bufLen: size_t, + flags: c_int, + from: *mut crate::sockaddr, + pFromLen: *mut crate::socklen_t, + ) -> ssize_t; + + pub fn recvmsg(socket: c_int, mp: *mut crate::msghdr, flags: c_int) -> ssize_t; + + // socket.h + pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t; + + pub fn sendmsg(socket: c_int, mp: *const crate::msghdr, flags: c_int) -> ssize_t; + + // socket.h + pub fn sendto( + socket: c_int, + buf: *const c_void, + len: size_t, + flags: c_int, + addr: *const sockaddr, + addrlen: socklen_t, + ) -> ssize_t; + + // socket.h + pub fn setsockopt( + socket: c_int, + level: c_int, + name: c_int, + value: *const c_void, + option_len: socklen_t, + ) -> c_int; + + // socket.h + pub fn shutdown(s: c_int, how: c_int) -> c_int; + + // socket.h + pub fn socket(domain: c_int, _type: c_int, protocol: c_int) -> c_int; + + // icotl.h + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + + // fcntl.h + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; + + // ntp_rfc2553.h for kernel + // netdb.h for user + pub fn gai_strerror(errcode: c_int) -> *mut c_char; + + // ioLib.h or + // unistd.h + pub fn close(fd: c_int) -> c_int; + + // ioLib.h or + // unistd.h + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; + + // ioLib.h or + // unistd.h + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + + // ioLib.h or + // unistd.h + pub fn isatty(fd: c_int) -> c_int; + + // ioLib.h or + // unistd.h + pub fn dup(src: c_int) -> c_int; + + // ioLib.h or + // unistd.h + pub fn dup2(src: c_int, dst: c_int) -> c_int; + + // ioLib.h or + // unistd.h + pub fn pipe(fds: *mut c_int) -> c_int; + + // ioLib.h or + // unistd.h + pub fn unlink(pathname: *const c_char) -> c_int; + + // unistd.h and + // ioLib.h + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + + // netdb.h + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + + // netdb.h + pub fn freeaddrinfo(res: *mut addrinfo); + + // signal.h + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; + + // unistd.h + pub fn getpid() -> pid_t; + + // unistd.h + pub fn getppid() -> pid_t; + + // unistd.h + pub fn setpgid(pid: pid_t, pgid: pid_t) -> pid_t; + + // wait.h + pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t; + + // unistd.h + pub fn sysconf(attr: c_int) -> c_long; + + // stdlib.h + pub fn setenv( + // setenv.c + envVarName: *const c_char, + envVarValue: *const c_char, + overwrite: c_int, + ) -> c_int; + + // stdlib.h + pub fn unsetenv( + // setenv.c + envVarName: *const c_char, + ) -> c_int; + + // stdlib.h + pub fn realpath(fileName: *const c_char, resolvedName: *mut c_char) -> *mut c_char; + + // unistd.h + pub fn link(src: *const c_char, dst: *const c_char) -> c_int; + + // unistd.h + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsize: size_t) -> ssize_t; + + // unistd.h + pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int; + + // dirent.h + pub fn opendir(name: *const c_char) -> *mut crate::DIR; + + // unistd.h + pub fn rmdir(path: *const c_char) -> c_int; + + // stat.h + pub fn mkdir(dirName: *const c_char, mode: mode_t) -> c_int; + + // stat.h + pub fn chmod(path: *const c_char, mode: mode_t) -> c_int; + + // stat.h + pub fn fchmod(attr1: c_int, attr2: mode_t) -> c_int; + + // unistd.h + pub fn fsync(fd: c_int) -> c_int; + + // unistd.h + pub fn fdatasync(fd: c_int) -> c_int; + + // dirent.h + pub fn closedir(ptr: *mut crate::DIR) -> c_int; + + //sched.h + pub fn sched_get_priority_max(policy: c_int) -> c_int; + + //sched.h + pub fn sched_get_priority_min(policy: c_int) -> c_int; + + //sched.h + pub fn sched_setparam(pid: crate::pid_t, param: *const crate::sched_param) -> c_int; + + //sched.h + pub fn sched_getparam(pid: crate::pid_t, param: *mut crate::sched_param) -> c_int; + + //sched.h + pub fn sched_setscheduler( + pid: crate::pid_t, + policy: c_int, + param: *const crate::sched_param, + ) -> c_int; + + //sched.h + pub fn sched_getscheduler(pid: crate::pid_t) -> c_int; + + //sched.h + pub fn sched_rr_get_interval(pid: crate::pid_t, tp: *mut crate::timespec) -> c_int; + + // sched.h + pub fn sched_yield() -> c_int; + + // errnoLib.h + pub fn errnoSet(err: c_int) -> c_int; + + // errnoLib.h + pub fn errnoGet() -> c_int; + + // unistd.h + pub fn _exit(status: c_int) -> !; + + // unistd.h + pub fn setgid(gid: crate::gid_t) -> c_int; + + // unistd.h + pub fn getgid() -> crate::gid_t; + + // unistd.h + pub fn setuid(uid: crate::uid_t) -> c_int; + + // unistd.h + pub fn getuid() -> crate::uid_t; + + // signal.h + pub fn sigemptyset(__set: *mut sigset_t) -> c_int; + pub fn sigfillset(set: *mut sigset_t) -> c_int; + pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int; + pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int; + + // pthread.h for kernel + // signal.h for user + pub fn pthread_sigmask(__how: c_int, __set: *const sigset_t, __oset: *mut sigset_t) -> c_int; + + // signal.h for user + pub fn kill(__pid: pid_t, __signo: c_int) -> c_int; + + // signal.h for user + pub fn sigqueue(__pid: pid_t, __signo: c_int, __value: crate::sigval) -> c_int; + + // signal.h for user + pub fn _sigqueue( + rtpId: crate::RTP_ID, + signo: c_int, + pValue: *const crate::sigval, + sigCode: c_int, + ) -> c_int; + + // signal.h + pub fn taskKill(taskId: crate::TASK_ID, signo: c_int) -> c_int; + + // signal.h + pub fn raise(__signo: c_int) -> c_int; + + // taskLibCommon.h + pub fn taskIdSelf() -> crate::TASK_ID; + pub fn taskDelay(ticks: crate::_Vx_ticks_t) -> c_int; + + // taskLib.h + pub fn taskNameSet(task_id: crate::TASK_ID, task_name: *mut c_char) -> c_int; + pub fn taskNameGet(task_id: crate::TASK_ID, buf_name: *mut c_char, bufsize: size_t) -> c_int; + + // rtpLibCommon.h + pub fn rtpInfoGet(rtpId: crate::RTP_ID, rtpStruct: *mut crate::RTP_DESC) -> c_int; + pub fn rtpSpawn( + pubrtpFileName: *const c_char, + argv: *mut *const c_char, + envp: *mut *const c_char, + priority: c_int, + uStackSize: size_t, + options: c_int, + taskOptions: c_int, + ) -> RTP_ID; + + // ioLib.h + pub fn _realpath(fileName: *const c_char, resolvedName: *mut c_char) -> *mut c_char; + + // pathLib.h + pub fn _pathIsAbsolute(filepath: *const c_char, pNameTail: *mut *const c_char) -> BOOL; + + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + + // randomNumGen.h + pub fn randBytes(buf: *mut c_uchar, length: c_int) -> c_int; + pub fn randABytes(buf: *mut c_uchar, length: c_int) -> c_int; + pub fn randUBytes(buf: *mut c_uchar, length: c_int) -> c_int; + pub fn randSecure() -> c_int; + + // mqueue.h + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> crate::mqd_t; + pub fn mq_close(mqd: crate::mqd_t) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mq_receive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_timedreceive( + mqd: crate::mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const crate::timespec, + ) -> ssize_t; + pub fn mq_send( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_timedsend( + mqd: crate::mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const crate::timespec, + ) -> c_int; + pub fn mq_getattr(mqd: crate::mqd_t, attr: *mut crate::mq_attr) -> c_int; + pub fn mq_setattr( + mqd: crate::mqd_t, + newattr: *const crate::mq_attr, + oldattr: *mut crate::mq_attr, + ) -> c_int; + + // vxCpuLib.h + pub fn vxCpuEnabledGet() -> crate::cpuset_t; // Get set of running CPU's in the system + pub fn vxCpuConfiguredGet() -> crate::cpuset_t; // Get set of Configured CPU's in the system +} + +//Dummy functions, these don't really exist in VxWorks. + +// wait.h macros +safe_f! { + pub const fn WIFEXITED(status: c_int) -> bool { + (status & 0xFF00) == 0 + } + pub const fn WIFSIGNALED(status: c_int) -> bool { + (status & 0xFF00) != 0 + } + pub const fn WIFSTOPPED(status: c_int) -> bool { + (status & 0xFF0000) != 0 + } + pub const fn WEXITSTATUS(status: c_int) -> c_int { + status & 0xFF + } + pub const fn WIFCONTINUED(status: c_int) -> c_int { + (status >> 24) & 0xFF + } + pub const fn WTERMSIG(status: c_int) -> c_int { + (status >> 8) & 0xFF + } + pub const fn WSTOPSIG(status: c_int) -> c_int { + (status >> 16) & 0xFF + } +} + +pub fn pread(_fd: c_int, _buf: *mut c_void, _count: size_t, _offset: off64_t) -> ssize_t { + -1 +} + +pub fn pwrite(_fd: c_int, _buf: *const c_void, _count: size_t, _offset: off64_t) -> ssize_t { + -1 +} +pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int { + // check to see if align is a power of 2 and if align is a multiple + // of sizeof(void *) + if (align & align - 1 != 0) || (align as usize % size_of::() != 0) { + return crate::EINVAL; + } + + unsafe { + // posix_memalign should not set errno + let e = crate::errnoGet(); + + let temp = memalign(align, size); + crate::errnoSet(e as c_int); + + if temp.is_null() { + crate::ENOMEM + } else { + *memptr = temp; + 0 + } + } +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "powerpc64")] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(target_arch = "riscv32")] { + mod riscv32; + pub use self::riscv32::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } else { + // Unknown target_arch + } +} diff --git a/deps/crates/vendor/libc/src/vxworks/powerpc.rs b/deps/crates/vendor/libc/src/vxworks/powerpc.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/powerpc.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/vxworks/powerpc64.rs b/deps/crates/vendor/libc/src/vxworks/powerpc64.rs new file mode 100644 index 00000000000000..376783c8234baf --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/powerpc64.rs @@ -0,0 +1 @@ +pub type wchar_t = u32; diff --git a/deps/crates/vendor/libc/src/vxworks/riscv32.rs b/deps/crates/vendor/libc/src/vxworks/riscv32.rs new file mode 100644 index 00000000000000..f562626f7fb2b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/riscv32.rs @@ -0,0 +1 @@ +pub type wchar_t = i32; diff --git a/deps/crates/vendor/libc/src/vxworks/riscv64.rs b/deps/crates/vendor/libc/src/vxworks/riscv64.rs new file mode 100644 index 00000000000000..f562626f7fb2b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/riscv64.rs @@ -0,0 +1 @@ +pub type wchar_t = i32; diff --git a/deps/crates/vendor/libc/src/vxworks/x86.rs b/deps/crates/vendor/libc/src/vxworks/x86.rs new file mode 100644 index 00000000000000..f562626f7fb2b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/x86.rs @@ -0,0 +1 @@ +pub type wchar_t = i32; diff --git a/deps/crates/vendor/libc/src/vxworks/x86_64.rs b/deps/crates/vendor/libc/src/vxworks/x86_64.rs new file mode 100644 index 00000000000000..f562626f7fb2b7 --- /dev/null +++ b/deps/crates/vendor/libc/src/vxworks/x86_64.rs @@ -0,0 +1 @@ +pub type wchar_t = i32; diff --git a/deps/crates/vendor/libc/src/wasi/mod.rs b/deps/crates/vendor/libc/src/wasi/mod.rs new file mode 100644 index 00000000000000..e580df52ad224a --- /dev/null +++ b/deps/crates/vendor/libc/src/wasi/mod.rs @@ -0,0 +1,1098 @@ +//! [wasi-libc](https://github.com/WebAssembly/wasi-libc) definitions. +//! +//! `wasi-libc` project provides multiple libraries including emulated features, but we list only +//! basic features with `libc.a` here. + +use core::iter::Iterator; + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; +pub type size_t = usize; +pub type ssize_t = isize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type off_t = i64; +pub type pid_t = i32; +pub type clock_t = c_longlong; +pub type time_t = c_longlong; +pub type ino_t = u64; +pub type sigset_t = c_uchar; +pub type suseconds_t = c_longlong; +pub type mode_t = u32; +pub type dev_t = u64; +pub type uid_t = u32; +pub type gid_t = u32; +pub type nlink_t = u64; +pub type blksize_t = c_long; +pub type blkcnt_t = i64; +pub type nfds_t = c_ulong; +pub type wchar_t = i32; +pub type nl_item = c_int; +pub type __wasi_rights_t = u64; +pub type locale_t = *mut __locale_struct; +pub type pthread_t = *mut c_void; +pub type pthread_once_t = c_int; +pub type pthread_key_t = c_uint; +pub type pthread_spinlock_t = c_int; + +s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } +} + +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub enum FILE {} +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub enum DIR {} +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub enum __locale_struct {} + +s_paren! { + // in wasi-libc clockid_t is const struct __clockid* (where __clockid is an opaque struct), + // but that's an implementation detail that we don't want to have to deal with + #[repr(transparent)] + #[allow(dead_code)] + pub struct clockid_t(*const u8); +} + +unsafe impl Send for clockid_t {} +unsafe impl Sync for clockid_t {} + +s! { + #[repr(align(8))] + pub struct fpos_t { + data: [u8; 16], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub __tm_gmtoff: c_int, + pub __tm_zone: *const c_char, + pub __tm_nsec: c_int, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + pub struct tms { + pub tms_utime: clock_t, + pub tms_stime: clock_t, + pub tms_cutime: clock_t, + pub tms_cstime: clock_t, + } + + pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct pollfd { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + __pad0: Padding, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atim: timespec, + pub st_mtim: timespec, + pub st_ctim: timespec, + __reserved: Padding<[c_longlong; 3]>, + } + + pub struct fd_set { + __nfds: usize, + __fds: [c_int; FD_SETSIZE as usize], + } + + pub struct pthread_attr_t { + size: [c_long; 9], + } + + pub struct pthread_mutexattr_t { + __attr: c_uint, + } + + pub struct pthread_condattr_t { + __attr: c_uint, + } + + pub struct pthread_barrierattr_t { + __attr: c_uint, + } + + pub struct pthread_rwlockattr_t { + __attr: [c_uint; 2], + } + + pub struct pthread_cond_t { + size: [*mut c_void; 12], + } + + pub struct pthread_mutex_t { + size: [*mut c_void; 6], + } + + pub struct pthread_rwlock_t { + size: [*mut c_void; 8], + } + + pub struct pthread_barrier_t { + size: [*mut c_void; 5], + } +} + +// Declare dirent outside of s! so that it doesn't implement Copy, Eq, Hash, +// etc., since it contains a flexible array member with a dynamic size. +#[repr(C)] +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + /// d_name is declared in WASI libc as a flexible array member, which + /// can't be directly expressed in Rust. As an imperfect workaround, + /// declare it as a zero-length array instead. + pub d_name: [c_char; 0], +} + +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; +pub const STDIN_FILENO: c_int = 0; +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const F_GETFD: c_int = 1; +pub const F_SETFD: c_int = 2; +pub const F_GETFL: c_int = 3; +pub const F_SETFL: c_int = 4; +pub const FD_CLOEXEC: c_int = 1; +pub const FD_SETSIZE: size_t = 1024; +pub const O_APPEND: c_int = 0x0001; +pub const O_DSYNC: c_int = 0x0002; +pub const O_NONBLOCK: c_int = 0x0004; +pub const O_RSYNC: c_int = 0x0008; +pub const O_SYNC: c_int = 0x0010; +pub const O_CREAT: c_int = 0x0001 << 12; +pub const O_DIRECTORY: c_int = 0x0002 << 12; +pub const O_EXCL: c_int = 0x0004 << 12; +pub const O_TRUNC: c_int = 0x0008 << 12; +pub const O_NOFOLLOW: c_int = 0x01000000; +pub const O_EXEC: c_int = 0x02000000; +pub const O_RDONLY: c_int = 0x04000000; +pub const O_SEARCH: c_int = 0x08000000; +pub const O_WRONLY: c_int = 0x10000000; +pub const O_CLOEXEC: c_int = 0x0; +pub const O_RDWR: c_int = O_WRONLY | O_RDONLY; +pub const O_ACCMODE: c_int = O_EXEC | O_RDWR | O_SEARCH; +pub const O_NOCTTY: c_int = 0x0; +pub const POSIX_FADV_DONTNEED: c_int = 4; +pub const POSIX_FADV_NOREUSE: c_int = 5; +pub const POSIX_FADV_NORMAL: c_int = 0; +pub const POSIX_FADV_RANDOM: c_int = 2; +pub const POSIX_FADV_SEQUENTIAL: c_int = 1; +pub const POSIX_FADV_WILLNEED: c_int = 3; +pub const AT_FDCWD: c_int = -2; +pub const AT_EACCESS: c_int = 0x0; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x1; +pub const AT_SYMLINK_FOLLOW: c_int = 0x2; +pub const AT_REMOVEDIR: c_int = 0x4; +pub const UTIME_OMIT: c_long = 0xfffffffe; +pub const UTIME_NOW: c_long = 0xffffffff; +pub const S_IFIFO: mode_t = 0o1_0000; +pub const S_IFCHR: mode_t = 0o2_0000; +pub const S_IFBLK: mode_t = 0o6_0000; +pub const S_IFDIR: mode_t = 0o4_0000; +pub const S_IFREG: mode_t = 0o10_0000; +pub const S_IFLNK: mode_t = 0o12_0000; +pub const S_IFSOCK: mode_t = 0o14_0000; +pub const S_IFMT: mode_t = 0o17_0000; +pub const S_IRWXO: mode_t = 0o0007; +pub const S_IXOTH: mode_t = 0o0001; +pub const S_IWOTH: mode_t = 0o0002; +pub const S_IROTH: mode_t = 0o0004; +pub const S_IRWXG: mode_t = 0o0070; +pub const S_IXGRP: mode_t = 0o0010; +pub const S_IWGRP: mode_t = 0o0020; +pub const S_IRGRP: mode_t = 0o0040; +pub const S_IRWXU: mode_t = 0o0700; +pub const S_IXUSR: mode_t = 0o0100; +pub const S_IWUSR: mode_t = 0o0200; +pub const S_IRUSR: mode_t = 0o0400; +pub const S_ISVTX: mode_t = 0o1000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISUID: mode_t = 0o4000; +pub const DT_UNKNOWN: u8 = 0; +pub const DT_BLK: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 3; +pub const DT_REG: u8 = 4; +pub const DT_FIFO: u8 = 6; +pub const DT_LNK: u8 = 7; +pub const DT_SOCK: u8 = 20; +pub const FIONREAD: c_int = 1; +pub const FIONBIO: c_int = 2; +pub const F_OK: c_int = 0; +pub const R_OK: c_int = 4; +pub const W_OK: c_int = 2; +pub const X_OK: c_int = 1; +pub const POLLIN: c_short = 0x1; +pub const POLLOUT: c_short = 0x2; +pub const POLLERR: c_short = 0x1000; +pub const POLLHUP: c_short = 0x2000; +pub const POLLNVAL: c_short = 0x4000; +pub const POLLRDNORM: c_short = 0x1; +pub const POLLWRNORM: c_short = 0x2; + +pub const E2BIG: c_int = 1; +pub const EACCES: c_int = 2; +pub const EADDRINUSE: c_int = 3; +pub const EADDRNOTAVAIL: c_int = 4; +pub const EAFNOSUPPORT: c_int = 5; +pub const EAGAIN: c_int = 6; +pub const EALREADY: c_int = 7; +pub const EBADF: c_int = 8; +pub const EBADMSG: c_int = 9; +pub const EBUSY: c_int = 10; +pub const ECANCELED: c_int = 11; +pub const ECHILD: c_int = 12; +pub const ECONNABORTED: c_int = 13; +pub const ECONNREFUSED: c_int = 14; +pub const ECONNRESET: c_int = 15; +pub const EDEADLK: c_int = 16; +pub const EDESTADDRREQ: c_int = 17; +pub const EDOM: c_int = 18; +pub const EDQUOT: c_int = 19; +pub const EEXIST: c_int = 20; +pub const EFAULT: c_int = 21; +pub const EFBIG: c_int = 22; +pub const EHOSTUNREACH: c_int = 23; +pub const EIDRM: c_int = 24; +pub const EILSEQ: c_int = 25; +pub const EINPROGRESS: c_int = 26; +pub const EINTR: c_int = 27; +pub const EINVAL: c_int = 28; +pub const EIO: c_int = 29; +pub const EISCONN: c_int = 30; +pub const EISDIR: c_int = 31; +pub const ELOOP: c_int = 32; +pub const EMFILE: c_int = 33; +pub const EMLINK: c_int = 34; +pub const EMSGSIZE: c_int = 35; +pub const EMULTIHOP: c_int = 36; +pub const ENAMETOOLONG: c_int = 37; +pub const ENETDOWN: c_int = 38; +pub const ENETRESET: c_int = 39; +pub const ENETUNREACH: c_int = 40; +pub const ENFILE: c_int = 41; +pub const ENOBUFS: c_int = 42; +pub const ENODEV: c_int = 43; +pub const ENOENT: c_int = 44; +pub const ENOEXEC: c_int = 45; +pub const ENOLCK: c_int = 46; +pub const ENOLINK: c_int = 47; +pub const ENOMEM: c_int = 48; +pub const ENOMSG: c_int = 49; +pub const ENOPROTOOPT: c_int = 50; +pub const ENOSPC: c_int = 51; +pub const ENOSYS: c_int = 52; +pub const ENOTCONN: c_int = 53; +pub const ENOTDIR: c_int = 54; +pub const ENOTEMPTY: c_int = 55; +pub const ENOTRECOVERABLE: c_int = 56; +pub const ENOTSOCK: c_int = 57; +pub const ENOTSUP: c_int = 58; +pub const ENOTTY: c_int = 59; +pub const ENXIO: c_int = 60; +pub const EOVERFLOW: c_int = 61; +pub const EOWNERDEAD: c_int = 62; +pub const EPERM: c_int = 63; +pub const EPIPE: c_int = 64; +pub const EPROTO: c_int = 65; +pub const EPROTONOSUPPORT: c_int = 66; +pub const EPROTOTYPE: c_int = 67; +pub const ERANGE: c_int = 68; +pub const EROFS: c_int = 69; +pub const ESPIPE: c_int = 70; +pub const ESRCH: c_int = 71; +pub const ESTALE: c_int = 72; +pub const ETIMEDOUT: c_int = 73; +pub const ETXTBSY: c_int = 74; +pub const EXDEV: c_int = 75; +pub const ENOTCAPABLE: c_int = 76; +pub const EOPNOTSUPP: c_int = ENOTSUP; +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const _SC_ARG_MAX: c_int = 0; +pub const _SC_CHILD_MAX: c_int = 1; +pub const _SC_CLK_TCK: c_int = 2; +pub const _SC_NGROUPS_MAX: c_int = 3; +pub const _SC_OPEN_MAX: c_int = 4; +pub const _SC_STREAM_MAX: c_int = 5; +pub const _SC_TZNAME_MAX: c_int = 6; +pub const _SC_JOB_CONTROL: c_int = 7; +pub const _SC_SAVED_IDS: c_int = 8; +pub const _SC_REALTIME_SIGNALS: c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: c_int = 10; +pub const _SC_TIMERS: c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: c_int = 12; +pub const _SC_PRIORITIZED_IO: c_int = 13; +pub const _SC_SYNCHRONIZED_IO: c_int = 14; +pub const _SC_FSYNC: c_int = 15; +pub const _SC_MAPPED_FILES: c_int = 16; +pub const _SC_MEMLOCK: c_int = 17; +pub const _SC_MEMLOCK_RANGE: c_int = 18; +pub const _SC_MEMORY_PROTECTION: c_int = 19; +pub const _SC_MESSAGE_PASSING: c_int = 20; +pub const _SC_SEMAPHORES: c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; +pub const _SC_AIO_LISTIO_MAX: c_int = 23; +pub const _SC_AIO_MAX: c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; +pub const _SC_DELAYTIMER_MAX: c_int = 26; +pub const _SC_MQ_OPEN_MAX: c_int = 27; +pub const _SC_MQ_PRIO_MAX: c_int = 28; +pub const _SC_VERSION: c_int = 29; +pub const _SC_PAGESIZE: c_int = 30; +pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: c_int = 31; +pub const _SC_SEM_NSEMS_MAX: c_int = 32; +pub const _SC_SEM_VALUE_MAX: c_int = 33; +pub const _SC_SIGQUEUE_MAX: c_int = 34; +pub const _SC_TIMER_MAX: c_int = 35; +pub const _SC_BC_BASE_MAX: c_int = 36; +pub const _SC_BC_DIM_MAX: c_int = 37; +pub const _SC_BC_SCALE_MAX: c_int = 38; +pub const _SC_BC_STRING_MAX: c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; +pub const _SC_EXPR_NEST_MAX: c_int = 42; +pub const _SC_LINE_MAX: c_int = 43; +pub const _SC_RE_DUP_MAX: c_int = 44; +pub const _SC_2_VERSION: c_int = 46; +pub const _SC_2_C_BIND: c_int = 47; +pub const _SC_2_C_DEV: c_int = 48; +pub const _SC_2_FORT_DEV: c_int = 49; +pub const _SC_2_FORT_RUN: c_int = 50; +pub const _SC_2_SW_DEV: c_int = 51; +pub const _SC_2_LOCALEDEF: c_int = 52; +pub const _SC_UIO_MAXIOV: c_int = 60; +pub const _SC_IOV_MAX: c_int = 60; +pub const _SC_THREADS: c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; +pub const _SC_LOGIN_NAME_MAX: c_int = 71; +pub const _SC_TTY_NAME_MAX: c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; +pub const _SC_THREAD_KEYS_MAX: c_int = 74; +pub const _SC_THREAD_STACK_MIN: c_int = 75; +pub const _SC_THREAD_THREADS_MAX: c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; +pub const _SC_NPROCESSORS_CONF: c_int = 83; +pub const _SC_NPROCESSORS_ONLN: c_int = 84; +pub const _SC_PHYS_PAGES: c_int = 85; +pub const _SC_AVPHYS_PAGES: c_int = 86; +pub const _SC_ATEXIT_MAX: c_int = 87; +pub const _SC_PASS_MAX: c_int = 88; +pub const _SC_XOPEN_VERSION: c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: c_int = 90; +pub const _SC_XOPEN_UNIX: c_int = 91; +pub const _SC_XOPEN_CRYPT: c_int = 92; +pub const _SC_XOPEN_ENH_I18N: c_int = 93; +pub const _SC_XOPEN_SHM: c_int = 94; +pub const _SC_2_CHAR_TERM: c_int = 95; +pub const _SC_2_UPE: c_int = 97; +pub const _SC_XOPEN_XPG2: c_int = 98; +pub const _SC_XOPEN_XPG3: c_int = 99; +pub const _SC_XOPEN_XPG4: c_int = 100; +pub const _SC_NZERO: c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; +pub const _SC_XBS5_LP64_OFF64: c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; +pub const _SC_XOPEN_LEGACY: c_int = 129; +pub const _SC_XOPEN_REALTIME: c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; +pub const _SC_ADVISORY_INFO: c_int = 132; +pub const _SC_BARRIERS: c_int = 133; +pub const _SC_CLOCK_SELECTION: c_int = 137; +pub const _SC_CPUTIME: c_int = 138; +pub const _SC_THREAD_CPUTIME: c_int = 139; +pub const _SC_MONOTONIC_CLOCK: c_int = 149; +pub const _SC_READER_WRITER_LOCKS: c_int = 153; +pub const _SC_SPIN_LOCKS: c_int = 154; +pub const _SC_REGEXP: c_int = 155; +pub const _SC_SHELL: c_int = 157; +pub const _SC_SPAWN: c_int = 159; +pub const _SC_SPORADIC_SERVER: c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: c_int = 161; +pub const _SC_TIMEOUTS: c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 165; +pub const _SC_2_PBS: c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: c_int = 169; +pub const _SC_2_PBS_LOCATE: c_int = 170; +pub const _SC_2_PBS_MESSAGE: c_int = 171; +pub const _SC_2_PBS_TRACK: c_int = 172; +pub const _SC_SYMLOOP_MAX: c_int = 173; +pub const _SC_STREAMS: c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: c_int = 175; +pub const _SC_V6_ILP32_OFF32: c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: c_int = 177; +pub const _SC_V6_LP64_OFF64: c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: c_int = 179; +pub const _SC_HOST_NAME_MAX: c_int = 180; +pub const _SC_TRACE: c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: c_int = 182; +pub const _SC_TRACE_INHERIT: c_int = 183; +pub const _SC_TRACE_LOG: c_int = 184; +pub const _SC_IPV6: c_int = 235; +pub const _SC_RAW_SOCKETS: c_int = 236; +pub const _SC_V7_ILP32_OFF32: c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: c_int = 238; +pub const _SC_V7_LP64_OFF64: c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: c_int = 240; +pub const _SC_SS_REPL_MAX: c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 242; +pub const _SC_TRACE_NAME_MAX: c_int = 243; +pub const _SC_TRACE_SYS_MAX: c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: c_int = 245; +pub const _SC_XOPEN_STREAMS: c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: c_int = 248; +pub const _SC_MINSIGSTKSZ: c_int = 249; +pub const _SC_SIGSTKSZ: c_int = 250; + +// FIXME(msrv): `addr_of!(EXTERN_STATIC)` is now safe; remove `unsafe` when MSRV >= 1.82 +#[allow(unused_unsafe)] +pub static CLOCK_MONOTONIC: clockid_t = unsafe { clockid_t(core::ptr::addr_of!(_CLOCK_MONOTONIC)) }; +#[allow(unused_unsafe)] +pub static CLOCK_REALTIME: clockid_t = unsafe { clockid_t(core::ptr::addr_of!(_CLOCK_REALTIME)) }; + +pub const ABDAY_1: crate::nl_item = 0x20000; +pub const ABDAY_2: crate::nl_item = 0x20001; +pub const ABDAY_3: crate::nl_item = 0x20002; +pub const ABDAY_4: crate::nl_item = 0x20003; +pub const ABDAY_5: crate::nl_item = 0x20004; +pub const ABDAY_6: crate::nl_item = 0x20005; +pub const ABDAY_7: crate::nl_item = 0x20006; + +pub const DAY_1: crate::nl_item = 0x20007; +pub const DAY_2: crate::nl_item = 0x20008; +pub const DAY_3: crate::nl_item = 0x20009; +pub const DAY_4: crate::nl_item = 0x2000A; +pub const DAY_5: crate::nl_item = 0x2000B; +pub const DAY_6: crate::nl_item = 0x2000C; +pub const DAY_7: crate::nl_item = 0x2000D; + +pub const ABMON_1: crate::nl_item = 0x2000E; +pub const ABMON_2: crate::nl_item = 0x2000F; +pub const ABMON_3: crate::nl_item = 0x20010; +pub const ABMON_4: crate::nl_item = 0x20011; +pub const ABMON_5: crate::nl_item = 0x20012; +pub const ABMON_6: crate::nl_item = 0x20013; +pub const ABMON_7: crate::nl_item = 0x20014; +pub const ABMON_8: crate::nl_item = 0x20015; +pub const ABMON_9: crate::nl_item = 0x20016; +pub const ABMON_10: crate::nl_item = 0x20017; +pub const ABMON_11: crate::nl_item = 0x20018; +pub const ABMON_12: crate::nl_item = 0x20019; + +pub const MON_1: crate::nl_item = 0x2001A; +pub const MON_2: crate::nl_item = 0x2001B; +pub const MON_3: crate::nl_item = 0x2001C; +pub const MON_4: crate::nl_item = 0x2001D; +pub const MON_5: crate::nl_item = 0x2001E; +pub const MON_6: crate::nl_item = 0x2001F; +pub const MON_7: crate::nl_item = 0x20020; +pub const MON_8: crate::nl_item = 0x20021; +pub const MON_9: crate::nl_item = 0x20022; +pub const MON_10: crate::nl_item = 0x20023; +pub const MON_11: crate::nl_item = 0x20024; +pub const MON_12: crate::nl_item = 0x20025; + +pub const AM_STR: crate::nl_item = 0x20026; +pub const PM_STR: crate::nl_item = 0x20027; + +pub const D_T_FMT: crate::nl_item = 0x20028; +pub const D_FMT: crate::nl_item = 0x20029; +pub const T_FMT: crate::nl_item = 0x2002A; +pub const T_FMT_AMPM: crate::nl_item = 0x2002B; + +pub const ERA: crate::nl_item = 0x2002C; +pub const ERA_D_FMT: crate::nl_item = 0x2002E; +pub const ALT_DIGITS: crate::nl_item = 0x2002F; +pub const ERA_D_T_FMT: crate::nl_item = 0x20030; +pub const ERA_T_FMT: crate::nl_item = 0x20031; + +pub const CODESET: crate::nl_item = 14; +pub const CRNCYSTR: crate::nl_item = 0x4000F; +pub const RADIXCHAR: crate::nl_item = 0x10000; +pub const THOUSEP: crate::nl_item = 0x10001; +pub const YESEXPR: crate::nl_item = 0x50000; +pub const NOEXPR: crate::nl_item = 0x50001; +pub const YESSTR: crate::nl_item = 0x50002; +pub const NOSTR: crate::nl_item = 0x50003; + +pub const PTHREAD_STACK_MIN: usize = 2048; +pub const TIMER_ABSTIME: c_int = 1; + +f! { + pub fn FD_ISSET(fd: c_int, set: *const fd_set) -> bool { + let set = &*set; + let n = set.__nfds; + return set.__fds[..n].iter().any(|p| *p == fd); + } + + pub fn FD_SET(fd: c_int, set: *mut fd_set) -> () { + let set = &mut *set; + let n = set.__nfds; + if !set.__fds[..n].iter().any(|p| *p == fd) { + set.__nfds = n + 1; + set.__fds[n] = fd; + } + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + (*set).__nfds = 0; + return; + } +} + +#[cfg_attr( + feature = "rustc-dep-of-std", + link( + name = "c", + kind = "static", + modifiers = "-bundle", + cfg(target_feature = "crt-static") + ) +)] +#[cfg_attr( + feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))) +)] +extern "C" { + pub fn _Exit(code: c_int) -> !; + pub fn _exit(code: c_int) -> !; + pub fn abort() -> !; + pub fn aligned_alloc(a: size_t, b: size_t) -> *mut c_void; + pub fn calloc(amt: size_t, amt2: size_t) -> *mut c_void; + pub fn exit(code: c_int) -> !; + pub fn free(ptr: *mut c_void); + pub fn getenv(s: *const c_char) -> *mut c_char; + pub fn malloc(amt: size_t) -> *mut c_void; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + pub fn sbrk(increment: intptr_t) -> *mut c_void; + pub fn rand() -> c_int; + pub fn read(fd: c_int, ptr: *mut c_void, size: size_t) -> ssize_t; + pub fn realloc(ptr: *mut c_void, amt: size_t) -> *mut c_void; + pub fn setenv(k: *const c_char, v: *const c_char, a: c_int) -> c_int; + pub fn unsetenv(k: *const c_char) -> c_int; + pub fn clearenv() -> c_int; + pub fn write(fd: c_int, ptr: *const c_void, size: size_t) -> ssize_t; + pub static mut environ: *mut *mut c_char; + pub fn fopen(a: *const c_char, b: *const c_char) -> *mut FILE; + pub fn freopen(a: *const c_char, b: *const c_char, f: *mut FILE) -> *mut FILE; + pub fn fclose(f: *mut FILE) -> c_int; + pub fn remove(a: *const c_char) -> c_int; + pub fn rename(a: *const c_char, b: *const c_char) -> c_int; + pub fn feof(f: *mut FILE) -> c_int; + pub fn ferror(f: *mut FILE) -> c_int; + pub fn fflush(f: *mut FILE) -> c_int; + pub fn clearerr(f: *mut FILE); + pub fn fseek(f: *mut FILE, b: c_long, c: c_int) -> c_int; + pub fn ftell(f: *mut FILE) -> c_long; + pub fn rewind(f: *mut FILE); + pub fn fgetpos(f: *mut FILE, pos: *mut fpos_t) -> c_int; + pub fn fsetpos(f: *mut FILE, pos: *const fpos_t) -> c_int; + pub fn fread(buf: *mut c_void, a: size_t, b: size_t, f: *mut FILE) -> size_t; + pub fn fwrite(buf: *const c_void, a: size_t, b: size_t, f: *mut FILE) -> size_t; + pub fn fgetc(f: *mut FILE) -> c_int; + pub fn getc(f: *mut FILE) -> c_int; + pub fn getchar() -> c_int; + pub fn ungetc(a: c_int, f: *mut FILE) -> c_int; + pub fn fputc(a: c_int, f: *mut FILE) -> c_int; + pub fn putc(a: c_int, f: *mut FILE) -> c_int; + pub fn putchar(a: c_int) -> c_int; + pub fn fputs(a: *const c_char, f: *mut FILE) -> c_int; + pub fn puts(a: *const c_char) -> c_int; + pub fn perror(a: *const c_char); + pub fn srand(a: c_uint); + pub fn atexit(a: extern "C" fn()) -> c_int; + pub fn at_quick_exit(a: extern "C" fn()) -> c_int; + pub fn quick_exit(a: c_int) -> !; + pub fn posix_memalign(a: *mut *mut c_void, b: size_t, c: size_t) -> c_int; + pub fn rand_r(a: *mut c_uint) -> c_int; + pub fn random() -> c_long; + pub fn srandom(a: c_uint); + pub fn putenv(a: *mut c_char) -> c_int; + pub fn clock() -> clock_t; + pub fn time(a: *mut time_t) -> time_t; + pub fn difftime(a: time_t, b: time_t) -> c_double; + pub fn mktime(a: *mut tm) -> time_t; + pub fn strftime(a: *mut c_char, b: size_t, c: *const c_char, d: *const tm) -> size_t; + pub fn gmtime(a: *const time_t) -> *mut tm; + pub fn gmtime_r(a: *const time_t, b: *mut tm) -> *mut tm; + pub fn localtime(a: *const time_t) -> *mut tm; + pub fn localtime_r(a: *const time_t, b: *mut tm) -> *mut tm; + pub fn asctime_r(a: *const tm, b: *mut c_char) -> *mut c_char; + pub fn ctime_r(a: *const time_t, b: *mut c_char) -> *mut c_char; + + static _CLOCK_MONOTONIC: u8; + static _CLOCK_REALTIME: u8; + pub fn nanosleep(a: *const timespec, b: *mut timespec) -> c_int; + pub fn clock_getres(a: clockid_t, b: *mut timespec) -> c_int; + pub fn clock_gettime(a: clockid_t, b: *mut timespec) -> c_int; + pub fn clock_nanosleep(a: clockid_t, a2: c_int, b: *const timespec, c: *mut timespec) -> c_int; + + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn atof(s: *const c_char) -> c_double; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atol(s: *const c_char) -> c_long; + pub fn atoll(s: *const c_char) -> c_longlong; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtof(s: *const c_char, endp: *mut *mut c_char) -> c_float; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoll(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoull(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulonglong; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strndup(cs: *const c_char, n: size_t) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn fprintf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn snprintf(s: *mut c_char, n: size_t, format: *const c_char, ...) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + pub fn fscanf(stream: *mut crate::FILE, format: *const c_char, ...) -> c_int; + pub fn scanf(format: *const c_char, ...) -> c_int; + pub fn sscanf(s: *const c_char, format: *const c_char, ...) -> c_int; + pub fn getchar_unlocked() -> c_int; + pub fn putchar_unlocked(c: c_int) -> c_int; + + pub fn shutdown(socket: c_int, how: c_int) -> c_int; + pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; + pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; + pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; + pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut crate::FILE; + pub fn fileno(stream: *mut crate::FILE) -> c_int; + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + pub fn creat(path: *const c_char, mode: mode_t) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; + pub fn opendir(dirname: *const c_char) -> *mut crate::DIR; + pub fn fdopendir(fd: c_int) -> *mut crate::DIR; + pub fn readdir(dirp: *mut crate::DIR) -> *mut crate::dirent; + pub fn closedir(dirp: *mut crate::DIR) -> c_int; + pub fn rewinddir(dirp: *mut crate::DIR); + pub fn dirfd(dirp: *mut crate::DIR) -> c_int; + pub fn seekdir(dirp: *mut crate::DIR, loc: c_long); + pub fn telldir(dirp: *mut crate::DIR) -> c_long; + + pub fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int, ...) -> c_int; + pub fn fstatat(dirfd: c_int, pathname: *const c_char, buf: *mut stat, flags: c_int) -> c_int; + pub fn linkat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + pub fn mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int; + pub fn readlinkat( + dirfd: c_int, + pathname: *const c_char, + buf: *mut c_char, + bufsiz: size_t, + ) -> ssize_t; + pub fn renameat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + ) -> c_int; + pub fn symlinkat(target: *const c_char, newdirfd: c_int, linkpath: *const c_char) -> c_int; + pub fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int; + + pub fn access(path: *const c_char, amode: c_int) -> c_int; + pub fn close(fd: c_int) -> c_int; + pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; + pub fn getopt(argc: c_int, argv: *const *mut c_char, optstr: *const c_char) -> c_int; + pub fn isatty(fd: c_int) -> c_int; + pub fn link(src: *const c_char, dst: *const c_char) -> c_int; + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: c_int) -> c_long; + pub fn rmdir(path: *const c_char) -> c_int; + pub fn sleep(secs: c_uint) -> c_uint; + pub fn unlink(c: *const c_char) -> c_int; + pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_t) -> ssize_t; + + pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; + + pub fn fsync(fd: c_int) -> c_int; + pub fn fdatasync(fd: c_int) -> c_int; + + pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int; + + pub fn truncate(path: *const c_char, length: off_t) -> c_int; + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + + pub fn getrusage(resource: c_int, usage: *mut rusage) -> c_int; + + pub fn gettimeofday(tp: *mut crate::timeval, tz: *mut c_void) -> c_int; + pub fn times(buf: *mut crate::tms) -> crate::clock_t; + + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; + + pub fn usleep(secs: c_uint) -> c_int; + pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int; + pub fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char; + pub fn localeconv() -> *mut lconv; + + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> ssize_t; + + pub fn timegm(tm: *mut crate::tm) -> time_t; + + pub fn sysconf(name: c_int) -> c_long; + + pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; + + pub fn fseeko(stream: *mut crate::FILE, offset: off_t, whence: c_int) -> c_int; + pub fn ftello(stream: *mut crate::FILE) -> off_t; + pub fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int; + + pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn getline(lineptr: *mut *mut c_char, n: *mut size_t, stream: *mut FILE) -> ssize_t; + + pub fn faccessat(dirfd: c_int, pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn writev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn readv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int) -> ssize_t; + pub fn pwritev(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn preadv(fd: c_int, iov: *const crate::iovec, iovcnt: c_int, offset: off_t) -> ssize_t; + pub fn posix_fadvise(fd: c_int, offset: off_t, len: off_t, advise: c_int) -> c_int; + pub fn futimens(fd: c_int, times: *const crate::timespec) -> c_int; + pub fn utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flag: c_int, + ) -> c_int; + pub fn getentropy(buf: *mut c_void, buflen: size_t) -> c_int; + pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn duplocale(base: crate::locale_t) -> crate::locale_t; + pub fn freelocale(loc: crate::locale_t); + pub fn newlocale(mask: c_int, locale: *const c_char, base: crate::locale_t) -> crate::locale_t; + pub fn uselocale(loc: crate::locale_t) -> crate::locale_t; + pub fn sched_yield() -> c_int; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + pub fn chdir(dir: *const c_char) -> c_int; + + pub fn nl_langinfo(item: crate::nl_item) -> *mut c_char; + pub fn nl_langinfo_l(item: crate::nl_item, loc: crate::locale_t) -> *mut c_char; + + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timeval, + ) -> c_int; + + #[cfg(target_env = "p1")] + pub fn __wasilibc_register_preopened_fd(fd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_fd_renumber(fd: c_int, newfd: c_int) -> c_int; + pub fn __wasilibc_unlinkat(fd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_rmdirat(fd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_find_relpath( + path: *const c_char, + abs_prefix: *mut *const c_char, + relative_path: *mut *mut c_char, + relative_path_len: usize, + ) -> c_int; + pub fn __wasilibc_tell(fd: c_int) -> off_t; + pub fn __wasilibc_nocwd___wasilibc_unlinkat(dirfd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_nocwd___wasilibc_rmdirat(dirfd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_nocwd_linkat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_nocwd_symlinkat( + target: *const c_char, + dirfd: c_int, + path: *const c_char, + ) -> c_int; + pub fn __wasilibc_nocwd_readlinkat( + dirfd: c_int, + path: *const c_char, + buf: *mut c_char, + bufsize: usize, + ) -> isize; + pub fn __wasilibc_nocwd_faccessat( + dirfd: c_int, + path: *const c_char, + mode: c_int, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_nocwd_renameat( + olddirfd: c_int, + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + ) -> c_int; + pub fn __wasilibc_nocwd_openat_nomode(dirfd: c_int, path: *const c_char, flags: c_int) + -> c_int; + pub fn __wasilibc_nocwd_fstatat( + dirfd: c_int, + path: *const c_char, + buf: *mut stat, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_nocwd_mkdirat_nomode(dirfd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_nocwd_utimensat( + dirfd: c_int, + path: *const c_char, + times: *const crate::timespec, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_nocwd_opendirat(dirfd: c_int, path: *const c_char) -> *mut crate::DIR; + pub fn __wasilibc_access(pathname: *const c_char, mode: c_int, flags: c_int) -> c_int; + pub fn __wasilibc_stat(pathname: *const c_char, buf: *mut stat, flags: c_int) -> c_int; + pub fn __wasilibc_utimens( + pathname: *const c_char, + times: *const crate::timespec, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_link(oldpath: *const c_char, newpath: *const c_char, flags: c_int) -> c_int; + pub fn __wasilibc_link_oldat( + olddirfd: c_int, + oldpath: *const c_char, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_link_newat( + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + flags: c_int, + ) -> c_int; + pub fn __wasilibc_rename_oldat( + olddirfd: c_int, + oldpath: *const c_char, + newpath: *const c_char, + ) -> c_int; + pub fn __wasilibc_rename_newat( + oldpath: *const c_char, + newdirfd: c_int, + newpath: *const c_char, + ) -> c_int; + + pub fn arc4random() -> u32; + pub fn arc4random_buf(a: *mut c_void, b: size_t); + pub fn arc4random_uniform(a: u32) -> u32; + + pub fn __errno_location() -> *mut c_int; + + pub fn chmod(path: *const c_char, mode: mode_t) -> c_int; + pub fn fchmod(fd: c_int, mode: mode_t) -> c_int; + pub fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char; + + pub fn pthread_self() -> pthread_t; + pub fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, + ) -> c_int; + pub fn pthread_equal(t1: pthread_t, t2: pthread_t) -> c_int; + pub fn pthread_join(native: pthread_t, value: *mut *mut c_void) -> c_int; + pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_attr_getstacksize(attr: *const pthread_attr_t, stacksize: *mut size_t) -> c_int; + pub fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stack_size: size_t) -> c_int; + pub fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, state: c_int) -> c_int; + pub fn pthread_detach(thread: pthread_t) -> c_int; + + pub fn pthread_key_create( + key: *mut pthread_key_t, + dtor: Option, + ) -> c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int; + pub fn pthread_mutex_init( + lock: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t, + ) -> c_int; + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> c_int; + + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: c_int) -> c_int; + + pub fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int; + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, lock: *mut pthread_mutex_t) -> c_int; + pub fn pthread_cond_timedwait( + cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const timespec, + ) -> c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int; + pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int; + pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int; + + pub fn pthread_rwlock_init( + lock: *mut pthread_rwlock_t, + attr: *const pthread_rwlockattr_t, + ) -> c_int; + pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) -> c_int; +} + +cfg_if! { + if #[cfg(not(target_env = "p1"))] { + mod p2; + pub use self::p2::*; + } +} diff --git a/deps/crates/vendor/libc/src/wasi/p2.rs b/deps/crates/vendor/libc/src/wasi/p2.rs new file mode 100644 index 00000000000000..7332a779396d37 --- /dev/null +++ b/deps/crates/vendor/libc/src/wasi/p2.rs @@ -0,0 +1,188 @@ +use crate::prelude::*; + +pub type sa_family_t = c_ushort; +pub type in_port_t = c_ushort; +pub type in_addr_t = c_uint; + +pub type socklen_t = c_uint; + +s! { + #[repr(align(16))] + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 0], + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + #[repr(align(16))] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + } + + #[repr(align(4))] + pub struct in6_addr { + pub s6_addr: [c_uchar; 16], + } + + #[repr(align(16))] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: c_uint, + pub sin6_addr: in6_addr, + pub sin6_scope_id: c_uint, + } + + #[repr(align(16))] + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + pub __ss_data: [c_char; 32], + } + + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } +} + +pub const SHUT_RD: c_int = 1 << 0; +pub const SHUT_WR: c_int = 1 << 1; +pub const SHUT_RDWR: c_int = SHUT_RD | SHUT_WR; + +pub const MSG_NOSIGNAL: c_int = 0x4000; +pub const MSG_PEEK: c_int = 0x0002; + +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_LINGER: c_int = 13; +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; +pub const SO_RCVTIMEO: c_int = 66; +pub const SO_SNDTIMEO: c_int = 67; + +pub const SOCK_DGRAM: c_int = 5; +pub const SOCK_STREAM: c_int = 6; +pub const SOCK_NONBLOCK: c_int = 0x00004000; + +pub const SOL_SOCKET: c_int = 0x7fffffff; + +pub const AF_UNSPEC: c_int = 0; +pub const AF_INET: c_int = 1; +pub const AF_INET6: c_int = 2; + +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_UDP: c_int = 17; +pub const IPPROTO_IPV6: c_int = 41; + +pub const IP_TTL: c_int = 2; +pub const IP_MULTICAST_TTL: c_int = 33; +pub const IP_MULTICAST_LOOP: c_int = 34; +pub const IP_ADD_MEMBERSHIP: c_int = 35; +pub const IP_DROP_MEMBERSHIP: c_int = 36; + +pub const IPV6_UNICAST_HOPS: c_int = 16; +pub const IPV6_MULTICAST_LOOP: c_int = 19; +pub const IPV6_JOIN_GROUP: c_int = 20; +pub const IPV6_LEAVE_GROUP: c_int = 21; +pub const IPV6_V6ONLY: c_int = 26; + +pub const IPV6_ADD_MEMBERSHIP: c_int = IPV6_JOIN_GROUP; +pub const IPV6_DROP_MEMBERSHIP: c_int = IPV6_LEAVE_GROUP; + +pub const TCP_NODELAY: c_int = 1; +pub const TCP_KEEPIDLE: c_int = 4; +pub const TCP_KEEPINTVL: c_int = 5; +pub const TCP_KEEPCNT: c_int = 6; + +pub const EAI_SYSTEM: c_int = -11; + +extern "C" { + pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int; + pub fn connect(fd: c_int, name: *const sockaddr, addrlen: socklen_t) -> c_int; + pub fn bind(socket: c_int, addr: *const sockaddr, addrlen: socklen_t) -> c_int; + pub fn listen(socket: c_int, backlog: c_int) -> c_int; + pub fn accept(socket: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + pub fn accept4( + socket: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t, + flags: c_int, + ) -> c_int; + + pub fn getsockname(socket: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + pub fn getpeername(socket: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + + pub fn sendto( + socket: c_int, + buffer: *const c_void, + length: size_t, + flags: c_int, + addr: *const sockaddr, + addrlen: socklen_t, + ) -> ssize_t; + pub fn recvfrom( + socket: c_int, + buffer: *mut c_void, + length: size_t, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t, + ) -> ssize_t; + + pub fn getsockopt( + sockfd: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut socklen_t, + ) -> c_int; + pub fn setsockopt( + sockfd: c_int, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: socklen_t, + ) -> c_int; + + pub fn getaddrinfo( + host: *const c_char, + serv: *const c_char, + hint: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + pub fn freeaddrinfo(p: *mut addrinfo); + pub fn gai_strerror(ecode: c_int) -> *const c_char; +} diff --git a/deps/crates/vendor/libc/src/windows/gnu/mod.rs b/deps/crates/vendor/libc/src/windows/gnu/mod.rs new file mode 100644 index 00000000000000..6dfa85231b4429 --- /dev/null +++ b/deps/crates/vendor/libc/src/windows/gnu/mod.rs @@ -0,0 +1,35 @@ +use crate::prelude::*; + +// The below configuration for machines with 32-bit word size aligns with the +// declaration in the `mingw-w64` headers. +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + s_no_extra_traits! { + #[repr(align(16))] + pub struct max_align_t { + priv_: [f64; 4], + } + } + } else if #[cfg(target_pointer_width = "32")] { + s_no_extra_traits! { + #[repr(align(8))] + pub struct max_align_t { + priv_: [i64; 3], + } + } + } +} + +// stdio file descriptor numbers +pub const STDIN_FILENO: c_int = 0; +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; + +extern "C" { + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + + // NOTE: For MSVC target, `wmemchr` is only a inline function in `` + // header file. We cannot find a way to link to that symbol from Rust. + pub fn wmemchr(cx: *const crate::wchar_t, c: crate::wchar_t, n: size_t) -> *mut crate::wchar_t; +} diff --git a/deps/crates/vendor/libc/src/windows/mod.rs b/deps/crates/vendor/libc/src/windows/mod.rs new file mode 100644 index 00000000000000..612c0ee11c4f36 --- /dev/null +++ b/deps/crates/vendor/libc/src/windows/mod.rs @@ -0,0 +1,612 @@ +//! Windows CRT definitions + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; +pub type sighandler_t = usize; + +pub type wchar_t = u16; + +pub type clock_t = i32; + +pub type errno_t = c_int; + +cfg_if! { + if #[cfg(all(target_arch = "x86", target_env = "gnu"))] { + pub type time_t = i32; + } else { + pub type time_t = i64; + } +} + +pub type off_t = i32; +pub type dev_t = u32; +pub type ino_t = u16; + +extern_ty! { + pub enum timezone {} +} + +pub type time64_t = i64; + +pub type SOCKET = crate::uintptr_t; + +s! { + // note this is the struct called stat64 in Windows. Not stat, nor stati64. + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: u16, + pub st_nlink: c_short, + pub st_uid: c_short, + pub st_gid: c_short, + pub st_rdev: dev_t, + pub st_size: i64, + pub st_atime: time64_t, + pub st_mtime: time64_t, + pub st_ctime: time64_t, + } + + // note that this is called utimbuf64 in Windows + pub struct utimbuf { + pub actime: time64_t, + pub modtime: time64_t, + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + } + + #[derive(Default)] + pub struct timeval { + pub tv_sec: c_long, + pub tv_usec: c_long, + } + + #[derive(Default)] + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + pub struct sockaddr { + pub sa_family: c_ushort, + pub sa_data: [c_char; 14], + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const EXIT_FAILURE: c_int = 1; +pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 32767; +pub const EOF: c_int = -1; +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 4; +pub const _IOLBF: c_int = 64; +pub const BUFSIZ: c_uint = 512; +pub const FOPEN_MAX: c_uint = 20; +pub const FILENAME_MAX: c_uint = 260; + +// fcntl.h +pub const O_RDONLY: c_int = 0x0000; +pub const O_WRONLY: c_int = 0x0001; +pub const O_RDWR: c_int = 0x0002; +pub const O_APPEND: c_int = 0x0008; +pub const O_CREAT: c_int = 0x0100; +pub const O_TRUNC: c_int = 0x0200; +pub const O_EXCL: c_int = 0x0400; +pub const O_TEXT: c_int = 0x4000; +pub const O_BINARY: c_int = 0x8000; +pub const _O_WTEXT: c_int = 0x10000; +pub const _O_U16TEXT: c_int = 0x20000; +pub const _O_U8TEXT: c_int = 0x40000; +pub const O_RAW: c_int = O_BINARY; +pub const O_NOINHERIT: c_int = 0x0080; +pub const O_TEMPORARY: c_int = 0x0040; +pub const _O_SHORT_LIVED: c_int = 0x1000; +pub const _O_OBTAIN_DIR: c_int = 0x2000; +pub const O_SEQUENTIAL: c_int = 0x0020; +pub const O_RANDOM: c_int = 0x0010; + +pub const S_IFCHR: c_int = 0o2_0000; +pub const S_IFDIR: c_int = 0o4_0000; +pub const S_IFREG: c_int = 0o10_0000; +pub const S_IFMT: c_int = 0o17_0000; +pub const S_IEXEC: c_int = 0o0100; +pub const S_IWRITE: c_int = 0o0200; +pub const S_IREAD: c_int = 0o0400; + +pub const LC_ALL: c_int = 0; +pub const LC_COLLATE: c_int = 1; +pub const LC_CTYPE: c_int = 2; +pub const LC_MONETARY: c_int = 3; +pub const LC_NUMERIC: c_int = 4; +pub const LC_TIME: c_int = 5; + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const EDEADLK: c_int = 36; +pub const EDEADLOCK: c_int = 36; +pub const ENAMETOOLONG: c_int = 38; +pub const ENOLCK: c_int = 39; +pub const ENOSYS: c_int = 40; +pub const ENOTEMPTY: c_int = 41; +pub const EILSEQ: c_int = 42; +pub const STRUNCATE: c_int = 80; + +// POSIX Supplement (from errno.h) +pub const EADDRINUSE: c_int = 100; +pub const EADDRNOTAVAIL: c_int = 101; +pub const EAFNOSUPPORT: c_int = 102; +pub const EALREADY: c_int = 103; +pub const EBADMSG: c_int = 104; +pub const ECANCELED: c_int = 105; +pub const ECONNABORTED: c_int = 106; +pub const ECONNREFUSED: c_int = 107; +pub const ECONNRESET: c_int = 108; +pub const EDESTADDRREQ: c_int = 109; +pub const EHOSTUNREACH: c_int = 110; +pub const EIDRM: c_int = 111; +pub const EINPROGRESS: c_int = 112; +pub const EISCONN: c_int = 113; +pub const ELOOP: c_int = 114; +pub const EMSGSIZE: c_int = 115; +pub const ENETDOWN: c_int = 116; +pub const ENETRESET: c_int = 117; +pub const ENETUNREACH: c_int = 118; +pub const ENOBUFS: c_int = 119; +pub const ENODATA: c_int = 120; +pub const ENOLINK: c_int = 121; +pub const ENOMSG: c_int = 122; +pub const ENOPROTOOPT: c_int = 123; +pub const ENOSR: c_int = 124; +pub const ENOSTR: c_int = 125; +pub const ENOTCONN: c_int = 126; +pub const ENOTRECOVERABLE: c_int = 127; +pub const ENOTSOCK: c_int = 128; +pub const ENOTSUP: c_int = 129; +pub const EOPNOTSUPP: c_int = 130; +pub const EOVERFLOW: c_int = 132; +pub const EOWNERDEAD: c_int = 133; +pub const EPROTO: c_int = 134; +pub const EPROTONOSUPPORT: c_int = 135; +pub const EPROTOTYPE: c_int = 136; +pub const ETIME: c_int = 137; +pub const ETIMEDOUT: c_int = 138; +pub const ETXTBSY: c_int = 139; +pub const EWOULDBLOCK: c_int = 140; + +// signal codes +pub const SIGINT: c_int = 2; +pub const SIGILL: c_int = 4; +pub const SIGFPE: c_int = 8; +pub const SIGSEGV: c_int = 11; +pub const SIGTERM: c_int = 15; +pub const SIGABRT: c_int = 22; +pub const NSIG: c_int = 23; + +pub const SIG_ERR: c_int = -1; +pub const SIG_DFL: crate::sighandler_t = 0; +pub const SIG_IGN: crate::sighandler_t = 1; +pub const SIG_GET: crate::sighandler_t = 2; +pub const SIG_SGE: crate::sighandler_t = 3; +pub const SIG_ACK: crate::sighandler_t = 4; + +pub const L_tmpnam: c_uint = 260; +pub const TMP_MAX: c_uint = 0x7fff_ffff; + +// DIFF(main): removed in 458c58f409 +// FIXME(msrv): done by `std` starting in 1.79.0 +// inline comment below appeases style checker +#[cfg(all(target_env = "msvc", feature = "rustc-dep-of-std"))] // " if " +#[link(name = "msvcrt", cfg(not(target_feature = "crt-static")))] +#[link(name = "libcmt", cfg(target_feature = "crt-static"))] +extern "C" {} + +extern_ty! { + pub enum FILE {} + pub enum fpos_t {} // FIXME(windows): fill this out with a struct +} + +// Special handling for all print and scan type functions because of https://github.com/rust-lang/libc/issues/2860 +cfg_if! { + if #[cfg(not(feature = "rustc-dep-of-std"))] { + #[cfg_attr( + all(windows, target_env = "msvc"), + link(name = "legacy_stdio_definitions") + )] + extern "C" { + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn fprintf(stream: *mut FILE, format: *const c_char, ...) -> c_int; + pub fn snprintf( + buffer: *mut c_char, + count: size_t, + format: *const c_char, + ... + ) -> c_int; + pub fn sprintf(buffer: *mut c_char, format: *const c_char, ...) -> c_int; + + pub fn scanf(format: *const c_char, ...) -> c_int; + pub fn sscanf(buffer: *const c_char, format: *const c_char, ...) -> c_int; + pub fn fscanf(stream: *mut FILE, format: *const c_char, ...) -> c_int; + } + } +} + +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn qsort( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + ); + pub fn qsort_s( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option c_int>, + arg: *mut c_void, + ); + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atof(s: *const c_char) -> c_double; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atol(s: *const c_char) -> c_long; + pub fn atoll(s: *const c_char) -> c_longlong; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtof(s: *const c_char, endp: *mut *mut c_char) -> c_float; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoll(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_longlong; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; + pub fn strtoull(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulonglong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn _msize(p: *mut c_void) -> size_t; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern "C" fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcsnlen(str: *const wchar_t, numberOfElements: size_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; + pub fn raise(signum: c_int) -> c_int; + + pub fn clock() -> clock_t; + pub fn ctime(sourceTime: *const time_t) -> *mut c_char; + pub fn difftime(timeEnd: time_t, timeStart: time_t) -> c_double; + #[link_name = "_gmtime64_s"] + pub fn gmtime_s(destTime: *mut tm, srcTime: *const time_t) -> c_int; + #[link_name = "_get_daylight"] + pub fn get_daylight(hours: *mut c_int) -> errno_t; + #[link_name = "_get_dstbias"] + pub fn get_dstbias(seconds: *mut c_long) -> errno_t; + #[link_name = "_get_timezone"] + pub fn get_timezone(seconds: *mut c_long) -> errno_t; + #[link_name = "_get_tzname"] + pub fn get_tzname( + p_return_value: *mut size_t, + time_zone_name: *mut c_char, + size_in_bytes: size_t, + index: c_int, + ) -> errno_t; + #[link_name = "_localtime64_s"] + pub fn localtime_s(tmDest: *mut tm, sourceTime: *const time_t) -> crate::errno_t; + #[link_name = "_time64"] + pub fn time(destTime: *mut time_t) -> time_t; + #[link_name = "_tzset"] + pub fn tzset(); + #[link_name = "_chmod"] + pub fn chmod(path: *const c_char, mode: c_int) -> c_int; + #[link_name = "_wchmod"] + pub fn wchmod(path: *const wchar_t, mode: c_int) -> c_int; + #[link_name = "_mkdir"] + pub fn mkdir(path: *const c_char) -> c_int; + #[link_name = "_wrmdir"] + pub fn wrmdir(path: *const wchar_t) -> c_int; + #[link_name = "_fstat64"] + pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; + #[link_name = "_stat64"] + pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; + #[link_name = "_wstat64"] + pub fn wstat(path: *const wchar_t, buf: *mut stat) -> c_int; + #[link_name = "_wutime64"] + pub fn wutime(file: *const wchar_t, buf: *mut utimbuf) -> c_int; + #[link_name = "_popen"] + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE; + #[link_name = "_pclose"] + pub fn pclose(stream: *mut crate::FILE) -> c_int; + #[link_name = "_fdopen"] + pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut crate::FILE; + #[link_name = "_fileno"] + pub fn fileno(stream: *mut crate::FILE) -> c_int; + #[link_name = "_open"] + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + #[link_name = "_wopen"] + pub fn wopen(path: *const wchar_t, oflag: c_int, ...) -> c_int; + #[link_name = "_creat"] + pub fn creat(path: *const c_char, mode: c_int) -> c_int; + #[link_name = "_access"] + pub fn access(path: *const c_char, amode: c_int) -> c_int; + #[link_name = "_chdir"] + pub fn chdir(dir: *const c_char) -> c_int; + #[link_name = "_close"] + pub fn close(fd: c_int) -> c_int; + #[link_name = "_dup"] + pub fn dup(fd: c_int) -> c_int; + #[link_name = "_dup2"] + pub fn dup2(src: c_int, dst: c_int) -> c_int; + #[link_name = "_execl"] + pub fn execl(path: *const c_char, arg0: *const c_char, ...) -> intptr_t; + #[link_name = "_wexecl"] + pub fn wexecl(path: *const wchar_t, arg0: *const wchar_t, ...) -> intptr_t; + #[link_name = "_execle"] + pub fn execle(path: *const c_char, arg0: *const c_char, ...) -> intptr_t; + #[link_name = "_wexecle"] + pub fn wexecle(path: *const wchar_t, arg0: *const wchar_t, ...) -> intptr_t; + #[link_name = "_execlp"] + pub fn execlp(path: *const c_char, arg0: *const c_char, ...) -> intptr_t; + #[link_name = "_wexeclp"] + pub fn wexeclp(path: *const wchar_t, arg0: *const wchar_t, ...) -> intptr_t; + #[link_name = "_execlpe"] + pub fn execlpe(path: *const c_char, arg0: *const c_char, ...) -> intptr_t; + #[link_name = "_wexeclpe"] + pub fn wexeclpe(path: *const wchar_t, arg0: *const wchar_t, ...) -> intptr_t; + #[link_name = "_execv"] + // DIFF(main): changed to `intptr_t` in e77f551de9 + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> intptr_t; + #[link_name = "_execve"] + pub fn execve( + prog: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + #[link_name = "_execvp"] + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; + #[link_name = "_execvpe"] + pub fn execvpe( + c: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, + ) -> c_int; + + #[link_name = "_wexecv"] + pub fn wexecv(prog: *const wchar_t, argv: *const *const wchar_t) -> intptr_t; + #[link_name = "_wexecve"] + pub fn wexecve( + prog: *const wchar_t, + argv: *const *const wchar_t, + envp: *const *const wchar_t, + ) -> intptr_t; + #[link_name = "_wexecvp"] + pub fn wexecvp(c: *const wchar_t, argv: *const *const wchar_t) -> intptr_t; + #[link_name = "_wexecvpe"] + pub fn wexecvpe( + c: *const wchar_t, + argv: *const *const wchar_t, + envp: *const *const wchar_t, + ) -> intptr_t; + #[link_name = "_getcwd"] + pub fn getcwd(buf: *mut c_char, size: c_int) -> *mut c_char; + #[link_name = "_getpid"] + pub fn getpid() -> c_int; + #[link_name = "_isatty"] + pub fn isatty(fd: c_int) -> c_int; + #[link_name = "_lseek"] + pub fn lseek(fd: c_int, offset: c_long, origin: c_int) -> c_long; + #[link_name = "_lseeki64"] + pub fn lseek64(fd: c_int, offset: c_longlong, origin: c_int) -> c_longlong; + #[link_name = "_pipe"] + pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int) -> c_int; + #[link_name = "_read"] + pub fn read(fd: c_int, buf: *mut c_void, count: c_uint) -> c_int; + #[link_name = "_rmdir"] + pub fn rmdir(path: *const c_char) -> c_int; + #[link_name = "_unlink"] + pub fn unlink(c: *const c_char) -> c_int; + #[link_name = "_write"] + pub fn write(fd: c_int, buf: *const c_void, count: c_uint) -> c_int; + #[link_name = "_commit"] + pub fn commit(fd: c_int) -> c_int; + #[link_name = "_get_osfhandle"] + pub fn get_osfhandle(fd: c_int) -> intptr_t; + #[link_name = "_open_osfhandle"] + pub fn open_osfhandle(osfhandle: intptr_t, flags: c_int) -> c_int; + pub fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char; + #[link_name = "_wsetlocale"] + pub fn wsetlocale(category: c_int, locale: *const wchar_t) -> *mut wchar_t; + #[link_name = "_aligned_malloc"] + pub fn aligned_malloc(size: size_t, alignment: size_t) -> *mut c_void; + #[link_name = "_aligned_free"] + pub fn aligned_free(ptr: *mut c_void); + #[link_name = "_aligned_realloc"] + pub fn aligned_realloc(memblock: *mut c_void, size: size_t, alignment: size_t) -> *mut c_void; + #[link_name = "_putenv"] + pub fn putenv(envstring: *const c_char) -> c_int; + #[link_name = "_wputenv"] + pub fn wputenv(envstring: *const crate::wchar_t) -> c_int; + #[link_name = "_putenv_s"] + pub fn putenv_s(envstring: *const c_char, value_string: *const c_char) -> crate::errno_t; + #[link_name = "_wputenv_s"] + pub fn wputenv_s( + envstring: *const crate::wchar_t, + value_string: *const crate::wchar_t, + ) -> crate::errno_t; +} + +extern "system" { + pub fn listen(s: SOCKET, backlog: c_int) -> c_int; + pub fn accept(s: SOCKET, addr: *mut crate::sockaddr, addrlen: *mut c_int) -> SOCKET; + pub fn bind(s: SOCKET, name: *const crate::sockaddr, namelen: c_int) -> c_int; + pub fn connect(s: SOCKET, name: *const crate::sockaddr, namelen: c_int) -> c_int; + pub fn getpeername(s: SOCKET, name: *mut crate::sockaddr, nameln: *mut c_int) -> c_int; + pub fn getsockname(s: SOCKET, name: *mut crate::sockaddr, nameln: *mut c_int) -> c_int; + pub fn getsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: *mut c_int, + ) -> c_int; + pub fn recvfrom( + s: SOCKET, + buf: *mut c_char, + len: c_int, + flags: c_int, + from: *mut crate::sockaddr, + fromlen: *mut c_int, + ) -> c_int; + pub fn sendto( + s: SOCKET, + buf: *const c_char, + len: c_int, + flags: c_int, + to: *const crate::sockaddr, + tolen: c_int, + ) -> c_int; + pub fn setsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_char, + optlen: c_int, + ) -> c_int; + pub fn socket(af: c_int, socket_type: c_int, protocol: c_int) -> SOCKET; +} + +cfg_if! { + if #[cfg(all(target_env = "gnu"))] { + mod gnu; + pub use self::gnu::*; + } else if #[cfg(all(target_env = "msvc"))] { + mod msvc; + pub use self::msvc::*; + } else { + // Unknown target_env + } +} diff --git a/deps/crates/vendor/libc/src/windows/msvc/mod.rs b/deps/crates/vendor/libc/src/windows/msvc/mod.rs new file mode 100644 index 00000000000000..967df8c57f8bd7 --- /dev/null +++ b/deps/crates/vendor/libc/src/windows/msvc/mod.rs @@ -0,0 +1,14 @@ +use crate::prelude::*; + +// POSIX Supplement (from errno.h) +// This particular error code is only currently available in msvc toolchain +pub const EOTHER: c_int = 131; + +extern "C" { + #[link_name = "_stricmp"] + pub fn stricmp(s1: *const c_char, s2: *const c_char) -> c_int; + #[link_name = "_strnicmp"] + pub fn strnicmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int; + #[link_name = "_memccpy"] + pub fn memccpy(dest: *mut c_void, src: *const c_void, c: c_int, count: size_t) -> *mut c_void; +} diff --git a/deps/crates/vendor/libc/src/xous.rs b/deps/crates/vendor/libc/src/xous.rs new file mode 100644 index 00000000000000..2415fd42824e1c --- /dev/null +++ b/deps/crates/vendor/libc/src/xous.rs @@ -0,0 +1,18 @@ +//! Xous C type definitions + +use crate::prelude::*; + +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type off_t = i64; +pub type wchar_t = u32; + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; diff --git a/deps/crates/vendor/libc/tests/const_fn.rs b/deps/crates/vendor/libc/tests/const_fn.rs new file mode 100644 index 00000000000000..d9b41b8073c70d --- /dev/null +++ b/deps/crates/vendor/libc/tests/const_fn.rs @@ -0,0 +1,3 @@ +#[cfg(target_os = "linux")] +const _FOO: libc::c_uint = unsafe { libc::CMSG_SPACE(1) }; +//^ if CMSG_SPACE is not const, this will fail to compile diff --git a/deps/crates/vendor/log/.cargo-checksum.json b/deps/crates/vendor/log/.cargo-checksum.json new file mode 100644 index 00000000000000..ec1f007513d482 --- /dev/null +++ b/deps/crates/vendor/log/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"fe75b2d660e4f5cecfc6e8926b75370a30752399a8d0293a90902fcd3be8caaa",".github/workflows/main.yml":"ec945c9615b558fa1125e012369675daa107997389f25ad70d923898aaf2dd0c","CHANGELOG.md":"a216e6550df9437781c01c09783c59276245b0121d3d39b874675148d412d361","Cargo.lock":"7439a99151c8c47a4df860560ff30531aff5fb80dc7583d3e25652da288b1a38","Cargo.toml":"1471858c37a27ccb84d7274816ead00082c0e4acbbb28acc547a6329e3bdaf22","Cargo.toml.orig":"f9bcbe8c7872abcca77b6a3f8b0346835c17326baa861fa8a0f47b2c9d957ef1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"486c6cf85f99a2a3ea14dbd5fc6d6075fdc047a0dbf2b93682595db0de6a115f","benches/value.rs":"b613ff353d3cf0ef8cb98e4ca461ea929b8ba553fe299f2eb2942d77a5b1b6a0","src/__private_api.rs":"c1b8541fe7b7906a654ad1c23a643c516a3b735de4fbd1d07ca7a7a5754b74ac","src/kv/error.rs":"6dae12424164c33b93915f5e70bd6d99d616c969c8bfb543806721dd9b423981","src/kv/key.rs":"9037de97791fa0fb6def6c44ada324351d10ed0f4db8015c9ac4e90504141b87","src/kv/mod.rs":"a62c4dbfbcf28fc755c3662ea4a1e79268edc15311d5ca97b7f0325cc2dfb43f","src/kv/source.rs":"0f7c3a89c8998fe3805ae35f3e87778bca30a444da9f67964e674028f7864625","src/kv/value.rs":"b6df78e50ca912f2d97fdb1155408b538669e5be237b1f9471f9443c9d01f748","src/lib.rs":"5f47680950577eb5213a99b022f7789c2cf22dc3d6ddacda94a54f8e035c6ca2","src/macros.rs":"34c367a645483e21eee4c7846d0efbf97c29a52156d56536c82cdfe1d226a54d","src/serde.rs":"ead8df70c3ca3fafeed062f7a42d9b6f87bc7826055d71d8c4b77a0a25b57634","tests/integration.rs":"0980b3bd85d36863bc9f355e80bc7cf7987d2599adbc87e8e0082861a08a1097","tests/macros.rs":"a94f3cc181c9ecb30af6b5ca8bd2b4e5accc93689c0eb19051b8479a298dc21b","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"} \ No newline at end of file diff --git a/deps/crates/vendor/log/.cargo_vcs_info.json b/deps/crates/vendor/log/.cargo_vcs_info.json new file mode 100644 index 00000000000000..7cbf9624a16d43 --- /dev/null +++ b/deps/crates/vendor/log/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "b1e2df7bce7a1b685aa9bfd1db0a5cac1f0fc27d" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/log/.github/workflows/main.yml b/deps/crates/vendor/log/.github/workflows/main.yml new file mode 100644 index 00000000000000..249cc08eb3464d --- /dev/null +++ b/deps/crates/vendor/log/.github/workflows/main.yml @@ -0,0 +1,117 @@ +name: CI +on: [push, pull_request] + +# Ensure only read permission is granted +permissions: + contents: read + +jobs: + test: + name: Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - build: stable + os: ubuntu-latest + rust: stable + - build: beta + os: ubuntu-latest + rust: beta + - build: nightly + os: ubuntu-latest + rust: nightly + - build: macos + os: macos-latest + rust: stable + - build: win32 + os: windows-latest + rust: stable-i686-pc-windows-msvc + - build: win64 + os: windows-latest + rust: stable-x86_64-pc-windows-msvc + - build: mingw + os: windows-latest + rust: stable-x86_64-pc-windows-gnu + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - uses: taiki-e/install-action@cargo-hack + - run: cargo hack test --feature-powerset --exclude-features max_level_off,max_level_error,max_level_warn,max_level_info,max_level_debug,max_level_trace,release_max_level_off,release_max_level_error,release_max_level_warn,release_max_level_info,release_max_level_debug,release_max_level_trace + - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml + - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml --release + + check: + name: Check Format and Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - run: cargo fmt -- --check + - run: cargo fmt --manifest-path test_max_level_features/Cargo.toml -- --check + - run: cargo clippy --verbose + - run: cargo clippy --verbose --manifest-path test_max_level_features/Cargo.toml + + doc: + name: Check Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - name: Run rustdoc + env: + RUSTDOCFLAGS: "-D warnings" + run: cargo doc --verbose --features std,kv,kv_std,kv_sval,kv_serde + + features: + name: Feature check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo build --verbose -Z avoid-dev-deps --features kv + - run: cargo build --verbose -Z avoid-dev-deps --features "kv std" + - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_sval" + - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_serde" + - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_std" + - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_sval kv_serde" + + minimalv: + name: Minimal versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo build --verbose -Z minimal-versions --features kv + - run: cargo build --verbose -Z minimal-versions --features "kv std" + - run: cargo build --verbose -Z minimal-versions --features "kv kv_sval" + - run: cargo build --verbose -Z minimal-versions --features "kv kv_serde" + - run: cargo build --verbose -Z minimal-versions --features "kv kv_std" + - run: cargo build --verbose -Z minimal-versions --features "kv kv_sval kv_serde" + + msrv: + name: MSRV + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@1.68.0 + with: + components: clippy + - uses: taiki-e/install-action@cargo-hack + - run: cargo hack test --feature-powerset --exclude-features max_level_off,max_level_error,max_level_warn,max_level_info,max_level_debug,max_level_trace,release_max_level_off,release_max_level_error,release_max_level_warn,release_max_level_info,release_max_level_debug,release_max_level_trace + - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml + - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml --release + + embedded: + name: Embedded + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add thumbv6m-none-eabi riscv32imc-unknown-none-elf + - run: cargo build --verbose --target=thumbv6m-none-eabi + - run: cargo build --verbose --target=riscv32imc-unknown-none-elf diff --git a/deps/crates/vendor/log/CHANGELOG.md b/deps/crates/vendor/log/CHANGELOG.md new file mode 100644 index 00000000000000..ff039887f642ee --- /dev/null +++ b/deps/crates/vendor/log/CHANGELOG.md @@ -0,0 +1,423 @@ +# Change Log + +## [Unreleased] + +## [0.4.29] - 2025-12-02 + +## What's Changed +* perf: reduce llvm-lines of FromStr for `Level` and `LevelFilter` by @dishmaker in https://github.com/rust-lang/log/pull/709 +* Replace serde with serde_core by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/712 + +## New Contributors +* @AldaronLau made their first contribution in https://github.com/rust-lang/log/pull/703 +* @dishmaker made their first contribution in https://github.com/rust-lang/log/pull/709 + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.28...0.4.29 + +## [0.4.28] - 2025-09-02 + +## What's Changed +* ci: drop really old trick and ensure MSRV for all feature combo by @tisonkun in https://github.com/rust-lang/log/pull/676 +* Chore: delete compare_exchange method for AtomicUsize on platforms without atomics by @HaoliangXu in https://github.com/rust-lang/log/pull/690 +* Add `increment_severity()` and `decrement_severity()` methods for `Level` and `LevelFilter` by @nebkor in https://github.com/rust-lang/log/pull/692 + +## New Contributors +* @xixishidibei made their first contribution in https://github.com/rust-lang/log/pull/677 +* @ZylosLumen made their first contribution in https://github.com/rust-lang/log/pull/688 +* @HaoliangXu made their first contribution in https://github.com/rust-lang/log/pull/690 +* @nebkor made their first contribution in https://github.com/rust-lang/log/pull/692 + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.27...0.4.28 + +### Notable Changes +* MSRV is bumped to 1.61.0 in https://github.com/rust-lang/log/pull/676 + +## [0.4.27] - 2025-03-24 + +### What's Changed +* A few minor lint fixes by @nyurik in https://github.com/rust-lang/log/pull/671 +* Enable clippy support for format-like macros by @nyurik in https://github.com/rust-lang/log/pull/665 +* Add an optional logger param by @tisonkun in https://github.com/rust-lang/log/pull/664 +* Pass global logger by value, supplied logger by ref by @KodrAus in https://github.com/rust-lang/log/pull/673 + + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.26...0.4.27 + + +## [0.4.26] - 2025-02-18 + +### What's Changed +* Derive `Clone` for `kv::Value` by @SpriteOvO in https://github.com/rust-lang/log/pull/668 +* Add `spdlog-rs` link to crate doc by @SpriteOvO in https://github.com/rust-lang/log/pull/669 + + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.25...0.4.26 + +## [0.4.25] - 2025-01-14 + +### What's Changed +* Revert loosening of kv cargo features by @KodrAus in https://github.com/rust-lang/log/pull/662 + + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.24...0.4.25 + +## [0.4.24] - 2025-01-11 + +### What's Changed +* Fix up kv feature activation by @KodrAus in https://github.com/rust-lang/log/pull/659 + + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.23...0.4.24 + +## [0.4.23] - 2025-01-10 (yanked) + +### What's Changed +* Fix some typos by @Kleinmarb in https://github.com/rust-lang/log/pull/637 +* Add logforth to implementation by @tisonkun in https://github.com/rust-lang/log/pull/638 +* Add `spdlog-rs` link to README by @SpriteOvO in https://github.com/rust-lang/log/pull/639 +* Add correct lifetime to kv::Value::to_borrowed_str by @stevenroose in https://github.com/rust-lang/log/pull/643 +* docs: Add logforth as an impl by @tisonkun in https://github.com/rust-lang/log/pull/642 +* Add clang_log implementation by @DDAN-17 in https://github.com/rust-lang/log/pull/646 +* Bind lifetimes of &str returned from Key by the lifetime of 'k rather than the lifetime of the Key struct by @gbbosak in https://github.com/rust-lang/log/pull/648 +* Fix up key lifetimes and add method to try get a borrowed key by @KodrAus in https://github.com/rust-lang/log/pull/653 +* Add Ftail implementation by @tjardoo in https://github.com/rust-lang/log/pull/652 + +### New Contributors +* @Kleinmarb made their first contribution in https://github.com/rust-lang/log/pull/637 +* @tisonkun made their first contribution in https://github.com/rust-lang/log/pull/638 +* @SpriteOvO made their first contribution in https://github.com/rust-lang/log/pull/639 +* @stevenroose made their first contribution in https://github.com/rust-lang/log/pull/643 +* @DDAN-17 made their first contribution in https://github.com/rust-lang/log/pull/646 +* @gbbosak made their first contribution in https://github.com/rust-lang/log/pull/648 +* @tjardoo made their first contribution in https://github.com/rust-lang/log/pull/652 + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.22...0.4.23 + +## [0.4.22] - 2024-06-27 + +### What's Changed +* Add some clarifications to the library docs by @KodrAus in https://github.com/rust-lang/log/pull/620 +* Add links to `colog` crate by @chrivers in https://github.com/rust-lang/log/pull/621 +* adding line_number test + updating some testing infrastructure by @DIvkov575 in https://github.com/rust-lang/log/pull/619 +* Clarify the actual set of functions that can race in _racy variants by @KodrAus in https://github.com/rust-lang/log/pull/623 +* Replace deprecated std::sync::atomic::spin_loop_hint() by @Catamantaloedis in https://github.com/rust-lang/log/pull/625 +* Check usage of max_level features by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/627 +* Remove unneeded import by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/628 +* Loosen orderings for logger initialization in https://github.com/rust-lang/log/pull/632. Originally by @pwoolcoc in https://github.com/rust-lang/log/pull/599 +* Use Location::caller() for file and line info in https://github.com/rust-lang/log/pull/633. Originally by @Cassy343 in https://github.com/rust-lang/log/pull/520 + +### New Contributors +* @chrivers made their first contribution in https://github.com/rust-lang/log/pull/621 +* @DIvkov575 made their first contribution in https://github.com/rust-lang/log/pull/619 +* @Catamantaloedis made their first contribution in https://github.com/rust-lang/log/pull/625 + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.21...0.4.22 + +## [0.4.21] - 2024-02-27 + +### What's Changed +* Minor clippy nits by @nyurik in https://github.com/rust-lang/log/pull/578 +* Simplify Display impl by @nyurik in https://github.com/rust-lang/log/pull/579 +* Set all crates to 2021 edition by @nyurik in https://github.com/rust-lang/log/pull/580 +* Various changes based on review by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/583 +* Fix typo in file_static() method doc by @dimo414 in https://github.com/rust-lang/log/pull/590 +* Specialize empty key value pairs by @EFanZh in https://github.com/rust-lang/log/pull/576 +* Fix incorrect lifetime in Value::to_str() by @peterjoel in https://github.com/rust-lang/log/pull/587 +* Remove some API of the key-value feature by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/585 +* Add logcontrol-log and log-reload by @swsnr in https://github.com/rust-lang/log/pull/595 +* Add Serialization section to kv::Value docs by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/593 +* Rename Value::to_str to to_cow_str by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/592 +* Clarify documentation and simplify initialization of `STATIC_MAX_LEVEL` by @ptosi in https://github.com/rust-lang/log/pull/594 +* Update docs to 2021 edition, test by @nyurik in https://github.com/rust-lang/log/pull/577 +* Add "alterable_logger" link to README.md by @brummer-simon in https://github.com/rust-lang/log/pull/589 +* Normalize line ending by @EFanZh in https://github.com/rust-lang/log/pull/602 +* Remove `ok_or` in favor of `Option::ok_or` by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/607 +* Use `Acquire` ordering for initialization check by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/610 +* Get structured logging API ready for stabilization by @KodrAus in https://github.com/rust-lang/log/pull/613 + +### New Contributors +* @nyurik made their first contribution in https://github.com/rust-lang/log/pull/578 +* @dimo414 made their first contribution in https://github.com/rust-lang/log/pull/590 +* @peterjoel made their first contribution in https://github.com/rust-lang/log/pull/587 +* @ptosi made their first contribution in https://github.com/rust-lang/log/pull/594 +* @brummer-simon made their first contribution in https://github.com/rust-lang/log/pull/589 +* @AngelicosPhosphoros made their first contribution in https://github.com/rust-lang/log/pull/607 + +## [0.4.20] - 2023-07-11 + +* Remove rustversion dev-dependency by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/568 +* Remove `local_inner_macros` usage by @EFanZh in https://github.com/rust-lang/log/pull/570 + +## [0.4.19] - 2023-06-10 + +* Use target_has_atomic instead of the old atomic_cas cfg by @GuillaumeGomez in https://github.com/rust-lang/log/pull/555 +* Put MSRV into Cargo.toml by @est31 in https://github.com/rust-lang/log/pull/557 + +## [0.4.18] - 2023-05-28 + +* fix Markdown links (again) by @hellow554 in https://github.com/rust-lang/log/pull/513 +* add cargo doc to workflow by @hellow554 in https://github.com/rust-lang/log/pull/515 +* Apply Clippy lints by @hellow554 in https://github.com/rust-lang/log/pull/516 +* Replace ad-hoc eq_ignore_ascii_case with slice::eq_ignore_ascii_case by @glandium in https://github.com/rust-lang/log/pull/519 +* fix up windows targets by @KodrAus in https://github.com/rust-lang/log/pull/528 +* typo fix by @jiangying000 in https://github.com/rust-lang/log/pull/529 +* Remove dependency on cfg_if by @EriKWDev in https://github.com/rust-lang/log/pull/536 +* GitHub Workflows security hardening by @sashashura in https://github.com/rust-lang/log/pull/538 +* Fix build status badge by @atouchet in https://github.com/rust-lang/log/pull/539 +* Add call_logger to the documentation by @a1ecbr0wn in https://github.com/rust-lang/log/pull/547 +* Use stable internals for key-value API by @KodrAus in https://github.com/rust-lang/log/pull/550 +* Change wording of list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/553 +* Add std-logger to list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/554 +* Add `set_max_level_racy` and gate `set_max_level` by @djkoloski in https://github.com/rust-lang/log/pull/544 +* [doc] src/lib.rs : prefix an unused variable with an underscore by @OccupyMars2025 in https://github.com/rust-lang/log/pull/561 +* [doc] src/macros.rs : correct grammar errors of an example in lib documentation by @OccupyMars2025 in https://github.com/rust-lang/log/pull/562 + +## [0.4.17] - 2022-04-29 + +* Update `kv_unstable` internal dependencies. + +## [0.4.16] - 2022-03-22 + +* Fix a conflict with unqualified `Option` use in macros. + +## [0.4.15] - 2022-02-23 + +* Silence a warning about the deprecated `spin_loop_hint`. +* Relax ordering in the atomic `set_max_level` call. +* Add thumbv4t-none-eabi to targets that don't support atomics +* Allow levels to be iterated over. +* Implement `Log` on some common wrapper types. +* Improvements to test coverage. +* Improvements to documentation. +* Add key-value support to the `log!` macros. +* Tighten `kv_unstable` internal dependencies, so they don't bump past their current alpha. +* Add a simple visit API to `kv_unstable`. +* Support `NonZero*` integers as values in structured logging +* Support static strings as keys in structured logging + +## [0.4.14] - 2021-01-27 + +* Remove the `__private_api_log_lit` special case. +* Fixed incorrect combination of `kv_unstable` and `std` features causing compile failures. +* Remove unstable `Value::to_*` conversions that were incorrectly using `as`. +* Rename unstable `Value::to_error` to `Value::to_borrowed_error`. + +## [0.4.13] - 2021-01-11 + +* This is the same as `0.4.11`, except with a `kv_unstable_std` feature added to aid migrating current dependents to `0.4.14` (which was originally going to be `0.4.13` until it was decided to create a patch from `0.4.11` to minimize disruption). + +## [0.4.12] - 2020-12-24 + +### New + +* Support platforms without atomics by racing instead of failing to compile +* Implement `Log` for `Box` +* Update `cfg-if` to `1.0` +* Internal reworks of the structured logging API. Removed the `Fill` API +and added `source::as_map` and `source::as_list` to easily serialize a `Source` +as either a map of `{key: value, ..}` or as a list of `[(key, value), ..]`. + +### Fixed + +* Fixed deserialization of `LevelFilter` to use their `u64` index variants + +## [0.4.11] - 2020-07-09 + +### New + +* Support coercing structured values into concrete types. +* Reference the `win_dbg_logger` in the readme. + +### Fixed + +* Updates a few deprecated items used internally. +* Fixed issues in docs and expands sections. +* Show the correct build badge in the readme. +* Fix up a possible inference breakage with structured value errors. +* Respect formatting flags in structured value formatting. + +## [0.4.10] - 2019-12-16 (yanked) + +### Fixed + +* Fixed the `log!` macros, so they work in expression context (this regressed in `0.4.9`, which has been yanked). + +## [0.4.9] - 2019-12-12 (yanked) + +### Minimum Supported Rust Version + +This release bumps the minimum compiler version to `1.31.0`. This was mainly needed for `cfg-if`, +but between `1.16.0` and `1.31.0` there are a lot of language and library improvements we now +take advantage of. + +### New + +* Unstable support for capturing key-value pairs in a record using the `log!` macros + +### Improved + +* Better documentation for max level filters. +* Internal updates to line up with bumped MSRV + +## [0.4.8] - 2019-07-28 + +### New + +* Support attempting to get `Record` fields as static strings. + +## [0.4.7] - 2019-07-06 + +### New + +* Support for embedded environments with thread-unsafe initialization. +* Initial unstable support for capturing structured data under the `kv_unstable` +feature gate. This new API doesn't affect existing users and may change in future +patches (so those changes may not appear in the changelog until it stabilizes). + +### Improved + +* Docs for using `log` with the 2018 edition. +* Error messages for macros missing arguments. + +## [0.4.6] - 2018-10-27 + +### Improved + +* Support 2018-style macro import for the `log_enabled!` macro. + +## [0.4.5] - 2018-09-03 + +### Improved + +* Make `log`'s internal helper macros less likely to conflict with user-defined + macros. + +## [0.4.4] - 2018-08-17 + +### Improved + +* Support 2018-style imports of the log macros. + +## [0.4.3] - 2018-06-29 + +### Improved + +* More code generation improvements. + +## [0.4.2] - 2018-06-05 + +### Improved + +* Log invocations now generate less code. + +### Fixed + +* Example Logger implementations now properly set the max log level. + +## [0.4.1] - 2017-12-30 + +### Fixed + +* Some doc links were fixed. + +## [0.4.0] - 2017-12-24 + +The changes in this release include cleanup of some obscure functionality and a more robust public +API designed to support bridges to other logging systems, and provide more flexibility to new +features in the future. + +### Compatibility + +Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force +the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along +with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow +crates using either version to coexist without losing messages from one side or the other. + +There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging +implementation using 0.3.x will not have a file name or module path. Applications affected by this +can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The +other direction does not lose any information, fortunately! + +**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking +change. Applications may need to update their logging implementation (e.g. env-logger) to a newer +version using log 0.4.x to avoid losing module and file information. + +### New + +* The crate is now `no_std` by default. +* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is + enabled. +* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API. +* The `logger` free function returns a reference to the logger implementation. This, along with the + ability to construct `Record`s, makes it possible to bridge from another logging framework to + this one without digging into the private internals of the crate. The standard `error!` `warn!`, + etc., macros now exclusively use the public API of the crate rather than "secret" internal APIs. +* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all + "in flight" log events have been persisted. This can be used, for example, just before an + application exits to ensure that asynchronous log sinks finish their work. + +### Removed + +* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly + complicated the implementation and imposed a performance cost on each logging operation. +* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the + [log-panics](https://crates.io/crates/log-panics) instead. + +### Changed + +* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now + `LevelFilter`, and `LogRecord` is now `Record`. +* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function. +* The `set_logger` free functions have been restructured. The logger is now directly passed to the + functions rather than a closure which returns the logger. `set_logger` now takes a `&'static + Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger` + is a convenience function which takes a `Box` but otherwise acts like `set_logger`. It + requires the `std` feature. +* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support + integration with other logging frameworks that don't provide a `'static` lifetime for the + equivalent values. +* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration + with other logging frameworks that don't provide those values. + +### In the Future + +* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of + information in a log event in addition to the normal string message. This should be able to be + added in a backwards compatible manner to the 0.4.x series when the design is worked out. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.29...HEAD +[0.4.29]: https://github.com/rust-lang/log/compare/0.4.28...0.4.29 +[0.4.28]: https://github.com/rust-lang/log/compare/0.4.27...0.4.28 +[0.4.27]: https://github.com/rust-lang/log/compare/0.4.26...0.4.27 +[0.4.26]: https://github.com/rust-lang/log/compare/0.4.25...0.4.26 +[0.4.25]: https://github.com/rust-lang/log/compare/0.4.24...0.4.25 +[0.4.24]: https://github.com/rust-lang/log/compare/0.4.23...0.4.24 +[0.4.23]: https://github.com/rust-lang/log/compare/0.4.22...0.4.23 +[0.4.22]: https://github.com/rust-lang/log/compare/0.4.21...0.4.22 +[0.4.21]: https://github.com/rust-lang/log/compare/0.4.20...0.4.21 +[0.4.20]: https://github.com/rust-lang-nursery/log/compare/0.4.19...0.4.20 +[0.4.19]: https://github.com/rust-lang-nursery/log/compare/0.4.18...0.4.19 +[0.4.18]: https://github.com/rust-lang-nursery/log/compare/0.4.17...0.4.18 +[0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17 +[0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16 +[0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15 +[0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14 +[0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13 +[0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12 +[0.4.11]: https://github.com/rust-lang-nursery/log/compare/0.4.10...0.4.11 +[0.4.10]: https://github.com/rust-lang-nursery/log/compare/0.4.9...0.4.10 +[0.4.9]: https://github.com/rust-lang-nursery/log/compare/0.4.8...0.4.9 +[0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8 +[0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7 +[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6 +[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5 +[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4 +[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3 +[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2 +[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1 +[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0 +[release tags]: https://github.com/rust-lang-nursery/log/releases diff --git a/deps/crates/vendor/log/Cargo.lock b/deps/crates/vendor/log/Cargo.lock new file mode 100644 index 00000000000000..5268618e83b8c0 --- /dev/null +++ b/deps/crates/vendor/log/Cargo.lock @@ -0,0 +1,283 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "log" +version = "0.4.29" +dependencies = [ + "proc-macro2", + "serde", + "serde_core", + "serde_json", + "serde_test", + "sval", + "sval_derive", + "sval_ref", + "value-bag", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_fmt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e497af288b3b95d067a23a4f749f2861121ffcb2f6d8379310dcda040c345ed" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_test" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +dependencies = [ + "serde", +] + +[[package]] +name = "sval" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502b8906c4736190684646827fbab1e954357dfe541013bbd7994d033d53a1ca" + +[[package]] +name = "sval_buffer" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4b854348b15b6c441bdd27ce9053569b016a0723eab2d015b1fd8e6abe4f708" +dependencies = [ + "sval", + "sval_ref", +] + +[[package]] +name = "sval_derive" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32579aae2a134498be6d360355d7f085260377479d08cb032f0a90340bfd72d" +dependencies = [ + "sval_derive_macros", +] + +[[package]] +name = "sval_derive_macros" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c855576b719497b925e9646ec865ffb79122027aeafee855b18f0612cc998947" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sval_dynamic" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bd9e8b74410ddad37c6962587c5f9801a2caadba9e11f3f916ee3f31ae4a1f" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_fmt" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe17b8deb33a9441280b4266c2d257e166bafbaea6e66b4b34ca139c91766d9" +dependencies = [ + "itoa", + "ryu", + "sval", +] + +[[package]] +name = "sval_json" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854addb048a5bafb1f496c98e0ab5b9b581c3843f03ca07c034ae110d3b7c623" +dependencies = [ + "itoa", + "ryu", + "sval", +] + +[[package]] +name = "sval_nested" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf068f482108ff44ae8013477cb047a1665d5f1a635ad7cf79582c1845dce9" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + +[[package]] +name = "sval_ref" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed02126365ffe5ab8faa0abd9be54fbe68d03d607cd623725b0a71541f8aaa6f" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_serde" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a263383c6aa2076c4ef6011d3bae1b356edf6ea2613e3d8e8ebaa7b57dd707d5" +dependencies = [ + "serde_core", + "sval", + "sval_nested", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" +dependencies = [ + "value-bag-serde1", + "value-bag-sval2", +] + +[[package]] +name = "value-bag-serde1" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16530907bfe2999a1773ca5900a65101e092c70f642f25cc23ca0c43573262c5" +dependencies = [ + "erased-serde", + "serde_core", + "serde_fmt", +] + +[[package]] +name = "value-bag-sval2" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00ae130edd690eaa877e4f40605d534790d1cf1d651e7685bd6a144521b251f" +dependencies = [ + "sval", + "sval_buffer", + "sval_dynamic", + "sval_fmt", + "sval_json", + "sval_ref", + "sval_serde", +] diff --git a/deps/crates/vendor/log/Cargo.toml b/deps/crates/vendor/log/Cargo.toml new file mode 100644 index 00000000000000..e8c88a9d523f08 --- /dev/null +++ b/deps/crates/vendor/log/Cargo.toml @@ -0,0 +1,152 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.68.0" +name = "log" +version = "0.4.29" +authors = ["The Rust Project Developers"] +build = false +exclude = ["rfcs/**/*"] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +A lightweight logging facade for Rust +""" +documentation = "https://docs.rs/log" +readme = "README.md" +keywords = ["logging"] +categories = ["development-tools::debugging"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/log" + +[package.metadata.docs.rs] +features = [ + "std", + "serde", + "kv_std", + "kv_sval", + "kv_serde", +] + +[features] +kv = [] +kv_serde = [ + "kv_std", + "value-bag/serde", + "serde", +] +kv_std = [ + "std", + "kv", + "value-bag/error", +] +kv_sval = [ + "kv", + "value-bag/sval", + "sval", + "sval_ref", +] +kv_unstable = [ + "kv", + "value-bag", +] +kv_unstable_serde = [ + "kv_serde", + "kv_unstable_std", +] +kv_unstable_std = [ + "kv_std", + "kv_unstable", +] +kv_unstable_sval = [ + "kv_sval", + "kv_unstable", +] +max_level_debug = [] +max_level_error = [] +max_level_info = [] +max_level_off = [] +max_level_trace = [] +max_level_warn = [] +release_max_level_debug = [] +release_max_level_error = [] +release_max_level_info = [] +release_max_level_off = [] +release_max_level_trace = [] +release_max_level_warn = [] +serde = ["serde_core"] +std = [] + +[lib] +name = "log" +path = "src/lib.rs" + +[[test]] +name = "integration" +path = "tests/integration.rs" + +[[test]] +name = "macros" +path = "tests/macros.rs" + +[[bench]] +name = "value" +path = "benches/value.rs" + +[dependencies.serde_core] +version = "1.0" +optional = true +default-features = false + +[dependencies.sval] +version = "2.16" +optional = true +default-features = false + +[dependencies.sval_ref] +version = "2.16" +optional = true +default-features = false + +[dependencies.value-bag] +version = "1.12" +features = ["inline-i128"] +optional = true +default-features = false + +[dev-dependencies.proc-macro2] +version = "1.0.63" +default-features = false + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.serde_test] +version = "1.0" + +[dev-dependencies.sval] +version = "2.16" + +[dev-dependencies.sval_derive] +version = "2.16" + +[dev-dependencies.value-bag] +version = "1.12" +features = ["test"] diff --git a/deps/crates/vendor/log/Cargo.toml.orig b/deps/crates/vendor/log/Cargo.toml.orig new file mode 100644 index 00000000000000..964b887e726479 --- /dev/null +++ b/deps/crates/vendor/log/Cargo.toml.orig @@ -0,0 +1,76 @@ +[package] + +name = "log" +version = "0.4.29" # remember to update html_root_url +authors = ["The Rust Project Developers"] +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/log" +documentation = "https://docs.rs/log" +description = """ +A lightweight logging facade for Rust +""" +categories = ["development-tools::debugging"] +keywords = ["logging"] +exclude = ["rfcs/**/*"] +rust-version = "1.68.0" +edition = "2021" + +[package.metadata.docs.rs] +features = ["std", "serde", "kv_std", "kv_sval", "kv_serde"] + +[features] +max_level_off = [] +max_level_error = [] +max_level_warn = [] +max_level_info = [] +max_level_debug = [] +max_level_trace = [] + +release_max_level_off = [] +release_max_level_error = [] +release_max_level_warn = [] +release_max_level_info = [] +release_max_level_debug = [] +release_max_level_trace = [] + +std = [] + +kv = [] +kv_sval = ["kv", "value-bag/sval", "sval", "sval_ref"] +kv_std = ["std", "kv", "value-bag/error"] +kv_serde = ["kv_std", "value-bag/serde", "serde"] + +# This is here to not break backwards compatibility with the implicit feature +# that enables support for serde based on the dependency name. Since we're now +# using serde_core, the implicit feature was renamed, this adds back an alias. +serde = ["serde_core"] + +# Deprecated: use `kv_*` instead +# These `*_unstable` features will be removed in a future release +kv_unstable = ["kv", "value-bag"] +kv_unstable_sval = ["kv_sval", "kv_unstable"] +kv_unstable_std = ["kv_std", "kv_unstable"] +kv_unstable_serde = ["kv_serde", "kv_unstable_std"] + +[dependencies] +serde_core = { version = "1.0", optional = true, default-features = false } +sval = { version = "2.16", optional = true, default-features = false } +sval_ref = { version = "2.16", optional = true, default-features = false } +value-bag = { version = "1.12", optional = true, default-features = false, features = ["inline-i128"] } + +[dev-dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0" } +serde_test = { version = "1.0" } +sval = { version = "2.16" } +sval_derive = { version = "2.16" } +value-bag = { version = "1.12", features = ["test"] } + +# NOTE: log doesn't actually depend on this crate. However, our dependencies, +# serde and sval, dependent on version 1.0 of the crate, which has problem fixed +# in 1.0.60, specifically in the following commit +# https://github.com/dtolnay/proc-macro2/commit/e31d61910049e097afdd3d27c37786309082bdcb. +# By defining the crate as direct dependency we can increase its minimal +# version making the minimal (crate) version CI happy. +proc-macro2 = { version = "1.0.63", default-features = false } diff --git a/deps/crates/vendor/log/LICENSE-APACHE b/deps/crates/vendor/log/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/log/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/log/LICENSE-MIT b/deps/crates/vendor/log/LICENSE-MIT new file mode 100644 index 00000000000000..39d4bdb5acd313 --- /dev/null +++ b/deps/crates/vendor/log/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/log/README.md b/deps/crates/vendor/log/README.md new file mode 100644 index 00000000000000..9d5113d2402386 --- /dev/null +++ b/deps/crates/vendor/log/README.md @@ -0,0 +1,134 @@ +log +=== + +A Rust library providing a lightweight logging *facade*. + +[![Build status](https://img.shields.io/github/actions/workflow/status/rust-lang/log/main.yml?branch=master)](https://github.com/rust-lang/log/actions) +[![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log) +[![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log) +![License](https://img.shields.io/crates/l/log.svg) + +* [`log` documentation](https://docs.rs/log) + +A logging facade provides a single logging API that abstracts over the actual +logging implementation. Libraries can use the logging API provided by this +crate, and the consumer of those libraries can choose the logging +implementation that is most suitable for its use case. + + +## Minimum supported `rustc` + +`1.61.0+` + +This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes. + +## Usage + +### In libraries + +Libraries should link only to the `log` crate, and use the provided macros to +log whatever information will be useful to downstream consumers: + +```toml +[dependencies] +log = "0.4" +``` + +```rust +use log::{info, trace, warn}; + +pub fn shave_the_yak(yak: &mut Yak) { + trace!("Commencing yak shaving"); + + loop { + match find_a_razor() { + Ok(razor) => { + info!("Razor located: {razor}"); + yak.shave(razor); + break; + } + Err(err) => { + warn!("Unable to locate a razor: {err}, retrying"); + } + } + } +} +``` + +### In executables + +In order to produce log output, executables have to use a logger implementation compatible with the facade. +There are many available implementations to choose from, here are some options: + +* Simple minimal loggers: + * [`env_logger`](https://docs.rs/env_logger/*/env_logger/) + * [`colog`](https://docs.rs/colog/*/colog/) + * [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/) + * [`simplelog`](https://docs.rs/simplelog/*/simplelog/) + * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/) + * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/) + * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/) + * [`call_logger`](https://docs.rs/call_logger/*/call_logger/) + * [`std-logger`](https://docs.rs/std-logger/*/std_logger/) + * [`structured-logger`](https://docs.rs/structured-logger/latest/structured_logger/) + * [`clang_log`](https://docs.rs/clang_log/latest/clang_log) + * [`ftail`](https://docs.rs/ftail/latest/ftail/) +* Complex configurable frameworks: + * [`log4rs`](https://docs.rs/log4rs/*/log4rs/) + * [`logforth`](https://docs.rs/logforth/*/logforth/) + * [`fern`](https://docs.rs/fern/*/fern/) + * [`spdlog-rs`](https://docs.rs/spdlog-rs/*/spdlog/) +* Adaptors for other facilities: + * [`syslog`](https://docs.rs/syslog/*/syslog/) + * [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/) + * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/) + * [`android_log`](https://docs.rs/android_log/*/android_log/) + * [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/) + * [`db_logger`](https://docs.rs/db_logger/*/db_logger/) + * [`log-to-defmt`](https://docs.rs/log-to-defmt/*/log_to_defmt/) + * [`logcontrol-log`](https://docs.rs/logcontrol-log/*/logcontrol_log/) +* For WebAssembly binaries: + * [`console_log`](https://docs.rs/console_log/*/console_log/) +* For dynamic libraries: + * You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries. +* Utilities: + * [`log_err`](https://docs.rs/log_err/*/log_err/) + * [`log-reload`](https://docs.rs/log-reload/*/log_reload/) + * [`alterable_logger`](https://docs.rs/alterable_logger/*/alterable_logger) + +Executables should choose a logger implementation and initialize it early in the +runtime of the program. Logger implementations will typically include a +function to do this. Any log messages generated before the logger is +initialized will be ignored. + +The executable itself may use the `log` crate to log as well. + +## Structured logging + +If you enable the `kv` feature, you can associate structured data with your log records: + +```rust +use log::{info, trace, warn}; + +pub fn shave_the_yak(yak: &mut Yak) { + // `yak:serde` will capture `yak` using its `serde::Serialize` impl + // + // You could also use `:?` for `Debug`, or `:%` for `Display`. For a + // full list, see the `log` crate documentation + trace!(target = "yak_events", yak:serde; "Commencing yak shaving"); + + loop { + match find_a_razor() { + Ok(razor) => { + info!(razor; "Razor located"); + yak.shave(razor); + break; + } + Err(e) => { + // `e:err` will capture `e` using its `std::error::Error` impl + warn!(e:err; "Unable to locate a razor, retrying"); + } + } + } +} +``` diff --git a/deps/crates/vendor/log/benches/value.rs b/deps/crates/vendor/log/benches/value.rs new file mode 100644 index 00000000000000..3d0f18bfe43e06 --- /dev/null +++ b/deps/crates/vendor/log/benches/value.rs @@ -0,0 +1,27 @@ +#![cfg(feature = "kv")] +#![feature(test)] + +use log::kv::Value; + +#[bench] +fn u8_to_value(b: &mut test::Bencher) { + b.iter(|| Value::from(1u8)); +} + +#[bench] +fn u8_to_value_debug(b: &mut test::Bencher) { + b.iter(|| Value::from_debug(&1u8)); +} + +#[bench] +fn str_to_value_debug(b: &mut test::Bencher) { + b.iter(|| Value::from_debug(&"a string")); +} + +#[bench] +fn custom_to_value_debug(b: &mut test::Bencher) { + #[derive(Debug)] + struct A; + + b.iter(|| Value::from_debug(&A)); +} diff --git a/deps/crates/vendor/log/src/__private_api.rs b/deps/crates/vendor/log/src/__private_api.rs new file mode 100644 index 00000000000000..8d44467273fa48 --- /dev/null +++ b/deps/crates/vendor/log/src/__private_api.rs @@ -0,0 +1,151 @@ +//! WARNING: this is not part of the crate's public API and is subject to change at any time + +use self::sealed::KVs; +use crate::{logger, Level, Log, Metadata, Record}; +use std::fmt::Arguments; +use std::panic::Location; +pub use std::{format_args, module_path, stringify}; + +#[cfg(not(feature = "kv"))] +pub type Value<'a> = &'a str; + +mod sealed { + /// Types for the `kv` argument. + pub trait KVs<'a> { + fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>; + } +} + +// Types for the `kv` argument. + +impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + Some(self) + } +} + +impl<'a> KVs<'a> for () { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + None + } +} + +// Log implementation. + +/// The global logger proxy. +#[derive(Debug)] +pub struct GlobalLogger; + +impl Log for GlobalLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + logger().enabled(metadata) + } + + fn log(&self, record: &Record) { + logger().log(record) + } + + fn flush(&self) { + logger().flush() + } +} + +// Split from `log` to reduce generics and code size +fn log_impl( + logger: L, + args: Arguments, + level: Level, + &(target, module_path, loc): &(&str, &'static str, &'static Location), + kvs: Option<&[(&str, Value)]>, +) { + #[cfg(not(feature = "kv"))] + if kvs.is_some() { + panic!("key-value support is experimental and must be enabled using the `kv` feature") + } + + let mut builder = Record::builder(); + + builder + .args(args) + .level(level) + .target(target) + .module_path_static(Some(module_path)) + .file_static(Some(loc.file())) + .line(Some(loc.line())); + + #[cfg(feature = "kv")] + builder.key_values(&kvs); + + logger.log(&builder.build()); +} + +pub fn log<'a, K, L>( + logger: L, + args: Arguments, + level: Level, + target_module_path_and_loc: &(&str, &'static str, &'static Location), + kvs: K, +) where + K: KVs<'a>, + L: Log, +{ + log_impl( + logger, + args, + level, + target_module_path_and_loc, + kvs.into_kvs(), + ) +} + +pub fn enabled(logger: L, level: Level, target: &str) -> bool { + logger.enabled(&Metadata::builder().level(level).target(target).build()) +} + +#[track_caller] +pub fn loc() -> &'static Location<'static> { + Location::caller() +} + +#[cfg(feature = "kv")] +mod kv_support { + use crate::kv; + + pub type Value<'a> = kv::Value<'a>; + + // NOTE: Many functions here accept a double reference &&V + // This is so V itself can be ?Sized, while still letting us + // erase it to some dyn Trait (because &T is sized) + + pub fn capture_to_value<'a, V: kv::ToValue + ?Sized>(v: &'a &'a V) -> Value<'a> { + v.to_value() + } + + pub fn capture_debug<'a, V: core::fmt::Debug + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_debug(v) + } + + pub fn capture_display<'a, V: core::fmt::Display + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_display(v) + } + + #[cfg(feature = "kv_std")] + pub fn capture_error<'a>(v: &'a (dyn std::error::Error + 'static)) -> Value<'a> { + Value::from_dyn_error(v) + } + + #[cfg(feature = "kv_sval")] + pub fn capture_sval<'a, V: sval::Value + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_sval(v) + } + + #[cfg(feature = "kv_serde")] + pub fn capture_serde<'a, V: serde_core::Serialize + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_serde(v) + } +} + +#[cfg(feature = "kv")] +pub use self::kv_support::*; diff --git a/deps/crates/vendor/log/src/kv/error.rs b/deps/crates/vendor/log/src/kv/error.rs new file mode 100644 index 00000000000000..7efa5af3612605 --- /dev/null +++ b/deps/crates/vendor/log/src/kv/error.rs @@ -0,0 +1,94 @@ +use std::fmt; + +/// An error encountered while working with structured data. +#[derive(Debug)] +pub struct Error { + inner: Inner, +} + +#[derive(Debug)] +enum Inner { + #[cfg(feature = "std")] + Boxed(std_support::BoxedError), + Msg(&'static str), + #[cfg(feature = "value-bag")] + Value(crate::kv::value::inner::Error), + Fmt, +} + +impl Error { + /// Create an error from a message. + pub fn msg(msg: &'static str) -> Self { + Error { + inner: Inner::Msg(msg), + } + } + + // Not public so we don't leak the `crate::kv::value::inner` API + #[cfg(feature = "value-bag")] + pub(super) fn from_value(err: crate::kv::value::inner::Error) -> Self { + Error { + inner: Inner::Value(err), + } + } + + // Not public so we don't leak the `crate::kv::value::inner` API + #[cfg(feature = "value-bag")] + pub(super) fn into_value(self) -> crate::kv::value::inner::Error { + match self.inner { + Inner::Value(err) => err, + #[cfg(feature = "kv_std")] + _ => crate::kv::value::inner::Error::boxed(self), + #[cfg(not(feature = "kv_std"))] + _ => crate::kv::value::inner::Error::msg("error inspecting a value"), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Inner::*; + match &self.inner { + #[cfg(feature = "std")] + Boxed(err) => err.fmt(f), + #[cfg(feature = "value-bag")] + Value(err) => err.fmt(f), + Msg(msg) => msg.fmt(f), + Fmt => fmt::Error.fmt(f), + } + } +} + +impl From for Error { + fn from(_: fmt::Error) -> Self { + Error { inner: Inner::Fmt } + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use std::{error, io}; + + pub(super) type BoxedError = Box; + + impl Error { + /// Create an error from a standard error type. + pub fn boxed(err: E) -> Self + where + E: Into, + { + Error { + inner: Inner::Boxed(err.into()), + } + } + } + + impl error::Error for Error {} + + impl From for Error { + fn from(err: io::Error) -> Self { + Error::boxed(err) + } + } +} diff --git a/deps/crates/vendor/log/src/kv/key.rs b/deps/crates/vendor/log/src/kv/key.rs new file mode 100644 index 00000000000000..f0557d0cf71869 --- /dev/null +++ b/deps/crates/vendor/log/src/kv/key.rs @@ -0,0 +1,164 @@ +//! Structured keys. + +use std::borrow::Borrow; +use std::fmt; + +/// A type that can be converted into a [`Key`](struct.Key.html). +pub trait ToKey { + /// Perform the conversion. + fn to_key(&self) -> Key<'_>; +} + +impl ToKey for &T +where + T: ToKey + ?Sized, +{ + fn to_key(&self) -> Key<'_> { + (**self).to_key() + } +} + +impl<'k> ToKey for Key<'k> { + fn to_key(&self) -> Key<'_> { + Key { key: self.key } + } +} + +impl ToKey for str { + fn to_key(&self) -> Key<'_> { + Key::from_str(self) + } +} + +/// A key in a key-value. +// These impls must only be based on the as_str() representation of the key +// If a new field (such as an optional index) is added to the key they must not affect comparison +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Key<'k> { + // NOTE: This may become `Cow<'k, str>` + key: &'k str, +} + +impl<'k> Key<'k> { + /// Get a key from a borrowed string. + #[allow(clippy::should_implement_trait)] // Part of the public API now. + pub fn from_str(key: &'k str) -> Self { + Key { key } + } + + /// Get a borrowed string from this key. + /// + /// The lifetime of the returned string is bound to the borrow of `self` rather + /// than to `'k`. + pub fn as_str(&self) -> &str { + self.key + } + + /// Try get a borrowed string for the lifetime `'k` from this key. + /// + /// If the key is a borrow of a longer lived string, this method will return `Some`. + /// If the key is internally buffered, this method will return `None`. + pub fn to_borrowed_str(&self) -> Option<&'k str> { + // NOTE: If the internals of `Key` support buffering this + // won't be unconditionally `Some` anymore. We want to keep + // this option open + Some(self.key) + } +} + +impl<'k> fmt::Display for Key<'k> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.key.fmt(f) + } +} + +impl<'k> AsRef for Key<'k> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'k> Borrow for Key<'k> { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<'k> From<&'k str> for Key<'k> { + fn from(s: &'k str) -> Self { + Key::from_str(s) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use std::borrow::Cow; + + impl ToKey for String { + fn to_key(&self) -> Key<'_> { + Key::from_str(self) + } + } + + impl<'a> ToKey for Cow<'a, str> { + fn to_key(&self) -> Key<'_> { + Key::from_str(self) + } + } +} + +#[cfg(feature = "kv_sval")] +mod sval_support { + use super::*; + + use sval::Value; + use sval_ref::ValueRef; + + impl<'a> Value for Key<'a> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + self.key.stream(stream) + } + } + + impl<'a> ValueRef<'a> for Key<'a> { + fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { + self.key.stream(stream) + } + } +} + +#[cfg(feature = "kv_serde")] +mod serde_support { + use super::*; + + use serde_core::{Serialize, Serializer}; + + impl<'a> Serialize for Key<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.key.serialize(serializer) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn key_from_string() { + assert_eq!("a key", Key::from_str("a key").as_str()); + } + + #[test] + fn key_to_borrowed() { + assert_eq!("a key", Key::from_str("a key").to_borrowed_str().unwrap()); + } +} diff --git a/deps/crates/vendor/log/src/kv/mod.rs b/deps/crates/vendor/log/src/kv/mod.rs new file mode 100644 index 00000000000000..dff2179e0e66cf --- /dev/null +++ b/deps/crates/vendor/log/src/kv/mod.rs @@ -0,0 +1,265 @@ +//! Structured logging. +//! +//! Add the `kv` feature to your `Cargo.toml` to enable +//! this module: +//! +//! ```toml +//! [dependencies.log] +//! features = ["kv"] +//! ``` +//! +//! # Structured logging in `log` +//! +//! Structured logging enhances traditional text-based log records with user-defined +//! attributes. Structured logs can be analyzed using a variety of data processing +//! techniques, without needing to find and parse attributes from unstructured text first. +//! +//! In `log`, user-defined attributes are part of a [`Source`] on the log record. +//! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings +//! and values are a datum of any type that can be formatted or serialized. Simple types +//! like strings, booleans, and numbers are supported, as well as arbitrarily complex +//! structures involving nested objects and sequences. +//! +//! ## Adding key-values to log records +//! +//! Key-values appear before the message format in the `log!` macros: +//! +//! ``` +//! # use log::info; +//! info!(a = 1; "Something of interest"); +//! ``` +//! +//! Key-values support the same shorthand identifier syntax as `format_args`: +//! +//! ``` +//! # use log::info; +//! let a = 1; +//! +//! info!(a; "Something of interest"); +//! ``` +//! +//! Values are capturing using the [`ToValue`] trait by default. To capture a value +//! using a different trait implementation, use a modifier after its key. Here's how +//! the same example can capture `a` using its `Debug` implementation instead: +//! +//! ``` +//! # use log::info; +//! info!(a:? = 1; "Something of interest"); +//! ``` +//! +//! The following capturing modifiers are supported: +//! +//! - `:?` will capture the value using `Debug`. +//! - `:debug` will capture the value using `Debug`. +//! - `:%` will capture the value using `Display`. +//! - `:display` will capture the value using `Display`. +//! - `:err` will capture the value using `std::error::Error` (requires the `kv_std` feature). +//! - `:sval` will capture the value using `sval::Value` (requires the `kv_sval` feature). +//! - `:serde` will capture the value using `serde::Serialize` (requires the `kv_serde` feature). +//! +//! ## Working with key-values on log records +//! +//! Use the [`Record::key_values`](../struct.Record.html#method.key_values) method to access key-values. +//! +//! Individual values can be pulled from the source by their key: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{Source, Key, Value}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a: Value = record.key_values().get(Key::from("a")).unwrap(); +//! assert_eq!(1, a.to_i64().unwrap()); +//! # Ok(()) +//! # } +//! ``` +//! +//! All key-values can also be enumerated using a [`VisitSource`]: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use std::collections::BTreeMap; +//! +//! use log::kv::{self, Source, Key, Value, VisitSource}; +//! +//! struct Collect<'kvs>(BTreeMap, Value<'kvs>>); +//! +//! impl<'kvs> VisitSource<'kvs> for Collect<'kvs> { +//! fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { +//! self.0.insert(key, value); +//! +//! Ok(()) +//! } +//! } +//! +//! let mut visitor = Collect(BTreeMap::new()); +//! +//! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build(); +//! // info!(a = 1, b = 2, c = 3; "Something of interest"); +//! +//! record.key_values().visit(&mut visitor)?; +//! +//! let collected = visitor.0; +//! +//! assert_eq!( +//! vec!["a", "b", "c"], +//! collected +//! .keys() +//! .map(|k| k.as_str()) +//! .collect::>(), +//! ); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`Value`]s have methods for conversions to common types: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{Source, Key}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!(1, a.to_i64().unwrap()); +//! # Ok(()) +//! # } +//! ``` +//! +//! Values also have their own [`VisitValue`] type. Value visitors are a lightweight +//! API for working with primitives types: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{self, Source, Key, VisitValue}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! struct IsNumeric(bool); +//! +//! impl<'kvs> VisitValue<'kvs> for IsNumeric { +//! fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> { +//! self.0 = false; +//! Ok(()) +//! } +//! +//! fn visit_u64(&mut self, _value: u64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_i64(&mut self, _value: i64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_u128(&mut self, _value: u128) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_i128(&mut self, _value: i128) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_f64(&mut self, _value: f64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! } +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! let mut visitor = IsNumeric(false); +//! +//! a.visit(&mut visitor)?; +//! +//! let is_numeric = visitor.0; +//! +//! assert!(is_numeric); +//! # Ok(()) +//! # } +//! ``` +//! +//! To serialize a value to a format like JSON, you can also use either `serde` or `sval`: +//! +//! ``` +//! # fn main() -> Result<(), Box> { +//! # #[cfg(feature = "kv_serde")] +//! # { +//! # use log::kv::Key; +//! #[derive(serde::Serialize)] +//! struct Data { +//! a: i32, b: bool, +//! c: &'static str, +//! } +//! +//! let data = Data { a: 1, b: true, c: "Some data" }; +//! +//! # let source = [("a", log::kv::Value::from_serde(&data))]; +//! # let record = log::Record::builder().key_values(&source).build(); +//! // info!(a = data; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?); +//! # } +//! # Ok(()) +//! # } +//! ``` +//! +//! The choice of serialization framework depends on the needs of the consumer. +//! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`. +//! Log producers and log consumers don't need to agree on the serialization framework. +//! A value can be captured using its `serde::Serialize` implementation and still be serialized +//! through `sval` without losing any structure or data. +//! +//! Values can also always be formatted using the standard `Debug` and `Display` +//! traits: +//! +//! ``` +//! # use log::kv::Key; +//! #[derive(Debug)] +//! struct Data { +//! a: i32, +//! b: bool, +//! c: &'static str, +//! } +//! +//! let data = Data { a: 1, b: true, c: "Some data" }; +//! +//! # let source = [("a", log::kv::Value::from_debug(&data))]; +//! # let record = log::Record::builder().key_values(&source).build(); +//! // info!(a = data; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}")); +//! ``` + +mod error; +mod key; + +#[cfg(not(feature = "kv_unstable"))] +mod source; +#[cfg(not(feature = "kv_unstable"))] +mod value; + +pub use self::error::Error; +pub use self::key::{Key, ToKey}; +pub use self::source::{Source, VisitSource}; +pub use self::value::{ToValue, Value, VisitValue}; + +#[cfg(feature = "kv_unstable")] +pub mod source; +#[cfg(feature = "kv_unstable")] +pub mod value; + +#[cfg(feature = "kv_unstable")] +pub use self::source::Visitor; diff --git a/deps/crates/vendor/log/src/kv/source.rs b/deps/crates/vendor/log/src/kv/source.rs new file mode 100644 index 00000000000000..a9c6b437bbbcba --- /dev/null +++ b/deps/crates/vendor/log/src/kv/source.rs @@ -0,0 +1,515 @@ +//! Sources for key-values. +//! +//! This module defines the [`Source`] type and supporting APIs for +//! working with collections of key-values. + +use crate::kv::{Error, Key, ToKey, ToValue, Value}; +use std::fmt; + +/// A source of key-values. +/// +/// The source may be a single pair, a set of pairs, or a filter over a set of pairs. +/// Use the [`VisitSource`](trait.VisitSource.html) trait to inspect the structured data +/// in a source. +/// +/// A source is like an iterator over its key-values, except with a push-based API +/// instead of a pull-based one. +/// +/// # Examples +/// +/// Enumerating the key-values in a source: +/// +/// ``` +/// # fn main() -> Result<(), log::kv::Error> { +/// use log::kv::{self, Source, Key, Value, VisitSource}; +/// +/// // A `VisitSource` that prints all key-values +/// // VisitSources are fed the key-value pairs of each key-values +/// struct Printer; +/// +/// impl<'kvs> VisitSource<'kvs> for Printer { +/// fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { +/// println!("{key}: {value}"); +/// +/// Ok(()) +/// } +/// } +/// +/// // A source with 3 key-values +/// // Common collection types implement the `Source` trait +/// let source = &[ +/// ("a", 1), +/// ("b", 2), +/// ("c", 3), +/// ]; +/// +/// // Pass an instance of the `VisitSource` to a `Source` to visit it +/// source.visit(&mut Printer)?; +/// # Ok(()) +/// # } +/// ``` +pub trait Source { + /// Visit key-values. + /// + /// A source doesn't have to guarantee any ordering or uniqueness of key-values. + /// If the given visitor returns an error then the source may early-return with it, + /// even if there are more key-values. + /// + /// # Implementation notes + /// + /// A source should yield the same key-values to a subsequent visitor unless + /// that visitor itself fails. + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error>; + + /// Get the value for a given key. + /// + /// If the key appears multiple times in the source then which key is returned + /// is implementation specific. + /// + /// # Implementation notes + /// + /// A source that can provide a more efficient implementation of this method + /// should override it. + fn get(&self, key: Key) -> Option> { + get_default(self, key) + } + + /// Count the number of key-values that can be visited. + /// + /// # Implementation notes + /// + /// A source that knows the number of key-values upfront may provide a more + /// efficient implementation. + /// + /// A subsequent call to `visit` should yield the same number of key-values. + fn count(&self) -> usize { + count_default(self) + } +} + +/// The default implementation of `Source::get` +fn get_default<'v>(source: &'v (impl Source + ?Sized), key: Key) -> Option> { + struct Get<'k, 'v> { + key: Key<'k>, + found: Option>, + } + + impl<'k, 'kvs> VisitSource<'kvs> for Get<'k, 'kvs> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + if self.key == key { + self.found = Some(value); + } + + Ok(()) + } + } + + let mut get = Get { key, found: None }; + + let _ = source.visit(&mut get); + get.found +} + +/// The default implementation of `Source::count`. +fn count_default(source: impl Source) -> usize { + struct Count(usize); + + impl<'kvs> VisitSource<'kvs> for Count { + fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> { + self.0 += 1; + + Ok(()) + } + } + + let mut count = Count(0); + let _ = source.visit(&mut count); + count.0 +} + +impl Source for &T +where + T: Source + ?Sized, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } +} + +impl Source for (K, V) +where + K: ToKey, + V: ToValue, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + visitor.visit_pair(self.0.to_key(), self.1.to_value()) + } + + fn get(&self, key: Key) -> Option> { + if self.0.to_key() == key { + Some(self.1.to_value()) + } else { + None + } + } + + fn count(&self) -> usize { + 1 + } +} + +impl Source for [S] +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for source in self { + source.visit(visitor)?; + } + + Ok(()) + } + + fn get(&self, key: Key) -> Option> { + for source in self { + if let Some(found) = source.get(key.clone()) { + return Some(found); + } + } + + None + } + + fn count(&self) -> usize { + self.iter().map(Source::count).sum() + } +} + +impl Source for [S; N] +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(self as &[_], visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(self as &[_], key) + } + + fn count(&self) -> usize { + Source::count(self as &[_]) + } +} + +impl Source for Option +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + if let Some(source) = self { + source.visit(visitor)?; + } + + Ok(()) + } + + fn get(&self, key: Key) -> Option> { + self.as_ref().and_then(|s| s.get(key)) + } + + fn count(&self) -> usize { + self.as_ref().map_or(0, Source::count) + } +} + +/// A visitor for the key-value pairs in a [`Source`](trait.Source.html). +pub trait VisitSource<'kvs> { + /// Visit a key-value pair. + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error>; +} + +#[allow(clippy::needless_lifetimes)] // Not needless. +impl<'a, 'kvs, T> VisitSource<'kvs> for &'a mut T +where + T: VisitSource<'kvs> + ?Sized, +{ + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + (**self).visit_pair(key, value) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugMap<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&key, &value); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugList<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&(key, value)); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugSet<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&(key, value)); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugTuple<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.field(&key); + self.field(&value); + Ok(()) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use std::borrow::Borrow; + use std::collections::{BTreeMap, HashMap}; + use std::hash::{BuildHasher, Hash}; + use std::rc::Rc; + use std::sync::Arc; + + impl Source for Box + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl Source for Arc + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl Source for Rc + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl Source for Vec + where + S: Source, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl<'kvs, V> VisitSource<'kvs> for Box + where + V: VisitSource<'kvs> + ?Sized, + { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + (**self).visit_pair(key, value) + } + } + + impl Source for HashMap + where + K: ToKey + Borrow + Eq + Hash, + V: ToValue, + S: BuildHasher, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for (key, value) in self { + visitor.visit_pair(key.to_key(), value.to_value())?; + } + Ok(()) + } + + fn get(&self, key: Key) -> Option> { + HashMap::get(self, key.as_str()).map(|v| v.to_value()) + } + + fn count(&self) -> usize { + self.len() + } + } + + impl Source for BTreeMap + where + K: ToKey + Borrow + Ord, + V: ToValue, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for (key, value) in self { + visitor.visit_pair(key.to_key(), value.to_value())?; + } + Ok(()) + } + + fn get(&self, key: Key) -> Option> { + BTreeMap::get(self, key.as_str()).map(|v| v.to_value()) + } + + fn count(&self) -> usize { + self.len() + } + } + + #[cfg(test)] + mod tests { + use crate::kv::value; + + use super::*; + + #[test] + fn count() { + assert_eq!(1, Source::count(&Box::new(("a", 1)))); + assert_eq!(2, Source::count(&vec![("a", 1), ("b", 2)])); + } + + #[test] + fn get() { + let source = vec![("a", 1), ("b", 2), ("a", 1)]; + assert_eq!( + value::inner::Token::I64(1), + Source::get(&source, Key::from_str("a")).unwrap().to_token() + ); + + let source = Box::new(None::<(&str, i32)>); + assert!(Source::get(&source, Key::from_str("a")).is_none()); + } + + #[test] + fn hash_map() { + let mut map = HashMap::new(); + map.insert("a", 1); + map.insert("b", 2); + + assert_eq!(2, Source::count(&map)); + assert_eq!( + value::inner::Token::I64(1), + Source::get(&map, Key::from_str("a")).unwrap().to_token() + ); + } + + #[test] + fn btree_map() { + let mut map = BTreeMap::new(); + map.insert("a", 1); + map.insert("b", 2); + + assert_eq!(2, Source::count(&map)); + assert_eq!( + value::inner::Token::I64(1), + Source::get(&map, Key::from_str("a")).unwrap().to_token() + ); + } + } +} + +// NOTE: Deprecated; but aliases can't carry this attribute +#[cfg(feature = "kv_unstable")] +pub use VisitSource as Visitor; + +#[cfg(test)] +mod tests { + use crate::kv::value; + + use super::*; + + #[test] + fn source_is_object_safe() { + fn _check(_: &dyn Source) {} + } + + #[test] + fn visitor_is_object_safe() { + fn _check(_: &dyn VisitSource) {} + } + + #[test] + fn count() { + struct OnePair { + key: &'static str, + value: i32, + } + + impl Source for OnePair { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + visitor.visit_pair(self.key.to_key(), self.value.to_value()) + } + } + + assert_eq!(1, Source::count(&("a", 1))); + assert_eq!(2, Source::count(&[("a", 1), ("b", 2)] as &[_])); + assert_eq!(0, Source::count(&None::<(&str, i32)>)); + assert_eq!(1, Source::count(&OnePair { key: "a", value: 1 })); + } + + #[test] + fn get() { + let source = &[("a", 1), ("b", 2), ("a", 1)] as &[_]; + assert_eq!( + value::inner::Token::I64(1), + Source::get(source, Key::from_str("a")).unwrap().to_token() + ); + assert_eq!( + value::inner::Token::I64(2), + Source::get(source, Key::from_str("b")).unwrap().to_token() + ); + assert!(Source::get(&source, Key::from_str("c")).is_none()); + + let source = None::<(&str, i32)>; + assert!(Source::get(&source, Key::from_str("a")).is_none()); + } +} diff --git a/deps/crates/vendor/log/src/kv/value.rs b/deps/crates/vendor/log/src/kv/value.rs new file mode 100644 index 00000000000000..5e79bb816de2dc --- /dev/null +++ b/deps/crates/vendor/log/src/kv/value.rs @@ -0,0 +1,1396 @@ +//! Structured values. +//! +//! This module defines the [`Value`] type and supporting APIs for +//! capturing and serializing them. + +use std::fmt; + +pub use crate::kv::Error; + +/// A type that can be converted into a [`Value`](struct.Value.html). +pub trait ToValue { + /// Perform the conversion. + fn to_value(&self) -> Value<'_>; +} + +impl ToValue for &T +where + T: ToValue + ?Sized, +{ + fn to_value(&self) -> Value<'_> { + (**self).to_value() + } +} + +impl<'v> ToValue for Value<'v> { + fn to_value(&self) -> Value<'_> { + Value { + inner: self.inner.clone(), + } + } +} + +/// A value in a key-value. +/// +/// Values are an anonymous bag containing some structured datum. +/// +/// # Capturing values +/// +/// There are a few ways to capture a value: +/// +/// - Using the `Value::from_*` methods. +/// - Using the `ToValue` trait. +/// - Using the standard `From` trait. +/// +/// ## Using the `Value::from_*` methods +/// +/// `Value` offers a few constructor methods that capture values of different kinds. +/// +/// ``` +/// use log::kv::Value; +/// +/// let value = Value::from_debug(&42i32); +/// +/// assert_eq!(None, value.to_i64()); +/// ``` +/// +/// ## Using the `ToValue` trait +/// +/// The `ToValue` trait can be used to capture values generically. +/// It's the bound used by `Source`. +/// +/// ``` +/// # use log::kv::ToValue; +/// let value = 42i32.to_value(); +/// +/// assert_eq!(Some(42), value.to_i64()); +/// ``` +/// +/// ## Using the standard `From` trait +/// +/// Standard types that implement `ToValue` also implement `From`. +/// +/// ``` +/// use log::kv::Value; +/// +/// let value = Value::from(42i32); +/// +/// assert_eq!(Some(42), value.to_i64()); +/// ``` +/// +/// # Data model +/// +/// Values can hold one of a number of types: +/// +/// - **Null:** The absence of any other meaningful value. Note that +/// `Some(Value::null())` is not the same as `None`. The former is +/// `null` while the latter is `undefined`. This is important to be +/// able to tell the difference between a key-value that was logged, +/// but its value was empty (`Some(Value::null())`) and a key-value +/// that was never logged at all (`None`). +/// - **Strings:** `str`, `char`. +/// - **Booleans:** `bool`. +/// - **Integers:** `u8`-`u128`, `i8`-`i128`, `NonZero*`. +/// - **Floating point numbers:** `f32`-`f64`. +/// - **Errors:** `dyn (Error + 'static)`. +/// - **`serde`:** Any type in `serde`'s data model. +/// - **`sval`:** Any type in `sval`'s data model. +/// +/// # Serialization +/// +/// Values provide a number of ways to be serialized. +/// +/// For basic types the [`Value::visit`] method can be used to extract the +/// underlying typed value. However, this is limited in the amount of types +/// supported (see the [`VisitValue`] trait methods). +/// +/// For more complex types one of the following traits can be used: +/// * `sval::Value`, requires the `kv_sval` feature. +/// * `serde::Serialize`, requires the `kv_serde` feature. +/// +/// You don't need a visitor to serialize values through `serde` or `sval`. +/// +/// A value can always be serialized using any supported framework, regardless +/// of how it was captured. If, for example, a value was captured using its +/// `Display` implementation, it will serialize through `serde` as a string. If it was +/// captured as a struct using `serde`, it will also serialize as a struct +/// through `sval`, or can be formatted using a `Debug`-compatible representation. +#[derive(Clone)] +pub struct Value<'v> { + inner: inner::Inner<'v>, +} + +impl<'v> Value<'v> { + /// Get a value from a type implementing `ToValue`. + pub fn from_any(value: &'v T) -> Self + where + T: ToValue, + { + value.to_value() + } + + /// Get a value from a type implementing `std::fmt::Debug`. + pub fn from_debug(value: &'v T) -> Self + where + T: fmt::Debug, + { + Value { + inner: inner::Inner::from_debug(value), + } + } + + /// Get a value from a type implementing `std::fmt::Display`. + pub fn from_display(value: &'v T) -> Self + where + T: fmt::Display, + { + Value { + inner: inner::Inner::from_display(value), + } + } + + /// Get a value from a type implementing `serde::Serialize`. + #[cfg(feature = "kv_serde")] + pub fn from_serde(value: &'v T) -> Self + where + T: serde_core::Serialize, + { + Value { + inner: inner::Inner::from_serde1(value), + } + } + + /// Get a value from a type implementing `sval::Value`. + #[cfg(feature = "kv_sval")] + pub fn from_sval(value: &'v T) -> Self + where + T: sval::Value, + { + Value { + inner: inner::Inner::from_sval2(value), + } + } + + /// Get a value from a dynamic `std::fmt::Debug`. + pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { + Value { + inner: inner::Inner::from_dyn_debug(value), + } + } + + /// Get a value from a dynamic `std::fmt::Display`. + pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { + Value { + inner: inner::Inner::from_dyn_display(value), + } + } + + /// Get a value from a dynamic error. + #[cfg(feature = "kv_std")] + pub fn from_dyn_error(err: &'v (dyn std::error::Error + 'static)) -> Self { + Value { + inner: inner::Inner::from_dyn_error(err), + } + } + + /// Get a `null` value. + pub fn null() -> Self { + Value { + inner: inner::Inner::empty(), + } + } + + /// Get a value from an internal primitive. + fn from_inner(value: T) -> Self + where + T: Into>, + { + Value { + inner: value.into(), + } + } + + /// Inspect this value using a simple visitor. + /// + /// When the `kv_serde` or `kv_sval` features are enabled, you can also + /// serialize a value using its `Serialize` or `Value` implementation. + pub fn visit(&self, visitor: impl VisitValue<'v>) -> Result<(), Error> { + inner::visit(&self.inner, visitor) + } +} + +impl<'v> fmt::Debug for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} + +impl<'v> fmt::Display for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, f) + } +} + +#[cfg(feature = "kv_serde")] +impl<'v> serde_core::Serialize for Value<'v> { + fn serialize(&self, s: S) -> Result + where + S: serde_core::Serializer, + { + self.inner.serialize(s) + } +} + +#[cfg(feature = "kv_sval")] +impl<'v> sval::Value for Value<'v> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { + sval::Value::stream(&self.inner, stream) + } +} + +#[cfg(feature = "kv_sval")] +impl<'v> sval_ref::ValueRef<'v> for Value<'v> { + fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { + sval_ref::ValueRef::stream_ref(&self.inner, stream) + } +} + +impl ToValue for str { + fn to_value(&self) -> Value<'_> { + Value::from(self) + } +} + +impl<'v> From<&'v str> for Value<'v> { + fn from(value: &'v str) -> Self { + Value::from_inner(value) + } +} + +impl ToValue for () { + fn to_value(&self) -> Value<'_> { + Value::from_inner(()) + } +} + +impl ToValue for Option +where + T: ToValue, +{ + fn to_value(&self) -> Value<'_> { + match *self { + Some(ref value) => value.to_value(), + None => Value::from_inner(()), + } + } +} + +macro_rules! impl_to_value_primitive { + ($($into_ty:ty,)*) => { + $( + impl ToValue for $into_ty { + fn to_value(&self) -> Value<'_> { + Value::from(*self) + } + } + + impl<'v> From<$into_ty> for Value<'v> { + fn from(value: $into_ty) -> Self { + Value::from_inner(value) + } + } + + impl<'v> From<&'v $into_ty> for Value<'v> { + fn from(value: &'v $into_ty) -> Self { + Value::from_inner(*value) + } + } + )* + }; +} + +macro_rules! impl_to_value_nonzero_primitive { + ($($into_ty:ident,)*) => { + $( + impl ToValue for std::num::$into_ty { + fn to_value(&self) -> Value<'_> { + Value::from(self.get()) + } + } + + impl<'v> From for Value<'v> { + fn from(value: std::num::$into_ty) -> Self { + Value::from(value.get()) + } + } + + impl<'v> From<&'v std::num::$into_ty> for Value<'v> { + fn from(value: &'v std::num::$into_ty) -> Self { + Value::from(value.get()) + } + } + )* + }; +} + +macro_rules! impl_value_to_primitive { + ($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => { + impl<'v> Value<'v> { + $( + #[doc = $doc] + pub fn $into_name(&self) -> Option<$into_ty> { + self.inner.$into_name() + } + )* + } + } +} + +impl_to_value_primitive![ + usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool, +]; + +#[rustfmt::skip] +impl_to_value_nonzero_primitive![ + NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, + NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, +]; + +impl_value_to_primitive![ + #[doc = "Try convert this value into a `u64`."] + to_u64 -> u64, + #[doc = "Try convert this value into a `i64`."] + to_i64 -> i64, + #[doc = "Try convert this value into a `u128`."] + to_u128 -> u128, + #[doc = "Try convert this value into a `i128`."] + to_i128 -> i128, + #[doc = "Try convert this value into a `f64`."] + to_f64 -> f64, + #[doc = "Try convert this value into a `char`."] + to_char -> char, + #[doc = "Try convert this value into a `bool`."] + to_bool -> bool, +]; + +impl<'v> Value<'v> { + /// Try to convert this value into an error. + #[cfg(feature = "kv_std")] + pub fn to_borrowed_error(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.to_borrowed_error() + } + + /// Try to convert this value into a borrowed string. + pub fn to_borrowed_str(&self) -> Option<&'v str> { + self.inner.to_borrowed_str() + } +} + +#[cfg(feature = "kv_std")] +mod std_support { + use std::borrow::Cow; + use std::rc::Rc; + use std::sync::Arc; + + use super::*; + + impl ToValue for Box + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value<'_> { + (**self).to_value() + } + } + + impl ToValue for Arc + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value<'_> { + (**self).to_value() + } + } + + impl ToValue for Rc + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value<'_> { + (**self).to_value() + } + } + + impl ToValue for String { + fn to_value(&self) -> Value<'_> { + Value::from(&**self) + } + } + + impl<'v> ToValue for Cow<'v, str> { + fn to_value(&self) -> Value<'_> { + Value::from(&**self) + } + } + + impl<'v> Value<'v> { + /// Try convert this value into a string. + pub fn to_cow_str(&self) -> Option> { + self.inner.to_str() + } + } + + impl<'v> From<&'v String> for Value<'v> { + fn from(v: &'v String) -> Self { + Value::from(&**v) + } + } +} + +/// A visitor for a [`Value`]. +/// +/// Also see [`Value`'s documentation on serialization]. Value visitors are a simple alternative +/// to a more fully-featured serialization framework like `serde` or `sval`. A value visitor +/// can differentiate primitive types through methods like [`VisitValue::visit_bool`] and +/// [`VisitValue::visit_str`], but more complex types like maps and sequences +/// will fallthrough to [`VisitValue::visit_any`]. +/// +/// If you're trying to serialize a value to a format like JSON, you can use either `serde` +/// or `sval` directly with the value. You don't need a visitor. +/// +/// [`Value`'s documentation on serialization]: Value#serialization +pub trait VisitValue<'v> { + /// Visit a `Value`. + /// + /// This is the only required method on `VisitValue` and acts as a fallback for any + /// more specific methods that aren't overridden. + /// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation, + /// or serialized using its `sval::Value` or `serde::Serialize` implementation. + fn visit_any(&mut self, value: Value) -> Result<(), Error>; + + /// Visit an empty value. + fn visit_null(&mut self) -> Result<(), Error> { + self.visit_any(Value::null()) + } + + /// Visit an unsigned integer. + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a signed integer. + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a big unsigned integer. + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + self.visit_any((value).into()) + } + + /// Visit a big signed integer. + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + self.visit_any((value).into()) + } + + /// Visit a floating point. + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a boolean. + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a string. + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a string. + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.visit_str(value) + } + + /// Visit a Unicode character. + fn visit_char(&mut self, value: char) -> Result<(), Error> { + let mut b = [0; 4]; + self.visit_str(&*value.encode_utf8(&mut b)) + } + + /// Visit an error. + #[cfg(feature = "kv_std")] + fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { + self.visit_any(Value::from_dyn_error(err)) + } + + /// Visit an error. + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.visit_any(Value::from_dyn_error(err)) + } +} + +#[allow(clippy::needless_lifetimes)] // Not needless. +impl<'a, 'v, T: ?Sized> VisitValue<'v> for &'a mut T +where + T: VisitValue<'v>, +{ + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + (**self).visit_any(value) + } + + fn visit_null(&mut self) -> Result<(), Error> { + (**self).visit_null() + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + (**self).visit_u64(value) + } + + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + (**self).visit_i64(value) + } + + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + (**self).visit_u128(value) + } + + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + (**self).visit_i128(value) + } + + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + (**self).visit_f64(value) + } + + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + (**self).visit_bool(value) + } + + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + (**self).visit_str(value) + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + (**self).visit_borrowed_str(value) + } + + fn visit_char(&mut self, value: char) -> Result<(), Error> { + (**self).visit_char(value) + } + + #[cfg(feature = "kv_std")] + fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { + (**self).visit_error(err) + } + + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + (**self).visit_borrowed_error(err) + } +} + +#[cfg(feature = "value-bag")] +pub(in crate::kv) mod inner { + /** + An implementation of `Value` based on a library called `value_bag`. + + `value_bag` was written specifically for use in `log`'s value, but was split out when it outgrew + the codebase here. It's a general-purpose type-erasure library that handles mapping between + more fully-featured serialization frameworks. + */ + use super::*; + + pub use value_bag::ValueBag as Inner; + + pub use value_bag::Error; + + #[cfg(test)] + pub use value_bag::test::TestToken as Token; + + pub fn visit<'v>( + inner: &Inner<'v>, + visitor: impl VisitValue<'v>, + ) -> Result<(), crate::kv::Error> { + struct InnerVisitValue(V); + + impl<'v, V> value_bag::visit::Visit<'v> for InnerVisitValue + where + V: VisitValue<'v>, + { + fn visit_any(&mut self, value: value_bag::ValueBag) -> Result<(), Error> { + self.0 + .visit_any(Value { inner: value }) + .map_err(crate::kv::Error::into_value) + } + + fn visit_empty(&mut self) -> Result<(), Error> { + self.0.visit_null().map_err(crate::kv::Error::into_value) + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.0 + .visit_u64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + self.0 + .visit_i64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + self.0 + .visit_u128(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + self.0 + .visit_i128(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + self.0 + .visit_f64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + self.0 + .visit_bool(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + self.0 + .visit_str(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.0 + .visit_borrowed_str(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_char(&mut self, value: char) -> Result<(), Error> { + self.0 + .visit_char(value) + .map_err(crate::kv::Error::into_value) + } + + #[cfg(feature = "kv_std")] + fn visit_error( + &mut self, + err: &(dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.0 + .visit_error(err) + .map_err(crate::kv::Error::into_value) + } + + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.0 + .visit_borrowed_error(err) + .map_err(crate::kv::Error::into_value) + } + } + + inner + .visit(&mut InnerVisitValue(visitor)) + .map_err(crate::kv::Error::from_value) + } +} + +#[cfg(not(feature = "value-bag"))] +pub(in crate::kv) mod inner { + /** + This is a dependency-free implementation of `Value` when there's no serialization frameworks involved. + In these simple cases a more fully featured solution like `value_bag` isn't needed, so we avoid pulling it in. + + There are a few things here that need to remain consistent with the `value_bag`-based implementation: + + 1. Conversions should always produce the same results. If a conversion here returns `Some`, then + the same `value_bag`-based conversion must also. Of particular note here are floats to ints; they're + based on the standard library's `TryInto` conversions, which need to be converted to `i32` or `u32`, + and then to `f64`. + 2. VisitValues should always be called in the same way. If a particular type of value calls `visit_i64`, + then the same `value_bag`-based visitor must also. + */ + use super::*; + + #[derive(Clone)] + pub enum Inner<'v> { + None, + Bool(bool), + Str(&'v str), + Char(char), + I64(i64), + U64(u64), + F64(f64), + I128(i128), + U128(u128), + Debug(&'v dyn fmt::Debug), + Display(&'v dyn fmt::Display), + } + + impl<'v> From<()> for Inner<'v> { + fn from(_: ()) -> Self { + Inner::None + } + } + + impl<'v> From for Inner<'v> { + fn from(v: bool) -> Self { + Inner::Bool(v) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: char) -> Self { + Inner::Char(v) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: f32) -> Self { + Inner::F64(v as f64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: f64) -> Self { + Inner::F64(v) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: i8) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: i16) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: i32) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: i64) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: isize) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: u8) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: u16) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: u32) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: u64) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: usize) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: i128) -> Self { + Inner::I128(v) + } + } + + impl<'v> From for Inner<'v> { + fn from(v: u128) -> Self { + Inner::U128(v) + } + } + + impl<'v> From<&'v str> for Inner<'v> { + fn from(v: &'v str) -> Self { + Inner::Str(v) + } + } + + impl<'v> fmt::Debug for Inner<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Inner::None => fmt::Debug::fmt(&None::<()>, f), + Inner::Bool(v) => fmt::Debug::fmt(v, f), + Inner::Str(v) => fmt::Debug::fmt(v, f), + Inner::Char(v) => fmt::Debug::fmt(v, f), + Inner::I64(v) => fmt::Debug::fmt(v, f), + Inner::U64(v) => fmt::Debug::fmt(v, f), + Inner::F64(v) => fmt::Debug::fmt(v, f), + Inner::I128(v) => fmt::Debug::fmt(v, f), + Inner::U128(v) => fmt::Debug::fmt(v, f), + Inner::Debug(v) => fmt::Debug::fmt(v, f), + Inner::Display(v) => fmt::Display::fmt(v, f), + } + } + } + + impl<'v> fmt::Display for Inner<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Inner::None => fmt::Debug::fmt(&None::<()>, f), + Inner::Bool(v) => fmt::Display::fmt(v, f), + Inner::Str(v) => fmt::Display::fmt(v, f), + Inner::Char(v) => fmt::Display::fmt(v, f), + Inner::I64(v) => fmt::Display::fmt(v, f), + Inner::U64(v) => fmt::Display::fmt(v, f), + Inner::F64(v) => fmt::Display::fmt(v, f), + Inner::I128(v) => fmt::Display::fmt(v, f), + Inner::U128(v) => fmt::Display::fmt(v, f), + Inner::Debug(v) => fmt::Debug::fmt(v, f), + Inner::Display(v) => fmt::Display::fmt(v, f), + } + } + } + + impl<'v> Inner<'v> { + pub fn from_debug(value: &'v T) -> Self { + Inner::Debug(value) + } + + pub fn from_display(value: &'v T) -> Self { + Inner::Display(value) + } + + pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { + Inner::Debug(value) + } + + pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { + Inner::Display(value) + } + + pub fn empty() -> Self { + Inner::None + } + + pub fn to_bool(&self) -> Option { + match self { + Inner::Bool(v) => Some(*v), + _ => None, + } + } + + pub fn to_char(&self) -> Option { + match self { + Inner::Char(v) => Some(*v), + _ => None, + } + } + + pub fn to_f64(&self) -> Option { + match self { + Inner::F64(v) => Some(*v), + Inner::I64(v) => { + let v: i32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::U64(v) => { + let v: u32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::I128(v) => { + let v: i32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::U128(v) => { + let v: u32 = (*v).try_into().ok()?; + v.try_into().ok() + } + _ => None, + } + } + + pub fn to_i64(&self) -> Option { + match self { + Inner::I64(v) => Some(*v), + Inner::U64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_u64(&self) -> Option { + match self { + Inner::U64(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_u128(&self) -> Option { + match self { + Inner::U128(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::U64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_i128(&self) -> Option { + match self { + Inner::I128(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::U64(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_borrowed_str(&self) -> Option<&'v str> { + match self { + Inner::Str(v) => Some(v), + _ => None, + } + } + + #[cfg(test)] + pub fn to_test_token(&self) -> Token { + match self { + Inner::None => Token::None, + Inner::Bool(v) => Token::Bool(*v), + Inner::Str(v) => Token::Str(*v), + Inner::Char(v) => Token::Char(*v), + Inner::I64(v) => Token::I64(*v), + Inner::U64(v) => Token::U64(*v), + Inner::F64(v) => Token::F64(*v), + Inner::I128(_) => unimplemented!(), + Inner::U128(_) => unimplemented!(), + Inner::Debug(_) => unimplemented!(), + Inner::Display(_) => unimplemented!(), + } + } + } + + #[cfg(test)] + #[derive(Debug, PartialEq)] + pub enum Token<'v> { + None, + Bool(bool), + Char(char), + Str(&'v str), + F64(f64), + I64(i64), + U64(u64), + } + + pub fn visit<'v>( + inner: &Inner<'v>, + mut visitor: impl VisitValue<'v>, + ) -> Result<(), crate::kv::Error> { + match inner { + Inner::None => visitor.visit_null(), + Inner::Bool(v) => visitor.visit_bool(*v), + Inner::Str(v) => visitor.visit_borrowed_str(*v), + Inner::Char(v) => visitor.visit_char(*v), + Inner::I64(v) => visitor.visit_i64(*v), + Inner::U64(v) => visitor.visit_u64(*v), + Inner::F64(v) => visitor.visit_f64(*v), + Inner::I128(v) => visitor.visit_i128(*v), + Inner::U128(v) => visitor.visit_u128(*v), + Inner::Debug(v) => visitor.visit_any(Value::from_dyn_debug(*v)), + Inner::Display(v) => visitor.visit_any(Value::from_dyn_display(*v)), + } + } +} + +impl<'v> Value<'v> { + /// Get a value from a type implementing `std::fmt::Debug`. + #[cfg(feature = "kv_unstable")] + #[deprecated(note = "use `from_debug` instead")] + pub fn capture_debug(value: &'v T) -> Self + where + T: fmt::Debug + 'static, + { + Value::from_debug(value) + } + + /// Get a value from a type implementing `std::fmt::Display`. + #[cfg(feature = "kv_unstable")] + #[deprecated(note = "use `from_display` instead")] + pub fn capture_display(value: &'v T) -> Self + where + T: fmt::Display + 'static, + { + Value::from_display(value) + } + + /// Get a value from an error. + #[cfg(feature = "kv_unstable_std")] + #[deprecated(note = "use `from_dyn_error` instead")] + pub fn capture_error(err: &'v T) -> Self + where + T: std::error::Error + 'static, + { + Value::from_dyn_error(err) + } + + /// Get a value from a type implementing `serde::Serialize`. + #[cfg(feature = "kv_unstable_serde")] + #[deprecated(note = "use `from_serde` instead")] + pub fn capture_serde(value: &'v T) -> Self + where + T: serde_core::Serialize + 'static, + { + Value::from_serde(value) + } + + /// Get a value from a type implementing `sval::Value`. + #[cfg(feature = "kv_unstable_sval")] + #[deprecated(note = "use `from_sval` instead")] + pub fn capture_sval(value: &'v T) -> Self + where + T: sval::Value + 'static, + { + Value::from_sval(value) + } + + /// Check whether this value can be downcast to `T`. + #[cfg(feature = "kv_unstable")] + #[deprecated( + note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" + )] + pub fn is(&self) -> bool { + false + } + + /// Try downcast this value to `T`. + #[cfg(feature = "kv_unstable")] + #[deprecated( + note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" + )] + pub fn downcast_ref(&self) -> Option<&T> { + None + } +} + +// NOTE: Deprecated; but aliases can't carry this attribute +#[cfg(feature = "kv_unstable")] +pub use VisitValue as Visit; + +/// Get a value from a type implementing `std::fmt::Debug`. +#[cfg(feature = "kv_unstable")] +#[deprecated(note = "use the `key:? = value` macro syntax instead")] +#[macro_export] +macro_rules! as_debug { + ($capture:expr) => { + $crate::kv::Value::from_debug(&$capture) + }; +} + +/// Get a value from a type implementing `std::fmt::Display`. +#[cfg(feature = "kv_unstable")] +#[deprecated(note = "use the `key:% = value` macro syntax instead")] +#[macro_export] +macro_rules! as_display { + ($capture:expr) => { + $crate::kv::Value::from_display(&$capture) + }; +} + +/// Get a value from an error. +#[cfg(feature = "kv_unstable_std")] +#[deprecated(note = "use the `key:err = value` macro syntax instead")] +#[macro_export] +macro_rules! as_error { + ($capture:expr) => { + $crate::kv::Value::from_dyn_error(&$capture) + }; +} + +#[cfg(feature = "kv_unstable_serde")] +#[deprecated(note = "use the `key:serde = value` macro syntax instead")] +/// Get a value from a type implementing `serde::Serialize`. +#[macro_export] +macro_rules! as_serde { + ($capture:expr) => { + $crate::kv::Value::from_serde(&$capture) + }; +} + +/// Get a value from a type implementing `sval::Value`. +#[cfg(feature = "kv_unstable_sval")] +#[deprecated(note = "use the `key:sval = value` macro syntax instead")] +#[macro_export] +macro_rules! as_sval { + ($capture:expr) => { + $crate::kv::Value::from_sval(&$capture) + }; +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + impl<'v> Value<'v> { + pub(crate) fn to_token(&self) -> inner::Token { + self.inner.to_test_token() + } + } + + fn unsigned() -> impl Iterator> { + vec![ + Value::from(8u8), + Value::from(16u16), + Value::from(32u32), + Value::from(64u64), + Value::from(1usize), + Value::from(std::num::NonZeroU8::new(8).unwrap()), + Value::from(std::num::NonZeroU16::new(16).unwrap()), + Value::from(std::num::NonZeroU32::new(32).unwrap()), + Value::from(std::num::NonZeroU64::new(64).unwrap()), + Value::from(std::num::NonZeroUsize::new(1).unwrap()), + ] + .into_iter() + } + + fn signed() -> impl Iterator> { + vec![ + Value::from(-8i8), + Value::from(-16i16), + Value::from(-32i32), + Value::from(-64i64), + Value::from(-1isize), + Value::from(std::num::NonZeroI8::new(-8).unwrap()), + Value::from(std::num::NonZeroI16::new(-16).unwrap()), + Value::from(std::num::NonZeroI32::new(-32).unwrap()), + Value::from(std::num::NonZeroI64::new(-64).unwrap()), + Value::from(std::num::NonZeroIsize::new(-1).unwrap()), + ] + .into_iter() + } + + fn float() -> impl Iterator> { + vec![Value::from(32.32f32), Value::from(64.64f64)].into_iter() + } + + fn bool() -> impl Iterator> { + vec![Value::from(true), Value::from(false)].into_iter() + } + + fn str() -> impl Iterator> { + vec![Value::from("a string"), Value::from("a loong string")].into_iter() + } + + fn char() -> impl Iterator> { + vec![Value::from('a'), Value::from('⛰')].into_iter() + } + + #[test] + fn test_to_value_display() { + assert_eq!(42u64.to_value().to_string(), "42"); + assert_eq!(42i64.to_value().to_string(), "42"); + assert_eq!(42.01f64.to_value().to_string(), "42.01"); + assert_eq!(true.to_value().to_string(), "true"); + assert_eq!('a'.to_value().to_string(), "a"); + assert_eq!("a loong string".to_value().to_string(), "a loong string"); + assert_eq!(Some(true).to_value().to_string(), "true"); + assert_eq!(().to_value().to_string(), "None"); + assert_eq!(None::.to_value().to_string(), "None"); + } + + #[test] + fn test_to_value_structured() { + assert_eq!(42u64.to_value().to_token(), inner::Token::U64(42)); + assert_eq!(42i64.to_value().to_token(), inner::Token::I64(42)); + assert_eq!(42.01f64.to_value().to_token(), inner::Token::F64(42.01)); + assert_eq!(true.to_value().to_token(), inner::Token::Bool(true)); + assert_eq!('a'.to_value().to_token(), inner::Token::Char('a')); + assert_eq!( + "a loong string".to_value().to_token(), + inner::Token::Str("a loong string".into()) + ); + assert_eq!(Some(true).to_value().to_token(), inner::Token::Bool(true)); + assert_eq!(().to_value().to_token(), inner::Token::None); + assert_eq!(None::.to_value().to_token(), inner::Token::None); + } + + #[test] + fn test_to_number() { + for v in unsigned() { + assert!(v.to_u64().is_some()); + assert!(v.to_i64().is_some()); + } + + for v in signed() { + assert!(v.to_i64().is_some()); + } + + for v in unsigned().chain(signed()).chain(float()) { + assert!(v.to_f64().is_some()); + } + + for v in bool().chain(str()).chain(char()) { + assert!(v.to_u64().is_none()); + assert!(v.to_i64().is_none()); + assert!(v.to_f64().is_none()); + } + } + + #[test] + fn test_to_float() { + // Only integers from i32::MIN..=u32::MAX can be converted into floats + assert!(Value::from(i32::MIN).to_f64().is_some()); + assert!(Value::from(u32::MAX).to_f64().is_some()); + + assert!(Value::from((i32::MIN as i64) - 1).to_f64().is_none()); + assert!(Value::from((u32::MAX as u64) + 1).to_f64().is_none()); + } + + #[test] + fn test_to_cow_str() { + for v in str() { + assert!(v.to_borrowed_str().is_some()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_some()); + } + + let short_lived = String::from("short lived"); + let v = Value::from(&*short_lived); + + assert!(v.to_borrowed_str().is_some()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_some()); + + for v in unsigned().chain(signed()).chain(float()).chain(bool()) { + assert!(v.to_borrowed_str().is_none()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_none()); + } + } + + #[test] + fn test_to_bool() { + for v in bool() { + assert!(v.to_bool().is_some()); + } + + for v in unsigned() + .chain(signed()) + .chain(float()) + .chain(str()) + .chain(char()) + { + assert!(v.to_bool().is_none()); + } + } + + #[test] + fn test_to_char() { + for v in char() { + assert!(v.to_char().is_some()); + } + + for v in unsigned() + .chain(signed()) + .chain(float()) + .chain(str()) + .chain(bool()) + { + assert!(v.to_char().is_none()); + } + } + + #[test] + fn test_visit_integer() { + struct Extract(Option); + + impl<'v> VisitValue<'v> for Extract { + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + unimplemented!("unexpected value: {value:?}") + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.0 = Some(value); + + Ok(()) + } + } + + let mut extract = Extract(None); + Value::from(42u64).visit(&mut extract).unwrap(); + + assert_eq!(Some(42), extract.0); + } + + #[test] + fn test_visit_borrowed_str() { + struct Extract<'v>(Option<&'v str>); + + impl<'v> VisitValue<'v> for Extract<'v> { + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + unimplemented!("unexpected value: {value:?}") + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.0 = Some(value); + + Ok(()) + } + } + + let mut extract = Extract(None); + + let short_lived = String::from("A short-lived string"); + Value::from(&*short_lived).visit(&mut extract).unwrap(); + + assert_eq!(Some("A short-lived string"), extract.0); + } +} diff --git a/deps/crates/vendor/log/src/lib.rs b/deps/crates/vendor/log/src/lib.rs new file mode 100644 index 00000000000000..0ad1b3d41e49a0 --- /dev/null +++ b/deps/crates/vendor/log/src/lib.rs @@ -0,0 +1,2010 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A lightweight logging facade. +//! +//! The `log` crate provides a single logging API that abstracts over the +//! actual logging implementation. Libraries can use the logging API provided +//! by this crate, and the consumer of those libraries can choose the logging +//! implementation that is most suitable for its use case. +//! +//! If no logging implementation is selected, the facade falls back to a "noop" +//! implementation that ignores all log messages. The overhead in this case +//! is very small - just an integer load, comparison and jump. +//! +//! A log request consists of a _target_, a _level_, and a _body_. A target is a +//! string which defaults to the module path of the location of the log request, +//! though that default may be overridden. Logger implementations typically use +//! the target to filter requests based on some user configuration. +//! +//! # Usage +//! +//! The basic use of the log crate is through the five logging macros: [`error!`], +//! [`warn!`], [`info!`], [`debug!`] and [`trace!`] +//! where `error!` represents the highest-priority log messages +//! and `trace!` the lowest. The log messages are filtered by configuring +//! the log level to exclude messages with a lower priority. +//! Each of these macros accept format strings similarly to [`println!`]. +//! +//! +//! [`error!`]: ./macro.error.html +//! [`warn!`]: ./macro.warn.html +//! [`info!`]: ./macro.info.html +//! [`debug!`]: ./macro.debug.html +//! [`trace!`]: ./macro.trace.html +//! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html +//! +//! Avoid writing expressions with side-effects in log statements. They may not be evaluated. +//! +//! ## In libraries +//! +//! Libraries should link only to the `log` crate, and use the provided +//! macros to log whatever information will be useful to downstream consumers. +//! +//! ### Examples +//! +//! ``` +//! # #[derive(Debug)] pub struct Yak(String); +//! # impl Yak { fn shave(&mut self, _: u32) {} } +//! # fn find_a_razor() -> Result { Ok(1) } +//! use log::{info, warn}; +//! +//! pub fn shave_the_yak(yak: &mut Yak) { +//! info!(target: "yak_events", "Commencing yak shaving for {yak:?}"); +//! +//! loop { +//! match find_a_razor() { +//! Ok(razor) => { +//! info!("Razor located: {razor}"); +//! yak.shave(razor); +//! break; +//! } +//! Err(err) => { +//! warn!("Unable to locate a razor: {err}, retrying"); +//! } +//! } +//! } +//! } +//! # fn main() {} +//! ``` +//! +//! ## In executables +//! +//! Executables should choose a logging implementation and initialize it early in the +//! runtime of the program. Logging implementations will typically include a +//! function to do this. Any log messages generated before +//! the implementation is initialized will be ignored. +//! +//! The executable itself may use the `log` crate to log as well. +//! +//! ### Warning +//! +//! The logging system may only be initialized once. +//! +//! ## Structured logging +//! +//! If you enable the `kv` feature you can associate structured values +//! with your log records. If we take the example from before, we can include +//! some additional context besides what's in the formatted message: +//! +//! ``` +//! # use serde::Serialize; +//! # #[derive(Debug, Serialize)] pub struct Yak(String); +//! # impl Yak { fn shave(&mut self, _: u32) {} } +//! # fn find_a_razor() -> Result { Ok(1) } +//! # #[cfg(feature = "kv_serde")] +//! # fn main() { +//! use log::{info, warn}; +//! +//! pub fn shave_the_yak(yak: &mut Yak) { +//! info!(target: "yak_events", yak:serde; "Commencing yak shaving"); +//! +//! loop { +//! match find_a_razor() { +//! Ok(razor) => { +//! info!(razor; "Razor located"); +//! yak.shave(razor); +//! break; +//! } +//! Err(e) => { +//! warn!(e:err; "Unable to locate a razor, retrying"); +//! } +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "kv_serde"))] +//! # fn main() {} +//! ``` +//! +//! See the [`kv`] module documentation for more details. +//! +//! # Available logging implementations +//! +//! In order to produce log output executables have to use +//! a logger implementation compatible with the facade. +//! There are many available implementations to choose from, +//! here are some of the most popular ones: +//! +//! * Simple minimal loggers: +//! * [env_logger] +//! * [colog] +//! * [simple_logger] +//! * [simplelog] +//! * [pretty_env_logger] +//! * [stderrlog] +//! * [flexi_logger] +//! * [call_logger] +//! * [std-logger] +//! * [structured-logger] +//! * [clang_log] +//! * [ftail] +//! * Complex configurable frameworks: +//! * [log4rs] +//! * [logforth] +//! * [fern] +//! * [spdlog-rs] +//! * Adaptors for other facilities: +//! * [syslog] +//! * [slog-stdlog] +//! * [systemd-journal-logger] +//! * [android_log] +//! * [win_dbg_logger] +//! * [db_logger] +//! * [log-to-defmt] +//! * [logcontrol-log] +//! * For WebAssembly binaries: +//! * [console_log] +//! * For dynamic libraries: +//! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries +//! * Utilities: +//! * [log_err] +//! * [log-reload] +//! * [alterable_logger] +//! +//! # Implementing a Logger +//! +//! Loggers implement the [`Log`] trait. Here's a very basic example that simply +//! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or +//! [`Info`][level_link] levels to stdout: +//! +//! ``` +//! use log::{Record, Level, Metadata}; +//! +//! struct SimpleLogger; +//! +//! impl log::Log for SimpleLogger { +//! fn enabled(&self, metadata: &Metadata) -> bool { +//! metadata.level() <= Level::Info +//! } +//! +//! fn log(&self, record: &Record) { +//! if self.enabled(record.metadata()) { +//! println!("{} - {}", record.level(), record.args()); +//! } +//! } +//! +//! fn flush(&self) {} +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Loggers are installed by calling the [`set_logger`] function. The maximum +//! log level also needs to be adjusted via the [`set_max_level`] function. The +//! logging facade uses this as an optimization to improve performance of log +//! messages at levels that are disabled. It's important to set it, as it +//! defaults to [`Off`][filter_link], so no log messages will ever be captured! +//! In the case of our example logger, we'll want to set the maximum log level +//! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or +//! [`Trace`][level_link] level log messages. A logging implementation should +//! provide a function that wraps a call to [`set_logger`] and +//! [`set_max_level`], handling initialization of the logger: +//! +//! ``` +//! # use log::{Level, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! use log::{SetLoggerError, LevelFilter}; +//! +//! static LOGGER: SimpleLogger = SimpleLogger; +//! +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_logger(&LOGGER) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! Implementations that adjust their configurations at runtime should take care +//! to adjust the maximum log level as well. +//! +//! # Use with `std` +//! +//! `set_logger` requires you to provide a `&'static Log`, which can be hard to +//! obtain if your logger depends on some runtime configuration. The +//! `set_boxed_logger` function is available with the `std` Cargo feature. It is +//! identical to `set_logger` except that it takes a `Box` rather than a +//! `&'static Log`: +//! +//! ``` +//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! # #[cfg(feature = "std")] +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_boxed_logger(Box::new(SimpleLogger)) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! # Compile time filters +//! +//! Log levels can be statically disabled at compile time by enabling one of these Cargo features: +//! +//! * `max_level_off` +//! * `max_level_error` +//! * `max_level_warn` +//! * `max_level_info` +//! * `max_level_debug` +//! * `max_level_trace` +//! +//! Log invocations at disabled levels will be skipped and will not even be present in the +//! resulting binary. These features control the value of the `STATIC_MAX_LEVEL` constant. The +//! logging macros check this value before logging a message. By default, no levels are disabled. +//! +//! It is possible to override this level for release builds only with the following features: +//! +//! * `release_max_level_off` +//! * `release_max_level_error` +//! * `release_max_level_warn` +//! * `release_max_level_info` +//! * `release_max_level_debug` +//! * `release_max_level_trace` +//! +//! Libraries should avoid using the max level features because they're global and can't be changed +//! once they're set. +//! +//! For example, a crate can disable trace level logs in debug builds and trace, debug, and info +//! level logs in release builds with the following configuration: +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] } +//! ``` +//! # Crate Feature Flags +//! +//! The following crate feature flags are available in addition to the filters. They are +//! configured in your `Cargo.toml`. +//! +//! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and +//! `set_boxed_logger` functionality. +//! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`. +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["std", "serde"] } +//! ``` +//! +//! # Version compatibility +//! +//! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages +//! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log +//! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the +//! module path and file name information associated with the message will unfortunately be lost. +//! +//! [`Log`]: trait.Log.html +//! [level_link]: enum.Level.html +//! [filter_link]: enum.LevelFilter.html +//! [`set_logger`]: fn.set_logger.html +//! [`set_max_level`]: fn.set_max_level.html +//! [`try_set_logger_raw`]: fn.try_set_logger_raw.html +//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html +//! [env_logger]: https://docs.rs/env_logger/*/env_logger/ +//! [colog]: https://docs.rs/colog/*/colog/ +//! [simple_logger]: https://github.com/borntyping/rust-simple_logger +//! [simplelog]: https://github.com/drakulix/simplelog.rs +//! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/ +//! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/ +//! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/ +//! [call_logger]: https://docs.rs/call_logger/*/call_logger/ +//! [std-logger]: https://docs.rs/std-logger/*/std_logger/ +//! [syslog]: https://docs.rs/syslog/*/syslog/ +//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/ +//! [log4rs]: https://docs.rs/log4rs/*/log4rs/ +//! [logforth]: https://docs.rs/logforth/*/logforth/ +//! [fern]: https://docs.rs/fern/*/fern/ +//! [spdlog-rs]: https://docs.rs/spdlog-rs/*/spdlog/ +//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/ +//! [android_log]: https://docs.rs/android_log/*/android_log/ +//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/ +//! [db_logger]: https://docs.rs/db_logger/*/db_logger/ +//! [log-to-defmt]: https://docs.rs/log-to-defmt/*/log_to_defmt/ +//! [console_log]: https://docs.rs/console_log/*/console_log/ +//! [structured-logger]: https://docs.rs/structured-logger/latest/structured_logger/ +//! [logcontrol-log]: https://docs.rs/logcontrol-log/*/logcontrol_log/ +//! [log_err]: https://docs.rs/log_err/*/log_err/ +//! [log-reload]: https://docs.rs/log-reload/*/log_reload/ +//! [alterable_logger]: https://docs.rs/alterable_logger/*/alterable_logger +//! [clang_log]: https://docs.rs/clang_log/latest/clang_log +//! [ftail]: https://docs.rs/ftail/latest/ftail + +#![doc( + html_logo_url = "https://prev.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://prev.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/log/0.4.29" +)] +#![warn(missing_docs)] +#![deny(missing_debug_implementations, unconditional_recursion)] +#![cfg_attr(all(not(feature = "std"), not(test)), no_std)] + +#[cfg(any( + all(feature = "max_level_off", feature = "max_level_error"), + all(feature = "max_level_off", feature = "max_level_warn"), + all(feature = "max_level_off", feature = "max_level_info"), + all(feature = "max_level_off", feature = "max_level_debug"), + all(feature = "max_level_off", feature = "max_level_trace"), + all(feature = "max_level_error", feature = "max_level_warn"), + all(feature = "max_level_error", feature = "max_level_info"), + all(feature = "max_level_error", feature = "max_level_debug"), + all(feature = "max_level_error", feature = "max_level_trace"), + all(feature = "max_level_warn", feature = "max_level_info"), + all(feature = "max_level_warn", feature = "max_level_debug"), + all(feature = "max_level_warn", feature = "max_level_trace"), + all(feature = "max_level_info", feature = "max_level_debug"), + all(feature = "max_level_info", feature = "max_level_trace"), + all(feature = "max_level_debug", feature = "max_level_trace"), +))] +compile_error!("multiple max_level_* features set"); + +#[rustfmt::skip] +#[cfg(any( + all(feature = "release_max_level_off", feature = "release_max_level_error"), + all(feature = "release_max_level_off", feature = "release_max_level_warn"), + all(feature = "release_max_level_off", feature = "release_max_level_info"), + all(feature = "release_max_level_off", feature = "release_max_level_debug"), + all(feature = "release_max_level_off", feature = "release_max_level_trace"), + all(feature = "release_max_level_error", feature = "release_max_level_warn"), + all(feature = "release_max_level_error", feature = "release_max_level_info"), + all(feature = "release_max_level_error", feature = "release_max_level_debug"), + all(feature = "release_max_level_error", feature = "release_max_level_trace"), + all(feature = "release_max_level_warn", feature = "release_max_level_info"), + all(feature = "release_max_level_warn", feature = "release_max_level_debug"), + all(feature = "release_max_level_warn", feature = "release_max_level_trace"), + all(feature = "release_max_level_info", feature = "release_max_level_debug"), + all(feature = "release_max_level_info", feature = "release_max_level_trace"), + all(feature = "release_max_level_debug", feature = "release_max_level_trace"), +))] +compile_error!("multiple release_max_level_* features set"); + +#[cfg(all(not(feature = "std"), not(test)))] +extern crate core as std; + +use std::cfg; +#[cfg(feature = "std")] +use std::error; +use std::str::FromStr; +use std::{cmp, fmt, mem}; + +#[macro_use] +mod macros; +mod serde; + +#[cfg(feature = "kv")] +pub mod kv; + +#[cfg(target_has_atomic = "ptr")] +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[cfg(not(target_has_atomic = "ptr"))] +use std::cell::Cell; +#[cfg(not(target_has_atomic = "ptr"))] +use std::sync::atomic::Ordering; + +#[cfg(not(target_has_atomic = "ptr"))] +struct AtomicUsize { + v: Cell, +} + +#[cfg(not(target_has_atomic = "ptr"))] +impl AtomicUsize { + const fn new(v: usize) -> AtomicUsize { + AtomicUsize { v: Cell::new(v) } + } + + fn load(&self, _order: Ordering) -> usize { + self.v.get() + } + + fn store(&self, val: usize, _order: Ordering) { + self.v.set(val) + } +} + +// Any platform without atomics is unlikely to have multiple cores, so +// writing via Cell will not be a race condition. +#[cfg(not(target_has_atomic = "ptr"))] +unsafe impl Sync for AtomicUsize {} + +// The LOGGER static holds a pointer to the global logger. It is protected by +// the STATE static which determines whether LOGGER has been initialized yet. +static mut LOGGER: &dyn Log = &NopLogger; + +static STATE: AtomicUsize = AtomicUsize::new(0); + +// There are three different states that we care about: the logger's +// uninitialized, the logger's initializing (set_logger's been called but +// LOGGER hasn't actually been set yet), or the logger's active. +const UNINITIALIZED: usize = 0; +const INITIALIZING: usize = 1; +const INITIALIZED: usize = 2; + +static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0); + +static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; + +static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \ + was already initialized"; +static LEVEL_PARSE_ERROR: &str = + "attempted to convert a string that doesn't match an existing log level"; + +/// An enum representing the available verbosity levels of the logger. +/// +/// Typical usage includes: checking if a certain `Level` is enabled with +/// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of +/// [`log!`](macro.log.html), and comparing a `Level` directly to a +/// [`LevelFilter`](enum.LevelFilter.html). +#[repr(usize)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Level { + /// The "error" level. + /// + /// Designates very serious errors. + // This way these line up with the discriminants for LevelFilter below + // This works because Rust treats field-less enums the same way as C does: + // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations + Error = 1, + /// The "warn" level. + /// + /// Designates hazardous situations. + Warn, + /// The "info" level. + /// + /// Designates useful information. + Info, + /// The "debug" level. + /// + /// Designates lower priority information. + Debug, + /// The "trace" level. + /// + /// Designates very low priority, often extremely verbose, information. + Trace, +} + +impl PartialEq for Level { + #[inline] + fn eq(&self, other: &LevelFilter) -> bool { + *self as usize == *other as usize + } +} + +impl PartialOrd for Level { + #[inline] + fn partial_cmp(&self, other: &LevelFilter) -> Option { + Some((*self as usize).cmp(&(*other as usize))) + } +} + +impl FromStr for Level { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result { + // iterate from 1, excluding "OFF" + for idx in 1..LOG_LEVEL_NAMES.len() { + if LOG_LEVEL_NAMES[idx].eq_ignore_ascii_case(level) { + return Ok(Level::from_usize(idx).unwrap()); + } + } + Err(ParseLevelError(())) + } +} + +impl fmt::Display for Level { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.pad(self.as_str()) + } +} + +impl Level { + fn from_usize(u: usize) -> Option { + match u { + 1 => Some(Level::Error), + 2 => Some(Level::Warn), + 3 => Some(Level::Info), + 4 => Some(Level::Debug), + 5 => Some(Level::Trace), + _ => None, + } + } + + /// Returns the most verbose logging level. + #[inline] + pub fn max() -> Level { + Level::Trace + } + + /// Converts the `Level` to the equivalent `LevelFilter`. + #[inline] + pub fn to_level_filter(&self) -> LevelFilter { + LevelFilter::from_usize(*self as usize).unwrap() + } + + /// Returns the string representation of the `Level`. + /// + /// This returns the same string as the `fmt::Display` implementation. + pub fn as_str(&self) -> &'static str { + LOG_LEVEL_NAMES[*self as usize] + } + + /// Iterate through all supported logging levels. + /// + /// The order of iteration is from more severe to less severe log messages. + /// + /// # Examples + /// + /// ``` + /// use log::Level; + /// + /// let mut levels = Level::iter(); + /// + /// assert_eq!(Some(Level::Error), levels.next()); + /// assert_eq!(Some(Level::Trace), levels.last()); + /// ``` + pub fn iter() -> impl Iterator { + (1..6).map(|i| Self::from_usize(i).unwrap()) + } + + /// Get the next-highest `Level` from this one. + /// + /// If the current `Level` is at the highest level, the returned `Level` will be the same as the + /// current one. + /// + /// # Examples + /// + /// ``` + /// use log::Level; + /// + /// let level = Level::Info; + /// + /// assert_eq!(Level::Debug, level.increment_severity()); + /// assert_eq!(Level::Trace, level.increment_severity().increment_severity()); + /// assert_eq!(Level::Trace, level.increment_severity().increment_severity().increment_severity()); // max level + /// ``` + pub fn increment_severity(&self) -> Self { + let current = *self as usize; + Self::from_usize(current + 1).unwrap_or(*self) + } + + /// Get the next-lowest `Level` from this one. + /// + /// If the current `Level` is at the lowest level, the returned `Level` will be the same as the + /// current one. + /// + /// # Examples + /// + /// ``` + /// use log::Level; + /// + /// let level = Level::Info; + /// + /// assert_eq!(Level::Warn, level.decrement_severity()); + /// assert_eq!(Level::Error, level.decrement_severity().decrement_severity()); + /// assert_eq!(Level::Error, level.decrement_severity().decrement_severity().decrement_severity()); // min level + /// ``` + pub fn decrement_severity(&self) -> Self { + let current = *self as usize; + Self::from_usize(current.saturating_sub(1)).unwrap_or(*self) + } +} + +/// An enum representing the available verbosity level filters of the logger. +/// +/// A `LevelFilter` may be compared directly to a [`Level`]. Use this type +/// to get and set the maximum log level with [`max_level()`] and [`set_max_level`]. +/// +/// [`Level`]: enum.Level.html +/// [`max_level()`]: fn.max_level.html +/// [`set_max_level`]: fn.set_max_level.html +#[repr(usize)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum LevelFilter { + /// A level lower than all log levels. + Off, + /// Corresponds to the `Error` log level. + Error, + /// Corresponds to the `Warn` log level. + Warn, + /// Corresponds to the `Info` log level. + Info, + /// Corresponds to the `Debug` log level. + Debug, + /// Corresponds to the `Trace` log level. + Trace, +} + +impl PartialEq for LevelFilter { + #[inline] + fn eq(&self, other: &Level) -> bool { + other.eq(self) + } +} + +impl PartialOrd for LevelFilter { + #[inline] + fn partial_cmp(&self, other: &Level) -> Option { + Some((*self as usize).cmp(&(*other as usize))) + } +} + +impl FromStr for LevelFilter { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result { + // iterate from 0, including "OFF" + for idx in 0..LOG_LEVEL_NAMES.len() { + if LOG_LEVEL_NAMES[idx].eq_ignore_ascii_case(level) { + return Ok(LevelFilter::from_usize(idx).unwrap()); + } + } + Err(ParseLevelError(())) + } +} + +impl fmt::Display for LevelFilter { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.pad(self.as_str()) + } +} + +impl LevelFilter { + fn from_usize(u: usize) -> Option { + match u { + 0 => Some(LevelFilter::Off), + 1 => Some(LevelFilter::Error), + 2 => Some(LevelFilter::Warn), + 3 => Some(LevelFilter::Info), + 4 => Some(LevelFilter::Debug), + 5 => Some(LevelFilter::Trace), + _ => None, + } + } + + /// Returns the most verbose logging level filter. + #[inline] + pub fn max() -> LevelFilter { + LevelFilter::Trace + } + + /// Converts `self` to the equivalent `Level`. + /// + /// Returns `None` if `self` is `LevelFilter::Off`. + #[inline] + pub fn to_level(&self) -> Option { + Level::from_usize(*self as usize) + } + + /// Returns the string representation of the `LevelFilter`. + /// + /// This returns the same string as the `fmt::Display` implementation. + pub fn as_str(&self) -> &'static str { + LOG_LEVEL_NAMES[*self as usize] + } + + /// Iterate through all supported filtering levels. + /// + /// The order of iteration is from less to more verbose filtering. + /// + /// # Examples + /// + /// ``` + /// use log::LevelFilter; + /// + /// let mut levels = LevelFilter::iter(); + /// + /// assert_eq!(Some(LevelFilter::Off), levels.next()); + /// assert_eq!(Some(LevelFilter::Trace), levels.last()); + /// ``` + pub fn iter() -> impl Iterator { + (0..6).map(|i| Self::from_usize(i).unwrap()) + } + + /// Get the next-highest `LevelFilter` from this one. + /// + /// If the current `LevelFilter` is at the highest level, the returned `LevelFilter` will be the + /// same as the current one. + /// + /// # Examples + /// + /// ``` + /// use log::LevelFilter; + /// + /// let level_filter = LevelFilter::Info; + /// + /// assert_eq!(LevelFilter::Debug, level_filter.increment_severity()); + /// assert_eq!(LevelFilter::Trace, level_filter.increment_severity().increment_severity()); + /// assert_eq!(LevelFilter::Trace, level_filter.increment_severity().increment_severity().increment_severity()); // max level + /// ``` + pub fn increment_severity(&self) -> Self { + let current = *self as usize; + Self::from_usize(current + 1).unwrap_or(*self) + } + + /// Get the next-lowest `LevelFilter` from this one. + /// + /// If the current `LevelFilter` is at the lowest level, the returned `LevelFilter` will be the + /// same as the current one. + /// + /// # Examples + /// + /// ``` + /// use log::LevelFilter; + /// + /// let level_filter = LevelFilter::Info; + /// + /// assert_eq!(LevelFilter::Warn, level_filter.decrement_severity()); + /// assert_eq!(LevelFilter::Error, level_filter.decrement_severity().decrement_severity()); + /// assert_eq!(LevelFilter::Off, level_filter.decrement_severity().decrement_severity().decrement_severity()); + /// assert_eq!(LevelFilter::Off, level_filter.decrement_severity().decrement_severity().decrement_severity().decrement_severity()); // min level + /// ``` + pub fn decrement_severity(&self) -> Self { + let current = *self as usize; + Self::from_usize(current.saturating_sub(1)).unwrap_or(*self) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), +} + +impl<'a> MaybeStaticStr<'a> { + #[inline] + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Static(s) => s, + MaybeStaticStr::Borrowed(s) => s, + } + } +} + +/// The "payload" of a log message. +/// +/// # Use +/// +/// `Record` structures are passed as parameters to the [`log`][method.log] +/// method of the [`Log`] trait. Logger implementors manipulate these +/// structures in order to display log messages. `Record`s are automatically +/// created by the [`log!`] macro and so are not seen by log users. +/// +/// Note that the [`level()`] and [`target()`] accessors are equivalent to +/// `self.metadata().level()` and `self.metadata().target()` respectively. +/// These methods are provided as a convenience for users of this structure. +/// +/// # Example +/// +/// The following example shows a simple logger that displays the level, +/// module path, and message of any `Record` that is passed to it. +/// +/// ``` +/// struct SimpleLogger; +/// +/// impl log::Log for SimpleLogger { +/// fn enabled(&self, _metadata: &log::Metadata) -> bool { +/// true +/// } +/// +/// fn log(&self, record: &log::Record) { +/// if !self.enabled(record.metadata()) { +/// return; +/// } +/// +/// println!("{}:{} -- {}", +/// record.level(), +/// record.target(), +/// record.args()); +/// } +/// fn flush(&self) {} +/// } +/// ``` +/// +/// [method.log]: trait.Log.html#tymethod.log +/// [`Log`]: trait.Log.html +/// [`log!`]: macro.log.html +/// [`level()`]: struct.Record.html#method.level +/// [`target()`]: struct.Record.html#method.target +#[derive(Clone, Debug)] +pub struct Record<'a> { + metadata: Metadata<'a>, + args: fmt::Arguments<'a>, + module_path: Option>, + file: Option>, + line: Option, + #[cfg(feature = "kv")] + key_values: KeyValues<'a>, +} + +// This wrapper type is only needed so we can +// `#[derive(Debug)]` on `Record`. It also +// provides a useful `Debug` implementation for +// the underlying `Source`. +#[cfg(feature = "kv")] +#[derive(Clone)] +struct KeyValues<'a>(&'a dyn kv::Source); + +#[cfg(feature = "kv")] +impl<'a> fmt::Debug for KeyValues<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut visitor = f.debug_map(); + self.0.visit(&mut visitor).map_err(|_| fmt::Error)?; + visitor.finish() + } +} + +impl<'a> Record<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> RecordBuilder<'a> { + RecordBuilder::new() + } + + /// The message body. + #[inline] + pub fn args(&self) -> &fmt::Arguments<'a> { + &self.args + } + + /// Metadata about the log directive. + #[inline] + pub fn metadata(&self) -> &Metadata<'a> { + &self.metadata + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.metadata.level() + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.metadata.target() + } + + /// The module path of the message. + #[inline] + pub fn module_path(&self) -> Option<&'a str> { + self.module_path.map(|s| s.get()) + } + + /// The module path of the message, if it is a `'static` string. + #[inline] + pub fn module_path_static(&self) -> Option<&'static str> { + match self.module_path { + Some(MaybeStaticStr::Static(s)) => Some(s), + _ => None, + } + } + + /// The source file containing the message. + #[inline] + pub fn file(&self) -> Option<&'a str> { + self.file.map(|s| s.get()) + } + + /// The source file containing the message, if it is a `'static` string. + #[inline] + pub fn file_static(&self) -> Option<&'static str> { + match self.file { + Some(MaybeStaticStr::Static(s)) => Some(s), + _ => None, + } + } + + /// The line containing the message. + #[inline] + pub fn line(&self) -> Option { + self.line + } + + /// The structured key-value pairs associated with the message. + #[cfg(feature = "kv")] + #[inline] + pub fn key_values(&self) -> &dyn kv::Source { + self.key_values.0 + } + + /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record. + #[cfg(feature = "kv")] + #[inline] + pub fn to_builder(&self) -> RecordBuilder<'_> { + RecordBuilder { + record: Record { + metadata: Metadata { + level: self.metadata.level, + target: self.metadata.target, + }, + args: self.args, + module_path: self.module_path, + file: self.file, + line: self.line, + key_values: self.key_values.clone(), + }, + } + } +} + +/// Builder for [`Record`](struct.Record.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `RecordBuilder` can set the different parameters of `Record` object, and returns +/// the created object when `build` is called. +/// +/// # Examples +/// +/// ``` +/// use log::{Level, Record}; +/// +/// let record = Record::builder() +/// .args(format_args!("Error!")) +/// .level(Level::Error) +/// .target("myApp") +/// .file(Some("server.rs")) +/// .line(Some(144)) +/// .module_path(Some("server")) +/// .build(); +/// ``` +/// +/// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html): +/// +/// ``` +/// use log::{Record, Level, MetadataBuilder}; +/// +/// let error_metadata = MetadataBuilder::new() +/// .target("myApp") +/// .level(Level::Error) +/// .build(); +/// +/// let record = Record::builder() +/// .metadata(error_metadata) +/// .args(format_args!("Error!")) +/// .line(Some(433)) +/// .file(Some("app.rs")) +/// .module_path(Some("server")) +/// .build(); +/// ``` +#[derive(Debug)] +pub struct RecordBuilder<'a> { + record: Record<'a>, +} + +impl<'a> RecordBuilder<'a> { + /// Construct new `RecordBuilder`. + /// + /// The default options are: + /// + /// - `args`: [`format_args!("")`] + /// - `metadata`: [`Metadata::builder().build()`] + /// - `module_path`: `None` + /// - `file`: `None` + /// - `line`: `None` + /// + /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html + /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build + #[inline] + pub fn new() -> RecordBuilder<'a> { + RecordBuilder { + record: Record { + args: format_args!(""), + metadata: Metadata::builder().build(), + module_path: None, + file: None, + line: None, + #[cfg(feature = "kv")] + key_values: KeyValues(&None::<(kv::Key, kv::Value)>), + }, + } + } + + /// Set [`args`](struct.Record.html#method.args). + #[inline] + pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> { + self.record.args = args; + self + } + + /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html). + #[inline] + pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> { + self.record.metadata = metadata; + self + } + + /// Set [`Metadata::level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> { + self.record.metadata.level = level; + self + } + + /// Set [`Metadata::target`](struct.Metadata.html#method.target) + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> { + self.record.metadata.target = target; + self + } + + /// Set [`module_path`](struct.Record.html#method.module_path) + #[inline] + pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.module_path = path.map(MaybeStaticStr::Borrowed); + self + } + + /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string + #[inline] + pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> { + self.record.module_path = path.map(MaybeStaticStr::Static); + self + } + + /// Set [`file`](struct.Record.html#method.file) + #[inline] + pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.file = file.map(MaybeStaticStr::Borrowed); + self + } + + /// Set [`file`](struct.Record.html#method.file) to a `'static` string. + #[inline] + pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> { + self.record.file = file.map(MaybeStaticStr::Static); + self + } + + /// Set [`line`](struct.Record.html#method.line) + #[inline] + pub fn line(&mut self, line: Option) -> &mut RecordBuilder<'a> { + self.record.line = line; + self + } + + /// Set [`key_values`](struct.Record.html#method.key_values) + #[cfg(feature = "kv")] + #[inline] + pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> { + self.record.key_values = KeyValues(kvs); + self + } + + /// Invoke the builder and return a `Record` + #[inline] + pub fn build(&self) -> Record<'a> { + self.record.clone() + } +} + +impl Default for RecordBuilder<'_> { + fn default() -> Self { + Self::new() + } +} + +/// Metadata about a log message. +/// +/// # Use +/// +/// `Metadata` structs are created when users of the library use +/// logging macros. +/// +/// They are consumed by implementations of the `Log` trait in the +/// `enabled` method. +/// +/// `Record`s use `Metadata` to determine the log message's severity +/// and target. +/// +/// Users should use the `log_enabled!` macro in their code to avoid +/// constructing expensive log messages. +/// +/// # Examples +/// +/// ``` +/// use log::{Record, Level, Metadata}; +/// +/// struct MyLogger; +/// +/// impl log::Log for MyLogger { +/// fn enabled(&self, metadata: &Metadata) -> bool { +/// metadata.level() <= Level::Info +/// } +/// +/// fn log(&self, record: &Record) { +/// if self.enabled(record.metadata()) { +/// println!("{} - {}", record.level(), record.args()); +/// } +/// } +/// fn flush(&self) {} +/// } +/// +/// # fn main(){} +/// ``` +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Metadata<'a> { + level: Level, + target: &'a str, +} + +impl<'a> Metadata<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> MetadataBuilder<'a> { + MetadataBuilder::new() + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.level + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.target + } +} + +/// Builder for [`Metadata`](struct.Metadata.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns +/// the created object when `build` is called. +/// +/// # Example +/// +/// ``` +/// let target = "myApp"; +/// use log::{Level, MetadataBuilder}; +/// let metadata = MetadataBuilder::new() +/// .level(Level::Debug) +/// .target(target) +/// .build(); +/// ``` +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct MetadataBuilder<'a> { + metadata: Metadata<'a>, +} + +impl<'a> MetadataBuilder<'a> { + /// Construct a new `MetadataBuilder`. + /// + /// The default options are: + /// + /// - `level`: `Level::Info` + /// - `target`: `""` + #[inline] + pub fn new() -> MetadataBuilder<'a> { + MetadataBuilder { + metadata: Metadata { + level: Level::Info, + target: "", + }, + } + } + + /// Setter for [`level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> { + self.metadata.level = arg; + self + } + + /// Setter for [`target`](struct.Metadata.html#method.target). + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> { + self.metadata.target = target; + self + } + + /// Returns a `Metadata` object. + #[inline] + pub fn build(&self) -> Metadata<'a> { + self.metadata.clone() + } +} + +impl Default for MetadataBuilder<'_> { + fn default() -> Self { + Self::new() + } +} + +/// A trait encapsulating the operations required of a logger. +pub trait Log: Sync + Send { + /// Determines if a log message with the specified metadata would be + /// logged. + /// + /// This is used by the `log_enabled!` macro to allow callers to avoid + /// expensive computation of log message arguments if the message would be + /// discarded anyway. + /// + /// # For implementors + /// + /// This method isn't called automatically by the `log!` macros. + /// It's up to an implementation of the `Log` trait to call `enabled` in its own + /// `log` method implementation to guarantee that filtering is applied. + fn enabled(&self, metadata: &Metadata) -> bool; + + /// Logs the `Record`. + /// + /// # For implementors + /// + /// Note that `enabled` is *not* necessarily called before this method. + /// Implementations of `log` should perform all necessary filtering + /// internally. + fn log(&self, record: &Record); + + /// Flushes any buffered records. + /// + /// # For implementors + /// + /// This method isn't called automatically by the `log!` macros. + /// It can be called manually on shut-down to ensure any in-flight records are flushed. + fn flush(&self); +} + +/// A dummy initial value for LOGGER. +struct NopLogger; + +impl Log for NopLogger { + fn enabled(&self, _: &Metadata) -> bool { + false + } + + fn log(&self, _: &Record) {} + fn flush(&self) {} +} + +impl Log for &'_ T +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + (**self).enabled(metadata) + } + + fn log(&self, record: &Record) { + (**self).log(record); + } + fn flush(&self) { + (**self).flush(); + } +} + +#[cfg(feature = "std")] +impl Log for std::boxed::Box +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + self.as_ref().enabled(metadata) + } + + fn log(&self, record: &Record) { + self.as_ref().log(record); + } + fn flush(&self) { + self.as_ref().flush(); + } +} + +#[cfg(feature = "std")] +impl Log for std::sync::Arc +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + self.as_ref().enabled(metadata) + } + + fn log(&self, record: &Record) { + self.as_ref().log(record); + } + fn flush(&self) { + self.as_ref().flush(); + } +} + +/// Sets the global maximum log level. +/// +/// Generally, this should only be called by the active logging implementation. +/// +/// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs. +#[inline] +#[cfg(target_has_atomic = "ptr")] +pub fn set_max_level(level: LevelFilter) { + MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); +} + +/// A thread-unsafe version of [`set_max_level`]. +/// +/// This function is available on all platforms, even those that do not have +/// support for atomics that is needed by [`set_max_level`]. +/// +/// In almost all cases, [`set_max_level`] should be preferred. +/// +/// # Safety +/// +/// This function is only safe to call when it cannot race with any other +/// calls to `set_max_level` or `set_max_level_racy`. +/// +/// This can be upheld by (for example) making sure that **there are no other +/// threads**, and (on embedded) that **interrupts are disabled**. +/// +/// It is safe to use all other logging functions while this function runs +/// (including all logging macros). +/// +/// [`set_max_level`]: fn.set_max_level.html +#[inline] +pub unsafe fn set_max_level_racy(level: LevelFilter) { + // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a + // platform doesn't support `target_has_atomic = "ptr"`, so even though this looks the same + // as `set_max_level` it may have different safety properties. + MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); +} + +/// Returns the current maximum log level. +/// +/// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check +/// this value and discard any message logged at a higher level. The maximum +/// log level is set by the [`set_max_level`] function. +/// +/// [`log!`]: macro.log.html +/// [`error!`]: macro.error.html +/// [`warn!`]: macro.warn.html +/// [`info!`]: macro.info.html +/// [`debug!`]: macro.debug.html +/// [`trace!`]: macro.trace.html +/// [`set_max_level`]: fn.set_max_level.html +#[inline(always)] +pub fn max_level() -> LevelFilter { + // Since `LevelFilter` is `repr(usize)`, + // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER` + // is set to a usize that is a valid discriminant for `LevelFilter`. + // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set + // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`. + // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant. + unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } +} + +/// Sets the global logger to a `Box`. +/// +/// This is a simple convenience wrapper over `set_logger`, which takes a +/// `Box` rather than a `&'static Log`. See the documentation for +/// [`set_logger`] for more details. +/// +/// Requires the `std` feature. +/// +/// # Errors +/// +/// An error is returned if a logger has already been set. +/// +/// [`set_logger`]: fn.set_logger.html +#[cfg(all(feature = "std", target_has_atomic = "ptr"))] +pub fn set_boxed_logger(logger: Box) -> Result<(), SetLoggerError> { + set_logger_inner(|| Box::leak(logger)) +} + +/// Sets the global logger to a `&'static Log`. +/// +/// This function may only be called once in the lifetime of a program. Any log +/// events that occur before the call to `set_logger` completes will be ignored. +/// +/// This function does not typically need to be called manually. Logger +/// implementations should provide an initialization method that installs the +/// logger internally. +/// +/// # Availability +/// +/// This method is available even when the `std` feature is disabled. However, +/// it is currently unavailable on `thumbv6` targets, which lack support for +/// some atomic operations which are used by this function. Even on those +/// targets, [`set_logger_racy`] will be available. +/// +/// # Errors +/// +/// An error is returned if a logger has already been set. +/// +/// # Examples +/// +/// ``` +/// use log::{error, info, warn, Record, Level, Metadata, LevelFilter}; +/// +/// static MY_LOGGER: MyLogger = MyLogger; +/// +/// struct MyLogger; +/// +/// impl log::Log for MyLogger { +/// fn enabled(&self, metadata: &Metadata) -> bool { +/// metadata.level() <= Level::Info +/// } +/// +/// fn log(&self, record: &Record) { +/// if self.enabled(record.metadata()) { +/// println!("{} - {}", record.level(), record.args()); +/// } +/// } +/// fn flush(&self) {} +/// } +/// +/// # fn main(){ +/// log::set_logger(&MY_LOGGER).unwrap(); +/// log::set_max_level(LevelFilter::Info); +/// +/// info!("hello log"); +/// warn!("warning"); +/// error!("oops"); +/// # } +/// ``` +/// +/// [`set_logger_racy`]: fn.set_logger_racy.html +#[cfg(target_has_atomic = "ptr")] +pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> { + set_logger_inner(|| logger) +} + +#[cfg(target_has_atomic = "ptr")] +fn set_logger_inner(make_logger: F) -> Result<(), SetLoggerError> +where + F: FnOnce() -> &'static dyn Log, +{ + match STATE.compare_exchange( + UNINITIALIZED, + INITIALIZING, + Ordering::Acquire, + Ordering::Relaxed, + ) { + Ok(UNINITIALIZED) => { + unsafe { + LOGGER = make_logger(); + } + STATE.store(INITIALIZED, Ordering::Release); + Ok(()) + } + Err(INITIALIZING) => { + while STATE.load(Ordering::Relaxed) == INITIALIZING { + std::hint::spin_loop(); + } + Err(SetLoggerError(())) + } + _ => Err(SetLoggerError(())), + } +} + +/// A thread-unsafe version of [`set_logger`]. +/// +/// This function is available on all platforms, even those that do not have +/// support for atomics that is needed by [`set_logger`]. +/// +/// In almost all cases, [`set_logger`] should be preferred. +/// +/// # Safety +/// +/// This function is only safe to call when it cannot race with any other +/// calls to `set_logger` or `set_logger_racy`. +/// +/// This can be upheld by (for example) making sure that **there are no other +/// threads**, and (on embedded) that **interrupts are disabled**. +/// +/// It is safe to use other logging functions while this function runs +/// (including all logging macros). +/// +/// [`set_logger`]: fn.set_logger.html +pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> { + match STATE.load(Ordering::Acquire) { + UNINITIALIZED => { + LOGGER = logger; + STATE.store(INITIALIZED, Ordering::Release); + Ok(()) + } + INITIALIZING => { + // This is just plain UB, since we were racing another initialization function + unreachable!("set_logger_racy must not be used with other initialization functions") + } + _ => Err(SetLoggerError(())), + } +} + +/// The type returned by [`set_logger`] if [`set_logger`] has already been called. +/// +/// [`set_logger`]: fn.set_logger.html +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct SetLoggerError(()); + +impl fmt::Display for SetLoggerError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(SET_LOGGER_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for SetLoggerError {} + +/// The type returned by [`from_str`] when the string doesn't match any of the log levels. +/// +/// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str +#[allow(missing_copy_implementations)] +#[derive(Debug, PartialEq, Eq)] +pub struct ParseLevelError(()); + +impl fmt::Display for ParseLevelError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(LEVEL_PARSE_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for ParseLevelError {} + +/// Returns a reference to the logger. +/// +/// If a logger has not been set, a no-op implementation is returned. +pub fn logger() -> &'static dyn Log { + // Acquire memory ordering guarantees that current thread would see any + // memory writes that happened before store of the value + // into `STATE` with memory ordering `Release` or stronger. + // + // Since the value `INITIALIZED` is written only after `LOGGER` was + // initialized, observing it after `Acquire` load here makes both + // write to the `LOGGER` static and initialization of the logger + // internal state synchronized with current thread. + if STATE.load(Ordering::Acquire) != INITIALIZED { + static NOP: NopLogger = NopLogger; + &NOP + } else { + unsafe { LOGGER } + } +} + +// WARNING: this is not part of the crate's public API and is subject to change at any time +#[doc(hidden)] +pub mod __private_api; + +/// The statically resolved maximum log level. +/// +/// See the crate level documentation for information on how to configure this. +/// +/// This value is checked by the log macros, but not by the `Log`ger returned by +/// the [`logger`] function. Code that manually calls functions on that value +/// should compare the level against this value. +/// +/// [`logger`]: fn.logger.html +pub const STATIC_MAX_LEVEL: LevelFilter = match cfg!(debug_assertions) { + false if cfg!(feature = "release_max_level_off") => LevelFilter::Off, + false if cfg!(feature = "release_max_level_error") => LevelFilter::Error, + false if cfg!(feature = "release_max_level_warn") => LevelFilter::Warn, + false if cfg!(feature = "release_max_level_info") => LevelFilter::Info, + false if cfg!(feature = "release_max_level_debug") => LevelFilter::Debug, + false if cfg!(feature = "release_max_level_trace") => LevelFilter::Trace, + _ if cfg!(feature = "max_level_off") => LevelFilter::Off, + _ if cfg!(feature = "max_level_error") => LevelFilter::Error, + _ if cfg!(feature = "max_level_warn") => LevelFilter::Warn, + _ if cfg!(feature = "max_level_info") => LevelFilter::Info, + _ if cfg!(feature = "max_level_debug") => LevelFilter::Debug, + _ => LevelFilter::Trace, +}; + +#[cfg(test)] +mod tests { + use super::{Level, LevelFilter, ParseLevelError, STATIC_MAX_LEVEL}; + + #[test] + fn test_levelfilter_from_str() { + let tests = [ + ("off", Ok(LevelFilter::Off)), + ("error", Ok(LevelFilter::Error)), + ("warn", Ok(LevelFilter::Warn)), + ("info", Ok(LevelFilter::Info)), + ("debug", Ok(LevelFilter::Debug)), + ("trace", Ok(LevelFilter::Trace)), + ("OFF", Ok(LevelFilter::Off)), + ("ERROR", Ok(LevelFilter::Error)), + ("WARN", Ok(LevelFilter::Warn)), + ("INFO", Ok(LevelFilter::Info)), + ("DEBUG", Ok(LevelFilter::Debug)), + ("TRACE", Ok(LevelFilter::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_from_str() { + let tests = [ + ("OFF", Err(ParseLevelError(()))), + ("error", Ok(Level::Error)), + ("warn", Ok(Level::Warn)), + ("info", Ok(Level::Info)), + ("debug", Ok(Level::Debug)), + ("trace", Ok(Level::Trace)), + ("ERROR", Ok(Level::Error)), + ("WARN", Ok(Level::Warn)), + ("INFO", Ok(Level::Info)), + ("DEBUG", Ok(Level::Debug)), + ("TRACE", Ok(Level::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_as_str() { + let tests = &[ + (Level::Error, "ERROR"), + (Level::Warn, "WARN"), + (Level::Info, "INFO"), + (Level::Debug, "DEBUG"), + (Level::Trace, "TRACE"), + ]; + for (input, expected) in tests { + assert_eq!(*expected, input.as_str()); + } + } + + #[test] + fn test_level_show() { + assert_eq!("INFO", Level::Info.to_string()); + assert_eq!("ERROR", Level::Error.to_string()); + } + + #[test] + fn test_levelfilter_show() { + assert_eq!("OFF", LevelFilter::Off.to_string()); + assert_eq!("ERROR", LevelFilter::Error.to_string()); + } + + #[test] + fn test_cross_cmp() { + assert!(Level::Debug > LevelFilter::Error); + assert!(LevelFilter::Warn < Level::Trace); + assert!(LevelFilter::Off < Level::Error); + } + + #[test] + fn test_cross_eq() { + assert!(Level::Error == LevelFilter::Error); + assert!(LevelFilter::Off != Level::Error); + assert!(Level::Trace == LevelFilter::Trace); + } + + #[test] + fn test_to_level() { + assert_eq!(Some(Level::Error), LevelFilter::Error.to_level()); + assert_eq!(None, LevelFilter::Off.to_level()); + assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level()); + } + + #[test] + fn test_to_level_filter() { + assert_eq!(LevelFilter::Error, Level::Error.to_level_filter()); + assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter()); + } + + #[test] + fn test_level_filter_as_str() { + let tests = &[ + (LevelFilter::Off, "OFF"), + (LevelFilter::Error, "ERROR"), + (LevelFilter::Warn, "WARN"), + (LevelFilter::Info, "INFO"), + (LevelFilter::Debug, "DEBUG"), + (LevelFilter::Trace, "TRACE"), + ]; + for (input, expected) in tests { + assert_eq!(*expected, input.as_str()); + } + } + + #[test] + fn test_level_up() { + let info = Level::Info; + let up = info.increment_severity(); + assert_eq!(up, Level::Debug); + + let trace = Level::Trace; + let up = trace.increment_severity(); + // trace is already highest level + assert_eq!(up, trace); + } + + #[test] + fn test_level_filter_up() { + let info = LevelFilter::Info; + let up = info.increment_severity(); + assert_eq!(up, LevelFilter::Debug); + + let trace = LevelFilter::Trace; + let up = trace.increment_severity(); + // trace is already highest level + assert_eq!(up, trace); + } + + #[test] + fn test_level_down() { + let info = Level::Info; + let down = info.decrement_severity(); + assert_eq!(down, Level::Warn); + + let error = Level::Error; + let down = error.decrement_severity(); + // error is already lowest level + assert_eq!(down, error); + } + + #[test] + fn test_level_filter_down() { + let info = LevelFilter::Info; + let down = info.decrement_severity(); + assert_eq!(down, LevelFilter::Warn); + + let error = LevelFilter::Error; + let down = error.decrement_severity(); + assert_eq!(down, LevelFilter::Off); + // Off is already the lowest + assert_eq!(down.decrement_severity(), down); + } + + #[test] + #[cfg_attr(not(debug_assertions), ignore)] + fn test_static_max_level_debug() { + if cfg!(feature = "max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } + } + + #[test] + #[cfg_attr(debug_assertions, ignore)] + fn test_static_max_level_release() { + if cfg!(feature = "release_max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "release_max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "release_max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "release_max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "release_max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else if cfg!(feature = "release_max_level_trace") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } else if cfg!(feature = "max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } + } + + #[test] + #[cfg(feature = "std")] + fn test_error_trait() { + use super::SetLoggerError; + let e = SetLoggerError(()); + assert_eq!( + &e.to_string(), + "attempted to set a logger after the logging system \ + was already initialized" + ); + } + + #[test] + fn test_metadata_builder() { + use super::MetadataBuilder; + let target = "myApp"; + let metadata_test = MetadataBuilder::new() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_metadata_convenience_builder() { + use super::Metadata; + let target = "myApp"; + let metadata_test = Metadata::builder() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_record_builder() { + use super::{MetadataBuilder, RecordBuilder}; + let target = "myApp"; + let metadata = MetadataBuilder::new().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = RecordBuilder::new() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.metadata().target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_convenience_builder() { + use super::{Metadata, Record}; + let target = "myApp"; + let metadata = Metadata::builder().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = Record::builder() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_complete_builder() { + use super::{Level, Record}; + let target = "myApp"; + let record_test = Record::builder() + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .target(target) + .level(Level::Error) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.level(), Level::Error); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + #[cfg(feature = "kv")] + fn test_record_key_values_builder() { + use super::Record; + use crate::kv::{self, VisitSource}; + + struct TestVisitSource { + seen_pairs: usize, + } + + impl<'kvs> VisitSource<'kvs> for TestVisitSource { + fn visit_pair( + &mut self, + _: kv::Key<'kvs>, + _: kv::Value<'kvs>, + ) -> Result<(), kv::Error> { + self.seen_pairs += 1; + Ok(()) + } + } + + let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)]; + let record_test = Record::builder().key_values(&kvs).build(); + + let mut visitor = TestVisitSource { seen_pairs: 0 }; + + record_test.key_values().visit(&mut visitor).unwrap(); + + assert_eq!(2, visitor.seen_pairs); + } + + #[test] + #[cfg(feature = "kv")] + fn test_record_key_values_get_coerce() { + use super::Record; + + let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")]; + let record = Record::builder().key_values(&kvs).build(); + + assert_eq!( + "2", + record + .key_values() + .get("b".into()) + .expect("missing key") + .to_borrowed_str() + .expect("invalid value") + ); + } + + // Test that the `impl Log for Foo` blocks work + // This test mostly operates on a type level, so failures will be compile errors + #[test] + fn test_foreign_impl() { + use super::Log; + #[cfg(feature = "std")] + use std::sync::Arc; + + fn assert_is_log() {} + + assert_is_log::<&dyn Log>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + + // Assert these statements for all T: Log + ?Sized + #[allow(unused)] + fn forall() { + #[cfg(feature = "std")] + assert_is_log::>(); + + assert_is_log::<&T>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + } + } +} diff --git a/deps/crates/vendor/log/src/macros.rs b/deps/crates/vendor/log/src/macros.rs new file mode 100644 index 00000000000000..14e4ac64ba72a8 --- /dev/null +++ b/deps/crates/vendor/log/src/macros.rs @@ -0,0 +1,579 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The standard logging macro. +/// +/// This macro will generically log with the specified `Level` and `format!` +/// based argument list. +/// +/// ``` +/// use log::{log, Level}; +/// +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1); +/// ``` +/// +/// Optionally, you can specify a `target` argument to attach a specific target +/// to the log record. By default, the target is the module path of the caller. +/// +/// ``` +/// use log::{log, Level}; +/// +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// log!( +/// target: "app_events", +/// Level::Error, +/// "Received errors: {}, {}", +/// data.0, data.1 +/// ); +/// ``` +/// +/// And optionally, you can specify a `logger` argument to use a specific logger +/// instead of the default global logger. +/// +/// ``` +/// # struct MyLogger {} +/// # impl Log for MyLogger { +/// # fn enabled(&self, _metadata: &log::Metadata) -> bool { +/// # false +/// # } +/// # fn log(&self, _record: &log::Record) {} +/// # fn flush(&self) {} +/// # } +/// use log::{log, Level, Log}; +/// +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// let my_logger = MyLogger {}; +/// log!( +/// logger: my_logger, +/// Level::Error, +/// "Received errors: {}, {}", +/// data.0, data.1 +/// ); +/// ``` +/// +/// The `logger` argument accepts a value that implements the `Log` trait. The value +/// will be borrowed within the macro. +/// +/// Note that the global level set via Cargo features, or through `set_max_level` will +/// still apply, even when a custom logger is supplied with the `logger` argument. +#[macro_export] +#[clippy::format_args] +macro_rules! log { + // log!(logger: my_logger, target: "my_target", Level::Info, "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!($logger), + target: $target, + $lvl, + $($arg)+ + ) + }); + + // log!(logger: my_logger, Level::Info, "a log event") + (logger: $logger:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!($logger), + target: $crate::__private_api::module_path!(), + $lvl, + $($arg)+ + ) + }); + + // log!(target: "my_target", Level::Info, "a log event") + (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!(__log_global_logger), + target: $target, + $lvl, + $($arg)+ + ) + }); + + // log!(Level::Info, "a log event") + ($lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!(__log_global_logger), + target: $crate::__private_api::module_path!(), + $lvl, + $($arg)+ + ) + }); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log { + // log!(logger: my_logger, target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { + $crate::__private_api::log( + $logger, + $crate::__private_api::format_args!($($arg)+), + lvl, + &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), + &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+] as &[_], + ); + } + }); + + // log!(logger: my_logger, target: "my_target", Level::Info, "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { + $crate::__private_api::log( + $logger, + $crate::__private_api::format_args!($($arg)+), + lvl, + &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), + (), + ); + } + }); +} + +/// Logs a message at the error level. +/// +/// # Examples +/// +/// ``` +/// use log::error; +/// +/// # let my_logger = log::__private_api::GlobalLogger; +/// let (err_info, port) = ("No connection", 22); +/// +/// error!("Error: {err_info} on port {port}"); +/// error!(target: "app_events", "App Error: {err_info}, Port: {port}"); +/// error!(logger: my_logger, "App Error: {err_info}, Port: {port}"); +/// ``` +#[macro_export] +#[clippy::format_args] +macro_rules! error { + // error!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // error!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Error, $($arg)+) + }); + + // error!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // error!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Error, $($arg)+) + }); + + // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // error!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Error, $($arg)+) + }); + + // error!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Error, $($arg)+)) +} + +/// Logs a message at the warn level. +/// +/// # Examples +/// +/// ``` +/// use log::warn; +/// +/// # let my_logger = log::__private_api::GlobalLogger; +/// let warn_description = "Invalid Input"; +/// +/// warn!("Warning! {warn_description}!"); +/// warn!(target: "input_events", "App received warning: {warn_description}"); +/// warn!(logger: my_logger, "App received warning: {warn_description}"); +/// ``` +#[macro_export] +#[clippy::format_args] +macro_rules! warn { + // warn!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // warn!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Warn, $($arg)+) + }); + + // warn!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // warn!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Warn, $($arg)+) + }); + + // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // warn!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Warn, $($arg)+) + }); + + // warn!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Warn, $($arg)+)) +} + +/// Logs a message at the info level. +/// +/// # Examples +/// +/// ``` +/// use log::info; +/// +/// # let my_logger = log::__private_api::GlobalLogger; +/// # struct Connection { port: u32, speed: f32 } +/// let conn_info = Connection { port: 40, speed: 3.20 }; +/// +/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); +/// info!( +/// target: "connection_events", +/// "Successful connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed +/// ); +/// info!( +/// logger: my_logger, +/// "Successful connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed +/// ); +/// ``` +#[macro_export] +#[clippy::format_args] +macro_rules! info { + // info!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // info!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Info, $($arg)+) + }); + + // info!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // info!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Info, $($arg)+) + }); + + // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // info!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Info, $($arg)+) + }); + + // info!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+)) +} + +/// Logs a message at the debug level. +/// +/// # Examples +/// +/// ``` +/// use log::debug; +/// +/// # let my_logger = log::__private_api::GlobalLogger; +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// debug!("New position: x: {}, y: {}", pos.x, pos.y); +/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); +/// debug!(logger: my_logger, "New position: x: {}, y: {}", pos.x, pos.y); +/// ``` +#[macro_export] +#[clippy::format_args] +macro_rules! debug { + // debug!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // debug!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Debug, $($arg)+) + }); + + // debug!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // debug!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Debug, $($arg)+) + }); + + // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // debug!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Debug, $($arg)+) + }); + + // debug!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Debug, $($arg)+)) +} + +/// Logs a message at the trace level. +/// +/// # Examples +/// +/// ``` +/// use log::trace; +/// +/// # let my_logger = log::__private_api::GlobalLogger; +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// trace!("Position is: x: {}, y: {}", pos.x, pos.y); +/// trace!(target: "app_events", "x is {} and y is {}", +/// if pos.x >= 0.0 { "positive" } else { "negative" }, +/// if pos.y >= 0.0 { "positive" } else { "negative" }); +/// trace!(logger: my_logger, "x is {} and y is {}", +/// if pos.x >= 0.0 { "positive" } else { "negative" }, +/// if pos.y >= 0.0 { "positive" } else { "negative" }); +/// ``` +#[macro_export] +#[clippy::format_args] +macro_rules! trace { + // trace!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // trace!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Trace, $($arg)+) + }); + + // trace!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // trace!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Trace, $($arg)+) + }); + + // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // trace!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Trace, $($arg)+) + }); + + // trace!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Trace, $($arg)+)) +} + +/// Determines if a message logged at the specified level in that module will +/// be logged. +/// +/// This can be used to avoid expensive computation of log message arguments if +/// the message would be ignored anyway. +/// +/// # Examples +/// +/// ``` +/// use log::{debug, log_enabled, Level}; +/// +/// # struct Data { x: u32, y: u32 } +/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } +/// # let my_logger = log::__private_api::GlobalLogger; +/// if log_enabled!(Level::Debug) { +/// let data = expensive_call(); +/// debug!("expensive debug data: {} {}", data.x, data.y); +/// } +/// +/// if log_enabled!(target: "Global", Level::Debug) { +/// let data = expensive_call(); +/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); +/// } +/// +/// if log_enabled!(logger: my_logger, Level::Debug) { +/// let data = expensive_call(); +/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); +/// } +/// ``` +/// +/// This macro accepts the same `target` and `logger` arguments as [`macro@log`]. +#[macro_export] +macro_rules! log_enabled { + // log_enabled!(logger: my_logger, target: "my_target", Level::Info) + (logger: $logger:expr, target: $target:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!($logger), target: $target, $lvl) + }); + + // log_enabled!(logger: my_logger, Level::Info) + (logger: $logger:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!($logger), target: $crate::__private_api::module_path!(), $lvl) + }); + + // log_enabled!(target: "my_target", Level::Info) + (target: $target:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!(__log_global_logger), target: $target, $lvl) + }); + + // log_enabled!(Level::Info) + ($lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!(__log_global_logger), target: $crate::__private_api::module_path!(), $lvl) + }); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_enabled { + // log_enabled!(logger: my_logger, target: "my_target", Level::Info) + (logger: $logger:expr, target: $target:expr, $lvl:expr) => {{ + let lvl = $lvl; + lvl <= $crate::STATIC_MAX_LEVEL + && lvl <= $crate::max_level() + && $crate::__private_api::enabled($logger, lvl, $target) + }}; +} + +// Determine the logger to use, and whether to take it by-value or by reference + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_logger { + (__log_global_logger) => {{ + $crate::__private_api::GlobalLogger + }}; + + ($logger:expr) => {{ + &($logger) + }}; +} + +// These macros use a pattern of #[cfg]s to produce nicer error +// messages when log features aren't available + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv")] +macro_rules! __log_key { + // key1 = 42 + ($($args:ident)*) => { + $crate::__private_api::stringify!($($args)*) + }; + // "key1" = 42 + ($($args:expr)*) => { + $($args)* + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv"))] +macro_rules! __log_key { + ($($args:tt)*) => { + compile_error!("key value support requires the `kv` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv")] +macro_rules! __log_value { + // Entrypoint + ($key:tt = $args:expr) => { + $crate::__log_value!(($args):value) + }; + ($key:tt :$capture:tt = $args:expr) => { + $crate::__log_value!(($args):$capture) + }; + ($key:ident =) => { + $crate::__log_value!(($key):value) + }; + ($key:ident :$capture:tt =) => { + $crate::__log_value!(($key):$capture) + }; + // ToValue + (($args:expr):value) => { + $crate::__private_api::capture_to_value(&&$args) + }; + // Debug + (($args:expr):?) => { + $crate::__private_api::capture_debug(&&$args) + }; + (($args:expr):debug) => { + $crate::__private_api::capture_debug(&&$args) + }; + // Display + (($args:expr):%) => { + $crate::__private_api::capture_display(&&$args) + }; + (($args:expr):display) => { + $crate::__private_api::capture_display(&&$args) + }; + //Error + (($args:expr):err) => { + $crate::__log_value_error!($args) + }; + // sval::Value + (($args:expr):sval) => { + $crate::__log_value_sval!($args) + }; + // serde::Serialize + (($args:expr):serde) => { + $crate::__log_value_serde!($args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv"))] +macro_rules! __log_value { + ($($args:tt)*) => { + compile_error!("key value support requires the `kv` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_sval")] +macro_rules! __log_value_sval { + ($args:expr) => { + $crate::__private_api::capture_sval(&&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_sval"))] +macro_rules! __log_value_sval { + ($args:expr) => { + compile_error!("capturing values as `sval::Value` requites the `kv_sval` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_serde")] +macro_rules! __log_value_serde { + ($args:expr) => { + $crate::__private_api::capture_serde(&&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_serde"))] +macro_rules! __log_value_serde { + ($args:expr) => { + compile_error!( + "capturing values as `serde::Serialize` requites the `kv_serde` feature of `log`" + ) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_std")] +macro_rules! __log_value_error { + ($args:expr) => { + $crate::__private_api::capture_error(&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_std"))] +macro_rules! __log_value_error { + ($args:expr) => { + compile_error!( + "capturing values as `std::error::Error` requites the `kv_std` feature of `log`" + ) + }; +} diff --git a/deps/crates/vendor/log/src/serde.rs b/deps/crates/vendor/log/src/serde.rs new file mode 100644 index 00000000000000..f664756f353488 --- /dev/null +++ b/deps/crates/vendor/log/src/serde.rs @@ -0,0 +1,397 @@ +#![cfg(feature = "serde_core")] + +use serde_core::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess, + Visitor, +}; +use serde_core::ser::{Serialize, Serializer}; + +use crate::{Level, LevelFilter, LOG_LEVEL_NAMES}; + +use std::fmt; +use std::str::{self, FromStr}; + +// The Deserialize impls are handwritten to be case-insensitive using FromStr. + +impl Serialize for Level { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"), + Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"), + Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"), + Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"), + Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for Level { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct LevelIdentifier; + + impl<'de> Visitor<'de> for LevelIdentifier { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + let variant = LOG_LEVEL_NAMES[1..] + .get(v as usize) + .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; + + self.visit_str(variant) + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + // Case-insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..])) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelIdentifier { + type Value = Level; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelIdentifier) + } + } + + struct LevelEnum; + + impl<'de> Visitor<'de> for LevelEnum { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_enum(self, value: A) -> Result + where + A: EnumAccess<'de>, + { + let (level, variant) = value.variant_seed(LevelIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level) + } + } + + deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum) + } +} + +impl Serialize for LevelFilter { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"), + LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"), + LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"), + LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"), + LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"), + LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for LevelFilter { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct LevelFilterIdentifier; + + impl<'de> Visitor<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + let variant = LOG_LEVEL_NAMES + .get(v as usize) + .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; + + self.visit_str(variant) + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + // Case-insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES)) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelFilterIdentifier) + } + } + + struct LevelFilterEnum; + + impl<'de> Visitor<'de> for LevelFilterEnum { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_enum(self, value: A) -> Result + where + A: EnumAccess<'de>, + { + let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level_filter) + } + } + + deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum) + } +} + +#[cfg(test)] +mod tests { + use crate::{Level, LevelFilter}; + use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; + + fn level_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "Level", + variant, + } + } + + fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { name: "Level" }, + Token::Bytes(variant), + Token::Unit, + ] + } + + fn level_variant_tokens(variant: u32) -> [Token; 3] { + [ + Token::Enum { name: "Level" }, + Token::U32(variant), + Token::Unit, + ] + } + + fn level_filter_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "LevelFilter", + variant, + } + } + + fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { + name: "LevelFilter", + }, + Token::Bytes(variant), + Token::Unit, + ] + } + + fn level_filter_variant_tokens(variant: u32) -> [Token; 3] { + [ + Token::Enum { + name: "LevelFilter", + }, + Token::U32(variant), + Token::Unit, + ] + } + + #[test] + fn test_level_ser_de() { + let cases = &[ + (Level::Error, [level_token("ERROR")]), + (Level::Warn, [level_token("WARN")]), + (Level::Info, [level_token("INFO")]), + (Level::Debug, [level_token("DEBUG")]), + (Level::Trace, [level_token("TRACE")]), + ]; + + for (s, expected) in cases { + assert_tokens(s, expected); + } + } + + #[test] + fn test_level_case_insensitive() { + let cases = &[ + (Level::Error, [level_token("error")]), + (Level::Warn, [level_token("warn")]), + (Level::Info, [level_token("info")]), + (Level::Debug, [level_token("debug")]), + (Level::Trace, [level_token("trace")]), + ]; + + for (s, expected) in cases { + assert_de_tokens(s, expected); + } + } + + #[test] + fn test_level_de_bytes() { + let cases = &[ + (Level::Error, level_bytes_tokens(b"ERROR")), + (Level::Warn, level_bytes_tokens(b"WARN")), + (Level::Info, level_bytes_tokens(b"INFO")), + (Level::Debug, level_bytes_tokens(b"DEBUG")), + (Level::Trace, level_bytes_tokens(b"TRACE")), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_de_variant_index() { + let cases = &[ + (Level::Error, level_variant_tokens(0)), + (Level::Warn, level_variant_tokens(1)), + (Level::Info, level_variant_tokens(2)), + (Level::Debug, level_variant_tokens(3)), + (Level::Trace, level_variant_tokens(4)), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::(&[level_token("errorx")], msg); + } + + #[test] + fn test_level_filter_ser_de() { + let cases = &[ + (LevelFilter::Off, [level_filter_token("OFF")]), + (LevelFilter::Error, [level_filter_token("ERROR")]), + (LevelFilter::Warn, [level_filter_token("WARN")]), + (LevelFilter::Info, [level_filter_token("INFO")]), + (LevelFilter::Debug, [level_filter_token("DEBUG")]), + (LevelFilter::Trace, [level_filter_token("TRACE")]), + ]; + + for (s, expected) in cases { + assert_tokens(s, expected); + } + } + + #[test] + fn test_level_filter_case_insensitive() { + let cases = &[ + (LevelFilter::Off, [level_filter_token("off")]), + (LevelFilter::Error, [level_filter_token("error")]), + (LevelFilter::Warn, [level_filter_token("warn")]), + (LevelFilter::Info, [level_filter_token("info")]), + (LevelFilter::Debug, [level_filter_token("debug")]), + (LevelFilter::Trace, [level_filter_token("trace")]), + ]; + + for (s, expected) in cases { + assert_de_tokens(s, expected); + } + } + + #[test] + fn test_level_filter_de_bytes() { + let cases = &[ + (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")), + (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")), + (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")), + (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")), + (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")), + (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_filter_de_variant_index() { + let cases = &[ + (LevelFilter::Off, level_filter_variant_tokens(0)), + (LevelFilter::Error, level_filter_variant_tokens(1)), + (LevelFilter::Warn, level_filter_variant_tokens(2)), + (LevelFilter::Info, level_filter_variant_tokens(3)), + (LevelFilter::Debug, level_filter_variant_tokens(4)), + (LevelFilter::Trace, level_filter_variant_tokens(5)), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_filter_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::(&[level_filter_token("errorx")], msg); + } +} diff --git a/deps/crates/vendor/log/tests/integration.rs b/deps/crates/vendor/log/tests/integration.rs new file mode 100644 index 00000000000000..9bcb0469787984 --- /dev/null +++ b/deps/crates/vendor/log/tests/integration.rs @@ -0,0 +1,101 @@ +#![allow(dead_code, unused_imports)] + +use log::{debug, error, info, trace, warn, Level, LevelFilter, Log, Metadata, Record}; +use std::sync::{Arc, Mutex}; + +struct State { + last_log_level: Mutex>, + last_log_location: Mutex>, +} + +struct Logger(Arc); + +impl Log for Logger { + fn enabled(&self, _: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + *self.0.last_log_level.lock().unwrap() = Some(record.level()); + *self.0.last_log_location.lock().unwrap() = record.line(); + } + fn flush(&self) {} +} + +#[test] +fn test_integration() { + // These tests don't really make sense when static + // max level filtering is applied + #[cfg(not(any( + feature = "max_level_off", + feature = "max_level_error", + feature = "max_level_warn", + feature = "max_level_info", + feature = "max_level_debug", + feature = "max_level_trace", + feature = "release_max_level_off", + feature = "release_max_level_error", + feature = "release_max_level_warn", + feature = "release_max_level_info", + feature = "release_max_level_debug", + feature = "release_max_level_trace", + )))] + { + let me = Arc::new(State { + last_log_level: Mutex::new(None), + last_log_location: Mutex::new(None), + }); + let a = me.clone(); + let logger = Logger(me); + + test_filter(&logger, &a, LevelFilter::Off); + test_filter(&logger, &a, LevelFilter::Error); + test_filter(&logger, &a, LevelFilter::Warn); + test_filter(&logger, &a, LevelFilter::Info); + test_filter(&logger, &a, LevelFilter::Debug); + test_filter(&logger, &a, LevelFilter::Trace); + + test_line_numbers(&logger, &a); + } +} + +fn test_filter(logger: &dyn Log, a: &State, filter: LevelFilter) { + // tests to ensure logs with a level beneath 'max_level' are filtered out + log::set_max_level(filter); + error!(logger: logger, ""); + last(a, t(Level::Error, filter)); + warn!(logger: logger, ""); + last(a, t(Level::Warn, filter)); + info!(logger: logger, ""); + last(a, t(Level::Info, filter)); + debug!(logger: logger, ""); + last(a, t(Level::Debug, filter)); + trace!(logger: logger, ""); + last(a, t(Level::Trace, filter)); + + fn t(lvl: Level, filter: LevelFilter) -> Option { + if lvl <= filter { + Some(lvl) + } else { + None + } + } + fn last(state: &State, expected: Option) { + let lvl = state.last_log_level.lock().unwrap().take(); + assert_eq!(lvl, expected); + } +} + +fn test_line_numbers(logger: &dyn Log, state: &State) { + log::set_max_level(LevelFilter::Trace); + + info!(logger: logger, ""); // ensure check_line function follows log macro + check_log_location(state); + + #[track_caller] + fn check_log_location(state: &State) { + let location = std::panic::Location::caller().line(); // get function calling location + let line_number = state.last_log_location.lock().unwrap().take().unwrap(); // get location of most recent log + assert_eq!(line_number, location - 1); + } +} diff --git a/deps/crates/vendor/log/tests/macros.rs b/deps/crates/vendor/log/tests/macros.rs new file mode 100644 index 00000000000000..dded475c1c082d --- /dev/null +++ b/deps/crates/vendor/log/tests/macros.rs @@ -0,0 +1,429 @@ +use log::{log, log_enabled, Log, Metadata, Record}; + +macro_rules! all_log_macros { + ($($arg:tt)*) => ({ + ::log::trace!($($arg)*); + ::log::debug!($($arg)*); + ::log::info!($($arg)*); + ::log::warn!($($arg)*); + ::log::error!($($arg)*); + }); +} + +// Not `Copy` +struct Logger; + +impl Log for Logger { + fn enabled(&self, _: &Metadata) -> bool { + false + } + fn log(&self, _: &Record) {} + fn flush(&self) {} +} + +#[test] +fn no_args() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(lvl, "hello"); + log!(lvl, "hello",); + + log!(target: "my_target", lvl, "hello"); + log!(target: "my_target", lvl, "hello",); + + log!(logger: logger, lvl, "hello"); + log!(logger: logger, lvl, "hello",); + + log!(logger: logger, target: "my_target", lvl, "hello"); + log!(logger: logger, target: "my_target", lvl, "hello",); + } + + all_log_macros!("hello"); + all_log_macros!("hello",); + + all_log_macros!(target: "my_target", "hello"); + all_log_macros!(target: "my_target", "hello",); + + all_log_macros!(logger: logger, "hello"); + all_log_macros!(logger: logger, "hello",); + + all_log_macros!(logger: logger, target: "my_target", "hello"); + all_log_macros!(logger: logger, target: "my_target", "hello",); +} + +#[test] +fn anonymous_args() { + for lvl in log::Level::iter() { + log!(lvl, "hello {}", "world"); + log!(lvl, "hello {}", "world",); + + log!(target: "my_target", lvl, "hello {}", "world"); + log!(target: "my_target", lvl, "hello {}", "world",); + + log!(lvl, "hello {}", "world"); + log!(lvl, "hello {}", "world",); + } + + all_log_macros!("hello {}", "world"); + all_log_macros!("hello {}", "world",); + + all_log_macros!(target: "my_target", "hello {}", "world"); + all_log_macros!(target: "my_target", "hello {}", "world",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {}", "world"); + all_log_macros!(logger: logger, "hello {}", "world",); + + all_log_macros!(logger: logger, target: "my_target", "hello {}", "world"); + all_log_macros!(logger: logger, target: "my_target", "hello {}", "world",); +} + +#[test] +fn named_args() { + for lvl in log::Level::iter() { + log!(lvl, "hello {world}", world = "world"); + log!(lvl, "hello {world}", world = "world",); + + log!(target: "my_target", lvl, "hello {world}", world = "world"); + log!(target: "my_target", lvl, "hello {world}", world = "world",); + + log!(lvl, "hello {world}", world = "world"); + log!(lvl, "hello {world}", world = "world",); + } + + all_log_macros!("hello {world}", world = "world"); + all_log_macros!("hello {world}", world = "world",); + + all_log_macros!(target: "my_target", "hello {world}", world = "world"); + all_log_macros!(target: "my_target", "hello {world}", world = "world",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {world}", world = "world"); + all_log_macros!(logger: logger, "hello {world}", world = "world",); + + all_log_macros!(logger: logger, target: "my_target", "hello {world}", world = "world"); + all_log_macros!(logger: logger, target: "my_target", "hello {world}", world = "world",); +} + +#[test] +fn inlined_args() { + let world = "world"; + + for lvl in log::Level::iter() { + log!(lvl, "hello {world}"); + log!(lvl, "hello {world}",); + + log!(target: "my_target", lvl, "hello {world}"); + log!(target: "my_target", lvl, "hello {world}",); + + log!(lvl, "hello {world}"); + log!(lvl, "hello {world}",); + } + + all_log_macros!("hello {world}"); + all_log_macros!("hello {world}",); + + all_log_macros!(target: "my_target", "hello {world}"); + all_log_macros!(target: "my_target", "hello {world}",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {world}"); + all_log_macros!(logger: logger, "hello {world}",); + + all_log_macros!(logger: logger, target: "my_target", "hello {world}"); + all_log_macros!(logger: logger, target: "my_target", "hello {world}",); +} + +#[test] +fn enabled() { + let logger = Logger; + + for lvl in log::Level::iter() { + let _enabled = log_enabled!(lvl); + let _enabled = log_enabled!(target: "my_target", lvl); + let _enabled = log_enabled!(logger: logger, target: "my_target", lvl); + let _enabled = log_enabled!(logger: logger, lvl); + } +} + +#[test] +fn expr() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(lvl, "hello"); + + log!(logger: logger, lvl, "hello"); + } +} + +#[test] +#[cfg(feature = "kv")] +fn kv_no_args() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + } + + all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_expr_args() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + log!(lvl, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + log!(lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + log!(logger: logger, target: "my_target", lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + log!(logger: logger, lvl, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + log!(logger: logger, lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + } + + all_log_macros!(target: "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + all_log_macros!(logger: logger, target: "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(logger: logger, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(logger: logger, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_anonymous_args() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + log!(lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + log!(logger: logger, lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + } + + all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(logger: logger, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_named_args() { + let logger = Logger; + + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + log!(lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + log!(logger: logger, lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + } + + all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(logger: logger, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_ident() { + let cat_1 = "chashu"; + let cat_2 = "nori"; + + all_log_macros!(cat_1, cat_2:%, cat_count = 2; "hello {world}", world = "world"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_expr_context() { + match "chashu" { + cat_1 => { + log::info!(target: "target", cat_1 = cat_1, cat_2 = "nori"; "hello {}", "cats"); + } + }; +} + +#[test] +fn implicit_named_args() { + let world = "world"; + + for lvl in log::Level::iter() { + log!(lvl, "hello {world}"); + log!(lvl, "hello {world}",); + + log!(target: "my_target", lvl, "hello {world}"); + log!(target: "my_target", lvl, "hello {world}",); + + log!(lvl, "hello {world}"); + log!(lvl, "hello {world}",); + } + + all_log_macros!("hello {world}"); + all_log_macros!("hello {world}",); + + all_log_macros!(target: "my_target", "hello {world}"); + all_log_macros!(target: "my_target", "hello {world}",); + + #[cfg(feature = "kv")] + all_log_macros!(target = "my_target"; "hello {world}"); + #[cfg(feature = "kv")] + all_log_macros!(target = "my_target"; "hello {world}",); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_implicit_named_args() { + let world = "world"; + + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}"); + + log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}"); + } + + all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}"); + all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}"); + all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_string_keys() { + for lvl in log::Level::iter() { + log!(target: "my_target", lvl, "also dogs" = "Fílos", "key/that-can't/be/an/ident" = "hi"; "hello {world}", world = "world"); + } + + all_log_macros!(target: "my_target", "also dogs" = "Fílos", "key/that-can't/be/an/ident" = "hi"; "hello {world}", world = "world"); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_common_value_types() { + all_log_macros!( + u8 = 42u8, + u16 = 42u16, + u32 = 42u32, + u64 = 42u64, + u128 = 42u128, + i8 = -42i8, + i16 = -42i16, + i32 = -42i32, + i64 = -42i64, + i128 = -42i128, + f32 = 4.2f32, + f64 = -4.2f64, + bool = true, + str = "string"; + "hello world" + ); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_debug() { + all_log_macros!( + a:? = 42, + b:debug = 42; + "hello world" + ); +} + +#[test] +#[cfg(feature = "kv")] +fn kv_display() { + all_log_macros!( + a:% = 42, + b:display = 42; + "hello world" + ); +} + +#[test] +#[cfg(feature = "kv_std")] +fn kv_error() { + all_log_macros!( + a:err = std::io::Error::new(std::io::ErrorKind::Other, "an error"); + "hello world" + ); +} + +#[test] +#[cfg(feature = "kv_sval")] +fn kv_sval() { + all_log_macros!( + a:sval = 42; + "hello world" + ); +} + +#[test] +#[cfg(feature = "kv_serde")] +fn kv_serde() { + all_log_macros!( + a:serde = 42; + "hello world" + ); +} + +#[test] +fn logger_short_lived() { + all_log_macros!(logger: Logger, "hello"); + all_log_macros!(logger: &Logger, "hello"); +} + +#[test] +fn logger_expr() { + all_log_macros!(logger: { + let logger = Logger; + logger + }, "hello"); +} + +/// Some and None (from Option) are used in the macros. +#[derive(Debug)] +enum Type { + Some, + None, +} + +#[test] +fn regression_issue_494() { + use self::Type::*; + all_log_macros!("some message: {:?}, {:?}", None, Some); +} diff --git a/deps/crates/vendor/log/triagebot.toml b/deps/crates/vendor/log/triagebot.toml new file mode 100644 index 00000000000000..fa0824ac53c0a9 --- /dev/null +++ b/deps/crates/vendor/log/triagebot.toml @@ -0,0 +1 @@ +[assign] diff --git a/deps/crates/vendor/memmap2/.cargo-checksum.json b/deps/crates/vendor/memmap2/.cargo-checksum.json new file mode 100644 index 00000000000000..3b738541a812c5 --- /dev/null +++ b/deps/crates/vendor/memmap2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"57a15fc6b2ddb894def64e09a11e5cc52e575be77740a6fc0aa3c451c8c0fa49",".github/workflows/main.yml":"e2b3d5678a31325a616bae0c1ccb223f9ed2f5b43d39a134c5c45858e4fbf4ca","CHANGELOG.md":"832a95917c80f443c113ede708a5602550d081bd79cc33f4152365357ab36bb8","Cargo.lock":"6ddd1fa91a86a6e8bbbc17161703f21799213d823ea26d7f7ce86181295a3fc8","Cargo.toml":"01ff6425d680ddac0a8efb1b41e6b0503d0153388fadcc4bf584ca38c4dca221","Cargo.toml.orig":"507519ce5facd6b78a80e3cfab1437c7b6b5a1fc99c65e24552525c884d4ed3e","LICENSE-APACHE":"04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad","LICENSE-MIT":"0d25d03b5ab49576178ad0cae7a2648d12c17ad0452fe49c07e55e4b59aa5257","README.md":"e3388f55065d69e076d90871c0a91dc97420bd0d07b4f154b08e40ac47b115eb","examples/cat.rs":"594b9457ca6eb4ce9b840133da5076fa7b96334953df03f894233169564622f6","src/advice.rs":"a4c023982a598a77c23b5a4e524de581329d42287d639be88e2ffda3bd929511","src/lib.rs":"d93f73dd80b5bfdecc10836a7ebcd04c124f6283f9a104686fe48a18d34764ab","src/stub.rs":"beccccb0233903df5de1773674b2dcd9b0991889a10c23719f5aee8f7496f958","src/unix.rs":"fea7c7c21a6082bc77052e5e40a2bff1311103a19c2cd281ff383604fa799b35","src/windows.rs":"0fbd1efc122a7e83defb5d0a401e973a3876e90c6a1f14f2ac1976462633dd79"},"package":"714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"} \ No newline at end of file diff --git a/deps/crates/vendor/memmap2/.cargo_vcs_info.json b/deps/crates/vendor/memmap2/.cargo_vcs_info.json new file mode 100644 index 00000000000000..7891adc2164329 --- /dev/null +++ b/deps/crates/vendor/memmap2/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "1f0196ab31cf1e6f4eb4b3633c51a4d3ba920788" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/memmap2/.github/workflows/main.yml b/deps/crates/vendor/memmap2/.github/workflows/main.yml new file mode 100644 index 00000000000000..41da8839a9cf0f --- /dev/null +++ b/deps/crates/vendor/memmap2/.github/workflows/main.yml @@ -0,0 +1,143 @@ +name: Rust + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-pc-windows-gnu + components: clippy, rustfmt + + - name: Run checks + env: + CLIPPY_OPTS: --all-targets + run: | + cargo fmt --check + cargo clippy $CLIPPY_OPTS + cargo clippy --target x86_64-pc-windows-gnu $CLIPPY_OPTS + + test-win: + runs-on: windows-latest + strategy: + matrix: + target: + - i686-pc-windows-gnu + - i686-pc-windows-msvc + - x86_64-pc-windows-gnu + - x86_64-pc-windows-msvc + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable-${{ matrix.target }} + + - name: Run tests + run: cargo test --all-features + + test-macos: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Run tests + run: cargo test --all-features + + test-linux: + runs-on: ubuntu-latest + strategy: + matrix: + target: + - i686-unknown-linux-gnu + - i686-unknown-linux-musl + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + - x86_64-linux-android + steps: + - name: Checkout + uses: actions/checkout@v3 + + # We need nightly for -Zminimal-versions + - name: Install nightly toolchain + uses: dtolnay/rust-toolchain@nightly + + - name: Install toolchain + uses: dtolnay/rust-toolchain@stable + with: + target: ${{ matrix.target }} + + - name: Install multilib + if: ${{ contains(matrix.target, 'i686-unknown-linux-') }} + run: | + sudo apt update -yqq + sudo apt install gcc-multilib + + # Make sure we're testing against the minimal libc version. + - name: Generate Cargo.lock + run: cargo +nightly update -Zminimal-versions + + - name: Run tests + if: ${{ !contains(matrix.target, 'android') }} + run: cargo test --locked --all-features --target ${{ matrix.target }} + + # Just make sure it builds. Not tests running. + - name: Run tests + if: ${{ contains(matrix.target, 'android') }} + run: cargo build --locked --all-features --target ${{ matrix.target }} + + check-stub: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + + - name: Run check + run: cargo check --all-features --target wasm32-unknown-unknown + + check-visionos: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + + - name: Run check + run: cargo check --all-features --target aarch64-apple-visionos -Zbuild-std + + test-msrv: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@1.63.0 + + # do not test, because dev-dependencies do not follow MSRV + - name: Build + run: cargo build --all-features diff --git a/deps/crates/vendor/memmap2/CHANGELOG.md b/deps/crates/vendor/memmap2/CHANGELOG.md new file mode 100644 index 00000000000000..2c68de5460e938 --- /dev/null +++ b/deps/crates/vendor/memmap2/CHANGELOG.md @@ -0,0 +1,273 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [0.9.10] - 2026-02-15 +### Fixed +- Fix compilation on AIX targets. + [@xingxue-ibm](https://github.com/xingxue-ibm) +### Changed +- Return `ErrorKind::Unsupported` on unsupported platforms to allow reliable runtime detection. + [@daxpedda](https://github.com/daxpedda) + +## [0.9.9] - 2025-10-21 +### Fixed +- Fix compilation on visionOS (and other apple operating systems). + [@sinkingsugar](https://github.com/sinkingsugar) +- Do not assume `isize::MAX` fits in a `u64`. + [@ThomasHabets](https://github.com/ThomasHabets) + +## [0.9.8] - 2025-08-22 +### Added +- `MmapOptions::no_reserve_swap`. + [@nhtyy](https://github.com/nhtyy) + +## [0.9.7] - 2025-07-13 +### Fixed +- Fix incomplete validation of mapping length, which could lead to violation of safety requirements of `slice::from_raw_parts` on 32-bit platforms. + [@nabijaczleweli](https://github.com/nabijaczleweli) + +## [0.9.6] - 2025-05-14 +### Fixed +- Fix huge page mappings with non-default page-bits. + [@Alex1s](https://github.com/Alex1s) + +## [0.9.5] - 2024-09-13 +### Added +- `Advise::is_supported` and `UncheckedAdvice::is_supported`. Linux only. + [@xzfc](https://github.com/xzfc) +- Documentation improvements. + [@RalfJung](https://github.com/RalfJung) + [@betelgeuse](https://github.com/betelgeuse) + [@ADSteele916](https://github.com/ADSteele916) + +## [0.9.4] - 2024-01-25 +### Changed +- The `libc` crate >= 0.2.151 is required now. + +### Fixed +- Build on Android with an older `libc` crate. + +## [0.9.3] - 2023-12-19 +### Fixed +- Build on Android. + +## [0.9.2] - 2023-12-17 +### Fixed +- Build on FreeBSD. + +## [0.9.1] - 2023-12-16 +### Changed +- Added `MmapOptions::huge` method to support mapping hugetlb. Linux only. + [@ollie-etl](https://github.com/ollie-etl) + [@oliverbunting](https://github.com/oliverbunting) + +## [0.9.0] - 2023-10-03 +### Changed +- The `Advice` struct was split into two enums: `Advice` and `UncheckedAdvice`.
+ `Advice` can be passed to safe `advise` and `advise_range` methods. + And `UncheckedAdvice` can be passed to unsafe `unchecked_advise` + and `unchecked_advise_range` methods.
+ [@adamreichold](https://github.com/adamreichold) + +## [0.8.0] - 2023-09-25 +### Changed +- The `Advice` type is a struct and not an enum now. + [@adamreichold](https://github.com/adamreichold) + +### Fixed +- Some of the `Advise` variants were unsound and now require `unsafe` to be constructed. + [@adamreichold](https://github.com/adamreichold) + +## [0.7.1] - 2023-06-24 +### Fixed +- Mapping beyond 4GB offset on 32 bit glibc. Linux-only. + [@lvella](https://github.com/lvella) + +## [0.7.0] - 2023-06-08 +### Added +- `Mmap::remap`, `MmapMut::remap` and `MmapRaw::remap`. Linux-only. + [@Phantomical](https://github.com/Phantomical) +- `Advice::PopulateRead` and `Advice::PopulateWrite`. Linux-only. + [@Jesse-Bakker](https://github.com/Jesse-Bakker) + +### Changed +- libc crate >= 0.2.143 is required now. + +## [0.6.2] - 2023-05-24 +### Fixed +- Alignment for empty files on Windows. + [@timvisee](https://github.com/timvisee) + +## [0.6.1] - 2023-05-10 +### Added +- Add `MmapOptions::map_raw_read_only` to avoid intermediate invalid `Mmap` instances. + [@adamreichold](https://github.com/adamreichold) + +## [0.6.0] - 2023-05-09 +### Changed +- `lock()` and `unlock` methods require `&self` and not `&mut self` now. + [@timvisee](https://github.com/timvisee) + +## [0.5.10] - 2023-02-22 +### Added +- `MmapOptions::map_anon` accounts for `populate` on Linux now. + [@jsgf](https://github.com/jsgf) + +## [0.5.9] - 2023-02-17 +### Added +- `From for MmapRaw` and `From for MmapRaw`. + [@swlynch99](https://github.com/swlynch99) +- `Mmap::advise_range`, `MmapMut::advise_range`, `MmapRaw::advise_range`. + [@ho-229](https://github.com/ho-229) + +## [0.5.8] - 2022-11-09 +### Added +- `MmapRaw::advise`, `MmapRaw::lock` and `MmapRaw::unlock`. + [@diwic](https://github.com/diwic) +- Improve `MmapMut::make_exec` documentation. + +## [0.5.7] - 2022-08-15 +### Changed +- Simplify file size retrieving code. + [@saethlin](https://github.com/saethlin) + +## [0.5.6] - 2022-08-11 +### Added +- Memory locking and unlocking. See `Mmap::lock`, `Mmap::unlock`, + `MmapMut::lock` and `MmapMut::unlock`. + [@vmx](https://github.com/vmx) + +## [0.5.5] - 2022-07-09 +### Fixed +- Limit mapping length to `isize::MAX` to prevent undefined behavior + on calling `std::slice::from_raw_parts`. Technically affects only 32-bit systems. + [@adamreichold](https://github.com/adamreichold) + +## [0.5.4] - 2022-06-04 +### Added +- Add madvice operations specific to Darwin. [@turbocool3r](https://github.com/turbocool3r) +- Implement common traits for the `Advice` enum. [@nyurik](https://github.com/nyurik) + +### Changed +- Make stub implementation Infallible. [@coolreader18](https://github.com/coolreader18) +- Use `tempfile` crate instead of `tempdir` in tests. + [@alexanderkjall](https://github.com/alexanderkjall) + +## [0.5.3] - 2022-02-10 +### Added +- `Mmap::advise` and `MmapMut::advise`. [@nyurik](https://github.com/nyurik) + +## [0.5.2] - 2022-01-10 +### Added +- `flush`, `flush_async`, `flush_range` and `flush_async_range` to `MmapRaw` matching + the corresponding methods on `MmapMut`. + [@cberner](https://github.com/cberner) + +## [0.5.1] - 2022-01-09 +### Fixed +- Explicitly call `fstat64` on Linux, emscripten and l4re targets. + [@adamreichold](https://github.com/adamreichold) + +## [0.5.0] - 2021-09-19 +### Added +- `MmapOptions` accepts any type that supports `RawHandle`/`RawFd` returning now. + This allows using `memmap2` not only with Rust std types, but also with + [async-std](https://github.com/async-rs/async-std) one. + [@adamreichold](https://github.com/adamreichold) +- (unix) Memoize page size to avoid repeatedly calling into sysconf machinery. + [@adamreichold](https://github.com/adamreichold) + +### Changed +- (win) Use `std::os::windows::io::AsRawHandle` directly, without relying on `std::fs::File`. + [@adamreichold](https://github.com/adamreichold) +- Do not panic when failing to release resources in Drop impls. + [@adamreichold](https://github.com/adamreichold) + +## [0.4.0] - 2021-09-16 +### Added +- Optional [`StableDeref`](https://github.com/storyyeller/stable_deref_trait) support. + [@SimonSapin](https://github.com/SimonSapin) + +### Changed +- Mapping of zero-sized files is no longer an error. + [@SimonSapin](https://github.com/SimonSapin) +- MSRV changed from 1.31 to 1.36 + +## [0.3.1] - 2021-08-15 +### Fixed +- Integer overflow during file length calculation on 32bit targets. +- Stub implementation. [@Mrmaxmeier](https://github.com/Mrmaxmeier) + +## [0.3.0] - 2021-06-10 +### Changed +- `MmapOptions` allows mapping using Unix descriptors and not only `std::fs::File` now. + [@mripard](https://github.com/mripard) + +## [0.2.3] - 2021-05-24 +### Added +- Allow compilation on unsupported platforms. + The code will panic on access just like in `std`. + [@jcaesar](https://github.com/jcaesar) + +## [0.2.2] - 2021-04-03 +### Added +- `MmapOptions::populate`. [@adamreichold](https://github.com/adamreichold) + +### Fixed +- Fix alignment computation for `flush_async` to match `flush`. + [@adamreichold](https://github.com/adamreichold) + +## [0.2.1] - 2021-02-08 +### Added +- `MmapOptions::map_raw` and `MmapRaw`. [@diwic](https://github.com/diwic) + +## [0.2.0] - 2020-12-19 +### Changed +- MSRV is 1.31 now (edition 2018). +- Make anonymous memory maps private by default on unix. [@CensoredUsername](https://github.com/CensoredUsername) +- Add `map_copy_read_only`. [@zseri](https://github.com/zseri) + +## 0.1.0 - 2020-01-18 +### Added +- Fork [memmap-rs](https://github.com/danburkert/memmap-rs). + +### Changed +- Use `LICENSE-APACHE` instead of `README.md` for some tests since it's immutable. + +### Removed +- `winapi` dependency. [memmap-rs/pull/89](https://github.com/danburkert/memmap-rs/pull/89) + +[Unreleased]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.5...HEAD +[0.9.5]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.4...v0.9.5 +[0.9.4]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.3...v0.9.4 +[0.9.3]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.2...v0.9.3 +[0.9.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.1...v0.9.2 +[0.9.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.9.0...v0.9.1 +[0.9.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.8.0...v0.9.0 +[0.8.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.7.1...v0.8.0 +[0.7.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.7.0...v0.7.1 +[0.7.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.2...v0.7.0 +[0.6.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.1...v0.6.2 +[0.6.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.0...v0.6.1 +[0.6.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.10...v0.6.0 +[0.5.10]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.9...v0.5.10 +[0.5.9]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.8...v0.5.9 +[0.5.8]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.7...v0.5.8 +[0.5.7]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.6...v0.5.7 +[0.5.6]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.5...v0.5.6 +[0.5.5]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.4...v0.5.5 +[0.5.4]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.3...v0.5.4 +[0.5.3]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.2...v0.5.3 +[0.5.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.1...v0.5.2 +[0.5.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.4.0...v0.5.0 +[0.4.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.3.1...v0.4.0 +[0.3.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.3...v0.3.0 +[0.2.3]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.2...v0.2.3 +[0.2.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.1...v0.2.2 +[0.2.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.1.0...v0.2.0 diff --git a/deps/crates/vendor/memmap2/Cargo.lock b/deps/crates/vendor/memmap2/Cargo.lock new file mode 100644 index 00000000000000..41bc3d973abaed --- /dev/null +++ b/deps/crates/vendor/memmap2/Cargo.lock @@ -0,0 +1,209 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "memmap2" +version = "0.9.10" +dependencies = [ + "libc", + "owning_ref", + "stable_deref_trait", + "tempfile", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] diff --git a/deps/crates/vendor/memmap2/Cargo.toml b/deps/crates/vendor/memmap2/Cargo.toml new file mode 100644 index 00000000000000..31c5d97b2fff1c --- /dev/null +++ b/deps/crates/vendor/memmap2/Cargo.toml @@ -0,0 +1,59 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.63" +name = "memmap2" +version = "0.9.10" +authors = [ + "Dan Burkert ", + "Yevhenii Reizner ", + "The Contributors", +] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Cross-platform Rust API for memory-mapped file IO" +documentation = "https://docs.rs/memmap2" +readme = "README.md" +keywords = [ + "mmap", + "memory-map", + "io", + "file", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RazrFalcon/memmap2-rs" + +[lib] +name = "memmap2" +path = "src/lib.rs" + +[[example]] +name = "cat" +path = "examples/cat.rs" + +[dependencies.stable_deref_trait] +version = "1.0" +optional = true + +[dev-dependencies.owning_ref] +version = "0.4.1" + +[dev-dependencies.tempfile] +version = "3" + +[target."cfg(unix)".dependencies.libc] +version = "0.2.151" diff --git a/deps/crates/vendor/memmap2/Cargo.toml.orig b/deps/crates/vendor/memmap2/Cargo.toml.orig new file mode 100644 index 00000000000000..901693f2620a57 --- /dev/null +++ b/deps/crates/vendor/memmap2/Cargo.toml.orig @@ -0,0 +1,25 @@ +[package] +name = "memmap2" +version = "0.9.10" +authors = [ + "Dan Burkert ", + "Yevhenii Reizner ", + "The Contributors", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RazrFalcon/memmap2-rs" +documentation = "https://docs.rs/memmap2" +description = "Cross-platform Rust API for memory-mapped file IO" +keywords = ["mmap", "memory-map", "io", "file"] +edition = "2021" +rust-version = "1.63" + +[dependencies] +stable_deref_trait = { version = "1.0", optional = true } + +[target.'cfg(unix)'.dependencies] +libc = "0.2.151" + +[dev-dependencies] +tempfile = "3" +owning_ref = "0.4.1" diff --git a/deps/crates/vendor/memmap2/LICENSE-APACHE b/deps/crates/vendor/memmap2/LICENSE-APACHE new file mode 100644 index 00000000000000..7be3d81ac7f8dd --- /dev/null +++ b/deps/crates/vendor/memmap2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [2015] [Dan Burkert] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/memmap2/LICENSE-MIT b/deps/crates/vendor/memmap2/LICENSE-MIT new file mode 100644 index 00000000000000..6357f40d65af1e --- /dev/null +++ b/deps/crates/vendor/memmap2/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2020 Yevhenii Reizner +Copyright (c) 2015 Dan Burkert + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/memmap2/README.md b/deps/crates/vendor/memmap2/README.md new file mode 100644 index 00000000000000..55eed9e7dae7ec --- /dev/null +++ b/deps/crates/vendor/memmap2/README.md @@ -0,0 +1,33 @@ +# memmap2 +![Build Status](https://github.com/RazrFalcon/memmap2-rs/workflows/Rust/badge.svg) +[![Crates.io](https://img.shields.io/crates/v/memmap2.svg)](https://crates.io/crates/memmap2) +[![Documentation](https://docs.rs/memmap2/badge.svg)](https://docs.rs/memmap2) +[![MSRV 1.63.0](https://img.shields.io/badge/msrv-1.63.0-dea584.svg?logo=rust)](https://github.com/rust-lang/rust/releases/tag/1.63.0) + +A Rust library for cross-platform memory mapped IO. + +This is a **fork** of the [memmap-rs](https://github.com/danburkert/memmap-rs) crate. + +## Features + +- [x] file-backed memory maps +- [x] anonymous memory maps +- [x] synchronous and asynchronous flushing +- [x] copy-on-write memory maps +- [x] read-only memory maps +- [x] stack support (`MAP_STACK` on unix) +- [x] executable memory maps +- [x] huge page support (linux only) + +A list of supported/tested targets can be found in [Actions](https://github.com/RazrFalcon/memmap2-rs/actions). + +## License + +`memmap2` is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +Copyright (c) 2020 Yevhenii Reizner + +Copyright (c) 2015 Dan Burkert diff --git a/deps/crates/vendor/memmap2/examples/cat.rs b/deps/crates/vendor/memmap2/examples/cat.rs new file mode 100644 index 00000000000000..d0dce7e7d285a9 --- /dev/null +++ b/deps/crates/vendor/memmap2/examples/cat.rs @@ -0,0 +1,21 @@ +use std::env; +use std::fs::File; +use std::io::{self, Write}; + +use memmap2::Mmap; + +/// Output a file's contents to stdout. The file path must be provided as the first process +/// argument. +fn main() { + let path = env::args() + .nth(1) + .expect("supply a single path as the program argument"); + + let file = File::open(path).expect("failed to open the file"); + + let mmap = unsafe { Mmap::map(&file).expect("failed to map the file") }; + + io::stdout() + .write_all(&mmap[..]) + .expect("failed to output the file contents"); +} diff --git a/deps/crates/vendor/memmap2/src/advice.rs b/deps/crates/vendor/memmap2/src/advice.rs new file mode 100644 index 00000000000000..8b7e1e6f17e8ba --- /dev/null +++ b/deps/crates/vendor/memmap2/src/advice.rs @@ -0,0 +1,422 @@ +/// Values supported by [`Mmap::advise`][crate::Mmap::advise] and [`MmapMut::advise`][crate::MmapMut::advise] functions. +/// +/// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum Advice { + /// **MADV_NORMAL** + /// + /// No special treatment. This is the default. + Normal = libc::MADV_NORMAL, + + /// **MADV_RANDOM** + /// + /// Expect page references in random order. (Hence, read + /// ahead may be less useful than normally.) + Random = libc::MADV_RANDOM, + + /// **MADV_SEQUENTIAL** + /// + /// Expect page references in sequential order. (Hence, pages + /// in the given range can be aggressively read ahead, and may + /// be freed soon after they are accessed.) + Sequential = libc::MADV_SEQUENTIAL, + + /// **MADV_WILLNEED** + /// + /// Expect access in the near future. (Hence, it might be a + /// good idea to read some pages ahead.) + WillNeed = libc::MADV_WILLNEED, + + /// **MADV_DONTFORK** - Linux only (since Linux 2.6.16) + /// + /// Do not make the pages in this range available to the child + /// after a fork(2). This is useful to prevent copy-on-write + /// semantics from changing the physical location of a page if + /// the parent writes to it after a fork(2). (Such page + /// relocations cause problems for hardware that DMAs into the + /// page.) + #[cfg(target_os = "linux")] + DontFork = libc::MADV_DONTFORK, + + /// **MADV_DOFORK** - Linux only (since Linux 2.6.16) + /// + /// Undo the effect of MADV_DONTFORK, restoring the default + /// behavior, whereby a mapping is inherited across fork(2). + #[cfg(target_os = "linux")] + DoFork = libc::MADV_DOFORK, + + /// **MADV_MERGEABLE** - Linux only (since Linux 2.6.32) + /// + /// Enable Kernel Samepage Merging (KSM) for the pages in the + /// range specified by addr and length. The kernel regularly + /// scans those areas of user memory that have been marked as + /// mergeable, looking for pages with identical content. + /// These are replaced by a single write-protected page (which + /// is automatically copied if a process later wants to update + /// the content of the page). KSM merges only private + /// anonymous pages (see mmap(2)). + /// + /// The KSM feature is intended for applications that generate + /// many instances of the same data (e.g., virtualization + /// systems such as KVM). It can consume a lot of processing + /// power; use with care. See the Linux kernel source file + /// Documentation/admin-guide/mm/ksm.rst for more details. + /// + /// The MADV_MERGEABLE and MADV_UNMERGEABLE operations are + /// available only if the kernel was configured with + /// CONFIG_KSM. + #[cfg(target_os = "linux")] + Mergeable = libc::MADV_MERGEABLE, + + /// **MADV_UNMERGEABLE** - Linux only (since Linux 2.6.32) + /// + /// Undo the effect of an earlier MADV_MERGEABLE operation on + /// the specified address range; KSM unmerges whatever pages + /// it had merged in the address range specified by addr and + /// length. + #[cfg(target_os = "linux")] + Unmergeable = libc::MADV_UNMERGEABLE, + + /// **MADV_HUGEPAGE** - Linux only (since Linux 2.6.38) + /// + /// Enable Transparent Huge Pages (THP) for pages in the range + /// specified by addr and length. Currently, Transparent Huge + /// Pages work only with private anonymous pages (see + /// mmap(2)). The kernel will regularly scan the areas marked + /// as huge page candidates to replace them with huge pages. + /// The kernel will also allocate huge pages directly when the + /// region is naturally aligned to the huge page size (see + /// posix_memalign(2)). + /// + /// This feature is primarily aimed at applications that use + /// large mappings of data and access large regions of that + /// memory at a time (e.g., virtualization systems such as + /// QEMU). It can very easily waste memory (e.g., a 2 MB + /// mapping that only ever accesses 1 byte will result in 2 MB + /// of wired memory instead of one 4 KB page). See the Linux + /// kernel source file + /// Documentation/admin-guide/mm/transhuge.rst for more + /// details. + /// + /// Most common kernels configurations provide MADV_HUGEPAGE- + /// style behavior by default, and thus MADV_HUGEPAGE is + /// normally not necessary. It is mostly intended for + /// embedded systems, where MADV_HUGEPAGE-style behavior may + /// not be enabled by default in the kernel. On such systems, + /// this flag can be used in order to selectively enable THP. + /// Whenever MADV_HUGEPAGE is used, it should always be in + /// regions of memory with an access pattern that the + /// developer knows in advance won't risk to increase the + /// memory footprint of the application when transparent + /// hugepages are enabled. + /// + /// The MADV_HUGEPAGE and MADV_NOHUGEPAGE operations are + /// available only if the kernel was configured with + /// CONFIG_TRANSPARENT_HUGEPAGE. + #[cfg(target_os = "linux")] + HugePage = libc::MADV_HUGEPAGE, + + /// **MADV_NOHUGEPAGE** - Linux only (since Linux 2.6.38) + /// + /// Ensures that memory in the address range specified by addr + /// and length will not be backed by transparent hugepages. + #[cfg(target_os = "linux")] + NoHugePage = libc::MADV_NOHUGEPAGE, + + /// **MADV_DONTDUMP** - Linux only (since Linux 3.4) + /// + /// Exclude from a core dump those pages in the range + /// specified by addr and length. This is useful in + /// applications that have large areas of memory that are + /// known not to be useful in a core dump. The effect of + /// **MADV_DONTDUMP** takes precedence over the bit mask that is + /// set via the `/proc/[pid]/coredump_filter` file (see + /// core(5)). + #[cfg(target_os = "linux")] + DontDump = libc::MADV_DONTDUMP, + + /// **MADV_DODUMP** - Linux only (since Linux 3.4) + /// + /// Undo the effect of an earlier MADV_DONTDUMP. + #[cfg(target_os = "linux")] + DoDump = libc::MADV_DODUMP, + + /// **MADV_HWPOISON** - Linux only (since Linux 2.6.32) + /// + /// Poison the pages in the range specified by addr and length + /// and handle subsequent references to those pages like a + /// hardware memory corruption. This operation is available + /// only for privileged (CAP_SYS_ADMIN) processes. This + /// operation may result in the calling process receiving a + /// SIGBUS and the page being unmapped. + /// + /// This feature is intended for testing of memory error- + /// handling code; it is available only if the kernel was + /// configured with CONFIG_MEMORY_FAILURE. + #[cfg(target_os = "linux")] + HwPoison = libc::MADV_HWPOISON, + + /// **MADV_POPULATE_READ** - Linux only (since Linux 5.14) + /// + /// Populate (prefault) page tables readable, faulting in all + /// pages in the range just as if manually reading from each + /// page; however, avoid the actual memory access that would have + /// been performed after handling the fault. + /// + /// In contrast to MAP_POPULATE, MADV_POPULATE_READ does not hide + /// errors, can be applied to (parts of) existing mappings and + /// will always populate (prefault) page tables readable. One + /// example use case is prefaulting a file mapping, reading all + /// file content from disk; however, pages won't be dirtied and + /// consequently won't have to be written back to disk when + /// evicting the pages from memory. + /// + /// Depending on the underlying mapping, map the shared zeropage, + /// preallocate memory or read the underlying file; files with + /// holes might or might not preallocate blocks. If populating + /// fails, a SIGBUS signal is not generated; instead, an error is + /// returned. + /// + /// If MADV_POPULATE_READ succeeds, all page tables have been + /// populated (prefaulted) readable once. If MADV_POPULATE_READ + /// fails, some page tables might have been populated. + /// + /// MADV_POPULATE_READ cannot be applied to mappings without read + /// permissions and special mappings, for example, mappings + /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO, + /// or secret memory regions created using memfd_secret(2). + /// + /// Note that with MADV_POPULATE_READ, the process can be killed + /// at any moment when the system runs out of memory. + #[cfg(target_os = "linux")] + PopulateRead = libc::MADV_POPULATE_READ, + + /// **MADV_POPULATE_WRITE** - Linux only (since Linux 5.14) + /// + /// Populate (prefault) page tables writable, faulting in all + /// pages in the range just as if manually writing to each each + /// page; however, avoid the actual memory access that would have + /// been performed after handling the fault. + /// + /// In contrast to MAP_POPULATE, MADV_POPULATE_WRITE does not + /// hide errors, can be applied to (parts of) existing mappings + /// and will always populate (prefault) page tables writable. + /// One example use case is preallocating memory, breaking any + /// CoW (Copy on Write). + /// + /// Depending on the underlying mapping, preallocate memory or + /// read the underlying file; files with holes will preallocate + /// blocks. If populating fails, a SIGBUS signal is not gener‐ + /// ated; instead, an error is returned. + /// + /// If MADV_POPULATE_WRITE succeeds, all page tables have been + /// populated (prefaulted) writable once. If MADV_POPULATE_WRITE + /// fails, some page tables might have been populated. + /// + /// MADV_POPULATE_WRITE cannot be applied to mappings without + /// write permissions and special mappings, for example, mappings + /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO, + /// or secret memory regions created using memfd_secret(2). + /// + /// Note that with MADV_POPULATE_WRITE, the process can be killed + /// at any moment when the system runs out of memory. + #[cfg(target_os = "linux")] + PopulateWrite = libc::MADV_POPULATE_WRITE, + + /// **MADV_ZERO_WIRED_PAGES** - Darwin only + /// + /// Indicates that the application would like the wired pages in this address range to be + /// zeroed out if the address range is deallocated without first unwiring the pages (i.e. + /// a munmap(2) without a preceding munlock(2) or the application quits). This is used + /// with `madvise()` system call. + #[cfg(target_vendor = "apple")] + ZeroWiredPages = libc::MADV_ZERO_WIRED_PAGES, +} + +/// Values supported by [`Mmap::unchecked_advise`][crate::Mmap::unchecked_advise] and [`MmapMut::unchecked_advise`][crate::MmapMut::unchecked_advise] functions. +/// +/// These flags can be passed to the [madvise (2)][man_page] system call +/// and effects on the mapped pages which are conceptually writes, +/// i.e. the change the observable contents of these pages which +/// implies undefined behaviour if the mapping is still borrowed. +/// +/// Hence, these potentially unsafe flags must be used with the unsafe +/// methods and the programmer has to justify that the code +/// does not keep any borrows of the mapping active while the mapped pages +/// are updated by the kernel's memory management subsystem. +/// +/// [man_page]: https://man7.org/linux/man-pages/man2/madvise.2.html +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum UncheckedAdvice { + /// **MADV_DONTNEED** + /// + /// Do not expect access in the near future. (For the time + /// being, the application is finished with the given range, + /// so the kernel can free resources associated with it.) + /// + /// After a successful MADV_DONTNEED operation, the semantics + /// of memory access in the specified region are changed: + /// subsequent accesses of pages in the range will succeed, + /// but will result in either repopulating the memory contents + /// from the up-to-date contents of the underlying mapped file + /// (for shared file mappings, shared anonymous mappings, and + /// shmem-based techniques such as System V shared memory + /// segments) or zero-fill-on-demand pages for anonymous + /// private mappings. + /// + /// Note that, when applied to shared mappings, MADV_DONTNEED + /// might not lead to immediate freeing of the pages in the + /// range. The kernel is free to delay freeing the pages + /// until an appropriate moment. The resident set size (RSS) + /// of the calling process will be immediately reduced + /// however. + /// + /// **MADV_DONTNEED** cannot be applied to locked pages, Huge TLB + /// pages, or VM_PFNMAP pages. (Pages marked with the kernel- + /// internal VM_PFNMAP flag are special memory areas that are + /// not managed by the virtual memory subsystem. Such pages + /// are typically created by device drivers that map the pages + /// into user space.) + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping when the pages + /// are freed results in undefined behaviour. + DontNeed = libc::MADV_DONTNEED, + + // + // The rest are Linux-specific + // + /// **MADV_FREE** - Linux (since Linux 4.5) and Darwin + /// + /// The application no longer requires the pages in the range + /// specified by addr and len. The kernel can thus free these + /// pages, but the freeing could be delayed until memory + /// pressure occurs. For each of the pages that has been + /// marked to be freed but has not yet been freed, the free + /// operation will be canceled if the caller writes into the + /// page. After a successful MADV_FREE operation, any stale + /// data (i.e., dirty, unwritten pages) will be lost when the + /// kernel frees the pages. However, subsequent writes to + /// pages in the range will succeed and then kernel cannot + /// free those dirtied pages, so that the caller can always + /// see just written data. If there is no subsequent write, + /// the kernel can free the pages at any time. Once pages in + /// the range have been freed, the caller will see zero-fill- + /// on-demand pages upon subsequent page references. + /// + /// The MADV_FREE operation can be applied only to private + /// anonymous pages (see mmap(2)). In Linux before version + /// 4.12, when freeing pages on a swapless system, the pages + /// in the given range are freed instantly, regardless of + /// memory pressure. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping while the pages + /// are still being freed results in undefined behaviour. + #[cfg(any(target_os = "linux", target_vendor = "apple"))] + Free = libc::MADV_FREE, + + /// **MADV_REMOVE** - Linux only (since Linux 2.6.16) + /// + /// Free up a given range of pages and its associated backing + /// store. This is equivalent to punching a hole in the + /// corresponding byte range of the backing store (see + /// fallocate(2)). Subsequent accesses in the specified + /// address range will see bytes containing zero. + /// + /// The specified address range must be mapped shared and + /// writable. This flag cannot be applied to locked pages, + /// Huge TLB pages, or VM_PFNMAP pages. + /// + /// In the initial implementation, only tmpfs(5) was supported + /// **MADV_REMOVE**; but since Linux 3.5, any filesystem which + /// supports the fallocate(2) FALLOC_FL_PUNCH_HOLE mode also + /// supports MADV_REMOVE. Hugetlbfs fails with the error + /// EINVAL and other filesystems fail with the error + /// EOPNOTSUPP. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping when the pages + /// are freed results in undefined behaviour. + #[cfg(target_os = "linux")] + Remove = libc::MADV_REMOVE, + + /// **MADV_FREE_REUSABLE** - Darwin only + /// + /// Behaves like **MADV_FREE**, but the freed pages are accounted for in the RSS of the process. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping while the pages + /// are still being freed results in undefined behaviour. + #[cfg(target_vendor = "apple")] + FreeReusable = libc::MADV_FREE_REUSABLE, + + /// **MADV_FREE_REUSE** - Darwin only + /// + /// Marks a memory region previously freed by **MADV_FREE_REUSABLE** as non-reusable, accounts + /// for the pages in the RSS of the process. Pages that have been freed will be replaced by + /// zero-filled pages on demand, other pages will be left as is. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping while the pages + /// are still being freed results in undefined behaviour. + #[cfg(target_vendor = "apple")] + FreeReuse = libc::MADV_FREE_REUSE, +} + +// Future expansion: +// MADV_SOFT_OFFLINE (since Linux 2.6.33) +// MADV_WIPEONFORK (since Linux 4.14) +// MADV_KEEPONFORK (since Linux 4.14) +// MADV_COLD (since Linux 5.4) +// MADV_PAGEOUT (since Linux 5.4) + +#[cfg(target_os = "linux")] +impl Advice { + /// Performs a runtime check if this advice is supported by the kernel. + /// Only supported on Linux. See the [`madvise(2)`] man page. + /// + /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html#VERSIONS + pub fn is_supported(self) -> bool { + (unsafe { libc::madvise(std::ptr::null_mut(), 0, self as libc::c_int) }) == 0 + } +} + +#[cfg(target_os = "linux")] +impl UncheckedAdvice { + /// Performs a runtime check if this advice is supported by the kernel. + /// Only supported on Linux. See the [`madvise(2)`] man page. + /// + /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html#VERSIONS + pub fn is_supported(self) -> bool { + (unsafe { libc::madvise(std::ptr::null_mut(), 0, self as libc::c_int) }) == 0 + } +} + +#[cfg(test)] +mod tests { + #[cfg(target_os = "linux")] + #[test] + fn test_is_supported() { + use super::*; + + assert!(Advice::Normal.is_supported()); + assert!(Advice::Random.is_supported()); + assert!(Advice::Sequential.is_supported()); + assert!(Advice::WillNeed.is_supported()); + + assert!(UncheckedAdvice::DontNeed.is_supported()); + } +} diff --git a/deps/crates/vendor/memmap2/src/lib.rs b/deps/crates/vendor/memmap2/src/lib.rs new file mode 100644 index 00000000000000..365f82803a8b1a --- /dev/null +++ b/deps/crates/vendor/memmap2/src/lib.rs @@ -0,0 +1,2328 @@ +#![deny(clippy::all, clippy::pedantic)] +#![allow( + // pedantic exceptions + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_sign_loss, + clippy::doc_markdown, + clippy::explicit_deref_methods, + clippy::missing_errors_doc, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::needless_pass_by_value, + clippy::return_self_not_must_use, + clippy::unreadable_literal, + clippy::upper_case_acronyms, +)] + +//! A cross-platform Rust API for memory mapped buffers. +//! +//! The core functionality is provided by either [`Mmap`] or [`MmapMut`], +//! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html) +//! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html) +//! respectively. Both function by dereferencing to a slice, allowing the +//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice +//! types. +//! +//! [`File`]: std::fs::File +//! +//! # Examples +//! +//! For simple cases [`Mmap`] can be used directly: +//! +//! ``` +//! use std::fs::File; +//! use std::io::Read; +//! +//! use memmap2::Mmap; +//! +//! # fn main() -> std::io::Result<()> { +//! let mut file = File::open("LICENSE-APACHE")?; +//! +//! let mut contents = Vec::new(); +//! file.read_to_end(&mut contents)?; +//! +//! let mmap = unsafe { Mmap::map(&file)? }; +//! +//! assert_eq!(&contents[..], &mmap[..]); +//! # Ok(()) +//! # } +//! ``` +//! +//! However for cases which require configuration of the mapping, then +//! you can use [`MmapOptions`] in order to further configure a mapping +//! before you create it. + +#![allow(clippy::len_without_is_empty, clippy::missing_safety_doc)] + +#[cfg_attr(unix, path = "unix.rs")] +#[cfg_attr(windows, path = "windows.rs")] +#[cfg_attr(not(any(unix, windows)), path = "stub.rs")] +mod os; +use crate::os::{file_len, MmapInner}; + +#[cfg(unix)] +mod advice; +#[cfg(unix)] +pub use crate::advice::{Advice, UncheckedAdvice}; + +use std::fmt; +#[cfg(not(any(unix, windows)))] +use std::fs::File; +use std::io::{Error, ErrorKind, Result}; +use std::ops::{Deref, DerefMut}; +#[cfg(unix)] +use std::os::unix::io::{AsRawFd, RawFd}; +#[cfg(windows)] +use std::os::windows::io::{AsRawHandle, RawHandle}; +use std::slice; + +#[cfg(not(any(unix, windows)))] +pub struct MmapRawDescriptor<'a>(&'a File); + +#[cfg(unix)] +pub struct MmapRawDescriptor(RawFd); + +#[cfg(windows)] +pub struct MmapRawDescriptor(RawHandle); + +pub trait MmapAsRawDesc { + fn as_raw_desc(&self) -> MmapRawDescriptor; +} + +#[cfg(not(any(unix, windows)))] +impl MmapAsRawDesc for &File { + fn as_raw_desc(&self) -> MmapRawDescriptor { + MmapRawDescriptor(self) + } +} + +#[cfg(unix)] +impl MmapAsRawDesc for RawFd { + fn as_raw_desc(&self) -> MmapRawDescriptor { + MmapRawDescriptor(*self) + } +} + +#[cfg(unix)] +impl MmapAsRawDesc for &T +where + T: AsRawFd, +{ + fn as_raw_desc(&self) -> MmapRawDescriptor { + MmapRawDescriptor(self.as_raw_fd()) + } +} + +#[cfg(windows)] +impl MmapAsRawDesc for RawHandle { + fn as_raw_desc(&self) -> MmapRawDescriptor { + MmapRawDescriptor(*self) + } +} + +#[cfg(windows)] +impl MmapAsRawDesc for &T +where + T: AsRawHandle, +{ + fn as_raw_desc(&self) -> MmapRawDescriptor { + MmapRawDescriptor(self.as_raw_handle()) + } +} + +/// A memory map builder, providing advanced options and flags for specifying memory map behavior. +/// +/// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a +/// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`], +/// [`map_copy()`], or [`map_copy_read_only()`]. +/// +/// ## Safety +/// +/// All file-backed memory map constructors are marked `unsafe` because of the potential for +/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or +/// out of process. Applications must consider the risk and take appropriate precautions when +/// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g. +/// unlinked) files exist but are platform specific and limited. +/// +/// [`map_anon()`]: MmapOptions::map_anon() +/// [`map()`]: MmapOptions::map() +/// [`map_mut()`]: MmapOptions::map_mut() +/// [`map_exec()`]: MmapOptions::map_exec() +/// [`map_copy()`]: MmapOptions::map_copy() +/// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only() +#[derive(Clone, Debug, Default)] +pub struct MmapOptions { + offset: u64, + len: Option, + huge: Option, + stack: bool, + populate: bool, + no_reserve_swap: bool, +} + +impl MmapOptions { + /// Creates a new set of options for configuring and creating a memory map. + /// + /// # Example + /// + /// ``` + /// use memmap2::{MmapMut, MmapOptions}; + /// # use std::io::Result; + /// + /// # fn main() -> Result<()> { + /// // Create a new memory map builder. + /// let mut mmap_options = MmapOptions::new(); + /// + /// // Configure the memory map builder using option setters, then create + /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`, + /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`: + /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?; + /// + /// // Use the memory map: + /// mmap.copy_from_slice(b"...data to copy to the memory map..."); + /// # Ok(()) + /// # } + /// ``` + pub fn new() -> MmapOptions { + MmapOptions::default() + } + + /// Configures the memory map to start at byte `offset` from the beginning of the file. + /// + /// This option has no effect on anonymous memory maps. + /// + /// By default, the offset is 0. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// + /// # fn main() -> std::io::Result<()> { + /// let mmap = unsafe { + /// MmapOptions::new() + /// .offset(30) + /// .map(&File::open("LICENSE-APACHE")?)? + /// }; + /// assert_eq!(&b"Apache License"[..], + /// &mmap[..14]); + /// # Ok(()) + /// # } + /// ``` + pub fn offset(&mut self, offset: u64) -> &mut Self { + self.offset = offset; + self + } + + /// Configures the created memory mapped buffer to be `len` bytes long. + /// + /// This option is mandatory for anonymous memory maps. + /// + /// For file-backed memory maps, the length will default to the file length. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// + /// # fn main() -> std::io::Result<()> { + /// let mmap = unsafe { + /// MmapOptions::new() + /// .len(9) + /// .map(&File::open("README.md")?)? + /// }; + /// assert_eq!(&b"# memmap2"[..], &mmap[..]); + /// # Ok(()) + /// # } + /// ``` + pub fn len(&mut self, len: usize) -> &mut Self { + self.len = Some(len); + self + } + + fn validate_len(len: u64) -> Result { + // Rust's slice cannot be larger than isize::MAX. + // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + // + // This is not a problem on 64-bit targets, but on 32-bit one + // having a file or an anonymous mapping larger than 2GB is quite normal + // and we have to prevent it. + if isize::try_from(len).is_err() { + return Err(Error::new( + ErrorKind::InvalidData, + "memory map length overflows isize", + )); + } + // If an unsigned number (u64) fits in isize, then it fits in usize. + Ok(len as usize) + } + + /// Returns the configured length, or the length of the provided file. + fn get_len(&self, file: &T) -> Result { + let len = if let Some(len) = self.len { + len as u64 + } else { + let desc = file.as_raw_desc(); + let file_len = file_len(desc.0)?; + + if file_len < self.offset { + return Err(Error::new( + ErrorKind::InvalidData, + "memory map offset is larger than length", + )); + } + + file_len - self.offset + }; + Self::validate_len(len) + } + + /// Configures the anonymous memory map to be suitable for a process or thread stack. + /// + /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on file-backed memory maps. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// + /// # fn main() -> std::io::Result<()> { + /// let stack = MmapOptions::new().stack().len(4096).map_anon(); + /// # Ok(()) + /// # } + /// ``` + pub fn stack(&mut self) -> &mut Self { + self.stack = true; + self + } + + /// Configures the anonymous memory map to be allocated using huge pages. + /// + /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// + /// The size of the requested page can be specified in page bits. If not provided, the system + /// default is requested. The requested length should be a multiple of this, or the mapping + /// will fail. + /// + /// This option has no effect on file-backed memory maps. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// + /// # fn main() -> std::io::Result<()> { + /// let stack = MmapOptions::new().huge(Some(21)).len(2*1024*1024).map_anon(); + /// # Ok(()) + /// # } + /// ``` + /// + /// The number 21 corresponds to `MAP_HUGE_2MB`. See mmap(2) for more details. + pub fn huge(&mut self, page_bits: Option) -> &mut Self { + self.huge = Some(page_bits.unwrap_or(0)); + self + } + + /// Populate (prefault) page tables for a mapping. + /// + /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. + /// + /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// + /// # fn main() -> std::io::Result<()> { + /// let file = File::open("LICENSE-MIT")?; + /// + /// let mmap = unsafe { + /// MmapOptions::new().populate().map(&file)? + /// }; + /// + /// assert_eq!(&b"Copyright"[..], &mmap[..9]); + /// # Ok(()) + /// # } + /// ``` + pub fn populate(&mut self) -> &mut Self { + self.populate = true; + self + } + + /// Do not reserve swap space for the memory map. + /// + /// By default, platforms may reserve swap space for memory maps. + /// This guarantees that a write to the mapped memory will succeed, even if physical memory is exhausted. + /// Otherwise, the write to memory could fail (on Linux with a segfault). + /// + /// This option requests that no swap space will be allocated for the memory map, + /// which can be useful for extremely large maps that are only written to sparsely. + /// + /// This option is currently supported on Linux, Android, Apple platforms (macOS, iOS, visionOS, etc.), NetBSD, Solaris and Illumos. + /// On those platforms, this option corresponds to the `MAP_NORESERVE` flag. + /// On Linux, this option is ignored if [`vm.overcommit_memory`](https://www.kernel.org/doc/Documentation/vm/overcommit-accounting) is set to 2. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// + /// # fn main() -> std::io::Result<()> { + /// let file = File::open("LICENSE-MIT")?; + /// + /// let mmap = unsafe { + /// MmapOptions::new().no_reserve_swap().map_copy(&file)? + /// }; + /// + /// assert_eq!(&b"Copyright"[..], &mmap[..9]); + /// # Ok(()) + /// # } + /// ``` + pub fn no_reserve_swap(&mut self) -> &mut Self { + self.no_reserve_swap = true; + self + } + + /// Creates a read-only memory map backed by a file. + /// + /// # Safety + /// + /// See the [type-level][MmapOptions] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// use std::io::Read; + /// + /// # fn main() -> std::io::Result<()> { + /// let mut file = File::open("LICENSE-APACHE")?; + /// + /// let mut contents = Vec::new(); + /// file.read_to_end(&mut contents)?; + /// + /// let mmap = unsafe { + /// MmapOptions::new().map(&file)? + /// }; + /// + /// assert_eq!(&contents[..], &mmap[..]); + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| Mmap { inner }) + } + + /// Creates a readable and executable memory map backed by a file. + /// + /// # Safety + /// + /// See the [type-level][MmapOptions] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub unsafe fn map_exec(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map_exec( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| Mmap { inner }) + } + + /// Creates a writeable memory map backed by a file. + /// + /// # Safety + /// + /// See the [type-level][MmapOptions] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read and write permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use std::fs::OpenOptions; + /// use std::path::PathBuf; + /// + /// use memmap2::MmapOptions; + /// # + /// # fn main() -> std::io::Result<()> { + /// # let tempdir = tempfile::tempdir()?; + /// let path: PathBuf = /* path to file */ + /// # tempdir.path().join("map_mut"); + /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?; + /// file.set_len(13)?; + /// + /// let mut mmap = unsafe { + /// MmapOptions::new().map_mut(&file)? + /// }; + /// + /// mmap.copy_from_slice(b"Hello, world!"); + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map_mut(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map_mut( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| MmapMut { inner }) + } + + /// Creates a copy-on-write memory map backed by a file. + /// + /// Data written to the memory map will not be visible by other processes, + /// and will not be carried through to the underlying file. + /// + /// # Safety + /// + /// See the [type-level][MmapOptions] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with writable permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// use std::io::Write; + /// + /// # fn main() -> std::io::Result<()> { + /// let file = File::open("LICENSE-APACHE")?; + /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? }; + /// (&mut mmap[..]).write_all(b"Hello, world!")?; + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map_copy(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map_copy( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| MmapMut { inner }) + } + + /// Creates a copy-on-write read-only memory map backed by a file. + /// + /// # Safety + /// + /// See the [type-level][MmapOptions] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// use std::fs::File; + /// use std::io::Read; + /// + /// # fn main() -> std::io::Result<()> { + /// let mut file = File::open("README.md")?; + /// + /// let mut contents = Vec::new(); + /// file.read_to_end(&mut contents)?; + /// + /// let mmap = unsafe { + /// MmapOptions::new().map_copy_read_only(&file)? + /// }; + /// + /// assert_eq!(&contents[..], &mmap[..]); + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map_copy_read_only(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map_copy_read_only( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| Mmap { inner }) + } + + /// Creates an anonymous memory map. + /// + /// The memory map length should be configured using [`MmapOptions::len()`] + /// before creating an anonymous memory map, otherwise a zero-length mapping + /// will be crated. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails or + /// when `len > isize::MAX`. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub fn map_anon(&self) -> Result { + let len = self.len.unwrap_or(0); + + // See get_len() for details. + let len = Self::validate_len(len as u64)?; + + MmapInner::map_anon( + len, + self.stack, + self.populate, + self.huge, + self.no_reserve_swap, + ) + .map(|inner| MmapMut { inner }) + } + + /// Creates a raw memory map. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read and write permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub fn map_raw(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map_mut( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| MmapRaw { inner }) + } + + /// Creates a read-only raw memory map + /// + /// This is primarily useful to avoid intermediate `Mmap` instances when + /// read-only access to files modified elsewhere are required. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub fn map_raw_read_only(&self, file: T) -> Result { + let desc = file.as_raw_desc(); + + MmapInner::map( + self.get_len(&file)?, + desc.0, + self.offset, + self.populate, + self.no_reserve_swap, + ) + .map(|inner| MmapRaw { inner }) + } +} + +/// A handle to an immutable memory mapped buffer. +/// +/// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use +/// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable +/// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable +/// with [`MmapMut::make_read_only()`]. +/// +/// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the +/// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File` +/// used to create it. For consistency, on some platforms this is achieved by duplicating the +/// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped. +/// +/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping +/// the mapped pages into physical memory) though the details of this are platform specific. +/// +/// `Mmap` is [`Sync`] and [`Send`]. +/// +/// See [`MmapMut`] for the mutable version. +/// +/// ## Safety +/// +/// All file-backed memory map constructors are marked `unsafe` because of the potential for +/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or +/// out of process. Applications must consider the risk and take appropriate precautions when using +/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) +/// files exist but are platform specific and limited. +/// +/// ## Example +/// +/// ``` +/// use memmap2::MmapOptions; +/// use std::io::Write; +/// use std::fs::File; +/// +/// # fn main() -> std::io::Result<()> { +/// let file = File::open("README.md")?; +/// let mmap = unsafe { MmapOptions::new().map(&file)? }; +/// assert_eq!(b"# memmap2", &mmap[0..9]); +/// # Ok(()) +/// # } +/// ``` +/// +/// [`map()`]: Mmap::map() +pub struct Mmap { + inner: MmapInner, +} + +impl Mmap { + /// Creates a read-only memory map backed by a file. + /// + /// This is equivalent to calling `MmapOptions::new().map(file)`. + /// + /// # Safety + /// + /// See the [type-level][Mmap] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use std::fs::File; + /// use std::io::Read; + /// + /// use memmap2::Mmap; + /// + /// # fn main() -> std::io::Result<()> { + /// let mut file = File::open("LICENSE-APACHE")?; + /// + /// let mut contents = Vec::new(); + /// file.read_to_end(&mut contents)?; + /// + /// let mmap = unsafe { Mmap::map(&file)? }; + /// + /// assert_eq!(&contents[..], &mmap[..]); + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map(file: T) -> Result { + MmapOptions::new().map(file) + } + + /// Transition the memory map to be writable. + /// + /// If the memory map is file-backed, the file must have been opened with write permissions. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with writable permissions. + /// + /// # Example + /// + /// ``` + /// use memmap2::Mmap; + /// use std::ops::DerefMut; + /// use std::io::Write; + /// # use std::fs::OpenOptions; + /// + /// # fn main() -> std::io::Result<()> { + /// # let tempdir = tempfile::tempdir()?; + /// let file = /* file opened with write permissions */ + /// # OpenOptions::new() + /// # .read(true) + /// # .write(true) + /// # .create(true) + /// # .truncate(true) + /// # .open(tempdir.path() + /// # .join("make_mut"))?; + /// # file.set_len(128)?; + /// let mmap = unsafe { Mmap::map(&file)? }; + /// // ... use the read-only memory map ... + /// let mut mut_mmap = mmap.make_mut()?; + /// mut_mmap.deref_mut().write_all(b"hello, world!")?; + /// # Ok(()) + /// # } + /// ``` + pub fn make_mut(mut self) -> Result { + self.inner.make_mut()?; + Ok(MmapMut { inner: self.inner }) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise(&self, advice: Advice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Lock the whole memory map into RAM. Only supported on Unix. + /// + /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. + #[cfg(unix)] + pub fn lock(&self) -> Result<()> { + self.inner.lock() + } + + /// Unlock the whole memory map. Only supported on Unix. + /// + /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. + #[cfg(unix)] + pub fn unlock(&self) -> Result<()> { + self.inner.unlock() + } + + /// Adjust the size of the memory mapping. + /// + /// This will try to resize the memory mapping in place. If + /// [`RemapOptions::may_move`] is specified it will move the mapping if it + /// could not resize in place, otherwise it will error. + /// + /// Only supported on Linux. + /// + /// See the [`mremap(2)`] man page. + /// + /// # Safety + /// + /// Resizing the memory mapping beyond the end of the mapped file will + /// result in UB should you happen to access memory beyond the end of the + /// file. + /// + /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html + #[cfg(target_os = "linux")] + pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { + self.inner.remap(new_len, options) + } +} + +#[cfg(feature = "stable_deref_trait")] +unsafe impl stable_deref_trait::StableDeref for Mmap {} + +impl Deref for Mmap { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } + } +} + +impl AsRef<[u8]> for Mmap { + #[inline] + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl fmt::Debug for Mmap { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Mmap") + .field("ptr", &self.as_ptr()) + .field("len", &self.len()) + .finish() + } +} + +/// A handle to a raw memory mapped buffer. +/// +/// This struct never hands out references to its interior, only raw pointers. +/// This can be helpful when creating shared memory maps between untrusted processes. +/// +/// For the safety concerns that arise when converting these raw pointers to references, +/// see the [`Mmap`] safety documentation. +pub struct MmapRaw { + inner: MmapInner, +} + +impl MmapRaw { + /// Creates a writeable memory map backed by a file. + /// + /// This is equivalent to calling `MmapOptions::new().map_raw(file)`. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read and write permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub fn map_raw(file: T) -> Result { + MmapOptions::new().map_raw(file) + } + + /// Returns a raw pointer to the memory mapped file. + /// + /// Before dereferencing this pointer, you have to make sure that the file has not been + /// truncated since the memory map was created. + /// Avoiding this will not introduce memory safety issues in Rust terms, + /// but will cause SIGBUS (or equivalent) signal. + #[inline] + pub fn as_ptr(&self) -> *const u8 { + self.inner.ptr() + } + + /// Returns an unsafe mutable pointer to the memory mapped file. + /// + /// Before dereferencing this pointer, you have to make sure that the file has not been + /// truncated since the memory map was created. + /// Avoiding this will not introduce memory safety issues in Rust terms, + /// but will cause SIGBUS (or equivalent) signal. + #[inline] + pub fn as_mut_ptr(&self) -> *mut u8 { + self.inner.ptr() as *mut u8 + } + + /// Returns the length in bytes of the memory map. + /// + /// Note that truncating the file can cause the length to change (and render this value unusable). + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + /// Flushes outstanding memory map modifications to disk. + /// + /// When this method returns with a non-error result, all outstanding changes to a file-backed + /// memory map are guaranteed to be durably stored. The file's metadata (including last + /// modification timestamp) may not be updated. + /// + /// # Example + /// + /// ``` + /// use std::fs::OpenOptions; + /// use std::io::Write; + /// use std::path::PathBuf; + /// use std::slice; + /// + /// use memmap2::MmapRaw; + /// + /// # fn main() -> std::io::Result<()> { + /// let tempdir = tempfile::tempdir()?; + /// let path: PathBuf = /* path to file */ + /// # tempdir.path().join("flush"); + /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?; + /// file.set_len(128)?; + /// + /// let mut mmap = unsafe { MmapRaw::map_raw(&file)? }; + /// + /// let mut memory = unsafe { slice::from_raw_parts_mut(mmap.as_mut_ptr(), 128) }; + /// memory.write_all(b"Hello, world!")?; + /// mmap.flush()?; + /// # Ok(()) + /// # } + /// ``` + pub fn flush(&self) -> Result<()> { + let len = self.len(); + self.inner.flush(0, len) + } + + /// Asynchronously flushes outstanding memory map modifications to disk. + /// + /// This method initiates flushing modified pages to durable storage, but it will not wait for + /// the operation to complete before returning. The file's metadata (including last + /// modification timestamp) may not be updated. + pub fn flush_async(&self) -> Result<()> { + let len = self.len(); + self.inner.flush_async(0, len) + } + + /// Flushes outstanding memory map modifications in the range to disk. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// When this method returns with a non-error result, all outstanding changes to a file-backed + /// memory in the range are guaranteed to be durable stored. The file's metadata (including + /// last modification timestamp) may not be updated. It is not guaranteed the only the changes + /// in the specified range are flushed; other outstanding changes to the memory map may be + /// flushed as well. + pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { + self.inner.flush(offset, len) + } + + /// Asynchronously flushes outstanding memory map modifications in the range to disk. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// This method initiates flushing modified pages to durable storage, but it will not wait for + /// the operation to complete before returning. The file's metadata (including last + /// modification timestamp) may not be updated. It is not guaranteed that the only changes + /// flushed are those in the specified range; other outstanding changes to the memory map may + /// be flushed as well. + pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { + self.inner.flush_async(offset, len) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise(&self, advice: Advice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Lock the whole memory map into RAM. Only supported on Unix. + /// + /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. + #[cfg(unix)] + pub fn lock(&self) -> Result<()> { + self.inner.lock() + } + + /// Unlock the whole memory map. Only supported on Unix. + /// + /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. + #[cfg(unix)] + pub fn unlock(&self) -> Result<()> { + self.inner.unlock() + } + + /// Adjust the size of the memory mapping. + /// + /// This will try to resize the memory mapping in place. If + /// [`RemapOptions::may_move`] is specified it will move the mapping if it + /// could not resize in place, otherwise it will error. + /// + /// Only supported on Linux. + /// + /// See the [`mremap(2)`] man page. + /// + /// # Safety + /// + /// Resizing the memory mapping beyond the end of the mapped file will + /// result in UB should you happen to access memory beyond the end of the + /// file. + /// + /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html + #[cfg(target_os = "linux")] + pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { + self.inner.remap(new_len, options) + } +} + +impl fmt::Debug for MmapRaw { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("MmapRaw") + .field("ptr", &self.as_ptr()) + .field("len", &self.len()) + .finish() + } +} + +impl From for MmapRaw { + fn from(value: Mmap) -> Self { + Self { inner: value.inner } + } +} + +impl From for MmapRaw { + fn from(value: MmapMut) -> Self { + Self { inner: value.inner } + } +} + +/// A handle to a mutable memory mapped buffer. +/// +/// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous +/// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use +/// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the +/// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default +/// options are required. +/// +/// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the +/// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File` +/// used to create it. For consistency, on some platforms this is achieved by duplicating the +/// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped. +/// +/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping +/// the mapped pages into physical memory) though the details of this are platform specific. +/// +/// `MmapMut` is [`Sync`] and [`Send`]. +/// +/// See [`Mmap`] for the immutable version. +/// +/// ## Safety +/// +/// All file-backed memory map constructors are marked `unsafe` because of the potential for +/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or +/// out of process. Applications must consider the risk and take appropriate precautions when using +/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) +/// files exist but are platform specific and limited. +pub struct MmapMut { + inner: MmapInner, +} + +impl MmapMut { + /// Creates a writeable memory map backed by a file. + /// + /// This is equivalent to calling `MmapOptions::new().map_mut(file)`. + /// + /// # Safety + /// + /// See the [type-level][MmapMut] docs for why this function is unsafe. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file is not open with read and write permissions. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + /// + /// # Example + /// + /// ``` + /// use std::fs::OpenOptions; + /// use std::path::PathBuf; + /// + /// use memmap2::MmapMut; + /// # + /// # fn main() -> std::io::Result<()> { + /// # let tempdir = tempfile::tempdir()?; + /// let path: PathBuf = /* path to file */ + /// # tempdir.path().join("map_mut"); + /// let file = OpenOptions::new() + /// .read(true) + /// .write(true) + /// .create(true) + /// .truncate(true) + /// .open(&path)?; + /// file.set_len(13)?; + /// + /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; + /// + /// mmap.copy_from_slice(b"Hello, world!"); + /// # Ok(()) + /// # } + /// ``` + pub unsafe fn map_mut(file: T) -> Result { + MmapOptions::new().map_mut(file) + } + + /// Creates an anonymous memory map. + /// + /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails or + /// when `len > isize::MAX`. + /// + /// Returns [`ErrorKind::Unsupported`] on unsupported platforms. + pub fn map_anon(length: usize) -> Result { + MmapOptions::new().len(length).map_anon() + } + + /// Flushes outstanding memory map modifications to disk. + /// + /// When this method returns with a non-error result, all outstanding changes to a file-backed + /// memory map are guaranteed to be durably stored. The file's metadata (including last + /// modification timestamp) may not be updated. + /// + /// # Example + /// + /// ``` + /// use std::fs::OpenOptions; + /// use std::io::Write; + /// use std::path::PathBuf; + /// + /// use memmap2::MmapMut; + /// + /// # fn main() -> std::io::Result<()> { + /// # let tempdir = tempfile::tempdir()?; + /// let path: PathBuf = /* path to file */ + /// # tempdir.path().join("flush"); + /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?; + /// file.set_len(128)?; + /// + /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; + /// + /// (&mut mmap[..]).write_all(b"Hello, world!")?; + /// mmap.flush()?; + /// # Ok(()) + /// # } + /// ``` + pub fn flush(&self) -> Result<()> { + let len = self.len(); + self.inner.flush(0, len) + } + + /// Asynchronously flushes outstanding memory map modifications to disk. + /// + /// This method initiates flushing modified pages to durable storage, but it will not wait for + /// the operation to complete before returning. The file's metadata (including last + /// modification timestamp) may not be updated. + pub fn flush_async(&self) -> Result<()> { + let len = self.len(); + self.inner.flush_async(0, len) + } + + /// Flushes outstanding memory map modifications in the range to disk. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// When this method returns with a non-error result, all outstanding changes to a file-backed + /// memory in the range are guaranteed to be durable stored. The file's metadata (including + /// last modification timestamp) may not be updated. It is not guaranteed the only the changes + /// in the specified range are flushed; other outstanding changes to the memory map may be + /// flushed as well. + pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { + self.inner.flush(offset, len) + } + + /// Asynchronously flushes outstanding memory map modifications in the range to disk. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// This method initiates flushing modified pages to durable storage, but it will not wait for + /// the operation to complete before returning. The file's metadata (including last + /// modification timestamp) may not be updated. It is not guaranteed that the only changes + /// flushed are those in the specified range; other outstanding changes to the memory map may + /// be flushed as well. + pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { + self.inner.flush_async(offset, len) + } + + /// Returns an immutable version of this memory mapped buffer. + /// + /// If the memory map is file-backed, the file must have been opened with read permissions. + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file has not been opened with read permissions. + /// + /// # Example + /// + /// ``` + /// use std::io::Write; + /// use std::path::PathBuf; + /// + /// use memmap2::{Mmap, MmapMut}; + /// + /// # fn main() -> std::io::Result<()> { + /// let mut mmap = MmapMut::map_anon(128)?; + /// + /// (&mut mmap[..]).write(b"Hello, world!")?; + /// + /// let mmap: Mmap = mmap.make_read_only()?; + /// # Ok(()) + /// # } + /// ``` + pub fn make_read_only(mut self) -> Result { + self.inner.make_read_only()?; + Ok(Mmap { inner: self.inner }) + } + + /// Transition the memory map to be readable and executable. + /// + /// If the memory map is file-backed, the file must have been opened with execute permissions. + /// + /// On systems with separate instructions and data caches (a category that includes many ARM + /// chips), a platform-specific call may be needed to ensure that the changes are visible to the + /// execution unit (e.g. when using this function to implement a JIT compiler). For more + /// details, see [this ARM write-up](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code) + /// or the `man` page for [`sys_icache_invalidate`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html). + /// + /// # Errors + /// + /// This method returns an error when the underlying system call fails, which can happen for a + /// variety of reasons, such as when the file has not been opened with execute permissions. + pub fn make_exec(mut self) -> Result { + self.inner.make_exec()?; + Ok(Mmap { inner: self.inner }) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise(&self, advice: Advice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Lock the whole memory map into RAM. Only supported on Unix. + /// + /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. + #[cfg(unix)] + pub fn lock(&self) -> Result<()> { + self.inner.lock() + } + + /// Unlock the whole memory map. Only supported on Unix. + /// + /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. + #[cfg(unix)] + pub fn unlock(&self) -> Result<()> { + self.inner.unlock() + } + + /// Adjust the size of the memory mapping. + /// + /// This will try to resize the memory mapping in place. If + /// [`RemapOptions::may_move`] is specified it will move the mapping if it + /// could not resize in place, otherwise it will error. + /// + /// Only supported on Linux. + /// + /// See the [`mremap(2)`] man page. + /// + /// # Safety + /// + /// Resizing the memory mapping beyond the end of the mapped file will + /// result in UB should you happen to access memory beyond the end of the + /// file. + /// + /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html + #[cfg(target_os = "linux")] + pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { + self.inner.remap(new_len, options) + } +} + +#[cfg(feature = "stable_deref_trait")] +unsafe impl stable_deref_trait::StableDeref for MmapMut {} + +impl Deref for MmapMut { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } + } +} + +impl DerefMut for MmapMut { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) } + } +} + +impl AsRef<[u8]> for MmapMut { + #[inline] + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl AsMut<[u8]> for MmapMut { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + self.deref_mut() + } +} + +impl fmt::Debug for MmapMut { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("MmapMut") + .field("ptr", &self.as_ptr()) + .field("len", &self.len()) + .finish() + } +} + +/// Options for [`Mmap::remap`] and [`MmapMut::remap`]. +#[derive(Copy, Clone, Default, Debug)] +#[cfg(target_os = "linux")] +pub struct RemapOptions { + may_move: bool, +} + +#[cfg(target_os = "linux")] +impl RemapOptions { + /// Creates a mew set of options for resizing a memory map. + pub fn new() -> Self { + Self::default() + } + + /// Controls whether the memory map can be moved if it is not possible to + /// resize it in place. + /// + /// If false then the memory map is guaranteed to remain at the same + /// address when being resized but attempting to resize will return an + /// error if the new memory map would overlap with something else in the + /// current process' memory. + /// + /// By default this is false. + /// + /// # `may_move` and `StableDeref` + /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and + /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the + /// memory map dereferences to a fixed address, however, calling `remap` + /// with `may_move` set may result in the backing memory of the mapping + /// being moved to a new address. This may cause UB in other code + /// depending on the `StableDeref` guarantees. + pub fn may_move(mut self, may_move: bool) -> Self { + self.may_move = may_move; + self + } + + pub(crate) fn into_flags(self) -> libc::c_int { + if self.may_move { + libc::MREMAP_MAYMOVE + } else { + 0 + } + } +} + +#[cfg(test)] +mod test { + #[cfg(unix)] + use crate::advice::Advice; + use std::fs::{File, OpenOptions}; + use std::io::{Read, Write}; + use std::mem; + #[cfg(unix)] + use std::os::unix::io::AsRawFd; + #[cfg(windows)] + use std::os::windows::fs::OpenOptionsExt; + + #[cfg(windows)] + const GENERIC_ALL: u32 = 0x10000000; + + use super::{Mmap, MmapMut, MmapOptions}; + + #[test] + fn map_file() { + let expected_len = 128; + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + file.set_len(expected_len as u64).unwrap(); + + let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + let len = mmap.len(); + assert_eq!(expected_len, len); + + let zeros = vec![0; len]; + let incr: Vec = (0..len as u8).collect(); + + // check that the mmap is empty + assert_eq!(&zeros[..], &mmap[..]); + + // write values into the mmap + (&mut mmap[..]).write_all(&incr[..]).unwrap(); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + } + + #[test] + #[cfg(unix)] + fn map_fd() { + let expected_len = 128; + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + file.set_len(expected_len as u64).unwrap(); + + let mut mmap = unsafe { MmapMut::map_mut(file.as_raw_fd()).unwrap() }; + let len = mmap.len(); + assert_eq!(expected_len, len); + + let zeros = vec![0; len]; + let incr: Vec = (0..len as u8).collect(); + + // check that the mmap is empty + assert_eq!(&zeros[..], &mmap[..]); + + // write values into the mmap + (&mut mmap[..]).write_all(&incr[..]).unwrap(); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + } + + /// Checks that "mapping" a 0-length file derefs to an empty slice. + #[test] + fn map_empty_file() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + let mmap = unsafe { Mmap::map(&file).unwrap() }; + assert!(mmap.is_empty()); + assert_eq!(mmap.as_ptr().align_offset(mem::size_of::()), 0); + let mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + assert!(mmap.is_empty()); + assert_eq!(mmap.as_ptr().align_offset(mem::size_of::()), 0); + } + + #[test] + fn map_anon() { + let expected_len = 128; + let mut mmap = MmapMut::map_anon(expected_len).unwrap(); + let len = mmap.len(); + assert_eq!(expected_len, len); + + let zeros = vec![0; len]; + let incr: Vec = (0..len as u8).collect(); + + // check that the mmap is empty + assert_eq!(&zeros[..], &mmap[..]); + + // write values into the mmap + (&mut mmap[..]).write_all(&incr[..]).unwrap(); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + } + + #[test] + fn map_anon_zero_len() { + assert!(MmapOptions::new().map_anon().unwrap().is_empty()); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn map_anon_len_overflow() { + let res = MmapMut::map_anon(0x80000000); + + assert_eq!( + res.unwrap_err().to_string(), + "memory map length overflows isize" + ); + } + + #[test] + fn file_write() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(128).unwrap(); + + let write = b"abc123"; + let mut read = [0u8; 6]; + + let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + (&mut mmap[..]).write_all(write).unwrap(); + mmap.flush().unwrap(); + + file.read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + } + + #[test] + fn flush_range() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(128).unwrap(); + let write = b"abc123"; + + let mut mmap = unsafe { + MmapOptions::new() + .offset(2) + .len(write.len()) + .map_mut(&file) + .unwrap() + }; + (&mut mmap[..]).write_all(write).unwrap(); + mmap.flush_async_range(0, write.len()).unwrap(); + mmap.flush_range(0, write.len()).unwrap(); + } + + #[test] + fn map_copy() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(128).unwrap(); + + let nulls = b"\0\0\0\0\0\0"; + let write = b"abc123"; + let mut read = [0u8; 6]; + + let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() }; + + (&mut mmap[..]).write_all(write).unwrap(); + mmap.flush().unwrap(); + + // The mmap contains the write + (&mmap[..]).read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + + // The file does not contain the write + file.read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + + // another mmap does not contain the write + let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; + (&mmap2[..]).read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + } + + #[test] + fn map_copy_read_only() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(128).unwrap(); + + let nulls = b"\0\0\0\0\0\0"; + let mut read = [0u8; 6]; + + let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() }; + (&mmap[..]).read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + + let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; + (&mmap2[..]).read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + } + + #[test] + fn map_offset() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + let offset = u64::from(u32::MAX) + 2; + let len = 5432; + file.set_len(offset + len as u64).unwrap(); + + // Check inferred length mmap. + let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() }; + assert_eq!(len, mmap.len()); + + // Check explicit length mmap. + let mut mmap = unsafe { + MmapOptions::new() + .offset(offset) + .len(len) + .map_mut(&file) + .unwrap() + }; + assert_eq!(len, mmap.len()); + + let zeros = vec![0; len]; + let incr: Vec<_> = (0..len).map(|i| i as u8).collect(); + + // check that the mmap is empty + assert_eq!(&zeros[..], &mmap[..]); + + // write values into the mmap + (&mut mmap[..]).write_all(&incr[..]).unwrap(); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + } + + #[test] + fn index() { + let mut mmap = MmapMut::map_anon(128).unwrap(); + mmap[0] = 42; + assert_eq!(42, mmap[0]); + } + + #[test] + fn sync_send() { + fn is_sync_send(_val: T) + where + T: Sync + Send, + { + } + + let mmap = MmapMut::map_anon(129).unwrap(); + is_sync_send(mmap); + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn jit_x86(mut mmap: MmapMut) { + mmap[0] = 0xB8; // mov eax, 0xAB + mmap[1] = 0xAB; + mmap[2] = 0x00; + mmap[3] = 0x00; + mmap[4] = 0x00; + mmap[5] = 0xC3; // ret + + let mmap = mmap.make_exec().expect("make_exec"); + + let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) }; + assert_eq!(jitfn(), 0xab); + } + + #[test] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn jit_x86_anon() { + jit_x86(MmapMut::map_anon(4096).unwrap()); + } + + #[test] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn jit_x86_file() { + let tempdir = tempfile::tempdir().unwrap(); + let mut options = OpenOptions::new(); + #[cfg(windows)] + options.access_mode(GENERIC_ALL); + + let file = options + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(tempdir.path().join("jit_x86")) + .expect("open"); + + file.set_len(4096).expect("set_len"); + jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") }); + } + + #[test] + fn mprotect_file() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let mut options = OpenOptions::new(); + #[cfg(windows)] + options.access_mode(GENERIC_ALL); + + let mut file = options + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .expect("open"); + file.set_len(256_u64).expect("set_len"); + + let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") }; + + let mmap = mmap.make_read_only().expect("make_read_only"); + let mut mmap = mmap.make_mut().expect("make_mut"); + + let write = b"abc123"; + let mut read = [0u8; 6]; + + (&mut mmap[..]).write_all(write).unwrap(); + mmap.flush().unwrap(); + + // The mmap contains the write + (&mmap[..]).read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + + // The file should contain the write + file.read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + + // another mmap should contain the write + let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; + (&mmap2[..]).read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + + let mmap = mmap.make_exec().expect("make_exec"); + + drop(mmap); + } + + #[test] + fn mprotect_copy() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap"); + + let mut options = OpenOptions::new(); + #[cfg(windows)] + options.access_mode(GENERIC_ALL); + + let mut file = options + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .expect("open"); + file.set_len(256_u64).expect("set_len"); + + let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") }; + + let mmap = mmap.make_read_only().expect("make_read_only"); + let mut mmap = mmap.make_mut().expect("make_mut"); + + let nulls = b"\0\0\0\0\0\0"; + let write = b"abc123"; + let mut read = [0u8; 6]; + + (&mut mmap[..]).write_all(write).unwrap(); + mmap.flush().unwrap(); + + // The mmap contains the write + (&mmap[..]).read_exact(&mut read).unwrap(); + assert_eq!(write, &read); + + // The file does not contain the write + file.read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + + // another mmap does not contain the write + let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; + (&mmap2[..]).read_exact(&mut read).unwrap(); + assert_eq!(nulls, &read); + + let mmap = mmap.make_exec().expect("make_exec"); + + drop(mmap); + } + + #[test] + fn mprotect_anon() { + let mmap = MmapMut::map_anon(256).expect("map_mut"); + + let mmap = mmap.make_read_only().expect("make_read_only"); + let mmap = mmap.make_mut().expect("make_mut"); + let mmap = mmap.make_exec().expect("make_exec"); + drop(mmap); + } + + #[test] + fn raw() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmapraw"); + + let mut options = OpenOptions::new(); + let mut file = options + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .expect("open"); + file.write_all(b"abc123").unwrap(); + let mmap = MmapOptions::new().map_raw(&file).unwrap(); + assert_eq!(mmap.len(), 6); + assert!(!mmap.as_ptr().is_null()); + assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a'); + } + + #[test] + fn raw_read_only() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmaprawro"); + + File::create(&path).unwrap().write_all(b"abc123").unwrap(); + + let mmap = MmapOptions::new() + .map_raw_read_only(&File::open(&path).unwrap()) + .unwrap(); + + assert_eq!(mmap.len(), 6); + assert!(!mmap.as_ptr().is_null()); + assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a'); + } + + /// Something that relies on StableDeref + #[test] + #[cfg(feature = "stable_deref_trait")] + fn owning_ref() { + let mut map = MmapMut::map_anon(128).unwrap(); + map[10] = 42; + let owning = owning_ref::OwningRef::new(map); + let sliced = owning.map(|map| &map[10..20]); + assert_eq!(42, sliced[0]); + + let map = sliced.into_owner().make_read_only().unwrap(); + let owning = owning_ref::OwningRef::new(map); + let sliced = owning.map(|map| &map[10..20]); + assert_eq!(42, sliced[0]); + } + + #[test] + #[cfg(unix)] + fn advise() { + let expected_len = 128; + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap_advise"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + file.set_len(expected_len as u64).unwrap(); + + // Test MmapMut::advise + let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + mmap.advise(Advice::Random) + .expect("mmap advising should be supported on unix"); + + let len = mmap.len(); + assert_eq!(expected_len, len); + + let zeros = vec![0; len]; + let incr: Vec = (0..len as u8).collect(); + + // check that the mmap is empty + assert_eq!(&zeros[..], &mmap[..]); + + mmap.advise_range(Advice::Sequential, 0, mmap.len()) + .expect("mmap advising should be supported on unix"); + + // write values into the mmap + (&mut mmap[..]).write_all(&incr[..]).unwrap(); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + + // Set advice and Read from the read-only map + let mmap = unsafe { Mmap::map(&file).unwrap() }; + + mmap.advise(Advice::Random) + .expect("mmap advising should be supported on unix"); + + // read values back + assert_eq!(&incr[..], &mmap[..]); + } + + #[test] + #[cfg(target_os = "linux")] + fn advise_writes_unsafely() { + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + + let mut mmap = MmapMut::map_anon(page_size).unwrap(); + mmap.as_mut().fill(255); + let mmap = mmap.make_read_only().unwrap(); + + let a = mmap.as_ref()[0]; + unsafe { + mmap.unchecked_advise(crate::UncheckedAdvice::DontNeed) + .unwrap(); + } + let b = mmap.as_ref()[0]; + + assert_eq!(a, 255); + assert_eq!(b, 0); + } + + #[test] + #[cfg(target_os = "linux")] + fn advise_writes_unsafely_to_part_of_map() { + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + + let mut mmap = MmapMut::map_anon(2 * page_size).unwrap(); + mmap.as_mut().fill(255); + let mmap = mmap.make_read_only().unwrap(); + + let a = mmap.as_ref()[0]; + let b = mmap.as_ref()[page_size]; + unsafe { + mmap.unchecked_advise_range(crate::UncheckedAdvice::DontNeed, page_size, page_size) + .unwrap(); + } + let c = mmap.as_ref()[0]; + let d = mmap.as_ref()[page_size]; + + assert_eq!(a, 255); + assert_eq!(b, 255); + assert_eq!(c, 255); + assert_eq!(d, 0); + } + + /// Returns true if a non-zero amount of memory is locked. + #[cfg(target_os = "linux")] + fn is_locked() -> bool { + let status = &std::fs::read_to_string("/proc/self/status") + .expect("/proc/self/status should be available"); + for line in status.lines() { + if line.starts_with("VmLck:") { + let numbers = line.replace(|c: char| !c.is_ascii_digit(), ""); + return numbers != "0"; + } + } + panic!("cannot get VmLck information") + } + + #[test] + #[cfg(unix)] + fn lock() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap_lock"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.set_len(128).unwrap(); + + let mmap = unsafe { Mmap::map(&file).unwrap() }; + #[cfg(target_os = "linux")] + assert!(!is_locked()); + + mmap.lock().expect("mmap lock should be supported on unix"); + #[cfg(target_os = "linux")] + assert!(is_locked()); + + mmap.lock() + .expect("mmap lock again should not cause problems"); + #[cfg(target_os = "linux")] + assert!(is_locked()); + + mmap.unlock() + .expect("mmap unlock should be supported on unix"); + #[cfg(target_os = "linux")] + assert!(!is_locked()); + + mmap.unlock() + .expect("mmap unlock again should not cause problems"); + #[cfg(target_os = "linux")] + assert!(!is_locked()); + } + + #[test] + #[cfg(target_os = "linux")] + fn remap_grow() { + use crate::RemapOptions; + + let initial_len = 128; + let final_len = 2000; + + let zeros = vec![0u8; final_len]; + let incr: Vec = (0..final_len).map(|v| v as u8).collect(); + + let file = tempfile::tempfile().unwrap(); + file.set_len(final_len as u64).unwrap(); + + let mut mmap = unsafe { MmapOptions::new().len(initial_len).map_mut(&file).unwrap() }; + assert_eq!(mmap.len(), initial_len); + assert_eq!(&mmap[..], &zeros[..initial_len]); + + unsafe { + mmap.remap(final_len, RemapOptions::new().may_move(true)) + .unwrap(); + } + + // The size should have been updated + assert_eq!(mmap.len(), final_len); + + // Should still be all zeros + assert_eq!(&mmap[..], &zeros); + + // Write out to the whole expanded slice. + mmap.copy_from_slice(&incr); + } + + #[test] + #[cfg(target_os = "linux")] + fn remap_shrink() { + use crate::RemapOptions; + + let initial_len = 20000; + let final_len = 400; + + let incr: Vec = (0..final_len).map(|v| v as u8).collect(); + + let file = tempfile::tempfile().unwrap(); + file.set_len(initial_len as u64).unwrap(); + + let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; + assert_eq!(mmap.len(), initial_len); + + unsafe { mmap.remap(final_len, RemapOptions::new()).unwrap() }; + assert_eq!(mmap.len(), final_len); + + // Check that the mmap is still writable along the slice length + mmap.copy_from_slice(&incr); + } + + #[test] + #[cfg(target_os = "linux")] + #[cfg(target_pointer_width = "32")] + fn remap_len_overflow() { + use crate::RemapOptions; + + let file = tempfile::tempfile().unwrap(); + file.set_len(1024).unwrap(); + let mut mmap = unsafe { MmapOptions::new().len(1024).map(&file).unwrap() }; + + let res = unsafe { mmap.remap(0x80000000, RemapOptions::new().may_move(true)) }; + assert_eq!( + res.unwrap_err().to_string(), + "memory map length overflows isize" + ); + + assert_eq!(mmap.len(), 1024); + } + + #[test] + #[cfg(target_os = "linux")] + fn remap_with_offset() { + use crate::RemapOptions; + + let offset = 77; + let initial_len = 128; + let final_len = 2000; + + let zeros = vec![0u8; final_len]; + let incr: Vec = (0..final_len).map(|v| v as u8).collect(); + + let file = tempfile::tempfile().unwrap(); + file.set_len(final_len as u64 + offset).unwrap(); + + let mut mmap = unsafe { + MmapOptions::new() + .len(initial_len) + .offset(offset) + .map_mut(&file) + .unwrap() + }; + assert_eq!(mmap.len(), initial_len); + assert_eq!(&mmap[..], &zeros[..initial_len]); + + unsafe { + mmap.remap(final_len, RemapOptions::new().may_move(true)) + .unwrap(); + } + + // The size should have been updated + assert_eq!(mmap.len(), final_len); + + // Should still be all zeros + assert_eq!(&mmap[..], &zeros); + + // Write out to the whole expanded slice. + mmap.copy_from_slice(&incr); + } +} diff --git a/deps/crates/vendor/memmap2/src/stub.rs b/deps/crates/vendor/memmap2/src/stub.rs new file mode 100644 index 00000000000000..aa2e527fe63194 --- /dev/null +++ b/deps/crates/vendor/memmap2/src/stub.rs @@ -0,0 +1,84 @@ +use std::fs::File; +use std::io; + +// A stable alternative to https://doc.rust-lang.org/stable/std/primitive.never.html +enum Never {} + +pub struct MmapInner { + never: Never, +} + +impl MmapInner { + fn new() -> io::Result { + Err(io::ErrorKind::Unsupported.into()) + } + + pub fn map(_: usize, _: &File, _: u64, _: bool, _: bool) -> io::Result { + MmapInner::new() + } + + pub fn map_exec(_: usize, _: &File, _: u64, _: bool, _: bool) -> io::Result { + MmapInner::new() + } + + pub fn map_mut(_: usize, _: &File, _: u64, _: bool, _: bool) -> io::Result { + MmapInner::new() + } + + pub fn map_copy(_: usize, _: &File, _: u64, _: bool, _: bool) -> io::Result { + MmapInner::new() + } + + pub fn map_copy_read_only( + _: usize, + _: &File, + _: u64, + _: bool, + _: bool, + ) -> io::Result { + MmapInner::new() + } + + pub fn map_anon(_: usize, _: bool, _: bool, _: Option, _: bool) -> io::Result { + MmapInner::new() + } + + pub fn flush(&self, _: usize, _: usize) -> io::Result<()> { + match self.never {} + } + + pub fn flush_async(&self, _: usize, _: usize) -> io::Result<()> { + match self.never {} + } + + pub fn make_read_only(&mut self) -> io::Result<()> { + match self.never {} + } + + pub fn make_exec(&mut self) -> io::Result<()> { + match self.never {} + } + + pub fn make_mut(&mut self) -> io::Result<()> { + match self.never {} + } + + #[inline] + pub fn ptr(&self) -> *const u8 { + match self.never {} + } + + #[inline] + pub fn mut_ptr(&mut self) -> *mut u8 { + match self.never {} + } + + #[inline] + pub fn len(&self) -> usize { + match self.never {} + } +} + +pub fn file_len(file: &File) -> io::Result { + Ok(file.metadata()?.len()) +} diff --git a/deps/crates/vendor/memmap2/src/unix.rs b/deps/crates/vendor/memmap2/src/unix.rs new file mode 100644 index 00000000000000..74e4d27720c18c --- /dev/null +++ b/deps/crates/vendor/memmap2/src/unix.rs @@ -0,0 +1,525 @@ +use std::fs::File; +use std::mem::ManuallyDrop; +use std::os::unix::io::{FromRawFd, RawFd}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::{io, ptr}; + +#[cfg(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "freebsd", + target_os = "android" +))] +const MAP_STACK: libc::c_int = libc::MAP_STACK; + +#[cfg(not(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "freebsd", + target_os = "android" +)))] +const MAP_STACK: libc::c_int = 0; + +#[cfg(any(target_os = "linux", target_os = "android"))] +const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE; + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +const MAP_POPULATE: libc::c_int = 0; + +#[cfg(any(target_os = "linux", target_os = "android"))] +const MAP_HUGETLB: libc::c_int = libc::MAP_HUGETLB; + +#[cfg(target_os = "linux")] +const MAP_HUGE_MASK: libc::c_int = libc::MAP_HUGE_MASK; + +#[cfg(any(target_os = "linux", target_os = "android"))] +const MAP_HUGE_SHIFT: libc::c_int = libc::MAP_HUGE_SHIFT; + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +const MAP_HUGETLB: libc::c_int = 0; + +#[cfg(not(target_os = "linux"))] +const MAP_HUGE_MASK: libc::c_int = 0; + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +const MAP_HUGE_SHIFT: libc::c_int = 0; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_vendor = "apple", + target_os = "netbsd", + target_os = "solaris", + target_os = "illumos", +))] +const MAP_NORESERVE: libc::c_int = libc::MAP_NORESERVE; + +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_vendor = "apple", + target_os = "netbsd", + target_os = "solaris", + target_os = "illumos", +)))] +const MAP_NORESERVE: libc::c_int = 0; + +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "musl")) +))] +use libc::{mmap64 as mmap, off64_t as off_t}; + +#[cfg(not(any( + target_os = "android", + all(target_os = "linux", not(target_env = "musl")) +)))] +use libc::{mmap, off_t}; + +pub struct MmapInner { + ptr: *mut libc::c_void, + len: usize, +} + +impl MmapInner { + /// Creates a new `MmapInner`. + /// + /// This is a thin wrapper around the `mmap` system call. + fn new( + len: usize, + prot: libc::c_int, + flags: libc::c_int, + file: RawFd, + offset: u64, + ) -> io::Result { + let alignment = offset % page_size() as u64; + let aligned_offset = offset - alignment; + + let (map_len, map_offset) = Self::adjust_mmap_params(len, alignment as usize)?; + + unsafe { + let ptr = mmap( + ptr::null_mut(), + map_len as libc::size_t, + prot, + flags, + file, + aligned_offset as off_t, + ); + + if ptr == libc::MAP_FAILED { + Err(io::Error::last_os_error()) + } else { + Ok(Self::from_raw_parts(ptr, len, map_offset)) + } + } + } + + fn adjust_mmap_params(len: usize, alignment: usize) -> io::Result<(usize, usize)> { + // Rust's slice cannot be larger than isize::MAX. + // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + // + // This is not a problem on 64-bit targets, but on 32-bit one + // having a file or an anonymous mapping larger than 2GB is quite normal + // and we have to prevent it. + // + // The code below is essentially the same as in Rust's std: + // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495 + if std::mem::size_of::() < 8 && len > isize::MAX as usize { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "memory map length overflows isize", + )); + } + + let map_len = len + alignment; + let map_offset = alignment; + + // `libc::mmap` does not support zero-size mappings. POSIX defines: + // + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html + // > If `len` is zero, `mmap()` shall fail and no mapping shall be established. + // + // So if we would create such a mapping, crate a one-byte mapping instead: + let map_len = map_len.max(1); + + // Note that in that case `MmapInner::len` is still set to zero, + // and `Mmap` will still dereferences to an empty slice. + // + // If this mapping is backed by an empty file, we create a mapping larger than the file. + // This is unusual but well-defined. On the same man page, POSIX further defines: + // + // > The `mmap()` function can be used to map a region of memory that is larger + // > than the current size of the object. + // + // (The object here is the file.) + // + // > Memory access within the mapping but beyond the current end of the underlying + // > objects may result in SIGBUS signals being sent to the process. The reason for this + // > is that the size of the object can be manipulated by other processes and can change + // > at any moment. The implementation should tell the application that a memory reference + // > is outside the object where this can be detected; otherwise, written data may be lost + // > and read data may not reflect actual data in the object. + // + // Because `MmapInner::len` is not incremented, this increment of `aligned_len` + // will not allow accesses past the end of the file and will not cause SIGBUS. + // + // (SIGBUS is still possible by mapping a non-empty file and then truncating it + // to a shorter size, but that is unrelated to this handling of empty files.) + Ok((map_len, map_offset)) + } + + /// Get the current memory mapping as a `(ptr, map_len, offset)` tuple. + /// + /// Note that `map_len` is the length of the memory mapping itself and + /// _not_ the one that would be passed to `from_raw_parts`. + fn as_mmap_params(&self) -> (*mut libc::c_void, usize, usize) { + let offset = self.ptr as usize % page_size(); + let len = self.len + offset; + + // There are two possible memory layouts we could have, depending on + // the length and offset passed when constructing this instance: + // + // 1. The "normal" memory layout looks like this: + // + // |<------------------>|<---------------------->| + // mmap ptr offset ptr public slice + // + // That is, we have + // - The start of the page-aligned memory mapping returned by mmap, + // followed by, + // - Some number of bytes that are memory mapped but ignored since + // they are before the byte offset requested by the user, followed + // by, + // - The actual memory mapped slice requested by the user. + // + // This maps cleanly to a (ptr, len, offset) tuple. + // + // 2. Then, we have the case where the user requested a zero-length + // memory mapping. mmap(2) does not support zero-length mappings so + // this crate works around that by actually making a mapping of + // length one. This means that we have + // - A length zero slice, followed by, + // - A single memory mapped byte + // + // Note that this only happens if the offset within the page is also + // zero. Otherwise, we have a memory map of offset bytes and not a + // zero-length memory map. + // + // This doesn't fit cleanly into a (ptr, len, offset) tuple. Instead, + // we fudge it slightly: a zero-length memory map turns into a + // mapping of length one and can't be told apart outside of this + // method without knowing the original length. + if len == 0 { + (self.ptr, 1, 0) + } else { + (unsafe { self.ptr.offset(-(offset as isize)) }, len, offset) + } + } + + /// Construct this `MmapInner` from its raw components + /// + /// # Safety + /// + /// - `ptr` must point to the start of memory mapping that can be freed + /// using `munmap(2)` (i.e. returned by `mmap(2)` or `mremap(2)`) + /// - The memory mapping at `ptr` must have a length of `len + offset`. + /// - If `len + offset == 0` then the memory mapping must be of length 1. + /// - `offset` must be less than the current page size. + unsafe fn from_raw_parts(ptr: *mut libc::c_void, len: usize, offset: usize) -> Self { + debug_assert_eq!(ptr as usize % page_size(), 0, "ptr not page-aligned"); + debug_assert!(offset < page_size(), "offset larger than page size"); + + Self { + ptr: ptr.add(offset), + len, + } + } + + pub fn map( + len: usize, + file: RawFd, + offset: u64, + populate: bool, + no_reserve: bool, + ) -> io::Result { + let populate = if populate { MAP_POPULATE } else { 0 }; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ, + libc::MAP_SHARED | populate | no_reserve, + file, + offset, + ) + } + + pub fn map_exec( + len: usize, + file: RawFd, + offset: u64, + populate: bool, + no_reserve: bool, + ) -> io::Result { + let populate = if populate { MAP_POPULATE } else { 0 }; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ | libc::PROT_EXEC, + libc::MAP_SHARED | populate | no_reserve, + file, + offset, + ) + } + + pub fn map_mut( + len: usize, + file: RawFd, + offset: u64, + populate: bool, + no_reserve: bool, + ) -> io::Result { + let populate = if populate { MAP_POPULATE } else { 0 }; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED | populate | no_reserve, + file, + offset, + ) + } + + pub fn map_copy( + len: usize, + file: RawFd, + offset: u64, + populate: bool, + no_reserve: bool, + ) -> io::Result { + let populate = if populate { MAP_POPULATE } else { 0 }; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE | populate | no_reserve, + file, + offset, + ) + } + + pub fn map_copy_read_only( + len: usize, + file: RawFd, + offset: u64, + populate: bool, + no_reserve: bool, + ) -> io::Result { + let populate = if populate { MAP_POPULATE } else { 0 }; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ, + libc::MAP_PRIVATE | populate | no_reserve, + file, + offset, + ) + } + + /// Open an anonymous memory map. + pub fn map_anon( + len: usize, + stack: bool, + populate: bool, + huge: Option, + no_reserve: bool, + ) -> io::Result { + let stack = if stack { MAP_STACK } else { 0 }; + let populate = if populate { MAP_POPULATE } else { 0 }; + let hugetlb = if huge.is_some() { MAP_HUGETLB } else { 0 }; + let hugetlb_size = huge.map_or(0, |mask| { + (u64::from(mask) & (MAP_HUGE_MASK as u64)) << MAP_HUGE_SHIFT + }) as i32; + let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; + MmapInner::new( + len, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE + | libc::MAP_ANON + | stack + | populate + | hugetlb + | hugetlb_size + | no_reserve, + -1, + 0, + ) + } + + pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> { + let alignment = (self.ptr as usize + offset) % page_size(); + let offset = offset as isize - alignment as isize; + let len = len + alignment; + let result = + unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_SYNC) }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> { + let alignment = (self.ptr as usize + offset) % page_size(); + let offset = offset as isize - alignment as isize; + let len = len + alignment; + let result = + unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_ASYNC) }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + fn mprotect(&mut self, prot: libc::c_int) -> io::Result<()> { + unsafe { + let alignment = self.ptr as usize % page_size(); + let ptr = self.ptr.offset(-(alignment as isize)); + let len = self.len + alignment; + let len = len.max(1); + if libc::mprotect(ptr, len, prot) == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn make_read_only(&mut self) -> io::Result<()> { + self.mprotect(libc::PROT_READ) + } + + pub fn make_exec(&mut self) -> io::Result<()> { + self.mprotect(libc::PROT_READ | libc::PROT_EXEC) + } + + pub fn make_mut(&mut self) -> io::Result<()> { + self.mprotect(libc::PROT_READ | libc::PROT_WRITE) + } + + #[inline] + pub fn ptr(&self) -> *const u8 { + self.ptr as *const u8 + } + + #[inline] + pub fn mut_ptr(&mut self) -> *mut u8 { + self.ptr.cast() + } + + #[inline] + pub fn len(&self) -> usize { + self.len + } + + pub fn advise(&self, advice: libc::c_int, offset: usize, len: usize) -> io::Result<()> { + let alignment = (self.ptr as usize + offset) % page_size(); + let offset = offset as isize - alignment as isize; + let len = len + alignment; + unsafe { + let ptr = { + // The AIX signature of 'madvise()' differs from the POSIX + // specification, which expects 'void *' as the type of the + // 'addr' argument, whereas AIX uses 'caddr_t' (i.e., 'char *'). + #[cfg(target_os = "aix")] + { + self.ptr.offset(offset) as *mut u8 + } + #[cfg(not(target_os = "aix"))] + { + self.ptr.offset(offset) + } + }; + if libc::madvise(ptr, len, advice) != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } + + #[cfg(target_os = "linux")] + pub fn remap(&mut self, new_len: usize, options: crate::RemapOptions) -> io::Result<()> { + let (old_ptr, old_len, offset) = self.as_mmap_params(); + let (map_len, offset) = Self::adjust_mmap_params(new_len, offset)?; + + unsafe { + let new_ptr = libc::mremap(old_ptr, old_len, map_len, options.into_flags()); + + if new_ptr == libc::MAP_FAILED { + Err(io::Error::last_os_error()) + } else { + // We explicitly don't drop self since the pointer within is no longer valid. + ptr::write(self, Self::from_raw_parts(new_ptr, new_len, offset)); + Ok(()) + } + } + } + + pub fn lock(&self) -> io::Result<()> { + unsafe { + if libc::mlock(self.ptr, self.len) != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } + + pub fn unlock(&self) -> io::Result<()> { + unsafe { + if libc::munlock(self.ptr, self.len) != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} + +impl Drop for MmapInner { + fn drop(&mut self) { + let (ptr, len, _) = self.as_mmap_params(); + + // Any errors during unmapping/closing are ignored as the only way + // to report them would be through panicking which is highly discouraged + // in Drop impls, c.f. https://github.com/rust-lang/lang-team/issues/97 + unsafe { libc::munmap(ptr, len as libc::size_t) }; + } +} + +unsafe impl Sync for MmapInner {} +unsafe impl Send for MmapInner {} + +fn page_size() -> usize { + static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); + + match PAGE_SIZE.load(Ordering::Relaxed) { + 0 => { + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + + PAGE_SIZE.store(page_size, Ordering::Relaxed); + + page_size + } + page_size => page_size, + } +} + +pub fn file_len(file: RawFd) -> io::Result { + // SAFETY: We must not close the passed-in fd by dropping the File we create, + // we ensure this by immediately wrapping it in a ManuallyDrop. + unsafe { + let file = ManuallyDrop::new(File::from_raw_fd(file)); + Ok(file.metadata()?.len()) + } +} diff --git a/deps/crates/vendor/memmap2/src/windows.rs b/deps/crates/vendor/memmap2/src/windows.rs new file mode 100644 index 00000000000000..3d2fc4955bcee3 --- /dev/null +++ b/deps/crates/vendor/memmap2/src/windows.rs @@ -0,0 +1,530 @@ +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use std::fs::File; +use std::mem::ManuallyDrop; +use std::os::raw::c_void; +use std::os::windows::io::{FromRawHandle, RawHandle}; +use std::{io, mem, ptr}; + +type BOOL = i32; +type WORD = u16; +type DWORD = u32; +type WCHAR = u16; +type HANDLE = *mut c_void; +type LPHANDLE = *mut HANDLE; +type LPVOID = *mut c_void; +type LPCVOID = *const c_void; +type ULONG_PTR = usize; +type SIZE_T = ULONG_PTR; +type LPCWSTR = *const WCHAR; +type PDWORD = *mut DWORD; +type DWORD_PTR = ULONG_PTR; +type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +type LPSYSTEM_INFO = *mut SYSTEM_INFO; + +const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; + +const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; + +const STANDARD_RIGHTS_REQUIRED: DWORD = 0x000F0000; + +const SECTION_QUERY: DWORD = 0x0001; +const SECTION_MAP_WRITE: DWORD = 0x0002; +const SECTION_MAP_READ: DWORD = 0x0004; +const SECTION_MAP_EXECUTE: DWORD = 0x0008; +const SECTION_EXTEND_SIZE: DWORD = 0x0010; +const SECTION_MAP_EXECUTE_EXPLICIT: DWORD = 0x0020; +const SECTION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED + | SECTION_QUERY + | SECTION_MAP_WRITE + | SECTION_MAP_READ + | SECTION_MAP_EXECUTE + | SECTION_EXTEND_SIZE; + +const PAGE_READONLY: DWORD = 0x02; +const PAGE_READWRITE: DWORD = 0x04; +const PAGE_WRITECOPY: DWORD = 0x08; +const PAGE_EXECUTE_READ: DWORD = 0x20; +const PAGE_EXECUTE_READWRITE: DWORD = 0x40; +const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80; + +const FILE_MAP_WRITE: DWORD = SECTION_MAP_WRITE; +const FILE_MAP_READ: DWORD = SECTION_MAP_READ; +const FILE_MAP_ALL_ACCESS: DWORD = SECTION_ALL_ACCESS; +const FILE_MAP_EXECUTE: DWORD = SECTION_MAP_EXECUTE_EXPLICIT; +const FILE_MAP_COPY: DWORD = 0x00000001; + +#[repr(C)] +struct SECURITY_ATTRIBUTES { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +} + +#[repr(C)] +struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + wReserved: WORD, + dwPageSize: DWORD, + lpMinimumApplicationAddress: LPVOID, + lpMaximumApplicationAddress: LPVOID, + dwActiveProcessorMask: DWORD_PTR, + dwNumberOfProcessors: DWORD, + dwProcessorType: DWORD, + dwAllocationGranularity: DWORD, + wProcessorLevel: WORD, + wProcessorRevision: WORD, +} + +#[allow(dead_code)] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +extern "system" { + fn GetCurrentProcess() -> HANDLE; + + fn CloseHandle(hObject: HANDLE) -> BOOL; + + fn DuplicateHandle( + hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD, + ) -> BOOL; + + fn CreateFileMappingW( + hFile: HANDLE, + lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCWSTR, + ) -> HANDLE; + + fn FlushFileBuffers(hFile: HANDLE) -> BOOL; + + fn FlushViewOfFile(lpBaseAddress: LPCVOID, dwNumberOfBytesToFlush: SIZE_T) -> BOOL; + + fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL; + + fn MapViewOfFile( + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, + dwNumberOfBytesToMap: SIZE_T, + ) -> LPVOID; + + fn VirtualProtect( + lpAddress: LPVOID, + dwSize: SIZE_T, + flNewProtect: DWORD, + lpflOldProtect: PDWORD, + ) -> BOOL; + + fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO); +} + +/// Returns a fixed aligned pointer that is valid for `slice::from_raw_parts::` with `len == 0`. +/// +/// This aligns the pointer to `allocation_granularity()` or 1 if unknown. +fn empty_slice_ptr() -> *mut c_void { + allocation_granularity().max(1) as *mut c_void +} + +pub struct MmapInner { + handle: Option, + ptr: *mut c_void, + len: usize, + copy: bool, +} + +impl MmapInner { + /// Creates a new `MmapInner`. + /// + /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls. + pub fn new( + handle: RawHandle, + protect: DWORD, + access: DWORD, + offset: u64, + len: usize, + copy: bool, + ) -> io::Result { + let alignment = offset % allocation_granularity() as u64; + let aligned_offset = offset - alignment as u64; + let aligned_len = len + alignment as usize; + if aligned_len == 0 { + // `CreateFileMappingW` documents: + // + // https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw + // > An attempt to map a file with a length of 0 (zero) fails with an error code + // > of ERROR_FILE_INVALID. Applications should test for files with a length of 0 + // > (zero) and reject those files. + // + // For such files, don’t create a mapping at all and use a marker pointer instead. + return Ok(MmapInner { + handle: None, + ptr: empty_slice_ptr(), + len: 0, + copy, + }); + } + + unsafe { + let mapping = CreateFileMappingW(handle, ptr::null_mut(), protect, 0, 0, ptr::null()); + if mapping.is_null() { + return Err(io::Error::last_os_error()); + } + + let ptr = MapViewOfFile( + mapping, + access, + (aligned_offset >> 16 >> 16) as DWORD, + (aligned_offset & 0xffffffff) as DWORD, + aligned_len as SIZE_T, + ); + CloseHandle(mapping); + if ptr.is_null() { + return Err(io::Error::last_os_error()); + } + + let mut new_handle = 0 as RawHandle; + let cur_proc = GetCurrentProcess(); + let ok = DuplicateHandle( + cur_proc, + handle, + cur_proc, + &mut new_handle, + 0, + 0, + DUPLICATE_SAME_ACCESS, + ); + if ok == 0 { + UnmapViewOfFile(ptr); + return Err(io::Error::last_os_error()); + } + + Ok(MmapInner { + handle: Some(new_handle), + ptr: ptr.offset(alignment as isize), + len, + copy, + }) + } + } + + pub fn map( + len: usize, + handle: RawHandle, + offset: u64, + _populate: bool, + _no_reserve: bool, + ) -> io::Result { + let write = protection_supported(handle, PAGE_READWRITE); + let exec = protection_supported(handle, PAGE_EXECUTE_READ); + let mut access = FILE_MAP_READ; + let protection = match (write, exec) { + (true, true) => { + access |= FILE_MAP_WRITE | FILE_MAP_EXECUTE; + PAGE_EXECUTE_READWRITE + } + (true, false) => { + access |= FILE_MAP_WRITE; + PAGE_READWRITE + } + (false, true) => { + access |= FILE_MAP_EXECUTE; + PAGE_EXECUTE_READ + } + (false, false) => PAGE_READONLY, + }; + + let mut inner = MmapInner::new(handle, protection, access, offset, len, false)?; + if write || exec { + inner.make_read_only()?; + } + Ok(inner) + } + + pub fn map_exec( + len: usize, + handle: RawHandle, + offset: u64, + _populate: bool, + _no_reserve: bool, + ) -> io::Result { + let write = protection_supported(handle, PAGE_READWRITE); + let mut access = FILE_MAP_READ | FILE_MAP_EXECUTE; + let protection = if write { + access |= FILE_MAP_WRITE; + PAGE_EXECUTE_READWRITE + } else { + PAGE_EXECUTE_READ + }; + + let mut inner = MmapInner::new(handle, protection, access, offset, len, false)?; + if write { + inner.make_exec()?; + } + Ok(inner) + } + + pub fn map_mut( + len: usize, + handle: RawHandle, + offset: u64, + _populate: bool, + _no_reserve: bool, + ) -> io::Result { + let exec = protection_supported(handle, PAGE_EXECUTE_READ); + let mut access = FILE_MAP_READ | FILE_MAP_WRITE; + let protection = if exec { + access |= FILE_MAP_EXECUTE; + PAGE_EXECUTE_READWRITE + } else { + PAGE_READWRITE + }; + + let mut inner = MmapInner::new(handle, protection, access, offset, len, false)?; + if exec { + inner.make_mut()?; + } + Ok(inner) + } + + pub fn map_copy( + len: usize, + handle: RawHandle, + offset: u64, + _populate: bool, + _no_reserve: bool, + ) -> io::Result { + let exec = protection_supported(handle, PAGE_EXECUTE_READWRITE); + let mut access = FILE_MAP_COPY; + let protection = if exec { + access |= FILE_MAP_EXECUTE; + PAGE_EXECUTE_WRITECOPY + } else { + PAGE_WRITECOPY + }; + + let mut inner = MmapInner::new(handle, protection, access, offset, len, true)?; + if exec { + inner.make_mut()?; + } + Ok(inner) + } + + pub fn map_copy_read_only( + len: usize, + handle: RawHandle, + offset: u64, + _populate: bool, + _no_reserve: bool, + ) -> io::Result { + let write = protection_supported(handle, PAGE_READWRITE); + let exec = protection_supported(handle, PAGE_EXECUTE_READ); + let mut access = FILE_MAP_COPY; + let protection = if exec { + access |= FILE_MAP_EXECUTE; + PAGE_EXECUTE_WRITECOPY + } else { + PAGE_WRITECOPY + }; + + let mut inner = MmapInner::new(handle, protection, access, offset, len, true)?; + if write || exec { + inner.make_read_only()?; + } + Ok(inner) + } + + pub fn map_anon( + len: usize, + _stack: bool, + _populate: bool, + _huge: Option, + _no_reserve: bool, + ) -> io::Result { + // Ensure a non-zero length for the underlying mapping + let mapped_len = len.max(1); + unsafe { + // Create a mapping and view with maximum access permissions, then use `VirtualProtect` + // to set the actual `Protection`. This way, we can set more permissive protection later + // on. + // Also see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537.aspx + + let mapping = CreateFileMappingW( + INVALID_HANDLE_VALUE, + ptr::null_mut(), + PAGE_EXECUTE_READWRITE, + (mapped_len >> 16 >> 16) as DWORD, + (mapped_len & 0xffffffff) as DWORD, + ptr::null(), + ); + if mapping.is_null() { + return Err(io::Error::last_os_error()); + } + let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE; + let ptr = MapViewOfFile(mapping, access, 0, 0, mapped_len as SIZE_T); + CloseHandle(mapping); + + if ptr.is_null() { + return Err(io::Error::last_os_error()); + } + + let mut old = 0; + let result = VirtualProtect(ptr, mapped_len as SIZE_T, PAGE_READWRITE, &mut old); + if result != 0 { + Ok(MmapInner { + handle: None, + ptr, + len, + copy: false, + }) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> { + self.flush_async(offset, len)?; + + if let Some(handle) = self.handle { + let ok = unsafe { FlushFileBuffers(handle) }; + if ok == 0 { + return Err(io::Error::last_os_error()); + } + } + + Ok(()) + } + + pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> { + if self.ptr == empty_slice_ptr() { + return Ok(()); + } + let result = unsafe { FlushViewOfFile(self.ptr.add(offset), len as SIZE_T) }; + if result != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + fn virtual_protect(&mut self, protect: DWORD) -> io::Result<()> { + if self.ptr == empty_slice_ptr() { + return Ok(()); + } + unsafe { + let alignment = self.ptr as usize % allocation_granularity(); + let ptr = self.ptr.offset(-(alignment as isize)); + let aligned_len = self.len as SIZE_T + alignment as SIZE_T; + + let mut old = 0; + let result = VirtualProtect(ptr, aligned_len, protect, &mut old); + + if result != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn make_read_only(&mut self) -> io::Result<()> { + self.virtual_protect(PAGE_READONLY) + } + + pub fn make_exec(&mut self) -> io::Result<()> { + if self.copy { + self.virtual_protect(PAGE_EXECUTE_WRITECOPY) + } else { + self.virtual_protect(PAGE_EXECUTE_READ) + } + } + + pub fn make_mut(&mut self) -> io::Result<()> { + if self.copy { + self.virtual_protect(PAGE_WRITECOPY) + } else { + self.virtual_protect(PAGE_READWRITE) + } + } + + #[inline] + pub fn ptr(&self) -> *const u8 { + self.ptr as *const u8 + } + + #[inline] + pub fn mut_ptr(&mut self) -> *mut u8 { + self.ptr.cast() + } + + #[inline] + pub fn len(&self) -> usize { + self.len + } +} + +impl Drop for MmapInner { + fn drop(&mut self) { + if self.ptr == empty_slice_ptr() { + return; + } + let alignment = self.ptr as usize % allocation_granularity(); + // Any errors during unmapping/closing are ignored as the only way + // to report them would be through panicking which is highly discouraged + // in Drop impls, c.f. https://github.com/rust-lang/lang-team/issues/97 + unsafe { + let ptr = self.ptr.offset(-(alignment as isize)); + UnmapViewOfFile(ptr); + + if let Some(handle) = self.handle { + CloseHandle(handle); + } + } + } +} + +unsafe impl Sync for MmapInner {} +unsafe impl Send for MmapInner {} + +fn protection_supported(handle: RawHandle, protection: DWORD) -> bool { + unsafe { + let mapping = CreateFileMappingW(handle, ptr::null_mut(), protection, 0, 0, ptr::null()); + if mapping.is_null() { + return false; + } + CloseHandle(mapping); + true + } +} + +fn allocation_granularity() -> usize { + unsafe { + let mut info = mem::zeroed(); + GetSystemInfo(&mut info); + info.dwAllocationGranularity as usize + } +} + +pub fn file_len(handle: RawHandle) -> io::Result { + // SAFETY: We must not close the passed-in fd by dropping the File we create, + // we ensure this by immediately wrapping it in a ManuallyDrop. + unsafe { + let file = ManuallyDrop::new(File::from_raw_handle(handle)); + Ok(file.metadata()?.len()) + } +} diff --git a/deps/crates/vendor/regalloc2/.cargo-checksum.json b/deps/crates/vendor/regalloc2/.cargo-checksum.json new file mode 100644 index 00000000000000..c3c97ed3fe5753 --- /dev/null +++ b/deps/crates/vendor/regalloc2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"3b9f786902e8e02da3defe759844e37e9badd3bfe9bae3bd58f2aea3d83b0b00",".github/workflows/rust.yml":"eeb5d84dfb1f0b73d12d8e3727aa8aaba20b5c954cffe57c1142fa472db80e8f","Cargo.lock":"13cd1a4a25b68a6559236916ff1a493cc130003aad4afbf07cf88b7ac93be72c","Cargo.toml":"256ceb2eaed95fb9078481bbef6c51cc2b8dad32d47a262b42217db14cf0be19","Cargo.toml.orig":"6ece897972209d60bdccbee4a3d596a3080f46e5779731e2c5a8ca4d8d651052","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"07c682e768c3ee0c63b7738978da6374a6c44bc70a8cc743990e8944985157e7","deny.toml":"6223c6eed8b14ee4738ca089da143d21ce1e8c8885b49d5a3ce8b83b54466438","doc/FASTALLOC.md":"28b4521461bf814b9e38f1d42e2d697ab32728ed60e53839181e42f63c3ae894","doc/GENERAL.md":"5a9c5e0433d787ae473773b53fa37b7cdfbc3ce28928d35ce741f1276d34f1e3","doc/ION.md":"ddb694f45a0d41cfd52e77fb2036ddafc0240050f9c3dbbf04dd9ecb4cbaf74b","doc/TODO":"1b1b9581ea6137663cfe40125980d9c76c473c9b12d874e3c5ab5d000b26ea37","src/cfg.rs":"9d00b2801da417eff31c46601f9384a2a9bfd6cd76db7bb7af5d26862a69e01c","src/checker.rs":"1904270440954d493a261d51adb80e53758171190a346b4d8306e32eb17408ac","src/domtree.rs":"098c6e0610e7811ae22c81f1cd1f15d62b8b4524d923211f85fd427ce654d1c0","src/fastalloc/iter.rs":"07819007a57db858c3cd22e0b22e6a8f59c9f704861fb28bd335a0f3e6679908","src/fastalloc/lru.rs":"b5f040dd95e6bf5a6c7e1de392a9d9d6502f95dfdcf77b7f87a518e9ab1cc8e8","src/fastalloc/mod.rs":"6900de803fb8741662f8677322747b6deb9c5cddcfa98f24a01a9dcaef9d4152","src/fastalloc/tests.rs":"c4218177d83d564a1646078e1dbce4c1b02ac1cf68b38b63b48556ed429edca1","src/fastalloc/vregset.rs":"956cf43b335d21d0cc753ddbabcf2c419e06d97a85b0d923607631365d7facfd","src/fuzzing/func.rs":"6015b4bcb78e993e7ccb943b6c109843afd68c3e243616accac091a5b08d7720","src/fuzzing/mod.rs":"38f1d8936226f906e824c2a751d43bf54a3438a8d67a24f7734191beea2d9f62","src/index.rs":"299f2b2c82a1f1d40caf85b716b912764b7db0f9f3c99c181797f4a23cdbd54c","src/indexset.rs":"ef6b0aaea1c6e760f0182d800d66144d832d72511068683d9e41309408c768f7","src/ion/data_structures.rs":"a30d60cf2e1be45d1517cd1b118237ce33414762c1b45cb4f3f4f31c3165b004","src/ion/dump.rs":"81563d146296fb9bcb43dbd206809fe0643d799e61a860b3505378fc02a113ca","src/ion/liveranges.rs":"228c52dec27445c97cbc3d1911e97eb1cf2ae0712f8dc79db4b35c93d9cc520a","src/ion/merge.rs":"75af28f4e7327d67fd353e66b391a885f1bf18b1793390322ceb1897368b1b18","src/ion/mod.rs":"7f813fa066cc9d901ab2c8e7bf659eab72a8487b22bea75910873eabb16f9b26","src/ion/moves.rs":"13bffe75671a32c80df56806876a2c2706055629098c448dc36af26c6683dc40","src/ion/process.rs":"d8d023953e25e8a5139f23d43a523f57309b942755e2c31fa05693c6a32df4bc","src/ion/redundant_moves.rs":"6e5ca6d1936083ad11f258373809d77e38cb58854deb3ca187414dbcdd4f00c9","src/ion/reg_traversal.rs":"093a3b78ef8f064d98e4ef15eb1bd38ac09bbf27cb5fae5309c5d6c04766f272","src/ion/requirement.rs":"3b2e06f978adf84d8149e7acb6b6808c0b4e870f7fb282ae9ddbcc9ee1f16570","src/ion/spill.rs":"2cfc3655303f0c88de80e52f12bf9d8b7753970d40193ae406ab83489b218ec3","src/lib.rs":"6eb1cecafdca06b0657be1d0d884cbdcad8ac3e6ad57d202595c549d3348fd46","src/moves.rs":"4e67a51f7bca84f1112d2a13705eddcf29c5f3ea0b3963f354a25aea5ddf491a","src/postorder.rs":"d298ddb7aa6c519c51fc2841bb23185a47241088d5630852601daca811b23d74","src/serialize.rs":"71db4d6146de80562c331fd1f1f138a684dd12425ba8c9620e21f5ce5e56d61b","src/ssa.rs":"74f17029fe0326619b40bbeb94698f0bb284d20ec4fc9edf9f95fb00c6c6a33c"},"package":"dc06e6b318142614e4a48bc725abbf08ff166694835c43c9dae5a9009704639a"} \ No newline at end of file diff --git a/deps/crates/vendor/regalloc2/.cargo_vcs_info.json b/deps/crates/vendor/regalloc2/.cargo_vcs_info.json new file mode 100644 index 00000000000000..6fff380b551caa --- /dev/null +++ b/deps/crates/vendor/regalloc2/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "3b6f83a01492d6dd16eaf46522d54dd510e11f15" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/regalloc2/.github/workflows/rust.yml b/deps/crates/vendor/regalloc2/.github/workflows/rust.yml new file mode 100644 index 00000000000000..9bcdcb42a5970f --- /dev/null +++ b/deps/crates/vendor/regalloc2/.github/workflows/rust.yml @@ -0,0 +1,82 @@ +# Derived from regalloc.rs' GitHub CI config file. + +name: Rust + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + # Lint code with rustfmt, report an error if it needs to be run. + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install rustfmt + run: rustup component add rustfmt + - name: Run rustfmt and check there's no difference + run: cargo fmt --all -- --check + + # Make sure the code compiles and that all the tests pass. + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build + - name: Run tests + run: cargo test --all --verbose + + # Make sure the code typechecks with non-default features enabled. + features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check with all features + run: cargo check --all-features + + # Make sure the code and its dependencies compile without std. + no_std: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install thumbv6m-none-eabi target + run: rustup target add thumbv6m-none-eabi + - name: Check no_std build + run: cargo check --target thumbv6m-none-eabi --no-default-features --features trace-log,checker,enable-serde + + # Lint dependency graph for security advisories, duplicate versions, and + # incompatible licences. + cargo_deny: + name: Cargo deny + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - run: | + set -e + curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.22/cargo-deny-0.14.22-x86_64-unknown-linux-musl.tar.gz | tar xzf - + mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny + echo `pwd` >> $GITHUB_PATH + - run: cargo deny check + + # Builds the fuzz targets. + fuzz: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install nightly + run: rustup toolchain install nightly + - name: Install cargo-fuzz + run: cargo +nightly install cargo-fuzz + - name: Build ssagen fuzzing target + run: cargo +nightly fuzz build ssagen + - name: Build moves fuzzing target + run: cargo +nightly fuzz build moves + - name: Build ion fuzzing target + run: cargo +nightly fuzz build ion + - name: Build and smoke-test ion_checker fuzzing target + run: cargo +nightly fuzz run ion_checker ./fuzz/smoketest/ion_checker.bin diff --git a/deps/crates/vendor/regalloc2/Cargo.lock b/deps/crates/vendor/regalloc2/Cargo.lock new file mode 100644 index 00000000000000..932b3d182065e6 --- /dev/null +++ b/deps/crates/vendor/regalloc2/Cargo.lock @@ -0,0 +1,149 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "arbitrary" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regalloc2" +version = "0.11.2" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown", + "libfuzzer-sys", + "log", + "rustc-hash", + "serde", + "smallvec", +] + +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" diff --git a/deps/crates/vendor/regalloc2/Cargo.toml b/deps/crates/vendor/regalloc2/Cargo.toml new file mode 100644 index 00000000000000..45b76da0182597 --- /dev/null +++ b/deps/crates/vendor/regalloc2/Cargo.toml @@ -0,0 +1,89 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "regalloc2" +version = "0.11.2" +authors = [ + "Chris Fallin ", + "Mozilla SpiderMonkey Developers", +] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Backtracking register allocator inspired from IonMonkey" +readme = "README.md" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/regalloc2" + +[features] +checker = [] +default = ["std"] +enable-serde = ["serde"] +fuzzing = [ + "libfuzzer-sys", + "checker", + "trace-log", +] +std = [] +trace-log = [] + +[lib] +name = "regalloc2" +path = "src/lib.rs" + +[dependencies.allocator-api2] +version = "0.2.18" +features = ["alloc"] +default-features = false + +[dependencies.bumpalo] +version = "3.16.0" +features = ["allocator-api2"] + +[dependencies.hashbrown] +version = "0.15" +features = [] +default-features = false + +[dependencies.libfuzzer-sys] +version = "0.4.2" +optional = true + +[dependencies.log] +version = "0.4.8" +default-features = false + +[dependencies.rustc-hash] +version = "2.0.0" +default-features = false + +[dependencies.serde] +version = "1.0.136" +features = [ + "derive", + "alloc", +] +optional = true +default-features = false + +[dependencies.smallvec] +version = "1.6.1" +features = ["union"] + +[profile.release] +debug = 2 +debug-assertions = true +overflow-checks = true diff --git a/deps/crates/vendor/regalloc2/Cargo.toml.orig b/deps/crates/vendor/regalloc2/Cargo.toml.orig new file mode 100644 index 00000000000000..bfd11d5aa241d0 --- /dev/null +++ b/deps/crates/vendor/regalloc2/Cargo.toml.orig @@ -0,0 +1,55 @@ +[workspace] +members = ["regalloc2-tool"] + +[package] +name = "regalloc2" +version = "0.11.2" +authors = [ + "Chris Fallin ", + "Mozilla SpiderMonkey Developers", +] +edition = "2018" +license = "Apache-2.0 WITH LLVM-exception" +description = "Backtracking register allocator inspired from IonMonkey" +repository = "https://github.com/bytecodealliance/regalloc2" + +[dependencies] +log = { version = "0.4.8", default-features = false } +smallvec = { version = "1.6.1", features = ["union"] } +rustc-hash = { version = "2.0.0", default-features = false } +hashbrown = { version = "0.15", default-features = false, features = [] } + +# Optional serde support, enabled by feature below. +serde = { version = "1.0.136", features = [ + "derive", + "alloc", +], default-features = false, optional = true } + +# The below are only needed for fuzzing. +libfuzzer-sys = { version = "0.4.2", optional = true } +bumpalo = { version = "3.16.0", features = ["allocator-api2"] } +allocator-api2 = { version = "0.2.18", default-features = false, features = ["alloc"] } + +# When testing regalloc2 by itself, enable debug assertions and overflow checks +[profile.release] +debug = true +debug-assertions = true +overflow-checks = true + +[features] +default = ["std"] + +# Enables std-specific features such as the Error trait for RegAllocError. +std = [] + +# Enables generation of DefAlloc edits for the checker. +checker = [] + +# Enables detailed logging which can be somewhat expensive. +trace-log = [] + +# Exposes the internal API for fuzzing. +fuzzing = ["libfuzzer-sys", "checker", "trace-log"] + +# Enables serde for exposed types. +enable-serde = ["serde"] diff --git a/deps/crates/vendor/regalloc2/LICENSE b/deps/crates/vendor/regalloc2/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/regalloc2/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/regalloc2/README.md b/deps/crates/vendor/regalloc2/README.md new file mode 100644 index 00000000000000..bf8e3beb276445 --- /dev/null +++ b/deps/crates/vendor/regalloc2/README.md @@ -0,0 +1,22 @@ +## regalloc2: another register allocator + +This is a register allocator that started life as, and is about 50% +still, a port of IonMonkey's backtracking register allocator to +Rust. In many regards, it has been generalized, optimized, and +improved since the initial port. + +In addition, it contains substantial amounts of testing infrastructure +(fuzzing harnesses and checkers) that does not exist in the original +IonMonkey allocator. + +See the [design overview](doc/GENERAL.md) for (much!) more detail on +how the allocator works. + +## License + +This crate is licensed under the Apache 2.0 License with LLVM +Exception. This license text can be found in the file `LICENSE`. + +Parts of the code are derived from regalloc.rs: in particular, +`src/checker.rs` and `src/domtree.rs`. This crate has the same license +as regalloc.rs, so the license on these files does not differ. diff --git a/deps/crates/vendor/regalloc2/deny.toml b/deps/crates/vendor/regalloc2/deny.toml new file mode 100644 index 00000000000000..8522b2c1cf1d2e --- /dev/null +++ b/deps/crates/vendor/regalloc2/deny.toml @@ -0,0 +1,28 @@ +[graph] +targets = [ + { triple = "x86_64-unknown-linux-gnu" }, + { triple = "x86_64-apple-darwin" }, + { triple = "x86_64-pc-windows-msvc" }, + { triple = "aarch64-linux-android" }, +] + +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +yanked = "deny" +ignore = [] + +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +allow = [ + "Apache-2.0 WITH LLVM-exception", + "Apache-2.0", + "MIT", + "Unicode-DFS-2016", + "Unicode-3.0", +] + +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +multiple-versions = "deny" +wildcards = "allow" +deny = [] diff --git a/deps/crates/vendor/regalloc2/doc/FASTALLOC.md b/deps/crates/vendor/regalloc2/doc/FASTALLOC.md new file mode 100644 index 00000000000000..79dac025e78949 --- /dev/null +++ b/deps/crates/vendor/regalloc2/doc/FASTALLOC.md @@ -0,0 +1,321 @@ +# Fastalloc Design Overview + +Fastalloc is a register allocator made specifically for fast +compile times. It's based on the reverse linear scan register +allocation/SSRA algorithm. +This document describes the data structures used and the allocation steps. + +# Data Structures + +The main data structures that Fastalloc uses to track its state are +described below. + +## Current VReg Allocations (`vreg_allocs`) + +This is a vector that is used to hold the current allocation for every +VReg during execution. + +## VReg Spillslots (`vreg_spillslots`) + +Whenever a VReg needs a spillslot, a dedicated slot is allocated for it. +This vector is where all VReg's spillslots are stored. + +## Live VRegs (`live_vregs`) + +Live VReg information is kept in a `VRegSet`, a doubly linked list +based on a vector. This is used for quick insertion, removal, and +iteration. + +## Least Recently Used Caches (`lrus`) + +Every register class (int, float, and vector) has its own LRU and they +are stored together in an array: `lrus`. An LRU is represented similarly +to a `VRegSet`: it's a circular, doubly-linked list based on a vector. + +The last PReg in an LRU is the least recently allocated PReg: + +most recently used PReg (head) -> 2nd MRU PReg -> ... -> LRU PReg + +## Current VReg In PReg Info (`vreg_in_preg`) + +During allocation, it's necessary to determine which VReg is in a PReg +to generate the right move(s) for eviction. +`vreg_in_preg` is a vector that stores this information. + +## Available PRegs For Use In Instruction (`available_pregs`) + +This is a 2-tuple of `PRegSet`s, a bitset of physical registers, one for +the instruction's early phase and one for the late phase. +They are used to determine which registers are available for use in the +early/late phases of an instruction. + +Prior to the beginning of any instruction's allocation, this set is reset +to include all allocatable physical registers, some of which may already +contain a VReg. + +## VReg Liverange Location Info (`vreg_to_live_inst_range`) + +This is a vector of 3-tuples containing the beginning and the end +of all VReg's liveranges, along with an allocation they are guaranteed +to be in throughout that liverange. +This is used to build the debug locations vector after allocation +is complete. + +# Allocation Process Breakdown + +Allocation proceeds in reverse: from the last block to the first block, +and in each block: from the last instruction to the first instruction. + +The allocation for each operand in an instruction can be viewed to happen +in four phases: selection, assignment, eviction, and edit insertion. + +## Allocation Phase: Selection + +In this phase, a PReg is selected from `available_pregs` for the +operand based on the operand constraints. Depending on the operand's +position the selected PReg is removed from either the early or late +phase or both, indicating that the PReg is no longer available for +allocation by other operands in that phase. + +## Allocation Phase: Assignment + +In this phase, the selected PReg is set as the allocation for +the operand in the final output. + +## Allocation Phase: Eviction + +In this phase, the previous VReg in the allocation assigned to +an operand is evicted, if any. + +During eviction, a dedicated spillslot is allocated for the evicted +VReg and an edit is inserted after the instruction to move from the +slot to the allocation it's expected to be in after the instruction. + +## Allocation Phase: Edit Insertion + +In this phase, edits are inserted to ensure that the dataflow from +before the instruction to the selected allocation to after +the instruction remain correct. + +# Invariants + +Some invariants that remain true throughout execution: + +1. During processing, the allocation of a VReg at any point in time +as indicated in `vreg_allocs` changes exactly twice or thrice. +Initially, it is set to none. When it's allocated, it is +changed to that allocation. After this, it doesn't change unless +it's evicted or spilled across a block boundary; +if it is, then its current allocation will change to its dedicated +spillslot. After this, it doesn't change again until its definition +is reached and it's deallocated, during which its `vreg_allocs` +entry is set to none. The only exception is block parameters that +are never used: these are never allocated. + +2. A virtual register that outlives the block it was defined in will +be in its dedicated spillslot by the end of the block. + +3. At the end of a block, before edits are inserted to move values +from branch arguments to block parameters spillslots, all branch +arguments will be in their dedicated spillslots. + +4. At the beginning of a block, all branch parameters and livein +virtual registers will be in their dedicated spillslots. + +# Instruction Allocation + +To allocate a single instruction, the first step is to reset the +`available_pregs` sets to all allocatable PRegs. + +Next, the selection phase is carried out for all operands with +fixed register constraints: the registers they are constrained to use are +marked as unavailable in the `available_pregs` set, depending on the +phase that they are valid in. If the operand is an early use or late +def operand, then the register will be marked as unavailable in the +early set or late set, respectively. Otherwise, the PReg is marked +as unavailable in both the early and late sets, because a PReg +assigned to an early def or late use operand cannot be reused by another +operand in the same instruction. + +After selection for fixed register operands, the eviction phase is +carried out for fixed register operands. Any VReg in their selected +registers, indicated by `vreg_in_preg`, is evicted: a dedicated +spillslot is allocated for the VReg (if it doesn't have one already), +an edit is inserted to move from the slot to the PReg, which is where +the VReg expected to be after the instruction, and its current +allocation in `vreg_allocs` is set to the spillslot. + +Next, all clobbers are removed from the early and late `available_pregs` +sets to avoid allocating a clobber to a def. + +Next, the selection, assignment, eviction, and edit insertion phases are +carried out for all def operands. When each def operand's allocation is +complete, the def operands is immediately freed, marking the end of the +VReg's liverange. It is removed from the `live_vregs` set, its allocation +in `vreg_allocs` is set to none, and if it was in a PReg, that PReg's +entry in `vreg_in_preg` is set to none. The selection and eviction phases +are omitted if the operand has a fixed constraint, as those phases have +already been carried out. + +Next, the selection, assignment, and eviction phases are carried out for all +use operands. As with def operands, the selection and eviction phases are +omitted if the operand has a fixed constraint, as those phases have already +been carried out. + +Then the edit insertion phase is carried out for all use operands. + +Lastly, if the instruction being processed is a branch instruction, the +parallel move resolver is used to insert edits before the instruction +to move from the branch arguments spillslots to the block parameter +spillslots. + +## Operand Allocation + +During the allocation of an operand, a check is first made to +see if the VReg's current allocation as indicated in +`vreg_allocs` is within the operand constraints. + +If it is, the assignment phase is carried out, setting the final +allocation output's entry for that operand to the allocation. +The selection phase is carried out, marking the PReg +(if the allocation is a PReg) as unavailable in the respective +early/late sets. The state of the LRUs is also updated to reflect +the new most recently used PReg. +No eviction needs to be done since the VReg is already in the +allocation and no edit insertion needs to be done either. + +On the other hand, if the VReg's current allocation is not within +constraints, the selection and eviction phases are carried out for +non-fixed operands. First, a set of PRegs that can be drawn from is +created from `available_pregs`. For early uses and late defs, +this draw-from set is the early set or late set, respectively. +For late uses and early defs, the draw-from set is an intersection +of the available early and late sets (because a PReg used for a late +use can't be reassigned to another operand in the early phase; +likewise, a PReg used for an early def can't be reassigned to another +operand in the late phase). +The LRU for the VReg's regclass is then traversed from the end to find +the least recently used PReg in the draw-from set. Once a PReg is found, +it is marked as the most recently used in the LRU, unavailable in the +`available_pregs` sets, and whatever VReg was in it before is evicted. + +The assignment phase is carried out next. The final allocation for the +operand is set to the selected register. + +If the newly allocated operand has not been allocated before, that is, +this is the first use/def of the VReg encountered; the VReg is +inserted into `live_vregs` and marked as the value in the allocated +PReg in `vreg_in_preg`. + +Otherwise, if the VReg has been allocated before, then an edit will need +to be inserted to ensure that the dataflow remains correct. +The edit insertion phase is now carried out if the operand is a def +operand: an edit is inserted after the instruction to move from the +new allocation to the allocation it's expected to be in after the +instruction. + +The edit insertion phase for use operands is done after all operands +have been processed. Edits are inserted to move from the current +allocations in `vreg_allocs` to the final allocated position before +the instruction. This is to account for the possibility of multiple +uses of the same operand in the instruction. + +## Reuse Operands + +Reuse def operands are handled by creating a new operand identical to the +reuse def, except that its constraints are the constraints of the +reused input and allocating that in its place. + +Reused inputs are handled by creating a new operand with a fixed register +constraint to use whatever register was assigned to the reuse def. + +Because of the way reuse operands and reused inputs are handled, when +selecting a register for an early-use operand with a fixed constraint, +the PReg is also marked as unavailable in the `available_pregs` late +set if the operand is a reused input. And when selecting a register +for reuse def operands, the selected register is marked as unavailable +in the `available_pregs` early set. + +## VReg Spillslots + +Whenever a VReg needs a spillslot, a suitable one is allocated and +marked as the VReg's dedicated spillslot in `vreg_spillslots`. +If a VReg never needs a spillslot, none is allocated for it. +To ensure that a VReg will always be in its spillslot when expected, +during the processing of a def operand, before it's deallocated, +an edit is inserted to move from its current allocation as indicated +in `vreg_allocs` to its dedicated spillslot, if one is present in +`vreg_spillslots`. + +## Branch Instructions + +As an invariant, all branch arguments will be in their dedicated +spillslots at the end of the block before edits are inserted to +move from those spillslots to the block parameter spillslots +of the successor blocks. + +If a branch argument is already in an allocation that isn't +its spillslot (this could happen if the branch argument is used +as an operand in the same instruction, because all normal +instruction processing is completed before branch-specific +processing), then an edit is inserted +to move from the spillslot to that allocation and its current +allocation in `vreg_allocs` is set to the spillslot. + +It's after these edits have been inserted that the parallel move +resolver is then used to generate and insert edits to move from +those spillslots to the spillslots of the block parameters. + +# Across Blocks + +When a block completes processing, some VRegs will still be live. +These VRegs are either block parameters or livein VRegs. +As an invariant, prior to the first instruction in a block, all +block parameters and livein VRegs will be in their dedicated spillslots. + +To maintain this invariant, after a block completes processing, edits +are inserted at the beginning of the block to move from the block +parameter and livein spillslots to the allocation they are expected +to be in from the first instruction. +All block parameters are freed, just like defs, and liveins' current +allocations in `vreg_allocs` are set to their spillslots. + +# Edits Order + +`regalloc2`'s outward interface guarantees that edits are in +sorted order. Since allocation proceeds in reverse, all edits +are also added in reverse. After all blocks have completed +processing the edits are simply reversed to put it in the +correct order. + +One of the reasons why the allocation order proceeds the way it +does is because of this edit-order constraint. All edits that +occur after the instruction must be inserted before all edits +that occur before the instruction. + +# Debug Info + +After all blocks have completed processing, the debug locations +vector is built. +The information it's built from is assembled from liverange info +that is tracked throughout the allocation. +Whenever a VReg is allocated for the first time, its liverange end +is saved in the VReg's slot in the `vreg_to_live_inst_range` +vector. Whenever a VReg's definition is encountered, its liverange +beginning is saved, too. And the allocation it will be in +throughout that range is also saved alongside. + +To determine the allocation the VReg will be in throughout the +liverange, the first invariant is used: the first time a VReg +is allocated, its current allocation in `vreg_allocs` doesn't +change unless its evicted or spilled across block boundaries. +Using this info, if by the time the def of a VReg is allocated, +that VReg has no dedicated spillslot, +that implies that the VReg was never evicted or spilled, so whatever +value its `vreg_allocs` entry says is the location it will be in +throughout its liverange. Otherwise, if it has a spillslot +allocated to it, that implies that the VReg was either evicted +at some point or it was a livein of a predecessor or a block parameter. +Either way, since all spillslots are dedicated to their respective VRegs, +it is safe to record the spillslot as the allocation for the +`vreg_to_live_inst_range` info. diff --git a/deps/crates/vendor/regalloc2/doc/GENERAL.md b/deps/crates/vendor/regalloc2/doc/GENERAL.md new file mode 100644 index 00000000000000..f5d70ff2d33628 --- /dev/null +++ b/deps/crates/vendor/regalloc2/doc/GENERAL.md @@ -0,0 +1,212 @@ +# regalloc2 Design Overview + +This document describes the basic architecture of the regalloc2 +register allocator. It describes the externally-visible interface: +input CFG, instructions, operands, with their invariants; meaning of +various parts of the output. +`ION.md` and `FASTALLOC.md` describe the specifics of the main Ion +allocator and the fast allocator, respectively. + +# API, Input IR and Invariants + +The toplevel API to regalloc2 consists of a single entry point `run()` +that takes a register environment, which specifies all physical +registers, and the input program. The function returns either an error +or an `Output` struct that provides allocations for each operand and a +vector of additional instructions (moves, loads, stores) to insert. + +## Register Environment + +The allocator takes a `MachineEnv` which specifies, for each of the +two register classes `Int` and `Float`, a vector of `PReg`s by index. A +`PReg` is nothing more than the class and index within the class; the +allocator does not need to know anything more. + +The `MachineEnv` provides a vector of preferred and non-preferred +physical registers per class. Any register not in either vector will +not be allocated. Usually, registers that do not need to be saved in +the prologue if used (i.e., caller-save registers) are given in the +"preferred" vector. The environment also provides exactly one scratch +register per class. This register must not be in the preferred or +non-preferred vectors, and is used whenever a set of moves that need +to occur logically in parallel have a cycle (for a simple example, +consider a swap `r0, r1 := r1, r0`). + +With some more work, we could potentially remove the need for the +scratch register by requiring support for an additional edit type from +the client ("swap"), but we have not pursued this. + +## CFG and Instructions + +The allocator operates on an input program that is in a standard CFG +representation: the function body is a sequence of basic blocks, and +each block has a sequence of instructions and zero or more +successors. The allocator also requires the client to provide +predecessors for each block, and these must be consistent with the +successors. + +Instructions are opaque to the allocator except for a few important +bits: (1) `is_ret` (is a return instruction); (2) `is_branch` (is a +branch instruction); and (3) a vector of Operands, covered below. +Every block must end in a return or branch. + +Both instructions and blocks are named by indices in contiguous index +spaces. A block's instructions must be a contiguous range of +instruction indices, and block i's first instruction must come +immediately after block i-1's last instruction. + +The CFG must have *no critical edges*. A critical edge is an edge from +block A to block B such that A has more than one successor *and* B has +more than one predecessor. For this definition, the entry block has an +implicit predecessor, and any block that ends in a return has an +implicit successor. + +Note that there are *no* requirements related to the ordering of +blocks, and there is no requirement that the control flow be +reducible. Some *heuristics* used by the allocator will perform better +if the code is reducible and ordered in reverse postorder (RPO), +however: in particular, (1) this interacts better with the +contiguous-range-of-instruction-indices live range representation that +we use, and (2) the "approximate loop depth" metric will actually be +exact if both these conditions are met. + +## Operands and VRegs + +Every instruction operates on values by way of `Operand`s. An operand +consists of the following fields: + +- VReg, or virtual register. *Every* operand mentions a virtual + register, even if it is constrained to a single physical register in + practice. This is because we track liveranges uniformly by vreg. + +- Policy, or "constraint". Every reference to a vreg can apply some + constraint to the vreg at that point in the program. Valid policies are: + + - Any location; + - Any register of the vreg's class; + - Any stack slot; + - A particular fixed physical register; or + - For a def (output), a *reuse* of an input register. + +- The "kind" of reference to this vreg: Def, Use, Mod. A def + (definition) writes to the vreg, and disregards any possible earlier + value. A mod (modify) reads the current value then writes a new + one. A use simply reads the vreg's value. + +- The position: before or after the instruction. + - Note that to have a def (output) register available in a way that + does not conflict with inputs, the def should be placed at the + "before" position. Similarly, to have a use (input) register + available in a way that does not conflict with outputs, the use + should be placed at the "after" position. + +VRegs, or virtual registers, are specified by an index and a register +class (Float or Int). The classes are not given separately; they are +encoded on every mention of the vreg. (In a sense, the class is an +extra index bit, or part of the register name.) The input function +trait does require the client to provide the exact vreg count, +however. + +Implementation note: both vregs and operands are bit-packed into +u32s. This is essential for memory-efficiency. As a result of the +operand bit-packing in particular (including the policy constraints!), +the allocator supports up to 2^21 (2M) vregs per function, and 2^6 +(64) physical registers per class. Later we will also see a limit of +2^20 (1M) instructions per function. These limits are considered +sufficient for the anticipated use-cases (e.g., compiling Wasm, which +also has function-size implementation limits); for larger functions, +it is likely better to use a simpler register allocator in any case. + +## Reuses and Two-Address ISAs + +Some instruction sets primarily have instructions that name only two +registers for a binary operator, rather than three: both registers are +inputs, and the result is placed in one of the registers, clobbering +its original value. The most well-known modern example is x86. It is +thus imperative that we support this pattern well in the register +allocator. + +This instruction-set design is somewhat at odds with an SSA +representation, where a value cannot be redefined. + +Thus, the allocator supports a useful fiction of sorts: the +instruction can be described as if it has three register mentions -- +two inputs and a separate output -- and neither input will be +clobbered. The output, however, is special: its register-placement +policy is "reuse input i" (where i == 0 or 1). The allocator +guarantees that the register assignment for that input and the output +will be the same, so the instruction can use that register as its +"modifies" operand. If the input is needed again later, the allocator +will take care of the necessary copying. + +We will see below how the allocator makes this work by doing some +preprocessing so that the core allocation algorithms do not need to +worry about this constraint. + +## SSA + +regalloc2 takes an SSA IR as input, where the usual definitions apply: +every vreg is defined exactly once, and every vreg use is dominated by +its one def. (Using blockparams means that we do not need additional +conditions for phi-nodes.) + +## Block Parameters + +Every block can have *block parameters*, and a branch to a block with +block parameters must provide values for those parameters via +operands. When a branch has more than one successor, it provides +separate operands for each possible successor. These block parameters +are equivalent to phi-nodes; we chose this representation because they +are in many ways a more consistent representation of SSA. + +To see why we believe block parameters are a slightly nicer design +choice than use of phi nodes, consider: phis are special +pseudoinstructions that must come first in a block, are all defined in +parallel, and whose uses occur on the edge of a particular +predecessor. All of these facts complicate any analysis that scans +instructions and reasons about uses and defs. It is much closer to the +truth to actually put those uses *in* the predecessor, on the branch, +and put all the defs at the top of the block as a separate kind of +def. The tradeoff is that a vreg's def now has two possibilities -- +ordinary instruction def or blockparam def -- but this is fairly +reasonable to handle. + +## Output + +The allocator produces two main data structures as output: an array of +`Allocation`s and a sequence of edits. Some other miscellaneous data is also +provided. + +### Allocations + +The allocator provides an array of `Allocation` values, one per +`Operand`. Each `Allocation` has a kind and an index. The kind may +indicate that this is a physical register or a stack slot, and the +index gives the respective register or slot. All allocations will +conform to the constraints given, and will faithfully preserve the +dataflow of the input program. + +### Inserted Moves + +In order to implement the necessary movement of data between +allocations, the allocator needs to insert moves at various program +points. + +The vector of inserted moves contains tuples that name a program point +and an "edit". The edit is either a move, from one `Allocation` to +another, or else a kind of metadata used by the checker to know which +VReg is live in a given allocation at any particular time. The latter +sort of edit can be ignored by a backend that is just interested in +generating machine code. + +Note that the allocator will never generate a move from one stackslot +directly to another, by design. Instead, if it needs to do so, it will +make use of the scratch register. (Sometimes such a move occurs when +the scratch register is already holding a value, e.g. to resolve a +cycle of moves; in this case, it will allocate another spillslot and +spill the original scratch value around the move.) + +Thus, the single "edit" type can become either a register-to-register +move, a load from a stackslot into a register, or a store from a +register into a stackslot. + diff --git a/deps/crates/vendor/regalloc2/doc/ION.md b/deps/crates/vendor/regalloc2/doc/ION.md new file mode 100644 index 00000000000000..aea2be2380ce44 --- /dev/null +++ b/deps/crates/vendor/regalloc2/doc/ION.md @@ -0,0 +1,1205 @@ +# Ion Design Overview + +This document describes the basic architecture of the Ion +register allocator. It describes the core data structures; and the allocation +pipeline, or series of algorithms that compute an allocation. It ends +with a description of future work and expectations, as well as an +appendix that notes design influences and similarities to the +IonMonkey backtracking allocator. + +# Data Structures + +We now review the data structures that regalloc2 uses to track its +state. + +## Program-Derived Alloc-Invariant Data + +There are a number of data structures that are computed in a +deterministic way from the input program and then subsequently used +only as read-only data during the core allocation procedure. + +### Livein/Liveout Bitsets + +The livein and liveout bitsets (`liveins` and `liveouts` on the `Env`) +are allocated one per basic block and record, per block, which vregs +are live entering and leaving that block. They are computed using a +standard backward iterative dataflow analysis and are exact; they do +not over-approximate (this turns out to be important for performance). + +### Blockparam Vectors: Source-Side and Dest-Side + +The initialization stage scans the input program and produces two +vectors that represent blockparam flows from branches to destination +blocks: `blockparam_ins` and `blockparam_outs`. + +These two vectors are the first instance we will see of a recurring +pattern: the vectors contain tuples that are carefully ordered in a +way such that their sort-order is meaningful. "Build a vector lazily +then sort" is a common idiom: it batches the O(n log n) cost into one +operation that the stdlib has aggressively optimized, it provides +dense storage, and it allows for a scan in a certain order that often +lines up with a scan over the program. + +In this particular case, we will build vectors of (vreg, block) points +that are meaningful either at the start or end of a block, so that +later, when we scan over a particular vreg's allocations in block +order, we can generate another vector of allocations. One side (the +"outs") also contains enough information that it can line up with the +other side (the "ins") in a later sort. + +To make this work, `blockparam_ins` contains a vector of (to-vreg, +to-block, from-block) tuples, and has an entry for every blockparam of +every block. Note that we can compute this without actually observing +from-blocks; we only need to iterate over `block_preds` at any given +block. + +Then, `blockparam_outs` contains a vector of (from-vreg, from-block, +to-block, to-vreg), and has an entry for every parameter on every +branch that ends a block. There is exactly one "out" tuple for every +"in" tuple. As mentioned above, we will later scan over both to +generate moves. + +## Core Allocation State: Ranges, Uses, Bundles, VRegs, PRegs + +We now come to the core data structures: live-ranges, bundles, virtual +registers and their state, and physical registers and their state. + +First we must define a `ProgPoint` precisely: a `ProgPoint` is an +instruction index and a `Before` or `After` suffix. We pack the +before/after suffix into the LSB of a `u32`, so a `ProgPoint` can be +incremented and compared as a simple integer. + +A live-range is a contiguous range of program points (half-open, +i.e. including `from` and excluding `to`) for which a particular vreg +is live with a value. + +A live-range contains a vector of uses. Each use contains four parts: +the Operand word (directly copied, so there is no need to dereference +it); the ProgPoint at which the use occurs; the operand slot on that +instruction, if any, that the operand comes from, and the use's +'weight". (It's possible to have "ghost uses" that do not derive from +any slot on the instruction.) These four parts are packed into three +`u32`s: the slot can fit in 8 bits, and the weight in 16. + +The live-range carries its program-point range, uses, vreg index, +bundle index (see below), and some metadata: spill weight and +flags. The spill weight is the sum of weights of each use. The flags +set currently carries one flag only: whether the live-range starts at +a Def-kind operand. (This is equivalent to whether the range consumes +a value at its start or not.) + +Uses are owned only by live-ranges and have no separate identity, but +live-ranges live in a toplevel array and are known by `LiveRangeIndex` +values throughout the allocator. New live-ranges can be created +(e.g. during splitting); old ones are not cleaned up, but rather, all +state is bulk-freed at the end. + +Live-ranges are aggregated into "bundles". A bundle is a collection of +ranges that does not overlap. Each bundle carries: a vector (inline +SmallVec) of (range, live-range index) tuples, an allocation (starts +as "none"), a "spillset" (more below), and some metadata, including a +spill weight (sum of ranges' weights), a priority (sum of ranges' +lengths), and three property flags: "minimal", "contains fixed +constraints", "contains stack constraints". + +VRegs also contain their vectors of live-ranges, in the same form as a +bundle does (inline SmallVec that has inline (from, to) range bounds +and range indices). + +There are two important overlap invariants: (i) no liveranges within a +bundle overlap, and (ii) no liveranges within a vreg overlap. These +are extremely important and we rely on them implicitly in many places. + +The live-range vectors in bundles and vregs, and use-vectors in ranges, +have various sorting invariants as well. These invariants differ +according to the phase of the allocator's computation. First, during +live-range construction, live-ranges are placed into vregs in reverse +order (because the computation is a reverse scan) and uses into ranges +in reverse order; these are sorted into forward order at the end of +live-range computation. When bundles are first constructed, their +range vectors are sorted, and they remain so for the rest of allocation, +as we need for interference testing. However, as ranges are created +and split, sortedness of vreg ranges is *not* maintained; they are +sorted once more, in bulk, when allocation is done and we start to +resolve moves. + +Finally, we have physical registers. The main data associated with +each is the allocation map. This map is a standard BTree, indexed by +ranges (`from` and `to` ProgPoints) and yielding a LiveRange for each +location range. The ranges have a custom comparison operator defined +that compares equal for any overlap. + +This comparison operator allows us to determine whether a range is +free, i.e. has no overlap with a particular range, in one probe -- the +btree will not contain a match. However, it makes iteration over *all* +overlapping ranges somewhat tricky to get right. Notably, Rust's +BTreeMap does not guarantee that the lookup result will be the *first* +equal key, if multiple keys are equal to the probe key. Thus, when we +want to enumerate all overlapping ranges, we probe with a range that +consists of the single program point *before* the start of the actual +query range, using the API that returns an iterator over a range in +the BTree, and then iterate through the resulting iterator to gather +all overlapping ranges (which will be contiguous). + +## Spill Bundles + +It is worth describing "spill bundles" separately. Every spillset (see +below; a group of bundles that originated from one bundle) optionally +points to a single bundle that we designate the "spill bundle" for +that spillset. Contrary to the name, this bundle is not +unconditionally spilled. Rather, one can see it as a sort of fallback: +it is where liveranges go when we give up on processing them via the +normal backtracking loop, and will only process them once more in the +"second-chance" stage. + +This fallback behavior implies that the spill bundle must always be +able to accept a spillslot allocation, i.e., it cannot require a +register. This invariant is what allows spill bundles to be processed +in a different way, after backtracking has completed. + +The spill bundle acquires liveranges in two ways. First, as we split +bundles, we will trim the split pieces in certain ways so that some +liveranges are immediately placed in the spill bundle. Intuitively, +the "empty" regions that just carry a value, but do not satisfy any +operands, should be in the spill bundle: it is better to have a single +consistent location for the value than to move it between lots of +different split pieces without using it, as moves carry a cost. + +Second, the spill bundle acquires the liveranges of a bundle that has +no requirement to be in a register when that bundle is processed, but +only if the spill bundle already exists. In other words, we won't +create a second-chance spill bundle just for a liverange with an "Any" +use; but if it was already forced into existence by splitting and +trimming, then we might as well use it. + +Note that unlike other bundles, a spill bundle's liverange vector +remains unsorted until we do the second-chance allocation. This allows +quick appends of more liveranges. + +## Allocation Queue + +The allocation queue is simply a priority queue (built with a binary +max-heap) of (prio, bundle-index) tuples. + +## Spillsets and Spillslots + +Every bundle contains a reference to a spillset. Spillsets are used to +assign spillslots near the end of allocation, but before then, they +are also a convenient place to store information that is common among +*all bundles* that share the spillset. In particular, spillsets are +initially assigned 1-to-1 to bundles after all bundle-merging is +complete; so spillsets represent in some sense the "original bundles", +and as splitting commences, the smaller bundle-pieces continue to +refer to their original spillsets. + +We stash some useful information on the spillset because of this: a +register hint, used to create some "stickiness" between pieces of an +original bundle that are assigned separately after splitting; the +spill bundle; the common register class of all vregs in this bundle; +the vregs whose liveranges are contained in this bundle; and then some +information actually used if this is spilled to the stack (`required` +indicates actual stack use; `size` is the spillslot count; `slot` is +the actual stack slot). + +Spill *sets* are later allocated to spill *slots*. Multiple spillsets +can be assigned to one spillslot; the only constraint is that +spillsets assigned to a spillslot must not overlap. When we look up +the allocation for a bundle, if the bundle is not given a specific +allocation (its `alloc` field is `Allocation::none()`), this means it +is spilled, and we traverse to the spillset then spillslot. + +## Other: Fixups, Stats, Debug Annotations + +There are a few fixup vectors that we will cover in more detail +later. Of particular note is the "multi-fixed-reg fixup vector": this +handles instructions that constrain the same input vreg to multiple, +different, fixed registers for different operands at the same program +point. The only way to satisfy such a set of constraints is to +decouple all but one of the inputs (make them no longer refer to the +vreg) and then later insert copies from the first fixed use of the +vreg to the other fixed regs. + +The `Env` also carries a statistics structure with counters that are +incremented, which can be useful for evaluating the effects of +changes; and a "debug annotations" hashmap from program point to +arbitrary strings that is filled out with various useful diagnostic +information if enabled, so that an annotated view of the program with +its liveranges, bundle assignments, inserted moves, merge and split +decisions, etc. can be viewed. + +# Allocation Pipeline + +We now describe the pipeline that computes register allocations. + +## Live-range Construction + +The first step in performing allocation is to analyze the input +program to understand its dataflow: that is, the ranges during which +virtual registers must be assigned to physical registers. Computing +these ranges is what allows us to do better than a trivial "every vreg +lives in a different location, always" allocation. + +We compute precise liveness first using an iterative dataflow +algorithm with BitVecs. (See below for our sparse chunked BitVec +description.) This produces the `liveins` and `liveouts` vectors of +BitVecs per block. + +We then perform a single pass over blocks in reverse order, and scan +instructions in each block in reverse order. Why reverse order? We +must see instructions within a block in reverse to properly compute +liveness (a value is live backward from an use to a def). Because we +want to keep liveranges in-order as we build them, to enable +coalescing, we visit blocks in reverse order as well, so overall this +is simply a scan over the whole instruction index space in reverse +order. + +For each block, we perform a scan with the following state: + +- A liveness bitvec, initialized at the start from `liveouts`. +- A vector of live-range indices, with one entry per vreg, initially + "invalid" (this vector is allocated once and reused at each block). +- In-progress vector of live-range indices per vreg in the vreg state, + in *reverse* order (we will reverse it when we're done). + +A vreg is live at the current point in the scan if its bit is set in +the bitvec; its entry in the vreg-to-liverange vec may be stale, but +if the bit is not set, we ignore it. + +We initially create a liverange for all vregs that are live out of the +block, spanning the whole block. We will trim this below if it is +locally def'd and does not pass through the block. + +For each instruction, we process its effects on the scan state: + +- For all clobbers (which logically happen at the end of the + instruction), add a single-program-point liverange to each clobbered + preg. + +- For each program point [after, before], for each operand at + this point(\*): + - if a def: + - if not currently live, this is a dead def; create an empty LR. + - set the start of the LR for this vreg to this point. + - set as dead. + - if a use: + - create LR if not live, with start at beginning of block. + + +(\*) an instruction operand's effective point is adjusted in a few +cases. If the instruction is a branch, its uses (which are +blockparams) are extended to the "after" point. If there is a reused +input, all *other* inputs are extended to "after": this ensures proper +interference (as we explain more below). + +We then treat blockparams as defs at the end of the scan (beginning of +the block), and create the "ins" tuples. (The uses for the other side +of the edge are already handled as normal uses on a branch +instruction.) + +### Handling Reused Inputs + +Reused inputs are also handled a bit specially. We have already +described how we essentially translate the idiom so that the output's +allocation is used for input and output, and there is a move just +before the instruction that copies the actual input (which will not be +clobbered) to the output. Together with an attempt to merge the +bundles for the two, to elide the move if possible, this works +perfectly well as long as we ignore all of the other inputs. + +But we can't do that: we have to ensure that other inputs' allocations +are correct too. Note that using the output's allocation as the input +is actually potentially incorrect if the output is at the After point +and the input is at the Before: the output might share a register with +one of the *other* (normal, non-reused) inputs if that input's vreg +were dead afterward. This will mean that we clobber the other input. + +So, to get the interference right, we *extend* all other (non-reused) +inputs of an instruction with a reused input to the After point. This +ensures that the other inputs are *not* clobbered by the slightly +premature use of the output register. + +The source has a link to a comment in IonMonkey that implies that it +uses a similar solution to this problem, though it's not entirely +clear. + +(This odd dance, like many of the others above and below, is "written +in fuzzbug failures", so to speak. It's not entirely obvious until one +sees the corner case where it's necessary!) + +## Bundle Merging + +Once we have built the liverange vectors for every vreg, we can reverse +these vectors (recall, they were built in strict reverse order) and +initially assign one bundle per (non-pinned) vreg. We then try to +merge bundles together as long as find pairs of bundles that do not +overlap and that (heuristically) make sense to merge. + +Note that this is the only point in the allocation pipeline where +bundles get larger. We initially merge as large as we dare (but not +too large, because then we'll just cause lots of conflicts and +splitting later), and then try out assignments, backtrack via +eviction, and split continuously to chip away at the problem until we +have a working set of allocation assignments. + +We attempt to merge two kinds of bundle pairs: reused-input to +corresponding output; and across blockparam assignments. + +To merge two bundles, we traverse over both their sorted liverange +vectors at once, checking for overlaps. Note that we can do this without +pointer-chasing to the liverange data; the (from, to) range is in the +liverange vector itself. + +We also check whether the merged bundle would have conflicting +requirements (see below for more on requirements). We do a coarse +check first, checking 1-bit flags that indicate whether either bundle +has any fixed-reg constraints or stack-only constraints. If so, we +need to do a detailed check by actually computing merged requirements +on both sides, merging, and checking for Conflict (the lattice bottom +value). If no conflict, we merge. + +A performance note: merging is extremely performance-sensitive, and it +turns out that a mergesort-like merge of the liverange vectors is too +expensive, partly because it requires allocating a separate result +vector (in-place merge in mergesort is infamously complex). Instead, +we simply append one vector onto the end of the other and invoke +Rust's builtin sort. We could special-case "one bundle is completely +before the other", but we currently don't do that (performance idea!). + +Once all bundles are merged as far as they will go, we compute cached +bundle properties (priorities and weights) and enqueue them on the +priority queue for allocation. + +## Recurring: Bundle Property Computation + +The core allocation loop is a recurring iteration of the following: we +take the highest-priority bundle from the allocation queue; we compute +its requirements; we try to find it a register according to those +requirements; if no fit, we either evict some other bundle(s) from +their allocations and try again, or we split the bundle and put the +parts back on the queue. We record all the information we need to make +the evict-or-split decision (and where to split) *during* the physical +register allocation-map scans, so we don't need to go back again to +compute that. + +Termination is nontrivial to see, because of eviction. How do we +guarantee we don't get into an infinite loop where two bundles fight +over a register forever? In fact, this can easily happen if there is a +bug; we fixed many fuzzbugs like this, and we have a check for +"infinite loop" based on an upper bound on iterations. But if the +allocator is correct, it should never happen. + +Termination is guaranteed because (i) bundles always get smaller, (ii) +eviction only occurs when a bundle is *strictly* higher weight (not +higher-or-equal), and (iii) once a bundle gets down to its "minimal" +size, it has an extremely high weight that is guaranteed to evict any +non-minimal bundle. A minimal bundle is one that covers only one +instruction. As long as the input program does not have impossible +constraints that require more than one vreg to exist in one preg, an +allocation problem of all minimal bundles will always have a solution. + +## Bundle Processing + +Let's now talk about what happens when we take a bundle off the +allocation queue. The three basic outcomes are: allocate; split and +requeue; or evict and try again immediately (and eventually allocate +or split/requeue). + +### Properties: Weight, Priority, and Requirements + +To process a bundle, we have to compute a few properties. In fact we +will have already computed a few of these beforehand, but we describe +them all here. + +- Priority: a bundle's priority determines the order in which it is + considered for allocation. RA2 defines as the sum of the lengths (in + instruction index space) of each liverange. This causes the + allocator to consider larger bundles first, when the allocation maps + are generally more free; they can always be evicted and split later. + +- Weight: a bundle's weight indicates how important (in terms of + runtime) its uses/register mentions are. In an approximate sense, + inner loop bodies create higher-weight uses. Fixed register + constraints add some weight, and defs add some weight. Finally, + weight is divided by priority, so a very large bundle that happens + to have a few important uses does not unformly exert its weight + across its entire range. This has the effect of causing bundles to + be more important (more likely to evict others) the more they are + split. + +- Requirement: a bundle's requirement is a value in a lattice that we + have defined, where top is "Unknown" and bottom is + "Conflict". Between these two, we have: any register (of a class); + any stackslot (of a class); a particular register. "Any register" + can degrade to "a particular register", but any other pair of + different requirements meets to Conflict. Requirements are derived + from the operand constraints for all uses in all liveranges in a + bundle, and then merged with the lattice meet-function. + +The lattice is as follows (diagram simplified to remove multiple +classes and multiple fixed registers which parameterize nodes; any two +differently-parameterized values are unordered with respect to each +other): + +```plain + + Any(rc) + / \ + FixedReg(reg) FixedStack(reg) + \ / + Conflict +``` + +Once we have the Requirement for a bundle, we can decide what to do. + +### No-Register-Required Cases + +If the requirement indicates that no register is needed (`Unknown` or +`Any`, i.e. a register or stack slot would be OK), *and* if the spill +bundle already exists for this bundle's spillset, then we move all the +liveranges over to the spill bundle, as described above. + +If the requirement indicates a conflict, we immediately split and +requeue the split pieces. This split is performed at the point at +which the conflict is first introduced, i.e. just before the first use +whose requirement, when merged into the requirement for all prior uses +combined, goes to `Conflict`. In this way, we always guarantee forward +progress. Note also that a bundle can reach this stage with a +conflicting requirement only if the original liverange had conflicting +uses (e.g., a liverange from a def in a register to a use on stack, or +a liverange between two different fixed-reg-constrained operands); our +bundle merging logic explicitly avoids merging two bundles if it would +create a conflict. + +### Allocation-Map Probing + +If we did not immediately dispose of the bundle as described above, +then we *can* use a register (either `Any`, which accepts a register +as one of several options, or `Reg`, which must have one, or `Fixed`, +which must have a particular one). + +We determine which physical registers whose allocation maps we will +probe, and in what order. If a particular fixed register is required, +we probe only that register. Otherwise, we probe all registers in the +required class. + +The order in which we probe, if we are not constrained to a single +register, is carefully chosen. First, if there is a hint register from +the spillset (this is set by the last allocation into a register of +any other bundle in this spillset), we probe that. Then, we probe all +preferred registers; then all non-preferred registers. + +For each of the preferred and non-preferred register sequences, we +probe in an *offset* manner: we start at some index partway through +the sequence, determined by some heuristic number that is random and +well-distributed. (In practice, we use the sum of the bundle index and +the instruction index of the start of the first range in the bundle.) +We then march through the sequence and wrap around, stopping before we +hit our starting point again. + +The purpose of this offset is to distribute the contention and speed +up the allocation process. In the common case where there are enough +registers to hold values without spilling (for small functions), we +are more likely to choose a free register right away if we throw the +dart at random than if we start *every* probe at register 0, in +order. This has a large allocation performance impact in practice. + +For each register in probe order, we probe the allocation map, and +gather, simultaneously, several results: (i) whether the entire range +is free; (ii) if not, the vector of all conflicting bundles, *and* the +highest weight among those bundles; (iii) if not, the *first* conflict +point. + +We do this by iterating over all liveranges in the preg's btree that +overlap with each range in the current bundle. This iteration is +somewhat subtle due to multiple "equal" keys (see above where we +describe the use of the btree). It is also adaptive for performance +reasons: it initially obtains an iterator into the btree corresponding +to the start of the first range in the bundle, and concurrently +iterates through both the btree and the bundle. However, if there is a +large gap in the bundle, this might require skipping many irrelevant +entries in the btree. So, if we skip too many entries (heuristically, +16, right now), we do another lookup from scratch in the btree for the +start of the next range in the bundle. This balances between the two +cases: dense bundle, where O(1) iteration through the btree is faster, +and sparse bundle, where O(log n) lookup for each entry is better. + +### Decision: Allocate, Evict, or Split + +First, the "allocate" case is easy: if, during our register probe +loop, we find a physical register whose allocations do not overlap +this bundle, then we allocate this register; done! + +If not, then we need to decide whether to evict some conflicting +bundles and retry, or to split the current bundle into smaller pieces +that may have better luck. + +A bit about our split strategy first: contrary to the IonMonkey +allocator which inspired much of our design, we do *not* have a list +of split strategies that split one bundle into many pieces at +once. Instead, each iteration of the allocation loop splits at most +*once*. This simplifies the splitting code greatly, but also turns out +to be a nice heuristic: we split at the point that the bundle first +encounters a conflict for a particular preg assignment, then we hint +that preg for the first (pre-conflict) piece when we retry. In this +way, we always make forward progress -- one piece of the bundle is +always allocated -- and splits are informed by the actual situation at +hand, rather than best guesses. Also note that while this may appear +at first to be a greedy algorithm, it still allows backtracking: the +first half of the split bundle, which we *can* now assign to a preg, +does not necessarily remain on that preg forever (it can still be +evicted later). It is just a split that is known to make at least one +part of the allocation problem solvable. + +To determine whether to split or evict, we track our best options: as +we probe, we track the "lowest cost eviction option", which is a set +of bundles and the maximum weight in that set of bundles. We also +track the "lowest cost split option", which is the cost (more below), +the point at which to split, and the register for this option. + +For each register we probe, if there is a conflict but none of the +conflicts are fixed allocations, we receive a vector of bundles that +conflicted, and also separately, the first conflicting program +point. We update the lowest-cost eviction option if the cost (max +weight) of the conflicting bundles is less than the current best. We +update the lowest-cost split option if the cost is less as well, +according to the following definition of cost: a split's cost is the +cost of its move, as defined by the weight of a normal def operand at +the split program point, plus the cost of all bundles beyond the split +point (which will still be conflicts even after the split). + +If there is a conflict with a fixed allocation, then eviction is not +an option, but we can still compute the candidate split point and cost +in the same way as above. + +Finally, as an optimization, we pass in the current best cost to the +btree probe inner loop; if, while probing, we have already exceeded +the best cost, we stop early (this improves allocation time without +affecting the result). + +Once we have the best cost for split and evict options, we split if +(i) the bundle is not already a minimal bundle, and (ii) we've already +evicted once in this toplevel iteration without success, or the weight +of the current bundle is less than the eviction cost. We then requeue +*both* resulting halves of the bundle with the preg that resulted in +this option as the register hint. Otherwise, we evict all conflicting +bundles and try again. + +Note that the split cost does not actually play into the above (split +vs. evict) decision; it is only used to choose *which* split is +best. This is equivalent to saying: we never evict if the current +bundle is less important than the evicted bundles, even if the split +is more expensive still. This is important for forward progress, and +the case where the split would be even more expensive should be very +very rare (it would have to come from a costly move in the middle of +an inner loop). + +### How to Split + +The actual split procedure is fairly simple. We are given a bundle and +a split-point. We create a new bundle to take on the second half +("rest") of the original. We find the point in the liverange vector +that corresponds to the split, and distribute appropriately. If the +split-point lands in the middle of a liverange, then we split that +liverange as well. + +In the case that a new liverange is created, we add the liverange to +the corresponding vreg liverange vector as well. Note that, as described +above, the vreg's liverange vector is unsorted while splitting is +occurring (because we do not need to traverse it or do any lookups +during this phase); so we just append. + +The splitting code also supports a "minimal split", in which it simply +peels off the first use. This is used to ensure forward progress when +a bundle has conflicting requirements within it (see above). + +#### Spill Bundle and Splitting + +Once a split occurs, however, it turns out that we can improve results +by doing a little cleanup. Once we distribute a bundle's liveranges +across two half-bundles, we postprocess by trimming a bit. + +In particular, if we see that the "loose ends" around the split point +extend beyond uses, we will create and move ranges to a spill +bundle. That is: if the last liverange in the first-half bundle +extends beyond its last use, we trim that part off into an empty (no +uses) liverange and place that liverange in the spill +bundle. Likewise, if the first liverange in the second-half bundle +starts before its first use, we trim that part off into an empty +liverange and place it in the spill bundle. + +This is, empirically, an improvement: it reduces register contention +and makes splitting more effective. The intuition is twofold: (i) it +is better to put all of the "flow-through" parts of a vreg's liveness +into one bundle that is never split, and can be spilled to the stack +if needed, to avoid unnecessary moves; and (ii) if contention is high +enough to cause splitting, it is more likely there will be an actual +stack spill, and if this is the case, it is better to do the store +just after the last use and reload just before the first use of the +respective bundles. + +## Second-Chance Allocation: Spilled Bundles + +Once the main allocation loop terminates, when all bundles have either +been allocated or punted to the "spilled bundles" vector, we do +second-chance allocation. This is a simpler loop that never evicts and +never splits. Instead, each bundle gets one second chance, in which it +can probe pregs and attempt to allocate. If it fails, it will actually +live on the stack. + +This is correct because we are careful to only place bundles on the +spilled-bundles vector that are *allowed* to live on the +stack. Specifically, only the canonical spill bundles (which will +contain only empty ranges) and other bundles that have an "any" or +"unknown" requirement are placed here (but *not* "stack" requirements; +those *must* be on the stack, so do not undergo second-chance +allocation). + +At the end of this process, we have marked spillsets as required +whenever at least one bundle in the spillset actually requires a stack +slot. We can then allocate slots to the spillsets. + +## Spillslot Allocation + +We must allocate space on the stack, denoted by an abstract index +space, to each spillset that requires it, and for the liveranges in +which it requires it. + +To facilitate this, we keep a btree per spillslot in the same way we +do per preg. We will allocate spillsets to slots in a way that avoids +interference. + +Note that we actually overapproximate the required ranges for each +spillset in order to improve the behavior of a later phase (redundant +move elimination). Specifically, when we allocate a slot for a +spillset, we reserve that slot for *all* of the liveranges of *every* +vreg that is assigned to that spillset (due to merging rules that +initially merge one-vreg bundles into final merged bundles, there will +be no overlaps here). In other words, we rule out interleaving of +completely different values in the same slot, though bundle merging +does mean that potentially many (non-interfering) vregs may share +it. This provides the important property that if a vreg has been +reloaded, but not modified, its spillslot *still contains the +up-to-date value* (because the slot is reserved for all liveranges of +the vreg). This enables us to avoid another store to the spillslot +later if there is another spilled range. + +We perform probing in a way that is somewhat different than for +registers, because the spillslot space is conceptually infinite. We +can thus optimize for slightly better allocation performance by giving +up and allocating a new slot at any time. + +For each size class, we keep a linked list of slots. When we need to +allocate a spillset to a slot, we traverse down the list and try a +fixed number of slots. If we find one that fits the spillset's ranges, +we allocate, and we remove the slot from its current place in the list +and append to the end. In this way, it is deprioritized from probing +"for a while", which tends to reduce contention. This is a simple way +to round-robin between slots. If we don't find one that fits after a +fixed number of probes, we allocate a new slot. + +And with that, we have valid allocations for all vregs for all points +that they are live! Now we just need to modify the program to reify +these choices. + +## Allocation Assignment + +The first step in reifying the allocation is to iterate through all +mentions of a vreg and fill in the resulting `Allocation` array with +the appropriate allocations. We do this by simply traversing +liveranges per vreg, looking up the allocation by observing the bundle +(and spillset if no specific allocation for the bundle), and for each +use, filling in the slot according to the saved progpoint/slot info in +the use data. + +## Move Generation + +The more difficult half of the reification step is generating the +*moves* that will put the values in the right spots. + +There are two sources of moves that we must generate. The first are +moves between different ranges of the same vreg, as the split pieces +of that vreg's original bundle may have been assigned to different +locations. The second are moves that result from move semantics in the +input program: assignments from blockparam args on branches to the +target block's params. + +Moves are tricky to handle efficiently because they join two +potentially very different locations in the program (in the case of +control-flow-edge moves). In order to avoid the need for random +lookups, which are a cache-locality nightmare even if we have O(log n) +lookups, we instead take a scan-sort-scan approach. + +First, we scan over each vreg's liveranges, find the allocation for +each, and for each move that comes *to* or *from* this liverange, +generate a "half-move". The key idea is that we generate a record for +each "side" of the move, and these records are keyed in a way that +after a sort, the "from" and "to" ends will be consecutive. We can +sort the vector of halfmoves once (this is expensive, but not as +expensive as many separate pointer-chasing lookups), then scan it +again to actually generate the move instructions. + +To enable the sort to work, half-moves are sorted by a key that is +equivalent to the tuple (from-block, to-block, to-vreg, kind), where +`kind` is "source" or "dest". For each key, the payload is an +allocation. The fields in this tuple are carefully chosen: we know all +of them at every location we generate a halfmove, without expensive +lookups, and sorting by this key will make the source and all dests +(there can be more than one) contiguous in the final order. + +Half-moves are generated for several situations. First, at the start +of every block covered by a liverange, we can generate "dest" +half-moves for blockparams, and at the end of every block covered by a +liverange, we can generate "source" half-moves for blockparam args on +branches. Incidentally, this is the reason that `blockparam_ins` and +`blockparam_outs` are sorted tuple-vectors whose tuples begin with +(vreg, block, ...): this is the order in which we do the toplevel scan +over allocations. + +Second, at every block edge, if the vreg is live in any pred (at +block-start) or succ (at block-end), we generate a half-move to +transfer the vreg to its own location in the connected block. + +This completes the "edge-moves". We sort the half-move array and then +have all of the alloc-to-alloc pairs on a given (from-block, to-block) +edge. + +Next, when a live-range ends and another begins for the same vreg in +the same block (i.e., a split in the middle of a block), we know both +sides of the move immediately (because it is the same vreg and we can +look up the adjacent allocation easily), and we can generate that +move. + +Finally, we generate moves to fix up multi-fixed-reg-constraint +situations, and make reused inputs work, as described earlier. + +## Move Resolution + +During this whole discussion, we have described "generating moves", +but we have not said what that meant. Note that in many cases, there +are several moves at a particular program point that semantically +happen *in parallel*. For example, if multiple vregs change +allocations between two instructions, all of those moves happen as +part of one parallel permutation. Similarly, blockparams have +parallel-assignment semantics. We thus enqueue all the moves that we +generate at program points and resolve them into sequences of +sequential moves that can actually be lowered to move instructions in +the machine code. + +First, a word on *move priorities*. There are different kinds of moves +that are generated between instructions, and we have to ensure that +some happen before others, i.e., *not* in parallel. For example, a +vreg might change allocation (due to a split) before an instruction, +then be copied to an output register for an output with a reused-input +policy. The latter move must happen *after* the vreg has been moved +into its location for this instruction. + +To enable this, we define "move priorities", which are a logical +extension of program points (i.e., they are sub-points) that enable +finer-grained ordering of moves. We currently have the following +priorities: + +- In-edge moves, to place edge-moves before the first instruction in a + block. +- Regular, used for vreg movement between allocations. +- Multi-fixed-reg, used for moves that handle the + single-vreg-in-multiple-fixed-pregs constraint case. +- Reused-input, used for implementing outputs with reused-input policies. +- Out-edge moves, to place edge-moves after the last instruction + (prior to the branch) in a block. + +Every move is statically given one of these priorities by the code +that generates it. + +We collect moves with (prog-point, prio) keys, and we sort by those +keys. We then have, for each such key, a set of moves that +semantically happen in parallel. + +We then resolve those moves using a parallel-move resolver, as we now +describe. + +### Parallel-Move Resolver + +The fundamental issue that arises when resolving parallel moves to +sequential moves is *overlap*: some of the moves may overwrite +registers that other moves use as sources. We must carefully order +moves so that this does not clobber values incorrectly. + +We first check if such overlap occurs. If it does not (this is +actually the most common case), the sequence of parallel moves can be +emitted as sequential moves directly. Done! + +Otherwise, we have to order the moves carefully. Furthermore, if there +is a *cycle* anywhere among the moves, we will need a scratch +register. (Consider, e.g., t0 := t1 and t1 := t0 in parallel: with +only move instructions and no direct "exchange" instruction, we cannot +reify this without a third register.) + +We first compute a mapping from each move instruction to the move +instruction, if any, that it must precede. Note that there can be only +one such move for a given move, because each destination can be +written only once; so a move might be constrained only before the one +move that overwrites its source. (This will be important in a bit!) + +Our task is now to find an ordering of moves that respects these +dependencies. To do so, we perform a depth-first search on the graph +induced by the dependencies, which will generate a sequence of +sequential moves in reverse order. We keep a stack of moves; we start +with any move that has not been visited yet; in each iteration, if the +top-of-stack has no out-edge to another move (does not need to come +before any others), then push it to a result vector, followed by all +others on the stack (in popped order). If it does have an out-edge and +the target is already visited and not on the stack anymore (so already +emitted), likewise, emit this move and the rest on the stack. If it +has an out-edge to a move not yet visited, push on the stack and +continue. Otherwise, if out-edge to a move currently on the stack, we +have found a cycle. In this case, we emit the moves on the stack with +a modification: the first move writes to a scratch register, and we +emit an additional move that moves from the scratch to the first +move's dest. This breaks the cycle. + +The astute reader may notice that this sounds like a canonical +application of Tarjan's algorithm for finding SCCs (strongly-connected +components). Why don't we have the full complexity of that algorithm? +In particular, *why* can we emit the cycle *right away* once we find +it, rather than ensuring that we have gotten all of the SCC first? + +The answer is that because there is only *one* out-edge at most (a +move can only require preceding *one* other move), all SCCs must be +simple cycles. This means that once we have found a cycle, no other +nodes (moves) can be part of the SCC, because every node's single +out-edge is already accounted for. This is what allows us to avoid a +fully general SCC algorithm. + +Once the vector of moves in-reverse has been constructed, we reverse +it and return. + +Note that this "move resolver" is fuzzed separately with a simple +symbolic move simulator (the `moves` fuzz-target). + +### Stack-to-Stack Moves + +There is one potentially difficult situation that could arise from the +move-resolution logic so far: if a vreg moves from one spillslot to +another, this implies a memory-to-memory move, which most machine +architectures cannot handle natively. It would be much nicer if we +could ensure within the regalloc that this never occurs. + +This is in fact possible to do in a postprocessing step. We iterate +through the sequential moves, tracking whether the scratch register is +in use (has been written). When we see a stack-to-stack move: (i) if +the scratch register is not in use, generate a stack-to-scratch move +and scratch-to-stack move; otherwise, (ii) if the scratch register is +in use, allocate an "extra spillslot" if one has not already been +allocated, move the scratch reg to that, do the above stack-to-scratch +/ scratch-to-stack sequence, then reload the scratch reg from the +extra spillslot. + +## Redundant-Spill/Load Elimination + +As a final step before returning the vector of program edits to the +client, we perform one optimization: redundant-spill/load elimination. + +To understand the need for this, consider what will occur when a vreg +is (i) defined once, (ii) used many times, and (iii) spilled multiple +times between some of the uses: with the design described above, we +will move the value from the preg to the stack after every segment of +uses, and then reload it when the next use occurs. However, only the +first spill is actually needed; as we noted above, we allocate +spillslots so that the slot that corresponded to the vreg at the first +spill will always be reserved for that vreg as long as it is live. If +no other defs or mods occur, the value in the slot can be reloaded, +and need not be written back every time. + +This inefficiency is a result of our invariant that a vreg lives in +exactly one place at a time, and these locations are joined by +moves. This is a simple and effective design to use for most of the +allocation pipeline, but falls flat here. It is especially inefficient +when the unnecessary spill occurs in an inner loop. (E.g.: value +defined at top of function is spilled, then used once in the middle of +an inner loop body.) + +The opposite case can also sometimes occur, though it is rarer: a +value is loaded into a register, spilled, and then reloaded into the +same register. This can happen when hinting is successful at getting +several segments of a vreg to use the same preg, but splitting has +trimmed part of the liverange between uses and put it in the spill +bundle, and the spill bundle did not get a reg. + +In order to resolve this inefficiency, we implement a general +redundant-spill/load elimination pass (an even more general solution +would be a full redundant-move elimination pass, but we focus on moves +that are spills/loads to contain the complexity for now). This pass +tracks, for every allocation (reg or spillslot), whether it is a copy +of another allocation. This state is invalidated whenever either that +allocation or the allocation of which it is a copy is +overwritten. When we see a move instruction, if the destination is +already a copy of the source, we elide the move. (There are some +additional complexities to preserve checker metadata which we do not +describe here.) + +Note that this could, in principle, be done as a fixpoint analysis +over the CFG; it must be, if we try to preserve state across +blocks. This is because a location is only a copy of another if that +is true on every incoming edge. However, to avoid the cost and +complexity of doing such an analysis, we instead take the much simpler +approach of doing only an intra-block analysis. This turns out to be +sufficient to remove most redundant moves, especially in the common +case of a single use of an otherwise-spilled value. + +Note that there is an opportunity to do better: as we only accept SSA +code we would know that a value could not be redefined once written. + +# Future Plans + +## Better Split Heuristics + +We have spent quite some effort trying to improve splitting behavior, +and it is now generally decent, but more work could be done here, +especially with regard to the interaction between splits and the loop +nest. + +# Appendix: Comparison to IonMonkey Allocator + +There are a number of differences between the [IonMonkey +allocator](https://searchfox.org/mozilla-central/source/js/src/jit/BacktrackingAllocator.cpp) +and this one. While this allocator initially began as an attempt to +clone IonMonkey's, it has drifted significantly as we optimized the +design (especially after we built the regalloc.rs shim and had to +adapt to its code style); it is easier at this point to name the +similarities than the differences. + +* The core abstractions of "liverange", "bundle", "vreg", "preg", and + "operand" (with policies/constraints) are the same. + +* The overall allocator pipeline is the same, and the top-level + structure of each stage should look similar. Both allocators begin + by computing liveranges, then merging bundles, then handling bundles + and splitting/evicting as necessary, then doing second-chance + allocation, then reifying the decisions. + +* The cost functions are very similar, though the heuristics that make + decisions based on them are not. + +Several notable high-level differences are: + +* There are [fuzz/fuzz_targets/](many different fuzz targets) that + exercise the allocator, including a full symbolic checker + (`ion_checker` target) based on the [symbolic checker in + regalloc.rs](https://cfallin.org/blog/2021/03/15/cranelift-isel-3/) + and, e.g., a targetted fuzzer for the parallel move-resolution + algorithm (`moves`) and the SSA generator used for generating cases + for the other fuzz targets (`ssagen`). + +* The data-structure invariants are simplified. While the IonMonkey + allocator allowed for LiveRanges and Bundles to overlap in certain + cases, this allocator sticks to a strict invariant: ranges do not + overlap in bundles, and bundles do not overlap. There are other + examples too: e.g., the definition of minimal bundles is very simple + and does not depend on scanning the code at all. In general, we + should be able to state simple invariants and see by inspection (as + well as fuzzing -- see above) that they hold. + +* The data structures themselves are simplified. Where IonMonkey uses + linked lists in many places, this allocator stores simple inline + smallvecs of liveranges on bundles and vregs, and smallvecs of uses + on liveranges. We also (i) find a way to construct liveranges + in-order immediately, without any need for splicing, unlike + IonMonkey, and (ii) relax sorting invariants where possible to allow + for cheap append operations in many cases. + +* The splitting heuristics are significantly reworked. Whereas + IonMonkey has an all-at-once approach to splitting an entire bundle, + and has a list of complex heuristics to choose where to split, this + allocator does conflict-based splitting, and tries to decide whether + to split or evict and which split to take based on cost heuristics. + +* The liverange computation is exact, whereas IonMonkey approximates + using a single-pass algorithm that makes vregs live across entire + loop bodies. We have found that precise liveness improves allocation + performance and generated code quality, even though the liveness + itself is slightly more expensive to compute. + +* Many of the algorithms in the IonMonkey allocator are built with + helper functions that do linear scans. These "small quadratic" loops + are likely not a huge issue in practice, but nevertheless have the + potential to be in corner cases. As much as possible, all work in + this allocator is done in linear scans. + +* There are novel schemes for solving certain interesting design + challenges. One example: in IonMonkey, liveranges are connected + across blocks by, when reaching one end of a control-flow edge in a + scan, doing a lookup of the allocation at the other end. This is in + principle a linear lookup (so quadratic overall). We instead + generate a vector of "half-moves", keyed on the edge and from/to + vregs, with each holding one of the allocations. By sorting and then + scanning this vector, we can generate all edge moves in one linear + scan. There are a number of other examples of simplifications: for + example, we handle multiple conflicting + physical-register-constrained uses of a vreg in a single instruction + by recording a copy to do in a side-table, then removing constraints + for the core regalloc. Ion instead has to tweak its definition of + minimal bundles and create two liveranges that overlap (!) to + represent the two uses. + +* Using block parameters rather than phi-nodes significantly + simplifies handling of inter-block data movement. IonMonkey had to + special-case phis in many ways because they are actually quite + weird: their uses happen semantically in other blocks, and their + defs happen in parallel at the top of the block. Block parameters + naturally and explicitly reprsent these semantics in a direct way. + +* The allocator supports irreducible control flow and arbitrary block + ordering (its only CFG requirement is that critical edges are + split). + +* The allocator supports non-SSA code, and has native support for + handling program moves specially. + +# Appendix: Performance-Tuning Lessons + +In the course of optimizing the allocator's performance, we found a +number of general principles: + +* We got substantial performance speedups from using vectors rather + than linked lists everywhere. This is well-known, but nevertheless, + it took some thought to work out how to avoid the need for any + splicing, and it turns out that even when our design is slightly + less efficient asymptotically (e.g., apend-and-re-sort rather than + linear-time merge of two sorted liverange lists when merging + bundles), it is faster. + +* We initially used a direct translation of IonMonkey's splay tree as + an allocation map for each PReg. This turned out to be significantly + (!) less efficient than Rust's built-in BTree data structures, for + the usual cache-efficiency vs. pointer-chasing reasons. + +* We initially used dense bitvecs, as IonMonkey does, for + livein/liveout bits. It turned out that a chunked sparse design (see + below) was much more efficient. + +* Precise liveness significantly improves performance because it + reduces the size of liveranges (i.e., interference), and probing + registers with liveranges is the most significant hot inner + loop. Paying a fraction of a percent runtime for the iterative + dataflow algorithm to get precise bitsets is more than worth it. + +* The randomized probing of registers was a huge win: as above, the + probing is very expensive, and reducing the average number of probes + it takes to find a free register is very important. + +* In general, single-pass algorithms and design of data structures to + enable them are important. For example, the half-move technique + avoids the need to do any O(log n) search at all, and is relatively + cache-efficient. As another example, a side-effect of the precise + liveness was that we could then process operands within blocks in + actual instruction order (in reverse), which allowed us to simply + append liveranges to in-progress vreg liverange vectors and then + reverse at the end. The expensive part is a single pass; only the + bitset computation is a fixpoint loop. + +* Sorts are better than always-sorted data structures (like btrees): + they amortize all the comparison and update cost to one phase, and + this phase is much more cache-friendly than a bunch of spread-out + updates. + +* Take care of basic data structures and their operator definitions! + We initially used the auto-derived comparator on ProgPoint, and let + ProgPoint be a normal struct (with a u32 inst index and a + Befor/After enum). The comparator for this, used in many sorting + inner loops, was a compound thing with conditionals. Instead, pack + them in a u32 and do a simple compare (and save half the memory as + well). Likewise, the half-move key is a single value packed in a + u64; this is far more efficient than the tuple comparator on a + 4-tuple, and the half-move sort (which can be a few percent or more + of total allocation time) became multiple times cheaper. + +# Appendix: Data Structure: Chunked Sparse BitVec + +We use a "chunked sparse bitvec" to store liveness information, which +is just a set of VReg indices. The design is fairly simple: the +toplevel is a HashMap from "chunk" to a `u64`, and each `u64` +represents 64 contiguous indices. + +The intuition is that while the vreg sets are likely sparse overall, +they will probably be dense within small regions of the index +space. For example, in the Nth block in a function, the values that +flow from block N-1 will largely be almost-contiguous vreg indices, if +vregs are allocated in sequence down the function body. Or, at least, +they will be some local vregs together with a few defined at the top +of the function; two separate chunks will cover that. + +We tried a number of other designs as well. Initially we used a simple +dense bitvec, but this was prohibitively expensive: O(n^2) space when +the real need is closer to O(n) (i.e., a classic sparse matrix). We +also tried a hybrid scheme that kept a vector of indices when small +and used either a bitvec or a hashset when large. This did not perform +as well because (i) it was less memory-efficient (the chunking helps +with this) and (ii) insertions are more expensive when they always +require a full hashset/hashmap insert. + +# Appendix: Fuzzing + +We have five fuzz targets: `ssagen`, `domtree`, `moves`, `ion`, and +`ion_checker`. + +## SSAGen + +The SSAGen target tests our SSA generator, which generates cases for +the full allocator fuzz targets. The SSA generator is careful to +always generate a valid CFG, with split critical edges, and valid SSA, +so that we never have to throw out a test input before we reach the +allocator itself. (An alternative fuzzing approach randomly generates +programs and then throws out those that do not meet certain conditions +before using them as legitimate testcases; this is much simpler, but +less efficient.) + +To generate a valid CFG, with no unreachable blocks and with no +critical edges, the generator (i) glues together units of either one +or three blocks (A->B, A->C), forming either a straight-through +section or a conditional. These are glued together into a "spine", and +the conditionals (the "C" block), where they exist, are then linked to +a random target block chosen among the main blocks of these one- or +three-block units. The targets are chosen either randomly, for +potentially irreducible CFGs, or in a way that ensures proper nesting +of loop backedges, if a structured CFG is requested. + +SSA is generated by first choosing which vregs will be defined in each +block, and which will be defined as blockparams vs. instruction +defs. Instructions are then generated, with operands chosen among the +"available" vregs: those defined so far in the current block and all +of those in any other block that dominates this one. + +The SSAGen fuzz target runs the above code generator against an SSA +validator, and thus ensures that it will only generate valid SSA code. + +## Domtree + +The `domtree` fuzz target computes dominance using the algorithm that +we use elsewhere in our CFG analysis, and then walks a +randomly-generated path through the CFG. It checks that the dominance +definition ("a dom b if any path from entry to b must pass through a") +is consistent with this particular randomly-chosen path. + +## Moves + +The `moves` fuzz target tests the parallel move resolver. It generates +a random sequence of parallel moves, careful to ensure that each +destination is written only once. It then runs the parallel move +resolver, and then *abstractly interprets* the resulting sequential +series of moves, thus determining which inputs flow to which +outputs. This must match the original set of parallel moves. + +## Ion and Ion-checker + +The `ion` fuzz target runs the allocator over test programs generated +by SSAGen. It does not validate the output; it only tests that the +allocator runs to completion and does not panic. This was used mainly +during development, and is now less useful than the checker-based +target. + +The `ion_checker` fuzz target runs the allocator's result through a +symbolic checker, which is adapted from the one developed for +regalloc.rs (see [this blog +post](https://cfallin.org/blog/2021/01/22/cranelift-isel-2/) for more +details). This is the most useful fuzz target in the fuzzing suite, +and has found many bugs in development. diff --git a/deps/crates/vendor/regalloc2/doc/TODO b/deps/crates/vendor/regalloc2/doc/TODO new file mode 100644 index 00000000000000..3e430305065ec5 --- /dev/null +++ b/deps/crates/vendor/regalloc2/doc/TODO @@ -0,0 +1,34 @@ +# Features + +- Large-input support (> 1M vregs, > 1M blocks) + - Two operand impls: u64-based and u32-based. Always accept + u64-based `Operand` publicly (do not expose this in interface). + - Trait to generalize over them and support both internally + (parameterize the whole allocator impl) + - On data-structure init, choose one or the other based on max vreg + index + - Update halfmove keys: u128 rather than u64 + +- Support allocation of register pairs (or overlapping registers generally) + +- Rematerialization +- Stack-location constraints that place operands in user-defined stack + locations (distinct from SpillSlots) (e.g., stack args) + +# Performance + +- Investigate better register hinting +- Investigate more principled cost functions and split locations, + especially around loop nests + +- Investigate ways to improve bundle-merging; e.g., merge moves before + other types of connections + +- Add limited inter-block redundant-move elimination: propagate across + splits but not joins. + +- Optimize allocations (some reports of 5-7% of time spent in allocator) + +# Cleanup + +- Remove support for non-SSA code once no longer necessary \ No newline at end of file diff --git a/deps/crates/vendor/regalloc2/src/cfg.rs b/deps/crates/vendor/regalloc2/src/cfg.rs new file mode 100644 index 00000000000000..8a653cd3f758a4 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/cfg.rs @@ -0,0 +1,155 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +//! Lightweight CFG analyses. + +use crate::alloc::vec::Vec; + +use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError, VecExt}; +use smallvec::{smallvec, SmallVec}; + +#[derive(Debug, Default)] +pub struct CFGInfoCtx { + visited: Vec, + block_to_rpo: Vec>, + backedge: Vec, +} + +#[derive(Debug, Default)] +pub struct CFGInfo { + /// Postorder traversal of blocks. + pub postorder: Vec, + /// Domtree parents, indexed by block. + pub domtree: Vec, + /// For each instruction, the block it belongs to. + pub insn_block: Vec, + /// For each block, the first instruction. + pub block_entry: Vec, + /// For each block, the last instruction. + pub block_exit: Vec, + /// For each block, what is the approximate loop depth? + /// + /// This measure is fully precise iff the input CFG is reducible + /// and blocks are in RPO, so that loop backedges are precisely + /// those whose block target indices are less than their source + /// indices. Otherwise, it will be approximate, but should still + /// be usable for heuristic purposes. + pub approx_loop_depth: Vec, +} + +impl CFGInfo { + pub fn new(f: &F) -> Result { + let mut ctx = CFGInfoCtx::default(); + let mut this = Self::default(); + this.init(f, &mut ctx)?; + Ok(this) + } + + pub fn init(&mut self, f: &F, ctx: &mut CFGInfoCtx) -> Result<(), RegAllocError> { + let nb = f.num_blocks(); + + postorder::calculate( + nb, + f.entry_block(), + &mut ctx.visited, + &mut self.postorder, + |block| f.block_succs(block), + ); + + domtree::calculate( + nb, + |block| f.block_preds(block), + &self.postorder, + &mut ctx.block_to_rpo, + &mut self.domtree, + f.entry_block(), + ); + + let insn_block = self.insn_block.repopulate(f.num_insts(), Block::invalid()); + let block_entry = self + .block_entry + .repopulate(nb, ProgPoint::before(Inst::invalid())); + let block_exit = self + .block_exit + .repopulate(nb, ProgPoint::before(Inst::invalid())); + let (backedge_in, backedge_out) = ctx.backedge.repopulate(nb * 2, 0).split_at_mut(nb); + + for block in 0..f.num_blocks() { + let block = Block::new(block); + for inst in f.block_insns(block).iter() { + insn_block[inst.index()] = block; + } + block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first()); + block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last()); + + // Check critical edge condition: if there is more than + // one predecessor, each must have only one successor + // (this block). + let preds = f.block_preds(block).len() + if block == f.entry_block() { 1 } else { 0 }; + if preds > 1 { + for &pred in f.block_preds(block) { + let succs = f.block_succs(pred).len(); + if succs > 1 { + return Err(RegAllocError::CritEdge(pred, block)); + } + } + } + + // Check branch-arg condition: if any successors have more + // than one predecessor (given above, there will only be + // one such successor), then the last instruction of this + // block (the branch) cannot have any args other than the + // blockparams. + let mut require_no_branch_args = false; + for &succ in f.block_succs(block) { + let preds = f.block_preds(succ).len() + if succ == f.entry_block() { 1 } else { 0 }; + if preds > 1 { + require_no_branch_args = true; + break; + } + } + if require_no_branch_args { + let last = f.block_insns(block).last(); + if !f.inst_operands(last).is_empty() { + return Err(RegAllocError::DisallowedBranchArg(last)); + } + } + + for &succ in f.block_succs(block) { + if succ.index() <= block.index() { + backedge_in[succ.index()] += 1; + backedge_out[block.index()] += 1; + } + } + } + + let approx_loop_depth = self.approx_loop_depth.cleared(); + let mut backedge_stack: SmallVec<[u32; 4]> = smallvec![]; + let mut cur_depth = 0; + for block in 0..nb { + if backedge_in[block] > 0 { + cur_depth += 1; + backedge_stack.push(backedge_in[block]); + } + + approx_loop_depth.push(cur_depth); + + while backedge_stack.len() > 0 && backedge_out[block] > 0 { + backedge_out[block] -= 1; + *backedge_stack.last_mut().unwrap() -= 1; + if *backedge_stack.last().unwrap() == 0 { + cur_depth -= 1; + backedge_stack.pop(); + } + } + } + + Ok(()) + } + + pub fn dominates(&self, a: Block, b: Block) -> bool { + domtree::dominates(&self.domtree[..], a, b) + } +} diff --git a/deps/crates/vendor/regalloc2/src/checker.rs b/deps/crates/vendor/regalloc2/src/checker.rs new file mode 100644 index 00000000000000..d67dc2da786b70 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/checker.rs @@ -0,0 +1,984 @@ +/* + * The following code is derived from `lib/src/checker.rs` in the + * regalloc.rs project + * (https://github.com/bytecodealliance/regalloc.rs). regalloc.rs is + * also licensed under Apache-2.0 with the LLVM exception, as the rest + * of regalloc2 is. + */ + +//! Checker: verifies that spills/reloads/moves retain equivalent +//! dataflow to original, VReg-based code. +//! +//! The basic idea is that we track symbolic values as they flow +//! through spills and reloads. The symbolic values represent +//! particular virtual registers in the original function body +//! presented to the register allocator. Any instruction in the +//! original function body (i.e., not added by the allocator) +//! conceptually generates a symbolic value "Vn" when storing to (or +//! modifying) a virtual register. +//! +//! A symbolic value is logically a *set of virtual registers*, +//! representing all virtual registers equal to the value in the given +//! storage slot at a given program point. This representation (as +//! opposed to tracking just one virtual register) is necessary +//! because the regalloc may implement moves in the source program +//! (via move instructions or blockparam assignments on edges) in +//! "intelligent" ways, taking advantage of values that are already in +//! the right place, so we need to know *all* names for a value. +//! +//! These symbolic values are precise but partial: in other words, if +//! a physical register is described as containing a virtual register +//! at a program point, it must actually contain the value of this +//! register (modulo any analysis bugs); but it may describe fewer +//! virtual registers even in cases where one *could* statically prove +//! that it contains a certain register, because the analysis is not +//! perfectly path-sensitive or value-sensitive. However, all +//! assignments *produced by our register allocator* should be +//! analyzed fully precisely. (This last point is important and bears +//! repeating: we only need to verify the programs that we produce, +//! not arbitrary programs.) +//! +//! Operand constraints (fixed register, register, any) are also checked +//! at each operand. +//! +//! ## Formal Definition +//! +//! The analysis lattice consists of the elements of 𝒫(V), the +//! powerset (set of all subsets) of V (the set of all virtual +//! registers). The ⊤ (top) value in the lattice is V itself, and the +//! ⊥ (bottom) value in the lattice is ∅ (the empty set). The lattice +//! ordering relation is the subset relation: S ≤ U iff S ⊆ U. These +//! definitions imply that the lattice meet-function (greatest lower +//! bound) is set-intersection. +//! +//! (For efficiency, we represent ⊤ not by actually listing out all +//! virtual registers, but by representing a special "top" value, but +//! the semantics are the same.) +//! +//! The dataflow analysis state at each program point (each point +//! before or after an instruction) is: +//! +//! - map of: Allocation -> lattice value +//! +//! And the transfer functions for instructions are (where `A` is the +//! above map from allocated physical registers to lattice values): +//! +//! - `Edit::Move` inserted by RA: [ alloc_d := alloc_s ] +//! +//! A' = A[alloc_d → A[alloc_s]] +//! +//! - statement in pre-regalloc function [ V_i := op V_j, V_k, ... ] +//! with allocated form [ A_i := op A_j, A_k, ... ] +//! +//! A' = { A_k → A[A_k] \ { V_i } for k ≠ i } ∪ +//! { A_i -> { V_i } } +//! +//! In other words, a statement, even after allocation, generates +//! a symbol that corresponds to its original virtual-register +//! def. Simultaneously, that same virtual register symbol is removed +//! from all other allocs: they no longer carry the current value. +//! +//! - Parallel moves or blockparam-assignments in original program +//! [ V_d1 := V_s1, V_d2 := V_s2, ... ] +//! +//! A' = { A_k → subst(A[A_k]) for all k } +//! where subst(S) removes symbols for overwritten virtual +//! registers (V_d1 .. V_dn) and then adds V_di whenever +//! V_si appeared prior to the removals. +//! +//! To check correctness, we first find the dataflow fixpoint with the +//! above lattice and transfer/meet functions. Then, at each op, we +//! examine the dataflow solution at the preceding program point, and +//! check that the allocation for each op arg (input/use) contains the +//! symbol corresponding to the original virtual register specified +//! for this arg. + +#![allow(dead_code)] + +use crate::{ + Allocation, AllocationKind, Block, Edit, Function, FxHashMap, FxHashSet, Inst, InstOrEdit, + InstPosition, MachineEnv, Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg, + PRegSet, VReg, +}; +use alloc::vec::Vec; +use alloc::{format, vec}; +use core::default::Default; +use core::hash::Hash; +use core::result::Result; +use smallvec::{smallvec, SmallVec}; + +/// A set of errors detected by the regalloc checker. +#[derive(Clone, Debug)] +pub struct CheckerErrors { + errors: Vec, +} + +/// A single error detected by the regalloc checker. +#[derive(Clone, Debug)] +pub enum CheckerError { + MissingAllocation { + inst: Inst, + op: Operand, + }, + UnknownValueInAllocation { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + ConflictedValueInAllocation { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + IncorrectValuesInAllocation { + inst: Inst, + op: Operand, + alloc: Allocation, + actual: FxHashSet, + }, + ConstraintViolated { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + AllocationIsNotReg { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + AllocationIsNotFixedReg { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + AllocationIsNotReuse { + inst: Inst, + op: Operand, + alloc: Allocation, + expected_alloc: Allocation, + }, + AllocationIsNotStack { + inst: Inst, + op: Operand, + alloc: Allocation, + }, + StackToStackMove { + into: Allocation, + from: Allocation, + }, +} + +/// Abstract state for an allocation. +/// +/// Equivalent to a set of virtual register names, with the +/// universe-set as top and empty set as bottom lattice element. The +/// meet-function is thus set intersection. +#[derive(Clone, Debug, PartialEq, Eq)] +enum CheckerValue { + /// The lattice top-value: this value could be equivalent to any + /// vreg (i.e., the universe set). + Universe, + /// The set of VRegs that this value is equal to. + VRegs(FxHashSet), +} + +impl CheckerValue { + fn vregs(&self) -> Option<&FxHashSet> { + match self { + CheckerValue::Universe => None, + CheckerValue::VRegs(vregs) => Some(vregs), + } + } + + fn vregs_mut(&mut self) -> Option<&mut FxHashSet> { + match self { + CheckerValue::Universe => None, + CheckerValue::VRegs(vregs) => Some(vregs), + } + } +} + +impl Default for CheckerValue { + fn default() -> CheckerValue { + CheckerValue::Universe + } +} + +impl CheckerValue { + /// Meet function of the abstract-interpretation value + /// lattice. Returns a boolean value indicating whether `self` was + /// changed. + fn meet_with(&mut self, other: &CheckerValue) { + match (self, other) { + (_, CheckerValue::Universe) => { + // Nothing. + } + (this @ CheckerValue::Universe, _) => { + *this = other.clone(); + } + (CheckerValue::VRegs(my_vregs), CheckerValue::VRegs(other_vregs)) => { + my_vregs.retain(|vreg| other_vregs.contains(vreg)); + } + } + } + + fn from_reg(reg: VReg) -> CheckerValue { + CheckerValue::VRegs(core::iter::once(reg).collect()) + } + + fn remove_vreg(&mut self, reg: VReg) { + match self { + CheckerValue::Universe => { + panic!("Cannot remove VReg from Universe set (we do not have the full list of vregs available"); + } + CheckerValue::VRegs(vregs) => { + vregs.remove(®); + } + } + } + + fn copy_vreg(&mut self, src: VReg, dst: VReg) { + match self { + CheckerValue::Universe => { + // Nothing. + } + CheckerValue::VRegs(vregs) => { + if vregs.contains(&src) { + vregs.insert(dst); + } + } + } + } + + fn empty() -> CheckerValue { + CheckerValue::VRegs(FxHashSet::default()) + } +} + +fn visit_all_vregs(f: &F, mut v: V) { + for block in 0..f.num_blocks() { + let block = Block::new(block); + for inst in f.block_insns(block).iter() { + for op in f.inst_operands(inst) { + v(op.vreg()); + } + if f.is_branch(inst) { + for succ_idx in 0..f.block_succs(block).len() { + for ¶m in f.branch_blockparams(block, inst, succ_idx) { + v(param); + } + } + } + } + for &vreg in f.block_params(block) { + v(vreg); + } + } +} + +/// State that steps through program points as we scan over the instruction stream. +#[derive(Clone, Debug, PartialEq, Eq)] +enum CheckerState { + Top, + Allocations(FxHashMap), +} + +impl CheckerState { + fn get_value(&self, alloc: &Allocation) -> Option<&CheckerValue> { + match self { + CheckerState::Top => None, + CheckerState::Allocations(allocs) => allocs.get(alloc), + } + } + + fn get_values_mut(&mut self) -> impl Iterator { + match self { + CheckerState::Top => panic!("Cannot get mutable values iterator on Top state"), + CheckerState::Allocations(allocs) => allocs.values_mut(), + } + } + + fn get_mappings(&self) -> impl Iterator { + match self { + CheckerState::Top => panic!("Cannot get mappings iterator on Top state"), + CheckerState::Allocations(allocs) => allocs.iter(), + } + } + + fn get_mappings_mut(&mut self) -> impl Iterator { + match self { + CheckerState::Top => panic!("Cannot get mutable mappings iterator on Top state"), + CheckerState::Allocations(allocs) => allocs.iter_mut(), + } + } + + /// Transition from a "top" (undefined/unanalyzed) state to an empty set of allocations. + fn become_defined(&mut self) { + match self { + CheckerState::Top => *self = CheckerState::Allocations(FxHashMap::default()), + _ => {} + } + } + + fn set_value(&mut self, alloc: Allocation, value: CheckerValue) { + match self { + CheckerState::Top => { + panic!("Cannot set value on Top state"); + } + CheckerState::Allocations(allocs) => { + allocs.insert(alloc, value); + } + } + } + + fn copy_vreg(&mut self, src: VReg, dst: VReg) { + match self { + CheckerState::Top => { + // Nothing. + } + CheckerState::Allocations(allocs) => { + for value in allocs.values_mut() { + value.copy_vreg(src, dst); + } + } + } + } + + fn remove_value(&mut self, alloc: &Allocation) { + match self { + CheckerState::Top => { + panic!("Cannot remove value on Top state"); + } + CheckerState::Allocations(allocs) => { + allocs.remove(alloc); + } + } + } + + fn initial() -> Self { + CheckerState::Allocations(FxHashMap::default()) + } +} + +impl Default for CheckerState { + fn default() -> CheckerState { + CheckerState::Top + } +} + +impl core::fmt::Display for CheckerValue { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + CheckerValue::Universe => { + write!(f, "top") + } + CheckerValue::VRegs(vregs) => { + write!(f, "{{ ")?; + for vreg in vregs { + write!(f, "{} ", vreg)?; + } + write!(f, "}}")?; + Ok(()) + } + } + } +} + +/// Meet function for analysis value: meet individual values at +/// matching allocations, and intersect keys (remove key-value pairs +/// only on one side). Returns boolean flag indicating whether `into` +/// changed. +fn merge_map( + into: &mut FxHashMap, + from: &FxHashMap, +) { + into.retain(|k, _| from.contains_key(k)); + for (k, into_v) in into.iter_mut() { + let from_v = from.get(k).unwrap(); + into_v.meet_with(from_v); + } +} + +impl CheckerState { + /// Create a new checker state. + fn new() -> CheckerState { + Default::default() + } + + /// Merge this checker state with another at a CFG join-point. + fn meet_with(&mut self, other: &CheckerState) { + match (self, other) { + (_, CheckerState::Top) => { + // Nothing. + } + (this @ CheckerState::Top, _) => { + *this = other.clone(); + } + ( + CheckerState::Allocations(my_allocations), + CheckerState::Allocations(other_allocations), + ) => { + merge_map(my_allocations, other_allocations); + } + } + } + + fn check_val<'a, F: Function>( + &self, + inst: Inst, + op: Operand, + alloc: Allocation, + val: &CheckerValue, + allocs: &[Allocation], + checker: &Checker<'a, F>, + ) -> Result<(), CheckerError> { + if alloc == Allocation::none() { + return Err(CheckerError::MissingAllocation { inst, op }); + } + + if op.kind() == OperandKind::Use && op.as_fixed_nonallocatable().is_none() { + match val { + CheckerValue::Universe => { + return Err(CheckerError::UnknownValueInAllocation { inst, op, alloc }); + } + CheckerValue::VRegs(vregs) if !vregs.contains(&op.vreg()) => { + return Err(CheckerError::IncorrectValuesInAllocation { + inst, + op, + alloc, + actual: vregs.clone(), + }); + } + _ => {} + } + } + + self.check_constraint(inst, op, alloc, allocs, checker)?; + + Ok(()) + } + + /// Check an instruction against this state. This must be called + /// twice: once with `InstPosition::Before`, and once with + /// `InstPosition::After` (after updating state with defs). + fn check<'a, F: Function>( + &self, + pos: InstPosition, + checkinst: &CheckerInst, + checker: &Checker<'a, F>, + ) -> Result<(), CheckerError> { + let default_val = Default::default(); + match checkinst { + &CheckerInst::Op { + inst, + ref operands, + ref allocs, + .. + } => { + // Skip Use-checks at the After point if there are any + // reused inputs: the Def which reuses the input + // happens early. + let has_reused_input = operands + .iter() + .any(|op| matches!(op.constraint(), OperandConstraint::Reuse(_))); + if has_reused_input && pos == InstPosition::After { + return Ok(()); + } + + // For each operand, check (i) that the allocation + // contains the expected vreg, and (ii) that it meets + // the requirements of the OperandConstraint. + for (op, alloc) in operands.iter().zip(allocs.iter()) { + let is_here = match (op.pos(), pos) { + (OperandPos::Early, InstPosition::Before) => true, + (OperandPos::Late, InstPosition::After) => true, + _ => false, + }; + if !is_here { + continue; + } + + let val = self.get_value(alloc).unwrap_or(&default_val); + trace!( + "checker: checkinst {:?}: op {:?}, alloc {:?}, checker value {:?}", + checkinst, + op, + alloc, + val + ); + self.check_val(inst, *op, *alloc, val, allocs, checker)?; + } + } + &CheckerInst::Move { into, from } => { + // Ensure that the allocator never returns stack-to-stack moves. + let is_stack = |alloc: Allocation| { + if let Some(reg) = alloc.as_reg() { + checker.stack_pregs.contains(reg) + } else { + alloc.is_stack() + } + }; + if is_stack(into) && is_stack(from) { + return Err(CheckerError::StackToStackMove { into, from }); + } + } + &CheckerInst::ParallelMove { .. } => { + // This doesn't need verification; we just update + // according to the move semantics in the step + // function below. + } + } + Ok(()) + } + + /// Update according to instruction. + fn update(&mut self, checkinst: &CheckerInst) { + self.become_defined(); + + match checkinst { + &CheckerInst::Move { into, from } => { + // Value may not be present if this move is part of + // the parallel move resolver's fallback sequence that + // saves a victim register elsewhere. (In other words, + // that sequence saves an undefined value and restores + // it, so has no effect.) The checker needs to avoid + // putting Universe lattice values into the map. + if let Some(val) = self.get_value(&from).cloned() { + trace!( + "checker: checkinst {:?} updating: move {:?} -> {:?} val {:?}", + checkinst, + from, + into, + val + ); + self.set_value(into, val); + } + } + &CheckerInst::ParallelMove { ref moves } => { + // First, build map of actions for each vreg in an + // alloc. If an alloc has a reg V_i before a parallel + // move, then for each use of V_i as a source (V_i -> + // V_j), we might add a new V_j wherever V_i appears; + // and if V_i is used as a dest (at most once), then + // it must be removed first from allocs' vreg sets. + let mut additions: FxHashMap> = FxHashMap::default(); + let mut deletions: FxHashSet = FxHashSet::default(); + + for &(dest, src) in moves { + deletions.insert(dest); + additions + .entry(src) + .or_insert_with(|| smallvec![]) + .push(dest); + } + + // Now process each allocation's set of vreg labels, + // first deleting those labels that were updated by + // this parallel move, then adding back labels + // redefined by the move. + for value in self.get_values_mut() { + if let Some(vregs) = value.vregs_mut() { + let mut insertions: SmallVec<[VReg; 2]> = smallvec![]; + for &vreg in vregs.iter() { + if let Some(additions) = additions.get(&vreg) { + insertions.extend(additions.iter().cloned()); + } + } + for &d in &deletions { + vregs.remove(&d); + } + vregs.extend(insertions); + } + } + } + &CheckerInst::Op { + ref operands, + ref allocs, + ref clobbers, + .. + } => { + // For each def, (i) update alloc to reflect defined + // vreg (and only that vreg), and (ii) update all + // other allocs in the checker state by removing this + // vreg, if defined (other defs are now stale). + for (op, alloc) in operands.iter().zip(allocs.iter()) { + if op.kind() != OperandKind::Def { + continue; + } + self.remove_vreg(op.vreg()); + self.set_value(*alloc, CheckerValue::from_reg(op.vreg())); + } + for clobber in clobbers { + self.remove_value(&Allocation::reg(*clobber)); + } + } + } + } + + fn remove_vreg(&mut self, vreg: VReg) { + for (_, value) in self.get_mappings_mut() { + value.remove_vreg(vreg); + } + } + + fn check_constraint<'a, F: Function>( + &self, + inst: Inst, + op: Operand, + alloc: Allocation, + allocs: &[Allocation], + checker: &Checker<'a, F>, + ) -> Result<(), CheckerError> { + match op.constraint() { + OperandConstraint::Any => {} + OperandConstraint::Reg => { + if let Some(preg) = alloc.as_reg() { + // Reject pregs that represent a fixed stack slot. + if !checker.machine_env.fixed_stack_slots.contains(&preg) { + return Ok(()); + } + } + return Err(CheckerError::AllocationIsNotReg { inst, op, alloc }); + } + OperandConstraint::FixedReg(preg) => { + if alloc != Allocation::reg(preg) { + return Err(CheckerError::AllocationIsNotFixedReg { inst, op, alloc }); + } + } + OperandConstraint::Reuse(idx) => { + if alloc.kind() != AllocationKind::Reg { + return Err(CheckerError::AllocationIsNotReg { inst, op, alloc }); + } + if alloc != allocs[idx] { + return Err(CheckerError::AllocationIsNotReuse { + inst, + op, + alloc, + expected_alloc: allocs[idx], + }); + } + } + } + Ok(()) + } +} + +/// An instruction representation in the checker's BB summary. +#[derive(Clone, Debug)] +pub(crate) enum CheckerInst { + /// A move between allocations (these could be registers or + /// spillslots). + Move { into: Allocation, from: Allocation }, + + /// A parallel move in the original program. Simultaneously moves + /// from all source vregs to all corresponding dest vregs, + /// permitting overlap in the src and dest sets and doing all + /// reads before any writes. + ParallelMove { + /// Vector of (dest, src) moves. + moves: Vec<(VReg, VReg)>, + }, + + /// A regular instruction with fixed use and def slots. Contains + /// both the original operands (as given to the regalloc) and the + /// allocation results. + Op { + inst: Inst, + operands: Vec, + allocs: Vec, + clobbers: Vec, + }, +} + +#[derive(Debug)] +pub struct Checker<'a, F: Function> { + f: &'a F, + bb_in: FxHashMap, + bb_insts: FxHashMap>, + edge_insts: FxHashMap<(Block, Block), Vec>, + machine_env: &'a MachineEnv, + stack_pregs: PRegSet, +} + +impl<'a, F: Function> Checker<'a, F> { + /// Create a new checker for the given function, initializing CFG + /// info immediately. The client should call the `add_*()` + /// methods to add abstract instructions to each BB before + /// invoking `run()` to check for errors. + pub fn new(f: &'a F, machine_env: &'a MachineEnv) -> Checker<'a, F> { + let mut bb_in = FxHashMap::default(); + let mut bb_insts = FxHashMap::default(); + let mut edge_insts = FxHashMap::default(); + + for block in 0..f.num_blocks() { + let block = Block::new(block); + bb_in.insert(block, Default::default()); + bb_insts.insert(block, vec![]); + for &succ in f.block_succs(block) { + edge_insts.insert((block, succ), vec![]); + } + } + + bb_in.insert(f.entry_block(), CheckerState::default()); + + let mut stack_pregs = PRegSet::empty(); + for &preg in &machine_env.fixed_stack_slots { + stack_pregs.add(preg); + } + + Checker { + f, + bb_in, + bb_insts, + edge_insts, + machine_env, + stack_pregs, + } + } + + /// Build the list of checker instructions based on the given func + /// and allocation results. + pub fn prepare(&mut self, out: &Output) { + trace!("checker: out = {:?}", out); + let mut last_inst = None; + for block in 0..self.f.num_blocks() { + let block = Block::new(block); + for inst_or_edit in out.block_insts_and_edits(self.f, block) { + match inst_or_edit { + InstOrEdit::Inst(inst) => { + debug_assert!(last_inst.is_none() || inst > last_inst.unwrap()); + last_inst = Some(inst); + self.handle_inst(block, inst, out); + } + InstOrEdit::Edit(edit) => self.handle_edit(block, edit), + } + } + } + } + + /// For each original instruction, create an `Op`. + fn handle_inst(&mut self, block: Block, inst: Inst, out: &Output) { + // Skip normal checks if this is a branch: the blockparams do + // not exist in post-regalloc code, and the edge-moves have to + // be inserted before the branch rather than after. + if !self.f.is_branch(inst) { + let operands: Vec<_> = self.f.inst_operands(inst).iter().cloned().collect(); + let allocs: Vec<_> = out.inst_allocs(inst).iter().cloned().collect(); + let clobbers: Vec<_> = self.f.inst_clobbers(inst).into_iter().collect(); + let checkinst = CheckerInst::Op { + inst, + operands, + allocs, + clobbers, + }; + trace!("checker: adding inst {:?}", checkinst); + self.bb_insts.get_mut(&block).unwrap().push(checkinst); + } + // Instead, if this is a branch, emit a ParallelMove on each + // outgoing edge as necessary to handle blockparams. + else { + for (i, &succ) in self.f.block_succs(block).iter().enumerate() { + let args = self.f.branch_blockparams(block, inst, i); + let params = self.f.block_params(succ); + assert_eq!( + args.len(), + params.len(), + "block{} has succ block{}; gave {} args for {} params", + block.index(), + succ.index(), + args.len(), + params.len() + ); + if args.len() > 0 { + let moves = params.iter().cloned().zip(args.iter().cloned()).collect(); + self.edge_insts + .get_mut(&(block, succ)) + .unwrap() + .push(CheckerInst::ParallelMove { moves }); + } + } + } + } + + fn handle_edit(&mut self, block: Block, edit: &Edit) { + trace!("checker: adding edit {:?}", edit); + match edit { + &Edit::Move { from, to } => { + self.bb_insts + .get_mut(&block) + .unwrap() + .push(CheckerInst::Move { into: to, from }); + } + } + } + + /// Perform the dataflow analysis to compute checker state at each BB entry. + fn analyze(&mut self) { + let mut queue = Vec::new(); + let mut queue_set = FxHashSet::default(); + + // Put every block in the queue to start with, to ensure + // everything is visited even if the initial state remains + // `Top` after preds update it. + // + // We add blocks in reverse order so that when we process + // back-to-front below, we do our initial pass in input block + // order, which is (usually) RPO order or at least a + // reasonable visit order. + for block in (0..self.f.num_blocks()).rev() { + let block = Block::new(block); + queue.push(block); + queue_set.insert(block); + } + + while let Some(block) = queue.pop() { + queue_set.remove(&block); + let mut state = self.bb_in.get(&block).cloned().unwrap(); + trace!("analyze: block {} has state {:?}", block.index(), state); + for inst in self.bb_insts.get(&block).unwrap() { + state.update(inst); + trace!("analyze: inst {:?} -> state {:?}", inst, state); + } + + for &succ in self.f.block_succs(block) { + let mut new_state = state.clone(); + for edge_inst in self.edge_insts.get(&(block, succ)).unwrap() { + new_state.update(edge_inst); + trace!( + "analyze: succ {:?}: inst {:?} -> state {:?}", + succ, + edge_inst, + new_state + ); + } + + let cur_succ_in = self.bb_in.get(&succ).unwrap(); + trace!( + "meeting state {:?} for block {} with state {:?} for block {}", + new_state, + block.index(), + cur_succ_in, + succ.index() + ); + new_state.meet_with(cur_succ_in); + let changed = &new_state != cur_succ_in; + trace!(" -> {:?}, changed {}", new_state, changed); + + if changed { + trace!( + "analyze: block {} state changed from {:?} to {:?}; pushing onto queue", + succ.index(), + cur_succ_in, + new_state + ); + self.bb_in.insert(succ, new_state); + if queue_set.insert(succ) { + queue.push(succ); + } + } + } + } + } + + /// Using BB-start state computed by `analyze()`, step the checker state + /// through each BB and check each instruction's register allocations + /// for errors. + fn find_errors(&self) -> Result<(), CheckerErrors> { + let mut errors = vec![]; + for (block, input) in &self.bb_in { + let mut state = input.clone(); + for inst in self.bb_insts.get(block).unwrap() { + if let Err(e) = state.check(InstPosition::Before, inst, self) { + trace!("Checker error: {:?}", e); + errors.push(e); + } + state.update(inst); + if let Err(e) = state.check(InstPosition::After, inst, self) { + trace!("Checker error: {:?}", e); + errors.push(e); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(CheckerErrors { errors }) + } + } + + /// Find any errors, returning `Err(CheckerErrors)` with all errors found + /// or `Ok(())` otherwise. + pub fn run(mut self) -> Result<(), CheckerErrors> { + self.analyze(); + let result = self.find_errors(); + + trace!("=== CHECKER RESULT ==="); + fn print_state(state: &CheckerState) { + if !trace_enabled!() { + return; + } + if let CheckerState::Allocations(allocs) = state { + let mut s = vec![]; + for (alloc, state) in allocs { + s.push(format!("{} := {}", alloc, state)); + } + trace!(" {{ {} }}", s.join(", ")) + } + } + for bb in 0..self.f.num_blocks() { + let bb = Block::new(bb); + trace!("block{}:", bb.index()); + let insts = self.bb_insts.get(&bb).unwrap(); + let mut state = self.bb_in.get(&bb).unwrap().clone(); + print_state(&state); + for inst in insts { + match inst { + &CheckerInst::Op { + inst, + ref operands, + ref allocs, + ref clobbers, + } => { + trace!( + " inst{}: {:?} ({:?}) clobbers:{:?}", + inst.index(), + operands, + allocs, + clobbers + ); + } + &CheckerInst::Move { from, into } => { + trace!(" {} -> {}", from, into); + } + &CheckerInst::ParallelMove { .. } => { + panic!("unexpected parallel_move in body (non-edge)") + } + } + state.update(inst); + print_state(&state); + } + + for &succ in self.f.block_succs(bb) { + trace!(" succ {:?}:", succ); + let mut state = state.clone(); + for edge_inst in self.edge_insts.get(&(bb, succ)).unwrap() { + match edge_inst { + &CheckerInst::ParallelMove { ref moves } => { + let moves = moves + .iter() + .map(|(dest, src)| format!("{} -> {}", src, dest)) + .collect::>(); + trace!(" parallel_move {}", moves.join(", ")); + } + _ => panic!("unexpected edge_inst: not a parallel move"), + } + state.update(edge_inst); + print_state(&state); + } + } + } + + result + } +} diff --git a/deps/crates/vendor/regalloc2/src/domtree.rs b/deps/crates/vendor/regalloc2/src/domtree.rs new file mode 100644 index 00000000000000..4b90d4dcf6f537 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/domtree.rs @@ -0,0 +1,119 @@ +/* + * Derives from the dominator tree implementation in regalloc.rs, which is + * licensed under the Apache Public License 2.0 with LLVM Exception. See: + * https://github.com/bytecodealliance/regalloc.rs + */ + +// This is an implementation of the algorithm described in +// +// A Simple, Fast Dominance Algorithm +// Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy +// Department of Computer Science, Rice University, Houston, Texas, USA +// TR-06-33870 +// https://www.cs.rice.edu/~keith/EMBED/dom.pdf + +use core::u32; + +use alloc::vec::Vec; + +use crate::{Block, VecExt}; + +// Helper +fn merge_sets( + idom: &[Block], // map from Block to Block + block_to_rpo: &[Option], + mut node1: Block, + mut node2: Block, +) -> Block { + while node1 != node2 { + if node1.is_invalid() || node2.is_invalid() { + return Block::invalid(); + } + let rpo1 = block_to_rpo[node1.index()].unwrap(); + let rpo2 = block_to_rpo[node2.index()].unwrap(); + if rpo1 > rpo2 { + node1 = idom[node1.index()]; + } else if rpo2 > rpo1 { + node2 = idom[node2.index()]; + } + } + debug_assert!(node1 == node2); + node1 +} + +pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>( + num_blocks: usize, + preds: PredFn, + post_ord: &[Block], + block_to_rpo_scratch: &mut Vec>, + out: &mut Vec, + start: Block, +) { + // We have post_ord, which is the postorder sequence. + // Compute maps from RPO to block number and vice-versa. + let block_to_rpo = block_to_rpo_scratch.repopulate(num_blocks, None); + for (i, rpo_block) in post_ord.iter().rev().enumerate() { + block_to_rpo[rpo_block.index()] = Some(i as u32); + } + + let idom = out.repopulate(num_blocks, Block::invalid()); + // The start node must have itself as a parent. + idom[start.index()] = start; + + let mut changed = true; + while changed { + changed = false; + // Consider blocks in reverse postorder. Skip any that are unreachable. + for &node in post_ord.iter().rev() { + let rponum = block_to_rpo[node.index()].unwrap(); + + let mut parent = Block::invalid(); + for &pred in preds(node).iter() { + let pred_rpo = match block_to_rpo[pred.index()] { + None => { + // Skip unreachable preds. + continue; + } + Some(r) => r, + }; + if pred_rpo < rponum { + parent = pred; + break; + } + } + + if parent.is_valid() { + for &pred in preds(node).iter() { + if pred == parent { + continue; + } + if idom[pred.index()].is_invalid() { + continue; + } + parent = merge_sets(&idom, &block_to_rpo[..], parent, pred); + } + } + + if parent.is_valid() && parent != idom[node.index()] { + idom[node.index()] = parent; + changed = true; + } + } + } + + // Now set the start node's dominator-tree parent to "invalid"; + // this allows the loop in `dominates` to terminate. + idom[start.index()] = Block::invalid(); +} + +pub fn dominates(idom: &[Block], a: Block, mut b: Block) -> bool { + loop { + if a == b { + return true; + } + if b.is_invalid() { + return false; + } + b = idom[b.index()]; + } +} diff --git a/deps/crates/vendor/regalloc2/src/fastalloc/iter.rs b/deps/crates/vendor/regalloc2/src/fastalloc/iter.rs new file mode 100644 index 00000000000000..d1437559abf5b7 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fastalloc/iter.rs @@ -0,0 +1,44 @@ +use crate::{Operand, OperandConstraint, OperandKind}; + +pub struct Operands<'a>(pub &'a [Operand]); + +impl<'a> Operands<'a> { + pub fn new(operands: &'a [Operand]) -> Self { + Self(operands) + } + + pub fn matches bool + 'a>( + &self, + predicate: F, + ) -> impl Iterator + 'a { + self.0 + .iter() + .cloned() + .enumerate() + .filter(move |(_, op)| predicate(*op)) + } + + pub fn def_ops(&self) -> impl Iterator + 'a { + self.matches(|op| op.kind() == OperandKind::Def) + } + + pub fn use_ops(&self) -> impl Iterator + 'a { + self.matches(|op| op.kind() == OperandKind::Use) + } + + pub fn reuse(&self) -> impl Iterator + 'a { + self.matches(|op| matches!(op.constraint(), OperandConstraint::Reuse(_))) + } + + pub fn fixed(&self) -> impl Iterator + 'a { + self.matches(|op| matches!(op.constraint(), OperandConstraint::FixedReg(_))) + } +} + +impl<'a> core::ops::Index for Operands<'a> { + type Output = Operand; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} diff --git a/deps/crates/vendor/regalloc2/src/fastalloc/lru.rs b/deps/crates/vendor/regalloc2/src/fastalloc/lru.rs new file mode 100644 index 00000000000000..37c61155755f3b --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fastalloc/lru.rs @@ -0,0 +1,324 @@ +use crate::{FxHashSet, PReg, PRegSet, RegClass}; +use alloc::vec; +use alloc::vec::Vec; +use core::{ + fmt, + ops::{Index, IndexMut}, +}; + +/// A least-recently-used cache organized as a linked list based on a vector. +pub struct Lru { + /// The list of node information. + /// + /// Each node corresponds to a physical register. + /// The index of a node is the `address` from the perspective of the linked list. + pub data: Vec, + /// Index of the most recently used register. + pub head: u8, + /// Class of registers in the cache. + pub regclass: RegClass, +} + +#[derive(Clone, Copy, Debug)] +pub struct LruNode { + /// The previous physical register in the list. + pub prev: u8, + /// The next physical register in the list. + pub next: u8, +} + +impl Lru { + pub fn new(regclass: RegClass, regs: &[PReg]) -> Self { + let mut data = vec![ + LruNode { + prev: u8::MAX, + next: u8::MAX + }; + PReg::MAX + 1 + ]; + let no_of_regs = regs.len(); + for i in 0..no_of_regs { + let (reg, prev_reg, next_reg) = ( + regs[i], + regs[i.checked_sub(1).unwrap_or(no_of_regs - 1)], + regs[if i >= no_of_regs - 1 { 0 } else { i + 1 }], + ); + data[reg.hw_enc()].prev = prev_reg.hw_enc() as u8; + data[reg.hw_enc()].next = next_reg.hw_enc() as u8; + } + Self { + head: if regs.is_empty() { + u8::MAX + } else { + regs[0].hw_enc() as u8 + }, + data, + regclass, + } + } + + /// Marks the physical register `preg` as the most recently used + pub fn poke(&mut self, preg: PReg) { + trace!( + "Before poking: {:?} LRU. head: {:?}, Actual data: {:?}", + self.regclass, + self.head, + self.data + ); + trace!("About to poke {:?} in {:?} LRU", preg, self.regclass); + let prev_newest = self.head; + let hw_enc = preg.hw_enc() as u8; + if hw_enc == prev_newest { + return; + } + if self.data[prev_newest as usize].prev != hw_enc { + self.remove(hw_enc as usize); + self.insert_before(hw_enc, self.head); + } + self.head = hw_enc; + trace!("Poked {:?} in {:?} LRU", preg, self.regclass); + if cfg!(debug_assertions) { + self.validate_lru(); + } + } + + /// Gets the least recently used physical register. + pub fn pop(&mut self) -> PReg { + trace!( + "Before popping: {:?} LRU. head: {:?}, Actual data: {:?}", + self.regclass, + self.head, + self.data + ); + trace!("Popping {:?} LRU", self.regclass); + if self.is_empty() { + panic!("LRU is empty"); + } + let oldest = self.data[self.head as usize].prev; + trace!("Popped p{oldest} in {:?} LRU", self.regclass); + if cfg!(debug_assertions) { + self.validate_lru(); + } + PReg::new(oldest as usize, self.regclass) + } + + /// Get the last PReg in the LRU from the set `from`. + pub fn last(&self, from: PRegSet) -> Option { + trace!("Getting the last preg from the LRU in set {from}"); + self.last_satisfying(|preg| from.contains(preg)) + } + + /// Get the last PReg from the LRU for which `f` returns true. + pub fn last_satisfying bool>(&self, f: F) -> Option { + trace!("Getting the last preg from the LRU satisfying..."); + if self.is_empty() { + panic!("LRU is empty"); + } + let mut last = self.data[self.head as usize].prev; + let init_last = last; + loop { + let preg = PReg::new(last as usize, self.regclass); + if f(preg) { + return Some(preg); + } + last = self.data[last as usize].prev; + if last == init_last { + return None; + } + } + } + + /// Splices out a node from the list. + fn remove(&mut self, hw_enc: usize) { + trace!( + "Before removing: {:?} LRU. head: {:?}, Actual data: {:?}", + self.regclass, + self.head, + self.data + ); + trace!("Removing p{hw_enc} from {:?} LRU", self.regclass); + let (iprev, inext) = ( + self.data[hw_enc].prev as usize, + self.data[hw_enc].next as usize, + ); + self.data[iprev].next = self.data[hw_enc].next; + self.data[inext].prev = self.data[hw_enc].prev; + self.data[hw_enc].prev = u8::MAX; + self.data[hw_enc].next = u8::MAX; + if hw_enc == self.head as usize { + if hw_enc == inext { + // There are no regs in the LRU + self.head = u8::MAX; + } else { + self.head = inext as u8; + } + } + trace!("Removed p{hw_enc} from {:?} LRU", self.regclass); + if cfg!(debug_assertions) { + self.validate_lru(); + } + } + + /// Insert node `i` before node `j` in the list. + fn insert_before(&mut self, i: u8, j: u8) { + trace!( + "Before inserting: {:?} LRU. head: {:?}, Actual data: {:?}", + self.regclass, + self.head, + self.data + ); + trace!("Inserting p{i} before {j} in {:?} LRU", self.regclass); + let prev = self.data[j as usize].prev; + self.data[prev as usize].next = i; + self.data[j as usize].prev = i; + self.data[i as usize] = LruNode { next: j, prev }; + trace!("Done inserting p{i} before {j} in {:?} LRU", self.regclass); + if cfg!(debug_assertions) { + self.validate_lru(); + } + } + + pub fn is_empty(&self) -> bool { + self.head == u8::MAX + } + + // Using this to debug. + fn validate_lru(&self) { + trace!( + "{:?} LRU. head: {:?}, Actual data: {:?}", + self.regclass, + self.head, + self.data + ); + if self.head != u8::MAX { + let mut node = self.data[self.head as usize].next; + let mut seen = FxHashSet::default(); + while node != self.head { + if seen.contains(&node) { + panic!( + "Cycle detected in {:?} LRU.\n + head: {:?}, actual data: {:?}", + self.regclass, self.head, self.data + ); + } + seen.insert(node); + node = self.data[node as usize].next; + } + for i in 0..self.data.len() { + if self.data[i].prev == u8::MAX && self.data[i].next == u8::MAX { + // Removed + continue; + } + if self.data[i].prev == u8::MAX || self.data[i].next == u8::MAX { + panic!( + "Invalid LRU. p{} next or previous is an invalid value, but not both", + i + ); + } + if self.data[self.data[i].prev as usize].next != i as u8 { + panic!( + "Invalid LRU. p{i} prev is p{:?}, but p{:?} next is {:?}", + self.data[i].prev, + self.data[i].prev, + self.data[self.data[i].prev as usize].next + ); + } + if self.data[self.data[i].next as usize].prev != i as u8 { + panic!( + "Invalid LRU. p{i} next is p{:?}, but p{:?} prev is p{:?}", + self.data[i].next, + self.data[i].next, + self.data[self.data[i].next as usize].prev + ); + } + } + } + } +} + +impl fmt::Debug for Lru { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use alloc::format; + let data_str = if self.head == u8::MAX { + format!("") + } else { + let mut data_str = format!("p{}", self.head); + let mut node = self.data[self.head as usize].next; + let mut seen = FxHashSet::default(); + while node != self.head { + if seen.contains(&node) { + panic!( + "The {:?} LRU is messed up: + head: {:?}, {:?} -> p{node}, actual data: {:?}", + self.regclass, self.head, data_str, self.data + ); + } + seen.insert(node); + data_str += &format!(" -> p{}", node); + node = self.data[node as usize].next; + } + data_str + }; + f.debug_struct("Lru") + .field("head", if self.is_empty() { &"none" } else { &self.head }) + .field("class", &self.regclass) + .field("data", &data_str) + .finish() + } +} + +#[derive(Clone)] +pub struct PartedByRegClass { + pub items: [T; 3], +} + +impl Index for PartedByRegClass { + type Output = T; + + fn index(&self, index: RegClass) -> &Self::Output { + &self.items[index as usize] + } +} + +impl IndexMut for PartedByRegClass { + fn index_mut(&mut self, index: RegClass) -> &mut Self::Output { + &mut self.items[index as usize] + } +} + +/// Least-recently-used caches for register classes Int, Float, and Vector, respectively. +pub type Lrus = PartedByRegClass; + +impl Lrus { + pub fn new(int_regs: &[PReg], float_regs: &[PReg], vec_regs: &[PReg]) -> Self { + Self { + items: [ + Lru::new(RegClass::Int, int_regs), + Lru::new(RegClass::Float, float_regs), + Lru::new(RegClass::Vector, vec_regs), + ], + } + } +} + +use core::fmt::{Debug, Display}; + +impl Display for PartedByRegClass { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{{ int: {}, float: {}, vector: {} }}", + self.items[0], self.items[1], self.items[2] + ) + } +} + +impl Debug for PartedByRegClass { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{{ int: {:?}, float: {:?}, vector: {:?} }}", + self.items[0], self.items[1], self.items[2] + ) + } +} diff --git a/deps/crates/vendor/regalloc2/src/fastalloc/mod.rs b/deps/crates/vendor/regalloc2/src/fastalloc/mod.rs new file mode 100644 index 00000000000000..c8d41f6cb3d6a6 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fastalloc/mod.rs @@ -0,0 +1,1312 @@ +use crate::moves::{MoveAndScratchResolver, ParallelMoves}; +use crate::{cfg::CFGInfo, ion::Stats, Allocation, RegAllocError}; +use crate::{ssa::validate_ssa, Edit, Function, MachineEnv, Output, ProgPoint}; +use crate::{ + AllocationKind, Block, FxHashMap, Inst, InstPosition, Operand, OperandConstraint, OperandKind, + OperandPos, PReg, PRegSet, RegClass, SpillSlot, VReg, +}; +use alloc::vec::Vec; +use core::convert::TryInto; +use core::iter::FromIterator; +use core::ops::{Index, IndexMut}; + +mod iter; +mod lru; +mod vregset; +use iter::*; +use lru::*; +use vregset::VRegSet; + +#[cfg(test)] +mod tests; + +#[derive(Debug)] +struct Allocs { + allocs: Vec, + /// `inst_alloc_offsets[i]` is the offset into `allocs` for the allocations of + /// instruction `i`'s operands. + inst_alloc_offsets: Vec, +} + +impl Allocs { + fn new(func: &F) -> (Self, u32) { + let mut allocs = Vec::new(); + let mut inst_alloc_offsets = Vec::with_capacity(func.num_insts()); + let mut max_operand_len = 0; + let mut no_of_operands = 0; + for inst in 0..func.num_insts() { + let operands_len = func.inst_operands(Inst::new(inst)).len() as u32; + max_operand_len = max_operand_len.max(operands_len); + inst_alloc_offsets.push(no_of_operands as u32); + no_of_operands += operands_len; + } + allocs.resize(no_of_operands as usize, Allocation::none()); + ( + Self { + allocs, + inst_alloc_offsets, + }, + max_operand_len, + ) + } +} + +impl Index<(usize, usize)> for Allocs { + type Output = Allocation; + + /// Retrieve the allocation for operand `idx.1` at instruction `idx.0` + fn index(&self, idx: (usize, usize)) -> &Allocation { + &self.allocs[self.inst_alloc_offsets[idx.0] as usize + idx.1] + } +} + +impl IndexMut<(usize, usize)> for Allocs { + fn index_mut(&mut self, idx: (usize, usize)) -> &mut Allocation { + &mut self.allocs[self.inst_alloc_offsets[idx.0] as usize + idx.1] + } +} + +#[derive(Debug)] +struct Stack<'a, F: Function> { + num_spillslots: u32, + func: &'a F, +} + +impl<'a, F: Function> Stack<'a, F> { + fn new(func: &'a F) -> Self { + Self { + num_spillslots: 0, + func, + } + } + + /// Allocates a spill slot on the stack for `vreg` + fn allocstack(&mut self, class: RegClass) -> SpillSlot { + trace!("Allocating a spillslot for class {class:?}"); + let size: u32 = self.func.spillslot_size(class).try_into().unwrap(); + // Rest of this function was copied verbatim + // from `Env::allocate_spillslot` in src/ion/spill.rs. + let mut offset = self.num_spillslots; + // Align up to `size`. + debug_assert!(size.is_power_of_two()); + offset = (offset + size - 1) & !(size - 1); + let slot = if self.func.multi_spillslot_named_by_last_slot() { + offset + size - 1 + } else { + offset + }; + offset += size; + self.num_spillslots = offset; + trace!("Allocated slot: {slot}"); + SpillSlot::new(slot as usize) + } +} + +#[derive(Debug)] +struct Edits { + /// The final output edits. + edits: Vec<(ProgPoint, Edit)>, + fixed_stack_slots: PRegSet, + /// The scratch registers being used in the instruction being + /// currently processed. + scratch_regs: PartedByRegClass>, + dedicated_scratch_regs: PartedByRegClass>, +} + +impl Edits { + fn new( + fixed_stack_slots: PRegSet, + num_insts: usize, + dedicated_scratch_regs: PartedByRegClass>, + ) -> Self { + // This guess is based on the sightglass benchmarks: + // The average number of edits per instruction is 1. + let edits_len_guess = num_insts; + Self { + edits: Vec::with_capacity(edits_len_guess), + fixed_stack_slots, + scratch_regs: dedicated_scratch_regs.clone(), + dedicated_scratch_regs, + } + } +} + +impl Edits { + fn is_stack(&self, alloc: Allocation) -> bool { + alloc.is_stack() + || (alloc.is_reg() && self.fixed_stack_slots.contains(alloc.as_reg().unwrap())) + } + + fn add_move( + &mut self, + inst: Inst, + from: Allocation, + to: Allocation, + class: RegClass, + pos: InstPosition, + ) { + trace!( + "Recording edit: {:?}", + (ProgPoint::new(inst, pos), Edit::Move { from, to }, class) + ); + if self.is_stack(from) && self.is_stack(to) { + trace!("Edit is stack-to-stack. Generating two edits with a scratch register"); + let scratch_reg = self.scratch_regs[class].unwrap(); + let scratch_alloc = Allocation::reg(scratch_reg); + trace!("Move 1: {scratch_alloc:?} to {to:?}"); + self.edits.push(( + ProgPoint::new(inst, pos), + Edit::Move { + from: scratch_alloc, + to, + }, + )); + trace!("Move 2: {from:?} to {scratch_alloc:?}"); + self.edits.push(( + ProgPoint::new(inst, pos), + Edit::Move { + from, + to: scratch_alloc, + }, + )); + } else { + self.edits + .push((ProgPoint::new(inst, pos), Edit::Move { from, to })); + } + } +} + +#[derive(Debug, Clone)] +struct PartedByOperandPos { + items: [T; 2], +} + +impl Index for PartedByOperandPos { + type Output = T; + fn index(&self, index: OperandPos) -> &Self::Output { + &self.items[index as usize] + } +} + +impl IndexMut for PartedByOperandPos { + fn index_mut(&mut self, index: OperandPos) -> &mut Self::Output { + &mut self.items[index as usize] + } +} + +use core::fmt; + +impl fmt::Display for PartedByOperandPos { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{{ early: {}, late: {} }}", self.items[0], self.items[1]) + } +} + +#[derive(Debug)] +pub struct Env<'a, F: Function> { + func: &'a F, + + /// The current allocations for all virtual registers. + vreg_allocs: Vec, + /// Spillslots for all virtual registers. + /// `vreg_spillslots[i]` is the spillslot for virtual register `i`. + vreg_spillslots: Vec, + /// The virtual registers that are currently live. + live_vregs: VRegSet, + /// Least-recently-used caches for register classes Int, Float, and Vector, respectively. + lrus: Lrus, + /// `vreg_in_preg[i]` is the virtual register currently in the physical register + /// with index `i`. + vreg_in_preg: Vec, + /// `reused_input_to_reuse_op[i]` is the operand index of the reuse operand + /// that uses the `i`th operand in the current instruction as its input. + reused_input_to_reuse_op: Vec, + /// The set of registers that can be used for allocation in the + /// early and late phases of an instruction. + /// Allocatable registers that contain no vregs, registers that can be + /// evicted can be in the set, and fixed stack slots are in this set. + available_pregs: PartedByOperandPos, + init_available_pregs: PRegSet, + allocatable_regs: PRegSet, + stack: Stack<'a, F>, + preferred_victim: PartedByRegClass, + vreg_to_live_inst_range: Vec<(ProgPoint, ProgPoint, Allocation)>, + + fixed_stack_slots: PRegSet, + + // Output. + allocs: Allocs, + edits: Edits, + stats: Stats, + debug_locations: Vec<(u32, ProgPoint, ProgPoint, Allocation)>, +} + +impl<'a, F: Function> Env<'a, F> { + fn new(func: &'a F, env: &'a MachineEnv) -> Self { + use alloc::vec; + let mut regs = [ + env.preferred_regs_by_class[RegClass::Int as usize].clone(), + env.preferred_regs_by_class[RegClass::Float as usize].clone(), + env.preferred_regs_by_class[RegClass::Vector as usize].clone(), + ]; + regs[0].extend( + env.non_preferred_regs_by_class[RegClass::Int as usize] + .iter() + .cloned(), + ); + regs[1].extend( + env.non_preferred_regs_by_class[RegClass::Float as usize] + .iter() + .cloned(), + ); + regs[2].extend( + env.non_preferred_regs_by_class[RegClass::Vector as usize] + .iter() + .cloned(), + ); + let allocatable_regs = PRegSet::from(env); + let init_available_pregs = { + let mut regs = allocatable_regs; + for preg in env.fixed_stack_slots.iter() { + regs.add(*preg); + } + regs + }; + let dedicated_scratch_regs = PartedByRegClass { + items: [ + env.scratch_by_class[0], + env.scratch_by_class[1], + env.scratch_by_class[2], + ], + }; + trace!("{:?}", env); + let (allocs, max_operand_len) = Allocs::new(func); + let fixed_stack_slots = PRegSet::from_iter(env.fixed_stack_slots.iter().cloned()); + Self { + func, + allocatable_regs, + vreg_allocs: vec![Allocation::none(); func.num_vregs()], + vreg_spillslots: vec![SpillSlot::invalid(); func.num_vregs()], + live_vregs: VRegSet::with_capacity(func.num_vregs()), + lrus: Lrus::new(®s[0], ®s[1], ®s[2]), + vreg_in_preg: vec![VReg::invalid(); PReg::NUM_INDEX], + stack: Stack::new(func), + fixed_stack_slots, + vreg_to_live_inst_range: vec![ + ( + ProgPoint::invalid(), + ProgPoint::invalid(), + Allocation::none() + ); + func.num_vregs() + ], + preferred_victim: PartedByRegClass { + items: [ + regs[0].last().cloned().unwrap_or(PReg::invalid()), + regs[1].last().cloned().unwrap_or(PReg::invalid()), + regs[2].last().cloned().unwrap_or(PReg::invalid()), + ], + }, + reused_input_to_reuse_op: vec![usize::MAX; max_operand_len as usize], + init_available_pregs, + available_pregs: PartedByOperandPos { + items: [init_available_pregs, init_available_pregs], + }, + allocs, + edits: Edits::new(fixed_stack_slots, func.num_insts(), dedicated_scratch_regs), + stats: Stats::default(), + debug_locations: Vec::with_capacity(func.debug_value_labels().len()), + } + } + + fn reset_available_pregs_and_scratch_regs(&mut self) { + trace!("Resetting the available pregs"); + self.available_pregs = PartedByOperandPos { + items: [self.init_available_pregs, self.init_available_pregs], + }; + self.edits.scratch_regs = self.edits.dedicated_scratch_regs.clone(); + } + + fn alloc_scratch_reg(&mut self, inst: Inst, class: RegClass) -> Result<(), RegAllocError> { + use OperandPos::{Early, Late}; + let reg = self.get_scratch_reg( + inst, + class, + self.available_pregs[Late] & self.available_pregs[Early], + )?; + self.edits.scratch_regs[class] = Some(reg); + self.available_pregs[OperandPos::Early].remove(reg); + self.available_pregs[OperandPos::Late].remove(reg); + Ok(()) + } + + fn get_scratch_reg_for_reload( + &mut self, + inst: Inst, + class: RegClass, + avail_regs: PRegSet, + ) -> Result { + let Some(preg) = self.lrus[class].last(avail_regs) else { + return Err(RegAllocError::TooManyLiveRegs); + }; + if self.vreg_in_preg[preg.index()] != VReg::invalid() { + self.evict_vreg_in_preg_before_inst(inst, preg); + } + Ok(preg) + } + + fn get_scratch_reg( + &mut self, + inst: Inst, + class: RegClass, + avail_regs: PRegSet, + ) -> Result { + let Some(preg) = self.lrus[class].last(avail_regs) else { + return Err(RegAllocError::TooManyLiveRegs); + }; + if self.vreg_in_preg[preg.index()] != VReg::invalid() { + self.evict_vreg_in_preg(inst, preg); + } + Ok(preg) + } + + fn reserve_reg_for_fixed_operand( + &mut self, + op: Operand, + op_idx: usize, + preg: PReg, + ) -> Result<(), RegAllocError> { + trace!("Reserving register {preg} for fixed operand {op}"); + let early_avail_pregs = self.available_pregs[OperandPos::Early]; + let late_avail_pregs = self.available_pregs[OperandPos::Late]; + match (op.pos(), op.kind()) { + (OperandPos::Early, OperandKind::Use) => { + if op.as_fixed_nonallocatable().is_none() && !early_avail_pregs.contains(preg) { + return Err(RegAllocError::TooManyLiveRegs); + } + self.available_pregs[OperandPos::Early].remove(preg); + if self.reused_input_to_reuse_op[op_idx] != usize::MAX { + if op.as_fixed_nonallocatable().is_none() && !late_avail_pregs.contains(preg) { + return Err(RegAllocError::TooManyLiveRegs); + } + self.available_pregs[OperandPos::Late].remove(preg); + } + } + (OperandPos::Late, OperandKind::Def) => { + if op.as_fixed_nonallocatable().is_none() && !late_avail_pregs.contains(preg) { + return Err(RegAllocError::TooManyLiveRegs); + } + self.available_pregs[OperandPos::Late].remove(preg); + } + _ => { + if op.as_fixed_nonallocatable().is_none() + && (!early_avail_pregs.contains(preg) || !late_avail_pregs.contains(preg)) + { + return Err(RegAllocError::TooManyLiveRegs); + } + self.available_pregs[OperandPos::Early].remove(preg); + self.available_pregs[OperandPos::Late].remove(preg); + } + } + Ok(()) + } + + fn allocd_within_constraint(&self, op: Operand) -> bool { + let alloc = self.vreg_allocs[op.vreg().vreg()]; + match op.constraint() { + OperandConstraint::Any => { + if let Some(preg) = alloc.as_reg() { + if !self.available_pregs[op.pos()].contains(preg) { + // If a register isn't in the available pregs list, then + // there are two cases: either it's reserved for a + // fixed register constraint or a vreg allocated in the instruction + // is already assigned to it. + // + // For example: + // 1. use v0, use v0, use v0 + // + // Say p0 is assigned to v0 during the processing of the first operand. + // When the second v0 operand is being processed, v0 will still be in + // v0, so it is still allocated within constraints. + trace!("The vreg in {preg}: {}", self.vreg_in_preg[preg.index()]); + self.vreg_in_preg[preg.index()] == op.vreg() + } else { + true + } + } else { + !alloc.is_none() + } + } + OperandConstraint::Reg => { + if self.edits.is_stack(alloc) { + return false; + } + if let Some(preg) = alloc.as_reg() { + if !self.available_pregs[op.pos()].contains(preg) { + trace!("The vreg in {preg}: {}", self.vreg_in_preg[preg.index()]); + self.vreg_in_preg[preg.index()] == op.vreg() + } else { + true + } + } else { + false + } + } + // It is possible for an operand to have a fixed register constraint to + // a clobber. + OperandConstraint::FixedReg(preg) => alloc.is_reg() && alloc.as_reg().unwrap() == preg, + OperandConstraint::Reuse(_) => { + unreachable!() + } + } + } + + fn base_evict_vreg_in_preg(&mut self, inst: Inst, preg: PReg, pos: InstPosition) { + trace!("Removing the vreg in preg {} for eviction", preg); + let evicted_vreg = self.vreg_in_preg[preg.index()]; + trace!("The removed vreg: {}", evicted_vreg); + debug_assert_ne!(evicted_vreg, VReg::invalid()); + if self.vreg_spillslots[evicted_vreg.vreg()].is_invalid() { + self.vreg_spillslots[evicted_vreg.vreg()] = self.stack.allocstack(evicted_vreg.class()); + } + let slot = self.vreg_spillslots[evicted_vreg.vreg()]; + self.vreg_allocs[evicted_vreg.vreg()] = Allocation::stack(slot); + trace!("Move reason: eviction"); + self.edits.add_move( + inst, + self.vreg_allocs[evicted_vreg.vreg()], + Allocation::reg(preg), + evicted_vreg.class(), + pos, + ); + } + + fn evict_vreg_in_preg_before_inst(&mut self, inst: Inst, preg: PReg) { + self.base_evict_vreg_in_preg(inst, preg, InstPosition::Before) + } + + fn evict_vreg_in_preg(&mut self, inst: Inst, preg: PReg) { + self.base_evict_vreg_in_preg(inst, preg, InstPosition::After) + } + + fn freealloc(&mut self, vreg: VReg) { + trace!("Freeing vreg {}", vreg); + let alloc = self.vreg_allocs[vreg.vreg()]; + match alloc.kind() { + AllocationKind::Reg => { + let preg = alloc.as_reg().unwrap(); + self.vreg_in_preg[preg.index()] = VReg::invalid(); + } + AllocationKind::Stack => (), + AllocationKind::None => unreachable!("Attempting to free an unallocated operand!"), + } + self.vreg_allocs[vreg.vreg()] = Allocation::none(); + self.live_vregs.remove(vreg.vreg()); + trace!( + "{} curr alloc is now {}", + vreg, + self.vreg_allocs[vreg.vreg()] + ); + } + + /// Allocates a physical register for the operand `op`. + fn alloc_reg_for_operand( + &mut self, + inst: Inst, + op: Operand, + ) -> Result { + trace!("available regs: {}", self.available_pregs); + trace!("Int LRU: {:?}", self.lrus[RegClass::Int]); + trace!("Float LRU: {:?}", self.lrus[RegClass::Float]); + trace!("Vector LRU: {:?}", self.lrus[RegClass::Vector]); + trace!(""); + let draw_from = match (op.pos(), op.kind()) { + (OperandPos::Late, OperandKind::Use) + | (OperandPos::Early, OperandKind::Def) + | (OperandPos::Late, OperandKind::Def) + if matches!(op.constraint(), OperandConstraint::Reuse(_)) => + { + self.available_pregs[OperandPos::Late] & self.available_pregs[OperandPos::Early] + } + _ => self.available_pregs[op.pos()], + }; + if draw_from.is_empty(op.class()) { + trace!("No registers available for {op}"); + return Err(RegAllocError::TooManyLiveRegs); + } + let Some(preg) = self.lrus[op.class()].last(draw_from) else { + trace!( + "Failed to find an available {:?} register in the LRU for operand {op}", + op.class() + ); + return Err(RegAllocError::TooManyLiveRegs); + }; + if self.vreg_in_preg[preg.index()] != VReg::invalid() { + self.evict_vreg_in_preg(inst, preg); + } + trace!("The allocated register for vreg {}: {}", op.vreg(), preg); + self.lrus[op.class()].poke(preg); + self.available_pregs[op.pos()].remove(preg); + match (op.pos(), op.kind()) { + (OperandPos::Late, OperandKind::Use) => { + self.available_pregs[OperandPos::Early].remove(preg); + } + (OperandPos::Early, OperandKind::Def) => { + self.available_pregs[OperandPos::Late].remove(preg); + } + (OperandPos::Late, OperandKind::Def) + if matches!(op.constraint(), OperandConstraint::Reuse(_)) => + { + self.available_pregs[OperandPos::Early].remove(preg); + } + _ => (), + }; + Ok(Allocation::reg(preg)) + } + + /// Allocates for the operand `op` with index `op_idx` into the + /// vector of instruction `inst`'s operands. + fn alloc_operand( + &mut self, + inst: Inst, + op: Operand, + op_idx: usize, + ) -> Result { + let new_alloc = match op.constraint() { + OperandConstraint::Any => self.alloc_reg_for_operand(inst, op)?, + OperandConstraint::Reg => self.alloc_reg_for_operand(inst, op)?, + OperandConstraint::FixedReg(preg) => { + trace!("The fixed preg: {} for operand {}", preg, op); + + Allocation::reg(preg) + } + OperandConstraint::Reuse(_) => { + // This is handled elsewhere. + unreachable!(); + } + }; + self.allocs[(inst.index(), op_idx)] = new_alloc; + Ok(new_alloc) + } + + /// Allocate operand the `op_idx`th operand `op` in instruction `inst` within its constraint. + /// Since only fixed register constraints are allowed, `fixed_spillslot` is used when a + /// fixed stack allocation is needed, like when transferring a stack allocation from a + /// reuse operand allocation to the reused input. + fn process_operand_allocation( + &mut self, + inst: Inst, + op: Operand, + op_idx: usize, + ) -> Result<(), RegAllocError> { + if let Some(preg) = op.as_fixed_nonallocatable() { + self.allocs[(inst.index(), op_idx)] = Allocation::reg(preg); + trace!( + "Allocation for instruction {:?} and operand {}: {}", + inst, + op, + self.allocs[(inst.index(), op_idx)] + ); + return Ok(()); + } + if !self.allocd_within_constraint(op) { + trace!("{op} isn't allocated within constraints."); + let curr_alloc = self.vreg_allocs[op.vreg().vreg()]; + let new_alloc = self.alloc_operand(inst, op, op_idx)?; + if curr_alloc.is_none() { + self.live_vregs.insert(op.vreg()); + self.vreg_to_live_inst_range[op.vreg().vreg()].1 = match (op.pos(), op.kind()) { + (OperandPos::Late, OperandKind::Use) | (_, OperandKind::Def) => { + // Live range ends just before the early phase of the + // next instruction. + ProgPoint::before(Inst::new(inst.index() + 1)) + } + (OperandPos::Early, OperandKind::Use) => { + // Live range ends just before the late phase of the current instruction. + ProgPoint::after(inst) + } + }; + self.vreg_to_live_inst_range[op.vreg().vreg()].2 = new_alloc; + + trace!("Setting vreg_allocs[{op}] to {new_alloc:?}"); + self.vreg_allocs[op.vreg().vreg()] = new_alloc; + if let Some(preg) = new_alloc.as_reg() { + self.vreg_in_preg[preg.index()] = op.vreg(); + } + } + // Need to insert a move to propagate flow from the current + // allocation to the subsequent places where the value was + // used (in `prev_alloc`, that is). + else { + trace!("Move reason: Prev allocation doesn't meet constraints"); + if self.edits.is_stack(new_alloc) + && self.edits.is_stack(curr_alloc) + && self.edits.scratch_regs[op.class()].is_none() + { + self.alloc_scratch_reg(inst, op.class())?; + } + if op.kind() == OperandKind::Def { + trace!("Adding edit from {new_alloc:?} to {curr_alloc:?} after inst {inst:?} for {op}"); + self.edits.add_move( + inst, + new_alloc, + curr_alloc, + op.class(), + InstPosition::After, + ); + // No need to set vreg_in_preg because it will be set during + // `freealloc` if needed. + } + // Edits for use operands are added later to avoid inserting + // edits out of order. + + if let Some(preg) = new_alloc.as_reg() { + // Don't change the allocation. + self.vreg_in_preg[preg.index()] = VReg::invalid(); + } + } + trace!( + "Allocation for instruction {:?} and operand {}: {}", + inst, + op, + self.allocs[(inst.index(), op_idx)] + ); + } else { + trace!("{op} is already allocated within constraints"); + self.allocs[(inst.index(), op_idx)] = self.vreg_allocs[op.vreg().vreg()]; + if let Some(preg) = self.allocs[(inst.index(), op_idx)].as_reg() { + if self.allocatable_regs.contains(preg) { + self.lrus[preg.class()].poke(preg); + } + self.available_pregs[op.pos()].remove(preg); + match (op.pos(), op.kind()) { + (OperandPos::Late, OperandKind::Use) => { + self.available_pregs[OperandPos::Early].remove(preg); + } + (OperandPos::Early, OperandKind::Def) => { + self.available_pregs[OperandPos::Late].remove(preg); + } + _ => (), + }; + } + trace!( + "Allocation for instruction {:?} and operand {}: {}", + inst, + op, + self.allocs[(inst.index(), op_idx)] + ); + } + trace!( + "Late available regs: {}", + self.available_pregs[OperandPos::Late] + ); + trace!( + "Early available regs: {}", + self.available_pregs[OperandPos::Early] + ); + Ok(()) + } + + fn remove_clobbers_from_available_pregs(&mut self, clobbers: PRegSet) { + trace!("Removing clobbers {clobbers} from available reg sets"); + // Don't let defs get allocated to clobbers. + // Consider a scenario: + // + // 1. (early|late) def v0 (reg). Clobbers: [p0] + // 2. use v0 (fixed: p0) + // + // If p0 isn't removed from the both available reg sets, then + // p0 could get allocated to v0 in inst 1, making it impossible + // to restore it after the instruction. + // To avoid this scenario, clobbers should be removed from both late + // and early reg sets. + let all_but_clobbers = clobbers.invert(); + self.available_pregs[OperandPos::Late].intersect_from(all_but_clobbers); + self.available_pregs[OperandPos::Early].intersect_from(all_but_clobbers); + } + + /// If instruction `inst` is a branch in `block`, + /// this function places branch arguments in the spillslots + /// expected by the destination blocks. + fn process_branch(&mut self, block: Block, inst: Inst) -> Result<(), RegAllocError> { + use OperandPos::*; + trace!("Processing branch instruction {inst:?} in block {block:?}"); + + let mut int_parallel_moves = ParallelMoves::new(); + let mut float_parallel_moves = ParallelMoves::new(); + let mut vec_parallel_moves = ParallelMoves::new(); + + for (succ_idx, succ) in self.func.block_succs(block).iter().enumerate() { + for (pos, vreg) in self + .func + .branch_blockparams(block, inst, succ_idx) + .iter() + .enumerate() + { + let succ_params = self.func.block_params(*succ); + let succ_param_vreg = succ_params[pos]; + if self.vreg_spillslots[succ_param_vreg.vreg()].is_invalid() { + self.vreg_spillslots[succ_param_vreg.vreg()] = + self.stack.allocstack(succ_param_vreg.class()); + } + if self.vreg_spillslots[vreg.vreg()].is_invalid() { + self.vreg_spillslots[vreg.vreg()] = self.stack.allocstack(vreg.class()); + } + let vreg_spill = Allocation::stack(self.vreg_spillslots[vreg.vreg()]); + let curr_alloc = self.vreg_allocs[vreg.vreg()]; + if curr_alloc.is_none() { + self.live_vregs.insert(*vreg); + self.vreg_to_live_inst_range[vreg.vreg()].1 = ProgPoint::before(inst); + } else if curr_alloc != vreg_spill { + if self.edits.is_stack(curr_alloc) + && self.edits.scratch_regs[vreg.class()].is_none() + { + let reg = self.get_scratch_reg_for_reload( + inst, + vreg.class(), + self.available_pregs[Early] & self.available_pregs[Late], + )?; + self.edits.scratch_regs[vreg.class()] = Some(reg); + self.available_pregs[OperandPos::Early].remove(reg); + self.available_pregs[OperandPos::Late].remove(reg); + } + self.edits.add_move( + inst, + vreg_spill, + curr_alloc, + vreg.class(), + InstPosition::Before, + ); + } + self.vreg_allocs[vreg.vreg()] = vreg_spill; + let parallel_moves = match vreg.class() { + RegClass::Int => &mut int_parallel_moves, + RegClass::Float => &mut float_parallel_moves, + RegClass::Vector => &mut vec_parallel_moves, + }; + let from = Allocation::stack(self.vreg_spillslots[vreg.vreg()]); + let to = Allocation::stack(self.vreg_spillslots[succ_param_vreg.vreg()]); + trace!("Recording parallel move from {from} to {to}"); + parallel_moves.add(from, to, Some(*vreg)); + } + } + + let resolved_int = int_parallel_moves.resolve(); + let resolved_float = float_parallel_moves.resolve(); + let resolved_vec = vec_parallel_moves.resolve(); + let mut scratch_regs = self.edits.scratch_regs.clone(); + let mut num_spillslots = self.stack.num_spillslots; + let mut avail_regs = self.available_pregs[Early] & self.available_pregs[Late]; + + trace!("Resolving parallel moves"); + for (resolved, class) in [ + (resolved_int, RegClass::Int), + (resolved_float, RegClass::Float), + (resolved_vec, RegClass::Vector), + ] { + let scratch_resolver = MoveAndScratchResolver { + find_free_reg: || { + if let Some(reg) = scratch_regs[class] { + trace!("Retrieved reg {reg} for scratch resolver"); + scratch_regs[class] = None; + Some(Allocation::reg(reg)) + } else { + let Some(preg) = self.lrus[class].last(avail_regs) else { + trace!("Couldn't find any reg for scratch resolver"); + return None; + }; + avail_regs.remove(preg); + trace!("Retrieved reg {preg} for scratch resolver"); + Some(Allocation::reg(preg)) + } + }, + get_stackslot: || { + let size: u32 = self.func.spillslot_size(class).try_into().unwrap(); + let mut offset = num_spillslots; + debug_assert!(size.is_power_of_two()); + offset = (offset + size - 1) & !(size - 1); + let slot = if self.func.multi_spillslot_named_by_last_slot() { + offset + size - 1 + } else { + offset + }; + offset += size; + num_spillslots = offset; + trace!("Retrieved slot {slot} for scratch resolver"); + Allocation::stack(SpillSlot::new(slot as usize)) + }, + is_stack_alloc: |alloc| self.edits.is_stack(alloc), + borrowed_scratch_reg: self.preferred_victim[class], + }; + let moves = scratch_resolver.compute(resolved); + trace!("Resolved {class:?} parallel moves"); + for (from, to, _) in moves.into_iter().rev() { + self.edits + .edits + .push((ProgPoint::before(inst), Edit::Move { from, to })) + } + self.stack.num_spillslots = num_spillslots; + } + trace!("Completed processing branch"); + Ok(()) + } + + fn alloc_inst(&mut self, block: Block, inst: Inst) -> Result<(), RegAllocError> { + trace!("Allocating instruction {:?}", inst); + self.reset_available_pregs_and_scratch_regs(); + let operands = Operands::new(self.func.inst_operands(inst)); + let clobbers = self.func.inst_clobbers(inst); + + for (op_idx, op) in operands.reuse() { + trace!("Initializing reused_input_to_reuse_op for {op}"); + let OperandConstraint::Reuse(reused_idx) = op.constraint() else { + unreachable!() + }; + self.reused_input_to_reuse_op[reused_idx] = op_idx; + } + for (op_idx, op) in operands.fixed() { + let OperandConstraint::FixedReg(preg) = op.constraint() else { + unreachable!(); + }; + self.reserve_reg_for_fixed_operand(op, op_idx, preg)?; + if self.allocatable_regs.contains(preg) { + self.lrus[preg.class()].poke(preg); + } + } + for (_, op) in operands.fixed() { + let OperandConstraint::FixedReg(preg) = op.constraint() else { + unreachable!(); + }; + // Eviction has to be done separately to avoid using a fixed register + // as a scratch register. + if self.vreg_in_preg[preg.index()] != VReg::invalid() + && self.vreg_in_preg[preg.index()] != op.vreg() + { + trace!( + "Evicting {} from fixed register {preg}", + self.vreg_in_preg[preg.index()] + ); + if self.fixed_stack_slots.contains(preg) + && self.edits.scratch_regs[preg.class()].is_none() + { + self.alloc_scratch_reg(inst, preg.class())?; + } + self.evict_vreg_in_preg(inst, preg); + self.vreg_in_preg[preg.index()] = VReg::invalid(); + } + } + self.remove_clobbers_from_available_pregs(clobbers); + for preg in clobbers { + if self.vreg_in_preg[preg.index()] != VReg::invalid() { + trace!( + "Evicting {} from clobber {preg}", + self.vreg_in_preg[preg.index()] + ); + if self.fixed_stack_slots.contains(preg) + && self.edits.scratch_regs[preg.class()].is_none() + { + self.alloc_scratch_reg(inst, preg.class())?; + } + self.evict_vreg_in_preg(inst, preg); + self.vreg_in_preg[preg.index()] = VReg::invalid(); + } + } + for (op_idx, op) in operands.def_ops() { + trace!("Allocating def operands {op}"); + if let OperandConstraint::Reuse(reused_idx) = op.constraint() { + let reused_op = operands[reused_idx]; + let new_reuse_op = + Operand::new(op.vreg(), reused_op.constraint(), op.kind(), op.pos()); + trace!("allocating reuse op {op} as {new_reuse_op}"); + self.process_operand_allocation(inst, new_reuse_op, op_idx)?; + } else { + self.process_operand_allocation(inst, op, op_idx)?; + } + let slot = self.vreg_spillslots[op.vreg().vreg()]; + if slot.is_valid() { + self.vreg_to_live_inst_range[op.vreg().vreg()].2 = Allocation::stack(slot); + let curr_alloc = self.vreg_allocs[op.vreg().vreg()]; + let vreg_slot = self.vreg_spillslots[op.vreg().vreg()]; + let (is_stack_to_stack, src_and_dest_are_same) = + if let Some(curr_alloc) = curr_alloc.as_stack() { + (true, curr_alloc == vreg_slot) + } else { + (self.edits.is_stack(curr_alloc), false) + }; + if !src_and_dest_are_same { + if is_stack_to_stack && self.edits.scratch_regs[op.class()].is_none() { + self.alloc_scratch_reg(inst, op.class())?; + }; + self.edits.add_move( + inst, + self.vreg_allocs[op.vreg().vreg()], + Allocation::stack(self.vreg_spillslots[op.vreg().vreg()]), + op.class(), + InstPosition::After, + ); + } + } + self.vreg_to_live_inst_range[op.vreg().vreg()].0 = ProgPoint::after(inst); + self.freealloc(op.vreg()); + } + for (op_idx, op) in operands.use_ops() { + trace!("Allocating use operand {op}"); + if self.reused_input_to_reuse_op[op_idx] != usize::MAX { + let reuse_op_idx = self.reused_input_to_reuse_op[op_idx]; + let reuse_op_alloc = self.allocs[(inst.index(), reuse_op_idx)]; + let Some(preg) = reuse_op_alloc.as_reg() else { + unreachable!(); + }; + let new_reused_input_constraint = OperandConstraint::FixedReg(preg); + let new_reused_input = + Operand::new(op.vreg(), new_reused_input_constraint, op.kind(), op.pos()); + trace!("Allocating reused input {op} as {new_reused_input}"); + self.process_operand_allocation(inst, new_reused_input, op_idx)?; + } else { + self.process_operand_allocation(inst, op, op_idx)?; + } + } + for (op_idx, op) in operands.use_ops() { + if op.as_fixed_nonallocatable().is_some() { + continue; + } + if self.vreg_allocs[op.vreg().vreg()] != self.allocs[(inst.index(), op_idx)] { + let curr_alloc = self.vreg_allocs[op.vreg().vreg()]; + let new_alloc = self.allocs[(inst.index(), op_idx)]; + trace!("Adding edit from {curr_alloc:?} to {new_alloc:?} before inst {inst:?} for {op}"); + self.edits.add_move( + inst, + curr_alloc, + new_alloc, + op.class(), + InstPosition::Before, + ); + } + } + if self.func.is_branch(inst) { + self.process_branch(block, inst)?; + } + for entry in self.reused_input_to_reuse_op.iter_mut() { + *entry = usize::MAX; + } + if trace_enabled!() { + self.log_post_inst_processing_state(inst); + } + Ok(()) + } + + /// At the beginning of every block, all virtual registers that are + /// livein are expected to be in their respective spillslots. + /// This function sets the current allocations of livein registers + /// to their spillslots and inserts the edits to flow livein values to + /// the allocations where they are expected to be before the first + /// instruction. + fn reload_at_begin(&mut self, block: Block) -> Result<(), RegAllocError> { + trace!( + "Reloading live registers at the beginning of block {:?}", + block + ); + trace!( + "Live registers at the beginning of block {:?}: {:?}", + block, + self.live_vregs + ); + trace!( + "Block params at block {:?} beginning: {:?}", + block, + self.func.block_params(block) + ); + trace!( + "Available pregs: {}", + self.available_pregs[OperandPos::Early] + ); + self.reset_available_pregs_and_scratch_regs(); + let avail_regs_for_scratch = self.available_pregs[OperandPos::Early]; + let first_inst = self.func.block_insns(block).first(); + // We need to check for the registers that are still live. + // These registers are either livein or block params + // Liveins should be stack-allocated and block params should be freed. + for vreg in self.func.block_params(block).iter().cloned() { + trace!("Processing {}", vreg); + if self.vreg_allocs[vreg.vreg()] == Allocation::none() { + // If this block param was never used, its allocation will + // be none at this point. + continue; + } + if self.vreg_spillslots[vreg.vreg()].is_invalid() { + self.vreg_spillslots[vreg.vreg()] = self.stack.allocstack(vreg.class()); + } + // The allocation where the vreg is expected to be before + // the first instruction. + let prev_alloc = self.vreg_allocs[vreg.vreg()]; + let slot = Allocation::stack(self.vreg_spillslots[vreg.vreg()]); + self.vreg_to_live_inst_range[vreg.vreg()].2 = slot; + self.vreg_to_live_inst_range[vreg.vreg()].0 = ProgPoint::before(first_inst); + trace!("{} is a block param. Freeing it", vreg); + // A block's block param is not live before the block. + // And `vreg_allocs[i]` of a virtual register i is none for + // dead vregs. + self.freealloc(vreg); + if slot == prev_alloc { + // No need to do any movements if the spillslot is where the vreg is expected to be. + trace!( + "No need to reload {} because it's already in its expected allocation", + vreg + ); + continue; + } + trace!( + "Move reason: reload {} at begin - move from its spillslot", + vreg + ); + if self.edits.is_stack(prev_alloc) && self.edits.scratch_regs[vreg.class()].is_none() { + let reg = self.get_scratch_reg_for_reload( + first_inst, + vreg.class(), + avail_regs_for_scratch, + )?; + self.edits.scratch_regs[vreg.class()] = Some(reg); + } + self.edits.add_move( + self.func.block_insns(block).first(), + slot, + prev_alloc, + vreg.class(), + InstPosition::Before, + ); + } + for vreg in self.live_vregs.iter() { + trace!("Processing {}", vreg); + trace!( + "{} is not a block param. It's a liveout vreg from some predecessor", + vreg + ); + if self.vreg_spillslots[vreg.vreg()].is_invalid() { + self.vreg_spillslots[vreg.vreg()] = self.stack.allocstack(vreg.class()); + } + // The allocation where the vreg is expected to be before + // the first instruction. + let prev_alloc = self.vreg_allocs[vreg.vreg()]; + let slot = Allocation::stack(self.vreg_spillslots[vreg.vreg()]); + trace!("Setting {}'s current allocation to its spillslot", vreg); + self.vreg_allocs[vreg.vreg()] = slot; + if let Some(preg) = prev_alloc.as_reg() { + trace!("{} was in {}. Removing it", preg, vreg); + // Nothing is in that preg anymore. + self.vreg_in_preg[preg.index()] = VReg::invalid(); + } + if slot == prev_alloc { + // No need to do any movements if the spillslot is where the vreg is expected to be. + trace!( + "No need to reload {} because it's already in its expected allocation", + vreg + ); + continue; + } + trace!( + "Move reason: reload {} at begin - move from its spillslot", + vreg + ); + if self.edits.is_stack(prev_alloc) && self.edits.scratch_regs[vreg.class()].is_none() { + let Some(preg) = self.lrus[vreg.class()].last(avail_regs_for_scratch) else { + return Err(RegAllocError::TooManyLiveRegs); + }; + if self.vreg_in_preg[preg.index()] != VReg::invalid() { + // Had to put `evict_reg_in_preg_before_inst` here because of borrow checker rules. + trace!("Removing the vreg in preg {} for eviction", preg); + let evicted_vreg = self.vreg_in_preg[preg.index()]; + trace!("The removed vreg: {}", evicted_vreg); + debug_assert_ne!(evicted_vreg, VReg::invalid()); + if self.vreg_spillslots[evicted_vreg.vreg()].is_invalid() { + self.vreg_spillslots[evicted_vreg.vreg()] = + self.stack.allocstack(evicted_vreg.class()); + } + let slot = self.vreg_spillslots[evicted_vreg.vreg()]; + self.vreg_allocs[evicted_vreg.vreg()] = Allocation::stack(slot); + trace!("Move reason: eviction"); + self.edits.add_move( + first_inst, + self.vreg_allocs[evicted_vreg.vreg()], + Allocation::reg(preg), + evicted_vreg.class(), + InstPosition::Before, + ); + } + self.edits.scratch_regs[vreg.class()] = Some(preg); + } + self.edits.add_move( + first_inst, + slot, + prev_alloc, + vreg.class(), + InstPosition::Before, + ); + } + if trace_enabled!() { + self.log_post_reload_at_begin_state(block); + } + Ok(()) + } + + fn log_post_reload_at_begin_state(&self, block: Block) { + use alloc::format; + trace!(""); + trace!("State after instruction reload_at_begin of {:?}", block); + let mut map = FxHashMap::default(); + for (vreg_idx, alloc) in self.vreg_allocs.iter().enumerate() { + if *alloc != Allocation::none() { + map.insert(format!("vreg{vreg_idx}"), alloc); + } + } + trace!("vreg_allocs: {:?}", map); + let mut map = FxHashMap::default(); + for i in 0..self.vreg_in_preg.len() { + if self.vreg_in_preg[i] != VReg::invalid() { + map.insert(PReg::from_index(i), self.vreg_in_preg[i]); + } + } + trace!("vreg_in_preg: {:?}", map); + trace!("Int LRU: {:?}", self.lrus[RegClass::Int]); + trace!("Float LRU: {:?}", self.lrus[RegClass::Float]); + trace!("Vector LRU: {:?}", self.lrus[RegClass::Vector]); + } + + fn log_post_inst_processing_state(&self, inst: Inst) { + use alloc::format; + trace!(""); + trace!("State after instruction {:?}", inst); + let mut map = FxHashMap::default(); + for (vreg_idx, alloc) in self.vreg_allocs.iter().enumerate() { + if *alloc != Allocation::none() { + map.insert(format!("vreg{vreg_idx}"), alloc); + } + } + trace!("vreg_allocs: {:?}", map); + let mut v = Vec::new(); + for i in 0..self.vreg_in_preg.len() { + if self.vreg_in_preg[i] != VReg::invalid() { + v.push(format!( + "{}: {}, ", + PReg::from_index(i), + self.vreg_in_preg[i] + )); + } + } + trace!("vreg_in_preg: {:?}", v); + trace!("Int LRU: {:?}", self.lrus[RegClass::Int]); + trace!("Float LRU: {:?}", self.lrus[RegClass::Float]); + trace!("Vector LRU: {:?}", self.lrus[RegClass::Vector]); + trace!(""); + } + + fn alloc_block(&mut self, block: Block) -> Result<(), RegAllocError> { + trace!("{:?} start", block); + for inst in self.func.block_insns(block).iter().rev() { + self.alloc_inst(block, inst)?; + } + self.reload_at_begin(block)?; + trace!("{:?} end\n", block); + Ok(()) + } + + fn build_debug_info(&mut self) { + trace!("Building debug location info"); + for &(vreg, start, end, label) in self.func.debug_value_labels() { + let (point_start, point_end, alloc) = self.vreg_to_live_inst_range[vreg.vreg()]; + if point_start.inst() <= start && end <= point_end.inst().next() { + self.debug_locations + .push((label, point_start, point_end, alloc)); + } + } + self.debug_locations.sort_by_key(|loc| loc.0); + } + + fn run(&mut self) -> Result<(), RegAllocError> { + debug_assert_eq!(self.func.entry_block().index(), 0); + for block in (0..self.func.num_blocks()).rev() { + self.alloc_block(Block::new(block))?; + } + self.edits.edits.reverse(); + self.build_debug_info(); + // Ought to check if there are livein registers + // then throw an error, but will that be expensive? + Ok(()) + } +} + +fn log_function(func: &F) { + trace!("Processing a new function"); + for block in 0..func.num_blocks() { + let block = Block::new(block); + trace!( + "Block {:?}. preds: {:?}. succs: {:?}, params: {:?}", + block, + func.block_preds(block), + func.block_succs(block), + func.block_params(block) + ); + for inst in func.block_insns(block).iter() { + let clobbers = func.inst_clobbers(inst); + trace!( + "inst{:?}: {:?}. Clobbers: {}", + inst.index(), + func.inst_operands(inst), + clobbers + ); + if func.is_branch(inst) { + trace!("Block args: "); + for (succ_idx, _succ) in func.block_succs(block).iter().enumerate() { + trace!(" {:?}", func.branch_blockparams(block, inst, succ_idx)); + } + } + } + trace!(""); + } +} + +fn log_output<'a, F: Function>(env: &Env<'a, F>) { + trace!("Done!"); + use alloc::format; + let mut v = Vec::new(); + for i in 0..env.func.num_vregs() { + if env.vreg_spillslots[i].is_valid() { + v.push(( + format!("{}", VReg::new(i, RegClass::Int)), + format!("{}", Allocation::stack(env.vreg_spillslots[i])), + )); + } + } + trace!("VReg spillslots: {:?}", v); + trace!("Final edits: {:?}", env.edits.edits); +} + +pub fn run( + func: &F, + mach_env: &MachineEnv, + verbose_log: bool, + enable_ssa_checker: bool, +) -> Result { + if enable_ssa_checker { + validate_ssa(func, &CFGInfo::new(func)?)?; + } + + if trace_enabled!() || verbose_log { + log_function(func); + } + + let mut env = Env::new(func, mach_env); + env.run()?; + + if trace_enabled!() || verbose_log { + log_output(&env); + } + + Ok(Output { + edits: env.edits.edits, + allocs: env.allocs.allocs, + inst_alloc_offsets: env.allocs.inst_alloc_offsets, + num_spillslots: env.stack.num_spillslots as usize, + debug_locations: env.debug_locations, + stats: env.stats, + }) +} diff --git a/deps/crates/vendor/regalloc2/src/fastalloc/tests.rs b/deps/crates/vendor/regalloc2/src/fastalloc/tests.rs new file mode 100644 index 00000000000000..41be37719f04a3 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fastalloc/tests.rs @@ -0,0 +1,315 @@ +use crate::OperandConstraint::{self, *}; +use crate::OperandKind::{self, *}; +use crate::{ + run, Algorithm, Allocation, Block, Function, Inst, InstRange, MachineEnv, Operand, OperandPos, + PReg, PRegSet, ProgPoint, RegClass, RegallocOptions, VReg, +}; +use alloc::vec; +use alloc::vec::Vec; + +#[test] +fn test_debug_locations1() { + let mach_env = mach_env(10); + let mut options = RegallocOptions::default(); + options.validate_ssa = true; + options.algorithm = Algorithm::Fastalloc; + let mut f = RealFunction::new(vec![BlockBuildInfo { + insts: vec![ + /* 0. */ vec![op(Def, 0, FixedReg(p(0)))], + /* 1. */ + vec![ + op(Def, 1, FixedReg(p(0))), + op(Use, 0, FixedReg(p(0))), + op(Use, 0, Reg), + ], + /* 2. */ + vec![ + op(Def, 2, FixedReg(p(8))), + op(Use, 0, FixedReg(p(2))), + op(Use, 1, FixedReg(p(0))), + ], + /* 3. */ vec![op(Def, 3, FixedReg(p(9))), op(Use, 0, FixedReg(p(9)))], + ], + }]); + f.debug_value_labels = vec![ + (v(0), i(0), i(4), 32), + (v(2), i(2), i(4), 70), + (v(2), i(2), i(4), 71), + (v(3), i(3), i(4), 34), + ]; + let result = run(&f, &mach_env, &options).unwrap(); + assert_eq!( + result.debug_locations, + vec![ + ( + 32, + ProgPoint::after(i(0)), + ProgPoint::after(i(3)), + alloc(p(9)) + ), + ( + 34, + ProgPoint::after(i(3)), + ProgPoint::before(i(4)), + alloc(p(9)) + ), + ( + 70, + ProgPoint::after(i(2)), + ProgPoint::before(i(3)), + alloc(p(8)) + ), + ( + 71, + ProgPoint::after(i(2)), + ProgPoint::before(i(3)), + alloc(p(8)) + ), + ] + ); +} + +#[test] +fn test_debug_locations2() { + let mach_env = mach_env(2); + let mut options = RegallocOptions::default(); + options.validate_ssa = true; + options.algorithm = Algorithm::Fastalloc; + let mut f = RealFunction::new(vec![BlockBuildInfo { + insts: vec![ + /* 0. */ vec![op(Def, 2, FixedReg(p(0)))], + /* 1. */ vec![op(Def, 0, FixedReg(p(0)))], + /* 2. */ vec![op(Def, 1, FixedReg(p(1)))], + /* 3. */ vec![op(Use, 0, FixedReg(p(0))), op(Use, 0, FixedReg(p(1)))], + /* 4. */ vec![op(Use, 1, FixedReg(p(1)))], + ], + }]); + f.debug_value_labels = vec![ + (v(0), i(1), i(4), 10), + (v(1), i(0), i(1), 11), + (v(1), i(2), i(3), 23), + ]; + let result = run(&f, &mach_env, &options).unwrap(); + assert_eq!(result.debug_locations.len(), 2); + assert_eq!( + result.debug_locations[0], + ( + 10, + ProgPoint::after(i(1)), + ProgPoint::after(i(3)), + alloc(p(0)) + ) + ); + assert_eq!(result.debug_locations[1].0, 23); + assert_eq!(result.debug_locations[1].1, ProgPoint::after(i(2))); + assert_eq!(result.debug_locations[1].2, ProgPoint::after(i(4))); + assert!(matches!(result.debug_locations[1].3.as_stack(), Some(_))); +} + +impl RealFunction { + fn new(blocks: Vec) -> Self { + assert!(blocks.len() <= 2, "Just for testing purposes"); + let mut f = Self::default(); + let mut max_vreg_num_seen = 0; + for block in blocks.iter() { + f.blocks.push(RealBlock { + params: vec![], + preds: vec![], + succs: vec![], + }); + let start_inst_idx = f.insts.len(); + for inst in block.insts.iter() { + f.insts.push(RealInst { + inst: Inst::new(f.insts.len()), + kind: RealInstKind::Normal, + }); + let start_op_idx = f.operands.len(); + for op in inst.iter() { + max_vreg_num_seen = max_vreg_num_seen.max(op.vreg().vreg()); + f.operands.push(*op); + } + f.operand_ranges.push((start_op_idx, f.operands.len())); + } + if !block.insts.is_empty() { + f.insts.last_mut().unwrap().kind = RealInstKind::Ret; + } + f.inst_ranges.push((start_inst_idx, f.insts.len())); + } + f.num_vregs = max_vreg_num_seen + 1; + f + } +} + +fn mach_env(no_of_regs: usize) -> MachineEnv { + MachineEnv { + preferred_regs_by_class: [ + (0..no_of_regs) + .map(|no| PReg::new(no, RegClass::Int)) + .collect(), + vec![], + vec![], + ], + non_preferred_regs_by_class: [vec![], vec![], vec![]], + scratch_by_class: [None, None, None], + fixed_stack_slots: vec![], + } +} + +fn op(kind: OperandKind, vreg_num: usize, constraint: OperandConstraint) -> Operand { + Operand::new( + VReg::new(vreg_num, RegClass::Int), + constraint, + kind, + match kind { + Use => OperandPos::Early, + Def => OperandPos::Late, + }, + ) +} + +fn alloc(preg: PReg) -> Allocation { + Allocation::reg(preg) +} + +fn v(vreg_num: usize) -> VReg { + VReg::new(vreg_num, RegClass::Int) +} + +fn i(inst: usize) -> Inst { + Inst::new(inst) +} + +fn p(hw_enc: usize) -> PReg { + PReg::new(hw_enc, RegClass::Int) +} + +struct BlockBuildInfo { + insts: Vec>, +} + +#[derive(Default)] +struct RealFunction { + blocks: Vec, + insts: Vec, + operands: Vec, + operand_ranges: Vec<(usize, usize)>, + inst_ranges: Vec<(usize, usize)>, + num_vregs: usize, + debug_value_labels: Vec<(VReg, Inst, Inst, u32)>, +} + +struct RealBlock { + params: Vec, + preds: Vec, + succs: Vec, +} + +struct RealInst { + inst: Inst, + kind: RealInstKind, +} + +impl RealInst { + fn is_branch(&self) -> bool { + match self.kind { + RealInstKind::Branch(_, _) => true, + _ => false, + } + } + + fn is_ret(&self) -> bool { + match self.kind { + RealInstKind::Ret => true, + _ => false, + } + } +} + +enum RealInstKind { + Normal, + Branch(Block, Vec), + Ret, +} + +impl Function for RealFunction { + fn num_insts(&self) -> usize { + self.insts.len() + } + + fn num_blocks(&self) -> usize { + self.blocks.len() + } + + fn block_insns(&self, block: crate::Block) -> crate::InstRange { + let (start, end) = self.inst_ranges[block.index()]; + if start != end { + InstRange::new( + self.insts[start].inst, + Inst::new(self.insts[end - 1].inst.index() + 1), + ) + } else { + InstRange::new(Inst::new(0), Inst::new(0)) + } + } + + fn allow_multiple_vreg_defs(&self) -> bool { + false + } + + fn block_params(&self, block: crate::Block) -> &[VReg] { + &self.blocks[block.index()].params + } + + fn block_preds(&self, block: crate::Block) -> &[crate::Block] { + &self.blocks[block.index()].preds + } + + fn block_succs(&self, block: Block) -> &[Block] { + &self.blocks[block.index()].succs + } + + fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] { + &self.debug_value_labels + } + + fn entry_block(&self) -> Block { + Block::new(0) + } + + fn inst_clobbers(&self, _insn: Inst) -> crate::PRegSet { + PRegSet::empty() + } + + fn inst_operands(&self, insn: Inst) -> &[Operand] { + let (start, end) = self.operand_ranges[insn.index()]; + &self.operands[start..end] + } + + fn is_branch(&self, insn: Inst) -> bool { + self.insts[insn.index()].is_branch() + } + + fn is_ret(&self, insn: Inst) -> bool { + self.insts[insn.index()].is_ret() + } + + fn multi_spillslot_named_by_last_slot(&self) -> bool { + false + } + + fn num_vregs(&self) -> usize { + self.num_vregs + } + + fn spillslot_size(&self, regclass: crate::RegClass) -> usize { + match regclass { + RegClass::Int => 2, + RegClass::Float => 4, + RegClass::Vector => 8, + } + } + + fn branch_blockparams(&self, _block: Block, _insn: Inst, _succ_idx: usize) -> &[VReg] { + &[] + } +} diff --git a/deps/crates/vendor/regalloc2/src/fastalloc/vregset.rs b/deps/crates/vendor/regalloc2/src/fastalloc/vregset.rs new file mode 100644 index 00000000000000..77287dccf5a8d2 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fastalloc/vregset.rs @@ -0,0 +1,143 @@ +use core::fmt; + +use crate::ion::data_structures::VRegIndex; +use crate::VReg; +use alloc::vec; +use alloc::vec::Vec; + +#[derive(Clone)] +struct VRegNode { + next: VRegIndex, + prev: VRegIndex, + vreg: VReg, +} + +// Using a doubly linked list here for fast insertion, +// removal and iteration. +pub struct VRegSet { + items: Vec, + head: VRegIndex, +} + +impl VRegSet { + pub fn with_capacity(num_vregs: usize) -> Self { + Self { + items: vec![ + VRegNode { + prev: VRegIndex::new(num_vregs), + next: VRegIndex::new(num_vregs), + vreg: VReg::invalid() + }; + num_vregs + 1 + ], + head: VRegIndex::new(num_vregs), + } + } + + pub fn insert(&mut self, vreg: VReg) { + debug_assert_eq!(self.items[vreg.vreg()].vreg, VReg::invalid()); + let old_head_next = self.items[self.head.index()].next; + self.items[vreg.vreg()] = VRegNode { + next: old_head_next, + prev: self.head, + vreg, + }; + self.items[self.head.index()].next = VRegIndex::new(vreg.vreg()); + self.items[old_head_next.index()].prev = VRegIndex::new(vreg.vreg()); + } + + pub fn remove(&mut self, vreg_num: usize) { + let prev = self.items[vreg_num].prev; + let next = self.items[vreg_num].next; + self.items[prev.index()].next = next; + self.items[next.index()].prev = prev; + self.items[vreg_num].vreg = VReg::invalid(); + } + + pub fn is_empty(&self) -> bool { + self.items[self.head.index()].next == self.head + } + + pub fn iter(&self) -> VRegSetIter { + VRegSetIter { + curr_item: self.items[self.head.index()].next, + head: self.head, + items: &self.items, + } + } +} + +pub struct VRegSetIter<'a> { + curr_item: VRegIndex, + head: VRegIndex, + items: &'a [VRegNode], +} + +impl<'a> Iterator for VRegSetIter<'a> { + type Item = VReg; + + fn next(&mut self) -> Option { + if self.curr_item != self.head { + let item = self.items[self.curr_item.index()].clone(); + self.curr_item = item.next; + Some(item.vreg) + } else { + None + } + } +} + +impl fmt::Debug for VRegSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{{ ")?; + for vreg in self.iter() { + write!(f, "{vreg} ")?; + } + write!(f, "}}") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::RegClass; + use RegClass::*; + const VREG: fn(usize, RegClass) -> VReg = VReg::new; + + #[test] + fn operations() { + let mut set = VRegSet::with_capacity(3090); + assert!(set.is_empty()); + set.insert(VREG(10, Int)); + set.insert(VREG(2000, Int)); + set.insert(VREG(11, Vector)); + set.insert(VREG(199, Float)); + set.insert(VREG(23, Int)); + let mut iter = set.iter(); + assert_eq!(iter.next(), Some(VREG(23, Int))); + assert_eq!(iter.next(), Some(VREG(199, Float))); + assert_eq!(iter.next(), Some(VREG(11, Vector))); + assert_eq!(iter.next(), Some(VREG(2000, Int))); + assert_eq!(iter.next(), Some(VREG(10, Int))); + + set.remove(23); + set.remove(11); + set.insert(VREG(73, Vector)); + let mut iter = set.iter(); + assert_eq!(iter.next(), Some(VREG(73, Vector))); + assert_eq!(iter.next(), Some(VREG(199, Float))); + assert_eq!(iter.next(), Some(VREG(2000, Int))); + assert_eq!(iter.next(), Some(VREG(10, Int))); + assert!(!set.is_empty()); + } + + #[test] + fn empty() { + let mut set = VRegSet::with_capacity(2000); + assert!(set.is_empty()); + set.insert(VREG(100, Int)); + assert!(!set.is_empty()); + set.remove(100); + assert!(set.is_empty()); + } +} diff --git a/deps/crates/vendor/regalloc2/src/fuzzing/func.rs b/deps/crates/vendor/regalloc2/src/fuzzing/func.rs new file mode 100644 index 00000000000000..69ce7262d804ce --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fuzzing/func.rs @@ -0,0 +1,658 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +use crate::{ + domtree, postorder, Allocation, Block, Function, Inst, InstRange, MachineEnv, Operand, + OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg, +}; + +use alloc::vec::Vec; +use alloc::{format, vec}; + +use super::arbitrary::Result as ArbitraryResult; +use super::arbitrary::{Arbitrary, Unstructured}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum InstOpcode { + Op, + Ret, + Branch, +} + +#[derive(Clone, Debug)] +pub struct InstData { + op: InstOpcode, + operands: Vec, + clobbers: Vec, +} + +impl InstData { + pub fn branch() -> InstData { + InstData { + op: InstOpcode::Branch, + operands: vec![], + clobbers: vec![], + } + } + pub fn ret() -> InstData { + InstData { + op: InstOpcode::Ret, + operands: vec![], + clobbers: vec![], + } + } +} + +#[derive(Clone)] +pub struct Func { + insts: Vec, + blocks: Vec, + block_preds: Vec>, + block_succs: Vec>, + block_params_in: Vec>, + block_params_out: Vec>>, + num_vregs: usize, + reftype_vregs: Vec, + debug_value_labels: Vec<(VReg, Inst, Inst, u32)>, +} + +impl Function for Func { + fn num_insts(&self) -> usize { + self.insts.len() + } + + fn num_blocks(&self) -> usize { + self.blocks.len() + } + + fn entry_block(&self) -> Block { + debug_assert!(self.blocks.len() > 0); + Block::new(0) + } + + fn block_insns(&self, block: Block) -> InstRange { + self.blocks[block.index()] + } + + fn block_succs(&self, block: Block) -> &[Block] { + &self.block_succs[block.index()][..] + } + + fn block_preds(&self, block: Block) -> &[Block] { + &self.block_preds[block.index()][..] + } + + fn block_params(&self, block: Block) -> &[VReg] { + &self.block_params_in[block.index()][..] + } + + fn is_ret(&self, insn: Inst) -> bool { + self.insts[insn.index()].op == InstOpcode::Ret + } + + fn is_branch(&self, insn: Inst) -> bool { + self.insts[insn.index()].op == InstOpcode::Branch + } + + fn branch_blockparams(&self, block: Block, _: Inst, succ: usize) -> &[VReg] { + &self.block_params_out[block.index()][succ][..] + } + + fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] { + &self.debug_value_labels[..] + } + + fn inst_operands(&self, insn: Inst) -> &[Operand] { + &self.insts[insn.index()].operands[..] + } + + fn inst_clobbers(&self, insn: Inst) -> PRegSet { + let mut set = PRegSet::default(); + for &preg in &self.insts[insn.index()].clobbers { + set = set.with(preg); + } + set + } + + fn num_vregs(&self) -> usize { + self.num_vregs + } + + fn spillslot_size(&self, regclass: RegClass) -> usize { + match regclass { + // Test the case where 2 classes share the same + RegClass::Int => 1, + RegClass::Float => 1, + RegClass::Vector => 2, + } + } +} + +struct FuncBuilder { + postorder: Vec, + idom: Vec, + f: Func, + insts_per_block: Vec>, +} + +impl FuncBuilder { + fn new() -> Self { + FuncBuilder { + postorder: vec![], + idom: vec![], + f: Func { + block_preds: vec![], + block_succs: vec![], + block_params_in: vec![], + block_params_out: vec![], + insts: vec![], + blocks: vec![], + num_vregs: 0, + reftype_vregs: vec![], + debug_value_labels: vec![], + }, + insts_per_block: vec![], + } + } + + pub fn add_block(&mut self) -> Block { + let b = Block::new(self.f.blocks.len()); + self.f + .blocks + .push(InstRange::new(Inst::new(0), Inst::new(0))); + self.f.block_preds.push(vec![]); + self.f.block_succs.push(vec![]); + self.f.block_params_in.push(vec![]); + self.f.block_params_out.push(vec![]); + self.insts_per_block.push(vec![]); + b + } + + pub fn add_inst(&mut self, block: Block, data: InstData) { + self.insts_per_block[block.index()].push(data); + } + + pub fn add_edge(&mut self, from: Block, to: Block) { + self.f.block_succs[from.index()].push(to); + self.f.block_preds[to.index()].push(from); + } + + pub fn set_block_params_in(&mut self, block: Block, params: &[VReg]) { + self.f.block_params_in[block.index()] = params.iter().cloned().collect(); + } + + pub fn set_block_params_out(&mut self, block: Block, params: Vec>) { + self.f.block_params_out[block.index()] = params; + } + + fn compute_doms(&mut self) { + let f = &self.f; + postorder::calculate( + self.f.blocks.len(), + Block::new(0), + &mut vec![], + &mut self.postorder, + |block| &f.block_succs[block.index()][..], + ); + domtree::calculate( + self.f.blocks.len(), + |block| &f.block_preds[block.index()][..], + &self.postorder[..], + &mut vec![], + &mut self.idom, + Block::new(0), + ); + } + + fn finalize(mut self) -> Func { + for (blocknum, blockrange) in self.f.blocks.iter_mut().enumerate() { + let begin_inst = self.f.insts.len(); + for inst in &self.insts_per_block[blocknum] { + self.f.insts.push(inst.clone()); + } + let end_inst = self.f.insts.len(); + *blockrange = InstRange::new(Inst::new(begin_inst), Inst::new(end_inst)); + } + + self.f + } +} + +impl Arbitrary<'_> for RegClass { + fn arbitrary(u: &mut Unstructured) -> ArbitraryResult { + Ok(*u.choose(&[RegClass::Int, RegClass::Float, RegClass::Vector])?) + } +} + +impl Arbitrary<'_> for OperandConstraint { + fn arbitrary(u: &mut Unstructured) -> ArbitraryResult { + Ok(*u.choose(&[OperandConstraint::Any, OperandConstraint::Reg])?) + } +} + +fn choose_dominating_block( + idom: &[Block], + mut block: Block, + allow_self: bool, + u: &mut Unstructured, +) -> ArbitraryResult { + debug_assert!(block.is_valid()); + let orig_block = block; + loop { + if (allow_self || block != orig_block) && bool::arbitrary(u)? { + break; + } + if idom[block.index()].is_invalid() { + break; + } + block = idom[block.index()]; + } + let block = if block != orig_block || allow_self { + block + } else { + Block::invalid() + }; + Ok(block) +} + +#[derive(Clone, Copy, Debug)] +pub struct Options { + pub reused_inputs: bool, + pub fixed_regs: bool, + pub fixed_nonallocatable: bool, + pub clobbers: bool, + pub reftypes: bool, +} + +impl core::default::Default for Options { + fn default() -> Self { + Options { + reused_inputs: false, + fixed_regs: false, + fixed_nonallocatable: false, + clobbers: false, + reftypes: false, + } + } +} + +impl Arbitrary<'_> for Func { + fn arbitrary(u: &mut Unstructured) -> ArbitraryResult { + Func::arbitrary_with_options(u, &Options::default()) + } +} + +impl Func { + pub fn arbitrary_with_options(u: &mut Unstructured, opts: &Options) -> ArbitraryResult { + // General strategy: + // 1. Create an arbitrary CFG. + // 2. Create a list of vregs to define in each block. + // 3. Define some of those vregs in each block as blockparams.f. + // 4. Populate blocks with ops that define the rest of the vregs. + // - For each use, choose an available vreg: either one + // already defined (via blockparam or inst) in this block, + // or one defined in a dominating block. + + let mut builder = FuncBuilder::new(); + for _ in 0..u.int_in_range(1..=100)? { + builder.add_block(); + } + let num_blocks = builder.f.blocks.len(); + + // Generate a CFG. Create a "spine" of either single blocks, + // with links to the next; or fork patterns, with the left + // fork linking to the next and the right fork in `out_blocks` + // to be connected below. This creates an arbitrary CFG with + // split critical edges, which is a property that we require + // for the regalloc. + let mut from = 0; + let mut out_blocks = vec![]; + let mut in_blocks = vec![]; + while from < num_blocks { + in_blocks.push(from); + if num_blocks > 3 && from < num_blocks - 3 && bool::arbitrary(u)? { + // To avoid critical edges, we use from+1 as an edge + // block, and advance `from` an extra block; `from+2` + // will be the next normal iteration. + builder.add_edge(Block::new(from), Block::new(from + 1)); + builder.add_edge(Block::new(from), Block::new(from + 2)); + builder.add_edge(Block::new(from + 2), Block::new(from + 3)); + out_blocks.push(from + 1); + from += 2; + } else if from < num_blocks - 1 { + builder.add_edge(Block::new(from), Block::new(from + 1)); + } + from += 1; + } + for pred in out_blocks { + let succ = *u.choose(&in_blocks[..])?; + builder.add_edge(Block::new(pred), Block::new(succ)); + } + + builder.compute_doms(); + + for block in 0..num_blocks { + builder.f.block_preds[block].clear(); + } + for block in 0..num_blocks { + for &succ in &builder.f.block_succs[block] { + builder.f.block_preds[succ.index()].push(Block::new(block)); + } + } + + builder.compute_doms(); + + let mut vregs_by_block = vec![]; + let mut vregs_by_block_to_be_defined = vec![]; + let mut block_params = vec![vec![]; num_blocks]; + for block in 0..num_blocks { + let mut vregs = vec![]; + for _ in 0..u.int_in_range(5..=15)? { + let vreg = VReg::new(builder.f.num_vregs, RegClass::arbitrary(u)?); + builder.f.num_vregs += 1; + vregs.push(vreg); + if opts.reftypes && bool::arbitrary(u)? { + builder.f.reftype_vregs.push(vreg); + } + if bool::arbitrary(u)? { + let assumed_end_inst = 10 * num_blocks; + let mut start = u.int_in_range::(0..=assumed_end_inst)?; + for _ in 0..10 { + if start >= assumed_end_inst { + break; + } + let end = u.int_in_range::(start..=assumed_end_inst)?; + let label = u.int_in_range::(0..=100)?; + builder.f.debug_value_labels.push(( + vreg, + Inst::new(start), + Inst::new(end), + label, + )); + start = end; + } + } + } + vregs_by_block.push(vregs.clone()); + let mut vregs_to_be_defined = vec![]; + let mut max_block_params = u.int_in_range(0..=core::cmp::min(3, vregs.len() / 3))?; + for &vreg in &vregs { + if block > 0 && bool::arbitrary(u)? && max_block_params > 0 { + block_params[block].push(vreg); + max_block_params -= 1; + } else { + vregs_to_be_defined.push(vreg); + } + } + vregs_to_be_defined.reverse(); + vregs_by_block_to_be_defined.push(vregs_to_be_defined); + builder.set_block_params_in(Block::new(block), &block_params[block][..]); + } + + for block in 0..num_blocks { + let mut avail = block_params[block].clone(); + let mut remaining_nonlocal_uses = u.int_in_range(0..=3)?; + while let Some(vreg) = vregs_by_block_to_be_defined[block].pop() { + let def_constraint = OperandConstraint::arbitrary(u)?; + let def_pos = if bool::arbitrary(u)? { + OperandPos::Early + } else { + OperandPos::Late + }; + let mut operands = vec![Operand::new( + vreg, + def_constraint, + OperandKind::Def, + def_pos, + )]; + let mut allocations = vec![Allocation::none()]; + for _ in 0..u.int_in_range(0..=3)? { + let vreg = if avail.len() > 0 + && (remaining_nonlocal_uses == 0 || bool::arbitrary(u)?) + { + *u.choose(&avail[..])? + } else { + let def_block = choose_dominating_block( + &builder.idom[..], + Block::new(block), + /* allow_self = */ false, + u, + )?; + if !def_block.is_valid() { + // No vregs already defined, and no pred blocks that dominate us + // (perhaps we are the entry block): just stop generating inputs. + break; + } + remaining_nonlocal_uses -= 1; + *u.choose(&vregs_by_block[def_block.index()])? + }; + let use_constraint = OperandConstraint::arbitrary(u)?; + operands.push(Operand::new( + vreg, + use_constraint, + OperandKind::Use, + OperandPos::Early, + )); + allocations.push(Allocation::none()); + } + let mut clobbers: Vec = vec![]; + if operands.len() > 1 && opts.reused_inputs && bool::arbitrary(u)? { + // Make the def a reused input. + let op = operands[0]; + debug_assert_eq!(op.kind(), OperandKind::Def); + let reused = u.int_in_range(1..=(operands.len() - 1))?; + if op.class() == operands[reused].class() { + operands[0] = Operand::new( + op.vreg(), + OperandConstraint::Reuse(reused), + op.kind(), + OperandPos::Late, + ); + // Make sure reused input is a Reg. + let op = operands[reused]; + operands[reused] = Operand::new( + op.vreg(), + OperandConstraint::Reg, + op.kind(), + OperandPos::Early, + ); + } + } else if opts.fixed_regs && bool::arbitrary(u)? { + let mut fixed_early = vec![]; + let mut fixed_late = vec![]; + for _ in 0..u.int_in_range(0..=operands.len() - 1)? { + // Pick an operand and make it a fixed reg. + let i = u.int_in_range(0..=(operands.len() - 1))?; + let op = operands[i]; + let fixed_reg = PReg::new(u.int_in_range(0..=62)?, op.class()); + if op.kind() == OperandKind::Def && op.pos() == OperandPos::Early { + // Early-defs with fixed constraints conflict with + // any other fixed uses of the same preg. + if fixed_late.contains(&fixed_reg) { + break; + } + } + if op.kind() == OperandKind::Use && op.pos() == OperandPos::Late { + // Late-use with fixed constraints conflict with + // any other fixed uses of the same preg. + if fixed_early.contains(&fixed_reg) { + break; + } + } + let fixed_list = match op.pos() { + OperandPos::Early => &mut fixed_early, + OperandPos::Late => &mut fixed_late, + }; + if fixed_list.contains(&fixed_reg) { + break; + } + fixed_list.push(fixed_reg); + operands[i] = Operand::new( + op.vreg(), + OperandConstraint::FixedReg(fixed_reg), + op.kind(), + op.pos(), + ); + } + } else if opts.clobbers && bool::arbitrary(u)? { + for _ in 0..u.int_in_range(0..=5)? { + let reg = u.int_in_range(0..=30)?; + if clobbers.iter().any(|r| r.hw_enc() == reg) { + break; + } + clobbers.push(PReg::new(reg, RegClass::arbitrary(u)?)); + } + } else if opts.fixed_nonallocatable && bool::arbitrary(u)? { + operands.push(Operand::fixed_nonallocatable(PReg::new( + 63, + RegClass::arbitrary(u)?, + ))); + } + + builder.add_inst( + Block::new(block), + InstData { + op: InstOpcode::Op, + operands, + clobbers, + }, + ); + avail.push(vreg); + } + + // Define the branch with blockparam args that must end + // the block. + if builder.f.block_succs[block].len() > 0 { + let mut params = vec![]; + for &succ in &builder.f.block_succs[block] { + let mut args = vec![]; + for i in 0..builder.f.block_params_in[succ.index()].len() { + let dom_block = choose_dominating_block( + &builder.idom[..], + Block::new(block), + false, + u, + )?; + + // Look for a vreg with a suitable class. If no + // suitable vreg is available then we error out, which + // causes the fuzzer to skip this function. + let vregs = if dom_block.is_valid() && bool::arbitrary(u)? { + &vregs_by_block[dom_block.index()][..] + } else { + &avail[..] + }; + let suitable_vregs: Vec<_> = vregs + .iter() + .filter(|vreg| { + vreg.class() == builder.f.block_params_in[succ.index()][i].class() + }) + .copied() + .collect(); + let vreg = u.choose(&suitable_vregs)?; + args.push(*vreg); + } + params.push(args); + } + builder.set_block_params_out(Block::new(block), params); + builder.add_inst(Block::new(block), InstData::branch()); + } else { + builder.add_inst(Block::new(block), InstData::ret()); + } + } + + builder.f.debug_value_labels.sort_unstable(); + + Ok(builder.finalize()) + } +} + +impl core::fmt::Debug for Func { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{{\n")?; + for (i, blockrange) in self.blocks.iter().enumerate() { + let succs = self.block_succs[i] + .iter() + .map(|b| b.index()) + .collect::>(); + let preds = self.block_preds[i] + .iter() + .map(|b| b.index()) + .collect::>(); + let params_in = self.block_params_in[i] + .iter() + .map(|v| format!("v{}", v.vreg())) + .collect::>() + .join(", "); + let params_out = self.block_params_out[i] + .iter() + .enumerate() + .map(|(succ_idx, vec)| { + let succ = self.block_succs[i][succ_idx]; + let params = vec + .iter() + .map(|v| format!("v{}", v.vreg())) + .collect::>() + .join(", "); + format!("block{}({})", succ.index(), params) + }) + .collect::>() + .join(", "); + write!( + f, + " block{}({}): # succs:{:?} preds:{:?}\n", + i, params_in, succs, preds + )?; + for inst in blockrange.iter() { + write!( + f, + " inst{}: {:?} ops:{:?} clobber:{:?}\n", + inst.index(), + self.insts[inst.index()].op, + self.insts[inst.index()].operands, + self.insts[inst.index()].clobbers + )?; + if let InstOpcode::Branch = self.insts[inst.index()].op { + write!(f, " params: {}\n", params_out)?; + } + } + } + write!(f, "}}\n")?; + Ok(()) + } +} + +pub fn machine_env() -> MachineEnv { + fn regs(r: core::ops::Range, c: RegClass) -> Vec { + r.map(|i| PReg::new(i, c)).collect() + } + let preferred_regs_by_class: [Vec; 3] = [ + regs(0..24, RegClass::Int), + regs(0..24, RegClass::Float), + regs(0..24, RegClass::Vector), + ]; + let non_preferred_regs_by_class: [Vec; 3] = [ + regs(24..32, RegClass::Int), + regs(24..32, RegClass::Float), + regs(24..32, RegClass::Vector), + ]; + let scratch_by_class: [Option; 3] = [None, None, None]; + let fixed_stack_slots = (32..63) + .flat_map(|i| { + [ + PReg::new(i, RegClass::Int), + PReg::new(i, RegClass::Float), + PReg::new(i, RegClass::Vector), + ] + }) + .collect(); + // Register 63 is reserved for use as a fixed non-allocatable register. + MachineEnv { + preferred_regs_by_class, + non_preferred_regs_by_class, + scratch_by_class, + fixed_stack_slots, + } +} diff --git a/deps/crates/vendor/regalloc2/src/fuzzing/mod.rs b/deps/crates/vendor/regalloc2/src/fuzzing/mod.rs new file mode 100644 index 00000000000000..1aa619ec08bfa5 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/fuzzing/mod.rs @@ -0,0 +1,34 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +//! Utilities for fuzzing. + +pub mod func; + +// Re-exports for fuzz targets. + +pub mod domtree { + pub use crate::domtree::*; +} +pub mod postorder { + pub use crate::postorder::*; +} +pub mod moves { + pub use crate::moves::*; +} +pub mod cfg { + pub use crate::cfg::*; +} +pub mod ion { + pub use crate::ion::*; +} +pub mod fastalloc { + pub use crate::fastalloc::*; +} +pub mod checker { + pub use crate::checker::*; +} + +pub use libfuzzer_sys::{arbitrary, fuzz_target}; diff --git a/deps/crates/vendor/regalloc2/src/index.rs b/deps/crates/vendor/regalloc2/src/index.rs new file mode 100644 index 00000000000000..12c4572b4d4194 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/index.rs @@ -0,0 +1,209 @@ +#[macro_export] +macro_rules! define_index { + ($ix:ident, $storage:ident, $elem:ident) => { + define_index!($ix); + + #[derive(Clone, Debug, Default)] + pub struct $storage { + storage: Vec<$elem>, + } + + impl $storage { + #[inline(always)] + /// See `VecExt::preallocate` + pub fn preallocate(&mut self, cap: usize) { + use $crate::VecExt; + self.storage.preallocate(cap); + } + + #[inline(always)] + pub fn len(&self) -> usize { + self.storage.len() + } + + #[inline(always)] + pub fn iter(&self) -> impl Iterator { + self.storage.iter() + } + + #[inline(always)] + pub fn iter_mut(&mut self) -> impl Iterator { + self.storage.iter_mut() + } + + #[inline(always)] + pub fn push(&mut self, value: $elem) -> $ix { + let idx = $ix(self.storage.len() as u32); + self.storage.push(value); + idx + } + } + + impl core::ops::Index<$ix> for $storage { + type Output = $elem; + + #[inline(always)] + fn index(&self, i: $ix) -> &Self::Output { + &self.storage[i.index()] + } + } + + impl core::ops::IndexMut<$ix> for $storage { + #[inline(always)] + fn index_mut(&mut self, i: $ix) -> &mut Self::Output { + &mut self.storage[i.index()] + } + } + + impl<'a> IntoIterator for &'a $storage { + type Item = &'a $elem; + type IntoIter = core::slice::Iter<'a, $elem>; + + #[inline(always)] + fn into_iter(self) -> Self::IntoIter { + self.storage.iter() + } + } + + impl<'a> IntoIterator for &'a mut $storage { + type Item = &'a mut $elem; + type IntoIter = core::slice::IterMut<'a, $elem>; + + #[inline(always)] + fn into_iter(self) -> Self::IntoIter { + self.storage.iter_mut() + } + } + }; + + ($ix:ident) => { + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[cfg_attr( + feature = "enable-serde", + derive(::serde::Serialize, ::serde::Deserialize) + )] + pub struct $ix(pub u32); + impl $ix { + #[inline(always)] + pub fn new(i: usize) -> Self { + Self(i as u32) + } + #[inline(always)] + pub fn index(self) -> usize { + debug_assert!(self.is_valid()); + self.0 as usize + } + #[inline(always)] + pub fn invalid() -> Self { + Self(u32::MAX) + } + #[inline(always)] + pub fn is_invalid(self) -> bool { + self == Self::invalid() + } + #[inline(always)] + pub fn is_valid(self) -> bool { + self != Self::invalid() + } + #[inline(always)] + pub fn next(self) -> $ix { + debug_assert!(self.is_valid()); + Self(self.0 + 1) + } + #[inline(always)] + pub fn prev(self) -> $ix { + debug_assert!(self.is_valid()); + Self(self.0 - 1) + } + + #[inline(always)] + pub fn raw_u32(self) -> u32 { + self.0 + } + } + + impl crate::index::ContainerIndex for $ix {} + }; +} + +pub trait ContainerIndex: Clone + Copy + core::fmt::Debug + PartialEq + Eq {} + +pub trait ContainerComparator { + type Ix: ContainerIndex; + fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering; +} + +define_index!(Inst); +define_index!(Block); + +#[derive(Clone, Copy, Debug)] +#[cfg_attr( + feature = "enable-serde", + derive(::serde::Serialize, ::serde::Deserialize) +)] +pub struct InstRange(Inst, Inst); + +impl InstRange { + #[inline(always)] + pub fn new(from: Inst, to: Inst) -> Self { + debug_assert!(from.index() <= to.index()); + InstRange(from, to) + } + + #[inline(always)] + pub fn first(self) -> Inst { + debug_assert!(self.len() > 0); + self.0 + } + + #[inline(always)] + pub fn last(self) -> Inst { + debug_assert!(self.len() > 0); + self.1.prev() + } + + #[inline(always)] + pub fn rest(self) -> InstRange { + debug_assert!(self.len() > 0); + InstRange::new(self.0.next(), self.1) + } + + #[inline(always)] + pub fn len(self) -> usize { + self.1.index() - self.0.index() + } + + #[inline(always)] + pub fn iter(self) -> impl DoubleEndedIterator { + (self.0.index()..self.1.index()).map(|i| Inst::new(i)) + } +} + +#[cfg(test)] +mod test { + use alloc::vec; + use alloc::vec::Vec; + + use super::*; + + #[test] + fn test_inst_range() { + let range = InstRange::new(Inst::new(0), Inst::new(0)); + debug_assert_eq!(range.len(), 0); + + let range = InstRange::new(Inst::new(0), Inst::new(5)); + debug_assert_eq!(range.first().index(), 0); + debug_assert_eq!(range.last().index(), 4); + debug_assert_eq!(range.len(), 5); + debug_assert_eq!( + range.iter().collect::>(), + vec![ + Inst::new(0), + Inst::new(1), + Inst::new(2), + Inst::new(3), + Inst::new(4) + ] + ); + } +} diff --git a/deps/crates/vendor/regalloc2/src/indexset.rs b/deps/crates/vendor/regalloc2/src/indexset.rs new file mode 100644 index 00000000000000..1fd58a2013b7d7 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/indexset.rs @@ -0,0 +1,349 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +//! Index sets: sets of integers that represent indices into a space. + +use alloc::vec::Vec; +use core::cell::Cell; + +use crate::FxHashMap; + +const SMALL_ELEMS: usize = 12; + +/// A hybrid large/small-mode sparse mapping from integer indices to +/// elements. +/// +/// The trailing `(u32, u64)` elements in each variant is a one-item +/// cache to allow fast access when streaming through. +#[derive(Clone, Debug)] +enum AdaptiveMap { + Small { + len: u32, + keys: [u32; SMALL_ELEMS], + values: [u64; SMALL_ELEMS], + }, + Large(FxHashMap), +} + +const INVALID: u32 = 0xffff_ffff; + +impl AdaptiveMap { + fn new() -> Self { + Self::Small { + len: 0, + keys: [INVALID; SMALL_ELEMS], + values: [0; SMALL_ELEMS], + } + } + + #[inline(always)] + fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 { + // Check whether the key is present and we are in small mode; + // if no to both, we need to expand first. + let small_mode_idx = match self { + &mut Self::Small { + len, + ref mut keys, + ref values, + } => { + // Perform this scan but do not return right away; + // doing so runs into overlapping-borrow issues + // because the current non-lexical lifetimes + // implementation is not able to see that the `self` + // mutable borrow on return is only on the + // early-return path. + if let Some(i) = keys[..len as usize].iter().position(|&k| k == key) { + Some(i) + } else if len != SMALL_ELEMS as u32 { + debug_assert!(len < SMALL_ELEMS as u32); + None + } else if let Some(i) = values.iter().position(|&v| v == 0) { + // If an existing value is zero, reuse that slot. + keys[i] = key; + Some(i) + } else { + *self = Self::Large(keys.iter().copied().zip(values.iter().copied()).collect()); + None + } + } + _ => None, + }; + + match self { + Self::Small { len, keys, values } => { + // If we found the key already while checking whether + // we need to expand above, use that index to return + // early. + if let Some(i) = small_mode_idx { + return &mut values[i]; + } + // Otherwise, the key must not be present; add a new + // entry. + debug_assert!(*len < SMALL_ELEMS as u32); + let idx = *len as usize; + *len += 1; + keys[idx] = key; + values[idx] = 0; + &mut values[idx] + } + Self::Large(map) => map.entry(key).or_insert(0), + } + } + + #[inline(always)] + fn get_mut(&mut self, key: u32) -> Option<&mut u64> { + match self { + &mut Self::Small { + len, + ref keys, + ref mut values, + } => { + for i in 0..len { + if keys[i as usize] == key { + return Some(&mut values[i as usize]); + } + } + None + } + &mut Self::Large(ref mut map) => map.get_mut(&key), + } + } + #[inline(always)] + fn get(&self, key: u32) -> Option { + match self { + &Self::Small { + len, + ref keys, + ref values, + } => { + for i in 0..len { + if keys[i as usize] == key { + let value = values[i as usize]; + return Some(value); + } + } + None + } + &Self::Large(ref map) => { + let value = map.get(&key).cloned(); + value + } + } + } + fn iter<'a>(&'a self) -> AdaptiveMapIter<'a> { + match self { + &Self::Small { + len, + ref keys, + ref values, + } => AdaptiveMapIter::Small(&keys[0..len as usize], &values[0..len as usize]), + &Self::Large(ref map) => AdaptiveMapIter::Large(map.iter()), + } + } + + fn is_empty(&self) -> bool { + match self { + AdaptiveMap::Small { values, .. } => values.iter().all(|&value| value == 0), + AdaptiveMap::Large(m) => m.values().all(|&value| value == 0), + } + } +} + +enum AdaptiveMapIter<'a> { + Small(&'a [u32], &'a [u64]), + Large(hashbrown::hash_map::Iter<'a, u32, u64>), +} + +impl<'a> core::iter::Iterator for AdaptiveMapIter<'a> { + type Item = (u32, u64); + + #[inline] + fn next(&mut self) -> Option { + match self { + &mut Self::Small(ref mut keys, ref mut values) => { + if keys.is_empty() { + None + } else { + let (k, v) = ((*keys)[0], (*values)[0]); + *keys = &(*keys)[1..]; + *values = &(*values)[1..]; + Some((k, v)) + } + } + &mut Self::Large(ref mut it) => it.next().map(|(&k, &v)| (k, v)), + } + } +} + +/// A conceptually infinite-length set of indices that allows union +/// and efficient iteration over elements. +#[derive(Clone)] +pub struct IndexSet { + elems: AdaptiveMap, + cache: Cell<(u32, u64)>, +} + +const BITS_PER_WORD: usize = 64; + +impl IndexSet { + pub fn new() -> Self { + Self { + elems: AdaptiveMap::new(), + cache: Cell::new((INVALID, 0)), + } + } + + #[inline(always)] + fn elem(&mut self, bit_index: usize) -> &mut u64 { + let word_index = (bit_index / BITS_PER_WORD) as u32; + if self.cache.get().0 == word_index { + self.cache.set((INVALID, 0)); + } + self.elems.get_or_insert(word_index) + } + + #[inline(always)] + fn maybe_elem_mut(&mut self, bit_index: usize) -> Option<&mut u64> { + let word_index = (bit_index / BITS_PER_WORD) as u32; + if self.cache.get().0 == word_index { + self.cache.set((INVALID, 0)); + } + self.elems.get_mut(word_index) + } + + #[inline(always)] + fn maybe_elem(&self, bit_index: usize) -> Option { + let word_index = (bit_index / BITS_PER_WORD) as u32; + if self.cache.get().0 == word_index { + Some(self.cache.get().1) + } else { + self.elems.get(word_index) + } + } + + #[inline(always)] + pub fn set(&mut self, idx: usize, val: bool) { + let bit = idx % BITS_PER_WORD; + if val { + *self.elem(idx) |= 1 << bit; + } else if let Some(word) = self.maybe_elem_mut(idx) { + *word &= !(1 << bit); + } + } + + pub fn assign(&mut self, other: &Self) { + self.elems = other.elems.clone(); + self.cache = other.cache.clone(); + } + + #[inline(always)] + pub fn get(&self, idx: usize) -> bool { + let bit = idx % BITS_PER_WORD; + if let Some(word) = self.maybe_elem(idx) { + (word & (1 << bit)) != 0 + } else { + false + } + } + + pub fn union_with(&mut self, other: &Self) -> bool { + let mut changed = 0; + for (word_idx, bits) in other.elems.iter() { + if bits == 0 { + continue; + } + let word_idx = word_idx as usize; + let self_word = self.elem(word_idx * BITS_PER_WORD); + changed |= bits & !*self_word; + *self_word |= bits; + } + changed != 0 + } + + pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.elems.iter().flat_map(|(word_idx, bits)| { + let word_idx = word_idx as usize; + SetBitsIter(bits).map(move |i| BITS_PER_WORD * word_idx + i) + }) + } + + /// Is the adaptive data structure in "small" mode? This is meant + /// for testing assertions only. + pub(crate) fn is_small(&self) -> bool { + match &self.elems { + &AdaptiveMap::Small { .. } => true, + _ => false, + } + } + + /// Is the set empty? + pub(crate) fn is_empty(&self) -> bool { + self.elems.is_empty() + } +} + +pub struct SetBitsIter(u64); + +impl Iterator for SetBitsIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // Build an `Option` so that on the nonzero path, + // the compiler can optimize the trailing-zeroes operator + // using that knowledge. + core::num::NonZeroU64::new(self.0).map(|nz| { + let bitidx = nz.trailing_zeros(); + self.0 &= self.0 - 1; // clear highest set bit + bitidx as usize + }) + } +} + +impl core::fmt::Debug for IndexSet { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let vals = self.iter().collect::>(); + write!(f, "{:?}", vals) + } +} + +#[cfg(test)] +mod test { + use super::IndexSet; + + #[test] + fn test_set_bits_iter() { + let mut vec = IndexSet::new(); + let mut sum = 0; + for i in 0..1024 { + if i % 17 == 0 { + vec.set(i, true); + sum += i; + } + } + + let mut checksum = 0; + for bit in vec.iter() { + debug_assert!(bit % 17 == 0); + checksum += bit; + } + + debug_assert_eq!(sum, checksum); + } + + #[test] + fn test_expand_remove_zero_elems() { + let mut vec = IndexSet::new(); + // Set 12 different words (this is the max small-mode size). + for i in 0..12 { + vec.set(64 * i, true); + } + // Now clear a bit, and set a bit in a different word. We + // should still be in small mode. + vec.set(64 * 5, false); + vec.set(64 * 100, true); + debug_assert!(vec.is_small()); + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/data_structures.rs b/deps/crates/vendor/regalloc2/src/ion/data_structures.rs new file mode 100644 index 00000000000000..848ab2a3edb62f --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/data_structures.rs @@ -0,0 +1,852 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Data structures for backtracking allocator. + +use super::liveranges::SpillWeight; +use crate::cfg::{CFGInfo, CFGInfoCtx}; +use crate::index::ContainerComparator; +use crate::indexset::IndexSet; +use crate::Vec2; +use crate::{ + define_index, Allocation, Block, Bump, Edit, Function, FxHashMap, FxHashSet, MachineEnv, + Operand, Output, PReg, ProgPoint, RegClass, VReg, +}; +use alloc::collections::BTreeMap; +use alloc::collections::VecDeque; +use alloc::string::String; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt::Debug; +use core::ops::{Deref, DerefMut}; +use smallvec::SmallVec; + +/// A range from `from` (inclusive) to `to` (exclusive). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CodeRange { + pub from: ProgPoint, + pub to: ProgPoint, +} + +impl CodeRange { + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.from >= self.to + } + #[inline(always)] + pub fn contains(&self, other: &Self) -> bool { + other.from >= self.from && other.to <= self.to + } + #[inline(always)] + pub fn contains_point(&self, other: ProgPoint) -> bool { + other >= self.from && other < self.to + } + #[inline(always)] + pub fn overlaps(&self, other: &Self) -> bool { + other.to > self.from && other.from < self.to + } + #[inline(always)] + pub fn len(&self) -> usize { + self.to.inst().index() - self.from.inst().index() + } + /// Returns the range covering just one program point. + #[inline(always)] + pub fn singleton(pos: ProgPoint) -> CodeRange { + CodeRange { + from: pos, + to: pos.next(), + } + } + + /// Join two [CodeRange] values together, producing a [CodeRange] that includes both. + #[inline(always)] + pub fn join(&self, other: CodeRange) -> Self { + CodeRange { + from: self.from.min(other.from), + to: self.to.max(other.to), + } + } +} + +impl core::cmp::PartialOrd for CodeRange { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl core::cmp::Ord for CodeRange { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + if self.to <= other.from { + Ordering::Less + } else if self.from >= other.to { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +define_index!(LiveBundleIndex, LiveBundles, LiveBundle); +define_index!(LiveRangeIndex, LiveRanges, LiveRange); +define_index!(SpillSetIndex, SpillSets, SpillSet); +define_index!(UseIndex); +define_index!(VRegIndex, VRegs, VRegData); +define_index!(PRegIndex); +define_index!(SpillSlotIndex); + +/// Used to carry small sets of bundles, e.g. for conflict sets. +pub type LiveBundleVec = Vec; + +#[derive(Clone, Copy, Debug)] +pub struct LiveRangeListEntry { + pub range: CodeRange, + pub index: LiveRangeIndex, +} + +pub type LiveRangeList = Vec2; +pub type UseList = Vec2; + +#[derive(Clone, Debug)] +pub struct LiveRange { + pub range: CodeRange, + + pub vreg: VRegIndex, + pub bundle: LiveBundleIndex, + pub uses_spill_weight_and_flags: u32, + pub(crate) uses: UseList, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u32)] +pub enum LiveRangeFlag { + StartsAtDef = 1, +} + +impl LiveRange { + #[inline(always)] + pub fn set_flag(&mut self, flag: LiveRangeFlag) { + self.uses_spill_weight_and_flags |= (flag as u32) << 29; + } + #[inline(always)] + pub fn clear_flag(&mut self, flag: LiveRangeFlag) { + self.uses_spill_weight_and_flags &= !((flag as u32) << 29); + } + #[inline(always)] + pub fn assign_flag(&mut self, flag: LiveRangeFlag, val: bool) { + let bit = if val { (flag as u32) << 29 } else { 0 }; + self.uses_spill_weight_and_flags &= 0xe000_0000; + self.uses_spill_weight_and_flags |= bit; + } + #[inline(always)] + pub fn has_flag(&self, flag: LiveRangeFlag) -> bool { + self.uses_spill_weight_and_flags & ((flag as u32) << 29) != 0 + } + #[inline(always)] + pub fn flag_word(&self) -> u32 { + self.uses_spill_weight_and_flags & 0xe000_0000 + } + #[inline(always)] + pub fn merge_flags(&mut self, flag_word: u32) { + self.uses_spill_weight_and_flags |= flag_word; + } + #[inline(always)] + pub fn uses_spill_weight(&self) -> SpillWeight { + // NOTE: the spill weight is technically stored in 29 bits, but we ignore the sign bit as + // we will always be dealing with positive values. Thus we mask out the top 3 bits to + // ensure that the sign bit is clear, then shift left by only two. + let bits = (self.uses_spill_weight_and_flags & 0x1fff_ffff) << 2; + SpillWeight::from_f32(f32::from_bits(bits)) + } + #[inline(always)] + pub fn set_uses_spill_weight(&mut self, weight: SpillWeight) { + let weight_bits = (weight.to_f32().to_bits() >> 2) & 0x1fff_ffff; + self.uses_spill_weight_and_flags = + (self.uses_spill_weight_and_flags & 0xe000_0000) | weight_bits; + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Use { + pub operand: Operand, + pub pos: ProgPoint, + pub slot: u8, + pub weight: u16, +} + +impl Use { + #[inline(always)] + pub fn new(operand: Operand, pos: ProgPoint, slot: u8) -> Self { + Self { + operand, + pos, + slot, + // Weight is updated on insertion into LR. + weight: 0, + } + } +} + +#[derive(Clone, Debug)] +pub struct LiveBundle { + pub(crate) ranges: LiveRangeList, + pub spillset: SpillSetIndex, + pub allocation: Allocation, + pub prio: u32, // recomputed after every bulk update + pub spill_weight_and_props: u32, +} + +pub const BUNDLE_MAX_SPILL_WEIGHT: u32 = (1 << 29) - 1; +pub const MINIMAL_FIXED_BUNDLE_SPILL_WEIGHT: u32 = BUNDLE_MAX_SPILL_WEIGHT; +pub const MINIMAL_BUNDLE_SPILL_WEIGHT: u32 = BUNDLE_MAX_SPILL_WEIGHT - 1; +pub const BUNDLE_MAX_NORMAL_SPILL_WEIGHT: u32 = BUNDLE_MAX_SPILL_WEIGHT - 2; + +impl LiveBundle { + #[inline(always)] + pub fn set_cached_spill_weight_and_props( + &mut self, + spill_weight: u32, + minimal: bool, + fixed: bool, + fixed_def: bool, + ) { + debug_assert!(spill_weight <= BUNDLE_MAX_SPILL_WEIGHT); + self.spill_weight_and_props = spill_weight + | (if minimal { 1 << 31 } else { 0 }) + | (if fixed { 1 << 30 } else { 0 }) + | (if fixed_def { 1 << 29 } else { 0 }); + } + + #[inline(always)] + pub fn cached_minimal(&self) -> bool { + self.spill_weight_and_props & (1 << 31) != 0 + } + + #[inline(always)] + pub fn cached_fixed(&self) -> bool { + self.spill_weight_and_props & (1 << 30) != 0 + } + + #[inline(always)] + pub fn cached_fixed_def(&self) -> bool { + self.spill_weight_and_props & (1 << 29) != 0 + } + + #[inline(always)] + pub fn set_cached_fixed(&mut self) { + self.spill_weight_and_props |= 1 << 30; + } + + #[inline(always)] + pub fn set_cached_fixed_def(&mut self) { + self.spill_weight_and_props |= 1 << 29; + } + + #[inline(always)] + pub fn cached_spill_weight(&self) -> u32 { + self.spill_weight_and_props & BUNDLE_MAX_SPILL_WEIGHT + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct BundleProperties { + pub minimal: bool, + pub fixed: bool, +} + +/// Calculate the maximum `N` inline capacity for a `SmallVec<[T; N]>` we can +/// have without bloating its size to be larger than a `Vec`. +const fn no_bloat_capacity() -> usize { + // `Vec` is three words: `(pointer, capacity, length)`. + // + // A `SmallVec<[T; N]>` replaces the first two members with the following: + // + // union { + // Inline([T; N]), + // Heap(pointer, capacity), + // } + // + // So if `size_of([T; N]) == size_of(pointer) + size_of(capacity)` then we + // get the maximum inline capacity without bloat. + core::mem::size_of::() * 2 / core::mem::size_of::() +} + +#[derive(Clone, Debug)] +pub struct SpillSet { + pub slot: SpillSlotIndex, + pub reg_hint: PReg, + pub class: RegClass, + pub spill_bundle: LiveBundleIndex, + pub required: bool, + pub splits: u8, + + /// The aggregate [`CodeRange`] of all involved [`LiveRange`]s. The effect of this abstraction + /// is that we attempt to allocate one spill slot for the extent of a bundle. For fragmented + /// bundles with lots of open space this abstraction is pessimistic, but when bundles are small + /// or dense this yields similar results to tracking individual live ranges. + pub range: CodeRange, +} + +pub(crate) const MAX_SPLITS_PER_SPILLSET: u8 = 2; + +#[derive(Clone, Debug)] +pub struct VRegData { + pub(crate) ranges: LiveRangeList, + pub blockparam: Block, + // We don't initially know the RegClass until we observe a use of the VReg. + pub class: Option, +} + +#[derive(Clone, Debug)] +pub struct PRegData { + pub allocations: LiveRangeSet, + pub is_stack: bool, +} + +#[derive(Clone, Debug)] +pub struct MultiFixedRegFixup { + pub pos: ProgPoint, + pub from_slot: u8, + pub to_slot: u8, + pub level: FixedRegFixupLevel, + pub to_preg: PRegIndex, + pub vreg: VRegIndex, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FixedRegFixupLevel { + /// A fixup copy for the initial fixed reg; must come first. + Initial, + /// A fixup copy from the first fixed reg to other fixed regs for + /// the same vreg; must come second. + Secondary, +} + +/// The field order is significant: these are sorted so that a +/// scan over vregs, then blocks in each range, can scan in +/// order through this (sorted) list and add allocs to the +/// half-move list. +/// +/// The fields in this struct are reversed in sort order so that the entire +/// struct can be treated as a u128 for sorting purposes. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(C)] +pub struct BlockparamOut { + pub to_vreg: VRegIndex, + pub to_block: Block, + pub from_block: Block, + pub from_vreg: VRegIndex, +} +impl BlockparamOut { + #[inline(always)] + pub fn key(&self) -> u128 { + u128_key( + self.from_vreg.raw_u32(), + self.from_block.raw_u32(), + self.to_block.raw_u32(), + self.to_vreg.raw_u32(), + ) + } +} + +/// As above for `BlockparamIn`, field order is significant. +/// +/// The fields in this struct are reversed in sort order so that the entire +/// struct can be treated as a u128 for sorting purposes. +#[derive(Clone, Debug)] +#[repr(C)] +pub struct BlockparamIn { + pub from_block: Block, + pub to_block: Block, + pub to_vreg: VRegIndex, +} +impl BlockparamIn { + #[inline(always)] + pub fn key(&self) -> u128 { + u128_key( + self.to_vreg.raw_u32(), + self.to_block.raw_u32(), + self.from_block.raw_u32(), + 0, + ) + } +} + +impl LiveRanges { + pub(crate) fn add(&mut self, range: CodeRange, bump: Bump) -> LiveRangeIndex { + self.push(LiveRange { + range, + vreg: VRegIndex::invalid(), + bundle: LiveBundleIndex::invalid(), + uses_spill_weight_and_flags: 0, + uses: UseList::new_in(bump), + }) + } +} + +impl LiveBundles { + pub(crate) fn add(&mut self, bump: Bump) -> LiveBundleIndex { + self.push(LiveBundle { + allocation: Allocation::none(), + ranges: LiveRangeList::new_in(bump), + spillset: SpillSetIndex::invalid(), + prio: 0, + spill_weight_and_props: 0, + }) + } +} + +impl VRegs { + pub fn add(&mut self, reg: VReg, data: VRegData) -> VRegIndex { + let idx = self.push(data); + debug_assert_eq!(reg.vreg(), idx.index()); + idx + } +} + +impl core::ops::Index for VRegs { + type Output = VRegData; + + #[inline(always)] + fn index(&self, idx: VReg) -> &Self::Output { + &self.storage[idx.vreg()] + } +} + +impl core::ops::IndexMut for VRegs { + #[inline(always)] + fn index_mut(&mut self, idx: VReg) -> &mut Self::Output { + &mut self.storage[idx.vreg()] + } +} + +#[derive(Default)] +pub struct Ctx { + pub(crate) cfginfo: CFGInfo, + pub(crate) cfginfo_ctx: CFGInfoCtx, + pub(crate) liveins: Vec, + pub(crate) liveouts: Vec, + pub(crate) blockparam_outs: Vec, + pub(crate) blockparam_ins: Vec, + + pub(crate) ranges: LiveRanges, + pub(crate) bundles: LiveBundles, + pub(crate) spillsets: SpillSets, + pub(crate) vregs: VRegs, + pub(crate) pregs: Vec, + pub(crate) allocation_queue: PrioQueue, + + pub(crate) spilled_bundles: Vec, + pub(crate) spillslots: Vec, + pub(crate) slots_by_class: [SpillSlotList; 3], + + pub(crate) extra_spillslots_by_class: [SmallVec<[Allocation; 2]>; 3], + pub(crate) preferred_victim_by_class: [PReg; 3], + + // When multiple fixed-register constraints are present on a + // single VReg at a single program point (this can happen for, + // e.g., call args that use the same value multiple times), we + // remove all but one of the fixed-register constraints, make a + // note here, and add a clobber with that PReg instread to keep + // the register available. When we produce the final edit-list, we + // will insert a copy from wherever the VReg's primary allocation + // was to the approprate PReg. + pub(crate) multi_fixed_reg_fixups: Vec, + + pub(crate) allocated_bundle_count: usize, + + // For debug output only: a list of textual annotations at every + // ProgPoint to insert into the final allocated program listing. + pub(crate) debug_annotations: FxHashMap>, + pub(crate) annotations_enabled: bool, + + // Cached allocation for `try_to_allocate_bundle_to_reg` to avoid allocating + // a new HashSet on every call. + pub(crate) conflict_set: FxHashSet, + + // Output: + pub output: Output, + + pub(crate) scratch_conflicts: LiveBundleVec, + pub(crate) scratch_bundle: LiveBundleVec, + pub(crate) scratch_vreg_ranges: Vec, + pub(crate) scratch_spillset_pool: Vec, + + pub(crate) scratch_workqueue: VecDeque, + + pub(crate) scratch_operand_rewrites: FxHashMap, + pub(crate) scratch_removed_lrs: FxHashSet, + pub(crate) scratch_removed_lrs_vregs: FxHashSet, + pub(crate) scratch_workqueue_set: FxHashSet, + + pub(crate) scratch_bump: Bump, +} + +impl Ctx { + pub(crate) fn bump(&self) -> Bump { + self.scratch_bump.clone() + } +} + +pub struct Env<'a, F: Function> { + pub func: &'a F, + pub env: &'a MachineEnv, + pub ctx: &'a mut Ctx, +} + +impl<'a, F: Function> Deref for Env<'a, F> { + type Target = Ctx; + + fn deref(&self) -> &Self::Target { + self.ctx + } +} + +impl<'a, F: Function> DerefMut for Env<'a, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.ctx + } +} + +impl<'a, F: Function> Env<'a, F> { + /// Get the VReg (with bundled RegClass) from a vreg index. + #[inline] + pub fn vreg(&self, index: VRegIndex) -> VReg { + let class = self.vregs[index] + .class + .expect("trying to get a VReg before observing its class"); + VReg::new(index.index(), class) + } + + /// Record the class of a VReg. We learn this only when we observe + /// the VRegs in use. + pub fn observe_vreg_class(&mut self, vreg: VReg) { + let old_class = self.vregs[vreg].class.replace(vreg.class()); + // We should never observe two different classes for two + // mentions of a VReg in the source program. + debug_assert!(old_class == None || old_class == Some(vreg.class())); + } + + /// Is this vreg actually used in the source program? + pub fn is_vreg_used(&self, index: VRegIndex) -> bool { + self.vregs[index].class.is_some() + } +} + +#[derive(Clone, Debug, Default)] +pub struct SpillSetRanges { + pub btree: BTreeMap, +} + +#[derive(Clone, Debug)] +pub struct SpillSlotData { + pub ranges: SpillSetRanges, + pub slots: u32, + pub alloc: Allocation, +} + +#[derive(Clone, Debug, Default)] +pub struct SpillSlotList { + pub slots: SmallVec<[SpillSlotIndex; 32]>, + pub probe_start: usize, +} + +impl SpillSlotList { + /// Get the next spillslot index in probing order, wrapping around + /// at the end of the slots list. + pub(crate) fn next_index(&self, index: usize) -> usize { + debug_assert!(index < self.slots.len()); + if index == self.slots.len() - 1 { + 0 + } else { + index + 1 + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct PrioQueue { + pub heap: alloc::collections::BinaryHeap, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct PrioQueueEntry { + pub prio: u32, + pub bundle: LiveBundleIndex, + pub reg_hint: PReg, +} + +#[derive(Clone, Debug)] +pub struct LiveRangeSet { + pub btree: BTreeMap, +} + +#[derive(Clone, Copy, Debug)] +pub struct LiveRangeKey { + pub from: u32, + pub to: u32, +} + +impl LiveRangeKey { + #[inline(always)] + pub fn from_range(range: &CodeRange) -> Self { + Self { + from: range.from.to_index(), + to: range.to.to_index(), + } + } + + #[inline(always)] + pub fn to_range(&self) -> CodeRange { + CodeRange { + from: ProgPoint::from_index(self.from), + to: ProgPoint::from_index(self.to), + } + } +} + +impl core::cmp::PartialEq for LiveRangeKey { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { + self.to > other.from && self.from < other.to + } +} +impl core::cmp::Eq for LiveRangeKey {} +impl core::cmp::PartialOrd for LiveRangeKey { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl core::cmp::Ord for LiveRangeKey { + #[inline(always)] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + if self.to <= other.from { + core::cmp::Ordering::Less + } else if self.from >= other.to { + core::cmp::Ordering::Greater + } else { + core::cmp::Ordering::Equal + } + } +} + +pub struct PrioQueueComparator<'a> { + pub prios: &'a [usize], +} +impl<'a> ContainerComparator for PrioQueueComparator<'a> { + type Ix = LiveBundleIndex; + fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering { + self.prios[a.index()].cmp(&self.prios[b.index()]) + } +} + +impl PrioQueue { + #[inline(always)] + pub fn insert(&mut self, bundle: LiveBundleIndex, prio: usize, reg_hint: PReg) { + self.heap.push(PrioQueueEntry { + prio: prio as u32, + bundle, + reg_hint, + }); + } + + #[inline(always)] + pub fn is_empty(self) -> bool { + self.heap.is_empty() + } + + #[inline(always)] + pub fn pop(&mut self) -> Option<(LiveBundleIndex, PReg)> { + self.heap.pop().map(|entry| (entry.bundle, entry.reg_hint)) + } +} + +impl LiveRangeSet { + pub(crate) fn new() -> Self { + Self { + btree: BTreeMap::default(), + } + } +} + +#[derive(Clone, Debug)] +pub struct InsertedMove { + pub pos_prio: PosWithPrio, + pub from_alloc: Allocation, + pub to_alloc: Allocation, + pub to_vreg: VReg, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum InsertMovePrio { + InEdgeMoves, + Regular, + MultiFixedRegInitial, + MultiFixedRegSecondary, + ReusedInput, + OutEdgeMoves, +} + +#[derive(Debug, Default)] +pub struct InsertedMoves { + pub moves: Vec, +} + +impl InsertedMoves { + pub fn push( + &mut self, + pos: ProgPoint, + prio: InsertMovePrio, + from_alloc: Allocation, + to_alloc: Allocation, + to_vreg: VReg, + ) { + trace!( + "insert_move: pos {:?} prio {:?} from_alloc {:?} to_alloc {:?} to_vreg {:?}", + pos, + prio, + from_alloc, + to_alloc, + to_vreg + ); + if from_alloc == to_alloc { + trace!(" -> skipping move with same source and dest"); + return; + } + if let Some(from) = from_alloc.as_reg() { + debug_assert_eq!(from.class(), to_vreg.class()); + } + if let Some(to) = to_alloc.as_reg() { + debug_assert_eq!(to.class(), to_vreg.class()); + } + self.moves.push(InsertedMove { + pos_prio: PosWithPrio { + pos, + prio: prio as u32, + }, + from_alloc, + to_alloc, + to_vreg, + }); + } +} + +#[derive(Clone, Debug, Default)] +pub struct Edits { + edits: Vec<(PosWithPrio, Edit)>, +} + +impl Edits { + #[inline(always)] + pub fn with_capacity(n: usize) -> Self { + Self { + edits: Vec::with_capacity(n), + } + } + + #[inline(always)] + pub fn len(&self) -> usize { + self.edits.len() + } + + #[inline(always)] + pub fn iter(&self) -> impl Iterator { + self.edits.iter() + } + + #[inline(always)] + pub fn drain_edits(&mut self) -> impl Iterator + '_ { + self.edits.drain(..).map(|(pos, edit)| (pos.pos, edit)) + } + + /// Sort edits by the combination of their program position and priority. This is a stable sort + /// to preserve the order of the moves the parallel move resolver inserts. + #[inline(always)] + pub fn sort(&mut self) { + self.edits.sort_by_key(|&(pos_prio, _)| pos_prio.key()); + } + + pub fn add(&mut self, pos_prio: PosWithPrio, from: Allocation, to: Allocation) { + if from != to { + if from.is_reg() && to.is_reg() { + debug_assert_eq!(from.as_reg().unwrap().class(), to.as_reg().unwrap().class()); + } + self.edits.push((pos_prio, Edit::Move { from, to })); + } + } +} + +/// The fields in this struct are reversed in sort order so that the entire +/// struct can be treated as a u64 for sorting purposes. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(C)] +pub struct PosWithPrio { + pub prio: u32, + pub pos: ProgPoint, +} + +impl PosWithPrio { + #[inline] + pub fn key(self) -> u64 { + u64_key(self.pos.to_index(), self.prio) + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Stats { + pub livein_blocks: usize, + pub livein_iterations: usize, + pub initial_liverange_count: usize, + pub merged_bundle_count: usize, + pub process_bundle_count: usize, + pub process_bundle_reg_probes_fixed: usize, + pub process_bundle_reg_success_fixed: usize, + pub process_bundle_bounding_range_probe_start_any: usize, + pub process_bundle_bounding_range_probes_any: usize, + pub process_bundle_bounding_range_success_any: usize, + pub process_bundle_reg_probe_start_any: usize, + pub process_bundle_reg_probes_any: usize, + pub process_bundle_reg_success_any: usize, + pub evict_bundle_event: usize, + pub evict_bundle_count: usize, + pub splits: usize, + pub splits_clobbers: usize, + pub splits_hot: usize, + pub splits_conflicts: usize, + pub splits_defs: usize, + pub splits_all: usize, + pub final_liverange_count: usize, + pub final_bundle_count: usize, + pub spill_bundle_count: usize, + pub spill_bundle_reg_probes: usize, + pub spill_bundle_reg_success: usize, + pub blockparam_ins_count: usize, + pub blockparam_outs_count: usize, + pub halfmoves_count: usize, + pub edits_count: usize, +} + +// Helper function for generating sorting keys. The order of arguments is from +// the most significant field to the least significant one. +// +// These work best when the fields are stored in reverse order in memory so that +// they can be loaded with a single u64 load on little-endian machines. +#[inline(always)] +pub fn u64_key(b: u32, a: u32) -> u64 { + a as u64 | (b as u64) << 32 +} +#[inline(always)] +pub fn u128_key(d: u32, c: u32, b: u32, a: u32) -> u128 { + a as u128 | (b as u128) << 32 | (c as u128) << 64 | (d as u128) << 96 +} diff --git a/deps/crates/vendor/regalloc2/src/ion/dump.rs b/deps/crates/vendor/regalloc2/src/ion/dump.rs new file mode 100644 index 00000000000000..abcaaf320b7974 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/dump.rs @@ -0,0 +1,143 @@ +//! Debugging output. + +use alloc::string::ToString; +use alloc::{format, vec}; +use alloc::{string::String, vec::Vec}; + +use super::Env; +use crate::{Block, Function, ProgPoint}; + +impl<'a, F: Function> Env<'a, F> { + pub fn dump_state(&self) { + trace!("Bundles:"); + for (i, b) in self.bundles.iter().enumerate() { + trace!( + "bundle{}: spillset={:?} alloc={:?}", + i, + b.spillset, + b.allocation + ); + for entry in &b.ranges { + trace!( + " * range {:?} -- {:?}: range{}", + entry.range.from, + entry.range.to, + entry.index.index() + ); + } + } + trace!("VRegs:"); + for (i, v) in self.vregs.iter().enumerate() { + trace!("vreg{}:", i); + for entry in &v.ranges { + trace!( + " * range {:?} -- {:?}: range{}", + entry.range.from, + entry.range.to, + entry.index.index() + ); + } + } + trace!("Ranges:"); + for (i, r) in self.ranges.iter().enumerate() { + trace!( + "range{}: range={:?} vreg={:?} bundle={:?} weight={:?}", + i, + r.range, + r.vreg, + r.bundle, + r.uses_spill_weight(), + ); + for u in &r.uses { + trace!(" * use at {:?} (slot {}): {:?}", u.pos, u.slot, u.operand); + } + } + } + + pub fn annotate(&mut self, progpoint: ProgPoint, s: String) { + if self.annotations_enabled { + self.debug_annotations + .entry(progpoint) + .or_insert_with(|| vec![]) + .push(s); + } + } + + pub fn dump_results(&self) { + log::info!("=== REGALLOC RESULTS ==="); + for block in 0..self.func.num_blocks() { + let block = Block::new(block); + log::info!( + "block{}: [succs {:?} preds {:?}]", + block.index(), + self.func + .block_succs(block) + .iter() + .map(|b| b.index()) + .collect::>(), + self.func + .block_preds(block) + .iter() + .map(|b| b.index()) + .collect::>() + ); + for inst in self.func.block_insns(block).iter() { + for annotation in self + .debug_annotations + .get(&ProgPoint::before(inst)) + .map(|v| &v[..]) + .unwrap_or(&[]) + { + log::info!(" inst{}-pre: {}", inst.index(), annotation); + } + let ops = self + .func + .inst_operands(inst) + .iter() + .map(|op| format!("{}", op)) + .collect::>(); + let clobbers = self + .func + .inst_clobbers(inst) + .into_iter() + .map(|preg| format!("{}", preg)) + .collect::>(); + let allocs = (0..ops.len()) + .map(|i| format!("{}", self.get_alloc(inst, i))) + .collect::>(); + let opname = if self.func.is_branch(inst) { + "br" + } else if self.func.is_ret(inst) { + "ret" + } else { + "op" + }; + let args = ops + .iter() + .zip(allocs.iter()) + .map(|(op, alloc)| format!("{} [{}]", op, alloc)) + .collect::>(); + let clobbers = if clobbers.is_empty() { + "".to_string() + } else { + format!(" [clobber: {}]", clobbers.join(", ")) + }; + log::info!( + " inst{}: {} {}{}", + inst.index(), + opname, + args.join(", "), + clobbers + ); + for annotation in self + .debug_annotations + .get(&ProgPoint::after(inst)) + .map(|v| &v[..]) + .unwrap_or(&[]) + { + log::info!(" inst{}-post: {}", inst.index(), annotation); + } + } + } + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/liveranges.rs b/deps/crates/vendor/regalloc2/src/ion/liveranges.rs new file mode 100644 index 00000000000000..c518262bbea2d1 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/liveranges.rs @@ -0,0 +1,888 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Live-range computation. + +use super::{ + CodeRange, Env, LiveRangeFlag, LiveRangeIndex, LiveRangeKey, LiveRangeList, LiveRangeListEntry, + LiveRangeSet, PRegData, PRegIndex, RegClass, Use, VRegData, VRegIndex, +}; +use crate::indexset::IndexSet; +use crate::ion::data_structures::{ + BlockparamIn, BlockparamOut, FixedRegFixupLevel, MultiFixedRegFixup, +}; +use crate::{ + Allocation, Block, Function, Inst, InstPosition, Operand, OperandConstraint, OperandKind, + OperandPos, PReg, ProgPoint, RegAllocError, VReg, VecExt, +}; +use smallvec::{smallvec, SmallVec}; + +/// A spill weight computed for a certain Use. +#[derive(Clone, Copy, Debug)] +pub struct SpillWeight(f32); + +#[inline(always)] +pub fn spill_weight_from_constraint( + constraint: OperandConstraint, + loop_depth: usize, + is_def: bool, +) -> SpillWeight { + // A bonus of 1000 for one loop level, 4000 for two loop levels, + // 16000 for three loop levels, etc. Avoids exponentiation. + let loop_depth = core::cmp::min(10, loop_depth); + let hot_bonus: f32 = (0..loop_depth).fold(1000.0, |a, _| a * 4.0); + let def_bonus: f32 = if is_def { 2000.0 } else { 0.0 }; + let constraint_bonus: f32 = match constraint { + OperandConstraint::Any => 1000.0, + OperandConstraint::Reg | OperandConstraint::FixedReg(_) => 2000.0, + _ => 0.0, + }; + SpillWeight(hot_bonus + def_bonus + constraint_bonus) +} + +impl SpillWeight { + /// Convert a floating-point weight to a u16 that can be compactly + /// stored in a `Use`. We simply take the top 16 bits of the f32; this + /// is equivalent to the bfloat16 format + /// (https://en.wikipedia.org/wiki/Bfloat16_floating-point_format). + pub fn to_bits(self) -> u16 { + (self.0.to_bits() >> 15) as u16 + } + + /// Convert a value that was returned from + /// `SpillWeight::to_bits()` back into a `SpillWeight`. Note that + /// some precision may be lost when round-tripping from a spill + /// weight to packed bits and back. + pub fn from_bits(bits: u16) -> SpillWeight { + let x = f32::from_bits((bits as u32) << 15); + SpillWeight(x) + } + + /// Get a zero spill weight. + pub fn zero() -> SpillWeight { + SpillWeight(0.0) + } + + /// Convert to a raw floating-point value. + pub fn to_f32(self) -> f32 { + self.0 + } + + /// Create a `SpillWeight` from a raw floating-point value. + pub fn from_f32(x: f32) -> SpillWeight { + SpillWeight(x) + } + + pub fn to_int(self) -> u32 { + self.0 as u32 + } +} + +impl core::ops::Add for SpillWeight { + type Output = SpillWeight; + fn add(self, other: SpillWeight) -> Self { + SpillWeight(self.0 + other.0) + } +} + +impl<'a, F: Function> Env<'a, F> { + pub fn create_pregs_and_vregs(&mut self) { + // Create PRegs from the env. + self.pregs.resize( + PReg::NUM_INDEX, + PRegData { + allocations: LiveRangeSet::new(), + is_stack: false, + }, + ); + for &preg in &self.env.fixed_stack_slots { + self.pregs[preg.index()].is_stack = true; + } + for class in 0..self.preferred_victim_by_class.len() { + self.preferred_victim_by_class[class] = self.env.non_preferred_regs_by_class[class] + .last() + .or(self.env.preferred_regs_by_class[class].last()) + .cloned() + .unwrap_or(PReg::invalid()); + } + // Create VRegs from the vreg count. + for idx in 0..self.func.num_vregs() { + // We'll fill in the real details when we see the def. + self.ctx.vregs.add( + VReg::new(idx, RegClass::Int), + VRegData { + ranges: LiveRangeList::new_in(self.ctx.bump()), + blockparam: Block::invalid(), + // We'll learn the RegClass as we scan the code. + class: None, + }, + ); + } + // Create allocations too. + for inst in 0..self.func.num_insts() { + let start = self.output.allocs.len() as u32; + self.output.inst_alloc_offsets.push(start); + for _ in 0..self.func.inst_operands(Inst::new(inst)).len() { + self.output.allocs.push(Allocation::none()); + } + } + } + + /// Mark `range` as live for the given `vreg`. + /// + /// Returns the liverange that contains the given range. + pub fn add_liverange_to_vreg( + &mut self, + vreg: VRegIndex, + mut range: CodeRange, + ) -> LiveRangeIndex { + trace!("add_liverange_to_vreg: vreg {:?} range {:?}", vreg, range); + + // Invariant: as we are building liveness information, we + // *always* process instructions bottom-to-top, and as a + // consequence, new liveranges are always created before any + // existing liveranges for a given vreg. We assert this here, + // then use it to avoid an O(n) merge step (which would lead + // to O(n^2) liveness construction cost overall). + // + // We store liveranges in reverse order in the `.ranges` + // array, then reverse them at the end of + // `compute_liveness()`. + + if !self.vregs[vreg].ranges.is_empty() { + let last_range_index = self.vregs[vreg].ranges.last().unwrap().index; + let last_range = self.ranges[last_range_index].range; + if self.func.allow_multiple_vreg_defs() { + if last_range.contains(&range) { + // Special case (may occur when multiple defs of pinned + // physical regs occur): if this new range overlaps the + // existing range, return it. + return last_range_index; + } + // If this range's end falls in the middle of the last + // range, truncate it to be contiguous so we can merge + // below. + if range.to >= last_range.from && range.to <= last_range.to { + range.to = last_range.from; + } + } + debug_assert!( + range.to <= last_range.from, + "range {:?}, last_range {:?}", + range, + last_range + ); + } + + if self.vregs[vreg].ranges.is_empty() + || range.to + < self.ranges[self.vregs[vreg].ranges.last().unwrap().index] + .range + .from + { + // Is not contiguous with previously-added (immediately + // following) range; create a new range. + let lr = self.ctx.ranges.add(range, self.ctx.bump()); + self.ranges[lr].vreg = vreg; + self.vregs[vreg] + .ranges + .push(LiveRangeListEntry { range, index: lr }); + lr + } else { + // Is contiguous with previously-added range; just extend + // its range and return it. + let lr = self.vregs[vreg].ranges.last().unwrap().index; + debug_assert!(range.to == self.ranges[lr].range.from); + self.ranges[lr].range.from = range.from; + lr + } + } + + pub fn insert_use_into_liverange(&mut self, into: LiveRangeIndex, mut u: Use) { + let operand = u.operand; + let constraint = operand.constraint(); + let block = self.cfginfo.insn_block[u.pos.inst().index()]; + let loop_depth = self.cfginfo.approx_loop_depth[block.index()] as usize; + let weight = spill_weight_from_constraint( + constraint, + loop_depth, + operand.kind() != OperandKind::Use, + ); + u.weight = weight.to_bits(); + + trace!( + "insert use {:?} into lr {:?} with weight {:?}", + u, + into, + weight, + ); + + // N.B.: we do *not* update `requirement` on the range, + // because those will be computed during the multi-fixed-reg + // fixup pass later (after all uses are inserted). + + self.ranges[into].uses.push(u); + + // Update stats. + let range_weight = self.ranges[into].uses_spill_weight() + weight; + self.ranges[into].set_uses_spill_weight(range_weight); + trace!( + " -> now range has weight {:?}", + self.ranges[into].uses_spill_weight(), + ); + } + + pub fn find_vreg_liverange_for_pos( + &self, + vreg: VRegIndex, + pos: ProgPoint, + ) -> Option { + for entry in &self.vregs[vreg].ranges { + if entry.range.contains_point(pos) { + return Some(entry.index); + } + } + None + } + + pub fn add_liverange_to_preg(&mut self, range: CodeRange, reg: PReg) { + trace!("adding liverange to preg: {:?} to {}", range, reg); + let preg_idx = PRegIndex::new(reg.index()); + let res = self.pregs[preg_idx.index()] + .allocations + .btree + .insert(LiveRangeKey::from_range(&range), LiveRangeIndex::invalid()); + debug_assert!(res.is_none()); + } + + pub fn is_live_in(&mut self, block: Block, vreg: VRegIndex) -> bool { + self.liveins[block.index()].get(vreg.index()) + } + + pub fn compute_liveness(&mut self) -> Result<(), RegAllocError> { + // Create initial LiveIn and LiveOut bitsets. + for _ in 0..self.func.num_blocks() { + self.liveins.push(IndexSet::new()); + self.liveouts.push(IndexSet::new()); + } + + // Run a worklist algorithm to precisely compute liveins and + // liveouts. + let mut workqueue = core::mem::take(&mut self.ctx.scratch_workqueue); + let mut workqueue_set = core::mem::take(&mut self.ctx.scratch_workqueue_set); + workqueue_set.clear(); + // Initialize workqueue with postorder traversal. + for &block in &self.cfginfo.postorder[..] { + workqueue.push_back(block); + workqueue_set.insert(block); + } + + while let Some(block) = workqueue.pop_front() { + workqueue_set.remove(&block); + let insns = self.func.block_insns(block); + + trace!("computing liveins for block{}", block.index()); + + self.output.stats.livein_iterations += 1; + + let mut live = self.liveouts[block.index()].clone(); + trace!(" -> initial liveout set: {:?}", live); + + // Include outgoing blockparams in the initial live set. + if self.func.is_branch(insns.last()) { + for i in 0..self.func.block_succs(block).len() { + for ¶m in self.func.branch_blockparams(block, insns.last(), i) { + live.set(param.vreg(), true); + self.observe_vreg_class(param); + } + } + } + + for inst in insns.iter().rev() { + for pos in &[OperandPos::Late, OperandPos::Early] { + for op in self.func.inst_operands(inst) { + if op.as_fixed_nonallocatable().is_some() { + continue; + } + if op.pos() == *pos { + let was_live = live.get(op.vreg().vreg()); + trace!("op {:?} was_live = {}", op, was_live); + match op.kind() { + OperandKind::Use => { + live.set(op.vreg().vreg(), true); + } + OperandKind::Def => { + live.set(op.vreg().vreg(), false); + } + } + self.observe_vreg_class(op.vreg()); + } + } + } + } + for &blockparam in self.func.block_params(block) { + live.set(blockparam.vreg(), false); + self.observe_vreg_class(blockparam); + } + + for &pred in self.func.block_preds(block) { + if self.ctx.liveouts[pred.index()].union_with(&live) { + if !workqueue_set.contains(&pred) { + workqueue_set.insert(pred); + workqueue.push_back(pred); + } + } + } + + trace!("computed liveins at block{}: {:?}", block.index(), live); + self.liveins[block.index()] = live; + } + + // Check that there are no liveins to the entry block. + if !self.liveins[self.func.entry_block().index()].is_empty() { + trace!( + "non-empty liveins to entry block: {:?}", + self.liveins[self.func.entry_block().index()] + ); + return Err(RegAllocError::EntryLivein); + } + + self.ctx.scratch_workqueue = workqueue; + self.ctx.scratch_workqueue_set = workqueue_set; + + Ok(()) + } + + pub fn build_liveranges(&mut self) { + // Create Uses and Defs referring to VRegs, and place the Uses + // in LiveRanges. + // + // We already computed precise liveouts and liveins for every + // block above, so we don't need to run an iterative algorithm + // here; instead, every block's computation is purely local, + // from end to start. + + // Track current LiveRange for each vreg. + // + // Invariant: a stale range may be present here; ranges are + // only valid if `live.get(vreg)` is true. + let mut vreg_ranges = core::mem::take(&mut self.ctx.scratch_vreg_ranges); + vreg_ranges.repopulate(self.func.num_vregs(), LiveRangeIndex::invalid()); + let mut operand_rewrites = core::mem::take(&mut self.ctx.scratch_operand_rewrites); + + for i in (0..self.func.num_blocks()).rev() { + let block = Block::new(i); + let insns = self.func.block_insns(block); + + self.output.stats.livein_blocks += 1; + + // Init our local live-in set. + let mut live = self.liveouts[block.index()].clone(); + + // If the last instruction is a branch (rather than + // return), create blockparam_out entries. + if self.func.is_branch(insns.last()) { + for (i, &succ) in self.func.block_succs(block).iter().enumerate() { + let blockparams_in = self.func.block_params(succ); + let blockparams_out = self.func.branch_blockparams(block, insns.last(), i); + for (&blockparam_in, &blockparam_out) in + blockparams_in.iter().zip(blockparams_out) + { + let blockparam_out = VRegIndex::new(blockparam_out.vreg()); + let blockparam_in = VRegIndex::new(blockparam_in.vreg()); + self.blockparam_outs.push(BlockparamOut { + to_vreg: blockparam_in, + to_block: succ, + from_block: block, + from_vreg: blockparam_out, + }); + + // Include outgoing blockparams in the initial live set. + live.set(blockparam_out.index(), true); + } + } + } + + // Initially, registers are assumed live for the whole block. + for vreg in live.iter() { + let range = CodeRange { + from: self.cfginfo.block_entry[block.index()], + to: self.cfginfo.block_exit[block.index()].next(), + }; + trace!( + "vreg {:?} live at end of block --> create range {:?}", + VRegIndex::new(vreg), + range + ); + let lr = self.add_liverange_to_vreg(VRegIndex::new(vreg), range); + vreg_ranges[vreg] = lr; + } + + // Create vreg data for blockparams. + for ¶m in self.func.block_params(block) { + self.vregs[param].blockparam = block; + } + + // For each instruction, in reverse order, process + // operands and clobbers. + for inst in insns.iter().rev() { + // Mark clobbers with CodeRanges on PRegs. + for clobber in self.func.inst_clobbers(inst) { + // Clobber range is at After point only: an + // instruction can still take an input in a reg + // that it later clobbers. (In other words, the + // clobber is like a normal def that never gets + // used.) + let range = CodeRange { + from: ProgPoint::after(inst), + to: ProgPoint::before(inst.next()), + }; + self.add_liverange_to_preg(range, clobber); + } + + // Does the instruction have any input-reusing + // outputs? This is important below to establish + // proper interference wrt other inputs. We note the + // *vreg* that is reused, not the index. + let mut reused_input = None; + for op in self.func.inst_operands(inst) { + if let OperandConstraint::Reuse(i) = op.constraint() { + debug_assert!(self.func.inst_operands(inst)[i] + .as_fixed_nonallocatable() + .is_none()); + reused_input = Some(self.func.inst_operands(inst)[i].vreg()); + break; + } + } + + // Preprocess defs and uses. Specifically, if there + // are any fixed-reg-constrained defs at Late position + // and fixed-reg-constrained uses at Early position + // with the same preg, we need to (i) add a fixup move + // for the use, (ii) rewrite the use to have an Any + // constraint, and (ii) move the def to Early position + // to reserve the register for the whole instruction. + // + // We don't touch any fixed-early-def or fixed-late-use + // constraints: the only situation where the same physical + // register can be used multiple times in the same + // instruction is with an early-use and a late-def. Anything + // else is a user error. + operand_rewrites.clear(); + let mut late_def_fixed: SmallVec<[PReg; 8]> = smallvec![]; + for &operand in self.func.inst_operands(inst) { + if let OperandConstraint::FixedReg(preg) = operand.constraint() { + match (operand.pos(), operand.kind()) { + (OperandPos::Late, OperandKind::Def) => { + late_def_fixed.push(preg); + } + _ => {} + } + } + } + for (i, &operand) in self.func.inst_operands(inst).iter().enumerate() { + if operand.as_fixed_nonallocatable().is_some() { + continue; + } + if let OperandConstraint::FixedReg(preg) = operand.constraint() { + match (operand.pos(), operand.kind()) { + (OperandPos::Early, OperandKind::Use) + if live.get(operand.vreg().vreg()) => + { + // If we have a use constraint at the + // Early point for a fixed preg, and + // this preg is also constrained with + // a *separate* def at Late or is + // clobbered, and *if* the vreg is + // live downward, we have to use the + // multi-fixed-reg mechanism for a + // fixup and rewrite here without the + // constraint. See #53. + // + // We adjust the def liverange and Use + // to an "early" position to reserve + // the register, it still must not be + // used by some other vreg at the + // use-site. + // + // Note that we handle multiple + // conflicting constraints for the + // same vreg in a separate pass (see + // `fixup_multi_fixed_vregs` below). + if late_def_fixed.contains(&preg) + || self.func.inst_clobbers(inst).contains(preg) + { + trace!( + concat!( + "-> operand {:?} is fixed to preg {:?}, ", + "is downward live, and there is also a ", + "def or clobber at this preg" + ), + operand, + preg + ); + let pos = ProgPoint::before(inst); + self.multi_fixed_reg_fixups.push(MultiFixedRegFixup { + pos, + from_slot: i as u8, + to_slot: i as u8, + to_preg: PRegIndex::new(preg.index()), + vreg: VRegIndex::new(operand.vreg().vreg()), + level: FixedRegFixupLevel::Initial, + }); + + // We need to insert a reservation + // at the before-point to reserve + // the reg for the use too. + let range = CodeRange::singleton(pos); + self.add_liverange_to_preg(range, preg); + + // Remove the fixed-preg + // constraint from the Use. + operand_rewrites.insert( + i, + Operand::new( + operand.vreg(), + OperandConstraint::Any, + operand.kind(), + operand.pos(), + ), + ); + } + } + _ => {} + } + } + } + + // Process defs and uses. + for &cur_pos in &[InstPosition::After, InstPosition::Before] { + for i in 0..self.func.inst_operands(inst).len() { + // don't borrow `self` + let operand = operand_rewrites + .get(&i) + .cloned() + .unwrap_or(self.func.inst_operands(inst)[i]); + let pos = match (operand.kind(), operand.pos()) { + (OperandKind::Def, OperandPos::Early) => ProgPoint::before(inst), + (OperandKind::Def, OperandPos::Late) => ProgPoint::after(inst), + (OperandKind::Use, OperandPos::Late) => ProgPoint::after(inst), + // If there are any reused inputs in this + // instruction, and this is *not* the + // reused vreg, force `pos` to + // `After`. This ensures that we correctly + // account for the interference between + // the other inputs and the + // input-that-is-reused/output. + (OperandKind::Use, OperandPos::Early) + if reused_input.is_some() + && reused_input.unwrap() != operand.vreg() => + { + ProgPoint::after(inst) + } + (OperandKind::Use, OperandPos::Early) => ProgPoint::before(inst), + }; + + if pos.pos() != cur_pos { + continue; + } + + trace!( + "processing inst{} operand at {:?}: {:?}", + inst.index(), + pos, + operand + ); + + // If this is a "fixed non-allocatable + // register" operand, set the alloc + // immediately and then ignore the operand + // hereafter. + if let Some(preg) = operand.as_fixed_nonallocatable() { + self.set_alloc(inst, i, Allocation::reg(preg)); + continue; + } + + match operand.kind() { + OperandKind::Def => { + trace!("Def of {} at {:?}", operand.vreg(), pos); + + // Get or create the LiveRange. + let mut lr = vreg_ranges[operand.vreg().vreg()]; + trace!(" -> has existing LR {:?}", lr); + // If there was no liverange (dead def), create a trivial one. + if !live.get(operand.vreg().vreg()) { + let from = pos; + // We want to we want to span + // until Before of the next + // inst. This ensures that early + // defs used for temps on an + // instruction are reserved across + // the whole instruction. + let to = ProgPoint::before(pos.inst().next()); + lr = self.add_liverange_to_vreg( + VRegIndex::new(operand.vreg().vreg()), + CodeRange { from, to }, + ); + trace!(" -> invalid; created {:?}", lr); + vreg_ranges[operand.vreg().vreg()] = lr; + live.set(operand.vreg().vreg(), true); + } + // Create the use in the LiveRange. + self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8)); + // If def (not mod), this reg is now dead, + // scanning backward; make it so. + if operand.kind() == OperandKind::Def { + // Trim the range for this vreg to start + // at `pos` if it previously ended at the + // start of this block (i.e. was not + // merged into some larger LiveRange due + // to out-of-order blocks). + if self.ranges[lr].range.from + == self.cfginfo.block_entry[block.index()] + { + trace!(" -> started at block start; trimming to {:?}", pos); + self.ranges[lr].range.from = pos; + } + + self.ranges[lr].set_flag(LiveRangeFlag::StartsAtDef); + + // Remove from live-set. + live.set(operand.vreg().vreg(), false); + vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid(); + } + } + OperandKind::Use => { + // Create/extend the LiveRange if it + // doesn't already exist, and add the use + // to the range. + let mut lr = vreg_ranges[operand.vreg().vreg()]; + if !live.get(operand.vreg().vreg()) { + let range = CodeRange { + from: self.cfginfo.block_entry[block.index()], + to: pos.next(), + }; + lr = self.add_liverange_to_vreg( + VRegIndex::new(operand.vreg().vreg()), + range, + ); + vreg_ranges[operand.vreg().vreg()] = lr; + } + debug_assert!(lr.is_valid()); + + trace!("Use of {:?} at {:?} -> {:?}", operand, pos, lr,); + + self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8)); + + // Add to live-set. + live.set(operand.vreg().vreg(), true); + } + } + } + } + } + + // Block parameters define vregs at the very beginning of + // the block. Remove their live vregs from the live set + // here. + for vreg in self.func.block_params(block) { + if live.get(vreg.vreg()) { + live.set(vreg.vreg(), false); + } else { + // Create trivial liverange if blockparam is dead. + let start = self.cfginfo.block_entry[block.index()]; + self.add_liverange_to_vreg( + VRegIndex::new(vreg.vreg()), + CodeRange { + from: start, + to: start.next(), + }, + ); + } + // add `blockparam_ins` entries. + let vreg_idx = VRegIndex::new(vreg.vreg()); + for &pred in self.func.block_preds(block) { + self.blockparam_ins.push(BlockparamIn { + to_vreg: vreg_idx, + to_block: block, + from_block: pred, + }); + } + } + } + + // Make ranges in each vreg and uses in each range appear in + // sorted order. We built them in reverse order above, so this + // is a simple reversal, *not* a full sort. + // + // The ordering invariant is always maintained for uses and + // always for ranges in bundles (which are initialized later), + // but not always for ranges in vregs; those are sorted only + // when needed, here and then again at the end of allocation + // when resolving moves. + + for vreg in &mut self.ctx.vregs { + vreg.ranges.reverse(); + let mut last = None; + for entry in &mut vreg.ranges { + // Ranges may have been truncated above at defs. We + // need to update with the final range here. + entry.range = self.ctx.ranges[entry.index].range; + // Assert in-order and non-overlapping. + debug_assert!(last.is_none() || last.unwrap() <= entry.range.from); + last = Some(entry.range.to); + } + } + + for range in &mut self.ranges { + range.uses.reverse(); + debug_assert!(range.uses.windows(2).all(|win| win[0].pos <= win[1].pos)); + } + + self.blockparam_ins.sort_unstable_by_key(|x| x.key()); + self.blockparam_outs.sort_unstable_by_key(|x| x.key()); + + self.output.stats.initial_liverange_count = self.ranges.len(); + self.output.stats.blockparam_ins_count = self.blockparam_ins.len(); + self.output.stats.blockparam_outs_count = self.blockparam_outs.len(); + self.ctx.scratch_vreg_ranges = vreg_ranges; + self.ctx.scratch_operand_rewrites = operand_rewrites; + } + + pub fn fixup_multi_fixed_vregs(&mut self) { + // Do a fixed-reg cleanup pass: if there are any LiveRanges with + // multiple uses at the same ProgPoint and there is + // more than one FixedReg constraint at that ProgPoint, we + // need to record all but one of them in a special fixup list + // and handle them later; otherwise, bundle-splitting to + // create minimal bundles becomes much more complex (we would + // have to split the multiple uses at the same progpoint into + // different bundles, which breaks invariants related to + // disjoint ranges and bundles). + let mut extra_clobbers: SmallVec<[(PReg, ProgPoint); 8]> = smallvec![]; + for vreg in 0..self.vregs.len() { + let vreg = VRegIndex::new(vreg); + for range_idx in 0..self.vregs[vreg].ranges.len() { + let entry = self.vregs[vreg].ranges[range_idx]; + let range = entry.index; + trace!("multi-fixed-reg cleanup: vreg {:?} range {:?}", vreg, range,); + + // Find groups of uses that occur in at the same program point. + for uses in self.ctx.ranges[range] + .uses + .chunk_by_mut(|a, b| a.pos == b.pos) + { + if uses.len() < 2 { + continue; + } + + // Search for conflicting constraints in the uses. + let mut requires_reg = false; + let mut num_fixed_reg = 0; + let mut num_fixed_stack = 0; + let mut first_reg_slot = None; + let mut first_stack_slot = None; + for u in uses.iter() { + match u.operand.constraint() { + OperandConstraint::Any => { + first_reg_slot.get_or_insert(u.slot); + first_stack_slot.get_or_insert(u.slot); + } + OperandConstraint::Reg | OperandConstraint::Reuse(_) => { + first_reg_slot.get_or_insert(u.slot); + requires_reg = true; + } + OperandConstraint::FixedReg(preg) => { + if self.ctx.pregs[preg.index()].is_stack { + num_fixed_stack += 1; + first_stack_slot.get_or_insert(u.slot); + } else { + requires_reg = true; + num_fixed_reg += 1; + first_reg_slot.get_or_insert(u.slot); + } + } + } + } + + // Fast path if there are no conflicts. + if num_fixed_reg + num_fixed_stack <= 1 + && !(requires_reg && num_fixed_stack != 0) + { + continue; + } + + // We pick one constraint (in order: FixedReg, Reg, FixedStack) + // and then rewrite any incompatible constraints to Any. + // This allows register allocation to succeed and we will + // later insert moves to satisfy the rewritten constraints. + let source_slot = if requires_reg { + first_reg_slot.unwrap() + } else { + first_stack_slot.unwrap() + }; + let mut first_preg = None; + for u in uses.iter_mut() { + if let OperandConstraint::FixedReg(preg) = u.operand.constraint() { + let vreg_idx = VRegIndex::new(u.operand.vreg().vreg()); + let preg_idx = PRegIndex::new(preg.index()); + trace!( + "at pos {:?}, vreg {:?} has fixed constraint to preg {:?}", + u.pos, + vreg_idx, + preg_idx + ); + + // FixedStack is incompatible if there are any + // Reg/FixedReg constraints. FixedReg is + // incompatible if there already is a different + // FixedReg constraint. If either condition is true, + // we edit the constraint below; otherwise, we can + // skip this edit. + if !(requires_reg && self.ctx.pregs[preg.index()].is_stack) + && *first_preg.get_or_insert(preg) == preg + { + continue; + } + + trace!(" -> duplicate; switching to constraint Any"); + self.ctx.multi_fixed_reg_fixups.push(MultiFixedRegFixup { + pos: u.pos, + from_slot: source_slot, + to_slot: u.slot, + to_preg: preg_idx, + vreg: vreg_idx, + level: FixedRegFixupLevel::Secondary, + }); + u.operand = Operand::new( + u.operand.vreg(), + OperandConstraint::Any, + u.operand.kind(), + u.operand.pos(), + ); + trace!(" -> extra clobber {} at inst{}", preg, u.pos.inst().index()); + extra_clobbers.push((preg, u.pos)); + } + } + } + + for (clobber, pos) in extra_clobbers.drain(..) { + let range = CodeRange { + from: pos, + to: pos.next(), + }; + self.add_liverange_to_preg(range, clobber); + } + } + } + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/merge.rs b/deps/crates/vendor/regalloc2/src/ion/merge.rs new file mode 100644 index 00000000000000..f503acf15e0a2d --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/merge.rs @@ -0,0 +1,385 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Bundle merging. + +use super::{Env, LiveBundleIndex, SpillSet, SpillSlotIndex, VRegIndex}; +use crate::{ + ion::{ + data_structures::{BlockparamOut, CodeRange}, + LiveRangeList, + }, + Function, Inst, OperandConstraint, OperandKind, PReg, ProgPoint, +}; +use alloc::format; + +impl<'a, F: Function> Env<'a, F> { + pub fn merge_bundles(&mut self, from: LiveBundleIndex, to: LiveBundleIndex) -> bool { + if from == to { + // Merge bundle into self -- trivial merge. + return true; + } + trace!( + "merging from bundle{} to bundle{}", + from.index(), + to.index() + ); + + // Both bundles must deal with the same RegClass. + let from_rc = self.spillsets[self.bundles[from].spillset].class; + let to_rc = self.spillsets[self.bundles[to].spillset].class; + if from_rc != to_rc { + trace!(" -> mismatching reg classes"); + return false; + } + + // If either bundle is already assigned (due to a pinned vreg), don't merge. + if self.bundles[from].allocation.is_some() || self.bundles[to].allocation.is_some() { + trace!("one of the bundles is already assigned (pinned)"); + return false; + } + + #[cfg(debug_assertions)] + { + // Sanity check: both bundles should contain only ranges with appropriate VReg classes. + for entry in &self.bundles[from].ranges { + let vreg = self.ranges[entry.index].vreg; + debug_assert_eq!(from_rc, self.vreg(vreg).class()); + } + for entry in &self.bundles[to].ranges { + let vreg = self.ranges[entry.index].vreg; + debug_assert_eq!(to_rc, self.vreg(vreg).class()); + } + } + + // If a bundle has a fixed-reg def then we need to be careful to not + // extend the bundle to include another use in the same instruction. + // This could result in a minimal bundle that is impossible to split. + // + // This can only happen with an early use and a late def, so we round + // the start of each range containing a fixed def up to the start of + // its instruction to detect overlaps. + let adjust_range_start = |bundle_idx, range: CodeRange| { + if self.bundles[bundle_idx].cached_fixed_def() { + ProgPoint::before(range.from.inst()) + } else { + range.from + } + }; + + // Check for overlap in LiveRanges and for conflicting + // requirements. + let ranges_from = &self.bundles[from].ranges[..]; + let ranges_to = &self.bundles[to].ranges[..]; + let mut idx_from = 0; + let mut idx_to = 0; + let mut range_count = 0; + while idx_from < ranges_from.len() && idx_to < ranges_to.len() { + range_count += 1; + if range_count > 200 { + trace!( + "reached merge complexity (range_count = {}); exiting", + range_count + ); + // Limit merge complexity. + return false; + } + + if adjust_range_start(from, ranges_from[idx_from].range) >= ranges_to[idx_to].range.to { + idx_to += 1; + } else if adjust_range_start(to, ranges_to[idx_to].range) + >= ranges_from[idx_from].range.to + { + idx_from += 1; + } else { + // Overlap -- cannot merge. + trace!( + " -> overlap between {:?} and {:?}, exiting", + ranges_from[idx_from].index, + ranges_to[idx_to].index + ); + return false; + } + } + + // Check for a requirements conflict. + if self.bundles[from].cached_fixed() || self.bundles[to].cached_fixed() { + if self.merge_bundle_requirements(from, to).is_err() { + trace!(" -> conflicting requirements; aborting merge"); + return false; + } + } + + trace!(" -> committing to merge"); + + // If we reach here, then the bundles do not overlap -- merge + // them! We do this with a merge-sort-like scan over both + // lists, building a new range list and replacing the list on + // `to` when we're done. + if ranges_from.is_empty() { + // `from` bundle is empty -- trivial merge. + trace!(" -> from bundle{} is empty; trivial merge", from.index()); + return true; + } + if ranges_to.is_empty() { + // `to` bundle is empty -- just move the list over from + // `from` and set `bundle` up-link on all ranges. + trace!(" -> to bundle{} is empty; trivial merge", to.index()); + let empty_vec = LiveRangeList::new_in(self.ctx.bump()); + let list = core::mem::replace(&mut self.bundles[from].ranges, empty_vec); + for entry in &list { + self.ranges[entry.index].bundle = to; + + if self.annotations_enabled { + self.annotate( + entry.range.from, + format!( + " MERGE range{} v{} from bundle{} to bundle{}", + entry.index.index(), + self.ranges[entry.index].vreg.index(), + from.index(), + to.index(), + ), + ); + } + } + self.bundles[to].ranges = list; + + if self.bundles[from].cached_fixed() { + self.bundles[to].set_cached_fixed(); + } + if self.bundles[from].cached_fixed_def() { + self.bundles[to].set_cached_fixed_def(); + } + + return true; + } + + trace!( + "merging: ranges_from = {:?} ranges_to = {:?}", + ranges_from, + ranges_to + ); + + let empty_vec = LiveRangeList::new_in(self.ctx.bump()); + let mut from_list = core::mem::replace(&mut self.bundles[from].ranges, empty_vec); + for entry in &from_list { + self.ranges[entry.index].bundle = to; + } + + if from_list.len() == 1 { + // Optimize for the common case where `from_list` contains a single + // item. Using a binary search to find the insertion point and then + // calling `insert` is more efficient than re-sorting the entire + // list, specially after the changes in sorting algorithms introduced + // in rustc 1.81. + // See: https://github.com/bytecodealliance/regalloc2/issues/203 + let single_entry = from_list.pop().unwrap(); + let pos = self.bundles[to] + .ranges + .binary_search_by_key(&single_entry.range.from, |entry| entry.range.from) + .unwrap_or_else(|pos| pos); + self.bundles[to].ranges.insert(pos, single_entry); + } else { + // Two non-empty lists of LiveRanges: concatenate and sort. This is + // faster than a mergesort-like merge into a new list, empirically. + self.bundles[to].ranges.extend_from_slice(&from_list[..]); + self.bundles[to] + .ranges + .sort_unstable_by_key(|entry| entry.range.from); + } + + if self.annotations_enabled { + trace!("merging: merged = {:?}", self.bundles[to].ranges); + let mut last_range = None; + for i in 0..self.bundles[to].ranges.len() { + let entry = self.bundles[to].ranges[i]; + if last_range.is_some() { + debug_assert!(last_range.unwrap() < entry.range); + } + last_range = Some(entry.range); + + if self.ranges[entry.index].bundle == from { + self.annotate( + entry.range.from, + format!( + " MERGE range{} v{} from bundle{} to bundle{}", + entry.index.index(), + self.ranges[entry.index].vreg.index(), + from.index(), + to.index(), + ), + ); + } + + trace!( + " -> merged result for bundle{}: range{}", + to.index(), + entry.index.index(), + ); + } + } + + if self.bundles[from].spillset != self.bundles[to].spillset { + // Widen the range for the target spillset to include the one being merged in. + let from_range = self.spillsets[self.bundles[from].spillset].range; + let to_range = &mut self.ctx.spillsets[self.ctx.bundles[to].spillset].range; + *to_range = to_range.join(from_range); + } + + if self.bundles[from].cached_fixed() { + self.bundles[to].set_cached_fixed(); + } + if self.bundles[from].cached_fixed_def() { + self.bundles[to].set_cached_fixed_def(); + } + + true + } + + pub fn merge_vreg_bundles(&mut self) { + // Create a bundle for every vreg, initially. + trace!("merge_vreg_bundles: creating vreg bundles"); + for vreg in 0..self.vregs.len() { + let vreg = VRegIndex::new(vreg); + if self.vregs[vreg].ranges.is_empty() { + continue; + } + + let bundle = self.ctx.bundles.add(self.ctx.bump()); + let mut range = self.vregs[vreg].ranges.first().unwrap().range; + + self.bundles[bundle].ranges = self.vregs[vreg].ranges.clone(); + trace!("vreg v{} gets bundle{}", vreg.index(), bundle.index()); + for entry in &self.ctx.bundles[bundle].ranges { + trace!( + " -> with LR range{}: {:?}", + entry.index.index(), + entry.range + ); + range = range.join(entry.range); + self.ctx.ranges[entry.index].bundle = bundle; + } + + let mut fixed = false; + let mut fixed_def = false; + for entry in &self.bundles[bundle].ranges { + for u in &self.ranges[entry.index].uses { + if let OperandConstraint::FixedReg(_) = u.operand.constraint() { + fixed = true; + if u.operand.kind() == OperandKind::Def { + fixed_def = true; + } + } + if fixed && fixed_def { + break; + } + } + } + if fixed { + self.bundles[bundle].set_cached_fixed(); + } + if fixed_def { + self.bundles[bundle].set_cached_fixed_def(); + } + + // Create a spillslot for this bundle. + let reg = self.vreg(vreg); + let ssidx = self.spillsets.push(SpillSet { + slot: SpillSlotIndex::invalid(), + required: false, + class: reg.class(), + reg_hint: PReg::invalid(), + spill_bundle: LiveBundleIndex::invalid(), + splits: 0, + range, + }); + self.bundles[bundle].spillset = ssidx; + } + + for inst in 0..self.func.num_insts() { + let inst = Inst::new(inst); + + // Attempt to merge Reuse-constraint operand outputs with the + // corresponding inputs. + for op in self.func.inst_operands(inst) { + if let OperandConstraint::Reuse(reuse_idx) = op.constraint() { + let src_vreg = op.vreg(); + let dst_vreg = self.func.inst_operands(inst)[reuse_idx].vreg(); + + trace!( + "trying to merge reused-input def: src {} to dst {}", + src_vreg, + dst_vreg + ); + let src_bundle = self.ranges[self.vregs[src_vreg].ranges[0].index].bundle; + debug_assert!(src_bundle.is_valid()); + let dest_bundle = self.ranges[self.vregs[dst_vreg].ranges[0].index].bundle; + debug_assert!(dest_bundle.is_valid()); + self.merge_bundles(/* from */ dest_bundle, /* to */ src_bundle); + } + } + } + + // Attempt to merge blockparams with their inputs. + for i in 0..self.blockparam_outs.len() { + let BlockparamOut { + from_vreg, to_vreg, .. + } = self.blockparam_outs[i]; + trace!( + "trying to merge blockparam v{} with input v{}", + to_vreg.index(), + from_vreg.index() + ); + let to_bundle = self.ranges[self.vregs[to_vreg].ranges[0].index].bundle; + debug_assert!(to_bundle.is_valid()); + let from_bundle = self.ranges[self.vregs[from_vreg].ranges[0].index].bundle; + debug_assert!(from_bundle.is_valid()); + trace!( + " -> from bundle{} to bundle{}", + from_bundle.index(), + to_bundle.index() + ); + self.merge_bundles(from_bundle, to_bundle); + } + + trace!("done merging bundles"); + } + + pub fn compute_bundle_prio(&self, bundle: LiveBundleIndex) -> u32 { + // The priority is simply the total "length" -- the number of + // instructions covered by all LiveRanges. + let mut total = 0; + for entry in &self.bundles[bundle].ranges { + total += entry.range.len() as u32; + } + total + } + + pub fn queue_bundles(&mut self) { + for bundle in 0..self.bundles.len() { + trace!("enqueueing bundle{}", bundle); + let bundle = LiveBundleIndex::new(bundle); + if self.bundles[bundle].ranges.is_empty() { + trace!(" -> no ranges; skipping"); + continue; + } + let prio = self.compute_bundle_prio(bundle); + trace!(" -> prio {}", prio); + self.bundles[bundle].prio = prio; + self.recompute_bundle_properties(bundle); + self.allocation_queue + .insert(bundle, prio as usize, PReg::invalid()); + } + self.output.stats.merged_bundle_count = self.allocation_queue.heap.len(); + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/mod.rs b/deps/crates/vendor/regalloc2/src/ion/mod.rs new file mode 100644 index 00000000000000..0de5f87ad0d354 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/mod.rs @@ -0,0 +1,131 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Backtracking register allocator. See doc/DESIGN.md for details of +//! its design. + +use crate::ssa::validate_ssa; +use crate::{Function, MachineEnv, PReg, RegAllocError, RegClass, VecExt}; +pub(crate) mod data_structures; +pub use data_structures::Ctx; +pub use data_structures::Stats; +use data_structures::*; +pub(crate) mod reg_traversal; +use reg_traversal::*; +pub(crate) mod requirement; +use requirement::*; +pub(crate) mod redundant_moves; +use redundant_moves::*; +pub(crate) mod liveranges; +use liveranges::*; +pub(crate) mod merge; +pub(crate) mod process; +use process::*; +use smallvec::smallvec; +pub(crate) mod dump; +pub(crate) mod moves; +pub(crate) mod spill; + +impl<'a, F: Function> Env<'a, F> { + pub(crate) fn new(func: &'a F, env: &'a MachineEnv, ctx: &'a mut Ctx) -> Self { + let ninstrs = func.num_insts(); + let nblocks = func.num_blocks(); + + ctx.liveins.preallocate(nblocks); + ctx.liveouts.preallocate(nblocks); + ctx.blockparam_ins.clear(); + ctx.blockparam_outs.clear(); + ctx.ranges.preallocate(4 * ninstrs); + ctx.bundles.preallocate(ninstrs); + ctx.spillsets.preallocate(ninstrs); + ctx.vregs.preallocate(ninstrs); + for preg in ctx.pregs.iter_mut() { + preg.is_stack = false; + preg.allocations.btree.clear(); + } + ctx.allocation_queue.heap.clear(); + ctx.spilled_bundles.clear(); + ctx.scratch_spillset_pool + .extend(ctx.spillslots.drain(..).map(|mut s| { + s.ranges.btree.clear(); + s.ranges + })); + ctx.slots_by_class = core::array::from_fn(|_| SpillSlotList::default()); + ctx.extra_spillslots_by_class = core::array::from_fn(|_| smallvec![]); + ctx.preferred_victim_by_class = [PReg::invalid(); 3]; + ctx.multi_fixed_reg_fixups.clear(); + ctx.allocated_bundle_count = 0; + ctx.debug_annotations.clear(); + ctx.scratch_bump + .get_mut() + .expect("we dropped all refs to this") + .reset(); + + ctx.output.allocs.preallocate(4 * ninstrs); + ctx.output.inst_alloc_offsets.clear(); + ctx.output.num_spillslots = 0; + ctx.output.debug_locations.clear(); + ctx.output.edits.clear(); + ctx.output.stats = Stats::default(); + + Self { func, env, ctx } + } + + pub(crate) fn init(&mut self) -> Result<(), RegAllocError> { + self.create_pregs_and_vregs(); + self.compute_liveness()?; + self.build_liveranges(); + self.fixup_multi_fixed_vregs(); + self.merge_vreg_bundles(); + self.queue_bundles(); + if trace_enabled!() { + self.dump_state(); + } + Ok(()) + } + + pub(crate) fn run(&mut self) -> Result { + self.process_bundles()?; + self.try_allocating_regs_for_spilled_bundles(); + self.allocate_spillslots(); + let moves = self.apply_allocations_and_insert_moves(); + Ok(self.resolve_inserted_moves(moves)) + } +} + +pub fn run( + func: &F, + mach_env: &MachineEnv, + ctx: &mut Ctx, + enable_annotations: bool, + enable_ssa_checker: bool, +) -> Result<(), RegAllocError> { + ctx.cfginfo.init(func, &mut ctx.cfginfo_ctx)?; + + if enable_ssa_checker { + validate_ssa(func, &ctx.cfginfo)?; + } + + ctx.annotations_enabled = enable_annotations; + let mut env = Env::new(func, mach_env, ctx); + env.init()?; + + let mut edits = env.run()?; + + if enable_annotations { + env.dump_results(); + } + + ctx.output.edits.extend(edits.drain_edits()); + + Ok(()) +} diff --git a/deps/crates/vendor/regalloc2/src/ion/moves.rs b/deps/crates/vendor/regalloc2/src/ion/moves.rs new file mode 100644 index 00000000000000..22685e53ae3da1 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/moves.rs @@ -0,0 +1,1013 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Move resolution. + +use alloc::vec; + +use super::{ + Env, InsertMovePrio, InsertedMove, InsertedMoves, LiveRangeFlag, LiveRangeIndex, + RedundantMoveEliminator, VRegIndex, +}; +use crate::ion::data_structures::{ + u64_key, BlockparamIn, BlockparamOut, CodeRange, Edits, FixedRegFixupLevel, LiveRangeKey, + LiveRangeListEntry, +}; +use crate::ion::reg_traversal::RegTraversalIter; +use crate::moves::{MoveAndScratchResolver, ParallelMoves}; +use crate::{ + Allocation, Block, Edit, Function, FxHashMap, Inst, InstPosition, OperandConstraint, + OperandKind, OperandPos, PReg, ProgPoint, RegClass, SpillSlot, +}; +use alloc::format; +use alloc::vec::Vec; +use hashbrown::hash_map::Entry; +use smallvec::{smallvec, SmallVec}; + +impl<'a, F: Function> Env<'a, F> { + pub fn is_start_of_block(&self, pos: ProgPoint) -> bool { + let block = self.ctx.cfginfo.insn_block[pos.inst().index()]; + pos == self.ctx.cfginfo.block_entry[block.index()] + } + pub fn is_end_of_block(&self, pos: ProgPoint) -> bool { + let block = self.ctx.cfginfo.insn_block[pos.inst().index()]; + pos == self.ctx.cfginfo.block_exit[block.index()] + } + + pub fn get_alloc(&self, inst: Inst, slot: usize) -> Allocation { + let inst_allocs = + &self.ctx.output.allocs[self.ctx.output.inst_alloc_offsets[inst.index()] as usize..]; + inst_allocs[slot] + } + + pub fn set_alloc(&mut self, inst: Inst, slot: usize, alloc: Allocation) { + let inst_allocs = &mut self.ctx.output.allocs + [self.ctx.output.inst_alloc_offsets[inst.index()] as usize..]; + inst_allocs[slot] = alloc; + } + + pub fn get_alloc_for_range(&self, range: LiveRangeIndex) -> Allocation { + trace!("get_alloc_for_range: {:?}", range); + let bundle = self.ctx.ranges[range].bundle; + trace!(" -> bundle: {:?}", bundle); + let bundledata = &self.ctx.bundles[bundle]; + trace!(" -> allocation {:?}", bundledata.allocation); + if bundledata.allocation != Allocation::none() { + bundledata.allocation + } else { + trace!(" -> spillset {:?}", bundledata.spillset); + trace!( + " -> spill slot {:?}", + self.ctx.spillsets[bundledata.spillset].slot + ); + self.ctx.spillslots[self.ctx.spillsets[bundledata.spillset].slot.index()].alloc + } + } + + pub fn apply_allocations_and_insert_moves(&mut self) -> InsertedMoves { + trace!("apply_allocations_and_insert_moves"); + trace!("blockparam_ins: {:?}", self.blockparam_ins); + trace!("blockparam_outs: {:?}", self.blockparam_outs); + + let mut inserted_moves = InsertedMoves::default(); + + // Now that all splits are done, we can pay the cost once to + // sort VReg range lists and update with the final ranges. + for vreg in &mut self.ctx.vregs { + for entry in &mut vreg.ranges { + entry.range = self.ctx.ranges[entry.index].range; + } + vreg.ranges.sort_unstable_by_key(|entry| entry.range.from); + } + + /// Buffered information about the previous liverange that was processed. + struct PrevBuffer { + prev: Option, + prev_ins_idx: usize, + buffered: Option, + buffered_ins_idx: usize, + } + + impl PrevBuffer { + fn new(prev_ins_idx: usize) -> Self { + Self { + prev: None, + prev_ins_idx, + buffered: None, + buffered_ins_idx: prev_ins_idx, + } + } + + /// Returns the previous `LiveRangeListEntry` when it's present. + #[inline(always)] + fn is_valid(&self) -> Option { + self.prev + } + + /// Fetch the current index into the `Env::blockparam_ins` vector. + #[inline(always)] + fn blockparam_ins_idx(&self) -> usize { + self.prev_ins_idx + } + + /// Record this index as the next index to use when the previous liverange buffer + /// anvances. + #[inline(always)] + fn update_blockparam_ins_idx(&mut self, idx: usize) { + self.buffered_ins_idx = idx; + } + + /// As overlapping liveranges might start at the same program point, we buffer the + /// previous liverange used when determining where to take the last value from for + /// intra-block moves. The liveranges we process are buffered until we encounter one + /// that starts at a later program point, indicating that it's now safe to advance the + /// previous LR buffer. We accumulate the longest-lived liverange in the buffer as a + /// heuristic for finding the most stable source of a value. + /// + /// We also buffer the index into the `Env::blockparam_ins` vector, as we may see + /// multiple uses of a blockparam within a single instruction, and as such may need to + /// generate multiple blockparam move destinations by re-traversing that section of the + /// vector. + #[inline(always)] + fn advance(&mut self, current: LiveRangeListEntry) { + // Advance the `prev` pointer to the `next` pointer, as long as the `next` pointer + // does not start at the same time as the current LR we're processing. + if self + .buffered + .map(|entry| entry.range.from < current.range.from) + .unwrap_or(false) + { + self.prev = self.buffered; + self.prev_ins_idx = self.buffered_ins_idx; + } + + // Advance the `next` pointer to the currently processed LR, as long as it ends + // later than the current `next`. + if self + .buffered + .map(|entry| entry.range.to < current.range.to) + .unwrap_or(true) + { + self.buffered = Some(current); + } + } + } + + // Determine the ProgPoint where moves on this (from, to) + // edge should go: + // - If there is more than one in-edge to `to`, then + // `from` must have only one out-edge; moves go at tail of + // `from` just before last Branch/Ret. + // - Otherwise, there must be at most one in-edge to `to`, + // and moves go at start of `to`. + #[inline(always)] + fn choose_move_location<'a, F: Function>( + env: &Env<'a, F>, + from: Block, + to: Block, + ) -> (ProgPoint, InsertMovePrio) { + let from_last_insn = env.func.block_insns(from).last(); + let to_first_insn = env.func.block_insns(to).first(); + let from_is_ret = env.func.is_ret(from_last_insn); + let to_is_entry = env.func.entry_block() == to; + let from_outs = env.func.block_succs(from).len() + if from_is_ret { 1 } else { 0 }; + let to_ins = env.func.block_preds(to).len() + if to_is_entry { 1 } else { 0 }; + + if to_ins > 1 && from_outs <= 1 { + ( + // N.B.: though semantically the edge moves happen + // after the branch, we must insert them before + // the branch because otherwise, of course, they + // would never execute. This is correct even in + // the presence of branches that read register + // inputs (e.g. conditional branches on some RISCs + // that branch on reg zero/not-zero, or any + // indirect branch), but for a very subtle reason: + // all cases of such branches will (or should) + // have multiple successors, and thus due to + // critical-edge splitting, their successors will + // have only the single predecessor, and we prefer + // to insert at the head of the successor in that + // case (rather than here). We make this a + // requirement, in fact: the user of this library + // shall not read registers in a branch + // instruction of there is only one successor per + // the given CFG information. + ProgPoint::before(from_last_insn), + InsertMovePrio::OutEdgeMoves, + ) + } else if to_ins <= 1 { + ( + ProgPoint::before(to_first_insn), + InsertMovePrio::InEdgeMoves, + ) + } else { + panic!( + "Critical edge: can't insert moves between blocks {:?} and {:?}", + from, to + ); + } + } + + #[derive(PartialEq)] + struct InterBlockDest { + to: Block, + from: Block, + alloc: Allocation, + } + + impl InterBlockDest { + fn key(&self) -> u64 { + u64_key(self.from.raw_u32(), self.to.raw_u32()) + } + } + + let mut inter_block_sources: FxHashMap = FxHashMap::default(); + let mut inter_block_dests = Vec::with_capacity(self.func.num_blocks()); + + #[derive(Hash, Eq, PartialEq)] + struct BlockparamSourceKey { + bits: u64, + } + + impl BlockparamSourceKey { + fn new(from_block: Block, to_vreg: VRegIndex) -> Self { + BlockparamSourceKey { + bits: u64_key(from_block.raw_u32(), to_vreg.raw_u32()), + } + } + } + + struct BlockparamDest { + from_block: Block, + to_block: Block, + to_vreg: VRegIndex, + alloc: Allocation, + } + + impl BlockparamDest { + fn key(&self) -> u64 { + u64_key(self.to_block.raw_u32(), self.from_block.raw_u32()) + } + + fn source(&self) -> BlockparamSourceKey { + BlockparamSourceKey::new(self.from_block, self.to_vreg) + } + } + + let mut block_param_sources = + FxHashMap::::with_capacity_and_hasher( + 3 * self.func.num_insts(), + Default::default(), + ); + let mut block_param_dests = Vec::with_capacity(3 * self.func.num_insts()); + + let debug_labels = self.func.debug_value_labels(); + + let mut reuse_input_insts = Vec::with_capacity(self.func.num_insts() / 2); + + let mut blockparam_in_idx = 0; + let mut blockparam_out_idx = 0; + for vreg in 0..self.vregs.len() { + let vreg = VRegIndex::new(vreg); + if !self.is_vreg_used(vreg) { + continue; + } + + inter_block_sources.clear(); + + // For each range in each vreg, insert moves or + // half-moves. We also scan over `blockparam_ins` and + // `blockparam_outs`, which are sorted by (block, vreg), + // to fill in allocations. + let mut prev = PrevBuffer::new(blockparam_in_idx); + for range_idx in 0..self.vregs[vreg].ranges.len() { + let entry = self.vregs[vreg].ranges[range_idx]; + let alloc = self.get_alloc_for_range(entry.index); + let range = entry.range; + trace!( + "apply_allocations: vreg {:?} LR {:?} with range {:?} has alloc {:?}", + vreg, + entry.index, + range, + alloc, + ); + debug_assert!(alloc != Allocation::none()); + + if self.annotations_enabled { + self.annotate( + range.from, + format!( + " <<< start v{} in {} (range{}) (bundle{})", + vreg.index(), + alloc, + entry.index.index(), + self.ranges[entry.index].bundle.raw_u32(), + ), + ); + self.annotate( + range.to, + format!( + " end v{} in {} (range{}) (bundle{}) >>>", + vreg.index(), + alloc, + entry.index.index(), + self.ranges[entry.index].bundle.raw_u32(), + ), + ); + } + + prev.advance(entry); + + // Does this range follow immediately after a prior + // range in the same block? If so, insert a move (if + // the allocs differ). We do this directly rather than + // with half-moves because we eagerly know both sides + // already (and also, half-moves are specific to + // inter-block transfers). + // + // Note that we do *not* do this if there is also a + // def as the first use in the new range: it's + // possible that an old liverange covers the Before + // pos of an inst, a new liverange covers the After + // pos, and the def also happens at After. In this + // case we don't want to an insert a move after the + // instruction copying the old liverange. + // + // Note also that we assert that the new range has to + // start at the Before-point of an instruction; we + // can't insert a move that logically happens just + // before After (i.e. in the middle of a single + // instruction). + if let Some(prev) = prev.is_valid() { + let prev_alloc = self.get_alloc_for_range(prev.index); + debug_assert!(prev_alloc != Allocation::none()); + + if prev.range.to >= range.from + && (prev.range.to > range.from || !self.is_start_of_block(range.from)) + && !self.ranges[entry.index].has_flag(LiveRangeFlag::StartsAtDef) + { + trace!( + "prev LR {} abuts LR {} in same block; moving {} -> {} for v{}", + prev.index.index(), + entry.index.index(), + prev_alloc, + alloc, + vreg.index() + ); + debug_assert_eq!(range.from.pos(), InstPosition::Before); + inserted_moves.push( + range.from, + InsertMovePrio::Regular, + prev_alloc, + alloc, + self.vreg(vreg), + ); + } + } + + // Scan over blocks whose ends are covered by this + // range. For each, for each successor that is not + // already in this range (hence guaranteed to have the + // same allocation) and if the vreg is live, add a + // Source half-move. + let mut block = self.cfginfo.insn_block[range.from.inst().index()]; + while block.is_valid() && block.index() < self.func.num_blocks() { + if range.to < self.cfginfo.block_exit[block.index()].next() { + break; + } + trace!("examining block with end in range: block{}", block.index()); + + match inter_block_sources.entry(block) { + // If the entry is already present in the map, we'll try to prefer a + // register allocation. + Entry::Occupied(mut entry) => { + if !entry.get().is_reg() { + entry.insert(alloc); + } + } + Entry::Vacant(entry) => { + entry.insert(alloc); + } + } + + // Scan forward in `blockparam_outs`, adding all + // half-moves for outgoing values to blockparams + // in succs. + trace!( + "scanning blockparam_outs for v{} block{}: blockparam_out_idx = {}", + vreg.index(), + block.index(), + blockparam_out_idx, + ); + while blockparam_out_idx < self.blockparam_outs.len() { + let BlockparamOut { + from_vreg, + from_block, + to_block, + to_vreg, + } = self.blockparam_outs[blockparam_out_idx]; + if (from_vreg, from_block) > (vreg, block) { + break; + } + if (from_vreg, from_block) == (vreg, block) { + trace!( + " -> found: from v{} block{} to v{} block{}", + from_vreg.index(), + from_block.index(), + to_vreg.index(), + to_vreg.index() + ); + + let key = BlockparamSourceKey::new(from_block, to_vreg); + match block_param_sources.entry(key) { + // As with inter-block moves, if the entry is already present we'll + // try to prefer a register allocation. + Entry::Occupied(mut entry) => { + if !entry.get().is_reg() { + entry.insert(alloc); + } + } + Entry::Vacant(entry) => { + entry.insert(alloc); + } + } + + if self.annotations_enabled { + self.annotate( + self.cfginfo.block_exit[block.index()], + format!( + "blockparam-out: block{} to block{}: v{} to v{} in {}", + from_block.index(), + to_block.index(), + from_vreg.index(), + to_vreg.index(), + alloc + ), + ); + } + } + + blockparam_out_idx += 1; + } + + block = block.next(); + } + + // Scan over blocks whose beginnings are covered by + // this range and for which the vreg is live at the + // start of the block. For each, for each predecessor, + // add a Dest half-move. + let mut block = self.cfginfo.insn_block[range.from.inst().index()]; + if self.cfginfo.block_entry[block.index()] < range.from { + block = block.next(); + } + while block.is_valid() && block.index() < self.func.num_blocks() { + if self.cfginfo.block_entry[block.index()] >= range.to { + break; + } + + // Add half-moves for blockparam inputs. + trace!( + "scanning blockparam_ins at vreg {} block {}: blockparam_in_idx = {}", + vreg.index(), + block.index(), + prev.prev_ins_idx, + ); + let mut idx = prev.blockparam_ins_idx(); + while idx < self.blockparam_ins.len() { + let BlockparamIn { + from_block, + to_block, + to_vreg, + } = self.blockparam_ins[idx]; + if (to_vreg, to_block) > (vreg, block) { + break; + } + if (to_vreg, to_block) == (vreg, block) { + block_param_dests.push(BlockparamDest { + from_block, + to_block, + to_vreg, + alloc, + }); + trace!( + "match: blockparam_in: v{} in block{} from block{} into {}", + to_vreg.index(), + to_block.index(), + from_block.index(), + alloc, + ); + #[cfg(debug_assertions)] + if self.annotations_enabled { + self.annotate( + self.cfginfo.block_entry[block.index()], + format!( + "blockparam-in: block{} to block{}:into v{} in {}", + from_block.index(), + to_block.index(), + to_vreg.index(), + alloc + ), + ); + } + } + idx += 1; + } + + prev.update_blockparam_ins_idx(idx); + + if !self.is_live_in(block, vreg) { + block = block.next(); + continue; + } + + trace!( + "scanning preds at vreg {} block {} for ends outside the range", + vreg.index(), + block.index() + ); + + // Now find any preds whose ends are not in the + // same range, and insert appropriate moves. + for &pred in self.func.block_preds(block) { + trace!( + "pred block {} has exit {:?}", + pred.index(), + self.cfginfo.block_exit[pred.index()] + ); + if range.contains_point(self.cfginfo.block_exit[pred.index()]) { + continue; + } + + inter_block_dests.push(InterBlockDest { + from: pred, + to: block, + alloc, + }) + } + + block = block.next(); + } + + // Scan over def/uses and apply allocations. + for use_idx in 0..self.ranges[entry.index].uses.len() { + let usedata = self.ranges[entry.index].uses[use_idx]; + trace!("applying to use: {:?}", usedata); + debug_assert!(range.contains_point(usedata.pos)); + let inst = usedata.pos.inst(); + let slot = usedata.slot; + let operand = usedata.operand; + self.set_alloc(inst, slot as usize, alloc); + if let OperandConstraint::Reuse(_) = operand.constraint() { + reuse_input_insts.push(inst); + } + } + + // Scan debug-labels on this vreg that overlap with + // this range, producing a debug-info output record + // giving the allocation location for each label. + if !debug_labels.is_empty() { + // Do a binary search to find the start of any + // labels for this vreg. Recall that we require + // debug-label requests to be sorted by vreg as a + // precondition (which we verified above). + let start = debug_labels + .binary_search_by(|&(label_vreg, _label_from, _label_to, _label)| { + // Search for the point just before the first + // tuple that could be for `vreg` overlapping + // with `range`. Never return + // `Ordering::Equal`; `binary_search_by` in + // this case returns the index of the first + // entry that is greater as an `Err`. + if label_vreg.vreg() < vreg.index() { + core::cmp::Ordering::Less + } else { + core::cmp::Ordering::Greater + } + }) + .unwrap_err(); + + for &(label_vreg, label_from, label_to, label) in &debug_labels[start..] { + let label_from = ProgPoint::before(label_from); + let label_to = ProgPoint::before(label_to); + let label_range = CodeRange { + from: label_from, + to: label_to, + }; + if label_vreg.vreg() != vreg.index() { + break; + } + if !range.overlaps(&label_range) { + continue; + } + + let from = core::cmp::max(label_from, range.from); + let to = core::cmp::min(label_to, range.to); + + self.ctx + .output + .debug_locations + .push((label, from, to, alloc)); + } + } + } + + if !inter_block_dests.is_empty() { + self.output.stats.halfmoves_count += inter_block_dests.len() * 2; + + inter_block_dests.sort_unstable_by_key(InterBlockDest::key); + + let vreg = self.vreg(vreg); + trace!("processing inter-block moves for {}", vreg); + for dest in inter_block_dests.drain(..) { + let src = inter_block_sources[&dest.from]; + + trace!( + " -> moving from {} to {} between {:?} and {:?}", + src, + dest.alloc, + dest.from, + dest.to + ); + + let (pos, prio) = choose_move_location(self, dest.from, dest.to); + inserted_moves.push(pos, prio, src, dest.alloc, vreg); + } + } + + blockparam_in_idx = prev.blockparam_ins_idx(); + } + + if !block_param_dests.is_empty() { + self.output.stats.halfmoves_count += block_param_sources.len(); + self.output.stats.halfmoves_count += block_param_dests.len(); + + trace!("processing block-param moves"); + for dest in block_param_dests { + let src = dest.source(); + let src_alloc = block_param_sources.get(&src).unwrap(); + let (pos, prio) = choose_move_location(self, dest.from_block, dest.to_block); + inserted_moves.push(pos, prio, *src_alloc, dest.alloc, self.vreg(dest.to_vreg)); + } + } + + // Handle multi-fixed-reg constraints by copying. + for fixup in core::mem::replace(&mut self.multi_fixed_reg_fixups, vec![]) { + let from_alloc = self.get_alloc(fixup.pos.inst(), fixup.from_slot as usize); + let to_alloc = Allocation::reg(PReg::from_index(fixup.to_preg.index())); + trace!( + "multi-fixed-move constraint at {:?} from {} to {} for v{}", + fixup.pos, + from_alloc, + to_alloc, + fixup.vreg.index(), + ); + let prio = match fixup.level { + FixedRegFixupLevel::Initial => InsertMovePrio::MultiFixedRegInitial, + FixedRegFixupLevel::Secondary => InsertMovePrio::MultiFixedRegSecondary, + }; + inserted_moves.push(fixup.pos, prio, from_alloc, to_alloc, self.vreg(fixup.vreg)); + self.set_alloc( + fixup.pos.inst(), + fixup.to_slot as usize, + Allocation::reg(PReg::from_index(fixup.to_preg.index())), + ); + } + + // Handle outputs that reuse inputs: copy beforehand, then set + // input's alloc to output's. + // + // Note that the output's allocation may not *actually* be + // valid until InstPosition::After, but the reused input may + // occur at InstPosition::Before. This may appear incorrect, + // but we make it work by ensuring that all *other* inputs are + // extended to InstPosition::After so that the def will not + // interfere. (The liveness computation code does this -- we + // do not require the user to do so.) + // + // One might ask: why not insist that input-reusing defs occur + // at InstPosition::Before? this would be correct, but would + // mean that the reused input and the reusing output + // interfere, *guaranteeing* that every such case would + // require a move. This is really bad on ISAs (like x86) where + // reused inputs are ubiquitous. + // + // Another approach might be to put the def at Before, and + // trim the reused input's liverange back to the previous + // instruction's After. This is kind of OK until (i) a block + // boundary occurs between the prior inst and this one, or + // (ii) any moves/spills/reloads occur between the two + // instructions. We really do need the input to be live at + // this inst's Before. + // + // In principle what we really need is a "BeforeBefore" + // program point, but we don't want to introduce that + // everywhere and pay the cost of twice as many ProgPoints + // throughout the allocator. + // + // Or we could introduce a separate move instruction -- this + // is the approach that regalloc.rs takes with "mod" operands + // -- but that is also costly. + // + // So we take this approach (invented by IonMonkey -- somewhat + // hard to discern, though see [0] for a comment that makes + // this slightly less unclear) to avoid interference between + // the actual reused input and reusing output, ensure + // interference (hence no incorrectness) between other inputs + // and the reusing output, and not require a separate explicit + // move instruction. + // + // [0] https://searchfox.org/mozilla-central/rev/3a798ef9252896fb389679f06dd3203169565af0/js/src/jit/shared/Lowering-shared-inl.h#108-110 + for inst in reuse_input_insts { + let mut input_reused: SmallVec<[usize; 4]> = smallvec![]; + for output_idx in 0..self.func.inst_operands(inst).len() { + let operand = self.func.inst_operands(inst)[output_idx]; + if let OperandConstraint::Reuse(input_idx) = operand.constraint() { + debug_assert!(!input_reused.contains(&input_idx)); + debug_assert_eq!(operand.pos(), OperandPos::Late); + input_reused.push(input_idx); + let input_alloc = self.get_alloc(inst, input_idx); + let output_alloc = self.get_alloc(inst, output_idx); + trace!( + "reuse-input inst {:?}: output {} has alloc {:?}, input {} has alloc {:?}", + inst, + output_idx, + output_alloc, + input_idx, + input_alloc + ); + if input_alloc != output_alloc { + #[cfg(debug_assertions)] + if self.annotations_enabled { + self.annotate( + ProgPoint::before(inst), + format!(" reuse-input-copy: {} -> {}", input_alloc, output_alloc), + ); + } + let input_operand = self.func.inst_operands(inst)[input_idx]; + inserted_moves.push( + ProgPoint::before(inst), + InsertMovePrio::ReusedInput, + input_alloc, + output_alloc, + input_operand.vreg(), + ); + self.set_alloc(inst, input_idx, output_alloc); + } + } + } + } + + // Sort the debug-locations vector; we provide this + // invariant to the client. + self.output.debug_locations.sort_unstable(); + + inserted_moves + } + + pub fn resolve_inserted_moves(&mut self, mut inserted_moves: InsertedMoves) -> Edits { + // For each program point, gather all moves together. Then + // resolve (see cases below). + let mut i = 0; + inserted_moves + .moves + .sort_unstable_by_key(|m| m.pos_prio.key()); + + // Redundant-move elimination state tracker. + let mut redundant_moves = RedundantMoveEliminator::default(); + + fn redundant_move_process_side_effects<'a, F: Function>( + this: &Env<'a, F>, + redundant_moves: &mut RedundantMoveEliminator, + from: ProgPoint, + to: ProgPoint, + ) { + // If we cross a block boundary, clear and return. + if this.cfginfo.insn_block[from.inst().index()] + != this.cfginfo.insn_block[to.inst().index()] + { + redundant_moves.clear(); + return; + } + + let start_inst = if from.pos() == InstPosition::Before { + from.inst() + } else { + from.inst().next() + }; + let end_inst = if to.pos() == InstPosition::Before { + to.inst() + } else { + to.inst().next() + }; + for inst in start_inst.index()..end_inst.index() { + let inst = Inst::new(inst); + for (i, op) in this.func.inst_operands(inst).iter().enumerate() { + match op.kind() { + OperandKind::Def => { + let alloc = this.get_alloc(inst, i); + redundant_moves.clear_alloc(alloc); + } + _ => {} + } + } + for reg in this.func.inst_clobbers(inst) { + redundant_moves.clear_alloc(Allocation::reg(reg)); + } + // The dedicated scratch registers may be clobbered by any + // instruction. + for reg in this.env.scratch_by_class { + if let Some(reg) = reg { + redundant_moves.clear_alloc(Allocation::reg(reg)); + } + } + } + } + + let mut last_pos = ProgPoint::before(Inst::new(0)); + let mut edits = Edits::with_capacity(self.func.num_insts()); + + while i < inserted_moves.moves.len() { + let start = i; + let pos_prio = inserted_moves.moves[i].pos_prio; + while i < inserted_moves.moves.len() && inserted_moves.moves[i].pos_prio == pos_prio { + i += 1; + } + let moves = &inserted_moves.moves[start..i]; + + redundant_move_process_side_effects(self, &mut redundant_moves, last_pos, pos_prio.pos); + last_pos = pos_prio.pos; + + // Gather all the moves in each RegClass separately. + // These cannot interact, so it is safe to have separate + // ParallelMove instances. They need to be separate because + // moves between the classes are impossible. (We could + // enhance ParallelMoves to understand register classes, but + // this seems simpler.) + let mut int_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; + let mut float_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; + let mut vec_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; + + for m in moves { + match m.to_vreg.class() { + RegClass::Int => { + int_moves.push(m.clone()); + } + RegClass::Float => { + float_moves.push(m.clone()); + } + RegClass::Vector => { + vec_moves.push(m.clone()); + } + } + } + + for &(regclass, moves) in &[ + (RegClass::Int, &int_moves), + (RegClass::Float, &float_moves), + (RegClass::Vector, &vec_moves), + ] { + // All moves in `moves` semantically happen in + // parallel. Let's resolve these to a sequence of moves + // that can be done one at a time. + let mut parallel_moves = ParallelMoves::new(); + trace!( + "parallel moves at pos {:?} prio {:?}", + pos_prio.pos, + pos_prio.prio + ); + for m in moves { + trace!(" {} -> {}", m.from_alloc, m.to_alloc); + parallel_moves.add(m.from_alloc, m.to_alloc, Some(m.to_vreg)); + } + + let resolved = parallel_moves.resolve(); + let mut scratch_iter = RegTraversalIter::new( + self.env, + regclass, + PReg::invalid(), + PReg::invalid(), + 0, + None, + ); + let mut dedicated_scratch = self.env.scratch_by_class[regclass as usize]; + let key = LiveRangeKey::from_range(&CodeRange { + from: pos_prio.pos, + to: pos_prio.pos.next(), + }); + let find_free_reg = || { + // Use the dedicated scratch register first if it is + // available. + if let Some(reg) = dedicated_scratch.take() { + return Some(Allocation::reg(reg)); + } + while let Some(preg) = scratch_iter.next() { + if !self.pregs[preg.index()] + .allocations + .btree + .contains_key(&key) + { + let alloc = Allocation::reg(preg); + if moves + .iter() + .any(|m| m.from_alloc == alloc || m.to_alloc == alloc) + { + // Skip pregs used by moves in this + // parallel move set, even if not + // marked used at progpoint: edge move + // liveranges meet but don't overlap + // so otherwise we may incorrectly + // overwrite a source reg. + continue; + } + return Some(alloc); + } + } + None + }; + let mut stackslot_idx = 0; + let get_stackslot = || { + let idx = stackslot_idx; + stackslot_idx += 1; + // We can't borrow `self` as mutable, so we create + // these placeholders then allocate the actual + // slots if needed with `self.allocate_spillslot` + // below. + Allocation::stack(SpillSlot::new(SpillSlot::MAX - idx)) + }; + let is_stack_alloc = |alloc: Allocation| { + if let Some(preg) = alloc.as_reg() { + self.pregs[preg.index()].is_stack + } else { + alloc.is_stack() + } + }; + let preferred_victim = self.preferred_victim_by_class[regclass as usize]; + + let scratch_resolver = MoveAndScratchResolver { + find_free_reg, + get_stackslot, + is_stack_alloc, + borrowed_scratch_reg: preferred_victim, + }; + + let resolved = scratch_resolver.compute(resolved); + + let mut rewrites = FxHashMap::default(); + for i in 0..stackslot_idx { + if i >= self.extra_spillslots_by_class[regclass as usize].len() { + let slot = + self.allocate_spillslot(self.func.spillslot_size(regclass) as u32); + self.extra_spillslots_by_class[regclass as usize].push(slot); + } + rewrites.insert( + Allocation::stack(SpillSlot::new(SpillSlot::MAX - i)), + self.extra_spillslots_by_class[regclass as usize][i], + ); + } + + for (src, dst, to_vreg) in resolved { + let src = rewrites.get(&src).cloned().unwrap_or(src); + let dst = rewrites.get(&dst).cloned().unwrap_or(dst); + trace!(" resolved: {} -> {} ({:?})", src, dst, to_vreg); + let action = redundant_moves.process_move(src, dst, to_vreg); + if !action.elide { + edits.add(pos_prio, src, dst); + } else { + trace!(" -> redundant move elided"); + } + } + } + } + + // Ensure edits are in sorted ProgPoint order. N.B.: this must + // be a stable sort! We have to keep the order produced by the + // parallel-move resolver for all moves within a single sort + // key. + edits.sort(); + self.output.stats.edits_count = edits.len(); + + // Add debug annotations. + if self.annotations_enabled { + for &(pos_prio, ref edit) in edits.iter() { + match edit { + &Edit::Move { from, to } => { + self.annotate(pos_prio.pos, format!("move {} -> {}", from, to)); + } + } + } + } + + edits + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/process.rs b/deps/crates/vendor/regalloc2/src/ion/process.rs new file mode 100644 index 00000000000000..cc57effb939b44 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/process.rs @@ -0,0 +1,1361 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Main allocation loop that processes bundles. + +use super::{ + spill_weight_from_constraint, Env, LiveBundleIndex, LiveBundleVec, LiveRangeFlag, + LiveRangeIndex, LiveRangeKey, LiveRangeList, LiveRangeListEntry, PRegIndex, RegTraversalIter, + Requirement, SpillWeight, UseList, VRegIndex, +}; +use crate::{ + ion::data_structures::{ + CodeRange, BUNDLE_MAX_NORMAL_SPILL_WEIGHT, MAX_SPLITS_PER_SPILLSET, + MINIMAL_BUNDLE_SPILL_WEIGHT, MINIMAL_FIXED_BUNDLE_SPILL_WEIGHT, + }, + Allocation, Function, Inst, InstPosition, OperandConstraint, OperandKind, PReg, ProgPoint, + RegAllocError, +}; +use core::fmt::Debug; +use smallvec::{smallvec, SmallVec}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum AllocRegResult<'a> { + Allocated(Allocation), + Conflict(&'a [LiveBundleIndex], ProgPoint), + ConflictWithFixed(u32, ProgPoint), + ConflictHighCost, +} + +impl<'a, F: Function> Env<'a, F> { + pub fn process_bundles(&mut self) -> Result<(), RegAllocError> { + while let Some((bundle, reg_hint)) = self.ctx.allocation_queue.pop() { + self.ctx.output.stats.process_bundle_count += 1; + self.process_bundle(bundle, reg_hint)?; + } + self.ctx.output.stats.final_liverange_count = self.ranges.len(); + self.ctx.output.stats.final_bundle_count = self.bundles.len(); + self.ctx.output.stats.spill_bundle_count = self.spilled_bundles.len(); + + Ok(()) + } + + pub fn try_to_allocate_bundle_to_reg<'b>( + &mut self, + bundle: LiveBundleIndex, + reg: PRegIndex, + // if the max bundle weight in the conflict set exceeds this + // cost (if provided), just return + // `AllocRegResult::ConflictHighCost`. + max_allowable_cost: Option, + conflicts: &'b mut LiveBundleVec, + ) -> AllocRegResult<'b> { + trace!("try_to_allocate_bundle_to_reg: {:?} -> {:?}", bundle, reg); + conflicts.clear(); + self.ctx.conflict_set.clear(); + let mut max_conflict_weight = 0; + // Traverse the BTreeMap in order by requesting the whole + // range spanned by the bundle and iterating over that + // concurrently with our ranges. Because our ranges are in + // order, and the BTreeMap is as well, this allows us to have + // an overall O(n log n) + O(b) complexity, where the PReg has + // n current ranges and the bundle has b ranges, rather than + // O(b * n log n) with the simple probe-for-each-bundle-range + // approach. + // + // Note that the comparator function on a CodeRange tests for + // *overlap*, so we are checking whether the BTree contains + // any preg range that *overlaps* with range `range`, not + // literally the range `range`. + let bundle_ranges = &self.ctx.bundles[bundle].ranges; + let from_key = LiveRangeKey::from_range(&CodeRange { + from: bundle_ranges.first().unwrap().range.from, + to: bundle_ranges.first().unwrap().range.from, + }); + let mut preg_range_iter = self.ctx.pregs[reg.index()] + .allocations + .btree + .range(from_key..) + .peekable(); + trace!( + "alloc map for {:?} in range {:?}..: {:?}", + reg, + from_key, + self.ctx.pregs[reg.index()].allocations.btree + ); + let mut first_conflict: Option = None; + + 'ranges: for entry in bundle_ranges { + trace!(" -> range LR {:?}: {:?}", entry.index, entry.range); + let key = LiveRangeKey::from_range(&entry.range); + + let mut skips = 0; + 'alloc: loop { + trace!(" -> PReg range {:?}", preg_range_iter.peek()); + + // Advance our BTree traversal until it is >= this bundle + // range (i.e., skip PReg allocations in the BTree that + // are completely before this bundle range). + + if preg_range_iter.peek().is_some() && *preg_range_iter.peek().unwrap().0 < key { + trace!( + "Skipping PReg range {:?}", + preg_range_iter.peek().unwrap().0 + ); + preg_range_iter.next(); + skips += 1; + if skips >= 16 { + let from_pos = entry.range.from; + let from_key = LiveRangeKey::from_range(&CodeRange { + from: from_pos, + to: from_pos, + }); + preg_range_iter = self.ctx.pregs[reg.index()] + .allocations + .btree + .range(from_key..) + .peekable(); + skips = 0; + } + continue 'alloc; + } + skips = 0; + + // If there are no more PReg allocations, we're done! + if preg_range_iter.peek().is_none() { + trace!(" -> no more PReg allocations; so no conflict possible!"); + break 'ranges; + } + + // If the current PReg range is beyond this range, there is no conflict; continue. + if *preg_range_iter.peek().unwrap().0 > key { + trace!( + " -> next PReg allocation is at {:?}; moving to next VReg range", + preg_range_iter.peek().unwrap().0 + ); + break 'alloc; + } + + // Otherwise, there is a conflict. + let preg_key = *preg_range_iter.peek().unwrap().0; + debug_assert_eq!(preg_key, key); // Assert that this range overlaps. + let preg_range = preg_range_iter.next().unwrap().1; + + trace!(" -> btree contains range {:?} that overlaps", preg_range); + if preg_range.is_valid() { + trace!(" -> from vreg {:?}", self.ctx.ranges[*preg_range].vreg); + // range from an allocated bundle: find the bundle and add to + // conflicts list. + let conflict_bundle = self.ctx.ranges[*preg_range].bundle; + trace!(" -> conflict bundle {:?}", conflict_bundle); + if self.ctx.conflict_set.insert(conflict_bundle) { + conflicts.push(conflict_bundle); + max_conflict_weight = core::cmp::max( + max_conflict_weight, + self.ctx.bundles[conflict_bundle].cached_spill_weight(), + ); + if max_allowable_cost.is_some() + && max_conflict_weight > max_allowable_cost.unwrap() + { + trace!(" -> reached high cost, retrying early"); + return AllocRegResult::ConflictHighCost; + } + } + + if first_conflict.is_none() { + first_conflict = Some(ProgPoint::from_index(core::cmp::max( + preg_key.from, + key.from, + ))); + } + } else { + trace!(" -> conflict with fixed reservation"); + // range from a direct use of the PReg (due to clobber). + return AllocRegResult::ConflictWithFixed( + max_conflict_weight, + ProgPoint::from_index(preg_key.from), + ); + } + } + } + + if conflicts.len() > 0 { + return AllocRegResult::Conflict(conflicts, first_conflict.unwrap()); + } + + // We can allocate! Add our ranges to the preg's BTree. + let preg = PReg::from_index(reg.index()); + trace!(" -> bundle {:?} assigned to preg {:?}", bundle, preg); + self.ctx.bundles[bundle].allocation = Allocation::reg(preg); + for entry in &self.ctx.bundles[bundle].ranges { + let key = LiveRangeKey::from_range(&entry.range); + let res = self.ctx.pregs[reg.index()] + .allocations + .btree + .insert(key, entry.index); + + // We disallow LR overlap within bundles, so this should never be possible. + debug_assert!(res.is_none()); + } + + AllocRegResult::Allocated(Allocation::reg(preg)) + } + + pub fn evict_bundle(&mut self, bundle: LiveBundleIndex) { + trace!( + "evicting bundle {:?}: alloc {:?}", + bundle, + self.ctx.bundles[bundle].allocation + ); + let preg = match self.ctx.bundles[bundle].allocation.as_reg() { + Some(preg) => preg, + None => { + trace!( + " -> has no allocation! {:?}", + self.ctx.bundles[bundle].allocation + ); + return; + } + }; + let preg_idx = PRegIndex::new(preg.index()); + self.ctx.bundles[bundle].allocation = Allocation::none(); + for entry in &self.ctx.bundles[bundle].ranges { + trace!(" -> removing LR {:?} from reg {:?}", entry.index, preg_idx); + self.ctx.pregs[preg_idx.index()] + .allocations + .btree + .remove(&LiveRangeKey::from_range(&entry.range)); + } + let prio = self.ctx.bundles[bundle].prio; + trace!(" -> prio {}; back into queue", prio); + self.ctx + .allocation_queue + .insert(bundle, prio as usize, PReg::invalid()); + } + + pub fn bundle_spill_weight(&self, bundle: LiveBundleIndex) -> u32 { + self.ctx.bundles[bundle].cached_spill_weight() + } + + pub fn maximum_spill_weight_in_bundle_set(&self, bundles: &[LiveBundleIndex]) -> u32 { + trace!("maximum_spill_weight_in_bundle_set: {:?}", bundles); + let m = bundles + .iter() + .map(|&b| { + let w = self.ctx.bundles[b].cached_spill_weight(); + trace!("bundle{}: {}", b.index(), w); + w + }) + .max() + .unwrap_or(0); + trace!(" -> max: {}", m); + m + } + + pub fn recompute_bundle_properties(&mut self, bundle: LiveBundleIndex) { + trace!("recompute bundle properties: bundle {:?}", bundle); + + let minimal; + let mut fixed = false; + let mut fixed_def = false; + let bundledata = &self.ctx.bundles[bundle]; + let first_range = bundledata.ranges[0].index; + let first_range_data = &self.ctx.ranges[first_range]; + + self.ctx.bundles[bundle].prio = self.compute_bundle_prio(bundle); + + if first_range_data.vreg.is_invalid() { + trace!(" -> no vreg; minimal and fixed"); + minimal = true; + fixed = true; + } else { + for u in &first_range_data.uses { + trace!(" -> use: {:?}", u); + if let OperandConstraint::FixedReg(_) = u.operand.constraint() { + trace!(" -> fixed operand at {:?}: {:?}", u.pos, u.operand); + fixed = true; + if u.operand.kind() == OperandKind::Def { + trace!(" -> is fixed def"); + fixed_def = true; + } + + break; + } + } + // Minimal if the range covers only one instruction. Note + // that it could cover just one ProgPoint, + // i.e. X.Before..X.After, or two ProgPoints, + // i.e. X.Before..X+1.Before. + trace!(" -> first range has range {:?}", first_range_data.range); + let bundle_start = self.ctx.bundles[bundle].ranges.first().unwrap().range.from; + let bundle_end = self.ctx.bundles[bundle].ranges.last().unwrap().range.to; + minimal = bundle_start.inst() == bundle_end.prev().inst(); + trace!(" -> minimal: {}", minimal); + } + + let spill_weight = if minimal { + if fixed { + trace!(" -> fixed and minimal"); + MINIMAL_FIXED_BUNDLE_SPILL_WEIGHT + } else { + trace!(" -> non-fixed and minimal"); + MINIMAL_BUNDLE_SPILL_WEIGHT + } + } else { + let mut total = SpillWeight::zero(); + for entry in &self.ctx.bundles[bundle].ranges { + let range_data = &self.ctx.ranges[entry.index]; + trace!( + " -> uses spill weight: +{:?}", + range_data.uses_spill_weight() + ); + total = total + range_data.uses_spill_weight(); + } + + if self.ctx.bundles[bundle].prio > 0 { + let final_weight = (total.to_f32() as u32) / self.ctx.bundles[bundle].prio; + trace!( + " -> dividing by prio {}; final weight {}", + self.ctx.bundles[bundle].prio, + final_weight + ); + core::cmp::min(BUNDLE_MAX_NORMAL_SPILL_WEIGHT, final_weight) + } else { + 0 + } + }; + + self.ctx.bundles[bundle].set_cached_spill_weight_and_props( + spill_weight, + minimal, + fixed, + fixed_def, + ); + } + + pub fn minimal_bundle(&self, bundle: LiveBundleIndex) -> bool { + self.ctx.bundles[bundle].cached_minimal() + } + + pub fn recompute_range_properties(&mut self, range: LiveRangeIndex) { + let rangedata = &mut self.ctx.ranges[range]; + let mut w = SpillWeight::zero(); + for u in &rangedata.uses { + w = w + SpillWeight::from_bits(u.weight); + trace!("range{}: use {:?}", range.index(), u); + } + rangedata.set_uses_spill_weight(w); + if rangedata.uses.len() > 0 && rangedata.uses[0].operand.kind() == OperandKind::Def { + // Note that we *set* the flag here, but we never *clear* + // it: it may be set by a progmove as well (which does not + // create an explicit use or def), and we want to preserve + // that. We will never split or trim ranges in a way that + // removes a def at the front and requires the flag to be + // cleared. + rangedata.set_flag(LiveRangeFlag::StartsAtDef); + } + } + + pub fn get_or_create_spill_bundle( + &mut self, + bundle: LiveBundleIndex, + create_if_absent: bool, + ) -> Option { + let ssidx = self.ctx.bundles[bundle].spillset; + let idx = self.ctx.spillsets[ssidx].spill_bundle; + if idx.is_valid() { + Some(idx) + } else if create_if_absent { + let idx = self.ctx.bundles.add(self.ctx.bump()); + self.ctx.spillsets[ssidx].spill_bundle = idx; + self.ctx.bundles[idx].spillset = ssidx; + self.ctx.spilled_bundles.push(idx); + Some(idx) + } else { + None + } + } + + pub fn split_and_requeue_bundle( + &mut self, + bundle: LiveBundleIndex, + mut split_at: ProgPoint, + reg_hint: PReg, + // Do we trim the parts around the split and put them in the + // spill bundle? + mut trim_ends_into_spill_bundle: bool, + ) { + self.ctx.output.stats.splits += 1; + trace!( + "split bundle {:?} at {:?} and requeue with reg hint (for first part) {:?}", + bundle, + split_at, + reg_hint, + ); + + // Split `bundle` at `split_at`, creating new LiveRanges and + // bundles (and updating vregs' linked lists appropriately), + // and enqueue the new bundles. + + let spillset = self.ctx.bundles[bundle].spillset; + + // Have we reached the maximum split count? If so, fall back + // to a "minimal bundles and spill bundle" setup for this + // bundle. See the doc-comment on + // `split_into_minimal_bundles()` above for more. + if self.ctx.spillsets[spillset].splits >= MAX_SPLITS_PER_SPILLSET { + self.split_into_minimal_bundles(bundle, reg_hint); + return; + } + self.ctx.spillsets[spillset].splits += 1; + + debug_assert!(!self.ctx.bundles[bundle].ranges.is_empty()); + // Split point *at* start is OK; this means we peel off + // exactly one use to create a minimal bundle. + let bundle_start = self.ctx.bundles[bundle].ranges.first().unwrap().range.from; + debug_assert!(split_at >= bundle_start); + let bundle_end = self.ctx.bundles[bundle].ranges.last().unwrap().range.to; + debug_assert!(split_at < bundle_end); + + // Is the split point *at* the start? If so, peel off the + // first use: set the split point just after it, or just + // before it if it comes after the start of the bundle. + if split_at == bundle_start { + // Find any uses; if none, just chop off one instruction. + let mut first_use = None; + 'outer: for entry in &self.ctx.bundles[bundle].ranges { + for u in &self.ctx.ranges[entry.index].uses { + first_use = Some(u.pos); + break 'outer; + } + } + trace!(" -> first use loc is {:?}", first_use); + split_at = match first_use { + Some(pos) => { + if pos.inst() == bundle_start.inst() { + ProgPoint::before(pos.inst().next()) + } else { + ProgPoint::before(pos.inst()) + } + } + None => ProgPoint::before( + self.ctx.bundles[bundle] + .ranges + .first() + .unwrap() + .range + .from + .inst() + .next(), + ), + }; + trace!( + "split point is at bundle start; advancing to {:?}", + split_at + ); + } else { + // Don't split in the middle of an instruction -- this could + // create impossible moves (we cannot insert a move between an + // instruction's uses and defs). + if split_at.pos() == InstPosition::After { + split_at = split_at.next(); + } + if split_at >= bundle_end { + split_at = split_at.prev().prev(); + } + } + + debug_assert!(split_at > bundle_start && split_at < bundle_end); + + // We need to find which LRs fall on each side of the split, + // which LR we need to split down the middle, then update the + // current bundle, create a new one, and (re)-queue both. + + trace!(" -> LRs: {:?}", self.ctx.bundles[bundle].ranges); + + let mut last_lr_in_old_bundle_idx = 0; // last LR-list index in old bundle + let mut first_lr_in_new_bundle_idx = 0; // first LR-list index in new bundle + for (i, entry) in self.ctx.bundles[bundle].ranges.iter().enumerate() { + if split_at > entry.range.from { + last_lr_in_old_bundle_idx = i; + first_lr_in_new_bundle_idx = i; + } + if split_at < entry.range.to { + first_lr_in_new_bundle_idx = i; + + // When the bundle contains a fixed constraint, we advance the split point to right + // before the first instruction with a fixed use present. + if self.ctx.bundles[bundle].cached_fixed() { + for u in &self.ctx.ranges[entry.index].uses { + if u.pos < split_at { + continue; + } + + if matches!(u.operand.constraint(), OperandConstraint::FixedReg { .. }) { + split_at = ProgPoint::before(u.pos.inst()); + + if split_at > entry.range.from { + last_lr_in_old_bundle_idx = i; + } + + trace!(" -> advancing split point to {split_at:?}"); + + trim_ends_into_spill_bundle = false; + + break; + } + } + } + + break; + } + } + + trace!( + " -> last LR in old bundle: LR {:?}", + self.ctx.bundles[bundle].ranges[last_lr_in_old_bundle_idx] + ); + trace!( + " -> first LR in new bundle: LR {:?}", + self.ctx.bundles[bundle].ranges[first_lr_in_new_bundle_idx] + ); + + // Take the sublist of LRs that will go in the new bundle. + let mut new_lr_list: LiveRangeList = LiveRangeList::new_in(self.ctx.bump()); + new_lr_list.extend( + self.ctx.bundles[bundle] + .ranges + .iter() + .cloned() + .skip(first_lr_in_new_bundle_idx), + ); + self.ctx.bundles[bundle] + .ranges + .truncate(last_lr_in_old_bundle_idx + 1); + self.ctx.bundles[bundle].ranges.shrink_to_fit(); + + // If the first entry in `new_lr_list` is a LR that is split + // down the middle, replace it with a new LR and chop off the + // end of the same LR in the original list. + if split_at > new_lr_list[0].range.from { + debug_assert_eq!(last_lr_in_old_bundle_idx, first_lr_in_new_bundle_idx); + let orig_lr = new_lr_list[0].index; + let new_lr = self.ctx.ranges.add( + CodeRange { + from: split_at, + to: new_lr_list[0].range.to, + }, + self.ctx.bump(), + ); + self.ctx.ranges[new_lr].vreg = self.ranges[orig_lr].vreg; + trace!(" -> splitting LR {:?} into {:?}", orig_lr, new_lr); + let first_use = self.ctx.ranges[orig_lr] + .uses + .iter() + .position(|u| u.pos >= split_at) + .unwrap_or(self.ctx.ranges[orig_lr].uses.len()); + let mut rest_uses = UseList::new_in(self.ctx.bump()); + rest_uses.extend( + self.ctx.ranges[orig_lr] + .uses + .iter() + .cloned() + .skip(first_use), + ); + self.ctx.ranges[new_lr].uses = rest_uses; + self.ctx.ranges[orig_lr].uses.truncate(first_use); + self.ctx.ranges[orig_lr].uses.shrink_to_fit(); + self.recompute_range_properties(orig_lr); + self.recompute_range_properties(new_lr); + new_lr_list[0].index = new_lr; + new_lr_list[0].range = self.ctx.ranges[new_lr].range; + self.ctx.ranges[orig_lr].range.to = split_at; + self.ctx.bundles[bundle].ranges[last_lr_in_old_bundle_idx].range = + self.ctx.ranges[orig_lr].range; + + // Perform a lazy split in the VReg data. We just + // append the new LR and its range; we will sort by + // start of range, and fix up range ends, once when we + // iterate over the VReg's ranges after allocation + // completes (this is the only time when order + // matters). + self.ctx.vregs[self.ctx.ranges[new_lr].vreg] + .ranges + .push(LiveRangeListEntry { + range: self.ctx.ranges[new_lr].range, + index: new_lr, + }); + } + + let new_bundle = self.ctx.bundles.add(self.ctx.bump()); + trace!(" -> creating new bundle {:?}", new_bundle); + self.ctx.bundles[new_bundle].spillset = spillset; + for entry in &new_lr_list { + self.ctx.ranges[entry.index].bundle = new_bundle; + } + self.ctx.bundles[new_bundle].ranges = new_lr_list; + + if trim_ends_into_spill_bundle { + // Finally, handle moving LRs to the spill bundle when + // appropriate: If the first range in `new_bundle` or last + // range in `bundle` has "empty space" beyond the first or + // last use (respectively), trim it and put an empty LR into + // the spill bundle. (We are careful to treat the "starts at + // def" flag as an implicit first def even if no def-type Use + // is present.) + while let Some(entry) = self.ctx.bundles[bundle].ranges.last().cloned() { + let end = entry.range.to; + let vreg = self.ctx.ranges[entry.index].vreg; + let last_use = self.ctx.ranges[entry.index].uses.last().map(|u| u.pos); + if last_use.is_none() { + let spill = self + .get_or_create_spill_bundle(bundle, /* create_if_absent = */ true) + .unwrap(); + trace!( + " -> bundle {:?} range {:?}: no uses; moving to spill bundle {:?}", + bundle, + entry.index, + spill + ); + self.ctx.bundles[spill].ranges.push(entry); + self.ctx.bundles[bundle].ranges.pop(); + self.ctx.ranges[entry.index].bundle = spill; + continue; + } + let last_use = last_use.unwrap(); + let split = ProgPoint::before(last_use.inst().next()); + if split < end { + let spill = self + .get_or_create_spill_bundle(bundle, /* create_if_absent = */ true) + .unwrap(); + self.ctx.bundles[bundle].ranges.last_mut().unwrap().range.to = split; + self.ctx.ranges[self.ctx.bundles[bundle].ranges.last().unwrap().index] + .range + .to = split; + let range = CodeRange { + from: split, + to: end, + }; + let empty_lr = self.ctx.ranges.add(range, self.ctx.bump()); + self.ctx.bundles[spill].ranges.push(LiveRangeListEntry { + range, + index: empty_lr, + }); + self.ctx.ranges[empty_lr].bundle = spill; + self.ctx.vregs[vreg].ranges.push(LiveRangeListEntry { + range, + index: empty_lr, + }); + trace!( + " -> bundle {:?} range {:?}: last use implies split point {:?}", + bundle, + entry.index, + split + ); + trace!( + " -> moving trailing empty region to new spill bundle {:?} with new LR {:?}", + spill, + empty_lr + ); + } + break; + } + while let Some(entry) = self.ctx.bundles[new_bundle].ranges.first().cloned() { + if self.ctx.ranges[entry.index].has_flag(LiveRangeFlag::StartsAtDef) { + break; + } + let start = entry.range.from; + let vreg = self.ctx.ranges[entry.index].vreg; + let first_use = self.ctx.ranges[entry.index].uses.first().map(|u| u.pos); + if first_use.is_none() { + let spill = self + .get_or_create_spill_bundle(new_bundle, /* create_if_absent = */ true) + .unwrap(); + trace!( + " -> bundle {:?} range {:?}: no uses; moving to spill bundle {:?}", + new_bundle, + entry.index, + spill + ); + self.ctx.bundles[spill].ranges.push(entry); + self.ctx.bundles[new_bundle].ranges.drain(..1); + self.ctx.ranges[entry.index].bundle = spill; + continue; + } + let first_use = first_use.unwrap(); + let split = ProgPoint::before(first_use.inst()); + if split > start { + let spill = self + .get_or_create_spill_bundle(new_bundle, /* create_if_absent = */ true) + .unwrap(); + self.ctx.bundles[new_bundle] + .ranges + .first_mut() + .unwrap() + .range + .from = split; + self.ctx.ranges[self.ctx.bundles[new_bundle].ranges.first().unwrap().index] + .range + .from = split; + let range = CodeRange { + from: start, + to: split, + }; + let empty_lr = self.ctx.ranges.add(range, self.ctx.bump()); + self.ctx.bundles[spill].ranges.push(LiveRangeListEntry { + range, + index: empty_lr, + }); + self.ctx.ranges[empty_lr].bundle = spill; + self.ctx.vregs[vreg].ranges.push(LiveRangeListEntry { + range, + index: empty_lr, + }); + trace!( + " -> bundle {:?} range {:?}: first use implies split point {:?}", + bundle, + entry.index, + first_use, + ); + trace!( + " -> moving leading empty region to new spill bundle {:?} with new LR {:?}", + spill, + empty_lr + ); + } + break; + } + } + + if self.ctx.bundles[bundle].ranges.len() > 0 { + self.recompute_bundle_properties(bundle); + let prio = self.ctx.bundles[bundle].prio; + self.ctx + .allocation_queue + .insert(bundle, prio as usize, reg_hint); + } + if self.ctx.bundles[new_bundle].ranges.len() > 0 { + self.recompute_bundle_properties(new_bundle); + let prio = self.ctx.bundles[new_bundle].prio; + self.ctx + .allocation_queue + .insert(new_bundle, prio as usize, reg_hint); + } + } + + /// Splits the given bundle into minimal bundles per Use, falling + /// back onto the spill bundle. This must work for any bundle no + /// matter how many conflicts. + /// + /// This is meant to solve a quadratic-cost problem that exists + /// with "normal" splitting as implemented above. With that + /// procedure, , splitting a bundle produces two + /// halves. Furthermore, it has cost linear in the length of the + /// bundle, because the resulting half-bundles have their + /// requirements recomputed with a new scan, and because we copy + /// half the use-list over to the tail end sub-bundle. + /// + /// This works fine when a bundle has a handful of splits overall, + /// but not when an input has a systematic pattern of conflicts + /// that will require O(|bundle|) splits (e.g., every Use is + /// constrained to a different fixed register than the last + /// one). In such a case, we get quadratic behavior. + /// + /// This method implements a direct split into minimal bundles + /// along the whole length of the bundle, putting the regions + /// without uses in the spill bundle. We do this once the number + /// of splits in an original bundle (tracked by spillset) reaches + /// a pre-determined limit. + /// + /// This basically approximates what a non-splitting allocator + /// would do: it "spills" the whole bundle to possibly a + /// stackslot, or a second-chance register allocation at best, via + /// the spill bundle; and then does minimal reservations of + /// registers just at uses/defs and moves the "spilled" value + /// into/out of them immediately. + pub fn split_into_minimal_bundles(&mut self, bundle: LiveBundleIndex, reg_hint: PReg) { + assert_eq!(self.ctx.scratch_removed_lrs_vregs.len(), 0); + self.ctx.scratch_removed_lrs.clear(); + + let mut new_lrs: SmallVec<[(VRegIndex, LiveRangeIndex); 16]> = smallvec![]; + let mut new_bundles: SmallVec<[LiveBundleIndex; 16]> = smallvec![]; + + let spillset = self.ctx.bundles[bundle].spillset; + let spill = self + .get_or_create_spill_bundle(bundle, /* create_if_absent = */ true) + .unwrap(); + + trace!( + "Splitting bundle {:?} into minimal bundles with reg hint {}", + bundle, + reg_hint + ); + + let mut last_lr: Option = None; + let mut last_bundle: Option = None; + let mut last_inst: Option = None; + let mut last_vreg: Option = None; + + let mut spill_uses = UseList::new_in(self.ctx.bump()); + + let empty_vec = LiveRangeList::new_in(self.ctx.bump()); + for entry in core::mem::replace(&mut self.ctx.bundles[bundle].ranges, empty_vec) { + let lr_from = entry.range.from; + let lr_to = entry.range.to; + let vreg = self.ctx.ranges[entry.index].vreg; + + self.ctx.scratch_removed_lrs.insert(entry.index); + self.ctx.scratch_removed_lrs_vregs.insert(vreg); + + trace!(" -> removing old LR {:?} for vreg {:?}", entry.index, vreg); + + let mut spill_range = entry.range; + let mut spill_starts_def = false; + + let mut last_live_pos = entry.range.from; + let empty_vec = UseList::new_in(self.ctx.bump()); + for u in core::mem::replace(&mut self.ctx.ranges[entry.index].uses, empty_vec) { + trace!(" -> use {:?} (last_live_pos {:?})", u, last_live_pos); + + let is_def = u.operand.kind() == OperandKind::Def; + + // If this use has an `any` constraint, eagerly migrate it to the spill range. The + // reasoning here is that in the second-chance allocation for the spill bundle, + // any-constrained uses will be easy to satisfy. Solving those constraints earlier + // could create unnecessary conflicts with existing bundles that need to fit in a + // register, more strict requirements, so we delay them eagerly. + if u.operand.constraint() == OperandConstraint::Any { + trace!(" -> migrating this any-constrained use to the spill range"); + spill_uses.push(u); + + // Remember if we're moving the def of this vreg into the spill range, so that + // we can set the appropriate flags on it later. + spill_starts_def = spill_starts_def || is_def; + + continue; + } + + // If this is a def of the vreg the entry cares about, make sure that the spill + // range starts right before the next instruction so that the value is available. + if is_def { + trace!(" -> moving the spill range forward by one"); + spill_range.from = ProgPoint::before(u.pos.inst().next()); + } + + // If we just created a LR for this inst at the last + // pos, add this use to the same LR. + if Some(u.pos.inst()) == last_inst && Some(vreg) == last_vreg { + self.ctx.ranges[last_lr.unwrap()].uses.push(u); + trace!(" -> appended to last LR {:?}", last_lr.unwrap()); + continue; + } + + // The minimal bundle runs through the whole inst + // (up to the Before of the next inst), *unless* + // the original LR was only over the Before (up to + // the After) of this inst. + let to = core::cmp::min(ProgPoint::before(u.pos.inst().next()), lr_to); + + // If the last bundle was at the same inst, add a new + // LR to the same bundle; otherwise, create a LR and a + // new bundle. + if Some(u.pos.inst()) == last_inst { + let cr = CodeRange { from: u.pos, to }; + let lr = self.ctx.ranges.add(cr, self.ctx.bump()); + new_lrs.push((vreg, lr)); + self.ctx.ranges[lr].uses.push(u); + self.ctx.ranges[lr].vreg = vreg; + + trace!( + " -> created new LR {:?} but adding to existing bundle {:?}", + lr, + last_bundle.unwrap() + ); + // Edit the previous LR to end mid-inst. + self.ctx.bundles[last_bundle.unwrap()] + .ranges + .last_mut() + .unwrap() + .range + .to = u.pos; + self.ctx.ranges[last_lr.unwrap()].range.to = u.pos; + // Add this LR to the bundle. + self.ctx.bundles[last_bundle.unwrap()] + .ranges + .push(LiveRangeListEntry { + range: cr, + index: lr, + }); + self.ctx.ranges[lr].bundle = last_bundle.unwrap(); + last_live_pos = ProgPoint::before(u.pos.inst().next()); + continue; + } + + // Otherwise, create a new LR. + let pos = ProgPoint::before(u.pos.inst()); + let pos = core::cmp::max(lr_from, pos); + let cr = CodeRange { from: pos, to }; + let lr = self.ctx.ranges.add(cr, self.ctx.bump()); + new_lrs.push((vreg, lr)); + self.ctx.ranges[lr].uses.push(u); + self.ctx.ranges[lr].vreg = vreg; + + // Create a new bundle that contains only this LR. + let new_bundle = self.ctx.bundles.add(self.ctx.bump()); + self.ctx.ranges[lr].bundle = new_bundle; + self.ctx.bundles[new_bundle].spillset = spillset; + self.ctx.bundles[new_bundle] + .ranges + .push(LiveRangeListEntry { + range: cr, + index: lr, + }); + new_bundles.push(new_bundle); + + // If this use was a Def, set the StartsAtDef flag for the new LR. + if is_def { + self.ctx.ranges[lr].set_flag(LiveRangeFlag::StartsAtDef); + } + + trace!( + " -> created new LR {:?} range {:?} with new bundle {:?} for this use", + lr, + cr, + new_bundle + ); + + last_live_pos = ProgPoint::before(u.pos.inst().next()); + + last_lr = Some(lr); + last_bundle = Some(new_bundle); + last_inst = Some(u.pos.inst()); + last_vreg = Some(vreg); + } + + if !spill_range.is_empty() { + // Make one entry in the spill bundle that covers the whole range. + // TODO: it might be worth tracking enough state to only create this LR when there is + // open space in the original LR. + let spill_lr = self.ctx.ranges.add(spill_range, self.ctx.bump()); + self.ctx.ranges[spill_lr].vreg = vreg; + self.ctx.ranges[spill_lr].bundle = spill; + self.ctx.ranges[spill_lr].uses.extend(spill_uses.drain(..)); + new_lrs.push((vreg, spill_lr)); + + if spill_starts_def { + self.ctx.ranges[spill_lr].set_flag(LiveRangeFlag::StartsAtDef); + } + + self.ctx.bundles[spill].ranges.push(LiveRangeListEntry { + range: spill_range, + index: spill_lr, + }); + self.ctx.ranges[spill_lr].bundle = spill; + trace!( + " -> added spill range {:?} in new LR {:?} in spill bundle {:?}", + spill_range, + spill_lr, + spill + ); + } else { + assert!(spill_uses.is_empty()); + } + } + + // Remove all of the removed LRs from respective vregs' lists. + for vreg in self.ctx.scratch_removed_lrs_vregs.drain() { + let lrs = &mut self.ctx.scratch_removed_lrs; + self.ctx.vregs[vreg] + .ranges + .retain(|entry| !lrs.contains(&entry.index)); + } + + // Add the new LRs to their respective vreg lists. + for (vreg, lr) in new_lrs { + let range = self.ctx.ranges[lr].range; + let entry = LiveRangeListEntry { range, index: lr }; + self.ctx.vregs[vreg].ranges.push(entry); + } + + // Recompute bundle properties for all new bundles and enqueue + // them. + for bundle in new_bundles { + if self.ctx.bundles[bundle].ranges.len() > 0 { + self.recompute_bundle_properties(bundle); + let prio = self.ctx.bundles[bundle].prio; + self.ctx + .allocation_queue + .insert(bundle, prio as usize, reg_hint); + } + } + } + + pub fn process_bundle( + &mut self, + bundle: LiveBundleIndex, + reg_hint: PReg, + ) -> Result<(), RegAllocError> { + let class = self.ctx.spillsets[self.bundles[bundle].spillset].class; + // Grab a hint from either the queue or our spillset, if any. + let mut hint_reg = if reg_hint != PReg::invalid() { + reg_hint + } else { + self.ctx.spillsets[self.bundles[bundle].spillset].reg_hint + }; + if self.ctx.pregs[hint_reg.index()].is_stack { + hint_reg = PReg::invalid(); + } + trace!("process_bundle: bundle {:?} hint {:?}", bundle, hint_reg,); + + let req = match self.compute_requirement(bundle) { + Ok(req) => req, + Err(conflict) => { + trace!("conflict!: {:?}", conflict); + // We have to split right away. We'll find a point to + // split that would allow at least the first half of the + // split to be conflict-free. + debug_assert!( + !self.minimal_bundle(bundle), + "Minimal bundle with conflict!" + ); + self.split_and_requeue_bundle( + bundle, + /* split_at_point = */ conflict.suggested_split_point(), + reg_hint, + /* trim_ends_into_spill_bundle = */ + conflict.should_trim_edges_around_split(), + ); + return Ok(()); + } + }; + + // If no requirement at all (because no uses), and *if* a + // spill bundle is already present, then move the LRs over to + // the spill bundle right away. + match req { + Requirement::Any => { + if let Some(spill) = + self.get_or_create_spill_bundle(bundle, /* create_if_absent = */ false) + { + let empty_vec = LiveRangeList::new_in(self.ctx.bump()); + let mut list = + core::mem::replace(&mut self.ctx.bundles[bundle].ranges, empty_vec); + for entry in &list { + self.ctx.ranges[entry.index].bundle = spill; + } + self.ctx.bundles[spill].ranges.extend(list.drain(..)); + return Ok(()); + } + } + _ => {} + } + + // Try to allocate! + let mut attempts = 0; + let mut scratch = core::mem::take(&mut self.ctx.scratch_conflicts); + let mut lowest_cost_evict_conflict_set = core::mem::take(&mut self.ctx.scratch_bundle); + 'outer: loop { + attempts += 1; + trace!("attempt {}, req {:?}", attempts, req); + debug_assert!(attempts < 100 * self.func.num_insts()); + + let fixed_preg = match req { + Requirement::FixedReg(preg) | Requirement::FixedStack(preg) => Some(preg), + Requirement::Register => None, + + Requirement::Any => { + self.ctx.spilled_bundles.push(bundle); + break; + } + }; + // Scan all pregs, or the one fixed preg, and attempt to allocate. + + let mut lowest_cost_evict_conflict_cost: Option = None; + lowest_cost_evict_conflict_set.clear(); + + let mut lowest_cost_split_conflict_cost: Option = None; + let mut lowest_cost_split_conflict_point = ProgPoint::before(Inst::new(0)); + let mut lowest_cost_split_conflict_reg = PReg::invalid(); + + // Heuristic: start the scan for an available + // register at an offset influenced both by our + // location in the code and by the bundle we're + // considering. This has the effect of spreading + // demand more evenly across registers. + let scan_offset = self.ctx.ranges[self.bundles[bundle].ranges[0].index] + .range + .from + .inst() + .index() + + bundle.index(); + + self.ctx.output.stats.process_bundle_reg_probe_start_any += 1; + for preg in RegTraversalIter::new( + self.env, + class, + hint_reg, + PReg::invalid(), + scan_offset, + fixed_preg, + ) { + self.ctx.output.stats.process_bundle_reg_probes_any += 1; + let preg_idx = PRegIndex::new(preg.index()); + trace!("trying preg {:?}", preg_idx); + + let scan_limit_cost = match ( + lowest_cost_evict_conflict_cost, + lowest_cost_split_conflict_cost, + ) { + (Some(a), Some(b)) => Some(core::cmp::max(a, b)), + _ => None, + }; + match self.try_to_allocate_bundle_to_reg( + bundle, + preg_idx, + scan_limit_cost, + &mut scratch, + ) { + AllocRegResult::Allocated(alloc) => { + self.ctx.output.stats.process_bundle_reg_success_any += 1; + trace!(" -> allocated to any {:?}", preg_idx); + self.ctx.spillsets[self.ctx.bundles[bundle].spillset].reg_hint = + alloc.as_reg().unwrap(); + // Success, return scratch memory to context and finish + break 'outer; + } + AllocRegResult::Conflict(bundles, first_conflict_point) => { + trace!( + " -> conflict with bundles {:?}, first conflict at {:?}", + bundles, + first_conflict_point + ); + + let conflict_cost = self.maximum_spill_weight_in_bundle_set(bundles); + + if lowest_cost_evict_conflict_cost.is_none() + || conflict_cost < lowest_cost_evict_conflict_cost.unwrap() + { + lowest_cost_evict_conflict_cost = Some(conflict_cost); + lowest_cost_evict_conflict_set.clear(); + lowest_cost_evict_conflict_set.extend(bundles); + } + + let loop_depth = + self.ctx.cfginfo.approx_loop_depth[self.ctx.cfginfo.insn_block + [first_conflict_point.inst().index()] + .index()]; + let move_cost = spill_weight_from_constraint( + OperandConstraint::Reg, + loop_depth as usize, + /* is_def = */ true, + ) + .to_int(); + if lowest_cost_split_conflict_cost.is_none() + || (conflict_cost + move_cost) + < lowest_cost_split_conflict_cost.unwrap() + { + lowest_cost_split_conflict_cost = Some(conflict_cost + move_cost); + lowest_cost_split_conflict_point = first_conflict_point; + lowest_cost_split_conflict_reg = preg; + } + } + AllocRegResult::ConflictWithFixed(max_cost, point) => { + trace!(" -> conflict with fixed alloc; cost of other bundles up to point is {}, conflict at {:?}", max_cost, point); + + let loop_depth = self.ctx.cfginfo.approx_loop_depth + [self.ctx.cfginfo.insn_block[point.inst().index()].index()]; + let move_cost = spill_weight_from_constraint( + OperandConstraint::Reg, + loop_depth as usize, + /* is_def = */ true, + ) + .to_int(); + + if lowest_cost_split_conflict_cost.is_none() + || (max_cost + move_cost) < lowest_cost_split_conflict_cost.unwrap() + { + lowest_cost_split_conflict_cost = Some(max_cost + move_cost); + lowest_cost_split_conflict_point = point; + lowest_cost_split_conflict_reg = preg; + } + } + AllocRegResult::ConflictHighCost => { + // Simply don't consider -- we already have + // a lower-cost conflict bundle option + // to evict. + continue; + } + } + } + + // Otherwise, we *require* a register, but didn't fit into + // any with current bundle assignments. Hence, we will need + // to either split or attempt to evict some bundles. + + trace!( + " -> lowest cost evict: set {:?}, cost {:?}", + lowest_cost_evict_conflict_set, + lowest_cost_evict_conflict_cost, + ); + trace!( + " -> lowest cost split: cost {:?}, point {:?}, reg {:?}", + lowest_cost_split_conflict_cost, + lowest_cost_split_conflict_point, + lowest_cost_split_conflict_reg + ); + + // If we reach here, we *must* have an option either to split or evict. + debug_assert!( + lowest_cost_split_conflict_cost.is_some() + || lowest_cost_evict_conflict_cost.is_some() + ); + + let our_spill_weight = self.bundle_spill_weight(bundle); + trace!(" -> our spill weight: {}", our_spill_weight); + + // We detect the "too-many-live-registers" case here and + // return an error cleanly, rather than panicking, because + // the regalloc.rs fuzzer depends on the register + // allocator to correctly reject impossible-to-allocate + // programs in order to discard invalid test cases. + if self.minimal_bundle(bundle) + && (attempts >= 2 + || lowest_cost_evict_conflict_cost.is_none() + || lowest_cost_evict_conflict_cost.unwrap() >= our_spill_weight) + { + if let Requirement::Register = req { + // Check if this is a too-many-live-registers situation. + let range = self.ctx.bundles[bundle].ranges[0].range; + trace!("checking for too many live regs"); + let mut min_bundles_assigned = 0; + let mut fixed_assigned = 0; + let mut total_regs = 0; + for preg in self.env.preferred_regs_by_class[class as u8 as usize] + .iter() + .chain(self.env.non_preferred_regs_by_class[class as u8 as usize].iter()) + { + trace!(" -> PR {:?}", preg); + let start = LiveRangeKey::from_range(&CodeRange { + from: range.from.prev(), + to: range.from.prev(), + }); + for (key, lr) in self.ctx.pregs[preg.index()] + .allocations + .btree + .range(start..) + { + let preg_range = key.to_range(); + if preg_range.to <= range.from { + continue; + } + if preg_range.from >= range.to { + break; + } + if lr.is_valid() { + if self.minimal_bundle(self.ranges[*lr].bundle) { + trace!(" -> min bundle {:?}", lr); + min_bundles_assigned += 1; + } else { + trace!(" -> non-min bundle {:?}", lr); + } + } else { + trace!(" -> fixed bundle"); + fixed_assigned += 1; + } + } + total_regs += 1; + } + trace!( + " -> total {}, fixed {}, min {}", + total_regs, + fixed_assigned, + min_bundles_assigned + ); + if min_bundles_assigned + fixed_assigned >= total_regs { + return Err(RegAllocError::TooManyLiveRegs); + } + } + + panic!("Could not allocate minimal bundle, but the allocation problem should be possible to solve"); + } + + // If our bundle's weight is less than or equal to(*) the + // evict cost, choose to split. Also pick splitting if + // we're on our second or more attempt and we didn't + // allocate. Also pick splitting if the conflict set is + // empty, meaning a fixed conflict that can't be evicted. + // + // (*) the "equal to" part is very important: it prevents + // an infinite loop where two bundles with equal spill + // cost continually evict each other in an infinite + // allocation loop. In such a case, the first bundle in + // wins, and the other splits. + // + // Note that we don't split if the bundle is minimal. + if !self.minimal_bundle(bundle) + && (attempts >= 2 + || lowest_cost_evict_conflict_cost.is_none() + || our_spill_weight <= lowest_cost_evict_conflict_cost.unwrap()) + { + trace!( + " -> deciding to split: our spill weight is {}", + self.bundle_spill_weight(bundle) + ); + let bundle_start = self.ctx.bundles[bundle].ranges[0].range.from; + let mut split_at_point = + core::cmp::max(lowest_cost_split_conflict_point, bundle_start); + let requeue_with_reg = lowest_cost_split_conflict_reg; + + // Adjust `split_at_point` if it is within a deeper loop + // than the bundle start -- hoist it to just before the + // first loop header it encounters. + let bundle_start_depth = self.ctx.cfginfo.approx_loop_depth + [self.ctx.cfginfo.insn_block[bundle_start.inst().index()].index()]; + let split_at_depth = self.ctx.cfginfo.approx_loop_depth + [self.ctx.cfginfo.insn_block[split_at_point.inst().index()].index()]; + if split_at_depth > bundle_start_depth { + for block in (self.ctx.cfginfo.insn_block[bundle_start.inst().index()].index() + + 1) + ..=self.ctx.cfginfo.insn_block[split_at_point.inst().index()].index() + { + if self.ctx.cfginfo.approx_loop_depth[block] > bundle_start_depth { + split_at_point = self.ctx.cfginfo.block_entry[block]; + break; + } + } + } + + self.split_and_requeue_bundle( + bundle, + split_at_point, + requeue_with_reg, + /* should_trim = */ true, + ); + + // Success, return scratch memory to context and finish + break 'outer; + } else { + // Evict all bundles in `conflicting bundles` and try again. + self.ctx.output.stats.evict_bundle_event += 1; + for &bundle in &lowest_cost_evict_conflict_set { + trace!(" -> evicting {:?}", bundle); + self.evict_bundle(bundle); + self.ctx.output.stats.evict_bundle_count += 1; + } + } + } + + self.ctx.scratch_conflicts = scratch; + self.ctx.scratch_bundle = lowest_cost_evict_conflict_set; + return Ok(()); + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/redundant_moves.rs b/deps/crates/vendor/regalloc2/src/ion/redundant_moves.rs new file mode 100644 index 00000000000000..36c8c1eb88b577 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/redundant_moves.rs @@ -0,0 +1,129 @@ +//! Redundant-move elimination. + +use crate::{Allocation, FxHashMap, VReg}; +use smallvec::{smallvec, SmallVec}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RedundantMoveState { + Copy(Allocation, Option), + Orig(VReg), + None, +} +#[derive(Clone, Debug, Default)] +pub struct RedundantMoveEliminator { + allocs: FxHashMap, + reverse_allocs: FxHashMap>, +} +#[derive(Copy, Clone, Debug)] +pub struct RedundantMoveAction { + pub elide: bool, +} + +impl RedundantMoveEliminator { + pub fn process_move( + &mut self, + from: Allocation, + to: Allocation, + to_vreg: Option, + ) -> RedundantMoveAction { + // Look up the src and dest. + let from_state = self + .allocs + .get(&from) + .map(|&p| p) + .unwrap_or(RedundantMoveState::None); + let to_state = self + .allocs + .get(&to) + .map(|&p| p) + .unwrap_or(RedundantMoveState::None); + + trace!( + " -> redundant move tracker: from {} to {} to_vreg {:?}", + from, + to, + to_vreg + ); + trace!( + " -> from_state {:?} to_state {:?}", + from_state, + to_state + ); + + if from == to && to_vreg.is_some() { + self.clear_alloc(to); + self.allocs + .insert(to, RedundantMoveState::Orig(to_vreg.unwrap())); + return RedundantMoveAction { elide: true }; + } + + let src_vreg = match from_state { + RedundantMoveState::Copy(_, opt_r) => opt_r, + RedundantMoveState::Orig(r) => Some(r), + _ => None, + }; + trace!(" -> src_vreg {:?}", src_vreg); + let dst_vreg = to_vreg.or(src_vreg); + trace!(" -> dst_vreg {:?}", dst_vreg); + let existing_dst_vreg = match to_state { + RedundantMoveState::Copy(_, opt_r) => opt_r, + RedundantMoveState::Orig(r) => Some(r), + _ => None, + }; + trace!(" -> existing_dst_vreg {:?}", existing_dst_vreg); + + let elide = match (from_state, to_state) { + (_, RedundantMoveState::Copy(orig_alloc, _)) if orig_alloc == from => true, + (RedundantMoveState::Copy(new_alloc, _), _) if new_alloc == to => true, + _ => false, + }; + trace!(" -> elide {}", elide); + + // Invalidate all existing copies of `to` if `to` actually changed value. + if !elide { + self.clear_alloc(to); + } + + // Set up forward and reverse mapping. Don't track stack-to-stack copies. + if from.is_reg() || to.is_reg() { + self.allocs + .insert(to, RedundantMoveState::Copy(from, dst_vreg)); + trace!( + " -> create mapping {} -> {:?}", + to, + RedundantMoveState::Copy(from, dst_vreg) + ); + self.reverse_allocs + .entry(from) + .or_insert_with(|| smallvec![]) + .push(to); + } + + RedundantMoveAction { elide } + } + + pub fn clear(&mut self) { + trace!(" redundant move eliminator cleared"); + self.allocs.clear(); + self.reverse_allocs.clear(); + } + + pub fn clear_alloc(&mut self, alloc: Allocation) { + trace!(" redundant move eliminator: clear {:?}", alloc); + if let Some(ref mut existing_copies) = self.reverse_allocs.get_mut(&alloc) { + for to_inval in existing_copies.drain(..) { + trace!(" -> clear existing copy: {:?}", to_inval); + if let Some(val) = self.allocs.get_mut(&to_inval) { + match val { + RedundantMoveState::Copy(_, Some(vreg)) => { + *val = RedundantMoveState::Orig(*vreg); + } + _ => *val = RedundantMoveState::None, + } + } + self.allocs.remove(&to_inval); + } + } + self.allocs.remove(&alloc); + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/reg_traversal.rs b/deps/crates/vendor/regalloc2/src/ion/reg_traversal.rs new file mode 100644 index 00000000000000..729fd33eb30ee1 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/reg_traversal.rs @@ -0,0 +1,123 @@ +use crate::{MachineEnv, PReg, RegClass}; + +/// This iterator represents a traversal through all allocatable +/// registers of a given class, in a certain order designed to +/// minimize allocation contention. +/// +/// The order in which we try registers is somewhat complex: +/// - First, if there is a hint, we try that. +/// - Then, we try registers in a traversal order that is based on an +/// "offset" (usually the bundle index) spreading pressure evenly +/// among registers to reduce commitment-map contention. +/// - Within that scan, we try registers in two groups: first, +/// prferred registers; then, non-preferred registers. (In normal +/// usage, these consist of caller-save and callee-save registers +/// respectively, to minimize clobber-saves; but they need not.) + +pub struct RegTraversalIter<'a> { + env: &'a MachineEnv, + class: usize, + hints: [Option; 2], + hint_idx: usize, + pref_idx: usize, + non_pref_idx: usize, + offset_pref: usize, + offset_non_pref: usize, + is_fixed: bool, + fixed: Option, +} + +impl<'a> RegTraversalIter<'a> { + pub fn new( + env: &'a MachineEnv, + class: RegClass, + hint_reg: PReg, + hint2_reg: PReg, + offset: usize, + fixed: Option, + ) -> Self { + let mut hint_reg = if hint_reg != PReg::invalid() { + Some(hint_reg) + } else { + None + }; + let mut hint2_reg = if hint2_reg != PReg::invalid() { + Some(hint2_reg) + } else { + None + }; + + if hint_reg.is_none() { + hint_reg = hint2_reg; + hint2_reg = None; + } + let hints = [hint_reg, hint2_reg]; + let class = class as u8 as usize; + let offset_pref = if env.preferred_regs_by_class[class].len() > 0 { + offset % env.preferred_regs_by_class[class].len() + } else { + 0 + }; + let offset_non_pref = if env.non_preferred_regs_by_class[class].len() > 0 { + offset % env.non_preferred_regs_by_class[class].len() + } else { + 0 + }; + Self { + env, + class, + hints, + hint_idx: 0, + pref_idx: 0, + non_pref_idx: 0, + offset_pref, + offset_non_pref, + is_fixed: fixed.is_some(), + fixed, + } + } +} + +impl<'a> core::iter::Iterator for RegTraversalIter<'a> { + type Item = PReg; + + fn next(&mut self) -> Option { + if self.is_fixed { + let ret = self.fixed; + self.fixed = None; + return ret; + } + + fn wrap(idx: usize, limit: usize) -> usize { + if idx >= limit { + idx - limit + } else { + idx + } + } + if self.hint_idx < 2 && self.hints[self.hint_idx].is_some() { + let h = self.hints[self.hint_idx]; + self.hint_idx += 1; + return h; + } + while self.pref_idx < self.env.preferred_regs_by_class[self.class].len() { + let arr = &self.env.preferred_regs_by_class[self.class][..]; + let r = arr[wrap(self.pref_idx + self.offset_pref, arr.len())]; + self.pref_idx += 1; + if Some(r) == self.hints[0] || Some(r) == self.hints[1] { + continue; + } + return Some(r); + } + while self.non_pref_idx < self.env.non_preferred_regs_by_class[self.class].len() { + let arr = &self.env.non_preferred_regs_by_class[self.class][..]; + let r = arr[wrap(self.non_pref_idx + self.offset_non_pref, arr.len())]; + self.non_pref_idx += 1; + if Some(r) == self.hints[0] || Some(r) == self.hints[1] { + continue; + } + return Some(r); + } + None + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/requirement.rs b/deps/crates/vendor/regalloc2/src/ion/requirement.rs new file mode 100644 index 00000000000000..5e9af2a3d8f969 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/requirement.rs @@ -0,0 +1,167 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Requirements computation. + +use super::{Env, LiveBundleIndex}; +use crate::{Function, Inst, Operand, OperandConstraint, PReg, ProgPoint}; + +pub struct RequirementConflict; + +#[derive(Clone, Copy, Debug)] +pub enum RequirementConflictAt { + /// A transition from a stack-constrained to a reg-constrained + /// segment. The suggested split point is late, to keep the + /// intervening region with the stackslot (which is cheaper). + StackToReg(ProgPoint), + /// A transition from a reg-constraint to a stack-constrained + /// segment. Mirror of above: the suggested split point is early + /// (just after the last register use). + RegToStack(ProgPoint), + /// Any other transition. The suggested split point is late (just + /// before the conflicting use), but the split will also trim the + /// ends and create a split bundle, so the intervening region will + /// not appear with either side. This is probably for the best + /// when e.g. the two sides of the split are both constrained to + /// different physical registers: the part in the middle should be + /// constrained to neither. + Other(ProgPoint), +} + +impl RequirementConflictAt { + #[inline(always)] + pub fn should_trim_edges_around_split(self) -> bool { + match self { + RequirementConflictAt::RegToStack(..) | RequirementConflictAt::StackToReg(..) => false, + RequirementConflictAt::Other(..) => true, + } + } + + #[inline(always)] + pub fn suggested_split_point(self) -> ProgPoint { + match self { + RequirementConflictAt::RegToStack(pt) + | RequirementConflictAt::StackToReg(pt) + | RequirementConflictAt::Other(pt) => pt, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Requirement { + FixedReg(PReg), + FixedStack(PReg), + Register, + Any, +} +impl Requirement { + #[inline(always)] + pub fn merge(self, other: Requirement) -> Result { + match (self, other) { + (other, Requirement::Any) | (Requirement::Any, other) => Ok(other), + (Requirement::Register, Requirement::Register) => Ok(self), + (Requirement::Register, Requirement::FixedReg(preg)) + | (Requirement::FixedReg(preg), Requirement::Register) => { + Ok(Requirement::FixedReg(preg)) + } + (Requirement::FixedReg(a), Requirement::FixedReg(b)) if a == b => Ok(self), + (Requirement::FixedStack(a), Requirement::FixedStack(b)) if a == b => Ok(self), + _ => Err(RequirementConflict), + } + } + + #[inline(always)] + pub fn is_stack(self) -> bool { + match self { + Requirement::FixedStack(..) => true, + Requirement::Register | Requirement::FixedReg(..) => false, + Requirement::Any => false, + } + } + + #[inline(always)] + pub fn is_reg(self) -> bool { + match self { + Requirement::Register | Requirement::FixedReg(..) => true, + Requirement::FixedStack(..) => false, + Requirement::Any => false, + } + } +} + +impl<'a, F: Function> Env<'a, F> { + #[inline(always)] + pub fn requirement_from_operand(&self, op: Operand) -> Requirement { + match op.constraint() { + OperandConstraint::FixedReg(preg) => { + if self.pregs[preg.index()].is_stack { + Requirement::FixedStack(preg) + } else { + Requirement::FixedReg(preg) + } + } + OperandConstraint::Reg | OperandConstraint::Reuse(_) => Requirement::Register, + OperandConstraint::Any => Requirement::Any, + } + } + + pub fn compute_requirement( + &self, + bundle: LiveBundleIndex, + ) -> Result { + let mut req = Requirement::Any; + let mut last_pos = ProgPoint::before(Inst::new(0)); + trace!("compute_requirement: {:?}", bundle); + let ranges = &self.bundles[bundle].ranges; + for entry in ranges { + trace!(" -> LR {:?}: {:?}", entry.index, entry.range); + for u in &self.ranges[entry.index].uses { + trace!(" -> use {:?}", u); + let r = self.requirement_from_operand(u.operand); + req = req.merge(r).map_err(|_| { + trace!(" -> conflict"); + if req.is_stack() && r.is_reg() { + // Suggested split point just before the reg (i.e., late split). + RequirementConflictAt::StackToReg(u.pos) + } else if req.is_reg() && r.is_stack() { + // Suggested split point just after the stack + // (i.e., early split). Note that splitting + // with a use *right* at the beginning is + // interpreted by `split_and_requeue_bundle` + // as splitting off the first use. + RequirementConflictAt::RegToStack(last_pos) + } else { + RequirementConflictAt::Other(u.pos) + } + })?; + last_pos = u.pos; + trace!(" -> req {:?}", req); + } + } + trace!(" -> final: {:?}", req); + Ok(req) + } + + pub fn merge_bundle_requirements( + &self, + a: LiveBundleIndex, + b: LiveBundleIndex, + ) -> Result { + let req_a = self + .compute_requirement(a) + .map_err(|_| RequirementConflict)?; + let req_b = self + .compute_requirement(b) + .map_err(|_| RequirementConflict)?; + req_a.merge(req_b) + } +} diff --git a/deps/crates/vendor/regalloc2/src/ion/spill.rs b/deps/crates/vendor/regalloc2/src/ion/spill.rs new file mode 100644 index 00000000000000..c40efc80074e7d --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ion/spill.rs @@ -0,0 +1,171 @@ +/* + * This file was initially derived from the files + * `js/src/jit/BacktrackingAllocator.h` and + * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was + * originally licensed under the Mozilla Public License 2.0. We + * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see + * https://github.com/bytecodealliance/regalloc2/issues/7). + * + * Since the initial port, the design has been substantially evolved + * and optimized. + */ + +//! Spillslot allocation. + +use super::{ + AllocRegResult, Env, LiveRangeKey, PReg, PRegIndex, RegTraversalIter, SpillSetIndex, + SpillSlotData, SpillSlotIndex, +}; +use crate::{Allocation, Function, SpillSlot}; + +impl<'a, F: Function> Env<'a, F> { + pub fn try_allocating_regs_for_spilled_bundles(&mut self) { + trace!("allocating regs for spilled bundles"); + let mut scratch = core::mem::take(&mut self.ctx.scratch_conflicts); + for i in 0..self.ctx.spilled_bundles.len() { + let bundle = self.ctx.spilled_bundles[i]; // don't borrow self + + if self.ctx.bundles[bundle].ranges.is_empty() { + continue; + } + + let class = self.ctx.spillsets[self.ctx.bundles[bundle].spillset].class; + let hint = self.ctx.spillsets[self.ctx.bundles[bundle].spillset].reg_hint; + + // This may be an empty-range bundle whose ranges are not + // sorted; sort all range-lists again here. + self.ctx.bundles[bundle] + .ranges + .sort_unstable_by_key(|entry| entry.range.from); + + let mut success = false; + self.ctx.output.stats.spill_bundle_reg_probes += 1; + for preg in + RegTraversalIter::new(self.env, class, hint, PReg::invalid(), bundle.index(), None) + { + trace!("trying bundle {:?} to preg {:?}", bundle, preg); + let preg_idx = PRegIndex::new(preg.index()); + if let AllocRegResult::Allocated(_) = + self.try_to_allocate_bundle_to_reg(bundle, preg_idx, None, &mut scratch) + { + self.ctx.output.stats.spill_bundle_reg_success += 1; + success = true; + break; + } + } + if !success { + trace!( + "spilling bundle {:?}: marking spillset {:?} as required", + bundle, + self.ctx.bundles[bundle].spillset + ); + self.ctx.spillsets[self.ctx.bundles[bundle].spillset].required = true; + } + } + self.ctx.scratch_conflicts = scratch; + } + + pub fn spillslot_can_fit_spillset( + &mut self, + spillslot: SpillSlotIndex, + spillset: SpillSetIndex, + ) -> bool { + !self.ctx.spillslots[spillslot.index()] + .ranges + .btree + .contains_key(&LiveRangeKey::from_range( + &self.ctx.spillsets[spillset].range, + )) + } + + pub fn allocate_spillset_to_spillslot( + &mut self, + spillset: SpillSetIndex, + spillslot: SpillSlotIndex, + ) { + self.ctx.spillsets[spillset].slot = spillslot; + + let res = self.ctx.spillslots[spillslot.index()].ranges.btree.insert( + LiveRangeKey::from_range(&self.ctx.spillsets[spillset].range), + spillset, + ); + + debug_assert!(res.is_none()); + } + + pub fn allocate_spillslots(&mut self) { + const MAX_ATTEMPTS: usize = 10; + + for spillset in 0..self.ctx.spillsets.len() { + trace!("allocate spillslot: {}", spillset); + let spillset = SpillSetIndex::new(spillset); + if !self.ctx.spillsets[spillset].required { + continue; + } + let class = self.ctx.spillsets[spillset].class as usize; + // Try a few existing spillslots. + let mut i = self.ctx.slots_by_class[class].probe_start; + let mut success = false; + // Never probe the same element more than once: limit the + // attempt count to the number of slots in existence. + for _attempt in + 0..core::cmp::min(self.ctx.slots_by_class[class].slots.len(), MAX_ATTEMPTS) + { + // Note: this indexing of `slots` is always valid + // because either the `slots` list is empty and the + // iteration limit above consequently means we don't + // run this loop at all, or else `probe_start` is + // in-bounds (because it is made so below when we add + // a slot, and it always takes on the last index `i` + // after this loop). + let spillslot = self.ctx.slots_by_class[class].slots[i]; + + if self.spillslot_can_fit_spillset(spillslot, spillset) { + self.allocate_spillset_to_spillslot(spillset, spillslot); + success = true; + self.ctx.slots_by_class[class].probe_start = i; + break; + } + + i = self.ctx.slots_by_class[class].next_index(i); + } + + if !success { + // Allocate a new spillslot. + let spillslot = SpillSlotIndex::new(self.ctx.spillslots.len()); + self.ctx.spillslots.push(SpillSlotData { + ranges: self.ctx.scratch_spillset_pool.pop().unwrap_or_default(), + alloc: Allocation::none(), + slots: self.func.spillslot_size(self.ctx.spillsets[spillset].class) as u32, + }); + self.ctx.slots_by_class[class].slots.push(spillslot); + self.ctx.slots_by_class[class].probe_start = + self.ctx.slots_by_class[class].slots.len() - 1; + + self.allocate_spillset_to_spillslot(spillset, spillslot); + } + } + + // Assign actual slot indices to spillslots. + for i in 0..self.ctx.spillslots.len() { + self.ctx.spillslots[i].alloc = self.allocate_spillslot(self.ctx.spillslots[i].slots); + } + + trace!("spillslot allocator done"); + } + + pub fn allocate_spillslot(&mut self, size: u32) -> Allocation { + let mut offset = self.ctx.output.num_spillslots as u32; + // Align up to `size`. + debug_assert!(size.is_power_of_two()); + offset = (offset + size - 1) & !(size - 1); + let slot = if self.func.multi_spillslot_named_by_last_slot() { + offset + size - 1 + } else { + offset + }; + offset += size; + self.ctx.output.num_spillslots = offset as _; + Allocation::stack(SpillSlot::new(slot as usize)) + } +} diff --git a/deps/crates/vendor/regalloc2/src/lib.rs b/deps/crates/vendor/regalloc2/src/lib.rs new file mode 100644 index 00000000000000..539466a8eb5037 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/lib.rs @@ -0,0 +1,1731 @@ +/* + * The following license applies to this file, which derives many + * details (register and constraint definitions, for example) from the + * files `BacktrackingAllocator.h`, `BacktrackingAllocator.cpp`, + * `LIR.h`, and possibly definitions in other related files in + * `js/src/jit/`: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#![allow(dead_code)] +#![allow(clippy::all)] +#![no_std] + +#[cfg(feature = "std")] +extern crate std; + +extern crate alloc; + +// Even when trace logging is disabled, the trace macro has a significant +// performance cost so we disable it in release builds. +macro_rules! trace { + ($($tt:tt)*) => { + if cfg!(feature = "trace-log") { + ::log::trace!($($tt)*); + } + }; +} + +macro_rules! trace_enabled { + () => { + cfg!(feature = "trace-log") && ::log::log_enabled!(::log::Level::Trace) + }; +} + +use alloc::rc::Rc; +use allocator_api2::vec::Vec as Vec2; +use core::ops::Deref as _; +use core::{hash::BuildHasherDefault, iter::FromIterator}; +use rustc_hash::FxHasher; +type FxHashMap = hashbrown::HashMap>; +type FxHashSet = hashbrown::HashSet>; + +pub(crate) mod cfg; +pub(crate) mod domtree; +pub(crate) mod fastalloc; +pub mod indexset; +pub(crate) mod ion; +pub(crate) mod moves; +pub(crate) mod postorder; +pub mod ssa; + +#[macro_use] +mod index; + +pub use self::ion::data_structures::Ctx; +use alloc::vec::Vec; +pub use index::{Block, Inst, InstRange}; + +pub mod checker; + +#[cfg(feature = "fuzzing")] +pub mod fuzzing; + +#[cfg(feature = "enable-serde")] +pub mod serialize; + +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +/// Register classes. +/// +/// Every value has a "register class", which is like a type at the +/// register-allocator level. Every register must belong to only one +/// class; i.e., they are disjoint. +/// +/// For tight bit-packing throughout our data structures, we support +/// only three classes, "int", "float" and "vector". Usually two will +/// be enough on modern machines, as they have one class of general-purpose +/// integer registers of machine width (e.g. 64 bits), and another +/// class of float/vector registers used both for FP and for vector +/// operations. Additionally for machines with totally separate vector +/// registers a third class is provided. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum RegClass { + Int = 0, + Float = 1, + Vector = 2, +} + +/// A physical register. Contains a physical register number and a class. +/// +/// The `hw_enc` field contains the physical register number and is in +/// a logically separate index space per class; in other words, Int +/// register 0 is different than Float register 0. +/// +/// Because of bit-packed encodings throughout the implementation, +/// `hw_enc` must fit in 6 bits, i.e., at most 64 registers per class. +/// +/// The value returned by `index()`, in contrast, is in a single index +/// space shared by all classes, in order to enable uniform reasoning +/// about physical registers. This is done by putting the class bit at +/// the MSB, or equivalently, declaring that indices 0..=63 are the 64 +/// integer registers and indices 64..=127 are the 64 float registers. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PReg { + bits: u8, +} + +impl PReg { + pub const MAX_BITS: usize = 6; + pub const MAX: usize = (1 << Self::MAX_BITS) - 1; + pub const NUM_INDEX: usize = 1 << (Self::MAX_BITS + 2); // including RegClass bits + + /// Create a new PReg. The `hw_enc` range is 6 bits. + #[inline(always)] + pub const fn new(hw_enc: usize, class: RegClass) -> Self { + debug_assert!(hw_enc <= PReg::MAX); + PReg { + bits: ((class as u8) << Self::MAX_BITS) | (hw_enc as u8), + } + } + + /// The physical register number, as encoded by the ISA for the particular register class. + #[inline(always)] + pub const fn hw_enc(self) -> usize { + self.bits as usize & Self::MAX + } + + /// The register class. + #[inline(always)] + pub const fn class(self) -> RegClass { + match (self.bits >> Self::MAX_BITS) & 0b11 { + 0 => RegClass::Int, + 1 => RegClass::Float, + 2 => RegClass::Vector, + _ => unreachable!(), + } + } + + /// Get an index into the (not necessarily contiguous) index space of + /// all physical registers. Allows one to maintain an array of data for + /// all PRegs and index it efficiently. + #[inline(always)] + pub const fn index(self) -> usize { + self.bits as usize + } + + /// Construct a PReg from the value returned from `.index()`. + #[inline(always)] + pub const fn from_index(index: usize) -> Self { + PReg { + bits: (index & (Self::NUM_INDEX - 1)) as u8, + } + } + + /// Return the "invalid PReg", which can be used to initialize + /// data structures. + #[inline(always)] + pub const fn invalid() -> Self { + PReg::new(Self::MAX, RegClass::Int) + } +} + +impl Default for PReg { + fn default() -> Self { + Self::invalid() + } +} + +impl core::fmt::Debug for PReg { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "PReg(hw = {}, class = {:?}, index = {})", + self.hw_enc(), + self.class(), + self.index() + ) + } +} + +impl core::fmt::Display for PReg { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let class = match self.class() { + RegClass::Int => "i", + RegClass::Float => "f", + RegClass::Vector => "v", + }; + write!(f, "p{}{}", self.hw_enc(), class) + } +} + +/// A type for internal bit arrays. +type Bits = u64; + +/// A physical register set. Used to represent clobbers +/// efficiently. +/// +/// The set is `Copy` and is guaranteed to have constant, and small, +/// size, as it is based on a bitset internally. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PRegSet { + bits: [Bits; Self::LEN], +} + +impl PRegSet { + /// The number of bits per element in the internal bit array. + const BITS: usize = core::mem::size_of::() * 8; + + /// Length of the internal bit array. + const LEN: usize = (PReg::NUM_INDEX + Self::BITS - 1) / Self::BITS; + + /// Create an empty set. + pub const fn empty() -> Self { + Self { + bits: [0; Self::LEN], + } + } + + /// Splits the given register index into parts to access the internal bit array. + const fn split_index(reg: PReg) -> (usize, usize) { + let index = reg.index(); + (index >> Self::BITS.ilog2(), index & (Self::BITS - 1)) + } + + /// Returns whether the given register is part of the set. + pub fn contains(&self, reg: PReg) -> bool { + let (index, bit) = Self::split_index(reg); + self.bits[index] & (1 << bit) != 0 + } + + /// Add a physical register (PReg) to the set, returning the new value. + pub const fn with(self, reg: PReg) -> Self { + let (index, bit) = Self::split_index(reg); + let mut out = self; + out.bits[index] |= 1 << bit; + out + } + + /// Add a physical register (PReg) to the set. + pub fn add(&mut self, reg: PReg) { + let (index, bit) = Self::split_index(reg); + self.bits[index] |= 1 << bit; + } + + /// Remove a physical register (PReg) from the set. + pub fn remove(&mut self, reg: PReg) { + let (index, bit) = Self::split_index(reg); + self.bits[index] &= !(1 << bit); + } + + /// Add all of the registers in one set to this one, mutating in + /// place. + pub fn union_from(&mut self, other: PRegSet) { + for i in 0..self.bits.len() { + self.bits[i] |= other.bits[i]; + } + } + + pub fn intersect_from(&mut self, other: PRegSet) { + for i in 0..self.bits.len() { + self.bits[i] &= other.bits[i]; + } + } + + pub fn invert(&self) -> PRegSet { + let mut set = self.bits; + for i in 0..self.bits.len() { + set[i] = !self.bits[i]; + } + PRegSet { bits: set } + } + + pub fn is_empty(&self, regclass: RegClass) -> bool { + self.bits[regclass as usize] == 0 + } +} + +impl core::ops::BitAnd for PRegSet { + type Output = PRegSet; + + fn bitand(self, rhs: PRegSet) -> Self::Output { + let mut out = self; + out.intersect_from(rhs); + out + } +} + +impl core::ops::BitOr for PRegSet { + type Output = PRegSet; + + fn bitor(self, rhs: PRegSet) -> Self::Output { + let mut out = self; + out.union_from(rhs); + out + } +} + +impl IntoIterator for PRegSet { + type Item = PReg; + type IntoIter = PRegSetIter; + fn into_iter(self) -> PRegSetIter { + PRegSetIter { + bits: self.bits, + cur: 0, + } + } +} + +pub struct PRegSetIter { + bits: [Bits; PRegSet::LEN], + cur: usize, +} + +impl Iterator for PRegSetIter { + type Item = PReg; + fn next(&mut self) -> Option { + loop { + let bits = self.bits.get_mut(self.cur)?; + if *bits != 0 { + let bit = bits.trailing_zeros(); + *bits &= !(1 << bit); + let index = bit as usize + self.cur * PRegSet::BITS; + return Some(PReg::from_index(index)); + } + self.cur += 1; + } + } +} + +impl From<&MachineEnv> for PRegSet { + fn from(env: &MachineEnv) -> Self { + let mut res = Self::default(); + + for class in env.preferred_regs_by_class.iter() { + for preg in class { + res.add(*preg) + } + } + + for class in env.non_preferred_regs_by_class.iter() { + for preg in class { + res.add(*preg) + } + } + + res + } +} + +impl FromIterator for PRegSet { + fn from_iter>(iter: T) -> Self { + let mut set = Self::default(); + for preg in iter { + set.add(preg); + } + set + } +} + +impl core::fmt::Display for PRegSet { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{{")?; + for preg in self.into_iter() { + write!(f, "{preg}, ")?; + } + write!(f, "}}") + } +} + +/// A virtual register. Contains a virtual register number and a +/// class. +/// +/// A virtual register ("vreg") corresponds to an SSA value. All +/// dataflow in the input program is specified via flow through a +/// virtual register; even uses of specially-constrained locations, +/// such as fixed physical registers, are done by using vregs, because +/// we need the vreg's live range in order to track the use of that +/// location. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct VReg { + bits: u32, +} + +impl VReg { + pub const MAX_BITS: usize = 21; + pub const MAX: usize = (1 << Self::MAX_BITS) - 1; + + #[inline(always)] + pub const fn new(virt_reg: usize, class: RegClass) -> Self { + debug_assert!(virt_reg <= VReg::MAX); + VReg { + bits: ((virt_reg as u32) << 2) | (class as u8 as u32), + } + } + + #[inline(always)] + pub const fn vreg(self) -> usize { + let vreg = (self.bits >> 2) as usize; + vreg + } + + #[inline(always)] + pub const fn class(self) -> RegClass { + match self.bits & 0b11 { + 0 => RegClass::Int, + 1 => RegClass::Float, + 2 => RegClass::Vector, + _ => unreachable!(), + } + } + + #[inline(always)] + pub const fn invalid() -> Self { + VReg::new(Self::MAX, RegClass::Int) + } + + #[inline(always)] + pub const fn bits(self) -> usize { + self.bits as usize + } +} + +impl From for VReg { + fn from(value: u32) -> Self { + Self { bits: value } + } +} + +impl core::fmt::Debug for VReg { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "VReg(vreg = {}, class = {:?})", + self.vreg(), + self.class() + ) + } +} + +impl core::fmt::Display for VReg { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "v{}", self.vreg()) + } +} + +/// A spillslot is a space in the stackframe used by the allocator to +/// temporarily store a value. +/// +/// The allocator is responsible for allocating indices in this space, +/// and will specify how many spillslots have been used when the +/// allocation is completed. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct SpillSlot { + bits: u32, +} + +impl SpillSlot { + /// The maximum spillslot index. + pub const MAX: usize = (1 << 24) - 1; + + /// Create a new SpillSlot. + #[inline(always)] + pub fn new(slot: usize) -> Self { + debug_assert!(slot <= Self::MAX); + SpillSlot { bits: slot as u32 } + } + + /// Get the spillslot index for this spillslot. + #[inline(always)] + pub fn index(self) -> usize { + (self.bits & 0x00ffffff) as usize + } + + /// Get the spillslot `offset` slots away. + #[inline(always)] + pub fn plus(self, offset: usize) -> Self { + SpillSlot::new(self.index() + offset) + } + + /// Get the invalid spillslot, used for initializing data structures. + #[inline(always)] + pub fn invalid() -> Self { + SpillSlot { bits: 0xffff_ffff } + } + + /// Is this the invalid spillslot? + #[inline(always)] + pub fn is_invalid(self) -> bool { + self == Self::invalid() + } + + /// Is this a valid spillslot (not `SpillSlot::invalid()`)? + #[inline(always)] + pub fn is_valid(self) -> bool { + self != Self::invalid() + } +} + +impl core::fmt::Display for SpillSlot { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "stack{}", self.index()) + } +} + +/// An `OperandConstraint` specifies where a vreg's value must be +/// placed at a particular reference to that vreg via an +/// `Operand`. The constraint may be loose -- "any register of a given +/// class", for example -- or very specific, such as "this particular +/// physical register". The allocator's result will always satisfy all +/// given constraints; however, if the input has a combination of +/// constraints that are impossible to satisfy, then allocation may +/// fail or the allocator may panic (providing impossible constraints +/// is usually a programming error in the client, rather than a +/// function of bad input). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum OperandConstraint { + /// Any location is fine (register or stack slot). + Any, + /// Operand must be in a register. Register is read-only for Uses. + Reg, + /// Operand must be in a fixed register. + FixedReg(PReg), + /// On defs only: reuse a use's register. + Reuse(usize), +} + +impl core::fmt::Display for OperandConstraint { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Any => write!(f, "any"), + Self::Reg => write!(f, "reg"), + Self::FixedReg(preg) => write!(f, "fixed({})", preg), + Self::Reuse(idx) => write!(f, "reuse({})", idx), + } + } +} + +/// The "kind" of the operand: whether it reads a vreg (Use) or writes +/// a vreg (Def). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum OperandKind { + Def = 0, + Use = 1, +} + +/// The "position" of the operand: where it has its read/write +/// effects. These are positions "in" the instruction, and "early" and +/// "late" are relative to the instruction's main effect or +/// computation. In other words, the allocator assumes that the +/// instruction (i) performs all reads and writes of "early" operands, +/// (ii) does its work, and (iii) performs all reads and writes of its +/// "late" operands. +/// +/// A "write" (def) at "early" or a "read" (use) at "late" may be +/// slightly nonsensical, given the above, if the read is necessary +/// for the computation or the write is a result of it. A way to think +/// of it is that the value (even if a result of execution) *could* +/// have been read or written at the given location without causing +/// any register-usage conflicts. In other words, these write-early or +/// use-late operands ensure that the particular allocations are valid +/// for longer than usual and that a register is not reused between +/// the use (normally complete at "Early") and the def (normally +/// starting at "Late"). See `Operand` for more. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum OperandPos { + Early = 0, + Late = 1, +} + +/// An `Operand` encodes everything about a mention of a register in +/// an instruction: virtual register number, and any constraint that +/// applies to the register at this program point. +/// +/// An Operand may be a use or def (this corresponds to `LUse` and +/// `LAllocation` in Ion). +/// +/// Generally, regalloc2 considers operands to have their effects at +/// one of two points that exist in an instruction: "Early" or +/// "Late". All operands at a given program-point are assigned +/// non-conflicting locations based on their constraints. Each operand +/// has a "kind", one of use/def/mod, corresponding to +/// read/write/read-write, respectively. +/// +/// Usually, an instruction's inputs will be "early uses" and outputs +/// will be "late defs", though there are valid use-cases for other +/// combinations too. For example, a single "instruction" seen by the +/// regalloc that lowers into multiple machine instructions and reads +/// some of its inputs after it starts to write outputs must either +/// make those input(s) "late uses" or those output(s) "early defs" so +/// that the conflict (overlap) is properly accounted for. See +/// comments on the constructors below for more. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Operand { + /// Bit-pack into 32 bits. + /// + /// constraint:7 kind:1 pos:1 class:2 vreg:21 + /// + /// where `constraint` is an `OperandConstraint`, `kind` is an + /// `OperandKind`, `pos` is an `OperandPos`, `class` is a + /// `RegClass`, and `vreg` is a vreg index. + /// + /// The constraints are encoded as follows: + /// - 1xxxxxx => FixedReg(preg) + /// - 01xxxxx => Reuse(index) + /// - 0000000 => Any + /// - 0000001 => Reg + /// - 0000010 => Stack + /// - _ => Unused for now + bits: u32, +} + +impl Operand { + /// Construct a new operand. + #[inline(always)] + pub fn new( + vreg: VReg, + constraint: OperandConstraint, + kind: OperandKind, + pos: OperandPos, + ) -> Self { + let constraint_field = match constraint { + OperandConstraint::Any => 0, + OperandConstraint::Reg => 1, + OperandConstraint::FixedReg(preg) => { + debug_assert_eq!(preg.class(), vreg.class()); + 0b1000000 | preg.hw_enc() as u32 + } + OperandConstraint::Reuse(which) => { + debug_assert!(which <= 31); + 0b0100000 | which as u32 + } + }; + let class_field = vreg.class() as u8 as u32; + let pos_field = pos as u8 as u32; + let kind_field = kind as u8 as u32; + Operand { + bits: vreg.vreg() as u32 + | (class_field << 21) + | (pos_field << 23) + | (kind_field << 24) + | (constraint_field << 25), + } + } + + /// Create an `Operand` that designates a use of a VReg that must + /// be in a register, and that is used at the "before" point, + /// i.e., can be overwritten by a result. + #[inline(always)] + pub fn reg_use(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Reg, + OperandKind::Use, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a use of a VReg that must + /// be in a register, and that is used up until the "after" point, + /// i.e., must not conflict with any results. + #[inline(always)] + pub fn reg_use_at_end(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Reg, + OperandKind::Use, + OperandPos::Late, + ) + } + + /// Create an `Operand` that designates a definition of a VReg + /// that must be in a register, and that occurs at the "after" + /// point, i.e. may reuse a register that carried a use into this + /// instruction. + #[inline(always)] + pub fn reg_def(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Reg, + OperandKind::Def, + OperandPos::Late, + ) + } + + /// Create an `Operand` that designates a definition of a VReg + /// that must be in a register, and that occurs early at the + /// "before" point, i.e., must not conflict with any input to the + /// instruction. + /// + /// Note that the register allocator will ensure that such an + /// early-def operand is live throughout the instruction, i.e., also + /// at the after-point. Hence it will also avoid conflicts with all + /// outputs to the instruction. As such, early defs are appropriate + /// for use as "temporary registers" that an instruction can use + /// throughout its execution separately from the inputs and outputs. + #[inline(always)] + pub fn reg_def_at_start(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Reg, + OperandKind::Def, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a def (and use) of a + /// temporary *within* the instruction. This register is assumed + /// to be written by the instruction, and will not conflict with + /// any input or output, but should not be used after the + /// instruction completes. + /// + /// Note that within a single instruction, the dedicated scratch + /// register (as specified in the `MachineEnv`) is also always + /// available for use. The register allocator may use the register + /// *between* instructions in order to implement certain sequences + /// of moves, but will never hold a value live in the scratch + /// register across an instruction. + #[inline(always)] + pub fn reg_temp(vreg: VReg) -> Self { + // For now a temp is equivalent to a def-at-start operand, + // which gives the desired semantics but does not enforce the + // "not reused later" constraint. + Operand::new( + vreg, + OperandConstraint::Reg, + OperandKind::Def, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a def of a vreg that must + /// reuse the register assigned to an input to the + /// instruction. The input is identified by `idx` (is the `idx`th + /// `Operand` for the instruction) and must be constraint to a + /// register, i.e., be the result of `Operand::reg_use(vreg)`. + #[inline(always)] + pub fn reg_reuse_def(vreg: VReg, idx: usize) -> Self { + Operand::new( + vreg, + OperandConstraint::Reuse(idx), + OperandKind::Def, + OperandPos::Late, + ) + } + + /// Create an `Operand` that designates a use of a vreg and + /// ensures that it is placed in the given, fixed PReg at the + /// use. It is guaranteed that the `Allocation` resulting for this + /// operand will be `preg`. + #[inline(always)] + pub fn reg_fixed_use(vreg: VReg, preg: PReg) -> Self { + Operand::new( + vreg, + OperandConstraint::FixedReg(preg), + OperandKind::Use, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a def of a vreg and + /// ensures that it is placed in the given, fixed PReg at the + /// def. It is guaranteed that the `Allocation` resulting for this + /// operand will be `preg`. + #[inline(always)] + pub fn reg_fixed_def(vreg: VReg, preg: PReg) -> Self { + Operand::new( + vreg, + OperandConstraint::FixedReg(preg), + OperandKind::Def, + OperandPos::Late, + ) + } + + /// Same as `reg_fixed_use` but at `OperandPos::Late`. + #[inline(always)] + pub fn reg_fixed_use_at_end(vreg: VReg, preg: PReg) -> Self { + Operand::new( + vreg, + OperandConstraint::FixedReg(preg), + OperandKind::Use, + OperandPos::Late, + ) + } + + /// Same as `reg_fixed_def` but at `OperandPos::Early`. + #[inline(always)] + pub fn reg_fixed_def_at_start(vreg: VReg, preg: PReg) -> Self { + Operand::new( + vreg, + OperandConstraint::FixedReg(preg), + OperandKind::Def, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a use of a vreg and places + /// no constraints on its location (i.e., it can be allocated into + /// either a register or on the stack). + #[inline(always)] + pub fn any_use(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Any, + OperandKind::Use, + OperandPos::Early, + ) + } + + /// Create an `Operand` that designates a def of a vreg and places + /// no constraints on its location (i.e., it can be allocated into + /// either a register or on the stack). + #[inline(always)] + pub fn any_def(vreg: VReg) -> Self { + Operand::new( + vreg, + OperandConstraint::Any, + OperandKind::Def, + OperandPos::Late, + ) + } + + /// Create an `Operand` that always results in an assignment to the + /// given fixed `preg`, *without* tracking liveranges in that + /// `preg`. Must only be used for non-allocatable registers. + #[inline(always)] + pub fn fixed_nonallocatable(preg: PReg) -> Self { + Operand::new( + VReg::new(VReg::MAX, preg.class()), + OperandConstraint::FixedReg(preg), + OperandKind::Use, + OperandPos::Early, + ) + } + + /// Get the virtual register designated by an operand. Every + /// operand must name some virtual register, even if it constrains + /// the operand to a fixed physical register as well; the vregs + /// are used to track dataflow. + #[inline(always)] + pub fn vreg(self) -> VReg { + let vreg_idx = ((self.bits as usize) & VReg::MAX) as usize; + VReg::new(vreg_idx, self.class()) + } + + /// Get the register class used by this operand. + #[inline(always)] + pub fn class(self) -> RegClass { + let class_field = (self.bits >> 21) & 3; + match class_field { + 0 => RegClass::Int, + 1 => RegClass::Float, + 2 => RegClass::Vector, + _ => unreachable!(), + } + } + + /// Get the "kind" of this operand: a definition (write) or a use + /// (read). + #[inline(always)] + pub fn kind(self) -> OperandKind { + let kind_field = (self.bits >> 24) & 1; + match kind_field { + 0 => OperandKind::Def, + 1 => OperandKind::Use, + _ => unreachable!(), + } + } + + /// Get the "position" of this operand, i.e., where its read + /// and/or write occurs: either before the instruction executes, + /// or after it does. Ordinarily, uses occur at "before" and defs + /// at "after", though there are cases where this is not true. + #[inline(always)] + pub fn pos(self) -> OperandPos { + let pos_field = (self.bits >> 23) & 1; + match pos_field { + 0 => OperandPos::Early, + 1 => OperandPos::Late, + _ => unreachable!(), + } + } + + /// Get the "constraint" of this operand, i.e., what requirements + /// its allocation must fulfill. + #[inline(always)] + pub fn constraint(self) -> OperandConstraint { + let constraint_field = ((self.bits >> 25) as usize) & 127; + if constraint_field & 0b1000000 != 0 { + OperandConstraint::FixedReg(PReg::new(constraint_field & 0b0111111, self.class())) + } else if constraint_field & 0b0100000 != 0 { + OperandConstraint::Reuse(constraint_field & 0b0011111) + } else { + match constraint_field { + 0 => OperandConstraint::Any, + 1 => OperandConstraint::Reg, + _ => unreachable!(), + } + } + } + + /// If this operand is for a fixed non-allocatable register (see + /// [`Operand::fixed`]), then returns the physical register that it will + /// be assigned to. + #[inline(always)] + pub fn as_fixed_nonallocatable(self) -> Option { + match self.constraint() { + OperandConstraint::FixedReg(preg) if self.vreg().vreg() == VReg::MAX => Some(preg), + _ => None, + } + } + + /// Get the raw 32-bit encoding of this operand's fields. + #[inline(always)] + pub fn bits(self) -> u32 { + self.bits + } + + /// Construct an `Operand` from the raw 32-bit encoding returned + /// from `bits()`. + #[inline(always)] + pub fn from_bits(bits: u32) -> Self { + debug_assert!(bits >> 29 <= 4); + Operand { bits } + } +} + +impl core::fmt::Debug for Operand { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Display::fmt(self, f) + } +} + +impl core::fmt::Display for Operand { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + if let Some(preg) = self.as_fixed_nonallocatable() { + return write!(f, "Fixed: {preg}"); + } + match (self.kind(), self.pos()) { + (OperandKind::Def, OperandPos::Late) | (OperandKind::Use, OperandPos::Early) => { + write!(f, "{:?}", self.kind())?; + } + _ => { + write!(f, "{:?}@{:?}", self.kind(), self.pos())?; + } + } + write!( + f, + ": {}{} {}", + self.vreg(), + match self.class() { + RegClass::Int => "i", + RegClass::Float => "f", + RegClass::Vector => "v", + }, + self.constraint() + ) + } +} + +/// An Allocation represents the end result of regalloc for an +/// Operand. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Allocation { + /// Bit-pack in 32 bits. + /// + /// kind:3 unused:1 index:28 + bits: u32, +} + +impl core::fmt::Debug for Allocation { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Display::fmt(self, f) + } +} + +impl core::fmt::Display for Allocation { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self.kind() { + AllocationKind::None => write!(f, "none"), + AllocationKind::Reg => write!(f, "{}", self.as_reg().unwrap()), + AllocationKind::Stack => write!(f, "{}", self.as_stack().unwrap()), + } + } +} + +impl Allocation { + /// Construct a new Allocation. + #[inline(always)] + pub(crate) fn new(kind: AllocationKind, index: usize) -> Self { + debug_assert!(index < (1 << 28)); + Self { + bits: ((kind as u8 as u32) << 29) | (index as u32), + } + } + + /// Get the "none" allocation, which is distinct from the other + /// possibilities and is used to initialize data structures. + #[inline(always)] + pub fn none() -> Allocation { + Allocation::new(AllocationKind::None, 0) + } + + /// Create an allocation into a register. + #[inline(always)] + pub fn reg(preg: PReg) -> Allocation { + Allocation::new(AllocationKind::Reg, preg.index()) + } + + /// Create an allocation into a spillslot. + #[inline(always)] + pub fn stack(slot: SpillSlot) -> Allocation { + Allocation::new(AllocationKind::Stack, slot.bits as usize) + } + + /// Get the allocation's "kind": none, register, or stack (spillslot). + #[inline(always)] + pub fn kind(self) -> AllocationKind { + match (self.bits >> 29) & 7 { + 0 => AllocationKind::None, + 1 => AllocationKind::Reg, + 2 => AllocationKind::Stack, + _ => unreachable!(), + } + } + + /// Is the allocation "none"? + #[inline(always)] + pub fn is_none(self) -> bool { + self.kind() == AllocationKind::None + } + + /// Is the allocation not "none"? + #[inline(always)] + pub fn is_some(self) -> bool { + self.kind() != AllocationKind::None + } + + /// Is the allocation a register? + #[inline(always)] + pub fn is_reg(self) -> bool { + self.kind() == AllocationKind::Reg + } + + /// Is the allocation on the stack (a spillslot)? + #[inline(always)] + pub fn is_stack(self) -> bool { + self.kind() == AllocationKind::Stack + } + + /// Get the index of the spillslot or register. If register, this + /// is an index that can be used by `PReg::from_index()`. + #[inline(always)] + pub fn index(self) -> usize { + (self.bits & ((1 << 28) - 1)) as usize + } + + /// Get the allocation as a physical register, if any. + #[inline(always)] + pub fn as_reg(self) -> Option { + if self.kind() == AllocationKind::Reg { + Some(PReg::from_index(self.index())) + } else { + None + } + } + + /// Get the allocation as a spillslot, if any. + #[inline(always)] + pub fn as_stack(self) -> Option { + if self.kind() == AllocationKind::Stack { + Some(SpillSlot { + bits: self.index() as u32, + }) + } else { + None + } + } + + /// Get the raw bits for the packed encoding of this allocation. + #[inline(always)] + pub fn bits(self) -> u32 { + self.bits + } + + /// Construct an allocation from its packed encoding. + #[inline(always)] + pub fn from_bits(bits: u32) -> Self { + debug_assert!(bits >> 29 >= 5); + Self { bits } + } +} + +/// An allocation is one of two "kinds" (or "none"): register or +/// spillslot/stack. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum AllocationKind { + None = 0, + Reg = 1, + Stack = 2, +} + +/// A trait defined by the regalloc client to provide access to its +/// machine-instruction / CFG representation. +/// +/// (This trait's design is inspired by, and derives heavily from, the +/// trait of the same name in regalloc.rs.) +pub trait Function { + // ------------- + // CFG traversal + // ------------- + + /// How many instructions are there? + fn num_insts(&self) -> usize; + + /// How many blocks are there? + fn num_blocks(&self) -> usize; + + /// Get the index of the entry block. + fn entry_block(&self) -> Block; + + /// Provide the range of instruction indices contained in each block. + fn block_insns(&self, block: Block) -> InstRange; + + /// Get CFG successors for a given block. + fn block_succs(&self, block: Block) -> &[Block]; + + /// Get the CFG predecessors for a given block. + fn block_preds(&self, block: Block) -> &[Block]; + + /// Get the block parameters for a given block. + fn block_params(&self, block: Block) -> &[VReg]; + + /// Determine whether an instruction is a return instruction. + fn is_ret(&self, insn: Inst) -> bool; + + /// Determine whether an instruction is the end-of-block + /// branch. + fn is_branch(&self, insn: Inst) -> bool; + + /// If `insn` is a branch at the end of `block`, returns the + /// outgoing blockparam arguments for the given successor. The + /// number of arguments must match the number incoming blockparams + /// for each respective successor block. + fn branch_blockparams(&self, block: Block, insn: Inst, succ_idx: usize) -> &[VReg]; + + // -------------------------- + // Instruction register slots + // -------------------------- + + /// Get the Operands for an instruction. + fn inst_operands(&self, insn: Inst) -> &[Operand]; + + /// Get the clobbers for an instruction; these are the registers + /// that, after the instruction has executed, hold values that are + /// arbitrary, separately from the usual outputs to the + /// instruction. It is invalid to read a register that has been + /// clobbered; the register allocator is free to assume that + /// clobbered registers are filled with garbage and available for + /// reuse. It will avoid storing any value in a clobbered register + /// that must be live across the instruction. + /// + /// Another way of seeing this is that a clobber is equivalent to + /// a "late def" of a fresh vreg that is not used anywhere else + /// in the program, with a fixed-register constraint that places + /// it in a given PReg chosen by the client prior to regalloc. + /// + /// Every register written by an instruction must either + /// correspond to (be assigned to) an Operand of kind `Def`, or + /// else must be a "clobber". + /// + /// This can be used to, for example, describe ABI-specified + /// registers that are not preserved by a call instruction, or + /// fixed physical registers written by an instruction but not + /// used as a vreg output, or fixed physical registers used as + /// temps within an instruction out of necessity. + /// + /// Note that it is legal for a register to be both a clobber and + /// an actual def (via pinned vreg or via operand constrained to + /// the reg). This is for convenience: e.g., a call instruction + /// might have a constant clobber set determined by the ABI, but + /// some of those clobbered registers are sometimes return + /// value(s). + fn inst_clobbers(&self, insn: Inst) -> PRegSet; + + /// Get the number of `VReg` in use in this function. + fn num_vregs(&self) -> usize; + + /// Get the VRegs for which we should generate value-location + /// metadata for debugging purposes. This can be used to generate + /// e.g. DWARF with valid prgram-point ranges for each value + /// expression in a way that is more efficient than a post-hoc + /// analysis of the allocator's output. + /// + /// Each tuple is (vreg, inclusive_start, exclusive_end, + /// label). In the `Output` there will be (label, inclusive_start, + /// exclusive_end, alloc)` tuples. The ranges may not exactly + /// match -- specifically, the returned metadata may cover only a + /// subset of the requested ranges -- if the value is not live for + /// the entire requested ranges. + /// + /// The instruction indices imply a program point just *before* + /// the instruction. + /// + /// Precondition: we require this slice to be sorted by vreg. + fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] { + &[] + } + + // -------------- + // Spills/reloads + // -------------- + + /// How many logical spill slots does the given regclass require? E.g., on + /// a 64-bit machine, spill slots may nominally be 64-bit words, but a + /// 128-bit vector value will require two slots. The regalloc will always + /// align on this size. + /// + /// (This trait method's design and doc text derives from + /// regalloc.rs' trait of the same name.) + fn spillslot_size(&self, regclass: RegClass) -> usize; + + /// When providing a spillslot number for a multi-slot spillslot, + /// do we provide the first or the last? This is usually related + /// to which direction the stack grows and different clients may + /// have different preferences. + fn multi_spillslot_named_by_last_slot(&self) -> bool { + false + } + + // ----------- + // Misc config + // ----------- + + /// Allow a single instruction to define a vreg multiple times. If + /// allowed, the semantics are as if the definition occurs only + /// once, and all defs will get the same alloc. This flexibility is + /// meant to allow the embedder to more easily aggregate operands + /// together in macro/pseudoinstructions, or e.g. add additional + /// clobbered vregs without taking care to deduplicate. This may be + /// particularly useful when referring to physical registers via + /// pinned vregs. It is optional functionality because a strict mode + /// (at most one def per vreg) is also useful for finding bugs in + /// other applications. + fn allow_multiple_vreg_defs(&self) -> bool { + false + } +} + +/// A position before or after an instruction at which we can make an +/// edit. +/// +/// Note that this differs from `OperandPos` in that the former +/// describes specifically a constraint on an operand, while this +/// describes a program point. `OperandPos` could grow more options in +/// the future, for example if we decide that an "early write" or +/// "late read" phase makes sense, while `InstPosition` will always +/// describe these two insertion points. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum InstPosition { + Before = 0, + After = 1, +} + +/// A program point: a single point before or after a given instruction. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ProgPoint { + bits: u32, +} + +impl core::fmt::Debug for ProgPoint { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "progpoint{}{}", + self.inst().index(), + match self.pos() { + InstPosition::Before => "-pre", + InstPosition::After => "-post", + } + ) + } +} + +impl ProgPoint { + /// Create a new ProgPoint before or after the given instruction. + #[inline(always)] + pub fn new(inst: Inst, pos: InstPosition) -> Self { + let bits = ((inst.0 as u32) << 1) | (pos as u8 as u32); + Self { bits } + } + + /// Create a new ProgPoint before the given instruction. + #[inline(always)] + pub fn before(inst: Inst) -> Self { + Self::new(inst, InstPosition::Before) + } + + /// Create a new ProgPoint after the given instruction. + #[inline(always)] + pub fn after(inst: Inst) -> Self { + Self::new(inst, InstPosition::After) + } + + /// Get the instruction that this ProgPoint is before or after. + #[inline(always)] + pub fn inst(self) -> Inst { + // Cast to i32 to do an arithmetic right-shift, which will + // preserve an `Inst::invalid()` (which is -1, or all-ones). + Inst::new(((self.bits as i32) >> 1) as usize) + } + + /// Get the "position" (Before or After) relative to the + /// instruction. + #[inline(always)] + pub fn pos(self) -> InstPosition { + match self.bits & 1 { + 0 => InstPosition::Before, + 1 => InstPosition::After, + _ => unreachable!(), + } + } + + /// Get the "next" program point: for After, this is the Before of + /// the next instruction, while for Before, this is After of the + /// same instruction. + #[inline(always)] + pub fn next(self) -> ProgPoint { + Self { + bits: self.bits + 1, + } + } + + /// Get the "previous" program point, the inverse of `.next()` + /// above. + #[inline(always)] + pub fn prev(self) -> ProgPoint { + Self { + bits: self.bits - 1, + } + } + + /// Convert to a raw encoding in 32 bits. + #[inline(always)] + pub fn to_index(self) -> u32 { + self.bits + } + + /// Construct from the raw 32-bit encoding. + #[inline(always)] + pub fn from_index(index: u32) -> Self { + Self { bits: index } + } + + #[inline(always)] + pub fn invalid() -> Self { + Self::before(Inst::new(usize::MAX)) + } +} + +/// An instruction to insert into the program to perform some data movement. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum Edit { + /// Move one allocation to another. Each allocation may be a + /// register or a stack slot (spillslot). However, stack-to-stack + /// moves will never be generated. + /// + /// `Move` edits will be generated even if src and dst allocation + /// are the same if the vreg changes; this allows proper metadata + /// tracking even when moves are elided. + Move { from: Allocation, to: Allocation }, +} + +/// Wrapper around either an original instruction or an inserted edit. +#[derive(Clone, Debug)] +pub enum InstOrEdit<'a> { + Inst(Inst), + Edit(&'a Edit), +} + +/// Iterator over the instructions and edits in a block. +pub struct OutputIter<'a> { + /// List of edits starting at the first for the current block. + edits: &'a [(ProgPoint, Edit)], + + /// Remaining instructions in the current block. + inst_range: InstRange, +} + +impl<'a> Iterator for OutputIter<'a> { + type Item = InstOrEdit<'a>; + + fn next(&mut self) -> Option> { + // There can't be any edits after the last instruction in a block, so + // we don't need to worry about that case. + if self.inst_range.len() == 0 { + return None; + } + + // Return any edits that happen before the next instruction first. + let next_inst = self.inst_range.first(); + if let Some((edit, remaining_edits)) = self.edits.split_first() { + if edit.0 <= ProgPoint::before(next_inst) { + self.edits = remaining_edits; + return Some(InstOrEdit::Edit(&edit.1)); + } + } + + self.inst_range = self.inst_range.rest(); + Some(InstOrEdit::Inst(next_inst)) + } +} + +/// A machine environment tells the register allocator which registers +/// are available to allocate and what register may be used as a +/// scratch register for each class, and some other miscellaneous info +/// as well. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MachineEnv { + /// Preferred physical registers for each class. These are the + /// registers that will be allocated first, if free. + /// + /// If an explicit scratch register is provided in `scratch_by_class` then + /// it must not appear in this list. + pub preferred_regs_by_class: [Vec; 3], + + /// Non-preferred physical registers for each class. These are the + /// registers that will be allocated if a preferred register is + /// not available; using one of these is considered suboptimal, + /// but still better than spilling. + /// + /// If an explicit scratch register is provided in `scratch_by_class` then + /// it must not appear in this list. + pub non_preferred_regs_by_class: [Vec; 3], + + /// Optional dedicated scratch register per class. This is needed to perform + /// moves between registers when cyclic move patterns occur. The + /// register should not be placed in either the preferred or + /// non-preferred list (i.e., it is not otherwise allocatable). + /// + /// Note that the register allocator will freely use this register + /// between instructions, but *within* the machine code generated + /// by a single (regalloc-level) instruction, the client is free + /// to use the scratch register. E.g., if one "instruction" causes + /// the emission of two machine-code instructions, this lowering + /// can use the scratch register between them. + /// + /// If a scratch register is not provided then the register allocator will + /// automatically allocate one as needed, spilling a value to the stack if + /// necessary. + pub scratch_by_class: [Option; 3], + + /// Some `PReg`s can be designated as locations on the stack rather than + /// actual registers. These can be used to tell the register allocator about + /// pre-defined stack slots used for function arguments and return values. + /// + /// `PReg`s in this list cannot be used as an allocatable or scratch + /// register. + pub fixed_stack_slots: Vec, +} + +/// The output of the register allocator. +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Output { + /// How many spillslots are needed in the frame? + pub num_spillslots: usize, + + /// Edits (insertions or removals). Guaranteed to be sorted by + /// program point. + pub edits: Vec<(ProgPoint, Edit)>, + + /// Allocations for each operand. Mapping from instruction to + /// allocations provided by `inst_alloc_offsets` below. + pub allocs: Vec, + + /// Allocation offset in `allocs` for each instruction. + pub inst_alloc_offsets: Vec, + + /// Debug info: a labeled value (as applied to vregs by + /// `Function::debug_value_labels()` on the input side) is located + /// in the given allocation from the first program point + /// (inclusive) to the second (exclusive). Guaranteed to be sorted + /// by label and program point, and the ranges are guaranteed to + /// be disjoint. + pub debug_locations: Vec<(u32, ProgPoint, ProgPoint, Allocation)>, + + /// Internal stats from the allocator. + pub stats: ion::Stats, +} + +impl Output { + /// Get the allocations assigned to a given instruction. + pub fn inst_allocs(&self, inst: Inst) -> &[Allocation] { + let start = self.inst_alloc_offsets[inst.index()] as usize; + let end = if inst.index() + 1 == self.inst_alloc_offsets.len() { + self.allocs.len() + } else { + self.inst_alloc_offsets[inst.index() + 1] as usize + }; + &self.allocs[start..end] + } + + /// Returns an iterator over the instructions and edits in a block, in + /// order. + pub fn block_insts_and_edits(&self, func: &impl Function, block: Block) -> OutputIter<'_> { + let inst_range = func.block_insns(block); + + let edit_idx = self + .edits + .binary_search_by(|&(pos, _)| { + // This predicate effectively searches for a point *just* before + // the first ProgPoint. This never returns Ordering::Equal, but + // binary_search_by returns the index of where it would have + // been inserted in Err. + if pos < ProgPoint::before(inst_range.first()) { + core::cmp::Ordering::Less + } else { + core::cmp::Ordering::Greater + } + }) + .unwrap_err(); + + let edits = &self.edits[edit_idx..]; + OutputIter { inst_range, edits } + } +} + +/// An error that prevents allocation. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum RegAllocError { + /// Critical edge is not split between given blocks. + CritEdge(Block, Block), + /// Invalid SSA for given vreg at given inst: multiple defs or + /// illegal use. `inst` may be `Inst::invalid()` if this concerns + /// a block param. + SSA(VReg, Inst), + /// Invalid basic block: does not end in branch/ret, or contains a + /// branch/ret in the middle. + BB(Block), + /// Invalid branch: operand count does not match sum of block + /// params of successor blocks. + Branch(Inst), + /// A VReg is live-in on entry; this is not allowed. + EntryLivein, + /// A branch has non-blockparam arg(s) and at least one of the + /// successor blocks has more than one predecessor, forcing + /// edge-moves before this branch. This is disallowed because it + /// places a use after the edge moves occur; insert an edge block + /// to avoid the situation. + DisallowedBranchArg(Inst), + /// Too many pinned VRegs + Reg-constrained Operands are live at + /// once, making allocation impossible. + TooManyLiveRegs, +} + +impl core::fmt::Display for RegAllocError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for RegAllocError {} + +/// Run the allocator. +pub fn run( + func: &F, + env: &MachineEnv, + options: &RegallocOptions, +) -> Result { + match options.algorithm { + Algorithm::Ion => { + let mut ctx = Ctx::default(); + run_with_ctx(func, env, options, &mut ctx)?; + Ok(ctx.output) + } + Algorithm::Fastalloc => { + fastalloc::run(func, env, options.verbose_log, options.validate_ssa) + } + } +} + +/// Run the allocator with reusable context. +/// +/// Return value points to `ctx.output` that can be alternatively `std::mem::take`n. +pub fn run_with_ctx<'a, F: Function>( + func: &F, + env: &MachineEnv, + options: &RegallocOptions, + ctx: &'a mut Ctx, +) -> Result<&'a Output, RegAllocError> { + match options.algorithm { + Algorithm::Ion => ion::run(func, env, ctx, options.verbose_log, options.validate_ssa)?, + Algorithm::Fastalloc => { + ctx.output = fastalloc::run(func, env, options.verbose_log, options.validate_ssa)? + } + } + Ok(&ctx.output) +} + +#[derive(Clone, Copy, Debug, Default)] +pub enum Algorithm { + #[default] + Ion, + Fastalloc, +} + +/// Options for allocation. +#[derive(Clone, Copy, Debug, Default)] +pub struct RegallocOptions { + /// Add extra verbosity to debug logs. + pub verbose_log: bool, + + /// Run the SSA validator before allocating registers. + pub validate_ssa: bool, + + /// The register allocation algorithm to be used. + pub algorithm: Algorithm, +} + +pub(crate) trait VecExt { + /// Fills `self` with `value` up to `len` and return the mutable slice to the values. + fn repopulate(&mut self, len: usize, value: T) -> &mut [T] + where + T: Clone; + /// Clears the `self` and returns a mutable reference to it. + fn cleared(&mut self) -> &mut Self; + /// Makes sure `self` is empty and has at least `cap` capacity. + fn preallocate(&mut self, cap: usize) -> &mut Self; +} + +impl VecExt for Vec { + fn repopulate(&mut self, len: usize, value: T) -> &mut [T] + where + T: Clone, + { + self.clear(); + self.resize(len, value); + self + } + + fn cleared(&mut self) -> &mut Self { + self.clear(); + self + } + + fn preallocate(&mut self, cap: usize) -> &mut Self { + self.clear(); + self.reserve(cap); + self + } +} + +#[derive(Debug, Clone, Default)] +pub(crate) struct Bump(Rc); + +impl Bump { + pub(crate) fn get_mut(&mut self) -> Option<&mut bumpalo::Bump> { + Rc::get_mut(&mut self.0) + } +} + +// Simply delegating because `Rc` does not implement `Allocator`. +unsafe impl allocator_api2::alloc::Allocator for Bump { + fn allocate( + &self, + layout: core::alloc::Layout, + ) -> Result, allocator_api2::alloc::AllocError> { + self.0.deref().allocate(layout) + } + + unsafe fn deallocate(&self, ptr: core::ptr::NonNull, layout: core::alloc::Layout) { + self.0.deref().deallocate(ptr, layout); + } + + fn allocate_zeroed( + &self, + layout: core::alloc::Layout, + ) -> Result, allocator_api2::alloc::AllocError> { + self.0.deref().allocate_zeroed(layout) + } + + unsafe fn grow( + &self, + ptr: core::ptr::NonNull, + old_layout: core::alloc::Layout, + new_layout: core::alloc::Layout, + ) -> Result, allocator_api2::alloc::AllocError> { + self.0.deref().grow(ptr, old_layout, new_layout) + } + + unsafe fn grow_zeroed( + &self, + ptr: core::ptr::NonNull, + old_layout: core::alloc::Layout, + new_layout: core::alloc::Layout, + ) -> Result, allocator_api2::alloc::AllocError> { + self.0.deref().grow_zeroed(ptr, old_layout, new_layout) + } + + unsafe fn shrink( + &self, + ptr: core::ptr::NonNull, + old_layout: core::alloc::Layout, + new_layout: core::alloc::Layout, + ) -> Result, allocator_api2::alloc::AllocError> { + self.0.deref().shrink(ptr, old_layout, new_layout) + } +} diff --git a/deps/crates/vendor/regalloc2/src/moves.rs b/deps/crates/vendor/regalloc2/src/moves.rs new file mode 100644 index 00000000000000..9301149a8cccba --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/moves.rs @@ -0,0 +1,455 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +use crate::{ion::data_structures::u64_key, Allocation, PReg}; +use core::fmt::Debug; +use smallvec::{smallvec, SmallVec}; + +/// A list of moves to be performed in sequence, with auxiliary data +/// attached to each. +pub type MoveVec = SmallVec<[(Allocation, Allocation, T); 16]>; + +/// A list of moves to be performance in sequence, like a +/// `MoveVec`, except that an unchosen scratch space may occur as +/// well, represented by `Allocation::none()`. +#[derive(Clone, Debug)] +pub enum MoveVecWithScratch { + /// No scratch was actually used. + NoScratch(MoveVec), + /// A scratch space was used. + Scratch(MoveVec), +} + +/// A `ParallelMoves` represents a list of alloc-to-alloc moves that +/// must happen in parallel -- i.e., all reads of sources semantically +/// happen before all writes of destinations, and destinations are +/// allowed to overwrite sources. It can compute a list of sequential +/// moves that will produce the equivalent data movement, possibly +/// using a scratch register if one is necessary. +pub struct ParallelMoves { + parallel_moves: MoveVec, +} + +impl ParallelMoves { + pub fn new() -> Self { + Self { + parallel_moves: smallvec![], + } + } + + pub fn add(&mut self, from: Allocation, to: Allocation, t: T) { + self.parallel_moves.push((from, to, t)); + } + + fn sources_overlap_dests(&self) -> bool { + // Assumes `parallel_moves` has already been sorted by `dst` + // in `resolve()` below. The O(n log n) cost of this loop is no + // worse than the sort we already did. + for &(src, _, _) in &self.parallel_moves { + if self + .parallel_moves + .binary_search_by_key(&src, |&(_, dst, _)| dst) + .is_ok() + { + return true; + } + } + false + } + + /// Resolve the parallel-moves problem to a sequence of separate + /// moves, such that the combined effect of the sequential moves + /// is as-if all of the moves added to this `ParallelMoves` + /// resolver happened in parallel. + /// + /// Sometimes, if there is a cycle, a scratch register is + /// necessary to allow the moves to occur sequentially. In this + /// case, `Allocation::none()` is returned to represent the + /// scratch register. The caller may choose to always hold a + /// separate scratch register unused to allow this to be trivially + /// rewritten; or may dynamically search for or create a free + /// register as needed, if none are available. + pub fn resolve(mut self) -> MoveVecWithScratch { + // Easy case: zero or one move. Just return our vec. + if self.parallel_moves.len() <= 1 { + return MoveVecWithScratch::NoScratch(self.parallel_moves); + } + + // Sort moves so that we can efficiently test for presence. + // For that purpose it doesn't matter whether we sort by + // source or destination, but later we'll want them sorted + // by destination. + self.parallel_moves + .sort_by_key(|&(src, dst, _)| u64_key(dst.bits(), src.bits())); + + // Duplicate moves cannot change the semantics of this + // parallel move set, so remove them. This is cheap since we + // just sorted the list. + self.parallel_moves.dedup(); + + // General case: some moves overwrite dests that other moves + // read as sources. We'll use a general algorithm. + // + // *Important property*: because we expect that each register + // has only one writer (otherwise the effect of the parallel + // move is undefined), each move can only block one other move + // (with its one source corresponding to the one writer of + // that source). Thus, we *can only have simple cycles* (those + // that are a ring of nodes, i.e., with only one path from a + // node back to itself); there are no SCCs that are more + // complex than that. We leverage this fact below to avoid + // having to do a full Tarjan SCC DFS (with lowest-index + // computation, etc.): instead, as soon as we find a cycle, we + // know we have the full cycle and we can do a cyclic move + // sequence and continue. + + // Check that each destination has only one writer. + if cfg!(debug_assertions) { + let mut last_dst = None; + for &(_, dst, _) in &self.parallel_moves { + if last_dst.is_some() { + debug_assert!(last_dst.unwrap() != dst); + } + last_dst = Some(dst); + } + } + + // Moving an allocation into itself is technically a cycle but + // should have no effect, as long as there are no other writes + // into that destination. + self.parallel_moves.retain(|&mut (src, dst, _)| src != dst); + + // Do any dests overlap sources? If not, we can also just + // return the list. + if !self.sources_overlap_dests() { + return MoveVecWithScratch::NoScratch(self.parallel_moves); + } + + // Construct a mapping from move indices to moves they must + // come before. Any given move must come before a move that + // overwrites its destination; we have moves sorted by dest + // above so we can efficiently find such a move, if any. + const NONE: usize = usize::MAX; + let must_come_before: SmallVec<[usize; 16]> = self + .parallel_moves + .iter() + .map(|&(src, _, _)| { + self.parallel_moves + .binary_search_by_key(&src, |&(_, dst, _)| dst) + .unwrap_or(NONE) + }) + .collect(); + + // Do a simple stack-based DFS and emit moves in postorder, + // then reverse at the end for RPO. Unlike Tarjan's SCC + // algorithm, we can emit a cycle as soon as we find one, as + // noted above. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum State { + /// Not on stack, not visited + ToDo, + /// On stack, not yet visited + Pending, + /// Visited + Done, + } + let mut ret: MoveVec = smallvec![]; + let mut stack: SmallVec<[usize; 16]> = smallvec![]; + let mut state: SmallVec<[State; 16]> = smallvec![State::ToDo; self.parallel_moves.len()]; + let mut scratch_used = false; + + while let Some(next) = state.iter().position(|&state| state == State::ToDo) { + stack.push(next); + state[next] = State::Pending; + + while let Some(&top) = stack.last() { + debug_assert_eq!(state[top], State::Pending); + let next = must_come_before[top]; + if next == NONE || state[next] == State::Done { + ret.push(self.parallel_moves[top]); + state[top] = State::Done; + stack.pop(); + while let Some(top) = stack.pop() { + ret.push(self.parallel_moves[top]); + state[top] = State::Done; + } + } else if state[next] == State::ToDo { + stack.push(next); + state[next] = State::Pending; + } else { + // Found a cycle -- emit a cyclic-move sequence + // for the cycle on the top of stack, then normal + // moves below it. Recall that these moves will be + // reversed in sequence, so from the original + // parallel move set + // + // { B := A, C := B, A := B } + // + // we will generate something like: + // + // A := scratch + // B := A + // C := B + // scratch := C + // + // which will become: + // + // scratch := C + // C := B + // B := A + // A := scratch + debug_assert_ne!(top, next); + state[top] = State::Done; + stack.pop(); + + let (scratch_src, dst, dst_t) = self.parallel_moves[top]; + scratch_used = true; + + ret.push((Allocation::none(), dst, dst_t)); + while let Some(move_idx) = stack.pop() { + state[move_idx] = State::Done; + ret.push(self.parallel_moves[move_idx]); + + if move_idx == next { + break; + } + } + ret.push((scratch_src, Allocation::none(), T::default())); + } + } + } + + ret.reverse(); + + if scratch_used { + MoveVecWithScratch::Scratch(ret) + } else { + MoveVecWithScratch::NoScratch(ret) + } + } +} + +impl MoveVecWithScratch { + /// Fills in the scratch space, if needed, with the given + /// register/allocation and returns a final list of moves. The + /// scratch register must not occur anywhere in the parallel-move + /// problem given to the resolver that produced this + /// `MoveVecWithScratch`. + pub fn with_scratch(self, scratch: Allocation) -> MoveVec { + match self { + MoveVecWithScratch::NoScratch(moves) => moves, + MoveVecWithScratch::Scratch(mut moves) => { + for (src, dst, _) in &mut moves { + debug_assert!( + *src != scratch && *dst != scratch, + "Scratch register should not also be an actual source or dest of moves" + ); + debug_assert!( + !(src.is_none() && dst.is_none()), + "Move resolution should not have produced a scratch-to-scratch move" + ); + if src.is_none() { + *src = scratch; + } + if dst.is_none() { + *dst = scratch; + } + } + moves + } + } + } + + /// Unwrap without a scratch register. + pub fn without_scratch(self) -> Option> { + match self { + MoveVecWithScratch::NoScratch(moves) => Some(moves), + MoveVecWithScratch::Scratch(..) => None, + } + } + + /// Do we need a scratch register? + pub fn needs_scratch(&self) -> bool { + match self { + MoveVecWithScratch::NoScratch(..) => false, + MoveVecWithScratch::Scratch(..) => true, + } + } +} + +/// Final stage of move resolution: finding or using scratch +/// registers, creating them if necessary by using stackslots, and +/// ensuring that the final list of moves contains no stack-to-stack +/// moves. +/// +/// The resolved list of moves may need one or two scratch registers, +/// and maybe a stackslot, to ensure these conditions. Our general +/// strategy is in two steps. +/// +/// First, we find a scratch register, so we only have to worry about +/// a list of moves, all with real locations as src and dest. If we're +/// lucky and there are any registers not allocated at this +/// program-point, we can use a real register. Otherwise, we use an +/// extra stackslot. This is fine, because at this step, +/// stack-to-stack moves are OK. +/// +/// Then, we resolve stack-to-stack moves into stack-to-reg / +/// reg-to-stack pairs. For this, we try to allocate a second free +/// register. If unavailable, we create a new scratch stackslot to +/// serve as a backup of one of the in-use registers, then borrow that +/// register as the scratch register in the middle of stack-to-stack +/// moves. +pub struct MoveAndScratchResolver +where + GetReg: FnMut() -> Option, + GetStackSlot: FnMut() -> Allocation, + IsStackAlloc: Fn(Allocation) -> bool, +{ + /// Closure that finds us a PReg at the current location. + pub find_free_reg: GetReg, + /// Closure that gets us a stackslot, if needed. + pub get_stackslot: GetStackSlot, + /// Closure to determine whether an `Allocation` refers to a stack slot. + pub is_stack_alloc: IsStackAlloc, + /// Use this register if no free register is available to use as a + /// temporary in stack-to-stack moves. If we do use this register + /// for that purpose, its value will be restored by the end of the + /// move sequence. Provided by caller and statically chosen. This is + /// a very last-ditch option, so static choice is OK. + pub borrowed_scratch_reg: PReg, +} + +impl MoveAndScratchResolver +where + GetReg: FnMut() -> Option, + GetStackSlot: FnMut() -> Allocation, + IsStackAlloc: Fn(Allocation) -> bool, +{ + pub fn compute( + mut self, + moves: MoveVecWithScratch, + ) -> MoveVec { + let moves = if moves.needs_scratch() { + // Now, find a scratch allocation in order to resolve cycles. + let scratch = (self.find_free_reg)().unwrap_or_else(|| (self.get_stackslot)()); + trace!("scratch resolver: scratch alloc {:?}", scratch); + + moves.with_scratch(scratch) + } else { + moves.without_scratch().unwrap() + }; + + // Do we have any stack-to-stack moves? Fast return if not. + let stack_to_stack = moves + .iter() + .any(|&(src, dst, _)| self.is_stack_to_stack_move(src, dst)); + if !stack_to_stack { + return moves; + } + + // Allocate a scratch register for stack-to-stack move expansion. + let (scratch_reg, save_slot) = if let Some(reg) = (self.find_free_reg)() { + trace!( + "scratch resolver: have free stack-to-stack scratch preg: {:?}", + reg + ); + (reg, None) + } else { + let reg = Allocation::reg(self.borrowed_scratch_reg); + // Stackslot into which we need to save the stack-to-stack + // scratch reg before doing any stack-to-stack moves, if we stole + // the reg. + let save = (self.get_stackslot)(); + trace!( + "scratch resolver: stack-to-stack borrowing {:?} with save stackslot {:?}", + reg, + save + ); + (reg, Some(save)) + }; + + // Mutually exclusive flags for whether either scratch_reg or + // save_slot need to be restored from the other. Initially, + // scratch_reg has a value we should preserve and save_slot + // has garbage. + let mut scratch_dirty = false; + let mut save_dirty = true; + + let mut result = smallvec![]; + for &(src, dst, data) in &moves { + // Do we have a stack-to-stack move? If so, resolve. + if self.is_stack_to_stack_move(src, dst) { + trace!("scratch resolver: stack to stack: {:?} -> {:?}", src, dst); + + // If the selected scratch register is stolen from the + // set of in-use registers, then we need to save the + // current contents of the scratch register before using + // it as a temporary. + if let Some(save_slot) = save_slot { + // However we may have already done so for an earlier + // stack-to-stack move in which case we don't need + // to do it again. + if save_dirty { + debug_assert!(!scratch_dirty); + result.push((scratch_reg, save_slot, T::default())); + save_dirty = false; + } + } + + // We can't move directly from one stack slot to another + // on any architecture we care about, so stack-to-stack + // moves must go via a scratch register. + result.push((src, scratch_reg, data)); + result.push((scratch_reg, dst, data)); + scratch_dirty = true; + } else { + // This is not a stack-to-stack move, but we need to + // make sure that the scratch register is in the correct + // state if this move interacts with that register. + if src == scratch_reg && scratch_dirty { + // We're copying from the scratch register so if + // it was stolen for a stack-to-stack move then we + // need to make sure it has the correct contents, + // not whatever was temporarily copied into it. If + // we got scratch_reg from find_free_reg then it + // had better not have been used as the source of + // a move. So if we're here it's because we fell + // back to the caller-provided last-resort scratch + // register, and we must therefore have a save-slot + // allocated too. + debug_assert!(!save_dirty); + let save_slot = save_slot.expect("move source should not be a free register"); + result.push((save_slot, scratch_reg, T::default())); + scratch_dirty = false; + } + if dst == scratch_reg { + // We are writing something to the scratch register + // so it doesn't matter what was there before. We + // can avoid restoring it, but we will need to save + // it again before the next stack-to-stack move. + scratch_dirty = false; + save_dirty = true; + } + result.push((src, dst, data)); + } + } + + // Now that all the stack-to-stack moves are done, restore the + // scratch register if necessary. + if let Some(save_slot) = save_slot { + if scratch_dirty { + debug_assert!(!save_dirty); + result.push((save_slot, scratch_reg, T::default())); + } + } + + trace!("scratch resolver: got {:?}", result); + result + } + + fn is_stack_to_stack_move(&self, src: Allocation, dst: Allocation) -> bool { + (self.is_stack_alloc)(src) && (self.is_stack_alloc)(dst) + } +} diff --git a/deps/crates/vendor/regalloc2/src/postorder.rs b/deps/crates/vendor/regalloc2/src/postorder.rs new file mode 100644 index 00000000000000..d1e8330b5d5096 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/postorder.rs @@ -0,0 +1,50 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +//! Fast postorder computation. + +use crate::{Block, VecExt}; +use alloc::vec::Vec; +use smallvec::{smallvec, SmallVec}; + +pub fn calculate<'a, SuccFn: Fn(Block) -> &'a [Block]>( + num_blocks: usize, + entry: Block, + visited_scratch: &mut Vec, + out: &mut Vec, + succ_blocks: SuccFn, +) { + // State: visited-block map, and explicit DFS stack. + struct State<'a> { + block: Block, + succs: core::slice::Iter<'a, Block>, + } + + let visited = visited_scratch.repopulate(num_blocks, false); + let mut stack: SmallVec<[State; 64]> = smallvec![]; + out.clear(); + + visited[entry.index()] = true; + stack.push(State { + block: entry, + succs: succ_blocks(entry).iter(), + }); + + while let Some(ref mut state) = stack.last_mut() { + // Perform one action: push to new succ, skip an already-visited succ, or pop. + if let Some(&succ) = state.succs.next() { + if !visited[succ.index()] { + visited[succ.index()] = true; + stack.push(State { + block: succ, + succs: succ_blocks(succ).iter(), + }); + } + } else { + out.push(state.block); + stack.pop(); + } + } +} diff --git a/deps/crates/vendor/regalloc2/src/serialize.rs b/deps/crates/vendor/regalloc2/src/serialize.rs new file mode 100644 index 00000000000000..e98d88313e6194 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/serialize.rs @@ -0,0 +1,293 @@ +use core::fmt; + +use alloc::{format, string::ToString, vec::Vec}; +use serde::{Deserialize, Serialize}; + +use crate::{Block, Function, Inst, InstRange, MachineEnv, Operand, PRegSet, RegClass, VReg}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +enum InstOpcode { + Op, + Ret, + Branch, +} + +impl fmt::Display for InstOpcode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InstOpcode::Op => f.write_str("op"), + InstOpcode::Ret => f.write_str("ret"), + InstOpcode::Branch => f.write_str("branch"), + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct InstData { + op: InstOpcode, + operands: Vec, + clobbers: PRegSet, +} + +/// A wrapper around a `Function` and `MachineEnv` that can be serialized and +/// deserialized. +/// +/// The serialized form of this structure is not stable: it is intended to be +/// deserialized with the exact same version of regalloc2 as the one that it +/// was created with. +#[derive(Serialize, Deserialize)] +pub struct SerializableFunction { + machine_env: MachineEnv, + entry_block: Block, + insts: Vec, + blocks: Vec, + block_preds: Vec>, + block_succs: Vec>, + block_params_in: Vec>, + block_params_out: Vec>>, + num_vregs: usize, + debug_value_labels: Vec<(VReg, Inst, Inst, u32)>, + spillslot_size: Vec, + multi_spillslot_named_by_last_slot: bool, + allow_multiple_vreg_defs: bool, +} + +impl SerializableFunction { + /// Creates a new `SerializableFunction` from an arbitrary `Function` and + /// `MachineEnv`. + pub fn new(func: &impl Function, machine_env: MachineEnv) -> Self { + Self { + machine_env, + entry_block: func.entry_block(), + insts: (0..func.num_insts()) + .map(|i| { + let inst = Inst::new(i); + let op = if func.is_ret(inst) { + InstOpcode::Ret + } else if func.is_branch(inst) { + InstOpcode::Branch + } else { + InstOpcode::Op + }; + InstData { + op, + operands: func.inst_operands(inst).to_vec(), + clobbers: func.inst_clobbers(inst), + } + }) + .collect(), + blocks: (0..func.num_blocks()) + .map(|i| { + let block = Block::new(i); + func.block_insns(block) + }) + .collect(), + block_preds: (0..func.num_blocks()) + .map(|i| { + let block = Block::new(i); + func.block_preds(block).to_vec() + }) + .collect(), + block_succs: (0..func.num_blocks()) + .map(|i| { + let block = Block::new(i); + func.block_succs(block).to_vec() + }) + .collect(), + block_params_in: (0..func.num_blocks()) + .map(|i| { + let block = Block::new(i); + func.block_params(block).to_vec() + }) + .collect(), + block_params_out: (0..func.num_blocks()) + .map(|i| { + let block = Block::new(i); + let inst = func.block_insns(block).last(); + (0..func.block_succs(block).len()) + .map(|succ_idx| func.branch_blockparams(block, inst, succ_idx).to_vec()) + .collect() + }) + .collect(), + num_vregs: func.num_vregs(), + debug_value_labels: func.debug_value_labels().to_vec(), + spillslot_size: [ + func.spillslot_size(RegClass::Int), + func.spillslot_size(RegClass::Float), + func.spillslot_size(RegClass::Vector), + ] + .to_vec(), + multi_spillslot_named_by_last_slot: func.multi_spillslot_named_by_last_slot(), + allow_multiple_vreg_defs: func.allow_multiple_vreg_defs(), + } + } + + /// Returns the `MachineEnv` associated with this function. + pub fn machine_env(&self) -> &MachineEnv { + &self.machine_env + } +} + +impl Function for SerializableFunction { + fn num_insts(&self) -> usize { + self.insts.len() + } + + fn num_blocks(&self) -> usize { + self.blocks.len() + } + + fn entry_block(&self) -> Block { + self.entry_block + } + + fn block_insns(&self, block: Block) -> InstRange { + self.blocks[block.index()] + } + + fn block_succs(&self, block: Block) -> &[Block] { + &self.block_succs[block.index()][..] + } + + fn block_preds(&self, block: Block) -> &[Block] { + &self.block_preds[block.index()][..] + } + + fn block_params(&self, block: Block) -> &[VReg] { + &self.block_params_in[block.index()][..] + } + + fn is_ret(&self, insn: Inst) -> bool { + self.insts[insn.index()].op == InstOpcode::Ret + } + + fn is_branch(&self, insn: Inst) -> bool { + self.insts[insn.index()].op == InstOpcode::Branch + } + + fn branch_blockparams(&self, block: Block, _: Inst, succ: usize) -> &[VReg] { + &self.block_params_out[block.index()][succ][..] + } + + fn inst_operands(&self, insn: Inst) -> &[Operand] { + &self.insts[insn.index()].operands[..] + } + + fn inst_clobbers(&self, insn: Inst) -> PRegSet { + self.insts[insn.index()].clobbers + } + + fn num_vregs(&self) -> usize { + self.num_vregs + } + + fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] { + &self.debug_value_labels[..] + } + + fn spillslot_size(&self, regclass: RegClass) -> usize { + self.spillslot_size[regclass as usize] + } + + fn multi_spillslot_named_by_last_slot(&self) -> bool { + self.multi_spillslot_named_by_last_slot + } + + fn allow_multiple_vreg_defs(&self) -> bool { + self.allow_multiple_vreg_defs + } +} + +impl fmt::Debug for SerializableFunction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{{\n")?; + write!(f, " machine_env: {:#?}\n", self.machine_env())?; + write!( + f, + " spillslot_size(Int): {}\n", + self.spillslot_size(RegClass::Int) + )?; + write!( + f, + " spillslot_size(Float): {}\n", + self.spillslot_size(RegClass::Float) + )?; + write!( + f, + " spillslot_size(Vector): {}\n", + self.spillslot_size(RegClass::Vector) + )?; + write!( + f, + " multi_spillslot_named_by_last_slot: {}\n", + self.multi_spillslot_named_by_last_slot() + )?; + write!( + f, + " allow_multiple_vreg_defs: {}\n", + self.allow_multiple_vreg_defs() + )?; + for (i, blockrange) in self.blocks.iter().enumerate() { + let succs = self.block_succs[i] + .iter() + .map(|b| b.index()) + .collect::>(); + let preds = self.block_preds[i] + .iter() + .map(|b| b.index()) + .collect::>(); + let params_in = self.block_params_in[i] + .iter() + .map(|v| format!("v{}", v.vreg())) + .collect::>() + .join(", "); + let params_out = self.block_params_out[i] + .iter() + .enumerate() + .map(|(succ_idx, vec)| { + let succ = self.block_succs[i][succ_idx]; + let params = vec + .iter() + .map(|v| format!("v{}", v.vreg())) + .collect::>() + .join(", "); + format!("block{}({})", succ.index(), params) + }) + .collect::>() + .join(", "); + write!( + f, + " block{i}({params_in}): # succs:{succs:?} preds:{preds:?}\n", + )?; + for inst in blockrange.iter() { + let ops: Vec<_> = self + .inst_operands(inst) + .iter() + .map(|op| op.to_string()) + .collect(); + let ops = ops.join(", "); + let clobbers = if self.inst_clobbers(inst) == PRegSet::empty() { + format!("") + } else { + let clobbers: Vec<_> = self + .inst_clobbers(inst) + .into_iter() + .map(|preg| format!("Clobber: {preg}")) + .collect(); + format!(", {}", clobbers.join(", ")) + }; + write!( + f, + " inst{}: {} {ops}{clobbers}\n", + inst.index(), + self.insts[inst.index()].op, + )?; + if let InstOpcode::Branch = self.insts[inst.index()].op { + write!(f, " params: {}\n", params_out)?; + } + } + } + write!(f, "}}\n")?; + Ok(()) + } +} diff --git a/deps/crates/vendor/regalloc2/src/ssa.rs b/deps/crates/vendor/regalloc2/src/ssa.rs new file mode 100644 index 00000000000000..4742f46c87df36 --- /dev/null +++ b/deps/crates/vendor/regalloc2/src/ssa.rs @@ -0,0 +1,134 @@ +/* + * Released under the terms of the Apache 2.0 license with LLVM + * exception. See `LICENSE` for details. + */ + +//! SSA-related utilities. + +use alloc::vec; + +use crate::cfg::CFGInfo; +use crate::{Block, Function, FxHashSet, Inst, OperandKind, RegAllocError, VReg}; + +pub fn validate_ssa(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllocError> { + // For every block param and inst def, check that this is the only def. + let mut defined_in = vec![Block::invalid(); f.num_vregs()]; + for block in 0..f.num_blocks() { + let block = Block::new(block); + let mut def = |vreg: VReg, inst| { + if defined_in[vreg.vreg()].is_valid() { + trace!("Multiple def constraints for {:?}", vreg); + Err(RegAllocError::SSA(vreg, inst)) + } else { + defined_in[vreg.vreg()] = block; + Ok(()) + } + }; + for ¶m in f.block_params(block) { + def(param, Inst::invalid())?; + } + for inst in f.block_insns(block).iter() { + for operand in f.inst_operands(inst) { + if let OperandKind::Def = operand.kind() { + def(operand.vreg(), inst)?; + } + } + } + } + + // Walk the blocks in arbitrary order. Check, for every use, that + // the def is either in the same block in an earlier inst, or is + // defined (by inst or blockparam) in some other block that + // dominates this one. + let mut local = FxHashSet::default(); + for block in 0..f.num_blocks() { + let block = Block::new(block); + local.clear(); + local.extend(f.block_params(block)); + + for iix in f.block_insns(block).iter() { + let operands = f.inst_operands(iix); + for operand in operands { + // Fixed registers uses will likely not be SSA, but they also + // won't receive assignments. + if operand.as_fixed_nonallocatable().is_some() { + continue; + } + + match operand.kind() { + OperandKind::Use => { + let def_block = defined_in[operand.vreg().vreg()]; + let okay = def_block.is_valid() + && if def_block == block { + local.contains(&operand.vreg()) + } else { + cfginfo.dominates(def_block, block) + }; + if !okay { + trace!("Invalid use {:?}", operand.vreg()); + return Err(RegAllocError::SSA(operand.vreg(), iix)); + } + } + OperandKind::Def => { + // Check all the uses in this instruction + // first, before recording its defs below. + } + } + } + + // In SSA form, an instruction can't use a VReg that it + // also defines. So only record this instruction's defs + // after its uses have been checked. + for operand in operands { + if let OperandKind::Def = operand.kind() { + local.insert(operand.vreg()); + } + } + } + } + + // Check that the length of branch args matches the sum of the + // number of blockparams in their succs, and that the end of every + // block ends in this branch or in a ret, and that there are no + // other branches or rets in the middle of the block. + for block in 0..f.num_blocks() { + let block = Block::new(block); + let insns = f.block_insns(block); + for insn in insns.iter() { + if insn == insns.last() { + if !(f.is_branch(insn) || f.is_ret(insn)) { + trace!("block {:?} is not terminated by a branch or ret!", block); + return Err(RegAllocError::BB(block)); + } + if f.is_branch(insn) { + for (i, &succ) in f.block_succs(block).iter().enumerate() { + let blockparams_in = f.block_params(succ); + let blockparams_out = f.branch_blockparams(block, insn, i); + if blockparams_in.len() != blockparams_out.len() { + trace!( + "Mismatch on block params, found {} expected {}", + blockparams_out.len(), + blockparams_in.len() + ); + return Err(RegAllocError::Branch(insn)); + } + } + } + } else { + if f.is_branch(insn) || f.is_ret(insn) { + trace!("Block terminator found in the middle of a block"); + return Err(RegAllocError::BB(block)); + } + } + } + } + + // Check that the entry block has no block args: otherwise it is + // undefined what their value would be. + if f.block_params(f.entry_block()).len() > 0 { + trace!("Entry block contains block args"); + return Err(RegAllocError::BB(f.entry_block())); + } + + Ok(()) +} diff --git a/deps/crates/vendor/rustc-hash/.cargo-checksum.json b/deps/crates/vendor/rustc-hash/.cargo-checksum.json new file mode 100644 index 00000000000000..b400a660a9b489 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"18714b27c324e1100a99a311c0104619f4c000aa44070928d72c8cd3e3ec8090",".github/workflows/rust.yml":"ff0288f89c97203b725441e9d9717fa0c049f1cebb2bcbb556981bfa8be10029","CHANGELOG.md":"99bb0a76f5f4d89142295597be863b253a74276955ea9c669c49eef05828284a","CODE_OF_CONDUCT.md":"3e77f5476805b69467641b2c682aa2355344395056939089182cd901c56dce63","Cargo.lock":"a121372b7ec1431a3bce191d29046a17c49102fd3f5540e959df19ffab4ddb0b","Cargo.toml":"2db71897d3dc8cbd86f28507c3929a37b1d0a1e436037e40f935b647ee51e802","Cargo.toml.orig":"921bad999d97d293ab4a01163dfb9add86f20b4e1716cb32596da3795b8bcdb6","LICENSE-APACHE":"95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc","LICENSE-MIT":"30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652","README.md":"ccd7a15a2e2021dbbfd5b7f99a10666a64ac50f8d5d6926a858efdde724fb424","src/lib.rs":"59a4b66a26275ca202f834cb7bc2feda135136533f0e8599af97d2563d15f72f","src/random_state.rs":"39063b702c38dc93b7a9039f19f4acfdc539acf1604584a87eeb43cca149ca7e","src/seeded_state.rs":"530ba6e25d766231cc7540f968d3e41c5af5a38d936542b407010b9d35746fd8"},"package":"94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"} \ No newline at end of file diff --git a/deps/crates/vendor/rustc-hash/.cargo_vcs_info.json b/deps/crates/vendor/rustc-hash/.cargo_vcs_info.json new file mode 100644 index 00000000000000..b657dbb45707a5 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "fdb275c8a0135403067ce1c4be8e97e53c473764" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/rustc-hash/.github/workflows/rust.yml b/deps/crates/vendor/rustc-hash/.github/workflows/rust.yml new file mode 100644 index 00000000000000..0a019cbfb00afd --- /dev/null +++ b/deps/crates/vendor/rustc-hash/.github/workflows/rust.yml @@ -0,0 +1,73 @@ +name: Rust + +permissions: + contents: read + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + RUSTUP_MAX_RETRIES: 10 + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + test: + strategy: + matrix: + os: [ubuntu, windows, macos] + runs-on: ${{ matrix.os }}-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - run: rustup update stable && rustup default stable + - run: cargo check + - run: cargo test + - run: rustup update nightly && rustup default nightly + - run: cargo test --all-features + cross-test: + strategy: + matrix: + target: [ + "x86_64-unknown-linux-gnu", # 64-bits, little-endian + "i686-unknown-linux-gnu", # 32-bits, little-endian + "mips-unknown-linux-gnu", # 32-bits, big-endian + "mips64-unknown-linux-gnuabi64", # 64-bits, big-endian + ] + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: install miri + run: rustup toolchain add nightly --no-self-update --component miri && rustup default nightly + - run: | + cargo miri test --target=${{ matrix.target }} --all-features + env: + MIRIFLAGS: -Zmiri-strict-provenance + RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} -Z randomize-layout + RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup update stable && rustup default stable + - run: rustup component add rustfmt + - run: cargo fmt --all --check + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup update stable && rustup default stable + - run: cargo doc --workspace --document-private-items --no-deps + env: + RUSTDOCFLAGS: -D warnings + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup update stable && rustup default stable + - run: rustup component add clippy + - run: cargo clippy --workspace --all-targets --no-deps diff --git a/deps/crates/vendor/rustc-hash/CHANGELOG.md b/deps/crates/vendor/rustc-hash/CHANGELOG.md new file mode 100644 index 00000000000000..c05f916dffd278 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/CHANGELOG.md @@ -0,0 +1,36 @@ +# 2.1.2 + +- [Refactor byte hashing to remove unreachable panic](https://github.com/rust-lang/rustc-hash/pull/65) + +# 2.1.1 + +- Change the internal algorithm to better accomodate large hashmaps. + This mitigates a [regression with 2.0 in rustc](https://github.com/rust-lang/rust/issues/135477). + See [PR#55](https://github.com/rust-lang/rustc-hash/pull/55) for more details on the change (this PR was not merged). + This problem might be improved with changes to hashbrown in the future. + +## 2.1.0 + +- Implement `Clone` for `FxRandomState` +- Implement `Clone` for `FxSeededState` +- Use SPDX license expression in license field + +## 2.0.0 + +- Replace hash with faster and better finalized hash. + This replaces the previous "fxhash" algorithm originating in Firefox + with a custom hasher designed and implemented by Orson Peters ([`@orlp`](https://github.com/orlp)). + It was measured to have slightly better performance for rustc, has better theoretical properties + and also includes a significantly better string hasher. +- Fix `no_std` builds + +## 1.2.0 (**YANKED**) + +**Note: This version has been yanked due to issues with the `no_std` feature!** + +- Add a `FxBuildHasher` unit struct +- Improve documentation +- Add seed API for supplying custom seeds other than 0 +- Add `FxRandomState` based on `rand` (behind the `rand` feature) for random seeds +- Make many functions `const fn` +- Implement `Clone` for `FxHasher` struct diff --git a/deps/crates/vendor/rustc-hash/CODE_OF_CONDUCT.md b/deps/crates/vendor/rustc-hash/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000000..d6d774281213a9 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# The Rust Code of Conduct + +The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html). \ No newline at end of file diff --git a/deps/crates/vendor/rustc-hash/Cargo.lock b/deps/crates/vendor/rustc-hash/Cargo.lock new file mode 100644 index 00000000000000..31ecf1da58b787 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/deps/crates/vendor/rustc-hash/Cargo.toml b/deps/crates/vendor/rustc-hash/Cargo.toml new file mode 100644 index 00000000000000..495c178ffcd604 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/Cargo.toml @@ -0,0 +1,50 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.77" +name = "rustc-hash" +version = "2.1.2" +authors = ["The Rust Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A speedy, non-cryptographic hashing algorithm used by rustc" +readme = "README.md" +keywords = [ + "hash", + "hasher", + "fxhash", + "rustc", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/rust-lang/rustc-hash" + +[features] +default = ["std"] +nightly = [] +rand = [ + "dep:rand", + "std", +] +std = [] + +[lib] +name = "rustc_hash" +path = "src/lib.rs" + +[dependencies.rand] +version = "0.8" +optional = true diff --git a/deps/crates/vendor/rustc-hash/Cargo.toml.orig b/deps/crates/vendor/rustc-hash/Cargo.toml.orig new file mode 100644 index 00000000000000..72cc57ccb6cb1b --- /dev/null +++ b/deps/crates/vendor/rustc-hash/Cargo.toml.orig @@ -0,0 +1,20 @@ +[package] +name = "rustc-hash" +version = "2.1.2" +authors = ["The Rust Project Developers"] +description = "A speedy, non-cryptographic hashing algorithm used by rustc" +license = "Apache-2.0 OR MIT" +readme = "README.md" +keywords = ["hash", "hasher", "fxhash", "rustc"] +repository = "https://github.com/rust-lang/rustc-hash" +edition = "2021" +rust-version = "1.77" + +[features] +default = ["std"] +std = [] +nightly = [] +rand = ["dep:rand", "std"] + +[dependencies] +rand = { version = "0.8", optional = true } diff --git a/deps/crates/vendor/rustc-hash/LICENSE-APACHE b/deps/crates/vendor/rustc-hash/LICENSE-APACHE new file mode 100644 index 00000000000000..a7e77cb28d386e --- /dev/null +++ b/deps/crates/vendor/rustc-hash/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/deps/crates/vendor/rustc-hash/LICENSE-MIT b/deps/crates/vendor/rustc-hash/LICENSE-MIT new file mode 100644 index 00000000000000..468cd79a8f6e50 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/deps/crates/vendor/rustc-hash/README.md b/deps/crates/vendor/rustc-hash/README.md new file mode 100644 index 00000000000000..bcac3455ac90d6 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/README.md @@ -0,0 +1,42 @@ +# rustc-hash + +[![crates.io](https://img.shields.io/crates/v/rustc-hash.svg)](https://crates.io/crates/rustc-hash) +[![Documentation](https://docs.rs/rustc-hash/badge.svg)](https://docs.rs/rustc-hash) + +A speedy, non-cryptographic hashing algorithm used by `rustc`. +The [hash map in `std`](https://doc.rust-lang.org/std/collections/struct.HashMap.html) uses SipHash by default, which provides resistance against DOS attacks. +These attacks aren't a concern in the compiler so we prefer to use a quicker, +non-cryptographic hash algorithm. + +The original hash algorithm provided by this crate was one taken from Firefox, +hence the hasher it provides is called FxHasher. This name is kept for backwards +compatibility, but the underlying hash has since been replaced. The current +design for the hasher is a polynomial hash finished with a single bit rotation, +together with a wyhash-inspired compression function for strings/slices, both +designed by Orson Peters. + +For `rustc` we have tried many different hashing algorithms. Hashing speed is +critical, especially for single integers. Spending more CPU cycles on a higher +quality hash does not reduce hash collisions enough to make the compiler faster +on real-world benchmarks. + +## Usage + +This crate provides `FxHashMap` and `FxHashSet` as collections. +They are simply type aliases for their `std::collection` counterparts using the Fx hasher. + +```rust +use rustc_hash::FxHashMap; + +let mut map: FxHashMap = FxHashMap::default(); +map.insert(22, 44); +``` + +### `no_std` + +The `std` feature is on by default to enable collections. +It can be turned off in `Cargo.toml` like so: + +```toml +rustc-hash = { version = "2.1", default-features = false } +``` diff --git a/deps/crates/vendor/rustc-hash/src/lib.rs b/deps/crates/vendor/rustc-hash/src/lib.rs new file mode 100644 index 00000000000000..b3270c31bdecdf --- /dev/null +++ b/deps/crates/vendor/rustc-hash/src/lib.rs @@ -0,0 +1,498 @@ +//! A speedy, non-cryptographic hashing algorithm used by `rustc`. +//! +//! # Example +//! +//! ```rust +//! # #[cfg(feature = "std")] +//! # fn main() { +//! use rustc_hash::FxHashMap; +//! +//! let mut map: FxHashMap = FxHashMap::default(); +//! map.insert(22, 44); +//! # } +//! # #[cfg(not(feature = "std"))] +//! # fn main() { } +//! ``` + +#![no_std] +#![cfg_attr(feature = "nightly", feature(const_default))] +#![cfg_attr(feature = "nightly", feature(const_trait_impl))] +#![cfg_attr(feature = "nightly", feature(derive_const))] +#![cfg_attr(feature = "nightly", feature(hasher_prefixfree_extras))] +#![allow(rustc::default_hash_types)] + +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "rand")] +extern crate rand; + +#[cfg(feature = "rand")] +mod random_state; + +mod seeded_state; + +use core::default::Default; +use core::hash::{BuildHasher, Hasher}; +#[cfg(feature = "std")] +use std::collections::{HashMap, HashSet}; + +/// Type alias for a hash map that uses the Fx hashing algorithm. +#[cfg(feature = "std")] +pub type FxHashMap = HashMap; + +/// Type alias for a hash set that uses the Fx hashing algorithm. +#[cfg(feature = "std")] +pub type FxHashSet = HashSet; + +#[cfg(feature = "rand")] +pub use random_state::{FxHashMapRand, FxHashSetRand, FxRandomState}; + +pub use seeded_state::FxSeededState; +#[cfg(feature = "std")] +pub use seeded_state::{FxHashMapSeed, FxHashSetSeed}; + +/// A speedy hash algorithm for use within rustc. The hashmap in liballoc +/// by default uses SipHash which isn't quite as speedy as we want. In the +/// compiler we're not really worried about DOS attempts, so we use a fast +/// non-cryptographic hash. +/// +/// The current implementation is a fast polynomial hash with a single +/// bit rotation as a finishing step designed by Orson Peters. +#[derive(Clone)] +pub struct FxHasher { + hash: usize, +} + +// One might view a polynomial hash +// m[0] * k + m[1] * k^2 + m[2] * k^3 + ... +// as a multilinear hash with keystream k[..] +// m[0] * k[0] + m[1] * k[1] + m[2] * k[2] + ... +// where keystream k just happens to be generated using a multiplicative +// congruential pseudorandom number generator (MCG). For that reason we chose a +// constant that was found to be good for a MCG in: +// "Computationally Easy, Spectrally Good Multipliers for Congruential +// Pseudorandom Number Generators" by Guy Steele and Sebastiano Vigna. +#[cfg(target_pointer_width = "64")] +const K: usize = 0xf1357aea2e62a9c5; +#[cfg(target_pointer_width = "32")] +const K: usize = 0x93d765dd; + +impl FxHasher { + /// Creates a `fx` hasher with a given seed. + pub const fn with_seed(seed: usize) -> FxHasher { + FxHasher { hash: seed } + } + + /// Creates a default `fx` hasher. + pub const fn default() -> FxHasher { + FxHasher { hash: 0 } + } +} + +#[cfg(not(feature = "nightly"))] +macro_rules! default_impl { + () => { + impl Default for FxHasher { + #[inline] + fn default() -> FxHasher { + Self::default() + } + } + }; +} + +// In order to use the nightly-only `const` syntax, we gate the definition behind a macro so that +// parsing still succeeds on stable. +#[cfg(feature = "nightly")] +macro_rules! default_impl { + () => { + impl const Default for FxHasher { + #[inline] + fn default() -> FxHasher { + Self::default() + } + } + }; +} + +default_impl!(); + +impl FxHasher { + #[inline] + fn add_to_hash(&mut self, i: usize) { + self.hash = self.hash.wrapping_add(i).wrapping_mul(K); + } +} + +impl Hasher for FxHasher { + #[inline] + fn write(&mut self, bytes: &[u8]) { + // Compress the byte string to a single u64 and add to our hash. + self.write_u64(hash_bytes(bytes)); + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + #[cfg(target_pointer_width = "32")] + self.add_to_hash((i >> 32) as usize); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.add_to_hash(i as usize); + #[cfg(target_pointer_width = "32")] + self.add_to_hash((i >> 32) as usize); + self.add_to_hash((i >> 64) as usize); + #[cfg(target_pointer_width = "32")] + self.add_to_hash((i >> 96) as usize); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.add_to_hash(i); + } + + #[cfg(feature = "nightly")] + #[inline] + fn write_length_prefix(&mut self, _len: usize) { + // Most cases will specialize hash_slice to call write(), which encodes + // the length already in a more efficient manner than we could here. For + // HashDoS-resistance you would still need to include this for the + // non-slice collection hashes, but for the purposes of rustc we do not + // care and do not wish to pay the performance penalty of mixing in len + // for those collections. + } + + #[cfg(feature = "nightly")] + #[inline] + fn write_str(&mut self, s: &str) { + // Similarly here, write already encodes the length, so nothing special + // is needed. + self.write(s.as_bytes()) + } + + #[inline] + fn finish(&self) -> u64 { + // Since we used a multiplicative hash our top bits have the most + // entropy (with the top bit having the most, decreasing as you go). + // As most hash table implementations (including hashbrown) compute + // the bucket index from the bottom bits we want to move bits from the + // top to the bottom. Ideally we'd rotate left by exactly the hash table + // size, but as we don't know this we'll choose 26 bits, giving decent + // entropy up until 2^26 table sizes. On 32-bit hosts we'll dial it + // back down a bit to 15 bits. + + #[cfg(target_pointer_width = "64")] + const ROTATE: u32 = 26; + #[cfg(target_pointer_width = "32")] + const ROTATE: u32 = 15; + + self.hash.rotate_left(ROTATE) as u64 + + // A bit reversal would be even better, except hashbrown also expects + // good entropy in the top 7 bits and a bit reverse would fill those + // bits with low entropy. More importantly, bit reversals are very slow + // on x86-64. A byte reversal is relatively fast, but still has a 2 + // cycle latency on x86-64 compared to the 1 cycle latency of a rotate. + // It also suffers from the hashbrown-top-7-bit-issue. + } +} + +// Nothing special, digits of pi. +const SEED1: u64 = 0x243f6a8885a308d3; +const SEED2: u64 = 0x13198a2e03707344; +const PREVENT_TRIVIAL_ZERO_COLLAPSE: u64 = 0xa4093822299f31d0; + +#[inline] +fn multiply_mix(x: u64, y: u64) -> u64 { + // The following code path is only fast if 64-bit to 128-bit widening + // multiplication is supported by the architecture. Most 64-bit + // architectures except SPARC64 and Wasm64 support it. However, the target + // pointer width doesn't always indicate that we are dealing with a 64-bit + // architecture, as there are ABIs that reduce the pointer width, especially + // on AArch64 and x86-64. WebAssembly (regardless of pointer width) supports + // 64-bit to 128-bit widening multiplication with the `wide-arithmetic` + // proposal. + if cfg!(any( + all( + target_pointer_width = "64", + not(any(target_arch = "sparc64", target_arch = "wasm64")), + ), + target_arch = "aarch64", + target_arch = "x86_64", + all(target_family = "wasm", target_feature = "wide-arithmetic"), + )) { + // We compute the full u64 x u64 -> u128 product, this is a single mul + // instruction on x86-64, one mul plus one mulhi on ARM64. + let full = (x as u128).wrapping_mul(y as u128); + let lo = full as u64; + let hi = (full >> 64) as u64; + + // The middle bits of the full product fluctuate the most with small + // changes in the input. This is the top bits of lo and the bottom bits + // of hi. We can thus make the entire output fluctuate with small + // changes to the input by XOR'ing these two halves. + lo ^ hi + + // Unfortunately both 2^64 + 1 and 2^64 - 1 have small prime factors, + // otherwise combining with + or - could result in a really strong hash, as: + // x * y = 2^64 * hi + lo = (-1) * hi + lo = lo - hi, (mod 2^64 + 1) + // x * y = 2^64 * hi + lo = 1 * hi + lo = lo + hi, (mod 2^64 - 1) + // Multiplicative hashing is universal in a field (like mod p). + } else { + // u64 x u64 -> u128 product is prohibitively expensive on 32-bit. + // Decompose into 32-bit parts. + let lx = x as u32; + let ly = y as u32; + let hx = (x >> 32) as u32; + let hy = (y >> 32) as u32; + + // u32 x u32 -> u64 the low bits of one with the high bits of the other. + let afull = (lx as u64).wrapping_mul(hy as u64); + let bfull = (hx as u64).wrapping_mul(ly as u64); + + // Combine, swapping low/high of one of them so the upper bits of the + // product of one combine with the lower bits of the other. + afull ^ bfull.rotate_right(32) + } +} + +/// A wyhash-inspired non-collision-resistant hash for strings/slices designed +/// by Orson Peters, with a focus on small strings and small codesize. +/// +/// The 64-bit version of this hash passes the SMHasher3 test suite on the full +/// 64-bit output, that is, f(hash_bytes(b) ^ f(seed)) for some good avalanching +/// permutation f() passed all tests with zero failures. When using the 32-bit +/// version of multiply_mix this hash has a few non-catastrophic failures where +/// there are a handful more collisions than an optimal hash would give. +/// +/// We don't bother avalanching here as we'll feed this hash into a +/// multiplication after which we take the high bits, which avalanches for us. +#[inline] +fn hash_bytes(bytes: &[u8]) -> u64 { + let len = bytes.len(); + let mut s0 = SEED1; + let mut s1 = SEED2; + + if len <= 16 { + // XOR the input into s0, s1. + if len >= 8 { + s0 ^= u64::from_le_bytes(bytes[0..8].try_into().unwrap()); + s1 ^= u64::from_le_bytes(bytes[len - 8..].try_into().unwrap()); + } else if len >= 4 { + s0 ^= u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as u64; + s1 ^= u32::from_le_bytes(bytes[len - 4..].try_into().unwrap()) as u64; + } else if len > 0 { + let lo = bytes[0]; + let mid = bytes[len / 2]; + let hi = bytes[len - 1]; + s0 ^= lo as u64; + s1 ^= ((hi as u64) << 8) | mid as u64; + } + } else { + // Handle bulk (can partially overlap with suffix). + let mut bulk = &bytes[..(len - 1)]; + while let Some((chunk, rest)) = bulk.split_first_chunk::<16>() { + let x = u64::from_le_bytes((&chunk[..8]).try_into().unwrap()); + let y = u64::from_le_bytes((&chunk[8..]).try_into().unwrap()); + + // Replace s1 with a mix of s0, x, and y, and s0 with s1. + // This ensures the compiler can unroll this loop into two + // independent streams, one operating on s0, the other on s1. + // + // Since zeroes are a common input we prevent an immediate trivial + // collapse of the hash function by XOR'ing a constant with y. + let t = multiply_mix(s0 ^ x, PREVENT_TRIVIAL_ZERO_COLLAPSE ^ y); + s0 = s1; + s1 = t; + bulk = rest; + } + + let suffix = &bytes[len - 16..]; + s0 ^= u64::from_le_bytes(suffix[0..8].try_into().unwrap()); + s1 ^= u64::from_le_bytes(suffix[8..16].try_into().unwrap()); + } + + multiply_mix(s0, s1) ^ (len as u64) +} + +/// An implementation of [`BuildHasher`] that produces [`FxHasher`]s. +/// +/// ``` +/// use std::hash::BuildHasher; +/// use rustc_hash::FxBuildHasher; +/// assert_ne!(FxBuildHasher.hash_one(1), FxBuildHasher.hash_one(2)); +/// ``` +#[derive(Copy, Clone)] +#[cfg_attr(not(feature = "nightly"), derive(Default))] +#[cfg_attr(feature = "nightly", derive_const(Default))] +pub struct FxBuildHasher; + +impl BuildHasher for FxBuildHasher { + type Hasher = FxHasher; + fn build_hasher(&self) -> FxHasher { + FxHasher::default() + } +} + +#[cfg(test)] +mod tests { + #[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))] + compile_error!("The test suite only supports 64 bit and 32 bit usize"); + + use crate::{FxBuildHasher, FxHasher}; + use core::hash::{BuildHasher, Hash, Hasher}; + + macro_rules! test_hash { + ( + $( + hash($value:expr) == $result:expr, + )* + ) => { + $( + assert_eq!(FxBuildHasher.hash_one($value), $result); + )* + }; + } + + const B32: bool = cfg!(target_pointer_width = "32"); + + #[test] + fn unsigned() { + test_hash! { + hash(0_u8) == 0, + hash(1_u8) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_u8) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(u8::MAX) == if B32 { 999399879 } else { 1211781028898739645 }, + + hash(0_u16) == 0, + hash(1_u16) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_u16) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(u16::MAX) == if B32 { 3440503042 } else { 16279819243059860173 }, + + hash(0_u32) == 0, + hash(1_u32) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_u32) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(u32::MAX) == if B32 { 1293006356 } else { 7729994835221066939 }, + + hash(0_u64) == 0, + hash(1_u64) == if B32 { 275023839 } else { 12157901119326311915 }, + hash(100_u64) == if B32 { 1732383522 } else { 16751747135202103309 }, + hash(u64::MAX) == if B32 { 1017982517 } else { 6288842954450348564 }, + + hash(0_u128) == 0, + hash(1_u128) == if B32 { 1860738631 } else { 13032756267696824044 }, + hash(100_u128) == if B32 { 1389515751 } else { 12003541609544029302 }, + hash(u128::MAX) == if B32 { 2156022013 } else { 11702830760530184999 }, + + hash(0_usize) == 0, + hash(1_usize) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_usize) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(usize::MAX) == if B32 { 1293006356 } else { 6288842954450348564 }, + } + } + + #[test] + fn signed() { + test_hash! { + hash(i8::MIN) == if B32 { 2000713177 } else { 6684841074112525780 }, + hash(0_i8) == 0, + hash(1_i8) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_i8) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(i8::MAX) == if B32 { 3293686765 } else { 12973684028562874344 }, + + hash(i16::MIN) == if B32 { 1073764727 } else { 14218860181193086044 }, + hash(0_i16) == 0, + hash(1_i16) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_i16) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(i16::MAX) == if B32 { 2366738315 } else { 2060959061933882993 }, + + hash(i32::MIN) == if B32 { 16384 } else { 9943947977240134995 }, + hash(0_i32) == 0, + hash(1_i32) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_i32) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(i32::MAX) == if B32 { 1293022740 } else { 16232790931690483559 }, + + hash(i64::MIN) == if B32 { 16384 } else { 33554432 }, + hash(0_i64) == 0, + hash(1_i64) == if B32 { 275023839 } else { 12157901119326311915 }, + hash(100_i64) == if B32 { 1732383522 } else { 16751747135202103309 }, + hash(i64::MAX) == if B32 { 1017998901 } else { 6288842954483902996 }, + + hash(i128::MIN) == if B32 { 16384 } else { 33554432 }, + hash(0_i128) == 0, + hash(1_i128) == if B32 { 1860738631 } else { 13032756267696824044 }, + hash(100_i128) == if B32 { 1389515751 } else { 12003541609544029302 }, + hash(i128::MAX) == if B32 { 2156005629 } else { 11702830760496630567 }, + + hash(isize::MIN) == if B32 { 16384 } else { 33554432 }, + hash(0_isize) == 0, + hash(1_isize) == if B32 { 3001993707 } else { 12157901119326311915 }, + hash(100_isize) == if B32 { 3844759569 } else { 16751747135202103309 }, + hash(isize::MAX) == if B32 { 1293022740 } else { 6288842954483902996 }, + } + } + + // Avoid relying on any `Hash` implementations in the standard library. + struct HashBytes(&'static [u8]); + impl Hash for HashBytes { + fn hash(&self, state: &mut H) { + state.write(self.0); + } + } + + #[test] + fn bytes() { + test_hash! { + hash(HashBytes(&[])) == if B32 { 2673204745 } else { 17606491139363777937 }, + hash(HashBytes(&[0])) == if B32 { 2948228584 } else { 5448590020104574886 }, + hash(HashBytes(&[0, 0, 0, 0, 0, 0])) == if B32 { 3223252423 } else { 16766921560080789783 }, + hash(HashBytes(&[1])) == if B32 { 2943445104 } else { 5922447956811044110 }, + hash(HashBytes(&[2])) == if B32 { 1055423297 } else { 5229781508510959783 }, + hash(HashBytes(b"uwu")) == if B32 { 2699662140 } else { 7168164714682931527 }, + hash(HashBytes(b"These are some bytes for testing rustc_hash.")) == if B32 { 2303640537 } else { 2349210501944688211 }, + } + } + + #[test] + fn with_seed_actually_different() { + let seeds = [ + [1, 2], + [42, 17], + [124436707, 99237], + [usize::MIN, usize::MAX], + ]; + + for [a_seed, b_seed] in seeds { + let a = || FxHasher::with_seed(a_seed); + let b = || FxHasher::with_seed(b_seed); + + for x in u8::MIN..=u8::MAX { + let mut a = a(); + let mut b = b(); + + x.hash(&mut a); + x.hash(&mut b); + + assert_ne!(a.finish(), b.finish()) + } + } + } +} diff --git a/deps/crates/vendor/rustc-hash/src/random_state.rs b/deps/crates/vendor/rustc-hash/src/random_state.rs new file mode 100644 index 00000000000000..c8c35a0b1a4da9 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/src/random_state.rs @@ -0,0 +1,101 @@ +use std::collections::{HashMap, HashSet}; + +use crate::FxHasher; + +/// Type alias for a hashmap using the `fx` hash algorithm with [`FxRandomState`]. +pub type FxHashMapRand = HashMap; + +/// Type alias for a hashmap using the `fx` hash algorithm with [`FxRandomState`]. +pub type FxHashSetRand = HashSet; + +/// `FxRandomState` is an alternative state for `HashMap` types. +/// +/// A particular instance `FxRandomState` will create the same instances of +/// [`Hasher`], but the hashers created by two different `FxRandomState` +/// instances are unlikely to produce the same result for the same values. +#[derive(Clone)] +pub struct FxRandomState { + seed: usize, +} + +impl FxRandomState { + /// Constructs a new `FxRandomState` that is initialized with random seed. + pub fn new() -> FxRandomState { + use rand::Rng; + use std::{cell::Cell, thread_local}; + + // This mirrors what `std::collections::hash_map::RandomState` does, as of 2024-01-14. + // + // Basically + // 1. Cache result of the rng in a thread local, so repeatedly + // creating maps is cheaper + // 2. Change the cached result on every creation, so maps created + // on the same thread don't have the same iteration order + thread_local!(static SEED: Cell = { + Cell::new(rand::thread_rng().gen()) + }); + + SEED.with(|seed| { + let s = seed.get(); + seed.set(s.wrapping_add(1)); + FxRandomState { seed: s } + }) + } +} + +impl core::hash::BuildHasher for FxRandomState { + type Hasher = FxHasher; + + fn build_hasher(&self) -> Self::Hasher { + FxHasher::with_seed(self.seed) + } +} + +impl Default for FxRandomState { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use std::thread; + + use crate::FxHashMapRand; + + #[test] + fn cloned_random_states_are_equal() { + let a = FxHashMapRand::<&str, u32>::default(); + let b = a.clone(); + + assert_eq!(a.hasher().seed, b.hasher().seed); + } + + #[test] + fn random_states_are_different() { + let a = FxHashMapRand::<&str, u32>::default(); + let b = FxHashMapRand::<&str, u32>::default(); + + // That's the whole point of them being random! + // + // N.B.: `FxRandomState` uses a thread-local set to a random value and then incremented, + // which means that this is *guaranteed* to pass :> + assert_ne!(a.hasher().seed, b.hasher().seed); + } + + #[test] + fn random_states_are_different_cross_thread() { + // This is similar to the test above, but uses two different threads, so they both get + // completely random, unrelated values. + // + // This means that this test is technically flaky, but the probability of it failing is + // `1 / 2.pow(bit_size_of::())`. Or 1/1.7e19 for 64 bit platforms or 1/4294967295 + // for 32 bit platforms. I suppose this is acceptable. + let a = FxHashMapRand::<&str, u32>::default(); + let b = thread::spawn(|| FxHashMapRand::<&str, u32>::default()) + .join() + .unwrap(); + + assert_ne!(a.hasher().seed, b.hasher().seed); + } +} diff --git a/deps/crates/vendor/rustc-hash/src/seeded_state.rs b/deps/crates/vendor/rustc-hash/src/seeded_state.rs new file mode 100644 index 00000000000000..e84190625939e8 --- /dev/null +++ b/deps/crates/vendor/rustc-hash/src/seeded_state.rs @@ -0,0 +1,76 @@ +use crate::FxHasher; + +/// Type alias for a hashmap using the `fx` hash algorithm with [`FxSeededState`]. +#[cfg(feature = "std")] +pub type FxHashMapSeed = std::collections::HashMap; + +/// Type alias for a hashmap using the `fx` hash algorithm with [`FxSeededState`]. +#[cfg(feature = "std")] +pub type FxHashSetSeed = std::collections::HashSet; + +/// [`FxSeededState`] is an alternative state for `HashMap` types, allowing to use [`FxHasher`] with a set seed. +/// +/// ``` +/// # use std::collections::HashMap; +/// use rustc_hash::FxSeededState; +/// +/// let mut map = HashMap::with_hasher(FxSeededState::with_seed(12)); +/// map.insert(15, 610); +/// assert_eq!(map[&15], 610); +/// ``` +#[derive(Clone)] +pub struct FxSeededState { + seed: usize, +} + +impl FxSeededState { + /// Constructs a new `FxSeededState` that is initialized with a `seed`. + pub const fn with_seed(seed: usize) -> FxSeededState { + Self { seed } + } +} + +impl core::hash::BuildHasher for FxSeededState { + type Hasher = FxHasher; + + fn build_hasher(&self) -> Self::Hasher { + FxHasher::with_seed(self.seed) + } +} + +#[cfg(test)] +mod tests { + use core::hash::BuildHasher; + + use crate::FxSeededState; + + #[test] + fn cloned_seeded_states_are_equal() { + let seed = 2; + let a = FxSeededState::with_seed(seed); + let b = a.clone(); + + assert_eq!(a.seed, b.seed); + assert_eq!(a.seed, seed); + + assert_eq!(a.build_hasher().hash, b.build_hasher().hash); + } + + #[test] + fn same_seed_produces_same_hasher() { + let seed = 1; + let a = FxSeededState::with_seed(seed); + let b = FxSeededState::with_seed(seed); + + // The hashers should be the same, as they have the same seed. + assert_eq!(a.build_hasher().hash, b.build_hasher().hash); + } + + #[test] + fn different_states_are_different() { + let a = FxSeededState::with_seed(1); + let b = FxSeededState::with_seed(2); + + assert_ne!(a.build_hasher().hash, b.build_hasher().hash); + } +} diff --git a/deps/crates/vendor/target-lexicon/.cargo-checksum.json b/deps/crates/vendor/target-lexicon/.cargo-checksum.json new file mode 100644 index 00000000000000..9a731b044adf39 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"43cf58c3feef557572d099bb89ada7ac33863b5fcea2d60f1f6fe1d407442eef",".github/actions/install-rust/README.md":"ec3413893c747ac6a33cdf3331a5d17b9dfdb5b938c8d8edeb124c739feddfdf","Cargo.lock":"536bb6dd71e6b51e31e7166f7300b3289aca58467a2f7a836d72bb1b51748e9e","Cargo.toml":"68c92fd64e0ba0311fffd938aa03a2c58a13341c37523da1dd465c7eea9269ea","Cargo.toml.orig":"c9ab3fc97cf1702b3d4a4adc83d50959eb4bb4131460a29f0c015cecbfa8084a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"608a98115ed2846984e68cbbea120473f9803c04297898c06435336a24bf4c32","build.rs":"678ba872ef2254e8901d6a00536f64d74d375d919f845113bd3ded709b6edb4a","src/data_model.rs":"17d2a169891723972f726c95d03a20c4a1482464c685028685f48ca976482a1c","src/host.rs":"f51aae5e56e531648b94afd85012f73aad5615e634df64d2b1445a0e0285d8ba","src/lib.rs":"c372de38d232f90d1aa7142702fd122b00f3b8fcb87b9bb0a2177ed9b7c4b6e7","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"e51c256e555be425b8a912460e7c68c42b2788d3ea611908bc6727f7bb4f678a","src/triple.rs":"76ca408aeb22b5ac334483dba9024975a65c7d470ae71c9bfd0cf7b8bfa1b5ec"},"package":"adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"} \ No newline at end of file diff --git a/deps/crates/vendor/target-lexicon/.cargo_vcs_info.json b/deps/crates/vendor/target-lexicon/.cargo_vcs_info.json new file mode 100644 index 00000000000000..07e03d8c9e7794 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "6647bd7d681d3e218c88568d8285dfd8cae2dd97" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/target-lexicon/.github/actions/install-rust/README.md b/deps/crates/vendor/target-lexicon/.github/actions/install-rust/README.md new file mode 100644 index 00000000000000..df8e94dcccbf7a --- /dev/null +++ b/deps/crates/vendor/target-lexicon/.github/actions/install-rust/README.md @@ -0,0 +1,18 @@ +# install-rust + +A small github action to install `rustup` and a Rust toolchain. This is +generally expressed inline, but it was repeated enough in this repository it +seemed worthwhile to extract. + +Some gotchas: + +* Can't `--self-update` on Windows due to permission errors (a bug in Github + Actions) +* `rustup` isn't installed on macOS (a bug in Github Actions) + +When the above are fixed we should delete this action and just use this inline: + +```yml +- run: rustup update $toolchain && rustup default $toolchain + shell: bash +``` diff --git a/deps/crates/vendor/target-lexicon/Cargo.lock b/deps/crates/vendor/target-lexicon/Cargo.lock new file mode 100644 index 00000000000000..fc56ed7001d256 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/deps/crates/vendor/target-lexicon/Cargo.toml b/deps/crates/vendor/target-lexicon/Cargo.toml new file mode 100644 index 00000000000000..3223d5f0478643 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/Cargo.toml @@ -0,0 +1,71 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "target-lexicon" +version = "0.13.5" +authors = ["Dan Gohman "] +build = "build.rs" +include = [ + "Cargo.toml", + "README.md", + "LICENSE", + "build.rs", + "src/**/*.rs", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "LLVM target triple types" +documentation = "https://docs.rs/target-lexicon/" +readme = "README.md" +keywords = [ + "target", + "host", + "triple", + "compiler", + "jit", +] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/target-lexicon" + +[badges.maintenance] +status = "passively-maintained" + +[features] +arch_z80 = [] +arch_zkasm = [] +default = [] +serde_support = [ + "serde", + "std", +] +std = [] + +[lib] +name = "target_lexicon" +path = "src/lib.rs" + +[dependencies.serde] +version = "1.0" +optional = true + +[dev-dependencies.serde_json] +version = "1.0" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ['cfg(feature, values("rust_1_40", "cargo-clippy"))'] diff --git a/deps/crates/vendor/target-lexicon/Cargo.toml.orig b/deps/crates/vendor/target-lexicon/Cargo.toml.orig new file mode 100644 index 00000000000000..9726763ca8fe49 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/Cargo.toml.orig @@ -0,0 +1,34 @@ +[package] +name = "target-lexicon" +version = "0.13.5" +authors = ["Dan Gohman "] +description = "LLVM target triple types" +documentation = "https://docs.rs/target-lexicon/" +readme = "README.md" +keywords = ["target", "host", "triple", "compiler", "jit"] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/target-lexicon" +edition = "2018" +include = ["Cargo.toml", "README.md", "LICENSE", "build.rs", "src/**/*.rs"] + +[dependencies] +serde = { version = "1.0", optional = true } + +[dev-dependencies] +serde_json = "1.0" + +[features] +default = [] +serde_support = ["serde", "std"] +std = [] +# Enable (unstable) support for the zkasm architecture. +arch_zkasm = [] +# Enable (unstable) support for the z80 architecture. +arch_z80 = [] + +[badges] +maintenance = { status = "passively-maintained" } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("rust_1_40", "cargo-clippy"))'] } diff --git a/deps/crates/vendor/target-lexicon/LICENSE b/deps/crates/vendor/target-lexicon/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/target-lexicon/README.md b/deps/crates/vendor/target-lexicon/README.md new file mode 100644 index 00000000000000..0ecdb597a20fce --- /dev/null +++ b/deps/crates/vendor/target-lexicon/README.md @@ -0,0 +1,24 @@ +This is a library for managing targets for compilers and related tools. + +Currently, the main feature is support for decoding [LLVM "triples"], which +are strings that identify a particular target configuration. They're named +"triples" because historically they contained three fields, though over time +they've added additional fields. This library provides a `Triple` struct +containing enums for each of fields of a triple. `Triple` implements +`FromStr` and `fmt::Display` so it can be converted to and from the +conventional string representation of a triple. + +`Triple` also has functions for querying a triple's endianness, +pointer bit width, and binary format. + +And, `Triple` and the enum types have `host()` constructors, for targeting +the host. + +It somewhat supports reading triples currently used by `rustc` and rustup, +though beware that the mapping between `rustc` and LLVM triples is not +one-to-one. + +It does not support reading JSON target files itself. To use it with a JSON +target file, construct a `Triple` using the value of the "llvm-target" field. + +[LLVM "triples"]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple diff --git a/deps/crates/vendor/target-lexicon/build.rs b/deps/crates/vendor/target-lexicon/build.rs new file mode 100644 index 00000000000000..3375d89affd937 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/build.rs @@ -0,0 +1,179 @@ +//! build.rs file to obtain the host information. + +// Allow dead code in triple.rs and targets.rs for our purposes here. +#![allow(dead_code)] + +use std::env; +use std::fs::File; +use std::io::{self, Write}; +use std::path::PathBuf; +use std::process::Command; +use std::str::FromStr; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std as alloc; + +// Include triple.rs and targets.rs so we can parse the TARGET environment variable. +// targets.rs depends on data_model +mod data_model { + include!("src/data_model.rs"); +} +mod triple { + include!("src/triple.rs"); +} +mod targets { + include!("src/targets.rs"); +} + +// Stub out `ParseError` to minimally support triple.rs and targets.rs. +mod parse_error { + #[derive(Debug)] + pub enum ParseError { + UnrecognizedArchitecture(String), + UnrecognizedVendor(String), + UnrecognizedOperatingSystem(String), + UnrecognizedEnvironment(String), + UnrecognizedBinaryFormat(String), + UnrecognizedField(String), + } +} + +use self::targets::Vendor; +use self::triple::Triple; + +fn main() { + let out_dir = PathBuf::from( + env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"), + ); + let target = env::var("TARGET").expect("The TARGET environment variable must be set"); + let triple = + Triple::from_str(&target).unwrap_or_else(|_| panic!("Invalid target name: '{}'", target)); + let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs"); + write_host_rs(out, triple).expect("error writing host.rs"); + if using_1_40() { + println!("cargo:rustc-cfg=feature=\"rust_1_40\""); + } +} + +fn using_1_40() -> bool { + match (|| { + let rustc = env::var_os("RUSTC").unwrap(); + let output = Command::new(rustc).arg("--version").output().ok()?; + let stdout = if output.status.success() { + output.stdout + } else { + return None; + }; + std::str::from_utf8(&stdout) + .ok()? + .split(' ') + .nth(1)? + .split('.') + .nth(1)? + .parse::() + .ok() + })() { + Some(version) => version >= 40, + None => true, // assume we're using an up-to-date compiler + } +} + +fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { + // The generated Debug implementation for the inner architecture variants + // doesn't print the enum name qualifier, so import them here. There + // shouldn't be any conflicts because these enums all share a namespace + // in the triple string format. + writeln!( + out, + r#" +#[allow(unused_imports)] +use crate::Aarch64Architecture::*; +#[allow(unused_imports)] +use crate::ArmArchitecture::*; +#[allow(unused_imports)] +use crate::CustomVendor; +#[allow(unused_imports)] +use crate::Mips32Architecture::*; +#[allow(unused_imports)] +use crate::Mips64Architecture::*; +#[allow(unused_imports)] +use crate::Riscv32Architecture::*; +#[allow(unused_imports)] +use crate::Riscv64Architecture::*; +#[allow(unused_imports)] +use crate::X86_32Architecture::*; + +/// The `Triple` of the current host. +pub const HOST: Triple = Triple {{ + architecture: Architecture::{architecture:?}, + vendor: Vendor::{vendor}, + operating_system: OperatingSystem::{operating_system:?}, + environment: Environment::{environment:?}, + binary_format: BinaryFormat::{binary_format:?}, +}}; + +impl Architecture {{ + /// Return the architecture for the current host. + pub const fn host() -> Self {{ + Architecture::{architecture:?} + }} +}} + +impl Vendor {{ + /// Return the vendor for the current host. + pub const fn host() -> Self {{ + Vendor::{vendor} + }} +}} + +impl OperatingSystem {{ + /// Return the operating system for the current host. + pub const fn host() -> Self {{ + OperatingSystem::{operating_system:?} + }} +}} + +impl Environment {{ + /// Return the environment for the current host. + pub const fn host() -> Self {{ + Environment::{environment:?} + }} +}} + +impl BinaryFormat {{ + /// Return the binary format for the current host. + pub const fn host() -> Self {{ + BinaryFormat::{binary_format:?} + }} +}} + +impl Triple {{ + /// Return the triple for the current host. + pub const fn host() -> Self {{ + Self {{ + architecture: Architecture::{architecture:?}, + vendor: Vendor::{vendor}, + operating_system: OperatingSystem::{operating_system:?}, + environment: Environment::{environment:?}, + binary_format: BinaryFormat::{binary_format:?}, + }} + }} +}}"#, + architecture = triple.architecture, + vendor = vendor_display(&triple.vendor), + operating_system = triple.operating_system, + environment = triple.environment, + binary_format = triple.binary_format, + )?; + + Ok(()) +} + +fn vendor_display(vendor: &Vendor) -> String { + match vendor { + Vendor::Custom(custom) => format!("Custom(CustomVendor::Static({:?}))", custom.as_str()), + known => format!("{:?}", known), + } +} diff --git a/deps/crates/vendor/target-lexicon/src/data_model.rs b/deps/crates/vendor/target-lexicon/src/data_model.rs new file mode 100644 index 00000000000000..0954add85a0d4f --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/data_model.rs @@ -0,0 +1,120 @@ +/// The size of a type. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Size { + U8, + U16, + U32, + U64, +} + +impl Size { + /// Return the number of bits this `Size` represents. + pub fn bits(self) -> u8 { + use Size::*; + + match self { + U8 => 8, + U16 => 16, + U32 => 32, + U64 => 64, + } + } + + /// Return the number of bytes in a size. + /// + /// A byte is assumed to be 8 bits. + pub fn bytes(self) -> u8 { + use Size::*; + + match self { + U8 => 1, + U16 => 2, + U32 => 4, + U64 => 8, + } + } +} + +/// The C data model used on a target. +/// +/// See also https://en.cppreference.com/w/c/language/arithmetic_types +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +pub enum CDataModel { + /// The data model used most commonly on Win16. `long` and `pointer` are 32 bits. + LP32, + /// The data model used most commonly on Win32 and 32-bit Unix systems. + /// + /// `int`, `long`, and `pointer` are all 32 bits. + ILP32, + /// The data model used most commonly on Win64 + /// + /// `long long`, and `pointer` are 64 bits. + LLP64, + /// The data model used most commonly on 64-bit Unix systems + /// + /// `long`, and `pointer` are 64 bits. + LP64, + /// A rare data model used on early 64-bit Unix systems + /// + /// `int`, `long`, and `pointer` are all 64 bits. + ILP64, +} + +impl CDataModel { + /// The width of a pointer (in the default address space). + pub fn pointer_width(self) -> Size { + use CDataModel::*; + + match self { + LP32 | ILP32 => Size::U32, + LLP64 | LP64 | ILP64 => Size::U64, + } + } + /// The size of a C `short`. This is required to be at least 16 bits. + pub fn short_size(self) -> Size { + use CDataModel::*; + + match self { + LP32 | ILP32 | LLP64 | LP64 | ILP64 => Size::U16, + } + } + /// The size of a C `int`. This is required to be at least 16 bits. + pub fn int_size(self) -> Size { + use CDataModel::*; + + match self { + LP32 => Size::U16, + ILP32 | LLP64 | LP64 => Size::U32, + ILP64 => Size::U64, + } + } + /// The size of a C `long`. This is required to be at least 32 bits. + pub fn long_size(self) -> Size { + use CDataModel::*; + + match self { + LP32 | ILP32 | LLP64 => Size::U32, + LP64 | ILP64 => Size::U64, + } + } + /// The size of a C `long long`. This is required (in C99+) to be at least 64 bits. + pub fn long_long_size(self) -> Size { + use CDataModel::*; + + match self { + LP32 | ILP32 | LLP64 | ILP64 | LP64 => Size::U64, + } + } + /// The size of a C `float`. + pub fn float_size(self) -> Size { + // TODO: this is probably wrong on at least one architecture + Size::U32 + } + /// The size of a C `double`. + pub fn double_size(self) -> Size { + // TODO: this is probably wrong on at least one architecture + Size::U64 + } +} diff --git a/deps/crates/vendor/target-lexicon/src/host.rs b/deps/crates/vendor/target-lexicon/src/host.rs new file mode 100644 index 00000000000000..976ef1d75fcb2a --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/host.rs @@ -0,0 +1,70 @@ +use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; + +// Include the implementations of the `HOST` object containing information +// about the current host. +include!(concat!(env!("OUT_DIR"), "/host.rs")); + +#[cfg(test)] +mod tests { + #[cfg(target_os = "aix")] + #[test] + fn test_aix() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Aix); + } + + #[cfg(target_os = "cygwin")] + #[test] + fn test_cygwin() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Cygwin); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_linux() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Linux); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_macos() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Darwin(None)); + } + + #[cfg(windows)] + #[test] + fn test_windows() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Windows); + } + + #[cfg(target_pointer_width = "16")] + #[test] + fn test_ptr16() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 16); + } + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_ptr32() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 32); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_ptr64() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 64); + } + + #[test] + fn host_object() { + use super::*; + assert_eq!(HOST, Triple::host()); + } +} diff --git a/deps/crates/vendor/target-lexicon/src/lib.rs b/deps/crates/vendor/target-lexicon/src/lib.rs new file mode 100644 index 00000000000000..2cb1c58d650eec --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/lib.rs @@ -0,0 +1,109 @@ +//! LLVM target triple types. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![warn(unused_import_braces)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self, + ) +)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std as alloc; + +mod data_model; +mod host; +mod parse_error; +mod targets; +#[macro_use] +mod triple; + +pub use self::data_model::{CDataModel, Size}; +pub use self::host::HOST; +pub use self::parse_error::ParseError; +pub use self::targets::{ + Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, CleverArchitecture, + CustomVendor, DeploymentTarget, Environment, Mips32Architecture, Mips64Architecture, + OperatingSystem, Riscv32Architecture, Riscv64Architecture, Vendor, X86_32Architecture, +}; +pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; + +/// A simple wrapper around `Triple` that provides an implementation of +/// `Default` which defaults to `Triple::host()`. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DefaultToHost(pub Triple); + +impl Default for DefaultToHost { + fn default() -> Self { + Self(Triple::host()) + } +} + +/// A simple wrapper around `Triple` that provides an implementation of +/// `Default` which defaults to `Triple::unknown()`. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DefaultToUnknown(pub Triple); + +impl Default for DefaultToUnknown { + fn default() -> Self { + Self(Triple::unknown()) + } +} + +// For some reason, the below `serde` impls don't work when they're in the +// `triple` module. + +#[cfg(feature = "serde_support")] +impl serde::Serialize for Triple { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.to_string()) + } +} + +#[cfg(feature = "serde_support")] +impl<'de> serde::de::Deserialize<'de> for Triple { + fn deserialize>(deserializer: D) -> Result { + let s = String::deserialize(deserializer)?; + s.parse().map_err(serde::de::Error::custom) + } +} + +#[cfg(feature = "serde_support")] +#[test] +fn test_serialize() { + let triples: Vec = vec![ + "x86_64-unknown-linux-gnu".parse().unwrap(), + "i686-pc-windows-gnu".parse().unwrap(), + ]; + + let json = serde_json::to_string(&triples).unwrap(); + assert_eq!( + json, + r#"["x86_64-unknown-linux-gnu","i686-pc-windows-gnu"]"# + ); +} + +#[cfg(feature = "serde_support")] +#[test] +fn test_deserialize() { + let triples: Vec = vec![ + "x86_64-unknown-linux-gnu".parse().unwrap(), + "i686-pc-windows-gnu".parse().unwrap(), + ]; + + let vals: Vec = + serde_json::from_str(r#"["x86_64-unknown-linux-gnu","i686-pc-windows-gnu"]"#).unwrap(); + + assert_eq!(vals, triples); +} diff --git a/deps/crates/vendor/target-lexicon/src/parse_error.rs b/deps/crates/vendor/target-lexicon/src/parse_error.rs new file mode 100644 index 00000000000000..03ca4aedb9ee22 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/parse_error.rs @@ -0,0 +1,34 @@ +use alloc::string::String; + +use core::fmt; + +/// An error returned from parsing a triple. +#[derive(Clone, Debug, PartialEq, Eq)] +#[allow(missing_docs)] +pub enum ParseError { + UnrecognizedArchitecture(String), + UnrecognizedVendor(String), + UnrecognizedOperatingSystem(String), + UnrecognizedEnvironment(String), + UnrecognizedBinaryFormat(String), + UnrecognizedField(String), +} + +impl fmt::Display for ParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use ParseError::*; + match self { + UnrecognizedArchitecture(msg) => write!(fmt, "Unrecognized architecture: {}", msg), + UnrecognizedVendor(msg) => write!(fmt, "Unrecognized vendor: {}", msg), + UnrecognizedOperatingSystem(msg) => { + write!(fmt, "Unrecognized operating system: {}", msg) + } + UnrecognizedEnvironment(msg) => write!(fmt, "Unrecognized environment: {}", msg), + UnrecognizedBinaryFormat(msg) => write!(fmt, "Unrecognized binary format: {}", msg), + UnrecognizedField(msg) => write!(fmt, "Unrecognized field: {}", msg), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseError {} diff --git a/deps/crates/vendor/target-lexicon/src/targets.rs b/deps/crates/vendor/target-lexicon/src/targets.rs new file mode 100644 index 00000000000000..c908269c37d099 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/targets.rs @@ -0,0 +1,2215 @@ +// This file defines all the identifier enums and target-aware logic. + +use crate::triple::{Endianness, PointerWidth, Triple}; +use alloc::borrow::Cow; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::String; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::str::FromStr; + +/// The "architecture" field, which in some cases also specifies a specific +/// subarchitecture. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Architecture { + Unknown, + Arm(ArmArchitecture), + AmdGcn, + Aarch64(Aarch64Architecture), + Asmjs, + Avr, + Bpfeb, + Bpfel, + Hexagon, + X86_32(X86_32Architecture), + M68k, + LoongArch64, + Mips32(Mips32Architecture), + Mips64(Mips64Architecture), + Msp430, + Nvptx64, + Pulley32, + Pulley64, + Pulley32be, + Pulley64be, + Powerpc, + Powerpc64, + Powerpc64le, + Riscv32(Riscv32Architecture), + Riscv64(Riscv64Architecture), + S390x, + Sparc, + Sparc64, + Sparcv9, + Wasm32, + Wasm64, + X86_64, + /// x86_64 target that only supports Haswell-compatible Intel chips. + X86_64h, + XTensa, + Clever(CleverArchitecture), + /// A software machine that produces zero-knowledge proofs of the execution. + /// + /// See https://wiki.polygon.technology/docs/category/zk-assembly/ + #[cfg(feature = "arch_zkasm")] + ZkAsm, + #[cfg(feature = "arch_z80")] + Z80(Z80Architecture), +} + +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum ArmArchitecture { + Arm, // Generic arm + Armeb, + Armv4, + Armv4t, + Armv5t, + Armv5te, + Armv5tej, + Armv6, + Armv6j, + Armv6k, + Armv6z, + Armv6kz, + Armv6t2, + Armv6m, + Armv7, + Armv7a, + Armv7k, + Armv7ve, + Armv7m, + Armv7r, + Armv7s, + Armv8, + Armv8a, + Armv8_1a, + Armv8_2a, + Armv8_3a, + Armv8_4a, + Armv8_5a, + Armv8mBase, + Armv8mMain, + Armv8r, + + Armebv7r, + + Thumbeb, + Thumbv4t, + Thumbv5te, + Thumbv6m, + Thumbv7a, + Thumbv7em, + Thumbv7m, + Thumbv7neon, + Thumbv8mBase, + Thumbv8mMain, +} + +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Aarch64Architecture { + Aarch64, + Aarch64be, +} + +// #[cfg_attr(feature = "rust_1_40", non_exhaustive)] +// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +// #[allow(missing_docs)] +// pub enum ArmFpu { +// Vfp, +// Vfpv2, +// Vfpv3, +// Vfpv3Fp16, +// Vfpv3Xd, +// Vfpv3XdFp16, +// Neon, +// NeonVfpv3, +// NeonVfpv4, +// Vfpv4, +// Vfpv4D16, +// Fpv4SpD16, +// Fpv5SpD16, +// Fpv5D16, +// FpArmv8, +// NeonFpArmv8, +// CryptoNeonFpArmv8, +// } + +impl ArmArchitecture { + /// Test if this architecture uses the Thumb instruction set. + #[rustfmt::skip] + pub fn is_thumb(self) -> bool { + use ArmArchitecture::*; + + match self { + Arm + | Armeb + | Armv4 + | Armv4t + | Armv5t + | Armv5te + | Armv5tej + | Armv6 + | Armv6j + | Armv6k + | Armv6z + | Armv6kz + | Armv6t2 + | Armv6m + | Armv7 + | Armv7a + | Armv7k + | Armv7ve + | Armv7m + | Armv7r + | Armv7s + | Armv8 + | Armv8a + | Armv8_1a + | Armv8_2a + | Armv8_3a + | Armv8_4a + | Armv8_5a + | Armv8mBase + | Armv8mMain + | Armv8r + | Armebv7r => false, + Thumbeb + | Thumbv4t + | Thumbv5te + | Thumbv6m + | Thumbv7a + | Thumbv7em + | Thumbv7m + | Thumbv7neon + | Thumbv8mBase + | Thumbv8mMain => true, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + #[rustfmt::skip] + pub fn pointer_width(self) -> PointerWidth { + use ArmArchitecture::*; + + match self { + Arm + | Armeb + | Armv4 + | Armv4t + | Armv5t + | Armv5te + | Armv5tej + | Armv6 + | Armv6j + | Armv6k + | Armv6z + | Armv6kz + | Armv6t2 + | Armv6m + | Armv7 + | Armv7a + | Armv7k + | Armv7ve + | Armv7m + | Armv7r + | Armv7s + | Armv8 + | Armv8a + | Armv8_1a + | Armv8_2a + | Armv8_3a + | Armv8_4a + | Armv8_5a + | Armv8mBase + | Armv8mMain + | Armv8r + | Armebv7r + | Thumbeb + | Thumbv4t + | Thumbv5te + | Thumbv6m + | Thumbv7a + | Thumbv7em + | Thumbv7m + | Thumbv7neon + | Thumbv8mBase + | Thumbv8mMain => PointerWidth::U32, + } + } + + /// Return the endianness of this architecture. + #[rustfmt::skip] + pub fn endianness(self) -> Endianness { + use ArmArchitecture::*; + + match self { + Arm + | Armv4 + | Armv4t + | Armv5t + | Armv5te + | Armv5tej + | Armv6 + | Armv6j + | Armv6k + | Armv6z + | Armv6kz + | Armv6t2 + | Armv6m + | Armv7 + | Armv7a + | Armv7k + | Armv7ve + | Armv7m + | Armv7r + | Armv7s + | Armv8 + | Armv8a + | Armv8_1a + | Armv8_2a + | Armv8_3a + | Armv8_4a + | Armv8_5a + | Armv8mBase + | Armv8mMain + | Armv8r + | Thumbv4t + | Thumbv5te + | Thumbv6m + | Thumbv7a + | Thumbv7em + | Thumbv7m + | Thumbv7neon + | Thumbv8mBase + | Thumbv8mMain => Endianness::Little, + Armeb | Armebv7r | Thumbeb => Endianness::Big, + } + } + + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use ArmArchitecture::*; + + match self { + Arm => Cow::Borrowed("arm"), + Armeb => Cow::Borrowed("armeb"), + Armv4 => Cow::Borrowed("armv4"), + Armv4t => Cow::Borrowed("armv4t"), + Armv5t => Cow::Borrowed("armv5t"), + Armv5te => Cow::Borrowed("armv5te"), + Armv5tej => Cow::Borrowed("armv5tej"), + Armv6 => Cow::Borrowed("armv6"), + Armv6j => Cow::Borrowed("armv6j"), + Armv6k => Cow::Borrowed("armv6k"), + Armv6z => Cow::Borrowed("armv6z"), + Armv6kz => Cow::Borrowed("armv6kz"), + Armv6t2 => Cow::Borrowed("armv6t2"), + Armv6m => Cow::Borrowed("armv6m"), + Armv7 => Cow::Borrowed("armv7"), + Armv7a => Cow::Borrowed("armv7a"), + Armv7k => Cow::Borrowed("armv7k"), + Armv7ve => Cow::Borrowed("armv7ve"), + Armv7m => Cow::Borrowed("armv7m"), + Armv7r => Cow::Borrowed("armv7r"), + Armv7s => Cow::Borrowed("armv7s"), + Armv8 => Cow::Borrowed("armv8"), + Armv8a => Cow::Borrowed("armv8a"), + Armv8_1a => Cow::Borrowed("armv8.1a"), + Armv8_2a => Cow::Borrowed("armv8.2a"), + Armv8_3a => Cow::Borrowed("armv8.3a"), + Armv8_4a => Cow::Borrowed("armv8.4a"), + Armv8_5a => Cow::Borrowed("armv8.5a"), + Armv8mBase => Cow::Borrowed("armv8m.base"), + Armv8mMain => Cow::Borrowed("armv8m.main"), + Armv8r => Cow::Borrowed("armv8r"), + Thumbeb => Cow::Borrowed("thumbeb"), + Thumbv4t => Cow::Borrowed("thumbv4t"), + Thumbv5te => Cow::Borrowed("thumbv5te"), + Thumbv6m => Cow::Borrowed("thumbv6m"), + Thumbv7a => Cow::Borrowed("thumbv7a"), + Thumbv7em => Cow::Borrowed("thumbv7em"), + Thumbv7m => Cow::Borrowed("thumbv7m"), + Thumbv7neon => Cow::Borrowed("thumbv7neon"), + Thumbv8mBase => Cow::Borrowed("thumbv8m.base"), + Thumbv8mMain => Cow::Borrowed("thumbv8m.main"), + Armebv7r => Cow::Borrowed("armebv7r"), + } + } +} + +impl Aarch64Architecture { + /// Test if this architecture uses the Thumb instruction set. + pub fn is_thumb(self) -> bool { + match self { + Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => false, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + /// + /// This function is only aware of the CPU architecture so it is not aware + /// of ilp32 ABIs. + pub fn pointer_width(self) -> PointerWidth { + match self { + Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => PointerWidth::U64, + } + } + + /// Return the endianness of this architecture. + pub fn endianness(self) -> Endianness { + match self { + Aarch64Architecture::Aarch64 => Endianness::Little, + Aarch64Architecture::Aarch64be => Endianness::Big, + } + } + + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Aarch64Architecture::*; + + match self { + Aarch64 => Cow::Borrowed("aarch64"), + Aarch64be => Cow::Borrowed("aarch64_be"), + } + } +} + +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum CleverArchitecture { + Clever, + Clever1_0, +} + +impl CleverArchitecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use CleverArchitecture::*; + + match self { + Clever => Cow::Borrowed("clever"), + Clever1_0 => Cow::Borrowed("clever1.0"), + } + } +} + +/// An enum for all 32-bit RISC-V architectures. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Riscv32Architecture { + Riscv32, + Riscv32gc, + Riscv32i, + Riscv32im, + Riscv32ima, + Riscv32imac, + Riscv32imafc, + Riscv32imc, +} + +impl Riscv32Architecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Riscv32Architecture::*; + + match self { + Riscv32 => Cow::Borrowed("riscv32"), + Riscv32gc => Cow::Borrowed("riscv32gc"), + Riscv32i => Cow::Borrowed("riscv32i"), + Riscv32im => Cow::Borrowed("riscv32im"), + Riscv32ima => Cow::Borrowed("riscv32ima"), + Riscv32imac => Cow::Borrowed("riscv32imac"), + Riscv32imafc => Cow::Borrowed("riscv32imafc"), + Riscv32imc => Cow::Borrowed("riscv32imc"), + } + } +} + +/// An enum for all 64-bit RISC-V architectures. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Riscv64Architecture { + Riscv64, + Riscv64gc, + Riscv64imac, + Riscv64a23, +} + +impl Riscv64Architecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Riscv64Architecture::*; + + match self { + Riscv64 => Cow::Borrowed("riscv64"), + Riscv64gc => Cow::Borrowed("riscv64gc"), + Riscv64imac => Cow::Borrowed("riscv64imac"), + Riscv64a23 => Cow::Borrowed("riscv64a23"), + } + } +} + +/// An enum for all 32-bit x86 architectures. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum X86_32Architecture { + I386, + I586, + I686, +} + +impl X86_32Architecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use X86_32Architecture::*; + + match self { + I386 => Cow::Borrowed("i386"), + I586 => Cow::Borrowed("i586"), + I686 => Cow::Borrowed("i686"), + } + } +} + +/// An enum for all 32-bit MIPS architectures (not just "MIPS32"). +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Mips32Architecture { + Mips, + Mipsel, + Mipsisa32r6, + Mipsisa32r6el, +} + +impl Mips32Architecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Mips32Architecture::*; + + match self { + Mips => Cow::Borrowed("mips"), + Mipsel => Cow::Borrowed("mipsel"), + Mipsisa32r6 => Cow::Borrowed("mipsisa32r6"), + Mipsisa32r6el => Cow::Borrowed("mipsisa32r6el"), + } + } +} + +/// An enum for all 64-bit MIPS architectures (not just "MIPS64"). +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Mips64Architecture { + Mips64, + Mips64el, + Mipsisa64r6, + Mipsisa64r6el, +} + +impl Mips64Architecture { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Mips64Architecture::*; + + match self { + Mips64 => Cow::Borrowed("mips64"), + Mips64el => Cow::Borrowed("mips64el"), + Mipsisa64r6 => Cow::Borrowed("mipsisa64r6"), + Mipsisa64r6el => Cow::Borrowed("mipsisa64r6el"), + } + } +} + +#[cfg(feature = "arch_z80")] +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Z80Architecture { + Z80, + Z180, + Ez80, + Sm83, + Rabbit2000, + Rabbit2000A, + Rabbit3000, + Rabbit3000A, + Tlcs90, + R800, +} + +#[cfg(feature = "arch_z80")] +impl Z80Architecture { + pub fn into_str(self) -> Cow<'static, str> { + use Z80Architecture::*; + + match self { + Z80 => Cow::Borrowed("z80"), + Z180 => Cow::Borrowed("z180"), + Ez80 => Cow::Borrowed("ez80"), + Sm83 => Cow::Borrowed("sm83"), + Rabbit2000 => Cow::Borrowed("rabbit2000"), + Rabbit2000A => Cow::Borrowed("rabbit2000a"), + Rabbit3000 => Cow::Borrowed("rabbit3000"), + Rabbit3000A => Cow::Borrowed("rabbit3000a"), + Tlcs90 => Cow::Borrowed("tlcs90"), + R800 => Cow::Borrowed("r800"), + } + } +} + +/// A string for a `Vendor::Custom` that can either be used in `const` +/// contexts or hold dynamic strings. +#[derive(Clone, Debug, Eq)] +pub enum CustomVendor { + /// An owned `String`. This supports the general case. + Owned(Box), + /// A static `str`, so that `CustomVendor` can be constructed in `const` + /// contexts. + Static(&'static str), +} + +impl CustomVendor { + /// Extracts a string slice. + pub fn as_str(&self) -> &str { + match self { + CustomVendor::Owned(s) => s, + CustomVendor::Static(s) => s, + } + } +} + +impl PartialEq for CustomVendor { + fn eq(&self, other: &Self) -> bool { + self.as_str() == other.as_str() + } +} + +impl Hash for CustomVendor { + fn hash(&self, state: &mut H) { + self.as_str().hash(state) + } +} + +/// The "vendor" field, which in practice is little more than an arbitrary +/// modifier. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Vendor { + Unknown, + Amd, + Apple, + Espressif, + Experimental, + Fortanix, + Ibm, + Kmc, + Nintendo, + Nvidia, + Pc, + Rumprun, + Sun, + Uwp, + Wrs, + + /// A custom vendor. "Custom" in this context means that the vendor is + /// not specifically recognized by upstream Autotools, LLVM, Rust, or other + /// relevant authorities on triple naming. It's useful for people building + /// and using locally patched toolchains. + /// + /// Outside of such patched environments, users of `target-lexicon` should + /// treat `Custom` the same as `Unknown` and ignore the string. + Custom(CustomVendor), +} + +impl Vendor { + /// Extracts a string slice. + pub fn as_str(&self) -> &str { + use Vendor::*; + + match self { + Unknown => "unknown", + Amd => "amd", + Apple => "apple", + Espressif => "espressif", + Experimental => "experimental", + Fortanix => "fortanix", + Ibm => "ibm", + Kmc => "kmc", + Nintendo => "nintendo", + Nvidia => "nvidia", + Pc => "pc", + Rumprun => "rumprun", + Sun => "sun", + Uwp => "uwp", + Wrs => "wrs", + Custom(name) => name.as_str(), + } + } +} + +/// The minimum OS version that we're compiling for. +/// +/// This is formatted as `"major.minor.patch"`. +/// +/// The size of the parts here are limited by Mach-O's `LC_BUILD_VERSION`. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[allow(missing_docs)] +pub struct DeploymentTarget { + pub major: u16, + pub minor: u8, + pub patch: u8, +} + +/// The "operating system" field, which sometimes implies an environment, and +/// sometimes isn't an actual operating system. +/// +/// LLVM's Apple triples may optionally include the [deployment target]. +/// +/// [deployment target]: DeploymentTarget +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum OperatingSystem { + Unknown, + Aix, + AmdHsa, + Bitrig, + Cloudabi, + Cuda, + Cygwin, + /// The general [Darwin][darwin-wiki] core OS. + /// + /// Generally, `-mmacosx-version-min=...` or similar flags are required by + /// Clang to determine the actual OS (either macOS, iOS, tvOS, watchOS or + /// visionOS). + /// + /// WARNING: When parsing `rustc` target triples, this matches the macOS + /// target triples as well. + /// + /// [darwin-wiki]: https://en.wikipedia.org/wiki/Darwin_(operating_system) + Darwin(Option), + Dragonfly, + Emscripten, + Espidf, + Freebsd, + Fuchsia, + Haiku, + Hermit, + Horizon, + Hurd, + Illumos, + IOS(Option), + L4re, + Linux, + /// macOS. + /// + /// WARNING: This does _not_ match the macOS triples when parsing `rustc` + /// target triples, for that see the [`darwin`](Self::Darwin) OS name. + MacOSX(Option), + Nebulet, + Netbsd, + None_, + Openbsd, + Psp, + Redox, + Solaris, + SolidAsp3, + TvOS(Option), + Uefi, + VisionOS(Option), + VxWorks, + Wasi, + WasiP1, + WasiP2, + WatchOS(Option), + Windows, + /// An alternate name for [visionOS][Self::VisionOS]. + XROS(Option), +} + +impl OperatingSystem { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use OperatingSystem::*; + + let darwin_version = |name, deployment_target| { + if let Some(DeploymentTarget { + major, + minor, + patch, + }) = deployment_target + { + Cow::Owned(format!("{}{}.{}.{}", name, major, minor, patch)) + } else { + Cow::Borrowed(name) + } + }; + + match self { + Unknown => Cow::Borrowed("unknown"), + Aix => Cow::Borrowed("aix"), + AmdHsa => Cow::Borrowed("amdhsa"), + Bitrig => Cow::Borrowed("bitrig"), + Cloudabi => Cow::Borrowed("cloudabi"), + Cuda => Cow::Borrowed("cuda"), + Cygwin => Cow::Borrowed("cygwin"), + Darwin(deployment_target) => darwin_version("darwin", deployment_target), + Dragonfly => Cow::Borrowed("dragonfly"), + Emscripten => Cow::Borrowed("emscripten"), + Espidf => Cow::Borrowed("espidf"), + Freebsd => Cow::Borrowed("freebsd"), + Fuchsia => Cow::Borrowed("fuchsia"), + Haiku => Cow::Borrowed("haiku"), + Hermit => Cow::Borrowed("hermit"), + Horizon => Cow::Borrowed("horizon"), + Hurd => Cow::Borrowed("hurd"), + Illumos => Cow::Borrowed("illumos"), + IOS(deployment_target) => darwin_version("ios", deployment_target), + L4re => Cow::Borrowed("l4re"), + Linux => Cow::Borrowed("linux"), + MacOSX(deployment_target) => darwin_version("macosx", deployment_target), + Nebulet => Cow::Borrowed("nebulet"), + Netbsd => Cow::Borrowed("netbsd"), + None_ => Cow::Borrowed("none"), + Openbsd => Cow::Borrowed("openbsd"), + Psp => Cow::Borrowed("psp"), + Redox => Cow::Borrowed("redox"), + Solaris => Cow::Borrowed("solaris"), + SolidAsp3 => Cow::Borrowed("solid_asp3"), + TvOS(deployment_target) => darwin_version("tvos", deployment_target), + Uefi => Cow::Borrowed("uefi"), + VxWorks => Cow::Borrowed("vxworks"), + VisionOS(deployment_target) => darwin_version("visionos", deployment_target), + Wasi => Cow::Borrowed("wasi"), + WasiP1 => Cow::Borrowed("wasip1"), + WasiP2 => Cow::Borrowed("wasip2"), + WatchOS(deployment_target) => darwin_version("watchos", deployment_target), + Windows => Cow::Borrowed("windows"), + XROS(deployment_target) => darwin_version("xros", deployment_target), + } + } + + /// Whether the OS is similar to Darwin. + /// + /// This matches on any of: + /// - [Darwin](Self::Darwin) + /// - [iOS](Self::IOS) + /// - [macOS](Self::MacOSX) + /// - [tvOS](Self::TvOS) + /// - [visionOS](Self::VisionOS) + /// - [watchOS](Self::WatchOS) + /// - [xrOS](Self::XROS) + pub fn is_like_darwin(&self) -> bool { + use OperatingSystem::*; + + match self { + Darwin(_) | IOS(_) | MacOSX(_) | TvOS(_) | VisionOS(_) | WatchOS(_) | XROS(_) => true, + _ => false, + } + } +} + +/// The "environment" field, which specifies an ABI environment on top of the +/// operating system. In many configurations, this field is omitted, and the +/// environment is implied by the operating system. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Environment { + Unknown, + AmdGiz, + Android, + Androideabi, + Eabi, + Eabihf, + Gnu, + Gnuabi64, + Gnueabi, + Gnueabihf, + Gnuspe, + Gnux32, + GnuIlp32, + GnuLlvm, + HermitKernel, + HurdKernel, + LinuxKernel, + Macabi, + Musl, + Musleabi, + Musleabihf, + Muslabi64, + Msvc, + Newlib, + None, + Kernel, + Uclibc, + Uclibceabi, + Uclibceabihf, + Sgx, + Sim, + Softfloat, + Spe, + Threads, + Ohos, +} + +impl Environment { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Environment::*; + + match self { + Unknown => Cow::Borrowed("unknown"), + AmdGiz => Cow::Borrowed("amdgiz"), + Android => Cow::Borrowed("android"), + Androideabi => Cow::Borrowed("androideabi"), + Eabi => Cow::Borrowed("eabi"), + Eabihf => Cow::Borrowed("eabihf"), + Gnu => Cow::Borrowed("gnu"), + Gnuabi64 => Cow::Borrowed("gnuabi64"), + Gnueabi => Cow::Borrowed("gnueabi"), + Gnueabihf => Cow::Borrowed("gnueabihf"), + Gnuspe => Cow::Borrowed("gnuspe"), + Gnux32 => Cow::Borrowed("gnux32"), + GnuIlp32 => Cow::Borrowed("gnu_ilp32"), + GnuLlvm => Cow::Borrowed("gnullvm"), + HermitKernel => Cow::Borrowed("hermitkernel"), + HurdKernel => Cow::Borrowed("hurdkernel"), + LinuxKernel => Cow::Borrowed("linuxkernel"), + Macabi => Cow::Borrowed("macabi"), + Musl => Cow::Borrowed("musl"), + Musleabi => Cow::Borrowed("musleabi"), + Musleabihf => Cow::Borrowed("musleabihf"), + Muslabi64 => Cow::Borrowed("muslabi64"), + Msvc => Cow::Borrowed("msvc"), + Newlib => Cow::Borrowed("newlib"), + None => Cow::Borrowed("none"), + Kernel => Cow::Borrowed("kernel"), + Uclibc => Cow::Borrowed("uclibc"), + Uclibceabi => Cow::Borrowed("uclibceabi"), + Uclibceabihf => Cow::Borrowed("uclibceabihf"), + Sgx => Cow::Borrowed("sgx"), + Sim => Cow::Borrowed("sim"), + Softfloat => Cow::Borrowed("softfloat"), + Spe => Cow::Borrowed("spe"), + Threads => Cow::Borrowed("threads"), + Ohos => Cow::Borrowed("ohos"), + } + } +} + +/// The "binary format" field, which is usually omitted, and the binary format +/// is implied by the other fields. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum BinaryFormat { + Unknown, + Elf, + Coff, + Macho, + Wasm, + Xcoff, +} + +impl BinaryFormat { + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use BinaryFormat::*; + + match self { + Unknown => Cow::Borrowed("unknown"), + Elf => Cow::Borrowed("elf"), + Coff => Cow::Borrowed("coff"), + Macho => Cow::Borrowed("macho"), + Wasm => Cow::Borrowed("wasm"), + Xcoff => Cow::Borrowed("xcoff"), + } + } +} + +impl Architecture { + /// Return the endianness of this architecture. + #[rustfmt::skip] + pub fn endianness(self) -> Result { + use Architecture::*; + + match self { + Unknown => Err(()), + Arm(arm) => Ok(arm.endianness()), + Aarch64(aarch) => Ok(aarch.endianness()), + AmdGcn + | Asmjs + | Avr + | Bpfel + | Hexagon + | X86_32(_) + | LoongArch64 + | Mips64(Mips64Architecture::Mips64el) + | Mips32(Mips32Architecture::Mipsel) + | Mips32(Mips32Architecture::Mipsisa32r6el) + | Mips64(Mips64Architecture::Mipsisa64r6el) + | Msp430 + | Nvptx64 + | Pulley32 + | Pulley64 + | Powerpc64le + | Riscv32(_) + | Riscv64(_) + | Wasm32 + | Wasm64 + | X86_64 + | X86_64h + | XTensa + | Clever(_) => Ok(Endianness::Little), + Bpfeb + | M68k + | Mips32(Mips32Architecture::Mips) + | Mips64(Mips64Architecture::Mips64) + | Mips32(Mips32Architecture::Mipsisa32r6) + | Mips64(Mips64Architecture::Mipsisa64r6) + | Powerpc + | Powerpc64 + | Pulley32be + | Pulley64be + | S390x + | Sparc + | Sparc64 + | Sparcv9 => Ok(Endianness::Big), + #[cfg(feature="arch_zkasm")] + ZkAsm => Ok(Endianness::Big), + #[cfg(feature = "arch_z80")] + Z80(_) => Ok(Endianness::Little), + } + } + + /// Return the pointer bit width of this target's architecture. + /// + /// This function is only aware of the CPU architecture so it is not aware + /// of ilp32 and x32 ABIs. + #[rustfmt::skip] + pub fn pointer_width(self) -> Result { + use Architecture::*; + + match self { + Unknown => Err(()), + Avr | Msp430 => Ok(PointerWidth::U16), + Arm(arm) => Ok(arm.pointer_width()), + Aarch64(aarch) => Ok(aarch.pointer_width()), + Asmjs + | Hexagon + | X86_32(_) + | Riscv32(_) + | Sparc + | Wasm32 + | M68k + | Mips32(_) + | Pulley32 + | Pulley32be + | Powerpc + | XTensa => Ok(PointerWidth::U32), + AmdGcn + | Bpfeb + | Bpfel + | Powerpc64le + | Riscv64(_) + | X86_64 + | X86_64h + | Mips64(_) + | Nvptx64 + | Pulley64 + | Pulley64be + | Powerpc64 + | S390x + | Sparc64 + | Sparcv9 + | LoongArch64 + | Wasm64 + | Clever(_) => Ok(PointerWidth::U64), + #[cfg(feature="arch_zkasm")] + ZkAsm => Ok(PointerWidth::U64), + #[cfg(feature = "arch_z80")] + Z80(_) => Ok(PointerWidth::U16), + } + } + + /// Checks if this Architecture is some variant of Clever-ISA + pub fn is_clever(&self) -> bool { + match self { + Architecture::Clever(_) => true, + _ => false, + } + } + + /// Convert into a string + pub fn into_str(self) -> Cow<'static, str> { + use Architecture::*; + + match self { + Arm(arm) => arm.into_str(), + Aarch64(aarch) => aarch.into_str(), + Unknown => Cow::Borrowed("unknown"), + AmdGcn => Cow::Borrowed("amdgcn"), + Asmjs => Cow::Borrowed("asmjs"), + Avr => Cow::Borrowed("avr"), + Bpfeb => Cow::Borrowed("bpfeb"), + Bpfel => Cow::Borrowed("bpfel"), + Hexagon => Cow::Borrowed("hexagon"), + X86_32(x86_32) => x86_32.into_str(), + LoongArch64 => Cow::Borrowed("loongarch64"), + M68k => Cow::Borrowed("m68k"), + Mips32(mips32) => mips32.into_str(), + Mips64(mips64) => mips64.into_str(), + Msp430 => Cow::Borrowed("msp430"), + Nvptx64 => Cow::Borrowed("nvptx64"), + Pulley32 => Cow::Borrowed("pulley32"), + Pulley64 => Cow::Borrowed("pulley64"), + Pulley32be => Cow::Borrowed("pulley32be"), + Pulley64be => Cow::Borrowed("pulley64be"), + Powerpc => Cow::Borrowed("powerpc"), + Powerpc64 => Cow::Borrowed("powerpc64"), + Powerpc64le => Cow::Borrowed("powerpc64le"), + Riscv32(riscv32) => riscv32.into_str(), + Riscv64(riscv64) => riscv64.into_str(), + S390x => Cow::Borrowed("s390x"), + Sparc => Cow::Borrowed("sparc"), + Sparc64 => Cow::Borrowed("sparc64"), + Sparcv9 => Cow::Borrowed("sparcv9"), + Wasm32 => Cow::Borrowed("wasm32"), + Wasm64 => Cow::Borrowed("wasm64"), + X86_64 => Cow::Borrowed("x86_64"), + X86_64h => Cow::Borrowed("x86_64h"), + XTensa => Cow::Borrowed("xtensa"), + Clever(ver) => ver.into_str(), + #[cfg(feature = "arch_zkasm")] + ZkAsm => Cow::Borrowed("zkasm"), + #[cfg(feature = "arch_z80")] + Z80(z80) => z80.into_str(), + } + } +} + +/// Return the binary format implied by this target triple, ignoring its +/// `binary_format` field. +pub(crate) fn default_binary_format(triple: &Triple) -> BinaryFormat { + match triple.operating_system { + OperatingSystem::None_ => match triple.environment { + Environment::Eabi | Environment::Eabihf => BinaryFormat::Elf, + _ => BinaryFormat::Unknown, + }, + OperatingSystem::Aix => BinaryFormat::Xcoff, + os if os.is_like_darwin() => BinaryFormat::Macho, + OperatingSystem::Windows => BinaryFormat::Coff, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::VxWorks + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match triple.architecture { + Architecture::Wasm32 | Architecture::Wasm64 => BinaryFormat::Wasm, + Architecture::Unknown => BinaryFormat::Unknown, + // Default to ELF, following `getDefaultFormat` in LLVM. + _ => BinaryFormat::Elf, + }, + _ => BinaryFormat::Elf, + } +} + +impl fmt::Display for ArmArchitecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Aarch64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for CleverArchitecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Riscv32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Riscv64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for X86_32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Mips32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Mips64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +#[cfg(feature = "arch_z80")] +impl fmt::Display for Z80Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl fmt::Display for Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl FromStr for ArmArchitecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use ArmArchitecture::*; + + Ok(match s { + "arm" => Arm, + "armeb" => Armeb, + "armv4" => Armv4, + "armv4t" => Armv4t, + "armv5t" => Armv5t, + "armv5te" => Armv5te, + "armv5tej" => Armv5tej, + "armv6" => Armv6, + "armv6j" => Armv6j, + "armv6k" => Armv6k, + "armv6z" => Armv6z, + "armv6kz" => Armv6kz, + "armv6t2" => Armv6t2, + "armv6m" => Armv6m, + "armv7" => Armv7, + "armv7a" => Armv7a, + "armv7k" => Armv7k, + "armv7ve" => Armv7ve, + "armv7m" => Armv7m, + "armv7r" => Armv7r, + "armv7s" => Armv7s, + "armv8" => Armv8, + "armv8a" => Armv8a, + "armv8.1a" => Armv8_1a, + "armv8.2a" => Armv8_2a, + "armv8.3a" => Armv8_3a, + "armv8.4a" => Armv8_4a, + "armv8.5a" => Armv8_5a, + "armv8m.base" => Armv8mBase, + "armv8m.main" => Armv8mMain, + "armv8r" => Armv8r, + "thumbeb" => Thumbeb, + "thumbv4t" => Thumbv4t, + "thumbv5te" => Thumbv5te, + "thumbv6m" => Thumbv6m, + "thumbv7a" => Thumbv7a, + "thumbv7em" => Thumbv7em, + "thumbv7m" => Thumbv7m, + "thumbv7neon" => Thumbv7neon, + "thumbv8m.base" => Thumbv8mBase, + "thumbv8m.main" => Thumbv8mMain, + "armebv7r" => Armebv7r, + _ => return Err(()), + }) + } +} + +impl FromStr for Aarch64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Aarch64Architecture::*; + + Ok(match s { + "aarch64" => Aarch64, + "arm64" => Aarch64, + "aarch64_be" => Aarch64be, + _ => return Err(()), + }) + } +} + +impl FromStr for CleverArchitecture { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "clever" => Ok(CleverArchitecture::Clever), + "clever1.0" => Ok(CleverArchitecture::Clever1_0), + _ => Err(()), + } + } +} + +impl FromStr for Riscv32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Riscv32Architecture::*; + + Ok(match s { + "riscv32" => Riscv32, + "riscv32gc" => Riscv32gc, + "riscv32i" => Riscv32i, + "riscv32im" => Riscv32im, + "riscv32ima" => Riscv32ima, + "riscv32imac" => Riscv32imac, + "riscv32imafc" => Riscv32imafc, + "riscv32imc" => Riscv32imc, + _ => return Err(()), + }) + } +} + +impl FromStr for Riscv64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Riscv64Architecture::*; + + Ok(match s { + "riscv64" => Riscv64, + "riscv64gc" => Riscv64gc, + "riscv64imac" => Riscv64imac, + "riscv64a23" => Riscv64a23, + _ => return Err(()), + }) + } +} + +impl FromStr for X86_32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use X86_32Architecture::*; + + Ok(match s { + "i386" => I386, + "i586" => I586, + "i686" => I686, + _ => return Err(()), + }) + } +} + +impl FromStr for Mips32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Mips32Architecture::*; + + Ok(match s { + "mips" => Mips, + "mipsel" => Mipsel, + "mipsisa32r6" => Mipsisa32r6, + "mipsisa32r6el" => Mipsisa32r6el, + _ => return Err(()), + }) + } +} + +impl FromStr for Mips64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Mips64Architecture::*; + + Ok(match s { + "mips64" => Mips64, + "mips64el" => Mips64el, + "mipsisa64r6" => Mipsisa64r6, + "mipsisa64r6el" => Mipsisa64r6el, + _ => return Err(()), + }) + } +} + +#[cfg(feature = "arch_z80")] +impl FromStr for Z80Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Z80Architecture::*; + + Ok(match s { + "z80" => Z80, + "z180" => Z180, + "ez80" => Ez80, + "sm83" => Sm83, + "rabbit2000" => Rabbit2000, + "rabbit2000a" => Rabbit2000A, + "rabbit3000" => Rabbit3000, + "rabbit3000a" => Rabbit3000A, + "tlcs90" => Tlcs90, + "r800" => R800, + _ => return Err(()), + }) + } +} + +impl FromStr for Architecture { + type Err = (); + + fn from_str(s: &str) -> Result { + use Architecture::*; + + Ok(match s { + "unknown" => Unknown, + "amdgcn" => AmdGcn, + "asmjs" => Asmjs, + "avr" => Avr, + "bpfeb" => Bpfeb, + "bpfel" => Bpfel, + "hexagon" => Hexagon, + "loongarch64" => LoongArch64, + "m68k" => M68k, + "msp430" => Msp430, + "nvptx64" => Nvptx64, + "pulley32" => Pulley32, + "pulley64" => Pulley64, + "pulley32be" => Pulley32be, + "pulley64be" => Pulley64be, + "powerpc" => Powerpc, + "powerpc64" => Powerpc64, + "powerpc64le" => Powerpc64le, + "s390x" => S390x, + "sparc" => Sparc, + "sparc64" => Sparc64, + "sparcv9" => Sparcv9, + "wasm32" => Wasm32, + "wasm64" => Wasm64, + "x86_64" => X86_64, + "x86_64h" => X86_64h, + "xtensa" => XTensa, + #[cfg(feature = "arch_zkasm")] + "zkasm" => ZkAsm, + _ => { + if let Ok(arm) = ArmArchitecture::from_str(s) { + Arm(arm) + } else if let Ok(aarch64) = Aarch64Architecture::from_str(s) { + Aarch64(aarch64) + } else if let Ok(riscv32) = Riscv32Architecture::from_str(s) { + Riscv32(riscv32) + } else if let Ok(riscv64) = Riscv64Architecture::from_str(s) { + Riscv64(riscv64) + } else if let Ok(x86_32) = X86_32Architecture::from_str(s) { + X86_32(x86_32) + } else if let Ok(mips32) = Mips32Architecture::from_str(s) { + Mips32(mips32) + } else if let Ok(mips64) = Mips64Architecture::from_str(s) { + Mips64(mips64) + } else if let Ok(clever) = CleverArchitecture::from_str(s) { + Clever(clever) + } else { + #[cfg(feature = "arch_z80")] + { + if let Ok(z80) = Z80Architecture::from_str(s) { + return Ok(Architecture::Z80(z80)); + } + } + return Err(()); + } + } + }) + } +} + +impl fmt::Display for Vendor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl FromStr for Vendor { + type Err = (); + + fn from_str(s: &str) -> Result { + use Vendor::*; + + Ok(match s { + "unknown" => Unknown, + "amd" => Amd, + "apple" => Apple, + "espressif" => Espressif, + "experimental" => Experimental, + "fortanix" => Fortanix, + "ibm" => Ibm, + "kmc" => Kmc, + "nintendo" => Nintendo, + "nvidia" => Nvidia, + "pc" => Pc, + "rumprun" => Rumprun, + "sun" => Sun, + "uwp" => Uwp, + "wrs" => Wrs, + custom => { + #[cfg(not(feature = "std"))] + use alloc::borrow::ToOwned; + + // A custom vendor. Since triple syntax is so loosely defined, + // be as conservative as we can to avoid potential ambiguities. + // We err on the side of being too strict here, as we can + // always relax it if needed. + + // Don't allow empty string names. + if custom.is_empty() { + return Err(()); + } + + // Don't allow any other recognized name as a custom vendor, + // since vendors can be omitted in some contexts. + if Architecture::from_str(custom).is_ok() + || OperatingSystem::from_str(custom).is_ok() + || Environment::from_str(custom).is_ok() + || BinaryFormat::from_str(custom).is_ok() + { + return Err(()); + } + + // Require the first character to be an ascii lowercase. + if !custom.chars().next().unwrap().is_ascii_lowercase() { + return Err(()); + } + + // Restrict the set of characters permitted in a custom vendor. + let has_restricted = custom.chars().any(|c: char| { + !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '.') + }); + + if has_restricted { + return Err(()); + } + + Custom(CustomVendor::Owned(Box::new(custom.to_owned()))) + } + }) + } +} + +impl fmt::Display for OperatingSystem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use OperatingSystem::*; + + let mut with_version = |name, deployment_target| { + if let Some(DeploymentTarget { + major, + minor, + patch, + }) = deployment_target + { + write!(f, "{}{}.{}.{}", name, major, minor, patch) + } else { + write!(f, "{}", name) + } + }; + + match *self { + Darwin(deployment_target) => with_version("darwin", deployment_target), + IOS(deployment_target) => with_version("ios", deployment_target), + MacOSX(deployment_target) => with_version("macosx", deployment_target), + TvOS(deployment_target) => with_version("tvos", deployment_target), + VisionOS(deployment_target) => with_version("visionos", deployment_target), + WatchOS(deployment_target) => with_version("watchos", deployment_target), + XROS(deployment_target) => with_version("xros", deployment_target), + os => f.write_str(&os.into_str()), + } + } +} + +impl FromStr for OperatingSystem { + type Err = (); + + fn from_str(s: &str) -> Result { + use OperatingSystem::*; + + let parse_darwin = |name: &str| { + let s = &s[name.len()..]; + let mut parts = s.split('.'); + + if s.is_empty() { + // Not specifying a version is allowed! + return Ok(None); + } + + let major = if let Some(part) = parts.next() { + part.parse().map_err(|_| ())? + } else { + // If the string was just `.`, with no major version, that's + // clearly an error. + return Err(()); + }; + let minor = if let Some(part) = parts.next() { + part.parse().map_err(|_| ())? + } else { + // Fall back to 0 if no minor version was set + 0 + }; + let patch = if let Some(part) = parts.next() { + part.parse().map_err(|_| ())? + } else { + // Fall back to 0 if no patch version was set + 0 + }; + + if parts.next().is_some() { + // Too many parts + return Err(()); + } + + Ok(Some(DeploymentTarget { + major, + minor, + patch, + })) + }; + + // Parse operating system names that contain a version, like `macosx10.7.0`. + if s.starts_with("darwin") { + return Ok(Darwin(parse_darwin("darwin")?)); + } + if s.starts_with("ios") { + return Ok(IOS(parse_darwin("ios")?)); + } + if s.starts_with("macosx") { + return Ok(MacOSX(parse_darwin("macosx")?)); + } + if s.starts_with("tvos") { + return Ok(TvOS(parse_darwin("tvos")?)); + } + if s.starts_with("visionos") { + return Ok(VisionOS(parse_darwin("visionos")?)); + } + if s.starts_with("watchos") { + return Ok(WatchOS(parse_darwin("watchos")?)); + } + if s.starts_with("xros") { + return Ok(XROS(parse_darwin("xros")?)); + } + + Ok(match s { + "unknown" => Unknown, + "aix" => Aix, + "amdhsa" => AmdHsa, + "bitrig" => Bitrig, + "cloudabi" => Cloudabi, + "cuda" => Cuda, + "cygwin" => Cygwin, + "dragonfly" => Dragonfly, + "emscripten" => Emscripten, + "freebsd" => Freebsd, + "fuchsia" => Fuchsia, + "haiku" => Haiku, + "hermit" => Hermit, + "horizon" => Horizon, + "hurd" => Hurd, + "illumos" => Illumos, + "l4re" => L4re, + "linux" => Linux, + "nebulet" => Nebulet, + "netbsd" => Netbsd, + "none" => None_, + "openbsd" => Openbsd, + "psp" => Psp, + "redox" => Redox, + "solaris" => Solaris, + "solid_asp3" => SolidAsp3, + "uefi" => Uefi, + "vxworks" => VxWorks, + "wasi" => Wasi, + "wasip1" => WasiP1, + "wasip2" => WasiP2, + "windows" => Windows, + "espidf" => Espidf, + _ => return Err(()), + }) + } +} + +impl fmt::Display for Environment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl FromStr for Environment { + type Err = (); + + fn from_str(s: &str) -> Result { + use Environment::*; + + Ok(match s { + "unknown" => Unknown, + "amdgiz" => AmdGiz, + "android" => Android, + "androideabi" => Androideabi, + "eabi" => Eabi, + "eabihf" => Eabihf, + "gnu" => Gnu, + "gnuabi64" => Gnuabi64, + "gnueabi" => Gnueabi, + "gnueabihf" => Gnueabihf, + "gnuspe" => Gnuspe, + "gnux32" => Gnux32, + "gnu_ilp32" => GnuIlp32, + "gnullvm" => GnuLlvm, + "hermitkernel" => HermitKernel, + "hurdkernel" => HurdKernel, + "linuxkernel" => LinuxKernel, + "macabi" => Macabi, + "musl" => Musl, + "musleabi" => Musleabi, + "musleabihf" => Musleabihf, + "muslabi64" => Muslabi64, + "msvc" => Msvc, + "newlib" => Newlib, + "none" => None, + "kernel" => Kernel, + "uclibc" => Uclibc, + "uclibceabi" => Uclibceabi, + "uclibceabihf" => Uclibceabihf, + "sgx" => Sgx, + "sim" => Sim, + "softfloat" => Softfloat, + "spe" => Spe, + "threads" => Threads, + "ohos" => Ohos, + _ => return Err(()), + }) + } +} + +impl fmt::Display for BinaryFormat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.into_str()) + } +} + +impl FromStr for BinaryFormat { + type Err = (); + + fn from_str(s: &str) -> Result { + use BinaryFormat::*; + + Ok(match s { + "unknown" => Unknown, + "elf" => Elf, + "coff" => Coff, + "macho" => Macho, + "wasm" => Wasm, + "xcoff" => Xcoff, + _ => return Err(()), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn roundtrip_known_triples() { + // This list is constructed from: + // - targets emitted by "rustup target list" + // - targets emitted by "rustc +nightly --print target-list" + // - targets contributors have added + let targets = [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-macabi", + "aarch64-apple-ios-sim", + "aarch64-apple-tvos", + "aarch64-apple-tvos-sim", + "aarch64-apple-visionos", + "aarch64-apple-visionos-sim", + "aarch64-apple-watchos", + "aarch64-apple-watchos-sim", + "aarch64_be-unknown-linux-gnu", + "aarch64_be-unknown-linux-gnu_ilp32", + "aarch64_be-unknown-netbsd", + "aarch64-kmc-solid_asp3", + "aarch64-linux-android", + //"aarch64-nintendo-switch-freestanding", // TODO + "aarch64-pc-windows-gnullvm", + "aarch64-pc-windows-msvc", + "aarch64-unknown-cloudabi", + "aarch64-unknown-freebsd", + "aarch64-unknown-fuchsia", + "aarch64-unknown-hermit", + "aarch64-unknown-illumos", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu_ilp32", + "aarch64-unknown-linux-musl", + "aarch64-unknown-linux-ohos", + "aarch64-unknown-netbsd", + "aarch64-unknown-none", + "aarch64-unknown-none-softfloat", + //"aarch64-unknown-nto-qnx710", // TODO + "aarch64-unknown-openbsd", + "aarch64-unknown-redox", + //"aarch64-unknown-teeos", // TODO + "aarch64-unknown-uefi", + "aarch64-uwp-windows-msvc", + "aarch64-wrs-vxworks", + //"arm64_32-apple-watchos", // TODO + //"arm64e-apple-darwin", // TODO + "amdgcn-amd-amdhsa", + "amdgcn-amd-amdhsa-amdgiz", + //"arm64e-apple-ios", // TODO + //"arm64ec-pc-windows-msvc", // TODO + "armeb-unknown-linux-gnueabi", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", + "arm-linux-androideabi", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "armv4t-none-eabi", + "armv4t-unknown-linux-gnueabi", + "armv5te-none-eabi", + "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv5te-unknown-linux-uclibceabi", + "armv6k-nintendo-3ds", + "armv6-unknown-freebsd", + "armv6-unknown-netbsd-eabihf", + "armv7a-kmc-solid_asp3-eabi", + "armv7a-kmc-solid_asp3-eabihf", + "armv7a-none-eabi", + "armv7a-none-eabihf", + "armv7-apple-ios", + "armv7k-apple-watchos", + "armv7-linux-androideabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "armv7s-apple-ios", + "armv7-unknown-cloudabi-eabihf", + //"armv7-sony-vita-newlibeabihf", // TODO + "armv7-unknown-freebsd", + "armv7-unknown-linux-gnueabi", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabi", + "armv7-unknown-linux-musleabihf", + "armv7-unknown-linux-ohos", + "armv7-unknown-linux-uclibceabi", + "armv7-unknown-linux-uclibceabihf", + "armv7-unknown-netbsd-eabihf", + "armv7-wrs-vxworks-eabihf", + "asmjs-unknown-emscripten", + "armv8r-none-eabihf", + //"avr-unknown-gnu-atmega328", // TODO + "avr-unknown-unknown", + "bpfeb-unknown-none", + "bpfel-unknown-none", + //"csky-unknown-linux-gnuabiv2", // TODO + //"csky-unknown-linux-gnuabiv2hf", // TODO + "hexagon-unknown-linux-musl", + "hexagon-unknown-none-elf", + "i386-apple-ios", + //"i586-pc-nto-qnx700", // TODO + "i586-pc-windows-msvc", + "i586-unknown-linux-gnu", + "i586-unknown-linux-musl", + "i586-unknown-netbsd", + "i686-apple-darwin", + "i686-linux-android", + "i686-apple-macosx10.7.0", + "i686-pc-windows-gnu", + "i686-pc-windows-gnullvm", + "i686-pc-windows-msvc", + "i686-unknown-cloudabi", + "i686-unknown-dragonfly", + "i686-unknown-freebsd", + "i686-unknown-haiku", + "i686-unknown-hurd-gnu", + "i686-unknown-linux-gnu", + "i686-unknown-linux-musl", + "i686-unknown-netbsd", + "i686-unknown-openbsd", + "i686-unknown-redox", + "i686-unknown-uefi", + "i686-uwp-windows-gnu", + "i686-uwp-windows-msvc", + "i686-win7-windows-msvc", + "i686-wrs-vxworks", + "loongarch64-unknown-linux-gnu", + "loongarch64-unknown-linux-musl", + "loongarch64-unknown-none", + "loongarch64-unknown-none-softfloat", + "m68k-unknown-linux-gnu", + "mips64el-unknown-linux-gnuabi64", + "mips64el-unknown-linux-muslabi64", + "mips64-openwrt-linux-musl", + "mips64-unknown-linux-gnuabi64", + "mips64-unknown-linux-muslabi64", + "mipsel-sony-psp", + //"mipsel-sony-psx", // TODO + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "mipsel-unknown-linux-uclibc", + "mipsel-unknown-netbsd", + "mipsel-unknown-none", + "mipsisa32r6el-unknown-linux-gnu", + "mipsisa32r6-unknown-linux-gnu", + "mipsisa64r6el-unknown-linux-gnuabi64", + "mipsisa64r6-unknown-linux-gnuabi64", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips-unknown-linux-uclibc", + "msp430-none-elf", + "nvptx64-nvidia-cuda", + "powerpc64-ibm-aix", + "powerpc64le-unknown-freebsd", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "powerpc64-unknown-freebsd", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", + "powerpc64-unknown-openbsd", + "powerpc64-wrs-vxworks", + "powerpc-ibm-aix", + "powerpc-unknown-freebsd", + "powerpc-unknown-linux-gnu", + "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-linux-musl", + "powerpc-unknown-netbsd", + "powerpc-unknown-openbsd", + "powerpc-wrs-vxworks", + "powerpc-wrs-vxworks-spe", + "riscv32gc-unknown-linux-gnu", + "riscv32gc-unknown-linux-musl", + "riscv32imac-esp-espidf", + "riscv32imac-unknown-none-elf", + //"riscv32imac-unknown-xous-elf", // TODO + "riscv32imafc-esp-espidf", + "riscv32imafc-unknown-none-elf", + "riscv32ima-unknown-none-elf", + "riscv32imc-esp-espidf", + "riscv32imc-unknown-none-elf", + //"riscv32im-risc0-zkvm-elf", // TODO + "riscv32im-unknown-none-elf", + "riscv32i-unknown-none-elf", + "riscv64gc-unknown-freebsd", + "riscv64gc-unknown-fuchsia", + "riscv64gc-unknown-hermit", + "riscv64gc-unknown-linux-gnu", + "riscv64a23-unknown-linux-gnu", + "riscv64gc-unknown-linux-musl", + "riscv64gc-unknown-netbsd", + "riscv64gc-unknown-none-elf", + "riscv64gc-unknown-openbsd", + "riscv64imac-unknown-none-elf", + "riscv64-linux-android", + "s390x-unknown-linux-gnu", + "s390x-unknown-linux-musl", + "sparc64-unknown-linux-gnu", + "sparc64-unknown-netbsd", + "sparc64-unknown-openbsd", + "sparc-unknown-linux-gnu", + "sparc-unknown-none-elf", + "sparcv9-sun-solaris", + "thumbv4t-none-eabi", + "thumbv5te-none-eabi", + "thumbv6m-none-eabi", + "thumbv7a-pc-windows-msvc", + "thumbv7a-uwp-windows-msvc", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "thumbv7neon-unknown-linux-musleabihf", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", + "wasm32-experimental-emscripten", + "wasm32-unknown-emscripten", + "wasm32-unknown-unknown", + "wasm32-wasi", + "wasm32-wasip1", + "wasm32-wasip1-threads", + "wasm32-wasip2", + "wasm64-unknown-unknown", + "wasm64-wasi", + "x86_64-apple-darwin", + "x86_64-apple-darwin23.6.0", + "x86_64-apple-ios", + "x86_64-apple-ios-macabi", + "x86_64-apple-tvos", + "x86_64-apple-watchos-sim", + "x86_64-fortanix-unknown-sgx", + "x86_64h-apple-darwin", + "x86_64-linux-android", + //"x86_64-pc-nto-qnx710", // TODO + "x86_64-linux-kernel", // Changed to x86_64-unknown-none-linuxkernel in 1.53.0 + "x86_64-apple-macosx", + "x86_64-apple-macosx10.7.0", + "x86_64-pc-cygwin", + "x86_64-pc-solaris", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-gnullvm", + "x86_64-pc-windows-msvc", + "x86_64-rumprun-netbsd", // Removed in 1.53.0 + "x86_64-sun-solaris", + "x86_64-unknown-bitrig", + "x86_64-unknown-cloudabi", + "x86_64-unikraft-linux-musl", + "x86_64-unknown-dragonfly", + "x86_64-unknown-freebsd", + "x86_64-unknown-fuchsia", + "x86_64-unknown-haiku", + "x86_64-unknown-hermit-kernel", // Changed to x86_64-unknown-none-hermitkernel in 1.53.0 + "x86_64-unknown-hermit", + "x86_64-unknown-illumos", + "x86_64-unknown-l4re-uclibc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-gnux32", + "x86_64-unknown-linux-musl", + "x86_64-unknown-linux-none", + "x86_64-unknown-linux-ohos", + "x86_64-unknown-netbsd", + "x86_64-unknown-none", + "x86_64-unknown-none-hermitkernel", + "x86_64-unknown-none-linuxkernel", + "x86_64-unknown-openbsd", + "x86_64-unknown-redox", + "x86_64-unknown-uefi", + "x86_64-uwp-windows-gnu", + "x86_64-uwp-windows-msvc", + "x86_64-win7-windows-msvc", + "x86_64-wrs-vxworks", + "xtensa-esp32-espidf", + "clever-unknown-elf", + "xtensa-esp32-none-elf", + "xtensa-esp32s2-espidf", + "xtensa-esp32s2-none-elf", + "xtensa-esp32s3-espidf", + "xtensa-esp32s3-none-elf", + #[cfg(feature = "arch_zkasm")] + "zkasm-unknown-unknown", + #[cfg(feature = "arch_z80")] + "z80-zilog-none", + #[cfg(feature = "arch_z80")] + "sm83-nintendo-none", + #[cfg(feature = "arch_z80")] + "tlcs90-toshiba-none", + ]; + + for target in targets.iter() { + let t = Triple::from_str(target).expect("can't parse target"); + assert_ne!(t.architecture, Architecture::Unknown); + assert_eq!(t.to_string(), *target, "{:#?}", t); + } + } + + #[test] + fn default_format_to_elf() { + let t = Triple::from_str("riscv64").expect("can't parse target"); + assert_eq!( + t.architecture, + Architecture::Riscv64(Riscv64Architecture::Riscv64), + ); + assert_eq!(t.vendor, Vendor::Unknown); + assert_eq!(t.operating_system, OperatingSystem::Unknown); + assert_eq!(t.environment, Environment::Unknown); + assert_eq!(t.binary_format, BinaryFormat::Elf); + } + + #[test] + fn thumbv7em_none_eabihf() { + let t = Triple::from_str("thumbv7em-none-eabihf").expect("can't parse target"); + assert_eq!( + t.architecture, + Architecture::Arm(ArmArchitecture::Thumbv7em) + ); + assert_eq!(t.vendor, Vendor::Unknown); + assert_eq!(t.operating_system, OperatingSystem::None_); + assert_eq!(t.environment, Environment::Eabihf); + assert_eq!(t.binary_format, BinaryFormat::Elf); + } + + #[test] + fn fuchsia_rename() { + // Fuchsia targets were renamed to add the `unknown`. + assert_eq!( + Triple::from_str("aarch64-fuchsia"), + Triple::from_str("aarch64-unknown-fuchsia") + ); + assert_eq!( + Triple::from_str("x86_64-fuchsia"), + Triple::from_str("x86_64-unknown-fuchsia") + ); + } + + #[test] + fn custom_vendors() { + // Test various invalid cases. + assert!(Triple::from_str("x86_64--linux").is_err()); + assert!(Triple::from_str("x86_64-42-linux").is_err()); + assert!(Triple::from_str("x86_64-__customvendor__-linux").is_err()); + assert!(Triple::from_str("x86_64-^-linux").is_err()); + assert!(Triple::from_str("x86_64- -linux").is_err()); + assert!(Triple::from_str("x86_64-CustomVendor-linux").is_err()); + assert!(Triple::from_str("x86_64-linux-linux").is_err()); + assert!(Triple::from_str("x86_64-x86_64-linux").is_err()); + assert!(Triple::from_str("x86_64-elf-linux").is_err()); + assert!(Triple::from_str("x86_64-gnu-linux").is_err()); + assert!(Triple::from_str("x86_64-linux-customvendor").is_err()); + assert!(Triple::from_str("customvendor").is_err()); + assert!(Triple::from_str("customvendor-x86_64").is_err()); + assert!(Triple::from_str("x86_64-").is_err()); + assert!(Triple::from_str("x86_64--").is_err()); + + // Test various Unicode things. + assert!( + Triple::from_str("x86_64-𝓬𝓾𝓼𝓽𝓸𝓶𝓿𝓮𝓷𝓭𝓸𝓻-linux").is_err(), + "unicode font hazard" + ); + assert!( + Triple::from_str("x86_64-ćúśtőḿvéńdőŕ-linux").is_err(), + "diacritical mark stripping hazard" + ); + assert!( + Triple::from_str("x86_64-customvendοr-linux").is_err(), + "homoglyph hazard" + ); + assert!(Triple::from_str("x86_64-customvendor-linux").is_ok()); + assert!( + Triple::from_str("x86_64-ffi-linux").is_err(), + "normalization hazard" + ); + assert!(Triple::from_str("x86_64-ffi-linux").is_ok()); + assert!( + Triple::from_str("x86_64-custom‍vendor-linux").is_err(), + "zero-width character hazard" + ); + assert!( + Triple::from_str("x86_64-customvendor-linux").is_err(), + "BOM hazard" + ); + + // Test some valid cases. + let t = Triple::from_str("x86_64-customvendor-linux") + .expect("can't parse target with custom vendor"); + assert_eq!(t.architecture, Architecture::X86_64); + assert_eq!( + t.vendor, + Vendor::Custom(CustomVendor::Static("customvendor")) + ); + assert_eq!(t.operating_system, OperatingSystem::Linux); + assert_eq!(t.environment, Environment::Unknown); + assert_eq!(t.binary_format, BinaryFormat::Elf); + assert_eq!(t.to_string(), "x86_64-customvendor-linux"); + + let t = + Triple::from_str("x86_64-customvendor").expect("can't parse target with custom vendor"); + assert_eq!(t.architecture, Architecture::X86_64); + assert_eq!( + t.vendor, + Vendor::Custom(CustomVendor::Static("customvendor")) + ); + assert_eq!(t.operating_system, OperatingSystem::Unknown); + assert_eq!(t.environment, Environment::Unknown); + assert_eq!(t.binary_format, BinaryFormat::Elf); + + assert_eq!( + Triple::from_str("unknown-foo"), + Ok(Triple { + architecture: Architecture::Unknown, + vendor: Vendor::Custom(CustomVendor::Static("foo")), + operating_system: OperatingSystem::Unknown, + environment: Environment::Unknown, + binary_format: BinaryFormat::Unknown, + }) + ); + } + + #[test] + fn deployment_version_parsing() { + assert_eq!( + Triple::from_str("aarch64-apple-macosx"), + Ok(Triple { + architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64), + vendor: Vendor::Apple, + operating_system: OperatingSystem::MacOSX(None), + environment: Environment::Unknown, + binary_format: BinaryFormat::Macho, + }) + ); + + assert_eq!( + Triple::from_str("aarch64-apple-macosx10.14.6"), + Ok(Triple { + architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64), + vendor: Vendor::Apple, + operating_system: OperatingSystem::MacOSX(Some(DeploymentTarget { + major: 10, + minor: 14, + patch: 6, + })), + environment: Environment::Unknown, + binary_format: BinaryFormat::Macho, + }) + ); + + let expected = Triple { + architecture: Architecture::X86_64, + vendor: Vendor::Apple, + operating_system: OperatingSystem::Darwin(Some(DeploymentTarget { + major: 23, + minor: 0, + patch: 0, + })), + environment: Environment::Unknown, + binary_format: BinaryFormat::Macho, + }; + assert_eq!( + Triple::from_str("x86_64-apple-darwin23"), + Ok(expected.clone()) + ); + assert_eq!( + Triple::from_str("x86_64-apple-darwin23.0"), + Ok(expected.clone()) + ); + assert_eq!(Triple::from_str("x86_64-apple-darwin23.0.0"), Ok(expected)); + + assert!(Triple::from_str("x86_64-apple-darwin.").is_err()); + assert!(Triple::from_str("x86_64-apple-darwin23.0.0.0").is_err()); + } +} diff --git a/deps/crates/vendor/target-lexicon/src/triple.rs b/deps/crates/vendor/target-lexicon/src/triple.rs new file mode 100644 index 00000000000000..d92ea67ff6de12 --- /dev/null +++ b/deps/crates/vendor/target-lexicon/src/triple.rs @@ -0,0 +1,554 @@ +// This file defines the `Triple` type and support code shared by all targets. + +use crate::data_model::CDataModel; +use crate::parse_error::ParseError; +use crate::targets::{ + default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment, + OperatingSystem, Riscv32Architecture, Vendor, +}; +#[cfg(not(feature = "std"))] +use alloc::borrow::ToOwned; +use core::fmt; +use core::str::FromStr; + +/// The target memory endianness. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Endianness { + Little, + Big, +} + +/// The width of a pointer (in the default address space). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum PointerWidth { + U16, + U32, + U64, +} + +impl PointerWidth { + /// Return the number of bits in a pointer. + pub fn bits(self) -> u8 { + match self { + PointerWidth::U16 => 16, + PointerWidth::U32 => 32, + PointerWidth::U64 => 64, + } + } + + /// Return the number of bytes in a pointer. + /// + /// For these purposes, there are 8 bits in a byte. + pub fn bytes(self) -> u8 { + match self { + PointerWidth::U16 => 2, + PointerWidth::U32 => 4, + PointerWidth::U64 => 8, + } + } +} + +/// The calling convention, which specifies things like which registers are +/// used for passing arguments, which registers are callee-saved, and so on. +#[cfg_attr(feature = "rust_1_40", non_exhaustive)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CallingConvention { + /// "System V", which is used on most Unix-like platfoms. Note that the + /// specific conventions vary between hardware architectures; for example, + /// x86-32's "System V" is entirely different from x86-64's "System V". + SystemV, + + /// The WebAssembly C ABI. + /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md + WasmBasicCAbi, + + /// "Windows Fastcall", which is used on Windows. Note that like "System V", + /// this varies between hardware architectures. On x86-32 it describes what + /// Windows documentation calls "fastcall", and on x86-64 it describes what + /// Windows documentation often just calls the Windows x64 calling convention + /// (though the compiler still recognizes "fastcall" as an alias for it). + WindowsFastcall, + + /// Apple Aarch64 platforms use their own variant of the common Aarch64 + /// calling convention. + /// + /// + AppleAarch64, +} + +/// An LLVM target "triple". Historically such things had three fields, though +/// they've added additional fields over time. +/// +/// Note that `Triple` doesn't implement `Default` itself. If you want a type +/// which defaults to the host triple, or defaults to unknown-unknown-unknown, +/// use `DefaultToHost` or `DefaultToUnknown`, respectively. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Triple { + /// The "architecture" (and sometimes the subarchitecture). + pub architecture: Architecture, + /// The "vendor" (whatever that means). + pub vendor: Vendor, + /// The "operating system" (sometimes also the environment). + pub operating_system: OperatingSystem, + /// The "environment" on top of the operating system (often omitted for + /// operating systems with a single predominant environment). + pub environment: Environment, + /// The "binary format" (rarely used). + pub binary_format: BinaryFormat, +} + +impl Triple { + /// Return the endianness of this target's architecture. + pub fn endianness(&self) -> Result { + self.architecture.endianness() + } + + /// Return the pointer width of this target's architecture. + /// + /// This function is aware of x32 and ilp32 ABIs on 64-bit architectures. + pub fn pointer_width(&self) -> Result { + // Some ABIs have a different pointer width than the CPU architecture. + match self.environment { + Environment::Gnux32 | Environment::GnuIlp32 => return Ok(PointerWidth::U32), + _ => {} + } + + self.architecture.pointer_width() + } + + /// Return the default calling convention for the given target triple. + pub fn default_calling_convention(&self) -> Result { + Ok(match self.operating_system { + os if os.is_like_darwin() => match self.architecture { + Architecture::Aarch64(_) => CallingConvention::AppleAarch64, + _ => CallingConvention::SystemV, + }, + OperatingSystem::Aix + | OperatingSystem::Bitrig + | OperatingSystem::Cloudabi + | OperatingSystem::Dragonfly + | OperatingSystem::Freebsd + | OperatingSystem::Fuchsia + | OperatingSystem::Haiku + | OperatingSystem::Hermit + | OperatingSystem::Hurd + | OperatingSystem::L4re + | OperatingSystem::Linux + | OperatingSystem::Netbsd + | OperatingSystem::Openbsd + | OperatingSystem::Redox + | OperatingSystem::Solaris => CallingConvention::SystemV, + OperatingSystem::Windows => CallingConvention::WindowsFastcall, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match self.architecture { + Architecture::Wasm32 => CallingConvention::WasmBasicCAbi, + _ => return Err(()), + }, + _ => return Err(()), + }) + } + + /// The C data model for a given target. If the model is not known, returns `Err(())`. + pub fn data_model(&self) -> Result { + match self.pointer_width()? { + PointerWidth::U64 => { + if self.operating_system == OperatingSystem::Windows { + Ok(CDataModel::LLP64) + } else if self.default_calling_convention() == Ok(CallingConvention::SystemV) + || self.architecture == Architecture::Wasm64 + || self.default_calling_convention() == Ok(CallingConvention::AppleAarch64) + { + Ok(CDataModel::LP64) + } else { + Err(()) + } + } + PointerWidth::U32 => { + if self.operating_system == OperatingSystem::Windows + || self.default_calling_convention() == Ok(CallingConvention::SystemV) + || self.architecture == Architecture::Wasm32 + { + Ok(CDataModel::ILP32) + } else { + Err(()) + } + } + // TODO: on 16-bit machines there is usually a distinction + // between near-pointers and far-pointers. + // Additionally, code pointers sometimes have a different size than data pointers. + // We don't handle this case. + PointerWidth::U16 => Err(()), + } + } + + /// Return a `Triple` with all unknown fields. + pub fn unknown() -> Self { + Self { + architecture: Architecture::Unknown, + vendor: Vendor::Unknown, + operating_system: OperatingSystem::Unknown, + environment: Environment::Unknown, + binary_format: BinaryFormat::Unknown, + } + } +} + +impl fmt::Display for Triple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(res) = self.special_case_display(f) { + return res; + } + + let implied_binary_format = default_binary_format(&self); + + write!(f, "{}", self.architecture)?; + if self.vendor == Vendor::Unknown + && (self.environment != Environment::HermitKernel + && self.environment != Environment::LinuxKernel) + && ((self.operating_system == OperatingSystem::Linux + && (self.environment == Environment::Android + || self.environment == Environment::Androideabi + || self.environment == Environment::Kernel)) + || self.operating_system == OperatingSystem::Wasi + || self.operating_system == OperatingSystem::WasiP1 + || self.operating_system == OperatingSystem::WasiP2 + || (self.operating_system == OperatingSystem::None_ + && (self.architecture == Architecture::Arm(ArmArchitecture::Armv4t) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv5te) + || self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv7a) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv8r) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv4t) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv5te) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain) + || self.architecture == Architecture::Msp430))) + { + // As a special case, omit the vendor for Android, Wasi, and sometimes + // None_, depending on the hardware architecture. This logic is entirely + // ad-hoc, and is just sufficient to handle the current set of recognized + // triples. + write!(f, "-{}", self.operating_system)?; + } else if self.architecture.is_clever() && self.operating_system == OperatingSystem::Unknown + { + write!(f, "-{}", self.vendor)?; + } else { + write!(f, "-{}-{}", self.vendor, self.operating_system)?; + } + + match (&self.vendor, self.operating_system, self.environment) { + (Vendor::Nintendo, OperatingSystem::Horizon, Environment::Newlib) + | (Vendor::Espressif, OperatingSystem::Espidf, Environment::Newlib) => { + // The triple representations of these platforms don't have an environment field. + } + (_, _, Environment::Unknown) => { + // Don't print out the environment if it is unknown. + } + _ => { + write!(f, "-{}", self.environment)?; + } + } + + if self.binary_format != implied_binary_format || show_binary_format_with_no_os(self) { + // As a special case, omit a non-default binary format for some + // targets which happen to exclude it. + write!(f, "-{}", self.binary_format)?; + } + Ok(()) + } +} + +fn show_binary_format_with_no_os(triple: &Triple) -> bool { + if triple.binary_format == BinaryFormat::Unknown { + return false; + } + + #[cfg(feature = "arch_zkasm")] + { + if triple.architecture == Architecture::ZkAsm { + return false; + } + } + + triple.environment != Environment::Eabi + && triple.environment != Environment::Eabihf + && triple.environment != Environment::Sgx + && triple.architecture != Architecture::Avr + && triple.architecture != Architecture::Wasm32 + && triple.architecture != Architecture::Wasm64 + && (triple.operating_system == OperatingSystem::None_ + || triple.operating_system == OperatingSystem::Unknown) +} + +impl FromStr for Triple { + type Err = ParseError; + + /// Parse a triple from an LLVM target triple. + /// + /// This may also be able to parse `rustc` target triples, though support + /// for that is secondary. + fn from_str(s: &str) -> Result { + if let Some(triple) = Triple::special_case_from_str(s) { + return Ok(triple); + } + + let mut parts = s.split('-'); + let mut result = Self::unknown(); + let mut current_part; + + current_part = parts.next(); + if let Some(s) = current_part { + if let Ok(architecture) = Architecture::from_str(s) { + result.architecture = architecture; + current_part = parts.next(); + } else { + // Insist that the triple start with a valid architecture. + return Err(ParseError::UnrecognizedArchitecture(s.to_owned())); + } + } + + let mut has_vendor = false; + let mut has_operating_system = false; + if let Some(s) = current_part { + if let Ok(vendor) = Vendor::from_str(s) { + has_vendor = true; + result.vendor = vendor; + current_part = parts.next(); + } + } + + if !has_operating_system { + if let Some(s) = current_part { + if let Ok(operating_system) = OperatingSystem::from_str(s) { + has_operating_system = true; + result.operating_system = operating_system; + current_part = parts.next(); + } + } + } + + let mut has_environment = false; + + if !has_environment { + if let Some(s) = current_part { + if let Ok(environment) = Environment::from_str(s) { + has_environment = true; + result.environment = environment; + current_part = parts.next(); + } + } + } + + let mut has_binary_format = false; + if let Some(s) = current_part { + if let Ok(binary_format) = BinaryFormat::from_str(s) { + has_binary_format = true; + result.binary_format = binary_format; + current_part = parts.next(); + } + } + + // The binary format is frequently omitted; if that's the case here, + // infer it from the other fields. + if !has_binary_format { + result.binary_format = default_binary_format(&result); + } + + if let Some(s) = current_part { + Err( + if !has_vendor && !has_operating_system && !has_environment && !has_binary_format { + ParseError::UnrecognizedVendor(s.to_owned()) + } else if !has_operating_system && !has_environment && !has_binary_format { + ParseError::UnrecognizedOperatingSystem(s.to_owned()) + } else if !has_environment && !has_binary_format { + ParseError::UnrecognizedEnvironment(s.to_owned()) + } else if !has_binary_format { + ParseError::UnrecognizedBinaryFormat(s.to_owned()) + } else { + ParseError::UnrecognizedField(s.to_owned()) + }, + ) + } else { + Ok(result) + } + } +} + +impl Triple { + /// Handle special cases in the `Display` implementation. + fn special_case_display(&self, f: &mut fmt::Formatter) -> Option { + let res = match self { + Triple { + architecture: Architecture::Arm(ArmArchitecture::Armv6k), + vendor: Vendor::Nintendo, + operating_system: OperatingSystem::Horizon, + .. + } => write!(f, "{}-{}-3ds", self.architecture, self.vendor), + Triple { + architecture: Architecture::Riscv32(Riscv32Architecture::Riscv32imc), + vendor: Vendor::Espressif, + operating_system: OperatingSystem::Espidf, + .. + } => write!(f, "{}-esp-{}", self.architecture, self.operating_system), + _ => return None, + }; + Some(res) + } + + /// Handle special cases in the `FromStr` implementation. + fn special_case_from_str(s: &str) -> Option { + let mut triple = Triple::unknown(); + + match s { + "armv6k-nintendo-3ds" => { + triple.architecture = Architecture::Arm(ArmArchitecture::Armv6k); + triple.vendor = Vendor::Nintendo; + triple.operating_system = OperatingSystem::Horizon; + triple.environment = Environment::Newlib; + triple.binary_format = default_binary_format(&triple); + } + "riscv32imc-esp-espidf" => { + triple.architecture = Architecture::Riscv32(Riscv32Architecture::Riscv32imc); + triple.vendor = Vendor::Espressif; + triple.operating_system = OperatingSystem::Espidf; + triple.environment = Environment::Newlib; + triple.binary_format = default_binary_format(&triple); + } + _ => return None, + } + + Some(triple) + } +} + +/// A convenient syntax for triple literals. +/// +/// This currently expands to code that just calls `Triple::from_str` and does +/// an `expect`, though in the future it would be cool to use procedural macros +/// or so to report errors at compile time instead. +#[macro_export] +macro_rules! triple { + ($str:tt) => { + <$crate::Triple as core::str::FromStr>::from_str($str).expect("invalid triple literal") + }; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_errors() { + assert_eq!( + Triple::from_str(""), + Err(ParseError::UnrecognizedArchitecture("".to_owned())) + ); + assert_eq!( + Triple::from_str("foo"), + Err(ParseError::UnrecognizedArchitecture("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-foo"), + Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedEnvironment("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedField("foo".to_owned())) + ); + } + + #[test] + fn defaults() { + assert_eq!( + Triple::from_str("unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + } + + #[test] + fn unknown_properties() { + assert_eq!(Triple::unknown().endianness(), Err(())); + assert_eq!(Triple::unknown().pointer_width(), Err(())); + assert_eq!(Triple::unknown().default_calling_convention(), Err(())); + } + + #[test] + fn apple_calling_convention() { + for triple in &[ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-macabi", + "aarch64-apple-tvos", + "aarch64-apple-watchos", + ] { + let triple = Triple::from_str(triple).unwrap(); + assert_eq!( + triple.default_calling_convention().unwrap(), + CallingConvention::AppleAarch64 + ); + assert_eq!(triple.data_model().unwrap(), CDataModel::LP64); + } + + for triple in &["aarch64-linux-android", "x86_64-apple-ios"] { + assert_eq!( + Triple::from_str(triple) + .unwrap() + .default_calling_convention() + .unwrap(), + CallingConvention::SystemV + ); + } + } + + #[test] + fn p32_abi() { + // Test that special 32-bit pointer ABIs on 64-bit architectures are + // reported as having 32-bit pointers. + for triple in &[ + "x86_64-unknown-linux-gnux32", + "aarch64_be-unknown-linux-gnu_ilp32", + "aarch64-unknown-linux-gnu_ilp32", + ] { + assert_eq!( + Triple::from_str(triple).unwrap().pointer_width().unwrap(), + PointerWidth::U32 + ); + } + + // Test that the corresponding ABIs have 64-bit pointers. + for triple in &[ + "x86_64-unknown-linux-gnu", + "aarch64_be-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + ] { + assert_eq!( + Triple::from_str(triple).unwrap().pointer_width().unwrap(), + PointerWidth::U64 + ); + } + } +} diff --git a/doc/api/cli.md b/doc/api/cli.md index e979ec95c4259d..3ec5c8d91c34ad 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1195,6 +1195,20 @@ Enable the experimental [`node:ffi`][] module. This flag is only available in builds with FFI support. +### `--experimental-fast-ffi` + + + +> Stability: 1 - Experimental + +Enable the experimental fast call path for the [`node:ffi`][] module. + +This flag requires \[`--experimental-ffi`]\[] and is only available in builds with +fast FFI support. Unsupported signatures continue to use the regular FFI call +path. + ### `--experimental-import-meta-resolve`

(&self, pred: P) -> usize + where + P: FnMut(&K, &V) -> bool, + { + self.as_slice().partition_point(pred) + } + + /// Reverses the order of the map's key-value pairs in place. + /// + /// Computes in **O(n)** time and **O(1)** space. + pub fn reverse(&mut self) { + self.core.reverse() + } + + /// Returns a slice of all the key-value pairs in the map. + /// + /// Computes in **O(1)** time. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.as_entries()) + } + + /// Returns a mutable slice of all the key-value pairs in the map. + /// + /// Computes in **O(1)** time. + pub fn as_mut_slice(&mut self) -> &mut Slice { + Slice::from_mut_slice(self.as_entries_mut()) + } + + /// Converts into a boxed slice of all the key-value pairs in the map. + /// + /// Note that this will drop the inner hash table and any excess capacity. + pub fn into_boxed_slice(self) -> Box> { + Slice::from_boxed(self.into_entries().into_boxed_slice()) + } + + /// Get a key-value pair by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { + self.as_entries().get(index).map(Bucket::refs) + } + + /// Get a key-value pair by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::ref_mut) + } + + /// Get an entry in the map by index for in-place manipulation. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_index_entry(&mut self, index: usize) -> Option> { + IndexedEntry::new(&mut self.core, index) + } + + /// Get an array of `N` key-value pairs by `N` indices + /// + /// Valid indices are *0 <= index < self.len()* and each index needs to be unique. + /// + /// # Examples + /// + /// ``` + /// let mut map = indexmap::IndexMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Ok([(&2, &mut 'c'), (&1, &mut 'a')])); + /// ``` + pub fn get_disjoint_indices_mut( + &mut self, + indices: [usize; N], + ) -> Result<[(&K, &mut V); N], GetDisjointMutError> { + self.as_mut_slice().get_disjoint_mut(indices) + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + let entries = self.as_entries(); + let range = try_simplify_range(range, entries.len())?; + entries.get(range).map(Slice::from_slice) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Slice> { + let entries = self.as_entries_mut(); + let range = try_simplify_range(range, entries.len())?; + entries.get_mut(range).map(Slice::from_mut_slice) + } + + /// Get the first key-value pair + /// + /// Computes in **O(1)** time. + #[doc(alias = "first_key_value")] // like `BTreeMap` + pub fn first(&self) -> Option<(&K, &V)> { + self.as_entries().first().map(Bucket::refs) + } + + /// Get the first key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().first_mut().map(Bucket::ref_mut) + } + + /// Get the first entry in the map for in-place manipulation. + /// + /// Computes in **O(1)** time. + pub fn first_entry(&mut self) -> Option> { + self.get_index_entry(0) + } + + /// Get the last key-value pair + /// + /// Computes in **O(1)** time. + #[doc(alias = "last_key_value")] // like `BTreeMap` + pub fn last(&self) -> Option<(&K, &V)> { + self.as_entries().last().map(Bucket::refs) + } + + /// Get the last key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().last_mut().map(Bucket::ref_mut) + } + + /// Get the last entry in the map for in-place manipulation. + /// + /// Computes in **O(1)** time. + pub fn last_entry(&mut self) -> Option> { + self.get_index_entry(self.len().checked_sub(1)?) + } + + /// Remove the key-value pair by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Like [`Vec::swap_remove`], the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + self.core.swap_remove_index(index) + } + + /// Remove the key-value pair by index + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Like [`Vec::remove`], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + self.core.shift_remove_index(index) + } + + /// Moves the position of a key-value pair from one index to another + /// by shifting all other pairs in-between. + /// + /// * If `from < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `from > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `from` or `to` are out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn move_index(&mut self, from: usize, to: usize) { + self.core.move_index(from, to) + } + + /// Swaps the position of two key-value pairs in the map. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.core.swap_indices(a, b) + } +} + +/// Access [`IndexMap`] values corresponding to a key. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// assert_eq!(map["lorem"], "LOREM"); +/// assert_eq!(map["ipsum"], "IPSUM"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map["bar"]); // panics! +/// ``` +impl Index<&Q> for IndexMap +where + Q: Hash + Equivalent, + S: BuildHasher, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied `key`. + /// + /// ***Panics*** if `key` is not present in the map. + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +/// Access [`IndexMap`] values corresponding to a key. +/// +/// Mutable indexing allows changing / updating values of key-value +/// pairs that are already present. +/// +/// You can **not** insert new pairs with index syntax, use `.insert()`. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_string()); +/// } +/// let lorem = &mut map["lorem"]; +/// assert_eq!(lorem, "Lorem"); +/// lorem.retain(char::is_lowercase); +/// assert_eq!(map["lorem"], "orem"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// map["bar"] = 1; // panics! +/// ``` +impl IndexMut<&Q> for IndexMap +where + Q: Hash + Equivalent, + S: BuildHasher, +{ + /// Returns a mutable reference to the value corresponding to the supplied `key`. + /// + /// ***Panics*** if `key` is not present in the map. + fn index_mut(&mut self, key: &Q) -> &mut V { + self.get_mut(key).expect("no entry found for key") + } +} + +/// Access [`IndexMap`] values at indexed positions. +/// +/// See [`Index for Keys`][keys] to access a map's keys instead. +/// +/// [keys]: Keys#impl-Index-for-Keys<'a,+K,+V> +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// assert_eq!(map[0], "LOREM"); +/// assert_eq!(map[1], "IPSUM"); +/// map.reverse(); +/// assert_eq!(map[0], "AMET"); +/// assert_eq!(map[1], "SIT"); +/// map.sort_keys(); +/// assert_eq!(map[0], "AMET"); +/// assert_eq!(map[1], "DOLOR"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map[10]); // panics! +/// ``` +impl Index for IndexMap { + type Output = V; + + /// Returns a reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &V { + if let Some((_, value)) = self.get_index(index) { + value + } else { + panic!( + "index out of bounds: the len is {len} but the index is {index}", + len = self.len() + ); + } + } +} + +/// Access [`IndexMap`] values at indexed positions. +/// +/// Mutable indexing allows changing / updating indexed values +/// that are already present. +/// +/// You can **not** insert new values with index syntax -- use [`.insert()`][IndexMap::insert]. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_string()); +/// } +/// let lorem = &mut map[0]; +/// assert_eq!(lorem, "Lorem"); +/// lorem.retain(char::is_lowercase); +/// assert_eq!(map["lorem"], "orem"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// map[10] = 1; // panics! +/// ``` +impl IndexMut for IndexMap { + /// Returns a mutable reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index_mut(&mut self, index: usize) -> &mut V { + let len: usize = self.len(); + + if let Some((_, value)) = self.get_index_mut(index) { + value + } else { + panic!("index out of bounds: the len is {len} but the index is {index}"); + } + } +} + +impl FromIterator<(K, V)> for IndexMap +where + K: Hash + Eq, + S: BuildHasher + Default, +{ + /// Create an `IndexMap` from the sequence of key-value pairs in the + /// iterable. + /// + /// `from_iter` uses the same logic as `extend`. See + /// [`extend`][IndexMap::extend] for more details. + fn from_iter>(iterable: I) -> Self { + let iter = iterable.into_iter(); + let (low, _) = iter.size_hint(); + let mut map = Self::with_capacity_and_hasher(low, <_>::default()); + map.extend(iter); + map + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl From<[(K, V); N]> for IndexMap +where + K: Hash + Eq, +{ + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let map1 = IndexMap::from([(1, 2), (3, 4)]); + /// let map2: IndexMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + Self::from_iter(arr) + } +} + +impl Extend<(K, V)> for IndexMap +where + K: Hash + Eq, + S: BuildHasher, +{ + /// Extend the map with all key-value pairs in the iterable. + /// + /// This is equivalent to calling [`insert`][IndexMap::insert] for each of + /// them in order, which means that for keys that already existed + /// in the map, their value is updated but it keeps the existing order. + /// + /// New keys are inserted in the order they appear in the sequence. If + /// equivalents of a key occur more than once, the last corresponding value + /// prevails. + fn extend>(&mut self, iterable: I) { + // (Note: this is a copy of `std`/`hashbrown`'s reservation logic.) + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iterable.into_iter(); + let (lower_len, _) = iter.size_hint(); + let reserve = if self.is_empty() { + lower_len + } else { + lower_len.div_ceil(2) + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } +} + +impl<'a, K, V, S> Extend<(&'a K, &'a V)> for IndexMap +where + K: Hash + Eq + Copy, + V: Copy, + S: BuildHasher, +{ + /// Extend the map with all key-value pairs in the iterable. + /// + /// See the first extend method for more details. + fn extend>(&mut self, iterable: I) { + self.extend(iterable.into_iter().map(|(&key, &value)| (key, value))); + } +} + +impl Default for IndexMap +where + S: Default, +{ + /// Return an empty [`IndexMap`] + fn default() -> Self { + Self::with_capacity_and_hasher(0, S::default()) + } +} + +impl PartialEq> for IndexMap +where + K: Hash + Eq, + V1: PartialEq, + S1: BuildHasher, + S2: BuildHasher, +{ + fn eq(&self, other: &IndexMap) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for IndexMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, +{ +} diff --git a/deps/crates/vendor/indexmap/src/map/entry.rs b/deps/crates/vendor/indexmap/src/map/entry.rs new file mode 100644 index 00000000000000..28b97e3bdf0513 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/entry.rs @@ -0,0 +1,313 @@ +use crate::Bucket; +use crate::inner::{Core, OccupiedEntry, VacantEntry}; +use core::{fmt, mem}; + +/// Entry for an existing key-value pair in an [`IndexMap`][crate::IndexMap] +/// or a vacant location to insert one. +pub enum Entry<'a, K, V> { + /// Existing slot with equivalent key. + Occupied(OccupiedEntry<'a, K, V>), + /// Vacant slot (no equivalent key in the map). + Vacant(VacantEntry<'a, K, V>), +} + +impl<'a, K, V> Entry<'a, K, V> { + /// Return the index where the key-value pair exists or will be inserted. + pub fn index(&self) -> usize { + match self { + Entry::Occupied(entry) => entry.index(), + Entry::Vacant(entry) => entry.index(), + } + } + + /// Sets the value of the entry (after inserting if vacant), and returns an `OccupiedEntry`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Inserts the given default value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with(self, call: F) -> &'a mut V + where + F: FnOnce() -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(call()), + } + } + + /// Inserts the result of the `call` function with a reference to the entry's key if it is + /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to + /// an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with_key(self, call: F) -> &'a mut V + where + F: FnOnce(&K) -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = call(entry.key()); + entry.insert(value) + } + } + } + + /// Gets a reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Modifies the entry if it is occupied. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut V), + { + if let Entry::Occupied(entry) = &mut self { + f(entry.get_mut()); + } + self + } + + /// Inserts a default-constructed value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(V::default()), + } + } +} + +impl fmt::Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut tuple = f.debug_tuple("Entry"); + match self { + Entry::Vacant(v) => tuple.field(v), + Entry::Occupied(o) => tuple.field(o), + }; + tuple.finish() + } +} + +impl fmt::Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl fmt::Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into an occupied entry in an [`IndexMap`][crate::IndexMap] obtained by index. +/// +/// This `struct` is created from the [`get_index_entry`][crate::IndexMap::get_index_entry] method. +pub struct IndexedEntry<'a, K, V> { + map: &'a mut Core, + // We have a mutable reference to the map, which keeps the index + // valid and pointing to the correct entry. + index: usize, +} + +impl<'a, K, V> IndexedEntry<'a, K, V> { + pub(crate) fn new(map: &'a mut Core, index: usize) -> Option { + if index < map.len() { + Some(Self { map, index }) + } else { + None + } + } + + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.index + } + + pub(crate) fn into_core(self) -> &'a mut Core { + self.map + } + + fn get_bucket(&self) -> &Bucket { + &self.map.as_entries()[self.index] + } + + fn get_bucket_mut(&mut self) -> &mut Bucket { + &mut self.map.as_entries_mut()[self.index] + } + + fn into_bucket(self) -> &'a mut Bucket { + &mut self.map.as_entries_mut()[self.index] + } + + /// Gets a reference to the entry's key in the map. + pub fn key(&self) -> &K { + &self.get_bucket().key + } + + pub(super) fn key_mut(&mut self) -> &mut K { + &mut self.get_bucket_mut().key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.get_bucket().value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// `IndexedEntry` value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + &mut self.get_bucket_mut().value + } + + /// Sets the value of the entry to `value`, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + &mut self.into_bucket().value + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + self.map.swap_remove_index(self.index).unwrap() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + self.map.shift_remove_index(self.index).unwrap() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn move_index(self, to: usize) { + self.map.move_index(self.index, to); + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn swap_indices(self, other: usize) { + self.map.swap_indices(self.index, other); + } +} + +impl fmt::Debug for IndexedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IndexedEntry") + .field("index", &self.index) + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl<'a, K, V> From> for IndexedEntry<'a, K, V> { + fn from(other: OccupiedEntry<'a, K, V>) -> Self { + Self { + index: other.index(), + map: other.into_core(), + } + } +} + +#[test] +fn assert_send_sync() { + fn assert_send_sync() {} + assert_send_sync::>(); + assert_send_sync::>(); +} diff --git a/deps/crates/vendor/indexmap/src/map/iter.rs b/deps/crates/vendor/indexmap/src/map/iter.rs new file mode 100644 index 00000000000000..0a3eebdd93cc7a --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/iter.rs @@ -0,0 +1,894 @@ +use super::{Bucket, HashValue, IndexMap, Slice}; +use crate::inner::{Core, ExtractCore}; + +use alloc::vec::{self, Vec}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::mem::MaybeUninit; +use core::ops::{Index, RangeBounds}; +use core::slice; + +impl<'a, K, V, S> IntoIterator for &'a IndexMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut IndexMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl IntoIterator for IndexMap { + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.into_entries()) + } +} + +/// An iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::iter`] method. +/// See its documentation for more. +pub struct Iter<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Iter<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &'a Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + iterator_methods!(Bucket::refs); +} + +impl DoubleEndedIterator for Iter<'_, K, V> { + double_ended_iterator_methods!(Bucket::refs); +} + +impl ExactSizeIterator for Iter<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Iter<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// A mutable iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::iter_mut`] method. +/// See its documentation for more. +pub struct IterMut<'a, K, V> { + iter: slice::IterMut<'a, Bucket>, +} + +impl<'a, K, V> IterMut<'a, K, V> { + pub(super) fn new(entries: &'a mut [Bucket]) -> Self { + Self { + iter: entries.iter_mut(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } + + /// Returns a mutable slice of the remaining entries in the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to consume the iterator. + pub fn into_slice(self) -> &'a mut Slice { + Slice::from_mut_slice(self.iter.into_slice()) + } +} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + iterator_methods!(Bucket::ref_mut); +} + +impl DoubleEndedIterator for IterMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::ref_mut); +} + +impl ExactSizeIterator for IterMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IterMut<'_, K, V> { + fn default() -> Self { + Self { + iter: [].iter_mut(), + } + } +} + +/// A mutable iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`MutableKeys::iter_mut2`][super::MutableKeys::iter_mut2] method. +/// See its documentation for more. +pub struct IterMut2<'a, K, V> { + iter: slice::IterMut<'a, Bucket>, +} + +impl<'a, K, V> IterMut2<'a, K, V> { + pub(super) fn new(entries: &'a mut [Bucket]) -> Self { + Self { + iter: entries.iter_mut(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } + + /// Returns a mutable slice of the remaining entries in the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to consume the iterator. + pub fn into_slice(self) -> &'a mut Slice { + Slice::from_mut_slice(self.iter.into_slice()) + } +} + +impl<'a, K, V> Iterator for IterMut2<'a, K, V> { + type Item = (&'a mut K, &'a mut V); + + iterator_methods!(Bucket::muts); +} + +impl DoubleEndedIterator for IterMut2<'_, K, V> { + double_ended_iterator_methods!(Bucket::muts); +} + +impl ExactSizeIterator for IterMut2<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IterMut2<'_, K, V> {} + +impl fmt::Debug for IterMut2<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IterMut2<'_, K, V> { + fn default() -> Self { + Self { + iter: [].iter_mut(), + } + } +} + +/// An owning iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_iter`] method +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +#[derive(Clone)] +pub struct IntoIter { + iter: vec::IntoIter>, +} + +impl IntoIter { + pub(super) fn new(entries: Vec>) -> Self { + Self { + iter: entries.into_iter(), + } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } + + /// Returns a mutable slice of the remaining entries in the iterator. + pub fn as_mut_slice(&mut self) -> &mut Slice { + Slice::from_mut_slice(self.iter.as_mut_slice()) + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoIter { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A draining iterator over the entries of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::drain`] method. +/// See its documentation for more. +pub struct Drain<'a, K, V> { + iter: vec::Drain<'a, Bucket>, +} + +impl<'a, K, V> Drain<'a, K, V> { + pub(super) fn new(iter: vec::Drain<'a, Bucket>) -> Self { + Self { iter } + } + + /// Returns a slice of the remaining entries in the iterator. + pub fn as_slice(&self) -> &Slice { + Slice::from_slice(self.iter.as_slice()) + } +} + +impl Iterator for Drain<'_, K, V> { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for Drain<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for Drain<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, K, V> {} + +impl fmt::Debug for Drain<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +/// An iterator over the keys of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::keys`] method. +/// See its documentation for more. +pub struct Keys<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Keys<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Keys<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Keys<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Keys<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + fn clone(&self) -> Self { + Keys { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Keys<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// Access [`IndexMap`] keys at indexed positions. +/// +/// While [`Index for IndexMap`][values] accesses a map's values, +/// indexing through [`IndexMap::keys`] offers an alternative to access a map's +/// keys instead. +/// +/// [values]: IndexMap#impl-Index-for-IndexMap +/// +/// Since `Keys` is also an iterator, consuming items from the iterator will +/// offset the effective indices. Similarly, if `Keys` is obtained from +/// [`Slice::keys`], indices will be interpreted relative to the position of +/// that slice. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// +/// assert_eq!(map[0], "LOREM"); +/// assert_eq!(map.keys()[0], "lorem"); +/// assert_eq!(map[1], "IPSUM"); +/// assert_eq!(map.keys()[1], "ipsum"); +/// +/// map.reverse(); +/// assert_eq!(map.keys()[0], "amet"); +/// assert_eq!(map.keys()[1], "sit"); +/// +/// map.sort_keys(); +/// assert_eq!(map.keys()[0], "amet"); +/// assert_eq!(map.keys()[1], "dolor"); +/// +/// // Advancing the iterator will offset the indexing +/// let mut keys = map.keys(); +/// assert_eq!(keys[0], "amet"); +/// assert_eq!(keys.next().map(|s| &**s), Some("amet")); +/// assert_eq!(keys[0], "dolor"); +/// assert_eq!(keys[1], "ipsum"); +/// +/// // Slices may have an offset as well +/// let slice = &map[2..]; +/// assert_eq!(slice[0], "IPSUM"); +/// assert_eq!(slice.keys()[0], "ipsum"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map.keys()[10]); // panics! +/// ``` +impl Index for Keys<'_, K, V> { + type Output = K; + + /// Returns a reference to the key at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &K { + &self.iter.as_slice()[index].key + } +} + +/// An owning iterator over the keys of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_keys`] method. +/// See its documentation for more. +pub struct IntoKeys { + // We eagerly drop the values during construction so we can ignore them in + // `Clone`, but we keep uninit values so the bucket's size and alignment + // remain the same, and therefore the `Vec` conversion should be in-place. + iter: vec::IntoIter>>, +} + +impl IntoKeys { + pub(super) fn new(entries: Vec>) -> Self { + // The original values will be dropped here. + // The hash doesn't matter, but "copying" it in-place is free. + let entries = entries + .into_iter() + .map(|Bucket { hash, key, .. }| Bucket { + hash, + key, + value: MaybeUninit::uninit(), + }) + .collect::>(); + Self { + iter: entries.into_iter(), + } + } +} + +impl Clone for IntoKeys { + fn clone(&self) -> Self { + let entries = self + .iter + .as_slice() + .iter() + .map(|Bucket { key, .. }| Bucket { + hash: HashValue(0), + key: key.clone(), + value: MaybeUninit::uninit(), + }) + .collect::>(); + Self { + iter: entries.into_iter(), + } + } +} + +impl Iterator for IntoKeys { + type Item = K; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoKeys { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoKeys { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoKeys { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// An iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::values`] method. +/// See its documentation for more. +pub struct Values<'a, K, V> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, K, V> Values<'a, K, V> { + pub(super) fn new(entries: &'a [Bucket]) -> Self { + Self { + iter: entries.iter(), + } + } +} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + iterator_methods!(Bucket::value_ref); +} + +impl DoubleEndedIterator for Values<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_ref); +} + +impl ExactSizeIterator for Values<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Values<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + fn clone(&self) -> Self { + Values { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Default for Values<'_, K, V> { + fn default() -> Self { + Self { iter: [].iter() } + } +} + +/// A mutable iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::values_mut`] method. +/// See its documentation for more. +pub struct ValuesMut<'a, K, V> { + iter: slice::IterMut<'a, Bucket>, +} + +impl<'a, K, V> ValuesMut<'a, K, V> { + pub(super) fn new(entries: &'a mut [Bucket]) -> Self { + Self { + iter: entries.iter_mut(), + } + } +} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + iterator_methods!(Bucket::value_mut); +} + +impl DoubleEndedIterator for ValuesMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_mut); +} + +impl ExactSizeIterator for ValuesMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for ValuesMut<'_, K, V> { + fn default() -> Self { + Self { + iter: [].iter_mut(), + } + } +} + +/// An owning iterator over the values of an [`IndexMap`]. +/// +/// This `struct` is created by the [`IndexMap::into_values`] method. +/// See its documentation for more. +pub struct IntoValues { + // We eagerly drop the keys during construction so we can ignore them in + // `Clone`, but we keep uninit keys so the bucket's size and alignment + // remain the same, and therefore the `Vec` conversion should be in-place. + iter: vec::IntoIter, V>>, +} + +impl IntoValues { + pub(super) fn new(entries: Vec>) -> Self { + // The original keys will be dropped here. + // The hash doesn't matter, but "copying" it in-place is free. + let entries = entries + .into_iter() + .map(|Bucket { hash, value, .. }| Bucket { + hash, + key: MaybeUninit::uninit(), + value, + }) + .collect::>(); + Self { + iter: entries.into_iter(), + } + } +} + +impl Clone for IntoValues { + fn clone(&self) -> Self { + let entries = self + .iter + .as_slice() + .iter() + .map(|Bucket { value, .. }| Bucket { + hash: HashValue(0), + key: MaybeUninit::uninit(), + value: value.clone(), + }) + .collect::>(); + Self { + iter: entries.into_iter(), + } + } +} + +impl Iterator for IntoValues { + type Item = V; + + iterator_methods!(Bucket::value); +} + +impl DoubleEndedIterator for IntoValues { + double_ended_iterator_methods!(Bucket::value); +} + +impl ExactSizeIterator for IntoValues { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl Default for IntoValues { + fn default() -> Self { + Self { + iter: Vec::new().into_iter(), + } + } +} + +/// A splicing iterator for `IndexMap`. +/// +/// This `struct` is created by [`IndexMap::splice()`]. +/// See its documentation for more. +pub struct Splice<'a, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + map: &'a mut IndexMap, + tail: Core, + drain: vec::IntoIter>, + replace_with: I, +} + +impl<'a, I, K, V, S> Splice<'a, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + #[track_caller] + pub(super) fn new(map: &'a mut IndexMap, range: R, replace_with: I) -> Self + where + R: RangeBounds, + { + let (tail, drain) = map.core.split_splice(range); + Self { + map, + tail, + drain, + replace_with, + } + } +} + +impl Drop for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn drop(&mut self) { + // Finish draining unconsumed items. We don't strictly *have* to do this + // manually, since we already split it into separate memory, but it will + // match the drop order of `vec::Splice` items this way. + let _ = self.drain.nth(usize::MAX); + + // Now insert all the new items. If a key matches an existing entry, it + // keeps the original position and only replaces the value, like `insert`. + while let Some((key, value)) = self.replace_with.next() { + // Since the tail is disjoint, we can try to update it first, + // or else insert (update or append) the primary map. + let hash = self.map.hash(&key); + if let Some(i) = self.tail.get_index_of(hash, &key) { + self.tail.as_entries_mut()[i].value = value; + } else { + self.map.core.insert_full(hash, key, value); + } + } + + // Finally, re-append the tail + self.map.core.append_unchecked(&mut self.tail); + } +} + +impl Iterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + self.drain.next().map(Bucket::key_value) + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.drain.next_back().map(Bucket::key_value) + } +} + +impl ExactSizeIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ + fn len(&self) -> usize { + self.drain.len() + } +} + +impl FusedIterator for Splice<'_, I, K, V, S> +where + I: Iterator, + K: Hash + Eq, + S: BuildHasher, +{ +} + +impl fmt::Debug for Splice<'_, I, K, V, S> +where + I: fmt::Debug + Iterator, + K: fmt::Debug + Hash + Eq, + V: fmt::Debug, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Follow `vec::Splice` in only printing the drain and replacement + f.debug_struct("Splice") + .field("drain", &self.drain) + .field("replace_with", &self.replace_with) + .finish() + } +} + +/// An extracting iterator for `IndexMap`. +/// +/// This `struct` is created by [`IndexMap::extract_if()`]. +/// See its documentation for more. +pub struct ExtractIf<'a, K, V, F> { + inner: ExtractCore<'a, K, V>, + pred: F, +} + +impl ExtractIf<'_, K, V, F> { + #[track_caller] + pub(super) fn new(core: &mut Core, range: R, pred: F) -> ExtractIf<'_, K, V, F> + where + R: RangeBounds, + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { + inner: core.extract(range), + pred, + } + } +} + +impl Iterator for ExtractIf<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + self.inner + .extract_if(|bucket| { + let (key, value) = bucket.ref_mut(); + (self.pred)(key, value) + }) + .map(Bucket::key_value) + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.inner.remaining())) + } +} + +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +impl fmt::Debug for ExtractIf<'_, K, V, F> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} diff --git a/deps/crates/vendor/indexmap/src/map/mutable.rs b/deps/crates/vendor/indexmap/src/map/mutable.rs new file mode 100644 index 00000000000000..b0ecf344f41b2c --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/mutable.rs @@ -0,0 +1,165 @@ +use core::hash::{BuildHasher, Hash}; + +use super::{ + Bucket, Entry, Equivalent, IndexMap, IndexedEntry, IterMut2, OccupiedEntry, VacantEntry, +}; + +/// Opt-in mutable access to [`IndexMap`] keys. +/// +/// These methods expose `&mut K`, mutable references to the key as it is stored +/// in the map. +/// You are allowed to modify the keys in the map **if the modification +/// does not change the key's hash and equality**. +/// +/// If keys are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `IndexMap`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +#[expect(private_bounds)] +pub trait MutableKeys: Sealed { + type Key; + type Value; + + /// Return item index, mutable reference to key and value + /// + /// Computes in **O(1)** time (average). + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut Self::Key, &mut Self::Value)> + where + Q: ?Sized + Hash + Equivalent; + + /// Return mutable reference to key and value at an index. + /// + /// Valid indices are `0 <= index < self.len()`. + /// + /// Computes in **O(1)** time. + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut Self::Key, &mut Self::Value)>; + + /// Return an iterator over the key-value pairs of the map, in their order + fn iter_mut2(&mut self) -> IterMut2<'_, Self::Key, Self::Value>; + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; +} + +/// Opt-in mutable access to [`IndexMap`] keys. +/// +/// See [`MutableKeys`] for more information. +impl MutableKeys for IndexMap +where + S: BuildHasher, +{ + type Key = K; + type Value = V; + + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)> + where + Q: ?Sized + Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &mut entry.key, &mut entry.value)) + } else { + None + } + } + + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::muts) + } + + fn iter_mut2(&mut self) -> IterMut2<'_, Self::Key, Self::Value> { + IterMut2::new(self.as_entries_mut()) + } + + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + self.core.retain_in_order(keep); + } +} + +/// Opt-in mutable access to [`Entry`] keys. +/// +/// These methods expose `&mut K`, mutable references to the key as it is stored +/// in the map. +/// You are allowed to modify the keys in the map **if the modification +/// does not change the key's hash and equality**. +/// +/// If keys are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `Entry`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +#[expect(private_bounds)] +pub trait MutableEntryKey: Sealed { + type Key; + + /// Gets a mutable reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. + fn key_mut(&mut self) -> &mut Self::Key; +} + +/// Opt-in mutable access to [`Entry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for Entry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + match self { + Entry::Occupied(e) => e.key_mut(), + Entry::Vacant(e) => e.key_mut(), + } + } +} + +/// Opt-in mutable access to [`OccupiedEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for OccupiedEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + &mut self.get_bucket_mut().key + } +} + +/// Opt-in mutable access to [`VacantEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for VacantEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + self.key_mut() + } +} + +/// Opt-in mutable access to [`IndexedEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for IndexedEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + self.key_mut() + } +} + +trait Sealed {} + +impl Sealed for IndexMap {} +impl Sealed for Entry<'_, K, V> {} +impl Sealed for OccupiedEntry<'_, K, V> {} +impl Sealed for VacantEntry<'_, K, V> {} +impl Sealed for IndexedEntry<'_, K, V> {} diff --git a/deps/crates/vendor/indexmap/src/map/raw_entry_v1.rs b/deps/crates/vendor/indexmap/src/map/raw_entry_v1.rs new file mode 100644 index 00000000000000..4b5dbc9552a0d2 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/raw_entry_v1.rs @@ -0,0 +1,636 @@ +//! Opt-in access to the experimental raw entry API. +//! +//! This module is designed to mimic the raw entry API of [`HashMap`][std::collections::hash_map], +//! matching its unstable state as of Rust 1.75. See the tracking issue +//! [rust#56167](https://github.com/rust-lang/rust/issues/56167) for more details. +//! +//! The trait [`RawEntryApiV1`] and the `_v1` suffix on its methods are meant to insulate this for +//! the future, in case later breaking changes are needed. If the standard library stabilizes its +//! `hash_raw_entry` feature (or some replacement), matching *inherent* methods will be added to +//! `IndexMap` without such an opt-in trait. + +use super::{Core, OccupiedEntry}; +use crate::{Equivalent, HashValue, IndexMap}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use core::mem; + +/// Opt-in access to the experimental raw entry API. +/// +/// See the [`raw_entry_v1`][self] module documentation for more information. +#[expect(private_bounds)] +pub trait RawEntryApiV1: Sealed { + /// Creates a raw immutable entry builder for the [`IndexMap`]. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the [`Equivalent`] trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// [`get`][IndexMap::get] should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want + /// [`raw_entry_mut_v1`][Self::raw_entry_mut_v1]. + /// + /// # Examples + /// + /// ``` + /// use core::hash::BuildHasher; + /// use indexmap::map::{IndexMap, RawEntryApiV1}; + /// + /// let mut map = IndexMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = map.hasher().hash_one(k); + /// let i = map.get_index_of(k); + /// let v = map.get(k); + /// let kv = map.get_key_value(k); + /// let ikv = map.get_full(k); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry_v1().from_key(k), kv); + /// assert_eq!(map.raw_entry_v1().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry_v1().from_key_hashed_nocheck(hash, k), kv); + /// assert_eq!(map.raw_entry_v1().from_hash_full(hash, |q| *q == k), ikv); + /// assert_eq!(map.raw_entry_v1().index_from_hash(hash, |q| *q == k), i); + /// } + /// ``` + fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S>; + + /// Creates a raw entry builder for the [`IndexMap`]. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the [`Equivalent`] trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the `IndexMap` into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and more + /// foolproof APIs like [`entry`][IndexMap::entry] should be preferred when possible. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::BuildHasher; + /// use indexmap::map::{IndexMap, RawEntryApiV1}; + /// use indexmap::map::raw_entry_v1::RawEntryMut; + /// + /// let mut map = IndexMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut_v1().from_key("a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.index(), 0); + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map["a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = map.hasher().hash_one("c"); + /// match map.raw_entry_mut_v1().from_key_hashed_nocheck(hash, "c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.index(), 2); + /// assert_eq!(view.shift_remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry_v1().from_key("c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = map.hasher().hash_one(key); + /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// assert_eq!(view.index(), 2); + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map["d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.index(), 2); + /// assert_eq!(view.swap_remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get("d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + fn raw_entry_mut_v1(&mut self) -> RawEntryBuilderMut<'_, K, V, S>; +} + +impl RawEntryApiV1 for IndexMap { + fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S> { + RawEntryBuilder { map: self } + } + + fn raw_entry_mut_v1(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { + RawEntryBuilderMut { map: self } + } +} + +/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. +/// +/// This `struct` is created by the [`IndexMap::raw_entry_v1`] method, provided by the +/// [`RawEntryApiV1`] trait. See its documentation for more. +pub struct RawEntryBuilder<'a, K, V, S> { + map: &'a IndexMap, +} + +impl fmt::Debug for RawEntryBuilder<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> { + /// Access an entry by key. + pub fn from_key(self, key: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: ?Sized + Hash + Equivalent, + { + self.map.get_key_value(key) + } + + /// Access an entry by a key and its hash. + pub fn from_key_hashed_nocheck(self, hash: u64, key: &Q) -> Option<(&'a K, &'a V)> + where + Q: ?Sized + Equivalent, + { + let hash = HashValue(hash as usize); + let i = self.map.core.get_index_of(hash, key)?; + self.map.get_index(i) + } + + /// Access an entry by hash. + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + let map = self.map; + let i = self.index_from_hash(hash, is_match)?; + map.get_index(i) + } + + /// Access an entry by hash, including its index. + pub fn from_hash_full(self, hash: u64, is_match: F) -> Option<(usize, &'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + let map = self.map; + let i = self.index_from_hash(hash, is_match)?; + let (key, value) = map.get_index(i)?; + Some((i, key, value)) + } + + /// Access the index of an entry by hash. + pub fn index_from_hash(self, hash: u64, is_match: F) -> Option + where + F: FnMut(&K) -> bool, + { + let hash = HashValue(hash as usize); + self.map.core.get_index_of_raw(hash, is_match) + } +} + +/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. +/// +/// This `struct` is created by the [`IndexMap::raw_entry_mut_v1`] method, provided by the +/// [`RawEntryApiV1`] trait. See its documentation for more. +pub struct RawEntryBuilderMut<'a, K, V, S> { + map: &'a mut IndexMap, +} + +impl fmt::Debug for RawEntryBuilderMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilderMut").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> { + /// Access an entry by key. + pub fn from_key(self, key: &Q) -> RawEntryMut<'a, K, V, S> + where + S: BuildHasher, + Q: ?Sized + Hash + Equivalent, + { + let hash = self.map.hash(key); + self.from_key_hashed_nocheck(hash.get(), key) + } + + /// Access an entry by a key and its hash. + pub fn from_key_hashed_nocheck(self, hash: u64, key: &Q) -> RawEntryMut<'a, K, V, S> + where + Q: ?Sized + Equivalent, + { + self.from_hash(hash, |k| Q::equivalent(key, k)) + } + + /// Access an entry by hash. + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> + where + F: FnMut(&K) -> bool, + { + let hash = HashValue(hash as usize); + match OccupiedEntry::from_hash(&mut self.map.core, hash, is_match) { + Ok(inner) => RawEntryMut::Occupied(RawOccupiedEntryMut { + inner, + hash_builder: PhantomData, + }), + Err(map) => RawEntryMut::Vacant(RawVacantEntryMut { + map, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +/// Raw entry for an existing key-value pair or a vacant location to +/// insert one. +pub enum RawEntryMut<'a, K, V, S> { + /// Existing slot with equivalent key. + Occupied(RawOccupiedEntryMut<'a, K, V, S>), + /// Vacant slot (no equivalent key in the map). + Vacant(RawVacantEntryMut<'a, K, V, S>), +} + +impl fmt::Debug for RawEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut tuple = f.debug_tuple("RawEntryMut"); + match self { + Self::Vacant(v) => tuple.field(v), + Self::Occupied(o) => tuple.field(o), + }; + tuple.finish() + } +} + +impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { + /// Return the index where the key-value pair exists or may be inserted. + #[inline] + pub fn index(&self) -> usize { + match self { + Self::Occupied(entry) => entry.index(), + Self::Vacant(entry) => entry.index(), + } + } + + /// Inserts the given default key and value in the entry if it is vacant and returns mutable + /// references to them. Otherwise mutable references to an already existent pair are returned. + pub fn or_insert(self, default_key: K, default_value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + Self::Occupied(entry) => entry.into_key_value_mut(), + Self::Vacant(entry) => entry.insert(default_key, default_value), + } + } + + /// Inserts the result of the `call` function in the entry if it is vacant and returns mutable + /// references to them. Otherwise mutable references to an already existent pair are returned. + pub fn or_insert_with(self, call: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + Self::Occupied(entry) => entry.into_key_value_mut(), + Self::Vacant(entry) => { + let (key, value) = call(); + entry.insert(key, value) + } + } + } + + /// Modifies the entry if it is occupied. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + if let Self::Occupied(entry) = &mut self { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + self + } +} + +/// A raw view into an occupied entry in an [`IndexMap`]. +/// It is part of the [`RawEntryMut`] enum. +pub struct RawOccupiedEntryMut<'a, K, V, S> { + inner: OccupiedEntry<'a, K, V>, + hash_builder: PhantomData<&'a S>, +} + +impl fmt::Debug for RawOccupiedEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + self.inner.index() + } + + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key(&self) -> &K { + self.inner.key() + } + + /// Gets a mutable reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key_mut(&mut self) -> &mut K { + &mut self.inner.get_bucket_mut().key + } + + /// Converts into a mutable reference to the entry's key in the map, + /// with a lifetime bound to the map itself. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn into_key(self) -> &'a mut K { + &mut self.inner.into_bucket().key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + self.inner.get() + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// [`RawEntryMut`] value, see [`into_mut`][Self::into_mut]. + pub fn get_mut(&mut self) -> &mut V { + self.inner.get_mut() + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + self.inner.into_mut() + } + + /// Gets a reference to the entry's key and value in the map. + pub fn get_key_value(&self) -> (&K, &V) { + self.inner.get_bucket().refs() + } + + /// Gets a reference to the entry's key and value in the map. + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + self.inner.get_bucket_mut().muts() + } + + /// Converts into a mutable reference to the entry's key and value in the map, + /// with a lifetime bound to the map itself. + pub fn into_key_value_mut(self) -> (&'a mut K, &'a mut V) { + self.inner.into_bucket().muts() + } + + /// Sets the value of the entry, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + self.inner.insert(value) + } + + /// Sets the key of the entry, and returns the entry's old key. + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this + /// entry's position with the last element, and it is deprecated in favor of calling that + /// explicitly. If you need to preserve the relative order of the keys in the map, use + /// [`.shift_remove()`][Self::shift_remove] instead. + #[deprecated(note = "`remove` disrupts the map order -- \ + use `swap_remove` or `shift_remove` for explicit behavior.")] + pub fn remove(self) -> V { + self.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.inner.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.inner.shift_remove() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], + /// replacing this entry's position with the last element, and it is deprecated in favor of + /// calling that explicitly. If you need to preserve the relative order of the keys in the map, + /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead. + #[deprecated(note = "`remove_entry` disrupts the map order -- \ + use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] + pub fn remove_entry(self) -> (K, V) { + self.swap_remove_entry() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it + /// with the last element of the map and popping it off. + /// **This perturbs the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + self.inner.swap_remove_entry() + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + self.inner.shift_remove_entry() + } + + /// Moves the position of the entry to a new index + /// by shifting all other entries in-between. + /// + /// This is equivalent to [`IndexMap::move_index`] + /// coming `from` the current [`.index()`][Self::index]. + /// + /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. + /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. + /// + /// ***Panics*** if `to` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn move_index(self, to: usize) { + self.inner.move_index(to); + } + + /// Swaps the position of entry with another. + /// + /// This is equivalent to [`IndexMap::swap_indices`] + /// with the current [`.index()`][Self::index] as one of the two being swapped. + /// + /// ***Panics*** if the `other` index is out of bounds. + /// + /// Computes in **O(1)** time (average). + #[track_caller] + pub fn swap_indices(self, other: usize) { + self.inner.swap_indices(other); + } +} + +/// A view into a vacant raw entry in an [`IndexMap`]. +/// It is part of the [`RawEntryMut`] enum. +pub struct RawVacantEntryMut<'a, K, V, S> { + map: &'a mut Core, + hash_builder: &'a S, +} + +impl fmt::Debug for RawVacantEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish_non_exhaustive() + } +} + +impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { + /// Return the index where a key-value pair may be inserted. + pub fn index(&self) -> usize { + self.map.len() + } + + /// Inserts the given key and value into the map, + /// and returns mutable references to them. + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let h = self.hash_builder.hash_one(&key); + self.insert_hashed_nocheck(h, key, value) + } + + /// Inserts the given key and value into the map with the provided hash, + /// and returns mutable references to them. + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) { + let hash = HashValue(hash as usize); + self.map.insert_unique(hash, key, value).muts() + } + + /// Inserts the given key and value into the map at the given index, + /// shifting others to the right, and returns mutable references to them. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn shift_insert(self, index: usize, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let h = self.hash_builder.hash_one(&key); + self.shift_insert_hashed_nocheck(index, h, key, value) + } + + /// Inserts the given key and value into the map with the provided hash + /// at the given index, and returns mutable references to them. + /// + /// ***Panics*** if `index` is out of bounds. + /// + /// Computes in **O(n)** time (average). + #[track_caller] + pub fn shift_insert_hashed_nocheck( + self, + index: usize, + hash: u64, + key: K, + value: V, + ) -> (&'a mut K, &'a mut V) { + let hash = HashValue(hash as usize); + self.map.shift_insert_unique(index, hash, key, value).muts() + } +} + +trait Sealed {} + +impl Sealed for IndexMap {} + +#[test] +fn assert_send_sync() { + fn assert_send_sync() {} + assert_send_sync::>(); +} diff --git a/deps/crates/vendor/indexmap/src/map/serde_seq.rs b/deps/crates/vendor/indexmap/src/map/serde_seq.rs new file mode 100644 index 00000000000000..b4c64876b43fb8 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/serde_seq.rs @@ -0,0 +1,138 @@ +//! Functions to serialize and deserialize an [`IndexMap`] as an ordered sequence. +//! +//! The default `serde` implementation serializes `IndexMap` as a normal map, +//! but there is no guarantee that serialization formats will preserve the order +//! of the key-value pairs. This module serializes `IndexMap` as a sequence of +//! `(key, value)` elements instead, in order. +//! +//! This module may be used in a field attribute for derived implementations: +//! +//! ``` +//! # use indexmap::IndexMap; +//! # use serde::{Deserialize, Serialize}; +//! #[derive(Deserialize, Serialize)] +//! struct Data { +//! #[serde(with = "indexmap::map::serde_seq")] +//! map: IndexMap, +//! // ... +//! } +//! ``` + +use serde_core::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +use serde_core::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::IndexMap; +use crate::map::Slice as MapSlice; +use crate::serde::cautious_capacity; +use crate::set::Slice as SetSlice; + +/// Serializes a [`map::Slice`][MapSlice] as an ordered sequence. +/// +/// This behaves like [`crate::map::serde_seq`] for `IndexMap`, serializing a sequence +/// of `(key, value)` pairs, rather than as a map that might not preserve order. +impl Serialize for MapSlice +where + K: Serialize, + V: Serialize, +{ + fn serialize(&self, serializer: T) -> Result + where + T: Serializer, + { + serializer.collect_seq(self) + } +} + +/// Serializes a [`set::Slice`][SetSlice] as an ordered sequence. +impl Serialize for SetSlice +where + T: Serialize, +{ + fn serialize(&self, serializer: Se) -> Result + where + Se: Serializer, + { + serializer.collect_seq(self) + } +} + +/// Serializes an [`IndexMap`] as an ordered sequence. +/// +/// This function may be used in a field attribute for deriving [`Serialize`]: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde::Serialize; +/// #[derive(Serialize)] +/// struct Data { +/// #[serde(serialize_with = "indexmap::map::serde_seq::serialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +pub fn serialize(map: &IndexMap, serializer: T) -> Result +where + K: Serialize, + V: Serialize, + T: Serializer, +{ + serializer.collect_seq(map) +} + +/// Visitor to deserialize a *sequenced* `IndexMap` +struct SeqVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for SeqVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a sequenced map") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = cautious_capacity::(seq.size_hint()); + let mut map = IndexMap::with_capacity_and_hasher(capacity, S::default()); + + while let Some((key, value)) = seq.next_element()? { + map.insert(key, value); + } + + Ok(map) + } +} + +/// Deserializes an [`IndexMap`] from an ordered sequence. +/// +/// This function may be used in a field attribute for deriving [`Deserialize`]: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde::Deserialize; +/// #[derive(Deserialize)] +/// struct Data { +/// #[serde(deserialize_with = "indexmap::map::serde_seq::deserialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + deserializer.deserialize_seq(SeqVisitor(PhantomData)) +} diff --git a/deps/crates/vendor/indexmap/src/map/slice.rs b/deps/crates/vendor/indexmap/src/map/slice.rs new file mode 100644 index 00000000000000..41a483fda853a3 --- /dev/null +++ b/deps/crates/vendor/indexmap/src/map/slice.rs @@ -0,0 +1,821 @@ +use super::{ + Bucket, IndexMap, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut, +}; +use crate::GetDisjointMutError; +use crate::util::{slice_eq, try_simplify_range}; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{self, Bound, Index, IndexMut, RangeBounds}; + +/// A dynamically-sized slice of key-value pairs in an [`IndexMap`]. +/// +/// This supports indexed operations much like a `[(K, V)]` slice, +/// but not any hashed operations on the map keys. +/// +/// Unlike `IndexMap`, `Slice` does consider the order for [`PartialEq`] +/// and [`Eq`], and it also implements [`PartialOrd`], [`Ord`], and [`Hash`]. +#[repr(transparent)] +pub struct Slice { + pub(crate) entries: [Bucket], +} + +// SAFETY: `Slice` is a transparent wrapper around `[Bucket]`, +// and reference lifetimes are bound together in function signatures. +#[allow(unsafe_code)] +impl Slice { + pub(crate) const fn from_slice(entries: &[Bucket]) -> &Self { + unsafe { &*(entries as *const [Bucket] as *const Self) } + } + + pub(super) const fn from_mut_slice(entries: &mut [Bucket]) -> &mut Self { + unsafe { &mut *(entries as *mut [Bucket] as *mut Self) } + } + + pub(super) fn from_boxed(entries: Box<[Bucket]>) -> Box { + unsafe { Box::from_raw(Box::into_raw(entries) as *mut Self) } + } + + fn into_boxed(self: Box) -> Box<[Bucket]> { + unsafe { Box::from_raw(Box::into_raw(self) as *mut [Bucket]) } + } +} + +impl Slice { + pub(crate) fn into_entries(self: Box) -> Vec> { + self.into_boxed().into_vec() + } + + /// Returns an empty slice. + pub const fn new<'a>() -> &'a Self { + Self::from_slice(&[]) + } + + /// Returns an empty mutable slice. + pub const fn new_mut<'a>() -> &'a mut Self { + Self::from_mut_slice(&mut []) + } + + /// Return the number of key-value pairs in the map slice. + #[inline] + pub const fn len(&self) -> usize { + self.entries.len() + } + + /// Returns true if the map slice contains no elements. + #[inline] + pub const fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + /// Get a key-value pair by index. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { + self.entries.get(index).map(Bucket::refs) + } + + /// Get a key-value pair by index, with mutable access to the value. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { + self.entries.get_mut(index).map(Bucket::ref_mut) + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range>(&self, range: R) -> Option<&Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get(range).map(Slice::from_slice) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Self> { + let range = try_simplify_range(range, self.entries.len())?; + self.entries.get_mut(range).map(Slice::from_mut_slice) + } + + /// Get the first key-value pair. + pub const fn first(&self) -> Option<(&K, &V)> { + if let [first, ..] = &self.entries { + Some(first.refs()) + } else { + None + } + } + + /// Get the first key-value pair, with mutable access to the value. + pub const fn first_mut(&mut self) -> Option<(&K, &mut V)> { + if let [first, ..] = &mut self.entries { + Some(first.ref_mut()) + } else { + None + } + } + + /// Get the last key-value pair. + pub const fn last(&self) -> Option<(&K, &V)> { + if let [.., last] = &self.entries { + Some(last.refs()) + } else { + None + } + } + + /// Get the last key-value pair, with mutable access to the value. + pub const fn last_mut(&mut self) -> Option<(&K, &mut V)> { + if let [.., last] = &mut self.entries { + Some(last.ref_mut()) + } else { + None + } + } + + /// Divides one slice into two at an index. + /// + /// ***Panics*** if `index > len`. + /// For a non-panicking alternative see [`split_at_checked`][Self::split_at_checked]. + #[track_caller] + pub const fn split_at(&self, index: usize) -> (&Self, &Self) { + let (first, second) = self.entries.split_at(index); + (Self::from_slice(first), Self::from_slice(second)) + } + + /// Divides one mutable slice into two at an index. + /// + /// ***Panics*** if `index > len`. + /// For a non-panicking alternative see [`split_at_mut_checked`][Self::split_at_mut_checked]. + #[track_caller] + pub const fn split_at_mut(&mut self, index: usize) -> (&mut Self, &mut Self) { + let (first, second) = self.entries.split_at_mut(index); + (Self::from_mut_slice(first), Self::from_mut_slice(second)) + } + + /// Divides one slice into two at an index. + /// + /// Returns `None` if `index > len`. + pub const fn split_at_checked(&self, index: usize) -> Option<(&Self, &Self)> { + if let Some((first, second)) = self.entries.split_at_checked(index) { + Some((Self::from_slice(first), Self::from_slice(second))) + } else { + None + } + } + + /// Divides one mutable slice into two at an index. + /// + /// Returns `None` if `index > len`. + pub const fn split_at_mut_checked(&mut self, index: usize) -> Option<(&mut Self, &mut Self)> { + if let Some((first, second)) = self.entries.split_at_mut_checked(index) { + Some((Self::from_mut_slice(first), Self::from_mut_slice(second))) + } else { + None + } + } + + /// Returns the first key-value pair and the rest of the slice, + /// or `None` if it is empty. + pub const fn split_first(&self) -> Option<((&K, &V), &Self)> { + if let [first, rest @ ..] = &self.entries { + Some((first.refs(), Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the first key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + pub const fn split_first_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> { + if let [first, rest @ ..] = &mut self.entries { + Some((first.ref_mut(), Self::from_mut_slice(rest))) + } else { + None + } + } + + /// Returns the last key-value pair and the rest of the slice, + /// or `None` if it is empty. + pub const fn split_last(&self) -> Option<((&K, &V), &Self)> { + if let [rest @ .., last] = &self.entries { + Some((last.refs(), Self::from_slice(rest))) + } else { + None + } + } + + /// Returns the last key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + pub const fn split_last_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> { + if let [rest @ .., last] = &mut self.entries { + Some((last.ref_mut(), Self::from_mut_slice(rest))) + } else { + None + } + } + + /// Return an iterator over the key-value pairs of the map slice. + pub fn iter(&self) -> Iter<'_, K, V> { + Iter::new(&self.entries) + } + + /// Return an iterator over the key-value pairs of the map slice. + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut::new(&mut self.entries) + } + + /// Return an iterator over the keys of the map slice. + pub fn keys(&self) -> Keys<'_, K, V> { + Keys::new(&self.entries) + } + + /// Return an owning iterator over the keys of the map slice. + pub fn into_keys(self: Box) -> IntoKeys { + IntoKeys::new(self.into_entries()) + } + + /// Return an iterator over the values of the map slice. + pub fn values(&self) -> Values<'_, K, V> { + Values::new(&self.entries) + } + + /// Return an iterator over mutable references to the the values of the map slice. + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut::new(&mut self.entries) + } + + /// Return an owning iterator over the values of the map slice. + pub fn into_values(self: Box) -> IntoValues { + IntoValues::new(self.into_entries()) + } + + /// Search over a sorted map for a key. + /// + /// Returns the position where that key is present, or the position where it can be inserted to + /// maintain the sort. See [`slice::binary_search`] for more details. + /// + /// Computes in **O(log(n))** time, which is notably less scalable than looking the key up in + /// the map this is a slice from using [`IndexMap::get_index_of`], but this can also position + /// missing keys. + pub fn binary_search_keys(&self, x: &K) -> Result + where + K: Ord, + { + self.binary_search_by(|p, _| p.cmp(x)) + } + + /// Search over a sorted map with a comparator function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> Ordering, + { + self.entries.binary_search_by(move |a| f(&a.key, &a.value)) + } + + /// Search over a sorted map with an extraction function. + /// + /// Returns the position where that value is present, or the position where it can be inserted + /// to maintain the sort. See [`slice::binary_search_by_key`] for more details. + /// + /// Computes in **O(log(n))** time. + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: FnMut(&'a K, &'a V) -> B, + B: Ord, + { + self.binary_search_by(|k, v| f(k, v).cmp(b)) + } + + /// Checks if the keys of this slice are sorted. + #[inline] + pub fn is_sorted(&self) -> bool + where + K: PartialOrd, + { + self.entries.is_sorted_by(|a, b| a.key <= b.key) + } + + /// Checks if this slice is sorted using the given comparator function. + #[inline] + pub fn is_sorted_by<'a, F>(&'a self, mut cmp: F) -> bool + where + F: FnMut(&'a K, &'a V, &'a K, &'a V) -> bool, + { + self.entries + .is_sorted_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)) + } + + /// Checks if this slice is sorted using the given sort-key function. + #[inline] + pub fn is_sorted_by_key<'a, F, T>(&'a self, mut sort_key: F) -> bool + where + F: FnMut(&'a K, &'a V) -> T, + T: PartialOrd, + { + self.entries + .is_sorted_by_key(move |a| sort_key(&a.key, &a.value)) + } + + /// Returns the index of the partition point of a sorted map according to the given predicate + /// (the index of the first element of the second partition). + /// + /// See [`slice::partition_point`] for more details. + /// + /// Computes in **O(log(n))** time. + #[must_use] + pub fn partition_point

(self, predicate: P) -> TakeWhile + where + Self: Sized, + P: FnMut(&Self::Item) -> Result, + { + TakeWhile { + it: self, + flag: false, + predicate, + } + } + + /// Returns an iterator which skips the first `n` values of this iterator. + #[inline] + fn skip(self, n: usize) -> Skip + where + Self: Sized, + { + Skip { it: self, n } + } + + /// Returns an iterator that yields only the first `n` values of this + /// iterator. + #[inline] + fn take(self, n: usize) -> Take + where + Self: Sized, + { + Take { + it: self, + remaining: n, + } + } + + /// Returns an iterator which applies a stateful map to values of this + /// iterator. + #[inline] + fn scan(self, initial_state: St, f: F) -> Scan + where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Result, Self::Error>, + { + Scan { + it: self, + f, + state: initial_state, + } + } + + /// Returns an iterator which maps this iterator's elements to iterators, yielding those iterators' values. + #[inline] + fn flat_map(self, f: F) -> FlatMap + where + Self: Sized, + U: IntoFallibleIterator, + F: FnMut(Self::Item) -> Result, + { + FlatMap { + it: self.map(f), + cur: None, + } + } + + /// Returns an iterator which flattens an iterator of iterators, yielding those iterators' values. + #[inline] + fn flatten(self) -> Flatten + where + Self: Sized, + Self::Item: IntoFallibleIterator, + { + Flatten { + it: self, + cur: None, + } + } + + /// Returns an iterator which yields this iterator's elements and ends after + /// the first `Ok(None)`. + /// + /// The behavior of calling `next` after it has previously returned + /// `Ok(None)` is normally unspecified. The iterator returned by this method + /// guarantees that `Ok(None)` will always be returned. + #[inline] + fn fuse(self) -> Fuse + where + Self: Sized, + { + Fuse { + it: self, + done: false, + } + } + + /// Returns an iterator which passes each element to a closure before returning it. + #[inline] + fn inspect(self, f: F) -> Inspect + where + Self: Sized, + F: FnMut(&Self::Item) -> Result<(), Self::Error>, + { + Inspect { it: self, f } + } + + /// Borrow an iterator rather than consuming it. + /// + /// This is useful to allow the use of iterator adaptors that would + /// otherwise consume the value. + #[inline] + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } + + /// Transforms the iterator into a collection. + /// + /// An `Err` will be returned if any invocation of `next` returns `Err`. + #[inline] + fn collect(self) -> Result + where + T: iter::FromIterator, + Self: Sized, + { + self.iterator().collect() + } + + /// Transforms the iterator into two collections, partitioning elements by a closure. + #[inline] + fn partition(self, mut f: F) -> Result<(B, B), Self::Error> + where + Self: Sized, + B: Default + Extend, + F: FnMut(&Self::Item) -> Result, + { + let mut a = B::default(); + let mut b = B::default(); + + self.for_each(|i| { + if f(&i)? { + a.extend(Some(i)); + } else { + b.extend(Some(i)); + } + Ok(()) + })?; + + Ok((a, b)) + } + + /// Applies a function over the elements of the iterator, producing a single + /// final value. + #[inline] + fn fold(mut self, init: B, f: F) -> Result + where + Self: Sized, + F: FnMut(B, Self::Item) -> Result, + { + self.try_fold(init, f) + } + + /// Applies a function over the elements of the iterator, producing a single final value. + /// + /// This is used as the "base" of many methods on `FallibleIterator`. + #[inline] + fn try_fold(&mut self, mut init: B, mut f: F) -> Result + where + Self: Sized, + E: From, + F: FnMut(B, Self::Item) -> Result, + { + while let Some(v) = self.next()? { + init = f(init, v)?; + } + Ok(init) + } + + /// Determines if all elements of this iterator match a predicate. + #[inline] + fn all(&mut self, mut f: F) -> Result + where + Self: Sized, + F: FnMut(Self::Item) -> Result, + { + self.try_fold((), |(), v| { + if !f(v)? { + return Err(FoldStop::Break(false)); + } + Ok(()) + }) + .map(|()| true) + .unpack_fold() + } + + /// Determines if any element of this iterator matches a predicate. + #[inline] + fn any(&mut self, mut f: F) -> Result + where + Self: Sized, + F: FnMut(Self::Item) -> Result, + { + self.try_fold((), |(), v| { + if f(v)? { + return Err(FoldStop::Break(true)); + } + Ok(()) + }) + .map(|()| false) + .unpack_fold() + } + + /// Returns the first element of the iterator that matches a predicate. + #[inline] + fn find(&mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item) -> Result, + { + self.try_fold((), |(), v| { + if f(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + /// Applies a function to the elements of the iterator, returning the first non-`None` result. + #[inline] + fn find_map(&mut self, f: F) -> Result, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result, Self::Error>, + { + self.filter_map(f).next() + } + + /// Returns the position of the first element of this iterator that matches + /// a predicate. The predicate may fail; such failures are returned to the + /// caller. + #[inline] + fn position(&mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + F: FnMut(Self::Item) -> Result, + { + self.try_fold(0, |n, v| { + if f(v)? { + return Err(FoldStop::Break(Some(n))); + } + Ok(n + 1) + }) + .map(|_| None) + .unpack_fold() + } + + /// Returns the maximal element of the iterator. + #[inline] + fn max(self) -> Result, Self::Error> + where + Self: Sized, + Self::Item: Ord, + { + self.max_by(|a, b| Ok(a.cmp(b))) + } + + /// Returns the element of the iterator which gives the maximum value from + /// the function. + #[inline] + fn max_by_key(mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + B: Ord, + F: FnMut(&Self::Item) -> Result, + { + let max = match self.next()? { + Some(v) => (f(&v)?, v), + None => return Ok(None), + }; + + self.fold(max, |(key, max), v| { + let new_key = f(&v)?; + if key > new_key { + Ok((key, max)) + } else { + Ok((new_key, v)) + } + }) + .map(|v| Some(v.1)) + } + + /// Returns the element that gives the maximum value with respect to the function. + #[inline] + fn max_by(mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Result, + { + let max = match self.next()? { + Some(v) => v, + None => return Ok(None), + }; + + self.fold(max, |max, v| { + if f(&max, &v)? == Ordering::Greater { + Ok(max) + } else { + Ok(v) + } + }) + .map(Some) + } + + /// Returns the minimal element of the iterator. + #[inline] + fn min(self) -> Result, Self::Error> + where + Self: Sized, + Self::Item: Ord, + { + self.min_by(|a, b| Ok(a.cmp(b))) + } + + /// Returns the element of the iterator which gives the minimum value from + /// the function. + #[inline] + fn min_by_key(mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + B: Ord, + F: FnMut(&Self::Item) -> Result, + { + let min = match self.next()? { + Some(v) => (f(&v)?, v), + None => return Ok(None), + }; + + self.fold(min, |(key, min), v| { + let new_key = f(&v)?; + if key < new_key { + Ok((key, min)) + } else { + Ok((new_key, v)) + } + }) + .map(|v| Some(v.1)) + } + + /// Returns the element that gives the minimum value with respect to the function. + #[inline] + fn min_by(mut self, mut f: F) -> Result, Self::Error> + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Result, + { + let min = match self.next()? { + Some(v) => v, + None => return Ok(None), + }; + + self.fold(min, |min, v| { + if f(&min, &v)? == Ordering::Less { + Ok(min) + } else { + Ok(v) + } + }) + .map(Some) + } + + /// Returns an iterator that yields this iterator's items in the opposite + /// order. + #[inline] + fn rev(self) -> Rev + where + Self: Sized + DoubleEndedFallibleIterator, + { + Rev(self) + } + + /// Converts an iterator of pairs into a pair of containers. + #[inline] + fn unzip(self) -> Result<(FromA, FromB), Self::Error> + where + Self: Sized + FallibleIterator, + FromA: Default + Extend, + FromB: Default + Extend, + { + let mut from_a = FromA::default(); + let mut from_b = FromB::default(); + + self.for_each(|(a, b)| { + from_a.extend(Some(a)); + from_b.extend(Some(b)); + Ok(()) + })?; + + Ok((from_a, from_b)) + } + + /// Returns an iterator which clones all of its elements. + #[inline] + fn cloned<'a, T>(self) -> Cloned + where + Self: Sized + FallibleIterator, + T: 'a + Clone, + { + Cloned(self) + } + + /// Returns an iterator which repeats this iterator endlessly. + #[inline] + fn cycle(self) -> Cycle + where + Self: Sized + Clone, + { + Cycle { + it: self.clone(), + cur: self, + } + } + + /// Lexicographically compares the elements of this iterator to that of + /// another. + #[inline] + fn cmp(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: Ord, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(Ordering::Equal), + (None, _) => return Ok(Ordering::Less), + (_, None) => return Ok(Ordering::Greater), + (Some(x), Some(y)) => match x.cmp(&y) { + Ordering::Equal => {} + o => return Ok(o), + }, + } + } + } + + /// Lexicographically compares the elements of this iterator to that of + /// another. + #[inline] + fn partial_cmp(mut self, other: I) -> Result, Self::Error> + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialOrd, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(Some(Ordering::Equal)), + (None, _) => return Ok(Some(Ordering::Less)), + (_, None) => return Ok(Some(Ordering::Greater)), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Equal) => {} + o => return Ok(o), + }, + } + } + } + + /// Determines if the elements of this iterator are equal to those of + /// another. + #[inline] + fn eq(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialEq, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) | (_, None) => return Ok(false), + (Some(x), Some(y)) => { + if x != y { + return Ok(false); + } + } + } + } + } + + /// Determines if the elements of this iterator are not equal to those of + /// another. + #[inline] + fn ne(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialEq, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) | (_, None) => return Ok(true), + (Some(x), Some(y)) => { + if x != y { + return Ok(true); + } + } + } + } + } + + /// Determines if the elements of this iterator are lexicographically less + /// than those of another. + #[inline] + fn lt(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialOrd, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) => return Ok(true), + (_, None) => return Ok(false), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(true), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(false), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically less + /// than or equal to those of another. + #[inline] + fn le(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialOrd, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) => return Ok(true), + (_, None) => return Ok(false), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(true), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(false), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically + /// greater than those of another. + #[inline] + fn gt(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialOrd, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(false), + (None, _) => return Ok(false), + (_, None) => return Ok(true), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(false), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(true), + None => return Ok(false), + }, + } + } + } + + /// Determines if the elements of this iterator are lexicographically + /// greater than or equal to those of another. + #[inline] + fn ge(mut self, other: I) -> Result + where + Self: Sized, + I: IntoFallibleIterator, + Self::Item: PartialOrd, + { + let mut other = other.into_fallible_iter(); + + loop { + match (self.next()?, other.next()?) { + (None, None) => return Ok(true), + (None, _) => return Ok(false), + (_, None) => return Ok(true), + (Some(x), Some(y)) => match x.partial_cmp(&y) { + Some(Ordering::Less) => return Ok(false), + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => return Ok(true), + None => return Ok(false), + }, + } + } + } + + /// Returns a normal (non-fallible) iterator over `Result`. + #[inline] + fn iterator(self) -> Iterator + where + Self: Sized, + { + Iterator(self) + } + + /// Returns an iterator which applies a transform to the errors of the + /// underlying iterator. + #[inline] + fn map_err(self, f: F) -> MapErr + where + F: FnMut(Self::Error) -> B, + Self: Sized, + { + MapErr { it: self, f } + } + + /// Returns an iterator which unwraps all of its elements. + #[inline] + fn unwrap(self) -> Unwrap + where + Self: Sized + FallibleIterator, + Self::Error: core::fmt::Debug, + { + Unwrap(self) + } +} + +impl FallibleIterator for &mut I { + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + (**self).next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result, I::Error> { + (**self).nth(n) + } +} + +impl DoubleEndedFallibleIterator for &mut I { + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + (**self).next_back() + } +} + +#[cfg(feature = "alloc")] +impl FallibleIterator for Box { + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + (**self).next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result, I::Error> { + (**self).nth(n) + } +} + +#[cfg(feature = "alloc")] +impl DoubleEndedFallibleIterator for Box { + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + (**self).next_back() + } +} + +/// A fallible iterator able to yield elements from both ends. +pub trait DoubleEndedFallibleIterator: FallibleIterator { + /// Advances the end of the iterator, returning the last value. + fn next_back(&mut self) -> Result, Self::Error>; + + /// Applies a function over the elements of the iterator in reverse order, producing a single final value. + #[inline] + fn rfold(mut self, init: B, f: F) -> Result + where + Self: Sized, + F: FnMut(B, Self::Item) -> Result, + { + self.try_rfold(init, f) + } + + /// Applies a function over the elements of the iterator in reverse, producing a single final value. + /// + /// This is used as the "base" of many methods on `DoubleEndedFallibleIterator`. + #[inline] + fn try_rfold(&mut self, mut init: B, mut f: F) -> Result + where + Self: Sized, + E: From, + F: FnMut(B, Self::Item) -> Result, + { + while let Some(v) = self.next_back()? { + init = f(init, v)?; + } + Ok(init) + } +} + +/// Conversion into a `FallibleIterator`. +pub trait IntoFallibleIterator { + /// The elements of the iterator. + type Item; + + /// The error value of the iterator. + type Error; + + /// The iterator. + type IntoFallibleIter: FallibleIterator; + + /// Creates a fallible iterator from a value. + fn into_fallible_iter(self) -> Self::IntoFallibleIter; +} + +impl IntoFallibleIterator for I +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + type IntoFallibleIter = I; + + #[inline] + fn into_fallible_iter(self) -> I { + self + } +} + +/// An iterator which applies a fallible transform to the elements of the +/// underlying iterator. +#[derive(Clone)] +pub struct Map { + it: T, + f: F, +} + +impl core::fmt::Debug for Map { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Map").field("iter", &self.it).finish() + } +} + +impl FallibleIterator for Map +where + T: FallibleIterator, + F: FnMut(T::Item) -> Result, +{ + type Item = B; + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result, T::Error> { + match self.it.next() { + Ok(Some(v)) => Ok(Some((self.f)(v)?)), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, B) -> Result, + { + let map = &mut self.f; + self.it.try_fold(init, |b, v| f(b, map(v)?)) + } +} + +impl DoubleEndedFallibleIterator for Map +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Item) -> Result, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + match self.it.next_back() { + Ok(Some(v)) => Ok(Some((self.f)(v)?)), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + + #[inline] + fn try_rfold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, B) -> Result, + { + let map = &mut self.f; + self.it.try_rfold(init, |acc, v| f(acc, map(v)?)) + } +} + +#[derive(Clone, Debug)] +enum ChainState { + Both, + Front, + Back, +} + +/// An iterator which yields the elements of one iterator followed by another. +#[derive(Clone, Debug)] +pub struct Chain { + front: T, + back: U, + state: ChainState, +} + +impl FallibleIterator for Chain +where + T: FallibleIterator, + U: FallibleIterator, +{ + type Item = T::Item; + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result, T::Error> { + match self.state { + ChainState::Both => match self.front.next()? { + Some(e) => Ok(Some(e)), + None => { + self.state = ChainState::Back; + self.back.next() + } + }, + ChainState::Front => self.front.next(), + ChainState::Back => self.back.next(), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let front_hint = self.front.size_hint(); + let back_hint = self.back.size_hint(); + + let low = front_hint.0.saturating_add(back_hint.0); + let high = match (front_hint.1, back_hint.1) { + (Some(f), Some(b)) => f.checked_add(b), + _ => None, + }; + + (low, high) + } + + #[inline] + fn count(self) -> Result { + match self.state { + ChainState::Both => Ok(self.front.count()? + self.back.count()?), + ChainState::Front => self.front.count(), + ChainState::Back => self.back.count(), + } + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, T::Item) -> Result, + { + match self.state { + ChainState::Both => { + let init = self.front.try_fold(init, &mut f)?; + self.state = ChainState::Back; + self.back.try_fold(init, f) + } + ChainState::Front => self.front.try_fold(init, f), + ChainState::Back => self.back.try_fold(init, f), + } + } + + #[inline] + fn find(&mut self, mut f: F) -> Result, T::Error> + where + F: FnMut(&T::Item) -> Result, + { + match self.state { + ChainState::Both => match self.front.find(&mut f)? { + Some(v) => Ok(Some(v)), + None => { + self.state = ChainState::Back; + self.back.find(f) + } + }, + ChainState::Front => self.front.find(f), + ChainState::Back => self.back.find(f), + } + } + + #[inline] + fn last(self) -> Result, T::Error> { + match self.state { + ChainState::Both => { + self.front.last()?; + self.back.last() + } + ChainState::Front => self.front.last(), + ChainState::Back => self.back.last(), + } + } +} + +impl DoubleEndedFallibleIterator for Chain +where + T: DoubleEndedFallibleIterator, + U: DoubleEndedFallibleIterator, +{ + #[inline] + fn next_back(&mut self) -> Result, T::Error> { + match self.state { + ChainState::Both => match self.back.next_back()? { + Some(e) => Ok(Some(e)), + None => { + self.state = ChainState::Front; + self.front.next_back() + } + }, + ChainState::Front => self.front.next_back(), + ChainState::Back => self.back.next_back(), + } + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, T::Item) -> Result, + { + match self.state { + ChainState::Both => { + let init = self.back.try_rfold(init, &mut f)?; + self.state = ChainState::Front; + self.front.try_rfold(init, f) + } + ChainState::Front => self.front.try_rfold(init, f), + ChainState::Back => self.back.try_rfold(init, f), + } + } +} + +/// An iterator which clones the elements of the underlying iterator. +#[derive(Clone, Debug)] +pub struct Cloned(I); + +impl<'a, T, I> FallibleIterator for Cloned +where + I: FallibleIterator, + T: 'a + Clone, +{ + type Item = T; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + self.0.next().map(|o| o.cloned()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, T) -> Result, + { + self.0.try_fold(init, |acc, v| f(acc, v.clone())) + } +} + +impl<'a, T, I> DoubleEndedFallibleIterator for Cloned +where + I: DoubleEndedFallibleIterator, + T: 'a + Clone, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + self.0.next_back().map(|o| o.cloned()) + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, T) -> Result, + { + self.0.try_rfold(init, |acc, v| f(acc, v.clone())) + } +} + +/// Converts an `Iterator>` into a `FallibleIterator`. +#[inline] +pub fn convert(it: I) -> Convert +where + I: iter::Iterator>, +{ + Convert(it) +} + +/// A fallible iterator that wraps a normal iterator over `Result`s. +#[derive(Clone, Debug)] +pub struct Convert(I); + +impl FallibleIterator for Convert +where + I: iter::Iterator>, +{ + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, E> { + match self.0.next() { + Some(Ok(i)) => Ok(Some(i)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> Result + where + E2: From, + F: FnMut(B, T) -> Result, + { + self.0.try_fold(init, |acc, v| f(acc, v?)) + } +} + +impl DoubleEndedFallibleIterator for Convert +where + I: DoubleEndedIterator>, +{ + #[inline] + fn next_back(&mut self) -> Result, E> { + match self.0.next_back() { + Some(Ok(i)) => Ok(Some(i)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> Result + where + E2: From, + F: FnMut(B, T) -> Result, + { + self.0.try_rfold(init, |acc, v| f(acc, v?)) + } +} + +/// A fallible iterator that wraps a normal iterator over `Result`s. +#[derive(Clone, Debug)] +pub struct IntoFallible(I); + +impl FallibleIterator for IntoFallible +where + I: iter::Iterator, +{ + type Item = T; + type Error = Infallible; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + Ok(self.0.next()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> Result + where + E2: From, + F: FnMut(B, T) -> Result, + { + self.0.try_fold(init, f) + } +} + +impl> From for IntoFallible { + fn from(value: I) -> Self { + Self(value) + } +} + +impl DoubleEndedFallibleIterator for IntoFallible +where + I: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Result, Infallible> { + Ok(self.0.next_back()) + } + + #[inline] + fn try_rfold(&mut self, init: B, f: F) -> Result + where + E2: From, + F: FnMut(B, T) -> Result, + { + self.0.try_rfold(init, f) + } +} + +/// An iterator that yields the iteration count as well as the values of the +/// underlying iterator. +#[derive(Clone, Debug)] +pub struct Enumerate { + it: I, + n: usize, +} + +impl FallibleIterator for Enumerate +where + I: FallibleIterator, +{ + type Item = (usize, I::Item); + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + self.it.next().map(|o| { + o.map(|e| { + let i = self.n; + self.n += 1; + (i, e) + }) + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + #[inline] + fn count(self) -> Result { + self.it.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Result, I::Error> { + match self.it.nth(n)? { + Some(v) => { + let i = self.n + n; + self.n = i + 1; + Ok(Some((i, v))) + } + None => Ok(None), + } + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, (usize, I::Item)) -> Result, + { + let n = &mut self.n; + self.it.try_fold(init, |acc, v| { + let i = *n; + *n += 1; + f(acc, (i, v)) + }) + } +} + +/// An iterator which uses a fallible predicate to determine which values of the +/// underlying iterator should be yielded. +#[derive(Clone, Debug)] +pub struct Filter { + it: I, + f: F, +} + +impl FallibleIterator for Filter +where + I: FallibleIterator, + F: FnMut(&I::Item) -> Result, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + let filter = &mut self.f; + self.it + .try_fold((), |(), v| { + if filter(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.it.size_hint().1) + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, I::Item) -> Result, + { + let predicate = &mut self.f; + self.it.try_fold( + init, + |acc, v| { + if predicate(&v)? { + f(acc, v) + } else { + Ok(acc) + } + }, + ) + } +} + +impl DoubleEndedFallibleIterator for Filter +where + I: DoubleEndedFallibleIterator, + F: FnMut(&I::Item) -> Result, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + let filter = &mut self.f; + self.it + .try_rfold((), |(), v| { + if filter(&v)? { + return Err(FoldStop::Break(Some(v))); + } + Ok(()) + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, I::Item) -> Result, + { + let predicate = &mut self.f; + self.it.try_rfold( + init, + |acc, v| { + if predicate(&v)? { + f(acc, v) + } else { + Ok(acc) + } + }, + ) + } +} + +/// An iterator which both filters and maps the values of the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct FilterMap { + it: I, + f: F, +} + +impl FallibleIterator for FilterMap +where + I: FallibleIterator, + F: FnMut(I::Item) -> Result, I::Error>, +{ + type Item = B; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + let map = &mut self.f; + self.it + .try_fold((), |(), v| match map(v)? { + Some(v) => Err(FoldStop::Break(Some(v))), + None => Ok(()), + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.it.size_hint().1) + } + + #[inline] + fn try_fold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, B) -> Result, + { + let map = &mut self.f; + self.it.try_fold(init, |acc, v| match map(v)? { + Some(v) => f(acc, v), + None => Ok(acc), + }) + } +} + +impl DoubleEndedFallibleIterator for FilterMap +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Item) -> Result, I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + let map = &mut self.f; + self.it + .try_rfold((), |(), v| match map(v)? { + Some(v) => Err(FoldStop::Break(Some(v))), + None => Ok(()), + }) + .map(|()| None) + .unpack_fold() + } + + #[inline] + fn try_rfold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, B) -> Result, + { + let map = &mut self.f; + self.it.try_rfold(init, |acc, v| match map(v)? { + Some(v) => f(acc, v), + None => Ok(acc), + }) + } +} + +/// An iterator which maps each element to another iterator, yielding those iterator's elements. +#[derive(Clone, Debug)] +pub struct FlatMap +where + U: IntoFallibleIterator, +{ + it: Map, + cur: Option, +} + +impl FallibleIterator for FlatMap +where + I: FallibleIterator, + U: IntoFallibleIterator, + F: FnMut(I::Item) -> Result, +{ + type Item = U::Item; + type Error = U::Error; + + #[inline] + fn next(&mut self) -> Result, U::Error> { + loop { + if let Some(it) = &mut self.cur { + if let Some(v) = it.next()? { + return Ok(Some(v)); + } + } + match self.it.next()? { + Some(it) => self.cur = Some(it.into_fallible_iter()), + None => return Ok(None), + } + } + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, U::Item) -> Result, + { + let mut acc = init; + if let Some(cur) = &mut self.cur { + acc = cur.try_fold(acc, &mut f)?; + self.cur = None; + } + + let cur = &mut self.cur; + self.it.try_fold(acc, |acc, v| { + let mut it = v.into_fallible_iter(); + match it.try_fold(acc, &mut f) { + Ok(acc) => Ok(acc), + Err(e) => { + *cur = Some(it); + Err(e) + } + } + }) + } +} + +/// An iterator which flattens an iterator of iterators, yielding those iterators' elements. +pub struct Flatten +where + I: FallibleIterator, + I::Item: IntoFallibleIterator, +{ + it: I, + cur: Option<::IntoFallibleIter>, +} + +impl Clone for Flatten +where + I: FallibleIterator + Clone, + I::Item: IntoFallibleIterator, + ::IntoFallibleIter: Clone, +{ + #[inline] + fn clone(&self) -> Flatten { + Flatten { + it: self.it.clone(), + cur: self.cur.clone(), + } + } +} + +impl FallibleIterator for Flatten +where + I: FallibleIterator, + I::Item: IntoFallibleIterator, +{ + type Item = ::Item; + type Error = ::Error; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + loop { + if let Some(it) = &mut self.cur { + if let Some(v) = it.next()? { + return Ok(Some(v)); + } + } + match self.it.next()? { + Some(it) => self.cur = Some(it.into_fallible_iter()), + None => return Ok(None), + } + } + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, Self::Item) -> Result, + { + let mut acc = init; + if let Some(cur) = &mut self.cur { + acc = cur.try_fold(acc, &mut f)?; + self.cur = None; + } + + let cur = &mut self.cur; + self.it.try_fold(acc, |acc, v| { + let mut it = v.into_fallible_iter(); + match it.try_fold(acc, &mut f) { + Ok(acc) => Ok(acc), + Err(e) => { + *cur = Some(it); + Err(e) + } + } + }) + } +} + +/// Creates an iterator from a fallible function generating values. +/// +/// ``` +/// # use fallible_iterator::{from_fn, FallibleIterator}; +/// let mut count = 0; +/// let counter = from_fn(move || { +/// // Increment our count. This is why we started at zero. +/// count += 1; +/// +/// // Check to see if we've finished counting or not. +/// if count < 6 { +/// Ok(Some(count)) +/// } else if count < 7 { +/// Ok(None) +/// } else { +/// Err(()) +/// } +/// }); +/// assert_eq!(&counter.collect::>().unwrap(), &[1, 2, 3, 4, 5]); +/// ``` +#[inline] +pub fn from_fn(fun: F) -> FromFn +where + F: FnMut() -> Result, E>, +{ + FromFn { fun } +} + +/// An iterator using a function to generate new values. +#[derive(Clone, Debug)] +pub struct FromFn { + fun: F, +} + +impl FallibleIterator for FromFn +where + F: FnMut() -> Result, E>, +{ + type Item = I; + type Error = E; + + fn next(&mut self) -> Result, E> { + (self.fun)() + } +} + +/// An iterator that yields `Ok(None)` forever after the underlying iterator +/// yields `Ok(None)` once. +#[derive(Clone, Debug)] +pub struct Fuse { + it: I, + done: bool, +} + +impl FallibleIterator for Fuse +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if self.done { + return Ok(None); + } + + match self.it.next()? { + Some(i) => Ok(Some(i)), + None => { + self.done = true; + Ok(None) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.done { + (0, Some(0)) + } else { + self.it.size_hint() + } + } + + #[inline] + fn count(self) -> Result { + if self.done { + Ok(0) + } else { + self.it.count() + } + } + + #[inline] + fn last(self) -> Result, I::Error> { + if self.done { + Ok(None) + } else { + self.it.last() + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Result, I::Error> { + if self.done { + Ok(None) + } else { + let v = self.it.nth(n)?; + if v.is_none() { + self.done = true; + } + Ok(v) + } + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> Result + where + E: From, + F: FnMut(B, I::Item) -> Result, + { + if self.done { + Ok(init) + } else { + self.it.try_fold(init, f) + } + } +} + +/// An iterator which passes each element to a closure before returning it. +#[derive(Clone, Debug)] +pub struct Inspect { + it: I, + f: F, +} + +impl FallibleIterator for Inspect +where + I: FallibleIterator, + F: FnMut(&I::Item) -> Result<(), I::Error>, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + match self.it.next()? { + Some(i) => { + (self.f)(&i)?; + Ok(Some(i)) + } + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, I::Item) -> Result, + { + let inspect = &mut self.f; + self.it.try_fold(init, |acc, v| { + inspect(&v)?; + f(acc, v) + }) + } +} + +impl DoubleEndedFallibleIterator for Inspect +where + I: DoubleEndedFallibleIterator, + F: FnMut(&I::Item) -> Result<(), I::Error>, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + match self.it.next_back()? { + Some(i) => { + (self.f)(&i)?; + Ok(Some(i)) + } + None => Ok(None), + } + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: G) -> Result + where + E: From, + G: FnMut(B, I::Item) -> Result, + { + let inspect = &mut self.f; + self.it.try_rfold(init, |acc, v| { + inspect(&v)?; + f(acc, v) + }) + } +} + +/// A normal (non-fallible) iterator which wraps a fallible iterator. +#[derive(Clone, Debug)] +pub struct Iterator(I); + +impl iter::Iterator for Iterator +where + I: FallibleIterator, +{ + type Item = Result; + + #[inline] + fn next(&mut self) -> Option> { + match self.0.next() { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +impl DoubleEndedIterator for Iterator +where + I: DoubleEndedFallibleIterator, +{ + #[inline] + fn next_back(&mut self) -> Option> { + match self.0.next_back() { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + +/// An iterator which applies a transform to the errors of the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct MapErr { + it: I, + f: F, +} + +impl FallibleIterator for MapErr +where + I: FallibleIterator, + F: FnMut(I::Error) -> B, +{ + type Item = I::Item; + type Error = B; + + #[inline] + fn next(&mut self) -> Result, B> { + self.it.next().map_err(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + #[inline] + fn count(mut self) -> Result { + self.it.count().map_err(&mut self.f) + } + + #[inline] + fn last(mut self) -> Result, B> { + self.it.last().map_err(&mut self.f) + } + + #[inline] + fn nth(&mut self, n: usize) -> Result, B> { + self.it.nth(n).map_err(&mut self.f) + } + + #[inline] + fn try_fold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, I::Item) -> Result, + { + self.it + .try_fold(init, |acc, v| f(acc, v).map_err(MappedErr::Fold)) + .map_err(|e| match e { + MappedErr::It(e) => (self.f)(e).into(), + MappedErr::Fold(e) => e, + }) + } +} + +impl DoubleEndedFallibleIterator for MapErr +where + I: DoubleEndedFallibleIterator, + F: FnMut(I::Error) -> B, +{ + #[inline] + fn next_back(&mut self) -> Result, B> { + self.it.next_back().map_err(&mut self.f) + } + + #[inline] + fn try_rfold(&mut self, init: C, mut f: G) -> Result + where + E: From, + G: FnMut(C, I::Item) -> Result, + { + self.it + .try_rfold(init, |acc, v| f(acc, v).map_err(MappedErr::Fold)) + .map_err(|e| match e { + MappedErr::It(e) => (self.f)(e).into(), + MappedErr::Fold(e) => e, + }) + } +} + +enum MappedErr { + It(T), + Fold(U), +} + +impl From for MappedErr { + #[inline] + fn from(t: T) -> MappedErr { + MappedErr::It(t) + } +} + +/// An iterator which can look at the next element without consuming it. +#[derive(Clone, Debug)] +pub struct Peekable { + it: I, + next: Option, +} + +impl Peekable +where + I: FallibleIterator, +{ + /// Returns a reference to the next value without advancing the iterator. + #[inline] + pub fn peek(&mut self) -> Result, I::Error> { + if self.next.is_none() { + self.next = self.it.next()?; + } + + Ok(self.next.as_ref()) + } + + /// Consume and return the next value of this iterator if a condition is true. + /// + /// If func returns true for the next value of this iterator, consume and return it. Otherwise, return None. + #[inline] + pub fn next_if(&mut self, f: impl Fn(&I::Item) -> bool) -> Result, I::Error> { + match self.peek()? { + Some(item) if f(item) => self.next(), + _ => Ok(None), + } + } + + /// Consume and return the next item if it is equal to `expected`. + #[inline] + pub fn next_if_eq(&mut self, expected: &T) -> Result, I::Error> + where + T: ?Sized, + I::Item: PartialEq, + { + self.next_if(|found| found == expected) + } +} + +impl FallibleIterator for Peekable +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if let Some(next) = self.next.take() { + return Ok(Some(next)); + } + + self.it.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let mut hint = self.it.size_hint(); + if self.next.is_some() { + hint.0 = hint.0.saturating_add(1); + hint.1 = hint.1.and_then(|h| h.checked_add(1)); + } + hint + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> Result + where + E: From, + F: FnMut(B, I::Item) -> Result, + { + let mut acc = init; + if let Some(v) = self.next.take() { + acc = f(acc, v)?; + } + self.it.try_fold(acc, f) + } +} + +/// An iterator which yields elements of the underlying iterator in reverse +/// order. +#[derive(Clone, Debug)] +pub struct Rev(I); + +impl FallibleIterator for Rev +where + I: DoubleEndedFallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + self.0.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> Result { + self.0.count() + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> Result + where + E: From, + F: FnMut(B, I::Item) -> Result, + { + self.0.try_rfold(init, f) + } +} + +impl DoubleEndedFallibleIterator for Rev +where + I: DoubleEndedFallibleIterator, +{ + #[inline] + fn next_back(&mut self) -> Result, I::Error> { + self.0.next() + } + + #[inline] + fn try_rfold(&mut self, init: B, f: F) -> Result + where + E: From, + F: FnMut(B, I::Item) -> Result, + { + self.0.try_fold(init, f) + } +} + +/// An iterator which applies a stateful closure. +#[derive(Clone, Debug)] +pub struct Scan { + it: I, + f: F, + state: St, +} + +impl FallibleIterator for Scan +where + I: FallibleIterator, + F: FnMut(&mut St, I::Item) -> Result, I::Error>, +{ + type Item = B; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + match self.it.next()? { + Some(v) => (self.f)(&mut self.state, v), + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.it.size_hint(); + (0, hint.1) + } +} + +/// An iterator which skips initial elements. +#[derive(Clone, Debug)] +pub struct Skip { + it: I, + n: usize, +} + +impl FallibleIterator for Skip +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if self.n == 0 { + self.it.next() + } else { + let n = self.n; + self.n = 0; + self.it.nth(n) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.it.size_hint(); + + ( + hint.0.saturating_sub(self.n), + hint.1.map(|x| x.saturating_sub(self.n)), + ) + } +} + +/// An iterator which skips initial elements based on a predicate. +#[derive(Clone, Debug)] +pub struct SkipWhile { + it: I, + flag: bool, + predicate: P, +} + +impl FallibleIterator for SkipWhile +where + I: FallibleIterator, + P: FnMut(&I::Item) -> Result, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + let flag = &mut self.flag; + let pred = &mut self.predicate; + self.it.find(move |x| { + if *flag || !pred(x)? { + *flag = true; + Ok(true) + } else { + Ok(false) + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.it.size_hint(); + if self.flag { + hint + } else { + (0, hint.1) + } + } +} + +/// An iterator which steps through the elements of the underlying iterator by a certain amount. +#[derive(Clone, Debug)] +pub struct StepBy { + it: I, + step: usize, + first_take: bool, +} + +impl FallibleIterator for StepBy +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if self.first_take { + self.first_take = false; + self.it.next() + } else { + self.it.nth(self.step) + } + } + + fn size_hint(&self) -> (usize, Option) { + let inner_hint = self.it.size_hint(); + + if self.first_take { + let f = |n| { + if n == 0 { + 0 + } else { + 1 + (n - 1) / (self.step + 1) + } + }; + (f(inner_hint.0), inner_hint.1.map(f)) + } else { + let f = |n| n / (self.step + 1); + (f(inner_hint.0), inner_hint.1.map(f)) + } + } +} + +/// An iterator which yields a limited number of elements from the underlying +/// iterator. +#[derive(Clone, Debug)] +pub struct Take { + it: I, + remaining: usize, +} + +impl FallibleIterator for Take +where + I: FallibleIterator, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if self.remaining == 0 { + return Ok(None); + } + + let next = self.it.next(); + if let Ok(Some(_)) = next { + self.remaining -= 1; + } + next + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.it.size_hint(); + ( + cmp::min(hint.0, self.remaining), + hint.1.map(|n| cmp::min(n, self.remaining)), + ) + } +} + +/// An iterator which yields elements based on a predicate. +#[derive(Clone, Debug)] +pub struct TakeWhile { + it: I, + flag: bool, + predicate: P, +} + +impl FallibleIterator for TakeWhile +where + I: FallibleIterator, + P: FnMut(&I::Item) -> Result, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + if self.flag { + Ok(None) + } else { + match self.it.next()? { + Some(item) => { + if (self.predicate)(&item)? { + Ok(Some(item)) + } else { + self.flag = true; + Ok(None) + } + } + None => Ok(None), + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.flag { + (0, Some(0)) + } else { + let hint = self.it.size_hint(); + (0, hint.1) + } + } +} + +/// An iterator which cycles another endlessly. +#[derive(Clone, Debug)] +pub struct Cycle { + it: I, + cur: I, +} + +impl FallibleIterator for Cycle +where + I: FallibleIterator + Clone, +{ + type Item = I::Item; + type Error = I::Error; + + #[inline] + fn next(&mut self) -> Result, I::Error> { + match self.cur.next()? { + None => { + self.cur = self.it.clone(); + self.cur.next() + } + Some(v) => Ok(Some(v)), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} + +/// An iterator that yields pairs of this iterator's and another iterator's +/// values. +#[derive(Clone, Debug)] +pub struct Zip(T, U); + +impl FallibleIterator for Zip +where + T: FallibleIterator, + U: FallibleIterator, +{ + type Item = (T::Item, U::Item); + type Error = T::Error; + + #[inline] + fn next(&mut self) -> Result, T::Error> { + match (self.0.next()?, self.1.next()?) { + (Some(a), Some(b)) => Ok(Some((a, b))), + _ => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let a = self.0.size_hint(); + let b = self.1.size_hint(); + + let low = cmp::min(a.0, b.0); + + let high = match (a.1, b.1) { + (Some(a), Some(b)) => Some(cmp::min(a, b)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + }; + + (low, high) + } +} + +/// An iterator that unwraps every element yielded by the underlying +/// FallibleIterator +#[derive(Clone, Debug)] +pub struct Unwrap(T); + +impl iter::Iterator for Unwrap +where + T: FallibleIterator, + T::Error: core::fmt::Debug, +{ + type Item = T::Item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next().unwrap() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, max) = self.0.size_hint(); + (0, max) + } +} + +fn _is_object_safe(_: &dyn DoubleEndedFallibleIterator) {} + +/// An extnsion-trait with set of useful methods to convert [`core::iter::Iterator`] +/// into [`FallibleIterator`] +pub trait IteratorExt { + /// Convert an iterator of `Result`s into `FallibleIterator` by transposition + fn transpose_into_fallible(self) -> Convert + where + Self: iter::Iterator> + Sized; + + /// Convert an iterator of anything into `FallibleIterator` by wrapping + /// into `Result` where `Infallible` is an error that can never actually + /// happen. + fn into_fallible(self) -> IntoFallible + where + Self: iter::Iterator + Sized; +} + +impl IteratorExt for I +where + I: iter::Iterator, +{ + /// Convert an iterator of `Result`s into `FallibleIterator` by transposition + fn transpose_into_fallible(self) -> Convert + where + Self: iter::Iterator> + Sized, + { + Convert(self) + } + + /// Convert an iterator of anything into `FallibleIterator` by wrapping + /// into `Result` where `Infallible` is an error that can never actually + /// happen. + fn into_fallible(self) -> IntoFallible + where + Self: iter::Iterator + Sized, + { + IntoFallible(self) + } +} + +/// An iterator that yields nothing. +#[derive(Clone, Debug)] +pub struct Empty(PhantomData, PhantomData); + +impl FallibleIterator for Empty { + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, E> { + Ok(None) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +/// Creates an iterator that yields nothing. +pub fn empty() -> Empty { + Empty(PhantomData, PhantomData) +} + +/// An iterator that yields something exactly once. +#[derive(Clone, Debug)] +pub struct Once(Option, PhantomData); + +/// Creates an iterator that yields an element exactly once. +pub fn once(value: T) -> Once { + Once(Some(value), PhantomData) +} + +impl FallibleIterator for Once { + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + Ok(self.0.take()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + match self.0 { + Some(_) => (1, Some(1)), + None => (0, Some(0)), + } + } +} + +/// An iterator that fails with a predetermined error exactly once. +#[derive(Clone, Debug)] +pub struct OnceErr(PhantomData, Option); + +/// Creates an iterator that fails with a predetermined error exactly once. +pub fn once_err(value: E) -> OnceErr { + OnceErr(PhantomData, Some(value)) +} + +impl FallibleIterator for OnceErr { + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + match self.1.take() { + Some(value) => Err(value), + None => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +/// An iterator that endlessly repeats a single element. +#[derive(Clone, Debug)] +pub struct Repeat(T, PhantomData); + +/// Creates an iterator that endlessly repeats a single element. +pub fn repeat(value: T) -> Repeat { + Repeat(value, PhantomData) +} + +impl FallibleIterator for Repeat { + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + Ok(Some(self.0.clone())) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} + +/// An iterator that endlessly repeats a single error. +#[derive(Clone, Debug)] +pub struct RepeatErr(PhantomData, E); + +/// Creates an iterator that endlessly repeats a single error. +pub fn repeat_err(value: E) -> RepeatErr { + RepeatErr(PhantomData, value) +} + +impl FallibleIterator for RepeatErr { + type Item = T; + type Error = E; + + #[inline] + fn next(&mut self) -> Result, Self::Error> { + Err(self.1.clone()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/deps/crates/vendor/fallible-iterator/src/test.rs b/deps/crates/vendor/fallible-iterator/src/test.rs new file mode 100644 index 00000000000000..218c6929f5d1e7 --- /dev/null +++ b/deps/crates/vendor/fallible-iterator/src/test.rs @@ -0,0 +1,477 @@ +use alloc::{vec, vec::Vec}; +use core::{iter, ops::Range}; + +use super::{convert, FallibleIterator, IntoFallible}; + +#[test] +fn all() { + assert!(convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .all(|&i| Ok(i < 4)) + .unwrap()); + assert!(!convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .all(|&i| Ok(i < 4)) + .unwrap()); + assert!(convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .all(|_| Err(())) + .is_err()); +} + +#[test] +fn any() { + assert!(convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .any(|&i| Ok(i == 3)) + .unwrap()); + assert!(!convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .any(|&i| Ok(i == 3)) + .unwrap()); + assert!(convert([0, 1, 2, 4].iter().map(Ok::<&u32, ()>)) + .any(|_| Err(())) + .is_err()); +} + +#[test] +fn chain() { + let a = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + let b = convert(vec![4, 5, 6, 7].into_iter().map(Ok::)); + let it = a.chain(b); + + assert_eq!(it.collect::>().unwrap(), [0, 1, 2, 3, 4, 5, 6, 7]); + + let a = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + let b = convert(vec![4, 5, 6, 7].into_iter().map(Ok::)); + let it = a.chain(b).rev(); + + assert_eq!(it.collect::>().unwrap(), [7, 6, 5, 4, 3, 2, 1, 0]); +} + +#[test] +fn count() { + assert_eq!( + convert([0, 1, 2, 3].iter().map(Ok::<&u32, ()>)) + .count() + .unwrap(), + 4 + ); + + let it = Some(Ok(1)).into_iter().chain(iter::repeat(Err(()))); + assert!(convert(it).count().is_err()); +} + +#[test] +fn enumerate() { + let it = convert(vec![5, 6, 7, 8].into_iter().map(Ok::)).enumerate(); + + assert_eq!( + it.collect::>().unwrap(), + [(0, 5), (1, 6), (2, 7), (3, 8)] + ); +} + +#[test] +fn filter() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + let it = it.filter(|&x| if x % 2 == 0 { Ok(x % 3 == 0) } else { Err(x) }); + + assert_eq!(it.clone().collect::>(), Err(1)); + assert_eq!(it.rev().collect::>(), Err(3)); + + let it = convert(vec![0, 2, 4, 6].into_iter().map(Ok::)); + let it = it.filter(|&x| if x % 2 == 0 { Ok(x % 3 == 0) } else { Err(x) }); + + assert_eq!(it.clone().collect::>(), Ok(vec![0, 6])); + assert_eq!(it.rev().collect::>(), Ok(vec![6, 0])) +} + +#[test] +fn filter_map() { + fn twos_and_threes(x: u32) -> Result, u32> { + if x % 2 == 0 { + Ok(Some(x + 10)) + } else if x % 3 == 0 { + Ok(None) + } else { + Err(x) + } + } + + let it = convert(vec![0, 1, 2, 3, 4, 5, 6].into_iter().map(Ok::)) + .filter_map(twos_and_threes); + + assert_eq!(it.clone().collect::>(), Err(1)); + assert_eq!(it.rev().collect::>(), Err(5)); + + let it = + convert(vec![0, 2, 3, 4, 6].into_iter().map(Ok::)).filter_map(twos_and_threes); + + assert_eq!(it.clone().collect::>(), Ok(vec![10, 12, 14, 16])); + assert_eq!(it.rev().collect::>(), Ok(vec![16, 14, 12, 10])); +} + +#[test] +fn find() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + + assert_eq!(it.find(|x| Ok(x % 2 == 1)), Ok(Some(1))); + assert_eq!(it.next(), Ok(Some(2))); + + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + assert_eq!( + it.clone() + .find(|&x| if x == 2 { Err(29) } else { Ok(false) }), + Err(29) + ); + assert_eq!( + it.clone() + .find(|&x| if x == 2 { Err(29) } else { Ok(true) }), + Ok(Some(0)) + ); + assert_eq!( + it.clone() + .rev() + .find(|&x| if x == 2 { Err(29) } else { Ok(false) }), + Err(29) + ); + assert_eq!( + it.rev().find(|&x| if x == 2 { Err(29) } else { Ok(true) }), + Ok(Some(3)) + ); +} + +#[test] +fn fold() { + fn add_smol(a: u32, b: u32) -> Result { + if b <= 2 { + Ok(a + b) + } else { + Err(b) + } + } + + let it = convert(vec![0, 1, 3, 2].into_iter().map(Ok::)); + assert_eq!(it.fold(0, add_smol), Err(3)); + + let it = convert(vec![0, 1, 2, 1].into_iter().map(Ok::)); + assert_eq!(it.fold(0, add_smol), Ok(4)); +} + +#[test] +fn for_each() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + + let mut acc = vec![]; + it.for_each(|n| { + acc.push(n); + Ok(()) + }) + .unwrap(); + assert_eq!(acc, vec![0, 1, 2, 3]); +} + +#[test] +fn iterator() { + let it = convert( + "ab cd" + .chars() + .map(|c| if c.is_whitespace() { Err(()) } else { Ok(c) }), + ); + + assert!(it.clone().count().is_err()); + assert!(it.clone().rev().count().is_err()); + assert_eq!(it.clone().iterator().count(), 5); + assert_eq!(it.clone().iterator().rev().count(), 5); +} + +#[test] +fn last() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + assert_eq!(it.last().unwrap(), Some(3)); +} + +#[test] +fn map() { + let it = convert(vec![0, 1, 2, 3, 4].into_iter().map(Ok::)).map(|n| Ok(n * 2)); + fn assert_debug(_: &impl core::fmt::Debug) {} + assert_debug(&it); + assert_eq!(it.clone().collect::>().unwrap(), [0, 2, 4, 6, 8]); + assert_eq!(it.rev().collect::>().unwrap(), [8, 6, 4, 2, 0]); + + let it = convert(vec![0, 1, 2, 3, 4].into_iter().map(Ok::)).map(|n| { + if n == 2 { + Err(()) + } else { + Ok(n * 2) + } + }); + + { + let mut it = it.clone(); + assert_eq!(it.next(), Ok(Some(0))); + assert_eq!(it.next(), Ok(Some(2))); + assert_eq!(it.next(), Err(())); + } + + { + let mut it = it.rev(); + assert_eq!(it.next(), Ok(Some(8))); + assert_eq!(it.next(), Ok(Some(6))); + assert_eq!(it.next(), Err(())); + } +} + +#[test] +fn map_err() { + let it = convert( + vec![0, 1, 2, 3] + .into_iter() + .map(|n| if n % 2 == 0 { Ok(n) } else { Err(n) }), + ); + + assert_eq!(it.clone().collect::>(), Err(1)); + assert_eq!(it.rev().collect::>(), Err(3)); +} + +#[test] +fn max() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::)); + assert_eq!(it.max().unwrap(), Some(3)); +} + +#[test] +fn max_by_key() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::)); + assert_eq!(it.clone().max_by_key(|&i| Ok(-i)), Ok(Some(-10))); + // Exercise failure both on the first item, and later. + assert_eq!(it.clone().max_by_key(|&i| Err::(i)), Err(0)); + assert_eq!( + it.max_by_key(|&i| if i > 0 { Err(i) } else { Ok(-i) }), + Err(3) + ); +} + +#[test] +fn max_by() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::)); + assert_eq!(it.max_by(|a, b| Ok(b.cmp(a))), Ok(Some(-10))); +} + +#[test] +fn min() { + let it = convert(vec![0, 3, -10, 1].into_iter().map(Ok::)); + assert_eq!(it.min().unwrap(), Some(-10)); +} + +#[test] +fn min_by_key() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::)); + assert_eq!(it.clone().min_by_key(|&i| Ok(-i)), Ok(Some(3))); + // Exercise failure both on the first item, and later. + assert_eq!(it.clone().min_by_key(|&i| Err::(i)), Err(0)); + assert_eq!( + it.min_by_key(|&i| if i > 0 { Err(i) } else { Ok(-i) }), + Err(3) + ); +} + +#[test] +fn min_by() { + let it = convert(vec![0, 3, 1, -10].into_iter().map(Ok::)); + assert_eq!(it.min_by(|a, b| Ok(b.cmp(a))), Ok(Some(3))); +} + +#[test] +fn nth() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + assert_eq!(it.nth(1).unwrap(), Some(1)); + assert_eq!(it.nth(0).unwrap(), Some(2)); + assert_eq!(it.nth(2).unwrap(), None); +} + +#[test] +fn peekable() { + let mut it = convert(vec![0, 1].into_iter().map(Ok::)).peekable(); + assert_eq!(it.peek().unwrap(), Some(&0)); + assert_eq!(it.peek().unwrap(), Some(&0)); + assert_eq!(it.next().unwrap(), Some(0)); + assert_eq!(it.next().unwrap(), Some(1)); + assert_eq!(it.peek().unwrap(), None); + assert_eq!(it.next().unwrap(), None); +} + +#[test] +fn position() { + let mut it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::)); + assert_eq!(it.position(|n| Ok(n == 2)).unwrap(), Some(1)); + assert_eq!(it.position(|n| Ok(n == 3)).unwrap(), Some(0)); + assert_eq!(it.position(|n| Ok(n == 5)).unwrap(), None); + + let mut it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::)); + assert_eq!( + it.clone() + .position(|n| if n == 3 { Err(42) } else { Ok(n == 2) }), + Ok(Some(1)) + ); + assert_eq!( + it.position(|n| if n == 3 { Err(42) } else { Ok(n == 4) }), + Err(42) + ); +} + +#[test] +fn scan() { + let it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::)).scan(0, |st, v| { + if v > 3 { + Ok(None) + } else { + *st += v; + Ok(Some(-*st)) + } + }); + assert_eq!(it.collect::>(), Ok(vec![-1, -3, -6])); +} + +#[test] +fn skip() { + let it = convert(vec![1, 2, 3, 4].into_iter().map(Ok::)); + assert_eq!(it.clone().skip(0).collect::>(), Ok(vec![1, 2, 3, 4])); + assert_eq!(it.clone().skip(2).collect::>(), Ok(vec![3, 4])); + assert_eq!(it.skip(4).collect::>(), Ok(vec![])); +} + +#[test] +fn skip_while() { + let it = convert(vec![1, 2, 3, 4, 1].into_iter().map(Ok::)); + assert_eq!( + it.clone().skip_while(|x| Ok(*x < 1)).collect::>(), + Ok(vec![1, 2, 3, 4, 1]) + ); + assert_eq!( + it.clone().skip_while(|x| Ok(*x < 3)).collect::>(), + Ok(vec![3, 4, 1]) + ); + assert_eq!( + it.skip_while(|x| Ok(*x < 5)).collect::>(), + Ok(vec![]) + ); +} + +#[test] +fn step_by() { + let it = convert( + vec![0, 1, 2, 3, 4, 5, 6, 7, 8] + .into_iter() + .map(Ok::), + ) + .step_by(3); + assert_eq!(it.collect::>(), Ok(vec![0, 3, 6])); +} + +#[test] +fn take() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)).take(2); + assert_eq!(it.collect::>().unwrap(), [0, 1]); +} + +#[test] +fn take_while() { + let it = convert(vec![0, 1, 2, 3, 0].into_iter().map(Ok::)); + assert_eq!( + it.clone().take_while(|x| Ok(*x < 0)).collect::>(), + Ok(vec![]) + ); + assert_eq!( + it.clone().take_while(|x| Ok(*x < 2)).collect::>(), + Ok(vec![0, 1]) + ); + assert_eq!( + it.take_while(|x| Ok(*x < 4)).collect::>(), + Ok(vec![0, 1, 2, 3, 0]) + ); +} + +#[test] +fn flat_map() { + let it = convert(vec![0..1, 0..0, 1..5].into_iter().map(Ok::, ()>)) + .flat_map(|r| Ok(convert(r.map(Ok::)))); + assert_eq!(it.collect::>(), Ok(vec![0, 1, 2, 3, 4])); +} + +#[test] +fn flatten() { + let it = convert( + vec![0..1, 0..0, 1..5] + .into_iter() + .map(|r| convert(r.map(Ok::))) + .map(Ok::<_, ()>), + ) + .flatten(); + assert_eq!(it.collect::>(), Ok(vec![0, 1, 2, 3, 4])); +} + +#[test] +fn inspect() { + let mut buf = vec![]; + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)).inspect(|&v| { + buf.push(v); + Ok(()) + }); + it.count().unwrap(); + assert_eq!(buf, vec![0, 1, 2, 3]); +} + +#[test] +fn partition() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + let (even, odd): (Vec, Vec) = it.partition(|i| Ok(*i % 2 == 0)).unwrap(); + assert_eq!(even, vec![0, 2]); + assert_eq!(odd, vec![1, 3]); +} + +#[test] +fn find_map() { + let mut it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)); + assert_eq!( + it.find_map(|v| match v { + 2 => Ok(Some("hi")), + _ => Ok(None), + }), + Ok(Some("hi")) + ); +} + +#[test] +fn unzip() { + let it = convert( + vec![(0, 0), (1, -1), (2, -2), (3, -3)] + .into_iter() + .map(Ok::<_, ()>), + ); + let (pos, neg): (Vec, Vec) = it.unzip().unwrap(); + assert_eq!(pos, vec![0, 1, 2, 3]); + assert_eq!(neg, vec![0, -1, -2, -3]); +} + +#[test] +fn cycle() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)).cycle(); + assert_eq!(it.take(6).collect::>(), Ok(vec![0, 1, 2, 3, 0, 1])); +} + +#[test] +fn unwrap() { + let it = convert(vec![0, 1, 2, 3].into_iter().map(Ok::)).unwrap(); + assert_eq!(it.collect::>(), vec![0, 1, 2, 3]); +} + +#[test] +#[should_panic] +fn unwrap_panic() { + let _ = convert(vec![Ok(0), Err(())].into_iter()) + .unwrap() + .collect::>(); +} + +#[test] +fn wrap_std_iter_into_fallible() { + let it = IntoFallible::from(vec![0, 1, 2, 3].into_iter()); + assert_eq!(it.collect::>().unwrap(), vec![0, 1, 2, 3]); +} diff --git a/deps/crates/vendor/gimli/.cargo-checksum.json b/deps/crates/vendor/gimli/.cargo-checksum.json new file mode 100644 index 00000000000000..7795e57a753571 --- /dev/null +++ b/deps/crates/vendor/gimli/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"0b6c7b9d0fb69097dec83de46b656f81e2af61324cfa13253dbe84af73403089","CHANGELOG.md":"b62a5be34cfc438d03e68bacb75d02ce18465e6db344544559c98dadb65647b3","Cargo.toml":"565cde001e372608acdd3d8b4039c178e2a1a7295956a2f6241c828818602b95","Cargo.toml.orig":"526c2e5ae92deffc63015409a43cd62fcd1dc0befc6f07136e745ca72d8f33ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"ea11b770801edf3fb11ed727a164dc96142da211a85fdfdaca20fb5fb6251192","src/arch.rs":"64f37bf74cb82beaa467a2641be2d976e36fb505ef0bec52ca23301a14d4f5bc","src/common.rs":"616d2d91a81f7b3ecc6e9b5554efcc9c245e3fa176d412d195012210697a395c","src/constants.rs":"d28ab78922d0cb49b1cd0897b4fa46e337f3af99492f9715349807ac962c3147","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"81a0ca0e8ba56e749af4588fe76179611234062f79be1e9fb8ea8a27516b372f","src/lib.rs":"7c2640854e32a8b974f4e577b4a30e29f3d682e72203ce1d2a657e87752477ff","src/read/abbrev.rs":"f937e45d151ac5073f2c526b792e86e5ba96d3d36cb0377682a596c272be589a","src/read/addr.rs":"a6a535b690793e4c8ec85127d558e796cb8f6272533cd0418886bbc44289039e","src/read/aranges.rs":"4c526af254d9f6a2ee2b2fd7957b143f790854b40bed54092443f1ce75ea8c71","src/read/cfi.rs":"d42d3f82b9fb550c9882828fd3bb30797d7558cd7d0ab74ba205fee4b2e1c3a0","src/read/dwarf.rs":"216c8fa8353b119b5b2d2cda0b8b680173dcca8b43ed30dcbe07e06b62a0a9d4","src/read/endian_reader.rs":"6e7bf5b26719b1a5e396159387bb10666b218c10e603a4552882ec9d4d5cb8be","src/read/endian_slice.rs":"5b44661714967780b8c9f52fdaf655a53e309c38cbd3daf11bf6b1d5f6d067bb","src/read/index.rs":"42c9aae82e87cf7451d4434f68cd5d84e6bb482e51742af213a711b053633085","src/read/line.rs":"ff5e90c8df392af5814400acdc0c95282282d08554e5c9d67c554e561dcfc7d6","src/read/lists.rs":"5a4e33038ceedb48a8332a7713ee67a1be9b7a4031881a2ccb9b9259ba29356b","src/read/loclists.rs":"2c8f4c7b5823a59d1f05f86481cfb78cf6444230324f3444edbcd78f11bc679b","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"634ef620c648804e0d861103f9da2c3b2954e0cd988c28a9806eeb55991b888e","src/read/op.rs":"99f976309f4da7ea07aa2b09b4c26e97c8e78ba8c7b3016be22ab02869003c05","src/read/pubnames.rs":"ed752ee1a7017e6d3be42d81e4ddaaac960ef08081463a19106c9f041526d4a3","src/read/pubtypes.rs":"5e75b32c0923e827aff0bb2db456797a0e8d38ba46be992558a7990b3196bcf5","src/read/reader.rs":"502b303d33e2cb93fba54c97b487bf3f2216d645ab1c6eae8f4cad9c2e8f27e2","src/read/relocate.rs":"6844b113eb8218152e29912accc54b26bc2498e97bfe4af824472ddb69b8601c","src/read/rnglists.rs":"b376ca630f124fb92eca171bd6d80ff518d73fc33ad987d41abd399f61855aa0","src/read/str.rs":"4dd98cc8d93ce6f06c194eae034bfe0a3d45a9f06fbeaca38d8f29a9c7cf15a5","src/read/unit.rs":"f2fc760be1337a6a0351e9921e6e2e6290b17b6cfada6db96e0ebb3fdee68c90","src/read/util.rs":"f15a2bfa2d46e90eeb72b29de5ec3a7f69c871fbbde8bcbc2b0192e4802176f2","src/read/value.rs":"1c0db3759c65ffda3520fcecd36118367dfb46845035d5d97fcba2f0ea780380","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"22e93c21552d8d6329f5d9ea1c515fbe3820a23e89fff1b38d9478fa2bbab723","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"6af1c0f76e18fc7811985f24ef0eee10003479d7b08f216fd74b8c2610d2b2e5","src/write/loc.rs":"5d304049503286df914bb87c521aa5d042af650dd7d64e28c003fc9421581b8d","src/write/mod.rs":"7ebf0af9d4b558e1c24c7e6b84ae9c75b7e75c83d09a03ef8608973052d31913","src/write/op.rs":"13e59affa4e18ee44f0164115160209f6ccb3bd7e45ad4ebfc74eccf3ea132cd","src/write/range.rs":"b92959825e33984df2bb26bc562413027638f013920701df1ceb050a2ea43c46","src/write/relocate.rs":"117b97eae3ca2aad9d5b242652ebbdb333440e877be37873a7ef5ba1a39ced43","src/write/section.rs":"ea0e7e77650ef4c8972b409ef945c98bfa771712b6887591140d3e7baca9c599","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"6b2fba5f9bfad8bc54ea651b6aba9a6edfb0d2073abbb029c3f400bfa851b493","src/write/writer.rs":"c7696a3c2cff032ad6ada696132e4bbef92c4af76c7370c9ce82dedf2cf3716b"},"package":"07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"} \ No newline at end of file diff --git a/deps/crates/vendor/gimli/.cargo_vcs_info.json b/deps/crates/vendor/gimli/.cargo_vcs_info.json new file mode 100644 index 00000000000000..01345ed0347164 --- /dev/null +++ b/deps/crates/vendor/gimli/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "7e9d923a98c5eeed4d7a8b8cb32475d1ce16ced2" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/gimli/CHANGELOG.md b/deps/crates/vendor/gimli/CHANGELOG.md new file mode 100644 index 00000000000000..8e9a7c408ca557 --- /dev/null +++ b/deps/crates/vendor/gimli/CHANGELOG.md @@ -0,0 +1,1191 @@ +# `gimli` Change Log + +-------------------------------------------------------------------------------- + +## 0.31.1 + +Released 2024/10/04. + +### Changed + +* Changed `read::Evaluation::evaluate` to validate `DW_OP_deref_size`. + [#739](https://github.com/gimli-rs/gimli/pull/739) + +* Changed `write::LineProgram` to allow use of file index 0 for DWARF version 5. + [#740](https://github.com/gimli-rs/gimli/pull/740) + +* Improved the workaround for reading zero length entries in `.debug_frame`. + [#741](https://github.com/gimli-rs/gimli/pull/741) + +* Implemented `Default` for `read::DwarfSections` and `read::DwarfPackageSections`. + [#742](https://github.com/gimli-rs/gimli/pull/742) + +* Changed `read::ArangeEntryIter` to handle tombstones in `.debug_aranges`. + [#743](https://github.com/gimli-rs/gimli/pull/743) + +* Improved handling handling of 0 for tombstones in `DW_LNE_set_address` + and address pairs in ranges and locations. + [#750](https://github.com/gimli-rs/gimli/pull/750) + +* Changed the `read::ArrayLike` trait implementation to use const generics. + [#752](https://github.com/gimli-rs/gimli/pull/752) + +### Added + +* Added `MIPS::HI` and `MIPS::LO`. + [#749](https://github.com/gimli-rs/gimli/pull/749) + +-------------------------------------------------------------------------------- + +## 0.31.0 + +Released 2024/07/16. + +### Breaking changes + +* Deleted support for segment selectors. + [#720](https://github.com/gimli-rs/gimli/pull/720) + +* Added `read::FileEntry::source` and deleted `Copy` implementation. + [#728](https://github.com/gimli-rs/gimli/pull/728) + +* Changed `read::LineRow::execute` to return a `Result`. + [#731](https://github.com/gimli-rs/gimli/pull/731) + +* Deleted `Display` implementation for `read::LineInstruction`. + [#734](https://github.com/gimli-rs/gimli/pull/734) + +* Changed `read::Error` to be non-exhaustive. + +### Changed + +* Fixed `Hash` implementation for `read::EndianReader`. + [#723](https://github.com/gimli-rs/gimli/pull/723) + +* Changed `read::EhFrameHdr::parse` to validate the FDE count encoding. + [#725](https://github.com/gimli-rs/gimli/pull/725) + +* Changed address overflow to be an error for `read::UnwindTableRow`, + `read::LineRow`, and `read::ArangeEntry`. + [#730](https://github.com/gimli-rs/gimli/pull/730) + [#731](https://github.com/gimli-rs/gimli/pull/731) + [#732](https://github.com/gimli-rs/gimli/pull/732) + +* Changed wrapping addition for 32-bit addresses to wrap at 32 bits instead of + at 64 bits. + [#733](https://github.com/gimli-rs/gimli/pull/733) + +* Added earlier validation of address sizes. + [#733](https://github.com/gimli-rs/gimli/pull/733) + +### Added + +* Added `read::IndexSectionId::section_id`. + [#719](https://github.com/gimli-rs/gimli/pull/719) + +* Added `read::FrameDescriptionEntry::end_address`. + [#727](https://github.com/gimli-rs/gimli/pull/727) + +* Added support for `DW_LNCT_LLVM_source`. + [#728](https://github.com/gimli-rs/gimli/pull/728) + +-------------------------------------------------------------------------------- + +## 0.30.0 + +Released 2024/05/26. + +### Breaking changes + +* Added context to some `read::Error` variants. + [#703](https://github.com/gimli-rs/gimli/pull/703) + +* Changed type of `read::UnitIndexSection::section` to `IndexSectionId`. + [#716](https://github.com/gimli-rs/gimli/pull/716) + +### Changed + +* Fixed `write::Operation::ImplicitPointer::size`. + [#712](https://github.com/gimli-rs/gimli/pull/712) + +* Changed `read::RngListIter` and `read::LocListIter` to skip ranges where + the end is before the beginning, instead of returning an error. + [#715](https://github.com/gimli-rs/gimli/pull/715) + +* Fixed clippy warnings. + [#713](https://github.com/gimli-rs/gimli/pull/713) + +### Added + +* Added `read::UnitRef`. + [#711](https://github.com/gimli-rs/gimli/pull/711) + +-------------------------------------------------------------------------------- + +## 0.29.0 + +Released 2024/04/11. + +### Breaking changes + +* Changed `Reader` type parameter to `ReaderOffset` for `read::UnwindContext` and related types. + Replaced `Expression` with `UnwindExpression` in unwind information types. + [#703](https://github.com/gimli-rs/gimli/pull/703) + +### Changed + +* Changed `write::Sections::for_each` and `for_each_mut` to specify section lifetime. + [#699](https://github.com/gimli-rs/gimli/pull/699) + +* Fixed writing unwind information with an LSDA encoding that is not `DW_EH_PE_absptr`. + [#704](https://github.com/gimli-rs/gimli/pull/704) + +* Fixed parsing for an empty DWP index. + [#706](https://github.com/gimli-rs/gimli/pull/706) + +* Improved error handling in `read::Unit::dwo_name`. + [#693](https://github.com/gimli-rs/gimli/pull/693) + +* Fixed warnings. + [#692](https://github.com/gimli-rs/gimli/pull/692) + [#694](https://github.com/gimli-rs/gimli/pull/694) + [#695](https://github.com/gimli-rs/gimli/pull/695) + [#696](https://github.com/gimli-rs/gimli/pull/696) + +### Added + +* Added MIPS register definitions. + [#690](https://github.com/gimli-rs/gimli/pull/690) + +* Added PowerPC register definitions. + [#691](https://github.com/gimli-rs/gimli/pull/691) + +* Added `read::DwarfSections` and `read::DwarfPackageSections`. + [#698](https://github.com/gimli-rs/gimli/pull/698) + +* Implemented `BitOr` for `DwEhPe`. + [#709](https://github.com/gimli-rs/gimli/pull/709) + +* Added `read::Relocate`, `read::RelocateReader`, and `write::RelocateWriter`. + [#709](https://github.com/gimli-rs/gimli/pull/709) + +-------------------------------------------------------------------------------- + +## 0.28.1 + +Released 2023/11/24. + +### Changed + +* Changed `read::AbbreviationsCache` to require manual population using + `Dwarf::populate_abbreviations_cache`. + [#679](https://github.com/gimli-rs/gimli/pull/679) + +* Changed the default `read::UnwindContextStorage` to use `Box` instead of `Vec` + so that its memory usage is limited. + [#687](https://github.com/gimli-rs/gimli/pull/687) + +* Changed `read::UnwindTable::new` to always reset the context, because + previous errors may have left the context in an invalid state. + [#684](https://github.com/gimli-rs/gimli/pull/684) + +* Changed the `Debug` implementation for `read::EndianSlice` to limit the number + of bytes it displays. + [#686](https://github.com/gimli-rs/gimli/pull/686) + +### Added + +* Added more AArch64 register definitions. + [#680](https://github.com/gimli-rs/gimli/pull/680) + +* Added `read::Unit::new_with_abbreviations`. + [#677](https://github.com/gimli-rs/gimli/pull/677) + +* Added `read::Evaluation::value_result`. + [#676](https://github.com/gimli-rs/gimli/pull/676) + +-------------------------------------------------------------------------------- + +## 0.28.0 + +Released 2023/08/12. + +### Breaking changes + +* Deleted `impl From for &[u8]`. Use `EndianSlice::slice` instead. + [#669](https://github.com/gimli-rs/gimli/pull/669) + +* Deleted `impl Index for EndianSlice` and + `impl Index> for EndianSlice`. + [#669](https://github.com/gimli-rs/gimli/pull/669) + +* Replaced `impl From for u64` with `Pointer::pointer`. + [#670](https://github.com/gimli-rs/gimli/pull/670) + +* Updated `fallible-iterator` to 0.3.0. + [#672](https://github.com/gimli-rs/gimli/pull/672) + +* Changed some optional dependencies to use the `dep:` feature syntax. + [#672](https://github.com/gimli-rs/gimli/pull/672) + +* Added `non_exhaustive` attribute to `read::RegisterRule`, + `read::CallFrameInstruction`, and `write::CallFrameInstruction`. + [#673](https://github.com/gimli-rs/gimli/pull/673) + +### Changed + +* The minimum supported rust version for the `read` feature and its dependencies + increased to 1.60.0. + +* The minimum supported rust version for other features increased to 1.65.0. + +### Added + +* Added `Vendor`, `read::DebugFrame::set_vendor`, and `read::EhFrame::set_vendor`. + [#673](https://github.com/gimli-rs/gimli/pull/673) + +* Added more ARM and AArch64 register definitions, and + `DW_CFA_AARCH64_negate_ra_state` support. + [#673](https://github.com/gimli-rs/gimli/pull/673) + +-------------------------------------------------------------------------------- + +## 0.27.3 + +Released 2023/06/14. + +### Changed + +* Excluded test fixtures from published package. + [#661](https://github.com/gimli-rs/gimli/pull/661) + +### Added + +* Added `FallibleIterator` implementation for `read::OperationIter`. + [#649](https://github.com/gimli-rs/gimli/pull/649) + +* Added `DW_AT_GNU_deleted` constant. + [#658](https://github.com/gimli-rs/gimli/pull/658) + +-------------------------------------------------------------------------------- + +## 0.27.2 + +Released 2023/02/15. + +### Added + +* Added support for tombstones in `read::LineRows`. + [#642](https://github.com/gimli-rs/gimli/pull/642) + +-------------------------------------------------------------------------------- + +## 0.27.1 + +Released 2023/01/23. + +### Added + +* Added `SectionId::xcoff_name` and `read::Section::xcoff_section_name`. + [#635](https://github.com/gimli-rs/gimli/pull/635) + +* Added `read::Dwarf::make_dwo` and `read::Unit::dwo_name`. + [#637](https://github.com/gimli-rs/gimli/pull/637) + +### Changed + +* Changed `read::DwarfPackage::sections` to handle supplementary files. + [#638](https://github.com/gimli-rs/gimli/pull/638) + +-------------------------------------------------------------------------------- + +## 0.27.0 + +Released 2022/11/23. + +### Breaking changes + +* Added `read::Dwarf::abbreviations_cache` to cache abbreviations at offset 0. + Changed `read::Dwarf::abbreviations` to return `Result>`, + and changed `read::Unit::abbreviations` to `Arc`. + [#628](https://github.com/gimli-rs/gimli/pull/628) + +### Added + +* Added LoongArch register definitions. + [#624](https://github.com/gimli-rs/gimli/pull/624) + +* Added support for tombstones in `read::LocListIter` and `read::RngListIter`. + [#631](https://github.com/gimli-rs/gimli/pull/631) + +-------------------------------------------------------------------------------- + +## 0.26.2 + +Released 2022/07/16. + +### Changed + +* Fixed CFI personality encoding when writing. + [#609](https://github.com/gimli-rs/gimli/pull/609) + +* Fixed use of raw pointer for mutation, detected by Miri. + [#614](https://github.com/gimli-rs/gimli/pull/614) + +* Fixed `DW_OP_GNU_implicit_pointer` handling for DWARF version 2. + [#618](https://github.com/gimli-rs/gimli/pull/618) + +### Added + +* Added `read::EhHdrTable::iter`. + [#619](https://github.com/gimli-rs/gimli/pull/619) + +-------------------------------------------------------------------------------- + +## 0.26.1 + +Released 2021/11/02. + +### Changed + +* Fixed segmentation fault in `ArrayVec>::into_vec`, which may be used by + `read::Evaluation::result`. This regression was introduced in 0.26.0. + [#601](https://github.com/gimli-rs/gimli/pull/601) + +-------------------------------------------------------------------------------- + +## 0.26.0 + +Released 2021/10/24. + +### Breaking changes + +* Removed `read::UninitializedUnwindContext`. Use `Box` instead. + [#593](https://github.com/gimli-rs/gimli/pull/593) + +* Renamed `read::Error::CfiStackFull` to `StackFull`. + [#595](https://github.com/gimli-rs/gimli/pull/595) + +* Added `UnwindContextStorage` type parameter to `read::UnwindContext`, `read::UnwindTable`, + `read::UnwindTableRow`, and `read::RegisterRuleMap`. + [#595](https://github.com/gimli-rs/gimli/pull/595) + +* Added `EvaluationStorage` type parameter to `read::Evaluation`. + [#595](https://github.com/gimli-rs/gimli/pull/595) + +* Added `read::SectionId::DebugCuIndex` and `read::SectionId::DebugTuIndex`. + [#588](https://github.com/gimli-rs/gimli/pull/588) + +### Changed + +* Fixed `DW_EH_PE_pcrel` handling in default `write::Writer::write_eh_pointer` implementation. + [#576](https://github.com/gimli-rs/gimli/pull/576) + +* Fixed `read::AttributeSpecification::size` for some forms. + [#597](https://github.com/gimli-rs/gimli/pull/597) + +* Display more unit details in dwarfdump. + [#584](https://github.com/gimli-rs/gimli/pull/584) + +### Added + +* Added `write::DebuggingInformationEntry::delete_child`. + [#570](https://github.com/gimli-rs/gimli/pull/570) + +* Added ARM and AArch64 register definitions. + [#574](https://github.com/gimli-rs/gimli/pull/574) + [#577](https://github.com/gimli-rs/gimli/pull/577) + +* Added RISC-V register definitions. + [#579](https://github.com/gimli-rs/gimli/pull/579) + +* Added `read::DwarfPackage`, `read::DebugCuIndex`, and `read::DebugTuIndex`. + [#588](https://github.com/gimli-rs/gimli/pull/588) + +* Added `read-core` feature to allow building without `liballoc`. + [#596](https://github.com/gimli-rs/gimli/pull/596) + +* Added `read::EntriesRaw::skip_attributes`. + [#597](https://github.com/gimli-rs/gimli/pull/597) + +-------------------------------------------------------------------------------- + +## 0.25.0 + +Released 2021/07/26. + +### Breaking changes + +* `read::FrameDescriptionEntry::unwind_info_for_address` now returns a reference + instead of cloning. + [#557](https://github.com/gimli-rs/gimli/pull/557) + +* `read::AttributeValue::RangeListsRef` now contains a `RawRangeListsOffset` + to allow handling of GNU split DWARF extensions. + Use `read::Dwarf::ranges_offset_from_raw` to handle it. + [#568](https://github.com/gimli-rs/gimli/pull/568) + [#569](https://github.com/gimli-rs/gimli/pull/569) + +* Added `read::Unit::dwo_id`. + [#569](https://github.com/gimli-rs/gimli/pull/569) + +### Changed + +* `.debug_aranges` parsing now accepts version 3. + [#560](https://github.com/gimli-rs/gimli/pull/560) + +* `read::Dwarf::attr_ranges_offset` and its callers now handle GNU split DWARF extensions. + [#568](https://github.com/gimli-rs/gimli/pull/568) + [#569](https://github.com/gimli-rs/gimli/pull/569) + +### Added + +* Added `read::DebugLineStr::new`. + [#556](https://github.com/gimli-rs/gimli/pull/556) + +* Added `read::UnwindTable::into_current_row`. + [#557](https://github.com/gimli-rs/gimli/pull/557) + +* Added more `DW_LANG` constants. + [#565](https://github.com/gimli-rs/gimli/pull/565) + +* dwarfdump: added DWO parent support. + [#568](https://github.com/gimli-rs/gimli/pull/568) + +* Added `read::Dwarf` methods: `ranges_offset_from_raw`, `raw_ranges`, and `raw_locations`. + [#568](https://github.com/gimli-rs/gimli/pull/568) + [#569](https://github.com/gimli-rs/gimli/pull/569) + +-------------------------------------------------------------------------------- + +## 0.24.0 + +Released 2021/05/01. + +### Breaking changes + +* Minimum Rust version increased to 1.42.0. + +* Added `read::Dwarf::debug_aranges`. + [#539](https://github.com/gimli-rs/gimli/pull/539) + +* Replaced `read::DebugAranges::items` with `read::DebugAranges::headers`. + [#539](https://github.com/gimli-rs/gimli/pull/539) + +* Added `read::Operation::Wasm*`. + [#546](https://github.com/gimli-rs/gimli/pull/546) + +* `read::LineRow::line` now returns `Option`. + The `read::ColumnType::Column` variant now contains a `NonZeroU64`. + [#551](https://github.com/gimli-rs/gimli/pull/551) + +* Replaced `read::Dwarf::debug_str_sup` with `read::Dwarf::sup`. + Deleted `sup` parameter of `read::Dwarf::load`. + Added `read::Dwarf::load_sup`. + [#554](https://github.com/gimli-rs/gimli/pull/554) + +### Added + +* dwarfdump: Supplementary object file support. + [#552](https://github.com/gimli-rs/gimli/pull/552) + +### Changed + +* Support `DW_FORM_addrx*` for `DW_AT_low_pc`/`DW_AT_high_pc` in `read::Dwarf`. + [#541](https://github.com/gimli-rs/gimli/pull/541) + +* Performance improvement in `EndianReader`. + [#549](https://github.com/gimli-rs/gimli/pull/549) + +-------------------------------------------------------------------------------- + +## 0.23.0 + +Released 2020/10/27. + +### Breaking changes + +* Added more variants to `read::UnitType`. + Added `read::AttributeValue::DwoId` + [#521](https://github.com/gimli-rs/gimli/pull/521) + +* Replaced `CompilationUnitHeader` and `TypeUnitHeader` with `UnitHeader`. + Replaced `CompilationUnitHeadersIter` with `DebugInfoUnitHeadersIter`. + Replaced `TypeUnitHeadersIter` with `DebugTypesUnitHeadersIter`. + [#523](https://github.com/gimli-rs/gimli/pull/523) + + +### Added + +* Added read support for split DWARF. + [#527](https://github.com/gimli-rs/gimli/pull/527) + [#529](https://github.com/gimli-rs/gimli/pull/529) + +* Added `read::Dwarf::attr_address`. + [#524](https://github.com/gimli-rs/gimli/pull/524) + +* Added read support for `DW_AT_GNU_addr_base` and `DW_AT_GNU_ranges_base`. + [#525](https://github.com/gimli-rs/gimli/pull/525) + +* dwarfdump: Display index values for attributes. + [#526](https://github.com/gimli-rs/gimli/pull/526) + +* Added `name_to_register`. + [#532](https://github.com/gimli-rs/gimli/pull/532) + +-------------------------------------------------------------------------------- + +## 0.22.0 + +Released 2020/07/03. + +### Breaking changes + +* Fixed `UnitHeader::size_of_header` for DWARF 5 units. + [#518](https://github.com/gimli-rs/gimli/pull/518) + +### Added + +* Added fuzz targets in CI. + [#512](https://github.com/gimli-rs/gimli/pull/512) + +* Added read support for `DW_OP_GNU_addr_index` and `DW_OP_GNU_const_index`. + [#516](https://github.com/gimli-rs/gimli/pull/516) + +* Added `.dwo` support to dwarfdump. + [#516](https://github.com/gimli-rs/gimli/pull/516) + +* Added `SectionId::dwo_name` and `Section::dwo_section_name`. + [#517](https://github.com/gimli-rs/gimli/pull/517) + +### Fixed + +* Fixed panic when reading `DW_FORM_indirect` combined with `DW_FORM_implicit_const`. + [#502](https://github.com/gimli-rs/gimli/pull/502) + +* Fixed panic for `read::Abbreviations::get(0)`. + [#505](https://github.com/gimli-rs/gimli/pull/505) + +* Fixed arithmetic overflow when reading `.debug_line`. + [#508](https://github.com/gimli-rs/gimli/pull/508) + +* Fixed arithmetic overflow when reading CFI. + [#509](https://github.com/gimli-rs/gimli/pull/509) + +* Fixed arithmetic overflow and division by zero when reading `.debug_aranges`. + [#510](https://github.com/gimli-rs/gimli/pull/510) + +* Don't return error from `read::Unit::new` when `DW_AT_name` or `DW_AT_comp_dir` is missing. + [#515](https://github.com/gimli-rs/gimli/pull/515) + +-------------------------------------------------------------------------------- + +## 0.21.0 + +Released 2020/05/12. + +### Breaking changes + +* Minimum Rust version increased to 1.38.0. + +* Replaced `read::Operation::Literal` with `Operation::UnsignedConstant` and `Operation::SignedConstant`. + Changed `read::Operation::Bra` and `read::Operation::Skip` to contain the target offset instead of the bytecode. + [#479](https://github.com/gimli-rs/gimli/pull/479) + +* Changed `write::Expression` to support references. Existing users can convert to use `Expression::raw`. + [#479](https://github.com/gimli-rs/gimli/pull/479) + +* Replaced `write::AttributeValue::AnyUnitEntryRef` with `DebugInfoRef`. + Renamed `write::AttributeValue::ThisUnitEntryRef` to `UnitRef`. + [#479](https://github.com/gimli-rs/gimli/pull/479) + +* Added more optional features: `endian-reader` and `fallible-iterator`. + [#495](https://github.com/gimli-rs/gimli/pull/495) + [#498](https://github.com/gimli-rs/gimli/pull/498) + +### Added + +* Added `read::Expression::operations` + [#479](https://github.com/gimli-rs/gimli/pull/479) + +### Fixed + +* Fixed newlines in `dwarfdump` example. + [#470](https://github.com/gimli-rs/gimli/pull/470) + +* Ignore zero terminators when reading `.debug_frame` sections. + [#486](https://github.com/gimli-rs/gimli/pull/486) + +* Increase the number of CFI register rules supported by `read::UnwindContext`. + [#487](https://github.com/gimli-rs/gimli/pull/487) + +* Fixed version handling and return register encoding when reading `.eh_frame` sections. + [#493](https://github.com/gimli-rs/gimli/pull/493) + +### Changed + +* Added `EhFrame` and `DebugFrame` to `write::Sections`. + [#492](https://github.com/gimli-rs/gimli/pull/492) + +* Improved performance of `write::LineProgram::generate_row`. + [#476](https://github.com/gimli-rs/gimli/pull/476) + +* Removed use of the `byteorder`, `arrayvec` and `smallvec` crates. + [#494](https://github.com/gimli-rs/gimli/pull/494) + [#496](https://github.com/gimli-rs/gimli/pull/496) + [#497](https://github.com/gimli-rs/gimli/pull/497) + +-------------------------------------------------------------------------------- + +## 0.20.0 + +Released 2020/01/11. + +### Breaking changes + +* Changed type of `DwTag`, `DwAt`, and `DwForm` constants. + [#451](https://github.com/gimli-rs/gimli/pull/451) + +* Added `read/write::AttributeValue::DebugMacroRef`, and returned where + required in `read::Attribute::value`. Added `SectionId::DebugMacro`. + [#454](https://github.com/gimli-rs/gimli/pull/454) + +* Deleted `alloc` feature, and fixed `no-std` builds with stable rust. + [#459](https://github.com/gimli-rs/gimli/pull/459) + +* Deleted `read::Error::description`, and changed `` + to display what was previously the description. + [#462](https://github.com/gimli-rs/gimli/pull/462) + +### Added + +* Added GNU view constants. + [#434](https://github.com/gimli-rs/gimli/pull/434) + +* Added `read::EntriesRaw` for low level DIE parsing. + [#455](https://github.com/gimli-rs/gimli/pull/455) + +* Added `examples/simple-line.rs`. + [#460](https://github.com/gimli-rs/gimli/pull/460) + +### Fixed + +* Fixed handling of CFI augmentations without data. + [#438](https://github.com/gimli-rs/gimli/pull/438) + +* dwarfdump: fix panic for malformed expressions. + [#447](https://github.com/gimli-rs/gimli/pull/447) + +* dwarfdump: fix handling of Mach-O relocations. + [#449](https://github.com/gimli-rs/gimli/pull/449) + +### Changed + +* Improved abbreviation parsing performance. + [#451](https://github.com/gimli-rs/gimli/pull/451) + +-------------------------------------------------------------------------------- + +## 0.19.0 + +Released 2019/07/08. + +### Breaking changes + +* Small API changes related to `.debug_loc` and `.debug_loclists`: + added `read::RawLocListEntry::AddressOrOffsetPair` enum variant, + added `write::Sections::debug_loc/debug_loclists` public members, + and replaced `write::AttributeValue::LocationListsRef` with `LocationListRef`. + [#425](https://github.com/gimli-rs/gimli/pull/425) + +### Added + +* Added `read::Attribute::exprloc_value` and `read::AttributeValue::exprloc_value`. + [#422](https://github.com/gimli-rs/gimli/pull/422) + +* Added support for writing `.debug_loc` and `.debug_loclists` sections. + [#425](https://github.com/gimli-rs/gimli/pull/425) + +* Added `-G` flag to `dwarfdump` example to display global offsets. + [#427](https://github.com/gimli-rs/gimli/pull/427) + +* Added `examples/simple.rs`. + [#429](https://github.com/gimli-rs/gimli/pull/429) + +### Fixed + +* `write::LineProgram::from` no longer requires `DW_AT_name` or `DW_AT_comp_dir` + attributes to be present in the unit DIE. + [#430](https://github.com/gimli-rs/gimli/pull/430) + +-------------------------------------------------------------------------------- + +## 0.18.0 + +Released 2019/04/25. + +The focus of this release has been on improving support for reading CFI, +and adding support for writing CFI. + +### Breaking changes + +* For types which have an `Offset` type parameter, the default `Offset` + has changed from `usize` to `R::Offset`. + [#392](https://github.com/gimli-rs/gimli/pull/392) + +* Added an `Offset` type parameter to the `read::Unit` type to allow variance. + [#393](https://github.com/gimli-rs/gimli/pull/393) + +* Changed the `UninitializedUnwindContext::initialize` method to borrow `self`, + and return `&mut UnwindContext`. Deleted the `InitializedUnwindContext` type. + [#395](https://github.com/gimli-rs/gimli/pull/395) + +* Deleted the `UnwindSection` type parameters from the `CommonInformationEntry`, + `FrameDescriptionEntry`, `UninitializedUnwindContext`, + `UnwindContext`, and `UnwindTable` types. + [#399](https://github.com/gimli-rs/gimli/pull/399) + +* Changed the signature of the `get_cie` callback parameter for various functions. + The signature now matches the `UnwindSection::cie_from_offset` method, so + that method can be used as the parameter. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Reduced the number of lifetime parameters for the `UnwindTable` type. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Updated `fallible-iterator` to version 0.2.0. + [#407](https://github.com/gimli-rs/gimli/pull/407) + +* Added a parameter to the `Error::UnexpectedEof` enum variant. + [#408](https://github.com/gimli-rs/gimli/pull/408) + +### Added + +* Update to 2018 edition. + [#391](https://github.com/gimli-rs/gimli/pull/391) + +* Added the `FrameDescriptionEntry::unwind_info_for_address` method. + [#396](https://github.com/gimli-rs/gimli/pull/396) + +* Added the `FrameDescriptionEntry::rows` method. + [#396](https://github.com/gimli-rs/gimli/pull/396) + +* Added the `EhHdrTable::unwind_info_for_address` method. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Added the `EhHdrTable::fde_for_address` method and deprecated the + `EhHdrTable::lookup_and_parse` method. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Added the `EhHdrTable::pointer_to_offset` method. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Added the `UnwindSection::fde_for_address` method. + [#396](https://github.com/gimli-rs/gimli/pull/396) + +* Added the `UnwindSection::fde_from_offset` method. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Added the `UnwindSection::partial_fde_from_offset` method. + [#400](https://github.com/gimli-rs/gimli/pull/400) + +* Added the `Section::id` method. + [#406](https://github.com/gimli-rs/gimli/pull/406) + +* Added the `Dwarf::load` method, and corresponding methods for individual sections. + [#406](https://github.com/gimli-rs/gimli/pull/406) + +* Added the `Dwarf::borrow` method, and corresponding methods for individual sections. + [#406](https://github.com/gimli-rs/gimli/pull/406) + +* Added the `Dwarf::format_error` method. + [#408](https://github.com/gimli-rs/gimli/pull/408) + +* Added the `Dwarf::die_ranges` method. + [#417](https://github.com/gimli-rs/gimli/pull/417) + +* Added the `Dwarf::unit_ranges` method. + [#417](https://github.com/gimli-rs/gimli/pull/417) + +* Added support for writing `.debug_frame` and `.eh_frame` sections. + [#412](https://github.com/gimli-rs/gimli/pull/412) + [#419](https://github.com/gimli-rs/gimli/pull/419) + +### Fixed + +* The `code_alignment_factor` is now used when evaluating CFI instructions + that advance the location. + [#401](https://github.com/gimli-rs/gimli/pull/401) + +* Fixed parsing of pointers encoded with `DW_EH_PE_funcrel`. + [#402](https://github.com/gimli-rs/gimli/pull/402) + +* Use the FDE address encoding from the augmentation when parsing `DW_CFA_set_loc`. + [#403](https://github.com/gimli-rs/gimli/pull/403) + +* Fixed setting of `.eh_frame` base addresses in dwarfdump. + [#410](https://github.com/gimli-rs/gimli/pull/410) + +## 0.17.0 + +Released 2019/02/21. + +The focus of this release has been on improving DWARF 5 support, and +adding support for writing DWARF. + +### Breaking changes + +* Changed register values to a `Register` type instead of `u8`/`u64`. + [#328](https://github.com/gimli-rs/gimli/pull/328) + +* Replaced `BaseAddresses::set_cfi` with `set_eh_frame_hdr` and `set_eh_frame`. + Replaced `BaseAddresses::set_data` with `set_got`. + You should now use the same `BaseAddresses` value for parsing both + `.eh_frame` and `.eh_frame_hdr`. + [#351](https://github.com/gimli-rs/gimli/pull/351) + +* Renamed many types and functions related to `.debug_line`. + Renamed `LineNumberProgram` to `LineProgram`. + Renamed `IncompleteLineNumberProgram` to `IncompleteLineProgram`. + Renamed `CompleteLineNumberProgram` to `CompleteLineProgram`. + Renamed `LineNumberProgramHeader` to `LineProgramHeader`. + Renamed `LineNumberRow` to `LineRow`. + Renamed `StateMachine` to `LineRows`. + Renamed `Opcode` to `LineInstruction`. + Renamed `OpcodesIter` to `LineInstructions`. + Renamed `LineNumberSequence` to `LineSequence`. + [#359](https://github.com/gimli-rs/gimli/pull/359) + +* Added `Offset` type parameter to `AttributeValue`, `LineProgram`, + `IncompleteLineProgram`, `CompleteLineProgram`, `LineRows`, `LineInstruction`, + and `FileEntry`. + [#324](https://github.com/gimli-rs/gimli/pull/324) + +* Changed `FileEntry::path_name`, `FileEntry::directory`, and + `LineProgramHeader::directory` to return an `AttributeValue` instead + of a `Reader`. + [#366](https://github.com/gimli-rs/gimli/pull/366) + +* Renamed `FileEntry::last_modification` to `FileEntry::timestamp` + and renamed `FileEntry::length` to `FileEntry::size`. + [#366](https://github.com/gimli-rs/gimli/pull/366) + +* Added an `Encoding` type. Changed many functions that previously accepted + `Format`, version or address size parameters to accept an `Encoding` + parameter instead. + Notable changes are `LocationLists::locations`, `RangeLists::ranges`, + and `Expression::evaluation`. + [#364](https://github.com/gimli-rs/gimli/pull/364) + +* Changed return type of `LocationLists::new` and `RangeLists::new`. + [#370](https://github.com/gimli-rs/gimli/pull/370) + +* Added parameters to `LocationsLists::locations` and `RangeLists::ranges` + to support `.debug_addr`. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Added more `AttributeValue` variants: `DebugAddrBase`, `DebugAddrIndex`, + `DebugLocListsBase`, `DebugLocListsIndex`, `DebugRngListsBase`, `DebugRngListsIndex`, + `DebugStrOffsetsBase`, `DebugStrOffsetsIndex`, `DebugLineStrRef`. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Changed `AttributeValue::Data*` attributes to native endian integers instead + of byte arrays. + [#365](https://github.com/gimli-rs/gimli/pull/365) + +* Replaced `EvaluationResult::TextBase` with + `EvaluationResult::RequiresRelocatedAddress`. The handling of `TextBase` + was incorrect. + [#335](https://github.com/gimli-rs/gimli/pull/335) + +* Added `EvaluationResult::IndexedAddress` for operations that require an + address from `.debug_addr`. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Added `Reader::read_slice`. Added a default implementation of + `Reader::read_u8_array` which uses this. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +### Added + +* Added initial support for writing DWARF. This is targeted at supporting + line number information only. + [#340](https://github.com/gimli-rs/gimli/pull/340) + [#344](https://github.com/gimli-rs/gimli/pull/344) + [#346](https://github.com/gimli-rs/gimli/pull/346) + [#361](https://github.com/gimli-rs/gimli/pull/361) + [#362](https://github.com/gimli-rs/gimli/pull/362) + [#365](https://github.com/gimli-rs/gimli/pull/365) + [#368](https://github.com/gimli-rs/gimli/pull/368) + [#382](https://github.com/gimli-rs/gimli/pull/382) + +* Added `read` and `write` Cargo features. Both are enabled by default. + [#343](https://github.com/gimli-rs/gimli/pull/343) + +* Added support for reading DWARF 5 `.debug_line` and `.debug_line_str` sections. + [#366](https://github.com/gimli-rs/gimli/pull/366) + +* Added support for reading DWARF 5 `.debug_str_offsets` sections, including + parsing `DW_FORM_strx*` attributes. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Added support for reading DWARF 5 `.debug_addr` sections, including parsing + `DW_FORM_addrx*` attributes and evaluating `DW_OP_addrx` and `DW_OP_constx` + operations. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Added support for reading DWARF 5 indexed addresses and offsets in + `.debug_loclists` and `.debug_rnglists`, including parsing `DW_FORM_rnglistx` + and `DW_FORM_loclistx` attributes. + [#358](https://github.com/gimli-rs/gimli/pull/358) + +* Added high level `Dwarf` and `Unit` types. Existing code does not need to + switch to using these types, but doing so will make DWARF 5 support simpler. + [#352](https://github.com/gimli-rs/gimli/pull/352) + [#380](https://github.com/gimli-rs/gimli/pull/380) + [#381](https://github.com/gimli-rs/gimli/pull/381) + +* Added `EhFrame::set_address_size` and `DebugFrame::set_address_size` methods + to allow parsing non-native CFI sections. The default address size is still + the native size. + [#325](https://github.com/gimli-rs/gimli/pull/325) + +* Added architecture specific definitions for `Register` values and names. + Changed dwarfdump to print them. + [#328](https://github.com/gimli-rs/gimli/pull/328) + +* Added support for reading relocatable DWARF sections. + [#337](https://github.com/gimli-rs/gimli/pull/337) + +* Added parsing of `DW_FORM_data16`. + [#366](https://github.com/gimli-rs/gimli/pull/366) + +### Fixed + +* Fixed parsing DWARF 5 ranges with `start == end == 0`. + [#323](https://github.com/gimli-rs/gimli/pull/323) + +* Changed `LineRows` to be covariant in its `Reader` type parameter. + [#324](https://github.com/gimli-rs/gimli/pull/324) + +* Fixed handling of empty units in dwarfdump. + [#330](https://github.com/gimli-rs/gimli/pull/330) + +* Fixed `UnitHeader::length_including_self` for `Dwarf64`. + [#342](https://github.com/gimli-rs/gimli/pull/342) + +* Fixed parsing of `DW_CFA_set_loc`. + [#355](https://github.com/gimli-rs/gimli/pull/355) + +* Fixed handling of multiple headers in `.debug_loclists` and `.debug_rnglists`. + [#370](https://github.com/gimli-rs/gimli/pull/370) + +-------------------------------------------------------------------------------- + +## 0.16.1 + +Released 2018/08/28. + +### Added + +* Added `EhFrameHdr::lookup_and_parse`. [#316][] +* Added support for `DW_CFA_GNU_args_size`. [#319][] + +### Fixed + +* Implement `Send`/`Sync` for `SubRange`. [#305][] +* Fixed `alloc` support on nightly. [#306][] [#310][] + +[#305]: https://github.com/gimli-rs/gimli/pull/305 +[#306]: https://github.com/gimli-rs/gimli/pull/306 +[#310]: https://github.com/gimli-rs/gimli/pull/310 +[#316]: https://github.com/gimli-rs/gimli/pull/316 +[#319]: https://github.com/gimli-rs/gimli/pull/319 + +-------------------------------------------------------------------------------- + +## 0.16.0 + +Released 2018/06/01. + +### Added + +* Added support for building in `#![no_std]` environments, when the `alloc` + crate is available. Disable the "std" feature and enable the "alloc" + feature. [#138][] [#271][] + +* Added support for DWARF 5 `.debug_rnglists` and `.debug_loclists` + sections. [#272][] + +* Added support for DWARF 5 `DW_FORM_ref_sup` and `DW_FORM_strp_sup` attribute + forms. [#288][] + +* Added support for DWARF 5 operations on typed values. [#293][] + +* A `dwarf-validate` example program that checks the integrity of the given + DWARF and its references between sections. [#290][] + +* Added the `EndianReader` type, an easy way to define a custom `Reader` + implementation with a reference to a generic buffer of bytes and an associated + endianity. [#298][] [#302][] + +### Changed + +* Various speed improvements for evaluating `.debug_line` line number + programs. [#276][] + +* The example `dwarfdump` clone is a [whole lot faster + now][dwarfdump-faster]. [#282][] [#284][] [#285][] + +### Deprecated + +* `EndianBuf` has been renamed to `EndianSlice`, use that name instead. [#295][] + +### Fixed + +* Evaluating the `DW_CFA_restore_state` opcode properly maintains the current + location. Previously it would incorrectly restore the old location when + popping from evaluation stack. [#274][] + +[#271]: https://github.com/gimli-rs/gimli/issues/271 +[#138]: https://github.com/gimli-rs/gimli/issues/138 +[#274]: https://github.com/gimli-rs/gimli/issues/274 +[#272]: https://github.com/gimli-rs/gimli/issues/272 +[#276]: https://github.com/gimli-rs/gimli/issues/276 +[#282]: https://github.com/gimli-rs/gimli/issues/282 +[#285]: https://github.com/gimli-rs/gimli/issues/285 +[#284]: https://github.com/gimli-rs/gimli/issues/284 +[#288]: https://github.com/gimli-rs/gimli/issues/288 +[#290]: https://github.com/gimli-rs/gimli/issues/290 +[#293]: https://github.com/gimli-rs/gimli/issues/293 +[#295]: https://github.com/gimli-rs/gimli/issues/295 +[#298]: https://github.com/gimli-rs/gimli/issues/298 +[#302]: https://github.com/gimli-rs/gimli/issues/302 +[dwarfdump-faster]: https://robert.ocallahan.org/2018/03/speeding-up-dwarfdump-with-rust.html + +-------------------------------------------------------------------------------- + +## 0.15.0 + +Released 2017/12/01. + +### Added + +* Added the `EndianBuf::to_string()` method. [#233][] + +* Added more robust error handling in our example `dwarfdump` clone. [#234][] + +* Added `FrameDescriptionEntry::initial_address` method. [#237][] + +* Added `FrameDescriptionEntry::len` method. [#237][] + +* Added the `FrameDescriptionEntry::entry_len` method. [#241][] + +* Added the `CommonInformationEntry::offset` method. [#241][] + +* Added the `CommonInformationEntry::entry_len` method. [#241][] + +* Added the `CommonInformationEntry::version` method. [#241][] + +* Added the `CommonInformationEntry::augmentation` method. [#241][] + +* Added the `CommonInformationEntry::code_alignment_factor` method. [#241][] + +* Added the `CommonInformationEntry::data_alignment_factor` method. [#241][] + +* Added the `CommonInformationEntry::return_address_register` method. [#241][] + +* Added support for printing `.eh_frame` sections to our example `dwarfdump` + clone. [#241][] + +* Added support for parsing the `.eh_frame_hdr` section. On Linux, the + `.eh_frame_hdr` section provides a pointer to the already-mapped-in-memory + `.eh_frame` data, so that it doesn't need to be duplicated, and a binary + search table of its entries for faster unwinding information lookups. [#250][] + +* Added support for parsing DWARF 5 compilation unit headers. [#257][] + +* Added support for DWARF 5's `DW_FORM_implicit_const`. [#257][] + +### Changed + +* Unwinding methods now give ownership of the unwinding context back to the + caller if errors are encountered, not just on the success path. This allows + recovering from errors in signal-safe code, where constructing a new unwinding + context is not an option because it requires allocation. This is a **breaking + change** affecting `UnwindSection::unwind_info_for_address` and + `UninitializedUnwindContext::initialize`. [#241][] + +* `CfaRule` and `RegisterRule` now expose their `DW_OP` expressions as + `Expression`. This is a minor **breaking change**. [#241][] + +* The `Error::UnknownVersion` variant now contains the unknown version + number. This is a minor **breaking change**. [#245][] + +* `EvaluationResult::RequiresEntryValue` requires an `Expression` instead of a + `Reader` now. This is a minor **breaking change**. [#256][] + + +[#233]: https://github.com/gimli-rs/gimli/pull/233 +[#234]: https://github.com/gimli-rs/gimli/pull/234 +[#237]: https://github.com/gimli-rs/gimli/pull/237 +[#241]: https://github.com/gimli-rs/gimli/pull/241 +[#245]: https://github.com/gimli-rs/gimli/pull/245 +[#250]: https://github.com/gimli-rs/gimli/pull/250 +[#256]: https://github.com/gimli-rs/gimli/pull/256 +[#257]: https://github.com/gimli-rs/gimli/pull/257 + +-------------------------------------------------------------------------------- + +## 0.14.0 + +Released 2017/08/08. + +### Added + +* All `pub` types now `derive(Hash)`. [#192][] + +* All the constants from DWARF 5 are now defined. [#193][] + +* Added support for the `DW_OP_GNU_parameter_ref` GNU extension to parsing and + evaluation DWARF opcodes. [#208][] + +* Improved LEB128 parsing performance. [#216][] + +* Improved `.debug_{aranges,pubnames,pubtypes}` parsing performance. [#218][] + +* Added the ability to choose endianity dynamically at run time, rather than + only statically at compile time. [#219][] + +### Changed + +* The biggest change of this release is that `gimli` no longer requires the + object file's section be fully loaded into memory. This enables using `gimli` + on 32 bit platforms where there often isn't enough contiguous virtual memory + address space to load debugging information into. The default behavior is + still geared for 64 bit platforms, where address space overfloweth, and you + can still load the whole sections of the object file (or the entire object + file) into memory. This is abstracted over with the `gimli::Reader` + trait. This manifests as small (but many) breaking changes to much of the + public API. [#182][] + +### Fixed + +* The `DW_END_*` constants for defining endianity of a compilation unit were + previously incorrect. [#193][] + +* The `DW_OP_addr` opcode is relative to the base address of the `.text` section + of the binary, but we were incorrectly treating it as an absolute value. [#210][] + +[GitHub]: https://github.com/gimli-rs/gimli +[crates.io]: https://crates.io/crates/gimli +[contributing]: https://github.com/gimli-rs/gimli/blob/master/CONTRIBUTING.md +[easy]: https://github.com/gimli-rs/gimli/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy +[#192]: https://github.com/gimli-rs/gimli/pull/192 +[#193]: https://github.com/gimli-rs/gimli/pull/193 +[#182]: https://github.com/gimli-rs/gimli/issues/182 +[#208]: https://github.com/gimli-rs/gimli/pull/208 +[#210]: https://github.com/gimli-rs/gimli/pull/210 +[#216]: https://github.com/gimli-rs/gimli/pull/216 +[#218]: https://github.com/gimli-rs/gimli/pull/218 +[#219]: https://github.com/gimli-rs/gimli/pull/219 diff --git a/deps/crates/vendor/gimli/Cargo.toml b/deps/crates/vendor/gimli/Cargo.toml new file mode 100644 index 00000000000000..53d2f0cf05bb6e --- /dev/null +++ b/deps/crates/vendor/gimli/Cargo.toml @@ -0,0 +1,118 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.60" +name = "gimli" +version = "0.31.1" +build = false +include = [ + "/CHANGELOG.md", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src", +] +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A library for reading and writing the DWARF debugging format." +documentation = "https://docs.rs/gimli" +readme = "README.md" +keywords = [ + "DWARF", + "debug", + "ELF", + "eh_frame", +] +categories = [ + "development-tools::debugging", + "development-tools::profiling", + "parser-implementations", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/gimli-rs/gimli" +resolver = "2" + +[profile.bench] +codegen-units = 1 +debug = 2 +split-debuginfo = "packed" + +[profile.test] +split-debuginfo = "packed" + +[lib] +name = "gimli" +path = "src/lib.rs" + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.fallible-iterator] +version = "0.3.0" +optional = true +default-features = false + +[dependencies.indexmap] +version = "2.0.0" +optional = true + +[dependencies.stable_deref_trait] +version = "1.1.0" +optional = true +default-features = false + +[dev-dependencies.test-assembler] +version = "0.1.3" + +[features] +default = [ + "read-all", + "write", +] +endian-reader = [ + "read", + "dep:stable_deref_trait", +] +fallible-iterator = ["dep:fallible-iterator"] +read = ["read-core"] +read-all = [ + "read", + "std", + "fallible-iterator", + "endian-reader", +] +read-core = [] +rustc-dep-of-std = [ + "dep:core", + "dep:alloc", + "dep:compiler_builtins", +] +std = [ + "fallible-iterator?/std", + "stable_deref_trait?/std", +] +write = ["dep:indexmap"] diff --git a/deps/crates/vendor/gimli/Cargo.toml.orig b/deps/crates/vendor/gimli/Cargo.toml.orig new file mode 100644 index 00000000000000..1af13260b0e66a --- /dev/null +++ b/deps/crates/vendor/gimli/Cargo.toml.orig @@ -0,0 +1,61 @@ +[package] +name = "gimli" +version = "0.31.1" +categories = ["development-tools::debugging", "development-tools::profiling", "parser-implementations"] +description = "A library for reading and writing the DWARF debugging format." +documentation = "https://docs.rs/gimli" +edition = "2018" +include = [ + "/CHANGELOG.md", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src", +] +keywords = ["DWARF", "debug", "ELF", "eh_frame"] +license = "MIT OR Apache-2.0" +readme = "./README.md" +repository = "https://github.com/gimli-rs/gimli" +rust-version = "1.60" + +[dependencies] +fallible-iterator = { version = "0.3.0", default-features = false, optional = true } +indexmap = { version = "2.0.0", optional = true } +stable_deref_trait = { version = "1.1.0", default-features = false, optional = true } + +# Internal feature, only used when building as part of libstd, not part of the +# stable interface of this crate. +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } +compiler_builtins = { version = "0.1.2", optional = true } + +[dev-dependencies] +test-assembler = "0.1.3" + +[features] +read-core = [] +read = ["read-core"] +read-all = ["read", "std", "fallible-iterator", "endian-reader"] +endian-reader = ["read", "dep:stable_deref_trait"] +fallible-iterator = ["dep:fallible-iterator"] +write = ["dep:indexmap"] +std = ["fallible-iterator?/std", "stable_deref_trait?/std"] +default = ["read-all", "write"] + +# Internal feature, only used when building as part of libstd, not part of the +# stable interface of this crate. +rustc-dep-of-std = ["dep:core", "dep:alloc", "dep:compiler_builtins"] + +[profile.test] +split-debuginfo = "packed" + +[profile.bench] +debug = true +codegen-units = 1 +split-debuginfo = "packed" + +[workspace] +members = ["crates/examples"] +default-members = [".", "crates/examples"] +resolver = "2" diff --git a/deps/crates/vendor/gimli/LICENSE-APACHE b/deps/crates/vendor/gimli/LICENSE-APACHE new file mode 100644 index 00000000000000..16fe87b06e802f --- /dev/null +++ b/deps/crates/vendor/gimli/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/crates/vendor/gimli/LICENSE-MIT b/deps/crates/vendor/gimli/LICENSE-MIT new file mode 100644 index 00000000000000..e69282e381bc07 --- /dev/null +++ b/deps/crates/vendor/gimli/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/gimli/README.md b/deps/crates/vendor/gimli/README.md new file mode 100644 index 00000000000000..2932651528ed18 --- /dev/null +++ b/deps/crates/vendor/gimli/README.md @@ -0,0 +1,81 @@ +# `gimli` + +[![](https://img.shields.io/crates/v/gimli.svg) ![](https://img.shields.io/crates/d/gimli.svg)](https://crates.io/crates/gimli) +[![](https://docs.rs/gimli/badge.svg)](https://docs.rs/gimli/) +[![Build Status](https://github.com/gimli-rs/gimli/workflows/Rust/badge.svg)](https://github.com/gimli-rs/gimli/actions) +[![Coverage Status](https://coveralls.io/repos/github/gimli-rs/gimli/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/gimli?branch=master) + +`gimli` is a library for reading and writing the +[DWARF debugging format](https://dwarfstd.org/). + +* **Zero copy:** everything is just a reference to the original input buffer. No + copies of the input data get made. + +* **Lazy:** you can iterate compilation units without parsing their + contents. Parse only as many debugging information entry (DIE) trees as you + iterate over. `gimli` also uses `DW_AT_sibling` references to avoid parsing a + DIE's children to find its next sibling, when possible. + +* **Cross-platform:** `gimli` makes no assumptions about what kind of object + file you're working with. The flipside to that is that it's up to you to + provide an ELF loader on Linux or Mach-O loader on macOS. + + * Unsure which object file parser to use? Try the cross-platform + [`object`](https://github.com/gimli-rs/object) crate. See the + [`gimli-examples`](./crates/examples/src/bin) crate for usage with `gimli`. + +## Install + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +gimli = "0.31.1" +``` + +The minimum supported Rust version is: + +* 1.60.0 for the `read` feature and its dependencies. +* 1.65.0 for other features. + +## Documentation + +* [Documentation on docs.rs](https://docs.rs/gimli/) + +* Example programs: + + * [A simple `.debug_info` parser](./crates/examples/src/bin/simple.rs) + + * [A simple `.debug_line` parser](./crates/examples/src/bin/simple_line.rs) + + * [A `dwarfdump` clone](./crates/examples/src/bin/dwarfdump.rs) + + * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) + + * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into + code generation by making debugging information readable. + + * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the + compilers used to create each compilation unit within a shared library or + executable (via `DW_AT_producer`). + + * [`dwarf-validate`](./crates/examples/src/bin/dwarf-validate.rs), a program to validate the + integrity of some DWARF and its references between sections and compilation + units. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for hacking. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/deps/crates/vendor/gimli/src/arch.rs b/deps/crates/vendor/gimli/src/arch.rs new file mode 100644 index 00000000000000..548c34474e01b3 --- /dev/null +++ b/deps/crates/vendor/gimli/src/arch.rs @@ -0,0 +1,1091 @@ +use crate::common::Register; + +macro_rules! registers { + ($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? } + $(, aliases { $($alias_name:ident = ($alias_val:expr, $alias_disp:expr)),+ $(,)? })?) => { + #[allow(missing_docs)] + impl $struct_name { + $( + pub const $name: Register = Register($val); + )+ + $( + $(pub const $alias_name: Register = Register($alias_val);)+ + )* + } + + impl $struct_name { + /// The name of a register, or `None` if the register number is unknown. + /// + /// Only returns the primary name for registers that alias with others. + pub fn register_name(register: Register) -> Option<&'static str> { + match register { + $( + Self::$name => Some($disp), + )+ + _ => return None, + } + } + + /// Converts a register name into a register number. + pub fn name_to_register(value: &str) -> Option { + match value { + $( + $disp => Some(Self::$name), + )+ + $( + $($alias_disp => Some(Self::$alias_name),)+ + )* + _ => return None, + } + } + } + }; +} + +/// ARM architecture specific definitions. +/// +/// See [DWARF for the ARM Architecture]( +/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst). +#[derive(Debug, Clone, Copy)] +pub struct Arm; + +registers!(Arm, { + R0 = (0, "R0"), + R1 = (1, "R1"), + R2 = (2, "R2"), + R3 = (3, "R3"), + R4 = (4, "R4"), + R5 = (5, "R5"), + R6 = (6, "R6"), + R7 = (7, "R7"), + R8 = (8, "R8"), + R9 = (9, "R9"), + R10 = (10, "R10"), + R11 = (11, "R11"), + R12 = (12, "R12"), + R13 = (13, "R13"), + R14 = (14, "R14"), + R15 = (15, "R15"), + + WCGR0 = (104, "wCGR0"), + WCGR1 = (105, "wCGR1"), + WCGR2 = (106, "wCGR2"), + WCGR3 = (107, "wCGR3"), + WCGR4 = (108, "wCGR4"), + WCGR5 = (109, "wCGR5"), + WCGR6 = (110, "wCGR6"), + WCGR7 = (111, "wCGR7"), + + WR0 = (112, "wR0"), + WR1 = (113, "wR1"), + WR2 = (114, "wR2"), + WR3 = (115, "wR3"), + WR4 = (116, "wR4"), + WR5 = (117, "wR5"), + WR6 = (118, "wR6"), + WR7 = (119, "wR7"), + WR8 = (120, "wR8"), + WR9 = (121, "wR9"), + WR10 = (122, "wR10"), + WR11 = (123, "wR11"), + WR12 = (124, "wR12"), + WR13 = (125, "wR13"), + WR14 = (126, "wR14"), + WR15 = (127, "wR15"), + + SPSR = (128, "SPSR"), + SPSR_FIQ = (129, "SPSR_FIQ"), + SPSR_IRQ = (130, "SPSR_IRQ"), + SPSR_ABT = (131, "SPSR_ABT"), + SPSR_UND = (132, "SPSR_UND"), + SPSR_SVC = (133, "SPSR_SVC"), + + RA_AUTH_CODE = (143, "RA_AUTH_CODE"), + + R8_USR = (144, "R8_USR"), + R9_USR = (145, "R9_USR"), + R10_USR = (146, "R10_USR"), + R11_USR = (147, "R11_USR"), + R12_USR = (148, "R12_USR"), + R13_USR = (149, "R13_USR"), + R14_USR = (150, "R14_USR"), + + R8_FIQ = (151, "R8_FIQ"), + R9_FIQ = (152, "R9_FIQ"), + R10_FIQ = (153, "R10_FIQ"), + R11_FIQ = (154, "R11_FIQ"), + R12_FIQ = (155, "R12_FIQ"), + R13_FIQ = (156, "R13_FIQ"), + R14_FIQ = (157, "R14_FIQ"), + + R13_IRQ = (158, "R13_IRQ"), + R14_IRQ = (159, "R14_IRQ"), + + R13_ABT = (160, "R13_ABT"), + R14_ABT = (161, "R14_ABT"), + + R13_UND = (162, "R13_UND"), + R14_UND = (163, "R14_UND"), + + R13_SVC = (164, "R13_SVC"), + R14_SVC = (165, "R14_SVC"), + + WC0 = (192, "wC0"), + WC1 = (193, "wC1"), + WC2 = (194, "wC2"), + WC3 = (195, "wC3"), + WC4 = (196, "wC4"), + WC5 = (197, "wC5"), + WC6 = (198, "wC6"), + WC7 = (199, "wC7"), + + D0 = (256, "D0"), + D1 = (257, "D1"), + D2 = (258, "D2"), + D3 = (259, "D3"), + D4 = (260, "D4"), + D5 = (261, "D5"), + D6 = (262, "D6"), + D7 = (263, "D7"), + D8 = (264, "D8"), + D9 = (265, "D9"), + D10 = (266, "D10"), + D11 = (267, "D11"), + D12 = (268, "D12"), + D13 = (269, "D13"), + D14 = (270, "D14"), + D15 = (271, "D15"), + D16 = (272, "D16"), + D17 = (273, "D17"), + D18 = (274, "D18"), + D19 = (275, "D19"), + D20 = (276, "D20"), + D21 = (277, "D21"), + D22 = (278, "D22"), + D23 = (279, "D23"), + D24 = (280, "D24"), + D25 = (281, "D25"), + D26 = (282, "D26"), + D27 = (283, "D27"), + D28 = (284, "D28"), + D29 = (285, "D29"), + D30 = (286, "D30"), + D31 = (287, "D31"), + + TPIDRURO = (320, "TPIDRURO"), + TPIDRURW = (321, "TPIDRURW"), + TPIDPR = (322, "TPIDPR"), + HTPIDPR = (323, "HTPIDPR"), +}, +aliases { + SP = (13, "SP"), + LR = (14, "LR"), + PC = (15, "PC"), + + ACC0 = (104, "ACC0"), + ACC1 = (105, "ACC1"), + ACC2 = (106, "ACC2"), + ACC3 = (107, "ACC3"), + ACC4 = (108, "ACC4"), + ACC5 = (109, "ACC5"), + ACC6 = (110, "ACC6"), + ACC7 = (111, "ACC7"), + + S0 = (256, "S0"), + S1 = (256, "S1"), + S2 = (257, "S2"), + S3 = (257, "S3"), + S4 = (258, "S4"), + S5 = (258, "S5"), + S6 = (259, "S6"), + S7 = (259, "S7"), + S8 = (260, "S8"), + S9 = (260, "S9"), + S10 = (261, "S10"), + S11 = (261, "S11"), + S12 = (262, "S12"), + S13 = (262, "S13"), + S14 = (263, "S14"), + S15 = (263, "S15"), + S16 = (264, "S16"), + S17 = (264, "S17"), + S18 = (265, "S18"), + S19 = (265, "S19"), + S20 = (266, "S20"), + S21 = (266, "S21"), + S22 = (267, "S22"), + S23 = (267, "S23"), + S24 = (268, "S24"), + S25 = (268, "S25"), + S26 = (269, "S26"), + S27 = (269, "S27"), + S28 = (270, "S28"), + S29 = (270, "S29"), + S30 = (271, "S30"), + S31 = (271, "S31"), +}); + +/// ARM 64-bit (AArch64) architecture specific definitions. +/// +/// See [DWARF for the ARM 64-bit Architecture]( +/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst). +#[derive(Debug, Clone, Copy)] +pub struct AArch64; + +registers!(AArch64, { + X0 = (0, "X0"), + X1 = (1, "X1"), + X2 = (2, "X2"), + X3 = (3, "X3"), + X4 = (4, "X4"), + X5 = (5, "X5"), + X6 = (6, "X6"), + X7 = (7, "X7"), + X8 = (8, "X8"), + X9 = (9, "X9"), + X10 = (10, "X10"), + X11 = (11, "X11"), + X12 = (12, "X12"), + X13 = (13, "X13"), + X14 = (14, "X14"), + X15 = (15, "X15"), + X16 = (16, "X16"), + X17 = (17, "X17"), + X18 = (18, "X18"), + X19 = (19, "X19"), + X20 = (20, "X20"), + X21 = (21, "X21"), + X22 = (22, "X22"), + X23 = (23, "X23"), + X24 = (24, "X24"), + X25 = (25, "X25"), + X26 = (26, "X26"), + X27 = (27, "X27"), + X28 = (28, "X28"), + X29 = (29, "X29"), + X30 = (30, "X30"), + SP = (31, "SP"), + PC = (32, "PC"), + ELR_MODE = (33, "ELR_mode"), + RA_SIGN_STATE = (34, "RA_SIGN_STATE"), + TPIDRRO_EL0 = (35, "TPIDRRO_EL0"), + TPIDR_EL0 = (36, "TPIDR_EL0"), + TPIDR_EL1 = (37, "TPIDR_EL1"), + TPIDR_EL2 = (38, "TPIDR_EL2"), + TPIDR_EL3 = (39, "TPIDR_EL3"), + + VG = (46, "VG"), + FFR = (47, "FFR"), + + P0 = (48, "P0"), + P1 = (49, "P1"), + P2 = (50, "P2"), + P3 = (51, "P3"), + P4 = (52, "P4"), + P5 = (53, "P5"), + P6 = (54, "P6"), + P7 = (55, "P7"), + P8 = (56, "P8"), + P9 = (57, "P9"), + P10 = (58, "P10"), + P11 = (59, "P11"), + P12 = (60, "P12"), + P13 = (61, "P13"), + P14 = (62, "P14"), + P15 = (63, "P15"), + + V0 = (64, "V0"), + V1 = (65, "V1"), + V2 = (66, "V2"), + V3 = (67, "V3"), + V4 = (68, "V4"), + V5 = (69, "V5"), + V6 = (70, "V6"), + V7 = (71, "V7"), + V8 = (72, "V8"), + V9 = (73, "V9"), + V10 = (74, "V10"), + V11 = (75, "V11"), + V12 = (76, "V12"), + V13 = (77, "V13"), + V14 = (78, "V14"), + V15 = (79, "V15"), + V16 = (80, "V16"), + V17 = (81, "V17"), + V18 = (82, "V18"), + V19 = (83, "V19"), + V20 = (84, "V20"), + V21 = (85, "V21"), + V22 = (86, "V22"), + V23 = (87, "V23"), + V24 = (88, "V24"), + V25 = (89, "V25"), + V26 = (90, "V26"), + V27 = (91, "V27"), + V28 = (92, "V28"), + V29 = (93, "V29"), + V30 = (94, "V30"), + V31 = (95, "V31"), + + Z0 = (96, "Z0"), + Z1 = (97, "Z1"), + Z2 = (98, "Z2"), + Z3 = (99, "Z3"), + Z4 = (100, "Z4"), + Z5 = (101, "Z5"), + Z6 = (102, "Z6"), + Z7 = (103, "Z7"), + Z8 = (104, "Z8"), + Z9 = (105, "Z9"), + Z10 = (106, "Z10"), + Z11 = (107, "Z11"), + Z12 = (108, "Z12"), + Z13 = (109, "Z13"), + Z14 = (110, "Z14"), + Z15 = (111, "Z15"), + Z16 = (112, "Z16"), + Z17 = (113, "Z17"), + Z18 = (114, "Z18"), + Z19 = (115, "Z19"), + Z20 = (116, "Z20"), + Z21 = (117, "Z21"), + Z22 = (118, "Z22"), + Z23 = (119, "Z23"), + Z24 = (120, "Z24"), + Z25 = (121, "Z25"), + Z26 = (122, "Z26"), + Z27 = (123, "Z27"), + Z28 = (124, "Z28"), + Z29 = (125, "Z29"), + Z30 = (126, "Z30"), + Z31 = (127, "Z31"), +}); + +/// LoongArch architecture specific definitions. +/// +/// See [LoongArch ELF psABI specification](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html). +#[derive(Debug, Clone, Copy)] +pub struct LoongArch; + +registers!(LoongArch, { + R0 = (0, "$r0"), + R1 = (1, "$r1"), + R2 = (2, "$r2"), + R3 = (3, "$r3"), + R4 = (4, "$r4"), + R5 = (5, "$r5"), + R6 = (6, "$r6"), + R7 = (7, "$r7"), + R8 = (8, "$r8"), + R9 = (9, "$r9"), + R10 = (10, "$r10"), + R11 = (11, "$r11"), + R12 = (12, "$r12"), + R13 = (13, "$r13"), + R14 = (14, "$r14"), + R15 = (15, "$r15"), + R16 = (16, "$r16"), + R17 = (17, "$r17"), + R18 = (18, "$r18"), + R19 = (19, "$r19"), + R20 = (20, "$r20"), + R21 = (21, "$r21"), + R22 = (22, "$r22"), + R23 = (23, "$r23"), + R24 = (24, "$r24"), + R25 = (25, "$r25"), + R26 = (26, "$r26"), + R27 = (27, "$r27"), + R28 = (28, "$r28"), + R29 = (29, "$r29"), + R30 = (30, "$r30"), + R31 = (31, "$r31"), + + F0 = (32, "$f0"), + F1 = (33, "$f1"), + F2 = (34, "$f2"), + F3 = (35, "$f3"), + F4 = (36, "$f4"), + F5 = (37, "$f5"), + F6 = (38, "$f6"), + F7 = (39, "$f7"), + F8 = (40, "$f8"), + F9 = (41, "$f9"), + F10 = (42, "$f10"), + F11 = (43, "$f11"), + F12 = (44, "$f12"), + F13 = (45, "$f13"), + F14 = (46, "$f14"), + F15 = (47, "$f15"), + F16 = (48, "$f16"), + F17 = (49, "$f17"), + F18 = (50, "$f18"), + F19 = (51, "$f19"), + F20 = (52, "$f20"), + F21 = (53, "$f21"), + F22 = (54, "$f22"), + F23 = (55, "$f23"), + F24 = (56, "$f24"), + F25 = (57, "$f25"), + F26 = (58, "$f26"), + F27 = (59, "$f27"), + F28 = (60, "$f28"), + F29 = (61, "$f29"), + F30 = (62, "$f30"), + F31 = (63, "$f31"), + FCC0 = (64, "$fcc0"), + FCC1 = (65, "$fcc1"), + FCC2 = (66, "$fcc2"), + FCC3 = (67, "$fcc3"), + FCC4 = (68, "$fcc4"), + FCC5 = (69, "$fcc5"), + FCC6 = (70, "$fcc6"), + FCC7 = (71, "$fcc7"), +}, +aliases { + ZERO = (0, "$zero"), + RA = (1, "$ra"), + TP = (2, "$tp"), + SP = (3, "$sp"), + A0 = (4, "$a0"), + A1 = (5, "$a1"), + A2 = (6, "$a2"), + A3 = (7, "$a3"), + A4 = (8, "$a4"), + A5 = (9, "$a5"), + A6 = (10, "$a6"), + A7 = (11, "$a7"), + T0 = (12, "$t0"), + T1 = (13, "$t1"), + T2 = (14, "$t2"), + T3 = (15, "$t3"), + T4 = (16, "$t4"), + T5 = (17, "$t5"), + T6 = (18, "$t6"), + T7 = (19, "$t7"), + T8 = (20, "$t8"), + FP = (22, "$fp"), + S0 = (23, "$s0"), + S1 = (24, "$s1"), + S2 = (25, "$s2"), + S3 = (26, "$s3"), + S4 = (27, "$s4"), + S5 = (28, "$s5"), + S6 = (29, "$s6"), + S7 = (30, "$s7"), + S8 = (31, "$s8"), + + FA0 = (32, "$fa0"), + FA1 = (33, "$fa1"), + FA2 = (34, "$fa2"), + FA3 = (35, "$fa3"), + FA4 = (36, "$fa4"), + FA5 = (37, "$fa5"), + FA6 = (38, "$fa6"), + FA7 = (39, "$fa7"), + FT0 = (40, "$ft0"), + FT1 = (41, "$ft1"), + FT2 = (42, "$ft2"), + FT3 = (43, "$ft3"), + FT4 = (44, "$ft4"), + FT5 = (45, "$ft5"), + FT6 = (46, "$ft6"), + FT7 = (47, "$ft7"), + FT8 = (48, "$ft8"), + FT9 = (49, "$ft9"), + FT10 = (50, "$ft10"), + FT11 = (51, "$ft11"), + FT12 = (52, "$ft12"), + FT13 = (53, "$ft13"), + FT14 = (54, "$ft14"), + FT15 = (55, "$ft15"), + FS0 = (56, "$fs0"), + FS1 = (57, "$fs1"), + FS2 = (58, "$fs2"), + FS3 = (59, "$fs3"), + FS4 = (60, "$fs4"), + FS5 = (61, "$fs5"), + FS6 = (62, "$fs6"), + FS7 = (63, "$fs7"), +}); + +/// MIPS architecture specific definitions. +/// +/// See [MIPS Details](https://en.wikibooks.org/wiki/MIPS_Assembly/MIPS_Details). +#[derive(Debug, Clone, Copy)] +pub struct MIPS; + +registers!(MIPS, { + R0 = (0, "$0"), + R1 = (1, "$1"), + R2 = (2, "$2"), + R3 = (3, "$3"), + R4 = (4, "$4"), + R5 = (5, "$5"), + R6 = (6, "$6"), + R7 = (7, "$7"), + R8 = (8, "$8"), + R9 = (9, "$9"), + R10 = (10, "$10"), + R11 = (11, "$11"), + R12 = (12, "$12"), + R13 = (13, "$13"), + R14 = (14, "$14"), + R15 = (15, "$15"), + R16 = (16, "$16"), + R17 = (17, "$17"), + R18 = (18, "$18"), + R19 = (19, "$19"), + R20 = (20, "$20"), + R21 = (21, "$21"), + R22 = (22, "$22"), + R23 = (23, "$23"), + R24 = (24, "$24"), + R25 = (25, "$25"), + R26 = (26, "$26"), + R27 = (27, "$27"), + R28 = (28, "$28"), + R29 = (29, "$29"), + R30 = (30, "$30"), + R31 = (31, "$31"), + + F0 = (32, "$f0"), + F1 = (33, "$f1"), + F2 = (34, "$f2"), + F3 = (35, "$f3"), + F4 = (36, "$f4"), + F5 = (37, "$f5"), + F6 = (38, "$f6"), + F7 = (39, "$f7"), + F8 = (40, "$f8"), + F9 = (41, "$f9"), + F10 = (42, "$f10"), + F11 = (43, "$f11"), + F12 = (44, "$f12"), + F13 = (45, "$f13"), + F14 = (46, "$f14"), + F15 = (47, "$f15"), + F16 = (48, "$f16"), + F17 = (49, "$f17"), + F18 = (50, "$f18"), + F19 = (51, "$f19"), + F20 = (52, "$f20"), + F21 = (53, "$f21"), + F22 = (54, "$f22"), + F23 = (55, "$f23"), + F24 = (56, "$f24"), + F25 = (57, "$f25"), + F26 = (58, "$f26"), + F27 = (59, "$f27"), + F28 = (60, "$f28"), + F29 = (61, "$f29"), + F30 = (62, "$f30"), + F31 = (63, "$f31"), + + HI = (64, "$hi"), + LO = (65, "$lo"), +}, +aliases { + ZERO = (0, "$zero"), + AT = (1, "$at"), + V0 = (2, "$v0"), + V1 = (3, "$v1"), + A0 = (4, "$a0"), + A1 = (5, "$a1"), + A2 = (6, "$a2"), + A3 = (7, "$a3"), + T0 = (8, "$t0"), + T1 = (9, "$t1"), + T2 = (10, "$t2"), + T3 = (11, "$t3"), + T4 = (12, "$t4"), + T5 = (13, "$t5"), + T6 = (14, "$t6"), + T7 = (15, "$t7"), + S0 = (16, "$s0"), + S1 = (17, "$s1"), + S2 = (18, "$s2"), + S3 = (19, "$s3"), + S4 = (20, "$s4"), + S5 = (21, "$s5"), + S6 = (22, "$s6"), + S7 = (23, "$s7"), + T8 = (24, "$t8"), + T9 = (25, "$t9"), + K0 = (26, "$k0"), + K1 = (27, "$k1"), + GP = (28, "$gp"), + SP = (29, "$sp"), + FP = (30, "$fp"), + RA = (31, "$ra"), + + S8 = (30, "$s8") +}); + +/// RISC-V architecture specific definitions. +/// +/// See [RISC-V ELF psABI specification](https://github.com/riscv/riscv-elf-psabi-doc). +#[derive(Debug, Clone, Copy)] +pub struct RiscV; + +registers!(RiscV, { + X0 = (0, "x0"), + X1 = (1, "x1"), + X2 = (2, "x2"), + X3 = (3, "x3"), + X4 = (4, "x4"), + X5 = (5, "x5"), + X6 = (6, "x6"), + X7 = (7, "x7"), + X8 = (8, "x8"), + X9 = (9, "x9"), + X10 = (10, "x10"), + X11 = (11, "x11"), + X12 = (12, "x12"), + X13 = (13, "x13"), + X14 = (14, "x14"), + X15 = (15, "x15"), + X16 = (16, "x16"), + X17 = (17, "x17"), + X18 = (18, "x18"), + X19 = (19, "x19"), + X20 = (20, "x20"), + X21 = (21, "x21"), + X22 = (22, "x22"), + X23 = (23, "x23"), + X24 = (24, "x24"), + X25 = (25, "x25"), + X26 = (26, "x26"), + X27 = (27, "x27"), + X28 = (28, "x28"), + X29 = (29, "x29"), + X30 = (30, "x30"), + X31 = (31, "x31"), + + F0 = (32, "f0"), + F1 = (33, "f1"), + F2 = (34, "f2"), + F3 = (35, "f3"), + F4 = (36, "f4"), + F5 = (37, "f5"), + F6 = (38, "f6"), + F7 = (39, "f7"), + F8 = (40, "f8"), + F9 = (41, "f9"), + F10 = (42, "f10"), + F11 = (43, "f11"), + F12 = (44, "f12"), + F13 = (45, "f13"), + F14 = (46, "f14"), + F15 = (47, "f15"), + F16 = (48, "f16"), + F17 = (49, "f17"), + F18 = (50, "f18"), + F19 = (51, "f19"), + F20 = (52, "f20"), + F21 = (53, "f21"), + F22 = (54, "f22"), + F23 = (55, "f23"), + F24 = (56, "f24"), + F25 = (57, "f25"), + F26 = (58, "f26"), + F27 = (59, "f27"), + F28 = (60, "f28"), + F29 = (61, "f29"), + F30 = (62, "f30"), + F31 = (63, "f31"), +}, +aliases { + ZERO = (0, "zero"), + RA = (1, "ra"), + SP = (2, "sp"), + GP = (3, "gp"), + TP = (4, "tp"), + T0 = (5, "t0"), + T1 = (6, "t1"), + T2 = (7, "t2"), + S0 = (8, "s0"), + S1 = (9, "s1"), + A0 = (10, "a0"), + A1 = (11, "a1"), + A2 = (12, "a2"), + A3 = (13, "a3"), + A4 = (14, "a4"), + A5 = (15, "a5"), + A6 = (16, "a6"), + A7 = (17, "a7"), + S2 = (18, "s2"), + S3 = (19, "s3"), + S4 = (20, "s4"), + S5 = (21, "s5"), + S6 = (22, "s6"), + S7 = (23, "s7"), + S8 = (24, "s8"), + S9 = (25, "s9"), + S10 = (26, "s10"), + S11 = (27, "s11"), + T3 = (28, "t3"), + T4 = (29, "t4"), + T5 = (30, "t5"), + T6 = (31, "t6"), + + FT0 = (32, "ft0"), + FT1 = (33, "ft1"), + FT2 = (34, "ft2"), + FT3 = (35, "ft3"), + FT4 = (36, "ft4"), + FT5 = (37, "ft5"), + FT6 = (38, "ft6"), + FT7 = (39, "ft7"), + FS0 = (40, "fs0"), + FS1 = (41, "fs1"), + FA0 = (42, "fa0"), + FA1 = (43, "fa1"), + FA2 = (44, "fa2"), + FA3 = (45, "fa3"), + FA4 = (46, "fa4"), + FA5 = (47, "fa5"), + FA6 = (48, "fa6"), + FA7 = (49, "fa7"), + FS2 = (50, "fs2"), + FS3 = (51, "fs3"), + FS4 = (52, "fs4"), + FS5 = (53, "fs5"), + FS6 = (54, "fs6"), + FS7 = (55, "fs7"), + FS8 = (56, "fs8"), + FS9 = (57, "fs9"), + FS10 = (58, "fs10"), + FS11 = (59, "fs11"), + FT8 = (60, "ft8"), + FT9 = (61, "ft9"), + FT10 = (62, "ft10"), + FT11 = (63, "ft11"), +}); + +/// Intel i386 architecture specific definitions. +/// +/// See Intel386 psABi version 1.1 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). +#[derive(Debug, Clone, Copy)] +pub struct X86; + +registers!(X86, { + EAX = (0, "eax"), + ECX = (1, "ecx"), + EDX = (2, "edx"), + EBX = (3, "ebx"), + ESP = (4, "esp"), + EBP = (5, "ebp"), + ESI = (6, "esi"), + EDI = (7, "edi"), + + // Return Address register. This is stored in `0(%esp, "")` and is not a physical register. + RA = (8, "RA"), + + ST0 = (11, "st0"), + ST1 = (12, "st1"), + ST2 = (13, "st2"), + ST3 = (14, "st3"), + ST4 = (15, "st4"), + ST5 = (16, "st5"), + ST6 = (17, "st6"), + ST7 = (18, "st7"), + + XMM0 = (21, "xmm0"), + XMM1 = (22, "xmm1"), + XMM2 = (23, "xmm2"), + XMM3 = (24, "xmm3"), + XMM4 = (25, "xmm4"), + XMM5 = (26, "xmm5"), + XMM6 = (27, "xmm6"), + XMM7 = (28, "xmm7"), + + MM0 = (29, "mm0"), + MM1 = (30, "mm1"), + MM2 = (31, "mm2"), + MM3 = (32, "mm3"), + MM4 = (33, "mm4"), + MM5 = (34, "mm5"), + MM6 = (35, "mm6"), + MM7 = (36, "mm7"), + + MXCSR = (39, "mxcsr"), + + ES = (40, "es"), + CS = (41, "cs"), + SS = (42, "ss"), + DS = (43, "ds"), + FS = (44, "fs"), + GS = (45, "gs"), + + TR = (48, "tr"), + LDTR = (49, "ldtr"), + + FS_BASE = (93, "fs.base"), + GS_BASE = (94, "gs.base"), +}); + +/// AMD64 architecture specific definitions. +/// +/// See x86-64 psABI version 1.0 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). +#[derive(Debug, Clone, Copy)] +pub struct X86_64; + +registers!(X86_64, { + RAX = (0, "rax"), + RDX = (1, "rdx"), + RCX = (2, "rcx"), + RBX = (3, "rbx"), + RSI = (4, "rsi"), + RDI = (5, "rdi"), + RBP = (6, "rbp"), + RSP = (7, "rsp"), + + R8 = (8, "r8"), + R9 = (9, "r9"), + R10 = (10, "r10"), + R11 = (11, "r11"), + R12 = (12, "r12"), + R13 = (13, "r13"), + R14 = (14, "r14"), + R15 = (15, "r15"), + + // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register. + RA = (16, "RA"), + + XMM0 = (17, "xmm0"), + XMM1 = (18, "xmm1"), + XMM2 = (19, "xmm2"), + XMM3 = (20, "xmm3"), + XMM4 = (21, "xmm4"), + XMM5 = (22, "xmm5"), + XMM6 = (23, "xmm6"), + XMM7 = (24, "xmm7"), + + XMM8 = (25, "xmm8"), + XMM9 = (26, "xmm9"), + XMM10 = (27, "xmm10"), + XMM11 = (28, "xmm11"), + XMM12 = (29, "xmm12"), + XMM13 = (30, "xmm13"), + XMM14 = (31, "xmm14"), + XMM15 = (32, "xmm15"), + + ST0 = (33, "st0"), + ST1 = (34, "st1"), + ST2 = (35, "st2"), + ST3 = (36, "st3"), + ST4 = (37, "st4"), + ST5 = (38, "st5"), + ST6 = (39, "st6"), + ST7 = (40, "st7"), + + MM0 = (41, "mm0"), + MM1 = (42, "mm1"), + MM2 = (43, "mm2"), + MM3 = (44, "mm3"), + MM4 = (45, "mm4"), + MM5 = (46, "mm5"), + MM6 = (47, "mm6"), + MM7 = (48, "mm7"), + + RFLAGS = (49, "rFLAGS"), + ES = (50, "es"), + CS = (51, "cs"), + SS = (52, "ss"), + DS = (53, "ds"), + FS = (54, "fs"), + GS = (55, "gs"), + + FS_BASE = (58, "fs.base"), + GS_BASE = (59, "gs.base"), + + TR = (62, "tr"), + LDTR = (63, "ldtr"), + MXCSR = (64, "mxcsr"), + FCW = (65, "fcw"), + FSW = (66, "fsw"), + + XMM16 = (67, "xmm16"), + XMM17 = (68, "xmm17"), + XMM18 = (69, "xmm18"), + XMM19 = (70, "xmm19"), + XMM20 = (71, "xmm20"), + XMM21 = (72, "xmm21"), + XMM22 = (73, "xmm22"), + XMM23 = (74, "xmm23"), + XMM24 = (75, "xmm24"), + XMM25 = (76, "xmm25"), + XMM26 = (77, "xmm26"), + XMM27 = (78, "xmm27"), + XMM28 = (79, "xmm28"), + XMM29 = (80, "xmm29"), + XMM30 = (81, "xmm30"), + XMM31 = (82, "xmm31"), + + K0 = (118, "k0"), + K1 = (119, "k1"), + K2 = (120, "k2"), + K3 = (121, "k3"), + K4 = (122, "k4"), + K5 = (123, "k5"), + K6 = (124, "k6"), + K7 = (125, "k7"), +}); + +/// PowerPC 64bit +/// +/// See [64-bit ELF ABI Specification for OpenPOWER Architecture](https://openpowerfoundation.org/specifications/64bitelfabi/). +#[derive(Debug, Clone, Copy)] +pub struct PowerPc64; + +registers!(PowerPc64, { + R0 = (0, "r0"), + R1 = (1, "r1"), + R2 = (2, "r2"), + R3 = (3, "r3"), + R4 = (4, "r4"), + R5 = (5, "r5"), + R6 = (6, "r6"), + R7 = (7, "r7"), + R8 = (8, "r8"), + R9 = (9, "r9"), + R10 = (10, "r10"), + R11 = (11, "r11"), + R12 = (12, "r12"), + R13 = (13, "r13"), + R14 = (14, "r14"), + R15 = (15, "r15"), + R16 = (16, "r16"), + R17 = (17, "r17"), + R18 = (18, "r18"), + R19 = (19, "r19"), + R20 = (20, "r20"), + R21 = (21, "r21"), + R22 = (22, "r22"), + R23 = (23, "r23"), + R24 = (24, "r24"), + R25 = (25, "r25"), + R26 = (26, "r26"), + R27 = (27, "r27"), + R28 = (28, "r28"), + R29 = (29, "r29"), + R30 = (30, "r30"), + R31 = (31, "r31"), + + F0 = (32, "f0"), + F1 = (33, "f1"), + F2 = (34, "f2"), + F3 = (35, "f3"), + F4 = (36, "f4"), + F5 = (37, "f5"), + F6 = (38, "f6"), + F7 = (39, "f7"), + F8 = (40, "f8"), + F9 = (41, "f9"), + F10 = (42, "f10"), + F11 = (43, "f11"), + F12 = (44, "f12"), + F13 = (45, "f13"), + F14 = (46, "f14"), + F15 = (47, "f15"), + F16 = (48, "f16"), + F17 = (49, "f17"), + F18 = (50, "f18"), + F19 = (51, "f19"), + F20 = (52, "f20"), + F21 = (53, "f21"), + F22 = (54, "f22"), + F23 = (55, "f23"), + F24 = (56, "f24"), + F25 = (57, "f25"), + F26 = (58, "f26"), + F27 = (59, "f27"), + F28 = (60, "f28"), + F29 = (61, "f29"), + F30 = (62, "f30"), + F31 = (63, "f31"), + + LR = (65, "lr"), + CTR = (66, "ctr"), + + CR0 = (68, "cr0"), + CR1 = (69, "cr1"), + CR2 = (70, "cr2"), + CR3 = (71, "cr3"), + CR4 = (72, "cr4"), + CR5 = (73, "cr5"), + CR6 = (74, "cr6"), + CR7 = (75, "cr7"), + XER = (76, "xer"), + + VR0 = (77, "vr0"), + VR1 = (78, "vr1"), + VR2 = (79, "vr2"), + VR3 = (80, "vr3"), + VR4 = (81, "vr4"), + VR5 = (82, "vr5"), + VR6 = (83, "vr6"), + VR7 = (84, "vr7"), + VR8 = (85, "vr8"), + VR9 = (86, "vr9"), + VR10 = (87, "vr10"), + VR11 = (88, "vr11"), + VR12 = (89, "vr12"), + VR13 = (90, "vr13"), + VR14 = (91, "vr14"), + VR15 = (92, "vr15"), + VR16 = (93, "vr16"), + VR17 = (94, "vr17"), + VR18 = (95, "vr18"), + VR19 = (96, "vr19"), + VR20 = (97, "vr20"), + VR21 = (98, "vr21"), + VR22 = (99, "vr22"), + VR23 = (100, "vr23"), + VR24 = (101, "vr24"), + VR25 = (102, "vr25"), + VR26 = (103, "vr26"), + VR27 = (104, "vr27"), + VR28 = (105, "vr28"), + VR29 = (106, "vr29"), + VR30 = (107, "vr30"), + VR31 = (108, "vr31"), + + VSCR = (110, "vscr"), + TFHAR = (114, "tfhar"), + TFIAR = (115, "tfiar"), + TEXASR = (116, "texasr"), +}); + +#[cfg(test)] +mod tests { + + #[test] + #[cfg(feature = "std")] + fn test_aarch64_registers() { + use super::*; + use std::collections::HashSet; + + let mut names = HashSet::new(); + for n in (0..=39).chain(46..=127) { + let name = AArch64::register_name(Register(n)) + .unwrap_or_else(|| panic!("Register {} should have a name.", n)); + assert!(names.insert(name)); + } + } + + #[test] + #[cfg(feature = "std")] + fn test_power64_registers() { + use super::*; + use std::collections::HashSet; + + let mut names = HashSet::new(); + for n in (0..=63).chain(68..=75).chain(77..=108) { + let name = PowerPc64::register_name(Register(n)) + .unwrap_or_else(|| panic!("Register {} should have a name.", n)); + assert!(names.insert(name)); + } + } +} diff --git a/deps/crates/vendor/gimli/src/common.rs b/deps/crates/vendor/gimli/src/common.rs new file mode 100644 index 00000000000000..8c51121a6e781e --- /dev/null +++ b/deps/crates/vendor/gimli/src/common.rs @@ -0,0 +1,397 @@ +/// Whether the format of a compilation unit is 32- or 64-bit. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Format { + /// 64-bit DWARF + Dwarf64 = 8, + /// 32-bit DWARF + Dwarf32 = 4, +} + +impl Format { + /// Return the serialized size of an initial length field for the format. + #[inline] + pub fn initial_length_size(self) -> u8 { + match self { + Format::Dwarf32 => 4, + Format::Dwarf64 => 12, + } + } + + /// Return the natural word size for the format + #[inline] + pub fn word_size(self) -> u8 { + match self { + Format::Dwarf32 => 4, + Format::Dwarf64 => 8, + } + } +} + +/// Which vendor extensions to support. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub enum Vendor { + /// A default set of extensions, including some common GNU extensions. + Default, + /// AAarch64 extensions. + AArch64, +} + +/// Encoding parameters that are commonly used for multiple DWARF sections. +/// +/// This is intended to be small enough to pass by value. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +// `address_size` and `format` are used more often than `version`, so keep +// them first. +#[repr(C)] +pub struct Encoding { + /// The size of an address. + pub address_size: u8, + + /// Whether the DWARF format is 32- or 64-bit. + pub format: Format, + + /// The DWARF version of the header. + pub version: u16, +} + +/// Encoding parameters for a line number program. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LineEncoding { + /// The size in bytes of the smallest target machine instruction. + pub minimum_instruction_length: u8, + + /// The maximum number of individual operations that may be encoded in an + /// instruction. + pub maximum_operations_per_instruction: u8, + + /// The initial value of the `is_stmt` register. + pub default_is_stmt: bool, + + /// The minimum value which a special opcode can add to the line register. + pub line_base: i8, + + /// The range of values which a special opcode can add to the line register. + pub line_range: u8, +} + +impl Default for LineEncoding { + fn default() -> Self { + // Values from LLVM. + LineEncoding { + minimum_instruction_length: 1, + maximum_operations_per_instruction: 1, + default_is_stmt: true, + line_base: -5, + line_range: 14, + } + } +} + +/// A DWARF register number. +/// +/// The meaning of this value is ABI dependent. This is generally encoded as +/// a ULEB128, but supported architectures need 16 bits at most. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Register(pub u16); + +/// An offset into the `.debug_abbrev` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugAbbrevOffset(pub T); + +/// An offset to a set of entries in the `.debug_addr` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugAddrBase(pub T); + +/// An index into a set of addresses in the `.debug_addr` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugAddrIndex(pub T); + +/// An offset into the `.debug_aranges` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugArangesOffset(pub T); + +/// An offset into the `.debug_info` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct DebugInfoOffset(pub T); + +/// An offset into the `.debug_line` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLineOffset(pub T); + +/// An offset into the `.debug_line_str` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLineStrOffset(pub T); + +/// An offset into either the `.debug_loc` section or the `.debug_loclists` section, +/// depending on the version of the unit the offset was contained in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocationListsOffset(pub T); + +/// An offset to a set of location list offsets in the `.debug_loclists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLocListsBase(pub T); + +/// An index into a set of location list offsets in the `.debug_loclists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLocListsIndex(pub T); + +/// An offset into the `.debug_macinfo` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugMacinfoOffset(pub T); + +/// An offset into the `.debug_macro` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugMacroOffset(pub T); + +/// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, +/// depending on the version of the unit the offset was contained in. +/// +/// If this is from a DWARF 4 DWO file, then it must additionally be offset by the +/// value of `DW_AT_GNU_ranges_base`. You can use `Dwarf::ranges_offset_from_raw` to do this. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RawRangeListsOffset(pub T); + +/// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, +/// depending on the version of the unit the offset was contained in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RangeListsOffset(pub T); + +/// An offset to a set of range list offsets in the `.debug_rnglists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugRngListsBase(pub T); + +/// An index into a set of range list offsets in the `.debug_rnglists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugRngListsIndex(pub T); + +/// An offset into the `.debug_str` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugStrOffset(pub T); + +/// An offset to a set of entries in the `.debug_str_offsets` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugStrOffsetsBase(pub T); + +/// An index into a set of entries in the `.debug_str_offsets` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugStrOffsetsIndex(pub T); + +/// An offset into the `.debug_types` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct DebugTypesOffset(pub T); + +/// A type signature as used in the `.debug_types` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugTypeSignature(pub u64); + +/// An offset into the `.debug_frame` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugFrameOffset(pub T); + +impl From for DebugFrameOffset { + #[inline] + fn from(o: T) -> Self { + DebugFrameOffset(o) + } +} + +/// An offset into the `.eh_frame` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EhFrameOffset(pub T); + +impl From for EhFrameOffset { + #[inline] + fn from(o: T) -> Self { + EhFrameOffset(o) + } +} + +/// An offset into the `.debug_info` or `.debug_types` sections. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub enum UnitSectionOffset { + /// An offset into the `.debug_info` section. + DebugInfoOffset(DebugInfoOffset), + /// An offset into the `.debug_types` section. + DebugTypesOffset(DebugTypesOffset), +} + +impl From> for UnitSectionOffset { + fn from(offset: DebugInfoOffset) -> Self { + UnitSectionOffset::DebugInfoOffset(offset) + } +} + +impl From> for UnitSectionOffset { + fn from(offset: DebugTypesOffset) -> Self { + UnitSectionOffset::DebugTypesOffset(offset) + } +} + +impl UnitSectionOffset +where + T: Clone, +{ + /// Returns the `DebugInfoOffset` inside, or `None` otherwise. + pub fn as_debug_info_offset(&self) -> Option> { + match self { + UnitSectionOffset::DebugInfoOffset(offset) => Some(offset.clone()), + UnitSectionOffset::DebugTypesOffset(_) => None, + } + } + /// Returns the `DebugTypesOffset` inside, or `None` otherwise. + pub fn as_debug_types_offset(&self) -> Option> { + match self { + UnitSectionOffset::DebugInfoOffset(_) => None, + UnitSectionOffset::DebugTypesOffset(offset) => Some(offset.clone()), + } + } +} + +/// An identifier for a DWARF section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub enum SectionId { + /// The `.debug_abbrev` section. + DebugAbbrev, + /// The `.debug_addr` section. + DebugAddr, + /// The `.debug_aranges` section. + DebugAranges, + /// The `.debug_cu_index` section. + DebugCuIndex, + /// The `.debug_frame` section. + DebugFrame, + /// The `.eh_frame` section. + EhFrame, + /// The `.eh_frame_hdr` section. + EhFrameHdr, + /// The `.debug_info` section. + DebugInfo, + /// The `.debug_line` section. + DebugLine, + /// The `.debug_line_str` section. + DebugLineStr, + /// The `.debug_loc` section. + DebugLoc, + /// The `.debug_loclists` section. + DebugLocLists, + /// The `.debug_macinfo` section. + DebugMacinfo, + /// The `.debug_macro` section. + DebugMacro, + /// The `.debug_pubnames` section. + DebugPubNames, + /// The `.debug_pubtypes` section. + DebugPubTypes, + /// The `.debug_ranges` section. + DebugRanges, + /// The `.debug_rnglists` section. + DebugRngLists, + /// The `.debug_str` section. + DebugStr, + /// The `.debug_str_offsets` section. + DebugStrOffsets, + /// The `.debug_tu_index` section. + DebugTuIndex, + /// The `.debug_types` section. + DebugTypes, +} + +impl SectionId { + /// Returns the ELF section name for this kind. + pub fn name(self) -> &'static str { + match self { + SectionId::DebugAbbrev => ".debug_abbrev", + SectionId::DebugAddr => ".debug_addr", + SectionId::DebugAranges => ".debug_aranges", + SectionId::DebugCuIndex => ".debug_cu_index", + SectionId::DebugFrame => ".debug_frame", + SectionId::EhFrame => ".eh_frame", + SectionId::EhFrameHdr => ".eh_frame_hdr", + SectionId::DebugInfo => ".debug_info", + SectionId::DebugLine => ".debug_line", + SectionId::DebugLineStr => ".debug_line_str", + SectionId::DebugLoc => ".debug_loc", + SectionId::DebugLocLists => ".debug_loclists", + SectionId::DebugMacinfo => ".debug_macinfo", + SectionId::DebugMacro => ".debug_macro", + SectionId::DebugPubNames => ".debug_pubnames", + SectionId::DebugPubTypes => ".debug_pubtypes", + SectionId::DebugRanges => ".debug_ranges", + SectionId::DebugRngLists => ".debug_rnglists", + SectionId::DebugStr => ".debug_str", + SectionId::DebugStrOffsets => ".debug_str_offsets", + SectionId::DebugTuIndex => ".debug_tu_index", + SectionId::DebugTypes => ".debug_types", + } + } + + /// Returns the ELF section name for this kind, when found in a .dwo or .dwp file. + pub fn dwo_name(self) -> Option<&'static str> { + Some(match self { + SectionId::DebugAbbrev => ".debug_abbrev.dwo", + SectionId::DebugCuIndex => ".debug_cu_index", + SectionId::DebugInfo => ".debug_info.dwo", + SectionId::DebugLine => ".debug_line.dwo", + // The debug_loc section can be present in the dwo when using the + // GNU split-dwarf extension to DWARF4. + SectionId::DebugLoc => ".debug_loc.dwo", + SectionId::DebugLocLists => ".debug_loclists.dwo", + SectionId::DebugMacinfo => ".debug_macinfo.dwo", + SectionId::DebugMacro => ".debug_macro.dwo", + SectionId::DebugRngLists => ".debug_rnglists.dwo", + SectionId::DebugStr => ".debug_str.dwo", + SectionId::DebugStrOffsets => ".debug_str_offsets.dwo", + SectionId::DebugTuIndex => ".debug_tu_index", + SectionId::DebugTypes => ".debug_types.dwo", + _ => return None, + }) + } + + /// Returns the XCOFF section name for this kind. + pub fn xcoff_name(self) -> Option<&'static str> { + Some(match self { + SectionId::DebugAbbrev => ".dwabrev", + SectionId::DebugAranges => ".dwarnge", + SectionId::DebugFrame => ".dwframe", + SectionId::DebugInfo => ".dwinfo", + SectionId::DebugLine => ".dwline", + SectionId::DebugLoc => ".dwloc", + SectionId::DebugMacinfo => ".dwmac", + SectionId::DebugPubNames => ".dwpbnms", + SectionId::DebugPubTypes => ".dwpbtyp", + SectionId::DebugRanges => ".dwrnges", + SectionId::DebugStr => ".dwstr", + _ => return None, + }) + } + + /// Returns true if this is a mergeable string section. + /// + /// This is useful for determining the correct section flags. + pub fn is_string(self) -> bool { + matches!(self, SectionId::DebugStr | SectionId::DebugLineStr) + } +} + +/// An optionally-provided implementation-defined compilation unit ID to enable +/// split DWARF and linking a split compilation unit back together. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DwoId(pub u64); + +/// The "type" of file with DWARF debugging information. This determines, among other things, +/// which files DWARF sections should be loaded from. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DwarfFileType { + /// A normal executable or object file. + Main, + /// A .dwo split DWARF file. + Dwo, + // TODO: Supplementary files, .dwps? +} + +impl Default for DwarfFileType { + fn default() -> Self { + DwarfFileType::Main + } +} diff --git a/deps/crates/vendor/gimli/src/constants.rs b/deps/crates/vendor/gimli/src/constants.rs new file mode 100644 index 00000000000000..8d39288dc1de09 --- /dev/null +++ b/deps/crates/vendor/gimli/src/constants.rs @@ -0,0 +1,1446 @@ +// This file originally from https://github.com/philipc/rust-dwarf/ and +// distributed under either MIT or Apache 2.0 licenses. +// +// Copyright 2016 The rust-dwarf Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Constant definitions. +//! +//! The DWARF spec's `DW_AT_*` type is represented as `struct DwAt(u16)`, +//! `DW_FORM_*` as `DwForm(u16)`, etc. +//! +//! There are also exported const definitions for each constant. + +#![allow(non_upper_case_globals)] +#![allow(missing_docs)] + +use core::{fmt, ops}; + +// The `dw!` macro turns this: +// +// dw!(DwFoo(u32) { +// DW_FOO_bar = 0, +// DW_FOO_baz = 1, +// DW_FOO_bang = 2, +// }); +// +// into this: +// +// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +// pub struct DwFoo(pub u32); +// +// pub const DW_FOO_bar: DwFoo = DwFoo(0); +// pub const DW_FOO_baz: DwFoo = DwFoo(1); +// pub const DW_FOO_bang: DwFoo = DwFoo(2); +// +// impl DwFoo { +// pub fn static_string(&self) -> Option<&'static str> { +// ... +// } +// } +// +// impl fmt::Display for DwFoo { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { +// ... +// } +// } +macro_rules! dw { + ($(#[$meta:meta])* $struct_name:ident($struct_type:ty) + { $($name:ident = $val:expr),+ $(,)? } + $(, aliases { $($alias_name:ident = $alias_val:expr),+ $(,)? })? + ) => { + $(#[$meta])* + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct $struct_name(pub $struct_type); + + $( + pub const $name: $struct_name = $struct_name($val); + )+ + $($( + pub const $alias_name: $struct_name = $struct_name($alias_val); + )+)* + + impl $struct_name { + pub fn static_string(&self) -> Option<&'static str> { + Some(match *self { + $( + $name => stringify!($name), + )+ + _ => return None, + }) + } + } + + impl fmt::Display for $struct_name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + if let Some(s) = self.static_string() { + f.pad(s) + } else { + #[cfg(feature = "read")] + { + f.pad(&format!("Unknown {}: {}", stringify!($struct_name), self.0)) + } + #[cfg(not(feature = "read"))] + { + write!(f, "Unknown {}: {}", stringify!($struct_name), self.0) + } + } + } + } + }; +} + +dw!( +/// The section type field in a `.dwp` unit index. +/// +/// This is used for version 5 and later. +/// +/// See Section 7.3.5. +DwSect(u32) { + DW_SECT_INFO = 1, + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOCLISTS = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8, +}); + +dw!( +/// The section type field in a `.dwp` unit index with version 2. +DwSectV2(u32) { + DW_SECT_V2_INFO = 1, + DW_SECT_V2_TYPES = 2, + DW_SECT_V2_ABBREV = 3, + DW_SECT_V2_LINE = 4, + DW_SECT_V2_LOC = 5, + DW_SECT_V2_STR_OFFSETS = 6, + DW_SECT_V2_MACINFO = 7, + DW_SECT_V2_MACRO = 8, +}); + +dw!( +/// The unit type field in a unit header. +/// +/// See Section 7.5.1, Table 7.2. +DwUt(u8) { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff, +}); + +dw!( +/// The opcode for a call frame instruction. +/// +/// Section 7.24: +/// > Call frame instructions are encoded in one or more bytes. The primary +/// > opcode is encoded in the high order two bits of the first byte (that is, +/// > opcode = byte >> 6). An operand or extended opcode may be encoded in the +/// > low order 6 bits. Additional operands are encoded in subsequent bytes. +DwCfa(u8) { + DW_CFA_advance_loc = 0x01 << 6, + DW_CFA_offset = 0x02 << 6, + DW_CFA_restore = 0x03 << 6, + DW_CFA_nop = 0, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + DW_CFA_lo_user = 0x1c, + DW_CFA_hi_user = 0x3f, + + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f, +}, +aliases { + DW_CFA_AARCH64_negate_ra_state = 0x2d, +}); + +dw!( +/// The child determination encodings for DIE attributes. +/// +/// See Section 7.5.3, Table 7.4. +DwChildren(u8) { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1, +}); + +dw!( +/// The tag encodings for DIE attributes. +/// +/// See Section 7.5.3, Table 7.3. +DwTag(u16) { + DW_TAG_null = 0x00, + + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_parameter = 0x2f, + DW_TAG_template_value_parameter = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + +// DWARF 3. + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + +// DWARF 4. + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + DW_TAG_template_alias = 0x43, + +// DWARF 5. + DW_TAG_coarray_type = 0x44, + DW_TAG_generic_subrange = 0x45, + DW_TAG_dynamic_type = 0x46, + DW_TAG_atomic_type = 0x47, + DW_TAG_call_site = 0x48, + DW_TAG_call_site_parameter = 0x49, + DW_TAG_skeleton_unit = 0x4a, + DW_TAG_immutable_type = 0x4b, + + DW_TAG_lo_user = 0x4080, + DW_TAG_hi_user = 0xffff, + +// SGI/MIPS extensions. + DW_TAG_MIPS_loop = 0x4081, + +// HP extensions. + DW_TAG_HP_array_descriptor = 0x4090, + DW_TAG_HP_Bliss_field = 0x4091, + DW_TAG_HP_Bliss_field_set = 0x4092, + +// GNU extensions. + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + DW_TAG_GNU_template_template_param = 0x4106, + DW_TAG_GNU_template_parameter_pack = 0x4107, + DW_TAG_GNU_formal_parameter_pack = 0x4108, + DW_TAG_GNU_call_site = 0x4109, + DW_TAG_GNU_call_site_parameter = 0x410a, + + DW_TAG_APPLE_property = 0x4200, + +// SUN extensions. + DW_TAG_SUN_function_template = 0x4201, + DW_TAG_SUN_class_template = 0x4202, + DW_TAG_SUN_struct_template = 0x4203, + DW_TAG_SUN_union_template = 0x4204, + DW_TAG_SUN_indirect_inheritance = 0x4205, + DW_TAG_SUN_codeflags = 0x4206, + DW_TAG_SUN_memop_info = 0x4207, + DW_TAG_SUN_omp_child_func = 0x4208, + DW_TAG_SUN_rtti_descriptor = 0x4209, + DW_TAG_SUN_dtor_info = 0x420a, + DW_TAG_SUN_dtor = 0x420b, + DW_TAG_SUN_f90_interface = 0x420c, + DW_TAG_SUN_fortran_vax_structure = 0x420d, + +// ALTIUM extensions. + DW_TAG_ALTIUM_circ_type = 0x5101, + DW_TAG_ALTIUM_mwa_circ_type = 0x5102, + DW_TAG_ALTIUM_rev_carry_type = 0x5103, + DW_TAG_ALTIUM_rom = 0x5111, + +// Extensions for UPC. + DW_TAG_upc_shared_type = 0x8765, + DW_TAG_upc_strict_type = 0x8766, + DW_TAG_upc_relaxed_type = 0x8767, + +// PGI (STMicroelectronics) extensions. + DW_TAG_PGI_kanji_type = 0xa000, + DW_TAG_PGI_interface_block = 0xa020, + +// Borland extensions. + DW_TAG_BORLAND_property = 0xb000, + DW_TAG_BORLAND_Delphi_string = 0xb001, + DW_TAG_BORLAND_Delphi_dynamic_array = 0xb002, + DW_TAG_BORLAND_Delphi_set = 0xb003, + DW_TAG_BORLAND_Delphi_variant = 0xb004, +}); + +dw!( +/// The attribute encodings for DIE attributes. +/// +/// See Section 7.5.4, Table 7.5. +DwAt(u16) { + DW_AT_null = 0x00, + + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_bit_stride = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_item = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + +// DWARF 3. + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_byte_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_binary_scale = 0x5b, + DW_AT_decimal_scale = 0x5c, + DW_AT_small = 0x5d, + DW_AT_decimal_sign = 0x5e, + DW_AT_digit_count = 0x5f, + DW_AT_picture_string = 0x60, + DW_AT_mutable = 0x61, + DW_AT_threads_scaled = 0x62, + DW_AT_explicit = 0x63, + DW_AT_object_pointer = 0x64, + DW_AT_endianity = 0x65, + DW_AT_elemental = 0x66, + DW_AT_pure = 0x67, + DW_AT_recursive = 0x68, + +// DWARF 4. + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, + DW_AT_enum_class = 0x6d, + DW_AT_linkage_name = 0x6e, + +// DWARF 5. + DW_AT_string_length_bit_size = 0x6f, + DW_AT_string_length_byte_size = 0x70, + DW_AT_rank = 0x71, + DW_AT_str_offsets_base = 0x72, + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, + DW_AT_dwo_name = 0x76, + DW_AT_reference = 0x77, + DW_AT_rvalue_reference = 0x78, + DW_AT_macros = 0x79, + DW_AT_call_all_calls = 0x7a, + DW_AT_call_all_source_calls = 0x7b, + DW_AT_call_all_tail_calls = 0x7c, + DW_AT_call_return_pc = 0x7d, + DW_AT_call_value = 0x7e, + DW_AT_call_origin = 0x7f, + DW_AT_call_parameter = 0x80, + DW_AT_call_pc = 0x81, + DW_AT_call_tail_call = 0x82, + DW_AT_call_target = 0x83, + DW_AT_call_target_clobbered = 0x84, + DW_AT_call_data_location = 0x85, + DW_AT_call_data_value = 0x86, + DW_AT_noreturn = 0x87, + DW_AT_alignment = 0x88, + DW_AT_export_symbols = 0x89, + DW_AT_deleted = 0x8a, + DW_AT_defaulted = 0x8b, + DW_AT_loclists_base = 0x8c, + + DW_AT_lo_user = 0x2000, + DW_AT_hi_user = 0x3fff, + +// SGI/MIPS extensions. + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + +// This one appears to have only been implemented by Open64 for +// fortran and may conflict with other extensions. + DW_AT_MIPS_assumed_size = 0x2011, + +// TODO: HP/CPQ extensions. +// These conflict with the MIPS extensions. + + DW_AT_INTEL_other_endian = 0x2026, + +// GNU extensions + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + DW_AT_GNU_guarded_by = 0x2108, + DW_AT_GNU_pt_guarded_by = 0x2109, + DW_AT_GNU_guarded = 0x210a, + DW_AT_GNU_pt_guarded = 0x210b, + DW_AT_GNU_locks_excluded = 0x210c, + DW_AT_GNU_exclusive_locks_required = 0x210d, + DW_AT_GNU_shared_locks_required = 0x210e, + DW_AT_GNU_odr_signature = 0x210f, + DW_AT_GNU_template_name = 0x2110, + DW_AT_GNU_call_site_value = 0x2111, + DW_AT_GNU_call_site_data_value = 0x2112, + DW_AT_GNU_call_site_target = 0x2113, + DW_AT_GNU_call_site_target_clobbered = 0x2114, + DW_AT_GNU_tail_call = 0x2115, + DW_AT_GNU_all_tail_call_sites = 0x2116, + DW_AT_GNU_all_call_sites = 0x2117, + DW_AT_GNU_all_source_call_sites = 0x2118, + DW_AT_GNU_macros = 0x2119, + DW_AT_GNU_deleted = 0x211a, + +// Extensions for Fission proposal. + DW_AT_GNU_dwo_name = 0x2130, + DW_AT_GNU_dwo_id = 0x2131, + DW_AT_GNU_ranges_base = 0x2132, + DW_AT_GNU_addr_base = 0x2133, + DW_AT_GNU_pubnames = 0x2134, + DW_AT_GNU_pubtypes = 0x2135, + DW_AT_GNU_discriminator = 0x2136, + DW_AT_GNU_locviews = 0x2137, + DW_AT_GNU_entry_view = 0x2138, + +// Conflict with Sun. +// DW_AT_VMS_rtnbeg_pd_address = 0x2201, + +// Sun extensions. + DW_AT_SUN_template = 0x2201, + DW_AT_SUN_alignment = 0x2202, + DW_AT_SUN_vtable = 0x2203, + DW_AT_SUN_count_guarantee = 0x2204, + DW_AT_SUN_command_line = 0x2205, + DW_AT_SUN_vbase = 0x2206, + DW_AT_SUN_compile_options = 0x2207, + DW_AT_SUN_language = 0x2208, + DW_AT_SUN_browser_file = 0x2209, + DW_AT_SUN_vtable_abi = 0x2210, + DW_AT_SUN_func_offsets = 0x2211, + DW_AT_SUN_cf_kind = 0x2212, + DW_AT_SUN_vtable_index = 0x2213, + DW_AT_SUN_omp_tpriv_addr = 0x2214, + DW_AT_SUN_omp_child_func = 0x2215, + DW_AT_SUN_func_offset = 0x2216, + DW_AT_SUN_memop_type_ref = 0x2217, + DW_AT_SUN_profile_id = 0x2218, + DW_AT_SUN_memop_signature = 0x2219, + DW_AT_SUN_obj_dir = 0x2220, + DW_AT_SUN_obj_file = 0x2221, + DW_AT_SUN_original_name = 0x2222, + DW_AT_SUN_hwcprof_signature = 0x2223, + DW_AT_SUN_amd64_parmdump = 0x2224, + DW_AT_SUN_part_link_name = 0x2225, + DW_AT_SUN_link_name = 0x2226, + DW_AT_SUN_pass_with_const = 0x2227, + DW_AT_SUN_return_with_const = 0x2228, + DW_AT_SUN_import_by_name = 0x2229, + DW_AT_SUN_f90_pointer = 0x222a, + DW_AT_SUN_pass_by_ref = 0x222b, + DW_AT_SUN_f90_allocatable = 0x222c, + DW_AT_SUN_f90_assumed_shape_array = 0x222d, + DW_AT_SUN_c_vla = 0x222e, + DW_AT_SUN_return_value_ptr = 0x2230, + DW_AT_SUN_dtor_start = 0x2231, + DW_AT_SUN_dtor_length = 0x2232, + DW_AT_SUN_dtor_state_initial = 0x2233, + DW_AT_SUN_dtor_state_final = 0x2234, + DW_AT_SUN_dtor_state_deltas = 0x2235, + DW_AT_SUN_import_by_lname = 0x2236, + DW_AT_SUN_f90_use_only = 0x2237, + DW_AT_SUN_namelist_spec = 0x2238, + DW_AT_SUN_is_omp_child_func = 0x2239, + DW_AT_SUN_fortran_main_alias = 0x223a, + DW_AT_SUN_fortran_based = 0x223b, + + DW_AT_ALTIUM_loclist = 0x2300, + + DW_AT_use_GNAT_descriptive_type = 0x2301, + DW_AT_GNAT_descriptive_type = 0x2302, + DW_AT_GNU_numerator = 0x2303, + DW_AT_GNU_denominator = 0x2304, + DW_AT_GNU_bias = 0x2305, + + DW_AT_upc_threads_scaled = 0x3210, + +// PGI (STMicroelectronics) extensions. + DW_AT_PGI_lbase = 0x3a00, + DW_AT_PGI_soffset = 0x3a01, + DW_AT_PGI_lstride = 0x3a02, + +// Borland extensions. + DW_AT_BORLAND_property_read = 0x3b11, + DW_AT_BORLAND_property_write = 0x3b12, + DW_AT_BORLAND_property_implements = 0x3b13, + DW_AT_BORLAND_property_index = 0x3b14, + DW_AT_BORLAND_property_default = 0x3b15, + DW_AT_BORLAND_Delphi_unit = 0x3b20, + DW_AT_BORLAND_Delphi_class = 0x3b21, + DW_AT_BORLAND_Delphi_record = 0x3b22, + DW_AT_BORLAND_Delphi_metaclass = 0x3b23, + DW_AT_BORLAND_Delphi_constructor = 0x3b24, + DW_AT_BORLAND_Delphi_destructor = 0x3b25, + DW_AT_BORLAND_Delphi_anonymous_method = 0x3b26, + DW_AT_BORLAND_Delphi_interface = 0x3b27, + DW_AT_BORLAND_Delphi_ABI = 0x3b28, + DW_AT_BORLAND_Delphi_return = 0x3b29, + DW_AT_BORLAND_Delphi_frameptr = 0x3b30, + DW_AT_BORLAND_closure = 0x3b31, + +// LLVM project extensions. + DW_AT_LLVM_include_path = 0x3e00, + DW_AT_LLVM_config_macros = 0x3e01, + DW_AT_LLVM_isysroot = 0x3e02, + +// Apple extensions. + DW_AT_APPLE_optimized = 0x3fe1, + DW_AT_APPLE_flags = 0x3fe2, + DW_AT_APPLE_isa = 0x3fe3, + DW_AT_APPLE_block = 0x3fe4, + DW_AT_APPLE_major_runtime_vers = 0x3fe5, + DW_AT_APPLE_runtime_class = 0x3fe6, + DW_AT_APPLE_omit_frame_ptr = 0x3fe7, + DW_AT_APPLE_property_name = 0x3fe8, + DW_AT_APPLE_property_getter = 0x3fe9, + DW_AT_APPLE_property_setter = 0x3fea, + DW_AT_APPLE_property_attribute = 0x3feb, + DW_AT_APPLE_objc_complete_type = 0x3fec, + DW_AT_APPLE_property = 0x3fed +}); + +dw!( +/// The attribute form encodings for DIE attributes. +/// +/// See Section 7.5.6, Table 7.6. +DwForm(u16) { + DW_FORM_null = 0x00, + + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + +// DWARF 4. + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20, + +// DWARF 5. + DW_FORM_strx = 0x1a, + DW_FORM_addrx = 0x1b, + DW_FORM_ref_sup4 = 0x1c, + DW_FORM_strp_sup = 0x1d, + DW_FORM_data16 = 0x1e, + DW_FORM_line_strp = 0x1f, + DW_FORM_implicit_const = 0x21, + DW_FORM_loclistx = 0x22, + DW_FORM_rnglistx = 0x23, + DW_FORM_ref_sup8 = 0x24, + DW_FORM_strx1 = 0x25, + DW_FORM_strx2 = 0x26, + DW_FORM_strx3 = 0x27, + DW_FORM_strx4 = 0x28, + DW_FORM_addrx1 = 0x29, + DW_FORM_addrx2 = 0x2a, + DW_FORM_addrx3 = 0x2b, + DW_FORM_addrx4 = 0x2c, + +// Extensions for Fission proposal + DW_FORM_GNU_addr_index = 0x1f01, + DW_FORM_GNU_str_index = 0x1f02, + +// Alternate debug sections proposal (output of "dwz" tool). + DW_FORM_GNU_ref_alt = 0x1f20, + DW_FORM_GNU_strp_alt = 0x1f21 +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_encoding` attribute. +/// +/// See Section 7.8, Table 7.11. +DwAte(u8) { + DW_ATE_address = 0x01, + DW_ATE_boolean = 0x02, + DW_ATE_complex_float = 0x03, + DW_ATE_float = 0x04, + DW_ATE_signed = 0x05, + DW_ATE_signed_char = 0x06, + DW_ATE_unsigned = 0x07, + DW_ATE_unsigned_char = 0x08, + +// DWARF 3. + DW_ATE_imaginary_float = 0x09, + DW_ATE_packed_decimal = 0x0a, + DW_ATE_numeric_string = 0x0b, + DW_ATE_edited = 0x0c, + DW_ATE_signed_fixed = 0x0d, + DW_ATE_unsigned_fixed = 0x0e, + DW_ATE_decimal_float = 0x0f , + +// DWARF 4. + DW_ATE_UTF = 0x10, + DW_ATE_UCS = 0x11, + DW_ATE_ASCII = 0x12, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff, +}); + +dw!( +/// The encodings of the constants used in location list entries. +/// +/// See Section 7.7.3, Table 7.10. +DwLle(u8) { + DW_LLE_end_of_list = 0x00, + DW_LLE_base_addressx = 0x01, + DW_LLE_startx_endx = 0x02, + DW_LLE_startx_length = 0x03, + DW_LLE_offset_pair = 0x04, + DW_LLE_default_location = 0x05, + DW_LLE_base_address = 0x06, + DW_LLE_start_end = 0x07, + DW_LLE_start_length = 0x08, + DW_LLE_GNU_view_pair = 0x09, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_decimal_sign` attribute. +/// +/// See Section 7.8, Table 7.12. +DwDs(u8) { + DW_DS_unsigned = 0x01, + DW_DS_leading_overpunch = 0x02, + DW_DS_trailing_overpunch = 0x03, + DW_DS_leading_separate = 0x04, + DW_DS_trailing_separate = 0x05, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_endianity` attribute. +/// +/// See Section 7.8, Table 7.13. +DwEnd(u8) { + DW_END_default = 0x00, + DW_END_big = 0x01, + DW_END_little = 0x02, + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_accessibility` attribute. +/// +/// See Section 7.9, Table 7.14. +DwAccess(u8) { + DW_ACCESS_public = 0x01, + DW_ACCESS_protected = 0x02, + DW_ACCESS_private = 0x03, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_visibility` attribute. +/// +/// See Section 7.10, Table 7.15. +DwVis(u8) { + DW_VIS_local = 0x01, + DW_VIS_exported = 0x02, + DW_VIS_qualified = 0x03, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_virtuality` attribute. +/// +/// See Section 7.11, Table 7.16. +DwVirtuality(u8) { + DW_VIRTUALITY_none = 0x00, + DW_VIRTUALITY_virtual = 0x01, + DW_VIRTUALITY_pure_virtual = 0x02, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_language` attribute. +/// +/// See Section 7.12, Table 7.17. +DwLang(u16) { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PLI = 0x000f, + DW_LANG_ObjC = 0x0010, + DW_LANG_ObjC_plus_plus = 0x0011, + DW_LANG_UPC = 0x0012, + DW_LANG_D = 0x0013, + DW_LANG_Python = 0x0014, + DW_LANG_OpenCL = 0x0015, + DW_LANG_Go = 0x0016, + DW_LANG_Modula3 = 0x0017, + DW_LANG_Haskell = 0x0018, + DW_LANG_C_plus_plus_03 = 0x0019, + DW_LANG_C_plus_plus_11 = 0x001a, + DW_LANG_OCaml = 0x001b, + DW_LANG_Rust = 0x001c, + DW_LANG_C11 = 0x001d, + DW_LANG_Swift = 0x001e, + DW_LANG_Julia = 0x001f, + DW_LANG_Dylan = 0x0020, + DW_LANG_C_plus_plus_14 = 0x0021, + DW_LANG_Fortran03 = 0x0022, + DW_LANG_Fortran08 = 0x0023, + DW_LANG_RenderScript = 0x0024, + DW_LANG_BLISS = 0x0025, + DW_LANG_Kotlin = 0x0026, + DW_LANG_Zig = 0x0027, + DW_LANG_Crystal = 0x0028, + DW_LANG_C_plus_plus_17 = 0x002a, + DW_LANG_C_plus_plus_20 = 0x002b, + DW_LANG_C17 = 0x002c, + DW_LANG_Fortran18 = 0x002d, + DW_LANG_Ada2005 = 0x002e, + DW_LANG_Ada2012 = 0x002f, + + DW_LANG_lo_user = 0x8000, + DW_LANG_hi_user = 0xffff, + + DW_LANG_Mips_Assembler = 0x8001, + DW_LANG_GOOGLE_RenderScript = 0x8e57, + DW_LANG_SUN_Assembler = 0x9001, + DW_LANG_ALTIUM_Assembler = 0x9101, + DW_LANG_BORLAND_Delphi = 0xb000, +}); + +impl DwLang { + /// Get the default DW_AT_lower_bound for this language. + pub fn default_lower_bound(self) -> Option { + match self { + DW_LANG_C89 + | DW_LANG_C + | DW_LANG_C_plus_plus + | DW_LANG_Java + | DW_LANG_C99 + | DW_LANG_ObjC + | DW_LANG_ObjC_plus_plus + | DW_LANG_UPC + | DW_LANG_D + | DW_LANG_Python + | DW_LANG_OpenCL + | DW_LANG_Go + | DW_LANG_Haskell + | DW_LANG_C_plus_plus_03 + | DW_LANG_C_plus_plus_11 + | DW_LANG_OCaml + | DW_LANG_Rust + | DW_LANG_C11 + | DW_LANG_Swift + | DW_LANG_Dylan + | DW_LANG_C_plus_plus_14 + | DW_LANG_RenderScript + | DW_LANG_BLISS => Some(0), + DW_LANG_Ada83 | DW_LANG_Cobol74 | DW_LANG_Cobol85 | DW_LANG_Fortran77 + | DW_LANG_Fortran90 | DW_LANG_Pascal83 | DW_LANG_Modula2 | DW_LANG_Ada95 + | DW_LANG_Fortran95 | DW_LANG_PLI | DW_LANG_Modula3 | DW_LANG_Julia + | DW_LANG_Fortran03 | DW_LANG_Fortran08 => Some(1), + _ => None, + } + } +} + +dw!( +/// The encodings of the constants used in the `DW_AT_address_class` attribute. +/// +/// There is only one value that is common to all target architectures. +/// See Section 7.13. +DwAddr(u64) { + DW_ADDR_none = 0x00, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_identifier_case` attribute. +/// +/// See Section 7.14, Table 7.18. +DwId(u8) { + DW_ID_case_sensitive = 0x00, + DW_ID_up_case = 0x01, + DW_ID_down_case = 0x02, + DW_ID_case_insensitive = 0x03, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_calling_convention` attribute. +/// +/// See Section 7.15, Table 7.19. +DwCc(u8) { + DW_CC_normal = 0x01, + DW_CC_program = 0x02, + DW_CC_nocall = 0x03, + DW_CC_pass_by_reference = 0x04, + DW_CC_pass_by_value = 0x05, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_inline` attribute. +/// +/// See Section 7.16, Table 7.20. +DwInl(u8) { + DW_INL_not_inlined = 0x00, + DW_INL_inlined = 0x01, + DW_INL_declared_not_inlined = 0x02, + DW_INL_declared_inlined = 0x03, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_ordering` attribute. +/// +/// See Section 7.17, Table 7.17. +DwOrd(u8) { + DW_ORD_row_major = 0x00, + DW_ORD_col_major = 0x01, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_discr_list` attribute. +/// +/// See Section 7.18, Table 7.22. +DwDsc(u8) { + DW_DSC_label = 0x00, + DW_DSC_range = 0x01, +}); + +dw!( +/// Name index attribute encodings. +/// +/// See Section 7.19, Table 7.23. +DwIdx(u16) { + DW_IDX_compile_unit = 1, + DW_IDX_type_unit = 2, + DW_IDX_die_offset = 3, + DW_IDX_parent = 4, + DW_IDX_type_hash = 5, + DW_IDX_lo_user = 0x2000, + DW_IDX_hi_user = 0x3fff, +}); + +dw!( +/// The encodings of the constants used in the `DW_AT_defaulted` attribute. +/// +/// See Section 7.20, Table 7.24. +DwDefaulted(u8) { + DW_DEFAULTED_no = 0x00, + DW_DEFAULTED_in_class = 0x01, + DW_DEFAULTED_out_of_class = 0x02, +}); + +dw!( +/// The encodings for the standard opcodes for line number information. +/// +/// See Section 7.22, Table 7.25. +DwLns(u8) { + DW_LNS_copy = 0x01, + DW_LNS_advance_pc = 0x02, + DW_LNS_advance_line = 0x03, + DW_LNS_set_file = 0x04, + DW_LNS_set_column = 0x05, + DW_LNS_negate_stmt = 0x06, + DW_LNS_set_basic_block = 0x07, + DW_LNS_const_add_pc = 0x08, + DW_LNS_fixed_advance_pc = 0x09, + DW_LNS_set_prologue_end = 0x0a, + DW_LNS_set_epilogue_begin = 0x0b, + DW_LNS_set_isa = 0x0c, +}); + +dw!( +/// The encodings for the extended opcodes for line number information. +/// +/// See Section 7.22, Table 7.26. +DwLne(u8) { + DW_LNE_end_sequence = 0x01, + DW_LNE_set_address = 0x02, + DW_LNE_define_file = 0x03, + DW_LNE_set_discriminator = 0x04, + + DW_LNE_lo_user = 0x80, + DW_LNE_hi_user = 0xff, +}); + +dw!( +/// The encodings for the line number header entry formats. +/// +/// See Section 7.22, Table 7.27. +DwLnct(u16) { + DW_LNCT_path = 0x1, + DW_LNCT_directory_index = 0x2, + DW_LNCT_timestamp = 0x3, + DW_LNCT_size = 0x4, + DW_LNCT_MD5 = 0x5, + // DW_LNCT_source = 0x6, + DW_LNCT_lo_user = 0x2000, + // We currently only implement the LLVM embedded source code extension for DWARF v5. + DW_LNCT_LLVM_source = 0x2001, + DW_LNCT_hi_user = 0x3fff, +}); + +dw!( +/// The encodings for macro information entry types. +/// +/// See Section 7.23, Table 7.28. +DwMacro(u8) { + DW_MACRO_define = 0x01, + DW_MACRO_undef = 0x02, + DW_MACRO_start_file = 0x03, + DW_MACRO_end_file = 0x04, + DW_MACRO_define_strp = 0x05, + DW_MACRO_undef_strp = 0x06, + DW_MACRO_import = 0x07, + DW_MACRO_define_sup = 0x08, + DW_MACRO_undef_sup = 0x09, + DW_MACRO_import_sup = 0x0a, + DW_MACRO_define_strx = 0x0b, + DW_MACRO_undef_strx = 0x0c, + DW_MACRO_lo_user = 0xe0, + DW_MACRO_hi_user = 0xff, +}); + +dw!( +/// Range list entry encoding values. +/// +/// See Section 7.25, Table 7.30. +DwRle(u8) { + DW_RLE_end_of_list = 0x00, + DW_RLE_base_addressx = 0x01, + DW_RLE_startx_endx = 0x02, + DW_RLE_startx_length = 0x03, + DW_RLE_offset_pair = 0x04, + DW_RLE_base_address = 0x05, + DW_RLE_start_end = 0x06, + DW_RLE_start_length = 0x07, +}); + +dw!( +/// The encodings for DWARF expression operations. +/// +/// See Section 7.7.1, Table 7.9. +DwOp(u8) { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3a, + DW_OP_lit11 = 0x3b, + DW_OP_lit12 = 0x3c, + DW_OP_lit13 = 0x3d, + DW_OP_lit14 = 0x3e, + DW_OP_lit15 = 0x3f, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4a, + DW_OP_lit27 = 0x4b, + DW_OP_lit28 = 0x4c, + DW_OP_lit29 = 0x4d, + DW_OP_lit30 = 0x4e, + DW_OP_lit31 = 0x4f, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5a, + DW_OP_reg11 = 0x5b, + DW_OP_reg12 = 0x5c, + DW_OP_reg13 = 0x5d, + DW_OP_reg14 = 0x5e, + DW_OP_reg15 = 0x5f, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6a, + DW_OP_reg27 = 0x6b, + DW_OP_reg28 = 0x6c, + DW_OP_reg29 = 0x6d, + DW_OP_reg30 = 0x6e, + DW_OP_reg31 = 0x6f, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7a, + DW_OP_breg11 = 0x7b, + DW_OP_breg12 = 0x7c, + DW_OP_breg13 = 0x7d, + DW_OP_breg14 = 0x7e, + DW_OP_breg15 = 0x7f, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8a, + DW_OP_breg27 = 0x8b, + DW_OP_breg28 = 0x8c, + DW_OP_breg29 = 0x8d, + DW_OP_breg30 = 0x8e, + DW_OP_breg31 = 0x8f, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b, + DW_OP_call_frame_cfa = 0x9c, + DW_OP_bit_piece = 0x9d, + DW_OP_implicit_value = 0x9e, + DW_OP_stack_value = 0x9f, + DW_OP_implicit_pointer = 0xa0, + DW_OP_addrx = 0xa1, + DW_OP_constx = 0xa2, + DW_OP_entry_value = 0xa3, + DW_OP_const_type = 0xa4, + DW_OP_regval_type = 0xa5, + DW_OP_deref_type = 0xa6, + DW_OP_xderef_type = 0xa7, + DW_OP_convert = 0xa8, + DW_OP_reinterpret = 0xa9, + + // GNU extensions + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_implicit_pointer = 0xf2, + DW_OP_GNU_entry_value = 0xf3, + DW_OP_GNU_const_type = 0xf4, + DW_OP_GNU_regval_type = 0xf5, + DW_OP_GNU_deref_type = 0xf6, + DW_OP_GNU_convert = 0xf7, + DW_OP_GNU_reinterpret = 0xf9, + DW_OP_GNU_parameter_ref = 0xfa, + DW_OP_GNU_addr_index = 0xfb, + DW_OP_GNU_const_index = 0xfc, + + // Wasm extensions + DW_OP_WASM_location = 0xed, +}); + +dw!( +/// Pointer encoding used by `.eh_frame`. +/// +/// The four lower bits describe the +/// format of the pointer, the upper four bits describe how the encoding should +/// be applied. +/// +/// Defined in `` +DwEhPe(u8) { +// Format of pointer encoding. + +// "Unsigned value is encoded using the Little Endian Base 128" + DW_EH_PE_uleb128 = 0x1, +// "A 2 bytes unsigned value." + DW_EH_PE_udata2 = 0x2, +// "A 4 bytes unsigned value." + DW_EH_PE_udata4 = 0x3, +// "An 8 bytes unsigned value." + DW_EH_PE_udata8 = 0x4, +// "Signed value is encoded using the Little Endian Base 128" + DW_EH_PE_sleb128 = 0x9, +// "A 2 bytes signed value." + DW_EH_PE_sdata2 = 0x0a, +// "A 4 bytes signed value." + DW_EH_PE_sdata4 = 0x0b, +// "An 8 bytes signed value." + DW_EH_PE_sdata8 = 0x0c, + +// How the pointer encoding should be applied. + +// `DW_EH_PE_pcrel` pointers are relative to their own location. + DW_EH_PE_pcrel = 0x10, +// "Value is relative to the beginning of the .text section." + DW_EH_PE_textrel = 0x20, +// "Value is relative to the beginning of the .got or .eh_frame_hdr section." + DW_EH_PE_datarel = 0x30, +// "Value is relative to the beginning of the function." + DW_EH_PE_funcrel = 0x40, +// "Value is aligned to an address unit sized boundary." + DW_EH_PE_aligned = 0x50, + +// This bit can be set for any of the above encoding applications. When set, +// the encoded value is the address of the real pointer result, not the +// pointer result itself. +// +// This isn't defined in the DWARF or the `.eh_frame` standards, but is +// generated by both GNU/Linux and macOS tooling. + DW_EH_PE_indirect = 0x80, + +// These constants apply to both the lower and upper bits. + +// "The Value is a literal pointer whose size is determined by the +// architecture." + DW_EH_PE_absptr = 0x0, +// The absence of a pointer and encoding. + DW_EH_PE_omit = 0xff, +}); + +const DW_EH_PE_FORMAT_MASK: u8 = 0b0000_1111; + +// Ignores indirection bit. +const DW_EH_PE_APPLICATION_MASK: u8 = 0b0111_0000; + +impl ops::BitOr for DwEhPe { + type Output = DwEhPe; + + fn bitor(self, rhs: DwEhPe) -> DwEhPe { + DwEhPe(self.0 | rhs.0) + } +} + +impl DwEhPe { + /// Get the pointer encoding's format. + #[inline] + pub fn format(self) -> DwEhPe { + DwEhPe(self.0 & DW_EH_PE_FORMAT_MASK) + } + + /// Get the pointer encoding's application. + #[inline] + pub fn application(self) -> DwEhPe { + DwEhPe(self.0 & DW_EH_PE_APPLICATION_MASK) + } + + /// Is this encoding the absent pointer encoding? + #[inline] + pub fn is_absent(self) -> bool { + self == DW_EH_PE_omit + } + + /// Is this coding indirect? If so, its encoded value is the address of the + /// real pointer result, not the pointer result itself. + #[inline] + pub fn is_indirect(self) -> bool { + self.0 & DW_EH_PE_indirect.0 != 0 + } + + /// Is this a known, valid pointer encoding? + pub fn is_valid_encoding(self) -> bool { + if self.is_absent() { + return true; + } + + match self.format() { + DW_EH_PE_absptr | DW_EH_PE_uleb128 | DW_EH_PE_udata2 | DW_EH_PE_udata4 + | DW_EH_PE_udata8 | DW_EH_PE_sleb128 | DW_EH_PE_sdata2 | DW_EH_PE_sdata4 + | DW_EH_PE_sdata8 => {} + _ => return false, + } + + match self.application() { + DW_EH_PE_absptr | DW_EH_PE_pcrel | DW_EH_PE_textrel | DW_EH_PE_datarel + | DW_EH_PE_funcrel | DW_EH_PE_aligned => {} + _ => return false, + } + + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dw_eh_pe_format() { + let encoding = DW_EH_PE_pcrel | DW_EH_PE_uleb128; + assert_eq!(encoding.format(), DW_EH_PE_uleb128); + } + + #[test] + fn test_dw_eh_pe_application() { + let encoding = DW_EH_PE_pcrel | DW_EH_PE_uleb128; + assert_eq!(encoding.application(), DW_EH_PE_pcrel); + } + + #[test] + fn test_dw_eh_pe_is_absent() { + assert!(!DW_EH_PE_absptr.is_absent()); + assert!(DW_EH_PE_omit.is_absent()); + } + + #[test] + fn test_dw_eh_pe_is_valid_encoding_ok() { + let encoding = DW_EH_PE_uleb128 | DW_EH_PE_pcrel; + assert!(encoding.is_valid_encoding()); + assert!(DW_EH_PE_absptr.is_valid_encoding()); + assert!(DW_EH_PE_omit.is_valid_encoding()); + } + + #[test] + fn test_dw_eh_pe_is_valid_encoding_bad_format() { + let encoding = DwEhPe((DW_EH_PE_sdata8.0 + 1) | DW_EH_PE_pcrel.0); + assert!(!encoding.is_valid_encoding()); + } + + #[test] + fn test_dw_eh_pe_is_valid_encoding_bad_application() { + let encoding = DwEhPe(DW_EH_PE_sdata8.0 | (DW_EH_PE_aligned.0 + 1)); + assert!(!encoding.is_valid_encoding()); + } +} diff --git a/deps/crates/vendor/gimli/src/endianity.rs b/deps/crates/vendor/gimli/src/endianity.rs new file mode 100644 index 00000000000000..3201551f1b8ad6 --- /dev/null +++ b/deps/crates/vendor/gimli/src/endianity.rs @@ -0,0 +1,256 @@ +//! Types for compile-time and run-time endianity. + +use core::convert::TryInto; +use core::fmt::Debug; + +/// A trait describing the endianity of some buffer. +pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { + /// Return true for big endian byte order. + fn is_big_endian(self) -> bool; + + /// Return true for little endian byte order. + #[inline] + fn is_little_endian(self) -> bool { + !self.is_big_endian() + } + + /// Reads an unsigned 16 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + #[inline] + fn read_u16(self, buf: &[u8]) -> u16 { + let bytes: &[u8; 2] = buf[..2].try_into().unwrap(); + if self.is_big_endian() { + u16::from_be_bytes(*bytes) + } else { + u16::from_le_bytes(*bytes) + } + } + + /// Reads an unsigned 32 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + #[inline] + fn read_u32(self, buf: &[u8]) -> u32 { + let bytes: &[u8; 4] = buf[..4].try_into().unwrap(); + if self.is_big_endian() { + u32::from_be_bytes(*bytes) + } else { + u32::from_le_bytes(*bytes) + } + } + + /// Reads an unsigned 64 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + #[inline] + fn read_u64(self, buf: &[u8]) -> u64 { + let bytes: &[u8; 8] = buf[..8].try_into().unwrap(); + if self.is_big_endian() { + u64::from_be_bytes(*bytes) + } else { + u64::from_le_bytes(*bytes) + } + } + + /// Read an unsigned n-bytes integer u64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 1` or `buf.len() > 8`. + #[inline] + fn read_uint(&mut self, buf: &[u8]) -> u64 { + let mut tmp = [0; 8]; + if self.is_big_endian() { + tmp[8 - buf.len()..].copy_from_slice(buf); + } else { + tmp[..buf.len()].copy_from_slice(buf); + } + self.read_u64(&tmp) + } + + /// Reads a signed 16 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + #[inline] + fn read_i16(self, buf: &[u8]) -> i16 { + self.read_u16(buf) as i16 + } + + /// Reads a signed 32 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + #[inline] + fn read_i32(self, buf: &[u8]) -> i32 { + self.read_u32(buf) as i32 + } + + /// Reads a signed 64 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + #[inline] + fn read_i64(self, buf: &[u8]) -> i64 { + self.read_u64(buf) as i64 + } + + /// Reads a 32 bit floating point number from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + #[inline] + fn read_f32(self, buf: &[u8]) -> f32 { + f32::from_bits(self.read_u32(buf)) + } + + /// Reads a 32 bit floating point number from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + #[inline] + fn read_f64(self, buf: &[u8]) -> f64 { + f64::from_bits(self.read_u64(buf)) + } + + /// Writes an unsigned 16 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + #[inline] + fn write_u16(self, buf: &mut [u8], n: u16) { + let bytes = if self.is_big_endian() { + n.to_be_bytes() + } else { + n.to_le_bytes() + }; + buf[..2].copy_from_slice(&bytes); + } + + /// Writes an unsigned 32 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + #[inline] + fn write_u32(self, buf: &mut [u8], n: u32) { + let bytes = if self.is_big_endian() { + n.to_be_bytes() + } else { + n.to_le_bytes() + }; + buf[..4].copy_from_slice(&bytes); + } + + /// Writes an unsigned 64 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + #[inline] + fn write_u64(self, buf: &mut [u8], n: u64) { + let bytes = if self.is_big_endian() { + n.to_be_bytes() + } else { + n.to_le_bytes() + }; + buf[..8].copy_from_slice(&bytes); + } +} + +/// Byte order that is selectable at runtime. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RunTimeEndian { + /// Little endian byte order. + Little, + /// Big endian byte order. + Big, +} + +impl Default for RunTimeEndian { + #[cfg(target_endian = "little")] + #[inline] + fn default() -> RunTimeEndian { + RunTimeEndian::Little + } + + #[cfg(target_endian = "big")] + #[inline] + fn default() -> RunTimeEndian { + RunTimeEndian::Big + } +} + +impl Endianity for RunTimeEndian { + #[inline] + fn is_big_endian(self) -> bool { + self != RunTimeEndian::Little + } +} + +/// Little endian byte order. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LittleEndian; + +impl Default for LittleEndian { + #[inline] + fn default() -> LittleEndian { + LittleEndian + } +} + +impl Endianity for LittleEndian { + #[inline] + fn is_big_endian(self) -> bool { + false + } +} + +/// Big endian byte order. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct BigEndian; + +impl Default for BigEndian { + #[inline] + fn default() -> BigEndian { + BigEndian + } +} + +impl Endianity for BigEndian { + #[inline] + fn is_big_endian(self) -> bool { + true + } +} + +/// The native endianity for the target platform. +#[cfg(target_endian = "little")] +pub type NativeEndian = LittleEndian; + +#[cfg(target_endian = "little")] +#[allow(non_upper_case_globals)] +#[doc(hidden)] +pub const NativeEndian: LittleEndian = LittleEndian; + +/// The native endianity for the target platform. +#[cfg(target_endian = "big")] +pub type NativeEndian = BigEndian; + +#[cfg(target_endian = "big")] +#[allow(non_upper_case_globals)] +#[doc(hidden)] +pub const NativeEndian: BigEndian = BigEndian; diff --git a/deps/crates/vendor/gimli/src/leb128.rs b/deps/crates/vendor/gimli/src/leb128.rs new file mode 100644 index 00000000000000..c0ee303ae54d2e --- /dev/null +++ b/deps/crates/vendor/gimli/src/leb128.rs @@ -0,0 +1,612 @@ +//! Read and write DWARF's "Little Endian Base 128" (LEB128) variable length +//! integer encoding. +//! +//! The implementation is a direct translation of the psuedocode in the DWARF 4 +//! standard's appendix C. +//! +//! Read and write signed integers: +//! +//! ``` +//! # #[cfg(all(feature = "read", feature = "write"))] { +//! use gimli::{EndianSlice, NativeEndian, leb128}; +//! +//! let mut buf = [0; 1024]; +//! +//! // Write to anything that implements `std::io::Write`. +//! { +//! let mut writable = &mut buf[..]; +//! leb128::write::signed(&mut writable, -12345).expect("Should write number"); +//! } +//! +//! // Read from anything that implements `gimli::Reader`. +//! let mut readable = EndianSlice::new(&buf[..], NativeEndian); +//! let val = leb128::read::signed(&mut readable).expect("Should read number"); +//! assert_eq!(val, -12345); +//! # } +//! ``` +//! +//! Or read and write unsigned integers: +//! +//! ``` +//! # #[cfg(all(feature = "read", feature = "write"))] { +//! use gimli::{EndianSlice, NativeEndian, leb128}; +//! +//! let mut buf = [0; 1024]; +//! +//! { +//! let mut writable = &mut buf[..]; +//! leb128::write::unsigned(&mut writable, 98765).expect("Should write number"); +//! } +//! +//! let mut readable = EndianSlice::new(&buf[..], NativeEndian); +//! let val = leb128::read::unsigned(&mut readable).expect("Should read number"); +//! assert_eq!(val, 98765); +//! # } +//! ``` + +const CONTINUATION_BIT: u8 = 1 << 7; +#[cfg(feature = "read-core")] +const SIGN_BIT: u8 = 1 << 6; + +#[inline] +fn low_bits_of_byte(byte: u8) -> u8 { + byte & !CONTINUATION_BIT +} + +#[inline] +#[allow(dead_code)] +fn low_bits_of_u64(val: u64) -> u8 { + let byte = val & u64::from(u8::MAX); + low_bits_of_byte(byte as u8) +} + +/// A module for reading signed and unsigned integers that have been LEB128 +/// encoded. +#[cfg(feature = "read-core")] +pub mod read { + use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT}; + use crate::read::{Error, Reader, Result}; + + /// Read bytes until the LEB128 continuation bit is not set. + pub fn skip(r: &mut R) -> Result<()> { + loop { + let byte = r.read_u8()?; + if byte & CONTINUATION_BIT == 0 { + return Ok(()); + } + } + } + + /// Read an unsigned LEB128 number from the given `Reader` and + /// return it or an error if reading failed. + pub fn unsigned(r: &mut R) -> Result { + let mut result = 0; + let mut shift = 0; + + loop { + let byte = r.read_u8()?; + if shift == 63 && byte != 0x00 && byte != 0x01 { + return Err(Error::BadUnsignedLeb128); + } + + let low_bits = u64::from(low_bits_of_byte(byte)); + result |= low_bits << shift; + + if byte & CONTINUATION_BIT == 0 { + return Ok(result); + } + + shift += 7; + } + } + + /// Read an LEB128 u16 from the given `Reader` and + /// return it or an error if reading failed. + pub fn u16(r: &mut R) -> Result { + let byte = r.read_u8()?; + let mut result = u16::from(low_bits_of_byte(byte)); + if byte & CONTINUATION_BIT == 0 { + return Ok(result); + } + + let byte = r.read_u8()?; + result |= u16::from(low_bits_of_byte(byte)) << 7; + if byte & CONTINUATION_BIT == 0 { + return Ok(result); + } + + let byte = r.read_u8()?; + if byte > 0x03 { + return Err(Error::BadUnsignedLeb128); + } + result += u16::from(byte) << 14; + Ok(result) + } + + /// Read a signed LEB128 number from the given `Reader` and + /// return it or an error if reading failed. + pub fn signed(r: &mut R) -> Result { + let mut result = 0; + let mut shift = 0; + let size = 64; + let mut byte; + + loop { + byte = r.read_u8()?; + if shift == 63 && byte != 0x00 && byte != 0x7f { + return Err(Error::BadSignedLeb128); + } + + let low_bits = i64::from(low_bits_of_byte(byte)); + result |= low_bits << shift; + shift += 7; + + if byte & CONTINUATION_BIT == 0 { + break; + } + } + + if shift < size && (SIGN_BIT & byte) == SIGN_BIT { + // Sign extend the result. + result |= !0 << shift; + } + + Ok(result) + } +} + +/// A module for writing integers encoded as LEB128. +#[cfg(feature = "write")] +pub mod write { + use super::{low_bits_of_u64, CONTINUATION_BIT}; + use std::io; + + /// Write the given unsigned number using the LEB128 encoding to the given + /// `std::io::Write`able. Returns the number of bytes written to `w`, or an + /// error if writing failed. + pub fn unsigned(w: &mut W, mut val: u64) -> Result + where + W: io::Write, + { + let mut bytes_written = 0; + loop { + let mut byte = low_bits_of_u64(val); + val >>= 7; + if val != 0 { + // More bytes to come, so set the continuation bit. + byte |= CONTINUATION_BIT; + } + + let buf = [byte]; + w.write_all(&buf)?; + bytes_written += 1; + + if val == 0 { + return Ok(bytes_written); + } + } + } + + /// Return the size of the LEB128 encoding of the given unsigned number. + pub fn uleb128_size(mut val: u64) -> usize { + let mut size = 0; + loop { + val >>= 7; + size += 1; + if val == 0 { + return size; + } + } + } + + /// Write the given signed number using the LEB128 encoding to the given + /// `std::io::Write`able. Returns the number of bytes written to `w`, or an + /// error if writing failed. + pub fn signed(w: &mut W, mut val: i64) -> Result + where + W: io::Write, + { + let mut bytes_written = 0; + loop { + let mut byte = val as u8; + // Keep the sign bit for testing + val >>= 6; + let done = val == 0 || val == -1; + if done { + byte &= !CONTINUATION_BIT; + } else { + // Remove the sign bit + val >>= 1; + // More bytes to come, so set the continuation bit. + byte |= CONTINUATION_BIT; + } + + let buf = [byte]; + w.write_all(&buf)?; + bytes_written += 1; + + if done { + return Ok(bytes_written); + } + } + } + + /// Return the size of the LEB128 encoding of the given signed number. + pub fn sleb128_size(mut val: i64) -> usize { + let mut size = 0; + loop { + val >>= 6; + let done = val == 0 || val == -1; + val >>= 1; + size += 1; + if done { + return size; + } + } + } +} + +#[cfg(test)] +#[cfg(all(feature = "read", feature = "write"))] +mod tests { + use super::{low_bits_of_byte, low_bits_of_u64, read, write, CONTINUATION_BIT}; + use crate::endianity::NativeEndian; + use crate::read::{EndianSlice, Error, ReaderOffsetId}; + + trait ResultExt { + fn map_eof(self, input: &[u8]) -> Self; + } + + impl ResultExt for Result { + fn map_eof(self, input: &[u8]) -> Self { + match self { + Err(Error::UnexpectedEof(id)) => { + let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); + Err(Error::UnexpectedEof(id)) + } + r => r, + } + } + } + + #[test] + fn test_low_bits_of_byte() { + for i in 0..127 { + assert_eq!(i, low_bits_of_byte(i)); + assert_eq!(i, low_bits_of_byte(i | CONTINUATION_BIT)); + } + } + + #[test] + fn test_low_bits_of_u64() { + for i in 0u64..127 { + assert_eq!(i as u8, low_bits_of_u64(1 << 16 | i)); + assert_eq!( + i as u8, + low_bits_of_u64(i << 16 | i | (u64::from(CONTINUATION_BIT))) + ); + } + } + + // Examples from the DWARF 4 standard, section 7.6, figure 22. + #[test] + fn test_read_unsigned() { + let buf = [2u8]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 2, + read::unsigned(&mut readable).expect("Should read number") + ); + + let buf = [127u8]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 127, + read::unsigned(&mut readable).expect("Should read number") + ); + + let buf = [CONTINUATION_BIT, 1]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 128, + read::unsigned(&mut readable).expect("Should read number") + ); + + let buf = [1u8 | CONTINUATION_BIT, 1]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 129, + read::unsigned(&mut readable).expect("Should read number") + ); + + let buf = [2u8 | CONTINUATION_BIT, 1]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 130, + read::unsigned(&mut readable).expect("Should read number") + ); + + let buf = [57u8 | CONTINUATION_BIT, 100]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 12857, + read::unsigned(&mut readable).expect("Should read number") + ); + } + + // Examples from the DWARF 4 standard, section 7.6, figure 23. + #[test] + fn test_read_signed() { + let buf = [2u8]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!(2, read::signed(&mut readable).expect("Should read number")); + + let buf = [0x7eu8]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!(-2, read::signed(&mut readable).expect("Should read number")); + + let buf = [127u8 | CONTINUATION_BIT, 0]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 127, + read::signed(&mut readable).expect("Should read number") + ); + + let buf = [1u8 | CONTINUATION_BIT, 0x7f]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + -127, + read::signed(&mut readable).expect("Should read number") + ); + + let buf = [CONTINUATION_BIT, 1]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 128, + read::signed(&mut readable).expect("Should read number") + ); + + let buf = [CONTINUATION_BIT, 0x7f]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + -128, + read::signed(&mut readable).expect("Should read number") + ); + + let buf = [1u8 | CONTINUATION_BIT, 1]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + 129, + read::signed(&mut readable).expect("Should read number") + ); + + let buf = [0x7fu8 | CONTINUATION_BIT, 0x7e]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + -129, + read::signed(&mut readable).expect("Should read number") + ); + } + + #[test] + fn test_read_signed_63_bits() { + let buf = [ + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + CONTINUATION_BIT, + 0x40, + ]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + -0x4000_0000_0000_0000, + read::signed(&mut readable).expect("Should read number") + ); + } + + #[test] + fn test_read_unsigned_not_enough_data() { + let buf = [CONTINUATION_BIT]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + read::unsigned(&mut readable).map_eof(&buf), + Err(Error::UnexpectedEof(ReaderOffsetId(1))) + ); + } + + #[test] + fn test_read_signed_not_enough_data() { + let buf = [CONTINUATION_BIT]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + read::signed(&mut readable).map_eof(&buf), + Err(Error::UnexpectedEof(ReaderOffsetId(1))) + ); + } + + #[test] + fn test_write_unsigned_not_enough_space() { + let mut buf = [0; 1]; + let mut writable = &mut buf[..]; + match write::unsigned(&mut writable, 128) { + Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::WriteZero), + otherwise => panic!("Unexpected: {:?}", otherwise), + } + } + + #[test] + fn test_write_signed_not_enough_space() { + let mut buf = [0; 1]; + let mut writable = &mut buf[..]; + match write::signed(&mut writable, 128) { + Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::WriteZero), + otherwise => panic!("Unexpected: {:?}", otherwise), + } + } + + #[test] + fn dogfood_signed() { + fn inner(i: i64) { + let mut buf = [0u8; 1024]; + + { + let mut writable = &mut buf[..]; + write::signed(&mut writable, i).expect("Should write signed number"); + } + + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + let result = read::signed(&mut readable).expect("Should be able to read it back again"); + assert_eq!(i, result); + } + for i in -513..513 { + inner(i); + } + inner(i64::MIN); + } + + #[test] + fn dogfood_unsigned() { + for i in 0..1025 { + let mut buf = [0u8; 1024]; + + { + let mut writable = &mut buf[..]; + write::unsigned(&mut writable, i).expect("Should write signed number"); + } + + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + let result = + read::unsigned(&mut readable).expect("Should be able to read it back again"); + assert_eq!(i, result); + } + } + + #[test] + fn test_read_unsigned_overflow() { + let buf = [ + 2u8 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 1, + ]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert!(read::unsigned(&mut readable).is_err()); + } + + #[test] + fn test_read_signed_overflow() { + let buf = [ + 2u8 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 2 | CONTINUATION_BIT, + 1, + ]; + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert!(read::signed(&mut readable).is_err()); + } + + #[test] + fn test_read_multiple() { + let buf = [2u8 | CONTINUATION_BIT, 1u8, 1u8]; + + let mut readable = EndianSlice::new(&buf[..], NativeEndian); + assert_eq!( + read::unsigned(&mut readable).expect("Should read first number"), + 130u64 + ); + assert_eq!( + read::unsigned(&mut readable).expect("Should read first number"), + 1u64 + ); + } + + #[test] + fn test_read_u16() { + for (buf, val) in [ + (&[2][..], 2), + (&[0x7f][..], 0x7f), + (&[0x80, 1][..], 0x80), + (&[0x81, 1][..], 0x81), + (&[0x82, 1][..], 0x82), + (&[0xff, 0x7f][..], 0x3fff), + (&[0x80, 0x80, 1][..], 0x4000), + (&[0xff, 0xff, 1][..], 0x7fff), + (&[0xff, 0xff, 3][..], 0xffff), + ] + .iter() + { + let mut readable = EndianSlice::new(buf, NativeEndian); + assert_eq!(*val, read::u16(&mut readable).expect("Should read number")); + } + + for buf in [ + &[0x80][..], + &[0x80, 0x80][..], + &[0x80, 0x80, 4][..], + &[0x80, 0x80, 0x80, 3][..], + ] + .iter() + { + let mut readable = EndianSlice::new(buf, NativeEndian); + assert!(read::u16(&mut readable).is_err(), "{:?}", buf); + } + } +} diff --git a/deps/crates/vendor/gimli/src/lib.rs b/deps/crates/vendor/gimli/src/lib.rs new file mode 100644 index 00000000000000..c69823c2ff2ea7 --- /dev/null +++ b/deps/crates/vendor/gimli/src/lib.rs @@ -0,0 +1,79 @@ +//! `gimli` is a library for reading and writing the +//! [DWARF debugging format](https://dwarfstd.org/). +//! +//! See the [read](./read/index.html) and [write](./write/index.html) modules +//! for examples and API documentation. +//! +//! ## Cargo Features +//! +//! Cargo features that can be enabled with `gimli`: +//! +//! * `std`: Enabled by default. Use the `std` library. Disabling this feature +//! allows using `gimli` in embedded environments that do not have access to +//! `std`. Note that even when `std` is disabled, `gimli` still requires an +//! implementation of the `alloc` crate. +//! +//! * `read`: Enabled by default. Enables the `read` module. Use of `std` is +//! optional. +//! +//! * `write`: Enabled by default. Enables the `write` module. Always uses +//! the `std` library. +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +// Selectively enable rust 2018 warnings +#![warn(bare_trait_objects)] +#![warn(unused_extern_crates)] +#![warn(ellipsis_inclusive_range_patterns)] +#![warn(elided_lifetimes_in_paths)] +#![warn(explicit_outlives_requirements)] +// Style. +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::collapsible_else_if)] +#![allow(clippy::comparison_chain)] +#![allow(clippy::manual_range_contains)] +#![allow(clippy::needless_late_init)] +#![allow(clippy::too_many_arguments)] +// False positives with `fallible_iterator`. +#![allow(clippy::should_implement_trait)] +// False positives. +#![allow(clippy::derive_partial_eq_without_eq)] +#![no_std] + +#[allow(unused_imports)] +#[cfg(any(feature = "read", feature = "write"))] +#[macro_use] +extern crate alloc; + +#[cfg(any(feature = "std", feature = "write"))] +#[macro_use] +extern crate std; + +#[cfg(feature = "endian-reader")] +pub use stable_deref_trait::{CloneStableDeref, StableDeref}; + +mod common; +pub use crate::common::*; + +mod arch; +pub use crate::arch::*; + +pub mod constants; +// For backwards compat. +pub use crate::constants::*; + +mod endianity; +pub use crate::endianity::*; + +pub mod leb128; + +#[cfg(feature = "read-core")] +pub mod read; +// For backwards compat. +#[cfg(feature = "read-core")] +pub use crate::read::*; + +#[cfg(feature = "write")] +pub mod write; + +#[cfg(test)] +mod test_util; diff --git a/deps/crates/vendor/gimli/src/read/abbrev.rs b/deps/crates/vendor/gimli/src/read/abbrev.rs new file mode 100644 index 00000000000000..b9931b2e9bfa57 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/abbrev.rs @@ -0,0 +1,1092 @@ +//! Functions for parsing DWARF debugging abbreviations. + +use alloc::collections::btree_map; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::convert::TryFrom; +use core::fmt::{self, Debug}; +use core::iter::FromIterator; +use core::ops::Deref; + +use crate::common::{DebugAbbrevOffset, Encoding, SectionId}; +use crate::constants; +use crate::endianity::Endianity; +use crate::read::{ + DebugInfoUnitHeadersIter, EndianSlice, Error, Reader, ReaderOffset, Result, Section, UnitHeader, +}; + +/// The `DebugAbbrev` struct represents the abbreviations describing +/// `DebuggingInformationEntry`s' attribute names and forms found in the +/// `.debug_abbrev` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugAbbrev { + debug_abbrev_section: R, +} + +impl<'input, Endian> DebugAbbrev> +where + Endian: Endianity, +{ + /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_abbrev` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugAbbrev, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_abbrev_section_somehow = || &buf; + /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); + /// ``` + pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(debug_abbrev_section, endian)) + } +} + +impl DebugAbbrev { + /// Parse the abbreviations at the given `offset` within this + /// `.debug_abbrev` section. + /// + /// The `offset` should generally be retrieved from a unit header. + pub fn abbreviations( + &self, + debug_abbrev_offset: DebugAbbrevOffset, + ) -> Result { + let input = &mut self.debug_abbrev_section.clone(); + input.skip(debug_abbrev_offset.0)?; + Abbreviations::parse(input) + } +} + +impl DebugAbbrev { + /// Create a `DebugAbbrev` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev + where + F: FnMut(&'a T) -> R, + { + borrow(&self.debug_abbrev_section).into() + } +} + +impl Section for DebugAbbrev { + fn id() -> SectionId { + SectionId::DebugAbbrev + } + + fn reader(&self) -> &R { + &self.debug_abbrev_section + } +} + +impl From for DebugAbbrev { + fn from(debug_abbrev_section: R) -> Self { + DebugAbbrev { + debug_abbrev_section, + } + } +} + +/// The strategy to use for caching abbreviations. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub enum AbbreviationsCacheStrategy { + /// Cache abbreviations that are used more than once. + /// + /// This is useful if the units in the `.debug_info` section will be parsed only once. + Duplicates, + /// Cache all abbreviations. + /// + /// This is useful if the units in the `.debug_info` section will be parsed more than once. + All, +} + +/// A cache of previously parsed `Abbreviations`. +#[derive(Debug, Default)] +pub struct AbbreviationsCache { + abbreviations: btree_map::BTreeMap>>, +} + +impl AbbreviationsCache { + /// Create an empty abbreviations cache. + pub fn new() -> Self { + Self::default() + } + + /// Parse abbreviations and store them in the cache. + /// + /// This will iterate over the given units to determine the abbreviations + /// offsets. Any existing cache entries are discarded. + /// + /// Errors during parsing abbreviations are also stored in the cache. + /// Errors during iterating over the units are ignored. + pub fn populate( + &mut self, + strategy: AbbreviationsCacheStrategy, + debug_abbrev: &DebugAbbrev, + mut units: DebugInfoUnitHeadersIter, + ) { + let mut offsets = Vec::new(); + match strategy { + AbbreviationsCacheStrategy::Duplicates => { + while let Ok(Some(unit)) = units.next() { + offsets.push(unit.debug_abbrev_offset()); + } + offsets.sort_unstable_by_key(|offset| offset.0); + let mut prev_offset = R::Offset::from_u8(0); + let mut count = 0; + offsets.retain(|offset| { + if count == 0 || prev_offset != offset.0 { + prev_offset = offset.0; + count = 1; + } else { + count += 1; + } + count == 2 + }); + } + AbbreviationsCacheStrategy::All => { + while let Ok(Some(unit)) = units.next() { + offsets.push(unit.debug_abbrev_offset()); + } + offsets.sort_unstable_by_key(|offset| offset.0); + offsets.dedup(); + } + } + self.abbreviations = offsets + .into_iter() + .map(|offset| { + ( + offset.0.into_u64(), + debug_abbrev.abbreviations(offset).map(Arc::new), + ) + }) + .collect(); + } + + /// Set an entry in the abbreviations cache. + /// + /// This is only required if you want to manually populate the cache. + pub fn set( + &mut self, + offset: DebugAbbrevOffset, + abbreviations: Arc, + ) { + self.abbreviations + .insert(offset.0.into_u64(), Ok(abbreviations)); + } + + /// Parse the abbreviations at the given offset. + /// + /// This uses the cache if possible, but does not update it. + pub fn get( + &self, + debug_abbrev: &DebugAbbrev, + offset: DebugAbbrevOffset, + ) -> Result> { + match self.abbreviations.get(&offset.0.into_u64()) { + Some(entry) => entry.clone(), + None => debug_abbrev.abbreviations(offset).map(Arc::new), + } + } +} + +/// A set of type abbreviations. +/// +/// Construct an `Abbreviations` instance with the +/// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) +/// method. +#[derive(Debug, Default, Clone)] +pub struct Abbreviations { + vec: Vec, + map: btree_map::BTreeMap, +} + +impl Abbreviations { + /// Construct a new, empty set of abbreviations. + fn empty() -> Abbreviations { + Abbreviations { + vec: Vec::new(), + map: btree_map::BTreeMap::new(), + } + } + + /// Insert an abbreviation into the set. + /// + /// Returns `Ok` if it is the first abbreviation in the set with its code, + /// `Err` if the code is a duplicate and there already exists an + /// abbreviation in the set with the given abbreviation's code. + fn insert(&mut self, abbrev: Abbreviation) -> ::core::result::Result<(), ()> { + let code_usize = abbrev.code as usize; + if code_usize as u64 == abbrev.code { + // Optimize for sequential abbreviation codes by storing them + // in a Vec, as long as the map doesn't already contain them. + // A potential further optimization would be to allow some + // holes in the Vec, but there's no need for that yet. + if code_usize - 1 < self.vec.len() { + return Err(()); + } else if code_usize - 1 == self.vec.len() { + if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { + return Err(()); + } else { + self.vec.push(abbrev); + return Ok(()); + } + } + } + match self.map.entry(abbrev.code) { + btree_map::Entry::Occupied(_) => Err(()), + btree_map::Entry::Vacant(entry) => { + entry.insert(abbrev); + Ok(()) + } + } + } + + /// Get the abbreviation associated with the given code. + #[inline] + pub fn get(&self, code: u64) -> Option<&Abbreviation> { + if let Ok(code) = usize::try_from(code) { + let index = code.checked_sub(1)?; + if index < self.vec.len() { + return Some(&self.vec[index]); + } + } + + self.map.get(&code) + } + + /// Parse a series of abbreviations, terminated by a null abbreviation. + fn parse(input: &mut R) -> Result { + let mut abbrevs = Abbreviations::empty(); + + while let Some(abbrev) = Abbreviation::parse(input)? { + if abbrevs.insert(abbrev).is_err() { + return Err(Error::DuplicateAbbreviationCode); + } + } + + Ok(abbrevs) + } +} + +/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: +/// its code, tag type, whether it has children, and its set of attributes. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Abbreviation { + code: u64, + tag: constants::DwTag, + has_children: constants::DwChildren, + attributes: Attributes, +} + +impl Abbreviation { + /// Construct a new `Abbreviation`. + /// + /// ### Panics + /// + /// Panics if `code` is `0`. + pub(crate) fn new( + code: u64, + tag: constants::DwTag, + has_children: constants::DwChildren, + attributes: Attributes, + ) -> Abbreviation { + assert_ne!(code, 0); + Abbreviation { + code, + tag, + has_children, + attributes, + } + } + + /// Get this abbreviation's code. + #[inline] + pub fn code(&self) -> u64 { + self.code + } + + /// Get this abbreviation's tag. + #[inline] + pub fn tag(&self) -> constants::DwTag { + self.tag + } + + /// Return true if this abbreviation's type has children, false otherwise. + #[inline] + pub fn has_children(&self) -> bool { + self.has_children == constants::DW_CHILDREN_yes + } + + /// Get this abbreviation's attributes. + #[inline] + pub fn attributes(&self) -> &[AttributeSpecification] { + &self.attributes[..] + } + + /// Parse an abbreviation's tag. + fn parse_tag(input: &mut R) -> Result { + let val = input.read_uleb128_u16()?; + if val == 0 { + Err(Error::AbbreviationTagZero) + } else { + Ok(constants::DwTag(val)) + } + } + + /// Parse an abbreviation's "does the type have children?" byte. + fn parse_has_children(input: &mut R) -> Result { + let val = input.read_u8()?; + let val = constants::DwChildren(val); + if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes { + Ok(val) + } else { + Err(Error::BadHasChildren) + } + } + + /// Parse a series of attribute specifications, terminated by a null attribute + /// specification. + fn parse_attributes(input: &mut R) -> Result { + let mut attrs = Attributes::new(); + + while let Some(attr) = AttributeSpecification::parse(input)? { + attrs.push(attr); + } + + Ok(attrs) + } + + /// Parse an abbreviation. Return `None` for the null abbreviation, `Some` + /// for an actual abbreviation. + fn parse(input: &mut R) -> Result> { + let code = input.read_uleb128()?; + if code == 0 { + return Ok(None); + } + + let tag = Self::parse_tag(input)?; + let has_children = Self::parse_has_children(input)?; + let attributes = Self::parse_attributes(input)?; + let abbrev = Abbreviation::new(code, tag, has_children, attributes); + Ok(Some(abbrev)) + } +} + +/// A list of attributes found in an `Abbreviation` +#[derive(Clone)] +pub(crate) enum Attributes { + Inline { + buf: [AttributeSpecification; MAX_ATTRIBUTES_INLINE], + len: usize, + }, + Heap(Vec), +} + +// Length of 5 based on benchmark results for both x86-64 and i686. +const MAX_ATTRIBUTES_INLINE: usize = 5; + +impl Attributes { + /// Returns a new empty list of attributes + fn new() -> Attributes { + let default = + AttributeSpecification::new(constants::DW_AT_null, constants::DW_FORM_null, None); + Attributes::Inline { + buf: [default; 5], + len: 0, + } + } + + /// Pushes a new value onto this list of attributes. + fn push(&mut self, attr: AttributeSpecification) { + match self { + Attributes::Heap(list) => list.push(attr), + Attributes::Inline { + buf, + len: MAX_ATTRIBUTES_INLINE, + } => { + let mut list = buf.to_vec(); + list.push(attr); + *self = Attributes::Heap(list); + } + Attributes::Inline { buf, len } => { + buf[*len] = attr; + *len += 1; + } + } + } +} + +impl Debug for Attributes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl PartialEq for Attributes { + fn eq(&self, other: &Attributes) -> bool { + **self == **other + } +} + +impl Eq for Attributes {} + +impl Deref for Attributes { + type Target = [AttributeSpecification]; + fn deref(&self) -> &[AttributeSpecification] { + match self { + Attributes::Inline { buf, len } => &buf[..*len], + Attributes::Heap(list) => list, + } + } +} + +impl FromIterator for Attributes { + fn from_iter(iter: I) -> Attributes + where + I: IntoIterator, + { + let mut list = Attributes::new(); + for item in iter { + list.push(item); + } + list + } +} + +impl From> for Attributes { + fn from(list: Vec) -> Attributes { + Attributes::Heap(list) + } +} + +/// The description of an attribute in an abbreviated type. It is a pair of name +/// and form. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AttributeSpecification { + name: constants::DwAt, + form: constants::DwForm, + implicit_const_value: i64, +} + +impl AttributeSpecification { + /// Construct a new `AttributeSpecification` from the given name and form + /// and implicit const value. + #[inline] + pub fn new( + name: constants::DwAt, + form: constants::DwForm, + implicit_const_value: Option, + ) -> AttributeSpecification { + debug_assert!( + (form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) + || (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()) + ); + AttributeSpecification { + name, + form, + implicit_const_value: implicit_const_value.unwrap_or(0), + } + } + + /// Get the attribute's name. + #[inline] + pub fn name(&self) -> constants::DwAt { + self.name + } + + /// Get the attribute's form. + #[inline] + pub fn form(&self) -> constants::DwForm { + self.form + } + + /// Get the attribute's implicit const value. + #[inline] + pub fn implicit_const_value(&self) -> Option { + if self.form == constants::DW_FORM_implicit_const { + Some(self.implicit_const_value) + } else { + None + } + } + + /// Return the size of the attribute, in bytes. + /// + /// Note that because some attributes are variably sized, the size cannot + /// always be known without parsing, in which case we return `None`. + pub fn size(&self, header: &UnitHeader) -> Option { + get_attribute_size(self.form, header.encoding()).map(usize::from) + } + + /// Parse an attribute's form. + fn parse_form(input: &mut R) -> Result { + let val = input.read_uleb128_u16()?; + if val == 0 { + Err(Error::AttributeFormZero) + } else { + Ok(constants::DwForm(val)) + } + } + + /// Parse an attribute specification. Returns `None` for the null attribute + /// specification, `Some` for an actual attribute specification. + fn parse(input: &mut R) -> Result> { + let name = input.read_uleb128_u16()?; + if name == 0 { + // Parse the null attribute specification. + let form = input.read_uleb128_u16()?; + return if form == 0 { + Ok(None) + } else { + Err(Error::ExpectedZero) + }; + } + + let name = constants::DwAt(name); + let form = Self::parse_form(input)?; + let implicit_const_value = if form == constants::DW_FORM_implicit_const { + Some(input.read_sleb128()?) + } else { + None + }; + let spec = AttributeSpecification::new(name, form, implicit_const_value); + Ok(Some(spec)) + } +} + +#[inline] +pub(crate) fn get_attribute_size(form: constants::DwForm, encoding: Encoding) -> Option { + match form { + constants::DW_FORM_addr => Some(encoding.address_size), + + constants::DW_FORM_implicit_const | constants::DW_FORM_flag_present => Some(0), + + constants::DW_FORM_data1 + | constants::DW_FORM_flag + | constants::DW_FORM_strx1 + | constants::DW_FORM_ref1 + | constants::DW_FORM_addrx1 => Some(1), + + constants::DW_FORM_data2 + | constants::DW_FORM_ref2 + | constants::DW_FORM_addrx2 + | constants::DW_FORM_strx2 => Some(2), + + constants::DW_FORM_addrx3 | constants::DW_FORM_strx3 => Some(3), + + constants::DW_FORM_data4 + | constants::DW_FORM_ref_sup4 + | constants::DW_FORM_ref4 + | constants::DW_FORM_strx4 + | constants::DW_FORM_addrx4 => Some(4), + + constants::DW_FORM_data8 + | constants::DW_FORM_ref8 + | constants::DW_FORM_ref_sig8 + | constants::DW_FORM_ref_sup8 => Some(8), + + constants::DW_FORM_data16 => Some(16), + + constants::DW_FORM_sec_offset + | constants::DW_FORM_GNU_ref_alt + | constants::DW_FORM_strp + | constants::DW_FORM_strp_sup + | constants::DW_FORM_GNU_strp_alt + | constants::DW_FORM_line_strp => Some(encoding.format.word_size()), + + constants::DW_FORM_ref_addr => { + // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr + // has the same size as an address on the target system. This was changed + // in DWARF version 3. + Some(if encoding.version == 2 { + encoding.address_size + } else { + encoding.format.word_size() + }) + } + + // Variably sized forms. + constants::DW_FORM_block + | constants::DW_FORM_block1 + | constants::DW_FORM_block2 + | constants::DW_FORM_block4 + | constants::DW_FORM_exprloc + | constants::DW_FORM_ref_udata + | constants::DW_FORM_string + | constants::DW_FORM_sdata + | constants::DW_FORM_udata + | constants::DW_FORM_indirect => None, + + // We don't know the size of unknown forms. + _ => None, + } +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + use crate::constants; + use crate::endianity::LittleEndian; + use crate::read::{EndianSlice, Error}; + use crate::test_util::GimliSectionMethods; + #[cfg(target_pointer_width = "32")] + use core::u32; + use test_assembler::Section; + + pub trait AbbrevSectionMethods { + fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self; + fn abbrev_null(self) -> Self; + fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self; + fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self; + fn abbrev_attr_null(self) -> Self; + } + + impl AbbrevSectionMethods for Section { + fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self { + self.uleb(code).uleb(tag.0.into()).D8(children.0) + } + + fn abbrev_null(self) -> Self { + self.D8(0) + } + + fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self { + self.uleb(name.0.into()).uleb(form.0.into()) + } + + fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self { + self.uleb(name.0.into()) + .uleb(constants::DW_FORM_implicit_const.0.into()) + .sleb(value) + } + + fn abbrev_attr_null(self) -> Self { + self.D8(0).D8(0) + } + } + + #[test] + fn test_debug_abbrev_ok() { + let extra_start = [1, 2, 3, 4]; + let expected_rest = [5, 6, 7, 8]; + #[rustfmt::skip] + let buf = Section::new() + .append_bytes(&extra_start) + .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) + .abbrev_attr_null() + .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) + .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) + .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) + .abbrev_attr_null() + .abbrev_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + + let abbrev1 = Abbreviation::new( + 1, + constants::DW_TAG_compile_unit, + constants::DW_CHILDREN_yes, + vec![ + AttributeSpecification::new( + constants::DW_AT_producer, + constants::DW_FORM_strp, + None, + ), + AttributeSpecification::new( + constants::DW_AT_language, + constants::DW_FORM_data2, + None, + ), + ] + .into(), + ); + + let abbrev2 = Abbreviation::new( + 2, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_no, + vec![AttributeSpecification::new( + constants::DW_AT_name, + constants::DW_FORM_string, + None, + )] + .into(), + ); + + let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian); + let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len()); + let abbrevs = debug_abbrev + .abbreviations(debug_abbrev_offset) + .expect("Should parse abbreviations"); + assert_eq!(abbrevs.get(1), Some(&abbrev1)); + assert_eq!(abbrevs.get(2), Some(&abbrev2)); + } + + #[test] + fn test_abbreviations_insert() { + fn abbrev(code: u16) -> Abbreviation { + Abbreviation::new( + code.into(), + constants::DwTag(code), + constants::DW_CHILDREN_no, + vec![].into(), + ) + } + + fn assert_abbrev(abbrevs: &Abbreviations, code: u16) { + let abbrev = abbrevs.get(code.into()).unwrap(); + assert_eq!(abbrev.tag(), constants::DwTag(code)); + } + + // Sequential insert. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(1)).unwrap(); + abbrevs.insert(abbrev(2)).unwrap(); + assert_eq!(abbrevs.vec.len(), 2); + assert!(abbrevs.map.is_empty()); + assert_abbrev(&abbrevs, 1); + assert_abbrev(&abbrevs, 2); + + // Out of order insert. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(2)).unwrap(); + abbrevs.insert(abbrev(3)).unwrap(); + assert!(abbrevs.vec.is_empty()); + assert_abbrev(&abbrevs, 2); + assert_abbrev(&abbrevs, 3); + + // Mixed order insert. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(1)).unwrap(); + abbrevs.insert(abbrev(3)).unwrap(); + abbrevs.insert(abbrev(2)).unwrap(); + assert_eq!(abbrevs.vec.len(), 2); + assert_abbrev(&abbrevs, 1); + assert_abbrev(&abbrevs, 2); + assert_abbrev(&abbrevs, 3); + + // Duplicate code in vec. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(1)).unwrap(); + abbrevs.insert(abbrev(2)).unwrap(); + assert_eq!(abbrevs.insert(abbrev(1)), Err(())); + assert_eq!(abbrevs.insert(abbrev(2)), Err(())); + + // Duplicate code in map when adding to map. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(2)).unwrap(); + assert_eq!(abbrevs.insert(abbrev(2)), Err(())); + + // Duplicate code in map when adding to vec. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(2)).unwrap(); + abbrevs.insert(abbrev(1)).unwrap(); + assert_eq!(abbrevs.insert(abbrev(2)), Err(())); + + // 32-bit usize conversions. + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(2)).unwrap(); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn test_abbreviations_insert_32() { + fn abbrev(code: u64) -> Abbreviation { + Abbreviation::new( + code, + constants::DwTag(code as u16), + constants::DW_CHILDREN_no, + vec![].into(), + ) + } + + fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { + let abbrev = abbrevs.get(code).unwrap(); + assert_eq!(abbrev.tag(), constants::DwTag(code as u16)); + } + + let mut abbrevs = Abbreviations::empty(); + abbrevs.insert(abbrev(1)).unwrap(); + + let wrap_code = (u32::MAX as u64 + 1) + 1; + // `get` should not treat the wrapped code as `1`. + assert_eq!(abbrevs.get(wrap_code), None); + // `insert` should not treat the wrapped code as `1`. + abbrevs.insert(abbrev(wrap_code)).unwrap(); + assert_abbrev(&abbrevs, 1); + assert_abbrev(&abbrevs, wrap_code); + } + + #[test] + fn test_parse_abbreviations_ok() { + let expected_rest = [1, 2, 3, 4]; + #[rustfmt::skip] + let buf = Section::new() + .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) + .abbrev_attr_null() + .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) + .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) + .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) + .abbrev_attr_null() + .abbrev_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let abbrev1 = Abbreviation::new( + 1, + constants::DW_TAG_compile_unit, + constants::DW_CHILDREN_yes, + vec![ + AttributeSpecification::new( + constants::DW_AT_producer, + constants::DW_FORM_strp, + None, + ), + AttributeSpecification::new( + constants::DW_AT_language, + constants::DW_FORM_data2, + None, + ), + ] + .into(), + ); + + let abbrev2 = Abbreviation::new( + 2, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_no, + vec![AttributeSpecification::new( + constants::DW_AT_name, + constants::DW_FORM_string, + None, + )] + .into(), + ); + + let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations"); + assert_eq!(abbrevs.get(1), Some(&abbrev1)); + assert_eq!(abbrevs.get(2), Some(&abbrev2)); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_abbreviations_duplicate() { + let expected_rest = [1, 2, 3, 4]; + #[rustfmt::skip] + let buf = Section::new() + .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) + .abbrev_attr_null() + .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) + .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) + .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) + .abbrev_attr_null() + .abbrev_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match Abbreviations::parse(buf) { + Err(Error::DuplicateAbbreviationCode) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_abbreviation_tag_ok() { + let buf = [0x01, 0x02]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let tag = Abbreviation::parse_tag(rest).expect("Should parse tag"); + assert_eq!(tag, constants::DW_TAG_array_type); + assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); + } + + #[test] + fn test_parse_abbreviation_tag_zero() { + let buf = [0x00]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + match Abbreviation::parse_tag(buf) { + Err(Error::AbbreviationTagZero) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_abbreviation_has_children() { + let buf = [0x00, 0x01, 0x02]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); + assert_eq!(val, constants::DW_CHILDREN_no); + let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); + assert_eq!(val, constants::DW_CHILDREN_yes); + match Abbreviation::parse_has_children(rest) { + Err(Error::BadHasChildren) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_abbreviation_ok() { + let expected_rest = [0x01, 0x02, 0x03, 0x04]; + let buf = Section::new() + .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) + .abbrev_attr_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let expect = Some(Abbreviation::new( + 1, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_no, + vec![AttributeSpecification::new( + constants::DW_AT_name, + constants::DW_FORM_string, + None, + )] + .into(), + )); + + let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); + assert_eq!(abbrev, expect); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_abbreviation_implicit_const_ok() { + let expected_rest = [0x01, 0x02, 0x03, 0x04]; + let buf = Section::new() + .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr_implicit_const(constants::DW_AT_name, -42) + .abbrev_attr_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let expect = Some(Abbreviation::new( + 1, + constants::DW_TAG_subprogram, + constants::DW_CHILDREN_no, + vec![AttributeSpecification::new( + constants::DW_AT_name, + constants::DW_FORM_implicit_const, + Some(-42), + )] + .into(), + )); + + let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); + assert_eq!(abbrev, expect); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_abbreviation_implicit_const_no_const() { + let buf = Section::new() + .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) + .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const) + .get_contents() + .unwrap(); + let buf = &mut EndianSlice::new(&buf, LittleEndian); + + match Abbreviation::parse(buf) { + Err(Error::UnexpectedEof(_)) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } + + #[test] + fn test_parse_null_abbreviation_ok() { + let expected_rest = [0x01, 0x02, 0x03, 0x04]; + let buf = Section::new() + .abbrev_null() + .append_bytes(&expected_rest) + .get_contents() + .unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation"); + assert!(abbrev.is_none()); + assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_attribute_form_ok() { + let buf = [0x01, 0x02]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let tag = AttributeSpecification::parse_form(rest).expect("Should parse form"); + assert_eq!(tag, constants::DW_FORM_addr); + assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); + } + + #[test] + fn test_parse_attribute_form_zero() { + let buf = [0x00]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + match AttributeSpecification::parse_form(buf) { + Err(Error::AttributeFormZero) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_null_attribute_specification_ok() { + let buf = [0x00, 0x00, 0x01]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let attr = + AttributeSpecification::parse(rest).expect("Should parse null attribute specification"); + assert!(attr.is_none()); + assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian)); + } + + #[test] + fn test_parse_attribute_specifications_name_zero() { + let buf = [0x00, 0x01, 0x00, 0x00]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + match AttributeSpecification::parse(buf) { + Err(Error::ExpectedZero) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_attribute_specifications_form_zero() { + let buf = [0x01, 0x00, 0x00, 0x00]; + let buf = &mut EndianSlice::new(&buf, LittleEndian); + match AttributeSpecification::parse(buf) { + Err(Error::AttributeFormZero) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_get_abbrev_zero() { + let mut abbrevs = Abbreviations::empty(); + abbrevs + .insert(Abbreviation::new( + 1, + constants::DwTag(1), + constants::DW_CHILDREN_no, + vec![].into(), + )) + .unwrap(); + assert!(abbrevs.get(0).is_none()); + } +} diff --git a/deps/crates/vendor/gimli/src/read/addr.rs b/deps/crates/vendor/gimli/src/read/addr.rs new file mode 100644 index 00000000000000..fc2fbabd126a87 --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/addr.rs @@ -0,0 +1,118 @@ +use crate::common::{DebugAddrBase, DebugAddrIndex, SectionId}; +use crate::read::{Reader, ReaderOffset, Result, Section}; + +/// The raw contents of the `.debug_addr` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugAddr { + section: R, +} + +impl DebugAddr { + // TODO: add an iterator over the sets of addresses in the section. + // This is not needed for common usage of the section though. + + /// Returns the address at the given `base` and `index`. + /// + /// A set of addresses in the `.debug_addr` section consists of a header + /// followed by a series of addresses. + /// + /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE. + /// This is an offset that points to the first address following the header. + /// + /// The `index` is the value of a `DW_FORM_addrx` attribute. + /// + /// The `address_size` must be the size of the address for the compilation unit. + /// This value must also match the header. However, note that we do not parse the + /// header to validate this, since locating the header is unreliable, and the GNU + /// extensions do not emit it. + pub fn get_address( + &self, + address_size: u8, + base: DebugAddrBase, + index: DebugAddrIndex, + ) -> Result { + let input = &mut self.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(address_size), + )?)?; + input.read_address(address_size) + } +} + +impl DebugAddr { + /// Create a `DebugAddr` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugAddr { + fn id() -> SectionId { + SectionId::DebugAddr + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugAddr { + fn from(section: R) -> Self { + DebugAddr { section } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::read::EndianSlice; + use crate::test_util::GimliSectionMethods; + use crate::{Format, LittleEndian}; + use test_assembler::{Endian, Label, LabelMaker, Section}; + + #[test] + fn test_get_address() { + for format in [Format::Dwarf32, Format::Dwarf64] { + for address_size in [4, 8] { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D8(address_size) + .D8(0) + .mark(&first); + for i in 0..20 { + section = section.word(address_size, 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + + let section = section.get_contents().unwrap(); + let debug_addr = DebugAddr::from(EndianSlice::new(§ion, LittleEndian)); + let base = DebugAddrBase((&first - &zero) as usize); + + assert_eq!( + debug_addr.get_address(address_size, base, DebugAddrIndex(0)), + Ok(1000) + ); + assert_eq!( + debug_addr.get_address(address_size, base, DebugAddrIndex(19)), + Ok(1019) + ); + } + } + } +} diff --git a/deps/crates/vendor/gimli/src/read/aranges.rs b/deps/crates/vendor/gimli/src/read/aranges.rs new file mode 100644 index 00000000000000..2829f261afa8ce --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/aranges.rs @@ -0,0 +1,810 @@ +use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId}; +use crate::endianity::Endianity; +use crate::read::{ + EndianSlice, Error, Range, Reader, ReaderAddress, ReaderOffset, Result, Section, +}; + +/// The `DebugAranges` struct represents the DWARF address range information +/// found in the `.debug_aranges` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugAranges { + section: R, +} + +impl<'input, Endian> DebugAranges> +where + Endian: Endianity, +{ + /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_aranges` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugAranges, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_aranges_section = || &buf; + /// let debug_aranges = + /// DebugAranges::new(read_debug_aranges_section(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + DebugAranges { + section: EndianSlice::new(section, endian), + } + } +} + +impl DebugAranges { + /// Iterate the sets of entries in the `.debug_aranges` section. + /// + /// Each set of entries belongs to a single unit. + pub fn headers(&self) -> ArangeHeaderIter { + ArangeHeaderIter { + input: self.section.clone(), + offset: DebugArangesOffset(R::Offset::from_u8(0)), + } + } + + /// Get the header at the given offset. + pub fn header(&self, offset: DebugArangesOffset) -> Result> { + let mut input = self.section.clone(); + input.skip(offset.0)?; + ArangeHeader::parse(&mut input, offset) + } +} + +impl DebugAranges { + /// Create a `DebugAranges` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// Used by `DwarfSections::borrow`. + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAranges + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() + } +} + +impl Section for DebugAranges { + fn id() -> SectionId { + SectionId::DebugAranges + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugAranges { + fn from(section: R) -> Self { + DebugAranges { section } + } +} + +/// An iterator over the headers of a `.debug_aranges` section. +#[derive(Clone, Debug)] +pub struct ArangeHeaderIter { + input: R, + offset: DebugArangesOffset, +} + +impl ArangeHeaderIter { + /// Advance the iterator to the next header. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + let len = self.input.len(); + match ArangeHeader::parse(&mut self.input, self.offset) { + Ok(header) => { + self.offset.0 += len - self.input.len(); + Ok(Some(header)) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for ArangeHeaderIter { + type Item = ArangeHeader; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + ArangeHeaderIter::next(self) + } +} + +/// A header for a set of entries in the `.debug_arange` section. +/// +/// These entries all belong to a single unit. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ArangeHeader::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + offset: DebugArangesOffset, + encoding: Encoding, + length: Offset, + debug_info_offset: DebugInfoOffset, + entries: R, +} + +impl ArangeHeader +where + R: Reader, + Offset: ReaderOffset, +{ + fn parse(input: &mut R, offset: DebugArangesOffset) -> Result { + let (length, format) = input.read_initial_length()?; + let mut rest = input.split(length)?; + + // Check the version. The DWARF 5 spec says that this is always 2, but version 3 + // has been observed in the wild, potentially due to a bug; see + // https://github.com/gimli-rs/gimli/issues/559 for more information. + // lldb allows versions 2 through 5, possibly by mistake. + let version = rest.read_u16()?; + if version != 2 && version != 3 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?; + let address_size = rest.read_address_size()?; + let segment_size = rest.read_u8()?; + if segment_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + + // unit_length + version + offset + address_size + segment_size + let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1; + + // The first tuple following the header in each set begins at an offset that is + // a multiple of the size of a single tuple (that is, twice the size of an address). + let tuple_length = address_size + .checked_mul(2) + .ok_or(Error::UnsupportedAddressSize(address_size))?; + if tuple_length == 0 { + return Err(Error::UnsupportedAddressSize(address_size)); + } + let padding = if header_length % tuple_length == 0 { + 0 + } else { + tuple_length - header_length % tuple_length + }; + rest.skip(R::Offset::from_u8(padding))?; + + let encoding = Encoding { + format, + version, + address_size, + }; + Ok(ArangeHeader { + offset, + encoding, + length, + debug_info_offset, + entries: rest, + }) + } + + /// Return the offset of this header within the `.debug_aranges` section. + #[inline] + pub fn offset(&self) -> DebugArangesOffset { + self.offset + } + + /// Return the length of this set of entries, including the header. + #[inline] + pub fn length(&self) -> Offset { + self.length + } + + /// Return the encoding parameters for this set of entries. + #[inline] + pub fn encoding(&self) -> Encoding { + self.encoding + } + + /// Return the offset into the .debug_info section for this set of arange entries. + #[inline] + pub fn debug_info_offset(&self) -> DebugInfoOffset { + self.debug_info_offset + } + + /// Return the arange entries in this set. + #[inline] + pub fn entries(&self) -> ArangeEntryIter { + ArangeEntryIter { + input: self.entries.clone(), + encoding: self.encoding, + } + } +} + +/// An iterator over the aranges from a `.debug_aranges` section. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Debug, Clone)] +pub struct ArangeEntryIter { + input: R, + encoding: Encoding, +} + +impl ArangeEntryIter { + /// Advance the iterator and return the next arange. + /// + /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)` + /// when iteration is complete and all aranges have already been parsed and + /// yielded. If an error occurs while parsing the next arange, then this error + /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. + pub fn next(&mut self) -> Result> { + loop { + let raw_entry = match self.next_raw()? { + Some(entry) => entry, + None => return Ok(None), + }; + + let entry = self.convert_raw(raw_entry)?; + if entry.is_some() { + return Ok(entry); + } + } + } + + /// Advance the iterator and return the next arange without validating it. + /// + /// The returned entry will have `range.end` set to 0. + /// This will return tombstone entries as well. + pub fn next_raw(&mut self) -> Result> { + if self.input.is_empty() { + return Ok(None); + } + + match ArangeEntry::parse(&mut self.input, self.encoding) { + Ok(Some(entry)) => Ok(Some(entry)), + Ok(None) => { + self.input.empty(); + Ok(None) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } + + /// Convert a raw range into a range. + /// + /// The raw range should have been obtained from `next_raw`. + #[doc(hidden)] + pub fn convert_raw(&self, mut entry: ArangeEntry) -> Result> { + // Skip tombstone entries. + // DWARF specifies a tombstone value of -1, but many linkers use 0. + // However, 0 may be a valid address, so the caller must handle that case. + let address_size = self.encoding.address_size; + let tombstone_address = !0 >> (64 - self.encoding.address_size * 8); + if entry.range.begin == tombstone_address { + return Ok(None); + } + + // Calculate end now so that we can handle overflow. + entry.range.end = entry.range.begin.add_sized(entry.length, address_size)?; + Ok(Some(entry)) + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for ArangeEntryIter { + type Item = ArangeEntry; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + ArangeEntryIter::next(self) + } +} + +/// A single parsed arange. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct ArangeEntry { + range: Range, + length: u64, +} + +impl ArangeEntry { + /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. + fn parse(input: &mut R, encoding: Encoding) -> Result> { + let address_size = encoding.address_size; + + let tuple_length = R::Offset::from_u8(2 * address_size); + if tuple_length > input.len() { + input.empty(); + return Ok(None); + } + + let begin = input.read_address(address_size)?; + let length = input.read_address(address_size)?; + let range = Range { begin, end: 0 }; + + match (begin, length) { + // This is meant to be a null terminator, but in practice it can occur + // before the end, possibly due to a linker omitting a function and + // leaving an unrelocated entry. + (0, 0) => Self::parse(input, encoding), + _ => Ok(Some(ArangeEntry { range, length })), + } + } + + /// Return the beginning address of this arange. + #[inline] + pub fn address(&self) -> u64 { + self.range.begin + } + + /// Return the length of this arange. + #[inline] + pub fn length(&self) -> u64 { + self.length + } + + /// Return the range. + #[inline] + pub fn range(&self) -> Range { + self.range + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::{DebugInfoOffset, Format}; + use crate::endianity::LittleEndian; + use crate::read::EndianSlice; + + #[test] + fn test_iterate_headers() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 28. + 0x1c, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x01, 0x02, 0x03, 0x04, + // Address size. + 0x04, + // Segment size. + 0x00, + // Dummy padding and arange tuples. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // 32-bit length = 36. + 0x24, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x11, 0x12, 0x13, 0x14, + // Address size. + 0x04, + // Segment size. + 0x00, + // Dummy padding and arange tuples. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let debug_aranges = DebugAranges::new(&buf, LittleEndian); + let mut headers = debug_aranges.headers(); + + let header = headers + .next() + .expect("should parse header ok") + .expect("should have a header"); + assert_eq!(header.offset(), DebugArangesOffset(0)); + assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x0403_0201)); + + let header = headers + .next() + .expect("should parse header ok") + .expect("should have a header"); + assert_eq!(header.offset(), DebugArangesOffset(0x20)); + assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x1413_1211)); + } + + #[test] + fn test_parse_header_ok() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 28 (8 bytes header, 4 bytes padding, 16 bytes tuple data). + 0x1c, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x01, 0x02, 0x03, 0x04, + // Address size. + 0x08, + // Segment size. + 0x00, + // Length to here = 12, tuple length = 16. + // Padding to tuple length multiple = 4. + 0x10, 0x00, 0x00, 0x00, + + // Dummy arange tuple data. + 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next arange. + 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let header = + ArangeHeader::parse(rest, DebugArangesOffset(0x10)).expect("should parse header ok"); + + assert_eq!( + *rest, + EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) + ); + assert_eq!( + header, + ArangeHeader { + offset: DebugArangesOffset(0x10), + encoding: Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }, + length: 0x1c, + debug_info_offset: DebugInfoOffset(0x0403_0201), + entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian), + } + ); + } + + #[test] + fn test_parse_header_overflow_error() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 32. + 0x20, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x01, 0x02, 0x03, 0x04, + // Address size. + 0xff, + // Segment size. + 0x00, + // Length to here = 12, tuple length = 20. + // Padding to tuple length multiple = 4. + 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy arange tuple data. + 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next arange. + 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) + .expect_err("should fail to parse header"); + assert_eq!(error, Error::UnsupportedAddressSize(0xff)); + } + + #[test] + fn test_parse_header_div_by_zero_error() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 32. + 0x20, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x01, 0x02, 0x03, 0x04, + // Address size = 0. Could cause a division by zero if we aren't + // careful. + 0x00, + // Segment size. + 0x00, + // Length to here = 12, tuple length = 20. + // Padding to tuple length multiple = 4. + 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy arange tuple data. + 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // Dummy next arange. + 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) + .expect_err("should fail to parse header"); + assert_eq!(error, Error::UnsupportedAddressSize(0)); + } + + #[test] + fn test_parse_entry_ok() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, + }; + let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next().expect("should parse entry ok"); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, + length: 0x0807_0605, + }) + ); + } + + #[test] + fn test_parse_entry_zero() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, + }; + #[rustfmt::skip] + let buf = [ + // Zero tuple. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Address. + 0x01, 0x02, 0x03, 0x04, + // Length. + 0x05, 0x06, 0x07, 0x08, + // Next tuple. + 0x09 + ]; + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next().expect("should parse entry ok"); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, + length: 0x0807_0605, + }) + ); + } + + #[test] + fn test_parse_entry_overflow_32() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0x01, 0x02, 0x03, 0x84, + // Length. + 0x05, 0x06, 0x07, 0x88, + // Next tuple. + 0x09 + ]; + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!(entry, Err(Error::AddressOverflow)); + } + + #[test] + fn test_parse_entry_overflow_64() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x80, + // Length. + 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x80, + // Next tuple. + 0x09 + ]; + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!(entry, Err(Error::AddressOverflow)); + } + + #[test] + fn test_parse_entry_tombstone_32() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0xff, 0xff, 0xff, 0xff, + // Length. + 0x05, 0x06, 0x07, 0x08, + // Address. + 0x01, 0x02, 0x03, 0x04, + // Length. + 0x05, 0x06, 0x07, 0x08, + // Next tuple. + 0x09 + ]; + + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next_raw().unwrap(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 9..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0xffff_ffff, + end: 0, + }, + length: 0x0807_0605, + }) + ); + + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next().unwrap(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, + length: 0x0807_0605, + }) + ); + } + + #[test] + fn test_parse_entry_tombstone_64() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // Length. + 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, + // Address. + 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, + // Length. + 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, + // Next tuple. + 0x09 + ]; + + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next_raw().unwrap(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 17..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0xffff_ffff_ffff_ffff, + end: 0, + }, + length: 0x0807_0605, + }) + ); + + let mut iter = ArangeEntryIter { + input: EndianSlice::new(&buf, LittleEndian), + encoding, + }; + let entry = iter.next().unwrap(); + assert_eq!( + iter.input, + EndianSlice::new(&buf[buf.len() - 1..], LittleEndian) + ); + assert_eq!( + entry, + Some(ArangeEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, + length: 0x0807_0605, + }) + ); + } +} diff --git a/deps/crates/vendor/gimli/src/read/cfi.rs b/deps/crates/vendor/gimli/src/read/cfi.rs new file mode 100644 index 00000000000000..f14f644795067e --- /dev/null +++ b/deps/crates/vendor/gimli/src/read/cfi.rs @@ -0,0 +1,7952 @@ +#[cfg(feature = "read")] +use alloc::boxed::Box; + +use core::cmp::Ordering; +use core::fmt::{self, Debug}; +use core::iter::FromIterator; +use core::mem; +use core::num::Wrapping; + +use super::util::{ArrayLike, ArrayVec}; +use crate::common::{ + DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor, +}; +use crate::constants::{self, DwEhPe}; +use crate::endianity::Endianity; +use crate::read::{ + EndianSlice, Error, Expression, Reader, ReaderAddress, ReaderOffset, Result, Section, + StoreOnHeap, +}; + +/// `DebugFrame` contains the `.debug_frame` section's frame unwinding +/// information required to unwind to and recover registers from older frames on +/// the stack. For example, this is useful for a debugger that wants to print +/// locals in a backtrace. +/// +/// Most interesting methods are defined in the +/// [`UnwindSection`](trait.UnwindSection.html) trait. +/// +/// ### Differences between `.debug_frame` and `.eh_frame` +/// +/// While the `.debug_frame` section's information has a lot of overlap with the +/// `.eh_frame` section's information, the `.eh_frame` information tends to only +/// encode the subset of information needed for exception handling. Often, only +/// one of `.eh_frame` or `.debug_frame` will be present in an object file. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DebugFrame { + section: R, + address_size: u8, + vendor: Vendor, +} + +impl DebugFrame { + /// Set the size of a target address in bytes. + /// + /// This defaults to the native word size. + /// This is only used if the CIE version is less than 4. + pub fn set_address_size(&mut self, address_size: u8) { + self.address_size = address_size + } + + /// Set the vendor extensions to use. + /// + /// This defaults to `Vendor::Default`. + pub fn set_vendor(&mut self, vendor: Vendor) { + self.vendor = vendor; + } +} + +impl<'input, Endian> DebugFrame> +where + Endian: Endianity, +{ + /// Construct a new `DebugFrame` instance from the data in the + /// `.debug_frame` section. + /// + /// It is the caller's responsibility to read the section and present it as + /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O + /// loader on macOS, etc. + /// + /// ``` + /// use gimli::{DebugFrame, NativeEndian}; + /// + /// // Use with `.debug_frame` + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_debug_frame_section_somehow = || &buf; + /// let debug_frame = DebugFrame::new(read_debug_frame_section_somehow(), NativeEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl Section for DebugFrame { + fn id() -> SectionId { + SectionId::DebugFrame + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for DebugFrame { + fn from(section: R) -> Self { + // Default to native word size. + DebugFrame { + section, + address_size: mem::size_of::() as u8, + vendor: Vendor::Default, + } + } +} + +/// `EhFrameHdr` contains the information about the `.eh_frame_hdr` section. +/// +/// A pointer to the start of the `.eh_frame` data, and optionally, a binary +/// search table of pointers to the `.eh_frame` records that are found in this section. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct EhFrameHdr(R); + +/// `ParsedEhFrameHdr` contains the parsed information from the `.eh_frame_hdr` section. +#[derive(Clone, Debug)] +pub struct ParsedEhFrameHdr { + address_size: u8, + section: R, + + eh_frame_ptr: Pointer, + fde_count: u64, + table_enc: DwEhPe, + table: R, +} + +impl<'input, Endian> EhFrameHdr> +where + Endian: Endianity, +{ + /// Constructs a new `EhFrameHdr` instance from the data in the `.eh_frame_hdr` section. + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl EhFrameHdr { + /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`. + pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result> { + let mut reader = self.0.clone(); + let version = reader.read_u8()?; + if version != 1 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + let eh_frame_ptr_enc = parse_pointer_encoding(&mut reader)?; + let fde_count_enc = parse_pointer_encoding(&mut reader)?; + let table_enc = parse_pointer_encoding(&mut reader)?; + + let parameters = PointerEncodingParameters { + bases: &bases.eh_frame_hdr, + func_base: None, + address_size, + section: &self.0, + }; + + // Omitting this pointer is not valid (defeats the purpose of .eh_frame_hdr entirely) + if eh_frame_ptr_enc == constants::DW_EH_PE_omit { + return Err(Error::CannotParseOmitPointerEncoding); + } + let eh_frame_ptr = parse_encoded_pointer(eh_frame_ptr_enc, ¶meters, &mut reader)?; + + let fde_count; + if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit { + fde_count = 0 + } else { + if fde_count_enc != fde_count_enc.format() { + return Err(Error::UnsupportedPointerEncoding); + } + fde_count = parse_encoded_value(fde_count_enc, ¶meters, &mut reader)?; + } + + Ok(ParsedEhFrameHdr { + address_size, + section: self.0.clone(), + + eh_frame_ptr, + fde_count, + table_enc, + table: reader, + }) + } +} + +impl Section for EhFrameHdr { + fn id() -> SectionId { + SectionId::EhFrameHdr + } + + fn reader(&self) -> &R { + &self.0 + } +} + +impl From for EhFrameHdr { + fn from(section: R) -> Self { + EhFrameHdr(section) + } +} + +impl ParsedEhFrameHdr { + /// Returns the address of the binary's `.eh_frame` section. + pub fn eh_frame_ptr(&self) -> Pointer { + self.eh_frame_ptr + } + + /// Retrieves the CFI binary search table, if there is one. + pub fn table(&self) -> Option> { + // There are two big edge cases here: + // * You search the table for an invalid address. As this is just a binary + // search table, we always have to return a valid result for that (unless + // you specify an address that is lower than the first address in the + // table). Since this means that you have to recheck that the FDE contains + // your address anyways, we just return the first FDE even when the address + // is too low. After all, we're just doing a normal binary search. + // * This falls apart when the table is empty - there is no entry we could + // return. We conclude that an empty table is not really a table at all. + if self.fde_count == 0 { + None + } else { + Some(EhHdrTable { hdr: self }) + } + } +} + +/// An iterator for `.eh_frame_hdr` section's binary search table. +/// +/// Each table entry consists of a tuple containing an `initial_location` and `address`. +/// The `initial location` represents the first address that the targeted FDE +/// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. +/// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. +#[derive(Debug)] +pub struct EhHdrTableIter<'a, 'bases, R: Reader> { + hdr: &'a ParsedEhFrameHdr, + table: R, + bases: &'bases BaseAddresses, + remain: u64, +} + +impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { + /// Yield the next entry in the `EhHdrTableIter`. + pub fn next(&mut self) -> Result> { + if self.remain == 0 { + return Ok(None); + } + + let parameters = PointerEncodingParameters { + bases: &self.bases.eh_frame_hdr, + func_base: None, + address_size: self.hdr.address_size, + section: &self.hdr.section, + }; + + self.remain -= 1; + let from = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; + let to = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; + Ok(Some((from, to))) + } + /// Yield the nth entry in the `EhHdrTableIter` + pub fn nth(&mut self, n: usize) -> Result> { + use core::convert::TryFrom; + let size = match self.hdr.table_enc.format() { + constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { + return Err(Error::VariableLengthSearchTable); + } + constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, + constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, + constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, + _ => return Err(Error::UnknownPointerEncoding(self.hdr.table_enc)), + }; + + let row_size = size * 2; + let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?; + self.remain = self.remain.saturating_sub(n); + self.table.skip(R::Offset::from_u64(n * row_size)?)?; + self.next() + } +} + +#[cfg(feature = "fallible-iterator")] +impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> { + type Item = (Pointer, Pointer); + type Error = Error; + fn next(&mut self) -> Result> { + EhHdrTableIter::next(self) + } + + fn size_hint(&self) -> (usize, Option) { + use core::convert::TryInto; + ( + self.remain.try_into().unwrap_or(0), + self.remain.try_into().ok(), + ) + } + + fn nth(&mut self, n: usize) -> Result> { + EhHdrTableIter::nth(self, n) + } +} + +/// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section. +#[derive(Debug, Clone)] +pub struct EhHdrTable<'a, R: Reader> { + hdr: &'a ParsedEhFrameHdr, +} + +impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { + /// Return an iterator that can walk the `.eh_frame_hdr` table. + /// + /// Each table entry consists of a tuple containing an `initial_location` and `address`. + /// The `initial location` represents the first address that the targeted FDE + /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. + /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. + pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> { + EhHdrTableIter { + hdr: self.hdr, + bases, + remain: self.hdr.fde_count, + table: self.hdr.table.clone(), + } + } + /// *Probably* returns a pointer to the FDE for the given address. + /// + /// This performs a binary search, so if there is no FDE for the given address, + /// this function **will** return a pointer to any other FDE that's close by. + /// + /// To be sure, you **must** call `contains` on the FDE. + pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result { + let size = match self.hdr.table_enc.format() { + constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { + return Err(Error::VariableLengthSearchTable); + } + constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, + constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, + constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, + _ => return Err(Error::UnknownPointerEncoding(self.hdr.table_enc)), + }; + + let row_size = size * 2; + + let mut len = self.hdr.fde_count; + + let mut reader = self.hdr.table.clone(); + + let parameters = PointerEncodingParameters { + bases: &bases.eh_frame_hdr, + func_base: None, + address_size: self.hdr.address_size, + section: &self.hdr.section, + }; + + while len > 1 { + let head = reader.split(R::Offset::from_u64((len / 2) * row_size)?)?; + let tail = reader.clone(); + + let pivot = + parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader)?.direct()?; + + match pivot.cmp(&address) { + Ordering::Equal => { + reader = tail; + break; + } + Ordering::Less => { + reader = tail; + len = len - (len / 2); + } + Ordering::Greater => { + reader = head; + len /= 2; + } + } + } + + reader.skip(R::Offset::from_u64(size)?)?; + + parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader) + } + + /// Convert a `Pointer` to a section offset. + /// + /// This does not support indirect pointers. + pub fn pointer_to_offset(&self, ptr: Pointer) -> Result> { + let ptr = ptr.direct()?; + let eh_frame_ptr = self.hdr.eh_frame_ptr().direct()?; + + // Calculate the offset in the EhFrame section + R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset) + } + + /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress` + /// if there are none. + /// + /// You must provide a function to get its associated CIE. See + /// `PartialFrameDescriptionEntry::parse` for more information. + /// + /// # Example + /// + /// ``` + /// # use gimli::{BaseAddresses, EhFrame, ParsedEhFrameHdr, EndianSlice, NativeEndian, Error, UnwindSection}; + /// # fn foo() -> Result<(), Error> { + /// # let eh_frame: EhFrame> = unreachable!(); + /// # let eh_frame_hdr: ParsedEhFrameHdr> = unimplemented!(); + /// # let addr = 0; + /// # let bases = unimplemented!(); + /// let table = eh_frame_hdr.table().unwrap(); + /// let fde = table.fde_for_address(&eh_frame, &bases, addr, EhFrame::cie_from_offset)?; + /// # Ok(()) + /// # } + /// ``` + pub fn fde_for_address( + &self, + frame: &EhFrame, + bases: &BaseAddresses, + address: u64, + get_cie: F, + ) -> Result> + where + F: FnMut( + &EhFrame, + &BaseAddresses, + EhFrameOffset, + ) -> Result>, + { + let fdeptr = self.lookup(address, bases)?; + let offset = self.pointer_to_offset(fdeptr)?; + let entry = frame.fde_from_offset(bases, offset, get_cie)?; + if entry.contains(address) { + Ok(entry) + } else { + Err(Error::NoUnwindInfoForAddress) + } + } + + #[inline] + #[doc(hidden)] + #[deprecated(note = "Method renamed to fde_for_address; use that instead.")] + pub fn lookup_and_parse( + &self, + address: u64, + bases: &BaseAddresses, + frame: EhFrame, + get_cie: F, + ) -> Result> + where + F: FnMut( + &EhFrame, + &BaseAddresses, + EhFrameOffset, + ) -> Result>, + { + self.fde_for_address(&frame, bases, address, get_cie) + } + + /// Returns the frame unwind information for the given address, + /// or `NoUnwindInfoForAddress` if there are none. + /// + /// You must provide a function to get the associated CIE. See + /// `PartialFrameDescriptionEntry::parse` for more information. + pub fn unwind_info_for_address<'ctx, F, S>( + &self, + frame: &EhFrame, + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: u64, + get_cie: F, + ) -> Result<&'ctx UnwindTableRow> + where + F: FnMut( + &EhFrame, + &BaseAddresses, + EhFrameOffset, + ) -> Result>, + S: UnwindContextStorage, + { + let fde = self.fde_for_address(frame, bases, address, get_cie)?; + fde.unwind_info_for_address(frame, bases, ctx, address) + } +} + +/// `EhFrame` contains the frame unwinding information needed during exception +/// handling found in the `.eh_frame` section. +/// +/// Most interesting methods are defined in the +/// [`UnwindSection`](trait.UnwindSection.html) trait. +/// +/// See +/// [`DebugFrame`](./struct.DebugFrame.html#differences-between-debug_frame-and-eh_frame) +/// for some discussion on the differences between `.debug_frame` and +/// `.eh_frame`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct EhFrame { + section: R, + address_size: u8, + vendor: Vendor, +} + +impl EhFrame { + /// Set the size of a target address in bytes. + /// + /// This defaults to the native word size. + pub fn set_address_size(&mut self, address_size: u8) { + self.address_size = address_size + } + + /// Set the vendor extensions to use. + /// + /// This defaults to `Vendor::Default`. + pub fn set_vendor(&mut self, vendor: Vendor) { + self.vendor = vendor; + } +} + +impl<'input, Endian> EhFrame> +where + Endian: Endianity, +{ + /// Construct a new `EhFrame` instance from the data in the + /// `.eh_frame` section. + /// + /// It is the caller's responsibility to read the section and present it as + /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O + /// loader on macOS, etc. + /// + /// ``` + /// use gimli::{EhFrame, EndianSlice, NativeEndian}; + /// + /// // Use with `.eh_frame` + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # let read_eh_frame_section_somehow = || &buf; + /// let eh_frame = EhFrame::new(read_eh_frame_section_somehow(), NativeEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) + } +} + +impl Section for EhFrame { + fn id() -> SectionId { + SectionId::EhFrame + } + + fn reader(&self) -> &R { + &self.section + } +} + +impl From for EhFrame { + fn from(section: R) -> Self { + // Default to native word size. + EhFrame { + section, + address_size: mem::size_of::() as u8, + vendor: Vendor::Default, + } + } +} + +// This has to be `pub` to silence a warning (that is deny(..)'d by default) in +// rustc. Eventually, not having this `pub` will become a hard error. +#[doc(hidden)] +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CieOffsetEncoding { + U32, + U64, +} + +/// An offset into an `UnwindSection`. +// +// Needed to avoid conflicting implementations of `Into`. +pub trait UnwindOffset: Copy + Debug + Eq + From +where + T: ReaderOffset, +{ + /// Convert an `UnwindOffset` into a `T`. + fn into(self) -> T; +} + +impl UnwindOffset for DebugFrameOffset +where + T: ReaderOffset, +{ + #[inline] + fn into(self) -> T { + self.0 + } +} + +impl UnwindOffset for EhFrameOffset +where + T: ReaderOffset, +{ + #[inline] + fn into(self) -> T { + self.0 + } +} + +/// This trait completely encapsulates everything that is different between +/// `.eh_frame` and `.debug_frame`, as well as all the bits that can change +/// between DWARF versions. +#[doc(hidden)] +pub trait _UnwindSectionPrivate { + /// Get the underlying section data. + fn section(&self) -> &R; + + /// Returns true if the section allows a zero terminator. + fn has_zero_terminator() -> bool; + + /// Return true if the given offset if the CIE sentinel, false otherwise. + fn is_cie(format: Format, id: u64) -> bool; + + /// Return the CIE offset/ID encoding used by this unwind section with the + /// given DWARF format. + fn cie_offset_encoding(format: Format) -> CieOffsetEncoding; + + /// For `.eh_frame`, CIE offsets are relative to the current position. For + /// `.debug_frame`, they are relative to the start of the section. We always + /// internally store them relative to the section, so we handle translating + /// `.eh_frame`'s relative offsets in this method. If the offset calculation + /// underflows, return `None`. + fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option; + + /// Does this version of this unwind section encode address and segment + /// sizes in its CIEs? + fn has_address_and_segment_sizes(version: u8) -> bool; + + /// The address size to use if `has_address_and_segment_sizes` returns false. + fn address_size(&self) -> u8; + + /// The vendor extensions to use. + fn vendor(&self) -> Vendor; +} + +/// A section holding unwind information: either `.debug_frame` or +/// `.eh_frame`. See [`DebugFrame`](./struct.DebugFrame.html) and +/// [`EhFrame`](./struct.EhFrame.html) respectively. +pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { + /// The offset type associated with this CFI section. Either + /// `DebugFrameOffset` or `EhFrameOffset`. + type Offset: UnwindOffset; + + /// Iterate over the `CommonInformationEntry`s and `FrameDescriptionEntry`s + /// in this `.debug_frame` section. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> { + CfiEntriesIter { + section: self.clone(), + bases, + input: self.section().clone(), + } + } + + /// Parse the `CommonInformationEntry` at the given offset. + fn cie_from_offset( + &self, + bases: &BaseAddresses, + offset: Self::Offset, + ) -> Result> { + let offset = UnwindOffset::into(offset); + let input = &mut self.section().clone(); + input.skip(offset)?; + CommonInformationEntry::parse(bases, self, input) + } + + /// Parse the `PartialFrameDescriptionEntry` at the given offset. + fn partial_fde_from_offset<'bases>( + &self, + bases: &'bases BaseAddresses, + offset: Self::Offset, + ) -> Result> { + let offset = UnwindOffset::into(offset); + let input = &mut self.section().clone(); + input.skip(offset)?; + PartialFrameDescriptionEntry::parse_partial(self, bases, input) + } + + /// Parse the `FrameDescriptionEntry` at the given offset. + fn fde_from_offset( + &self, + bases: &BaseAddresses, + offset: Self::Offset, + get_cie: F, + ) -> Result> + where + F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + { + let partial = self.partial_fde_from_offset(bases, offset)?; + partial.parse(get_cie) + } + + /// Find the `FrameDescriptionEntry` for the given address. + /// + /// If found, the FDE is returned. If not found, + /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. + /// If parsing fails, the error is returned. + /// + /// You must provide a function to get its associated CIE. See + /// `PartialFrameDescriptionEntry::parse` for more information. + /// + /// Note: this iterates over all FDEs. If available, it is possible + /// to do a binary search with `EhFrameHdr::fde_for_address` instead. + fn fde_for_address( + &self, + bases: &BaseAddresses, + address: u64, + mut get_cie: F, + ) -> Result> + where + F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + { + let mut entries = self.entries(bases); + while let Some(entry) = entries.next()? { + match entry { + CieOrFde::Cie(_) => {} + CieOrFde::Fde(partial) => { + let fde = partial.parse(&mut get_cie)?; + if fde.contains(address) { + return Ok(fde); + } + } + } + } + Err(Error::NoUnwindInfoForAddress) + } + + /// Find the frame unwind information for the given address. + /// + /// If found, the unwind information is returned. If not found, + /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or + /// CFI evaluation fails, the error is returned. + /// + /// ``` + /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindContext, + /// UnwindSection}; + /// + /// # fn foo() -> gimli::Result<()> { + /// # let read_eh_frame_section = || unimplemented!(); + /// // Get the `.eh_frame` section from the object file. Alternatively, + /// // use `EhFrame` with the `.eh_frame` section of the object file. + /// let eh_frame = EhFrame::new(read_eh_frame_section(), NativeEndian); + /// + /// # let get_frame_pc = || unimplemented!(); + /// // Get the address of the PC for a frame you'd like to unwind. + /// let address = get_frame_pc(); + /// + /// // This context is reusable, which cuts down on heap allocations. + /// let ctx = UnwindContext::new(); + /// + /// // Optionally provide base addresses for any relative pointers. If a + /// // base address isn't provided and a pointer is found that is relative to + /// // it, we will return an `Err`. + /// # let address_of_text_section_in_memory = unimplemented!(); + /// # let address_of_got_section_in_memory = unimplemented!(); + /// let bases = BaseAddresses::default() + /// .set_text(address_of_text_section_in_memory) + /// .set_got(address_of_got_section_in_memory); + /// + /// let unwind_info = eh_frame.unwind_info_for_address( + /// &bases, + /// &mut ctx, + /// address, + /// EhFrame::cie_from_offset, + /// )?; + /// + /// # let do_stuff_with = |_| unimplemented!(); + /// do_stuff_with(unwind_info); + /// # let _ = ctx; + /// # unreachable!() + /// # } + /// ``` + #[inline] + fn unwind_info_for_address<'ctx, F, S>( + &self, + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: u64, + get_cie: F, + ) -> Result<&'ctx UnwindTableRow> + where + F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + S: UnwindContextStorage, + { + let fde = self.fde_for_address(bases, address, get_cie)?; + fde.unwind_info_for_address(self, bases, ctx, address) + } +} + +impl _UnwindSectionPrivate for DebugFrame { + fn section(&self) -> &R { + &self.section + } + + fn has_zero_terminator() -> bool { + false + } + + fn is_cie(format: Format, id: u64) -> bool { + match format { + Format::Dwarf32 => id == 0xffff_ffff, + Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff, + } + } + + fn cie_offset_encoding(format: Format) -> CieOffsetEncoding { + match format { + Format::Dwarf32 => CieOffsetEncoding::U32, + Format::Dwarf64 => CieOffsetEncoding::U64, + } + } + + fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option { + Some(offset) + } + + fn has_address_and_segment_sizes(version: u8) -> bool { + version == 4 + } + + fn address_size(&self) -> u8 { + self.address_size + } + + fn vendor(&self) -> Vendor { + self.vendor + } +} + +impl UnwindSection for DebugFrame { + type Offset = DebugFrameOffset; +} + +impl _UnwindSectionPrivate for EhFrame { + fn section(&self) -> &R { + &self.section + } + + fn has_zero_terminator() -> bool { + true + } + + fn is_cie(_: Format, id: u64) -> bool { + id == 0 + } + + fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding { + // `.eh_frame` offsets are always 4 bytes, regardless of the DWARF + // format. + CieOffsetEncoding::U32 + } + + fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option { + base.checked_sub(offset) + } + + fn has_address_and_segment_sizes(_version: u8) -> bool { + false + } + + fn address_size(&self) -> u8 { + self.address_size + } + + fn vendor(&self) -> Vendor { + self.vendor + } +} + +impl UnwindSection for EhFrame { + type Offset = EhFrameOffset; +} + +/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers. +/// +/// During CIE/FDE parsing, if a relative pointer is encountered for a base +/// address that is unknown, an Err will be returned. +/// +/// ``` +/// use gimli::BaseAddresses; +/// +/// # fn foo() { +/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); +/// # let address_of_eh_frame_section_in_memory = unimplemented!(); +/// # let address_of_text_section_in_memory = unimplemented!(); +/// # let address_of_got_section_in_memory = unimplemented!(); +/// # let address_of_the_start_of_current_func = unimplemented!(); +/// let bases = BaseAddresses::default() +/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) +/// .set_eh_frame(address_of_eh_frame_section_in_memory) +/// .set_text(address_of_text_section_in_memory) +/// .set_got(address_of_got_section_in_memory); +/// # let _ = bases; +/// # } +/// ``` +#[derive(Clone, Default, Debug, PartialEq, Eq)] +pub struct BaseAddresses { + /// The base addresses to use for pointers in the `.eh_frame_hdr` section. + pub eh_frame_hdr: SectionBaseAddresses, + + /// The base addresses to use for pointers in the `.eh_frame` section. + pub eh_frame: SectionBaseAddresses, +} + +/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers +/// in a particular section. +/// +/// See `BaseAddresses` for methods that are helpful in setting these addresses. +#[derive(Clone, Default, Debug, PartialEq, Eq)] +pub struct SectionBaseAddresses { + /// The address of the section containing the pointer. + pub section: Option, + + /// The base address for text relative pointers. + /// This is generally the address of the `.text` section. + pub text: Option, + + /// The base address for data relative pointers. + /// + /// For pointers in the `.eh_frame_hdr` section, this is the address + /// of the `.eh_frame_hdr` section + /// + /// For pointers in the `.eh_frame` section, this is generally the + /// global pointer, such as the address of the `.got` section. + pub data: Option, +} + +impl BaseAddresses { + /// Set the `.eh_frame_hdr` section base address. + #[inline] + pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self { + self.eh_frame_hdr.section = Some(addr); + self.eh_frame_hdr.data = Some(addr); + self + } + + /// Set the `.eh_frame` section base address. + #[inline] + pub fn set_eh_frame(mut self, addr: u64) -> Self { + self.eh_frame.section = Some(addr); + self + } + + /// Set the `.text` section base address. + #[inline] + pub fn set_text(mut self, addr: u64) -> Self { + self.eh_frame_hdr.text = Some(addr); + self.eh_frame.text = Some(addr); + self + } + + /// Set the `.got` section base address. + #[inline] + pub fn set_got(mut self, addr: u64) -> Self { + self.eh_frame.data = Some(addr); + self + } +} + +/// An iterator over CIE and FDE entries in a `.debug_frame` or `.eh_frame` +/// section. +/// +/// Some pointers may be encoded relative to various base addresses. Use the +/// [`BaseAddresses`](./struct.BaseAddresses.html) parameter to provide them. By +/// default, none are provided. If a relative pointer is encountered for a base +/// address that is unknown, an `Err` will be returned and iteration will abort. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +/// +/// ``` +/// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindSection}; +/// +/// # fn foo() -> gimli::Result<()> { +/// # let read_eh_frame_somehow = || unimplemented!(); +/// let eh_frame = EhFrame::new(read_eh_frame_somehow(), NativeEndian); +/// +/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); +/// # let address_of_eh_frame_section_in_memory = unimplemented!(); +/// # let address_of_text_section_in_memory = unimplemented!(); +/// # let address_of_got_section_in_memory = unimplemented!(); +/// # let address_of_the_start_of_current_func = unimplemented!(); +/// // Provide base addresses for relative pointers. +/// let bases = BaseAddresses::default() +/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) +/// .set_eh_frame(address_of_eh_frame_section_in_memory) +/// .set_text(address_of_text_section_in_memory) +/// .set_got(address_of_got_section_in_memory); +/// +/// let mut entries = eh_frame.entries(&bases); +/// +/// # let do_stuff_with = |_| unimplemented!(); +/// while let Some(entry) = entries.next()? { +/// do_stuff_with(entry) +/// } +/// # unreachable!() +/// # } +/// ``` +#[derive(Clone, Debug)] +pub struct CfiEntriesIter<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + section: Section, + bases: &'bases BaseAddresses, + input: R, +} + +impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + /// Advance the iterator to the next entry. + pub fn next(&mut self) -> Result>> { + loop { + if self.input.is_empty() { + return Ok(None); + } + + match parse_cfi_entry(self.bases, &self.section, &mut self.input) { + Ok(Some(entry)) => return Ok(Some(entry)), + Err(e) => { + self.input.empty(); + return Err(e); + } + Ok(None) => { + if Section::has_zero_terminator() { + self.input.empty(); + return Ok(None); + } + + // Hack: If we get to here, then we're reading `.debug_frame` and + // encountered a length of 0. This is a compiler or linker bug + // (originally seen for NASM, fixed in 2.15rc9). + // Skip this value and try again. + continue; + } + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl<'bases, Section, R> fallible_iterator::FallibleIterator for CfiEntriesIter<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + type Item = CieOrFde<'bases, Section, R>; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + CfiEntriesIter::next(self) + } +} + +/// Either a `CommonInformationEntry` (CIE) or a `FrameDescriptionEntry` (FDE). +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CieOrFde<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + /// This CFI entry is a `CommonInformationEntry`. + Cie(CommonInformationEntry), + /// This CFI entry is a `FrameDescriptionEntry`, however fully parsing it + /// requires parsing its CIE first, so it is left in a partially parsed + /// state. + Fde(PartialFrameDescriptionEntry<'bases, Section, R>), +} + +fn parse_cfi_entry<'bases, Section, R>( + bases: &'bases BaseAddresses, + section: &Section, + input: &mut R, +) -> Result>> +where + R: Reader, + Section: UnwindSection, +{ + let offset = input.offset_from(section.section()); + let (length, format) = input.read_initial_length()?; + if length.into_u64() == 0 { + return Ok(None); + } + + let mut rest = input.split(length)?; + let cie_offset_base = rest.offset_from(section.section()); + let cie_id_or_offset = match Section::cie_offset_encoding(format) { + CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?, + CieOffsetEncoding::U64 => rest.read_u64()?, + }; + + if Section::is_cie(format, cie_id_or_offset) { + let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?; + Ok(Some(CieOrFde::Cie(cie))) + } else { + let cie_offset = R::Offset::from_u64(cie_id_or_offset)?; + let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) { + None => return Err(Error::OffsetOutOfBounds), + Some(cie_offset) => cie_offset, + }; + + let fde = PartialFrameDescriptionEntry { + offset, + length, + format, + cie_offset: cie_offset.into(), + rest, + section: section.clone(), + bases, + }; + + Ok(Some(CieOrFde::Fde(fde))) + } +} + +/// We support the z-style augmentation [defined by `.eh_frame`][ehframe]. +/// +/// [ehframe]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct Augmentation { + /// > A 'L' may be present at any position after the first character of the + /// > string. This character may only be present if 'z' is the first character + /// > of the string. If present, it indicates the presence of one argument in + /// > the Augmentation Data of the CIE, and a corresponding argument in the + /// > Augmentation Data of the FDE. The argument in the Augmentation Data of + /// > the CIE is 1-byte and represents the pointer encoding used for the + /// > argument in the Augmentation Data of the FDE, which is the address of a + /// > language-specific data area (LSDA). The size of the LSDA pointer is + /// > specified by the pointer encoding used. + lsda: Option, + + /// > A 'P' may be present at any position after the first character of the + /// > string. This character may only be present if 'z' is the first character + /// > of the string. If present, it indicates the presence of two arguments in + /// > the Augmentation Data of the CIE. The first argument is 1-byte and + /// > represents the pointer encoding used for the second argument, which is + /// > the address of a personality routine handler. The size of the + /// > personality routine pointer is specified by the pointer encoding used. + personality: Option<(constants::DwEhPe, Pointer)>, + + /// > A 'R' may be present at any position after the first character of the + /// > string. This character may only be present if 'z' is the first character + /// > of the string. If present, The Augmentation Data shall include a 1 byte + /// > argument that represents the pointer encoding for the address pointers + /// > used in the FDE. + fde_address_encoding: Option, + + /// True if this CIE's FDEs are trampolines for signal handlers. + is_signal_trampoline: bool, +} + +impl Augmentation { + fn parse( + augmentation_str: &mut R, + bases: &BaseAddresses, + address_size: u8, + section: &Section, + input: &mut R, + ) -> Result + where + R: Reader, + Section: UnwindSection, + { + debug_assert!( + !augmentation_str.is_empty(), + "Augmentation::parse should only be called if we have an augmentation" + ); + + let mut augmentation = Augmentation::default(); + + let mut parsed_first = false; + let mut data = None; + + while !augmentation_str.is_empty() { + let ch = augmentation_str.read_u8()?; + match ch { + b'z' => { + if parsed_first { + return Err(Error::UnknownAugmentation); + } + + let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?; + data = Some(input.split(augmentation_length)?); + } + b'L' => { + let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; + let encoding = parse_pointer_encoding(rest)?; + augmentation.lsda = Some(encoding); + } + b'P' => { + let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; + let encoding = parse_pointer_encoding(rest)?; + let parameters = PointerEncodingParameters { + bases: &bases.eh_frame, + func_base: None, + address_size, + section: section.section(), + }; + + let personality = parse_encoded_pointer(encoding, ¶meters, rest)?; + augmentation.personality = Some((encoding, personality)); + } + b'R' => { + let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; + let encoding = parse_pointer_encoding(rest)?; + augmentation.fde_address_encoding = Some(encoding); + } + b'S' => augmentation.is_signal_trampoline = true, + _ => return Err(Error::UnknownAugmentation), + } + + parsed_first = true; + } + + Ok(augmentation) + } +} + +/// Parsed augmentation data for a `FrameDescriptEntry`. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +struct AugmentationData { + lsda: Option, +} + +impl AugmentationData { + fn parse( + augmentation: &Augmentation, + encoding_parameters: &PointerEncodingParameters<'_, R>, + input: &mut R, + ) -> Result { + // In theory, we should be iterating over the original augmentation + // string, interpreting each character, and reading the appropriate bits + // out of the augmentation data as we go. However, the only character + // that defines augmentation data in the FDE is the 'L' character, so we + // can just check for its presence directly. + + let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?; + let rest = &mut input.split(aug_data_len)?; + let mut augmentation_data = AugmentationData::default(); + if let Some(encoding) = augmentation.lsda { + let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?; + augmentation_data.lsda = Some(lsda); + } + Ok(augmentation_data) + } +} + +/// > A Common Information Entry holds information that is shared among many +/// > Frame Description Entries. There is at least one CIE in every non-empty +/// > `.debug_frame` section. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CommonInformationEntry::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// The offset of this entry from the start of its containing section. + offset: Offset, + + /// > A constant that gives the number of bytes of the CIE structure, not + /// > including the length field itself (see Section 7.2.2). The size of the + /// > length field plus the value of length must be an integral multiple of + /// > the address size. + length: Offset, + + format: Format, + + /// > A version number (see Section 7.23). This number is specific to the + /// > call frame information and is independent of the DWARF version number. + version: u8, + + /// The parsed augmentation, if any. + augmentation: Option, + + /// > The size of a target address in this CIE and any FDEs that use it, in + /// > bytes. If a compilation unit exists for this frame, its address size + /// > must match the address size here. + address_size: u8, + + /// "A constant that is factored out of all advance location instructions + /// (see Section 6.4.2.1)." + code_alignment_factor: u64, + + /// > A constant that is factored out of certain offset instructions (see + /// > below). The resulting value is (operand * data_alignment_factor). + data_alignment_factor: i64, + + /// > An unsigned LEB128 constant that indicates which column in the rule + /// > table represents the return address of the function. Note that this + /// > column might not correspond to an actual machine register. + return_address_register: Register, + + /// > A sequence of rules that are interpreted to create the initial setting + /// > of each column in the table. + /// + /// > The default rule for all columns before interpretation of the initial + /// > instructions is the undefined rule. However, an ABI authoring body or a + /// > compilation system authoring body may specify an alternate default + /// > value for any or all columns. + /// + /// This is followed by `DW_CFA_nop` padding until the end of `length` bytes + /// in the input. + initial_instructions: R, +} + +impl CommonInformationEntry { + fn parse>( + bases: &BaseAddresses, + section: &Section, + input: &mut R, + ) -> Result> { + match parse_cfi_entry(bases, section, input)? { + Some(CieOrFde::Cie(cie)) => Ok(cie), + Some(CieOrFde::Fde(_)) => Err(Error::NotCieId), + None => Err(Error::NoEntryAtGivenOffset), + } + } + + fn parse_rest>( + offset: R::Offset, + length: R::Offset, + format: Format, + bases: &BaseAddresses, + section: &Section, + mut rest: R, + ) -> Result> { + let version = rest.read_u8()?; + + // Version 1 of `.debug_frame` corresponds to DWARF 2, and then for + // DWARF 3 and 4, I think they decided to just match the standard's + // version. + match version { + 1 | 3 | 4 => (), + _ => return Err(Error::UnknownVersion(u64::from(version))), + } + + let mut augmentation_string = rest.read_null_terminated_slice()?; + + let address_size = if Section::has_address_and_segment_sizes(version) { + let address_size = rest.read_address_size()?; + let segment_size = rest.read_u8()?; + if segment_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + address_size + } else { + section.address_size() + }; + + let code_alignment_factor = rest.read_uleb128()?; + let data_alignment_factor = rest.read_sleb128()?; + + let return_address_register = if version == 1 { + Register(rest.read_u8()?.into()) + } else { + rest.read_uleb128().and_then(Register::from_u64)? + }; + + let augmentation = if augmentation_string.is_empty() { + None + } else { + Some(Augmentation::parse( + &mut augmentation_string, + bases, + address_size, + section, + &mut rest, + )?) + }; + + let entry = CommonInformationEntry { + offset, + length, + format, + version, + augmentation, + address_size, + code_alignment_factor, + data_alignment_factor, + return_address_register, + initial_instructions: rest, + }; + + Ok(entry) + } +} + +/// # Signal Safe Methods +/// +/// These methods are guaranteed not to allocate, acquire locks, or perform any +/// other signal-unsafe operations. +impl CommonInformationEntry { + /// Get the offset of this entry from the start of its containing section. + pub fn offset(&self) -> R::Offset { + self.offset + } + + /// Return the encoding parameters for this CIE. + pub fn encoding(&self) -> Encoding { + Encoding { + format: self.format, + version: u16::from(self.version), + address_size: self.address_size, + } + } + + /// The size of addresses (in bytes) in this CIE. + pub fn address_size(&self) -> u8 { + self.address_size + } + + /// Iterate over this CIE's initial instructions. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn instructions<'a, Section>( + &self, + section: &'a Section, + bases: &'a BaseAddresses, + ) -> CallFrameInstructionIter<'a, R> + where + Section: UnwindSection, + { + CallFrameInstructionIter { + input: self.initial_instructions.clone(), + address_encoding: None, + parameters: PointerEncodingParameters { + bases: &bases.eh_frame, + func_base: None, + address_size: self.address_size, + section: section.section(), + }, + vendor: section.vendor(), + } + } + + /// > A constant that gives the number of bytes of the CIE structure, not + /// > including the length field itself (see Section 7.2.2). The size of the + /// > length field plus the value of length must be an integral multiple of + /// > the address size. + pub fn entry_len(&self) -> R::Offset { + self.length + } + + /// > A version number (see Section 7.23). This number is specific to the + /// > call frame information and is independent of the DWARF version number. + pub fn version(&self) -> u8 { + self.version + } + + /// Get the augmentation data, if any exists. + /// + /// The only augmentation understood by `gimli` is that which is defined by + /// `.eh_frame`. + pub fn augmentation(&self) -> Option<&Augmentation> { + self.augmentation.as_ref() + } + + /// True if this CIE's FDEs have a LSDA. + pub fn has_lsda(&self) -> bool { + self.augmentation.map_or(false, |a| a.lsda.is_some()) + } + + /// Return the encoding of the LSDA address for this CIE's FDEs. + pub fn lsda_encoding(&self) -> Option { + self.augmentation.and_then(|a| a.lsda) + } + + /// Return the encoding and address of the personality routine handler + /// for this CIE's FDEs. + pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> { + self.augmentation.as_ref().and_then(|a| a.personality) + } + + /// Return the address of the personality routine handler + /// for this CIE's FDEs. + pub fn personality(&self) -> Option { + self.augmentation + .as_ref() + .and_then(|a| a.personality) + .map(|(_, p)| p) + } + + /// Return the encoding of the addresses for this CIE's FDEs. + pub fn fde_address_encoding(&self) -> Option { + self.augmentation.and_then(|a| a.fde_address_encoding) + } + + /// True if this CIE's FDEs are trampolines for signal handlers. + pub fn is_signal_trampoline(&self) -> bool { + self.augmentation.map_or(false, |a| a.is_signal_trampoline) + } + + /// > A constant that is factored out of all advance location instructions + /// > (see Section 6.4.2.1). + pub fn code_alignment_factor(&self) -> u64 { + self.code_alignment_factor + } + + /// > A constant that is factored out of certain offset instructions (see + /// > below). The resulting value is (operand * data_alignment_factor). + pub fn data_alignment_factor(&self) -> i64 { + self.data_alignment_factor + } + + /// > An unsigned ... constant that indicates which column in the rule + /// > table represents the return address of the function. Note that this + /// > column might not correspond to an actual machine register. + pub fn return_address_register(&self) -> Register { + self.return_address_register + } +} + +/// A partially parsed `FrameDescriptionEntry`. +/// +/// Fully parsing this FDE requires first parsing its CIE. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PartialFrameDescriptionEntry<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + offset: R::Offset, + length: R::Offset, + format: Format, + cie_offset: Section::Offset, + rest: R, + section: Section, + bases: &'bases BaseAddresses, +} + +impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R> +where + R: Reader, + Section: UnwindSection, +{ + fn parse_partial( + section: &Section, + bases: &'bases BaseAddresses, + input: &mut R, + ) -> Result> { + match parse_cfi_entry(bases, section, input)? { + Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer), + Some(CieOrFde::Fde(partial)) => Ok(partial), + None => Err(Error::NoEntryAtGivenOffset), + } + } + + /// Fully parse this FDE. + /// + /// You must provide a function get its associated CIE (either by parsing it + /// on demand, or looking it up in some table mapping offsets to CIEs that + /// you've already parsed, etc.) + pub fn parse(&self, get_cie: F) -> Result> + where + F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, + { + FrameDescriptionEntry::parse_rest( + self.offset, + self.length, + self.format, + self.cie_offset, + self.rest.clone(), + &self.section, + self.bases, + get_cie, + ) + } + + /// Get the offset of this entry from the start of its containing section. + pub fn offset(&self) -> R::Offset { + self.offset + } + + /// Get the offset of this FDE's CIE. + pub fn cie_offset(&self) -> Section::Offset { + self.cie_offset + } + + /// > A constant that gives the number of bytes of the header and + /// > instruction stream for this function, not including the length field + /// > itself (see Section 7.2.2). The size of the length field plus the value + /// > of length must be an integral multiple of the address size. + pub fn entry_len(&self) -> R::Offset { + self.length + } +} + +/// A `FrameDescriptionEntry` is a set of CFA instructions for an address range. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FrameDescriptionEntry::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + /// The start of this entry within its containing section. + offset: Offset, + + /// > A constant that gives the number of bytes of the header and + /// > instruction stream for this function, not including the length field + /// > itself (see Section 7.2.2). The size of the length field plus the value + /// > of length must be an integral multiple of the address size. + length: Offset, + + format: Format, + + /// "A constant offset into the .debug_frame section that denotes the CIE + /// that is associated with this FDE." + /// + /// This is the CIE at that offset. + cie: CommonInformationEntry, + + /// > The address of the first location associated with this table entry. If + /// > the segment_size field of this FDE's CIE is non-zero, the initial + /// > location is preceded by a segment selector of the given length. + initial_address: u64, + + /// "The number of bytes of program instructions described by this entry." + address_range: u64, + + /// The parsed augmentation data, if we have any. + augmentation: Option, + + /// "A sequence of table defining instructions that are described below." + /// + /// This is followed by `DW_CFA_nop` padding until `length` bytes of the + /// input are consumed. + instructions: R, +} + +impl FrameDescriptionEntry { + fn parse_rest( + offset: R::Offset, + length: R::Offset, + format: Format, + cie_pointer: Section::Offset, + mut rest: R, + section: &Section, + bases: &BaseAddresses, + mut get_cie: F, + ) -> Result> + where + Section: UnwindSection, + F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, + { + let cie = get_cie(section, bases, cie_pointer)?; + + let mut parameters = PointerEncodingParameters { + bases: &bases.eh_frame, + func_base: None, + address_size: cie.address_size, + section: section.section(), + }; + + let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, ¶meters)?; + parameters.func_base = Some(initial_address); + + let aug_data = if let Some(ref augmentation) = cie.augmentation { + Some(AugmentationData::parse( + augmentation, + ¶meters, + &mut rest, + )?) + } else { + None + }; + + let entry = FrameDescriptionEntry { + offset, + length, + format, + cie, + initial_address, + address_range, + augmentation: aug_data, + instructions: rest, + }; + + Ok(entry) + } + + fn parse_addresses( + input: &mut R, + cie: &CommonInformationEntry, + parameters: &PointerEncodingParameters<'_, R>, + ) -> Result<(u64, u64)> { + let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding); + if let Some(encoding) = encoding { + // Ignore indirection. + let initial_address = parse_encoded_pointer(encoding, parameters, input)?.pointer(); + let address_range = parse_encoded_value(encoding, parameters, input)?; + Ok((initial_address, address_range)) + } else { + let initial_address = input.read_address(cie.address_size)?; + let address_range = input.read_address(cie.address_size)?; + Ok((initial_address, address_range)) + } + } + + /// Return the table of unwind information for this FDE. + #[inline] + pub fn rows<'a, 'ctx, Section, S>( + &self, + section: &'a Section, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, + ) -> Result> + where + Section: UnwindSection, + S: UnwindContextStorage, + { + UnwindTable::new(section, bases, ctx, self) + } + + /// Find the frame unwind information for the given address. + /// + /// If found, the unwind information is returned along with the reset + /// context in the form `Ok((unwind_info, context))`. If not found, + /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or + /// CFI evaluation fails, the error is returned. + pub fn unwind_info_for_address<'ctx, Section, S>( + &self, + section: &Section, + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: u64, + ) -> Result<&'ctx UnwindTableRow> + where + Section: UnwindSection, + S: UnwindContextStorage, + { + let mut table = self.rows(section, bases, ctx)?; + while let Some(row) = table.next_row()? { + if row.contains(address) { + return Ok(table.ctx.row()); + } + } + Err(Error::NoUnwindInfoForAddress) + } +} + +/// # Signal Safe Methods +/// +/// These methods are guaranteed not to allocate, acquire locks, or perform any +/// other signal-unsafe operations. +#[allow(clippy::len_without_is_empty)] +impl FrameDescriptionEntry { + /// Get the offset of this entry from the start of its containing section. + pub fn offset(&self) -> R::Offset { + self.offset + } + + /// Get a reference to this FDE's CIE. + pub fn cie(&self) -> &CommonInformationEntry { + &self.cie + } + + /// > A constant that gives the number of bytes of the header and + /// > instruction stream for this function, not including the length field + /// > itself (see Section 7.2.2). The size of the length field plus the value + /// > of length must be an integral multiple of the address size. + pub fn entry_len(&self) -> R::Offset { + self.length + } + + /// Iterate over this FDE's instructions. + /// + /// Will not include the CIE's initial instructions, if you want those do + /// `fde.cie().instructions()` first. + /// + /// Can be [used with + /// `FallibleIterator`](./index.html#using-with-fallibleiterator). + pub fn instructions<'a, Section>( + &self, + section: &'a Section, + bases: &'a BaseAddresses, + ) -> CallFrameInstructionIter<'a, R> + where + Section: UnwindSection, + { + CallFrameInstructionIter { + input: self.instructions.clone(), + address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding), + parameters: PointerEncodingParameters { + bases: &bases.eh_frame, + func_base: None, + address_size: self.cie.address_size, + section: section.section(), + }, + vendor: section.vendor(), + } + } + + /// The first address for which this entry has unwind information for. + pub fn initial_address(&self) -> u64 { + self.initial_address + } + + /// One more than the last address that this entry has unwind information for. + /// + /// This uses wrapping arithmetic, so the result may be less than + /// `initial_address`. + pub fn end_address(&self) -> u64 { + self.initial_address + .wrapping_add_sized(self.address_range, self.cie.address_size) + } + + /// The number of bytes of instructions that this entry has unwind + /// information for. + pub fn len(&self) -> u64 { + self.address_range + } + + /// Return `true` if the given address is within this FDE, `false` + /// otherwise. + /// + /// This is equivalent to `entry.initial_address() <= address < + /// entry.initial_address() + entry.len()`. + pub fn contains(&self, address: u64) -> bool { + self.initial_address() <= address && address < self.end_address() + } + + /// The address of this FDE's language-specific data area (LSDA), if it has + /// any. + pub fn lsda(&self) -> Option { + self.augmentation.as_ref().and_then(|a| a.lsda) + } + + /// Return true if this FDE's function is a trampoline for a signal handler. + #[inline] + pub fn is_signal_trampoline(&self) -> bool { + self.cie().is_signal_trampoline() + } + + /// Return the address of the FDE's function's personality routine + /// handler. The personality routine does language-specific clean up when + /// unwinding the stack frames with the intent to not run them again. + #[inline] + pub fn personality(&self) -> Option { + self.cie().personality() + } +} + +/// Specification of what storage should be used for [`UnwindContext`]. +/// +#[cfg_attr( + feature = "read", + doc = " +Normally you would only need to use [`StoreOnHeap`], which places the stack +on the heap using [`Box`]. This is the default storage type parameter for [`UnwindContext`]. + +You may want to supply your own storage type for one of the following reasons: + + 1. In rare cases you may run into failed unwinds due to the fixed stack size + used by [`StoreOnHeap`], so you may want to try a larger `Box`. If denial + of service is not a concern, then you could also try a `Vec`-based stack which + can grow as needed. + 2. You may want to avoid heap allocations entirely. You can use a fixed-size + stack with in-line arrays, which will place the entire storage in-line into + [`UnwindContext`]. +" +)] +/// +/// Here's an implementation which uses a fixed-size stack and allocates everything in-line, +/// which will cause `UnwindContext` to be large: +/// +/// ```rust,no_run +/// # use gimli::*; +/// # +/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry>) +/// # -> gimli::Result<()> { +/// # let eh_frame: gimli::EhFrame<_> = unreachable!(); +/// # let bases = unimplemented!(); +/// # +/// struct StoreOnStack; +/// +/// impl UnwindContextStorage for StoreOnStack { +/// type Rules = [(Register, RegisterRule); 192]; +/// type Stack = [UnwindTableRow; 4]; +/// } +/// +/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in(); +/// +/// // Initialize the context by evaluating the CIE's initial instruction program, +/// // and generate the unwind table. +/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?; +/// while let Some(row) = table.next_row()? { +/// // Do stuff with each row... +/// # let _ = row; +/// } +/// # unreachable!() +/// # } +/// ``` +pub trait UnwindContextStorage: Sized { + /// The storage used for register rules in a unwind table row. + /// + /// Note that this is nested within the stack. + type Rules: ArrayLike)>; + + /// The storage used for unwind table row stack. + type Stack: ArrayLike>; +} + +#[cfg(feature = "read")] +const MAX_RULES: usize = 192; +#[cfg(feature = "read")] +const MAX_UNWIND_STACK_DEPTH: usize = 4; + +#[cfg(feature = "read")] +impl UnwindContextStorage for StoreOnHeap { + type Rules = [(Register, RegisterRule); MAX_RULES]; + type Stack = Box<[UnwindTableRow; MAX_UNWIND_STACK_DEPTH]>; +} + +/// Common context needed when evaluating the call frame unwinding information. +/// +/// By default, this structure is small and allocates its internal storage +/// on the heap using [`Box`] during [`UnwindContext::new`]. +/// +/// This can be overridden by providing a custom [`UnwindContextStorage`] type parameter. +/// When using a custom storage with in-line arrays, the [`UnwindContext`] type itself +/// will be big, so in that case it's recommended to place [`UnwindContext`] on the +/// heap, e.g. using `Box::new(UnwindContext::::new_in())`. +/// +/// To avoid re-allocating the context multiple times when evaluating multiple +/// CFI programs, the same [`UnwindContext`] can be reused for multiple unwinds. +/// +/// ``` +/// use gimli::{UnwindContext, UnwindTable}; +/// +/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry>) +/// # -> gimli::Result<()> { +/// # let eh_frame: gimli::EhFrame<_> = unreachable!(); +/// # let bases = unimplemented!(); +/// // An uninitialized context. +/// let mut ctx = UnwindContext::new(); +/// +/// // Initialize the context by evaluating the CIE's initial instruction program, +/// // and generate the unwind table. +/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?; +/// while let Some(row) = table.next_row()? { +/// // Do stuff with each row... +/// # let _ = row; +/// } +/// # unreachable!() +/// # } +/// ``` +#[derive(Clone, PartialEq, Eq)] +pub struct UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + // Stack of rows. The last row is the row currently being built by the + // program. There is always at least one row. The vast majority of CFI + // programs will only ever have one row on the stack. + stack: ArrayVec, + + // If we are evaluating an FDE's instructions, then `is_initialized` will be + // `true`. If `initial_rule` is `Some`, then the initial register rules are either + // all default rules or have just 1 non-default rule, stored in `initial_rule`. + // If it's `None`, `stack[0]` will contain the initial register rules + // described by the CIE's initial instructions. These rules are used by + // `DW_CFA_restore`. Otherwise, when we are currently evaluating a CIE's + // initial instructions, `is_initialized` will be `false` and initial rules + // cannot be read. + initial_rule: Option<(Register, RegisterRule)>, + + is_initialized: bool, +} + +impl Debug for UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnwindContext") + .field("stack", &self.stack) + .field("initial_rule", &self.initial_rule) + .field("is_initialized", &self.is_initialized) + .finish() + } +} + +impl Default for UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn default() -> Self { + Self::new_in() + } +} + +#[cfg(feature = "read")] +impl UnwindContext { + /// Construct a new call frame unwinding context. + pub fn new() -> Self { + Self::new_in() + } +} + +/// # Signal Safe Methods +/// +/// These methods are guaranteed not to allocate, acquire locks, or perform any +/// other signal-unsafe operations, if an non-allocating storage is used. +impl UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + /// Construct a new call frame unwinding context. + pub fn new_in() -> Self { + let mut ctx = UnwindContext { + stack: Default::default(), + initial_rule: None, + is_initialized: false, + }; + ctx.reset(); + ctx + } + + /// Run the CIE's initial instructions and initialize this `UnwindContext`. + fn initialize( + &mut self, + section: &Section, + bases: &BaseAddresses, + cie: &CommonInformationEntry, + ) -> Result<()> + where + R: Reader, + Section: UnwindSection, + { + // Always reset because previous initialization failure may leave dirty state. + self.reset(); + + let mut table = UnwindTable::new_for_cie(section, bases, self, cie); + while table.next_row()?.is_some() {} + + self.save_initial_rules()?; + Ok(()) + } + + fn reset(&mut self) { + self.stack.clear(); + self.stack.try_push(UnwindTableRow::default()).unwrap(); + debug_assert!(self.stack[0].is_default()); + self.initial_rule = None; + self.is_initialized = false; + } + + fn row(&self) -> &UnwindTableRow { + self.stack.last().unwrap() + } + + fn row_mut(&mut self) -> &mut UnwindTableRow { + self.stack.last_mut().unwrap() + } + + fn save_initial_rules(&mut self) -> Result<()> { + debug_assert!(!self.is_initialized); + self.initial_rule = match *self.stack.last().unwrap().registers.rules { + // All rules are default (undefined). In this case just synthesize + // an undefined rule. + [] => Some((Register(0), RegisterRule::Undefined)), + [ref rule] => Some(rule.clone()), + _ => { + let rules = self.stack.last().unwrap().clone(); + self.stack + .try_insert(0, rules) + .map_err(|_| Error::StackFull)?; + None + } + }; + self.is_initialized = true; + Ok(()) + } + + fn start_address(&self) -> u64 { + self.row().start_address + } + + fn set_start_address(&mut self, start_address: u64) { + let row = self.row_mut(); + row.start_address = start_address; + } + + fn set_register_rule(&mut self, register: Register, rule: RegisterRule) -> Result<()> { + let row = self.row_mut(); + row.registers.set(register, rule) + } + + /// Returns `None` if we have not completed evaluation of a CIE's initial + /// instructions. + fn get_initial_rule(&self, register: Register) -> Option> { + if !self.is_initialized { + return None; + } + Some(match self.initial_rule { + None => self.stack[0].registers.get(register), + Some((r, ref rule)) if r == register => rule.clone(), + _ => RegisterRule::Undefined, + }) + } + + fn set_cfa(&mut self, cfa: CfaRule) { + self.row_mut().cfa = cfa; + } + + fn cfa_mut(&mut self) -> &mut CfaRule { + &mut self.row_mut().cfa + } + + fn push_row(&mut self) -> Result<()> { + let new_row = self.row().clone(); + self.stack.try_push(new_row).map_err(|_| Error::StackFull) + } + + fn pop_row(&mut self) -> Result<()> { + let min_size = if self.is_initialized && self.initial_rule.is_none() { + 2 + } else { + 1 + }; + if self.stack.len() <= min_size { + return Err(Error::PopWithEmptyStack); + } + self.stack.pop().unwrap(); + Ok(()) + } +} + +/// The `UnwindTable` iteratively evaluates a `FrameDescriptionEntry`'s +/// `CallFrameInstruction` program, yielding the each row one at a time. +/// +/// > 6.4.1 Structure of Call Frame Information +/// > +/// > DWARF supports virtual unwinding by defining an architecture independent +/// > basis for recording how procedures save and restore registers during their +/// > lifetimes. This basis must be augmented on some machines with specific +/// > information that is defined by an architecture specific ABI authoring +/// > committee, a hardware vendor, or a compiler producer. The body defining a +/// > specific augmentation is referred to below as the “augmenter.” +/// > +/// > Abstractly, this mechanism describes a very large table that has the +/// > following structure: +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// > +/// >
LOCCFAR0R1...RN
L0
L1
...
LN
+/// > +/// > The first column indicates an address for every location that contains code +/// > in a program. (In shared objects, this is an object-relative offset.) The +/// > remaining columns contain virtual unwinding rules that are associated with +/// > the indicated location. +/// > +/// > The CFA column defines the rule which computes the Canonical Frame Address +/// > value; it may be either a register and a signed offset that are added +/// > together, or a DWARF expression that is evaluated. +/// > +/// > The remaining columns are labeled by register number. This includes some +/// > registers that have special designation on some architectures such as the PC +/// > and the stack pointer register. (The actual mapping of registers for a +/// > particular architecture is defined by the augmenter.) The register columns +/// > contain rules that describe whether a given register has been saved and the +/// > rule to find the value for the register in the previous frame. +/// > +/// > ... +/// > +/// > This table would be extremely large if actually constructed as +/// > described. Most of the entries at any point in the table are identical to +/// > the ones above them. The whole table can be represented quite compactly by +/// > recording just the differences starting at the beginning address of each +/// > subroutine in the program. +#[derive(Debug)] +pub struct UnwindTable<'a, 'ctx, R, S = StoreOnHeap> +where + R: Reader, + S: UnwindContextStorage, +{ + code_alignment_factor: Wrapping, + data_alignment_factor: Wrapping, + address_size: u8, + next_start_address: u64, + last_end_address: u64, + returned_last_row: bool, + current_row_valid: bool, + instructions: CallFrameInstructionIter<'a, R>, + ctx: &'ctx mut UnwindContext, +} + +/// # Signal Safe Methods +/// +/// These methods are guaranteed not to allocate, acquire locks, or perform any +/// other signal-unsafe operations. +impl<'a, 'ctx, R, S> UnwindTable<'a, 'ctx, R, S> +where + R: Reader, + S: UnwindContextStorage, +{ + /// Construct a new `UnwindTable` for the given + /// `FrameDescriptionEntry`'s CFI unwinding program. + pub fn new>( + section: &'a Section, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, + fde: &FrameDescriptionEntry, + ) -> Result { + ctx.initialize(section, bases, fde.cie())?; + Ok(Self::new_for_fde(section, bases, ctx, fde)) + } + + fn new_for_fde>( + section: &'a Section, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, + fde: &FrameDescriptionEntry, + ) -> Self { + assert!(ctx.stack.len() >= 1); + UnwindTable { + code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()), + data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()), + address_size: fde.cie().address_size, + next_start_address: fde.initial_address(), + last_end_address: fde.end_address(), + returned_last_row: false, + current_row_valid: false, + instructions: fde.instructions(section, bases), + ctx, + } + } + + fn new_for_cie>( + section: &'a Section, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, + cie: &CommonInformationEntry, + ) -> Self { + assert!(ctx.stack.len() >= 1); + UnwindTable { + code_alignment_factor: Wrapping(cie.code_alignment_factor()), + data_alignment_factor: Wrapping(cie.data_alignment_factor()), + address_size: cie.address_size, + next_start_address: 0, + last_end_address: 0, + returned_last_row: false, + current_row_valid: false, + instructions: cie.instructions(section, bases), + ctx, + } + } + + /// Evaluate call frame instructions until the next row of the table is + /// completed, and return it. + /// + /// Unfortunately, this cannot be used with `FallibleIterator` because of + /// the restricted lifetime of the yielded item. + pub fn next_row(&mut self) -> Result>> { + assert!(self.ctx.stack.len() >= 1); + self.ctx.set_start_address(self.next_start_address); + self.current_row_valid = false; + + loop { + match self.instructions.next() { + Err(e) => return Err(e), + + Ok(None) => { + if self.returned_last_row { + return Ok(None); + } + + let row = self.ctx.row_mut(); + row.end_address = self.last_end_address; + + self.returned_last_row = true; + self.current_row_valid = true; + return Ok(Some(row)); + } + + Ok(Some(instruction)) => { + if self.evaluate(instruction)? { + self.current_row_valid = true; + return Ok(Some(self.ctx.row())); + } + } + }; + } + } + + /// Returns the current row with the lifetime of the context. + pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow> { + if self.current_row_valid { + Some(self.ctx.row()) + } else { + None + } + } + + /// Evaluate one call frame instruction. Return `Ok(true)` if the row is + /// complete, `Ok(false)` otherwise. + fn evaluate(&mut self, instruction: CallFrameInstruction) -> Result { + use crate::CallFrameInstruction::*; + + match instruction { + // Instructions that complete the current row and advance the + // address for the next row. + SetLoc { address } => { + if address < self.ctx.start_address() { + return Err(Error::InvalidAddressRange); + } + + self.next_start_address = address; + self.ctx.row_mut().end_address = self.next_start_address; + return Ok(true); + } + AdvanceLoc { delta } => { + let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor; + self.next_start_address = self + .ctx + .start_address() + .add_sized(delta.0, self.address_size)?; + self.ctx.row_mut().end_address = self.next_start_address; + return Ok(true); + } + + // Instructions that modify the CFA. + DefCfa { register, offset } => { + self.ctx.set_cfa(CfaRule::RegisterAndOffset { + register, + offset: offset as i64, + }); + } + DefCfaSf { + register, + factored_offset, + } => { + let data_align = self.data_alignment_factor; + self.ctx.set_cfa(CfaRule::RegisterAndOffset { + register, + offset: (Wrapping(factored_offset) * data_align).0, + }); + } + DefCfaRegister { register } => { + if let CfaRule::RegisterAndOffset { + register: ref mut reg, + .. + } = *self.ctx.cfa_mut() + { + *reg = register; + } else { + return Err(Error::CfiInstructionInInvalidContext); + } + } + DefCfaOffset { offset } => { + if let CfaRule::RegisterAndOffset { + offset: ref mut off, + .. + } = *self.ctx.cfa_mut() + { + *off = offset as i64; + } else { + return Err(Error::CfiInstructionInInvalidContext); + } + } + DefCfaOffsetSf { factored_offset } => { + if let CfaRule::RegisterAndOffset { + offset: ref mut off, + .. + } = *self.ctx.cfa_mut() + { + let data_align = self.data_alignment_factor; + *off = (Wrapping(factored_offset) * data_align).0; + } else { + return Err(Error::CfiInstructionInInvalidContext); + } + } + DefCfaExpression { expression } => { + self.ctx.set_cfa(CfaRule::Expression(expression)); + } + + // Instructions that define register rules. + Undefined { register } => { + self.ctx + .set_register_rule(register, RegisterRule::Undefined)?; + } + SameValue { register } => { + self.ctx + .set_register_rule(register, RegisterRule::SameValue)?; + } + Offset { + register, + factored_offset, + } => { + let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor; + self.ctx + .set_register_rule(register, RegisterRule::Offset(offset.0))?; + } + OffsetExtendedSf { + register, + factored_offset, + } => { + let offset = Wrapping(factored_offset) * self.data_alignment_factor; + self.ctx + .set_register_rule(register, RegisterRule::Offset(offset.0))?; + } + ValOffset { + register, + factored_offset, + } => { + let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor; + self.ctx + .set_register_rule(register, RegisterRule::ValOffset(offset.0))?; + } + ValOffsetSf { + register, + factored_offset, + } => { + let offset = Wrapping(factored_offset) * self.data_alignment_factor; + self.ctx + .set_register_rule(register, RegisterRule::ValOffset(offset.0))?; + } + Register { + dest_register, + src_register, + } => { + self.ctx + .set_register_rule(dest_register, RegisterRule::Register(src_register))?; + } + Expression { + register, + expression, + } => { + let expression = RegisterRule::Expression(expression); + self.ctx.set_register_rule(register, expression)?; + } + ValExpression { + register, + expression, + } => { + let expression = RegisterRule::ValExpression(expression); + self.ctx.set_register_rule(register, expression)?; + } + Restore { register } => { + let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) { + rule + } else { + // Can't restore the initial rule when we are + // evaluating the initial rules! + return Err(Error::CfiInstructionInInvalidContext); + }; + + self.ctx.set_register_rule(register, initial_rule)?; + } + + // Row push and pop instructions. + RememberState => { + self.ctx.push_row()?; + } + RestoreState => { + // Pop state while preserving current location. + let start_address = self.ctx.start_address(); + self.ctx.pop_row()?; + self.ctx.set_start_address(start_address); + } + + // GNU Extension. Save the size somewhere so the unwinder can use + // it when restoring IP + ArgsSize { size } => { + self.ctx.row_mut().saved_args_size = size; + } + + // AArch64 extension. + NegateRaState => { + let register = crate::AArch64::RA_SIGN_STATE; + let value = match self.ctx.row().register(register) { + RegisterRule::Undefined => 0, + RegisterRule::Constant(value) => value, + _ => return Err(Error::CfiInstructionInInvalidContext), + }; + self.ctx + .set_register_rule(register, RegisterRule::Constant(value ^ 1))?; + } + + // No operation. + Nop => {} + }; + + Ok(false) + } +} + +// We tend to have very few register rules: usually only a couple. Even if we +// have a rule for every register, on x86-64 with SSE and everything we're +// talking about ~100 rules. So rather than keeping the rules in a hash map, or +// a vector indexed by register number (which would lead to filling lots of +// empty entries), we store them as a vec of (register number, register rule) +// pairs. +// +// Additionally, because every register's default rule is implicitly +// `RegisterRule::Undefined`, we never store a register's rule in this vec if it +// is undefined and save a little bit more space and do a little fewer +// comparisons that way. +// +// The maximum number of rules preallocated by libunwind is 97 for AArch64, 128 +// for ARM, and even 188 for MIPS. It is extremely unlikely to encounter this +// many register rules in practice. +// +// See: +// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-x86_64/dwarf-config.h#L36 +// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32 +// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31 +// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31 +struct RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + rules: ArrayVec, +} + +impl Debug for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RegisterRuleMap") + .field("rules", &self.rules) + .finish() + } +} + +impl Clone for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn clone(&self) -> Self { + Self { + rules: self.rules.clone(), + } + } +} + +impl Default for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn default() -> Self { + RegisterRuleMap { + rules: Default::default(), + } + } +} + +/// # Signal Safe Methods +/// +/// These methods are guaranteed not to allocate, acquire locks, or perform any +/// other signal-unsafe operations. +impl RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn is_default(&self) -> bool { + self.rules.is_empty() + } + + fn get(&self, register: Register) -> RegisterRule { + self.rules + .iter() + .find(|rule| rule.0 == register) + .map(|r| { + debug_assert!(r.1.is_defined()); + r.1.clone() + }) + .unwrap_or(RegisterRule::Undefined) + } + + fn set(&mut self, register: Register, rule: RegisterRule) -> Result<()> { + if !rule.is_defined() { + let idx = self + .rules + .iter() + .enumerate() + .find(|&(_, r)| r.0 == register) + .map(|(i, _)| i); + if let Some(idx) = idx { + self.rules.swap_remove(idx); + } + return Ok(()); + } + + for &mut (reg, ref mut old_rule) in &mut *self.rules { + debug_assert!(old_rule.is_defined()); + if reg == register { + *old_rule = rule; + return Ok(()); + } + } + + self.rules + .try_push((register, rule)) + .map_err(|_| Error::TooManyRegisterRules) + } + + fn iter(&self) -> RegisterRuleIter<'_, T> { + RegisterRuleIter(self.rules.iter()) + } +} + +impl<'a, R, S> FromIterator<&'a (Register, RegisterRule)> for RegisterRuleMap +where + R: 'a + ReaderOffset, + S: UnwindContextStorage, +{ + fn from_iter(iter: T) -> Self + where + T: IntoIterator)>, + { + let iter = iter.into_iter(); + let mut rules = RegisterRuleMap::default(); + for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) { + rules.set(reg, rule.clone()).expect( + "This is only used in tests, impl isn't exposed publicly. + If you trip this, fix your test", + ); + } + rules + } +} + +impl PartialEq for RegisterRuleMap +where + T: ReaderOffset + PartialEq, + S: UnwindContextStorage, +{ + fn eq(&self, rhs: &Self) -> bool { + for &(reg, ref rule) in &*self.rules { + debug_assert!(rule.is_defined()); + if *rule != rhs.get(reg) { + return false; + } + } + + for &(reg, ref rhs_rule) in &*rhs.rules { + debug_assert!(rhs_rule.is_defined()); + if *rhs_rule != self.get(reg) { + return false; + } + } + + true + } +} + +impl Eq for RegisterRuleMap +where + T: ReaderOffset + Eq, + S: UnwindContextStorage, +{ +} + +/// An unordered iterator for register rules. +#[derive(Debug, Clone)] +pub struct RegisterRuleIter<'iter, T>(::core::slice::Iter<'iter, (Register, RegisterRule)>) +where + T: ReaderOffset; + +impl<'iter, T: ReaderOffset> Iterator for RegisterRuleIter<'iter, T> { + type Item = &'iter (Register, RegisterRule); + + fn next(&mut self) -> Option { + self.0.next() + } +} + +/// A row in the virtual unwind table that describes how to find the values of +/// the registers in the *previous* frame for a range of PC addresses. +#[derive(PartialEq, Eq)] +pub struct UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + start_address: u64, + end_address: u64, + saved_args_size: u64, + cfa: CfaRule, + registers: RegisterRuleMap, +} + +impl Debug for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnwindTableRow") + .field("start_address", &self.start_address) + .field("end_address", &self.end_address) + .field("saved_args_size", &self.saved_args_size) + .field("cfa", &self.cfa) + .field("registers", &self.registers) + .finish() + } +} + +impl Clone for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn clone(&self) -> Self { + Self { + start_address: self.start_address, + end_address: self.end_address, + saved_args_size: self.saved_args_size, + cfa: self.cfa.clone(), + registers: self.registers.clone(), + } + } +} + +impl Default for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn default() -> Self { + UnwindTableRow { + start_address: 0, + end_address: 0, + saved_args_size: 0, + cfa: Default::default(), + registers: Default::default(), + } + } +} + +impl UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ + fn is_default(&self) -> bool { + self.start_address == 0 + && self.end_address == 0 + && self.cfa.is_default() + && self.registers.is_default() + } + + /// Get the starting PC address that this row applies to. + pub fn start_address(&self) -> u64 { + self.start_address + } + + /// Get the end PC address where this row's register rules become + /// unapplicable. + /// + /// In other words, this row describes how to recover the last frame's + /// registers for all PCs where `row.start_address() <= PC < + /// row.end_address()`. This row does NOT describe how to recover registers + /// when `PC == row.end_address()`. + pub fn end_address(&self) -> u64 { + self.end_address + } + + /// Return `true` if the given `address` is within this row's address range, + /// `false` otherwise. + pub fn contains(&self, address: u64) -> bool { + self.start_address <= address && address < self.end_address + } + + /// Returns the amount of args currently on the stack. + /// + /// When unwinding, if the personality function requested a change in IP, + /// the SP needs to be adjusted by saved_args_size. + pub fn saved_args_size(&self) -> u64 { + self.saved_args_size + } + + /// Get the canonical frame address (CFA) recovery rule for this row. + pub fn cfa(&self) -> &CfaRule { + &self.cfa + } + + /// Get the register recovery rule for the given register number. + /// + /// The register number mapping is architecture dependent. For example, in + /// the x86-64 ABI the register number mapping is defined in Figure 3.36: + /// + /// > Figure 3.36: DWARF Register Number Mapping + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// > + /// >
Register Name Number Abbreviation
General Purpose Register RAX 0 %rax
General Purpose Register RDX 1 %rdx
General Purpose Register RCX 2 %rcx
General Purpose Register RBX 3 %rbx
General Purpose Register RSI 4 %rsi
General Purpose Register RDI 5 %rdi
General Purpose Register RBP 6 %rbp
Stack Pointer Register RSP 7 %rsp
Extended Integer Registers 8-15 8-15 %r8-%r15
Return Address RA 16
Vector Registers 0–7 17-24 %xmm0–%xmm7
Extended Vector Registers 8–15 25-32 %xmm8–%xmm15
Floating Point Registers 0–7 33-40 %st0–%st7
MMX Registers 0–7 41-48 %mm0–%mm7
Flag Register 49 %rFLAGS
Segment Register ES 50 %es
Segment Register CS 51 %cs
Segment Register SS 52 %ss
Segment Register DS 53 %ds
Segment Register FS 54 %fs
Segment Register GS 55 %gs
Reserved 56-57
FS Base address 58 %fs.base
GS Base address 59 %gs.base
Reserved 60-61
Task Register 62 %tr
LDT Register 63 %ldtr
128-bit Media Control and Status 64 %mxcsr
x87 Control Word 65 %fcw
x87 Status Word 66 %fsw
Upper Vector Registers 16–31 67-82 %xmm16–%xmm31
Reserved 83-117
Vector Mask Registers 0–7 118-125 %k0–%k7
Reserved 126-129
+ pub fn register(&self, register: Register) -> RegisterRule { + self.registers.get(register) + } + + /// Iterate over all defined register `(number, rule)` pairs. + /// + /// The rules are not iterated in any guaranteed order. Any register that + /// does not make an appearance in the iterator implicitly has the rule + /// `RegisterRule::Undefined`. + /// + /// ``` + /// # use gimli::{EndianSlice, LittleEndian, UnwindTableRow}; + /// # fn foo<'input>(unwind_table_row: UnwindTableRow) { + /// for &(register, ref rule) in unwind_table_row.registers() { + /// // ... + /// # drop(register); drop(rule); + /// } + /// # } + /// ``` + pub fn registers(&self) -> RegisterRuleIter<'_, T> { + self.registers.iter() + } +} + +/// The canonical frame address (CFA) recovery rules. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CfaRule { + /// The CFA is given offset from the given register's value. + RegisterAndOffset { + /// The register containing the base value. + register: Register, + /// The offset from the register's base value. + offset: i64, + }, + /// The CFA is obtained by evaluating a DWARF expression program. + Expression(UnwindExpression), +} + +impl Default for CfaRule { + fn default() -> Self { + CfaRule::RegisterAndOffset { + register: Register(0), + offset: 0, + } + } +} + +impl CfaRule { + fn is_default(&self) -> bool { + match *self { + CfaRule::RegisterAndOffset { register, offset } => { + register == Register(0) && offset == 0 + } + _ => false, + } + } +} + +/// An entry in the abstract CFI table that describes how to find the value of a +/// register. +/// +/// "The register columns contain rules that describe whether a given register +/// has been saved and the rule to find the value for the register in the +/// previous frame." +#[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub enum RegisterRule { + /// > A register that has this rule has no recoverable value in the previous + /// > frame. (By convention, it is not preserved by a callee.) + Undefined, + + /// > This register has not been modified from the previous frame. (By + /// > convention, it is preserved by the callee, but the callee has not + /// > modified it.) + SameValue, + + /// "The previous value of this register is saved at the address CFA+N where + /// CFA is the current CFA value and N is a signed offset." + Offset(i64), + + /// "The previous value of this register is the value CFA+N where CFA is the + /// current CFA value and N is a signed offset." + ValOffset(i64), + + /// "The previous value of this register is stored in another register + /// numbered R." + Register(Register), + + /// "The previous value of this register is located at the address produced + /// by executing the DWARF expression." + Expression(UnwindExpression), + + /// "The previous value of this register is the value produced by executing + /// the DWARF expression." + ValExpression(UnwindExpression), + + /// "The rule is defined externally to this specification by the augmenter." + Architectural, + + /// This is a pseudo-register with a constant value. + Constant(u64), +} + +impl RegisterRule { + fn is_defined(&self) -> bool { + !matches!(*self, RegisterRule::Undefined) + } +} + +/// A parsed call frame instruction. +#[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub enum CallFrameInstruction { + // 6.4.2.1 Row Creation Methods + /// > 1. DW_CFA_set_loc + /// > + /// > The DW_CFA_set_loc instruction takes a single operand that represents + /// > a target address. The required action is to create a new table row + /// > using the specified address as the location. All other values in the + /// > new row are initially identical to the current row. The new location + /// > value is always greater than the current one. If the segment_size + /// > field of this FDE's CIE is non- zero, the initial location is preceded + /// > by a segment selector of the given length. + SetLoc { + /// The target address. + address: u64, + }, + + /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and + /// `DW_CFA_advance_loc{1,2,4}`. + /// + /// > 2. DW_CFA_advance_loc + /// > + /// > The DW_CFA_advance instruction takes a single operand (encoded with + /// > the opcode) that represents a constant delta. The required action is + /// > to create a new table row with a location value that is computed by + /// > taking the current entry’s location value and adding the value of + /// > delta * code_alignment_factor. All other values in the new row are + /// > initially identical to the current row. + AdvanceLoc { + /// The delta to be added to the current address. + delta: u32, + }, + + // 6.4.2.2 CFA Definition Methods + /// > 1. DW_CFA_def_cfa + /// > + /// > The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands + /// > representing a register number and a (non-factored) offset. The + /// > required action is to define the current CFA rule to use the provided + /// > register and offset. + DefCfa { + /// The target register's number. + register: Register, + /// The non-factored offset. + offset: u64, + }, + + /// > 2. DW_CFA_def_cfa_sf + /// > + /// > The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned + /// > LEB128 value representing a register number and a signed LEB128 + /// > factored offset. This instruction is identical to DW_CFA_def_cfa + /// > except that the second operand is signed and factored. The resulting + /// > offset is factored_offset * data_alignment_factor. + DefCfaSf { + /// The target register's number. + register: Register, + /// The factored offset. + factored_offset: i64, + }, + + /// > 3. DW_CFA_def_cfa_register + /// > + /// > The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128 + /// > operand representing a register number. The required action is to + /// > define the current CFA rule to use the provided register (but to keep + /// > the old offset). This operation is valid only if the current CFA rule + /// > is defined to use a register and offset. + DefCfaRegister { + /// The target register's number. + register: Register, + }, + + /// > 4. DW_CFA_def_cfa_offset + /// > + /// > The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128 + /// > operand representing a (non-factored) offset. The required action is + /// > to define the current CFA rule to use the provided offset (but to keep + /// > the old register). This operation is valid only if the current CFA + /// > rule is defined to use a register and offset. + DefCfaOffset { + /// The non-factored offset. + offset: u64, + }, + + /// > 5. DW_CFA_def_cfa_offset_sf + /// > + /// > The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand + /// > representing a factored offset. This instruction is identical to + /// > DW_CFA_def_cfa_offset except that the operand is signed and + /// > factored. The resulting offset is factored_offset * + /// > data_alignment_factor. This operation is valid only if the current CFA + /// > rule is defined to use a register and offset. + DefCfaOffsetSf { + /// The factored offset. + factored_offset: i64, + }, + + /// > 6. DW_CFA_def_cfa_expression + /// > + /// > The DW_CFA_def_cfa_expression instruction takes a single operand + /// > encoded as a DW_FORM_exprloc value representing a DWARF + /// > expression. The required action is to establish that expression as the + /// > means by which the current CFA is computed. + DefCfaExpression { + /// The location of the DWARF expression. + expression: UnwindExpression, + }, + + // 6.4.2.3 Register Rule Instructions + /// > 1. DW_CFA_undefined + /// > + /// > The DW_CFA_undefined instruction takes a single unsigned LEB128 + /// > operand that represents a register number. The required action is to + /// > set the rule for the specified register to “undefined.” + Undefined { + /// The target register's number. + register: Register, + }, + + /// > 2. DW_CFA_same_value + /// > + /// > The DW_CFA_same_value instruction takes a single unsigned LEB128 + /// > operand that represents a register number. The required action is to + /// > set the rule for the specified register to “same value.” + SameValue { + /// The target register's number. + register: Register, + }, + + /// The `Offset` instruction represents both `DW_CFA_offset` and + /// `DW_CFA_offset_extended`. + /// + /// > 3. DW_CFA_offset + /// > + /// > The DW_CFA_offset instruction takes two operands: a register number + /// > (encoded with the opcode) and an unsigned LEB128 constant representing + /// > a factored offset. The required action is to change the rule for the + /// > register indicated by the register number to be an offset(N) rule + /// > where the value of N is factored offset * data_alignment_factor. + Offset { + /// The target register's number. + register: Register, + /// The factored offset. + factored_offset: u64, + }, + + /// > 5. DW_CFA_offset_extended_sf + /// > + /// > The DW_CFA_offset_extended_sf instruction takes two operands: an + /// > unsigned LEB128 value representing a register number and a signed + /// > LEB128 factored offset. This instruction is identical to + /// > DW_CFA_offset_extended except that the second operand is signed and + /// > factored. The resulting offset is factored_offset * + /// > data_alignment_factor. + OffsetExtendedSf { + /// The target register's number. + register: Register, + /// The factored offset. + factored_offset: i64, + }, + + /// > 6. DW_CFA_val_offset + /// > + /// > The DW_CFA_val_offset instruction takes two unsigned LEB128 operands + /// > representing a register number and a factored offset. The required + /// > action is to change the rule for the register indicated by the + /// > register number to be a val_offset(N) rule where the value of N is + /// > factored_offset * data_alignment_factor. + ValOffset { + /// The target register's number. + register: Register, + /// The factored offset. + factored_offset: u64, + }, + + /// > 7. DW_CFA_val_offset_sf + /// > + /// > The DW_CFA_val_offset_sf instruction takes two operands: an unsigned + /// > LEB128 value representing a register number and a signed LEB128 + /// > factored offset. This instruction is identical to DW_CFA_val_offset + /// > except that the second operand is signed and factored. The resulting + /// > offset is factored_offset * data_alignment_factor. + ValOffsetSf { + /// The target register's number. + register: Register, + /// The factored offset. + factored_offset: i64, + }, + + /// > 8. DW_CFA_register + /// > + /// > The DW_CFA_register instruction takes two unsigned LEB128 operands + /// > representing register numbers. The required action is to set the rule + /// > for the first register to be register(R) where R is the second + /// > register. + Register { + /// The number of the register whose rule is being changed. + dest_register: Register, + /// The number of the register where the other register's value can be + /// found. + src_register: Register, + }, + + /// > 9. DW_CFA_expression + /// > + /// > The DW_CFA_expression instruction takes two operands: an unsigned + /// > LEB128 value representing a register number, and a DW_FORM_block value + /// > representing a DWARF expression. The required action is to change the + /// > rule for the register indicated by the register number to be an + /// > expression(E) rule where E is the DWARF expression. That is, the DWARF + /// > expression computes the address. The value of the CFA is pushed on the + /// > DWARF evaluation stack prior to execution of the DWARF expression. + Expression { + /// The target register's number. + register: Register, + /// The location of the DWARF expression. + expression: UnwindExpression, + }, + + /// > 10. DW_CFA_val_expression + /// > + /// > The DW_CFA_val_expression instruction takes two operands: an unsigned + /// > LEB128 value representing a register number, and a DW_FORM_block value + /// > representing a DWARF expression. The required action is to change the + /// > rule for the register indicated by the register number to be a + /// > val_expression(E) rule where E is the DWARF expression. That is, the + /// > DWARF expression computes the value of the given register. The value + /// > of the CFA is pushed on the DWARF evaluation stack prior to execution + /// > of the DWARF expression. + ValExpression { + /// The target register's number. + register: Register, + /// The location of the DWARF expression. + expression: UnwindExpression, + }, + + /// The `Restore` instruction represents both `DW_CFA_restore` and + /// `DW_CFA_restore_extended`. + /// + /// > 11. DW_CFA_restore + /// > + /// > The DW_CFA_restore instruction takes a single operand (encoded with + /// > the opcode) that represents a register number. The required action is + /// > to change the rule for the indicated register to the rule assigned it + /// > by the initial_instructions in the CIE. + Restore { + /// The register to be reset. + register: Register, + }, + + // 6.4.2.4 Row State Instructions + /// > 1. DW_CFA_remember_state + /// > + /// > The DW_CFA_remember_state instruction takes no operands. The required + /// > action is to push the set of rules for every register onto an implicit + /// > stack. + RememberState, + + /// > 2. DW_CFA_restore_state + /// > + /// > The DW_CFA_restore_state instruction takes no operands. The required + /// > action is to pop the set of rules off the implicit stack and place + /// > them in the current row. + RestoreState, + + /// > DW_CFA_GNU_args_size + /// > + /// > GNU Extension + /// > + /// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand + /// > representing an argument size. This instruction specifies the total of + /// > the size of the arguments which have been pushed onto the stack. + ArgsSize { + /// The size of the arguments which have been pushed onto the stack + size: u64, + }, + + /// > DW_CFA_AARCH64_negate_ra_state + /// > + /// > AArch64 Extension + /// > + /// > The DW_CFA_AARCH64_negate_ra_state operation negates bit 0 of the + /// > RA_SIGN_STATE pseudo-register. It does not take any operands. The + /// > DW_CFA_AARCH64_negate_ra_state must not be mixed with other DWARF Register + /// > Rule Instructions on the RA_SIGN_STATE pseudo-register in one Common + /// > Information Entry (CIE) and Frame Descriptor Entry (FDE) program sequence. + NegateRaState, + + // 6.4.2.5 Padding Instruction + /// > 1. DW_CFA_nop + /// > + /// > The DW_CFA_nop instruction has no operands and no required actions. It + /// > is used as padding to make a CIE or FDE an appropriate size. + Nop, +} + +const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000; +const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK; + +impl CallFrameInstruction { + fn parse>( + input: &mut R, + address_encoding: Option, + parameters: &PointerEncodingParameters<'_, R>, + vendor: Vendor, + ) -> Result> { + let instruction = input.read_u8()?; + let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK; + + if high_bits == constants::DW_CFA_advance_loc.0 { + let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK; + return Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(delta), + }); + } + + if high_bits == constants::DW_CFA_offset.0 { + let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); + let offset = input.read_uleb128()?; + return Ok(CallFrameInstruction::Offset { + register, + factored_offset: offset, + }); + } + + if high_bits == constants::DW_CFA_restore.0 { + let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); + return Ok(CallFrameInstruction::Restore { register }); + } + + debug_assert_eq!(high_bits, 0); + let instruction = constants::DwCfa(instruction); + + match instruction { + constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop), + + constants::DW_CFA_set_loc => { + let address = if let Some(encoding) = address_encoding { + parse_encoded_pointer(encoding, parameters, input)?.direct()? + } else { + input.read_address(parameters.address_size)? + }; + Ok(CallFrameInstruction::SetLoc { address }) + } + + constants::DW_CFA_advance_loc1 => { + let delta = input.read_u8()?; + Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(delta), + }) + } + + constants::DW_CFA_advance_loc2 => { + let delta = input.read_u16()?; + Ok(CallFrameInstruction::AdvanceLoc { + delta: u32::from(delta), + }) + } + + constants::DW_CFA_advance_loc4 => { + let delta = input.read_u32()?; + Ok(CallFrameInstruction::AdvanceLoc { delta }) + } + + constants::DW_CFA_offset_extended => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_uleb128()?; + Ok(CallFrameInstruction::Offset { + register, + factored_offset: offset, + }) + } + + constants::DW_CFA_restore_extended => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + Ok(CallFrameInstruction::Restore { register }) + } + + constants::DW_CFA_undefined => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + Ok(CallFrameInstruction::Undefined { register }) + } + + constants::DW_CFA_same_value => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + Ok(CallFrameInstruction::SameValue { register }) + } + + constants::DW_CFA_register => { + let dest = input.read_uleb128().and_then(Register::from_u64)?; + let src = input.read_uleb128().and_then(Register::from_u64)?; + Ok(CallFrameInstruction::Register { + dest_register: dest, + src_register: src, + }) + } + + constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState), + + constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState), + + constants::DW_CFA_def_cfa => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_uleb128()?; + Ok(CallFrameInstruction::DefCfa { register, offset }) + } + + constants::DW_CFA_def_cfa_register => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + Ok(CallFrameInstruction::DefCfaRegister { register }) + } + + constants::DW_CFA_def_cfa_offset => { + let offset = input.read_uleb128()?; + Ok(CallFrameInstruction::DefCfaOffset { offset }) + } + + constants::DW_CFA_def_cfa_expression => { + let length = input.read_uleb128().and_then(R::Offset::from_u64)?; + let offset = input.offset_from(parameters.section); + input.skip(length)?; + Ok(CallFrameInstruction::DefCfaExpression { + expression: UnwindExpression { offset, length }, + }) + } + + constants::DW_CFA_expression => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let length = input.read_uleb128().and_then(R::Offset::from_u64)?; + let offset = input.offset_from(parameters.section); + input.skip(length)?; + Ok(CallFrameInstruction::Expression { + register, + expression: UnwindExpression { offset, length }, + }) + } + + constants::DW_CFA_offset_extended_sf => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_sleb128()?; + Ok(CallFrameInstruction::OffsetExtendedSf { + register, + factored_offset: offset, + }) + } + + constants::DW_CFA_def_cfa_sf => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_sleb128()?; + Ok(CallFrameInstruction::DefCfaSf { + register, + factored_offset: offset, + }) + } + + constants::DW_CFA_def_cfa_offset_sf => { + let offset = input.read_sleb128()?; + Ok(CallFrameInstruction::DefCfaOffsetSf { + factored_offset: offset, + }) + } + + constants::DW_CFA_val_offset => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_uleb128()?; + Ok(CallFrameInstruction::ValOffset { + register, + factored_offset: offset, + }) + } + + constants::DW_CFA_val_offset_sf => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let offset = input.read_sleb128()?; + Ok(CallFrameInstruction::ValOffsetSf { + register, + factored_offset: offset, + }) + } + + constants::DW_CFA_val_expression => { + let register = input.read_uleb128().and_then(Register::from_u64)?; + let length = input.read_uleb128().and_then(R::Offset::from_u64)?; + let offset = input.offset_from(parameters.section); + input.skip(length)?; + Ok(CallFrameInstruction::ValExpression { + register, + expression: UnwindExpression { offset, length }, + }) + } + + constants::DW_CFA_GNU_args_size => { + let size = input.read_uleb128()?; + Ok(CallFrameInstruction::ArgsSize { size }) + } + + constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => { + Ok(CallFrameInstruction::NegateRaState) + } + + otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)), + } + } +} + +/// A lazy iterator parsing call frame instructions. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Clone, Debug)] +pub struct CallFrameInstructionIter<'a, R: Reader> { + input: R, + address_encoding: Option, + parameters: PointerEncodingParameters<'a, R>, + vendor: Vendor, +} + +impl<'a, R: Reader> CallFrameInstructionIter<'a, R> { + /// Parse the next call frame instruction. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + match CallFrameInstruction::parse( + &mut self.input, + self.address_encoding, + &self.parameters, + self.vendor, + ) { + Ok(instruction) => Ok(Some(instruction)), + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> { + type Item = CallFrameInstruction; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + CallFrameInstructionIter::next(self) + } +} + +/// The location of a DWARF expression within an unwind section. +/// +/// This is stored as an offset and length within the section instead of as a +/// `Reader` to avoid lifetime issues when reusing [`UnwindContext`]. +/// +/// # Example +/// ``` +/// # use gimli::{EhFrame, EndianSlice, NativeEndian, Error, FrameDescriptionEntry, UnwindExpression, EvaluationResult}; +/// # fn foo() -> Result<(), Error> { +/// # let eh_frame: EhFrame> = unreachable!(); +/// # let fde: FrameDescriptionEntry> = unimplemented!(); +/// # let unwind_expression: UnwindExpression<_> = unimplemented!(); +/// let expression = unwind_expression.get(&eh_frame)?; +/// let mut evaluation = expression.evaluation(fde.cie().encoding()); +/// let mut result = evaluation.evaluate()?; +/// loop { +/// match result { +/// EvaluationResult::Complete => break, +/// // Provide information to the evaluation. +/// _ => { unimplemented!()} +/// } +/// } +/// let value = evaluation.value_result(); +/// # Ok(()) +/// # } +/// ``` +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct UnwindExpression { + /// The offset of the expression within the section. + pub offset: T, + /// The length of the expression. + pub length: T, +} + +impl UnwindExpression { + /// Get the expression from the section. + /// + /// The offset and length were previously validated when the + /// `UnwindExpression` was created, so this should not fail. + pub fn get(&self, section: &S) -> Result> + where + R: Reader, + S: UnwindSection, + { + let input = &mut section.section().clone(); + input.skip(self.offset)?; + let data = input.split(self.length)?; + Ok(Expression(data)) + } +} + +/// Parse a `DW_EH_PE_*` pointer encoding. +#[doc(hidden)] +#[inline] +fn parse_pointer_encoding(input: &mut R) -> Result { + let eh_pe = input.read_u8()?; + let eh_pe = constants::DwEhPe(eh_pe); + + if eh_pe.is_valid_encoding() { + Ok(eh_pe) + } else { + Err(Error::UnknownPointerEncoding(eh_pe)) + } +} + +/// A decoded pointer. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Pointer { + /// This value is the decoded pointer value. + Direct(u64), + + /// This value is *not* the pointer value, but points to the address of + /// where the real pointer value lives. In other words, deref this pointer + /// to get the real pointer value. + /// + /// Chase this pointer at your own risk: do you trust the DWARF data it came + /// from? + Indirect(u64), +} + +impl Default for Pointer { + #[inline] + fn default() -> Self { + Pointer::Direct(0) + } +} + +impl Pointer { + #[inline] + fn new(encoding: constants::DwEhPe, address: u64) -> Pointer { + if encoding.is_indirect() { + Pointer::Indirect(address) + } else { + Pointer::Direct(address) + } + } + + /// Return the direct pointer value. + #[inline] + pub fn direct(self) -> Result { + match self { + Pointer::Direct(p) => Ok(p), + Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding), + } + } + + /// Return the pointer value, discarding indirectness information. + #[inline] + pub fn pointer(self) -> u64 { + match self { + Pointer::Direct(p) | Pointer::Indirect(p) => p, + } + } +} + +#[derive(Clone, Debug)] +struct PointerEncodingParameters<'a, R: Reader> { + bases: &'a SectionBaseAddresses, + func_base: Option, + address_size: u8, + section: &'a R, +} + +fn parse_encoded_pointer( + encoding: constants::DwEhPe, + parameters: &PointerEncodingParameters<'_, R>, + input: &mut R, +) -> Result { + // TODO: check this once only in parse_pointer_encoding + if !encoding.is_valid_encoding() { + return Err(Error::UnknownPointerEncoding(encoding)); + } + + if encoding == constants::DW_EH_PE_omit { + return Err(Error::CannotParseOmitPointerEncoding); + } + + let base = match encoding.application() { + constants::DW_EH_PE_absptr => 0, + constants::DW_EH_PE_pcrel => { + if let Some(section_base) = parameters.bases.section { + let offset_from_section = input.offset_from(parameters.section); + section_base + .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size) + } else { + return Err(Error::PcRelativePointerButSectionBaseIsUndefined); + } + } + constants::DW_EH_PE_textrel => { + if let Some(text) = parameters.bases.text { + text + } else { + return Err(Error::TextRelativePointerButTextBaseIsUndefined); + } + } + constants::DW_EH_PE_datarel => { + if let Some(data) = parameters.bases.data { + data + } else { + return Err(Error::DataRelativePointerButDataBaseIsUndefined); + } + } + constants::DW_EH_PE_funcrel => { + if let Some(func) = parameters.func_base { + func + } else { + return Err(Error::FuncRelativePointerInBadContext); + } + } + constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding), + _ => unreachable!(), + }; + + let offset = parse_encoded_value(encoding, parameters, input)?; + Ok(Pointer::new( + encoding, + base.wrapping_add_sized(offset, parameters.address_size), + )) +} + +fn parse_encoded_value( + encoding: constants::DwEhPe, + parameters: &PointerEncodingParameters<'_, R>, + input: &mut R, +) -> Result { + match encoding.format() { + // Unsigned variants. + constants::DW_EH_PE_absptr => input.read_address(parameters.address_size), + constants::DW_EH_PE_uleb128 => input.read_uleb128(), + constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from), + constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from), + constants::DW_EH_PE_udata8 => input.read_u64(), + + // Signed variants. Here we sign extend the values (happens by + // default when casting a signed integer to a larger range integer + // in Rust), return them as u64, and rely on wrapping addition to do + // the right thing when adding these offsets to their bases. + constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64), + constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64), + constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64), + constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64), + + // That was all of the valid encoding formats. + _ => unreachable!(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext}; + use crate::common::Format; + use crate::constants; + use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian}; + use crate::read::{ + EndianSlice, Error, Pointer, ReaderOffsetId, Result, Section as ReadSection, + }; + use crate::test_util::GimliSectionMethods; + use alloc::boxed::Box; + use alloc::vec::Vec; + use core::marker::PhantomData; + use core::mem; + use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum}; + + // Ensure each test tries to read the same section kind that it wrote. + #[derive(Clone, Copy)] + struct SectionKind

::function_alignment() + } + + fn has_native_fma(&self) -> bool { + false + } + + fn has_x86_blendv_lowering(&self, _ty: ir::Type) -> bool { + false + } + + fn has_x86_pshufb_lowering(&self) -> bool { + false + } + + fn has_x86_pmulhrsw_lowering(&self) -> bool { + false + } + + fn has_x86_pmaddubsw_lowering(&self) -> bool { + false + } +} + +/// Create a new Pulley ISA builder. +pub fn isa_builder(triple: Triple) -> IsaBuilder { + let constructor = match triple.architecture { + Architecture::Pulley32 | Architecture::Pulley32be => isa_constructor_32, + Architecture::Pulley64 | Architecture::Pulley64be => isa_constructor_64, + other => panic!("unexpected architecture {other:?}"), + }; + IsaBuilder { + triple, + setup: self::settings::builder(), + constructor, + } +} + +fn isa_constructor_32( + triple: Triple, + shared_flags: Flags, + builder: &shared_settings::Builder, +) -> CodegenResult { + use crate::settings::Configurable; + let mut builder = builder.clone(); + builder.set("pointer_width", "pointer32").unwrap(); + if triple.endianness().unwrap() == target_lexicon::Endianness::Big { + builder.enable("big_endian").unwrap(); + } + let isa_flags = PulleyFlags::new(&shared_flags, &builder); + + let backend = + PulleyBackend::::new_with_flags(triple, shared_flags, isa_flags); + Ok(backend.wrapped()) +} + +fn isa_constructor_64( + triple: Triple, + shared_flags: Flags, + builder: &shared_settings::Builder, +) -> CodegenResult { + use crate::settings::Configurable; + let mut builder = builder.clone(); + builder.set("pointer_width", "pointer64").unwrap(); + if triple.endianness().unwrap() == target_lexicon::Endianness::Big { + builder.enable("big_endian").unwrap(); + } + let isa_flags = PulleyFlags::new(&shared_flags, &builder); + + let backend = + PulleyBackend::::new_with_flags(triple, shared_flags, isa_flags); + Ok(backend.wrapped()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/settings.rs b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/settings.rs new file mode 100644 index 00000000000000..937384db14686c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/pulley_shared/settings.rs @@ -0,0 +1,16 @@ +//! Pulley settings. + +// The generated settings include some dead code. +#![allow(dead_code)] + +use crate::{ + machinst::IsaFlags, + settings::{self, detail, Builder, Value}, +}; +use core::fmt; + +// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a +// public `Flags` struct with an impl for all of the settings defined in +include!(concat!(env!("OUT_DIR"), "/settings-pulley.rs")); + +impl IsaFlags for Flags {} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/abi.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/abi.rs new file mode 100644 index 00000000000000..6098769c017ea3 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/abi.rs @@ -0,0 +1,995 @@ +//! Implementation of a standard Riscv64 ABI. + +use crate::ir; +use crate::ir::types::*; + +use crate::isa; + +use crate::isa::riscv64::{inst::*, Riscv64Backend}; +use crate::isa::CallConv; +use crate::machinst::*; + +use crate::ir::LibCall; +use crate::ir::Signature; +use crate::isa::riscv64::settings::Flags as RiscvFlags; +use crate::isa::unwind::UnwindInst; +use crate::settings; +use crate::CodegenResult; +use alloc::boxed::Box; +use alloc::vec::Vec; +use regalloc2::{MachineEnv, PReg, PRegSet}; + +use smallvec::{smallvec, SmallVec}; +use std::borrow::ToOwned; +use std::sync::OnceLock; + +/// Support for the Riscv64 ABI from the callee side (within a function body). +pub(crate) type Riscv64Callee = Callee; + +/// Support for the Riscv64 ABI from the caller side (at a callsite). +pub(crate) type Riscv64ABICallSite = CallSite; + +/// Riscv64-specific ABI behavior. This struct just serves as an implementation +/// point for the trait; it is never actually instantiated. +pub struct Riscv64MachineDeps; + +impl IsaFlags for RiscvFlags {} + +impl RiscvFlags { + pub(crate) fn min_vec_reg_size(&self) -> u64 { + let entries = [ + (self.has_zvl65536b(), 65536), + (self.has_zvl32768b(), 32768), + (self.has_zvl16384b(), 16384), + (self.has_zvl8192b(), 8192), + (self.has_zvl4096b(), 4096), + (self.has_zvl2048b(), 2048), + (self.has_zvl1024b(), 1024), + (self.has_zvl512b(), 512), + (self.has_zvl256b(), 256), + // In order to claim the Application Profile V extension, a minimum + // register size of 128 is required. i.e. V implies Zvl128b. + (self.has_v(), 128), + (self.has_zvl128b(), 128), + (self.has_zvl64b(), 64), + (self.has_zvl32b(), 32), + ]; + + for (has_flag, size) in entries.into_iter() { + if !has_flag { + continue; + } + + // Due to a limitation in regalloc2, we can't support types + // larger than 1024 bytes. So limit that here. + return std::cmp::min(size, 1024); + } + + return 0; + } +} + +impl ABIMachineSpec for Riscv64MachineDeps { + type I = Inst; + type F = RiscvFlags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic: for now, 128 MB. + const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024; + + fn word_bits() -> u32 { + 64 + } + + /// Return required stack alignment in bytes. + fn stack_align(_call_conv: isa::CallConv) -> u32 { + 16 + } + + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + mut args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)> { + assert_ne!( + call_conv, + isa::CallConv::Winch, + "riscv64 does not support the 'winch' calling convention yet" + ); + + // All registers that can be used as parameters or rets. + // both start and end are included. + let (x_start, x_end, f_start, f_end) = match args_or_rets { + ArgsOrRets::Args => (10, 17, 10, 17), + ArgsOrRets::Rets => (10, 11, 10, 11), + }; + let mut next_x_reg = x_start; + let mut next_f_reg = f_start; + // Stack space. + let mut next_stack: u32 = 0; + + let ret_area_ptr = if add_ret_area_ptr { + assert!(ArgsOrRets::Args == args_or_rets); + next_x_reg += 1; + Some(ABIArg::reg( + x_reg(x_start).to_real_reg().unwrap(), + I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } else { + None + }; + + for param in params { + if let ir::ArgumentPurpose::StructArgument(_) = param.purpose { + panic!( + "StructArgument parameters are not supported on riscv64. \ + Use regular pointer arguments instead." + ); + } + + // Find regclass(es) of the register(s) used to store a value of this type. + let (rcs, reg_tys) = Inst::rc_for_type(param.value_type)?; + let mut slots = ABIArgSlotVec::new(); + for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) { + let next_reg = if (next_x_reg <= x_end) && *rc == RegClass::Int { + let x = Some(x_reg(next_x_reg)); + next_x_reg += 1; + x + } else if (next_f_reg <= f_end) && *rc == RegClass::Float { + let x = Some(f_reg(next_f_reg)); + next_f_reg += 1; + x + } else { + None + }; + if let Some(reg) = next_reg { + slots.push(ABIArgSlot::Reg { + reg: reg.to_real_reg().unwrap(), + ty: *reg_ty, + extension: param.extension, + }); + } else { + if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() { + return Err(crate::CodegenError::Unsupported( + "Too many return values to fit in registers. \ + Use a StructReturn argument instead. (#9510)" + .to_owned(), + )); + } + + // Compute size and 16-byte stack alignment happens + // separately after all args. + let size = reg_ty.bits() / 8; + let size = std::cmp::max(size, 8); + // Align. + debug_assert!(size.is_power_of_two()); + next_stack = align_to(next_stack, size); + slots.push(ABIArgSlot::Stack { + offset: next_stack as i64, + ty: *reg_ty, + extension: param.extension, + }); + next_stack += size; + } + } + args.push(ABIArg::Slots { + slots, + purpose: param.purpose, + }); + } + let pos = if let Some(ret_area_ptr) = ret_area_ptr { + args.push_non_formal(ret_area_ptr); + Some(args.args().len() - 1) + } else { + None + }; + + next_stack = align_to(next_stack, Self::stack_align(call_conv)); + + Ok((next_stack, pos)) + } + + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Inst { + Inst::gen_load(into_reg, mem.into(), ty, MemFlags::trusted()) + } + + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_store(mem.into(), from_reg, ty, MemFlags::trusted()) + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_move(to_reg, from_reg, ty) + } + + fn gen_extend( + to_reg: Writable, + from_reg: Reg, + signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Inst { + assert!(from_bits < to_bits); + Inst::Extend { + rd: to_reg, + rn: from_reg, + signed, + from_bits, + to_bits, + } + } + + fn get_ext_mode( + _call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension { + specified + } + + fn gen_args(args: Vec) -> Inst { + Inst::Args { args } + } + + fn gen_rets(rets: Vec) -> Inst { + Inst::Rets { rets } + } + + fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg { + spilltmp_reg() + } + + fn gen_add_imm( + _call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec { + let mut insts = SmallInstVec::new(); + if let Some(imm12) = Imm12::maybe_from_u64(imm as u64) { + insts.push(Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: into_reg, + rs: from_reg, + imm12, + }); + } else { + insts.extend(Inst::load_constant_u32( + writable_spilltmp_reg2(), + imm as u64, + )); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: into_reg, + rs1: spilltmp_reg2(), + rs2: from_reg, + }); + } + insts + } + + fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { + let mut insts = SmallVec::new(); + insts.push(Inst::TrapIf { + cc: IntCC::UnsignedLessThan, + rs1: stack_reg(), + rs2: limit_reg, + trap_code: ir::TrapCode::STACK_OVERFLOW, + }); + insts + } + + fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable) -> Inst { + Inst::LoadAddr { + rd: into_reg, + mem: mem.into(), + } + } + + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Inst { + let mem = AMode::RegOffset(base, offset as i64); + Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()) + } + + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst { + let mem = AMode::RegOffset(base, offset as i64); + Inst::gen_store(mem, from_reg, ty, MemFlags::trusted()) + } + + fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { + let mut insts = SmallVec::new(); + + if amount == 0 { + return insts; + } + + if let Some(imm) = Imm12::maybe_from_i64(amount as i64) { + insts.push(Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: writable_stack_reg(), + rs: stack_reg(), + imm12: imm, + }) + } else { + let tmp = writable_spilltmp_reg(); + insts.extend(Inst::load_constant_u64(tmp, amount as i64 as u64)); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: writable_stack_reg(), + rs1: stack_reg(), + rs2: tmp.to_reg(), + }); + } + + insts + } + + fn gen_prologue_frame_setup( + _call_conv: isa::CallConv, + flags: &settings::Flags, + _isa_flags: &RiscvFlags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + + if frame_layout.setup_area_size > 0 { + // add sp,sp,-16 ;; alloc stack space for fp. + // sd ra,8(sp) ;; save ra. + // sd fp,0(sp) ;; store old fp. + // mv fp,sp ;; set fp to sp. + insts.extend(Self::gen_sp_reg_adjust(-16)); + insts.push(Inst::gen_store( + AMode::SPOffset(8), + link_reg(), + I64, + MemFlags::trusted(), + )); + insts.push(Inst::gen_store( + AMode::SPOffset(0), + fp_reg(), + I64, + MemFlags::trusted(), + )); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::PushFrameRegs { + offset_upward_to_caller_sp: frame_layout.setup_area_size, + }, + }); + } + insts.push(Inst::Mov { + rd: writable_fp_reg(), + rm: stack_reg(), + ty: I64, + }); + } + + insts + } + /// reverse of gen_prologue_frame_setup. + fn gen_epilogue_frame_restore( + call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &RiscvFlags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + + if frame_layout.setup_area_size > 0 { + insts.push(Inst::gen_load( + writable_link_reg(), + AMode::SPOffset(8), + I64, + MemFlags::trusted(), + )); + insts.push(Inst::gen_load( + writable_fp_reg(), + AMode::SPOffset(0), + I64, + MemFlags::trusted(), + )); + insts.extend(Self::gen_sp_reg_adjust(16)); + } + + if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 { + insts.extend(Self::gen_sp_reg_adjust( + frame_layout.tail_args_size.try_into().unwrap(), + )); + } + + insts + } + + fn gen_return( + _call_conv: isa::CallConv, + _isa_flags: &RiscvFlags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + smallvec![Inst::Ret {}] + } + + fn gen_probestack(insts: &mut SmallInstVec, frame_size: u32) { + insts.extend(Inst::load_constant_u32(writable_a0(), frame_size as u64)); + let mut info = CallInfo::empty( + ExternalName::LibCall(LibCall::Probestack), + CallConv::SystemV, + ); + info.uses.push(CallArgPair { + vreg: a0(), + preg: a0(), + }); + insts.push(Inst::Call { + info: Box::new(info), + }); + } + + fn gen_clobber_save( + _call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + let setup_frame = frame_layout.setup_area_size > 0; + + let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size; + if incoming_args_diff > 0 { + // Decrement SP by the amount of additional incoming argument space we need + insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32))); + + if setup_frame { + // Write the lr position on the stack again, as it hasn't changed since it was + // pushed in `gen_prologue_frame_setup` + insts.push(Inst::gen_store( + AMode::SPOffset(8), + link_reg(), + I64, + MemFlags::trusted(), + )); + insts.push(Inst::gen_load( + writable_fp_reg(), + AMode::SPOffset(i64::from(incoming_args_diff)), + I64, + MemFlags::trusted(), + )); + insts.push(Inst::gen_store( + AMode::SPOffset(0), + fp_reg(), + I64, + MemFlags::trusted(), + )); + + // Finally, sync the frame pointer with SP + insts.push(Inst::gen_move(writable_fp_reg(), stack_reg(), I64)); + } + } + + if flags.unwind_info() && setup_frame { + // The *unwind* frame (but not the actual frame) starts at the + // clobbers, just below the saved FP/LR pair. + insts.push(Inst::Unwind { + inst: UnwindInst::DefineNewFrame { + offset_downward_to_clobbers: frame_layout.clobber_size, + offset_upward_to_caller_sp: frame_layout.setup_area_size, + }, + }); + } + + // Adjust the stack pointer downward for clobbers, the function fixed + // frame (spillslots and storage slots), and outgoing arguments. + let stack_size = frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size; + + // Store each clobbered register in order at offsets from SP, + // placing them above the fixed frame slots. + if stack_size > 0 { + insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32))); + + let mut cur_offset = 8; + for reg in &frame_layout.clobbered_callee_saves { + let r_reg = reg.to_reg(); + let ty = match r_reg.class() { + RegClass::Int => I64, + RegClass::Float => F64, + RegClass::Vector => unimplemented!("Vector Clobber Saves"), + }; + insts.push(Inst::gen_store( + AMode::SPOffset((stack_size - cur_offset) as i64), + Reg::from(reg.to_reg()), + ty, + MemFlags::trusted(), + )); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: frame_layout.clobber_size - cur_offset, + reg: r_reg, + }, + }); + } + + cur_offset += 8 + } + } + insts + } + + fn gen_clobber_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + + let stack_size = frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size; + + let mut cur_offset = 8; + for reg in &frame_layout.clobbered_callee_saves { + let rreg = reg.to_reg(); + let ty = match rreg.class() { + RegClass::Int => I64, + RegClass::Float => F64, + RegClass::Vector => unimplemented!("Vector Clobber Restores"), + }; + insts.push(Inst::gen_load( + reg.map(Reg::from), + AMode::SPOffset(i64::from(stack_size - cur_offset)), + ty, + MemFlags::trusted(), + )); + cur_offset += 8 + } + + if stack_size > 0 { + insts.extend(Self::gen_sp_reg_adjust(stack_size as i32)); + } + + insts + } + + fn gen_call(dest: &CallDest, tmp: Writable, info: CallInfo<()>) -> SmallVec<[Self::I; 2]> { + let mut insts = SmallVec::new(); + match &dest { + &CallDest::ExtName(ref name, RelocDistance::Near) => { + let info = Box::new(info.map(|()| name.clone())); + insts.push(Inst::Call { info }) + } + &CallDest::ExtName(ref name, RelocDistance::Far) => { + insts.push(Inst::LoadExtName { + rd: tmp, + name: Box::new(name.clone()), + offset: 0, + }); + let info = Box::new(info.map(|()| tmp.to_reg())); + insts.push(Inst::CallInd { info }); + } + &CallDest::Reg(reg) => { + let info = Box::new(info.map(|()| *reg)); + insts.push(Inst::CallInd { info }); + } + } + insts + } + + fn gen_memcpy Writable>( + call_conv: isa::CallConv, + dst: Reg, + src: Reg, + size: usize, + mut alloc_tmp: F, + ) -> SmallVec<[Self::I; 8]> { + let mut insts = SmallVec::new(); + let arg0 = Writable::from_reg(x_reg(10)); + let arg1 = Writable::from_reg(x_reg(11)); + let arg2 = Writable::from_reg(x_reg(12)); + let tmp = alloc_tmp(Self::word_type()); + insts.extend(Inst::load_constant_u64(tmp, size as u64).into_iter()); + insts.push(Inst::Call { + info: Box::new(CallInfo { + dest: ExternalName::LibCall(LibCall::Memcpy), + uses: smallvec![ + CallArgPair { + vreg: dst, + preg: arg0.to_reg() + }, + CallArgPair { + vreg: src, + preg: arg1.to_reg() + }, + CallArgPair { + vreg: tmp.to_reg(), + preg: arg2.to_reg() + } + ], + defs: smallvec![], + clobbers: Self::get_regs_clobbered_by_call(call_conv), + caller_conv: call_conv, + callee_conv: call_conv, + callee_pop_size: 0, + }), + }); + insts + } + + fn get_number_of_spillslots_for_value( + rc: RegClass, + _target_vector_bytes: u32, + isa_flags: &RiscvFlags, + ) -> u32 { + // We allocate in terms of 8-byte slots. + match rc { + RegClass::Int => 1, + RegClass::Float => 1, + RegClass::Vector => (isa_flags.min_vec_reg_size() / 8) as u32, + } + } + + fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(create_reg_environment) + } + + fn get_regs_clobbered_by_call(_call_conv_of_callee: isa::CallConv) -> PRegSet { + DEFAULT_CLOBBERS + } + + fn compute_frame_layout( + _call_conv: isa::CallConv, + flags: &settings::Flags, + _sig: &Signature, + regs: &[Writable], + is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + outgoing_args_size: u32, + ) -> FrameLayout { + let mut regs: Vec> = regs + .iter() + .cloned() + .filter(|r| DEFAULT_CALLEE_SAVES.contains(r.to_reg().into())) + .collect(); + + regs.sort_unstable(); + + // Compute clobber size. + let clobber_size = compute_clobber_size(®s); + + // Compute linkage frame size. + let setup_area_size = if flags.preserve_frame_pointers() + || !is_leaf + // The function arguments that are passed on the stack are addressed + // relative to the Frame Pointer. + || incoming_args_size > 0 + || clobber_size > 0 + || fixed_frame_storage_size > 0 + { + 16 // FP, LR + } else { + 0 + }; + + // Return FrameLayout structure. + FrameLayout { + incoming_args_size, + tail_args_size, + setup_area_size, + clobber_size, + fixed_frame_storage_size, + outgoing_args_size, + clobbered_callee_saves: regs, + } + } + + fn gen_inline_probestack( + insts: &mut SmallInstVec, + _call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ) { + // Unroll at most n consecutive probes, before falling back to using a loop + const PROBE_MAX_UNROLL: u32 = 3; + + // Calculate how many probes we need to perform. Round down, as we only + // need to probe whole guard_size regions we'd otherwise skip over. + let probe_count = frame_size / guard_size; + if probe_count == 0 { + // No probe necessary + return; + } + + // Must be a caller-saved register that is not an argument. + let tmp = Writable::from_reg(x_reg(28)); // t3 + + if probe_count <= PROBE_MAX_UNROLL { + Self::gen_probestack_unroll(insts, tmp, guard_size, probe_count) + } else { + insts.push(Inst::StackProbeLoop { + guard_size, + probe_count, + tmp, + }); + } + } +} + +impl Riscv64ABICallSite { + pub fn emit_return_call( + mut self, + ctx: &mut Lower, + args: isle::ValueSlice, + _backend: &Riscv64Backend, + ) { + let new_stack_arg_size = + u32::try_from(self.sig(ctx.sigs()).sized_stack_arg_space()).unwrap(); + + ctx.abi_mut().accumulate_tail_args_size(new_stack_arg_size); + + // Put all arguments in registers and stack slots (within that newly + // allocated stack space). + self.emit_args(ctx, args); + self.emit_stack_ret_arg_for_tail_call(ctx); + + let dest = self.dest().clone(); + let uses = self.take_uses(); + + match dest { + CallDest::ExtName(name, RelocDistance::Near) => { + let info = Box::new(ReturnCallInfo { + dest: name, + uses, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCall { info }); + } + CallDest::ExtName(name, RelocDistance::Far) => { + let callee = ctx.alloc_tmp(ir::types::I64).only_reg().unwrap(); + ctx.emit(Inst::LoadExtName { + rd: callee, + name: Box::new(name), + offset: 0, + }); + let info = Box::new(ReturnCallInfo { + dest: callee.to_reg(), + uses, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallInd { info }); + } + CallDest::Reg(callee) => { + let info = Box::new(ReturnCallInfo { + dest: callee, + uses, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallInd { info }); + } + } + } +} + +// NOTE: no V regs are callee save. +const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty() + // X Regs + .with(px_reg(2)) + .with(px_reg(8)) + .with(px_reg(9)) + .with(px_reg(18)) + .with(px_reg(19)) + .with(px_reg(20)) + .with(px_reg(21)) + .with(px_reg(22)) + .with(px_reg(23)) + .with(px_reg(24)) + .with(px_reg(25)) + .with(px_reg(26)) + .with(px_reg(27)) + // F Regs + .with(pf_reg(8)) + .with(pf_reg(18)) + .with(pf_reg(19)) + .with(pf_reg(20)) + .with(pf_reg(21)) + .with(pf_reg(22)) + .with(pf_reg(23)) + .with(pf_reg(24)) + .with(pf_reg(25)) + .with(pf_reg(26)) + .with(pf_reg(27)); + +fn compute_clobber_size(clobbers: &[Writable]) -> u32 { + let mut clobbered_size = 0; + for reg in clobbers { + match reg.to_reg().class() { + RegClass::Int => { + clobbered_size += 8; + } + RegClass::Float => { + clobbered_size += 8; + } + RegClass::Vector => unimplemented!("Vector Size Clobbered"), + } + } + align_to(clobbered_size, 16) +} + +const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty() + .with(px_reg(1)) + .with(px_reg(5)) + .with(px_reg(6)) + .with(px_reg(7)) + .with(px_reg(10)) + .with(px_reg(11)) + .with(px_reg(12)) + .with(px_reg(13)) + .with(px_reg(14)) + .with(px_reg(15)) + .with(px_reg(16)) + .with(px_reg(17)) + .with(px_reg(28)) + .with(px_reg(29)) + .with(px_reg(30)) + .with(px_reg(31)) + // F Regs + .with(pf_reg(0)) + .with(pf_reg(1)) + .with(pf_reg(2)) + .with(pf_reg(3)) + .with(pf_reg(4)) + .with(pf_reg(5)) + .with(pf_reg(6)) + .with(pf_reg(7)) + .with(pf_reg(9)) + .with(pf_reg(10)) + .with(pf_reg(11)) + .with(pf_reg(12)) + .with(pf_reg(13)) + .with(pf_reg(14)) + .with(pf_reg(15)) + .with(pf_reg(16)) + .with(pf_reg(17)) + .with(pf_reg(28)) + .with(pf_reg(29)) + .with(pf_reg(30)) + .with(pf_reg(31)) + // V Regs - All vector regs get clobbered + .with(pv_reg(0)) + .with(pv_reg(1)) + .with(pv_reg(2)) + .with(pv_reg(3)) + .with(pv_reg(4)) + .with(pv_reg(5)) + .with(pv_reg(6)) + .with(pv_reg(7)) + .with(pv_reg(8)) + .with(pv_reg(9)) + .with(pv_reg(10)) + .with(pv_reg(11)) + .with(pv_reg(12)) + .with(pv_reg(13)) + .with(pv_reg(14)) + .with(pv_reg(15)) + .with(pv_reg(16)) + .with(pv_reg(17)) + .with(pv_reg(18)) + .with(pv_reg(19)) + .with(pv_reg(20)) + .with(pv_reg(21)) + .with(pv_reg(22)) + .with(pv_reg(23)) + .with(pv_reg(24)) + .with(pv_reg(25)) + .with(pv_reg(26)) + .with(pv_reg(27)) + .with(pv_reg(28)) + .with(pv_reg(29)) + .with(pv_reg(30)) + .with(pv_reg(31)); + +fn create_reg_environment() -> MachineEnv { + // Some C Extension instructions can only use a subset of the registers. + // x8 - x15, f8 - f15, v8 - v15 so we should prefer to use those since + // they allow us to emit C instructions more often. + // + // In general the order of preference is: + // 1. Compressible Caller Saved registers. + // 2. Non-Compressible Caller Saved registers. + // 3. Compressible Callee Saved registers. + // 4. Non-Compressible Callee Saved registers. + + let preferred_regs_by_class: [Vec; 3] = { + let x_registers: Vec = (10..=15).map(px_reg).collect(); + let f_registers: Vec = (10..=15).map(pf_reg).collect(); + let v_registers: Vec = (8..=15).map(pv_reg).collect(); + + [x_registers, f_registers, v_registers] + }; + + let non_preferred_regs_by_class: [Vec; 3] = { + // x0 - x4 are special registers, so we don't want to use them. + // Omit x30 and x31 since they are the spilltmp registers. + + // Start with the Non-Compressible Caller Saved registers. + let x_registers: Vec = (5..=7) + .chain(16..=17) + .chain(28..=29) + // The first Callee Saved register is x9 since its Compressible + // Omit x8 since it's the frame pointer. + .chain(9..=9) + // The rest of the Callee Saved registers are Non-Compressible + .chain(18..=27) + .map(px_reg) + .collect(); + + // Prefer Caller Saved registers. + let f_registers: Vec = (0..=7) + .chain(16..=17) + .chain(28..=31) + // Once those are exhausted, we should prefer f8 and f9 since they are + // callee saved, but compressible. + .chain(8..=9) + .chain(18..=27) + .map(pf_reg) + .collect(); + + let v_registers = (0..=7).chain(16..=31).map(pv_reg).collect(); + + [x_registers, f_registers, v_registers] + }; + + MachineEnv { + preferred_regs_by_class, + non_preferred_regs_by_class, + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + } +} + +impl Riscv64MachineDeps { + fn gen_probestack_unroll( + insts: &mut SmallInstVec, + tmp: Writable, + guard_size: u32, + probe_count: u32, + ) { + // When manually unrolling adjust the stack pointer and then write a zero + // to the stack at that offset. + // + // We do this because valgrind expects us to never write beyond the stack + // pointer and associated redzone. + // See: https://github.com/bytecodealliance/wasmtime/issues/7454 + + // Store the adjust amount in a register upfront, so we don't have to + // reload it for each probe. It's worth loading this as a negative and + // using an `add` instruction since we have compressed versions of `add` + // but not the `sub` instruction. + insts.extend(Inst::load_constant_u64(tmp, (-(guard_size as i64)) as u64)); + + for _ in 0..probe_count { + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: writable_stack_reg(), + rs1: stack_reg(), + rs2: tmp.to_reg(), + }); + + insts.push(Inst::gen_store( + AMode::SPOffset(0), + zero_reg(), + I32, + MemFlags::trusted(), + )); + } + + // Restore the stack pointer to its original value + insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32)); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst.isle b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst.isle new file mode 100644 index 00000000000000..acdfa35f5da858 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst.isle @@ -0,0 +1,3147 @@ +;; Instruction formats. +(type MInst + (enum + ;; A no-op of zero size. + (Nop0) + (Nop4) + + ;; load immediate + (Lui + (rd WritableReg) + (imm Imm20)) + + (LoadInlineConst + (rd WritableReg) + (ty Type) + (imm u64)) + + (Auipc + (rd WritableReg) + (imm Imm20)) + + (Fli + (ty Type) + (imm FliConstant) + (rd WritableReg)) + + ;; An ALU operation with one register sources and a register destination. + (FpuRR + (alu_op FpuOPRR) + (width FpuOPWidth) + (frm FRM) + (rd WritableReg) + (rs Reg)) + + + ;; An ALU operation with two register sources and a register destination. + (AluRRR + (alu_op AluOPRRR) + (rd WritableReg) + (rs1 Reg) + (rs2 Reg)) + + ;; An ALU operation with two register sources and a register destination. + (FpuRRR + (alu_op FpuOPRRR) + (width FpuOPWidth) + (frm FRM) + (rd WritableReg) + (rs1 Reg) + (rs2 Reg)) + + ;; An ALU operation with three register sources and a register destination. + (FpuRRRR + (alu_op FpuOPRRRR) + (width FpuOPWidth) + (frm FRM) + (rd WritableReg) + (rs1 Reg) + (rs2 Reg) + (rs3 Reg)) + + ;; An ALU operation with a register source and an immediate-12 source, and a register + ;; destination. + (AluRRImm12 + (alu_op AluOPRRI) + (rd WritableReg) + (rs Reg) + (imm12 Imm12)) + + ;; A CSR Reading or Writing instruction with a register source and a register destination. + (CsrReg + (op CsrRegOP) + (rd WritableReg) + (rs Reg) + (csr CSR)) + + ;; A CSR Writing instruction with an immediate source and a register destination. + (CsrImm + (op CsrImmOP) + (rd WritableReg) + (imm UImm5) + (csr CSR)) + + ;; An load + (Load + (rd WritableReg) + (op LoadOP) + (flags MemFlags) + (from AMode)) + ;; An Store + (Store + (to AMode) + (op StoreOP) + (flags MemFlags) + (src Reg)) + + ;; A pseudo-instruction that captures register arguments in vregs. + (Args + (args VecArgPair)) + + ;; A pseudo-instruction that moves vregs to return registers. + (Rets + (rets VecRetPair)) + + (Ret) + + (Extend + (rd WritableReg) + (rn Reg) + (signed bool) + (from_bits u8) + (to_bits u8)) + + (Call (info BoxCallInfo)) + + ;; A machine indirect-call instruction. + (CallInd (info BoxCallIndInfo)) + + ;; A direct return-call macro instruction. + (ReturnCall (info BoxReturnCallInfo)) + + ;; An indirect return-call macro instruction. + (ReturnCallInd (info BoxReturnCallIndInfo)) + + ;; Emits a trap with the given trap code if the comparison succeeds + (TrapIf + (rs1 Reg) + (rs2 Reg) + (cc IntCC) + (trap_code TrapCode)) + + (Jal + ;; (rd WritableReg) don't use + (label MachLabel)) + + (CondBr + (taken CondBrTarget) + (not_taken CondBrTarget) + (kind IntegerCompare)) + + ;; Load an inline symbol reference. + (LoadExtName + (rd WritableReg) + (name BoxExternalName) + (offset i64)) + + ;; Load a TLS symbol address + (ElfTlsGetAddr + (rd WritableReg) + (name BoxExternalName)) + + ;; Load address referenced by `mem` into `rd`. + (LoadAddr + (rd WritableReg) + (mem AMode)) + + ;; A MOV instruction. These are encoded as OrR's (AluRRR form) but we + ;; keep them separate at the `Inst` level for better pretty-printing + ;; and faster `is_move()` logic. + (Mov + (rd WritableReg) + (rm Reg) + (ty Type)) + + ;; A MOV instruction, but where the source register is a non-allocatable + ;; PReg. It's important that the register be non-allocatable, as regalloc2 + ;; will not see it as used. + (MovFromPReg + (rd WritableReg) + (rm PReg)) + + (Fence + (pred FenceReq) + (succ FenceReq)) + + (EBreak) + + ;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at + ;; runtime. + (Udf + (trap_code TrapCode)) + ;; a jump and link register operation + (Jalr + ;;Plain unconditional jumps (assembler pseudo-op J) are encoded as a JAL with rd=x0. + (rd WritableReg) + (base Reg) + (offset Imm12)) + + ;; atomic operations. + (Atomic + (op AtomicOP) + (rd WritableReg) + (addr Reg) + (src Reg) + (amo AMO)) + ;; an atomic store + (AtomicStore + (src Reg) + (ty Type) + (p Reg)) + ;; an atomic load. + (AtomicLoad + (rd WritableReg) + (ty Type) + (p Reg)) + + ;; an atomic nand need using loop to implement. + (AtomicRmwLoop + (offset Reg) + (op AtomicRmwOp) + (dst WritableReg) + (ty Type) + (p Reg) + (x Reg) + (t0 WritableReg)) + + ;; select x or y base on condition + (Select + (dst WritableValueRegs) + (condition IntegerCompare) + (x ValueRegs) + (y ValueRegs)) + + (BrTable + (index Reg) + (tmp1 WritableReg) + (tmp2 WritableReg) + (targets VecMachLabel)) + + ;; atomic compare and set operation + (AtomicCas + (offset Reg) + (t0 WritableReg) + (dst WritableReg) + (e Reg) + (addr Reg) + (v Reg) + (ty Type)) + + (RawData (data VecU8)) + + ;; An unwind pseudo-instruction. + (Unwind + (inst UnwindInst)) + + ;; A dummy use, useful to keep a value alive. + (DummyUse + (reg Reg)) + + ;; popcnt if target doesn't support extension B + ;; use iteration to implement. + (Popcnt + (sum WritableReg) + (step WritableReg) + (tmp WritableReg) + (rs Reg) + (ty Type)) + + ;;; counting leading or trailing zeros. + (Cltz + ;; leading or trailing. + (leading bool) + (sum WritableReg) + (step WritableReg) + (tmp WritableReg) + (rs Reg) + (ty Type)) + + (Brev8 + (rs Reg) + (ty Type) + (step WritableReg) + (tmp WritableReg) + (tmp2 WritableReg) + (rd WritableReg)) + (StackProbeLoop + (guard_size u32) + (probe_count u32) + (tmp WritableReg)) + + (VecAluRRRR + (op VecAluOpRRRR) + (vd WritableReg) + (vd_src Reg) + (vs2 Reg) + (vs1 Reg) + (mask VecOpMasking) + (vstate VState)) + + (VecAluRRRImm5 + (op VecAluOpRRRImm5) + (vd WritableReg) + (vd_src Reg) + (vs2 Reg) + (imm Imm5) + (mask VecOpMasking) + (vstate VState)) + + (VecAluRRR + (op VecAluOpRRR) + (vd WritableReg) + (vs2 Reg) + (vs1 Reg) + (mask VecOpMasking) + (vstate VState)) + + (VecAluRRImm5 + (op VecAluOpRRImm5) + (vd WritableReg) + (vs2 Reg) + (imm Imm5) + (mask VecOpMasking) + (vstate VState)) + + (VecAluRR + (op VecAluOpRR) + (vd WritableReg) + (vs Reg) + (mask VecOpMasking) + (vstate VState)) + + (VecAluRImm5 + (op VecAluOpRImm5) + (vd WritableReg) + (imm Imm5) + (mask VecOpMasking) + (vstate VState)) + + (VecSetState + (rd WritableReg) + (vstate VState)) + + (VecLoad + (eew VecElementWidth) + (to WritableReg) + (from VecAMode) + (flags MemFlags) + (mask VecOpMasking) + (vstate VState)) + + (VecStore + (eew VecElementWidth) + (to VecAMode) + (from Reg) + (flags MemFlags) + (mask VecOpMasking) + (vstate VState)) +)) + +(type AtomicOP (enum + (LrW) + (ScW) + (AmoswapW) + (AmoaddW) + (AmoxorW) + (AmoandW) + (AmoorW) + (AmominW) + (AmomaxW) + (AmominuW) + (AmomaxuW) + (LrD) + (ScD) + (AmoswapD) + (AmoaddD) + (AmoxorD) + (AmoandD) + (AmoorD) + (AmominD) + (AmomaxD) + (AmominuD) + (AmomaxuD) +)) + +(type FpuOPRRRR (enum + (Fmadd) + (Fmsub) + (Fnmsub) + (Fnmadd) +)) + +(type FClassResult (enum + ;;0 rs1 is −∞. + (NegInfinite) + ;; 1 rs1 is a negative normal number. + (NegNormal) + ;; 2 rs1 is a negative subnormal number. + (NegSubNormal) + ;; 3 rs1 is −0. + (NegZero) + ;; 4 rs1 is +0. + (PosZero) + ;; 5 rs1 is a positive subnormal number. + (PosSubNormal) + ;; 6 rs1 is a positive normal number. + (PosNormal) + ;; 7 rs1 is +∞. + (PosInfinite) + ;; 8 rs1 is a signaling NaN. + (SNaN) + ;; 9 rs1 is a quiet NaN. + (QNaN) +)) + +(type FliConstant (primitive FliConstant)) + +(type FpuOPWidth (enum + (S) + (D) + (H) + (Q) +)) + +(decl pure fpu_op_width_from_ty (Type) FpuOPWidth) +(extern constructor fpu_op_width_from_ty fpu_op_width_from_ty) +(convert Type FpuOPWidth fpu_op_width_from_ty) + +(type FpuOPRR (enum + (Fsqrt) ;; fsqrt.{fmt} + (Fclass) ;; fclass.{fmt} + (FcvtWFmt) ;; fcvt.w.{fmt} + (FcvtWuFmt) ;; fcvt.wu.{fmt} + (FcvtLFmt) ;; fcvt.l.{fmt} + (FcvtLuFmt) ;; fcvt.lu.{fmt} + (FcvtFmtW) ;; fcvt.{fmt}.w + (FcvtFmtWu) ;; fcvt.{fmt}.wu + (FcvtFmtL) ;; fcvt.{fmt}.l + (FcvtFmtLu) ;; fcvt.{fmt}.lu + (FmvXFmt) ;; fmv.x.{fmt} + (FmvFmtX) ;; fmv.{fmt}.x + (FcvtSD) ;; fcvt.s.d + (FcvtDS) ;; fcvt.d.s + + ;; Zfa Extension + (Fround) ;; fround.{fmt} +)) + +(type LoadOP (enum + (Lb) + (Lh) + (Lw) + (Lbu) + (Lhu) + (Lwu) + (Ld) + (Flh) + (Flw) + (Fld) +)) + +(type StoreOP (enum + (Sb) + (Sh) + (Sw) + (Sd) + (Fsh) + (Fsw) + (Fsd) +)) + +(type AluOPRRR (enum + ;; base set + (Add) + (Sub) + (Sll) + (Slt) + (SltU) + (Sgt) + (Sgtu) + (Xor) + (Srl) + (Sra) + (Or) + (And) + + ;; RV64I Base Instruction Set (in addition to RV32I) + (Addw) + (Subw) + (Sllw) + (Srlw) + (Sraw) + + + ;;RV32M Standard Extension + (Mul) + (Mulh) + (Mulhsu) + (Mulhu) + (Div) + (DivU) + (Rem) + (RemU) + + ;; RV64M Standard Extension (in addition to RV32M) + (Mulw) + (Divw) + (Divuw) + (Remw) + (Remuw) + + ;; Zba: Address Generation Instructions + (Adduw) + (Sh1add) + (Sh1adduw) + (Sh2add) + (Sh2adduw) + (Sh3add) + (Sh3adduw) + + ;; Zbb: Bit Manipulation Instructions + (Andn) + (Orn) + (Xnor) + (Max) + (Maxu) + (Min) + (Minu) + (Rol) + (Rolw) + (Ror) + (Rorw) + + ;; Zbs: Single-bit instructions + (Bclr) + (Bext) + (Binv) + (Bset) + + ;; Zbc: Carry-less multiplication + (Clmul) + (Clmulh) + (Clmulr) + + ;; Zbkb: Bit-manipulation for Cryptography + (Pack) + (Packw) + (Packh) + + ;; ZiCond: Integer Conditional Operations + (CzeroEqz) + (CzeroNez) +)) + + +(type FpuOPRRR (enum + (Fadd) + (Fsub) + (Fmul) + (Fdiv) + (Fsgnj) + (Fsgnjn) + (Fsgnjx) + (Fmin) + (Fmax) + (Feq) + (Flt) + (Fle) + + ;; Zfa Extension + (Fminm) + (Fmaxm) +)) + + + +(type AluOPRRI (enum + ;; Base ISA + (Addi) + (Slti) + (SltiU) + (Xori) + (Ori) + (Andi) + (Slli) + (Srli) + (Srai) + (Addiw) + (Slliw) + (SrliW) + (Sraiw) + + ;; Zba: Address Generation Instructions + (SlliUw) + + ;; Zbb: Bit Manipulation Instructions + (Clz) + (Clzw) + (Ctz) + (Ctzw) + (Cpop) + (Cpopw) + (Sextb) + (Sexth) + (Zexth) + (Rori) + (Roriw) + (Rev8) + (Brev8) + (Orcb) + + ;; Zbs: Single-bit instructions + (Bclri) + (Bexti) + (Binvi) + (Bseti) +)) + +(type COpcodeSpace (enum + (C0) + (C1) + (C2) +)) + +;; Opcodes for the CR compressed instruction format +(type CrOp (enum + (CMv) + (CAdd) + (CJr) + (CJalr) + ;; c.ebreak technically isn't a CR format instruction, but it's encoding + ;; lines up with this format. + (CEbreak) +)) + +;; Opcodes for the CA compressed instruction format +(type CaOp (enum + (CAnd) + (COr) + (CXor) + (CSub) + (CAddw) + (CSubw) + (CMul) +)) + +;; Opcodes for the CJ compressed instruction format +(type CjOp (enum + (CJ) +)) + +;; Opcodes for the CI compressed instruction format +(type CiOp (enum + (CAddi) + (CAddiw) + (CAddi16sp) + (CSlli) + (CLi) + (CLui) + (CLwsp) + (CLdsp) + (CFldsp) +)) + +;; Opcodes for the CIW compressed instruction format +(type CiwOp (enum + (CAddi4spn) +)) + +;; Opcodes for the CB compressed instruction format +(type CbOp (enum + (CSrli) + (CSrai) + (CAndi) +)) + +;; Opcodes for the CSS compressed instruction format +(type CssOp (enum + (CSwsp) + (CSdsp) + (CFsdsp) +)) + +;; Opcodes for the CS compressed instruction format +(type CsOp (enum + (CSw) + (CSd) + (CFsd) +)) + +;; Opcodes for the CL compressed instruction format +(type ClOp (enum + (CLw) + (CLd) + (CFld) +)) + +;; Opcodes for the CSZN compressed instruction format +(type CsznOp (enum + (CNot) + (CZextb) + (CZexth) + (CZextw) + (CSextb) + (CSexth) +)) + +;; This is a mix of all Zcb memory addressing instructions +;; +;; Technically they are split across 4 different formats. +;; But they are all very similar, so we just group them all together. +(type ZcbMemOp (enum + (CLbu) + (CLhu) + (CLh) + (CSb) + (CSh) +)) + + +(type CsrRegOP (enum + ;; Atomic Read/Write CSR + (CsrRW) + ;; Atomic Read and Set Bits in CSR + (CsrRS) + ;; Atomic Read and Clear Bits in CSR + (CsrRC) +)) + +(type CsrImmOP (enum + ;; Atomic Read/Write CSR (Immediate Source) + (CsrRWI) + ;; Atomic Read and Set Bits in CSR (Immediate Source) + (CsrRSI) + ;; Atomic Read and Clear Bits in CSR (Immediate Source) + (CsrRCI) +)) + +;; Enum of the known CSR registers +(type CSR (enum + ;; Floating-Point Dynamic Rounding Mode + (Frm) +)) + + +(type FRM (enum + ;; Round to Nearest, ties to Even + (RNE) + ;; Round towards Zero + (RTZ) + ;; Round Down (towards −∞) + (RDN) + ;; Round Up (towards +∞) + (RUP) + ;; Round to Nearest, ties to Max Magnitude + (RMM) + ;; In instruction’s rm field, selects dynamic rounding mode; + ;;In Rounding Mode register, Invalid. + (Fcsr) +)) + +(decl pure frm_bits (FRM) UImm5) +(extern constructor frm_bits frm_bits) +(convert FRM UImm5 frm_bits) + +(type FFlagsException (enum + ;; Invalid Operation + (NV) + ;; Divide by Zero + (DZ) + ;; Overflow + (OF) + ;; Underflow + (UF) + ;; Inexact + (NX) +)) + +;;;; input output read write +;;;; SI SO SR SW +;;;; PI PO PR PW +;;;; lowest four bit are used. +(type FenceReq (primitive u8)) + +(type BoxCallInfo (primitive BoxCallInfo)) +(type BoxCallIndInfo (primitive BoxCallIndInfo)) +(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) +(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) +(type IntegerCompare (primitive IntegerCompare)) +(type AMode (primitive AMode)) +(type OptionReg (primitive OptionReg)) +(type OptionImm12 (primitive OptionImm12)) +(type OptionUimm5 (primitive OptionUimm5)) +(type Imm12 (primitive Imm12)) +(type UImm5 (primitive UImm5)) +(type Imm5 (primitive Imm5)) +(type Imm20 (primitive Imm20)) +(type Imm3 (primitive Imm3)) +(type CondBrTarget (primitive CondBrTarget)) +(type VecU8 (primitive VecU8)) +(type AMO (primitive AMO)) +(type VecMachLabel extern (enum)) + + +;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type XReg (primitive XReg)) +(type WritableXReg (primitive WritableXReg)) +(type FReg (primitive FReg)) +(type WritableFReg (primitive WritableFReg)) +(type VReg (primitive VReg)) +(type WritableVReg (primitive WritableVReg)) + +;; Construct a new `XReg` from a `Reg`. +;; +;; Asserts that the register has a Integer RegClass. +(decl xreg_new (Reg) XReg) +(extern constructor xreg_new xreg_new) +(convert Reg XReg xreg_new) + +;; Construct a new `WritableXReg` from a `WritableReg`. +;; +;; Asserts that the register has a Integer RegClass. +(decl writable_xreg_new (WritableReg) WritableXReg) +(extern constructor writable_xreg_new writable_xreg_new) +(convert WritableReg WritableXReg writable_xreg_new) + +;; Put a value into a XReg. +;; +;; Asserts that the value goes into a XReg. +(decl put_in_xreg (Value) XReg) +(rule (put_in_xreg val) (xreg_new (put_in_reg val))) +(convert Value XReg put_in_xreg) + +;; Construct an `InstOutput` out of a single XReg register. +(decl output_xreg (XReg) InstOutput) +(rule (output_xreg x) (output_reg x)) +(convert XReg InstOutput output_xreg) + +;; Convert a `WritableXReg` to an `XReg`. +(decl pure writable_xreg_to_xreg (WritableXReg) XReg) +(extern constructor writable_xreg_to_xreg writable_xreg_to_xreg) +(convert WritableXReg XReg writable_xreg_to_xreg) + +;; Convert a `WritableXReg` to an `WritableReg`. +(decl pure writable_xreg_to_writable_reg (WritableXReg) WritableReg) +(extern constructor writable_xreg_to_writable_reg writable_xreg_to_writable_reg) +(convert WritableXReg WritableReg writable_xreg_to_writable_reg) + +;; Convert a `WritableXReg` to an `Reg`. +(decl pure writable_xreg_to_reg (WritableXReg) Reg) +(rule (writable_xreg_to_reg x) (writable_xreg_to_writable_reg x)) +(convert WritableXReg Reg writable_xreg_to_reg) + +;; Convert an `XReg` to a `Reg`. +(decl pure xreg_to_reg (XReg) Reg) +(extern constructor xreg_to_reg xreg_to_reg) +(convert XReg Reg xreg_to_reg) + +;; Convert a `XReg` to a `ValueRegs`. +(decl xreg_to_value_regs (XReg) ValueRegs) +(rule (xreg_to_value_regs x) (value_reg x)) +(convert XReg ValueRegs xreg_to_reg) + +;; Convert a `WritableXReg` to a `ValueRegs`. +(decl writable_xreg_to_value_regs (WritableXReg) ValueRegs) +(rule (writable_xreg_to_value_regs x) (value_reg x)) +(convert WritableXReg ValueRegs writable_xreg_to_value_regs) + +;; Allocates a new `WritableXReg`. +(decl temp_writable_xreg () WritableXReg) +(rule (temp_writable_xreg) (temp_writable_reg $I64)) + + +;; Construct a new `FReg` from a `Reg`. +;; +;; Asserts that the register has a Float RegClass. +(decl freg_new (Reg) FReg) +(extern constructor freg_new freg_new) +(convert Reg FReg freg_new) + +;; Construct a new `WritableFReg` from a `WritableReg`. +;; +;; Asserts that the register has a Float RegClass. +(decl writable_freg_new (WritableReg) WritableFReg) +(extern constructor writable_freg_new writable_freg_new) +(convert WritableReg WritableFReg writable_freg_new) + +;; Put a value into a FReg. +;; +;; Asserts that the value goes into a FReg. +(decl put_in_freg (Value) FReg) +(rule (put_in_freg val) (freg_new (put_in_reg val))) +(convert Value FReg put_in_freg) + +;; Construct an `InstOutput` out of a single FReg register. +(decl output_freg (FReg) InstOutput) +(rule (output_freg x) (output_reg x)) +(convert FReg InstOutput output_freg) + +;; Convert a `WritableFReg` to an `FReg`. +(decl pure writable_freg_to_freg (WritableFReg) FReg) +(extern constructor writable_freg_to_freg writable_freg_to_freg) +(convert WritableFReg FReg writable_freg_to_freg) + +;; Convert a `WritableFReg` to an `WritableReg`. +(decl pure writable_freg_to_writable_reg (WritableFReg) WritableReg) +(extern constructor writable_freg_to_writable_reg writable_freg_to_writable_reg) +(convert WritableFReg WritableReg writable_freg_to_writable_reg) + +;; Convert a `WritableFReg` to an `Reg`. +(decl pure writable_freg_to_reg (WritableFReg) Reg) +(rule (writable_freg_to_reg x) (writable_freg_to_writable_reg x)) +(convert WritableFReg Reg writable_freg_to_reg) + +;; Convert an `FReg` to a `Reg`. +(decl pure freg_to_reg (FReg) Reg) +(extern constructor freg_to_reg freg_to_reg) +(convert FReg Reg freg_to_reg) + +;; Convert a `FReg` to a `ValueRegs`. +(decl freg_to_value_regs (FReg) ValueRegs) +(rule (freg_to_value_regs x) (value_reg x)) +(convert FReg ValueRegs xreg_to_reg) + +;; Convert a `WritableFReg` to a `ValueRegs`. +(decl writable_freg_to_value_regs (WritableFReg) ValueRegs) +(rule (writable_freg_to_value_regs x) (value_reg x)) +(convert WritableFReg ValueRegs writable_freg_to_value_regs) + +;; Allocates a new `WritableFReg`. +(decl temp_writable_freg () WritableFReg) +(rule (temp_writable_freg) (temp_writable_reg $F64)) + + + +;; Construct a new `VReg` from a `Reg`. +;; +;; Asserts that the register has a Vector RegClass. +(decl vreg_new (Reg) VReg) +(extern constructor vreg_new vreg_new) +(convert Reg VReg vreg_new) + +;; Construct a new `WritableVReg` from a `WritableReg`. +;; +;; Asserts that the register has a Vector RegClass. +(decl writable_vreg_new (WritableReg) WritableVReg) +(extern constructor writable_vreg_new writable_vreg_new) +(convert WritableReg WritableVReg writable_vreg_new) + +;; Put a value into a VReg. +;; +;; Asserts that the value goes into a VReg. +(decl put_in_vreg (Value) VReg) +(rule (put_in_vreg val) (vreg_new (put_in_reg val))) +(convert Value VReg put_in_vreg) + +;; Construct an `InstOutput` out of a single VReg register. +(decl output_vreg (VReg) InstOutput) +(rule (output_vreg x) (output_reg x)) +(convert VReg InstOutput output_vreg) + +;; Convert a `WritableVReg` to an `VReg`. +(decl pure writable_vreg_to_vreg (WritableVReg) VReg) +(extern constructor writable_vreg_to_vreg writable_vreg_to_vreg) +(convert WritableVReg VReg writable_vreg_to_vreg) + +;; Convert a `WritableVReg` to an `WritableReg`. +(decl pure writable_vreg_to_writable_reg (WritableVReg) WritableReg) +(extern constructor writable_vreg_to_writable_reg writable_vreg_to_writable_reg) +(convert WritableVReg WritableReg writable_vreg_to_writable_reg) + +;; Convert a `WritableVReg` to an `Reg`. +(decl pure writable_vreg_to_reg (WritableVReg) Reg) +(rule (writable_vreg_to_reg x) (writable_vreg_to_writable_reg x)) +(convert WritableVReg Reg writable_vreg_to_reg) + +;; Convert an `VReg` to a `Reg`. +(decl pure vreg_to_reg (VReg) Reg) +(extern constructor vreg_to_reg vreg_to_reg) +(convert VReg Reg vreg_to_reg) + +;; Convert a `VReg` to a `ValueRegs`. +(decl vreg_to_value_regs (VReg) ValueRegs) +(rule (vreg_to_value_regs x) (value_reg x)) +(convert VReg ValueRegs xreg_to_reg) + +;; Convert a `WritableVReg` to a `ValueRegs`. +(decl writable_vreg_to_value_regs (WritableVReg) ValueRegs) +(rule (writable_vreg_to_value_regs x) (value_reg x)) +(convert WritableVReg ValueRegs writable_vreg_to_value_regs) + +;; Allocates a new `WritableVReg`. +(decl temp_writable_vreg () WritableVReg) +(rule (temp_writable_vreg) (temp_writable_reg $I8X16)) + + +;; Converters + +(convert u8 i32 u8_as_i32) +(decl u8_as_i32 (u8) i32) +(extern constructor u8_as_i32 u8_as_i32) + +;; ISA Extension helpers + +(decl pure has_m () bool) +(extern constructor has_m has_m) + +(decl pure has_v () bool) +(extern constructor has_v has_v) + +(decl pure has_zfa () bool) +(extern constructor has_zfa has_zfa) + +(decl pure has_zfh () bool) +(extern constructor has_zfh has_zfh) + +(decl pure has_zbkb () bool) +(extern constructor has_zbkb has_zbkb) + +(decl pure has_zba () bool) +(extern constructor has_zba has_zba) + +(decl pure has_zbb () bool) +(extern constructor has_zbb has_zbb) + +(decl pure has_zbc () bool) +(extern constructor has_zbc has_zbc) + +(decl pure has_zbs () bool) +(extern constructor has_zbs has_zbs) + +(decl pure has_zicond () bool) +(extern constructor has_zicond has_zicond) + + +;;;; Type Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper that matches any supported type. This extractor checks the ISA flags +;; to determine if the type is supported. +(decl ty_supported (Type) Type) +(extern extractor ty_supported ty_supported) + +;; Helper that matches any scalar floating point type +(decl ty_supported_float (Type) Type) +(extern extractor ty_supported_float ty_supported_float) + +;; Helper that matches any supported vector type +(decl ty_supported_vec (Type) Type) +(extern extractor ty_supported_vec ty_supported_vec) + + +;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; RV32I Base Integer Instruction Set + +;; Helper for emitting the `add` instruction. +;; rd ← rs1 + rs2 +(decl rv_add (XReg XReg) XReg) +(rule (rv_add rs1 rs2) + (alu_rrr (AluOPRRR.Add) rs1 rs2)) + +;; Helper for emitting the `addi` ("Add Immediate") instruction. +;; rd ← rs1 + sext(imm) +(decl rv_addi (XReg Imm12) XReg) +(rule (rv_addi rs1 imm) + (alu_rr_imm12 (AluOPRRI.Addi) rs1 imm)) + +;; Helper for emitting the `sub` instruction. +;; rd ← rs1 - rs2 +(decl rv_sub (XReg XReg) XReg) +(rule (rv_sub rs1 rs2) + (alu_rrr (AluOPRRR.Sub) rs1 rs2)) + +;; Helper for emitting the `neg` instruction. +;; This instruction is a mnemonic for `sub rd, zero, rs1`. +(decl rv_neg (XReg) XReg) +(rule (rv_neg rs1) + (alu_rrr (AluOPRRR.Sub) (zero_reg) rs1)) + +;; Helper for emitting the `sll` ("Shift Left Logical") instruction. +;; rd ← rs1 << rs2 +(decl rv_sll (XReg XReg) XReg) +(rule (rv_sll rs1 rs2) + (alu_rrr (AluOPRRR.Sll) rs1 rs2)) + +;; Helper for emitting the `slli` ("Shift Left Logical Immediate") instruction. +;; rd ← rs1 << uext(imm) +(decl rv_slli (XReg Imm12) XReg) +(rule (rv_slli rs1 imm) + (alu_rr_imm12 (AluOPRRI.Slli) rs1 imm)) + +;; Helper for emitting the `srl` ("Shift Right Logical") instruction. +;; rd ← rs1 >> rs2 +(decl rv_srl (XReg XReg) XReg) +(rule (rv_srl rs1 rs2) + (alu_rrr (AluOPRRR.Srl) rs1 rs2)) + +;; Helper for emitting the `srli` ("Shift Right Logical Immediate") instruction. +;; rd ← rs1 >> uext(imm) +(decl rv_srli (XReg Imm12) XReg) +(rule (rv_srli rs1 imm) + (alu_rr_imm12 (AluOPRRI.Srli) rs1 imm)) + +;; Helper for emitting the `sra` ("Shift Right Arithmetic") instruction. +;; rd ← rs1 >> rs2 +(decl rv_sra (XReg XReg) XReg) +(rule (rv_sra rs1 rs2) + (alu_rrr (AluOPRRR.Sra) rs1 rs2)) + +;; Helper for emitting the `srai` ("Shift Right Arithmetic Immediate") instruction. +;; rd ← rs1 >> uext(imm) +(decl rv_srai (XReg Imm12) XReg) +(rule (rv_srai rs1 imm) + (alu_rr_imm12 (AluOPRRI.Srai) rs1 imm)) + +;; Helper for emitting the `or` instruction. +;; rd ← rs1 ∨ rs2 +(decl rv_or (XReg XReg) XReg) +(rule (rv_or rs1 rs2) + (alu_rrr (AluOPRRR.Or) rs1 rs2)) + +;; Helper for emitting the `ori` ("Or Immediate") instruction. +;; rd ← rs1 ∨ uext(imm) +(decl rv_ori (XReg Imm12) XReg) +(rule (rv_ori rs1 imm) + (alu_rr_imm12 (AluOPRRI.Ori) rs1 imm)) + +;; Helper for emitting the `xor` instruction. +;; rd ← rs1 ⊕ rs2 +(decl rv_xor (XReg XReg) XReg) +(rule (rv_xor rs1 rs2) + (alu_rrr (AluOPRRR.Xor) rs1 rs2)) + +;; Helper for emitting the `xori` ("Exclusive Or Immediate") instruction. +;; rd ← rs1 ⊕ uext(imm) +(decl rv_xori (XReg Imm12) XReg) +(rule (rv_xori rs1 imm) + (alu_rr_imm12 (AluOPRRI.Xori) rs1 imm)) + +;; Helper for emitting the `not` instruction. +;; This instruction is a mnemonic for `xori rd, rs1, -1`. +(decl rv_not (XReg) XReg) +(rule (rv_not rs1) + (rv_xori rs1 (imm12_const -1))) + +;; Helper for emitting the `and` instruction. +;; rd ← rs1 ∧ rs2 +(decl rv_and (XReg XReg) XReg) +(rule (rv_and rs1 rs2) + (alu_rrr (AluOPRRR.And) rs1 rs2)) + +;; Helper for emitting the `andi` ("And Immediate") instruction. +;; rd ← rs1 ∧ uext(imm) +(decl rv_andi (XReg Imm12) XReg) +(rule (rv_andi rs1 imm) + (alu_rr_imm12 (AluOPRRI.Andi) rs1 imm)) + +;; Helper for emitting the `slt` ("Set Less Than") instruction. +;; rd ← rs1 < rs2 +(decl rv_slt (XReg XReg) XReg) +(rule (rv_slt rs1 rs2) + (alu_rrr (AluOPRRR.Slt) rs1 rs2)) + +;; Helper for emitting the `sltu` ("Set Less Than Unsigned") instruction. +;; rd ← rs1 < rs2 +(decl rv_sltu (XReg XReg) XReg) +(rule (rv_sltu rs1 rs2) + (alu_rrr (AluOPRRR.SltU) rs1 rs2)) + +;; Helper for emitting the `snez` instruction. +;; This instruction is a mnemonic for `sltu rd, zero, rs`. +(decl rv_snez (XReg) XReg) +(rule (rv_snez rs1) + (rv_sltu (zero_reg) rs1)) + +;; Helper for emitting the `slti` ("Set Less Than Immediate") instruction. +;; rd ← rs1 < imm +(decl rv_slti (XReg Imm12) XReg) +(rule (rv_slti rs1 imm) + (alu_rr_imm12 (AluOPRRI.Slti) rs1 imm)) + +;; Helper for emitting the `sltiu` ("Set Less Than Immediate Unsigned") instruction. +;; rd ← rs1 < imm +(decl rv_sltiu (XReg Imm12) XReg) +(rule (rv_sltiu rs1 imm) + (alu_rr_imm12 (AluOPRRI.SltiU) rs1 imm)) + +;; Helper for emitting the `seqz` instruction. +;; This instruction is a mnemonic for `sltiu rd, rs, 1`. +(decl rv_seqz (XReg) XReg) +(rule (rv_seqz rs1) + (rv_sltiu rs1 (imm12_const 1))) + + +;; RV64I Base Integer Instruction Set +;; Unlike RV32I instructions these are only present in the 64bit ISA + +;; Helper for emitting the `addw` ("Add Word") instruction. +;; rd ← sext32(rs1) + sext32(rs2) +(decl rv_addw (XReg XReg) XReg) +(rule (rv_addw rs1 rs2) + (alu_rrr (AluOPRRR.Addw) rs1 rs2)) + +;; Helper for emitting the `addiw` ("Add Word Immediate") instruction. +;; rd ← sext32(rs1) + imm +(decl rv_addiw (XReg Imm12) XReg) +(rule (rv_addiw rs1 imm) + (alu_rr_imm12 (AluOPRRI.Addiw) rs1 imm)) + +;; Helper for emitting the `sext.w` ("Sign Extend Word") instruction. +;; This instruction is a mnemonic for `addiw rd, rs, zero`. +(decl rv_sextw (XReg) XReg) +(rule (rv_sextw rs1) + (rv_addiw rs1 (imm12_const 0))) + +;; Helper for emitting the `subw` ("Subtract Word") instruction. +;; rd ← sext32(rs1) - sext32(rs2) +(decl rv_subw (XReg XReg) XReg) +(rule (rv_subw rs1 rs2) + (alu_rrr (AluOPRRR.Subw) rs1 rs2)) + +;; Helper for emitting the `sllw` ("Shift Left Logical Word") instruction. +;; rd ← sext32(uext32(rs1) << rs2) +(decl rv_sllw (XReg XReg) XReg) +(rule (rv_sllw rs1 rs2) + (alu_rrr (AluOPRRR.Sllw) rs1 rs2)) + +;; Helper for emitting the `slliw` ("Shift Left Logical Immediate Word") instruction. +;; rd ← sext32(uext32(rs1) << imm) +(decl rv_slliw (XReg Imm12) XReg) +(rule (rv_slliw rs1 imm) + (alu_rr_imm12 (AluOPRRI.Slliw) rs1 imm)) + +;; Helper for emitting the `srlw` ("Shift Right Logical Word") instruction. +;; rd ← sext32(uext32(rs1) >> rs2) +(decl rv_srlw (XReg XReg) XReg) +(rule (rv_srlw rs1 rs2) + (alu_rrr (AluOPRRR.Srlw) rs1 rs2)) + +;; Helper for emitting the `srliw` ("Shift Right Logical Immediate Word") instruction. +;; rd ← sext32(uext32(rs1) >> imm) +(decl rv_srliw (XReg Imm12) XReg) +(rule (rv_srliw rs1 imm) + (alu_rr_imm12 (AluOPRRI.SrliW) rs1 imm)) + +;; Helper for emitting the `sraw` ("Shift Right Arithmetic Word") instruction. +;; rd ← sext32(rs1 >> rs2) +(decl rv_sraw (XReg XReg) XReg) +(rule (rv_sraw rs1 rs2) + (alu_rrr (AluOPRRR.Sraw) rs1 rs2)) + +;; Helper for emitting the `sraiw` ("Shift Right Arithmetic Immediate Word") instruction. +;; rd ← sext32(rs1 >> imm) +(decl rv_sraiw (XReg Imm12) XReg) +(rule (rv_sraiw rs1 imm) + (alu_rr_imm12 (AluOPRRI.Sraiw) rs1 imm)) + + +;; RV32M Extension +;; TODO: Enable these instructions only when we have the M extension + +;; Helper for emitting the `mul` instruction. +;; rd ← rs1 × rs2 +(decl rv_mul (XReg XReg) XReg) +(rule (rv_mul rs1 rs2) + (alu_rrr (AluOPRRR.Mul) rs1 rs2)) + +;; Helper for emitting the `mulh` ("Multiply High Signed Signed") instruction. +;; rd ← (sext(rs1) × sext(rs2)) » xlen +(decl rv_mulh (XReg XReg) XReg) +(rule (rv_mulh rs1 rs2) + (alu_rrr (AluOPRRR.Mulh) rs1 rs2)) + +;; Helper for emitting the `mulhu` ("Multiply High Unsigned Unsigned") instruction. +;; rd ← (uext(rs1) × uext(rs2)) » xlen +(decl rv_mulhu (XReg XReg) XReg) +(rule (rv_mulhu rs1 rs2) + (alu_rrr (AluOPRRR.Mulhu) rs1 rs2)) + +;; Helper for emitting the `div` instruction. +;; rd ← rs1 ÷ rs2 +(decl rv_div (XReg XReg) XReg) +(rule (rv_div rs1 rs2) + (alu_rrr (AluOPRRR.Div) rs1 rs2)) + +;; Helper for emitting the `divu` ("Divide Unsigned") instruction. +;; rd ← rs1 ÷ rs2 +(decl rv_divu (XReg XReg) XReg) +(rule (rv_divu rs1 rs2) + (alu_rrr (AluOPRRR.DivU) rs1 rs2)) + +;; Helper for emitting the `rem` instruction. +;; rd ← rs1 mod rs2 +(decl rv_rem (XReg XReg) XReg) +(rule (rv_rem rs1 rs2) + (alu_rrr (AluOPRRR.Rem) rs1 rs2)) + +;; Helper for emitting the `remu` ("Remainder Unsigned") instruction. +;; rd ← rs1 mod rs2 +(decl rv_remu (XReg XReg) XReg) +(rule (rv_remu rs1 rs2) + (alu_rrr (AluOPRRR.RemU) rs1 rs2)) + +;; RV64M Extension +;; TODO: Enable these instructions only when we have the M extension + +;; Helper for emitting the `mulw` ("Multiply Word") instruction. +;; rd ← uext32(rs1) × uext32(rs2) +(decl rv_mulw (XReg XReg) XReg) +(rule (rv_mulw rs1 rs2) + (alu_rrr (AluOPRRR.Mulw) rs1 rs2)) + +;; Helper for emitting the `divw` ("Divide Word") instruction. +;; rd ← sext32(rs1) ÷ sext32(rs2) +(decl rv_divw (XReg XReg) XReg) +(rule (rv_divw rs1 rs2) + (alu_rrr (AluOPRRR.Divw) rs1 rs2)) + +;; Helper for emitting the `divuw` ("Divide Unsigned Word") instruction. +;; rd ← uext32(rs1) ÷ uext32(rs2) +(decl rv_divuw (XReg XReg) XReg) +(rule (rv_divuw rs1 rs2) + (alu_rrr (AluOPRRR.Divuw) rs1 rs2)) + +;; Helper for emitting the `remw` ("Remainder Word") instruction. +;; rd ← sext32(rs1) mod sext32(rs2) +(decl rv_remw (XReg XReg) XReg) +(rule (rv_remw rs1 rs2) + (alu_rrr (AluOPRRR.Remw) rs1 rs2)) + +;; Helper for emitting the `remuw` ("Remainder Unsigned Word") instruction. +;; rd ← uext32(rs1) mod uext32(rs2) +(decl rv_remuw (XReg XReg) XReg) +(rule (rv_remuw rs1 rs2) + (alu_rrr (AluOPRRR.Remuw) rs1 rs2)) + + +;; F and D Extensions +;; TODO: Enable these instructions only when we have the F or D extensions + +;; Helper for emitting the `fadd` instruction. +(decl rv_fadd (Type FRM FReg FReg) FReg) +(rule (rv_fadd ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fadd) ty frm rs1 rs2)) + +;; Helper for emitting the `fsub` instruction. +(decl rv_fsub (Type FRM FReg FReg) FReg) +(rule (rv_fsub ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fsub) ty frm rs1 rs2)) + +;; Helper for emitting the `fmul` instruction. +(decl rv_fmul (Type FRM FReg FReg) FReg) +(rule (rv_fmul ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fmul) ty frm rs1 rs2)) + +;; Helper for emitting the `fdiv` instruction. +(decl rv_fdiv (Type FRM FReg FReg) FReg) +(rule (rv_fdiv ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fdiv) ty frm rs1 rs2)) + +;; Helper for emitting the `fsqrt` instruction. +(decl rv_fsqrt (Type FRM FReg) FReg) +(rule (rv_fsqrt ty frm rs1) (fpu_rr (FpuOPRR.Fsqrt) ty frm rs1)) + +;; Helper for emitting the `fmadd` instruction. +(decl rv_fmadd (Type FRM FReg FReg FReg) FReg) +(rule (rv_fmadd ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fmadd) ty frm rs1 rs2 rs3)) + +;; Helper for emitting the `fmsub` instruction. +(decl rv_fmsub (Type FRM FReg FReg FReg) FReg) +(rule (rv_fmsub ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fmsub) ty frm rs1 rs2 rs3)) + +;; Helper for emitting the `fnmadd` instruction. +(decl rv_fnmadd (Type FRM FReg FReg FReg) FReg) +(rule (rv_fnmadd ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fnmadd) ty frm rs1 rs2 rs3)) + +;; Helper for emitting the `fnmsub` instruction. +(decl rv_fnmsub (Type FRM FReg FReg FReg) FReg) +(rule (rv_fnmsub ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fnmsub) ty frm rs1 rs2 rs3)) + +;; Helper for emitting the `fmv.x.h` instruction. +(decl rv_fmvxh (FReg) XReg) +(rule (rv_fmvxh r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F16 (FRM.RNE) r)) + +;; Helper for emitting the `fmv.x.w` instruction. +(decl rv_fmvxw (FReg) XReg) +(rule (rv_fmvxw r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F32 (FRM.RNE) r)) + +;; Helper for emitting the `fmv.x.d` instruction. +(decl rv_fmvxd (FReg) XReg) +(rule (rv_fmvxd r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F64 (FRM.RNE) r)) + +;; Helper for emitting the `fmv.h.x` instruction. +(decl rv_fmvhx (XReg) FReg) +(rule (rv_fmvhx r) (fpu_rr (FpuOPRR.FmvFmtX) $F16 (FRM.RNE) r)) + +;; Helper for emitting the `fmv.w.x` instruction. +(decl rv_fmvwx (XReg) FReg) +(rule (rv_fmvwx r) (fpu_rr (FpuOPRR.FmvFmtX) $F32 (FRM.RNE) r)) + +;; Helper for emitting the `fmv.d.x` instruction. +(decl rv_fmvdx (XReg) FReg) +(rule (rv_fmvdx r) (fpu_rr (FpuOPRR.FmvFmtX) $F64 (FRM.RNE) r)) + +;; Helper for emitting the `fcvt.d.s` ("Float Convert Double to Single") instruction. +(decl rv_fcvtds (FReg) FReg) +(rule (rv_fcvtds rs1) (fpu_rr (FpuOPRR.FcvtDS) $F64 (FRM.RNE) rs1)) + +;; Helper for emitting the `fcvt.s.d` ("Float Convert Single to Double") instruction. +(decl rv_fcvtsd (FRM FReg) FReg) +(rule (rv_fcvtsd frm rs1) (fpu_rr (FpuOPRR.FcvtSD) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.s.w` instruction. +(decl rv_fcvtsw (FRM XReg) FReg) +(rule (rv_fcvtsw frm rs1) (fpu_rr (FpuOPRR.FcvtFmtW) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.s.wu` instruction. +(decl rv_fcvtswu (FRM XReg) FReg) +(rule (rv_fcvtswu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtWu) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.d.w` instruction. +(decl rv_fcvtdw (XReg) FReg) +(rule (rv_fcvtdw rs1) (fpu_rr (FpuOPRR.FcvtFmtW) $F64 (FRM.RNE) rs1)) + +;; Helper for emitting the `fcvt.d.wu` instruction. +(decl rv_fcvtdwu (XReg) FReg) +(rule (rv_fcvtdwu rs1) (fpu_rr (FpuOPRR.FcvtFmtWu) $F64 (FRM.RNE) rs1)) + +;; Helper for emitting the `fcvt.s.l` instruction. +(decl rv_fcvtsl (FRM XReg) FReg) +(rule (rv_fcvtsl frm rs1) (fpu_rr (FpuOPRR.FcvtFmtL) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.s.lu` instruction. +(decl rv_fcvtslu (FRM XReg) FReg) +(rule (rv_fcvtslu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtLu) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.d.l` instruction. +(decl rv_fcvtdl (FRM XReg) FReg) +(rule (rv_fcvtdl frm rs1) (fpu_rr (FpuOPRR.FcvtFmtL) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.d.lu` instruction. +(decl rv_fcvtdlu (FRM XReg) FReg) +(rule (rv_fcvtdlu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtLu) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.w.s` instruction. +(decl rv_fcvtws (FRM FReg) XReg) +(rule (rv_fcvtws frm rs1) (fpu_rr_int (FpuOPRR.FcvtWFmt) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.l.s` instruction. +(decl rv_fcvtls (FRM FReg) XReg) +(rule (rv_fcvtls frm rs1) (fpu_rr_int (FpuOPRR.FcvtLFmt) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.wu.s` instruction. +(decl rv_fcvtwus (FRM FReg) XReg) +(rule (rv_fcvtwus frm rs1) (fpu_rr_int (FpuOPRR.FcvtWuFmt) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.lu.s` instruction. +(decl rv_fcvtlus (FRM FReg) XReg) +(rule (rv_fcvtlus frm rs1) (fpu_rr_int (FpuOPRR.FcvtLuFmt) $F32 frm rs1)) + +;; Helper for emitting the `fcvt.w.d` instruction. +(decl rv_fcvtwd (FRM FReg) XReg) +(rule (rv_fcvtwd frm rs1) (fpu_rr_int (FpuOPRR.FcvtWFmt) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.l.d` instruction. +(decl rv_fcvtld (FRM FReg) XReg) +(rule (rv_fcvtld frm rs1) (fpu_rr_int (FpuOPRR.FcvtLFmt) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.wu.d` instruction. +(decl rv_fcvtwud (FRM FReg) XReg) +(rule (rv_fcvtwud frm rs1) (fpu_rr_int (FpuOPRR.FcvtWuFmt) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.lu.d` instruction. +(decl rv_fcvtlud (FRM FReg) XReg) +(rule (rv_fcvtlud frm rs1) (fpu_rr_int (FpuOPRR.FcvtLuFmt) $F64 frm rs1)) + +;; Helper for emitting the `fcvt.w.*` instructions. +(decl rv_fcvtw (Type FRM FReg) XReg) +(rule (rv_fcvtw $F32 frm rs1) (rv_fcvtws frm rs1)) +(rule (rv_fcvtw $F64 frm rs1) (rv_fcvtwd frm rs1)) + +;; Helper for emitting the `fcvt.l.*` instructions. +(decl rv_fcvtl (Type FRM FReg) XReg) +(rule (rv_fcvtl $F32 frm rs1) (rv_fcvtls frm rs1)) +(rule (rv_fcvtl $F64 frm rs1) (rv_fcvtld frm rs1)) + +;; Helper for emitting the `fcvt.wu.*` instructions. +(decl rv_fcvtwu (Type FRM FReg) XReg) +(rule (rv_fcvtwu $F32 frm rs1) (rv_fcvtwus frm rs1)) +(rule (rv_fcvtwu $F64 frm rs1) (rv_fcvtwud frm rs1)) + +;; Helper for emitting the `fcvt.lu.*` instructions. +(decl rv_fcvtlu (Type FRM FReg) XReg) +(rule (rv_fcvtlu $F32 frm rs1) (rv_fcvtlus frm rs1)) +(rule (rv_fcvtlu $F64 frm rs1) (rv_fcvtlud frm rs1)) + +;; Helper for emitting the `fsgnj` ("Floating Point Sign Injection") instruction. +;; The output of this instruction is `rs1` with the sign bit from `rs2` +;; This implements the `copysign` operation +(decl rv_fsgnj (Type FReg FReg) FReg) +(rule (rv_fsgnj ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnj) ty (FRM.RNE) rs1 rs2)) + +;; Helper for emitting the `fsgnjn` ("Floating Point Sign Injection Negated") instruction. +;; The output of this instruction is `rs1` with the negated sign bit from `rs2` +;; When `rs1 == rs2` this implements the `neg` operation +(decl rv_fsgnjn (Type FReg FReg) FReg) +(rule (rv_fsgnjn ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnjn) ty (FRM.RTZ) rs1 rs2)) + +;; Helper for emitting the `fneg` ("Floating Point Negate") instruction. +;; This instruction is a mnemonic for `fsgnjn rd, rs1, rs1` +(decl rv_fneg (Type FReg) FReg) +(rule (rv_fneg ty rs1) (rv_fsgnjn ty rs1 rs1)) + +;; Helper for emitting the `fsgnjx` ("Floating Point Sign Injection Exclusive") instruction. +;; The output of this instruction is `rs1` with the XOR of the sign bits from `rs1` and `rs2`. +;; When `rs1 == rs2` this implements `fabs` +(decl rv_fsgnjx (Type FReg FReg) FReg) +(rule (rv_fsgnjx ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnjx) ty (FRM.RDN) rs1 rs2)) + +;; Helper for emitting the `fabs` ("Floating Point Absolute") instruction. +;; This instruction is a mnemonic for `fsgnjx rd, rs1, rs1` +(decl rv_fabs (Type FReg) FReg) +(rule (rv_fabs ty rs1) (rv_fsgnjx ty rs1 rs1)) + +;; Helper for emitting the `feq` ("Float Equal") instruction. +(decl rv_feq (Type FReg FReg) XReg) +(rule (rv_feq ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Feq) ty (FRM.RDN) rs1 rs2)) + +;; Helper for emitting the `flt` ("Float Less Than") instruction. +(decl rv_flt (Type FReg FReg) XReg) +(rule (rv_flt ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Flt) ty (FRM.RTZ) rs1 rs2)) + +;; Helper for emitting the `fle` ("Float Less Than or Equal") instruction. +(decl rv_fle (Type FReg FReg) XReg) +(rule (rv_fle ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Fle) ty (FRM.RNE) rs1 rs2)) + +;; Helper for emitting the `fgt` ("Float Greater Than") instruction. +;; Note: The arguments are reversed +(decl rv_fgt (Type FReg FReg) XReg) +(rule (rv_fgt ty rs1 rs2) (rv_flt ty rs2 rs1)) + +;; Helper for emitting the `fge` ("Float Greater Than or Equal") instruction. +;; Note: The arguments are reversed +(decl rv_fge (Type FReg FReg) XReg) +(rule (rv_fge ty rs1 rs2) (rv_fle ty rs2 rs1)) + +;; Helper for emitting the `fmin` instruction. +(decl rv_fmin (Type FReg FReg) FReg) +(rule (rv_fmin ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmin) ty (FRM.RNE) rs1 rs2)) + +;; Helper for emitting the `fmax` instruction. +(decl rv_fmax (Type FReg FReg) FReg) +(rule (rv_fmax ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmax) ty (FRM.RTZ) rs1 rs2)) + +;; `Zfa` Extension Instructions + +;; Helper for emitting the `fminm` instruction. +(decl rv_fminm (Type FReg FReg) FReg) +(rule (rv_fminm ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fminm) ty (FRM.RDN) rs1 rs2)) + +;; Helper for emitting the `fmaxm` instruction. +(decl rv_fmaxm (Type FReg FReg) FReg) +(rule (rv_fmaxm ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmaxm) ty (FRM.RUP) rs1 rs2)) + +;; Helper for emitting the `fround` instruction. +(decl rv_fround (Type FRM FReg) FReg) +(rule (rv_fround ty frm rs) (fpu_rr (FpuOPRR.Fround) ty frm rs)) + +;; Helper for emitting the `fli` instruction. +(decl rv_fli (Type FliConstant) FReg) +(rule (rv_fli ty imm) + (let ((dst WritableFReg (temp_writable_freg)) + (_ Unit (emit (MInst.Fli ty + imm + dst)))) + dst)) + +;; `Zba` Extension Instructions + +;; Helper for emitting the `adduw` ("Add Unsigned Word") instruction. +;; rd ← uext32(rs1) + uext32(rs2) +(decl rv_adduw (XReg XReg) XReg) +(rule (rv_adduw rs1 rs2) + (alu_rrr (AluOPRRR.Adduw) rs1 rs2)) + +;; Helper for emitting the `zext.w` ("Zero Extend Word") instruction. +;; This instruction is a mnemonic for `adduw rd, rs1, zero`. +;; rd ← uext32(rs1) +(decl rv_zextw (XReg) XReg) +(rule (rv_zextw rs1) + (rv_adduw rs1 (zero_reg))) + +;; Helper for emitting the `slli.uw` ("Shift Left Logical Immediate Unsigned Word") instruction. +;; rd ← uext32(rs1) << imm +(decl rv_slliuw (XReg Imm12) XReg) +(rule (rv_slliuw rs1 imm) + (alu_rr_imm12 (AluOPRRI.SlliUw) rs1 imm)) + + +;; `Zbb` Extension Instructions + +;; Helper for emitting the `andn` ("And Negated") instruction. +;; rd ← rs1 ∧ ~(rs2) +(decl rv_andn (XReg XReg) XReg) +(rule (rv_andn rs1 rs2) + (if-let true (has_zbb)) + (alu_rrr (AluOPRRR.Andn) rs1 rs2)) +(rule (rv_andn rs1 rs2) + (if-let false (has_zbb)) + (rv_and rs1 (rv_not rs2))) + +;; Helper for emitting the `orn` ("Or Negated") instruction. +;; rd ← rs1 ∨ ~(rs2) +(decl rv_orn (XReg XReg) XReg) +(rule (rv_orn rs1 rs2) + (alu_rrr (AluOPRRR.Orn) rs1 rs2)) + +;; Helper for emitting the `xnor` ("Exclusive NOR") instruction. +;; rd ← ~(rs1 ^ rs2) +(decl rv_xnor (XReg XReg) XReg) +(rule (rv_xnor rs1 rs2) + (alu_rrr (AluOPRRR.Xnor) rs1 rs2)) + +;; Helper for emitting the `clz` ("Count Leading Zero Bits") instruction. +(decl rv_clz (XReg) XReg) +(rule (rv_clz rs1) + (alu_rr_funct12 (AluOPRRI.Clz) rs1)) + +;; Helper for emitting the `clzw` ("Count Leading Zero Bits in Word") instruction. +(decl rv_clzw (XReg) XReg) +(rule (rv_clzw rs1) + (alu_rr_funct12 (AluOPRRI.Clzw) rs1)) + +;; Helper for emitting the `ctz` ("Count Trailing Zero Bits") instruction. +(decl rv_ctz (XReg) XReg) +(rule (rv_ctz rs1) + (alu_rr_funct12 (AluOPRRI.Ctz) rs1)) + +;; Helper for emitting the `ctzw` ("Count Trailing Zero Bits in Word") instruction. +(decl rv_ctzw (XReg) XReg) +(rule (rv_ctzw rs1) + (alu_rr_funct12 (AluOPRRI.Ctzw) rs1)) + +;; Helper for emitting the `cpop` ("Count Population") instruction. +(decl rv_cpop (XReg) XReg) +(rule (rv_cpop rs1) + (alu_rr_funct12 (AluOPRRI.Cpop) rs1)) + +;; Helper for emitting the `cpopw` ("Count Population") instruction. +(decl rv_cpopw (XReg) XReg) +(rule (rv_cpopw rs1) + (alu_rr_funct12 (AluOPRRI.Cpopw) rs1)) + +;; Helper for emitting the `max` instruction. +(decl rv_max (XReg XReg) XReg) +(rule (rv_max rs1 rs2) + (alu_rrr (AluOPRRR.Max) rs1 rs2)) + +;; Helper for emitting the `maxu` instruction. +(decl rv_maxu (XReg XReg) XReg) +(rule (rv_maxu rs1 rs2) + (alu_rrr (AluOPRRR.Maxu) rs1 rs2)) + +;; Helper for emitting the `min` instruction. +(decl rv_min (XReg XReg) XReg) +(rule (rv_min rs1 rs2) + (alu_rrr (AluOPRRR.Min) rs1 rs2)) + +;; Helper for emitting the `minu` instruction. +(decl rv_minu (XReg XReg) XReg) +(rule (rv_minu rs1 rs2) + (alu_rrr (AluOPRRR.Minu) rs1 rs2)) + +;; Helper for emitting the `sext.b` instruction. +(decl rv_sextb (XReg) XReg) +(rule (rv_sextb rs1) + (alu_rr_imm12 (AluOPRRI.Sextb) rs1 (imm12_const 0))) + +;; Helper for emitting the `sext.h` instruction. +(decl rv_sexth (XReg) XReg) +(rule (rv_sexth rs1) + (alu_rr_imm12 (AluOPRRI.Sexth) rs1 (imm12_const 0))) + +;; Helper for emitting the `zext.h` instruction. +(decl rv_zexth (XReg) XReg) +(rule (rv_zexth rs1) + (alu_rr_imm12 (AluOPRRI.Zexth) rs1 (imm12_const 0))) + +;; Helper for emitting the `rol` ("Rotate Left") instruction. +(decl rv_rol (XReg XReg) XReg) +(rule (rv_rol rs1 rs2) + (alu_rrr (AluOPRRR.Rol) rs1 rs2)) + +;; Helper for emitting the `rolw` ("Rotate Left Word") instruction. +(decl rv_rolw (XReg XReg) XReg) +(rule (rv_rolw rs1 rs2) + (alu_rrr (AluOPRRR.Rolw) rs1 rs2)) + +;; Helper for emitting the `ror` ("Rotate Right") instruction. +(decl rv_ror (XReg XReg) XReg) +(rule (rv_ror rs1 rs2) + (alu_rrr (AluOPRRR.Ror) rs1 rs2)) + +;; Helper for emitting the `rorw` ("Rotate Right Word") instruction. +(decl rv_rorw (XReg XReg) XReg) +(rule (rv_rorw rs1 rs2) + (alu_rrr (AluOPRRR.Rorw) rs1 rs2)) + +;; Helper for emitting the `rori` ("Rotate Right") instruction. +(decl rv_rori (XReg Imm12) XReg) +(rule (rv_rori rs1 rs2) + (alu_rr_imm12 (AluOPRRI.Rori) rs1 rs2)) + +;; Helper for emitting the `roriw` ("Rotate Right Word") instruction. +(decl rv_roriw (XReg Imm12) XReg) +(rule (rv_roriw rs1 rs2) + (alu_rr_imm12 (AluOPRRI.Roriw) rs1 rs2)) + +;; Helper for emitting the `rev8` ("Byte Reverse") instruction. +(decl rv_rev8 (XReg) XReg) +(rule (rv_rev8 rs1) + (alu_rr_funct12 (AluOPRRI.Rev8) rs1)) + +;; Helper for emitting the `brev8` ("Bit Reverse Inside Bytes") instruction. +;; TODO: This instruction is mentioned in some older versions of the +;; spec, but has since disappeared, we should follow up on this. +;; It probably was renamed to `rev.b` which seems to be the closest match. +(decl rv_brev8 (XReg) XReg) +(rule (rv_brev8 rs1) + (alu_rr_funct12 (AluOPRRI.Brev8) rs1)) + +;; `Zbs` Extension Instructions + +(decl rv_bclr (XReg XReg) XReg) +(rule (rv_bclr rs1 rs2) + (alu_rrr (AluOPRRR.Bclr) rs1 rs2)) + +(decl rv_bclri (XReg Imm12) XReg) +(rule (rv_bclri rs1 imm) + (alu_rr_imm12 (AluOPRRI.Bclri) rs1 imm)) + +(decl rv_bext (XReg XReg) XReg) +(rule (rv_bext rs1 rs2) + (alu_rrr (AluOPRRR.Bext) rs1 rs2)) + +(decl rv_bexti (XReg Imm12) XReg) +(rule (rv_bexti rs1 imm) + (alu_rr_imm12 (AluOPRRI.Bexti) rs1 imm)) + +(decl rv_binv (XReg XReg) XReg) +(rule (rv_binv rs1 rs2) + (alu_rrr (AluOPRRR.Binv) rs1 rs2)) + +(decl rv_binvi (XReg Imm12) XReg) +(rule (rv_binvi rs1 imm) + (alu_rr_imm12 (AluOPRRI.Binvi) rs1 imm)) + +(decl rv_bset (XReg XReg) XReg) +(rule (rv_bset rs1 rs2) + (alu_rrr (AluOPRRR.Bset) rs1 rs2)) + +;; Helper for emitting the `bseti` ("Single-Bit Set Immediate") instruction. +(decl rv_bseti (XReg Imm12) XReg) +(rule (rv_bseti rs1 imm) + (alu_rr_imm12 (AluOPRRI.Bseti) rs1 imm)) + +;; `Zbkb` Extension Instructions + +;; Helper for emitting the `pack` ("Pack low halves of registers") instruction. +(decl rv_pack (XReg XReg) XReg) +(rule (rv_pack rs1 rs2) + (alu_rrr (AluOPRRR.Pack) rs1 rs2)) + +;; Helper for emitting the `packw` ("Pack low 16-bits of registers") instruction. +(decl rv_packw (XReg XReg) XReg) +(rule (rv_packw rs1 rs2) + (alu_rrr (AluOPRRR.Packw) rs1 rs2)) + +;; `ZiCond` Extension Instructions + +;; Helper for emitting the `czero.eqz` ("Conditional zero, if condition is equal to zero") instruction. +;; RS1 is the data source +;; RS2 is the condition +;; +;; rd = (rs2 == 0) ? 0 : rs1 +(decl rv_czero_eqz (XReg XReg) XReg) +(rule (rv_czero_eqz rs1 rs2) + (alu_rrr (AluOPRRR.CzeroEqz) rs1 rs2)) + +;; Helper for emitting the `czero.nez` ("Conditional zero, if condition is nonzero") instruction. +;; RS1 is the data source +;; RS2 is the condition +;; +;; rd = (rs2 != 0) ? 0 : rs1 +(decl rv_czero_nez (XReg XReg) XReg) +(rule (rv_czero_nez rs1 rs2) + (alu_rrr (AluOPRRR.CzeroNez) rs1 rs2)) + + +;; `Zicsr` Extension Instructions + +;; Helper for emitting the `csrrwi` instruction. +(decl rv_csrrwi (CSR UImm5) XReg) +(rule (rv_csrrwi csr imm) + (csr_imm (CsrImmOP.CsrRWI) csr imm)) + +;; This is a special case of `csrrwi` when the CSR is the `frm` CSR. +(decl rv_fsrmi (FRM) XReg) +(rule (rv_fsrmi frm) (rv_csrrwi (CSR.Frm) frm)) + + +;; Helper for emitting the `csrw` instruction. This is a special case of +;; `csrrw` where the destination register is always `x0`. +(decl rv_csrw (CSR XReg) Unit) +(rule (rv_csrw csr rs) + (csr_reg_dst_zero (CsrRegOP.CsrRW) csr rs)) + +;; This is a special case of `csrw` when the CSR is the `frm` CSR. +(decl rv_fsrm (XReg) Unit) +(rule (rv_fsrm rs) (rv_csrw (CSR.Frm) rs)) + + + + + + +;; Helper for generating a FliConstant from a u64 constant +(decl pure partial fli_constant_from_u64 (Type u64) FliConstant) +(extern constructor fli_constant_from_u64 fli_constant_from_u64) + +;; Helper for generating a FliConstant from a u64 negated constant +(decl pure partial fli_constant_from_negated_u64 (Type u64) FliConstant) +(extern constructor fli_constant_from_negated_u64 fli_constant_from_negated_u64) + +;; Helper for generating a i64 from a pair of Imm20 and Imm12 constants +(decl i64_generate_imm (Imm20 Imm12) i64) +(extern extractor i64_generate_imm i64_generate_imm) + +;; Helper for generating a i64 from a shift of a Imm20 constant with LUI +(decl i64_shift_for_lui (u64 Imm12) i64) +(extern extractor i64_shift_for_lui i64_shift_for_lui) + +;; Helper for generating a i64 from a shift of a Imm20 constant +(decl i64_shift (i64 Imm12) i64) +(extern extractor i64_shift i64_shift) + +;; Immediate Loading rules +;; TODO: Loading the zero reg directly causes a bunch of regalloc errors, we should look into it. +;; TODO: Load floats using `fld` instead of `ld` +(decl imm (Type u64) Reg) + +;; Special-case 0.0 for floats to use the `(zero_reg)` directly. +;; See #7162 for why this doesn't fall out of the rules below. +(rule 9 (imm (ty_supported_float $F16) 0) (gen_bitcast (zero_reg) $I16 $F16)) +(rule 9 (imm (ty_supported_float $F32) 0) (gen_bitcast (zero_reg) $I32 $F32)) +(rule 9 (imm (ty_supported_float $F64) 0) (gen_bitcast (zero_reg) $I64 $F64)) + +;; If Zfa is enabled, we can load certain constants with the `fli` instruction. +(rule 8 (imm (ty_supported_float (ty_32_or_64 ty)) imm) + (if-let true (has_zfa)) + (if-let const (fli_constant_from_u64 ty imm)) + (rv_fli ty const)) + +;; It is beneficial to load the negated constant with `fli` and then negate it +;; in a register. +;; +;; For f64's this saves one instruction, and for f32's it avoids +;; having to allocate an integer register, reducing integer register pressure. +(rule 7 (imm (ty_supported_float (ty_32_or_64 ty)) imm) + (if-let true (has_zfa)) + (if-let const (fli_constant_from_negated_u64 ty imm)) + (rv_fneg ty (rv_fli ty const))) + +;; Otherwise floats get loaded as integers and then moved into an F register. +(rule 6 (imm (ty_supported_float $F16) c) (gen_bitcast (imm $I16 c) $I16 $F16)) +(rule 6 (imm (ty_supported_float $F32) c) (gen_bitcast (imm $I32 c) $I32 $F32)) +(rule 6 (imm (ty_supported_float $F64) c) (gen_bitcast (imm $I64 c) $I64 $F64)) + +;; Try to match just an imm12 +(rule 4 (imm (ty_int ty) c) + (if-let (i64_generate_imm (imm20_is_zero) imm12) (i64_sextend_u64 ty c)) + (rv_addi (zero_reg) imm12)) + +;; We can also try to load using a single LUI. +;; LUI takes a 20 bit immediate, places it on bits 13 to 32 of the register. +;; In RV64 this value is then sign extended to 64bits. +(rule 3 (imm (ty_int ty) c) + (if-let (i64_generate_imm imm20 (imm12_is_zero)) (i64_sextend_u64 ty c)) + (rv_lui imm20)) + +;; We can combo addi + lui to represent all 32-bit immediates +;; And some 64-bit immediates as well. +(rule 2 (imm (ty_int ty) c) + (if-let (i64_generate_imm imm20 imm12) (i64_sextend_u64 ty c)) + (rv_addi (rv_lui imm20) imm12)) + +;; If the non-zero bits of the immediate fit in 20 bits, we can use LUI + shift +(rule 1 (imm (ty_int ty) c) + (if-let (i64_shift_for_lui (imm20_from_u64 base) shift) (i64_sextend_u64 ty c)) + (rv_slli (rv_lui base) shift)) + +;; Combine one of the above rules with a shift-left if possible, This chops off +;; all trailing zeros from the input constant and then attempts if the resulting +;; constant can itself use one of the above rules via the `i64_generate_imm` +;; matcher. This will then recurse on the above rules to materialize a smaller +;; constant which is then shifted left to create the desired constant. +(rule 0 (imm (ty_int ty) c) + (if-let (i64_shift c_shifted shift) (i64_sextend_u64 ty c)) ;; constant to make + (if-let (i64_generate_imm _ _) c_shifted) ;; can the smaller constant be made? + (rv_slli (imm ty (i64_as_u64 c_shifted)) shift)) + +;; Otherwise we fall back to loading the immediate from the constant pool. +(rule -1 (imm (ty_int ty) c) + (gen_load + (gen_const_amode (emit_u64_le_const c)) + (LoadOP.Ld) + (mem_flags_trusted))) + +;; Imm12 Rules + +(decl pure imm12_zero () Imm12) +(rule (imm12_zero) (imm12_const 0)) + +(decl pure imm12_const (i32) Imm12) +(extern constructor imm12_const imm12_const) + +(decl load_imm12 (i32) Reg) +(rule + (load_imm12 x) + (rv_addi (zero_reg) (imm12_const x))) + +;; for load immediate +(decl imm_from_bits (u64) Imm12) +(extern constructor imm_from_bits imm_from_bits) + +(decl imm_from_neg_bits (i64) Imm12) +(extern constructor imm_from_neg_bits imm_from_neg_bits) + +(decl imm12_const_add (i32 i32) Imm12) +(extern constructor imm12_const_add imm12_const_add) + +;; Performs a fallible add of the `Imm12` value and the 32-bit value provided. +(decl pure partial imm12_add (Imm12 i32) Imm12) +(extern constructor imm12_add imm12_add) + +(decl imm12_and (Imm12 u64) Imm12) +(extern constructor imm12_and imm12_and) + +;; Imm12 Extractors + +;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`. +(decl imm12_from_value (Imm12) Value) +(extractor (imm12_from_value n) (i64_from_iconst (imm12_from_i64 n))) + +;; Conceptually the same as `imm12_from_value`, but tries negating the constant +;; value (first sign-extending to handle narrow widths). +(decl pure partial imm12_from_negated_value (Value) Imm12) +(rule + (imm12_from_negated_value (has_type ty (iconst n))) + (if-let (imm12_from_u64 imm) (i64_as_u64 (i64_neg (i64_sextend_imm64 ty n)))) + imm) + +(decl imm12_from_u64 (Imm12) u64) +(extern extractor imm12_from_u64 imm12_from_u64) + +(decl imm12_from_i64 (Imm12) i64) +(extern extractor imm12_from_i64 imm12_from_i64) + +(decl pure partial u64_to_imm12 (u64) Imm12) +(rule (u64_to_imm12 (imm12_from_u64 n)) n) + +(decl pure imm12_is_zero () Imm12) +(extern extractor imm12_is_zero imm12_is_zero) + +;; Imm20 + +;; Extractor that matches if a Imm20 is zero +(decl pure imm20_is_zero () Imm20) +(extern extractor imm20_is_zero imm20_is_zero) + +(decl imm20_from_u64 (Imm20) u64) +(extern extractor imm20_from_u64 imm20_from_u64) + +(decl imm20_from_i64 (Imm20) i64) +(extern extractor imm20_from_i64 imm20_from_i64) + + +;; Imm5 Extractors + +(decl imm5_from_u64 (Imm5) u64) +(extern extractor imm5_from_u64 imm5_from_u64) + +(decl imm5_from_i64 (Imm5) i64) +(extern extractor imm5_from_i64 imm5_from_i64) + +;; Construct a Imm5 from an i8 +(decl pure partial i8_to_imm5 (i8) Imm5) +(extern constructor i8_to_imm5 i8_to_imm5) + +;; Helper to go directly from a `Value` to an `Imm5`. +(decl imm5_from_value (Imm5) Value) +(extractor (imm5_from_value n) (i64_from_iconst (imm5_from_i64 n))) + +;; Like imm5_from_value, but first negates the `Value`. +(decl pure partial imm5_from_negated_value (Value) Imm5) +(rule (imm5_from_negated_value (has_type ty (iconst n))) + (if-let (imm5_from_i64 imm) (i64_neg (i64_sextend_imm64 ty n))) + imm) + +;; Constructor that matches a `Value` equivalent to a replicated Imm5 on all lanes. +(decl pure partial replicated_imm5 (Value) Imm5) +(rule (replicated_imm5 (splat (imm5_from_value n))) n) +(rule (replicated_imm5 (vconst (u128_from_constant n128))) + (if-let (u128_replicated_u64 n64) n128) + (if-let (u64_replicated_u32 n32) n64) + (if-let (u32_replicated_u16 n16) n32) + (if-let (u16_replicated_u8 n8) n16) + (if-let n (i8_to_imm5 (u8_as_i8 n8))) + n) + +;; Like replicated_imm5, but first negates the `Value`. +(decl pure partial negated_replicated_imm5 (Value) Imm5) +(rule (negated_replicated_imm5 (splat n)) + (if-let imm5 (imm5_from_negated_value n)) + imm5) +(rule (negated_replicated_imm5 (vconst (u128_from_constant n128))) + (if-let (u128_replicated_u64 n64) n128) + (if-let (u64_replicated_u32 n32) n64) + (if-let (u32_replicated_u16 n16) n32) + (if-let (u16_replicated_u8 n8) n16) + (if-let n (i8_to_imm5 (i8_neg (u8_as_i8 n8)))) + n) + +;; UImm5 Helpers + +;; Constructor that matches a `Value` equivalent to a replicated UImm5 on all lanes. +(decl pure partial replicated_uimm5 (Value) UImm5) +(rule (replicated_uimm5 (splat (uimm5_from_value n))) n) +(rule 1 (replicated_uimm5 (vconst (u128_from_constant n128))) + (if-let (u128_replicated_u64 n64) n128) + (if-let (u64_replicated_u32 n32) n64) + (if-let (u32_replicated_u16 n16) n32) + (if-let (u16_replicated_u8 n8) n16) + (if-let (uimm5_from_u8 n) n8) + n) + +;; Helper to go directly from a `Value`, when it's an `iconst`, to an `UImm5`. +(decl uimm5_from_value (UImm5) Value) +(extractor (uimm5_from_value n) + (iconst (u64_from_imm64 (uimm5_from_u64 n)))) + +;; Extract a `UImm5` from an `u8`. +(decl pure partial uimm5_from_u8 (UImm5) u8) +(extern extractor uimm5_from_u8 uimm5_from_u8) + +;; Extract a `UImm5` from an `u64`. +(decl pure partial uimm5_from_u64 (UImm5) u64) +(extern extractor uimm5_from_u64 uimm5_from_u64) + +;; Convert a `u64` into an `UImm5` +(decl pure partial u64_to_uimm5 (u64) UImm5) +(rule (u64_to_uimm5 (uimm5_from_u64 n)) n) + +(decl uimm5_bitcast_to_imm5 (UImm5) Imm5) +(extern constructor uimm5_bitcast_to_imm5 uimm5_bitcast_to_imm5) + +;; Float Helpers + +;; Returns the bitpattern of the Canonical NaN for the given type. +(decl pure canonical_nan_u64 (Type) u64) +(rule (canonical_nan_u64 $F32) 0x7fc00000) +(rule (canonical_nan_u64 $F64) 0x7ff8000000000000) + +;; Helper for emitting `MInst.FpuRR` instructions. +(decl fpu_rr (FpuOPRR Type FRM Reg) FReg) +(rule (fpu_rr op ty frm src) + (let ((dst WritableFReg (temp_writable_freg)) + (_ Unit (emit (MInst.FpuRR op ty frm dst src)))) + dst)) + +;; Similar to fpu_rr but with an integer destination register +(decl fpu_rr_int (FpuOPRR Type FRM Reg) XReg) +(rule (fpu_rr_int op ty frm src) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.FpuRR op ty frm dst src)))) + dst)) + +;; Helper for emitting `MInst.AluRRR` instructions. +(decl alu_rrr (AluOPRRR Reg Reg) Reg) +(rule (alu_rrr op src1 src2) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.AluRRR op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.FpuRRR` instructions. +(decl fpu_rrr (FpuOPRRR Type FRM Reg Reg) FReg) +(rule (fpu_rrr op ty frm src1 src2) + (let ((dst WritableFReg (temp_writable_freg)) + (_ Unit (emit (MInst.FpuRRR op ty frm dst src1 src2)))) + dst)) + +;; Similar to fpu_rrr but with an integer destination register +(decl fpu_rrr_int (FpuOPRRR Type FRM Reg Reg) XReg) +(rule (fpu_rrr_int op ty frm src1 src2) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.FpuRRR op ty frm dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.FpuRRRR` instructions. +(decl fpu_rrrr (FpuOPRRRR Type FRM Reg Reg Reg) FReg) +(rule (fpu_rrrr op ty frm src1 src2 src3) + (let ((dst WritableFReg (temp_writable_freg)) + (_ Unit (emit (MInst.FpuRRRR op ty frm dst src1 src2 src3)))) + dst)) + + +;; Helper for emitting `MInst.AluRRImm12` instructions. +(decl alu_rr_imm12 (AluOPRRI Reg Imm12) Reg) +(rule (alu_rr_imm12 op src imm) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.AluRRImm12 op dst src imm)))) + dst)) + +;; some instruction use imm12 as funct12. +;; so we don't need the imm12 parameter. +(decl alu_rr_funct12 (AluOPRRI Reg) Reg) +(rule (alu_rr_funct12 op src) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.AluRRImm12 op dst src (imm12_zero))))) + dst)) + +;; Helper for emitting the `Lui` instruction. +;; TODO: This should be something like `emit_u_type`. And should share the +;; `MInst` with `auipc` since these instructions share the U-Type format. +(decl rv_lui (Imm20) XReg) +(rule (rv_lui imm) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Lui dst imm)))) + dst)) + +;; Helper for emitting `MInst.CsrImm` instructions. +(decl csr_imm (CsrImmOP CSR UImm5) XReg) +(rule (csr_imm op csr imm) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.CsrImm op dst imm csr)))) + dst)) + +;; Helper for emitting a `MInst.CsrReg` instruction that writes the result to x0. +(decl csr_reg_dst_zero (CsrRegOP CSR XReg) Unit) +(rule (csr_reg_dst_zero op csr rs) + (emit (MInst.CsrReg op (writable_zero_reg) rs csr))) + + + +(decl select_addi (Type) AluOPRRI) +(rule 1 (select_addi (fits_in_32 ty)) (AluOPRRI.Addiw)) +(rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi)) + + +(decl gen_andi (XReg u64) XReg) +(rule 1 (gen_andi x (imm12_from_u64 y)) + (rv_andi x y)) + +(rule 0 (gen_andi x y) + (rv_and x (imm $I64 y))) + + +(decl gen_or (Type ValueRegs ValueRegs) ValueRegs) +(rule 1 (gen_or $I128 x y) + (value_regs + (rv_or (value_regs_get x 0) (value_regs_get y 0)) + (rv_or (value_regs_get x 1) (value_regs_get y 1)))) + +(rule 0 (gen_or (fits_in_64 _) x y) + (rv_or (value_regs_get x 0) (value_regs_get y 0))) + + +(decl lower_ctz (Type Reg) Reg) +(rule (lower_ctz ty x) + (gen_cltz false x ty)) + +(rule 1 (lower_ctz (fits_in_16 ty) x) + (if-let true (has_zbb)) + (let ((tmp Reg (gen_bseti x (ty_bits ty)))) + (rv_ctzw tmp))) + +(rule 2 (lower_ctz $I32 x) + (if-let true (has_zbb)) + (rv_ctzw x)) + +(rule 2 (lower_ctz $I64 x) + (if-let true (has_zbb)) + (rv_ctz x)) + +;; Count leading zeros from a i128 bit value. +;; We count both halves separately and conditionally add them if it makes sense. + +(decl gen_cltz (bool XReg Type) XReg) +(rule (gen_cltz leading rs ty) + (let ((tmp WritableXReg (temp_writable_xreg)) + (step WritableXReg (temp_writable_xreg)) + (sum WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Cltz leading sum step tmp rs ty)))) + sum)) + +;; Performs a zero extension of the given value +(decl zext (Value) XReg) + +;; In the most generic case, we shift left and then shift right. +(rule 0 (zext val @ (value_type (fits_in_32 ty))) + (let ((shift Imm12 (imm_from_bits (u64_sub 64 (ty_bits ty))))) + (rv_srli (rv_slli val shift) shift))) + +;; If we are zero extending a U8 we can use a `andi` instruction. +(rule 1 (zext val @ (value_type $I8)) + (rv_andi val (imm12_const 0xff))) + +;; No point in trying to use `packh` here to zero extend 8 bit values +;; since we can just use `andi` instead which is part of the base ISA. + +;; If we have the `zbkb` extension `packw` can be used to zero extend 16 bit values +(rule 1 (zext val @ (value_type $I16)) + (if-let true (has_zbkb)) + (rv_packw val (zero_reg))) + +;; If we have the `zbkb` extension `pack` can be used to zero extend 32 bit registers +(rule 1 (zext val @ (value_type $I32)) + (if-let true (has_zbkb)) + (rv_pack val (zero_reg))) + +;; If we have the `zbb` extension we can use the dedicated `zext.h` instruction. +(rule 2 (zext val @ (value_type $I16)) + (if-let true (has_zbb)) + (rv_zexth val)) + +;; With `zba` we have a `zext.w` instruction +(rule 2 (zext val @ (value_type $I32)) + (if-let true (has_zba)) + (rv_zextw val)) + +;; Ignore sign extensions for values whose representation is already the full +;; register width. +(rule 3 (zext val) + (if (val_already_extended (ExtendOp.Zero) val)) + val) + +;; Performs a signed extension of the given value +(decl sext (Value) XReg) + +;; Same base case as `zext`, shift left-then-right. +(rule 0 (sext val @ (value_type (fits_in_32 ty))) + (let ((shift Imm12 (imm_from_bits (u64_sub 64 (ty_bits ty))))) + (rv_srai (rv_slli val shift) shift))) + +;; If we have the `zbb` extension we can use the dedicated `sext.b` instruction. +(rule 1 (sext val @ (value_type $I8)) + (if-let true (has_zbb)) + (rv_sextb val)) + +;; If we have the `zbb` extension we can use the dedicated `sext.h` instruction. +(rule 1 (sext val @ (value_type $I16)) + (if-let true (has_zbb)) + (rv_sexth val)) + +;; When signed extending from 32 to 64 bits we can use a +;; `addiw val 0`. Also known as a `sext.w` +(rule 1 (sext val @ (value_type $I32)) + (rv_sextw val)) + +;; Ignore sign extensions for values whose representation is already the full +;; register width. +(rule 2 (sext val) + (if (val_already_extended (ExtendOp.Signed) val)) + val) + +;; Helper matcher for when a value's representation is already sign or zero +;; extended to the full 64-bit register representation. This is used by `zext` +;; and `sext` above to skip the extension instruction entirely in some +;; circumstances. +(decl pure partial val_already_extended (ExtendOp Value) bool) +(rule 0 (val_already_extended _ v @ (value_type $I64)) true) + +;; When extending our backend always extends to the full register width, so +;; there's no need to extend-an-extend. +(rule 1 (val_already_extended (ExtendOp.Zero) (uextend _)) true) +(rule 1 (val_already_extended (ExtendOp.Signed) (sextend _)) true) + +;; The result of `icmp`/`fcmp` is zero or one, meaning that it's already sign +;; extended to the full register width. +(rule 1 (val_already_extended _ (icmp _ _ _)) true) +(rule 1 (val_already_extended _ (fcmp _ _ _)) true) + +;; The lowering for these operations always sign-extend their results due to the +;; use of the `*w` instructions in RV64I. Note that this requires that the +;; extension is from 32 to 64, 16/8-bit operations are explicitly excluded here. +;; There are no native instructions for the 16/8 bit operations so they must +;; fall through to actual sign extension above. +(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (ishl _ _))) true) +(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (ushr _ _))) true) +(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (sshr _ _))) true) +(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (iadd _ _))) true) +(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (isub _ _))) true) + +(type ExtendOp + (enum + (Zero) + (Signed))) + +(decl lower_b128_binary (AluOPRRR ValueRegs ValueRegs) ValueRegs) +(rule + (lower_b128_binary op a b) + (let + ( ;; low part. + (low XReg (alu_rrr op (value_regs_get a 0) (value_regs_get b 0))) + ;; high part. + (high XReg (alu_rrr op (value_regs_get a 1) (value_regs_get b 1)))) + (value_regs low high))) + +(decl lower_smlhi (Type XReg XReg) XReg) +(rule 1 + (lower_smlhi $I64 rs1 rs2) + (rv_mulh rs1 rs2)) + +(rule + (lower_smlhi ty rs1 rs2) + (let + ((tmp XReg (rv_mul rs1 rs2))) + (rv_srli tmp (imm12_const (ty_bits ty))))) + +;;;; construct shift amount.rotl on i128 will use shift to implement. So can call this function. +;;;; this will return shift amount and (ty_bits - "shift amount") +;;;; if ty_bits is greater than 64 like i128, then shmat will fallback to 64.because We are 64 bit platform. +(decl gen_shamt (Type XReg) ValueRegs) +(extern constructor gen_shamt gen_shamt) + +;; bseti: Set a single bit in a register, indexed by a constant. +(decl gen_bseti (Reg u64) Reg) +(rule (gen_bseti val bit) + (if-let false (has_zbs)) + (if-let false (u64_le bit 12)) + (let ((const XReg (imm $I64 (u64_shl 1 bit)))) + (rv_or val const))) + +(rule (gen_bseti val bit) + (if-let false (has_zbs)) + (if-let true (u64_le bit 12)) + (rv_ori val (imm12_const (u64_as_i32 (u64_shl 1 bit))))) + +(rule (gen_bseti val bit) + (if-let true (has_zbs)) + (rv_bseti val (imm12_const (u64_as_i32 bit)))) + + +(decl gen_popcnt (XReg) Reg) +(rule (gen_popcnt rs) + (let + ((tmp WritableXReg (temp_writable_xreg)) + (step WritableXReg (temp_writable_xreg)) + (sum WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Popcnt sum step tmp rs $I64)))) + (writable_reg_to_reg sum))) + +;; Generates a AMode that points to a register plus an offset. +(decl gen_reg_offset_amode (Reg i64) AMode) +(extern constructor gen_reg_offset_amode gen_reg_offset_amode) + +;; Generates a AMode that an offset from the stack pointer. +(decl gen_sp_offset_amode (i64) AMode) +(extern constructor gen_sp_offset_amode gen_sp_offset_amode) + +;; Generates a AMode that an offset from the frame pointer. +(decl gen_fp_offset_amode (i64) AMode) +(extern constructor gen_fp_offset_amode gen_fp_offset_amode) + +;; Generates an AMode that points to a stack slot + offset. +(decl gen_stack_slot_amode (StackSlot i64) AMode) +(extern constructor gen_stack_slot_amode gen_stack_slot_amode) + +;; Generates a AMode that points to a constant in the constant pool. +(decl gen_const_amode (VCodeConstant) AMode) +(extern constructor gen_const_amode gen_const_amode) + + + +;; Tries to match a Value + Offset into an AMode +(decl amode (Value i32) AMode) +(rule 0 (amode addr offset) (amode_inner addr offset)) + +;; If we are adding a constant offset with an iadd we can instead make that +;; offset part of the amode offset. +;; +;; We can't recurse into `amode` again since that could cause stack overflows. +;; See: https://github.com/bytecodealliance/wasmtime/pull/6968 +(rule 1 (amode (iadd addr (i32_from_iconst y)) offset) + (if-let new_offset (s32_add_fallible y offset)) + (amode_inner addr new_offset)) +(rule 2 (amode (iadd (i32_from_iconst x) addr) offset) + (if-let new_offset (s32_add_fallible x offset)) + (amode_inner addr new_offset)) + + +;; These are the normal rules for generating an AMode. +(decl amode_inner (Value i32) AMode) + +;; In the simplest case we just lower into a Reg+Offset +(rule 0 (amode_inner r @ (value_type (ty_addr64 _)) offset) + (gen_reg_offset_amode r offset)) + +;; If the value is a `get_frame_pointer`, we can just use the offset from that. +(rule 1 (amode_inner (get_frame_pointer) offset) + (gen_fp_offset_amode offset)) + +;; If the value is a `get_stack_pointer`, we can just use the offset from that. +(rule 1 (amode_inner (get_stack_pointer) offset) + (gen_sp_offset_amode offset)) + +;; Similarly if the value is a `stack_addr` we can also turn that into an sp offset. +(rule 1 (amode_inner (stack_addr ss ss_offset) amode_offset) + (if-let combined_offset (s32_add_fallible ss_offset amode_offset)) + (gen_stack_slot_amode ss combined_offset)) + + +;; Helpers for sinkable loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; RISC-V doesen't really have sinkable loads. But the regular load instructions +;; sign / zero extend their results to 64 bits. So we can pretend they are +;; an extend instruction with a sinkable load. This allows us to have better +;; lowerings on these cases. + +;; Extract a sinkable instruction from a value operand. +(decl sinkable_inst (Inst) Value) +(extern extractor sinkable_inst sinkable_inst) + +;; Matches a sinkable load. +(decl sinkable_load (Inst Type MemFlags Value Offset32) Value) +(extractor (sinkable_load inst ty flags addr offset) + (and + (load flags addr offset) + (sinkable_inst (has_type ty inst)))) + +;; Returns a canonical type for a LoadOP. We only return I64 or F64. +(decl load_op_reg_type (LoadOP) Type) +(rule 1 (load_op_reg_type (LoadOP.Fld)) $F64) +(rule 1 (load_op_reg_type (LoadOP.Flw)) $F64) +(rule 1 (load_op_reg_type (LoadOP.Flh)) $F64) +(rule 0 (load_op_reg_type _) $I64) + +;; Helper constructor to build a load instruction. +(decl gen_load (AMode LoadOP MemFlags) Reg) +(rule (gen_load amode op flags) + (let ((dst WritableReg (temp_writable_reg (load_op_reg_type op))) + (_ Unit (emit (MInst.Load dst op flags amode)))) + dst)) + +;; Similar to `gen_load` but marks `Inst` as sunk at the current point. +;; +;; This is only useful for load op's that perform some additional computation +;; such as extending the loaded value. +(decl gen_sunk_load (Inst AMode LoadOP MemFlags) Reg) +(rule (gen_sunk_load inst amode op flags) + (let ((_ Unit (sink_inst inst))) + (gen_load amode op flags))) + + +;; Helper constructor to build a store instruction. +;; +;; This helper contains a special-case for zero constants stored to memory to +;; directly store the `zero` register to memory. See #7162 for some discussion +;; on why this doesn't just fall out. +(decl gen_store (AMode MemFlags Value) InstOutput) +(rule 1 (gen_store amode flags val @ (value_type ty)) + (if-let (u64_from_iconst 0) val) + (rv_store amode (store_op ty) flags (zero_reg))) +(rule 0 (gen_store amode flags val @ (value_type ty)) + (rv_store amode (store_op ty) flags val)) + +;; Emit a raw instruction to store a register into memory. +;; +;; Note that the `src` operand must have the correct type for the `op` +;; specified. +(decl rv_store (AMode StoreOP MemFlags Reg) InstOutput) +(rule (rv_store amode op flags src) + (side_effect (SideEffectNoResult.Inst (MInst.Store amode op flags src)))) + + + + +(decl valid_atomic_transaction (Type) Type) +(extern extractor valid_atomic_transaction valid_atomic_transaction) + +;;helper function. +;;construct an atomic instruction. +(decl gen_atomic (AtomicOP Reg Reg AMO) Reg) +(rule + (gen_atomic op addr src amo) + (let + ((tmp WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Atomic op tmp addr src amo)))) + tmp)) + +;; helper function +(decl get_atomic_rmw_op (Type AtomicRmwOp) AtomicOP) +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Add)) + (AtomicOP.AmoaddW)) +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Add)) + (AtomicOP.AmoaddD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.And)) + (AtomicOP.AmoandW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.And)) + (AtomicOP.AmoandD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Or)) + (AtomicOP.AmoorW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Or)) + (AtomicOP.AmoorD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Smax)) + (AtomicOP.AmomaxW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Smax)) + (AtomicOP.AmomaxD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Smin)) + (AtomicOP.AmominW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Smin)) + (AtomicOP.AmominD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Umax)) + (AtomicOP.AmomaxuW) +) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Umax)) + (AtomicOP.AmomaxuD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Umin)) + (AtomicOP.AmominuW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Umin)) + (AtomicOP.AmominuD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Xchg)) + (AtomicOP.AmoswapW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Xchg)) + (AtomicOP.AmoswapD)) + +(rule + (get_atomic_rmw_op $I32 (AtomicRmwOp.Xor)) + (AtomicOP.AmoxorW)) + +(rule + (get_atomic_rmw_op $I64 (AtomicRmwOp.Xor)) + (AtomicOP.AmoxorD)) + +(decl atomic_amo () AMO) +(extern constructor atomic_amo atomic_amo) + + +(decl gen_atomic_load (Reg Type) Reg) +(rule + (gen_atomic_load p ty) + (let + ((tmp WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.AtomicLoad tmp ty p)))) + (writable_reg_to_reg tmp))) + +;;; +(decl gen_atomic_store (Reg Type Reg) InstOutput) +(rule + (gen_atomic_store p ty src) + (side_effect (SideEffectNoResult.Inst (MInst.AtomicStore src ty p))) +) + + +;; Rounds a FReg by converting the value into an integer and back with a specified +;; float rounding mode. +(decl float_round_fcvt (Type FRM FReg) FReg) +(rule (float_round_fcvt $F32 frm rs) (rv_fcvtsw frm (rv_fcvtws frm rs))) +(rule (float_round_fcvt $F64 frm rs) (rv_fcvtdl frm (rv_fcvtld frm rs))) + +(decl gen_float_round (FRM FReg Type) FReg) +(rule 0 (gen_float_round frm rs ty) + (let ( + ;; if rs is NaN/+-Infinity/+-Zero or if the exponent is larger than # of bits + ;; in mantissa, the result is the same as src, check for these cases first. + (max FReg (imm ty (float_int_max ty))) + (abs FReg (rv_fabs ty rs)) + (exact XReg (rv_flt ty abs max)) + + ;; Manually round the value using the fcvt instructions + ;; to move the value to an integer register and back. + (fcvt FReg (float_round_fcvt ty frm rs)) + ;; Restore the sign bit from the initial value. + (rounded FReg (rv_fsgnj ty fcvt rs)) + + ;; We want to return a arithmetic nan if the input is a canonical nan. + ;; Convert them by adding 0.0 to the input. + (float_zero FReg (gen_bitcast (zero_reg) (float_int_of_same_size ty) ty)) + (corrected_nan FReg (rv_fadd ty (FRM.RNE) rs float_zero))) + + ;; Check if the value cannot be rounded exactly and return the source input if so + (gen_select_freg (cmp_eqz exact) corrected_nan rounded))) + +;; With Zfa we can use the dedicated `fround` instruction. +(rule 1 (gen_float_round frm rs ty) + (if-let true (has_zfa)) + (rv_fround ty frm rs)) + + + +(decl gen_stack_addr (StackSlot Offset32) Reg) +(extern constructor gen_stack_addr gen_stack_addr) + +(decl gen_select_xreg (IntegerCompare XReg XReg) XReg) + +(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) + (if-let (IntCC.UnsignedLessThan) (intcc_without_eq cc)) + (if-let true (has_zbb)) + (rv_minu x y)) + +(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) + (if-let (IntCC.SignedLessThan) (intcc_without_eq cc)) + (if-let true (has_zbb)) + (rv_min x y)) + +(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) + (if-let (IntCC.UnsignedGreaterThan) (intcc_without_eq cc)) + (if-let true (has_zbb)) + (rv_maxu x y)) + +(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) + (if-let (IntCC.SignedGreaterThan) (intcc_without_eq cc)) + (if-let true (has_zbb)) + (rv_max x y)) + +;; Rotate Zero Reg to the right. This allows us to write fewer rules +;; below when matching the zero register +;; +;; Additionally prevent this rule from recursing infinitely by only +;; matching when one of the inputs is the zero register, but not both. + +(rule 5 (gen_select_xreg (int_compare_decompose cc a @ (zero_reg) b @ (non_zero_reg)) x y) + (if-let true (has_zicond)) + (gen_select_xreg (int_compare (intcc_swap_args cc) b a) x y)) + +(rule 4 (gen_select_xreg c @ (int_compare_decompose cc a b) x @ (zero_reg) y @ (non_zero_reg)) + (if-let true (has_zicond)) + (gen_select_xreg (int_compare (intcc_complement cc) a b) y x)) + +(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x (zero_reg)) + (if-let true (has_zicond)) + (rv_czero_nez x c)) + +(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x (zero_reg)) + (if-let true (has_zicond)) + (rv_czero_eqz x c)) + +(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x y) + (if-let true (has_zicond)) + (rv_or + (rv_czero_nez x c) + (rv_czero_eqz y c))) + +(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x y) + (if-let true (has_zicond)) + (rv_or + (rv_czero_eqz x c) + (rv_czero_nez y c))) + +;; It is still beneficial to emit the full compare instruction, and then the 3 instruction +;; select using zicond, so do that here as a last resort. +(rule 1 (gen_select_xreg compare x y) + (if-let true (has_zicond)) + (gen_select_xreg (cmp_nez (lower_int_compare compare)) x y)) + +;; In the base case we emit a conditional branch and a few moves. + +(rule 0 (gen_select_xreg c x y) + (let + ((dst WritableReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Select dst c x y)))) + (writable_reg_to_reg dst))) + + +(decl gen_select_vreg (IntegerCompare VReg VReg) VReg) +(rule (gen_select_vreg c x y) + (let + ((dst WritableReg (temp_writable_vreg)) + (_ Unit (emit (MInst.Select dst c (vreg_to_reg x) (vreg_to_reg y))))) + (writable_reg_to_reg dst))) +(decl gen_select_freg (IntegerCompare FReg FReg) FReg) +(rule (gen_select_freg c x y) + (let + ((dst WritableReg (temp_writable_freg)) + (_ Unit (emit (MInst.Select dst c (freg_to_reg x) (freg_to_reg y))))) + (writable_reg_to_reg dst))) +(decl gen_select_regs (IntegerCompare ValueRegs ValueRegs) ValueRegs) +(rule (gen_select_regs c x y) + (let + ((dst1 WritableReg (temp_writable_xreg)) + (dst2 WritableReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Select (writable_value_regs dst1 dst2) c x y)))) + (value_regs dst1 dst2))) + +(decl udf (TrapCode) InstOutput) +(rule + (udf code) + (side_effect (SideEffectNoResult.Inst (MInst.Udf code)))) + +(decl load_op (Type) LoadOP) +(extern constructor load_op load_op) + +(decl store_op (Type) StoreOP) +(extern constructor store_op store_op) + + +;;;; load extern name +(decl load_ext_name (ExternalName i64) Reg) +(extern constructor load_ext_name load_ext_name) + +(decl elf_tls_get_addr (ExternalName) Reg) +(rule (elf_tls_get_addr name) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ElfTlsGetAddr dst name)))) + dst)) + +;;; some float binary operation +;;; 1. need move into x register. +;;; 2. do the operation. +;;; 3. move back. +(decl lower_float_binary (AluOPRRR FReg FReg Type) FReg) +(rule + (lower_float_binary op rs1 rs2 ty) + (let ((x_rs1 XReg (move_f_to_x rs1 ty)) + (x_rs2 XReg (move_f_to_x rs2 ty)) + (tmp XReg (alu_rrr op x_rs1 x_rs2))) + (move_x_to_f tmp (float_int_of_same_size ty)))) + + +(decl i128_sub (ValueRegs ValueRegs) ValueRegs) +(rule + (i128_sub x y ) + (let ( + ;; low part. + (low XReg (rv_sub (value_regs_get x 0) (value_regs_get y 0))) + ;; compute borrow. + (borrow XReg (rv_sltu (value_regs_get x 0) low)) + ;; + (high_tmp XReg (rv_sub (value_regs_get x 1) (value_regs_get y 1))) + ;; + (high XReg (rv_sub high_tmp borrow))) + (value_regs low high))) + +;; Consume a CmpResult, producing a branch on its result. +(decl cond_br (IntegerCompare CondBrTarget CondBrTarget) SideEffectNoResult) +(rule (cond_br cmp then else) + (SideEffectNoResult.Inst + (MInst.CondBr then else cmp))) + +;; Helper for emitting the `j` mnemonic, an unconditional jump to label. +(decl rv_j (MachLabel) SideEffectNoResult) +(rule (rv_j label) + (SideEffectNoResult.Inst (MInst.Jal label))) + +;; Construct an IntegerCompare value. +(decl int_compare (IntCC XReg XReg) IntegerCompare) +(extern constructor int_compare int_compare) + +;; Extract the components of an `IntegerCompare` +(decl int_compare_decompose (IntCC XReg XReg) IntegerCompare) +(extern extractor infallible int_compare_decompose int_compare_decompose) + +(decl label_to_br_target (MachLabel) CondBrTarget) +(extern constructor label_to_br_target label_to_br_target) +(convert MachLabel CondBrTarget label_to_br_target) + +(decl cmp_eqz (XReg) IntegerCompare) +(rule (cmp_eqz r) (int_compare (IntCC.Equal) r (zero_reg))) + +(decl cmp_nez (XReg) IntegerCompare) +(rule (cmp_nez r) (int_compare (IntCC.NotEqual) r (zero_reg))) + +(decl cmp_eq (XReg XReg) IntegerCompare) +(rule (cmp_eq rs1 rs2) (int_compare (IntCC.Equal) rs1 rs2)) + +(decl cmp_ne (XReg XReg) IntegerCompare) +(rule (cmp_ne rs1 rs2) (int_compare (IntCC.NotEqual) rs1 rs2)) + +(decl cmp_lt (XReg XReg) IntegerCompare) +(rule (cmp_lt rs1 rs2) (int_compare (IntCC.SignedLessThan) rs1 rs2)) + +(decl cmp_ltz (XReg) IntegerCompare) +(rule (cmp_ltz rs) (int_compare (IntCC.SignedLessThan) rs (zero_reg))) + +(decl cmp_gt (XReg XReg) IntegerCompare) +(rule (cmp_gt rs1 rs2) (int_compare (IntCC.SignedGreaterThan) rs1 rs2)) + +(decl cmp_ge (XReg XReg) IntegerCompare) +(rule (cmp_ge rs1 rs2) (int_compare (IntCC.SignedGreaterThanOrEqual) rs1 rs2)) + +(decl cmp_le (XReg XReg) IntegerCompare) +(rule (cmp_le rs1 rs2) (int_compare (IntCC.SignedLessThanOrEqual) rs1 rs2)) + +(decl cmp_gtu (XReg XReg) IntegerCompare) +(rule (cmp_gtu rs1 rs2) (int_compare (IntCC.UnsignedGreaterThan) rs1 rs2)) + +(decl cmp_geu (XReg XReg) IntegerCompare) +(rule (cmp_geu rs1 rs2) (int_compare (IntCC.UnsignedGreaterThanOrEqual) rs1 rs2)) + +(decl cmp_ltu (XReg XReg) IntegerCompare) +(rule (cmp_ltu rs1 rs2) (int_compare (IntCC.UnsignedLessThan) rs1 rs2)) + +(decl cmp_leu (XReg XReg) IntegerCompare) +(rule (cmp_leu rs1 rs2) (int_compare (IntCC.UnsignedLessThanOrEqual) rs1 rs2)) + +;; Helper to generate an `IntegerCompare` which represents the "truthy" value of +;; the input provided. +;; +;; This is used in `Select` and `brif` for example to generate conditional +;; branches. The returned comparison, when taken, represents that `Value` is +;; nonzero. When not taken the input `Value` is zero. +(decl is_nonzero_cmp (Value) IntegerCompare) + +;; Base case - convert to a "truthy" value and compare it against zero. +;; +;; Note that non-64-bit types need to be extended since the upper bits from +;; Cranelift's point of view are undefined. Favor a zero extension for 8-bit +;; types because that's a single `andi` instruction, but favor sign-extension +;; for 16 and 32-bit types because many RISC-V which operate on the low 32-bits. +;; Additionally the base 64-bit ISA has a single instruction for sign-extending +;; from 32 to 64-bits which makes that a bit cheaper if used. +;; of registers sign-extend the results. +(rule 0 (is_nonzero_cmp val @ (value_type (fits_in_64 _))) + (cmp_nez (sext val))) +(rule 1 (is_nonzero_cmp val @ (value_type $I8)) + (cmp_nez (zext val))) +(rule 1 (is_nonzero_cmp val @ (value_type $I128)) + (cmp_nez (rv_or (value_regs_get val 0) (value_regs_get val 1)))) + +;; If the input value is itself an `icmp` or `fcmp` we can avoid generating the +;; result of the comparison and instead move the comparison directly into the +;; `IntegerCompare` that's returned. +(rule 2 (is_nonzero_cmp (maybe_uextend (icmp cc a b @ (value_type (fits_in_64 _))))) + (icmp_to_int_compare cc a b)) +(rule 2 (is_nonzero_cmp (maybe_uextend (fcmp cc a @ (value_type ty) b))) + (fcmp_to_float_compare cc ty a b)) + +;; Creates an `IntegerCompare` from an `icmp` node's parts. This will extend +;; values as necessary to their full register width to perform the +;; comparison. The returned `IntegerCompare` is suitable to use in conditional +;; branches for example. +;; +;; Note that this should ideally only be used when the `IntegerCompare` returned +;; is fed into a branch. If `IntegerCompare` is materialized this will miss out +;; on optimizations to compare against constants using some native instructions. +(decl icmp_to_int_compare (IntCC Value Value) IntegerCompare) +(rule 0 (icmp_to_int_compare cc a b @ (value_type (fits_in_64 in_ty))) + (int_compare cc (put_value_in_reg_for_icmp cc a) (put_value_in_reg_for_icmp cc b))) +(rule 1 (icmp_to_int_compare cc a b @ (value_type $I128)) + (cmp_nez (lower_icmp_i128 cc a b))) + +;; Places a `Value` into a full register width to prepare for a comparison +;; using `IntCC`. +;; +;; This is largely a glorified means of choosing sign-extension or +;; zero-extension for the `Value` input. +(decl put_value_in_reg_for_icmp (IntCC Value) XReg) + +;; Base cases, use the `cc` to determine whether to zero or sign extend. +(rule 0 (put_value_in_reg_for_icmp cc val) + (zext val)) +(rule 1 (put_value_in_reg_for_icmp cc val) + (if (signed_cond_code cc)) + (sext val)) + +;; For equality and inequality favor sign extension since it's generally +;; easier to perform sign extension on RV64 via native instructions. For 8-bit +;; types though use zero-extension since that's a single instruction `and`. +(rule 2 (put_value_in_reg_for_icmp (IntCC.Equal) val @ (value_type (fits_in_64 _))) + (sext val)) +(rule 2 (put_value_in_reg_for_icmp (IntCC.NotEqual) val @ (value_type (fits_in_64 _))) + (sext val)) +(rule 3 (put_value_in_reg_for_icmp (IntCC.Equal) val @ (value_type $I8)) + (zext val)) +(rule 3 (put_value_in_reg_for_icmp (IntCC.NotEqual) val @ (value_type $I8)) + (zext val)) + +;; As a special case use `x0` directly if a constant is 0. +(rule 4 (put_value_in_reg_for_icmp _ (i64_from_iconst 0)) + (zero_reg)) + + +(decl partial lower_branch (Inst MachLabelSlice) Unit) +(rule (lower_branch (jump _) (single_target label)) + (emit_side_effect (rv_j label))) + +(rule (lower_branch (brif v _ _) (two_targets then else)) + (emit_side_effect (cond_br (is_nonzero_cmp v) then else))) + +(decl lower_br_table (Reg MachLabelSlice) Unit) +(extern constructor lower_br_table lower_br_table) + +(rule (lower_branch (br_table index _) targets) + (lower_br_table index targets)) + +(decl load_ra () Reg) +(extern constructor load_ra load_ra) + + +;; Generates a bitcast instruction. +;; Args are: src, src_ty, dst_ty +(decl gen_bitcast (Reg Type Type) Reg) + +;; To support FP16 vfmv.* we need to check for the `zvfh` isa flag, which we currently don't +;; support, so restrict the floating point types to 32/64 bits. +(rule 5 (gen_bitcast r (ty_supported_float (ty_32_or_64 src_ty)) (ty_supported_vec _)) (rv_vfmv_sf r src_ty)) +(rule 4 (gen_bitcast r (ty_supported_vec _) (ty_supported_float (ty_32_or_64 dst_ty))) (rv_vfmv_fs r dst_ty)) + +(rule 3 (gen_bitcast r (ty_int_ref_scalar_64 src_ty) (ty_supported_vec _)) (rv_vmv_sx r src_ty)) +(rule 2 (gen_bitcast r (ty_supported_vec _) (ty_int_ref_scalar_64 dst_ty)) (rv_vmv_xs r dst_ty)) +(rule 1 (gen_bitcast r $F16 $I16) (rv_fmvxh r)) +(rule 1 (gen_bitcast r $F32 $I32) (rv_fmvxw r)) +(rule 1 (gen_bitcast r $F64 $I64) (rv_fmvxd r)) +(rule 1 (gen_bitcast r $I16 $F16) (rv_fmvhx r)) +(rule 1 (gen_bitcast r $I32 $F32) (rv_fmvwx r)) +(rule 1 (gen_bitcast r $I64 $F64) (rv_fmvdx r)) +(rule (gen_bitcast r _ _) r) + +(decl move_f_to_x (FReg Type) XReg) +(rule (move_f_to_x r $F32) (gen_bitcast r $F32 $I32)) +(rule (move_f_to_x r $F64) (gen_bitcast r $F64 $I64)) + +(decl move_x_to_f (XReg Type) FReg) +(rule (move_x_to_f r $I32) (gen_bitcast r $I32 $F32)) +(rule (move_x_to_f r $I64) (gen_bitcast r $I64 $F64)) + +(decl float_int_of_same_size (Type) Type) +(rule (float_int_of_same_size $F32) $I32) +(rule (float_int_of_same_size $F64) $I64) + + +(decl gen_brev8 (Reg Type) Reg) +(rule 1 + (gen_brev8 rs _) + (if-let true (has_zbkb)) + (rv_brev8 rs)) +(rule + (gen_brev8 rs ty) + (if-let false (has_zbkb)) + (let + ((tmp WritableXReg (temp_writable_xreg)) + (tmp2 WritableXReg (temp_writable_xreg)) + (step WritableXReg (temp_writable_xreg)) + (rd WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.Brev8 rs ty step tmp tmp2 rd)))) + (writable_reg_to_reg rd))) + +;; Negates x +;; Equivalent to 0 - x +(decl neg (Type ValueRegs) ValueRegs) +(rule 1 (neg (fits_in_64 (ty_int ty)) val) + (value_reg + (rv_neg (value_regs_get val 0)))) + +(rule 2 (neg $I128 val) + (i128_sub (value_regs_zero) val)) + + +;; Builds an instruction sequence that traps if the comparison succeeds. +(decl gen_trapif (IntCC XReg XReg TrapCode) InstOutput) +(rule (gen_trapif cc a b trap_code) + (side_effect (SideEffectNoResult.Inst (MInst.TrapIf a b cc trap_code)))) + +;; Builds an instruction sequence that traps if the input is non-zero. +(decl gen_trapnz (XReg TrapCode) InstOutput) +(rule (gen_trapnz test trap_code) + (gen_trapif (IntCC.NotEqual) test (zero_reg) trap_code)) + +;; Builds an instruction sequence that traps if the input is zero. +(decl gen_trapz (XReg TrapCode) InstOutput) +(rule (gen_trapz test trap_code) + (gen_trapif (IntCC.Equal) test (zero_reg) trap_code)) + +;; Converts bool to the corresponding {in,}equality condition +(type ZeroCond + (enum + Zero + NonZero)) + +(decl zero_cond_to_cc (ZeroCond) IntCC) +(rule (zero_cond_to_cc (ZeroCond.Zero)) (IntCC.Equal)) +(rule (zero_cond_to_cc (ZeroCond.NonZero)) (IntCC.NotEqual)) + +;; Builds an instruction sequence for wide trapz/nz +(decl gen_trapif_val_i128 (ZeroCond ValueRegs TrapCode) InstOutput) +(rule (gen_trapif_val_i128 zero_cond value trap_code) + (let ((lo XReg (value_regs_get value 0)) + (hi XReg (value_regs_get value 1)) + (test XReg (rv_or hi lo))) + (gen_trapif (zero_cond_to_cc zero_cond) test (zero_reg) trap_code))) + +;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_call (SigRef ExternalName RelocDistance ValueSlice) InstOutput) +(extern constructor gen_call gen_call) + +(decl gen_call_indirect (SigRef Value ValueSlice) InstOutput) +(extern constructor gen_call_indirect gen_call_indirect) + +;;; this is trying to imitate aarch64 `madd` instruction. +(decl madd (XReg XReg XReg) XReg) +(rule + (madd n m a) + (let + ((t XReg (rv_mul n m))) + (rv_add t a))) + +;;;; Helpers for bmask ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Generates either 0 if `Value` is zero or -1 otherwise. +(decl gen_bmask (Value) XReg) + +;; Base cases: use `snez` after a sign extension to ensure that the entire +;; register is defined. For i128 we test both the upper and lower half. +(rule 0 (gen_bmask val @ (value_type (fits_in_64 _))) + (let ((non_zero XReg (rv_snez (sext val)))) + (rv_neg non_zero))) +(rule 1 (gen_bmask val @ (value_type $I128)) + (let ((non_zero XReg (rv_snez (rv_or (value_regs_get val 0) (value_regs_get val 1))))) + (rv_neg non_zero))) + +;; If the input value is an `icmp` or an `fcmp` directly then the `snez` can +;; be omitted because the result of the icmp or fcmp is a 0 or 1 directly. This +;; means we can go straight to the `neg` instruction to produce the final +;; result. +(rule 2 (gen_bmask val @ (maybe_uextend (icmp _ _ _))) (rv_neg val)) +(rule 2 (gen_bmask val @ (maybe_uextend (fcmp _ _ _))) (rv_neg val)) + +(decl lower_bmask (Value Type) ValueRegs) +(rule 0 (lower_bmask val (fits_in_64 _)) + (value_reg (gen_bmask val))) +(rule 1 (lower_bmask val $I128) + (let ((bits XReg (gen_bmask val))) + (value_regs bits bits))) + +;;;; Helpers for physical registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_mov_from_preg (PReg) Reg) + +(rule + (gen_mov_from_preg rm) + (let ((rd WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.MovFromPReg rd rm)))) + rd)) + +(decl fp_reg () PReg) +(extern constructor fp_reg fp_reg) + +(decl sp_reg () PReg) +(extern constructor sp_reg sp_reg) + +;; Extractor that matches all registers, except the zero register +(decl non_zero_reg () XReg) +(extern extractor non_zero_reg is_non_zero_reg) + +;; Helper for creating the zero register. +(decl zero_reg () XReg) +(extern constructor zero_reg zero_reg) +(extern extractor zero_reg is_zero_reg) + +(decl value_regs_zero () ValueRegs) +(rule (value_regs_zero) + (value_regs (imm $I64 0) (imm $I64 0))) + +(decl writable_zero_reg () WritableReg) +(extern constructor writable_zero_reg writable_zero_reg) + + +;;;; Helpers for floating point comparisons ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type FloatCompare (enum + ;; The comparison succeeded if `r` is one + (One (r XReg)) + ;; The comparison succeeded if `r` is zero + (Zero (r XReg)) +)) + +(decl float_compare_invert (FloatCompare) FloatCompare) +(rule (float_compare_invert (FloatCompare.One r)) (FloatCompare.Zero r)) +(rule (float_compare_invert (FloatCompare.Zero r)) (FloatCompare.One r)) + +(decl float_to_int_compare (FloatCompare) IntegerCompare) +(rule (float_to_int_compare (FloatCompare.One r)) (cmp_nez r)) +(rule (float_to_int_compare (FloatCompare.Zero r)) (cmp_eqz r)) +(convert FloatCompare IntegerCompare float_to_int_compare) + +;; Compare two floating point numbers and return a zero/non-zero result. +(decl fcmp_to_float_compare (FloatCC Type FReg FReg) FloatCompare) + +;; Direct codegen for unordered comparisons is not that efficient, so invert +;; the comparison to get an ordered comparison and generate that. Then invert +;; the result to produce the final fcmp result. +(rule 0 (fcmp_to_float_compare cc ty a b) + (if-let true (floatcc_unordered cc)) + (float_compare_invert (fcmp_to_float_compare (floatcc_complement cc) ty a b))) + +;; a is not nan && b is not nan +(rule 1 (fcmp_to_float_compare (FloatCC.Ordered) ty a b) + (FloatCompare.One (rv_and (is_not_nan ty a) (is_not_nan ty b)))) + +(decl is_not_nan (Type FReg) XReg) +(rule (is_not_nan ty a) (rv_feq ty a a)) + +;; a == b +(rule 1 (fcmp_to_float_compare (FloatCC.Equal) ty a b) + (FloatCompare.One (rv_feq ty a b))) + +;; a != b +;; == !(a == b) +(rule 1 (fcmp_to_float_compare (FloatCC.NotEqual) ty a b) + (FloatCompare.Zero (rv_feq ty a b))) + +;; a < b || a > b +(rule 1 (fcmp_to_float_compare (FloatCC.OrderedNotEqual) ty a b) + (FloatCompare.One (rv_or (rv_flt ty a b) (rv_fgt ty a b)))) + +;; a < b +(rule 1 (fcmp_to_float_compare (FloatCC.LessThan) ty a b) + (FloatCompare.One (rv_flt ty a b))) + +;; a <= b +(rule 1 (fcmp_to_float_compare (FloatCC.LessThanOrEqual) ty a b) + (FloatCompare.One (rv_fle ty a b))) + +;; a > b +(rule 1 (fcmp_to_float_compare (FloatCC.GreaterThan) ty a b) + (FloatCompare.One (rv_fgt ty a b))) + +;; a >= b +(rule 1 (fcmp_to_float_compare (FloatCC.GreaterThanOrEqual) ty a b) + (FloatCompare.One (rv_fge ty a b))) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/args.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/args.rs new file mode 100644 index 00000000000000..6c973b0685905b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/args.rs @@ -0,0 +1,1957 @@ +//! Riscv64 ISA definitions: instruction arguments. + +use super::*; +use crate::ir::condcodes::CondCode; + +use crate::isa::riscv64::lower::isle::generated_code::{ + COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp, +}; +use crate::machinst::isle::WritableReg; + +use std::fmt::Result; + +/// A macro for defining a newtype of `Reg` that enforces some invariant about +/// the wrapped `Reg` (such as that it is of a particular register class). +macro_rules! newtype_of_reg { + ( + $newtype_reg:ident, + $newtype_writable_reg:ident, + |$check_reg:ident| $check:expr + ) => { + /// A newtype wrapper around `Reg`. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $newtype_reg(Reg); + + impl PartialEq for $newtype_reg { + fn eq(&self, other: &Reg) -> bool { + self.0 == *other + } + } + + impl From<$newtype_reg> for Reg { + fn from(r: $newtype_reg) -> Self { + r.0 + } + } + + impl $newtype_reg { + /// Create this newtype from the given register, or return `None` if the register + /// is not a valid instance of this newtype. + pub fn new($check_reg: Reg) -> Option { + if $check { + Some(Self($check_reg)) + } else { + None + } + } + + /// Get this newtype's underlying `Reg`. + pub fn to_reg(self) -> Reg { + self.0 + } + } + + // Convenience impl so that people working with this newtype can use it + // "just like" a plain `Reg`. + // + // NB: We cannot implement `DerefMut` because that would let people do + // nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the + // invariants that `XReg` provides. + impl std::ops::Deref for $newtype_reg { + type Target = Reg; + + fn deref(&self) -> &Reg { + &self.0 + } + } + + /// Writable Reg. + pub type $newtype_writable_reg = Writable<$newtype_reg>; + }; +} + +// Newtypes for registers classes. +newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int); +newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float); +newtype_of_reg!(VReg, WritableVReg, |reg| reg.class() == RegClass::Vector); + +/// An addressing mode specified for a load/store operation. +#[derive(Clone, Debug, Copy)] +pub enum AMode { + /// Arbitrary offset from a register. Converted to generation of large + /// offsets with multiple instructions as necessary during code emission. + RegOffset(Reg, i64), + /// Offset from the stack pointer. + SPOffset(i64), + + /// Offset from the frame pointer. + FPOffset(i64), + + /// Offset into the slot area of the stack, which lies just above the + /// outgoing argument area that's setup by the function prologue. + /// At emission time, this is converted to `SPOffset` with a fixup added to + /// the offset constant. The fixup is a running value that is tracked as + /// emission iterates through instructions in linear order, and can be + /// adjusted up and down with [Inst::VirtualSPOffsetAdj]. + /// + /// The standard ABI is in charge of handling this (by emitting the + /// adjustment meta-instructions). See the diagram in the documentation + /// for [crate::isa::aarch64::abi](the ABI module) for more details. + SlotOffset(i64), + + /// Offset into the argument area. + IncomingArg(i64), + + /// A reference to a constant which is placed outside of the function's + /// body, typically at the end. + Const(VCodeConstant), + + /// A reference to a label. + Label(MachLabel), +} + +impl AMode { + /// Add the registers referenced by this AMode to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + AMode::RegOffset(reg, ..) => collector.reg_use(reg), + // Registers used in these modes aren't allocatable. + AMode::SPOffset(..) + | AMode::FPOffset(..) + | AMode::SlotOffset(..) + | AMode::IncomingArg(..) + | AMode::Const(..) + | AMode::Label(..) => {} + } + } + + pub(crate) fn get_base_register(&self) -> Option { + match self { + &AMode::RegOffset(reg, ..) => Some(reg), + &AMode::SPOffset(..) => Some(stack_reg()), + &AMode::FPOffset(..) => Some(fp_reg()), + &AMode::SlotOffset(..) => Some(stack_reg()), + &AMode::IncomingArg(..) => Some(stack_reg()), + &AMode::Const(..) | AMode::Label(..) => None, + } + } + + pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 { + match self { + &AMode::SlotOffset(offset) => { + offset + i64::from(state.frame_layout().outgoing_args_size) + } + + // Compute the offset into the incoming argument area relative to SP + &AMode::IncomingArg(offset) => { + let frame_layout = state.frame_layout(); + let sp_offset = frame_layout.tail_args_size + + frame_layout.setup_area_size + + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size; + i64::from(sp_offset) - offset + } + + &AMode::RegOffset(_, offset) => offset, + &AMode::SPOffset(offset) => offset, + &AMode::FPOffset(offset) => offset, + &AMode::Const(_) | &AMode::Label(_) => 0, + } + } + + /// Retrieve a MachLabel that corresponds to this addressing mode, if it exists. + pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer) -> Option { + match self { + &AMode::Const(addr) => Some(sink.get_label_for_constant(addr)), + &AMode::Label(label) => Some(label), + &AMode::RegOffset(..) + | &AMode::SPOffset(..) + | &AMode::FPOffset(..) + | &AMode::IncomingArg(..) + | &AMode::SlotOffset(..) => None, + } + } +} + +impl Display for AMode { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self { + &AMode::RegOffset(r, offset, ..) => { + write!(f, "{}({})", offset, reg_name(r)) + } + &AMode::SPOffset(offset, ..) => { + write!(f, "{offset}(sp)") + } + &AMode::SlotOffset(offset, ..) => { + write!(f, "{offset}(slot)") + } + &AMode::IncomingArg(offset) => { + write!(f, "-{offset}(incoming_arg)") + } + &AMode::FPOffset(offset, ..) => { + write!(f, "{offset}(fp)") + } + &AMode::Const(addr, ..) => { + write!(f, "[const({})]", addr.as_u32()) + } + &AMode::Label(label) => { + write!(f, "[label{}]", label.as_u32()) + } + } + } +} + +impl Into for StackAMode { + fn into(self) -> AMode { + match self { + StackAMode::IncomingArg(offset, stack_args_size) => { + AMode::IncomingArg(i64::from(stack_args_size) - offset) + } + StackAMode::OutgoingArg(offset) => AMode::SPOffset(offset), + StackAMode::Slot(offset) => AMode::SlotOffset(offset), + } + } +} + +/// risc-v always take two register to compare +#[derive(Clone, Copy, Debug)] +pub struct IntegerCompare { + pub(crate) kind: IntCC, + pub(crate) rs1: Reg, + pub(crate) rs2: Reg, +} + +pub(crate) enum BranchFunct3 { + // == + Eq, + // != + Ne, + // signed < + Lt, + // signed >= + Ge, + // unsigned < + Ltu, + // unsigned >= + Geu, +} + +impl BranchFunct3 { + pub(crate) fn funct3(self) -> u32 { + match self { + BranchFunct3::Eq => 0b000, + BranchFunct3::Ne => 0b001, + BranchFunct3::Lt => 0b100, + BranchFunct3::Ge => 0b101, + BranchFunct3::Ltu => 0b110, + BranchFunct3::Geu => 0b111, + } + } +} + +impl IntegerCompare { + pub(crate) fn op_code(self) -> u32 { + 0b1100011 + } + + // funct3 and if need inverse the register + pub(crate) fn funct3(&self) -> (BranchFunct3, bool) { + match self.kind { + IntCC::Equal => (BranchFunct3::Eq, false), + IntCC::NotEqual => (BranchFunct3::Ne, false), + IntCC::SignedLessThan => (BranchFunct3::Lt, false), + IntCC::SignedGreaterThanOrEqual => (BranchFunct3::Ge, false), + + IntCC::SignedGreaterThan => (BranchFunct3::Lt, true), + IntCC::SignedLessThanOrEqual => (BranchFunct3::Ge, true), + + IntCC::UnsignedLessThan => (BranchFunct3::Ltu, false), + IntCC::UnsignedGreaterThanOrEqual => (BranchFunct3::Geu, false), + + IntCC::UnsignedGreaterThan => (BranchFunct3::Ltu, true), + IntCC::UnsignedLessThanOrEqual => (BranchFunct3::Geu, true), + } + } + + #[inline] + pub(crate) fn op_name(&self) -> &'static str { + match self.kind { + IntCC::Equal => "beq", + IntCC::NotEqual => "bne", + IntCC::SignedLessThan => "blt", + IntCC::SignedGreaterThanOrEqual => "bge", + IntCC::SignedGreaterThan => "bgt", + IntCC::SignedLessThanOrEqual => "ble", + IntCC::UnsignedLessThan => "bltu", + IntCC::UnsignedGreaterThanOrEqual => "bgeu", + IntCC::UnsignedGreaterThan => "bgtu", + IntCC::UnsignedLessThanOrEqual => "bleu", + } + } + + pub(crate) fn emit(self) -> u32 { + let (funct3, reverse) = self.funct3(); + let (rs1, rs2) = if reverse { + (self.rs2, self.rs1) + } else { + (self.rs1, self.rs2) + }; + + self.op_code() + | funct3.funct3() << 12 + | reg_to_gpr_num(rs1) << 15 + | reg_to_gpr_num(rs2) << 20 + } + + pub(crate) fn inverse(self) -> Self { + Self { + kind: self.kind.complement(), + ..self + } + } + + pub(crate) fn regs(&self) -> [Reg; 2] { + [self.rs1, self.rs2] + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct FliConstant(u8); + +impl FliConstant { + pub(crate) fn new(value: u8) -> Self { + debug_assert!(value <= 31, "Invalid FliConstant: {value}"); + Self(value) + } + + pub(crate) fn maybe_from_u64(ty: Type, imm: u64) -> Option { + // Convert the value into an F64, this allows us to represent + // values from both f32 and f64 in the same value. + let value = match ty { + F32 => f32::from_bits(imm as u32) as f64, + F64 => f64::from_bits(imm), + _ => unimplemented!(), + }; + + Some(match (ty, value) { + (_, f) if f == -1.0 => Self::new(0), + + // Since f64 can represent all f32 values, f32::min_positive won't be + // the same as f64::min_positive, so we need to check for both indepenendtly + (F32, f) if f == (f32::MIN_POSITIVE as f64) => Self::new(1), + (F64, f) if f == f64::MIN_POSITIVE => Self::new(1), + + (_, f) if f == 2.0f64.powi(-16) => Self::new(2), + (_, f) if f == 2.0f64.powi(-15) => Self::new(3), + (_, f) if f == 2.0f64.powi(-8) => Self::new(4), + (_, f) if f == 2.0f64.powi(-7) => Self::new(5), + (_, f) if f == 0.0625 => Self::new(6), + (_, f) if f == 0.125 => Self::new(7), + (_, f) if f == 0.25 => Self::new(8), + (_, f) if f == 0.3125 => Self::new(9), + (_, f) if f == 0.375 => Self::new(10), + (_, f) if f == 0.4375 => Self::new(11), + (_, f) if f == 0.5 => Self::new(12), + (_, f) if f == 0.625 => Self::new(13), + (_, f) if f == 0.75 => Self::new(14), + (_, f) if f == 0.875 => Self::new(15), + (_, f) if f == 1.0 => Self::new(16), + (_, f) if f == 1.25 => Self::new(17), + (_, f) if f == 1.5 => Self::new(18), + (_, f) if f == 1.75 => Self::new(19), + (_, f) if f == 2.0 => Self::new(20), + (_, f) if f == 2.5 => Self::new(21), + (_, f) if f == 3.0 => Self::new(22), + (_, f) if f == 4.0 => Self::new(23), + (_, f) if f == 8.0 => Self::new(24), + (_, f) if f == 16.0 => Self::new(25), + (_, f) if f == 128.0 => Self::new(26), + (_, f) if f == 256.0 => Self::new(27), + (_, f) if f == 32768.0 => Self::new(28), + (_, f) if f == 65536.0 => Self::new(29), + (_, f) if f == f64::INFINITY => Self::new(30), + + // NaN's are not guaranteed to preserve the sign / payload bits, so we need to check + // the original bits directly. + (F32, f) if f.is_nan() && imm == 0x7fc0_0000 => Self::new(31), // Canonical NaN + (F64, f) if f.is_nan() && imm == 0x7ff8_0000_0000_0000 => Self::new(31), // Canonical NaN + _ => return None, + }) + } + + pub(crate) fn format(self) -> &'static str { + // The preferred assembly syntax for entries 1, 30, and 31 is min, inf, and nan, respectively. + // For entries 0 through 29 (including entry 1), the assembler will accept decimal constants + // in C-like syntax. + match self.0 { + 0 => "-1.0", + 1 => "min", + 2 => "2^-16", + 3 => "2^-15", + 4 => "2^-8", + 5 => "2^-7", + 6 => "0.0625", + 7 => "0.125", + 8 => "0.25", + 9 => "0.3125", + 10 => "0.375", + 11 => "0.4375", + 12 => "0.5", + 13 => "0.625", + 14 => "0.75", + 15 => "0.875", + 16 => "1.0", + 17 => "1.25", + 18 => "1.5", + 19 => "1.75", + 20 => "2.0", + 21 => "2.5", + 22 => "3.0", + 23 => "4.0", + 24 => "8.0", + 25 => "16.0", + 26 => "128.0", + 27 => "256.0", + 28 => "32768.0", + 29 => "65536.0", + 30 => "inf", + 31 => "nan", + _ => panic!("Invalid FliConstant"), + } + } + + pub(crate) fn bits(self) -> u8 { + self.0 + } +} + +impl FpuOPRRRR { + pub(crate) fn op_name(self, width: FpuOPWidth) -> String { + match self { + Self::Fmadd => format!("fmadd.{width}"), + Self::Fmsub => format!("fmsub.{width}"), + Self::Fnmsub => format!("fnmsub.{width}"), + Self::Fnmadd => format!("fnmadd.{width}"), + } + } + + pub(crate) fn opcode(self) -> u32 { + match self { + Self::Fmadd => 0b1000011, + Self::Fmsub => 0b1000111, + Self::Fnmsub => 0b1001011, + Self::Fnmadd => 0b1001111, + } + } +} + +impl FpuOPRR { + pub(crate) fn op_name(self, width: FpuOPWidth) -> String { + let fmv_width = match width { + FpuOPWidth::H => "h", + FpuOPWidth::S => "w", + FpuOPWidth::D => "d", + FpuOPWidth::Q => "q", + }; + match self { + Self::Fsqrt => format!("fsqrt.{width}"), + Self::Fround => format!("fround.{width}"), + Self::Fclass => format!("fclass.{width}"), + Self::FcvtWFmt => format!("fcvt.w.{width}"), + Self::FcvtWuFmt => format!("fcvt.wu.{width}"), + Self::FcvtLFmt => format!("fcvt.l.{width}"), + Self::FcvtLuFmt => format!("fcvt.lu.{width}"), + Self::FcvtFmtW => format!("fcvt.{width}.w"), + Self::FcvtFmtWu => format!("fcvt.{width}.wu"), + Self::FcvtFmtL => format!("fcvt.{width}.l"), + Self::FcvtFmtLu => format!("fcvt.{width}.lu"), + + // fmv instructions deviate from the normal encoding and instead + // encode the width as "w" instead of "s". The ISA manual gives this rationale: + // + // Instructions FMV.S.X and FMV.X.S were renamed to FMV.W.X and FMV.X.W respectively + // to be more consistent with their semantics, which did not change. The old names will continue + // to be supported in the tools. + Self::FmvXFmt => format!("fmv.x.{fmv_width}"), + Self::FmvFmtX => format!("fmv.{fmv_width}.x"), + + Self::FcvtSD => "fcvt.s.d".to_string(), + Self::FcvtDS => "fcvt.d.s".to_string(), + } + } + + pub(crate) fn is_convert_to_int(self) -> bool { + match self { + Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true, + _ => false, + } + } + + pub(crate) fn has_frm(self) -> bool { + match self { + FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false, + _ => true, + } + } + + pub(crate) fn opcode(self) -> u32 { + // OP-FP Major opcode + 0b1010011 + } + + pub(crate) fn rs2(self) -> u32 { + match self { + Self::Fsqrt => 0b00000, + Self::Fround => 0b00100, + Self::Fclass => 0b00000, + Self::FcvtWFmt => 0b00000, + Self::FcvtWuFmt => 0b00001, + Self::FcvtLFmt => 0b00010, + Self::FcvtLuFmt => 0b00011, + Self::FcvtFmtW => 0b00000, + Self::FcvtFmtWu => 0b00001, + Self::FcvtFmtL => 0b00010, + Self::FcvtFmtLu => 0b00011, + Self::FmvXFmt => 0b00000, + Self::FmvFmtX => 0b00000, + Self::FcvtSD => 0b00001, + Self::FcvtDS => 0b00000, + } + } + + pub(crate) fn funct5(self) -> u32 { + match self { + Self::Fsqrt => 0b01011, + Self::Fround => 0b01000, + Self::Fclass => 0b11100, + Self::FcvtWFmt => 0b11000, + Self::FcvtWuFmt => 0b11000, + Self::FcvtLFmt => 0b11000, + Self::FcvtLuFmt => 0b11000, + Self::FcvtFmtW => 0b11010, + Self::FcvtFmtWu => 0b11010, + Self::FcvtFmtL => 0b11010, + Self::FcvtFmtLu => 0b11010, + Self::FmvXFmt => 0b11100, + Self::FmvFmtX => 0b11110, + Self::FcvtSD => 0b01000, + Self::FcvtDS => 0b01000, + } + } + + pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 { + (self.funct5() << 2) | width.as_u32() + } +} + +impl FpuOPRRR { + pub(crate) fn op_name(self, width: FpuOPWidth) -> String { + match self { + Self::Fadd => format!("fadd.{width}"), + Self::Fsub => format!("fsub.{width}"), + Self::Fmul => format!("fmul.{width}"), + Self::Fdiv => format!("fdiv.{width}"), + Self::Fsgnj => format!("fsgnj.{width}"), + Self::Fsgnjn => format!("fsgnjn.{width}"), + Self::Fsgnjx => format!("fsgnjx.{width}"), + Self::Fmin => format!("fmin.{width}"), + Self::Fmax => format!("fmax.{width}"), + Self::Feq => format!("feq.{width}"), + Self::Flt => format!("flt.{width}"), + Self::Fle => format!("fle.{width}"), + Self::Fminm => format!("fminm.{width}"), + Self::Fmaxm => format!("fmaxm.{width}"), + } + } + + pub(crate) fn opcode(self) -> u32 { + // OP-FP Major opcode + 0b1010011 + } + + pub(crate) const fn funct5(self) -> u32 { + match self { + Self::Fadd => 0b00000, + Self::Fsub => 0b00001, + Self::Fmul => 0b00010, + Self::Fdiv => 0b00011, + Self::Fsgnj => 0b00100, + Self::Fsgnjn => 0b00100, + Self::Fsgnjx => 0b00100, + Self::Fmin => 0b00101, + Self::Fmax => 0b00101, + Self::Feq => 0b10100, + Self::Flt => 0b10100, + Self::Fle => 0b10100, + Self::Fminm => 0b00101, + Self::Fmaxm => 0b00101, + } + } + + pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 { + (self.funct5() << 2) | width.as_u32() + } + + pub(crate) fn has_frm(self) -> bool { + match self { + FpuOPRRR::Fsgnj + | FpuOPRRR::Fsgnjn + | FpuOPRRR::Fsgnjx + | FpuOPRRR::Fmin + | FpuOPRRR::Fmax + | FpuOPRRR::Feq + | FpuOPRRR::Flt + | FpuOPRRR::Fle => false, + _ => true, + } + } +} + +impl Display for FpuOPWidth { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!( + f, + "{}", + match self { + FpuOPWidth::H => "h", + FpuOPWidth::S => "s", + FpuOPWidth::D => "d", + FpuOPWidth::Q => "q", + } + ) + } +} + +impl TryFrom for FpuOPWidth { + type Error = &'static str; + + fn try_from(value: Type) -> std::result::Result { + match value { + F16 => Ok(FpuOPWidth::H), + F32 => Ok(FpuOPWidth::S), + F64 => Ok(FpuOPWidth::D), + F128 => Ok(FpuOPWidth::Q), + _ => Err("Invalid type for FpuOPWidth"), + } + } +} + +impl FpuOPWidth { + pub(crate) fn as_u32(&self) -> u32 { + match self { + FpuOPWidth::S => 0b00, + FpuOPWidth::D => 0b01, + FpuOPWidth::H => 0b10, + FpuOPWidth::Q => 0b11, + } + } +} + +impl AluOPRRR { + pub(crate) const fn op_name(self) -> &'static str { + match self { + Self::Add => "add", + Self::Sub => "sub", + Self::Sll => "sll", + Self::Slt => "slt", + Self::Sgt => "sgt", + Self::SltU => "sltu", + Self::Sgtu => "sgtu", + Self::Xor => "xor", + Self::Srl => "srl", + Self::Sra => "sra", + Self::Or => "or", + Self::And => "and", + Self::Addw => "addw", + Self::Subw => "subw", + Self::Sllw => "sllw", + Self::Srlw => "srlw", + Self::Sraw => "sraw", + Self::Mul => "mul", + Self::Mulh => "mulh", + Self::Mulhsu => "mulhsu", + Self::Mulhu => "mulhu", + Self::Div => "div", + Self::DivU => "divu", + Self::Rem => "rem", + Self::RemU => "remu", + Self::Mulw => "mulw", + Self::Divw => "divw", + Self::Divuw => "divuw", + Self::Remw => "remw", + Self::Remuw => "remuw", + Self::Adduw => "add.uw", + Self::Andn => "andn", + Self::Bclr => "bclr", + Self::Bext => "bext", + Self::Binv => "binv", + Self::Bset => "bset", + Self::Clmul => "clmul", + Self::Clmulh => "clmulh", + Self::Clmulr => "clmulr", + Self::Max => "max", + Self::Maxu => "maxu", + Self::Min => "min", + Self::Minu => "minu", + Self::Orn => "orn", + Self::Rol => "rol", + Self::Rolw => "rolw", + Self::Ror => "ror", + Self::Rorw => "rorw", + Self::Sh1add => "sh1add", + Self::Sh1adduw => "sh1add.uw", + Self::Sh2add => "sh2add", + Self::Sh2adduw => "sh2add.uw", + Self::Sh3add => "sh3add", + Self::Sh3adduw => "sh3add.uw", + Self::Xnor => "xnor", + Self::Pack => "pack", + Self::Packw => "packw", + Self::Packh => "packh", + Self::CzeroEqz => "czero.eqz", + Self::CzeroNez => "czero.nez", + } + } + + pub fn funct3(self) -> u32 { + match self { + AluOPRRR::Add => 0b000, + AluOPRRR::Sll => 0b001, + AluOPRRR::Slt => 0b010, + AluOPRRR::Sgt => 0b010, + AluOPRRR::SltU => 0b011, + AluOPRRR::Sgtu => 0b011, + AluOPRRR::Xor => 0b100, + AluOPRRR::Srl => 0b101, + AluOPRRR::Sra => 0b101, + AluOPRRR::Or => 0b110, + AluOPRRR::And => 0b111, + AluOPRRR::Sub => 0b000, + + AluOPRRR::Addw => 0b000, + AluOPRRR::Subw => 0b000, + AluOPRRR::Sllw => 0b001, + AluOPRRR::Srlw => 0b101, + AluOPRRR::Sraw => 0b101, + + AluOPRRR::Mul => 0b000, + AluOPRRR::Mulh => 0b001, + AluOPRRR::Mulhsu => 0b010, + AluOPRRR::Mulhu => 0b011, + AluOPRRR::Div => 0b100, + AluOPRRR::DivU => 0b101, + AluOPRRR::Rem => 0b110, + AluOPRRR::RemU => 0b111, + + AluOPRRR::Mulw => 0b000, + AluOPRRR::Divw => 0b100, + AluOPRRR::Divuw => 0b101, + AluOPRRR::Remw => 0b110, + AluOPRRR::Remuw => 0b111, + + // Zbb + AluOPRRR::Adduw => 0b000, + AluOPRRR::Andn => 0b111, + AluOPRRR::Bclr => 0b001, + AluOPRRR::Bext => 0b101, + AluOPRRR::Binv => 0b001, + AluOPRRR::Bset => 0b001, + AluOPRRR::Clmul => 0b001, + AluOPRRR::Clmulh => 0b011, + AluOPRRR::Clmulr => 0b010, + AluOPRRR::Max => 0b110, + AluOPRRR::Maxu => 0b111, + AluOPRRR::Min => 0b100, + AluOPRRR::Minu => 0b101, + AluOPRRR::Orn => 0b110, + AluOPRRR::Rol => 0b001, + AluOPRRR::Rolw => 0b001, + AluOPRRR::Ror => 0b101, + AluOPRRR::Rorw => 0b101, + AluOPRRR::Sh1add => 0b010, + AluOPRRR::Sh1adduw => 0b010, + AluOPRRR::Sh2add => 0b100, + AluOPRRR::Sh2adduw => 0b100, + AluOPRRR::Sh3add => 0b110, + AluOPRRR::Sh3adduw => 0b110, + AluOPRRR::Xnor => 0b100, + + // Zbkb + AluOPRRR::Pack => 0b100, + AluOPRRR::Packw => 0b100, + AluOPRRR::Packh => 0b111, + + // ZiCond + AluOPRRR::CzeroEqz => 0b101, + AluOPRRR::CzeroNez => 0b111, + } + } + + pub fn op_code(self) -> u32 { + match self { + AluOPRRR::Add + | AluOPRRR::Sub + | AluOPRRR::Sll + | AluOPRRR::Slt + | AluOPRRR::Sgt + | AluOPRRR::SltU + | AluOPRRR::Sgtu + | AluOPRRR::Xor + | AluOPRRR::Srl + | AluOPRRR::Sra + | AluOPRRR::Or + | AluOPRRR::And + | AluOPRRR::Pack + | AluOPRRR::Packh => 0b0110011, + + AluOPRRR::Addw + | AluOPRRR::Subw + | AluOPRRR::Sllw + | AluOPRRR::Srlw + | AluOPRRR::Sraw + | AluOPRRR::Packw => 0b0111011, + + AluOPRRR::Mul + | AluOPRRR::Mulh + | AluOPRRR::Mulhsu + | AluOPRRR::Mulhu + | AluOPRRR::Div + | AluOPRRR::DivU + | AluOPRRR::Rem + | AluOPRRR::RemU => 0b0110011, + + AluOPRRR::Mulw + | AluOPRRR::Divw + | AluOPRRR::Divuw + | AluOPRRR::Remw + | AluOPRRR::Remuw => 0b0111011, + + AluOPRRR::Adduw => 0b0111011, + AluOPRRR::Andn + | AluOPRRR::Bclr + | AluOPRRR::Bext + | AluOPRRR::Binv + | AluOPRRR::Bset + | AluOPRRR::Clmul + | AluOPRRR::Clmulh + | AluOPRRR::Clmulr + | AluOPRRR::Max + | AluOPRRR::Maxu + | AluOPRRR::Min + | AluOPRRR::Minu + | AluOPRRR::Orn + | AluOPRRR::Rol + | AluOPRRR::Ror + | AluOPRRR::Sh1add + | AluOPRRR::Sh2add + | AluOPRRR::Sh3add + | AluOPRRR::Xnor + | AluOPRRR::CzeroEqz + | AluOPRRR::CzeroNez => 0b0110011, + + AluOPRRR::Rolw + | AluOPRRR::Rorw + | AluOPRRR::Sh2adduw + | AluOPRRR::Sh3adduw + | AluOPRRR::Sh1adduw => 0b0111011, + } + } + + pub const fn funct7(self) -> u32 { + match self { + AluOPRRR::Add => 0b0000000, + AluOPRRR::Sub => 0b0100000, + AluOPRRR::Sll => 0b0000000, + AluOPRRR::Slt => 0b0000000, + AluOPRRR::Sgt => 0b0000000, + AluOPRRR::SltU => 0b0000000, + AluOPRRR::Sgtu => 0b0000000, + + AluOPRRR::Xor => 0b0000000, + AluOPRRR::Srl => 0b0000000, + AluOPRRR::Sra => 0b0100000, + AluOPRRR::Or => 0b0000000, + AluOPRRR::And => 0b0000000, + + AluOPRRR::Addw => 0b0000000, + AluOPRRR::Subw => 0b0100000, + AluOPRRR::Sllw => 0b0000000, + AluOPRRR::Srlw => 0b0000000, + AluOPRRR::Sraw => 0b0100000, + + AluOPRRR::Mul => 0b0000001, + AluOPRRR::Mulh => 0b0000001, + AluOPRRR::Mulhsu => 0b0000001, + AluOPRRR::Mulhu => 0b0000001, + AluOPRRR::Div => 0b0000001, + AluOPRRR::DivU => 0b0000001, + AluOPRRR::Rem => 0b0000001, + AluOPRRR::RemU => 0b0000001, + + AluOPRRR::Mulw => 0b0000001, + AluOPRRR::Divw => 0b0000001, + AluOPRRR::Divuw => 0b0000001, + AluOPRRR::Remw => 0b0000001, + AluOPRRR::Remuw => 0b0000001, + AluOPRRR::Adduw => 0b0000100, + AluOPRRR::Andn => 0b0100000, + AluOPRRR::Bclr => 0b0100100, + AluOPRRR::Bext => 0b0100100, + AluOPRRR::Binv => 0b0110100, + AluOPRRR::Bset => 0b0010100, + AluOPRRR::Clmul => 0b0000101, + AluOPRRR::Clmulh => 0b0000101, + AluOPRRR::Clmulr => 0b0000101, + AluOPRRR::Max => 0b0000101, + AluOPRRR::Maxu => 0b0000101, + AluOPRRR::Min => 0b0000101, + AluOPRRR::Minu => 0b0000101, + AluOPRRR::Orn => 0b0100000, + AluOPRRR::Rol => 0b0110000, + AluOPRRR::Rolw => 0b0110000, + AluOPRRR::Ror => 0b0110000, + AluOPRRR::Rorw => 0b0110000, + AluOPRRR::Sh1add => 0b0010000, + AluOPRRR::Sh1adduw => 0b0010000, + AluOPRRR::Sh2add => 0b0010000, + AluOPRRR::Sh2adduw => 0b0010000, + AluOPRRR::Sh3add => 0b0010000, + AluOPRRR::Sh3adduw => 0b0010000, + AluOPRRR::Xnor => 0b0100000, + + // Zbkb + AluOPRRR::Pack => 0b0000100, + AluOPRRR::Packw => 0b0000100, + AluOPRRR::Packh => 0b0000100, + + // ZiCond + AluOPRRR::CzeroEqz => 0b0000111, + AluOPRRR::CzeroNez => 0b0000111, + } + } + + pub(crate) fn reverse_rs(self) -> bool { + // special case. + // sgt and sgtu is not defined in isa. + // emit should reverse rs1 and rs2. + self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu + } +} + +impl AluOPRRI { + pub(crate) fn option_funct6(self) -> Option { + let x: Option = match self { + Self::Slli => Some(0b00_0000), + Self::Srli => Some(0b00_0000), + Self::Srai => Some(0b01_0000), + Self::Bclri => Some(0b010010), + Self::Bexti => Some(0b010010), + Self::Binvi => Some(0b011010), + Self::Bseti => Some(0b001010), + Self::Rori => Some(0b011000), + Self::SlliUw => Some(0b000010), + _ => None, + }; + x + } + + pub(crate) fn option_funct7(self) -> Option { + let x = match self { + Self::Slliw => Some(0b000_0000), + Self::SrliW => Some(0b000_0000), + Self::Sraiw => Some(0b010_0000), + Self::Roriw => Some(0b0110000), + _ => None, + }; + x + } + + pub(crate) fn imm12(self, imm12: Imm12) -> u32 { + let x = imm12.bits(); + if let Some(func) = self.option_funct6() { + func << 6 | (x & 0b11_1111) + } else if let Some(func) = self.option_funct7() { + func << 5 | (x & 0b1_1111) + } else if let Some(func) = self.option_funct12() { + func + } else { + x + } + } + + pub(crate) fn option_funct12(self) -> Option { + match self { + Self::Clz => Some(0b011000000000), + Self::Clzw => Some(0b011000000000), + Self::Cpop => Some(0b011000000010), + Self::Cpopw => Some(0b011000000010), + Self::Ctz => Some(0b011000000001), + Self::Ctzw => Some(0b011000000001), + Self::Rev8 => Some(0b011010111000), + Self::Sextb => Some(0b011000000100), + Self::Sexth => Some(0b011000000101), + Self::Zexth => Some(0b000010000000), + Self::Orcb => Some(0b001010000111), + Self::Brev8 => Some(0b0110_1000_0111), + _ => None, + } + } + + pub(crate) fn op_name(self) -> &'static str { + match self { + Self::Addi => "addi", + Self::Slti => "slti", + Self::SltiU => "sltiu", + Self::Xori => "xori", + Self::Ori => "ori", + Self::Andi => "andi", + Self::Slli => "slli", + Self::Srli => "srli", + Self::Srai => "srai", + Self::Addiw => "addiw", + Self::Slliw => "slliw", + Self::SrliW => "srliw", + Self::Sraiw => "sraiw", + Self::Bclri => "bclri", + Self::Bexti => "bexti", + Self::Binvi => "binvi", + Self::Bseti => "bseti", + Self::Rori => "rori", + Self::Roriw => "roriw", + Self::SlliUw => "slli.uw", + Self::Clz => "clz", + Self::Clzw => "clzw", + Self::Cpop => "cpop", + Self::Cpopw => "cpopw", + Self::Ctz => "ctz", + Self::Ctzw => "ctzw", + Self::Rev8 => "rev8", + Self::Sextb => "sext.b", + Self::Sexth => "sext.h", + Self::Zexth => "zext.h", + Self::Orcb => "orc.b", + Self::Brev8 => "brev8", + } + } + + pub fn funct3(self) -> u32 { + match self { + AluOPRRI::Addi => 0b000, + AluOPRRI::Slti => 0b010, + AluOPRRI::SltiU => 0b011, + AluOPRRI::Xori => 0b100, + AluOPRRI::Ori => 0b110, + AluOPRRI::Andi => 0b111, + AluOPRRI::Slli => 0b001, + AluOPRRI::Srli => 0b101, + AluOPRRI::Srai => 0b101, + AluOPRRI::Addiw => 0b000, + AluOPRRI::Slliw => 0b001, + AluOPRRI::SrliW => 0b101, + AluOPRRI::Sraiw => 0b101, + AluOPRRI::Bclri => 0b001, + AluOPRRI::Bexti => 0b101, + AluOPRRI::Binvi => 0b001, + AluOPRRI::Bseti => 0b001, + AluOPRRI::Rori => 0b101, + AluOPRRI::Roriw => 0b101, + AluOPRRI::SlliUw => 0b001, + AluOPRRI::Clz => 0b001, + AluOPRRI::Clzw => 0b001, + AluOPRRI::Cpop => 0b001, + AluOPRRI::Cpopw => 0b001, + AluOPRRI::Ctz => 0b001, + AluOPRRI::Ctzw => 0b001, + AluOPRRI::Rev8 => 0b101, + AluOPRRI::Sextb => 0b001, + AluOPRRI::Sexth => 0b001, + AluOPRRI::Zexth => 0b100, + AluOPRRI::Orcb => 0b101, + AluOPRRI::Brev8 => 0b101, + } + } + + pub fn op_code(self) -> u32 { + match self { + AluOPRRI::Addi + | AluOPRRI::Slti + | AluOPRRI::SltiU + | AluOPRRI::Xori + | AluOPRRI::Ori + | AluOPRRI::Andi + | AluOPRRI::Slli + | AluOPRRI::Srli + | AluOPRRI::Srai + | AluOPRRI::Bclri + | AluOPRRI::Bexti + | AluOPRRI::Binvi + | AluOPRRI::Bseti + | AluOPRRI::Rori + | AluOPRRI::Clz + | AluOPRRI::Cpop + | AluOPRRI::Ctz + | AluOPRRI::Rev8 + | AluOPRRI::Sextb + | AluOPRRI::Sexth + | AluOPRRI::Orcb + | AluOPRRI::Brev8 => 0b0010011, + + AluOPRRI::Addiw + | AluOPRRI::Slliw + | AluOPRRI::SrliW + | AluOPRRI::Sraiw + | AluOPRRI::Roriw + | AluOPRRI::SlliUw + | AluOPRRI::Clzw + | AluOPRRI::Cpopw + | AluOPRRI::Ctzw => 0b0011011, + AluOPRRI::Zexth => 0b0111011, + } + } +} + +impl Default for FRM { + fn default() -> Self { + Self::Fcsr + } +} + +/// float rounding mode. +impl FRM { + pub(crate) fn to_static_str(self) -> &'static str { + match self { + FRM::RNE => "rne", + FRM::RTZ => "rtz", + FRM::RDN => "rdn", + FRM::RUP => "rup", + FRM::RMM => "rmm", + FRM::Fcsr => "fcsr", + } + } + + #[inline] + pub(crate) fn bits(self) -> u8 { + match self { + FRM::RNE => 0b000, + FRM::RTZ => 0b001, + FRM::RDN => 0b010, + FRM::RUP => 0b011, + FRM::RMM => 0b100, + FRM::Fcsr => 0b111, + } + } + pub(crate) fn as_u32(self) -> u32 { + self.bits() as u32 + } +} + +impl FFlagsException { + #[inline] + #[allow(dead_code)] + pub(crate) fn mask(self) -> u32 { + match self { + FFlagsException::NV => 1 << 4, + FFlagsException::DZ => 1 << 3, + FFlagsException::OF => 1 << 2, + FFlagsException::UF => 1 << 1, + FFlagsException::NX => 1 << 0, + } + } +} + +impl LoadOP { + pub(crate) fn op_name(self) -> &'static str { + match self { + Self::Lb => "lb", + Self::Lh => "lh", + Self::Lw => "lw", + Self::Lbu => "lbu", + Self::Lhu => "lhu", + Self::Lwu => "lwu", + Self::Ld => "ld", + Self::Flh => "flh", + Self::Flw => "flw", + Self::Fld => "fld", + } + } + + pub(crate) fn from_type(ty: Type) -> Self { + match ty { + F16 => Self::Flh, + F32 => Self::Flw, + F64 => Self::Fld, + I8 => Self::Lb, + I16 => Self::Lh, + I32 => Self::Lw, + I64 => Self::Ld, + _ => unreachable!(), + } + } + + pub(crate) fn size(&self) -> i64 { + match self { + Self::Lb | Self::Lbu => 1, + Self::Lh | Self::Lhu | Self::Flh => 2, + Self::Lw | Self::Lwu | Self::Flw => 4, + Self::Ld | Self::Fld => 8, + } + } + + pub(crate) fn op_code(self) -> u32 { + match self { + Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => { + 0b0000011 + } + Self::Flh | Self::Flw | Self::Fld => 0b0000111, + } + } + pub(crate) fn funct3(self) -> u32 { + match self { + Self::Lb => 0b000, + Self::Lh => 0b001, + Self::Lw => 0b010, + Self::Lwu => 0b110, + Self::Lbu => 0b100, + Self::Lhu => 0b101, + Self::Ld => 0b011, + Self::Flh => 0b001, + Self::Flw => 0b010, + Self::Fld => 0b011, + } + } +} + +impl StoreOP { + pub(crate) fn op_name(self) -> &'static str { + match self { + Self::Sb => "sb", + Self::Sh => "sh", + Self::Sw => "sw", + Self::Sd => "sd", + Self::Fsh => "fsh", + Self::Fsw => "fsw", + Self::Fsd => "fsd", + } + } + pub(crate) fn from_type(ty: Type) -> Self { + match ty { + F16 => Self::Fsh, + F32 => Self::Fsw, + F64 => Self::Fsd, + I8 => Self::Sb, + I16 => Self::Sh, + I32 => Self::Sw, + I64 => Self::Sd, + _ => unreachable!(), + } + } + + pub(crate) fn size(&self) -> i64 { + match self { + Self::Sb => 1, + Self::Sh | Self::Fsh => 2, + Self::Sw | Self::Fsw => 4, + Self::Sd | Self::Fsd => 8, + } + } + + pub(crate) fn op_code(self) -> u32 { + match self { + Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011, + Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111, + } + } + pub(crate) fn funct3(self) -> u32 { + match self { + Self::Sb => 0b000, + Self::Sh => 0b001, + Self::Sw => 0b010, + Self::Sd => 0b011, + Self::Fsh => 0b001, + Self::Fsw => 0b010, + Self::Fsd => 0b011, + } + } +} + +#[allow(dead_code)] +impl FClassResult { + pub(crate) const fn bit(self) -> u32 { + match self { + FClassResult::NegInfinite => 1 << 0, + FClassResult::NegNormal => 1 << 1, + FClassResult::NegSubNormal => 1 << 2, + FClassResult::NegZero => 1 << 3, + FClassResult::PosZero => 1 << 4, + FClassResult::PosSubNormal => 1 << 5, + FClassResult::PosNormal => 1 << 6, + FClassResult::PosInfinite => 1 << 7, + FClassResult::SNaN => 1 << 8, + FClassResult::QNaN => 1 << 9, + } + } + + #[inline] + pub(crate) const fn is_nan_bits() -> u32 { + Self::SNaN.bit() | Self::QNaN.bit() + } + #[inline] + pub(crate) fn is_zero_bits() -> u32 { + Self::NegZero.bit() | Self::PosZero.bit() + } + + #[inline] + pub(crate) fn is_infinite_bits() -> u32 { + Self::PosInfinite.bit() | Self::NegInfinite.bit() + } +} + +impl AtomicOP { + #[inline] + pub(crate) fn is_load(self) -> bool { + match self { + Self::LrW | Self::LrD => true, + _ => false, + } + } + + #[inline] + pub(crate) fn op_name(self, amo: AMO) -> String { + let s = match self { + Self::LrW => "lr.w", + Self::ScW => "sc.w", + + Self::AmoswapW => "amoswap.w", + Self::AmoaddW => "amoadd.w", + Self::AmoxorW => "amoxor.w", + Self::AmoandW => "amoand.w", + Self::AmoorW => "amoor.w", + Self::AmominW => "amomin.w", + Self::AmomaxW => "amomax.w", + Self::AmominuW => "amominu.w", + Self::AmomaxuW => "amomaxu.w", + Self::LrD => "lr.d", + Self::ScD => "sc.d", + Self::AmoswapD => "amoswap.d", + Self::AmoaddD => "amoadd.d", + Self::AmoxorD => "amoxor.d", + Self::AmoandD => "amoand.d", + Self::AmoorD => "amoor.d", + Self::AmominD => "amomin.d", + Self::AmomaxD => "amomax.d", + Self::AmominuD => "amominu.d", + Self::AmomaxuD => "amomaxu.d", + }; + format!("{}{}", s, amo.to_static_str()) + } + #[inline] + pub(crate) fn op_code(self) -> u32 { + 0b0101111 + } + + #[inline] + pub(crate) fn funct7(self, amo: AMO) -> u32 { + self.funct5() << 2 | amo.as_u32() & 0b11 + } + + pub(crate) fn funct3(self) -> u32 { + match self { + AtomicOP::LrW + | AtomicOP::ScW + | AtomicOP::AmoswapW + | AtomicOP::AmoaddW + | AtomicOP::AmoxorW + | AtomicOP::AmoandW + | AtomicOP::AmoorW + | AtomicOP::AmominW + | AtomicOP::AmomaxW + | AtomicOP::AmominuW + | AtomicOP::AmomaxuW => 0b010, + AtomicOP::LrD + | AtomicOP::ScD + | AtomicOP::AmoswapD + | AtomicOP::AmoaddD + | AtomicOP::AmoxorD + | AtomicOP::AmoandD + | AtomicOP::AmoorD + | AtomicOP::AmominD + | AtomicOP::AmomaxD + | AtomicOP::AmominuD + | AtomicOP::AmomaxuD => 0b011, + } + } + pub(crate) fn funct5(self) -> u32 { + match self { + AtomicOP::LrW => 0b00010, + AtomicOP::ScW => 0b00011, + AtomicOP::AmoswapW => 0b00001, + AtomicOP::AmoaddW => 0b00000, + AtomicOP::AmoxorW => 0b00100, + AtomicOP::AmoandW => 0b01100, + AtomicOP::AmoorW => 0b01000, + AtomicOP::AmominW => 0b10000, + AtomicOP::AmomaxW => 0b10100, + AtomicOP::AmominuW => 0b11000, + AtomicOP::AmomaxuW => 0b11100, + AtomicOP::LrD => 0b00010, + AtomicOP::ScD => 0b00011, + AtomicOP::AmoswapD => 0b00001, + AtomicOP::AmoaddD => 0b00000, + AtomicOP::AmoxorD => 0b00100, + AtomicOP::AmoandD => 0b01100, + AtomicOP::AmoorD => 0b01000, + AtomicOP::AmominD => 0b10000, + AtomicOP::AmomaxD => 0b10100, + AtomicOP::AmominuD => 0b11000, + AtomicOP::AmomaxuD => 0b11100, + } + } + + pub(crate) fn load_op(t: Type) -> Self { + if t.bits() <= 32 { + Self::LrW + } else { + Self::LrD + } + } + pub(crate) fn store_op(t: Type) -> Self { + if t.bits() <= 32 { + Self::ScW + } else { + Self::ScD + } + } + + /// extract + pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec { + let mut insts = SmallInstVec::new(); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Srl, + rd: rd, + rs1: rs, + rs2: offset, + }); + // + insts.push(Inst::Extend { + rd: rd, + rn: rd.to_reg(), + signed: false, + from_bits: ty.bits() as u8, + to_bits: 64, + }); + insts + } + + /// like extract but sign extend the value. + /// suitable for smax,etc. + pub(crate) fn extract_sext( + rd: WritableReg, + offset: Reg, + rs: Reg, + ty: Type, + ) -> SmallInstVec { + let mut insts = SmallInstVec::new(); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Srl, + rd: rd, + rs1: rs, + rs2: offset, + }); + // + insts.push(Inst::Extend { + rd: rd, + rn: rd.to_reg(), + signed: true, + from_bits: ty.bits() as u8, + to_bits: 64, + }); + insts + } + + pub(crate) fn unset( + rd: WritableReg, + tmp: WritableReg, + offset: Reg, + ty: Type, + ) -> SmallInstVec { + assert!(rd != tmp); + let mut insts = SmallInstVec::new(); + insts.extend(Inst::load_int_mask(tmp, ty)); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Sll, + rd: tmp, + rs1: tmp.to_reg(), + rs2: offset, + }); + insts.push(Inst::construct_bit_not(tmp, tmp.to_reg())); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: rd, + rs1: rd.to_reg(), + rs2: tmp.to_reg(), + }); + insts + } + + pub(crate) fn set( + rd: WritableReg, + tmp: WritableReg, + offset: Reg, + rs: Reg, + ty: Type, + ) -> SmallInstVec { + assert!(rd != tmp); + let mut insts = SmallInstVec::new(); + // make rs into tmp. + insts.push(Inst::Extend { + rd: tmp, + rn: rs, + signed: false, + from_bits: ty.bits() as u8, + to_bits: 64, + }); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Sll, + rd: tmp, + rs1: tmp.to_reg(), + rs2: offset, + }); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Or, + rd: rd, + rs1: rd.to_reg(), + rs2: tmp.to_reg(), + }); + insts + } + + /// Merge reset part of rs into rd. + /// Call this function must make sure that other part of value is already in rd. + pub(crate) fn merge( + rd: WritableReg, + tmp: WritableReg, + offset: Reg, + rs: Reg, + ty: Type, + ) -> SmallInstVec { + let mut insts = Self::unset(rd, tmp, offset, ty); + insts.extend(Self::set(rd, tmp, offset, rs, ty)); + insts + } +} + +///Atomic Memory ordering. +#[derive(Copy, Clone, Debug)] +pub enum AMO { + Relax = 0b00, + Release = 0b01, + Acquire = 0b10, + SeqCst = 0b11, +} + +impl AMO { + pub(crate) fn to_static_str(self) -> &'static str { + match self { + AMO::Relax => "", + AMO::Release => ".rl", + AMO::Acquire => ".aq", + AMO::SeqCst => ".aqrl", + } + } + pub(crate) fn as_u32(self) -> u32 { + self as u32 + } +} + +impl Inst { + /// fence request bits. + pub(crate) const FENCE_REQ_I: u8 = 1 << 3; + pub(crate) const FENCE_REQ_O: u8 = 1 << 2; + pub(crate) const FENCE_REQ_R: u8 = 1 << 1; + pub(crate) const FENCE_REQ_W: u8 = 1 << 0; + pub(crate) fn fence_req_to_string(x: u8) -> String { + let mut s = String::default(); + if x & Self::FENCE_REQ_I != 0 { + s.push_str("i"); + } + if x & Self::FENCE_REQ_O != 0 { + s.push_str("o"); + } + if x & Self::FENCE_REQ_R != 0 { + s.push_str("r"); + } + if x & Self::FENCE_REQ_W != 0 { + s.push_str("w"); + } + s + } +} + +pub(crate) fn f32_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f32, f32) { + match (signed, out_bits) { + (true, 8) => (i8::min_value() as f32 - 1., i8::max_value() as f32 + 1.), + (true, 16) => (i16::min_value() as f32 - 1., i16::max_value() as f32 + 1.), + (true, 32) => (-2147483904.0, 2147483648.0), + (true, 64) => (-9223373136366403584.0, 9223372036854775808.0), + (false, 8) => (-1., u8::max_value() as f32 + 1.), + (false, 16) => (-1., u16::max_value() as f32 + 1.), + (false, 32) => (-1., 4294967296.0), + (false, 64) => (-1., 18446744073709551616.0), + _ => unreachable!(), + } +} + +pub(crate) fn f64_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f64, f64) { + match (signed, out_bits) { + (true, 8) => (i8::min_value() as f64 - 1., i8::max_value() as f64 + 1.), + (true, 16) => (i16::min_value() as f64 - 1., i16::max_value() as f64 + 1.), + (true, 32) => (-2147483649.0, 2147483648.0), + (true, 64) => (-9223372036854777856.0, 9223372036854775808.0), + (false, 8) => (-1., u8::max_value() as f64 + 1.), + (false, 16) => (-1., u16::max_value() as f64 + 1.), + (false, 32) => (-1., 4294967296.0), + (false, 64) => (-1., 18446744073709551616.0), + _ => unreachable!(), + } +} + +impl CsrRegOP { + pub(crate) fn funct3(self) -> u32 { + match self { + CsrRegOP::CsrRW => 0b001, + CsrRegOP::CsrRS => 0b010, + CsrRegOP::CsrRC => 0b011, + } + } + + pub(crate) fn opcode(self) -> u32 { + 0b1110011 + } + + pub(crate) fn name(self) -> &'static str { + match self { + CsrRegOP::CsrRW => "csrrw", + CsrRegOP::CsrRS => "csrrs", + CsrRegOP::CsrRC => "csrrc", + } + } +} + +impl Display for CsrRegOP { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.name()) + } +} + +impl CsrImmOP { + pub(crate) fn funct3(self) -> u32 { + match self { + CsrImmOP::CsrRWI => 0b101, + CsrImmOP::CsrRSI => 0b110, + CsrImmOP::CsrRCI => 0b111, + } + } + + pub(crate) fn opcode(self) -> u32 { + 0b1110011 + } + + pub(crate) fn name(self) -> &'static str { + match self { + CsrImmOP::CsrRWI => "csrrwi", + CsrImmOP::CsrRSI => "csrrsi", + CsrImmOP::CsrRCI => "csrrci", + } + } +} + +impl Display for CsrImmOP { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.name()) + } +} + +impl CSR { + pub(crate) fn bits(self) -> Imm12 { + Imm12::from_i16(match self { + CSR::Frm => 0x0002, + }) + } + + pub(crate) fn name(self) -> &'static str { + match self { + CSR::Frm => "frm", + } + } +} + +impl Display for CSR { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.name()) + } +} + +impl COpcodeSpace { + pub fn bits(&self) -> u32 { + match self { + COpcodeSpace::C0 => 0b00, + COpcodeSpace::C1 => 0b01, + COpcodeSpace::C2 => 0b10, + } + } +} + +impl CrOp { + pub fn funct4(&self) -> u32 { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + // `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv. + CrOp::CMv | CrOp::CJr => 0b1000, + CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2, + } + } +} + +impl CaOp { + pub fn funct2(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CaOp::CAnd => 0b11, + CaOp::COr => 0b10, + CaOp::CXor => 0b01, + CaOp::CSub => 0b00, + CaOp::CAddw => 0b01, + CaOp::CSubw => 0b00, + CaOp::CMul => 0b10, + } + } + + pub fn funct6(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011, + CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CaOp::CAnd + | CaOp::COr + | CaOp::CXor + | CaOp::CSub + | CaOp::CAddw + | CaOp::CSubw + | CaOp::CMul => COpcodeSpace::C1, + } + } +} + +impl CjOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CjOp::CJ => 0b101, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CjOp::CJ => COpcodeSpace::C1, + } + } +} + +impl CiOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CiOp::CAddi | CiOp::CSlli => 0b000, + CiOp::CAddiw | CiOp::CFldsp => 0b001, + CiOp::CLi | CiOp::CLwsp => 0b010, + CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => { + COpcodeSpace::C1 + } + CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2, + } + } +} + +impl CiwOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CiwOp::CAddi4spn => 0b000, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CiwOp::CAddi4spn => COpcodeSpace::C0, + } + } +} + +impl CbOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100, + } + } + + pub fn funct2(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CbOp::CSrli => 0b00, + CbOp::CSrai => 0b01, + CbOp::CAndi => 0b10, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1, + } + } +} + +impl CssOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CssOp::CFsdsp => 0b101, + CssOp::CSwsp => 0b110, + CssOp::CSdsp => 0b111, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2, + } + } +} + +impl CsOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CsOp::CFsd => 0b101, + CsOp::CSw => 0b110, + CsOp::CSd => 0b111, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0, + } + } +} + +impl ClOp { + pub fn funct3(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + ClOp::CFld => 0b001, + ClOp::CLw => 0b010, + ClOp::CLd => 0b011, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0, + } + } +} + +impl CsznOp { + pub fn funct6(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CsznOp::CNot + | CsznOp::CZextw + | CsznOp::CZextb + | CsznOp::CZexth + | CsznOp::CSextb + | CsznOp::CSexth => 0b100_111, + } + } + + pub fn funct5(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + CsznOp::CNot => 0b11_101, + CsznOp::CZextb => 0b11_000, + CsznOp::CZexth => 0b11_010, + CsznOp::CZextw => 0b11_100, + CsznOp::CSextb => 0b11_001, + CsznOp::CSexth => 0b11_011, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + CsznOp::CNot + | CsznOp::CZextb + | CsznOp::CZexth + | CsznOp::CZextw + | CsznOp::CSextb + | CsznOp::CSexth => COpcodeSpace::C1, + } + } +} + +impl ZcbMemOp { + pub fn funct6(&self) -> u32 { + // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes + match self { + ZcbMemOp::CLbu => 0b100_000, + // These two opcodes are differentiated in the imm field of the instruction. + ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001, + ZcbMemOp::CSb => 0b100_010, + ZcbMemOp::CSh => 0b100_011, + } + } + + pub fn imm_bits(&self) -> u8 { + match self { + ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1, + ZcbMemOp::CLbu | ZcbMemOp::CSb => 2, + } + } + + pub fn op(&self) -> COpcodeSpace { + // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap + match self { + ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => { + COpcodeSpace::C0 + } + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit.rs new file mode 100644 index 00000000000000..2951e2a8f6db5b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit.rs @@ -0,0 +1,2685 @@ +//! Riscv64 ISA: binary code emission. + +use crate::ir::{self, LibCall, TrapCode}; +use crate::isa::riscv64::inst::*; +use crate::isa::riscv64::lower::isle::generated_code::{ + CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp, +}; +use cranelift_control::ControlPlane; + +pub struct EmitInfo { + shared_flag: settings::Flags, + isa_flags: super::super::riscv_settings::Flags, +} + +impl EmitInfo { + pub(crate) fn new( + shared_flag: settings::Flags, + isa_flags: super::super::riscv_settings::Flags, + ) -> Self { + Self { + shared_flag, + isa_flags, + } + } +} + +pub(crate) fn reg_to_gpr_num(m: Reg) -> u32 { + u32::from(m.to_real_reg().unwrap().hw_enc() & 31) +} + +pub(crate) fn reg_to_compressed_gpr_num(m: Reg) -> u32 { + let real_reg = m.to_real_reg().unwrap().hw_enc(); + debug_assert!(real_reg >= 8 && real_reg < 16); + let compressed_reg = real_reg - 8; + u32::from(compressed_reg) +} + +#[derive(Clone, Debug, PartialEq, Default)] +pub enum EmitVState { + #[default] + Unknown, + Known(VState), +} + +/// State carried between emissions of a sequence of instructions. +#[derive(Default, Clone, Debug)] +pub struct EmitState { + /// The user stack map for the upcoming instruction, as provided to + /// `pre_safepoint()`. + user_stack_map: Option, + + /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and + /// optimized away at compiletime. See [cranelift_control]. + ctrl_plane: ControlPlane, + + /// Vector State + /// Controls the current state of the vector unit at the emission point. + vstate: EmitVState, + + frame_layout: FrameLayout, +} + +impl EmitState { + fn take_stack_map(&mut self) -> Option { + self.user_stack_map.take() + } +} + +impl MachInstEmitState for EmitState { + fn new( + abi: &Callee, + ctrl_plane: ControlPlane, + ) -> Self { + EmitState { + user_stack_map: None, + ctrl_plane, + vstate: EmitVState::Unknown, + frame_layout: abi.frame_layout().clone(), + } + } + + fn pre_safepoint(&mut self, user_stack_map: Option) { + self.user_stack_map = user_stack_map; + } + + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane { + &mut self.ctrl_plane + } + + fn take_ctrl_plane(self) -> ControlPlane { + self.ctrl_plane + } + + fn on_new_block(&mut self) { + // Reset the vector state. + self.vstate = EmitVState::Unknown; + } + + fn frame_layout(&self) -> &FrameLayout { + &self.frame_layout + } +} + +impl Inst { + /// Load int mask. + /// If ty is int then 0xff in rd. + pub(crate) fn load_int_mask(rd: Writable, ty: Type) -> SmallInstVec { + let mut insts = SmallInstVec::new(); + assert!(ty.is_int() && ty.bits() <= 64); + match ty { + I64 => { + insts.push(Inst::load_imm12(rd, Imm12::from_i16(-1))); + } + I32 | I16 => { + insts.push(Inst::load_imm12(rd, Imm12::from_i16(-1))); + insts.push(Inst::Extend { + rd: rd, + rn: rd.to_reg(), + signed: false, + from_bits: ty.bits() as u8, + to_bits: 64, + }); + } + I8 => { + insts.push(Inst::load_imm12(rd, Imm12::from_i16(255))); + } + _ => unreachable!("ty:{:?}", ty), + } + insts + } + /// inverse all bit + pub(crate) fn construct_bit_not(rd: Writable, rs: Reg) -> Inst { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Xori, + rd, + rs, + imm12: Imm12::from_i16(-1), + } + } + + /// Returns Some(VState) if this instruction is expecting a specific vector state + /// before emission. + fn expected_vstate(&self) -> Option<&VState> { + match self { + Inst::Nop0 + | Inst::Nop4 + | Inst::BrTable { .. } + | Inst::Auipc { .. } + | Inst::Fli { .. } + | Inst::Lui { .. } + | Inst::LoadInlineConst { .. } + | Inst::AluRRR { .. } + | Inst::FpuRRR { .. } + | Inst::AluRRImm12 { .. } + | Inst::CsrReg { .. } + | Inst::CsrImm { .. } + | Inst::Load { .. } + | Inst::Store { .. } + | Inst::Args { .. } + | Inst::Rets { .. } + | Inst::Ret { .. } + | Inst::Extend { .. } + | Inst::Call { .. } + | Inst::CallInd { .. } + | Inst::ReturnCall { .. } + | Inst::ReturnCallInd { .. } + | Inst::Jal { .. } + | Inst::CondBr { .. } + | Inst::LoadExtName { .. } + | Inst::ElfTlsGetAddr { .. } + | Inst::LoadAddr { .. } + | Inst::Mov { .. } + | Inst::MovFromPReg { .. } + | Inst::Fence { .. } + | Inst::EBreak + | Inst::Udf { .. } + | Inst::FpuRR { .. } + | Inst::FpuRRRR { .. } + | Inst::Jalr { .. } + | Inst::Atomic { .. } + | Inst::Select { .. } + | Inst::AtomicCas { .. } + | Inst::RawData { .. } + | Inst::AtomicStore { .. } + | Inst::AtomicLoad { .. } + | Inst::AtomicRmwLoop { .. } + | Inst::TrapIf { .. } + | Inst::Unwind { .. } + | Inst::DummyUse { .. } + | Inst::Popcnt { .. } + | Inst::Cltz { .. } + | Inst::Brev8 { .. } + | Inst::StackProbeLoop { .. } => None, + + // VecSetState does not expect any vstate, rather it updates it. + Inst::VecSetState { .. } => None, + + // `vmv` instructions copy a set of registers and ignore vstate. + Inst::VecAluRRImm5 { op: VecAluOpRRImm5::VmvrV, .. } => None, + + Inst::VecAluRR { vstate, .. } | + Inst::VecAluRRR { vstate, .. } | + Inst::VecAluRRRR { vstate, .. } | + Inst::VecAluRImm5 { vstate, .. } | + Inst::VecAluRRImm5 { vstate, .. } | + Inst::VecAluRRRImm5 { vstate, .. } | + // TODO: Unit-stride loads and stores only need the AVL to be correct, not + // the full vtype. A future optimization could be to decouple these two when + // updating vstate. This would allow us to avoid emitting a VecSetState in + // some cases. + Inst::VecLoad { vstate, .. } + | Inst::VecStore { vstate, .. } => Some(vstate), + } + } +} + +impl MachInstEmit for Inst { + type State = EmitState; + type Info = EmitInfo; + + fn emit(&self, sink: &mut MachBuffer, emit_info: &Self::Info, state: &mut EmitState) { + // Check if we need to update the vector state before emitting this instruction + if let Some(expected) = self.expected_vstate() { + if state.vstate != EmitVState::Known(*expected) { + // Update the vector state. + Inst::VecSetState { + rd: writable_zero_reg(), + vstate: *expected, + } + .emit(sink, emit_info, state); + } + } + + // N.B.: we *must* not exceed the "worst-case size" used to compute + // where to insert islands, except when islands are explicitly triggered + // (with an `EmitIsland`). We check this in debug builds. This is `mut` + // to allow disabling the check for `JTSequence`, which is always + // emitted following an `EmitIsland`. + let mut start_off = sink.cur_offset(); + + // First try to emit this as a compressed instruction + let res = self.try_emit_compressed(sink, emit_info, state, &mut start_off); + if res.is_none() { + // If we can't lets emit it as a normal instruction + self.emit_uncompressed(sink, emit_info, state, &mut start_off); + } + + // We exclude br_table and return call from these checks since they emit + // their own islands, and thus are allowed to exceed the worst case size. + if !matches!( + self, + Inst::BrTable { .. } | Inst::ReturnCall { .. } | Inst::ReturnCallInd { .. } + ) { + let end_off = sink.cur_offset(); + assert!( + (end_off - start_off) <= Inst::worst_case_size(), + "Inst:{:?} length:{} worst_case_size:{}", + self, + end_off - start_off, + Inst::worst_case_size() + ); + } + } + + fn pretty_print_inst(&self, state: &mut Self::State) -> String { + self.print_with_state(state) + } +} + +impl Inst { + /// Tries to emit an instruction as compressed, if we can't return false. + fn try_emit_compressed( + &self, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, + start_off: &mut u32, + ) -> Option<()> { + let has_m = emit_info.isa_flags.has_m(); + let has_zba = emit_info.isa_flags.has_zba(); + let has_zbb = emit_info.isa_flags.has_zbb(); + let has_zca = emit_info.isa_flags.has_zca(); + let has_zcb = emit_info.isa_flags.has_zcb(); + let has_zcd = emit_info.isa_flags.has_zcd(); + + // Currently all compressed extensions (Zcb, Zcd, Zcmp, Zcmt, etc..) require Zca + // to be enabled, so check it early. + if !has_zca { + return None; + } + + fn reg_is_compressible(r: Reg) -> bool { + r.to_real_reg() + .map(|r| r.hw_enc() >= 8 && r.hw_enc() < 16) + .unwrap_or(false) + } + + match *self { + // C.ADD + Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd, + rs1, + rs2, + } if (rd.to_reg() == rs1 || rd.to_reg() == rs2) + && rs1 != zero_reg() + && rs2 != zero_reg() => + { + // Technically `c.add rd, rs` expands to `add rd, rd, rs`, but we can + // also swap rs1 with rs2 and we get an equivalent instruction. i.e we + // can also compress `add rd, rs, rd` into `c.add rd, rs`. + let src = if rd.to_reg() == rs1 { rs2 } else { rs1 }; + + sink.put2(encode_cr_type(CrOp::CAdd, rd, src)); + } + + // C.MV + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi | AluOPRRI::Ori, + rd, + rs, + imm12, + } if rd.to_reg() != rs + && rd.to_reg() != zero_reg() + && rs != zero_reg() + && imm12.as_i16() == 0 => + { + sink.put2(encode_cr_type(CrOp::CMv, rd, rs)); + } + + // CA Ops + Inst::AluRRR { + alu_op: + alu_op @ (AluOPRRR::And + | AluOPRRR::Or + | AluOPRRR::Xor + | AluOPRRR::Addw + | AluOPRRR::Mul), + rd, + rs1, + rs2, + } if (rd.to_reg() == rs1 || rd.to_reg() == rs2) + && reg_is_compressible(rs1) + && reg_is_compressible(rs2) => + { + let op = match alu_op { + AluOPRRR::And => CaOp::CAnd, + AluOPRRR::Or => CaOp::COr, + AluOPRRR::Xor => CaOp::CXor, + AluOPRRR::Addw => CaOp::CAddw, + AluOPRRR::Mul if has_zcb && has_m => CaOp::CMul, + _ => return None, + }; + // The canonical expansion for these instruction has `rd == rs1`, but + // these are all commutative operations, so we can swap the operands. + let src = if rd.to_reg() == rs1 { rs2 } else { rs1 }; + + sink.put2(encode_ca_type(op, rd, src)); + } + + // The sub instructions are non commutative, so we can't swap the operands. + Inst::AluRRR { + alu_op: alu_op @ (AluOPRRR::Sub | AluOPRRR::Subw), + rd, + rs1, + rs2, + } if rd.to_reg() == rs1 && reg_is_compressible(rs1) && reg_is_compressible(rs2) => { + let op = match alu_op { + AluOPRRR::Sub => CaOp::CSub, + AluOPRRR::Subw => CaOp::CSubw, + _ => return None, + }; + sink.put2(encode_ca_type(op, rd, rs2)); + } + + // c.j + // + // We don't have a separate JAL as that is only available in RV32C + Inst::Jal { label } => { + sink.use_label_at_offset(*start_off, label, LabelUse::RVCJump); + sink.add_uncond_branch(*start_off, *start_off + 2, label); + sink.put2(encode_cj_type(CjOp::CJ, Imm12::ZERO)); + } + + // c.jr + Inst::Jalr { rd, base, offset } + if rd.to_reg() == zero_reg() && base != zero_reg() && offset.as_i16() == 0 => + { + sink.put2(encode_cr2_type(CrOp::CJr, base)); + } + + // c.jalr + Inst::Jalr { rd, base, offset } + if rd.to_reg() == link_reg() && base != zero_reg() && offset.as_i16() == 0 => + { + sink.put2(encode_cr2_type(CrOp::CJalr, base)); + } + + // c.ebreak + Inst::EBreak => { + sink.put2(encode_cr_type( + CrOp::CEbreak, + writable_zero_reg(), + zero_reg(), + )); + } + + // c.unimp + Inst::Udf { trap_code } => { + sink.add_trap(trap_code); + sink.put2(0x0000); + } + // c.addi16sp + // + // c.addi16sp shares the opcode with c.lui, but has a destination field of x2. + // c.addi16sp adds the non-zero sign-extended 6-bit immediate to the value in the stack pointer (sp=x2), + // where the immediate is scaled to represent multiples of 16 in the range (-512,496). c.addi16sp is used + // to adjust the stack pointer in procedure prologues and epilogues. It expands into addi x2, x2, nzimm. c.addi16sp + // is only valid when nzimm≠0; the code point with nzimm=0 is reserved. + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + } if rd.to_reg() == rs + && rs == stack_reg() + && imm12.as_i16() != 0 + && (imm12.as_i16() % 16) == 0 + && Imm6::maybe_from_i16(imm12.as_i16() / 16).is_some() => + { + let imm6 = Imm6::maybe_from_i16(imm12.as_i16() / 16).unwrap(); + sink.put2(encode_c_addi16sp(imm6)); + } + + // c.addi4spn + // + // c.addi4spn is a CIW-format instruction that adds a zero-extended non-zero + // immediate, scaled by 4, to the stack pointer, x2, and writes the result to + // rd. This instruction is used to generate pointers to stack-allocated variables + // and expands to addi rd, x2, nzuimm. c.addi4spn is only valid when nzuimm≠0; + // the code points with nzuimm=0 are reserved. + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + } if reg_is_compressible(rd.to_reg()) + && rs == stack_reg() + && imm12.as_i16() != 0 + && (imm12.as_i16() % 4) == 0 + && u8::try_from(imm12.as_i16() / 4).is_ok() => + { + let imm = u8::try_from(imm12.as_i16() / 4).unwrap(); + sink.put2(encode_ciw_type(CiwOp::CAddi4spn, rd, imm)); + } + + // c.li + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + } if rd.to_reg() != zero_reg() && rs == zero_reg() => { + let imm6 = Imm6::maybe_from_imm12(imm12)?; + sink.put2(encode_ci_type(CiOp::CLi, rd, imm6)); + } + + // c.addi + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + } if rd.to_reg() == rs && rs != zero_reg() && imm12.as_i16() != 0 => { + let imm6 = Imm6::maybe_from_imm12(imm12)?; + sink.put2(encode_ci_type(CiOp::CAddi, rd, imm6)); + } + + // c.addiw + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addiw, + rd, + rs, + imm12, + } if rd.to_reg() == rs && rs != zero_reg() => { + let imm6 = Imm6::maybe_from_imm12(imm12)?; + sink.put2(encode_ci_type(CiOp::CAddiw, rd, imm6)); + } + + // c.lui + // + // c.lui loads the non-zero 6-bit immediate field into bits 17–12 + // of the destination register, clears the bottom 12 bits, and + // sign-extends bit 17 into all higher bits of the destination. + Inst::Lui { rd, imm: imm20 } + if rd.to_reg() != zero_reg() + && rd.to_reg() != stack_reg() + && imm20.as_i32() != 0 => + { + // Check that the top bits are sign extended + let imm = imm20.as_i32() << 14 >> 14; + if imm != imm20.as_i32() { + return None; + } + let imm6 = Imm6::maybe_from_i32(imm)?; + sink.put2(encode_ci_type(CiOp::CLui, rd, imm6)); + } + + // c.slli + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd, + rs, + imm12, + } if rd.to_reg() == rs && rs != zero_reg() && imm12.as_i16() != 0 => { + // The shift amount is unsigned, but we encode it as signed. + let shift = imm12.as_i16() & 0x3f; + let imm6 = Imm6::maybe_from_i16(shift << 10 >> 10).unwrap(); + sink.put2(encode_ci_type(CiOp::CSlli, rd, imm6)); + } + + // c.srli / c.srai + Inst::AluRRImm12 { + alu_op: op @ (AluOPRRI::Srli | AluOPRRI::Srai), + rd, + rs, + imm12, + } if rd.to_reg() == rs && reg_is_compressible(rs) && imm12.as_i16() != 0 => { + let op = match op { + AluOPRRI::Srli => CbOp::CSrli, + AluOPRRI::Srai => CbOp::CSrai, + _ => unreachable!(), + }; + + // The shift amount is unsigned, but we encode it as signed. + let shift = imm12.as_i16() & 0x3f; + let imm6 = Imm6::maybe_from_i16(shift << 10 >> 10).unwrap(); + sink.put2(encode_cb_type(op, rd, imm6)); + } + + // c.zextb + // + // This is an alias for `andi rd, rd, 0xff` + Inst::AluRRImm12 { + alu_op: AluOPRRI::Andi, + rd, + rs, + imm12, + } if has_zcb + && rd.to_reg() == rs + && reg_is_compressible(rs) + && imm12.as_i16() == 0xff => + { + sink.put2(encode_cszn_type(CsznOp::CZextb, rd)); + } + + // c.andi + Inst::AluRRImm12 { + alu_op: AluOPRRI::Andi, + rd, + rs, + imm12, + } if rd.to_reg() == rs && reg_is_compressible(rs) => { + let imm6 = Imm6::maybe_from_imm12(imm12)?; + sink.put2(encode_cb_type(CbOp::CAndi, rd, imm6)); + } + + // Stack Based Loads + Inst::Load { + rd, + op: op @ (LoadOP::Lw | LoadOP::Ld | LoadOP::Fld), + from, + flags, + } if from.get_base_register() == Some(stack_reg()) + && (from.get_offset_with_state(state) % op.size()) == 0 => + { + // We encode the offset in multiples of the load size. + let offset = from.get_offset_with_state(state); + let imm6 = u8::try_from(offset / op.size()) + .ok() + .and_then(Uimm6::maybe_from_u8)?; + + // Some additional constraints on these instructions. + // + // Integer loads are not allowed to target x0, but floating point loads + // are, since f0 is not a special register. + // + // Floating point loads are not included in the base Zca extension + // but in a separate Zcd extension. Both of these are part of the C Extension. + let rd_is_zero = rd.to_reg() == zero_reg(); + let op = match op { + LoadOP::Lw if !rd_is_zero => CiOp::CLwsp, + LoadOP::Ld if !rd_is_zero => CiOp::CLdsp, + LoadOP::Fld if has_zcd => CiOp::CFldsp, + _ => return None, + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + sink.put2(encode_ci_sp_load(op, rd, imm6)); + } + + // Regular Loads + Inst::Load { + rd, + op: + op + @ (LoadOP::Lw | LoadOP::Ld | LoadOP::Fld | LoadOP::Lbu | LoadOP::Lhu | LoadOP::Lh), + from, + flags, + } if reg_is_compressible(rd.to_reg()) + && from + .get_base_register() + .map(reg_is_compressible) + .unwrap_or(false) + && (from.get_offset_with_state(state) % op.size()) == 0 => + { + let base = from.get_base_register().unwrap(); + + // We encode the offset in multiples of the store size. + let offset = from.get_offset_with_state(state); + let offset = u8::try_from(offset / op.size()).ok()?; + + // We mix two different formats here. + // + // c.lw / c.ld / c.fld instructions are available in the standard Zca + // extension using the CL format. + // + // c.lbu / c.lhu / c.lh are only available in the Zcb extension and + // are also encoded differently. Technically they each have a different + // format, but they are similar enough that we can group them. + let is_zcb_load = matches!(op, LoadOP::Lbu | LoadOP::Lhu | LoadOP::Lh); + let encoded = if is_zcb_load { + if !has_zcb { + return None; + } + + let op = match op { + LoadOP::Lbu => ZcbMemOp::CLbu, + LoadOP::Lhu => ZcbMemOp::CLhu, + LoadOP::Lh => ZcbMemOp::CLh, + _ => unreachable!(), + }; + + // Byte stores & loads have 2 bits of immediate offset. Halfword stores + // and loads only have 1 bit. + let imm2 = Uimm2::maybe_from_u8(offset)?; + if (offset & !((1 << op.imm_bits()) - 1)) != 0 { + return None; + } + + encode_zcbmem_load(op, rd, base, imm2) + } else { + // Floating point loads are not included in the base Zca extension + // but in a separate Zcd extension. Both of these are part of the C Extension. + let op = match op { + LoadOP::Lw => ClOp::CLw, + LoadOP::Ld => ClOp::CLd, + LoadOP::Fld if has_zcd => ClOp::CFld, + _ => return None, + }; + let imm5 = Uimm5::maybe_from_u8(offset)?; + + encode_cl_type(op, rd, base, imm5) + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + sink.put2(encoded); + } + + // Stack Based Stores + Inst::Store { + src, + op: op @ (StoreOP::Sw | StoreOP::Sd | StoreOP::Fsd), + to, + flags, + } if to.get_base_register() == Some(stack_reg()) + && (to.get_offset_with_state(state) % op.size()) == 0 => + { + // We encode the offset in multiples of the store size. + let offset = to.get_offset_with_state(state); + let imm6 = u8::try_from(offset / op.size()) + .ok() + .and_then(Uimm6::maybe_from_u8)?; + + // Floating point stores are not included in the base Zca extension + // but in a separate Zcd extension. Both of these are part of the C Extension. + let op = match op { + StoreOP::Sw => CssOp::CSwsp, + StoreOP::Sd => CssOp::CSdsp, + StoreOP::Fsd if has_zcd => CssOp::CFsdsp, + _ => return None, + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + sink.put2(encode_css_type(op, src, imm6)); + } + + // Regular Stores + Inst::Store { + src, + op: op @ (StoreOP::Sw | StoreOP::Sd | StoreOP::Fsd | StoreOP::Sh | StoreOP::Sb), + to, + flags, + } if reg_is_compressible(src) + && to + .get_base_register() + .map(reg_is_compressible) + .unwrap_or(false) + && (to.get_offset_with_state(state) % op.size()) == 0 => + { + let base = to.get_base_register().unwrap(); + + // We encode the offset in multiples of the store size. + let offset = to.get_offset_with_state(state); + let offset = u8::try_from(offset / op.size()).ok()?; + + // We mix two different formats here. + // + // c.sw / c.sd / c.fsd instructions are available in the standard Zca + // extension using the CL format. + // + // c.sb / c.sh are only available in the Zcb extension and are also + // encoded differently. + let is_zcb_store = matches!(op, StoreOP::Sh | StoreOP::Sb); + let encoded = if is_zcb_store { + if !has_zcb { + return None; + } + + let op = match op { + StoreOP::Sh => ZcbMemOp::CSh, + StoreOP::Sb => ZcbMemOp::CSb, + _ => unreachable!(), + }; + + // Byte stores & loads have 2 bits of immediate offset. Halfword stores + // and loads only have 1 bit. + let imm2 = Uimm2::maybe_from_u8(offset)?; + if (offset & !((1 << op.imm_bits()) - 1)) != 0 { + return None; + } + + encode_zcbmem_store(op, src, base, imm2) + } else { + // Floating point stores are not included in the base Zca extension + // but in a separate Zcd extension. Both of these are part of the C Extension. + let op = match op { + StoreOP::Sw => CsOp::CSw, + StoreOP::Sd => CsOp::CSd, + StoreOP::Fsd if has_zcd => CsOp::CFsd, + _ => return None, + }; + let imm5 = Uimm5::maybe_from_u8(offset)?; + + encode_cs_type(op, src, base, imm5) + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + sink.put2(encoded); + } + + // c.not + // + // This is an alias for `xori rd, rd, -1` + Inst::AluRRImm12 { + alu_op: AluOPRRI::Xori, + rd, + rs, + imm12, + } if has_zcb + && rd.to_reg() == rs + && reg_is_compressible(rs) + && imm12.as_i16() == -1 => + { + sink.put2(encode_cszn_type(CsznOp::CNot, rd)); + } + + // c.sext.b / c.sext.h / c.zext.h + // + // These are all the extend instructions present in `Zcb`, they + // also require `Zbb` since they aren't available in the base ISA. + Inst::AluRRImm12 { + alu_op: alu_op @ (AluOPRRI::Sextb | AluOPRRI::Sexth | AluOPRRI::Zexth), + rd, + rs, + imm12, + } if has_zcb + && has_zbb + && rd.to_reg() == rs + && reg_is_compressible(rs) + && imm12.as_i16() == 0 => + { + let op = match alu_op { + AluOPRRI::Sextb => CsznOp::CSextb, + AluOPRRI::Sexth => CsznOp::CSexth, + AluOPRRI::Zexth => CsznOp::CZexth, + _ => unreachable!(), + }; + sink.put2(encode_cszn_type(op, rd)); + } + + // c.zext.w + // + // This is an alias for `add.uw rd, rd, zero` + Inst::AluRRR { + alu_op: AluOPRRR::Adduw, + rd, + rs1, + rs2, + } if has_zcb + && has_zba + && rd.to_reg() == rs1 + && reg_is_compressible(rs1) + && rs2 == zero_reg() => + { + sink.put2(encode_cszn_type(CsznOp::CZextw, rd)); + } + + _ => return None, + } + + return Some(()); + } + + fn emit_uncompressed( + &self, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, + start_off: &mut u32, + ) { + match self { + &Inst::Nop0 => { + // do nothing + } + // Addi x0, x0, 0 + &Inst::Nop4 => { + let x = Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: Writable::from_reg(zero_reg()), + rs: zero_reg(), + imm12: Imm12::ZERO, + }; + x.emit(sink, emit_info, state) + } + &Inst::RawData { ref data } => { + // Right now we only put a u32 or u64 in this instruction. + // It is not very long, no need to check if need `emit_island`. + // If data is very long , this is a bug because RawData is typically + // use to load some data and rely on some position in the code stream. + // and we may exceed `Inst::worst_case_size`. + // for more information see https://github.com/bytecodealliance/wasmtime/pull/5612. + sink.put_data(&data[..]); + } + &Inst::Lui { rd, ref imm } => { + let x: u32 = 0b0110111 | reg_to_gpr_num(rd.to_reg()) << 7 | (imm.bits() << 12); + sink.put4(x); + } + &Inst::Fli { rd, ty, imm } => { + sink.put4(encode_fli(ty, imm, rd)); + } + &Inst::LoadInlineConst { rd, ty, imm } => { + let data = &imm.to_le_bytes()[..ty.bytes() as usize]; + + let label_data: MachLabel = sink.get_label(); + let label_end: MachLabel = sink.get_label(); + + // Load into rd + Inst::Load { + rd, + op: LoadOP::from_type(ty), + flags: MemFlags::new(), + from: AMode::Label(label_data), + } + .emit(sink, emit_info, state); + + // Jump over the inline pool + Inst::gen_jump(label_end).emit(sink, emit_info, state); + + // Emit the inline data + sink.bind_label(label_data, &mut state.ctrl_plane); + Inst::RawData { data: data.into() }.emit(sink, emit_info, state); + + sink.bind_label(label_end, &mut state.ctrl_plane); + } + &Inst::FpuRR { + alu_op, + width, + frm, + rd, + rs, + } => { + if alu_op.is_convert_to_int() { + sink.add_trap(TrapCode::BAD_CONVERSION_TO_INTEGER); + } + sink.put4(encode_fp_rr(alu_op, width, frm, rd, rs)); + } + &Inst::FpuRRRR { + alu_op, + rd, + rs1, + rs2, + rs3, + frm, + width, + } => { + sink.put4(encode_fp_rrrr(alu_op, width, frm, rd, rs1, rs2, rs3)); + } + &Inst::FpuRRR { + alu_op, + width, + frm, + rd, + rs1, + rs2, + } => { + sink.put4(encode_fp_rrr(alu_op, width, frm, rd, rs1, rs2)); + } + &Inst::Unwind { ref inst } => { + sink.add_unwind(inst.clone()); + } + &Inst::DummyUse { .. } => { + // This has already been handled by Inst::allocate. + } + &Inst::AluRRR { + alu_op, + rd, + rs1, + rs2, + } => { + let (rs1, rs2) = if alu_op.reverse_rs() { + (rs2, rs1) + } else { + (rs1, rs2) + }; + + sink.put4(encode_r_type( + alu_op.op_code(), + rd, + alu_op.funct3(), + rs1, + rs2, + alu_op.funct7(), + )); + } + &Inst::AluRRImm12 { + alu_op, + rd, + rs, + imm12, + } => { + let x = alu_op.op_code() + | reg_to_gpr_num(rd.to_reg()) << 7 + | alu_op.funct3() << 12 + | reg_to_gpr_num(rs) << 15 + | alu_op.imm12(imm12) << 20; + sink.put4(x); + } + &Inst::CsrReg { op, rd, rs, csr } => { + sink.put4(encode_csr_reg(op, rd, rs, csr)); + } + &Inst::CsrImm { op, rd, csr, imm } => { + sink.put4(encode_csr_imm(op, rd, csr, imm)); + } + &Inst::Load { + rd, + op, + from, + flags, + } => { + let base = from.get_base_register(); + let offset = from.get_offset_with_state(state); + let offset_imm12 = Imm12::maybe_from_i64(offset); + let label = from.get_label_with_sink(sink); + + let (addr, imm12) = match (base, offset_imm12, label) { + // When loading from a Reg+Offset, if the offset fits into an imm12 we can directly encode it. + (Some(base), Some(imm12), None) => (base, imm12), + + // Otherwise, if the offset does not fit into a imm12, we need to materialize it into a + // register and load from that. + (Some(_), None, None) => { + let tmp = writable_spilltmp_reg(); + Inst::LoadAddr { rd: tmp, mem: from }.emit(sink, emit_info, state); + (tmp.to_reg(), Imm12::ZERO) + } + + // If the AMode contains a label we can emit an internal relocation that gets + // resolved with the correct address later. + (None, Some(imm), Some(label)) => { + debug_assert_eq!(imm.as_i16(), 0); + + // Get the current PC. + sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelHi20); + Inst::Auipc { + rd, + imm: Imm20::ZERO, + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // Emit a relocation for the load. This patches the offset into the instruction. + sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelLo12I); + + // Imm12 here is meaningless since it's going to get replaced. + (rd.to_reg(), Imm12::ZERO) + } + + // These cases are impossible with the current AModes that we have. We either + // always have a register, or always have a label. Never both, and never neither. + (None, None, None) + | (None, Some(_), None) + | (Some(_), None, Some(_)) + | (Some(_), Some(_), Some(_)) + | (None, None, Some(_)) => { + unreachable!("Invalid load address") + } + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + sink.put4(encode_i_type(op.op_code(), rd, op.funct3(), addr, imm12)); + } + &Inst::Store { op, src, flags, to } => { + let base = to.get_base_register(); + let offset = to.get_offset_with_state(state); + let offset_imm12 = Imm12::maybe_from_i64(offset); + + let (addr, imm12) = match (base, offset_imm12) { + // If the offset fits into an imm12 we can directly encode it. + (Some(base), Some(imm12)) => (base, imm12), + // Otherwise load the address it into a reg and load from it. + _ => { + let tmp = writable_spilltmp_reg(); + Inst::LoadAddr { rd: tmp, mem: to }.emit(sink, emit_info, state); + (tmp.to_reg(), Imm12::ZERO) + } + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + sink.put4(encode_s_type(op.op_code(), op.funct3(), addr, src, imm12)); + } + &Inst::Args { .. } | &Inst::Rets { .. } => { + // Nothing: this is a pseudoinstruction that serves + // only to constrain registers at a certain point. + } + &Inst::Ret {} => { + // RISC-V does not have a dedicated ret instruction, instead we emit the equivalent + // `jalr x0, x1, 0` that jumps to the return address. + Inst::Jalr { + rd: writable_zero_reg(), + base: link_reg(), + offset: Imm12::ZERO, + } + .emit(sink, emit_info, state); + } + + &Inst::Extend { + rd, + rn, + signed, + from_bits, + to_bits: _to_bits, + } => { + let mut insts = SmallInstVec::new(); + let shift_bits = (64 - from_bits) as i16; + let is_u8 = || from_bits == 8 && signed == false; + if is_u8() { + // special for u8. + insts.push(Inst::AluRRImm12 { + alu_op: AluOPRRI::Andi, + rd, + rs: rn, + imm12: Imm12::from_i16(255), + }); + } else { + insts.push(Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd, + rs: rn, + imm12: Imm12::from_i16(shift_bits), + }); + insts.push(Inst::AluRRImm12 { + alu_op: if signed { + AluOPRRI::Srai + } else { + AluOPRRI::Srli + }, + rd, + rs: rd.to_reg(), + imm12: Imm12::from_i16(shift_bits), + }); + } + insts + .into_iter() + .for_each(|i| i.emit(sink, emit_info, state)); + } + + &Inst::Call { ref info } => { + sink.add_call_site(); + sink.add_reloc(Reloc::RiscvCallPlt, &info.dest, 0); + + Inst::construct_auipc_and_jalr(Some(writable_link_reg()), writable_link_reg(), 0) + .into_iter() + .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + + let callee_pop_size = i32::try_from(info.callee_pop_size).unwrap(); + if callee_pop_size > 0 { + for inst in Riscv64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) { + inst.emit(sink, emit_info, state); + } + } + } + &Inst::CallInd { ref info } => { + Inst::Jalr { + rd: writable_link_reg(), + base: info.dest, + offset: Imm12::ZERO, + } + .emit(sink, emit_info, state); + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + + sink.add_call_site(); + + let callee_pop_size = i32::try_from(info.callee_pop_size).unwrap(); + if callee_pop_size > 0 { + for inst in Riscv64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) { + inst.emit(sink, emit_info, state); + } + } + } + + &Inst::ReturnCall { ref info } => { + emit_return_call_common_sequence(sink, emit_info, state, info); + + sink.add_call_site(); + sink.add_reloc(Reloc::RiscvCallPlt, &info.dest, 0); + Inst::construct_auipc_and_jalr(None, writable_spilltmp_reg(), 0) + .into_iter() + .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); + } + + &Inst::ReturnCallInd { ref info } => { + emit_return_call_common_sequence(sink, emit_info, state, &info); + + Inst::Jalr { + rd: writable_zero_reg(), + base: info.dest, + offset: Imm12::ZERO, + } + .emit(sink, emit_info, state); + } + &Inst::Jal { label } => { + sink.use_label_at_offset(*start_off, label, LabelUse::Jal20); + sink.add_uncond_branch(*start_off, *start_off + 4, label); + sink.put4(0b1101111); + } + &Inst::CondBr { + taken, + not_taken, + kind, + } => { + match taken { + CondBrTarget::Label(label) => { + let code = kind.emit(); + let code_inverse = kind.inverse().emit().to_le_bytes(); + sink.use_label_at_offset(*start_off, label, LabelUse::B12); + sink.add_cond_branch(*start_off, *start_off + 4, label, &code_inverse); + sink.put4(code); + } + CondBrTarget::Fallthrough => panic!("Cannot fallthrough in taken target"), + } + + match not_taken { + CondBrTarget::Label(label) => { + Inst::gen_jump(label).emit(sink, emit_info, state) + } + CondBrTarget::Fallthrough => {} + }; + } + + &Inst::Mov { rd, rm, ty } => { + debug_assert_eq!(rd.to_reg().class(), rm.class()); + if rd.to_reg() == rm { + return; + } + + match rm.class() { + RegClass::Int => Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: rd, + rs: rm, + imm12: Imm12::ZERO, + }, + RegClass::Float => Inst::FpuRRR { + alu_op: FpuOPRRR::Fsgnj, + width: FpuOPWidth::try_from(ty).unwrap(), + frm: FRM::RNE, + rd: rd, + rs1: rm, + rs2: rm, + }, + RegClass::Vector => Inst::VecAluRRImm5 { + op: VecAluOpRRImm5::VmvrV, + vd: rd, + vs2: rm, + // Imm 0 means copy 1 register. + imm: Imm5::maybe_from_i8(0).unwrap(), + mask: VecOpMasking::Disabled, + // Vstate for this instruction is ignored. + vstate: VState::from_type(ty), + }, + } + .emit(sink, emit_info, state); + } + + &Inst::MovFromPReg { rd, rm } => { + Inst::gen_move(rd, Reg::from(rm), I64).emit(sink, emit_info, state); + } + + &Inst::BrTable { + index, + tmp1, + tmp2, + ref targets, + } => { + let ext_index = writable_spilltmp_reg(); + + let label_compute_target = sink.get_label(); + + // The default target is passed in as the 0th element of `targets` + // separate it here for clarity. + let default_target = targets[0]; + let targets = &targets[1..]; + + // We are going to potentially emit a large amount of instructions, so ensure that we emit an island + // now if we need one. + // + // The worse case PC calculations are 12 instructions. And each entry in the jump table is 2 instructions. + // Check if we need to emit a jump table here to support that jump. + let inst_count = 12 + (targets.len() * 2); + let distance = (inst_count * Inst::UNCOMPRESSED_INSTRUCTION_SIZE as usize) as u32; + if sink.island_needed(distance) { + let jump_around_label = sink.get_label(); + Inst::gen_jump(jump_around_label).emit(sink, emit_info, state); + sink.emit_island(distance + 4, &mut state.ctrl_plane); + sink.bind_label(jump_around_label, &mut state.ctrl_plane); + } + + // We emit a bounds check on the index, if the index is larger than the number of + // jump table entries, we jump to the default block. Otherwise we compute a jump + // offset by multiplying the index by 8 (the size of each entry) and then jump to + // that offset. Each jump table entry is a regular auipc+jalr which we emit sequentially. + // + // Build the following sequence: + // + // extend_index: + // zext.w ext_index, index + // bounds_check: + // li tmp, n_labels + // bltu ext_index, tmp, compute_target + // jump_to_default_block: + // auipc pc, 0 + // jalr zero, pc, default_block + // compute_target: + // auipc pc, 0 + // slli tmp, ext_index, 3 + // add pc, pc, tmp + // jalr zero, pc, 0x10 + // jump_table: + // ; This repeats for each entry in the jumptable + // auipc pc, 0 + // jalr zero, pc, block_target + + // Extend the index to 64 bits. + // + // This prevents us branching on the top 32 bits of the index, which + // are undefined. + Inst::Extend { + rd: ext_index, + rn: index, + signed: false, + from_bits: 32, + to_bits: 64, + } + .emit(sink, emit_info, state); + + // Bounds check. + // + // Check if the index passed in is larger than the number of jumptable + // entries that we have. If it is, we fallthrough to a jump into the + // default block. + Inst::load_constant_u32(tmp2, targets.len() as u64) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + Inst::CondBr { + taken: CondBrTarget::Label(label_compute_target), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::UnsignedLessThan, + rs1: ext_index.to_reg(), + rs2: tmp2.to_reg(), + }, + } + .emit(sink, emit_info, state); + + sink.use_label_at_offset(sink.cur_offset(), default_target, LabelUse::PCRel32); + Inst::construct_auipc_and_jalr(None, tmp2, 0) + .iter() + .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); + + // Compute the jump table offset. + // We need to emit a PC relative offset, + sink.bind_label(label_compute_target, &mut state.ctrl_plane); + + // Get the current PC. + Inst::Auipc { + rd: tmp1, + imm: Imm20::ZERO, + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // These instructions must be emitted as uncompressed since we + // are manually computing the offset from the PC. + + // Multiply the index by 8, since that is the size in + // bytes of each jump table entry + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp2, + rs: ext_index.to_reg(), + imm12: Imm12::from_i16(3), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // Calculate the base of the jump, PC + the offset from above. + Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: tmp1, + rs1: tmp1.to_reg(), + rs2: tmp2.to_reg(), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // Jump to the middle of the jump table. + // We add a 16 byte offset here, since we used 4 instructions + // since the AUIPC that was used to get the PC. + Inst::Jalr { + rd: writable_zero_reg(), + base: tmp1.to_reg(), + offset: Imm12::from_i16((4 * Inst::UNCOMPRESSED_INSTRUCTION_SIZE) as i16), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // Emit the jump table. + // + // Each entry is a auipc + jalr to the target block. We also start with a island + // if necessary. + + // Emit the jumps back to back + for target in targets.iter() { + sink.use_label_at_offset(sink.cur_offset(), *target, LabelUse::PCRel32); + + Inst::construct_auipc_and_jalr(None, tmp2, 0) + .iter() + .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); + } + + // We've just emitted an island that is safe up to *here*. + // Mark it as such so that we don't needlessly emit additional islands. + *start_off = sink.cur_offset(); + } + + &Inst::Atomic { + op, + rd, + addr, + src, + amo, + } => { + // TODO: get flags from original CLIF atomic instruction + let flags = MemFlags::new(); + if let Some(trap_code) = flags.trap_code() { + sink.add_trap(trap_code); + } + let x = op.op_code() + | reg_to_gpr_num(rd.to_reg()) << 7 + | op.funct3() << 12 + | reg_to_gpr_num(addr) << 15 + | reg_to_gpr_num(src) << 20 + | op.funct7(amo) << 25; + + sink.put4(x); + } + &Inst::Fence { pred, succ } => { + let x = 0b0001111 + | 0b00000 << 7 + | 0b000 << 12 + | 0b00000 << 15 + | (succ as u32) << 20 + | (pred as u32) << 24; + + sink.put4(x); + } + &Inst::Auipc { rd, imm } => { + sink.put4(enc_auipc(rd, imm)); + } + + &Inst::LoadAddr { rd, mem } => { + let base = mem.get_base_register(); + let offset = mem.get_offset_with_state(state); + let offset_imm12 = Imm12::maybe_from_i64(offset); + + match (mem, base, offset_imm12) { + (_, Some(rs), Some(imm12)) => { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + } + .emit(sink, emit_info, state); + } + (_, Some(rs), None) => { + let mut insts = Inst::load_constant_u64(rd, offset as u64); + insts.push(Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd, + rs1: rd.to_reg(), + rs2: rs, + }); + insts + .into_iter() + .for_each(|inst| inst.emit(sink, emit_info, state)); + } + (AMode::Const(addr), None, _) => { + // Get an address label for the constant and recurse. + let label = sink.get_label_for_constant(addr); + Inst::LoadAddr { + rd, + mem: AMode::Label(label), + } + .emit(sink, emit_info, state); + } + (AMode::Label(label), None, _) => { + // Get the current PC. + sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelHi20); + let inst = Inst::Auipc { + rd, + imm: Imm20::ZERO, + }; + inst.emit_uncompressed(sink, emit_info, state, start_off); + + // Emit an add to the address with a relocation. + // This later gets patched up with the correct offset. + sink.use_label_at_offset(sink.cur_offset(), label, LabelUse::PCRelLo12I); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs: rd.to_reg(), + imm12: Imm12::ZERO, + } + .emit_uncompressed(sink, emit_info, state, start_off); + } + (amode, _, _) => { + unimplemented!("LoadAddr: {:?}", amode); + } + } + } + + &Inst::Select { + ref dst, + condition, + ref x, + ref y, + } => { + // The general form for this select is the following: + // + // mv rd, x + // b{cond} rcond, label_end + // mv rd, y + // label_end: + // ... etc + // + // This is built on the assumption that moves are cheap, but branches and jumps + // are not. So with this format we always avoid one jump instruction at the expense + // of an unconditional move. + // + // We also perform another optimization here. If the destination register is the same + // as one of the input registers, we can avoid emitting the first unconditional move + // and emit just the branch and the second move. + // + // To make sure that this happens as often as possible, we also try to invert the + // condition, so that if either of the input registers are the same as the destination + // we avoid that move. + + let label_end = sink.get_label(); + + let xregs = x.regs(); + let yregs = y.regs(); + let dstregs: Vec = dst.regs().into_iter().map(|r| r.to_reg()).collect(); + let condregs = condition.regs(); + + // We are going to write to the destination register before evaluating + // the condition, so we need to make sure that the destination register + // is not one of the condition registers. + // + // This should never happen, since hopefully the regalloc constraints + // for this register are set up correctly. + debug_assert_ne!(dstregs, condregs); + + // Check if we can invert the condition and avoid moving the y registers into + // the destination. This allows us to only emit the branch and one of the moves. + let (uncond_move, cond_move, condition) = if yregs == dstregs { + (yregs, xregs, condition.inverse()) + } else { + (xregs, yregs, condition) + }; + + // Unconditionally move one of the values to the destination register. + // + // These moves may not end up being emitted if the source and + // destination registers are the same. That logic is built into + // the emit function for `Inst::Mov`. + for i in gen_moves(dst.regs(), uncond_move) { + i.emit(sink, emit_info, state); + } + + // If the condition passes we skip over the conditional move + Inst::CondBr { + taken: CondBrTarget::Label(label_end), + not_taken: CondBrTarget::Fallthrough, + kind: condition, + } + .emit(sink, emit_info, state); + + // Move the conditional value to the destination register. + for i in gen_moves(dst.regs(), cond_move) { + i.emit(sink, emit_info, state); + } + + sink.bind_label(label_end, &mut state.ctrl_plane); + } + &Inst::Jalr { rd, base, offset } => { + sink.put4(enc_jalr(rd, base, offset)); + } + &Inst::EBreak => { + sink.put4(0x00100073); + } + &Inst::AtomicCas { + offset, + t0, + dst, + e, + addr, + v, + ty, + } => { + // # addr holds address of memory location + // # e holds expected value + // # v holds desired value + // # dst holds return value + // cas: + // lr.w dst, (addr) # Load original value. + // bne dst, e, fail # Doesn’t match, so fail. + // sc.w t0, v, (addr) # Try to update. + // bnez t0 , cas # if store not ok,retry. + // fail: + let fail_label = sink.get_label(); + let cas_lebel = sink.get_label(); + sink.bind_label(cas_lebel, &mut state.ctrl_plane); + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: dst, + addr, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + if ty.bits() < 32 { + AtomicOP::extract(dst, offset, dst.to_reg(), ty) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + } else if ty.bits() == 32 { + Inst::Extend { + rd: dst, + rn: dst.to_reg(), + signed: false, + from_bits: 32, + to_bits: 64, + } + .emit(sink, emit_info, state); + } + Inst::CondBr { + taken: CondBrTarget::Label(fail_label), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::NotEqual, + rs1: e, + rs2: dst.to_reg(), + }, + } + .emit(sink, emit_info, state); + let store_value = if ty.bits() < 32 { + // reload value to t0. + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: t0, + addr, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + // set reset part. + AtomicOP::merge(t0, writable_spilltmp_reg(), offset, v, ty) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + t0.to_reg() + } else { + v + }; + Inst::Atomic { + op: AtomicOP::store_op(ty), + rd: t0, + addr, + src: store_value, + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + // check is our value stored. + Inst::CondBr { + taken: CondBrTarget::Label(cas_lebel), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::NotEqual, + rs1: t0.to_reg(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + sink.bind_label(fail_label, &mut state.ctrl_plane); + } + &Inst::AtomicRmwLoop { + offset, + op, + dst, + ty, + p, + x, + t0, + } => { + let retry = sink.get_label(); + sink.bind_label(retry, &mut state.ctrl_plane); + // load old value. + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: dst, + addr: p, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + // + + let store_value: Reg = match op { + crate::ir::AtomicRmwOp::Add + | crate::ir::AtomicRmwOp::Sub + | crate::ir::AtomicRmwOp::And + | crate::ir::AtomicRmwOp::Or + | crate::ir::AtomicRmwOp::Xor => { + AtomicOP::extract(dst, offset, dst.to_reg(), ty) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + Inst::AluRRR { + alu_op: match op { + crate::ir::AtomicRmwOp::Add => AluOPRRR::Add, + crate::ir::AtomicRmwOp::Sub => AluOPRRR::Sub, + crate::ir::AtomicRmwOp::And => AluOPRRR::And, + crate::ir::AtomicRmwOp::Or => AluOPRRR::Or, + crate::ir::AtomicRmwOp::Xor => AluOPRRR::Xor, + _ => unreachable!(), + }, + rd: t0, + rs1: dst.to_reg(), + rs2: x, + } + .emit(sink, emit_info, state); + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: writable_spilltmp_reg2(), + addr: p, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + AtomicOP::merge( + writable_spilltmp_reg2(), + writable_spilltmp_reg(), + offset, + t0.to_reg(), + ty, + ) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + spilltmp_reg2() + } + crate::ir::AtomicRmwOp::Nand => { + if ty.bits() < 32 { + AtomicOP::extract(dst, offset, dst.to_reg(), ty) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + } + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: t0, + rs1: x, + rs2: dst.to_reg(), + } + .emit(sink, emit_info, state); + Inst::construct_bit_not(t0, t0.to_reg()).emit(sink, emit_info, state); + if ty.bits() < 32 { + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: writable_spilltmp_reg2(), + addr: p, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + AtomicOP::merge( + writable_spilltmp_reg2(), + writable_spilltmp_reg(), + offset, + t0.to_reg(), + ty, + ) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + spilltmp_reg2() + } else { + t0.to_reg() + } + } + + crate::ir::AtomicRmwOp::Umin + | crate::ir::AtomicRmwOp::Umax + | crate::ir::AtomicRmwOp::Smin + | crate::ir::AtomicRmwOp::Smax => { + let label_select_dst = sink.get_label(); + let label_select_done = sink.get_label(); + if op == crate::ir::AtomicRmwOp::Umin || op == crate::ir::AtomicRmwOp::Umax + { + AtomicOP::extract(dst, offset, dst.to_reg(), ty) + } else { + AtomicOP::extract_sext(dst, offset, dst.to_reg(), ty) + } + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + + Inst::CondBr { + taken: CondBrTarget::Label(label_select_dst), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: match op { + crate::ir::AtomicRmwOp::Umin => IntCC::UnsignedLessThan, + crate::ir::AtomicRmwOp::Umax => IntCC::UnsignedGreaterThan, + crate::ir::AtomicRmwOp::Smin => IntCC::SignedLessThan, + crate::ir::AtomicRmwOp::Smax => IntCC::SignedGreaterThan, + _ => unreachable!(), + }, + rs1: dst.to_reg(), + rs2: x, + }, + } + .emit(sink, emit_info, state); + // here we select x. + Inst::gen_move(t0, x, I64).emit(sink, emit_info, state); + Inst::gen_jump(label_select_done).emit(sink, emit_info, state); + sink.bind_label(label_select_dst, &mut state.ctrl_plane); + Inst::gen_move(t0, dst.to_reg(), I64).emit(sink, emit_info, state); + sink.bind_label(label_select_done, &mut state.ctrl_plane); + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: writable_spilltmp_reg2(), + addr: p, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + AtomicOP::merge( + writable_spilltmp_reg2(), + writable_spilltmp_reg(), + offset, + t0.to_reg(), + ty, + ) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + spilltmp_reg2() + } + crate::ir::AtomicRmwOp::Xchg => { + AtomicOP::extract(dst, offset, dst.to_reg(), ty) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + Inst::Atomic { + op: AtomicOP::load_op(ty), + rd: writable_spilltmp_reg2(), + addr: p, + src: zero_reg(), + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + AtomicOP::merge( + writable_spilltmp_reg2(), + writable_spilltmp_reg(), + offset, + x, + ty, + ) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + spilltmp_reg2() + } + }; + + Inst::Atomic { + op: AtomicOP::store_op(ty), + rd: t0, + addr: p, + src: store_value, + amo: AMO::SeqCst, + } + .emit(sink, emit_info, state); + + // if store is not ok,retry. + Inst::CondBr { + taken: CondBrTarget::Label(retry), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::NotEqual, + rs1: t0.to_reg(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + } + + &Inst::LoadExtName { + rd, + ref name, + offset, + } => { + if emit_info.shared_flag.is_pic() { + // Load a PC-relative address into a register. + // RISC-V does this slightly differently from other arches. We emit a relocation + // with a label, instead of the symbol itself. + // + // See: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + // + // Emit the following code: + // label: + // auipc rd, 0 # R_RISCV_GOT_HI20 (symbol_name) + // ld rd, rd, 0 # R_RISCV_PCREL_LO12_I (label) + + // Create the label that is going to be published to the final binary object. + let auipc_label = sink.get_label(); + sink.bind_label(auipc_label, &mut state.ctrl_plane); + + // Get the current PC. + sink.add_reloc(Reloc::RiscvGotHi20, &**name, 0); + Inst::Auipc { + rd: rd, + imm: Imm20::from_i32(0), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // The `ld` here, points to the `auipc` label instead of directly to the symbol. + sink.add_reloc(Reloc::RiscvPCRelLo12I, &auipc_label, 0); + Inst::Load { + rd, + op: LoadOP::Ld, + flags: MemFlags::trusted(), + from: AMode::RegOffset(rd.to_reg(), 0), + } + .emit_uncompressed(sink, emit_info, state, start_off); + } else { + // In the non PIC sequence we relocate the absolute address into + // a prealocatted space, load it into a register and jump over it. + // + // Emit the following code: + // ld rd, label_data + // j label_end + // label_data: + // <8 byte space> # ABS8 + // label_end: + + let label_data = sink.get_label(); + let label_end = sink.get_label(); + + // Load the value from a label + Inst::Load { + rd, + op: LoadOP::Ld, + flags: MemFlags::trusted(), + from: AMode::Label(label_data), + } + .emit(sink, emit_info, state); + + // Jump over the data + Inst::gen_jump(label_end).emit(sink, emit_info, state); + + sink.bind_label(label_data, &mut state.ctrl_plane); + sink.add_reloc(Reloc::Abs8, name.as_ref(), offset); + sink.put8(0); + + sink.bind_label(label_end, &mut state.ctrl_plane); + } + } + + &Inst::ElfTlsGetAddr { rd, ref name } => { + // RISC-V's TLS GD model is slightly different from other arches. + // + // We have a relocation (R_RISCV_TLS_GD_HI20) that loads the high 20 bits + // of the address relative to the GOT entry. This relocation points to + // the symbol as usual. + // + // However when loading the bottom 12bits of the address, we need to + // use a label that points to the previous AUIPC instruction. + // + // label: + // auipc a0,0 # R_RISCV_TLS_GD_HI20 (symbol) + // addi a0,a0,0 # R_RISCV_PCREL_LO12_I (label) + // + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#global-dynamic + + // Create the label that is going to be published to the final binary object. + let auipc_label = sink.get_label(); + sink.bind_label(auipc_label, &mut state.ctrl_plane); + + // Get the current PC. + sink.add_reloc(Reloc::RiscvTlsGdHi20, &**name, 0); + Inst::Auipc { + rd: rd, + imm: Imm20::from_i32(0), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + // The `addi` here, points to the `auipc` label instead of directly to the symbol. + sink.add_reloc(Reloc::RiscvPCRelLo12I, &auipc_label, 0); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: rd, + rs: rd.to_reg(), + imm12: Imm12::from_i16(0), + } + .emit_uncompressed(sink, emit_info, state, start_off); + + Inst::Call { + info: Box::new(CallInfo::empty( + ExternalName::LibCall(LibCall::ElfTlsGetAddr), + CallConv::SystemV, + )), + } + .emit_uncompressed(sink, emit_info, state, start_off); + } + + &Inst::TrapIf { + rs1, + rs2, + cc, + trap_code, + } => { + let label_end = sink.get_label(); + let cond = IntegerCompare { kind: cc, rs1, rs2 }; + + // Jump over the trap if we the condition is false. + Inst::CondBr { + taken: CondBrTarget::Label(label_end), + not_taken: CondBrTarget::Fallthrough, + kind: cond.inverse(), + } + .emit(sink, emit_info, state); + Inst::Udf { trap_code }.emit(sink, emit_info, state); + + sink.bind_label(label_end, &mut state.ctrl_plane); + } + &Inst::Udf { trap_code } => { + sink.add_trap(trap_code); + sink.put_data(Inst::TRAP_OPCODE); + } + &Inst::AtomicLoad { rd, ty, p } => { + // emit the fence. + Inst::Fence { + pred: Inst::FENCE_REQ_R | Inst::FENCE_REQ_W, + succ: Inst::FENCE_REQ_R | Inst::FENCE_REQ_W, + } + .emit(sink, emit_info, state); + // load. + Inst::Load { + rd: rd, + op: LoadOP::from_type(ty), + flags: MemFlags::new(), + from: AMode::RegOffset(p, 0), + } + .emit(sink, emit_info, state); + Inst::Fence { + pred: Inst::FENCE_REQ_R, + succ: Inst::FENCE_REQ_R | Inst::FENCE_REQ_W, + } + .emit(sink, emit_info, state); + } + &Inst::AtomicStore { src, ty, p } => { + Inst::Fence { + pred: Inst::FENCE_REQ_R | Inst::FENCE_REQ_W, + succ: Inst::FENCE_REQ_W, + } + .emit(sink, emit_info, state); + Inst::Store { + to: AMode::RegOffset(p, 0), + op: StoreOP::from_type(ty), + flags: MemFlags::new(), + src, + } + .emit(sink, emit_info, state); + } + + &Inst::Popcnt { + sum, + tmp, + step, + rs, + ty, + } => { + // load 0 to sum , init. + Inst::gen_move(sum, zero_reg(), I64).emit(sink, emit_info, state); + // load + Inst::load_imm12(step, Imm12::from_i16(ty.bits() as i16)) + .emit(sink, emit_info, state); + // + Inst::load_imm12(tmp, Imm12::ONE).emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::from_i16((ty.bits() - 1) as i16), + } + .emit(sink, emit_info, state); + let label_done = sink.get_label(); + let label_loop = sink.get_label(); + sink.bind_label(label_loop, &mut state.ctrl_plane); + Inst::CondBr { + taken: CondBrTarget::Label(label_done), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::SignedLessThanOrEqual, + rs1: step.to_reg(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + // test and add sum. + { + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: writable_spilltmp_reg2(), + rs1: tmp.to_reg(), + rs2: rs, + } + .emit(sink, emit_info, state); + let label_over = sink.get_label(); + Inst::CondBr { + taken: CondBrTarget::Label(label_over), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::Equal, + rs1: zero_reg(), + rs2: spilltmp_reg2(), + }, + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: sum, + rs: sum.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + sink.bind_label(label_over, &mut state.ctrl_plane); + } + // set step and tmp. + { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: step, + rs: step.to_reg(), + imm12: Imm12::from_i16(-1), + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srli, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + Inst::gen_jump(label_loop).emit(sink, emit_info, state); + } + sink.bind_label(label_done, &mut state.ctrl_plane); + } + &Inst::Cltz { + sum, + tmp, + step, + rs, + leading, + ty, + } => { + // load 0 to sum , init. + Inst::gen_move(sum, zero_reg(), I64).emit(sink, emit_info, state); + // load + Inst::load_imm12(step, Imm12::from_i16(ty.bits() as i16)) + .emit(sink, emit_info, state); + // + Inst::load_imm12(tmp, Imm12::ONE).emit(sink, emit_info, state); + if leading { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::from_i16((ty.bits() - 1) as i16), + } + .emit(sink, emit_info, state); + } + let label_done = sink.get_label(); + let label_loop = sink.get_label(); + sink.bind_label(label_loop, &mut state.ctrl_plane); + Inst::CondBr { + taken: CondBrTarget::Label(label_done), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::SignedLessThanOrEqual, + rs1: step.to_reg(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + // test and add sum. + { + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: writable_spilltmp_reg2(), + rs1: tmp.to_reg(), + rs2: rs, + } + .emit(sink, emit_info, state); + Inst::CondBr { + taken: CondBrTarget::Label(label_done), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::NotEqual, + rs1: zero_reg(), + rs2: spilltmp_reg2(), + }, + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: sum, + rs: sum.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + } + // set step and tmp. + { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: step, + rs: step.to_reg(), + imm12: Imm12::from_i16(-1), + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: if leading { + AluOPRRI::Srli + } else { + AluOPRRI::Slli + }, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + Inst::gen_jump(label_loop).emit(sink, emit_info, state); + } + sink.bind_label(label_done, &mut state.ctrl_plane); + } + &Inst::Brev8 { + rs, + ty, + step, + tmp, + tmp2, + rd, + } => { + Inst::gen_move(rd, zero_reg(), I64).emit(sink, emit_info, state); + Inst::load_imm12(step, Imm12::from_i16(ty.bits() as i16)) + .emit(sink, emit_info, state); + // + Inst::load_imm12(tmp, Imm12::ONE).emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::from_i16((ty.bits() - 1) as i16), + } + .emit(sink, emit_info, state); + Inst::load_imm12(tmp2, Imm12::ONE).emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp2, + rs: tmp2.to_reg(), + imm12: Imm12::from_i16((ty.bits() - 8) as i16), + } + .emit(sink, emit_info, state); + + let label_done = sink.get_label(); + let label_loop = sink.get_label(); + sink.bind_label(label_loop, &mut state.ctrl_plane); + Inst::CondBr { + taken: CondBrTarget::Label(label_done), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::SignedLessThanOrEqual, + rs1: step.to_reg(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + // test and set bit. + { + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: writable_spilltmp_reg2(), + rs1: tmp.to_reg(), + rs2: rs, + } + .emit(sink, emit_info, state); + let label_over = sink.get_label(); + Inst::CondBr { + taken: CondBrTarget::Label(label_over), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::Equal, + rs1: zero_reg(), + rs2: spilltmp_reg2(), + }, + } + .emit(sink, emit_info, state); + Inst::AluRRR { + alu_op: AluOPRRR::Or, + rd: rd, + rs1: rd.to_reg(), + rs2: tmp2.to_reg(), + } + .emit(sink, emit_info, state); + sink.bind_label(label_over, &mut state.ctrl_plane); + } + // set step and tmp. + { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: step, + rs: step.to_reg(), + imm12: Imm12::from_i16(-1), + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srli, + rd: tmp, + rs: tmp.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + { + // reset tmp2 + // if (step %=8 == 0) then tmp2 = tmp2 >> 15 + // if (step %=8 != 0) then tmp2 = tmp2 << 1 + let label_over = sink.get_label(); + let label_sll_1 = sink.get_label(); + Inst::load_imm12(writable_spilltmp_reg2(), Imm12::from_i16(8)) + .emit(sink, emit_info, state); + Inst::AluRRR { + alu_op: AluOPRRR::Rem, + rd: writable_spilltmp_reg2(), + rs1: step.to_reg(), + rs2: spilltmp_reg2(), + } + .emit(sink, emit_info, state); + Inst::CondBr { + taken: CondBrTarget::Label(label_sll_1), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::NotEqual, + rs1: spilltmp_reg2(), + rs2: zero_reg(), + }, + } + .emit(sink, emit_info, state); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srli, + rd: tmp2, + rs: tmp2.to_reg(), + imm12: Imm12::from_i16(15), + } + .emit(sink, emit_info, state); + Inst::gen_jump(label_over).emit(sink, emit_info, state); + sink.bind_label(label_sll_1, &mut state.ctrl_plane); + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: tmp2, + rs: tmp2.to_reg(), + imm12: Imm12::ONE, + } + .emit(sink, emit_info, state); + sink.bind_label(label_over, &mut state.ctrl_plane); + } + Inst::gen_jump(label_loop).emit(sink, emit_info, state); + } + sink.bind_label(label_done, &mut state.ctrl_plane); + } + &Inst::StackProbeLoop { + guard_size, + probe_count, + tmp: guard_size_tmp, + } => { + let step = writable_spilltmp_reg(); + Inst::load_constant_u64(step, (guard_size as u64) * (probe_count as u64)) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + Inst::load_constant_u64(guard_size_tmp, guard_size as u64) + .iter() + .for_each(|i| i.emit(sink, emit_info, state)); + + let loop_start = sink.get_label(); + let label_done = sink.get_label(); + sink.bind_label(loop_start, &mut state.ctrl_plane); + Inst::CondBr { + taken: CondBrTarget::Label(label_done), + not_taken: CondBrTarget::Fallthrough, + kind: IntegerCompare { + kind: IntCC::UnsignedLessThanOrEqual, + rs1: step.to_reg(), + rs2: guard_size_tmp.to_reg(), + }, + } + .emit(sink, emit_info, state); + // compute address. + Inst::AluRRR { + alu_op: AluOPRRR::Sub, + rd: writable_spilltmp_reg2(), + rs1: stack_reg(), + rs2: step.to_reg(), + } + .emit(sink, emit_info, state); + Inst::Store { + to: AMode::RegOffset(spilltmp_reg2(), 0), + op: StoreOP::Sb, + flags: MemFlags::new(), + src: zero_reg(), + } + .emit(sink, emit_info, state); + // reset step. + Inst::AluRRR { + alu_op: AluOPRRR::Sub, + rd: step, + rs1: step.to_reg(), + rs2: guard_size_tmp.to_reg(), + } + .emit(sink, emit_info, state); + Inst::gen_jump(loop_start).emit(sink, emit_info, state); + sink.bind_label(label_done, &mut state.ctrl_plane); + } + &Inst::VecAluRRRImm5 { + op, + vd, + vd_src, + imm, + vs2, + ref mask, + .. + } => { + debug_assert_eq!(vd.to_reg(), vd_src); + + sink.put4(encode_valu_rrr_imm(op, vd, imm, vs2, *mask)); + } + &Inst::VecAluRRRR { + op, + vd, + vd_src, + vs1, + vs2, + ref mask, + .. + } => { + debug_assert_eq!(vd.to_reg(), vd_src); + + sink.put4(encode_valu_rrrr(op, vd, vs2, vs1, *mask)); + } + &Inst::VecAluRRR { + op, + vd, + vs1, + vs2, + ref mask, + .. + } => { + sink.put4(encode_valu(op, vd, vs1, vs2, *mask)); + } + &Inst::VecAluRRImm5 { + op, + vd, + imm, + vs2, + ref mask, + .. + } => { + sink.put4(encode_valu_rr_imm(op, vd, imm, vs2, *mask)); + } + &Inst::VecAluRR { + op, + vd, + vs, + ref mask, + .. + } => { + sink.put4(encode_valu_rr(op, vd, vs, *mask)); + } + &Inst::VecAluRImm5 { + op, + vd, + imm, + ref mask, + .. + } => { + sink.put4(encode_valu_r_imm(op, vd, imm, *mask)); + } + &Inst::VecSetState { rd, ref vstate } => { + sink.put4(encode_vcfg_imm( + 0x57, + rd.to_reg(), + vstate.avl.unwrap_static(), + &vstate.vtype, + )); + + // Update the current vector emit state. + state.vstate = EmitVState::Known(*vstate); + } + + &Inst::VecLoad { + eew, + to, + ref from, + ref mask, + flags, + .. + } => { + // Vector Loads don't support immediate offsets, so we need to load it into a register. + let addr = match from { + VecAMode::UnitStride { base } => { + let base_reg = base.get_base_register(); + let offset = base.get_offset_with_state(state); + + // Reg+0 Offset can be directly encoded + if let (Some(base_reg), 0) = (base_reg, offset) { + base_reg + } else { + // Otherwise load the address it into a reg and load from it. + let tmp = writable_spilltmp_reg(); + Inst::LoadAddr { + rd: tmp, + mem: *base, + } + .emit(sink, emit_info, state); + tmp.to_reg() + } + } + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + sink.put4(encode_vmem_load( + 0x07, + to.to_reg(), + eew, + addr, + from.lumop(), + *mask, + from.mop(), + from.nf(), + )); + } + + &Inst::VecStore { + eew, + ref to, + from, + ref mask, + flags, + .. + } => { + // Vector Stores don't support immediate offsets, so we need to load it into a register. + let addr = match to { + VecAMode::UnitStride { base } => { + let base_reg = base.get_base_register(); + let offset = base.get_offset_with_state(state); + + // Reg+0 Offset can be directly encoded + if let (Some(base_reg), 0) = (base_reg, offset) { + base_reg + } else { + // Otherwise load the address it into a reg and load from it. + let tmp = writable_spilltmp_reg(); + Inst::LoadAddr { + rd: tmp, + mem: *base, + } + .emit(sink, emit_info, state); + tmp.to_reg() + } + } + }; + + if let Some(trap_code) = flags.trap_code() { + // Register the offset at which the actual load instruction starts. + sink.add_trap(trap_code); + } + + sink.put4(encode_vmem_store( + 0x27, + from, + eew, + addr, + to.sumop(), + *mask, + to.mop(), + to.nf(), + )); + } + }; + } +} + +fn emit_return_call_common_sequence( + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, + info: &ReturnCallInfo, +) { + // The return call sequence can potentially emit a lot of instructions (up to 634 bytes!) + // So lets emit an island here if we need it. + // + // It is difficult to calculate exactly how many instructions are going to be emitted, so + // we calculate it by emitting it into a disposable buffer, and then checking how many instructions + // were actually emitted. + let mut buffer = MachBuffer::new(); + let mut fake_emit_state = state.clone(); + + return_call_emit_impl(&mut buffer, emit_info, &mut fake_emit_state, info); + + // Finalize the buffer and get the number of bytes emitted. + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + let length = buffer.data().len() as u32; + + // And now emit the island inline with this instruction. + if sink.island_needed(length) { + let jump_around_label = sink.get_label(); + Inst::gen_jump(jump_around_label).emit(sink, emit_info, state); + sink.emit_island(length + 4, &mut state.ctrl_plane); + sink.bind_label(jump_around_label, &mut state.ctrl_plane); + } + + // Now that we're done, emit the *actual* return sequence. + return_call_emit_impl(sink, emit_info, state, info); +} + +/// This should not be called directly, Instead prefer to call [emit_return_call_common_sequence]. +fn return_call_emit_impl( + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, + info: &ReturnCallInfo, +) { + let sp_to_fp_offset = { + let frame_layout = state.frame_layout(); + i64::from( + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size, + ) + }; + + let mut clobber_offset = sp_to_fp_offset - 8; + for reg in state.frame_layout().clobbered_callee_saves.clone() { + let rreg = reg.to_reg(); + let ty = match rreg.class() { + RegClass::Int => I64, + RegClass::Float => F64, + RegClass::Vector => unimplemented!("Vector Clobber Restores"), + }; + + Inst::gen_load( + reg.map(Reg::from), + AMode::SPOffset(clobber_offset), + ty, + MemFlags::trusted(), + ) + .emit(sink, emit_info, state); + + clobber_offset -= 8 + } + + // Restore the link register and frame pointer + let setup_area_size = i64::from(state.frame_layout().setup_area_size); + if setup_area_size > 0 { + Inst::gen_load( + writable_link_reg(), + AMode::SPOffset(sp_to_fp_offset + 8), + I64, + MemFlags::trusted(), + ) + .emit(sink, emit_info, state); + + Inst::gen_load( + writable_fp_reg(), + AMode::SPOffset(sp_to_fp_offset), + I64, + MemFlags::trusted(), + ) + .emit(sink, emit_info, state); + } + + // If we over-allocated the incoming args area in the prologue, resize down to what the callee + // is expecting. + let incoming_args_diff = + i64::from(state.frame_layout().tail_args_size - info.new_stack_arg_size); + + // Increment SP all at once + let sp_increment = sp_to_fp_offset + setup_area_size + incoming_args_diff; + if sp_increment > 0 { + for inst in Riscv64MachineDeps::gen_sp_reg_adjust(i32::try_from(sp_increment).unwrap()) { + inst.emit(sink, emit_info, state); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit_tests.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit_tests.rs new file mode 100644 index 00000000000000..6f1b2d7df5e56a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/emit_tests.rs @@ -0,0 +1,2277 @@ +#[allow(unused)] +use crate::ir::LibCall; +use crate::isa::riscv64::inst::*; +use crate::isa::riscv64::lower::isle::generated_code::FpuOPWidth; +use std::borrow::Cow; + +fn fa7() -> Reg { + f_reg(17) +} + +#[test] +fn test_riscv64_binemit() { + struct TestUnit { + inst: Inst, + assembly: &'static str, + code: TestEncoding, + } + + struct TestEncoding(Cow<'static, str>); + + impl From<&'static str> for TestEncoding { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + + impl From for TestEncoding { + fn from(value: u32) -> Self { + let value = value.swap_bytes(); + let value = format!("{value:08X}"); + Self(value.into()) + } + } + + impl TestUnit { + fn new(inst: Inst, assembly: &'static str, code: impl Into) -> Self { + let code = code.into(); + Self { + inst, + assembly, + code, + } + } + } + + let mut insns = Vec::::with_capacity(500); + + insns.push(TestUnit::new(Inst::Ret {}, "ret", 0x00008067)); + + insns.push(TestUnit::new( + Inst::Mov { + rd: writable_fa0(), + rm: fa1(), + ty: F32, + }, + "fmv.s fa0,fa1", + 0x20b58553, + )); + + insns.push(TestUnit::new( + Inst::Mov { + rd: writable_fa0(), + rm: fa1(), + ty: F64, + }, + "fmv.d fa0,fa1", + 0x22b58553, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Brev8, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "brev8 a1,a0", + 0x68755593, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Rev8, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "rev8 a1,a0", + 0x6b855593, + )); + + // + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Bclri, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "bclri a1,a0,5", + 0x48551593, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Bexti, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "bexti a1,a0,5", + 0x48555593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Binvi, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "binvi a1,a0,5", + 0x68551593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Bseti, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "bseti a1,a0,5", + 0x28551593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Rori, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "rori a1,a0,5", + 0x60555593, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Roriw, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "roriw a1,a0,5", + 0x6055559b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::SlliUw, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "slli.uw a1,a0,5", + 0x855159b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Clz, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "clz a1,a0", + 0x60051593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Clzw, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "clzw a1,a0", + 0x6005159b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Cpop, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "cpop a1,a0", + 0x60251593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Cpopw, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "cpopw a1,a0", + 0x6025159b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Ctz, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "ctz a1,a0", + 0x60151593, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Ctzw, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "ctzw a1,a0", + 0x6015159b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Sextb, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "sext.b a1,a0", + 0x60451593, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Sexth, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "sext.h a1,a0", + 0x60551593, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Zexth, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "zext.h a1,a0", + 0x80545bb, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Orcb, + rd: writable_a1(), + rs: a0(), + imm12: Imm12::ZERO, + }, + "orc.b a1,a0", + 0x28755593, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Adduw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "zext.w a1,a0", + 0x80505bb, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Adduw, + rd: writable_a1(), + rs1: a0(), + rs2: a1(), + }, + "add.uw a1,a0,a1", + 0x08b505bb, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Andn, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "andn a1,a0,zero", + 0x400575b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Bclr, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "bclr a1,a0,zero", + 0x480515b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Bext, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "bext a1,a0,zero", + 0x480555b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Binv, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "binv a1,a0,zero", + 0x680515b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Bset, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "bset a1,a0,zero", + 0x280515b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Clmul, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "clmul a1,a0,zero", + 0xa0515b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Clmulh, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "clmulh a1,a0,zero", + 0xa0535b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Clmulr, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "clmulr a1,a0,zero", + 0xa0525b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Max, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "max a1,a0,zero", + 0xa0565b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Maxu, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "maxu a1,a0,zero", + 0xa0575b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Min, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "min a1,a0,zero", + 0xa0545b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Minu, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "minu a1,a0,zero", + 0xa0555b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Orn, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "orn a1,a0,zero", + 0x400565b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Rol, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "rol a1,a0,zero", + 0x600515b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Rolw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "rolw a1,a0,zero", + 0x600515bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Ror, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "ror a1,a0,zero", + 0x600555b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Rorw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "rorw a1,a0,zero", + 0x600555bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh1add, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh1add a1,a0,zero", + 0x200525b3, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh1adduw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh1add.uw a1,a0,zero", + 0x200525bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh2add, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh2add a1,a0,zero", + 0x200545b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh2adduw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh2add.uw a1,a0,zero", + 0x200545bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh3add, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh3add a1,a0,zero", + 0x200565b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sh3adduw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "sh3add.uw a1,a0,zero", + 0x200565bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Xnor, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "xnor a1,a0,zero", + 0x400545b3, + )); + + // Zbkb + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Pack, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "pack a1,a0,zero", + 0x080545b3, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Packw, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "packw a1,a0,zero", + 0x080545bb, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Packh, + rd: writable_a1(), + rs1: a0(), + rs2: zero_reg(), + }, + "packh a1,a0,zero", + 0x080575b3, + )); + + // + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: writable_fp_reg(), + rs1: fp_reg(), + rs2: zero_reg(), + }, + "add fp,fp,zero", + 0x40433, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: writable_fp_reg(), + rs: stack_reg(), + imm12: Imm12::maybe_from_u64(100).unwrap(), + }, + "addi fp,sp,100", + 0x6410413, + )); + insns.push(TestUnit::new( + Inst::Lui { + rd: writable_zero_reg(), + imm: Imm20::from_i32(120), + }, + "lui zero,120", + 0x78037, + )); + insns.push(TestUnit::new( + Inst::Auipc { + rd: writable_zero_reg(), + imm: Imm20::from_i32(120), + }, + "auipc zero,120", + 0x78017, + )); + + insns.push(TestUnit::new( + Inst::Jalr { + rd: writable_a0(), + base: a0(), + offset: Imm12::from_i16(100), + }, + "jalr a0,100(a0)", + 0x6450567, + )); + + insns.push(TestUnit::new( + Inst::Load { + rd: writable_a0(), + op: LoadOP::Lb, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "lb a0,100(a1)", + 0x6458503, + )); + insns.push(TestUnit::new( + Inst::Load { + rd: writable_a0(), + op: LoadOP::Lh, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "lh a0,100(a1)", + 0x6459503, + )); + + insns.push(TestUnit::new( + Inst::Load { + rd: writable_a0(), + op: LoadOP::Lw, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "lw a0,100(a1)", + 0x645a503, + )); + + insns.push(TestUnit::new( + Inst::Load { + rd: writable_a0(), + op: LoadOP::Ld, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "ld a0,100(a1)", + 0x645b503, + )); + insns.push(TestUnit::new( + Inst::Load { + rd: Writable::from_reg(fa0()), + op: LoadOP::Flw, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "flw fa0,100(a1)", + 0x645a507, + )); + + insns.push(TestUnit::new( + Inst::Load { + rd: Writable::from_reg(fa0()), + op: LoadOP::Fld, + flags: MemFlags::new(), + from: AMode::RegOffset(a1(), 100), + }, + "fld fa0,100(a1)", + 0x645b507, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Sb, + flags: MemFlags::new(), + src: a0(), + }, + "sb a0,100(sp)", + 0x6a10223, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Sh, + flags: MemFlags::new(), + src: a0(), + }, + "sh a0,100(sp)", + 0x6a11223, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Sw, + flags: MemFlags::new(), + src: a0(), + }, + "sw a0,100(sp)", + 0x6a12223, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Sd, + flags: MemFlags::new(), + src: a0(), + }, + "sd a0,100(sp)", + 0x6a13223, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Fsw, + flags: MemFlags::new(), + src: fa0(), + }, + "fsw fa0,100(sp)", + 0x6a12227, + )); + insns.push(TestUnit::new( + Inst::Store { + to: AMode::SPOffset(100), + op: StoreOP::Fsd, + flags: MemFlags::new(), + src: fa0(), + }, + "fsd fa0,100(sp)", + 0x6a13227, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(100), + }, + "addi a0,a0,100", + 0x6450513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slti, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(100), + }, + "slti a0,a0,100", + 0x6452513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::SltiU, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(100), + }, + "sltiu a0,a0,100", + 0x6453513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Xori, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(100), + }, + "xori a0,a0,100", + 0x6454513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Andi, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(100), + }, + "andi a0,a0,100", + 0x6457513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slli, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "slli a0,a0,5", + 0x551513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srli, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "srli a0,a0,5", + 0x555513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Srai, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "srai a0,a0,5", + 0x40555513, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addiw, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(120), + }, + "addiw a0,a0,120", + 0x785051b, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Slliw, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "slliw a0,a0,5", + 0x55151b, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::SrliW, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "srliw a0,a0,5", + 0x55551b, + )); + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Sraiw, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "sraiw a0,a0,5", + 0x4055551b, + )); + + insns.push(TestUnit::new( + Inst::AluRRImm12 { + alu_op: AluOPRRI::Sraiw, + rd: writable_a0(), + rs: a0(), + imm12: Imm12::from_i16(5), + }, + "sraiw a0,a0,5", + 0x4055551b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Add, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "add a0,a0,a1", + 0xb50533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sub, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sub a0,a0,a1", + 0x40b50533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sll, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sll a0,a0,a1", + 0xb51533, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Slt, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "slt a0,a0,a1", + 0xb52533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::SltU, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sltu a0,a0,a1", + 0xb53533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Xor, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "xor a0,a0,a1", + 0xb54533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Srl, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "srl a0,a0,a1", + 0xb55533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sra, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sra a0,a0,a1", + 0x40b55533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Or, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "or a0,a0,a1", + 0xb56533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::And, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "and a0,a0,a1", + 0xb57533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Addw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "addw a0,a0,a1", + 0xb5053b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Subw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "subw a0,a0,a1", + 0x40b5053b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sllw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sllw a0,a0,a1", + 0xb5153b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Srlw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "srlw a0,a0,a1", + 0xb5553b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Sraw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "sraw a0,a0,a1", + 0x40b5553b, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Mul, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "mul a0,a0,a1", + 0x2b50533, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Mulh, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "mulh a0,a0,a1", + 0x2b51533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Mulhsu, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "mulhsu a0,a0,a1", + 0x2b52533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Mulhu, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "mulhu a0,a0,a1", + 0x2b53533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Div, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "div a0,a0,a1", + 0x2b54533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::DivU, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "divu a0,a0,a1", + 0x2b55533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Rem, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "rem a0,a0,a1", + 0x2b56533, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::RemU, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "remu a0,a0,a1", + 0x2b57533, + )); + + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Mulw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "mulw a0,a0,a1", + 0x2b5053b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Divw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "divw a0,a0,a1", + 0x2b5453b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Remw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "remw a0,a0,a1", + 0x2b5653b, + )); + insns.push(TestUnit::new( + Inst::AluRRR { + alu_op: AluOPRRR::Remuw, + rd: writable_a0(), + rs1: a0(), + rs2: a1(), + }, + "remuw a0,a0,a1", + 0x2b5753b, + )); + + // + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fadd.s fa0,fa0,fa1,rne", + 0xb50553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsub.s fa0,fa0,fa1,rtz", + 0x8b51553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RUP, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fmul, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmul.s fa0,fa0,fa1,rup", + 0x10b53553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fdiv, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fdiv.s fa0,fa0,fa1,fcsr", + 0x18b57553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fsgnj, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnj.s fa0,fa0,fa1", + 0x20b50553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fsgnjn, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnjn.s fa0,fa0,fa1", + 0x20b51553, + )); + + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RDN, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fsgnjx, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnjx.s fa0,fa0,fa1", + 0x20b52553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fmin, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmin.s fa0,fa0,fa1", + 0x28b50553, + )); + + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fmax, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmax.s fa0,fa0,fa1", + 0x28b51553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RDN, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Feq, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "feq.s a0,fa0,fa1", + 0xa0b52553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Flt, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "flt.s a0,fa0,fa1", + 0xa0b51553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRRR::Fle, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "fle.s a0,fa0,fa1", + 0xa0b50553, + )); + + // + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fadd.d fa0,fa0,fa1,fcsr", + 0x2b57553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsub.d fa0,fa0,fa1,fcsr", + 0xab57553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fmul, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmul.d fa0,fa0,fa1,fcsr", + 0x12b57553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fdiv, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fdiv.d fa0,fa0,fa1,fcsr", + 0x1ab57553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fsgnj, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnj.d fa0,fa0,fa1", + 0x22b50553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fsgnjn, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnjn.d fa0,fa0,fa1", + 0x22b51553, + )); + + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RDN, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fsgnjx, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fsgnjx.d fa0,fa0,fa1", + 0x22b52553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fmin, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmin.d fa0,fa0,fa1", + 0x2ab50553, + )); + + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fmax, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + }, + "fmax.d fa0,fa0,fa1", + 0x2ab51553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RDN, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Feq, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "feq.d a0,fa0,fa1", + 0xa2b52553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RTZ, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Flt, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "flt.d a0,fa0,fa1", + 0xa2b51553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRRR::Fle, + rd: writable_a0(), + rs1: fa0(), + rs2: fa1(), + }, + "fle.d a0,fa0,fa1", + 0xa2b50553, + )); + + // + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRR::Fsqrt, + rd: writable_fa0(), + rs: fa1(), + }, + "fsqrt.s fa0,fa1,rne", + 0x58058553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtWFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fcvt.w.s a0,fa1,fcsr", + 0xc005f553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtWuFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fcvt.wu.s a0,fa1,fcsr", + 0xc015f553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FmvXFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fmv.x.w a0,fa1", + 0xe0058553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RTZ, + width: FpuOPWidth::S, + alu_op: FpuOPRR::Fclass, + rd: writable_a0(), + rs: fa1(), + }, + "fclass.s a0,fa1", + 0xe0059553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtFmtW, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.s.w fa0,a0,fcsr", + 0xd0057553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtFmtWu, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.s.wu fa0,a0,fcsr", + 0xd0157553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FmvFmtX, + rd: writable_fa0(), + rs: a0(), + }, + "fmv.w.x fa0,a0", + 0xf0050553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtLFmt, + rd: writable_a0(), + rs: fa0(), + }, + "fcvt.l.s a0,fa0,fcsr", + 0xc0257553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtLuFmt, + rd: writable_a0(), + rs: fa0(), + }, + "fcvt.lu.s a0,fa0,fcsr", + 0xc0357553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtFmtL, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.s.l fa0,a0,fcsr", + 0xd0257553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtFmtLu, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.s.lu fa0,a0,fcsr", + 0xd0357553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::Fsqrt, + rd: writable_fa0(), + rs: fa1(), + }, + "fsqrt.d fa0,fa1,fcsr", + 0x5a05f553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtWFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fcvt.w.d a0,fa1,fcsr", + 0xc205f553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtWuFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fcvt.wu.d a0,fa1,fcsr", + 0xc215f553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FmvXFmt, + rd: writable_a0(), + rs: fa1(), + }, + "fmv.x.d a0,fa1", + 0xe2058553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RTZ, + width: FpuOPWidth::D, + alu_op: FpuOPRR::Fclass, + rd: writable_a0(), + rs: fa1(), + }, + "fclass.d a0,fa1", + 0xe2059553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRR::FcvtSD, + rd: writable_fa0(), + rs: fa0(), + }, + "fcvt.s.d fa0,fa0,fcsr", + 0x40157553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtFmtWu, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.d.wu fa0,a0,rne", + 0xd2150553, + )); + + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::RNE, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FmvFmtX, + rd: writable_fa0(), + rs: a0(), + }, + "fmv.d.x fa0,a0", + 0xf2050553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtLFmt, + rd: writable_a0(), + rs: fa0(), + }, + "fcvt.l.d a0,fa0,fcsr", + 0xc2257553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtLuFmt, + rd: writable_a0(), + rs: fa0(), + }, + "fcvt.lu.d a0,fa0,fcsr", + 0xc2357553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtFmtL, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.d.l fa0,a0,fcsr", + 0xd2257553, + )); + insns.push(TestUnit::new( + Inst::FpuRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRR::FcvtFmtLu, + rd: writable_fa0(), + rs: a0(), + }, + "fcvt.d.lu fa0,a0,fcsr", + 0xd2357553, + )); + ////////////////////// + + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::RNE, + width: FpuOPWidth::S, + alu_op: FpuOPRRRR::Fmadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fmadd.s fa0,fa0,fa1,fa7,rne", + 0x88b50543, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRRRR::Fmsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fmsub.s fa0,fa0,fa1,fa7,fcsr", + 0x88b57547, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRRRR::Fnmsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fnmsub.s fa0,fa0,fa1,fa7,fcsr", + 0x88b5754b, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::S, + alu_op: FpuOPRRRR::Fnmadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fnmadd.s fa0,fa0,fa1,fa7,fcsr", + 0x88b5754f, + )); + + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRRR::Fmadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fmadd.d fa0,fa0,fa1,fa7,fcsr", + 0x8ab57543, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRRR::Fmsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fmsub.d fa0,fa0,fa1,fa7,fcsr", + 0x8ab57547, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRRR::Fnmsub, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fnmsub.d fa0,fa0,fa1,fa7,fcsr", + 0x8ab5754b, + )); + insns.push(TestUnit::new( + Inst::FpuRRRR { + frm: FRM::Fcsr, + width: FpuOPWidth::D, + alu_op: FpuOPRRRR::Fnmadd, + rd: writable_fa0(), + rs1: fa0(), + rs2: fa1(), + rs3: fa7(), + }, + "fnmadd.d fa0,fa0,fa1,fa7,fcsr", + 0x8ab5754f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::LrW, + rd: writable_a0(), + addr: a1(), + src: zero_reg(), + amo: AMO::Relax, + }, + "lr.w a0,(a1)", + 0x1005a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::ScW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Release, + }, + "sc.w.rl a0,a2,(a1)", + 0x1ac5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoswapW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Acquire, + }, + "amoswap.w.aq a0,a2,(a1)", + 0xcc5a52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoaddW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::SeqCst, + }, + "amoadd.w.aqrl a0,a2,(a1)", + 0x6c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoxorW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoxor.w a0,a2,(a1)", + 0x20c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoandW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoand.w a0,a2,(a1)", + 0x60c5a52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoorW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoor.w a0,a2,(a1)", + 0x40c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmominW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomin.w a0,a2,(a1)", + 0x80c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmomaxW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomax.w a0,a2,(a1)", + 0xa0c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmominuW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amominu.w a0,a2,(a1)", + 0xc0c5a52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmomaxuW, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomaxu.w a0,a2,(a1)", + 0xe0c5a52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::LrD, + rd: writable_a0(), + addr: a1(), + src: zero_reg(), + amo: AMO::Relax, + }, + "lr.d a0,(a1)", + 0x1005b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::ScD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "sc.d a0,a2,(a1)", + 0x18c5b52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoswapD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoswap.d a0,a2,(a1)", + 0x8c5b52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoaddD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoadd.d a0,a2,(a1)", + 0xc5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoxorD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoxor.d a0,a2,(a1)", + 0x20c5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoandD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoand.d a0,a2,(a1)", + 0x60c5b52f, + )); + + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmoorD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amoor.d a0,a2,(a1)", + 0x40c5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmominD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomin.d a0,a2,(a1)", + 0x80c5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmomaxD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomax.d a0,a2,(a1)", + 0xa0c5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmominuD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amominu.d a0,a2,(a1)", + 0xc0c5b52f, + )); + insns.push(TestUnit::new( + Inst::Atomic { + op: AtomicOP::AmomaxuD, + rd: writable_a0(), + addr: a1(), + src: a2(), + amo: AMO::Relax, + }, + "amomaxu.d a0,a2,(a1)", + 0xe0c5b52f, + )); + + ///////// + insns.push(TestUnit::new( + Inst::Fence { + pred: 1, + succ: 1 << 1, + }, + "fence w,r", + 0x120000f, + )); + insns.push(TestUnit::new(Inst::EBreak {}, "ebreak", 0x100073)); + + insns.push(TestUnit::new( + Inst::FpuRRR { + alu_op: FpuOPRRR::Fsgnj, + width: FpuOPWidth::S, + frm: FRM::RNE, + rd: writable_fa0(), + rs1: fa1(), + rs2: fa1(), + }, + "fmv.s fa0,fa1", + 0x20b58553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + alu_op: FpuOPRRR::Fsgnj, + width: FpuOPWidth::D, + frm: FRM::RNE, + rd: writable_fa0(), + rs1: fa1(), + rs2: fa1(), + }, + "fmv.d fa0,fa1", + 0x22b58553, + )); + + insns.push(TestUnit::new( + Inst::FpuRRR { + alu_op: FpuOPRRR::Fsgnjn, + width: FpuOPWidth::S, + frm: FRM::RTZ, + rd: writable_fa0(), + rs1: fa1(), + rs2: fa1(), + }, + "fneg.s fa0,fa1", + 0x20b59553, + )); + insns.push(TestUnit::new( + Inst::FpuRRR { + alu_op: FpuOPRRR::Fsgnjn, + width: FpuOPWidth::D, + frm: FRM::RTZ, + rd: writable_fa0(), + rs1: fa1(), + rs2: fa1(), + }, + "fneg.d fa0,fa1", + 0x22b59553, + )); + + insns.push(TestUnit::new( + Inst::Fli { + ty: F32, + rd: writable_fa0(), + imm: FliConstant::new(0), + }, + "fli.s fa0,-1.0", + 0xf0100553, + )); + + insns.push(TestUnit::new( + Inst::Fli { + ty: F64, + rd: writable_fa0(), + imm: FliConstant::new(13), + }, + "fli.d fa0,0.625", + 0xf2168553, + )); + + let (flags, isa_flags) = make_test_flags(); + let emit_info = EmitInfo::new(flags, isa_flags); + + for unit in insns.iter() { + println!("Riscv64: {:?}, {}", unit.inst, unit.assembly); + // Check the printed text is as expected. + let actual_printing = unit.inst.print_with_state(&mut EmitState::default()); + assert_eq!(unit.assembly, actual_printing); + let mut buffer = MachBuffer::new(); + unit.inst + .emit(&mut buffer, &emit_info, &mut Default::default()); + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + let actual_encoding = buffer.stringify_code_bytes(); + + assert_eq!(actual_encoding, unit.code.0); + } +} + +fn make_test_flags() -> (settings::Flags, super::super::riscv_settings::Flags) { + let b = settings::builder(); + let flags = settings::Flags::new(b.clone()); + let b2 = super::super::riscv_settings::builder(); + let isa_flags = super::super::riscv_settings::Flags::new(&flags, &b2); + (flags, isa_flags) +} + +#[test] +fn riscv64_worst_case_instruction_size() { + let (flags, isa_flags) = make_test_flags(); + let emit_info = EmitInfo::new(flags, isa_flags); + + // These are all candidate instructions with potential to generate a lot of bytes. + let mut candidates: Vec = vec![]; + + candidates.push(Inst::Popcnt { + sum: writable_a0(), + tmp: writable_a0(), + step: writable_a0(), + rs: a0(), + ty: I64, + }); + + candidates.push(Inst::Cltz { + sum: writable_a0(), + tmp: writable_a0(), + step: writable_a0(), + rs: a0(), + leading: true, + ty: I64, + }); + + candidates.push(Inst::Brev8 { + rd: writable_a0(), + tmp: writable_a0(), + step: writable_a0(), + tmp2: writable_a0(), + rs: a0(), + ty: I64, + }); + + candidates.push(Inst::AtomicCas { + offset: a0(), + t0: writable_a0(), + dst: writable_a0(), + e: a0(), + addr: a0(), + v: a0(), + ty: I64, + }); + + candidates.push(Inst::AtomicCas { + offset: a0(), + t0: writable_a0(), + dst: writable_a0(), + e: a0(), + addr: a0(), + v: a0(), + ty: I16, + }); + + candidates.extend( + crate::ir::AtomicRmwOp::all() + .iter() + .map(|op| Inst::AtomicRmwLoop { + op: *op, + offset: a0(), + dst: writable_a1(), + ty: I16, + p: a1(), + x: a2(), + t0: writable_a0(), + }), + ); + + // Return Call Indirect and BrTable are the largest instructions possible. However they + // emit their own island, so we don't account them here. + + let mut max: (u32, MInst) = (0, Inst::Nop0); + for i in candidates { + let mut buffer = MachBuffer::new(); + let mut emit_state = Default::default(); + i.emit(&mut buffer, &emit_info, &mut emit_state); + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + let length = buffer.data().len() as u32; + if length > max.0 { + let length = buffer.data().len() as u32; + max = (length, i.clone()); + } + println!("insn:{i:?} length: {length}"); + } + println!("calculate max size is {} , inst is {:?}", max.0, max.1); + assert!(max.0 <= Inst::worst_case_size()); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/encode.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/encode.rs new file mode 100644 index 00000000000000..f2f159f876057d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/encode.rs @@ -0,0 +1,721 @@ +//! Contains the RISC-V instruction encoding logic. +//! +//! These formats are specified in the RISC-V specification in section 2.2. +//! See: +//! +//! Some instructions especially in extensions have slight variations from +//! the base RISC-V specification. + +use super::*; +use crate::isa::riscv64::lower::isle::generated_code::{ + COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, + VecAluOpRImm5, VecAluOpRR, VecAluOpRRRImm5, VecAluOpRRRR, VecOpCategory, ZcbMemOp, +}; +use crate::machinst::isle::WritableReg; + +fn unsigned_field_width(value: u32, width: u8) -> u32 { + debug_assert_eq!(value & (!0 << width), 0); + value +} + +/// Layout: +/// 0-------6-7-------11-12------14-15------19-20------24-25-------31 +/// | Opcode | rd | funct3 | rs1 | rs2 | funct7 | +fn encode_r_type_bits(opcode: u32, rd: u32, funct3: u32, rs1: u32, rs2: u32, funct7: u32) -> u32 { + let mut bits = 0; + bits |= unsigned_field_width(opcode, 7); + bits |= unsigned_field_width(rd, 5) << 7; + bits |= unsigned_field_width(funct3, 3) << 12; + bits |= unsigned_field_width(rs1, 5) << 15; + bits |= unsigned_field_width(rs2, 5) << 20; + bits |= unsigned_field_width(funct7, 7) << 25; + bits +} + +/// Encode an R-type instruction. +pub fn encode_r_type( + opcode: u32, + rd: WritableReg, + funct3: u32, + rs1: Reg, + rs2: Reg, + funct7: u32, +) -> u32 { + encode_r_type_bits( + opcode, + reg_to_gpr_num(rd.to_reg()), + funct3, + reg_to_gpr_num(rs1), + reg_to_gpr_num(rs2), + funct7, + ) +} + +/// Layout: +/// 0-------6-7-------11-12------14-15------19-20------------------31 +/// | Opcode | rd | width | rs1 | Offset[11:0] | +fn encode_i_type_bits(opcode: u32, rd: u32, funct3: u32, rs1: u32, offset: u32) -> u32 { + let mut bits = 0; + bits |= unsigned_field_width(opcode, 7); + bits |= unsigned_field_width(rd, 5) << 7; + bits |= unsigned_field_width(funct3, 3) << 12; + bits |= unsigned_field_width(rs1, 5) << 15; + bits |= unsigned_field_width(offset, 12) << 20; + bits +} + +/// Encode an I-type instruction. +pub fn encode_i_type(opcode: u32, rd: WritableReg, width: u32, rs1: Reg, offset: Imm12) -> u32 { + encode_i_type_bits( + opcode, + reg_to_gpr_num(rd.to_reg()), + width, + reg_to_gpr_num(rs1), + offset.bits(), + ) +} + +/// Encode an S-type instruction. +/// +/// Layout: +/// 0-------6-7-------11-12------14-15------19-20---24-25-------------31 +/// | Opcode | imm[4:0] | width | base | src | imm[11:5] | +pub fn encode_s_type(opcode: u32, width: u32, base: Reg, src: Reg, offset: Imm12) -> u32 { + let mut bits = 0; + bits |= unsigned_field_width(opcode, 7); + bits |= (offset.bits() & 0b11111) << 7; + bits |= unsigned_field_width(width, 3) << 12; + bits |= reg_to_gpr_num(base) << 15; + bits |= reg_to_gpr_num(src) << 20; + bits |= unsigned_field_width(offset.bits() >> 5, 7) << 25; + bits +} + +/// Encodes a Vector ALU instruction. +/// +/// Fields: +/// - opcode (7 bits) +/// - vd (5 bits) +/// - funct3 (3 bits) +/// - vs1 (5 bits) +/// - vs2 (5 bits) +/// - vm (1 bit) +/// - funct6 (6 bits) +/// +/// See: https://github.com/riscv/riscv-v-spec/blob/master/valu-format.adoc +pub fn encode_valu( + op: VecAluOpRRR, + vd: WritableReg, + vs1: Reg, + vs2: Reg, + masking: VecOpMasking, +) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + reg_to_gpr_num(vs1), + reg_to_gpr_num(vs2), + funct7, + ) +} + +/// Encodes a Vector ALU+Imm instruction. +/// This is just a Vector ALU instruction with an immediate in the VS1 field. +/// +/// Fields: +/// - opcode (7 bits) +/// - vd (5 bits) +/// - funct3 (3 bits) +/// - imm (5 bits) +/// - vs2 (5 bits) +/// - vm (1 bit) +/// - funct6 (6 bits) +/// +/// See: https://github.com/riscv/riscv-v-spec/blob/master/valu-format.adoc +pub fn encode_valu_rr_imm( + op: VecAluOpRRImm5, + vd: WritableReg, + imm: Imm5, + vs2: Reg, + masking: VecOpMasking, +) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + let imm = imm.bits() as u32; + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + imm, + reg_to_gpr_num(vs2), + funct7, + ) +} + +pub fn encode_valu_rrrr( + op: VecAluOpRRRR, + vd: WritableReg, + vs2: Reg, + vs1: Reg, + masking: VecOpMasking, +) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + reg_to_gpr_num(vs1), + reg_to_gpr_num(vs2), + funct7, + ) +} + +pub fn encode_valu_rrr_imm( + op: VecAluOpRRRImm5, + vd: WritableReg, + imm: Imm5, + vs2: Reg, + masking: VecOpMasking, +) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + let imm = imm.bits() as u32; + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + imm, + reg_to_gpr_num(vs2), + funct7, + ) +} + +pub fn encode_valu_rr(op: VecAluOpRR, vd: WritableReg, vs: Reg, masking: VecOpMasking) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + + let (vs1, vs2) = if op.vs_is_vs2_encoded() { + (op.aux_encoding(), reg_to_gpr_num(vs)) + } else { + (reg_to_gpr_num(vs), op.aux_encoding()) + }; + + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + vs1, + vs2, + funct7, + ) +} + +pub fn encode_valu_r_imm( + op: VecAluOpRImm5, + vd: WritableReg, + imm: Imm5, + masking: VecOpMasking, +) -> u32 { + let funct7 = (op.funct6() << 1) | masking.encode(); + + // This is true for this opcode, not sure if there are any other ones. + debug_assert_eq!(op, VecAluOpRImm5::VmvVI); + let vs1 = imm.bits() as u32; + let vs2 = op.aux_encoding(); + + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(vd.to_reg()), + op.funct3(), + vs1, + vs2, + funct7, + ) +} + +/// Encodes a Vector CFG Imm instruction. +/// +/// See: https://github.com/riscv/riscv-v-spec/blob/master/vcfg-format.adoc +// TODO: Check if this is any of the known instruction types in the spec. +pub fn encode_vcfg_imm(opcode: u32, rd: Reg, imm: UImm5, vtype: &VType) -> u32 { + let mut bits = 0; + bits |= unsigned_field_width(opcode, 7); + bits |= reg_to_gpr_num(rd) << 7; + bits |= VecOpCategory::OPCFG.encode() << 12; + bits |= unsigned_field_width(imm.bits(), 5) << 15; + bits |= unsigned_field_width(vtype.encode(), 10) << 20; + bits |= 0b11 << 30; + bits +} + +/// Encodes a Vector Mem Unit Stride Load instruction. +/// +/// See: https://github.com/riscv/riscv-v-spec/blob/master/vmem-format.adoc +/// TODO: These instructions share opcode space with LOAD-FP and STORE-FP +pub fn encode_vmem_load( + opcode: u32, + vd: Reg, + width: VecElementWidth, + rs1: Reg, + lumop: u32, + masking: VecOpMasking, + mop: u32, + nf: u32, +) -> u32 { + // Width is encoded differently to avoid a clash with the FP load/store sizes. + let width = match width { + VecElementWidth::E8 => 0b000, + VecElementWidth::E16 => 0b101, + VecElementWidth::E32 => 0b110, + VecElementWidth::E64 => 0b111, + }; + + let mut bits = 0; + bits |= unsigned_field_width(opcode, 7); + bits |= reg_to_gpr_num(vd) << 7; + bits |= width << 12; + bits |= reg_to_gpr_num(rs1) << 15; + bits |= unsigned_field_width(lumop, 5) << 20; + bits |= masking.encode() << 25; + bits |= unsigned_field_width(mop, 2) << 26; + + // The mew bit (inst[28]) when set is expected to be used to encode expanded + // memory sizes of 128 bits and above, but these encodings are currently reserved. + bits |= 0b0 << 28; + + bits |= unsigned_field_width(nf, 3) << 29; + bits +} + +/// Encodes a Vector Mem Unit Stride Load instruction. +/// +/// See: https://github.com/riscv/riscv-v-spec/blob/master/vmem-format.adoc +/// TODO: These instructions share opcode space with LOAD-FP and STORE-FP +pub fn encode_vmem_store( + opcode: u32, + vs3: Reg, + width: VecElementWidth, + rs1: Reg, + sumop: u32, + masking: VecOpMasking, + mop: u32, + nf: u32, +) -> u32 { + // This is pretty much the same as the load instruction, just + // with different names on the fields. + encode_vmem_load(opcode, vs3, width, rs1, sumop, masking, mop, nf) +} + +// The CSR Reg instruction is really just an I type instruction with the CSR in +// the immediate field. +pub fn encode_csr_reg(op: CsrRegOP, rd: WritableReg, rs: Reg, csr: CSR) -> u32 { + encode_i_type(op.opcode(), rd, op.funct3(), rs, csr.bits()) +} + +// The CSR Imm instruction is an I type instruction with the CSR in +// the immediate field and the value to be set in the `rs1` field. +pub fn encode_csr_imm(op: CsrImmOP, rd: WritableReg, csr: CSR, imm: UImm5) -> u32 { + encode_i_type_bits( + op.opcode(), + reg_to_gpr_num(rd.to_reg()), + op.funct3(), + imm.bits(), + csr.bits().bits(), + ) +} + +// Encode a CR type instruction. +// +// 0--1-2-----6-7-------11-12-------15 +// |op | rs2 | rd/rs1 | funct4 | +pub fn encode_cr_type(op: CrOp, rd: WritableReg, rs2: Reg) -> u16 { + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= reg_to_gpr_num(rs2) << 2; + bits |= reg_to_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(op.funct4(), 4) << 12; + bits.try_into().unwrap() +} + +// This isn't technically a instruction format that exists. It's just a CR type +// where the source is rs1, rs2 is zero. rs1 is never written to. +// +// Used for C.JR and C.JALR +pub fn encode_cr2_type(op: CrOp, rs1: Reg) -> u16 { + encode_cr_type(op, WritableReg::from_reg(rs1), zero_reg()) +} + +// Encode a CA type instruction. +// +// 0--1-2-----4-5--------6-7--------9-10------15 +// |op | rs2 | funct2 | rd/rs1 | funct6 | +pub fn encode_ca_type(op: CaOp, rd: WritableReg, rs2: Reg) -> u16 { + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= reg_to_compressed_gpr_num(rs2) << 2; + bits |= unsigned_field_width(op.funct2(), 2) << 5; + bits |= reg_to_compressed_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(op.funct6(), 6) << 10; + bits.try_into().unwrap() +} + +// Encode a CJ type instruction. +// +// The imm field is a 11 bit signed immediate that is shifted left by 1. +// +// 0--1-2-----12-13--------15 +// |op | imm | funct3 | +pub fn encode_cj_type(op: CjOp, imm: Imm12) -> u16 { + let imm = imm.bits(); + debug_assert!(imm & 1 == 0); + + // The offset bits are in rather weird positions. + // [11|4|9:8|10|6|7|3:1|5] + let mut imm_field = 0; + imm_field |= ((imm >> 11) & 1) << 10; + imm_field |= ((imm >> 4) & 1) << 9; + imm_field |= ((imm >> 8) & 3) << 7; + imm_field |= ((imm >> 10) & 1) << 6; + imm_field |= ((imm >> 6) & 1) << 5; + imm_field |= ((imm >> 7) & 1) << 4; + imm_field |= ((imm >> 1) & 7) << 1; + imm_field |= ((imm >> 5) & 1) << 0; + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= unsigned_field_width(imm_field, 11) << 2; + bits |= unsigned_field_width(op.funct3(), 3) << 13; + bits.try_into().unwrap() +} + +// Encode a CI type instruction. +// +// The imm field is a 6 bit signed immediate. +// +// 0--1-2-------6-7-------11-12-----12-13-----15 +// |op | imm[4:0] | src | imm[5] | funct3 | +pub fn encode_ci_type(op: CiOp, rd: WritableReg, imm: Imm6) -> u16 { + let imm = imm.bits(); + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= unsigned_field_width((imm & 0x1f) as u32, 5) << 2; + bits |= reg_to_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(((imm >> 5) & 1) as u32, 1) << 12; + bits |= unsigned_field_width(op.funct3(), 3) << 13; + bits.try_into().unwrap() +} + +// Stack-Pointer relative loads are regular CI instructions, but, the immediate +// is zero extended, and with a slightly different immediate field encoding. +pub fn encode_ci_sp_load(op: CiOp, rd: WritableReg, imm: Uimm6) -> u16 { + let imm = imm.bits(); + + // These are the spec encoded offsets. + // LWSP: [5|4:2|7:6] + // LDSP: [5|4:3|8:6] + // FLDSP: [5|4:3|8:6] + // + // We don't receive the entire offset in `imm`, just a multiple of the load-size. + + // Number of bits in the lowest position of imm. 3 for lwsp, 2 for {f,}ldsp. + let low_bits = match op { + CiOp::CLwsp => 3, // [4:2] + CiOp::CLdsp | CiOp::CFldsp => 2, // [4:3] + _ => unreachable!(), + }; + let high_bits = 6 - 1 - low_bits; + let mut enc_imm = 0; + + // Encode [7:6] at the bottom of imm + enc_imm |= imm >> (6 - high_bits); + + // Next place [4:2] in the middle + enc_imm |= (imm & ((1 << low_bits) - 1)) << high_bits; + + // Finally place [5] at the top + enc_imm |= ((imm >> low_bits) & 1) << 5; + + let enc_imm = Imm6::maybe_from_i16((enc_imm as i16) << 10 >> 10).unwrap(); + + encode_ci_type(op, rd, enc_imm) +} + +/// c.addi16sp is a regular CI op, but the immediate field is encoded in a weird way +pub fn encode_c_addi16sp(imm: Imm6) -> u16 { + let imm = imm.bits(); + + // [6|1|3|5:4|2] + let mut enc_imm = 0; + enc_imm |= ((imm >> 5) & 1) << 5; + enc_imm |= ((imm >> 0) & 1) << 4; + enc_imm |= ((imm >> 2) & 1) << 3; + enc_imm |= ((imm >> 3) & 3) << 1; + enc_imm |= ((imm >> 1) & 1) << 0; + let enc_imm = Imm6::maybe_from_i16((enc_imm as i16) << 10 >> 10).unwrap(); + + encode_ci_type(CiOp::CAddi16sp, writable_stack_reg(), enc_imm) +} + +// Encode a CIW type instruction. +// +// 0--1-2------4-5------12-13--------15 +// |op | rd | imm | funct3 | +pub fn encode_ciw_type(op: CiwOp, rd: WritableReg, imm: u8) -> u16 { + // [3:2|7:4|0|1] + let mut imm_field = 0; + imm_field |= ((imm >> 1) & 1) << 0; + imm_field |= ((imm >> 0) & 1) << 1; + imm_field |= ((imm >> 4) & 15) << 2; + imm_field |= ((imm >> 2) & 3) << 6; + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= reg_to_compressed_gpr_num(rd.to_reg()) << 2; + bits |= unsigned_field_width(imm_field as u32, 8) << 5; + bits |= unsigned_field_width(op.funct3(), 3) << 13; + bits.try_into().unwrap() +} + +// Encode a CB type instruction. +// +// The imm field is a 6 bit signed immediate. +// +// 0--1-2-------6-7-------9-10-------11-12-------13--------15 +// |op | imm[4:0] | dst | funct2 | imm[5] | funct3 | +pub fn encode_cb_type(op: CbOp, rd: WritableReg, imm: Imm6) -> u16 { + let imm = imm.bits(); + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= unsigned_field_width((imm & 0x1f) as u32, 5) << 2; + bits |= reg_to_compressed_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(op.funct2(), 2) << 10; + bits |= unsigned_field_width(((imm >> 5) & 1) as u32, 1) << 12; + bits |= unsigned_field_width(op.funct3(), 3) << 13; + bits.try_into().unwrap() +} + +// Encode a CSS type instruction. +// +// The imm field is a 6 bit unsigned immediate. +// +// 0--1-2-------6-7--------12-13-------15 +// |op | src | imm | funct3 | +pub fn encode_css_type(op: CssOp, src: Reg, imm: Uimm6) -> u16 { + let imm = imm.bits(); + + // These are the spec encoded offsets. + // c.swsp: [5:2|7:6] + // c.sdsp: [5:3|8:6] + // c.fsdsp: [5:3|8:6] + // + // We don't receive the entire offset in `imm`, just a multiple of the load-size. + + // Number of bits in the lowest position of imm. 4 for c.swsp, 3 for c.{f,}sdsp. + let low_bits = match op { + CssOp::CSwsp => 4, // [5:2] + CssOp::CSdsp | CssOp::CFsdsp => 3, // [5:3] + }; + let high_bits = 6 - low_bits; + + let mut enc_imm = 0; + enc_imm |= (imm & ((1 << low_bits) - 1)) << high_bits; + enc_imm |= imm >> low_bits; + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= reg_to_gpr_num(src) << 2; + bits |= unsigned_field_width(enc_imm as u32, 6) << 7; + bits |= unsigned_field_width(op.funct3(), 3) << 13; + bits.try_into().unwrap() +} + +// Encode a CS type instruction. +// +// The imm field is a 5 bit unsigned immediate. +// +// 0--1-2-----4-5----------6-7---------9-10----------12-13-----15 +// |op | src | imm(2-bit) | base | imm(3-bit) | funct3 | +pub fn encode_cs_type(op: CsOp, src: Reg, base: Reg, imm: Uimm5) -> u16 { + let size = match op { + CsOp::CFsd | CsOp::CSd => 8, + CsOp::CSw => 4, + }; + + encode_cs_cl_type_bits(op.op(), op.funct3(), size, src, base, imm) +} + +// Encode a CL type instruction. +// +// The imm field is a 5 bit unsigned immediate. +// +// 0--1-2------4-5----------6-7---------9-10----------12-13-----15 +// |op | dest | imm(2-bit) | base | imm(3-bit) | funct3 | +pub fn encode_cl_type(op: ClOp, dest: WritableReg, base: Reg, imm: Uimm5) -> u16 { + let size = match op { + ClOp::CFld | ClOp::CLd => 8, + ClOp::CLw => 4, + }; + + encode_cs_cl_type_bits(op.op(), op.funct3(), size, dest.to_reg(), base, imm) +} + +// CL and CS type instructions have the same physical layout. +// +// 0--1-2----------4-5----------6-7---------9-10----------12-13-----15 +// |op | dest/src | imm(2-bit) | base | imm(3-bit) | funct3 | +fn encode_cs_cl_type_bits( + op: COpcodeSpace, + funct3: u32, + size: u32, + dest_src: Reg, + base: Reg, + imm: Uimm5, +) -> u16 { + let imm = imm.bits(); + + // c.sw / c.lw: [2|6] + // c.sd / c.ld: [7:6] + // c.fsd / c.fld: [7:6] + // + // We differentiate these based on the operation size + let imm2 = match size { + 4 => ((imm >> 4) & 1) | ((imm & 1) << 1), + 8 => (imm >> 3) & 0b11, + _ => unreachable!(), + }; + + // [5:3] on all opcodes + let imm3 = match size { + 4 => (imm >> 1) & 0b111, + 8 => (imm >> 0) & 0b111, + _ => unreachable!(), + }; + + let mut bits = 0; + bits |= unsigned_field_width(op.bits(), 2); + bits |= reg_to_compressed_gpr_num(dest_src) << 2; + bits |= unsigned_field_width(imm2 as u32, 2) << 5; + bits |= reg_to_compressed_gpr_num(base) << 7; + bits |= unsigned_field_width(imm3 as u32, 3) << 10; + bits |= unsigned_field_width(funct3, 3) << 13; + bits.try_into().unwrap() +} + +// Encode a CSZN type instruction. +// +// This is an additional encoding format that is introduced in the Zcb extension. +// +// 0--1-2---------6-7--------9-10------15 +// |op | funct5 | rd/rs1 | funct6 | +pub fn encode_cszn_type(op: CsznOp, rd: WritableReg) -> u16 { + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= unsigned_field_width(op.funct5(), 5) << 2; + bits |= reg_to_compressed_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(op.funct6(), 6) << 10; + bits.try_into().unwrap() +} + +// Encodes the various memory operations in the Zcb extension. +// +// 0--1-2----------4-5----------6-7---------9-10-------15 +// |op | dest/src | imm(2-bit) | base | funct6 | +fn encode_zcbmem_bits(op: ZcbMemOp, dest_src: Reg, base: Reg, imm: Uimm2) -> u16 { + let imm = imm.bits(); + + // For these ops, bit 6 is part of the opcode, and bit 5 encodes the imm offset. + let imm = match op { + ZcbMemOp::CLh | ZcbMemOp::CLhu | ZcbMemOp::CSh => { + debug_assert_eq!(imm & !1, 0); + // Only c.lh has this bit as 1 + let opcode_bit = (op == ZcbMemOp::CLh) as u8; + imm | (opcode_bit << 1) + } + // In the rest of the ops the imm is reversed. + _ => ((imm & 1) << 1) | ((imm >> 1) & 1), + }; + + let mut bits = 0; + bits |= unsigned_field_width(op.op().bits(), 2); + bits |= reg_to_compressed_gpr_num(dest_src) << 2; + bits |= unsigned_field_width(imm as u32, 2) << 5; + bits |= reg_to_compressed_gpr_num(base) << 7; + bits |= unsigned_field_width(op.funct6(), 6) << 10; + bits.try_into().unwrap() +} + +pub fn encode_zcbmem_load(op: ZcbMemOp, rd: WritableReg, base: Reg, imm: Uimm2) -> u16 { + encode_zcbmem_bits(op, rd.to_reg(), base, imm) +} + +pub fn encode_zcbmem_store(op: ZcbMemOp, src: Reg, base: Reg, imm: Uimm2) -> u16 { + encode_zcbmem_bits(op, src, base, imm) +} + +pub fn encode_fli(ty: Type, imm: FliConstant, rd: WritableReg) -> u32 { + // FLI.{S,D} is encoded as a FMV.{W,D} instruction with rs2 set to the + // immediate value to be loaded. + let op = FpuOPRR::FmvFmtX; + let width = FpuOPWidth::try_from(ty).unwrap(); + let frm = 0; // FRM is hard coded to 0 in both instructions + let rs2 = 1; // rs2 set to 1 is what differentiates FLI from FMV + + let mut bits = 0; + bits |= unsigned_field_width(op.opcode(), 7); + bits |= reg_to_gpr_num(rd.to_reg()) << 7; + bits |= unsigned_field_width(frm, 3) << 12; + bits |= unsigned_field_width(imm.bits() as u32, 5) << 15; + bits |= unsigned_field_width(rs2, 6) << 20; + bits |= unsigned_field_width(op.funct7(width), 7) << 25; + bits +} + +pub fn encode_fp_rr(op: FpuOPRR, width: FpuOPWidth, frm: FRM, rd: WritableReg, rs: Reg) -> u32 { + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(rd.to_reg()), + frm.as_u32(), + reg_to_gpr_num(rs), + op.rs2(), + op.funct7(width), + ) +} + +pub fn encode_fp_rrr( + op: FpuOPRRR, + width: FpuOPWidth, + frm: FRM, + rd: WritableReg, + rs1: Reg, + rs2: Reg, +) -> u32 { + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(rd.to_reg()), + frm.as_u32(), + reg_to_gpr_num(rs1), + reg_to_gpr_num(rs2), + op.funct7(width), + ) +} + +pub fn encode_fp_rrrr( + op: FpuOPRRRR, + width: FpuOPWidth, + frm: FRM, + rd: WritableReg, + rs1: Reg, + rs2: Reg, + rs3: Reg, +) -> u32 { + let funct7 = (reg_to_gpr_num(rs3) << 2) | width.as_u32(); + encode_r_type_bits( + op.opcode(), + reg_to_gpr_num(rd.to_reg()), + frm.as_u32(), + reg_to_gpr_num(rs1), + reg_to_gpr_num(rs2), + funct7, + ) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/imms.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/imms.rs new file mode 100644 index 00000000000000..8f53506ce04924 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/imms.rs @@ -0,0 +1,373 @@ +//! Riscv64 ISA definitions: immediate constants. + +// Some variants are never constructed, but we still want them as options in the future. +use super::Inst; +use std::fmt::{Debug, Display, Formatter, Result}; + +#[derive(Copy, Clone, Debug, Default)] +pub struct Imm12 { + /// 16-bit container where the low 12 bits are the data payload. + /// + /// Acquiring the underlying value requires sign-extending the 12th bit. + bits: u16, +} + +impl Imm12 { + pub(crate) const ZERO: Self = Self { bits: 0 }; + pub(crate) const ONE: Self = Self { bits: 1 }; + + pub fn maybe_from_u64(val: u64) -> Option { + Self::maybe_from_i64(val as i64) + } + + pub fn maybe_from_i64(val: i64) -> Option { + if val >= -2048 && val <= 2047 { + Some(Imm12 { + bits: val as u16 & 0xfff, + }) + } else { + None + } + } + + #[inline] + pub fn from_i16(bits: i16) -> Self { + assert!(bits >= -2048 && bits <= 2047); + Self { + bits: (bits & 0xfff) as u16, + } + } + + #[inline] + pub fn as_i16(self) -> i16 { + (self.bits << 4) as i16 >> 4 + } + + #[inline] + pub fn bits(&self) -> u32 { + self.bits.into() + } +} + +impl Into for Imm12 { + fn into(self) -> i64 { + self.as_i16().into() + } +} + +impl Display for Imm12 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{:+}", self.as_i16()) + } +} + +// signed +#[derive(Clone, Copy, Default)] +pub struct Imm20 { + /// 32-bit container where the low 20 bits are the data payload. + /// + /// Acquiring the underlying value requires sign-extending the 20th bit. + bits: u32, +} + +impl Imm20 { + pub(crate) const ZERO: Self = Self { bits: 0 }; + + pub fn maybe_from_u64(val: u64) -> Option { + Self::maybe_from_i64(val as i64) + } + + pub fn maybe_from_i64(val: i64) -> Option { + if val >= -(0x7_ffff + 1) && val <= 0x7_ffff { + Some(Imm20 { bits: val as u32 }) + } else { + None + } + } + + #[inline] + pub fn from_i32(bits: i32) -> Self { + assert!(bits >= -(0x7_ffff + 1) && bits <= 0x7_ffff); + Self { + bits: (bits as u32) & 0xf_ffff, + } + } + + #[inline] + pub fn as_i32(&self) -> i32 { + ((self.bits << 12) as i32) >> 12 + } + + #[inline] + pub fn bits(&self) -> u32 { + self.bits + } +} + +impl Debug for Imm20 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.as_i32()) + } +} + +impl Display for Imm20 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.bits) + } +} + +/// An unsigned 5-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct UImm5 { + value: u8, +} + +impl UImm5 { + /// Create an unsigned 5-bit immediate from u8. + pub fn maybe_from_u8(value: u8) -> Option { + if value < 32 { + Some(UImm5 { value }) + } else { + None + } + } + + /// Bits for encoding. + pub fn bits(&self) -> u32 { + u32::from(self.value) + } +} + +impl Display for UImm5 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +/// A Signed 5-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Imm5 { + value: i8, +} + +impl Imm5 { + /// Create an signed 5-bit immediate from an i8. + pub fn maybe_from_i8(value: i8) -> Option { + if value >= -16 && value <= 15 { + Some(Imm5 { value }) + } else { + None + } + } + + pub fn from_bits(value: u8) -> Imm5 { + assert_eq!(value & 0x1f, value); + let signed = ((value << 3) as i8) >> 3; + Imm5 { value: signed } + } + + /// Bits for encoding. + pub fn bits(&self) -> u8 { + self.value as u8 & 0x1f + } +} + +impl Display for Imm5 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +/// A Signed 6-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Imm6 { + value: i8, +} + +impl Imm6 { + /// Create an signed 6-bit immediate from an i16 + pub fn maybe_from_i16(value: i16) -> Option { + if value >= -32 && value <= 31 { + Some(Self { value: value as i8 }) + } else { + None + } + } + + pub fn maybe_from_i32(value: i32) -> Option { + value.try_into().ok().and_then(Imm6::maybe_from_i16) + } + + pub fn maybe_from_imm12(value: Imm12) -> Option { + Imm6::maybe_from_i16(value.as_i16()) + } + + /// Bits for encoding. + pub fn bits(&self) -> u8 { + self.value as u8 & 0x3f + } +} + +impl Display for Imm6 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +/// A unsigned 6-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Uimm6 { + value: u8, +} + +impl Uimm6 { + /// Create an unsigned 6-bit immediate from an u8 + pub fn maybe_from_u8(value: u8) -> Option { + if value <= 63 { + Some(Self { value }) + } else { + None + } + } + + /// Bits for encoding. + pub fn bits(&self) -> u8 { + self.value & 0x3f + } +} + +impl Display for Uimm6 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +/// A unsigned 5-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Uimm5 { + value: u8, +} + +impl Uimm5 { + /// Create an unsigned 5-bit immediate from an u8 + pub fn maybe_from_u8(value: u8) -> Option { + if value <= 31 { + Some(Self { value }) + } else { + None + } + } + + /// Bits for encoding. + pub fn bits(&self) -> u8 { + self.value & 0x1f + } +} + +impl Display for Uimm5 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +/// A unsigned 2-bit immediate. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Uimm2 { + value: u8, +} + +impl Uimm2 { + /// Create an unsigned 2-bit immediate from an u8 + pub fn maybe_from_u8(value: u8) -> Option { + if value <= 3 { + Some(Self { value }) + } else { + None + } + } + + /// Bits for encoding. + pub fn bits(&self) -> u8 { + self.value & 0x3 + } +} + +impl Display for Uimm2 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.value) + } +} + +impl Inst { + pub(crate) fn imm_min() -> i64 { + let imm20_max: i64 = (1 << 19) << 12; + let imm12_max = 1 << 11; + -imm20_max - imm12_max + } + pub(crate) fn imm_max() -> i64 { + let imm20_max: i64 = ((1 << 19) - 1) << 12; + let imm12_max = (1 << 11) - 1; + imm20_max + imm12_max + } + + /// An imm20 immediate and an Imm12 immediate can generate a 32-bit immediate. + /// This helper produces an imm12, imm20, or both to generate the value. + /// + /// `value` must be between `imm_min()` and `imm_max()`, or else + /// this helper returns `None`. + pub(crate) fn generate_imm(value: u64) -> Option<(Imm20, Imm12)> { + if let Some(imm12) = Imm12::maybe_from_u64(value) { + // can be load using single imm12. + return Some((Imm20::ZERO, imm12)); + } + let value = value as i64; + if !(value >= Self::imm_min() && value <= Self::imm_max()) { + // not in range, return None. + return None; + } + const MOD_NUM: i64 = 4096; + let (imm20, imm12) = if value > 0 { + let mut imm20 = value / MOD_NUM; + let mut imm12 = value % MOD_NUM; + if imm12 >= 2048 { + imm12 -= MOD_NUM; + imm20 += 1; + } + assert!(imm12 >= -2048 && imm12 <= 2047); + (imm20, imm12) + } else { + // this is the abs value. + let value_abs = value.abs(); + let imm20 = value_abs / MOD_NUM; + let imm12 = value_abs % MOD_NUM; + let mut imm20 = -imm20; + let mut imm12 = -imm12; + if imm12 < -2048 { + imm12 += MOD_NUM; + imm20 -= 1; + } + (imm20, imm12) + }; + assert!(imm20 != 0 || imm12 != 0); + let imm20 = i32::try_from(imm20).unwrap(); + let imm12 = i16::try_from(imm12).unwrap(); + Some((Imm20::from_i32(imm20), Imm12::from_i16(imm12))) + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_imm12() { + let x = Imm12::ZERO; + assert_eq!(0, x.bits()); + Imm12::maybe_from_u64(0xffff_ffff_ffff_ffff).unwrap(); + } + + #[test] + fn imm20_and_imm12() { + assert!(Inst::imm_max() == (i32::MAX - 2048) as i64); + assert!(Inst::imm_min() == i32::MIN as i64 - 2048); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/mod.rs new file mode 100644 index 00000000000000..14d5fd4fc76458 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/mod.rs @@ -0,0 +1,1865 @@ +//! This module defines riscv64-specific machine instruction types. + +use super::lower::isle::generated_code::{VecAMode, VecElementWidth, VecOpMasking}; +use crate::binemit::{Addend, CodeOffset, Reloc}; +pub use crate::ir::condcodes::IntCC; +use crate::ir::types::{self, F128, F16, F32, F64, I128, I16, I32, I64, I8, I8X16}; + +pub use crate::ir::{ExternalName, MemFlags, Type}; +use crate::isa::{CallConv, FunctionAlignment}; +use crate::machinst::*; +use crate::{settings, CodegenError, CodegenResult}; + +pub use crate::ir::condcodes::FloatCC; + +use alloc::vec::Vec; +use regalloc2::RegClass; +use smallvec::{smallvec, SmallVec}; +use std::boxed::Box; +use std::fmt::Write; +use std::string::{String, ToString}; + +pub mod regs; +pub use self::regs::*; +pub mod imms; +pub use self::imms::*; +pub mod args; +pub use self::args::*; +pub mod emit; +pub use self::emit::*; +pub mod vector; +pub use self::vector::*; +pub mod encode; +pub use self::encode::*; +pub mod unwind; + +use crate::isa::riscv64::abi::Riscv64MachineDeps; + +#[cfg(test)] +mod emit_tests; + +use std::fmt::{Display, Formatter}; + +pub(crate) type VecU8 = Vec; + +//============================================================================= +// Instructions (top level): definition + +pub use crate::isa::riscv64::lower::isle::generated_code::{ + AluOPRRI, AluOPRRR, AtomicOP, CsrImmOP, CsrRegOP, FClassResult, FFlagsException, FpuOPRR, + FpuOPRRR, FpuOPRRRR, LoadOP, MInst as Inst, StoreOP, CSR, FRM, +}; +use crate::isa::riscv64::lower::isle::generated_code::{CjOp, MInst, VecAluOpRRImm5, VecAluOpRRR}; + +/// Additional information for `return_call[_ind]` instructions, left out of +/// line to lower the size of the `Inst` enum. +#[derive(Clone, Debug)] +pub struct ReturnCallInfo { + pub dest: T, + pub uses: CallArgList, + pub new_stack_arg_size: u32, +} + +/// A conditional branch target. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CondBrTarget { + /// An unresolved reference to a Label, as passed into + /// `lower_branch_group()`. + Label(MachLabel), + /// No jump; fall through to the next instruction. + Fallthrough, +} + +impl CondBrTarget { + /// Return the target's label, if it is a label-based target. + pub(crate) fn as_label(self) -> Option { + match self { + CondBrTarget::Label(l) => Some(l), + _ => None, + } + } + + pub(crate) fn is_fallthrouh(&self) -> bool { + self == &CondBrTarget::Fallthrough + } +} + +impl Display for CondBrTarget { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + CondBrTarget::Label(l) => write!(f, "{}", l.to_string()), + CondBrTarget::Fallthrough => write!(f, "0"), + } + } +} + +pub(crate) fn enc_auipc(rd: Writable, imm: Imm20) -> u32 { + let x = 0b0010111 | reg_to_gpr_num(rd.to_reg()) << 7 | imm.bits() << 12; + x +} + +pub(crate) fn enc_jalr(rd: Writable, base: Reg, offset: Imm12) -> u32 { + let x = 0b1100111 + | reg_to_gpr_num(rd.to_reg()) << 7 + | 0b000 << 12 + | reg_to_gpr_num(base) << 15 + | offset.bits() << 20; + x +} + +/// rd and src must have the same length. +pub(crate) fn gen_moves(rd: &[Writable], src: &[Reg]) -> SmallInstVec { + assert!(rd.len() == src.len()); + assert!(rd.len() > 0); + let mut insts = SmallInstVec::new(); + for (dst, src) in rd.iter().zip(src.iter()) { + let ty = Inst::canonical_type_for_rc(dst.to_reg().class()); + insts.push(Inst::gen_move(*dst, *src, ty)); + } + insts +} + +impl Inst { + /// RISC-V can have multiple instruction sizes. 2 bytes for compressed + /// instructions, 4 for regular instructions, 6 and 8 byte instructions + /// are also being considered. + const UNCOMPRESSED_INSTRUCTION_SIZE: i32 = 4; + + #[inline] + pub(crate) fn load_imm12(rd: Writable, imm: Imm12) -> Inst { + Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs: zero_reg(), + imm12: imm, + } + } + + /// Immediates can be loaded using lui and addi instructions. + fn load_const_imm(rd: Writable, value: u64) -> Option> { + Inst::generate_imm(value).map(|(imm20, imm12)| { + let mut insts = SmallVec::new(); + + let imm20_is_zero = imm20.as_i32() == 0; + let imm12_is_zero = imm12.as_i16() == 0; + + let rs = if !imm20_is_zero { + insts.push(Inst::Lui { rd, imm: imm20 }); + rd.to_reg() + } else { + zero_reg() + }; + + // We also need to emit the addi if the value is 0, otherwise we just + // won't produce any instructions. + if !imm12_is_zero || (imm20_is_zero && imm12_is_zero) { + insts.push(Inst::AluRRImm12 { + alu_op: AluOPRRI::Addi, + rd, + rs, + imm12, + }) + } + + insts + }) + } + + pub(crate) fn load_constant_u32(rd: Writable, value: u64) -> SmallInstVec { + let insts = Inst::load_const_imm(rd, value); + insts.unwrap_or_else(|| { + smallvec![Inst::LoadInlineConst { + rd, + ty: I32, + imm: value + }] + }) + } + + pub fn load_constant_u64(rd: Writable, value: u64) -> SmallInstVec { + let insts = Inst::load_const_imm(rd, value); + insts.unwrap_or_else(|| { + smallvec![Inst::LoadInlineConst { + rd, + ty: I64, + imm: value + }] + }) + } + + pub(crate) fn construct_auipc_and_jalr( + link: Option>, + tmp: Writable, + offset: i64, + ) -> [Inst; 2] { + Inst::generate_imm(offset as u64) + .map(|(imm20, imm12)| { + let a = Inst::Auipc { + rd: tmp, + imm: imm20, + }; + let b = Inst::Jalr { + rd: link.unwrap_or(writable_zero_reg()), + base: tmp.to_reg(), + offset: imm12, + }; + [a, b] + }) + .expect("code range is too big.") + } + + /// Generic constructor for a load (zero-extending where appropriate). + pub fn gen_load(into_reg: Writable, mem: AMode, ty: Type, flags: MemFlags) -> Inst { + if ty.is_vector() { + Inst::VecLoad { + eew: VecElementWidth::from_type(ty), + to: into_reg, + from: VecAMode::UnitStride { base: mem }, + flags, + mask: VecOpMasking::Disabled, + vstate: VState::from_type(ty), + } + } else { + Inst::Load { + rd: into_reg, + op: LoadOP::from_type(ty), + from: mem, + flags, + } + } + } + + /// Generic constructor for a store. + pub fn gen_store(mem: AMode, from_reg: Reg, ty: Type, flags: MemFlags) -> Inst { + if ty.is_vector() { + Inst::VecStore { + eew: VecElementWidth::from_type(ty), + to: VecAMode::UnitStride { base: mem }, + from: from_reg, + flags, + mask: VecOpMasking::Disabled, + vstate: VState::from_type(ty), + } + } else { + Inst::Store { + src: from_reg, + op: StoreOP::from_type(ty), + to: mem, + flags, + } + } + } +} + +//============================================================================= + +fn vec_mask_operands(mask: &mut VecOpMasking, collector: &mut impl OperandVisitor) { + match mask { + VecOpMasking::Enabled { reg } => { + collector.reg_fixed_use(reg, pv_reg(0).into()); + } + VecOpMasking::Disabled => {} + } +} +fn vec_mask_late_operands(mask: &mut VecOpMasking, collector: &mut impl OperandVisitor) { + match mask { + VecOpMasking::Enabled { reg } => { + collector.reg_fixed_late_use(reg, pv_reg(0).into()); + } + VecOpMasking::Disabled => {} + } +} + +fn riscv64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { + match inst { + Inst::Nop0 | Inst::Nop4 => {} + Inst::BrTable { + index, tmp1, tmp2, .. + } => { + collector.reg_use(index); + collector.reg_early_def(tmp1); + collector.reg_early_def(tmp2); + } + Inst::Auipc { rd, .. } => collector.reg_def(rd), + Inst::Lui { rd, .. } => collector.reg_def(rd), + Inst::Fli { rd, .. } => collector.reg_def(rd), + Inst::LoadInlineConst { rd, .. } => collector.reg_def(rd), + Inst::AluRRR { rd, rs1, rs2, .. } => { + collector.reg_use(rs1); + collector.reg_use(rs2); + collector.reg_def(rd); + } + Inst::FpuRRR { rd, rs1, rs2, .. } => { + collector.reg_use(rs1); + collector.reg_use(rs2); + collector.reg_def(rd); + } + Inst::AluRRImm12 { rd, rs, .. } => { + collector.reg_use(rs); + collector.reg_def(rd); + } + Inst::CsrReg { rd, rs, .. } => { + collector.reg_use(rs); + collector.reg_def(rd); + } + Inst::CsrImm { rd, .. } => { + collector.reg_def(rd); + } + Inst::Load { rd, from, .. } => { + from.get_operands(collector); + collector.reg_def(rd); + } + Inst::Store { to, src, .. } => { + to.get_operands(collector); + collector.reg_use(src); + } + + Inst::Args { args } => { + for ArgPair { vreg, preg } in args { + collector.reg_fixed_def(vreg, *preg); + } + } + Inst::Rets { rets } => { + for RetPair { vreg, preg } in rets { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::Ret { .. } => {} + + Inst::Extend { rd, rn, .. } => { + collector.reg_use(rn); + collector.reg_def(rd); + } + Inst::Call { info, .. } => { + let CallInfo { uses, defs, .. } = &mut **info; + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(info.clobbers); + } + Inst::CallInd { info } => { + let CallInfo { + dest, uses, defs, .. + } = &mut **info; + collector.reg_use(dest); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(info.clobbers); + } + Inst::ReturnCall { info } => { + for CallArgPair { vreg, preg } in &mut info.uses { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::ReturnCallInd { info } => { + // TODO(https://github.com/bytecodealliance/regalloc2/issues/145): + // This shouldn't be a fixed register constraint. + collector.reg_fixed_use(&mut info.dest, x_reg(5)); + + for CallArgPair { vreg, preg } in &mut info.uses { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::Jal { .. } => { + // JAL technically has a rd register, but we currently always + // hardcode it to x0. + } + Inst::CondBr { + kind: IntegerCompare { rs1, rs2, .. }, + .. + } => { + collector.reg_use(rs1); + collector.reg_use(rs2); + } + Inst::LoadExtName { rd, .. } => { + collector.reg_def(rd); + } + Inst::ElfTlsGetAddr { rd, .. } => { + // x10 is a0 which is both the first argument and the first return value. + collector.reg_fixed_def(rd, a0()); + let mut clobbers = Riscv64MachineDeps::get_regs_clobbered_by_call(CallConv::SystemV); + clobbers.remove(px_reg(10)); + collector.reg_clobbers(clobbers); + } + Inst::LoadAddr { rd, mem } => { + mem.get_operands(collector); + collector.reg_early_def(rd); + } + + Inst::Mov { rd, rm, .. } => { + collector.reg_use(rm); + collector.reg_def(rd); + } + Inst::MovFromPReg { rd, rm } => { + debug_assert!([px_reg(2), px_reg(8)].contains(rm)); + collector.reg_def(rd); + } + Inst::Fence { .. } => {} + Inst::EBreak => {} + Inst::Udf { .. } => {} + Inst::FpuRR { rd, rs, .. } => { + collector.reg_use(rs); + collector.reg_def(rd); + } + Inst::FpuRRRR { + rd, rs1, rs2, rs3, .. + } => { + collector.reg_use(rs1); + collector.reg_use(rs2); + collector.reg_use(rs3); + collector.reg_def(rd); + } + + Inst::Jalr { rd, base, .. } => { + collector.reg_use(base); + collector.reg_def(rd); + } + Inst::Atomic { rd, addr, src, .. } => { + collector.reg_use(addr); + collector.reg_use(src); + collector.reg_def(rd); + } + Inst::Select { + dst, + condition: IntegerCompare { rs1, rs2, .. }, + x, + y, + .. + } => { + // Mark the condition registers as late use so that they don't overlap with the destination + // register. We may potentially write to the destination register before evaluating the + // condition. + collector.reg_late_use(rs1); + collector.reg_late_use(rs2); + + for reg in x.regs_mut() { + collector.reg_use(reg); + } + for reg in y.regs_mut() { + collector.reg_use(reg); + } + + // If there's more than one destination register then use + // `reg_early_def` to prevent destination registers from overlapping + // with any operands. This ensures that the lowering doesn't have to + // deal with a situation such as when the input registers need to be + // swapped when moved to the destination. + // + // When there's only one destination register though don't use an + // early def because once the register is written no other inputs + // are read so it's ok for the destination to overlap the sources. + // The condition registers are already marked as late use so they + // won't overlap with the destination. + match dst.regs_mut() { + [reg] => collector.reg_def(reg), + regs => { + for d in regs { + collector.reg_early_def(d); + } + } + } + } + Inst::AtomicCas { + offset, + t0, + dst, + e, + addr, + v, + .. + } => { + collector.reg_use(offset); + collector.reg_use(e); + collector.reg_use(addr); + collector.reg_use(v); + collector.reg_early_def(t0); + collector.reg_early_def(dst); + } + + Inst::RawData { .. } => {} + Inst::AtomicStore { src, p, .. } => { + collector.reg_use(src); + collector.reg_use(p); + } + Inst::AtomicLoad { rd, p, .. } => { + collector.reg_use(p); + collector.reg_def(rd); + } + Inst::AtomicRmwLoop { + offset, + dst, + p, + x, + t0, + .. + } => { + collector.reg_use(offset); + collector.reg_use(p); + collector.reg_use(x); + collector.reg_early_def(t0); + collector.reg_early_def(dst); + } + Inst::TrapIf { rs1, rs2, .. } => { + collector.reg_use(rs1); + collector.reg_use(rs2); + } + Inst::Unwind { .. } => {} + Inst::DummyUse { reg } => { + collector.reg_use(reg); + } + Inst::Popcnt { + sum, step, rs, tmp, .. + } => { + collector.reg_use(rs); + collector.reg_early_def(tmp); + collector.reg_early_def(step); + collector.reg_early_def(sum); + } + Inst::Cltz { + sum, step, tmp, rs, .. + } => { + collector.reg_use(rs); + collector.reg_early_def(tmp); + collector.reg_early_def(step); + collector.reg_early_def(sum); + } + Inst::Brev8 { + rs, + rd, + step, + tmp, + tmp2, + .. + } => { + collector.reg_use(rs); + collector.reg_early_def(step); + collector.reg_early_def(tmp); + collector.reg_early_def(tmp2); + collector.reg_early_def(rd); + } + Inst::StackProbeLoop { .. } => { + // StackProbeLoop has a tmp register and StackProbeLoop used at gen_prologue. + // t3 will do the job. (t3 is caller-save register and not used directly by compiler like writable_spilltmp_reg) + // gen_prologue is called at emit stage. + // no need let reg alloc know. + } + Inst::VecAluRRRR { + op, + vd, + vd_src, + vs1, + vs2, + mask, + .. + } => { + debug_assert_eq!(vd_src.class(), RegClass::Vector); + debug_assert_eq!(vd.to_reg().class(), RegClass::Vector); + debug_assert_eq!(vs2.class(), RegClass::Vector); + debug_assert_eq!(vs1.class(), op.vs1_regclass()); + + collector.reg_late_use(vs1); + collector.reg_late_use(vs2); + collector.reg_use(vd_src); + collector.reg_reuse_def(vd, 2); // `vd` == `vd_src`. + vec_mask_late_operands(mask, collector); + } + Inst::VecAluRRRImm5 { + op, + vd, + vd_src, + vs2, + mask, + .. + } => { + debug_assert_eq!(vd_src.class(), RegClass::Vector); + debug_assert_eq!(vd.to_reg().class(), RegClass::Vector); + debug_assert_eq!(vs2.class(), RegClass::Vector); + + // If the operation forbids source/destination overlap we need to + // ensure that the source and destination registers are different. + if op.forbids_overlaps(mask) { + collector.reg_late_use(vs2); + collector.reg_use(vd_src); + collector.reg_reuse_def(vd, 1); // `vd` == `vd_src`. + vec_mask_late_operands(mask, collector); + } else { + collector.reg_use(vs2); + collector.reg_use(vd_src); + collector.reg_reuse_def(vd, 1); // `vd` == `vd_src`. + vec_mask_operands(mask, collector); + } + } + Inst::VecAluRRR { + op, + vd, + vs1, + vs2, + mask, + .. + } => { + debug_assert_eq!(vd.to_reg().class(), RegClass::Vector); + debug_assert_eq!(vs2.class(), RegClass::Vector); + debug_assert_eq!(vs1.class(), op.vs1_regclass()); + + collector.reg_use(vs1); + collector.reg_use(vs2); + + // If the operation forbids source/destination overlap, then we must + // register it as an early_def. This encodes the constraint that + // these must not overlap. + if op.forbids_overlaps(mask) { + collector.reg_early_def(vd); + } else { + collector.reg_def(vd); + } + + vec_mask_operands(mask, collector); + } + Inst::VecAluRRImm5 { + op, vd, vs2, mask, .. + } => { + debug_assert_eq!(vd.to_reg().class(), RegClass::Vector); + debug_assert_eq!(vs2.class(), RegClass::Vector); + + collector.reg_use(vs2); + + // If the operation forbids source/destination overlap, then we must + // register it as an early_def. This encodes the constraint that + // these must not overlap. + if op.forbids_overlaps(mask) { + collector.reg_early_def(vd); + } else { + collector.reg_def(vd); + } + + vec_mask_operands(mask, collector); + } + Inst::VecAluRR { + op, vd, vs, mask, .. + } => { + debug_assert_eq!(vd.to_reg().class(), op.dst_regclass()); + debug_assert_eq!(vs.class(), op.src_regclass()); + + collector.reg_use(vs); + + // If the operation forbids source/destination overlap, then we must + // register it as an early_def. This encodes the constraint that + // these must not overlap. + if op.forbids_overlaps(mask) { + collector.reg_early_def(vd); + } else { + collector.reg_def(vd); + } + + vec_mask_operands(mask, collector); + } + Inst::VecAluRImm5 { op, vd, mask, .. } => { + debug_assert_eq!(vd.to_reg().class(), RegClass::Vector); + debug_assert!(!op.forbids_overlaps(mask)); + + collector.reg_def(vd); + vec_mask_operands(mask, collector); + } + Inst::VecSetState { rd, .. } => { + collector.reg_def(rd); + } + Inst::VecLoad { to, from, mask, .. } => { + from.get_operands(collector); + collector.reg_def(to); + vec_mask_operands(mask, collector); + } + Inst::VecStore { to, from, mask, .. } => { + to.get_operands(collector); + collector.reg_use(from); + vec_mask_operands(mask, collector); + } + } +} + +impl MachInst for Inst { + type LabelUse = LabelUse; + type ABIMachineSpec = Riscv64MachineDeps; + + // https://github.com/riscv/riscv-isa-manual/issues/850 + // all zero will cause invalid opcode. + const TRAP_OPCODE: &'static [u8] = &[0; 4]; + + fn gen_dummy_use(reg: Reg) -> Self { + Inst::DummyUse { reg } + } + + fn canonical_type_for_rc(rc: RegClass) -> Type { + match rc { + regalloc2::RegClass::Int => I64, + regalloc2::RegClass::Float => F64, + regalloc2::RegClass::Vector => I8X16, + } + } + + fn is_safepoint(&self) -> bool { + match self { + Inst::Call { .. } | Inst::CallInd { .. } => true, + _ => false, + } + } + + fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + riscv64_get_operands(self, collector); + } + + fn is_move(&self) -> Option<(Writable, Reg)> { + match self { + Inst::Mov { rd, rm, .. } => Some((*rd, *rm)), + _ => None, + } + } + + fn is_included_in_clobbers(&self) -> bool { + match self { + &Inst::Args { .. } => false, + _ => true, + } + } + + fn is_trap(&self) -> bool { + match self { + Self::Udf { .. } => true, + _ => false, + } + } + + fn is_args(&self) -> bool { + match self { + Self::Args { .. } => true, + _ => false, + } + } + + fn is_term(&self) -> MachTerminator { + match self { + &Inst::Jal { .. } => MachTerminator::Uncond, + &Inst::CondBr { .. } => MachTerminator::Cond, + &Inst::Jalr { .. } => MachTerminator::Uncond, + &Inst::Rets { .. } => MachTerminator::Ret, + &Inst::BrTable { .. } => MachTerminator::Indirect, + &Inst::ReturnCall { .. } | &Inst::ReturnCallInd { .. } => MachTerminator::RetCall, + _ => MachTerminator::None, + } + } + + fn is_mem_access(&self) -> bool { + panic!("TODO FILL ME OUT") + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { + let x = Inst::Mov { + rd: to_reg, + rm: from_reg, + ty, + }; + x + } + + fn gen_nop(preferred_size: usize) -> Inst { + if preferred_size == 0 { + return Inst::Nop0; + } + // We can't give a NOP (or any insn) < 4 bytes. + assert!(preferred_size >= 4); + Inst::Nop4 + } + + fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> { + match ty { + I8 => Ok((&[RegClass::Int], &[I8])), + I16 => Ok((&[RegClass::Int], &[I16])), + I32 => Ok((&[RegClass::Int], &[I32])), + I64 => Ok((&[RegClass::Int], &[I64])), + F16 => Ok((&[RegClass::Float], &[F16])), + F32 => Ok((&[RegClass::Float], &[F32])), + F64 => Ok((&[RegClass::Float], &[F64])), + I128 => Ok((&[RegClass::Int, RegClass::Int], &[I64, I64])), + _ if ty.is_vector() => { + debug_assert!(ty.bits() <= 512); + + // Here we only need to return a SIMD type with the same size as `ty`. + // We use these types for spills and reloads, so prefer types with lanes <= 31 + // since that fits in the immediate field of `vsetivli`. + const SIMD_TYPES: [[Type; 1]; 6] = [ + [types::I8X2], + [types::I8X4], + [types::I8X8], + [types::I8X16], + [types::I16X16], + [types::I32X16], + ]; + let idx = (ty.bytes().ilog2() - 1) as usize; + let ty = &SIMD_TYPES[idx][..]; + + Ok((&[RegClass::Vector], ty)) + } + _ => Err(CodegenError::Unsupported(format!( + "Unexpected SSA-value type: {ty}" + ))), + } + } + + fn gen_jump(target: MachLabel) -> Inst { + Inst::Jal { label: target } + } + + fn worst_case_size() -> CodeOffset { + // Our worst case size is determined by the riscv64_worst_case_instruction_size test + 84 + } + + fn ref_type_regclass(_settings: &settings::Flags) -> RegClass { + RegClass::Int + } + + fn function_alignment() -> FunctionAlignment { + FunctionAlignment { + minimum: 2, + preferred: 4, + } + } +} + +//============================================================================= +// Pretty-printing of instructions. +pub fn reg_name(reg: Reg) -> String { + match reg.to_real_reg() { + Some(real) => match real.class() { + RegClass::Int => match real.hw_enc() { + 0 => "zero".into(), + 1 => "ra".into(), + 2 => "sp".into(), + 3 => "gp".into(), + 4 => "tp".into(), + 5..=7 => format!("t{}", real.hw_enc() - 5), + 8 => "fp".into(), + 9 => "s1".into(), + 10..=17 => format!("a{}", real.hw_enc() - 10), + 18..=27 => format!("s{}", real.hw_enc() - 16), + 28..=31 => format!("t{}", real.hw_enc() - 25), + _ => unreachable!(), + }, + RegClass::Float => match real.hw_enc() { + 0..=7 => format!("ft{}", real.hw_enc() - 0), + 8..=9 => format!("fs{}", real.hw_enc() - 8), + 10..=17 => format!("fa{}", real.hw_enc() - 10), + 18..=27 => format!("fs{}", real.hw_enc() - 16), + 28..=31 => format!("ft{}", real.hw_enc() - 20), + _ => unreachable!(), + }, + RegClass::Vector => format!("v{}", real.hw_enc()), + }, + None => { + format!("{reg:?}") + } + } +} + +impl Inst { + fn print_with_state(&self, _state: &mut EmitState) -> String { + let format_reg = |reg: Reg| -> String { reg_name(reg) }; + + let format_vec_amode = |amode: &VecAMode| -> String { + match amode { + VecAMode::UnitStride { base } => base.to_string(), + } + }; + + let format_mask = |mask: &VecOpMasking| -> String { + match mask { + VecOpMasking::Enabled { reg } => format!(",{}.t", format_reg(*reg)), + VecOpMasking::Disabled => format!(""), + } + }; + + let format_regs = |regs: &[Reg]| -> String { + let mut x = if regs.len() > 1 { + String::from("[") + } else { + String::default() + }; + regs.iter().for_each(|i| { + x.push_str(format_reg(*i).as_str()); + if *i != *regs.last().unwrap() { + x.push_str(","); + } + }); + if regs.len() > 1 { + x.push_str("]"); + } + x + }; + let format_labels = |labels: &[MachLabel]| -> String { + if labels.len() == 0 { + return String::from("[_]"); + } + let mut x = String::from("["); + labels.iter().for_each(|l| { + x.push_str( + format!( + "{:?}{}", + l, + if l != labels.last().unwrap() { "," } else { "" }, + ) + .as_str(), + ); + }); + x.push_str("]"); + x + }; + + fn format_frm(rounding_mode: FRM) -> String { + format!(",{}", rounding_mode.to_static_str()) + } + + match self { + &Inst::Nop0 => { + format!("##zero length nop") + } + &Inst::Nop4 => { + format!("##fixed 4-size nop") + } + &Inst::StackProbeLoop { + guard_size, + probe_count, + tmp, + } => { + let tmp = format_reg(tmp.to_reg()); + format!( + "inline_stack_probe##guard_size={guard_size} probe_count={probe_count} tmp={tmp}" + ) + } + &Inst::AtomicStore { src, ty, p } => { + let src = format_reg(src); + let p = format_reg(p); + format!("atomic_store.{ty} {src},({p})") + } + &Inst::DummyUse { reg } => { + let reg = format_reg(reg); + format!("dummy_use {reg}") + } + + &Inst::AtomicLoad { rd, ty, p } => { + let p = format_reg(p); + let rd = format_reg(rd.to_reg()); + format!("atomic_load.{ty} {rd},({p})") + } + &Inst::AtomicRmwLoop { + offset, + op, + dst, + ty, + p, + x, + t0, + } => { + let offset = format_reg(offset); + let p = format_reg(p); + let x = format_reg(x); + let t0 = format_reg(t0.to_reg()); + let dst = format_reg(dst.to_reg()); + format!("atomic_rmw.{ty} {op} {dst},{x},({p})##t0={t0} offset={offset}") + } + + &Inst::RawData { ref data } => match data.len() { + 4 => { + let mut bytes = [0; 4]; + for i in 0..bytes.len() { + bytes[i] = data[i]; + } + format!(".4byte 0x{:x}", u32::from_le_bytes(bytes)) + } + 8 => { + let mut bytes = [0; 8]; + for i in 0..bytes.len() { + bytes[i] = data[i]; + } + format!(".8byte 0x{:x}", u64::from_le_bytes(bytes)) + } + _ => { + format!(".data {data:?}") + } + }, + &Inst::Unwind { ref inst } => { + format!("unwind {inst:?}") + } + &Inst::Brev8 { + rs, + ty, + step, + tmp, + tmp2, + rd, + } => { + let rs = format_reg(rs); + let step = format_reg(step.to_reg()); + let tmp = format_reg(tmp.to_reg()); + let tmp2 = format_reg(tmp2.to_reg()); + let rd = format_reg(rd.to_reg()); + format!("brev8 {rd},{rs}##tmp={tmp} tmp2={tmp2} step={step} ty={ty}") + } + &Inst::Popcnt { + sum, + step, + rs, + tmp, + ty, + } => { + let rs = format_reg(rs); + let tmp = format_reg(tmp.to_reg()); + let step = format_reg(step.to_reg()); + let sum = format_reg(sum.to_reg()); + format!("popcnt {sum},{rs}##ty={ty} tmp={tmp} step={step}") + } + &Inst::Cltz { + sum, + step, + rs, + tmp, + ty, + leading, + } => { + let rs = format_reg(rs); + let tmp = format_reg(tmp.to_reg()); + let step = format_reg(step.to_reg()); + let sum = format_reg(sum.to_reg()); + format!( + "{} {},{}##ty={} tmp={} step={}", + if leading { "clz" } else { "ctz" }, + sum, + rs, + ty, + tmp, + step + ) + } + &Inst::AtomicCas { + offset, + t0, + dst, + e, + addr, + v, + ty, + } => { + let offset = format_reg(offset); + let e = format_reg(e); + let addr = format_reg(addr); + let v = format_reg(v); + let t0 = format_reg(t0.to_reg()); + let dst = format_reg(dst.to_reg()); + format!("atomic_cas.{ty} {dst},{e},{v},({addr})##t0={t0} offset={offset}",) + } + &Inst::BrTable { + index, + tmp1, + tmp2, + ref targets, + } => { + format!( + "{} {},{}##tmp1={},tmp2={}", + "br_table", + format_reg(index), + format_labels(&targets[..]), + format_reg(tmp1.to_reg()), + format_reg(tmp2.to_reg()), + ) + } + &Inst::Auipc { rd, imm } => { + format!("{} {},{}", "auipc", format_reg(rd.to_reg()), imm.as_i32(),) + } + &Inst::Jalr { rd, base, offset } => { + let base = format_reg(base); + let rd = format_reg(rd.to_reg()); + format!("{} {},{}({})", "jalr", rd, offset.as_i16(), base) + } + &Inst::Lui { rd, ref imm } => { + format!("{} {},{}", "lui", format_reg(rd.to_reg()), imm.as_i32()) + } + &Inst::Fli { rd, ty, imm } => { + let rd_s = format_reg(rd.to_reg()); + let imm_s = imm.format(); + let suffix = match ty { + F32 => "s", + F64 => "d", + _ => unreachable!(), + }; + + format!("fli.{suffix} {rd_s},{imm_s}") + } + &Inst::LoadInlineConst { rd, imm, .. } => { + let rd = format_reg(rd.to_reg()); + let mut buf = String::new(); + write!(&mut buf, "auipc {rd},0; ").unwrap(); + write!(&mut buf, "ld {rd},12({rd}); ").unwrap(); + write!(&mut buf, "j {}; ", Inst::UNCOMPRESSED_INSTRUCTION_SIZE + 8).unwrap(); + write!(&mut buf, ".8byte 0x{imm:x}").unwrap(); + buf + } + &Inst::AluRRR { + alu_op, + rd, + rs1, + rs2, + } => { + let rs1_s = format_reg(rs1); + let rs2_s = format_reg(rs2); + let rd_s = format_reg(rd.to_reg()); + match alu_op { + AluOPRRR::Adduw if rs2 == zero_reg() => { + format!("zext.w {rd_s},{rs1_s}") + } + _ => { + format!("{} {},{},{}", alu_op.op_name(), rd_s, rs1_s, rs2_s) + } + } + } + &Inst::FpuRR { + alu_op, + width, + frm, + rd, + rs, + } => { + let rs = format_reg(rs); + let rd = format_reg(rd.to_reg()); + let frm = if alu_op.has_frm() { + format_frm(frm) + } else { + String::new() + }; + format!("{} {rd},{rs}{frm}", alu_op.op_name(width)) + } + &Inst::FpuRRR { + alu_op, + width, + rd, + rs1, + rs2, + frm, + } => { + let rs1 = format_reg(rs1); + let rs2 = format_reg(rs2); + let rd = format_reg(rd.to_reg()); + let frm = if alu_op.has_frm() { + format_frm(frm) + } else { + String::new() + }; + + let rs1_is_rs2 = rs1 == rs2; + match alu_op { + FpuOPRRR::Fsgnj if rs1_is_rs2 => format!("fmv.{width} {rd},{rs1}"), + FpuOPRRR::Fsgnjn if rs1_is_rs2 => format!("fneg.{width} {rd},{rs1}"), + FpuOPRRR::Fsgnjx if rs1_is_rs2 => format!("fabs.{width} {rd},{rs1}"), + _ => format!("{} {rd},{rs1},{rs2}{frm}", alu_op.op_name(width)), + } + } + &Inst::FpuRRRR { + alu_op, + rd, + rs1, + rs2, + rs3, + frm, + width, + } => { + let rs1 = format_reg(rs1); + let rs2 = format_reg(rs2); + let rs3 = format_reg(rs3); + let rd = format_reg(rd.to_reg()); + let frm = format_frm(frm); + let op_name = alu_op.op_name(width); + format!("{op_name} {rd},{rs1},{rs2},{rs3}{frm}") + } + &Inst::AluRRImm12 { + alu_op, + rd, + rs, + ref imm12, + } => { + let rs_s = format_reg(rs); + let rd = format_reg(rd.to_reg()); + + // Some of these special cases are better known as + // their pseudo-instruction version, so prefer printing those. + match (alu_op, rs, imm12) { + (AluOPRRI::Addi, rs, _) if rs == zero_reg() => { + return format!("li {},{}", rd, imm12.as_i16()); + } + (AluOPRRI::Addiw, _, imm12) if imm12.as_i16() == 0 => { + return format!("sext.w {rd},{rs_s}"); + } + (AluOPRRI::Xori, _, imm12) if imm12.as_i16() == -1 => { + return format!("not {rd},{rs_s}"); + } + (AluOPRRI::SltiU, _, imm12) if imm12.as_i16() == 1 => { + return format!("seqz {rd},{rs_s}"); + } + (alu_op, _, _) if alu_op.option_funct12().is_some() => { + format!("{} {},{}", alu_op.op_name(), rd, rs_s) + } + (alu_op, _, imm12) => { + format!("{} {},{},{}", alu_op.op_name(), rd, rs_s, imm12.as_i16()) + } + } + } + &Inst::CsrReg { op, rd, rs, csr } => { + let rs_s = format_reg(rs); + let rd_s = format_reg(rd.to_reg()); + + match (op, csr, rd) { + (CsrRegOP::CsrRW, CSR::Frm, rd) if rd.to_reg() == zero_reg() => { + format!("fsrm {rs_s}") + } + _ => { + format!("{op} {rd_s},{csr},{rs_s}") + } + } + } + &Inst::CsrImm { op, rd, csr, imm } => { + let rd_s = format_reg(rd.to_reg()); + + match (op, csr, rd) { + (CsrImmOP::CsrRWI, CSR::Frm, rd) if rd.to_reg() != zero_reg() => { + format!("fsrmi {rd_s},{imm}") + } + _ => { + format!("{op} {rd_s},{csr},{imm}") + } + } + } + &Inst::Load { + rd, + op, + from, + flags: _flags, + } => { + let base = from.to_string(); + let rd = format_reg(rd.to_reg()); + format!("{} {},{}", op.op_name(), rd, base,) + } + &Inst::Store { + to, + src, + op, + flags: _flags, + } => { + let base = to.to_string(); + let src = format_reg(src); + format!("{} {},{}", op.op_name(), src, base,) + } + &Inst::Args { ref args } => { + let mut s = "args".to_string(); + for arg in args { + let preg = format_reg(arg.preg); + let def = format_reg(arg.vreg.to_reg()); + write!(&mut s, " {def}={preg}").unwrap(); + } + s + } + &Inst::Rets { ref rets } => { + let mut s = "rets".to_string(); + for ret in rets { + let preg = format_reg(ret.preg); + let vreg = format_reg(ret.vreg); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + &Inst::Ret {} => "ret".to_string(), + + &MInst::Extend { + rd, + rn, + signed, + from_bits, + .. + } => { + let rn = format_reg(rn); + let rd = format_reg(rd.to_reg()); + return if signed == false && from_bits == 8 { + format!("andi {rd},{rn}") + } else { + let op = if signed { "srai" } else { "srli" }; + let shift_bits = (64 - from_bits) as i16; + format!("slli {rd},{rn},{shift_bits}; {op} {rd},{rd},{shift_bits}") + }; + } + &MInst::Call { ref info } => format!("call {}", info.dest.display(None)), + &MInst::CallInd { ref info } => { + let rd = format_reg(info.dest); + format!("callind {rd}") + } + &MInst::ReturnCall { ref info } => { + let mut s = format!( + "return_call {:?} new_stack_arg_size:{}", + info.dest, info.new_stack_arg_size + ); + for ret in &info.uses { + let preg = format_reg(ret.preg); + let vreg = format_reg(ret.vreg); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + &MInst::ReturnCallInd { ref info } => { + let callee = format_reg(info.dest); + let mut s = format!( + "return_call_ind {callee} new_stack_arg_size:{}", + info.new_stack_arg_size + ); + for ret in &info.uses { + let preg = format_reg(ret.preg); + let vreg = format_reg(ret.vreg); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + &MInst::TrapIf { + rs1, + rs2, + cc, + trap_code, + } => { + let rs1 = format_reg(rs1); + let rs2 = format_reg(rs2); + format!("trap_if {trap_code}##({rs1} {cc} {rs2})") + } + &MInst::Jal { label } => { + format!("j {}", label.to_string()) + } + &MInst::CondBr { + taken, + not_taken, + kind, + .. + } => { + let rs1 = format_reg(kind.rs1); + let rs2 = format_reg(kind.rs2); + if not_taken.is_fallthrouh() && taken.as_label().is_none() { + format!("{} {},{},0", kind.op_name(), rs1, rs2) + } else { + let x = format!( + "{} {},{},taken({}),not_taken({})", + kind.op_name(), + rs1, + rs2, + taken, + not_taken + ); + x + } + } + &MInst::Atomic { + op, + rd, + addr, + src, + amo, + } => { + let op_name = op.op_name(amo); + let addr = format_reg(addr); + let src = format_reg(src); + let rd = format_reg(rd.to_reg()); + if op.is_load() { + format!("{op_name} {rd},({addr})") + } else { + format!("{op_name} {rd},{src},({addr})") + } + } + &MInst::LoadExtName { + rd, + ref name, + offset, + } => { + let rd = format_reg(rd.to_reg()); + format!("load_sym {},{}{:+}", rd, name.display(None), offset) + } + &Inst::ElfTlsGetAddr { rd, ref name } => { + let rd = format_reg(rd.to_reg()); + format!("elf_tls_get_addr {rd},{}", name.display(None)) + } + &MInst::LoadAddr { ref rd, ref mem } => { + let rs = mem.to_string(); + let rd = format_reg(rd.to_reg()); + format!("load_addr {rd},{rs}") + } + &MInst::Mov { rd, rm, ty } => { + let rm = format_reg(rm); + let rd = format_reg(rd.to_reg()); + + let op = match ty { + F16 => "fmv.h", + F32 => "fmv.s", + F64 => "fmv.d", + ty if ty.is_vector() => "vmv1r.v", + _ => "mv", + }; + + format!("{op} {rd},{rm}") + } + &MInst::MovFromPReg { rd, rm } => { + let rd = format_reg(rd.to_reg()); + debug_assert!([px_reg(2), px_reg(8)].contains(&rm)); + let rm = reg_name(Reg::from(rm)); + format!("mv {rd},{rm}") + } + &MInst::Fence { pred, succ } => { + format!( + "fence {},{}", + Inst::fence_req_to_string(pred), + Inst::fence_req_to_string(succ), + ) + } + &MInst::Select { + ref dst, + condition, + ref x, + ref y, + } => { + let c_rs1 = format_reg(condition.rs1); + let c_rs2 = format_reg(condition.rs2); + let x = format_regs(x.regs()); + let y = format_regs(y.regs()); + let dst = dst.map(|r| r.to_reg()); + let dst = format_regs(dst.regs()); + format!( + "select {},{},{}##condition=({} {} {})", + dst, + x, + y, + c_rs1, + condition.kind.to_static_str(), + c_rs2 + ) + } + &MInst::Udf { trap_code } => format!("udf##trap_code={trap_code}"), + &MInst::EBreak {} => String::from("ebreak"), + &Inst::VecAluRRRR { + op, + vd, + vd_src, + vs1, + vs2, + ref mask, + ref vstate, + } => { + let vs1_s = format_reg(vs1); + let vs2_s = format_reg(vs2); + let vd_src_s = format_reg(vd_src); + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + let vd_fmt = if vd_s != vd_src_s { + format!("{vd_s},{vd_src_s}") + } else { + vd_s + }; + + // Note: vs2 and vs1 here are opposite to the standard scalar ordering. + // This is noted in Section 10.1 of the RISC-V Vector spec. + format!("{op} {vd_fmt},{vs2_s},{vs1_s}{mask} {vstate}") + } + &Inst::VecAluRRRImm5 { + op, + vd, + imm, + vs2, + ref mask, + ref vstate, + .. + } => { + let vs2_s = format_reg(vs2); + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + // Some opcodes interpret the immediate as unsigned, lets show the + // correct number here. + let imm_s = if op.imm_is_unsigned() { + format!("{}", imm.bits()) + } else { + format!("{imm}") + }; + + format!("{op} {vd_s},{vs2_s},{imm_s}{mask} {vstate}") + } + &Inst::VecAluRRR { + op, + vd, + vs1, + vs2, + ref mask, + ref vstate, + } => { + let vs1_s = format_reg(vs1); + let vs2_s = format_reg(vs2); + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + // Note: vs2 and vs1 here are opposite to the standard scalar ordering. + // This is noted in Section 10.1 of the RISC-V Vector spec. + match (op, vs2, vs1) { + (VecAluOpRRR::VrsubVX, _, vs1) if vs1 == zero_reg() => { + format!("vneg.v {vd_s},{vs2_s}{mask} {vstate}") + } + (VecAluOpRRR::VfsgnjnVV, vs2, vs1) if vs2 == vs1 => { + format!("vfneg.v {vd_s},{vs2_s}{mask} {vstate}") + } + (VecAluOpRRR::VfsgnjxVV, vs2, vs1) if vs2 == vs1 => { + format!("vfabs.v {vd_s},{vs2_s}{mask} {vstate}") + } + (VecAluOpRRR::VmnandMM, vs2, vs1) if vs2 == vs1 => { + format!("vmnot.m {vd_s},{vs2_s}{mask} {vstate}") + } + _ => format!("{op} {vd_s},{vs2_s},{vs1_s}{mask} {vstate}"), + } + } + &Inst::VecAluRRImm5 { + op, + vd, + imm, + vs2, + ref mask, + ref vstate, + } => { + let vs2_s = format_reg(vs2); + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + // Some opcodes interpret the immediate as unsigned, lets show the + // correct number here. + let imm_s = if op.imm_is_unsigned() { + format!("{}", imm.bits()) + } else { + format!("{imm}") + }; + + match (op, imm) { + (VecAluOpRRImm5::VxorVI, imm) if imm == Imm5::maybe_from_i8(-1).unwrap() => { + format!("vnot.v {vd_s},{vs2_s}{mask} {vstate}") + } + _ => format!("{op} {vd_s},{vs2_s},{imm_s}{mask} {vstate}"), + } + } + &Inst::VecAluRR { + op, + vd, + vs, + ref mask, + ref vstate, + } => { + let vs_s = format_reg(vs); + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + format!("{op} {vd_s},{vs_s}{mask} {vstate}") + } + &Inst::VecAluRImm5 { + op, + vd, + imm, + ref mask, + ref vstate, + } => { + let vd_s = format_reg(vd.to_reg()); + let mask = format_mask(mask); + + format!("{op} {vd_s},{imm}{mask} {vstate}") + } + &Inst::VecSetState { rd, ref vstate } => { + let rd_s = format_reg(rd.to_reg()); + assert!(vstate.avl.is_static()); + format!("vsetivli {}, {}, {}", rd_s, vstate.avl, vstate.vtype) + } + Inst::VecLoad { + eew, + to, + from, + ref mask, + ref vstate, + .. + } => { + let base = format_vec_amode(from); + let vd = format_reg(to.to_reg()); + let mask = format_mask(mask); + + format!("vl{eew}.v {vd},{base}{mask} {vstate}") + } + Inst::VecStore { + eew, + to, + from, + ref mask, + ref vstate, + .. + } => { + let dst = format_vec_amode(to); + let vs3 = format_reg(*from); + let mask = format_mask(mask); + + format!("vs{eew}.v {vs3},{dst}{mask} {vstate}") + } + } + } +} + +/// Different forms of label references for different instruction formats. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LabelUse { + /// 20-bit branch offset (unconditional branches). PC-rel, offset is + /// imm << 1. Immediate is 20 signed bits. Use in Jal instructions. + Jal20, + + /// The unconditional jump instructions all use PC-relative + /// addressing to help support position independent code. The JALR + /// instruction was defined to enable a two-instruction sequence to + /// jump anywhere in a 32-bit absolute address range. A LUI + /// instruction can first load rs1 with the upper 20 bits of a + /// target address, then JALR can add in the lower bits. Similarly, + /// AUIPC then JALR can jump anywhere in a 32-bit pc-relative + /// address range. + PCRel32, + + /// All branch instructions use the B-type instruction format. The + /// 12-bit B-immediate encodes signed offsets in multiples of 2, and + /// is added to the current pc to give the target address. The + /// conditional branch range is ±4 KiB. + B12, + + /// Equivalent to the `R_RISCV_PCREL_HI20` relocation, Allows setting + /// the immediate field of an `auipc` instruction. + PCRelHi20, + + /// Similar to the `R_RISCV_PCREL_LO12_I` relocation but pointing to + /// the final address, instead of the `PCREL_HI20` label. Allows setting + /// the immediate field of I Type instructions such as `addi` or `lw`. + /// + /// Since we currently don't support offsets in labels, this relocation has + /// an implicit offset of 4. + PCRelLo12I, + + /// 11-bit PC-relative jump offset. Equivalent to the `RVC_JUMP` relocation + RVCJump, +} + +impl MachInstLabelUse for LabelUse { + /// Alignment for veneer code. Every Riscv64 instruction must be + /// 4-byte-aligned. + const ALIGN: CodeOffset = 4; + + /// Maximum PC-relative range (positive), inclusive. + fn max_pos_range(self) -> CodeOffset { + match self { + LabelUse::Jal20 => ((1 << 19) - 1) * 2, + LabelUse::PCRelLo12I | LabelUse::PCRelHi20 | LabelUse::PCRel32 => { + Inst::imm_max() as CodeOffset + } + LabelUse::B12 => ((1 << 11) - 1) * 2, + LabelUse::RVCJump => ((1 << 10) - 1) * 2, + } + } + + /// Maximum PC-relative range (negative). + fn max_neg_range(self) -> CodeOffset { + match self { + LabelUse::PCRel32 => Inst::imm_min().abs() as CodeOffset, + _ => self.max_pos_range() + 2, + } + } + + /// Size of window into code needed to do the patch. + fn patch_size(self) -> CodeOffset { + match self { + LabelUse::RVCJump => 2, + LabelUse::Jal20 | LabelUse::B12 | LabelUse::PCRelHi20 | LabelUse::PCRelLo12I => 4, + LabelUse::PCRel32 => 8, + } + } + + /// Perform the patch. + fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) { + assert!(use_offset % 2 == 0); + assert!(label_offset % 2 == 0); + let offset = (label_offset as i64) - (use_offset as i64); + + // re-check range + assert!( + offset >= -(self.max_neg_range() as i64) && offset <= (self.max_pos_range() as i64), + "{self:?} offset '{offset}' use_offset:'{use_offset}' label_offset:'{label_offset}' must not exceed max range.", + ); + self.patch_raw_offset(buffer, offset); + } + + /// Is a veneer supported for this label reference type? + fn supports_veneer(self) -> bool { + match self { + Self::Jal20 | Self::B12 | Self::RVCJump => true, + _ => false, + } + } + + /// How large is the veneer, if supported? + fn veneer_size(self) -> CodeOffset { + match self { + Self::B12 | Self::Jal20 | Self::RVCJump => 8, + _ => unreachable!(), + } + } + + fn worst_case_veneer_size() -> CodeOffset { + 8 + } + + /// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return + /// an offset and label-use for the veneer's use of the original label. + fn generate_veneer( + self, + buffer: &mut [u8], + veneer_offset: CodeOffset, + ) -> (CodeOffset, LabelUse) { + let base = writable_spilltmp_reg(); + { + let x = enc_auipc(base, Imm20::ZERO).to_le_bytes(); + buffer[0] = x[0]; + buffer[1] = x[1]; + buffer[2] = x[2]; + buffer[3] = x[3]; + } + { + let x = enc_jalr(writable_zero_reg(), base.to_reg(), Imm12::ZERO).to_le_bytes(); + buffer[4] = x[0]; + buffer[5] = x[1]; + buffer[6] = x[2]; + buffer[7] = x[3]; + } + (veneer_offset, Self::PCRel32) + } + + fn from_reloc(reloc: Reloc, addend: Addend) -> Option { + match (reloc, addend) { + (Reloc::RiscvCallPlt, _) => Some(Self::PCRel32), + _ => None, + } + } +} + +impl LabelUse { + #[allow(dead_code)] // in case it's needed in the future + fn offset_in_range(self, offset: i64) -> bool { + let min = -(self.max_neg_range() as i64); + let max = self.max_pos_range() as i64; + offset >= min && offset <= max + } + + fn patch_raw_offset(self, buffer: &mut [u8], offset: i64) { + let insn = match self { + LabelUse::RVCJump => u16::from_le_bytes(buffer[..2].try_into().unwrap()) as u32, + _ => u32::from_le_bytes(buffer[..4].try_into().unwrap()), + }; + + match self { + LabelUse::Jal20 => { + let offset = offset as u32; + let v = ((offset >> 12 & 0b1111_1111) << 12) + | ((offset >> 11 & 0b1) << 20) + | ((offset >> 1 & 0b11_1111_1111) << 21) + | ((offset >> 20 & 0b1) << 31); + buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn | v)); + } + LabelUse::PCRel32 => { + let insn2 = u32::from_le_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]); + Inst::generate_imm(offset as u64) + .map(|(imm20, imm12)| { + // Encode the OR-ed-in value with zero_reg(). The + // register parameter must be in the original + // encoded instruction and or'ing in zeroes does not + // change it. + buffer[0..4].clone_from_slice(&u32::to_le_bytes( + insn | enc_auipc(writable_zero_reg(), imm20), + )); + buffer[4..8].clone_from_slice(&u32::to_le_bytes( + insn2 | enc_jalr(writable_zero_reg(), zero_reg(), imm12), + )); + }) + // expect make sure we handled. + .expect("we have check the range before,this is a compiler error."); + } + + LabelUse::B12 => { + let offset = offset as u32; + let v = ((offset >> 11 & 0b1) << 7) + | ((offset >> 1 & 0b1111) << 8) + | ((offset >> 5 & 0b11_1111) << 25) + | ((offset >> 12 & 0b1) << 31); + buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn | v)); + } + + LabelUse::PCRelHi20 => { + // See https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + // + // We need to add 0x800 to ensure that we land at the next page as soon as it goes out of range for the + // Lo12 relocation. That relocation is signed and has a maximum range of -2048..2047. So when we get an + // offset of 2048, we need to land at the next page and subtract instead. + let offset = offset as u32; + let hi20 = offset.wrapping_add(0x800) >> 12; + let insn = (insn & 0xFFF) | (hi20 << 12); + buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn)); + } + + LabelUse::PCRelLo12I => { + // `offset` is the offset from the current instruction to the target address. + // + // However we are trying to compute the offset to the target address from the previous instruction. + // The previous instruction should be the one that contains the PCRelHi20 relocation and + // stores/references the program counter (`auipc` usually). + // + // Since we are trying to compute the offset from the previous instruction, we can + // represent it as offset = target_address - (current_instruction_address - 4) + // which is equivalent to offset = target_address - current_instruction_address + 4. + // + // Thus we need to add 4 to the offset here. + let lo12 = (offset + 4) as u32 & 0xFFF; + let insn = (insn & 0xFFFFF) | (lo12 << 20); + buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn)); + } + LabelUse::RVCJump => { + debug_assert!(offset & 1 == 0); + + // We currently only support this for the C.J operation, so assert that is the opcode in + // the buffer. + debug_assert_eq!(insn & 0xFFFF, 0xA001); + + buffer[0..2].clone_from_slice(&u16::to_le_bytes(encode_cj_type( + CjOp::CJ, + Imm12::from_i16(i16::try_from(offset).unwrap()), + ))); + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn label_use_max_range() { + assert!(LabelUse::B12.max_neg_range() == LabelUse::B12.max_pos_range() + 2); + assert!(LabelUse::Jal20.max_neg_range() == LabelUse::Jal20.max_pos_range() + 2); + assert!(LabelUse::PCRel32.max_pos_range() == (Inst::imm_max() as CodeOffset)); + assert!(LabelUse::PCRel32.max_neg_range() == (Inst::imm_min().abs() as CodeOffset)); + assert!(LabelUse::B12.max_pos_range() == ((1 << 11) - 1) * 2); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/regs.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/regs.rs new file mode 100644 index 00000000000000..ffdc484a00c768 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/regs.rs @@ -0,0 +1,168 @@ +//! Riscv64 ISA definitions: registers. +//! + +use crate::machinst::{Reg, Writable}; + +use alloc::vec; +use alloc::vec::Vec; + +use regalloc2::{PReg, RegClass, VReg}; + +// first argument of function call +#[inline] +pub fn a0() -> Reg { + x_reg(10) +} + +// second argument of function call +#[inline] +#[allow(dead_code)] +pub fn a1() -> Reg { + x_reg(11) +} + +// third argument of function call +#[inline] +#[allow(dead_code)] +pub fn a2() -> Reg { + x_reg(12) +} + +#[inline] +#[allow(dead_code)] +pub fn writable_a0() -> Writable { + Writable::from_reg(a0()) +} +#[inline] +#[allow(dead_code)] +pub fn writable_a1() -> Writable { + Writable::from_reg(a1()) +} +#[inline] +#[allow(dead_code)] +pub fn writable_a2() -> Writable { + Writable::from_reg(a2()) +} + +#[inline] +#[allow(dead_code)] +pub fn fa0() -> Reg { + f_reg(10) +} +#[inline] +#[allow(dead_code)] +pub fn writable_fa0() -> Writable { + Writable::from_reg(fa0()) +} +#[inline] +#[allow(dead_code)] +pub fn writable_fa1() -> Writable { + Writable::from_reg(fa1()) +} +#[inline] +pub fn fa1() -> Reg { + f_reg(11) +} + +/// Get a reference to the zero-register. +#[inline] +pub fn zero_reg() -> Reg { + x_reg(0) +} + +/// Get a writable reference to the zero-register (this discards a result). +#[inline] +pub fn writable_zero_reg() -> Writable { + Writable::from_reg(zero_reg()) +} +#[inline] +pub fn stack_reg() -> Reg { + x_reg(2) +} + +/// Get a writable reference to the stack-pointer register. +#[inline] +pub fn writable_stack_reg() -> Writable { + Writable::from_reg(stack_reg()) +} + +/// Get a reference to the link register (x1). +pub fn link_reg() -> Reg { + x_reg(1) +} + +/// Get a writable reference to the link register. +#[inline] +pub fn writable_link_reg() -> Writable { + Writable::from_reg(link_reg()) +} + +/// Get a reference to the frame pointer (x8). +#[inline] +pub fn fp_reg() -> Reg { + x_reg(8) +} + +/// Get a writable reference to the frame pointer. +#[inline] +pub fn writable_fp_reg() -> Writable { + Writable::from_reg(fp_reg()) +} + +/// Get a reference to the first temporary, sometimes "spill temporary", +/// register. This register is used in various ways as a temporary. +#[inline] +pub fn spilltmp_reg() -> Reg { + x_reg(31) +} + +/// Get a writable reference to the spilltmp reg. +#[inline] +pub fn writable_spilltmp_reg() -> Writable { + Writable::from_reg(spilltmp_reg()) +} + +///spilltmp2 +#[inline] +pub fn spilltmp_reg2() -> Reg { + x_reg(30) +} + +/// Get a writable reference to the spilltmp2 reg. +#[inline] +pub fn writable_spilltmp_reg2() -> Writable { + Writable::from_reg(spilltmp_reg2()) +} + +#[inline] +pub fn x_reg(enc: usize) -> Reg { + let p_reg = PReg::new(enc, RegClass::Int); + let v_reg = VReg::new(p_reg.index(), p_reg.class()); + Reg::from(v_reg) +} +pub const fn px_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Int) +} + +#[inline] +pub fn f_reg(enc: usize) -> Reg { + let p_reg = PReg::new(enc, RegClass::Float); + let v_reg = VReg::new(p_reg.index(), p_reg.class()); + Reg::from(v_reg) +} +pub const fn pf_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Float) +} + +#[allow(dead_code)] +pub(crate) fn x_reg_range(start: usize, end: usize) -> Vec> { + let mut regs = vec![]; + for i in start..=end { + regs.push(Writable::from_reg(x_reg(i))); + } + regs +} + +pub const fn pv_reg(enc: usize) -> PReg { + PReg::new(enc, RegClass::Vector) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind.rs new file mode 100644 index 00000000000000..1e2bb904db74fc --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "unwind")] +pub(crate) mod systemv; diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind/systemv.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind/systemv.rs new file mode 100644 index 00000000000000..4bbb8401451e93 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/unwind/systemv.rs @@ -0,0 +1,170 @@ +//! Unwind information for System V ABI (Riscv64). + +use crate::isa::riscv64::inst::regs; +use crate::isa::unwind::systemv::RegisterMappingError; +use crate::machinst::Reg; +use gimli::{write::CommonInformationEntry, Encoding, Format, Register}; +use regalloc2::RegClass; + +/// Creates a new riscv64 common information entry (CIE). +pub fn create_cie() -> CommonInformationEntry { + use gimli::write::CallFrameInstruction; + + let mut entry = CommonInformationEntry::new( + Encoding { + address_size: 8, + format: Format::Dwarf32, + version: 1, + }, + 2, // Code alignment factor + -8, // Data alignment factor + Register(regs::link_reg().to_real_reg().unwrap().hw_enc() as u16), + ); + + // Every frame will start with the call frame address (CFA) at SP + let sp = Register(regs::stack_reg().to_real_reg().unwrap().hw_enc().into()); + entry.add_instruction(CallFrameInstruction::Cfa(sp, 0)); + + entry +} + +/// Map Cranelift registers to their corresponding Gimli registers. +pub fn map_reg(reg: Reg) -> Result { + let reg_offset = match reg.class() { + RegClass::Int => 0, + RegClass::Float => 32, + RegClass::Vector => 64, + }; + + let reg = reg.to_real_reg().unwrap().hw_enc() as u16; + Ok(Register(reg_offset + reg)) +} + +pub(crate) struct RegisterMapper; + +impl crate::isa::unwind::systemv::RegisterMapper for RegisterMapper { + fn map(&self, reg: Reg) -> Result { + Ok(map_reg(reg)?.0) + } + fn fp(&self) -> Option { + Some(regs::fp_reg().to_real_reg().unwrap().hw_enc() as u16) + } + fn lr(&self) -> Option { + Some(regs::link_reg().to_real_reg().unwrap().hw_enc() as u16) + } + fn lr_offset(&self) -> Option { + Some(8) + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, FuncCursor}; + + use crate::ir::{ + types, AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, + UserFuncName, + }; + use crate::isa::{lookup, CallConv}; + use crate::settings::{builder, Flags}; + use crate::Context; + use gimli::write::Address; + use target_lexicon::triple; + + #[test] + fn test_simple_func() { + let isa = lookup(triple!("riscv64")) + .expect("expect riscv64 ISA") + .finish(Flags::new(builder())) + .expect("Creating compiler backend"); + + let mut context = Context::for_function(create_function( + CallConv::SystemV, + Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)), + )); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(1234)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(1234), length: 40, lsda: None, instructions: [(12, CfaOffset(16)), (12, Offset(Register(8), -16)), (12, Offset(Register(1), -8)), (16, CfaRegister(Register(8)))] }"); + } + + fn create_function(call_conv: CallConv, stack_slot: Option) -> Function { + let mut func = + Function::with_name_signature(UserFuncName::user(0, 0), Signature::new(call_conv)); + + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().return_(&[]); + + if let Some(stack_slot) = stack_slot { + func.sized_stack_slots.push(stack_slot); + } + + func + } + + #[test] + fn test_multi_return_func() { + let isa = lookup(triple!("riscv64")) + .expect("expect riscv64 ISA") + .finish(Flags::new(builder())) + .expect("Creating compiler backend"); + + let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV)); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(4321)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!( + format!("{fde:?}"), + "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [] }" + ); + } + + fn create_multi_return_function(call_conv: CallConv) -> Function { + let mut sig = Signature::new(call_conv); + sig.params.push(AbiParam::new(types::I32)); + let mut func = Function::with_name_signature(UserFuncName::user(0, 0), sig); + + let block0 = func.dfg.make_block(); + let v0 = func.dfg.append_block_param(block0, types::I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().brif(v0, block2, &[], block1, &[]); + + pos.insert_block(block1); + pos.ins().return_(&[]); + + pos.insert_block(block2); + pos.ins().return_(&[]); + + func + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/vector.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/vector.rs new file mode 100644 index 00000000000000..d1ed3703cb6d66 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst/vector.rs @@ -0,0 +1,1150 @@ +use crate::isa::riscv64::lower::isle::generated_code::VecAluOpRRRR; +use crate::isa::riscv64::lower::isle::generated_code::{ + VecAMode, VecAluOpRImm5, VecAluOpRR, VecAluOpRRImm5, VecAluOpRRR, VecAluOpRRRImm5, VecAvl, + VecElementWidth, VecLmul, VecMaskMode, VecOpCategory, VecOpMasking, VecTailMode, +}; +use crate::machinst::{OperandVisitor, RegClass}; +use crate::Reg; +use core::fmt; + +use super::{Type, UImm5}; + +impl VecAvl { + pub fn _static(size: u32) -> Self { + VecAvl::Static { + size: UImm5::maybe_from_u8(size as u8).expect("Invalid size for AVL"), + } + } + + pub fn is_static(&self) -> bool { + match self { + VecAvl::Static { .. } => true, + } + } + + pub fn unwrap_static(&self) -> UImm5 { + match self { + VecAvl::Static { size } => *size, + } + } +} + +// TODO: Can we tell ISLE to derive this? +impl Copy for VecAvl {} + +// TODO: Can we tell ISLE to derive this? +impl PartialEq for VecAvl { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (VecAvl::Static { size: lhs }, VecAvl::Static { size: rhs }) => lhs == rhs, + } + } +} + +impl fmt::Display for VecAvl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VecAvl::Static { size } => write!(f, "{size}"), + } + } +} + +impl VecElementWidth { + pub fn from_type(ty: Type) -> Self { + Self::from_bits(ty.lane_bits()) + } + + pub fn from_bits(bits: u32) -> Self { + match bits { + 8 => VecElementWidth::E8, + 16 => VecElementWidth::E16, + 32 => VecElementWidth::E32, + 64 => VecElementWidth::E64, + _ => panic!("Invalid number of bits for VecElementWidth: {bits}"), + } + } + + pub fn bits(&self) -> u32 { + match self { + VecElementWidth::E8 => 8, + VecElementWidth::E16 => 16, + VecElementWidth::E32 => 32, + VecElementWidth::E64 => 64, + } + } + + pub fn encode(&self) -> u32 { + match self { + VecElementWidth::E8 => 0b000, + VecElementWidth::E16 => 0b001, + VecElementWidth::E32 => 0b010, + VecElementWidth::E64 => 0b011, + } + } +} + +impl fmt::Display for VecElementWidth { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "e{}", self.bits()) + } +} + +impl VecLmul { + pub fn encode(&self) -> u32 { + match self { + VecLmul::LmulF8 => 0b101, + VecLmul::LmulF4 => 0b110, + VecLmul::LmulF2 => 0b111, + VecLmul::Lmul1 => 0b000, + VecLmul::Lmul2 => 0b001, + VecLmul::Lmul4 => 0b010, + VecLmul::Lmul8 => 0b011, + } + } +} + +impl fmt::Display for VecLmul { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VecLmul::LmulF8 => write!(f, "mf8"), + VecLmul::LmulF4 => write!(f, "mf4"), + VecLmul::LmulF2 => write!(f, "mf2"), + VecLmul::Lmul1 => write!(f, "m1"), + VecLmul::Lmul2 => write!(f, "m2"), + VecLmul::Lmul4 => write!(f, "m4"), + VecLmul::Lmul8 => write!(f, "m8"), + } + } +} + +impl VecTailMode { + pub fn encode(&self) -> u32 { + match self { + VecTailMode::Agnostic => 1, + VecTailMode::Undisturbed => 0, + } + } +} + +impl fmt::Display for VecTailMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VecTailMode::Agnostic => write!(f, "ta"), + VecTailMode::Undisturbed => write!(f, "tu"), + } + } +} + +impl VecMaskMode { + pub fn encode(&self) -> u32 { + match self { + VecMaskMode::Agnostic => 1, + VecMaskMode::Undisturbed => 0, + } + } +} + +impl fmt::Display for VecMaskMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VecMaskMode::Agnostic => write!(f, "ma"), + VecMaskMode::Undisturbed => write!(f, "mu"), + } + } +} + +/// Vector Type (VType) +/// +/// vtype provides the default type used to interpret the contents of the vector register file. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct VType { + pub sew: VecElementWidth, + pub lmul: VecLmul, + pub tail_mode: VecTailMode, + pub mask_mode: VecMaskMode, +} + +impl VType { + // https://github.com/riscv/riscv-v-spec/blob/master/vtype-format.adoc + pub fn encode(&self) -> u32 { + let mut bits = 0; + bits |= self.lmul.encode(); + bits |= self.sew.encode() << 3; + bits |= self.tail_mode.encode() << 6; + bits |= self.mask_mode.encode() << 7; + bits + } +} + +impl fmt::Display for VType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}, {}, {}, {}", + self.sew, self.lmul, self.tail_mode, self.mask_mode + ) + } +} + +/// Vector State (VState) +/// +/// VState represents the state of the vector unit that each instruction expects before execution. +/// Unlike VType or any of the other types here, VState is not a part of the RISC-V ISA. It is +/// used by our instruction emission code to ensure that the vector unit is in the correct state. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct VState { + pub avl: VecAvl, + pub vtype: VType, +} + +impl VState { + pub fn from_type(ty: Type) -> Self { + VState { + avl: VecAvl::_static(ty.lane_count()), + vtype: VType { + sew: VecElementWidth::from_type(ty), + lmul: VecLmul::Lmul1, + tail_mode: VecTailMode::Agnostic, + mask_mode: VecMaskMode::Agnostic, + }, + } + } +} + +impl fmt::Display for VState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "#avl={}, #vtype=({})", self.avl, self.vtype) + } +} + +impl VecOpCategory { + pub fn encode(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#101-vector-arithmetic-instruction-encoding + match self { + VecOpCategory::OPIVV => 0b000, + VecOpCategory::OPFVV => 0b001, + VecOpCategory::OPMVV => 0b010, + VecOpCategory::OPIVI => 0b011, + VecOpCategory::OPIVX => 0b100, + VecOpCategory::OPFVF => 0b101, + VecOpCategory::OPMVX => 0b110, + VecOpCategory::OPCFG => 0b111, + } + } +} + +impl Copy for VecOpMasking {} +impl VecOpMasking { + pub fn is_enabled(&self) -> bool { + match self { + VecOpMasking::Enabled { .. } => true, + VecOpMasking::Disabled => false, + } + } + + pub fn encode(&self) -> u32 { + match self { + VecOpMasking::Enabled { .. } => 0, + VecOpMasking::Disabled => 1, + } + } +} + +impl VecAluOpRRRR { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + pub fn funct3(&self) -> u32 { + self.category().encode() + } + + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRRRR::VmaccVV | VecAluOpRRRR::VmaccVX => 0b101101, + VecAluOpRRRR::VnmsacVV | VecAluOpRRRR::VnmsacVX => 0b101111, + VecAluOpRRRR::VfmaccVV | VecAluOpRRRR::VfmaccVF => 0b101100, + VecAluOpRRRR::VfnmaccVV | VecAluOpRRRR::VfnmaccVF => 0b101101, + VecAluOpRRRR::VfmsacVV | VecAluOpRRRR::VfmsacVF => 0b101110, + VecAluOpRRRR::VfnmsacVV | VecAluOpRRRR::VfnmsacVF => 0b101111, + VecAluOpRRRR::Vslide1upVX => 0b001110, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRRRR::VmaccVV | VecAluOpRRRR::VnmsacVV => VecOpCategory::OPMVV, + VecAluOpRRRR::VmaccVX | VecAluOpRRRR::VnmsacVX | VecAluOpRRRR::Vslide1upVX => { + VecOpCategory::OPMVX + } + VecAluOpRRRR::VfmaccVV + | VecAluOpRRRR::VfnmaccVV + | VecAluOpRRRR::VfmsacVV + | VecAluOpRRRR::VfnmsacVV => VecOpCategory::OPFVV, + VecAluOpRRRR::VfmaccVF + | VecAluOpRRRR::VfnmaccVF + | VecAluOpRRRR::VfmsacVF + | VecAluOpRRRR::VfnmsacVF => VecOpCategory::OPFVF, + } + } + + // vs1 is the only variable source, vs2 is fixed. + pub fn vs1_regclass(&self) -> RegClass { + match self.category() { + VecOpCategory::OPMVV | VecOpCategory::OPFVV => RegClass::Vector, + VecOpCategory::OPMVX => RegClass::Int, + VecOpCategory::OPFVF => RegClass::Float, + _ => unreachable!(), + } + } +} + +impl VecInstOverlapInfo for VecAluOpRRRR { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRRR::Vslide1upVX => true, + _ => false, + } + } +} + +impl fmt::Display for VecAluOpRRRR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut s = format!("{self:?}"); + s.make_ascii_lowercase(); + let (opcode, category) = s.split_at(s.len() - 2); + f.write_str(&format!("{opcode}.{category}")) + } +} + +impl VecAluOpRRRImm5 { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + pub fn funct3(&self) -> u32 { + self.category().encode() + } + + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRRRImm5::VslideupVI => 0b001110, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRRRImm5::VslideupVI => VecOpCategory::OPIVI, + } + } + + pub fn imm_is_unsigned(&self) -> bool { + match self { + VecAluOpRRRImm5::VslideupVI => true, + } + } +} + +impl VecInstOverlapInfo for VecAluOpRRRImm5 { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRRImm5::VslideupVI => true, + } + } +} + +impl fmt::Display for VecAluOpRRRImm5 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut s = format!("{self:?}"); + s.make_ascii_lowercase(); + let (opcode, category) = s.split_at(s.len() - 2); + f.write_str(&format!("{opcode}.{category}")) + } +} + +impl VecAluOpRRR { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + pub fn funct3(&self) -> u32 { + self.category().encode() + } + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRRR::VaddVV + | VecAluOpRRR::VaddVX + | VecAluOpRRR::VfaddVV + | VecAluOpRRR::VfaddVF => 0b000000, + VecAluOpRRR::VsubVV + | VecAluOpRRR::VsubVX + | VecAluOpRRR::VfsubVV + | VecAluOpRRR::VfsubVF => 0b000010, + VecAluOpRRR::VrsubVX => 0b000011, + VecAluOpRRR::VmulVV | VecAluOpRRR::VmulVX => 0b100101, + VecAluOpRRR::VmulhVV | VecAluOpRRR::VmulhVX => 0b100111, + VecAluOpRRR::VmulhuVV + | VecAluOpRRR::VmulhuVX + | VecAluOpRRR::VfmulVV + | VecAluOpRRR::VfmulVF => 0b100100, + VecAluOpRRR::VsmulVV | VecAluOpRRR::VsmulVX => 0b100111, + VecAluOpRRR::VsllVV | VecAluOpRRR::VsllVX => 0b100101, + VecAluOpRRR::VsrlVV | VecAluOpRRR::VsrlVX => 0b101000, + VecAluOpRRR::VsraVV | VecAluOpRRR::VsraVX => 0b101001, + VecAluOpRRR::VandVV | VecAluOpRRR::VandVX => 0b001001, + VecAluOpRRR::VorVV | VecAluOpRRR::VorVX => 0b001010, + VecAluOpRRR::VxorVV | VecAluOpRRR::VxorVX => 0b001011, + VecAluOpRRR::VminuVV | VecAluOpRRR::VminuVX | VecAluOpRRR::VredminuVS => 0b000100, + VecAluOpRRR::VminVV | VecAluOpRRR::VminVX => 0b000101, + VecAluOpRRR::VmaxuVV | VecAluOpRRR::VmaxuVX | VecAluOpRRR::VredmaxuVS => 0b000110, + VecAluOpRRR::VmaxVV | VecAluOpRRR::VmaxVX => 0b000111, + VecAluOpRRR::VslidedownVX => 0b001111, + VecAluOpRRR::VfrsubVF => 0b100111, + VecAluOpRRR::VmergeVVM + | VecAluOpRRR::VmergeVXM + | VecAluOpRRR::VfmergeVFM + | VecAluOpRRR::VcompressVM => 0b010111, + VecAluOpRRR::VfdivVV + | VecAluOpRRR::VfdivVF + | VecAluOpRRR::VsadduVV + | VecAluOpRRR::VsadduVX => 0b100000, + VecAluOpRRR::VfrdivVF | VecAluOpRRR::VsaddVV | VecAluOpRRR::VsaddVX => 0b100001, + VecAluOpRRR::VfminVV => 0b000100, + VecAluOpRRR::VfmaxVV => 0b000110, + VecAluOpRRR::VssubuVV | VecAluOpRRR::VssubuVX => 0b100010, + VecAluOpRRR::VssubVV | VecAluOpRRR::VssubVX => 0b100011, + VecAluOpRRR::VfsgnjVV | VecAluOpRRR::VfsgnjVF => 0b001000, + VecAluOpRRR::VfsgnjnVV => 0b001001, + VecAluOpRRR::VfsgnjxVV => 0b001010, + VecAluOpRRR::VrgatherVV | VecAluOpRRR::VrgatherVX => 0b001100, + VecAluOpRRR::VwadduVV | VecAluOpRRR::VwadduVX => 0b110000, + VecAluOpRRR::VwaddVV | VecAluOpRRR::VwaddVX => 0b110001, + VecAluOpRRR::VwsubuVV | VecAluOpRRR::VwsubuVX => 0b110010, + VecAluOpRRR::VwsubVV | VecAluOpRRR::VwsubVX => 0b110011, + VecAluOpRRR::VwadduWV | VecAluOpRRR::VwadduWX => 0b110100, + VecAluOpRRR::VwaddWV | VecAluOpRRR::VwaddWX => 0b110101, + VecAluOpRRR::VwsubuWV | VecAluOpRRR::VwsubuWX => 0b110110, + VecAluOpRRR::VwsubWV | VecAluOpRRR::VwsubWX => 0b110111, + VecAluOpRRR::VmseqVV + | VecAluOpRRR::VmseqVX + | VecAluOpRRR::VmfeqVV + | VecAluOpRRR::VmfeqVF => 0b011000, + VecAluOpRRR::VmsneVV + | VecAluOpRRR::VmsneVX + | VecAluOpRRR::VmfleVV + | VecAluOpRRR::VmfleVF + | VecAluOpRRR::VmandMM => 0b011001, + VecAluOpRRR::VmsltuVV | VecAluOpRRR::VmsltuVX | VecAluOpRRR::VmorMM => 0b011010, + VecAluOpRRR::VmsltVV + | VecAluOpRRR::VmsltVX + | VecAluOpRRR::VmfltVV + | VecAluOpRRR::VmfltVF => 0b011011, + VecAluOpRRR::VmsleuVV + | VecAluOpRRR::VmsleuVX + | VecAluOpRRR::VmfneVV + | VecAluOpRRR::VmfneVF => 0b011100, + VecAluOpRRR::VmsleVV + | VecAluOpRRR::VmsleVX + | VecAluOpRRR::VmfgtVF + | VecAluOpRRR::VmnandMM => 0b011101, + VecAluOpRRR::VmsgtuVX | VecAluOpRRR::VmnorMM => 0b011110, + VecAluOpRRR::VmsgtVX | VecAluOpRRR::VmfgeVF => 0b011111, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRRR::VaddVV + | VecAluOpRRR::VsaddVV + | VecAluOpRRR::VsadduVV + | VecAluOpRRR::VsubVV + | VecAluOpRRR::VssubVV + | VecAluOpRRR::VssubuVV + | VecAluOpRRR::VsmulVV + | VecAluOpRRR::VsllVV + | VecAluOpRRR::VsrlVV + | VecAluOpRRR::VsraVV + | VecAluOpRRR::VandVV + | VecAluOpRRR::VorVV + | VecAluOpRRR::VxorVV + | VecAluOpRRR::VminuVV + | VecAluOpRRR::VminVV + | VecAluOpRRR::VmaxuVV + | VecAluOpRRR::VmaxVV + | VecAluOpRRR::VmergeVVM + | VecAluOpRRR::VrgatherVV + | VecAluOpRRR::VmseqVV + | VecAluOpRRR::VmsneVV + | VecAluOpRRR::VmsltuVV + | VecAluOpRRR::VmsltVV + | VecAluOpRRR::VmsleuVV + | VecAluOpRRR::VmsleVV => VecOpCategory::OPIVV, + VecAluOpRRR::VwaddVV + | VecAluOpRRR::VwaddWV + | VecAluOpRRR::VwadduVV + | VecAluOpRRR::VwadduWV + | VecAluOpRRR::VwsubVV + | VecAluOpRRR::VwsubWV + | VecAluOpRRR::VwsubuVV + | VecAluOpRRR::VwsubuWV + | VecAluOpRRR::VmulVV + | VecAluOpRRR::VmulhVV + | VecAluOpRRR::VmulhuVV + | VecAluOpRRR::VredmaxuVS + | VecAluOpRRR::VredminuVS + | VecAluOpRRR::VcompressVM + | VecAluOpRRR::VmandMM + | VecAluOpRRR::VmorMM + | VecAluOpRRR::VmnandMM + | VecAluOpRRR::VmnorMM => VecOpCategory::OPMVV, + VecAluOpRRR::VwaddVX + | VecAluOpRRR::VwadduVX + | VecAluOpRRR::VwadduWX + | VecAluOpRRR::VwaddWX + | VecAluOpRRR::VwsubVX + | VecAluOpRRR::VwsubuVX + | VecAluOpRRR::VwsubuWX + | VecAluOpRRR::VwsubWX + | VecAluOpRRR::VmulVX + | VecAluOpRRR::VmulhVX + | VecAluOpRRR::VmulhuVX => VecOpCategory::OPMVX, + VecAluOpRRR::VaddVX + | VecAluOpRRR::VsaddVX + | VecAluOpRRR::VsadduVX + | VecAluOpRRR::VsubVX + | VecAluOpRRR::VssubVX + | VecAluOpRRR::VssubuVX + | VecAluOpRRR::VrsubVX + | VecAluOpRRR::VsmulVX + | VecAluOpRRR::VsllVX + | VecAluOpRRR::VsrlVX + | VecAluOpRRR::VsraVX + | VecAluOpRRR::VandVX + | VecAluOpRRR::VorVX + | VecAluOpRRR::VxorVX + | VecAluOpRRR::VminuVX + | VecAluOpRRR::VminVX + | VecAluOpRRR::VmaxuVX + | VecAluOpRRR::VmaxVX + | VecAluOpRRR::VslidedownVX + | VecAluOpRRR::VmergeVXM + | VecAluOpRRR::VrgatherVX + | VecAluOpRRR::VmseqVX + | VecAluOpRRR::VmsneVX + | VecAluOpRRR::VmsltuVX + | VecAluOpRRR::VmsltVX + | VecAluOpRRR::VmsleuVX + | VecAluOpRRR::VmsleVX + | VecAluOpRRR::VmsgtuVX + | VecAluOpRRR::VmsgtVX => VecOpCategory::OPIVX, + VecAluOpRRR::VfaddVV + | VecAluOpRRR::VfsubVV + | VecAluOpRRR::VfmulVV + | VecAluOpRRR::VfdivVV + | VecAluOpRRR::VfmaxVV + | VecAluOpRRR::VfminVV + | VecAluOpRRR::VfsgnjVV + | VecAluOpRRR::VfsgnjnVV + | VecAluOpRRR::VfsgnjxVV + | VecAluOpRRR::VmfeqVV + | VecAluOpRRR::VmfneVV + | VecAluOpRRR::VmfltVV + | VecAluOpRRR::VmfleVV => VecOpCategory::OPFVV, + VecAluOpRRR::VfaddVF + | VecAluOpRRR::VfsubVF + | VecAluOpRRR::VfrsubVF + | VecAluOpRRR::VfmulVF + | VecAluOpRRR::VfdivVF + | VecAluOpRRR::VfrdivVF + | VecAluOpRRR::VfmergeVFM + | VecAluOpRRR::VfsgnjVF + | VecAluOpRRR::VmfeqVF + | VecAluOpRRR::VmfneVF + | VecAluOpRRR::VmfltVF + | VecAluOpRRR::VmfleVF + | VecAluOpRRR::VmfgtVF + | VecAluOpRRR::VmfgeVF => VecOpCategory::OPFVF, + } + } + + // vs1 is the only variable source, vs2 is fixed. + pub fn vs1_regclass(&self) -> RegClass { + match self.category() { + VecOpCategory::OPIVV | VecOpCategory::OPFVV | VecOpCategory::OPMVV => RegClass::Vector, + VecOpCategory::OPIVX | VecOpCategory::OPMVX => RegClass::Int, + VecOpCategory::OPFVF => RegClass::Float, + _ => unreachable!(), + } + } +} + +impl VecInstOverlapInfo for VecAluOpRRR { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRR::VrgatherVV + | VecAluOpRRR::VrgatherVX + | VecAluOpRRR::VcompressVM + | VecAluOpRRR::VwadduVV + | VecAluOpRRR::VwadduVX + | VecAluOpRRR::VwaddVV + | VecAluOpRRR::VwaddVX + | VecAluOpRRR::VwadduWV + | VecAluOpRRR::VwadduWX + | VecAluOpRRR::VwaddWV + | VecAluOpRRR::VwaddWX + | VecAluOpRRR::VwsubuVV + | VecAluOpRRR::VwsubuVX + | VecAluOpRRR::VwsubVV + | VecAluOpRRR::VwsubVX + | VecAluOpRRR::VwsubuWV + | VecAluOpRRR::VwsubuWX + | VecAluOpRRR::VwsubWV + | VecAluOpRRR::VwsubWX => true, + _ => false, + } + } + + // Only mask writing operations, and reduction operations (`vred*`) allow mask / dst overlaps. + fn forbids_mask_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRR::VredmaxuVS + | VecAluOpRRR::VredminuVS + | VecAluOpRRR::VmandMM + | VecAluOpRRR::VmorMM + | VecAluOpRRR::VmnandMM + | VecAluOpRRR::VmnorMM + | VecAluOpRRR::VmseqVX + | VecAluOpRRR::VmsneVX + | VecAluOpRRR::VmsltuVX + | VecAluOpRRR::VmsltVX + | VecAluOpRRR::VmsleuVX + | VecAluOpRRR::VmsleVX + | VecAluOpRRR::VmsgtuVX + | VecAluOpRRR::VmsgtVX + | VecAluOpRRR::VmfeqVV + | VecAluOpRRR::VmfneVV + | VecAluOpRRR::VmfltVV + | VecAluOpRRR::VmfleVV + | VecAluOpRRR::VmfeqVF + | VecAluOpRRR::VmfneVF + | VecAluOpRRR::VmfltVF + | VecAluOpRRR::VmfleVF + | VecAluOpRRR::VmfgtVF + | VecAluOpRRR::VmfgeVF => false, + _ => true, + } + } +} + +impl fmt::Display for VecAluOpRRR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let suffix_length = match self { + VecAluOpRRR::VmergeVVM | VecAluOpRRR::VmergeVXM | VecAluOpRRR::VfmergeVFM => 3, + _ => 2, + }; + + let mut s = format!("{self:?}"); + s.make_ascii_lowercase(); + let (opcode, category) = s.split_at(s.len() - suffix_length); + f.write_str(&format!("{opcode}.{category}")) + } +} + +impl VecAluOpRRImm5 { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + pub fn funct3(&self) -> u32 { + self.category().encode() + } + + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRRImm5::VaddVI => 0b000000, + VecAluOpRRImm5::VrsubVI => 0b000011, + VecAluOpRRImm5::VsllVI => 0b100101, + VecAluOpRRImm5::VsrlVI => 0b101000, + VecAluOpRRImm5::VsraVI => 0b101001, + VecAluOpRRImm5::VandVI => 0b001001, + VecAluOpRRImm5::VorVI => 0b001010, + VecAluOpRRImm5::VxorVI => 0b001011, + VecAluOpRRImm5::VslidedownVI => 0b001111, + VecAluOpRRImm5::VssrlVI => 0b101010, + VecAluOpRRImm5::VmergeVIM => 0b010111, + VecAluOpRRImm5::VsadduVI => 0b100000, + VecAluOpRRImm5::VsaddVI => 0b100001, + VecAluOpRRImm5::VrgatherVI => 0b001100, + VecAluOpRRImm5::VmvrV => 0b100111, + VecAluOpRRImm5::VnclipWI => 0b101111, + VecAluOpRRImm5::VnclipuWI => 0b101110, + VecAluOpRRImm5::VmseqVI => 0b011000, + VecAluOpRRImm5::VmsneVI => 0b011001, + VecAluOpRRImm5::VmsleuVI => 0b011100, + VecAluOpRRImm5::VmsleVI => 0b011101, + VecAluOpRRImm5::VmsgtuVI => 0b011110, + VecAluOpRRImm5::VmsgtVI => 0b011111, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRRImm5::VaddVI + | VecAluOpRRImm5::VrsubVI + | VecAluOpRRImm5::VsllVI + | VecAluOpRRImm5::VsrlVI + | VecAluOpRRImm5::VsraVI + | VecAluOpRRImm5::VandVI + | VecAluOpRRImm5::VorVI + | VecAluOpRRImm5::VxorVI + | VecAluOpRRImm5::VssrlVI + | VecAluOpRRImm5::VslidedownVI + | VecAluOpRRImm5::VmergeVIM + | VecAluOpRRImm5::VsadduVI + | VecAluOpRRImm5::VsaddVI + | VecAluOpRRImm5::VrgatherVI + | VecAluOpRRImm5::VmvrV + | VecAluOpRRImm5::VnclipWI + | VecAluOpRRImm5::VnclipuWI + | VecAluOpRRImm5::VmseqVI + | VecAluOpRRImm5::VmsneVI + | VecAluOpRRImm5::VmsleuVI + | VecAluOpRRImm5::VmsleVI + | VecAluOpRRImm5::VmsgtuVI + | VecAluOpRRImm5::VmsgtVI => VecOpCategory::OPIVI, + } + } + + pub fn imm_is_unsigned(&self) -> bool { + match self { + VecAluOpRRImm5::VsllVI + | VecAluOpRRImm5::VsrlVI + | VecAluOpRRImm5::VssrlVI + | VecAluOpRRImm5::VsraVI + | VecAluOpRRImm5::VslidedownVI + | VecAluOpRRImm5::VrgatherVI + | VecAluOpRRImm5::VmvrV + | VecAluOpRRImm5::VnclipWI + | VecAluOpRRImm5::VnclipuWI => true, + VecAluOpRRImm5::VaddVI + | VecAluOpRRImm5::VrsubVI + | VecAluOpRRImm5::VandVI + | VecAluOpRRImm5::VorVI + | VecAluOpRRImm5::VxorVI + | VecAluOpRRImm5::VmergeVIM + | VecAluOpRRImm5::VsadduVI + | VecAluOpRRImm5::VsaddVI + | VecAluOpRRImm5::VmseqVI + | VecAluOpRRImm5::VmsneVI + | VecAluOpRRImm5::VmsleuVI + | VecAluOpRRImm5::VmsleVI + | VecAluOpRRImm5::VmsgtuVI + | VecAluOpRRImm5::VmsgtVI => false, + } + } +} + +impl VecInstOverlapInfo for VecAluOpRRImm5 { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRImm5::VrgatherVI => true, + _ => false, + } + } + + // Only mask writing operations, and reduction operations (`vred*`) allow mask / dst overlaps. + fn forbids_mask_dst_overlaps(&self) -> bool { + match self { + VecAluOpRRImm5::VmseqVI + | VecAluOpRRImm5::VmsneVI + | VecAluOpRRImm5::VmsleuVI + | VecAluOpRRImm5::VmsleVI + | VecAluOpRRImm5::VmsgtuVI + | VecAluOpRRImm5::VmsgtVI => false, + _ => true, + } + } +} + +impl fmt::Display for VecAluOpRRImm5 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let suffix_length = match self { + VecAluOpRRImm5::VmergeVIM => 3, + _ => 2, + }; + + let mut s = format!("{self:?}"); + s.make_ascii_lowercase(); + let (opcode, category) = s.split_at(s.len() - suffix_length); + f.write_str(&format!("{opcode}.{category}")) + } +} + +impl VecAluOpRR { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + + pub fn funct3(&self) -> u32 { + self.category().encode() + } + + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRR::VmvSX | VecAluOpRR::VmvXS | VecAluOpRR::VfmvSF | VecAluOpRR::VfmvFS => { + 0b010000 + } + VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 => 0b010010, + VecAluOpRR::VfsqrtV => 0b010011, + VecAluOpRR::VmvVV | VecAluOpRR::VmvVX | VecAluOpRR::VfmvVF => 0b010111, + VecAluOpRR::VfcvtxufV + | VecAluOpRR::VfcvtxfV + | VecAluOpRR::VfcvtrtzxufV + | VecAluOpRR::VfcvtrtzxfV + | VecAluOpRR::VfcvtfxuV + | VecAluOpRR::VfcvtfxV + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => 0b010010, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRR::VmvSX => VecOpCategory::OPMVX, + VecAluOpRR::VmvXS + | VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 => VecOpCategory::OPMVV, + VecAluOpRR::VfmvSF | VecAluOpRR::VfmvVF => VecOpCategory::OPFVF, + VecAluOpRR::VfmvFS + | VecAluOpRR::VfsqrtV + | VecAluOpRR::VfcvtxufV + | VecAluOpRR::VfcvtxfV + | VecAluOpRR::VfcvtrtzxufV + | VecAluOpRR::VfcvtrtzxfV + | VecAluOpRR::VfcvtfxuV + | VecAluOpRR::VfcvtfxV + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => VecOpCategory::OPFVV, + VecAluOpRR::VmvVV => VecOpCategory::OPIVV, + VecAluOpRR::VmvVX => VecOpCategory::OPIVX, + } + } + + /// Returns the auxiliary encoding field for the instruction, if any. + pub fn aux_encoding(&self) -> u32 { + match self { + // VRXUNARY0 + VecAluOpRR::VmvSX => 0b00000, + // VWXUNARY0 + VecAluOpRR::VmvXS => 0b00000, + // VRFUNARY0 + VecAluOpRR::VfmvSF => 0b00000, + // VWFUNARY0 + VecAluOpRR::VfmvFS => 0b00000, + // VFUNARY1 + VecAluOpRR::VfsqrtV => 0b00000, + // VXUNARY0 + VecAluOpRR::VzextVF8 => 0b00010, + VecAluOpRR::VsextVF8 => 0b00011, + VecAluOpRR::VzextVF4 => 0b00100, + VecAluOpRR::VsextVF4 => 0b00101, + VecAluOpRR::VzextVF2 => 0b00110, + VecAluOpRR::VsextVF2 => 0b00111, + // VFUNARY0 + // single-width converts + VecAluOpRR::VfcvtxufV => 0b00000, + VecAluOpRR::VfcvtxfV => 0b00001, + VecAluOpRR::VfcvtrtzxufV => 0b00110, + VecAluOpRR::VfcvtrtzxfV => 0b00111, + VecAluOpRR::VfcvtfxuV => 0b00010, + VecAluOpRR::VfcvtfxV => 0b00011, + // widening converts + VecAluOpRR::VfwcvtffV => 0b01100, + // narrowing converts + VecAluOpRR::VfncvtffW => 0b10100, + // These don't have a explicit encoding table, but Section 11.16 Vector Integer Move Instruction states: + // > The first operand specifier (vs2) must contain v0, and any other vector register number in vs2 is reserved. + VecAluOpRR::VmvVV | VecAluOpRR::VmvVX | VecAluOpRR::VfmvVF => 0, + } + } + + /// Most of these opcodes have the source register encoded in the VS2 field and + /// the `aux_encoding` field in VS1. However some special snowflakes have it the + /// other way around. As far as I can tell only vmv.v.* are backwards. + pub fn vs_is_vs2_encoded(&self) -> bool { + match self { + VecAluOpRR::VmvXS + | VecAluOpRR::VfmvFS + | VecAluOpRR::VfsqrtV + | VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 + | VecAluOpRR::VfcvtxufV + | VecAluOpRR::VfcvtxfV + | VecAluOpRR::VfcvtrtzxufV + | VecAluOpRR::VfcvtrtzxfV + | VecAluOpRR::VfcvtfxuV + | VecAluOpRR::VfcvtfxV + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => true, + VecAluOpRR::VmvSX + | VecAluOpRR::VfmvSF + | VecAluOpRR::VmvVV + | VecAluOpRR::VmvVX + | VecAluOpRR::VfmvVF => false, + } + } + + pub fn dst_regclass(&self) -> RegClass { + match self { + VecAluOpRR::VfmvSF + | VecAluOpRR::VmvSX + | VecAluOpRR::VmvVV + | VecAluOpRR::VmvVX + | VecAluOpRR::VfmvVF + | VecAluOpRR::VfsqrtV + | VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 + | VecAluOpRR::VfcvtxufV + | VecAluOpRR::VfcvtxfV + | VecAluOpRR::VfcvtrtzxufV + | VecAluOpRR::VfcvtrtzxfV + | VecAluOpRR::VfcvtfxuV + | VecAluOpRR::VfcvtfxV + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => RegClass::Vector, + VecAluOpRR::VmvXS => RegClass::Int, + VecAluOpRR::VfmvFS => RegClass::Float, + } + } + + pub fn src_regclass(&self) -> RegClass { + match self { + VecAluOpRR::VmvXS + | VecAluOpRR::VfmvFS + | VecAluOpRR::VmvVV + | VecAluOpRR::VfsqrtV + | VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 + | VecAluOpRR::VfcvtxufV + | VecAluOpRR::VfcvtxfV + | VecAluOpRR::VfcvtrtzxufV + | VecAluOpRR::VfcvtrtzxfV + | VecAluOpRR::VfcvtfxuV + | VecAluOpRR::VfcvtfxV + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => RegClass::Vector, + VecAluOpRR::VfmvSF | VecAluOpRR::VfmvVF => RegClass::Float, + VecAluOpRR::VmvSX | VecAluOpRR::VmvVX => RegClass::Int, + } + } +} + +impl VecInstOverlapInfo for VecAluOpRR { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRR::VzextVF2 + | VecAluOpRR::VzextVF4 + | VecAluOpRR::VzextVF8 + | VecAluOpRR::VsextVF2 + | VecAluOpRR::VsextVF4 + | VecAluOpRR::VsextVF8 + | VecAluOpRR::VfwcvtffV + | VecAluOpRR::VfncvtffW => true, + _ => false, + } + } +} + +impl fmt::Display for VecAluOpRR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + VecAluOpRR::VmvSX => "vmv.s.x", + VecAluOpRR::VmvXS => "vmv.x.s", + VecAluOpRR::VfmvSF => "vfmv.s.f", + VecAluOpRR::VfmvFS => "vfmv.f.s", + VecAluOpRR::VfsqrtV => "vfsqrt.v", + VecAluOpRR::VzextVF2 => "vzext.vf2", + VecAluOpRR::VzextVF4 => "vzext.vf4", + VecAluOpRR::VzextVF8 => "vzext.vf8", + VecAluOpRR::VsextVF2 => "vsext.vf2", + VecAluOpRR::VsextVF4 => "vsext.vf4", + VecAluOpRR::VsextVF8 => "vsext.vf8", + VecAluOpRR::VmvVV => "vmv.v.v", + VecAluOpRR::VmvVX => "vmv.v.x", + VecAluOpRR::VfmvVF => "vfmv.v.f", + VecAluOpRR::VfcvtxufV => "vfcvt.xu.f.v", + VecAluOpRR::VfcvtxfV => "vfcvt.x.f.v", + VecAluOpRR::VfcvtrtzxufV => "vfcvt.rtz.xu.f.v", + VecAluOpRR::VfcvtrtzxfV => "vfcvt.rtz.x.f.v", + VecAluOpRR::VfcvtfxuV => "vfcvt.f.xu.v", + VecAluOpRR::VfcvtfxV => "vfcvt.f.x.v", + VecAluOpRR::VfwcvtffV => "vfwcvt.f.f.v", + VecAluOpRR::VfncvtffW => "vfncvt.f.f.w", + }) + } +} + +impl VecAluOpRImm5 { + pub fn opcode(&self) -> u32 { + // Vector Opcode + 0x57 + } + pub fn funct3(&self) -> u32 { + self.category().encode() + } + + pub fn funct6(&self) -> u32 { + // See: https://github.com/riscv/riscv-v-spec/blob/master/inst-table.adoc + match self { + VecAluOpRImm5::VmvVI => 0b010111, + } + } + + pub fn category(&self) -> VecOpCategory { + match self { + VecAluOpRImm5::VmvVI => VecOpCategory::OPIVI, + } + } + + /// Returns the auxiliary encoding field for the instruction, if any. + pub fn aux_encoding(&self) -> u32 { + match self { + // These don't have a explicit encoding table, but Section 11.16 Vector Integer Move Instruction states: + // > The first operand specifier (vs2) must contain v0, and any other vector register number in vs2 is reserved. + VecAluOpRImm5::VmvVI => 0, + } + } +} + +impl VecInstOverlapInfo for VecAluOpRImm5 { + fn forbids_src_dst_overlaps(&self) -> bool { + match self { + VecAluOpRImm5::VmvVI => false, + } + } +} + +impl fmt::Display for VecAluOpRImm5 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + VecAluOpRImm5::VmvVI => "vmv.v.i", + }) + } +} + +impl VecAMode { + pub fn get_base_register(&self) -> Option { + match self { + VecAMode::UnitStride { base, .. } => base.get_base_register(), + } + } + + pub fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + VecAMode::UnitStride { base, .. } => base.get_operands(collector), + } + } + + /// `mop` field, described in Table 7 of Section 7.2. Vector Load/Store Addressing Modes + /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes + pub fn mop(&self) -> u32 { + match self { + VecAMode::UnitStride { .. } => 0b00, + } + } + + /// `lumop` field, described in Table 9 of Section 7.2. Vector Load/Store Addressing Modes + /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes + pub fn lumop(&self) -> u32 { + match self { + VecAMode::UnitStride { .. } => 0b00000, + } + } + + /// `sumop` field, described in Table 10 of Section 7.2. Vector Load/Store Addressing Modes + /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes + pub fn sumop(&self) -> u32 { + match self { + VecAMode::UnitStride { .. } => 0b00000, + } + } + + /// The `nf[2:0]` field encodes the number of fields in each segment. For regular vector loads and + /// stores, nf=0, indicating that a single value is moved between a vector register group and memory + /// at each element position. Larger values in the nf field are used to access multiple contiguous + /// fields within a segment as described in Section 7.8 Vector Load/Store Segment Instructions. + /// + /// https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#72-vector-loadstore-addressing-modes + pub fn nf(&self) -> u32 { + match self { + VecAMode::UnitStride { .. } => 0b000, + } + } +} + +pub trait VecInstOverlapInfo { + /// § 5.2 Vector Operands states: + /// + /// A destination vector register group can overlap a source vector register group + /// only if one of the following holds: + /// + /// * The destination EEW equals the source EEW. + /// + /// * The destination EEW is smaller than the source EEW and the overlap is + /// in the lowest-numbered part of the source register group (e.g., when LMUL=1, + /// vnsrl.wi v0, v0, 3 is legal, but a destination of v1 is not). + /// + /// * The destination EEW is greater than the source EEW, the source EMUL is at + /// least 1, and the overlap is in the highest-numbered part of the destination register + /// group (e.g., when LMUL=8, vzext.vf4 v0, v6 is legal, but a source of v0, v2, or v4 is not). + /// + /// For the purpose of determining register group overlap constraints, mask elements have EEW=1. + fn forbids_src_dst_overlaps(&self) -> bool; + + /// § 5.3 Vector Masking states: + /// + /// > The destination vector register group for a masked vector instruction + /// > cannot overlap the source mask register (v0), unless the destination + /// > vector register is being written with a mask value (e.g., compares) or + /// > the scalar result of a reduction. These instruction encodings are reserved. + /// + /// In almost all instructions we should not allow the mask to be re-used as + /// a destination register. + fn forbids_mask_dst_overlaps(&self) -> bool { + true + } + + /// There are two broad categories of overlaps (see above). But we can't represent such + /// fine grained overlaps to regalloc. So if any of the two come into play we forbid + /// all source and destination overlaps (including masks). + fn forbids_overlaps(&self, mask: &VecOpMasking) -> bool { + self.forbids_src_dst_overlaps() || (mask.is_enabled() && self.forbids_mask_dst_overlaps()) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst_vector.isle b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst_vector.isle new file mode 100644 index 00000000000000..bea28c634aef22 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/inst_vector.isle @@ -0,0 +1,1908 @@ +;; Represents the possible widths of an element when used in an operation. +(type VecElementWidth (enum + (E8) + (E16) + (E32) + (E64) +)) + +;; Vector Register Group Multiplier (LMUL) +;; +;; The LMUL setting specifies how we should group registers together. LMUL can +;; also be a fractional value, reducing the number of bits used in a single +;; vector register. Fractional LMUL is used to increase the number of effective +;; usable vector register groups when operating on mixed-width values. +(type VecLmul (enum + (LmulF8) + (LmulF4) + (LmulF2) + (Lmul1) + (Lmul2) + (Lmul4) + (Lmul8) +)) + +;; Tail Mode +;; +;; The tail mode specifies how the tail elements of a vector register are handled. +(type VecTailMode (enum + ;; Tail Agnostic means that the tail elements are left in an undefined state. + (Agnostic) + ;; Tail Undisturbed means that the tail elements are left in their original values. + (Undisturbed) +)) + +;; Mask Mode +;; +;; The mask mode specifies how the masked elements of a vector register are handled. +(type VecMaskMode (enum + ;; Mask Agnostic means that the masked out elements are left in an undefined state. + (Agnostic) + ;; Mask Undisturbed means that the masked out elements are left in their original values. + (Undisturbed) +)) + +;; Application Vector Length (AVL) +;; +;; This setting specifies the number of elements that are going to be processed +;; in a single instruction. Note: We may end up processing fewer elements than +;; the AVL setting, if they don't fit in a single register. +(type VecAvl (enum + ;; Static AVL emits a `vsetivli` that uses a constant value + (Static (size UImm5)) + ;; TODO: Add a dynamic, register based AVL mode when we are able to properly test it +)) + +(type VType (primitive VType)) +(type VState (primitive VState)) + + +;; Vector Opcode Category +;; +;; These categories are used to determine the type of operands that are allowed in the +;; instruction. +(type VecOpCategory (enum + (OPIVV) + (OPFVV) + (OPMVV) + (OPIVI) + (OPIVX) + (OPFVF) + (OPMVX) + (OPCFG) +)) + +;; Vector Opcode Masking +;; +;; When masked, the instruction will only operate on the elements that are dictated by +;; the mask register. Currently this is always fixed to v0. +(type VecOpMasking (enum + (Enabled (reg Reg)) + (Disabled) +)) + +(decl pure masked (VReg) VecOpMasking) +(rule (masked reg) (VecOpMasking.Enabled reg)) + +(decl pure unmasked () VecOpMasking) +(rule (unmasked) (VecOpMasking.Disabled)) + +;; Register to Register ALU Ops +(type VecAluOpRRR (enum + ;; Vector-Vector Opcodes + (VaddVV) + (VsaddVV) + (VsadduVV) + (VwaddVV) + (VwaddWV) + (VwadduVV) + (VwadduWV) + (VsubVV) + (VwsubVV) + (VwsubWV) + (VwsubuVV) + (VwsubuWV) + (VssubVV) + (VssubuVV) + (VmulVV) + (VmulhVV) + (VmulhuVV) + (VsmulVV) + (VsllVV) + (VsrlVV) + (VsraVV) + (VandVV) + (VorVV) + (VxorVV) + (VmaxVV) + (VmaxuVV) + (VminVV) + (VminuVV) + (VfaddVV) + (VfsubVV) + (VfmulVV) + (VfdivVV) + (VfminVV) + (VfmaxVV) + (VfsgnjVV) + (VfsgnjnVV) + (VfsgnjxVV) + (VmergeVVM) + (VredmaxuVS) + (VredminuVS) + (VrgatherVV) + (VcompressVM) + (VmseqVV) + (VmsneVV) + (VmsltuVV) + (VmsltVV) + (VmsleuVV) + (VmsleVV) + (VmfeqVV) + (VmfneVV) + (VmfltVV) + (VmfleVV) + (VmandMM) + (VmorMM) + (VmnandMM) + (VmnorMM) + + + ;; Vector-Scalar Opcodes + (VaddVX) + (VsaddVX) + (VsadduVX) + (VwaddVX) + (VwaddWX) + (VwadduVX) + (VwadduWX) + (VsubVX) + (VrsubVX) + (VwsubVX) + (VwsubWX) + (VwsubuVX) + (VwsubuWX) + (VssubVX) + (VssubuVX) + (VmulVX) + (VmulhVX) + (VmulhuVX) + (VsmulVX) + (VsllVX) + (VsrlVX) + (VsraVX) + (VandVX) + (VorVX) + (VxorVX) + (VmaxVX) + (VmaxuVX) + (VminVX) + (VminuVX) + (VslidedownVX) + (VfaddVF) + (VfsubVF) + (VfrsubVF) + (VfmulVF) + (VfdivVF) + (VfsgnjVF) + (VfrdivVF) + (VmergeVXM) + (VfmergeVFM) + (VrgatherVX) + (VmseqVX) + (VmsneVX) + (VmsltuVX) + (VmsltVX) + (VmsleuVX) + (VmsleVX) + (VmsgtuVX) + (VmsgtVX) + (VmfeqVF) + (VmfneVF) + (VmfltVF) + (VmfleVF) + (VmfgtVF) + (VmfgeVF) +)) + + + +;; Register-Imm ALU Ops that modify the destination register +(type VecAluOpRRRImm5 (enum + (VslideupVI) +)) + +;; Register-Register ALU Ops that modify the destination register +(type VecAluOpRRRR (enum + ;; Vector-Vector Opcodes + (VmaccVV) + (VnmsacVV) + (VfmaccVV) + (VfnmaccVV) + (VfmsacVV) + (VfnmsacVV) + + ;; Vector-Scalar Opcodes + (VmaccVX) + (VnmsacVX) + (VfmaccVF) + (VfnmaccVF) + (VfmsacVF) + (VfnmsacVF) + (Vslide1upVX) +)) + +;; Register-Imm ALU Ops +(type VecAluOpRRImm5 (enum + ;; Regular VI Opcodes + (VaddVI) + (VsaddVI) + (VsadduVI) + (VrsubVI) + (VsllVI) + (VsrlVI) + (VsraVI) + (VandVI) + (VorVI) + (VxorVI) + (VssrlVI) + (VslidedownVI) + (VmergeVIM) + (VrgatherVI) + ;; This opcode represents multiple instructions `vmv1r`/`vmv2r`/`vmv4r`/etc... + ;; The immediate field specifies how many registers should be copied. + (VmvrV) + (VnclipWI) + (VnclipuWI) + (VmseqVI) + (VmsneVI) + (VmsleuVI) + (VmsleVI) + (VmsgtuVI) + (VmsgtVI) +)) + +;; Imm only ALU Ops +(type VecAluOpRImm5 (enum + (VmvVI) +)) + +;; These are all of the special cases that have weird encodings. They are all +;; single source, single destination instructions, and usually use one of +;; the two source registers as auxiliary encoding space. +(type VecAluOpRR (enum + (VmvSX) + (VmvXS) + (VfmvSF) + (VfmvFS) + ;; vmv.v* is special in that vs2 must be v0 (and is ignored) otherwise the instruction is illegal. + (VmvVV) + (VmvVX) + (VfmvVF) + (VfsqrtV) + (VsextVF2) + (VsextVF4) + (VsextVF8) + (VzextVF2) + (VzextVF4) + (VzextVF8) + (VfcvtxufV) + (VfcvtxfV) + (VfcvtrtzxufV) + (VfcvtrtzxfV) + (VfcvtfxuV) + (VfcvtfxV) + (VfwcvtffV) + (VfncvtffW) +)) + +;; Returns the canonical destination type for a VecAluOpRRImm5. +(decl pure vec_alu_rr_dst_type (VecAluOpRR) Type) +(extern constructor vec_alu_rr_dst_type vec_alu_rr_dst_type) + + +;; Vector Addressing Mode +(type VecAMode (enum + ;; Vector unit-stride operations access elements stored contiguously in memory + ;; starting from the base effective address. + (UnitStride + (base AMode)) + ;; TODO: Constant Stride + ;; TODO: Indexed Operations +)) + + +;; Builds a static VState matching a SIMD type. +;; The VState is guaranteed to be static with AVL set to the number of lanes. +;; Element size is set to the size of the type. +;; LMUL is set to 1. +;; Tail mode is set to agnostic. +;; Mask mode is set to agnostic. +(decl pure vstate_from_type (Type) VState) +(extern constructor vstate_from_type vstate_from_type) +(convert Type VState vstate_from_type) + +;; Alters the LMUL of a VState to mf2 +(decl pure vstate_mf2 (VState) VState) +(extern constructor vstate_mf2 vstate_mf2) + +;; Extracts an element width from a SIMD type. +(decl pure element_width_from_type (Type) VecElementWidth) +(rule (element_width_from_type ty) + (if-let $I8 (lane_type ty)) + (VecElementWidth.E8)) +(rule (element_width_from_type ty) + (if-let $I16 (lane_type ty)) + (VecElementWidth.E16)) +(rule (element_width_from_type ty) + (if-let $I32 (lane_type ty)) + (VecElementWidth.E32)) +(rule (element_width_from_type ty) + (if-let $F32 (lane_type ty)) + (VecElementWidth.E32)) +(rule (element_width_from_type ty) + (if-let $I64 (lane_type ty)) + (VecElementWidth.E64)) +(rule (element_width_from_type ty) + (if-let $F64 (lane_type ty)) + (VecElementWidth.E64)) + +(decl pure min_vec_reg_size () u64) +(extern constructor min_vec_reg_size min_vec_reg_size) + +;; An extractor that matches any type that is known to fit in a single vector +;; register. +(decl ty_vec_fits_in_register (Type) Type) +(extern extractor ty_vec_fits_in_register ty_vec_fits_in_register) + +;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; As noted in the RISC-V Vector Extension Specification, rs2 is the first +;; source register and rs1 is the second source register. This is the opposite +;; of the usual RISC-V register order. +;; See Section 10.1 of the RISC-V Vector Extension Specification. + + +;; Helper for emitting `MInst.VecAluRRRR` instructions. +;; These instructions modify the destination register. +(decl vec_alu_rrrr (VecAluOpRRRR VReg VReg Reg VecOpMasking VState) VReg) +(rule (vec_alu_rrrr op vd_src vs2 vs1 mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecAluRRRR op vd vd_src vs2 vs1 mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecAluRRRImm5` instructions. +;; These instructions modify the destination register. +(decl vec_alu_rrr_imm5 (VecAluOpRRRImm5 VReg VReg Imm5 VecOpMasking VState) VReg) +(rule (vec_alu_rrr_imm5 op vd_src vs2 imm mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecAluRRRImm5 op vd vd_src vs2 imm mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecAluRRRImm5` instructions where the immediate +;; is zero extended instead of sign extended. +(decl vec_alu_rrr_uimm5 (VecAluOpRRRImm5 VReg VReg UImm5 VecOpMasking VState) VReg) +(rule (vec_alu_rrr_uimm5 op vd_src vs2 imm mask vstate) + (vec_alu_rrr_imm5 op vd_src vs2 (uimm5_bitcast_to_imm5 imm) mask vstate)) + +;; Helper for emitting `MInst.VecAluRRR` instructions. +(decl vec_alu_rrr (VecAluOpRRR Reg Reg VecOpMasking VState) Reg) +(rule (vec_alu_rrr op vs2 vs1 mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecAluRRR op vd vs2 vs1 mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecAluRRImm5` instructions. +(decl vec_alu_rr_imm5 (VecAluOpRRImm5 Reg Imm5 VecOpMasking VState) Reg) +(rule (vec_alu_rr_imm5 op vs2 imm mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecAluRRImm5 op vd vs2 imm mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecAluRRImm5` instructions where the immediate +;; is zero extended instead of sign extended. +(decl vec_alu_rr_uimm5 (VecAluOpRRImm5 Reg UImm5 VecOpMasking VState) Reg) +(rule (vec_alu_rr_uimm5 op vs2 imm mask vstate) + (vec_alu_rr_imm5 op vs2 (uimm5_bitcast_to_imm5 imm) mask vstate)) + +;; Helper for emitting `MInst.VecAluRRImm5` instructions that use the Imm5 as +;; auxiliary encoding space. +(decl vec_alu_rr (VecAluOpRR Reg VecOpMasking VState) Reg) +(rule (vec_alu_rr op vs mask vstate) + (let ((vd WritableReg (temp_writable_reg (vec_alu_rr_dst_type op))) + (_ Unit (emit (MInst.VecAluRR op vd vs mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecAluRImm5` instructions. +(decl vec_alu_r_imm5 (VecAluOpRImm5 Imm5 VecOpMasking VState) Reg) +(rule (vec_alu_r_imm5 op imm mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecAluRImm5 op vd imm mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecLoad` instructions. +(decl vec_load (VecElementWidth VecAMode MemFlags VecOpMasking VState) Reg) +(rule (vec_load eew from flags mask vstate) + (let ((vd WritableVReg (temp_writable_vreg)) + (_ Unit (emit (MInst.VecLoad eew vd from flags mask vstate)))) + vd)) + +;; Helper for emitting `MInst.VecStore` instructions. +(decl vec_store (VecElementWidth VecAMode VReg MemFlags VecOpMasking VState) InstOutput) +(rule (vec_store eew to from flags mask vstate) + (side_effect + (SideEffectNoResult.Inst (MInst.VecStore eew to from flags mask vstate)))) + +;; Helper for emitting the `vadd.vv` instruction. +(decl rv_vadd_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vadd_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VaddVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vadd.vx` instruction. +(decl rv_vadd_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vadd_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VaddVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vadd.vi` instruction. +(decl rv_vadd_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vadd_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VaddVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vsadd.vv` instruction. +(decl rv_vsadd_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsadd_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsaddVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsadd.vx` instruction. +(decl rv_vsadd_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsadd_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsaddVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsadd.vi` instruction. +(decl rv_vsadd_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vsadd_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VsaddVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vsaddu.vv` instruction. +(decl rv_vsaddu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsaddu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsadduVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsaddu.vx` instruction. +(decl rv_vsaddu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsaddu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsadduVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsaddu.vi` instruction. +(decl rv_vsaddu_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vsaddu_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VsadduVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vwadd.vv` instruction. +;; +;; Widening integer add, 2*SEW = SEW + SEW +(decl rv_vwadd_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwadd_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwaddVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwadd.vx` instruction. +;; +;; Widening integer add, 2*SEW = SEW + SEW +(decl rv_vwadd_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwadd_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwaddVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwadd.wv` instruction. +;; +;; Widening integer add, 2*SEW = 2*SEW + SEW +(decl rv_vwadd_wv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwadd_wv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwaddWV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwadd.wx` instruction. +;; +;; Widening integer add, 2*SEW = 2*SEW + SEW +(decl rv_vwadd_wx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwadd_wx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwaddWX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwaddu.vv` instruction. +;; +;; Widening unsigned integer add, 2*SEW = SEW + SEW +(decl rv_vwaddu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwaddu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwadduVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwaddu.vv` instruction. +;; +;; Widening unsigned integer add, 2*SEW = SEW + SEW +(decl rv_vwaddu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwaddu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwadduVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwaddu.wv` instruction. +;; +;; Widening integer add, 2*SEW = 2*SEW + SEW +(decl rv_vwaddu_wv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwaddu_wv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwadduWV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwaddu.wx` instruction. +;; +;; Widening integer add, 2*SEW = 2*SEW + SEW +(decl rv_vwaddu_wx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwaddu_wx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwadduWX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsub.vv` instruction. +(decl rv_vsub_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsub_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsubVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsub.vx` instruction. +(decl rv_vsub_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsub_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsubVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vrsub.vx` instruction. +(decl rv_vrsub_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vrsub_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VrsubVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsub.vv` instruction. +;; +;; Widening integer sub, 2*SEW = SEW + SEW +(decl rv_vwsub_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwsub_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsub.vx` instruction. +;; +;; Widening integer sub, 2*SEW = SEW + SEW +(decl rv_vwsub_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwsub_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsub.wv` instruction. +;; +;; Widening integer sub, 2*SEW = 2*SEW + SEW +(decl rv_vwsub_wv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwsub_wv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubWV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsub.wx` instruction. +;; +;; Widening integer sub, 2*SEW = 2*SEW + SEW +(decl rv_vwsub_wx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwsub_wx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubWX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsubu.vv` instruction. +;; +;; Widening unsigned integer sub, 2*SEW = SEW + SEW +(decl rv_vwsubu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwsubu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsubu.vv` instruction. +;; +;; Widening unsigned integer sub, 2*SEW = SEW + SEW +(decl rv_vwsubu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwsubu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsubu.wv` instruction. +;; +;; Widening integer sub, 2*SEW = 2*SEW + SEW +(decl rv_vwsubu_wv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vwsubu_wv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubuWV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vwsubu.wx` instruction. +;; +;; Widening integer sub, 2*SEW = 2*SEW + SEW +(decl rv_vwsubu_wx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vwsubu_wx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VwsubuWX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vssub.vv` instruction. +(decl rv_vssub_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vssub_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VssubVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vssub.vx` instruction. +(decl rv_vssub_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vssub_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VssubVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vssubu.vv` instruction. +(decl rv_vssubu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vssubu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VssubuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vssubu.vx` instruction. +(decl rv_vssubu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vssubu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VssubuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vneg.v` pseudo-instruction. +(decl rv_vneg_v (VReg VecOpMasking VState) VReg) +(rule (rv_vneg_v vs2 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VrsubVX) vs2 (zero_reg) mask vstate)) + +;; Helper for emitting the `vrsub.vi` instruction. +(decl rv_vrsub_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vrsub_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VrsubVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmul.vv` instruction. +(decl rv_vmul_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmul_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmul.vx` instruction. +(decl rv_vmul_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmul_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmulh.vv` instruction. +(decl rv_vmulh_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmulh_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulhVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmulh.vx` instruction. +(decl rv_vmulh_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmulh_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulhVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmulhu.vv` instruction. +(decl rv_vmulhu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmulhu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulhuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmulhu.vx` instruction. +(decl rv_vmulhu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmulhu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmulhuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsmul.vv` instruction. +;; +;; Signed saturating and rounding fractional multiply +;; # vd[i] = clip(roundoff_signed(vs2[i]*vs1[i], SEW-1)) +(decl rv_vsmul_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsmul_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsmulVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsmul.vx` instruction. +;; +;; Signed saturating and rounding fractional multiply +;; # vd[i] = clip(roundoff_signed(vs2[i]*x[rs1], SEW-1)) +(decl rv_vsmul_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsmul_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsmulVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmacc.vv` instruction. +;; +;; Integer multiply-add, overwrite addend +;; # vd[i] = +(vs1[i] * vs2[i]) + vd[i] +(decl rv_vmacc_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmacc_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VmaccVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmacc.vx` instruction. +;; +;; Integer multiply-add, overwrite addend +;; # vd[i] = +(x[rs1] * vs2[i]) + vd[i] +(decl rv_vmacc_vx (VReg VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmacc_vx vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VmaccVX) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vnmsac.vv` instruction. +;; +;; Integer multiply-sub, overwrite minuend +;; # vd[i] = -(vs1[i] * vs2[i]) + vd[i] +(decl rv_vnmsac_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vnmsac_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VnmsacVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vnmsac.vx` instruction. +;; +;; Integer multiply-sub, overwrite minuend +;; # vd[i] = -(x[rs1] * vs2[i]) + vd[i] +(decl rv_vnmsac_vx (VReg VReg XReg VecOpMasking VState) VReg) +(rule (rv_vnmsac_vx vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VnmsacVX) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `sll.vv` instruction. +(decl rv_vsll_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsll_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsllVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `sll.vx` instruction. +(decl rv_vsll_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsll_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsllVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsll.vi` instruction. +(decl rv_vsll_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vsll_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VsllVI) vs2 imm mask vstate)) + +;; Helper for emitting the `srl.vv` instruction. +(decl rv_vsrl_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsrl_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsrlVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `srl.vx` instruction. +(decl rv_vsrl_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsrl_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsrlVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsrl.vi` instruction. +(decl rv_vsrl_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vsrl_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VsrlVI) vs2 imm mask vstate)) + +;; Helper for emitting the `sra.vv` instruction. +(decl rv_vsra_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vsra_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsraVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `sra.vx` instruction. +(decl rv_vsra_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vsra_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VsraVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vsra.vi` instruction. +(decl rv_vsra_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vsra_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VsraVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vand.vv` instruction. +(decl rv_vand_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vand_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VandVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vand.vx` instruction. +(decl rv_vand_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vand_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VandVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vand.vi` instruction. +(decl rv_vand_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vand_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VandVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vor.vv` instruction. +(decl rv_vor_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vor_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VorVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vor.vx` instruction. +(decl rv_vor_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vor_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VorVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vor.vi` instruction. +(decl rv_vor_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vor_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VorVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vxor.vv` instruction. +(decl rv_vxor_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vxor_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VxorVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vxor.vx` instruction. +(decl rv_vxor_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vxor_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VxorVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vxor.vi` instruction. +(decl rv_vxor_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vxor_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VxorVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vssrl.vi` instruction. +;; +;; vd[i] = (unsigned(vs2[i]) >> imm) + r +;; +;; `r` here is the rounding mode currently selected. +(decl rv_vssrl_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vssrl_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VssrlVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vnot.v` instruction. +;; This is just a mnemonic for `vxor.vi vd, vs, -1` +(decl rv_vnot_v (VReg VecOpMasking VState) VReg) +(rule (rv_vnot_v vs2 mask vstate) + (if-let neg1 (i8_to_imm5 -1)) + (rv_vxor_vi vs2 neg1 mask vstate)) + +;; Helper for emitting the `vmax.vv` instruction. +(decl rv_vmax_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmax_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmaxVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmax.vx` instruction. +(decl rv_vmax_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmax_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmaxVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmin.vv` instruction. +(decl rv_vmin_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmin_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VminVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmin.vx` instruction. +(decl rv_vmin_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmin_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VminVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmaxu.vv` instruction. +(decl rv_vmaxu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmaxu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmaxuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmaxu.vx` instruction. +(decl rv_vmaxu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmaxu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmaxuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vminu.vv` instruction. +(decl rv_vminu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vminu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VminuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vminu.vx` instruction. +(decl rv_vminu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vminu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VminuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfadd.vv` instruction. +(decl rv_vfadd_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfadd_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfaddVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfadd.vf` instruction. +(decl rv_vfadd_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfadd_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfaddVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfsub.vv` instruction. +(decl rv_vfsub_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfsub_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsubVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfsub.vf` instruction. +(decl rv_vfsub_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfsub_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsubVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfrsub.vf` instruction. +(decl rv_vfrsub_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfrsub_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfrsubVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmul.vv` instruction. +(decl rv_vfmul_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfmul_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfmulVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmul.vf` instruction. +(decl rv_vfmul_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfmul_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfmulVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmacc.vv` instruction. +;; +;; FP multiply-accumulate, overwrites addend +;; # vd[i] = +(vs1[i] * vs2[i]) + vd[i] +(decl rv_vfmacc_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfmacc_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfmaccVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmacc.vf` instruction. +;; +;; FP multiply-accumulate, overwrites addend +;; # vd[i] = +(f[rs1] * vs2[i]) + vd[i] +(decl rv_vfmacc_vf (VReg VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfmacc_vf vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfmaccVF) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfnmacc.vv` instruction. +;; +;; FP negate-(multiply-accumulate), overwrites subtrahend +;; # vd[i] = -(vs1[i] * vs2[i]) - vd[i] +(decl rv_vfnmacc_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfnmacc_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfnmaccVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfnmacc.vf` instruction. +;; +;; FP negate-(multiply-accumulate), overwrites subtrahend +;; # vd[i] = -(f[rs1] * vs2[i]) - vd[i] +(decl rv_vfnmacc_vf (VReg VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfnmacc_vf vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfnmaccVF) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmsac.vv` instruction. +;; +;; FP multiply-subtract-accumulator, overwrites subtrahend +;; # vd[i] = +(vs1[i] * vs2[i]) - vd[i] +(decl rv_vfmsac_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfmsac_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfmsacVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmsac.vf` instruction. +;; +;; FP multiply-subtract-accumulator, overwrites subtrahend +;; # vd[i] = +(f[rs1] * vs2[i]) - vd[i] +(decl rv_vfmsac_vf (VReg VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfmsac_vf vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfmsacVF) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfnmsac.vv` instruction. +;; +;; FP negate-(multiply-subtract-accumulator), overwrites minuend +;; # vd[i] = -(vs1[i] * vs2[i]) + vd[i] +(decl rv_vfnmsac_vv (VReg VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfnmsac_vv vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfnmsacVV) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfnmsac.vf` instruction. +;; +;; FP negate-(multiply-subtract-accumulator), overwrites minuend +;; # vd[i] = -(f[rs1] * vs2[i]) + vd[i] +(decl rv_vfnmsac_vf (VReg VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfnmsac_vf vd vs2 vs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.VfnmsacVF) vd vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfdiv.vv` instruction. +(decl rv_vfdiv_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfdiv_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfdivVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfdiv.vf` instruction. +(decl rv_vfdiv_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfdiv_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfdivVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfrdiv.vf` instruction. +(decl rv_vfrdiv_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfrdiv_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfrdivVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmin.vv` instruction. +(decl rv_vfmin_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfmin_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfminVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfmax.vv` instruction. +(decl rv_vfmax_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfmax_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfmaxVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfsgnj.vv` ("Floating Point Sign Injection") instruction. +;; The output of this instruction is `vs2` with the sign bit from `vs1` +(decl rv_vfsgnj_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfsgnj_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsgnjVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfsgnj.vf` ("Floating Point Sign Injection") instruction. +(decl rv_vfsgnj_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vfsgnj_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsgnjVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfsgnjn.vv` ("Floating Point Sign Injection Negated") instruction. +;; The output of this instruction is `vs2` with the negated sign bit from `vs1` +(decl rv_vfsgnjn_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfsgnjn_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsgnjnVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfneg.v` instruction. +;; This instruction is a mnemonic for `vfsgnjn.vv vd, vs, vs` +(decl rv_vfneg_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfneg_v vs mask vstate) (rv_vfsgnjn_vv vs vs mask vstate)) + +;; Helper for emitting the `vfsgnjx.vv` ("Floating Point Sign Injection Exclusive") instruction. +;; The output of this instruction is `vs2` with the XOR of the sign bits from `vs2` and `vs1`. +;; When `vs2 == vs1` this implements `fabs` +(decl rv_vfsgnjx_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vfsgnjx_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfsgnjxVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vfabs.v` instruction. +;; This instruction is a mnemonic for `vfsgnjx.vv vd, vs, vs` +(decl rv_vfabs_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfabs_v vs mask vstate) (rv_vfsgnjx_vv vs vs mask vstate)) + +;; Helper for emitting the `vfsqrt.v` instruction. +;; This instruction splats the F register into all elements of the destination vector. +(decl rv_vfsqrt_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfsqrt_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfsqrtV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.xu.f.v` instruction. +;; This instruction converts a float to an unsigned integer. +(decl rv_vfcvt_xu_f_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_xu_f_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtxufV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.x.f.v` instruction. +;; This instruction converts a float to a signed integer. +(decl rv_vfcvt_x_f_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_x_f_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtxfV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.rtz.xu.f.v` instruction. +;; This instruction converts a float to an unsigned integer +;; using the Round to Zero (RTZ) rounding mode and ignoring +;; the currently set FRM rounding mode. +(decl rv_vfcvt_rtz_xu_f_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_rtz_xu_f_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtrtzxufV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.rtz.x.f.v` instruction. +;; This instruction converts a float to a signed integer. +;; using the Round to Zero (RTZ) rounding mode and ignoring +;; the currently set FRM rounding mode. +(decl rv_vfcvt_rtz_x_f_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_rtz_x_f_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtrtzxfV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.f.xu.v` instruction. +;; This instruction converts a unsigned integer to a float. +(decl rv_vfcvt_f_xu_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_f_xu_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtfxuV) vs mask vstate)) + +;; Helper for emitting the `vfcvt.x.f.v` instruction. +;; This instruction converts a signed integer to a float. +(decl rv_vfcvt_f_x_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfcvt_f_x_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfcvtfxV) vs mask vstate)) + + ;; Helper for emitting the `vfwcvt.f.f.v` instruction. +;; Convert single-width float to double-width float. +(decl rv_vfwcvt_f_f_v (VReg VecOpMasking VState) VReg) +(rule (rv_vfwcvt_f_f_v vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfwcvtffV) vs mask vstate)) + +;; Helper for emitting the `vfncvt.f.f.w` instruction. +;; Convert double-width float to single-width float. +(decl rv_vfncvt_f_f_w (VReg VecOpMasking VState) VReg) +(rule (rv_vfncvt_f_f_w vs mask vstate) + (vec_alu_rr (VecAluOpRR.VfncvtffW) vs mask vstate)) + +;; Helper for emitting the `vslidedown.vx` instruction. +;; `vslidedown` moves all elements in the vector down by n elements. +;; The top most elements are up to the tail policy. +(decl rv_vslidedown_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vslidedown_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VslidedownVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vslidedown.vi` instruction. +;; Unlike other `vi` instructions the immediate is zero extended. +(decl rv_vslidedown_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vslidedown_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VslidedownVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vslideup.vi` instruction. +;; Unlike other `vi` instructions the immediate is zero extended. +;; This is implemented as a 2 source operand instruction, since it only +;; partially modifies the destination register. +(decl rv_vslideup_vvi (VReg VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vslideup_vvi vd vs2 imm mask vstate) + (vec_alu_rrr_uimm5 (VecAluOpRRRImm5.VslideupVI) vd vs2 imm mask vstate)) + +;; Helper for emitting the `vslide1up.vx` instruction. +;; +;; # vd[0]=x[rs1], vd[i+1] = vs2[i] +(decl rv_vslide1up_vx (VReg VReg XReg VecOpMasking VState) VReg) +(rule (rv_vslide1up_vx vd vs2 rs1 mask vstate) + (vec_alu_rrrr (VecAluOpRRRR.Vslide1upVX) vd vs2 rs1 mask vstate)) + +;; Helper for emitting the `vmv.x.s` instruction. +;; This instruction copies the first element of the source vector to the destination X register. +;; Masked versions of this instruction are not supported. +(decl rv_vmv_xs (VReg VState) XReg) +(rule (rv_vmv_xs vs vstate) + (vec_alu_rr (VecAluOpRR.VmvXS) vs (unmasked) vstate)) + +;; Helper for emitting the `vfmv.f.s` instruction. +;; This instruction copies the first element of the source vector to the destination F register. +;; Masked versions of this instruction are not supported. +(decl rv_vfmv_fs (VReg VState) FReg) +(rule (rv_vfmv_fs vs vstate) + (vec_alu_rr (VecAluOpRR.VfmvFS) vs (unmasked) vstate)) + +;; Helper for emitting the `vmv.s.x` instruction. +;; This instruction copies the source X register into first element of the source vector. +;; Masked versions of this instruction are not supported. +(decl rv_vmv_sx (XReg VState) VReg) +(rule (rv_vmv_sx vs vstate) + (vec_alu_rr (VecAluOpRR.VmvSX) vs (unmasked) vstate)) + +;; Helper for emitting the `vfmv.s.f` instruction. +;; This instruction copies the source F register into first element of the source vector. +;; Masked versions of this instruction are not supported. +(decl rv_vfmv_sf (FReg VState) VReg) +(rule (rv_vfmv_sf vs vstate) + (vec_alu_rr (VecAluOpRR.VfmvSF) vs (unmasked) vstate)) + +;; Helper for emitting the `vmv.v.x` instruction. +;; This instruction splats the X register into all elements of the destination vector. +;; Masked versions of this instruction are called `vmerge` +(decl rv_vmv_vx (XReg VState) VReg) +(rule (rv_vmv_vx vs vstate) + (vec_alu_rr (VecAluOpRR.VmvVX) vs (unmasked) vstate)) + +;; Helper for emitting the `vfmv.v.f` instruction. +;; This instruction splats the F register into all elements of the destination vector. +;; Masked versions of this instruction are called `vmerge` +(decl rv_vfmv_vf (FReg VState) VReg) +(rule (rv_vfmv_vf vs vstate) + (vec_alu_rr (VecAluOpRR.VfmvVF) vs (unmasked) vstate)) + +;; Helper for emitting the `vmv.v.i` instruction. +;; This instruction splat's the immediate value into all elements of the destination vector. +;; Masked versions of this instruction are called `vmerge` +(decl rv_vmv_vi (Imm5 VState) VReg) +(rule (rv_vmv_vi imm vstate) + (vec_alu_r_imm5 (VecAluOpRImm5.VmvVI) imm (unmasked) vstate)) + +;; Helper for emitting the `vmerge.vvm` instruction. +;; This instruction merges the elements of the two source vectors into the destination vector +;; based on a mask. Elements are taken from the first source vector if the mask bit is clear, +;; and from the second source vector if the mask bit is set. This instruction is always masked. +;; +;; vd[i] = v0.mask[i] ? vs1[i] : vs2[i] +(decl rv_vmerge_vvm (VReg VReg VReg VState) VReg) +(rule (rv_vmerge_vvm vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmergeVVM) vs2 vs1 (masked mask) vstate)) + +;; Helper for emitting the `vmerge.vxm` instruction. +;; Elements are taken from the first source vector if the mask bit is clear, and from the X +;; register if the mask bit is set. This instruction is always masked. +;; +;; vd[i] = v0.mask[i] ? x[rs1] : vs2[i] +(decl rv_vmerge_vxm (VReg XReg VReg VState) VReg) +(rule (rv_vmerge_vxm vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmergeVXM) vs2 vs1 (masked mask) vstate)) + +;; Helper for emitting the `vfmerge.vfm` instruction. +;; Elements are taken from the first source vector if the mask bit is clear, and from the F +;; register if the mask bit is set. This instruction is always masked. +;; +;; vd[i] = v0.mask[i] ? f[rs1] : vs2[i] +(decl rv_vfmerge_vfm (VReg FReg VReg VState) VReg) +(rule (rv_vfmerge_vfm vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VfmergeVFM) vs2 vs1 (masked mask) vstate)) + +;; Helper for emitting the `vmerge.vim` instruction. +;; Elements are taken from the first source vector if the mask bit is clear, and from the +;; immediate value if the mask bit is set. This instruction is always masked. +;; +;; vd[i] = v0.mask[i] ? imm : vs2[i] +(decl rv_vmerge_vim (VReg Imm5 VReg VState) VReg) +(rule (rv_vmerge_vim vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmergeVIM) vs2 imm (masked mask) vstate)) + + +;; Helper for emitting the `vredminu.vs` instruction. +;; +;; vd[0] = minu( vs1[0] , vs2[*] ) +(decl rv_vredminu_vs (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vredminu_vs vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VredminuVS) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vredmaxu.vs` instruction. +;; +;; vd[0] = maxu( vs1[0] , vs2[*] ) +(decl rv_vredmaxu_vs (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vredmaxu_vs vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VredmaxuVS) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vrgather.vv` instruction. +;; +;; vd[i] = (vs1[i] >= VLMAX) ? 0 : vs2[vs1[i]]; +(decl rv_vrgather_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vrgather_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VrgatherVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vrgather.vx` instruction. +;; +;; vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[x[rs1]] +(decl rv_vrgather_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vrgather_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VrgatherVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vrgather.vi` instruction. +(decl rv_vrgather_vi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vrgather_vi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VrgatherVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vcompress.vm` instruction. +;; +;; The vector compress instruction allows elements selected by a vector mask +;; register from a source vector register group to be packed into contiguous +;; elements at the start of the destination vector register group. +;; +;; The mask register is specified through vs1 +(decl rv_vcompress_vm (VReg VReg VState) VReg) +(rule (rv_vcompress_vm vs2 vs1 vstate) + (vec_alu_rrr (VecAluOpRRR.VcompressVM) vs2 vs1 (unmasked) vstate)) + +;; Helper for emitting the `vmseq.vv` (Vector Mask Set If Equal) instruction. +(decl rv_vmseq_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmseq_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmseqVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmseq.vx` (Vector Mask Set If Equal) instruction. +(decl rv_vmseq_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmseq_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmseqVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmseq.vi` (Vector Mask Set If Equal) instruction. +(decl rv_vmseq_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmseq_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmseqVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsne.vv` (Vector Mask Set If Not Equal) instruction. +(decl rv_vmsne_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsne_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsneVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsne.vx` (Vector Mask Set If Not Equal) instruction. +(decl rv_vmsne_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsne_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsneVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsne.vi` (Vector Mask Set If Not Equal) instruction. +(decl rv_vmsne_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmsne_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmsneVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsltu.vv` (Vector Mask Set If Less Than, Unsigned) instruction. +(decl rv_vmsltu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsltu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsltuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsltu.vx` (Vector Mask Set If Less Than, Unsigned) instruction. +(decl rv_vmsltu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsltu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsltuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmslt.vv` (Vector Mask Set If Less Than) instruction. +(decl rv_vmslt_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmslt_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsltVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmslt.vx` (Vector Mask Set If Less Than) instruction. +(decl rv_vmslt_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmslt_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsltVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsleu.vv` (Vector Mask Set If Less Than or Equal, Unsigned) instruction. +(decl rv_vmsleu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsleu_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsleuVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsleu.vx` (Vector Mask Set If Less Than or Equal, Unsigned) instruction. +(decl rv_vmsleu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsleu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsleuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsleu.vi` (Vector Mask Set If Less Than or Equal, Unsigned) instruction. +(decl rv_vmsleu_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmsleu_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmsleuVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsle.vv` (Vector Mask Set If Less Than or Equal) instruction. +(decl rv_vmsle_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsle_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsleVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsle.vx` (Vector Mask Set If Less Than or Equal) instruction. +(decl rv_vmsle_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsle_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsleVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsle.vi` (Vector Mask Set If Less Than or Equal) instruction. +(decl rv_vmsle_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmsle_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmsleVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsgt.vv` (Vector Mask Set If Greater Than, Unsigned) instruction. +;; This is an alias for `vmsltu.vv` with the operands inverted. +(decl rv_vmsgtu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsgtu_vv vs2 vs1 mask vstate) (rv_vmsltu_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmsgtu.vx` (Vector Mask Set If Greater Than, Unsigned) instruction. +(decl rv_vmsgtu_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsgtu_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsgtuVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsgtu.vi` (Vector Mask Set If Greater Than, Unsigned) instruction. +(decl rv_vmsgtu_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmsgtu_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmsgtuVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsgt.vv` (Vector Mask Set If Greater Than) instruction. +;; This is an alias for `vmslt.vv` with the operands inverted. +(decl rv_vmsgt_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsgt_vv vs2 vs1 mask vstate) (rv_vmslt_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmsgt.vx` (Vector Mask Set If Greater Than) instruction. +(decl rv_vmsgt_vx (VReg XReg VecOpMasking VState) VReg) +(rule (rv_vmsgt_vx vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmsgtVX) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmsgt.vi` (Vector Mask Set If Greater Than) instruction. +(decl rv_vmsgt_vi (VReg Imm5 VecOpMasking VState) VReg) +(rule (rv_vmsgt_vi vs2 imm mask vstate) + (vec_alu_rr_imm5 (VecAluOpRRImm5.VmsgtVI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmsgeu.vv` (Vector Mask Set If Greater Than or Equal, Unsigned) instruction. +;; This is an alias for `vmsleu.vv` with the operands inverted. +(decl rv_vmsgeu_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsgeu_vv vs2 vs1 mask vstate) (rv_vmsleu_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmsge.vv` (Vector Mask Set If Greater Than or Equal) instruction. +;; This is an alias for `vmsle.vv` with the operands inverted. +(decl rv_vmsge_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmsge_vv vs2 vs1 mask vstate) (rv_vmsle_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmfeq.vv` (Vector Mask Set If Float Equal) instruction. +(decl rv_vmfeq_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmfeq_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfeqVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfeq.vf` (Vector Mask Set If Float Equal) instruction. +(decl rv_vmfeq_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmfeq_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfeqVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfne.vv` (Vector Mask Set If Float Not Equal) instruction. +(decl rv_vmfne_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmfne_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfneVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfne.vf` (Vector Mask Set If Float Not Equal) instruction. +(decl rv_vmfne_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmfne_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfneVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmflt.vv` (Vector Mask Set If Float Less Than) instruction. +(decl rv_vmflt_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmflt_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfltVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmflt.vf` (Vector Mask Set If Float Less Than) instruction. +(decl rv_vmflt_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmflt_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfltVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfle.vv` (Vector Mask Set If Float Less Than Or Equal) instruction. +(decl rv_vmfle_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmfle_vv vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfleVV) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfle.vf` (Vector Mask Set If Float Less Than Or Equal) instruction. +(decl rv_vmfle_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmfle_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfleVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfgt.vv` (Vector Mask Set If Float Greater Than) instruction. +;; This is an alias for `vmflt.vv` with the operands inverted. +(decl rv_vmfgt_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmfgt_vv vs2 vs1 mask vstate) (rv_vmflt_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmfgt.vf` (Vector Mask Set If Float Greater Than) instruction. +(decl rv_vmfgt_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmfgt_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfgtVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vmfge.vv` (Vector Mask Set If Float Greater Than Or Equal) instruction. +;; This is an alias for `vmfle.vv` with the operands inverted. +(decl rv_vmfge_vv (VReg VReg VecOpMasking VState) VReg) +(rule (rv_vmfge_vv vs2 vs1 mask vstate) (rv_vmfle_vv vs1 vs2 mask vstate)) + +;; Helper for emitting the `vmfge.vf` (Vector Mask Set If Float Greater Than Or Equal) instruction. +(decl rv_vmfge_vf (VReg FReg VecOpMasking VState) VReg) +(rule (rv_vmfge_vf vs2 vs1 mask vstate) + (vec_alu_rrr (VecAluOpRRR.VmfgeVF) vs2 vs1 mask vstate)) + +;; Helper for emitting the `vzext.vf2` instruction. +;; Zero-extend SEW/2 source to SEW destination +(decl rv_vzext_vf2 (VReg VecOpMasking VState) VReg) +(rule (rv_vzext_vf2 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VzextVF2) vs mask vstate)) + +;; Helper for emitting the `vzext.vf4` instruction. +;; Zero-extend SEW/4 source to SEW destination +(decl rv_vzext_vf4 (VReg VecOpMasking VState) VReg) +(rule (rv_vzext_vf4 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VzextVF4) vs mask vstate)) + +;; Helper for emitting the `vzext.vf8` instruction. +;; Zero-extend SEW/8 source to SEW destination +(decl rv_vzext_vf8 (VReg VecOpMasking VState) VReg) +(rule (rv_vzext_vf8 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VzextVF8) vs mask vstate)) + +;; Helper for emitting the `vsext.vf2` instruction. +;; Sign-extend SEW/2 source to SEW destination +(decl rv_vsext_vf2 (VReg VecOpMasking VState) VReg) +(rule (rv_vsext_vf2 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VsextVF2) vs mask vstate)) + +;; Helper for emitting the `vsext.vf4` instruction. +;; Sign-extend SEW/4 source to SEW destination +(decl rv_vsext_vf4 (VReg VecOpMasking VState) VReg) +(rule (rv_vsext_vf4 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VsextVF4) vs mask vstate)) + +;; Helper for emitting the `vsext.vf8` instruction. +;; Sign-extend SEW/8 source to SEW destination +(decl rv_vsext_vf8 (VReg VecOpMasking VState) VReg) +(rule (rv_vsext_vf8 vs mask vstate) + (vec_alu_rr (VecAluOpRR.VsextVF8) vs mask vstate)) + +;; Helper for emitting the `vnclip.wi` instruction. +;; +;; vd[i] = clip(roundoff_signed(vs2[i], uimm)) +(decl rv_vnclip_wi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vnclip_wi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VnclipWI) vs2 imm mask vstate)) + +;; Helper for emitting the `vnclipu.wi` instruction. +;; +;; vd[i] = clip(roundoff_unsigned(vs2[i], uimm)) +(decl rv_vnclipu_wi (VReg UImm5 VecOpMasking VState) VReg) +(rule (rv_vnclipu_wi vs2 imm mask vstate) + (vec_alu_rr_uimm5 (VecAluOpRRImm5.VnclipuWI) vs2 imm mask vstate)) + +;; Helper for emitting the `vmand.mm` (Mask Bitwise AND) instruction. +;; +;; vd.mask[i] = vs2.mask[i] && vs1.mask[i] +(decl rv_vmand_mm (VReg VReg VState) VReg) +(rule (rv_vmand_mm vs2 vs1 vstate) + (vec_alu_rrr (VecAluOpRRR.VmandMM) vs2 vs1 (unmasked) vstate)) + +;; Helper for emitting the `vmor.mm` (Mask Bitwise OR) instruction. +;; +;; vd.mask[i] = vs2.mask[i] || vs1.mask[i] +(decl rv_vmor_mm (VReg VReg VState) VReg) +(rule (rv_vmor_mm vs2 vs1 vstate) + (vec_alu_rrr (VecAluOpRRR.VmorMM) vs2 vs1 (unmasked) vstate)) + +;; Helper for emitting the `vmnand.mm` (Mask Bitwise NAND) instruction. +;; +;; vd.mask[i] = !(vs2.mask[i] && vs1.mask[i]) +(decl rv_vmnand_mm (VReg VReg VState) VReg) +(rule (rv_vmnand_mm vs2 vs1 vstate) + (vec_alu_rrr (VecAluOpRRR.VmnandMM) vs2 vs1 (unmasked) vstate)) + +;; Helper for emitting the `vmnot.m` (Mask Bitwise NOT) instruction. +;; This is an alias for `vmnand.mm vd, vs, vs` +;; +;; vd.mask[i] = !vs.mask[i] +(decl rv_vmnot_m (VReg VState) VReg) +(rule (rv_vmnot_m vs vstate) (rv_vmnand_mm vs vs vstate)) + +;; Helper for emitting the `vmnor.mm` (Mask Bitwise NOR) instruction. +;; +;; vd.mask[i] = !(vs2.mask[i] || vs1.mask[i]) +(decl rv_vmnor_mm (VReg VReg VState) VReg) +(rule (rv_vmnor_mm vs2 vs1 vstate) + (vec_alu_rrr (VecAluOpRRR.VmnorMM) vs2 vs1 (unmasked) vstate)) + +;;;; Multi-Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_extractlane (Type VReg u8) Reg) + +;; When extracting lane 0 for floats, we can use `vfmv.f.s` directly. +(rule 3 (gen_extractlane (ty_vec_fits_in_register ty) src 0) + (if (ty_vector_float ty)) + (rv_vfmv_fs src ty)) + +;; When extracting lane 0 for integers, we can use `vmv.x.s` directly. +(rule 2 (gen_extractlane (ty_vec_fits_in_register ty) src 0) + (if (ty_vector_not_float ty)) + (rv_vmv_xs src ty)) + +;; In the general case, we must first use a `vslidedown` to place the correct lane +;; in index 0, and then use the appropriate `vmv` instruction. +;; If the index fits into a 5-bit immediate, we can emit a `vslidedown.vi`. +(rule 1 (gen_extractlane (ty_vec_fits_in_register ty) src (uimm5_from_u8 idx)) + (gen_extractlane ty (rv_vslidedown_vi src idx (unmasked) ty) 0)) + +;; Otherwise lower it into an X register. +(rule 0 (gen_extractlane (ty_vec_fits_in_register ty) src idx) + (gen_extractlane ty (rv_vslidedown_vx src (imm $I64 idx) (unmasked) ty) 0)) + + +;; Build a vector mask from a u64 +;; TODO(#6571): We should merge this with the `vconst` rules, and take advantage of +;; the other existing `vconst` rules. +(decl gen_vec_mask (u64) VReg) + +;; When the immediate fits in a 5-bit immediate, we can use `vmv.v.i` directly. +(rule 1 (gen_vec_mask (imm5_from_u64 imm)) + (rv_vmv_vi imm (vstate_from_type $I64X2))) + +;; Materialize the mask into an X register, and move it into the bottom of +;; the vector register. +(rule 0 (gen_vec_mask mask) + (rv_vmv_sx (imm $I64 mask) (vstate_from_type $I64X2))) + + +;; Loads a `VCodeConstant` value into a vector register. For some special `VCodeConstant`s +;; we can use a dedicated instruction, otherwise we load the value from the pool. +;; +;; Type is the preferred type to use when loading the constant. +(decl gen_constant (Type VCodeConstant) VReg) + +;; The fallback case is to load the constant from the pool. +(rule (gen_constant ty n) + (vec_load + (element_width_from_type ty) + (VecAMode.UnitStride (gen_const_amode n)) + (mem_flags_trusted) + (unmasked) + ty)) + + +;; Emits a vslidedown instruction that moves half the lanes down. +(decl gen_slidedown_half (Type VReg) VReg) + +;; If the lane count can fit in a 5-bit immediate, we can use `vslidedown.vi`. +(rule 1 (gen_slidedown_half (ty_vec_fits_in_register ty) src) + (if-let (uimm5_from_u64 amt) (u64_udiv (ty_lane_count ty) 2)) + (rv_vslidedown_vi src amt (unmasked) ty)) + +;; Otherwise lower it into an X register. +(rule 0 (gen_slidedown_half (ty_vec_fits_in_register ty) src) + (if-let amt (u64_udiv (ty_lane_count ty) 2)) + (rv_vslidedown_vx src (imm $I64 amt) (unmasked) ty)) + + +;; Expands a mask into SEW wide lanes. Enabled lanes are set to all ones, disabled +;; lanes are set to all zeros. +(decl gen_expand_mask (Type VReg) VReg) +(rule (gen_expand_mask ty mask) + (if-let zero (i8_to_imm5 0)) + (if-let neg1 (i8_to_imm5 -1)) + (rv_vmerge_vim (rv_vmv_vi zero ty) neg1 mask ty)) + + +;; Builds a vector mask corresponding to the IntCC operation. +;; TODO: We are still missing some rules here for immediates. See #6623 +(decl gen_icmp_mask (Type IntCC Value Value) VReg) + +;; IntCC.Equal + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.Equal) x y) + (rv_vmseq_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.Equal) x (splat y)) + (rv_vmseq_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.Equal) (splat x) y) + (rv_vmseq_vx y x (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.Equal) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmseq_vi x y_imm (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.Equal) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmseq_vi y x_imm (unmasked) ty)) + +;; IntCC.NotEqual + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.NotEqual) x y) + (rv_vmsne_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.NotEqual) x (splat y)) + (rv_vmsne_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.NotEqual) (splat x) y) + (rv_vmsne_vx y x (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.NotEqual) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmsne_vi x y_imm (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.NotEqual) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmsne_vi y x_imm (unmasked) ty)) + +;; IntCC.UnsignedLessThan + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThan) x y) + (rv_vmsltu_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThan) x (splat y)) + (rv_vmsltu_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThan) (splat x) y) + (rv_vmsgtu_vx y x (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThan) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmsgtu_vi y x_imm (unmasked) ty)) + +;; IntCC.SignedLessThan + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThan) x y) + (rv_vmslt_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThan) x (splat y)) + (rv_vmslt_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThan) (splat x) y) + (rv_vmsgt_vx y x (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThan) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmsgt_vi y x_imm (unmasked) ty)) + +;; IntCC.UnsignedLessThanOrEqual + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThanOrEqual) x y) + (rv_vmsleu_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThanOrEqual) x (splat y)) + (rv_vmsleu_vx x y (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedLessThanOrEqual) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmsleu_vi x y_imm (unmasked) ty)) + +;; IntCC.SignedLessThanOrEqual + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThanOrEqual) x y) + (rv_vmsle_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThanOrEqual) x (splat y)) + (rv_vmsle_vx x y (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedLessThanOrEqual) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmsle_vi x y_imm (unmasked) ty)) + +;; IntCC.UnsignedGreaterThan + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThan) x y) + (rv_vmsgtu_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThan) x (splat y)) + (rv_vmsgtu_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThan) (splat x) y) + (rv_vmsltu_vx y x (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThan) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmsgtu_vi x y_imm (unmasked) ty)) + +;; IntCC.SignedGreaterThan + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThan) x y) + (rv_vmsgt_vv x y (unmasked) ty)) + +(rule 1 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThan) x (splat y)) + (rv_vmsgt_vx x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThan) (splat x) y) + (rv_vmslt_vx y x (unmasked) ty)) + +(rule 3 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThan) x y) + (if-let y_imm (replicated_imm5 y)) + (rv_vmsgt_vi x y_imm (unmasked) ty)) + +;; IntCC.UnsignedGreaterThanOrEqual + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThanOrEqual) x y) + (rv_vmsgeu_vv x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThanOrEqual) (splat x) y) + (rv_vmsleu_vx y x (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.UnsignedGreaterThanOrEqual) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmsleu_vi y x_imm (unmasked) ty)) + +;; IntCC.SignedGreaterThanOrEqual + +(rule 0 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThanOrEqual) x y) + (rv_vmsge_vv x y (unmasked) ty)) + +(rule 2 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThanOrEqual) (splat x) y) + (rv_vmsle_vx y x (unmasked) ty)) + +(rule 4 (gen_icmp_mask (ty_vec_fits_in_register ty) (IntCC.SignedGreaterThanOrEqual) x y) + (if-let x_imm (replicated_imm5 x)) + (rv_vmsle_vi y x_imm (unmasked) ty)) + + + +;; Builds a vector mask corresponding to the FloatCC operation. +(decl gen_fcmp_mask (Type FloatCC Value Value) VReg) + +;; FloatCC.Equal + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.Equal) x y) + (rv_vmfeq_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.Equal) x (splat y)) + (rv_vmfeq_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.Equal) (splat x) y) + (rv_vmfeq_vf y x (unmasked) ty)) + +;; FloatCC.NotEqual +;; Note: This is UnorderedNotEqual. It is the only unordered comparison that is not named as such. + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.NotEqual) x y) + (rv_vmfne_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.NotEqual) x (splat y)) + (rv_vmfne_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.NotEqual) (splat x) y) + (rv_vmfne_vf y x (unmasked) ty)) + +;; FloatCC.LessThan + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThan) x y) + (rv_vmflt_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThan) x (splat y)) + (rv_vmflt_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThan) (splat x) y) + (rv_vmfgt_vf y x (unmasked) ty)) + +;; FloatCC.LessThanOrEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThanOrEqual) x y) + (rv_vmfle_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThanOrEqual) x (splat y)) + (rv_vmfle_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.LessThanOrEqual) (splat x) y) + (rv_vmfge_vf y x (unmasked) ty)) + +;; FloatCC.GreaterThan + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThan) x y) + (rv_vmfgt_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThan) x (splat y)) + (rv_vmfgt_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThan) (splat x) y) + (rv_vmflt_vf y x (unmasked) ty)) + +;; FloatCC.GreaterThanOrEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThanOrEqual) x y) + (rv_vmfge_vv x y (unmasked) ty)) + +(rule 1 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThanOrEqual) x (splat y)) + (rv_vmfge_vf x y (unmasked) ty)) + +(rule 2 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.GreaterThanOrEqual) (splat x) y) + (rv_vmfle_vf y x (unmasked) ty)) + +;; FloatCC.Ordered + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.Ordered) x y) + (rv_vmand_mm + (gen_fcmp_mask ty (FloatCC.Equal) x x) + (gen_fcmp_mask ty (FloatCC.Equal) y y) + ty)) + +;; FloatCC.Unordered + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.Unordered) x y) + (rv_vmor_mm + (gen_fcmp_mask ty (FloatCC.NotEqual) x x) + (gen_fcmp_mask ty (FloatCC.NotEqual) y y) + ty)) + +;; FloatCC.OrderedNotEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.OrderedNotEqual) x y) + (rv_vmor_mm + (gen_fcmp_mask ty (FloatCC.LessThan) x y) + (gen_fcmp_mask ty (FloatCC.LessThan) y x) + ty)) + +;; FloatCC.UnorderedOrEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.UnorderedOrEqual) x y) + (rv_vmnor_mm + (gen_fcmp_mask ty (FloatCC.LessThan) x y) + (gen_fcmp_mask ty (FloatCC.LessThan) y x) + ty)) + +;; FloatCC.UnorderedOrGreaterThan + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.UnorderedOrGreaterThan) x y) + (rv_vmnot_m (gen_fcmp_mask ty (FloatCC.LessThanOrEqual) x y) ty)) + +;; FloatCC.UnorderedOrGreaterThanOrEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.UnorderedOrGreaterThanOrEqual) x y) + (rv_vmnot_m (gen_fcmp_mask ty (FloatCC.LessThan) x y) ty)) + +;; FloatCC.UnorderedOrLessThan + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.UnorderedOrLessThan) x y) + (rv_vmnot_m (gen_fcmp_mask ty (FloatCC.GreaterThanOrEqual) x y) ty)) + +;; FloatCC.UnorderedOrLessThanOrEqual + +(rule 0 (gen_fcmp_mask (ty_vec_fits_in_register ty) (FloatCC.UnorderedOrLessThanOrEqual) x y) + (rv_vmnot_m (gen_fcmp_mask ty (FloatCC.GreaterThan) x y) ty)) + + +;; Emits a `vfcvt.x.f.v` instruction with the given rounding mode. +(decl gen_vfcvt_x_f (VReg FRM VState) VReg) + +;; We have a special instruction for RTZ +(rule 1 (gen_vfcvt_x_f x (FRM.RTZ) vstate) + (rv_vfcvt_rtz_x_f_v x (unmasked) vstate)) + +;; In the general case we need to first switch into the appropriate rounding mode. +(rule 0 (gen_vfcvt_x_f x frm vstate) + (let ( + ;; Set the rounding mode and save the current mode + (saved_frm XReg (rv_fsrmi frm)) + (res VReg (rv_vfcvt_x_f_v x (unmasked) vstate)) + ;; Restore the previous rounding mode + (_ Unit (rv_fsrm saved_frm))) + res)) + + +;; Returns the maximum value integer value that can be represented by a float +(decl float_int_max (Type) u64) +(rule (float_int_max $F32) 0x4B000000) +(rule (float_int_max $F64) 0x4330000000000000) + +;; Builds the instruction sequence to round a vector register to FRM +(decl gen_vec_round (VReg FRM Type) VReg) + +;; For floating-point round operations, if the input is NaN, +/-infinity, or +/-0, the +;; same input is returned as the rounded result; this differs from behavior of +;; RISCV fcvt instructions (which round out-of-range values to the nearest +;; max or min value), therefore special handling is needed for these values. +(rule (gen_vec_round x frm (ty_vec_fits_in_register ty)) + (let ((scalar_ty Type (lane_type ty)) + ;; if x is NaN/+-Infinity/+-Zero or if the exponent is larger than # of bits + ;; in mantissa, the result is the same as src, build a mask for those cases. + ;; (There is an additional fixup for NaN's at the end) + (abs VReg (rv_vfabs_v x (unmasked) ty)) + (max FReg (imm scalar_ty (float_int_max scalar_ty))) + (exact VReg (rv_vmflt_vf abs max (unmasked) ty)) + + ;; The rounding is performed by converting from float to integer, with the + ;; desired rounding mode. And then converting back with the default rounding + ;; mode. + (int VReg (gen_vfcvt_x_f x frm ty)) + (cvt VReg (rv_vfcvt_f_x_v int (unmasked) ty)) + ;; Copy the sign bit from the original value. + (signed VReg (rv_vfsgnj_vv cvt x (unmasked) ty)) + + ;; We want to return a arithmetic nan if the input is a canonical nan. + ;; Convert them by adding 0.0 to the input. + (float_zero FReg (gen_bitcast (zero_reg) (float_int_of_same_size scalar_ty) scalar_ty)) + (corrected_nan VReg (rv_vfadd_vf x float_zero (unmasked) ty))) + ;; Merge the original value if it does not need rounding, or the rounded value + (rv_vmerge_vvm corrected_nan signed exact ty))) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.isle b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.isle new file mode 100644 index 00000000000000..2a807608734107 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.isle @@ -0,0 +1,2996 @@ +;; riscv64 instruction selection and CLIF-to-MachInst lowering. + +;; The main lowering constructor term: takes a clif `Inst` and returns the +;; register(s) within which the lowered instruction's result values live. +(decl partial lower (Inst) InstOutput) + +;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (iconst (u64_from_imm64 n)))) + (imm ty n)) + +;; ;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_supported_vec ty) (vconst n))) + (gen_constant ty (const_to_vconst n))) + +;;;; Rules for `f16const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f16const (u16_from_ieee16 n))) + (imm $F16 n)) + +;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f32const (u32_from_ieee32 n))) + (imm $F32 n)) + +;;;; Rules for `f64const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f64const (u64_from_ieee64 n))) + (imm $F64 n)) + +;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Base case, simply adding things in registers. +(rule -1 (lower (has_type (fits_in_32 (ty_int ty)) (iadd x y))) + (rv_addw x y)) + +(rule 0 (lower (has_type $I64 (iadd x y))) + (rv_add x y)) + +;; Special cases for when one operand is an immediate that fits in 12 bits. +(rule 1 (lower (has_type (ty_int_ref_scalar_64 ty) (iadd x (imm12_from_value y)))) + (alu_rr_imm12 (select_addi ty) x y)) + +(rule 2 (lower (has_type (ty_int_ref_scalar_64 ty) (iadd (imm12_from_value x) y))) + (alu_rr_imm12 (select_addi ty) y x)) + +;; Special case when one of the operands is uextended +;; Needs `Zba` +(rule 3 (lower (has_type $I64 (iadd x (uextend y @ (value_type $I32))))) + (if-let true (has_zba)) + (rv_adduw y x)) + +(rule 4 (lower (has_type $I64 (iadd (uextend x @ (value_type $I32)) y))) + (if-let true (has_zba)) + (rv_adduw x y)) + +;; Add with const shift. We have a few of these instructions with `Zba`. +(decl pure partial match_shnadd (Imm64) AluOPRRR) +(rule (match_shnadd (u64_from_imm64 1)) (AluOPRRR.Sh1add)) +(rule (match_shnadd (u64_from_imm64 2)) (AluOPRRR.Sh2add)) +(rule (match_shnadd (u64_from_imm64 3)) (AluOPRRR.Sh3add)) + +(rule 3 (lower (has_type $I64 (iadd x (ishl y (maybe_uextend (iconst n)))))) + (if-let true (has_zba)) + (if-let shnadd (match_shnadd n)) + (alu_rrr shnadd y x)) + +(rule 4 (lower (has_type $I64 (iadd (ishl x (maybe_uextend (iconst n))) y))) + (if-let true (has_zba)) + (if-let shnadd (match_shnadd n)) + (alu_rrr shnadd x y)) + + +;; Add with uextended const shift. We have a few of these instructions with `Zba`. +;; +;; !!! Important !!! +;; These rules only work for (ishl (uextend _) _) and not for (uextend (ishl _ _))! +;; Getting this wrong means a potential misscalculation of the shift amount. +;; Additionally we can only ensure that this is correct if the uextend is 32 to 64 bits. +(decl pure partial match_shnadd_uw (Imm64) AluOPRRR) +(rule (match_shnadd_uw (u64_from_imm64 1)) (AluOPRRR.Sh1adduw)) +(rule (match_shnadd_uw (u64_from_imm64 2)) (AluOPRRR.Sh2adduw)) +(rule (match_shnadd_uw (u64_from_imm64 3)) (AluOPRRR.Sh3adduw)) + +(rule 5 (lower (has_type $I64 (iadd x (ishl (uextend y @ (value_type $I32)) (maybe_uextend (iconst n)))))) + (if-let true (has_zba)) + (if-let shnadd_uw (match_shnadd_uw n)) + (alu_rrr shnadd_uw y x)) + +(rule 6 (lower (has_type $I64 (iadd (ishl (uextend x @ (value_type $I32)) (maybe_uextend (iconst n))) y))) + (if-let true (has_zba)) + (if-let shnadd_uw (match_shnadd_uw n)) + (alu_rrr shnadd_uw x y)) + +;; I128 cases +(rule 7 (lower (has_type $I128 (iadd x y))) + (let ((low XReg (rv_add (value_regs_get x 0) (value_regs_get y 0))) + ;; compute carry. + (carry XReg (rv_sltu low (value_regs_get y 0))) + ;; + (high_tmp XReg (rv_add (value_regs_get x 1) (value_regs_get y 1))) + ;; add carry. + (high XReg (rv_add high_tmp carry))) + (value_regs low high))) + +;; SIMD Vectors +(rule 8 (lower (has_type (ty_supported_vec ty) (iadd x y))) + (rv_vadd_vv x y (unmasked) ty)) + +(rule 9 (lower (has_type (ty_supported_vec ty) (iadd x (splat y)))) + (rv_vadd_vx x y (unmasked) ty)) + +(rule 10 (lower (has_type (ty_supported_vec ty) (iadd x (splat (sextend y @ (value_type sext_ty)))))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) sext_ty)) + (rv_vwadd_wx x y (unmasked) (vstate_mf2 half_ty))) + +(rule 10 (lower (has_type (ty_supported_vec ty) (iadd x (splat (uextend y @ (value_type uext_ty)))))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) uext_ty)) + (rv_vwaddu_wx x y (unmasked) (vstate_mf2 half_ty))) + +(rule 20 (lower (has_type (ty_supported_vec ty) (iadd x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vadd_vi x y_imm (unmasked) ty)) + + +(rule 12 (lower (has_type (ty_supported_vec ty) (iadd (splat x) y))) + (rv_vadd_vx y x (unmasked) ty)) + +(rule 13 (lower (has_type (ty_supported_vec ty) (iadd (splat (sextend x @ (value_type sext_ty))) y))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) sext_ty)) + (rv_vwadd_wx y x (unmasked) (vstate_mf2 half_ty))) + +(rule 13 (lower (has_type (ty_supported_vec ty) (iadd (splat (uextend x @ (value_type uext_ty))) y))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) uext_ty)) + (rv_vwaddu_wx y x (unmasked) (vstate_mf2 half_ty))) + +(rule 21 (lower (has_type (ty_supported_vec ty) (iadd x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vadd_vi y x_imm (unmasked) ty)) + +;; Signed Widening Low Additions + +(rule 9 (lower (has_type (ty_supported_vec _) (iadd x (swiden_low y @ (value_type in_ty))))) + (rv_vwadd_wv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 12 (lower (has_type (ty_supported_vec _) (iadd (swiden_low x @ (value_type in_ty)) y))) + (rv_vwadd_wv y x (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_low x @ (value_type in_ty)) + (swiden_low y)))) + (rv_vwadd_vv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_low x @ (value_type in_ty)) + (splat (sextend y @ (value_type sext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwadd_vx x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 15 (lower (has_type (ty_supported_vec _) (iadd (splat (sextend x @ (value_type sext_ty))) + (swiden_low y @ (value_type in_ty))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwadd_vx y x (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Signed Widening High Additions +;; These are the same as the low additions, but we first slide down the inputs. + +(rule 9 (lower (has_type (ty_supported_vec _) (iadd x (swiden_high y @ (value_type in_ty))))) + (rv_vwadd_wv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 12 (lower (has_type (ty_supported_vec _) (iadd (swiden_high x @ (value_type in_ty)) y))) + (rv_vwadd_wv y (gen_slidedown_half in_ty x) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_high x @ (value_type in_ty)) + (swiden_high y)))) + (rv_vwadd_vv (gen_slidedown_half in_ty x) (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_high x @ (value_type in_ty)) + (splat (sextend y @ (value_type sext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwadd_vx (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 15 (lower (has_type (ty_supported_vec _) (iadd (splat (sextend x @ (value_type sext_ty))) + (swiden_high y @ (value_type in_ty))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwadd_vx (gen_slidedown_half in_ty y) x (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening Low Additions + +(rule 9 (lower (has_type (ty_supported_vec _) (iadd x (uwiden_low y @ (value_type in_ty))))) + (rv_vwaddu_wv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 12 (lower (has_type (ty_supported_vec _) (iadd (uwiden_low x @ (value_type in_ty)) y))) + (rv_vwaddu_wv y x (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_low x @ (value_type in_ty)) + (uwiden_low y)))) + (rv_vwaddu_vv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_low x @ (value_type in_ty)) + (splat (uextend y @ (value_type uext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwaddu_vx x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 15 (lower (has_type (ty_supported_vec _) (iadd (splat (uextend x @ (value_type uext_ty))) + (uwiden_low y @ (value_type in_ty))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwaddu_vx y x (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening High Additions +;; These are the same as the low additions, but we first slide down the inputs. + +(rule 9 (lower (has_type (ty_supported_vec _) (iadd x (uwiden_high y @ (value_type in_ty))))) + (rv_vwaddu_wv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 12 (lower (has_type (ty_supported_vec _) (iadd (uwiden_high x @ (value_type in_ty)) y))) + (rv_vwaddu_wv y (gen_slidedown_half in_ty x) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_high x @ (value_type in_ty)) + (uwiden_high y)))) + (rv_vwaddu_vv (gen_slidedown_half in_ty x) (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_high x @ (value_type in_ty)) + (splat (uextend y @ (value_type uext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwaddu_vx (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 15 (lower (has_type (ty_supported_vec _) (iadd (splat (uextend y @ (value_type uext_ty))) + (uwiden_high x @ (value_type in_ty))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwaddu_vx (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Signed Widening Mixed High/Low Additions + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_low x @ (value_type in_ty)) + (swiden_high y)))) + (rv_vwadd_vv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (swiden_high x @ (value_type in_ty)) + (swiden_low y)))) + (rv_vwadd_vv (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening Mixed High/Low Additions + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_low x @ (value_type in_ty)) + (uwiden_high y)))) + (rv_vwaddu_vv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 13 (lower (has_type (ty_supported_vec _) (iadd (uwiden_high x @ (value_type in_ty)) + (uwiden_low y)))) + (rv_vwaddu_vv (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Fused Multiply Accumulate Rules `vmacc` +;; +;; I dont think we can use `vmadd`/`vmnsub` here since it just modifies the multiplication +;; register instead of the addition one. The actual pattern matched seems to be +;; exactly the same. + +(rule 9 (lower (has_type (ty_supported_vec ty) (iadd x (imul y z)))) + (rv_vmacc_vv x y z (unmasked) ty)) + +(rule 10 (lower (has_type (ty_supported_vec ty) (iadd x (imul y (splat z))))) + (rv_vmacc_vx x y z (unmasked) ty)) + +(rule 11 (lower (has_type (ty_supported_vec ty) (iadd x (imul (splat y) z)))) + (rv_vmacc_vx x z y (unmasked) ty)) + +(rule 12 (lower (has_type (ty_supported_vec ty) (iadd (imul x y) z))) + (rv_vmacc_vv z x y (unmasked) ty)) + +(rule 13 (lower (has_type (ty_supported_vec ty) (iadd (imul x (splat y)) z))) + (rv_vmacc_vx z x y (unmasked) ty)) + +(rule 14 (lower (has_type (ty_supported_vec ty) (iadd (imul (splat x) y) z))) + (rv_vmacc_vx z y x (unmasked) ty)) + +;; Fused Multiply Subtract Rules `vnmsac` + +(rule 9 (lower (has_type (ty_supported_vec ty) (iadd x (ineg (imul y z))))) + (rv_vnmsac_vv x y z (unmasked) ty)) + +(rule 10 (lower (has_type (ty_supported_vec ty) (iadd x (ineg (imul y (splat z)))))) + (rv_vnmsac_vx x y z (unmasked) ty)) + +(rule 11 (lower (has_type (ty_supported_vec ty) (iadd x (ineg (imul (splat y) z))))) + (rv_vnmsac_vx x z y (unmasked) ty)) + +(rule 12 (lower (has_type (ty_supported_vec ty) (iadd (ineg (imul x y)) z))) + (rv_vnmsac_vv z x y (unmasked) ty)) + +(rule 13 (lower (has_type (ty_supported_vec ty) (iadd (ineg (imul x (splat y))) z))) + (rv_vnmsac_vx z x y (unmasked) ty)) + +(rule 14 (lower (has_type (ty_supported_vec ty) (iadd (ineg (imul (splat x) y)) z))) + (rv_vnmsac_vx z y x (unmasked) ty)) + +;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_32 ty) (uadd_overflow_trap x y tc))) + (let ((tmp_x XReg (zext x)) + (tmp_y XReg (zext y)) + (sum XReg (rv_add tmp_x tmp_y)) + (test XReg (rv_srli sum (imm12_const (ty_bits ty)))) + (_ InstOutput (gen_trapnz test tc))) + sum)) + +(rule 1 (lower (has_type $I64 (uadd_overflow_trap x y tc))) + (let ((tmp XReg (rv_add x y)) + (_ InstOutput (gen_trapif (IntCC.UnsignedLessThan) tmp x tc))) + tmp)) + +;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Base case, simply subtracting things in registers. + +(rule 0 (lower (has_type (fits_in_32 (ty_int ty)) (isub x y))) + (rv_subw x y)) + +(rule 1 (lower (has_type $I64 (isub x y))) + (rv_sub x y)) + +(rule 2 (lower (has_type $I128 (isub x y))) + (i128_sub x y)) + +;; Switch to an `addi` by a negative if we can fit the value in an `imm12`. +(rule 3 (lower (has_type (ty_int_ref_scalar_64 ty) (isub x y))) + (if-let imm12_neg (imm12_from_negated_value y)) + (alu_rr_imm12 (select_addi ty) x imm12_neg)) + +;; SIMD Vectors +(rule 4 (lower (has_type (ty_supported_vec ty) (isub x y))) + (rv_vsub_vv x y (unmasked) ty)) + +(rule 5 (lower (has_type (ty_supported_vec ty) (isub x (splat y)))) + (rv_vsub_vx x y (unmasked) ty)) + +(rule 6 (lower (has_type (ty_supported_vec ty) (isub x (splat (sextend y @ (value_type sext_ty)))))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) sext_ty)) + (rv_vwsub_wx x y (unmasked) (vstate_mf2 half_ty))) + +(rule 6 (lower (has_type (ty_supported_vec ty) (isub x (splat (uextend y @ (value_type uext_ty)))))) + (if-let half_ty (ty_half_width ty)) + (if-let true (ty_equal (lane_type half_ty) uext_ty)) + (rv_vwsubu_wx x y (unmasked) (vstate_mf2 half_ty))) + +(rule 7 (lower (has_type (ty_supported_vec ty) (isub (splat x) y))) + (rv_vrsub_vx y x (unmasked) ty)) + +(rule 8 (lower (has_type (ty_supported_vec ty) (isub x y))) + (if-let imm5_neg (negated_replicated_imm5 y)) + (rv_vadd_vi x imm5_neg (unmasked) ty)) + +(rule 9 (lower (has_type (ty_supported_vec ty) (isub x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vrsub_vi y x_imm (unmasked) ty)) + + +;; Signed Widening Low Subtractions + +(rule 6 (lower (has_type (ty_supported_vec _) (isub x (swiden_low y @ (value_type in_ty))))) + (rv_vwsub_wv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_low x @ (value_type in_ty)) + (swiden_low y)))) + (rv_vwsub_vv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_low x @ (value_type in_ty)) + (splat (sextend y @ (value_type sext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwsub_vx x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Signed Widening High Subtractions +;; These are the same as the low widenings, but we first slide down the inputs. + +(rule 6 (lower (has_type (ty_supported_vec _) (isub x (swiden_high y @ (value_type in_ty))))) + (rv_vwsub_wv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_high x @ (value_type in_ty)) + (swiden_high y)))) + (rv_vwsub_vv (gen_slidedown_half in_ty x) (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_high x @ (value_type in_ty)) + (splat (sextend y @ (value_type sext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) sext_ty)) + (rv_vwsub_vx (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening Low Subtractions + +(rule 6 (lower (has_type (ty_supported_vec _) (isub x (uwiden_low y @ (value_type in_ty))))) + (rv_vwsubu_wv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_low x @ (value_type in_ty)) + (uwiden_low y)))) + (rv_vwsubu_vv x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_low x @ (value_type in_ty)) + (splat (uextend y @ (value_type uext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwsubu_vx x y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening High Subtractions +;; These are the same as the low widenings, but we first slide down the inputs. + +(rule 6 (lower (has_type (ty_supported_vec _) (isub x (uwiden_high y @ (value_type in_ty))))) + (rv_vwsubu_wv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_high x @ (value_type in_ty)) + (uwiden_high y)))) + (rv_vwsubu_vv (gen_slidedown_half in_ty x) (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_high x @ (value_type in_ty)) + (splat (uextend y @ (value_type uext_ty)))))) + (if-let true (ty_equal (lane_type in_ty) uext_ty)) + (rv_vwsubu_vx (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Signed Widening Mixed High/Low Subtractions + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_low x @ (value_type in_ty)) + (swiden_high y)))) + (rv_vwsub_vv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (swiden_high x @ (value_type in_ty)) + (swiden_low y)))) + (rv_vwsub_vv (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +;; Unsigned Widening Mixed High/Low Subtractions + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_low x @ (value_type in_ty)) + (uwiden_high y)))) + (rv_vwsubu_vv x (gen_slidedown_half in_ty y) (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + +(rule 10 (lower (has_type (ty_supported_vec _) (isub (uwiden_high x @ (value_type in_ty)) + (uwiden_low y)))) + (rv_vwsubu_vv (gen_slidedown_half in_ty x) y (unmasked) (vstate_mf2 (ty_half_lanes in_ty)))) + + +;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_int ty) (ineg val))) + (neg ty val)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (ineg x))) + (rv_vneg_v x (unmasked) ty)) + + +;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int_ref_scalar_64 ty) (imul x y))) + (rv_mul x y)) + +(rule 1 (lower (has_type (fits_in_32 (ty_int ty)) (imul x y))) + (rv_mulw x y)) + +;; for I128 +(rule 2 (lower (has_type $I128 (imul x y))) + (let + ((x_regs ValueRegs x) + (x_lo XReg (value_regs_get x_regs 0)) + (x_hi XReg (value_regs_get x_regs 1)) + + ;; Get the high/low registers for `y`. + (y_regs ValueRegs y) + (y_lo XReg (value_regs_get y_regs 0)) + (y_hi XReg (value_regs_get y_regs 1)) + + ;; 128bit mul formula: + ;; dst_lo = x_lo * y_lo + ;; dst_hi = mulhu(x_lo, y_lo) + (x_lo * y_hi) + (x_hi * y_lo) + ;; + ;; We can convert the above formula into the following + ;; mulhu dst_hi, x_lo, y_lo + ;; madd dst_hi, x_lo, y_hi, dst_hi + ;; madd dst_hi, x_hi, y_lo, dst_hi + ;; madd dst_lo, x_lo, y_lo, zero + (dst_hi1 XReg (rv_mulhu x_lo y_lo)) + (dst_hi2 XReg (madd x_lo y_hi dst_hi1)) + (dst_hi XReg (madd x_hi y_lo dst_hi2)) + (dst_lo XReg (madd x_lo y_lo (zero_reg)))) + (value_regs dst_lo dst_hi))) + +;; Special case 128-bit multiplication where the operands are extended since +;; that maps directly to the `mulhu` and `mulh` instructions. +(rule 6 (lower (has_type $I128 (imul (uextend x) (uextend y)))) + (let ((x XReg (zext x)) + (y XReg (zext y))) + (value_regs (rv_mul x y) (rv_mulhu x y)))) + +(rule 6 (lower (has_type $I128 (imul (sextend x) (sextend y)))) + (let ((x XReg (sext x)) + (y XReg (sext y))) + (value_regs (rv_mul x y) (rv_mulh x y)))) + +;; Vector multiplication + +(rule 3 (lower (has_type (ty_supported_vec ty) (imul x y))) + (rv_vmul_vv x y (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (imul (splat x) y))) + (rv_vmul_vx y x (unmasked) ty)) + +(rule 5 (lower (has_type (ty_supported_vec ty) (imul x (splat y)))) + (rv_vmul_vx x y (unmasked) ty)) + +;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_int_ref_scalar_64 ty) (smulhi x y))) + (lower_smlhi ty (sext x) (sext y))) + +(rule 1 (lower (has_type (ty_supported_vec ty) (smulhi x y))) + (rv_vmulh_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (smulhi (splat x) y))) + (rv_vmulh_vx y x (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (smulhi x (splat y)))) + (rv_vmulh_vx x y (unmasked) ty)) + +;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_32 ty) (umulhi x y))) + (let ((tmp XReg (rv_mul (zext x) (zext y)))) + (rv_srli tmp (imm12_const (ty_bits ty))))) + +(rule 1 (lower (has_type $I64 (umulhi x y))) + (rv_mulhu x y)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (umulhi x y))) + (rv_vmulhu_vv x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (umulhi (splat x) y))) + (rv_vmulhu_vx y x (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (umulhi x (splat y)))) + (rv_vmulhu_vx x y (unmasked) ty)) + +;;;; Rules for `udiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_16 ty) (udiv x y))) + (if-let true (has_m)) + (rv_divuw (zext x) (nonzero_divisor (zext y)))) + +(rule 1 (lower (has_type (fits_in_16 ty) (udiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 ty imm)) + (rv_divuw (zext x) (zext y))) + +(rule 2 (lower (has_type $I32 (udiv x y))) + (if-let true (has_m)) + (rv_divuw x (nonzero_divisor (zext y)))) + +(rule 3 (lower (has_type $I32 (udiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I32 imm)) + (rv_divuw x y)) + +(rule 2 (lower (has_type $I64 (udiv x y))) + (if-let true (has_m)) + (rv_divu x (nonzero_divisor y))) + +(rule 3 (lower (has_type $I64 (udiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I64 imm)) + (rv_divu x y)) + +;; Traps if the input register is zero, otherwise returns the same register. +(decl nonzero_divisor (XReg) XReg) +(rule (nonzero_divisor val) + (let ((_ InstOutput (gen_trapif (IntCC.Equal) val (zero_reg) (TrapCode.INTEGER_DIVISION_BY_ZERO)))) + val)) + +;;;; Rules for `sdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_16 ty) (sdiv x y))) + (if-let true (has_m)) + (let ((x XReg (sext x))) + (rv_divw x (safe_sdiv_divisor ty x (sext y))))) + +(rule 1 (lower (has_type (fits_in_16 ty) (sdiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 ty imm)) + (rv_divw (sext x) (sext y))) + +(rule 2 (lower (has_type $I32 (sdiv x y))) + (if-let true (has_m)) + (let ((x XReg (sext x))) + (rv_divw x (safe_sdiv_divisor $I32 x (sext y))))) + +(rule 3 (lower (has_type $I32 (sdiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I32 imm)) + (rv_divw x y)) + +(rule 2 (lower (has_type $I64 (sdiv x y))) + (if-let true (has_m)) + (rv_div x (safe_sdiv_divisor $I64 x y))) + +(rule 3 (lower (has_type $I64 (sdiv x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I64 imm)) + (rv_div x y)) + +;; Check for two trapping conditions: +;; +;; * the divisor is 0, or... +;; * the divisor is -1 and the dividend is $ty::MIN +(decl safe_sdiv_divisor (Type XReg XReg) XReg) +(rule (safe_sdiv_divisor ty x y) + (let ( + (y XReg (nonzero_divisor y)) + (min XReg (imm $I64 (u64_shl 0xffffffff_ffffffff (u64_sub (ty_bits ty) 1)))) + (x_is_not_min XReg (rv_xor x min)) + (y_is_not_neg_one XReg (rv_not y)) + (no_int_overflow XReg (rv_or x_is_not_min y_is_not_neg_one)) + (_ InstOutput (gen_trapif + (IntCC.Equal) + no_int_overflow (zero_reg) + (TrapCode.INTEGER_OVERFLOW)))) + y)) + +;;;; Rules for `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_16 ty) (urem x y))) + (if-let true (has_m)) + (rv_remuw (zext x) (nonzero_divisor (zext y)))) + +(rule 1 (lower (has_type (fits_in_16 ty) (urem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 ty imm)) + (rv_remuw (zext x) (zext y))) + +(rule 2 (lower (has_type $I32 (urem x y))) + (if-let true (has_m)) + (rv_remuw x (nonzero_divisor (zext y)))) + +(rule 3 (lower (has_type $I32 (urem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I32 imm)) + (rv_remuw x y)) + +(rule 2 (lower (has_type $I64 (urem x y))) + (if-let true (has_m)) + (rv_remu x (nonzero_divisor y))) + +(rule 3 (lower (has_type $I64 (urem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I64 imm)) + (rv_remu x y)) + +;;;; Rules for `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_16 ty) (srem x y))) + (if-let true (has_m)) + (rv_remw (sext x) (nonzero_divisor (sext y)))) + +(rule 1 (lower (has_type (fits_in_16 ty) (srem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 ty imm)) + (rv_remw (sext x) (sext y))) + +(rule 2 (lower (has_type $I32 (srem x y))) + (if-let true (has_m)) + (rv_remw x (nonzero_divisor (sext y)))) + +(rule 3 (lower (has_type $I32 (srem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I32 imm)) + (rv_remw x y)) + +(rule 2 (lower (has_type $I64 (srem x y))) + (if-let true (has_m)) + (rv_rem x (nonzero_divisor y))) + +(rule 3 (lower (has_type $I64 (srem x y @ (iconst imm)))) + (if-let true (has_m)) + (if (safe_divisor_from_imm64 $I64 imm)) + (rv_rem x y)) + +;;;; Rules for `and` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule -1 (lower (has_type (fits_in_64 ty) (band x y))) + (rv_and x y)) + +(rule 0 (lower (has_type $I128 (band x y))) + (value_regs + (rv_and (value_regs_get x 0) (value_regs_get y 0)) + (rv_and (value_regs_get x 1) (value_regs_get y 1)))) + +;; Special cases for when one operand is an immediate that fits in 12 bits. +(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (band x (imm12_from_value y)))) + (rv_andi x y)) + +(rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (band (imm12_from_value x) y))) + (rv_andi y x)) + +(rule 3 (lower (has_type (ty_supported_float ty) (band x y))) + (lower_float_binary (AluOPRRR.And) x y ty)) + +;; Specialized lowerings for `(band x (bnot y))` which is additionally produced +;; by Cranelift's `band_not` instruction that is legalized into the simpler +;; forms early on. + +(rule 4 (lower (has_type (fits_in_64 (ty_int ty)) (band x (bnot y)))) + (if-let true (has_zbb)) + (rv_andn x y)) + +(rule 5 (lower (has_type (fits_in_64 (ty_int ty)) (band (bnot y) x))) + (if-let true (has_zbb)) + (rv_andn x y)) + +(rule 6 (lower (has_type $I128 (band x (bnot y)))) + (if-let true (has_zbb)) + (let ((low XReg (rv_andn (value_regs_get x 0) (value_regs_get y 0))) + (high XReg (rv_andn (value_regs_get x 1) (value_regs_get y 1)))) + (value_regs low high))) + +(rule 7 (lower (has_type $I128 (band (bnot y) x))) + (if-let true (has_zbb)) + (let ((low XReg (rv_andn (value_regs_get x 0) (value_regs_get y 0))) + (high XReg (rv_andn (value_regs_get x 1) (value_regs_get y 1)))) + (value_regs low high))) + +(rule 8 (lower (has_type (ty_supported_vec ty) (band x y))) + (rv_vand_vv x y (unmasked) ty)) + +(rule 9 (lower (has_type (ty_supported_vec ty) (band x (splat y)))) + (if (ty_vector_not_float ty)) + (rv_vand_vx x y (unmasked) ty)) + +(rule 10 (lower (has_type (ty_supported_vec ty) (band (splat x) y))) + (if (ty_vector_not_float ty)) + (rv_vand_vx y x (unmasked) ty)) + +(rule 11 (lower (has_type (ty_supported_vec ty) (band x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vand_vi x y_imm (unmasked) ty)) + +(rule 12 (lower (has_type (ty_supported_vec ty) (band x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vand_vi y x_imm (unmasked) ty)) + +;; `bclr{,i}` specializations from `zbs` + +(rule 13 (lower (has_type (fits_in_32 ty) (band x (bnot (ishl (i64_from_iconst 1) y))))) + (if-let true (has_zbs)) + (rv_bclr x (rv_andi y (imm12_const (u8_sub (ty_bits ty) 1))))) +(rule 14 (lower (has_type (fits_in_32 ty) (band (bnot (ishl (i64_from_iconst 1) y)) x))) + (if-let true (has_zbs)) + (rv_bclr x (rv_andi y (imm12_const (u8_sub (ty_bits ty) 1))))) + +(rule 15 (lower (has_type $I64 (band x (bnot (ishl (i64_from_iconst 1) y))))) + (if-let true (has_zbs)) + (rv_bclr x y)) +(rule 16 (lower (has_type $I64 (band (bnot (ishl (i64_from_iconst 1) y)) x))) + (if-let true (has_zbs)) + (rv_bclr x y)) + +(rule 17 (lower (has_type (fits_in_64 ty) (band x (u64_from_iconst n)))) + (if-let true (has_zbs)) + (if-let imm (bclr_imm ty n)) + (rv_bclri x imm)) +(rule 18 (lower (has_type (fits_in_64 ty) (band (u64_from_iconst n) x))) + (if-let true (has_zbs)) + (if-let imm (bclr_imm ty n)) + (rv_bclri x imm)) + +(decl pure partial bclr_imm (Type u64) Imm12) +(extern constructor bclr_imm bclr_imm) + +;; `bext{,i}` specializations from `zbs` + +(rule 19 (lower (has_type $I32 (band (ushr x y) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bext x (rv_andi y (imm12_const 31)))) +(rule 19 (lower (has_type $I32 (band (sshr x y) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bext x (rv_andi y (imm12_const 31)))) +(rule 19 (lower (has_type $I32 (band (u64_from_iconst 1) (ushr x y)))) + (if-let true (has_zbs)) + (rv_bext x (rv_andi y (imm12_const 31)))) +(rule 19 (lower (has_type $I32 (band (u64_from_iconst 1) (sshr x y)))) + (if-let true (has_zbs)) + (rv_bext x (rv_andi y (imm12_const 31)))) + +(rule 19 (lower (has_type $I64 (band (ushr x y) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bext x y)) +(rule 19 (lower (has_type $I64 (band (sshr x y) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bext x y)) +(rule 19 (lower (has_type $I64 (band (u64_from_iconst 1) (ushr x y)))) + (if-let true (has_zbs)) + (rv_bext x y)) +(rule 19 (lower (has_type $I64 (band (u64_from_iconst 1) (sshr x y)))) + (if-let true (has_zbs)) + (rv_bext x y)) + +(rule 20 (lower (has_type $I32 (band (ushr x (imm12_from_value y)) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bexti x (imm12_and y 31))) +(rule 20 (lower (has_type $I32 (band (sshr x (imm12_from_value y)) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bexti x (imm12_and y 31))) +(rule 20 (lower (has_type $I64 (band (ushr x (imm12_from_value y)) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bexti x (imm12_and y 63))) +(rule 20 (lower (has_type $I64 (band (sshr x (imm12_from_value y)) (u64_from_iconst 1)))) + (if-let true (has_zbs)) + (rv_bexti x (imm12_and y 63))) + +;;;; Rules for `or` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_int ty) (bor x y))) + (gen_or ty x y)) + +;; Special cases for when one operand is an immediate that fits in 12 bits. +(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bor x (imm12_from_value y)))) + (rv_ori x y)) + +(rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (bor (imm12_from_value x) y))) + (rv_ori y x)) + +(rule 3 (lower (has_type (ty_supported_float ty) (bor x y))) + (lower_float_binary (AluOPRRR.Or) x y ty)) + +;; Specialized lowerings for `(bor x (bnot y))` which is additionally produced +;; by Cranelift's `bor_not` instruction that is legalized into the simpler +;; forms early on. + +(rule 4 (lower (has_type (fits_in_64 (ty_int ty)) (bor x (bnot y)))) + (if-let true (has_zbb)) + (rv_orn x y)) + +(rule 5 (lower (has_type (fits_in_64 (ty_int ty)) (bor (bnot y) x))) + (if-let true (has_zbb)) + (rv_orn x y)) + +(rule 6 (lower (has_type $I128 (bor x (bnot y)))) + (if-let true (has_zbb)) + (let ((low XReg (rv_orn (value_regs_get x 0) (value_regs_get y 0))) + (high XReg (rv_orn (value_regs_get x 1) (value_regs_get y 1)))) + (value_regs low high))) + +(rule 7 (lower (has_type $I128 (bor (bnot y) x))) + (if-let true (has_zbb)) + (let ((low XReg (rv_orn (value_regs_get x 0) (value_regs_get y 0))) + (high XReg (rv_orn (value_regs_get x 1) (value_regs_get y 1)))) + (value_regs low high))) + +(rule 8 (lower (has_type (ty_supported_vec ty) (bor x y))) + (rv_vor_vv x y (unmasked) ty)) + +(rule 9 (lower (has_type (ty_supported_vec ty) (bor x (splat y)))) + (if (ty_vector_not_float ty)) + (rv_vor_vx x y (unmasked) ty)) + +(rule 10 (lower (has_type (ty_supported_vec ty) (bor (splat x) y))) + (if (ty_vector_not_float ty)) + (rv_vor_vx y x (unmasked) ty)) + +(rule 11 (lower (has_type (ty_supported_vec ty) (bor x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vor_vi x y_imm (unmasked) ty)) + +(rule 12 (lower (has_type (ty_supported_vec ty) (bor x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vor_vi y x_imm (unmasked) ty)) + +;; `bset{,i}` specializations from `zbs` + +(rule 13 (lower (has_type $I32 (bor x (ishl (i64_from_iconst 1) y)))) + (if-let true (has_zbs)) + (rv_bset x (rv_andi y (imm12_const 31)))) +(rule 14 (lower (has_type $I32 (bor (ishl (i64_from_iconst 1) y) x))) + (if-let true (has_zbs)) + (rv_bset x (rv_andi y (imm12_const 31)))) + +(rule 13 (lower (has_type $I64 (bor x (ishl (i64_from_iconst 1) y)))) + (if-let true (has_zbs)) + (rv_bset x y)) +(rule 14 (lower (has_type $I64 (bor (ishl (i64_from_iconst 1) y) x))) + (if-let true (has_zbs)) + (rv_bset x y)) + +(rule 15 (lower (has_type (fits_in_64 _) (bor x (u64_from_iconst n)))) + (if-let true (has_zbs)) + (if-let imm (bseti_imm n)) + (rv_bseti x imm)) +(rule 16 (lower (has_type (fits_in_64 _) (bor (u64_from_iconst n) x))) + (if-let true (has_zbs)) + (if-let imm (bseti_imm n)) + (rv_bseti x imm)) + +(decl pure partial bseti_imm (u64) Imm12) +(extern constructor bseti_imm bseti_imm) + +;;;; Rules for `xor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_64 (ty_int ty)) (bxor x y))) + (rv_xor x y)) + +;; Special cases for when one operand is an immediate that fits in 12 bits. +(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bxor x (imm12_from_value y)))) + (rv_xori x y)) + +(rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (bxor (imm12_from_value x) y))) + (rv_xori y x)) + +(rule 3 (lower (has_type $I128 (bxor x y))) + (lower_b128_binary (AluOPRRR.Xor) x y)) + +(rule 4 (lower (has_type (ty_supported_float ty) (bxor x y))) + (lower_float_binary (AluOPRRR.Xor) x y ty)) + +(rule 5 (lower (has_type (ty_supported_vec ty) (bxor x y))) + (rv_vxor_vv x y (unmasked) ty)) + +(rule 6 (lower (has_type (ty_supported_vec ty) (bxor x (splat y)))) + (if (ty_vector_not_float ty)) + (rv_vxor_vx x y (unmasked) ty)) + +(rule 7 (lower (has_type (ty_supported_vec ty) (bxor (splat x) y))) + (if (ty_vector_not_float ty)) + (rv_vxor_vx y x (unmasked) ty)) + +(rule 8 (lower (has_type (ty_supported_vec ty) (bxor x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vxor_vi x y_imm (unmasked) ty)) + +(rule 9 (lower (has_type (ty_supported_vec ty) (bxor x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vxor_vi y x_imm (unmasked) ty)) + +;; `binv{,i}` specializations from `zbs` + +(rule 13 (lower (has_type $I32 (bxor x (ishl (i64_from_iconst 1) y)))) + (if-let true (has_zbs)) + (rv_binv x (rv_andi y (imm12_const 31)))) +(rule 14 (lower (has_type $I32 (bxor (ishl (i64_from_iconst 1) y) x))) + (if-let true (has_zbs)) + (rv_binv x (rv_andi y (imm12_const 31)))) + +(rule 13 (lower (has_type $I64 (bxor x (ishl (i64_from_iconst 1) y)))) + (if-let true (has_zbs)) + (rv_binv x y)) +(rule 14 (lower (has_type $I64 (bxor (ishl (i64_from_iconst 1) y) x))) + (if-let true (has_zbs)) + (rv_binv x y)) + +(rule 15 (lower (has_type (fits_in_64 _) (bxor x (u64_from_iconst n)))) + (if-let true (has_zbs)) + (if-let imm (binvi_imm n)) + (rv_binvi x imm)) +(rule 16 (lower (has_type (fits_in_64 _) (bxor (u64_from_iconst n) x))) + (if-let true (has_zbs)) + (if-let imm (binvi_imm n)) + (rv_binvi x imm)) + +(decl pure partial binvi_imm (u64) Imm12) +(extern constructor binvi_imm binvi_imm) + +;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int_ref_scalar_64 _) (bnot x))) + (rv_not x)) + +(rule 1 (lower (has_type (ty_supported_float ty) (bnot x))) + (move_x_to_f (rv_not (move_f_to_x x ty)) (float_int_of_same_size ty))) + +(rule 2 (lower (has_type $I128 (bnot x))) + (value_regs + (rv_not (value_regs_get x 0)) + (rv_not (value_regs_get x 1)))) + +(rule 3 (lower (has_type (ty_supported_vec ty) (bnot x))) + (rv_vnot_v x (unmasked) ty)) + +(rule 4 (lower (has_type (ty_int_ref_scalar_64 _) (bnot (bxor x y)))) + (if-let true (has_zbb)) + (rv_xnor x y)) + +;;;; Rules for `bit_reverse` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_int_ref_scalar_64 ty) (bitrev x))) + (gen_bitrev ty x)) + +(rule 1 (lower (has_type $I128 (bitrev x))) + (value_regs + (gen_bitrev $I64 (value_regs_get x 1)) + (gen_bitrev $I64 (value_regs_get x 0)))) + + +;; Constructs a sequence of instructions that reverse all bits in `x` up to +;; the given type width. +(decl gen_bitrev (Type XReg) XReg) + +(rule 0 (gen_bitrev (ty_16_or_32 (ty_int ty)) x) + (if-let shift_amt (u64_to_imm12 (u64_sub 64 (ty_bits ty)))) + (rv_srli (gen_bitrev $I64 x) shift_amt)) + +(rule 1 (gen_bitrev $I8 x) + (gen_brev8 x $I8)) + +(rule 1 (gen_bitrev $I64 x) + (gen_brev8 (gen_bswap $I64 x) $I64)) + + +;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bswap x))) + (gen_bswap ty x)) + +(rule 2 (lower (has_type $I128 (bswap x))) + (value_regs + (gen_bswap $I64 (value_regs_get x 1)) + (gen_bswap $I64 (value_regs_get x 0)))) + +;; Builds a sequence of instructions that swaps the bytes in `x` up to the given +;; type width. +(decl gen_bswap (Type XReg) XReg) + +;; This is only here to make the rule below work. bswap.i8 isn't valid +(rule 0 (gen_bswap $I8 x) x) +(rule 1 (gen_bswap (ty_int_ref_16_to_64 ty) x) + (if-let half_ty (ty_half_width ty)) + (if-let half_size (u64_to_imm12 (ty_bits half_ty))) + (let ( + ;; This swaps the top bytes and zeroes the bottom bytes, so that + ;; we can or it with the bottom bytes later. + (swap_top XReg (gen_bswap half_ty x)) + (top XReg (rv_slli swap_top half_size)) + + ;; Get the top half, swap it, and zero extend it so we can `or` it + ;; with the bottom half. Note that zero extension here already knows + ;; that `zbb` isn't available and that `half_ty` is not `$I64`, so this + ;; falls back to the shift-then-shift sequence. + (shifted XReg (rv_srli x half_size)) + (swap_bot XReg (gen_bswap half_ty shifted)) + (shift Imm12 (imm_from_bits (u64_sub 64 (ty_bits half_ty)))) + (bot_shifted_left XReg (rv_slli swap_bot shift)) + (bot XReg (rv_srli bot_shifted_left shift))) + (rv_or top bot))) + +(rule 2 (gen_bswap (ty_16_or_32 (ty_int ty)) x) + (if-let true (has_zbb)) + (if-let shift_amt (u64_to_imm12 (u64_sub 64 (ty_bits ty)))) + (rv_srli (rv_rev8 x) shift_amt)) + +(rule 3 (gen_bswap $I64 x) + (if-let true (has_zbb)) + (rv_rev8 x)) + +;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type (fits_in_64 ty) (ctz x))) + (lower_ctz ty x)) + +(rule 1 (lower (has_type $I128 (ctz x))) + (let ((x_lo XReg (value_regs_get x 0)) + (x_hi XReg (value_regs_get x 1)) + ;; Count both halves + (high XReg (lower_ctz $I64 x_hi)) + (low XReg (lower_ctz $I64 x_lo)) + ;; Only add the top half if the bottom is zero + (high XReg (gen_select_xreg (cmp_eqz x_lo) high (zero_reg))) + (result XReg (rv_add low high))) + (value_regs result (imm $I64 0)))) + +;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_64 ty) (clz x))) + (gen_cltz true x ty)) + +(rule 1 (lower (has_type $I128 (clz x))) + (let ((x_lo XReg (value_regs_get x 0)) + (x_hi XReg (value_regs_get x 1)) + ;; Count both halves + (high XReg (gen_clz x_hi)) + (low XReg (gen_clz x_lo)) + ;; Only add the bottom zeros if the top half is zero + (low XReg (gen_select_xreg (cmp_eqz x_hi) low (zero_reg)))) + (value_regs (rv_add high low) (imm $I64 0)))) + +(rule 2 (lower (has_type (fits_in_16 ty) (clz x))) + (if-let true (has_zbb)) + (let ((tmp XReg (zext x)) + (count XReg (rv_clz tmp))) + ;; We always do the operation on the full 64-bit register, so subtract 64 from the result. + (rv_addi count (imm12_const_add (ty_bits ty) -64)))) + +(rule 3 (lower (has_type $I32 (clz x))) + (if-let true (has_zbb)) + (rv_clzw x)) + +(rule 3 (lower (has_type $I64 (clz x))) + (if-let true (has_zbb)) + (rv_clz x)) + +(decl gen_clz (XReg) XReg) +(rule 0 (gen_clz rs) + (gen_cltz true rs $I64)) +(rule 1 (gen_clz rs) + (if-let true (has_zbb)) + (rv_clz rs)) + +;;;; Rules for `cls` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (fits_in_64 ty) (cls x))) + (let ((tmp XReg (sext x)) + (tmp2 XReg (gen_select_xreg (cmp_ltz tmp) (rv_not tmp) tmp)) + (tmp3 XReg (gen_clz tmp2))) + ;; clz counted the full register width, so subtract (64-$width), and then + ;; additionally subtract one more, meaning here -65+width is added. + (rv_addi tmp3 (imm12_const_add (ty_bits ty) -65)))) + +;; If the sign bit is set, we count the leading zeros of the inverted value. +;; Otherwise we can just count the leading zeros of the original value. +;; Subtract 1 since the sign bit does not count. +(rule 1 (lower (has_type $I128 (cls x))) + (let ((low XReg (value_regs_get x 0)) + (high XReg (value_regs_get x 1)) + (low XReg (gen_select_xreg (cmp_ltz high) (rv_not low) low)) + (high XReg (gen_select_xreg (cmp_ltz high) (rv_not high) high)) + + ;; Count both halves + (high_cnt XReg (gen_clz high)) + (low_cnt XReg (gen_clz low)) + ;; Only add the bottom zeros if the top half is zero + (low_cnt XReg (gen_select_xreg (cmp_eqz high) low_cnt (zero_reg))) + (count XReg (rv_add high_cnt low_cnt)) + (result XReg (rv_addi count (imm12_const -1)))) + (value_regs result (imm $I64 0)))) + + +;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_64 _) (uextend val))) + (zext val)) + +(rule 1 (lower (has_type $I128 (uextend val))) + (value_regs (zext val) (imm $I64 0))) + +;; When the source of an `uextend` is a load, we can merge both ops +(rule 2 (lower (has_type (fits_in_64 _) (uextend (sinkable_load inst ty flags addr offset)))) + (gen_sunk_load inst (amode addr offset) (uextend_load_op ty) flags)) + +(decl pure uextend_load_op (Type) LoadOP) +(rule (uextend_load_op $I8) (LoadOP.Lbu)) +(rule (uextend_load_op $I16) (LoadOP.Lhu)) +(rule (uextend_load_op $I32) (LoadOP.Lwu)) + +;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (fits_in_64 _) (sextend val @ (value_type in_ty)))) + (sext val)) + +(rule 1 (lower (has_type $I128 (sextend val @ (value_type in_ty)))) + (let ((lo XReg (sext val))) + (value_regs lo (rv_srai lo (imm12_const 63))))) + +;; When the source of an `sextend` is a load, we can merge both ops +(rule 2 (lower (has_type (fits_in_64 _) (sextend (sinkable_load inst ty flags addr offset)))) + (gen_sunk_load inst (amode addr offset) (sextend_load_op ty) flags)) + +(decl pure sextend_load_op (Type) LoadOP) +(rule (sextend_load_op $I8) (LoadOP.Lb)) +(rule (sextend_load_op $I16) (LoadOP.Lh)) +(rule (sextend_load_op $I32) (LoadOP.Lw)) + +;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 _) (popcnt x))) + (gen_popcnt (zext x))) + +(rule 1 (lower (has_type $I128 (popcnt x))) + (let + ((x ValueRegs x) + (low XReg (gen_popcnt (value_regs_get x 0))) + (high XReg (gen_popcnt (value_regs_get x 1))) + (result XReg (rv_add low high))) + (value_regs result (imm $I64 0)))) + +(rule 2 (lower (has_type (fits_in_64 _) (popcnt x))) + (if-let true (has_zbb)) + (rv_cpop (zext x))) + +(rule 3 (lower (has_type $I32 (popcnt x))) + (if-let true (has_zbb)) + (rv_cpopw x)) + +(rule 3 (lower (has_type $I128 (popcnt x))) + (if-let true (has_zbb)) + (let + ((x ValueRegs x) + (low XReg (rv_cpop (value_regs_get x 0))) + (high XReg (rv_cpop (value_regs_get x 1))) + (result XReg (rv_add low high))) + (value_regs result (imm $I64 0)))) + +;; Popcount using multiply. +;; This is popcount64c() from +;; http://en.wikipedia.org/wiki/Hamming_weight +;; +;; Here's the C version for 32 bits: +;; x = x - ((x>> 1) & 0x55555555); +;; x = (x & 0x33333333) + ((x >> 2) & 0x33333333); +;; x = ((x + (x >> 4)) & 0x0F0F0F0F); +;; return (x * 0x01010101) >> 24; // Here 24 is the type width - 8. +;; +;; TODO: LLVM generates a much better implementation for I8X16. See: https://godbolt.org/z/qr6vf9Gr3 +;; For the other types it seems to be largely the same. +(rule 4 (lower (has_type (ty_supported_vec ty) (popcnt x))) + (if-let one (u64_to_uimm5 1)) + (if-let two (u64_to_uimm5 2)) + (if-let four (u64_to_uimm5 4)) + + (let ( + ;; x = x - ((x >> 1) & 0x55555555); + (mask_55 XReg (imm (lane_type ty) (u64_and 0x5555555555555555 (ty_mask (lane_type ty))))) + (count2_shr VReg (rv_vsrl_vi x one (unmasked) ty)) + (count2_and VReg (rv_vand_vx count2_shr mask_55 (unmasked) ty)) + (count2 VReg (rv_vsub_vv x count2_and (unmasked) ty)) + + ;; x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + (mask_33 XReg (imm (lane_type ty) (u64_and 0x3333333333333333 (ty_mask (lane_type ty))))) + (count4_shr VReg (rv_vsrl_vi count2 two (unmasked) ty)) + (count4_and VReg (rv_vand_vx count4_shr mask_33 (unmasked) ty)) + (count4_lhs VReg (rv_vand_vx count2 mask_33 (unmasked) ty)) + (count4 VReg (rv_vadd_vv count4_lhs count4_and (unmasked) ty)) + + ;; x = (x + (x >> 4)) & 0x0F0F0F0F; + (mask_0f XReg (imm (lane_type ty) (u64_and 0x0f0f0f0f0f0f0f0f (ty_mask (lane_type ty))))) + (count8_shr VReg (rv_vsrl_vi count4 four (unmasked) ty)) + (count8_add VReg (rv_vadd_vv count4 count8_shr (unmasked) ty)) + (count8 VReg (rv_vand_vx count8_add mask_0f (unmasked) ty)) + + ;; (x * 0x01010101) >> ( - 8) + (mask_01 XReg (imm (lane_type ty) (u64_and 0x0101010101010101 (ty_mask (lane_type ty))))) + (mul VReg (rv_vmul_vx count8 mask_01 (unmasked) ty)) + (shift XReg (imm $I64 (u64_sub (ty_bits (lane_type ty)) 8))) + (res VReg (rv_vsrl_vx mul shift (unmasked) ty))) + res)) + +;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 8/16 bit types need a mask on the shift amount +(rule 0 (lower (has_type (ty_int (ty_8_or_16 ty)) (ishl x y))) + (if-let mask (u64_to_imm12 (ty_shift_mask ty))) + (rv_sllw x (rv_andi (value_regs_get y 0) mask))) + +;; Using the 32bit version of `sll` automatically masks the shift amount. +(rule 1 (lower (has_type $I32 (ishl x y))) + (rv_sllw x (value_regs_get y 0))) + +;; Similarly, the 64bit version does the right thing. +(rule 1 (lower (has_type $I64 (ishl x y))) + (rv_sll x (value_regs_get y 0))) + +;; If the shift amount is known. We can mask it and encode it in the instruction. +(rule 2 (lower (has_type (int_fits_in_32 ty) (ishl x (maybe_uextend (imm12_from_value y))))) + (rv_slliw x (imm12_and y (ty_shift_mask ty)))) + +;; We technically don't need to mask the shift amount here. The instruction +;; does the right thing. But it's neater when pretty printing it. +(rule 3 (lower (has_type ty @ $I64 (ishl x (maybe_uextend (imm12_from_value y))))) + (rv_slli x (imm12_and y (ty_shift_mask ty)))) + +;; With `Zba` we have a shift that zero extends the LHS argument. +(rule 4 (lower (has_type $I64 (ishl (uextend x @ (value_type $I32)) (maybe_uextend (imm12_from_value y))))) + (if-let true (has_zba)) + (rv_slliuw x y)) + +;; I128 cases +(rule 4 (lower (has_type $I128 (ishl x y))) + (let ((tmp ValueRegs (gen_shamt $I128 (value_regs_get y 0))) + (shamt XReg (value_regs_get tmp 0)) + (len_sub_shamt XReg (value_regs_get tmp 1)) + ;; + (low XReg (rv_sll (value_regs_get x 0) shamt)) + ;; high part. + (high_part1 XReg (rv_srl (value_regs_get x 0) len_sub_shamt)) + (high_part2 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) high_part1)) + ;; + (high_part3 XReg (rv_sll (value_regs_get x 1) shamt)) + (high XReg (rv_or high_part2 high_part3)) + ;; + (const64 XReg (imm $I64 64)) + (shamt_128 XReg (rv_andi (value_regs_get y 0) (imm12_const 127)))) + (gen_select_regs + (cmp_geu shamt_128 const64) + (value_regs (zero_reg) low) + (value_regs low high)))) + +;; SIMD Cases +;; We don't need to mask anything since it is done by the instruction according to SEW. + +(rule 5 (lower (has_type (ty_supported_vec ty) (ishl x y))) + (rv_vsll_vx x (value_regs_get y 0) (unmasked) ty)) + +(rule 6 (lower (has_type (ty_supported_vec ty) (ishl x (maybe_uextend (uimm5_from_value y))))) + (rv_vsll_vi x y (unmasked) ty)) + +;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 8/16 bit types need a mask on the shift amount, and the LHS needs to be +;; zero extended. +(rule 0 (lower (has_type (ty_int (fits_in_16 ty)) (ushr x y))) + (if-let mask (u64_to_imm12 (ty_shift_mask ty))) + (rv_srlw (zext x) (rv_andi (value_regs_get y 0) mask))) + +;; Using the 32bit version of `srl` automatically masks the shift amount. +(rule 1 (lower (has_type $I32 (ushr x y))) + (rv_srlw x (value_regs_get y 0))) + +;; Similarly, the 64bit version does the right thing. +(rule 1 (lower (has_type $I64 (ushr x y))) + (rv_srl x (value_regs_get y 0))) + +;; When the RHS is known we can just encode it in the instruction. +(rule 2 (lower (has_type (ty_int (fits_in_16 ty)) (ushr x (maybe_uextend (imm12_from_value y))))) + (rv_srliw (zext x) (imm12_and y (ty_shift_mask ty)))) + +(rule 3 (lower (has_type $I32 (ushr x (maybe_uextend (imm12_from_value y))))) + (rv_srliw x y)) + +(rule 3 (lower (has_type $I64 (ushr x (maybe_uextend (imm12_from_value y))))) + (rv_srli x y)) + +(rule 3 (lower (has_type $I128 (ushr x y))) + (let ((tmp ValueRegs (gen_shamt $I128 (value_regs_get y 0))) + (shamt XReg (value_regs_get tmp 0)) + (len_sub_shamt XReg (value_regs_get tmp 1)) + ;; low part. + (low_part1 XReg (rv_sll (value_regs_get x 1) len_sub_shamt)) + (low_part2 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) low_part1)) + ;; + (low_part3 XReg (rv_srl (value_regs_get x 0) shamt)) + (low XReg (rv_or low_part2 low_part3)) + ;; + (const64 XReg (imm $I64 64)) + ;; + (high XReg (rv_srl (value_regs_get x 1) shamt)) + (shamt_128 XReg (rv_andi (value_regs_get y 0) (imm12_const 127)))) + (gen_select_regs + (cmp_geu shamt_128 const64) + (value_regs high (zero_reg)) + (value_regs low high)))) + +;; SIMD Cases +;; We don't need to mask or extend anything since it is done by the instruction according to SEW. + +(rule 4 (lower (has_type (ty_supported_vec ty) (ushr x y))) + (rv_vsrl_vx x (value_regs_get y 0) (unmasked) ty)) + +(rule 5 (lower (has_type (ty_supported_vec ty) (ushr x (maybe_uextend (uimm5_from_value y))))) + (rv_vsrl_vi x y (unmasked) ty)) + +;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 8/16 bit types need a mask on the shift amount, and the LHS needs to be +;; zero extended. +(rule 0 (lower (has_type (ty_int (fits_in_16 ty)) (sshr x y))) + (if-let mask (u64_to_imm12 (ty_shift_mask ty))) + (rv_sraw (sext x) (rv_andi (value_regs_get y 0) mask))) + +;; Using the 32bit version of `sra` automatically masks the shift amount. +(rule 1 (lower (has_type $I32 (sshr x y))) + (rv_sraw x (value_regs_get y 0))) + +;; Similarly, the 64bit version does the right thing. +(rule 1 (lower (has_type $I64 (sshr x y))) + (rv_sra x (value_regs_get y 0))) + +;; When the RHS is known we can just encode it in the instruction. +(rule 2 (lower (has_type (ty_int (fits_in_16 ty)) (sshr x (maybe_uextend (imm12_from_value y))))) + (rv_sraiw (sext x) (imm12_and y (ty_shift_mask ty)))) + +(rule 3 (lower (has_type $I32 (sshr x (maybe_uextend (imm12_from_value y))))) + (rv_sraiw x y)) + +(rule 3 (lower (has_type $I64 (sshr x (maybe_uextend (imm12_from_value y))))) + (rv_srai x y)) + +(rule 3 (lower (has_type $I128 (sshr x y))) + (let ((tmp ValueRegs (gen_shamt $I128 (value_regs_get y 0))) + (shamt XReg (value_regs_get tmp 0)) + (len_sub_shamt XReg (value_regs_get tmp 1)) + ;; low part. + (low_part1 XReg (rv_sll (value_regs_get x 1) len_sub_shamt)) + (low_part2 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) low_part1)) + ;; + (low_part3 XReg (rv_srl (value_regs_get x 0) shamt)) + (low XReg (rv_or low_part2 low_part3)) + ;; + (const64 XReg (imm $I64 64)) + ;; + (high XReg (rv_sra (value_regs_get x 1) shamt)) + ;; + (const_neg_1 XReg (imm $I64 (i64_as_u64 -1))) + ;; + (high_replacement XReg (gen_select_xreg (cmp_ltz (value_regs_get x 1)) const_neg_1 (zero_reg))) + (const64 XReg (imm $I64 64)) + (shamt_128 XReg (rv_andi (value_regs_get y 0) (imm12_const 127)))) + (gen_select_regs + (cmp_geu shamt_128 const64) + (value_regs high high_replacement) + (value_regs low high)))) + +;; SIMD Cases +;; We don't need to mask or extend anything since it is done by the instruction according to SEW. + +(rule 4 (lower (has_type (ty_supported_vec ty) (sshr x y))) + (rv_vsra_vx x (value_regs_get y 0) (unmasked) ty)) + +(rule 5 (lower (has_type (ty_supported_vec ty) (sshr x (maybe_uextend (uimm5_from_value y))))) + (rv_vsra_vi x y (unmasked) ty)) + + +;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 ty) (rotl rs amount))) + (let + ((rs XReg (zext rs)) + (amount XReg (value_regs_get amount 0)) + (x ValueRegs (gen_shamt ty amount)) + (shamt XReg (value_regs_get x 0)) + (len_sub_shamt Reg (value_regs_get x 1)) + (part1 Reg (rv_sll rs shamt)) + (part2 Reg (rv_srl rs len_sub_shamt)) + (part3 Reg (gen_select_xreg (cmp_eqz shamt) (zero_reg) part2))) + (rv_or part1 part3))) + +(rule 1 (lower (has_type $I32 (rotl rs amount))) + (if-let true (has_zbb)) + (rv_rolw rs (value_regs_get amount 0))) + +(rule 2 (lower (has_type $I32 (rotl rs (u64_from_iconst n)))) + (if-let true (has_zbb)) + (if-let (imm12_from_u64 imm) (u64_sub 32 (u64_and n 31))) + (rv_roriw rs imm)) + +(rule 1 (lower (has_type $I64 (rotl rs amount))) + (if-let true (has_zbb)) + (rv_rol rs (value_regs_get amount 0))) + +(rule 2 (lower (has_type $I64 (rotl rs (u64_from_iconst n)))) + (if-let true (has_zbb)) + (if-let (imm12_from_u64 imm) (u64_sub 64 (u64_and n 63))) + (rv_rori rs imm)) + +(rule 1 (lower (has_type $I128 (rotl x y))) + (let + ((tmp ValueRegs (gen_shamt $I128 (value_regs_get y 0))) + (shamt XReg (value_regs_get tmp 0)) + (len_sub_shamt XReg (value_regs_get tmp 1)) + (low_part1 XReg (rv_sll (value_regs_get x 0) shamt)) + (low_part2 XReg (rv_srl (value_regs_get x 1) len_sub_shamt)) + ;;; if shamt == 0 low_part2 will overflow we should zero instead. + (low_part3 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) low_part2)) + (low XReg (rv_or low_part1 low_part3)) + (high_part1 XReg (rv_sll (value_regs_get x 1) shamt)) + (high_part2 XReg (rv_srl (value_regs_get x 0) len_sub_shamt)) + (high_part3 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) high_part2)) + (high XReg (rv_or high_part1 high_part3)) + (const64 XReg (imm $I64 64)) + (shamt_128 XReg (rv_andi (value_regs_get y 0) (imm12_const 127)))) + ;; right now we only rotate less than 64 bits. + ;; if shamt is greater than or equal 64 , we should switch low and high. + (gen_select_regs + (cmp_geu shamt_128 const64) + (value_regs high low) + (value_regs low high) + ))) + +;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (fits_in_64 ty) (rotr rs amount))) + (let + ((rs XReg (zext rs)) + (amount XReg (value_regs_get amount 0)) + (x ValueRegs (gen_shamt ty amount)) + (shamt XReg (value_regs_get x 0)) + (len_sub_shamt XReg (value_regs_get x 1)) + (part1 XReg (rv_srl rs shamt)) + (part2 XReg (rv_sll rs len_sub_shamt)) + (part3 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) part2))) + (rv_or part1 part3))) + +(rule 1 (lower (has_type $I32 (rotr rs amount))) + (if-let true (has_zbb)) + (rv_rorw rs (value_regs_get amount 0))) + +(rule 2 (lower (has_type $I32 (rotr rs (imm12_from_value n)))) + (if-let true (has_zbb)) + (rv_roriw rs n)) + +(rule 1 (lower (has_type $I64 (rotr rs amount))) + (if-let true (has_zbb)) + (rv_ror rs (value_regs_get amount 0))) + +(rule 2 (lower (has_type $I64 (rotr rs (imm12_from_value n)))) + (if-let true (has_zbb)) + (rv_rori rs n)) + +(rule 1 (lower (has_type $I128 (rotr x y))) + (let + ((tmp ValueRegs (gen_shamt $I128 (value_regs_get y 0))) + (shamt XReg (value_regs_get tmp 0)) + (len_sub_shamt XReg (value_regs_get tmp 1)) + (low_part1 XReg (rv_srl (value_regs_get x 0) shamt)) + (low_part2 XReg (rv_sll (value_regs_get x 1) len_sub_shamt)) + ;;; if shamt == 0 low_part2 will overflow we should zero instead. + (low_part3 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) low_part2)) + (low XReg (rv_or low_part1 low_part3)) + (high_part1 XReg (rv_srl (value_regs_get x 1) shamt)) + (high_part2 XReg (rv_sll (value_regs_get x 0) len_sub_shamt)) + (high_part3 XReg (gen_select_xreg (cmp_eqz shamt) (zero_reg) high_part2)) + (high XReg (rv_or high_part1 high_part3)) + (const64 XReg (imm $I64 64)) + (shamt_128 XReg (rv_andi (value_regs_get y 0) (imm12_const 127)))) + ;; right now we only rotate less than 64 bits. + ;; if shamt is greater than or equal 64 , we should switch low and high. + (gen_select_regs + (cmp_geu shamt_128 const64) + (value_regs high low) + (value_regs low high) + ))) + +;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fabs x))) + (rv_fabs ty x)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fabs x))) + (rv_vfabs_v x (unmasked) ty)) + +;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fneg x))) + (rv_fneg ty x)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fneg x))) + (rv_vfneg_v x (unmasked) ty)) + +;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fcopysign x y))) + (rv_fsgnj ty x y)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fcopysign x y))) + (rv_vfsgnj_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (fcopysign x (splat y)))) + (rv_vfsgnj_vf x y (unmasked) ty)) + +;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; RISC-V has 4 FMA instructions that do a slightly different computation. +;; +;; fmadd: (rs1 * rs2) + rs3 +;; fmsub: (rs1 * rs2) - rs3 +;; fnmadd: -(rs1 * rs2) - rs3 +;; fnmsub: -(rs1 * rs2) + rs3 +;; +;; Additionally there are vector versions of these instructions with slightly different names. +;; The vector instructions also have two variants each. `.vv` and `.vf`, where `.vv` variants +;; take two vector operands and the `.vf` variants take a vector operand and a scalar operand. +;; +;; Due to this, variation they receive the arguments in a different order. So we need to swap +;; the arguments below. +;; +;; vfmacc: vd[i] = +(vs1[i] * vs2[i]) + vd[i] +;; vfmsac: vd[i] = +(vs1[i] * vs2[i]) - vd[i] +;; vfnmacc: vd[i] = -(vs1[i] * vs2[i]) - vd[i] +;; vfnmsac: vd[i] = -(vs1[i] * vs2[i]) + vd[i] + +(type IsFneg (enum (Result (negate u64) (value Value)))) + +(decl pure is_fneg (Value) IsFneg) +(rule 1 (is_fneg (fneg x)) (IsFneg.Result 1 x)) +(rule 0 (is_fneg x) (IsFneg.Result 0 x)) + +(decl pure is_fneg_neg (IsFneg) u64) +(rule (is_fneg_neg (IsFneg.Result n _)) n) + +(decl pure get_fneg_value (IsFneg) Value) +(rule (get_fneg_value (IsFneg.Result _ v)) v) + +(rule (lower (has_type ty (fma x_src y_src z_src))) + (let + ((x_res IsFneg (is_fneg x_src)) + (y_res IsFneg (is_fneg y_src)) + (z_res IsFneg (is_fneg z_src)) + (x Value (get_fneg_value x_res)) + (y Value (get_fneg_value y_res)) + (z Value (get_fneg_value z_res))) + (rv_fma ty (u64_xor (is_fneg_neg x_res) (is_fneg_neg y_res)) (is_fneg_neg z_res) x y z))) + +; parity arguments indicate whether to negate the x*y term or the z term, respectively +(decl rv_fma (Type u64 u64 Value Value Value) InstOutput) +(rule 0 (rv_fma (ty_supported_float ty) 0 0 x y z) (rv_fmadd ty (FRM.RNE) x y z)) +(rule 0 (rv_fma (ty_supported_float ty) 0 1 x y z) (rv_fmsub ty (FRM.RNE) x y z)) +(rule 0 (rv_fma (ty_supported_float ty) 1 0 x y z) (rv_fnmsub ty (FRM.RNE) x y z)) +(rule 0 (rv_fma (ty_supported_float ty) 1 1 x y z) (rv_fnmadd ty (FRM.RNE) x y z)) +(rule 1 (rv_fma (ty_supported_vec ty) 0 0 x y z) (rv_vfmacc_vv z y x (unmasked) ty)) +(rule 1 (rv_fma (ty_supported_vec ty) 0 1 x y z) (rv_vfmsac_vv z y x (unmasked) ty)) +(rule 1 (rv_fma (ty_supported_vec ty) 1 0 x y z) (rv_vfnmsac_vv z y x (unmasked) ty)) +(rule 1 (rv_fma (ty_supported_vec ty) 1 1 x y z) (rv_vfnmacc_vv z y x (unmasked) ty)) +(rule 2 (rv_fma (ty_supported_vec ty) 0 0 (splat x) y z) (rv_vfmacc_vf z y x (unmasked) ty)) +(rule 2 (rv_fma (ty_supported_vec ty) 0 1 (splat x) y z) (rv_vfmsac_vf z y x (unmasked) ty)) +(rule 2 (rv_fma (ty_supported_vec ty) 1 0 (splat x) y z) (rv_vfnmsac_vf z y x (unmasked) ty)) +(rule 2 (rv_fma (ty_supported_vec ty) 1 1 (splat x) y z) (rv_vfnmacc_vf z y x (unmasked) ty)) +(rule 3 (rv_fma (ty_supported_vec ty) 0 0 x (splat y) z) (rv_vfmacc_vf z x y (unmasked) ty)) +(rule 3 (rv_fma (ty_supported_vec ty) 0 1 x (splat y) z) (rv_vfmsac_vf z x y (unmasked) ty)) +(rule 3 (rv_fma (ty_supported_vec ty) 1 0 x (splat y) z) (rv_vfnmsac_vf z x y (unmasked) ty)) +(rule 3 (rv_fma (ty_supported_vec ty) 1 1 x (splat y) z) (rv_vfnmacc_vf z x y (unmasked) ty)) + +;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (sqrt x))) + (rv_fsqrt ty (FRM.RNE) x)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (sqrt x))) + (rv_vfsqrt_v x (unmasked) ty)) + +;;;; Rules for `AtomicRMW` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule -1 + ;; + (lower + (has_type (valid_atomic_transaction ty) (atomic_rmw flags op addr x))) + (gen_atomic (get_atomic_rmw_op ty op) addr x (atomic_amo))) + +;;; for I8 and I16 +(rule 1 + (lower + (has_type (valid_atomic_transaction (fits_in_16 ty)) (atomic_rmw flags op addr x))) + (gen_atomic_rmw_loop op ty addr x)) + +;;;special for I8 and I16 max min etc. +;;;because I need uextend or sextend the value. +(rule 2 + (lower + (has_type (valid_atomic_transaction (fits_in_16 ty)) (atomic_rmw flags (is_atomic_rmw_max_etc op true) addr x))) + (gen_atomic_rmw_loop op ty addr (sext x))) + + +(rule 2 + ;; + (lower + (has_type (valid_atomic_transaction (fits_in_16 ty)) (atomic_rmw flags (is_atomic_rmw_max_etc op false) addr x))) + ;; + (gen_atomic_rmw_loop op ty addr (zext x))) + +;;;;; Rules for `AtomicRmwOp.Sub` +(rule + (lower + (has_type (valid_atomic_transaction ty) (atomic_rmw flags (AtomicRmwOp.Sub) addr x))) + (let + ((tmp WritableReg (temp_writable_reg ty)) + (x2 Reg (rv_neg x))) + (gen_atomic (get_atomic_rmw_op ty (AtomicRmwOp.Add)) addr x2 (atomic_amo)))) + +(decl gen_atomic_rmw_loop (AtomicRmwOp Type XReg XReg) XReg) +(rule + (gen_atomic_rmw_loop op ty addr x) + (let + ((dst WritableXReg (temp_writable_xreg)) + (t0 WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.AtomicRmwLoop (gen_atomic_offset addr ty) op dst ty (gen_atomic_p addr ty) x t0)))) + (writable_reg_to_reg dst))) + +;;;;; Rules for `AtomicRmwOp.Nand` +(rule + (lower + (has_type (valid_atomic_transaction ty) (atomic_rmw flags (AtomicRmwOp.Nand) addr x))) + (gen_atomic_rmw_loop (AtomicRmwOp.Nand) ty addr x)) + +(decl is_atomic_rmw_max_etc (AtomicRmwOp bool) AtomicRmwOp) +(extern extractor is_atomic_rmw_max_etc is_atomic_rmw_max_etc) + +;;;;; Rules for `atomic load`;;;;;;;;;;;;;;;;; +(rule + (lower (has_type (valid_atomic_transaction ty) (atomic_load flags p))) + (gen_atomic_load p ty)) + + +;;;;; Rules for `atomic store`;;;;;;;;;;;;;;;;; +(rule + (lower (atomic_store flags src @ (value_type (valid_atomic_transaction ty)) p)) + (gen_atomic_store p ty src)) + +(decl gen_atomic_offset (XReg Type) XReg) +(rule 1 (gen_atomic_offset p (fits_in_16 ty)) + (rv_slli (rv_andi p (imm12_const 3)) (imm12_const 3))) + +(rule (gen_atomic_offset p _) + (zero_reg)) + +(decl gen_atomic_p (XReg Type) XReg) +(rule 1 (gen_atomic_p p (fits_in_16 ty)) + (rv_andi p (imm12_const -4))) + +(rule (gen_atomic_p p _) + p) + + +;;;;; Rules for `atomic cas`;;;;;;;;;;;;;;;;; +(rule + (lower (has_type (valid_atomic_transaction ty) (atomic_cas flags p e x))) + (let + ((t0 WritableReg (temp_writable_reg ty)) + (dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AtomicCas (gen_atomic_offset p ty) t0 dst (zext e) (gen_atomic_p p ty) x ty)))) + (writable_reg_to_reg dst))) + +;;;;; Rules for `ireduce`;;;;;;;;;;;;;;;;; +(rule + (lower (has_type ty (ireduce x))) + (value_regs_get x 0)) + +;;;;; Rules for `fpromote`;;;;;;;;;;;;;;;;; +(rule (lower (fpromote x)) + (rv_fcvtds x)) + +;;;;; Rules for `fvpromote_low`;;;;;;;;;;;; + +(rule (lower (has_type (ty_supported_vec ty) (fvpromote_low x))) + (if-let half_ty (ty_half_width ty)) + (rv_vfwcvt_f_f_v x (unmasked) (vstate_mf2 half_ty))) + +;;;;; Rules for `fdemote`;;;;;;;;;;;;;;;;;; +(rule (lower (fdemote x)) + (rv_fcvtsd (FRM.RNE) x)) + +;;;;; Rules for `fvdemote`;;;;;;;;;;;;;;;;; + +;; `vfncvt...` leaves the upper bits of the register undefined so +;; we need to zero them out. +(rule (lower (has_type (ty_supported_vec ty @ $F32X4) (fvdemote x))) + (if-let zero (i8_to_imm5 0)) + (let ((narrow VReg (rv_vfncvt_f_f_w x (unmasked) (vstate_mf2 ty))) + (mask VReg (gen_vec_mask 0xC))) + (rv_vmerge_vim narrow zero mask ty))) + + +;;;;; Rules for for float arithmetic + + +;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_float ty) (fadd x y))) + (rv_fadd ty (FRM.RNE) x y)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fadd x y))) + (rv_vfadd_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (fadd x (splat y)))) + (rv_vfadd_vf x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (fadd (splat x) y))) + (rv_vfadd_vf y x (unmasked) ty)) + + +;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fsub x y))) + (rv_fsub ty (FRM.RNE) x y)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fsub x y))) + (rv_vfsub_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (fsub x (splat y)))) + (rv_vfsub_vf x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (fsub (splat x) y))) + (rv_vfrsub_vf y x (unmasked) ty)) + +;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fmul x y))) + (rv_fmul ty (FRM.RNE) x y)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fmul x y))) + (rv_vfmul_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (fmul x (splat y)))) + (rv_vfmul_vf x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (fmul (splat x) y))) + (rv_vfmul_vf y x (unmasked) ty)) + + +;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (fdiv x y))) + (rv_fdiv ty (FRM.RNE) x y)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (fdiv x y))) + (rv_vfdiv_vv x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (fdiv x (splat y)))) + (rv_vfdiv_vf x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (fdiv (splat x) y))) + (rv_vfrdiv_vf y x (unmasked) ty)) + +;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; RISC-V's `fmin` instruction returns the number input if one of inputs is a +;; NaN. We handle this by manually checking if one of the inputs is a NaN +;; and selecting based on that result. +(rule 0 (lower (has_type (ty_supported_float ty) (fmin x y))) + (let ( + ;; Check if both inputs are not nan. + (is_ordered FloatCompare (fcmp_to_float_compare (FloatCC.Ordered) ty x y)) + ;; `fadd` returns a nan if any of the inputs is a NaN. + (nan FReg (rv_fadd ty (FRM.RNE) x y)) + (min FReg (rv_fmin ty x y))) + (gen_select_freg is_ordered min nan))) + +;; With Zfa we can use the special `fminm` that precisely matches the expected +;; NaN behavior. +(rule 1 (lower (has_type (ty_supported_float ty) (fmin x y))) + (if-let true (has_zfa)) + (rv_fminm ty x y)) + +;; vfmin does almost the right thing, but it does not handle NaN's correctly. +;; We should return a NaN if any of the inputs is a NaN, but vfmin returns the +;; number input instead. +;; +;; TODO: We can improve this by using a masked `fmin` instruction that modifies +;; the canonical nan register. That way we could avoid the `vmerge.vv` instruction. +(rule 2 (lower (has_type (ty_supported_vec ty) (fmin x y))) + (let ((is_not_nan VReg (gen_fcmp_mask ty (FloatCC.Ordered) x y)) + (nan XReg (imm $I64 (canonical_nan_u64 (lane_type ty)))) + (vec_nan VReg (rv_vmv_vx nan ty)) + (min VReg (rv_vfmin_vv x y (unmasked) ty))) + (rv_vmerge_vvm vec_nan min is_not_nan ty))) + +;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; RISC-V's `fmax` instruction returns the number input if one of inputs is a +;; NaN. We handle this by manually checking if one of the inputs is a NaN +;; and selecting based on that result. +(rule 0 (lower (has_type (ty_supported_float ty) (fmax x y))) + (let ( + ;; Check if both inputs are not nan. + (is_ordered FloatCompare (fcmp_to_float_compare (FloatCC.Ordered) ty x y)) + ;; `fadd` returns a NaN if any of the inputs is a NaN. + (nan FReg (rv_fadd ty (FRM.RNE) x y)) + (max FReg (rv_fmax ty x y))) + (gen_select_freg is_ordered max nan))) + +;; With Zfa we can use the special `fmaxm` that precisely matches the expected +;; NaN behavior. +(rule 1 (lower (has_type (ty_supported_float ty) (fmax x y))) + (if-let true (has_zfa)) + (rv_fmaxm ty x y)) + +;; vfmax does almost the right thing, but it does not handle NaN's correctly. +;; We should return a NaN if any of the inputs is a NaN, but vfmax returns the +;; number input instead. +;; +;; TODO: We can improve this by using a masked `fmax` instruction that modifies +;; the canonical nan register. That way we could avoid the `vmerge.vv` instruction. +(rule 2 (lower (has_type (ty_supported_vec ty) (fmax x y))) + (let ((is_not_nan VReg (gen_fcmp_mask ty (FloatCC.Ordered) x y)) + (nan XReg (imm $I64 (canonical_nan_u64 (lane_type ty)))) + (vec_nan VReg (rv_vmv_vx nan ty)) + (max VReg (rv_vfmax_vv x y (unmasked) ty))) + (rv_vmerge_vvm vec_nan max is_not_nan ty))) + +;;;;; Rules for `stack_addr`;;;;;;;;; +(rule + (lower (stack_addr ss offset)) + (gen_stack_addr ss offset)) + +;;;;; Rules for `select`;;;;;;;;; + +;; Manually matching (iconst 0) here is a bit of a hack. We can't do that as part +;; of the iconst rule because that runs into regalloc issues. gen_select_xreg +;; has some optimizations based on the use of the zero register so we have to +;; manually match it here. +(rule 5 (lower (has_type (ty_int_ref_scalar_64 _) (select c (i64_from_iconst 0) y))) + (gen_select_xreg (is_nonzero_cmp c) (zero_reg) y)) + +(rule 4 (lower (has_type (ty_int_ref_scalar_64 _) (select c x (i64_from_iconst 0)))) + (gen_select_xreg (is_nonzero_cmp c) x (zero_reg))) + +(rule 3 (lower (has_type (ty_int_ref_scalar_64 _) (select c x y))) + (gen_select_xreg (is_nonzero_cmp c) x y)) + +(rule 2 (lower (has_type $I128 (select c x y))) + (gen_select_regs (is_nonzero_cmp c) x y)) + +(rule 1 (lower (has_type (ty_supported_vec _) (select c x y))) + (gen_select_vreg (is_nonzero_cmp c) x y)) + +(rule 0 (lower (has_type (ty_supported_float _) (select c x y))) + (gen_select_freg (is_nonzero_cmp c) x y)) + +;;;;; Rules for `bitselect`;;;;;;;;; + +;; Do a (c & x) | (~c & y) operation. +(rule 0 (lower (has_type (ty_int_ref_scalar_64 ty) (bitselect c x y))) + (let ((tmp_x XReg (rv_and c x)) + (c_inverse XReg (rv_not c)) + (tmp_y XReg (rv_and c_inverse y))) + (rv_or tmp_x tmp_y))) + +;; For vectors, we also do the same operation. +;; We can technically use any type in the bitwise operations, but prefer +;; using the type of the inputs so that we avoid emitting unnecessary +;; `vsetvl` instructions. it's likely that the vector unit is already +;; configured for that type. +(rule 1 (lower (has_type (ty_supported_vec ty) (bitselect c x y))) + (let ((tmp_x VReg (rv_vand_vv c x (unmasked) ty)) + (c_inverse VReg (rv_vnot_v c (unmasked) ty)) + (tmp_y VReg (rv_vand_vv c_inverse y (unmasked) ty))) + (rv_vor_vv tmp_x tmp_y (unmasked) ty))) + +;; Special case for bitselects with cmp's as an input. +;; +;; This allows us to skip the mask expansion step and use the more efficient +;; vmerge.vvm instruction. +;; +;; We should be careful to ensure that the mask and the vmerge have the +;; same type. So that we don't generate a mask with length 16 (i.e. for i8x16), and then +;; only copy the first few lanes of the result to the destination register because +;; the bitselect has a different length (i.e. i64x2). +;; +;; See: https://github.com/bytecodealliance/wasmtime/issues/8131 + +(rule 2 (lower (has_type (ty_supported_vec _ty) (bitselect (icmp cc a @ (value_type (ty_supported_vec cmp_ty)) b) x y))) + (let ((mask VReg (gen_icmp_mask cmp_ty cc a b))) + (rv_vmerge_vvm y x mask cmp_ty))) + +(rule 2 (lower (has_type (ty_supported_vec _ty) (bitselect (fcmp cc a @ (value_type (ty_supported_vec cmp_ty)) b) x y))) + (let ((mask VReg (gen_fcmp_mask cmp_ty cc a b))) + (rv_vmerge_vvm y x mask cmp_ty))) + +(rule 2 (lower (has_type (ty_supported_vec _ty) (bitselect (bitcast _ (fcmp cc a @ (value_type (ty_supported_vec cmp_ty)) b)) x y))) + (let ((mask VReg (gen_fcmp_mask cmp_ty cc a b))) + (rv_vmerge_vvm y x mask cmp_ty))) + +(rule 2 (lower (has_type (ty_supported_vec _ty) (bitselect (bitcast _ (icmp cc a @ (value_type (ty_supported_vec cmp_ty)) b)) x y))) + (let ((mask VReg (gen_icmp_mask cmp_ty cc a b))) + (rv_vmerge_vvm y x mask cmp_ty))) + + +;;;;; Rules for `isplit`;;;;;;;;; +(rule + (lower (isplit x)) + (let + ((t1 XReg (value_regs_get x 0)) + (t2 XReg (value_regs_get x 1))) + (output_pair t1 t2))) + +;;;;; Rules for `iconcat`;;;;;;;;; +(rule + (lower (has_type $I128 (iconcat x y))) + (let + ((t1 XReg x) + (t2 XReg y)) + (value_regs t1 t2))) + +;; Special-case the lowering of an `isplit` of a 128-bit multiply where the +;; lower bits of the result are discarded and the operands are sign or zero +;; extended. This maps directly to `umulh` and `smulh`. +(rule 1 (lower i @ (isplit (has_type $I128 (imul (uextend x) (uextend y))))) + (if-let (first_result lo) i) + (if-let true (value_is_unused lo)) + (output_pair (invalid_reg) (rv_mulhu (zext x) (zext y)))) + +(rule 1 (lower i @ (isplit (has_type $I128 (imul (sextend x) (sextend y))))) + (if-let (first_result lo) i) + (if-let true (value_is_unused lo)) + (output_pair (invalid_reg) (rv_mulh (sext x) (sext y)))) + +;;;;; Rules for `smax`;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 ty) (smax x y))) + (let ((x XReg (sext x)) + (y XReg (sext y))) + (gen_select_xreg (cmp_gt x y) x y))) + +(rule 1 (lower (has_type $I128 (smax x y))) + (gen_select_regs (icmp_to_int_compare (IntCC.SignedGreaterThan) x y) x y)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (smax x y))) + (rv_vmax_vv x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (smax x (splat y)))) + (rv_vmax_vx x y (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (smax (splat x) y))) + (rv_vmax_vx y x (unmasked) ty)) + +;;;;; Rules for `smin`;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 ty) (smin x y))) + (let ((x XReg (sext x)) + (y XReg (sext y))) + (gen_select_xreg (cmp_lt x y) x y))) + +(rule 1 (lower (has_type $I128 (smin x y))) + (gen_select_regs (icmp_to_int_compare (IntCC.SignedLessThan) x y) x y)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (smin x y))) + (rv_vmin_vv x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (smin x (splat y)))) + (rv_vmin_vx x y (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (smin (splat x) y))) + (rv_vmin_vx y x (unmasked) ty)) + +;;;;; Rules for `umax`;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 ty) (umax x y))) + (let ((x XReg (zext x)) + (y XReg (zext y))) + (gen_select_xreg (cmp_gtu x y) x y))) + +(rule 1 (lower (has_type $I128 (umax x y))) + (gen_select_regs (icmp_to_int_compare (IntCC.UnsignedGreaterThan) x y) x y)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (umax x y))) + (rv_vmaxu_vv x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (umax x (splat y)))) + (rv_vmaxu_vx x y (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (umax (splat x) y))) + (rv_vmaxu_vx y x (unmasked) ty)) + +;;;;; Rules for `umin`;;;;;;;;; + +(rule 0 (lower (has_type (fits_in_64 ty) (umin x y))) + (let ((x XReg (zext x)) + (y XReg (zext y))) + (gen_select_xreg (cmp_ltu x y) x y))) + +(rule 1 (lower (has_type $I128 (umin x y))) + (gen_select_regs (icmp_to_int_compare (IntCC.UnsignedLessThan) x y) x y)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (umin x y))) + (rv_vminu_vv x y (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (umin x (splat y)))) + (rv_vminu_vx x y (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (umin (splat x) y))) + (rv_vminu_vx y x (unmasked) ty)) + + +;;;;; Rules for `debugtrap`;;;;;;;;; +(rule + (lower (debugtrap)) + (side_effect (SideEffectNoResult.Inst (MInst.EBreak)))) + +;;;;; Rules for `fence`;;;;;;;;; +(rule + (lower (fence)) + (side_effect (SideEffectNoResult.Inst (MInst.Fence 15 15)))) + +;;;;; Rules for `trap`;;;;;;;;; +(rule + (lower (trap code)) + (udf code)) + +;;;;; Rules for `trapz`;;;;;;;;; +(rule + (lower (trapz value @ (value_type (fits_in_64 _)) code)) + (gen_trapz value code)) + +(rule 1 + (lower (trapz value @ (value_type $I128) code)) + (gen_trapif_val_i128 (ZeroCond.Zero) value code)) + +; fold icmp + trapz +(rule 2 (lower (trapz (icmp cc x @ (value_type (fits_in_64 _)) y) code)) + (gen_trapif (intcc_complement cc) x y code)) + +;;;;; Rules for `trapnz`;;;;;;;;; +(rule + (lower (trapnz value @ (value_type (fits_in_64 _)) code)) + (gen_trapnz value code)) + +(rule 1 + (lower (trapnz value @ (value_type $I128) code)) + (gen_trapif_val_i128 (ZeroCond.NonZero) value code)) + +; fold icmp + trapnz +(rule 2 (lower (trapnz (icmp cc x @ (value_type (fits_in_64 _)) y) code)) + (gen_trapif cc x y code)) + +;;;;; Rules for `uload8`;;;;;;;;; +(rule (lower (uload8 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lbu) flags)) + +;;;;; Rules for `sload8`;;;;;;;;; +(rule (lower (sload8 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lb) flags)) + +;;;;; Rules for `uload16`;;;;;;;;; +(rule (lower (uload16 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lhu) flags)) + +;;;;; Rules for `iload16`;;;;;;;;; +(rule (lower (sload16 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lh) flags)) + +;;;;; Rules for `uload32`;;;;;;;;; +(rule (lower (uload32 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lwu) flags)) + +;;;;; Rules for `sload32`;;;;;;;;; +(rule (lower (sload32 flags addr offset)) + (gen_load (amode addr offset) (LoadOP.Lw) flags)) + +;;;;; Rules for `load`;;;;;;;;; +(rule (lower (has_type ty (load flags addr offset))) + (gen_load (amode addr offset) (load_op ty) flags)) + +(rule 1 (lower (has_type $I128 (load flags addr offset))) + (if-let offset_plus_8 (s32_add_fallible offset 8)) + (let ((lo XReg (gen_load (amode addr offset) (LoadOP.Ld) flags)) + (hi XReg (gen_load (amode addr offset_plus_8) (LoadOP.Ld) flags))) + (value_regs lo hi))) + +(rule 2 (lower (has_type (ty_supported_vec ty) (load flags addr offset))) + (let ((eew VecElementWidth (element_width_from_type ty)) + (amode AMode (amode addr offset))) + (vec_load eew (VecAMode.UnitStride amode) flags (unmasked) ty))) + +;;;;; Rules for Load + Extend Combos ;;;;;;;;; + +;; These rules cover the special loads that load a 64bit value and do some sort of extension. +;; We don't have any special instructions to do this, so just load the 64 bits as a vector, and +;; do a SEW/2 extension. This only reads half width elements from the source vector register +;; extends it, and writes the back the full register. + +(decl gen_load64_extend (Type ExtendOp MemFlags AMode) VReg) + +(rule (gen_load64_extend ty (ExtendOp.Signed) flags amode) + (let ((eew VecElementWidth (element_width_from_type $I64)) + (load_state VState (vstate_from_type $I64)) + (loaded VReg (vec_load eew (VecAMode.UnitStride amode) flags (unmasked) load_state))) + (rv_vsext_vf2 loaded (unmasked) ty))) + +(rule (gen_load64_extend ty (ExtendOp.Zero) flags amode) + (let ((eew VecElementWidth (element_width_from_type $I64)) + (load_state VState (vstate_from_type $I64)) + (loaded VReg (vec_load eew (VecAMode.UnitStride amode) flags (unmasked) load_state))) + (rv_vzext_vf2 loaded (unmasked) ty))) + +;;;;; Rules for `uload8x8`;;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I16X8) (uload8x8 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Zero) flags (amode addr offset))) + +;;;;; Rules for `uload16x4`;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I32X4) (uload16x4 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Zero) flags (amode addr offset))) + +;;;;; Rules for `uload32x2`;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I64X2) (uload32x2 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Zero) flags (amode addr offset))) + +;;;;; Rules for `sload8x8`;;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I16X8) (sload8x8 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Signed) flags (amode addr offset))) + +;;;;; Rules for `sload16x4`;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I32X4) (sload16x4 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Signed) flags (amode addr offset))) + +;;;;; Rules for `sload32x2`;;;;;;;;; +(rule (lower (has_type (ty_supported_vec ty @ $I64X2) (sload32x2 flags addr offset))) + (gen_load64_extend ty (ExtendOp.Signed) flags (amode addr offset))) + +;;;;; Rules for `istore8`;;;;;;;;; +(rule (lower (istore8 flags src addr offset)) + (rv_store (amode addr offset) (StoreOP.Sb) flags src)) + +;;;;; Rules for `istore16`;;;;;;;;; +(rule (lower (istore16 flags src addr offset)) + (rv_store (amode addr offset) (StoreOP.Sh) flags src)) + +;;;;; Rules for `istore32`;;;;;;;;; +(rule (lower (istore32 flags src addr offset)) + (rv_store (amode addr offset) (StoreOP.Sw) flags src)) + +;;;;; Rules for `store`;;;;;;;;; +(rule (lower (store flags src @ (value_type ty) addr offset)) + (gen_store (amode addr offset) flags src)) + +(rule 1 (lower (store flags src @ (value_type $I128) addr offset)) + (if-let offset_plus_8 (s32_add_fallible offset 8)) + (let ((_ InstOutput (rv_store (amode addr offset) (StoreOP.Sd) flags (value_regs_get src 0)))) + (rv_store (amode addr offset_plus_8) (StoreOP.Sd) flags (value_regs_get src 1)))) + +(rule 2 (lower (store flags src @ (value_type (ty_supported_vec ty)) addr offset)) + (let ((eew VecElementWidth (element_width_from_type ty)) + (amode AMode (amode addr offset))) + (vec_store eew (VecAMode.UnitStride amode) src flags (unmasked) ty))) + + +;;;;; Rules for `icmp`;;;;;;;;; + +;; 8-64 bit comparisons. Mostly fall back onto `IntegerCompare` and then +;; materializing that, but before that happens try to match some +;; constant-related patterns + +(rule 0 (lower (icmp cc x @ (value_type (fits_in_64 ty)) y)) + (lower_icmp cc x y)) + +(decl lower_icmp (IntCC Value Value) XReg) +(rule 0 (lower_icmp cc x y) + (lower_int_compare (icmp_to_int_compare cc x y))) + +;; a == $imm => seqz(xori(..)) +(rule 1 (lower_icmp (IntCC.Equal) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) y) + (rv_seqz (rv_xori (sext x) imm))) +(rule 2 (lower_icmp (IntCC.Equal) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) x) + (rv_seqz (rv_xori (sext y) imm))) + +;; a != $imm => snez(xori(..)) +(rule 1 (lower_icmp (IntCC.NotEqual) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) y) + (rv_snez (rv_xori (sext x) imm))) +(rule 2 (lower_icmp (IntCC.NotEqual) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) x) + (rv_snez (rv_xori (sext y) imm))) + +;; a < $imm => slti(..) +(rule 1 (lower_icmp (IntCC.SignedLessThan) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) y) + (rv_slti (sext x) imm)) +(rule 1 (lower_icmp (IntCC.SignedGreaterThan) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 imm))) x) + (rv_slti (sext y) imm)) +(rule 1 (lower_icmp (IntCC.UnsignedLessThan) x y) + (if-let (u64_from_iconst (u64_nonzero (imm12_from_u64 imm))) y) + (rv_sltiu (zext x) imm)) +(rule 1 (lower_icmp (IntCC.UnsignedGreaterThan) x y) + (if-let (u64_from_iconst (u64_nonzero (imm12_from_u64 imm))) x) + (rv_sltiu (zext y) imm)) + +;; a >= $imm => !(a < $imm) +(rule 2 (lower_icmp cc @ (IntCC.SignedGreaterThanOrEqual) x y) + (if-let (i64_from_iconst (i64_nonzero (imm12_from_i64 _))) y) + (rv_xori (lower_icmp (intcc_complement cc) x y) (imm12_const 1))) +(rule 2 (lower_icmp cc @ (IntCC.UnsignedGreaterThanOrEqual) x y) + (if-let (u64_from_iconst (u64_nonzero (imm12_from_u64 _))) y) + (rv_xori (lower_icmp (intcc_complement cc) x y) (imm12_const 1))) + +;; Materializes an `IntegerCompare` bundle directly into an `XReg` with a 0 +;; or 1 value. +(decl lower_int_compare (IntegerCompare) XReg) + +;; x == y => x ^ y == 0 +(rule 0 (lower_int_compare (int_compare_decompose (IntCC.Equal) x y)) + (rv_seqz (rv_xor x y))) +(rule 1 (lower_int_compare (int_compare_decompose (IntCC.Equal) x (zero_reg))) + (rv_seqz x)) +(rule 2 (lower_int_compare (int_compare_decompose (IntCC.Equal) (zero_reg) y)) + (rv_seqz y)) +;; x != y => x ^ y != 0 +(rule 0 (lower_int_compare (int_compare_decompose (IntCC.NotEqual) x y)) + (rv_snez (rv_xor x y))) +(rule 1 (lower_int_compare (int_compare_decompose (IntCC.NotEqual) x (zero_reg))) + (rv_snez x)) +(rule 2 (lower_int_compare (int_compare_decompose (IntCC.NotEqual) (zero_reg) x)) + (rv_snez x)) +;; x < y => x < y +(rule (lower_int_compare (int_compare_decompose (IntCC.SignedLessThan) x y)) + (rv_slt x y)) +(rule (lower_int_compare (int_compare_decompose (IntCC.UnsignedLessThan) x y)) + (rv_sltu x y)) +;; x > y => y < x +(rule (lower_int_compare (int_compare_decompose (IntCC.SignedGreaterThan) x y)) + (rv_slt y x)) +(rule (lower_int_compare (int_compare_decompose (IntCC.UnsignedGreaterThan) x y)) + (rv_sltu y x)) +;; x <= y => !(y < x) +(rule (lower_int_compare (int_compare_decompose (IntCC.SignedLessThanOrEqual) x y)) + (rv_xori (rv_slt y x) (imm12_const 1))) +(rule (lower_int_compare (int_compare_decompose (IntCC.UnsignedLessThanOrEqual) x y)) + (rv_xori (rv_sltu y x) (imm12_const 1))) +;; x >= y => !(x < y) +(rule (lower_int_compare (int_compare_decompose (IntCC.SignedGreaterThanOrEqual) x y)) + (rv_xori (rv_slt x y) (imm12_const 1))) +(rule (lower_int_compare (int_compare_decompose (IntCC.UnsignedGreaterThanOrEqual) x y)) + (rv_xori (rv_sltu x y) (imm12_const 1))) + +;; 128-bit comparisons. +;; +;; Currently only `==`, `!=`, and `<` are implemented, and everything else +;; delegates to one of those. + +(rule 20 (lower (icmp cc x @ (value_type $I128) y)) + (lower_icmp_i128 cc x y)) + +(decl lower_icmp_i128 (IntCC ValueRegs ValueRegs) XReg) +(rule 0 (lower_icmp_i128 (IntCC.Equal) x y) + (let ((lo XReg (rv_xor (value_regs_get x 0) (value_regs_get y 0))) + (hi XReg (rv_xor (value_regs_get x 1) (value_regs_get y 1)))) + (rv_seqz (rv_or lo hi)))) +(rule 0 (lower_icmp_i128 (IntCC.NotEqual) x y) + (let ((lo XReg (rv_xor (value_regs_get x 0) (value_regs_get y 0))) + (hi XReg (rv_xor (value_regs_get x 1) (value_regs_get y 1)))) + (rv_snez (rv_or lo hi)))) + +;; swap args for `>` to use `<` instead +(rule 0 (lower_icmp_i128 cc @ (IntCC.SignedGreaterThan) x y) + (lower_icmp_i128 (intcc_swap_args cc) y x)) +(rule 0 (lower_icmp_i128 cc @ (IntCC.UnsignedGreaterThan) x y) + (lower_icmp_i128 (intcc_swap_args cc) y x)) + +;; complement `=`-related conditions to get ones that don't use `=`. +(rule 0 (lower_icmp_i128 cc @ (IntCC.SignedLessThanOrEqual) x y) + (rv_xori (lower_icmp_i128 (intcc_complement cc) x y) (imm12_const 1))) +(rule 0 (lower_icmp_i128 cc @ (IntCC.SignedGreaterThanOrEqual) x y) + (rv_xori (lower_icmp_i128 (intcc_complement cc) x y) (imm12_const 1))) +(rule 0 (lower_icmp_i128 cc @ (IntCC.UnsignedLessThanOrEqual) x y) + (rv_xori (lower_icmp_i128 (intcc_complement cc) x y) (imm12_const 1))) +(rule 0 (lower_icmp_i128 cc @ (IntCC.UnsignedGreaterThanOrEqual) x y) + (rv_xori (lower_icmp_i128 (intcc_complement cc) x y) (imm12_const 1))) + +;; Compare both the bottom and upper halves of the 128-bit values. If +;; the top half is equal use the bottom comparison, otherwise use the upper +;; comparison. Note that the lower comparison is always unsigned since if it's +;; used the top halves are all zeros and the semantic values are positive. +(rule 1 (lower_icmp_i128 cc x y) + (if-let (IntCC.UnsignedLessThan) (intcc_unsigned cc)) + (let ((x_lo Reg (value_regs_get x 0)) + (x_hi Reg (value_regs_get x 1)) + (y_lo Reg (value_regs_get y 0)) + (y_hi Reg (value_regs_get y 1)) + (top_cmp XReg (lower_int_compare (int_compare cc x_hi y_hi))) + (bottom_cmp XReg (rv_sltu x_lo y_lo))) + (gen_select_xreg (cmp_eqz (rv_xor x_hi y_hi)) bottom_cmp top_cmp))) + +;; vector icmp comparisons + +(rule 30 (lower (icmp cc x @ (value_type (ty_supported_vec ty)) y)) + (gen_expand_mask ty (gen_icmp_mask ty cc x y))) + +;;;;; Rules for `fcmp`;;;;;;;;; +(rule 0 (lower (fcmp cc x @ (value_type (ty_supported_float ty)) y)) + (lower_float_compare (fcmp_to_float_compare cc ty x y))) + +(decl lower_float_compare (FloatCompare) XReg) +(rule (lower_float_compare (FloatCompare.One r)) r) +(rule (lower_float_compare (FloatCompare.Zero r)) (rv_seqz r)) + +(rule 1 (lower (fcmp cc x @ (value_type (ty_supported_vec ty)) y)) + (gen_expand_mask ty (gen_fcmp_mask ty cc x y))) + +;;;;; Rules for `func_addr`;;;;;;;;; +(rule + (lower (func_addr (func_ref_data _ name _))) + (load_ext_name name 0)) + +;;;;; Rules for `fcvt_to_uint`;;;;;;;;; + +;; RISC-V float-to-integer conversion does not trap, but Cranelift semantics are +;; to trap. This manually performs checks for NaN and out-of-bounds values and +;; traps in such cases. +;; +;; TODO: could this perhaps be more optimal through inspection of the `fcsr`? +;; Unsure whether that needs to be preserved across function calls and/or would +;; cause other problems. Also unsure whether it's actually more performant. +(rule (lower (has_type ity (fcvt_to_uint v @ (value_type fty)))) + (let ((_ InstOutput (gen_trapz (rv_feq fty v v) (TrapCode.BAD_CONVERSION_TO_INTEGER))) + (min FReg (imm fty (fcvt_umin_bound fty false))) + (_ InstOutput (gen_trapnz (rv_fle fty v min) (TrapCode.INTEGER_OVERFLOW))) + (max FReg (imm fty (fcvt_umax_bound fty ity false))) + (_ InstOutput (gen_trapnz (rv_fge fty v max) (TrapCode.INTEGER_OVERFLOW)))) + (lower_inbounds_fcvt_to_uint ity fty v))) + +(decl lower_inbounds_fcvt_to_uint (Type Type FReg) XReg) +(rule 0 (lower_inbounds_fcvt_to_uint (fits_in_32 _) fty v) + (rv_fcvtwu fty (FRM.RTZ) v)) +(rule 1 (lower_inbounds_fcvt_to_uint $I64 fty v) + (rv_fcvtlu fty (FRM.RTZ) v)) + +;;;;; Rules for `fcvt_to_sint`;;;;;;;;; + +;; NB: see above with `fcvt_to_uint` as this is similar +(rule (lower (has_type ity (fcvt_to_sint v @ (value_type fty)))) + (let ((_ InstOutput (gen_trapz (rv_feq fty v v) (TrapCode.BAD_CONVERSION_TO_INTEGER))) + (min FReg (imm fty (fcvt_smin_bound fty ity false))) + (_ InstOutput (gen_trapnz (rv_fle fty v min) (TrapCode.INTEGER_OVERFLOW))) + (max FReg (imm fty (fcvt_smax_bound fty ity false))) + (_ InstOutput (gen_trapnz (rv_fge fty v max) (TrapCode.INTEGER_OVERFLOW)))) + (lower_inbounds_fcvt_to_sint ity fty v))) + +(decl lower_inbounds_fcvt_to_sint (Type Type FReg) XReg) +(rule 0 (lower_inbounds_fcvt_to_sint (fits_in_32 _) fty v) + (rv_fcvtw fty (FRM.RTZ) v)) +(rule 1 (lower_inbounds_fcvt_to_sint $I64 fty v) + (rv_fcvtl fty (FRM.RTZ) v)) + +;;;;; Rules for `fcvt_to_sint_sat`;;;;;;;;; + +(rule 0 (lower (has_type to (fcvt_to_sint_sat v @ (value_type (ty_supported_float from))))) + (handle_fcvt_to_int_nan from v (lower_fcvt_to_sint_sat from to v))) + +;; Lowers to a `rv_fcvt*` instruction but handles 8/16-bit cases where the +;; float is clamped before the conversion. +(decl lower_fcvt_to_sint_sat (Type Type FReg) XReg) +(rule 0 (lower_fcvt_to_sint_sat ty (fits_in_16 out_ty) v) + (let ((max FReg (imm ty (fcvt_smax_bound ty out_ty true))) + (min FReg (imm ty (fcvt_smin_bound ty out_ty true))) + (clamped FReg (rv_fmin ty max (rv_fmax ty min v)))) + (rv_fcvtw ty (FRM.RTZ) clamped))) +(rule 1 (lower_fcvt_to_sint_sat ty $I32 v) (rv_fcvtw ty (FRM.RTZ) v)) +(rule 1 (lower_fcvt_to_sint_sat ty $I64 v) (rv_fcvtl ty (FRM.RTZ) v)) + +(decl fcvt_smax_bound (Type Type bool) u64) +(extern constructor fcvt_smax_bound fcvt_smax_bound) +(decl fcvt_smin_bound (Type Type bool) u64) +(extern constructor fcvt_smin_bound fcvt_smin_bound) + +;; RISC-V float-to-int conversions generate the same output for NaN and +Inf, +;; but Cranelift semantics are to produce 0 for NaN instead. This helper +;; translates these semantics by taking the float being converted (with the type +;; specified) and the native RISC-V output as an `XReg`. The returned `XReg` +;; will be zeroed out if the float is NaN. +;; +;; This is done by comparing the float to itself, generating 0 if it's NaN. This +;; bit is then negated to become either all-ones or all-zeros which is then +;; and-ed against the native output. That'll produce all zeros if the input is +;; NaN or the native output otherwise. +(decl handle_fcvt_to_int_nan (Type FReg XReg) XReg) +(rule (handle_fcvt_to_int_nan ty freg xreg) + (let ((is_not_nan XReg (rv_feq ty freg freg)) + (not_nan_mask XReg (rv_neg is_not_nan))) + (rv_and xreg not_nan_mask))) + +(rule 1 (lower (has_type (ty_supported_vec _) (fcvt_to_sint_sat v @ (value_type from_ty)))) + (if-let zero (i8_to_imm5 0)) + (let ((is_nan VReg (rv_vmfne_vv v v (unmasked) from_ty)) + (cvt VReg (rv_vfcvt_rtz_x_f_v v (unmasked) from_ty))) + (rv_vmerge_vim cvt zero is_nan from_ty))) + +;;;;; Rules for `fcvt_to_uint_sat`;;;;;;;;; + +(rule 0 (lower (has_type to (fcvt_to_uint_sat v @ (value_type (ty_supported_float from))))) + (handle_fcvt_to_int_nan from v (lower_fcvt_to_uint_sat from to v))) + +;; Lowers to a `rv_fcvt*` instruction but handles 8/16-bit cases where the +;; float is clamped before the conversion. +(decl lower_fcvt_to_uint_sat (Type Type FReg) XReg) +(rule 0 (lower_fcvt_to_uint_sat ty (fits_in_16 out_ty) v) + (let ((max FReg (imm ty (fcvt_umax_bound ty out_ty true))) + (min FReg (rv_fmvdx (zero_reg))) + (clamped FReg (rv_fmin ty max (rv_fmax ty min v)))) + (rv_fcvtwu ty (FRM.RTZ) clamped))) +(rule 1 (lower_fcvt_to_uint_sat ty $I32 v) (rv_fcvtwu ty (FRM.RTZ) v)) +(rule 1 (lower_fcvt_to_uint_sat ty $I64 v) (rv_fcvtlu ty (FRM.RTZ) v)) + +(decl fcvt_umax_bound (Type Type bool) u64) +(extern constructor fcvt_umax_bound fcvt_umax_bound) +(decl fcvt_umin_bound (Type bool) u64) +(extern constructor fcvt_umin_bound fcvt_umin_bound) + +(rule 1 (lower (has_type (ty_supported_vec _) (fcvt_to_uint_sat v @ (value_type from_ty)))) + (if-let zero (i8_to_imm5 0)) + (let ((is_nan VReg (rv_vmfne_vv v v (unmasked) from_ty)) + (cvt VReg (rv_vfcvt_rtz_xu_f_v v (unmasked) from_ty))) + (rv_vmerge_vim cvt zero is_nan from_ty))) + +;;;;; Rules for `fcvt_from_sint`;;;;;;;;; +(rule 0 (lower (has_type $F32 (fcvt_from_sint v @ (value_type (fits_in_16 ty))))) + (rv_fcvtsl (FRM.RNE) (sext v))) + +(rule 1 (lower (has_type $F32 (fcvt_from_sint v @ (value_type $I32)))) + (rv_fcvtsw (FRM.RNE) v)) + +(rule 1 (lower (has_type $F32 (fcvt_from_sint v @ (value_type $I64)))) + (rv_fcvtsl (FRM.RNE) v)) + +(rule 0 (lower (has_type $F64 (fcvt_from_sint v @ (value_type (fits_in_16 ty))))) + (rv_fcvtdl (FRM.RNE) (sext v))) + +(rule 1 (lower (has_type $F64 (fcvt_from_sint v @ (value_type $I32)))) + (rv_fcvtdw v)) + +(rule 1 (lower (has_type $F64 (fcvt_from_sint v @ (value_type $I64)))) + (rv_fcvtdl (FRM.RNE) v)) + +(rule 2 (lower (has_type (ty_supported_vec _) (fcvt_from_sint v @ (value_type from_ty)))) + (rv_vfcvt_f_x_v v (unmasked) from_ty)) + +;;;;; Rules for `fcvt_from_uint`;;;;;;;;; +(rule 0 (lower (has_type $F32 (fcvt_from_uint v @ (value_type (fits_in_16 ty))))) + (rv_fcvtslu (FRM.RNE) (zext v))) + +(rule 1 (lower (has_type $F32 (fcvt_from_uint v @ (value_type $I32)))) + (rv_fcvtswu (FRM.RNE) v)) + +(rule 1 (lower (has_type $F32 (fcvt_from_uint v @ (value_type $I64)))) + (rv_fcvtslu (FRM.RNE) v)) + +(rule 0 (lower (has_type $F64 (fcvt_from_uint v @ (value_type (fits_in_16 ty))))) + (rv_fcvtdlu (FRM.RNE) (zext v))) + +(rule 1 (lower (has_type $F64 (fcvt_from_uint v @ (value_type $I32)))) + (rv_fcvtdwu v)) + +(rule 1 (lower (has_type $F64 (fcvt_from_uint v @ (value_type $I64)))) + (rv_fcvtdlu (FRM.RNE) v)) + +(rule 2 (lower (has_type (ty_supported_vec _) (fcvt_from_uint v @ (value_type from_ty)))) + (rv_vfcvt_f_xu_v v (unmasked) from_ty)) + +;;;;; Rules for `symbol_value`;;;;;;;;; +(rule + (lower (symbol_value (symbol_value_data name _ offset))) + (load_ext_name name offset)) + +;;;;; Rules for `tls_value` ;;;;;;;;;;;;;; + +(rule (lower (has_type (tls_model (TlsModel.ElfGd)) (tls_value (symbol_value_data name _ _)))) + (elf_tls_get_addr name)) + +;;;;; Rules for `bitcast`;;;;;;;;; + +;; These rules should probably be handled in `gen_bitcast`, but it's convenient to have that return +;; a single register, instead of a `ValueRegs` +(rule 3 (lower (has_type $I128 (bitcast _ v @ (value_type (ty_supported_vec _))))) + (value_regs + (gen_extractlane $I64X2 v 0) + (gen_extractlane $I64X2 v 1))) + +;; Move the high half into a vector register, and then use vslide1up to move it up and +;; insert the lower half in one instruction. +(rule 2 (lower (has_type (ty_supported_vec _) (bitcast _ v @ (value_type $I128)))) + (let ((lo XReg (value_regs_get v 0)) + (hi XReg (value_regs_get v 1)) + (vstate VState (vstate_from_type $I64X2)) + (vec VReg (rv_vmv_sx hi vstate))) + (rv_vslide1up_vx vec vec lo (unmasked) vstate))) + +;; `gen_bitcast` below only works with single register values, so handle I128 +;; specially here. +(rule 1 (lower (has_type $I128 (bitcast _ v @ (value_type $I128)))) + v) + +(rule 0 (lower (has_type out_ty (bitcast _ v @ (value_type in_ty)))) + (gen_bitcast v in_ty out_ty)) + +;;;;; Rules for `ceil`;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (ceil x))) + (gen_float_round (FRM.RUP) x ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (ceil x))) + (gen_vec_round x (FRM.RUP) ty)) + +;;;;; Rules for `floor`;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (floor x))) + (gen_float_round (FRM.RDN) x ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (floor x))) + (gen_vec_round x (FRM.RDN) ty)) + +;;;;; Rules for `trunc`;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (trunc x))) + (gen_float_round (FRM.RTZ) x ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (trunc x))) + (gen_vec_round x (FRM.RTZ) ty)) + +;;;;; Rules for `nearest`;;;;;;;;; +(rule 0 (lower (has_type (ty_supported_float ty) (nearest x))) + (gen_float_round (FRM.RNE) x ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (nearest x))) + (gen_vec_round x (FRM.RNE) ty)) + + +;;;;; Rules for `select_spectre_guard`;;;;;;;;; + +;; SelectSpectreGuard is equivalent to Select, but we should not use a branch based +;; lowering for it. Instead we use a conditional move based lowering. +;; +;; We don't have cmov's in RISC-V either, but we can emulate those using bitwise +;; operations, which is what we do below. + +;; Base case: use `gen_bmask` to generate a 0 mask or -1 mask from the value of +;; `cmp`. This is then used with some bit twiddling to produce the final result. +(rule 0 (lower (has_type (fits_in_64 _) (select_spectre_guard cmp x y))) + (let ((mask XReg (gen_bmask cmp))) + (rv_or (rv_and mask x) (rv_andn y mask)))) +(rule 1 (lower (has_type $I128 (select_spectre_guard cmp x y))) + (let ((mask XReg (gen_bmask cmp))) + (value_regs + (rv_or (rv_and mask (value_regs_get x 0)) (rv_andn (value_regs_get y 0) mask)) + (rv_or (rv_and mask (value_regs_get x 1)) (rv_andn (value_regs_get y 1) mask))))) + +;; Special case when an argument is the constant zero as some ands and ors +;; can be folded away. +(rule 2 (lower (has_type (fits_in_64 _) (select_spectre_guard cmp (i64_from_iconst 0) y))) + (rv_andn y (gen_bmask cmp))) +(rule 3 (lower (has_type (fits_in_64 _) (select_spectre_guard cmp x (i64_from_iconst 0)))) + (rv_and x (gen_bmask cmp))) + +;;;;; Rules for `bmask`;;;;;;;;; +(rule + (lower (has_type oty (bmask x))) + (lower_bmask x oty)) + +;; N.B.: the Ret itself is generated by the ABI. +(rule (lower (return args)) + (lower_return args)) + +;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;; + +(rule (lower (get_frame_pointer)) + (gen_mov_from_preg (fp_reg))) + +(rule (lower (get_stack_pointer)) + (gen_mov_from_preg (sp_reg))) + +(rule (lower (get_return_address)) + (load_ra)) + +;;; Rules for `iabs` ;;;;;;;;;;;;; + +;; I64 and lower +;; Generate the following code: +;; sext.{b,h,w} a0, a0 +;; neg a1, a0 +;; max a0, a0, a1 +(rule 0 (lower (has_type (ty_int_ref_scalar_64 ty) (iabs x))) + (let ((extended XReg (sext x)) + (negated XReg (rv_neg extended))) + (gen_select_xreg (cmp_gt extended negated) extended negated))) + +;; For vectors we generate the same code, but with vector instructions +;; we can skip the sign extension, since the vector unit will only process +;; Element Sized chunks. +(rule 1 (lower (has_type (ty_supported_vec ty) (iabs x))) + (let ((negated VReg (rv_vneg_v x (unmasked) ty))) + (rv_vmax_vv x negated (unmasked) ty))) + +;;;; Rules for calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (call (func_ref_data sig_ref extname dist) inputs)) + (gen_call sig_ref extname dist inputs)) + +(rule (lower (call_indirect sig_ref val inputs)) + (gen_call_indirect sig_ref val inputs)) + +;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (return_call (func_ref_data sig_ref extname dist) args)) + (gen_return_call sig_ref extname dist args)) + +(rule (lower (return_call_indirect sig_ref callee args)) + (gen_return_call_indirect sig_ref callee args)) + + +;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (extractlane x @ (value_type ty) (u8_from_uimm8 idx))) + (gen_extractlane ty x idx)) + +;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We can insert a lane by using a masked splat from an X register. +;; Build a mask that is only enabled in the lane we want to insert. +;; Then use a masked splat (vmerge) to insert the value. +(rule 0 (lower (insertlane vec @ (value_type (ty_supported_vec ty)) + val @ (value_type (ty_int _)) + (u8_from_uimm8 lane))) + (let ((mask VReg (gen_vec_mask (u64_shl 1 lane)))) + (rv_vmerge_vxm vec val mask ty))) + +;; Similar to above, but using the float variants of the instructions. +(rule 1 (lower (insertlane vec @ (value_type (ty_supported_vec ty)) + val @ (value_type (ty_supported_float _)) + (u8_from_uimm8 lane))) + (let ((mask VReg (gen_vec_mask (u64_shl 1 lane)))) + (rv_vfmerge_vfm vec val mask ty))) + +;; If we are inserting from an Imm5 const we can use the immediate +;; variant of vmerge. +(rule 2 (lower (insertlane vec @ (value_type (ty_supported_vec ty)) + (i64_from_iconst (imm5_from_i64 imm)) + (u8_from_uimm8 lane))) + (let ((mask VReg (gen_vec_mask (u64_shl 1 lane)))) + (rv_vmerge_vim vec imm mask ty))) + +;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type ty (splat n @ (value_type (ty_supported_float _))))) + (rv_vfmv_vf n ty)) + +(rule 1 (lower (has_type ty (splat n @ (value_type (ty_int_ref_scalar_64 _))))) + (rv_vmv_vx n ty)) + +(rule 2 (lower (has_type ty (splat (iconst (u64_from_imm64 (imm5_from_u64 imm)))))) + (rv_vmv_vi imm ty)) + +;; TODO: We can splat out more patterns by using for example a vmv.v.i i8x16 for +;; a i64x2 const with a compatible bit pattern. The AArch64 Backend does something +;; similar in its splat rules. +;; TODO: Look through bitcasts when splatting out registers. We can use +;; `vmv.v.x` in a `(splat.f32x4 (bitcast.f32 val))`. And vice versa for integers. + +;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (uadd_sat x y))) + (rv_vsaddu_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (uadd_sat x (splat y)))) + (rv_vsaddu_vx x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (uadd_sat (splat x) y))) + (rv_vsaddu_vx y x (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (uadd_sat x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vsaddu_vi x y_imm (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (uadd_sat x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vsaddu_vi y x_imm (unmasked) ty)) + +;;;; Rules for `sadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (sadd_sat x y))) + (rv_vsadd_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (sadd_sat x (splat y)))) + (rv_vsadd_vx x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (sadd_sat (splat x) y))) + (rv_vsadd_vx y x (unmasked) ty)) + +(rule 3 (lower (has_type (ty_supported_vec ty) (sadd_sat x y))) + (if-let y_imm (replicated_imm5 y)) + (rv_vsadd_vi x y_imm (unmasked) ty)) + +(rule 4 (lower (has_type (ty_supported_vec ty) (sadd_sat x y))) + (if-let x_imm (replicated_imm5 x)) + (rv_vsadd_vi y x_imm (unmasked) ty)) + +;;;; Rules for `usub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (usub_sat x y))) + (rv_vssubu_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (usub_sat x (splat y)))) + (rv_vssubu_vx x y (unmasked) ty)) + +;;;; Rules for `ssub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (ssub_sat x y))) + (rv_vssub_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (ssub_sat x (splat y)))) + (rv_vssub_vx x y (unmasked) ty)) + +;;;; Rules for `vall_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Here we do a Vector Reduce operation. Get the unsigned minimum value of any +;; lane in the vector. The fixed input to the reduce operation is a 1. +;; This way, if any lane is 0, the result will be 0. Otherwise, the result will +;; be a 1. +;; The reduce operation leaves the result in the lowest lane, we then move it +;; into the destination X register. +(rule (lower (vall_true x @ (value_type (ty_supported_vec ty)))) + (if-let one (i8_to_imm5 1)) + ;; We don't need to broadcast the immediate into all lanes, only into lane 0. + ;; I did it this way since it uses one less instruction than with a vmv.s.x. + (let ((fixed VReg (rv_vmv_vi one ty)) + (min VReg (rv_vredminu_vs x fixed (unmasked) ty))) + (rv_vmv_xs min ty))) + + +;;;; Rules for `vany_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Here we do a Vector Reduce operation. Get the unsigned maximum value of the +;; input vector register. Move the max to an X register, and do a `snez` on it +;; to ensure its either 1 or 0. +(rule (lower (vany_true x @ (value_type (ty_supported_vec ty)))) + (let ((max VReg (rv_vredmaxu_vs x x (unmasked) ty)) + (x_max XReg (rv_vmv_xs max ty))) + (rv_snez x_max))) + + +;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; To check if the MSB of a lane is set, we do a `vmslt` with zero, this sets +;; the mask bit to 1 if the value is negative (MSB 1) and 0 if not. We can then +;; just move that mask to an X Register. +;; +;; We must ensure that the move to the X register has a SEW with enough bits +;; to hold the full mask. Additionally, in some cases (e.g. i64x2) we are going +;; to read some tail bits. These are undefined, so we need to further mask them +;; off. +(rule (lower (vhigh_bits x @ (value_type (ty_supported_vec ty)))) + (let ((mask VReg (rv_vmslt_vx x (zero_reg) (unmasked) ty)) + ;; Here we only need I64X1, but emit an AVL of 2 since it + ;; saves one vector state change in the case of I64X2. + ;; + ;; TODO: For types that have more lanes than element bits, we can + ;; use the original type as a VState and avoid a state change. + (x_mask XReg (rv_vmv_xs mask (vstate_from_type $I64X2)))) + (gen_andi x_mask (ty_lane_mask ty)))) + +;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (swizzle x y))) + (rv_vrgather_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (swizzle x (splat y)))) + (rv_vrgather_vx x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (swizzle x y))) + (if-let y_imm (replicated_uimm5 y)) + (rv_vrgather_vi x y_imm (unmasked) ty)) + +;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Use a vrgather to load all 0-15 lanes from x. And then modify the mask to load all +;; 16-31 lanes from y. Finally, use a vor to combine the two vectors. +;; +;; vrgather will insert a 0 for lanes that are out of bounds, so we can let it load +;; negative and out of bounds indexes. +(rule (lower (has_type (ty_supported_vec ty @ $I8X16) (shuffle x y (vconst_from_immediate mask)))) + (if-let neg16 (i8_to_imm5 -16)) + (let ((x_mask VReg (gen_constant ty mask)) + (x_lanes VReg (rv_vrgather_vv x x_mask (unmasked) ty)) + (y_mask VReg (rv_vadd_vi x_mask neg16 (unmasked) ty)) + (y_lanes VReg (rv_vrgather_vv y y_mask (unmasked) ty))) + (rv_vor_vv x_lanes y_lanes (unmasked) ty))) + +;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Slide down half the vector, and do a signed extension. +(rule 0 (lower (has_type (ty_supported_vec out_ty) (swiden_high x @ (value_type in_ty)))) + (rv_vsext_vf2 (gen_slidedown_half in_ty x) (unmasked) out_ty)) + +(rule 1 (lower (has_type (ty_supported_vec out_ty) (swiden_high (swiden_high x @ (value_type in_ty))))) + (if-let (uimm5_from_u64 amt) (u64_sub (ty_lane_count in_ty) (ty_lane_count out_ty))) + (rv_vsext_vf4 (rv_vslidedown_vi x amt (unmasked) in_ty) (unmasked) out_ty)) + +(rule 2 (lower (has_type (ty_supported_vec out_ty) (swiden_high (swiden_high (swiden_high x @ (value_type in_ty)))))) + (if-let (uimm5_from_u64 amt) (u64_sub (ty_lane_count in_ty) (ty_lane_count out_ty))) + (rv_vsext_vf8 (rv_vslidedown_vi x amt (unmasked) in_ty) (unmasked) out_ty)) + +;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Slide down half the vector, and do a zero extension. +(rule 0 (lower (has_type (ty_supported_vec out_ty) (uwiden_high x @ (value_type in_ty)))) + (rv_vzext_vf2 (gen_slidedown_half in_ty x) (unmasked) out_ty)) + +(rule 1 (lower (has_type (ty_supported_vec out_ty) (uwiden_high (uwiden_high x @ (value_type in_ty))))) + (if-let (uimm5_from_u64 amt) (u64_sub (ty_lane_count in_ty) (ty_lane_count out_ty))) + (rv_vzext_vf4 (rv_vslidedown_vi x amt (unmasked) in_ty) (unmasked) out_ty)) + +(rule 2 (lower (has_type (ty_supported_vec out_ty) (uwiden_high (uwiden_high (uwiden_high x @ (value_type in_ty)))))) + (if-let (uimm5_from_u64 amt) (u64_sub (ty_lane_count in_ty) (ty_lane_count out_ty))) + (rv_vzext_vf8 (rv_vslidedown_vi x amt (unmasked) in_ty) (unmasked) out_ty)) + +;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec out_ty) (swiden_low x))) + (rv_vsext_vf2 x (unmasked) out_ty)) + +(rule 1 (lower (has_type (ty_supported_vec out_ty) (swiden_low (swiden_low x)))) + (rv_vsext_vf4 x (unmasked) out_ty)) + +(rule 2 (lower (has_type (ty_supported_vec out_ty) (swiden_low (swiden_low (swiden_low x))))) + (rv_vsext_vf8 x (unmasked) out_ty)) + +;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec out_ty) (uwiden_low x))) + (rv_vzext_vf2 x (unmasked) out_ty)) + +(rule 1 (lower (has_type (ty_supported_vec out_ty) (uwiden_low (uwiden_low x)))) + (rv_vzext_vf4 x (unmasked) out_ty)) + +(rule 2 (lower (has_type (ty_supported_vec out_ty) (uwiden_low (uwiden_low (uwiden_low x))))) + (rv_vzext_vf8 x (unmasked) out_ty)) + +;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We don't have a dedicated instruction for this, rearrange the register elements +;; and use a vadd. +;; +;; We do this by building two masks, one for the even elements and one for the odd +;; elements. Using vcompress we can extract the elements and group them together. +;; +;; This is likely not the optimal way of doing this. LLVM does this using a bunch +;; of vrgathers (See: https://godbolt.org/z/jq8Wj8WG4), that doesn't seem to be +;; too much better than this. +;; +;; However V8 does something better. They use 2 vcompresses using LMUL2, that means +;; that they can do the whole thing in 3 instructions (2 vcompress + vadd). We don't +;; support LMUL > 1, so we can't do that. +(rule (lower (has_type (ty_supported_vec ty) (iadd_pairwise x y))) + (if-let half_size (u64_to_uimm5 (u64_udiv (ty_lane_count ty) 2))) + (let ((odd_mask VReg (gen_vec_mask 0x5555555555555555)) + (lhs_lo VReg (rv_vcompress_vm x odd_mask ty)) + (lhs_hi VReg (rv_vcompress_vm y odd_mask ty)) + (lhs VReg (rv_vslideup_vvi lhs_lo lhs_hi half_size (unmasked) ty)) + + (even_mask VReg (gen_vec_mask 0xAAAAAAAAAAAAAAAA)) + (rhs_lo VReg (rv_vcompress_vm x even_mask ty)) + (rhs_hi VReg (rv_vcompress_vm y even_mask ty)) + (rhs VReg (rv_vslideup_vvi rhs_lo rhs_hi half_size (unmasked) ty))) + (rv_vadd_vv lhs rhs (unmasked) ty))) + +;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `avg_round` computes the unsigned average with rounding: a := (x + y + 1) // 2 +;; +;; See Section "2–5 Average of Two Integers" of the Hacker's Delight book +;; +;; The floor average of two integers without overflow can be computed as: +;; t = (x & y) + ((x ^ y) >> 1) +;; +;; The right shift should be a logical shift if the integers are unsigned. +;; +;; We are however interested in the ceiling average (x + y + 1). For that +;; we use a special rounding mode in the right shift instruction. +;; +;; For the right shift instruction we use `vssrl` which is a Scaling Shift +;; Right Logical instruction using the `vxrm` fixed-point rounding mode. The +;; default rounding mode is `rnu` (round-to-nearest-up (add +0.5 LSB)). +;; Which is coincidentally the rounding mode we want for `avg_round`. +(rule (lower (has_type (ty_supported_vec ty) (avg_round x y))) + (if-let one (u64_to_uimm5 1)) + (let ((lhs VReg (rv_vand_vv x y (unmasked) ty)) + (xor VReg (rv_vxor_vv x y (unmasked) ty)) + (rhs VReg (rv_vssrl_vi xor one (unmasked) ty))) + (rv_vadd_vv lhs rhs (unmasked) ty))) + +;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (scalar_to_vector x))) + (if (ty_vector_float ty)) + (let ((zero VReg (rv_vmv_vx (zero_reg) ty)) + (elem VReg (rv_vfmv_sf x ty)) + (mask VReg (gen_vec_mask 1))) + (rv_vmerge_vvm zero elem mask ty))) + +(rule 1 (lower (has_type (ty_supported_vec ty) (scalar_to_vector x))) + (if (ty_vector_not_float ty)) + (let ((zero VReg (rv_vmv_vx (zero_reg) ty)) + (mask VReg (gen_vec_mask 1))) + (rv_vmerge_vxm zero x mask ty))) + +(rule 2 (lower (has_type (ty_supported_vec ty) (scalar_to_vector (imm5_from_value x)))) + (let ((zero VReg (rv_vmv_vx (zero_reg) ty)) + (mask VReg (gen_vec_mask 1))) + (rv_vmerge_vim zero x mask ty))) + +;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (has_type (ty_supported_vec ty) (sqmul_round_sat x y))) + (rv_vsmul_vv x y (unmasked) ty)) + +(rule 1 (lower (has_type (ty_supported_vec ty) (sqmul_round_sat x (splat y)))) + (rv_vsmul_vx x y (unmasked) ty)) + +(rule 2 (lower (has_type (ty_supported_vec ty) (sqmul_round_sat (splat x) y))) + (rv_vsmul_vx y x (unmasked) ty)) + +;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_supported_vec out_ty) (snarrow x @ (value_type in_ty) y))) + (if-let lane_diff (u64_to_uimm5 (u64_udiv (ty_lane_count out_ty) 2))) + (if-let zero (u64_to_uimm5 0)) + (let ((x_clip VReg (rv_vnclip_wi x zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty)))) + (y_clip VReg (rv_vnclip_wi y zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty))))) + (rv_vslideup_vvi x_clip y_clip lane_diff (unmasked) out_ty))) + +;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (ty_supported_vec out_ty) (uunarrow x @ (value_type in_ty) y))) + (if-let lane_diff (u64_to_uimm5 (u64_udiv (ty_lane_count out_ty) 2))) + (if-let zero (u64_to_uimm5 0)) + (let ((x_clip VReg (rv_vnclipu_wi x zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty)))) + (y_clip VReg (rv_vnclipu_wi y zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty))))) + (rv_vslideup_vvi x_clip y_clip lane_diff (unmasked) out_ty))) + +;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We don't have a instruction that saturates a signed source into an unsigned destination. +;; To correct for this we just remove negative values using `vmax` and then use the normal +;; unsigned to unsigned narrowing instruction. + +(rule (lower (has_type (ty_supported_vec out_ty) (unarrow x @ (value_type in_ty) y))) + (if-let lane_diff (u64_to_uimm5 (u64_udiv (ty_lane_count out_ty) 2))) + (if-let zero (u64_to_uimm5 0)) + (let ((x_pos VReg (rv_vmax_vx x (zero_reg) (unmasked) in_ty)) + (y_pos VReg (rv_vmax_vx y (zero_reg) (unmasked) in_ty)) + (x_clip VReg (rv_vnclipu_wi x_pos zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty)))) + (y_clip VReg (rv_vnclipu_wi y_pos zero (unmasked) (vstate_mf2 (ty_half_lanes out_ty))))) + (rv_vslideup_vvi x_clip y_clip lane_diff (unmasked) out_ty))) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.rs new file mode 100644 index 00000000000000..41b1144410522a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower.rs @@ -0,0 +1,35 @@ +//! Lowering rules for Riscv64. +use crate::ir::Inst as IRInst; +use crate::isa::riscv64::inst::*; +use crate::isa::riscv64::Riscv64Backend; +use crate::machinst::lower::*; +use crate::machinst::*; +pub mod isle; + +//============================================================================= +// Lowering-backend trait implementation. + +impl LowerBackend for Riscv64Backend { + type MInst = Inst; + + fn lower(&self, ctx: &mut Lower, ir_inst: IRInst) -> Option { + isle::lower(ctx, self, ir_inst) + } + + fn lower_branch( + &self, + ctx: &mut Lower, + ir_inst: IRInst, + targets: &[MachLabel], + ) -> Option<()> { + isle::lower_branch(ctx, self, ir_inst, targets) + } + + fn maybe_pinned_reg(&self) -> Option { + // pinned register is a register that you want put anything in it. + // right now riscv64 not support this feature. + None + } + + type FactFlowState = (); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle.rs new file mode 100644 index 00000000000000..c39bfd4e5dfb8c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle.rs @@ -0,0 +1,665 @@ +//! ISLE integration glue code for riscv64 lowering. + +// Pull in the ISLE generated code. +#[allow(unused)] +pub mod generated_code; +use generated_code::MInst; + +// Types that the generated ISLE code uses via `use super::*`. +use self::generated_code::{FpuOPWidth, VecAluOpRR, VecLmul}; +use crate::isa; +use crate::isa::riscv64::abi::Riscv64ABICallSite; +use crate::isa::riscv64::lower::args::{ + FReg, VReg, WritableFReg, WritableVReg, WritableXReg, XReg, +}; +use crate::isa::riscv64::Riscv64Backend; +use crate::machinst::Reg; +use crate::machinst::{isle::*, CallInfo, MachInst}; +use crate::machinst::{VCodeConstant, VCodeConstantData}; +use crate::{ + ir::{ + immediates::*, types::*, AtomicRmwOp, BlockCall, ExternalName, Inst, InstructionData, + MemFlags, Opcode, TrapCode, Value, ValueList, + }, + isa::riscv64::inst::*, + machinst::{ArgPair, InstOutput, IsTailCall}, +}; +use regalloc2::PReg; +use std::boxed::Box; +use std::vec::Vec; + +type BoxCallInfo = Box>; +type BoxCallIndInfo = Box>; +type BoxReturnCallInfo = Box>; +type BoxReturnCallIndInfo = Box>; +type BoxExternalName = Box; +type VecMachLabel = Vec; +type VecArgPair = Vec; + +pub(crate) struct RV64IsleContext<'a, 'b, I, B> +where + I: VCodeInst, + B: LowerBackend, +{ + pub lower_ctx: &'a mut Lower<'b, I>, + pub backend: &'a B, + /// Precalucated value for the minimum vector register size. Will be 0 if + /// vectors are not supported. + min_vec_reg_size: u64, +} + +impl<'a, 'b> RV64IsleContext<'a, 'b, MInst, Riscv64Backend> { + fn new(lower_ctx: &'a mut Lower<'b, MInst>, backend: &'a Riscv64Backend) -> Self { + Self { + lower_ctx, + backend, + min_vec_reg_size: backend.isa_flags.min_vec_reg_size(), + } + } +} + +impl generated_code::Context for RV64IsleContext<'_, '_, MInst, Riscv64Backend> { + isle_lower_prelude_methods!(); + isle_prelude_caller_methods!(Riscv64ABICallSite); + + fn fpu_op_width_from_ty(&mut self, ty: Type) -> FpuOPWidth { + match ty { + F16 => FpuOPWidth::H, + F32 => FpuOPWidth::S, + F64 => FpuOPWidth::D, + F128 => FpuOPWidth::Q, + _ => unimplemented!("Unimplemented FPU Op Width: {ty}"), + } + } + + fn vreg_new(&mut self, r: Reg) -> VReg { + VReg::new(r).unwrap() + } + fn writable_vreg_new(&mut self, r: WritableReg) -> WritableVReg { + r.map(|wr| VReg::new(wr).unwrap()) + } + fn writable_vreg_to_vreg(&mut self, arg0: WritableVReg) -> VReg { + arg0.to_reg() + } + fn writable_vreg_to_writable_reg(&mut self, arg0: WritableVReg) -> WritableReg { + arg0.map(|vr| vr.to_reg()) + } + fn vreg_to_reg(&mut self, arg0: VReg) -> Reg { + *arg0 + } + fn xreg_new(&mut self, r: Reg) -> XReg { + XReg::new(r).unwrap() + } + fn writable_xreg_new(&mut self, r: WritableReg) -> WritableXReg { + r.map(|wr| XReg::new(wr).unwrap()) + } + fn writable_xreg_to_xreg(&mut self, arg0: WritableXReg) -> XReg { + arg0.to_reg() + } + fn writable_xreg_to_writable_reg(&mut self, arg0: WritableXReg) -> WritableReg { + arg0.map(|xr| xr.to_reg()) + } + fn xreg_to_reg(&mut self, arg0: XReg) -> Reg { + *arg0 + } + fn freg_new(&mut self, r: Reg) -> FReg { + FReg::new(r).unwrap() + } + fn writable_freg_new(&mut self, r: WritableReg) -> WritableFReg { + r.map(|wr| FReg::new(wr).unwrap()) + } + fn writable_freg_to_freg(&mut self, arg0: WritableFReg) -> FReg { + arg0.to_reg() + } + fn writable_freg_to_writable_reg(&mut self, arg0: WritableFReg) -> WritableReg { + arg0.map(|fr| fr.to_reg()) + } + fn freg_to_reg(&mut self, arg0: FReg) -> Reg { + *arg0 + } + + fn min_vec_reg_size(&mut self) -> u64 { + self.min_vec_reg_size + } + + #[inline] + fn ty_vec_fits_in_register(&mut self, ty: Type) -> Option { + if ty.is_vector() && (ty.bits() as u64) <= self.min_vec_reg_size() { + Some(ty) + } else { + None + } + } + + fn ty_supported(&mut self, ty: Type) -> Option { + let lane_type = ty.lane_type(); + let supported = match ty { + // Scalar integers are always supported + ty if ty.is_int() => true, + // Floating point types depend on certain extensions + F16 => self.backend.isa_flags.has_zfh(), + // F32 depends on the F extension + F32 => self.backend.isa_flags.has_f(), + // F64 depends on the D extension + F64 => self.backend.isa_flags.has_d(), + + // The base vector extension supports all integer types, up to 64 bits + // as long as they fit in a register + ty if self.ty_vec_fits_in_register(ty).is_some() + && lane_type.is_int() + && lane_type.bits() <= 64 => + { + true + } + + // If the vector type has floating point lanes then the spec states: + // + // Vector instructions where any floating-point vector operand’s EEW is not a + // supported floating-point type width (which includes when FLEN < SEW) are reserved. + // + // So we also have to check if we support the scalar version of the type. + ty if self.ty_vec_fits_in_register(ty).is_some() + && lane_type.is_float() + && self.ty_supported(lane_type).is_some() + // Additionally the base V spec only supports 32 and 64 bit floating point types. + && (lane_type.bits() == 32 || lane_type.bits() == 64) => + { + true + } + + // Otherwise do not match + _ => false, + }; + + if supported { + Some(ty) + } else { + None + } + } + + fn ty_supported_float(&mut self, ty: Type) -> Option { + self.ty_supported(ty).filter(|ty| ty.is_float()) + } + + fn ty_supported_vec(&mut self, ty: Type) -> Option { + self.ty_supported(ty).filter(|ty| ty.is_vector()) + } + + fn load_ra(&mut self) -> Reg { + if self.backend.flags.preserve_frame_pointers() { + let tmp = self.temp_writable_reg(I64); + self.emit(&MInst::Load { + rd: tmp, + op: LoadOP::Ld, + flags: MemFlags::trusted(), + from: AMode::FPOffset(8), + }); + tmp.to_reg() + } else { + link_reg() + } + } + + fn label_to_br_target(&mut self, label: MachLabel) -> CondBrTarget { + CondBrTarget::Label(label) + } + + fn imm12_and(&mut self, imm: Imm12, x: u64) -> Imm12 { + Imm12::from_i16(imm.as_i16() & (x as i16)) + } + + fn fli_constant_from_u64(&mut self, ty: Type, imm: u64) -> Option { + FliConstant::maybe_from_u64(ty, imm) + } + + fn fli_constant_from_negated_u64(&mut self, ty: Type, imm: u64) -> Option { + let negated_imm = match ty { + F64 => imm ^ 0x8000000000000000, + F32 => imm ^ 0x80000000, + _ => unimplemented!(), + }; + + FliConstant::maybe_from_u64(ty, negated_imm) + } + + fn i64_generate_imm(&mut self, imm: i64) -> Option<(Imm20, Imm12)> { + MInst::generate_imm(imm as u64) + } + + fn i64_shift_for_lui(&mut self, imm: i64) -> Option<(u64, Imm12)> { + let trailing = imm.trailing_zeros(); + if trailing < 12 { + return None; + } + + let shift = Imm12::from_i16(trailing as i16 - 12); + let base = (imm as u64) >> trailing; + Some((base, shift)) + } + + fn i64_shift(&mut self, imm: i64) -> Option<(i64, Imm12)> { + let trailing = imm.trailing_zeros(); + // We can do without this condition but in this case there is no need to go further + if trailing == 0 { + return None; + } + + let shift = Imm12::from_i16(trailing as i16); + let base = imm >> trailing; + Some((base, shift)) + } + + #[inline] + fn emit(&mut self, arg0: &MInst) -> Unit { + self.lower_ctx.emit(arg0.clone()); + } + #[inline] + fn imm12_from_u64(&mut self, arg0: u64) -> Option { + Imm12::maybe_from_u64(arg0) + } + #[inline] + fn imm12_from_i64(&mut self, arg0: i64) -> Option { + Imm12::maybe_from_i64(arg0) + } + #[inline] + fn imm12_is_zero(&mut self, imm: Imm12) -> Option<()> { + if imm.as_i16() == 0 { + Some(()) + } else { + None + } + } + + #[inline] + fn imm20_from_u64(&mut self, arg0: u64) -> Option { + Imm20::maybe_from_u64(arg0) + } + #[inline] + fn imm20_from_i64(&mut self, arg0: i64) -> Option { + Imm20::maybe_from_i64(arg0) + } + #[inline] + fn imm20_is_zero(&mut self, imm: Imm20) -> Option<()> { + if imm.as_i32() == 0 { + Some(()) + } else { + None + } + } + + #[inline] + fn imm5_from_u64(&mut self, arg0: u64) -> Option { + Imm5::maybe_from_i8(i8::try_from(arg0 as i64).ok()?) + } + #[inline] + fn imm5_from_i64(&mut self, arg0: i64) -> Option { + Imm5::maybe_from_i8(i8::try_from(arg0).ok()?) + } + #[inline] + fn i8_to_imm5(&mut self, arg0: i8) -> Option { + Imm5::maybe_from_i8(arg0) + } + #[inline] + fn uimm5_bitcast_to_imm5(&mut self, arg0: UImm5) -> Imm5 { + Imm5::from_bits(arg0.bits() as u8) + } + #[inline] + fn uimm5_from_u8(&mut self, arg0: u8) -> Option { + UImm5::maybe_from_u8(arg0) + } + #[inline] + fn uimm5_from_u64(&mut self, arg0: u64) -> Option { + arg0.try_into().ok().and_then(UImm5::maybe_from_u8) + } + #[inline] + fn writable_zero_reg(&mut self) -> WritableReg { + writable_zero_reg() + } + #[inline] + fn zero_reg(&mut self) -> XReg { + XReg::new(zero_reg()).unwrap() + } + fn is_non_zero_reg(&mut self, reg: XReg) -> Option<()> { + if reg != self.zero_reg() { + Some(()) + } else { + None + } + } + fn is_zero_reg(&mut self, reg: XReg) -> Option<()> { + if reg == self.zero_reg() { + Some(()) + } else { + None + } + } + #[inline] + fn imm_from_bits(&mut self, val: u64) -> Imm12 { + Imm12::maybe_from_u64(val).unwrap() + } + #[inline] + fn imm_from_neg_bits(&mut self, val: i64) -> Imm12 { + Imm12::maybe_from_i64(val).unwrap() + } + + fn frm_bits(&mut self, frm: &FRM) -> UImm5 { + UImm5::maybe_from_u8(frm.bits()).unwrap() + } + + fn u8_as_i32(&mut self, x: u8) -> i32 { + x as i32 + } + + fn imm12_const(&mut self, val: i32) -> Imm12 { + if let Some(res) = Imm12::maybe_from_i64(val as i64) { + res + } else { + panic!("Unable to make an Imm12 value from {val}") + } + } + fn imm12_const_add(&mut self, val: i32, add: i32) -> Imm12 { + Imm12::maybe_from_i64((val + add) as i64).unwrap() + } + fn imm12_add(&mut self, val: Imm12, add: i32) -> Option { + Imm12::maybe_from_i64((i32::from(val.as_i16()) + add).into()) + } + + // + fn gen_shamt(&mut self, ty: Type, shamt: XReg) -> ValueRegs { + let ty_bits = if ty.bits() > 64 { 64 } else { ty.bits() }; + let ty_bits = i16::try_from(ty_bits).unwrap(); + let shamt = { + let tmp = self.temp_writable_reg(I64); + self.emit(&MInst::AluRRImm12 { + alu_op: AluOPRRI::Andi, + rd: tmp, + rs: shamt.to_reg(), + imm12: Imm12::from_i16(ty_bits - 1), + }); + tmp.to_reg() + }; + let len_sub_shamt = { + let tmp = self.temp_writable_reg(I64); + self.emit(&MInst::load_imm12(tmp, Imm12::from_i16(ty_bits))); + let len_sub_shamt = self.temp_writable_reg(I64); + self.emit(&MInst::AluRRR { + alu_op: AluOPRRR::Sub, + rd: len_sub_shamt, + rs1: tmp.to_reg(), + rs2: shamt, + }); + len_sub_shamt.to_reg() + }; + ValueRegs::two(shamt, len_sub_shamt) + } + + fn has_v(&mut self) -> bool { + self.backend.isa_flags.has_v() + } + + fn has_m(&mut self) -> bool { + self.backend.isa_flags.has_m() + } + + fn has_zfa(&mut self) -> bool { + self.backend.isa_flags.has_zfa() + } + + fn has_zfh(&mut self) -> bool { + self.backend.isa_flags.has_zfh() + } + + fn has_zbkb(&mut self) -> bool { + self.backend.isa_flags.has_zbkb() + } + + fn has_zba(&mut self) -> bool { + self.backend.isa_flags.has_zba() + } + + fn has_zbb(&mut self) -> bool { + self.backend.isa_flags.has_zbb() + } + + fn has_zbc(&mut self) -> bool { + self.backend.isa_flags.has_zbc() + } + + fn has_zbs(&mut self) -> bool { + self.backend.isa_flags.has_zbs() + } + + fn has_zicond(&mut self) -> bool { + self.backend.isa_flags.has_zicond() + } + + fn gen_reg_offset_amode(&mut self, base: Reg, offset: i64) -> AMode { + AMode::RegOffset(base, offset) + } + + fn gen_sp_offset_amode(&mut self, offset: i64) -> AMode { + AMode::SPOffset(offset) + } + + fn gen_fp_offset_amode(&mut self, offset: i64) -> AMode { + AMode::FPOffset(offset) + } + + fn gen_stack_slot_amode(&mut self, ss: StackSlot, offset: i64) -> AMode { + // Offset from beginning of stackslot area. + let stack_off = self.lower_ctx.abi().sized_stackslot_offsets()[ss] as i64; + let sp_off: i64 = stack_off + offset; + AMode::SlotOffset(sp_off) + } + + fn gen_const_amode(&mut self, c: VCodeConstant) -> AMode { + AMode::Const(c) + } + + fn valid_atomic_transaction(&mut self, ty: Type) -> Option { + if ty.is_int() && ty.bits() <= 64 { + Some(ty) + } else { + None + } + } + fn is_atomic_rmw_max_etc(&mut self, op: &AtomicRmwOp) -> Option<(AtomicRmwOp, bool)> { + let op = *op; + match op { + crate::ir::AtomicRmwOp::Umin => Some((op, false)), + crate::ir::AtomicRmwOp::Umax => Some((op, false)), + crate::ir::AtomicRmwOp::Smin => Some((op, true)), + crate::ir::AtomicRmwOp::Smax => Some((op, true)), + _ => None, + } + } + + fn sinkable_inst(&mut self, val: Value) -> Option { + self.is_sinkable_inst(val) + } + + fn load_op(&mut self, ty: Type) -> LoadOP { + LoadOP::from_type(ty) + } + fn store_op(&mut self, ty: Type) -> StoreOP { + StoreOP::from_type(ty) + } + fn load_ext_name(&mut self, name: ExternalName, offset: i64) -> Reg { + let tmp = self.temp_writable_reg(I64); + self.emit(&MInst::LoadExtName { + rd: tmp, + name: Box::new(name), + offset, + }); + tmp.to_reg() + } + + fn gen_stack_addr(&mut self, slot: StackSlot, offset: Offset32) -> Reg { + let result = self.temp_writable_reg(I64); + let i = self + .lower_ctx + .abi() + .sized_stackslot_addr(slot, i64::from(offset) as u32, result); + self.emit(&i); + result.to_reg() + } + fn atomic_amo(&mut self) -> AMO { + AMO::SeqCst + } + + fn lower_br_table(&mut self, index: Reg, targets: &[MachLabel]) -> Unit { + let tmp1 = self.temp_writable_reg(I64); + let tmp2 = self.temp_writable_reg(I64); + self.emit(&MInst::BrTable { + index, + tmp1, + tmp2, + targets: targets.to_vec(), + }); + } + + fn fp_reg(&mut self) -> PReg { + px_reg(8) + } + + fn sp_reg(&mut self) -> PReg { + px_reg(2) + } + + #[inline] + fn int_compare(&mut self, kind: &IntCC, rs1: XReg, rs2: XReg) -> IntegerCompare { + IntegerCompare { + kind: *kind, + rs1: rs1.to_reg(), + rs2: rs2.to_reg(), + } + } + + #[inline] + fn int_compare_decompose(&mut self, cmp: IntegerCompare) -> (IntCC, XReg, XReg) { + (cmp.kind, self.xreg_new(cmp.rs1), self.xreg_new(cmp.rs2)) + } + + #[inline] + fn vstate_from_type(&mut self, ty: Type) -> VState { + VState::from_type(ty) + } + + #[inline] + fn vstate_mf2(&mut self, vs: VState) -> VState { + VState { + vtype: VType { + lmul: VecLmul::LmulF2, + ..vs.vtype + }, + ..vs + } + } + + fn vec_alu_rr_dst_type(&mut self, op: &VecAluOpRR) -> Type { + MInst::canonical_type_for_rc(op.dst_regclass()) + } + + fn bclr_imm(&mut self, ty: Type, i: u64) -> Option { + // Only consider those bits in the immediate which are up to the width + // of `ty`. + let neg = !i & (u64::MAX >> (64 - ty.bits())); + if neg.count_ones() != 1 { + return None; + } + Imm12::maybe_from_u64(neg.trailing_zeros().into()) + } + + fn binvi_imm(&mut self, i: u64) -> Option { + if i.count_ones() != 1 { + return None; + } + Imm12::maybe_from_u64(i.trailing_zeros().into()) + } + fn bseti_imm(&mut self, i: u64) -> Option { + self.binvi_imm(i) + } + + fn fcvt_smin_bound(&mut self, float: Type, int: Type, saturating: bool) -> u64 { + match (int, float) { + // Saturating cases for larger integers are handled using the + // `fcvt.{w,d}.{s,d}` instruction directly, that automatically + // saturates up/down to the correct limit. + // + // NB: i32/i64 don't use this function because the native RISC-V + // instruction does everything we already need, so only cases for + // i8/i16 are listed here. + (I8, F32) if saturating => f32::from(i8::MIN).to_bits().into(), + (I8, F64) if saturating => f64::from(i8::MIN).to_bits(), + (I16, F32) if saturating => f32::from(i16::MIN).to_bits().into(), + (I16, F64) if saturating => f64::from(i16::MIN).to_bits(), + + (_, F32) if !saturating => f32_cvt_to_int_bounds(true, int.bits()).0.to_bits().into(), + (_, F64) if !saturating => f64_cvt_to_int_bounds(true, int.bits()).0.to_bits(), + _ => unimplemented!(), + } + } + + fn fcvt_smax_bound(&mut self, float: Type, int: Type, saturating: bool) -> u64 { + // NB: see `fcvt_smin_bound` for some more comments + match (int, float) { + (I8, F32) if saturating => f32::from(i8::MAX).to_bits().into(), + (I8, F64) if saturating => f64::from(i8::MAX).to_bits(), + (I16, F32) if saturating => f32::from(i16::MAX).to_bits().into(), + (I16, F64) if saturating => f64::from(i16::MAX).to_bits(), + + (_, F32) if !saturating => f32_cvt_to_int_bounds(true, int.bits()).1.to_bits().into(), + (_, F64) if !saturating => f64_cvt_to_int_bounds(true, int.bits()).1.to_bits(), + _ => unimplemented!(), + } + } + + fn fcvt_umax_bound(&mut self, float: Type, int: Type, saturating: bool) -> u64 { + // NB: see `fcvt_smin_bound` for some more comments + match (int, float) { + (I8, F32) if saturating => f32::from(u8::MAX).to_bits().into(), + (I8, F64) if saturating => f64::from(u8::MAX).to_bits(), + (I16, F32) if saturating => f32::from(u16::MAX).to_bits().into(), + (I16, F64) if saturating => f64::from(u16::MAX).to_bits(), + + (_, F32) if !saturating => f32_cvt_to_int_bounds(false, int.bits()).1.to_bits().into(), + (_, F64) if !saturating => f64_cvt_to_int_bounds(false, int.bits()).1.to_bits(), + _ => unimplemented!(), + } + } + + fn fcvt_umin_bound(&mut self, float: Type, saturating: bool) -> u64 { + assert!(!saturating); + match float { + F32 => (-1.0f32).to_bits().into(), + F64 => (-1.0f64).to_bits(), + _ => unimplemented!(), + } + } +} + +/// The main entry point for lowering with ISLE. +pub(crate) fn lower( + lower_ctx: &mut Lower, + backend: &Riscv64Backend, + inst: Inst, +) -> Option { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = RV64IsleContext::new(lower_ctx, backend); + generated_code::constructor_lower(&mut isle_ctx, inst) +} + +/// The main entry point for branch lowering with ISLE. +pub(crate) fn lower_branch( + lower_ctx: &mut Lower, + backend: &Riscv64Backend, + branch: Inst, + targets: &[MachLabel], +) -> Option<()> { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = RV64IsleContext::new(lower_ctx, backend); + generated_code::constructor_lower_branch(&mut isle_ctx, branch, targets) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle/generated_code.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle/generated_code.rs new file mode 100644 index 00000000000000..d5d1feae93bb34 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/lower/isle/generated_code.rs @@ -0,0 +1,9 @@ +// See https://github.com/rust-lang/rust/issues/47995: we cannot use `#![...]` attributes inside of +// the generated ISLE source below because we include!() it. We must include!() it because its path +// depends on an environment variable; and also because of this, we can't do the `#[path = "..."] +// mod generated_code;` trick either. +#![allow(dead_code, unreachable_code, unreachable_patterns)] +#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)] +#![allow(irrefutable_let_patterns, clippy::clone_on_copy)] + +include!(concat!(env!("ISLE_DIR"), "/isle_riscv64.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/mod.rs new file mode 100644 index 00000000000000..0035a721048cda --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/mod.rs @@ -0,0 +1,265 @@ +//! risc-v 64-bit Instruction Set Architecture. + +use crate::dominator_tree::DominatorTree; +use crate::ir::{Function, Type}; +use crate::isa::riscv64::settings as riscv_settings; +use crate::isa::{Builder as IsaBuilder, FunctionAlignment, OwnedTargetIsa, TargetIsa}; +use crate::machinst::{ + compile, CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, + TextSectionBuilder, VCode, +}; +use crate::result::CodegenResult; +use crate::settings::{self as shared_settings, Flags}; +use crate::{ir, CodegenError}; +use alloc::{boxed::Box, vec::Vec}; +use core::fmt; +use cranelift_control::ControlPlane; +use target_lexicon::{Architecture, Triple}; +mod abi; +pub(crate) mod inst; +mod lower; +mod settings; +#[cfg(feature = "unwind")] +use crate::isa::unwind::systemv; + +use self::inst::EmitInfo; + +/// An riscv64 backend. +pub struct Riscv64Backend { + triple: Triple, + flags: shared_settings::Flags, + isa_flags: riscv_settings::Flags, +} + +impl Riscv64Backend { + /// Create a new riscv64 backend with the given (shared) flags. + pub fn new_with_flags( + triple: Triple, + flags: shared_settings::Flags, + isa_flags: riscv_settings::Flags, + ) -> Riscv64Backend { + Riscv64Backend { + triple, + flags, + isa_flags, + } + } + + /// This performs lowering to VCode, register-allocates the code, computes block layout and + /// finalizes branches. The result is ready for binary emission. + fn compile_vcode( + &self, + func: &Function, + domtree: &DominatorTree, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<(VCode, regalloc2::Output)> { + let emit_info = EmitInfo::new(self.flags.clone(), self.isa_flags.clone()); + let sigs = SigSet::new::(func, &self.flags)?; + let abi = abi::Riscv64Callee::new(func, self, &self.isa_flags, &sigs)?; + compile::compile::(func, domtree, self, abi, emit_info, sigs, ctrl_plane) + } +} + +impl TargetIsa for Riscv64Backend { + fn compile_function( + &self, + func: &Function, + domtree: &DominatorTree, + want_disasm: bool, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult { + let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; + + let want_disasm = want_disasm || log::log_enabled!(log::Level::Debug); + let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane); + let frame_size = emit_result.frame_size; + let value_labels_ranges = emit_result.value_labels_ranges; + let buffer = emit_result.buffer; + let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; + let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; + + if let Some(disasm) = emit_result.disasm.as_ref() { + log::debug!("disassembly:\n{}", disasm); + } + + Ok(CompiledCodeStencil { + buffer, + frame_size, + vcode: emit_result.disasm, + value_labels_ranges, + sized_stackslot_offsets, + dynamic_stackslot_offsets, + bb_starts: emit_result.bb_offsets, + bb_edges: emit_result.bb_edges, + }) + } + + fn name(&self) -> &'static str { + "riscv64" + } + fn dynamic_vector_bytes(&self, _dynamic_ty: ir::Type) -> u32 { + 16 + } + + fn triple(&self) -> &Triple { + &self.triple + } + + fn flags(&self) -> &shared_settings::Flags { + &self.flags + } + + fn isa_flags(&self) -> Vec { + self.isa_flags.iter().collect() + } + + #[cfg(feature = "unwind")] + fn emit_unwind_info( + &self, + result: &CompiledCode, + kind: crate::isa::unwind::UnwindInfoKind, + ) -> CodegenResult> { + use crate::isa::unwind::UnwindInfo; + use crate::isa::unwind::UnwindInfoKind; + Ok(match kind { + UnwindInfoKind::SystemV => { + let mapper = self::inst::unwind::systemv::RegisterMapper; + Some(UnwindInfo::SystemV( + crate::isa::unwind::systemv::create_unwind_info_from_insts( + &result.buffer.unwind_info[..], + result.buffer.data().len(), + &mapper, + )?, + )) + } + UnwindInfoKind::Windows => None, + _ => None, + }) + } + + #[cfg(feature = "unwind")] + fn create_systemv_cie(&self) -> Option { + Some(inst::unwind::systemv::create_cie()) + } + + fn text_section_builder(&self, num_funcs: usize) -> Box { + Box::new(MachTextSectionBuilder::::new(num_funcs)) + } + + #[cfg(feature = "unwind")] + fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result { + inst::unwind::systemv::map_reg(reg).map(|reg| reg.0) + } + + fn function_alignment(&self) -> FunctionAlignment { + inst::Inst::function_alignment() + } + + fn page_size_align_log2(&self) -> u8 { + debug_assert_eq!(1 << 12, 0x1000); + 12 + } + + #[cfg(feature = "disas")] + fn to_capstone(&self) -> Result { + use capstone::prelude::*; + let mut cs_builder = Capstone::new().riscv().mode(arch::riscv::ArchMode::RiscV64); + + // Enable C instruction decoding if we have compressed instructions enabled. + // + // We can't enable this unconditionally because it will cause Capstone to + // emit weird instructions and generally mess up when it encounters unknown + // instructions, such as any Zba,Zbb,Zbc or Vector instructions. + // + // This causes the default disassembly to be quite unreadable, so enable + // it only when we are actually going to be using them. + let uses_compressed = self + .isa_flags() + .iter() + .filter(|f| ["has_zca", "has_zcb", "has_zcd"].contains(&f.name)) + .any(|f| f.as_bool().unwrap_or(false)); + if uses_compressed { + cs_builder = cs_builder.extra_mode([arch::riscv::ArchExtraMode::RiscVC].into_iter()); + } + + let mut cs = cs_builder.build()?; + + // Similar to AArch64, RISC-V uses inline constants rather than a separate + // constant pool. We want to skip disassembly over inline constants instead + // of stopping on invalid bytes. + cs.set_skipdata(true)?; + Ok(cs) + } + + fn has_native_fma(&self) -> bool { + true + } + + fn has_x86_blendv_lowering(&self, _: Type) -> bool { + false + } + + fn has_x86_pshufb_lowering(&self) -> bool { + false + } + + fn has_x86_pmulhrsw_lowering(&self) -> bool { + false + } + + fn has_x86_pmaddubsw_lowering(&self) -> bool { + false + } +} + +impl fmt::Display for Riscv64Backend { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MachBackend") + .field("name", &self.name()) + .field("triple", &self.triple()) + .field("flags", &format!("{}", self.flags())) + .finish() + } +} + +/// Create a new `isa::Builder`. +pub fn isa_builder(triple: Triple) -> IsaBuilder { + match triple.architecture { + Architecture::Riscv64(..) => {} + _ => unreachable!(), + } + IsaBuilder { + triple, + setup: riscv_settings::builder(), + constructor: isa_constructor, + } +} + +fn isa_constructor( + triple: Triple, + shared_flags: Flags, + builder: &shared_settings::Builder, +) -> CodegenResult { + let isa_flags = riscv_settings::Flags::new(&shared_flags, builder); + + // The RISC-V backend does not work without at least the G extension enabled. + // The G extension is simply a combination of the following extensions: + // - I: Base Integer Instruction Set + // - M: Integer Multiplication and Division + // - A: Atomic Instructions + // - F: Single-Precision Floating-Point + // - D: Double-Precision Floating-Point + // - Zicsr: Control and Status Register Instructions + // - Zifencei: Instruction-Fetch Fence + // + // Ensure that those combination of features is enabled. + if !isa_flags.has_g() { + return Err(CodegenError::Unsupported( + "The RISC-V Backend currently requires all the features in the G Extension enabled" + .into(), + )); + } + + let backend = Riscv64Backend::new_with_flags(triple, shared_flags, isa_flags); + Ok(backend.wrapped()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/settings.rs b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/settings.rs new file mode 100644 index 00000000000000..993062a9b8312b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/riscv64/settings.rs @@ -0,0 +1,8 @@ +//! riscv64 Settings. + +use crate::settings::{self, detail, Builder, Value}; +use core::fmt; + +// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a +// public `Flags` struct with an impl for all of the settings defined in +include!(concat!(env!("OUT_DIR"), "/settings-riscv64.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/abi.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/abi.rs new file mode 100644 index 00000000000000..845599cb04a65c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/abi.rs @@ -0,0 +1,1399 @@ +//! Implementation of a standard S390x ABI. +//! +//! This machine uses the "vanilla" ABI implementation from abi.rs, +//! however a few details are different from the description there: +//! +//! - On s390x, the caller must provide a "register save area" of 160 +//! bytes to any function it calls. The called function is free to use +//! this space for any purpose; usually to save callee-saved GPRs. +//! (Note that while this area is allocated by the caller, it is counted +//! as part of the callee's stack frame; in particular, the callee's CFA +//! is the top of the register save area, not the incoming SP value.) +//! +//! - Overflow arguments are passed on the stack starting immediately +//! above the register save area. On s390x, this space is allocated +//! only once directly in the prologue, using a size large enough to +//! hold overflow arguments for every call in the function. +//! +//! - On s390x we do not use a frame pointer register; instead, every +//! element of the stack frame is addressed via (constant) offsets +//! from the stack pointer. Note that due to the above (and because +//! there are no variable-sized stack allocations in cranelift), the +//! value of the stack pointer register never changes after the +//! initial allocation in the function prologue. +//! +//! - If we are asked to "preserve frame pointers" to enable stack +//! unwinding, we use the stack backchain feature instead, which +//! is documented by the s390x ELF ABI, but marked as optional. +//! This ensures that at all times during execution of a function, +//! the lowest word on the stack (part of the register save area) +//! holds a copy of the stack pointer at function entry. +//! +//! Overall, the stack frame layout on s390x is as follows: +//! +//! ```plain +//! (high address) +//! +//! +---------------------------+ +//! | ... | +//! CFA -----> | stack args | +//! +---------------------------+ +//! | ... | +//! | 160 bytes reg save area | +//! | (used to save GPRs) | +//! SP at function entry -----> | (incl. caller's backchain)| +//! +---------------------------+ +//! | ... | +//! | clobbered callee-saves | +//! | (used to save FPRs) | +//! unwind-frame base ----> | (alloc'd by prologue) | +//! +---------------------------+ +//! | ... | +//! | spill slots | +//! | (accessed via SP) | +//! | ... | +//! | stack slots | +//! | (accessed via SP) | +//! | (alloc'd by prologue) | +//! +---------------------------+ +//! | ... | +//! | args for call | +//! | outgoing reg save area | +//! | (alloc'd by prologue) | +//! SP during function ------> | (incl. callee's backchain)| +//! +---------------------------+ +//! +//! (low address) +//! ``` +//! +//! +//! The tail-call ABI has the following changes to the system ABI: +//! +//! - %r6 and %r7 are both non-callee-saved argument registers. +//! +//! - The argument save area for outgoing (non-tail) calls to +//! a tail-call ABI function is placed *below* the caller's +//! stack frame. This means the caller temporarily allocates +//! a part of the callee's frame, including temporary space +//! for a register save area holding a copy of the backchain. +//! +//! - For tail calls, the caller puts outgoing arguments at the +//! very top of its stack frame, overlapping the incoming +//! argument area. This is extended by the prolog if needed. +//! +//! Overall, the tail-call stack frame layout on s390x is as follows: +//! +//! ```plain +//! (high address) +//! +//! +---------------------------+ +//! | ... | +//! CFA -----> | (caller's frame) | +//! +---------------------------+ +//! | ... | +//! | 160 bytes reg save area | +//! | (used to save GPRs) | +//! SP at function return-----> | (incl. caller's backchain)| +//! +---------------------------+ +//! | ... | +//! | incoming stack args | +//! SP at function entry -----> | (incl. backchain copy) | +//! +---------------------------+ +//! | ... | +//! | outgoing tail call args | +//! | (overlaps incoming args) | +//! | (incl. backchain copy) | +//! SP at tail cail ----> | (alloc'd by prologue) | +//! +---------------------------+ +//! | ... | +//! | clobbered callee-saves | +//! | (used to save FPRs) | +//! unwind-frame base ----> | (alloc'd by prologue) | +//! +---------------------------+ +//! | ... | +//! | spill slots | +//! | (accessed via SP) | +//! | ... | +//! | stack slots | +//! | (accessed via SP) | +//! | (alloc'd by prologue) | +//! +---------------------------+ +//! | ... | +//! | outgoing calls return buf | +//! | outgoing reg save area | +//! | (alloc'd by prologue) | +//! SP during function ------> | (incl. callee's backchain)| +//! +---------------------------+ +//! | ... | +//! | outgoing stack args | +//! | (alloc'd by call sequence)| +//! SP at non-tail call -----> | (incl. backchain copy) | +//! +---------------------------+ +//! (low address) +//! ``` + +use crate::ir; +use crate::ir::condcodes::IntCC; +use crate::ir::types; +use crate::ir::MemFlags; +use crate::ir::Signature; +use crate::ir::Type; +use crate::isa; +use crate::isa::s390x::{inst::*, settings as s390x_settings}; +use crate::isa::unwind::UnwindInst; +use crate::machinst::*; +use crate::settings; +use crate::CodegenResult; +use alloc::vec::Vec; +use regalloc2::{MachineEnv, PRegSet}; +use smallvec::{smallvec, SmallVec}; +use std::borrow::ToOwned; +use std::sync::OnceLock; + +// We use a generic implementation that factors out ABI commonalities. + +/// Support for the S390x ABI from the callee side (within a function body). +pub type S390xCallee = Callee; + +/// ABI Register usage + +fn in_int_reg(ty: Type) -> bool { + match ty { + types::I8 | types::I16 | types::I32 | types::I64 => true, + _ => false, + } +} + +fn in_flt_reg(ty: Type) -> bool { + match ty { + types::F32 | types::F64 => true, + _ => false, + } +} + +fn in_vec_reg(ty: Type) -> bool { + ty.is_vector() && ty.bits() == 128 +} + +fn get_intreg_for_arg(call_conv: isa::CallConv, idx: usize) -> Option { + match idx { + 0 => Some(regs::gpr(2)), + 1 => Some(regs::gpr(3)), + 2 => Some(regs::gpr(4)), + 3 => Some(regs::gpr(5)), + 4 => Some(regs::gpr(6)), + 5 if call_conv == isa::CallConv::Tail => Some(regs::gpr(7)), + _ => None, + } +} + +fn get_fltreg_for_arg(idx: usize) -> Option { + match idx { + 0 => Some(regs::vr(0)), + 1 => Some(regs::vr(2)), + 2 => Some(regs::vr(4)), + 3 => Some(regs::vr(6)), + _ => None, + } +} + +fn get_vecreg_for_arg(idx: usize) -> Option { + match idx { + 0 => Some(regs::vr(24)), + 1 => Some(regs::vr(25)), + 2 => Some(regs::vr(26)), + 3 => Some(regs::vr(27)), + 4 => Some(regs::vr(28)), + 5 => Some(regs::vr(29)), + 6 => Some(regs::vr(30)), + 7 => Some(regs::vr(31)), + _ => None, + } +} + +fn get_intreg_for_ret(call_conv: isa::CallConv, idx: usize) -> Option { + match idx { + 0 => Some(regs::gpr(2)), + // ABI extension to support multi-value returns: + 1 => Some(regs::gpr(3)), + 2 => Some(regs::gpr(4)), + 3 => Some(regs::gpr(5)), + 4 if call_conv == isa::CallConv::Tail => Some(regs::gpr(6)), + 5 if call_conv == isa::CallConv::Tail => Some(regs::gpr(7)), + _ => None, + } +} + +fn get_fltreg_for_ret(idx: usize) -> Option { + match idx { + 0 => Some(regs::vr(0)), + // ABI extension to support multi-value returns: + 1 => Some(regs::vr(2)), + 2 => Some(regs::vr(4)), + 3 => Some(regs::vr(6)), + _ => None, + } +} + +fn get_vecreg_for_ret(idx: usize) -> Option { + match idx { + 0 => Some(regs::vr(24)), + // ABI extension to support multi-value returns: + 1 => Some(regs::vr(25)), + 2 => Some(regs::vr(26)), + 3 => Some(regs::vr(27)), + 4 => Some(regs::vr(28)), + 5 => Some(regs::vr(29)), + 6 => Some(regs::vr(30)), + 7 => Some(regs::vr(31)), + _ => None, + } +} + +/// The size of the register save area +pub static REG_SAVE_AREA_SIZE: u32 = 160; + +impl Into for StackAMode { + fn into(self) -> MemArg { + match self { + // Argument area always begins at the initial SP. + StackAMode::IncomingArg(off, _) => MemArg::InitialSPOffset { off }, + StackAMode::Slot(off) => MemArg::SlotOffset { off }, + StackAMode::OutgoingArg(off) => MemArg::NominalSPOffset { off }, + } + } +} + +/// S390x-specific ABI behavior. This struct just serves as an implementation +/// point for the trait; it is never actually instantiated. +pub struct S390xMachineDeps; + +impl IsaFlags for s390x_settings::Flags {} + +impl ABIMachineSpec for S390xMachineDeps { + type I = Inst; + + type F = s390x_settings::Flags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic: for now, 128 MB. + const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024; + + fn word_bits() -> u32 { + 64 + } + + /// Return required stack alignment in bytes. + fn stack_align(_call_conv: isa::CallConv) -> u32 { + 8 + } + + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + mut args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)> { + assert_ne!( + call_conv, + isa::CallConv::Winch, + "s390x does not support the 'winch' calling convention yet" + ); + + let mut next_gpr = 0; + let mut next_fpr = 0; + let mut next_vr = 0; + let mut next_stack: u32 = 0; + + // The bottom of the stack frame holds the register save area. To simplify + // offset computation, include this area as part of the argument area; + // however, this does not apply to the tail-call convention, which uses the + // callee frame instead to pass arguments. + if call_conv != isa::CallConv::Tail && args_or_rets == ArgsOrRets::Args { + next_stack = REG_SAVE_AREA_SIZE; + } + + let ret_area_ptr = if add_ret_area_ptr { + debug_assert_eq!(args_or_rets, ArgsOrRets::Args); + next_gpr += 1; + Some(ABIArg::reg( + get_intreg_for_arg(call_conv, 0) + .unwrap() + .to_real_reg() + .unwrap(), + types::I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } else { + None + }; + + for mut param in params.into_iter().copied() { + if let ir::ArgumentPurpose::StructArgument(_) = param.purpose { + panic!( + "StructArgument parameters are not supported on s390x. \ + Use regular pointer arguments instead." + ); + } + + let intreg = in_int_reg(param.value_type); + let fltreg = in_flt_reg(param.value_type); + let vecreg = in_vec_reg(param.value_type); + debug_assert!(intreg as i32 + fltreg as i32 + vecreg as i32 <= 1); + + let (next_reg, candidate, implicit_ref) = if intreg { + let candidate = match args_or_rets { + ArgsOrRets::Args => get_intreg_for_arg(call_conv, next_gpr), + ArgsOrRets::Rets => get_intreg_for_ret(call_conv, next_gpr), + }; + (&mut next_gpr, candidate, None) + } else if fltreg { + let candidate = match args_or_rets { + ArgsOrRets::Args => get_fltreg_for_arg(next_fpr), + ArgsOrRets::Rets => get_fltreg_for_ret(next_fpr), + }; + (&mut next_fpr, candidate, None) + } else if vecreg { + let candidate = match args_or_rets { + ArgsOrRets::Args => get_vecreg_for_arg(next_vr), + ArgsOrRets::Rets => get_vecreg_for_ret(next_vr), + }; + (&mut next_vr, candidate, None) + } else { + // We must pass this by implicit reference. + if args_or_rets == ArgsOrRets::Rets { + // For return values, just force them to memory. + (&mut next_gpr, None, None) + } else { + // For arguments, implicitly convert to pointer type. + let implicit_ref = Some(param.value_type); + param = ir::AbiParam::new(types::I64); + let candidate = get_intreg_for_arg(call_conv, next_gpr); + (&mut next_gpr, candidate, implicit_ref) + } + }; + + let slot = if let Some(reg) = candidate { + *next_reg += 1; + ABIArgSlot::Reg { + reg: reg.to_real_reg().unwrap(), + ty: param.value_type, + extension: param.extension, + } + } else { + if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() { + return Err(crate::CodegenError::Unsupported( + "Too many return values to fit in registers. \ + Use a StructReturn argument instead. (#9510)" + .to_owned(), + )); + } + + // Compute size. Every argument or return value takes a slot of + // at least 8 bytes. + let size = (ty_bits(param.value_type) / 8) as u32; + let slot_size = std::cmp::max(size, 8); + + // Align the stack slot. + debug_assert!(slot_size.is_power_of_two()); + let slot_align = std::cmp::min(slot_size, 8); + next_stack = align_to(next_stack, slot_align); + + // If the type is actually of smaller size (and the argument + // was not extended), it is passed right-aligned. + let offset = if size < slot_size && param.extension == ir::ArgumentExtension::None { + slot_size - size + } else { + 0 + }; + let offset = (next_stack + offset) as i64; + next_stack += slot_size; + ABIArgSlot::Stack { + offset, + ty: param.value_type, + extension: param.extension, + } + }; + + if let Some(ty) = implicit_ref { + assert!( + (ty_bits(ty) / 8) % 8 == 0, + "implicit argument size is not properly aligned" + ); + args.push(ABIArg::ImplicitPtrArg { + pointer: slot, + offset: 0, // Will be filled in later + ty, + purpose: param.purpose, + }); + } else { + args.push(ABIArg::Slots { + slots: smallvec![slot], + purpose: param.purpose, + }); + } + } + + next_stack = align_to(next_stack, 8); + + let extra_arg = if let Some(ret_area_ptr) = ret_area_ptr { + args.push_non_formal(ret_area_ptr); + Some(args.args().len() - 1) + } else { + None + }; + + // After all arguments are in their well-defined location, + // allocate buffers for all ImplicitPtrArg arguments. + for arg in args.args_mut() { + match arg { + ABIArg::StructArg { .. } => unreachable!(), + ABIArg::ImplicitPtrArg { offset, ty, .. } => { + *offset = next_stack as i64; + next_stack += (ty_bits(*ty) / 8) as u32; + } + _ => {} + } + } + + // With the tail-call convention, arguments are passed in the *callee*'s + // frame instead of the caller's frame. Update all offsets accordingly + // (note that resulting offsets will all be negative). + if call_conv == isa::CallConv::Tail && args_or_rets == ArgsOrRets::Args && next_stack != 0 { + for arg in args.args_mut() { + match arg { + ABIArg::Slots { slots, .. } => { + for slot in slots { + match slot { + ABIArgSlot::Reg { .. } => {} + ABIArgSlot::Stack { offset, .. } => { + *offset -= next_stack as i64; + } + } + } + } + ABIArg::StructArg { .. } => unreachable!(), + ABIArg::ImplicitPtrArg { offset, .. } => { + *offset -= next_stack as i64; + } + } + } + // If we have any stack arguments, also allow for a temporary copy + // of the register save area. This is only used until the callee + // has finished setting up its own frame. + next_stack += REG_SAVE_AREA_SIZE; + } + + Ok((next_stack, extra_arg)) + } + + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Inst { + Inst::gen_load(into_reg, mem.into(), ty) + } + + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_store(mem.into(), from_reg, ty) + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { + Inst::gen_move(to_reg, from_reg, ty) + } + + fn gen_extend( + to_reg: Writable, + from_reg: Reg, + signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Inst { + assert!(from_bits < to_bits); + Inst::Extend { + rd: to_reg, + rn: from_reg, + signed, + from_bits, + to_bits, + } + } + + fn gen_args(args: Vec) -> Inst { + Inst::Args { args } + } + + fn gen_rets(rets: Vec) -> Inst { + Inst::Rets { rets } + } + + fn gen_add_imm( + _call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + if let Some(imm) = UImm12::maybe_from_u64(imm as u64) { + insts.push(Inst::LoadAddr { + rd: into_reg, + mem: MemArg::BXD12 { + base: from_reg, + index: zero_reg(), + disp: imm, + flags: MemFlags::trusted(), + }, + }); + } else if let Some(imm) = SImm20::maybe_from_i64(imm as i64) { + insts.push(Inst::LoadAddr { + rd: into_reg, + mem: MemArg::BXD20 { + base: from_reg, + index: zero_reg(), + disp: imm, + flags: MemFlags::trusted(), + }, + }); + } else { + if from_reg != into_reg.to_reg() { + insts.push(Inst::mov64(into_reg, from_reg)); + } + insts.push(Inst::AluRUImm32 { + alu_op: ALUOp::AddLogical64, + rd: into_reg, + ri: into_reg.to_reg(), + imm, + }); + } + insts + } + + fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { + let mut insts = SmallVec::new(); + insts.push(Inst::CmpTrapRR { + op: CmpOp::CmpL64, + rn: stack_reg(), + rm: limit_reg, + cond: Cond::from_intcc(IntCC::UnsignedLessThanOrEqual), + trap_code: ir::TrapCode::STACK_OVERFLOW, + }); + insts + } + + fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable) -> Inst { + let mem = mem.into(); + Inst::LoadAddr { rd: into_reg, mem } + } + + fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg { + spilltmp_reg() + } + + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Inst { + let mem = MemArg::reg_plus_off(base, offset.into(), MemFlags::trusted()); + Inst::gen_load(into_reg, mem, ty) + } + + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst { + let mem = MemArg::reg_plus_off(base, offset.into(), MemFlags::trusted()); + Inst::gen_store(mem, from_reg, ty) + } + + fn gen_sp_reg_adjust(imm: i32) -> SmallInstVec { + if imm == 0 { + return SmallVec::new(); + } + + let mut insts = SmallVec::new(); + if let Ok(imm) = i16::try_from(imm) { + insts.push(Inst::AluRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_stack_reg(), + ri: stack_reg(), + imm, + }); + } else { + insts.push(Inst::AluRSImm32 { + alu_op: ALUOp::Add64, + rd: writable_stack_reg(), + ri: stack_reg(), + imm, + }); + } + insts + } + + fn gen_prologue_frame_setup( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &s390x_settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + SmallVec::new() + } + + fn gen_epilogue_frame_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &s390x_settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + SmallVec::new() + } + + fn gen_return( + _call_conv: isa::CallConv, + _isa_flags: &s390x_settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + smallvec![Inst::Ret { link: gpr(14) }] + } + + fn gen_probestack(_insts: &mut SmallInstVec, _: u32) { + // TODO: implement if we ever require stack probes on an s390x host + // (unlikely unless Lucet is ported) + unimplemented!("Stack probing is unimplemented on S390x"); + } + + fn gen_inline_probestack( + insts: &mut SmallInstVec, + _call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ) { + // The stack probe loop currently takes 4 instructions and each unrolled + // probe takes 2. Set this to 2 to keep the max size to 4 instructions. + const PROBE_MAX_UNROLL: u32 = 2; + + // Calculate how many probes we need to perform. Round down, as we only + // need to probe whole guard_size regions we'd otherwise skip over. + let probe_count = frame_size / guard_size; + if probe_count == 0 { + // No probe necessary + } else if probe_count <= PROBE_MAX_UNROLL { + // Unrolled probe loop. + for _ in 0..probe_count { + insts.extend(Self::gen_sp_reg_adjust(-(guard_size as i32))); + + insts.push(Inst::StoreImm8 { + imm: 0, + mem: MemArg::reg(stack_reg(), MemFlags::trusted()), + }); + } + } else { + // Explicit probe loop. + + // Load the number of probes into a register used as loop counter. + // `gen_inline_probestack` is called after regalloc2, so we can + // use the nonallocatable spilltmp register for this purpose. + let probe_count_reg = writable_spilltmp_reg(); + if let Ok(probe_count) = i16::try_from(probe_count) { + insts.push(Inst::Mov32SImm16 { + rd: probe_count_reg, + imm: probe_count, + }); + } else { + insts.push(Inst::Mov32Imm { + rd: probe_count_reg, + imm: probe_count, + }); + } + + // Emit probe loop. The guard size is assumed to fit in 16 bits. + insts.push(Inst::StackProbeLoop { + probe_count: probe_count_reg, + guard_size: i16::try_from(guard_size).unwrap(), + }); + } + + // Restore the stack pointer to its original position. + insts.extend(Self::gen_sp_reg_adjust((probe_count * guard_size) as i32)); + } + + fn gen_clobber_save( + call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + + // With the tail call convention, the caller already allocated the + // part of our stack frame that contains incoming arguments. + let incoming_tail_args_size = if call_conv == isa::CallConv::Tail { + frame_layout.incoming_args_size + } else { + 0 + }; + + // Define unwind stack frame. + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::DefineNewFrame { + offset_upward_to_caller_sp: REG_SAVE_AREA_SIZE + incoming_tail_args_size, + offset_downward_to_clobbers: frame_layout.clobber_size + - incoming_tail_args_size, + }, + }); + } + + // Use STMG to save clobbered GPRs into save area. + // Note that we always save SP (%r15) here if anything is saved. + if let Some((first_clobbered_gpr, _)) = get_clobbered_gprs(frame_layout) { + let mut last_clobbered_gpr = 15; + let offset = 8 * first_clobbered_gpr as i64 + incoming_tail_args_size as i64; + insts.push(Inst::StoreMultiple64 { + rt: gpr(first_clobbered_gpr), + rt2: gpr(last_clobbered_gpr), + mem: MemArg::reg_plus_off(stack_reg(), offset, MemFlags::trusted()), + }); + if flags.unwind_info() { + // Normally, we instruct the unwinder to restore the stack pointer + // from its slot in the save area. However, if we have incoming + // tail-call arguments, the value saved in that slot is incorrect. + // In that case, we instead instruct the unwinder to compute the + // unwound SP relative to the current CFA, as CFA == SP + 160. + if incoming_tail_args_size != 0 { + insts.push(Inst::Unwind { + inst: UnwindInst::RegStackOffset { + clobber_offset: frame_layout.clobber_size, + reg: gpr(last_clobbered_gpr).to_real_reg().unwrap(), + }, + }); + last_clobbered_gpr = last_clobbered_gpr - 1; + } + for i in first_clobbered_gpr..(last_clobbered_gpr + 1) { + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: frame_layout.clobber_size + (i * 8) as u32, + reg: gpr(i).to_real_reg().unwrap(), + }, + }); + } + } + } + + // Save current stack pointer value if we need to write the backchain. + if flags.preserve_frame_pointers() { + if incoming_tail_args_size == 0 { + insts.push(Inst::mov64(writable_gpr(1), stack_reg())); + } else { + insts.extend(Self::gen_add_imm( + call_conv, + writable_gpr(1), + stack_reg(), + incoming_tail_args_size, + )); + } + } + + // Decrement stack pointer. + let stack_size = frame_layout.outgoing_args_size as i32 + + frame_layout.clobber_size as i32 + + frame_layout.fixed_frame_storage_size as i32 + - incoming_tail_args_size as i32; + insts.extend(Self::gen_sp_reg_adjust(-stack_size)); + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::StackAlloc { + size: stack_size as u32, + }, + }); + } + + // Write the stack backchain if requested, using the value saved above. + if flags.preserve_frame_pointers() { + insts.push(Inst::Store64 { + rd: gpr(1), + mem: MemArg::reg_plus_off(stack_reg(), 0, MemFlags::trusted()), + }); + } + + // Save FPRs. + for (i, reg) in get_clobbered_fprs(frame_layout).iter().enumerate() { + insts.push(Inst::VecStoreLane { + size: 64, + rd: reg.to_reg().into(), + mem: MemArg::reg_plus_off( + stack_reg(), + (i * 8) as i64 + + frame_layout.outgoing_args_size as i64 + + frame_layout.fixed_frame_storage_size as i64, + MemFlags::trusted(), + ), + lane_imm: 0, + }); + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: (i * 8) as u32, + reg: reg.to_reg(), + }, + }); + } + } + + insts + } + + fn gen_clobber_restore( + call_conv: isa::CallConv, + _flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + + // Restore FPRs. + insts.extend(gen_restore_fprs(frame_layout)); + + // Restore GPRs (including SP). + insts.extend(gen_restore_gprs(call_conv, frame_layout, 0)); + + insts + } + + fn gen_call(_dest: &CallDest, _tmp: Writable, _info: CallInfo<()>) -> SmallVec<[Inst; 2]> { + unreachable!(); + } + + fn gen_memcpy Writable>( + _call_conv: isa::CallConv, + _dst: Reg, + _src: Reg, + _size: usize, + _alloc: F, + ) -> SmallVec<[Self::I; 8]> { + unimplemented!("StructArgs not implemented for S390X yet"); + } + + fn get_number_of_spillslots_for_value( + rc: RegClass, + _vector_scale: u32, + _isa_flags: &Self::F, + ) -> u32 { + // We allocate in terms of 8-byte slots. + match rc { + RegClass::Int => 1, + RegClass::Float => 2, + RegClass::Vector => unreachable!(), + } + } + + fn get_machine_env(_flags: &settings::Flags, call_conv: isa::CallConv) -> &MachineEnv { + match call_conv { + isa::CallConv::Tail => { + static TAIL_MACHINE_ENV: OnceLock = OnceLock::new(); + TAIL_MACHINE_ENV.get_or_init(tail_create_machine_env) + } + _ => { + static SYSV_MACHINE_ENV: OnceLock = OnceLock::new(); + SYSV_MACHINE_ENV.get_or_init(sysv_create_machine_env) + } + } + } + + fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> PRegSet { + match call_conv_of_callee { + isa::CallConv::Tail => TAIL_CLOBBERS, + _ => SYSV_CLOBBERS, + } + } + + fn get_ext_mode( + _call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension { + specified + } + + fn compute_frame_layout( + call_conv: isa::CallConv, + flags: &settings::Flags, + _sig: &Signature, + regs: &[Writable], + _is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + mut outgoing_args_size: u32, + ) -> FrameLayout { + assert!( + !flags.enable_pinned_reg(), + "Pinned register not supported on s390x" + ); + + let mut regs: Vec> = regs + .iter() + .cloned() + .filter(|r| is_reg_saved_in_prologue(call_conv, r.to_reg())) + .collect(); + + // If the front end asks to preserve frame pointers (which we do not + // really have in the s390x ABI), we use the stack backchain instead. + // For this to work in all cases, we must allocate a stack frame with + // at least the outgoing register save area even in leaf functions. + // Update our caller's outgoing_args_size to reflect this. + if flags.preserve_frame_pointers() { + if outgoing_args_size < REG_SAVE_AREA_SIZE { + outgoing_args_size = REG_SAVE_AREA_SIZE; + } + } + + // We need to save/restore the link register in non-leaf functions. + // This is not included in the clobber list because we have excluded + // call instructions via the is_included_in_clobbers callback. + // We also want to enforce saving the link register in leaf functions + // for stack unwinding, if we're asked to preserve frame pointers. + if outgoing_args_size > 0 { + let link_reg = Writable::from_reg(RealReg::from(gpr_preg(14))); + if !regs.contains(&link_reg) { + regs.push(link_reg); + } + } + + // Sort registers for deterministic code output. We can do an unstable + // sort because the registers will be unique (there are no dups). + regs.sort_unstable(); + + // Compute clobber size. We only need to count FPR save slots. + let mut clobber_size = 0; + for reg in ®s { + match reg.to_reg().class() { + RegClass::Int => {} + RegClass::Float => { + clobber_size += 8; + } + RegClass::Vector => unreachable!(), + } + } + + // Common code assumes that tail-call arguments are part of the caller's + // frame. This is not correct for our tail-call convention. To ensure + // common code still gets the total size of this stack frame correct, + // we add the (incoming and outgoing) taill-call argument size to the + // "clobber" size. + if call_conv == isa::CallConv::Tail { + clobber_size += tail_args_size; + } + + // Return FrameLayout structure. + FrameLayout { + incoming_args_size, + // We already accounted for tail-call arguments above, so reset + // this value to its default. + tail_args_size: incoming_args_size, + setup_area_size: 0, + clobber_size, + fixed_frame_storage_size, + outgoing_args_size, + clobbered_callee_saves: regs, + } + } +} + +impl S390xMachineDeps { + pub fn gen_tail_epilogue( + frame_layout: &FrameLayout, + callee_pop_size: u32, + target_reg: Option<&mut Reg>, + ) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + let call_conv = isa::CallConv::Tail; + + // Restore FPRs. + insts.extend(gen_restore_fprs(frame_layout)); + + // If the tail call target is in a callee-saved GPR, we need to move it + // to %r1 (as the only available temp register) before restoring GPRs + // (but after restoring FPRs, which might clobber %r1). + if let Some(reg) = target_reg { + if is_reg_saved_in_prologue(call_conv, reg.to_real_reg().unwrap()) { + insts.push(Inst::Mov64 { + rd: writable_gpr(1), + rm: *reg, + }); + *reg = gpr(1); + } + } + + // Restore GPRs (including SP). + insts.extend(gen_restore_gprs(call_conv, frame_layout, callee_pop_size)); + + insts + } +} + +fn is_reg_saved_in_prologue(call_conv: isa::CallConv, r: RealReg) -> bool { + match (call_conv, r.class()) { + (isa::CallConv::Tail, RegClass::Int) => { + // r8 - r15 inclusive are callee-saves. + r.hw_enc() >= 8 && r.hw_enc() <= 15 + } + (_, RegClass::Int) => { + // r6 - r15 inclusive are callee-saves. + r.hw_enc() >= 6 && r.hw_enc() <= 15 + } + (_, RegClass::Float) => { + // f8 - f15 inclusive are callee-saves. + r.hw_enc() >= 8 && r.hw_enc() <= 15 + } + (_, RegClass::Vector) => unreachable!(), + } +} + +fn get_clobbered_gprs(frame_layout: &FrameLayout) -> Option<(u8, u8)> { + // Collect clobbered GPRs. Note we save/restore GPR always as + // a block of registers using LOAD MULTIPLE / STORE MULTIPLE, starting + // with the clobbered GPR with the lowest number up to the clobbered GPR + // with the highest number. + let (clobbered_gpr, _) = frame_layout.clobbered_callee_saves_by_class(); + if clobbered_gpr.is_empty() { + return None; + } + + let first = clobbered_gpr.first().unwrap().to_reg().hw_enc(); + let last = clobbered_gpr.last().unwrap().to_reg().hw_enc(); + debug_assert!(clobbered_gpr.iter().all(|r| r.to_reg().hw_enc() >= first)); + debug_assert!(clobbered_gpr.iter().all(|r| r.to_reg().hw_enc() <= last)); + Some((first, last)) +} + +fn get_clobbered_fprs(frame_layout: &FrameLayout) -> &[Writable] { + // Collect clobbered floating-point registers. + let (_, clobbered_fpr) = frame_layout.clobbered_callee_saves_by_class(); + clobbered_fpr +} + +// Restore GPRs (including SP) from the register save area. +// This must not clobber any register, specifically including %r1. +fn gen_restore_gprs( + call_conv: isa::CallConv, + frame_layout: &FrameLayout, + callee_pop_size: u32, +) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + + // Determine GPRs to be restored. + let clobbered_gpr = get_clobbered_gprs(frame_layout); + + // Increment stack pointer unless it will be restored implicitly. + // Note that implicit stack pointer restoration cannot be done in the + // presence of either incoming or outgoing tail call arguments. + let stack_size = frame_layout.outgoing_args_size as i32 + + frame_layout.clobber_size as i32 + + frame_layout.fixed_frame_storage_size as i32; + let implicit_sp_restore = callee_pop_size == 0 + && (call_conv != isa::CallConv::Tail || frame_layout.incoming_args_size == 0) + && clobbered_gpr.map_or(false, |(first, _)| { + SImm20::maybe_from_i64(8 * first as i64 + stack_size as i64).is_some() + }); + if !implicit_sp_restore { + insts.extend(S390xMachineDeps::gen_sp_reg_adjust( + stack_size - callee_pop_size as i32, + )); + } + + // Use LMG to restore clobbered GPRs from save area. + if let Some((first, mut last)) = clobbered_gpr { + // Attempt to restore via SP, taking implicit restoration into account. + let mut reg = stack_reg(); + let mut offset = callee_pop_size as i64 + 8 * first as i64; + if implicit_sp_restore { + offset += stack_size as i64 - callee_pop_size as i64; + last = 15; + } + // If the offset still overflows, use the first restored GPR + // as temporary holding the address, as we cannot use %r1. + if SImm20::maybe_from_i64(offset).is_none() { + insts.extend(S390xMachineDeps::gen_add_imm( + call_conv, + writable_gpr(first), + stack_reg(), + offset as u32, + )); + reg = gpr(first); + offset = 0; + } + // Now this LMG will always have an in-range offset. + insts.push(Inst::LoadMultiple64 { + rt: writable_gpr(first), + rt2: writable_gpr(last), + mem: MemArg::reg_plus_off(reg, offset, MemFlags::trusted()), + }); + } + + insts +} + +// Restore FPRs from the clobber area. +fn gen_restore_fprs(frame_layout: &FrameLayout) -> SmallVec<[Inst; 16]> { + let mut insts = SmallVec::new(); + + // Determine FPRs to be restored. + let clobbered_fpr = get_clobbered_fprs(frame_layout); + + // Restore FPRs. + for (i, reg) in clobbered_fpr.iter().enumerate() { + insts.push(Inst::VecLoadLaneUndef { + size: 64, + rd: Writable::from_reg(reg.to_reg().into()), + mem: MemArg::reg_plus_off( + stack_reg(), + (i * 8) as i64 + + frame_layout.outgoing_args_size as i64 + + frame_layout.fixed_frame_storage_size as i64, + MemFlags::trusted(), + ), + lane_imm: 0, + }); + } + + insts +} + +const fn sysv_clobbers() -> PRegSet { + PRegSet::empty() + .with(gpr_preg(0)) + .with(gpr_preg(1)) + .with(gpr_preg(2)) + .with(gpr_preg(3)) + .with(gpr_preg(4)) + .with(gpr_preg(5)) + // v0 - v7 inclusive and v16 - v31 inclusive are + // caller-saves. The upper 64 bits of v8 - v15 inclusive are + // also caller-saves. However, because we cannot currently + // represent partial registers to regalloc2, we indicate here + // that every vector register is caller-save. Because this + // function is used at *callsites*, approximating in this + // direction (save more than necessary) is conservative and + // thus safe. + // + // Note that we exclude clobbers from a call instruction when + // a call instruction's callee has the same ABI as the caller + // (the current function body); this is safe (anything + // clobbered by callee can be clobbered by caller as well) and + // avoids unnecessary saves of v8-v15 in the prologue even + // though we include them as defs here. + .with(vr_preg(0)) + .with(vr_preg(1)) + .with(vr_preg(2)) + .with(vr_preg(3)) + .with(vr_preg(4)) + .with(vr_preg(5)) + .with(vr_preg(6)) + .with(vr_preg(7)) + .with(vr_preg(8)) + .with(vr_preg(9)) + .with(vr_preg(10)) + .with(vr_preg(11)) + .with(vr_preg(12)) + .with(vr_preg(13)) + .with(vr_preg(14)) + .with(vr_preg(15)) + .with(vr_preg(16)) + .with(vr_preg(17)) + .with(vr_preg(18)) + .with(vr_preg(19)) + .with(vr_preg(20)) + .with(vr_preg(21)) + .with(vr_preg(22)) + .with(vr_preg(23)) + .with(vr_preg(24)) + .with(vr_preg(25)) + .with(vr_preg(26)) + .with(vr_preg(27)) + .with(vr_preg(28)) + .with(vr_preg(29)) + .with(vr_preg(30)) + .with(vr_preg(31)) +} +const SYSV_CLOBBERS: PRegSet = sysv_clobbers(); + +const fn tail_clobbers() -> PRegSet { + // Same as the SystemV ABI, except that %r6 and %r7 are clobbered. + PRegSet::empty() + .with(gpr_preg(0)) + .with(gpr_preg(1)) + .with(gpr_preg(2)) + .with(gpr_preg(3)) + .with(gpr_preg(4)) + .with(gpr_preg(5)) + .with(gpr_preg(6)) + .with(gpr_preg(7)) + .with(vr_preg(0)) + .with(vr_preg(1)) + .with(vr_preg(2)) + .with(vr_preg(3)) + .with(vr_preg(4)) + .with(vr_preg(5)) + .with(vr_preg(6)) + .with(vr_preg(7)) + .with(vr_preg(8)) + .with(vr_preg(9)) + .with(vr_preg(10)) + .with(vr_preg(11)) + .with(vr_preg(12)) + .with(vr_preg(13)) + .with(vr_preg(14)) + .with(vr_preg(15)) + .with(vr_preg(16)) + .with(vr_preg(17)) + .with(vr_preg(18)) + .with(vr_preg(19)) + .with(vr_preg(20)) + .with(vr_preg(21)) + .with(vr_preg(22)) + .with(vr_preg(23)) + .with(vr_preg(24)) + .with(vr_preg(25)) + .with(vr_preg(26)) + .with(vr_preg(27)) + .with(vr_preg(28)) + .with(vr_preg(29)) + .with(vr_preg(30)) + .with(vr_preg(31)) +} +const TAIL_CLOBBERS: PRegSet = tail_clobbers(); + +fn sysv_create_machine_env() -> MachineEnv { + MachineEnv { + preferred_regs_by_class: [ + vec![ + // no r0; can't use for addressing? + // no r1; it is our spilltmp. + gpr_preg(2), + gpr_preg(3), + gpr_preg(4), + gpr_preg(5), + ], + vec![ + vr_preg(0), + vr_preg(1), + vr_preg(2), + vr_preg(3), + vr_preg(4), + vr_preg(5), + vr_preg(6), + vr_preg(7), + vr_preg(16), + vr_preg(17), + vr_preg(18), + vr_preg(19), + vr_preg(20), + vr_preg(21), + vr_preg(22), + vr_preg(23), + vr_preg(24), + vr_preg(25), + vr_preg(26), + vr_preg(27), + vr_preg(28), + vr_preg(29), + vr_preg(30), + vr_preg(31), + ], + // Vector Regclass is unused + vec![], + ], + non_preferred_regs_by_class: [ + vec![ + gpr_preg(6), + gpr_preg(7), + gpr_preg(8), + gpr_preg(9), + gpr_preg(10), + gpr_preg(11), + gpr_preg(12), + gpr_preg(13), + gpr_preg(14), + // no r15; it is the stack pointer. + ], + vec![ + vr_preg(8), + vr_preg(9), + vr_preg(10), + vr_preg(11), + vr_preg(12), + vr_preg(13), + vr_preg(14), + vr_preg(15), + ], + // Vector Regclass is unused + vec![], + ], + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + } +} + +fn tail_create_machine_env() -> MachineEnv { + // Same as the SystemV ABI, except that %r6 and %r7 are preferred. + MachineEnv { + preferred_regs_by_class: [ + vec![ + // no r0; can't use for addressing? + // no r1; it is our spilltmp. + gpr_preg(2), + gpr_preg(3), + gpr_preg(4), + gpr_preg(5), + gpr_preg(6), + gpr_preg(7), + ], + vec![ + vr_preg(0), + vr_preg(1), + vr_preg(2), + vr_preg(3), + vr_preg(4), + vr_preg(5), + vr_preg(6), + vr_preg(7), + vr_preg(16), + vr_preg(17), + vr_preg(18), + vr_preg(19), + vr_preg(20), + vr_preg(21), + vr_preg(22), + vr_preg(23), + vr_preg(24), + vr_preg(25), + vr_preg(26), + vr_preg(27), + vr_preg(28), + vr_preg(29), + vr_preg(30), + vr_preg(31), + ], + // Vector Regclass is unused + vec![], + ], + non_preferred_regs_by_class: [ + vec![ + gpr_preg(8), + gpr_preg(9), + gpr_preg(10), + gpr_preg(11), + gpr_preg(12), + gpr_preg(13), + gpr_preg(14), + // no r15; it is the stack pointer. + ], + vec![ + vr_preg(8), + vr_preg(9), + vr_preg(10), + vr_preg(11), + vr_preg(12), + vr_preg(13), + vr_preg(14), + vr_preg(15), + ], + // Vector Regclass is unused + vec![], + ], + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst.isle b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst.isle new file mode 100644 index 00000000000000..7fad425ae0b359 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst.isle @@ -0,0 +1,5019 @@ +;; Instruction formats. +(type MInst + (enum + ;; A no-op of zero size. + (Nop0) + + ;; A no-op of size two bytes. + (Nop2) + + ;; An ALU operation with two register sources and a register destination. + (AluRRR + (alu_op ALUOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; An ALU operation with a register source and a signed 16-bit + ;; immediate source, and a separate register destination. + (AluRRSImm16 + (alu_op ALUOp) + (rd WritableReg) + (rn Reg) + (imm i16)) + + ;; An ALU operation with a register in-/out operand and + ;; a second register source. + (AluRR + (alu_op ALUOp) + (rd WritableReg) + ;; Input side of `rd`. `rd` is constrained to reuse `ri`'s + ;; allocation during regalloc. Hence, we have SSA form here (ri + ;; is strictly a use, rd is strictly a def) and it becomes a + ;; modified-reg form when encoded. + (ri Reg) + (rm Reg)) + + ;; An ALU operation with a register in-/out operand and + ;; a memory source. + (AluRX + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (mem MemArg)) + + ;; An ALU operation with a register in-/out operand and a signed 16-bit + ;; immediate source. + (AluRSImm16 + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (imm i16)) + + ;; An ALU operation with a register in-/out operand and a signed 32-bit + ;; immediate source. + (AluRSImm32 + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (imm i32)) + + ;; An ALU operation with a register in-/out operand and an unsigned 32-bit + ;; immediate source. + (AluRUImm32 + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (imm u32)) + + ;; An ALU operation with a register in-/out operand and a shifted 16-bit + ;; immediate source. + (AluRUImm16Shifted + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (imm UImm16Shifted)) + + ;; An ALU operation with a register in-/out operand and a shifted 32-bit + ;; immediate source. + (AluRUImm32Shifted + (alu_op ALUOp) + (rd WritableReg) + (ri Reg) + (imm UImm32Shifted)) + + ;; A multiply operation with two register sources and a register pair destination. + (SMulWide + (rd WritableRegPair) + (rn Reg) + (rm Reg)) + + ;; A multiply operation with an in/out register pair, and an extra register source. + ;; Only the lower half of the register pair is used as input. + (UMulWide + (rd WritableRegPair) + (ri Reg) + (rn Reg)) + + ;; A divide operation with an in/out register pair, and an extra register source. + ;; Only the lower half of the register pair is used as input. + (SDivMod32 + (rd WritableRegPair) + (ri Reg) + (rn Reg)) + (SDivMod64 + (rd WritableRegPair) + (ri Reg) + (rn Reg)) + + ;; A divide operation with an in/out register pair, and an extra register source. + (UDivMod32 + (rd WritableRegPair) + (ri RegPair) + (rn Reg)) + (UDivMod64 + (rd WritableRegPair) + (ri RegPair) + (rn Reg)) + + ;; A FLOGR operation with a register source and a register pair destination. + (Flogr + (rd WritableRegPair) + (rn Reg)) + + ;; A shift instruction with a register source, a register destination, + ;; and an immediate plus an optional register as shift count. + (ShiftRR + (shift_op ShiftOp) + (rd WritableReg) + (rn Reg) + (shift_imm u8) + (shift_reg Reg)) + + ;; A rotate-then--selected-bits instruction with a register + ;; in/out-operand, another register source, and three immediates. + (RxSBG + (op RxSBGOp) + (rd WritableReg) + (ri Reg) + (rn Reg) + (start_bit u8) + (end_bit u8) + (rotate_amt i8)) + + ;; The test-only version of RxSBG, which does not modify any register + ;; but only sets the condition code. + (RxSBGTest + (op RxSBGOp) + (rd Reg) + (rn Reg) + (start_bit u8) + (end_bit u8) + (rotate_amt i8)) + + ;; An unary operation with a register source and a register destination. + (UnaryRR + (op UnaryOp) + (rd WritableReg) + (rn Reg)) + + ;; A compare operation with two register sources. + (CmpRR + (op CmpOp) + (rn Reg) + (rm Reg)) + + ;; A compare operation with a register source and a memory source. + (CmpRX + (op CmpOp) + (rn Reg) + (mem MemArg)) + + ;; A compare operation with a register source and a signed 16-bit + ;; immediate source. + (CmpRSImm16 + (op CmpOp) + (rn Reg) + (imm i16)) + + ;; A compare operation with a register source and a signed 32-bit + ;; immediate source. + (CmpRSImm32 + (op CmpOp) + (rn Reg) + (imm i32)) + + ;; A compare operation with a register source and a unsigned 32-bit + ;; immediate source. + (CmpRUImm32 + (op CmpOp) + (rn Reg) + (imm u32)) + + ;; A compare-and-trap instruction with two register sources. + (CmpTrapRR + (op CmpOp) + (rn Reg) + (rm Reg) + (cond Cond) + (trap_code TrapCode)) + + ;; A compare-and-trap operation with a register source and a signed 16-bit + ;; immediate source. + (CmpTrapRSImm16 + (op CmpOp) + (rn Reg) + (imm i16) + (cond Cond) + (trap_code TrapCode)) + + ;; A compare-and-trap operation with a register source and an unsigned 16-bit + ;; immediate source. + (CmpTrapRUImm16 + (op CmpOp) + (rn Reg) + (imm u16) + (cond Cond) + (trap_code TrapCode)) + + ;; An atomic read-modify-write operation with a memory in-/out operand, + ;; a register destination, and a register source. + ;; a memory source. + (AtomicRmw + (alu_op ALUOp) + (rd WritableReg) + (rn Reg) + (mem MemArg)) + + ;; A 32-bit atomic compare-and-swap operation. + (AtomicCas32 + (rd WritableReg) + (ri Reg) + (rn Reg) + (mem MemArg)) + + ;; A 64-bit atomic compare-and-swap operation. + (AtomicCas64 + (rd WritableReg) + (ri Reg) + (rn Reg) + (mem MemArg)) + + ;; A memory fence operation. + (Fence) + + ;; A 32-bit load. + (Load32 + (rd WritableReg) + (mem MemArg)) + + ;; An unsigned (zero-extending) 8-bit to 32-bit load. + (Load32ZExt8 + (rd WritableReg) + (mem MemArg)) + + ;; A signed (sign-extending) 8-bit to 32-bit load. + (Load32SExt8 + (rd WritableReg) + (mem MemArg)) + + ;; An unsigned (zero-extending) 16-bit to 32-bit load. + (Load32ZExt16 + (rd WritableReg) + (mem MemArg)) + + ;; A signed (sign-extending) 16-bit to 32-bit load. + (Load32SExt16 + (rd WritableReg) + (mem MemArg)) + + ;; A 64-bit load. + (Load64 + (rd WritableReg) + (mem MemArg)) + + ;; An unsigned (zero-extending) 8-bit to 64-bit load. + (Load64ZExt8 + (rd WritableReg) + (mem MemArg)) + + ;; A signed (sign-extending) 8-bit to 64-bit load. + (Load64SExt8 + (rd WritableReg) + (mem MemArg)) + + ;; An unsigned (zero-extending) 16-bit to 64-bit load. + (Load64ZExt16 + (rd WritableReg) + (mem MemArg)) + + ;; A signed (sign-extending) 16-bit to 64-bit load. + (Load64SExt16 + (rd WritableReg) + (mem MemArg)) + + ;; An unsigned (zero-extending) 32-bit to 64-bit load. + (Load64ZExt32 + (rd WritableReg) + (mem MemArg)) + + ;; A signed (sign-extending) 32-bit to 64-bit load. + (Load64SExt32 + (rd WritableReg) + (mem MemArg)) + + ;; A 16-bit byte-reversed load. + (LoadRev16 + (rd WritableReg) + (mem MemArg)) + + ;; A 32-bit byte-reversed load. + (LoadRev32 + (rd WritableReg) + (mem MemArg)) + + ;; A 64-bit byte-reversed load. + (LoadRev64 + (rd WritableReg) + (mem MemArg)) + + ;; An 8-bit store. + (Store8 + (rd Reg) + (mem MemArg)) + + ;; A 16-bit store. + (Store16 + (rd Reg) + (mem MemArg)) + + ;; A 32-bit store. + (Store32 + (rd Reg) + (mem MemArg)) + + ;; A 64-bit store. + (Store64 + (rd Reg) + (mem MemArg)) + + ;; An 8-bit store of an immediate. + (StoreImm8 + (imm u8) + (mem MemArg)) + + ;; A 16-bit store of an immediate. + (StoreImm16 + (imm i16) + (mem MemArg)) + + ;; A 32-bit store of a sign-extended 16-bit immediate. + (StoreImm32SExt16 + (imm i16) + (mem MemArg)) + + ;; A 64-bit store of a sign-extended 16-bit immediate. + (StoreImm64SExt16 + (imm i16) + (mem MemArg)) + + ;; A 16-bit byte-reversed store. + (StoreRev16 + (rd Reg) + (mem MemArg)) + + ;; A 32-bit byte-reversed store. + (StoreRev32 + (rd Reg) + (mem MemArg)) + + ;; A 64-bit byte-reversed store. + (StoreRev64 + (rd Reg) + (mem MemArg)) + + ;; A load-multiple instruction. + (LoadMultiple64 + (rt WritableReg) + (rt2 WritableReg) + (mem MemArg)) + + ;; A store-multiple instruction. + (StoreMultiple64 + (rt Reg) + (rt2 Reg) + (mem MemArg)) + + ;; A 32-bit move instruction. + (Mov32 + (rd WritableReg) + (rm Reg)) + + ;; A 64-bit move instruction. + (Mov64 + (rd WritableReg) + (rm Reg)) + + ;; Like `Mov64` but with a particular physical register source. + (MovPReg + (rd WritableReg) + (rm PReg)) + + ;; A 32-bit move instruction with a full 32-bit immediate. + (Mov32Imm + (rd WritableReg) + (imm u32)) + + ;; A 32-bit move instruction with a 16-bit signed immediate. + (Mov32SImm16 + (rd WritableReg) + (imm i16)) + + ;; A 64-bit move instruction with a 16-bit signed immediate. + (Mov64SImm16 + (rd WritableReg) + (imm i16)) + + ;; A 64-bit move instruction with a 32-bit signed immediate. + (Mov64SImm32 + (rd WritableReg) + (imm i32)) + + ;; A 64-bit move instruction with a shifted 16-bit immediate. + (Mov64UImm16Shifted + (rd WritableReg) + (imm UImm16Shifted)) + + ;; A 64-bit move instruction with a shifted 32-bit immediate. + (Mov64UImm32Shifted + (rd WritableReg) + (imm UImm32Shifted)) + + ;; A 64-bit insert instruction with a shifted 16-bit immediate. + (Insert64UImm16Shifted + (rd WritableReg) + (ri Reg) + (imm UImm16Shifted)) + + ;; A 64-bit insert instruction with a shifted 32-bit immediate. + (Insert64UImm32Shifted + (rd WritableReg) + (ri Reg) + (imm UImm32Shifted)) + + ;; Load 32-bit access register into GPR. + (LoadAR + (rd WritableReg) + (ar u8)) + + ;; Insert 32-bit access register into low half of a GPR. + ;; (Identical operation to LoadAR, but considers rd to be use/def.) + (InsertAR + (rd WritableReg) + (ri Reg) + (ar u8)) + + ;; A sign- or zero-extend operation. + (Extend + (rd WritableReg) + (rn Reg) + (signed bool) + (from_bits u8) + (to_bits u8)) + + ;; A 32-bit conditional move instruction. `ri` is the value that's used if + ;; the conditional is true, `rm` is used otherwise. + (CMov32 + (rd WritableReg) + (cond Cond) + (ri Reg) + (rm Reg)) + + ;; A 64-bit conditional move instruction. + (CMov64 + (rd WritableReg) + (cond Cond) + (ri Reg) + (rm Reg)) + + ;; A 32-bit conditional move instruction with a 16-bit signed immediate. + (CMov32SImm16 + (rd WritableReg) + (cond Cond) + (ri Reg) + (imm i16)) + + ;; A 64-bit conditional move instruction with a 16-bit signed immediate. + (CMov64SImm16 + (rd WritableReg) + (cond Cond) + (ri Reg) + (imm i16)) + + ;; A 32-bit FPU move possibly implemented as vector instruction. + (FpuMove32 + (rd WritableReg) + (rn Reg)) + + ;; A 64-bit FPU move possibly implemented as vector instruction. + (FpuMove64 + (rd WritableReg) + (rn Reg)) + + ;; A 32-bit conditional move FPU instruction, possibly as vector instruction. + (FpuCMov32 + (rd WritableReg) + (cond Cond) + (ri Reg) + (rm Reg)) + + ;; A 64-bit conditional move FPU instruction, possibly as vector instruction. + (FpuCMov64 + (rd WritableReg) + (cond Cond) + (ri Reg) + (rm Reg)) + + ;; 1-op FPU instruction implemented as vector instruction with the W bit. + (FpuRR + (fpu_op FPUOp1) + (rd WritableReg) + (rn Reg)) + + ;; 2-op FPU instruction implemented as vector instruction with the W bit. + (FpuRRR + (fpu_op FPUOp2) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; 3-op FPU instruction implemented as vector instruction with the W bit. + (FpuRRRR + (fpu_op FPUOp3) + (rd WritableReg) + (rn Reg) + (rm Reg) + (ra Reg)) + + ;; 1-op FPU instruction with rounding mode. + (FpuRound + (op FpuRoundOp) + (mode FpuRoundMode) + (rd WritableReg) + (rn Reg)) + + ;; FPU comparison, single-precision (32 bit). + (FpuCmp32 + (rn Reg) + (rm Reg)) + + ;; FPU comparison, double-precision (64 bit). + (FpuCmp64 + (rn Reg) + (rm Reg)) + + ;; Load floating-point constant, single-precision (32 bit). + (LoadFpuConst32 + (rd WritableReg) + (const_data u32)) + + ;; Load floating-point constant, double-precision (64 bit). + (LoadFpuConst64 + (rd WritableReg) + (const_data u64)) + + ;; A binary vector operation with two vector register sources. + (VecRRR + (op VecBinaryOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; A unary vector operation with a vector register source. + (VecRR + (op VecUnaryOp) + (rd WritableReg) + (rn Reg)) + + ;; Vector shift instruction with a register source, a register destination, + ;; and an immediate plus an optional register as shift count. + (VecShiftRR + (shift_op VecShiftOp) + (rd WritableReg) + (rn Reg) + (shift_imm u8) + (shift_reg Reg)) + + ;; Vector select instruction. + (VecSelect + (rd WritableReg) + (rn Reg) + (rm Reg) + (ra Reg)) + + ;; Vector permute instruction. + (VecPermute + (rd WritableReg) + (rn Reg) + (rm Reg) + (ra Reg)) + + ;; Vector permute doubleword immediate instruction. + (VecPermuteDWImm + (rd WritableReg) + (rn Reg) + (rm Reg) + (idx1 u8) + (idx2 u8)) + + ;; Vector integer comparison with two register sources and a register + ;; destination. + (VecIntCmp + (op VecIntCmpOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Same, but also set the condition code. + (VecIntCmpS + (op VecIntCmpOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Vector floating-point comparison with two register sources and a register + ;; destination. + (VecFloatCmp + (op VecFloatCmpOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Same, but also set the condition code. + (VecFloatCmpS + (op VecFloatCmpOp) + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Synthetic instruction to compare signed 128-bit values. + ;; Sets CC 1 if rn > rm, sets a different CC otherwise. + (VecInt128SCmpHi + (tmp WritableReg) + (rn Reg) + (rm Reg)) + + ;; Synthetic instruction to compare unsigned 128-bit values. + ;; Sets CC 1 if rn > rm, sets a different CC otherwise. + (VecInt128UCmpHi + (tmp WritableReg) + (rn Reg) + (rm Reg)) + + ;; 128-bit vector load instruction. + (VecLoad + (rd WritableReg) + (mem MemArg)) + + ;; 128-bit byte-reversed vector load instruction. + (VecLoadRev + (rd WritableReg) + (mem MemArg)) + + ;; 8x16-bit byte-reversed vector load instruction. + (VecLoadByte16Rev + (rd WritableReg) + (mem MemArg)) + + ;; 4x32-bit byte-reversed vector load instruction. + (VecLoadByte32Rev + (rd WritableReg) + (mem MemArg)) + + ;; 2x64-bit byte-reversed vector load instruction. + (VecLoadByte64Rev + (rd WritableReg) + (mem MemArg)) + + ;; 8x16-bit element-reversed vector load instruction. + (VecLoadElt16Rev + (rd WritableReg) + (mem MemArg)) + + ;; 4x32-bit element-reversed vector load instruction. + (VecLoadElt32Rev + (rd WritableReg) + (mem MemArg)) + + ;; 2x64-bit element-reversed vector load instruction. + (VecLoadElt64Rev + (rd WritableReg) + (mem MemArg)) + + ;; 128-bit vector store instruction. + (VecStore + (rd Reg) + (mem MemArg)) + + ;; 128-bit byte-reversed vector store instruction. + (VecStoreRev + (rd Reg) + (mem MemArg)) + + ;; 8x16-bit byte-reversed vector store instruction. + (VecStoreByte16Rev + (rd Reg) + (mem MemArg)) + + ;; 4x32-bit byte-reversed vector store instruction. + (VecStoreByte32Rev + (rd Reg) + (mem MemArg)) + + ;; 2x64-bit byte-reversed vector store instruction. + (VecStoreByte64Rev + (rd Reg) + (mem MemArg)) + + ;; 8x16-bit element-reversed vector store instruction. + (VecStoreElt16Rev + (rd Reg) + (mem MemArg)) + + ;; 4x32-bit element-reversed vector store instruction. + (VecStoreElt32Rev + (rd Reg) + (mem MemArg)) + + ;; 2x64-bit element-reversed vector store instruction. + (VecStoreElt64Rev + (rd Reg) + (mem MemArg)) + + ;; 128-bit vector load replicated element instruction. + (VecLoadReplicate + (size u32) + (rd WritableReg) + (mem MemArg)) + + ;; 128-bit byte-reversed vector load replicated element instruction. + (VecLoadReplicateRev + (size u32) + (rd WritableReg) + (mem MemArg)) + + ;; Vector move instruction. + (VecMov + (rd WritableReg) + (rn Reg)) + + ;; Conditional vector move instruction. + (VecCMov + (rd WritableReg) + (cond Cond) + (ri Reg) + (rm Reg)) + + ;; A 128-bit move instruction from two GPRs to a VR. + (MovToVec128 + (rd WritableReg) + (rn Reg) + (rm Reg)) + + ;; Load 128-bit (big-endian) vector constant. + (VecLoadConst + (rd WritableReg) + (const_data u128)) + + ;; Load 128-bit (big-endian) replicated vector constant. + (VecLoadConstReplicate + (size u32) + (rd WritableReg) + (const_data u64)) + + ;; Load vector immediate generated via byte mask. + (VecImmByteMask + (rd WritableReg) + (mask u16)) + + ;; Load vector replicated contiguous bit mask. + (VecImmBitMask + (size u32) + (rd WritableReg) + (start_bit u8) + (end_bit u8)) + + ;; Load vector replicated immediate. + (VecImmReplicate + (size u32) + (rd WritableReg) + (imm i16)) + + ;; Vector lane insertion with an in/out VR, a memory source, + ;; and an immediate as lane index. + (VecLoadLane + (size u32) + (rd WritableReg) + (ri Reg) + (mem MemArg) + (lane_imm u8)) + + ;; Same as VecLoadLane, but allow undefined input VR. + (VecLoadLaneUndef + (size u32) + (rd WritableReg) + (mem MemArg) + (lane_imm u8)) + + ;; Byte-reversed vector lane insertion with an in/out VR, a memory source, + ;; and an immediate as lane index. + (VecLoadLaneRev + (size u32) + (rd WritableReg) + (ri Reg) + (mem MemArg) + (lane_imm u8)) + + ;; Same as VecLoadLaneRev, but allow undefined input VR. + (VecLoadLaneRevUndef + (size u32) + (rd WritableReg) + (mem MemArg) + (lane_imm u8)) + + ;; Vector lane extraction with a memory destination, a VR source, + ;; and an immediate as lane index. + (VecStoreLane + (size u32) + (rd Reg) + (mem MemArg) + (lane_imm u8)) + + ;; Byte-reversed vector lane extraction with a memory destination, a VR source, + ;; and an immediate as lane index. + (VecStoreLaneRev + (size u32) + (rd Reg) + (mem MemArg) + (lane_imm u8)) + + ;; Vector lane insertion with an in/out VR, a GPR source, + ;; and an immediate plus an optional register as lane index. + (VecInsertLane + (size u32) + (rd WritableReg) + (ri Reg) + (rn Reg) + (lane_imm u8) + (lane_reg Reg)) + + ;; Same as VecInsertLane, but allow undefined input VR. + (VecInsertLaneUndef + (size u32) + (rd WritableReg) + (rn Reg) + (lane_imm u8) + (lane_reg Reg)) + + ;; Vector lane extraction with a VR source, a GPR destination, + ;; and an immediate plus an optional register as lane index. + (VecExtractLane + (size u32) + (rd WritableReg) + (rn Reg) + (lane_imm u8) + (lane_reg Reg)) + + ;; Vector lane insertion with an in/out VR, an immediate source, + ;; and an immediate as lane index. + (VecInsertLaneImm + (size u32) + (rd WritableReg) + (ri Reg) + (imm i16) + (lane_imm u8)) + + ;; Vector lane replication with a VR source, a VR destination, + ;; and an immediate as lane index. + (VecReplicateLane + (size u32) + (rd WritableReg) + (rn Reg) + (lane_imm u8)) + + ;; Allocate stack space for outgoing tail-call arguments. + (AllocateArgs + (size u32)) + + ;; A machine call instruction. + (Call + (link WritableReg) + (info BoxCallInfo)) + + ;; A machine indirect-call instruction. + (CallInd + (link WritableReg) + (info BoxCallIndInfo)) + + ;; A machine tail call instruction. + (ReturnCall + (info BoxReturnCallInfo)) + + ;; A machine indirect tail call instruction. + (ReturnCallInd + (info BoxReturnCallIndInfo)) + + ;; A pseudo-instruction that captures register arguments in vregs. + (Args + (args VecArgPair)) + + ;; A pseudo-instruction that moves vregs to return registers. + (Rets + (rets VecRetPair)) + + ;; ---- branches (exactly one must appear at end of BB) ---- + + ;; A machine return instruction. + (Ret + (link Reg)) + + ;; An unconditional branch. + (Jump + (dest MachLabel)) + + ;; A conditional branch. Contains two targets; at emission time, both are emitted, but + ;; the MachBuffer knows to truncate the trailing branch if fallthrough. We optimize the + ;; choice of taken/not_taken (inverting the branch polarity as needed) based on the + ;; fallthrough at the time of lowering. + (CondBr + (taken MachLabel) + (not_taken MachLabel) + (cond Cond)) + + ;; A conditional trap execute a `Trap` if the condition is true. This is + ;; one VCode instruction because it uses embedded control flow; it is + ;; logically a single-in, single-out region, but needs to appear as one + ;; unit to the register allocator. + ;; + ;; The `Cond` gives the conditional-branch condition that will + ;; *execute* the embedded `Trap`. (In the emitted code, we use the inverse + ;; of this condition in a branch that skips the trap instruction.) + (TrapIf + (cond Cond) + (trap_code TrapCode)) + + ;; A one-way conditional branch, invisible to the CFG processing; used *only* as part of + ;; straight-line sequences in code to be emitted. + ;; + ;; In more detail: + ;; - This branch is lowered to a branch at the machine-code level, but does not end a basic + ;; block, and does not create edges in the CFG seen by regalloc. + ;; - Thus, it is *only* valid to use as part of a single-in, single-out sequence that is + ;; lowered from a single CLIF instruction. For example, certain arithmetic operations may + ;; use these branches to handle certain conditions, such as overflows, traps, etc. + ;; + ;; See, e.g., the lowering of `trapif` (conditional trap) for an example. + (OneWayCondBr + (target MachLabel) + (cond Cond)) + + ;; An indirect branch through a register, augmented with set of all + ;; possible successors. + (IndirectBr + (rn Reg) + (targets VecMachLabel)) + + ;; A "debugtrap" instruction, used for e.g. traps and debug breakpoints. + (Debugtrap) + + ;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at + ;; runtime. + (Trap + (trap_code TrapCode)) + + ;; Jump-table sequence, as one compound instruction (see note in lower.rs + ;; for rationale). + (JTSequence + (ridx Reg) + (targets BoxVecMachLabel)) + + ;; Stack probe loop sequence, as one compound instruction. + (StackProbeLoop + (probe_count WritableReg) + (guard_size i16)) + + ;; Load an inline symbol reference with relocation. + (LoadSymbolReloc + (rd WritableReg) + (symbol_reloc BoxSymbolReloc)) + + ;; Load address referenced by `mem` into `rd`. + (LoadAddr + (rd WritableReg) + (mem MemArg)) + + ;; Meta-instruction to emit a loop around a sequence of instructions. + ;; This control flow is not visible to the compiler core, in particular + ;; the register allocator. Therefore, instructions in the loop may not + ;; write to any virtual register, so any writes must use reserved hard + ;; registers (e.g. %r0, %r1). *Reading* virtual registers is OK. + (Loop + (body VecMInst) + (cond Cond)) + + ;; Conditional branch breaking out of a loop emitted via Loop. + (CondBreak + (cond Cond)) + + ;; Pseudoinstruction to keep a value alive. + (DummyUse + (reg Reg)) + + ;; An unwind pseudoinstruction describing the state of the + ;; machine at this program point. + (Unwind + (inst UnwindInst)) + + ;; Pseudo-instruction used for `tls_value` to call the libcall of the same + ;; name. + (ElfTlsGetOffset + (tls_offset WritableReg) + (got Reg) + (got_offset Reg) + (symbol BoxSymbolReloc)) +)) + +;; Primitive types used in instruction formats. + +(type BoxCallInfo (primitive BoxCallInfo)) +(type BoxCallIndInfo (primitive BoxCallIndInfo)) +(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) +(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) +(type BoxJTSequenceInfo (primitive BoxJTSequenceInfo)) +(type VecMachLabel extern (enum)) + +;; A symbol reference carrying relocation information. +(type SymbolReloc + (enum + ;; Absolute symbol reference (with optional offset). + (Absolute + (name ExternalName) + (offset i64)) + ;; Reference to a TLS symbol in general-dynamic mode. + (TlsGd + (name ExternalName)))) + +;; Boxed version of SymbolReloc to save space. +(type BoxSymbolReloc (primitive BoxSymbolReloc)) +(decl box_symbol_reloc (SymbolReloc) BoxSymbolReloc) +(extern constructor box_symbol_reloc box_symbol_reloc) +(convert SymbolReloc BoxSymbolReloc box_symbol_reloc) + +;; An ALU operation. +(type ALUOp + (enum + (Add32) + (Add32Ext16) + (Add64) + (Add64Ext16) + (Add64Ext32) + (AddLogical32) + (AddLogical64) + (AddLogical64Ext32) + (Sub32) + (Sub32Ext16) + (Sub64) + (Sub64Ext16) + (Sub64Ext32) + (SubLogical32) + (SubLogical64) + (SubLogical64Ext32) + (Mul32) + (Mul32Ext16) + (Mul64) + (Mul64Ext16) + (Mul64Ext32) + (And32) + (And64) + (Orr32) + (Orr64) + (Xor32) + (Xor64) + ;; NAND + (NotAnd32) + (NotAnd64) + ;; NOR + (NotOrr32) + (NotOrr64) + ;; XNOR + (NotXor32) + (NotXor64) + ;; And with complement + (AndNot32) + (AndNot64) + ;; Or with complement + (OrrNot32) + (OrrNot64) +)) + +;; A unary operation. +(type UnaryOp + (enum + (Abs32) + (Abs64) + (Abs64Ext32) + (Neg32) + (Neg64) + (Neg64Ext32) + (PopcntByte) + (PopcntReg) + (BSwap32) + (BSwap64) +)) + +;; A shift operation. +(type ShiftOp + (enum + (RotL32) + (RotL64) + (LShL32) + (LShL64) + (LShR32) + (LShR64) + (AShR32) + (AShR64) +)) + +;; A rotate-then--selected-bits operation. +(type RxSBGOp + (enum + (Insert) + (And) + (Or) + (Xor) +)) + +;; An integer comparison operation. +(type CmpOp + (enum + (CmpS32) + (CmpS32Ext16) + (CmpS64) + (CmpS64Ext16) + (CmpS64Ext32) + (CmpL32) + (CmpL32Ext16) + (CmpL64) + (CmpL64Ext16) + (CmpL64Ext32) +)) + +;; A binary vector operation. +(type VecBinaryOp + (enum + ;; Addition and subtraction + (Add8x16) + (Add16x8) + (Add32x4) + (Add64x2) + (Add128) + (Sub8x16) + (Sub16x8) + (Sub32x4) + (Sub64x2) + (Sub128) + ;; Multiplication (64-bit not supported) + (Mul8x16) + (Mul16x8) + (Mul32x4) + (UMulHi8x16) + (UMulHi16x8) + (UMulHi32x4) + (SMulHi8x16) + (SMulHi16x8) + (SMulHi32x4) + (UMulEven8x16) + (UMulEven16x8) + (UMulEven32x4) + (SMulEven8x16) + (SMulEven16x8) + (SMulEven32x4) + (UMulOdd8x16) + (UMulOdd16x8) + (UMulOdd32x4) + (SMulOdd8x16) + (SMulOdd16x8) + (SMulOdd32x4) + ;; Minimum, maximum, and average + (UMax8x16) + (UMax16x8) + (UMax32x4) + (UMax64x2) + (SMax8x16) + (SMax16x8) + (SMax32x4) + (SMax64x2) + (UMin8x16) + (UMin16x8) + (UMin32x4) + (UMin64x2) + (SMin8x16) + (SMin16x8) + (SMin32x4) + (SMin64x2) + (UAvg8x16) + (UAvg16x8) + (UAvg32x4) + (UAvg64x2) + (SAvg8x16) + (SAvg16x8) + (SAvg32x4) + (SAvg64x2) + ;; Bitwise operations + (And128) + (Orr128) + (Xor128) + (NotAnd128) + (NotOrr128) + (NotXor128) + (AndNot128) + (OrrNot128) + ;; Bit permute + (BitPermute128) + ;; Full vector shift operations + (LShLByByte128) + (LShRByByte128) + (AShRByByte128) + (LShLByBit128) + (LShRByBit128) + (AShRByBit128) + ;; Pack + (Pack16x8) + (Pack32x4) + (Pack64x2) + ;; Pack saturate (unsigned) + (PackUSat16x8) + (PackUSat32x4) + (PackUSat64x2) + ;; Pack saturate (signed) + (PackSSat16x8) + (PackSSat32x4) + (PackSSat64x2) + ;; Merge + (MergeLow8x16) + (MergeLow16x8) + (MergeLow32x4) + (MergeLow64x2) + (MergeHigh8x16) + (MergeHigh16x8) + (MergeHigh32x4) + (MergeHigh64x2) +)) + +;; A vector unary operation. +(type VecUnaryOp + (enum + ;; Sign operations + (Abs8x16) + (Abs16x8) + (Abs32x4) + (Abs64x2) + (Neg8x16) + (Neg16x8) + (Neg32x4) + (Neg64x2) + ;; Population count + (Popcnt8x16) + (Popcnt16x8) + (Popcnt32x4) + (Popcnt64x2) + ;; Count leading/trailing zeros + (Clz8x16) + (Clz16x8) + (Clz32x4) + (Clz64x2) + (Ctz8x16) + (Ctz16x8) + (Ctz32x4) + (Ctz64x2) + ;; Unpack + (UnpackULow8x16) + (UnpackULow16x8) + (UnpackULow32x4) + (UnpackUHigh8x16) + (UnpackUHigh16x8) + (UnpackUHigh32x4) + (UnpackSLow8x16) + (UnpackSLow16x8) + (UnpackSLow32x4) + (UnpackSHigh8x16) + (UnpackSHigh16x8) + (UnpackSHigh32x4) +)) + +;; A vector shift operation. +(type VecShiftOp + (enum + (RotL8x16) + (RotL16x8) + (RotL32x4) + (RotL64x2) + (LShL8x16) + (LShL16x8) + (LShL32x4) + (LShL64x2) + (LShR8x16) + (LShR16x8) + (LShR32x4) + (LShR64x2) + (AShR8x16) + (AShR16x8) + (AShR32x4) + (AShR64x2) +)) + +;; An integer vector comparison operation. +(type VecIntCmpOp + (enum + (CmpEq8x16) + (CmpEq16x8) + (CmpEq32x4) + (CmpEq64x2) + (SCmpHi8x16) + (SCmpHi16x8) + (SCmpHi32x4) + (SCmpHi64x2) + (UCmpHi8x16) + (UCmpHi16x8) + (UCmpHi32x4) + (UCmpHi64x2) +)) + +;; A floatint-point vector comparison operation. +(type VecFloatCmpOp + (enum + (CmpEq32x4) + (CmpEq64x2) + (CmpHi32x4) + (CmpHi64x2) + (CmpHiEq32x4) + (CmpHiEq64x2) +)) + +;; A floating-point unit (FPU) operation with one arg. +(type FPUOp1 + (enum + (Abs32) + (Abs64) + (Abs32x4) + (Abs64x2) + (Neg32) + (Neg64) + (Neg32x4) + (Neg64x2) + (NegAbs32) + (NegAbs64) + (NegAbs32x4) + (NegAbs64x2) + (Sqrt32) + (Sqrt64) + (Sqrt32x4) + (Sqrt64x2) + (Cvt32To64) + (Cvt32x4To64x2) +)) + +;; A floating-point unit (FPU) operation with two args. +(type FPUOp2 + (enum + (Add32) + (Add64) + (Add32x4) + (Add64x2) + (Sub32) + (Sub64) + (Sub32x4) + (Sub64x2) + (Mul32) + (Mul64) + (Mul32x4) + (Mul64x2) + (Div32) + (Div64) + (Div32x4) + (Div64x2) + (Max32) + (Max64) + (Max32x4) + (Max64x2) + (Min32) + (Min64) + (Min32x4) + (Min64x2) + (MaxPseudo32) + (MaxPseudo64) + (MaxPseudo32x4) + (MaxPseudo64x2) + (MinPseudo32) + (MinPseudo64) + (MinPseudo32x4) + (MinPseudo64x2) +)) + +;; A floating-point unit (FPU) operation with three args. +(type FPUOp3 + (enum + (MAdd32) + (MAdd64) + (MAdd32x4) + (MAdd64x2) + (MSub32) + (MSub64) + (MSub32x4) + (MSub64x2) +)) + +;; A floating-point unit (FPU) operation with one arg, and rounding mode. +(type FpuRoundOp + (enum + (Cvt64To32) + (Cvt64x2To32x4) + (Round32) + (Round64) + (Round32x4) + (Round64x2) + (ToSInt32) + (ToSInt64) + (ToUInt32) + (ToUInt64) + (ToSInt32x4) + (ToSInt64x2) + (ToUInt32x4) + (ToUInt64x2) + (FromSInt32) + (FromSInt64) + (FromUInt32) + (FromUInt64) + (FromSInt32x4) + (FromSInt64x2) + (FromUInt32x4) + (FromUInt64x2) +)) + +;; Rounding modes for floating-point ops. +(type FpuRoundMode + (enum + (Current) + (ToNearest) + (ShorterPrecision) + (ToNearestTiesToEven) + (ToZero) + (ToPosInfinity) + (ToNegInfinity) +)) + + +;; Helpers for querying enabled ISA extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl mie2_enabled () Type) +(extern extractor mie2_enabled mie2_enabled) +(decl mie2_disabled () Type) +(extern extractor mie2_disabled mie2_disabled) + +(decl vxrs_ext2_enabled () Type) +(extern extractor vxrs_ext2_enabled vxrs_ext2_enabled) +(decl vxrs_ext2_disabled () Type) +(extern extractor vxrs_ext2_disabled vxrs_ext2_disabled) + +;; Helpers for SIMD lane number operations ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; There are two ways to map vector types onto the SIMD vector registers +;; supported by the ISA, differing by the way lanes are numbered. In +;; little-endian lane order, lane 0 of a multi-lane vector value resides +;; in the least-significant parts of a vector register (when interpreted +;; as holding a single $I128 value); in big-endian lane order, lane 0 +;; instead resides in the most-significant parts of the register. +;; +;; As long as used consistently, output of cranelift may use either lane +;; order method to implement CLIF semantics. However, depending on the +;; particular use case, one or the other order will lead to more efficient +;; code. Therefore this back end supports both code generation options. +;; +;; Note that the ISA instructions use immediate lane number according +;; to big-endian lane order; so when using little-endian lane order, +;; immediate lane numbers have to be translated. +(type LaneOrder + (enum + (LittleEndian) + (BigEndian))) + +;; Return the lane order to be used when compiling the current function. +;; This will be a property of the function ABI. Functions using the +;; the Wasmtime ABI will use little-endian lane order, functions using +;; other ABIs will big-endian lane order. +(decl pure lane_order () LaneOrder) +(extern constructor lane_order lane_order) + +;; Check whether two lane order values are equal. +(decl pure lane_order_equal (LaneOrder LaneOrder) bool) +(rule (lane_order_equal (LaneOrder.LittleEndian) (LaneOrder.LittleEndian)) true) +(rule (lane_order_equal (LaneOrder.LittleEndian) (LaneOrder.BigEndian)) false) +(rule (lane_order_equal (LaneOrder.BigEndian) (LaneOrder.LittleEndian)) false) +(rule (lane_order_equal (LaneOrder.BigEndian) (LaneOrder.BigEndian)) true) + +;; Return lane order matching memory byte order. +(decl pure lane_order_from_memflags (MemFlags) LaneOrder) +(rule 0 (lane_order_from_memflags (littleendian)) (LaneOrder.LittleEndian)) +(rule 1 (lane_order_from_memflags (bigendian)) (LaneOrder.BigEndian)) + +;; Convert a CLIF immediate lane index value to big-endian lane order. +(decl be_lane_idx (Type u8) u8) +(extern constructor be_lane_idx be_lane_idx) + +;; Convert a CLIF immediate vector constant to big-endian lane order. +(decl be_vec_const (Type u128) u128) +(extern constructor be_vec_const be_vec_const) + + +;; Helpers for register numbers and types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Hard-coded registers. +(decl writable_gpr (u8) WritableReg) +(extern constructor writable_gpr writable_gpr) + +;; The zero register. +(decl zero_reg () Reg) +(extern constructor zero_reg zero_reg) + +;; Types that can be operated on using 32-bit GPR instructions +(decl gpr32_ty (Type) Type) +(extern extractor gpr32_ty gpr32_ty) + +;; Types that can be operated on using 64-bit GPR instructions +(decl gpr64_ty (Type) Type) +(extern extractor gpr64_ty gpr64_ty) + +;; Types that can be operated on using 128-bit vector instructions +(decl vr128_ty (Type) Type) +(extern extractor vr128_ty vr128_ty) + + +;; Helpers for various immediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Special integer types and their constructors + +(type UImm32Shifted (primitive UImm32Shifted)) +(decl uimm32shifted (u32 u8) UImm32Shifted) +(extern constructor uimm32shifted uimm32shifted) + +(type UImm16Shifted (primitive UImm16Shifted)) +(decl uimm16shifted (u16 u8) UImm16Shifted) +(extern constructor uimm16shifted uimm16shifted) + +;; Detect specific integer values + +(decl pure partial i64_nonequal (i64 i64) i64) +(extern constructor i64_nonequal i64_nonequal) + +(decl pure partial i64_not_neg1 (i64) i64) +(rule (i64_not_neg1 x) + (if (i64_nonequal x -1)) + x) + +;; Integer type casts (with the rust `as` semantics). + +(decl u8_as_u16 (u8) u16) +(extern constructor u8_as_u16 u8_as_u16) + +(decl u64_truncate_to_u32 (u64) u32) +(extern constructor u64_truncate_to_u32 u64_truncate_to_u32) + +(decl u64_as_i16 (u64) i16) +(extern constructor u64_as_i16 u64_as_i16) + +;; Construct and extract immediate vector constants. + +(decl u64_pair (u64 u64) u128) +(extern constructor u64_pair u64_pair_concat) +(extern extractor infallible u64_pair u64_pair_split) + +(decl u32_pair (u32 u32) u64) +(extern constructor u32_pair u32_pair_concat) +(extern extractor infallible u32_pair u32_pair_split) + +(decl u16_pair (u16 u16) u32) +(extern constructor u16_pair u16_pair_concat) +(extern extractor infallible u16_pair u16_pair_split) + +(decl u8_pair (u8 u8) u16) +(extern constructor u8_pair u8_pair_concat) +(extern extractor infallible u8_pair u8_pair_split) + +(decl imm8x16 (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) u128) +(extractor (imm8x16 a b c d e f g h i j k l m n o p) + (u64_pair (u32_pair (u16_pair (u8_pair a b) (u8_pair c d)) + (u16_pair (u8_pair e f) (u8_pair g h))) + (u32_pair (u16_pair (u8_pair i j) (u8_pair k l)) + (u16_pair (u8_pair m n) (u8_pair o p))))) +(rule (imm8x16 a b c d e f g h i j k l m n o p) + (u64_pair (u32_pair (u16_pair (u8_pair a b) (u8_pair c d)) + (u16_pair (u8_pair e f) (u8_pair g h))) + (u32_pair (u16_pair (u8_pair i j) (u8_pair k l)) + (u16_pair (u8_pair m n) (u8_pair o p))))) + +;; Construct a VGBM mask to set all bits in one lane of a vector. + +(decl lane_byte_mask (Type u8) u16) +(extern constructor lane_byte_mask lane_byte_mask) + +;; Extract "permute" and "and" masks from a shuffle constant + +(decl shuffle_mask_from_u128 (u128 u16) u128) +(extern extractor infallible shuffle_mask_from_u128 shuffle_mask_from_u128) + +(decl shuffle_mask (u128 u16) Immediate) +(extractor (shuffle_mask permute_mask and_mask) + (u128_from_immediate (shuffle_mask_from_u128 permute_mask and_mask))) + +;; Split an u64 into high and low parts. + +(decl u64_nonzero_hipart (u64) u64) +(extern extractor u64_nonzero_hipart u64_nonzero_hipart) + +(decl u64_nonzero_lopart (u64) u64) +(extern extractor u64_nonzero_lopart u64_nonzero_lopart) + +;; Extract smaller integer type from u64 if it matches. + +(decl i32_from_u64 (i32) u64) +(extern extractor i32_from_u64 i32_from_u64) + +(decl i16_from_u64 (i16) u64) +(extern extractor i16_from_u64 i16_from_u64) + +(decl i16_from_u32 (i16) u32) +(extern extractor i16_from_u32 i16_from_u32) + +(decl uimm32shifted_from_u64 (UImm32Shifted) u64) +(extern extractor uimm32shifted_from_u64 uimm32shifted_from_u64) + +(decl uimm16shifted_from_u64 (UImm16Shifted) u64) +(extern extractor uimm16shifted_from_u64 uimm16shifted_from_u64) + +;; Extract integer of certain type from value if it matches. + +(decl u64_from_value (u64) Value) +(extern extractor u64_from_value u64_from_value) + +(decl u32_from_value (u32) Value) +(extern extractor u32_from_value u32_from_value) + +(decl u8_from_value (u8) Value) +(extern extractor u8_from_value u8_from_value) + +(decl u64_from_signed_value (u64) Value) +(extern extractor u64_from_signed_value u64_from_signed_value) + +(decl u64_from_inverted_value (u64) Value) +(extern extractor u64_from_inverted_value u64_from_inverted_value) + +(decl i64_from_value (i64) Value) +(extern extractor i64_from_value i64_from_value) + +(decl i32_from_value (i32) Value) +(extern extractor i32_from_value i32_from_value) + +(decl i16_from_value (i16) Value) +(extern extractor i16_from_value i16_from_value) + +(decl i16_from_swapped_value (i16) Value) +(extern extractor i16_from_swapped_value i16_from_swapped_value) + +(decl i64_from_negated_value (i64) Value) +(extern extractor i64_from_negated_value i64_from_negated_value) + +(decl i32_from_negated_value (i32) Value) +(extern extractor i32_from_negated_value i32_from_negated_value) + +(decl i16_from_negated_value (i16) Value) +(extern extractor i16_from_negated_value i16_from_negated_value) + +(decl uimm16shifted_from_value (UImm16Shifted) Value) +(extern extractor uimm16shifted_from_value uimm16shifted_from_value) + +(decl uimm32shifted_from_value (UImm32Shifted) Value) +(extern extractor uimm32shifted_from_value uimm32shifted_from_value) + +(decl uimm16shifted_from_inverted_value (UImm16Shifted) Value) +(extern extractor uimm16shifted_from_inverted_value uimm16shifted_from_inverted_value) + +(decl uimm32shifted_from_inverted_value (UImm32Shifted) Value) +(extern extractor uimm32shifted_from_inverted_value uimm32shifted_from_inverted_value) + +(decl len_minus_one (u8) u64) +(extern extractor len_minus_one len_minus_one) + + +;; Helpers for masking shift amounts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Mask (immediate) shift amount to the type size. +(decl mask_amt_imm (Type i64) u8) +(extern constructor mask_amt_imm mask_amt_imm) + +;; Mask (immediate) shift amount to the type size. +;; Note that the hardware instructions always masks to six bits, so +;; in the case of a 64-bit type we do not need any explicit masking. +(decl mask_amt_reg (Type Reg) Reg) +(rule (mask_amt_reg (gpr32_ty ty) reg) + (let ((mask u8 (mask_amt_imm ty -1))) + (and_uimm16shifted ty reg (uimm16shifted (u8_as_u16 mask) 0)))) +(rule 1 (mask_amt_reg (gpr64_ty ty) reg) reg) + +;; Load a shift amount into a GPR. +(decl amt_reg (Value) Reg) +(rule 1 (amt_reg amt @ (value_type (fits_in_64 _))) amt) +(rule (amt_reg amt @ (value_type (vr128_ty _))) + (vec_extract_lane $I64X2 amt 1 (zero_reg))) + +;; Load a shift amount into a VR, replicated across all 16 bytes. +(decl amt_vr (Value) Reg) +(rule (amt_vr amt @ (value_type (fits_in_64 _))) + (vec_replicate_lane $I8X16 + (vec_insert_lane_undef $I8X16 amt 0 (zero_reg)) 0)) +(rule 1 (amt_vr amt @ (value_type (vr128_ty _))) + (vec_replicate_lane $I8X16 amt 15)) +(rule 2 (amt_vr (u64_from_value amt)) + (vec_imm_splat $I8X16 amt)) + + +;; Helpers for condition codes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type Cond extern (enum)) + +(decl mask_as_cond (u8) Cond) +(extern constructor mask_as_cond mask_as_cond) + +(decl intcc_as_cond (IntCC) Cond) +(extern constructor intcc_as_cond intcc_as_cond) + +(decl floatcc_as_cond (FloatCC) Cond) +(extern constructor floatcc_as_cond floatcc_as_cond) + +(decl invert_cond (Cond) Cond) +(extern constructor invert_cond invert_cond) + +(decl signed () IntCC) +(extern extractor signed signed) + +(decl unsigned () IntCC) +(extern extractor unsigned unsigned) + + +;; Helpers for memory arguments ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Accessors for `Offset32`. + +(decl zero_offset () Offset32) +(extern constructor zero_offset zero_offset) + +(decl i64_from_offset (i64) Offset32) +(extern extractor infallible i64_from_offset i64_from_offset) + +;; Accessors for `MemFlags`. + +(decl littleendian () MemFlags) +(extern extractor littleendian littleendian) + +(decl bigendian () MemFlags) +(extern extractor bigendian bigendian) + +(decl memflags_trusted () MemFlags) +(extern constructor memflags_trusted memflags_trusted) + +;; Accessors for `MemArg`. + +(type MemArg extern (enum)) + +(decl memarg_flags (MemArg) MemFlags) +(extern constructor memarg_flags memarg_flags) + +(decl memarg_reg_plus_reg (Reg Reg u8 MemFlags) MemArg) +(extern constructor memarg_reg_plus_reg memarg_reg_plus_reg) + +(decl memarg_reg_plus_off (Reg i64 u8 MemFlags) MemArg) +(extern constructor memarg_reg_plus_off memarg_reg_plus_off) + +(decl memarg_symbol (ExternalName i32 MemFlags) MemArg) +(extern constructor memarg_symbol memarg_symbol) + +(decl memarg_got () MemArg) +(extern constructor memarg_got memarg_got) + +;; Add an offset to a virtual MemArg. +(decl memarg_offset (MemArg i64) MemArg) +(extern constructor memarg_offset memarg_offset) + +;; Form the sum of two offset values, and check that the result is +;; a valid `MemArg::Symbol` offset (i.e. is even and fits into i32). +(decl pure partial memarg_symbol_offset_sum (i64 i64) i32) +(extern constructor memarg_symbol_offset_sum memarg_symbol_offset_sum) + +;; Likewise, but just check a single offset value. +(decl pure partial memarg_symbol_offset (i64) i32) +(rule (memarg_symbol_offset x) + (memarg_symbol_offset_sum x 0)) + +;; Create a MemArg referring to the saved frame pointer location. +(decl memarg_frame_pointer_offset () MemArg) +(extern constructor memarg_frame_pointer_offset memarg_frame_pointer_offset) + +;; Create a MemArg referring to the saved return address location. +(decl memarg_return_address_offset () MemArg) +(extern constructor memarg_return_address_offset memarg_return_address_offset) + +;; Lower an address into a `MemArg`. + +(decl lower_address (MemFlags Value Offset32) MemArg) + +(rule (lower_address flags addr @ (value_type (ty_addr64 _)) (i64_from_offset offset)) + (memarg_reg_plus_off addr offset 0 flags)) + +(rule 1 (lower_address flags (has_type (ty_addr64 _) (iadd x y)) (i64_from_offset 0)) + (memarg_reg_plus_reg x y 0 flags)) + +(rule 1 (lower_address flags + (symbol_value (symbol_value_data name (reloc_distance_near) sym_offset)) + (i64_from_offset offset)) + (if-let final_offset (memarg_symbol_offset_sum offset sym_offset)) + (memarg_symbol name final_offset flags)) + + +;; Lower an address plus a small bias into a `MemArg`. + +(decl lower_address_bias (MemFlags Value Offset32 u8) MemArg) + +(rule (lower_address_bias flags addr @ (value_type $I64) (i64_from_offset offset) bias) + (memarg_reg_plus_off addr offset bias flags)) + +(rule 1 (lower_address_bias flags (has_type $I64 (iadd x y)) (i64_from_offset 0) bias) + (memarg_reg_plus_reg x y bias flags)) + + +;; Test whether a `load` address will be lowered to a `MemArg::Symbol`. + +(decl pure partial load_sym (Inst) Inst) +(rule (load_sym inst) + (if-let (load _ (symbol_value (symbol_value_data _ (reloc_distance_near) sym_offset)) + (i64_from_offset load_offset)) + inst) + (if (memarg_symbol_offset_sum sym_offset load_offset)) + inst) + +(decl pure partial uload16_sym (Inst) Inst) +(rule (uload16_sym inst) + (if-let (uload16 _ (symbol_value (symbol_value_data _ (reloc_distance_near) sym_offset)) + (i64_from_offset load_offset)) + inst) + (if (memarg_symbol_offset_sum sym_offset load_offset)) + inst) + + +;; Helpers for stack-slot addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl stack_addr_impl (Type StackSlot Offset32) Reg) +(rule (stack_addr_impl ty stack_slot offset) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (abi_stackslot_addr dst stack_slot offset)))) + dst)) + + +;; Helpers for extracting extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; A value that is the result of a sign-extend from a 32-bit value. +(decl sext32_value (Value) Value) +(extractor (sext32_value x) (sextend (and x (value_type $I32)))) + +;; A value that is the result of a zero-extend from a 32-bit value. +(decl zext32_value (Value) Value) +(extractor (zext32_value x) (uextend (and x (value_type $I32)))) + + +;; Helpers for sinkable loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extract a sinkable instruction from a value operand. +(decl sinkable_inst (Inst) Value) +(extern extractor sinkable_inst sinkable_inst) + +;; Sinkable big-endian load instruction. +(decl sinkable_load (Inst) Value) +(extractor (sinkable_load inst) + (sinkable_inst (and inst (load (bigendian) _addr _offset)))) + +;; Sinkable big-endian load instruction (32/64-bit types only). +(decl sinkable_load_32_64 (Inst) Value) +(extractor (sinkable_load_32_64 inst) + (and (value_type (ty_32_or_64 _)) (sinkable_load inst))) + +;; Sinkable big-endian load instruction (16-bit types only). +(decl sinkable_load_16 (Inst) Value) +(extractor (sinkable_load_16 inst) + (and (value_type $I16) (sinkable_load inst))) + +;; Sinkable little-endian load instruction. +(decl sinkable_load_little (Inst) Value) +(extractor (sinkable_load_little inst) + (sinkable_inst (and inst (load (littleendian) _addr _offset)))) + +;; Sinkable big-endian sload16 instruction. +(decl sinkable_sload16 (Inst) Value) +(extractor (sinkable_sload16 inst) + (sinkable_inst (and inst (sload16 (bigendian) _addr _offset)))) + +;; Sinkable big-endian sload32 instruction. +(decl sinkable_sload32 (Inst) Value) +(extractor (sinkable_sload32 inst) + (sinkable_inst (and inst (sload32 (bigendian) _addr _offset)))) + +;; Sinkable big-endian uload16 instruction. +(decl sinkable_uload16 (Inst) Value) +(extractor (sinkable_uload16 inst) + (sinkable_inst (and inst (uload16 (bigendian) _addr _offset)))) + +;; Sinkable big-endian uload32 instruction. +(decl sinkable_uload32 (Inst) Value) +(extractor (sinkable_uload32 inst) + (sinkable_inst (and inst (uload32 (bigendian) _addr _offset)))) + +;; Sink a load instruction, returning its address as `MemArg`. +;; This is a side-effectful operation, see `sink_inst`. +(decl sink_load (Inst) MemArg) +(rule (sink_load inst @ (load flags addr offset)) + (let ((_ Unit (sink_inst inst))) + (lower_address flags addr offset))) + +;; Sink a sload16 instruction, returning its address as `MemArg`. +;; This is a side-effectful operation, see `sink_inst`. +(decl sink_sload16 (Inst) MemArg) +(rule (sink_sload16 inst @ (sload16 flags addr offset)) + (let ((_ Unit (sink_inst inst))) + (lower_address flags addr offset))) + +;; Sink a sload32 instruction, returning its address as `MemArg`. +;; This is a side-effectful operation, see `sink_inst`. +(decl sink_sload32 (Inst) MemArg) +(rule (sink_sload32 inst @ (sload32 flags addr offset)) + (let ((_ Unit (sink_inst inst))) + (lower_address flags addr offset))) + +;; Sink a uload16 instruction, returning its address as `MemArg`. +;; This is a side-effectful operation, see `sink_inst`. +(decl sink_uload16 (Inst) MemArg) +(rule (sink_uload16 inst @ (uload16 flags addr offset)) + (let ((_ Unit (sink_inst inst))) + (lower_address flags addr offset))) + +;; Sink a uload32 instruction, returning its address as `MemArg`. +;; This is a side-effectful operation, see `sink_inst`. +(decl sink_uload32 (Inst) MemArg) +(rule (sink_uload32 inst @ (uload32 flags addr offset)) + (let ((_ Unit (sink_inst inst))) + (lower_address flags addr offset))) + + +;; Helpers for register pairs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; A writable register pair. +(type WritableRegPair (primitive WritableRegPair)) + +;; Construct a WritableRegPair from two registers. +(decl writable_regpair (WritableReg WritableReg) WritableRegPair) +(extern constructor writable_regpair writable_regpair) + +;; Allocate a writable register pair. +(decl temp_writable_regpair () WritableRegPair) +(rule (temp_writable_regpair) + (writable_regpair (temp_writable_reg $I64) (temp_writable_reg $I64))) + +;; Retrieve the high word of the writable register pair. +(decl writable_regpair_hi (WritableRegPair) WritableReg) +(extern constructor writable_regpair_hi writable_regpair_hi) + +;; Retrieve the low word of the writable register pair. +(decl writable_regpair_lo (WritableRegPair) WritableReg) +(extern constructor writable_regpair_lo writable_regpair_lo) + +;; A (read-only) register pair. +(type RegPair (primitive RegPair)) + +;; Construct a register pair from a writable register pair. +(decl writable_regpair_to_regpair (WritableRegPair) RegPair) +(rule (writable_regpair_to_regpair w) + (regpair (writable_regpair_hi w) (writable_regpair_lo w))) + +;; Construct a regpair from two registers. +(decl regpair (Reg Reg) RegPair) +(extern constructor regpair regpair) + +;; Retrieve the high word of the register pair. +(decl regpair_hi (RegPair) Reg) +(extern constructor regpair_hi regpair_hi) + +;; Retrieve the low word of the register pair. +(decl regpair_lo (RegPair) Reg) +(extern constructor regpair_lo regpair_lo) + + +;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper for emitting `MInst.AluRRR` instructions. +(decl alu_rrr (Type ALUOp Reg Reg) Reg) +(rule (alu_rrr ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRRR op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.AluRRR` instructions as flag producers. +(decl alu_rrr_with_flags_paired (Type ALUOp Reg Reg) ProducesFlags) +(rule (alu_rrr_with_flags_paired ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRRR op dst src1 src2) dst))) + +;; Helper for emitting `MInst.AluRRSImm16` instructions. +(decl alu_rrsimm16 (Type ALUOp Reg i16) Reg) +(rule (alu_rrsimm16 ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRRSImm16 op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRR` instructions. +(decl alu_rr (Type ALUOp Reg Reg) Reg) +(rule (alu_rr ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRR op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.AluRR` instructions as flag producers. +(decl alu_rr_with_flags_paired (Type ALUOp Reg Reg) ProducesFlags) +(rule (alu_rr_with_flags_paired ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRR op dst src1 src2) dst))) + +;; Helper for emitting `MInst.AluRX` instructions. +(decl alu_rx (Type ALUOp Reg MemArg) Reg) +(rule (alu_rx ty op src mem) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRX op dst src mem)))) + dst)) + +;; Helper for emitting `MInst.AluRX` instructions as flags producers. +(decl alu_rx_with_flags_paired (Type ALUOp Reg MemArg) ProducesFlags) +(rule (alu_rx_with_flags_paired ty op src mem) + (let ((dst WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRX op dst src mem) dst))) + +;; Helper for emitting `MInst.AluRSImm16` instructions. +(decl alu_rsimm16 (Type ALUOp Reg i16) Reg) +(rule (alu_rsimm16 ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRSImm16 op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRSImm32` instructions. +(decl alu_rsimm32 (Type ALUOp Reg i32) Reg) +(rule (alu_rsimm32 ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRSImm32 op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRUImm32` instructions. +(decl alu_ruimm32 (Type ALUOp Reg u32) Reg) +(rule (alu_ruimm32 ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRUImm32 op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRUImm32` instructions as flag producers. +(decl alu_ruimm32_with_flags_paired (Type ALUOp Reg u32) ProducesFlags) +(rule (alu_ruimm32_with_flags_paired ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRUImm32 op dst src imm) dst))) + +;; Helper for emitting `MInst.AluRUImm16Shifted` instructions. +(decl alu_ruimm16shifted (Type ALUOp Reg UImm16Shifted) Reg) +(rule (alu_ruimm16shifted ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRUImm16Shifted op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.AluRUImm32Shifted` instructions. +(decl alu_ruimm32shifted (Type ALUOp Reg UImm32Shifted) Reg) +(rule (alu_ruimm32shifted ty op src imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AluRUImm32Shifted op dst src imm)))) + dst)) + +;; Helper for emitting `MInst.SMulWide` instructions. +(decl smul_wide (Reg Reg) RegPair) +(rule (smul_wide src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.SMulWide dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.UMulWide` instructions. +(decl umul_wide (Reg Reg) RegPair) +(rule (umul_wide src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.UMulWide dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.SDivMod32` instructions. +(decl sdivmod32 (Reg Reg) RegPair) +(rule (sdivmod32 src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.SDivMod32 dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.SDivMod64` instructions. +(decl sdivmod64 (Reg Reg) RegPair) +(rule (sdivmod64 src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.SDivMod64 dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.UDivMod32` instructions. +(decl udivmod32 (RegPair Reg) RegPair) +(rule (udivmod32 src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.UDivMod32 dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.UDivMod64` instructions. +(decl udivmod64 (RegPair Reg) RegPair) +(rule (udivmod64 src1 src2) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.UDivMod64 dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.ShiftRR` instructions. +(decl shift_rr (Type ShiftOp Reg u8 Reg) Reg) +(rule (shift_rr ty op src shift_imm shift_reg) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.ShiftRR op dst src shift_imm shift_reg)))) + dst)) + +;; Helper for emitting `MInst.RxSBGTest` instructions. +(decl rxsbg_test (RxSBGOp Reg Reg u8 u8 i8) ProducesFlags) +(rule (rxsbg_test op src1 src2 start_bit end_bit rotate_amt) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.RxSBGTest op src1 src2 start_bit end_bit rotate_amt))) + +;; Helper for emitting `MInst.UnaryRR` instructions. +(decl unary_rr (Type UnaryOp Reg) Reg) +(rule (unary_rr ty op src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.UnaryRR op dst src)))) + dst)) + +;; Helper for emitting `MInst.CmpRR` instructions. +(decl cmp_rr (CmpOp Reg Reg) ProducesFlags) +(rule (cmp_rr op src1 src2) + (ProducesFlags.ProducesFlagsSideEffect (MInst.CmpRR op src1 src2))) + +;; Helper for emitting `MInst.CmpRX` instructions. +(decl cmp_rx (CmpOp Reg MemArg) ProducesFlags) +(rule (cmp_rx op src mem) + (ProducesFlags.ProducesFlagsSideEffect (MInst.CmpRX op src mem))) + +;; Helper for emitting `MInst.CmpRSImm16` instructions. +(decl cmp_rsimm16 (CmpOp Reg i16) ProducesFlags) +(rule (cmp_rsimm16 op src imm) + (ProducesFlags.ProducesFlagsSideEffect (MInst.CmpRSImm16 op src imm))) + +;; Helper for emitting `MInst.CmpRSImm32` instructions. +(decl cmp_rsimm32 (CmpOp Reg i32) ProducesFlags) +(rule (cmp_rsimm32 op src imm) + (ProducesFlags.ProducesFlagsSideEffect (MInst.CmpRSImm32 op src imm))) + +;; Helper for emitting `MInst.CmpRUImm32` instructions. +(decl cmp_ruimm32 (CmpOp Reg u32) ProducesFlags) +(rule (cmp_ruimm32 op src imm) + (ProducesFlags.ProducesFlagsSideEffect (MInst.CmpRUImm32 op src imm))) + +;; Helper for emitting `MInst.AtomicRmw` instructions. +(decl atomic_rmw_impl (Type ALUOp Reg MemArg) Reg) +(rule (atomic_rmw_impl ty op src mem) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.AtomicRmw op dst src mem)))) + dst)) + +;; Helper for emitting `MInst.AtomicCas32` instructions. +(decl atomic_cas32 (Reg Reg MemArg) Reg) +(rule (atomic_cas32 src1 src2 mem) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.AtomicCas32 dst src1 src2 mem)))) + dst)) + +;; Helper for emitting `MInst.AtomicCas64` instructions. +(decl atomic_cas64 (Reg Reg MemArg) Reg) +(rule (atomic_cas64 src1 src2 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.AtomicCas64 dst src1 src2 mem)))) + dst)) + +;; Helper for emitting `MInst.Fence` instructions. +(decl fence_impl () SideEffectNoResult) +(rule (fence_impl) + (SideEffectNoResult.Inst (MInst.Fence))) + +;; Helper for emitting `MInst.Load32` instructions. +(decl load32 (MemArg) Reg) +(rule (load32 addr) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Load32 dst addr)))) + dst)) + +;; Helper for emitting `MInst.Load64` instructions. +(decl load64 (MemArg) Reg) +(rule (load64 addr) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64 dst addr)))) + dst)) + +;; Helper for emitting `MInst.LoadRev16` instructions. +(decl loadrev16 (MemArg) Reg) +(rule (loadrev16 addr) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.LoadRev16 dst addr)))) + dst)) + +;; Helper for emitting `MInst.LoadRev32` instructions. +(decl loadrev32 (MemArg) Reg) +(rule (loadrev32 addr) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.LoadRev32 dst addr)))) + dst)) + +;; Helper for emitting `MInst.LoadRev64` instructions. +(decl loadrev64 (MemArg) Reg) +(rule (loadrev64 addr) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadRev64 dst addr)))) + dst)) + +;; Helper for emitting `MInst.Store8` instructions. +(decl store8 (Reg MemArg) SideEffectNoResult) +(rule (store8 src addr) + (SideEffectNoResult.Inst (MInst.Store8 src addr))) + +;; Helper for emitting `MInst.Store16` instructions. +(decl store16 (Reg MemArg) SideEffectNoResult) +(rule (store16 src addr) + (SideEffectNoResult.Inst (MInst.Store16 src addr))) + +;; Helper for emitting `MInst.Store32` instructions. +(decl store32 (Reg MemArg) SideEffectNoResult) +(rule (store32 src addr) + (SideEffectNoResult.Inst (MInst.Store32 src addr))) + +;; Helper for emitting `MInst.Store64` instructions. +(decl store64 (Reg MemArg) SideEffectNoResult) +(rule (store64 src addr) + (SideEffectNoResult.Inst (MInst.Store64 src addr))) + +;; Helper for emitting `MInst.StoreImm8` instructions. +(decl store8_imm (u8 MemArg) SideEffectNoResult) +(rule (store8_imm imm addr) + (SideEffectNoResult.Inst (MInst.StoreImm8 imm addr))) + +;; Helper for emitting `MInst.StoreImm16` instructions. +(decl store16_imm (i16 MemArg) SideEffectNoResult) +(rule (store16_imm imm addr) + (SideEffectNoResult.Inst (MInst.StoreImm16 imm addr))) + +;; Helper for emitting `MInst.StoreImm32SExt16` instructions. +(decl store32_simm16 (i16 MemArg) SideEffectNoResult) +(rule (store32_simm16 imm addr) + (SideEffectNoResult.Inst (MInst.StoreImm32SExt16 imm addr))) + +;; Helper for emitting `MInst.StoreImm64SExt16` instructions. +(decl store64_simm16 (i16 MemArg) SideEffectNoResult) +(rule (store64_simm16 imm addr) + (SideEffectNoResult.Inst (MInst.StoreImm64SExt16 imm addr))) + +;; Helper for emitting `MInst.StoreRev16` instructions. +(decl storerev16 (Reg MemArg) SideEffectNoResult) +(rule (storerev16 src addr) + (SideEffectNoResult.Inst (MInst.StoreRev16 src addr))) + +;; Helper for emitting `MInst.StoreRev32` instructions. +(decl storerev32 (Reg MemArg) SideEffectNoResult) +(rule (storerev32 src addr) + (SideEffectNoResult.Inst (MInst.StoreRev32 src addr))) + +;; Helper for emitting `MInst.StoreRev64` instructions. +(decl storerev64 (Reg MemArg) SideEffectNoResult) +(rule (storerev64 src addr) + (SideEffectNoResult.Inst (MInst.StoreRev64 src addr))) + +;; Helper for emitting `MInst.LoadAR` instructions. +(decl load_ar (u8) Reg) +(rule (load_ar ar) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadAR dst ar)))) + dst)) + +;; Helper for emitting `MInst.InsertAR` instructions. +(decl insert_ar (Reg u8) Reg) +(rule (insert_ar src ar) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.InsertAR dst src ar)))) + dst)) + +;; Helper for emitting `MInst.FpuRR` instructions. +(decl fpu_rr (Type FPUOp1 Reg) Reg) +(rule (fpu_rr ty op src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.FpuRR op dst src)))) + dst)) + +;; Helper for emitting `MInst.FpuRRR` instructions. +(decl fpu_rrr (Type FPUOp2 Reg Reg) Reg) +(rule (fpu_rrr ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.FpuRRR op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.FpuRRRR` instructions. +(decl fpu_rrrr (Type FPUOp3 Reg Reg Reg) Reg) +(rule (fpu_rrrr ty op src1 src2 src3) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.FpuRRRR op dst src1 src2 src3)))) + dst)) + +;; Helper for emitting `MInst.FpuCmp32` instructions. +(decl fpu_cmp32 (Reg Reg) ProducesFlags) +(rule (fpu_cmp32 src1 src2) + (ProducesFlags.ProducesFlagsSideEffect (MInst.FpuCmp32 src1 src2))) + +;; Helper for emitting `MInst.FpuCmp64` instructions. +(decl fpu_cmp64 (Reg Reg) ProducesFlags) +(rule (fpu_cmp64 src1 src2) + (ProducesFlags.ProducesFlagsSideEffect (MInst.FpuCmp64 src1 src2))) + +;; Helper for emitting `MInst.FpuRound` instructions. +(decl fpu_round (Type FpuRoundOp FpuRoundMode Reg) Reg) +(rule (fpu_round ty op mode src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.FpuRound op mode dst src)))) + dst)) + +;; Helper for emitting `MInst.VecRRR` instructions. +(decl vec_rrr (Type VecBinaryOp Reg Reg) Reg) +(rule (vec_rrr ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecRRR op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.VecRR` instructions. +(decl vec_rr (Type VecUnaryOp Reg) Reg) +(rule (vec_rr ty op src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecRR op dst src)))) + dst)) + +;; Helper for emitting `MInst.VecShiftRR` instructions. +(decl vec_shift_rr (Type VecShiftOp Reg u8 Reg) Reg) +(rule (vec_shift_rr ty op src shift_imm shift_reg) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecShiftRR op dst src shift_imm shift_reg)))) + dst)) + +;; Helper for emitting `MInst.VecSelect` instructions. +(decl vec_select (Type Reg Reg Reg) Reg) +(rule (vec_select ty src1 src2 src3) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecSelect dst src1 src2 src3)))) + dst)) + +;; Helper for emitting `MInst.VecPermute` instructions. +(decl vec_permute (Type Reg Reg Reg) Reg) +(rule (vec_permute ty src1 src2 src3) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecPermute dst src1 src2 src3)))) + dst)) + +;; Helper for emitting `MInst.VecPermuteDWImm` instructions. +(decl vec_permute_dw_imm (Type Reg u8 Reg u8) Reg) +(rule (vec_permute_dw_imm ty src1 idx1 src2 idx2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecPermuteDWImm dst src1 src2 idx1 idx2)))) + dst)) + +;; Helper for emitting `MInst.VecIntCmp` instructions. +(decl vec_int_cmp (Type VecIntCmpOp Reg Reg) Reg) +(rule (vec_int_cmp ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecIntCmp op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.VecIntCmpS` instructions. +(decl vec_int_cmps (Type VecIntCmpOp Reg Reg) ProducesFlags) +(rule (vec_int_cmps ty op src1 src2) + (let ((tmp WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsSideEffect (MInst.VecIntCmpS op tmp src1 src2)))) + +;; Helper for emitting `MInst.VecFloatCmp` instructions. +(decl vec_float_cmp (Type VecFloatCmpOp Reg Reg) Reg) +(rule (vec_float_cmp ty op src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecFloatCmp op dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.VecFloatCmpS` instructions. +(decl vec_float_cmps (Type VecFloatCmpOp Reg Reg) ProducesFlags) +(rule (vec_float_cmps ty op src1 src2) + (let ((tmp WritableReg (temp_writable_reg ty))) + (ProducesFlags.ProducesFlagsSideEffect (MInst.VecFloatCmpS op tmp src1 src2)))) + +;; Helper for emitting `MInst.VecInt128SCmpHi` instructions. +(decl vec_int128_scmphi (Reg Reg) ProducesBool) +(rule (vec_int128_scmphi src1 src2) + (let ((tmp WritableReg (temp_writable_reg $I128))) + (bool (ProducesFlags.ProducesFlagsSideEffect (MInst.VecInt128SCmpHi tmp src1 src2)) + (mask_as_cond 4)))) + +;; Helper for emitting `MInst.VecInt128UCmpHi` instructions. +(decl vec_int128_ucmphi (Reg Reg) ProducesBool) +(rule (vec_int128_ucmphi src1 src2) + (let ((tmp WritableReg (temp_writable_reg $I128))) + (bool (ProducesFlags.ProducesFlagsSideEffect (MInst.VecInt128UCmpHi tmp src1 src2)) + (mask_as_cond 4)))) + +;; Helper for emitting `MInst.VecLoad` instructions. +(decl vec_load (Type MemArg) Reg) +(rule (vec_load ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoad dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadRev` instructions. +(decl vec_loadrev (Type MemArg) Reg) +(rule (vec_loadrev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadRev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadByte16Rev` instructions. +(decl vec_load_byte16rev (Type MemArg) Reg) +(rule (vec_load_byte16rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadByte16Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadByte32Rev` instructions. +(decl vec_load_byte32rev (Type MemArg) Reg) +(rule (vec_load_byte32rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadByte32Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadByte64Rev` instructions. +(decl vec_load_byte64rev (Type MemArg) Reg) +(rule (vec_load_byte64rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadByte64Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadElt16Rev` instructions. +(decl vec_load_elt16rev (Type MemArg) Reg) +(rule (vec_load_elt16rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadElt16Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadElt32Rev` instructions. +(decl vec_load_elt32rev (Type MemArg) Reg) +(rule (vec_load_elt32rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadElt32Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadElt64Rev` instructions. +(decl vec_load_elt64rev (Type MemArg) Reg) +(rule (vec_load_elt64rev ty addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadElt64Rev dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecStore` instructions. +(decl vec_store (Reg MemArg) SideEffectNoResult) +(rule (vec_store src addr) + (SideEffectNoResult.Inst (MInst.VecStore src addr))) + +;; Helper for emitting `MInst.VecStoreRev` instructions. +(decl vec_storerev (Reg MemArg) SideEffectNoResult) +(rule (vec_storerev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreRev src addr))) + +;; Helper for emitting `MInst.VecStoreByte16Rev` instructions. +(decl vec_store_byte16rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_byte16rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreByte16Rev src addr))) + +;; Helper for emitting `MInst.VecStoreByte32Rev` instructions. +(decl vec_store_byte32rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_byte32rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreByte32Rev src addr))) + +;; Helper for emitting `MInst.VecStoreByte64Rev` instructions. +(decl vec_store_byte64rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_byte64rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreByte64Rev src addr))) + +;; Helper for emitting `MInst.VecStoreElt16Rev` instructions. +(decl vec_store_elt16rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_elt16rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreElt16Rev src addr))) + +;; Helper for emitting `MInst.VecStoreElt32Rev` instructions. +(decl vec_store_elt32rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_elt32rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreElt32Rev src addr))) + +;; Helper for emitting `MInst.VecStoreElt64Rev` instructions. +(decl vec_store_elt64rev (Reg MemArg) SideEffectNoResult) +(rule (vec_store_elt64rev src addr) + (SideEffectNoResult.Inst (MInst.VecStoreElt64Rev src addr))) + +;; Helper for emitting `MInst.VecLoadReplicate` instructions. +(decl vec_load_replicate (Type MemArg) Reg) +(rule (vec_load_replicate (ty_vec128 ty @ (multi_lane size _)) addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadReplicate size dst addr)))) + dst)) + +;; Helper for emitting `MInst.VecLoadReplicateRev` instructions. +(decl vec_load_replicate_rev (Type MemArg) Reg) +(rule (vec_load_replicate_rev (ty_vec128 ty @ (multi_lane size _)) addr) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadReplicateRev size dst addr)))) + dst)) + +;; Helper for emitting `MInst.MovToVec128` instructions. +(decl mov_to_vec128 (Type Reg Reg) Reg) +(rule (mov_to_vec128 ty src1 src2) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.MovToVec128 dst src1 src2)))) + dst)) + +;; Helper for emitting `MInst.VecLoadConst` instructions. +(decl vec_load_const (Type u128) Reg) +(rule (vec_load_const (vr128_ty ty) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadConst dst n)))) + dst)) + +;; Helper for emitting `MInst.VecLoadConstReplicate` instructions. +(decl vec_load_const_replicate (Type u64) Reg) +(rule (vec_load_const_replicate ty @ (multi_lane size _) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadConstReplicate size dst n)))) + dst)) + +;; Helper for emitting `MInst.VecImmByteMask` instructions. +(decl vec_imm_byte_mask (Type u16) Reg) +(rule (vec_imm_byte_mask (vr128_ty ty) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecImmByteMask dst n)))) + dst)) + +;; Helper for emitting `MInst.VecImmBitMask` instructions. +(decl vec_imm_bit_mask (Type u8 u8) Reg) +(rule (vec_imm_bit_mask (ty_vec128 ty @ (multi_lane size _)) start_bit end_bit) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecImmBitMask size dst start_bit end_bit)))) + dst)) + +;; Helper for emitting `MInst.VecImmReplicate` instructions. +(decl vec_imm_replicate (Type i16) Reg) +(rule (vec_imm_replicate (ty_vec128 ty @ (multi_lane size _)) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecImmReplicate size dst n)))) + dst)) + +;; Helper for emitting `MInst.VecLoadLane` instructions. +(decl vec_load_lane (Type Reg MemArg u8) Reg) +(rule (vec_load_lane ty @ (multi_lane size _) src addr lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadLane size dst src addr lane_imm)))) + dst)) + +;; Helper for emitting `MInst.VecLoadLaneUndef` instructions. +(decl vec_load_lane_undef (Type MemArg u8) Reg) +(rule (vec_load_lane_undef ty @ (multi_lane size _) addr lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadLaneUndef size dst addr lane_imm)))) + dst)) + +;; Helper for emitting `MInst.VecLoadLaneRev` instructions. +(decl vec_load_lane_rev (Type Reg MemArg u8) Reg) +(rule (vec_load_lane_rev ty @ (multi_lane size _) src addr lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadLaneRev size dst src addr lane_imm)))) + dst)) + +;; Helper for emitting `MInst.VecLoadLaneRevUndef` instructions. +(decl vec_load_lane_rev_undef (Type MemArg u8) Reg) +(rule (vec_load_lane_rev_undef ty @ (multi_lane size _) addr lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecLoadLaneRevUndef size dst addr lane_imm)))) + dst)) + +;; Helper for emitting `MInst.VecStoreLane` instructions. +(decl vec_store_lane (Type Reg MemArg u8) SideEffectNoResult) +(rule (vec_store_lane ty @ (multi_lane size _) src addr lane_imm) + (SideEffectNoResult.Inst (MInst.VecStoreLane size src addr lane_imm))) + +;; Helper for emitting `MInst.VecStoreLaneRev` instructions. +(decl vec_store_lane_rev (Type Reg MemArg u8) SideEffectNoResult) +(rule (vec_store_lane_rev ty @ (multi_lane size _) src addr lane_imm) + (SideEffectNoResult.Inst (MInst.VecStoreLaneRev size src addr lane_imm))) + +;; Helper for emitting `MInst.VecInsertLane` instructions. +(decl vec_insert_lane (Type Reg Reg u8 Reg) Reg) +(rule (vec_insert_lane ty @ (multi_lane size _) src1 src2 lane_imm lane_reg) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecInsertLane size dst src1 src2 lane_imm lane_reg)))) + dst)) + +;; Helper for emitting `MInst.VecInsertLaneUndef` instructions. +(decl vec_insert_lane_undef (Type Reg u8 Reg) Reg) +(rule (vec_insert_lane_undef ty @ (multi_lane size _) src lane_imm lane_reg) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecInsertLaneUndef size dst src lane_imm lane_reg)))) + dst)) + +;; Helper for emitting `MInst.VecExtractLane` instructions. +(decl vec_extract_lane (Type Reg u8 Reg) Reg) +(rule (vec_extract_lane (multi_lane size _) src lane_imm lane_reg) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.VecExtractLane size dst src lane_imm lane_reg)))) + dst)) + +;; Helper for emitting `MInst.VecInsertLaneImm` instructions. +(decl vec_insert_lane_imm (Type Reg i16 u8) Reg) +(rule (vec_insert_lane_imm ty @ (multi_lane size _) src imm lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecInsertLaneImm size dst src imm lane_imm)))) + dst)) + +;; Helper for emitting `MInst.VecReplicateLane` instructions. +(decl vec_replicate_lane (Type Reg u8) Reg) +(rule (vec_replicate_lane ty @ (multi_lane size _) src lane_imm) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.VecReplicateLane size dst src lane_imm)))) + dst)) + +;; Helper for emitting `MInst.LoadSymbolReloc` instructions. +(decl load_symbol_reloc (SymbolReloc) Reg) +(rule (load_symbol_reloc symbol_reloc) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadSymbolReloc dst symbol_reloc)))) + dst)) + +;; Helper for emitting `MInst.LoadAddr` instructions. +(decl load_addr (MemArg) Reg) +(rule (load_addr mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.LoadAddr dst mem)))) + dst)) + +;; Helper for emitting `MInst.Call` instructions. +(decl call_impl (WritableReg BoxCallInfo) SideEffectNoResult) +(rule (call_impl reg info) + (SideEffectNoResult.Inst (MInst.Call reg info))) + +;; Helper for emitting `MInst.CallInd` instructions. +(decl call_ind_impl (WritableReg BoxCallIndInfo) SideEffectNoResult) +(rule (call_ind_impl reg info) + (SideEffectNoResult.Inst (MInst.CallInd reg info))) + +;; Helper for emitting `MInst.ReturnCall` instructions. +(decl return_call_impl (BoxReturnCallInfo) SideEffectNoResult) +(rule (return_call_impl info) + (SideEffectNoResult.Inst (MInst.ReturnCall info))) + +;; Helper for emitting `MInst.ReturnCallInd` instructions. +(decl return_call_ind_impl (BoxReturnCallIndInfo) SideEffectNoResult) +(rule (return_call_ind_impl info) + (SideEffectNoResult.Inst (MInst.ReturnCallInd info))) + +;; Helper for emitting `MInst.Jump` instructions. +(decl jump_impl (MachLabel) SideEffectNoResult) +(rule (jump_impl target) + (SideEffectNoResult.Inst (MInst.Jump target))) + +;; Helper for emitting `MInst.CondBr` instructions. +(decl cond_br (MachLabel MachLabel Cond) ConsumesFlags) +(rule (cond_br taken not_taken cond) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.CondBr taken not_taken cond))) + +;; Helper for emitting `MInst.OneWayCondBr` instructions. +(decl oneway_cond_br (MachLabel Cond) ConsumesFlags) +(rule (oneway_cond_br dest cond) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.OneWayCondBr dest cond))) + +;; Helper for emitting `MInst.JTSequence` instructions. +(decl jt_sequence (Reg BoxVecMachLabel) SideEffectNoResult) +(rule (jt_sequence ridx targets) + (SideEffectNoResult.Inst (MInst.JTSequence ridx targets))) + + +;; Helpers for instruction sequences ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Completed instruction sequence for use in MInst.Loop. +(type VecMInst (primitive VecMInst)) + +;; Partial (mutable) instruction sequence in the process of being created. +(type VecMInstBuilder extern (enum)) + +;; Create a new empty instruction sequence builder. +(decl inst_builder_new () VecMInstBuilder) +(extern constructor inst_builder_new inst_builder_new) + +;; Push an instruction to a sequence under construction. +(decl inst_builder_push (VecMInstBuilder MInst) Unit) +(extern constructor inst_builder_push inst_builder_push) + +;; Complete the sequence under construction. +(decl inst_builder_finish (VecMInstBuilder) VecMInst) +(extern constructor inst_builder_finish inst_builder_finish) + +;; It is not safe to write to virtual registers in the loop, so all destination +;; registers must be real. This must be handled by the user of these helpers, +;; so we simply verify this constraint here. +(decl real_reg (WritableReg) WritableReg) +(extern extractor real_reg real_reg) + +;; Similarly, because we cannot allocate temp registers, if an instruction +;; requires matching source and destination registers, this needs to be handled +;; by the user. Another helper to verify that constraint. +(decl pure partial same_reg (WritableReg Reg) Reg) +(extern constructor same_reg same_reg) + +;; Push a `MInst.AluRRR` instruction to a sequence. +(decl push_alu_reg (VecMInstBuilder ALUOp WritableReg Reg Reg) Reg) +(rule (push_alu_reg ib op (real_reg dst) src1 src2) + (let ((_ Unit (inst_builder_push ib (MInst.AluRRR op dst src1 src2)))) + dst)) + +;; Push a `MInst.AluRUImm32Shifted` instruction to a sequence. +(decl push_alu_uimm32shifted (VecMInstBuilder ALUOp WritableReg Reg UImm32Shifted) Reg) +(rule (push_alu_uimm32shifted ib op (real_reg dst) r imm) + (let ((_ Unit (inst_builder_push ib (MInst.AluRUImm32Shifted op dst r imm)))) + dst)) + +;; Push a `MInst.ShiftRR` instruction to a sequence. +(decl push_shift (VecMInstBuilder ShiftOp WritableReg Reg u8 Reg) Reg) +(rule (push_shift ib op (real_reg dst) src shift_imm shift_reg) + (let ((_ Unit (inst_builder_push ib + (MInst.ShiftRR op dst src shift_imm shift_reg)))) + dst)) + +;; Push a `MInst.RxSBG` instruction to a sequence. +(decl push_rxsbg (VecMInstBuilder RxSBGOp WritableReg Reg Reg u8 u8 i8) Reg) +(rule (push_rxsbg ib op (real_reg dst) r src start_bit end_bit rotate_amt) + (if (same_reg dst r)) + (let ((_ Unit (inst_builder_push ib + (MInst.RxSBG op dst r src start_bit end_bit rotate_amt)))) + dst)) + +;; Push a `MInst.UnaryRR` instruction to a sequence. +(decl push_unary (VecMInstBuilder UnaryOp WritableReg Reg) Reg) +(rule (push_unary ib op (real_reg dst) src) + (let ((_ Unit (inst_builder_push ib (MInst.UnaryRR op dst src)))) + dst)) + +;; Push a `MInst.AtomicCas32` instruction to a sequence. +(decl push_atomic_cas32 (VecMInstBuilder WritableReg Reg MemArg) Reg) +(rule (push_atomic_cas32 ib (real_reg dst_src1) src2 mem) + (let ((_ Unit (inst_builder_push ib (MInst.AtomicCas32 dst_src1 dst_src1 src2 mem)))) + dst_src1)) + +;; Push a `MInst.AtomicCas64` instruction to a sequence. +(decl push_atomic_cas64 (VecMInstBuilder WritableReg Reg MemArg) Reg) +(rule (push_atomic_cas64 ib (real_reg dst_src1) src2 mem) + (let ((_ Unit (inst_builder_push ib (MInst.AtomicCas64 dst_src1 dst_src1 src2 mem)))) + dst_src1)) + +;; Push instructions to break out of the loop if condition is met. +(decl push_break_if (VecMInstBuilder ProducesFlags Cond) Reg) +(rule (push_break_if ib (ProducesFlags.ProducesFlagsSideEffect inst) cond) + (let ((_ Unit (inst_builder_push ib inst)) + (_ Unit (inst_builder_push ib (MInst.CondBreak cond)))) + (invalid_reg))) + +;; Emit a `MInst.Loop` instruction holding a loop body instruction sequence. +(decl emit_loop (VecMInstBuilder Cond) Unit) +(rule (emit_loop ib cond) + (emit (MInst.Loop (inst_builder_finish ib) cond))) + + +;; Helpers for generating register moves ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Copy GPR into a virtual register. +(decl copy_reg (Type Reg) Reg) +(rule 1 (copy_reg (gpr32_ty ty) src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov32 dst src)))) + dst)) +(rule 2 (copy_reg (gpr64_ty ty) src) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov64 dst src)))) + dst)) + +;; Move from memory location into destination. +(decl emit_load (Type WritableReg MemArg) Unit) +(rule (emit_load $I32 dst addr) + (emit (MInst.Load32 dst addr))) +(rule (emit_load $I64 dst addr) + (emit (MInst.Load64 dst addr))) + +;; Helper for creating `MInst.MovPReg` instructions. +(decl mov_preg (PReg) Reg) +(rule (mov_preg src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.MovPReg dst src)))) + dst)) + +(decl preg_stack () PReg) +(extern constructor preg_stack preg_stack) + +(decl preg_gpr_0 () PReg) +(extern constructor preg_gpr_0 preg_gpr_0) + +;; Copy the physical stack register into a virtual register. +(decl sp () Reg) +(rule (sp) + (mov_preg (preg_stack))) + +;; Helpers for accessing argument / return value slots ;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl arg_store (Type Reg MemArg) SideEffectNoResult) +(rule (arg_store $I8 reg mem) (store8 reg mem)) +(rule (arg_store $I16 reg mem) (store16 reg mem)) +(rule (arg_store $I32 reg mem) (store32 reg mem)) +(rule (arg_store $I64 reg mem) (store64 reg mem)) +(rule (arg_store $F32 reg mem) (vec_store_lane $F32X4 reg mem 0)) +(rule (arg_store $F64 reg mem) (vec_store_lane $F64X2 reg mem 0)) +(rule -1 (arg_store (vr128_ty ty) reg mem) (vec_store reg mem)) + +(decl arg_load (Type MemArg) Reg) +(rule (arg_load $I8 mem) (zext32_mem $I8 mem)) +(rule (arg_load $I16 mem) (zext32_mem $I16 mem)) +(rule (arg_load $I32 mem) (load32 mem)) +(rule (arg_load $I64 mem) (load64 mem)) +(rule (arg_load $F32 mem) (vec_load_lane_undef $F32X4 mem 0)) +(rule (arg_load $F64 mem) (vec_load_lane_undef $F64X2 mem 0)) +(rule -1 (arg_load (vr128_ty ty) mem) (vec_load ty mem)) + +;; Helper to perform a lane swap in register. +(decl vec_elt_rev (Type Reg) Reg) +(rule (vec_elt_rev (multi_lane 64 2) reg) + (vec_permute_dw_imm $I64X2 reg 1 reg 0)) +(rule (vec_elt_rev (multi_lane 32 4) reg) + (let ((rev Reg (vec_permute_dw_imm $I64X2 reg 1 reg 0))) + (vec_rot_imm $I64X2 rev 32))) +(rule (vec_elt_rev (multi_lane 16 8) reg) + (let ((rev Reg (vec_permute_dw_imm $I64X2 reg 1 reg 0))) + (vec_rot_imm $I32X4 (vec_rot_imm $I64X2 rev 32) 16))) +(rule (vec_elt_rev (multi_lane 8 16) reg) + (let ((rev Reg (vec_permute_dw_imm $I64X2 reg 1 reg 0))) + (vec_rot_imm $I16X8 (vec_rot_imm $I32X4 (vec_rot_imm $I64X2 rev 32) 16) 8))) + +;; When passing a vector value to a function whose ABI uses a different +;; lane order than the current function, we need to swap lanes. +;; The first operand is the lane order used by the callee. +(decl abi_vec_elt_rev (LaneOrder Type Reg) Reg) +(rule 5 (abi_vec_elt_rev _ (gpr32_ty ty) reg) reg) +(rule 4 (abi_vec_elt_rev _ (gpr64_ty ty) reg) reg) +(rule 3 (abi_vec_elt_rev _ $I128 reg) reg) +(rule 2 (abi_vec_elt_rev _ (ty_scalar_float ty) reg) reg) +(rule 0 (abi_vec_elt_rev callee_lane_order _ reg) + (if-let true (lane_order_equal callee_lane_order (lane_order))) + reg) +(rule 1 (abi_vec_elt_rev callee_lane_order (ty_vec128 ty) reg) + (if-let false (lane_order_equal callee_lane_order (lane_order))) + (vec_elt_rev ty reg)) + +;; Prepare a stack copy of a single (oversized) argument. +(decl copy_to_buffer (MemArg ABIArg Value) InstOutput) +(rule 2 (copy_to_buffer base (abi_arg_only_slot slot) _) (output_none)) +(rule 0 (copy_to_buffer base (abi_arg_implicit_pointer _ offset ty) + val @ (value_type ty)) + (side_effect (arg_store ty val (memarg_offset base offset)))) + +;; Copy a single argument/return value to its slots. +;; For oversized arguments, set the slot to the buffer address. +(decl copy_to_arg (CallArgListBuilder LaneOrder MemArg ABIArg Value) InstOutput) +(rule 2 (copy_to_arg uses lo base (abi_arg_only_slot slot) val) + (copy_reg_to_arg_slot uses lo base slot (prepare_arg_val slot val))) +(rule 0 (copy_to_arg uses lo base (abi_arg_implicit_pointer slot offset _) _) + (let ((ptr Reg (load_addr (memarg_offset base offset)))) + (copy_reg_to_arg_slot uses lo base slot ptr))) + +;; Copy a single argument/return value from its slots. +(decl copy_from_arg (CallRetList LaneOrder MemArg ABIArg) ValueRegs) +(rule (copy_from_arg defs lo base (abi_arg_only_slot slot)) + (value_reg (copy_reg_from_arg_slot defs lo base slot))) + +;; Place one component of an argument/return value into a register. +;; Copy reference values into registers of integer type. +;; Zero- or sign-extend as required by the ABI. +(decl prepare_arg_val (ABIArgSlot Value) Reg) +(rule (prepare_arg_val (ABIArgSlot.Reg _ _ (ArgumentExtension.None)) val) + val) +(rule (prepare_arg_val (ABIArgSlot.Reg _ _ (ArgumentExtension.Uext)) val) + (put_in_reg_zext64 val)) +(rule (prepare_arg_val (ABIArgSlot.Reg _ _ (ArgumentExtension.Sext)) val) + (put_in_reg_sext64 val)) +(rule (prepare_arg_val (ABIArgSlot.Stack _ _ (ArgumentExtension.None)) val) + val) +(rule (prepare_arg_val (ABIArgSlot.Stack _ _ (ArgumentExtension.Uext)) val) + (put_in_reg_zext64 val)) +(rule (prepare_arg_val (ABIArgSlot.Stack _ _ (ArgumentExtension.Sext)) val) + (put_in_reg_sext64 val)) + +;; Copy one component of an argument/return value to its slot, where the +;; value is already extended and present in a register. +(decl copy_reg_to_arg_slot (CallArgListBuilder LaneOrder MemArg ABIArgSlot Reg) InstOutput) +(rule (copy_reg_to_arg_slot uses lo _ (ABIArgSlot.Reg reg ty ext) src) + (let ((_ Unit (args_builder_push uses (abi_vec_elt_rev lo ty src) reg))) + (output_none))) +(rule (copy_reg_to_arg_slot _ lo base (ABIArgSlot.Stack offset ty ext) src) + (side_effect (arg_store (abi_ext_ty ext ty) (abi_vec_elt_rev lo ty src) + (memarg_offset base offset)))) + +;; Copy one component of an argument/return value from its slot. +(decl copy_reg_from_arg_slot (CallRetList LaneOrder MemArg ABIArgSlot) Reg) +(rule (copy_reg_from_arg_slot defs lo _ (ABIArgSlot.Reg reg ty ext)) + (abi_vec_elt_rev lo ty (defs_lookup defs reg))) +(rule (copy_reg_from_arg_slot _ lo base (ABIArgSlot.Stack offset ty ext)) + (abi_vec_elt_rev lo ty (arg_load (abi_ext_ty ext ty) + (memarg_offset base offset)))) + +;; Helper to compute the type of an implicitly extended argument/return value. +(decl abi_ext_ty (ArgumentExtension Type) Type) +(rule 0 (abi_ext_ty _ ty) ty) +(rule 1 (abi_ext_ty (ArgumentExtension.Uext) (gpr32_ty _)) $I64) +(rule 1 (abi_ext_ty (ArgumentExtension.Sext) (gpr32_ty _)) $I64) + + +;; Helpers for generating immediate values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Allocate a temporary register, initialized with an immediate. +(decl imm (Type u64) Reg) + +;; 16-bit (or smaller) result type, any value +(rule 7 (imm (fits_in_16 ty) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov32SImm16 dst (u64_as_i16 n))))) + dst)) + +;; 32-bit result type, value fits in i16 +(rule 6 (imm (gpr32_ty ty) (u32_pair _ (i16_from_u32 n))) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov32SImm16 dst n)))) + dst)) + +;; 32-bit result type, any value +(rule 5 (imm (gpr32_ty ty) n) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov32Imm dst (u64_truncate_to_u32 n))))) + dst)) + +;; 64-bit result type, value fits in i16 +(rule 4 (imm (gpr64_ty ty) (i16_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov64SImm16 dst n)))) + dst)) + +;; 64-bit result type, value fits in i32 +(rule 3 (imm (gpr64_ty ty) (i32_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov64SImm32 dst n)))) + dst)) + +;; 64-bit result type, value fits in UImm16Shifted +(rule 2 (imm (gpr64_ty ty) (uimm16shifted_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov64UImm16Shifted dst n)))) + dst)) + +;; 64-bit result type, value fits in UImm32Shifted +(rule 1 (imm (gpr64_ty ty) (uimm32shifted_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Mov64UImm32Shifted dst n)))) + dst)) + +;; 64-bit result type, value with non-zero low-/high-parts. +(rule 0 (imm (gpr64_ty ty) (and (u64_nonzero_hipart hi) + (u64_nonzero_lopart lo))) + (insert_imm ty (imm ty hi) lo)) + +;; Replace low 32 bits of 64-bit value with immediate. +(decl insert_imm (Type Reg u64) Reg) + +;; Insertion, value fits in UImm16Shifted +(rule 1 (insert_imm ty src (uimm16shifted_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Insert64UImm16Shifted dst src n)))) + dst)) + +;; Insertion, value fits in UImm32Shifted +(rule (insert_imm ty src (uimm32shifted_from_u64 n)) + (let ((dst WritableReg (temp_writable_reg ty)) + (_ Unit (emit (MInst.Insert64UImm32Shifted dst src n)))) + dst)) + +;; 32-bit floating-point type, any value. Loaded from literal pool. +;; TODO: use LZER to load 0.0 +(rule 8 (imm $F32 n) + (let ((dst WritableReg (temp_writable_reg $F32)) + (_ Unit (emit (MInst.LoadFpuConst32 dst (u64_truncate_to_u32 n))))) + dst)) + +;; 64-bit floating-point type, any value. Loaded from literal pool. +;; TODO: use LZDR to load 0.0 +(rule 8 (imm $F64 n) + (let ((dst WritableReg (temp_writable_reg $F64)) + (_ Unit (emit (MInst.LoadFpuConst64 dst n)))) + dst)) + +;; Variant used for negative constants. +(decl imm32 (Type i32) Reg) +(rule (imm32 $I64 n) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Mov64SImm32 dst n)))) + (writable_reg_to_reg dst))) + +;; Allocate a temporary register, initialized with a vector immediate. +(decl vec_imm (Type u128) Reg) +(rule 2 (vec_imm (vr128_ty ty) 0) + (vec_imm_byte_mask ty 0)) +(rule 1 (vec_imm (vr128_ty ty) (u64_pair n n)) + (vec_imm_splat $I64X2 n)) +(rule (vec_imm (vr128_ty ty) n) + (vec_load_const ty n)) + +;; Variant with replicated immediate. +(decl vec_imm_splat (Type u64) Reg) +(rule 1 (vec_imm_splat (ty_vec128 ty) 0) + (vec_imm_byte_mask ty 0)) +(rule 2 (vec_imm_splat ty @ (multi_lane 8 _) n) + (vec_imm_replicate ty (u64_as_i16 n))) +(rule 2 (vec_imm_splat ty @ (multi_lane 16 _) n) + (vec_imm_replicate ty (u64_as_i16 n))) +(rule 2 (vec_imm_splat ty @ (multi_lane 32 _) (u32_pair _ (i16_from_u32 n))) + (vec_imm_replicate ty n)) +(rule 2 (vec_imm_splat ty @ (multi_lane 64 _) (i16_from_u64 n)) + (vec_imm_replicate ty n)) +(rule 3 (vec_imm_splat (multi_lane 16 _) (u32_pair _ (u16_pair _ (u8_pair n n)))) + (vec_imm_splat $I8X16 (u8_as_u64 n))) +(rule 3 (vec_imm_splat (multi_lane 32 _) (u32_pair _ (u16_pair n n))) + (vec_imm_splat $I16X8 (u16_as_u64 n))) +(rule 3 (vec_imm_splat (multi_lane 64 _) (u32_pair n n)) + (vec_imm_splat $I32X4 (u32_as_u64 n))) +(rule 0 (vec_imm_splat (ty_vec128 ty) n) + (vec_load_const_replicate ty n)) + + +;; Helpers for generating extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Result type of extending integer `Type` to 32 bits if smaller. +(decl ty_ext32 (Type) Type) +(rule (ty_ext32 $I8) $I32) +(rule (ty_ext32 $I16) $I32) +(rule (ty_ext32 $I32) $I32) +(rule (ty_ext32 $I64) $I64) + +;; Result type of extending integer `Type` to 64 bits if smaller. +(decl ty_ext64 (Type) Type) +(rule (ty_ext64 $I8) $I64) +(rule (ty_ext64 $I16) $I64) +(rule (ty_ext64 $I32) $I64) +(rule (ty_ext64 $I64) $I64) + + +;; Zero-extend a register from a smaller `Type` into a 32-bit register. +(decl zext32_reg (Type Reg) Reg) +(rule (zext32_reg ty src) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Extend dst src false (ty_bits ty) 32)))) + dst)) + +;; Sign-extend a register from a smaller `Type` into a 32-bit register. +(decl sext32_reg (Type Reg) Reg) +(rule (sext32_reg ty src) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Extend dst src true (ty_bits ty) 32)))) + dst)) + +;; Zero-extend a register from a smaller `Type` into a 64-bit register. +(decl zext64_reg (Type Reg) Reg) +(rule (zext64_reg ty src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Extend dst src false (ty_bits ty) 64)))) + dst)) + +;; Sign-extend a register from a smaller `Type` into a 64-bit register. +(decl sext64_reg (Type Reg) Reg) +(rule (sext64_reg ty src) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Extend dst src true (ty_bits ty) 64)))) + dst)) + + +;; Zero-extend memory from a smaller `Type` into a 32-bit register. +(decl zext32_mem (Type MemArg) Reg) +(rule (zext32_mem $I8 mem) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Load32ZExt8 dst mem)))) + dst)) +(rule (zext32_mem $I16 mem) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Load32ZExt16 dst mem)))) + dst)) + +;; Sign-extend memory from a smaller `Type` into a 32-bit register. +(decl sext32_mem (Type MemArg) Reg) +(rule (sext32_mem $I8 mem) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Load32SExt8 dst mem)))) + dst)) +(rule (sext32_mem $I16 mem) + (let ((dst WritableReg (temp_writable_reg $I32)) + (_ Unit (emit (MInst.Load32SExt16 dst mem)))) + dst)) + +;; Zero-extend memory from a smaller `Type` into a 64-bit register. +(decl zext64_mem (Type MemArg) Reg) +(rule (zext64_mem $I8 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64ZExt8 dst mem)))) + dst)) +(rule (zext64_mem $I16 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64ZExt16 dst mem)))) + dst)) +(rule (zext64_mem $I32 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64ZExt32 dst mem)))) + dst)) + +;; Sign-extend memory from a smaller `Type` into a 64-bit register. +(decl sext64_mem (Type MemArg) Reg) +(rule (sext64_mem $I8 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64SExt8 dst mem)))) + dst)) +(rule (sext64_mem $I16 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64SExt16 dst mem)))) + dst)) +(rule (sext64_mem $I32 mem) + (let ((dst WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.Load64SExt32 dst mem)))) + dst)) + + +;; Place `Value` into a register, zero-extending to 32 bits if smaller. +(decl put_in_reg_zext32 (Value) Reg) +(rule 3 (put_in_reg_zext32 (and (value_type ty) (u64_from_value val))) + (imm (ty_ext32 ty) val)) +(rule 1 (put_in_reg_zext32 (and (value_type (fits_in_16 ty)) (sinkable_load load))) + (zext32_mem ty (sink_load load))) +(rule 0 (put_in_reg_zext32 val @ (value_type (fits_in_16 ty))) + (zext32_reg ty val)) +(rule 2 (put_in_reg_zext32 val @ (value_type (ty_32_or_64 _ty))) + val) + +;; Place `Value` into a register, sign-extending to 32 bits if smaller. +(decl put_in_reg_sext32 (Value) Reg) +(rule 3 (put_in_reg_sext32 (and (value_type ty) (u64_from_signed_value val))) + (imm (ty_ext32 ty) val)) +(rule 1 (put_in_reg_sext32 (and (value_type (fits_in_16 ty)) (sinkable_load load))) + (sext32_mem ty (sink_load load))) +(rule 0 (put_in_reg_sext32 val @ (value_type (fits_in_16 ty))) + (sext32_reg ty val)) +(rule 2 (put_in_reg_sext32 val @ (value_type (ty_32_or_64 _ty))) + val) + +;; Place `Value` into a register, zero-extending to 64 bits if smaller. +(decl put_in_reg_zext64 (Value) Reg) +(rule 3 (put_in_reg_zext64 (and (value_type ty) (u64_from_value val))) + (imm (ty_ext64 ty) val)) +(rule 1 (put_in_reg_zext64 (and (value_type (gpr32_ty ty)) (sinkable_load load))) + (zext64_mem ty (sink_load load))) +(rule 0 (put_in_reg_zext64 val @ (value_type (gpr32_ty ty))) + (zext64_reg ty val)) +(rule 2 (put_in_reg_zext64 val @ (value_type (gpr64_ty ty))) + val) + +;; Place `Value` into a register, sign-extending to 64 bits if smaller. +(decl put_in_reg_sext64 (Value) Reg) +(rule 3 (put_in_reg_sext64 (and (value_type ty) (u64_from_signed_value val))) + (imm (ty_ext64 ty) val)) +(rule 1 (put_in_reg_sext64 (and (value_type (gpr32_ty ty)) (sinkable_load load))) + (sext64_mem ty (sink_load load))) +(rule 0 (put_in_reg_sext64 val @ (value_type (gpr32_ty ty))) + (sext64_reg ty val)) +(rule 2 (put_in_reg_sext64 val @ (value_type (gpr64_ty ty))) + val) + + +;; Helpers for generating conditional moves ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Conditionally select between immediate and source register. +(decl cmov_imm (Type Cond i16 Reg) ConsumesFlags) +(rule 0 (cmov_imm (gpr32_ty ty) cond imm_true reg_false) + (let ((dst WritableReg (temp_writable_reg ty)) + (inst MInst (MInst.CMov32SImm16 dst cond reg_false imm_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) +(rule 1 (cmov_imm (gpr64_ty ty) cond imm_true reg_false) + (let ((dst WritableReg (temp_writable_reg ty)) + (inst MInst (MInst.CMov64SImm16 dst cond reg_false imm_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) + +;; Conditionally select between two immediates. +(decl cmov_imm_imm (Type Cond i16 i16) ConsumesFlags) +(rule 0 (cmov_imm_imm (gpr32_ty ty) cond imm_true imm_false) + (let ((tmp1 WritableReg (temp_writable_reg ty)) + (tmp2 WritableReg (temp_writable_reg ty)) + (inst1 MInst (MInst.Mov32SImm16 tmp1 imm_false)) + (inst2 MInst (MInst.CMov32SImm16 tmp2 cond tmp1 imm_true)) + (dst ValueRegs (value_reg tmp2))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs inst1 inst2 dst))) +(rule 1 (cmov_imm_imm (gpr64_ty ty) cond imm_true imm_false) + (let ((tmp1 WritableReg (temp_writable_reg ty)) + (tmp2 WritableReg (temp_writable_reg ty)) + (inst1 MInst (MInst.Mov64SImm16 tmp1 imm_false)) + (inst2 MInst (MInst.CMov64SImm16 tmp2 cond tmp1 imm_true)) + (dst ValueRegs (value_reg tmp2))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs inst1 inst2 dst))) + +;; Conditionally select between two source registers. +(decl cmov_reg_reg (Type Cond Reg Reg) ConsumesFlags) +(rule 1 (cmov_reg_reg (gpr32_ty ty) cond reg_true reg_false) + (let ((dst WritableReg (temp_writable_reg ty)) + (inst MInst (MInst.CMov32 dst cond reg_false reg_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) +(rule 2 (cmov_reg_reg (gpr64_ty ty) cond reg_true reg_false) + (let ((dst WritableReg (temp_writable_reg ty)) + (inst MInst (MInst.CMov64 dst cond reg_false reg_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) +(rule 3 (cmov_reg_reg $F32 cond reg_true reg_false) + (let ((dst WritableReg (temp_writable_reg $F32)) + (inst MInst (MInst.FpuCMov32 dst cond reg_false reg_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) +(rule 3 (cmov_reg_reg $F64 cond reg_true reg_false) + (let ((dst WritableReg (temp_writable_reg $F64)) + (inst MInst (MInst.FpuCMov64 dst cond reg_false reg_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) +(rule 0 (cmov_reg_reg (vr128_ty ty) cond reg_true reg_false) + (let ((dst WritableReg (temp_writable_reg $F64)) + (inst MInst (MInst.VecCMov dst cond reg_false reg_true))) + (ConsumesFlags.ConsumesFlagsReturnsReg inst dst))) + + +;; Helpers for generating conditional traps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl trap_if (ProducesFlags Cond TrapCode) Reg) +(rule (trap_if producer cond trap_code) + (let ((consumer ConsumesFlags (trap_if_impl cond trap_code)) + (_ InstOutput (side_effect (with_flags_side_effect producer consumer)))) + (invalid_reg))) + +(decl icmps_reg_and_trap (Type Reg Reg Cond TrapCode) Reg) +(rule (icmps_reg_and_trap ty src1 src2 cond trap_code) + (let ((_ Unit (emit (MInst.CmpTrapRR (cmpop_cmps ty) + src1 src2 cond trap_code)))) + (invalid_reg))) + +(decl icmps_simm16_and_trap (Type Reg i16 Cond TrapCode) Reg) +(rule (icmps_simm16_and_trap ty src imm cond trap_code) + (let ((_ Unit (emit (MInst.CmpTrapRSImm16 (cmpop_cmps ty) + src imm cond trap_code)))) + (invalid_reg))) + +(decl icmpu_reg_and_trap (Type Reg Reg Cond TrapCode) Reg) +(rule (icmpu_reg_and_trap ty src1 src2 cond trap_code) + (let ((_ Unit (emit (MInst.CmpTrapRR (cmpop_cmpu ty) + src1 src2 cond trap_code)))) + (invalid_reg))) + +(decl icmpu_uimm16_and_trap (Type Reg u16 Cond TrapCode) Reg) +(rule (icmpu_uimm16_and_trap ty src imm cond trap_code) + (let ((_ Unit (emit (MInst.CmpTrapRUImm16 (cmpop_cmpu ty) + src imm cond trap_code)))) + (invalid_reg))) + +(decl trap_impl (TrapCode) SideEffectNoResult) +(rule (trap_impl trap_code) + (SideEffectNoResult.Inst (MInst.Trap trap_code))) + +(decl trap_if_impl (Cond TrapCode) ConsumesFlags) +(rule (trap_if_impl cond trap_code) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.TrapIf cond trap_code))) + +(decl debugtrap_impl () SideEffectNoResult) +(rule (debugtrap_impl) + (SideEffectNoResult.Inst (MInst.Debugtrap))) + + +;; Helpers for handling boolean conditions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Capture a flags-producing instruction together with a condition code mask +;; that tells how to interpret the resulting condition code. The result can +;; be used to represent a boolean condition. +(type ProducesBool (enum (ProducesBool (producer ProducesFlags) (cond Cond)))) +(decl bool (ProducesFlags Cond) ProducesBool) +(rule (bool producer cond) (ProducesBool.ProducesBool producer cond)) + +;; Invert boolean condition. +(decl invert_bool (ProducesBool) ProducesBool) +(rule (invert_bool (ProducesBool.ProducesBool producer cond)) + (bool producer (invert_cond cond))) + +;; Use a boolean condition to select between two registers. +(decl select_bool_reg (Type ProducesBool Reg Reg) Reg) +(rule (select_bool_reg ty (ProducesBool.ProducesBool producer cond) reg_true reg_false) + (with_flags_reg producer (cmov_reg_reg ty cond reg_true reg_false))) + +;; Use a boolean condition to select between two immediate values. +(decl select_bool_imm (Type ProducesBool i16 i16) Reg) +(rule (select_bool_imm ty (ProducesBool.ProducesBool producer cond) imm_true imm_false) + (with_flags_reg producer (cmov_imm_imm ty cond imm_true imm_false))) + +;; Lower a boolean condition to the values 1/0. This rule is only used in the +;; context of instructions that return $I8 results. +(decl lower_bool (Type ProducesBool) Reg) +(rule (lower_bool $I8 cond) (select_bool_imm $I8 cond 1 0)) + +;; Lower a boolean condition to the values -1/0. +(decl lower_bool_to_mask (Type ProducesBool) Reg) +(rule 0 (lower_bool_to_mask (fits_in_64 ty) producer) + (select_bool_imm ty producer -1 0)) + +(rule 1 (lower_bool_to_mask $I128 producer) + (let ((res Reg (lower_bool_to_mask $I64 producer))) + (mov_to_vec128 $I128 res res))) + +;; Emit a conditional branch based on a boolean condition. +(decl cond_br_bool (ProducesBool MachLabel MachLabel) SideEffectNoResult) +(rule (cond_br_bool (ProducesBool.ProducesBool producer cond) taken not_taken) + (with_flags_side_effect producer (cond_br taken not_taken cond))) + +;; Emit a one-way conditional branch based on a boolean condition. +(decl oneway_cond_br_bool (ProducesBool MachLabel) SideEffectNoResult) +(rule (oneway_cond_br_bool (ProducesBool.ProducesBool producer cond) dest) + (with_flags_side_effect producer (oneway_cond_br dest cond))) + +;; Emit a conditional trap based on a boolean condition. +(decl trap_if_bool (ProducesBool TrapCode) SideEffectNoResult) +(rule (trap_if_bool (ProducesBool.ProducesBool producer cond) trap_code) + (with_flags_side_effect producer (trap_if_impl cond trap_code))) + + +;;;; Helpers for compare-and-swap loops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We use the emit_loop functionality to create compare-and-swap loops. +;; As noted there, code inside a loop emitted via emit_loop cannot write +;; to any virtual register, only hard registers. We use the two reserved +;; registers %r0 and %r1 in compare-and-swap loops. + +;; %r0 always holds the value currently loaded from the memory location. +(decl casloop_val_reg () WritableReg) +(rule (casloop_val_reg) (writable_gpr 0)) + +;; %r1 is available to compute the new value to be written. +(decl casloop_tmp_reg () WritableReg) +(rule (casloop_tmp_reg) (writable_gpr 1)) + +;; This takes a loop body for a compare-and-swap loop, completes it by +;; adding the actual compare-and-swap instruction, and emits the initial +;; memory load followed by the loop itself. "val" is the new value to +;; be written if the memory location still holds the old value in %r0. +;; The result should be passed to "casloop_result" or (in the case of +;; subword loops) to "casloop_rotate_result". +(decl casloop_emit (VecMInstBuilder Type MemFlags Reg Reg) PReg) +(rule (casloop_emit ib ty flags aligned_addr val) + (let ( + ;; Construct a memory argument for the aligned word. + (aligned_mem MemArg (memarg_reg_plus_off aligned_addr 0 0 flags)) + ;; Add the compare-and-swap instruction to the builder. + (result Reg (push_atomic_cas ib (ty_ext32 ty) + (casloop_val_reg) val aligned_mem)) + ;; Emit initial load followed by compare-and-swap loop. + (_ Unit (emit_load (ty_ext32 ty) (casloop_val_reg) aligned_mem)) + (_ Unit (emit_loop ib (intcc_as_cond (IntCC.NotEqual))))) + + ;; push_atomic_cas above returns its destination register argument, + ;; cas_loop_val_reg, as its result. As cas_loop_val_reg is a writable + ;; version of `gpr 0`, we return that directly here as a physical + ;; register to avoid accidentally using it with a non-preg move + ;; instruction. + (preg_gpr_0))) + +;; Compute the previous memory value after a (fullword) compare-and-swap loop. +;; In the big-endian case, the value is already correct, but may need to be +;; copied out of the hard register. In the little-endian case, we need to +;; byte-swap since the compare-and-swap instruction is always big-endian. +(decl casloop_result (Type MemFlags PReg) Reg) +(rule 1 (casloop_result (ty_32_or_64 ty) (bigendian) result) + (mov_preg result)) +(rule (casloop_result (ty_32_or_64 ty) (littleendian) result) + (bswap_reg ty (preg_to_reg result))) + +;; Emit a fullword compare-and-swap loop, returning the previous memory value. +(decl casloop (VecMInstBuilder Type MemFlags Reg Reg) Reg) +(rule (casloop ib ty flags aligned_addr val) + (casloop_result ty flags (casloop_emit ib ty flags aligned_addr val))) + +;; For types smaller than $I32, we have no native compare-and-swap +;; instruction, so we need to perform the compare-and-swap loop on the +;; surrounding aligned word. To actually operate on the target $I8 or +;; $I16 data, that aligned word then needs to be rotated by an amount +;; determined by the low address bits. + +;; Determine the rotate amount to bring the target data into a position +;; in the high bytes of the enclosing $I32. Since the compare-and-swap +;; instruction performs a big-endian memory access, this can be done by +;; rotating (left) by "(addr & 3) * 8" bits, or "(addr << 3) & 31" bits. +;; We can omit the "& 31" since this is implicit with a 32-bit rotate. +(decl casloop_bitshift (Reg) Reg) +(rule (casloop_bitshift addr) + (lshl_imm $I32 addr 3)) + +;; The address of the surrounding 32-bit word, by masking off low bits. +(decl casloop_aligned_addr (Reg) Reg) +(rule (casloop_aligned_addr addr) + (and_uimm16shifted $I64 addr (uimm16shifted 0xfffc 0))) + +;; Push an instruction sequence to rotate a value loaded from memory +;; to the well-defined location: the high bytes in case of a big-endian +;; memory operation, and the low bytes in the little-endian case. +;; (This is somewhat arbitrary but chosen to allow the most efficient +;; sequences to compute the various atomic operations.) +;; Note that $I8 accesses always use the big-endian case. +(decl casloop_rotate_in (VecMInstBuilder Type MemFlags Reg Reg) Reg) +(rule (casloop_rotate_in ib $I8 _ bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 0 bitshift)) +(rule 1 (casloop_rotate_in ib $I16 (bigendian) bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 0 bitshift)) +(rule (casloop_rotate_in ib $I16 (littleendian) bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 16 bitshift)) + +;; The inverse operation: rotate values back to the original memory order. +;; This can be done by simply using the negated shift count. As an extra +;; optimization, we note that in the $I16 case the shift count can only +;; take the values 0 or 16, both of which negate to themselves (mod 32), +;; so the explicit negation operation can be omitted here. +(decl casloop_rotate_out (VecMInstBuilder Type MemFlags Reg Reg) Reg) +(rule (casloop_rotate_out ib $I8 _ bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 0 (neg_reg $I32 bitshift))) +(rule 1 (casloop_rotate_out ib $I16 (bigendian) bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 0 bitshift)) +(rule (casloop_rotate_out ib $I16 (littleendian) bitshift val) + (push_rot_imm_reg ib $I32 (casloop_tmp_reg) val 16 bitshift)) + +;; Compute the previous memory value after a subword compare-and-swap loop. +;; This is similar to casloop_rotate_in, but brings the value to the *low* +;; bytes. This can be achieved simply by adding the type size to the rotate +;; amount, which can be done within the same instruction. In the little- +;; endian case, we also need to byte-swap the result. Since we only have +;; a 32-bit byte-swap instruction, we load the value to the high bytes in +;; this case before performing the 32-bit byte-swap. +(decl casloop_rotate_result (Type MemFlags Reg Reg) Reg) +(rule (casloop_rotate_result $I8 _ bitshift result) + (rot_imm_reg $I32 result 8 bitshift)) +(rule 1 (casloop_rotate_result $I16 (bigendian) bitshift result) + (rot_imm_reg $I32 result 16 bitshift)) +(rule (casloop_rotate_result $I16 (littleendian) bitshift result) + (bswap_reg $I32 (rot_reg $I32 result bitshift))) + +;; Emit a subword compare-and-swap loop, returning the previous memory value. +(decl casloop_subword (VecMInstBuilder Type MemFlags Reg Reg Reg) Reg) +(rule (casloop_subword ib ty flags aligned_addr bitshift val) + (casloop_rotate_result ty flags bitshift + (casloop_emit ib ty flags aligned_addr val))) + + +;; Helpers for generating `call` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Partial (mutable) argument list in the process of being created. +(type CallArgListBuilder extern (enum)) + +;; Create a new empty instruction sequence builder. +(decl args_builder_new () CallArgListBuilder) +(extern constructor args_builder_new args_builder_new) + +;; Push an instruction to a sequence under construction. +(decl args_builder_push (CallArgListBuilder Reg RealReg) Unit) +(extern constructor args_builder_push args_builder_push) + +;; Complete the sequence under construction. +(decl args_builder_finish (CallArgListBuilder) CallArgList) +(extern constructor args_builder_finish args_builder_finish) + +;; List of return registers for a call instnuction. +(type CallRetList extern (enum)) + +;; Initialize return register list. +(decl defs_init (Sig) CallRetList) +(extern constructor defs_init defs_init) + +;; Look up return register in list. +(decl defs_lookup (CallRetList RealReg) Reg) +(extern constructor defs_lookup defs_lookup) + +(decl abi_sig (SigRef) Sig) +(extern constructor abi_sig abi_sig) + +(decl abi_first_ret (SigRef Sig) usize) +(extern constructor abi_first_ret abi_first_ret) + +(decl abi_call_info (Sig ExternalName CallArgList CallRetList) BoxCallInfo) +(extern constructor abi_call_info abi_call_info) + +(decl abi_call_ind_info (Sig Reg CallArgList CallRetList) BoxCallIndInfo) +(extern constructor abi_call_ind_info abi_call_ind_info) + +(decl abi_return_call_info (Sig ExternalName CallArgList) BoxReturnCallInfo) +(extern constructor abi_return_call_info abi_return_call_info) + +(decl abi_return_call_ind_info (Sig Reg CallArgList) BoxReturnCallIndInfo) +(extern constructor abi_return_call_ind_info abi_return_call_ind_info) + +(decl abi_call_stack_args (Sig) MemArg) +(extern constructor abi_call_stack_args abi_call_stack_args) + +(decl abi_call_stack_rets (Sig) MemArg) +(extern constructor abi_call_stack_rets abi_call_stack_rets) + +(decl abi_return_call_stack_args (Sig) MemArg) +(extern constructor abi_return_call_stack_args abi_return_call_stack_args) + +(decl writable_link_reg () WritableReg) +(rule (writable_link_reg) (writable_gpr 14)) + +(decl abi_call (Sig ExternalName CallArgList CallRetList) SideEffectNoResult) +(rule (abi_call abi name uses defs) + (call_impl (writable_link_reg) (abi_call_info abi name uses defs))) + +(decl abi_call_ind (Sig Reg CallArgList CallRetList) SideEffectNoResult) +(rule (abi_call_ind abi target uses defs) + (call_ind_impl (writable_link_reg) (abi_call_ind_info abi target uses defs))) + +(decl abi_return_call (Sig ExternalName CallArgList) SideEffectNoResult) +(rule (abi_return_call abi name uses) + (return_call_impl (abi_return_call_info abi name uses))) + +(decl abi_return_call_ind (Sig Reg CallArgList) SideEffectNoResult) +(rule (abi_return_call_ind abi target uses) + (return_call_ind_impl (abi_return_call_ind_info abi target uses))) + +(decl abi_lane_order (Sig) LaneOrder) +(extern constructor abi_lane_order abi_lane_order) + + +;; Helpers for generating vector pack and unpack instructions ;;;;;;;;;;;;;;;;;; + +(decl vec_widen_type (Type) Type) +(rule (vec_widen_type $I8X16) $I16X8) +(rule (vec_widen_type $I16X8) $I32X4) +(rule (vec_widen_type $I32X4) $I64X2) + +(decl vecop_pack (Type) VecBinaryOp) +(rule (vecop_pack $I16X8) (VecBinaryOp.Pack16x8)) +(rule (vecop_pack $I32X4) (VecBinaryOp.Pack32x4)) +(rule (vecop_pack $I64X2) (VecBinaryOp.Pack64x2)) + +(decl vec_pack (Type Reg Reg) Reg) +(rule (vec_pack ty x y) (vec_rrr ty (vecop_pack ty) x y)) + +(decl vecop_pack_ssat (Type) VecBinaryOp) +(rule (vecop_pack_ssat $I16X8) (VecBinaryOp.PackSSat16x8)) +(rule (vecop_pack_ssat $I32X4) (VecBinaryOp.PackSSat32x4)) +(rule (vecop_pack_ssat $I64X2) (VecBinaryOp.PackSSat64x2)) + +(decl vec_pack_ssat (Type Reg Reg) Reg) +(rule (vec_pack_ssat ty x y) (vec_rrr ty (vecop_pack_ssat ty) x y)) + +(decl vecop_pack_usat (Type) VecBinaryOp) +(rule (vecop_pack_usat $I16X8) (VecBinaryOp.PackUSat16x8)) +(rule (vecop_pack_usat $I32X4) (VecBinaryOp.PackUSat32x4)) +(rule (vecop_pack_usat $I64X2) (VecBinaryOp.PackUSat64x2)) + +(decl vec_pack_usat (Type Reg Reg) Reg) +(rule (vec_pack_usat ty x y) (vec_rrr ty (vecop_pack_usat ty) x y)) + +(decl vecop_unpacks_low (Type) VecUnaryOp) +(rule (vecop_unpacks_low $I8X16) (VecUnaryOp.UnpackSLow8x16)) +(rule (vecop_unpacks_low $I16X8) (VecUnaryOp.UnpackSLow16x8)) +(rule (vecop_unpacks_low $I32X4) (VecUnaryOp.UnpackSLow32x4)) + +(decl vec_unpacks_low (Type Reg) Reg) +(rule (vec_unpacks_low ty x) (vec_rr ty (vecop_unpacks_low ty) x)) + +(decl vecop_unpacks_high (Type) VecUnaryOp) +(rule (vecop_unpacks_high $I8X16) (VecUnaryOp.UnpackSHigh8x16)) +(rule (vecop_unpacks_high $I16X8) (VecUnaryOp.UnpackSHigh16x8)) +(rule (vecop_unpacks_high $I32X4) (VecUnaryOp.UnpackSHigh32x4)) + +(decl vec_unpacks_high (Type Reg) Reg) +(rule (vec_unpacks_high ty x) (vec_rr ty (vecop_unpacks_high ty) x)) + +(decl vecop_unpacku_low (Type) VecUnaryOp) +(rule (vecop_unpacku_low $I8X16) (VecUnaryOp.UnpackULow8x16)) +(rule (vecop_unpacku_low $I16X8) (VecUnaryOp.UnpackULow16x8)) +(rule (vecop_unpacku_low $I32X4) (VecUnaryOp.UnpackULow32x4)) + +(decl vec_unpacku_low (Type Reg) Reg) +(rule (vec_unpacku_low ty x) (vec_rr ty (vecop_unpacku_low ty) x)) + +(decl vecop_unpacku_high (Type) VecUnaryOp) +(rule (vecop_unpacku_high $I8X16) (VecUnaryOp.UnpackUHigh8x16)) +(rule (vecop_unpacku_high $I16X8) (VecUnaryOp.UnpackUHigh16x8)) +(rule (vecop_unpacku_high $I32X4) (VecUnaryOp.UnpackUHigh32x4)) + +(decl vec_unpacku_high (Type Reg) Reg) +(rule (vec_unpacku_high ty x) (vec_rr ty (vecop_unpacku_high ty) x)) + +;; Versions of pack using current lane order semantics. +;; First source operand contains values that will end up in the +;; lower-numbered lanes of the result, second operand contains +;; values that will end up in the higher-numbered lanes. + +(decl vec_pack_lane_order (Type Reg Reg) Reg) +(rule 1 (vec_pack_lane_order ty x y) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_pack ty x y)) +(rule (vec_pack_lane_order ty x y) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_pack ty y x)) + +(decl vec_pack_ssat_lane_order (Type Reg Reg) Reg) +(rule 1 (vec_pack_ssat_lane_order ty x y) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_pack_ssat ty x y)) +(rule (vec_pack_ssat_lane_order ty x y) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_pack_ssat ty y x)) + +(decl vec_pack_usat_lane_order (Type Reg Reg) Reg) +(rule 1 (vec_pack_usat_lane_order ty x y) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_pack_usat ty x y)) +(rule (vec_pack_usat_lane_order ty x y) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_pack_usat ty y x)) + +;; Versions of unpack using current lane order semantics. +;; unpack_low will consume values from the lower-numbered +;; lanes of the input, and unpack_high will consume values +;; from higher-numbered lanes. + +(decl vec_unpacks_low_lane_order (Type Reg) Reg) +(rule 1 (vec_unpacks_low_lane_order ty x) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_unpacks_high ty x)) +(rule (vec_unpacks_low_lane_order ty x) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_unpacks_low ty x)) + +(decl vec_unpacks_high_lane_order (Type Reg) Reg) +(rule 1 (vec_unpacks_high_lane_order ty x) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_unpacks_low ty x)) +(rule (vec_unpacks_high_lane_order ty x) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_unpacks_high ty x)) + +(decl vec_unpacku_low_lane_order (Type Reg) Reg) +(rule 1 (vec_unpacku_low_lane_order ty x) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_unpacku_high ty x)) +(rule (vec_unpacku_low_lane_order ty x) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_unpacku_low ty x)) + +(decl vec_unpacku_high_lane_order (Type Reg) Reg) +(rule 1 (vec_unpacku_high_lane_order ty x) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_unpacku_low ty x)) +(rule (vec_unpacku_high_lane_order ty x) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_unpacku_high ty x)) + + +;; Helpers for generating vector merge instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_merge_low (Type) VecBinaryOp) +(rule (vecop_merge_low $I8X16) (VecBinaryOp.MergeLow8x16)) +(rule (vecop_merge_low $I16X8) (VecBinaryOp.MergeLow16x8)) +(rule (vecop_merge_low $I32X4) (VecBinaryOp.MergeLow32x4)) +(rule (vecop_merge_low $I64X2) (VecBinaryOp.MergeLow64x2)) + +(decl vec_merge_low (Type Reg Reg) Reg) +(rule (vec_merge_low ty x y) (vec_rrr ty (vecop_merge_low ty) x y)) + +(decl vecop_merge_high (Type) VecBinaryOp) +(rule (vecop_merge_high $I8X16) (VecBinaryOp.MergeHigh8x16)) +(rule (vecop_merge_high $I16X8) (VecBinaryOp.MergeHigh16x8)) +(rule (vecop_merge_high $I32X4) (VecBinaryOp.MergeHigh32x4)) +(rule (vecop_merge_high $I64X2) (VecBinaryOp.MergeHigh64x2)) + +(decl vec_merge_high (Type Reg Reg) Reg) +(rule (vec_merge_high ty x y) (vec_rrr ty (vecop_merge_high ty) x y)) + +;; Versions of merge using current lane order semantics. +;; merge_low will consume values from the lower-numbered +;; lanes of the inputs, and merge_high will consume values +;; from higher-numbered lanes. In both cases, values from +;; the first input will end up in even-numbered lanes, and +;; values from the second input will end up in odd-numbered +;; lanes of the output. + +(decl vec_merge_low_lane_order (Type Reg Reg) Reg) +(rule 1 (vec_merge_low_lane_order ty x y) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_merge_high ty x y)) +(rule (vec_merge_low_lane_order ty x y) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_merge_low ty y x)) + +(decl vec_merge_high_lane_order (Type Reg Reg) Reg) +(rule 1 (vec_merge_high_lane_order ty x y) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_merge_low ty x y)) +(rule (vec_merge_high_lane_order ty x y) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_merge_high ty y x)) + + +;; Helpers for generating `clz` and `ctz` instructions ;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Count leading zeroes. For a zero input, return the specified value. +(decl clz_reg (i16 Reg) Reg) + +;; The flogr instruction returns 64 for zero input by default. +(rule (clz_reg 64 x) + (let ((dst WritableRegPair (temp_writable_regpair)) + (_ Unit (emit (MInst.Flogr dst x)))) + (regpair_hi dst))) + +;; If another zero return value was requested, we need to override the flogr result. +(rule -1 (clz_reg zeroval x) + (let ((tmp WritableRegPair (temp_writable_regpair))) + (with_flags_reg + (ProducesFlags.ProducesFlagsSideEffect (MInst.Flogr tmp x)) + (cmov_imm $I64 (intcc_as_cond (IntCC.Equal)) zeroval (regpair_hi tmp))))) + +;; Vector count leading zeros. +(decl vecop_clz (Type) VecUnaryOp) +(rule (vecop_clz $I8X16) (VecUnaryOp.Clz8x16)) +(rule (vecop_clz $I16X8) (VecUnaryOp.Clz16x8)) +(rule (vecop_clz $I32X4) (VecUnaryOp.Clz32x4)) +(rule (vecop_clz $I64X2) (VecUnaryOp.Clz64x2)) + +(decl vec_clz (Type Reg) Reg) +(rule (vec_clz ty x) (vec_rr ty (vecop_clz ty) x)) + +;; Vector count trailing zeros. +(decl vecop_ctz (Type) VecUnaryOp) +(rule (vecop_ctz $I8X16) (VecUnaryOp.Ctz8x16)) +(rule (vecop_ctz $I16X8) (VecUnaryOp.Ctz16x8)) +(rule (vecop_ctz $I32X4) (VecUnaryOp.Ctz32x4)) +(rule (vecop_ctz $I64X2) (VecUnaryOp.Ctz64x2)) + +(decl vec_ctz (Type Reg) Reg) +(rule (vec_ctz ty x) (vec_rr ty (vecop_ctz ty) x)) + + +;; Helpers for generating saturating integer instructions ;;;;;;;;;;;;;;;;;;;;;; + +(decl uint_sat_reg (Type Type Reg) Reg) +(rule 1 (uint_sat_reg ty ty reg) reg) +(rule (uint_sat_reg $I8 (ty_32_or_64 ty) reg) + (with_flags_reg (icmpu_uimm32 ty reg 256) + (cmov_imm ty (intcc_as_cond (IntCC.UnsignedGreaterThan)) 255 reg))) +(rule (uint_sat_reg $I16 (ty_32_or_64 ty) reg) + (with_flags_reg (icmpu_uimm32 ty reg 65535) + (cmov_imm ty (intcc_as_cond (IntCC.UnsignedGreaterThan)) -1 reg))) +(rule (uint_sat_reg $I32 $I64 reg) + (let ((bound Reg (imm $I64 4294967295)) + (cond ProducesBool + (bool (icmpu_reg $I64 reg bound) + (intcc_as_cond (IntCC.UnsignedGreaterThan))))) + (select_bool_reg $I64 cond bound reg))) + +(decl sint_sat_reg (Type Type Reg) Reg) +(rule 1 (sint_sat_reg ty ty reg) reg) +(rule (sint_sat_reg $I8 (ty_32_or_64 ty) reg) + (let ((ub Reg (with_flags_reg (icmps_simm16 ty reg 127) + (cmov_imm ty + (intcc_as_cond (IntCC.SignedGreaterThan)) 127 reg)))) + (with_flags_reg (icmps_simm16 ty ub -128) + (cmov_imm ty (intcc_as_cond (IntCC.SignedLessThan)) -128 ub)))) +(rule (sint_sat_reg $I16 (ty_32_or_64 ty) reg) + (let ((ub Reg (with_flags_reg (icmps_simm16 ty reg 32767) + (cmov_imm ty + (intcc_as_cond (IntCC.SignedGreaterThan)) 32767 reg)))) + (with_flags_reg (icmps_simm16 ty ub -32768) + (cmov_imm ty (intcc_as_cond (IntCC.SignedLessThan)) -32768 ub)))) +(rule (sint_sat_reg $I32 $I64 reg) + (let ((u_bound Reg (imm32 $I64 2147483647)) + (u_cond ProducesBool + (bool (icmps_reg $I64 reg u_bound) + (intcc_as_cond (IntCC.SignedGreaterThan)))) + (ub Reg (select_bool_reg $I64 u_cond u_bound reg)) + (l_bound Reg (imm32 $I64 -2147483648)) + (l_cond ProducesBool + (bool (icmps_reg $I64 ub l_bound) + (intcc_as_cond (IntCC.SignedLessThan))))) + (select_bool_reg $I64 l_cond l_bound ub))) + + +;; Helpers for generating `add` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_add (Type) ALUOp) +(rule (aluop_add $I8) (ALUOp.Add32)) +(rule (aluop_add $I16) (ALUOp.Add32)) +(rule (aluop_add $I32) (ALUOp.Add32)) +(rule (aluop_add $I64) (ALUOp.Add64)) + +(decl aluop_add_sext16 (Type) ALUOp) +(rule (aluop_add_sext16 $I16) (ALUOp.Add32Ext16)) +(rule (aluop_add_sext16 $I32) (ALUOp.Add32Ext16)) +(rule (aluop_add_sext16 $I64) (ALUOp.Add64Ext16)) + +(decl aluop_add_sext32 (Type) ALUOp) +(rule (aluop_add_sext32 $I64) (ALUOp.Add64Ext32)) + +(decl add_reg (Type Reg Reg) Reg) +(rule (add_reg ty x y) (alu_rrr ty (aluop_add ty) x y)) + +(decl add_reg_sext32 (Type Reg Reg) Reg) +(rule (add_reg_sext32 ty x y) (alu_rr ty (aluop_add_sext32 ty) x y)) + +(decl add_simm16 (Type Reg i16) Reg) +(rule (add_simm16 ty x y) (alu_rrsimm16 ty (aluop_add ty) x y)) + +(decl add_simm32 (Type Reg i32) Reg) +(rule (add_simm32 ty x y) (alu_rsimm32 ty (aluop_add ty) x y)) + +(decl add_mem (Type Reg MemArg) Reg) +(rule (add_mem ty x y) (alu_rx ty (aluop_add ty) x y)) + +(decl add_mem_sext16 (Type Reg MemArg) Reg) +(rule (add_mem_sext16 ty x y) (alu_rx ty (aluop_add_sext16 ty) x y)) + +(decl add_mem_sext32 (Type Reg MemArg) Reg) +(rule (add_mem_sext32 ty x y) (alu_rx ty (aluop_add_sext32 ty) x y)) + +(decl vecop_add (Type) VecBinaryOp) +(rule (vecop_add $I8X16) (VecBinaryOp.Add8x16)) +(rule (vecop_add $I16X8) (VecBinaryOp.Add16x8)) +(rule (vecop_add $I32X4) (VecBinaryOp.Add32x4)) +(rule (vecop_add $I64X2) (VecBinaryOp.Add64x2)) +(rule (vecop_add $I128) (VecBinaryOp.Add128)) + +(decl vec_add (Type Reg Reg) Reg) +(rule (vec_add ty x y) (vec_rrr ty (vecop_add ty) x y)) + + +;; Helpers for generating `add_logical` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_add_logical (Type) ALUOp) +(rule (aluop_add_logical $I32) (ALUOp.AddLogical32)) +(rule (aluop_add_logical $I64) (ALUOp.AddLogical64)) + +(decl aluop_add_logical_zext32 (Type) ALUOp) +(rule (aluop_add_logical_zext32 $I64) (ALUOp.AddLogical64Ext32)) + +(decl add_logical_reg (Type Reg Reg) Reg) +(rule (add_logical_reg ty x y) (alu_rrr ty (aluop_add_logical ty) x y)) + +(decl add_logical_reg_with_flags_paired (Type Reg Reg) ProducesFlags) +(rule (add_logical_reg_with_flags_paired ty x y) + (alu_rrr_with_flags_paired ty (aluop_add_logical ty) x y)) + +(decl add_logical_reg_zext32 (Type Reg Reg) Reg) +(rule (add_logical_reg_zext32 ty x y) (alu_rr ty (aluop_add_logical_zext32 ty) x y)) + +(decl add_logical_reg_zext32_with_flags_paired (Type Reg Reg) ProducesFlags) +(rule (add_logical_reg_zext32_with_flags_paired ty x y) + (alu_rr_with_flags_paired ty (aluop_add_logical_zext32 ty) x y)) + +(decl add_logical_zimm32 (Type Reg u32) Reg) +(rule (add_logical_zimm32 ty x y) (alu_ruimm32 ty (aluop_add_logical ty) x y)) + +(decl add_logical_zimm32_with_flags_paired (Type Reg u32) ProducesFlags) +(rule (add_logical_zimm32_with_flags_paired ty x y) + (alu_ruimm32_with_flags_paired ty (aluop_add_logical ty) x y)) + +(decl add_logical_mem (Type Reg MemArg) Reg) +(rule (add_logical_mem ty x y) (alu_rx ty (aluop_add_logical ty) x y)) + +(decl add_logical_mem_with_flags_paired (Type Reg MemArg) ProducesFlags) +(rule (add_logical_mem_with_flags_paired ty x y) + (alu_rx_with_flags_paired ty (aluop_add_logical ty) x y)) + +(decl add_logical_mem_zext32 (Type Reg MemArg) Reg) +(rule (add_logical_mem_zext32 ty x y) (alu_rx ty (aluop_add_logical_zext32 ty) x y)) + +(decl add_logical_mem_zext32_with_flags_paired (Type Reg MemArg) ProducesFlags) +(rule (add_logical_mem_zext32_with_flags_paired ty x y) + (alu_rx_with_flags_paired ty (aluop_add_logical_zext32 ty) x y)) + + +;; Helpers for generating `sub` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_sub (Type) ALUOp) +(rule (aluop_sub $I8) (ALUOp.Sub32)) +(rule (aluop_sub $I16) (ALUOp.Sub32)) +(rule (aluop_sub $I32) (ALUOp.Sub32)) +(rule (aluop_sub $I64) (ALUOp.Sub64)) + +(decl aluop_sub_sext16 (Type) ALUOp) +(rule (aluop_sub_sext16 $I16) (ALUOp.Sub32Ext16)) +(rule (aluop_sub_sext16 $I32) (ALUOp.Sub32Ext16)) +(rule (aluop_sub_sext16 $I64) (ALUOp.Sub64Ext16)) + +(decl aluop_sub_sext32 (Type) ALUOp) +(rule (aluop_sub_sext32 $I64) (ALUOp.Sub64Ext32)) + +(decl sub_reg (Type Reg Reg) Reg) +(rule (sub_reg ty x y) (alu_rrr ty (aluop_sub ty) x y)) + +(decl sub_reg_sext32 (Type Reg Reg) Reg) +(rule (sub_reg_sext32 ty x y) (alu_rr ty (aluop_sub_sext32 ty) x y)) + +(decl sub_mem (Type Reg MemArg) Reg) +(rule (sub_mem ty x y) (alu_rx ty (aluop_sub ty) x y)) + +(decl sub_mem_sext16 (Type Reg MemArg) Reg) +(rule (sub_mem_sext16 ty x y) (alu_rx ty (aluop_sub_sext16 ty) x y)) + +(decl sub_mem_sext32 (Type Reg MemArg) Reg) +(rule (sub_mem_sext32 ty x y) (alu_rx ty (aluop_sub_sext32 ty) x y)) + +(decl vecop_sub (Type) VecBinaryOp) +(rule (vecop_sub $I8X16) (VecBinaryOp.Sub8x16)) +(rule (vecop_sub $I16X8) (VecBinaryOp.Sub16x8)) +(rule (vecop_sub $I32X4) (VecBinaryOp.Sub32x4)) +(rule (vecop_sub $I64X2) (VecBinaryOp.Sub64x2)) +(rule (vecop_sub $I128) (VecBinaryOp.Sub128)) + +(decl vec_sub (Type Reg Reg) Reg) +(rule (vec_sub ty x y) (vec_rrr ty (vecop_sub ty) x y)) + + +;; Helpers for generating `sub_logical` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_sub_logical (Type) ALUOp) +(rule (aluop_sub_logical $I32) (ALUOp.SubLogical32)) +(rule (aluop_sub_logical $I64) (ALUOp.SubLogical64)) + +(decl aluop_sub_logical_zext32 (Type) ALUOp) +(rule (aluop_sub_logical_zext32 $I64) (ALUOp.SubLogical64Ext32)) + +(decl sub_logical_reg (Type Reg Reg) Reg) +(rule (sub_logical_reg ty x y) (alu_rrr ty (aluop_sub_logical ty) x y)) + +(decl sub_logical_reg_zext32 (Type Reg Reg) Reg) +(rule (sub_logical_reg_zext32 ty x y) (alu_rr ty (aluop_sub_logical_zext32 ty) x y)) + +(decl sub_logical_zimm32 (Type Reg u32) Reg) +(rule (sub_logical_zimm32 ty x y) (alu_ruimm32 ty (aluop_sub_logical ty) x y)) + +(decl sub_logical_mem (Type Reg MemArg) Reg) +(rule (sub_logical_mem ty x y) (alu_rx ty (aluop_sub_logical ty) x y)) + +(decl sub_logical_mem_zext32 (Type Reg MemArg) Reg) +(rule (sub_logical_mem_zext32 ty x y) (alu_rx ty (aluop_sub_logical ty) x y)) + + +;; Helpers for generating `mul` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_mul (Type) ALUOp) +(rule (aluop_mul $I8) (ALUOp.Mul32)) +(rule (aluop_mul $I16) (ALUOp.Mul32)) +(rule (aluop_mul $I32) (ALUOp.Mul32)) +(rule (aluop_mul $I64) (ALUOp.Mul64)) + +(decl aluop_mul_sext16 (Type) ALUOp) +(rule (aluop_mul_sext16 $I16) (ALUOp.Mul32Ext16)) +(rule (aluop_mul_sext16 $I32) (ALUOp.Mul32Ext16)) +(rule (aluop_mul_sext16 $I64) (ALUOp.Mul64Ext16)) + +(decl aluop_mul_sext32 (Type) ALUOp) +(rule (aluop_mul_sext32 $I64) (ALUOp.Mul64Ext32)) + +(decl mul_reg (Type Reg Reg) Reg) +(rule (mul_reg ty x y) (alu_rrr ty (aluop_mul ty) x y)) + +(decl mul_reg_sext32 (Type Reg Reg) Reg) +(rule (mul_reg_sext32 ty x y) (alu_rr ty (aluop_mul_sext32 ty) x y)) + +(decl mul_simm16 (Type Reg i16) Reg) +(rule (mul_simm16 ty x y) (alu_rsimm16 ty (aluop_mul ty) x y)) + +(decl mul_simm32 (Type Reg i32) Reg) +(rule (mul_simm32 ty x y) (alu_rsimm32 ty (aluop_mul ty) x y)) + +(decl mul_mem (Type Reg MemArg) Reg) +(rule (mul_mem ty x y) (alu_rx ty (aluop_mul ty) x y)) + +(decl mul_mem_sext16 (Type Reg MemArg) Reg) +(rule (mul_mem_sext16 ty x y) (alu_rx ty (aluop_mul_sext16 ty) x y)) + +(decl mul_mem_sext32 (Type Reg MemArg) Reg) +(rule (mul_mem_sext32 ty x y) (alu_rx ty (aluop_mul_sext32 ty) x y)) + +(decl vecop_mul (Type) VecBinaryOp) +(rule (vecop_mul $I8X16) (VecBinaryOp.Mul8x16)) +(rule (vecop_mul $I16X8) (VecBinaryOp.Mul16x8)) +(rule (vecop_mul $I32X4) (VecBinaryOp.Mul32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_mul (Type Reg Reg) Reg) +(rule (vec_mul ty x y) (vec_rrr ty (vecop_mul ty) x y)) + +(decl vecop_umulhi (Type) VecBinaryOp) +(rule (vecop_umulhi $I8X16) (VecBinaryOp.UMulHi8x16)) +(rule (vecop_umulhi $I16X8) (VecBinaryOp.UMulHi16x8)) +(rule (vecop_umulhi $I32X4) (VecBinaryOp.UMulHi32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_umulhi (Type Reg Reg) Reg) +(rule (vec_umulhi ty x y) (vec_rrr ty (vecop_umulhi ty) x y)) + +(decl vecop_smulhi (Type) VecBinaryOp) +(rule (vecop_smulhi $I8X16) (VecBinaryOp.SMulHi8x16)) +(rule (vecop_smulhi $I16X8) (VecBinaryOp.SMulHi16x8)) +(rule (vecop_smulhi $I32X4) (VecBinaryOp.SMulHi32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_smulhi (Type Reg Reg) Reg) +(rule (vec_smulhi ty x y) (vec_rrr ty (vecop_smulhi ty) x y)) + +(decl vecop_umul_even (Type) VecBinaryOp) +(rule (vecop_umul_even $I8X16) (VecBinaryOp.UMulEven8x16)) +(rule (vecop_umul_even $I16X8) (VecBinaryOp.UMulEven16x8)) +(rule (vecop_umul_even $I32X4) (VecBinaryOp.UMulEven32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_umul_even (Type Reg Reg) Reg) +(rule (vec_umul_even ty x y) (vec_rrr ty (vecop_umul_even ty) x y)) + +(decl vecop_smul_even (Type) VecBinaryOp) +(rule (vecop_smul_even $I8X16) (VecBinaryOp.SMulEven8x16)) +(rule (vecop_smul_even $I16X8) (VecBinaryOp.SMulEven16x8)) +(rule (vecop_smul_even $I32X4) (VecBinaryOp.SMulEven32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_smul_even (Type Reg Reg) Reg) +(rule (vec_smul_even ty x y) (vec_rrr ty (vecop_smul_even ty) x y)) + +(decl vecop_umul_odd (Type) VecBinaryOp) +(rule (vecop_umul_odd $I8X16) (VecBinaryOp.UMulOdd8x16)) +(rule (vecop_umul_odd $I16X8) (VecBinaryOp.UMulOdd16x8)) +(rule (vecop_umul_odd $I32X4) (VecBinaryOp.UMulOdd32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_umul_odd (Type Reg Reg) Reg) +(rule (vec_umul_odd ty x y) (vec_rrr ty (vecop_umul_odd ty) x y)) + +(decl vecop_smul_odd (Type) VecBinaryOp) +(rule (vecop_smul_odd $I8X16) (VecBinaryOp.SMulOdd8x16)) +(rule (vecop_smul_odd $I16X8) (VecBinaryOp.SMulOdd16x8)) +(rule (vecop_smul_odd $I32X4) (VecBinaryOp.SMulOdd32x4)) +;; No support for $I64X2 multiplication. + +(decl vec_smul_odd (Type Reg Reg) Reg) +(rule (vec_smul_odd ty x y) (vec_rrr ty (vecop_smul_odd ty) x y)) + + +;; Helpers for generating `udivmod` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl udivmod (Type RegPair Reg) RegPair) +(rule (udivmod $I32 x y) (udivmod32 x y)) +(rule (udivmod $I64 x y) (udivmod64 x y)) + + +;; Helpers for generating `sdivmod` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl sdivmod (Type Reg Reg) RegPair) +(rule (sdivmod $I32 x y) (sdivmod32 x y)) +(rule (sdivmod $I64 x y) (sdivmod64 x y)) + + +;; Helpers for generating `umax` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_umax (Type) VecBinaryOp) +(rule (vecop_umax $I8X16) (VecBinaryOp.UMax8x16)) +(rule (vecop_umax $I16X8) (VecBinaryOp.UMax16x8)) +(rule (vecop_umax $I32X4) (VecBinaryOp.UMax32x4)) +(rule (vecop_umax $I64X2) (VecBinaryOp.UMax64x2)) + +(decl vec_umax (Type Reg Reg) Reg) +(rule (vec_umax ty x y) (vec_rrr ty (vecop_umax ty) x y)) + + +;; Helpers for generating `smax` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_smax (Type) VecBinaryOp) +(rule (vecop_smax $I8X16) (VecBinaryOp.SMax8x16)) +(rule (vecop_smax $I16X8) (VecBinaryOp.SMax16x8)) +(rule (vecop_smax $I32X4) (VecBinaryOp.SMax32x4)) +(rule (vecop_smax $I64X2) (VecBinaryOp.SMax64x2)) + +(decl vec_smax (Type Reg Reg) Reg) +(rule (vec_smax ty x y) (vec_rrr ty (vecop_smax ty) x y)) + + +;; Helpers for generating `umin` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_umin (Type) VecBinaryOp) +(rule (vecop_umin $I8X16) (VecBinaryOp.UMin8x16)) +(rule (vecop_umin $I16X8) (VecBinaryOp.UMin16x8)) +(rule (vecop_umin $I32X4) (VecBinaryOp.UMin32x4)) +(rule (vecop_umin $I64X2) (VecBinaryOp.UMin64x2)) + +(decl vec_umin (Type Reg Reg) Reg) +(rule (vec_umin ty x y) (vec_rrr ty (vecop_umin ty) x y)) + + +;; Helpers for generating `smin` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_smin (Type) VecBinaryOp) +(rule (vecop_smin $I8X16) (VecBinaryOp.SMin8x16)) +(rule (vecop_smin $I16X8) (VecBinaryOp.SMin16x8)) +(rule (vecop_smin $I32X4) (VecBinaryOp.SMin32x4)) +(rule (vecop_smin $I64X2) (VecBinaryOp.SMin64x2)) + +(decl vec_smin (Type Reg Reg) Reg) +(rule (vec_smin ty x y) (vec_rrr ty (vecop_smin ty) x y)) + + +;; Helpers for generating `avg_round` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_uavg (Type) VecBinaryOp) +(rule (vecop_uavg $I8X16) (VecBinaryOp.UAvg8x16)) +(rule (vecop_uavg $I16X8) (VecBinaryOp.UAvg16x8)) +(rule (vecop_uavg $I32X4) (VecBinaryOp.UAvg32x4)) +(rule (vecop_uavg $I64X2) (VecBinaryOp.UAvg64x2)) + +(decl vec_uavg (Type Reg Reg) Reg) +(rule (vec_uavg ty x y) (vec_rrr ty (vecop_uavg ty) x y)) + + +;; Helpers for generating `and` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_and (Type) ALUOp) +(rule (aluop_and (gpr32_ty _ty)) (ALUOp.And32)) +(rule 1 (aluop_and (gpr64_ty _ty)) (ALUOp.And64)) + +(decl and_reg (Type Reg Reg) Reg) +(rule (and_reg ty x y) (alu_rrr ty (aluop_and ty) x y)) + +(decl and_uimm16shifted (Type Reg UImm16Shifted) Reg) +(rule (and_uimm16shifted ty x y) (alu_ruimm16shifted ty (aluop_and ty) x y)) + +(decl and_uimm32shifted (Type Reg UImm32Shifted) Reg) +(rule (and_uimm32shifted ty x y) (alu_ruimm32shifted ty (aluop_and ty) x y)) + +(decl and_mem (Type Reg MemArg) Reg) +(rule (and_mem ty x y) (alu_rx ty (aluop_and ty) x y)) + +(decl vec_and (Type Reg Reg) Reg) +(rule (vec_and (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.And128) x y)) + + +;; Helpers for generating `or` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_or (Type) ALUOp) +(rule (aluop_or (gpr32_ty _ty)) (ALUOp.Orr32)) +(rule 1 (aluop_or (gpr64_ty _ty)) (ALUOp.Orr64)) + +(decl or_reg (Type Reg Reg) Reg) +(rule (or_reg ty x y) (alu_rrr ty (aluop_or ty) x y)) + +(decl or_uimm16shifted (Type Reg UImm16Shifted) Reg) +(rule (or_uimm16shifted ty x y) (alu_ruimm16shifted ty (aluop_or ty) x y)) + +(decl or_uimm32shifted (Type Reg UImm32Shifted) Reg) +(rule (or_uimm32shifted ty x y) (alu_ruimm32shifted ty (aluop_or ty) x y)) + +(decl or_mem (Type Reg MemArg) Reg) +(rule (or_mem ty x y) (alu_rx ty (aluop_or ty) x y)) + +(decl vec_or (Type Reg Reg) Reg) +(rule (vec_or (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.Orr128) x y)) + + +;; Helpers for generating `xor` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_xor (Type) ALUOp) +(rule (aluop_xor (gpr32_ty _ty)) (ALUOp.Xor32)) +(rule 1 (aluop_xor (gpr64_ty _ty)) (ALUOp.Xor64)) + +(decl xor_reg (Type Reg Reg) Reg) +(rule (xor_reg ty x y) (alu_rrr ty (aluop_xor ty) x y)) + +(decl xor_uimm32shifted (Type Reg UImm32Shifted) Reg) +(rule (xor_uimm32shifted ty x y) (alu_ruimm32shifted ty (aluop_xor ty) x y)) + +(decl xor_mem (Type Reg MemArg) Reg) +(rule (xor_mem ty x y) (alu_rx ty (aluop_xor ty) x y)) + +(decl push_xor_uimm32shifted (VecMInstBuilder Type WritableReg Reg UImm32Shifted) Reg) +(rule (push_xor_uimm32shifted ib ty dst src imm) + (push_alu_uimm32shifted ib (aluop_xor ty) dst src imm)) + +(decl vec_xor (Type Reg Reg) Reg) +(rule (vec_xor (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.Xor128) x y)) + + +;; Helpers for generating `not` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl not_reg (Type Reg) Reg) +(rule (not_reg (gpr32_ty ty) x) + (xor_uimm32shifted ty x (uimm32shifted 0xffffffff 0))) +(rule 1 (not_reg (gpr64_ty ty) x) + (xor_uimm32shifted ty + (xor_uimm32shifted ty x (uimm32shifted 0xffffffff 0)) + (uimm32shifted 0xffffffff 32))) + +(decl push_not_reg (VecMInstBuilder Type WritableReg Reg) Reg) +(rule (push_not_reg ib (gpr32_ty ty) dst src) + (push_xor_uimm32shifted ib ty dst src (uimm32shifted 0xffffffff 0))) +(rule 1 (push_not_reg ib (gpr64_ty ty) dst src) + (let ((val Reg (push_xor_uimm32shifted ib ty dst src (uimm32shifted 0xffffffff 0)))) + (push_xor_uimm32shifted ib ty dst val (uimm32shifted 0xffffffff 32)))) + +(decl vec_not (Type Reg) Reg) +(rule (vec_not ty x) (vec_not_or ty x x)) + + +;; Helpers for generating `not_and` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_not_and (Type) ALUOp) +(rule (aluop_not_and (gpr32_ty _ty)) (ALUOp.NotAnd32)) +(rule 1 (aluop_not_and (gpr64_ty _ty)) (ALUOp.NotAnd64)) + +(decl not_and_reg (Type Reg Reg) Reg) +(rule (not_and_reg ty x y) (alu_rrr ty (aluop_not_and ty) x y)) + +(decl vec_not_and (Type Reg Reg) Reg) +(rule (vec_not_and (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.NotAnd128) x y)) + + +;; Helpers for generating `not_or` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_not_or (Type) ALUOp) +(rule (aluop_not_or (gpr32_ty _ty)) (ALUOp.NotOrr32)) +(rule 1 (aluop_not_or (gpr64_ty _ty)) (ALUOp.NotOrr64)) + +(decl not_or_reg (Type Reg Reg) Reg) +(rule (not_or_reg ty x y) (alu_rrr ty (aluop_not_or ty) x y)) + +(decl vec_not_or (Type Reg Reg) Reg) +(rule (vec_not_or (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.NotOrr128) x y)) + + +;; Helpers for generating `not_xor` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_not_xor (Type) ALUOp) +(rule (aluop_not_xor (gpr32_ty _ty)) (ALUOp.NotXor32)) +(rule 1 (aluop_not_xor (gpr64_ty _ty)) (ALUOp.NotXor64)) + +(decl not_xor_reg (Type Reg Reg) Reg) +(rule (not_xor_reg ty x y) (alu_rrr ty (aluop_not_xor ty) x y)) + +(decl vec_not_xor (Type Reg Reg) Reg) +(rule (vec_not_xor (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.NotXor128) x y)) + + +;; Helpers for generating `and_not` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_and_not (Type) ALUOp) +(rule (aluop_and_not (gpr32_ty _ty)) (ALUOp.AndNot32)) +(rule 1 (aluop_and_not (gpr64_ty _ty)) (ALUOp.AndNot64)) + +(decl and_not_reg (Type Reg Reg) Reg) +(rule (and_not_reg ty x y) (alu_rrr ty (aluop_and_not ty) x y)) + +(decl vec_and_not (Type Reg Reg) Reg) +(rule (vec_and_not (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.AndNot128) x y)) + + +;; Helpers for generating `or_not` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl aluop_or_not (Type) ALUOp) +(rule (aluop_or_not (gpr32_ty _ty)) (ALUOp.OrrNot32)) +(rule 1 (aluop_or_not (gpr64_ty _ty)) (ALUOp.OrrNot64)) + +(decl or_not_reg (Type Reg Reg) Reg) +(rule (or_not_reg ty x y) (alu_rrr ty (aluop_or_not ty) x y)) + +(decl vec_or_not (Type Reg Reg) Reg) +(rule (vec_or_not (vr128_ty ty) x y) (vec_rrr ty (VecBinaryOp.OrrNot128) x y)) + + +;; Helpers for generating `bitpermute` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vec_bitpermute (Reg Reg) Reg) +(rule (vec_bitpermute x y) (vec_rrr $I64X2 (VecBinaryOp.BitPermute128) x y)) + + +;; Helpers for generating `abs` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl unaryop_abs (Type) UnaryOp) +(rule (unaryop_abs $I32) (UnaryOp.Abs32)) +(rule (unaryop_abs $I64) (UnaryOp.Abs64)) + +(decl unaryop_abs_sext32 (Type) UnaryOp) +(rule (unaryop_abs_sext32 $I64) (UnaryOp.Abs64Ext32)) + +(decl abs_reg (Type Reg) Reg) +(rule (abs_reg ty x) (unary_rr ty (unaryop_abs ty) x)) + +(decl abs_reg_sext32 (Type Reg) Reg) +(rule (abs_reg_sext32 ty x) (unary_rr ty (unaryop_abs_sext32 ty) x)) + +(decl vecop_abs (Type) VecUnaryOp) +(rule (vecop_abs $I8X16) (VecUnaryOp.Abs8x16)) +(rule (vecop_abs $I16X8) (VecUnaryOp.Abs16x8)) +(rule (vecop_abs $I32X4) (VecUnaryOp.Abs32x4)) +(rule (vecop_abs $I64X2) (VecUnaryOp.Abs64x2)) + +(decl vec_abs (Type Reg) Reg) +(rule (vec_abs ty x) (vec_rr ty (vecop_abs ty) x)) + + +;; Helpers for generating `neg` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl unaryop_neg (Type) UnaryOp) +(rule (unaryop_neg $I8) (UnaryOp.Neg32)) +(rule (unaryop_neg $I16) (UnaryOp.Neg32)) +(rule (unaryop_neg $I32) (UnaryOp.Neg32)) +(rule (unaryop_neg $I64) (UnaryOp.Neg64)) + +(decl unaryop_neg_sext32 (Type) UnaryOp) +(rule (unaryop_neg_sext32 $I64) (UnaryOp.Neg64Ext32)) + +(decl neg_reg (Type Reg) Reg) +(rule (neg_reg ty x) (unary_rr ty (unaryop_neg ty) x)) + +(decl neg_reg_sext32 (Type Reg) Reg) +(rule (neg_reg_sext32 ty x) (unary_rr ty (unaryop_neg_sext32 ty) x)) + +(decl vecop_neg (Type) VecUnaryOp) +(rule (vecop_neg $I8X16) (VecUnaryOp.Neg8x16)) +(rule (vecop_neg $I16X8) (VecUnaryOp.Neg16x8)) +(rule (vecop_neg $I32X4) (VecUnaryOp.Neg32x4)) +(rule (vecop_neg $I64X2) (VecUnaryOp.Neg64x2)) + +(decl vec_neg (Type Reg) Reg) +(rule (vec_neg ty x) (vec_rr ty (vecop_neg ty) x)) + + +;; Helpers for generating `bswap` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl unaryop_bswap (Type) UnaryOp) +(rule (unaryop_bswap $I32) (UnaryOp.BSwap32)) +(rule (unaryop_bswap $I64) (UnaryOp.BSwap64)) + +(decl bswap_reg (Type Reg) Reg) +(rule (bswap_reg ty x) (unary_rr ty (unaryop_bswap ty) x)) + +(decl push_bswap_reg (VecMInstBuilder Type WritableReg Reg) Reg) +(rule (push_bswap_reg ib ty dst src) (push_unary ib (unaryop_bswap ty) dst src)) + + +;; Helpers for generating `rot` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl shiftop_rot (Type) ShiftOp) +(rule (shiftop_rot $I32) (ShiftOp.RotL32)) +(rule (shiftop_rot $I64) (ShiftOp.RotL64)) + +(decl rot_reg (Type Reg Reg) Reg) +(rule (rot_reg ty x shift_reg) + (shift_rr ty (shiftop_rot ty) x 0 shift_reg)) + +(decl rot_imm (Type Reg u8) Reg) +(rule (rot_imm ty x shift_imm) + (shift_rr ty (shiftop_rot ty) x shift_imm (zero_reg))) + +(decl rot_imm_reg (Type Reg u8 Reg) Reg) +(rule (rot_imm_reg ty x shift_imm shift_reg) + (shift_rr ty (shiftop_rot ty) x shift_imm shift_reg)) + +(decl push_rot_imm_reg (VecMInstBuilder Type WritableReg Reg u8 Reg) Reg) +(rule (push_rot_imm_reg ib ty dst src shift_imm shift_reg) + (push_shift ib (shiftop_rot ty) dst src shift_imm shift_reg)) + +(decl vec_shiftop_rot (Type) VecShiftOp) +(rule (vec_shiftop_rot $I8X16) (VecShiftOp.RotL8x16)) +(rule (vec_shiftop_rot $I16X8) (VecShiftOp.RotL16x8)) +(rule (vec_shiftop_rot $I32X4) (VecShiftOp.RotL32x4)) +(rule (vec_shiftop_rot $I64X2) (VecShiftOp.RotL64x2)) + +(decl vec_rot_reg (Type Reg Reg) Reg) +(rule (vec_rot_reg ty x shift_reg) + (vec_shift_rr ty (vec_shiftop_rot ty) x 0 shift_reg)) + +(decl vec_rot_imm (Type Reg u8) Reg) +(rule (vec_rot_imm ty x shift_imm) + (vec_shift_rr ty (vec_shiftop_rot ty) x shift_imm (zero_reg))) + + +;; Helpers for generating `lshl` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl shiftop_lshl (Type) ShiftOp) +(rule (shiftop_lshl $I8) (ShiftOp.LShL32)) +(rule (shiftop_lshl $I16) (ShiftOp.LShL32)) +(rule (shiftop_lshl $I32) (ShiftOp.LShL32)) +(rule (shiftop_lshl $I64) (ShiftOp.LShL64)) + +(decl lshl_reg (Type Reg Reg) Reg) +(rule (lshl_reg ty x shift_reg) + (shift_rr ty (shiftop_lshl ty) x 0 shift_reg)) + +(decl lshl_imm (Type Reg u8) Reg) +(rule (lshl_imm ty x shift_imm) + (shift_rr ty (shiftop_lshl ty) x shift_imm (zero_reg))) + +(decl vec_shiftop_lshl (Type) VecShiftOp) +(rule (vec_shiftop_lshl $I8X16) (VecShiftOp.LShL8x16)) +(rule (vec_shiftop_lshl $I16X8) (VecShiftOp.LShL16x8)) +(rule (vec_shiftop_lshl $I32X4) (VecShiftOp.LShL32x4)) +(rule (vec_shiftop_lshl $I64X2) (VecShiftOp.LShL64x2)) + +(decl vec_lshl_reg (Type Reg Reg) Reg) +(rule (vec_lshl_reg ty x shift_reg) + (vec_shift_rr ty (vec_shiftop_lshl ty) x 0 shift_reg)) + +(decl vec_lshl_imm (Type Reg u8) Reg) +(rule (vec_lshl_imm ty x shift_imm) + (vec_shift_rr ty (vec_shiftop_lshl ty) x shift_imm (zero_reg))) + +(decl vec_lshl_by_byte (Reg Reg) Reg) +(rule (vec_lshl_by_byte x y) (vec_rrr $I8X16 (VecBinaryOp.LShLByByte128) x y)) + +(decl vec_lshl_by_bit (Reg Reg) Reg) +(rule (vec_lshl_by_bit x y) (vec_rrr $I8X16 (VecBinaryOp.LShLByBit128) x y)) + + +;; Helpers for generating `lshr` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl shiftop_lshr (Type) ShiftOp) +(rule (shiftop_lshr $I32) (ShiftOp.LShR32)) +(rule (shiftop_lshr $I64) (ShiftOp.LShR64)) + +(decl lshr_reg (Type Reg Reg) Reg) +(rule (lshr_reg ty x shift_reg) + (shift_rr ty (shiftop_lshr ty) x 0 shift_reg)) + +(decl lshr_imm (Type Reg u8) Reg) +(rule (lshr_imm ty x shift_imm) + (shift_rr ty (shiftop_lshr ty) x shift_imm (zero_reg))) + +(decl vec_shiftop_lshr (Type) VecShiftOp) +(rule (vec_shiftop_lshr $I8X16) (VecShiftOp.LShR8x16)) +(rule (vec_shiftop_lshr $I16X8) (VecShiftOp.LShR16x8)) +(rule (vec_shiftop_lshr $I32X4) (VecShiftOp.LShR32x4)) +(rule (vec_shiftop_lshr $I64X2) (VecShiftOp.LShR64x2)) + +(decl vec_lshr_reg (Type Reg Reg) Reg) +(rule (vec_lshr_reg ty x shift_reg) + (vec_shift_rr ty (vec_shiftop_lshr ty) x 0 shift_reg)) + +(decl vec_lshr_imm (Type Reg u8) Reg) +(rule (vec_lshr_imm ty x shift_imm) + (vec_shift_rr ty (vec_shiftop_lshr ty) x shift_imm (zero_reg))) + +(decl vec_lshr_by_byte (Reg Reg) Reg) +(rule (vec_lshr_by_byte x y) (vec_rrr $I8X16 (VecBinaryOp.LShRByByte128) x y)) + +(decl vec_lshr_by_bit (Reg Reg) Reg) +(rule (vec_lshr_by_bit x y) (vec_rrr $I8X16 (VecBinaryOp.LShRByBit128) x y)) + + +;; Helpers for generating `ashr` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl shiftop_ashr (Type) ShiftOp) +(rule (shiftop_ashr $I32) (ShiftOp.AShR32)) +(rule (shiftop_ashr $I64) (ShiftOp.AShR64)) + +(decl ashr_reg (Type Reg Reg) Reg) +(rule (ashr_reg ty x shift_reg) + (shift_rr ty (shiftop_ashr ty) x 0 shift_reg)) + +(decl ashr_imm (Type Reg u8) Reg) +(rule (ashr_imm ty x shift_imm) + (shift_rr ty (shiftop_ashr ty) x shift_imm (zero_reg))) + +(decl vec_shiftop_ashr (Type) VecShiftOp) +(rule (vec_shiftop_ashr $I8X16) (VecShiftOp.AShR8x16)) +(rule (vec_shiftop_ashr $I16X8) (VecShiftOp.AShR16x8)) +(rule (vec_shiftop_ashr $I32X4) (VecShiftOp.AShR32x4)) +(rule (vec_shiftop_ashr $I64X2) (VecShiftOp.AShR64x2)) + +(decl vec_ashr_reg (Type Reg Reg) Reg) +(rule (vec_ashr_reg ty x shift_reg) + (vec_shift_rr ty (vec_shiftop_ashr ty) x 0 shift_reg)) + +(decl vec_ashr_imm (Type Reg u8) Reg) +(rule (vec_ashr_imm ty x shift_imm) + (vec_shift_rr ty (vec_shiftop_ashr ty) x shift_imm (zero_reg))) + +(decl vec_ashr_by_byte (Reg Reg) Reg) +(rule (vec_ashr_by_byte x y) (vec_rrr $I8X16 (VecBinaryOp.AShRByByte128) x y)) + +(decl vec_ashr_by_bit (Reg Reg) Reg) +(rule (vec_ashr_by_bit x y) (vec_rrr $I8X16 (VecBinaryOp.AShRByBit128) x y)) + + +;; Helpers for generating `popcnt` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl popcnt_byte (Reg) Reg) +(rule (popcnt_byte x) (unary_rr $I64 (UnaryOp.PopcntByte) x)) + +(decl popcnt_reg (Reg) Reg) +(rule (popcnt_reg x) (unary_rr $I64 (UnaryOp.PopcntReg) x)) + +(decl vecop_popcnt (Type) VecUnaryOp) +(rule (vecop_popcnt $I8X16) (VecUnaryOp.Popcnt8x16)) +(rule (vecop_popcnt $I16X8) (VecUnaryOp.Popcnt16x8)) +(rule (vecop_popcnt $I32X4) (VecUnaryOp.Popcnt32x4)) +(rule (vecop_popcnt $I64X2) (VecUnaryOp.Popcnt64x2)) + +(decl vec_popcnt (Type Reg) Reg) +(rule (vec_popcnt ty x) (vec_rr ty (vecop_popcnt ty) x)) + + +;; Helpers for generating `atomic_rmw` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl atomic_rmw_and (Type Reg MemArg) Reg) +(rule (atomic_rmw_and $I32 src mem) (atomic_rmw_impl $I32 (ALUOp.And32) src mem)) +(rule (atomic_rmw_and $I64 src mem) (atomic_rmw_impl $I64 (ALUOp.And64) src mem)) + +(decl atomic_rmw_or (Type Reg MemArg) Reg) +(rule (atomic_rmw_or $I32 src mem) (atomic_rmw_impl $I32 (ALUOp.Orr32) src mem)) +(rule (atomic_rmw_or $I64 src mem) (atomic_rmw_impl $I64 (ALUOp.Orr64) src mem)) + +(decl atomic_rmw_xor (Type Reg MemArg) Reg) +(rule (atomic_rmw_xor $I32 src mem) (atomic_rmw_impl $I32 (ALUOp.Xor32) src mem)) +(rule (atomic_rmw_xor $I64 src mem) (atomic_rmw_impl $I64 (ALUOp.Xor64) src mem)) + +(decl atomic_rmw_add (Type Reg MemArg) Reg) +(rule (atomic_rmw_add $I32 src mem) (atomic_rmw_impl $I32 (ALUOp.Add32) src mem)) +(rule (atomic_rmw_add $I64 src mem) (atomic_rmw_impl $I64 (ALUOp.Add64) src mem)) + + +;; Helpers for generating `atomic_cas` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl atomic_cas_impl (Type Reg Reg MemArg) Reg) +(rule (atomic_cas_impl $I32 src1 src2 mem) (atomic_cas32 src1 src2 mem)) +(rule (atomic_cas_impl $I64 src1 src2 mem) (atomic_cas64 src1 src2 mem)) + +(decl push_atomic_cas (VecMInstBuilder Type WritableReg Reg MemArg) Reg) +(rule (push_atomic_cas ib $I32 src1 src2 mem) (push_atomic_cas32 ib src1 src2 mem)) +(rule (push_atomic_cas ib $I64 src1 src2 mem) (push_atomic_cas64 ib src1 src2 mem)) + + +;; Helpers for generating `fadd` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_add (Type) FPUOp2) +(rule (fpuop2_add $F32) (FPUOp2.Add32)) +(rule (fpuop2_add $F64) (FPUOp2.Add64)) +(rule (fpuop2_add $F32X4) (FPUOp2.Add32x4)) +(rule (fpuop2_add $F64X2) (FPUOp2.Add64x2)) + +(decl fadd_reg (Type Reg Reg) Reg) +(rule (fadd_reg ty x y) (fpu_rrr ty (fpuop2_add ty) x y)) + + +;; Helpers for generating `fsub` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_sub (Type) FPUOp2) +(rule (fpuop2_sub $F32) (FPUOp2.Sub32)) +(rule (fpuop2_sub $F64) (FPUOp2.Sub64)) +(rule (fpuop2_sub $F32X4) (FPUOp2.Sub32x4)) +(rule (fpuop2_sub $F64X2) (FPUOp2.Sub64x2)) + +(decl fsub_reg (Type Reg Reg) Reg) +(rule (fsub_reg ty x y) (fpu_rrr ty (fpuop2_sub ty) x y)) + + +;; Helpers for generating `fmul` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_mul (Type) FPUOp2) +(rule (fpuop2_mul $F32) (FPUOp2.Mul32)) +(rule (fpuop2_mul $F64) (FPUOp2.Mul64)) +(rule (fpuop2_mul $F32X4) (FPUOp2.Mul32x4)) +(rule (fpuop2_mul $F64X2) (FPUOp2.Mul64x2)) + +(decl fmul_reg (Type Reg Reg) Reg) +(rule (fmul_reg ty x y) (fpu_rrr ty (fpuop2_mul ty) x y)) + + +;; Helpers for generating `fdiv` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_div (Type) FPUOp2) +(rule (fpuop2_div $F32) (FPUOp2.Div32)) +(rule (fpuop2_div $F64) (FPUOp2.Div64)) +(rule (fpuop2_div $F32X4) (FPUOp2.Div32x4)) +(rule (fpuop2_div $F64X2) (FPUOp2.Div64x2)) + +(decl fdiv_reg (Type Reg Reg) Reg) +(rule (fdiv_reg ty x y) (fpu_rrr ty (fpuop2_div ty) x y)) + + +;; Helpers for generating `fmin` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_min (Type) FPUOp2) +(rule (fpuop2_min $F32) (FPUOp2.Min32)) +(rule (fpuop2_min $F64) (FPUOp2.Min64)) +(rule (fpuop2_min $F32X4) (FPUOp2.Min32x4)) +(rule (fpuop2_min $F64X2) (FPUOp2.Min64x2)) + +(decl fmin_reg (Type Reg Reg) Reg) +(rule (fmin_reg ty x y) (fpu_rrr ty (fpuop2_min ty) x y)) + + +;; Helpers for generating `fmax` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_max (Type) FPUOp2) +(rule (fpuop2_max $F32) (FPUOp2.Max32)) +(rule (fpuop2_max $F64) (FPUOp2.Max64)) +(rule (fpuop2_max $F32X4) (FPUOp2.Max32x4)) +(rule (fpuop2_max $F64X2) (FPUOp2.Max64x2)) + +(decl fmax_reg (Type Reg Reg) Reg) +(rule (fmax_reg ty x y) (fpu_rrr ty (fpuop2_max ty) x y)) + + +;; Helpers for generating `fmin_pseudo` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_min_pseudo (Type) FPUOp2) +(rule (fpuop2_min_pseudo $F32) (FPUOp2.MinPseudo32)) +(rule (fpuop2_min_pseudo $F64) (FPUOp2.MinPseudo64)) +(rule (fpuop2_min_pseudo $F32X4) (FPUOp2.MinPseudo32x4)) +(rule (fpuop2_min_pseudo $F64X2) (FPUOp2.MinPseudo64x2)) + +(decl fmin_pseudo_reg (Type Reg Reg) Reg) +(rule (fmin_pseudo_reg ty x y) (fpu_rrr ty (fpuop2_min_pseudo ty) x y)) + + +;; Helpers for generating `fmax_pseudo` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop2_max_pseudo (Type) FPUOp2) +(rule (fpuop2_max_pseudo $F32) (FPUOp2.MaxPseudo32)) +(rule (fpuop2_max_pseudo $F64) (FPUOp2.MaxPseudo64)) +(rule (fpuop2_max_pseudo $F32X4) (FPUOp2.MaxPseudo32x4)) +(rule (fpuop2_max_pseudo $F64X2) (FPUOp2.MaxPseudo64x2)) + +(decl fmax_pseudo_reg (Type Reg Reg) Reg) +(rule (fmax_pseudo_reg ty x y) (fpu_rrr ty (fpuop2_max_pseudo ty) x y)) + + +;; Helpers for generating `fma` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop3_fma (Type) FPUOp3) +(rule (fpuop3_fma $F32) (FPUOp3.MAdd32)) +(rule (fpuop3_fma $F64) (FPUOp3.MAdd64)) +(rule (fpuop3_fma $F32X4) (FPUOp3.MAdd32x4)) +(rule (fpuop3_fma $F64X2) (FPUOp3.MAdd64x2)) + +(decl fma_reg (Type Reg Reg Reg) Reg) +(rule (fma_reg ty x y acc) (fpu_rrrr ty (fpuop3_fma ty) x y acc)) + + +;; Helpers for generating `sqrt` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop1_sqrt (Type) FPUOp1) +(rule (fpuop1_sqrt $F32) (FPUOp1.Sqrt32)) +(rule (fpuop1_sqrt $F64) (FPUOp1.Sqrt64)) +(rule (fpuop1_sqrt $F32X4) (FPUOp1.Sqrt32x4)) +(rule (fpuop1_sqrt $F64X2) (FPUOp1.Sqrt64x2)) + +(decl sqrt_reg (Type Reg) Reg) +(rule (sqrt_reg ty x) (fpu_rr ty (fpuop1_sqrt ty) x)) + + +;; Helpers for generating `fneg` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop1_neg (Type) FPUOp1) +(rule (fpuop1_neg $F32) (FPUOp1.Neg32)) +(rule (fpuop1_neg $F64) (FPUOp1.Neg64)) +(rule (fpuop1_neg $F32X4) (FPUOp1.Neg32x4)) +(rule (fpuop1_neg $F64X2) (FPUOp1.Neg64x2)) + +(decl fneg_reg (Type Reg) Reg) +(rule (fneg_reg ty x) (fpu_rr ty (fpuop1_neg ty) x)) + + +;; Helpers for generating `fabs` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpuop1_abs (Type) FPUOp1) +(rule (fpuop1_abs $F32) (FPUOp1.Abs32)) +(rule (fpuop1_abs $F64) (FPUOp1.Abs64)) +(rule (fpuop1_abs $F32X4) (FPUOp1.Abs32x4)) +(rule (fpuop1_abs $F64X2) (FPUOp1.Abs64x2)) + +(decl fabs_reg (Type Reg) Reg) +(rule (fabs_reg ty x) (fpu_rr ty (fpuop1_abs ty) x)) + + +;; Helpers for generating `ceil`, `floor`, `trunc`, `nearest` instructions ;;;; + +(decl fpuroundop_round (Type) FpuRoundOp) +(rule (fpuroundop_round $F32) (FpuRoundOp.Round32)) +(rule (fpuroundop_round $F64) (FpuRoundOp.Round64)) +(rule (fpuroundop_round $F32X4) (FpuRoundOp.Round32x4)) +(rule (fpuroundop_round $F64X2) (FpuRoundOp.Round64x2)) + +(decl ceil_reg (Type Reg) Reg) +(rule (ceil_reg ty x) (fpu_round ty (fpuroundop_round ty) + (FpuRoundMode.ToPosInfinity) x)) + +(decl floor_reg (Type Reg) Reg) +(rule (floor_reg ty x) (fpu_round ty (fpuroundop_round ty) + (FpuRoundMode.ToNegInfinity) x)) + +(decl trunc_reg (Type Reg) Reg) +(rule (trunc_reg ty x) (fpu_round ty (fpuroundop_round ty) + (FpuRoundMode.ToZero) x)) + +(decl nearest_reg (Type Reg) Reg) +(rule (nearest_reg ty x) (fpu_round ty (fpuroundop_round ty) + (FpuRoundMode.ToNearestTiesToEven) x)) + + +;; Helpers for generating `fpromote` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fpromote_reg (Type Type Reg) Reg) +(rule 1 (fpromote_reg ty ty x) x) +(rule (fpromote_reg $F64 $F32 x) + (fpu_rr $F64 (FPUOp1.Cvt32To64) x)) +(rule (fpromote_reg $F64X2 $F32X4 x) + (fpu_rr $F64 (FPUOp1.Cvt32x4To64x2) x)) + + +;; Helpers for generating `fdemote` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fdemote_reg (Type Type FpuRoundMode Reg) Reg) +(rule 1 (fdemote_reg ty ty mode x) x) +(rule (fdemote_reg $F32 $F64 mode x) + (fpu_round $F32 (FpuRoundOp.Cvt64To32) mode x)) +(rule (fdemote_reg $F32X4 $F64X2 mode x) + (fpu_round $F32X4 (FpuRoundOp.Cvt64x2To32x4) mode x)) + + +;; Helpers for generating `fcvt_from_uint` instructions ;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcvt_from_uint_reg (Type FpuRoundMode Reg) Reg) +(rule (fcvt_from_uint_reg $F32 mode x) + (fpu_round $F32 (FpuRoundOp.FromUInt32) mode (vec_insert_lane_undef $I32X4 x 0 (zero_reg)))) +(rule (fcvt_from_uint_reg $F64 mode x) + (fpu_round $F64 (FpuRoundOp.FromUInt64) mode (vec_insert_lane_undef $I64X2 x 0 (zero_reg)))) +(rule (fcvt_from_uint_reg $F32X4 mode x) + (fpu_round $F32X4 (FpuRoundOp.FromUInt32x4) mode x)) +(rule (fcvt_from_uint_reg $F64X2 mode x) + (fpu_round $F64X2 (FpuRoundOp.FromUInt64x2) mode x)) + + +;; Helpers for generating `fcvt_from_sint` instructions ;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcvt_from_sint_reg (Type FpuRoundMode Reg) Reg) +(rule (fcvt_from_sint_reg $F32 mode x) + (fpu_round $F32 (FpuRoundOp.FromSInt32) mode (vec_insert_lane_undef $I32X4 x 0 (zero_reg)))) +(rule (fcvt_from_sint_reg $F64 mode x) + (fpu_round $F64 (FpuRoundOp.FromSInt64) mode (vec_insert_lane_undef $I64X2 x 0 (zero_reg)))) +(rule (fcvt_from_sint_reg $F32X4 mode x) + (fpu_round $F32X4 (FpuRoundOp.FromSInt32x4) mode x)) +(rule (fcvt_from_sint_reg $F64X2 mode x) + (fpu_round $F64X2 (FpuRoundOp.FromSInt64x2) mode x)) + + +;; Helpers for generating `fcvt_to_[us]int` instructions ;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcvt_flt_ty (Type Type) Type) +(rule 1 (fcvt_flt_ty (fits_in_32 ty) (and (vxrs_ext2_enabled) $F32)) $F32) +(rule (fcvt_flt_ty (fits_in_64 ty) $F32) $F64) +(rule (fcvt_flt_ty (fits_in_64 ty) $F64) $F64) + +(decl fcvt_int_ty (Type Type) Type) +(rule 1 (fcvt_int_ty (fits_in_32 ty) (and (vxrs_ext2_enabled) $F32)) $I32) +(rule (fcvt_int_ty (fits_in_64 ty) $F32) $I64) +(rule (fcvt_int_ty (fits_in_64 ty) $F64) $I64) + + +;; Helpers for generating `fcvt_to_uint` instructions ;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcvt_to_uint_reg (Type FpuRoundMode Reg) Reg) +(rule (fcvt_to_uint_reg $F32 mode x) + (vec_extract_lane $I32X4 (fpu_round $F32 (FpuRoundOp.ToUInt32) mode x) 0 (zero_reg))) +(rule (fcvt_to_uint_reg $F64 mode x) + (vec_extract_lane $I64X2 (fpu_round $F64 (FpuRoundOp.ToUInt64) mode x) 0 (zero_reg))) +(rule (fcvt_to_uint_reg $F32X4 mode x) + (fpu_round $F32X4 (FpuRoundOp.ToUInt32x4) mode x)) +(rule (fcvt_to_uint_reg $F64X2 mode x) + (fpu_round $F64X2 (FpuRoundOp.ToUInt64x2) mode x)) + +(decl fcvt_to_uint_ub (Type Type) Reg) +(rule (fcvt_to_uint_ub $F32 dst_ty) + (imm $F32 (fcvt_to_uint_ub32 (ty_bits dst_ty)))) +(rule (fcvt_to_uint_ub $F64 dst_ty) + (imm $F64 (fcvt_to_uint_ub64 (ty_bits dst_ty)))) + +(decl fcvt_to_uint_lb (Type) Reg) +(rule (fcvt_to_uint_lb $F32) (imm $F32 (fcvt_to_uint_lb32))) +(rule (fcvt_to_uint_lb $F64) (imm $F64 (fcvt_to_uint_lb64))) + +(decl fcvt_to_uint_ub32 (u8) u64) +(extern constructor fcvt_to_uint_ub32 fcvt_to_uint_ub32) +(decl fcvt_to_uint_lb32 () u64) +(extern constructor fcvt_to_uint_lb32 fcvt_to_uint_lb32) +(decl fcvt_to_uint_ub64 (u8) u64) +(extern constructor fcvt_to_uint_ub64 fcvt_to_uint_ub64) +(decl fcvt_to_uint_lb64 () u64) +(extern constructor fcvt_to_uint_lb64 fcvt_to_uint_lb64) + + +;; Helpers for generating `fcvt_to_sint` instructions ;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcvt_to_sint_reg (Type FpuRoundMode Reg) Reg) +(rule (fcvt_to_sint_reg $F32 mode x) + (vec_extract_lane $F32X4 (fpu_round $F32 (FpuRoundOp.ToSInt32) mode x) 0 (zero_reg))) +(rule (fcvt_to_sint_reg $F64 mode x) + (vec_extract_lane $F64X2 (fpu_round $F64 (FpuRoundOp.ToSInt64) mode x) 0 (zero_reg))) +(rule (fcvt_to_sint_reg $F32X4 mode x) + (fpu_round $F32X4 (FpuRoundOp.ToSInt32x4) mode x)) +(rule (fcvt_to_sint_reg $F64X2 mode x) + (fpu_round $F64X2 (FpuRoundOp.ToSInt64x2) mode x)) + +(decl fcvt_to_sint_ub (Type Type) Reg) +(rule (fcvt_to_sint_ub $F32 dst_ty) + (imm $F32 (fcvt_to_sint_ub32 (ty_bits dst_ty)))) +(rule (fcvt_to_sint_ub $F64 dst_ty) + (imm $F64 (fcvt_to_sint_ub64 (ty_bits dst_ty)))) + +(decl fcvt_to_sint_lb (Type Type) Reg) +(rule (fcvt_to_sint_lb $F32 dst_ty) + (imm $F32 (fcvt_to_sint_lb32 (ty_bits dst_ty)))) +(rule (fcvt_to_sint_lb $F64 dst_ty) + (imm $F64 (fcvt_to_sint_lb64 (ty_bits dst_ty)))) + +(decl fcvt_to_sint_ub32 (u8) u64) +(extern constructor fcvt_to_sint_ub32 fcvt_to_sint_ub32) +(decl fcvt_to_sint_lb32 (u8) u64) +(extern constructor fcvt_to_sint_lb32 fcvt_to_sint_lb32) +(decl fcvt_to_sint_ub64 (u8) u64) +(extern constructor fcvt_to_sint_ub64 fcvt_to_sint_ub64) +(decl fcvt_to_sint_lb64 (u8) u64) +(extern constructor fcvt_to_sint_lb64 fcvt_to_sint_lb64) + + +;; Helpers for generating signed `icmp` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl cmpop_cmps (Type) CmpOp) +(rule (cmpop_cmps $I32) (CmpOp.CmpS32)) +(rule (cmpop_cmps $I64) (CmpOp.CmpS64)) + +(decl cmpop_cmps_sext16 (Type) CmpOp) +(rule (cmpop_cmps_sext16 $I32) (CmpOp.CmpS32Ext16)) +(rule (cmpop_cmps_sext16 $I64) (CmpOp.CmpS64Ext16)) + +(decl cmpop_cmps_sext32 (Type) CmpOp) +(rule (cmpop_cmps_sext32 $I64) (CmpOp.CmpS64Ext32)) + +(decl icmps_reg (Type Reg Reg) ProducesFlags) +(rule (icmps_reg ty src1 src2) (cmp_rr (cmpop_cmps ty) src1 src2)) + +(decl icmps_reg_sext32 (Type Reg Reg) ProducesFlags) +(rule (icmps_reg_sext32 ty src1 src2) (cmp_rr (cmpop_cmps_sext32 ty) src1 src2)) + +(decl icmps_simm16 (Type Reg i16) ProducesFlags) +(rule (icmps_simm16 ty src imm) (cmp_rsimm16 (cmpop_cmps ty) src imm)) + +(decl icmps_simm32 (Type Reg i32) ProducesFlags) +(rule (icmps_simm32 ty src imm) (cmp_rsimm32 (cmpop_cmps ty) src imm)) + +(decl icmps_mem (Type Reg MemArg) ProducesFlags) +(rule (icmps_mem ty src mem) (cmp_rx (cmpop_cmps ty) src mem)) + +(decl icmps_mem_sext16 (Type Reg MemArg) ProducesFlags) +(rule (icmps_mem_sext16 ty src mem) (cmp_rx (cmpop_cmps_sext16 ty) src mem)) + +(decl icmps_mem_sext32 (Type Reg MemArg) ProducesFlags) +(rule (icmps_mem_sext32 ty src mem) (cmp_rx (cmpop_cmps_sext32 ty) src mem)) + + +;; Helpers for generating unsigned `icmp` instructions ;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl cmpop_cmpu (Type) CmpOp) +(rule (cmpop_cmpu $I32) (CmpOp.CmpL32)) +(rule (cmpop_cmpu $I64) (CmpOp.CmpL64)) + +(decl cmpop_cmpu_zext16 (Type) CmpOp) +(rule (cmpop_cmpu_zext16 $I32) (CmpOp.CmpL32Ext16)) +(rule (cmpop_cmpu_zext16 $I64) (CmpOp.CmpL64Ext16)) + +(decl cmpop_cmpu_zext32 (Type) CmpOp) +(rule (cmpop_cmpu_zext32 $I64) (CmpOp.CmpL64Ext32)) + +(decl icmpu_reg (Type Reg Reg) ProducesFlags) +(rule (icmpu_reg ty src1 src2) (cmp_rr (cmpop_cmpu ty) src1 src2)) + +(decl icmpu_reg_zext32 (Type Reg Reg) ProducesFlags) +(rule (icmpu_reg_zext32 ty src1 src2) (cmp_rr (cmpop_cmpu_zext32 ty) src1 src2)) + +(decl icmpu_uimm32 (Type Reg u32) ProducesFlags) +(rule (icmpu_uimm32 ty src imm) (cmp_ruimm32 (cmpop_cmpu ty) src imm)) + +(decl icmpu_mem (Type Reg MemArg) ProducesFlags) +(rule (icmpu_mem ty src mem) (cmp_rx (cmpop_cmpu ty) src mem)) + +(decl icmpu_mem_zext16 (Type Reg MemArg) ProducesFlags) +(rule (icmpu_mem_zext16 ty src mem) (cmp_rx (cmpop_cmpu_zext16 ty) src mem)) + +(decl icmpu_mem_zext32 (Type Reg MemArg) ProducesFlags) +(rule (icmpu_mem_zext32 ty src mem) (cmp_rx (cmpop_cmpu_zext32 ty) src mem)) + + +;; Helpers for generating vector `icmp` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_int_cmpeq (Type) VecIntCmpOp) +(rule (vecop_int_cmpeq (multi_lane 8 16)) (VecIntCmpOp.CmpEq8x16)) +(rule (vecop_int_cmpeq (multi_lane 16 8)) (VecIntCmpOp.CmpEq16x8)) +(rule (vecop_int_cmpeq (multi_lane 32 4)) (VecIntCmpOp.CmpEq32x4)) +(rule (vecop_int_cmpeq (multi_lane 64 2)) (VecIntCmpOp.CmpEq64x2)) + +(decl vec_cmpeq (Type Reg Reg) Reg) +(rule (vec_cmpeq (ty_vec128 ty) x y) (vec_int_cmp ty (vecop_int_cmpeq ty) x y)) +(decl vec_cmpeqs (Type Reg Reg) ProducesFlags) +(rule (vec_cmpeqs (ty_vec128 ty) x y) (vec_int_cmps ty (vecop_int_cmpeq ty) x y)) + +(decl vecop_int_cmph (Type) VecIntCmpOp) +(rule (vecop_int_cmph (multi_lane 8 16)) (VecIntCmpOp.SCmpHi8x16)) +(rule (vecop_int_cmph (multi_lane 16 8)) (VecIntCmpOp.SCmpHi16x8)) +(rule (vecop_int_cmph (multi_lane 32 4)) (VecIntCmpOp.SCmpHi32x4)) +(rule (vecop_int_cmph (multi_lane 64 2)) (VecIntCmpOp.SCmpHi64x2)) + +(decl vec_cmph (Type Reg Reg) Reg) +(rule (vec_cmph (ty_vec128 ty) x y) (vec_int_cmp ty (vecop_int_cmph ty) x y)) +(decl vec_cmphs (Type Reg Reg) ProducesFlags) +(rule (vec_cmphs (ty_vec128 ty) x y) (vec_int_cmps ty (vecop_int_cmph ty) x y)) + +(decl vecop_int_cmphl (Type) VecIntCmpOp) +(rule (vecop_int_cmphl (multi_lane 8 16)) (VecIntCmpOp.UCmpHi8x16)) +(rule (vecop_int_cmphl (multi_lane 16 8)) (VecIntCmpOp.UCmpHi16x8)) +(rule (vecop_int_cmphl (multi_lane 32 4)) (VecIntCmpOp.UCmpHi32x4)) +(rule (vecop_int_cmphl (multi_lane 64 2)) (VecIntCmpOp.UCmpHi64x2)) + +(decl vec_cmphl (Type Reg Reg) Reg) +(rule (vec_cmphl (ty_vec128 ty) x y) (vec_int_cmp ty (vecop_int_cmphl ty) x y)) +(decl vec_cmphls (Type Reg Reg) ProducesFlags) +(rule (vec_cmphls (ty_vec128 ty) x y) (vec_int_cmps ty (vecop_int_cmphl ty) x y)) + + +;; Helpers for generating `fcmp` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl fcmp_reg (Type Reg Reg) ProducesFlags) +(rule (fcmp_reg $F32 src1 src2) (fpu_cmp32 src1 src2)) +(rule (fcmp_reg $F64 src1 src2) (fpu_cmp64 src1 src2)) + + +;; Helpers for generating vector `fcmp` instructions ;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl vecop_float_cmpeq (Type) VecFloatCmpOp) +(rule (vecop_float_cmpeq (multi_lane 32 4)) (VecFloatCmpOp.CmpEq32x4)) +(rule (vecop_float_cmpeq (multi_lane 64 2)) (VecFloatCmpOp.CmpEq64x2)) + +(decl vec_fcmpeq (Type Reg Reg) Reg) +(rule (vec_fcmpeq (ty_vec128 ty) x y) (vec_float_cmp ty (vecop_float_cmpeq ty) x y)) +(decl vec_fcmpeqs (Type Reg Reg) ProducesFlags) +(rule (vec_fcmpeqs (ty_vec128 ty) x y) (vec_float_cmps ty (vecop_float_cmpeq ty) x y)) + +(decl vecop_float_cmph (Type) VecFloatCmpOp) +(rule (vecop_float_cmph (multi_lane 32 4)) (VecFloatCmpOp.CmpHi32x4)) +(rule (vecop_float_cmph (multi_lane 64 2)) (VecFloatCmpOp.CmpHi64x2)) + +(decl vec_fcmph (Type Reg Reg) Reg) +(rule (vec_fcmph (ty_vec128 ty) x y) (vec_float_cmp ty (vecop_float_cmph ty) x y)) +(decl vec_fcmphs (Type Reg Reg) ProducesFlags) +(rule (vec_fcmphs (ty_vec128 ty) x y) (vec_float_cmps ty (vecop_float_cmph ty) x y)) + +(decl vecop_float_cmphe (Type) VecFloatCmpOp) +(rule (vecop_float_cmphe (multi_lane 32 4)) (VecFloatCmpOp.CmpHiEq32x4)) +(rule (vecop_float_cmphe (multi_lane 64 2)) (VecFloatCmpOp.CmpHiEq64x2)) + +(decl vec_fcmphe (Type Reg Reg) Reg) +(rule (vec_fcmphe (ty_vec128 ty) x y) (vec_float_cmp ty (vecop_float_cmphe ty) x y)) +(decl vec_fcmphes (Type Reg Reg) ProducesFlags) +(rule (vec_fcmphes (ty_vec128 ty) x y) (vec_float_cmps ty (vecop_float_cmphe ty) x y)) + + +;; Implicit conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(convert WritableRegPair RegPair writable_regpair_to_regpair) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/args.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/args.rs new file mode 100644 index 00000000000000..5134f9bd397ffa --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/args.rs @@ -0,0 +1,275 @@ +//! S390x ISA definitions: instruction arguments. + +use crate::ir::condcodes::{FloatCC, IntCC}; +use crate::ir::MemFlags; +use crate::isa::s390x::inst::*; + +//============================================================================= +// Instruction sub-components (memory addresses): definitions + +/// A memory argument to load/store, encapsulating the possible addressing modes. +#[derive(Clone, Debug)] +pub enum MemArg { + // + // Real IBM Z addressing modes: + // + /// Base register, index register, and 12-bit unsigned displacement. + BXD12 { + base: Reg, + index: Reg, + disp: UImm12, + flags: MemFlags, + }, + + /// Base register, index register, and 20-bit signed displacement. + BXD20 { + base: Reg, + index: Reg, + disp: SImm20, + flags: MemFlags, + }, + + /// PC-relative Reference to a label. + Label { target: MachLabel }, + + /// PC-relative Reference to a near symbol. + Symbol { + name: Box, + offset: i32, + flags: MemFlags, + }, + + // + // Virtual addressing modes that are lowered at emission time: + // + /// Arbitrary offset from a register. Converted to generation of large + /// offsets with multiple instructions as necessary during code emission. + RegOffset { reg: Reg, off: i64, flags: MemFlags }, + + /// Offset from the stack pointer at function entry. + InitialSPOffset { off: i64 }, + + /// Offset from the (nominal) stack pointer during this function. + NominalSPOffset { off: i64 }, + + /// Offset into the slot area of the stack, which lies just above the + /// outgoing argument area that's setup by the function prologue. + /// At emission time, this is converted to `SPOffset` with a fixup added to + /// the offset constant. The fixup is a running value that is tracked as + /// emission iterates through instructions in linear order, and can be + /// adjusted up and down with [Inst::VirtualSPOffsetAdj]. + /// + /// The standard ABI is in charge of handling this (by emitting the + /// adjustment meta-instructions). See the diagram in the documentation + /// for [crate::isa::aarch64::abi](the ABI module) for more details. + SlotOffset { off: i64 }, +} + +impl MemArg { + /// Memory reference using an address in a register. + pub fn reg(reg: Reg, flags: MemFlags) -> MemArg { + MemArg::BXD12 { + base: reg, + index: zero_reg(), + disp: UImm12::zero(), + flags, + } + } + + /// Memory reference using the sum of two registers as an address. + pub fn reg_plus_reg(reg1: Reg, reg2: Reg, flags: MemFlags) -> MemArg { + MemArg::BXD12 { + base: reg1, + index: reg2, + disp: UImm12::zero(), + flags, + } + } + + /// Memory reference using the sum of a register an an offset as address. + pub fn reg_plus_off(reg: Reg, off: i64, flags: MemFlags) -> MemArg { + MemArg::RegOffset { reg, off, flags } + } + + /// Add an offset to a virtual addressing mode. + pub fn offset(base: &MemArg, offset: i64) -> MemArg { + match base { + &MemArg::RegOffset { reg, off, flags } => MemArg::RegOffset { + reg, + off: off + offset, + flags, + }, + &MemArg::InitialSPOffset { off } => MemArg::InitialSPOffset { off: off + offset }, + &MemArg::NominalSPOffset { off } => MemArg::NominalSPOffset { off: off + offset }, + &MemArg::SlotOffset { off } => MemArg::SlotOffset { off: off + offset }, + // This routine is only defined for virtual addressing modes. + &MemArg::BXD12 { .. } + | &MemArg::BXD20 { .. } + | &MemArg::Label { .. } + | &MemArg::Symbol { .. } => unreachable!(), + } + } + + pub(crate) fn get_flags(&self) -> MemFlags { + match self { + MemArg::BXD12 { flags, .. } => *flags, + MemArg::BXD20 { flags, .. } => *flags, + MemArg::RegOffset { flags, .. } => *flags, + MemArg::Label { .. } => MemFlags::trusted(), + MemArg::Symbol { flags, .. } => *flags, + MemArg::InitialSPOffset { .. } => MemFlags::trusted(), + MemArg::NominalSPOffset { .. } => MemFlags::trusted(), + MemArg::SlotOffset { .. } => MemFlags::trusted(), + } + } +} + +//============================================================================= +// Instruction sub-components (conditions, branches and branch targets): +// definitions + +/// Condition for conditional branches. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Cond { + mask: u8, +} + +impl Cond { + pub fn from_mask(mask: u8) -> Cond { + assert!(mask >= 1 && mask <= 14); + Cond { mask } + } + + pub fn from_intcc(cc: IntCC) -> Cond { + let mask = match cc { + IntCC::Equal => 8, + IntCC::NotEqual => 4 | 2, + IntCC::SignedGreaterThanOrEqual => 8 | 2, + IntCC::SignedGreaterThan => 2, + IntCC::SignedLessThanOrEqual => 8 | 4, + IntCC::SignedLessThan => 4, + IntCC::UnsignedGreaterThanOrEqual => 8 | 2, + IntCC::UnsignedGreaterThan => 2, + IntCC::UnsignedLessThanOrEqual => 8 | 4, + IntCC::UnsignedLessThan => 4, + }; + Cond { mask } + } + + pub fn from_floatcc(cc: FloatCC) -> Cond { + let mask = match cc { + FloatCC::Ordered => 8 | 4 | 2, + FloatCC::Unordered => 1, + FloatCC::Equal => 8, + FloatCC::NotEqual => 4 | 2 | 1, + FloatCC::OrderedNotEqual => 4 | 2, + FloatCC::UnorderedOrEqual => 8 | 1, + FloatCC::LessThan => 4, + FloatCC::LessThanOrEqual => 8 | 4, + FloatCC::GreaterThan => 2, + FloatCC::GreaterThanOrEqual => 8 | 2, + FloatCC::UnorderedOrLessThan => 4 | 1, + FloatCC::UnorderedOrLessThanOrEqual => 8 | 4 | 1, + FloatCC::UnorderedOrGreaterThan => 2 | 1, + FloatCC::UnorderedOrGreaterThanOrEqual => 8 | 2 | 1, + }; + Cond { mask } + } + + /// Return the inverted condition. + pub fn invert(self) -> Cond { + Cond { + mask: !self.mask & 15, + } + } + + /// Return the machine encoding of this condition. + pub fn bits(self) -> u8 { + self.mask + } +} + +impl PrettyPrint for MemArg { + fn pretty_print(&self, _: u8) -> String { + match self { + &MemArg::BXD12 { + base, index, disp, .. + } => { + if base != zero_reg() { + if index != zero_reg() { + format!( + "{}({},{})", + disp.pretty_print_default(), + show_reg(index), + show_reg(base), + ) + } else { + format!("{}({})", disp.pretty_print_default(), show_reg(base)) + } + } else { + if index != zero_reg() { + format!("{}({},)", disp.pretty_print_default(), show_reg(index)) + } else { + format!("{}", disp.pretty_print_default()) + } + } + } + &MemArg::BXD20 { + base, index, disp, .. + } => { + if base != zero_reg() { + if index != zero_reg() { + format!( + "{}({},{})", + disp.pretty_print_default(), + show_reg(index), + show_reg(base), + ) + } else { + format!("{}({})", disp.pretty_print_default(), show_reg(base)) + } + } else { + if index != zero_reg() { + format!("{}({},)", disp.pretty_print_default(), show_reg(index)) + } else { + format!("{}", disp.pretty_print_default()) + } + } + } + &MemArg::Label { target } => target.to_string(), + &MemArg::Symbol { + ref name, offset, .. + } => format!("{} + {}", name.display(None), offset), + // Eliminated by `mem_finalize()`. + &MemArg::InitialSPOffset { .. } + | &MemArg::NominalSPOffset { .. } + | &MemArg::SlotOffset { .. } + | &MemArg::RegOffset { .. } => { + panic!("Unexpected pseudo mem-arg mode (stack-offset or generic reg-offset)!") + } + } + } +} + +impl PrettyPrint for Cond { + fn pretty_print(&self, _: u8) -> String { + let s = match self.mask { + 1 => "o", + 2 => "h", + 3 => "nle", + 4 => "l", + 5 => "nhe", + 6 => "lh", + 7 => "ne", + 8 => "e", + 9 => "nlh", + 10 => "he", + 11 => "nl", + 12 => "le", + 13 => "nh", + 14 => "no", + _ => unreachable!(), + }; + s.to_string() + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit.rs new file mode 100644 index 00000000000000..53d383ea535a97 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit.rs @@ -0,0 +1,3435 @@ +//! S390x ISA: binary code emission. + +use crate::ir::{self, LibCall, MemFlags, TrapCode}; +use crate::isa::s390x::inst::*; +use crate::isa::s390x::settings as s390x_settings; +use cranelift_control::ControlPlane; + +/// Debug macro for testing that a regpair is valid: that the high register is even, and the low +/// register is one higher than the high register. +macro_rules! debug_assert_valid_regpair { + ($hi:expr, $lo:expr) => { + if cfg!(debug_assertions) { + match ($hi.to_real_reg(), $lo.to_real_reg()) { + (Some(hi), Some(lo)) => { + assert!( + hi.hw_enc() % 2 == 0, + "High register is not even: {}", + show_reg($hi) + ); + assert_eq!( + hi.hw_enc() + 1, + lo.hw_enc(), + "Low register is not valid: {}, {}", + show_reg($hi), + show_reg($lo) + ); + } + + _ => { + panic!( + "Expected real registers for {} {}", + show_reg($hi), + show_reg($lo) + ); + } + } + } + }; +} + +/// Type(s) of memory instructions available for mem_finalize. +pub struct MemInstType { + /// True if 12-bit unsigned displacement is supported. + pub have_d12: bool, + /// True if 20-bit signed displacement is supported. + pub have_d20: bool, + /// True if PC-relative addressing is supported (memory access). + pub have_pcrel: bool, + /// True if PC-relative addressing is supported (load address). + pub have_unaligned_pcrel: bool, + /// True if an index register is supported. + pub have_index: bool, +} + +/// Memory addressing mode finalization: convert "special" modes (e.g., +/// generic arbitrary stack offset) into real addressing modes, possibly by +/// emitting some helper instructions that come immediately before the use +/// of this amode. +pub fn mem_finalize( + mem: &MemArg, + state: &EmitState, + mi: MemInstType, +) -> (SmallVec<[Inst; 4]>, MemArg) { + let mut insts = SmallVec::new(); + + // Resolve virtual addressing modes. + let mem = match mem { + &MemArg::RegOffset { off, .. } + | &MemArg::InitialSPOffset { off } + | &MemArg::NominalSPOffset { off } + | &MemArg::SlotOffset { off } => { + let base = match mem { + &MemArg::RegOffset { reg, .. } => reg, + &MemArg::InitialSPOffset { .. } + | &MemArg::NominalSPOffset { .. } + | &MemArg::SlotOffset { .. } => stack_reg(), + _ => unreachable!(), + }; + let adj = match mem { + &MemArg::InitialSPOffset { .. } => i64::from( + state.frame_layout().clobber_size + + state.frame_layout().fixed_frame_storage_size + + state.frame_layout().outgoing_args_size + + state.nominal_sp_offset, + ), + &MemArg::SlotOffset { .. } => { + i64::from(state.frame_layout().outgoing_args_size + state.nominal_sp_offset) + } + &MemArg::NominalSPOffset { .. } => i64::from(state.nominal_sp_offset), + _ => 0, + }; + let off = off + adj; + + if let Some(disp) = UImm12::maybe_from_u64(off as u64) { + MemArg::BXD12 { + base, + index: zero_reg(), + disp, + flags: mem.get_flags(), + } + } else if let Some(disp) = SImm20::maybe_from_i64(off) { + MemArg::BXD20 { + base, + index: zero_reg(), + disp, + flags: mem.get_flags(), + } + } else { + let tmp = writable_spilltmp_reg(); + assert!(base != tmp.to_reg()); + if let Ok(imm) = i16::try_from(off) { + insts.push(Inst::Mov64SImm16 { rd: tmp, imm }); + } else if let Ok(imm) = i32::try_from(off) { + insts.push(Inst::Mov64SImm32 { rd: tmp, imm }); + } else { + // The offset must be smaller than the stack frame size, + // which the ABI code limits to 128 MB. + unreachable!(); + } + MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags()) + } + } + _ => mem.clone(), + }; + + // If this addressing mode cannot be handled by the instruction, use load-address. + let need_load_address = match &mem { + &MemArg::Label { .. } | &MemArg::Symbol { .. } if !mi.have_pcrel => true, + &MemArg::Symbol { flags, .. } if !mi.have_unaligned_pcrel && !flags.aligned() => true, + &MemArg::BXD20 { .. } if !mi.have_d20 => true, + &MemArg::BXD12 { index, .. } | &MemArg::BXD20 { index, .. } if !mi.have_index => { + index != zero_reg() + } + _ => false, + }; + let mem = if need_load_address { + let flags = mem.get_flags(); + let tmp = writable_spilltmp_reg(); + insts.push(Inst::LoadAddr { rd: tmp, mem }); + MemArg::reg(tmp.to_reg(), flags) + } else { + mem + }; + + // Convert 12-bit displacement to 20-bit if required. + let mem = match &mem { + &MemArg::BXD12 { + base, + index, + disp, + flags, + } if !mi.have_d12 => { + assert!(mi.have_d20); + MemArg::BXD20 { + base, + index, + disp: SImm20::from_uimm12(disp), + flags, + } + } + _ => mem, + }; + + (insts, mem) +} + +pub fn mem_emit( + rd: Reg, + mem: &MemArg, + opcode_rx: Option, + opcode_rxy: Option, + opcode_ril: Option, + add_trap: bool, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, +) { + let (mem_insts, mem) = mem_finalize( + mem, + state, + MemInstType { + have_d12: opcode_rx.is_some(), + have_d20: opcode_rxy.is_some(), + have_pcrel: opcode_ril.is_some(), + have_unaligned_pcrel: opcode_ril.is_some() && !add_trap, + have_index: true, + }, + ); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + if add_trap { + if let Some(trap_code) = mem.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + match &mem { + &MemArg::BXD12 { + base, index, disp, .. + } => { + put( + sink, + &enc_rx(opcode_rx.unwrap(), rd, base, index, disp.bits()), + ); + } + &MemArg::BXD20 { + base, index, disp, .. + } => { + put( + sink, + &enc_rxy(opcode_rxy.unwrap(), rd, base, index, disp.bits()), + ); + } + &MemArg::Label { target } => { + sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL); + put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0)); + } + &MemArg::Symbol { + ref name, offset, .. + } => { + let reloc_offset = sink.cur_offset() + 2; + sink.add_reloc_at_offset( + reloc_offset, + Reloc::S390xPCRel32Dbl, + &**name, + (offset + 2).into(), + ); + put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0)); + } + _ => unreachable!(), + } +} + +pub fn mem_rs_emit( + rd: Reg, + rn: Reg, + mem: &MemArg, + opcode_rs: Option, + opcode_rsy: Option, + add_trap: bool, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, +) { + let (mem_insts, mem) = mem_finalize( + mem, + state, + MemInstType { + have_d12: opcode_rs.is_some(), + have_d20: opcode_rsy.is_some(), + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + if add_trap { + if let Some(trap_code) = mem.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + match &mem { + &MemArg::BXD12 { + base, index, disp, .. + } => { + assert!(index == zero_reg()); + put(sink, &enc_rs(opcode_rs.unwrap(), rd, rn, base, disp.bits())); + } + &MemArg::BXD20 { + base, index, disp, .. + } => { + assert!(index == zero_reg()); + put( + sink, + &enc_rsy(opcode_rsy.unwrap(), rd, rn, base, disp.bits()), + ); + } + _ => unreachable!(), + } +} + +pub fn mem_imm8_emit( + imm: u8, + mem: &MemArg, + opcode_si: u16, + opcode_siy: u16, + add_trap: bool, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, +) { + let (mem_insts, mem) = mem_finalize( + mem, + state, + MemInstType { + have_d12: true, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + if add_trap { + if let Some(trap_code) = mem.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + match &mem { + &MemArg::BXD12 { + base, index, disp, .. + } => { + assert!(index == zero_reg()); + put(sink, &enc_si(opcode_si, base, disp.bits(), imm)); + } + &MemArg::BXD20 { + base, index, disp, .. + } => { + assert!(index == zero_reg()); + put(sink, &enc_siy(opcode_siy, base, disp.bits(), imm)); + } + _ => unreachable!(), + } +} + +pub fn mem_imm16_emit( + imm: i16, + mem: &MemArg, + opcode_sil: u16, + add_trap: bool, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, +) { + let (mem_insts, mem) = mem_finalize( + mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + if add_trap { + if let Some(trap_code) = mem.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + match &mem { + &MemArg::BXD12 { + base, index, disp, .. + } => { + assert!(index == zero_reg()); + put(sink, &enc_sil(opcode_sil, base, disp.bits(), imm)); + } + _ => unreachable!(), + } +} + +pub fn mem_vrx_emit( + rd: Reg, + mem: &MemArg, + opcode: u16, + m3: u8, + add_trap: bool, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, +) { + let (mem_insts, mem) = mem_finalize( + mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + for inst in mem_insts.into_iter() { + inst.emit(sink, emit_info, state); + } + + if add_trap { + if let Some(trap_code) = mem.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + match &mem { + &MemArg::BXD12 { + base, index, disp, .. + } => { + put(sink, &enc_vrx(opcode, rd, base, index, disp.bits(), m3)); + } + _ => unreachable!(), + } +} + +//============================================================================= +// Instructions and subcomponents: emission + +fn machreg_to_gpr(m: Reg) -> u8 { + assert_eq!(m.class(), RegClass::Int); + u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap() +} + +fn machreg_to_vr(m: Reg) -> u8 { + assert_eq!(m.class(), RegClass::Float); + u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap() +} + +fn machreg_to_fpr(m: Reg) -> u8 { + assert!(is_fpr(m)); + u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap() +} + +fn machreg_to_gpr_or_fpr(m: Reg) -> u8 { + let reg = u8::try_from(m.to_real_reg().unwrap().hw_enc()).unwrap(); + assert!(reg < 16); + reg +} + +fn rxb(v1: Option, v2: Option, v3: Option, v4: Option) -> u8 { + let mut rxb = 0; + + let is_high_vr = |reg| -> bool { + if let Some(reg) = reg { + if !is_fpr(reg) { + return true; + } + } + false + }; + + if is_high_vr(v1) { + rxb = rxb | 8; + } + if is_high_vr(v2) { + rxb = rxb | 4; + } + if is_high_vr(v3) { + rxb = rxb | 2; + } + if is_high_vr(v4) { + rxb = rxb | 1; + } + + rxb +} + +/// E-type instructions. +/// +/// 15 +/// opcode +/// 0 +/// +fn enc_e(opcode: u16) -> [u8; 2] { + let mut enc: [u8; 2] = [0; 2]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + + enc[0] = opcode1; + enc[1] = opcode2; + enc +} + +/// RIa-type instructions. +/// +/// 31 23 19 15 +/// opcode1 r1 opcode2 i2 +/// 24 20 16 0 +/// +fn enc_ri_a(opcode: u16, r1: Reg, i2: u16) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4 | opcode2; + enc[2..].copy_from_slice(&i2.to_be_bytes()); + enc +} + +/// RIb-type instructions. +/// +/// 31 23 19 15 +/// opcode1 r1 opcode2 ri2 +/// 24 20 16 0 +/// +fn enc_ri_b(opcode: u16, r1: Reg, ri2: i32) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let ri2 = ((ri2 >> 1) & 0xffff) as u16; + + enc[0] = opcode1; + enc[1] = r1 << 4 | opcode2; + enc[2..].copy_from_slice(&ri2.to_be_bytes()); + enc +} + +/// RIc-type instructions. +/// +/// 31 23 19 15 +/// opcode1 m1 opcode2 ri2 +/// 24 20 16 0 +/// +fn enc_ri_c(opcode: u16, m1: u8, ri2: i32) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let m1 = m1 & 0x0f; + let ri2 = ((ri2 >> 1) & 0xffff) as u16; + + enc[0] = opcode1; + enc[1] = m1 << 4 | opcode2; + enc[2..].copy_from_slice(&ri2.to_be_bytes()); + enc +} + +/// RIEa-type instructions. +/// +/// 47 39 35 31 15 11 7 +/// opcode1 r1 -- i2 m3 -- opcode2 +/// 40 36 32 16 12 8 0 +/// +fn enc_rie_a(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let m3 = m3 & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4; + enc[2..4].copy_from_slice(&i2.to_be_bytes()); + enc[4] = m3 << 4; + enc[5] = opcode2; + enc +} + +/// RIEd-type instructions. +/// +/// 47 39 35 31 15 7 +/// opcode1 r1 r3 i2 -- opcode2 +/// 40 36 32 16 8 0 +/// +fn enc_rie_d(opcode: u16, r1: Reg, r3: Reg, i2: u16) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let r3 = machreg_to_gpr(r3) & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4 | r3; + enc[2..4].copy_from_slice(&i2.to_be_bytes()); + enc[5] = opcode2; + enc +} + +/// RIEf-type instructions. +/// +/// 47 39 35 31 23 15 7 +/// opcode1 r1 r2 i3 i4 i5 opcode2 +/// 40 36 32 24 16 8 0 +/// +fn enc_rie_f(opcode: u16, r1: Reg, r2: Reg, i3: u8, i4: u8, i5: u8) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let r2 = machreg_to_gpr(r2) & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4 | r2; + enc[2] = i3; + enc[3] = i4; + enc[4] = i5; + enc[5] = opcode2; + enc +} + +/// RIEg-type instructions. +/// +/// 47 39 35 31 15 7 +/// opcode1 r1 m3 i2 -- opcode2 +/// 40 36 32 16 8 0 +/// +fn enc_rie_g(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let m3 = m3 & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4 | m3; + enc[2..4].copy_from_slice(&i2.to_be_bytes()); + enc[5] = opcode2; + enc +} + +/// RILa-type instructions. +/// +/// 47 39 35 31 +/// opcode1 r1 opcode2 i2 +/// 40 36 32 0 +/// +fn enc_ril_a(opcode: u16, r1: Reg, i2: u32) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + + enc[0] = opcode1; + enc[1] = r1 << 4 | opcode2; + enc[2..].copy_from_slice(&i2.to_be_bytes()); + enc +} + +/// RILb-type instructions. +/// +/// 47 39 35 31 +/// opcode1 r1 opcode2 ri2 +/// 40 36 32 0 +/// +fn enc_ril_b(opcode: u16, r1: Reg, ri2: u32) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let r1 = machreg_to_gpr(r1) & 0x0f; + let ri2 = ri2 >> 1; + + enc[0] = opcode1; + enc[1] = r1 << 4 | opcode2; + enc[2..].copy_from_slice(&ri2.to_be_bytes()); + enc +} + +/// RILc-type instructions. +/// +/// 47 39 35 31 +/// opcode1 m1 opcode2 i2 +/// 40 36 32 0 +/// +fn enc_ril_c(opcode: u16, m1: u8, ri2: u32) -> [u8; 6] { + let mut enc: [u8; 6] = [0; 6]; + let opcode1 = ((opcode >> 4) & 0xff) as u8; + let opcode2 = (opcode & 0xf) as u8; + let m1 = m1 & 0x0f; + let ri2 = ri2 >> 1; + + enc[0] = opcode1; + enc[1] = m1 << 4 | opcode2; + enc[2..].copy_from_slice(&ri2.to_be_bytes()); + enc +} + +/// RR-type instructions. +/// +/// 15 7 3 +/// opcode r1 r2 +/// 8 4 0 +/// +fn enc_rr(opcode: u16, r1: Reg, r2: Reg) -> [u8; 2] { + let mut enc: [u8; 2] = [0; 2]; + let opcode = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f; + + enc[0] = opcode; + enc[1] = r1 << 4 | r2; + enc +} + +/// RRD-type instructions. +/// +/// 31 15 11 7 3 +/// opcode r1 -- r3 r2 +/// 16 12 8 4 0 +/// +fn enc_rrd(opcode: u16, r1: Reg, r2: Reg, r3: Reg) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_fpr(r1) & 0x0f; + let r2 = machreg_to_fpr(r2) & 0x0f; + let r3 = machreg_to_fpr(r3) & 0x0f; + + enc[0] = opcode1; + enc[1] = opcode2; + enc[2] = r1 << 4; + enc[3] = r3 << 4 | r2; + enc +} + +/// RRE-type instructions. +/// +/// 31 15 7 3 +/// opcode -- r1 r2 +/// 16 8 4 0 +/// +fn enc_rre(opcode: u16, r1: Reg, r2: Reg) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f; + + enc[0] = opcode1; + enc[1] = opcode2; + enc[3] = r1 << 4 | r2; + enc +} + +/// RRFa/b-type instructions. +/// +/// 31 15 11 7 3 +/// opcode r3 m4 r1 r2 +/// 16 12 8 4 0 +/// +fn enc_rrf_ab(opcode: u16, r1: Reg, r2: Reg, r3: Reg, m4: u8) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f; + let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f; + let m4 = m4 & 0x0f; + + enc[0] = opcode1; + enc[1] = opcode2; + enc[2] = r3 << 4 | m4; + enc[3] = r1 << 4 | r2; + enc +} + +/// RRFc/d/e-type instructions. +/// +/// 31 15 11 7 3 +/// opcode m3 m4 r1 r2 +/// 16 12 8 4 0 +/// +fn enc_rrf_cde(opcode: u16, r1: Reg, r2: Reg, m3: u8, m4: u8) -> [u8; 4] { + let mut enc: [u8; 4] = [0; 4]; + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f; + let m3 = m3 & 0x0f; + let m4 = m4 & 0x0f; + + enc[0] = opcode1; + enc[1] = opcode2; + enc[2] = m3 << 4 | m4; + enc[3] = r1 << 4 | r2; + enc +} + +/// RS-type instructions. +/// +/// 31 23 19 15 11 +/// opcode r1 r3 b2 d2 +/// 24 20 16 12 0 +/// +fn enc_rs(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 4] { + let opcode = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + + let mut enc: [u8; 4] = [0; 4]; + enc[0] = opcode; + enc[1] = r1 << 4 | r3; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc +} + +/// RSY-type instructions. +/// +/// 47 39 35 31 27 15 7 +/// opcode1 r1 r3 b2 dl2 dh2 opcode2 +/// 40 36 32 28 16 8 0 +/// +fn enc_rsy(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let dl2_lo = (d2 & 0xff) as u8; + let dl2_hi = ((d2 >> 8) & 0x0f) as u8; + let dh2 = ((d2 >> 12) & 0xff) as u8; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = r1 << 4 | r3; + enc[2] = b2 << 4 | dl2_hi; + enc[3] = dl2_lo; + enc[4] = dh2; + enc[5] = opcode2; + enc +} + +/// RX-type instructions. +/// +/// 31 23 19 15 11 +/// opcode r1 x2 b2 d2 +/// 24 20 16 12 0 +/// +fn enc_rx(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 4] { + let opcode = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let x2 = machreg_to_gpr(x2) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + + let mut enc: [u8; 4] = [0; 4]; + enc[0] = opcode; + enc[1] = r1 << 4 | x2; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc +} + +/// RXY-type instructions. +/// +/// 47 39 35 31 27 15 7 +/// opcode1 r1 x2 b2 dl2 dh2 opcode2 +/// 40 36 32 28 16 8 0 +/// +fn enc_rxy(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let x2 = machreg_to_gpr(x2) & 0x0f; + let dl2_lo = (d2 & 0xff) as u8; + let dl2_hi = ((d2 >> 8) & 0x0f) as u8; + let dh2 = ((d2 >> 12) & 0xff) as u8; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = r1 << 4 | x2; + enc[2] = b2 << 4 | dl2_hi; + enc[3] = dl2_lo; + enc[4] = dh2; + enc[5] = opcode2; + enc +} + +/// SI-type instructions. +/// +/// 31 23 15 11 +/// opcode i2 b1 d1 +/// 24 16 12 0 +/// +fn enc_si(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 4] { + let opcode = (opcode & 0xff) as u8; + let b1 = machreg_to_gpr(b1) & 0x0f; + let d1_lo = (d1 & 0xff) as u8; + let d1_hi = ((d1 >> 8) & 0x0f) as u8; + + let mut enc: [u8; 4] = [0; 4]; + enc[0] = opcode; + enc[1] = i2; + enc[2] = b1 << 4 | d1_hi; + enc[3] = d1_lo; + enc +} + +/// SIL-type instructions. +/// +/// 47 31 27 15 +/// opcode b1 d1 i2 +/// 32 28 16 0 +/// +fn enc_sil(opcode: u16, b1: Reg, d1: u32, i2: i16) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let b1 = machreg_to_gpr(b1) & 0x0f; + let d1_lo = (d1 & 0xff) as u8; + let d1_hi = ((d1 >> 8) & 0x0f) as u8; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = opcode2; + enc[2] = b1 << 4 | d1_hi; + enc[3] = d1_lo; + enc[4..].copy_from_slice(&i2.to_be_bytes()); + enc +} + +/// SIY-type instructions. +/// +/// 47 39 31 27 15 7 +/// opcode1 i2 b1 dl1 dh1 opcode2 +/// 40 32 28 16 8 0 +/// +fn enc_siy(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let b1 = machreg_to_gpr(b1) & 0x0f; + let dl1_lo = (d1 & 0xff) as u8; + let dl1_hi = ((d1 >> 8) & 0x0f) as u8; + let dh1 = ((d1 >> 12) & 0xff) as u8; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = i2; + enc[2] = b1 << 4 | dl1_hi; + enc[3] = dl1_lo; + enc[4] = dh1; + enc[5] = opcode2; + enc +} + +/// VRIa-type instructions. +/// +/// 47 39 35 31 15 11 7 +/// opcode1 v1 - i2 m3 rxb opcode2 +/// 40 36 32 16 12 8 0 +/// +fn enc_vri_a(opcode: u16, v1: Reg, i2: u16, m3: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), None, None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let m3 = m3 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4; + enc[2..4].copy_from_slice(&i2.to_be_bytes()); + enc[4] = m3 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRIb-type instructions. +/// +/// 47 39 35 31 23 15 11 7 +/// opcode1 v1 - i2 i3 m4 rxb opcode2 +/// 40 36 32 24 16 12 8 0 +/// +fn enc_vri_b(opcode: u16, v1: Reg, i2: u8, i3: u8, m4: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), None, None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let m4 = m4 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4; + enc[2] = i2; + enc[3] = i3; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRIc-type instructions. +/// +/// 47 39 35 31 15 11 7 +/// opcode1 v1 v3 i2 m4 rxb opcode2 +/// 40 36 32 16 12 8 0 +/// +fn enc_vri_c(opcode: u16, v1: Reg, i2: u16, v3: Reg, m4: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v3), None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let m4 = m4 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v3; + enc[2..4].copy_from_slice(&i2.to_be_bytes()); + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRRa-type instructions. +/// +/// 47 39 35 31 23 19 15 11 7 +/// opcode1 v1 v2 - m5 m3 m2 rxb opcode2 +/// 40 36 32 24 20 16 12 8 0 +/// +fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v2), None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let v2 = machreg_to_vr(v2) & 0x0f; + let m3 = m3 & 0x0f; + let m4 = m4 & 0x0f; + let m5 = m5 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v2; + enc[2] = 0; + enc[3] = m5 << 4 | m4; + enc[4] = m3 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRRb-type instructions. +/// +/// 47 39 35 31 27 23 19 15 11 7 +/// opcode1 v1 v2 v3 - m5 - m4 rxb opcode2 +/// 40 36 32 28 24 20 16 12 8 0 +/// +fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v2), Some(v3), None); + let v1 = machreg_to_vr(v1) & 0x0f; + let v2 = machreg_to_vr(v2) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let m4 = m4 & 0x0f; + let m5 = m5 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v2; + enc[2] = v3 << 4; + enc[3] = m5 << 4; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRRc-type instructions. +/// +/// 47 39 35 31 27 23 19 15 11 7 +/// opcode1 v1 v2 v3 - m6 m5 m4 rxb opcode2 +/// 40 36 32 28 24 20 16 12 8 0 +/// +fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v2), Some(v3), None); + let v1 = machreg_to_vr(v1) & 0x0f; + let v2 = machreg_to_vr(v2) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let m4 = m4 & 0x0f; + let m5 = m5 & 0x0f; + let m6 = m6 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v2; + enc[2] = v3 << 4; + enc[3] = m6 << 4 | m5; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRRe-type instructions. +/// +/// 47 39 35 31 27 23 19 15 11 7 +/// opcode1 v1 v2 v3 m6 - m5 v4 rxb opcode2 +/// 40 36 32 28 24 20 16 12 8 0 +/// +fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4)); + let v1 = machreg_to_vr(v1) & 0x0f; + let v2 = machreg_to_vr(v2) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let v4 = machreg_to_vr(v4) & 0x0f; + let m5 = m5 & 0x0f; + let m6 = m6 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v2; + enc[2] = v3 << 4 | m6; + enc[3] = m5; + enc[4] = v4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRRf-type instructions. +/// +/// 47 39 35 31 27 11 7 +/// opcode1 v1 r2 r3 - rxb opcode2 +/// 40 36 32 28 12 8 0 +/// +fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), None, None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let r2 = machreg_to_gpr(r2) & 0x0f; + let r3 = machreg_to_gpr(r3) & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | r2; + enc[2] = r3 << 4; + enc[4] = rxb; + enc[5] = opcode2; + enc +} + +/// VRSa-type instructions. +/// +/// 47 39 35 31 27 15 11 7 +/// opcode1 v1 v3 b2 d2 m4 rxb opcode2 +/// 40 36 32 28 16 12 8 0 +/// +fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), Some(v3), None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + let m4 = m4 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | v3; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRSb-type instructions. +/// +/// 47 39 35 31 27 15 11 7 +/// opcode1 v1 r3 b2 d2 m4 rxb opcode2 +/// 40 36 32 28 16 12 8 0 +/// +fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), None, None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let r3 = machreg_to_gpr(r3) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + let m4 = m4 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | r3; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRSc-type instructions. +/// +/// 47 39 35 31 27 15 11 7 +/// opcode1 r1 v3 b2 d2 m4 rxb opcode2 +/// 40 36 32 28 16 12 8 0 +/// +fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(None, Some(v3), None, None); + let r1 = machreg_to_gpr(r1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let v3 = machreg_to_vr(v3) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + let m4 = m4 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = r1 << 4 | v3; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc[4] = m4 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// VRX-type instructions. +/// +/// 47 39 35 31 27 15 11 7 +/// opcode1 v1 x2 b2 d2 m3 rxb opcode2 +/// 40 36 32 28 16 12 8 0 +/// +fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] { + let opcode1 = ((opcode >> 8) & 0xff) as u8; + let opcode2 = (opcode & 0xff) as u8; + let rxb = rxb(Some(v1), None, None, None); + let v1 = machreg_to_vr(v1) & 0x0f; + let b2 = machreg_to_gpr(b2) & 0x0f; + let x2 = machreg_to_gpr(x2) & 0x0f; + let d2_lo = (d2 & 0xff) as u8; + let d2_hi = ((d2 >> 8) & 0x0f) as u8; + let m3 = m3 & 0x0f; + + let mut enc: [u8; 6] = [0; 6]; + enc[0] = opcode1; + enc[1] = v1 << 4 | x2; + enc[2] = b2 << 4 | d2_hi; + enc[3] = d2_lo; + enc[4] = m3 << 4 | rxb; + enc[5] = opcode2; + enc +} + +/// Emit encoding to sink. +fn put(sink: &mut MachBuffer, enc: &[u8]) { + for byte in enc { + sink.put1(*byte); + } +} + +/// Emit encoding to sink, adding a trap on the last byte. +fn put_with_trap(sink: &mut MachBuffer, enc: &[u8], trap_code: TrapCode) { + let len = enc.len(); + for i in 0..len - 1 { + sink.put1(enc[i]); + } + sink.add_trap(trap_code); + sink.put1(enc[len - 1]); +} + +/// State carried between emissions of a sequence of instructions. +#[derive(Default, Clone, Debug)] +pub struct EmitState { + /// Offset from the actual SP to the "nominal SP". The latter is defined + /// as the value the stack pointer has after the prolog. This offset is + /// normally always zero, except during a call sequence using the tail-call + /// ABI, between the AllocateArgs and the actual call instruction. + pub(crate) nominal_sp_offset: u32, + + /// The user stack map for the upcoming instruction, as provided to + /// `pre_safepoint()`. + user_stack_map: Option, + + /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and + /// optimized away at compiletime. See [cranelift_control]. + ctrl_plane: ControlPlane, + + frame_layout: FrameLayout, +} + +impl MachInstEmitState for EmitState { + fn new(abi: &Callee, ctrl_plane: ControlPlane) -> Self { + EmitState { + nominal_sp_offset: 0, + user_stack_map: None, + ctrl_plane, + frame_layout: abi.frame_layout().clone(), + } + } + + fn pre_safepoint(&mut self, user_stack_map: Option) { + self.user_stack_map = user_stack_map; + } + + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane { + &mut self.ctrl_plane + } + + fn take_ctrl_plane(self) -> ControlPlane { + self.ctrl_plane + } + + fn frame_layout(&self) -> &FrameLayout { + &self.frame_layout + } +} + +impl EmitState { + fn take_stack_map(&mut self) -> Option { + self.user_stack_map.take() + } + + fn clear_post_insn(&mut self) { + self.user_stack_map = None; + } +} + +/// Constant state used during function compilation. +pub struct EmitInfo { + isa_flags: s390x_settings::Flags, +} + +impl EmitInfo { + pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self { + Self { isa_flags } + } +} + +impl MachInstEmit for Inst { + type State = EmitState; + type Info = EmitInfo; + + fn emit(&self, sink: &mut MachBuffer, emit_info: &Self::Info, state: &mut EmitState) { + self.emit_with_alloc_consumer(sink, emit_info, state) + } + + fn pretty_print_inst(&self, state: &mut EmitState) -> String { + self.print_with_state(state) + } +} + +impl Inst { + fn emit_with_alloc_consumer( + &self, + sink: &mut MachBuffer, + emit_info: &EmitInfo, + state: &mut EmitState, + ) { + // Verify that we can emit this Inst in the current ISA + let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool { + match iset_requirement { + // Baseline ISA is z14 + InstructionSet::Base => true, + // Miscellaneous-Instruction-Extensions Facility 2 (z15) + InstructionSet::MIE2 => emit_info.isa_flags.has_mie2(), + // Vector-Enhancements Facility 2 (z15) + InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(), + } + }; + let isa_requirements = self.available_in_isa(); + if !matches_isa_flags(&isa_requirements) { + panic!( + "Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}" + ) + } + + // N.B.: we *must* not exceed the "worst-case size" used to compute + // where to insert islands, except when islands are explicitly triggered + // (with an `EmitIsland`). We check this in debug builds. This is `mut` + // to allow disabling the check for `JTSequence`, which is always + // emitted following an `EmitIsland`. + let mut start_off = sink.cur_offset(); + + match self { + &Inst::AluRRR { alu_op, rd, rn, rm } => { + let (opcode, have_rr) = match alu_op { + ALUOp::Add32 => (0xb9f8, true), // ARK + ALUOp::Add64 => (0xb9e8, true), // AGRK + ALUOp::AddLogical32 => (0xb9fa, true), // ALRK + ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK + ALUOp::Sub32 => (0xb9f9, true), // SRK + ALUOp::Sub64 => (0xb9e9, true), // SGRK + ALUOp::SubLogical32 => (0xb9fb, true), // SLRK + ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK + ALUOp::Mul32 => (0xb9fd, true), // MSRKC + ALUOp::Mul64 => (0xb9ed, true), // MSGRKC + ALUOp::And32 => (0xb9f4, true), // NRK + ALUOp::And64 => (0xb9e4, true), // NGRK + ALUOp::Orr32 => (0xb9f6, true), // ORK + ALUOp::Orr64 => (0xb9e6, true), // OGRK + ALUOp::Xor32 => (0xb9f7, true), // XRK + ALUOp::Xor64 => (0xb9e7, true), // XGRK + ALUOp::NotAnd32 => (0xb974, false), // NNRK + ALUOp::NotAnd64 => (0xb964, false), // NNGRK + ALUOp::NotOrr32 => (0xb976, false), // NORK + ALUOp::NotOrr64 => (0xb966, false), // NOGRK + ALUOp::NotXor32 => (0xb977, false), // NXRK + ALUOp::NotXor64 => (0xb967, false), // NXGRK + ALUOp::AndNot32 => (0xb9f5, false), // NCRK + ALUOp::AndNot64 => (0xb9e5, false), // NCGRK + ALUOp::OrrNot32 => (0xb975, false), // OCRK + ALUOp::OrrNot64 => (0xb965, false), // OCGRK + _ => unreachable!(), + }; + if have_rr && rd.to_reg() == rn { + let inst = Inst::AluRR { + alu_op, + rd, + ri: rn, + rm, + }; + inst.emit(sink, emit_info, state); + } else { + put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0)); + } + } + &Inst::AluRRSImm16 { + alu_op, + rd, + rn, + imm, + } => { + if rd.to_reg() == rn { + let inst = Inst::AluRSImm16 { + alu_op, + rd, + ri: rn, + imm, + }; + inst.emit(sink, emit_info, state); + } else { + let opcode = match alu_op { + ALUOp::Add32 => 0xecd8, // AHIK + ALUOp::Add64 => 0xecd9, // AGHIK + _ => unreachable!(), + }; + put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16)); + } + } + &Inst::AluRR { alu_op, rd, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let (opcode, is_rre) = match alu_op { + ALUOp::Add32 => (0x1a, false), // AR + ALUOp::Add64 => (0xb908, true), // AGR + ALUOp::Add64Ext32 => (0xb918, true), // AGFR + ALUOp::AddLogical32 => (0x1e, false), // ALR + ALUOp::AddLogical64 => (0xb90a, true), // ALGR + ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR + ALUOp::Sub32 => (0x1b, false), // SR + ALUOp::Sub64 => (0xb909, true), // SGR + ALUOp::Sub64Ext32 => (0xb919, true), // SGFR + ALUOp::SubLogical32 => (0x1f, false), // SLR + ALUOp::SubLogical64 => (0xb90b, true), // SLGR + ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR + ALUOp::Mul32 => (0xb252, true), // MSR + ALUOp::Mul64 => (0xb90c, true), // MSGR + ALUOp::Mul64Ext32 => (0xb91c, true), // MSGFR + ALUOp::And32 => (0x14, false), // NR + ALUOp::And64 => (0xb980, true), // NGR + ALUOp::Orr32 => (0x16, false), // OR + ALUOp::Orr64 => (0xb981, true), // OGR + ALUOp::Xor32 => (0x17, false), // XR + ALUOp::Xor64 => (0xb982, true), // XGR + _ => unreachable!(), + }; + if is_rre { + put(sink, &enc_rre(opcode, rd.to_reg(), rm)); + } else { + put(sink, &enc_rr(opcode, rd.to_reg(), rm)); + } + } + &Inst::AluRX { + alu_op, + rd, + ri, + ref mem, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let mem = mem.clone(); + + let (opcode_rx, opcode_rxy) = match alu_op { + ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), // A(Y) + ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), // AH(Y) + ALUOp::Add64 => (None, Some(0xe308)), // AG + ALUOp::Add64Ext16 => (None, Some(0xe338)), // AGH + ALUOp::Add64Ext32 => (None, Some(0xe318)), // AGF + ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y) + ALUOp::AddLogical64 => (None, Some(0xe30a)), // ALG + ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), // ALGF + ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), // S(Y) + ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), // SH(Y) + ALUOp::Sub64 => (None, Some(0xe309)), // SG + ALUOp::Sub64Ext16 => (None, Some(0xe339)), // SGH + ALUOp::Sub64Ext32 => (None, Some(0xe319)), // SGF + ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y) + ALUOp::SubLogical64 => (None, Some(0xe30b)), // SLG + ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), // SLGF + ALUOp::Mul32 => (Some(0x71), Some(0xe351)), // MS(Y) + ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), // MH(Y) + ALUOp::Mul64 => (None, Some(0xe30c)), // MSG + ALUOp::Mul64Ext16 => (None, Some(0xe33c)), // MSH + ALUOp::Mul64Ext32 => (None, Some(0xe31c)), // MSGF + ALUOp::And32 => (Some(0x54), Some(0xe354)), // N(Y) + ALUOp::And64 => (None, Some(0xe380)), // NG + ALUOp::Orr32 => (Some(0x56), Some(0xe356)), // O(Y) + ALUOp::Orr64 => (None, Some(0xe381)), // OG + ALUOp::Xor32 => (Some(0x57), Some(0xe357)), // X(Y) + ALUOp::Xor64 => (None, Some(0xe382)), // XG + _ => unreachable!(), + }; + let rd = rd.to_reg(); + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state, + ); + } + &Inst::AluRSImm16 { + alu_op, + rd, + ri, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match alu_op { + ALUOp::Add32 => 0xa7a, // AHI + ALUOp::Add64 => 0xa7b, // AGHI + ALUOp::Mul32 => 0xa7c, // MHI + ALUOp::Mul64 => 0xa7d, // MGHI + _ => unreachable!(), + }; + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16)); + } + &Inst::AluRSImm32 { + alu_op, + rd, + ri, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match alu_op { + ALUOp::Add32 => 0xc29, // AFI + ALUOp::Add64 => 0xc28, // AGFI + ALUOp::Mul32 => 0xc21, // MSFI + ALUOp::Mul64 => 0xc20, // MSGFI + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32)); + } + &Inst::AluRUImm32 { + alu_op, + rd, + ri, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match alu_op { + ALUOp::AddLogical32 => 0xc2b, // ALFI + ALUOp::AddLogical64 => 0xc2a, // ALGFI + ALUOp::SubLogical32 => 0xc25, // SLFI + ALUOp::SubLogical64 => 0xc24, // SLGFI + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm)); + } + &Inst::AluRUImm16Shifted { + alu_op, + rd, + ri, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match (alu_op, imm.shift) { + (ALUOp::And32, 0) => 0xa57, // NILL + (ALUOp::And32, 1) => 0xa56, // NILH + (ALUOp::And64, 0) => 0xa57, // NILL + (ALUOp::And64, 1) => 0xa56, // NILH + (ALUOp::And64, 2) => 0xa55, // NIHL + (ALUOp::And64, 3) => 0xa54, // NIHL + (ALUOp::Orr32, 0) => 0xa5b, // OILL + (ALUOp::Orr32, 1) => 0xa5a, // OILH + (ALUOp::Orr64, 0) => 0xa5b, // OILL + (ALUOp::Orr64, 1) => 0xa5a, // OILH + (ALUOp::Orr64, 2) => 0xa59, // OIHL + (ALUOp::Orr64, 3) => 0xa58, // OIHH + _ => unreachable!(), + }; + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits)); + } + &Inst::AluRUImm32Shifted { + alu_op, + rd, + ri, + imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match (alu_op, imm.shift) { + (ALUOp::And32, 0) => 0xc0b, // NILF + (ALUOp::And64, 0) => 0xc0b, // NILF + (ALUOp::And64, 1) => 0xc0a, // NIHF + (ALUOp::Orr32, 0) => 0xc0d, // OILF + (ALUOp::Orr64, 0) => 0xc0d, // OILF + (ALUOp::Orr64, 1) => 0xc0c, // OILF + (ALUOp::Xor32, 0) => 0xc07, // XILF + (ALUOp::Xor64, 0) => 0xc07, // XILF + (ALUOp::Xor64, 1) => 0xc06, // XILH + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits)); + } + + &Inst::SMulWide { rd, rn, rm } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + + let opcode = 0xb9ec; // MGRK + put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0)); + } + &Inst::UMulWide { rd, ri, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + debug_assert_eq!(rd2.to_reg(), ri); + + let opcode = 0xb986; // MLGR + put(sink, &enc_rre(opcode, rd1.to_reg(), rn)); + } + &Inst::SDivMod32 { rd, ri, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + debug_assert_eq!(rd2.to_reg(), ri); + + let opcode = 0xb91d; // DSGFR + let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO; + put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code); + } + &Inst::SDivMod64 { rd, ri, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + debug_assert_eq!(rd2.to_reg(), ri); + + let opcode = 0xb90d; // DSGR + let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO; + put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code); + } + &Inst::UDivMod32 { rd, ri, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + let ri1 = ri.hi; + let ri2 = ri.lo; + debug_assert_eq!(rd1.to_reg(), ri1); + debug_assert_eq!(rd2.to_reg(), ri2); + + let opcode = 0xb997; // DLR + let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO; + put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code); + } + &Inst::UDivMod64 { rd, ri, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + let ri1 = ri.hi; + let ri2 = ri.lo; + debug_assert_eq!(rd1.to_reg(), ri1); + debug_assert_eq!(rd2.to_reg(), ri2); + + let opcode = 0xb987; // DLGR + let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO; + put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code); + } + &Inst::Flogr { rd, rn } => { + let rd1 = rd.hi; + let rd2 = rd.lo; + debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg()); + + let opcode = 0xb983; // FLOGR + put(sink, &enc_rre(opcode, rd1.to_reg(), rn)); + } + + &Inst::ShiftRR { + shift_op, + rd, + rn, + shift_imm, + shift_reg, + } => { + let opcode = match shift_op { + ShiftOp::RotL32 => 0xeb1d, // RLL + ShiftOp::RotL64 => 0xeb1c, // RLLG + ShiftOp::LShL32 => 0xebdf, // SLLK (SLL ?) + ShiftOp::LShL64 => 0xeb0d, // SLLG + ShiftOp::LShR32 => 0xebde, // SRLK (SRL ?) + ShiftOp::LShR64 => 0xeb0c, // SRLG + ShiftOp::AShR32 => 0xebdc, // SRAK (SRA ?) + ShiftOp::AShR64 => 0xeb0a, // SRAG + }; + put( + sink, + &enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()), + ); + } + + &Inst::RxSBG { + op, + rd, + ri, + rn, + start_bit, + end_bit, + rotate_amt, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match op { + RxSBGOp::Insert => 0xec59, // RISBGN + RxSBGOp::And => 0xec54, // RNSBG + RxSBGOp::Or => 0xec56, // ROSBG + RxSBGOp::Xor => 0xec57, // RXSBG + }; + put( + sink, + &enc_rie_f( + opcode, + rd.to_reg(), + rn, + start_bit, + end_bit, + (rotate_amt as u8) & 63, + ), + ); + } + + &Inst::RxSBGTest { + op, + rd, + rn, + start_bit, + end_bit, + rotate_amt, + } => { + let opcode = match op { + RxSBGOp::And => 0xec54, // RNSBG + RxSBGOp::Or => 0xec56, // ROSBG + RxSBGOp::Xor => 0xec57, // RXSBG + _ => unreachable!(), + }; + put( + sink, + &enc_rie_f( + opcode, + rd, + rn, + start_bit | 0x80, + end_bit, + (rotate_amt as u8) & 63, + ), + ); + } + + &Inst::UnaryRR { op, rd, rn } => { + match op { + UnaryOp::Abs32 => { + let opcode = 0x10; // LPR + put(sink, &enc_rr(opcode, rd.to_reg(), rn)); + } + UnaryOp::Abs64 => { + let opcode = 0xb900; // LPGR + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + UnaryOp::Abs64Ext32 => { + let opcode = 0xb910; // LPGFR + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + UnaryOp::Neg32 => { + let opcode = 0x13; // LCR + put(sink, &enc_rr(opcode, rd.to_reg(), rn)); + } + UnaryOp::Neg64 => { + let opcode = 0xb903; // LCGR + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + UnaryOp::Neg64Ext32 => { + let opcode = 0xb913; // LCGFR + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + UnaryOp::PopcntByte => { + let opcode = 0xb9e1; // POPCNT + put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0)); + } + UnaryOp::PopcntReg => { + let opcode = 0xb9e1; // POPCNT + put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0)); + } + UnaryOp::BSwap32 => { + let opcode = 0xb91f; // LRVR + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + UnaryOp::BSwap64 => { + let opcode = 0xb90f; // LRVRG + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + } + } + + &Inst::Extend { + rd, + rn, + signed, + from_bits, + to_bits, + } => { + let opcode = match (signed, from_bits, to_bits) { + (_, 1, 32) => 0xb926, // LBR + (_, 1, 64) => 0xb906, // LGBR + (false, 8, 32) => 0xb994, // LLCR + (false, 8, 64) => 0xb984, // LLGCR + (true, 8, 32) => 0xb926, // LBR + (true, 8, 64) => 0xb906, // LGBR + (false, 16, 32) => 0xb995, // LLHR + (false, 16, 64) => 0xb985, // LLGHR + (true, 16, 32) => 0xb927, // LHR + (true, 16, 64) => 0xb907, // LGHR + (false, 32, 64) => 0xb916, // LLGFR + (true, 32, 64) => 0xb914, // LGFR + _ => panic!( + "Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}" + ), + }; + put(sink, &enc_rre(opcode, rd.to_reg(), rn)); + } + + &Inst::CmpRR { op, rn, rm } => { + let (opcode, is_rre) = match op { + CmpOp::CmpS32 => (0x19, false), // CR + CmpOp::CmpS64 => (0xb920, true), // CGR + CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR + CmpOp::CmpL32 => (0x15, false), // CLR + CmpOp::CmpL64 => (0xb921, true), // CLGR + CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR + _ => unreachable!(), + }; + if is_rre { + put(sink, &enc_rre(opcode, rn, rm)); + } else { + put(sink, &enc_rr(opcode, rn, rm)); + } + } + &Inst::CmpRX { op, rn, ref mem } => { + let mem = mem.clone(); + + let (opcode_rx, opcode_rxy, opcode_ril) = match op { + CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), // C(Y), CRL + CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL + CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), // CG, CGRL + CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), // CGH, CGHRL + CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), // CGF, CGFRL + CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL + CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), // CLHRL + CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), // CLG, CLGRL + CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), // CLGHRL + CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), // CLGF, CLGFRL + }; + mem_emit( + rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state, + ); + } + &Inst::CmpRSImm16 { op, rn, imm } => { + let opcode = match op { + CmpOp::CmpS32 => 0xa7e, // CHI + CmpOp::CmpS64 => 0xa7f, // CGHI + _ => unreachable!(), + }; + put(sink, &enc_ri_a(opcode, rn, imm as u16)); + } + &Inst::CmpRSImm32 { op, rn, imm } => { + let opcode = match op { + CmpOp::CmpS32 => 0xc2d, // CFI + CmpOp::CmpS64 => 0xc2c, // CGFI + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rn, imm as u32)); + } + &Inst::CmpRUImm32 { op, rn, imm } => { + let opcode = match op { + CmpOp::CmpL32 => 0xc2f, // CLFI + CmpOp::CmpL64 => 0xc2e, // CLGFI + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rn, imm)); + } + &Inst::CmpTrapRR { + op, + rn, + rm, + cond, + trap_code, + } => { + let opcode = match op { + CmpOp::CmpS32 => 0xb972, // CRT + CmpOp::CmpS64 => 0xb960, // CGRT + CmpOp::CmpL32 => 0xb973, // CLRT + CmpOp::CmpL64 => 0xb961, // CLGRT + _ => unreachable!(), + }; + put_with_trap( + sink, + &enc_rrf_cde(opcode, rn, rm, cond.bits(), 0), + trap_code, + ); + } + &Inst::CmpTrapRSImm16 { + op, + rn, + imm, + cond, + trap_code, + } => { + let opcode = match op { + CmpOp::CmpS32 => 0xec72, // CIT + CmpOp::CmpS64 => 0xec70, // CGIT + _ => unreachable!(), + }; + put_with_trap( + sink, + &enc_rie_a(opcode, rn, imm as u16, cond.bits()), + trap_code, + ); + } + &Inst::CmpTrapRUImm16 { + op, + rn, + imm, + cond, + trap_code, + } => { + let opcode = match op { + CmpOp::CmpL32 => 0xec73, // CLFIT + CmpOp::CmpL64 => 0xec71, // CLGIT + _ => unreachable!(), + }; + put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code); + } + + &Inst::AtomicRmw { + alu_op, + rd, + rn, + ref mem, + } => { + let mem = mem.clone(); + + let opcode = match alu_op { + ALUOp::Add32 => 0xebf8, // LAA + ALUOp::Add64 => 0xebe8, // LAAG + ALUOp::AddLogical32 => 0xebfa, // LAAL + ALUOp::AddLogical64 => 0xebea, // LAALG + ALUOp::And32 => 0xebf4, // LAN + ALUOp::And64 => 0xebe4, // LANG + ALUOp::Orr32 => 0xebf6, // LAO + ALUOp::Orr64 => 0xebe6, // LAOG + ALUOp::Xor32 => 0xebf7, // LAX + ALUOp::Xor64 => 0xebe7, // LAXG + _ => unreachable!(), + }; + + let rd = rd.to_reg(); + mem_rs_emit( + rd, + rn, + &mem, + None, + Some(opcode), + true, + sink, + emit_info, + state, + ); + } + &Inst::Loop { ref body, cond } => { + // This sequence is *one* instruction in the vcode, and is expanded only here at + // emission time, because it requires branching to internal labels. + let loop_label = sink.get_label(); + let done_label = sink.get_label(); + + // Emit label at the start of the loop. + sink.bind_label(loop_label, &mut state.ctrl_plane); + + for inst in (&body).into_iter() { + match &inst { + // Replace a CondBreak with a branch to done_label. + &Inst::CondBreak { cond } => { + let inst = Inst::OneWayCondBr { + target: done_label, + cond: *cond, + }; + inst.emit_with_alloc_consumer(sink, emit_info, state); + } + _ => inst.emit_with_alloc_consumer(sink, emit_info, state), + }; + } + + let inst = Inst::OneWayCondBr { + target: loop_label, + cond, + }; + inst.emit(sink, emit_info, state); + + // Emit label at the end of the loop. + sink.bind_label(done_label, &mut state.ctrl_plane); + } + &Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop. + &Inst::AtomicCas32 { + rd, + ri, + rn, + ref mem, + } + | &Inst::AtomicCas64 { + rd, + ri, + rn, + ref mem, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let mem = mem.clone(); + + let (opcode_rs, opcode_rsy) = match self { + &Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), // CS(Y) + &Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), // CSG + _ => unreachable!(), + }; + + let rd = rd.to_reg(); + mem_rs_emit( + rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state, + ); + } + &Inst::Fence => { + put(sink, &enc_e(0x07e0)); + } + + &Inst::Load32 { rd, ref mem } + | &Inst::Load32ZExt8 { rd, ref mem } + | &Inst::Load32SExt8 { rd, ref mem } + | &Inst::Load32ZExt16 { rd, ref mem } + | &Inst::Load32SExt16 { rd, ref mem } + | &Inst::Load64 { rd, ref mem } + | &Inst::Load64ZExt8 { rd, ref mem } + | &Inst::Load64SExt8 { rd, ref mem } + | &Inst::Load64ZExt16 { rd, ref mem } + | &Inst::Load64SExt16 { rd, ref mem } + | &Inst::Load64ZExt32 { rd, ref mem } + | &Inst::Load64SExt32 { rd, ref mem } + | &Inst::LoadRev16 { rd, ref mem } + | &Inst::LoadRev32 { rd, ref mem } + | &Inst::LoadRev64 { rd, ref mem } => { + let mem = mem.clone(); + + let (opcode_rx, opcode_rxy, opcode_ril) = match self { + &Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), // L(Y), LRL + &Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), // LLC + &Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), // LB + &Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL + &Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL + &Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL + &Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), // LLGC + &Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), // LGB + &Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL + &Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL + &Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL + &Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL + &Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), // LRVH + &Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), // LRV + &Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), // LRVG + _ => unreachable!(), + }; + let rd = rd.to_reg(); + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state, + ); + } + + &Inst::Store8 { rd, ref mem } + | &Inst::Store16 { rd, ref mem } + | &Inst::Store32 { rd, ref mem } + | &Inst::Store64 { rd, ref mem } + | &Inst::StoreRev16 { rd, ref mem } + | &Inst::StoreRev32 { rd, ref mem } + | &Inst::StoreRev64 { rd, ref mem } => { + let mem = mem.clone(); + + let (opcode_rx, opcode_rxy, opcode_ril) = match self { + &Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), // STC(Y) + &Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL + &Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL + &Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), // STG, STGRL + &Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), // STRVH + &Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), // STRV + &Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), // STRVG + _ => unreachable!(), + }; + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state, + ); + } + &Inst::StoreImm8 { imm, ref mem } => { + let mem = mem.clone(); + + let opcode_si = 0x92; // MVI + let opcode_siy = 0xeb52; // MVIY + mem_imm8_emit( + imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state, + ); + } + &Inst::StoreImm16 { imm, ref mem } + | &Inst::StoreImm32SExt16 { imm, ref mem } + | &Inst::StoreImm64SExt16 { imm, ref mem } => { + let mem = mem.clone(); + + let opcode = match self { + &Inst::StoreImm16 { .. } => 0xe544, // MVHHI + &Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI + &Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI + _ => unreachable!(), + }; + mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state); + } + + &Inst::LoadMultiple64 { rt, rt2, ref mem } => { + let mem = mem.clone(); + + let opcode = 0xeb04; // LMG + let rt = rt.to_reg(); + let rt2 = rt2.to_reg(); + mem_rs_emit( + rt, + rt2, + &mem, + None, + Some(opcode), + true, + sink, + emit_info, + state, + ); + } + &Inst::StoreMultiple64 { rt, rt2, ref mem } => { + let mem = mem.clone(); + + let opcode = 0xeb24; // STMG + mem_rs_emit( + rt, + rt2, + &mem, + None, + Some(opcode), + true, + sink, + emit_info, + state, + ); + } + + &Inst::LoadAddr { rd, ref mem } => { + let mem = mem.clone(); + + let opcode_rx = Some(0x41); // LA + let opcode_rxy = Some(0xe371); // LAY + let opcode_ril = Some(0xc00); // LARL + let rd = rd.to_reg(); + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state, + ); + } + + &Inst::Mov64 { rd, rm } => { + let opcode = 0xb904; // LGR + put(sink, &enc_rre(opcode, rd.to_reg(), rm)); + } + &Inst::MovPReg { rd, rm } => { + Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state); + } + &Inst::Mov32 { rd, rm } => { + let opcode = 0x18; // LR + put(sink, &enc_rr(opcode, rd.to_reg(), rm)); + } + &Inst::Mov32Imm { rd, imm } => { + let opcode = 0xc09; // IILF + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm)); + } + &Inst::Mov32SImm16 { rd, imm } => { + let opcode = 0xa78; // LHI + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16)); + } + &Inst::Mov64SImm16 { rd, imm } => { + let opcode = 0xa79; // LGHI + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16)); + } + &Inst::Mov64SImm32 { rd, imm } => { + let opcode = 0xc01; // LGFI + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32)); + } + &Inst::CMov32 { rd, cond, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xb9f2; // LOCR + put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0)); + } + &Inst::CMov64 { rd, cond, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xb9e2; // LOCGR + put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0)); + } + &Inst::CMov32SImm16 { rd, cond, ri, imm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xec42; // LOCHI + put( + sink, + &enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()), + ); + } + &Inst::CMov64SImm16 { rd, cond, ri, imm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xec46; // LOCGHI + put( + sink, + &enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()), + ); + } + &Inst::Mov64UImm16Shifted { rd, imm } => { + let opcode = match imm.shift { + 0 => 0xa5f, // LLILL + 1 => 0xa5e, // LLILH + 2 => 0xa5d, // LLIHL + 3 => 0xa5c, // LLIHH + _ => unreachable!(), + }; + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits)); + } + &Inst::Mov64UImm32Shifted { rd, imm } => { + let opcode = match imm.shift { + 0 => 0xc0f, // LLILF + 1 => 0xc0e, // LLIHF + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits)); + } + &Inst::Insert64UImm16Shifted { rd, ri, imm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match imm.shift { + 0 => 0xa53, // IILL + 1 => 0xa52, // IILH + 2 => 0xa51, // IIHL + 3 => 0xa50, // IIHH + _ => unreachable!(), + }; + put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits)); + } + &Inst::Insert64UImm32Shifted { rd, ri, imm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match imm.shift { + 0 => 0xc09, // IILF + 1 => 0xc08, // IIHF + _ => unreachable!(), + }; + put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits)); + } + &Inst::LoadAR { rd, ar } => { + let opcode = 0xb24f; // EAR + put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar))); + } + + &Inst::InsertAR { rd, ri, ar } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xb24f; // EAR + put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar))); + } + &Inst::LoadSymbolReloc { + rd, + ref symbol_reloc, + } => { + let opcode = 0xa75; // BRAS + let reg = writable_spilltmp_reg().to_reg(); + put(sink, &enc_ri_b(opcode, reg, 12)); + let (reloc, name, offset) = match &**symbol_reloc { + SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset), + SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0), + }; + sink.add_reloc(reloc, name, offset); + sink.put8(0); + let inst = Inst::Load64 { + rd, + mem: MemArg::reg(reg, MemFlags::trusted()), + }; + inst.emit(sink, emit_info, state); + } + + &Inst::FpuMove32 { rd, rn } => { + if is_fpr(rd.to_reg()) && is_fpr(rn) { + let opcode = 0x38; // LER + put(sink, &enc_rr(opcode, rd.to_reg(), rn)); + } else { + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0)); + } + } + &Inst::FpuMove64 { rd, rn } => { + if is_fpr(rd.to_reg()) && is_fpr(rn) { + let opcode = 0x28; // LDR + put(sink, &enc_rr(opcode, rd.to_reg(), rn)); + } else { + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0)); + } + } + &Inst::FpuCMov32 { rd, cond, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + if is_fpr(rd.to_reg()) && is_fpr(rm) { + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2)); + let opcode = 0x38; // LER + put(sink, &enc_rr(opcode, rd.to_reg(), rm)); + } else { + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6)); + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0)); + } + } + &Inst::FpuCMov64 { rd, cond, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + if is_fpr(rd.to_reg()) && is_fpr(rm) { + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 2)); + let opcode = 0x28; // LDR + put(sink, &enc_rr(opcode, rd.to_reg(), rm)); + } else { + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6)); + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0)); + } + } + &Inst::LoadFpuConst32 { rd, const_data } => { + let opcode = 0xa75; // BRAS + let reg = writable_spilltmp_reg().to_reg(); + put(sink, &enc_ri_b(opcode, reg, 8)); + sink.put4(const_data.swap_bytes()); + let inst = Inst::VecLoadLaneUndef { + size: 32, + rd, + mem: MemArg::reg(reg, MemFlags::trusted()), + lane_imm: 0, + }; + inst.emit(sink, emit_info, state); + } + &Inst::LoadFpuConst64 { rd, const_data } => { + let opcode = 0xa75; // BRAS + let reg = writable_spilltmp_reg().to_reg(); + put(sink, &enc_ri_b(opcode, reg, 12)); + sink.put8(const_data.swap_bytes()); + let inst = Inst::VecLoadLaneUndef { + size: 64, + rd, + mem: MemArg::reg(reg, MemFlags::trusted()), + lane_imm: 0, + }; + inst.emit(sink, emit_info, state); + } + &Inst::FpuRR { fpu_op, rd, rn } => { + let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op { + FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), // WFPSO, LPEBR + FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR + FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), // VFPSO + FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), // VFPSO + FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR + FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR + FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), // VFPSO + FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), // VFPSO + FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR + FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR + FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), // VFPSO + FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), // VFPSO + FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR + FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR + FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), // VFSQ + FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), // VFSQ + FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR + FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL + }; + if m4 == 8 && is_fpr(rd.to_reg()) && is_fpr(rn) { + put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn)); + } else { + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5)); + } + } + &Inst::FpuRRR { fpu_op, rd, rn, rm } => { + let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op { + FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), // WFA, AEBR + FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR + FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), // VFA + FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), // VFA + FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR + FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR + FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), // VFS + FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), // VFS + FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR + FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR + FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), // VFM + FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), // VFM + FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR + FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR + FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), // VFD + FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), // VFD + FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), // WFMAX + FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), // WFMAX + FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), // VFMAX + FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), // VFMAX + FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), // WFMIN + FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), // WFMIN + FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), // VFMIN + FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), // VFMIN + FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), // WFMAX + FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), // WFMAX + FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX + FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX + FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), // WFMIN + FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), // WFMIN + FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN + FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN + }; + if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm) + { + put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm)); + } else { + put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6)); + } + } + &Inst::FpuRRRR { + fpu_op, + rd, + rn, + rm, + ra, + } => { + let (opcode, m5, m6, opcode_fpr) = match fpu_op { + FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), // WFMA, MAEBR + FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR + FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), // VFMA + FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), // VFMA + FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR + FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR + FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), // VFMS + FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), // VFMS + }; + if m5 == 8 && rd.to_reg() == ra && is_fpr(rn) && is_fpr(rm) && is_fpr(ra) { + put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn)); + } else { + put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6)); + } + } + &Inst::FpuRound { op, mode, rd, rn } => { + let mode = match mode { + FpuRoundMode::Current => 0, + FpuRoundMode::ToNearest => 1, + FpuRoundMode::ShorterPrecision => 3, + FpuRoundMode::ToNearestTiesToEven => 4, + FpuRoundMode::ToZero => 5, + FpuRoundMode::ToPosInfinity => 6, + FpuRoundMode::ToNegInfinity => 7, + }; + let (opcode, m3, m4, opcode_fpr) = match op { + FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), // WFLR, LEDBR(A) + FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), // VFLR + FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), // WFI, FIEBR + FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), // WFI, FIDBR + FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), // VFI + FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), // VFI + FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), // WCSFP + FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), // WCSFP + FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), // WCLFP + FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), // WCLFP + FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), // VCSFP + FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), // VCSFP + FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), // VCLFP + FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), // VCLFP + FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), // WCFPS + FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), // WCFPS + FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), // WCFPL + FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), // WCFPL + FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), // VCFPS + FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), // VCFPS + FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), // VCFPL + FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), // VCFPL + }; + if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) { + put( + sink, + &enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0), + ); + } else { + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode)); + } + } + &Inst::FpuCmp32 { rn, rm } => { + if is_fpr(rn) && is_fpr(rm) { + let opcode = 0xb309; // CEBR + put(sink, &enc_rre(opcode, rn, rm)); + } else { + let opcode = 0xe7cb; // WFC + put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0)); + } + } + &Inst::FpuCmp64 { rn, rm } => { + if is_fpr(rn) && is_fpr(rm) { + let opcode = 0xb319; // CDBR + put(sink, &enc_rre(opcode, rn, rm)); + } else { + let opcode = 0xe7cb; // WFC + put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0)); + } + } + + &Inst::VecRRR { op, rd, rn, rm } => { + let (opcode, m4) = match op { + VecBinaryOp::Add8x16 => (0xe7f3, 0), // VAB + VecBinaryOp::Add16x8 => (0xe7f3, 1), // VAH + VecBinaryOp::Add32x4 => (0xe7f3, 2), // VAF + VecBinaryOp::Add64x2 => (0xe7f3, 3), // VAG + VecBinaryOp::Add128 => (0xe7f3, 4), // VAQ + VecBinaryOp::Sub8x16 => (0xe7f7, 0), // VSB + VecBinaryOp::Sub16x8 => (0xe7f7, 1), // VSH + VecBinaryOp::Sub32x4 => (0xe7f7, 2), // VSF + VecBinaryOp::Sub64x2 => (0xe7f7, 3), // VSG + VecBinaryOp::Sub128 => (0xe7f7, 4), // VSQ + VecBinaryOp::Mul8x16 => (0xe7a2, 0), // VMLB + VecBinaryOp::Mul16x8 => (0xe7a2, 1), // VMLHW + VecBinaryOp::Mul32x4 => (0xe7a2, 2), // VMLF + VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), // VMLHB + VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), // VMLHH + VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), // VMLHF + VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), // VMHB + VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), // VMHH + VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), // VMHF + VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), // VMLEB + VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), // VMLEH + VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), // VMLEF + VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), // VMEB + VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), // VMEH + VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), // VMEF + VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), // VMLOB + VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), // VMLOH + VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), // VMLOF + VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), // VMOB + VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), // VMOH + VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), // VMOF + VecBinaryOp::UMax8x16 => (0xe7fd, 0), // VMXLB + VecBinaryOp::UMax16x8 => (0xe7fd, 1), // VMXLH + VecBinaryOp::UMax32x4 => (0xe7fd, 2), // VMXLF + VecBinaryOp::UMax64x2 => (0xe7fd, 3), // VMXLG + VecBinaryOp::SMax8x16 => (0xe7ff, 0), // VMXB + VecBinaryOp::SMax16x8 => (0xe7ff, 1), // VMXH + VecBinaryOp::SMax32x4 => (0xe7ff, 2), // VMXF + VecBinaryOp::SMax64x2 => (0xe7ff, 3), // VMXG + VecBinaryOp::UMin8x16 => (0xe7fc, 0), // VMNLB + VecBinaryOp::UMin16x8 => (0xe7fc, 1), // VMNLH + VecBinaryOp::UMin32x4 => (0xe7fc, 2), // VMNLF + VecBinaryOp::UMin64x2 => (0xe7fc, 3), // VMNLG + VecBinaryOp::SMin8x16 => (0xe7fe, 0), // VMNB + VecBinaryOp::SMin16x8 => (0xe7fe, 1), // VMNH + VecBinaryOp::SMin32x4 => (0xe7fe, 2), // VMNF + VecBinaryOp::SMin64x2 => (0xe7fe, 3), // VMNG + VecBinaryOp::UAvg8x16 => (0xe7f0, 0), // VAVGLB + VecBinaryOp::UAvg16x8 => (0xe7f0, 1), // VAVGLH + VecBinaryOp::UAvg32x4 => (0xe7f0, 2), // VAVGLF + VecBinaryOp::UAvg64x2 => (0xe7f0, 3), // VAVGLG + VecBinaryOp::SAvg8x16 => (0xe7f2, 0), // VAVGB + VecBinaryOp::SAvg16x8 => (0xe7f2, 1), // VAVGH + VecBinaryOp::SAvg32x4 => (0xe7f2, 2), // VAVGF + VecBinaryOp::SAvg64x2 => (0xe7f2, 3), // VAVGG + VecBinaryOp::And128 => (0xe768, 0), // VN + VecBinaryOp::Orr128 => (0xe76a, 0), // VO + VecBinaryOp::Xor128 => (0xe76d, 0), // VX + VecBinaryOp::NotAnd128 => (0xe76e, 0), // VNN + VecBinaryOp::NotOrr128 => (0xe76b, 0), // VNO + VecBinaryOp::NotXor128 => (0xe76c, 0), // VNX + VecBinaryOp::AndNot128 => (0xe769, 0), // VNC + VecBinaryOp::OrrNot128 => (0xe76f, 0), // VOC + VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM + VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB + VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB + VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB + VecBinaryOp::LShLByBit128 => (0xe774, 0), // VSL + VecBinaryOp::LShRByBit128 => (0xe77c, 0), // VSRL + VecBinaryOp::AShRByBit128 => (0xe77e, 0), // VSRA + VecBinaryOp::Pack16x8 => (0xe794, 1), // VPKH + VecBinaryOp::Pack32x4 => (0xe794, 2), // VPKF + VecBinaryOp::Pack64x2 => (0xe794, 3), // VPKG + VecBinaryOp::PackUSat16x8 => (0xe795, 1), // VPKLSH + VecBinaryOp::PackUSat32x4 => (0xe795, 2), // VPKLSF + VecBinaryOp::PackUSat64x2 => (0xe795, 3), // VPKLSG + VecBinaryOp::PackSSat16x8 => (0xe797, 1), // VPKSH + VecBinaryOp::PackSSat32x4 => (0xe797, 2), // VPKSF + VecBinaryOp::PackSSat64x2 => (0xe797, 3), // VPKSG + VecBinaryOp::MergeLow8x16 => (0xe760, 0), // VMRLB + VecBinaryOp::MergeLow16x8 => (0xe760, 1), // VMRLH + VecBinaryOp::MergeLow32x4 => (0xe760, 2), // VMRLF + VecBinaryOp::MergeLow64x2 => (0xe760, 3), // VMRLG + VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB + VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH + VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF + VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG + }; + + put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0)); + } + &Inst::VecRR { op, rd, rn } => { + let (opcode, m3) = match op { + VecUnaryOp::Abs8x16 => (0xe7df, 0), // VLPB + VecUnaryOp::Abs16x8 => (0xe7df, 1), // VLPH + VecUnaryOp::Abs32x4 => (0xe7df, 2), // VLPF + VecUnaryOp::Abs64x2 => (0xe7df, 3), // VLPG + VecUnaryOp::Neg8x16 => (0xe7de, 0), // VLCB + VecUnaryOp::Neg16x8 => (0xe7de, 1), // VLCH + VecUnaryOp::Neg32x4 => (0xe7de, 2), // VLCF + VecUnaryOp::Neg64x2 => (0xe7de, 3), // VLCG + VecUnaryOp::Popcnt8x16 => (0xe750, 0), // VPOPCTB + VecUnaryOp::Popcnt16x8 => (0xe750, 1), // VPOPCTH + VecUnaryOp::Popcnt32x4 => (0xe750, 2), // VPOPCTF + VecUnaryOp::Popcnt64x2 => (0xe750, 3), // VPOPCTG + VecUnaryOp::Clz8x16 => (0xe753, 0), // VCLZB + VecUnaryOp::Clz16x8 => (0xe753, 1), // VCLZH + VecUnaryOp::Clz32x4 => (0xe753, 2), // VCLZF + VecUnaryOp::Clz64x2 => (0xe753, 3), // VCLZG + VecUnaryOp::Ctz8x16 => (0xe752, 0), // VCTZB + VecUnaryOp::Ctz16x8 => (0xe752, 1), // VCTZH + VecUnaryOp::Ctz32x4 => (0xe752, 2), // VCTZF + VecUnaryOp::Ctz64x2 => (0xe752, 3), // VCTZG + VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), // VUPLLB + VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), // VUPLLH + VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), // VUPLLF + VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB + VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH + VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF + VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), // VUPLB + VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), // VUPLH + VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), // VUPLF + VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB + VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH + VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF + }; + + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0)); + } + &Inst::VecShiftRR { + shift_op, + rd, + rn, + shift_imm, + shift_reg, + } => { + let (opcode, m4) = match shift_op { + VecShiftOp::RotL8x16 => (0xe733, 0), // VERLLB + VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH + VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF + VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG + VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB + VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH + VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF + VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG + VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB + VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH + VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF + VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG + VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB + VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH + VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF + VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG + }; + put( + sink, + &enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4), + ); + } + &Inst::VecSelect { rd, rn, rm, ra } => { + let opcode = 0xe78d; // VSEL + put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0)); + } + &Inst::VecPermute { rd, rn, rm, ra } => { + let opcode = 0xe78c; // VPERM + put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0)); + } + &Inst::VecPermuteDWImm { + rd, + rn, + rm, + idx1, + idx2, + } => { + let m4 = (idx1 & 1) * 4 + (idx2 & 1); + + let opcode = 0xe784; // VPDI + put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0)); + } + &Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => { + let (opcode, m4) = match op { + VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), // VCEQB + VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), // VCEQH + VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), // VCEQF + VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), // VCEQG + VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB + VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH + VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG + VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG + VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB + VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH + VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG + VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG + }; + let m5 = match self { + &Inst::VecIntCmp { .. } => 0, + &Inst::VecIntCmpS { .. } => 1, + _ => unreachable!(), + }; + + put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5)); + } + &Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => { + let (opcode, m4) = match op { + VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), // VFCESB + VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), // VFCEDB + VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), // VFCHSB + VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), // VFCHDB + VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB + VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB + }; + let m6 = match self { + &Inst::VecFloatCmp { .. } => 0, + &Inst::VecFloatCmpS { .. } => 1, + _ => unreachable!(), + }; + + put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6)); + } + &Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => { + // Synthetic instruction to compare 128-bit values. + // Sets CC 1 if rn > rm, sets a different CC otherwise. + + // Use VECTOR ELEMENT COMPARE to compare the high parts. + // Swap the inputs to get: + // CC 1 if high(rn) > high(rm) + // CC 2 if high(rn) < high(rm) + // CC 0 if high(rn) == high(rm) + let (opcode, m3) = match self { + &Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG + &Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG + _ => unreachable!(), + }; + put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0)); + + // If CC != 0, we'd done, so jump over the next instruction. + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, 7, 4 + 6)); + + // Otherwise, use VECTOR COMPARE HIGH LOGICAL. + // Since we already know the high parts are equal, the CC + // result will only depend on the low parts: + // CC 1 if low(rn) > low(rm) + // CC 3 if low(rn) <= low(rm) + let inst = Inst::VecIntCmpS { + op: VecIntCmpOp::UCmpHi64x2, + // N.B.: This is the first write to tmp, and it happens + // after all uses of rn and rm. If this were to ever + // change, tmp would have to become an early-def. + rd: tmp, + rn, + rm, + }; + inst.emit(sink, emit_info, state); + } + + &Inst::VecLoad { rd, ref mem } + | &Inst::VecLoadRev { rd, ref mem } + | &Inst::VecLoadByte16Rev { rd, ref mem } + | &Inst::VecLoadByte32Rev { rd, ref mem } + | &Inst::VecLoadByte64Rev { rd, ref mem } + | &Inst::VecLoadElt16Rev { rd, ref mem } + | &Inst::VecLoadElt32Rev { rd, ref mem } + | &Inst::VecLoadElt64Rev { rd, ref mem } => { + let mem = mem.clone(); + + let (opcode, m3) = match self { + &Inst::VecLoad { .. } => (0xe706, 0), // VL + &Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ + &Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH + &Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF + &Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG + &Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH + &Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF + &Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG + _ => unreachable!(), + }; + mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state); + } + &Inst::VecStore { rd, ref mem } + | &Inst::VecStoreRev { rd, ref mem } + | &Inst::VecStoreByte16Rev { rd, ref mem } + | &Inst::VecStoreByte32Rev { rd, ref mem } + | &Inst::VecStoreByte64Rev { rd, ref mem } + | &Inst::VecStoreElt16Rev { rd, ref mem } + | &Inst::VecStoreElt32Rev { rd, ref mem } + | &Inst::VecStoreElt64Rev { rd, ref mem } => { + let mem = mem.clone(); + + let (opcode, m3) = match self { + &Inst::VecStore { .. } => (0xe70e, 0), // VST + &Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ + &Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH + &Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF + &Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG + &Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH + &Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF + &Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG + _ => unreachable!(), + }; + mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state); + } + &Inst::VecLoadReplicate { size, rd, ref mem } + | &Inst::VecLoadReplicateRev { size, rd, ref mem } => { + let mem = mem.clone(); + + let (opcode, m3) = match (self, size) { + (&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), // VLREPB + (&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH + (&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF + (&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG + (&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH + (&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF + (&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG + _ => unreachable!(), + }; + mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state); + } + + &Inst::VecMov { rd, rn } => { + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, 0, 0, 0)); + } + &Inst::VecCMov { rd, cond, ri, rm } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = 0xa74; // BCR + put(sink, &enc_ri_c(opcode, cond.invert().bits(), 4 + 6)); + let opcode = 0xe756; // VLR + put(sink, &enc_vrr_a(opcode, rd.to_reg(), rm, 0, 0, 0)); + } + &Inst::MovToVec128 { rd, rn, rm } => { + let opcode = 0xe762; // VLVGP + put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm)); + } + &Inst::VecLoadConst { rd, const_data } => { + let opcode = 0xa75; // BRAS + let reg = writable_spilltmp_reg().to_reg(); + put(sink, &enc_ri_b(opcode, reg, 20)); + for i in const_data.to_be_bytes().iter() { + sink.put1(*i); + } + let inst = Inst::VecLoad { + rd, + mem: MemArg::reg(reg, MemFlags::trusted()), + }; + inst.emit(sink, emit_info, state); + } + &Inst::VecLoadConstReplicate { + size, + rd, + const_data, + } => { + let opcode = 0xa75; // BRAS + let reg = writable_spilltmp_reg().to_reg(); + put(sink, &enc_ri_b(opcode, reg, (4 + size / 8) as i32)); + for i in 0..size / 8 { + sink.put1((const_data >> (size - 8 - 8 * i)) as u8); + } + let inst = Inst::VecLoadReplicate { + size, + rd, + mem: MemArg::reg(reg, MemFlags::trusted()), + }; + inst.emit(sink, emit_info, state); + } + &Inst::VecImmByteMask { rd, mask } => { + let opcode = 0xe744; // VGBM + put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0)); + } + &Inst::VecImmBitMask { + size, + rd, + start_bit, + end_bit, + } => { + let (opcode, m4) = match size { + 8 => (0xe746, 0), // VGMB + 16 => (0xe746, 1), // VGMH + 32 => (0xe746, 2), // VGMF + 64 => (0xe746, 3), // VGMG + _ => unreachable!(), + }; + put( + sink, + &enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4), + ); + } + &Inst::VecImmReplicate { size, rd, imm } => { + let (opcode, m3) = match size { + 8 => (0xe745, 0), // VREPIB + 16 => (0xe745, 1), // VREPIH + 32 => (0xe745, 2), // VREPIF + 64 => (0xe745, 3), // VREPIG + _ => unreachable!(), + }; + put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3)); + } + &Inst::VecLoadLane { + size, + rd, + ri, + ref mem, + lane_imm, + } + | &Inst::VecLoadLaneRev { + size, + rd, + ri, + ref mem, + lane_imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + let mem = mem.clone(); + + let opcode_vrx = match (self, size) { + (&Inst::VecLoadLane { .. }, 8) => 0xe700, // VLEB + (&Inst::VecLoadLane { .. }, 16) => 0xe701, // VLEH + (&Inst::VecLoadLane { .. }, 32) => 0xe703, // VLEF + (&Inst::VecLoadLane { .. }, 64) => 0xe702, // VLEG + (&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH + (&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF + (&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG + _ => unreachable!(), + }; + + let rd = rd.to_reg(); + mem_vrx_emit( + rd, + &mem, + opcode_vrx, + lane_imm.into(), + true, + sink, + emit_info, + state, + ); + } + &Inst::VecLoadLaneUndef { + size, + rd, + ref mem, + lane_imm, + } + | &Inst::VecLoadLaneRevUndef { + size, + rd, + ref mem, + lane_imm, + } => { + let mem = mem.clone(); + + let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) { + (&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), // VLEB + (&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH + (&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y) + (&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y) + (&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH + (&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF + (&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG + _ => unreachable!(), + }; + + let rd = rd.to_reg(); + if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() { + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state, + ); + } else { + mem_vrx_emit( + rd, + &mem, + opcode_vrx, + lane_imm.into(), + true, + sink, + emit_info, + state, + ); + } + } + &Inst::VecStoreLane { + size, + rd, + ref mem, + lane_imm, + } + | &Inst::VecStoreLaneRev { + size, + rd, + ref mem, + lane_imm, + } => { + let mem = mem.clone(); + + let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) { + (&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), // VSTEB + (&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH + (&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y) + (&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y) + (&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH + (&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF + (&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG + _ => unreachable!(), + }; + + if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() { + mem_emit( + rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state, + ); + } else { + mem_vrx_emit( + rd, + &mem, + opcode_vrx, + lane_imm.into(), + true, + sink, + emit_info, + state, + ); + } + } + &Inst::VecInsertLane { + size, + rd, + ri, + rn, + lane_imm, + lane_reg, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let (opcode_vrs, m4) = match size { + 8 => (0xe722, 0), // VLVGB + 16 => (0xe722, 1), // VLVGH + 32 => (0xe722, 2), // VLVGF + 64 => (0xe722, 3), // VLVGG + _ => unreachable!(), + }; + put( + sink, + &enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4), + ); + } + &Inst::VecInsertLaneUndef { + size, + rd, + rn, + lane_imm, + lane_reg, + } => { + let (opcode_vrs, m4, opcode_rre) = match size { + 8 => (0xe722, 0, None), // VLVGB + 16 => (0xe722, 1, None), // VLVGH + 32 => (0xe722, 2, None), // VLVGF + 64 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR + _ => unreachable!(), + }; + if opcode_rre.is_some() + && lane_imm == 0 + && lane_reg == zero_reg() + && is_fpr(rd.to_reg()) + { + put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn)); + } else { + put( + sink, + &enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4), + ); + } + } + &Inst::VecExtractLane { + size, + rd, + rn, + lane_imm, + lane_reg, + } => { + let (opcode_vrs, m4, opcode_rre) = match size { + 8 => (0xe721, 0, None), // VLGVB + 16 => (0xe721, 1, None), // VLGVH + 32 => (0xe721, 2, None), // VLGVF + 64 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR + _ => unreachable!(), + }; + if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) { + put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn)); + } else { + put( + sink, + &enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4), + ); + } + } + &Inst::VecInsertLaneImm { + size, + rd, + ri, + imm, + lane_imm, + } => { + debug_assert_eq!(rd.to_reg(), ri); + + let opcode = match size { + 8 => 0xe740, // VLEIB + 16 => 0xe741, // LEIVH + 32 => 0xe743, // VLEIF + 64 => 0xe742, // VLEIG + _ => unreachable!(), + }; + put( + sink, + &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm.into()), + ); + } + &Inst::VecReplicateLane { + size, + rd, + rn, + lane_imm, + } => { + let (opcode, m4) = match size { + 8 => (0xe74d, 0), // VREPB + 16 => (0xe74d, 1), // VREPH + 32 => (0xe74d, 2), // VREPF + 64 => (0xe74d, 3), // VREPG + _ => unreachable!(), + }; + put( + sink, + &enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4), + ); + } + + &Inst::AllocateArgs { size } => { + let inst = if let Ok(size) = i16::try_from(size) { + Inst::AluRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_stack_reg(), + ri: stack_reg(), + imm: -size, + } + } else { + Inst::AluRUImm32 { + alu_op: ALUOp::SubLogical64, + rd: writable_stack_reg(), + ri: stack_reg(), + imm: size, + } + }; + inst.emit(sink, emit_info, state); + state.nominal_sp_offset += size; + } + &Inst::Call { link, ref info } => { + let opcode = 0xc05; // BRASL + + // Add relocation for target function. This has to be done *before* + // the S390xTlsGdCall relocation if any, to ensure linker relaxation + // works correctly. + let offset = sink.cur_offset() + 2; + sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &info.dest, 2); + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset() + 6; + sink.push_user_stack_map(state, offset, s); + } + + put(sink, &enc_ril_b(opcode, link.to_reg(), 0)); + sink.add_call_site(); + + state.nominal_sp_offset -= info.callee_pop_size; + } + &Inst::CallInd { link, ref info } => { + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset() + 2; + sink.push_user_stack_map(state, offset, s); + } + + let opcode = 0x0d; // BASR + put(sink, &enc_rr(opcode, link.to_reg(), info.dest)); + sink.add_call_site(); + + state.nominal_sp_offset -= info.callee_pop_size; + } + &Inst::ReturnCall { ref info } => { + for inst in S390xMachineDeps::gen_tail_epilogue( + state.frame_layout(), + info.callee_pop_size, + None, + ) { + inst.emit(sink, emit_info, state); + } + + let opcode = 0xc04; // BCRL + let offset = sink.cur_offset() + 2; + sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &info.dest, 2); + put(sink, &enc_ril_c(opcode, 15, 0)); + sink.add_call_site(); + } + &Inst::ReturnCallInd { ref info } => { + let mut rn = info.dest; + for inst in S390xMachineDeps::gen_tail_epilogue( + state.frame_layout(), + info.callee_pop_size, + Some(&mut rn), + ) { + inst.emit(sink, emit_info, state); + } + + let opcode = 0x07; // BCR + put(sink, &enc_rr(opcode, gpr(15), rn)); + sink.add_call_site(); + } + &Inst::ElfTlsGetOffset { ref symbol, .. } => { + let opcode = 0xc05; // BRASL + + // Add relocation for target function. This has to be done + // *before* the S390xTlsGdCall, to ensure linker relaxation + // works correctly. + let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset); + let offset = sink.cur_offset() + 2; + sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2); + match &**symbol { + SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0), + _ => unreachable!(), + } + + put(sink, &enc_ril_b(opcode, gpr(14), 0)); + sink.add_call_site(); + } + &Inst::Args { .. } => {} + &Inst::Rets { .. } => {} + &Inst::Ret { link } => { + let opcode = 0x07; // BCR + put(sink, &enc_rr(opcode, gpr(15), link)); + } + &Inst::Jump { dest } => { + let off = sink.cur_offset(); + // Indicate that the jump uses a label, if so, so that a fixup can occur later. + sink.use_label_at_offset(off, dest, LabelUse::BranchRIL); + sink.add_uncond_branch(off, off + 6, dest); + // Emit the jump itself. + let opcode = 0xc04; // BCRL + put(sink, &enc_ril_c(opcode, 15, 0)); + } + &Inst::IndirectBr { rn, .. } => { + let opcode = 0x07; // BCR + put(sink, &enc_rr(opcode, gpr(15), rn)); + } + &Inst::CondBr { + taken, + not_taken, + cond, + } => { + let opcode = 0xc04; // BCRL + + // Conditional part first. + let cond_off = sink.cur_offset(); + sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL); + let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0); + sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted); + put(sink, &enc_ril_c(opcode, cond.bits(), 0)); + + // Unconditional part next. + let uncond_off = sink.cur_offset(); + sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL); + sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken); + put(sink, &enc_ril_c(opcode, 15, 0)); + } + &Inst::OneWayCondBr { target, cond } => { + let opcode = 0xc04; // BCRL + sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL); + put(sink, &enc_ril_c(opcode, cond.bits(), 0)); + } + &Inst::Nop0 => {} + &Inst::Nop2 => { + put(sink, &enc_e(0x0707)); + } + &Inst::Debugtrap => { + put(sink, &enc_e(0x0001)); + } + &Inst::Trap { trap_code } => { + put_with_trap(sink, &enc_e(0x0000), trap_code); + } + &Inst::TrapIf { cond, trap_code } => { + // We implement a TrapIf as a conditional branch into the middle + // of the branch (BRCL) instruction itself - those middle two bytes + // are zero, which matches the trap instruction itself. + let opcode = 0xc04; // BCRL + let enc = &enc_ril_c(opcode, cond.bits(), 2); + debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0); + // The trap must be placed on the last byte of the embedded trap + // instruction, so we need to emit the encoding in two parts. + put_with_trap(sink, &enc[0..4], trap_code); + put(sink, &enc[4..6]); + } + &Inst::JTSequence { ridx, ref targets } => { + let table_label = sink.get_label(); + + // This sequence is *one* instruction in the vcode, and is expanded only here at + // emission time, because we cannot allow the regalloc to insert spills/reloads in + // the middle; we depend on hardcoded PC-rel addressing below. + + // Set temp register to address of jump table. + let rtmp = writable_spilltmp_reg(); + let inst = Inst::LoadAddr { + rd: rtmp, + mem: MemArg::Label { + target: table_label, + }, + }; + inst.emit(sink, emit_info, state); + + // Set temp to target address by adding the value of the jump table entry. + let inst = Inst::AluRX { + alu_op: ALUOp::Add64Ext32, + rd: rtmp, + ri: rtmp.to_reg(), + mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()), + }; + inst.emit(sink, emit_info, state); + + // Branch to computed address. (`targets` here is only used for successor queries + // and is not needed for emission.) + let inst = Inst::IndirectBr { + rn: rtmp.to_reg(), + targets: vec![], + }; + inst.emit(sink, emit_info, state); + + // Emit jump table (table of 32-bit offsets). + sink.bind_label(table_label, &mut state.ctrl_plane); + let jt_off = sink.cur_offset(); + for &target in targets.iter() { + let word_off = sink.cur_offset(); + let off_into_table = word_off - jt_off; + sink.use_label_at_offset(word_off, target, LabelUse::PCRel32); + sink.put4(off_into_table.swap_bytes()); + } + + // Lowering produces an EmitIsland before using a JTSequence, so we can safely + // disable the worst-case-size check in this case. + start_off = sink.cur_offset(); + } + + Inst::StackProbeLoop { + probe_count, + guard_size, + } => { + // Emit the loop start label + let loop_start = sink.get_label(); + sink.bind_label(loop_start, state.ctrl_plane_mut()); + + // aghi %r15, -GUARD_SIZE + let inst = Inst::AluRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_stack_reg(), + ri: stack_reg(), + imm: -guard_size, + }; + inst.emit(sink, emit_info, state); + + // mvi 0(%r15), 0 + let inst = Inst::StoreImm8 { + imm: 0, + mem: MemArg::reg(stack_reg(), MemFlags::trusted()), + }; + inst.emit(sink, emit_info, state); + + // brct PROBE_COUNT, LOOP_START + let opcode = 0xa76; // BRCT + sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI); + put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0)); + } + + &Inst::Unwind { ref inst } => { + sink.add_unwind(inst.clone()); + } + + &Inst::DummyUse { .. } => {} + } + + let end_off = sink.cur_offset(); + debug_assert!((end_off - start_off) <= Inst::worst_case_size()); + + state.clear_post_insn(); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit_tests.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit_tests.rs new file mode 100644 index 00000000000000..7a5841e137074b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/emit_tests.rs @@ -0,0 +1,13361 @@ +use crate::ir::{MemFlags, TrapCode}; +use crate::isa::s390x::inst::*; +use crate::isa::s390x::settings as s390x_settings; + +#[cfg(test)] +fn simm20_zero() -> SImm20 { + SImm20::maybe_from_i64(0).unwrap() +} + +#[test] +fn test_s390x_binemit() { + let mut insns = Vec::<(Inst, &str, &str)>::new(); + + insns.push((Inst::Nop0, "", "nop-zero-len")); + insns.push((Inst::Nop2, "0707", "nop")); + + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Add32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F83012", + "ark %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E86045", + "agrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9FA3012", + "alrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9EA6045", + "algrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Sub32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F93012", + "srk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Sub64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E96045", + "sgrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9FB3012", + "slrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::SubLogical64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9EB6045", + "slgrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Mul32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9FD3012", + "msrkc %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Mul64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9ED6045", + "msgrkc %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::And32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F43012", + "nrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E46045", + "ngrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Orr32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F63012", + "ork %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E66045", + "ogrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Xor32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F73012", + "xrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E76045", + "xgrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotAnd32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9743012", + "nnrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotAnd64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9646045", + "nngrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotOrr32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9763012", + "nork %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotOrr64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9666045", + "nogrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotXor32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9773012", + "nxrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::NotXor64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9676045", + "nxgrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::AndNot32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9F53012", + "ncrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::AndNot64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9E56045", + "ncgrk %r4, %r5, %r6", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::OrrNot32, + rd: writable_gpr(1), + rn: gpr(2), + rm: gpr(3), + }, + "B9753012", + "ocrk %r1, %r2, %r3", + )); + insns.push(( + Inst::AluRRR { + alu_op: ALUOp::OrrNot64, + rd: writable_gpr(4), + rn: gpr(5), + rm: gpr(6), + }, + "B9656045", + "ocgrk %r4, %r5, %r6", + )); + + insns.push(( + Inst::AluRRSImm16 { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + imm: -32768, + }, + "EC45800000D8", + "ahik %r4, %r5, -32768", + )); + insns.push(( + Inst::AluRRSImm16 { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + imm: 32767, + }, + "EC457FFF00D8", + "ahik %r4, %r5, 32767", + )); + insns.push(( + Inst::AluRRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + imm: -32768, + }, + "EC45800000D9", + "aghik %r4, %r5, -32768", + )); + insns.push(( + Inst::AluRRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + imm: 32767, + }, + "EC457FFF00D9", + "aghik %r4, %r5, 32767", + )); + + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Add32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1A12", + "ar %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9080045", + "agr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Add64Ext32, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9180045", + "agfr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1E12", + "alr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B90A0045", + "algr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::AddLogical64Ext32, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B91A0045", + "algfr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Sub32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1B12", + "sr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Sub64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9090045", + "sgr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Sub64Ext32, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9190045", + "sgfr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1F12", + "slr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::SubLogical64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B90B0045", + "slgr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::SubLogical64Ext32, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B91B0045", + "slgfr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Mul32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "B2520012", + "msr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Mul64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B90C0045", + "msgr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Mul64Ext32, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B91C0045", + "msgfr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::And32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1412", + "nr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9800045", + "ngr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Orr32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1612", + "or %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9810045", + "ogr %r4, %r5", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Xor32, + rd: writable_gpr(1), + ri: gpr(1), + rm: gpr(2), + }, + "1712", + "xr %r1, %r2", + )); + insns.push(( + Inst::AluRR { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + ri: gpr(4), + rm: gpr(5), + }, + "B9820045", + "xgr %r4, %r5", + )); + + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "5A102000", + "a %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "4A102000", + "ah %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000005A", + "ay %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000007A", + "ahy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000008", + "ag %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add64Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000038", + "agh %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Add64Ext32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000018", + "agf %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "5E102000", + "al %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000005E", + "aly %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000000A", + "alg %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::AddLogical64Ext32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000001A", + "algf %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "5B102000", + "s %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "4B102000", + "sh %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000005B", + "sy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000007B", + "shy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000009", + "sg %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub64Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000039", + "sgh %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Sub64Ext32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000019", + "sgf %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "5F102000", + "sl %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000005F", + "sly %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::SubLogical64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000000B", + "slg %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::SubLogical64Ext32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000001B", + "slgf %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "71102000", + "ms %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "4C102000", + "mh %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000051", + "msy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul32Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000007C", + "mhy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000000C", + "msg %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul64Ext16, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000003C", + "mgh %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Mul64Ext32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000001C", + "msgf %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::And32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "54102000", + "n %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::And32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000054", + "ny %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::And64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000080", + "ng %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Orr32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "56102000", + "o %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Orr32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000056", + "oy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Orr64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000081", + "og %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Xor32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "57102000", + "x %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Xor32, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000057", + "xy %r1, 0(%r2)", + )); + insns.push(( + Inst::AluRX { + alu_op: ALUOp::Xor64, + rd: writable_gpr(1), + ri: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000082", + "xg %r1, 0(%r2)", + )); + + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Add32, + rd: writable_gpr(7), + ri: gpr(7), + imm: -32768, + }, + "A77A8000", + "ahi %r7, -32768", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Add32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 32767, + }, + "A77A7FFF", + "ahi %r7, 32767", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_gpr(7), + ri: gpr(7), + imm: -32768, + }, + "A77B8000", + "aghi %r7, -32768", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Add64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 32767, + }, + "A77B7FFF", + "aghi %r7, 32767", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Mul32, + rd: writable_gpr(7), + ri: gpr(7), + imm: -32768, + }, + "A77C8000", + "mhi %r7, -32768", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Mul32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 32767, + }, + "A77C7FFF", + "mhi %r7, 32767", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Mul64, + rd: writable_gpr(7), + ri: gpr(7), + imm: -32768, + }, + "A77D8000", + "mghi %r7, -32768", + )); + insns.push(( + Inst::AluRSImm16 { + alu_op: ALUOp::Mul64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 32767, + }, + "A77D7FFF", + "mghi %r7, 32767", + )); + + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Add32, + rd: writable_gpr(7), + ri: gpr(7), + imm: -2147483648, + }, + "C27980000000", + "afi %r7, -2147483648", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Add32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 2147483647, + }, + "C2797FFFFFFF", + "afi %r7, 2147483647", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Mul32, + rd: writable_gpr(7), + ri: gpr(7), + imm: -2147483648, + }, + "C27180000000", + "msfi %r7, -2147483648", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Mul32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 2147483647, + }, + "C2717FFFFFFF", + "msfi %r7, 2147483647", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Add64, + rd: writable_gpr(7), + ri: gpr(7), + imm: -2147483648, + }, + "C27880000000", + "agfi %r7, -2147483648", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Add64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 2147483647, + }, + "C2787FFFFFFF", + "agfi %r7, 2147483647", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Mul64, + rd: writable_gpr(7), + ri: gpr(7), + imm: -2147483648, + }, + "C27080000000", + "msgfi %r7, -2147483648", + )); + insns.push(( + Inst::AluRSImm32 { + alu_op: ALUOp::Mul64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 2147483647, + }, + "C2707FFFFFFF", + "msgfi %r7, 2147483647", + )); + + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 0, + }, + "C27B00000000", + "alfi %r7, 0", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 4294967295, + }, + "C27BFFFFFFFF", + "alfi %r7, 4294967295", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 0, + }, + "C27500000000", + "slfi %r7, 0", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::SubLogical32, + rd: writable_gpr(7), + ri: gpr(7), + imm: 4294967295, + }, + "C275FFFFFFFF", + "slfi %r7, 4294967295", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 0, + }, + "C27A00000000", + "algfi %r7, 0", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 4294967295, + }, + "C27AFFFFFFFF", + "algfi %r7, 4294967295", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::SubLogical64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 0, + }, + "C27400000000", + "slgfi %r7, 0", + )); + insns.push(( + Inst::AluRUImm32 { + alu_op: ALUOp::SubLogical64, + rd: writable_gpr(7), + ri: gpr(7), + imm: 4294967295, + }, + "C274FFFFFFFF", + "slgfi %r7, 4294967295", + )); + + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff).unwrap(), + }, + "A587FFFF", + "nill %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000).unwrap(), + }, + "A586FFFF", + "nilh %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(), + }, + "A587FFFF", + "nill %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(), + }, + "A586FFFF", + "nilh %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(), + }, + "A585FFFF", + "nihl %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000_0000_0000).unwrap(), + }, + "A584FFFF", + "nihh %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff).unwrap(), + }, + "A58BFFFF", + "oill %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000).unwrap(), + }, + "A58AFFFF", + "oilh %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(), + }, + "A58BFFFF", + "oill %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(), + }, + "A58AFFFF", + "oilh %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(), + }, + "A589FFFF", + "oihl %r8, 65535", + )); + insns.push(( + Inst::AluRUImm16Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000_0000_0000).unwrap(), + }, + "A588FFFF", + "oihh %r8, 65535", + )); + + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::And32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff).unwrap(), + }, + "C08BFFFFFFFF", + "nilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0x0000_0000_ffff_ffff).unwrap(), + }, + "C08BFFFFFFFF", + "nilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::And64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff_0000_0000).unwrap(), + }, + "C08AFFFFFFFF", + "nihf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Orr32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff).unwrap(), + }, + "C08DFFFFFFFF", + "oilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0x0000_0000_ffff_ffff).unwrap(), + }, + "C08DFFFFFFFF", + "oilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Orr64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff_0000_0000).unwrap(), + }, + "C08CFFFFFFFF", + "oihf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Xor32, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff).unwrap(), + }, + "C087FFFFFFFF", + "xilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Xor64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0x0000_0000_ffff_ffff).unwrap(), + }, + "C087FFFFFFFF", + "xilf %r8, 4294967295", + )); + insns.push(( + Inst::AluRUImm32Shifted { + alu_op: ALUOp::Xor64, + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff_0000_0000).unwrap(), + }, + "C086FFFFFFFF", + "xihf %r8, 4294967295", + )); + + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Abs32, + rd: writable_gpr(1), + rn: gpr(10), + }, + "101A", + "lpr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Abs64, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B900001A", + "lpgr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Abs64Ext32, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B910001A", + "lpgfr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Neg32, + rd: writable_gpr(1), + rn: gpr(10), + }, + "131A", + "lcr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Neg64, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B903001A", + "lcgr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::Neg64Ext32, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B913001A", + "lcgfr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::PopcntByte, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B9E1001A", + "popcnt %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::PopcntReg, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B9E1801A", + "popcnt %r1, %r10, 8", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::BSwap32, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B91F001A", + "lrvr %r1, %r10", + )); + insns.push(( + Inst::UnaryRR { + op: UnaryOp::BSwap64, + rd: writable_gpr(1), + rn: gpr(10), + }, + "B90F001A", + "lrvgr %r1, %r10", + )); + + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpS32, + rn: gpr(5), + rm: gpr(6), + }, + "1956", + "cr %r5, %r6", + )); + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpS64, + rn: gpr(5), + rm: gpr(6), + }, + "B9200056", + "cgr %r5, %r6", + )); + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpS64Ext32, + rn: gpr(5), + rm: gpr(6), + }, + "B9300056", + "cgfr %r5, %r6", + )); + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpL32, + rn: gpr(5), + rm: gpr(6), + }, + "1556", + "clr %r5, %r6", + )); + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpL64, + rn: gpr(5), + rm: gpr(6), + }, + "B9210056", + "clgr %r5, %r6", + )); + insns.push(( + Inst::CmpRR { + op: CmpOp::CmpL64Ext32, + rn: gpr(5), + rm: gpr(6), + }, + "B9310056", + "clgfr %r5, %r6", + )); + + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "59102000", + "c %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32, + rn: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000059", + "cy %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61D00000003", + "crl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32Ext16, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "49102000", + "ch %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32Ext16, + rn: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000079", + "chy %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS32Ext16, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61500000003", + "chrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000020", + "cg %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61800000003", + "cgrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64Ext16, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000034", + "cgh %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64Ext16, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61400000003", + "cghrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64Ext32, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000030", + "cgf %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpS64Ext32, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61C00000003", + "cgfrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL32, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "55102000", + "cl %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL32, + rn: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: simm20_zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000055", + "cly %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL32, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61F00000003", + "clrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL32Ext16, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61700000003", + "clhrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL64, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000021", + "clg %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL64, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61A00000003", + "clgrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL64Ext16, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61600000003", + "clghrl %r1, label1", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL64Ext32, + rn: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000031", + "clgf %r1, 0(%r2)", + )); + insns.push(( + Inst::CmpRX { + op: CmpOp::CmpL64Ext32, + rn: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C61E00000003", + "clgfrl %r1, label1", + )); + + insns.push(( + Inst::CmpRSImm16 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: -32768, + }, + "A77E8000", + "chi %r7, -32768", + )); + insns.push(( + Inst::CmpRSImm16 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: 32767, + }, + "A77E7FFF", + "chi %r7, 32767", + )); + insns.push(( + Inst::CmpRSImm16 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: -32768, + }, + "A77F8000", + "cghi %r7, -32768", + )); + insns.push(( + Inst::CmpRSImm16 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: 32767, + }, + "A77F7FFF", + "cghi %r7, 32767", + )); + insns.push(( + Inst::CmpRSImm32 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: -2147483648, + }, + "C27D80000000", + "cfi %r7, -2147483648", + )); + insns.push(( + Inst::CmpRSImm32 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: 2147483647, + }, + "C27D7FFFFFFF", + "cfi %r7, 2147483647", + )); + insns.push(( + Inst::CmpRSImm32 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: -2147483648, + }, + "C27C80000000", + "cgfi %r7, -2147483648", + )); + insns.push(( + Inst::CmpRSImm32 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: 2147483647, + }, + "C27C7FFFFFFF", + "cgfi %r7, 2147483647", + )); + insns.push(( + Inst::CmpRUImm32 { + op: CmpOp::CmpL32, + rn: gpr(7), + imm: 0, + }, + "C27F00000000", + "clfi %r7, 0", + )); + insns.push(( + Inst::CmpRUImm32 { + op: CmpOp::CmpL32, + rn: gpr(7), + imm: 4294967295, + }, + "C27FFFFFFFFF", + "clfi %r7, 4294967295", + )); + insns.push(( + Inst::CmpRUImm32 { + op: CmpOp::CmpL64, + rn: gpr(7), + imm: 0, + }, + "C27E00000000", + "clgfi %r7, 0", + )); + insns.push(( + Inst::CmpRUImm32 { + op: CmpOp::CmpL64, + rn: gpr(7), + imm: 4294967295, + }, + "C27EFFFFFFFF", + "clgfi %r7, 4294967295", + )); + + insns.push(( + Inst::CmpTrapRR { + op: CmpOp::CmpS32, + rn: gpr(5), + rm: gpr(6), + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "B9728056", + "crte %r5, %r6", + )); + insns.push(( + Inst::CmpTrapRR { + op: CmpOp::CmpS64, + rn: gpr(5), + rm: gpr(6), + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "B9608056", + "cgrte %r5, %r6", + )); + insns.push(( + Inst::CmpTrapRR { + op: CmpOp::CmpL32, + rn: gpr(5), + rm: gpr(6), + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "B9738056", + "clrte %r5, %r6", + )); + insns.push(( + Inst::CmpTrapRR { + op: CmpOp::CmpL64, + rn: gpr(5), + rm: gpr(6), + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "B9618056", + "clgrte %r5, %r6", + )); + insns.push(( + Inst::CmpTrapRSImm16 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: -32768, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC7080008072", + "cite %r7, -32768", + )); + insns.push(( + Inst::CmpTrapRSImm16 { + op: CmpOp::CmpS32, + rn: gpr(7), + imm: 32767, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC707FFF8072", + "cite %r7, 32767", + )); + insns.push(( + Inst::CmpTrapRSImm16 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: -32768, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC7080008070", + "cgite %r7, -32768", + )); + insns.push(( + Inst::CmpTrapRSImm16 { + op: CmpOp::CmpS64, + rn: gpr(7), + imm: 32767, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC707FFF8070", + "cgite %r7, 32767", + )); + insns.push(( + Inst::CmpTrapRUImm16 { + op: CmpOp::CmpL32, + rn: gpr(7), + imm: 0, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC7000008073", + "clfite %r7, 0", + )); + insns.push(( + Inst::CmpTrapRUImm16 { + op: CmpOp::CmpL32, + rn: gpr(7), + imm: 65535, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC70FFFF8073", + "clfite %r7, 65535", + )); + insns.push(( + Inst::CmpTrapRUImm16 { + op: CmpOp::CmpL64, + rn: gpr(7), + imm: 0, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC7000008071", + "clgite %r7, 0", + )); + insns.push(( + Inst::CmpTrapRUImm16 { + op: CmpOp::CmpL64, + rn: gpr(7), + imm: 65535, + cond: Cond::from_mask(8), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "EC70FFFF8071", + "clgite %r7, 65535", + )); + + let w_regpair = WritableRegPair { + hi: writable_gpr(2), + lo: writable_gpr(3), + }; + let regpair = RegPair { + hi: gpr(2), + lo: gpr(3), + }; + + insns.push(( + Inst::SMulWide { + rd: w_regpair, + rn: gpr(5), + rm: gpr(6), + }, + "B9EC6025", + "mgrk %r2, %r5, %r6", + )); + insns.push(( + Inst::UMulWide { + rd: w_regpair, + ri: gpr(3), + rn: gpr(5), + }, + "B9860025", + "mlgr %r2, %r5", + )); + insns.push(( + Inst::SDivMod32 { + rd: w_regpair, + ri: gpr(3), + rn: gpr(5), + }, + "B91D0025", + "dsgfr %r2, %r5", + )); + insns.push(( + Inst::SDivMod64 { + rd: w_regpair, + ri: gpr(3), + rn: gpr(5), + }, + "B90D0025", + "dsgr %r2, %r5", + )); + insns.push(( + Inst::UDivMod32 { + rd: w_regpair, + ri: regpair, + rn: gpr(5), + }, + "B9970025", + "dlr %r2, %r5", + )); + insns.push(( + Inst::UDivMod64 { + rd: w_regpair, + ri: regpair, + rn: gpr(5), + }, + "B9870025", + "dlgr %r2, %r5", + )); + + insns.push(( + Inst::Flogr { + rd: w_regpair, + rn: gpr(5), + }, + "B9830025", + "flogr %r2, %r5", + )); + + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB450000001D", + "rll %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F001D", + "rll %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB456000001D", + "rll %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F001D", + "rll %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB450000001C", + "rllg %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F001C", + "rllg %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB456000001C", + "rllg %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::RotL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F001C", + "rllg %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB45000000DF", + "sllk %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F00DF", + "sllk %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB45600000DF", + "sllk %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F00DF", + "sllk %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB450000000D", + "sllg %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F000D", + "sllg %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB456000000D", + "sllg %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShL64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F000D", + "sllg %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB45000000DE", + "srlk %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F00DE", + "srlk %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB45600000DE", + "srlk %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F00DE", + "srlk %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB450000000C", + "srlg %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F000C", + "srlg %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB456000000C", + "srlg %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::LShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F000C", + "srlg %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB45000000DC", + "srak %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F00DC", + "srak %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB45600000DC", + "srak %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR32, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F00DC", + "srak %r4, %r5, 63(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: zero_reg(), + }, + "EB450000000A", + "srag %r4, %r5, 0", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: zero_reg(), + }, + "EB45003F000A", + "srag %r4, %r5, 63", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 0, + shift_reg: gpr(6), + }, + "EB456000000A", + "srag %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::ShiftRR { + shift_op: ShiftOp::AShR64, + rd: writable_gpr(4), + rn: gpr(5), + shift_imm: 63, + shift_reg: gpr(6), + }, + "EB45603F000A", + "srag %r4, %r5, 63(%r6)", + )); + + insns.push(( + Inst::RxSBG { + op: RxSBGOp::Insert, + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: -16, + }, + "EC4508203059", + "risbgn %r4, %r5, 8, 32, 48", + )); + insns.push(( + Inst::RxSBG { + op: RxSBGOp::And, + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4508203F54", + "rnsbg %r4, %r5, 8, 32, 63", + )); + insns.push(( + Inst::RxSBG { + op: RxSBGOp::Or, + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4508203F56", + "rosbg %r4, %r5, 8, 32, 63", + )); + insns.push(( + Inst::RxSBG { + op: RxSBGOp::Xor, + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4508203F57", + "rxsbg %r4, %r5, 8, 32, 63", + )); + insns.push(( + Inst::RxSBGTest { + op: RxSBGOp::And, + rd: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4588203F54", + "rnsbg %r4, %r5, 136, 32, 63", + )); + insns.push(( + Inst::RxSBGTest { + op: RxSBGOp::Or, + rd: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4588203F56", + "rosbg %r4, %r5, 136, 32, 63", + )); + insns.push(( + Inst::RxSBGTest { + op: RxSBGOp::Xor, + rd: gpr(4), + rn: gpr(5), + start_bit: 8, + end_bit: 32, + rotate_amt: 63, + }, + "EC4588203F57", + "rxsbg %r4, %r5, 136, 32, 63", + )); + + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080F8", + "laa %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FF8", + "laa %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080F8", + "laa %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FF8", + "laa %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080E8", + "laag %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FE8", + "laag %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080E8", + "laag %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Add64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FE8", + "laag %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080FA", + "laal %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FFA", + "laal %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080FA", + "laal %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FFA", + "laal %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080EA", + "laalg %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FEA", + "laalg %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080EA", + "laalg %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::AddLogical64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FEA", + "laalg %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080F4", + "lan %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FF4", + "lan %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080F4", + "lan %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FF4", + "lan %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080E4", + "lang %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FE4", + "lang %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080E4", + "lang %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::And64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FE4", + "lang %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080F6", + "lao %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FF6", + "lao %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080F6", + "lao %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FF6", + "lao %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080E6", + "laog %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FE6", + "laog %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080E6", + "laog %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Orr64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FE6", + "laog %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080F7", + "lax %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FF7", + "lax %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080F7", + "lax %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor32, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FF7", + "lax %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45000080E7", + "laxg %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7FE7", + "laxg %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB45600080E7", + "laxg %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicRmw { + alu_op: ALUOp::Xor64, + rd: writable_gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7FE7", + "laxg %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD12 { + base: zero_reg(), + index: zero_reg(), + disp: UImm12::maybe_from_u64(0).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "BA450000", + "cs %r4, %r5, 0", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD12 { + base: zero_reg(), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "BA450FFF", + "cs %r4, %r5, 4095", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB4500008014", + "csy %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7F14", + "csy %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD12 { + base: gpr(6), + index: zero_reg(), + disp: UImm12::maybe_from_u64(0).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "BA456000", + "cs %r4, %r5, 0(%r6)", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD12 { + base: gpr(6), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "BA456FFF", + "cs %r4, %r5, 4095(%r6)", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB4560008014", + "csy %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7F14", + "csy %r4, %r5, 524287(%r6)", + )); + insns.push(( + Inst::AtomicCas64 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB4500008030", + "csg %r4, %r5, -524288", + )); + insns.push(( + Inst::AtomicCas64 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB450FFF7F30", + "csg %r4, %r5, 524287", + )); + insns.push(( + Inst::AtomicCas64 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB4560008030", + "csg %r4, %r5, -524288(%r6)", + )); + insns.push(( + Inst::AtomicCas64 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD20 { + base: gpr(6), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB456FFF7F30", + "csg %r4, %r5, 524287(%r6)", + )); + insns.push((Inst::Fence, "07E0", "bcr 14, 0")); + + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "58102000", + "l %r1, 0(%r2)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "58102FFF", + "l %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008058", + "ly %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F58", + "ly %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "58123000", + "l %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "58123FFF", + "l %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008058", + "ly %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F58", + "ly %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000094", + "llc %r1, 0(%r2)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0094", + "llc %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008094", + "llc %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F94", + "llc %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000094", + "llc %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0094", + "llc %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008094", + "llc %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F94", + "llc %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000076", + "lb %r1, 0(%r2)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0076", + "lb %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008076", + "lb %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F76", + "lb %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000076", + "lb %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0076", + "lb %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008076", + "lb %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F76", + "lb %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000095", + "llh %r1, 0(%r2)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0095", + "llh %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008095", + "llh %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F95", + "llh %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000095", + "llh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0095", + "llh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008095", + "llh %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F95", + "llh %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "48102000", + "lh %r1, 0(%r2)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "48102FFF", + "lh %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008078", + "lhy %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F78", + "lhy %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "48123000", + "lh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "48123FFF", + "lh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008078", + "lhy %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F78", + "lhy %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000004", + "lg %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0004", + "lg %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008004", + "lg %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F04", + "lg %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000004", + "lg %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0004", + "lg %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008004", + "lg %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F04", + "lg %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000090", + "llgc %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0090", + "llgc %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008090", + "llgc %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F90", + "llgc %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000090", + "llgc %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0090", + "llgc %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008090", + "llgc %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F90", + "llgc %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000077", + "lgb %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0077", + "lgb %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008077", + "lgb %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F77", + "lgb %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000077", + "lgb %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0077", + "lgb %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008077", + "lgb %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt8 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F77", + "lgb %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000091", + "llgh %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0091", + "llgh %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008091", + "llgh %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F91", + "llgh %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000091", + "llgh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0091", + "llgh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008091", + "llgh %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F91", + "llgh %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000015", + "lgh %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0015", + "lgh %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008015", + "lgh %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F15", + "lgh %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000015", + "lgh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0015", + "lgh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008015", + "lgh %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F15", + "lgh %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000016", + "llgf %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0016", + "llgf %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008016", + "llgf %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F16", + "llgf %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000016", + "llgf %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0016", + "llgf %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008016", + "llgf %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F16", + "llgf %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000014", + "lgf %r1, 0(%r2)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0014", + "lgf %r1, 4095(%r2)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008014", + "lgf %r1, -524288(%r2)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F14", + "lgf %r1, 524287(%r2)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000014", + "lgf %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0014", + "lgf %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008014", + "lgf %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F14", + "lgf %r1, 524287(%r2,%r3)", + )); + + insns.push(( + Inst::Load32 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41D00000003", + "lrl %r1, label1", + )); + insns.push(( + Inst::Load32SExt16 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41500000003", + "lhrl %r1, label1", + )); + insns.push(( + Inst::Load32ZExt16 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41200000003", + "llhrl %r1, label1", + )); + insns.push(( + Inst::Load64 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41800000003", + "lgrl %r1, label1", + )); + insns.push(( + Inst::Load64SExt16 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41400000003", + "lghrl %r1, label1", + )); + insns.push(( + Inst::Load64ZExt16 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41600000003", + "llghrl %r1, label1", + )); + insns.push(( + Inst::Load64SExt32 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41C00000003", + "lgfrl %r1, label1", + )); + insns.push(( + Inst::Load64ZExt32 { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41E00000003", + "llgfrl %r1, label1", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000001F", + "lrvh %r1, 0(%r2)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF001F", + "lrvh %r1, 4095(%r2)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000801F", + "lrvh %r1, -524288(%r2)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F1F", + "lrvh %r1, 524287(%r2)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000001F", + "lrvh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF001F", + "lrvh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000801F", + "lrvh %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev16 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F1F", + "lrvh %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000001E", + "lrv %r1, 0(%r2)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF001E", + "lrv %r1, 4095(%r2)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000801E", + "lrv %r1, -524288(%r2)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F1E", + "lrv %r1, 524287(%r2)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000001E", + "lrv %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF001E", + "lrv %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000801E", + "lrv %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev32 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F1E", + "lrv %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000000F", + "lrvg %r1, 0(%r2)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF000F", + "lrvg %r1, 4095(%r2)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000800F", + "lrvg %r1, -524288(%r2)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F0F", + "lrvg %r1, 524287(%r2)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000000F", + "lrvg %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF000F", + "lrvg %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000800F", + "lrvg %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::LoadRev64 { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F0F", + "lrvg %r1, 524287(%r2,%r3)", + )); + + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "42102000", + "stc %r1, 0(%r2)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "42102FFF", + "stc %r1, 4095(%r2)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008072", + "stcy %r1, -524288(%r2)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F72", + "stcy %r1, 524287(%r2)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "42123000", + "stc %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "42123FFF", + "stc %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008072", + "stcy %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Store8 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F72", + "stcy %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "40102000", + "sth %r1, 0(%r2)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "40102FFF", + "sth %r1, 4095(%r2)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008070", + "sthy %r1, -524288(%r2)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F70", + "sthy %r1, 524287(%r2)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "40123000", + "sth %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "40123FFF", + "sth %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008070", + "sthy %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F70", + "sthy %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "50102000", + "st %r1, 0(%r2)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "50102FFF", + "st %r1, 4095(%r2)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008050", + "sty %r1, -524288(%r2)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F50", + "sty %r1, 524287(%r2)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "50123000", + "st %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "50123FFF", + "st %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008050", + "sty %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F50", + "sty %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31020000024", + "stg %r1, 0(%r2)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF0024", + "stg %r1, 4095(%r2)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008024", + "stg %r1, -524288(%r2)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F24", + "stg %r1, 524287(%r2)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E31230000024", + "stg %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF0024", + "stg %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008024", + "stg %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F24", + "stg %r1, 524287(%r2,%r3)", + )); + + insns.push(( + Inst::StoreImm8 { + imm: 255, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "92FF2000", + "mvi 0(%r2), 255", + )); + insns.push(( + Inst::StoreImm8 { + imm: 0, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "92002FFF", + "mvi 4095(%r2), 0", + )); + insns.push(( + Inst::StoreImm8 { + imm: 255, + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EBFF20008052", + "mviy -524288(%r2), 255", + )); + insns.push(( + Inst::StoreImm8 { + imm: 0, + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB002FFF7F52", + "mviy 524287(%r2), 0", + )); + insns.push(( + Inst::StoreImm16 { + imm: -32768, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E54420008000", + "mvhhi 0(%r2), -32768", + )); + insns.push(( + Inst::StoreImm16 { + imm: 32767, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E5442FFF7FFF", + "mvhhi 4095(%r2), 32767", + )); + insns.push(( + Inst::StoreImm32SExt16 { + imm: -32768, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E54C20008000", + "mvhi 0(%r2), -32768", + )); + insns.push(( + Inst::StoreImm32SExt16 { + imm: 32767, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E54C2FFF7FFF", + "mvhi 4095(%r2), 32767", + )); + insns.push(( + Inst::StoreImm64SExt16 { + imm: -32768, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E54820008000", + "mvghi 0(%r2), -32768", + )); + insns.push(( + Inst::StoreImm64SExt16 { + imm: 32767, + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E5482FFF7FFF", + "mvghi 4095(%r2), 32767", + )); + + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000003F", + "strvh %r1, 0(%r2)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF003F", + "strvh %r1, 4095(%r2)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000803F", + "strvh %r1, -524288(%r2)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F3F", + "strvh %r1, 524287(%r2)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000003F", + "strvh %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF003F", + "strvh %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000803F", + "strvh %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev16 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F3F", + "strvh %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000003E", + "strv %r1, 0(%r2)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF003E", + "strv %r1, 4095(%r2)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000803E", + "strv %r1, -524288(%r2)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F3E", + "strv %r1, 524287(%r2)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000003E", + "strv %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF003E", + "strv %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000803E", + "strv %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev32 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F3E", + "strv %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3102000002F", + "strvg %r1, 0(%r2)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF002F", + "strvg %r1, 4095(%r2)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102000802F", + "strvg %r1, -524288(%r2)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F2F", + "strvg %r1, 524287(%r2)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E3123000002F", + "strvg %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF002F", + "strvg %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123000802F", + "strvg %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::StoreRev64 { + rd: gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F2F", + "strvg %r1, 524287(%r2,%r3)", + )); + + insns.push(( + Inst::Store16 { + rd: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41700000003", + "sthrl %r1, label1", + )); + insns.push(( + Inst::Store32 { + rd: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41F00000003", + "strl %r1, label1", + )); + insns.push(( + Inst::Store64 { + rd: gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C41B00000003", + "stgrl %r1, label1", + )); + + insns.push(( + Inst::LoadMultiple64 { + rt: writable_gpr(8), + rt2: writable_gpr(12), + mem: MemArg::BXD20 { + base: gpr(15), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB8CF0008004", + "lmg %r8, %r12, -524288(%r15)", + )); + insns.push(( + Inst::LoadMultiple64 { + rt: writable_gpr(8), + rt2: writable_gpr(12), + mem: MemArg::BXD20 { + base: gpr(15), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB8CFFFF7F04", + "lmg %r8, %r12, 524287(%r15)", + )); + + insns.push(( + Inst::StoreMultiple64 { + rt: gpr(8), + rt2: gpr(12), + mem: MemArg::BXD20 { + base: gpr(15), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB8CF0008024", + "stmg %r8, %r12, -524288(%r15)", + )); + insns.push(( + Inst::StoreMultiple64 { + rt: gpr(8), + rt2: gpr(12), + mem: MemArg::BXD20 { + base: gpr(15), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "EB8CFFFF7F24", + "stmg %r8, %r12, 524287(%r15)", + )); + + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: zero_reg(), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "41100000", + "la %r1, 0", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: zero_reg(), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "41100FFF", + "la %r1, 4095", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31000008071", + "lay %r1, -524288", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: zero_reg(), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3100FFF7F71", + "lay %r1, 524287", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "41102000", + "la %r1, 0(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "41102FFF", + "la %r1, 4095(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31020008071", + "lay %r1, -524288(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F71", + "lay %r1, 524287(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "41123000", + "la %r1, 0(%r2,%r3)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "41123FFF", + "la %r1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E31230008071", + "lay %r1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E3123FFF7F71", + "lay %r1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::Label { + target: MachLabel::from_block(BlockIndex::new(1)), + }, + }, + "C01000000003", + "larl %r1, label1", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::Symbol { + name: Box::new(ExternalName::testcase("test0")), + offset: 64, + flags: MemFlags::trusted(), + }, + }, + "C01000000000", + "larl %r1, %test0 + 64", + )); + + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: 0, + flags: MemFlags::trusted(), + }, + }, + "41102000", + "la %r1, 0(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: 4095, + flags: MemFlags::trusted(), + }, + }, + "41102FFF", + "la %r1, 4095(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: -524288, + flags: MemFlags::trusted(), + }, + }, + "E31020008071", + "lay %r1, -524288(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: 524287, + flags: MemFlags::trusted(), + }, + }, + "E3102FFF7F71", + "lay %r1, 524287(%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: -2147483648, + flags: MemFlags::trusted(), + }, + }, + "C0118000000041112000", + "lgfi %r1, -2147483648 ; la %r1, 0(%r1,%r2)", + )); + insns.push(( + Inst::LoadAddr { + rd: writable_gpr(1), + mem: MemArg::RegOffset { + reg: gpr(2), + off: 2147483647, + flags: MemFlags::trusted(), + }, + }, + "C0117FFFFFFF41112000", + "lgfi %r1, 2147483647 ; la %r1, 0(%r1,%r2)", + )); + + insns.push(( + Inst::Mov64 { + rd: writable_gpr(8), + rm: gpr(9), + }, + "B9040089", + "lgr %r8, %r9", + )); + insns.push(( + Inst::Mov32 { + rd: writable_gpr(8), + rm: gpr(9), + }, + "1889", + "lr %r8, %r9", + )); + + insns.push(( + Inst::Mov32SImm16 { + rd: writable_gpr(8), + imm: -32768, + }, + "A7888000", + "lhi %r8, -32768", + )); + insns.push(( + Inst::Mov32SImm16 { + rd: writable_gpr(8), + imm: 32767, + }, + "A7887FFF", + "lhi %r8, 32767", + )); + insns.push(( + Inst::Mov32Imm { + rd: writable_gpr(8), + imm: 2147483648, + }, + "C08980000000", + "iilf %r8, 2147483648", + )); + insns.push(( + Inst::Mov32Imm { + rd: writable_gpr(8), + imm: 2147483647, + }, + "C0897FFFFFFF", + "iilf %r8, 2147483647", + )); + insns.push(( + Inst::Mov64SImm16 { + rd: writable_gpr(8), + imm: -32768, + }, + "A7898000", + "lghi %r8, -32768", + )); + insns.push(( + Inst::Mov64SImm16 { + rd: writable_gpr(8), + imm: 32767, + }, + "A7897FFF", + "lghi %r8, 32767", + )); + insns.push(( + Inst::Mov64SImm32 { + rd: writable_gpr(8), + imm: -2147483648, + }, + "C08180000000", + "lgfi %r8, -2147483648", + )); + insns.push(( + Inst::Mov64SImm32 { + rd: writable_gpr(8), + imm: 2147483647, + }, + "C0817FFFFFFF", + "lgfi %r8, 2147483647", + )); + insns.push(( + Inst::Mov64UImm16Shifted { + rd: writable_gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(), + }, + "A58FFFFF", + "llill %r8, 65535", + )); + insns.push(( + Inst::Mov64UImm16Shifted { + rd: writable_gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(), + }, + "A58EFFFF", + "llilh %r8, 65535", + )); + insns.push(( + Inst::Mov64UImm16Shifted { + rd: writable_gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(), + }, + "A58DFFFF", + "llihl %r8, 65535", + )); + insns.push(( + Inst::Mov64UImm16Shifted { + rd: writable_gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000_0000_0000).unwrap(), + }, + "A58CFFFF", + "llihh %r8, 65535", + )); + insns.push(( + Inst::Mov64UImm32Shifted { + rd: writable_gpr(8), + imm: UImm32Shifted::maybe_from_u64(0x0000_0000_ffff_ffff).unwrap(), + }, + "C08FFFFFFFFF", + "llilf %r8, 4294967295", + )); + insns.push(( + Inst::Mov64UImm32Shifted { + rd: writable_gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff_0000_0000).unwrap(), + }, + "C08EFFFFFFFF", + "llihf %r8, 4294967295", + )); + + insns.push(( + Inst::Insert64UImm16Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(), + }, + "A583FFFF", + "iill %r8, 65535", + )); + insns.push(( + Inst::Insert64UImm16Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(), + }, + "A582FFFF", + "iilh %r8, 65535", + )); + insns.push(( + Inst::Insert64UImm16Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(), + }, + "A581FFFF", + "iihl %r8, 65535", + )); + insns.push(( + Inst::Insert64UImm16Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm16Shifted::maybe_from_u64(0xffff_0000_0000_0000).unwrap(), + }, + "A580FFFF", + "iihh %r8, 65535", + )); + insns.push(( + Inst::Insert64UImm32Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0x0000_0000_ffff_ffff).unwrap(), + }, + "C089FFFFFFFF", + "iilf %r8, 4294967295", + )); + insns.push(( + Inst::Insert64UImm32Shifted { + rd: writable_gpr(8), + ri: gpr(8), + imm: UImm32Shifted::maybe_from_u64(0xffff_ffff_0000_0000).unwrap(), + }, + "C088FFFFFFFF", + "iihf %r8, 4294967295", + )); + + insns.push(( + Inst::CMov32 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + ri: gpr(8), + rm: gpr(9), + }, + "B9F21089", + "locro %r8, %r9", + )); + insns.push(( + Inst::CMov64 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + ri: gpr(8), + rm: gpr(9), + }, + "B9E21089", + "locgro %r8, %r9", + )); + + insns.push(( + Inst::CMov32SImm16 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + imm: -32768, + ri: gpr(8), + }, + "EC8180000042", + "lochio %r8, -32768", + )); + insns.push(( + Inst::CMov32SImm16 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + imm: 32767, + ri: gpr(8), + }, + "EC817FFF0042", + "lochio %r8, 32767", + )); + insns.push(( + Inst::CMov64SImm16 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + imm: -32768, + ri: gpr(8), + }, + "EC8180000046", + "locghio %r8, -32768", + )); + insns.push(( + Inst::CMov64SImm16 { + rd: writable_gpr(8), + cond: Cond::from_mask(1), + imm: 32767, + ri: gpr(8), + }, + "EC817FFF0046", + "locghio %r8, 32767", + )); + + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: false, + from_bits: 8, + to_bits: 32, + }, + "B9940012", + "llcr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: true, + from_bits: 8, + to_bits: 32, + }, + "B9260012", + "lbr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: false, + from_bits: 16, + to_bits: 32, + }, + "B9950012", + "llhr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: true, + from_bits: 16, + to_bits: 32, + }, + "B9270012", + "lhr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: false, + from_bits: 8, + to_bits: 64, + }, + "B9840012", + "llgcr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: true, + from_bits: 8, + to_bits: 64, + }, + "B9060012", + "lgbr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: false, + from_bits: 16, + to_bits: 64, + }, + "B9850012", + "llghr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: true, + from_bits: 16, + to_bits: 64, + }, + "B9070012", + "lghr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: false, + from_bits: 32, + to_bits: 64, + }, + "B9160012", + "llgfr %r1, %r2", + )); + insns.push(( + Inst::Extend { + rd: writable_gpr(1), + rn: gpr(2), + signed: true, + from_bits: 32, + to_bits: 64, + }, + "B9140012", + "lgfr %r1, %r2", + )); + + insns.push(( + Inst::Jump { + dest: MachLabel::from_block(BlockIndex::new(0)), + }, + "C0F400000000", + "jg label0", + )); + + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(1), + }, + "C01400000000", + "jgo label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(2), + }, + "C02400000000", + "jgh label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(3), + }, + "C03400000000", + "jgnle label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(4), + }, + "C04400000000", + "jgl label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(5), + }, + "C05400000000", + "jgnhe label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(6), + }, + "C06400000000", + "jglh label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(7), + }, + "C07400000000", + "jgne label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(8), + }, + "C08400000000", + "jge label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(9), + }, + "C09400000000", + "jgnlh label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(10), + }, + "C0A400000000", + "jghe label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(11), + }, + "C0B400000000", + "jgnl label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(12), + }, + "C0C400000000", + "jgle label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(13), + }, + "C0D400000000", + "jgnh label0", + )); + insns.push(( + Inst::OneWayCondBr { + target: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(14), + }, + "C0E400000000", + "jgno label0", + )); + + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(1), + }, + "C01400000000C0F4FFFFFFFD", + "jgo label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(2), + }, + "C02400000000C0F4FFFFFFFD", + "jgh label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(3), + }, + "C03400000000C0F4FFFFFFFD", + "jgnle label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(4), + }, + "C04400000000C0F4FFFFFFFD", + "jgl label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(5), + }, + "C05400000000C0F4FFFFFFFD", + "jgnhe label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(6), + }, + "C06400000000C0F4FFFFFFFD", + "jglh label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(7), + }, + "C07400000000C0F4FFFFFFFD", + "jgne label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(8), + }, + "C08400000000C0F4FFFFFFFD", + "jge label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(9), + }, + "C09400000000C0F4FFFFFFFD", + "jgnlh label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(10), + }, + "C0A400000000C0F4FFFFFFFD", + "jghe label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(11), + }, + "C0B400000000C0F4FFFFFFFD", + "jgnl label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(12), + }, + "C0C400000000C0F4FFFFFFFD", + "jgle label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(13), + }, + "C0D400000000C0F4FFFFFFFD", + "jgnh label0 ; jg label0", + )); + insns.push(( + Inst::CondBr { + taken: MachLabel::from_block(BlockIndex::new(0)), + not_taken: MachLabel::from_block(BlockIndex::new(0)), + cond: Cond::from_mask(14), + }, + "C0E400000000C0F4FFFFFFFD", + "jgno label0 ; jg label0", + )); + + insns.push(( + Inst::IndirectBr { + rn: gpr(3), + targets: vec![], + }, + "07F3", + "br %r3", + )); + + insns.push(( + Inst::Call { + link: writable_gpr(14), + info: Box::new(CallInfo::empty( + ExternalName::testcase("test0"), + CallConv::SystemV, + )), + }, + "C0E500000000", + "brasl %r14, %test0", + )); + + insns.push(( + Inst::CallInd { + link: writable_gpr(14), + info: Box::new(CallInfo::empty(gpr(1), CallConv::SystemV)), + }, + "0DE1", + "basr %r14, %r1", + )); + + insns.push((Inst::Ret { link: gpr(14) }, "07FE", "br %r14")); + + insns.push((Inst::Debugtrap, "0001", ".word 0x0001 # debugtrap")); + + insns.push(( + Inst::Trap { + trap_code: TrapCode::STACK_OVERFLOW, + }, + "0000", + ".word 0x0000 # trap=stk_ovf", + )); + insns.push(( + Inst::TrapIf { + cond: Cond::from_mask(1), + trap_code: TrapCode::STACK_OVERFLOW, + }, + "C01400000001", + "jgo .+2 # trap=stk_ovf", + )); + + insns.push(( + Inst::Loop { + body: vec![ + Inst::CmpRR { + op: CmpOp::CmpS32, + rn: gpr(2), + rm: gpr(3), + }, + Inst::CondBreak { + cond: Cond::from_mask(13), + }, + Inst::AtomicCas32 { + rd: writable_gpr(4), + ri: gpr(4), + rn: gpr(5), + mem: MemArg::BXD12 { + base: gpr(6), + index: zero_reg(), + disp: UImm12::maybe_from_u64(0).unwrap(), + flags: MemFlags::trusted(), + }, + }, + ], + cond: Cond::from_mask(6), + }, + "1923C0D400000008BA456000C064FFFFFFFA", + "0: cr %r2, %r3 ; jgnh 1f ; cs %r4, %r5, 0(%r6) ; jglh 0b ; 1:", + )); + + insns.push(( + Inst::StackProbeLoop { + probe_count: writable_gpr(1), + guard_size: 4096, + }, + "A7FBF0009200F000A716FFFC", + "0: aghi %r15, -4096 ; mvi 0(%r15), 0 ; brct %r1, 0b", + )); + + insns.push(( + Inst::FpuMove32 { + rd: writable_vr(8), + rn: vr(4), + }, + "3884", + "ler %f8, %f4", + )); + insns.push(( + Inst::FpuMove32 { + rd: writable_vr(8), + rn: vr(20), + }, + "E78400000456", + "vlr %v8, %v20", + )); + insns.push(( + Inst::FpuMove64 { + rd: writable_vr(8), + rn: vr(4), + }, + "2884", + "ldr %f8, %f4", + )); + insns.push(( + Inst::FpuMove64 { + rd: writable_vr(8), + rn: vr(20), + }, + "E78400000456", + "vlr %v8, %v20", + )); + insns.push(( + Inst::FpuCMov32 { + rd: writable_vr(8), + ri: vr(8), + rm: vr(4), + cond: Cond::from_mask(1), + }, + "A7E400033884", + "jno 6 ; ler %f8, %f4", + )); + insns.push(( + Inst::FpuCMov32 { + rd: writable_vr(8), + ri: vr(8), + rm: vr(20), + cond: Cond::from_mask(1), + }, + "A7E40005E78400000456", + "jno 10 ; vlr %v8, %v20", + )); + insns.push(( + Inst::FpuCMov64 { + rd: writable_vr(8), + ri: vr(8), + rm: vr(4), + cond: Cond::from_mask(1), + }, + "A7E400032884", + "jno 6 ; ldr %f8, %f4", + )); + insns.push(( + Inst::FpuCMov64 { + rd: writable_vr(8), + ri: vr(8), + rm: vr(20), + cond: Cond::from_mask(1), + }, + "A7E40005E78400000456", + "jno 10 ; vlr %v8, %v20", + )); + + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs32, + rd: writable_vr(8), + rn: vr(12), + }, + "B300008C", + "lpebr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs32, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C002828CC", + "wflpsb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs32x4, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C002028CC", + "vflpsb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs64, + rd: writable_vr(8), + rn: vr(12), + }, + "B310008C", + "lpdbr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs64, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C002838CC", + "wflpdb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Abs64x2, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C002038CC", + "vflpdb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg32, + rd: writable_vr(8), + rn: vr(12), + }, + "B303008C", + "lcebr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg32, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000828CC", + "wflcsb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg32x4, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000028CC", + "vflcsb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg64, + rd: writable_vr(8), + rn: vr(12), + }, + "B313008C", + "lcdbr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg64, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000838CC", + "wflcdb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Neg64x2, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000038CC", + "vflcdb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs32, + rd: writable_vr(8), + rn: vr(12), + }, + "B301008C", + "lnebr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs32, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828CC", + "wflnsb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs32x4, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028CC", + "vflnsb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs64, + rd: writable_vr(8), + rn: vr(12), + }, + "B311008C", + "lndbr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs64, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838CC", + "wflndb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::NegAbs64x2, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038CC", + "vflndb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt32, + rd: writable_vr(8), + rn: vr(12), + }, + "B314008C", + "sqebr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt32, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000828CE", + "wfsqsb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt32x4, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000028CE", + "vfsqsb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt64, + rd: writable_vr(8), + rn: vr(12), + }, + "B315008C", + "sqdbr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt64, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000838CE", + "wfsqdb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Sqrt64x2, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000038CE", + "vfsqdb %v24, %v12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Cvt32To64, + rd: writable_vr(8), + rn: vr(12), + }, + "B304008C", + "ldebr %f8, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Cvt32To64, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000828C4", + "wldeb %v24, %f12", + )); + insns.push(( + Inst::FpuRR { + fpu_op: FPUOp1::Cvt32x4To64x2, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C000028C4", + "vldeb %v24, %v12", + )); + + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add32, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B30A008C", + "aebr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add32, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00828E3", + "wfasb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028E3", + "vfasb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add64, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B31A008C", + "adbr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add64, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00838E3", + "wfadb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Add64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038E3", + "vfadb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub32, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B30B008C", + "sebr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub32, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00828E2", + "wfssb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028E2", + "vfssb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub64, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B31B008C", + "sdbr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub64, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00838E2", + "wfsdb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Sub64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038E2", + "vfsdb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul32, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B317008C", + "meebr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul32, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00828E7", + "wfmsb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028E7", + "vfmsb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul64, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B31C008C", + "mdbr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul64, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00838E7", + "wfmdb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Mul64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038E7", + "vfmdb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div32, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B30D008C", + "debr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div32, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00828E5", + "wfdsb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028E5", + "vfdsb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div64, + rd: writable_vr(8), + rn: vr(8), + rm: vr(12), + }, + "B31D008C", + "ddbr %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div64, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00838E5", + "wfddb %v20, %f8, %f12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Div64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038E5", + "vfddb %v20, %v8, %v12", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Max32, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801820EF", + "wfmaxsb %f4, %f6, %f8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Max32x4, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801020EF", + "vfmaxsb %v4, %v6, %v8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Max64, + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + }, + "E746801832EF", + "wfmaxdb %f4, %f6, %v24, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Max64x2, + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + }, + "E746801032EF", + "vfmaxdb %v4, %v6, %v24, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Min32, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801820EE", + "wfminsb %f4, %f6, %f8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Min32x4, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801020EE", + "vfminsb %v4, %v6, %v8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Min64, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801830EE", + "wfmindb %f4, %f6, %f8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::Min64x2, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746801030EE", + "vfmindb %v4, %v6, %v8, 1", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MaxPseudo32, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803820EF", + "wfmaxsb %f4, %f6, %f8, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MaxPseudo32x4, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803020EF", + "vfmaxsb %v4, %v6, %v8, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MaxPseudo64, + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + }, + "E746803832EF", + "wfmaxdb %f4, %f6, %v24, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MaxPseudo64x2, + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + }, + "E746803032EF", + "vfmaxdb %v4, %v6, %v24, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MinPseudo32, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803820EE", + "wfminsb %f4, %f6, %f8, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MinPseudo32x4, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803020EE", + "vfminsb %v4, %v6, %v8, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MinPseudo64, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803830EE", + "wfmindb %f4, %f6, %f8, 3", + )); + insns.push(( + Inst::FpuRRR { + fpu_op: FPUOp2::MinPseudo64x2, + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + }, + "E746803030EE", + "vfmindb %v4, %v6, %v8, 3", + )); + + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd32, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(8), + }, + "B30E80CD", + "maebr %f8, %f12, %f13", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd32, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD208418F", + "wfmasb %f8, %f12, %f13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd32x4, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD200418F", + "vfmasb %v8, %v12, %v13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd64, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(8), + }, + "B31E80CD", + "madbr %f8, %f12, %f13", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd64, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD308418F", + "wfmadb %f8, %f12, %f13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MAdd64x2, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD300418F", + "vfmadb %v8, %v12, %v13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub32, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(8), + }, + "B30F80CD", + "msebr %f8, %f12, %f13", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub32, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD208418E", + "wfmssb %f8, %f12, %f13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub32x4, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD200418E", + "vfmssb %v8, %v12, %v13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub64, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(8), + }, + "B31F80CD", + "msdbr %f8, %f12, %f13", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub64, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD308418E", + "wfmsdb %f8, %f12, %f13, %v20", + )); + insns.push(( + Inst::FpuRRRR { + fpu_op: FPUOp3::MSub64x2, + rd: writable_vr(8), + rn: vr(12), + rm: vr(13), + ra: vr(20), + }, + "E78CD300418E", + "vfmsdb %v8, %v12, %v13, %v20", + )); + + insns.push(( + Inst::FpuCmp32 { + rn: vr(8), + rm: vr(12), + }, + "B309008C", + "cebr %f8, %f12", + )); + insns.push(( + Inst::FpuCmp32 { + rn: vr(24), + rm: vr(12), + }, + "E78C000028CB", + "wfcsb %v24, %f12", + )); + insns.push(( + Inst::FpuCmp64 { + rn: vr(8), + rm: vr(12), + }, + "B319008C", + "cdbr %f8, %f12", + )); + insns.push(( + Inst::FpuCmp64 { + rn: vr(24), + rm: vr(12), + }, + "E78C000038CB", + "wfcdb %v24, %f12", + )); + + insns.push(( + Inst::LoadFpuConst32 { + rd: writable_vr(8), + const_data: 1.0_f32.to_bits(), + }, + "A71500043F80000078801000", + "bras %r1, 8 ; data.f32 1 ; le %f8, 0(%r1)", + )); + insns.push(( + Inst::LoadFpuConst32 { + rd: writable_vr(24), + const_data: 1.0_f32.to_bits(), + }, + "A71500043F800000E78010000803", + "bras %r1, 8 ; data.f32 1 ; vlef %v24, 0(%r1), 0", + )); + insns.push(( + Inst::LoadFpuConst64 { + rd: writable_vr(8), + const_data: 1.0_f64.to_bits(), + }, + "A71500063FF000000000000068801000", + "bras %r1, 12 ; data.f64 1 ; ld %f8, 0(%r1)", + )); + insns.push(( + Inst::LoadFpuConst64 { + rd: writable_vr(24), + const_data: 1.0_f64.to_bits(), + }, + "A71500063FF0000000000000E78010000802", + "bras %r1, 12 ; data.f64 1 ; vleg %v24, 0(%r1), 0", + )); + + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Cvt64To32, + mode: FpuRoundMode::Current, + rd: writable_vr(8), + rn: vr(12), + }, + "B344008C", + "ledbra %f8, 0, %f12, 0", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Cvt64To32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C5", + "wledb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Cvt64x2To32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C5", + "vledb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32, + mode: FpuRoundMode::ToNegInfinity, + rd: writable_vr(8), + rn: vr(12), + }, + "B357708C", + "fiebr %f8, 7, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64, + mode: FpuRoundMode::ToNegInfinity, + rd: writable_vr(8), + rn: vr(12), + }, + "B35F708C", + "fidbr %f8, 7, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32, + mode: FpuRoundMode::ToPosInfinity, + rd: writable_vr(8), + rn: vr(12), + }, + "B357608C", + "fiebr %f8, 6, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64, + mode: FpuRoundMode::ToPosInfinity, + rd: writable_vr(8), + rn: vr(12), + }, + "B35F608C", + "fidbr %f8, 6, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32, + mode: FpuRoundMode::ToZero, + rd: writable_vr(8), + rn: vr(12), + }, + "B357508C", + "fiebr %f8, 5, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64, + mode: FpuRoundMode::ToZero, + rd: writable_vr(8), + rn: vr(12), + }, + "B35F508C", + "fidbr %f8, 5, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32, + mode: FpuRoundMode::ToNearestTiesToEven, + rd: writable_vr(8), + rn: vr(12), + }, + "B357408C", + "fiebr %f8, 4, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64, + mode: FpuRoundMode::ToNearestTiesToEven, + rd: writable_vr(8), + rn: vr(12), + }, + "B35F408C", + "fidbr %f8, 4, %f12", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828C7", + "wfisb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028C7", + "vfisb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C7", + "wfidb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::Round64x2, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C7", + "vfidb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToSInt32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828C2", + "wcfeb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToSInt32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028C2", + "vcfeb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToSInt64, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C2", + "wcgdb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToSInt64x2, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C2", + "vcgdb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToUInt32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828C0", + "wclfeb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToUInt32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028C0", + "vclfeb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToUInt64, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C0", + "wclgdb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::ToUInt64x2, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C0", + "vclgdb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromSInt32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828C3", + "wcefb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromSInt32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028C3", + "vcefb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromSInt64, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C3", + "wcdgb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromSInt64x2, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C3", + "vcdgb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromUInt32, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001828C1", + "wcelfb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromUInt32x4, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001028C1", + "vcelfb %v24, %v12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromUInt64, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001838C1", + "wcdlgb %v24, %f12, 0, 1", + )); + insns.push(( + Inst::FpuRound { + op: FpuRoundOp::FromUInt64x2, + mode: FpuRoundMode::ToNearest, + rd: writable_vr(24), + rn: vr(12), + }, + "E78C001038C1", + "vcdlgb %v24, %v12, 0, 1", + )); + + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Add8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F3", + "vab %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Add16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F3", + "vah %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Add32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F3", + "vaf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Add64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F3", + "vag %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Add128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00048F3", + "vaq %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Sub8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F7", + "vsb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Sub16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F7", + "vsh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Sub32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F7", + "vsf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Sub64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F7", + "vsg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Sub128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00048F7", + "vsq %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Mul8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A2", + "vmlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Mul16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A2", + "vmlhw %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Mul32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A2", + "vmlf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A1", + "vmlhb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A1", + "vmlhh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A1", + "vmlhf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A3", + "vmhb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A3", + "vmhh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A3", + "vmhf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulEven8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A4", + "vmleb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulEven16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A4", + "vmleh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulEven32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A4", + "vmlef %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulEven8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A6", + "vmeb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulEven16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A6", + "vmeh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulEven32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A6", + "vmef %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulOdd8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A5", + "vmlob %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulOdd16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A5", + "vmloh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMulOdd32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A5", + "vmlof %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulOdd8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008A7", + "vmob %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulOdd16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018A7", + "vmoh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMulOdd32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028A7", + "vmof %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMax8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008FD", + "vmxlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMax16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018FD", + "vmxlh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMax32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028FD", + "vmxlf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMax64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038FD", + "vmxlg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMax8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008FF", + "vmxb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMax16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018FF", + "vmxh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMax32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028FF", + "vmxf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMax64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038FF", + "vmxg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMin8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008FC", + "vmnlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMin16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018FC", + "vmnlh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMin32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028FC", + "vmnlf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UMin64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038FC", + "vmnlg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMin8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008FE", + "vmnb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMin16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018FE", + "vmnh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMin32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028FE", + "vmnf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SMin64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038FE", + "vmng %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UAvg8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F0", + "vavglb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UAvg16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F0", + "vavglh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UAvg32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F0", + "vavglf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::UAvg64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F0", + "vavglg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SAvg8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F2", + "vavgb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SAvg16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F2", + "vavgh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SAvg32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F2", + "vavgf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::SAvg64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F2", + "vavgg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::And128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000868", + "vn %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Orr128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086A", + "vo %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Xor128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086D", + "vx %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::NotAnd128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086E", + "vnn %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::NotOrr128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086B", + "vno %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::NotXor128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086C", + "vnx %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::AndNot128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000869", + "vnc %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::OrrNot128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000086F", + "voc %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::BitPermute128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000885", + "vbperm %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::LShLByByte128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000875", + "vslb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::LShRByByte128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000087D", + "vsrlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::AShRByByte128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000087F", + "vsrab %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::LShLByBit128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000874", + "vsl %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::LShRByBit128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000087C", + "vsrl %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::AShRByBit128, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C000087E", + "vsra %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Pack16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0001894", + "vpkh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Pack32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0002894", + "vpkf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::Pack64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0003894", + "vpkg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackUSat16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0001895", + "vpklsh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackUSat32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0002895", + "vpklsf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackUSat64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0003895", + "vpklsg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackSSat16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0001897", + "vpksh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackSSat32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0002897", + "vpksf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::PackSSat64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0003897", + "vpksg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeLow8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000860", + "vmrlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeLow16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0001860", + "vmrlh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeLow32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0002860", + "vmrlf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeLow64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0003860", + "vmrlg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeHigh8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0000861", + "vmrhb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeHigh16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0001861", + "vmrhh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeHigh32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0002861", + "vmrhf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecRRR { + op: VecBinaryOp::MergeHigh64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C0003861", + "vmrhg %v20, %v8, %v12", + )); + + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Abs8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008DF", + "vlpb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Abs16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018DF", + "vlph %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Abs32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028DF", + "vlpf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Abs64x2, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000038DF", + "vlpg %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Neg8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008DE", + "vlcb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Neg16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018DE", + "vlch %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Neg32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028DE", + "vlcf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Neg64x2, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000038DE", + "vlcg %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Popcnt8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800000850", + "vpopctb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Popcnt16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800001850", + "vpopcth %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Popcnt32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800002850", + "vpopctf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Popcnt64x2, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800003850", + "vpopctg %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Clz8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800000853", + "vclzb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Clz16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800001853", + "vclzh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Clz32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800002853", + "vclzf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Clz64x2, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800003853", + "vclzg %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Ctz8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800000852", + "vctzb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Ctz16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800001852", + "vctzh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Ctz32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800002852", + "vctzf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::Ctz64x2, + rd: writable_vr(20), + rn: vr(8), + }, + "E74800003852", + "vctzg %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackULow8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008D4", + "vupllb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackULow16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018D4", + "vupllh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackULow32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028D4", + "vupllf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackUHigh8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008D5", + "vuplhb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackUHigh16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018D5", + "vuplhh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackUHigh32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028D5", + "vuplhf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSLow8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008D6", + "vuplb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSLow16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018D6", + "vuplh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSLow32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028D6", + "vuplf %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSHigh8x16, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000008D7", + "vuphb %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSHigh16x8, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000018D7", + "vuphh %v20, %v8", + )); + insns.push(( + Inst::VecRR { + op: VecUnaryOp::UnpackSHigh32x4, + rd: writable_vr(20), + rn: vr(8), + }, + "E748000028D7", + "vuphf %v20, %v8", + )); + + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::RotL8x16, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560030833", + "verllb %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::RotL16x8, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560031833", + "verllh %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::RotL32x4, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560032833", + "verllf %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::RotL64x2, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560033833", + "verllg %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShL8x16, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560030830", + "veslb %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShL16x8, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560031830", + "veslh %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShL32x4, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560032830", + "veslf %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShL64x2, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560033830", + "veslg %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShR8x16, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560030838", + "vesrlb %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShR16x8, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560031838", + "vesrlh %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShR32x4, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560032838", + "vesrlf %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::LShR64x2, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E74560033838", + "vesrlg %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::AShR8x16, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E7456003083A", + "vesrab %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::AShR16x8, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E7456003183A", + "vesrah %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::AShR32x4, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E7456003283A", + "vesraf %v20, %v5, 3(%r6)", + )); + insns.push(( + Inst::VecShiftRR { + shift_op: VecShiftOp::AShR64x2, + rd: writable_vr(20), + rn: vr(5), + shift_imm: 3, + shift_reg: gpr(6), + }, + "E7456003383A", + "vesrag %v20, %v5, 3(%r6)", + )); + + insns.push(( + Inst::VecSelect { + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + ra: vr(10), + }, + "E7468000A08D", + "vsel %v4, %v6, %v8, %v10", + )); + insns.push(( + Inst::VecSelect { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + ra: vr(10), + }, + "E7468000A88D", + "vsel %v20, %v6, %v8, %v10", + )); + insns.push(( + Inst::VecSelect { + rd: writable_vr(4), + rn: vr(22), + rm: vr(8), + ra: vr(10), + }, + "E7468000A48D", + "vsel %v4, %v22, %v8, %v10", + )); + insns.push(( + Inst::VecSelect { + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + ra: vr(10), + }, + "E7468000A28D", + "vsel %v4, %v6, %v24, %v10", + )); + insns.push(( + Inst::VecSelect { + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + ra: vr(26), + }, + "E7468000A18D", + "vsel %v4, %v6, %v8, %v26", + )); + insns.push(( + Inst::VecSelect { + rd: writable_vr(20), + rn: vr(22), + rm: vr(24), + ra: vr(26), + }, + "E7468000AF8D", + "vsel %v20, %v22, %v24, %v26", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + ra: vr(10), + }, + "E7468000A08C", + "vperm %v4, %v6, %v8, %v10", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + ra: vr(10), + }, + "E7468000A88C", + "vperm %v20, %v6, %v8, %v10", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(4), + rn: vr(22), + rm: vr(8), + ra: vr(10), + }, + "E7468000A48C", + "vperm %v4, %v22, %v8, %v10", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(4), + rn: vr(6), + rm: vr(24), + ra: vr(10), + }, + "E7468000A28C", + "vperm %v4, %v6, %v24, %v10", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(4), + rn: vr(6), + rm: vr(8), + ra: vr(26), + }, + "E7468000A18C", + "vperm %v4, %v6, %v8, %v26", + )); + insns.push(( + Inst::VecPermute { + rd: writable_vr(20), + rn: vr(22), + rm: vr(24), + ra: vr(26), + }, + "E7468000AF8C", + "vperm %v20, %v22, %v24, %v26", + )); + insns.push(( + Inst::VecPermuteDWImm { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + idx1: 0, + idx2: 0, + }, + "E74680000884", + "vpdi %v20, %v6, %v8, 0", + )); + insns.push(( + Inst::VecPermuteDWImm { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + idx1: 0, + idx2: 1, + }, + "E74680001884", + "vpdi %v20, %v6, %v8, 1", + )); + insns.push(( + Inst::VecPermuteDWImm { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + idx1: 1, + idx2: 0, + }, + "E74680004884", + "vpdi %v20, %v6, %v8, 4", + )); + insns.push(( + Inst::VecPermuteDWImm { + rd: writable_vr(20), + rn: vr(6), + rm: vr(8), + idx1: 1, + idx2: 1, + }, + "E74680005884", + "vpdi %v20, %v6, %v8, 5", + )); + + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::CmpEq8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F8", + "vceqb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::CmpEq16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F8", + "vceqh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::CmpEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F8", + "vceqf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::CmpEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F8", + "vceqg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::SCmpHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008FB", + "vchb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::SCmpHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018FB", + "vchh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::SCmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028FB", + "vchf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::SCmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038FB", + "vchg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::UCmpHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00008F9", + "vchlb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::UCmpHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00018F9", + "vchlh %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::UCmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028F9", + "vchlf %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmp { + op: VecIntCmpOp::UCmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038F9", + "vchlg %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::CmpEq8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01008F8", + "vceqbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::CmpEq16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01018F8", + "vceqhs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::CmpEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028F8", + "vceqfs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::CmpEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038F8", + "vceqgs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::SCmpHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01008FB", + "vchbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::SCmpHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01018FB", + "vchhs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::SCmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028FB", + "vchfs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::SCmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038FB", + "vchgs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::UCmpHi8x16, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01008F9", + "vchlbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::UCmpHi16x8, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01018F9", + "vchlhs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::UCmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028F9", + "vchlfs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecIntCmpS { + op: VecIntCmpOp::UCmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038F9", + "vchlgs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecInt128SCmpHi { + tmp: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E7C8000030DBA7740005E748C01038F9", + "vecg %v12, %v8 ; jne 10 ; vchlgs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecInt128UCmpHi { + tmp: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E7C8000030D9A7740005E748C01038F9", + "veclg %v12, %v8 ; jne 10 ; vchlgs %v20, %v8, %v12", + )); + + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028E8", + "vfcesb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038E8", + "vfcedb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028EB", + "vfchsb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038EB", + "vfchdb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpHiEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00028EA", + "vfchesb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmp { + op: VecFloatCmpOp::CmpHiEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C00038EA", + "vfchedb %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028E8", + "vfcesbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038E8", + "vfcedbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpHi32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028EB", + "vfchsbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpHi64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038EB", + "vfchdbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpHiEq32x4, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01028EA", + "vfchesbs %v20, %v8, %v12", + )); + insns.push(( + Inst::VecFloatCmpS { + op: VecFloatCmpOp::CmpHiEq64x2, + rd: writable_vr(20), + rn: vr(8), + rm: vr(12), + }, + "E748C01038EA", + "vfchedbs %v20, %v8, %v12", + )); + + insns.push(( + Inst::VecLoad { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E71020000806", + "vl %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoad { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E7102FFF0806", + "vl %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoad { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E71230000806", + "vl %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadRev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020004806", + "vlbrq %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadRev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF4806", + "vlbrq %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadRev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230004806", + "vlbrq %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadByte16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020001806", + "vlbrh %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadByte16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF1806", + "vlbrh %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadByte16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230001806", + "vlbrh %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadByte32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020002806", + "vlbrf %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadByte32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF2806", + "vlbrf %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadByte32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230002806", + "vlbrf %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadByte64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020003806", + "vlbrg %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadByte64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF3806", + "vlbrg %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadByte64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230003806", + "vlbrg %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadElt16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020001807", + "vlerh %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadElt16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF1807", + "vlerh %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadElt16Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230001807", + "vlerh %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadElt32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020002807", + "vlerf %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadElt32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF2807", + "vlerf %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadElt32Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230002807", + "vlerf %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadElt64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61020003807", + "vlerg %v17, 0(%r2)", + )); + insns.push(( + Inst::VecLoadElt64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF3807", + "vlerg %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadElt64Rev { + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E61230003807", + "vlerg %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStore { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E7102000080E", + "vst %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStore { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E7102FFF080E", + "vst %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStore { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E7123000080E", + "vst %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreRev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000480E", + "vstbrq %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreRev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF480E", + "vstbrq %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreRev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000480E", + "vstbrq %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreByte16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000180E", + "vstbrh %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreByte16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF180E", + "vstbrh %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreByte16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000180E", + "vstbrh %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreByte32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000280E", + "vstbrf %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreByte32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF280E", + "vstbrf %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreByte32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000280E", + "vstbrf %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreByte64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000380E", + "vstbrg %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreByte64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF380E", + "vstbrg %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreByte64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000380E", + "vstbrg %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreElt16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000180F", + "vsterh %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreElt16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF180F", + "vsterh %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreElt16Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000180F", + "vsterh %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreElt32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000280F", + "vsterf %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreElt32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF280F", + "vsterf %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreElt32Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000280F", + "vsterf %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreElt64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6102000380F", + "vsterg %v17, 0(%r2)", + )); + insns.push(( + Inst::VecStoreElt64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E6102FFF380F", + "vsterg %v17, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreElt64Rev { + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + }, + "E6123000380F", + "vsterg %v17, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadReplicate { + size: 8, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E71020800805", + "vlrepb %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicate { + size: 16, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E71020801805", + "vlreph %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicate { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E71020802805", + "vlrepf %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicate { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E71020803805", + "vlrepg %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicateRev { + size: 16, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E61020801805", + "vlbrreph %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicateRev { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E61020802805", + "vlbrrepf %v17, 128(%r2)", + )); + insns.push(( + Inst::VecLoadReplicateRev { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(128).unwrap(), + flags: MemFlags::trusted(), + }, + }, + "E61020803805", + "vlbrrepg %v17, 128(%r2)", + )); + + insns.push(( + Inst::VecMov { + rd: writable_vr(8), + rn: vr(20), + }, + "E78400000456", + "vlr %v8, %v20", + )); + insns.push(( + Inst::VecCMov { + rd: writable_vr(8), + ri: vr(8), + rm: vr(20), + cond: Cond::from_mask(1), + }, + "A7E40005E78400000456", + "jno 10 ; vlr %v8, %v20", + )); + insns.push(( + Inst::MovToVec128 { + rd: writable_vr(20), + rn: gpr(5), + rm: gpr(6), + }, + "E74560000862", + "vlvgp %v20, %r5, %r6", + )); + insns.push(( + Inst::VecLoadConst { + rd: writable_vr(24), + const_data: 0x0102030405060708090a0b0c0d0e0fu128, + }, + "A715000A000102030405060708090A0B0C0D0E0FE78010000806", + "bras %r1, 20 ; data.u128 0x000102030405060708090a0b0c0d0e0f ; vl %v24, 0(%r1)", + )); + insns.push(( + Inst::VecLoadConstReplicate { + size: 64, + rd: writable_vr(24), + const_data: 0x01020304050607u64, + }, + "A71500060001020304050607E78010003805", + "bras %r1, 12 ; data.u64 0x0001020304050607 ; vlrepg %v24, 0(%r1)", + )); + insns.push(( + Inst::VecLoadConstReplicate { + size: 32, + rd: writable_vr(24), + const_data: 0x010203u64, + }, + "A715000400010203E78010002805", + "bras %r1, 8 ; data.u32 0x00010203 ; vlrepf %v24, 0(%r1)", + )); + + insns.push(( + Inst::VecImmByteMask { + rd: writable_vr(20), + mask: 0x1234, + }, + "E74012340844", + "vgbm %v20, 4660", + )); + insns.push(( + Inst::VecImmBitMask { + size: 8, + rd: writable_vr(20), + start_bit: 1, + end_bit: 7, + }, + "E74001070846", + "vgmb %v20, 1, 7", + )); + insns.push(( + Inst::VecImmBitMask { + size: 16, + rd: writable_vr(20), + start_bit: 1, + end_bit: 7, + }, + "E74001071846", + "vgmh %v20, 1, 7", + )); + insns.push(( + Inst::VecImmBitMask { + size: 32, + rd: writable_vr(20), + start_bit: 1, + end_bit: 7, + }, + "E74001072846", + "vgmf %v20, 1, 7", + )); + insns.push(( + Inst::VecImmBitMask { + size: 64, + rd: writable_vr(20), + start_bit: 1, + end_bit: 7, + }, + "E74001073846", + "vgmg %v20, 1, 7", + )); + insns.push(( + Inst::VecImmReplicate { + size: 8, + rd: writable_vr(20), + imm: 0x1234, + }, + "E74012340845", + "vrepib %v20, 4660", + )); + insns.push(( + Inst::VecImmReplicate { + size: 16, + rd: writable_vr(20), + imm: 0x1234, + }, + "E74012341845", + "vrepih %v20, 4660", + )); + insns.push(( + Inst::VecImmReplicate { + size: 32, + rd: writable_vr(20), + imm: 0x1234, + }, + "E74012342845", + "vrepif %v20, 4660", + )); + insns.push(( + Inst::VecImmReplicate { + size: 64, + rd: writable_vr(20), + imm: 0x1234, + }, + "E74012343845", + "vrepig %v20, 4660", + )); + + insns.push(( + Inst::VecLoadLane { + size: 8, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 15, + }, + "E7102000F800", + "vleb %v17, 0(%r2), 15", + )); + insns.push(( + Inst::VecLoadLane { + size: 8, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0800", + "vleb %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 8, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 15, + }, + "E7123000F800", + "vleb %v17, 0(%r2,%r3), 15", + )); + insns.push(( + Inst::VecLoadLane { + size: 8, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0800", + "vleb %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 16, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E71020007801", + "vleh %v17, 0(%r2), 7", + )); + insns.push(( + Inst::VecLoadLane { + size: 16, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0801", + "vleh %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 16, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E71230007801", + "vleh %v17, 0(%r2,%r3), 7", + )); + insns.push(( + Inst::VecLoadLane { + size: 16, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0801", + "vleh %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 32, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 3, + }, + "E71020003803", + "vlef %v17, 0(%r2), 3", + )); + insns.push(( + Inst::VecLoadLane { + size: 32, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0803", + "vlef %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 32, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 3, + }, + "E71230003803", + "vlef %v17, 0(%r2,%r3), 3", + )); + insns.push(( + Inst::VecLoadLane { + size: 32, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0803", + "vlef %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 64, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 1, + }, + "E71020001802", + "vleg %v17, 0(%r2), 1", + )); + insns.push(( + Inst::VecLoadLane { + size: 64, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0802", + "vleg %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLane { + size: 64, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 1, + }, + "E71230001802", + "vleg %v17, 0(%r2,%r3), 1", + )); + insns.push(( + Inst::VecLoadLane { + size: 64, + rd: writable_vr(17), + ri: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0802", + "vleg %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "78102000", + "le %f1, 0(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "78102FFF", + "le %f1, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1020008064", + "ley %f1, -524288(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED102FFF7F64", + "ley %f1, 524287(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E71020000803", + "vlef %v17, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0803", + "vlef %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "78123000", + "le %f1, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "78123FFF", + "le %f1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1230008064", + "ley %f1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED123FFF7F64", + "ley %f1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E71230000803", + "vlef %v17, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 32, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0803", + "vlef %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "68102000", + "ld %f1, 0(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "68102FFF", + "ld %f1, 4095(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1020008065", + "ldy %f1, -524288(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED102FFF7F65", + "ldy %f1, 524287(%r2)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E71020000802", + "vleg %v17, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0802", + "vleg %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "68123000", + "ld %f1, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "68123FFF", + "ld %f1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1230008065", + "ldy %f1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED123FFF7F65", + "ldy %f1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E71230000802", + "vleg %v17, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneUndef { + size: 64, + rd: writable_vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0802", + "vleg %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 8, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 15, + }, + "E7102000F808", + "vsteb %v17, 0(%r2), 15", + )); + insns.push(( + Inst::VecStoreLane { + size: 8, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0808", + "vsteb %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 8, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 15, + }, + "E7123000F808", + "vsteb %v17, 0(%r2,%r3), 15", + )); + insns.push(( + Inst::VecStoreLane { + size: 8, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0808", + "vsteb %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 16, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E71020007809", + "vsteh %v17, 0(%r2), 7", + )); + insns.push(( + Inst::VecStoreLane { + size: 16, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF0809", + "vsteh %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 16, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E71230007809", + "vsteh %v17, 0(%r2,%r3), 7", + )); + insns.push(( + Inst::VecStoreLane { + size: 16, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF0809", + "vsteh %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "70102000", + "ste %f1, 0(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "70102FFF", + "ste %f1, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1020008066", + "stey %f1, -524288(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED102FFF7F66", + "stey %f1, 524287(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102000080B", + "vstef %v17, 0(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF080B", + "vstef %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "70123000", + "ste %f1, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "70123FFF", + "ste %f1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1230008066", + "stey %f1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED123FFF7F66", + "stey %f1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123000080B", + "vstef %v17, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 32, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF080B", + "vstef %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "60102000", + "std %f1, 0(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "60102FFF", + "std %f1, 4095(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1020008067", + "stdy %f1, -524288(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED102FFF7F67", + "stdy %f1, 524287(%r2)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102000080A", + "vsteg %v17, 0(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7102FFF080A", + "vsteg %v17, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "60123000", + "std %f1, 0(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "60123FFF", + "std %f1, 4095(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED1230008067", + "stdy %f1, -524288(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "ED123FFF7F67", + "stdy %f1, 524287(%r2,%r3)", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123000080A", + "vsteg %v17, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLane { + size: 64, + rd: vr(17), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E7123FFF080A", + "vsteg %v17, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 16, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61020000001", + "vlebrh %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 16, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0001", + "vlebrh %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 16, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61230000001", + "vlebrh %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 16, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0001", + "vlebrh %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 32, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61020000003", + "vlebrf %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 32, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0003", + "vlebrf %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 32, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61230000003", + "vlebrf %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 32, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0003", + "vlebrf %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 64, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61020000002", + "vlebrg %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 64, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0002", + "vlebrg %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 64, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61230000002", + "vlebrg %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRev { + size: 64, + rd: writable_vr(1), + ri: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0002", + "vlebrg %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61020000003", + "vlebrf %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0003", + "vlebrf %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31020008071E61010000003", + "lay %r1, -524288(%r2) ; vlebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3102FFF7F71E61010000003", + "lay %r1, 524287(%r2) ; vlebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61230000003", + "vlebrf %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0003", + "vlebrf %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31230008071E61010000003", + "lay %r1, -524288(%r2,%r3) ; vlebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 32, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3123FFF7F71E61010000003", + "lay %r1, 524287(%r2,%r3) ; vlebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61020000002", + "vlebrg %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0002", + "vlebrg %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31020008071E61010000002", + "lay %r1, -524288(%r2) ; vlebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3102FFF7F71E61010000002", + "lay %r1, 524287(%r2) ; vlebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E61230000002", + "vlebrg %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0002", + "vlebrg %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31230008071E61010000002", + "lay %r1, -524288(%r2,%r3) ; vlebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecLoadLaneRevUndef { + size: 64, + rd: writable_vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3123FFF7F71E61010000002", + "lay %r1, 524287(%r2,%r3) ; vlebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 16, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E61020007009", + "vstebrh %v1, 0(%r2), 7", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 16, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF0009", + "vstebrh %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 16, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 7, + }, + "E61230007009", + "vstebrh %v1, 0(%r2,%r3), 7", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 16, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF0009", + "vstebrh %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102000000B", + "vstebrf %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF000B", + "vstebrf %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31020008071E6101000000B", + "lay %r1, -524288(%r2) ; vstebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3102FFF7F71E6101000000B", + "lay %r1, 524287(%r2) ; vstebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123000000B", + "vstebrf %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF000B", + "vstebrf %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31230008071E6101000000B", + "lay %r1, -524288(%r2,%r3) ; vstebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 32, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3123FFF7F71E6101000000B", + "lay %r1, 524287(%r2,%r3) ; vstebrf %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102000000A", + "vstebrg %v1, 0(%r2), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(2), + index: zero_reg(), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6102FFF000A", + "vstebrg %v1, 4095(%r2), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31020008071E6101000000A", + "lay %r1, -524288(%r2) ; vstebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(2), + index: zero_reg(), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3102FFF7F71E6101000000A", + "lay %r1, 524287(%r2) ; vstebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::zero(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123000000A", + "vstebrg %v1, 0(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD12 { + base: gpr(3), + index: gpr(2), + disp: UImm12::maybe_from_u64(4095).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E6123FFF000A", + "vstebrg %v1, 4095(%r2,%r3), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(-524288).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E31230008071E6101000000A", + "lay %r1, -524288(%r2,%r3) ; vstebrg %v1, 0(%r1), 0", + )); + insns.push(( + Inst::VecStoreLaneRev { + size: 64, + rd: vr(1), + mem: MemArg::BXD20 { + base: gpr(3), + index: gpr(2), + disp: SImm20::maybe_from_i64(524287).unwrap(), + flags: MemFlags::trusted(), + }, + lane_imm: 0, + }, + "E3123FFF7F71E6101000000A", + "lay %r1, 524287(%r2,%r3) ; vstebrg %v1, 0(%r1), 0", + )); + + insns.push(( + Inst::VecInsertLane { + size: 8, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400000022", + "vlvgb %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLane { + size: 8, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF0022", + "vlvgb %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLane { + size: 8, + rd: writable_vr(24), + ri: vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430000822", + "vlvgb %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLane { + size: 16, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400001022", + "vlvgh %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLane { + size: 16, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF1022", + "vlvgh %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLane { + size: 16, + rd: writable_vr(24), + ri: vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430001822", + "vlvgh %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLane { + size: 32, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400002022", + "vlvgf %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLane { + size: 32, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF2022", + "vlvgf %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLane { + size: 32, + rd: writable_vr(24), + ri: vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430002822", + "vlvgf %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLane { + size: 64, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400003022", + "vlvgg %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLane { + size: 64, + rd: writable_vr(8), + ri: vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF3022", + "vlvgg %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLane { + size: 64, + rd: writable_vr(24), + ri: vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430003822", + "vlvgg %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 8, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400000022", + "vlvgb %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 8, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF0022", + "vlvgb %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 8, + rd: writable_vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430000822", + "vlvgb %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 16, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400001022", + "vlvgh %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 16, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF1022", + "vlvgh %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 16, + rd: writable_vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430001822", + "vlvgh %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 32, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400002022", + "vlvgf %v8, %r4, 0", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 32, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF2022", + "vlvgf %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 32, + rd: writable_vr(24), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430002822", + "vlvgf %v24, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 64, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "B3C10084", + "ldgr %f8, %r4", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 64, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF3022", + "vlvgg %v8, %r4, 255", + )); + insns.push(( + Inst::VecInsertLaneUndef { + size: 64, + rd: writable_vr(8), + rn: gpr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430003022", + "vlvgg %v8, %r4, 0(%r3)", + )); + insns.push(( + Inst::VecExtractLane { + size: 8, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF0021", + "vlgvb %r8, %v4, 255", + )); + insns.push(( + Inst::VecExtractLane { + size: 8, + rd: writable_gpr(8), + rn: vr(20), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430000421", + "vlgvb %r8, %v20, 0(%r3)", + )); + insns.push(( + Inst::VecExtractLane { + size: 16, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400001021", + "vlgvh %r8, %v4, 0", + )); + insns.push(( + Inst::VecExtractLane { + size: 16, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF1021", + "vlgvh %r8, %v4, 255", + )); + insns.push(( + Inst::VecExtractLane { + size: 16, + rd: writable_gpr(8), + rn: vr(20), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430001421", + "vlgvh %r8, %v20, 0(%r3)", + )); + insns.push(( + Inst::VecExtractLane { + size: 32, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "E78400002021", + "vlgvf %r8, %v4, 0", + )); + insns.push(( + Inst::VecExtractLane { + size: 32, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF2021", + "vlgvf %r8, %v4, 255", + )); + insns.push(( + Inst::VecExtractLane { + size: 32, + rd: writable_gpr(8), + rn: vr(20), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430002421", + "vlgvf %r8, %v20, 0(%r3)", + )); + insns.push(( + Inst::VecExtractLane { + size: 64, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 0, + lane_reg: zero_reg(), + }, + "B3CD0084", + "lgdr %r8, %f4", + )); + insns.push(( + Inst::VecExtractLane { + size: 64, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 255, + lane_reg: zero_reg(), + }, + "E78400FF3021", + "vlgvg %r8, %v4, 255", + )); + insns.push(( + Inst::VecExtractLane { + size: 64, + rd: writable_gpr(8), + rn: vr(4), + lane_imm: 0, + lane_reg: gpr(3), + }, + "E78430003021", + "vlgvg %r8, %v4, 0(%r3)", + )); + insns.push(( + Inst::VecInsertLaneImm { + size: 8, + rd: writable_vr(20), + ri: vr(20), + imm: 0x1234, + lane_imm: 15, + }, + "E7401234F840", + "vleib %v20, 4660, 15", + )); + insns.push(( + Inst::VecInsertLaneImm { + size: 16, + rd: writable_vr(20), + ri: vr(20), + imm: 0x1234, + lane_imm: 7, + }, + "E74012347841", + "vleih %v20, 4660, 7", + )); + insns.push(( + Inst::VecInsertLaneImm { + size: 32, + rd: writable_vr(20), + ri: vr(20), + imm: 0x1234, + lane_imm: 3, + }, + "E74012343843", + "vleif %v20, 4660, 3", + )); + insns.push(( + Inst::VecInsertLaneImm { + size: 64, + rd: writable_vr(20), + ri: vr(20), + imm: 0x1234, + lane_imm: 1, + }, + "E74012341842", + "vleig %v20, 4660, 1", + )); + insns.push(( + Inst::VecReplicateLane { + size: 8, + rd: writable_vr(20), + rn: vr(8), + lane_imm: 15, + }, + "E748000F084D", + "vrepb %v20, %v8, 15", + )); + insns.push(( + Inst::VecReplicateLane { + size: 16, + rd: writable_vr(20), + rn: vr(8), + lane_imm: 7, + }, + "E7480007184D", + "vreph %v20, %v8, 7", + )); + insns.push(( + Inst::VecReplicateLane { + size: 32, + rd: writable_vr(20), + rn: vr(8), + lane_imm: 3, + }, + "E7480003284D", + "vrepf %v20, %v8, 3", + )); + insns.push(( + Inst::VecReplicateLane { + size: 64, + rd: writable_vr(20), + rn: vr(8), + lane_imm: 1, + }, + "E7480001384D", + "vrepg %v20, %v8, 1", + )); + + let flags = settings::Flags::new(settings::builder()); + + use crate::settings::Configurable; + let mut isa_flag_builder = s390x_settings::builder(); + isa_flag_builder.enable("arch13").unwrap(); + let isa_flags = s390x_settings::Flags::new(&flags, &isa_flag_builder); + let ctrl_plane = &mut Default::default(); + let constants = Default::default(); + + let emit_info = EmitInfo::new(isa_flags); + for (insn, expected_encoding, expected_printing) in insns { + println!("S390x: {insn:?}, {expected_encoding}, {expected_printing}"); + + // Check the printed text is as expected. + let actual_printing = insn.print_with_state(&mut EmitState::default()); + assert_eq!(expected_printing, actual_printing); + + let mut buffer = MachBuffer::new(); + + // Label 0 before the instruction. + let label0 = buffer.get_label(); + buffer.bind_label(label0, ctrl_plane); + + // Emit the instruction. + insn.emit(&mut buffer, &emit_info, &mut Default::default()); + + // Label 1 after the instruction. + let label1 = buffer.get_label(); + buffer.bind_label(label1, ctrl_plane); + + let buffer = buffer.finish(&constants, ctrl_plane); + let actual_encoding = &buffer.stringify_code_bytes(); + assert_eq!(expected_encoding, actual_encoding); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/imms.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/imms.rs new file mode 100644 index 00000000000000..8ceebbcdac15c8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/imms.rs @@ -0,0 +1,202 @@ +//! S390x ISA definitions: immediate constants. + +use crate::machinst::PrettyPrint; +use std::string::String; + +/// An unsigned 12-bit immediate. +#[derive(Clone, Copy, Debug)] +pub struct UImm12 { + /// The value. + value: u16, +} + +impl UImm12 { + pub fn maybe_from_u64(value: u64) -> Option { + if value < 4096 { + Some(UImm12 { + value: value as u16, + }) + } else { + None + } + } + + /// Create a zero immediate of this format. + pub fn zero() -> UImm12 { + UImm12 { value: 0 } + } + + /// Bits for encoding. + pub fn bits(&self) -> u32 { + u32::from(self.value) + } +} + +/// A signed 20-bit immediate. +#[derive(Clone, Copy, Debug)] +pub struct SImm20 { + /// The value. + value: i32, +} + +impl SImm20 { + pub fn maybe_from_i64(value: i64) -> Option { + if value >= -524288 && value < 524288 { + Some(SImm20 { + value: value as i32, + }) + } else { + None + } + } + + pub fn from_uimm12(value: UImm12) -> SImm20 { + SImm20 { + value: value.bits() as i32, + } + } + + /// Bits for encoding. + pub fn bits(&self) -> u32 { + let encoded: u32 = self.value as u32; + encoded & 0xfffff + } +} + +/// A 16-bit immediate with a {0,16,32,48}-bit shift. +#[derive(Clone, Copy, Debug)] +pub struct UImm16Shifted { + /// The value. + pub bits: u16, + /// Result is `bits` shifted 16*shift bits to the left. + pub shift: u8, +} + +impl UImm16Shifted { + /// Construct a UImm16Shifted from an arbitrary 64-bit constant if possible. + pub fn maybe_from_u64(value: u64) -> Option { + let mask0 = 0x0000_0000_0000_ffffu64; + let mask1 = 0x0000_0000_ffff_0000u64; + let mask2 = 0x0000_ffff_0000_0000u64; + let mask3 = 0xffff_0000_0000_0000u64; + + if value == (value & mask0) { + return Some(UImm16Shifted { + bits: (value & mask0) as u16, + shift: 0, + }); + } + if value == (value & mask1) { + return Some(UImm16Shifted { + bits: ((value >> 16) & mask0) as u16, + shift: 1, + }); + } + if value == (value & mask2) { + return Some(UImm16Shifted { + bits: ((value >> 32) & mask0) as u16, + shift: 2, + }); + } + if value == (value & mask3) { + return Some(UImm16Shifted { + bits: ((value >> 48) & mask0) as u16, + shift: 3, + }); + } + None + } + + pub fn maybe_with_shift(imm: u16, shift: u8) -> Option { + let shift_enc = shift / 16; + if shift_enc > 3 { + None + } else { + Some(UImm16Shifted { + bits: imm, + shift: shift_enc, + }) + } + } + + pub fn negate_bits(&self) -> UImm16Shifted { + UImm16Shifted { + bits: !self.bits, + shift: self.shift, + } + } +} + +/// A 32-bit immediate with a {0,32}-bit shift. +#[derive(Clone, Copy, Debug)] +pub struct UImm32Shifted { + /// The value. + pub bits: u32, + /// Result is `bits` shifted 32*shift bits to the left. + pub shift: u8, +} + +impl UImm32Shifted { + /// Construct a UImm32Shifted from an arbitrary 64-bit constant if possible. + pub fn maybe_from_u64(value: u64) -> Option { + let mask0 = 0x0000_0000_ffff_ffffu64; + let mask1 = 0xffff_ffff_0000_0000u64; + + if value == (value & mask0) { + return Some(UImm32Shifted { + bits: (value & mask0) as u32, + shift: 0, + }); + } + if value == (value & mask1) { + return Some(UImm32Shifted { + bits: ((value >> 32) & mask0) as u32, + shift: 1, + }); + } + None + } + + pub fn maybe_with_shift(imm: u32, shift: u8) -> Option { + let shift_enc = shift / 32; + if shift_enc > 3 { + None + } else { + Some(UImm32Shifted { + bits: imm, + shift: shift_enc, + }) + } + } + + pub fn negate_bits(&self) -> UImm32Shifted { + UImm32Shifted { + bits: !self.bits, + shift: self.shift, + } + } +} + +impl PrettyPrint for UImm12 { + fn pretty_print(&self, _: u8) -> String { + format!("{}", self.value) + } +} + +impl PrettyPrint for SImm20 { + fn pretty_print(&self, _: u8) -> String { + format!("{}", self.value) + } +} + +impl PrettyPrint for UImm16Shifted { + fn pretty_print(&self, _: u8) -> String { + format!("{}", self.bits) + } +} + +impl PrettyPrint for UImm32Shifted { + fn pretty_print(&self, _: u8) -> String { + format!("{}", self.bits) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/mod.rs new file mode 100644 index 00000000000000..75e7daab707fea --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/mod.rs @@ -0,0 +1,3441 @@ +//! This module defines s390x-specific machine instruction types. + +use crate::binemit::{Addend, CodeOffset, Reloc}; +use crate::ir::{types, ExternalName, Type}; +use crate::isa::s390x::abi::S390xMachineDeps; +use crate::isa::{CallConv, FunctionAlignment}; +use crate::machinst::*; +use crate::{settings, CodegenError, CodegenResult}; +use alloc::boxed::Box; +use alloc::vec::Vec; +use regalloc2::{PReg, PRegSet}; +use smallvec::SmallVec; +use std::fmt::Write; +use std::string::{String, ToString}; +pub mod regs; +pub use self::regs::*; +pub mod imms; +pub use self::imms::*; +pub mod args; +pub use self::args::*; +pub mod emit; +pub use self::emit::*; +pub mod unwind; + +#[cfg(test)] +mod emit_tests; + +//============================================================================= +// Instructions (top level): definition + +pub use crate::isa::s390x::lower::isle::generated_code::{ + ALUOp, CmpOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode, FpuRoundOp, LaneOrder, MInst as Inst, + RxSBGOp, ShiftOp, SymbolReloc, UnaryOp, VecBinaryOp, VecFloatCmpOp, VecIntCmpOp, VecShiftOp, + VecUnaryOp, +}; + +/// Additional information for (direct) ReturnCall instructions, left out of line to lower the size of +/// the Inst enum. +#[derive(Clone, Debug)] +pub struct ReturnCallInfo { + pub dest: T, + pub uses: CallArgList, + pub callee_pop_size: u32, +} + +#[test] +fn inst_size_test() { + // This test will help with unintentionally growing the size + // of the Inst enum. + assert_eq!(32, std::mem::size_of::()); +} + +/// A register pair. Enum so it can be destructured in ISLE. +#[derive(Clone, Copy, Debug)] +pub struct RegPair { + pub hi: Reg, + pub lo: Reg, +} + +/// A writable register pair. Enum so it can be destructured in ISLE. +#[derive(Clone, Copy, Debug)] +pub struct WritableRegPair { + pub hi: Writable, + pub lo: Writable, +} + +impl WritableRegPair { + pub fn to_regpair(&self) -> RegPair { + RegPair { + hi: self.hi.to_reg(), + lo: self.lo.to_reg(), + } + } +} + +/// Supported instruction sets +#[allow(non_camel_case_types)] +#[derive(Debug)] +pub(crate) enum InstructionSet { + /// Baseline ISA for cranelift is z14. + Base, + /// Miscellaneous-Instruction-Extensions Facility 2 (z15) + MIE2, + /// Vector-Enhancements Facility 2 (z15) + VXRS_EXT2, +} + +impl Inst { + /// Retrieve the ISA feature set in which the instruction is available. + fn available_in_isa(&self) -> InstructionSet { + match self { + // These instructions are part of the baseline ISA for cranelift (z14) + Inst::Nop0 + | Inst::Nop2 + | Inst::AluRRSImm16 { .. } + | Inst::AluRR { .. } + | Inst::AluRX { .. } + | Inst::AluRSImm16 { .. } + | Inst::AluRSImm32 { .. } + | Inst::AluRUImm32 { .. } + | Inst::AluRUImm16Shifted { .. } + | Inst::AluRUImm32Shifted { .. } + | Inst::ShiftRR { .. } + | Inst::RxSBG { .. } + | Inst::RxSBGTest { .. } + | Inst::SMulWide { .. } + | Inst::UMulWide { .. } + | Inst::SDivMod32 { .. } + | Inst::SDivMod64 { .. } + | Inst::UDivMod32 { .. } + | Inst::UDivMod64 { .. } + | Inst::Flogr { .. } + | Inst::CmpRR { .. } + | Inst::CmpRX { .. } + | Inst::CmpRSImm16 { .. } + | Inst::CmpRSImm32 { .. } + | Inst::CmpRUImm32 { .. } + | Inst::CmpTrapRR { .. } + | Inst::CmpTrapRSImm16 { .. } + | Inst::CmpTrapRUImm16 { .. } + | Inst::AtomicRmw { .. } + | Inst::AtomicCas32 { .. } + | Inst::AtomicCas64 { .. } + | Inst::Fence + | Inst::Load32 { .. } + | Inst::Load32ZExt8 { .. } + | Inst::Load32SExt8 { .. } + | Inst::Load32ZExt16 { .. } + | Inst::Load32SExt16 { .. } + | Inst::Load64 { .. } + | Inst::Load64ZExt8 { .. } + | Inst::Load64SExt8 { .. } + | Inst::Load64ZExt16 { .. } + | Inst::Load64SExt16 { .. } + | Inst::Load64ZExt32 { .. } + | Inst::Load64SExt32 { .. } + | Inst::LoadRev16 { .. } + | Inst::LoadRev32 { .. } + | Inst::LoadRev64 { .. } + | Inst::Store8 { .. } + | Inst::Store16 { .. } + | Inst::Store32 { .. } + | Inst::Store64 { .. } + | Inst::StoreImm8 { .. } + | Inst::StoreImm16 { .. } + | Inst::StoreImm32SExt16 { .. } + | Inst::StoreImm64SExt16 { .. } + | Inst::StoreRev16 { .. } + | Inst::StoreRev32 { .. } + | Inst::StoreRev64 { .. } + | Inst::LoadMultiple64 { .. } + | Inst::StoreMultiple64 { .. } + | Inst::Mov32 { .. } + | Inst::Mov64 { .. } + | Inst::MovPReg { .. } + | Inst::Mov32Imm { .. } + | Inst::Mov32SImm16 { .. } + | Inst::Mov64SImm16 { .. } + | Inst::Mov64SImm32 { .. } + | Inst::Mov64UImm16Shifted { .. } + | Inst::Mov64UImm32Shifted { .. } + | Inst::Insert64UImm16Shifted { .. } + | Inst::Insert64UImm32Shifted { .. } + | Inst::LoadAR { .. } + | Inst::InsertAR { .. } + | Inst::Extend { .. } + | Inst::CMov32 { .. } + | Inst::CMov64 { .. } + | Inst::CMov32SImm16 { .. } + | Inst::CMov64SImm16 { .. } + | Inst::FpuMove32 { .. } + | Inst::FpuMove64 { .. } + | Inst::FpuCMov32 { .. } + | Inst::FpuCMov64 { .. } + | Inst::FpuRR { .. } + | Inst::FpuRRR { .. } + | Inst::FpuRRRR { .. } + | Inst::FpuCmp32 { .. } + | Inst::FpuCmp64 { .. } + | Inst::LoadFpuConst32 { .. } + | Inst::LoadFpuConst64 { .. } + | Inst::VecRRR { .. } + | Inst::VecRR { .. } + | Inst::VecShiftRR { .. } + | Inst::VecSelect { .. } + | Inst::VecPermute { .. } + | Inst::VecPermuteDWImm { .. } + | Inst::VecIntCmp { .. } + | Inst::VecIntCmpS { .. } + | Inst::VecFloatCmp { .. } + | Inst::VecFloatCmpS { .. } + | Inst::VecInt128SCmpHi { .. } + | Inst::VecInt128UCmpHi { .. } + | Inst::VecLoad { .. } + | Inst::VecStore { .. } + | Inst::VecLoadReplicate { .. } + | Inst::VecMov { .. } + | Inst::VecCMov { .. } + | Inst::MovToVec128 { .. } + | Inst::VecLoadConst { .. } + | Inst::VecLoadConstReplicate { .. } + | Inst::VecImmByteMask { .. } + | Inst::VecImmBitMask { .. } + | Inst::VecImmReplicate { .. } + | Inst::VecLoadLane { .. } + | Inst::VecLoadLaneUndef { .. } + | Inst::VecStoreLane { .. } + | Inst::VecInsertLane { .. } + | Inst::VecInsertLaneUndef { .. } + | Inst::VecExtractLane { .. } + | Inst::VecInsertLaneImm { .. } + | Inst::VecReplicateLane { .. } + | Inst::AllocateArgs { .. } + | Inst::Call { .. } + | Inst::CallInd { .. } + | Inst::ReturnCall { .. } + | Inst::ReturnCallInd { .. } + | Inst::Args { .. } + | Inst::Rets { .. } + | Inst::Ret { .. } + | Inst::Jump { .. } + | Inst::CondBr { .. } + | Inst::TrapIf { .. } + | Inst::OneWayCondBr { .. } + | Inst::IndirectBr { .. } + | Inst::Debugtrap + | Inst::Trap { .. } + | Inst::JTSequence { .. } + | Inst::StackProbeLoop { .. } + | Inst::LoadSymbolReloc { .. } + | Inst::LoadAddr { .. } + | Inst::Loop { .. } + | Inst::CondBreak { .. } + | Inst::Unwind { .. } + | Inst::ElfTlsGetOffset { .. } => InstructionSet::Base, + + // These depend on the opcode + Inst::AluRRR { alu_op, .. } => match alu_op { + ALUOp::NotAnd32 | ALUOp::NotAnd64 => InstructionSet::MIE2, + ALUOp::NotOrr32 | ALUOp::NotOrr64 => InstructionSet::MIE2, + ALUOp::NotXor32 | ALUOp::NotXor64 => InstructionSet::MIE2, + ALUOp::AndNot32 | ALUOp::AndNot64 => InstructionSet::MIE2, + ALUOp::OrrNot32 | ALUOp::OrrNot64 => InstructionSet::MIE2, + _ => InstructionSet::Base, + }, + Inst::UnaryRR { op, .. } => match op { + UnaryOp::PopcntReg => InstructionSet::MIE2, + _ => InstructionSet::Base, + }, + Inst::FpuRound { op, .. } => match op { + FpuRoundOp::ToSInt32 | FpuRoundOp::FromSInt32 => InstructionSet::VXRS_EXT2, + FpuRoundOp::ToUInt32 | FpuRoundOp::FromUInt32 => InstructionSet::VXRS_EXT2, + FpuRoundOp::ToSInt32x4 | FpuRoundOp::FromSInt32x4 => InstructionSet::VXRS_EXT2, + FpuRoundOp::ToUInt32x4 | FpuRoundOp::FromUInt32x4 => InstructionSet::VXRS_EXT2, + _ => InstructionSet::Base, + }, + + // These are all part of VXRS_EXT2 + Inst::VecLoadRev { .. } + | Inst::VecLoadByte16Rev { .. } + | Inst::VecLoadByte32Rev { .. } + | Inst::VecLoadByte64Rev { .. } + | Inst::VecLoadElt16Rev { .. } + | Inst::VecLoadElt32Rev { .. } + | Inst::VecLoadElt64Rev { .. } + | Inst::VecStoreRev { .. } + | Inst::VecStoreByte16Rev { .. } + | Inst::VecStoreByte32Rev { .. } + | Inst::VecStoreByte64Rev { .. } + | Inst::VecStoreElt16Rev { .. } + | Inst::VecStoreElt32Rev { .. } + | Inst::VecStoreElt64Rev { .. } + | Inst::VecLoadReplicateRev { .. } + | Inst::VecLoadLaneRev { .. } + | Inst::VecLoadLaneRevUndef { .. } + | Inst::VecStoreLaneRev { .. } => InstructionSet::VXRS_EXT2, + + Inst::DummyUse { .. } => InstructionSet::Base, + } + } + + /// Create a 128-bit move instruction. + pub fn mov128(to_reg: Writable, from_reg: Reg) -> Inst { + assert!(to_reg.to_reg().class() == RegClass::Float); + assert!(from_reg.class() == RegClass::Float); + Inst::VecMov { + rd: to_reg, + rn: from_reg, + } + } + + /// Create a 64-bit move instruction. + pub fn mov64(to_reg: Writable, from_reg: Reg) -> Inst { + assert!(to_reg.to_reg().class() == from_reg.class()); + if from_reg.class() == RegClass::Int { + Inst::Mov64 { + rd: to_reg, + rm: from_reg, + } + } else { + Inst::FpuMove64 { + rd: to_reg, + rn: from_reg, + } + } + } + + /// Create a 32-bit move instruction. + pub fn mov32(to_reg: Writable, from_reg: Reg) -> Inst { + if from_reg.class() == RegClass::Int { + Inst::Mov32 { + rd: to_reg, + rm: from_reg, + } + } else { + Inst::FpuMove32 { + rd: to_reg, + rn: from_reg, + } + } + } + + /// Generic constructor for a load (zero-extending where appropriate). + pub fn gen_load(into_reg: Writable, mem: MemArg, ty: Type) -> Inst { + match ty { + types::I8 => Inst::Load64ZExt8 { rd: into_reg, mem }, + types::I16 => Inst::Load64ZExt16 { rd: into_reg, mem }, + types::I32 => Inst::Load64ZExt32 { rd: into_reg, mem }, + types::I64 => Inst::Load64 { rd: into_reg, mem }, + types::F32 => Inst::VecLoadLaneUndef { + size: 32, + rd: into_reg, + mem, + lane_imm: 0, + }, + types::F64 => Inst::VecLoadLaneUndef { + size: 64, + rd: into_reg, + mem, + lane_imm: 0, + }, + _ if ty.is_vector() && ty.bits() == 128 => Inst::VecLoad { rd: into_reg, mem }, + types::I128 => Inst::VecLoad { rd: into_reg, mem }, + _ => unimplemented!("gen_load({})", ty), + } + } + + /// Generic constructor for a store. + pub fn gen_store(mem: MemArg, from_reg: Reg, ty: Type) -> Inst { + match ty { + types::I8 => Inst::Store8 { rd: from_reg, mem }, + types::I16 => Inst::Store16 { rd: from_reg, mem }, + types::I32 => Inst::Store32 { rd: from_reg, mem }, + types::I64 => Inst::Store64 { rd: from_reg, mem }, + types::F32 => Inst::VecStoreLane { + size: 32, + rd: from_reg, + mem, + lane_imm: 0, + }, + types::F64 => Inst::VecStoreLane { + size: 64, + rd: from_reg, + mem, + lane_imm: 0, + }, + _ if ty.is_vector() && ty.bits() == 128 => Inst::VecStore { rd: from_reg, mem }, + types::I128 => Inst::VecStore { rd: from_reg, mem }, + _ => unimplemented!("gen_store({})", ty), + } + } +} + +//============================================================================= +// Instructions: get_regs + +fn memarg_operands(memarg: &mut MemArg, collector: &mut impl OperandVisitor) { + match memarg { + MemArg::BXD12 { base, index, .. } | MemArg::BXD20 { base, index, .. } => { + collector.reg_use(base); + collector.reg_use(index); + } + MemArg::Label { .. } | MemArg::Symbol { .. } => {} + MemArg::RegOffset { reg, .. } => { + collector.reg_use(reg); + } + MemArg::InitialSPOffset { .. } + | MemArg::NominalSPOffset { .. } + | MemArg::SlotOffset { .. } => {} + } + // mem_finalize might require %r1 to hold (part of) the address. + // Conservatively assume this will always be necessary here. + collector.reg_fixed_nonallocatable(gpr_preg(1)); +} + +fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor) { + match inst { + Inst::AluRRR { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::AluRRSImm16 { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::AluRR { rd, ri, rm, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rm); + } + Inst::AluRX { rd, ri, mem, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + memarg_operands(mem, collector); + } + Inst::AluRSImm16 { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::AluRSImm32 { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::AluRUImm32 { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::AluRUImm16Shifted { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::AluRUImm32Shifted { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::SMulWide { rd, rn, rm } => { + collector.reg_use(rn); + collector.reg_use(rm); + // FIXME: The pair is hard-coded as %r2/%r3 because regalloc cannot handle pairs. If + // that changes, all the hard-coded uses of %r2/%r3 can be changed. + collector.reg_fixed_def(&mut rd.hi, gpr(2)); + collector.reg_fixed_def(&mut rd.lo, gpr(3)); + } + Inst::UMulWide { rd, ri, rn } => { + collector.reg_use(rn); + collector.reg_fixed_def(&mut rd.hi, gpr(2)); + collector.reg_fixed_def(&mut rd.lo, gpr(3)); + collector.reg_fixed_use(ri, gpr(3)); + } + Inst::SDivMod32 { rd, ri, rn } | Inst::SDivMod64 { rd, ri, rn } => { + collector.reg_use(rn); + collector.reg_fixed_def(&mut rd.hi, gpr(2)); + collector.reg_fixed_def(&mut rd.lo, gpr(3)); + collector.reg_fixed_use(ri, gpr(3)); + } + Inst::UDivMod32 { rd, ri, rn } | Inst::UDivMod64 { rd, ri, rn } => { + collector.reg_use(rn); + collector.reg_fixed_def(&mut rd.hi, gpr(2)); + collector.reg_fixed_def(&mut rd.lo, gpr(3)); + collector.reg_fixed_use(&mut ri.hi, gpr(2)); + collector.reg_fixed_use(&mut ri.lo, gpr(3)); + } + Inst::Flogr { rd, rn } => { + collector.reg_use(rn); + collector.reg_fixed_def(&mut rd.hi, gpr(2)); + collector.reg_fixed_def(&mut rd.lo, gpr(3)); + } + Inst::ShiftRR { + rd, rn, shift_reg, .. + } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(shift_reg); + } + Inst::RxSBG { rd, ri, rn, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rn); + } + Inst::RxSBGTest { rd, rn, .. } => { + collector.reg_use(rd); + collector.reg_use(rn); + } + Inst::UnaryRR { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::CmpRR { rn, rm, .. } => { + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::CmpRX { rn, mem, .. } => { + collector.reg_use(rn); + memarg_operands(mem, collector); + } + Inst::CmpRSImm16 { rn, .. } => { + collector.reg_use(rn); + } + Inst::CmpRSImm32 { rn, .. } => { + collector.reg_use(rn); + } + Inst::CmpRUImm32 { rn, .. } => { + collector.reg_use(rn); + } + Inst::CmpTrapRR { rn, rm, .. } => { + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::CmpTrapRSImm16 { rn, .. } => { + collector.reg_use(rn); + } + Inst::CmpTrapRUImm16 { rn, .. } => { + collector.reg_use(rn); + } + Inst::AtomicRmw { rd, rn, mem, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + memarg_operands(mem, collector); + } + Inst::AtomicCas32 { + rd, ri, rn, mem, .. + } + | Inst::AtomicCas64 { + rd, ri, rn, mem, .. + } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rn); + memarg_operands(mem, collector); + } + Inst::Fence => {} + Inst::Load32 { rd, mem, .. } + | Inst::Load32ZExt8 { rd, mem, .. } + | Inst::Load32SExt8 { rd, mem, .. } + | Inst::Load32ZExt16 { rd, mem, .. } + | Inst::Load32SExt16 { rd, mem, .. } + | Inst::Load64 { rd, mem, .. } + | Inst::Load64ZExt8 { rd, mem, .. } + | Inst::Load64SExt8 { rd, mem, .. } + | Inst::Load64ZExt16 { rd, mem, .. } + | Inst::Load64SExt16 { rd, mem, .. } + | Inst::Load64ZExt32 { rd, mem, .. } + | Inst::Load64SExt32 { rd, mem, .. } + | Inst::LoadRev16 { rd, mem, .. } + | Inst::LoadRev32 { rd, mem, .. } + | Inst::LoadRev64 { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::Store8 { rd, mem, .. } + | Inst::Store16 { rd, mem, .. } + | Inst::Store32 { rd, mem, .. } + | Inst::Store64 { rd, mem, .. } + | Inst::StoreRev16 { rd, mem, .. } + | Inst::StoreRev32 { rd, mem, .. } + | Inst::StoreRev64 { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::StoreImm8 { mem, .. } + | Inst::StoreImm16 { mem, .. } + | Inst::StoreImm32SExt16 { mem, .. } + | Inst::StoreImm64SExt16 { mem, .. } => { + memarg_operands(mem, collector); + } + Inst::LoadMultiple64 { rt, rt2, mem, .. } => { + memarg_operands(mem, collector); + let first_regnum = rt.to_reg().to_real_reg().unwrap().hw_enc(); + let last_regnum = rt2.to_reg().to_real_reg().unwrap().hw_enc(); + for regnum in first_regnum..last_regnum + 1 { + collector.reg_fixed_nonallocatable(gpr_preg(regnum)); + } + } + Inst::StoreMultiple64 { rt, rt2, mem, .. } => { + memarg_operands(mem, collector); + let first_regnum = rt.to_real_reg().unwrap().hw_enc(); + let last_regnum = rt2.to_real_reg().unwrap().hw_enc(); + for regnum in first_regnum..last_regnum + 1 { + collector.reg_fixed_nonallocatable(gpr_preg(regnum)); + } + } + Inst::Mov64 { rd, rm } => { + collector.reg_def(rd); + collector.reg_use(rm); + } + Inst::MovPReg { rd, rm } => { + collector.reg_def(rd); + collector.reg_fixed_nonallocatable(*rm); + } + Inst::Mov32 { rd, rm } => { + collector.reg_def(rd); + collector.reg_use(rm); + } + Inst::Mov32Imm { rd, .. } + | Inst::Mov32SImm16 { rd, .. } + | Inst::Mov64SImm16 { rd, .. } + | Inst::Mov64SImm32 { rd, .. } + | Inst::Mov64UImm16Shifted { rd, .. } + | Inst::Mov64UImm32Shifted { rd, .. } => { + collector.reg_def(rd); + } + Inst::CMov32 { rd, ri, rm, .. } | Inst::CMov64 { rd, ri, rm, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rm); + } + Inst::CMov32SImm16 { rd, ri, .. } | Inst::CMov64SImm16 { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::Insert64UImm16Shifted { rd, ri, .. } | Inst::Insert64UImm32Shifted { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::LoadAR { rd, .. } => { + collector.reg_def(rd); + } + Inst::InsertAR { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::FpuMove32 { rd, rn } | Inst::FpuMove64 { rd, rn } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::FpuCMov32 { rd, ri, rm, .. } | Inst::FpuCMov64 { rd, ri, rm, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rm); + } + Inst::FpuRR { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::FpuRRR { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::FpuRRRR { rd, rn, rm, ra, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + collector.reg_use(ra); + } + Inst::FpuCmp32 { rn, rm } | Inst::FpuCmp64 { rn, rm } => { + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::LoadFpuConst32 { rd, .. } | Inst::LoadFpuConst64 { rd, .. } => { + collector.reg_def(rd); + collector.reg_fixed_nonallocatable(gpr_preg(1)); + } + Inst::FpuRound { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::VecRRR { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecRR { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::VecShiftRR { + rd, rn, shift_reg, .. + } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(shift_reg); + } + Inst::VecSelect { rd, rn, rm, ra, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + collector.reg_use(ra); + } + Inst::VecPermute { rd, rn, rm, ra, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + collector.reg_use(ra); + } + Inst::VecPermuteDWImm { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecIntCmp { rd, rn, rm, .. } | Inst::VecIntCmpS { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecFloatCmp { rd, rn, rm, .. } | Inst::VecFloatCmpS { rd, rn, rm, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecInt128SCmpHi { tmp, rn, rm, .. } | Inst::VecInt128UCmpHi { tmp, rn, rm, .. } => { + collector.reg_def(tmp); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecLoad { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadRev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadByte16Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadByte32Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadByte64Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadElt16Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadElt32Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadElt64Rev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecStore { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreRev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreByte16Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreByte32Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreByte64Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreElt16Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreElt32Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreElt64Rev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadReplicate { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadReplicateRev { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecMov { rd, rn } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::VecCMov { rd, ri, rm, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rm); + } + Inst::MovToVec128 { rd, rn, rm } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(rm); + } + Inst::VecLoadConst { rd, .. } | Inst::VecLoadConstReplicate { rd, .. } => { + collector.reg_def(rd); + collector.reg_fixed_nonallocatable(gpr_preg(1)); + } + Inst::VecImmByteMask { rd, .. } => { + collector.reg_def(rd); + } + Inst::VecImmBitMask { rd, .. } => { + collector.reg_def(rd); + } + Inst::VecImmReplicate { rd, .. } => { + collector.reg_def(rd); + } + Inst::VecLoadLane { rd, ri, mem, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + memarg_operands(mem, collector); + } + Inst::VecLoadLaneUndef { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreLaneRev { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadLaneRevUndef { rd, mem, .. } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::VecStoreLane { rd, mem, .. } => { + collector.reg_use(rd); + memarg_operands(mem, collector); + } + Inst::VecLoadLaneRev { rd, ri, mem, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + memarg_operands(mem, collector); + } + Inst::VecInsertLane { + rd, + ri, + rn, + lane_reg, + .. + } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + collector.reg_use(rn); + collector.reg_use(lane_reg); + } + Inst::VecInsertLaneUndef { + rd, rn, lane_reg, .. + } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(lane_reg); + } + Inst::VecExtractLane { + rd, rn, lane_reg, .. + } => { + collector.reg_def(rd); + collector.reg_use(rn); + collector.reg_use(lane_reg); + } + Inst::VecInsertLaneImm { rd, ri, .. } => { + collector.reg_reuse_def(rd, 1); + collector.reg_use(ri); + } + Inst::VecReplicateLane { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::Extend { rd, rn, .. } => { + collector.reg_def(rd); + collector.reg_use(rn); + } + Inst::AllocateArgs { .. } => {} + Inst::Call { link, info, .. } => { + let CallInfo { + uses, + defs, + clobbers, + .. + } = &mut **info; + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + let mut clobbers = *clobbers; + clobbers.add(link.to_reg().to_real_reg().unwrap().into()); + for CallRetPair { vreg, preg } in defs { + clobbers.remove(PReg::from(preg.to_real_reg().unwrap())); + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(clobbers); + } + Inst::CallInd { link, info } => { + let CallInfo { + dest, + uses, + defs, + clobbers, + .. + } = &mut **info; + collector.reg_use(dest); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + let mut clobbers = *clobbers; + clobbers.add(link.to_reg().to_real_reg().unwrap().into()); + for CallRetPair { vreg, preg } in defs { + clobbers.remove(PReg::from(preg.to_real_reg().unwrap())); + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(clobbers); + } + Inst::ReturnCall { info } => { + let ReturnCallInfo { uses, .. } = &mut **info; + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::ReturnCallInd { info } => { + let ReturnCallInfo { dest, uses, .. } = &mut **info; + collector.reg_use(dest); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::ElfTlsGetOffset { + tls_offset, + got, + got_offset, + .. + } => { + collector.reg_fixed_use(got, gpr(12)); + collector.reg_fixed_use(got_offset, gpr(2)); + collector.reg_fixed_def(tls_offset, gpr(2)); + + let mut clobbers = S390xMachineDeps::get_regs_clobbered_by_call(CallConv::SystemV); + clobbers.add(gpr_preg(14)); + clobbers.remove(gpr_preg(2)); + collector.reg_clobbers(clobbers); + } + Inst::Args { args } => { + for ArgPair { vreg, preg } in args { + collector.reg_fixed_def(vreg, *preg); + } + } + Inst::Rets { rets } => { + for RetPair { vreg, preg } in rets { + collector.reg_fixed_use(vreg, *preg); + } + } + Inst::Ret { .. } => { + // NOTE: we explicitly don't mark the link register as used here, as the use is only in + // the epilog where callee-save registers are restored. + } + Inst::Jump { .. } => {} + Inst::IndirectBr { rn, .. } => { + collector.reg_use(rn); + } + Inst::CondBr { .. } | Inst::OneWayCondBr { .. } => {} + Inst::Nop0 | Inst::Nop2 => {} + Inst::Debugtrap => {} + Inst::Trap { .. } => {} + Inst::TrapIf { .. } => {} + Inst::JTSequence { ridx, .. } => { + collector.reg_use(ridx); + collector.reg_fixed_nonallocatable(gpr_preg(1)); + } + Inst::LoadSymbolReloc { rd, .. } => { + collector.reg_def(rd); + collector.reg_fixed_nonallocatable(gpr_preg(1)); + } + Inst::LoadAddr { rd, mem } => { + collector.reg_def(rd); + memarg_operands(mem, collector); + } + Inst::StackProbeLoop { probe_count, .. } => { + collector.reg_early_def(probe_count); + } + Inst::Loop { body, .. } => { + // `reuse_def` constraints can't be permitted in a Loop instruction because the operand + // index will always be relative to the Loop instruction, not the individual + // instruction in the loop body. However, fixed-nonallocatable registers used with + // instructions that would have emitted `reuse_def` constraints are fine. + let mut collector = DenyReuseVisitor { + inner: collector.inner, + deny_reuse: true, + }; + for inst in body { + s390x_get_operands(inst, &mut collector); + } + } + Inst::CondBreak { .. } => {} + Inst::Unwind { .. } => {} + Inst::DummyUse { reg } => { + collector.reg_use(reg); + } + } +} + +struct DenyReuseVisitor<'a, T> { + inner: &'a mut T, + deny_reuse: bool, +} + +impl OperandVisitor for DenyReuseVisitor<'_, T> { + fn add_operand( + &mut self, + reg: &mut Reg, + constraint: regalloc2::OperandConstraint, + kind: regalloc2::OperandKind, + pos: regalloc2::OperandPos, + ) { + debug_assert!( + !self.deny_reuse || !matches!(constraint, regalloc2::OperandConstraint::Reuse(_)) + ); + self.inner.add_operand(reg, constraint, kind, pos); + } + + fn debug_assert_is_allocatable_preg(&self, reg: regalloc2::PReg, expected: bool) { + self.inner.debug_assert_is_allocatable_preg(reg, expected); + } + + fn reg_clobbers(&mut self, regs: PRegSet) { + self.inner.reg_clobbers(regs); + } +} + +//============================================================================= +// Instructions: misc functions and external interface + +impl MachInst for Inst { + type ABIMachineSpec = S390xMachineDeps; + type LabelUse = LabelUse; + const TRAP_OPCODE: &'static [u8] = &[0, 0]; + + fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + s390x_get_operands( + self, + &mut DenyReuseVisitor { + inner: collector, + deny_reuse: false, + }, + ); + } + + fn is_move(&self) -> Option<(Writable, Reg)> { + match self { + &Inst::Mov32 { rd, rm } => Some((rd, rm)), + &Inst::Mov64 { rd, rm } => Some((rd, rm)), + &Inst::FpuMove32 { rd, rn } => Some((rd, rn)), + &Inst::FpuMove64 { rd, rn } => Some((rd, rn)), + &Inst::VecMov { rd, rn } => Some((rd, rn)), + _ => None, + } + } + + fn is_included_in_clobbers(&self) -> bool { + // We exclude call instructions from the clobber-set when they are calls + // from caller to callee with the same ABI. Such calls cannot possibly + // force any new registers to be saved in the prologue, because anything + // that the callee clobbers, the caller is also allowed to clobber. This + // both saves work and enables us to more precisely follow the + // half-caller-save, half-callee-save SysV ABI for some vector + // registers. + match self { + &Inst::Args { .. } => false, + &Inst::Call { ref info, .. } => info.caller_conv != info.callee_conv, + &Inst::CallInd { ref info, .. } => info.caller_conv != info.callee_conv, + &Inst::ElfTlsGetOffset { .. } => false, + _ => true, + } + } + + fn is_trap(&self) -> bool { + match self { + Self::Trap { .. } => true, + _ => false, + } + } + + fn is_args(&self) -> bool { + match self { + Self::Args { .. } => true, + _ => false, + } + } + + fn is_term(&self) -> MachTerminator { + match self { + &Inst::Rets { .. } => MachTerminator::Ret, + &Inst::ReturnCall { .. } | &Inst::ReturnCallInd { .. } => MachTerminator::RetCall, + &Inst::Jump { .. } => MachTerminator::Uncond, + &Inst::CondBr { .. } => MachTerminator::Cond, + &Inst::OneWayCondBr { .. } => { + // Explicitly invisible to CFG processing. + MachTerminator::None + } + &Inst::IndirectBr { .. } => MachTerminator::Indirect, + &Inst::JTSequence { .. } => MachTerminator::Indirect, + _ => MachTerminator::None, + } + } + + fn is_mem_access(&self) -> bool { + panic!("TODO FILL ME OUT") + } + + fn is_safepoint(&self) -> bool { + match self { + Inst::Call { .. } | Inst::CallInd { .. } => true, + _ => false, + } + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { + assert!(ty.bits() <= 128); + if ty.bits() <= 32 { + Inst::mov32(to_reg, from_reg) + } else if ty.bits() <= 64 { + Inst::mov64(to_reg, from_reg) + } else { + Inst::mov128(to_reg, from_reg) + } + } + + fn gen_nop(preferred_size: usize) -> Inst { + if preferred_size == 0 { + Inst::Nop0 + } else { + // We can't give a NOP (or any insn) < 2 bytes. + assert!(preferred_size >= 2); + Inst::Nop2 + } + } + + fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> { + match ty { + types::I8 => Ok((&[RegClass::Int], &[types::I8])), + types::I16 => Ok((&[RegClass::Int], &[types::I16])), + types::I32 => Ok((&[RegClass::Int], &[types::I32])), + types::I64 => Ok((&[RegClass::Int], &[types::I64])), + types::F32 => Ok((&[RegClass::Float], &[types::F32])), + types::F64 => Ok((&[RegClass::Float], &[types::F64])), + types::I128 => Ok((&[RegClass::Float], &[types::I128])), + _ if ty.is_vector() && ty.bits() == 128 => Ok((&[RegClass::Float], &[types::I8X16])), + _ => Err(CodegenError::Unsupported(format!( + "Unexpected SSA-value type: {ty}" + ))), + } + } + + fn canonical_type_for_rc(rc: RegClass) -> Type { + match rc { + RegClass::Int => types::I64, + RegClass::Float => types::I8X16, + RegClass::Vector => unreachable!(), + } + } + + fn gen_jump(target: MachLabel) -> Inst { + Inst::Jump { dest: target } + } + + fn worst_case_size() -> CodeOffset { + // The maximum size, in bytes, of any `Inst`'s emitted code. We have at least one case of + // an 8-instruction sequence (saturating int-to-float conversions) with three embedded + // 64-bit f64 constants. + // + // Note that inline jump-tables handle island/pool insertion separately, so we do not need + // to account for them here (otherwise the worst case would be 2^31 * 4, clearly not + // feasible for other reasons). + 44 + } + + fn ref_type_regclass(_: &settings::Flags) -> RegClass { + RegClass::Int + } + + fn gen_dummy_use(reg: Reg) -> Inst { + Inst::DummyUse { reg } + } + + fn function_alignment() -> FunctionAlignment { + FunctionAlignment { + minimum: 4, + preferred: 4, + } + } +} + +//============================================================================= +// Pretty-printing of instructions. + +fn mem_finalize_for_show(mem: &MemArg, state: &EmitState, mi: MemInstType) -> (String, MemArg) { + let (mem_insts, mem) = mem_finalize(mem, state, mi); + let mut mem_str = mem_insts + .into_iter() + .map(|inst| inst.print_with_state(&mut EmitState::default())) + .collect::>() + .join(" ; "); + if !mem_str.is_empty() { + mem_str += " ; "; + } + + (mem_str, mem) +} + +impl Inst { + fn print_with_state(&self, state: &mut EmitState) -> String { + match self { + &Inst::Nop0 => "nop-zero-len".to_string(), + &Inst::Nop2 => "nop".to_string(), + &Inst::AluRRR { alu_op, rd, rn, rm } => { + let (op, have_rr) = match alu_op { + ALUOp::Add32 => ("ark", true), + ALUOp::Add64 => ("agrk", true), + ALUOp::AddLogical32 => ("alrk", true), + ALUOp::AddLogical64 => ("algrk", true), + ALUOp::Sub32 => ("srk", true), + ALUOp::Sub64 => ("sgrk", true), + ALUOp::SubLogical32 => ("slrk", true), + ALUOp::SubLogical64 => ("slgrk", true), + ALUOp::Mul32 => ("msrkc", true), + ALUOp::Mul64 => ("msgrkc", true), + ALUOp::And32 => ("nrk", true), + ALUOp::And64 => ("ngrk", true), + ALUOp::Orr32 => ("ork", true), + ALUOp::Orr64 => ("ogrk", true), + ALUOp::Xor32 => ("xrk", true), + ALUOp::Xor64 => ("xgrk", true), + ALUOp::NotAnd32 => ("nnrk", false), + ALUOp::NotAnd64 => ("nngrk", false), + ALUOp::NotOrr32 => ("nork", false), + ALUOp::NotOrr64 => ("nogrk", false), + ALUOp::NotXor32 => ("nxrk", false), + ALUOp::NotXor64 => ("nxgrk", false), + ALUOp::AndNot32 => ("ncrk", false), + ALUOp::AndNot64 => ("ncgrk", false), + ALUOp::OrrNot32 => ("ocrk", false), + ALUOp::OrrNot64 => ("ocgrk", false), + _ => unreachable!(), + }; + if have_rr && rd.to_reg() == rn { + let inst = Inst::AluRR { + alu_op, + rd, + ri: rd.to_reg(), + rm, + }; + return inst.print_with_state(state); + } + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op} {rd}, {rn}, {rm}") + } + &Inst::AluRRSImm16 { + alu_op, + rd, + rn, + imm, + } => { + if rd.to_reg() == rn { + let inst = Inst::AluRSImm16 { + alu_op, + rd, + ri: rd.to_reg(), + imm, + }; + return inst.print_with_state(state); + } + let op = match alu_op { + ALUOp::Add32 => "ahik", + ALUOp::Add64 => "aghik", + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + format!("{op} {rd}, {rn}, {imm}") + } + &Inst::AluRR { alu_op, rd, ri, rm } => { + let op = match alu_op { + ALUOp::Add32 => "ar", + ALUOp::Add64 => "agr", + ALUOp::Add64Ext32 => "agfr", + ALUOp::AddLogical32 => "alr", + ALUOp::AddLogical64 => "algr", + ALUOp::AddLogical64Ext32 => "algfr", + ALUOp::Sub32 => "sr", + ALUOp::Sub64 => "sgr", + ALUOp::Sub64Ext32 => "sgfr", + ALUOp::SubLogical32 => "slr", + ALUOp::SubLogical64 => "slgr", + ALUOp::SubLogical64Ext32 => "slgfr", + ALUOp::Mul32 => "msr", + ALUOp::Mul64 => "msgr", + ALUOp::Mul64Ext32 => "msgfr", + ALUOp::And32 => "nr", + ALUOp::And64 => "ngr", + ALUOp::Orr32 => "or", + ALUOp::Orr64 => "ogr", + ALUOp::Xor32 => "xr", + ALUOp::Xor64 => "xgr", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + let rm = pretty_print_reg(rm); + format!("{op} {rd}, {rm}") + } + &Inst::AluRX { + alu_op, + rd, + ri, + ref mem, + } => { + let (opcode_rx, opcode_rxy) = match alu_op { + ALUOp::Add32 => (Some("a"), Some("ay")), + ALUOp::Add32Ext16 => (Some("ah"), Some("ahy")), + ALUOp::Add64 => (None, Some("ag")), + ALUOp::Add64Ext16 => (None, Some("agh")), + ALUOp::Add64Ext32 => (None, Some("agf")), + ALUOp::AddLogical32 => (Some("al"), Some("aly")), + ALUOp::AddLogical64 => (None, Some("alg")), + ALUOp::AddLogical64Ext32 => (None, Some("algf")), + ALUOp::Sub32 => (Some("s"), Some("sy")), + ALUOp::Sub32Ext16 => (Some("sh"), Some("shy")), + ALUOp::Sub64 => (None, Some("sg")), + ALUOp::Sub64Ext16 => (None, Some("sgh")), + ALUOp::Sub64Ext32 => (None, Some("sgf")), + ALUOp::SubLogical32 => (Some("sl"), Some("sly")), + ALUOp::SubLogical64 => (None, Some("slg")), + ALUOp::SubLogical64Ext32 => (None, Some("slgf")), + ALUOp::Mul32 => (Some("ms"), Some("msy")), + ALUOp::Mul32Ext16 => (Some("mh"), Some("mhy")), + ALUOp::Mul64 => (None, Some("msg")), + ALUOp::Mul64Ext16 => (None, Some("mgh")), + ALUOp::Mul64Ext32 => (None, Some("msgf")), + ALUOp::And32 => (Some("n"), Some("ny")), + ALUOp::And64 => (None, Some("ng")), + ALUOp::Orr32 => (Some("o"), Some("oy")), + ALUOp::Orr64 => (None, Some("og")), + ALUOp::Xor32 => (Some("x"), Some("xy")), + ALUOp::Xor64 => (None, Some("xg")), + _ => unreachable!(), + }; + + let rd = pretty_print_reg_mod(rd, ri); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: opcode_rx.is_some(), + have_d20: opcode_rxy.is_some(), + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem) + } + &Inst::AluRSImm16 { + alu_op, + rd, + ri, + imm, + } => { + let op = match alu_op { + ALUOp::Add32 => "ahi", + ALUOp::Add64 => "aghi", + ALUOp::Mul32 => "mhi", + ALUOp::Mul64 => "mghi", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{op} {rd}, {imm}") + } + &Inst::AluRSImm32 { + alu_op, + rd, + ri, + imm, + } => { + let op = match alu_op { + ALUOp::Add32 => "afi", + ALUOp::Add64 => "agfi", + ALUOp::Mul32 => "msfi", + ALUOp::Mul64 => "msgfi", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{op} {rd}, {imm}") + } + &Inst::AluRUImm32 { + alu_op, + rd, + ri, + imm, + } => { + let op = match alu_op { + ALUOp::AddLogical32 => "alfi", + ALUOp::AddLogical64 => "algfi", + ALUOp::SubLogical32 => "slfi", + ALUOp::SubLogical64 => "slgfi", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{op} {rd}, {imm}") + } + &Inst::AluRUImm16Shifted { + alu_op, + rd, + ri, + imm, + } => { + let op = match (alu_op, imm.shift) { + (ALUOp::And32, 0) => "nill", + (ALUOp::And32, 1) => "nilh", + (ALUOp::And64, 0) => "nill", + (ALUOp::And64, 1) => "nilh", + (ALUOp::And64, 2) => "nihl", + (ALUOp::And64, 3) => "nihh", + (ALUOp::Orr32, 0) => "oill", + (ALUOp::Orr32, 1) => "oilh", + (ALUOp::Orr64, 0) => "oill", + (ALUOp::Orr64, 1) => "oilh", + (ALUOp::Orr64, 2) => "oihl", + (ALUOp::Orr64, 3) => "oihh", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::AluRUImm32Shifted { + alu_op, + rd, + ri, + imm, + } => { + let op = match (alu_op, imm.shift) { + (ALUOp::And32, 0) => "nilf", + (ALUOp::And64, 0) => "nilf", + (ALUOp::And64, 1) => "nihf", + (ALUOp::Orr32, 0) => "oilf", + (ALUOp::Orr64, 0) => "oilf", + (ALUOp::Orr64, 1) => "oihf", + (ALUOp::Xor32, 0) => "xilf", + (ALUOp::Xor64, 0) => "xilf", + (ALUOp::Xor64, 1) => "xihf", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::SMulWide { rd, rn, rm } => { + let op = "mgrk"; + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + let rd = pretty_print_regpair(rd.to_regpair()); + format!("{op} {rd}, {rn}, {rm}") + } + &Inst::UMulWide { rd, ri, rn } => { + let op = "mlgr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair_mod_lo(rd, ri); + format!("{op} {rd}, {rn}") + } + &Inst::SDivMod32 { rd, ri, rn } => { + let op = "dsgfr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair_mod_lo(rd, ri); + format!("{op} {rd}, {rn}") + } + &Inst::SDivMod64 { rd, ri, rn } => { + let op = "dsgr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair_mod_lo(rd, ri); + format!("{op} {rd}, {rn}") + } + &Inst::UDivMod32 { rd, ri, rn } => { + let op = "dlr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair_mod(rd, ri); + format!("{op} {rd}, {rn}") + } + &Inst::UDivMod64 { rd, ri, rn } => { + let op = "dlgr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair_mod(rd, ri); + format!("{op} {rd}, {rn}") + } + &Inst::Flogr { rd, rn } => { + let op = "flogr"; + let rn = pretty_print_reg(rn); + let rd = pretty_print_regpair(rd.to_regpair()); + format!("{op} {rd}, {rn}") + } + &Inst::ShiftRR { + shift_op, + rd, + rn, + shift_imm, + shift_reg, + } => { + let op = match shift_op { + ShiftOp::RotL32 => "rll", + ShiftOp::RotL64 => "rllg", + ShiftOp::LShL32 => "sllk", + ShiftOp::LShL64 => "sllg", + ShiftOp::LShR32 => "srlk", + ShiftOp::LShR64 => "srlg", + ShiftOp::AShR32 => "srak", + ShiftOp::AShR64 => "srag", + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let shift_reg = if shift_reg != zero_reg() { + format!("({})", pretty_print_reg(shift_reg)) + } else { + "".to_string() + }; + format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}") + } + &Inst::RxSBG { + op, + rd, + ri, + rn, + start_bit, + end_bit, + rotate_amt, + } => { + let op = match op { + RxSBGOp::Insert => "risbgn", + RxSBGOp::And => "rnsbg", + RxSBGOp::Or => "rosbg", + RxSBGOp::Xor => "rxsbg", + }; + let rd = pretty_print_reg_mod(rd, ri); + let rn = pretty_print_reg(rn); + format!( + "{} {}, {}, {}, {}, {}", + op, + rd, + rn, + start_bit, + end_bit, + (rotate_amt as u8) & 63 + ) + } + &Inst::RxSBGTest { + op, + rd, + rn, + start_bit, + end_bit, + rotate_amt, + } => { + let op = match op { + RxSBGOp::And => "rnsbg", + RxSBGOp::Or => "rosbg", + RxSBGOp::Xor => "rxsbg", + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd); + let rn = pretty_print_reg(rn); + format!( + "{} {}, {}, {}, {}, {}", + op, + rd, + rn, + start_bit | 0x80, + end_bit, + (rotate_amt as u8) & 63 + ) + } + &Inst::UnaryRR { op, rd, rn } => { + let (op, extra) = match op { + UnaryOp::Abs32 => ("lpr", ""), + UnaryOp::Abs64 => ("lpgr", ""), + UnaryOp::Abs64Ext32 => ("lpgfr", ""), + UnaryOp::Neg32 => ("lcr", ""), + UnaryOp::Neg64 => ("lcgr", ""), + UnaryOp::Neg64Ext32 => ("lcgfr", ""), + UnaryOp::PopcntByte => ("popcnt", ""), + UnaryOp::PopcntReg => ("popcnt", ", 8"), + UnaryOp::BSwap32 => ("lrvr", ""), + UnaryOp::BSwap64 => ("lrvgr", ""), + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + format!("{op} {rd}, {rn}{extra}") + } + &Inst::CmpRR { op, rn, rm } => { + let op = match op { + CmpOp::CmpS32 => "cr", + CmpOp::CmpS64 => "cgr", + CmpOp::CmpS64Ext32 => "cgfr", + CmpOp::CmpL32 => "clr", + CmpOp::CmpL64 => "clgr", + CmpOp::CmpL64Ext32 => "clgfr", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op} {rn}, {rm}") + } + &Inst::CmpRX { op, rn, ref mem } => { + let (opcode_rx, opcode_rxy, opcode_ril) = match op { + CmpOp::CmpS32 => (Some("c"), Some("cy"), Some("crl")), + CmpOp::CmpS32Ext16 => (Some("ch"), Some("chy"), Some("chrl")), + CmpOp::CmpS64 => (None, Some("cg"), Some("cgrl")), + CmpOp::CmpS64Ext16 => (None, Some("cgh"), Some("cghrl")), + CmpOp::CmpS64Ext32 => (None, Some("cgf"), Some("cgfrl")), + CmpOp::CmpL32 => (Some("cl"), Some("cly"), Some("clrl")), + CmpOp::CmpL32Ext16 => (None, None, Some("clhrl")), + CmpOp::CmpL64 => (None, Some("clg"), Some("clgrl")), + CmpOp::CmpL64Ext16 => (None, None, Some("clghrl")), + CmpOp::CmpL64Ext32 => (None, Some("clgf"), Some("clgfrl")), + }; + + let rn = pretty_print_reg(rn); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: opcode_rx.is_some(), + have_d20: opcode_rxy.is_some(), + have_pcrel: opcode_ril.is_some(), + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + &MemArg::Label { .. } | &MemArg::Symbol { .. } => opcode_ril, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{}{} {}, {}", mem_str, op.unwrap(), rn, mem) + } + &Inst::CmpRSImm16 { op, rn, imm } => { + let op = match op { + CmpOp::CmpS32 => "chi", + CmpOp::CmpS64 => "cghi", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + format!("{op} {rn}, {imm}") + } + &Inst::CmpRSImm32 { op, rn, imm } => { + let op = match op { + CmpOp::CmpS32 => "cfi", + CmpOp::CmpS64 => "cgfi", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + format!("{op} {rn}, {imm}") + } + &Inst::CmpRUImm32 { op, rn, imm } => { + let op = match op { + CmpOp::CmpL32 => "clfi", + CmpOp::CmpL64 => "clgfi", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + format!("{op} {rn}, {imm}") + } + &Inst::CmpTrapRR { + op, rn, rm, cond, .. + } => { + let op = match op { + CmpOp::CmpS32 => "crt", + CmpOp::CmpS64 => "cgrt", + CmpOp::CmpL32 => "clrt", + CmpOp::CmpL64 => "clgrt", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + let cond = cond.pretty_print_default(); + format!("{op}{cond} {rn}, {rm}") + } + &Inst::CmpTrapRSImm16 { + op, rn, imm, cond, .. + } => { + let op = match op { + CmpOp::CmpS32 => "cit", + CmpOp::CmpS64 => "cgit", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + let cond = cond.pretty_print_default(); + format!("{op}{cond} {rn}, {imm}") + } + &Inst::CmpTrapRUImm16 { + op, rn, imm, cond, .. + } => { + let op = match op { + CmpOp::CmpL32 => "clfit", + CmpOp::CmpL64 => "clgit", + _ => unreachable!(), + }; + let rn = pretty_print_reg(rn); + let cond = cond.pretty_print_default(); + format!("{op}{cond} {rn}, {imm}") + } + &Inst::AtomicRmw { + alu_op, + rd, + rn, + ref mem, + } => { + let op = match alu_op { + ALUOp::Add32 => "laa", + ALUOp::Add64 => "laag", + ALUOp::AddLogical32 => "laal", + ALUOp::AddLogical64 => "laalg", + ALUOp::And32 => "lan", + ALUOp::And64 => "lang", + ALUOp::Orr32 => "lao", + ALUOp::Orr64 => "laog", + ALUOp::Xor32 => "lax", + ALUOp::Xor64 => "laxg", + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: false, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{op} {rd}, {rn}, {mem}") + } + &Inst::AtomicCas32 { + rd, + ri, + rn, + ref mem, + } + | &Inst::AtomicCas64 { + rd, + ri, + rn, + ref mem, + } => { + let (opcode_rs, opcode_rsy) = match self { + &Inst::AtomicCas32 { .. } => (Some("cs"), Some("csy")), + &Inst::AtomicCas64 { .. } => (None, Some("csg")), + _ => unreachable!(), + }; + + let rd = pretty_print_reg_mod(rd, ri); + let rn = pretty_print_reg(rn); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: opcode_rs.is_some(), + have_d20: opcode_rsy.is_some(), + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rs, + &MemArg::BXD20 { .. } => opcode_rsy, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{}{} {}, {}, {}", mem_str, op.unwrap(), rd, rn, mem) + } + &Inst::Fence => "bcr 14, 0".to_string(), + &Inst::Load32 { rd, ref mem } + | &Inst::Load32ZExt8 { rd, ref mem } + | &Inst::Load32SExt8 { rd, ref mem } + | &Inst::Load32ZExt16 { rd, ref mem } + | &Inst::Load32SExt16 { rd, ref mem } + | &Inst::Load64 { rd, ref mem } + | &Inst::Load64ZExt8 { rd, ref mem } + | &Inst::Load64SExt8 { rd, ref mem } + | &Inst::Load64ZExt16 { rd, ref mem } + | &Inst::Load64SExt16 { rd, ref mem } + | &Inst::Load64ZExt32 { rd, ref mem } + | &Inst::Load64SExt32 { rd, ref mem } + | &Inst::LoadRev16 { rd, ref mem } + | &Inst::LoadRev32 { rd, ref mem } + | &Inst::LoadRev64 { rd, ref mem } => { + let (opcode_rx, opcode_rxy, opcode_ril) = match self { + &Inst::Load32 { .. } => (Some("l"), Some("ly"), Some("lrl")), + &Inst::Load32ZExt8 { .. } => (None, Some("llc"), None), + &Inst::Load32SExt8 { .. } => (None, Some("lb"), None), + &Inst::Load32ZExt16 { .. } => (None, Some("llh"), Some("llhrl")), + &Inst::Load32SExt16 { .. } => (Some("lh"), Some("lhy"), Some("lhrl")), + &Inst::Load64 { .. } => (None, Some("lg"), Some("lgrl")), + &Inst::Load64ZExt8 { .. } => (None, Some("llgc"), None), + &Inst::Load64SExt8 { .. } => (None, Some("lgb"), None), + &Inst::Load64ZExt16 { .. } => (None, Some("llgh"), Some("llghrl")), + &Inst::Load64SExt16 { .. } => (None, Some("lgh"), Some("lghrl")), + &Inst::Load64ZExt32 { .. } => (None, Some("llgf"), Some("llgfrl")), + &Inst::Load64SExt32 { .. } => (None, Some("lgf"), Some("lgfrl")), + &Inst::LoadRev16 { .. } => (None, Some("lrvh"), None), + &Inst::LoadRev32 { .. } => (None, Some("lrv"), None), + &Inst::LoadRev64 { .. } => (None, Some("lrvg"), None), + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd.to_reg()); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: opcode_rx.is_some(), + have_d20: opcode_rxy.is_some(), + have_pcrel: opcode_ril.is_some(), + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + &MemArg::Label { .. } | &MemArg::Symbol { .. } => opcode_ril, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem) + } + &Inst::Store8 { rd, ref mem } + | &Inst::Store16 { rd, ref mem } + | &Inst::Store32 { rd, ref mem } + | &Inst::Store64 { rd, ref mem } + | &Inst::StoreRev16 { rd, ref mem } + | &Inst::StoreRev32 { rd, ref mem } + | &Inst::StoreRev64 { rd, ref mem } => { + let (opcode_rx, opcode_rxy, opcode_ril) = match self { + &Inst::Store8 { .. } => (Some("stc"), Some("stcy"), None), + &Inst::Store16 { .. } => (Some("sth"), Some("sthy"), Some("sthrl")), + &Inst::Store32 { .. } => (Some("st"), Some("sty"), Some("strl")), + &Inst::Store64 { .. } => (None, Some("stg"), Some("stgrl")), + &Inst::StoreRev16 { .. } => (None, Some("strvh"), None), + &Inst::StoreRev32 { .. } => (None, Some("strv"), None), + &Inst::StoreRev64 { .. } => (None, Some("strvg"), None), + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: opcode_rx.is_some(), + have_d20: opcode_rxy.is_some(), + have_pcrel: opcode_ril.is_some(), + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + &MemArg::Label { .. } | &MemArg::Symbol { .. } => opcode_ril, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem) + } + &Inst::StoreImm8 { imm, ref mem } => { + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => "mvi", + &MemArg::BXD20 { .. } => "mviy", + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{mem_str}{op} {mem}, {imm}") + } + &Inst::StoreImm16 { imm, ref mem } + | &Inst::StoreImm32SExt16 { imm, ref mem } + | &Inst::StoreImm64SExt16 { imm, ref mem } => { + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: false, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let op = match self { + &Inst::StoreImm16 { .. } => "mvhhi", + &Inst::StoreImm32SExt16 { .. } => "mvhi", + &Inst::StoreImm64SExt16 { .. } => "mvghi", + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{mem_str}{op} {mem}, {imm}") + } + &Inst::LoadMultiple64 { rt, rt2, ref mem } => { + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: false, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let rt = pretty_print_reg(rt.to_reg()); + let rt2 = pretty_print_reg(rt2.to_reg()); + let mem = mem.pretty_print_default(); + format!("{mem_str}lmg {rt}, {rt2}, {mem}") + } + &Inst::StoreMultiple64 { rt, rt2, ref mem } => { + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: false, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: false, + }, + ); + let rt = pretty_print_reg(rt); + let rt2 = pretty_print_reg(rt2); + let mem = mem.pretty_print_default(); + format!("{mem_str}stmg {rt}, {rt2}, {mem}") + } + &Inst::Mov64 { rd, rm } => { + let rd = pretty_print_reg(rd.to_reg()); + let rm = pretty_print_reg(rm); + format!("lgr {rd}, {rm}") + } + &Inst::MovPReg { rd, rm } => { + let rd = pretty_print_reg(rd.to_reg()); + let rm = show_reg(rm.into()); + format!("lgr {rd}, {rm}") + } + &Inst::Mov32 { rd, rm } => { + let rd = pretty_print_reg(rd.to_reg()); + let rm = pretty_print_reg(rm); + format!("lr {rd}, {rm}") + } + &Inst::Mov32Imm { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("iilf {rd}, {imm}") + } + &Inst::Mov32SImm16 { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("lhi {rd}, {imm}") + } + &Inst::Mov64SImm16 { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("lghi {rd}, {imm}") + } + &Inst::Mov64SImm32 { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("lgfi {rd}, {imm}") + } + &Inst::Mov64UImm16Shifted { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + let op = match imm.shift { + 0 => "llill", + 1 => "llilh", + 2 => "llihl", + 3 => "llihh", + _ => unreachable!(), + }; + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::Mov64UImm32Shifted { rd, ref imm } => { + let rd = pretty_print_reg(rd.to_reg()); + let op = match imm.shift { + 0 => "llilf", + 1 => "llihf", + _ => unreachable!(), + }; + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::Insert64UImm16Shifted { rd, ri, ref imm } => { + let rd = pretty_print_reg_mod(rd, ri); + let op = match imm.shift { + 0 => "iill", + 1 => "iilh", + 2 => "iihl", + 3 => "iihh", + _ => unreachable!(), + }; + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::Insert64UImm32Shifted { rd, ri, ref imm } => { + let rd = pretty_print_reg_mod(rd, ri); + let op = match imm.shift { + 0 => "iilf", + 1 => "iihf", + _ => unreachable!(), + }; + format!("{} {}, {}", op, rd, imm.bits) + } + &Inst::LoadAR { rd, ar } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("ear {rd}, %a{ar}") + } + &Inst::InsertAR { rd, ri, ar } => { + let rd = pretty_print_reg_mod(rd, ri); + format!("ear {rd}, %a{ar}") + } + &Inst::CMov32 { rd, cond, ri, rm } => { + let rd = pretty_print_reg_mod(rd, ri); + let rm = pretty_print_reg(rm); + let cond = cond.pretty_print_default(); + format!("locr{cond} {rd}, {rm}") + } + &Inst::CMov64 { rd, cond, ri, rm } => { + let rd = pretty_print_reg_mod(rd, ri); + let rm = pretty_print_reg(rm); + let cond = cond.pretty_print_default(); + format!("locgr{cond} {rd}, {rm}") + } + &Inst::CMov32SImm16 { + rd, + cond, + ri, + ref imm, + } => { + let rd = pretty_print_reg_mod(rd, ri); + let cond = cond.pretty_print_default(); + format!("lochi{cond} {rd}, {imm}") + } + &Inst::CMov64SImm16 { + rd, + cond, + ri, + ref imm, + } => { + let rd = pretty_print_reg_mod(rd, ri); + let cond = cond.pretty_print_default(); + format!("locghi{cond} {rd}, {imm}") + } + &Inst::FpuMove32 { rd, rn } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + if rd_fpr.is_some() && rn_fpr.is_some() { + format!("ler {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap()) + } else { + format!("vlr {rd}, {rn}") + } + } + &Inst::FpuMove64 { rd, rn } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + if rd_fpr.is_some() && rn_fpr.is_some() { + format!("ldr {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap()) + } else { + format!("vlr {rd}, {rn}") + } + } + &Inst::FpuCMov32 { rd, cond, rm, .. } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rm, rm_fpr) = pretty_print_fpr(rm); + if rd_fpr.is_some() && rm_fpr.is_some() { + let cond = cond.invert().pretty_print_default(); + format!("j{} 6 ; ler {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap()) + } else { + let cond = cond.invert().pretty_print_default(); + format!("j{cond} 10 ; vlr {rd}, {rm}") + } + } + &Inst::FpuCMov64 { rd, cond, rm, .. } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rm, rm_fpr) = pretty_print_fpr(rm); + if rd_fpr.is_some() && rm_fpr.is_some() { + let cond = cond.invert().pretty_print_default(); + format!("j{} 6 ; ldr {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap()) + } else { + let cond = cond.invert().pretty_print_default(); + format!("j{cond} 10 ; vlr {rd}, {rm}") + } + } + &Inst::FpuRR { fpu_op, rd, rn } => { + let (op, op_fpr) = match fpu_op { + FPUOp1::Abs32 => ("wflpsb", Some("lpebr")), + FPUOp1::Abs64 => ("wflpdb", Some("lpdbr")), + FPUOp1::Abs32x4 => ("vflpsb", None), + FPUOp1::Abs64x2 => ("vflpdb", None), + FPUOp1::Neg32 => ("wflcsb", Some("lcebr")), + FPUOp1::Neg64 => ("wflcdb", Some("lcdbr")), + FPUOp1::Neg32x4 => ("vflcsb", None), + FPUOp1::Neg64x2 => ("vflcdb", None), + FPUOp1::NegAbs32 => ("wflnsb", Some("lnebr")), + FPUOp1::NegAbs64 => ("wflndb", Some("lndbr")), + FPUOp1::NegAbs32x4 => ("vflnsb", None), + FPUOp1::NegAbs64x2 => ("vflndb", None), + FPUOp1::Sqrt32 => ("wfsqsb", Some("sqebr")), + FPUOp1::Sqrt64 => ("wfsqdb", Some("sqdbr")), + FPUOp1::Sqrt32x4 => ("vfsqsb", None), + FPUOp1::Sqrt64x2 => ("vfsqdb", None), + FPUOp1::Cvt32To64 => ("wldeb", Some("ldebr")), + FPUOp1::Cvt32x4To64x2 => ("vldeb", None), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + if op_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() { + format!( + "{} {}, {}", + op_fpr.unwrap(), + rd_fpr.unwrap(), + rn_fpr.unwrap() + ) + } else if op.starts_with('w') { + format!("{} {}, {}", op, rd_fpr.unwrap_or(rd), rn_fpr.unwrap_or(rn)) + } else { + format!("{op} {rd}, {rn}") + } + } + &Inst::FpuRRR { fpu_op, rd, rn, rm } => { + let (op, opt_m6, op_fpr) = match fpu_op { + FPUOp2::Add32 => ("wfasb", "", Some("aebr")), + FPUOp2::Add64 => ("wfadb", "", Some("adbr")), + FPUOp2::Add32x4 => ("vfasb", "", None), + FPUOp2::Add64x2 => ("vfadb", "", None), + FPUOp2::Sub32 => ("wfssb", "", Some("sebr")), + FPUOp2::Sub64 => ("wfsdb", "", Some("sdbr")), + FPUOp2::Sub32x4 => ("vfssb", "", None), + FPUOp2::Sub64x2 => ("vfsdb", "", None), + FPUOp2::Mul32 => ("wfmsb", "", Some("meebr")), + FPUOp2::Mul64 => ("wfmdb", "", Some("mdbr")), + FPUOp2::Mul32x4 => ("vfmsb", "", None), + FPUOp2::Mul64x2 => ("vfmdb", "", None), + FPUOp2::Div32 => ("wfdsb", "", Some("debr")), + FPUOp2::Div64 => ("wfddb", "", Some("ddbr")), + FPUOp2::Div32x4 => ("vfdsb", "", None), + FPUOp2::Div64x2 => ("vfddb", "", None), + FPUOp2::Max32 => ("wfmaxsb", ", 1", None), + FPUOp2::Max64 => ("wfmaxdb", ", 1", None), + FPUOp2::Max32x4 => ("vfmaxsb", ", 1", None), + FPUOp2::Max64x2 => ("vfmaxdb", ", 1", None), + FPUOp2::Min32 => ("wfminsb", ", 1", None), + FPUOp2::Min64 => ("wfmindb", ", 1", None), + FPUOp2::Min32x4 => ("vfminsb", ", 1", None), + FPUOp2::Min64x2 => ("vfmindb", ", 1", None), + FPUOp2::MaxPseudo32 => ("wfmaxsb", ", 3", None), + FPUOp2::MaxPseudo64 => ("wfmaxdb", ", 3", None), + FPUOp2::MaxPseudo32x4 => ("vfmaxsb", ", 3", None), + FPUOp2::MaxPseudo64x2 => ("vfmaxdb", ", 3", None), + FPUOp2::MinPseudo32 => ("wfminsb", ", 3", None), + FPUOp2::MinPseudo64 => ("wfmindb", ", 3", None), + FPUOp2::MinPseudo32x4 => ("vfminsb", ", 3", None), + FPUOp2::MinPseudo64x2 => ("vfmindb", ", 3", None), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + let (rm, rm_fpr) = pretty_print_fpr(rm); + if op_fpr.is_some() && rd == rn && rd_fpr.is_some() && rm_fpr.is_some() { + format!( + "{} {}, {}", + op_fpr.unwrap(), + rd_fpr.unwrap(), + rm_fpr.unwrap() + ) + } else if op.starts_with('w') { + format!( + "{} {}, {}, {}{}", + op, + rd_fpr.unwrap_or(rd), + rn_fpr.unwrap_or(rn), + rm_fpr.unwrap_or(rm), + opt_m6 + ) + } else { + format!("{op} {rd}, {rn}, {rm}{opt_m6}") + } + } + &Inst::FpuRRRR { + fpu_op, + rd, + rn, + rm, + ra, + } => { + let (op, op_fpr) = match fpu_op { + FPUOp3::MAdd32 => ("wfmasb", Some("maebr")), + FPUOp3::MAdd64 => ("wfmadb", Some("madbr")), + FPUOp3::MAdd32x4 => ("vfmasb", None), + FPUOp3::MAdd64x2 => ("vfmadb", None), + FPUOp3::MSub32 => ("wfmssb", Some("msebr")), + FPUOp3::MSub64 => ("wfmsdb", Some("msdbr")), + FPUOp3::MSub32x4 => ("vfmssb", None), + FPUOp3::MSub64x2 => ("vfmsdb", None), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + let (rm, rm_fpr) = pretty_print_fpr(rm); + let (ra, ra_fpr) = pretty_print_fpr(ra); + if op_fpr.is_some() + && rd == ra + && rd_fpr.is_some() + && rn_fpr.is_some() + && rm_fpr.is_some() + { + format!( + "{} {}, {}, {}", + op_fpr.unwrap(), + rd_fpr.unwrap(), + rn_fpr.unwrap(), + rm_fpr.unwrap() + ) + } else if op.starts_with('w') { + format!( + "{} {}, {}, {}, {}", + op, + rd_fpr.unwrap_or(rd), + rn_fpr.unwrap_or(rn), + rm_fpr.unwrap_or(rm), + ra_fpr.unwrap_or(ra) + ) + } else { + format!("{op} {rd}, {rn}, {rm}, {ra}") + } + } + &Inst::FpuCmp32 { rn, rm } => { + let (rn, rn_fpr) = pretty_print_fpr(rn); + let (rm, rm_fpr) = pretty_print_fpr(rm); + if rn_fpr.is_some() && rm_fpr.is_some() { + format!("cebr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap()) + } else { + format!("wfcsb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm)) + } + } + &Inst::FpuCmp64 { rn, rm } => { + let (rn, rn_fpr) = pretty_print_fpr(rn); + let (rm, rm_fpr) = pretty_print_fpr(rm); + if rn_fpr.is_some() && rm_fpr.is_some() { + format!("cdbr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap()) + } else { + format!("wfcdb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm)) + } + } + &Inst::LoadFpuConst32 { rd, const_data } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + if rd_fpr.is_some() { + format!( + "bras {}, 8 ; data.f32 {} ; le {}, 0({})", + tmp, + f32::from_bits(const_data), + rd_fpr.unwrap(), + tmp + ) + } else { + format!( + "bras {}, 8 ; data.f32 {} ; vlef {}, 0({}), 0", + tmp, + f32::from_bits(const_data), + rd, + tmp + ) + } + } + &Inst::LoadFpuConst64 { rd, const_data } => { + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + if rd_fpr.is_some() { + format!( + "bras {}, 12 ; data.f64 {} ; ld {}, 0({})", + tmp, + f64::from_bits(const_data), + rd_fpr.unwrap(), + tmp + ) + } else { + format!( + "bras {}, 12 ; data.f64 {} ; vleg {}, 0({}), 0", + tmp, + f64::from_bits(const_data), + rd, + tmp + ) + } + } + &Inst::FpuRound { op, mode, rd, rn } => { + let mode = match mode { + FpuRoundMode::Current => 0, + FpuRoundMode::ToNearest => 1, + FpuRoundMode::ShorterPrecision => 3, + FpuRoundMode::ToNearestTiesToEven => 4, + FpuRoundMode::ToZero => 5, + FpuRoundMode::ToPosInfinity => 6, + FpuRoundMode::ToNegInfinity => 7, + }; + let (opcode, opcode_fpr) = match op { + FpuRoundOp::Cvt64To32 => ("wledb", Some("ledbra")), + FpuRoundOp::Cvt64x2To32x4 => ("vledb", None), + FpuRoundOp::Round32 => ("wfisb", Some("fiebr")), + FpuRoundOp::Round64 => ("wfidb", Some("fidbr")), + FpuRoundOp::Round32x4 => ("vfisb", None), + FpuRoundOp::Round64x2 => ("vfidb", None), + FpuRoundOp::ToSInt32 => ("wcfeb", None), + FpuRoundOp::ToSInt64 => ("wcgdb", None), + FpuRoundOp::ToUInt32 => ("wclfeb", None), + FpuRoundOp::ToUInt64 => ("wclgdb", None), + FpuRoundOp::ToSInt32x4 => ("vcfeb", None), + FpuRoundOp::ToSInt64x2 => ("vcgdb", None), + FpuRoundOp::ToUInt32x4 => ("vclfeb", None), + FpuRoundOp::ToUInt64x2 => ("vclgdb", None), + FpuRoundOp::FromSInt32 => ("wcefb", None), + FpuRoundOp::FromSInt64 => ("wcdgb", None), + FpuRoundOp::FromUInt32 => ("wcelfb", None), + FpuRoundOp::FromUInt64 => ("wcdlgb", None), + FpuRoundOp::FromSInt32x4 => ("vcefb", None), + FpuRoundOp::FromSInt64x2 => ("vcdgb", None), + FpuRoundOp::FromUInt32x4 => ("vcelfb", None), + FpuRoundOp::FromUInt64x2 => ("vcdlgb", None), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + if opcode_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() { + format!( + "{} {}, {}, {}{}", + opcode_fpr.unwrap(), + rd_fpr.unwrap(), + mode, + rn_fpr.unwrap(), + if opcode_fpr.unwrap().ends_with('a') { + ", 0" + } else { + "" + } + ) + } else if opcode.starts_with('w') { + format!( + "{} {}, {}, 0, {}", + opcode, + rd_fpr.unwrap_or(rd), + rn_fpr.unwrap_or(rn), + mode + ) + } else { + format!("{opcode} {rd}, {rn}, 0, {mode}") + } + } + &Inst::VecRRR { op, rd, rn, rm } => { + let op = match op { + VecBinaryOp::Add8x16 => "vab", + VecBinaryOp::Add16x8 => "vah", + VecBinaryOp::Add32x4 => "vaf", + VecBinaryOp::Add64x2 => "vag", + VecBinaryOp::Add128 => "vaq", + VecBinaryOp::Sub8x16 => "vsb", + VecBinaryOp::Sub16x8 => "vsh", + VecBinaryOp::Sub32x4 => "vsf", + VecBinaryOp::Sub64x2 => "vsg", + VecBinaryOp::Sub128 => "vsq", + VecBinaryOp::Mul8x16 => "vmlb", + VecBinaryOp::Mul16x8 => "vmlhw", + VecBinaryOp::Mul32x4 => "vmlf", + VecBinaryOp::UMulHi8x16 => "vmlhb", + VecBinaryOp::UMulHi16x8 => "vmlhh", + VecBinaryOp::UMulHi32x4 => "vmlhf", + VecBinaryOp::SMulHi8x16 => "vmhb", + VecBinaryOp::SMulHi16x8 => "vmhh", + VecBinaryOp::SMulHi32x4 => "vmhf", + VecBinaryOp::UMulEven8x16 => "vmleb", + VecBinaryOp::UMulEven16x8 => "vmleh", + VecBinaryOp::UMulEven32x4 => "vmlef", + VecBinaryOp::SMulEven8x16 => "vmeb", + VecBinaryOp::SMulEven16x8 => "vmeh", + VecBinaryOp::SMulEven32x4 => "vmef", + VecBinaryOp::UMulOdd8x16 => "vmlob", + VecBinaryOp::UMulOdd16x8 => "vmloh", + VecBinaryOp::UMulOdd32x4 => "vmlof", + VecBinaryOp::SMulOdd8x16 => "vmob", + VecBinaryOp::SMulOdd16x8 => "vmoh", + VecBinaryOp::SMulOdd32x4 => "vmof", + VecBinaryOp::UMax8x16 => "vmxlb", + VecBinaryOp::UMax16x8 => "vmxlh", + VecBinaryOp::UMax32x4 => "vmxlf", + VecBinaryOp::UMax64x2 => "vmxlg", + VecBinaryOp::SMax8x16 => "vmxb", + VecBinaryOp::SMax16x8 => "vmxh", + VecBinaryOp::SMax32x4 => "vmxf", + VecBinaryOp::SMax64x2 => "vmxg", + VecBinaryOp::UMin8x16 => "vmnlb", + VecBinaryOp::UMin16x8 => "vmnlh", + VecBinaryOp::UMin32x4 => "vmnlf", + VecBinaryOp::UMin64x2 => "vmnlg", + VecBinaryOp::SMin8x16 => "vmnb", + VecBinaryOp::SMin16x8 => "vmnh", + VecBinaryOp::SMin32x4 => "vmnf", + VecBinaryOp::SMin64x2 => "vmng", + VecBinaryOp::UAvg8x16 => "vavglb", + VecBinaryOp::UAvg16x8 => "vavglh", + VecBinaryOp::UAvg32x4 => "vavglf", + VecBinaryOp::UAvg64x2 => "vavglg", + VecBinaryOp::SAvg8x16 => "vavgb", + VecBinaryOp::SAvg16x8 => "vavgh", + VecBinaryOp::SAvg32x4 => "vavgf", + VecBinaryOp::SAvg64x2 => "vavgg", + VecBinaryOp::And128 => "vn", + VecBinaryOp::Orr128 => "vo", + VecBinaryOp::Xor128 => "vx", + VecBinaryOp::NotAnd128 => "vnn", + VecBinaryOp::NotOrr128 => "vno", + VecBinaryOp::NotXor128 => "vnx", + VecBinaryOp::AndNot128 => "vnc", + VecBinaryOp::OrrNot128 => "voc", + VecBinaryOp::BitPermute128 => "vbperm", + VecBinaryOp::LShLByByte128 => "vslb", + VecBinaryOp::LShRByByte128 => "vsrlb", + VecBinaryOp::AShRByByte128 => "vsrab", + VecBinaryOp::LShLByBit128 => "vsl", + VecBinaryOp::LShRByBit128 => "vsrl", + VecBinaryOp::AShRByBit128 => "vsra", + VecBinaryOp::Pack16x8 => "vpkh", + VecBinaryOp::Pack32x4 => "vpkf", + VecBinaryOp::Pack64x2 => "vpkg", + VecBinaryOp::PackUSat16x8 => "vpklsh", + VecBinaryOp::PackUSat32x4 => "vpklsf", + VecBinaryOp::PackUSat64x2 => "vpklsg", + VecBinaryOp::PackSSat16x8 => "vpksh", + VecBinaryOp::PackSSat32x4 => "vpksf", + VecBinaryOp::PackSSat64x2 => "vpksg", + VecBinaryOp::MergeLow8x16 => "vmrlb", + VecBinaryOp::MergeLow16x8 => "vmrlh", + VecBinaryOp::MergeLow32x4 => "vmrlf", + VecBinaryOp::MergeLow64x2 => "vmrlg", + VecBinaryOp::MergeHigh8x16 => "vmrhb", + VecBinaryOp::MergeHigh16x8 => "vmrhh", + VecBinaryOp::MergeHigh32x4 => "vmrhf", + VecBinaryOp::MergeHigh64x2 => "vmrhg", + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op} {rd}, {rn}, {rm}") + } + &Inst::VecRR { op, rd, rn } => { + let op = match op { + VecUnaryOp::Abs8x16 => "vlpb", + VecUnaryOp::Abs16x8 => "vlph", + VecUnaryOp::Abs32x4 => "vlpf", + VecUnaryOp::Abs64x2 => "vlpg", + VecUnaryOp::Neg8x16 => "vlcb", + VecUnaryOp::Neg16x8 => "vlch", + VecUnaryOp::Neg32x4 => "vlcf", + VecUnaryOp::Neg64x2 => "vlcg", + VecUnaryOp::Popcnt8x16 => "vpopctb", + VecUnaryOp::Popcnt16x8 => "vpopcth", + VecUnaryOp::Popcnt32x4 => "vpopctf", + VecUnaryOp::Popcnt64x2 => "vpopctg", + VecUnaryOp::Clz8x16 => "vclzb", + VecUnaryOp::Clz16x8 => "vclzh", + VecUnaryOp::Clz32x4 => "vclzf", + VecUnaryOp::Clz64x2 => "vclzg", + VecUnaryOp::Ctz8x16 => "vctzb", + VecUnaryOp::Ctz16x8 => "vctzh", + VecUnaryOp::Ctz32x4 => "vctzf", + VecUnaryOp::Ctz64x2 => "vctzg", + VecUnaryOp::UnpackULow8x16 => "vupllb", + VecUnaryOp::UnpackULow16x8 => "vupllh", + VecUnaryOp::UnpackULow32x4 => "vupllf", + VecUnaryOp::UnpackUHigh8x16 => "vuplhb", + VecUnaryOp::UnpackUHigh16x8 => "vuplhh", + VecUnaryOp::UnpackUHigh32x4 => "vuplhf", + VecUnaryOp::UnpackSLow8x16 => "vuplb", + VecUnaryOp::UnpackSLow16x8 => "vuplh", + VecUnaryOp::UnpackSLow32x4 => "vuplf", + VecUnaryOp::UnpackSHigh8x16 => "vuphb", + VecUnaryOp::UnpackSHigh16x8 => "vuphh", + VecUnaryOp::UnpackSHigh32x4 => "vuphf", + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + format!("{op} {rd}, {rn}") + } + &Inst::VecShiftRR { + shift_op, + rd, + rn, + shift_imm, + shift_reg, + } => { + let op = match shift_op { + VecShiftOp::RotL8x16 => "verllb", + VecShiftOp::RotL16x8 => "verllh", + VecShiftOp::RotL32x4 => "verllf", + VecShiftOp::RotL64x2 => "verllg", + VecShiftOp::LShL8x16 => "veslb", + VecShiftOp::LShL16x8 => "veslh", + VecShiftOp::LShL32x4 => "veslf", + VecShiftOp::LShL64x2 => "veslg", + VecShiftOp::LShR8x16 => "vesrlb", + VecShiftOp::LShR16x8 => "vesrlh", + VecShiftOp::LShR32x4 => "vesrlf", + VecShiftOp::LShR64x2 => "vesrlg", + VecShiftOp::AShR8x16 => "vesrab", + VecShiftOp::AShR16x8 => "vesrah", + VecShiftOp::AShR32x4 => "vesraf", + VecShiftOp::AShR64x2 => "vesrag", + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let shift_reg = if shift_reg != zero_reg() { + format!("({})", pretty_print_reg(shift_reg)) + } else { + "".to_string() + }; + format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}") + } + &Inst::VecSelect { rd, rn, rm, ra } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + let ra = pretty_print_reg(ra); + format!("vsel {rd}, {rn}, {rm}, {ra}") + } + &Inst::VecPermute { rd, rn, rm, ra } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + let ra = pretty_print_reg(ra); + format!("vperm {rd}, {rn}, {rm}, {ra}") + } + &Inst::VecPermuteDWImm { + rd, + rn, + rm, + idx1, + idx2, + } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + let m4 = (idx1 & 1) * 4 + (idx2 & 1); + format!("vpdi {rd}, {rn}, {rm}, {m4}") + } + &Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => { + let op = match op { + VecIntCmpOp::CmpEq8x16 => "vceqb", + VecIntCmpOp::CmpEq16x8 => "vceqh", + VecIntCmpOp::CmpEq32x4 => "vceqf", + VecIntCmpOp::CmpEq64x2 => "vceqg", + VecIntCmpOp::SCmpHi8x16 => "vchb", + VecIntCmpOp::SCmpHi16x8 => "vchh", + VecIntCmpOp::SCmpHi32x4 => "vchf", + VecIntCmpOp::SCmpHi64x2 => "vchg", + VecIntCmpOp::UCmpHi8x16 => "vchlb", + VecIntCmpOp::UCmpHi16x8 => "vchlh", + VecIntCmpOp::UCmpHi32x4 => "vchlf", + VecIntCmpOp::UCmpHi64x2 => "vchlg", + }; + let s = match self { + &Inst::VecIntCmp { .. } => "", + &Inst::VecIntCmpS { .. } => "s", + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op}{s} {rd}, {rn}, {rm}") + } + &Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => { + let op = match op { + VecFloatCmpOp::CmpEq32x4 => "vfcesb", + VecFloatCmpOp::CmpEq64x2 => "vfcedb", + VecFloatCmpOp::CmpHi32x4 => "vfchsb", + VecFloatCmpOp::CmpHi64x2 => "vfchdb", + VecFloatCmpOp::CmpHiEq32x4 => "vfchesb", + VecFloatCmpOp::CmpHiEq64x2 => "vfchedb", + }; + let s = match self { + &Inst::VecFloatCmp { .. } => "", + &Inst::VecFloatCmpS { .. } => "s", + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op}{s} {rd}, {rn}, {rm}") + } + &Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => { + let op = match self { + &Inst::VecInt128SCmpHi { .. } => "vecg", + &Inst::VecInt128UCmpHi { .. } => "veclg", + _ => unreachable!(), + }; + let tmp = pretty_print_reg(tmp.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("{op} {rm}, {rn} ; jne 10 ; vchlgs {tmp}, {rn}, {rm}") + } + &Inst::VecLoad { rd, ref mem } + | &Inst::VecLoadRev { rd, ref mem } + | &Inst::VecLoadByte16Rev { rd, ref mem } + | &Inst::VecLoadByte32Rev { rd, ref mem } + | &Inst::VecLoadByte64Rev { rd, ref mem } + | &Inst::VecLoadElt16Rev { rd, ref mem } + | &Inst::VecLoadElt32Rev { rd, ref mem } + | &Inst::VecLoadElt64Rev { rd, ref mem } => { + let opcode = match self { + &Inst::VecLoad { .. } => "vl", + &Inst::VecLoadRev { .. } => "vlbrq", + &Inst::VecLoadByte16Rev { .. } => "vlbrh", + &Inst::VecLoadByte32Rev { .. } => "vlbrf", + &Inst::VecLoadByte64Rev { .. } => "vlbrg", + &Inst::VecLoadElt16Rev { .. } => "vlerh", + &Inst::VecLoadElt32Rev { .. } => "vlerf", + &Inst::VecLoadElt64Rev { .. } => "vlerg", + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd.to_reg()); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode} {rd}, {mem}") + } + &Inst::VecStore { rd, ref mem } + | &Inst::VecStoreRev { rd, ref mem } + | &Inst::VecStoreByte16Rev { rd, ref mem } + | &Inst::VecStoreByte32Rev { rd, ref mem } + | &Inst::VecStoreByte64Rev { rd, ref mem } + | &Inst::VecStoreElt16Rev { rd, ref mem } + | &Inst::VecStoreElt32Rev { rd, ref mem } + | &Inst::VecStoreElt64Rev { rd, ref mem } => { + let opcode = match self { + &Inst::VecStore { .. } => "vst", + &Inst::VecStoreRev { .. } => "vstbrq", + &Inst::VecStoreByte16Rev { .. } => "vstbrh", + &Inst::VecStoreByte32Rev { .. } => "vstbrf", + &Inst::VecStoreByte64Rev { .. } => "vstbrg", + &Inst::VecStoreElt16Rev { .. } => "vsterh", + &Inst::VecStoreElt32Rev { .. } => "vsterf", + &Inst::VecStoreElt64Rev { .. } => "vsterg", + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode} {rd}, {mem}") + } + &Inst::VecLoadReplicate { size, rd, ref mem } + | &Inst::VecLoadReplicateRev { size, rd, ref mem } => { + let opcode = match (self, size) { + (&Inst::VecLoadReplicate { .. }, 8) => "vlrepb", + (&Inst::VecLoadReplicate { .. }, 16) => "vlreph", + (&Inst::VecLoadReplicate { .. }, 32) => "vlrepf", + (&Inst::VecLoadReplicate { .. }, 64) => "vlrepg", + (&Inst::VecLoadReplicateRev { .. }, 16) => "vlbrreph", + (&Inst::VecLoadReplicateRev { .. }, 32) => "vlbrrepf", + (&Inst::VecLoadReplicateRev { .. }, 64) => "vlbrrepg", + _ => unreachable!(), + }; + + let rd = pretty_print_reg(rd.to_reg()); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode} {rd}, {mem}") + } + &Inst::VecMov { rd, rn } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + format!("vlr {rd}, {rn}") + } + &Inst::VecCMov { rd, cond, ri, rm } => { + let rd = pretty_print_reg_mod(rd, ri); + let rm = pretty_print_reg(rm); + let cond = cond.invert().pretty_print_default(); + format!("j{cond} 10 ; vlr {rd}, {rm}") + } + &Inst::MovToVec128 { rd, rn, rm } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let rm = pretty_print_reg(rm); + format!("vlvgp {rd}, {rn}, {rm}") + } + &Inst::VecLoadConst { rd, const_data } => { + let rd = pretty_print_reg(rd.to_reg()); + let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + format!("bras {tmp}, 20 ; data.u128 0x{const_data:032x} ; vl {rd}, 0({tmp})") + } + &Inst::VecLoadConstReplicate { + size, + rd, + const_data, + } => { + let rd = pretty_print_reg(rd.to_reg()); + let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + let (opcode, data) = match size { + 32 => ("vlrepf", format!("0x{:08x}", const_data as u32)), + 64 => ("vlrepg", format!("0x{const_data:016x}")), + _ => unreachable!(), + }; + format!( + "bras {}, {} ; data.u{} {} ; {} {}, 0({})", + tmp, + 4 + size / 8, + size, + data, + opcode, + rd, + tmp + ) + } + &Inst::VecImmByteMask { rd, mask } => { + let rd = pretty_print_reg(rd.to_reg()); + format!("vgbm {rd}, {mask}") + } + &Inst::VecImmBitMask { + size, + rd, + start_bit, + end_bit, + } => { + let rd = pretty_print_reg(rd.to_reg()); + let op = match size { + 8 => "vgmb", + 16 => "vgmh", + 32 => "vgmf", + 64 => "vgmg", + _ => unreachable!(), + }; + format!("{op} {rd}, {start_bit}, {end_bit}") + } + &Inst::VecImmReplicate { size, rd, imm } => { + let rd = pretty_print_reg(rd.to_reg()); + let op = match size { + 8 => "vrepib", + 16 => "vrepih", + 32 => "vrepif", + 64 => "vrepig", + _ => unreachable!(), + }; + format!("{op} {rd}, {imm}") + } + &Inst::VecLoadLane { + size, + rd, + ref mem, + lane_imm, + .. + } + | &Inst::VecLoadLaneRev { + size, + rd, + ref mem, + lane_imm, + .. + } => { + let opcode_vrx = match (self, size) { + (&Inst::VecLoadLane { .. }, 8) => "vleb", + (&Inst::VecLoadLane { .. }, 16) => "vleh", + (&Inst::VecLoadLane { .. }, 32) => "vlef", + (&Inst::VecLoadLane { .. }, 64) => "vleg", + (&Inst::VecLoadLaneRev { .. }, 16) => "vlebrh", + (&Inst::VecLoadLaneRev { .. }, 32) => "vlebrf", + (&Inst::VecLoadLaneRev { .. }, 64) => "vlebrg", + _ => unreachable!(), + }; + + let (rd, _) = pretty_print_fpr(rd.to_reg()); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}") + } + &Inst::VecLoadLaneUndef { + size, + rd, + ref mem, + lane_imm, + } + | &Inst::VecLoadLaneRevUndef { + size, + rd, + ref mem, + lane_imm, + } => { + let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) { + (&Inst::VecLoadLaneUndef { .. }, 8) => ("vleb", None, None), + (&Inst::VecLoadLaneUndef { .. }, 16) => ("vleh", None, None), + (&Inst::VecLoadLaneUndef { .. }, 32) => ("vlef", Some("le"), Some("ley")), + (&Inst::VecLoadLaneUndef { .. }, 64) => ("vleg", Some("ld"), Some("ldy")), + (&Inst::VecLoadLaneRevUndef { .. }, 16) => ("vlebrh", None, None), + (&Inst::VecLoadLaneRevUndef { .. }, 32) => ("vlebrf", None, None), + (&Inst::VecLoadLaneRevUndef { .. }, 64) => ("vlebrg", None, None), + _ => unreachable!(), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let mem = mem.clone(); + if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() { + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem) + } else { + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}") + } + } + &Inst::VecStoreLane { + size, + rd, + ref mem, + lane_imm, + } + | &Inst::VecStoreLaneRev { + size, + rd, + ref mem, + lane_imm, + } => { + let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) { + (&Inst::VecStoreLane { .. }, 8) => ("vsteb", None, None), + (&Inst::VecStoreLane { .. }, 16) => ("vsteh", None, None), + (&Inst::VecStoreLane { .. }, 32) => ("vstef", Some("ste"), Some("stey")), + (&Inst::VecStoreLane { .. }, 64) => ("vsteg", Some("std"), Some("stdy")), + (&Inst::VecStoreLaneRev { .. }, 16) => ("vstebrh", None, None), + (&Inst::VecStoreLaneRev { .. }, 32) => ("vstebrf", None, None), + (&Inst::VecStoreLaneRev { .. }, 64) => ("vstebrg", None, None), + _ => unreachable!(), + }; + + let (rd, rd_fpr) = pretty_print_fpr(rd); + let mem = mem.clone(); + if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() { + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: true, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => opcode_rx, + &MemArg::BXD20 { .. } => opcode_rxy, + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem) + } else { + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: false, + have_pcrel: false, + have_unaligned_pcrel: false, + have_index: true, + }, + ); + let mem = mem.pretty_print_default(); + format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}",) + } + } + &Inst::VecInsertLane { + size, + rd, + ri, + rn, + lane_imm, + lane_reg, + } => { + let op = match size { + 8 => "vlvgb", + 16 => "vlvgh", + 32 => "vlvgf", + 64 => "vlvgg", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + let rn = pretty_print_reg(rn); + let lane_reg = if lane_reg != zero_reg() { + format!("({})", pretty_print_reg(lane_reg)) + } else { + "".to_string() + }; + format!("{op} {rd}, {rn}, {lane_imm}{lane_reg}") + } + &Inst::VecInsertLaneUndef { + size, + rd, + rn, + lane_imm, + lane_reg, + } => { + let (opcode_vrs, opcode_rre) = match size { + 8 => ("vlvgb", None), + 16 => ("vlvgh", None), + 32 => ("vlvgf", None), + 64 => ("vlvgg", Some("ldgr")), + _ => unreachable!(), + }; + let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg()); + let rn = pretty_print_reg(rn); + let lane_reg = if lane_reg != zero_reg() { + format!("({})", pretty_print_reg(lane_reg)) + } else { + "".to_string() + }; + if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rd_fpr.is_some() + { + format!("{} {}, {}", opcode_rre.unwrap(), rd_fpr.unwrap(), rn) + } else { + format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}") + } + } + &Inst::VecExtractLane { + size, + rd, + rn, + lane_imm, + lane_reg, + } => { + let (opcode_vrs, opcode_rre) = match size { + 8 => ("vlgvb", None), + 16 => ("vlgvh", None), + 32 => ("vlgvf", None), + 64 => ("vlgvg", Some("lgdr")), + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd.to_reg()); + let (rn, rn_fpr) = pretty_print_fpr(rn); + let lane_reg = if lane_reg != zero_reg() { + format!("({})", pretty_print_reg(lane_reg)) + } else { + "".to_string() + }; + if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rn_fpr.is_some() + { + format!("{} {}, {}", opcode_rre.unwrap(), rd, rn_fpr.unwrap()) + } else { + format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}") + } + } + &Inst::VecInsertLaneImm { + size, + rd, + ri, + imm, + lane_imm, + } => { + let op = match size { + 8 => "vleib", + 16 => "vleih", + 32 => "vleif", + 64 => "vleig", + _ => unreachable!(), + }; + let rd = pretty_print_reg_mod(rd, ri); + format!("{op} {rd}, {imm}, {lane_imm}") + } + &Inst::VecReplicateLane { + size, + rd, + rn, + lane_imm, + } => { + let op = match size { + 8 => "vrepb", + 16 => "vreph", + 32 => "vrepf", + 64 => "vrepg", + _ => unreachable!(), + }; + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + format!("{op} {rd}, {rn}, {lane_imm}") + } + &Inst::Extend { + rd, + rn, + signed, + from_bits, + to_bits, + } => { + let rd = pretty_print_reg(rd.to_reg()); + let rn = pretty_print_reg(rn); + let op = match (signed, from_bits, to_bits) { + (_, 1, 32) => "llcr", + (_, 1, 64) => "llgcr", + (false, 8, 32) => "llcr", + (false, 8, 64) => "llgcr", + (true, 8, 32) => "lbr", + (true, 8, 64) => "lgbr", + (false, 16, 32) => "llhr", + (false, 16, 64) => "llghr", + (true, 16, 32) => "lhr", + (true, 16, 64) => "lghr", + (false, 32, 64) => "llgfr", + (true, 32, 64) => "lgfr", + _ => panic!("Unsupported Extend case: {self:?}"), + }; + format!("{op} {rd}, {rn}") + } + &Inst::AllocateArgs { size } => { + if let Ok(size) = i16::try_from(size) { + format!("aghi {}, {}", show_reg(stack_reg()), -size) + } else { + format!("slgfi {}, {}", show_reg(stack_reg()), size) + } + } + &Inst::Call { link, ref info } => { + let link = link.to_reg(); + let callee_pop_size = if info.callee_pop_size > 0 { + format!(" ; callee_pop_size {}", info.callee_pop_size) + } else { + "".to_string() + }; + format!( + "brasl {}, {}{}", + show_reg(link), + info.dest.display(None), + callee_pop_size + ) + } + &Inst::CallInd { link, ref info, .. } => { + let link = link.to_reg(); + let rn = pretty_print_reg(info.dest); + let callee_pop_size = if info.callee_pop_size > 0 { + format!(" ; callee_pop_size {}", info.callee_pop_size) + } else { + "".to_string() + }; + format!("basr {}, {}{}", show_reg(link), rn, callee_pop_size) + } + &Inst::ReturnCall { ref info } => { + let callee_pop_size = if info.callee_pop_size > 0 { + format!(" ; callee_pop_size {}", info.callee_pop_size) + } else { + "".to_string() + }; + format!("return_call {}{}", info.dest.display(None), callee_pop_size) + } + &Inst::ReturnCallInd { ref info } => { + let rn = pretty_print_reg(info.dest); + let callee_pop_size = if info.callee_pop_size > 0 { + format!(" ; callee_pop_size {}", info.callee_pop_size) + } else { + "".to_string() + }; + format!("return_call_ind {rn}{callee_pop_size}") + } + &Inst::ElfTlsGetOffset { ref symbol, .. } => { + let dest = match &**symbol { + SymbolReloc::TlsGd { name } => { + format!("tls_gdcall:{}", name.display(None)) + } + _ => unreachable!(), + }; + format!("brasl {}, {}", show_reg(gpr(14)), dest) + } + &Inst::Args { ref args } => { + let mut s = "args".to_string(); + for arg in args { + let preg = pretty_print_reg(arg.preg); + let def = pretty_print_reg(arg.vreg.to_reg()); + write!(&mut s, " {def}={preg}").unwrap(); + } + s + } + &Inst::Rets { ref rets } => { + let mut s = "rets".to_string(); + for ret in rets { + let preg = pretty_print_reg(ret.preg); + let vreg = pretty_print_reg(ret.vreg); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + &Inst::Ret { link } => { + let link = show_reg(link); + format!("br {link}") + } + &Inst::Jump { dest } => { + let dest = dest.to_string(); + format!("jg {dest}") + } + &Inst::IndirectBr { rn, .. } => { + let rn = pretty_print_reg(rn); + format!("br {rn}") + } + &Inst::CondBr { + taken, + not_taken, + cond, + } => { + let taken = taken.to_string(); + let not_taken = not_taken.to_string(); + let cond = cond.pretty_print_default(); + format!("jg{cond} {taken} ; jg {not_taken}") + } + &Inst::OneWayCondBr { target, cond } => { + let target = target.to_string(); + let cond = cond.pretty_print_default(); + format!("jg{cond} {target}") + } + &Inst::Debugtrap => ".word 0x0001 # debugtrap".to_string(), + &Inst::Trap { trap_code } => { + format!(".word 0x0000 # trap={trap_code}") + } + &Inst::TrapIf { cond, trap_code } => { + let cond = cond.pretty_print_default(); + format!("jg{cond} .+2 # trap={trap_code}") + } + &Inst::JTSequence { ridx, ref targets } => { + let ridx = pretty_print_reg(ridx); + let rtmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + // The first entry is the default target, which is not emitted + // into the jump table, so we skip it here. It is only in the + // list so MachTerminator will see the potential target. + let jt_entries: String = targets + .iter() + .skip(1) + .map(|label| format!(" {}", label.to_string())) + .collect(); + format!( + concat!( + "larl {}, 14 ; ", + "agf {}, 0({}, {}) ; ", + "br {} ; ", + "jt_entries{}" + ), + rtmp, rtmp, rtmp, ridx, rtmp, jt_entries, + ) + } + &Inst::LoadSymbolReloc { + rd, + ref symbol_reloc, + } => { + let rd = pretty_print_reg(rd.to_reg()); + let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg()); + let symbol = match &**symbol_reloc { + SymbolReloc::Absolute { name, offset } => { + format!("{} + {}", name.display(None), offset) + } + SymbolReloc::TlsGd { name } => format!("{}@tlsgd", name.display(None)), + }; + format!("bras {tmp}, 12 ; data {symbol} ; lg {rd}, 0({tmp})") + } + &Inst::LoadAddr { rd, ref mem } => { + let rd = pretty_print_reg(rd.to_reg()); + let mem = mem.clone(); + let (mem_str, mem) = mem_finalize_for_show( + &mem, + state, + MemInstType { + have_d12: true, + have_d20: true, + have_pcrel: true, + have_unaligned_pcrel: true, + have_index: true, + }, + ); + let op = match &mem { + &MemArg::BXD12 { .. } => "la", + &MemArg::BXD20 { .. } => "lay", + &MemArg::Label { .. } | &MemArg::Symbol { .. } => "larl", + _ => unreachable!(), + }; + let mem = mem.pretty_print_default(); + + format!("{mem_str}{op} {rd}, {mem}") + } + &Inst::StackProbeLoop { + probe_count, + guard_size, + } => { + let probe_count = pretty_print_reg(probe_count.to_reg()); + let stack_reg = pretty_print_reg(stack_reg()); + format!("0: aghi {stack_reg}, -{guard_size} ; mvi 0({stack_reg}), 0 ; brct {probe_count}, 0b") + } + &Inst::Loop { ref body, cond } => { + let body = body + .into_iter() + .map(|inst| inst.print_with_state(state)) + .collect::>() + .join(" ; "); + let cond = cond.pretty_print_default(); + format!("0: {body} ; jg{cond} 0b ; 1:") + } + &Inst::CondBreak { cond } => { + let cond = cond.pretty_print_default(); + format!("jg{cond} 1f") + } + &Inst::Unwind { ref inst } => { + format!("unwind {inst:?}") + } + &Inst::DummyUse { reg } => { + let reg = pretty_print_reg(reg); + format!("dummy_use {reg}") + } + } + } +} + +//============================================================================= +// Label fixups and jump veneers. + +/// Different forms of label references for different instruction formats. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LabelUse { + #[allow(dead_code)] + /// RI-format branch. 16-bit signed offset. PC-relative, offset is imm << 1. + BranchRI, + /// RIL-format branch. 32-bit signed offset. PC-relative, offset is imm << 1. + BranchRIL, + /// 32-bit PC relative constant offset (from address of constant itself), + /// signed. Used in jump tables. + PCRel32, + /// 32-bit PC relative constant offset (from address of call instruction), + /// signed. Offset is imm << 1. Used for call relocations. + PCRel32Dbl, +} + +impl MachInstLabelUse for LabelUse { + /// Alignment for veneer code. + const ALIGN: CodeOffset = 2; + + /// Maximum PC-relative range (positive), inclusive. + fn max_pos_range(self) -> CodeOffset { + match self { + // 16-bit signed immediate, left-shifted by 1. + LabelUse::BranchRI => ((1 << 15) - 1) << 1, + // 32-bit signed immediate, left-shifted by 1. + LabelUse::BranchRIL => 0xffff_fffe, + // 32-bit signed immediate. + LabelUse::PCRel32 => 0x7fff_ffff, + // 32-bit signed immediate, left-shifted by 1, offset by 2. + LabelUse::PCRel32Dbl => 0xffff_fffc, + } + } + + /// Maximum PC-relative range (negative). + fn max_neg_range(self) -> CodeOffset { + match self { + // 16-bit signed immediate, left-shifted by 1. + LabelUse::BranchRI => (1 << 15) << 1, + // 32-bit signed immediate, left-shifted by 1. + // NOTE: This should be 4GB, but CodeOffset is only u32. + LabelUse::BranchRIL => 0xffff_ffff, + // 32-bit signed immediate. + LabelUse::PCRel32 => 0x8000_0000, + // 32-bit signed immediate, left-shifted by 1, offset by 2. + // NOTE: This should be 4GB + 2, but CodeOffset is only u32. + LabelUse::PCRel32Dbl => 0xffff_ffff, + } + } + + /// Size of window into code needed to do the patch. + fn patch_size(self) -> CodeOffset { + match self { + LabelUse::BranchRI => 4, + LabelUse::BranchRIL => 6, + LabelUse::PCRel32 => 4, + LabelUse::PCRel32Dbl => 4, + } + } + + /// Perform the patch. + fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) { + let pc_rel = (label_offset as i64) - (use_offset as i64); + debug_assert!(pc_rel <= self.max_pos_range() as i64); + debug_assert!(pc_rel >= -(self.max_neg_range() as i64)); + debug_assert!(pc_rel & 1 == 0); + let pc_rel_shifted = pc_rel >> 1; + + match self { + LabelUse::BranchRI => { + buffer[2..4].clone_from_slice(&u16::to_be_bytes(pc_rel_shifted as u16)); + } + LabelUse::BranchRIL => { + buffer[2..6].clone_from_slice(&u32::to_be_bytes(pc_rel_shifted as u32)); + } + LabelUse::PCRel32 => { + let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]); + let insn_word = insn_word.wrapping_add(pc_rel as u32); + buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word)); + } + LabelUse::PCRel32Dbl => { + let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]); + let insn_word = insn_word.wrapping_add((pc_rel_shifted + 1) as u32); + buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word)); + } + } + } + + /// Is a veneer supported for this label reference type? + fn supports_veneer(self) -> bool { + false + } + + /// How large is the veneer, if supported? + fn veneer_size(self) -> CodeOffset { + 0 + } + + fn worst_case_veneer_size() -> CodeOffset { + 0 + } + + /// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return + /// an offset and label-use for the veneer's use of the original label. + fn generate_veneer( + self, + _buffer: &mut [u8], + _veneer_offset: CodeOffset, + ) -> (CodeOffset, LabelUse) { + unreachable!(); + } + + fn from_reloc(reloc: Reloc, addend: Addend) -> Option { + match (reloc, addend) { + (Reloc::S390xPCRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl), + (Reloc::S390xPLTRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl), + _ => None, + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/regs.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/regs.rs new file mode 100644 index 00000000000000..cbdc628cc555a5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/regs.rs @@ -0,0 +1,169 @@ +//! S390x ISA definitions: registers. + +use alloc::string::String; +use regalloc2::PReg; + +use crate::isa::s390x::inst::{RegPair, WritableRegPair}; +use crate::machinst::*; + +//============================================================================= +// Registers, the Universe thereof, and printing + +/// Get a reference to a GPR (integer register). +pub fn gpr(num: u8) -> Reg { + Reg::from(gpr_preg(num)) +} + +pub(crate) const fn gpr_preg(num: u8) -> PReg { + assert!(num < 16); + PReg::new(num as usize, RegClass::Int) +} + +/// Get a writable reference to a GPR. +pub fn writable_gpr(num: u8) -> Writable { + Writable::from_reg(gpr(num)) +} + +/// Get a reference to a VR (vector register). +pub fn vr(num: u8) -> Reg { + Reg::from(vr_preg(num)) +} + +pub(crate) const fn vr_preg(num: u8) -> PReg { + assert!(num < 32); + PReg::new(num as usize, RegClass::Float) +} + +/// Get a writable reference to a VR. +#[allow(dead_code)] // used by tests. +pub fn writable_vr(num: u8) -> Writable { + Writable::from_reg(vr(num)) +} + +/// Test whether a vector register is overlapping an FPR. +pub fn is_fpr(r: Reg) -> bool { + let r = r.to_real_reg().unwrap(); + assert!(r.class() == RegClass::Float); + return r.hw_enc() < 16; +} + +/// Get a reference to the stack-pointer register. +pub fn stack_reg() -> Reg { + gpr(15) +} + +/// Get a writable reference to the stack-pointer register. +pub fn writable_stack_reg() -> Writable { + Writable::from_reg(stack_reg()) +} + +/// Get a reference to the first temporary, sometimes "spill temporary", register. This register is +/// used to compute the address of a spill slot when a direct offset addressing mode from FP is not +/// sufficient (+/- 2^11 words). We exclude this register from regalloc and reserve it for this +/// purpose for simplicity; otherwise we need a multi-stage analysis where we first determine how +/// many spill slots we have, then perhaps remove the reg from the pool and recompute regalloc. +/// +/// We use r1 for this because it's a scratch register but is slightly special (used for linker +/// veneers). We're free to use it as long as we don't expect it to live through call instructions. +pub fn spilltmp_reg() -> Reg { + gpr(1) +} + +/// Get a writable reference to the spilltmp reg. +pub fn writable_spilltmp_reg() -> Writable { + Writable::from_reg(spilltmp_reg()) +} + +pub fn zero_reg() -> Reg { + gpr(0) +} + +pub fn show_reg(reg: Reg) -> String { + if let Some(rreg) = reg.to_real_reg() { + match rreg.class() { + RegClass::Int => format!("%r{}", rreg.hw_enc()), + RegClass::Float => format!("%v{}", rreg.hw_enc()), + RegClass::Vector => unreachable!(), + } + } else { + format!("%{reg:?}") + } +} + +pub fn maybe_show_fpr(reg: Reg) -> Option { + if let Some(rreg) = reg.to_real_reg() { + if is_fpr(reg) { + return Some(format!("%f{}", rreg.hw_enc())); + } + } + None +} + +pub fn pretty_print_reg(reg: Reg) -> String { + show_reg(reg) +} + +pub fn pretty_print_regpair(pair: RegPair) -> String { + let hi = pair.hi; + let lo = pair.lo; + if let Some(hi_reg) = hi.to_real_reg() { + if let Some(lo_reg) = lo.to_real_reg() { + assert!( + hi_reg.hw_enc() + 1 == lo_reg.hw_enc(), + "Invalid regpair: {} {}", + show_reg(hi), + show_reg(lo) + ); + return show_reg(hi); + } + } + + format!("{}/{}", show_reg(hi), show_reg(lo)) +} + +pub fn pretty_print_reg_mod(rd: Writable, ri: Reg) -> String { + let output = rd.to_reg(); + let input = ri; + if output == input { + show_reg(output) + } else { + format!("{}<-{}", show_reg(output), show_reg(input)) + } +} + +pub fn pretty_print_regpair_mod(rd: WritableRegPair, ri: RegPair) -> String { + let rd_hi = rd.hi.to_reg(); + let rd_lo = rd.lo.to_reg(); + let ri_hi = ri.hi; + let ri_lo = ri.lo; + if rd_hi == ri_hi { + show_reg(rd_hi) + } else { + format!( + "{}/{}<-{}/{}", + show_reg(rd_hi), + show_reg(rd_lo), + show_reg(ri_hi), + show_reg(ri_lo) + ) + } +} + +pub fn pretty_print_regpair_mod_lo(rd: WritableRegPair, ri: Reg) -> String { + let rd_hi = rd.hi.to_reg(); + let rd_lo = rd.lo.to_reg(); + if rd_lo == ri { + show_reg(rd_hi) + } else { + format!( + "{}/{}<-_/{}", + show_reg(rd_hi), + show_reg(rd_lo), + show_reg(ri), + ) + } +} + +pub fn pretty_print_fpr(reg: Reg) -> (String, Option) { + (show_reg(reg), maybe_show_fpr(reg)) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind.rs new file mode 100644 index 00000000000000..1e2bb904db74fc --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "unwind")] +pub(crate) mod systemv; diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind/systemv.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind/systemv.rs new file mode 100644 index 00000000000000..203fbc7591332c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/inst/unwind/systemv.rs @@ -0,0 +1,212 @@ +//! Unwind information for System V ABI (s390x). + +use crate::isa::unwind::systemv::RegisterMappingError; +use crate::machinst::{Reg, RegClass}; +use gimli::{write::CommonInformationEntry, Encoding, Format, Register}; + +/// Creates a new s390x common information entry (CIE). +pub fn create_cie() -> CommonInformationEntry { + use gimli::write::CallFrameInstruction; + + let mut entry = CommonInformationEntry::new( + Encoding { + address_size: 8, + format: Format::Dwarf32, + version: 1, + }, + 1, // Code alignment factor + -8, // Data alignment factor + Register(14), // Return address column - register %r14 + ); + + // Every frame will start with the call frame address (CFA) at %r15 + 160. + entry.add_instruction(CallFrameInstruction::Cfa(Register(15), 160)); + + entry +} + +/// Map Cranelift registers to their corresponding Gimli registers. +pub fn map_reg(reg: Reg) -> Result { + const GPR_MAP: [gimli::Register; 16] = [ + Register(0), + Register(1), + Register(2), + Register(3), + Register(4), + Register(5), + Register(6), + Register(7), + Register(8), + Register(9), + Register(10), + Register(11), + Register(12), + Register(13), + Register(14), + Register(15), + ]; + const VR_MAP: [gimli::Register; 32] = [ + Register(16), + Register(20), + Register(17), + Register(21), + Register(18), + Register(22), + Register(19), + Register(23), + Register(24), + Register(28), + Register(25), + Register(29), + Register(26), + Register(30), + Register(27), + Register(31), + Register(68), + Register(72), + Register(69), + Register(73), + Register(70), + Register(74), + Register(71), + Register(75), + Register(76), + Register(80), + Register(77), + Register(81), + Register(78), + Register(82), + Register(79), + Register(83), + ]; + + match reg.class() { + RegClass::Int => Ok(GPR_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]), + RegClass::Float => Ok(VR_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]), + RegClass::Vector => unreachable!(), + } +} + +pub(crate) struct RegisterMapper; + +impl crate::isa::unwind::systemv::RegisterMapper for RegisterMapper { + fn map(&self, reg: Reg) -> Result { + Ok(map_reg(reg)?.0) + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::{ + types, AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, + }; + use crate::isa::{lookup, CallConv}; + use crate::settings::{builder, Flags}; + use crate::Context; + use gimli::write::Address; + use target_lexicon::triple; + + #[test] + fn test_simple_func() { + let isa = lookup(triple!("s390x")) + .expect("expect s390x ISA") + .finish(Flags::new(builder())) + .expect("Creating compiler backend"); + + let mut context = Context::for_function(create_function( + CallConv::SystemV, + Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)), + )); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(1234)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(1234), length: 10, lsda: None, instructions: [(4, CfaOffset(224))] }"); + } + + fn create_function(call_conv: CallConv, stack_slot: Option) -> Function { + let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv)); + + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().return_(&[]); + + if let Some(stack_slot) = stack_slot { + func.sized_stack_slots.push(stack_slot); + } + + func + } + + #[test] + fn test_multi_return_func() { + let isa = lookup(triple!("s390x")) + .expect("expect s390x ISA") + .finish(Flags::new(builder())) + .expect("Creating compiler backend"); + + let mut context = Context::for_function(create_multi_return_function( + CallConv::SystemV, + Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)), + )); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(4321)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(4321), length: 26, lsda: None, instructions: [(4, CfaOffset(224))] }"); + } + + fn create_multi_return_function( + call_conv: CallConv, + stack_slot: Option, + ) -> Function { + let mut sig = Signature::new(call_conv); + sig.params.push(AbiParam::new(types::I32)); + let mut func = Function::with_name_signature(Default::default(), sig); + + let block0 = func.dfg.make_block(); + let v0 = func.dfg.append_block_param(block0, types::I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().brif(v0, block2, &[], block1, &[]); + + pos.insert_block(block1); + pos.ins().return_(&[]); + + pos.insert_block(block2); + pos.ins().return_(&[]); + + if let Some(stack_slot) = stack_slot { + func.sized_stack_slots.push(stack_slot); + } + + func + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.isle b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.isle new file mode 100644 index 00000000000000..3b403ef5b37baa --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.isle @@ -0,0 +1,3992 @@ +;; s390x instruction selection and CLIF-to-MachInst lowering. + +;; The main lowering constructor term: takes a clif `Inst` and returns the +;; register(s) within which the lowered instruction's result values live. +(decl partial lower (Inst) InstOutput) + +;; A variant of the main lowering constructor term, used for branches. +;; The only difference is that it gets an extra argument holding a vector +;; of branch targets to be used. +(decl partial lower_branch (Inst MachLabelSlice) Unit) + + +;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (iconst (u64_from_imm64 n)))) + (imm ty n)) + + +;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f32const (u32_from_ieee32 x))) + (imm $F32 x)) + + +;;;; Rules for `f64const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f64const (u64_from_ieee64 x))) + (imm $F64 x)) + + +;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (vconst (u128_from_constant x)))) + (vec_imm ty (be_vec_const ty x))) + + +;;;; Rules for `nop` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (nop)) + (invalid_reg)) + + +;;;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (vr128_ty ty) (iconcat x y))) + (mov_to_vec128 ty y x)) + + +;;;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (isplit x @ (value_type $I128))) + (let ((x_reg Reg x) + (x_hi Reg (vec_extract_lane $I64X2 x_reg 0 (zero_reg))) + (x_lo Reg (vec_extract_lane $I64X2 x_reg 1 (zero_reg)))) + (output_pair x_lo x_hi))) + + +;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add two registers. +(rule 0 (lower (has_type (fits_in_64 ty) (iadd x y))) + (add_reg ty x y)) + +;; Add a register and a sign-extended register. +(rule 8 (lower (has_type (fits_in_64 ty) (iadd x (sext32_value y)))) + (add_reg_sext32 ty x y)) +(rule 15 (lower (has_type (fits_in_64 ty) (iadd (sext32_value x) y))) + (add_reg_sext32 ty y x)) + +;; Add a register and an immediate. +(rule 7 (lower (has_type (fits_in_64 ty) (iadd x (i16_from_value y)))) + (add_simm16 ty x y)) +(rule 14 (lower (has_type (fits_in_64 ty) (iadd (i16_from_value x) y))) + (add_simm16 ty y x)) +(rule 6 (lower (has_type (fits_in_64 ty) (iadd x (i32_from_value y)))) + (add_simm32 ty x y)) +(rule 13 (lower (has_type (fits_in_64 ty) (iadd (i32_from_value x) y))) + (add_simm32 ty y x)) + +;; Add a register and memory (32/64-bit types). +(rule 5 (lower (has_type (fits_in_64 ty) (iadd x (sinkable_load_32_64 y)))) + (add_mem ty x (sink_load y))) +(rule 12 (lower (has_type (fits_in_64 ty) (iadd (sinkable_load_32_64 x) y))) + (add_mem ty y (sink_load x))) + +;; Add a register and memory (16-bit types). +(rule 4 (lower (has_type (fits_in_64 ty) (iadd x (sinkable_load_16 y)))) + (add_mem_sext16 ty x (sink_load y))) +(rule 11 (lower (has_type (fits_in_64 ty) (iadd (sinkable_load_16 x) y))) + (add_mem_sext16 ty y (sink_load x))) + +;; Add a register and sign-extended memory. +(rule 3 (lower (has_type (fits_in_64 ty) (iadd x (sinkable_sload16 y)))) + (add_mem_sext16 ty x (sink_sload16 y))) +(rule 10 (lower (has_type (fits_in_64 ty) (iadd (sinkable_sload16 x) y))) + (add_mem_sext16 ty y (sink_sload16 x))) +(rule 2 (lower (has_type (fits_in_64 ty) (iadd x (sinkable_sload32 y)))) + (add_mem_sext32 ty x (sink_sload32 y))) +(rule 9 (lower (has_type (fits_in_64 ty) (iadd (sinkable_sload32 x) y))) + (add_mem_sext32 ty y (sink_sload32 x))) + +;; Add two vector registers. +(rule 1 (lower (has_type (vr128_ty ty) (iadd x y))) + (vec_add ty x y)) + + +;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add (saturate unsigned) two vector registers. +(rule (lower (has_type (ty_vec128 ty) (uadd_sat x y))) + (let ((sum Reg (vec_add ty x y))) + (vec_or ty sum (vec_cmphl ty x sum)))) + + +;;;; Rules for `sadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add (saturate signed) two vector registers. $I64X2 not supported. +(rule (lower (has_type (ty_vec128 ty) (sadd_sat x y))) + (vec_pack_ssat (vec_widen_type ty) + (vec_add (vec_widen_type ty) (vec_unpacks_high ty x) + (vec_unpacks_high ty y)) + (vec_add (vec_widen_type ty) (vec_unpacks_low ty x) + (vec_unpacks_low ty y)))) + + +;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Lane-wise integer pairwise addition for 8-/16/32-bit vector registers. +(rule (lower (has_type ty @ (multi_lane bits _) (iadd_pairwise x y))) + (let ((size Reg (vec_imm_splat $I8X16 (u32_as_u64 bits)))) + (vec_pack_lane_order (vec_widen_type ty) + (vec_add ty x (vec_lshr_by_byte x size)) + (vec_add ty y (vec_lshr_by_byte y size))))) + +;; special case for the `i32x4.dot_i16x8_s` wasm instruction +(rule 1 (lower + (has_type dst_ty (iadd_pairwise + (imul (swiden_low x @ (value_type src_ty)) (swiden_low y)) + (imul (swiden_high x) (swiden_high y))))) + (vec_add dst_ty (vec_smul_even src_ty x y) + (vec_smul_odd src_ty x y))) + + +;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Sub two registers. +(rule 0 (lower (has_type (fits_in_64 ty) (isub x y))) + (sub_reg ty x y)) + +;; Sub a register and a sign-extended register. +(rule 8 (lower (has_type (fits_in_64 ty) (isub x (sext32_value y)))) + (sub_reg_sext32 ty x y)) + +;; Sub a register and an immediate (using add of the negated value). +(rule 7 (lower (has_type (fits_in_64 ty) (isub x (i16_from_negated_value y)))) + (add_simm16 ty x y)) +(rule 6 (lower (has_type (fits_in_64 ty) (isub x (i32_from_negated_value y)))) + (add_simm32 ty x y)) + +;; Sub a register and memory (32/64-bit types). +(rule 5 (lower (has_type (fits_in_64 ty) (isub x (sinkable_load_32_64 y)))) + (sub_mem ty x (sink_load y))) + +;; Sub a register and memory (16-bit types). +(rule 4 (lower (has_type (fits_in_64 ty) (isub x (sinkable_load_16 y)))) + (sub_mem_sext16 ty x (sink_load y))) + +;; Sub a register and sign-extended memory. +(rule 3 (lower (has_type (fits_in_64 ty) (isub x (sinkable_sload16 y)))) + (sub_mem_sext16 ty x (sink_sload16 y))) +(rule 2 (lower (has_type (fits_in_64 ty) (isub x (sinkable_sload32 y)))) + (sub_mem_sext32 ty x (sink_sload32 y))) + +;; Sub two vector registers. +(rule 1 (lower (has_type (vr128_ty ty) (isub x y))) + (vec_sub ty x y)) + + +;;;; Rules for `usub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add (saturate unsigned) two vector registers. +(rule (lower (has_type (ty_vec128 ty) (usub_sat x y))) + (vec_and ty (vec_sub ty x y) (vec_cmphl ty x y))) + + +;;;; Rules for `ssub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add (saturate signed) two vector registers. $I64X2 not supported. +(rule (lower (has_type (ty_vec128 ty) (ssub_sat x y))) + (vec_pack_ssat (vec_widen_type ty) + (vec_sub (vec_widen_type ty) (vec_unpacks_high ty x) + (vec_unpacks_high ty y)) + (vec_sub (vec_widen_type ty) (vec_unpacks_low ty x) + (vec_unpacks_low ty y)))) + + +;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Absolute value of a register. +;; For types smaller than 32-bit, the input value must be sign-extended. +(rule 2 (lower (has_type (fits_in_64 ty) (iabs x))) + (abs_reg (ty_ext32 ty) (put_in_reg_sext32 x))) + +;; Absolute value of a sign-extended register. +(rule 3 (lower (has_type (fits_in_64 ty) (iabs (sext32_value x)))) + (abs_reg_sext32 ty x)) + +;; Absolute value of a vector register. +(rule 1 (lower (has_type (ty_vec128 ty) (iabs x))) + (vec_abs ty x)) + +;; Absolute value of a 128-bit integer. +(rule 0 (lower (has_type $I128 (iabs x))) + (let ((zero Reg (vec_imm $I128 0)) + (pos Reg x) + (neg Reg (vec_sub $I128 zero pos)) + (rep Reg (vec_replicate_lane $I64X2 pos 0)) + (mask Reg (vec_cmph $I64X2 zero rep))) + (vec_select $I128 neg pos mask))) + + +;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Negate a register. +(rule 2 (lower (has_type (fits_in_64 ty) (ineg x))) + (neg_reg ty x)) + +;; Negate a sign-extended register. +(rule 3 (lower (has_type (fits_in_64 ty) (ineg (sext32_value x)))) + (neg_reg_sext32 ty x)) + +;; Negate a vector register. +(rule 1 (lower (has_type (ty_vec128 ty) (ineg x))) + (vec_neg ty x)) + +;; Negate a 128-bit integer. +(rule 0 (lower (has_type $I128 (ineg x))) + (vec_sub $I128 (vec_imm $I128 0) x)) + + +;;;; Rules for `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unsigned maximum of two scalar integers - expand to icmp + select. +(rule 2 (lower (has_type (fits_in_64 ty) (umax x y))) + (let ((x_ext Reg (put_in_reg_zext32 x)) + (y_ext Reg (put_in_reg_zext32 y)) + (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext) + (intcc_as_cond (IntCC.UnsignedLessThan))))) + (select_bool_reg ty cond y_ext x_ext))) + +;; Unsigned maximum of two 128-bit integers - expand to icmp + select. +(rule 1 (lower (has_type $I128 (umax x y))) + (let ((x_reg Reg (put_in_reg x)) + (y_reg Reg (put_in_reg y)) + (cond ProducesBool (vec_int128_ucmphi y_reg x_reg))) + (select_bool_reg $I128 cond y_reg x_reg))) + +;; Unsigned maximum of two vector registers. +(rule 0 (lower (has_type (ty_vec128 ty) (umax x y))) + (vec_umax ty x y)) + + +;;;; Rules for `umin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unsigned minimum of two scalar integers - expand to icmp + select. +(rule 2 (lower (has_type (fits_in_64 ty) (umin x y))) + (let ((x_ext Reg (put_in_reg_zext32 x)) + (y_ext Reg (put_in_reg_zext32 y)) + (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext) + (intcc_as_cond (IntCC.UnsignedGreaterThan))))) + (select_bool_reg ty cond y_ext x_ext))) + +;; Unsigned maximum of two 128-bit integers - expand to icmp + select. +(rule 1 (lower (has_type $I128 (umin x y))) + (let ((x_reg Reg (put_in_reg x)) + (y_reg Reg (put_in_reg y)) + (cond ProducesBool (vec_int128_ucmphi x_reg y_reg))) + (select_bool_reg $I128 cond y_reg x_reg))) + +;; Unsigned minimum of two vector registers. +(rule 0 (lower (has_type (ty_vec128 ty) (umin x y))) + (vec_umin ty x y)) + + +;;;; Rules for `smax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Signed maximum of two scalar integers - expand to icmp + select. +(rule 2 (lower (has_type (fits_in_64 ty) (smax x y))) + (let ((x_ext Reg (put_in_reg_sext32 x)) + (y_ext Reg (put_in_reg_sext32 y)) + (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext) + (intcc_as_cond (IntCC.SignedLessThan))))) + (select_bool_reg ty cond y_ext x_ext))) + +;; Signed maximum of two 128-bit integers - expand to icmp + select. +(rule 1 (lower (has_type $I128 (smax x y))) + (let ((x_reg Reg (put_in_reg x)) + (y_reg Reg (put_in_reg y)) + (cond ProducesBool (vec_int128_scmphi y_reg x_reg))) + (select_bool_reg $I128 cond y_reg x_reg))) + +;; Signed maximum of two vector registers. +(rule (lower (has_type (ty_vec128 ty) (smax x y))) + (vec_smax ty x y)) + + +;;;; Rules for `smin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Signed minimum of two scalar integers - expand to icmp + select. +(rule 2 (lower (has_type (fits_in_64 ty) (smin x y))) + (let ((x_ext Reg (put_in_reg_sext32 x)) + (y_ext Reg (put_in_reg_sext32 y)) + (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext) + (intcc_as_cond (IntCC.SignedGreaterThan))))) + (select_bool_reg ty cond y_ext x_ext))) + +;; Signed maximum of two 128-bit integers - expand to icmp + select. +(rule 1 (lower (has_type $I128 (smin x y))) + (let ((x_reg Reg (put_in_reg x)) + (y_reg Reg (put_in_reg y)) + (cond ProducesBool (vec_int128_scmphi x_reg y_reg))) + (select_bool_reg $I128 cond y_reg x_reg))) + +;; Signed minimum of two vector registers. +(rule (lower (has_type (ty_vec128 ty) (smin x y))) + (vec_smin ty x y)) + + +;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unsigned average of two vector registers. +(rule (lower (has_type (ty_vec128 ty) (avg_round x y))) + (vec_uavg ty x y)) + + +;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Multiply two registers. +(rule 0 (lower (has_type (fits_in_64 ty) (imul x y))) + (mul_reg ty x y)) + +;; Multiply a register and a sign-extended register. +(rule 8 (lower (has_type (fits_in_64 ty) (imul x (sext32_value y)))) + (mul_reg_sext32 ty x y)) +(rule 15 (lower (has_type (fits_in_64 ty) (imul (sext32_value x) y))) + (mul_reg_sext32 ty y x)) + +;; Multiply a register and an immediate. +(rule 7 (lower (has_type (fits_in_64 ty) (imul x (i16_from_value y)))) + (mul_simm16 ty x y)) +(rule 14 (lower (has_type (fits_in_64 ty) (imul (i16_from_value x) y))) + (mul_simm16 ty y x)) +(rule 6 (lower (has_type (fits_in_64 ty) (imul x (i32_from_value y)))) + (mul_simm32 ty x y)) +(rule 13 (lower (has_type (fits_in_64 ty) (imul (i32_from_value x) y))) + (mul_simm32 ty y x)) + +;; Multiply a register and memory (32/64-bit types). +(rule 5 (lower (has_type (fits_in_64 ty) (imul x (sinkable_load_32_64 y)))) + (mul_mem ty x (sink_load y))) +(rule 12 (lower (has_type (fits_in_64 ty) (imul (sinkable_load_32_64 x) y))) + (mul_mem ty y (sink_load x))) + +;; Multiply a register and memory (16-bit types). +(rule 4 (lower (has_type (fits_in_64 ty) (imul x (sinkable_load_16 y)))) + (mul_mem_sext16 ty x (sink_load y))) +(rule 11 (lower (has_type (fits_in_64 ty) (imul (sinkable_load_16 x) y))) + (mul_mem_sext16 ty y (sink_load x))) + +;; Multiply a register and sign-extended memory. +(rule 3 (lower (has_type (fits_in_64 ty) (imul x (sinkable_sload16 y)))) + (mul_mem_sext16 ty x (sink_sload16 y))) +(rule 10 (lower (has_type (fits_in_64 ty) (imul (sinkable_sload16 x) y))) + (mul_mem_sext16 ty y (sink_sload16 x))) +(rule 2 (lower (has_type (fits_in_64 ty) (imul x (sinkable_sload32 y)))) + (mul_mem_sext32 ty x (sink_sload32 y))) +(rule 9 (lower (has_type (fits_in_64 ty) (imul (sinkable_sload32 x) y))) + (mul_mem_sext32 ty y (sink_sload32 x))) + +;; Multiply two vector registers, using a helper. +(decl vec_mul_impl (Type Reg Reg) Reg) +(rule 1 (lower (has_type (vr128_ty ty) (imul x y))) + (vec_mul_impl ty x y)) + +;; Multiply two vector registers - byte, halfword, and word. +(rule (vec_mul_impl $I8X16 x y) (vec_mul $I8X16 x y)) +(rule (vec_mul_impl $I16X8 x y) (vec_mul $I16X8 x y)) +(rule (vec_mul_impl $I32X4 x y) (vec_mul $I32X4 x y)) + +;; Multiply two vector registers - doubleword. Has to be scalarized. +(rule (vec_mul_impl $I64X2 x y) + (mov_to_vec128 $I64X2 + (mul_reg $I64 (vec_extract_lane $I64X2 x 0 (zero_reg)) + (vec_extract_lane $I64X2 y 0 (zero_reg))) + (mul_reg $I64 (vec_extract_lane $I64X2 x 1 (zero_reg)) + (vec_extract_lane $I64X2 y 1 (zero_reg))))) + +;; Multiply two vector registers - quadword. +(rule (vec_mul_impl $I128 x y) + (let ((x_hi Reg (vec_extract_lane $I64X2 x 0 (zero_reg))) + (x_lo Reg (vec_extract_lane $I64X2 x 1 (zero_reg))) + (y_hi Reg (vec_extract_lane $I64X2 y 0 (zero_reg))) + (y_lo Reg (vec_extract_lane $I64X2 y 1 (zero_reg))) + (lo_pair RegPair (umul_wide x_lo y_lo)) + (res_lo Reg (regpair_lo lo_pair)) + (res_hi_1 Reg (regpair_hi lo_pair)) + (res_hi_2 Reg (mul_reg $I64 x_lo y_hi)) + (res_hi_3 Reg (mul_reg $I64 x_hi y_lo)) + (res_hi Reg (add_reg $I64 res_hi_3 (add_reg $I64 res_hi_2 res_hi_1)))) + (mov_to_vec128 $I64X2 res_hi res_lo))) + +;; Special-case the lowering of a 128-bit multiply where the operands are sign +;; or zero extended. This maps directly to `umul_wide` and `smul_wide`. +(rule 16 (lower (has_type $I128 (imul (uextend x) (uextend y)))) + (let ((pair RegPair (umul_wide (put_in_reg_zext64 x) (put_in_reg_zext64 y)))) + (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair)))) + +(rule 16 (lower (has_type $I128 (imul (sextend x) (sextend y)))) + (let ((pair RegPair (smul_wide (put_in_reg_sext64 x) (put_in_reg_sext64 y)))) + (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair)))) + +;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Multiply high part unsigned, 8-bit or 16-bit types. (Uses 32-bit multiply.) +(rule -1 (lower (has_type (ty_8_or_16 ty) (umulhi x y))) + (let ((ext_reg_x Reg (put_in_reg_zext32 x)) + (ext_reg_y Reg (put_in_reg_zext32 y)) + (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y))) + (lshr_imm $I32 ext_mul (ty_bits ty)))) + +;; Multiply high part unsigned, 32-bit types. (Uses 64-bit multiply.) +(rule (lower (has_type $I32 (umulhi x y))) + (let ((ext_reg_x Reg (put_in_reg_zext64 x)) + (ext_reg_y Reg (put_in_reg_zext64 y)) + (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y))) + (lshr_imm $I64 ext_mul 32))) + +;; Multiply high part unsigned, 64-bit types. (Uses umul_wide.) +(rule (lower (has_type $I64 (umulhi x y))) + (let ((pair RegPair (umul_wide x y))) + (regpair_hi pair))) + +;; Multiply high part unsigned, vector types with 8-, 16-, or 32-bit elements. +(rule (lower (has_type $I8X16 (umulhi x y))) (vec_umulhi $I8X16 x y)) +(rule (lower (has_type $I16X8 (umulhi x y))) (vec_umulhi $I16X8 x y)) +(rule (lower (has_type $I32X4 (umulhi x y))) (vec_umulhi $I32X4 x y)) + +;; Multiply high part unsigned, vector types with 64-bit elements. +;; Has to be scalarized. +(rule (lower (has_type $I64X2 (umulhi x y))) + (let ((pair_0 RegPair (umul_wide (vec_extract_lane $I64X2 x 0 (zero_reg)) + (vec_extract_lane $I64X2 y 0 (zero_reg)))) + (res_0 Reg (regpair_hi pair_0)) + (pair_1 RegPair (umul_wide (vec_extract_lane $I64X2 x 1 (zero_reg)) + (vec_extract_lane $I64X2 y 1 (zero_reg)))) + (res_1 Reg (regpair_hi pair_1))) + (mov_to_vec128 $I64X2 res_0 res_1))) + + +;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Multiply high part signed, 8-bit or 16-bit types. (Uses 32-bit multiply.) +(rule -1 (lower (has_type (ty_8_or_16 ty) (smulhi x y))) + (let ((ext_reg_x Reg (put_in_reg_sext32 x)) + (ext_reg_y Reg (put_in_reg_sext32 y)) + (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y))) + (ashr_imm $I32 ext_mul (ty_bits ty)))) + +;; Multiply high part signed, 32-bit types. (Uses 64-bit multiply.) +(rule (lower (has_type $I32 (smulhi x y))) + (let ((ext_reg_x Reg (put_in_reg_sext64 x)) + (ext_reg_y Reg (put_in_reg_sext64 y)) + (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y))) + (ashr_imm $I64 ext_mul 32))) + +;; Multiply high part signed, 64-bit types. (Uses smul_wide.) +(rule (lower (has_type $I64 (smulhi x y))) + (let ((pair RegPair (smul_wide x y))) + (regpair_hi pair))) + +;; Multiply high part signed, vector types with 8-, 16-, or 32-bit elements. +(rule (lower (has_type $I8X16 (smulhi x y))) (vec_smulhi $I8X16 x y)) +(rule (lower (has_type $I16X8 (smulhi x y))) (vec_smulhi $I16X8 x y)) +(rule (lower (has_type $I32X4 (smulhi x y))) (vec_smulhi $I32X4 x y)) + +;; Multiply high part unsigned, vector types with 64-bit elements. +;; Has to be scalarized. +(rule (lower (has_type $I64X2 (smulhi x y))) + (let ((pair_0 RegPair (smul_wide (vec_extract_lane $I64X2 x 0 (zero_reg)) + (vec_extract_lane $I64X2 y 0 (zero_reg)))) + (res_0 Reg (copy_reg $I64 (regpair_hi pair_0))) + (pair_1 RegPair (smul_wide (vec_extract_lane $I64X2 x 1 (zero_reg)) + (vec_extract_lane $I64X2 y 1 (zero_reg)))) + (res_1 Reg (regpair_hi pair_1))) + (mov_to_vec128 $I64X2 res_0 res_1))) + + +;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Fixed-point multiplication of two vector registers. +(rule (lower (has_type (ty_vec128 ty) (sqmul_round_sat x y))) + (vec_pack_ssat (vec_widen_type ty) + (sqmul_impl (vec_widen_type ty) + (vec_unpacks_high ty x) + (vec_unpacks_high ty y)) + (sqmul_impl (vec_widen_type ty) + (vec_unpacks_low ty x) + (vec_unpacks_low ty y)))) + +;; Helper to perform the rounded multiply in the wider type. +(decl sqmul_impl (Type Reg Reg) Reg) +(rule (sqmul_impl $I32X4 x y) + (vec_ashr_imm $I32X4 (vec_add $I32X4 (vec_mul_impl $I32X4 x y) + (vec_imm_bit_mask $I32X4 17 17)) + 15)) +(rule (sqmul_impl $I64X2 x y) + (vec_ashr_imm $I64X2 (vec_add $I64X2 (vec_mul_impl $I64X2 x y) + (vec_imm_bit_mask $I64X2 33 33)) + 31)) + + +;;;; Rules for `udiv` and `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Divide two registers. The architecture provides combined udiv / urem +;; instructions with the following combination of data types: +;; +;; - 64-bit dividend (split across a 2x32-bit register pair), +;; 32-bit divisor (in a single input register) +;; 32-bit quotient & remainder (in a 2x32-bit register pair) +;; +;; - 128-bit dividend (split across a 2x64-bit register pair), +;; 64-bit divisor (in a single input register) +;; 64-bit quotient & remainder (in a 2x64-bit register pair) +;; +;; We use the first variant for 32-bit and smaller input types, +;; and the second variant for 64-bit input types. + +;; Implement `udiv`. +(rule (lower (has_type (fits_in_64 ty) (udiv x y))) + (let ( + ;; Look at the divisor to determine whether we need to generate + ;; an explicit division-by zero check. + ;; Load up the dividend, by loading the input (possibly zero- + ;; extended) input into the low half of the register pair, + ;; and setting the high half to zero. + (ext_x RegPair (regpair (imm (ty_ext32 ty) 0) + (put_in_reg_zext32 x))) + ;; Load up the divisor, zero-extended if necessary. + (ext_y Reg (put_in_reg_zext32 y)) + (ext_ty Type (ty_ext32 ty)) + ;; Emit the actual divide instruction. + (pair RegPair (udivmod ext_ty ext_x ext_y))) + ;; The quotient can be found in the low half of the result. + (regpair_lo pair))) + +;; Implement `urem`. Same as `udiv`, but finds the remainder in +;; the high half of the result register pair instead. +(rule (lower (has_type (fits_in_64 ty) (urem x y))) + (let ((ext_x RegPair (regpair (imm (ty_ext32 ty) 0) + (put_in_reg_zext32 x))) + (ext_y Reg (put_in_reg_zext32 y)) + (ext_ty Type (ty_ext32 ty)) + (pair RegPair (udivmod ext_ty ext_x ext_y))) + (regpair_hi pair))) + + +;;;; Rules for `sdiv` and `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Divide two registers. The architecture provides combined sdiv / srem +;; instructions with the following combination of data types: +;; +;; - 64-bit dividend (in the low half of a 2x64-bit register pair), +;; 32-bit divisor (in a single input register) +;; 64-bit quotient & remainder (in a 2x64-bit register pair) +;; +;; - 64-bit dividend (in the low half of a 2x64-bit register pair), +;; 64-bit divisor (in a single input register) +;; 64-bit quotient & remainder (in a 2x64-bit register pair) +;; +;; We use the first variant for 32-bit and smaller input types, +;; and the second variant for 64-bit input types. + +;; Implement `sdiv`. +(rule (lower (has_type (fits_in_64 ty) (sdiv x y))) + (let ( + ;; Look at the divisor to determine whether we need to generate + ;; explicit division-by-zero and/or integer-overflow checks. + (OFcheck bool (div_overflow_check_needed y)) + ;; Load up the dividend (sign-extended to 64-bit) + (ext_x Reg (put_in_reg_sext64 x)) + ;; Load up the divisor (sign-extended if necessary). + (ext_y Reg (put_in_reg_sext32 y)) + (ext_ty Type (ty_ext32 ty)) + ;; Perform integer-overflow check if necessary. + (_ Reg (maybe_trap_if_sdiv_overflow OFcheck ext_ty ty ext_x ext_y)) + ;; Emit the actual divide instruction. + (pair RegPair (sdivmod ext_ty ext_x ext_y))) + ;; The quotient can be found in the low half of the result. + (regpair_lo pair))) + +;; Implement `srem`. Same as `sdiv`, but finds the remainder in +;; the high half of the result register pair instead. Also, handle +;; the integer overflow case differently, see below. +(rule (lower (has_type (fits_in_64 ty) (srem x y))) + (let ((OFcheck bool (div_overflow_check_needed y)) + (ext_x Reg (put_in_reg_sext64 x)) + (ext_y Reg (put_in_reg_sext32 y)) + (ext_ty Type (ty_ext32 ty)) + (checked_x Reg (maybe_avoid_srem_overflow OFcheck ext_ty ext_x ext_y)) + (pair RegPair (sdivmod ext_ty checked_x ext_y))) + (regpair_hi pair))) + +;; Determine whether we need to perform an integer-overflow check. +;; +;; We never rely on the divide instruction itself to trap; while that trap +;; would indeed happen, we have no way of signalling two different trap +;; conditions from the same instruction. By explicitly checking for the +;; integer-overflow case ahead of time, any hardware trap in the divide +;; instruction is guaranteed to indicate division-by-zero. +;; +;; In addition, for types smaller than 64 bits we would have to perform +;; the check explicitly anyway, since the instruction provides a 64-bit +;; quotient and only traps if *that* overflows. +;; +;; However, the only case where integer overflow can occur is if the +;; minimum (signed) integer value is divided by -1, so if the divisor +;; is any immediate different from -1, the check can be omitted. +(decl div_overflow_check_needed (Value) bool) +(rule 1 (div_overflow_check_needed (i64_from_value x)) + (if (i64_not_neg1 x)) + false) +(rule (div_overflow_check_needed _) true) + +;; Perform the integer-overflow check if necessary. This implements: +;; +;; if divisor == INT_MIN && dividend == -1 { trap } +;; +;; but to avoid introducing control flow, it is actually done as: +;; +;; if ((divisor ^ INT_MAX) & dividend) == -1 { trap } +;; +;; instead, using a single conditional trap instruction. +(decl maybe_trap_if_sdiv_overflow (bool Type Type Reg Reg) Reg) +(rule (maybe_trap_if_sdiv_overflow false ext_ty _ _ _) (invalid_reg)) +(rule (maybe_trap_if_sdiv_overflow true ext_ty ty x y) + (let ((int_max Reg (imm ext_ty (int_max ty))) + (reg Reg (and_reg ext_ty (xor_reg ext_ty int_max x) y))) + (icmps_simm16_and_trap ext_ty reg -1 + (intcc_as_cond (IntCC.Equal)) + (trap_code_integer_overflow)))) +(decl int_max (Type) u64) +(rule (int_max $I8) 0x7f) +(rule (int_max $I16) 0x7fff) +(rule (int_max $I32) 0x7fffffff) +(rule (int_max $I64) 0x7fffffffffffffff) + +;; When performing `srem`, we do not want to trap in the +;; integer-overflow scenario, because it is only the quotient +;; that overflows, not the remainder. +;; +;; For types smaller than 64 bits, we can simply let the +;; instruction execute, since (as above) it will never trap. +;; +;; For 64-bit inputs, we check whether the divisor is -1, and +;; if so simply replace the dividend by zero, which will give +;; the correct result, since any value modulo -1 is zero. +;; +;; (We could in fact avoid executing the divide instruction +;; at all in this case, but that would require introducing +;; control flow.) +(decl maybe_avoid_srem_overflow (bool Type Reg Reg) Reg) +(rule (maybe_avoid_srem_overflow false _ x _) x) +(rule (maybe_avoid_srem_overflow true $I32 x _) x) +(rule (maybe_avoid_srem_overflow true $I64 x y) + (with_flags_reg (icmps_simm16 $I64 y -1) + (cmov_imm $I64 (intcc_as_cond (IntCC.Equal)) 0 x))) + + +;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Shift left, shift amount in register. +(rule 0 (lower (has_type (fits_in_64 ty) (ishl x y))) + (let ((masked_amt Reg (mask_amt_reg ty (amt_reg y)))) + (lshl_reg ty x masked_amt))) + +;; Shift left, immediate shift amount. +(rule 1 (lower (has_type (fits_in_64 ty) (ishl x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (lshl_imm ty x masked_amt))) + +;; Vector shift left, shift amount in register. +(rule 2 (lower (has_type (ty_vec128 ty) (ishl x y))) + (vec_lshl_reg ty x (amt_reg y))) + +;; Vector shift left, immediate shift amount. +(rule 3 (lower (has_type (ty_vec128 ty) (ishl x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (vec_lshl_imm ty x masked_amt))) + +;; 128-bit vector shift left. +(rule 4 (lower (has_type $I128 (ishl x y))) + (let ((amt Reg (amt_vr y))) + (vec_lshl_by_bit (vec_lshl_by_byte x amt) amt))) + + +;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Shift right logical, shift amount in register. +;; For types smaller than 32-bit, the input value must be zero-extended. +(rule 0 (lower (has_type (fits_in_64 ty) (ushr x y))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (masked_amt Reg (mask_amt_reg ty (amt_reg y)))) + (lshr_reg (ty_ext32 ty) ext_reg masked_amt))) + +;; Shift right logical, immediate shift amount. +;; For types smaller than 32-bit, the input value must be zero-extended. +(rule 1 (lower (has_type (fits_in_64 ty) (ushr x (i64_from_value y)))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (masked_amt u8 (mask_amt_imm ty y))) + (lshr_imm (ty_ext32 ty) ext_reg masked_amt))) + +;; Vector shift right logical, shift amount in register. +(rule 2 (lower (has_type (ty_vec128 ty) (ushr x y))) + (vec_lshr_reg ty x (amt_reg y))) + +;; Vector shift right logical, immediate shift amount. +(rule 3 (lower (has_type (ty_vec128 ty) (ushr x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (vec_lshr_imm ty x masked_amt))) + +;; 128-bit vector shift right logical. +(rule 4 (lower (has_type $I128 (ushr x y))) + (let ((amt Reg (amt_vr y))) + (vec_lshr_by_bit (vec_lshr_by_byte x amt) amt))) + + +;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Shift right arithmetic, shift amount in register. +;; For types smaller than 32-bit, the input value must be sign-extended. +(rule 0 (lower (has_type (fits_in_64 ty) (sshr x y))) + (let ((ext_reg Reg (put_in_reg_sext32 x)) + (masked_amt Reg (mask_amt_reg ty (amt_reg y)))) + (ashr_reg (ty_ext32 ty) ext_reg masked_amt))) + +;; Shift right arithmetic, immediate shift amount. +;; For types smaller than 32-bit, the input value must be sign-extended. +(rule 1 (lower (has_type (fits_in_64 ty) (sshr x (i64_from_value y)))) + (let ((ext_reg Reg (put_in_reg_sext32 x)) + (masked_amt u8 (mask_amt_imm ty y))) + (ashr_imm (ty_ext32 ty) ext_reg masked_amt))) + +;; Vector shift right arithmetic, shift amount in register. +(rule 2 (lower (has_type (ty_vec128 ty) (sshr x y))) + (vec_ashr_reg ty x (amt_reg y))) + +;; Vector shift right arithmetic, immediate shift amount. +(rule 3 (lower (has_type (ty_vec128 ty) (sshr x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (vec_ashr_imm ty x masked_amt))) + +;; 128-bit vector shift right arithmetic. +(rule 4 (lower (has_type $I128 (sshr x y))) + (let ((amt Reg (amt_vr y))) + (vec_ashr_by_bit (vec_ashr_by_byte x amt) amt))) + + +;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Rotate left, shift amount in register. 32-bit or 64-bit types. +(rule 0 (lower (has_type (ty_32_or_64 ty) (rotl x y))) + (rot_reg ty x (amt_reg y))) + +;; Rotate left arithmetic, immediate shift amount. 32-bit or 64-bit types. +(rule 1 (lower (has_type (ty_32_or_64 ty) (rotl x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (rot_imm ty x masked_amt))) + +;; Rotate left, shift amount in register. 8-bit or 16-bit types. +;; Implemented via a pair of 32-bit shifts on the zero-extended input. +(rule 2 (lower (has_type (ty_8_or_16 ty) (rotl x y))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (ext_ty Type (ty_ext32 ty)) + (pos_amt Reg (amt_reg y)) + (neg_amt Reg (neg_reg $I32 pos_amt)) + (masked_pos_amt Reg (mask_amt_reg ty pos_amt)) + (masked_neg_amt Reg (mask_amt_reg ty neg_amt))) + (or_reg ty (lshl_reg ext_ty ext_reg masked_pos_amt) + (lshr_reg ext_ty ext_reg masked_neg_amt)))) + +;; Rotate left, immediate shift amount. 8-bit or 16-bit types. +;; Implemented via a pair of 32-bit shifts on the zero-extended input. +(rule 3 (lower (has_type (ty_8_or_16 ty) (rotl x (and (i64_from_value pos_amt) + (i64_from_negated_value neg_amt))))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (ext_ty Type (ty_ext32 ty)) + (masked_pos_amt u8 (mask_amt_imm ty pos_amt)) + (masked_neg_amt u8 (mask_amt_imm ty neg_amt))) + (or_reg ty (lshl_imm ext_ty ext_reg masked_pos_amt) + (lshr_imm ext_ty ext_reg masked_neg_amt)))) + +;; Vector rotate left, shift amount in register. +(rule 4 (lower (has_type (ty_vec128 ty) (rotl x y))) + (vec_rot_reg ty x (amt_reg y))) + +;; Vector rotate left, immediate shift amount. +(rule 5 (lower (has_type (ty_vec128 ty) (rotl x (i64_from_value y)))) + (let ((masked_amt u8 (mask_amt_imm ty y))) + (vec_rot_imm ty x masked_amt))) + +;; 128-bit full vector rotate left. +;; Implemented via a pair of 128-bit full vector shifts. +(rule 6 (lower (has_type $I128 (rotl x y))) + (let ((x_reg Reg x) + (pos_amt Reg (amt_vr y)) + (neg_amt Reg (vec_neg $I8X16 pos_amt))) + (vec_or $I128 + (vec_lshl_by_bit (vec_lshl_by_byte x_reg pos_amt) pos_amt) + (vec_lshr_by_bit (vec_lshr_by_byte x_reg neg_amt) neg_amt)))) + + +;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Rotate right, shift amount in register. 32-bit or 64-bit types. +;; Implemented as rotate left with negated rotate amount. +(rule 0 (lower (has_type (ty_32_or_64 ty) (rotr x y))) + (let ((negated_amt Reg (neg_reg $I32 (amt_reg y)))) + (rot_reg ty x negated_amt))) + +;; Rotate right arithmetic, immediate shift amount. 32-bit or 64-bit types. +;; Implemented as rotate left with negated rotate amount. +(rule 1 (lower (has_type (ty_32_or_64 ty) (rotr x (i64_from_negated_value y)))) + (let ((negated_amt u8 (mask_amt_imm ty y))) + (rot_imm ty x negated_amt))) + +;; Rotate right, shift amount in register. 8-bit or 16-bit types. +;; Implemented as rotate left with negated rotate amount. +(rule 2 (lower (has_type (ty_8_or_16 ty) (rotr x y))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (ext_ty Type (ty_ext32 ty)) + (pos_amt Reg (amt_reg y)) + (neg_amt Reg (neg_reg $I32 pos_amt)) + (masked_pos_amt Reg (mask_amt_reg ty pos_amt)) + (masked_neg_amt Reg (mask_amt_reg ty neg_amt))) + (or_reg ty (lshl_reg ext_ty ext_reg masked_neg_amt) + (lshr_reg ext_ty ext_reg masked_pos_amt)))) + +;; Rotate right, immediate shift amount. 8-bit or 16-bit types. +;; Implemented as rotate left with negated rotate amount. +(rule 3 (lower (has_type (ty_8_or_16 ty) (rotr x (and (i64_from_value pos_amt) + (i64_from_negated_value neg_amt))))) + (let ((ext_reg Reg (put_in_reg_zext32 x)) + (ext_ty Type (ty_ext32 ty)) + (masked_pos_amt u8 (mask_amt_imm ty pos_amt)) + (masked_neg_amt u8 (mask_amt_imm ty neg_amt))) + (or_reg ty (lshl_imm ext_ty ext_reg masked_neg_amt) + (lshr_imm ext_ty ext_reg masked_pos_amt)))) + +;; Vector rotate right, shift amount in register. +;; Implemented as rotate left with negated rotate amount. +(rule 4 (lower (has_type (ty_vec128 ty) (rotr x y))) + (let ((negated_amt Reg (neg_reg $I32 (amt_reg y)))) + (vec_rot_reg ty x negated_amt))) + +;; Vector rotate right, immediate shift amount. +;; Implemented as rotate left with negated rotate amount. +(rule 5 (lower (has_type (ty_vec128 ty) (rotr x (i64_from_negated_value y)))) + (let ((negated_amt u8 (mask_amt_imm ty y))) + (vec_rot_imm ty x negated_amt))) + +;; 128-bit full vector rotate right. +;; Implemented via a pair of 128-bit full vector shifts. +(rule 6 (lower (has_type $I128 (rotr x y))) + (let ((x_reg Reg x) + (pos_amt Reg (amt_vr y)) + (neg_amt Reg (vec_neg $I8X16 pos_amt))) + (vec_or $I128 + (vec_lshl_by_bit (vec_lshl_by_byte x_reg neg_amt) neg_amt) + (vec_lshr_by_bit (vec_lshr_by_byte x_reg pos_amt) pos_amt)))) + + +;;;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Up to 64-bit source type: Always a no-op. +(rule 1 (lower (ireduce x @ (value_type (fits_in_64 _ty)))) + x) + +;; 128-bit source type: Extract the low half. +(rule (lower (ireduce x @ (value_type (vr128_ty _ty)))) + (vec_extract_lane $I64X2 x 1 (zero_reg))) + + +;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 16- or 32-bit target types. +(rule 1 (lower (has_type (gpr32_ty _ty) (uextend x))) + (put_in_reg_zext32 x)) + +;; 64-bit target types. +(rule 2 (lower (has_type (gpr64_ty _ty) (uextend x))) + (put_in_reg_zext64 x)) + +;; 128-bit target types. +(rule (lower (has_type $I128 (uextend x @ (value_type $I8)))) + (vec_insert_lane $I8X16 (vec_imm $I128 0) x 15 (zero_reg))) +(rule (lower (has_type $I128 (uextend x @ (value_type $I16)))) + (vec_insert_lane $I16X8 (vec_imm $I128 0) x 7 (zero_reg))) +(rule (lower (has_type $I128 (uextend x @ (value_type $I32)))) + (vec_insert_lane $I32X4 (vec_imm $I128 0) x 3 (zero_reg))) +(rule (lower (has_type $I128 (uextend x @ (value_type $I64)))) + (vec_insert_lane $I64X2 (vec_imm $I128 0) x 1 (zero_reg))) + + +;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 16- or 32-bit target types. +(rule 1 (lower (has_type (gpr32_ty _ty) (sextend x))) + (put_in_reg_sext32 x)) + +;; 64-bit target types. +(rule 2 (lower (has_type (gpr64_ty _ty) (sextend x))) + (put_in_reg_sext64 x)) + +;; 128-bit target types. +(rule (lower (has_type $I128 (sextend x))) + (let ((x_ext Reg (put_in_reg_sext64 x))) + (mov_to_vec128 $I128 (ashr_imm $I64 x_ext 63) x_ext))) + + +;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (snarrow x @ (value_type (ty_vec128 ty)) y)) + (vec_pack_ssat_lane_order ty x y)) + + +;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (uunarrow x @ (value_type (ty_vec128 ty)) y)) + (vec_pack_usat_lane_order ty x y)) + + +;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (unarrow x @ (value_type (ty_vec128 ty)) y)) + (let ((zero Reg (vec_imm ty 0))) + (vec_pack_usat_lane_order ty (vec_smax ty x zero) (vec_smax ty y zero)))) + + +;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (swiden_low x @ (value_type (ty_vec128 ty)))) + (vec_unpacks_low_lane_order ty x)) + + +;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (swiden_high x @ (value_type (ty_vec128 ty)))) + (vec_unpacks_high_lane_order ty x)) + + +;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (uwiden_low x @ (value_type (ty_vec128 ty)))) + (vec_unpacku_low_lane_order ty x)) + + +;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (uwiden_high x @ (value_type (ty_vec128 ty)))) + (vec_unpacku_high_lane_order ty x)) + + +;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; z15 version using a single instruction (NOR). +(rule 2 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bnot x))) + (let ((rx Reg x)) + (not_or_reg ty rx rx))) + +;; z14 version using XOR with -1. +(rule 1 (lower (has_type (and (mie2_disabled) (fits_in_64 ty)) (bnot x))) + (not_reg ty x)) + +;; Vector version using vector NOR. +(rule (lower (has_type (vr128_ty ty) (bnot x))) + (vec_not ty x)) + +;; With z15 (bnot (bxor ...)) can be a single instruction, similar to the +;; (bxor _ (bnot _)) lowering. +(rule 3 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bnot (bxor x y)))) + (not_xor_reg ty x y)) + +;; Combine a not/xor operation of vector types into one. +(rule 4 (lower (has_type (vr128_ty ty) (bnot (bxor x y)))) + (vec_not_xor ty x y)) + + +;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; And two registers. +(rule -1 (lower (has_type (fits_in_64 ty) (band x y))) + (and_reg ty x y)) + +;; And a register and an immediate. +(rule 5 (lower (has_type (fits_in_64 ty) (band x (uimm16shifted_from_inverted_value y)))) + (and_uimm16shifted ty x y)) +(rule 6 (lower (has_type (fits_in_64 ty) (band (uimm16shifted_from_inverted_value x) y))) + (and_uimm16shifted ty y x)) +(rule 3 (lower (has_type (fits_in_64 ty) (band x (uimm32shifted_from_inverted_value y)))) + (and_uimm32shifted ty x y)) +(rule 4 (lower (has_type (fits_in_64 ty) (band (uimm32shifted_from_inverted_value x) y))) + (and_uimm32shifted ty y x)) + +;; And a register and memory (32/64-bit types). +(rule 1 (lower (has_type (fits_in_64 ty) (band x (sinkable_load_32_64 y)))) + (and_mem ty x (sink_load y))) +(rule 2 (lower (has_type (fits_in_64 ty) (band (sinkable_load_32_64 x) y))) + (and_mem ty y (sink_load x))) + +;; And two vector registers. +(rule 0 (lower (has_type (vr128_ty ty) (band x y))) + (vec_and ty x y)) + +;; Specialized lowerings for `(band x (bnot y))` which is additionally produced +;; by Cranelift's `band_not` instruction that is legalized into the simpler +;; forms early on. + +;; z15 version using a single instruction. +(rule 7 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (band x (bnot y)))) + (and_not_reg ty x y)) +(rule 8 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (band (bnot y) x))) + (and_not_reg ty x y)) + +;; And-not two vector registers. +(rule 9 (lower (has_type (vr128_ty ty) (band x (bnot y)))) + (vec_and_not ty x y)) +(rule 10 (lower (has_type (vr128_ty ty) (band (bnot y) x))) + (vec_and_not ty x y)) + +;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Or two registers. +(rule -1 (lower (has_type (fits_in_64 ty) (bor x y))) + (or_reg ty x y)) + +;; Or a register and an immediate. +(rule 5 (lower (has_type (fits_in_64 ty) (bor x (uimm16shifted_from_value y)))) + (or_uimm16shifted ty x y)) +(rule 6 (lower (has_type (fits_in_64 ty) (bor (uimm16shifted_from_value x) y))) + (or_uimm16shifted ty y x)) +(rule 3 (lower (has_type (fits_in_64 ty) (bor x (uimm32shifted_from_value y)))) + (or_uimm32shifted ty x y)) +(rule 4 (lower (has_type (fits_in_64 ty) (bor (uimm32shifted_from_value x) y))) + (or_uimm32shifted ty y x)) + +;; Or a register and memory (32/64-bit types). +(rule 1 (lower (has_type (fits_in_64 ty) (bor x (sinkable_load_32_64 y)))) + (or_mem ty x (sink_load y))) +(rule 2 (lower (has_type (fits_in_64 ty) (bor (sinkable_load_32_64 x) y))) + (or_mem ty y (sink_load x))) + +;; Or two vector registers. +(rule 0 (lower (has_type (vr128_ty ty) (bor x y))) + (vec_or ty x y)) + +;; Specialized lowerings for `(bor x (bnot y))` which is additionally produced +;; by Cranelift's `bor_not` instruction that is legalized into the simpler +;; forms early on. + +;; z15 version using a single instruction. +(rule 7 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bor x (bnot y)))) + (or_not_reg ty x y)) +(rule 8 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bor (bnot y) x))) + (or_not_reg ty x y)) + +;; Or-not two vector registers. +(rule 9 (lower (has_type (vr128_ty ty) (bor x (bnot y)))) + (vec_or_not ty x y)) +(rule 10 (lower (has_type (vr128_ty ty) (bor (bnot y) x))) + (vec_or_not ty x y)) + + +;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Xor two registers. +(rule -1 (lower (has_type (fits_in_64 ty) (bxor x y))) + (xor_reg ty x y)) + +;; Xor a register and an immediate. +(rule 3 (lower (has_type (fits_in_64 ty) (bxor x (uimm32shifted_from_value y)))) + (xor_uimm32shifted ty x y)) +(rule 4 (lower (has_type (fits_in_64 ty) (bxor (uimm32shifted_from_value x) y))) + (xor_uimm32shifted ty y x)) + +;; Xor a register and memory (32/64-bit types). +(rule 1 (lower (has_type (fits_in_64 ty) (bxor x (sinkable_load_32_64 y)))) + (xor_mem ty x (sink_load y))) +(rule 2 (lower (has_type (fits_in_64 ty) (bxor (sinkable_load_32_64 x) y))) + (xor_mem ty y (sink_load x))) + +;; Xor two vector registers. +(rule 0 (lower (has_type (vr128_ty ty) (bxor x y))) + (vec_xor ty x y)) + +;; Specialized lowerings for `(bxor x (bnot y))` which is additionally produced +;; by Cranelift's `bxor_not` instruction that is legalized into the simpler +;; forms early on. + +;; z15 version using a single instruction. +(rule 5 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bxor x (bnot y)))) + (not_xor_reg ty x y)) +(rule 6 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bxor (bnot y) x))) + (not_xor_reg ty x y)) + +;; Xor-not two vector registers. +(rule 7 (lower (has_type (vr128_ty ty) (bxor x (bnot y)))) + (vec_not_xor ty x y)) +(rule 8 (lower (has_type (vr128_ty ty) (bxor (bnot y) x))) + (vec_not_xor ty x y)) + + +;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; z15 version using a NAND instruction. +(rule 2 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (bitselect x y z))) + (let ((rx Reg x) + (if_true Reg (and_reg ty y rx)) + (if_false Reg (and_not_reg ty z rx))) + (or_reg ty if_false if_true))) + +;; z14 version using XOR with -1. +(rule 1 (lower (has_type (and (mie2_disabled) (fits_in_64 ty)) (bitselect x y z))) + (let ((rx Reg x) + (if_true Reg (and_reg ty y rx)) + (if_false Reg (and_reg ty z (not_reg ty rx)))) + (or_reg ty if_false if_true))) + +;; Bitselect vector registers. +(rule (lower (has_type (vr128_ty ty) (bitselect x y z))) + (vec_select ty y z x)) + +;; Special-case some float-selection instructions for min/max +(rule 3 (lower (has_type (ty_vec128 ty) (bitselect (bitcast _ (fcmp (FloatCC.LessThan) x y)) x y))) + (fmin_pseudo_reg ty y x)) +(rule 4 (lower (has_type (ty_vec128 ty) (bitselect (bitcast _ (fcmp (FloatCC.LessThan) y x)) x y))) + (fmax_pseudo_reg ty y x)) + + + +;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (bmask x))) + (lower_bool_to_mask ty (value_nonzero x))) + + +;;;; Rules for `bitrev` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (bitrev x))) + (bitrev_bytes ty + (bitrev_bits 4 0xf0f0_f0f0_f0f0_f0f0 ty + (bitrev_bits 2 0xcccc_cccc_cccc_cccc ty + (bitrev_bits 1 0xaaaa_aaaa_aaaa_aaaa ty x))))) + +(decl bitrev_bits (u8 u64 Type Reg) Reg) +(rule 1 (bitrev_bits size bitmask (fits_in_64 ty) x) + (let ((mask Reg (imm ty bitmask)) + (xh Reg (lshl_imm (ty_ext32 ty) x size)) + (xl Reg (lshr_imm (ty_ext32 ty) x size)) + (xh_masked Reg (and_reg ty xh mask)) + (xl_masked Reg (and_reg ty xl (not_reg ty mask)))) + (or_reg ty xh_masked xl_masked))) + +(rule (bitrev_bits size bitmask (vr128_ty ty) x) + (let ((mask Reg (vec_imm_splat $I64X2 bitmask)) + (size_reg Reg (vec_imm_splat $I8X16 (u8_as_u64 size))) + (xh Reg (vec_lshl_by_bit x size_reg)) + (xl Reg (vec_lshr_by_bit x size_reg))) + (vec_select ty xh xl mask))) + +(decl bitrev_bytes (Type Reg) Reg) +(rule (bitrev_bytes $I8 x) x) +(rule (bitrev_bytes $I16 x) (lshr_imm $I32 (bswap_reg $I32 x) 16)) +(rule (bitrev_bytes $I32 x) (bswap_reg $I32 x)) +(rule (bitrev_bytes $I64 x) (bswap_reg $I64 x)) +(rule (bitrev_bytes $I128 x) + (vec_permute $I128 x x + (vec_imm $I8X16 (imm8x16 15 14 13 12 11 10 9 8 + 7 6 5 4 3 2 1 0)))) + + +;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (bswap x))) + (bitrev_bytes ty x)) + +;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The FLOGR hardware instruction always operates on the full 64-bit register. +;; We can zero-extend smaller types, but then we have to compensate for the +;; additional leading zero bits the instruction will actually see. +(decl clz_offset (Type Reg) Reg) +(rule (clz_offset $I8 x) (add_simm16 $I8 x -56)) +(rule (clz_offset $I16 x) (add_simm16 $I16 x -48)) +(rule (clz_offset $I32 x) (add_simm16 $I32 x -32)) +(rule (clz_offset $I64 x) x) + +;; Count leading zeros, via FLOGR on an input zero-extended to 64 bits, +;; with the result compensated for the extra bits. +(rule 1 (lower (has_type (fits_in_64 ty) (clz x))) + (let ((ext_reg Reg (put_in_reg_zext64 x)) + ;; Ask for a value of 64 in the all-zero 64-bit input case. + ;; After compensation this will match the expected semantics. + (clz Reg (clz_reg 64 ext_reg))) + (clz_offset ty clz))) + +;; Count leading zeros, 128-bit full vector. +(rule (lower (has_type $I128 (clz x))) + (let ((clz_vec Reg (vec_clz $I64X2 x)) + (zero Reg (vec_imm $I64X2 0)) + (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0)) + (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1)) + (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo)) + (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64)))) + (vec_select $I128 clz_sum clz_hi mask))) + + +;;;; Rules for `cls` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The result of cls is not supposed to count the sign bit itself, just +;; additional copies of it. Therefore, when computing cls in terms of clz, +;; we need to subtract one. Fold this into the offset computation. +(decl cls_offset (Type Reg) Reg) +(rule (cls_offset $I8 x) (add_simm16 $I8 x -57)) +(rule (cls_offset $I16 x) (add_simm16 $I16 x -49)) +(rule (cls_offset $I32 x) (add_simm16 $I32 x -33)) +(rule (cls_offset $I64 x) (add_simm16 $I64 x -1)) + +;; Count leading sign-bit copies. We don't have any instruction for that, +;; so we instead count the leading zeros after inverting the input if negative, +;; i.e. computing +;; cls(x) == clz(x ^ (x >> 63)) - 1 +;; where x is the sign-extended input. +(rule 1 (lower (has_type (fits_in_64 ty) (cls x))) + (let ((ext_reg Reg (put_in_reg_sext64 x)) + (signbit_copies Reg (ashr_imm $I64 ext_reg 63)) + (inv_reg Reg (xor_reg $I64 ext_reg signbit_copies)) + (clz Reg (clz_reg 64 inv_reg))) + (cls_offset ty clz))) + +;; Count leading sign-bit copies, 128-bit full vector. +(rule (lower (has_type $I128 (cls x))) + (let ((x_reg Reg x) + (ones Reg (vec_imm_splat $I8X16 255)) + (signbit_copies Reg (vec_ashr_by_bit (vec_ashr_by_byte x_reg ones) ones)) + (inv_reg Reg (vec_xor $I128 x_reg signbit_copies)) + (clz_vec Reg (vec_clz $I64X2 inv_reg)) + (zero Reg (vec_imm $I64X2 0)) + (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0)) + (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1)) + (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo)) + (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64)))) + (vec_add $I128 (vec_select $I128 clz_sum clz_hi mask) ones))) + + +;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; To count trailing zeros, we find the last bit set in the input via (x & -x), +;; count the leading zeros of that value, and subtract from 63: +;; +;; ctz(x) == 63 - clz(x & -x) +;; +;; This works for all cases except a zero input, where the above formula would +;; return -1, but we are expected to return the type size. The compensation +;; for this case is handled differently for 64-bit types vs. smaller types. + +;; For smaller types, we simply ensure that the extended 64-bit input is +;; never zero by setting a "guard bit" in the position corresponding to +;; the input type size. This way the 64-bit algorithm above will handle +;; that case correctly automatically. +(rule 2 (lower (has_type (gpr32_ty ty) (ctz x))) + (let ((rx Reg (or_uimm16shifted $I64 x (ctz_guardbit ty))) + (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx))) + (clz Reg (clz_reg 64 lastbit))) + (sub_reg ty (imm ty 63) clz))) + +(decl ctz_guardbit (Type) UImm16Shifted) +(rule (ctz_guardbit $I8) (uimm16shifted 256 0)) +(rule (ctz_guardbit $I16) (uimm16shifted 1 16)) +(rule (ctz_guardbit $I32) (uimm16shifted 1 32)) + +;; For 64-bit types, the FLOGR instruction will indicate the zero input case +;; via its condition code. We check for that and replace the instruction +;; result with the value -1 via a conditional move, which will then lead to +;; the correct result after the final subtraction from 63. +(rule 1 (lower (has_type (gpr64_ty _ty) (ctz x))) + (let ((rx Reg x) + (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx))) + (clz Reg (clz_reg -1 lastbit))) + (sub_reg $I64 (imm $I64 63) clz))) + +;; Count trailing zeros, 128-bit full vector. +(rule 0 (lower (has_type $I128 (ctz x))) + (let ((ctz_vec Reg (vec_ctz $I64X2 x)) + (zero Reg (vec_imm $I64X2 0)) + (ctz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 0)) + (ctz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 1)) + (ctz_sum Reg (vec_add $I64X2 ctz_hi ctz_lo)) + (mask Reg (vec_cmpeq $I64X2 ctz_lo (vec_imm_splat $I64X2 64)))) + (vec_select $I128 ctz_sum ctz_lo mask))) + + +;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Population count for 8-bit types is supported by the POPCNT instruction. +(rule (lower (has_type $I8 (popcnt x))) + (popcnt_byte x)) + +;; On z15, the POPCNT instruction has a variant to compute a full 64-bit +;; population count, which we also use for 16- and 32-bit types. +(rule -1 (lower (has_type (and (mie2_enabled) (fits_in_64 ty)) (popcnt x))) + (popcnt_reg (put_in_reg_zext64 x))) + +;; On z14, we use the regular POPCNT, which computes the population count +;; of each input byte separately, so we need to accumulate those partial +;; results via a series of log2(type size in bytes) - 1 additions. We +;; accumulate in the high byte, so that a final right shift will zero out +;; any unrelated bits to give a clean result. (This does not work with +;; $I16, where we instead accumulate in the low byte and clear high bits +;; via an explicit and operation.) + +(rule (lower (has_type (and (mie2_disabled) $I16) (popcnt x))) + (let ((cnt2 Reg (popcnt_byte x)) + (cnt1 Reg (add_reg $I32 cnt2 (lshr_imm $I32 cnt2 8)))) + (and_uimm16shifted $I32 cnt1 (uimm16shifted 255 0)))) + +(rule (lower (has_type (and (mie2_disabled) $I32) (popcnt x))) + (let ((cnt4 Reg (popcnt_byte x)) + (cnt2 Reg (add_reg $I32 cnt4 (lshl_imm $I32 cnt4 16))) + (cnt1 Reg (add_reg $I32 cnt2 (lshl_imm $I32 cnt2 8)))) + (lshr_imm $I32 cnt1 24))) + +(rule (lower (has_type (and (mie2_disabled) $I64) (popcnt x))) + (let ((cnt8 Reg (popcnt_byte x)) + (cnt4 Reg (add_reg $I64 cnt8 (lshl_imm $I64 cnt8 32))) + (cnt2 Reg (add_reg $I64 cnt4 (lshl_imm $I64 cnt4 16))) + (cnt1 Reg (add_reg $I64 cnt2 (lshl_imm $I64 cnt2 8)))) + (lshr_imm $I64 cnt1 56))) + +;; Population count for vector types. +(rule 1 (lower (has_type (ty_vec128 ty) (popcnt x))) + (vec_popcnt ty x)) + +;; Population count, 128-bit full vector. +(rule (lower (has_type $I128 (popcnt x))) + (let ((popcnt_vec Reg (vec_popcnt $I64X2 x)) + (zero Reg (vec_imm $I64X2 0)) + (popcnt_hi Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 0)) + (popcnt_lo Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 1))) + (vec_add $I64X2 popcnt_hi popcnt_lo))) + + +;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add two registers. +(rule (lower (has_type ty (fadd x y))) + (fadd_reg ty x y)) + + +;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Subtract two registers. +(rule (lower (has_type ty (fsub x y))) + (fsub_reg ty x y)) + + +;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Multiply two registers. +(rule (lower (has_type ty (fmul x y))) + (fmul_reg ty x y)) + + +;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Divide two registers. +(rule (lower (has_type ty (fdiv x y))) + (fdiv_reg ty x y)) + + +;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Minimum of two registers. +(rule (lower (has_type ty (fmin x y))) + (fmin_reg ty x y)) + + +;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Maximum of two registers. +(rule (lower (has_type ty (fmax x y))) + (fmax_reg ty x y)) + + +;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Copysign of two registers. +(rule (lower (has_type $F32 (fcopysign x y))) + (vec_select $F32 x y (imm $F32 2147483647))) +(rule (lower (has_type $F64 (fcopysign x y))) + (vec_select $F64 x y (imm $F64 9223372036854775807))) +(rule (lower (has_type $F32X4 (fcopysign x y))) + (vec_select $F32X4 x y (vec_imm_bit_mask $F32X4 1 31))) +(rule (lower (has_type $F64X2 (fcopysign x y))) + (vec_select $F64X2 x y (vec_imm_bit_mask $F64X2 1 63))) + + +;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Multiply-and-add of three registers. +(rule (lower (has_type ty (fma x y z))) + (fma_reg ty x y z)) + + +;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Square root of a register. +(rule (lower (has_type ty (sqrt x))) + (sqrt_reg ty x)) + + +;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Negated value of a register. +(rule (lower (has_type ty (fneg x))) + (fneg_reg ty x)) + + +;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Absolute value of a register. +(rule (lower (has_type ty (fabs x))) + (fabs_reg ty x)) + + +;;;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Round value in a register towards positive infinity. +(rule (lower (has_type ty (ceil x))) + (ceil_reg ty x)) + + +;;;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Round value in a register towards negative infinity. +(rule (lower (has_type ty (floor x))) + (floor_reg ty x)) + + +;;;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Round value in a register towards zero. +(rule (lower (has_type ty (trunc x))) + (trunc_reg ty x)) + + +;;;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Round value in a register towards nearest. +(rule (lower (has_type ty (nearest x))) + (nearest_reg ty x)) + + +;;;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Promote a register. +(rule (lower (has_type (fits_in_64 dst_ty) (fpromote x @ (value_type src_ty)))) + (fpromote_reg dst_ty src_ty x)) + + +;;;; Rules for `fvpromote_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Promote a register. +(rule (lower (has_type $F64X2 (fvpromote_low x @ (value_type $F32X4)))) + (fpromote_reg $F64X2 $F32X4 (vec_merge_low_lane_order $I32X4 x x))) + + +;;;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Demote a register. +(rule (lower (has_type (fits_in_64 dst_ty) (fdemote x @ (value_type src_ty)))) + (fdemote_reg dst_ty src_ty (FpuRoundMode.Current) x)) + + +;;;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Demote a register. +(rule (lower (has_type $F32X4 (fvdemote x @ (value_type $F64X2)))) + (let ((dst Reg (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.Current) x))) + (vec_pack_lane_order $I64X2 (vec_lshr_imm $I64X2 dst 32) + (vec_imm $I64X2 0)))) + + +;;;; Rules for `fcvt_from_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a 32-bit or smaller unsigned integer to $F32 (z15 instruction). +(rule 1 (lower (has_type $F32 + (fcvt_from_uint x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty)))))) + (fcvt_from_uint_reg $F32 (FpuRoundMode.ToNearestTiesToEven) + (put_in_reg_zext32 x))) + +;; Convert a 64-bit or smaller unsigned integer to $F32, via an intermediate $F64. +(rule (lower (has_type $F32 (fcvt_from_uint x @ (value_type (fits_in_64 ty))))) + (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_uint_reg $F64 (FpuRoundMode.ShorterPrecision) + (put_in_reg_zext64 x)))) + +;; Convert a 64-bit or smaller unsigned integer to $F64. +(rule (lower (has_type $F64 (fcvt_from_uint x @ (value_type (fits_in_64 ty))))) + (fcvt_from_uint_reg $F64 (FpuRoundMode.ToNearestTiesToEven) + (put_in_reg_zext64 x))) + +;; Convert $I32X4 to $F32X4 (z15 instruction). +(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4) + (fcvt_from_uint x @ (value_type $I32X4)))) + (fcvt_from_uint_reg $F32X4 (FpuRoundMode.ToNearestTiesToEven) x)) + +;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14). +(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4) + (fcvt_from_uint x @ (value_type $I32X4)))) + (vec_permute $F32X4 + (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_uint_reg $F64X2 (FpuRoundMode.ShorterPrecision) + (vec_unpacku_high $I32X4 x))) + (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_uint_reg $F64X2 (FpuRoundMode.ShorterPrecision) + (vec_unpacku_low $I32X4 x))) + (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27)))) + +;; Convert $I64X2 to $F64X2. +(rule (lower (has_type $F64X2 (fcvt_from_uint x @ (value_type $I64X2)))) + (fcvt_from_uint_reg $F64X2 (FpuRoundMode.ToNearestTiesToEven) x)) + + +;;;; Rules for `fcvt_from_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a 32-bit or smaller signed integer to $F32 (z15 instruction). +(rule 1 (lower (has_type $F32 + (fcvt_from_sint x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty)))))) + (fcvt_from_sint_reg $F32 (FpuRoundMode.ToNearestTiesToEven) + (put_in_reg_sext32 x))) + +;; Convert a 64-bit or smaller signed integer to $F32, via an intermediate $F64. +(rule (lower (has_type $F32 (fcvt_from_sint x @ (value_type (fits_in_64 ty))))) + (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_sint_reg $F64 (FpuRoundMode.ShorterPrecision) + (put_in_reg_sext64 x)))) + +;; Convert a 64-bit or smaller signed integer to $F64. +(rule (lower (has_type $F64 (fcvt_from_sint x @ (value_type (fits_in_64 ty))))) + (fcvt_from_sint_reg $F64 (FpuRoundMode.ToNearestTiesToEven) + (put_in_reg_sext64 x))) + +;; Convert $I32X4 to $F32X4 (z15 instruction). +(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4) + (fcvt_from_sint x @ (value_type $I32X4)))) + (fcvt_from_sint_reg $F32X4 (FpuRoundMode.ToNearestTiesToEven) x)) + +;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14). +(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4) + (fcvt_from_sint x @ (value_type $I32X4)))) + (vec_permute $F32X4 + (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_sint_reg $F64X2 (FpuRoundMode.ShorterPrecision) + (vec_unpacks_high $I32X4 x))) + (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) + (fcvt_from_sint_reg $F64X2 (FpuRoundMode.ShorterPrecision) + (vec_unpacks_low $I32X4 x))) + (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27)))) + +;; Convert $I64X2 to $F64X2. +(rule (lower (has_type $F64X2 (fcvt_from_sint x @ (value_type $I64X2)))) + (fcvt_from_sint_reg $F64X2 (FpuRoundMode.ToNearestTiesToEven) x)) + + +;;;; Rules for `fcvt_to_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a scalar floating-point value in a register to an unsigned integer. +;; Traps if the input cannot be represented in the output type. +(rule (lower (has_type (fits_in_64 dst_ty) + (fcvt_to_uint x @ (value_type src_ty)))) + (let ((src Reg (put_in_reg x)) + ;; First, check whether the input is a NaN, and trap if so. + (_ Reg (trap_if (fcmp_reg src_ty src src) + (floatcc_as_cond (FloatCC.Unordered)) + (trap_code_bad_conversion_to_integer))) + ;; Now check whether the input is out of range for the target type. + (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_ub src_ty dst_ty)) + (floatcc_as_cond (FloatCC.GreaterThanOrEqual)) + (trap_code_integer_overflow))) + (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_lb src_ty)) + (floatcc_as_cond (FloatCC.LessThanOrEqual)) + (trap_code_integer_overflow))) + ;; Perform the conversion using the larger type size. + (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) + (src_ext Reg (fpromote_reg flt_ty src_ty src))) + (fcvt_to_uint_reg flt_ty (FpuRoundMode.ToZero) src_ext))) + + +;;;; Rules for `fcvt_to_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a scalar floating-point value in a register to a signed integer. +;; Traps if the input cannot be represented in the output type. +(rule (lower (has_type (fits_in_64 dst_ty) + (fcvt_to_sint x @ (value_type src_ty)))) + (let ((src Reg (put_in_reg x)) + ;; First, check whether the input is a NaN, and trap if so. + (_ Reg (trap_if (fcmp_reg src_ty src src) + (floatcc_as_cond (FloatCC.Unordered)) + (trap_code_bad_conversion_to_integer))) + ;; Now check whether the input is out of range for the target type. + (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_ub src_ty dst_ty)) + (floatcc_as_cond (FloatCC.GreaterThanOrEqual)) + (trap_code_integer_overflow))) + (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_lb src_ty dst_ty)) + (floatcc_as_cond (FloatCC.LessThanOrEqual)) + (trap_code_integer_overflow))) + ;; Perform the conversion using the larger type size. + (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) + (src_ext Reg (fpromote_reg flt_ty src_ty src))) + ;; Perform the conversion. + (fcvt_to_sint_reg flt_ty (FpuRoundMode.ToZero) src_ext))) + + +;;;; Rules for `fcvt_to_uint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a scalar floating-point value in a register to an unsigned integer. +(rule -1 (lower (has_type (fits_in_64 dst_ty) + (fcvt_to_uint_sat x @ (value_type src_ty)))) + (let ((src Reg (put_in_reg x)) + ;; Perform the conversion using the larger type size. + (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) + (int_ty Type (fcvt_int_ty dst_ty src_ty)) + (src_ext Reg (fpromote_reg flt_ty src_ty src)) + (dst Reg (fcvt_to_uint_reg flt_ty (FpuRoundMode.ToZero) src_ext))) + ;; Clamp the output to the destination type bounds. + (uint_sat_reg dst_ty int_ty dst))) + +;; Convert $F32X4 to $I32X4 (z15 instruction). +(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4) + (fcvt_to_uint_sat x @ (value_type $F32X4)))) + (fcvt_to_uint_reg $F32X4 (FpuRoundMode.ToZero) x)) + +;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14). +(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4) + (fcvt_to_uint_sat x @ (value_type $F32X4)))) + (vec_pack_usat $I64X2 + (fcvt_to_uint_reg $F64X2 (FpuRoundMode.ToZero) + (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 x x))) + (fcvt_to_uint_reg $F64X2 (FpuRoundMode.ToZero) + (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 x x))))) + +;; Convert $F64X2 to $I64X2. +(rule (lower (has_type $I64X2 (fcvt_to_uint_sat x @ (value_type $F64X2)))) + (fcvt_to_uint_reg $F64X2 (FpuRoundMode.ToZero) x)) + + +;;;; Rules for `fcvt_to_sint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert a scalar floating-point value in a register to a signed integer. +(rule -1 (lower (has_type (fits_in_64 dst_ty) + (fcvt_to_sint_sat x @ (value_type src_ty)))) + (let ((src Reg (put_in_reg x)) + ;; Perform the conversion using the larger type size. + (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) + (int_ty Type (fcvt_int_ty dst_ty src_ty)) + (src_ext Reg (fpromote_reg flt_ty src_ty src)) + (dst Reg (fcvt_to_sint_reg flt_ty (FpuRoundMode.ToZero) src_ext)) + ;; In most special cases, the Z instruction already yields the + ;; result expected by Cranelift semantics. The only exception + ;; it the case where the input was a NaN. We explicitly check + ;; for that and force the output to 0 in that case. + (sat Reg (with_flags_reg (fcmp_reg src_ty src src) + (cmov_imm int_ty + (floatcc_as_cond (FloatCC.Unordered)) 0 dst)))) + ;; Clamp the output to the destination type bounds. + (sint_sat_reg dst_ty int_ty sat))) + +;; Convert $F32X4 to $I32X4 (z15 instruction). +(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4) + (fcvt_to_sint_sat src @ (value_type $F32X4)))) + ;; See above for why we need to handle NaNs specially. + (vec_select $I32X4 + (fcvt_to_sint_reg $F32X4 (FpuRoundMode.ToZero) src) + (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src))) + +;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14). +(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4) + (fcvt_to_sint_sat src @ (value_type $F32X4)))) + ;; See above for why we need to handle NaNs specially. + (vec_select $I32X4 + (vec_pack_ssat $I64X2 + (fcvt_to_sint_reg $F64X2 (FpuRoundMode.ToZero) + (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 src src))) + (fcvt_to_sint_reg $F64X2 (FpuRoundMode.ToZero) + (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 src src)))) + (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src))) + +;; Convert $F64X2 to $I64X2. +(rule (lower (has_type $I64X2 (fcvt_to_sint_sat src @ (value_type $F64X2)))) + ;; See above for why we need to handle NaNs specially. + (vec_select $I64X2 + (fcvt_to_sint_reg $F64X2 (FpuRoundMode.ToZero) src) + (vec_imm $I64X2 0) (vec_fcmpeq $F64X2 src src))) + + +;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Reinterpret a 64-bit integer value as floating-point. +(rule (lower (has_type $F64 (bitcast _ x @ (value_type $I64)))) + (vec_insert_lane_undef $F64X2 x 0 (zero_reg))) + +;; Reinterpret a 64-bit floating-point value as integer. +(rule (lower (has_type $I64 (bitcast _ x @ (value_type $F64)))) + (vec_extract_lane $F64X2 x 0 (zero_reg))) + +;; Reinterpret a 32-bit integer value as floating-point. +(rule (lower (has_type $F32 (bitcast _ x @ (value_type $I32)))) + (vec_insert_lane_undef $F32X4 x 0 (zero_reg))) + +;; Reinterpret a 32-bit floating-point value as integer. +(rule (lower (has_type $I32 (bitcast _ x @ (value_type $F32)))) + (vec_extract_lane $F32X4 x 0 (zero_reg))) + +;; Bitcast between types residing in GPRs is a no-op. +(rule 1 (lower (has_type (gpr32_ty _) + (bitcast _ x @ (value_type (gpr32_ty _))))) + x) +(rule 2 (lower (has_type (gpr64_ty _) + (bitcast _ x @ (value_type (gpr64_ty _))))) + x) + +;; Bitcast between types residing in FPRs is a no-op. +(rule 3 (lower (has_type (ty_scalar_float _) + (bitcast _ x @ (value_type (ty_scalar_float _))))) + x) + +;; Bitcast between types residing in VRs is a no-op if lane count is unchanged. +(rule 5 (lower (has_type (multi_lane bits count) + (bitcast _ x @ (value_type (multi_lane bits count))))) + x) + +;; Bitcast between types residing in VRs with different lane counts is a +;; no-op if the operation's MemFlags indicate a byte order compatible with +;; the current lane order. Otherwise, lane elements need to be swapped, +;; first in the input type, and then again in the output type. This could +;; be optimized further, but we don't bother at the moment since due to our +;; choice of lane order depending on the current function ABI, this case will +;; currently never arise in practice. +(rule 4 (lower (has_type (vr128_ty out_ty) + (bitcast flags x @ (value_type (vr128_ty in_ty))))) + (abi_vec_elt_rev (lane_order_from_memflags flags) out_ty + (abi_vec_elt_rev (lane_order_from_memflags flags) in_ty x))) + + +;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Insert vector lane from general-purpose register. +(rule 1 (lower (insertlane x @ (value_type ty) + y @ (value_type in_ty) + (u8_from_uimm8 idx))) + (if (ty_int_ref_scalar_64 in_ty)) + (vec_insert_lane ty x y (be_lane_idx ty idx) (zero_reg))) + +;; Insert vector lane from floating-point register. +(rule 0 (lower (insertlane x @ (value_type ty) + y @ (value_type (ty_scalar_float _)) + (u8_from_uimm8 idx))) + (vec_move_lane_and_insert ty x (be_lane_idx ty idx) y 0)) + +;; Insert vector lane from another vector lane. +(rule 2 (lower (insertlane x @ (value_type ty) + (extractlane y (u8_from_uimm8 src_idx)) + (u8_from_uimm8 dst_idx))) + (vec_move_lane_and_insert ty x (be_lane_idx ty dst_idx) + y (be_lane_idx ty src_idx))) + +;; Insert vector lane from signed 16-bit immediate. +(rule 3 (lower (insertlane x @ (value_type ty) (i16_from_value y) + (u8_from_uimm8 idx))) + (vec_insert_lane_imm ty x y (be_lane_idx ty idx))) + +;; Insert vector lane from big-endian memory. +(rule 4 (lower (insertlane x @ (value_type ty) (sinkable_load y) + (u8_from_uimm8 idx))) + (vec_load_lane ty x (sink_load y) (be_lane_idx ty idx))) + +;; Insert vector lane from little-endian memory. +(rule 5 (lower (insertlane x @ (value_type ty) (sinkable_load_little y) + (u8_from_uimm8 idx))) + (vec_load_lane_little ty x (sink_load y) (be_lane_idx ty idx))) + + +;; Helper to extract one lane from a vector and insert it into another. +(decl vec_move_lane_and_insert (Type Reg u8 Reg u8) Reg) + +;; For 64-bit elements we always use VPDI. +(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 0 src src_idx) + (vec_permute_dw_imm ty src src_idx dst 1)) +(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 1 src src_idx) + (vec_permute_dw_imm ty dst 0 src src_idx)) + +;; If source and destination index are the same, use vec_select. +(rule -1 (vec_move_lane_and_insert ty dst idx src idx) + (vec_select ty src + dst (vec_imm_byte_mask ty (lane_byte_mask ty idx)))) + +;; Otherwise replicate source first and then use vec_select. +(rule -2 (vec_move_lane_and_insert ty dst dst_idx src src_idx) + (vec_select ty (vec_replicate_lane ty src src_idx) + dst (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx)))) + + +;; Helper to implement a generic little-endian variant of vec_load_lane. +(decl vec_load_lane_little (Type Reg MemArg u8) Reg) + +;; 8-byte little-endian loads can be performed via a normal load. +(rule (vec_load_lane_little ty @ (multi_lane 8 _) dst addr lane_imm) + (vec_load_lane ty dst addr lane_imm)) + +;; On z15, we have instructions to perform little-endian loads. +(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 16 _)) dst addr lane_imm) + (vec_load_lane_rev ty dst addr lane_imm)) +(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 32 _)) dst addr lane_imm) + (vec_load_lane_rev ty dst addr lane_imm)) +(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 64 _)) dst addr lane_imm) + (vec_load_lane_rev ty dst addr lane_imm)) + +;; On z14, use a little-endian load to GPR followed by vec_insert_lane. +(rule (vec_load_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 16 _)) dst addr lane_imm) + (vec_insert_lane ty dst (loadrev16 addr) lane_imm (zero_reg))) +(rule (vec_load_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 32 _)) dst addr lane_imm) + (vec_insert_lane ty dst (loadrev32 addr) lane_imm (zero_reg))) +(rule (vec_load_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 64 _)) dst addr lane_imm) + (vec_insert_lane ty dst (loadrev64 addr) lane_imm (zero_reg))) + +;; Helper to implement a generic little-endian variant of vec_load_lane_undef. +(decl vec_load_lane_little_undef (Type MemArg u8) Reg) + +;; 8-byte little-endian loads can be performed via a normal load. +(rule (vec_load_lane_little_undef ty @ (multi_lane 8 _) addr lane_imm) + (vec_load_lane_undef ty addr lane_imm)) + +;; On z15, we have instructions to perform little-endian loads. +(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) + ty @ (multi_lane 16 _)) addr lane_imm) + (vec_load_lane_rev_undef ty addr lane_imm)) +(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) + ty @ (multi_lane 32 _)) addr lane_imm) + (vec_load_lane_rev_undef ty addr lane_imm)) +(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) + ty @ (multi_lane 64 _)) addr lane_imm) + (vec_load_lane_rev_undef ty addr lane_imm)) + +;; On z14, use a little-endian load to GPR followed by vec_insert_lane_undef. +(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) + ty @ (multi_lane 16 _)) addr lane_imm) + (vec_insert_lane_undef ty (loadrev16 addr) lane_imm (zero_reg))) +(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) + ty @ (multi_lane 32 _)) addr lane_imm) + (vec_insert_lane_undef ty (loadrev32 addr) lane_imm (zero_reg))) +(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) + ty @ (multi_lane 64 _)) addr lane_imm) + (vec_insert_lane_undef ty (loadrev64 addr) lane_imm (zero_reg))) + + +;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extract vector lane to general-purpose register. +(rule 1 (lower (has_type out_ty + (extractlane x @ (value_type ty) (u8_from_uimm8 idx)))) + (if (ty_int_ref_scalar_64 out_ty)) + (vec_extract_lane ty x (be_lane_idx ty idx) (zero_reg))) + +;; Extract vector lane to floating-point register. +(rule 0 (lower (has_type (ty_scalar_float _) + (extractlane x @ (value_type ty) (u8_from_uimm8 idx)))) + (vec_replicate_lane ty x (be_lane_idx ty idx))) + +;; Extract vector lane and store to big-endian memory. +(rule 6 (lower (store flags @ (bigendian) + (extractlane x @ (value_type ty) (u8_from_uimm8 idx)) + addr offset)) + (side_effect (vec_store_lane ty x + (lower_address flags addr offset) (be_lane_idx ty idx)))) + +;; Extract vector lane and store to little-endian memory. +(rule 5 (lower (store flags @ (littleendian) + (extractlane x @ (value_type ty) (u8_from_uimm8 idx)) + addr offset)) + (side_effect (vec_store_lane_little ty x + (lower_address flags addr offset) (be_lane_idx ty idx)))) + + +;; Helper to implement a generic little-endian variant of vec_store_lane. +(decl vec_store_lane_little (Type Reg MemArg u8) SideEffectNoResult) + +;; 8-byte little-endian stores can be performed via a normal store. +(rule (vec_store_lane_little ty @ (multi_lane 8 _) src addr lane_imm) + (vec_store_lane ty src addr lane_imm)) + +;; On z15, we have instructions to perform little-endian stores. +(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 16 _)) src addr lane_imm) + (vec_store_lane_rev ty src addr lane_imm)) +(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 32 _)) src addr lane_imm) + (vec_store_lane_rev ty src addr lane_imm)) +(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 64 _)) src addr lane_imm) + (vec_store_lane_rev ty src addr lane_imm)) + +;; On z14, use vec_extract_lane followed by a little-endian store from GPR. +(rule (vec_store_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 16 _)) src addr lane_imm) + (storerev16 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) +(rule (vec_store_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 32 _)) src addr lane_imm) + (storerev32 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) +(rule (vec_store_lane_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 64 _)) src addr lane_imm) + (storerev64 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) + + +;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load replicated value from general-purpose register. +(rule 1 (lower (has_type ty (splat x @ (value_type in_ty)))) + (if (ty_int_ref_scalar_64 in_ty)) + (vec_replicate_lane ty (vec_insert_lane_undef ty x 0 (zero_reg)) 0)) + +;; Load replicated value from floating-point register. +(rule 0 (lower (has_type ty (splat + x @ (value_type (ty_scalar_float _))))) + (vec_replicate_lane ty x 0)) + +;; Load replicated value from vector lane. +(rule 2 (lower (has_type ty (splat (extractlane x (u8_from_uimm8 idx))))) + (vec_replicate_lane ty x (be_lane_idx ty idx))) + +;; Load replicated 16-bit immediate value. +(rule 3 (lower (has_type ty (splat (i16_from_value x)))) + (vec_imm_replicate ty x)) + +;; Load replicated value from big-endian memory. +(rule 4 (lower (has_type ty (splat (sinkable_load x)))) + (vec_load_replicate ty (sink_load x))) + +;; Load replicated value from little-endian memory. +(rule 5 (lower (has_type ty (splat (sinkable_load_little x)))) + (vec_load_replicate_little ty (sink_load x))) + + +;; Helper to implement a generic little-endian variant of vec_load_replicate +(decl vec_load_replicate_little (Type MemArg) Reg) + +;; 8-byte little-endian loads can be performed via a normal load. +(rule (vec_load_replicate_little ty @ (multi_lane 8 _) addr) + (vec_load_replicate ty addr)) + +;; On z15, we have instructions to perform little-endian loads. +(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 16 _)) addr) + (vec_load_replicate_rev ty addr)) +(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 32 _)) addr) + (vec_load_replicate_rev ty addr)) +(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) + ty @ (multi_lane 64 _)) addr) + (vec_load_replicate_rev ty addr)) + +;; On z14, use a little-endian load (via GPR) and replicate. +(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 16 _)) addr) + (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) +(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 32 _)) addr) + (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) +(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) + ty @ (multi_lane 64 _)) addr) + (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) + + +;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load scalar value from general-purpose register. +(rule 1 (lower (has_type ty (scalar_to_vector + x @ (value_type in_ty)))) + (if (ty_int_ref_scalar_64 in_ty)) + (vec_insert_lane ty (vec_imm ty 0) x (be_lane_idx ty 0) (zero_reg))) + +;; Load scalar value from floating-point register. +(rule 0 (lower (has_type ty (scalar_to_vector + x @ (value_type (ty_scalar_float _))))) + (vec_move_lane_and_zero ty (be_lane_idx ty 0) x 0)) + +;; Load scalar value from vector lane. +(rule 2 (lower (has_type ty (scalar_to_vector + (extractlane x (u8_from_uimm8 idx))))) + (vec_move_lane_and_zero ty (be_lane_idx ty 0) x (be_lane_idx ty idx))) + +;; Load scalar 16-bit immediate value. +(rule 3 (lower (has_type ty (scalar_to_vector (i16_from_value x)))) + (vec_insert_lane_imm ty (vec_imm ty 0) x (be_lane_idx ty 0))) + +;; Load scalar value from big-endian memory. +(rule 4 (lower (has_type ty (scalar_to_vector (sinkable_load x)))) + (vec_load_lane ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0))) + +;; Load scalar value lane from little-endian memory. +(rule 5 (lower (has_type ty (scalar_to_vector (sinkable_load_little x)))) + (vec_load_lane_little ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0))) + + +;; Helper to extract one lane from a vector and insert it into a zero vector. +(decl vec_move_lane_and_zero (Type u8 Reg u8) Reg) + +;; For 64-bit elements we always use VPDI. +(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 0 src src_idx) + (vec_permute_dw_imm ty src src_idx (vec_imm ty 0) 0)) +(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 1 src src_idx) + (vec_permute_dw_imm ty (vec_imm ty 0) 0 src src_idx)) + +;; If source and destination index are the same, simply mask to this lane. +(rule -1 (vec_move_lane_and_zero ty idx src idx) + (vec_and ty src + (vec_imm_byte_mask ty (lane_byte_mask ty idx)))) + +;; Otherwise replicate source first and then mask to the lane. +(rule -2 (vec_move_lane_and_zero ty dst_idx src src_idx) + (vec_and ty (vec_replicate_lane ty src src_idx) + (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx)))) + + +;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; General case: use vec_permute and then mask off zero lanes. +(rule -2 (lower (shuffle x y (shuffle_mask permute_mask and_mask))) + (vec_and $I8X16 (vec_imm_byte_mask $I8X16 and_mask) + (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask)))) + +;; If the pattern has no zero lanes, just a vec_permute suffices. +(rule -1 (lower (shuffle x y (shuffle_mask permute_mask 65535))) + (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask))) + +;; Special patterns that can be implemented via MERGE HIGH. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23) 65535))) + (vec_merge_high $I64X2 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 16 17 18 19 4 5 6 7 20 21 22 23) 65535))) + (vec_merge_high $I32X4 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 16 17 2 3 18 19 4 5 20 21 6 7 22 23) 65535))) + (vec_merge_high $I16X8 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 16 1 17 2 18 3 19 4 20 5 21 6 22 7 23) 65535))) + (vec_merge_high $I8X16 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 0 1 2 3 4 5 6 7) 65535))) + (vec_merge_high $I64X2 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 0 1 2 3 20 21 22 23 4 5 6 7) 65535))) + (vec_merge_high $I32X4 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 0 1 18 19 2 3 20 21 4 5 22 23 6 7) 65535))) + (vec_merge_high $I16X8 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 0 17 1 18 2 19 3 20 4 21 5 22 6 23 7) 65535))) + (vec_merge_high $I8X16 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7) 65535))) + (vec_merge_high $I64X2 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 0 1 2 3 4 5 6 7 4 5 6 7) 65535))) + (vec_merge_high $I32X4 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 0 1 2 3 2 3 4 5 4 5 6 7 6 7) 65535))) + (vec_merge_high $I16X8 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7) 65535))) + (vec_merge_high $I8X16 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23) 65535))) + (vec_merge_high $I64X2 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 16 17 18 19 20 21 22 23 20 21 22 23) 65535))) + (vec_merge_high $I32X4 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 16 17 18 19 18 19 20 21 20 21 22 23 22 23) 65535))) + (vec_merge_high $I16X8 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23) 65535))) + (vec_merge_high $I8X16 y y)) + +;; Special patterns that can be implemented via MERGE LOW. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31) 65535))) + (vec_merge_low $I64X2 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 24 25 26 27 12 13 14 15 28 29 30 31) 65535))) + (vec_merge_low $I32X4 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 24 25 10 11 26 27 12 13 28 29 14 15 30 31) 65535))) + (vec_merge_low $I16X8 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 24 9 25 10 26 11 27 12 28 13 29 14 30 15 31) 65535))) + (vec_merge_low $I8X16 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 8 9 10 11 12 13 14 15) 65535))) + (vec_merge_low $I64X2 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 8 9 10 11 28 29 30 31 12 13 14 15) 65535))) + (vec_merge_low $I32X4 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 8 9 26 27 10 11 28 29 12 13 30 31 14 15) 65535))) + (vec_merge_low $I16X8 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 8 25 9 26 10 27 11 28 12 29 13 30 14 31 15) 65535))) + (vec_merge_low $I8X16 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15) 65535))) + (vec_merge_low $I64X2 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 8 9 10 11 12 13 14 15 12 13 14 15) 65535))) + (vec_merge_low $I32X4 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 8 9 10 11 10 11 12 13 12 13 14 15 14 15) 65535))) + (vec_merge_low $I16X8 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15) 65535))) + (vec_merge_low $I8X16 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31) 65535))) + (vec_merge_low $I64X2 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 24 25 26 27 28 29 30 31 28 29 30 31) 65535))) + (vec_merge_low $I32X4 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 24 25 26 27 26 27 28 29 28 29 30 31 30 31) 65535))) + (vec_merge_low $I16X8 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31) 65535))) + (vec_merge_low $I8X16 y y)) + +;; Special patterns that can be implemented via PACK. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 20 21 22 23 28 29 30 31) 65535))) + (vec_pack $I64X2 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 18 19 22 23 26 27 30 31) 65535))) + (vec_pack $I32X4 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31) 65535))) + (vec_pack $I16X8 x y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 4 5 6 7 12 13 14 15) 65535))) + (vec_pack $I64X2 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 2 3 6 7 10 11 14 15) 65535))) + (vec_pack $I32X4 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 1 3 5 7 9 11 13 15) 65535))) + (vec_pack $I16X8 y x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 4 5 6 7 12 13 14 15) 65535))) + (vec_pack $I64X2 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 2 3 6 7 10 11 14 15) 65535))) + (vec_pack $I32X4 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 1 3 5 7 9 11 13 15) 65535))) + (vec_pack $I16X8 x x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 20 21 22 23 28 29 30 31) 65535))) + (vec_pack $I64X2 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 18 19 22 23 26 27 30 31) 65535))) + (vec_pack $I32X4 y y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 17 19 21 23 25 27 29 31) 65535))) + (vec_pack $I16X8 y y)) + +;; Special patterns that can be implemented via UNPACK HIGH. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ _ _ 0 1 2 3 _ _ _ _ 4 5 6 7) 3855))) + (vec_unpacku_high $I32X4 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ 0 1 _ _ 2 3 _ _ 4 5 _ _ 6 7) 13107))) + (vec_unpacku_high $I16X8 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ 0 _ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7) 21845))) + (vec_unpacku_high $I8X16 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ _ _ 16 17 18 19 _ _ _ _ 20 21 22 23) 3855))) + (vec_unpacku_high $I32X4 y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ 16 17 _ _ 18 19 _ _ 20 21 _ _ 22 23) 13107))) + (vec_unpacku_high $I16X8 y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ 16 _ 17 _ 18 _ 19 _ 20 _ 21 _ 22 _ 23) 21845))) + (vec_unpacku_high $I8X16 y)) + +;; Special patterns that can be implemented via UNPACK LOW. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ _ _ 8 9 10 11 _ _ _ _ 12 13 14 15) 3855))) + (vec_unpacku_low $I32X4 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ 8 9 _ _ 10 11 _ _ 12 13 _ _ 14 15) 13107))) + (vec_unpacku_low $I16X8 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ 8 _ 9 _ 10 _ 11 _ 12 _ 13 _ 14 _ 15) 21845))) + (vec_unpacku_low $I8X16 x)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ _ _ 24 25 26 27 _ _ _ _ 28 29 30 31) 3855))) + (vec_unpacku_low $I32X4 y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ _ 24 25 _ _ 26 27 _ _ 28 29 _ _ 30 31) 13107))) + (vec_unpacku_low $I16X8 y)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 _ 24 _ 25 _ 26 _ 27 _ 28 _ 29 _ 30 _ 31) 21845))) + (vec_unpacku_low $I8X16 y)) + +;; Special patterns that can be implemented via PERMUTE DOUBLEWORD IMMEDIATE. +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31) 65535))) + (vec_permute_dw_imm $I8X16 x 0 y 1)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23) 65535))) + (vec_permute_dw_imm $I8X16 x 1 y 0)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15) 65535))) + (vec_permute_dw_imm $I8X16 y 0 x 1)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7) 65535))) + (vec_permute_dw_imm $I8X16 y 1 x 0)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 65535))) + (vec_permute_dw_imm $I8X16 x 0 x 1)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7) 65535))) + (vec_permute_dw_imm $I8X16 x 1 x 0)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) 65535))) + (vec_permute_dw_imm $I8X16 y 0 y 1)) +(rule (lower (shuffle x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23) 65535))) + (vec_permute_dw_imm $I8X16 y 1 y 0)) + + +;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; When using big-endian lane order, the lane mask is mostly correct, but we +;; need to handle mask elements outside the range 0..15 by zeroing the lane. +;; +;; To do so efficiently, we compute: +;; permute-lane-element := umin (16, swizzle-lane-element) +;; and pass a zero vector as second operand to the permute instruction. + +(rule 1 (lower (has_type (ty_vec128 ty) (swizzle x y))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_permute ty x (vec_imm ty 0) + (vec_umin $I8X16 (vec_imm_splat $I8X16 16) y))) + +;; When using little-endian lane order, in addition to zeroing (as above), +;; we need to convert from little-endian to big-endian lane numbering. +;; +;; To do so efficiently, we compute: +;; permute-lane-element := umax (239, ~ swizzle-lane-element) +;; which has the following effect: +;; elements 0 .. 15 --> 255 .. 240 (i.e. 31 .. 16 mod 32) +;; everything else --> 239 (i.e. 15 mod 32) +;; +;; Then, we can use a single permute instruction with +;; a zero vector as first operand (covering lane 15) +;; the input vector as second operand (covering lanes 16 .. 31) +;; to implement the required swizzle semantics. + +(rule (lower (has_type (ty_vec128 ty) (swizzle x y))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_permute ty (vec_imm ty 0) x + (vec_umax $I8X16 (vec_imm_splat $I8X16 239) + (vec_not $I8X16 y)))) + + +;;;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load the address of a stack slot. +(rule (lower (has_type ty (stack_addr stack_slot offset))) + (stack_addr_impl ty stack_slot offset)) + + +;;;; Rules for `func_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load the address of a function, target reachable via PC-relative instruction. +(rule 1 (lower (func_addr (func_ref_data _ name (reloc_distance_near)))) + (load_addr (memarg_symbol name 0 (memflags_trusted)))) + +;; Load the address of a function, general case. +(rule (lower (func_addr (func_ref_data _ name _))) + (load_symbol_reloc (SymbolReloc.Absolute name 0))) + + +;;;; Rules for `symbol_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load the address of a symbol, target reachable via PC-relative instruction. +(rule 1 (lower (symbol_value (symbol_value_data name (reloc_distance_near) + off))) + (if-let offset (memarg_symbol_offset off)) + (load_addr (memarg_symbol name offset (memflags_trusted)))) + +;; Load the address of a symbol, general case. +(rule (lower (symbol_value (symbol_value_data name _ offset))) + (load_symbol_reloc (SymbolReloc.Absolute name offset))) + + +;;;; Rules for `tls_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load the address of a TLS symbol (ELF general-dynamic model). +(rule (lower (tls_value (symbol_value_data name _ 0))) + (if (tls_model_is_elf_gd)) + (let ((symbol SymbolReloc (SymbolReloc.TlsGd name)) + (got Reg (load_addr (memarg_got))) + (got_offset Reg (load_symbol_reloc symbol)) + (tls_offset Reg (lib_call_tls_get_offset got got_offset symbol))) + (add_reg $I64 tls_offset (thread_pointer)))) + +;; Helper to perform a call to the __tls_get_offset library routine. +(decl lib_call_tls_get_offset (Reg Reg SymbolReloc) Reg) +(rule (lib_call_tls_get_offset got got_offset symbol) + (let ((tls_offset WritableReg (temp_writable_reg $I64)) + (_ Unit (abi_for_elf_tls_get_offset)) + (_ Unit (emit (MInst.ElfTlsGetOffset tls_offset got got_offset symbol)))) + tls_offset)) + +(decl abi_for_elf_tls_get_offset () Unit) +(extern constructor abi_for_elf_tls_get_offset abi_for_elf_tls_get_offset) + +;; Helper to extract the current thread pointer from %a0/%a1. +(decl thread_pointer () Reg) +(rule (thread_pointer) + (insert_ar (lshl_imm $I64 (load_ar 0) 32) 1)) + + +;;;; Rules for `load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load 8-bit integers. +(rule (lower (has_type $I8 (load flags addr offset))) + (zext32_mem $I8 (lower_address flags addr offset))) + +;; Load 16-bit big-endian integers. +(rule (lower (has_type $I16 (load flags @ (bigendian) addr offset))) + (zext32_mem $I16 (lower_address flags addr offset))) + +;; Load 16-bit little-endian integers. +(rule -1 (lower (has_type $I16 (load flags @ (littleendian) addr offset))) + (loadrev16 (lower_address flags addr offset))) + +;; Load 32-bit big-endian integers. +(rule (lower (has_type $I32 (load flags @ (bigendian) addr offset))) + (load32 (lower_address flags addr offset))) + +;; Load 32-bit little-endian integers. +(rule -1 (lower (has_type $I32 (load flags @ (littleendian) addr offset))) + (loadrev32 (lower_address flags addr offset))) + +;; Load 64-bit big-endian integers. +(rule (lower (has_type $I64 (load flags @ (bigendian) addr offset))) + (load64 (lower_address flags addr offset))) + +;; Load 64-bit little-endian integers. +(rule -1 (lower (has_type $I64 (load flags @ (littleendian) addr offset))) + (loadrev64 (lower_address flags addr offset))) + +;; Load 32-bit big-endian floating-point values (as vector lane). +(rule (lower (has_type $F32 (load flags @ (bigendian) addr offset))) + (vec_load_lane_undef $F32X4 (lower_address flags addr offset) 0)) + +;; Load 32-bit little-endian floating-point values (as vector lane). +(rule -1 (lower (has_type $F32 (load flags @ (littleendian) addr offset))) + (vec_load_lane_little_undef $F32X4 (lower_address flags addr offset) 0)) + +;; Load 64-bit big-endian floating-point values (as vector lane). +(rule (lower (has_type $F64 (load flags @ (bigendian) addr offset))) + (vec_load_lane_undef $F64X2 (lower_address flags addr offset) 0)) + +;; Load 64-bit little-endian floating-point values (as vector lane). +(rule -1 (lower (has_type $F64 (load flags @ (littleendian) addr offset))) + (vec_load_lane_little_undef $F64X2 (lower_address flags addr offset) 0)) + +;; Load 128-bit big-endian vector values, BE lane order - direct load. +(rule 4 (lower (has_type (vr128_ty ty) (load flags @ (bigendian) addr offset))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_load ty (lower_address flags addr offset))) + +;; Load 128-bit little-endian vector values, BE lane order - byte-reversed load. +(rule 3 (lower (has_type (vr128_ty ty) (load flags @ (littleendian) addr offset))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_load_byte_rev ty flags addr offset)) + +;; Load 128-bit big-endian vector values, LE lane order - element-reversed load. +(rule 2 (lower (has_type (vr128_ty ty) (load flags @ (bigendian) addr offset))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_load_elt_rev ty flags addr offset)) + +;; Load 128-bit little-endian vector values, LE lane order - fully-reversed load. +(rule 1 (lower (has_type (vr128_ty ty) (load flags @ (littleendian) addr offset))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_load_full_rev ty flags addr offset)) + + +;; Helper to perform a 128-bit full-vector byte-reversed load. +(decl vec_load_full_rev (Type MemFlags Value Offset32) Reg) + +;; Full-vector byte-reversed load via single instruction on z15. +(rule 1 (vec_load_full_rev (and (vxrs_ext2_enabled) (vr128_ty ty)) flags addr offset) + (vec_loadrev ty (lower_address flags addr offset))) + +;; Full-vector byte-reversed load via GPRs on z14. +(rule (vec_load_full_rev (and (vxrs_ext2_disabled) (vr128_ty ty)) flags addr offset) + (let ((lo_addr MemArg (lower_address_bias flags addr offset 0)) + (hi_addr MemArg (lower_address_bias flags addr offset 8)) + (lo_val Reg (loadrev64 lo_addr)) + (hi_val Reg (loadrev64 hi_addr))) + (mov_to_vec128 ty hi_val lo_val))) + + +;; Helper to perform an element-wise byte-reversed load. +(decl vec_load_byte_rev (Type MemFlags Value Offset32) Reg) + +;; Element-wise byte-reversed 1x128-bit load is a full byte-reversed load. +(rule -1 (vec_load_byte_rev $I128 flags addr offset) + (vec_load_full_rev $I128 flags addr offset)) + +;; Element-wise byte-reversed 16x8-bit load is a direct load. +(rule (vec_load_byte_rev ty @ (multi_lane 8 16) flags addr offset) + (vec_load ty (lower_address flags addr offset))) + +;; Element-wise byte-reversed load via single instruction on z15. +(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) + flags addr offset) + (vec_load_byte64rev ty (lower_address flags addr offset))) +(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) + flags addr offset) + (vec_load_byte32rev ty (lower_address flags addr offset))) +(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) + flags addr offset) + (vec_load_byte16rev ty (lower_address flags addr offset))) + +;; Element-wise byte-reversed load as element-swapped byte-reversed load on z14. +(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) + flags addr offset) + (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) +(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) + flags addr offset) + (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) +(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) + flags addr offset) + (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) + + +;; Helper to perform an element-reversed load. +(decl vec_load_elt_rev (Type MemFlags Value Offset32) Reg) + +;; Element-reversed 1x128-bit load is a direct load. +;; For 1x128-bit types, this is a direct load. +(rule -1 (vec_load_elt_rev $I128 flags addr offset) + (vec_load $I128 (lower_address flags addr offset))) + +;; Element-reversed 16x8-bit load is a full byte-reversed load. +(rule (vec_load_elt_rev ty @ (multi_lane 8 16) flags addr offset) + (vec_load_full_rev ty flags addr offset)) + +;; Element-reversed load via single instruction on z15. +(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) + flags addr offset) + (vec_load_elt64rev ty (lower_address flags addr offset))) +(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) + flags addr offset) + (vec_load_elt32rev ty (lower_address flags addr offset))) +(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) + flags addr offset) + (vec_load_elt16rev ty (lower_address flags addr offset))) + +;; Element-reversed load as element-swapped direct load on z14. +(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) + flags addr offset) + (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) +(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) + flags addr offset) + (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) +(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) + flags addr offset) + (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) + + +;;;; Rules for `uload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 16- or 32-bit target types. +(rule (lower (has_type (gpr32_ty _ty) (uload8 flags addr offset))) + (zext32_mem $I8 (lower_address flags addr offset))) + +;; 64-bit target types. +(rule 1 (lower (has_type (gpr64_ty _ty) (uload8 flags addr offset))) + (zext64_mem $I8 (lower_address flags addr offset))) + + +;;;; Rules for `sload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 16- or 32-bit target types. +(rule (lower (has_type (gpr32_ty _ty) (sload8 flags addr offset))) + (sext32_mem $I8 (lower_address flags addr offset))) + +;; 64-bit target types. +(rule 1 (lower (has_type (gpr64_ty _ty) (sload8 flags addr offset))) + (sext64_mem $I8 (lower_address flags addr offset))) + + +;;;; Rules for `uload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 32-bit target type, big-endian source value. +(rule 3 (lower (has_type (gpr32_ty _ty) + (uload16 flags @ (bigendian) addr offset))) + (zext32_mem $I16 (lower_address flags addr offset))) + +;; 32-bit target type, little-endian source value (via explicit extension). +(rule 1 (lower (has_type (gpr32_ty _ty) + (uload16 flags @ (littleendian) addr offset))) + (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) + (zext32_reg $I16 reg16))) + +;; 64-bit target type, big-endian source value. +(rule 4 (lower (has_type (gpr64_ty _ty) + (uload16 flags @ (bigendian) addr offset))) + (zext64_mem $I16 (lower_address flags addr offset))) + +;; 64-bit target type, little-endian source value (via explicit extension). +(rule 2 (lower (has_type (gpr64_ty _ty) + (uload16 flags @ (littleendian) addr offset))) + (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) + (zext64_reg $I16 reg16))) + + +;;;; Rules for `sload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 32-bit target type, big-endian source value. +(rule 2 (lower (has_type (gpr32_ty _ty) + (sload16 flags @ (bigendian) addr offset))) + (sext32_mem $I16 (lower_address flags addr offset))) + +;; 32-bit target type, little-endian source value (via explicit extension). +(rule 0 (lower (has_type (gpr32_ty _ty) + (sload16 flags @ (littleendian) addr offset))) + (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) + (sext32_reg $I16 reg16))) + +;; 64-bit target type, big-endian source value. +(rule 3 (lower (has_type (gpr64_ty _ty) + (sload16 flags @ (bigendian) addr offset))) + (sext64_mem $I16 (lower_address flags addr offset))) + +;; 64-bit target type, little-endian source value (via explicit extension). +(rule 1 (lower (has_type (gpr64_ty _ty) + (sload16 flags @ (littleendian) addr offset))) + (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) + (sext64_reg $I16 reg16))) + + +;;;; Rules for `uload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 64-bit target type, big-endian source value. +(rule 1 (lower (has_type (gpr64_ty _ty) + (uload32 flags @ (bigendian) addr offset))) + (zext64_mem $I32 (lower_address flags addr offset))) + +;; 64-bit target type, little-endian source value (via explicit extension). +(rule (lower (has_type (gpr64_ty _ty) + (uload32 flags @ (littleendian) addr offset))) + (let ((reg32 Reg (loadrev32 (lower_address flags addr offset)))) + (zext64_reg $I32 reg32))) + + +;;;; Rules for `sload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 64-bit target type, big-endian source value. +(rule 1 (lower (has_type (gpr64_ty _ty) + (sload32 flags @ (bigendian) addr offset))) + (sext64_mem $I32 (lower_address flags addr offset))) + +;; 64-bit target type, little-endian source value (via explicit extension). +(rule (lower (has_type (gpr64_ty _ty) + (sload32 flags @ (littleendian) addr offset))) + (let ((reg32 Reg (loadrev32 (lower_address flags addr offset)))) + (sext64_reg $I32 reg32))) + + +;;;; Rules for `uloadNxM` and `sloadNxM` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unsigned 8->16 bit extension. +(rule (lower (has_type $I16X8 (uload8x8 flags addr offset))) + (vec_unpacku_high $I8X16 (load_v64 $I8X16 flags addr offset))) + +;; Signed 8->16 bit extension. +(rule (lower (has_type $I16X8 (sload8x8 flags addr offset))) + (vec_unpacks_high $I8X16 (load_v64 $I8X16 flags addr offset))) + +;; Unsigned 16->32 bit extension. +(rule (lower (has_type $I32X4 (uload16x4 flags addr offset))) + (vec_unpacku_high $I16X8 (load_v64 $I16X8 flags addr offset))) + +;; Signed 16->32 bit extension. +(rule (lower (has_type $I32X4 (sload16x4 flags addr offset))) + (vec_unpacks_high $I16X8 (load_v64 $I16X8 flags addr offset))) + +;; Unsigned 32->64 bit extension. +(rule (lower (has_type $I64X2 (uload32x2 flags addr offset))) + (vec_unpacku_high $I32X4 (load_v64 $I32X4 flags addr offset))) + +;; Signed 32->64 bit extension. +(rule (lower (has_type $I64X2 (sload32x2 flags addr offset))) + (vec_unpacks_high $I32X4 (load_v64 $I32X4 flags addr offset))) + + +;; Helper to load a 64-bit half-size vector from memory. +(decl load_v64 (Type MemFlags Value Offset32) Reg) + +;; Any big-endian source value, BE lane order. +(rule -1 (load_v64 _ flags @ (bigendian) addr offset) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0)) + +;; Any little-endian source value, LE lane order. +(rule -2 (load_v64 _ flags @ (littleendian) addr offset) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0)) + +;; Big-endian or little-endian 8x8-bit source value, BE lane order. +(rule (load_v64 (multi_lane 8 16) flags addr offset) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0)) + +;; Big-endian or little-endian 8x8-bit source value, LE lane order. +(rule 1 (load_v64 (multi_lane 8 16) flags addr offset) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0)) + +;; Little-endian 4x16-bit source value, BE lane order. +(rule (load_v64 (multi_lane 16 8) flags @ (littleendian) addr offset) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_rot_imm $I16X8 + (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 8)) + +;; Big-endian 4x16-bit source value, LE lane order. +(rule 1 (load_v64 (multi_lane 16 8) flags @ (bigendian) addr offset) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_rot_imm $I16X8 + (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 8)) + +;; Little-endian 2x32-bit source value, BE lane order. +(rule (load_v64 (multi_lane 32 4) flags @ (littleendian) addr offset) + (if-let (LaneOrder.BigEndian) (lane_order)) + (vec_rot_imm $I64X2 + (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 32)) + +;; Big-endian 2x32-bit source value, LE lane order. +(rule 1 (load_v64 (multi_lane 32 4) flags @ (bigendian) addr offset) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (vec_rot_imm $I64X2 + (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 32)) + + +;;;; Rules for `store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The actual store logic for integer types is identical for the `store`, +;; `istoreNN`, and `atomic_store` instructions, so we share common helpers. + +;; Store 8-bit integer type, main lowering entry point. +(rule (lower (store flags val @ (value_type $I8) addr offset)) + (side_effect (istore8_impl flags val addr offset))) + +;; Store 16-bit integer type, main lowering entry point. +(rule (lower (store flags val @ (value_type $I16) addr offset)) + (side_effect (istore16_impl flags val addr offset))) + +;; Store 32-bit integer type, main lowering entry point. +(rule (lower (store flags val @ (value_type $I32) addr offset)) + (side_effect (istore32_impl flags val addr offset))) + +;; Store 64-bit integer type, main lowering entry point. +(rule (lower (store flags val @ (value_type $I64) addr offset)) + (side_effect (istore64_impl flags val addr offset))) + +;; Store 32-bit big-endian floating-point type (as vector lane). +(rule -1 (lower (store flags @ (bigendian) + val @ (value_type $F32) addr offset)) + (side_effect (vec_store_lane $F32X4 val + (lower_address flags addr offset) 0))) + +;; Store 32-bit little-endian floating-point type (as vector lane). +(rule (lower (store flags @ (littleendian) + val @ (value_type $F32) addr offset)) + (side_effect (vec_store_lane_little $F32X4 val + (lower_address flags addr offset) 0))) + +;; Store 64-bit big-endian floating-point type (as vector lane). +(rule -1 (lower (store flags @ (bigendian) + val @ (value_type $F64) addr offset)) + (side_effect (vec_store_lane $F64X2 val + (lower_address flags addr offset) 0))) + +;; Store 64-bit little-endian floating-point type (as vector lane). +(rule (lower (store flags @ (littleendian) + val @ (value_type $F64) addr offset)) + (side_effect (vec_store_lane_little $F64X2 val + (lower_address flags addr offset) 0))) + +;; Store 128-bit big-endian vector type, BE lane order - direct store. +(rule 4 (lower (store flags @ (bigendian) + val @ (value_type (vr128_ty ty)) addr offset)) + (if-let (LaneOrder.BigEndian) (lane_order)) + (side_effect (vec_store val (lower_address flags addr offset)))) + +;; Store 128-bit little-endian vector type, BE lane order - byte-reversed store. +(rule 3 (lower (store flags @ (littleendian) + val @ (value_type (vr128_ty ty)) addr offset)) + (if-let (LaneOrder.BigEndian) (lane_order)) + (side_effect (vec_store_byte_rev ty val flags addr offset))) + +;; Store 128-bit big-endian vector type, LE lane order - element-reversed store. +(rule 2 (lower (store flags @ (bigendian) + val @ (value_type (vr128_ty ty)) addr offset)) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (side_effect (vec_store_elt_rev ty val flags addr offset))) + +;; Store 128-bit little-endian vector type, LE lane order - fully-reversed store. +(rule 1 (lower (store flags @ (littleendian) + val @ (value_type (vr128_ty ty)) addr offset)) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (side_effect (vec_store_full_rev ty val flags addr offset))) + + +;; Helper to perform a 128-bit full-vector byte-reversed store. +(decl vec_store_full_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) + +;; Full-vector byte-reversed store via single instruction on z15. +(rule 1 (vec_store_full_rev (vxrs_ext2_enabled) val flags addr offset) + (vec_storerev val (lower_address flags addr offset))) + +;; Full-vector byte-reversed store via GPRs on z14. +(rule (vec_store_full_rev (vxrs_ext2_disabled) val flags addr offset) + (let ((lo_addr MemArg (lower_address_bias flags addr offset 0)) + (hi_addr MemArg (lower_address_bias flags addr offset 8)) + (lo_val Reg (vec_extract_lane $I64X2 val 1 (zero_reg))) + (hi_val Reg (vec_extract_lane $I64X2 val 0 (zero_reg)))) + (side_effect_concat (storerev64 lo_val lo_addr) + (storerev64 hi_val hi_addr)))) + + +;; Helper to perform an element-wise byte-reversed store. +(decl vec_store_byte_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) + +;; Element-wise byte-reversed 1x128-bit store is a full byte-reversed store. +(rule -1 (vec_store_byte_rev $I128 val flags addr offset) + (vec_store_full_rev $I128 val flags addr offset)) + +;; Element-wise byte-reversed 16x8-bit store is a direct store. +(rule (vec_store_byte_rev (multi_lane 8 16) val flags addr offset) + (vec_store val (lower_address flags addr offset))) + +;; Element-wise byte-reversed store via single instruction on z15. +(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) + val flags addr offset) + (vec_store_byte64rev val (lower_address flags addr offset))) +(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) + val flags addr offset) + (vec_store_byte32rev val (lower_address flags addr offset))) +(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) + val flags addr offset) + (vec_store_byte16rev val (lower_address flags addr offset))) + +;; Element-wise byte-reversed load as element-swapped byte-reversed store on z14. +(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) + val flags addr offset) + (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) +(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) + val flags addr offset) + (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) +(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) + val flags addr offset) + (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) + + +;; Helper to perform an element-reversed store. +(decl vec_store_elt_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) + +;; Element-reversed 1x128-bit store is a direct store. +(rule -1 (vec_store_elt_rev $I128 val flags addr offset) + (vec_store val (lower_address flags addr offset))) + +;; Element-reversed 16x8-bit store is a full byte-reversed store. +(rule (vec_store_elt_rev ty @ (multi_lane 8 16) val flags addr offset) + (vec_store_full_rev ty val flags addr offset)) + +;; Element-reversed store via single instruction on z15. +(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) + val flags addr offset) + (vec_store_elt64rev val (lower_address flags addr offset))) +(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) + val flags addr offset) + (vec_store_elt32rev val (lower_address flags addr offset))) +(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) + val flags addr offset) + (vec_store_elt16rev val (lower_address flags addr offset))) + +;; Element-reversed store as element-swapped direct store on z14. +(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) + val flags addr offset) + (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) +(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) + val flags addr offset) + (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) +(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) + val flags addr offset) + (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) + + +;;;; Rules for 8-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `istore8` lowering entry point, dispatching to the helper. +(rule (lower (istore8 flags val addr offset)) + (side_effect (istore8_impl flags val addr offset))) + +;; Helper to store 8-bit integer types. +(decl istore8_impl (MemFlags Value Value Offset32) SideEffectNoResult) + +;; Store 8-bit integer types, register input. +(rule (istore8_impl flags val addr offset) + (store8 (put_in_reg val) (lower_address flags addr offset))) + +;; Store 8-bit integer types, immediate input. +(rule 1 (istore8_impl flags (u8_from_value imm) addr offset) + (store8_imm imm (lower_address flags addr offset))) + + +;;;; Rules for 16-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `istore16` lowering entry point, dispatching to the helper. +(rule (lower (istore16 flags val addr offset)) + (side_effect (istore16_impl flags val addr offset))) + +;; Helper to store 16-bit integer types. +(decl istore16_impl (MemFlags Value Value Offset32) SideEffectNoResult) + +;; Store 16-bit big-endian integer types, register input. +(rule 2 (istore16_impl flags @ (bigendian) val addr offset) + (store16 (put_in_reg val) (lower_address flags addr offset))) + +;; Store 16-bit little-endian integer types, register input. +(rule 0 (istore16_impl flags @ (littleendian) val addr offset) + (storerev16 (put_in_reg val) (lower_address flags addr offset))) + +;; Store 16-bit big-endian integer types, immediate input. +(rule 3 (istore16_impl flags @ (bigendian) (i16_from_value imm) addr offset) + (store16_imm imm (lower_address flags addr offset))) + +;; Store 16-bit little-endian integer types, immediate input. +(rule 1 (istore16_impl flags @ (littleendian) (i16_from_swapped_value imm) addr offset) + (store16_imm imm (lower_address flags addr offset))) + + +;;;; Rules for 32-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `istore32` lowering entry point, dispatching to the helper. +(rule (lower (istore32 flags val addr offset)) + (side_effect (istore32_impl flags val addr offset))) + +;; Helper to store 32-bit integer types. +(decl istore32_impl (MemFlags Value Value Offset32) SideEffectNoResult) + +;; Store 32-bit big-endian integer types, register input. +(rule 1 (istore32_impl flags @ (bigendian) val addr offset) + (store32 (put_in_reg val) (lower_address flags addr offset))) + +;; Store 32-bit big-endian integer types, immediate input. +(rule 2 (istore32_impl flags @ (bigendian) (i16_from_value imm) addr offset) + (store32_simm16 imm (lower_address flags addr offset))) + +;; Store 32-bit little-endian integer types. +(rule 0 (istore32_impl flags @ (littleendian) val addr offset) + (storerev32 (put_in_reg val) (lower_address flags addr offset))) + + +;;;; Rules for 64-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper to store 64-bit integer types. +(decl istore64_impl (MemFlags Value Value Offset32) SideEffectNoResult) + +;; Store 64-bit big-endian integer types, register input. +(rule 1 (istore64_impl flags @ (bigendian) val addr offset) + (store64 (put_in_reg val) (lower_address flags addr offset))) + +;; Store 64-bit big-endian integer types, immediate input. +(rule 2 (istore64_impl flags @ (bigendian) (i16_from_value imm) addr offset) + (store64_simm16 imm (lower_address flags addr offset))) + +;; Store 64-bit little-endian integer types. +(rule 0 (istore64_impl flags @ (littleendian) val addr offset) + (storerev64 (put_in_reg val) (lower_address flags addr offset))) + + +;;;; Rules for `atomic_rmw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Atomic operations that do not require a compare-and-swap loop. + +;; Atomic AND for 32/64-bit big-endian types, using a single instruction. +(rule 1 (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (bigendian) (AtomicRmwOp.And) addr src))) + (atomic_rmw_and ty (put_in_reg src) + (lower_address flags addr (zero_offset)))) + +;; Atomic AND for 32/64-bit big-endian types, using byte-swapped input/output. +(rule (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (littleendian) (AtomicRmwOp.And) addr src))) + (bswap_reg ty (atomic_rmw_and ty (bswap_reg ty (put_in_reg src)) + (lower_address flags addr (zero_offset))))) + +;; Atomic OR for 32/64-bit big-endian types, using a single instruction. +(rule 1 (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (bigendian) (AtomicRmwOp.Or) addr src))) + (atomic_rmw_or ty (put_in_reg src) + (lower_address flags addr (zero_offset)))) + +;; Atomic OR for 32/64-bit little-endian types, using byte-swapped input/output. +(rule (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (littleendian) (AtomicRmwOp.Or) addr src))) + (bswap_reg ty (atomic_rmw_or ty (bswap_reg ty (put_in_reg src)) + (lower_address flags addr (zero_offset))))) + +;; Atomic XOR for 32/64-bit big-endian types, using a single instruction. +(rule 1 (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (bigendian) (AtomicRmwOp.Xor) addr src))) + (atomic_rmw_xor ty (put_in_reg src) + (lower_address flags addr (zero_offset)))) + +;; Atomic XOR for 32/64-bit little-endian types, using byte-swapped input/output. +(rule (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (littleendian) (AtomicRmwOp.Xor) addr src))) + (bswap_reg ty (atomic_rmw_xor ty (bswap_reg ty (put_in_reg src)) + (lower_address flags addr (zero_offset))))) + +;; Atomic ADD for 32/64-bit big-endian types, using a single instruction. +(rule (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (bigendian) (AtomicRmwOp.Add) addr src))) + (atomic_rmw_add ty (put_in_reg src) + (lower_address flags addr (zero_offset)))) + +;; Atomic SUB for 32/64-bit big-endian types, using atomic ADD with negated input. +(rule (lower (has_type (ty_32_or_64 ty) + (atomic_rmw flags @ (bigendian) (AtomicRmwOp.Sub) addr src))) + (atomic_rmw_add ty (neg_reg ty (put_in_reg src)) + (lower_address flags addr (zero_offset)))) + + +;; Atomic operations that require a compare-and-swap loop. + +;; Operations for 32/64-bit types can use a fullword compare-and-swap loop. +(rule -1 (lower (has_type (ty_32_or_64 ty) (atomic_rmw flags op addr src))) + (let ((src_reg Reg (put_in_reg src)) + (addr_reg Reg (put_in_reg addr)) + ;; Create body of compare-and-swap loop. + (ib VecMInstBuilder (inst_builder_new)) + (val0 Reg (writable_reg_to_reg (casloop_val_reg))) + (val1 Reg (atomic_rmw_body ib ty flags op + (casloop_tmp_reg) val0 src_reg))) + ;; Emit compare-and-swap loop and extract final result. + (casloop ib ty flags addr_reg val1))) + +;; Operations for 8/16-bit types must operate on the surrounding aligned word. +(rule -2 (lower (has_type (ty_8_or_16 ty) (atomic_rmw flags op addr src))) + (let ((src_reg Reg (put_in_reg src)) + (addr_reg Reg (put_in_reg addr)) + ;; Prepare access to surrounding aligned word. + (bitshift Reg (casloop_bitshift addr_reg)) + (aligned_addr Reg (casloop_aligned_addr addr_reg)) + ;; Create body of compare-and-swap loop. + (ib VecMInstBuilder (inst_builder_new)) + (val0 Reg (writable_reg_to_reg (casloop_val_reg))) + (val1 Reg (casloop_rotate_in ib ty flags bitshift val0)) + (val2 Reg (atomic_rmw_body ib ty flags op + (casloop_tmp_reg) val1 src_reg)) + (val3 Reg (casloop_rotate_out ib ty flags bitshift val2))) + ;; Emit compare-and-swap loop and extract final result. + (casloop_subword ib ty flags aligned_addr bitshift val3))) + +;; Loop bodies for atomic read-modify-write operations. +(decl atomic_rmw_body (VecMInstBuilder Type MemFlags AtomicRmwOp + WritableReg Reg Reg) Reg) + +;; Loop bodies for 32-/64-bit atomic XCHG operations. +;; Simply use the source (possibly byte-swapped) as new target value. +(rule 2 (atomic_rmw_body ib (ty_32_or_64 ty) (bigendian) + (AtomicRmwOp.Xchg) tmp val src) + src) +(rule 1 (atomic_rmw_body ib (ty_32_or_64 ty) (littleendian) + (AtomicRmwOp.Xchg) tmp val src) + (bswap_reg ty src)) + +;; Loop bodies for 32-/64-bit atomic NAND operations. +;; On z15 this can use the NN(G)RK instruction. On z14, perform an And +;; operation and invert the result. In the little-endian case, we can +;; simply byte-swap the source operand. +(rule 4 (atomic_rmw_body ib (and (mie2_enabled) (ty_32_or_64 ty)) (bigendian) + (AtomicRmwOp.Nand) tmp val src) + (push_alu_reg ib (aluop_not_and ty) tmp val src)) +(rule 3 (atomic_rmw_body ib (and (mie2_enabled) (ty_32_or_64 ty)) (littleendian) + (AtomicRmwOp.Nand) tmp val src) + (push_alu_reg ib (aluop_not_and ty) tmp val (bswap_reg ty src))) +(rule 2 (atomic_rmw_body ib (and (mie2_disabled) (ty_32_or_64 ty)) (bigendian) + (AtomicRmwOp.Nand) tmp val src) + (push_not_reg ib ty tmp + (push_alu_reg ib (aluop_and ty) tmp val src))) +(rule 1 (atomic_rmw_body ib (and (mie2_disabled) (ty_32_or_64 ty)) (littleendian) + (AtomicRmwOp.Nand) tmp val src) + (push_not_reg ib ty tmp + (push_alu_reg ib (aluop_and ty) tmp val (bswap_reg ty src)))) + +;; Loop bodies for 8-/16-bit atomic bit operations. +;; These use the "rotate-then--selected bits" family of instructions. +;; For the Nand operation, we again perform And and invert the result. +(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xchg) tmp val src) + (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Insert) tmp val src)) +(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.And) tmp val src) + (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src)) +(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Or) tmp val src) + (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Or) tmp val src)) +(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xor) tmp val src) + (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Xor) tmp val src)) +(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Nand) tmp val src) + (atomic_rmw_body_invert ib ty flags tmp + (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src))) + +;; RxSBG subword operation. +(decl atomic_rmw_body_rxsbg (VecMInstBuilder Type MemFlags RxSBGOp + WritableReg Reg Reg) Reg) +;; 8-bit case: use the low byte of "src" and the high byte of "val". +(rule (atomic_rmw_body_rxsbg ib $I8 _ op tmp val src) + (push_rxsbg ib op tmp val src 32 40 24)) +;; 16-bit big-endian case: use the low two bytes of "src" and the +;; high two bytes of "val". +(rule 1 (atomic_rmw_body_rxsbg ib $I16 (bigendian) op tmp val src) + (push_rxsbg ib op tmp val src 32 48 16)) +;; 16-bit little-endian case: use the low two bytes of "src", byte-swapped +;; so they end up in the high two bytes, and the low two bytes of "val". +(rule (atomic_rmw_body_rxsbg ib $I16 (littleendian) op tmp val src) + (push_rxsbg ib op tmp val (bswap_reg $I32 src) 48 64 -16)) + +;; Invert a subword. +(decl atomic_rmw_body_invert (VecMInstBuilder Type MemFlags WritableReg Reg) Reg) +;; 8-bit case: invert the high byte. +(rule (atomic_rmw_body_invert ib $I8 _ tmp val) + (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xff000000 0))) +;; 16-bit big-endian case: invert the two high bytes. +(rule 1 (atomic_rmw_body_invert ib $I16 (bigendian) tmp val) + (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff0000 0))) +;; 16-bit little-endian case: invert the two low bytes. +(rule (atomic_rmw_body_invert ib $I16 (littleendian) tmp val) + (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff 0))) + +;; Loop bodies for atomic ADD/SUB operations. +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Add) tmp val src) + (atomic_rmw_body_addsub ib ty flags (aluop_add (ty_ext32 ty)) tmp val src)) +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Sub) tmp val src) + (atomic_rmw_body_addsub ib ty flags (aluop_sub (ty_ext32 ty)) tmp val src)) + +;; Addition or subtraction operation. +(decl atomic_rmw_body_addsub (VecMInstBuilder Type MemFlags ALUOp + WritableReg Reg Reg) Reg) +;; 32/64-bit big-endian case: just a regular add/sub operation. +(rule 2 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (bigendian) op tmp val src) + (push_alu_reg ib op tmp val src)) +;; 32/64-bit little-endian case: byte-swap the value loaded from memory before +;; and after performing the operation in native endianness. +(rule 1 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (littleendian) op tmp val src) + (let ((val_swapped Reg (push_bswap_reg ib ty tmp val)) + (res_swapped Reg (push_alu_reg ib op tmp val_swapped src))) + (push_bswap_reg ib ty tmp res_swapped))) +;; 8-bit case: perform a 32-bit addition of the source value shifted by 24 bits +;; to the memory value, which contains the target in its high byte. +(rule (atomic_rmw_body_addsub ib $I8 _ op tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 24))) + (push_alu_reg ib op tmp val src_shifted))) +;; 16-bit big-endian case: similar, just shift the source by 16 bits. +(rule 3 (atomic_rmw_body_addsub ib $I16 (bigendian) op tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 16))) + (push_alu_reg ib op tmp val src_shifted))) +;; 16-bit little-endian case: the same, but in addition we need to byte-swap +;; the memory value before and after the operation. Since the value was placed +;; in the low two bytes by our standard rotation, we can use a 32-bit byte-swap +;; and the native-endian value will end up in the high bytes where we need it +;; to perform the operation. +(rule (atomic_rmw_body_addsub ib $I16 (littleendian) op tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 16)) + (val_swapped Reg (push_bswap_reg ib $I32 tmp val)) + (res_swapped Reg (push_alu_reg ib op tmp val_swapped src_shifted))) + (push_bswap_reg ib $I32 tmp res_swapped))) + +;; Loop bodies for atomic MIN/MAX operations. +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smin) tmp val src) + (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty)) + (intcc_as_cond (IntCC.SignedLessThan)) tmp val src)) +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smax) tmp val src) + (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty)) + (intcc_as_cond (IntCC.SignedGreaterThan)) tmp val src)) +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umin) tmp val src) + (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty)) + (intcc_as_cond (IntCC.UnsignedLessThan)) tmp val src)) +(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umax) tmp val src) + (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty)) + (intcc_as_cond (IntCC.UnsignedGreaterThan)) tmp val src)) + +;; Minimum or maximum operation. +(decl atomic_rmw_body_minmax (VecMInstBuilder Type MemFlags CmpOp Cond + WritableReg Reg Reg) Reg) +;; 32/64-bit big-endian case: just a comparison followed by a conditional +;; break out of the loop if the memory value does not need to change. +;; If it does need to change, the new value is simply the source operand. +(rule 2 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (bigendian) + op cond tmp val src) + (let ((_ Reg (push_break_if ib (cmp_rr op src val) (invert_cond cond)))) + src)) +;; 32/64-bit little-endian case: similar, but we need to byte-swap the +;; memory value before the comparison. If we need to store the new value, +;; it also needs to be byte-swapped. +(rule 1 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (littleendian) + op cond tmp val src) + (let ((val_swapped Reg (push_bswap_reg ib ty tmp val)) + (_ Reg (push_break_if ib (cmp_rr op src val_swapped) + (invert_cond cond)))) + (push_bswap_reg ib ty tmp src))) +;; 8-bit case: compare the memory value (which contains the target in the +;; high byte) with the source operand shifted by 24 bits. Note that in +;; the case where the high bytes are equal, the comparison may succeed +;; or fail depending on the unrelated low bits of the memory value, and +;; so we either may or may not perform the update. But it would be an +;; update with the same value in any case, so this does not matter. +(rule (atomic_rmw_body_minmax ib $I8 _ op cond tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 24)) + (_ Reg (push_break_if ib (cmp_rr op src_shifted val) + (invert_cond cond)))) + (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 40 0))) +;; 16-bit big-endian case: similar, just shift the source by 16 bits. +(rule 3 (atomic_rmw_body_minmax ib $I16 (bigendian) op cond tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 16)) + (_ Reg (push_break_if ib (cmp_rr op src_shifted val) + (invert_cond cond)))) + (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 48 0))) +;; 16-bit little-endian case: similar, but in addition byte-swap the +;; memory value before and after the operation, like for _addsub_. +(rule (atomic_rmw_body_minmax ib $I16 (littleendian) op cond tmp val src) + (let ((src_shifted Reg (lshl_imm $I32 src 16)) + (val_swapped Reg (push_bswap_reg ib $I32 tmp val)) + (_ Reg (push_break_if ib (cmp_rr op src_shifted val_swapped) + (invert_cond cond))) + (res_swapped Reg (push_rxsbg ib (RxSBGOp.Insert) + tmp val_swapped src_shifted 32 48 0))) + (push_bswap_reg ib $I32 tmp res_swapped))) + + +;;;; Rules for `atomic_cas` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 32/64-bit big-endian atomic compare-and-swap instruction. +(rule 2 (lower (has_type (ty_32_or_64 ty) + (atomic_cas flags @ (bigendian) addr src1 src2))) + (atomic_cas_impl ty (put_in_reg src1) (put_in_reg src2) + (lower_address flags addr (zero_offset)))) + +;; 32/64-bit little-endian atomic compare-and-swap instruction. +;; Implemented by byte-swapping old/new inputs and the output. +(rule 1 (lower (has_type (ty_32_or_64 ty) + (atomic_cas flags @ (littleendian) addr src1 src2))) + (bswap_reg ty (atomic_cas_impl ty (bswap_reg ty (put_in_reg src1)) + (bswap_reg ty (put_in_reg src2)) + (lower_address flags addr (zero_offset))))) + +;; 8/16-bit atomic compare-and-swap implemented via loop. +(rule (lower (has_type (ty_8_or_16 ty) (atomic_cas flags addr src1 src2))) + (let ((src1_reg Reg (put_in_reg src1)) + (src2_reg Reg (put_in_reg src2)) + (addr_reg Reg (put_in_reg addr)) + ;; Prepare access to the surrounding aligned word. + (bitshift Reg (casloop_bitshift addr_reg)) + (aligned_addr Reg (casloop_aligned_addr addr_reg)) + ;; Create body of compare-and-swap loop. + (ib VecMInstBuilder (inst_builder_new)) + (val0 Reg (writable_reg_to_reg (casloop_val_reg))) + (val1 Reg (casloop_rotate_in ib ty flags bitshift val0)) + (val2 Reg (atomic_cas_body ib ty flags + (casloop_tmp_reg) val1 src1_reg src2_reg)) + (val3 Reg (casloop_rotate_out ib ty flags bitshift val2))) + ;; Emit compare-and-swap loop and extract final result. + (casloop_subword ib ty flags aligned_addr bitshift val3))) + +;; Emit loop body instructions to perform a subword compare-and-swap. +(decl atomic_cas_body (VecMInstBuilder Type MemFlags + WritableReg Reg Reg Reg) Reg) + +;; 8-bit case: "val" contains the value loaded from memory in the high byte. +;; Compare with the comparison value in the low byte of "src1". If unequal, +;; break out of the loop, otherwise replace the target byte in "val" with +;; the low byte of "src2". +(rule (atomic_cas_body ib $I8 _ tmp val src1 src2) + (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 40 24) + (intcc_as_cond (IntCC.NotEqual))))) + (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 40 24))) + +;; 16-bit big-endian case: Same as above, except with values in the high +;; two bytes of "val" and low two bytes of "src1" and "src2". +(rule 1 (atomic_cas_body ib $I16 (bigendian) tmp val src1 src2) + (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 48 16) + (intcc_as_cond (IntCC.NotEqual))))) + (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 48 16))) + +;; 16-bit little-endian case: "val" here contains a little-endian value in the +;; *low* two bytes. "src1" and "src2" contain native (i.e. big-endian) values +;; in their low two bytes. Perform the operation in little-endian mode by +;; byte-swapping "src1" and "src" ahead of the loop. Note that this is a +;; 32-bit operation so the little-endian 16-bit values end up in the *high* +;; two bytes of the swapped values. +(rule (atomic_cas_body ib $I16 (littleendian) tmp val src1 src2) + (let ((src1_swapped Reg (bswap_reg $I32 src1)) + (src2_swapped Reg (bswap_reg $I32 src2)) + (_ Reg (push_break_if ib + (rxsbg_test (RxSBGOp.Xor) val src1_swapped 48 64 -16) + (intcc_as_cond (IntCC.NotEqual))))) + (push_rxsbg ib (RxSBGOp.Insert) tmp val src2_swapped 48 64 -16))) + + +;;;; Rules for `atomic_load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Atomic loads can be implemented via regular loads on this platform. + +;; 8-bit atomic load. +(rule (lower (has_type $I8 (atomic_load flags addr))) + (zext32_mem $I8 (lower_address flags addr (zero_offset)))) + +;; 16-bit big-endian atomic load. +(rule 1 (lower (has_type $I16 (atomic_load flags @ (bigendian) addr))) + (zext32_mem $I16 (lower_address flags addr (zero_offset)))) + +;; 16-bit little-endian atomic load. +(rule (lower (has_type $I16 (atomic_load flags @ (littleendian) addr))) + (loadrev16 (lower_address flags addr (zero_offset)))) + +;; 32-bit big-endian atomic load. +(rule 1 (lower (has_type $I32 (atomic_load flags @ (bigendian) addr))) + (load32 (lower_address flags addr (zero_offset)))) + +;; 32-bit little-endian atomic load. +(rule (lower (has_type $I32 (atomic_load flags @ (littleendian) addr))) + (loadrev32 (lower_address flags addr (zero_offset)))) + +;; 64-bit big-endian atomic load. +(rule 1 (lower (has_type $I64 (atomic_load flags @ (bigendian) addr))) + (load64 (lower_address flags addr (zero_offset)))) + +;; 64-bit little-endian atomic load. +(rule (lower (has_type $I64 (atomic_load flags @ (littleendian) addr))) + (loadrev64 (lower_address flags addr (zero_offset)))) + + +;;;; Rules for `atomic_store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Atomic stores can be implemented via regular stores followed by a fence. +(decl atomic_store_impl (SideEffectNoResult) InstOutput) +(rule (atomic_store_impl store) + (let ((_ InstOutput (side_effect store))) + (side_effect (fence_impl)))) + +;; 8-bit atomic store. +(rule (lower (atomic_store flags val @ (value_type $I8) addr)) + (atomic_store_impl (istore8_impl flags val addr (zero_offset)))) + +;; 16-bit atomic store. +(rule (lower (atomic_store flags val @ (value_type $I16) addr)) + (atomic_store_impl (istore16_impl flags val addr (zero_offset)))) + +;; 32-bit atomic store. +(rule (lower (atomic_store flags val @ (value_type $I32) addr)) + (atomic_store_impl (istore32_impl flags val addr (zero_offset)))) + +;; 64-bit atomic store. +(rule (lower (atomic_store flags val @ (value_type $I64) addr)) + (atomic_store_impl (istore64_impl flags val addr (zero_offset)))) + + +;;;; Rules for `fence` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Fence to ensure sequential consistency. +(rule (lower (fence)) + (side_effect (fence_impl))) + + +;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We want to optimize the typical use of `icmp` (generating an integer 0/1 +;; result) followed by some user, like a `select` or a conditional branch. +;; Instead of first generating the integer result and later testing it again, +;; we want to sink the comparison to be performed at the site of use. +;; +;; To enable this, we provide generic helpers that return a `ProducesBool` +;; encapsulating the comparison in question, which can be used by all the +;; above scenarios. +;; +;; N.B. There are specific considerations when sinking a memory load into a +;; comparison. When emitting an `icmp` directly, this can of course be done +;; as usual. However, when we use the `ProducesBool` elsewhere, we need to +;; consider *three* instructions: the load, the `icmp`, and the final user +;; (e.g. a conditional branch). The only way to safely sink the load would +;; be to sink it direct into the final user, which is only possible if there +;; is no *other* user of the `icmp` result. This is not currently being +;; verified by the `SinkableInst` logic, so to be safe we do not perform this +;; optimization at all. +;; +;; The generic `icmp_val` helper therefore has a flag indicating whether +;; it is being invoked in a context where it is safe to sink memory loads +;; (e.g. when directly emitting an `icmp`), or whether it is not (e.g. when +;; sinking the `icmp` result into a conditional branch or select). + +;; Main `icmp` entry point. Generate a `ProducesBool` capturing the +;; integer comparison and immediately lower it to a 0/1 integer result. +;; In this case, it is safe to sink memory loads. +(rule -1 (lower (has_type (fits_in_64 ty) (icmp int_cc x y))) + (lower_bool ty (icmp_val true int_cc x y))) + + +;; Return a `ProducesBool` to implement any integer comparison. +;; The first argument is a flag to indicate whether it is safe to sink +;; memory loads as discussed above. +(decl icmp_val (bool IntCC Value Value) ProducesBool) + +;; Dispatch for signed comparisons. +(rule -1 (icmp_val allow_mem int_cc @ (signed) x @ (value_type (fits_in_64 _)) y) + (bool (icmps_val allow_mem x y) (intcc_as_cond int_cc))) +;; Dispatch for unsigned comparisons. +(rule -2 (icmp_val allow_mem int_cc @ (unsigned) x @ (value_type (fits_in_64 _)) y) + (bool (icmpu_val allow_mem x y) (intcc_as_cond int_cc))) + + +;; Return a `ProducesBool` to implement signed integer comparisons. +(decl icmps_val (bool Value Value) ProducesFlags) + +;; Compare (signed) two registers. +(rule 0 (icmps_val _ x @ (value_type (fits_in_64 ty)) y) + (icmps_reg (ty_ext32 ty) (put_in_reg_sext32 x) (put_in_reg_sext32 y))) + +;; Compare (signed) a register and a sign-extended register. +(rule 3 (icmps_val _ x @ (value_type (fits_in_64 ty)) (sext32_value y)) + (icmps_reg_sext32 ty x y)) + +;; Compare (signed) a register and an immediate. +(rule 2 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i16_from_value y)) + (icmps_simm16 (ty_ext32 ty) (put_in_reg_sext32 x) y)) +(rule 1 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i32_from_value y)) + (icmps_simm32 (ty_ext32 ty) (put_in_reg_sext32 x) y)) + +;; Compare (signed) a register and memory (32/64-bit types). +(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y)) + (icmps_mem ty x (sink_load y))) + +;; Compare (signed) a register and memory (16-bit types). +(rule 5 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_16 y)) + (icmps_mem_sext16 (ty_ext32 ty) (put_in_reg_sext32 x) (sink_load y))) + +;; Compare (signed) a register and sign-extended memory. +(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload16 y)) + (icmps_mem_sext16 ty x (sink_sload16 y))) +(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload32 y)) + (icmps_mem_sext32 ty x (sink_sload32 y))) + + +;; Return a `ProducesBool` to implement unsigned integer comparisons. +(decl icmpu_val (bool Value Value) ProducesFlags) + +;; Compare (unsigned) two registers. +(rule (icmpu_val _ x @ (value_type (fits_in_64 ty)) y) + (icmpu_reg (ty_ext32 ty) (put_in_reg_zext32 x) (put_in_reg_zext32 y))) + +;; Compare (unsigned) a register and a sign-extended register. +(rule 1 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (zext32_value y)) + (icmpu_reg_zext32 ty x y)) + +;; Compare (unsigned) a register and an immediate. +(rule 2 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (u32_from_value y)) + (icmpu_uimm32 (ty_ext32 ty) (put_in_reg_zext32 x) y)) + +;; Compare (unsigned) a register and memory (32/64-bit types). +(rule 4 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y)) + (icmpu_mem ty x (sink_load y))) + +;; Compare (unsigned) a register and memory (16-bit types). +;; Note that the ISA only provides instructions with a PC-relative memory +;; address here, so we need to check whether the sinkable load matches this. +(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) + (sinkable_load_16 ld)) + (if-let y (load_sym ld)) + (icmpu_mem_zext16 (ty_ext32 ty) (put_in_reg_zext32 x) (sink_load y))) + +;; Compare (unsigned) a register and zero-extended memory. +;; Note that the ISA only provides instructions with a PC-relative memory +;; address here, so we need to check whether the sinkable load matches this. +(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) + (sinkable_uload16 ld)) + (if-let y (uload16_sym ld)) + (icmpu_mem_zext16 ty x (sink_uload16 y))) +(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_uload32 y)) + (icmpu_mem_zext32 ty x (sink_uload32 y))) + + +;; Compare 128-bit integers for equality. +;; Implemented via element-wise comparison using the all-element true CC flag. +(rule (icmp_val _ (IntCC.Equal) x @ (value_type (vr128_ty _)) y) + (bool (vec_cmpeqs $I64X2 x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (icmp_val _ (IntCC.NotEqual) x @ (value_type (vr128_ty _)) y) + (bool (vec_cmpeqs $I64X2 x y) + (floatcc_as_cond (FloatCC.NotEqual)))) + +;; Compare (signed) 128-bit integers for relational inequality. +;; Implemented via synthetic instruction using VECG and VCHLGS. +(rule (icmp_val _ (IntCC.SignedGreaterThan) x @ (value_type (vr128_ty ty)) y) + (vec_int128_scmphi x y)) +(rule (icmp_val _ (IntCC.SignedLessThan) x @ (value_type (vr128_ty ty)) y) + (vec_int128_scmphi y x)) +(rule (icmp_val _ (IntCC.SignedGreaterThanOrEqual) x @ (value_type (vr128_ty ty)) y) + (invert_bool (vec_int128_scmphi y x))) +(rule (icmp_val _ (IntCC.SignedLessThanOrEqual) x @ (value_type (vr128_ty ty)) y) + (invert_bool (vec_int128_scmphi x y))) + +;; Compare (unsigned) 128-bit integers for relational inequality. +;; Implemented via synthetic instruction using VECLG and VCHLGS. +(rule (icmp_val _ (IntCC.UnsignedGreaterThan) x @ (value_type (vr128_ty ty)) y) + (vec_int128_ucmphi x y)) +(rule (icmp_val _ (IntCC.UnsignedLessThan) x @ (value_type (vr128_ty ty)) y) + (vec_int128_ucmphi y x)) +(rule (icmp_val _ (IntCC.UnsignedGreaterThanOrEqual) x @ (value_type (vr128_ty ty)) y) + (invert_bool (vec_int128_ucmphi y x))) +(rule (icmp_val _ (IntCC.UnsignedLessThanOrEqual) x @ (value_type (vr128_ty ty)) y) + (invert_bool (vec_int128_ucmphi x y))) + + +;; Vector `icmp` produces a boolean vector. +;; We need to handle the various IntCC flags separately here. + +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.Equal) x y))) + (vec_cmpeq ty x y)) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.NotEqual) x y))) + (vec_not ty (vec_cmpeq ty x y))) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.SignedGreaterThan) x y))) + (vec_cmph ty x y)) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.SignedLessThanOrEqual) x y))) + (vec_not ty (vec_cmph ty x y))) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.SignedLessThan) x y))) + (vec_cmph ty y x)) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.SignedGreaterThanOrEqual) x y))) + (vec_not ty (vec_cmph ty y x))) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.UnsignedGreaterThan) x y))) + (vec_cmphl ty x y)) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.UnsignedLessThanOrEqual) x y))) + (vec_not ty (vec_cmphl ty x y))) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.UnsignedLessThan) x y))) + (vec_cmphl ty y x)) +(rule (lower (has_type (ty_vec128 ty) (icmp (IntCC.UnsignedGreaterThanOrEqual) x y))) + (vec_not ty (vec_cmphl ty y x))) + + +;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `fcmp` entry point. Generate a `ProducesBool` capturing the +;; integer comparison and immediately lower it to a 0/1 integer result. +(rule -1 (lower (has_type (fits_in_64 ty) (fcmp float_cc x y))) + (lower_bool ty (fcmp_val float_cc x y))) + +;; Return a `ProducesBool` to implement any floating-point comparison. +(decl fcmp_val (FloatCC Value Value) ProducesBool) +(rule (fcmp_val float_cc x @ (value_type ty) y) + (bool (fcmp_reg ty x y) + (floatcc_as_cond float_cc))) + +;; Vector `fcmp` produces a boolean vector. +;; We need to handle the various FloatCC flags separately here. + +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.Equal) x y))) + (vec_fcmpeq ty x y)) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.NotEqual) x y))) + (vec_not ty (vec_fcmpeq ty x y))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.GreaterThan) x y))) + (vec_fcmph ty x y)) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.UnorderedOrLessThanOrEqual) x y))) + (vec_not ty (vec_fcmph ty x y))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.GreaterThanOrEqual) x y))) + (vec_fcmphe ty x y)) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.UnorderedOrLessThan) x y))) + (vec_not ty (vec_fcmphe ty x y))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.LessThan) x y))) + (vec_fcmph ty y x)) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) + (vec_not ty (vec_fcmph ty y x))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.LessThanOrEqual) x y))) + (vec_fcmphe ty y x)) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.UnorderedOrGreaterThan) x y))) + (vec_not ty (vec_fcmphe ty y x))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.Ordered) x y))) + (vec_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.Unordered) x y))) + (vec_not_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.OrderedNotEqual) x y))) + (vec_or ty (vec_fcmph ty x y) (vec_fcmph ty y x))) +(rule (lower (has_type (ty_vec128 ty) (fcmp (FloatCC.UnorderedOrEqual) x y))) + (vec_not_or ty (vec_fcmph ty x y) (vec_fcmph ty y x))) + + +;;;; Rules for `vall_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `vall_true` entry point. Generate a `ProducesBool` capturing the +;; comparison and immediately lower it to a 0/1 integer result. +(rule (lower (has_type (fits_in_64 ty) (vall_true x))) + (lower_bool ty (vall_true_val x))) + +;; Return a `ProducesBool` to implement `vall_true`. +(decl vall_true_val (Value) ProducesBool) +(rule -1 (vall_true_val x @ (value_type ty)) + (bool (vec_cmpeqs ty x (vec_imm ty 0)) + (floatcc_as_cond (FloatCC.Unordered)))) + +;; Short-circuit `vall_true` on the result of a `icmp`. +(rule (vall_true_val (has_type ty (icmp (IntCC.Equal) x y))) + (bool (vec_cmpeqs ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.NotEqual) x y))) + (bool (vec_cmpeqs ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.SignedGreaterThan) x y))) + (bool (vec_cmphs ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.SignedLessThanOrEqual) x y))) + (bool (vec_cmphs ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.SignedLessThan) x y))) + (bool (vec_cmphs ty y x) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.SignedGreaterThanOrEqual) x y))) + (bool (vec_cmphs ty y x) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.UnsignedGreaterThan) x y))) + (bool (vec_cmphls ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.UnsignedLessThanOrEqual) x y))) + (bool (vec_cmphls ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.UnsignedLessThan) x y))) + (bool (vec_cmphls ty y x) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (icmp (IntCC.UnsignedGreaterThanOrEqual) x y))) + (bool (vec_cmphls ty y x) + (floatcc_as_cond (FloatCC.Unordered)))) + +;; Short-circuit `vall_true` on the result of a `fcmp` where possible. +(rule (vall_true_val (has_type ty (fcmp (FloatCC.Equal) x y))) + (bool (vec_fcmpeqs ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.NotEqual) x y))) + (bool (vec_fcmpeqs ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.GreaterThan) x y))) + (bool (vec_fcmphs ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.UnorderedOrLessThanOrEqual) x y))) + (bool (vec_fcmphs ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.GreaterThanOrEqual) x y))) + (bool (vec_fcmphes ty x y) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.UnorderedOrLessThan) x y))) + (bool (vec_fcmphes ty x y) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.LessThan) x y))) + (bool (vec_fcmphs ty y x) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) + (bool (vec_fcmphs ty y x) + (floatcc_as_cond (FloatCC.Unordered)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.LessThanOrEqual) x y))) + (bool (vec_fcmphes ty y x) + (floatcc_as_cond (FloatCC.Equal)))) +(rule (vall_true_val (has_type ty (fcmp (FloatCC.UnorderedOrGreaterThan) x y))) + (bool (vec_fcmphes ty y x) + (floatcc_as_cond (FloatCC.Unordered)))) + + +;;;; Rules for `vany_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Main `vany_true` entry point. Generate a `ProducesBool` capturing the +;; comparison and immediately lower it to a 0/1 integer result. +(rule (lower (has_type (fits_in_64 ty) (vany_true x))) + (lower_bool ty (vany_true_val x))) + +;; Return a `ProducesBool` to implement `vany_true`. +(decl vany_true_val (Value) ProducesBool) +(rule -1 (vany_true_val x @ (value_type ty)) + (bool (vec_cmpeqs ty x (vec_imm ty 0)) + (floatcc_as_cond (FloatCC.NotEqual)))) + +;; Short-circuit `vany_true` on the result of a `icmp`. +(rule (vany_true_val (has_type ty (icmp (IntCC.Equal) x y))) + (bool (vec_cmpeqs ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.NotEqual) x y))) + (bool (vec_cmpeqs ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.SignedGreaterThan) x y))) + (bool (vec_cmphs ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.SignedLessThanOrEqual) x y))) + (bool (vec_cmphs ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.SignedLessThan) x y))) + (bool (vec_cmphs ty y x) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.SignedGreaterThanOrEqual) x y))) + (bool (vec_cmphs ty y x) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.UnsignedGreaterThan) x y))) + (bool (vec_cmphls ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.UnsignedLessThanOrEqual) x y))) + (bool (vec_cmphls ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.UnsignedLessThan) x y))) + (bool (vec_cmphls ty y x) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (icmp (IntCC.UnsignedGreaterThanOrEqual) x y))) + (bool (vec_cmphls ty y x) + (floatcc_as_cond (FloatCC.NotEqual)))) + +;; Short-circuit `vany_true` on the result of a `fcmp` where possible. +(rule (vany_true_val (has_type ty (fcmp (FloatCC.Equal) x y))) + (bool (vec_fcmpeqs ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.NotEqual) x y))) + (bool (vec_fcmpeqs ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.GreaterThan) x y))) + (bool (vec_fcmphs ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.UnorderedOrLessThanOrEqual) x y))) + (bool (vec_fcmphs ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.GreaterThanOrEqual) x y))) + (bool (vec_fcmphes ty x y) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.UnorderedOrLessThan) x y))) + (bool (vec_fcmphes ty x y) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.LessThan) x y))) + (bool (vec_fcmphs ty y x) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) + (bool (vec_fcmphs ty y x) + (floatcc_as_cond (FloatCC.NotEqual)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.LessThanOrEqual) x y))) + (bool (vec_fcmphes ty y x) + (floatcc_as_cond (FloatCC.Ordered)))) +(rule (vany_true_val (has_type ty (fcmp (FloatCC.UnorderedOrGreaterThan) x y))) + (bool (vec_fcmphes ty y x) + (floatcc_as_cond (FloatCC.NotEqual)))) + + +;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (vhigh_bits x @ (value_type (multi_lane 8 16)))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 0 8 16 24 32 40 48 56 + 64 72 80 88 96 104 112 120)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) +(rule 1 (lower (vhigh_bits x @ (value_type (multi_lane 8 16)))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 120 112 104 96 88 80 72 64 + 56 48 40 32 24 16 8 0)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) + +(rule (lower (vhigh_bits x @ (value_type (multi_lane 16 8)))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 0 16 32 48 64 80 96 112)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) +(rule 1 (lower (vhigh_bits x @ (value_type (multi_lane 16 8)))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 112 96 80 64 48 32 16 0)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) + +(rule (lower (vhigh_bits x @ (value_type (multi_lane 32 4)))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 128 128 128 128 0 32 64 96)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) +(rule 1 (lower (vhigh_bits x @ (value_type (multi_lane 32 4)))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 128 128 128 128 96 64 32 0)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) + +(rule (lower (vhigh_bits x @ (value_type (multi_lane 64 2)))) + (if-let (LaneOrder.LittleEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 128 128 128 128 128 128 0 64)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) +(rule 1 (lower (vhigh_bits x @ (value_type (multi_lane 64 2)))) + (if-let (LaneOrder.BigEndian) (lane_order)) + (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 + 128 128 128 128 128 128 64 0)))) + (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) + + +;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Return a `ProducesBool` to capture the fact that the input value is nonzero. +;; In the common case where that input is the result of an `icmp` or `fcmp` +;; instruction, directly use that compare. Note that it is not safe to sink +;; memory loads here, see the `icmp` comment. +(decl value_nonzero (Value) ProducesBool) +(rule (value_nonzero (icmp int_cc x y)) (icmp_val false int_cc x y)) +(rule (value_nonzero (fcmp float_cc x y)) (fcmp_val float_cc x y)) +(rule -1 (value_nonzero val @ (value_type (gpr32_ty ty))) + (bool (icmps_simm16 $I32 (put_in_reg_sext32 val) 0) + (intcc_as_cond (IntCC.NotEqual)))) +(rule -2 (value_nonzero val @ (value_type (gpr64_ty ty))) + (bool (icmps_simm16 $I64 (put_in_reg val) 0) + (intcc_as_cond (IntCC.NotEqual)))) +(rule -3 (value_nonzero val @ (value_type (vr128_ty ty))) + (bool (vec_cmpeqs $I64X2 val (vec_imm $I64X2 0)) + (floatcc_as_cond (FloatCC.NotEqual)))) + +;; Main `select` entry point. Lower the `value_nonzero` result. +(rule (lower (has_type ty (select val_cond val_true val_false))) + (select_bool_reg ty (value_nonzero val_cond) + (put_in_reg val_true) (put_in_reg val_false))) + +;; Special-case some float-selection instructions for min/max +(rule 1 (lower (has_type (ty_scalar_float ty) (select (maybe_uextend (fcmp (FloatCC.LessThan) x y)) x y))) + (fmin_pseudo_reg ty y x)) +(rule 2 (lower (has_type (ty_scalar_float ty) (select (maybe_uextend (fcmp (FloatCC.LessThan) y x)) x y))) + (fmax_pseudo_reg ty y x)) + + +;;;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; We need to guarantee a conditional move instruction. But on this platform +;; this is already the best way to implement select in general, so the +;; implementation of `select_spectre_guard` is identical to `select`. +(rule (lower (has_type ty (select_spectre_guard + val_cond val_true val_false))) + (select_bool_reg ty (value_nonzero val_cond) + (put_in_reg val_true) (put_in_reg val_false))) + + +;;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unconditional branch. The target is found as first (and only) element in +;; the list of the current block's branch targets passed as `targets`. +(rule (lower_branch (jump _) (single_target label)) + (emit_side_effect (jump_impl label))) + + +;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Jump table. `targets` contains the default target followed by the +;; list of branch targets per index value. +(rule (lower_branch (br_table val_idx _) (jump_table_targets default targets)) + (let ((idx Reg (put_in_reg_zext64 val_idx)) + ;; Bounds-check the index and branch to default. + ;; This is an internal branch that is not a terminator insn. + ;; Instead, the default target is listed a potential target + ;; in the final JTSequence, which is the block terminator. + (cond ProducesBool + (bool (icmpu_uimm32 $I64 idx (jump_table_size targets)) + (intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual)))) + (_ Unit (emit_side_effect (oneway_cond_br_bool cond default)))) + ;; Scale the index by the element size, and then emit the + ;; compound instruction that does: + ;; + ;; larl %r1, + ;; agf %r1, 0(%r1, %rScaledIndex) + ;; br %r1 + ;; [jt entries] + ;; + ;; This must be *one* instruction in the vcode because + ;; we cannot allow regalloc to insert any spills/fills + ;; in the middle of the sequence; otherwise, the LARL's + ;; PC-rel offset to the jumptable would be incorrect. + ;; (The alternative is to introduce a relocation pass + ;; for inlined jumptables, which is much worse, IMHO.) + (emit_side_effect (jt_sequence (lshl_imm $I64 idx 2) targets)))) + + +;;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Two-way conditional branch on nonzero. `targets` contains: +;; - element 0: target if the condition is true (i.e. value is nonzero) +;; - element 1: target if the condition is false (i.e. value is zero) +(rule (lower_branch (brif val_cond _ _) (two_targets then else)) + (emit_side_effect (cond_br_bool (value_nonzero val_cond) then else))) + + +;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trap trap_code)) + (side_effect (trap_impl trap_code))) + + +;;;; Rules for `trapz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trapz val trap_code)) + (side_effect (trap_if_bool (invert_bool (value_nonzero val)) trap_code))) + + +;;;; Rules for `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trapnz val trap_code)) + (side_effect (trap_if_bool (value_nonzero val) trap_code))) + + +;;;; Rules for `debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (debugtrap)) + (side_effect (debugtrap_impl))) + +;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; UaddOverflowTrap is implemented via a ADD LOGICAL instruction, which sets the +;; the condition code as follows: +;; 0 Result zero; no carry +;; 1 Result not zero; no carry +;; 2 Result zero; carry +;; 3 Result not zero; carry +;; This means "carry" corresponds to condition code 2 or 3, i.e. +;; a condition mask of 2 | 1. +;; +;; As this does not match any of the encodings used with a normal integer +;; comparison, this cannot be represented by any IntCC value. We need to +;; remap the IntCC::UnsignedGreaterThan value that we have here as result +;; of the unsigned_add_overflow_condition call to the correct mask. + +(rule 0 (lower (has_type (fits_in_64 ty) (uadd_overflow_trap x y tc))) + (with_flags + (add_logical_reg_with_flags_paired ty x y) + (trap_if_impl (mask_as_cond 3) tc))) + +;; Add a register an a zero-extended register. +(rule 4 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap x (zext32_value y) tc))) + (with_flags + (add_logical_reg_zext32_with_flags_paired ty x y) + (trap_if_impl (mask_as_cond 3) tc))) +(rule 8 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (zext32_value x) y tc))) + (with_flags + (add_logical_reg_zext32_with_flags_paired ty y x) + (trap_if_impl (mask_as_cond 3) tc))) + +;; Add a register and an immediate +(rule 3 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap x (u32_from_value y) tc))) + (with_flags + (add_logical_zimm32_with_flags_paired ty x y) + (trap_if_impl (mask_as_cond 3) tc))) +(rule 7 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (u32_from_value x) y tc))) + (with_flags + (add_logical_zimm32_with_flags_paired ty y x) + (trap_if_impl (mask_as_cond 3) tc))) + +;; Add a register and memory (32/64-bit types). +(rule 2 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap x (sinkable_load_32_64 y) tc))) + (with_flags + (add_logical_mem_with_flags_paired ty x (sink_load y)) + (trap_if_impl (mask_as_cond 3) tc))) +(rule 6 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (sinkable_load_32_64 x) y tc))) + (with_flags + (add_logical_mem_with_flags_paired ty y (sink_load x)) + (trap_if_impl (mask_as_cond 3) tc))) + +;; Add a register and zero-extended memory. +(rule 1 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap x (sinkable_uload32 y) tc))) + (with_flags + (add_logical_mem_zext32_with_flags_paired ty x (sink_uload32 y)) + (trap_if_impl (mask_as_cond 3) tc))) +(rule 5 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (sinkable_uload32 x) y tc))) + (with_flags + (add_logical_mem_zext32_with_flags_paired ty y (sink_uload32 x)) + (trap_if_impl (mask_as_cond 3) tc))) + +;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (return args)) + (lower_return args)) + + +;;;; Rules for `call` and `call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Direct call to an in-range function. +(rule 1 (lower (call (func_ref_data sig_ref name (reloc_distance_near)) args)) + (let ((abi Sig (abi_sig sig_ref)) + (uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args)) + (defs CallRetList (defs_init abi)) + (_ InstOutput (side_effect (abi_call abi name uses defs)))) + (lower_call_rets abi defs (range (abi_first_ret sig_ref abi) + (abi_num_rets abi)) (output_builder_new)))) + +;; Direct call to an out-of-range function (implicitly via pointer). +(rule (lower (call (func_ref_data sig_ref name _) args)) + (let ((abi Sig (abi_sig sig_ref)) + (uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args)) + (defs CallRetList (defs_init abi)) + (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0))) + (_ InstOutput (side_effect (abi_call_ind abi target uses defs)))) + (lower_call_rets abi defs (range (abi_first_ret sig_ref abi) + (abi_num_rets abi)) (output_builder_new)))) + +;; Indirect call. +(rule (lower (call_indirect sig_ref ptr args)) + (let ((abi Sig (abi_sig sig_ref)) + (target Reg (put_in_reg ptr)) + (uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args)) + (defs CallRetList (defs_init abi)) + (_ InstOutput (side_effect (abi_call_ind abi target uses defs)))) + (lower_call_rets abi defs (range (abi_first_ret sig_ref abi) + (abi_num_rets abi)) (output_builder_new)))) + +;; Lower function arguments. +(decl lower_call_args (Sig Range ValueSlice) CallArgList) +(rule (lower_call_args abi range args) + (let ((uses CallArgListBuilder (args_builder_new)) + (stack MemArg (abi_call_stack_args abi)) + (_ InstOutput (lower_call_args_buffer abi stack range args)) + (_ InstOutput (lower_call_args_slots abi uses stack range args)) + (_ InstOutput (lower_call_ret_arg abi uses stack))) + (args_builder_finish uses))) + +;; Lower function return values by collecting them from registers / stack slots. +(decl lower_call_rets (Sig CallRetList Range InstOutputBuilder) InstOutput) +(rule (lower_call_rets abi _ (range_empty) builder) (output_builder_finish builder)) +(rule (lower_call_rets abi defs (range_unwrap head tail) builder) + (let ((ret ValueRegs (copy_from_arg defs (abi_lane_order abi) + (abi_call_stack_rets abi) + (abi_get_ret abi head))) + (_ Unit (output_builder_push builder ret))) + (lower_call_rets abi defs tail builder))) + + +;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;; + +;; Direct tail call to an in-range function. +(rule 1 (lower (return_call (func_ref_data sig_ref name (reloc_distance_near)) args)) + (let ((abi Sig (abi_sig sig_ref)) + (uses CallArgList (lower_return_call_args abi (range 0 (abi_num_args abi)) args))) + (side_effect (abi_return_call abi name uses)))) + +;; Direct tail call to an out-of-range function (implicitly via pointer). +(rule (lower (return_call (func_ref_data sig_ref name _) args)) + (let ((abi Sig (abi_sig sig_ref)) + (uses CallArgList (lower_return_call_args abi (range 0 (abi_num_args abi)) args)) + (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0)))) + (side_effect (abi_return_call_ind abi target uses)))) + +;; Indirect tail call. +(rule (lower (return_call_indirect sig_ref ptr args)) + (let ((abi Sig (abi_sig sig_ref)) + (target Reg (put_in_reg ptr)) + (uses CallArgList (lower_return_call_args abi (range 0 (abi_num_args abi)) args))) + (side_effect (abi_return_call_ind abi target uses)))) + +;; Lower tail call function arguments. +(decl lower_return_call_args (Sig Range ValueSlice) CallArgList) +(rule (lower_return_call_args abi range args) + (let ((uses CallArgListBuilder (args_builder_new)) + (stack MemArg (abi_return_call_stack_args abi)) + (_ InstOutput (lower_call_args_buffer abi stack range args)) + (_ InstOutput (lower_call_args_slots abi uses stack range args)) + (_ InstOutput (lower_return_call_ret_arg abi uses stack))) + (args_builder_finish uses))) + + +;;;; Common helpers for argument lowering ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Lower function arguments (part 1): prepare buffer copies. +(decl lower_call_args_buffer (Sig MemArg Range ValueSlice) InstOutput) +(rule (lower_call_args_buffer abi _ (range_empty) _) (output_none)) +(rule (lower_call_args_buffer abi stack (range_unwrap head tail) args) + (let ((_ InstOutput (copy_to_buffer stack (abi_get_arg abi head) + (value_slice_get args head)))) + (lower_call_args_buffer abi stack tail args))) + +;; Lower function arguments (part 2): set up registers / stack slots. +(decl lower_call_args_slots (Sig CallArgListBuilder MemArg Range ValueSlice) InstOutput) +(rule (lower_call_args_slots abi _ _ (range_empty) _) (output_none)) +(rule (lower_call_args_slots abi uses stack (range_unwrap head tail) args) + (let ((_ InstOutput (copy_to_arg uses (abi_lane_order abi) + stack (abi_get_arg abi head) + (value_slice_get args head)))) + (lower_call_args_slots abi uses stack tail args))) + +;; Lower function arguments (part 3): implicit return-area pointer (call). +(decl lower_call_ret_arg (Sig CallArgListBuilder MemArg) InstOutput) +(rule (lower_call_ret_arg (abi_no_ret_arg) _ _) (output_none)) +(rule 1 (lower_call_ret_arg abi @ (abi_ret_arg (abi_arg_only_slot slot)) uses stack) + (copy_reg_to_arg_slot uses (abi_lane_order abi) + stack slot (load_addr (abi_call_stack_rets abi)))) + +;; Lower function arguments (part 3): implicit return-area pointer (return call). +(decl lower_return_call_ret_arg (Sig CallArgListBuilder MemArg) InstOutput) +(rule (lower_return_call_ret_arg (abi_no_ret_arg) _ _) (output_none)) +(rule 1 (lower_return_call_ret_arg abi @ (abi_ret_arg (abi_arg_only_slot slot)) uses stack) + (copy_reg_to_arg_slot uses (abi_lane_order abi) + stack slot (abi_unwrap_ret_area_ptr))) + + +;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;; + +(rule (lower (get_stack_pointer)) + (sp)) + +(rule (lower (get_frame_pointer)) + (load64 (memarg_frame_pointer_offset))) + +(rule (lower (get_return_address)) + (load64 (memarg_return_address_offset))) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.rs new file mode 100644 index 00000000000000..eea3c1fdc98538 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower.rs @@ -0,0 +1,30 @@ +//! Lowering rules for S390x. + +use crate::ir::Inst as IRInst; +use crate::isa::s390x::inst::Inst; +use crate::isa::s390x::S390xBackend; +use crate::machinst::{InstOutput, Lower, LowerBackend, MachLabel}; + +pub mod isle; + +//============================================================================= +// Lowering-backend trait implementation. + +impl LowerBackend for S390xBackend { + type MInst = Inst; + + fn lower(&self, ctx: &mut Lower, ir_inst: IRInst) -> Option { + isle::lower(ctx, self, ir_inst) + } + + fn lower_branch( + &self, + ctx: &mut Lower, + ir_inst: IRInst, + targets: &[MachLabel], + ) -> Option<()> { + isle::lower_branch(ctx, self, ir_inst, targets) + } + + type FactFlowState = (); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle.rs new file mode 100644 index 00000000000000..c65aa9c2184a66 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle.rs @@ -0,0 +1,1053 @@ +//! ISLE integration glue code for s390x lowering. + +// Pull in the ISLE generated code. +pub mod generated_code; + +use crate::ir::ExternalName; +// Types that the generated ISLE code uses via `use super::*`. +use crate::isa::s390x::abi::{S390xMachineDeps, REG_SAVE_AREA_SIZE}; +use crate::isa::s390x::inst::{ + gpr, stack_reg, writable_gpr, zero_reg, Cond, Inst as MInst, LaneOrder, MemArg, RegPair, + ReturnCallInfo, SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair, +}; +use crate::isa::s390x::S390xBackend; +use crate::machinst::isle::*; +use crate::machinst::{CallInfo, MachLabel, Reg}; +use crate::{ + ir::{ + condcodes::*, immediates::*, types::*, ArgumentExtension, ArgumentPurpose, AtomicRmwOp, + BlockCall, Endianness, Inst, InstructionData, KnownSymbol, MemFlags, Opcode, TrapCode, + Value, ValueList, + }, + isa::CallConv, + machinst::abi::ABIMachineSpec, + machinst::{ + ArgPair, CallArgList, CallArgPair, CallRetList, CallRetPair, InstOutput, MachInst, + VCodeConstant, VCodeConstantData, + }, +}; +use regalloc2::PReg; +use smallvec::smallvec; +use std::boxed::Box; +use std::cell::Cell; +use std::vec::Vec; + +type BoxCallInfo = Box>; +type BoxCallIndInfo = Box>; +type BoxReturnCallInfo = Box>; +type BoxReturnCallIndInfo = Box>; +type VecMachLabel = Vec; +type BoxExternalName = Box; +type BoxSymbolReloc = Box; +type VecMInst = Vec; +type VecMInstBuilder = Cell>; +type VecArgPair = Vec; +type CallArgListBuilder = Cell; + +/// The main entry point for lowering with ISLE. +pub(crate) fn lower( + lower_ctx: &mut Lower, + backend: &S390xBackend, + inst: Inst, +) -> Option { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = IsleContext { lower_ctx, backend }; + generated_code::constructor_lower(&mut isle_ctx, inst) +} + +/// The main entry point for branch lowering with ISLE. +pub(crate) fn lower_branch( + lower_ctx: &mut Lower, + backend: &S390xBackend, + branch: Inst, + targets: &[MachLabel], +) -> Option<()> { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = IsleContext { lower_ctx, backend }; + generated_code::constructor_lower_branch(&mut isle_ctx, branch, targets) +} + +impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> { + isle_lower_prelude_methods!(); + + fn gen_return_call( + &mut self, + callee_sig: SigRef, + callee: ExternalName, + distance: RelocDistance, + args: ValueSlice, + ) -> InstOutput { + let _ = (callee_sig, callee, distance, args); + todo!() + } + + fn gen_return_call_indirect( + &mut self, + callee_sig: SigRef, + callee: Value, + args: ValueSlice, + ) -> InstOutput { + let _ = (callee_sig, callee, args); + todo!() + } + + #[inline] + fn args_builder_new(&mut self) -> CallArgListBuilder { + Cell::new(CallArgList::new()) + } + + #[inline] + fn args_builder_push( + &mut self, + builder: &CallArgListBuilder, + vreg: Reg, + preg: RealReg, + ) -> Unit { + let mut args = builder.take(); + args.push(CallArgPair { + vreg, + preg: preg.into(), + }); + builder.set(args); + } + + #[inline] + fn args_builder_finish(&mut self, builder: &CallArgListBuilder) -> CallArgList { + builder.take() + } + + fn defs_init(&mut self, abi: Sig) -> CallRetList { + // Allocate writable registers for all retval regs, except for StructRet args. + let mut defs = smallvec![]; + for i in 0..self.lower_ctx.sigs().num_rets(abi) { + if let &ABIArg::Slots { + ref slots, purpose, .. + } = &self.lower_ctx.sigs().get_ret(abi, i) + { + if purpose == ArgumentPurpose::StructReturn { + continue; + } + for slot in slots { + match slot { + &ABIArgSlot::Reg { reg, ty, .. } => { + let value_regs = self.lower_ctx.alloc_tmp(ty); + defs.push(CallRetPair { + vreg: value_regs.only_reg().unwrap(), + preg: reg.into(), + }); + } + _ => {} + } + } + } + } + defs + } + + fn defs_lookup(&mut self, defs: &CallRetList, reg: RealReg) -> Reg { + let reg = Reg::from(reg); + for def in defs { + if def.preg == reg { + return def.vreg.to_reg(); + } + } + unreachable!() + } + + fn abi_sig(&mut self, sig_ref: SigRef) -> Sig { + self.lower_ctx.sigs().abi_sig_for_sig_ref(sig_ref) + } + + fn abi_first_ret(&mut self, sig_ref: SigRef, abi: Sig) -> usize { + // Return the index of the first actual return value, excluding + // any StructReturn that might have been added to Sig. + let sig = &self.lower_ctx.dfg().signatures[sig_ref]; + self.lower_ctx.sigs().num_rets(abi) - sig.returns.len() + } + + fn abi_lane_order(&mut self, abi: Sig) -> LaneOrder { + lane_order_for_call_conv(self.lower_ctx.sigs()[abi].call_conv()) + } + + fn abi_call_stack_args(&mut self, abi: Sig) -> MemArg { + let sig_data = &self.lower_ctx.sigs()[abi]; + if sig_data.call_conv() != CallConv::Tail { + // System ABI: outgoing arguments are at the bottom of the + // caller's frame (register save area included in offsets). + let arg_space = sig_data.sized_stack_arg_space() as u32; + self.lower_ctx + .abi_mut() + .accumulate_outgoing_args_size(arg_space); + MemArg::reg_plus_off(stack_reg(), 0, MemFlags::trusted()) + } else { + // Tail-call ABI: outgoing arguments are at the top of the + // callee's frame; so we need to allocate that bit of this + // frame here, including a backchain copy if needed. + let arg_space = sig_data.sized_stack_arg_space() as u32; + if arg_space > 0 { + if self.backend.flags.preserve_frame_pointers() { + let tmp = self.lower_ctx.alloc_tmp(I64).only_reg().unwrap(); + let src_mem = MemArg::reg(stack_reg(), MemFlags::trusted()); + let dst_mem = MemArg::reg(stack_reg(), MemFlags::trusted()); + self.emit(&MInst::Load64 { + rd: tmp, + mem: src_mem, + }); + self.emit(&MInst::AllocateArgs { size: arg_space }); + self.emit(&MInst::Store64 { + rd: tmp.to_reg(), + mem: dst_mem, + }); + } else { + self.emit(&MInst::AllocateArgs { size: arg_space }); + } + } + MemArg::reg_plus_off(stack_reg(), arg_space.into(), MemFlags::trusted()) + } + } + + fn abi_call_stack_rets(&mut self, abi: Sig) -> MemArg { + let sig_data = &self.lower_ctx.sigs()[abi]; + if sig_data.call_conv() != CallConv::Tail { + // System ABI: buffer for outgoing return values is just above + // the outgoing arguments. + let arg_space = sig_data.sized_stack_arg_space() as u32; + let ret_space = sig_data.sized_stack_ret_space() as u32; + self.lower_ctx + .abi_mut() + .accumulate_outgoing_args_size(arg_space + ret_space); + MemArg::reg_plus_off(stack_reg(), arg_space.into(), MemFlags::trusted()) + } else { + // Tail-call ABI: buffer for outgoing return values is at the + // bottom of the caller's frame (above the register save area). + let ret_space = sig_data.sized_stack_ret_space() as u32; + self.lower_ctx + .abi_mut() + .accumulate_outgoing_args_size(REG_SAVE_AREA_SIZE + ret_space); + MemArg::NominalSPOffset { + off: REG_SAVE_AREA_SIZE as i64, + } + } + } + + fn abi_return_call_stack_args(&mut self, abi: Sig) -> MemArg { + // Tail calls: outgoing arguments at the top of the caller's frame. + // Create a backchain copy if needed to ensure correct stack unwinding + // during the tail-call sequence. + let sig_data = &self.lower_ctx.sigs()[abi]; + let arg_space = sig_data.sized_stack_arg_space() as u32; + self.lower_ctx + .abi_mut() + .accumulate_tail_args_size(arg_space); + if arg_space > 0 { + let tmp = self.lower_ctx.alloc_tmp(I64).only_reg().unwrap(); + let src_mem = MemArg::InitialSPOffset { off: 0 }; + let dst_mem = MemArg::InitialSPOffset { + off: -(arg_space as i64), + }; + self.emit(&MInst::Load64 { + rd: tmp, + mem: src_mem, + }); + self.emit(&MInst::Store64 { + rd: tmp.to_reg(), + mem: dst_mem, + }); + } + MemArg::InitialSPOffset { off: 0 } + } + + fn abi_call_info( + &mut self, + abi: Sig, + dest: ExternalName, + uses: &CallArgList, + defs: &CallRetList, + ) -> BoxCallInfo { + Box::new(self.abi_call_info_no_dest(abi, uses, defs).map(|()| dest)) + } + + fn abi_call_ind_info( + &mut self, + abi: Sig, + dest: Reg, + uses: &CallArgList, + defs: &CallRetList, + ) -> BoxCallIndInfo { + Box::new(self.abi_call_info_no_dest(abi, uses, defs).map(|()| dest)) + } + + fn abi_return_call_info( + &mut self, + abi: Sig, + name: ExternalName, + uses: &CallArgList, + ) -> BoxReturnCallInfo { + let sig_data = &self.lower_ctx.sigs()[abi]; + let callee_pop_size = sig_data.sized_stack_arg_space() as u32; + Box::new(ReturnCallInfo { + dest: name.clone(), + uses: uses.clone(), + callee_pop_size, + }) + } + + fn abi_return_call_ind_info( + &mut self, + abi: Sig, + target: Reg, + uses: &CallArgList, + ) -> BoxReturnCallIndInfo { + let sig_data = &self.lower_ctx.sigs()[abi]; + let callee_pop_size = sig_data.sized_stack_arg_space() as u32; + Box::new(ReturnCallInfo { + dest: target, + uses: uses.clone(), + callee_pop_size, + }) + } + + fn abi_for_elf_tls_get_offset(&mut self) { + self.lower_ctx + .abi_mut() + .accumulate_outgoing_args_size(REG_SAVE_AREA_SIZE); + } + + #[inline] + fn box_symbol_reloc(&mut self, symbol_reloc: &SymbolReloc) -> BoxSymbolReloc { + Box::new(symbol_reloc.clone()) + } + + #[inline] + fn mie2_enabled(&mut self, _: Type) -> Option<()> { + if self.backend.isa_flags.has_mie2() { + Some(()) + } else { + None + } + } + + #[inline] + fn mie2_disabled(&mut self, _: Type) -> Option<()> { + if !self.backend.isa_flags.has_mie2() { + Some(()) + } else { + None + } + } + + #[inline] + fn vxrs_ext2_enabled(&mut self, _: Type) -> Option<()> { + if self.backend.isa_flags.has_vxrs_ext2() { + Some(()) + } else { + None + } + } + + #[inline] + fn vxrs_ext2_disabled(&mut self, _: Type) -> Option<()> { + if !self.backend.isa_flags.has_vxrs_ext2() { + Some(()) + } else { + None + } + } + + #[inline] + fn writable_gpr(&mut self, regno: u8) -> WritableReg { + writable_gpr(regno) + } + + #[inline] + fn zero_reg(&mut self) -> Reg { + zero_reg() + } + + #[inline] + fn gpr32_ty(&mut self, ty: Type) -> Option { + match ty { + I8 | I16 | I32 => Some(ty), + _ => None, + } + } + + #[inline] + fn gpr64_ty(&mut self, ty: Type) -> Option { + match ty { + I64 => Some(ty), + _ => None, + } + } + + #[inline] + fn vr128_ty(&mut self, ty: Type) -> Option { + match ty { + I128 => Some(ty), + _ if ty.is_vector() && ty.bits() == 128 => Some(ty), + _ => None, + } + } + + #[inline] + fn uimm32shifted(&mut self, n: u32, shift: u8) -> UImm32Shifted { + UImm32Shifted::maybe_with_shift(n, shift).unwrap() + } + + #[inline] + fn uimm16shifted(&mut self, n: u16, shift: u8) -> UImm16Shifted { + UImm16Shifted::maybe_with_shift(n, shift).unwrap() + } + + #[inline] + fn i64_nonequal(&mut self, val: i64, cmp: i64) -> Option { + if val != cmp { + Some(val) + } else { + None + } + } + + #[inline] + fn u64_pair_split(&mut self, n: u128) -> (u64, u64) { + ((n >> 64) as u64, n as u64) + } + + #[inline] + fn u64_pair_concat(&mut self, hi: u64, lo: u64) -> u128 { + (hi as u128) << 64 | (lo as u128) + } + + #[inline] + fn u32_pair_split(&mut self, n: u64) -> (u32, u32) { + ((n >> 32) as u32, n as u32) + } + + #[inline] + fn u32_pair_concat(&mut self, hi: u32, lo: u32) -> u64 { + (hi as u64) << 32 | (lo as u64) + } + + #[inline] + fn u16_pair_split(&mut self, n: u32) -> (u16, u16) { + ((n >> 16) as u16, n as u16) + } + + #[inline] + fn u16_pair_concat(&mut self, hi: u16, lo: u16) -> u32 { + (hi as u32) << 16 | (lo as u32) + } + + #[inline] + fn u8_pair_split(&mut self, n: u16) -> (u8, u8) { + ((n >> 8) as u8, n as u8) + } + + #[inline] + fn u8_pair_concat(&mut self, hi: u8, lo: u8) -> u16 { + (hi as u16) << 8 | (lo as u16) + } + + #[inline] + fn u8_as_u16(&mut self, n: u8) -> u16 { + n as u16 + } + + #[inline] + fn u64_truncate_to_u32(&mut self, n: u64) -> u32 { + n as u32 + } + + #[inline] + fn u64_as_i16(&mut self, n: u64) -> i16 { + n as i16 + } + + #[inline] + fn u64_nonzero_hipart(&mut self, n: u64) -> Option { + let part = n & 0xffff_ffff_0000_0000; + if part != 0 { + Some(part) + } else { + None + } + } + + #[inline] + fn u64_nonzero_lopart(&mut self, n: u64) -> Option { + let part = n & 0x0000_0000_ffff_ffff; + if part != 0 { + Some(part) + } else { + None + } + } + + #[inline] + fn i32_from_u64(&mut self, n: u64) -> Option { + if let Ok(imm) = i32::try_from(n as i64) { + Some(imm) + } else { + None + } + } + + #[inline] + fn i16_from_u64(&mut self, n: u64) -> Option { + if let Ok(imm) = i16::try_from(n as i64) { + Some(imm) + } else { + None + } + } + + #[inline] + fn i16_from_u32(&mut self, n: u32) -> Option { + if let Ok(imm) = i16::try_from(n as i32) { + Some(imm) + } else { + None + } + } + + #[inline] + fn uimm32shifted_from_u64(&mut self, n: u64) -> Option { + UImm32Shifted::maybe_from_u64(n) + } + + #[inline] + fn uimm16shifted_from_u64(&mut self, n: u64) -> Option { + UImm16Shifted::maybe_from_u64(n) + } + + #[inline] + fn lane_order(&mut self) -> LaneOrder { + lane_order_for_call_conv(self.lower_ctx.abi().call_conv(self.lower_ctx.sigs())) + } + + #[inline] + fn be_lane_idx(&mut self, ty: Type, idx: u8) -> u8 { + match self.lane_order() { + LaneOrder::LittleEndian => ty.lane_count() as u8 - 1 - idx, + LaneOrder::BigEndian => idx, + } + } + + #[inline] + fn be_vec_const(&mut self, ty: Type, n: u128) -> u128 { + match self.lane_order() { + LaneOrder::LittleEndian => n, + LaneOrder::BigEndian => { + let lane_count = ty.lane_count(); + let lane_bits = ty.lane_bits(); + let lane_mask = (1u128 << lane_bits) - 1; + let mut n_le = n; + let mut n_be = 0u128; + for _ in 0..lane_count { + n_be = (n_be << lane_bits) | (n_le & lane_mask); + n_le = n_le >> lane_bits; + } + n_be + } + } + } + + #[inline] + fn lane_byte_mask(&mut self, ty: Type, idx: u8) -> u16 { + let lane_bytes = (ty.lane_bits() / 8) as u8; + let lane_mask = (1u16 << lane_bytes) - 1; + lane_mask << (16 - ((idx + 1) * lane_bytes)) + } + + #[inline] + fn shuffle_mask_from_u128(&mut self, idx: u128) -> (u128, u16) { + let bytes = match self.lane_order() { + LaneOrder::LittleEndian => idx.to_be_bytes().map(|x| { + if x < 16 { + 15 - x + } else if x < 32 { + 47 - x + } else { + 128 + } + }), + LaneOrder::BigEndian => idx.to_le_bytes().map(|x| if x < 32 { x } else { 128 }), + }; + let and_mask = bytes.iter().fold(0, |acc, &x| (acc << 1) | (x < 32) as u16); + let permute_mask = u128::from_be_bytes(bytes); + (permute_mask, and_mask) + } + + #[inline] + fn u64_from_value(&mut self, val: Value) -> Option { + let inst = self.lower_ctx.dfg().value_def(val).inst()?; + let constant = self.lower_ctx.get_constant(inst)?; + let ty = self.lower_ctx.output_ty(inst, 0); + Some(zero_extend_to_u64(constant, self.ty_bits(ty))) + } + + #[inline] + fn u64_from_inverted_value(&mut self, val: Value) -> Option { + let inst = self.lower_ctx.dfg().value_def(val).inst()?; + let constant = self.lower_ctx.get_constant(inst)?; + let ty = self.lower_ctx.output_ty(inst, 0); + Some(zero_extend_to_u64(!constant, self.ty_bits(ty))) + } + + #[inline] + fn u32_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_value(val)?; + let imm = u32::try_from(constant).ok()?; + Some(imm) + } + + #[inline] + fn u8_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_value(val)?; + let imm = u8::try_from(constant).ok()?; + Some(imm) + } + + #[inline] + fn u64_from_signed_value(&mut self, val: Value) -> Option { + let inst = self.lower_ctx.dfg().value_def(val).inst()?; + let constant = self.lower_ctx.get_constant(inst)?; + let ty = self.lower_ctx.output_ty(inst, 0); + Some(sign_extend_to_u64(constant, self.ty_bits(ty))) + } + + #[inline] + fn i64_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + Some(constant) + } + + #[inline] + fn i32_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = i32::try_from(constant).ok()?; + Some(imm) + } + + #[inline] + fn i16_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = i16::try_from(constant).ok()?; + Some(imm) + } + + #[inline] + fn i16_from_swapped_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = i16::try_from(constant).ok()?; + Some(imm.swap_bytes()) + } + + #[inline] + fn i64_from_negated_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = constant.wrapping_neg(); + Some(imm) + } + + #[inline] + fn i32_from_negated_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = i32::try_from(constant.wrapping_neg()).ok()?; + Some(imm) + } + + #[inline] + fn i16_from_negated_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_signed_value(val)? as i64; + let imm = i16::try_from(constant.wrapping_neg()).ok()?; + Some(imm) + } + + #[inline] + fn uimm16shifted_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_value(val)?; + UImm16Shifted::maybe_from_u64(constant) + } + + #[inline] + fn uimm32shifted_from_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_value(val)?; + UImm32Shifted::maybe_from_u64(constant) + } + + #[inline] + fn uimm16shifted_from_inverted_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_inverted_value(val)?; + let imm = UImm16Shifted::maybe_from_u64(constant)?; + Some(imm.negate_bits()) + } + + #[inline] + fn uimm32shifted_from_inverted_value(&mut self, val: Value) -> Option { + let constant = self.u64_from_inverted_value(val)?; + let imm = UImm32Shifted::maybe_from_u64(constant)?; + Some(imm.negate_bits()) + } + + #[inline] + fn len_minus_one(&mut self, len: u64) -> Option { + if len > 0 && len <= 256 { + Some((len - 1) as u8) + } else { + None + } + } + + #[inline] + fn mask_amt_imm(&mut self, ty: Type, amt: i64) -> u8 { + let mask = ty.lane_bits() - 1; + (amt as u8) & (mask as u8) + } + + #[inline] + fn mask_as_cond(&mut self, mask: u8) -> Cond { + Cond::from_mask(mask) + } + + #[inline] + fn intcc_as_cond(&mut self, cc: &IntCC) -> Cond { + Cond::from_intcc(*cc) + } + + #[inline] + fn floatcc_as_cond(&mut self, cc: &FloatCC) -> Cond { + Cond::from_floatcc(*cc) + } + + #[inline] + fn invert_cond(&mut self, cond: &Cond) -> Cond { + Cond::invert(*cond) + } + + #[inline] + fn signed(&mut self, cc: &IntCC) -> Option<()> { + if condcode_is_signed(*cc) { + Some(()) + } else { + None + } + } + + #[inline] + fn unsigned(&mut self, cc: &IntCC) -> Option<()> { + if !condcode_is_signed(*cc) { + Some(()) + } else { + None + } + } + + #[inline] + fn zero_offset(&mut self) -> Offset32 { + Offset32::new(0) + } + + #[inline] + fn i64_from_offset(&mut self, off: Offset32) -> i64 { + i64::from(off) + } + + #[inline] + fn fcvt_to_uint_ub32(&mut self, size: u8) -> u64 { + (2.0_f32).powi(size.into()).to_bits() as u64 + } + + #[inline] + fn fcvt_to_uint_lb32(&mut self) -> u64 { + (-1.0_f32).to_bits() as u64 + } + + #[inline] + fn fcvt_to_uint_ub64(&mut self, size: u8) -> u64 { + (2.0_f64).powi(size.into()).to_bits() + } + + #[inline] + fn fcvt_to_uint_lb64(&mut self) -> u64 { + (-1.0_f64).to_bits() + } + + #[inline] + fn fcvt_to_sint_ub32(&mut self, size: u8) -> u64 { + (2.0_f32).powi((size - 1).into()).to_bits() as u64 + } + + #[inline] + fn fcvt_to_sint_lb32(&mut self, size: u8) -> u64 { + let lb = (-2.0_f32).powi((size - 1).into()); + std::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits()) as u64 + } + + #[inline] + fn fcvt_to_sint_ub64(&mut self, size: u8) -> u64 { + (2.0_f64).powi((size - 1).into()).to_bits() + } + + #[inline] + fn fcvt_to_sint_lb64(&mut self, size: u8) -> u64 { + let lb = (-2.0_f64).powi((size - 1).into()); + std::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits()) + } + + #[inline] + fn littleendian(&mut self, flags: MemFlags) -> Option<()> { + let endianness = flags.endianness(Endianness::Big); + if endianness == Endianness::Little { + Some(()) + } else { + None + } + } + + #[inline] + fn bigendian(&mut self, flags: MemFlags) -> Option<()> { + let endianness = flags.endianness(Endianness::Big); + if endianness == Endianness::Big { + Some(()) + } else { + None + } + } + + #[inline] + fn memflags_trusted(&mut self) -> MemFlags { + MemFlags::trusted() + } + + #[inline] + fn memarg_flags(&mut self, mem: &MemArg) -> MemFlags { + mem.get_flags() + } + + #[inline] + fn memarg_offset(&mut self, base: &MemArg, offset: i64) -> MemArg { + MemArg::offset(base, offset) + } + + #[inline] + fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, bias: u8, flags: MemFlags) -> MemArg { + MemArg::BXD12 { + base: x, + index: y, + disp: UImm12::maybe_from_u64(bias as u64).unwrap(), + flags, + } + } + + #[inline] + fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, bias: u8, flags: MemFlags) -> MemArg { + MemArg::reg_plus_off(reg, off + (bias as i64), flags) + } + + #[inline] + fn memarg_symbol(&mut self, name: ExternalName, offset: i32, flags: MemFlags) -> MemArg { + MemArg::Symbol { + name: Box::new(name), + offset, + flags, + } + } + + #[inline] + fn memarg_got(&mut self) -> MemArg { + MemArg::Symbol { + name: Box::new(ExternalName::KnownSymbol(KnownSymbol::ElfGlobalOffsetTable)), + offset: 0, + flags: MemFlags::trusted(), + } + } + + #[inline] + fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option { + let off = i32::try_from(off1 + off2).ok()?; + if off & 1 == 0 { + Some(off) + } else { + None + } + } + + #[inline] + fn memarg_frame_pointer_offset(&mut self) -> MemArg { + // The frame pointer (back chain) is stored directly at SP. + MemArg::NominalSPOffset { off: 0 } + } + + #[inline] + fn memarg_return_address_offset(&mut self) -> MemArg { + // The return address is stored 14 pointer-sized slots above the initial SP. + MemArg::InitialSPOffset { off: 14 * 8 } + } + + #[inline] + fn inst_builder_new(&mut self) -> VecMInstBuilder { + Cell::new(Vec::::new()) + } + + #[inline] + fn inst_builder_push(&mut self, builder: &VecMInstBuilder, inst: &MInst) -> Unit { + let mut vec = builder.take(); + vec.push(inst.clone()); + builder.set(vec); + } + + #[inline] + fn inst_builder_finish(&mut self, builder: &VecMInstBuilder) -> Vec { + builder.take() + } + + #[inline] + fn real_reg(&mut self, reg: WritableReg) -> Option { + if reg.to_reg().is_real() { + Some(reg) + } else { + None + } + } + + #[inline] + fn same_reg(&mut self, dst: WritableReg, src: Reg) -> Option { + if dst.to_reg() == src { + Some(src) + } else { + None + } + } + + #[inline] + fn sinkable_inst(&mut self, val: Value) -> Option { + self.is_sinkable_inst(val) + } + + #[inline] + fn emit(&mut self, inst: &MInst) -> Unit { + self.lower_ctx.emit(inst.clone()); + } + + #[inline] + fn preg_stack(&mut self) -> PReg { + stack_reg().to_real_reg().unwrap().into() + } + + #[inline] + fn preg_gpr_0(&mut self) -> PReg { + gpr(0).to_real_reg().unwrap().into() + } + + #[inline] + fn writable_regpair(&mut self, hi: WritableReg, lo: WritableReg) -> WritableRegPair { + WritableRegPair { hi, lo } + } + + #[inline] + fn writable_regpair_hi(&mut self, w: WritableRegPair) -> WritableReg { + w.hi + } + + #[inline] + fn writable_regpair_lo(&mut self, w: WritableRegPair) -> WritableReg { + w.lo + } + + #[inline] + fn regpair(&mut self, hi: Reg, lo: Reg) -> RegPair { + RegPair { hi, lo } + } + + #[inline] + fn regpair_hi(&mut self, w: RegPair) -> Reg { + w.hi + } + + #[inline] + fn regpair_lo(&mut self, w: RegPair) -> Reg { + w.lo + } +} + +impl IsleContext<'_, '_, MInst, S390xBackend> { + fn abi_call_info_no_dest( + &mut self, + abi: Sig, + uses: &CallArgList, + defs: &CallRetList, + ) -> CallInfo<()> { + let sig_data = &self.lower_ctx.sigs()[abi]; + // Get clobbers: all caller-saves. These may include return value + // regs, which we will remove from the clobber set later. + let clobbers = S390xMachineDeps::get_regs_clobbered_by_call(sig_data.call_conv()); + let callee_pop_size = if sig_data.call_conv() == CallConv::Tail { + sig_data.sized_stack_arg_space() as u32 + } else { + 0 + }; + CallInfo { + dest: (), + uses: uses.clone(), + defs: defs.clone(), + clobbers, + callee_pop_size, + caller_conv: self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()), + callee_conv: self.lower_ctx.sigs()[abi].call_conv(), + } + } +} + +/// Lane order to be used for a given calling convention. +#[inline] +fn lane_order_for_call_conv(call_conv: CallConv) -> LaneOrder { + match call_conv { + CallConv::Tail => LaneOrder::LittleEndian, + _ => LaneOrder::BigEndian, + } +} + +/// Zero-extend the low `from_bits` bits of `value` to a full u64. +#[inline] +fn zero_extend_to_u64(value: u64, from_bits: u8) -> u64 { + assert!(from_bits <= 64); + if from_bits >= 64 { + value + } else { + value & ((1u64 << from_bits) - 1) + } +} + +/// Sign-extend the low `from_bits` bits of `value` to a full u64. +#[inline] +fn sign_extend_to_u64(value: u64, from_bits: u8) -> u64 { + assert!(from_bits <= 64); + if from_bits >= 64 { + value + } else { + (((value << (64 - from_bits)) as i64) >> (64 - from_bits)) as u64 + } +} + +/// Determines whether this condcode interprets inputs as signed or +/// unsigned. See the documentation for the `icmp` instruction in +/// cranelift-codegen/meta/src/shared/instructions.rs for further insights +/// into this. +#[inline] +fn condcode_is_signed(cc: IntCC) -> bool { + match cc { + IntCC::Equal => false, + IntCC::NotEqual => false, + IntCC::SignedGreaterThanOrEqual => true, + IntCC::SignedGreaterThan => true, + IntCC::SignedLessThanOrEqual => true, + IntCC::SignedLessThan => true, + IntCC::UnsignedGreaterThanOrEqual => false, + IntCC::UnsignedGreaterThan => false, + IntCC::UnsignedLessThanOrEqual => false, + IntCC::UnsignedLessThan => false, + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle/generated_code.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle/generated_code.rs new file mode 100644 index 00000000000000..c470bfdad4c6e7 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/lower/isle/generated_code.rs @@ -0,0 +1,14 @@ +// See https://github.com/rust-lang/rust/issues/47995: we cannot use `#![...]` attributes inside of +// the generated ISLE source below because we include!() it. We must include!() it because its path +// depends on an environment variable; and also because of this, we can't do the `#[path = "..."] +// mod generated_code;` trick either. +#![allow(dead_code, unreachable_code, unreachable_patterns)] +#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)] +#![allow( + irrefutable_let_patterns, + unused_assignments, + non_camel_case_types, + clippy::clone_on_copy +)] + +include!(concat!(env!("ISLE_DIR"), "/isle_s390x.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/mod.rs new file mode 100644 index 00000000000000..842cc4cdf11e66 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/mod.rs @@ -0,0 +1,220 @@ +//! IBM Z 64-bit Instruction Set Architecture. + +use crate::dominator_tree::DominatorTree; +use crate::ir::{Function, Type}; +use crate::isa::s390x::settings as s390x_settings; +#[cfg(feature = "unwind")] +use crate::isa::unwind::systemv::RegisterMappingError; +use crate::isa::{Builder as IsaBuilder, FunctionAlignment, TargetIsa}; +use crate::machinst::{ + compile, CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, + TextSectionBuilder, VCode, +}; +use crate::result::CodegenResult; +use crate::settings as shared_settings; +use alloc::{boxed::Box, vec::Vec}; +use core::fmt; +use cranelift_control::ControlPlane; +use target_lexicon::{Architecture, Triple}; + +// New backend: +mod abi; +pub(crate) mod inst; +mod lower; +mod settings; + +use self::inst::EmitInfo; + +/// A IBM Z backend. +pub struct S390xBackend { + triple: Triple, + flags: shared_settings::Flags, + isa_flags: s390x_settings::Flags, +} + +impl S390xBackend { + /// Create a new IBM Z backend with the given (shared) flags. + pub fn new_with_flags( + triple: Triple, + flags: shared_settings::Flags, + isa_flags: s390x_settings::Flags, + ) -> S390xBackend { + S390xBackend { + triple, + flags, + isa_flags, + } + } + + /// This performs lowering to VCode, register-allocates the code, computes block layout and + /// finalizes branches. The result is ready for binary emission. + fn compile_vcode( + &self, + func: &Function, + domtree: &DominatorTree, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<(VCode, regalloc2::Output)> { + let emit_info = EmitInfo::new(self.isa_flags.clone()); + let sigs = SigSet::new::(func, &self.flags)?; + let abi = abi::S390xCallee::new(func, self, &self.isa_flags, &sigs)?; + compile::compile::(func, domtree, self, abi, emit_info, sigs, ctrl_plane) + } +} + +impl TargetIsa for S390xBackend { + fn compile_function( + &self, + func: &Function, + domtree: &DominatorTree, + want_disasm: bool, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult { + let flags = self.flags(); + let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; + + let emit_result = vcode.emit(®alloc_result, want_disasm, flags, ctrl_plane); + let frame_size = emit_result.frame_size; + let value_labels_ranges = emit_result.value_labels_ranges; + let buffer = emit_result.buffer; + let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; + let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; + + if let Some(disasm) = emit_result.disasm.as_ref() { + log::debug!("disassembly:\n{}", disasm); + } + + Ok(CompiledCodeStencil { + buffer, + frame_size, + vcode: emit_result.disasm, + value_labels_ranges, + sized_stackslot_offsets, + dynamic_stackslot_offsets, + bb_starts: emit_result.bb_offsets, + bb_edges: emit_result.bb_edges, + }) + } + + fn name(&self) -> &'static str { + "s390x" + } + + fn triple(&self) -> &Triple { + &self.triple + } + + fn flags(&self) -> &shared_settings::Flags { + &self.flags + } + + fn isa_flags(&self) -> Vec { + self.isa_flags.iter().collect() + } + + fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 { + 16 + } + + #[cfg(feature = "unwind")] + fn emit_unwind_info( + &self, + result: &CompiledCode, + kind: crate::isa::unwind::UnwindInfoKind, + ) -> CodegenResult> { + use crate::isa::unwind::UnwindInfo; + use crate::isa::unwind::UnwindInfoKind; + Ok(match kind { + UnwindInfoKind::SystemV => { + let mapper = self::inst::unwind::systemv::RegisterMapper; + Some(UnwindInfo::SystemV( + crate::isa::unwind::systemv::create_unwind_info_from_insts( + &result.buffer.unwind_info[..], + result.buffer.data().len(), + &mapper, + )?, + )) + } + _ => None, + }) + } + + #[cfg(feature = "unwind")] + fn create_systemv_cie(&self) -> Option { + Some(inst::unwind::systemv::create_cie()) + } + + #[cfg(feature = "unwind")] + fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result { + inst::unwind::systemv::map_reg(reg).map(|reg| reg.0) + } + + fn text_section_builder(&self, num_funcs: usize) -> Box { + Box::new(MachTextSectionBuilder::::new(num_funcs)) + } + + fn function_alignment(&self) -> FunctionAlignment { + inst::Inst::function_alignment() + } + + fn page_size_align_log2(&self) -> u8 { + debug_assert_eq!(1 << 12, 0x1000); + 12 + } + + #[cfg(feature = "disas")] + fn to_capstone(&self) -> Result { + use capstone::prelude::*; + let mut cs = Capstone::new() + .sysz() + .mode(arch::sysz::ArchMode::Default) + .build()?; + + cs.set_skipdata(true)?; + + Ok(cs) + } + + fn has_native_fma(&self) -> bool { + true + } + + fn has_x86_blendv_lowering(&self, _: Type) -> bool { + false + } + + fn has_x86_pshufb_lowering(&self) -> bool { + false + } + + fn has_x86_pmulhrsw_lowering(&self) -> bool { + false + } + + fn has_x86_pmaddubsw_lowering(&self) -> bool { + false + } +} + +impl fmt::Display for S390xBackend { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MachBackend") + .field("name", &self.name()) + .field("triple", &self.triple()) + .field("flags", &format!("{}", self.flags())) + .finish() + } +} + +/// Create a new `isa::Builder`. +pub fn isa_builder(triple: Triple) -> IsaBuilder { + assert!(triple.architecture == Architecture::S390x); + IsaBuilder { + triple, + setup: s390x_settings::builder(), + constructor: |triple, shared_flags, builder| { + let isa_flags = s390x_settings::Flags::new(&shared_flags, builder); + let backend = S390xBackend::new_with_flags(triple, shared_flags, isa_flags); + Ok(backend.wrapped()) + }, + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/s390x/settings.rs b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/settings.rs new file mode 100644 index 00000000000000..69859cee4feb05 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/s390x/settings.rs @@ -0,0 +1,9 @@ +//! S390X Settings. + +use crate::settings::{self, detail, Builder, Value}; +use core::fmt; + +// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a +// public `Flags` struct with an impl for all of the settings defined in +// `cranelift-codegen/meta/src/isa/s390x/settings.rs`. +include!(concat!(env!("OUT_DIR"), "/settings-s390x.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/unwind.rs b/deps/crates/vendor/cranelift-codegen/src/isa/unwind.rs new file mode 100644 index 00000000000000..ada37b03ccbb33 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/unwind.rs @@ -0,0 +1,250 @@ +//! Represents information relating to function unwinding. + +use crate::machinst::RealReg; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +#[cfg(feature = "unwind")] +pub mod systemv; + +#[cfg(feature = "unwind")] +pub mod winx64; + +#[cfg(feature = "unwind")] +pub mod winarm64; + +/// CFA-based unwind information used on SystemV. +pub type CfaUnwindInfo = systemv::UnwindInfo; + +/// Expected unwind info type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum UnwindInfoKind { + /// No unwind info. + None, + /// SystemV CIE/FDE unwind info. + #[cfg(feature = "unwind")] + SystemV, + /// Windows X64 Unwind info + #[cfg(feature = "unwind")] + Windows, +} + +/// Represents unwind information for a single function. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[non_exhaustive] +pub enum UnwindInfo { + /// Windows x64 ABI unwind information. + #[cfg(feature = "unwind")] + WindowsX64(winx64::UnwindInfo), + /// System V ABI unwind information. + #[cfg(feature = "unwind")] + SystemV(CfaUnwindInfo), + /// Windows Arm64 ABI unwind information. + #[cfg(feature = "unwind")] + WindowsArm64(winarm64::UnwindInfo), +} + +/// Unwind pseudoinstruction used in VCode backends: represents that +/// at the present location, an action has just been taken. +/// +/// VCode backends always emit unwind info that is relative to a frame +/// pointer, because we are planning to allow for dynamic frame allocation, +/// and because it makes the design quite a lot simpler in general: we don't +/// have to be precise about SP adjustments throughout the body of the function. +/// +/// We include only unwind info for prologues at this time. Note that unwind +/// info for epilogues is only necessary if one expects to unwind while within +/// the last few instructions of the function (after FP has been restored) or +/// if one wishes to instruction-step through the epilogue and see a backtrace +/// at every point. This is not necessary for correct operation otherwise and so +/// we simplify the world a bit by omitting epilogue information. (Note that +/// some platforms also don't require or have a way to describe unwind +/// information for epilogues at all: for example, on Windows, the `UNWIND_INFO` +/// format only stores information for the function prologue.) +/// +/// Because we are defining an abstraction over multiple unwind formats (at +/// least Windows/fastcall and System V) and multiple architectures (at least +/// x86-64 and aarch64), we have to be a little bit flexible in how we describe +/// the frame. However, it turns out that a least-common-denominator prologue +/// works for all of the cases we have to worry about today! +/// +/// We assume the stack looks something like this: +/// +/// +/// ```plain +/// +----------------------------------------------+ +/// | stack arg area, etc (according to ABI) | +/// | ... | +/// SP at call --> +----------------------------------------------+ +/// | return address (pushed by HW or SW) | +/// +----------------------------------------------+ +/// | old frame pointer (FP) | +/// FP in this --> +----------------------------------------------+ +/// function | clobbered callee-save registers | +/// | ... | +/// start of --> +----------------------------------------------+ +/// clobbers | (rest of function's frame, irrelevant here) | +/// | ... | +/// SP in this --> +----------------------------------------------+ +/// function +/// ``` +/// +/// We assume that the prologue consists of: +/// +/// * `PushFrameRegs`: A push operation that adds the old FP to the stack (and +/// maybe the link register, on architectures that do not push return addresses +/// in hardware) +/// * `DefineFrame`: An update that sets FP to SP to establish a new frame +/// * `SaveReg`: A number of stores or pushes to the stack to save clobbered registers +/// +/// Each of these steps has a corresponding pseudo-instruction. At each step, +/// we need some information to determine where the current stack frame is +/// relative to SP or FP. When the `PushFrameRegs` occurs, we need to know how +/// much SP was decremented by, so we can allow the unwinder to continue to find +/// the caller's frame. When we define the new frame, we need to know where FP +/// is in relation to "SP at call" and also "start of clobbers", because +/// different unwind formats define one or the other of those as the anchor by +/// which we define the frame. Finally, when registers are saved, we need to +/// know which ones, and where. +/// +/// Different unwind formats work differently; here is a whirlwind tour of how +/// they define frames to help understanding: +/// +/// - Windows unwind information defines a frame that must start below the +/// clobber area, because all clobber-save offsets are non-negative. We set it +/// at the "start of clobbers" in the figure above. The `UNWIND_INFO` contains +/// a "frame pointer offset" field; when we define the new frame, the frame is +/// understood to be the value of FP (`RBP`) *minus* this offset. In other +/// words, the FP is *at the frame pointer offset* relative to the +/// start-of-clobber-frame. We use the "FP offset down to clobber area" offset +/// to generate this info. +/// +/// - System V unwind information defines a frame in terms of the CFA +/// (call-frame address), which is equal to the "SP at call" above. SysV +/// allows negative offsets, so there is no issue defining clobber-save +/// locations in terms of CFA. The format allows us to define CFA flexibly in +/// terms of any register plus an offset; we define it in terms of FP plus +/// the clobber-to-caller-SP offset once FP is established. +/// +/// Note that certain architectures impose limits on offsets: for example, on +/// Windows, the base of the clobber area must not be more than 240 bytes below +/// FP. +/// +/// Unwind pseudoinstructions are emitted inline by ABI code as it generates +/// a prologue. Thus, for the usual case, a prologue might look like (using x64 +/// as an example): +/// +/// ```plain +/// push rbp +/// unwind UnwindInst::PushFrameRegs { offset_upward_to_caller_sp: 16 } +/// mov rbp, rsp +/// unwind UnwindInst::DefineNewFrame { offset_upward_to_caller_sp: 16, +/// offset_downward_to_clobbers: 16 } +/// sub rsp, 32 +/// mov [rsp+16], r12 +/// unwind UnwindInst::SaveReg { reg: R12, clobber_offset: 0 } +/// mov [rsp+24], r13 +/// unwind UnwindInst::SaveReg { reg: R13, clobber_offset: 8 } +/// ... +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum UnwindInst { + /// The frame-pointer register for this architecture has just been pushed to + /// the stack (and on architectures where return-addresses are not pushed by + /// hardware, the link register as well). The FP has not been set to this + /// frame yet. The current location of SP is such that + /// `offset_upward_to_caller_sp` is the distance to SP-at-callsite (our + /// caller's frame). + PushFrameRegs { + /// The offset from the current SP (after push) to the SP at + /// caller's callsite. + offset_upward_to_caller_sp: u32, + }, + /// The frame-pointer register for this architecture has just been + /// set to the current stack location. We wish to define a new + /// frame that is anchored on this new FP value. Offsets are provided + /// upward to the caller's stack frame and downward toward the clobber + /// area. We expect this pseudo-op to come after `PushFrameRegs`. + DefineNewFrame { + /// The offset from the current SP and FP value upward to the value of + /// SP at the callsite that invoked us. + offset_upward_to_caller_sp: u32, + /// The offset from the current SP and FP value downward to the start of + /// the clobber area. + offset_downward_to_clobbers: u32, + }, + /// The stack pointer was adjusted to allocate the stack. + StackAlloc { + /// Size to allocate. + size: u32, + }, + /// The stack slot at the given offset from the clobber-area base has been + /// used to save the given register. + /// + /// Given that `CreateFrame` has occurred first with some + /// `offset_downward_to_clobbers`, `SaveReg` with `clobber_offset` indicates + /// that the value of `reg` is saved on the stack at address `FP - + /// offset_downward_to_clobbers + clobber_offset`. + SaveReg { + /// The offset from the start of the clobber area to this register's + /// stack location. + clobber_offset: u32, + /// The saved register. + reg: RealReg, + }, + /// Computes the value of the given register in the caller as stack offset. + /// Typically used to unwind the stack pointer if the default rule does not apply. + /// The `clobber_offset` is computed the same way as for the `SaveReg` rule. + RegStackOffset { + /// The offset from the start of the clobber area to this register's value. + clobber_offset: u32, + /// The register whose value is to be set. + reg: RealReg, + }, + /// Defines if the aarch64-specific pointer authentication available for ARM v8.3+ devices + /// is enabled for certain pointers or not. + Aarch64SetPointerAuth { + /// Whether return addresses (hold in LR) contain a pointer-authentication code. + return_addresses: bool, + }, +} + +struct Writer<'a> { + buf: &'a mut [u8], + offset: usize, +} + +impl<'a> Writer<'a> { + pub fn new(buf: &'a mut [u8]) -> Self { + Self { buf, offset: 0 } + } + + fn write_u8(&mut self, v: u8) { + self.buf[self.offset] = v; + self.offset += 1; + } + + fn write_u16_le(&mut self, v: u16) { + self.buf[self.offset..(self.offset + 2)].copy_from_slice(&v.to_le_bytes()); + self.offset += 2; + } + + fn write_u16_be(&mut self, v: u16) { + self.buf[self.offset..(self.offset + 2)].copy_from_slice(&v.to_be_bytes()); + self.offset += 2; + } + + fn write_u32_le(&mut self, v: u32) { + self.buf[self.offset..(self.offset + 4)].copy_from_slice(&v.to_le_bytes()); + self.offset += 4; + } + + fn write_u32_be(&mut self, v: u32) { + self.buf[self.offset..(self.offset + 4)].copy_from_slice(&v.to_be_bytes()); + self.offset += 4; + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/unwind/systemv.rs b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/systemv.rs new file mode 100644 index 00000000000000..5a721fbd82321f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/systemv.rs @@ -0,0 +1,289 @@ +//! System V ABI unwind information. + +use crate::isa::unwind::UnwindInst; +use crate::machinst::Reg; +use crate::result::CodegenResult; +use crate::{binemit::CodeOffset, CodegenError}; +use alloc::vec::Vec; +use gimli::write::{Address, FrameDescriptionEntry}; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +type Register = u16; + +/// Enumerate the errors possible in mapping Cranelift registers to their DWARF equivalent. +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Eq)] +pub enum RegisterMappingError { + MissingBank, + UnsupportedArchitecture, + UnsupportedRegisterBank(&'static str), +} + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for RegisterMappingError {} + +impl std::fmt::Display for RegisterMappingError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + RegisterMappingError::MissingBank => write!(f, "unable to find bank for register info"), + RegisterMappingError::UnsupportedArchitecture => write!( + f, + "register mapping is currently only implemented for x86_64" + ), + RegisterMappingError::UnsupportedRegisterBank(bank) => { + write!(f, "unsupported register bank: {bank}") + } + } + } +} + +// This mirrors gimli's CallFrameInstruction, but is serializable +// This excludes CfaExpression, Expression, ValExpression due to +// https://github.com/gimli-rs/gimli/issues/513. +// TODO: if gimli ever adds serialization support, remove this type +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub(crate) enum CallFrameInstruction { + Cfa(Register, i32), + CfaRegister(Register), + CfaOffset(i32), + Restore(Register), + Undefined(Register), + SameValue(Register), + Offset(Register, i32), + ValOffset(Register, i32), + Register(Register, Register), + RememberState, + RestoreState, + ArgsSize(u32), + /// Enables or disables pointer authentication on aarch64 platforms post ARMv8.3. This + /// particular item maps to gimli::ValExpression(RA_SIGN_STATE, lit0/lit1). + Aarch64SetPointerAuth { + return_addresses: bool, + }, +} + +impl From for CallFrameInstruction { + fn from(cfi: gimli::write::CallFrameInstruction) -> Self { + use gimli::write::CallFrameInstruction; + + match cfi { + CallFrameInstruction::Cfa(reg, offset) => Self::Cfa(reg.0, offset), + CallFrameInstruction::CfaRegister(reg) => Self::CfaRegister(reg.0), + CallFrameInstruction::CfaOffset(offset) => Self::CfaOffset(offset), + CallFrameInstruction::Restore(reg) => Self::Restore(reg.0), + CallFrameInstruction::Undefined(reg) => Self::Undefined(reg.0), + CallFrameInstruction::SameValue(reg) => Self::SameValue(reg.0), + CallFrameInstruction::Offset(reg, offset) => Self::Offset(reg.0, offset), + CallFrameInstruction::ValOffset(reg, offset) => Self::ValOffset(reg.0, offset), + CallFrameInstruction::Register(reg1, reg2) => Self::Register(reg1.0, reg2.0), + CallFrameInstruction::RememberState => Self::RememberState, + CallFrameInstruction::RestoreState => Self::RestoreState, + CallFrameInstruction::ArgsSize(size) => Self::ArgsSize(size), + _ => { + // Cranelift's unwind support does not generate `CallFrameInstruction`s with + // Expression at this moment, and it is not trivial to + // serialize such instructions. + panic!("CallFrameInstruction with Expression not supported"); + } + } + } +} + +impl Into for CallFrameInstruction { + fn into(self) -> gimli::write::CallFrameInstruction { + use gimli::{write::CallFrameInstruction, write::Expression, Register}; + + match self { + Self::Cfa(reg, offset) => CallFrameInstruction::Cfa(Register(reg), offset), + Self::CfaRegister(reg) => CallFrameInstruction::CfaRegister(Register(reg)), + Self::CfaOffset(offset) => CallFrameInstruction::CfaOffset(offset), + Self::Restore(reg) => CallFrameInstruction::Restore(Register(reg)), + Self::Undefined(reg) => CallFrameInstruction::Undefined(Register(reg)), + Self::SameValue(reg) => CallFrameInstruction::SameValue(Register(reg)), + Self::Offset(reg, offset) => CallFrameInstruction::Offset(Register(reg), offset), + Self::ValOffset(reg, offset) => CallFrameInstruction::ValOffset(Register(reg), offset), + Self::Register(reg1, reg2) => { + CallFrameInstruction::Register(Register(reg1), Register(reg2)) + } + Self::RememberState => CallFrameInstruction::RememberState, + Self::RestoreState => CallFrameInstruction::RestoreState, + Self::ArgsSize(size) => CallFrameInstruction::ArgsSize(size), + Self::Aarch64SetPointerAuth { return_addresses } => { + // To enable pointer authentication for return addresses in dwarf directives, we + // use a small dwarf expression that sets the value of the pseudo-register + // RA_SIGN_STATE (RA stands for return address) to 0 or 1. This behavior is + // documented in + // https://github.com/ARM-software/abi-aa/blob/master/aadwarf64/aadwarf64.rst#41dwarf-register-names. + let mut expr = Expression::new(); + expr.op(if return_addresses { + gimli::DW_OP_lit1 + } else { + gimli::DW_OP_lit0 + }); + const RA_SIGN_STATE: Register = Register(34); + CallFrameInstruction::ValExpression(RA_SIGN_STATE, expr) + } + } + } +} + +/// Maps UnwindInfo register to gimli's index space. +pub(crate) trait RegisterMapper { + /// Maps Reg. + fn map(&self, reg: Reg) -> Result; + /// Gets the frame pointer register, if any. + fn fp(&self) -> Option { + None + } + /// Gets the link register, if any. + fn lr(&self) -> Option { + None + } + /// What is the offset from saved FP to saved LR? + fn lr_offset(&self) -> Option { + None + } +} + +/// Represents unwind information for a single System V ABI function. +/// +/// This representation is not ISA specific. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UnwindInfo { + instructions: Vec<(u32, CallFrameInstruction)>, + len: u32, +} + +/// Offset from the caller's SP to CFA as we define it. +pub(crate) fn caller_sp_to_cfa_offset() -> u32 { + // Currently we define them to always be equal. + 0 +} + +pub(crate) fn create_unwind_info_from_insts>( + insts: &[(CodeOffset, UnwindInst)], + code_len: usize, + mr: &MR, +) -> CodegenResult { + let mut instructions = vec![]; + + let mut cfa_offset = 0; + let mut clobber_offset_to_cfa = 0; + for &(instruction_offset, ref inst) in insts { + match inst { + &UnwindInst::PushFrameRegs { + offset_upward_to_caller_sp, + } => { + // Define CFA in terms of current SP (SP changed and we haven't + // set FP yet). + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaOffset(offset_upward_to_caller_sp as i32), + )); + // Note that we saved the old FP value on the stack. Use of this + // operation implies that the target defines a FP register. + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset( + mr.fp().unwrap(), + -(offset_upward_to_caller_sp as i32), + ), + )); + // If there is a link register on this architecture, note that + // we saved it as well. + if let Some(lr) = mr.lr() { + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset( + lr, + -(offset_upward_to_caller_sp as i32) + + mr.lr_offset().expect("LR offset not provided") as i32, + ), + )); + } + } + &UnwindInst::DefineNewFrame { + offset_upward_to_caller_sp, + offset_downward_to_clobbers, + } => { + // Define CFA in terms of FP. Note that we assume it was already + // defined correctly in terms of the current SP, and FP has just + // been set to the current SP, so we do not need to change the + // offset, only the register. (This is done only if the target + // defines a frame pointer register.) + if let Some(fp) = mr.fp() { + instructions.push((instruction_offset, CallFrameInstruction::CfaRegister(fp))); + } + // Record initial CFA offset. This will be used with later + // StackAlloc calls if we do not have a frame pointer. + cfa_offset = offset_upward_to_caller_sp; + // Record distance from CFA downward to clobber area so we can + // express clobber offsets later in terms of CFA. + clobber_offset_to_cfa = offset_upward_to_caller_sp + offset_downward_to_clobbers; + } + &UnwindInst::StackAlloc { size } => { + // If we do not use a frame pointer, we need to update the + // CFA offset whenever the stack pointer changes. + if mr.fp().is_none() { + cfa_offset += size; + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaOffset(cfa_offset as i32), + )); + } + } + &UnwindInst::SaveReg { + clobber_offset, + reg, + } => { + let reg = mr + .map(reg.into()) + .map_err(|e| CodegenError::RegisterMappingError(e))?; + let off = (clobber_offset as i32) - (clobber_offset_to_cfa as i32); + instructions.push((instruction_offset, CallFrameInstruction::Offset(reg, off))); + } + &UnwindInst::RegStackOffset { + clobber_offset, + reg, + } => { + let reg = mr + .map(reg.into()) + .map_err(|e| CodegenError::RegisterMappingError(e))?; + let off = (clobber_offset as i32) - (clobber_offset_to_cfa as i32); + instructions.push(( + instruction_offset, + CallFrameInstruction::ValOffset(reg, off), + )); + } + &UnwindInst::Aarch64SetPointerAuth { return_addresses } => { + instructions.push(( + instruction_offset, + CallFrameInstruction::Aarch64SetPointerAuth { return_addresses }, + )); + } + } + } + + Ok(UnwindInfo { + instructions, + len: code_len as u32, + }) +} + +impl UnwindInfo { + /// Converts the unwind information into a `FrameDescriptionEntry`. + pub fn to_fde(&self, address: Address) -> gimli::write::FrameDescriptionEntry { + let mut fde = FrameDescriptionEntry::new(address, self.len); + + for (offset, inst) in &self.instructions { + fde.add_instruction(*offset, inst.clone().into()); + } + + fde + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winarm64.rs b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winarm64.rs new file mode 100644 index 00000000000000..58a1b38b9df49b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winarm64.rs @@ -0,0 +1,318 @@ +//! Windows Arm64 ABI unwind information. + +use alloc::vec::Vec; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +use crate::binemit::CodeOffset; +use crate::isa::unwind::UnwindInst; +use crate::result::CodegenResult; + +use super::Writer; + +/// The supported unwind codes for the Arm64 Windows ABI. +/// +/// See: +/// Only what is needed to describe the prologues generated by the Cranelift AArch64 ISA are represented here. +#[allow(dead_code)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub(crate) enum UnwindCode { + /// Save int register, or register pair. + SaveReg { + reg: u8, + stack_offset: u16, + is_pair: bool, + }, + /// Save floating point register, or register pair. + SaveFReg { + reg: u8, + stack_offset: u16, + is_pair: bool, + }, + /// Save frame-pointer register (X29) and LR register pair. + SaveFpLrPair { + stack_offset: u16, + }, + // Small (<512b) stack allocation. + AllocS { + size: u16, + }, + // Medium (<32Kb) stack allocation. + AllocM { + size: u16, + }, + // Large (<256Mb) stack allocation. + AllocL { + size: u32, + }, + /// PAC sign the LR register. + PacSignLr, + /// Set the frame-pointer register to the stack-pointer register. + SetFp, + /// Set the frame-pointer register to the stack-pointer register with an + /// offset. + AddFp { + offset: u16, + }, +} + +/// Represents Windows Arm64 unwind information. +/// +/// For information about Windows Arm64 unwind info, see: +/// +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UnwindInfo { + pub(crate) unwind_codes: Vec, +} + +impl UnwindInfo { + /// Calculate the number of words needed to encode the unwind codes. + pub fn code_words(&self) -> u8 { + let mut bytes = 0u16; + for code in self.unwind_codes.iter() { + let next_bytes = match code { + UnwindCode::SaveFpLrPair { .. } + | UnwindCode::AllocS { .. } + | UnwindCode::PacSignLr + | UnwindCode::SetFp => 1, + UnwindCode::SaveReg { .. } + | UnwindCode::SaveFReg { .. } + | UnwindCode::AllocM { .. } + | UnwindCode::AddFp { .. } => 2, + UnwindCode::AllocL { .. } => 4, + }; + bytes = bytes.checked_add(next_bytes).unwrap(); + } + + bytes.div_ceil(4).try_into().unwrap() + } + + /// Emits the unwind information into the given mutable byte slice. + /// + /// This function will panic if the slice is not at least `emit_size` in length. + pub fn emit(&self, buf: &mut [u8]) { + fn encode_stack_offset(stack_offset: u16) -> u16 { + let encoded = (stack_offset / 8) - 1; + assert!(encoded < (1 << BITS), "Stack offset too large"); + encoded + } + + // NOTE: Unwind codes are written in big-endian! + + let mut writer = Writer::new(buf); + for code in self.unwind_codes.iter().rev() { + match code { + &UnwindCode::SaveReg { + reg, + stack_offset, + is_pair, + } => { + assert!(reg >= 19, "Can't save registers before X19"); + let reg = u16::from(reg - 19); + let encoding = if is_pair { + let mut encoding = 0b11001100_00000000u16; + encoding |= reg << 6; + encoding |= encode_stack_offset::<6>(stack_offset); + encoding + } else { + let mut encoding = 0b11010100_00000000u16; + encoding |= reg << 5; + encoding |= encode_stack_offset::<5>(stack_offset); + encoding + }; + writer.write_u16_be(encoding); + } + &UnwindCode::SaveFReg { + reg, + stack_offset, + is_pair, + } => { + assert!(reg >= 8, "Can't save registers before D8"); + let reg = u16::from(reg - 8); + let encoding = if is_pair { + let mut encoding = 0b11011010_00000000u16; + encoding |= reg << 6; + encoding |= encode_stack_offset::<6>(stack_offset); + encoding + } else { + let mut encoding = 0b11011110_00000000u16; + encoding |= reg << 5; + encoding |= encode_stack_offset::<5>(stack_offset); + encoding + }; + writer.write_u16_be(encoding); + } + &UnwindCode::SaveFpLrPair { stack_offset } => { + if stack_offset == 0 { + writer.write_u8(0b01000000); + } else { + let encoding = 0b10000000u8 + | u8::try_from(encode_stack_offset::<6>(stack_offset)).unwrap(); + writer.write_u8(encoding); + } + } + &UnwindCode::AllocS { size } => { + // Size is measured in double 64-bit words. + let encoding = size / 16; + assert!(encoding < (1 << 5), "Stack alloc size too large"); + // Tag is 0b000, so we don't need to encode that. + writer.write_u8(encoding.try_into().unwrap()); + } + &UnwindCode::AllocM { size } => { + // Size is measured in double 64-bit words. + let mut encoding = size / 16; + assert!(encoding < (1 << 11), "Stack alloc size too large"); + encoding |= 0b11000 << 11; + writer.write_u16_be(encoding); + } + &UnwindCode::AllocL { size } => { + // Size is measured in double 64-bit words. + let mut encoding = size / 16; + assert!(encoding < (1 << 24), "Stack alloc size too large"); + encoding |= 0b11100000 << 24; + writer.write_u32_be(encoding); + } + UnwindCode::PacSignLr => { + writer.write_u8(0b11111100); + } + UnwindCode::SetFp => { + writer.write_u8(0b11100001); + } + &UnwindCode::AddFp { mut offset } => { + offset /= 8; + assert!(offset & !0xFF == 0, "Offset too large"); + let encoding = (0b11100010 << 8) | offset; + writer.write_u16_be(encoding); + } + } + } + } +} + +pub(crate) fn create_unwind_info_from_insts( + insts: &[(CodeOffset, UnwindInst)], +) -> CodegenResult { + let mut unwind_codes = vec![]; + let mut last_stackalloc = None; + let mut last_clobber_offset = None; + for &(_, ref inst) in insts { + match inst { + &UnwindInst::PushFrameRegs { .. } => { + unwind_codes.push(UnwindCode::SaveFpLrPair { stack_offset: 16 }); + unwind_codes.push(UnwindCode::SetFp); + } + &UnwindInst::DefineNewFrame { + offset_downward_to_clobbers, + .. + } => { + assert!(last_clobber_offset.is_none(), "More than one frame defined"); + last_clobber_offset = Some(offset_downward_to_clobbers); + + // If we've seen a stackalloc, then we were adjusting the stack + // to make space for additional arguments, so encode that now. + if let &Some(last_stackalloc) = &last_stackalloc { + assert!(last_stackalloc < (1u32 << 8) * 8); + unwind_codes.push(UnwindCode::AddFp { + offset: u16::try_from(last_stackalloc).unwrap(), + }); + unwind_codes.push(UnwindCode::SaveFpLrPair { stack_offset: 0 }); + unwind_codes.push(UnwindCode::SetFp); + } + } + &UnwindInst::StackAlloc { size } => { + last_stackalloc = Some(size); + assert!(size % 16 == 0, "Size must be a multiple of 16"); + const SMALL_STACK_ALLOC_MAX: u32 = (1 << 5) * 16 - 1; + const MEDIUM_STACK_ALLOC_MIN: u32 = SMALL_STACK_ALLOC_MAX + 1; + const MEDIUM_STACK_ALLOC_MAX: u32 = (1 << 11) * 16 - 1; + const LARGE_STACK_ALLOC_MIN: u32 = MEDIUM_STACK_ALLOC_MAX + 1; + const LARGE_STACK_ALLOC_MAX: u32 = (1 << 24) * 16 - 1; + match size { + 0..=SMALL_STACK_ALLOC_MAX => unwind_codes.push(UnwindCode::AllocS { + size: size.try_into().unwrap(), + }), + MEDIUM_STACK_ALLOC_MIN..=MEDIUM_STACK_ALLOC_MAX => { + unwind_codes.push(UnwindCode::AllocM { + size: size.try_into().unwrap(), + }) + } + LARGE_STACK_ALLOC_MIN..=LARGE_STACK_ALLOC_MAX => { + unwind_codes.push(UnwindCode::AllocL { size: size }) + } + _ => panic!("Stack allocation size too large"), + } + } + &UnwindInst::SaveReg { + clobber_offset, + reg, + } => { + // We're given the clobber offset, but we need to encode how far + // the stack was adjusted, so calculate that based on the last + // clobber offset we saw. + let last_clobber_offset = last_clobber_offset.as_mut().expect("No frame defined"); + if *last_clobber_offset > clobber_offset { + let stack_offset = *last_clobber_offset - clobber_offset; + *last_clobber_offset = clobber_offset; + + assert!(stack_offset % 8 == 0, "Offset must be a multiple of 8"); + match reg.class() { + regalloc2::RegClass::Int => { + let reg = reg.hw_enc(); + if reg < 19 { + panic!("Can't save registers before X19"); + } + unwind_codes.push(UnwindCode::SaveReg { + reg, + stack_offset: stack_offset.try_into().unwrap(), + is_pair: false, + }); + } + regalloc2::RegClass::Float => { + let reg = reg.hw_enc(); + if reg < 8 { + panic!("Can't save registers before D8"); + } + unwind_codes.push(UnwindCode::SaveFReg { + reg, + stack_offset: stack_offset.try_into().unwrap(), + is_pair: false, + }); + } + regalloc2::RegClass::Vector => unreachable!(), + } + } else { + // If we see a clobber offset within the last offset amount, + // then we're actually saving a pair of registers. + let last_unwind_code = unwind_codes.last_mut().unwrap(); + match last_unwind_code { + UnwindCode::SaveReg { is_pair, .. } => { + assert_eq!(reg.class(), regalloc2::RegClass::Int); + assert!(!*is_pair); + *is_pair = true; + } + UnwindCode::SaveFReg { is_pair, .. } => { + assert_eq!(reg.class(), regalloc2::RegClass::Float); + assert!(!*is_pair); + *is_pair = true; + } + _ => unreachable!("Previous code should have been a register save"), + } + } + } + &UnwindInst::RegStackOffset { .. } => { + unreachable!("only supported with DWARF"); + } + &UnwindInst::Aarch64SetPointerAuth { return_addresses } => { + assert!( + return_addresses, + "Windows doesn't support explicitly disabling return address signing" + ); + unwind_codes.push(UnwindCode::PacSignLr); + } + } + } + + Ok(UnwindInfo { unwind_codes }) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winx64.rs b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winx64.rs new file mode 100644 index 00000000000000..55014518b54f24 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/unwind/winx64.rs @@ -0,0 +1,313 @@ +//! Windows x64 ABI unwind information. + +use alloc::vec::Vec; +use log::warn; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +use crate::binemit::CodeOffset; +use crate::isa::unwind::UnwindInst; +use crate::result::{CodegenError, CodegenResult}; + +use super::Writer; + +/// Maximum (inclusive) size of a "small" stack allocation +const SMALL_ALLOC_MAX_SIZE: u32 = 128; +/// Maximum (inclusive) size of a "large" stack allocation that can represented in 16-bits +const LARGE_ALLOC_16BIT_MAX_SIZE: u32 = 524280; + +/// The supported unwind codes for the x64 Windows ABI. +/// +/// See: +/// Only what is needed to describe the prologues generated by the Cranelift x86 ISA are represented here. +/// Note: the Cranelift x86 ISA RU enum matches the Windows unwind GPR encoding values. +#[allow(dead_code)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub(crate) enum UnwindCode { + PushRegister { + instruction_offset: u8, + reg: u8, + }, + SaveReg { + instruction_offset: u8, + reg: u8, + stack_offset: u32, + }, + SaveXmm { + instruction_offset: u8, + reg: u8, + stack_offset: u32, + }, + StackAlloc { + instruction_offset: u8, + size: u32, + }, + SetFPReg { + instruction_offset: u8, + }, +} + +impl UnwindCode { + fn emit(&self, writer: &mut Writer) { + enum UnwindOperation { + PushNonvolatileRegister = 0, + LargeStackAlloc = 1, + SmallStackAlloc = 2, + SetFPReg = 3, + SaveNonVolatileRegister = 4, + SaveNonVolatileRegisterFar = 5, + SaveXmm128 = 8, + SaveXmm128Far = 9, + } + + match self { + Self::PushRegister { + instruction_offset, + reg, + } => { + writer.write_u8(*instruction_offset); + writer.write_u8((*reg << 4) | (UnwindOperation::PushNonvolatileRegister as u8)); + } + Self::SaveReg { + instruction_offset, + reg, + stack_offset, + } + | Self::SaveXmm { + instruction_offset, + reg, + stack_offset, + } => { + let is_xmm = match self { + Self::SaveXmm { .. } => true, + _ => false, + }; + let (op_small, op_large) = if is_xmm { + (UnwindOperation::SaveXmm128, UnwindOperation::SaveXmm128Far) + } else { + ( + UnwindOperation::SaveNonVolatileRegister, + UnwindOperation::SaveNonVolatileRegisterFar, + ) + }; + writer.write_u8(*instruction_offset); + let scaled_stack_offset = stack_offset / 16; + if scaled_stack_offset <= core::u16::MAX as u32 { + writer.write_u8((*reg << 4) | (op_small as u8)); + writer.write_u16_le(scaled_stack_offset as u16); + } else { + writer.write_u8((*reg << 4) | (op_large as u8)); + writer.write_u16_le(*stack_offset as u16); + writer.write_u16_le((stack_offset >> 16) as u16); + } + } + Self::StackAlloc { + instruction_offset, + size, + } => { + // Stack allocations on Windows must be a multiple of 8 and be at least 1 slot + assert!(*size >= 8); + assert!((*size % 8) == 0); + + writer.write_u8(*instruction_offset); + if *size <= SMALL_ALLOC_MAX_SIZE { + writer.write_u8( + ((((*size - 8) / 8) as u8) << 4) | UnwindOperation::SmallStackAlloc as u8, + ); + } else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE { + writer.write_u8(UnwindOperation::LargeStackAlloc as u8); + writer.write_u16_le((*size / 8) as u16); + } else { + writer.write_u8((1 << 4) | (UnwindOperation::LargeStackAlloc as u8)); + writer.write_u32_le(*size); + } + } + Self::SetFPReg { instruction_offset } => { + writer.write_u8(*instruction_offset); + writer.write_u8(UnwindOperation::SetFPReg as u8); + } + } + } + + fn node_count(&self) -> usize { + match self { + Self::StackAlloc { size, .. } => { + if *size <= SMALL_ALLOC_MAX_SIZE { + 1 + } else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE { + 2 + } else { + 3 + } + } + Self::SaveXmm { stack_offset, .. } | Self::SaveReg { stack_offset, .. } => { + if *stack_offset <= core::u16::MAX as u32 { + 2 + } else { + 3 + } + } + _ => 1, + } + } +} + +pub(crate) enum MappedRegister { + Int(u8), + Xmm(u8), +} + +/// Maps UnwindInfo register to Windows x64 unwind data. +pub(crate) trait RegisterMapper { + /// Maps a Reg to a Windows unwind register number. + fn map(reg: Reg) -> MappedRegister; +} + +/// Represents Windows x64 unwind information. +/// +/// For information about Windows x64 unwind info, see: +/// +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UnwindInfo { + pub(crate) flags: u8, + pub(crate) prologue_size: u8, + pub(crate) frame_register: Option, + pub(crate) frame_register_offset: u8, + pub(crate) unwind_codes: Vec, +} + +impl UnwindInfo { + /// Gets the emit size of the unwind information, in bytes. + pub fn emit_size(&self) -> usize { + let node_count = self.node_count(); + + // Calculation of the size requires no SEH handler or chained info + assert!(self.flags == 0); + + // Size of fixed part of UNWIND_INFO is 4 bytes + // Then comes the UNWIND_CODE nodes (2 bytes each) + // Then comes 2 bytes of padding for the unwind codes if necessary + // Next would come the SEH data, but we assert above that the function doesn't have SEH data + + 4 + (node_count * 2) + if (node_count & 1) == 1 { 2 } else { 0 } + } + + /// Emits the unwind information into the given mutable byte slice. + /// + /// This function will panic if the slice is not at least `emit_size` in length. + pub fn emit(&self, buf: &mut [u8]) { + const UNWIND_INFO_VERSION: u8 = 1; + + let node_count = self.node_count(); + assert!(node_count <= 256); + + let mut writer = Writer::new(buf); + + writer.write_u8((self.flags << 3) | UNWIND_INFO_VERSION); + writer.write_u8(self.prologue_size); + writer.write_u8(node_count as u8); + + if let Some(reg) = self.frame_register { + writer.write_u8((self.frame_register_offset << 4) | reg); + } else { + writer.write_u8(0); + } + + // Unwind codes are written in reverse order (prologue offset descending) + for code in self.unwind_codes.iter().rev() { + code.emit(&mut writer); + } + + // To keep a 32-bit alignment, emit 2 bytes of padding if there's an odd number of 16-bit nodes + if (node_count & 1) == 1 { + writer.write_u16_le(0); + } + + // Ensure the correct number of bytes was emitted + assert_eq!(writer.offset, self.emit_size()); + } + + fn node_count(&self) -> usize { + self.unwind_codes + .iter() + .fold(0, |nodes, c| nodes + c.node_count()) + } +} + +const UNWIND_RBP_REG: u8 = 5; + +pub(crate) fn create_unwind_info_from_insts>( + insts: &[(CodeOffset, UnwindInst)], +) -> CodegenResult { + let mut unwind_codes = vec![]; + let mut frame_register_offset = 0; + let mut max_unwind_offset = 0; + for &(instruction_offset, ref inst) in insts { + let instruction_offset = ensure_unwind_offset(instruction_offset)?; + match inst { + &UnwindInst::PushFrameRegs { .. } => { + unwind_codes.push(UnwindCode::PushRegister { + instruction_offset, + reg: UNWIND_RBP_REG, + }); + } + &UnwindInst::DefineNewFrame { + offset_downward_to_clobbers, + .. + } => { + frame_register_offset = ensure_unwind_offset(offset_downward_to_clobbers)?; + unwind_codes.push(UnwindCode::SetFPReg { instruction_offset }); + } + &UnwindInst::StackAlloc { size } => { + unwind_codes.push(UnwindCode::StackAlloc { + instruction_offset, + size, + }); + } + &UnwindInst::SaveReg { + clobber_offset, + reg, + } => match MR::map(reg.into()) { + MappedRegister::Int(reg) => { + unwind_codes.push(UnwindCode::SaveReg { + instruction_offset, + reg, + stack_offset: clobber_offset, + }); + } + MappedRegister::Xmm(reg) => { + unwind_codes.push(UnwindCode::SaveXmm { + instruction_offset, + reg, + stack_offset: clobber_offset, + }); + } + }, + &UnwindInst::RegStackOffset { .. } => { + unreachable!("only supported with DWARF"); + } + &UnwindInst::Aarch64SetPointerAuth { .. } => { + unreachable!("no aarch64 on x64"); + } + } + max_unwind_offset = instruction_offset; + } + + Ok(UnwindInfo { + flags: 0, + prologue_size: max_unwind_offset, + frame_register: Some(UNWIND_RBP_REG), + frame_register_offset, + unwind_codes, + }) +} + +fn ensure_unwind_offset(offset: u32) -> CodegenResult { + if offset > 255 { + warn!("function prologues cannot exceed 255 bytes in size for Windows x64"); + return Err(CodegenError::CodeTooLarge); + } + Ok(offset as u8) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/winch.rs b/deps/crates/vendor/cranelift-codegen/src/isa/winch.rs new file mode 100644 index 00000000000000..c37ddd373ee05e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/winch.rs @@ -0,0 +1,22 @@ +use crate::machinst::{ABIArg, ABIArgSlot, ArgsAccumulator}; + +// Winch writes the first result to the highest offset, so we need to iterate through the +// args and adjust the offsets down. +pub(super) fn reverse_stack(mut args: ArgsAccumulator, next_stack: u32, uses_extension: bool) { + for arg in args.args_mut() { + if let ABIArg::Slots { slots, .. } = arg { + for slot in slots.iter_mut() { + if let ABIArgSlot::Stack { offset, ty, .. } = slot { + let size = if uses_extension { + i64::from(std::cmp::max(ty.bytes(), 8)) + } else { + i64::from(ty.bytes()) + }; + *offset = i64::from(next_stack) - *offset - size; + } + } + } else { + unreachable!("Winch cannot handle {arg:?}"); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/abi.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/abi.rs new file mode 100644 index 00000000000000..52005855553d1d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/abi.rs @@ -0,0 +1,1386 @@ +//! Implementation of the standard x64 ABI. + +use crate::ir::{self, types, LibCall, MemFlags, Signature, TrapCode}; +use crate::ir::{types::*, ExternalName}; +use crate::isa; +use crate::isa::winch; +use crate::isa::x64::X64Backend; +use crate::isa::{unwind::UnwindInst, x64::inst::*, x64::settings as x64_settings, CallConv}; +use crate::machinst::abi::*; +use crate::machinst::*; +use crate::settings; +use crate::CodegenResult; +use alloc::boxed::Box; +use alloc::vec::Vec; +use args::*; +use regalloc2::{MachineEnv, PReg, PRegSet}; +use smallvec::{smallvec, SmallVec}; +use std::borrow::ToOwned; +use std::sync::OnceLock; + +/// Support for the x64 ABI from the callee side (within a function body). +pub(crate) type X64Callee = Callee; + +/// Support for the x64 ABI from the caller side (at a callsite). +pub(crate) type X64CallSite = CallSite; + +/// Implementation of ABI primitives for x64. +pub struct X64ABIMachineSpec; + +impl X64ABIMachineSpec { + fn gen_probestack_unroll(insts: &mut SmallInstVec, guard_size: u32, probe_count: u32) { + insts.reserve(probe_count as usize); + for _ in 0..probe_count { + // "Allocate" stack space for the probe by decrementing the stack pointer before + // the write. This is required to make valgrind happy. + // See: https://github.com/bytecodealliance/wasmtime/issues/7454 + insts.extend(Self::gen_sp_reg_adjust(-(guard_size as i32))); + + // TODO: It would be nice if we could store the imm 0, but we don't have insts for those + // so store the stack pointer. Any register will do, since the stack is undefined at this point + insts.push(Inst::store( + I32, + regs::rsp(), + Amode::imm_reg(0, regs::rsp()), + )); + } + + // Restore the stack pointer to its original value + insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32)); + } + + fn gen_probestack_loop( + insts: &mut SmallInstVec, + _call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ) { + // We have to use a caller-saved register since clobbering only + // happens after stack probing. + // `r11` is caller saved on both Fastcall and SystemV, and not used + // for argument passing, so it's pretty much free. It is also not + // used by the stacklimit mechanism. + let tmp = regs::r11(); + debug_assert!({ + let real_reg = tmp.to_real_reg().unwrap(); + !is_callee_save_systemv(real_reg, false) && !is_callee_save_fastcall(real_reg, false) + }); + + insts.push(Inst::StackProbeLoop { + tmp: Writable::from_reg(tmp), + frame_size, + guard_size, + }); + } +} + +impl IsaFlags for x64_settings::Flags {} + +impl ABIMachineSpec for X64ABIMachineSpec { + type I = Inst; + + type F = x64_settings::Flags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic: for now, 128 MB. + const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024; + + fn word_bits() -> u32 { + 64 + } + + /// Return required stack alignment in bytes. + fn stack_align(_call_conv: isa::CallConv) -> u32 { + 16 + } + + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + mut args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)> { + let is_fastcall = call_conv == CallConv::WindowsFastcall; + + let mut next_gpr = 0; + let mut next_vreg = 0; + let mut next_stack: u32 = 0; + let mut next_param_idx = 0; // Fastcall cares about overall param index + + if args_or_rets == ArgsOrRets::Args && is_fastcall { + // Fastcall always reserves 32 bytes of shadow space corresponding to + // the four initial in-arg parameters. + // + // (See: + // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160) + next_stack = 32; + } + + let ret_area_ptr = if add_ret_area_ptr { + debug_assert_eq!(args_or_rets, ArgsOrRets::Args); + next_gpr += 1; + next_param_idx += 1; + // In the SystemV and WindowsFastcall ABIs, the return area pointer is the first + // argument. For the Tail and Winch ABIs we do the same for simplicity sake. + Some(ABIArg::reg( + get_intreg_for_arg(call_conv, 0, 0) + .unwrap() + .to_real_reg() + .unwrap(), + types::I64, + ir::ArgumentExtension::None, + ir::ArgumentPurpose::Normal, + )) + } else { + None + }; + + // If any param uses extension, the winch calling convention will not pack its results + // on the stack and will instead align them to 8-byte boundaries the same way that all the + // other calling conventions do. This isn't consistent with Winch itself, but is fine as + // Winch only uses this calling convention via trampolines, and those trampolines don't add + // extension annotations. Additionally, handling extension attributes this way allows clif + // functions that use them with the Winch calling convention to interact successfully with + // testing infrastructure. + // The results are also not packed if any of the types are `f16`. This is to simplify the + // implementation of `Inst::load`/`Inst::store` (which would otherwise require multiple + // instructions), and doesn't affect Winch itself as Winch doesn't support `f16` at all. + let uses_extension = params + .iter() + .any(|p| p.extension != ir::ArgumentExtension::None || p.value_type == types::F16); + + for (ix, param) in params.iter().enumerate() { + let last_param = ix == params.len() - 1; + + if let ir::ArgumentPurpose::StructArgument(size) = param.purpose { + let offset = next_stack as i64; + let size = size; + assert!(size % 8 == 0, "StructArgument size is not properly aligned"); + next_stack += size; + args.push(ABIArg::StructArg { + offset, + size: size as u64, + purpose: param.purpose, + }); + continue; + } + + // Find regclass(es) of the register(s) used to store a value of this type. + let (rcs, reg_tys) = Inst::rc_for_type(param.value_type)?; + + // Now assign ABIArgSlots for each register-sized part. + // + // Note that the handling of `i128` values is unique here: + // + // - If `enable_llvm_abi_extensions` is set in the flags, each + // `i128` is split into two `i64`s and assigned exactly as if it + // were two consecutive 64-bit args, except that if one of the + // two halves is forced onto the stack, the other half is too. + // This is consistent with LLVM's behavior, and is needed for + // some uses of Cranelift (e.g., the rustc backend). + // + // - Otherwise, both SysV and Fastcall specify behavior (use of + // vector register, a register pair, or passing by reference + // depending on the case), but for simplicity, we will just panic if + // an i128 type appears in a signature and the LLVM extensions flag + // is not set. + // + // For examples of how rustc compiles i128 args and return values on + // both SysV and Fastcall platforms, see: + // https://godbolt.org/z/PhG3ob + + if param.value_type.bits() > 64 + && !(param.value_type.is_vector() || param.value_type.is_float()) + && !flags.enable_llvm_abi_extensions() + { + panic!( + "i128 args/return values not supported unless LLVM ABI extensions are enabled" + ); + } + // As MSVC doesn't support f16/f128 there is no standard way to pass/return them with + // the Windows ABI. LLVM passes/returns them in XMM registers. + if matches!(param.value_type, types::F16 | types::F128) + && is_fastcall + && !flags.enable_llvm_abi_extensions() + { + panic!( + "f16/f128 args/return values not supported for windows_fastcall unless LLVM ABI extensions are enabled" + ); + } + + // Windows fastcall dictates that `__m128i` parameters to a function + // are passed indirectly as pointers, so handle that as a special + // case before the loop below. + if param.value_type.is_vector() + && param.value_type.bits() >= 128 + && args_or_rets == ArgsOrRets::Args + && is_fastcall + { + let pointer = match get_intreg_for_arg(call_conv, next_gpr, next_param_idx) { + Some(reg) => { + next_gpr += 1; + ABIArgSlot::Reg { + reg: reg.to_real_reg().unwrap(), + ty: ir::types::I64, + extension: ir::ArgumentExtension::None, + } + } + + None => { + next_stack = align_to(next_stack, 8) + 8; + ABIArgSlot::Stack { + offset: (next_stack - 8) as i64, + ty: ir::types::I64, + extension: param.extension, + } + } + }; + next_param_idx += 1; + args.push(ABIArg::ImplicitPtrArg { + // NB: this is filled in after this loop + offset: 0, + pointer, + ty: param.value_type, + purpose: param.purpose, + }); + continue; + } + + // SystemV dictates that 128bit int parameters are always either + // passed in two registers or on the stack, so handle that as a + // special case before the loop below. + if param.value_type == types::I128 + && args_or_rets == ArgsOrRets::Args + && call_conv == CallConv::SystemV + { + let mut slots = ABIArgSlotVec::new(); + match ( + get_intreg_for_arg(CallConv::SystemV, next_gpr, next_param_idx), + get_intreg_for_arg(CallConv::SystemV, next_gpr + 1, next_param_idx + 1), + ) { + (Some(reg1), Some(reg2)) => { + slots.push(ABIArgSlot::Reg { + reg: reg1.to_real_reg().unwrap(), + ty: ir::types::I64, + extension: ir::ArgumentExtension::None, + }); + slots.push(ABIArgSlot::Reg { + reg: reg2.to_real_reg().unwrap(), + ty: ir::types::I64, + extension: ir::ArgumentExtension::None, + }); + } + _ => { + let size = 16; + + // Align. + next_stack = align_to(next_stack, size); + + slots.push(ABIArgSlot::Stack { + offset: next_stack as i64, + ty: ir::types::I64, + extension: param.extension, + }); + slots.push(ABIArgSlot::Stack { + offset: next_stack as i64 + 8, + ty: ir::types::I64, + extension: param.extension, + }); + next_stack += size; + } + }; + // Unconditionally increment next_gpr even when storing the + // argument on the stack to prevent reusing a possibly + // remaining register for the next argument. + next_gpr += 2; + next_param_idx += 2; + + args.push(ABIArg::Slots { + slots, + purpose: param.purpose, + }); + continue; + } + + let mut slots = ABIArgSlotVec::new(); + for (ix, (rc, reg_ty)) in rcs.iter().zip(reg_tys.iter()).enumerate() { + let last_slot = last_param && ix == rcs.len() - 1; + + let intreg = *rc == RegClass::Int; + let nextreg = if intreg { + match args_or_rets { + ArgsOrRets::Args => get_intreg_for_arg(call_conv, next_gpr, next_param_idx), + ArgsOrRets::Rets => { + get_intreg_for_retval(call_conv, flags, next_gpr, last_slot) + } + } + } else { + match args_or_rets { + ArgsOrRets::Args => { + get_fltreg_for_arg(call_conv, next_vreg, next_param_idx) + } + ArgsOrRets::Rets => get_fltreg_for_retval(call_conv, next_vreg, last_slot), + } + }; + next_param_idx += 1; + if let Some(reg) = nextreg { + if intreg { + next_gpr += 1; + } else { + next_vreg += 1; + } + slots.push(ABIArgSlot::Reg { + reg: reg.to_real_reg().unwrap(), + ty: *reg_ty, + extension: param.extension, + }); + } else { + if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() { + return Err(crate::CodegenError::Unsupported( + "Too many return values to fit in registers. \ + Use a StructReturn argument instead. (#9510)" + .to_owned(), + )); + } + + let size = reg_ty.bytes(); + let size = if call_conv == CallConv::Winch + && args_or_rets == ArgsOrRets::Rets + && !uses_extension + { + size + } else { + let size = std::cmp::max(size, 8); + + // Align. + debug_assert!(size.is_power_of_two()); + next_stack = align_to(next_stack, size); + size + }; + + slots.push(ABIArgSlot::Stack { + offset: next_stack as i64, + ty: *reg_ty, + extension: param.extension, + }); + next_stack += size; + } + } + + args.push(ABIArg::Slots { + slots, + purpose: param.purpose, + }); + } + + // Fastcall's indirect 128+ bit vector arguments are all located on the + // stack, and stack space is reserved after all parameters are passed, + // so allocate from the space now. + if args_or_rets == ArgsOrRets::Args && is_fastcall { + for arg in args.args_mut() { + if let ABIArg::ImplicitPtrArg { offset, .. } = arg { + assert_eq!(*offset, 0); + next_stack = align_to(next_stack, 16); + *offset = next_stack as i64; + next_stack += 16; + } + } + } + let extra_arg_idx = if let Some(ret_area_ptr) = ret_area_ptr { + args.push_non_formal(ret_area_ptr); + Some(args.args().len() - 1) + } else { + None + }; + + // Winch writes the first result to the highest offset, so we need to iterate through the + // args and adjust the offsets down. + if call_conv == CallConv::Winch && args_or_rets == ArgsOrRets::Rets { + winch::reverse_stack(args, next_stack, uses_extension); + } + + next_stack = align_to(next_stack, 16); + + Ok((next_stack, extra_arg_idx)) + } + + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Self::I { + // For integer-typed values, we always load a full 64 bits (and we always spill a full 64 + // bits as well -- see `Inst::store()`). + let ty = match ty { + types::I8 | types::I16 | types::I32 => types::I64, + // Stack slots are always at least 8 bytes, so it's fine to load 4 bytes instead of only + // two. + types::F16 => types::F32, + _ => ty, + }; + Inst::load(ty, mem, into_reg, ExtKind::None) + } + + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I { + let ty = match ty { + // See `gen_load_stack`. + types::F16 => types::F32, + _ => ty, + }; + Inst::store(ty, from_reg, mem) + } + + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self::I { + Inst::gen_move(to_reg, from_reg, ty) + } + + /// Generate an integer-extend operation. + fn gen_extend( + to_reg: Writable, + from_reg: Reg, + is_signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Self::I { + let ext_mode = ExtMode::new(from_bits as u16, to_bits as u16) + .unwrap_or_else(|| panic!("invalid extension: {from_bits} -> {to_bits}")); + if is_signed { + Inst::movsx_rm_r(ext_mode, RegMem::reg(from_reg), to_reg) + } else { + Inst::movzx_rm_r(ext_mode, RegMem::reg(from_reg), to_reg) + } + } + + fn gen_args(args: Vec) -> Inst { + Inst::Args { args } + } + + fn gen_rets(rets: Vec) -> Inst { + Inst::Rets { rets } + } + + fn gen_add_imm( + _call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec { + let mut ret = SmallVec::new(); + if from_reg != into_reg.to_reg() { + ret.push(Inst::gen_move(into_reg, from_reg, I64)); + } + ret.push(Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(imm), + into_reg, + )); + ret + } + + fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { + smallvec![ + Inst::cmp_rmi_r(OperandSize::Size64, limit_reg, RegMemImm::reg(regs::rsp())), + Inst::TrapIf { + // NBE == "> unsigned"; args above are reversed; this tests limit_reg > rsp. + cc: CC::NBE, + trap_code: TrapCode::STACK_OVERFLOW, + }, + ] + } + + fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable) -> Self::I { + let mem: SyntheticAmode = mem.into(); + Inst::lea(mem, into_reg) + } + + fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg { + // As per comment on trait definition, we must return a caller-save + // register that is not used as an argument here. + debug_assert!(!is_callee_save_systemv( + regs::r10().to_real_reg().unwrap(), + false + )); + regs::r10() + } + + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Self::I { + // Only ever used for I64s and vectors; if that changes, see if the + // ExtKind below needs to be changed. + assert!(ty == I64 || ty.is_vector()); + let mem = Amode::imm_reg(offset, base); + Inst::load(ty, mem, into_reg, ExtKind::None) + } + + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Self::I { + let ty = match ty { + // See `gen_load_stack`. + types::F16 => types::F32, + _ => ty, + }; + let mem = Amode::imm_reg(offset, base); + Inst::store(ty, from_reg, mem) + } + + fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { + let (alu_op, amount) = if amount >= 0 { + (AluRmiROpcode::Add, amount) + } else { + (AluRmiROpcode::Sub, -amount) + }; + + let amount = amount as u32; + + smallvec![Inst::alu_rmi_r( + OperandSize::Size64, + alu_op, + RegMemImm::imm(amount), + Writable::from_reg(regs::rsp()), + )] + } + + fn gen_prologue_frame_setup( + _call_conv: isa::CallConv, + flags: &settings::Flags, + _isa_flags: &x64_settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + let r_rsp = regs::rsp(); + let r_rbp = regs::rbp(); + let w_rbp = Writable::from_reg(r_rbp); + let mut insts = SmallVec::new(); + // `push %rbp` + // RSP before the call will be 0 % 16. So here, it is 8 % 16. + insts.push(Inst::push64(RegMemImm::reg(r_rbp))); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::PushFrameRegs { + offset_upward_to_caller_sp: frame_layout.setup_area_size, + }, + }); + } + + // `mov %rsp, %rbp` + // RSP is now 0 % 16 + insts.push(Inst::mov_r_r(OperandSize::Size64, r_rsp, w_rbp)); + + insts + } + + fn gen_epilogue_frame_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + _isa_flags: &x64_settings::Flags, + _frame_layout: &FrameLayout, + ) -> SmallInstVec { + let mut insts = SmallVec::new(); + // `mov %rbp, %rsp` + insts.push(Inst::mov_r_r( + OperandSize::Size64, + regs::rbp(), + Writable::from_reg(regs::rsp()), + )); + // `pop %rbp` + insts.push(Inst::pop64(Writable::from_reg(regs::rbp()))); + insts + } + + fn gen_return( + call_conv: CallConv, + _isa_flags: &x64_settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallInstVec { + // Emit return instruction. + let stack_bytes_to_pop = if call_conv == CallConv::Tail { + frame_layout.tail_args_size + } else { + 0 + }; + smallvec![Inst::ret(stack_bytes_to_pop)] + } + + fn gen_probestack(insts: &mut SmallInstVec, frame_size: u32) { + insts.push(Inst::imm( + OperandSize::Size32, + frame_size as u64, + Writable::from_reg(regs::rax()), + )); + insts.push(Inst::CallKnown { + // No need to include arg here: we are post-regalloc + // so no constraints will be seen anyway. + info: Box::new(CallInfo::empty( + ExternalName::LibCall(LibCall::Probestack), + CallConv::Probestack, + )), + }); + } + + fn gen_inline_probestack( + insts: &mut SmallInstVec, + call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ) { + // Unroll at most n consecutive probes, before falling back to using a loop + // + // This was number was picked because the loop version is 38 bytes long. We can fit + // 4 inline probes in that space, so unroll if its beneficial in terms of code size. + const PROBE_MAX_UNROLL: u32 = 4; + + // Calculate how many probes we need to perform. Round down, as we only + // need to probe whole guard_size regions we'd otherwise skip over. + let probe_count = frame_size / guard_size; + if probe_count == 0 { + // No probe necessary + } else if probe_count <= PROBE_MAX_UNROLL { + Self::gen_probestack_unroll(insts, guard_size, probe_count) + } else { + Self::gen_probestack_loop(insts, call_conv, frame_size, guard_size) + } + } + + fn gen_clobber_save( + _call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]> { + let mut insts = SmallVec::new(); + + // When a return_call within this function required more stack arguments than we have + // present, resize the incoming argument area of the frame to accommodate those arguments. + let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size; + if incoming_args_diff > 0 { + // Decrement the stack pointer to make space for the new arguments + insts.push(Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(incoming_args_diff), + Writable::from_reg(regs::rsp()), + )); + + // Make sure to keep the frame pointer and stack pointer in sync at this point + insts.push(Inst::mov_r_r( + OperandSize::Size64, + regs::rsp(), + Writable::from_reg(regs::rbp()), + )); + + let incoming_args_diff = i32::try_from(incoming_args_diff).unwrap(); + + // Move the saved frame pointer down by `incoming_args_diff` + insts.push(Inst::mov64_m_r( + Amode::imm_reg(incoming_args_diff, regs::rsp()), + Writable::from_reg(regs::r11()), + )); + insts.push(Inst::mov_r_m( + OperandSize::Size64, + regs::r11(), + Amode::imm_reg(0, regs::rsp()), + )); + + // Move the saved return address down by `incoming_args_diff` + insts.push(Inst::mov64_m_r( + Amode::imm_reg(incoming_args_diff + 8, regs::rsp()), + Writable::from_reg(regs::r11()), + )); + insts.push(Inst::mov_r_m( + OperandSize::Size64, + regs::r11(), + Amode::imm_reg(8, regs::rsp()), + )); + } + + // We need to factor `incoming_args_diff` into the offset upward here, as we have grown + // the argument area -- `setup_area_size` alone will not be the correct offset up to the + // original caller's SP. + let offset_upward_to_caller_sp = frame_layout.setup_area_size + incoming_args_diff; + if flags.unwind_info() && offset_upward_to_caller_sp > 0 { + // Emit unwind info: start the frame. The frame (from unwind + // consumers' point of view) starts at clobbbers, just below + // the FP and return address. Spill slots and stack slots are + // part of our actual frame but do not concern the unwinder. + insts.push(Inst::Unwind { + inst: UnwindInst::DefineNewFrame { + offset_downward_to_clobbers: frame_layout.clobber_size, + offset_upward_to_caller_sp, + }, + }); + } + + // Adjust the stack pointer downward for clobbers and the function fixed + // frame (spillslots, storage slots, and argument area). + let stack_size = frame_layout.fixed_frame_storage_size + + frame_layout.clobber_size + + frame_layout.outgoing_args_size; + if stack_size > 0 { + insts.push(Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(stack_size), + Writable::from_reg(regs::rsp()), + )); + } + + // Store each clobbered register in order at offsets from RSP, + // placing them above the fixed frame slots. + let clobber_offset = + frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size; + let mut cur_offset = 0; + for reg in &frame_layout.clobbered_callee_saves { + let r_reg = reg.to_reg(); + let ty = match r_reg.class() { + RegClass::Int => types::I64, + RegClass::Float => types::I8X16, + RegClass::Vector => unreachable!(), + }; + + // Align to 8 or 16 bytes as required by the storage type of the clobber. + cur_offset = align_to(cur_offset, ty.bytes()); + let off = cur_offset; + cur_offset += ty.bytes(); + + insts.push(Inst::store( + ty, + r_reg.into(), + Amode::imm_reg(i32::try_from(off + clobber_offset).unwrap(), regs::rsp()), + )); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::SaveReg { + clobber_offset: off, + reg: r_reg, + }, + }); + } + } + + insts + } + + fn gen_clobber_restore( + _call_conv: isa::CallConv, + _flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]> { + let mut insts = SmallVec::new(); + + // Restore regs by loading from offsets of RSP. We compute the offset from + // the same base as above in clobber_save, as RSP won't change between the + // prologue and epilogue. + let mut cur_offset = + frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size; + for reg in &frame_layout.clobbered_callee_saves { + let rreg = reg.to_reg(); + let ty = match rreg.class() { + RegClass::Int => types::I64, + RegClass::Float => types::I8X16, + RegClass::Vector => unreachable!(), + }; + + // Align to 8 or 16 bytes as required by the storage type of the clobber. + cur_offset = align_to(cur_offset, ty.bytes()); + + insts.push(Inst::load( + ty, + Amode::imm_reg(cur_offset.try_into().unwrap(), regs::rsp()), + Writable::from_reg(rreg.into()), + ExtKind::None, + )); + + cur_offset += ty.bytes(); + } + + let stack_size = frame_layout.fixed_frame_storage_size + + frame_layout.clobber_size + + frame_layout.outgoing_args_size; + + // Adjust RSP back upward. + if stack_size > 0 { + insts.push(Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(stack_size), + Writable::from_reg(regs::rsp()), + )); + } + + insts + } + + /// Generate a call instruction/sequence. + fn gen_call(dest: &CallDest, tmp: Writable, info: CallInfo<()>) -> SmallVec<[Self::I; 2]> { + let mut insts = SmallVec::new(); + match dest { + &CallDest::ExtName(ref name, RelocDistance::Near) => { + let info = Box::new(info.map(|()| name.clone())); + insts.push(Inst::call_known(info)); + } + &CallDest::ExtName(ref name, RelocDistance::Far) => { + insts.push(Inst::LoadExtName { + dst: tmp, + name: Box::new(name.clone()), + offset: 0, + distance: RelocDistance::Far, + }); + let info = Box::new(info.map(|()| RegMem::reg(tmp.to_reg()))); + insts.push(Inst::call_unknown(info)); + } + &CallDest::Reg(reg) => { + let info = Box::new(info.map(|()| RegMem::reg(reg))); + insts.push(Inst::call_unknown(info)); + } + } + insts + } + + fn gen_memcpy Writable>( + call_conv: isa::CallConv, + dst: Reg, + src: Reg, + size: usize, + mut alloc_tmp: F, + ) -> SmallVec<[Self::I; 8]> { + let mut insts = SmallVec::new(); + let arg0 = get_intreg_for_arg(call_conv, 0, 0).unwrap(); + let arg1 = get_intreg_for_arg(call_conv, 1, 1).unwrap(); + let arg2 = get_intreg_for_arg(call_conv, 2, 2).unwrap(); + let temp = alloc_tmp(Self::word_type()); + let temp2 = alloc_tmp(Self::word_type()); + insts.push(Inst::imm(OperandSize::Size64, size as u64, temp)); + // We use an indirect call and a full LoadExtName because we do not have + // information about the libcall `RelocDistance` here, so we + // conservatively use the more flexible calling sequence. + insts.push(Inst::LoadExtName { + dst: temp2, + name: Box::new(ExternalName::LibCall(LibCall::Memcpy)), + offset: 0, + distance: RelocDistance::Far, + }); + let callee_pop_size = 0; + insts.push(Inst::call_unknown(Box::new(CallInfo { + dest: RegMem::reg(temp2.to_reg()), + uses: smallvec![ + CallArgPair { + vreg: dst, + preg: arg0 + }, + CallArgPair { + vreg: src, + preg: arg1 + }, + CallArgPair { + vreg: temp.to_reg(), + preg: arg2 + }, + ], + defs: smallvec![], + clobbers: Self::get_regs_clobbered_by_call(call_conv), + callee_pop_size, + callee_conv: call_conv, + caller_conv: call_conv, + }))); + insts + } + + fn get_number_of_spillslots_for_value( + rc: RegClass, + vector_scale: u32, + _isa_flags: &Self::F, + ) -> u32 { + // We allocate in terms of 8-byte slots. + match rc { + RegClass::Int => 1, + RegClass::Float => vector_scale / 8, + RegClass::Vector => unreachable!(), + } + } + + fn get_machine_env(flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv { + if flags.enable_pinned_reg() { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(|| create_reg_env_systemv(true)) + } else { + static MACHINE_ENV: OnceLock = OnceLock::new(); + MACHINE_ENV.get_or_init(|| create_reg_env_systemv(false)) + } + } + + fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> PRegSet { + match call_conv_of_callee { + CallConv::Winch => ALL_CLOBBERS, + CallConv::WindowsFastcall => WINDOWS_CLOBBERS, + _ => SYSV_CLOBBERS, + } + } + + fn get_ext_mode( + _call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension { + specified + } + + fn compute_frame_layout( + call_conv: CallConv, + flags: &settings::Flags, + _sig: &Signature, + regs: &[Writable], + _is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + outgoing_args_size: u32, + ) -> FrameLayout { + debug_assert!(tail_args_size >= incoming_args_size); + + let mut regs: Vec> = match call_conv { + // The `winch` calling convention doesn't have any callee-save + // registers. + CallConv::Winch => vec![], + CallConv::Fast | CallConv::Cold | CallConv::SystemV | CallConv::Tail => regs + .iter() + .cloned() + .filter(|r| is_callee_save_systemv(r.to_reg(), flags.enable_pinned_reg())) + .collect(), + CallConv::WindowsFastcall => regs + .iter() + .cloned() + .filter(|r| is_callee_save_fastcall(r.to_reg(), flags.enable_pinned_reg())) + .collect(), + CallConv::Probestack => todo!("probestack?"), + CallConv::AppleAarch64 => unreachable!(), + }; + // Sort registers for deterministic code output. We can do an unstable sort because the + // registers will be unique (there are no dups). + regs.sort_unstable(); + + // Compute clobber size. + let clobber_size = compute_clobber_size(®s); + + // Compute setup area size. + let setup_area_size = 16; // RBP, return address + + // Return FrameLayout structure. + FrameLayout { + incoming_args_size, + tail_args_size: align_to(tail_args_size, 16), + setup_area_size, + clobber_size, + fixed_frame_storage_size, + outgoing_args_size, + clobbered_callee_saves: regs, + } + } +} + +impl X64CallSite { + pub fn emit_return_call( + mut self, + ctx: &mut Lower, + args: isle::ValueSlice, + _backend: &X64Backend, + ) { + let new_stack_arg_size = + u32::try_from(self.sig(ctx.sigs()).sized_stack_arg_space()).unwrap(); + + ctx.abi_mut().accumulate_tail_args_size(new_stack_arg_size); + + // Put all arguments in registers and stack slots (within that newly + // allocated stack space). + self.emit_args(ctx, args); + self.emit_stack_ret_arg_for_tail_call(ctx); + + // Finally, do the actual tail call! + let dest = self.dest().clone(); + let uses = self.take_uses(); + let tmp = ctx.temp_writable_gpr(); + match dest { + CallDest::ExtName(callee, RelocDistance::Near) => { + let info = Box::new(ReturnCallInfo { + dest: callee, + uses, + tmp, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallKnown { info }); + } + CallDest::ExtName(callee, RelocDistance::Far) => { + let tmp2 = ctx.temp_writable_gpr(); + ctx.emit(Inst::LoadExtName { + dst: tmp2.to_writable_reg(), + name: Box::new(callee), + offset: 0, + distance: RelocDistance::Far, + }); + let info = Box::new(ReturnCallInfo { + dest: tmp2.to_reg().to_reg().into(), + uses, + tmp, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallUnknown { info }); + } + CallDest::Reg(callee) => { + let info = Box::new(ReturnCallInfo { + dest: callee.into(), + uses, + tmp, + new_stack_arg_size, + }); + ctx.emit(Inst::ReturnCallUnknown { info }); + } + } + } +} + +impl From for SyntheticAmode { + fn from(amode: StackAMode) -> Self { + // We enforce a 128 MB stack-frame size limit above, so these + // `expect()`s should never fail. + match amode { + StackAMode::IncomingArg(off, stack_args_size) => { + let offset = u32::try_from(off).expect( + "Offset in IncomingArg is greater than 4GB; should hit impl limit first", + ); + SyntheticAmode::IncomingArg { + offset: stack_args_size - offset, + } + } + StackAMode::Slot(off) => { + let off = i32::try_from(off) + .expect("Offset in Slot is greater than 2GB; should hit impl limit first"); + SyntheticAmode::slot_offset(off) + } + StackAMode::OutgoingArg(off) => { + let off = i32::try_from(off).expect( + "Offset in OutgoingArg is greater than 2GB; should hit impl limit first", + ); + SyntheticAmode::Real(Amode::ImmReg { + simm32: off, + base: regs::rsp(), + flags: MemFlags::trusted(), + }) + } + } + } +} + +fn get_intreg_for_arg(call_conv: CallConv, idx: usize, arg_idx: usize) -> Option { + let is_fastcall = call_conv == CallConv::WindowsFastcall; + + // Fastcall counts by absolute argument number; SysV counts by argument of + // this (integer) class. + let i = if is_fastcall { arg_idx } else { idx }; + match (i, is_fastcall) { + (0, false) => Some(regs::rdi()), + (1, false) => Some(regs::rsi()), + (2, false) => Some(regs::rdx()), + (3, false) => Some(regs::rcx()), + (4, false) => Some(regs::r8()), + (5, false) => Some(regs::r9()), + (0, true) => Some(regs::rcx()), + (1, true) => Some(regs::rdx()), + (2, true) => Some(regs::r8()), + (3, true) => Some(regs::r9()), + _ => None, + } +} + +fn get_fltreg_for_arg(call_conv: CallConv, idx: usize, arg_idx: usize) -> Option { + let is_fastcall = call_conv == CallConv::WindowsFastcall; + + // Fastcall counts by absolute argument number; SysV counts by argument of + // this (floating-point) class. + let i = if is_fastcall { arg_idx } else { idx }; + match (i, is_fastcall) { + (0, false) => Some(regs::xmm0()), + (1, false) => Some(regs::xmm1()), + (2, false) => Some(regs::xmm2()), + (3, false) => Some(regs::xmm3()), + (4, false) => Some(regs::xmm4()), + (5, false) => Some(regs::xmm5()), + (6, false) => Some(regs::xmm6()), + (7, false) => Some(regs::xmm7()), + (0, true) => Some(regs::xmm0()), + (1, true) => Some(regs::xmm1()), + (2, true) => Some(regs::xmm2()), + (3, true) => Some(regs::xmm3()), + _ => None, + } +} + +fn get_intreg_for_retval( + call_conv: CallConv, + flags: &settings::Flags, + intreg_idx: usize, + is_last: bool, +) -> Option { + match call_conv { + CallConv::Tail => match intreg_idx { + 0 => Some(regs::rax()), + 1 => Some(regs::rcx()), + 2 => Some(regs::rdx()), + 3 => Some(regs::rsi()), + 4 => Some(regs::rdi()), + 5 => Some(regs::r8()), + 6 => Some(regs::r9()), + 7 => Some(regs::r10()), + 8 => Some(regs::r11()), + // NB: `r15` is reserved as a scratch register. + _ => None, + }, + CallConv::Fast | CallConv::Cold | CallConv::SystemV => match intreg_idx { + 0 => Some(regs::rax()), + 1 => Some(regs::rdx()), + 2 if flags.enable_llvm_abi_extensions() => Some(regs::rcx()), + _ => None, + }, + CallConv::WindowsFastcall => match intreg_idx { + 0 => Some(regs::rax()), + 1 => Some(regs::rdx()), // The Rust ABI for i128s needs this. + _ => None, + }, + + CallConv::Winch => { + // TODO: Once Winch supports SIMD, this will need to be updated to support values + // returned in more than one register. + // https://github.com/bytecodealliance/wasmtime/issues/8093 + is_last.then(|| regs::rax()) + } + CallConv::Probestack => todo!(), + CallConv::AppleAarch64 => unreachable!(), + } +} + +fn get_fltreg_for_retval(call_conv: CallConv, fltreg_idx: usize, is_last: bool) -> Option { + match call_conv { + CallConv::Tail => match fltreg_idx { + 0 => Some(regs::xmm0()), + 1 => Some(regs::xmm1()), + 2 => Some(regs::xmm2()), + 3 => Some(regs::xmm3()), + 4 => Some(regs::xmm4()), + 5 => Some(regs::xmm5()), + 6 => Some(regs::xmm6()), + 7 => Some(regs::xmm7()), + _ => None, + }, + CallConv::Fast | CallConv::Cold | CallConv::SystemV => match fltreg_idx { + 0 => Some(regs::xmm0()), + 1 => Some(regs::xmm1()), + _ => None, + }, + CallConv::WindowsFastcall => match fltreg_idx { + 0 => Some(regs::xmm0()), + _ => None, + }, + CallConv::Winch => is_last.then(|| regs::xmm0()), + CallConv::Probestack => todo!(), + CallConv::AppleAarch64 => unreachable!(), + } +} + +fn is_callee_save_systemv(r: RealReg, enable_pinned_reg: bool) -> bool { + use regs::*; + match r.class() { + RegClass::Int => match r.hw_enc() { + ENC_RBX | ENC_RBP | ENC_R12 | ENC_R13 | ENC_R14 => true, + // R15 is the pinned register; if we're using it that way, + // it is effectively globally-allocated, and is not + // callee-saved. + ENC_R15 => !enable_pinned_reg, + _ => false, + }, + RegClass::Float => false, + RegClass::Vector => unreachable!(), + } +} + +fn is_callee_save_fastcall(r: RealReg, enable_pinned_reg: bool) -> bool { + use regs::*; + match r.class() { + RegClass::Int => match r.hw_enc() { + ENC_RBX | ENC_RBP | ENC_RSI | ENC_RDI | ENC_R12 | ENC_R13 | ENC_R14 => true, + // See above for SysV: we must treat the pinned reg specially. + ENC_R15 => !enable_pinned_reg, + _ => false, + }, + RegClass::Float => match r.hw_enc() { + 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 => true, + _ => false, + }, + RegClass::Vector => unreachable!(), + } +} + +fn compute_clobber_size(clobbers: &[Writable]) -> u32 { + let mut clobbered_size = 0; + for reg in clobbers { + match reg.to_reg().class() { + RegClass::Int => { + clobbered_size += 8; + } + RegClass::Float => { + clobbered_size = align_to(clobbered_size, 16); + clobbered_size += 16; + } + RegClass::Vector => unreachable!(), + } + } + align_to(clobbered_size, 16) +} + +const WINDOWS_CLOBBERS: PRegSet = windows_clobbers(); +const SYSV_CLOBBERS: PRegSet = sysv_clobbers(); +pub(crate) const ALL_CLOBBERS: PRegSet = all_clobbers(); + +const fn windows_clobbers() -> PRegSet { + PRegSet::empty() + .with(regs::gpr_preg(regs::ENC_RAX)) + .with(regs::gpr_preg(regs::ENC_RCX)) + .with(regs::gpr_preg(regs::ENC_RDX)) + .with(regs::gpr_preg(regs::ENC_R8)) + .with(regs::gpr_preg(regs::ENC_R9)) + .with(regs::gpr_preg(regs::ENC_R10)) + .with(regs::gpr_preg(regs::ENC_R11)) + .with(regs::fpr_preg(0)) + .with(regs::fpr_preg(1)) + .with(regs::fpr_preg(2)) + .with(regs::fpr_preg(3)) + .with(regs::fpr_preg(4)) + .with(regs::fpr_preg(5)) +} + +const fn sysv_clobbers() -> PRegSet { + PRegSet::empty() + .with(regs::gpr_preg(regs::ENC_RAX)) + .with(regs::gpr_preg(regs::ENC_RCX)) + .with(regs::gpr_preg(regs::ENC_RDX)) + .with(regs::gpr_preg(regs::ENC_RSI)) + .with(regs::gpr_preg(regs::ENC_RDI)) + .with(regs::gpr_preg(regs::ENC_R8)) + .with(regs::gpr_preg(regs::ENC_R9)) + .with(regs::gpr_preg(regs::ENC_R10)) + .with(regs::gpr_preg(regs::ENC_R11)) + .with(regs::fpr_preg(0)) + .with(regs::fpr_preg(1)) + .with(regs::fpr_preg(2)) + .with(regs::fpr_preg(3)) + .with(regs::fpr_preg(4)) + .with(regs::fpr_preg(5)) + .with(regs::fpr_preg(6)) + .with(regs::fpr_preg(7)) + .with(regs::fpr_preg(8)) + .with(regs::fpr_preg(9)) + .with(regs::fpr_preg(10)) + .with(regs::fpr_preg(11)) + .with(regs::fpr_preg(12)) + .with(regs::fpr_preg(13)) + .with(regs::fpr_preg(14)) + .with(regs::fpr_preg(15)) +} + +/// For calling conventions that clobber all registers. +const fn all_clobbers() -> PRegSet { + PRegSet::empty() + .with(regs::gpr_preg(regs::ENC_RAX)) + .with(regs::gpr_preg(regs::ENC_RCX)) + .with(regs::gpr_preg(regs::ENC_RDX)) + .with(regs::gpr_preg(regs::ENC_RBX)) + .with(regs::gpr_preg(regs::ENC_RSI)) + .with(regs::gpr_preg(regs::ENC_RDI)) + .with(regs::gpr_preg(regs::ENC_R8)) + .with(regs::gpr_preg(regs::ENC_R9)) + .with(regs::gpr_preg(regs::ENC_R10)) + .with(regs::gpr_preg(regs::ENC_R11)) + .with(regs::gpr_preg(regs::ENC_R12)) + .with(regs::gpr_preg(regs::ENC_R13)) + .with(regs::gpr_preg(regs::ENC_R14)) + .with(regs::gpr_preg(regs::ENC_R15)) + .with(regs::fpr_preg(0)) + .with(regs::fpr_preg(1)) + .with(regs::fpr_preg(2)) + .with(regs::fpr_preg(3)) + .with(regs::fpr_preg(4)) + .with(regs::fpr_preg(5)) + .with(regs::fpr_preg(6)) + .with(regs::fpr_preg(7)) + .with(regs::fpr_preg(8)) + .with(regs::fpr_preg(9)) + .with(regs::fpr_preg(10)) + .with(regs::fpr_preg(11)) + .with(regs::fpr_preg(12)) + .with(regs::fpr_preg(13)) + .with(regs::fpr_preg(14)) + .with(regs::fpr_preg(15)) +} + +fn create_reg_env_systemv(enable_pinned_reg: bool) -> MachineEnv { + fn preg(r: Reg) -> PReg { + r.to_real_reg().unwrap().into() + } + + let mut env = MachineEnv { + preferred_regs_by_class: [ + // Preferred GPRs: caller-saved in the SysV ABI. + vec![ + preg(regs::rsi()), + preg(regs::rdi()), + preg(regs::rax()), + preg(regs::rcx()), + preg(regs::rdx()), + preg(regs::r8()), + preg(regs::r9()), + preg(regs::r10()), + preg(regs::r11()), + ], + // Preferred XMMs: the first 8, which can have smaller encodings + // with AVX instructions. + vec![ + preg(regs::xmm0()), + preg(regs::xmm1()), + preg(regs::xmm2()), + preg(regs::xmm3()), + preg(regs::xmm4()), + preg(regs::xmm5()), + preg(regs::xmm6()), + preg(regs::xmm7()), + ], + // The Vector Regclass is unused + vec![], + ], + non_preferred_regs_by_class: [ + // Non-preferred GPRs: callee-saved in the SysV ABI. + vec![ + preg(regs::rbx()), + preg(regs::r12()), + preg(regs::r13()), + preg(regs::r14()), + ], + // Non-preferred XMMs: the last 8 registers, which can have larger + // encodings with AVX instructions. + vec![ + preg(regs::xmm8()), + preg(regs::xmm9()), + preg(regs::xmm10()), + preg(regs::xmm11()), + preg(regs::xmm12()), + preg(regs::xmm13()), + preg(regs::xmm14()), + preg(regs::xmm15()), + ], + // The Vector Regclass is unused + vec![], + ], + fixed_stack_slots: vec![], + scratch_by_class: [None, None, None], + }; + + debug_assert_eq!(regs::r15(), regs::pinned_reg()); + if !enable_pinned_reg { + env.non_preferred_regs_by_class[0].push(preg(regs::r15())); + } + + env +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/evex.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/evex.rs new file mode 100644 index 00000000000000..bacbf841643b16 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/evex.rs @@ -0,0 +1,747 @@ +//! Encodes EVEX instructions. These instructions are those added by the AVX-512 extensions. The +//! EVEX encoding requires a 4-byte prefix: +//! +//! Byte 0: 0x62 +//! ┌───┬───┬───┬───┬───┬───┬───┬───┐ +//! Byte 1: │ R │ X │ B │ R'│ 0 │ 0 │ m │ m │ +//! ├───┼───┼───┼───┼───┼───┼───┼───┤ +//! Byte 2: │ W │ v │ v │ v │ v │ 1 │ p │ p │ +//! ├───┼───┼───┼───┼───┼───┼───┼───┤ +//! Byte 3: │ z │ L'│ L │ b │ V'│ a │ a │ a │ +//! └───┴───┴───┴───┴───┴───┴───┴───┘ +//! +//! The prefix is then followed by the opcode byte, the ModR/M byte, and other optional suffixes +//! (e.g. SIB byte, displacements, immediates) based on the instruction (see section 2.6, Intel +//! Software Development Manual, volume 2A). + +use super::rex::{self, LegacyPrefixes, OpcodeMap}; +use crate::isa::x64::args::{Amode, Avx512TupleType}; +use crate::isa::x64::inst::Inst; +use crate::MachBuffer; +use core::ops::RangeInclusive; + +/// Constructs an EVEX-encoded instruction using a builder pattern. This approach makes it visually +/// easier to transform something the manual's syntax, `EVEX.256.66.0F38.W1 1F /r` to code: +/// `EvexInstruction::new().length(...).prefix(...).map(...).w(true).opcode(0x1F).reg(...).rm(...)`. +pub struct EvexInstruction { + bits: u32, + opcode: u8, + reg: Register, + rm: RegisterOrAmode, + tuple_type: Option, + imm: Option, +} + +/// Because some of the bit flags in the EVEX prefix are reversed and users of `EvexInstruction` may +/// choose to skip setting fields, here we set some sane defaults. Note that: +/// - the first byte is always `0x62` but you will notice it at the end of the default `bits` value +/// implemented--remember the little-endian order +/// - some bits are always set to certain values: bits 10-11 to 0, bit 18 to 1 +/// - the other bits set correspond to reversed bits: R, X, B, R' (byte 1), vvvv (byte 2), V' (byte +/// 3). +/// +/// See the `default_emission` test for what these defaults are equivalent to (e.g. using RAX, +/// unsetting the W bit, etc.) +impl Default for EvexInstruction { + fn default() -> Self { + Self { + bits: 0x08_7C_F0_62, + opcode: 0, + reg: Register::default(), + rm: RegisterOrAmode::Register(Register::default()), + tuple_type: None, + imm: None, + } + } +} + +#[allow(non_upper_case_globals)] // This makes it easier to match the bit range names to the manual's names. +impl EvexInstruction { + /// Construct a default EVEX instruction. + pub fn new() -> Self { + Self::default() + } + + /// Set the length of the instruction . Note that there are sets of instructions (i.e. rounding, + /// memory broadcast) that modify the same underlying bits--at some point (TODO) we can add a + /// way to set those context bits and verify that both are not used (e.g. rounding AND length). + /// For now, this method is very convenient. + #[inline(always)] + pub fn length(mut self, length: EvexVectorLength) -> Self { + self.write(Self::LL, EvexContext::Other { length }.bits() as u32); + self + } + + /// Set the legacy prefix byte of the instruction: None | 66 | F0 | F2 | F3. EVEX instructions + /// pack these into the prefix, not as separate bytes. + #[inline(always)] + pub fn prefix(mut self, prefix: LegacyPrefixes) -> Self { + self.write(Self::pp, prefix.bits() as u32); + self + } + + /// Set the opcode map byte of the instruction: None | 0F | 0F38 | 0F3A. EVEX instructions pack + /// these into the prefix, not as separate bytes. + #[inline(always)] + pub fn map(mut self, map: OpcodeMap) -> Self { + self.write(Self::mm, map.bits() as u32); + self + } + + /// Set the W bit, typically used to indicate an instruction using 64 bits of an operand (e.g. + /// 64 bit lanes). EVEX packs this bit in the EVEX prefix; previous encodings used the REX + /// prefix. + #[inline(always)] + pub fn w(mut self, w: bool) -> Self { + self.write(Self::W, w as u32); + self + } + + /// Set the instruction opcode byte. + #[inline(always)] + pub fn opcode(mut self, opcode: u8) -> Self { + self.opcode = opcode; + self + } + + /// Set the "tuple type" which is used for 8-bit scaling when a memory + /// operand is used. + #[inline(always)] + pub fn tuple_type(mut self, tt: Avx512TupleType) -> Self { + self.tuple_type = Some(tt); + self + } + + /// Set the register to use for the `reg` bits; many instructions use this as the write operand. + /// Setting this affects both the ModRM byte (`reg` section) and the EVEX prefix (the extension + /// bits for register encodings > 8). + #[inline(always)] + pub fn reg(mut self, reg: impl Into) -> Self { + self.reg = reg.into(); + let r = !(self.reg.0 >> 3) & 1; + let r_ = !(self.reg.0 >> 4) & 1; + self.write(Self::R, r as u32); + self.write(Self::R_, r_ as u32); + self + } + + /// Set the mask to use. See section 2.6 in the Intel Software Developer's Manual, volume 2A for + /// more details. + #[allow(dead_code)] + #[inline(always)] + pub fn mask(mut self, mask: EvexMasking) -> Self { + self.write(Self::aaa, mask.aaa_bits() as u32); + self.write(Self::z, mask.z_bit() as u32); + self + } + + /// Set the `vvvvv` register; some instructions allow using this as a second, non-destructive + /// source register in 3-operand instructions (e.g. 2 read, 1 write). + #[allow(dead_code)] + #[inline(always)] + pub fn vvvvv(mut self, reg: impl Into) -> Self { + let reg = reg.into(); + self.write(Self::vvvv, !(reg.0 as u32) & 0b1111); + self.write(Self::V_, !(reg.0 as u32 >> 4) & 0b1); + self + } + + /// Set the register to use for the `rm` bits; many instructions use this + /// as the "read from register/memory" operand. Setting this affects both + /// the ModRM byte (`rm` section) and the EVEX prefix (the extension bits + /// for register encodings > 8). + #[inline(always)] + pub fn rm(mut self, reg: impl Into) -> Self { + // NB: See Table 2-31. 32-Register Support in 64-bit Mode Using EVEX + // with Embedded REX Bits + self.rm = reg.into(); + let x = match &self.rm { + RegisterOrAmode::Register(r) => r.0 >> 4, + RegisterOrAmode::Amode(Amode::ImmRegRegShift { index, .. }) => { + index.to_real_reg().unwrap().hw_enc() >> 3 + } + + // These two modes technically don't use the X bit, so leave it at + // 0. + RegisterOrAmode::Amode(Amode::ImmReg { .. }) => 0, + RegisterOrAmode::Amode(Amode::RipRelative { .. }) => 0, + }; + // The X bit is stored in an inverted format, so invert it here. + self.write(Self::X, u32::from(!x & 1)); + + let b = match &self.rm { + RegisterOrAmode::Register(r) => r.0 >> 3, + RegisterOrAmode::Amode(Amode::ImmReg { base, .. }) => { + base.to_real_reg().unwrap().hw_enc() >> 3 + } + RegisterOrAmode::Amode(Amode::ImmRegRegShift { base, .. }) => { + base.to_real_reg().unwrap().hw_enc() >> 3 + } + // The 4th bit of %rip is 0 + RegisterOrAmode::Amode(Amode::RipRelative { .. }) => 0, + }; + // The B bit is stored in an inverted format, so invert it here. + self.write(Self::B, u32::from(!b & 1)); + self + } + + /// Set the imm byte. + #[inline(always)] + pub fn imm(mut self, imm: u8) -> Self { + self.imm = Some(imm); + self + } + + /// Emit the EVEX-encoded instruction to the code sink: + /// + /// - the 4-byte EVEX prefix; + /// - the opcode byte; + /// - the ModR/M byte + /// - SIB bytes, if necessary + /// - an optional immediate, if necessary (not currently implemented) + pub fn encode(&self, sink: &mut MachBuffer) { + if let RegisterOrAmode::Amode(amode) = &self.rm { + if let Some(trap_code) = amode.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + sink.put4(self.bits); + sink.put1(self.opcode); + + match &self.rm { + RegisterOrAmode::Register(reg) => { + let rm: u8 = (*reg).into(); + sink.put1(rex::encode_modrm(3, self.reg.0 & 7, rm & 7)); + } + RegisterOrAmode::Amode(amode) => { + let scaling = self.scaling_for_8bit_disp(); + + let bytes_at_end = if self.imm.is_some() { 1 } else { 0 }; + rex::emit_modrm_sib_disp(sink, self.reg.0 & 7, amode, bytes_at_end, Some(scaling)); + } + } + if let Some(imm) = self.imm { + sink.put1(imm); + } + } + + // In order to simplify the encoding of the various bit ranges in the prefix, we specify those + // ranges according to the table below (extracted from the Intel Software Development Manual, + // volume 2A). Remember that, because we pack the 4-byte prefix into a little-endian `u32`, this + // chart should be read from right-to-left, top-to-bottom. Note also that we start ranges at bit + // 8, leaving bits 0-7 for the mandatory `0x62`. + // ┌───┬───┬───┬───┬───┬───┬───┬───┐ + // Byte 1: │ R │ X │ B │ R'│ 0 │ 0 │ m │ m │ + // ├───┼───┼───┼───┼───┼───┼───┼───┤ + // Byte 2: │ W │ v │ v │ v │ v │ 1 │ p │ p │ + // ├───┼───┼───┼───┼───┼───┼───┼───┤ + // Byte 3: │ z │ L'│ L │ b │ V'│ a │ a │ a │ + // └───┴───┴───┴───┴───┴───┴───┴───┘ + + // Byte 1: + const mm: RangeInclusive = 8..=9; + const R_: RangeInclusive = 12..=12; + const B: RangeInclusive = 13..=13; + const X: RangeInclusive = 14..=14; + const R: RangeInclusive = 15..=15; + + // Byte 2: + const pp: RangeInclusive = 16..=17; + const vvvv: RangeInclusive = 19..=22; + const W: RangeInclusive = 23..=23; + + // Byte 3: + const aaa: RangeInclusive = 24..=26; + const V_: RangeInclusive = 27..=27; + const b: RangeInclusive = 28..=28; + const LL: RangeInclusive = 29..=30; + const z: RangeInclusive = 31..=31; + + // A convenience method for writing the `value` bits to the given range in `self.bits`. + #[inline] + fn write(&mut self, range: RangeInclusive, value: u32) { + assert!(ExactSizeIterator::len(&range) > 0); + let size = range.end() - range.start() + 1; // Calculate the number of bits in the range. + let mask: u32 = (1 << size) - 1; // Generate a bit mask. + debug_assert!( + value <= mask, + "The written value should have fewer than {size} bits." + ); + let mask_complement = !(mask << *range.start()); // Create the bitwise complement for the clear mask. + self.bits &= mask_complement; // Clear the bits in `range`; otherwise the OR below may allow previously-set bits to slip through. + let value = value << *range.start(); // Place the value in the correct location (assumes `value <= mask`). + self.bits |= value; // Modify the bits in `range`. + } + + /// A convenience method for reading given range of bits in `self.bits` + /// shifted to the LSB of the returned value.. + #[inline] + fn read(&self, range: RangeInclusive) -> u32 { + (self.bits >> range.start()) & ((1 << range.len()) - 1) + } + + fn scaling_for_8bit_disp(&self) -> i8 { + use Avx512TupleType::*; + + let vector_size_scaling = || match self.read(Self::LL) { + 0b00 => 16, + 0b01 => 32, + 0b10 => 64, + _ => unreachable!(), + }; + + match self.tuple_type { + Some(Full) => { + if self.read(Self::b) == 1 { + if self.read(Self::W) == 0 { + 4 + } else { + 8 + } + } else { + vector_size_scaling() + } + } + Some(FullMem) => vector_size_scaling(), + Some(Mem128) => 16, + None => panic!("tuple type was not set"), + } + } +} + +/// Describe the register index to use. This wrapper is a type-safe way to pass +/// around the registers defined in `inst/regs.rs`. +#[derive(Debug, Copy, Clone, Default)] +pub struct Register(u8); +impl From for Register { + fn from(reg: u8) -> Self { + debug_assert!(reg < 16); + Self(reg) + } +} +impl Into for Register { + fn into(self) -> u8 { + self.0 + } +} + +#[allow(missing_docs)] +#[derive(Debug, Clone)] +pub enum RegisterOrAmode { + Register(Register), + Amode(Amode), +} + +impl From for RegisterOrAmode { + fn from(reg: u8) -> Self { + RegisterOrAmode::Register(reg.into()) + } +} + +impl From for RegisterOrAmode { + fn from(amode: Amode) -> Self { + RegisterOrAmode::Amode(amode) + } +} + +/// Defines the EVEX context for the `L'`, `L`, and `b` bits (bits 6:4 of EVEX P2 byte). Table 2-36 in +/// section 2.6.10 (Intel Software Development Manual, volume 2A) describes how these bits can be +/// used together for certain classes of instructions; i.e., special care should be taken to ensure +/// that instructions use an applicable correct `EvexContext`. Table 2-39 contains cases where +/// opcodes can result in an #UD. +#[allow(dead_code, missing_docs)] // Rounding and broadcast modes are not yet used. +pub enum EvexContext { + RoundingRegToRegFP { + rc: EvexRoundingControl, + }, + NoRoundingFP { + sae: bool, + length: EvexVectorLength, + }, + MemoryOp { + broadcast: bool, + length: EvexVectorLength, + }, + Other { + length: EvexVectorLength, + }, +} + +impl Default for EvexContext { + fn default() -> Self { + Self::Other { + length: EvexVectorLength::default(), + } + } +} + +impl EvexContext { + /// Encode the `L'`, `L`, and `b` bits (bits 6:4 of EVEX P2 byte) for merging with the P2 byte. + pub fn bits(&self) -> u8 { + match self { + Self::RoundingRegToRegFP { rc } => 0b001 | rc.bits() << 1, + Self::NoRoundingFP { sae, length } => (*sae as u8) | length.bits() << 1, + Self::MemoryOp { broadcast, length } => (*broadcast as u8) | length.bits() << 1, + Self::Other { length } => length.bits() << 1, + } + } +} + +/// The EVEX format allows choosing a vector length in the `L'` and `L` bits; see `EvexContext`. +#[allow(dead_code, missing_docs)] // Wider-length vectors are not yet used. +pub enum EvexVectorLength { + V128, + V256, + V512, +} + +impl EvexVectorLength { + /// Encode the `L'` and `L` bits for merging with the P2 byte. + fn bits(&self) -> u8 { + match self { + Self::V128 => 0b00, + Self::V256 => 0b01, + Self::V512 => 0b10, + // 0b11 is reserved (#UD). + } + } +} + +impl Default for EvexVectorLength { + fn default() -> Self { + Self::V128 + } +} + +/// The EVEX format allows defining rounding control in the `L'` and `L` bits; see `EvexContext`. +#[allow(dead_code, missing_docs)] // Rounding controls are not yet used. +pub enum EvexRoundingControl { + RNE, + RD, + RU, + RZ, +} + +impl EvexRoundingControl { + /// Encode the `L'` and `L` bits for merging with the P2 byte. + fn bits(&self) -> u8 { + match self { + Self::RNE => 0b00, + Self::RD => 0b01, + Self::RU => 0b10, + Self::RZ => 0b11, + } + } +} + +/// Defines the EVEX masking behavior; masking support is described in section 2.6.4 of the Intel +/// Software Development Manual, volume 2A. +#[allow(dead_code, missing_docs)] // Masking is not yet used. +pub enum EvexMasking { + None, + Merging { k: u8 }, + Zeroing { k: u8 }, +} + +impl Default for EvexMasking { + fn default() -> Self { + EvexMasking::None + } +} + +impl EvexMasking { + /// Encode the `z` bit for merging with the P2 byte. + pub fn z_bit(&self) -> u8 { + match self { + Self::None | Self::Merging { .. } => 0, + Self::Zeroing { .. } => 1, + } + } + + /// Encode the `aaa` bits for merging with the P2 byte. + pub fn aaa_bits(&self) -> u8 { + match self { + Self::None => 0b000, + Self::Merging { k } | Self::Zeroing { k } => { + debug_assert!(*k <= 7); + *k + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::MemFlags; + use crate::isa::x64::args::Gpr; + use crate::isa::x64::inst::regs; + use std::vec::Vec; + + // As a sanity test, we verify that the output of `xed-asmparse-main 'vpabsq xmm0{k0}, + // xmm1'` matches this EVEX encoding machinery. + #[test] + fn vpabsq() { + let mut tmp = MachBuffer::::new(); + let tests: &[(crate::Reg, RegisterOrAmode, Vec)] = &[ + // vpabsq %xmm1, %xmm0 + ( + regs::xmm0(), + regs::xmm1().to_real_reg().unwrap().hw_enc().into(), + vec![0x62, 0xf2, 0xfd, 0x08, 0x1f, 0xc1], + ), + // vpabsq %xmm8, %xmm10 + ( + regs::xmm10(), + regs::xmm8().to_real_reg().unwrap().hw_enc().into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0xd0], + ), + // vpabsq %xmm15, %xmm3 + ( + regs::xmm3(), + regs::xmm15().to_real_reg().unwrap().hw_enc().into(), + vec![0x62, 0xd2, 0xfd, 0x08, 0x1f, 0xdf], + ), + // vpabsq (%rsi), %xmm12 + ( + regs::xmm12(), + Amode::ImmReg { + simm32: 0, + base: regs::rsi(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x72, 0xfd, 0x08, 0x1f, 0x26], + ), + // vpabsq 8(%r15), %xmm14 + ( + regs::xmm14(), + Amode::ImmReg { + simm32: 8, + base: regs::r15(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0xb7, 0x08, 0x00, 0x00, 0x00], + ), + // vpabsq 16(%r15), %xmm14 + ( + regs::xmm14(), + Amode::ImmReg { + simm32: 16, + base: regs::r15(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0x77, 0x01], + ), + // vpabsq 17(%rax), %xmm3 + ( + regs::xmm3(), + Amode::ImmReg { + simm32: 17, + base: regs::rax(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0xf2, 0xfd, 0x08, 0x1f, 0x98, 0x11, 0x00, 0x00, 0x00], + ), + // vpabsq (%rbx, %rsi, 8), %xmm9 + ( + regs::xmm9(), + Amode::ImmRegRegShift { + simm32: 0, + base: Gpr::unwrap_new(regs::rbx()), + index: Gpr::unwrap_new(regs::rsi()), + shift: 3, + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x72, 0xfd, 0x08, 0x1f, 0x0c, 0xf3], + ), + // vpabsq 1(%r11, %rdi, 4), %xmm13 + ( + regs::xmm13(), + Amode::ImmRegRegShift { + simm32: 1, + base: Gpr::unwrap_new(regs::r11()), + index: Gpr::unwrap_new(regs::rdi()), + shift: 2, + flags: MemFlags::trusted(), + } + .into(), + vec![ + 0x62, 0x52, 0xfd, 0x08, 0x1f, 0xac, 0xbb, 0x01, 0x00, 0x00, 0x00, + ], + ), + // vpabsq 128(%rsp, %r10, 2), %xmm5 + ( + regs::xmm5(), + Amode::ImmRegRegShift { + simm32: 128, + base: Gpr::unwrap_new(regs::rsp()), + index: Gpr::unwrap_new(regs::r10()), + shift: 1, + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0xb2, 0xfd, 0x08, 0x1f, 0x6c, 0x54, 0x08], + ), + // vpabsq 112(%rbp, %r13, 1), %xmm6 + ( + regs::xmm6(), + Amode::ImmRegRegShift { + simm32: 112, + base: Gpr::unwrap_new(regs::rbp()), + index: Gpr::unwrap_new(regs::r13()), + shift: 0, + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0xb2, 0xfd, 0x08, 0x1f, 0x74, 0x2d, 0x07], + ), + // vpabsq (%rbp, %r13, 1), %xmm7 + ( + regs::xmm7(), + Amode::ImmRegRegShift { + simm32: 0, + base: Gpr::unwrap_new(regs::rbp()), + index: Gpr::unwrap_new(regs::r13()), + shift: 0, + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0xb2, 0xfd, 0x08, 0x1f, 0x7c, 0x2d, 0x00], + ), + // vpabsq 2032(%r12), %xmm8 + ( + regs::xmm8(), + Amode::ImmReg { + simm32: 2032, + base: regs::r12(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0x44, 0x24, 0x7f], + ), + // vpabsq 2048(%r13), %xmm9 + ( + regs::xmm9(), + Amode::ImmReg { + simm32: 2048, + base: regs::r13(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0x8d, 0x00, 0x08, 0x00, 0x00], + ), + // vpabsq -16(%r14), %xmm10 + ( + regs::xmm10(), + Amode::ImmReg { + simm32: -16, + base: regs::r14(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0x56, 0xff], + ), + // vpabsq -5(%r15), %xmm11 + ( + regs::xmm11(), + Amode::ImmReg { + simm32: -5, + base: regs::r15(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x52, 0xfd, 0x08, 0x1f, 0x9f, 0xfb, 0xff, 0xff, 0xff], + ), + // vpabsq -2048(%rdx), %xmm12 + ( + regs::xmm12(), + Amode::ImmReg { + simm32: -2048, + base: regs::rdx(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x72, 0xfd, 0x08, 0x1f, 0x62, 0x80], + ), + // vpabsq -2064(%rsi), %xmm13 + ( + regs::xmm13(), + Amode::ImmReg { + simm32: -2064, + base: regs::rsi(), + flags: MemFlags::trusted(), + } + .into(), + vec![0x62, 0x72, 0xfd, 0x08, 0x1f, 0xae, 0xf0, 0xf7, 0xff, 0xff], + ), + // a: vpabsq a(%rip), %xmm14 + ( + regs::xmm14(), + Amode::RipRelative { + target: tmp.get_label(), + } + .into(), + vec![0x62, 0x72, 0xfd, 0x08, 0x1f, 0x35, 0xf6, 0xff, 0xff, 0xff], + ), + ]; + + for (dst, src, encoding) in tests { + let mut sink = MachBuffer::new(); + let label = sink.get_label(); + sink.bind_label(label, &mut Default::default()); + EvexInstruction::new() + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F38) + .w(true) + .opcode(0x1F) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src.clone()) + .length(EvexVectorLength::V128) + .tuple_type(Avx512TupleType::Full) + .encode(&mut sink); + let bytes0 = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!( + bytes0.as_slice(), + encoding.as_slice(), + "dst={dst:?} src={src:?}" + ); + } + } + + /// Verify that the defaults are equivalent to an instruction with a `0x00` opcode using the + /// "0" register (i.e. `rax`), with sane defaults for the various configurable parameters. This + /// test is more interesting than it may appear because some of the parameters have flipped-bit + /// representations (e.g. `vvvvv`) so emitting 0s as a default will not work. + #[test] + fn default_emission() { + let mut sink = MachBuffer::new(); + EvexInstruction::new().encode(&mut sink); + let bytes0 = sink + .finish(&Default::default(), &mut Default::default()) + .data; + + let mut sink = MachBuffer::new(); + EvexInstruction::new() + .length(EvexVectorLength::V128) + .prefix(LegacyPrefixes::None) + .map(OpcodeMap::None) + .w(false) + .opcode(0x00) + .reg(regs::rax().to_real_reg().unwrap().hw_enc()) + .rm(regs::rax().to_real_reg().unwrap().hw_enc()) + .mask(EvexMasking::None) + .encode(&mut sink); + let bytes1 = sink + .finish(&Default::default(), &mut Default::default()) + .data; + + assert_eq!(bytes0, bytes1); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/mod.rs new file mode 100644 index 00000000000000..9dd2697649898f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/mod.rs @@ -0,0 +1,60 @@ +//! Contains the encoding machinery for the various x64 instruction formats. +use crate::{isa::x64, machinst::MachBuffer}; +use std::vec::Vec; + +pub mod evex; +pub mod rex; +pub mod vex; + +/// The encoding formats in this module all require a way of placing bytes into +/// a buffer. +pub trait ByteSink { + /// Add 1 byte to the code section. + fn put1(&mut self, _: u8); + + /// Add 2 bytes to the code section. + fn put2(&mut self, _: u16); + + /// Add 4 bytes to the code section. + fn put4(&mut self, _: u32); + + /// Add 8 bytes to the code section. + fn put8(&mut self, _: u64); +} + +impl ByteSink for MachBuffer { + fn put1(&mut self, value: u8) { + self.put1(value) + } + + fn put2(&mut self, value: u16) { + self.put2(value) + } + + fn put4(&mut self, value: u32) { + self.put4(value) + } + + fn put8(&mut self, value: u64) { + self.put8(value) + } +} + +/// Provide a convenient implementation for testing. +impl ByteSink for Vec { + fn put1(&mut self, v: u8) { + self.extend_from_slice(&[v]) + } + + fn put2(&mut self, v: u16) { + self.extend_from_slice(&v.to_le_bytes()) + } + + fn put4(&mut self, v: u32) { + self.extend_from_slice(&v.to_le_bytes()) + } + + fn put8(&mut self, v: u64) { + self.extend_from_slice(&v.to_le_bytes()) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/rex.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/rex.rs new file mode 100644 index 00000000000000..ae456b7d654556 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/rex.rs @@ -0,0 +1,594 @@ +//! Encodes instructions in the standard x86 encoding mode. This is called +//! IA-32E mode in the Intel manuals but corresponds to the addition of the +//! REX-prefix format (hence the name of this module) that allowed encoding +//! instructions in both compatibility mode (32-bit instructions running on a +//! 64-bit OS) and in 64-bit mode (using the full 64-bit address space). +//! +//! For all of the routines that take both a memory-or-reg operand (sometimes +//! called "E" in the Intel documentation, see the Intel Developer's manual, +//! vol. 2, section A.2) and a reg-only operand ("G" in Intel-ese), the order is +//! always G first, then E. The term "enc" in the following means "hardware +//! register encoding number". + +use super::ByteSink; +use crate::isa::x64::inst::args::{Amode, OperandSize}; +use crate::isa::x64::inst::{regs, Inst, LabelUse}; +use crate::machinst::{MachBuffer, Reg, RegClass}; + +pub(crate) fn low8_will_sign_extend_to_64(x: u32) -> bool { + let xs = (x as i32) as i64; + xs == ((xs << 56) >> 56) +} + +pub(crate) fn low8_will_sign_extend_to_32(x: u32) -> bool { + let xs = x as i32; + xs == ((xs << 24) >> 24) +} + +/// Encode the ModR/M byte. +#[inline(always)] +pub fn encode_modrm(m0d: u8, enc_reg_g: u8, rm_e: u8) -> u8 { + debug_assert!(m0d < 4); + debug_assert!(enc_reg_g < 8); + debug_assert!(rm_e < 8); + ((m0d & 3) << 6) | ((enc_reg_g & 7) << 3) | (rm_e & 7) +} + +#[inline(always)] +pub(crate) fn encode_sib(shift: u8, enc_index: u8, enc_base: u8) -> u8 { + debug_assert!(shift < 4); + debug_assert!(enc_index < 8); + debug_assert!(enc_base < 8); + ((shift & 3) << 6) | ((enc_index & 7) << 3) | (enc_base & 7) +} + +/// Get the encoding number of a GPR. +#[inline(always)] +pub(crate) fn int_reg_enc(reg: impl Into) -> u8 { + let reg = reg.into(); + debug_assert!(reg.is_real(), "reg = {reg:?}"); + debug_assert_eq!(reg.class(), RegClass::Int); + reg.to_real_reg().unwrap().hw_enc() +} + +/// Get the encoding number of any register. +#[inline(always)] +pub(crate) fn reg_enc(reg: impl Into) -> u8 { + let reg = reg.into(); + debug_assert!(reg.is_real()); + reg.to_real_reg().unwrap().hw_enc() +} + +/// A small bit field to record a REX prefix specification: +/// - bit 0 set to 1 indicates REX.W must be 0 (cleared). +/// - bit 1 set to 1 indicates the REX prefix must always be emitted. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct RexFlags(u8); + +impl RexFlags { + /// By default, set the W field, and don't always emit. + #[inline(always)] + pub fn set_w() -> Self { + Self(0) + } + + /// Creates a new RexPrefix for which the REX.W bit will be cleared. + #[inline(always)] + pub fn clear_w() -> Self { + Self(1) + } + + /// True if 64-bit operands are used. + #[inline(always)] + pub fn must_clear_w(&self) -> bool { + (self.0 & 1) != 0 + } + + /// Require that the REX prefix is emitted. + #[inline(always)] + pub fn always_emit(&mut self) -> &mut Self { + self.0 = self.0 | 2; + self + } + + /// True if the REX prefix must always be emitted. + #[inline(always)] + pub fn must_always_emit(&self) -> bool { + (self.0 & 2) != 0 + } + + /// Emit the rex prefix if the referenced register would require it for 8-bit operations. + #[inline(always)] + pub fn always_emit_if_8bit_needed(&mut self, reg: Reg) -> &mut Self { + let enc_reg = int_reg_enc(reg); + if enc_reg >= 4 && enc_reg <= 7 { + self.always_emit(); + } + self + } + + /// Emit a unary instruction. + #[inline(always)] + pub fn emit_one_op(&self, sink: &mut BS, enc_e: u8) { + // Register Operand coded in Opcode Byte + // REX.R and REX.X unused + // REX.B == 1 accesses r8-r15 + let w = if self.must_clear_w() { 0 } else { 1 }; + let r = 0; + let x = 0; + let b = (enc_e >> 3) & 1; + let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b; + if rex != 0x40 || self.must_always_emit() { + sink.put1(rex); + } + } + + /// Emit a binary instruction. + #[inline(always)] + pub fn emit_two_op(&self, sink: &mut BS, enc_g: u8, enc_e: u8) { + let w = if self.must_clear_w() { 0 } else { 1 }; + let r = (enc_g >> 3) & 1; + let x = 0; + let b = (enc_e >> 3) & 1; + let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b; + if rex != 0x40 || self.must_always_emit() { + sink.put1(rex); + } + } + + /// Emit a ternary instruction. + #[inline(always)] + pub fn emit_three_op( + &self, + sink: &mut BS, + enc_g: u8, + enc_index: u8, + enc_base: u8, + ) { + let w = if self.must_clear_w() { 0 } else { 1 }; + let r = (enc_g >> 3) & 1; + let x = (enc_index >> 3) & 1; + let b = (enc_base >> 3) & 1; + let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b; + if rex != 0x40 || self.must_always_emit() { + sink.put1(rex); + } + } +} + +/// Generate the proper Rex flags for the given operand size. +impl From for RexFlags { + fn from(size: OperandSize) -> Self { + match size { + OperandSize::Size64 => RexFlags::set_w(), + _ => RexFlags::clear_w(), + } + } +} +/// Generate Rex flags for an OperandSize/register tuple. +impl From<(OperandSize, Reg)> for RexFlags { + fn from((size, reg): (OperandSize, Reg)) -> Self { + let mut rex = RexFlags::from(size); + if size == OperandSize::Size8 { + rex.always_emit_if_8bit_needed(reg); + } + rex + } +} + +/// Allows using the same opcode byte in different "opcode maps" to allow for more instruction +/// encodings. See appendix A in the Intel Software Developer's Manual, volume 2A, for more details. +#[allow(missing_docs)] +#[derive(PartialEq)] +pub enum OpcodeMap { + None, + _0F, + _0F38, + _0F3A, +} + +impl OpcodeMap { + /// Normally the opcode map is specified as bytes in the instruction, but some x64 encoding + /// formats pack this information as bits in a prefix (e.g. VEX / EVEX). + pub(crate) fn bits(&self) -> u8 { + match self { + OpcodeMap::None => 0b00, + OpcodeMap::_0F => 0b01, + OpcodeMap::_0F38 => 0b10, + OpcodeMap::_0F3A => 0b11, + } + } +} + +impl Default for OpcodeMap { + fn default() -> Self { + Self::None + } +} + +/// We may need to include one or more legacy prefix bytes before the REX prefix. This enum +/// covers only the small set of possibilities that we actually need. +#[derive(PartialEq)] +pub enum LegacyPrefixes { + /// No prefix bytes. + None, + /// Operand Size Override -- here, denoting "16-bit operation". + _66, + /// The Lock prefix. + _F0, + /// Operand size override and Lock. + _66F0, + /// REPNE, but no specific meaning here -- is just an opcode extension. + _F2, + /// REP/REPE, but no specific meaning here -- is just an opcode extension. + _F3, + /// Operand size override and same effect as F3. + _66F3, +} + +impl LegacyPrefixes { + /// Emit the legacy prefix as bytes (e.g. in REX instructions). + #[inline(always)] + pub(crate) fn emit(&self, sink: &mut BS) { + match self { + Self::_66 => sink.put1(0x66), + Self::_F0 => sink.put1(0xF0), + Self::_66F0 => { + // I don't think the order matters, but in any case, this is the same order that + // the GNU assembler uses. + sink.put1(0x66); + sink.put1(0xF0); + } + Self::_F2 => sink.put1(0xF2), + Self::_F3 => sink.put1(0xF3), + Self::_66F3 => { + sink.put1(0x66); + sink.put1(0xF3); + } + Self::None => (), + } + } + + /// Emit the legacy prefix as bits (e.g. for EVEX instructions). + #[inline(always)] + pub(crate) fn bits(&self) -> u8 { + match self { + Self::None => 0b00, + Self::_66 => 0b01, + Self::_F3 => 0b10, + Self::_F2 => 0b11, + _ => panic!( + "VEX and EVEX bits can only be extracted from single prefixes: None, 66, F3, F2" + ), + } + } +} + +impl Default for LegacyPrefixes { + fn default() -> Self { + Self::None + } +} + +/// This is the core 'emit' function for instructions that reference memory. +/// +/// For an instruction that has as operands a reg encoding `enc_g` and a memory address `mem_e`, +/// create and emit: +/// - first the legacy prefixes, if any +/// - then the REX prefix, if needed +/// - then caller-supplied opcode byte(s) (`opcodes` and `num_opcodes`), +/// - then the MOD/RM byte, +/// - then optionally, a SIB byte, +/// - and finally optionally an immediate that will be derived from the `mem_e` operand. +/// +/// For most instructions up to and including SSE4.2, that will be the whole instruction: this is +/// what we call "standard" instructions, and abbreviate "std" in the name here. VEX-prefixed +/// instructions will require their own emitter functions. +/// +/// This will also work for 32-bits x86 instructions, assuming no REX prefix is provided. +/// +/// The opcodes are written bigendianly for the convenience of callers. For example, if the opcode +/// bytes to be emitted are, in this order, F3 0F 27, then the caller should pass `opcodes` == +/// 0xF3_0F_27 and `num_opcodes` == 3. +/// +/// The register operand is represented here not as a `Reg` but as its hardware encoding, `enc_g`. +/// `rex` can specify special handling for the REX prefix. By default, the REX prefix will +/// indicate a 64-bit operation and will be deleted if it is redundant (0x40). Note that for a +/// 64-bit operation, the REX prefix will normally never be redundant, since REX.W must be 1 to +/// indicate a 64-bit operation. +pub(crate) fn emit_std_enc_mem( + sink: &mut MachBuffer, + prefixes: LegacyPrefixes, + opcodes: u32, + mut num_opcodes: usize, + enc_g: u8, + mem_e: &Amode, + rex: RexFlags, + bytes_at_end: u8, +) { + // General comment for this function: the registers in `mem_e` must be + // 64-bit integer registers, because they are part of an address + // expression. But `enc_g` can be derived from a register of any class. + + if let Some(trap_code) = mem_e.get_flags().trap_code() { + sink.add_trap(trap_code); + } + + prefixes.emit(sink); + + // After prefixes, first emit the REX byte depending on the kind of + // addressing mode that's being used. + match *mem_e { + Amode::ImmReg { base, .. } => { + let enc_e = int_reg_enc(base); + rex.emit_two_op(sink, enc_g, enc_e); + } + + Amode::ImmRegRegShift { + base: reg_base, + index: reg_index, + .. + } => { + let enc_base = int_reg_enc(*reg_base); + let enc_index = int_reg_enc(*reg_index); + rex.emit_three_op(sink, enc_g, enc_index, enc_base); + } + + Amode::RipRelative { .. } => { + // note REX.B = 0. + rex.emit_two_op(sink, enc_g, 0); + } + } + + // Now the opcode(s). These include any other prefixes the caller + // hands to us. + while num_opcodes > 0 { + num_opcodes -= 1; + sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8); + } + + // And finally encode the mod/rm bytes and all further information. + emit_modrm_sib_disp(sink, enc_g, mem_e, bytes_at_end, None) +} + +pub(crate) fn emit_modrm_sib_disp( + sink: &mut MachBuffer, + enc_g: u8, + mem_e: &Amode, + bytes_at_end: u8, + evex_scaling: Option, +) { + match *mem_e { + Amode::ImmReg { simm32, base, .. } => { + let enc_e = int_reg_enc(base); + let mut imm = Imm::new(simm32, evex_scaling); + + // Most base registers allow for a single ModRM byte plus an + // optional immediate. If rsp is the base register, however, then a + // SIB byte must be used. + let enc_e_low3 = enc_e & 7; + if enc_e_low3 != regs::ENC_RSP { + // If the base register is rbp and there's no offset then force + // a 1-byte zero offset since otherwise the encoding would be + // invalid. + if enc_e_low3 == regs::ENC_RBP { + imm.force_immediate(); + } + sink.put1(encode_modrm(imm.m0d(), enc_g & 7, enc_e & 7)); + imm.emit(sink); + } else { + // Displacement from RSP is encoded with a SIB byte where + // the index and base are both encoded as RSP's encoding of + // 0b100. This special encoding means that the index register + // isn't used and the base is 0b100 with or without a + // REX-encoded 4th bit (e.g. rsp or r12) + sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); + sink.put1(0b00_100_100); + imm.emit(sink); + } + } + + Amode::ImmRegRegShift { + simm32, + base: reg_base, + index: reg_index, + shift, + .. + } => { + let enc_base = int_reg_enc(*reg_base); + let enc_index = int_reg_enc(*reg_index); + + // Encoding of ModRM/SIB bytes don't allow the index register to + // ever be rsp. Note, though, that the encoding of r12, whose three + // lower bits match the encoding of rsp, is explicitly allowed with + // REX bytes so only rsp is disallowed. + assert!(enc_index != regs::ENC_RSP); + + // If the offset is zero then there is no immediate. Note, though, + // that if the base register's lower three bits are `101` then an + // offset must be present. This is a special case in the encoding of + // the SIB byte and requires an explicit displacement with rbp/r13. + let mut imm = Imm::new(simm32, evex_scaling); + if enc_base & 7 == regs::ENC_RBP { + imm.force_immediate(); + } + + // With the above determined encode the ModRM byte, then the SIB + // byte, then any immediate as necessary. + sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); + sink.put1(encode_sib(shift, enc_index & 7, enc_base & 7)); + imm.emit(sink); + } + + Amode::RipRelative { ref target } => { + // RIP-relative is mod=00, rm=101. + sink.put1(encode_modrm(0b00, enc_g & 7, 0b101)); + + let offset = sink.cur_offset(); + sink.use_label_at_offset(offset, *target, LabelUse::JmpRel32); + // N.B.: some instructions (XmmRmRImm format for example) + // have bytes *after* the RIP-relative offset. The + // addressed location is relative to the end of the + // instruction, but the relocation is nominally relative + // to the end of the u32 field. So, to compensate for + // this, we emit a negative extra offset in the u32 field + // initially, and the relocation will add to it. + sink.put4(-(i32::from(bytes_at_end)) as u32); + } + } +} + +#[derive(Copy, Clone)] +enum Imm { + None, + Imm8(i8), + Imm32(i32), +} + +impl Imm { + /// Classifies the 32-bit immediate `val` as how this can be encoded + /// with ModRM/SIB bytes. + /// + /// For `evex_scaling` according to Section 2.7.5 of Intel's manual: + /// + /// > EVEX-encoded instructions always use a compressed displacement scheme + /// > by multiplying disp8 in conjunction with a scaling factor N that is + /// > determined based on the vector length, the value of EVEX.b bit + /// > (embedded broadcast) and the input element size of the instruction + /// + /// The `evex_scaling` factor provided here is `Some(N)` for EVEX + /// instructions. This is taken into account where the `Imm` value + /// contained is the raw byte offset. + fn new(val: i32, evex_scaling: Option) -> Imm { + if val == 0 { + return Imm::None; + } + match evex_scaling { + Some(scaling) => { + if val % i32::from(scaling) == 0 { + let scaled = val / i32::from(scaling); + if low8_will_sign_extend_to_32(scaled as u32) { + return Imm::Imm8(scaled as i8); + } + } + Imm::Imm32(val) + } + None => match i8::try_from(val) { + Ok(val) => Imm::Imm8(val), + Err(_) => Imm::Imm32(val), + }, + } + } + + /// Forces `Imm::None` to become `Imm::Imm8(0)`, used for special cases + /// where some base registers require an immediate. + fn force_immediate(&mut self) { + if let Imm::None = self { + *self = Imm::Imm8(0); + } + } + + /// Returns the two "mod" bits present at the upper bits of the mod/rm + /// byte. + fn m0d(&self) -> u8 { + match self { + Imm::None => 0b00, + Imm::Imm8(_) => 0b01, + Imm::Imm32(_) => 0b10, + } + } + + fn emit(&self, sink: &mut BS) { + match self { + Imm::None => {} + Imm::Imm8(n) => sink.put1(*n as u8), + Imm::Imm32(n) => sink.put4(*n as u32), + } + } +} + +/// This is the core 'emit' function for instructions that do not reference memory. +/// +/// This is conceptually the same as emit_modrm_sib_enc_ge, except it is for the case where the E +/// operand is a register rather than memory. Hence it is much simpler. +pub(crate) fn emit_std_enc_enc( + sink: &mut BS, + prefixes: LegacyPrefixes, + opcodes: u32, + mut num_opcodes: usize, + enc_g: u8, + enc_e: u8, + rex: RexFlags, +) { + // EncG and EncE can be derived from registers of any class, and they + // don't even have to be from the same class. For example, for an + // integer-to-FP conversion insn, one might be RegClass::I64 and the other + // RegClass::V128. + + // The legacy prefixes. + prefixes.emit(sink); + + // The rex byte. + rex.emit_two_op(sink, enc_g, enc_e); + + // All other prefixes and opcodes. + while num_opcodes > 0 { + num_opcodes -= 1; + sink.put1(((opcodes >> (num_opcodes << 3)) & 0xFF) as u8); + } + + // Now the mod/rm byte. The instruction we're generating doesn't access + // memory, so there is no SIB byte or immediate -- we're done. + sink.put1(encode_modrm(0b11, enc_g & 7, enc_e & 7)); +} + +// These are merely wrappers for the above two functions that facilitate passing +// actual `Reg`s rather than their encodings. + +pub(crate) fn emit_std_reg_mem( + sink: &mut MachBuffer, + prefixes: LegacyPrefixes, + opcodes: u32, + num_opcodes: usize, + reg_g: Reg, + mem_e: &Amode, + rex: RexFlags, + bytes_at_end: u8, +) { + let enc_g = reg_enc(reg_g); + emit_std_enc_mem( + sink, + prefixes, + opcodes, + num_opcodes, + enc_g, + mem_e, + rex, + bytes_at_end, + ); +} + +pub(crate) fn emit_std_reg_reg( + sink: &mut BS, + prefixes: LegacyPrefixes, + opcodes: u32, + num_opcodes: usize, + reg_g: Reg, + reg_e: Reg, + rex: RexFlags, +) { + let enc_g = reg_enc(reg_g); + let enc_e = reg_enc(reg_e); + emit_std_enc_enc(sink, prefixes, opcodes, num_opcodes, enc_g, enc_e, rex); +} + +/// Write a suitable number of bits from an imm64 to the sink. +pub(crate) fn emit_simm(sink: &mut BS, size: u8, simm32: u32) { + match size { + 8 | 4 => sink.put4(simm32), + 2 => sink.put2(simm32 as u16), + 1 => sink.put1(simm32 as u8), + _ => unreachable!(), + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/vex.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/vex.rs new file mode 100644 index 00000000000000..44942570b67908 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/encoding/vex.rs @@ -0,0 +1,491 @@ +//! Encodes VEX instructions. These instructions are those added by the Advanced Vector Extensions +//! (AVX). + +use super::evex::{Register, RegisterOrAmode}; +use super::rex::{LegacyPrefixes, OpcodeMap}; +use super::ByteSink; +use crate::isa::x64::args::Amode; +use crate::isa::x64::encoding::rex; +use crate::isa::x64::inst::Inst; +use crate::machinst::MachBuffer; + +/// Constructs a VEX-encoded instruction using a builder pattern. This approach makes it visually +/// easier to transform something the manual's syntax, `VEX.128.66.0F 73 /7 ib` to code: +/// `VexInstruction::new().length(...).prefix(...).map(...).w(true).opcode(0x1F).reg(...).rm(...)`. +pub struct VexInstruction { + length: VexVectorLength, + prefix: LegacyPrefixes, + map: OpcodeMap, + opcode: u8, + w: bool, + reg: u8, + rm: RegisterOrAmode, + vvvv: Option, + imm: Option, +} + +impl Default for VexInstruction { + fn default() -> Self { + Self { + length: VexVectorLength::default(), + prefix: LegacyPrefixes::None, + map: OpcodeMap::None, + opcode: 0x00, + w: false, + reg: 0x00, + rm: RegisterOrAmode::Register(Register::default()), + vvvv: None, + imm: None, + } + } +} + +impl VexInstruction { + /// Construct a default VEX instruction. + pub fn new() -> Self { + Self::default() + } + + /// Set the length of the instruction. + #[inline(always)] + pub fn length(mut self, length: VexVectorLength) -> Self { + self.length = length; + self + } + + /// Set the legacy prefix byte of the instruction: None | 66 | F2 | F3. VEX instructions + /// pack these into the prefix, not as separate bytes. + #[inline(always)] + pub fn prefix(mut self, prefix: LegacyPrefixes) -> Self { + debug_assert!( + prefix == LegacyPrefixes::None + || prefix == LegacyPrefixes::_66 + || prefix == LegacyPrefixes::_F2 + || prefix == LegacyPrefixes::_F3 + ); + + self.prefix = prefix; + self + } + + /// Set the opcode map byte of the instruction: None | 0F | 0F38 | 0F3A. VEX instructions pack + /// these into the prefix, not as separate bytes. + #[inline(always)] + pub fn map(mut self, map: OpcodeMap) -> Self { + self.map = map; + self + } + + /// Set the W bit, denoted by `.W1` or `.W0` in the instruction string. + /// Typically used to indicate an instruction using 64 bits of an operand (e.g. + /// 64 bit lanes). EVEX packs this bit in the EVEX prefix; previous encodings used the REX + /// prefix. + #[inline(always)] + pub fn w(mut self, w: bool) -> Self { + self.w = w; + self + } + + /// Set the instruction opcode byte. + #[inline(always)] + pub fn opcode(mut self, opcode: u8) -> Self { + self.opcode = opcode; + self + } + + /// Set the register to use for the `reg` bits; many instructions use this as the write operand. + #[inline(always)] + pub fn reg(mut self, reg: impl Into) -> Self { + self.reg = reg.into().into(); + self + } + + /// Some instructions use the ModRM.reg field as an opcode extension. This is usually denoted by + /// a `/n` field in the manual. + #[inline(always)] + pub fn opcode_ext(mut self, n: u8) -> Self { + self.reg = n; + self + } + + /// Set the register to use for the `rm` bits; many instructions use this + /// as the "read from register/memory" operand. Setting this affects both + /// the ModRM byte (`rm` section) and the VEX prefix (the extension bits + /// for register encodings > 8). + #[inline(always)] + pub fn rm(mut self, reg: impl Into) -> Self { + self.rm = reg.into(); + self + } + + /// Set the `vvvv` register; some instructions allow using this as a second, non-destructive + /// source register in 3-operand instructions (e.g. 2 read, 1 write). + #[allow(dead_code)] + #[inline(always)] + pub fn vvvv(mut self, reg: impl Into) -> Self { + self.vvvv = Some(reg.into()); + self + } + + /// Set the imm byte when used for a register. The reg bits are stored in `imm8[7:4]` with + /// the lower bits unused. Overrides a previously set [Self::imm] field. + #[inline(always)] + pub fn imm_reg(mut self, reg: impl Into) -> Self { + let reg: u8 = reg.into().into(); + self.imm = Some((reg & 0xf) << 4); + self + } + + /// Set the imm byte. + /// Overrides a previously set [Self::imm_reg] field. + #[inline(always)] + pub fn imm(mut self, imm: u8) -> Self { + self.imm = Some(imm); + self + } + + /// The R bit in encoded format (inverted). + #[inline(always)] + fn r_bit(&self) -> u8 { + (!(self.reg >> 3)) & 1 + } + + /// The X bit in encoded format (inverted). + #[inline(always)] + fn x_bit(&self) -> u8 { + let reg = match &self.rm { + RegisterOrAmode::Register(_) => 0, + RegisterOrAmode::Amode(Amode::ImmReg { .. }) => 0, + RegisterOrAmode::Amode(Amode::ImmRegRegShift { index, .. }) => { + index.to_real_reg().unwrap().hw_enc() + } + RegisterOrAmode::Amode(Amode::RipRelative { .. }) => 0, + }; + + !(reg >> 3) & 1 + } + + /// The B bit in encoded format (inverted). + #[inline(always)] + fn b_bit(&self) -> u8 { + let reg = match &self.rm { + RegisterOrAmode::Register(r) => (*r).into(), + RegisterOrAmode::Amode(Amode::ImmReg { base, .. }) => { + base.to_real_reg().unwrap().hw_enc() + } + RegisterOrAmode::Amode(Amode::ImmRegRegShift { base, .. }) => { + base.to_real_reg().unwrap().hw_enc() + } + RegisterOrAmode::Amode(Amode::RipRelative { .. }) => 0, + }; + + !(reg >> 3) & 1 + } + + /// Is the 2 byte prefix available for this instruction? + /// We essentially just check if we need any of the bits that are only available + /// in the 3 byte instruction + #[inline(always)] + fn use_2byte_prefix(&self) -> bool { + // These bits are only represented on the 3 byte prefix, so their presence + // implies the use of the 3 byte prefix + self.b_bit() == 1 && self.x_bit() == 1 && + // The presence of W1 in the opcode column implies the opcode must be encoded using the + // 3-byte form of the VEX prefix. + self.w == false && + // The presence of 0F3A and 0F38 in the opcode column implies that opcode can only be + // encoded by the three-byte form of VEX + !(self.map == OpcodeMap::_0F3A || self.map == OpcodeMap::_0F38) + } + + /// The last byte of the 2byte and 3byte prefixes is mostly the same, share the common + /// encoding logic here. + #[inline(always)] + fn prefix_last_byte(&self) -> u8 { + let vvvv = self.vvvv.map(|r| r.into()).unwrap_or(0x00); + + let mut byte = 0x00; + byte |= self.prefix.bits(); + byte |= self.length.bits() << 2; + byte |= ((!vvvv) & 0xF) << 3; + byte + } + + /// Encode the 2 byte prefix + #[inline(always)] + fn encode_2byte_prefix(&self, sink: &mut CS) { + // 2 bytes: + // +-----+ +-------------------+ + // | C5h | | R | vvvv | L | pp | + // +-----+ +-------------------+ + + let last_byte = self.prefix_last_byte() | (self.r_bit() << 7); + + sink.put1(0xC5); + sink.put1(last_byte); + } + + /// Encode the 3 byte prefix + #[inline(always)] + fn encode_3byte_prefix(&self, sink: &mut CS) { + // 3 bytes: + // +-----+ +--------------+ +-------------------+ + // | C4h | | RXB | m-mmmm | | W | vvvv | L | pp | + // +-----+ +--------------+ +-------------------+ + + let mut second_byte = 0x00; + second_byte |= self.map.bits(); // m-mmmm field + second_byte |= self.b_bit() << 5; + second_byte |= self.x_bit() << 6; + second_byte |= self.r_bit() << 7; + + let w_bit = self.w as u8; + let last_byte = self.prefix_last_byte() | (w_bit << 7); + + sink.put1(0xC4); + sink.put1(second_byte); + sink.put1(last_byte); + } + + /// Emit the VEX-encoded instruction to the provided buffer. + pub fn encode(&self, sink: &mut MachBuffer) { + if let RegisterOrAmode::Amode(amode) = &self.rm { + if let Some(trap_code) = amode.get_flags().trap_code() { + sink.add_trap(trap_code); + } + } + + // 2/3 byte prefix + if self.use_2byte_prefix() { + self.encode_2byte_prefix(sink); + } else { + self.encode_3byte_prefix(sink); + } + + // 1 Byte Opcode + sink.put1(self.opcode); + + match &self.rm { + // Not all instructions use Reg as a reg, some use it as an extension + // of the opcode. + RegisterOrAmode::Register(reg) => { + let rm: u8 = (*reg).into(); + sink.put1(rex::encode_modrm(3, self.reg & 7, rm & 7)); + } + // For address-based modes reuse the logic from the `rex` module + // for the modrm and trailing bytes since VEX uses the same + // encoding. + RegisterOrAmode::Amode(amode) => { + let bytes_at_end = if self.imm.is_some() { 1 } else { 0 }; + rex::emit_modrm_sib_disp(sink, self.reg & 7, amode, bytes_at_end, None); + } + } + + // Optional 1 Byte imm + if let Some(imm) = self.imm { + sink.put1(imm); + } + } +} + +/// The VEX format allows choosing a vector length in the `L` bit. +#[allow(dead_code, missing_docs)] // Wider-length vectors are not yet used. +pub enum VexVectorLength { + V128, + V256, +} + +impl VexVectorLength { + /// Encode the `L` bit. + fn bits(&self) -> u8 { + match self { + Self::V128 => 0b0, + Self::V256 => 0b1, + } + } +} + +impl Default for VexVectorLength { + fn default() -> Self { + Self::V128 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::isa::x64::inst::args::Gpr; + use crate::isa::x64::inst::regs; + use crate::opts::MemFlags; + + #[test] + fn vpslldq() { + // VEX.128.66.0F 73 /7 ib + // VPSLLDQ xmm1, xmm2, imm8 + + let dst = regs::xmm1().to_real_reg().unwrap().hw_enc(); + let src = regs::xmm2().to_real_reg().unwrap().hw_enc(); + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F) + .opcode(0x73) + .opcode_ext(7) + .vvvv(dst) + .rm(src) + .imm(0x17) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc5, 0xf1, 0x73, 0xfa, 0x17]); + } + + #[test] + fn vblendvpd() { + // A four operand instruction + // VEX.128.66.0F3A.W0 4B /r /is4 + // VBLENDVPD xmm1, xmm2, xmm3, xmm4 + + let dst = regs::xmm1().to_real_reg().unwrap().hw_enc(); + let a = regs::xmm2().to_real_reg().unwrap().hw_enc(); + let b = regs::xmm3().to_real_reg().unwrap().hw_enc(); + let c = regs::xmm4().to_real_reg().unwrap().hw_enc(); + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F3A) + .w(false) + .opcode(0x4B) + .reg(dst) + .vvvv(a) + .rm(b) + .imm_reg(c) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc4, 0xe3, 0x69, 0x4b, 0xcb, 0x40]); + } + + #[test] + fn vcmpps() { + // VEX.128.0F.WIG C2 /r ib + // VCMPPS ymm10, ymm11, ymm12, 4 // neq + + let dst = regs::xmm10().to_real_reg().unwrap().hw_enc(); + let a = regs::xmm11().to_real_reg().unwrap().hw_enc(); + let b = regs::xmm12().to_real_reg().unwrap().hw_enc(); + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V256) + .prefix(LegacyPrefixes::None) + .map(OpcodeMap::_0F) + .opcode(0xC2) + .reg(dst) + .vvvv(a) + .rm(b) + .imm(4) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc4, 0x41, 0x24, 0xc2, 0xd4, 0x04]); + } + + #[test] + fn vandnps() { + // VEX.128.0F 55 /r + // VANDNPS xmm0, xmm1, xmm2 + + let dst = regs::xmm2().to_real_reg().unwrap().hw_enc(); + let src1 = regs::xmm1().to_real_reg().unwrap().hw_enc(); + let src2 = regs::xmm0().to_real_reg().unwrap().hw_enc(); + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::None) + .map(OpcodeMap::_0F) + .opcode(0x55) + .reg(dst) + .vvvv(src1) + .rm(src2) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc5, 0xf0, 0x55, 0xd0]); + } + + #[test] + fn vandnps_mem() { + // VEX.128.0F 55 /r + // VANDNPS 10(%r13), xmm1, xmm2 + + let dst = regs::xmm2().to_real_reg().unwrap().hw_enc(); + let src1 = regs::xmm1().to_real_reg().unwrap().hw_enc(); + let src2 = Amode::ImmReg { + base: regs::r13(), + flags: MemFlags::trusted(), + simm32: 10, + }; + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::None) + .map(OpcodeMap::_0F) + .opcode(0x55) + .reg(dst) + .vvvv(src1) + .rm(src2) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc4, 0xc1, 0x70, 0x55, 0x55, 0x0a]); + } + + #[test] + fn vandnps_more_mem() { + // VEX.128.0F 55 /r + // VANDNPS 100(%rax,%r13,4), xmm1, xmm2 + + let dst = regs::xmm2().to_real_reg().unwrap().hw_enc(); + let src1 = regs::xmm1().to_real_reg().unwrap().hw_enc(); + let src2 = Amode::ImmRegRegShift { + base: Gpr::unwrap_new(regs::rax()), + index: Gpr::unwrap_new(regs::r13()), + flags: MemFlags::trusted(), + simm32: 100, + shift: 2, + }; + let mut sink = MachBuffer::new(); + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::None) + .map(OpcodeMap::_0F) + .opcode(0x55) + .reg(dst) + .vvvv(src1) + .rm(src2) + .encode(&mut sink); + + let bytes = sink + .finish(&Default::default(), &mut Default::default()) + .data; + assert_eq!(bytes.as_slice(), [0xc4, 0xa1, 0x70, 0x55, 0x54, 0xa8, 100]); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst.isle b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst.isle new file mode 100644 index 00000000000000..393174e48e73ee --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst.isle @@ -0,0 +1,5758 @@ +;; Extern type definitions and constructors for the x64 `MachInst` type. + +;;;; `MInst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Don't build `MInst` variants directly, in general. Instead, use the +;; instruction-emitting helpers defined further down. + +(type MInst nodebug + (enum + ;; Nops of various sizes, including zero. + (Nop (len u8)) + + ;; ========================================= + ;; Integer instructions. + + ;; Integer arithmetic/bit-twiddling. + (AluRmiR (size OperandSize) ;; 1, 2, 4 or 8 + (op AluRmiROpcode) + (src1 Gpr) + (src2 GprMemImm) + (dst WritableGpr)) + + ;; Integer arithmetic read-modify-write on memory. + (AluRM (size OperandSize) ;; 1, 2, 4 or 8 + (op AluRmiROpcode) + (src1_dst SyntheticAmode) + (src2 Gpr) + (lock bool)) + + ;; Integer arithmetic binary op that relies on the VEX prefix. + ;; NOTE: we don't currently support emitting VEX instructions with memory + ;; arguments, so `src2` is artificially constrained to be a Gpr. + (AluRmRVex (size OperandSize) + (op AluRmROpcode) + (src1 Gpr) + (src2 GprMem) + (dst WritableGpr)) + + ;; Production of a zero value into a register of the specified size. + (AluConstOp (op AluRmiROpcode) + (size OperandSize) + (dst WritableGpr)) + + ;; Instructions on general-purpose registers that only read src and + ;; defines dst (dst is not modified). `bsr`, etc. + (UnaryRmR (size OperandSize) ;; 2, 4, or 8 + (op UnaryRmROpcode) + (src GprMem) + (dst WritableGpr)) + + ;; Same as `UnaryRmR` but with the VEX prefix for BMI1 instructions. + (UnaryRmRVex (size OperandSize) + (op UnaryRmRVexOpcode) + (src GprMem) + (dst WritableGpr)) + + ;; Same as `UnaryRmRVex` but with an immediate + (UnaryRmRImmVex (size OperandSize) + (op UnaryRmRImmVexOpcode) + (src GprMem) + (dst WritableGpr) + (imm u8)) + + ;; Bitwise not. + (Not (size OperandSize) ;; 1, 2, 4, or 8 + (src Gpr) + (dst WritableGpr)) + + ;; Integer negation. + (Neg (size OperandSize) ;; 1, 2, 4, or 8 + (src Gpr) + (dst WritableGpr)) + + ;; Integer quotient and remainder: (div idiv) $rax $rdx (reg addr) + ;; + ;; Note that this isn't used for 8-bit division which has its own `Div8` + ;; instruction. + (Div (size OperandSize) ;; 2, 4, or 8 + (sign DivSignedness) + (trap TrapCode) + (divisor GprMem) + (dividend_lo Gpr) + (dividend_hi Gpr) + (dst_quotient WritableGpr) + (dst_remainder WritableGpr)) + + ;; Same as `Div`, but for 8-bits where the regalloc behavior is different + (Div8 (sign DivSignedness) + (trap TrapCode) + (divisor GprMem) + (dividend Gpr) + (dst WritableGpr)) + + ;; Unsigned multiplication producing the high bits of the result in one + ;; register and the low bits in another register. + (Mul (size OperandSize) + (signed bool) + (src1 Gpr) + (src2 GprMem) + (dst_lo WritableGpr) + (dst_hi WritableGpr)) + + ;; Same as `Mul`, but for the BMI2 `mulx` instruction. This is different + ;; where the two `dst_*` registers can be arbitrary registers and it + ;; is always unsigned multiplication. Note that this instruction does + ;; not modify or read flags. + ;; + ;; Note that `dst_hi` here is always a valid register but `dst_lo` + ;; is allowed to be `invalid_reg` to indicate that only the high + ;; bits are desired. If `dst_lo` is invalid then the instruction itself + ;; will only define `dst_hi`. + (MulX (size OperandSize) + (src1 Gpr) + (src2 GprMem) + (dst_lo WritableGpr) + (dst_hi WritableGpr)) + + ;; Same as `Mul` but the 16-bit multiplication result is stored in `AX`. + (Mul8 (signed bool) + (src1 Gpr) + (src2 GprMem) + (dst WritableGpr)) + + ;; The two-operand form of `imul` which produces a truncated same-size + ;; result as the operands. + (IMul (size OperandSize) + (src1 Gpr) + (src2 GprMem) + (dst WritableGpr)) + + ;; The three-operand form of `imul` where the third operand must be + ;; a constant. + (IMulImm (size OperandSize) + (src1 GprMem) + (src2 i32) + (dst WritableGpr)) + + ;; A synthetic instruction sequence used as part of the lowering of the + ;; `srem` instruction which returns 0 if the divisor is -1 and + ;; otherwise executes an `idiv` instruction. + ;; + ;; Note that this does not check for 0 as that's expected to be done + ;; separately. Also note that 8-bit types don't use this and use + ;; `CheckedSRemSeq8` instead. + (CheckedSRemSeq (size OperandSize) + (dividend_lo Gpr) + (dividend_hi Gpr) + (divisor Gpr) + (dst_quotient WritableGpr) + (dst_remainder WritableGpr)) + + ;; Same as above but for 8-bit types. + (CheckedSRemSeq8 (dividend Gpr) + (divisor Gpr) + (dst WritableGpr)) + + ;; Do a sign-extend based on the sign of the value in rax into rdx: (cwd + ;; cdq cqo) or al into ah: (cbw) + (SignExtendData (size OperandSize) ;; 1, 2, 4, or 8 + (src Gpr) + (dst WritableGpr)) + + ;; Constant materialization: (imm32 imm64) reg. + ;; + ;; Either: movl $imm32, %reg32 or movabsq $imm64, %reg32. + (Imm (dst_size OperandSize) ;; 4 or 8 + (simm64 u64) + (dst WritableGpr)) + + ;; GPR to GPR move: mov (64 32) reg reg. + (MovRR (size OperandSize) ;; 4 or 8 + (src Gpr) + (dst WritableGpr)) + + ;; Like `MovRR` but with a physical register source (for implementing + ;; CLIF instructions like `get_stack_pointer`). + (MovFromPReg (src PReg) + (dst WritableGpr)) + + ;; Like `MovRR` but with a physical register destination (for + ;; implementing CLIF instructions like `set_pinned_reg`). + (MovToPReg (src Gpr) + (dst PReg)) + + ;; Zero-extended loads, except for 64 bits: movz (bl bq wl wq lq) addr + ;; reg. + ;; + ;; Note that the lq variant doesn't really exist since the default + ;; zero-extend rule makes it unnecessary. For that case we emit the + ;; equivalent "movl AM, reg32". + (MovzxRmR (ext_mode ExtMode) + (src GprMem) + (dst WritableGpr)) + + ;; A plain 64-bit integer load, since MovZX_RM_R can't represent that. + (Mov64MR (src SyntheticAmode) + (dst WritableGpr)) + + ;; Loads the memory address of addr into dst. + (LoadEffectiveAddress (addr SyntheticAmode) + (dst WritableGpr) + (size OperandSize)) + + ;; Sign-extended loads and moves: movs (bl bq wl wq lq) addr reg. + (MovsxRmR (ext_mode ExtMode) + (src GprMem) + (dst WritableGpr)) + + ;; Immediate store. + (MovImmM (size OperandSize) + (simm32 i32) + (dst SyntheticAmode)) + + ;; Integer stores: mov (b w l q) reg addr. + (MovRM (size OperandSize) ;; 1, 2, 4, or 8 + (src Gpr) + (dst SyntheticAmode)) + + ;; Arithmetic shifts: (shl shr sar) (b w l q) imm reg. + (ShiftR (size OperandSize) ;; 1, 2, 4, or 8 + (kind ShiftKind) + (src Gpr) + ;; shift count: `Imm8Gpr::Imm8(0 .. #bits-in-type - 1)` or + ;; `Imm8Reg::Gpr(r)` where `r` gets move mitosis'd into `%cl`. + (num_bits Imm8Gpr) + (dst WritableGpr)) + + ;; Arithmetic SIMD shifts. + (XmmRmiReg (opcode SseOpcode) + (src1 Xmm) + (src2 XmmMemAlignedImm) + (dst WritableXmm)) + + ;; Integer comparisons/tests: cmp or test (b w l q) (reg addr imm) reg. + (CmpRmiR (size OperandSize) ;; 1, 2, 4, or 8 + (opcode CmpOpcode) + (src1 Gpr) + (src2 GprMemImm)) + + ;; Materializes the requested condition code in the destination reg. + (Setcc (cc CC) + (dst WritableGpr)) + + ;; Swaps byte order in register + (Bswap (size OperandSize) ;; 4 or 8 + (src Gpr) + (dst WritableGpr)) + + ;; ========================================= + ;; Conditional moves. + + ;; GPR conditional move; overwrites the destination register. + (Cmove (size OperandSize) + (cc CC) + (consequent GprMem) + (alternative Gpr) + (dst WritableGpr)) + + ;; XMM conditional move; overwrites the destination register. + (XmmCmove (ty Type) + (cc CC) + (consequent Xmm) + (alternative Xmm) + (dst WritableXmm)) + + ;; ========================================= + ;; Stack manipulation. + + ;; pushq (reg addr imm) + (Push64 (src GprMemImm)) + + ;; popq reg + (Pop64 (dst WritableGpr)) + + ;; Emits a inline stack probe loop. + (StackProbeLoop (tmp WritableReg) + (frame_size u32) + (guard_size u32)) + + ;; ========================================= + ;; Floating-point operations. + + ;; XMM (scalar or vector) binary op: (add sub and or xor mul adc? sbb?) + ;; (32 64) (reg addr) reg + (XmmRmR (op SseOpcode) + (src1 Xmm) + (src2 XmmMemAligned) + (dst WritableXmm)) + + ;; Same as `XmmRmR` except the memory operand can be unaligned + (XmmRmRUnaligned (op SseOpcode) + (src1 Xmm) + (src2 XmmMem) + (dst WritableXmm)) + + ;; XMM (scalar or vector) blend op. The mask is used to blend between + ;; src1 and src2. This differs from a use of `XmmRmR` as the mask is + ;; implicitly in register xmm0; this special case exists to allow us to + ;; communicate the constraint on the `mask` register to regalloc2. + (XmmRmRBlend + (op SseOpcode) + (src1 Xmm) + (src2 XmmMemAligned) + (mask Xmm) + (dst WritableXmm)) + + ;; XMM (scalar or vector) binary op that relies on the VEX prefix and + ;; has two inputs. + (XmmRmiRVex (op AvxOpcode) + (src1 Xmm) + (src2 XmmMemImm) + (dst WritableXmm)) + + ;; XMM (scalar or vector) ternary op that relies on the VEX prefix and + ;; has two dynamic inputs plus one immediate input. + (XmmRmRImmVex (op AvxOpcode) + (src1 Xmm) + (src2 XmmMem) + (dst WritableXmm) + (imm u8)) + + ;; XMM instruction for `vpinsr{b,w,d,q}` which is separate from + ;; `XmmRmRImmVex` because `src2` is a gpr, not xmm register. + (XmmVexPinsr (op AvxOpcode) + (src1 Xmm) + (src2 GprMem) + (dst WritableXmm) + (imm u8)) + + ;; XMM (scalar or vector) ternary op that relies on the VEX prefix and + ;; has three dynamic inputs. + (XmmRmRVex3 (op AvxOpcode) + (src1 Xmm) + (src2 Xmm) + (src3 XmmMem) + (dst WritableXmm)) + + ;; XMM blend operation using the VEX encoding. + (XmmRmRBlendVex (op AvxOpcode) + (src1 Xmm) + (src2 XmmMem) + (mask Xmm) + (dst WritableXmm)) + + ;; XMM unary op using a VEX encoding (aka AVX). + (XmmUnaryRmRVex (op AvxOpcode) + (src XmmMem) + (dst WritableXmm)) + + ;; XMM unary op using a VEX encoding (aka AVX) with an immediate. + (XmmUnaryRmRImmVex (op AvxOpcode) + (src XmmMem) + (dst WritableXmm) + (imm u8)) + + ;; XMM (scalar or vector) unary op (from xmm to reg/mem) using the + ;; VEX prefix + (XmmMovRMVex (op AvxOpcode) + (src Xmm) + (dst SyntheticAmode)) + (XmmMovRMImmVex (op AvxOpcode) + (src Xmm) + (dst SyntheticAmode) + (imm u8)) + + ;; XMM (scalar) unary op (from xmm to integer reg): vpextr{w,b,d,q} + (XmmToGprImmVex (op AvxOpcode) + (src Xmm) + (dst WritableGpr) + (imm u8)) + + ;; XMM (scalar) unary op (from integer to float reg): vmovd, vmovq, + ;; vcvtsi2s{s,d} + (GprToXmmVex (op AvxOpcode) + (src GprMem) + (dst WritableXmm) + (src_size OperandSize)) + + ;; XMM (scalar) unary op (from xmm to integer reg): vmovd, vmovq, + ;; vcvtts{s,d}2si + (XmmToGprVex (op AvxOpcode) + (src Xmm) + (dst WritableGpr) + (dst_size OperandSize)) + + ;; Float comparisons/tests: cmp (b w l q) (reg addr imm) reg. + (XmmCmpRmRVex (op AvxOpcode) + (src1 Xmm) + (src2 XmmMem)) + + ;; XMM (scalar or vector) binary op that relies on the EVEX + ;; prefix. Takes two inputs. + (XmmRmREvex (op Avx512Opcode) + (src1 Xmm) + (src2 XmmMem) + (dst WritableXmm)) + + ;; Same as `XmmRmREvex` but for unary operations. + (XmmUnaryRmRImmEvex (op Avx512Opcode) + (src XmmMem) + (dst WritableXmm) + (imm u8)) + + ;; XMM (scalar or vector) binary op that relies on the EVEX + ;; prefix. Takes three inputs. + (XmmRmREvex3 (op Avx512Opcode) + (src1 Xmm) + (src2 Xmm) + (src3 XmmMem) + (dst WritableXmm)) + + ;; XMM (scalar or vector) unary op: mov between XMM registers (32 64) + ;; (reg addr) reg, sqrt, etc. + ;; + ;; This differs from XMM_RM_R in that the dst register of XmmUnaryRmR is + ;; not used in the computation of the instruction dst value and so does + ;; not have to be a previously valid value. This is characteristic of mov + ;; instructions. + (XmmUnaryRmR (op SseOpcode) + (src XmmMemAligned) + (dst WritableXmm)) + + ;; Same as `XmmUnaryRmR` but used for opcodes where the memory address + ;; can be unaligned. + (XmmUnaryRmRUnaligned (op SseOpcode) + (src XmmMem) + (dst WritableXmm)) + + ;; XMM (scalar or vector) unary op with immediate: roundss, roundsd, etc. + ;; + ;; This differs from XMM_RM_R_IMM in that the dst register of + ;; XmmUnaryRmRImm is not used in the computation of the instruction dst + ;; value and so does not have to be a previously valid value. + (XmmUnaryRmRImm (op SseOpcode) + (src XmmMemAligned) + (imm u8) + (dst WritableXmm)) + + ;; XMM (scalar or vector) unary op that relies on the EVEX prefix. + (XmmUnaryRmREvex (op Avx512Opcode) + (src XmmMem) + (dst WritableXmm)) + + ;; XMM (scalar or vector) unary op (from xmm to reg/mem): stores, movd, + ;; movq + (XmmMovRM (op SseOpcode) + (src Xmm) + (dst SyntheticAmode)) + (XmmMovRMImm (op SseOpcode) + (src Xmm) + (dst SyntheticAmode) + (imm u8)) + + ;; XMM (scalar) unary op (from xmm to integer reg): movd, movq, + ;; cvtts{s,d}2si + (XmmToGpr (op SseOpcode) + (src Xmm) + (dst WritableGpr) + (dst_size OperandSize)) + + ;; XMM (scalar) unary op (from xmm to integer reg): pextr{w,b,d,q} + (XmmToGprImm (op SseOpcode) + (src Xmm) + (dst WritableGpr) + (imm u8)) + + ;; XMM (scalar) unary op (from integer to float reg): movd, movq, + ;; cvtsi2s{s,d} + (GprToXmm (op SseOpcode) + (src GprMem) + (dst WritableXmm) + (src_size OperandSize)) + + ;; Conversion from signed integers to floats, the `{v,}`cvtsi2s{s,d}` + ;; instructions. + ;; + ;; Note that this is special in that `src1` is an xmm/float register + ;; while `src2` is a general purpose register as this is converting an + ;; integer in a gpr to an equivalent float in an xmm reg. + (CvtIntToFloat (op SseOpcode) + (src1 Xmm) + (src2 GprMem) + (dst WritableXmm) + (src2_size OperandSize)) + (CvtIntToFloatVex (op AvxOpcode) + (src1 Xmm) + (src2 GprMem) + (dst WritableXmm) + (src2_size OperandSize)) + + ;; Converts an unsigned int64 to a float32/float64. + (CvtUint64ToFloatSeq (dst_size OperandSize) ;; 4 or 8 + (src Gpr) + (dst WritableXmm) + (tmp_gpr1 WritableGpr) + (tmp_gpr2 WritableGpr)) + + ;; Converts a scalar xmm to a signed int32/int64. + (CvtFloatToSintSeq (dst_size OperandSize) + (src_size OperandSize) + (is_saturating bool) + (src Xmm) + (dst WritableGpr) + (tmp_gpr WritableGpr) + (tmp_xmm WritableXmm)) + + ;; Converts a scalar xmm to an unsigned int32/int64. + (CvtFloatToUintSeq (dst_size OperandSize) + (src_size OperandSize) + (is_saturating bool) + (src Xmm) + (dst WritableGpr) + (tmp_gpr WritableGpr) + (tmp_xmm WritableXmm) + (tmp_xmm2 WritableXmm)) + + ;; A sequence to compute min/max with the proper NaN semantics for xmm + ;; registers. + (XmmMinMaxSeq (size OperandSize) + (is_min bool) + (lhs Xmm) + (rhs Xmm) + (dst WritableXmm)) + + ;; Float comparisons/tests + ;; + ;; Compares `src1` against `src2` with `op`. Note that if you're testing + ;; `a < b` then `src1 == a` and `src2 == b`. + (XmmCmpRmR (op SseOpcode) + (src1 Xmm) + (src2 XmmMemAligned)) + + ;; A binary XMM instruction with an 8-bit immediate: e.g. cmp (ps pd) imm + ;; (reg addr) reg + ;; + ;; Note: this has to use `Reg*`, not `Xmm*`, operands because it is used + ;; in various lane insertion and extraction instructions that move + ;; between XMMs and GPRs. + (XmmRmRImm (op SseOpcode) + (src1 Reg) + (src2 RegMem) + (dst WritableReg) + (imm u8) + (size OperandSize)) + + ;; ========================================= + ;; Control flow instructions. + + ;; Direct call: call simm32. + (CallKnown (info BoxCallInfo)) + + ;; Indirect call: callq (reg mem) + (CallUnknown (info BoxCallIndInfo)) + + ;; Tail call to a direct destination. + (ReturnCallKnown (info BoxReturnCallInfo)) + + ;; Tail call to an indirect destination. + (ReturnCallUnknown (info BoxReturnCallIndInfo)) + + ;; A pseudo-instruction that captures register arguments in vregs. + (Args + (args VecArgPair)) + + ;; A pseudo-instruction that moves vregs to return registers. + (Rets + (rets VecRetPair)) + + ;; Return. + (Ret (stack_bytes_to_pop u32)) + + ;; Stack switching + (StackSwitchBasic (store_context_ptr Gpr) + (load_context_ptr Gpr) + (in_payload0 Gpr) + (out_payload0 WritableGpr)) + + ;; Jump to a known target: jmp simm32. + (JmpKnown (dst MachLabel)) + + ;; One-way conditional branch: jcond cond target. + ;; + ;; This instruction is useful when we have conditional jumps depending on + ;; more than two conditions, see for instance the lowering of Brif + ;; with Fcmp inputs. + ;; + ;; A note of caution: in contexts where the branch target is another + ;; block, this has to be the same successor as the one specified in the + ;; terminator branch of the current block. Otherwise, this might confuse + ;; register allocation by creating new invisible edges. + (JmpIf (cc CC) + (taken MachLabel)) + + ;; Two-way conditional branch: jcond cond target target. + ;; + ;; Emitted as a compound sequence; the MachBuffer will shrink it as + ;; appropriate. + (JmpCond (cc CC) + (taken MachLabel) + (not_taken MachLabel)) + + ;; Jump-table sequence, as one compound instruction (see note in lower.rs + ;; for rationale). + ;; + ;; The generated code sequence is described in the emit's function match + ;; arm for this instruction. + ;; + ;; See comment on jmp_table_seq below about the temporaries signedness. + (JmpTableSeq (idx Reg) + (tmp1 WritableReg) + (tmp2 WritableReg) + (default_target MachLabel) + (targets BoxVecMachLabel)) + + ;; Indirect jump: jmpq (reg mem). + (JmpUnknown (target RegMem)) + + ;; Traps if the condition code is set. + (TrapIf (cc CC) + (trap_code TrapCode)) + + ;; Traps if both of the condition codes are set. + (TrapIfAnd (cc1 CC) + (cc2 CC) + (trap_code TrapCode)) + + ;; Traps if either of the condition codes are set. + (TrapIfOr (cc1 CC) + (cc2 CC) + (trap_code TrapCode)) + + ;; A debug trap. + (Hlt) + + ;; An instruction that will always trigger the illegal instruction + ;; exception. + (Ud2 (trap_code TrapCode)) + + ;; Loads an external symbol in a register, with a relocation: + ;; + ;; movq $name@GOTPCREL(%rip), dst if PIC is enabled, or + ;; lea $name($rip), dst if distance is near, or + ;; movabsq $name, dst otherwise. + (LoadExtName (dst WritableReg) + (name BoxExternalName) + (offset i64) + (distance RelocDistance)) + + ;; ========================================= + ;; Instructions pertaining to atomic memory accesses. + + ;; A standard (native) `lock cmpxchg src, (amode)`, with register + ;; conventions: + ;; + ;; `mem` (read) address + ;; `replacement` (read) replacement value + ;; %rax (modified) in: expected value, out: value that was actually at `dst` + ;; %rflags is written. Do not assume anything about it after the instruction. + ;; + ;; The instruction "succeeded" iff the lowest `ty` bits of %rax + ;; afterwards are the same as they were before. + (LockCmpxchg (ty Type) ;; I8, I16, I32, or I64 + (replacement Reg) + (expected Reg) + (mem SyntheticAmode) + (dst_old WritableReg)) + + ;; A standard (native) `lock cmpxchg16b (amode)`, with register + ;; conventions: + ;; + ;; `mem` (read) address + ;; %rbx (low), %rcx (high) (read) replacement value + ;; %rax (low), %rdx (high) (modified) in: expected value, out: value that was actually at `dst` + ;; %rflags is written. Do not assume anything about it after the instruction. + ;; + ;; The instruction "succeeded" iff the bits of %rax and %rdx + ;; afterwards are the same as they were before. + (LockCmpxchg16b (replacement_low Reg) + (replacement_high Reg) + (expected_low Reg) + (expected_high Reg) + (mem BoxSyntheticAmode) + (dst_old_low WritableReg) + (dst_old_high WritableReg)) + + ;; A standard (native) `lock xadd src, (amode)` + (LockXadd (size OperandSize) + (operand Reg) + (mem SyntheticAmode) + (dst_old WritableReg)) + + ;; A standard (native) `xchg src, (amode)` + (Xchg (size OperandSize) + (operand Reg) + (mem SyntheticAmode) + (dst_old WritableReg)) + + ;; A synthetic instruction, based on a loop around a native `lock + ;; cmpxchg` instruction. + ;; + ;; This atomically modifies a value in memory and returns the old value. + ;; The sequence consists of an initial "normal" load from `dst`, followed + ;; by a loop which computes the new value and tries to compare-and-swap + ;; ("CAS") it into `dst`, using the native instruction `lock + ;; cmpxchg{b,w,l,q}`. The loop iterates until the CAS is successful. If + ;; there is no contention, there will be only one pass through the loop + ;; body. The sequence does *not* perform any explicit memory fence + ;; instructions (`mfence`/`sfence`/`lfence`). + ;; + ;; Note that the transaction is atomic in the sense that, as observed by + ;; some other thread, `dst` either has the initial or final value, but no + ;; other. It isn't atomic in the sense of guaranteeing that no other + ;; thread writes to `dst` in between the initial load and the CAS -- but + ;; that would cause the CAS to fail unless the other thread's last write + ;; before the CAS wrote the same value that was already there. In other + ;; words, this implementation suffers (unavoidably) from the A-B-A + ;; problem. + ;; + ;; This instruction sequence has fixed register uses as follows: + ;; - %rax (written) the old value at `mem` + ;; - %rflags is written. Do not assume anything about it after the + ;; instruction. + (AtomicRmwSeq (ty Type) ;; I8, I16, I32, or I64 + (op AtomicRmwSeqOp) + (mem SyntheticAmode) + (operand Reg) + (temp WritableReg) + (dst_old WritableReg)) + + ;; A synthetic instruction, based on a loop around a native `lock + ;; cmpxchg16b` instruction. + ;; + ;; This is the same as `AtomicRmwSeq`, but for 128-bit integers. + ;; + ;; For `AtomicRmwOp::Xchg`, use `Atomic128XchgSeq` instead. + ;; + ;; This instruction sequence has fixed register uses as follows: + ;; - %rax (low), %rdx (high) (written) the old value at `mem` + ;; - %rbx (low), %rcx (high) (written) used as temp registers to hold + ;; the replacement value + ;; - %rflags is written. Do not assume anything about it after the + ;; instruction. + (Atomic128RmwSeq (op Atomic128RmwSeqOp) + (mem BoxSyntheticAmode) + (operand_low Reg) + (operand_high Reg) + (temp_low WritableReg) + (temp_high WritableReg) + (dst_old_low WritableReg) + (dst_old_high WritableReg)) + + ;; A synthetic instruction, based on a loop around a native `lock + ;; cmpxchg16b` instruction. + ;; + ;; This is `Atomic128XchgSeq` but only for `AtomicRmwOp::Xchg`. As the + ;; replacement value is the same every time, this instruction doesn't + ;; require any temporary registers. + ;; + ;; This instruction sequence has fixed register uses as follows: + ;; - %rax (low), %rdx (high) (written) the old value at `mem` + ;; - %rbx (low), %rcx (high) (read) the replacement value + ;; - %rflags is written. Do not assume anything about it after the + ;; instruction. + (Atomic128XchgSeq (mem SyntheticAmode) + (operand_low Reg) + (operand_high Reg) + (dst_old_low WritableReg) + (dst_old_high WritableReg)) + + ;; A memory fence (mfence, lfence or sfence). + (Fence (kind FenceKind)) + + ;; ========================================= + ;; Meta-instructions generating no code. + + ;; Provides a way to tell the register allocator that the upcoming + ;; sequence of instructions will overwrite `dst` so it should be + ;; considered as a `def`; use this with care. + ;; + ;; This is useful when we have a sequence of instructions whose register + ;; usages are nominally `mod`s, but such that the combination of + ;; operations creates a result that is independent of the initial + ;; register value. It's thus semantically a `def`, not a `mod`, when all + ;; the instructions are taken together, so we want to ensure the register + ;; is defined (its live-range starts) prior to the sequence to keep + ;; analyses happy. + ;; + ;; One alternative would be a compound instruction that somehow + ;; encapsulates the others and reports its own `def`s/`use`s/`mod`s; this + ;; adds complexity (the instruction list is no longer flat) and requires + ;; knowledge about semantics and initial-value independence anyway. + (XmmUninitializedValue (dst WritableXmm)) + + ;; A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol + ;; `dst`, which is constrained to `rax`. + (ElfTlsGetAddr (symbol ExternalName) + (dst WritableGpr)) + + ;; A Mach-O TLS symbol access. Returns address of the TLS symbol in + ;; `dst`, which is constrained to `rax`. + (MachOTlsGetAddr (symbol ExternalName) + (dst WritableGpr)) + + ;; A Coff TLS symbol access. Returns address of the TLS symbol in + ;; `dst`, which is constrained to `rax`. + (CoffTlsGetAddr (symbol ExternalName) + (dst WritableGpr) + (tmp WritableGpr)) + + ;; An unwind pseudoinstruction describing the state of the machine at + ;; this program point. + (Unwind (inst UnwindInst)) + + ;; A pseudoinstruction that just keeps a value alive. + (DummyUse (reg Reg)))) + +(type OperandSize extern + (enum Size8 + Size16 + Size32 + Size64)) + +(type DivSignedness + (enum Signed + Unsigned)) + +(type FenceKind extern + (enum MFence + LFence + SFence)) + +(type BoxCallInfo extern (enum)) +(type BoxCallIndInfo extern (enum)) +(type BoxReturnCallInfo extern (enum)) +(type BoxReturnCallIndInfo extern (enum)) +(type BoxSyntheticAmode extern (enum)) + +(decl pure box_synthetic_amode (SyntheticAmode) BoxSyntheticAmode) +(extern constructor box_synthetic_amode box_synthetic_amode) +(convert SyntheticAmode BoxSyntheticAmode box_synthetic_amode) + +;; Get the `OperandSize` for a given `Type`, rounding smaller types up to 32 bits. +(decl operand_size_of_type_32_64 (Type) OperandSize) +(extern constructor operand_size_of_type_32_64 operand_size_of_type_32_64) + +;; Get the true `OperandSize` for a given `Type`, with no rounding. +(decl raw_operand_size_of_type (Type) OperandSize) +(extern constructor raw_operand_size_of_type raw_operand_size_of_type) + +;; Get the bit width of an `OperandSize`. +(decl operand_size_bits (OperandSize) u16) +(rule (operand_size_bits (OperandSize.Size8)) 8) +(rule (operand_size_bits (OperandSize.Size16)) 16) +(rule (operand_size_bits (OperandSize.Size32)) 32) +(rule (operand_size_bits (OperandSize.Size64)) 64) + +(type AluRmiROpcode extern + (enum Add + Adc + Sub + Sbb + And + Or + Xor)) + +(type AluRmROpcode + (enum Andn + Sarx + Shrx + Shlx + Bzhi)) + +(type UnaryRmROpcode extern + (enum Bsr + Bsf + Lzcnt + Tzcnt + Popcnt)) + +(type UnaryRmRVexOpcode + (enum Blsi + Blsmsk + Blsr)) + +(type UnaryRmRImmVexOpcode + (enum Rorx)) + +(type SseOpcode extern + (enum Addps + Addpd + Addss + Addsd + Andps + Andpd + Andnps + Andnpd + Blendvpd + Blendvps + Comiss + Comisd + Cmpps + Cmppd + Cmpss + Cmpsd + Cvtdq2ps + Cvtdq2pd + Cvtpd2ps + Cvtps2pd + Cvtsd2ss + Cvtsd2si + Cvtsi2ss + Cvtsi2sd + Cvtss2si + Cvtss2sd + Cvttpd2dq + Cvttps2dq + Cvttss2si + Cvttsd2si + Divps + Divpd + Divss + Divsd + Insertps + Maxps + Maxpd + Maxss + Maxsd + Minps + Minpd + Minss + Minsd + Movaps + Movapd + Movd + Movdqa + Movdqu + Movlhps + Movmskps + Movmskpd + Movq + Movss + Movsd + Movups + Movupd + Mulps + Mulpd + Mulss + Mulsd + Orps + Orpd + Pabsb + Pabsw + Pabsd + Packssdw + Packsswb + Packusdw + Packuswb + Paddb + Paddd + Paddq + Paddw + Paddsb + Paddsw + Paddusb + Paddusw + Palignr + Pand + Pandn + Pavgb + Pavgw + Pblendvb + Pcmpeqb + Pcmpeqw + Pcmpeqd + Pcmpeqq + Pcmpgtb + Pcmpgtw + Pcmpgtd + Pcmpgtq + Pextrb + Pextrw + Pextrd + Pextrq + Pinsrb + Pinsrw + Pinsrd + Pmaddubsw + Pmaddwd + Pmaxsb + Pmaxsw + Pmaxsd + Pmaxub + Pmaxuw + Pmaxud + Pminsb + Pminsw + Pminsd + Pminub + Pminuw + Pminud + Pmovmskb + Pmovsxbd + Pmovsxbw + Pmovsxbq + Pmovsxwd + Pmovsxwq + Pmovsxdq + Pmovzxbd + Pmovzxbw + Pmovzxbq + Pmovzxwd + Pmovzxwq + Pmovzxdq + Pmuldq + Pmulhw + Pmulhuw + Pmulhrsw + Pmulld + Pmullw + Pmuludq + Por + Pshufb + Pshufd + Psllw + Pslld + Psllq + Psraw + Psrad + Psrlw + Psrld + Psrlq + Psubb + Psubd + Psubq + Psubw + Psubsb + Psubsw + Psubusb + Psubusw + Ptest + Punpckhbw + Punpckhwd + Punpcklbw + Punpcklwd + Pxor + Rcpss + Roundps + Roundpd + Roundss + Roundsd + Rsqrtss + Shufps + Sqrtps + Sqrtpd + Sqrtss + Sqrtsd + Subps + Subpd + Subss + Subsd + Ucomiss + Ucomisd + Unpcklps + Unpcklpd + Unpckhps + Xorps + Xorpd + Phaddw + Phaddd + Punpckhdq + Punpckldq + Punpckhqdq + Punpcklqdq + Pshuflw + Pshufhw + Pblendw + Movddup + )) + +(type CmpOpcode extern + (enum Cmp + Test)) + +(type RegMemImm extern + (enum + (Reg (reg Reg)) + (Mem (addr SyntheticAmode)) + (Imm (simm32 u32)))) + +;; Put the given clif value into a `RegMemImm` operand. +;; +;; Asserts that the value fits into a single register, and doesn't require +;; multiple registers for its representation (like `i128` for example). +;; +;; As a side effect, this marks the value as used. +(decl put_in_reg_mem_imm (Value) RegMemImm) +(extern constructor put_in_reg_mem_imm put_in_reg_mem_imm) + +(type RegMem extern + (enum + (Reg (reg Reg)) + (Mem (addr SyntheticAmode)))) + +;; Convert a RegMem to a RegMemImm. +(decl reg_mem_to_reg_mem_imm (RegMem) RegMemImm) +(rule (reg_mem_to_reg_mem_imm (RegMem.Reg reg)) + (RegMemImm.Reg reg)) +(rule (reg_mem_to_reg_mem_imm (RegMem.Mem addr)) + (RegMemImm.Mem addr)) + +;; Put the given clif value into a `RegMem` operand. +;; +;; Asserts that the value fits into a single register, and doesn't require +;; multiple registers for its representation (like `i128` for example). +;; +;; As a side effect, this marks the value as used. +(decl put_in_reg_mem (Value) RegMem) +(extern constructor put_in_reg_mem put_in_reg_mem) + +;; Addressing modes. + +(type SyntheticAmode extern (enum)) + +(decl synthetic_amode_to_reg_mem (SyntheticAmode) RegMem) +(extern constructor synthetic_amode_to_reg_mem synthetic_amode_to_reg_mem) + +(spec (amode_to_synthetic_amode amode) (provide (= result amode))) +(decl amode_to_synthetic_amode (Amode) SyntheticAmode) +(extern constructor amode_to_synthetic_amode amode_to_synthetic_amode) + +;; An `Amode` represents a possible addressing mode that can be used +;; in instructions. These denote a 64-bit value only. +(type Amode (enum + ;; Immediate sign-extended and a register + (ImmReg (simm32 i32) + (base Reg) + (flags MemFlags)) + + ;; Sign-extend-32-to-64(simm32) + base + (index << shift) + (ImmRegRegShift (simm32 i32) + (base Gpr) + (index Gpr) + (shift u8) + (flags MemFlags)) + + ;; Sign-extend-32-to-64(immediate) + RIP (instruction + ;; pointer). The appropriate relocation is emitted so + ;; that the resulting immediate makes this Amode refer to + ;; the given MachLabel. + (RipRelative (target MachLabel)))) + +;; Model an Amode as a combination of flags and the calculated 64-bit address. +;; 16 bits 64 bits +;; [ flags | address ] +(model Amode (type (bv 80))) + +(spec (Amode.ImmReg simm base flags) + (provide (= result (concat flags (bvadd base (sign_ext 64 simm))))) + (require + (= (widthof simm) 32) + (= (widthof base) 64) + (= (widthof flags) 16))) + +(spec (Amode.ImmRegRegShift simm base index shift flags) + (provide + (= result + (concat flags + (bvadd + (bvadd base (sign_ext 64 simm)) + (bvshl index (zero_ext 64 shift)))))) + (require + (= (widthof simm) 32) + (= (widthof base) 64) + (= (widthof index) 64) + (= (widthof shift) 8) + (= (widthof flags) 16))) + +;; A helper to both check that the `Imm64` and `Offset32` values sum to less +;; than 32-bits AND return this summed `u32` value. Also, the `Imm64` will be +;; zero-extended from `Type` up to 64 bits. This is useful for `to_amode`. +(decl pure partial sum_extend_fits_in_32_bits (Type Imm64 Offset32) u32) +(extern constructor sum_extend_fits_in_32_bits sum_extend_fits_in_32_bits) + +;;;; Amode lowering ;;;; + +;; Converts a `Value` and a static offset into an `Amode` for x64, attempting +;; to be as fancy as possible with offsets/registers/shifts/etc to make maximal +;; use of the x64 addressing modes. +;; +;; This is a bit subtle unfortunately due to a few constraints. This function +;; was originally written recursively but that can lead to stack overflow +;; for certain inputs due to the recursion being defined by user-controlled +;; input. This means that nowadays this function is not recursive and has a +;; specific structure to handle that. +;; +;; Additionally currently in CLIF all loads/stores have an `Offset32` immediate +;; to go with them, but the wasm lowering to CLIF doesn't use this meaning that +;; it's frequently 0. Additionally mid-end optimizations do not fold `iconst` +;; values into this `Offset32`, meaning that it's left up to backends to hunt +;; for constants for good codegen. That means that one important aspect of this +;; function is that it searches for constants to fold into the `Offset32` to +;; avoid unnecessary instructions. +;; +;; Note, though, that the "optimal addressing modes" are only guaranteed to be +;; generated if egraph-based optimizations have run. For example this will only +;; attempt to find one constant as opposed to many, and that'll only happen +;; with constant folding from optimizations. +;; +;; Finally there's two primary entry points for this function. One is this +;; function here, `to_amode,` and another is `to_amode_add`. The latter is used +;; by the lowering of `iadd` in the x64 backend to use the `lea` instruction +;; where the input is two `Value` operands instead of just one. Most of the +;; logic here is then deferred through `to_amode_add`. +;; +;; In the future if mid-end optimizations fold constants into `Offset32` then +;; this in theory can "simply" delegate to the `amode_imm_reg` helper, and +;; below can delegate to `amode_imm_reg_reg_shift`, or something like that. +(spec (to_amode flags val offset) + (provide (= result (concat flags (bvadd val (sign_ext 64 offset))))) + (require + (= (widthof val) 64))) +(decl to_amode (MemFlags Value Offset32) Amode) +(rule 0 (to_amode flags base offset) + (amode_imm_reg flags base offset)) +(rule 1 (to_amode flags (iadd x y) offset) + (to_amode_add flags x y offset)) + +;; Same as `to_amode`, except that the base address is computed via the addition +;; of the two `Value` arguments provided. +;; +;; The primary purpose of this is to hunt for constants within the two `Value` +;; operands provided. Failing that this will defer to `amode_imm_reg` or +;; `amode_imm_reg_reg_shift` which is the final step in amode lowering and +;; performs final pattern matches related to shifts to see if that can be +;; peeled out into the amode. +;; +;; In other words this function's job is to find constants and then defer to +;; `amode_imm_reg*`. +;; +(spec (to_amode_add flags x y offset) + (provide (= result (concat flags (bvadd (bvadd (sign_ext 64 x) (sign_ext 64 y)) (sign_ext 64 offset)))))) +(instantiate to_amode_add + ((args (bv 16) (bv 64) (bv 64) (bv 32)) (ret (bv 80)) (canon (bv 64)))) +(decl to_amode_add (MemFlags Value Value Offset32) Amode) + +(rule to_amode_add_base_case 0 (to_amode_add flags x y offset) + (amode_imm_reg_reg_shift flags x y offset)) +(rule to_amode_add_const_rhs 1 (to_amode_add flags x (i32_from_iconst c) offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg flags x sum)) +(rule to_amode_add_const_lhs 2 (to_amode_add flags (i32_from_iconst c) x offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg flags x sum)) +(rule to_amode_add_const_fold_iadd_lhs_rhs 3 (to_amode_add flags (iadd x (i32_from_iconst c)) y offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg_reg_shift flags x y sum)) +(rule to_amode_add_const_fold_iadd_lhs_lhs 4 (to_amode_add flags (iadd (i32_from_iconst c) x) y offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg_reg_shift flags x y sum)) +(rule to_amode_add_const_fold_iadd_rhs_rhs 5 (to_amode_add flags x (iadd y (i32_from_iconst c)) offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg_reg_shift flags x y sum)) +(rule to_amode_add_const_fold_iadd_rhs_lhs 6 (to_amode_add flags x (iadd (i32_from_iconst c) y) offset) + (if-let sum (s32_add_fallible offset c)) + (amode_imm_reg_reg_shift flags x y sum)) + +;; Final cases of amode lowering. Does not hunt for constants and only attempts +;; to pattern match add-of-shifts to generate fancier `ImmRegRegShift` modes, +;; otherwise falls back on `ImmReg`. +(spec (amode_imm_reg flags x offset) + (provide (= result (concat flags (bvadd (sign_ext 64 x) (sign_ext 64 offset)))))) +(instantiate amode_imm_reg + ((args (bv 16) (bv 64) (bv 32)) (ret (bv 80)) (canon (bv 64)))) +(decl amode_imm_reg (MemFlags Value Offset32) Amode) +(rule amode_imm_reg_base 0 (amode_imm_reg flags base offset) + (Amode.ImmReg offset base flags)) +(rule amode_imm_reg_iadd 1 (amode_imm_reg flags (iadd x y) offset) + (amode_imm_reg_reg_shift flags x y offset)) + +(spec (amode_imm_reg_reg_shift flags x y offset) + (provide (= result (concat flags (bvadd (sign_ext 64 (bvadd x y)) (sign_ext 64 offset))))) + (require + (= (widthof flags) 16) + (= (widthof x) (widthof y)) + (= (widthof offset) 32))) +(instantiate amode_imm_reg_reg_shift + ((args (bv 16) (bv 64) (bv 64) (bv 32)) (ret (bv 80)) (canon (bv 64)))) +(decl amode_imm_reg_reg_shift (MemFlags Value Value Offset32) Amode) +(rule amode_imm_reg_reg_shift_no_shift 0 (amode_imm_reg_reg_shift flags x y offset) + (Amode.ImmRegRegShift offset x y 0 flags)) ;; 0 == y<<0 == "no shift" +(rule amode_imm_reg_reg_shift_shl_rhs 1 (amode_imm_reg_reg_shift flags x (ishl y (iconst (uimm8 shift))) offset) + (if (u32_lteq (u8_as_u32 shift) 3)) + (Amode.ImmRegRegShift offset x y shift flags)) +(rule amode_imm_reg_reg_shift_shl_lhs 2 (amode_imm_reg_reg_shift flags (ishl y (iconst (uimm8 shift))) x offset) + (if (u32_lteq (u8_as_u32 shift) 3)) + (Amode.ImmRegRegShift offset x y shift flags)) + +;; Offsetting an Amode. Used when we need to do consecutive +;; loads/stores to adjacent addresses. +(decl amode_offset (Amode i32) Amode) +(extern constructor amode_offset amode_offset) + +;; Return a zero offset as an `Offset32`. +(spec (zero_offset) (provide (= result #x00000000))) +(decl zero_offset () Offset32) +(extern constructor zero_offset zero_offset) + +;; Shift kinds. + +(type ShiftKind extern + (enum ShiftLeft + ShiftRightLogical + ShiftRightArithmetic + RotateLeft + RotateRight)) + +(type Imm8Reg extern + (enum (Imm8 (imm u8)) + (Reg (reg Reg)))) + +;; Put the given clif value into a `Imm8Reg` operand, masked to the bit width of +;; the given type. +;; +;; Asserts that the value fits into a single register, and doesn't require +;; multiple registers for its representation (like `i128` for example). +;; +;; As a side effect, this marks the value as used. +;; +;; This is used when lowering various shifts and rotates. +(decl put_masked_in_imm8_gpr (Value Type) Imm8Gpr) +(rule 2 (put_masked_in_imm8_gpr (u64_from_iconst amt) ty) + (const_to_type_masked_imm8 amt ty)) +(rule 1 (put_masked_in_imm8_gpr amt (fits_in_16 ty)) + (x64_and $I64 (value_regs_get_gpr amt 0) (RegMemImm.Imm (shift_mask ty)))) +(rule (put_masked_in_imm8_gpr amt ty) + (value_regs_get_gpr amt 0)) + +;; Condition codes +(type CC extern + (enum O + NO + B + NB + Z + NZ + BE + NBE + S + NS + L + NL + LE + NLE + P + NP)) + +(decl intcc_to_cc (IntCC) CC) +(extern constructor intcc_to_cc intcc_to_cc) + +(decl cc_invert (CC) CC) +(extern constructor cc_invert cc_invert) + +;; Fails if the argument is not either CC.NZ or CC.Z. +(decl cc_nz_or_z (CC) CC) +(extern extractor cc_nz_or_z cc_nz_or_z) + +(type AvxOpcode + (enum Vfmadd213ss + Vfmadd213sd + Vfmadd213ps + Vfmadd213pd + Vfmadd132ss + Vfmadd132sd + Vfmadd132ps + Vfmadd132pd + Vfnmadd213ss + Vfnmadd213sd + Vfnmadd213ps + Vfnmadd213pd + Vfnmadd132ss + Vfnmadd132sd + Vfnmadd132ps + Vfnmadd132pd + Vfmsub213ss + Vfmsub213sd + Vfmsub213ps + Vfmsub213pd + Vfmsub132ss + Vfmsub132sd + Vfmsub132ps + Vfmsub132pd + Vfnmsub213ss + Vfnmsub213sd + Vfnmsub213ps + Vfnmsub213pd + Vfnmsub132ss + Vfnmsub132sd + Vfnmsub132ps + Vfnmsub132pd + Vcmpps + Vcmppd + Vpsrlw + Vpsrld + Vpsrlq + Vpaddb + Vpaddw + Vpaddd + Vpaddq + Vpaddsb + Vpaddsw + Vpaddusb + Vpaddusw + Vpsubb + Vpsubw + Vpsubd + Vpsubq + Vpsubsb + Vpsubsw + Vpsubusb + Vpsubusw + Vpavgb + Vpavgw + Vpand + Vandps + Vandpd + Vpor + Vorps + Vorpd + Vpxor + Vxorps + Vxorpd + Vpmullw + Vpmulld + Vpmulhw + Vpmulhd + Vpmulhrsw + Vpmulhuw + Vpmuldq + Vpmuludq + Vpunpckhwd + Vpunpcklwd + Vunpcklps + Vunpcklpd + Vunpckhps + Vandnps + Vandnpd + Vpandn + Vaddps + Vaddpd + Vsubps + Vsubpd + Vmulps + Vmulpd + Vdivps + Vdivpd + Vpcmpeqb + Vpcmpeqw + Vpcmpeqd + Vpcmpeqq + Vpcmpgtb + Vpcmpgtw + Vpcmpgtd + Vpcmpgtq + Vminps + Vminpd + Vmaxps + Vmaxpd + Vblendvpd + Vblendvps + Vpblendvb + Vmovlhps + Vpmaxsb + Vpmaxsw + Vpmaxsd + Vpminsb + Vpminsw + Vpminsd + Vpmaxub + Vpmaxuw + Vpmaxud + Vpminub + Vpminuw + Vpminud + Vpunpcklbw + Vpunpckhbw + Vpacksswb + Vpackssdw + Vpackuswb + Vpackusdw + Vpalignr + Vpinsrb + Vpinsrw + Vpinsrd + Vpinsrq + Vpmaddwd + Vpmaddubsw + Vinsertps + Vpshufb + Vshufps + Vpsllw + Vpslld + Vpsllq + Vpsraw + Vpsrad + Vpmovsxbw + Vpmovzxbw + Vpmovsxwd + Vpmovzxwd + Vpmovsxdq + Vpmovzxdq + Vaddss + Vaddsd + Vmulss + Vmulsd + Vsubss + Vsubsd + Vdivss + Vdivsd + Vpabsb + Vpabsw + Vpabsd + Vminss + Vminsd + Vmaxss + Vmaxsd + Vsqrtps + Vsqrtpd + Vroundps + Vroundpd + Vcvtdq2pd + Vcvtdq2ps + Vcvtpd2ps + Vcvtps2pd + Vcvttpd2dq + Vcvttps2dq + Vphaddw + Vphaddd + Vpunpckhdq + Vpunpckldq + Vpunpckhqdq + Vpunpcklqdq + Vpshuflw + Vpshufhw + Vpshufd + Vmovss + Vmovsd + Vmovups + Vmovupd + Vmovdqu + Vpextrb + Vpextrw + Vpextrd + Vpextrq + Vpblendw + Vmovddup + Vpbroadcastb + Vpbroadcastw + Vpbroadcastd + Vbroadcastss + Vmovd + Vmovq + Vmovmskps + Vmovmskpd + Vpmovmskb + Vcvtsi2ss + Vcvtsi2sd + Vcvtss2sd + Vcvtsd2ss + Vsqrtss + Vsqrtsd + Vroundss + Vroundsd + Vucomiss + Vucomisd + Vptest + )) + +(type Avx512Opcode + (enum Vcvtudq2ps + Vpabsq + Vpermi2b + Vpmullq + Vpopcntb + Vpsraq + VpsraqImm)) + +(type FcmpImm extern + (enum Equal + LessThan + LessThanOrEqual + Unordered + NotEqual + UnorderedOrGreaterThanOrEqual + UnorderedOrGreaterThan + Ordered)) + +(decl encode_fcmp_imm (FcmpImm) u8) +(extern constructor encode_fcmp_imm encode_fcmp_imm) + +(type RoundImm extern + (enum RoundNearest + RoundDown + RoundUp + RoundZero)) + +(decl encode_round_imm (RoundImm) u8) +(extern constructor encode_round_imm encode_round_imm) + +;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type Gpr (primitive Gpr)) +(type WritableGpr (primitive WritableGpr)) +(type OptionWritableGpr (primitive OptionWritableGpr)) +(type GprMem extern (enum)) +(type GprMemImm extern (enum)) +(type Imm8Gpr extern (enum)) + +(type Xmm (primitive Xmm)) +(type WritableXmm (primitive WritableXmm)) +(type OptionWritableXmm (primitive OptionWritableXmm)) +(type XmmMem extern (enum)) +(type XmmMemAligned extern (enum)) +(type XmmMemImm extern (enum)) +(type XmmMemAlignedImm extern (enum)) + +;; Convert an `Imm8Reg` into an `Imm8Gpr`. +(decl imm8_reg_to_imm8_gpr (Imm8Reg) Imm8Gpr) +(extern constructor imm8_reg_to_imm8_gpr imm8_reg_to_imm8_gpr) + +;; Convert an `Imm8Gpr` into a `Gpr`. +(decl gpr_from_imm8_gpr (Gpr) Imm8Gpr) +(extern extractor gpr_from_imm8_gpr gpr_from_imm8_gpr) + +;; Convert an `Imm8Gpr` into an `Imm8`. +(decl imm8_from_imm8_gpr (u8) Imm8Gpr) +(extern extractor imm8_from_imm8_gpr imm8_from_imm8_gpr) + +;; Convert a `WritableGpr` to a `WritableReg`. +(decl writable_gpr_to_reg (WritableGpr) WritableReg) +(extern constructor writable_gpr_to_reg writable_gpr_to_reg) + +;; Convert a `WritableXmm` to a `WritableReg`. +(decl writable_xmm_to_reg (WritableXmm) WritableReg) +(extern constructor writable_xmm_to_reg writable_xmm_to_reg) + +;; Convert a `WritableReg` to a `WritableXmm`. +(decl writable_reg_to_xmm (WritableReg) WritableXmm) +(extern constructor writable_reg_to_xmm writable_reg_to_xmm) + +;; Convert a `WritableXmm` to an `Xmm`. +(decl writable_xmm_to_xmm (WritableXmm) Xmm) +(extern constructor writable_xmm_to_xmm writable_xmm_to_xmm) + +;; Convert a `WritableGpr` to an `Gpr`. +(decl writable_gpr_to_gpr (WritableGpr) Gpr) +(extern constructor writable_gpr_to_gpr writable_gpr_to_gpr) + +;; Convert an `Gpr` to a `Reg`. +(decl gpr_to_reg (Gpr) Reg) +(extern constructor gpr_to_reg gpr_to_reg) + +;; Convert an `Gpr` to a `GprMem`. +(decl gpr_to_gpr_mem (Gpr) GprMem) +(extern constructor gpr_to_gpr_mem gpr_to_gpr_mem) + +;; Convert an `Gpr` to a `GprMemImm`. +(decl gpr_to_gpr_mem_imm (Gpr) GprMemImm) +(extern constructor gpr_to_gpr_mem_imm gpr_to_gpr_mem_imm) + +;; Convert an `Xmm` to a `Reg`. +(decl xmm_to_reg (Xmm) Reg) +(extern constructor xmm_to_reg xmm_to_reg) + +;; Convert an `Xmm` into an `XmmMemImm`. +(decl xmm_to_xmm_mem_imm (Xmm) XmmMemImm) +(extern constructor xmm_to_xmm_mem_imm xmm_to_xmm_mem_imm) + +;; Convert an `XmmMem` into an `XmmMemImm`. +(decl xmm_mem_to_xmm_mem_imm (XmmMem) XmmMemImm) +(extern constructor xmm_mem_to_xmm_mem_imm xmm_mem_to_xmm_mem_imm) + +;; Convert an `XmmMem` into an `XmmMemAligned`. +;; +;; Note that this is an infallible conversion, not a fallible one. If the +;; original `XmmMem` source is a register, then it's passed through directly. +;; If it's `Mem` and refers to aligned memory, it's also passed through +;; directly. Otherwise, though, it's a memory source which is not aligned to +;; 16 bytes so a load is performed and the temporary register which is the +;; result of the load is passed through. The end-result is that the return value +;; here is guaranteed to be a register or an aligned memory location. +(decl xmm_mem_to_xmm_mem_aligned (XmmMem) XmmMemAligned) +(extern constructor xmm_mem_to_xmm_mem_aligned xmm_mem_to_xmm_mem_aligned) + +;; Convert an `XmmMemImm` into an `XmmMemImmAligned`. +;; +;; Note that this is the same as `xmm_mem_to_xmm_mem_aligned` except it handles +;; an immediate case as well. +(decl xmm_mem_imm_to_xmm_mem_aligned_imm (XmmMemImm) XmmMemAlignedImm) +(extern constructor xmm_mem_imm_to_xmm_mem_aligned_imm xmm_mem_imm_to_xmm_mem_aligned_imm) + +;; Allocate a new temporary GPR register. +(decl temp_writable_gpr () WritableGpr) +(extern constructor temp_writable_gpr temp_writable_gpr) + +;; Allocate a new temporary XMM register. +(decl temp_writable_xmm () WritableXmm) +(extern constructor temp_writable_xmm temp_writable_xmm) + +;; Construct a new `XmmMem` from the given `RegMem`. +;; +;; Asserts that the `RegMem`'s register, if any, is an XMM register. +(decl reg_mem_to_xmm_mem (RegMem) XmmMem) +(extern constructor reg_mem_to_xmm_mem reg_mem_to_xmm_mem) + +;; Construct a new `RegMemImm` from the given `Reg`. +(decl reg_to_reg_mem_imm (Reg) RegMemImm) +(extern constructor reg_to_reg_mem_imm reg_to_reg_mem_imm) + +;; Construct a new `GprMemImm` from the given `RegMemImm`. +;; +;; Asserts that the `RegMemImm`'s register, if any, is an GPR register. +(decl gpr_mem_imm_new (RegMemImm) GprMemImm) +(extern constructor gpr_mem_imm_new gpr_mem_imm_new) + +;; Construct a new `XmmMemImm` from the given `RegMemImm`. +;; +;; Asserts that the `RegMemImm`'s register, if any, is an XMM register. +(decl xmm_mem_imm_new (RegMemImm) XmmMemImm) +(extern constructor xmm_mem_imm_new xmm_mem_imm_new) + +;; Construct a new `XmmMem` from an `Xmm`. +(decl xmm_to_xmm_mem (Xmm) XmmMem) +(extern constructor xmm_to_xmm_mem xmm_to_xmm_mem) + +;; Construct a new `XmmMem` from an `RegMem`. +(decl pure xmm_mem_to_reg_mem (XmmMem) RegMem) +(extern constructor xmm_mem_to_reg_mem xmm_mem_to_reg_mem) + +;; Convert a `GprMem` to a `RegMem`. +(decl gpr_mem_to_reg_mem (GprMem) RegMem) +(extern constructor gpr_mem_to_reg_mem gpr_mem_to_reg_mem) + +;; Construct a new `Xmm` from a `Reg`. +;; +;; Asserts that the register is a XMM. +(decl xmm_new (Reg) Xmm) +(extern constructor xmm_new xmm_new) + +;; Construct a new `Gpr` from a `Reg`. +;; +;; Asserts that the register is a GPR. +(decl gpr_new (Reg) Gpr) +(extern constructor gpr_new gpr_new) + +;; Construct a new `GprMem` from a `RegMem`. +;; +;; Asserts that the `RegMem`'s register, if any, is a GPR. +(decl reg_mem_to_gpr_mem (RegMem) GprMem) +(extern constructor reg_mem_to_gpr_mem reg_mem_to_gpr_mem) + +;; Construct a `GprMem` from a `Reg`. +;; +;; Asserts that the `Reg` is a GPR. +(decl reg_to_gpr_mem (Reg) GprMem) +(extern constructor reg_to_gpr_mem reg_to_gpr_mem) + +;; Construct a `GprMemImm` from a `Reg`. +;; +;; Asserts that the `Reg` is a GPR. +(decl reg_to_gpr_mem_imm (Reg) GprMemImm) +(rule (reg_to_gpr_mem_imm r) + (gpr_to_gpr_mem_imm (gpr_new r))) + +;; Put a value into a GPR. +;; +;; Moves the value into a GPR if it is a type that would naturally go into an +;; XMM register. +(spec (put_in_gpr arg) (provide (= result (conv_to 64 arg)))) +(decl put_in_gpr (Value) Gpr) + +;; Case for when the value naturally lives in a GPR. +(rule (put_in_gpr val) + (if-let (value_type ty) val) + (if-let (type_register_class (RegisterClass.Gpr _)) ty) + (gpr_new (put_in_reg val))) + +;; Case for when the value naturally lives in an XMM register and we must +;; bitcast it from an XMM into a GPR. +(rule (put_in_gpr val) + (if-let (value_type ty) val) + (if-let (type_register_class (RegisterClass.Xmm)) ty) + (bitcast_xmm_to_gpr (ty_bits ty) (xmm_new (put_in_reg val)))) + +;; Put a value into a `GprMem`. +;; +;; Asserts that the value goes into a GPR. +(decl put_in_gpr_mem (Value) GprMem) +(rule (put_in_gpr_mem val) + (reg_mem_to_gpr_mem (put_in_reg_mem val))) + +;; Put a value into a `GprMemImm`. +;; +;; Asserts that the value goes into a GPR. +(decl put_in_gpr_mem_imm (Value) GprMemImm) +(rule (put_in_gpr_mem_imm val) + (gpr_mem_imm_new (put_in_reg_mem_imm val))) + +;; Put a value into a XMM. +;; +;; Asserts that the value goes into a XMM. +(decl put_in_xmm (Value) Xmm) +(rule (put_in_xmm val) + (xmm_new (put_in_reg val))) + +;; Put a value into a `XmmMem`. +;; +;; Asserts that the value goes into a XMM. +(decl put_in_xmm_mem (Value) XmmMem) +(extern constructor put_in_xmm_mem put_in_xmm_mem) + +;; Put a value into a `XmmMemImm`. +;; +;; Asserts that the value goes into a XMM. +(decl put_in_xmm_mem_imm (Value) XmmMemImm) +(extern constructor put_in_xmm_mem_imm put_in_xmm_mem_imm) + +;; Construct an `InstOutput` out of a single GPR register. +(spec (output_gpr x) + (provide (= result (conv_to (widthof result) x)))) +(decl output_gpr (Gpr) InstOutput) +(rule (output_gpr x) + (output_reg (gpr_to_reg x))) + +;; Construct a `ValueRegs` out of two GPR registers. +(decl value_gprs (Gpr Gpr) ValueRegs) +(rule (value_gprs x y) + (value_regs (gpr_to_reg x) (gpr_to_reg y))) + +;; Construct an `InstOutput` out of a single XMM register. +(decl output_xmm (Xmm) InstOutput) +(rule (output_xmm x) + (output_reg (xmm_to_reg x))) + +;; Get the `n`th reg in a `ValueRegs` and construct a GPR from it. +;; +;; Asserts that the register is a GPR. +(decl value_regs_get_gpr (ValueRegs usize) Gpr) +(rule (value_regs_get_gpr regs n) + (gpr_new (value_regs_get regs n))) + +;; Convert a `Gpr` to an `Imm8Gpr`. +(decl gpr_to_imm8_gpr (Gpr) Imm8Gpr) +(extern constructor gpr_to_imm8_gpr gpr_to_imm8_gpr) + +;; Convert an 8-bit immediate into an `Imm8Gpr`. +(decl imm8_to_imm8_gpr (u8) Imm8Gpr) +(extern constructor imm8_to_imm8_gpr imm8_to_imm8_gpr) + +;; Get the low half of the given `Value` as a GPR. +(decl lo_gpr (Value) Gpr) +(rule (lo_gpr regs) (gpr_new (lo_reg regs))) + +;; Construct a new `XmmMemImm` from a 32-bit immediate. +(decl xmi_imm (u32) XmmMemImm) +(extern constructor xmi_imm xmi_imm) + +;;;; Helpers for determining the register class of a value type ;;;;;;;;;;;;;;;; + +(type RegisterClass + (enum + (Gpr (single_register bool)) + (Xmm))) + +(decl type_register_class (RegisterClass) Type) +(extern extractor type_register_class type_register_class) + +(decl is_xmm_type (Type) Type) +(extractor (is_xmm_type ty) (and (type_register_class (RegisterClass.Xmm)) ty)) + +(spec (is_gpr_type arg) + (provide (= result arg)) + (require (<= arg 64))) +(decl is_gpr_type (Type) Type) +(extractor (is_gpr_type ty) (and (type_register_class (RegisterClass.Gpr _)) ty)) + +(decl is_single_register_gpr_type (Type) Type) +(extractor (is_single_register_gpr_type ty) + (and (type_register_class (RegisterClass.Gpr true)) ty)) + +(decl is_multi_register_gpr_type (Type) Type) +(extractor (is_multi_register_gpr_type ty) + (and (type_register_class (RegisterClass.Gpr false)) ty)) + +;;;; Helpers for Querying Enabled ISA Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pure use_avx512vl () bool) +(extern constructor use_avx512vl use_avx512vl) + +(decl pure use_avx512dq () bool) +(extern constructor use_avx512dq use_avx512dq) + +(decl pure use_avx512f () bool) +(extern constructor use_avx512f use_avx512f) + +(decl pure use_avx512bitalg () bool) +(extern constructor use_avx512bitalg use_avx512bitalg) + +(decl pure use_avx512vbmi () bool) +(extern constructor use_avx512vbmi use_avx512vbmi) + +(decl pure use_lzcnt () bool) +(extern constructor use_lzcnt use_lzcnt) + +(decl pure use_bmi1 () bool) +(extern constructor use_bmi1 use_bmi1) + +(decl pure use_bmi2 () bool) +(extern constructor use_bmi2 use_bmi2) + +(decl pure use_popcnt () bool) +(extern constructor use_popcnt use_popcnt) + +(decl pure use_fma () bool) +(extern constructor use_fma use_fma) + +(decl pure use_ssse3 () bool) +(extern constructor use_ssse3 use_ssse3) + +(decl pure use_sse41 () bool) +(extern constructor use_sse41 use_sse41) + +(decl pure use_sse42 () bool) +(extern constructor use_sse42 use_sse42) + +(decl pure use_avx () bool) +(extern constructor use_avx use_avx) + +(decl pure use_avx2 () bool) +(extern constructor use_avx2 use_avx2) + +(decl pure use_cmpxchg16b () bool) +(extern constructor use_cmpxchg16b use_cmpxchg16b) + +;;;; Helpers for Merging and Sinking Immediates/Loads ;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extract a constant `Imm8Reg.Imm8` from a value operand. +(decl imm8_from_value (Imm8Reg) Value) +(extern extractor imm8_from_value imm8_from_value) + +;; Mask a constant to the bit-width of the given type and package it into an +;; `Imm8Reg.Imm8`. This is used for shifts and rotates, so that we don't try and +;; shift/rotate more bits than the type has available, per Cranelift's +;; semantics. +(decl const_to_type_masked_imm8 (u64 Type) Imm8Gpr) +(extern constructor const_to_type_masked_imm8 const_to_type_masked_imm8) + +;; Generate a mask for the bit-width of the given type +(decl shift_mask (Type) u8) +(extern constructor shift_mask shift_mask) + +;; Mask a constant with the type's shift mask +(decl shift_amount_masked (Type Imm64) u8) +(extern constructor shift_amount_masked shift_amount_masked) + +;; Extract a constant `GprMemImm.Imm` from a value operand. +(decl simm32_from_value (GprMemImm) Value) +(extern extractor simm32_from_value simm32_from_value) + +;; A load that can be sunk into another operation. +(type SinkableLoad extern (enum)) + +;; Extract a `SinkableLoad` that works with `RegMemImm.Mem` from a value +;; operand. +;; +;; Note that this will only work for 32-bit-types-or-larger since this is +;; pervasively used with operations that load a minimum of 32-bits. For +;; instructions which load exactly the type width necessary use +;; `sinkable_load_exact`. +(decl sinkable_load (SinkableLoad) Value) +(spec (sinkable_load inst) + (provide (= result inst))) +(extern extractor sinkable_load sinkable_load) + +;; Same as `sinkable_load` except that all type widths of loads are supported. +;; +;; Only use this when the instruction which performs the load is guaranteed to +;; load the precisely correct size. +(decl sinkable_load_exact (SinkableLoad) Value) +(extern extractor sinkable_load_exact sinkable_load_exact) + +;; Sink a `SinkableLoad` into a `SyntheticAmode`. +;; +;; This is a side-effectful operation that notifies the context that the +;; instruction that produced the `SinkableImm` has been sunk into another +;; instruction, and no longer needs to be lowered. +(decl sink_load (SinkableLoad) SyntheticAmode) +(extern constructor sink_load sink_load) + +(decl sink_load_to_gpr_mem_imm (SinkableLoad) GprMemImm) +(rule (sink_load_to_gpr_mem_imm load) + (gpr_mem_imm_new load)) + +(decl sink_load_to_xmm_mem (SinkableLoad) XmmMem) +(rule (sink_load_to_xmm_mem load) + (reg_mem_to_xmm_mem load)) + +(decl sink_load_to_reg_mem (SinkableLoad) RegMem) +(rule (sink_load_to_reg_mem load) (RegMem.Mem load)) + +(decl sink_load_to_gpr_mem (SinkableLoad) GprMem) +(rule (sink_load_to_gpr_mem load) (RegMem.Mem load)) + +(decl sink_load_to_reg_mem_imm (SinkableLoad) RegMemImm) +(spec (sink_load_to_reg_mem_imm load) + (provide (= result load))) +(rule (sink_load_to_reg_mem_imm load) (RegMemImm.Mem load)) + +;;;; Helpers for constructing and emitting an `MInst` ;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; These helpers are intended to assist in emitting instructions by taking +;; source operands and automatically creating output operands which are then +;; returned. These are additionally designed to assist with SSA-like +;; construction where the writable version of a register is only present in +;; an `MInst` and every other reference to it is a readonly version. + +;; Helper for creating XmmUninitializedValue instructions. +(decl xmm_uninit_value () Xmm) +(rule (xmm_uninit_value) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUninitializedValue dst)))) + dst)) + +;; Helper for constructing a LoadExtName instruction. +(decl load_ext_name (ExternalName i64 RelocDistance) Reg) +(rule (load_ext_name extname offset distance) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.LoadExtName dst extname offset distance)))) + dst)) + +;; Helper for constructing a Mov64MR instruction. +(decl mov64_mr (SyntheticAmode) Reg) +(rule (mov64_mr addr) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Mov64MR addr dst)))) + dst)) + +;; Helper for emitting `MInst.AluRmiR` instructions. +(decl alu_rmi_r (Type AluRmiROpcode Gpr GprMemImm) Gpr) +(rule (alu_rmi_r ty opcode src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.AluRmiR size opcode src1 src2 dst)))) + dst)) + +;; Helper for emitting `MInst.AluRmRVex` instructions. +(decl alu_rm_r_vex (Type AluRmROpcode Gpr GprMem) Gpr) +(rule (alu_rm_r_vex ty opcode src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.AluRmRVex size opcode src1 src2 dst)))) + dst)) + +;; Helper for creating `MInst.XmmRmR` instructions. +(decl xmm_rm_r (SseOpcode Xmm XmmMemAligned) Xmm) +(rule (xmm_rm_r op src1 src2) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmR op src1 src2 dst)))) + dst)) + +;; Helper for creating `MInst.XmmRmRUnaligned` instructions. +(decl xmm_rm_r_unaligned (SseOpcode Xmm XmmMem) Xmm) +(rule (xmm_rm_r_unaligned op src1 src2) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRUnaligned op src1 src2 dst)))) + dst)) + +;; Helper for creating `XmmRmRBlend` instructions +(decl xmm_rm_r_blend (SseOpcode Xmm XmmMemAligned Xmm) Xmm) +(rule (xmm_rm_r_blend op src1 src2 mask) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRBlend op src1 src2 mask dst)))) + dst)) + +;; Helper for creating `XmmRmRBlendVex` instructions +(decl xmm_rmr_blend_vex (AvxOpcode Xmm XmmMem Xmm) Xmm) +(rule (xmm_rmr_blend_vex op src1 src2 mask) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRBlendVex op src1 src2 mask dst)))) + dst)) + +;; Helper for creating `XmmUnaryRmRVex` instructions +(decl xmm_unary_rm_r_vex (AvxOpcode XmmMem) Xmm) +(rule (xmm_unary_rm_r_vex op src) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmRVex op src dst)))) + dst)) + +;; Helper for creating `XmmUnaryRmRImmVex` instructions +(decl xmm_unary_rm_r_imm_vex (AvxOpcode XmmMem u8) Xmm) +(rule (xmm_unary_rm_r_imm_vex op src imm) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmRImmVex op src dst imm)))) + dst)) + +;; Helper for creating `MInst.XmmRmRImm` instructions. +(decl xmm_rm_r_imm (SseOpcode Reg RegMem u8 OperandSize) Xmm) +(rule (xmm_rm_r_imm op src1 src2 imm size) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRImm op + src1 + src2 + dst + imm + size)))) + dst)) + +;; Helper for constructing `XmmVexPinsr` instructions. +(decl xmm_vex_pinsr (AvxOpcode Xmm GprMem u8) Xmm) +(rule (xmm_vex_pinsr op src1 src2 imm) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmVexPinsr op src1 src2 dst imm)))) + dst)) + +;; Helper for constructing `XmmUnaryRmRImm` instructions. +(decl xmm_unary_rm_r_imm (SseOpcode XmmMemAligned u8) Xmm) +(rule (xmm_unary_rm_r_imm op src1 imm) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmRImm op src1 imm dst)))) + dst)) + +;; Helper for creating `MInst.XmmUnaryRmR` instructions. +(decl xmm_unary_rm_r (SseOpcode XmmMemAligned) Xmm) +(rule (xmm_unary_rm_r op src) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmR op src dst)))) + dst)) + +;; Helper for creating `MInst.XmmUnaryRmRUnaligned` instructions. +(decl xmm_unary_rm_r_unaligned (SseOpcode XmmMem) Xmm) +(rule (xmm_unary_rm_r_unaligned op src) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmRUnaligned op src dst)))) + dst)) + +;; Helper for creating `MInst.XmmUnaryRmREvex` instructions. +(decl xmm_unary_rm_r_evex (Avx512Opcode XmmMem) Xmm) +(rule (xmm_unary_rm_r_evex op src) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmREvex op src dst)))) + dst)) + +;; Helper for creating `MInst.XmmRmREvex` instructions. +(decl xmm_rm_r_evex (Avx512Opcode Xmm XmmMem) Xmm) +(rule (xmm_rm_r_evex op src1 src2) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmREvex op + src1 + src2 + dst)))) + dst)) + +;; Helper for creating `MInst.XmmUnaryRmRImmEvex` instructions. +(decl xmm_unary_rm_r_imm_evex (Avx512Opcode XmmMem u8) Xmm) +(rule (xmm_unary_rm_r_imm_evex op src imm) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmUnaryRmRImmEvex op src dst imm)))) + dst)) + +;; Helper for creating `MInst.XmmRmiXmm` instructions. +(decl xmm_rmi_xmm (SseOpcode Xmm XmmMemAlignedImm) Xmm) +(rule (xmm_rmi_xmm op src1 src2) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmiReg op + src1 + src2 + dst)))) + dst)) + +;; Helper for creating `MInst.XmmToGprImm` instructions. +(decl xmm_to_gpr_imm (SseOpcode Xmm u8) Gpr) +(rule (xmm_to_gpr_imm op src imm) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.XmmToGprImm op src dst imm)))) + dst)) + +;; Helper for creating `MInst.XmmToGprImmVex` instructions. +(decl xmm_to_gpr_imm_vex (AvxOpcode Xmm u8) Gpr) +(rule (xmm_to_gpr_imm_vex op src imm) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.XmmToGprImmVex op src dst imm)))) + dst)) + +;; Helper for creating `MInst.GprToXmm` instructions. +(decl gpr_to_xmm (SseOpcode GprMem OperandSize) Xmm) +(rule (gpr_to_xmm op src size) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.GprToXmm op src dst size)))) + dst)) + +;; Helper for creating `MInst.GprToXmmVex` instructions. +(decl gpr_to_xmm_vex (AvxOpcode GprMem OperandSize) Xmm) +(rule (gpr_to_xmm_vex op src size) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.GprToXmmVex op src dst size)))) + dst)) + +;; Helper for creating `MInst.XmmToGpr` instructions. +(decl xmm_to_gpr (SseOpcode Xmm OperandSize) Gpr) +(rule (xmm_to_gpr op src size) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.XmmToGpr op src dst size)))) + dst)) + +;; Helper for creating `MInst.XmmToGprVex` instructions. +(decl xmm_to_gpr_vex (AvxOpcode Xmm OperandSize) Gpr) +(rule (xmm_to_gpr_vex op src size) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.XmmToGprVex op src dst size)))) + dst)) + +;; Helper for creating `xmm_min_max_seq` pseudo-instructions. +(decl xmm_min_max_seq (Type bool Xmm Xmm) Xmm) +(rule (xmm_min_max_seq ty is_min lhs rhs) + (let ((dst WritableXmm (temp_writable_xmm)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.XmmMinMaxSeq size is_min lhs rhs dst)))) + dst)) + +;; Helper for creating `MInst.XmmRmiRVex` instructions. +(decl xmm_rmir_vex (AvxOpcode Xmm XmmMemImm) Xmm) +(rule (xmm_rmir_vex op src1 src2) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmiRVex op src1 src2 dst)))) + dst)) + +;; Helper for creating `MInst.XmmRmRImmVex` instructions. +(decl xmm_rmr_imm_vex (AvxOpcode Xmm XmmMem u8) Xmm) +(rule (xmm_rmr_imm_vex op src1 src2 imm) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRImmVex op src1 src2 dst imm)))) + dst)) + +;; Helper for creating `MInst.XmmRmRVex3` instructions. +(decl xmm_rmr_vex3 (AvxOpcode Xmm Xmm XmmMem) Xmm) +(rule (xmm_rmr_vex3 op src1 src2 src3) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmRVex3 op src1 src2 src3 dst)))) + dst)) + +;; Helper for creating `MInst.UnaryRmR` instructions. +(decl unary_rm_r (UnaryRmROpcode Gpr OperandSize) Gpr) +(rule (unary_rm_r op src size) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.UnaryRmR size op src dst)))) + dst)) + +;; Helper for creating `MInst.UnaryRmRVex` instructions. +(decl unary_rm_r_vex (UnaryRmRVexOpcode GprMem OperandSize) Gpr) +(rule (unary_rm_r_vex op src size) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.UnaryRmRVex size op src dst)))) + dst)) + +;; Helper for creating `MInst.UnaryRmRImmVex` instructions. +(decl unary_rm_r_imm_vex (UnaryRmRImmVexOpcode GprMem OperandSize u8) Gpr) +(rule (unary_rm_r_imm_vex op src size imm) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.UnaryRmRImmVex size op src dst imm)))) + dst)) + +(decl cvt_int_to_float (SseOpcode Xmm GprMem OperandSize) Xmm) +(rule (cvt_int_to_float op src1 src2 size) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.CvtIntToFloat op src1 src2 dst size)))) + dst)) + +(decl cvt_int_to_float_vex (AvxOpcode Xmm GprMem OperandSize) Xmm) +(rule (cvt_int_to_float_vex op src1 src2 size) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.CvtIntToFloatVex op src1 src2 dst size)))) + dst)) + +(decl cvt_u64_to_float_seq (Type Gpr) Xmm) +(rule (cvt_u64_to_float_seq ty src) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (dst WritableXmm (temp_writable_xmm)) + (tmp_gpr1 WritableGpr (temp_writable_gpr)) + (tmp_gpr2 WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CvtUint64ToFloatSeq size src dst tmp_gpr1 tmp_gpr2)))) + dst)) + +(decl cvt_float_to_uint_seq (Type Value bool) Gpr) +(rule (cvt_float_to_uint_seq out_ty src @ (value_type src_ty) is_saturating) + (let ((out_size OperandSize (raw_operand_size_of_type out_ty)) + (src_size OperandSize (raw_operand_size_of_type src_ty)) + + (dst WritableGpr (temp_writable_gpr)) + (tmp_xmm WritableXmm (temp_writable_xmm)) + (tmp_xmm2 WritableXmm (temp_writable_xmm)) + (tmp_gpr WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CvtFloatToUintSeq out_size src_size is_saturating src dst tmp_gpr tmp_xmm tmp_xmm2)))) + dst)) + +(decl cvt_float_to_sint_seq (Type Value bool) Gpr) +(rule (cvt_float_to_sint_seq out_ty src @ (value_type src_ty) is_saturating) + (let ((out_size OperandSize (raw_operand_size_of_type out_ty)) + (src_size OperandSize (raw_operand_size_of_type src_ty)) + + (dst WritableGpr (temp_writable_gpr)) + (tmp_xmm WritableXmm (temp_writable_xmm)) + (tmp_gpr WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CvtFloatToSintSeq out_size src_size is_saturating src dst tmp_gpr tmp_xmm)))) + dst)) + +;; Helper for creating `MovFromPReg` instructions. +(decl mov_from_preg (PReg) Reg) +(rule (mov_from_preg preg) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.MovFromPReg preg dst)))) + dst)) + +;;;; Helpers for Sign/Zero Extending ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type ExtKind extern + (enum None + SignExtend + ZeroExtend)) + +(type ExtendKind (enum Sign Zero)) + +(model ExtMode (enum + (BL #b000) + (BQ #b001) + (WL #b010) + (WQ #b011) + (LQ #b100) +)) +(type ExtMode extern (enum BL BQ WL WQ LQ)) + +;; `ExtMode::new` + +(spec (ext_mode x y) + (provide (= result (switch x + (#x0008 (switch y + (#x0020 (ExtMode.BL)) + (#x0040 (ExtMode.BQ)) + )) + (#x0010 (switch y + (#x0020 (ExtMode.WL)) + (#x0040 (ExtMode.WQ)) + )) + (#x0020 (switch y + (#x0040 (ExtMode.LQ)) + )) + )) + ) +) +(decl ext_mode (u16 u16) ExtMode) +(extern constructor ext_mode ext_mode) + +;; Put the given value into a register, but extended as the given type. +(decl extend_to_gpr (Value Type ExtendKind) Gpr) + +;; If the value is already of the requested type, no extending is necessary. +(rule 3 (extend_to_gpr val @ (value_type ty) ty _kind) + val) + +;; I32 -> I64 with op that produces a zero-extended value in a register. +;; +;; As a particular x64 extra-pattern matching opportunity, all the ALU +;; opcodes on 32-bits will zero-extend the upper 32-bits, so we can +;; even not generate a zero-extended move in this case. +(rule 2 (extend_to_gpr src @ (value_type $I32) $I64 (ExtendKind.Zero)) + (if-let true (value32_zeros_upper32 src)) + (add_range_fact src 64 0 0xffff_ffff)) + +;; Both extend instructions are guaranteed to load exactly the source type's size. +;; So we can use `sinkable_load_exact` here to sink loads for small types (<= 16 bits). +(rule 1 (extend_to_gpr (and (sinkable_load_exact val) (value_type from_ty)) to_ty kind) + (extend_to_gpr_types val from_ty to_ty kind)) + +;; Otherwise emit the extend from a Gpr to a Gpr. +(rule (extend_to_gpr (and val (value_type from_ty)) to_ty kind) + (extend_to_gpr_types val from_ty to_ty kind)) + +;; Calculates the correct extension mode for an extend between `from_ty` and `to_ty`. +(decl extend_to_gpr_types (GprMem Type Type ExtendKind) Gpr) +(rule (extend_to_gpr_types val from_ty to_ty kind) + (let ((from_bits u16 (ty_bits_u16 from_ty)) + ;; Use `operand_size_of_type` so that the we clamp the output to 32- + ;; or 64-bit width types. + (to_bits u16 (operand_size_bits (operand_size_of_type_32_64 to_ty)))) + (extend kind + to_ty + (ext_mode from_bits to_bits) + val))) + + +;; Do a sign or zero extension of the given `GprMem`. +(decl extend (ExtendKind Type ExtMode GprMem) Gpr) + +;; Zero extending uses `movzx`. +(rule (extend (ExtendKind.Zero) ty mode src) + (x64_movzx mode src)) + +;; Sign extending uses `movsx`. +(rule (extend (ExtendKind.Sign) ty mode src) + (x64_movsx mode src)) + +;; Tests whether the operation used to produce the input `Value`, which must +;; be a 32-bit operation, will automatically zero the upper 32-bits of the +;; destination register that `Value` is placed in. +(decl pure value32_zeros_upper32 (Value) bool) +(rule (value32_zeros_upper32 (iadd _ _)) true) +(rule (value32_zeros_upper32 (isub _ _)) true) +(rule (value32_zeros_upper32 (imul _ _)) true) +(rule (value32_zeros_upper32 (band _ _)) true) +(rule (value32_zeros_upper32 (bor _ _)) true) +(rule (value32_zeros_upper32 (bxor _ _)) true) +(rule (value32_zeros_upper32 (ishl _ _)) true) +(rule (value32_zeros_upper32 (ushr _ _)) true) +(rule (value32_zeros_upper32 (uload32 _ _ _)) true) +(rule -1 (value32_zeros_upper32 _) false) + +;;;; Helpers for Working SSE tidbits ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Turn a vector type into its integer-typed vector equivalent. +(decl vec_int_type (Type) Type) +(rule (vec_int_type (multi_lane 8 16)) $I8X16) +(rule (vec_int_type (multi_lane 16 8)) $I16X8) +(rule (vec_int_type (multi_lane 32 4)) $I32X4) +(rule (vec_int_type (multi_lane 64 2)) $I64X2) + +;; Performs an xor operation of the two operands specified. +(decl x64_xor_vector (Type Xmm XmmMem) Xmm) +(rule 1 (x64_xor_vector $F16 x y) (x64_xorps x y)) +(rule 1 (x64_xor_vector $F32 x y) (x64_xorps x y)) +(rule 1 (x64_xor_vector $F64 x y) (x64_xorpd x y)) +(rule 1 (x64_xor_vector $F128 x y) (x64_xorps x y)) +(rule 1 (x64_xor_vector $F32X4 x y) (x64_xorps x y)) +(rule 1 (x64_xor_vector $F64X2 x y) (x64_xorpd x y)) +(rule 0 (x64_xor_vector (multi_lane _ _) x y) (x64_pxor x y)) + +;; Generates a register value which has an all-ones pattern. +;; +;; Note that this is accomplished by comparing a fresh register with itself, +;; which for integers is always true. Also note that the comparison is always +;; done for integers. This is because we're comparing a fresh register to itself +;; and we don't know the previous contents of the register. If a floating-point +;; comparison is used then it runs the risk of comparing NaN against NaN and not +;; actually producing an all-ones mask. By using integer comparison operations +;; we're guaranteeed that everything is equal to itself. +(decl vector_all_ones () Xmm) +(rule (vector_all_ones) + (let ((tmp Xmm (xmm_uninit_value))) + (x64_pcmpeqd tmp tmp))) + +;; Move a `RegMemImm.Reg` operand to an XMM register, if necessary. +(decl mov_rmi_to_xmm (RegMemImm) XmmMemImm) +(rule (mov_rmi_to_xmm rmi @ (RegMemImm.Mem _)) (xmm_mem_imm_new rmi)) +(rule (mov_rmi_to_xmm rmi @ (RegMemImm.Imm _)) (xmm_mem_imm_new rmi)) +(rule (mov_rmi_to_xmm (RegMemImm.Reg r)) (x64_movd_to_xmm r)) + +;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl gen_call (SigRef ExternalName RelocDistance ValueSlice) InstOutput) +(extern constructor gen_call gen_call) + +(decl gen_call_indirect (SigRef Value ValueSlice) InstOutput) +(extern constructor gen_call_indirect gen_call_indirect) + +;;;; Helpers for emitting stack switches ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl x64_stack_switch_basic (Gpr Gpr Gpr) Gpr) +(rule (x64_stack_switch_basic store_context_ptr load_context_ptr in_payload0) + (let ((out_payload0 WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.StackSwitchBasic store_context_ptr + load_context_ptr + in_payload0 + out_payload0)))) + out_payload0)) + +;;;; Helpers for Emitting Loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load a value into a register. +(decl x64_load (Type SyntheticAmode ExtKind) Reg) + +(rule 1 (x64_load (fits_in_32 ty) addr (ExtKind.SignExtend)) + (x64_movsx (ext_mode (ty_bytes ty) 8) + addr)) + +(rule 2 (x64_load $I64 addr _ext_kind) + (mov64_mr addr)) + +(rule 2 (x64_load $F32 addr _ext_kind) + (x64_movss_load addr)) + +(rule 2 (x64_load $F64 addr _ext_kind) + (x64_movsd_load addr)) + +(rule 2 (x64_load $F128 addr _ext_kind) + (x64_movdqu_load addr)) + +(rule 2 (x64_load $F32X4 addr _ext_kind) + (x64_movups_load addr)) + +(rule 2 (x64_load $F64X2 addr _ext_kind) + (x64_movupd_load addr)) + +(rule 0 (x64_load (multi_lane _bits _lanes) addr _ext_kind) + (x64_movdqu_load addr)) + +(decl x64_mov (Amode) Reg) +(spec (x64_mov addr) + (provide (= result (conv_to 64 (load_effect (extract 79 64 addr) 64 (extract 63 0 addr)))))) +(rule (x64_mov addr) + (mov64_mr addr)) + +(decl x64_movzx (ExtMode GprMem) Gpr) +(spec (x64_movzx mode src) + (provide + (= result + (conv_to + 64 + (zero_ext + 32 + (load_effect + (extract 79 64 src) + (switch mode + ((ExtMode.BL) 8) + ((ExtMode.BQ) 8) + ((ExtMode.WL) 16) + ((ExtMode.WQ) 16) + ((ExtMode.LQ) 32)) + (extract 63 0 src)))))) + (require (or (= mode (ExtMode.BL)) + (= mode (ExtMode.BQ)) + (= mode (ExtMode.WL)) + (= mode (ExtMode.WQ)) + (= mode (ExtMode.LQ))))) +(rule (x64_movzx mode src) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.MovzxRmR mode src dst)))) + dst)) + +(decl x64_movsx (ExtMode GprMem) Gpr) +(rule (x64_movsx mode src) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.MovsxRmR mode src dst)))) + dst)) + +(decl x64_movss_load (SyntheticAmode) Xmm) +(rule (x64_movss_load from) + (xmm_unary_rm_r_unaligned (SseOpcode.Movss) from)) +(rule 1 (x64_movss_load from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovss) from)) + +(decl x64_movss_store (SyntheticAmode Xmm) SideEffectNoResult) +(rule (x64_movss_store addr data) + (xmm_movrm (SseOpcode.Movss) addr data)) +(rule 1 (x64_movss_store addr data) + (if-let true (use_avx)) + (xmm_movrm_vex (AvxOpcode.Vmovss) addr data)) + +(decl x64_movsd_load (SyntheticAmode) Xmm) +(rule (x64_movsd_load from) + (xmm_unary_rm_r_unaligned (SseOpcode.Movsd) from)) +(rule 1 (x64_movsd_load from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovsd) from)) + +(decl x64_movsd_store (SyntheticAmode Xmm) SideEffectNoResult) +(rule (x64_movsd_store addr data) + (xmm_movrm (SseOpcode.Movsd) addr data)) +(rule 1 (x64_movsd_store addr data) + (if-let true (use_avx)) + (xmm_movrm_vex (AvxOpcode.Vmovsd) addr data)) + +(decl x64_movups_load (SyntheticAmode) Xmm) +(rule (x64_movups_load from) + (xmm_unary_rm_r_unaligned (SseOpcode.Movups) from)) +(rule 1 (x64_movups_load from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovups) from)) + +(decl x64_movups_store (SyntheticAmode Xmm) SideEffectNoResult) +(rule (x64_movups_store addr data) + (xmm_movrm (SseOpcode.Movups) addr data)) +(rule 1 (x64_movups_store addr data) + (if-let true (use_avx)) + (xmm_movrm_vex (AvxOpcode.Vmovups) addr data)) + +(decl x64_movupd_load (SyntheticAmode) Xmm) +(rule (x64_movupd_load from) + (xmm_unary_rm_r_unaligned (SseOpcode.Movupd) from)) +(rule 1 (x64_movupd_load from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovupd) from)) + +(decl x64_movupd_store (SyntheticAmode Xmm) SideEffectNoResult) +(rule (x64_movupd_store addr data) + (xmm_movrm (SseOpcode.Movupd) addr data)) +(rule 1 (x64_movupd_store addr data) + (if-let true (use_avx)) + (xmm_movrm_vex (AvxOpcode.Vmovupd) addr data)) + +;; Helper for creating `movd` instructions. +(decl x64_movd_to_gpr (Xmm) Gpr) +(rule (x64_movd_to_gpr from) + (xmm_to_gpr (SseOpcode.Movd) from (OperandSize.Size32))) +(rule 1 (x64_movd_to_gpr from) + (if-let true (use_avx)) + (xmm_to_gpr_vex (AvxOpcode.Vmovd) from (OperandSize.Size32))) + +;; Helper for creating `movd` instructions. +(decl x64_movd_to_xmm (GprMem) Xmm) +(rule (x64_movd_to_xmm from) + (gpr_to_xmm (SseOpcode.Movd) from (OperandSize.Size32))) +(rule 1 (x64_movd_to_xmm from) + (if-let true (use_avx)) + (gpr_to_xmm_vex (AvxOpcode.Vmovd) from (OperandSize.Size32))) + +;; Helper for creating `movq` instructions. +(decl x64_movq_to_xmm (GprMem) Xmm) +(rule (x64_movq_to_xmm src) + (gpr_to_xmm (SseOpcode.Movq) src (OperandSize.Size64))) +(rule 1 (x64_movq_to_xmm from) + (if-let true (use_avx)) + (gpr_to_xmm_vex (AvxOpcode.Vmovq) from (OperandSize.Size64))) + +;; Helper for creating `movq` instructions. +(decl x64_movq_to_gpr (Xmm) Gpr) +(rule (x64_movq_to_gpr src) + (xmm_to_gpr (SseOpcode.Movq) src (OperandSize.Size64))) +(rule 1 (x64_movq_to_gpr from) + (if-let true (use_avx)) + (xmm_to_gpr_vex (AvxOpcode.Vmovq) from (OperandSize.Size64))) + +(decl x64_movdqu_load (XmmMem) Xmm) +(rule (x64_movdqu_load from) + (xmm_unary_rm_r_unaligned (SseOpcode.Movdqu) from)) +(rule 1 (x64_movdqu_load from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovdqu) from)) + +(decl x64_movdqu_store (SyntheticAmode Xmm) SideEffectNoResult) +(rule (x64_movdqu_store addr data) + (xmm_movrm (SseOpcode.Movdqu) addr data)) +(rule 1 (x64_movdqu_store addr data) + (if-let true (use_avx)) + (xmm_movrm_vex (AvxOpcode.Vmovdqu) addr data)) + +(decl x64_pmovsxbw (XmmMem) Xmm) +(rule (x64_pmovsxbw from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovsxbw) from)) +(rule 1 (x64_pmovsxbw from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovsxbw) from)) + +(decl x64_pmovzxbw (XmmMem) Xmm) +(rule (x64_pmovzxbw from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovzxbw) from)) +(rule 1 (x64_pmovzxbw from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovzxbw) from)) + +(decl x64_pmovsxwd (XmmMem) Xmm) +(rule (x64_pmovsxwd from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovsxwd) from)) +(rule 1 (x64_pmovsxwd from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovsxwd) from)) + +(decl x64_pmovzxwd (XmmMem) Xmm) +(rule (x64_pmovzxwd from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovzxwd) from)) +(rule 1 (x64_pmovzxwd from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovzxwd) from)) + +(decl x64_pmovsxdq (XmmMem) Xmm) +(rule (x64_pmovsxdq from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovsxdq) from)) +(rule 1 (x64_pmovsxdq from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovsxdq) from)) + +(decl x64_pmovzxdq (XmmMem) Xmm) +(rule (x64_pmovzxdq from) + (xmm_unary_rm_r_unaligned (SseOpcode.Pmovzxdq) from)) +(rule 1 (x64_pmovzxdq from) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpmovzxdq) from)) + +(decl x64_movrm (Type SyntheticAmode Gpr) SideEffectNoResult) +(spec (x64_movrm ty addr data) + (provide (= result (store_effect (extract 79 64 addr) ty (conv_to ty data) (extract 63 0 addr))))) +(rule (x64_movrm ty addr data) + (let ((size OperandSize (raw_operand_size_of_type ty))) + (SideEffectNoResult.Inst (MInst.MovRM size data addr)))) + +(decl x64_movimm_m (Type SyntheticAmode i32) SideEffectNoResult) +(rule (x64_movimm_m ty addr imm) + (let ((size OperandSize (raw_operand_size_of_type ty))) + (SideEffectNoResult.Inst (MInst.MovImmM size imm addr)))) + +(decl xmm_movrm (SseOpcode SyntheticAmode Xmm) SideEffectNoResult) +(rule (xmm_movrm op addr data) + (SideEffectNoResult.Inst (MInst.XmmMovRM op data addr))) + +(decl xmm_movrm_imm (SseOpcode SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (xmm_movrm_imm op addr data imm) + (SideEffectNoResult.Inst (MInst.XmmMovRMImm op data addr imm))) + +(decl xmm_movrm_vex (AvxOpcode SyntheticAmode Xmm) SideEffectNoResult) +(rule (xmm_movrm_vex op addr data) + (SideEffectNoResult.Inst (MInst.XmmMovRMVex op data addr))) + +(decl xmm_movrm_imm_vex (AvxOpcode SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (xmm_movrm_imm_vex op addr data imm) + (SideEffectNoResult.Inst (MInst.XmmMovRMImmVex op data addr imm))) + +;; Load a constant into an XMM register. +(decl x64_xmm_load_const (Type VCodeConstant) Xmm) +(rule (x64_xmm_load_const ty const) + (x64_load ty (const_to_synthetic_amode const) (ExtKind.None))) + +;;;; Instruction Constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; These constructors create SSA-style `MInst`s. It is their responsibility to +;; maintain the invariant that each temporary register they allocate and define +;; only gets defined the once. + +;; Helper for emitting `add` instructions. +(decl x64_add (Type Gpr GprMemImm) Gpr) +(rule (x64_add ty src1 src2) + (alu_rmi_r ty + (AluRmiROpcode.Add) + src1 + src2)) + +;; Helper for creating `add` instructions whose flags are also used. +(decl x64_add_with_flags_paired (Type Gpr GprMemImm) ProducesFlags) +(rule (x64_add_with_flags_paired ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRmiR (operand_size_of_type_32_64 ty) + (AluRmiROpcode.Add) + src1 + src2 + dst) + dst))) + +(decl x64_alurmi_with_flags_paired (AluRmiROpcode Type Gpr GprMemImm) ProducesFlags) +(rule (x64_alurmi_with_flags_paired opc (fits_in_64 ty) src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRmiR (raw_operand_size_of_type ty) + opc + src1 + src2 + dst) + dst))) + +(decl x64_alurmi_flags_side_effect (AluRmiROpcode Type Gpr GprMemImm) ProducesFlags) +(rule (x64_alurmi_flags_side_effect opc (fits_in_64 ty) src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRmiR (raw_operand_size_of_type ty) + opc + src1 + src2 + (temp_writable_gpr)))) + +;; Should only be used for Adc and Sbb +(decl x64_alurmi_with_flags_chained (AluRmiROpcode Type Gpr GprMemImm) ConsumesAndProducesFlags) +(rule (x64_alurmi_with_flags_chained opc (fits_in_64 ty) src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ConsumesAndProducesFlags.ReturnsReg + (MInst.AluRmiR (raw_operand_size_of_type ty) + opc + src1 + src2 + dst) + dst))) + +;; Helper for creating `adc` instructions. +(decl x64_adc_paired (Type Gpr GprMemImm) ConsumesFlags) +(rule (x64_adc_paired ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer + (MInst.AluRmiR (operand_size_of_type_32_64 ty) + (AluRmiROpcode.Adc) + src1 + src2 + dst) + dst))) + +;; Helper for emitting `sub` instructions. +(decl x64_sub (Type Gpr GprMemImm) Gpr) +(rule (x64_sub ty src1 src2) + (alu_rmi_r ty + (AluRmiROpcode.Sub) + src1 + src2)) + +;; Helper for creating `sub` instructions whose flags are also used. +(decl x64_sub_with_flags_paired (Type Gpr GprMemImm) ProducesFlags) +(rule (x64_sub_with_flags_paired ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.AluRmiR (operand_size_of_type_32_64 ty) + (AluRmiROpcode.Sub) + src1 + src2 + dst) + dst))) + +;; Helper for creating `sbb` instructions. +(decl x64_sbb_paired (Type Gpr GprMemImm) ConsumesFlags) +(rule (x64_sbb_paired ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer + (MInst.AluRmiR (operand_size_of_type_32_64 ty) + (AluRmiROpcode.Sbb) + src1 + src2 + dst) + dst))) + +;; Helper for creating `mul` instructions or `imul` instructions (depending +;; on `signed`) +(decl x64_mul (Type bool Gpr GprMem) ValueRegs) +(rule (x64_mul ty signed src1 src2) + (let ((dst_lo WritableGpr (temp_writable_gpr)) + (dst_hi WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.Mul size signed src1 src2 dst_lo dst_hi)))) + (value_gprs dst_lo dst_hi))) + +;; Special case the `mulx` pattern with the BMI2 instruction set. +(rule 1 (x64_mul (ty_32_or_64 ty) false src1 src2) + (if-let true (use_bmi2)) + (let ((dst_lo WritableGpr (temp_writable_gpr)) + (dst_hi WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.MulX size src1 src2 dst_lo dst_hi)))) + (value_gprs dst_lo dst_hi))) + +(decl x64_mulx_hi (Type Gpr GprMem) Gpr) +(rule (x64_mulx_hi (ty_32_or_64 ty) src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.MulX size src1 src2 (writable_invalid_gpr) dst)))) + dst)) + +;; Get the invalid register as writable +(decl writable_invalid_gpr () WritableGpr) +(extern constructor writable_invalid_gpr writable_invalid_gpr) + +;; Helper for creating `mul` instructions or `imul` instructions (depending +;; on `signed`) for 8-bit operands. +(decl x64_mul8 (bool Gpr GprMem) Gpr) +(rule (x64_mul8 signed src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Mul8 signed src1 src2 dst)))) + dst)) + +;; Helper for creating `imul` instructions. +(decl x64_imul (Type Gpr GprMem) Gpr) +(rule (x64_imul ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.IMul size src1 src2 dst)))) + dst)) + +;; Helper for creating `imul` instructions with an immediate operand. +(decl x64_imul_imm (Type GprMem i32) Gpr) +(rule (x64_imul_imm ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.IMulImm size src1 src2 dst)))) + dst)) + +(decl x64_mul8_with_flags_paired (bool Gpr GprMem) ProducesFlags) +(rule (x64_mul8_with_flags_paired signed src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.Mul8 signed src1 src2 dst) + dst))) + +(decl x64_mul_lo_with_flags_paired (Type bool Gpr GprMem) ProducesFlags) +(rule (x64_mul_lo_with_flags_paired ty signed src1 src2) + (let ((dst_lo WritableGpr (temp_writable_gpr)) + (dst_hi WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer + (MInst.Mul size signed src1 src2 dst_lo dst_hi) + dst_lo))) + +;; Helper for emitting `and` instructions. +(decl x64_and (Type Gpr GprMemImm) Gpr) +(rule (x64_and ty src1 src2) + (alu_rmi_r ty + (AluRmiROpcode.And) + src1 + src2)) + +(decl x64_and_with_flags_paired (Type Gpr GprMemImm) ProducesFlags) +(rule (x64_and_with_flags_paired ty src1 src2) + (let ((dst WritableGpr (temp_writable_gpr))) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.AluRmiR (operand_size_of_type_32_64 ty) + (AluRmiROpcode.And) + src1 + src2 + dst)))) + +;; Helper for emitting `or` instructions. +(decl x64_or (Type Gpr GprMemImm) Gpr) +(rule (x64_or ty src1 src2) + (alu_rmi_r ty + (AluRmiROpcode.Or) + src1 + src2)) + +;; Helper for emitting `xor` instructions. +(decl x64_xor (Type Gpr GprMemImm) Gpr) +(rule (x64_xor ty src1 src2) + (alu_rmi_r ty + (AluRmiROpcode.Xor) + src1 + src2)) + +(decl x64_andn (Type Gpr GprMem) Gpr) +(rule (x64_andn ty src1 src2) + (alu_rm_r_vex ty (AluRmROpcode.Andn) src1 src2)) + +;; Helper for emitting immediates with an `i64` value. Note that +;; integer constants in ISLE are always parsed as `i128`s; this enables +;; negative numbers to be used as immediates. +(decl imm_i64 (Type i64) Reg) +(rule (imm_i64 ty value) + (imm ty (i64_as_u64 value))) + +(decl nonzero_u64_fits_in_u32 (u64) u64) +(extern extractor nonzero_u64_fits_in_u32 nonzero_u64_fits_in_u32) + +;; Helper for emitting immediates. +;; +;; There are three priorities in use in this rule: +;; 2 - rules that match on an explicit type +;; 1 - rules that match on types that fit in 64 bits +;; 0 - rules that match on vectors +(decl imm (Type u64) Reg) + +;; Integer immediates. +(rule 1 (imm (fits_in_64 ty) (u64_nonzero simm64)) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.Imm size simm64 dst)))) + dst)) + +;; `f16` immediates. +(rule 2 (imm $F16 (u64_nonzero bits)) + (bitcast_gpr_to_xmm 16 (imm $I16 bits))) + +;; `f32` immediates. +(rule 2 (imm $F32 (u64_nonzero bits)) + (x64_movd_to_xmm (imm $I32 bits))) + +;; `f64` immediates. +(rule 2 (imm $F64 (u64_nonzero bits)) + (x64_movq_to_xmm (imm $I64 bits))) + +;; Special case for when a 64-bit immediate fits into 32-bits. We can use a +;; 32-bit move that zero-extends the value, which has a smaller encoding. +(rule 2 (imm $I64 (nonzero_u64_fits_in_u32 x)) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Imm (OperandSize.Size32) x dst)))) + dst)) + +;; Special case for integer zero immediates: turn them into an `xor r, r`. +(rule 1 (imm (fits_in_64 ty) (u64_zero)) + (let ((wgpr WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.AluConstOp (AluRmiROpcode.Xor) size wgpr)))) + (gpr_to_reg wgpr))) + +;; Special case for zero immediates with vector types, they turn into an xor +;; specific to the vector type. +(rule 0 (imm ty @ (multi_lane _bits _lanes) 0) + (xmm_to_reg (xmm_zero ty))) + +;; Special case for `f16` zero immediates +(rule 2 (imm ty @ $F16 (u64_zero)) (xmm_zero ty)) + +;; Special case for `f32` zero immediates +(rule 2 (imm ty @ $F32 (u64_zero)) (xmm_zero ty)) + +;; TODO: use cmpeqps for all 1s + +;; Special case for `f64` zero immediates to use `xorpd`. +(rule 2 (imm ty @ $F64 (u64_zero)) (xmm_zero ty)) + +;; TODO: use cmpeqpd for all 1s + +(decl xmm_zero (Type) Xmm) +(rule (xmm_zero ty) + (let ((tmp Xmm (xmm_uninit_value))) + (x64_xor_vector ty tmp tmp))) + +;; Helper for creating `MInst.ShiftR` instructions. +(decl shift_r (Type ShiftKind Gpr Imm8Gpr) Gpr) +(rule (shift_r ty kind src1 src2) + (let ((dst WritableGpr (temp_writable_gpr)) + ;; Use actual 8/16-bit instructions when appropriate: we + ;; rely on their shift-amount-masking semantics. + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.ShiftR size kind src1 src2 dst)))) + dst)) + +;; Helper for creating `rotl` instructions. +(decl x64_rotl (Type Gpr Imm8Gpr) Gpr) +(rule (x64_rotl ty src1 src2) + (shift_r ty (ShiftKind.RotateLeft) src1 src2)) +(rule 1 (x64_rotl (ty_32_or_64 ty) src (imm8_from_imm8_gpr imm)) + (if-let true (use_bmi2)) + (x64_rorx ty src (u8_sub (ty_bits ty) imm))) + +;; Helper for creating `rotr` instructions. +(decl x64_rotr (Type Gpr Imm8Gpr) Gpr) +(rule (x64_rotr ty src1 src2) + (shift_r ty (ShiftKind.RotateRight) src1 src2)) +(rule 1 (x64_rotr (ty_32_or_64 ty) src (imm8_from_imm8_gpr imm)) + (if-let true (use_bmi2)) + (x64_rorx ty src imm)) + +;; Helper for creating `shl` instructions. +(decl x64_shl (Type Gpr Imm8Gpr) Gpr) +(rule (x64_shl ty src1 src2) + (shift_r ty (ShiftKind.ShiftLeft) src1 src2)) +;; With BMI2 the `shlx` instruction is also available, and it's unconditionally +;; used for registers shifted by registers since it provides more freedom +;; in regalloc since nothing is constrained. Note that the `shlx` instruction +;; doesn't encode an immediate so any immediate-based shift still uses `shl`. +(rule 1 (x64_shl (ty_32_or_64 ty) src1 (gpr_from_imm8_gpr src2)) + (if-let true (use_bmi2)) + (x64_shlx ty src1 src2)) + +;; Helper for creating logical shift-right instructions. +(decl x64_shr (Type Gpr Imm8Gpr) Gpr) +(rule (x64_shr ty src1 src2) + (shift_r ty (ShiftKind.ShiftRightLogical) src1 src2)) +;; see `x64_shl` for more info about this rule +(rule 1 (x64_shr (ty_32_or_64 ty) src1 (gpr_from_imm8_gpr src2)) + (if-let true (use_bmi2)) + (x64_shrx ty src1 src2)) + +;; Helper for creating arithmetic shift-right instructions. +(decl x64_sar (Type Gpr Imm8Gpr) Gpr) +(rule (x64_sar ty src1 src2) + (shift_r ty (ShiftKind.ShiftRightArithmetic) src1 src2)) +;; see `x64_shl` for more info about this rule +(rule 1 (x64_sar (ty_32_or_64 ty) src1 (gpr_from_imm8_gpr src2)) + (if-let true (use_bmi2)) + (x64_sarx ty src1 src2)) + +;; Helper for creating zeroing-of-high-bits instructions bzhi +;; +;; Note that the `src` operands are swapped here. The amount-to-shift-by +;; is stored in `vvvv` which is `src1` in the `AluRmRVex` instruction shape. +(decl x64_bzhi (Type GprMem Gpr) Gpr) +(rule (x64_bzhi ty src1 src2) + (alu_rm_r_vex ty (AluRmROpcode.Bzhi) src2 src1)) + +;; Helper for creating byteswap instructions. +;; In x64, 32- and 64-bit registers use BSWAP instruction, and +;; for 16-bit registers one must instead use xchg or rol/ror +(decl x64_bswap (Type Gpr) Gpr) +(rule (x64_bswap ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.Bswap size src dst)))) + dst)) + +;; Helper for creating `MInst.CmpRmiR` instructions. +(decl cmp_rmi_r (OperandSize CmpOpcode Gpr GprMemImm) ProducesFlags) +(rule (cmp_rmi_r size opcode src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.CmpRmiR size + opcode + src1 + src2))) + +;; Helper for creating `cmp` instructions. +(decl x64_cmp (OperandSize Gpr GprMemImm) ProducesFlags) +(rule (x64_cmp size src1 src2) + (cmp_rmi_r size (CmpOpcode.Cmp) src1 src2)) + +;; Helper for creating `cmp` instructions with an immediate. +(decl x64_cmp_imm (OperandSize Gpr u32) ProducesFlags) +(rule (x64_cmp_imm size src1 src2) + (x64_cmp size src1 (RegMemImm.Imm src2))) + +;; Helper for creating `MInst.XmmCmpRmR` instructions. +(decl xmm_cmp_rm_r (SseOpcode Xmm XmmMem) ProducesFlags) +(rule (xmm_cmp_rm_r opcode src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.XmmCmpRmR opcode src1 src2))) + +;; Helper for creating `MInst.XmmCmpRmRVex` instructions. +(decl xmm_cmp_rm_r_vex (AvxOpcode Xmm XmmMem) ProducesFlags) +(rule (xmm_cmp_rm_r_vex opcode src1 src2) + (ProducesFlags.ProducesFlagsSideEffect + (MInst.XmmCmpRmRVex opcode src1 src2))) + +;; Helper for creating floating-point comparison instructions (`UCOMIS[S|D]`). +(decl x64_ucomis (Type Xmm XmmMem) ProducesFlags) +(rule (x64_ucomis $F32 src1 src2) + (xmm_cmp_rm_r (SseOpcode.Ucomiss) src1 src2)) +(rule (x64_ucomis $F64 src1 src2) + (xmm_cmp_rm_r (SseOpcode.Ucomisd) src1 src2)) +(rule 1 (x64_ucomis $F32 src1 src2) + (if-let true (use_avx)) + (xmm_cmp_rm_r_vex (AvxOpcode.Vucomiss) src1 src2)) +(rule 1 (x64_ucomis $F64 src1 src2) + (if-let true (use_avx)) + (xmm_cmp_rm_r_vex (AvxOpcode.Vucomisd) src1 src2)) + +;; Helper for creating `test` instructions. +(decl x64_test (OperandSize Gpr GprMemImm) ProducesFlags) +(rule (x64_test size src1 src2) + (cmp_rmi_r size (CmpOpcode.Test) src1 src2)) + +;; Helper for creating `ptest` instructions. +(decl x64_ptest (Xmm XmmMem) ProducesFlags) +(rule (x64_ptest src1 src2) + (xmm_cmp_rm_r (SseOpcode.Ptest) src1 src2)) +(rule 1 (x64_ptest src1 src2) + (if-let true (use_avx)) + (xmm_cmp_rm_r_vex (AvxOpcode.Vptest) src1 src2)) + +;; Helper for creating `cmove` instructions. Note that these instructions do not +;; always result in a single emitted x86 instruction; e.g., XmmCmove uses jumps +;; to conditionally move the selected value into an XMM register. +(decl cmove (Type CC GprMem Gpr) ConsumesFlags) +(rule (cmove ty cc consequent alternative) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.Cmove size cc consequent alternative dst) + dst))) + +(decl cmove_xmm (Type CC Xmm Xmm) ConsumesFlags) +(rule (cmove_xmm ty cc consequent alternative) + (let ((dst WritableXmm (temp_writable_xmm))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.XmmCmove ty cc consequent alternative dst) + dst))) + +;; Helper for creating `cmove` instructions directly from values. This allows us +;; to special-case the `I128` types and default to the `cmove` helper otherwise. +;; It also eliminates some `put_in_reg*` boilerplate in the lowering ISLE code. +(decl cmove_from_values (Type CC Value Value) ConsumesFlags) +(rule (cmove_from_values (is_multi_register_gpr_type $I128) cc consequent alternative) + (let ((cons ValueRegs consequent) + (alt ValueRegs alternative) + (dst1 WritableGpr (temp_writable_gpr)) + (dst2 WritableGpr (temp_writable_gpr)) + (size OperandSize (OperandSize.Size64)) + (lower_cmove MInst (MInst.Cmove + size cc + (value_regs_get_gpr cons 0) + (value_regs_get_gpr alt 0) + dst1)) + (upper_cmove MInst (MInst.Cmove + size cc + (value_regs_get_gpr cons 1) + (value_regs_get_gpr alt 1) + dst2))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + lower_cmove + upper_cmove + (value_regs dst1 dst2)))) + +(rule (cmove_from_values (is_single_register_gpr_type ty) cc consequent alternative) + (cmove ty cc consequent alternative)) + +(rule (cmove_from_values (is_xmm_type ty) cc consequent alternative) + (cmove_xmm ty cc consequent alternative)) + +;; Helper for creating `cmove` instructions with the logical OR of multiple +;; flags. Note that these instructions will always result in more than one +;; emitted x86 instruction. +(decl cmove_or (Type CC CC GprMem Gpr) ConsumesFlags) +(rule (cmove_or ty cc1 cc2 consequent alternative) + (let ((dst WritableGpr (temp_writable_gpr)) + (tmp WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (cmove1 MInst (MInst.Cmove size cc1 consequent alternative tmp)) + (cmove2 MInst (MInst.Cmove size cc2 consequent tmp dst))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + cmove1 + cmove2 + dst))) + +(decl cmove_or_xmm (Type CC CC Xmm Xmm) ConsumesFlags) +(rule (cmove_or_xmm ty cc1 cc2 consequent alternative) + (let ((dst WritableXmm (temp_writable_xmm)) + (tmp WritableXmm (temp_writable_xmm)) + (cmove1 MInst (MInst.XmmCmove ty cc1 consequent alternative tmp)) + (cmove2 MInst (MInst.XmmCmove ty cc2 consequent tmp dst))) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + cmove1 + cmove2 + dst))) + +;; Helper for creating `cmove_or` instructions directly from values. This allows +;; us to special-case the `I128` types and default to the `cmove_or` helper +;; otherwise. +(decl cmove_or_from_values (Type CC CC Value Value) ConsumesFlags) +(rule (cmove_or_from_values (is_multi_register_gpr_type $I128) cc1 cc2 consequent alternative) + (let ((cons ValueRegs consequent) + (alt ValueRegs alternative) + (dst1 WritableGpr (temp_writable_gpr)) + (dst2 WritableGpr (temp_writable_gpr)) + (tmp1 WritableGpr (temp_writable_gpr)) + (tmp2 WritableGpr (temp_writable_gpr)) + (size OperandSize (OperandSize.Size64)) + (cmove1 MInst (MInst.Cmove size cc1 (value_regs_get_gpr cons 0) (value_regs_get_gpr alt 0) tmp1)) + (cmove2 MInst (MInst.Cmove size cc2 (value_regs_get_gpr cons 0) tmp1 dst1)) + (cmove3 MInst (MInst.Cmove size cc1 (value_regs_get_gpr cons 1) (value_regs_get_gpr alt 1) tmp2)) + (cmove4 MInst (MInst.Cmove size cc2 (value_regs_get_gpr cons 1) tmp2 dst2))) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs + cmove1 + cmove2 + cmove3 + cmove4 + (value_regs dst1 dst2)))) + +(rule (cmove_or_from_values (is_single_register_gpr_type ty) cc1 cc2 consequent alternative) + (cmove_or ty cc1 cc2 consequent alternative)) + +(rule (cmove_or_from_values (is_xmm_type ty) cc1 cc2 consequent alternative) + (cmove_or_xmm ty cc1 cc2 consequent alternative)) + +;; Helper for creating `MInst.Setcc` instructions. +(decl x64_setcc (CC) ConsumesFlags) +(rule (x64_setcc cc) + (let ((dst WritableGpr (temp_writable_gpr))) + (ConsumesFlags.ConsumesFlagsReturnsReg + (MInst.Setcc cc dst) + dst))) + +;; Helper for creating `MInst.Setcc` instructions, when the flags producer will +;; also return a value. +(decl x64_setcc_paired (CC) ConsumesFlags) +(rule (x64_setcc_paired cc) + (let ((dst WritableGpr (temp_writable_gpr))) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer + (MInst.Setcc cc dst) + dst))) + +;; Helper for creating `paddb` instructions. +(decl x64_paddb (Xmm XmmMem) Xmm) +(rule 0 (x64_paddb src1 src2) + (xmm_rm_r (SseOpcode.Paddb) src1 src2)) +(rule 1 (x64_paddb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddb) src1 src2)) + +;; Helper for creating `paddw` instructions. +(decl x64_paddw (Xmm XmmMem) Xmm) +(rule 0 (x64_paddw src1 src2) + (xmm_rm_r (SseOpcode.Paddw) src1 src2)) +(rule 1 (x64_paddw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddw) src1 src2)) + +;; Helper for creating `paddd` instructions. +(decl x64_paddd (Xmm XmmMem) Xmm) +(rule 0 (x64_paddd src1 src2) + (xmm_rm_r (SseOpcode.Paddd) src1 src2)) +(rule 1 (x64_paddd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddd) src1 src2)) + +;; Helper for creating `paddq` instructions. +(decl x64_paddq (Xmm XmmMem) Xmm) +(rule 0 (x64_paddq src1 src2) + (xmm_rm_r (SseOpcode.Paddq) src1 src2)) +(rule 1 (x64_paddq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddq) src1 src2)) + +;; Helper for creating `paddsb` instructions. +(decl x64_paddsb (Xmm XmmMem) Xmm) +(rule 0 (x64_paddsb src1 src2) + (xmm_rm_r (SseOpcode.Paddsb) src1 src2)) +(rule 1 (x64_paddsb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddsb) src1 src2)) + +;; Helper for creating `paddsw` instructions. +(decl x64_paddsw (Xmm XmmMem) Xmm) +(rule 0 (x64_paddsw src1 src2) + (xmm_rm_r (SseOpcode.Paddsw) src1 src2)) +(rule 1 (x64_paddsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddsw) src1 src2)) + +;; Helper for creating `phaddw` instructions. +(decl x64_phaddw (Xmm XmmMem) Xmm) +(rule 0 (x64_phaddw src1 src2) + (xmm_rm_r (SseOpcode.Phaddw) src1 src2)) +(rule 1 (x64_phaddw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vphaddw) src1 src2)) + +;; Helper for creating `phaddd` instructions. +(decl x64_phaddd (Xmm XmmMem) Xmm) +(rule 0 (x64_phaddd src1 src2) + (xmm_rm_r (SseOpcode.Phaddd) src1 src2)) +(rule 1 (x64_phaddd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vphaddd) src1 src2)) + +;; Helper for creating `paddusb` instructions. +(decl x64_paddusb (Xmm XmmMem) Xmm) +(rule 0 (x64_paddusb src1 src2) + (xmm_rm_r (SseOpcode.Paddusb) src1 src2)) +(rule 1 (x64_paddusb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddusb) src1 src2)) + +;; Helper for creating `paddusw` instructions. +(decl x64_paddusw (Xmm XmmMem) Xmm) +(rule 0 (x64_paddusw src1 src2) + (xmm_rm_r (SseOpcode.Paddusw) src1 src2)) +(rule 1 (x64_paddusw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpaddusw) src1 src2)) + +;; Helper for creating `psubb` instructions. +(decl x64_psubb (Xmm XmmMem) Xmm) +(rule 0 (x64_psubb src1 src2) + (xmm_rm_r (SseOpcode.Psubb) src1 src2)) +(rule 1 (x64_psubb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubb) src1 src2)) + +;; Helper for creating `psubw` instructions. +(decl x64_psubw (Xmm XmmMem) Xmm) +(rule 0 (x64_psubw src1 src2) + (xmm_rm_r (SseOpcode.Psubw) src1 src2)) +(rule 1 (x64_psubw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubw) src1 src2)) + +;; Helper for creating `psubd` instructions. +(decl x64_psubd (Xmm XmmMem) Xmm) +(rule 0 (x64_psubd src1 src2) + (xmm_rm_r (SseOpcode.Psubd) src1 src2)) +(rule 1 (x64_psubd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubd) src1 src2)) + +;; Helper for creating `psubq` instructions. +(decl x64_psubq (Xmm XmmMem) Xmm) +(rule 0 (x64_psubq src1 src2) + (xmm_rm_r (SseOpcode.Psubq) src1 src2)) +(rule 1 (x64_psubq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubq) src1 src2)) + +;; Helper for creating `psubsb` instructions. +(decl x64_psubsb (Xmm XmmMem) Xmm) +(rule 0 (x64_psubsb src1 src2) + (xmm_rm_r (SseOpcode.Psubsb) src1 src2)) +(rule 1 (x64_psubsb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubsb) src1 src2)) + +;; Helper for creating `psubsw` instructions. +(decl x64_psubsw (Xmm XmmMem) Xmm) +(rule 0 (x64_psubsw src1 src2) + (xmm_rm_r (SseOpcode.Psubsw) src1 src2)) +(rule 1 (x64_psubsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubsw) src1 src2)) + +;; Helper for creating `psubusb` instructions. +(decl x64_psubusb (Xmm XmmMem) Xmm) +(rule 0 (x64_psubusb src1 src2) + (xmm_rm_r (SseOpcode.Psubusb) src1 src2)) +(rule 1 (x64_psubusb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubusb) src1 src2)) + +;; Helper for creating `psubusw` instructions. +(decl x64_psubusw (Xmm XmmMem) Xmm) +(rule 0 (x64_psubusw src1 src2) + (xmm_rm_r (SseOpcode.Psubusw) src1 src2)) +(rule 1 (x64_psubusw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsubusw) src1 src2)) + +;; Helper for creating `pavgb` instructions. +(decl x64_pavgb (Xmm XmmMem) Xmm) +(rule 0 (x64_pavgb src1 src2) + (xmm_rm_r (SseOpcode.Pavgb) src1 src2)) +(rule 1 (x64_pavgb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpavgb) src1 src2)) + +;; Helper for creating `pavgw` instructions. +(decl x64_pavgw (Xmm XmmMem) Xmm) +(rule 0 (x64_pavgw src1 src2) + (xmm_rm_r (SseOpcode.Pavgw) src1 src2)) +(rule 1 (x64_pavgw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpavgw) src1 src2)) + +;; Helper for creating `pand` instructions. +(decl x64_pand (Xmm XmmMem) Xmm) +(rule 0 (x64_pand src1 src2) + (xmm_rm_r (SseOpcode.Pand) src1 src2)) +(rule 1 (x64_pand src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpand) src1 src2)) + +;; Helper for creating `andps` instructions. +(decl x64_andps (Xmm XmmMem) Xmm) +(rule 0 (x64_andps src1 src2) + (xmm_rm_r (SseOpcode.Andps) src1 src2)) +(rule 1 (x64_andps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vandps) src1 src2)) + +;; Helper for creating `andpd` instructions. +(decl x64_andpd (Xmm XmmMem) Xmm) +(rule 0 (x64_andpd src1 src2) + (xmm_rm_r (SseOpcode.Andpd) src1 src2)) +(rule 1 (x64_andpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vandpd) src1 src2)) + +;; Helper for creating `por` instructions. +(decl x64_por (Xmm XmmMem) Xmm) +(rule 0 (x64_por src1 src2) + (xmm_rm_r (SseOpcode.Por) src1 src2)) +(rule 1 (x64_por src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpor) src1 src2)) + +;; Helper for creating `orps` instructions. +(decl x64_orps (Xmm XmmMem) Xmm) +(rule 0 (x64_orps src1 src2) + (xmm_rm_r (SseOpcode.Orps) src1 src2)) +(rule 1 (x64_orps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vorps) src1 src2)) + +;; Helper for creating `orpd` instructions. +(decl x64_orpd (Xmm XmmMem) Xmm) +(rule 0 (x64_orpd src1 src2) + (xmm_rm_r (SseOpcode.Orpd) src1 src2)) +(rule 1 (x64_orpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vorpd) src1 src2)) + +;; Helper fxor creating `pxor` instructions. +(decl x64_pxor (Xmm XmmMem) Xmm) +(rule 0 (x64_pxor src1 src2) + (xmm_rm_r (SseOpcode.Pxor) src1 src2)) +(rule 1 (x64_pxor src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpxor) src1 src2)) + +;; Helper fxor creating `xorps` instructions. +(decl x64_xorps (Xmm XmmMem) Xmm) +(rule 0 (x64_xorps src1 src2) + (xmm_rm_r (SseOpcode.Xorps) src1 src2)) +(rule 1 (x64_xorps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vxorps) src1 src2)) + +;; Helper fxor creating `xorpd` instructions. +(decl x64_xorpd (Xmm XmmMem) Xmm) +(rule 0 (x64_xorpd src1 src2) + (xmm_rm_r (SseOpcode.Xorpd) src1 src2)) +(rule 1 (x64_xorpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vxorpd) src1 src2)) + +;; Helper for creating `pmullw` instructions. +(decl x64_pmullw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmullw src1 src2) + (xmm_rm_r (SseOpcode.Pmullw) src1 src2)) +(rule 1 (x64_pmullw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmullw) src1 src2)) + +;; Helper for creating `pmulld` instructions. +(decl x64_pmulld (Xmm XmmMem) Xmm) +(rule 0 (x64_pmulld src1 src2) + (xmm_rm_r (SseOpcode.Pmulld) src1 src2)) +(rule 1 (x64_pmulld src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmulld) src1 src2)) + +;; Helper for creating `pmulhw` instructions. +(decl x64_pmulhw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmulhw src1 src2) + (xmm_rm_r (SseOpcode.Pmulhw) src1 src2)) +(rule 1 (x64_pmulhw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmulhw) src1 src2)) + +;; Helper for creating `pmulhrsw` instructions. +(decl x64_pmulhrsw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmulhrsw src1 src2) + (xmm_rm_r (SseOpcode.Pmulhrsw) src1 src2)) +(rule 1 (x64_pmulhrsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmulhrsw) src1 src2)) + +;; Helper for creating `pmulhuw` instructions. +(decl x64_pmulhuw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmulhuw src1 src2) + (xmm_rm_r (SseOpcode.Pmulhuw) src1 src2)) +(rule 1 (x64_pmulhuw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmulhuw) src1 src2)) + +;; Helper for creating `pmuldq` instructions. +(decl x64_pmuldq (Xmm XmmMem) Xmm) +(rule 0 (x64_pmuldq src1 src2) + (xmm_rm_r (SseOpcode.Pmuldq) src1 src2)) +(rule 1 (x64_pmuldq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmuldq) src1 src2)) + +;; Helper for creating `pmuludq` instructions. +(decl x64_pmuludq (Xmm XmmMem) Xmm) +(rule 0 (x64_pmuludq src1 src2) + (xmm_rm_r (SseOpcode.Pmuludq) src1 src2)) +(rule 1 (x64_pmuludq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmuludq) src1 src2)) + +;; Helper for creating `punpckhwd` instructions. +(decl x64_punpckhwd (Xmm XmmMem) Xmm) +(rule 0 (x64_punpckhwd src1 src2) + (xmm_rm_r (SseOpcode.Punpckhwd) src1 src2)) +(rule 1 (x64_punpckhwd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpckhwd) src1 src2)) + +;; Helper for creating `punpcklwd` instructions. +(decl x64_punpcklwd (Xmm XmmMem) Xmm) +(rule 0 (x64_punpcklwd src1 src2) + (xmm_rm_r (SseOpcode.Punpcklwd) src1 src2)) +(rule 1 (x64_punpcklwd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpcklwd) src1 src2)) + +;; Helper for creating `punpckldq` instructions. +(decl x64_punpckldq (Xmm XmmMem) Xmm) +(rule 0 (x64_punpckldq src1 src2) + (xmm_rm_r (SseOpcode.Punpckldq) src1 src2)) +(rule 1 (x64_punpckldq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpckldq) src1 src2)) + +;; Helper for creating `punpckhdq` instructions. +(decl x64_punpckhdq (Xmm XmmMem) Xmm) +(rule 0 (x64_punpckhdq src1 src2) + (xmm_rm_r (SseOpcode.Punpckhdq) src1 src2)) +(rule 1 (x64_punpckhdq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpckhdq) src1 src2)) + +;; Helper for creating `punpcklqdq` instructions. +(decl x64_punpcklqdq (Xmm XmmMem) Xmm) +(rule 0 (x64_punpcklqdq src1 src2) + (xmm_rm_r (SseOpcode.Punpcklqdq) src1 src2)) +(rule 1 (x64_punpcklqdq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpcklqdq) src1 src2)) + +;; Helper for creating `punpckhqdq` instructions. +(decl x64_punpckhqdq (Xmm XmmMem) Xmm) +(rule 0 (x64_punpckhqdq src1 src2) + (xmm_rm_r (SseOpcode.Punpckhqdq) src1 src2)) +(rule 1 (x64_punpckhqdq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpckhqdq) src1 src2)) + +;; Helper for creating `unpcklps` instructions. +(decl x64_unpcklps (Xmm XmmMem) Xmm) +(rule 0 (x64_unpcklps src1 src2) + (xmm_rm_r (SseOpcode.Unpcklps) src1 src2)) +(rule 1 (x64_unpcklps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vunpcklps) src1 src2)) + +;; Helper for creating `unpcklpd` instructions. +(decl x64_unpcklpd (Xmm XmmMem) Xmm) +(rule 0 (x64_unpcklpd src1 src2) + (xmm_rm_r (SseOpcode.Unpcklpd) src1 src2)) +(rule 1 (x64_unpcklpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vunpcklpd) src1 src2)) + +;; Helper for creating `unpckhps` instructions. +(decl x64_unpckhps (Xmm XmmMem) Xmm) +(rule 0 (x64_unpckhps src1 src2) + (xmm_rm_r (SseOpcode.Unpckhps) src1 src2)) +(rule 1 (x64_unpckhps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vunpckhps) src1 src2)) + +;; Helper for creating `andnps` instructions. +(decl x64_andnps (Xmm XmmMem) Xmm) +(rule 0 (x64_andnps src1 src2) + (xmm_rm_r (SseOpcode.Andnps) src1 src2)) +(rule 1 (x64_andnps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vandnps) src1 src2)) + +;; Helper for creating `andnpd` instructions. +(decl x64_andnpd (Xmm XmmMem) Xmm) +(rule 0 (x64_andnpd src1 src2) + (xmm_rm_r (SseOpcode.Andnpd) src1 src2)) +(rule 1 (x64_andnpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vandnpd) src1 src2)) + +;; Helper for creating `pandn` instructions. +(decl x64_pandn (Xmm XmmMem) Xmm) +(rule 0 (x64_pandn src1 src2) + (xmm_rm_r (SseOpcode.Pandn) src1 src2)) +(rule 1 (x64_pandn src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpandn) src1 src2)) + +;; Helper for creating `addss` instructions. +(decl x64_addss (Xmm XmmMem) Xmm) +(rule (x64_addss src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Addss) src1 src2)) +(rule 1 (x64_addss src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vaddss) src1 src2)) + +;; Helper for creating `addsd` instructions. +(decl x64_addsd (Xmm XmmMem) Xmm) +(rule (x64_addsd src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Addsd) src1 src2)) +(rule 1 (x64_addsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vaddsd) src1 src2)) + +;; Helper for creating `addps` instructions. +(decl x64_addps (Xmm XmmMem) Xmm) +(rule 0 (x64_addps src1 src2) + (xmm_rm_r (SseOpcode.Addps) src1 src2)) +(rule 1 (x64_addps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vaddps) src1 src2)) + +;; Helper for creating `addpd` instructions. +(decl x64_addpd (Xmm XmmMem) Xmm) +(rule 0 (x64_addpd src1 src2) + (xmm_rm_r (SseOpcode.Addpd) src1 src2)) +(rule 1 (x64_addpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vaddpd) src1 src2)) + +;; Helper for creating `subss` instructions. +(decl x64_subss (Xmm XmmMem) Xmm) +(rule (x64_subss src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Subss) src1 src2)) +(rule 1 (x64_subss src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsubss) src1 src2)) + +;; Helper for creating `subsd` instructions. +(decl x64_subsd (Xmm XmmMem) Xmm) +(rule (x64_subsd src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Subsd) src1 src2)) +(rule 1 (x64_subsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsubsd) src1 src2)) + +;; Helper for creating `subps` instructions. +(decl x64_subps (Xmm XmmMem) Xmm) +(rule 0 (x64_subps src1 src2) + (xmm_rm_r (SseOpcode.Subps) src1 src2)) +(rule 1 (x64_subps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsubps) src1 src2)) + +;; Helper for creating `subpd` instructions. +(decl x64_subpd (Xmm XmmMem) Xmm) +(rule 0 (x64_subpd src1 src2) + (xmm_rm_r (SseOpcode.Subpd) src1 src2)) +(rule 1 (x64_subpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsubpd) src1 src2)) + +;; Helper for creating `mulss` instructions. +(decl x64_mulss (Xmm XmmMem) Xmm) +(rule (x64_mulss src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Mulss) src1 src2)) +(rule 1 (x64_mulss src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmulss) src1 src2)) + +;; Helper for creating `mulsd` instructions. +(decl x64_mulsd (Xmm XmmMem) Xmm) +(rule (x64_mulsd src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Mulsd) src1 src2)) +(rule 1 (x64_mulsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmulsd) src1 src2)) + +;; Helper for creating `mulps` instructions. +(decl x64_mulps (Xmm XmmMem) Xmm) +(rule 0 (x64_mulps src1 src2) + (xmm_rm_r (SseOpcode.Mulps) src1 src2)) +(rule 1 (x64_mulps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmulps) src1 src2)) + +;; Helper for creating `mulpd` instructions. +(decl x64_mulpd (Xmm XmmMem) Xmm) +(rule (x64_mulpd src1 src2) + (xmm_rm_r (SseOpcode.Mulpd) src1 src2)) +(rule 1 (x64_mulpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmulpd) src1 src2)) + +;; Helper for creating `divss` instructions. +(decl x64_divss (Xmm XmmMem) Xmm) +(rule (x64_divss src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Divss) src1 src2)) +(rule 1 (x64_divss src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vdivss) src1 src2)) + +;; Helper for creating `divsd` instructions. +(decl x64_divsd (Xmm XmmMem) Xmm) +(rule (x64_divsd src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Divsd) src1 src2)) +(rule 1 (x64_divsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vdivsd) src1 src2)) + +;; Helper for creating `divps` instructions. +(decl x64_divps (Xmm XmmMem) Xmm) +(rule 0 (x64_divps src1 src2) + (xmm_rm_r (SseOpcode.Divps) src1 src2)) +(rule 1 (x64_divps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vdivps) src1 src2)) + +;; Helper for creating `divpd` instructions. +(decl x64_divpd (Xmm XmmMem) Xmm) +(rule 0 (x64_divpd src1 src2) + (xmm_rm_r (SseOpcode.Divpd) src1 src2)) +(rule 1 (x64_divpd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vdivpd) src1 src2)) + +;; Helper for creating `blendvpd` instructions. +(decl x64_blendvpd (Xmm XmmMem Xmm) Xmm) +(rule 0 (x64_blendvpd src1 src2 mask) + (xmm_rm_r_blend (SseOpcode.Blendvpd) src1 src2 mask)) +(rule 1 (x64_blendvpd src1 src2 mask) + (if-let true (use_avx)) + (xmm_rmr_blend_vex (AvxOpcode.Vblendvpd) src1 src2 mask)) + +;; Helper for creating `blendvps` instructions. +(decl x64_blendvps (Xmm XmmMem Xmm) Xmm) +(rule 0 (x64_blendvps src1 src2 mask) + (xmm_rm_r_blend (SseOpcode.Blendvps) src1 src2 mask)) +(rule 1 (x64_blendvps src1 src2 mask) + (if-let true (use_avx)) + (xmm_rmr_blend_vex (AvxOpcode.Vblendvps) src1 src2 mask)) + +;; Helper for creating `pblendvb` instructions. +(decl x64_pblendvb (Xmm XmmMem Xmm) Xmm) +(rule 0 (x64_pblendvb src1 src2 mask) + (xmm_rm_r_blend (SseOpcode.Pblendvb) src1 src2 mask)) +(rule 1 (x64_pblendvb src1 src2 mask) + (if-let true (use_avx)) + (xmm_rmr_blend_vex (AvxOpcode.Vpblendvb) src1 src2 mask)) + +;; Helper for creating `pblendw` instructions. +(decl x64_pblendw (Xmm XmmMem u8) Xmm) +(rule 0 (x64_pblendw src1 src2 imm) + (xmm_rm_r_imm (SseOpcode.Pblendw) src1 src2 imm (OperandSize.Size32))) +(rule 1 (x64_pblendw src1 src2 imm) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vpblendw) src1 src2 imm)) + +;; Helper for creating `movsd`/`movss` instructions which create a new vector +;; register where the upper bits are from the first operand and the low +;; bits are from the second operand. +;; +;; Note that the second argument here is specifically `Xmm` instead of `XmmMem` +;; because there is no encoding of a 3-operand form of `movsd` and otherwise +;; when used as a load instruction it wipes out the entire destination register +;; which defeats the purpose of this being a 2-operand instruction. +(decl x64_movsd_regmove (Xmm Xmm) Xmm) +(rule (x64_movsd_regmove src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Movsd) src1 src2)) +(rule 1 (x64_movsd_regmove src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmovsd) src1 src2)) + +(decl x64_movss_regmove (Xmm Xmm) Xmm) +(rule (x64_movss_regmove src1 src2) + (xmm_rm_r_unaligned (SseOpcode.Movss) src1 src2)) +(rule 1 (x64_movss_regmove src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmovss) src1 src2)) + +;; Helper for creating `movlhps` instructions. +(decl x64_movlhps (Xmm XmmMem) Xmm) +(rule 0 (x64_movlhps src1 src2) + (xmm_rm_r (SseOpcode.Movlhps) src1 src2)) +(rule 1 (x64_movlhps src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmovlhps) src1 src2)) + +;; Helpers for creating `pmaxs*` instructions. +(decl x64_pmaxs (Type Xmm XmmMem) Xmm) +(rule (x64_pmaxs $I8X16 x y) (x64_pmaxsb x y)) +(rule (x64_pmaxs $I16X8 x y) (x64_pmaxsw x y)) +(rule (x64_pmaxs $I32X4 x y) (x64_pmaxsd x y)) +;; No $I64X2 version (PMAXSQ) in SSE4.1. +(decl x64_pmaxsb (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxsb src1 src2) (xmm_rm_r (SseOpcode.Pmaxsb) src1 src2)) +(rule 1 (x64_pmaxsb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxsb) src1 src2)) +(decl x64_pmaxsw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxsw src1 src2) (xmm_rm_r (SseOpcode.Pmaxsw) src1 src2)) +(rule 1 (x64_pmaxsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxsw) src1 src2)) +(decl x64_pmaxsd (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxsd src1 src2) (xmm_rm_r (SseOpcode.Pmaxsd) src1 src2)) +(rule 1 (x64_pmaxsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxsd) src1 src2)) + +;; Helpers for creating `pmins*` instructions. +(decl x64_pmins (Type Xmm XmmMem) Xmm) +(rule (x64_pmins $I8X16 x y) (x64_pminsb x y)) +(rule (x64_pmins $I16X8 x y) (x64_pminsw x y)) +(rule (x64_pmins $I32X4 x y) (x64_pminsd x y)) +;; No $I64X2 version (PMINSQ) in SSE4.1. +(decl x64_pminsb (Xmm XmmMem) Xmm) +(rule 0 (x64_pminsb src1 src2) (xmm_rm_r (SseOpcode.Pminsb) src1 src2)) +(rule 1 (x64_pminsb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminsb) src1 src2)) +(decl x64_pminsw (Xmm XmmMem) Xmm) +(rule 0 (x64_pminsw src1 src2) (xmm_rm_r (SseOpcode.Pminsw) src1 src2)) +(rule 1 (x64_pminsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminsw) src1 src2)) +(decl x64_pminsd (Xmm XmmMem) Xmm) +(rule 0 (x64_pminsd src1 src2) (xmm_rm_r (SseOpcode.Pminsd) src1 src2)) +(rule 1 (x64_pminsd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminsd) src1 src2)) + +;; Helpers for creating `pmaxu*` instructions. +(decl x64_pmaxu (Type Xmm XmmMem) Xmm) +(rule (x64_pmaxu $I8X16 x y) (x64_pmaxub x y)) +(rule (x64_pmaxu $I16X8 x y) (x64_pmaxuw x y)) +(rule (x64_pmaxu $I32X4 x y) (x64_pmaxud x y)) +;; No $I64X2 version (PMAXUQ) in SSE4.1. +(decl x64_pmaxub (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxub src1 src2) (xmm_rm_r (SseOpcode.Pmaxub) src1 src2)) +(rule 1 (x64_pmaxub src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxub) src1 src2)) +(decl x64_pmaxuw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxuw src1 src2) (xmm_rm_r (SseOpcode.Pmaxuw) src1 src2)) +(rule 1 (x64_pmaxuw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxuw) src1 src2)) +(decl x64_pmaxud (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaxud src1 src2) (xmm_rm_r (SseOpcode.Pmaxud) src1 src2)) +(rule 1 (x64_pmaxud src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaxud) src1 src2)) + +;; Helper for creating `pminu*` instructions. +(decl x64_pminu (Type Xmm XmmMem) Xmm) +(rule (x64_pminu $I8X16 x y) (x64_pminub x y)) +(rule (x64_pminu $I16X8 x y) (x64_pminuw x y)) +(rule (x64_pminu $I32X4 x y) (x64_pminud x y)) +;; No $I64X2 version (PMINUQ) in SSE4.1. +(decl x64_pminub (Xmm XmmMem) Xmm) +(rule 0 (x64_pminub src1 src2) (xmm_rm_r (SseOpcode.Pminub) src1 src2)) +(rule 1 (x64_pminub src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminub) src1 src2)) +(decl x64_pminuw (Xmm XmmMem) Xmm) +(rule 0 (x64_pminuw src1 src2) (xmm_rm_r (SseOpcode.Pminuw) src1 src2)) +(rule 1 (x64_pminuw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminuw) src1 src2)) +(decl x64_pminud (Xmm XmmMem) Xmm) +(rule 0 (x64_pminud src1 src2) (xmm_rm_r (SseOpcode.Pminud) src1 src2)) +(rule 1 (x64_pminud src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpminud) src1 src2)) + +;; Helper for creating `punpcklbw` instructions. +(decl x64_punpcklbw (Xmm XmmMem) Xmm) +(rule 0 (x64_punpcklbw src1 src2) + (xmm_rm_r (SseOpcode.Punpcklbw) src1 src2)) +(rule 1 (x64_punpcklbw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpcklbw) src1 src2)) + +;; Helper for creating `punpckhbw` instructions. +(decl x64_punpckhbw (Xmm XmmMem) Xmm) +(rule 0 (x64_punpckhbw src1 src2) + (xmm_rm_r (SseOpcode.Punpckhbw) src1 src2)) +(rule 1 (x64_punpckhbw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpunpckhbw) src1 src2)) + +;; Helper for creating `packsswb` instructions. +(decl x64_packsswb (Xmm XmmMem) Xmm) +(rule 0 (x64_packsswb src1 src2) + (xmm_rm_r (SseOpcode.Packsswb) src1 src2)) +(rule 1 (x64_packsswb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpacksswb) src1 src2)) + +;; Helper for creating `packssdw` instructions. +(decl x64_packssdw (Xmm XmmMem) Xmm) +(rule 0 (x64_packssdw src1 src2) + (xmm_rm_r (SseOpcode.Packssdw) src1 src2)) +(rule 1 (x64_packssdw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpackssdw) src1 src2)) + +;; Helper for creating `packuswb` instructions. +(decl x64_packuswb (Xmm XmmMem) Xmm) +(rule 0 (x64_packuswb src1 src2) + (xmm_rm_r (SseOpcode.Packuswb) src1 src2)) +(rule 1 (x64_packuswb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpackuswb) src1 src2)) + +;; Helper for creating `packusdw` instructions. +(decl x64_packusdw (Xmm XmmMem) Xmm) +(rule 0 (x64_packusdw src1 src2) + (xmm_rm_r (SseOpcode.Packusdw) src1 src2)) +(rule 1 (x64_packusdw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpackusdw) src1 src2)) + +;; Helper for creating `palignr` instructions. +(decl x64_palignr (Xmm XmmMem u8) Xmm) +(rule 0 (x64_palignr src1 src2 imm) + (xmm_rm_r_imm (SseOpcode.Palignr) + src1 + src2 + imm + (OperandSize.Size32))) +(rule 1 (x64_palignr src1 src2 imm) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vpalignr) src1 src2 imm)) + +;; Helpers for creating `cmpp*` instructions. +(decl x64_cmpp (Type Xmm XmmMem FcmpImm) Xmm) +(rule (x64_cmpp $F32X4 x y imm) (x64_cmpps x y imm)) +(rule (x64_cmpp $F64X2 x y imm) (x64_cmppd x y imm)) + +(decl x64_cmpps (Xmm XmmMem FcmpImm) Xmm) +(rule 0 (x64_cmpps src1 src2 imm) + (xmm_rm_r_imm (SseOpcode.Cmpps) + src1 + src2 + (encode_fcmp_imm imm) + (OperandSize.Size32))) +(rule 1 (x64_cmpps src1 src2 imm) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vcmpps) + src1 + src2 + (encode_fcmp_imm imm))) + +;; Note that `Size32` is intentional despite this being used for 64-bit +;; operations, since this presumably induces the correct encoding of the +;; instruction. +(decl x64_cmppd (Xmm XmmMem FcmpImm) Xmm) +(rule 0 (x64_cmppd src1 src2 imm) + (xmm_rm_r_imm (SseOpcode.Cmppd) + src1 + src2 + (encode_fcmp_imm imm) + (OperandSize.Size32))) +(rule 1 (x64_cmppd src1 src2 imm) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vcmppd) + src1 + src2 + (encode_fcmp_imm imm))) + +;; Helper for creating `pinsrb` instructions. +(decl x64_pinsrb (Xmm GprMem u8) Xmm) +(rule 0 (x64_pinsrb src1 src2 lane) + (xmm_rm_r_imm (SseOpcode.Pinsrb) + src1 + src2 + lane + (OperandSize.Size32))) +(rule 1 (x64_pinsrb src1 src2 lane) + (if-let true (use_avx)) + (xmm_vex_pinsr (AvxOpcode.Vpinsrb) src1 src2 lane)) + +;; Helper for creating `pinsrw` instructions. +(decl x64_pinsrw (Xmm GprMem u8) Xmm) +(rule 0 (x64_pinsrw src1 src2 lane) + (xmm_rm_r_imm (SseOpcode.Pinsrw) + src1 + src2 + lane + (OperandSize.Size32))) +(rule 1 (x64_pinsrw src1 src2 lane) + (if-let true (use_avx)) + (xmm_vex_pinsr (AvxOpcode.Vpinsrw) src1 src2 lane)) + +;; Helper for creating `pinsrd` instructions. +(decl x64_pinsrd (Xmm GprMem u8) Xmm) +(rule 0 (x64_pinsrd src1 src2 lane) + (xmm_rm_r_imm (SseOpcode.Pinsrd) + src1 + src2 + lane + (OperandSize.Size32))) +(rule 1 (x64_pinsrd src1 src2 lane) + (if-let true (use_avx)) + (xmm_vex_pinsr (AvxOpcode.Vpinsrd) src1 src2 lane)) + +;; Helper for creating `pinsrq` instructions. +(decl x64_pinsrq (Xmm GprMem u8) Xmm) +(rule (x64_pinsrq src1 src2 lane) + (xmm_rm_r_imm (SseOpcode.Pinsrd) + src1 + src2 + lane + (OperandSize.Size64))) +(rule 1 (x64_pinsrq src1 src2 lane) + (if-let true (use_avx)) + (xmm_vex_pinsr (AvxOpcode.Vpinsrq) src1 src2 lane)) + +;; Helper for creating `roundss` instructions. +;; +;; NB: the non-AVX variant of this instruction does not require that the operand +;; is aligned, but the instruction variant used here requires it to be aligned. +;; This means that if the operand here points to memory then we'll eagerly load +;; it, but the eager load will load too much (the full register width of 16 +;; bytes). To fix this a `put_xmm_mem_in_xmm` helper is used to force the +;; operand to be a register where the load is done with the appropriate type if +;; it's in memory. +;; +;; Some more discussion of this can be found on #8112. Ideally this would use +;; a variant that allows an unaligned `XmmMem` in the instruction variant. +;; Either that or the auto-conversion to aligned memory is removed and/or starts +;; to require a type. +;; +;; Also note that the argument here isn't changed to `Xmm` instead of `XmmMem` +;; because the AVX variant, when available, doesn't need alignment and can +;; pass through the `src1` argument as-is. +(decl x64_roundss (XmmMem RoundImm) Xmm) +(rule (x64_roundss src1 round) + (xmm_unary_rm_r_imm (SseOpcode.Roundss) (put_xmm_mem_in_xmm $F32 src1) (encode_round_imm round))) +(rule 1 (x64_roundss src1 round) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundss) src1 (encode_round_imm round))) + +;; Helper for creating `roundsd` instructions. +;; +;; NB: see `x64_roundss` above for `put_xmm_mem_in_xmm` in call. +(decl x64_roundsd (XmmMem RoundImm) Xmm) +(rule (x64_roundsd src1 round) + (xmm_unary_rm_r_imm (SseOpcode.Roundsd) (put_xmm_mem_in_xmm $F64 src1) (encode_round_imm round))) +(rule 1 (x64_roundsd src1 round) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundsd) src1 (encode_round_imm round))) + +;; Helper for forcing an `XmmMem` to be placed into an `Xmm` register. +;; +;; If it's already in a register it stays there, otherwise it turns into a +;; load instruction with the destination register as output. +(decl put_xmm_mem_in_xmm (Type XmmMem) Xmm) +(rule (put_xmm_mem_in_xmm ty xmm_mem) + (if-let (RegMem.Reg r) (xmm_mem_to_reg_mem xmm_mem)) + (xmm_new r)) +(rule (put_xmm_mem_in_xmm ty xmm_mem) + (if-let (RegMem.Mem amode) (xmm_mem_to_reg_mem xmm_mem)) + (x64_load ty amode (ExtKind.None))) + +;; Helper for creating `roundps` instructions. +(decl x64_roundps (XmmMem RoundImm) Xmm) +(rule (x64_roundps src1 round) + (xmm_unary_rm_r_imm (SseOpcode.Roundps) src1 (encode_round_imm round))) +(rule 1 (x64_roundps src1 round) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundps) src1 (encode_round_imm round))) + +;; Helper for creating `roundpd` instructions. +(decl x64_roundpd (XmmMem RoundImm) Xmm) +(rule (x64_roundpd src1 round) + (xmm_unary_rm_r_imm (SseOpcode.Roundpd) src1 (encode_round_imm round))) +(rule 1 (x64_roundpd src1 round) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vroundpd) src1 (encode_round_imm round))) + +;; Helper for creating `pmaddwd` instructions. +(decl x64_pmaddwd (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaddwd src1 src2) + (xmm_rm_r (SseOpcode.Pmaddwd) src1 src2)) +(rule 1 (x64_pmaddwd src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaddwd) src1 src2)) + +(decl x64_pmaddubsw (Xmm XmmMem) Xmm) +(rule 0 (x64_pmaddubsw src1 src2) + (xmm_rm_r (SseOpcode.Pmaddubsw) src1 src2)) +(rule 1 (x64_pmaddubsw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpmaddubsw) src1 src2)) + +;; Helper for creating `insertps` instructions. +(decl x64_insertps (Xmm XmmMem u8) Xmm) +(rule 0 (x64_insertps src1 src2 lane) + (xmm_rm_r_imm (SseOpcode.Insertps) + src1 + src2 + lane + (OperandSize.Size32))) +(rule 1 (x64_insertps src1 src2 lane) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vinsertps) src1 src2 lane)) + +;; Helper for creating `pshufd` instructions. +(decl x64_pshufd (XmmMem u8) Xmm) +(rule (x64_pshufd src imm) + (xmm_unary_rm_r_imm (SseOpcode.Pshufd) src imm)) +(rule 1 (x64_pshufd src imm) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vpshufd) src imm)) + +;; Helper for creating `pshufb` instructions. +(decl x64_pshufb (Xmm XmmMem) Xmm) +(rule 0 (x64_pshufb src1 src2) + (xmm_rm_r (SseOpcode.Pshufb) src1 src2)) +(rule 1 (x64_pshufb src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpshufb) src1 src2)) + +;; Helper for creating `pshuflw` instructions. +(decl x64_pshuflw (XmmMem u8) Xmm) +(rule (x64_pshuflw src imm) + (xmm_unary_rm_r_imm (SseOpcode.Pshuflw) src imm)) +(rule 1 (x64_pshuflw src imm) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vpshuflw) src imm)) + +;; Helper for creating `pshufhw` instructions. +(decl x64_pshufhw (XmmMem u8) Xmm) +(rule (x64_pshufhw src imm) + (xmm_unary_rm_r_imm (SseOpcode.Pshufhw) src imm)) +(rule 1 (x64_pshufhw src imm) + (if-let true (use_avx)) + (xmm_unary_rm_r_imm_vex (AvxOpcode.Vpshufhw) src imm)) + +;; Helper for creating `shufps` instructions. +(decl x64_shufps (Xmm XmmMem u8) Xmm) +(rule 0 (x64_shufps src1 src2 byte) + (xmm_rm_r_imm (SseOpcode.Shufps) + src1 + src2 + byte + (OperandSize.Size32))) +(rule 1 (x64_shufps src1 src2 byte) + (if-let true (use_avx)) + (xmm_rmr_imm_vex (AvxOpcode.Vshufps) src1 src2 byte)) + +;; Helper for creating `pabsb` instructions. +(decl x64_pabsb (XmmMem) Xmm) +(rule (x64_pabsb src) + (xmm_unary_rm_r (SseOpcode.Pabsb) src)) +(rule 1 (x64_pabsb src) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpabsb) src)) + +;; Helper for creating `pabsw` instructions. +(decl x64_pabsw (XmmMem) Xmm) +(rule (x64_pabsw src) + (xmm_unary_rm_r (SseOpcode.Pabsw) src)) +(rule 1 (x64_pabsw src) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpabsw) src)) + +;; Helper for creating `pabsd` instructions. +(decl x64_pabsd (XmmMem) Xmm) +(rule (x64_pabsd src) + (xmm_unary_rm_r (SseOpcode.Pabsd) src)) +(rule 1 (x64_pabsd src) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vpabsd) src)) + +;; Helper for creating `vcvtudq2ps` instructions. +(decl x64_vcvtudq2ps (XmmMem) Xmm) +(rule (x64_vcvtudq2ps src) + (xmm_unary_rm_r_evex (Avx512Opcode.Vcvtudq2ps) src)) + +;; Helper for creating `vpabsq` instructions. +(decl x64_vpabsq (XmmMem) Xmm) +(rule (x64_vpabsq src) + (xmm_unary_rm_r_evex (Avx512Opcode.Vpabsq) src)) + +;; Helper for creating `vpopcntb` instructions. +(decl x64_vpopcntb (XmmMem) Xmm) +(rule (x64_vpopcntb src) + (xmm_unary_rm_r_evex (Avx512Opcode.Vpopcntb) src)) + +;; Helper for creating `vpmullq` instructions. +;; +;; Requires AVX-512 vl and dq. +(decl x64_vpmullq (Xmm XmmMem) Xmm) +(rule (x64_vpmullq src1 src2) + (xmm_rm_r_evex (Avx512Opcode.Vpmullq) + src1 + src2)) + +;; Helper for creating `vpermi2b` instructions. +;; +;; Requires AVX-512 vl and vbmi extensions. +(decl x64_vpermi2b (Xmm Xmm XmmMem) Xmm) +(rule (x64_vpermi2b src1 src2 src3) + (let ((dst WritableXmm (temp_writable_xmm)) + (_ Unit (emit (MInst.XmmRmREvex3 (Avx512Opcode.Vpermi2b) + src1 + src2 + src3 + dst)))) + dst)) + +;; Helper for creating `psllw` instructions. +(decl x64_psllw (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psllw src1 src2) + (xmm_rmi_xmm (SseOpcode.Psllw) src1 src2)) +(rule 1 (x64_psllw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsllw) src1 src2)) + +;; Helper for creating `pslld` instructions. +(decl x64_pslld (Xmm XmmMemImm) Xmm) +(rule 0 (x64_pslld src1 src2) + (xmm_rmi_xmm (SseOpcode.Pslld) src1 src2)) +(rule 1 (x64_pslld src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpslld) src1 src2)) + +;; Helper for creating `psllq` instructions. +(decl x64_psllq (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psllq src1 src2) + (xmm_rmi_xmm (SseOpcode.Psllq) src1 src2)) +(rule 1 (x64_psllq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsllq) src1 src2)) + +;; Helper for creating `psrlw` instructions. +(decl x64_psrlw (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psrlw src1 src2) + (xmm_rmi_xmm (SseOpcode.Psrlw) src1 src2)) +(rule 1 (x64_psrlw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsrlw) src1 src2)) + +;; Helper for creating `psrld` instructions. +(decl x64_psrld (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psrld src1 src2) + (xmm_rmi_xmm (SseOpcode.Psrld) src1 src2)) +(rule 1 (x64_psrld src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsrld) src1 src2)) + +;; Helper for creating `psrlq` instructions. +(decl x64_psrlq (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psrlq src1 src2) + (xmm_rmi_xmm (SseOpcode.Psrlq) src1 src2)) +(rule 1 (x64_psrlq src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsrlq) src1 src2)) + +;; Helper for creating `psraw` instructions. +(decl x64_psraw (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psraw src1 src2) + (xmm_rmi_xmm (SseOpcode.Psraw) src1 src2)) +(rule 1 (x64_psraw src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsraw) src1 src2)) + +;; Helper for creating `psrad` instructions. +(decl x64_psrad (Xmm XmmMemImm) Xmm) +(rule 0 (x64_psrad src1 src2) + (xmm_rmi_xmm (SseOpcode.Psrad) src1 src2)) +(rule 1 (x64_psrad src1 src2) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpsrad) src1 src2)) + +;; Helper for creating `vpsraq` instructions. +(decl x64_vpsraq (Xmm XmmMem) Xmm) +(rule (x64_vpsraq src1 src2) + (xmm_rm_r_evex (Avx512Opcode.Vpsraq) src1 src2)) + +;; Helper for creating `vpsraq` instructions. +(decl x64_vpsraq_imm (XmmMem u8) Xmm) +(rule (x64_vpsraq_imm src imm) + (xmm_unary_rm_r_imm_evex (Avx512Opcode.VpsraqImm) src imm)) + +;; Helper for creating `pextrb` instructions. +(decl x64_pextrb (Xmm u8) Gpr) +(rule (x64_pextrb src lane) + (xmm_to_gpr_imm (SseOpcode.Pextrb) src lane)) +(rule 1 (x64_pextrb src lane) + (if-let true (use_avx)) + (xmm_to_gpr_imm_vex (AvxOpcode.Vpextrb) src lane)) + +(decl x64_pextrb_store (SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (x64_pextrb_store addr src lane) + (xmm_movrm_imm (SseOpcode.Pextrb) addr src lane)) +(rule 1 (x64_pextrb_store addr src lane) + (if-let true (use_avx)) + (xmm_movrm_imm_vex (AvxOpcode.Vpextrb) addr src lane)) + +;; Helper for creating `pextrw` instructions. +(decl x64_pextrw (Xmm u8) Gpr) +(rule (x64_pextrw src lane) + (xmm_to_gpr_imm (SseOpcode.Pextrw) src lane)) +(rule 1 (x64_pextrw src lane) + (if-let true (use_avx)) + (xmm_to_gpr_imm_vex (AvxOpcode.Vpextrw) src lane)) + +(decl x64_pextrw_store (SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (x64_pextrw_store addr src lane) + (xmm_movrm_imm (SseOpcode.Pextrw) addr src lane)) +(rule 1 (x64_pextrw_store addr src lane) + (if-let true (use_avx)) + (xmm_movrm_imm_vex (AvxOpcode.Vpextrw) addr src lane)) + +;; Helper for creating `pextrd` instructions. +(decl x64_pextrd (Xmm u8) Gpr) +(rule (x64_pextrd src lane) + (xmm_to_gpr_imm (SseOpcode.Pextrd) src lane)) +(rule 1 (x64_pextrd src lane) + (if-let true (use_avx)) + (xmm_to_gpr_imm_vex (AvxOpcode.Vpextrd) src lane)) + +(decl x64_pextrd_store (SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (x64_pextrd_store addr src lane) + (xmm_movrm_imm (SseOpcode.Pextrd) addr src lane)) +(rule 1 (x64_pextrd_store addr src lane) + (if-let true (use_avx)) + (xmm_movrm_imm_vex (AvxOpcode.Vpextrd) addr src lane)) + +;; Helper for creating `pextrq` instructions. +(decl x64_pextrq (Xmm u8) Gpr) +(rule (x64_pextrq src lane) + (xmm_to_gpr_imm (SseOpcode.Pextrq) src lane)) +(rule 1 (x64_pextrq src lane) + (if-let true (use_avx)) + (xmm_to_gpr_imm_vex (AvxOpcode.Vpextrq) src lane)) + +(decl x64_pextrq_store (SyntheticAmode Xmm u8) SideEffectNoResult) +(rule (x64_pextrq_store addr src lane) + (xmm_movrm_imm (SseOpcode.Pextrq) addr src lane)) +(rule 1 (x64_pextrq_store addr src lane) + (if-let true (use_avx)) + (xmm_movrm_imm_vex (AvxOpcode.Vpextrq) addr src lane)) + +;; Helper for creating `pmovmskb` instructions. +(decl x64_pmovmskb (OperandSize Xmm) Gpr) +(rule (x64_pmovmskb size src) + (xmm_to_gpr (SseOpcode.Pmovmskb) src size)) +(rule 1 (x64_pmovmskb size src) + (if-let true (use_avx)) + (xmm_to_gpr_vex (AvxOpcode.Vpmovmskb) src size)) + +;; Helper for creating `movmskps` instructions. +(decl x64_movmskps (OperandSize Xmm) Gpr) +(rule (x64_movmskps size src) + (xmm_to_gpr (SseOpcode.Movmskps) src size)) +(rule 1 (x64_movmskps size src) + (if-let true (use_avx)) + (xmm_to_gpr_vex (AvxOpcode.Vmovmskps) src size)) + +;; Helper for creating `movmskpd` instructions. +(decl x64_movmskpd (OperandSize Xmm) Gpr) +(rule (x64_movmskpd size src) + (xmm_to_gpr (SseOpcode.Movmskpd) src size)) +(rule 1 (x64_movmskpd size src) + (if-let true (use_avx)) + (xmm_to_gpr_vex (AvxOpcode.Vmovmskpd) src size)) + +;; Helper for creating `not` instructions. +(decl x64_not (Type Gpr) Gpr) +(rule (x64_not ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (_ Unit (emit (MInst.Not size src dst)))) + dst)) + +;; Helper for creating `neg` instructions. +(decl x64_neg (Type Gpr) Gpr) +(rule (x64_neg ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (_ Unit (emit (MInst.Neg size src dst)))) + dst)) + +;; Helper for creating `neg` instructions whose flags are also used. +(decl x64_neg_paired (Type Gpr) ProducesFlags) +(rule (x64_neg_paired ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (raw_operand_size_of_type ty)) + (inst MInst (MInst.Neg size src dst))) + (ProducesFlags.ProducesFlagsReturnsResultWithConsumer inst dst))) + +(spec (x64_lea ty amode) + (provide (= result amode)) + (require (or (= ty 32) (= ty 64)))) +(decl x64_lea (Type SyntheticAmode) Gpr) +(rule (x64_lea ty addr) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.LoadEffectiveAddress addr dst (operand_size_of_type_32_64 ty))))) + dst)) + +;; Helper for creating `ud2` instructions. +(decl x64_ud2 (TrapCode) SideEffectNoResult) +(rule (x64_ud2 code) + (SideEffectNoResult.Inst (MInst.Ud2 code))) + +;; Helper for creating `hlt` instructions. +(decl x64_hlt () SideEffectNoResult) +(rule (x64_hlt) + (SideEffectNoResult.Inst (MInst.Hlt))) + +;; Helper for creating `lzcnt` instructions. +(decl x64_lzcnt (Type Gpr) Gpr) +(rule (x64_lzcnt ty src) + (unary_rm_r (UnaryRmROpcode.Lzcnt) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `tzcnt` instructions. +(decl x64_tzcnt (Type Gpr) Gpr) +(rule (x64_tzcnt ty src) + (unary_rm_r (UnaryRmROpcode.Tzcnt) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `bsr` instructions. +(decl x64_bsr (Type Gpr) ProducesFlags) +(rule (x64_bsr ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (inst MInst (MInst.UnaryRmR size (UnaryRmROpcode.Bsr) src dst))) + (ProducesFlags.ProducesFlagsReturnsReg inst dst))) + +;; Helper for creating `bsr + cmov` instruction pairs that produce the +;; result of the `bsr`, or `alt` if the input was zero. +(decl bsr_or_else (Type Gpr Gpr) Gpr) +(rule (bsr_or_else ty src alt) + (let ((bsr ProducesFlags (x64_bsr ty src)) + ;; Manually extract the result from the bsr, then ignore + ;; it below, since we need to thread it into the cmove + ;; before we pass the cmove to with_flags_reg. + (bsr_result Gpr (produces_flags_get_reg bsr)) + (cmove ConsumesFlags (cmove ty (CC.Z) alt bsr_result))) + (with_flags_reg (produces_flags_ignore bsr) cmove))) + +;; Helper for creating `bsf` instructions. +(decl x64_bsf (Type Gpr) ProducesFlags) +(rule (x64_bsf ty src) + (let ((dst WritableGpr (temp_writable_gpr)) + (size OperandSize (operand_size_of_type_32_64 ty)) + (inst MInst (MInst.UnaryRmR size (UnaryRmROpcode.Bsf) src dst))) + (ProducesFlags.ProducesFlagsReturnsReg inst dst))) + +;; Helper for creating `bsf + cmov` instruction pairs that produce the +;; result of the `bsf`, or `alt` if the input was zero. +(decl bsf_or_else (Type Gpr Gpr) Gpr) +(rule (bsf_or_else ty src alt) + (let ((bsf ProducesFlags (x64_bsf ty src)) + ;; Manually extract the result from the bsf, then ignore + ;; it below, since we need to thread it into the cmove + ;; before we pass the cmove to with_flags_reg. + (bsf_result Gpr (produces_flags_get_reg bsf)) + (cmove ConsumesFlags (cmove ty (CC.Z) alt bsf_result))) + (with_flags_reg (produces_flags_ignore bsf) cmove))) + +;; Helper for creating `blsi` instructions. +(decl x64_blsi (Type GprMem) Gpr) +(rule (x64_blsi ty src) + (unary_rm_r_vex (UnaryRmRVexOpcode.Blsi) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `blsmsk` instructions. +(decl x64_blsmsk (Type GprMem) Gpr) +(rule (x64_blsmsk ty src) + (unary_rm_r_vex (UnaryRmRVexOpcode.Blsmsk) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `blsr` instructions. +(decl x64_blsr (Type GprMem) Gpr) +(rule (x64_blsr ty src) + (unary_rm_r_vex (UnaryRmRVexOpcode.Blsr) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `sarx` instructions. +(decl x64_sarx (Type GprMem Gpr) Gpr) +(rule (x64_sarx ty val amt) + (alu_rm_r_vex ty (AluRmROpcode.Sarx) amt val)) + +;; Helper for creating `shrx` instructions. +(decl x64_shrx (Type GprMem Gpr) Gpr) +(rule (x64_shrx ty val amt) + (alu_rm_r_vex ty (AluRmROpcode.Shrx) amt val)) + +;; Helper for creating `shlx` instructions. +(decl x64_shlx (Type GprMem Gpr) Gpr) +(rule (x64_shlx ty val amt) + (alu_rm_r_vex ty (AluRmROpcode.Shlx) amt val)) + +;; Helper for creating `rorx` instructions. +(decl x64_rorx (Type GprMem u8) Gpr) +(rule (x64_rorx ty src imm) + (unary_rm_r_imm_vex (UnaryRmRImmVexOpcode.Rorx) + src + (operand_size_of_type_32_64 ty) + imm)) + +;; Helper for creating `popcnt` instructions. +(decl x64_popcnt (Type Gpr) Gpr) +(rule (x64_popcnt ty src) + (unary_rm_r (UnaryRmROpcode.Popcnt) src (operand_size_of_type_32_64 ty))) + +;; Helper for creating `minss` instructions. +(decl x64_minss (Xmm XmmMem) Xmm) +(rule (x64_minss x y) + (xmm_rm_r_unaligned (SseOpcode.Minss) x y)) +(rule 1 (x64_minss x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vminss) x y)) + +;; Helper for creating `minsd` instructions. +(decl x64_minsd (Xmm XmmMem) Xmm) +(rule (x64_minsd x y) + (xmm_rm_r_unaligned (SseOpcode.Minsd) x y)) +(rule 1 (x64_minsd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vminsd) x y)) + +;; Helper for creating `minps` instructions. +(decl x64_minps (Xmm XmmMem) Xmm) +(rule 0 (x64_minps x y) + (xmm_rm_r (SseOpcode.Minps) x y)) +(rule 1 (x64_minps x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vminps) x y)) + +;; Helper for creating `minpd` instructions. +(decl x64_minpd (Xmm XmmMem) Xmm) +(rule 0 (x64_minpd x y) + (xmm_rm_r (SseOpcode.Minpd) x y)) +(rule 1 (x64_minpd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vminpd) x y)) + +;; Helper for creating `maxss` instructions. +(decl x64_maxss (Xmm XmmMem) Xmm) +(rule (x64_maxss x y) + (xmm_rm_r_unaligned (SseOpcode.Maxss) x y)) +(rule 1 (x64_maxss x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmaxss) x y)) + +;; Helper for creating `maxsd` instructions. +(decl x64_maxsd (Xmm XmmMem) Xmm) +(rule (x64_maxsd x y) + (xmm_rm_r_unaligned (SseOpcode.Maxsd) x y)) +(rule 1 (x64_maxsd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmaxsd) x y)) + +;; Helper for creating `maxps` instructions. +(decl x64_maxps (Xmm XmmMem) Xmm) +(rule 0 (x64_maxps x y) + (xmm_rm_r (SseOpcode.Maxps) x y)) +(rule 1 (x64_maxps x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmaxps) x y)) + +;; Helper for creating `maxpd` instructions. +(decl x64_maxpd (Xmm XmmMem) Xmm) +(rule 0 (x64_maxpd x y) + (xmm_rm_r (SseOpcode.Maxpd) x y)) +(rule 1 (x64_maxpd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vmaxpd) x y)) + +;; Helper for creating `vfmadd213*` instructions +(decl x64_vfmadd213 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfmadd213 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd213ss) a b c)) +(rule (x64_vfmadd213 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd213sd) a b c)) +(rule (x64_vfmadd213 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd213ps) a b c)) +(rule (x64_vfmadd213 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd213pd) a b c)) + +;; Helper for creating `vfmadd132*` instructions +(decl x64_vfmadd132 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfmadd132 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd132ss) a b c)) +(rule (x64_vfmadd132 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd132sd) a b c)) +(rule (x64_vfmadd132 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd132ps) a b c)) +(rule (x64_vfmadd132 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmadd132pd) a b c)) + +;; Helper for creating `vfnmadd213*` instructions +(decl x64_vfnmadd213 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfnmadd213 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd213ss) a b c)) +(rule (x64_vfnmadd213 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd213sd) a b c)) +(rule (x64_vfnmadd213 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd213ps) a b c)) +(rule (x64_vfnmadd213 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd213pd) a b c)) + +;; Helper for creating `vfnmadd132*` instructions +(decl x64_vfnmadd132 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfnmadd132 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd132ss) a b c)) +(rule (x64_vfnmadd132 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd132sd) a b c)) +(rule (x64_vfnmadd132 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd132ps) a b c)) +(rule (x64_vfnmadd132 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmadd132pd) a b c)) + +;; Helper for creating `vfmsub213*` instructions +(decl x64_vfmsub213 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfmsub213 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub213ss) a b c)) +(rule (x64_vfmsub213 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub213sd) a b c)) +(rule (x64_vfmsub213 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub213ps) a b c)) +(rule (x64_vfmsub213 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub213pd) a b c)) + +;; Helper for creating `vfmsub132*` instructions +(decl x64_vfmsub132 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfmsub132 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub132ss) a b c)) +(rule (x64_vfmsub132 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub132sd) a b c)) +(rule (x64_vfmsub132 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub132ps) a b c)) +(rule (x64_vfmsub132 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfmsub132pd) a b c)) + +;; Helper for creating `vfnmsub213*` instructions +(decl x64_vfnmsub213 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfnmsub213 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub213ss) a b c)) +(rule (x64_vfnmsub213 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub213sd) a b c)) +(rule (x64_vfnmsub213 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub213ps) a b c)) +(rule (x64_vfnmsub213 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub213pd) a b c)) + +;; Helper for creating `vfnmsub132*` instructions +(decl x64_vfnmsub132 (Type Xmm Xmm XmmMem) Xmm) +(rule (x64_vfnmsub132 $F32 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub132ss) a b c)) +(rule (x64_vfnmsub132 $F64 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub132sd) a b c)) +(rule (x64_vfnmsub132 $F32X4 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub132ps) a b c)) +(rule (x64_vfnmsub132 $F64X2 a b c) (xmm_rmr_vex3 (AvxOpcode.Vfnmsub132pd) a b c)) + +;; Note, the `vfmsub231` and `vfnmsub231*` instructions are omitted, because +;; instruction selection happens before register allocation and therefore there +;; is no benefit to a a third permutation + +;; Helper for creating `sqrtss` instructions. +;; +;; NB: the square-root operation technically only has one operand but this +;; instruction has two. This is to reflect how the square root operation copies +;; the upper bits of the first register and only performs the square root +;; operation on the low bits of the second register. This introduces +;; a data-dependency on the contents of the first register which is modeled +;; here. +(decl x64_sqrtss (Xmm XmmMem) Xmm) +(rule (x64_sqrtss x y) (xmm_rm_r_unaligned (SseOpcode.Sqrtss) x y)) +(rule 1 (x64_sqrtss x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsqrtss) x y)) + +;; Helper for creating `sqrtsd` instructions. +;; +;; NB: see `x64_sqrtss` for explanation of why this has two args. +(decl x64_sqrtsd (Xmm XmmMem) Xmm) +(rule (x64_sqrtsd x y) (xmm_rm_r_unaligned (SseOpcode.Sqrtsd) x y)) +(rule 1 (x64_sqrtsd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vsqrtsd) x y)) + +;; Helper for creating `sqrtps` instructions. +(decl x64_sqrtps (XmmMem) Xmm) +(rule (x64_sqrtps x) (xmm_unary_rm_r (SseOpcode.Sqrtps) x)) +(rule 1 (x64_sqrtps x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtps) x)) + +;; Helper for creating `sqrtpd` instructions. +(decl x64_sqrtpd (XmmMem) Xmm) +(rule (x64_sqrtpd x) (xmm_unary_rm_r (SseOpcode.Sqrtpd) x)) +(rule 1 (x64_sqrtpd x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vsqrtpd) x)) + +;; Helper for creating `cvtss2sd` instructions. +;; +;; NB: see `x64_sqrtss` for why this has two args (same reasoning, different op) +(decl x64_cvtss2sd (Xmm XmmMem) Xmm) +(rule (x64_cvtss2sd x y) (xmm_rm_r_unaligned (SseOpcode.Cvtss2sd) x y)) +(rule 1 (x64_cvtss2sd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vcvtss2sd) x y)) + +;; Helper for creating `cvtsd2ss` instructions. +;; +;; NB: see `x64_sqrtss` for why this has two args (same reasoning, different op) +(decl x64_cvtsd2ss (Xmm XmmMem) Xmm) +(rule (x64_cvtsd2ss x y) (xmm_rm_r_unaligned (SseOpcode.Cvtsd2ss) x y)) +(rule 1 (x64_cvtsd2ss x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vcvtsd2ss) x y)) + +;; Helper for creating `cvtdq2ps` instructions. +(decl x64_cvtdq2ps (XmmMem) Xmm) +(rule (x64_cvtdq2ps x) (xmm_unary_rm_r (SseOpcode.Cvtdq2ps) x)) +(rule 1 (x64_cvtdq2ps x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvtdq2ps) x)) + +;; Helper for creating `cvtps2pd` instructions. +(decl x64_cvtps2pd (XmmMem) Xmm) +(rule (x64_cvtps2pd x) (xmm_unary_rm_r (SseOpcode.Cvtps2pd) x)) +(rule 1 (x64_cvtps2pd x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvtps2pd) x)) + +;; Helper for creating `cvtpd2ps` instructions. +(decl x64_cvtpd2ps (XmmMem) Xmm) +(rule (x64_cvtpd2ps x) (xmm_unary_rm_r (SseOpcode.Cvtpd2ps) x)) +(rule 1 (x64_cvtpd2ps x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvtpd2ps) x)) + +;; Helper for creating `cvtdq2pd` instructions. +(decl x64_cvtdq2pd (XmmMem) Xmm) +(rule (x64_cvtdq2pd x) (xmm_unary_rm_r (SseOpcode.Cvtdq2pd) x)) +(rule 1 (x64_cvtdq2pd x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvtdq2pd) x)) + +;; Helper for creating `cvtsi2ss` instructions. +(decl x64_cvtsi2ss (Type Xmm GprMem) Xmm) +(rule (x64_cvtsi2ss ty x y) + (cvt_int_to_float (SseOpcode.Cvtsi2ss) x y (raw_operand_size_of_type ty))) +(rule 1 (x64_cvtsi2ss ty x y) + (if-let true (use_avx)) + (cvt_int_to_float_vex (AvxOpcode.Vcvtsi2ss) x y (raw_operand_size_of_type ty))) + +;; Helper for creating `cvtsi2sd` instructions. +(decl x64_cvtsi2sd (Type Xmm GprMem) Xmm) +(rule (x64_cvtsi2sd ty x y) + (cvt_int_to_float (SseOpcode.Cvtsi2sd) x y (raw_operand_size_of_type ty))) +(rule 1 (x64_cvtsi2sd ty x y) + (if-let true (use_avx)) + (cvt_int_to_float_vex (AvxOpcode.Vcvtsi2sd) x y (raw_operand_size_of_type ty))) + +;; Helper for creating `cvttps2dq` instructions. +(decl x64_cvttps2dq (XmmMem) Xmm) +(rule (x64_cvttps2dq x) + (xmm_unary_rm_r (SseOpcode.Cvttps2dq) x)) +(rule 1 (x64_cvttps2dq x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvttps2dq) x)) + +;; Helper for creating `cvttpd2dq` instructions. +(decl x64_cvttpd2dq (XmmMem) Xmm) +(rule (x64_cvttpd2dq x) + (xmm_unary_rm_r (SseOpcode.Cvttpd2dq) x)) +(rule 1 (x64_cvttpd2dq x) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vcvttpd2dq) x)) + +;; Helpers for creating `pcmpeq*` instructions. +(decl x64_pcmpeq (Type Xmm XmmMem) Xmm) +(rule (x64_pcmpeq $I8X16 x y) (x64_pcmpeqb x y)) +(rule (x64_pcmpeq $I16X8 x y) (x64_pcmpeqw x y)) +(rule (x64_pcmpeq $I32X4 x y) (x64_pcmpeqd x y)) +(rule (x64_pcmpeq $I64X2 x y) + (if-let true (use_sse41)) + (x64_pcmpeqq x y)) + +;; Without SSE 4.1 there's no access to `pcmpeqq`, so it's emulated by comparing +;; 32-bit lanes instead. The upper and lower halves of the 32-bit comparison are +;; swapped and then these two results are and'd together. This way only if both +;; 32-bit values were equal is the result all ones, otherwise the result is +;; all zeros if either 32-bit comparison was zero. +(rule -1 (x64_pcmpeq $I64X2 x y) + (let ((cmp32 Xmm (x64_pcmpeqd x y)) + (cmp32_swapped Xmm (x64_pshufd cmp32 0b10_11_00_01))) + (x64_pand cmp32 cmp32_swapped))) + +(decl x64_pcmpeqb (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpeqb x y) (xmm_rm_r (SseOpcode.Pcmpeqb) x y)) +(rule 1 (x64_pcmpeqb x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpeqb) x y)) +(decl x64_pcmpeqw (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpeqw x y) (xmm_rm_r (SseOpcode.Pcmpeqw) x y)) +(rule 1 (x64_pcmpeqw x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpeqw) x y)) +(decl x64_pcmpeqd (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpeqd x y) (xmm_rm_r (SseOpcode.Pcmpeqd) x y)) +(rule 1 (x64_pcmpeqd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpeqd) x y)) +(decl x64_pcmpeqq (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpeqq x y) (xmm_rm_r (SseOpcode.Pcmpeqq) x y)) +(rule 1 (x64_pcmpeqq x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpeqq) x y)) + +;; Helpers for creating `pcmpgt*` instructions. +(decl x64_pcmpgt (Type Xmm XmmMem) Xmm) +(rule (x64_pcmpgt $I8X16 x y) (x64_pcmpgtb x y)) +(rule (x64_pcmpgt $I16X8 x y) (x64_pcmpgtw x y)) +(rule (x64_pcmpgt $I32X4 x y) (x64_pcmpgtd x y)) + +;; SSE4.2 gives a single-instruction for this lowering, but prior to that it's a +;; bit more complicated. +(rule 1 (x64_pcmpgt $I64X2 x y) + (if-let true (use_sse42)) + (x64_pcmpgtq x y)) + +;; Without SSE4.2 a 64-bit comparison is expanded to a number of instructions. +;; The basic idea is to delegate to a 32-bit comparison and work with the +;; results from there. The comparison to execute is: +;; +;; [ xhi ][ xlo ] > [ yhi ][ ylo ] +;; +;; If xhi != yhi, then the result is whatever the result of that comparison is. +;; If xhi == yhi, then the result is the unsigned comparison of xlo/ylo since +;; the 64-bit value is positive. To achieve this as part of the same comparison +;; the upper bit of `xlo` and `ylo` is flipped to change the sign when compared +;; as a 32-bit signed number. The result here is then: +;; +;; * if xlo and yhi had the same upper bit, then the unsigned comparison should +;; be the same as comparing the flipped versions as signed. +;; * if xlo had an upper bit of 0 and ylo had an upper bit of 1, then xlo > ylo +;; is false. When flipping the bits xlo becomes negative and ylo becomes +;; positive when compared as 32-bits, so the result is the same. +;; * if xlo had an upper bit of 1 and ylo had an upper bit of 0, then xlo > ylo +;; is true. When flipping the bits xlo becomes positive and ylo becomes +;; negative when compared as 32-bits, so the result is the same. +;; +;; Given all that the sequence here is to flip the upper bits of xlo and ylo, +;; then compare the masked results for equality and for gt. If the upper 32-bits +;; are not equal then the gt result for the upper bits is used. If the upper +;; 32-bits are equal then the lower 32-bits comparison is used instead. +(rule 0 (x64_pcmpgt $I64X2 x y) + (let ( + (mask Xmm (x64_movdqu_load (emit_u128_le_const 0x00000000_80000000_00000000_80000000))) + (x_masked Xmm (x64_pxor mask x)) + (y_masked Xmm (x64_pxor mask y)) + (cmp32 Xmm (x64_pcmpgtd x_masked y_masked)) + (low_halves_gt Xmm (x64_pshufd cmp32 0xa0)) + (high_halves_gt Xmm (x64_pshufd cmp32 0xf5)) + (cmp_eq Xmm (x64_pcmpeqd x_masked y_masked)) + (high_halves_eq Xmm (x64_pshufd cmp_eq 0xf5)) + (low_gt_and_high_eq Xmm (x64_pand low_halves_gt high_halves_eq)) + ) + (x64_por low_gt_and_high_eq high_halves_gt))) + +(decl x64_pcmpgtb (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpgtb x y) (xmm_rm_r (SseOpcode.Pcmpgtb) x y)) +(rule 1 (x64_pcmpgtb x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpgtb) x y)) +(decl x64_pcmpgtw (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpgtw x y) (xmm_rm_r (SseOpcode.Pcmpgtw) x y)) +(rule 1 (x64_pcmpgtw x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpgtw) x y)) +(decl x64_pcmpgtd (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpgtd x y) (xmm_rm_r (SseOpcode.Pcmpgtd) x y)) +(rule 1 (x64_pcmpgtd x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpgtd) x y)) +(decl x64_pcmpgtq (Xmm XmmMem) Xmm) +(rule 0 (x64_pcmpgtq x y) (xmm_rm_r (SseOpcode.Pcmpgtq) x y)) +(rule 1 (x64_pcmpgtq x y) + (if-let true (use_avx)) + (xmm_rmir_vex (AvxOpcode.Vpcmpgtq) x y)) + +;; Helpers for read-modify-write ALU form (AluRM). +(decl alu_rm (Type AluRmiROpcode Amode Gpr) SideEffectNoResult) +(rule (alu_rm ty opcode src1_dst src2) + (let ((size OperandSize (operand_size_of_type_32_64 ty))) + (SideEffectNoResult.Inst (MInst.AluRM size opcode src1_dst src2 false)))) + +(decl x64_add_mem (Type Amode Gpr) SideEffectNoResult) +(spec (x64_add_mem ty addr val) + (provide (= result (store_effect + (extract 79 64 addr) + ty + (conv_to ty (bvadd (load_effect (extract 79 64 addr) ty (extract 63 0 addr)) (conv_to ty val))) + (extract 63 0 addr)) + ) + ) + (require (or (= ty 32) (= ty 64))) +) +(rule (x64_add_mem ty addr val) + (alu_rm ty (AluRmiROpcode.Add) addr val)) + +(decl x64_sub_mem (Type Amode Gpr) SideEffectNoResult) +(rule (x64_sub_mem ty addr val) + (alu_rm ty (AluRmiROpcode.Sub) addr val)) + +(decl x64_and_mem (Type Amode Gpr) SideEffectNoResult) +(rule (x64_and_mem ty addr val) + (alu_rm ty (AluRmiROpcode.And) addr val)) + +(decl x64_or_mem (Type Amode Gpr) SideEffectNoResult) +(rule (x64_or_mem ty addr val) + (alu_rm ty (AluRmiROpcode.Or) addr val)) + +(decl x64_xor_mem (Type Amode Gpr) SideEffectNoResult) +(rule (x64_xor_mem ty addr val) + (alu_rm ty (AluRmiROpcode.Xor) addr val)) + +;; Trap if the condition code supplied is set. +(decl trap_if (CC TrapCode) ConsumesFlags) +(rule (trap_if cc tc) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.TrapIf cc tc))) + +;; Trap if both of the condition codes supplied are set. +(decl trap_if_and (CC CC TrapCode) ConsumesFlags) +(rule (trap_if_and cc1 cc2 tc) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.TrapIfAnd cc1 cc2 tc))) + +;; Trap if either of the condition codes supplied are set. +(decl trap_if_or (CC CC TrapCode) ConsumesFlags) +(rule (trap_if_or cc1 cc2 tc) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.TrapIfOr cc1 cc2 tc))) + +(decl trap_if_icmp (IcmpCondResult TrapCode) SideEffectNoResult) +(rule (trap_if_icmp (IcmpCondResult.Condition producer cc) tc) + (with_flags_side_effect producer (trap_if cc tc))) + +(decl trap_if_fcmp (FcmpCondResult TrapCode) SideEffectNoResult) +(rule (trap_if_fcmp (FcmpCondResult.Condition producer cc) tc) + (with_flags_side_effect producer (trap_if cc tc))) +(rule (trap_if_fcmp (FcmpCondResult.AndCondition producer cc1 cc2) tc) + (with_flags_side_effect producer (trap_if_and cc1 cc2 tc))) +(rule (trap_if_fcmp (FcmpCondResult.OrCondition producer cc1 cc2) tc) + (with_flags_side_effect producer (trap_if_or cc1 cc2 tc))) + +;; Trap if zero/not zero +(type ZeroCond + (enum + Zero + NonZero)) + +(decl zero_cond_to_cc (ZeroCond) CC) +(rule (zero_cond_to_cc (ZeroCond.Zero)) (CC.Z)) +(rule (zero_cond_to_cc (ZeroCond.NonZero)) (CC.NZ)) + +(decl trap_if_val (ZeroCond Value TrapCode) SideEffectNoResult) +(rule (trap_if_val zero_cond a @ (value_type (fits_in_64 ty)) tc) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (a Gpr (put_in_reg a)) + (producer ProducesFlags (x64_test size a a))) + (with_flags_side_effect producer (trap_if (zero_cond_to_cc zero_cond) tc)))) + +(rule 1 (trap_if_val zero_cond a @ (value_type $I128) tc) + (let ((a_lo Gpr (value_regs_get_gpr a 0)) + (a_hi Gpr (value_regs_get_gpr a 1)) + (a_or Gpr (x64_or $I64 a_hi a_lo)) + (producer ProducesFlags (x64_test (OperandSize.Size64) a_or a_or))) + (with_flags_side_effect producer (trap_if (zero_cond_to_cc zero_cond) tc)))) + +;; Helper for creating `movddup` instructions +(decl x64_movddup (XmmMem) Xmm) +(rule (x64_movddup src) + (xmm_unary_rm_r_unaligned (SseOpcode.Movddup) src)) +(rule 1 (x64_movddup src) + (if-let true (use_avx)) + (xmm_unary_rm_r_vex (AvxOpcode.Vmovddup) src)) + +;; Helper for creating `vpbroadcastb` instructions +(decl x64_vpbroadcastb (XmmMem) Xmm) +(rule (x64_vpbroadcastb src) + (xmm_unary_rm_r_vex (AvxOpcode.Vpbroadcastb) src)) + +;; Helper for creating `vpbroadcastw` instructions +(decl x64_vpbroadcastw (XmmMem) Xmm) +(rule (x64_vpbroadcastw src) + (xmm_unary_rm_r_vex (AvxOpcode.Vpbroadcastw) src)) + +;; Helper for creating `vpbroadcastd` instructions +(decl x64_vpbroadcastd (XmmMem) Xmm) +(rule (x64_vpbroadcastd src) + (xmm_unary_rm_r_vex (AvxOpcode.Vpbroadcastd) src)) + +;; Helper for creating `vbroadcastss` instructions +(decl x64_vbroadcastss (XmmMem) Xmm) +(rule (x64_vbroadcastss src) + (xmm_unary_rm_r_vex (AvxOpcode.Vbroadcastss) src)) + +;;;; Jumps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Unconditional jump. +(decl jmp_known (MachLabel) SideEffectNoResult) +(rule (jmp_known target) + (SideEffectNoResult.Inst (MInst.JmpKnown target))) + +(decl jmp_if (CC MachLabel) ConsumesFlags) +(rule (jmp_if cc taken) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.JmpIf cc taken))) + +;; Conditional jump based on the condition code. +(decl jmp_cond (CC MachLabel MachLabel) ConsumesFlags) +(rule (jmp_cond cc taken not_taken) + (ConsumesFlags.ConsumesFlagsSideEffect (MInst.JmpCond cc taken not_taken))) + +;; Conditional jump based on the result of an icmp. +(decl jmp_cond_icmp (IcmpCondResult MachLabel MachLabel) SideEffectNoResult) +(rule (jmp_cond_icmp (IcmpCondResult.Condition producer cc) taken not_taken) + (with_flags_side_effect producer (jmp_cond cc taken not_taken))) + +;; Conditional jump based on the result of an fcmp. +(decl jmp_cond_fcmp (FcmpCondResult MachLabel MachLabel) SideEffectNoResult) +(rule (jmp_cond_fcmp (FcmpCondResult.Condition producer cc) taken not_taken) + (with_flags_side_effect producer (jmp_cond cc taken not_taken))) +(rule (jmp_cond_fcmp (FcmpCondResult.AndCondition producer cc1 cc2) taken not_taken) + (with_flags_side_effect producer + (consumes_flags_concat + (jmp_if (cc_invert cc1) not_taken) + (jmp_cond (cc_invert cc2) not_taken taken)))) +(rule (jmp_cond_fcmp (FcmpCondResult.OrCondition producer cc1 cc2) taken not_taken) + (with_flags_side_effect producer + (consumes_flags_concat + (jmp_if cc1 taken) + (jmp_cond cc2 taken not_taken)))) + +;; Emit the compound instruction that does: +;; +;; lea $jt, %rA +;; movsbl [%rA, %rIndex, 2], %rB +;; add %rB, %rA +;; j *%rA +;; [jt entries] +;; +;; This must be *one* instruction in the vcode because we cannot allow regalloc +;; to insert any spills/fills in the middle of the sequence; otherwise, the +;; lea PC-rel offset to the jumptable would be incorrect. (The alternative +;; is to introduce a relocation pass for inlined jumptables, which is much +;; worse.) +(decl jmp_table_seq (Type Gpr MachLabel BoxVecMachLabel) SideEffectNoResult) +(rule (jmp_table_seq ty idx default_target jt_targets) + (let ( + ;; This temporary is used as a signed integer of 64-bits (to hold + ;; addresses). + (tmp1 WritableGpr (temp_writable_gpr)) + + ;; This temporary is used as a signed integer of 32-bits (for the + ;; wasm-table index) and then 64-bits (address addend). The small + ;; lie about the I64 type is benign, since the temporary is dead + ;; after this instruction (and its Cranelift type is thus unused). + (tmp2 WritableGpr (temp_writable_gpr))) + + (SideEffectNoResult.Inst + (MInst.JmpTableSeq idx tmp1 tmp2 default_target jt_targets)))) + +;;;; Comparisons ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type IcmpCondResult (enum (Condition (producer ProducesFlags) (cc CC)))) + +(decl icmp_cond_result (ProducesFlags CC) IcmpCondResult) +(rule (icmp_cond_result producer cc) (IcmpCondResult.Condition producer cc)) + +(decl invert_icmp_cond_result (IcmpCondResult) IcmpCondResult) +(rule (invert_icmp_cond_result (IcmpCondResult.Condition producer cc)) + (icmp_cond_result producer (cc_invert cc))) + +;; Lower an Icmp result into a boolean value in a register. +(decl lower_icmp_bool (IcmpCondResult) ValueRegs) +(rule (lower_icmp_bool (IcmpCondResult.Condition producer cc)) + (with_flags producer (x64_setcc cc))) + +;; Emit a conditional move based on the result of an icmp. +(decl select_icmp (IcmpCondResult Value Value) ValueRegs) + +;; Ensure that we put the `x` argument into a register for single-register +;; gpr-typed arguments, as we rely on this for the legalization of heap_addr and +;; loading easily computed constants (like 0) from memory is too expensive. +(rule 1 (select_icmp (IcmpCondResult.Condition producer cc) x @ (value_type (is_single_register_gpr_type ty)) y) + (with_flags producer (cmove ty cc (put_in_gpr x) y))) + +;; Otherwise, fall back on the behavior of `cmove_from_values`. +(rule 0 (select_icmp (IcmpCondResult.Condition producer cc) x @ (value_type ty) y) + (with_flags producer (cmove_from_values ty cc x y))) + +(decl emit_cmp (IntCC Value Value) IcmpCondResult) + +;; For GPR-held values we only need to emit `CMP + SETCC`. We rely here on +;; Cranelift's verification that `a` and `b` are of the same type. +(rule 0 (emit_cmp cc a @ (value_type ty) b) + (let ((size OperandSize (raw_operand_size_of_type ty))) + (icmp_cond_result (x64_cmp size a b) cc))) + +;; As a special case, swap the arguments to the comparison when the LHS is a +;; constant. This ensures that we avoid moving the constant into a register when +;; performing the comparison. +(rule 1 (emit_cmp cc (and (simm32_from_value a) (value_type ty)) b) + (let ((size OperandSize (raw_operand_size_of_type ty))) + (icmp_cond_result (x64_cmp size b a) (intcc_swap_args cc)))) + +;; Special case: use the test instruction for comparisons with 0. +(rule 2 (emit_cmp cc a @ (value_type ty) (u64_from_iconst 0)) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (a Gpr (put_in_reg a))) + (icmp_cond_result (x64_test size a a) cc))) + +(rule 3 (emit_cmp cc (u64_from_iconst 0) b @ (value_type ty)) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (b Gpr (put_in_reg b))) + (icmp_cond_result (x64_test size b b) (intcc_swap_args cc)))) + +;; For I128 values (held in two GPRs), the instruction sequences depend on what +;; kind of condition is tested. +(rule 4 (emit_cmp cc a @ (value_type $I128) b) + (let ((a_lo Gpr (value_regs_get_gpr a 0)) + (a_hi Gpr (value_regs_get_gpr a 1)) + (b_lo Gpr (value_regs_get_gpr b 0)) + (b_hi Gpr (value_regs_get_gpr b 1))) + (emit_cmp_i128 cc a_hi a_lo b_hi b_lo))) + +(decl emit_cmp_i128 (CC Gpr Gpr Gpr Gpr) IcmpCondResult) +;; Eliminate cases which compare something "or equal" by swapping arguments. +(rule 2 (emit_cmp_i128 (CC.NLE) a_hi a_lo b_hi b_lo) + (emit_cmp_i128 (CC.L) b_hi b_lo a_hi a_lo)) +(rule 2 (emit_cmp_i128 (CC.LE) a_hi a_lo b_hi b_lo) + (emit_cmp_i128 (CC.NL) b_hi b_lo a_hi a_lo)) +(rule 2 (emit_cmp_i128 (CC.NBE) a_hi a_lo b_hi b_lo) + (emit_cmp_i128 (CC.B) b_hi b_lo a_hi a_lo)) +(rule 2 (emit_cmp_i128 (CC.BE) a_hi a_lo b_hi b_lo) + (emit_cmp_i128 (CC.NB) b_hi b_lo a_hi a_lo)) + +;; 128-bit strict equality/inequality can't be easily tested using subtraction +;; but we can quickly determine whether any bits are different instead. +(rule 1 (emit_cmp_i128 (cc_nz_or_z cc) a_hi a_lo b_hi b_lo) + (let ((same_lo Reg (x64_xor $I64 a_lo b_lo)) + (same_hi Reg (x64_xor $I64 a_hi b_hi))) + (icmp_cond_result + (x64_alurmi_flags_side_effect (AluRmiROpcode.Or) $I64 same_lo same_hi) + cc))) + +;; The only cases left are L/NL/B/NB which we can implement with a sub/sbb +;; sequence. But since we don't care about anything but the flags we can +;; replace the sub with cmp, which avoids clobbering one of the registers. +(rule 0 (emit_cmp_i128 cc a_hi a_lo b_hi b_lo) + (icmp_cond_result + (produces_flags_concat + (x64_cmp (OperandSize.Size64) a_lo b_lo) + (x64_alurmi_flags_side_effect (AluRmiROpcode.Sbb) $I64 a_hi b_hi)) + cc)) + +(type FcmpCondResult + (enum + ;; The given condition code must be set. + (Condition (producer ProducesFlags) (cc CC)) + + ;; Both condition codes must be set. + (AndCondition (producer ProducesFlags) (cc1 CC) (cc2 CC)) + + ;; Either of the conditions codes must be set. + (OrCondition (producer ProducesFlags) (cc1 CC) (cc2 CC)))) + +;; Lower a FcmpCondResult to a boolean value in a register. +(decl lower_fcmp_bool (FcmpCondResult) ValueRegs) + +(rule (lower_fcmp_bool (FcmpCondResult.Condition producer cc)) + (with_flags producer (x64_setcc cc))) + +(rule (lower_fcmp_bool (FcmpCondResult.AndCondition producer cc1 cc2)) + (let ((maybe ValueRegs (with_flags producer + (consumes_flags_concat + (x64_setcc cc1) + (x64_setcc cc2)))) + (maybe0 Gpr (value_regs_get_gpr maybe 0)) + (maybe1 Gpr (value_regs_get_gpr maybe 1))) + (value_reg (x64_and $I8 maybe0 maybe1)))) + +(rule (lower_fcmp_bool (FcmpCondResult.OrCondition producer cc1 cc2)) + (let ((maybe ValueRegs (with_flags producer + (consumes_flags_concat + (x64_setcc cc1) + (x64_setcc cc2)))) + (maybe0 Gpr (value_regs_get_gpr maybe 0)) + (maybe1 Gpr (value_regs_get_gpr maybe 1))) + (value_reg (x64_or $I8 maybe0 maybe1)))) + +;; CLIF's `fcmp` instruction always operates on XMM registers--both scalar and +;; vector. For the scalar versions, we use the flag-setting behavior of the +;; `UCOMIS*` instruction to `SETcc` a 0 or 1 in a GPR register. Note that CLIF's +;; `select` uses the same kind of flag-setting behavior but chooses values other +;; than 0 or 1. +;; +;; Checking the result of `UCOMIS*` is unfortunately difficult in some cases +;; because we do not have `SETcc` instructions that explicitly check +;; simultaneously for the condition (i.e., `eq`, `le`, `gt`, etc.) *and* +;; orderedness. Instead, we must check the flags multiple times. The UCOMIS* +;; documentation (see Intel's Software Developer's Manual, volume 2, chapter 4) +;; is helpful: +;; - unordered assigns Z = 1, P = 1, C = 1 +;; - greater than assigns Z = 0, P = 0, C = 0 +;; - less than assigns Z = 0, P = 0, C = 1 +;; - equal assigns Z = 1, P = 0, C = 0 +(decl emit_fcmp (FloatCC Value Value) FcmpCondResult) + +(rule (emit_fcmp (FloatCC.Equal) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.AndCondition (x64_ucomis ty a b) (CC.NP) (CC.Z))) + +(rule (emit_fcmp (FloatCC.NotEqual) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.OrCondition (x64_ucomis ty a b) (CC.P) (CC.NZ))) + +;; Some scalar lowerings correspond to one condition code. + +(rule (emit_fcmp (FloatCC.Ordered) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.NP))) +(rule (emit_fcmp (FloatCC.Unordered) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.P))) +(rule (emit_fcmp (FloatCC.OrderedNotEqual) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.NZ))) +(rule (emit_fcmp (FloatCC.UnorderedOrEqual) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.Z))) +(rule (emit_fcmp (FloatCC.GreaterThan) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.NBE))) +(rule (emit_fcmp (FloatCC.GreaterThanOrEqual) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.NB))) +(rule (emit_fcmp (FloatCC.UnorderedOrLessThan) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.B))) +(rule (emit_fcmp (FloatCC.UnorderedOrLessThanOrEqual) a @ (value_type (ty_scalar_float ty)) b) + (FcmpCondResult.Condition (x64_ucomis ty a b) (CC.BE))) + +;; Other scalar lowerings are made possible by flipping the operands and +;; reversing the condition code. + +(rule (emit_fcmp (FloatCC.LessThan) a @ (value_type (ty_scalar_float ty)) b) + ;; Same flags as `GreaterThan`. + (FcmpCondResult.Condition (x64_ucomis ty b a) (CC.NBE))) +(rule (emit_fcmp (FloatCC.LessThanOrEqual) a @ (value_type (ty_scalar_float ty)) b) + ;; Same flags as `GreaterThanOrEqual`. + (FcmpCondResult.Condition (x64_ucomis ty b a) (CC.NB))) +(rule (emit_fcmp (FloatCC.UnorderedOrGreaterThan) a @ (value_type (ty_scalar_float ty)) b) + ;; Same flags as `UnorderedOrLessThan`. + (FcmpCondResult.Condition (x64_ucomis ty b a) (CC.B))) +(rule (emit_fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) a @ (value_type (ty_scalar_float ty)) b) + ;; Same flags as `UnorderedOrLessThanOrEqual`. + (FcmpCondResult.Condition (x64_ucomis ty b a) (CC.BE))) + +;;;; Type Guards ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; A type guard for matching ints and bools up to 64 bits, or 64 bit references. +(decl ty_int_bool_or_ref () Type) +(extern extractor ty_int_bool_or_ref ty_int_bool_or_ref) + +;;;; Atomics ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl x64_mfence () SideEffectNoResult) +(rule (x64_mfence) + (SideEffectNoResult.Inst (MInst.Fence (FenceKind.MFence)))) + +(decl x64_cmpxchg (Type Gpr Gpr SyntheticAmode) Gpr) +(rule (x64_cmpxchg ty expected replacement addr) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.LockCmpxchg ty replacement expected addr dst)))) + dst)) + +(decl x64_cmpxchg16b (ValueRegs ValueRegs SyntheticAmode) ValueRegs) +(rule (x64_cmpxchg16b expected replacement addr) + (let ((expected_low Gpr (value_regs_get_gpr expected 0)) + (expected_high Gpr (value_regs_get_gpr expected 1)) + (replacement_low Gpr (value_regs_get_gpr replacement 0)) + (replacement_high Gpr (value_regs_get_gpr replacement 1)) + (dst_low WritableGpr (temp_writable_gpr)) + (dst_high WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.LockCmpxchg16b replacement_low replacement_high expected_low expected_high addr dst_low dst_high)))) + (value_regs dst_low dst_high))) + +(decl x64_xadd (OperandSize SyntheticAmode Gpr) Gpr) +(rule (x64_xadd size addr operand) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.LockXadd size operand addr dst)))) + dst)) + +(decl x64_xchg (OperandSize SyntheticAmode Gpr) Gpr) +(rule (x64_xchg size addr operand) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Xchg size operand addr dst)))) + dst)) + +(decl lock_alu_rm (OperandSize AluRmiROpcode SyntheticAmode Gpr) Reg) +(rule (lock_alu_rm size opcode addr operand) + (let ((_ Unit (emit (MInst.AluRM size opcode addr operand true)))) + (invalid_reg))) + +(decl x64_lock_add (OperandSize SyntheticAmode Gpr) Reg) +(rule (x64_lock_add size addr operand) + (lock_alu_rm size (AluRmiROpcode.Add) addr operand)) + +(decl x64_lock_sub (OperandSize SyntheticAmode Gpr) Reg) +(rule (x64_lock_sub size addr operand) + (lock_alu_rm size (AluRmiROpcode.Sub) addr operand)) + +(decl x64_lock_and (OperandSize SyntheticAmode Gpr) Reg) +(rule (x64_lock_and size addr operand) + (lock_alu_rm size (AluRmiROpcode.And) addr operand)) + +(decl x64_lock_or (OperandSize SyntheticAmode Gpr) Reg) +(rule (x64_lock_or size addr operand) + (lock_alu_rm size (AluRmiROpcode.Or) addr operand)) + +(decl x64_lock_xor (OperandSize SyntheticAmode Gpr) Reg) +(rule (x64_lock_xor size addr operand) + (lock_alu_rm size (AluRmiROpcode.Xor) addr operand)) + +(decl x64_atomic_rmw_seq (Type AtomicRmwSeqOp SyntheticAmode Gpr) Gpr) +(rule (x64_atomic_rmw_seq ty op mem input) + (let ((dst WritableGpr (temp_writable_gpr)) + (tmp WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.AtomicRmwSeq ty op mem input tmp dst)))) + dst)) + +(decl x64_atomic_128_rmw_seq (AtomicRmwOp SyntheticAmode ValueRegs) ValueRegs) +(rule (x64_atomic_128_rmw_seq op mem input) + (let ((dst_low WritableGpr (temp_writable_gpr)) + (dst_high WritableGpr (temp_writable_gpr)) + (tmp_low WritableGpr (temp_writable_gpr)) + (tmp_high WritableGpr (temp_writable_gpr)) + (input_low Gpr (value_regs_get_gpr input 0)) + (input_high Gpr (value_regs_get_gpr input 1)) + (_ Unit (emit (MInst.Atomic128RmwSeq (atomic_128_rmw_seq_op op) mem input_low input_high tmp_low tmp_high dst_low dst_high)))) + (value_regs dst_low dst_high))) + +(rule 1 (x64_atomic_128_rmw_seq (AtomicRmwOp.Xchg) mem input) + (let ((dst_low WritableGpr (temp_writable_gpr)) + (dst_high WritableGpr (temp_writable_gpr)) + (input_low Gpr (value_regs_get_gpr input 0)) + (input_high Gpr (value_regs_get_gpr input 1)) + (_ Unit (emit (MInst.Atomic128XchgSeq mem input_low input_high dst_low dst_high)))) + (value_regs dst_low dst_high))) + +(decl x64_atomic_128_store_seq (SyntheticAmode ValueRegs) SideEffectNoResult) +(rule (x64_atomic_128_store_seq mem input) + (let ((dst_low WritableGpr (temp_writable_gpr)) + (dst_high WritableGpr (temp_writable_gpr)) + (input_low Gpr (value_regs_get_gpr input 0)) + (input_high Gpr (value_regs_get_gpr input 1))) + (SideEffectNoResult.Inst (MInst.Atomic128XchgSeq mem input_low input_high dst_low dst_high)))) + + +(type AtomicRmwSeqOp + (enum And + Nand + Or + Xor + Umin + Umax + Smin + Smax)) + +(decl atomic_rmw_seq_op (AtomicRmwOp) AtomicRmwSeqOp) +(rule (atomic_rmw_seq_op (AtomicRmwOp.And)) (AtomicRmwSeqOp.And)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Nand)) (AtomicRmwSeqOp.Nand)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Or)) (AtomicRmwSeqOp.Or)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Xor)) (AtomicRmwSeqOp.Xor)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Umin)) (AtomicRmwSeqOp.Umin)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Umax)) (AtomicRmwSeqOp.Umax)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Smin)) (AtomicRmwSeqOp.Smin)) +(rule (atomic_rmw_seq_op (AtomicRmwOp.Smax)) (AtomicRmwSeqOp.Smax)) + +(type Atomic128RmwSeqOp + (enum Add + Sub + And + Nand + Or + Xor + Umin + Umax + Smin + Smax)) + +(decl atomic_128_rmw_seq_op (AtomicRmwOp) Atomic128RmwSeqOp) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Add)) (Atomic128RmwSeqOp.Add)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Sub)) (Atomic128RmwSeqOp.Sub)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.And)) (Atomic128RmwSeqOp.And)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Nand)) (Atomic128RmwSeqOp.Nand)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Or)) (Atomic128RmwSeqOp.Or)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Xor)) (Atomic128RmwSeqOp.Xor)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Umin)) (Atomic128RmwSeqOp.Umin)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Umax)) (Atomic128RmwSeqOp.Umax)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Smin)) (Atomic128RmwSeqOp.Smin)) +(rule (atomic_128_rmw_seq_op (AtomicRmwOp.Smax)) (Atomic128RmwSeqOp.Smax)) + +;;;; Casting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl bitcast_xmm_to_gpr (u8 Xmm) Gpr) +(rule (bitcast_xmm_to_gpr 16 src) + (x64_pextrw src 0)) +(rule (bitcast_xmm_to_gpr 32 src) + (x64_movd_to_gpr src)) +(rule (bitcast_xmm_to_gpr 64 src) + (x64_movq_to_gpr src)) + +(decl bitcast_xmm_to_gprs (Xmm) ValueRegs) +(rule (bitcast_xmm_to_gprs src) + (value_regs (x64_movq_to_gpr src) (x64_movq_to_gpr (x64_pshufd src 0b11101110)))) + +(decl bitcast_gpr_to_xmm (u8 Gpr) Xmm) +(rule (bitcast_gpr_to_xmm 16 src) + (x64_pinsrw (xmm_uninit_value) src 0)) +(rule (bitcast_gpr_to_xmm 32 src) + (x64_movd_to_xmm src)) +(rule (bitcast_gpr_to_xmm 64 src) + (x64_movq_to_xmm src)) + +(decl bitcast_gprs_to_xmm (ValueRegs) Xmm) +(rule (bitcast_gprs_to_xmm src) + (x64_punpcklqdq (x64_movq_to_xmm (value_regs_get_gpr src 0)) (x64_movq_to_xmm (value_regs_get_gpr src 1)))) + +;;;; Stack Addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl stack_addr_impl (StackSlot Offset32) Gpr) +(rule (stack_addr_impl stack_slot offset) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (abi_stackslot_addr dst stack_slot offset)))) + dst)) + +;;;; Division/Remainders ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper for creating `CheckedSRemSeq` instructions. +(decl x64_checked_srem_seq (OperandSize Gpr Gpr Gpr) ValueRegs) +(rule (x64_checked_srem_seq size dividend_lo dividend_hi divisor) + (let ((dst_quotient WritableGpr (temp_writable_gpr)) + (dst_remainder WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CheckedSRemSeq size dividend_lo dividend_hi divisor dst_quotient dst_remainder)))) + (value_regs dst_quotient dst_remainder))) + +(decl x64_checked_srem_seq8 (Gpr Gpr) Gpr) +(rule (x64_checked_srem_seq8 dividend divisor) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CheckedSRemSeq8 dividend divisor dst)))) + dst)) + +;; Helper for creating `Div8` instructions +(decl x64_div8 (Gpr GprMem DivSignedness TrapCode) Gpr) +(rule (x64_div8 dividend divisor sign trap) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Div8 sign trap divisor dividend dst)))) + dst)) + +;; Helper for creating `Div` instructions +;; +;; Two registers are returned through `ValueRegs` where the first is the +;; quotient and the second is the remainder. +(decl x64_div (Gpr Gpr GprMem OperandSize DivSignedness TrapCode) ValueRegs) +(rule (x64_div dividend_lo dividend_hi divisor size sign trap) + (let ((dst_quotient WritableGpr (temp_writable_gpr)) + (dst_remainder WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.Div size sign trap divisor dividend_lo dividend_hi dst_quotient dst_remainder)))) + (value_regs dst_quotient dst_remainder))) + +;; Helper for `Div`, returning the quotient and discarding the remainder. +(decl x64_div_quotient (Gpr Gpr GprMem OperandSize DivSignedness TrapCode) ValueRegs) +(rule (x64_div_quotient dividend_lo dividend_hi divisor size sign trap) + (value_regs_get (x64_div dividend_lo dividend_hi divisor size sign trap) 0)) + +;; Helper for `Div`, returning the remainder and discarding the quotient. +(decl x64_div_remainder (Gpr Gpr GprMem OperandSize DivSignedness TrapCode) ValueRegs) +(rule (x64_div_remainder dividend_lo dividend_hi divisor size sign trap) + (value_regs_get (x64_div dividend_lo dividend_hi divisor size sign trap) 1)) + +;; Helper for creating `SignExtendData` instructions +(decl x64_sign_extend_data (Gpr OperandSize) Gpr) +(rule (x64_sign_extend_data src size) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.SignExtendData size src dst)))) + dst)) + +;;;; Pinned Register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl read_pinned_gpr () Gpr) +(rule (read_pinned_gpr) + (mov_from_preg (preg_pinned))) + +(decl write_pinned_gpr (Gpr) SideEffectNoResult) +(rule (write_pinned_gpr val) + (mov_to_preg (preg_pinned) val)) + +;;;; Shuffle ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Produce a mask suitable for use with `pshufb` for permuting the argument to +;; shuffle, when the arguments are the same (i.e. `shuffle a a mask`). This will +;; map all indices in the range 0..31 to the range 0..15. +(decl shuffle_0_31_mask (VecMask) VCodeConstant) +(extern constructor shuffle_0_31_mask shuffle_0_31_mask) + +;; Produce a mask suitable for use with `pshufb` for permuting the lhs of a +;; `shuffle` operation (lanes 0-15). +(decl shuffle_0_15_mask (VecMask) VCodeConstant) +(extern constructor shuffle_0_15_mask shuffle_0_15_mask) + +;; Produce a mask suitable for use with `pshufb` for permuting the rhs of a +;; `shuffle` operation (lanes 16-31). +(decl shuffle_16_31_mask (VecMask) VCodeConstant) +(extern constructor shuffle_16_31_mask shuffle_16_31_mask) + +;; Produce a permutation suitable for use with `vpermi2b`, for permuting two +;; I8X16 vectors simultaneously. +;; +;; NOTE: `vpermi2b` will mask the indices in each lane to 5 bits when indexing +;; into vectors, so this constructor makes no effort to handle indices that are +;; larger than 31. If you are lowering a clif opcode like `shuffle` that has +;; special behavior for out of bounds indices (emitting a `0` in the resulting +;; vector in the case of `shuffle`) you'll need to handle that behavior +;; separately. +(decl perm_from_mask (VecMask) VCodeConstant) +(extern constructor perm_from_mask perm_from_mask) + +;; If the mask that would be given to `shuffle` contains any out-of-bounds +;; indices, return a mask that will zero those. +(decl perm_from_mask_with_zeros (VCodeConstant VCodeConstant) VecMask) +(extern extractor perm_from_mask_with_zeros perm_from_mask_with_zeros) + +;;;; TLS Values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Helper for emitting ElfTlsGetAddr. +(decl elf_tls_get_addr (ExternalName) Gpr) +(rule (elf_tls_get_addr name) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.ElfTlsGetAddr name dst)))) + dst)) + +;; Helper for emitting MachOTlsGetAddr. +(decl macho_tls_get_addr (ExternalName) Gpr) +(rule (macho_tls_get_addr name) + (let ((dst WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.MachOTlsGetAddr name dst)))) + dst)) + +;; Helper for emitting CoffTlsGetAddr. +(decl coff_tls_get_addr (ExternalName) Gpr) +(rule (coff_tls_get_addr name) + (let ((dst WritableGpr (temp_writable_gpr)) + (tmp WritableGpr (temp_writable_gpr)) + (_ Unit (emit (MInst.CoffTlsGetAddr name dst tmp)))) + dst)) + +;;;; Automatic conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(convert Gpr InstOutput output_gpr) +(convert Value Gpr put_in_gpr) +(convert Value GprMem put_in_gpr_mem) +(convert Value GprMemImm put_in_gpr_mem_imm) +(convert Value RegMem put_in_reg_mem) +(convert Value RegMemImm put_in_reg_mem_imm) +(convert Gpr GprMemImm gpr_to_gpr_mem_imm) +(convert Gpr GprMem gpr_to_gpr_mem) +(convert Gpr Reg gpr_to_reg) +(convert GprMem RegMem gpr_mem_to_reg_mem) +(convert Reg Gpr gpr_new) +(convert WritableGpr Gpr writable_gpr_to_gpr) +(convert RegMemImm GprMemImm gpr_mem_imm_new) +(convert RegMem GprMem reg_mem_to_gpr_mem) +(convert RegMem RegMemImm reg_mem_to_reg_mem_imm) +(convert Reg GprMem reg_to_gpr_mem) +(convert Reg GprMemImm reg_to_gpr_mem_imm) +(convert WritableGpr WritableReg writable_gpr_to_reg) +(convert WritableGpr Reg writable_gpr_to_r_reg) +(convert WritableGpr GprMem writable_gpr_to_gpr_mem) +(convert WritableGpr ValueRegs writable_gpr_to_value_regs) + +(convert Xmm InstOutput output_xmm) +(convert Value Xmm put_in_xmm) +(convert Value XmmMem put_in_xmm_mem) +(convert Value XmmMemAligned put_in_xmm_mem_aligned) +(convert Value XmmMemImm put_in_xmm_mem_imm) +(convert Xmm Reg xmm_to_reg) +(convert Xmm RegMem xmm_to_reg_mem) +(convert Reg Xmm xmm_new) +(convert Reg XmmMem reg_to_xmm_mem) +(convert Reg RegMemImm reg_to_reg_mem_imm) +(convert RegMem XmmMem reg_mem_to_xmm_mem) +(convert Xmm XmmMem xmm_to_xmm_mem) +(convert Xmm XmmMemImm xmm_to_xmm_mem_imm) +(convert Xmm XmmMemAligned xmm_to_xmm_mem_aligned) +(convert XmmMem XmmMemImm xmm_mem_to_xmm_mem_imm) +(convert XmmMem RegMem xmm_mem_to_reg_mem) +(convert RegMemImm XmmMemImm xmm_mem_imm_new) +(convert WritableXmm Xmm writable_xmm_to_xmm) +(convert WritableXmm WritableReg writable_xmm_to_reg) +(convert WritableXmm Reg writable_xmm_to_r_reg) +(convert WritableXmm XmmMem writable_xmm_to_xmm_mem) +(convert WritableXmm ValueRegs writable_xmm_to_value_regs) + +;; Note that these conversions will introduce a `movupd` instruction if +;; the memory location is not aligned to a 16-byte boundary. This is primarily +;; used to convert `XmmMem` inputs, which themselves were typically created +;; via the `put_in_xmm_mem` constructor, into operands of SSE instructions. +;; Most pre-AVX instructions working with 16-bytes of data (e.g. full xmm +;; registers) require 16-byte alignment. +(convert XmmMem XmmMemAligned xmm_mem_to_xmm_mem_aligned) +(convert XmmMemImm XmmMemAlignedImm xmm_mem_imm_to_xmm_mem_aligned_imm) + +(convert Gpr Imm8Gpr gpr_to_imm8_gpr) +(convert Imm8Reg Imm8Gpr imm8_reg_to_imm8_gpr) + +(convert Amode SyntheticAmode amode_to_synthetic_amode) +(convert Amode GprMem amode_to_gpr_mem) +(convert SyntheticAmode GprMem synthetic_amode_to_gpr_mem) +(convert Amode XmmMem amode_to_xmm_mem) +(convert SyntheticAmode XmmMem synthetic_amode_to_xmm_mem) +(convert Amode XmmMemAligned amode_to_xmm_mem_aligned) +(convert SyntheticAmode XmmMemAligned synthetic_amode_to_xmm_mem_aligned) +(convert VCodeConstant SyntheticAmode const_to_synthetic_amode) +(convert VCodeConstant XmmMem const_to_xmm_mem) +(convert VCodeConstant RegMem const_to_reg_mem) + +(convert IntCC CC intcc_to_cc) + +(convert SinkableLoad RegMem sink_load_to_reg_mem) +(convert SinkableLoad GprMem sink_load_to_gpr_mem) +(convert SinkableLoad RegMemImm sink_load_to_reg_mem_imm) +(convert SinkableLoad GprMemImm sink_load_to_gpr_mem_imm) +(convert SinkableLoad XmmMem sink_load_to_xmm_mem) +(convert SinkableLoad SyntheticAmode sink_load) + +(decl reg_to_xmm_mem (Reg) XmmMem) +(rule (reg_to_xmm_mem r) + (xmm_to_xmm_mem (xmm_new r))) +(decl xmm_to_reg_mem (Reg) XmmMem) +(rule (xmm_to_reg_mem r) + (RegMem.Reg (xmm_to_reg r))) + +(decl writable_gpr_to_r_reg (WritableGpr) Reg) +(rule (writable_gpr_to_r_reg w_gpr) + (writable_reg_to_reg (writable_gpr_to_reg w_gpr))) +(decl writable_gpr_to_gpr_mem (WritableGpr) GprMem) +(rule (writable_gpr_to_gpr_mem w_gpr) + (gpr_to_gpr_mem w_gpr)) +(decl writable_gpr_to_value_regs (WritableGpr) ValueRegs) +(rule (writable_gpr_to_value_regs w_gpr) + (value_reg w_gpr)) +(decl writable_xmm_to_r_reg (WritableXmm) Reg) +(rule (writable_xmm_to_r_reg w_xmm) + (writable_reg_to_reg (writable_xmm_to_reg w_xmm))) +(decl writable_xmm_to_xmm_mem (WritableXmm) XmmMem) +(rule (writable_xmm_to_xmm_mem w_xmm) + (xmm_to_xmm_mem (writable_xmm_to_xmm w_xmm))) +(decl writable_xmm_to_value_regs (WritableXmm) ValueRegs) +(rule (writable_xmm_to_value_regs w_xmm) + (value_reg w_xmm)) + +(decl synthetic_amode_to_gpr_mem (SyntheticAmode) GprMem) + +(spec (amode_to_gpr_mem amode) + (provide (= result amode))) +(decl amode_to_gpr_mem (Amode) GprMem) +(rule (amode_to_gpr_mem amode) + (amode_to_synthetic_amode amode)) +(rule (synthetic_amode_to_gpr_mem amode) + (synthetic_amode_to_reg_mem amode)) +(decl amode_to_xmm_mem (Amode) XmmMem) +(rule (amode_to_xmm_mem amode) + (amode_to_synthetic_amode amode)) +(decl synthetic_amode_to_xmm_mem (SyntheticAmode) XmmMem) +(rule (synthetic_amode_to_xmm_mem amode) + (synthetic_amode_to_reg_mem amode)) +(decl const_to_synthetic_amode (VCodeConstant) SyntheticAmode) +(extern constructor const_to_synthetic_amode const_to_synthetic_amode) +(decl const_to_xmm_mem (VCodeConstant) XmmMem) +(rule (const_to_xmm_mem c) (const_to_synthetic_amode c)) +(decl const_to_reg_mem (VCodeConstant) RegMem) +(rule (const_to_reg_mem c) (RegMem.Mem (const_to_synthetic_amode c))) + +(decl xmm_to_xmm_mem_aligned (Xmm) XmmMemAligned) +(rule (xmm_to_xmm_mem_aligned reg) (xmm_mem_to_xmm_mem_aligned reg)) +(decl amode_to_xmm_mem_aligned (Amode) XmmMemAligned) +(rule (amode_to_xmm_mem_aligned mode) (amode_to_xmm_mem mode)) +(decl synthetic_amode_to_xmm_mem_aligned (SyntheticAmode) XmmMemAligned) +(rule (synthetic_amode_to_xmm_mem_aligned mode) (synthetic_amode_to_xmm_mem mode)) +(decl put_in_xmm_mem_aligned (Value) XmmMemAligned) +(rule (put_in_xmm_mem_aligned val) (put_in_xmm_mem val)) + +(decl mov_to_preg (PReg Gpr) SideEffectNoResult) +(rule (mov_to_preg dst src) + (SideEffectNoResult.Inst (MInst.MovToPReg src dst))) + +(decl preg_rbp () PReg) +(extern constructor preg_rbp preg_rbp) + +(decl preg_rsp () PReg) +(extern constructor preg_rsp preg_rsp) + +(decl preg_pinned () PReg) +(extern constructor preg_pinned preg_pinned) + +(decl x64_rbp () Reg) +(rule (x64_rbp) + (mov_from_preg (preg_rbp))) + +(decl x64_rsp () Reg) +(rule (x64_rsp) + (mov_from_preg (preg_rsp))) + +;;;; Helpers for Emitting LibCalls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type LibCall extern + (enum + FmaF32 + FmaF64 + CeilF32 + CeilF64 + FloorF32 + FloorF64 + NearestF32 + NearestF64 + TruncF32 + TruncF64 + X86Pshufb)) + +(decl libcall_1 (LibCall Reg) Reg) +(extern constructor libcall_1 libcall_1) + +(decl libcall_2 (LibCall Reg Reg) Reg) +(extern constructor libcall_2 libcall_2) + +(decl libcall_3 (LibCall Reg Reg Reg) Reg) +(extern constructor libcall_3 libcall_3) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/args.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/args.rs new file mode 100644 index 00000000000000..0e963d516d989c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/args.rs @@ -0,0 +1,2317 @@ +//! Instruction operand sub-components (aka "parts"): definitions and printing. + +use super::regs::{self}; +use crate::ir::condcodes::{FloatCC, IntCC}; +use crate::ir::types::*; +use crate::ir::MemFlags; +use crate::isa::x64::inst::regs::pretty_print_reg; +use crate::isa::x64::inst::Inst; +use crate::machinst::*; +use smallvec::{smallvec, SmallVec}; +use std::fmt; +use std::string::String; + +pub use crate::isa::x64::lower::isle::generated_code::DivSignedness; + +/// An extension trait for converting `Writable{Xmm,Gpr}` to `Writable`. +pub trait ToWritableReg { + /// Convert `Writable{Xmm,Gpr}` to `Writable`. + fn to_writable_reg(&self) -> Writable; +} + +/// An extension trait for converting `Writable` to `Writable{Xmm,Gpr}`. +pub trait FromWritableReg: Sized { + /// Convert `Writable` to `Writable{Xmm,Gpr}`. + fn from_writable_reg(w: Writable) -> Option; +} + +/// A macro for defining a newtype of `Reg` that enforces some invariant about +/// the wrapped `Reg` (such as that it is of a particular register class). +macro_rules! newtype_of_reg { + ( + $newtype_reg:ident, + $newtype_writable_reg:ident, + $newtype_option_writable_reg:ident, + reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*), + reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*), + $newtype_imm8_reg:ident, + |$check_reg:ident| $check:expr + ) => { + /// A newtype wrapper around `Reg`. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $newtype_reg(Reg); + + impl PartialEq for $newtype_reg { + fn eq(&self, other: &Reg) -> bool { + self.0 == *other + } + } + + impl From<$newtype_reg> for Reg { + fn from(r: $newtype_reg) -> Self { + r.0 + } + } + + impl $newtype_reg { + /// Create this newtype from the given register, or return `None` if the register + /// is not a valid instance of this newtype. + pub fn new($check_reg: Reg) -> Option { + if $check { + Some(Self($check_reg)) + } else { + None + } + } + + /// Like `Self::new(r).unwrap()` but with a better panic message on + /// failure. + pub fn unwrap_new($check_reg: Reg) -> Self { + if $check { + Self($check_reg) + } else { + panic!( + "cannot construct {} from register {:?} with register class {:?}", + stringify!($newtype_reg), + $check_reg, + $check_reg.class(), + ) + } + } + + /// Get this newtype's underlying `Reg`. + pub fn to_reg(self) -> Reg { + self.0 + } + } + + // Convenience impl so that people working with this newtype can use it + // "just like" a plain `Reg`. + // + // NB: We cannot implement `DerefMut` because that would let people do + // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the + // invariants that `Gpr` provides. + impl std::ops::Deref for $newtype_reg { + type Target = Reg; + + fn deref(&self) -> &Reg { + &self.0 + } + } + + /// If you know what you're doing, you can explicitly mutably borrow the + /// underlying `Reg`. Don't make it point to the wrong type of register + /// please. + impl AsMut for $newtype_reg { + fn as_mut(&mut self) -> &mut Reg { + &mut self.0 + } + } + + /// Writable Gpr. + pub type $newtype_writable_reg = Writable<$newtype_reg>; + + #[allow(dead_code)] // Used by some newtypes and not others. + /// Optional writable Gpr. + pub type $newtype_option_writable_reg = Option>; + + impl ToWritableReg for $newtype_writable_reg { + fn to_writable_reg(&self) -> Writable { + Writable::from_reg(self.to_reg().to_reg()) + } + } + + impl FromWritableReg for $newtype_writable_reg { + fn from_writable_reg(w: Writable) -> Option { + Some(Writable::from_reg($newtype_reg::new(w.to_reg())?)) + } + } + + $( + /// A newtype wrapper around `RegMem` for general-purpose registers. + #[derive(Clone, Debug)] + pub struct $newtype_reg_mem(RegMem); + + impl From<$newtype_reg_mem> for RegMem { + fn from(rm: $newtype_reg_mem) -> Self { + rm.0 + } + } + impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem { + fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem { + &rm.0 + } + } + + impl From<$newtype_reg> for $newtype_reg_mem { + fn from(r: $newtype_reg) -> Self { + $newtype_reg_mem(RegMem::reg(r.into())) + } + } + + impl $newtype_reg_mem { + /// Construct a `RegMem` newtype from the given `RegMem`, or return + /// `None` if the `RegMem` is not a valid instance of this `RegMem` + /// newtype. + pub fn new(rm: RegMem) -> Option { + match rm { + RegMem::Mem { addr } => { + let mut _allow = true; + $( + if $aligned { + _allow = addr.aligned(); + } + )? + if _allow { + Some(Self(RegMem::Mem { addr })) + } else { + None + } + } + RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()), + } + } + + /// Like `Self::new(rm).unwrap()` but with better panic messages + /// in case of failure. + pub fn unwrap_new(rm: RegMem) -> Self { + match rm { + RegMem::Mem { addr } => { + $( + if $aligned && !addr.aligned() { + panic!( + "cannot create {} from an unaligned memory address: {addr:?}", + stringify!($newtype_reg_mem), + ); + } + )? + Self(RegMem::Mem { addr }) + } + RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), + } + } + + /// Convert this newtype into its underlying `RegMem`. + pub fn to_reg_mem(self) -> RegMem { + self.0 + } + + #[allow(dead_code)] // Used by some newtypes and not others. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + self.0.get_operands(collector); + } + } + impl PrettyPrint for $newtype_reg_mem { + fn pretty_print(&self, size: u8) -> String { + self.0.pretty_print(size) + } + } + )* + + $( + /// A newtype wrapper around `RegMemImm`. + #[derive(Clone, Debug)] + pub struct $newtype_reg_mem_imm(RegMemImm); + + impl From<$newtype_reg_mem_imm> for RegMemImm { + fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm { + rmi.0 + } + } + impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm { + fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm { + &rmi.0 + } + } + + impl From<$newtype_reg> for $newtype_reg_mem_imm { + fn from(r: $newtype_reg) -> Self { + $newtype_reg_mem_imm(RegMemImm::reg(r.into())) + } + } + + impl $newtype_reg_mem_imm { + /// Construct this newtype from the given `RegMemImm`, or return + /// `None` if the `RegMemImm` is not a valid instance of this + /// newtype. + pub fn new(rmi: RegMemImm) -> Option { + match rmi { + RegMemImm::Imm { .. } => Some(Self(rmi)), + RegMemImm::Mem { addr } => { + let mut _allow = true; + $( + if $aligned_imm { + _allow = addr.aligned(); + } + )? + if _allow { + Some(Self(RegMemImm::Mem { addr })) + } else { + None + } + } + RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()), + } + } + + /// Like `Self::new(rmi).unwrap()` but with better panic + /// messages in case of failure. + pub fn unwrap_new(rmi: RegMemImm) -> Self { + match rmi { + RegMemImm::Imm { .. } => Self(rmi), + RegMemImm::Mem { addr } => { + $( + if $aligned_imm && !addr.aligned() { + panic!( + "cannot construct {} from unaligned memory address: {:?}", + stringify!($newtype_reg_mem_imm), + addr, + ); + } + )? + Self(RegMemImm::Mem { addr }) + + } + RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), + } + } + + /// Convert this newtype into its underlying `RegMemImm`. + #[allow(dead_code)] // Used by some newtypes and not others. + pub fn to_reg_mem_imm(self) -> RegMemImm { + self.0 + } + + #[allow(dead_code)] // Used by some newtypes and not others. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + self.0.get_operands(collector); + } + } + + impl PrettyPrint for $newtype_reg_mem_imm { + fn pretty_print(&self, size: u8) -> String { + self.0.pretty_print(size) + } + } + )* + + /// A newtype wrapper around `Imm8Reg`. + #[derive(Clone, Debug)] + #[allow(dead_code)] // Used by some newtypes and not others. + pub struct $newtype_imm8_reg(Imm8Reg); + + impl From<$newtype_reg> for $newtype_imm8_reg { + fn from(r: $newtype_reg) -> Self { + Self(Imm8Reg::Reg { reg: r.to_reg() }) + } + } + + impl $newtype_imm8_reg { + /// Construct this newtype from the given `Imm8Reg`, or return + /// `None` if the `Imm8Reg` is not a valid instance of this newtype. + #[allow(dead_code)] // Used by some newtypes and not others. + pub fn new(imm8_reg: Imm8Reg) -> Option { + match imm8_reg { + Imm8Reg::Imm8 { .. } => Some(Self(imm8_reg)), + Imm8Reg::Reg { reg } => Some($newtype_reg::new(reg)?.into()), + } + } + + /// Like `Self::new(imm8_reg).unwrap()` but with better panic + /// messages on failure. + pub fn unwrap_new(imm8_reg: Imm8Reg) -> Self { + match imm8_reg { + Imm8Reg::Imm8 { .. } => Self(imm8_reg), + Imm8Reg::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), + } + } + + /// Borrow this newtype as its underlying `Imm8Reg`. + #[allow(dead_code)] // Used by some newtypes and not others. + pub fn as_imm8_reg(&self) -> &Imm8Reg { + &self.0 + } + + /// Borrow this newtype as its underlying `Imm8Reg`. + #[allow(dead_code)] // Used by some newtypes and not others. + pub fn as_imm8_reg_mut(&mut self) -> &mut Imm8Reg { + &mut self.0 + } + } + }; +} + +// Define a newtype of `Reg` for general-purpose registers. +newtype_of_reg!( + Gpr, + WritableGpr, + OptionWritableGpr, + reg_mem: (GprMem), + reg_mem_imm: (GprMemImm), + Imm8Gpr, + |reg| reg.class() == RegClass::Int +); + +// Define a newtype of `Reg` for XMM registers. +newtype_of_reg!( + Xmm, + WritableXmm, + OptionWritableXmm, + reg_mem: (XmmMem, XmmMemAligned aligned:true), + reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true), + Imm8Xmm, + |reg| reg.class() == RegClass::Float +); + +// N.B.: `Amode` is defined in `inst.isle`. We add some convenience +// constructors here. + +// Re-export the type from the ISLE generated code. +pub use crate::isa::x64::lower::isle::generated_code::Amode; + +impl Amode { + /// Create an immediate sign-extended and register addressing mode. + pub fn imm_reg(simm32: i32, base: Reg) -> Self { + debug_assert!(base.class() == RegClass::Int); + Self::ImmReg { + simm32, + base, + flags: MemFlags::trusted(), + } + } + + /// Create a sign-extended-32-to-64 with register and shift addressing mode. + pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self { + debug_assert!(base.class() == RegClass::Int); + debug_assert!(index.class() == RegClass::Int); + debug_assert!(shift <= 3); + Self::ImmRegRegShift { + simm32, + base, + index, + shift, + flags: MemFlags::trusted(), + } + } + + pub(crate) fn rip_relative(target: MachLabel) -> Self { + Self::RipRelative { target } + } + + /// Set the specified [MemFlags] to the [Amode]. + pub fn with_flags(&self, flags: MemFlags) -> Self { + match self { + &Self::ImmReg { simm32, base, .. } => Self::ImmReg { + simm32, + base, + flags, + }, + &Self::ImmRegRegShift { + simm32, + base, + index, + shift, + .. + } => Self::ImmRegRegShift { + simm32, + base, + index, + shift, + flags, + }, + _ => panic!("Amode {self:?} cannot take memflags"), + } + } + + /// Add the registers mentioned by `self` to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + Amode::ImmReg { base, .. } => { + if *base != regs::rbp() && *base != regs::rsp() { + collector.reg_use(base); + } + } + Amode::ImmRegRegShift { base, index, .. } => { + debug_assert_ne!(base.to_reg(), regs::rbp()); + debug_assert_ne!(base.to_reg(), regs::rsp()); + collector.reg_use(base); + debug_assert_ne!(index.to_reg(), regs::rbp()); + debug_assert_ne!(index.to_reg(), regs::rsp()); + collector.reg_use(index); + } + Amode::RipRelative { .. } => { + // RIP isn't involved in regalloc. + } + } + } + + /// Same as `get_operands`, but add the registers in the "late" phase. + pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { + match self { + Amode::ImmReg { base, .. } => { + collector.reg_late_use(base); + } + Amode::ImmRegRegShift { base, index, .. } => { + collector.reg_late_use(base); + collector.reg_late_use(index); + } + Amode::RipRelative { .. } => { + // RIP isn't involved in regalloc. + } + } + } + + pub(crate) fn get_flags(&self) -> MemFlags { + match self { + Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags, + Amode::RipRelative { .. } => MemFlags::trusted(), + } + } + + /// Offset the amode by a fixed offset. + pub(crate) fn offset(&self, offset: i32) -> Self { + let mut ret = self.clone(); + match &mut ret { + &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset, + &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset, + _ => panic!("Cannot offset amode: {self:?}"), + } + ret + } + + pub(crate) fn aligned(&self) -> bool { + self.get_flags().aligned() + } +} + +impl PrettyPrint for Amode { + fn pretty_print(&self, _size: u8) -> String { + match self { + Amode::ImmReg { simm32, base, .. } => { + // Note: size is always 8; the address is 64 bits, + // even if the addressed operand is smaller. + format!("{}({})", *simm32, pretty_print_reg(*base, 8)) + } + Amode::ImmRegRegShift { + simm32, + base, + index, + shift, + .. + } => format!( + "{}({},{},{})", + *simm32, + pretty_print_reg(base.to_reg(), 8), + pretty_print_reg(index.to_reg(), 8), + 1 << shift + ), + Amode::RipRelative { ref target } => format!("label{}(%rip)", target.get()), + } + } +} + +/// A Memory Address. These denote a 64-bit value only. +/// Used for usual addressing modes as well as addressing modes used during compilation, when the +/// moving SP offset is not known. +#[derive(Clone, Debug)] +pub enum SyntheticAmode { + /// A real amode. + Real(Amode), + + /// A (virtual) offset into the incoming argument area. + IncomingArg { + /// The downward offset from the start of the incoming argument area. + offset: u32, + }, + + /// A (virtual) offset to the slot area of the function frame, which lies just above the + /// outgoing arguments. + SlotOffset { + /// The offset into the slot area. + simm32: i32, + }, + + /// A virtual offset to a constant that will be emitted in the constant section of the buffer. + ConstantOffset(VCodeConstant), +} + +impl SyntheticAmode { + /// Create a real addressing mode. + pub fn real(amode: Amode) -> Self { + Self::Real(amode) + } + + pub(crate) fn slot_offset(simm32: i32) -> Self { + SyntheticAmode::SlotOffset { simm32 } + } + + /// Add the registers mentioned by `self` to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + SyntheticAmode::Real(addr) => addr.get_operands(collector), + SyntheticAmode::IncomingArg { .. } => { + // Nothing to do; the base is known and isn't involved in regalloc. + } + SyntheticAmode::SlotOffset { .. } => { + // Nothing to do; the base is SP and isn't involved in regalloc. + } + SyntheticAmode::ConstantOffset(_) => {} + } + } + + /// Same as `get_operands`, but add the register in the "late" phase. + pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { + match self { + SyntheticAmode::Real(addr) => addr.get_operands_late(collector), + SyntheticAmode::IncomingArg { .. } => { + // Nothing to do; the base is known and isn't involved in regalloc. + } + SyntheticAmode::SlotOffset { .. } => { + // Nothing to do; the base is SP and isn't involved in regalloc. + } + SyntheticAmode::ConstantOffset(_) => {} + } + } + + pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer) -> Amode { + match self { + SyntheticAmode::Real(addr) => addr.clone(), + SyntheticAmode::IncomingArg { offset } => { + // NOTE: this could be made relative to RSP by adding additional + // offsets from the frame_layout. + let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size; + Amode::imm_reg( + i32::try_from(args_max_fp_offset - offset).unwrap(), + regs::rbp(), + ) + } + SyntheticAmode::SlotOffset { simm32 } => { + let off = *simm32 as i64 + i64::from(frame.outgoing_args_size); + Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp()) + } + SyntheticAmode::ConstantOffset(c) => { + Amode::rip_relative(buffer.get_label_for_constant(*c)) + } + } + } + + pub(crate) fn aligned(&self) -> bool { + match self { + SyntheticAmode::Real(addr) => addr.aligned(), + &SyntheticAmode::IncomingArg { .. } + | SyntheticAmode::SlotOffset { .. } + | SyntheticAmode::ConstantOffset { .. } => true, + } + } +} + +impl Into for Amode { + fn into(self) -> SyntheticAmode { + SyntheticAmode::Real(self) + } +} + +impl Into for VCodeConstant { + fn into(self) -> SyntheticAmode { + SyntheticAmode::ConstantOffset(self) + } +} + +impl PrettyPrint for SyntheticAmode { + fn pretty_print(&self, _size: u8) -> String { + match self { + // See note in `Amode` regarding constant size of `8`. + SyntheticAmode::Real(addr) => addr.pretty_print(8), + &SyntheticAmode::IncomingArg { offset } => { + format!("rbp(stack args max - {offset})") + } + SyntheticAmode::SlotOffset { simm32 } => { + format!("rsp({} + virtual offset)", *simm32) + } + SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()), + } + } +} + +/// An operand which is either an integer Register, a value in Memory or an Immediate. This can +/// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only +/// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by +/// `simm32` is its sign-extension out to 64 bits. +#[derive(Clone, Debug)] +pub enum RegMemImm { + /// A register operand. + Reg { + /// The underlying register. + reg: Reg, + }, + /// A memory operand. + Mem { + /// The memory address. + addr: SyntheticAmode, + }, + /// An immediate operand. + Imm { + /// The immediate value. + simm32: u32, + }, +} + +impl RegMemImm { + /// Create a register operand. + pub fn reg(reg: Reg) -> Self { + debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); + Self::Reg { reg } + } + + /// Create a memory operand. + pub fn mem(addr: impl Into) -> Self { + Self::Mem { addr: addr.into() } + } + + /// Create an immediate operand. + pub fn imm(simm32: u32) -> Self { + Self::Imm { simm32 } + } + + /// Asserts that in register mode, the reg class is the one that's expected. + pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { + if let Self::Reg { reg } = self { + debug_assert_eq!(reg.class(), expected_reg_class); + } + } + + /// Add the regs mentioned by `self` to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + Self::Reg { reg } => collector.reg_use(reg), + Self::Mem { addr } => addr.get_operands(collector), + Self::Imm { .. } => {} + } + } +} + +impl From for RegMemImm { + fn from(rm: RegMem) -> RegMemImm { + match rm { + RegMem::Reg { reg } => RegMemImm::Reg { reg }, + RegMem::Mem { addr } => RegMemImm::Mem { addr }, + } + } +} + +impl From for RegMemImm { + fn from(reg: Reg) -> Self { + RegMemImm::Reg { reg } + } +} + +impl PrettyPrint for RegMemImm { + fn pretty_print(&self, size: u8) -> String { + match self { + Self::Reg { reg } => pretty_print_reg(*reg, size), + Self::Mem { addr } => addr.pretty_print(size), + Self::Imm { simm32 } => format!("${}", *simm32 as i32), + } + } +} + +/// An operand which is either an 8-bit integer immediate or a register. +#[derive(Clone, Debug)] +pub enum Imm8Reg { + /// 8-bit immediate operand. + Imm8 { + /// The 8-bit immediate value. + imm: u8, + }, + /// A register operand. + Reg { + /// The underlying register. + reg: Reg, + }, +} + +impl From for Imm8Reg { + fn from(imm: u8) -> Self { + Self::Imm8 { imm } + } +} + +impl From for Imm8Reg { + fn from(reg: Reg) -> Self { + Self::Reg { reg } + } +} + +/// An operand which is either an integer Register or a value in Memory. This can denote an 8, 16, +/// 32, 64, or 128 bit value. +#[derive(Clone, Debug)] +pub enum RegMem { + /// A register operand. + Reg { + /// The underlying register. + reg: Reg, + }, + /// A memory operand. + Mem { + /// The memory address. + addr: SyntheticAmode, + }, +} + +impl RegMem { + /// Create a register operand. + pub fn reg(reg: Reg) -> Self { + debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); + Self::Reg { reg } + } + + /// Create a memory operand. + pub fn mem(addr: impl Into) -> Self { + Self::Mem { addr: addr.into() } + } + /// Asserts that in register mode, the reg class is the one that's expected. + pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { + if let Self::Reg { reg } = self { + debug_assert_eq!(reg.class(), expected_reg_class); + } + } + /// Add the regs mentioned by `self` to `collector`. + pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + match self { + RegMem::Reg { reg } => collector.reg_use(reg), + RegMem::Mem { addr, .. } => addr.get_operands(collector), + } + } +} + +impl From for RegMem { + fn from(reg: Reg) -> RegMem { + RegMem::Reg { reg } + } +} + +impl From> for RegMem { + fn from(r: Writable) -> Self { + RegMem::reg(r.to_reg()) + } +} + +impl PrettyPrint for RegMem { + fn pretty_print(&self, size: u8) -> String { + match self { + RegMem::Reg { reg } => pretty_print_reg(*reg, size), + RegMem::Mem { addr, .. } => addr.pretty_print(size), + } + } +} + +/// Some basic ALU operations. +#[derive(Copy, Clone, PartialEq)] +pub enum AluRmiROpcode { + /// Add operation. + Add, + /// Add with carry. + Adc, + /// Integer subtraction. + Sub, + /// Integer subtraction with borrow. + Sbb, + /// Bitwise AND operation. + And, + /// Bitwise inclusive OR. + Or, + /// Bitwise exclusive OR. + Xor, +} + +impl fmt::Debug for AluRmiROpcode { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let name = match self { + AluRmiROpcode::Add => "add", + AluRmiROpcode::Adc => "adc", + AluRmiROpcode::Sub => "sub", + AluRmiROpcode::Sbb => "sbb", + AluRmiROpcode::And => "and", + AluRmiROpcode::Or => "or", + AluRmiROpcode::Xor => "xor", + }; + write!(fmt, "{name}") + } +} + +impl fmt::Display for AluRmiROpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +pub use crate::isa::x64::lower::isle::generated_code::AluRmROpcode; + +impl AluRmROpcode { + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + AluRmROpcode::Andn => smallvec![InstructionSet::BMI1], + AluRmROpcode::Sarx | AluRmROpcode::Shrx | AluRmROpcode::Shlx | AluRmROpcode::Bzhi => { + smallvec![InstructionSet::BMI2] + } + } + } +} + +impl fmt::Display for AluRmROpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&format!("{self:?}").to_lowercase()) + } +} + +#[derive(Clone, PartialEq)] +/// Unary operations requiring register or memory and register operands. +pub enum UnaryRmROpcode { + /// Bit-scan reverse. + Bsr, + /// Bit-scan forward. + Bsf, + /// Counts leading zeroes (Leading Zero CouNT). + Lzcnt, + /// Counts trailing zeroes (Trailing Zero CouNT). + Tzcnt, + /// Counts the number of ones (POPulation CouNT). + Popcnt, +} + +impl UnaryRmROpcode { + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + UnaryRmROpcode::Bsr | UnaryRmROpcode::Bsf => smallvec![], + UnaryRmROpcode::Lzcnt => smallvec![InstructionSet::Lzcnt], + UnaryRmROpcode::Tzcnt => smallvec![InstructionSet::BMI1], + UnaryRmROpcode::Popcnt => smallvec![InstructionSet::Popcnt], + } + } +} + +impl fmt::Debug for UnaryRmROpcode { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + UnaryRmROpcode::Bsr => write!(fmt, "bsr"), + UnaryRmROpcode::Bsf => write!(fmt, "bsf"), + UnaryRmROpcode::Lzcnt => write!(fmt, "lzcnt"), + UnaryRmROpcode::Tzcnt => write!(fmt, "tzcnt"), + UnaryRmROpcode::Popcnt => write!(fmt, "popcnt"), + } + } +} + +impl fmt::Display for UnaryRmROpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +pub use crate::isa::x64::lower::isle::generated_code::UnaryRmRVexOpcode; + +impl UnaryRmRVexOpcode { + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + UnaryRmRVexOpcode::Blsi | UnaryRmRVexOpcode::Blsmsk | UnaryRmRVexOpcode::Blsr => { + smallvec![InstructionSet::BMI1] + } + } + } +} + +impl fmt::Display for UnaryRmRVexOpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&format!("{self:?}").to_lowercase()) + } +} + +pub use crate::isa::x64::lower::isle::generated_code::UnaryRmRImmVexOpcode; + +impl UnaryRmRImmVexOpcode { + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + UnaryRmRImmVexOpcode::Rorx => { + smallvec![InstructionSet::BMI2] + } + } + } +} + +impl fmt::Display for UnaryRmRImmVexOpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&format!("{self:?}").to_lowercase()) + } +} + +#[derive(Clone, Copy, PartialEq)] +/// Comparison operations. +pub enum CmpOpcode { + /// CMP instruction: compute `a - b` and set flags from result. + Cmp, + /// TEST instruction: compute `a & b` and set flags from result. + Test, +} + +#[derive(Debug)] +pub(crate) enum InstructionSet { + SSE, + SSE2, + CMPXCHG16b, + SSSE3, + SSE41, + SSE42, + Popcnt, + Lzcnt, + BMI1, + #[allow(dead_code)] // never constructed (yet). + BMI2, + FMA, + AVX, + AVX2, + AVX512BITALG, + AVX512DQ, + AVX512F, + AVX512VBMI, + AVX512VL, +} + +/// Some SSE operations requiring 2 operands r/m and r. +#[derive(Clone, Copy, PartialEq)] +#[allow(dead_code)] // some variants here aren't used just yet +#[allow(missing_docs)] +pub enum SseOpcode { + Addps, + Addpd, + Addss, + Addsd, + Andps, + Andpd, + Andnps, + Andnpd, + Blendvpd, + Blendvps, + Comiss, + Comisd, + Cmpps, + Cmppd, + Cmpss, + Cmpsd, + Cvtdq2ps, + Cvtdq2pd, + Cvtpd2ps, + Cvtps2pd, + Cvtsd2ss, + Cvtsd2si, + Cvtsi2ss, + Cvtsi2sd, + Cvtss2si, + Cvtss2sd, + Cvttpd2dq, + Cvttps2dq, + Cvttss2si, + Cvttsd2si, + Divps, + Divpd, + Divss, + Divsd, + Insertps, + Maxps, + Maxpd, + Maxss, + Maxsd, + Minps, + Minpd, + Minss, + Minsd, + Movaps, + Movapd, + Movd, + Movdqa, + Movdqu, + Movlhps, + Movmskps, + Movmskpd, + Movq, + Movss, + Movsd, + Movups, + Movupd, + Mulps, + Mulpd, + Mulss, + Mulsd, + Orps, + Orpd, + Pabsb, + Pabsw, + Pabsd, + Packssdw, + Packsswb, + Packusdw, + Packuswb, + Paddb, + Paddd, + Paddq, + Paddw, + Paddsb, + Paddsw, + Paddusb, + Paddusw, + Palignr, + Pand, + Pandn, + Pavgb, + Pavgw, + Pblendvb, + Pcmpeqb, + Pcmpeqw, + Pcmpeqd, + Pcmpeqq, + Pcmpgtb, + Pcmpgtw, + Pcmpgtd, + Pcmpgtq, + Pextrb, + Pextrw, + Pextrd, + Pextrq, + Pinsrb, + Pinsrw, + Pinsrd, + Pmaddubsw, + Pmaddwd, + Pmaxsb, + Pmaxsw, + Pmaxsd, + Pmaxub, + Pmaxuw, + Pmaxud, + Pminsb, + Pminsw, + Pminsd, + Pminub, + Pminuw, + Pminud, + Pmovmskb, + Pmovsxbd, + Pmovsxbw, + Pmovsxbq, + Pmovsxwd, + Pmovsxwq, + Pmovsxdq, + Pmovzxbd, + Pmovzxbw, + Pmovzxbq, + Pmovzxwd, + Pmovzxwq, + Pmovzxdq, + Pmuldq, + Pmulhw, + Pmulhuw, + Pmulhrsw, + Pmulld, + Pmullw, + Pmuludq, + Por, + Pshufb, + Pshufd, + Psllw, + Pslld, + Psllq, + Psraw, + Psrad, + Psrlw, + Psrld, + Psrlq, + Psubb, + Psubd, + Psubq, + Psubw, + Psubsb, + Psubsw, + Psubusb, + Psubusw, + Ptest, + Punpckhbw, + Punpckhwd, + Punpcklbw, + Punpcklwd, + Pxor, + Rcpss, + Roundps, + Roundpd, + Roundss, + Roundsd, + Rsqrtss, + Shufps, + Sqrtps, + Sqrtpd, + Sqrtss, + Sqrtsd, + Subps, + Subpd, + Subss, + Subsd, + Ucomiss, + Ucomisd, + Unpcklps, + Unpcklpd, + Unpckhps, + Xorps, + Xorpd, + Phaddw, + Phaddd, + Punpckhdq, + Punpckldq, + Punpckhqdq, + Punpcklqdq, + Pshuflw, + Pshufhw, + Pblendw, + Movddup, +} + +impl SseOpcode { + /// Which `InstructionSet` is the first supporting this opcode? + pub(crate) fn available_from(&self) -> InstructionSet { + use InstructionSet::*; + match self { + SseOpcode::Addps + | SseOpcode::Addss + | SseOpcode::Andps + | SseOpcode::Andnps + | SseOpcode::Comiss + | SseOpcode::Cmpps + | SseOpcode::Cmpss + | SseOpcode::Cvtsi2ss + | SseOpcode::Cvtss2si + | SseOpcode::Cvttss2si + | SseOpcode::Divps + | SseOpcode::Divss + | SseOpcode::Maxps + | SseOpcode::Maxss + | SseOpcode::Minps + | SseOpcode::Minss + | SseOpcode::Movaps + | SseOpcode::Movlhps + | SseOpcode::Movmskps + | SseOpcode::Movss + | SseOpcode::Movups + | SseOpcode::Mulps + | SseOpcode::Mulss + | SseOpcode::Orps + | SseOpcode::Rcpss + | SseOpcode::Rsqrtss + | SseOpcode::Shufps + | SseOpcode::Sqrtps + | SseOpcode::Sqrtss + | SseOpcode::Subps + | SseOpcode::Subss + | SseOpcode::Ucomiss + | SseOpcode::Unpcklps + | SseOpcode::Unpckhps + | SseOpcode::Xorps => SSE, + + SseOpcode::Addpd + | SseOpcode::Addsd + | SseOpcode::Andpd + | SseOpcode::Andnpd + | SseOpcode::Cmppd + | SseOpcode::Cmpsd + | SseOpcode::Comisd + | SseOpcode::Cvtdq2ps + | SseOpcode::Cvtdq2pd + | SseOpcode::Cvtpd2ps + | SseOpcode::Cvtps2pd + | SseOpcode::Cvtsd2ss + | SseOpcode::Cvtsd2si + | SseOpcode::Cvtsi2sd + | SseOpcode::Cvtss2sd + | SseOpcode::Cvttpd2dq + | SseOpcode::Cvttps2dq + | SseOpcode::Cvttsd2si + | SseOpcode::Divpd + | SseOpcode::Divsd + | SseOpcode::Maxpd + | SseOpcode::Maxsd + | SseOpcode::Minpd + | SseOpcode::Minsd + | SseOpcode::Movapd + | SseOpcode::Movd + | SseOpcode::Movmskpd + | SseOpcode::Movq + | SseOpcode::Movsd + | SseOpcode::Movupd + | SseOpcode::Movdqa + | SseOpcode::Movdqu + | SseOpcode::Mulpd + | SseOpcode::Mulsd + | SseOpcode::Orpd + | SseOpcode::Packssdw + | SseOpcode::Packsswb + | SseOpcode::Packuswb + | SseOpcode::Paddb + | SseOpcode::Paddd + | SseOpcode::Paddq + | SseOpcode::Paddw + | SseOpcode::Paddsb + | SseOpcode::Paddsw + | SseOpcode::Paddusb + | SseOpcode::Paddusw + | SseOpcode::Pand + | SseOpcode::Pandn + | SseOpcode::Pavgb + | SseOpcode::Pavgw + | SseOpcode::Pcmpeqb + | SseOpcode::Pcmpeqw + | SseOpcode::Pcmpeqd + | SseOpcode::Pcmpgtb + | SseOpcode::Pcmpgtw + | SseOpcode::Pcmpgtd + | SseOpcode::Pextrw + | SseOpcode::Pinsrw + | SseOpcode::Pmaddwd + | SseOpcode::Pmaxsw + | SseOpcode::Pmaxub + | SseOpcode::Pminsw + | SseOpcode::Pminub + | SseOpcode::Pmovmskb + | SseOpcode::Pmulhw + | SseOpcode::Pmulhuw + | SseOpcode::Pmullw + | SseOpcode::Pmuludq + | SseOpcode::Por + | SseOpcode::Pshufd + | SseOpcode::Psllw + | SseOpcode::Pslld + | SseOpcode::Psllq + | SseOpcode::Psraw + | SseOpcode::Psrad + | SseOpcode::Psrlw + | SseOpcode::Psrld + | SseOpcode::Psrlq + | SseOpcode::Psubb + | SseOpcode::Psubd + | SseOpcode::Psubq + | SseOpcode::Psubw + | SseOpcode::Psubsb + | SseOpcode::Psubsw + | SseOpcode::Psubusb + | SseOpcode::Psubusw + | SseOpcode::Punpckhbw + | SseOpcode::Punpckhwd + | SseOpcode::Punpcklbw + | SseOpcode::Punpcklwd + | SseOpcode::Pxor + | SseOpcode::Sqrtpd + | SseOpcode::Sqrtsd + | SseOpcode::Subpd + | SseOpcode::Subsd + | SseOpcode::Ucomisd + | SseOpcode::Xorpd + | SseOpcode::Punpckldq + | SseOpcode::Punpckhdq + | SseOpcode::Punpcklqdq + | SseOpcode::Punpckhqdq + | SseOpcode::Pshuflw + | SseOpcode::Pshufhw + | SseOpcode::Unpcklpd => SSE2, + + SseOpcode::Pabsb + | SseOpcode::Pabsw + | SseOpcode::Pabsd + | SseOpcode::Palignr + | SseOpcode::Pmulhrsw + | SseOpcode::Pshufb + | SseOpcode::Phaddw + | SseOpcode::Phaddd + | SseOpcode::Pmaddubsw + | SseOpcode::Movddup => SSSE3, + + SseOpcode::Blendvpd + | SseOpcode::Blendvps + | SseOpcode::Insertps + | SseOpcode::Packusdw + | SseOpcode::Pblendvb + | SseOpcode::Pcmpeqq + | SseOpcode::Pextrb + | SseOpcode::Pextrd + | SseOpcode::Pextrq + | SseOpcode::Pinsrb + | SseOpcode::Pinsrd + | SseOpcode::Pmaxsb + | SseOpcode::Pmaxsd + | SseOpcode::Pmaxuw + | SseOpcode::Pmaxud + | SseOpcode::Pminsb + | SseOpcode::Pminsd + | SseOpcode::Pminuw + | SseOpcode::Pminud + | SseOpcode::Pmovsxbd + | SseOpcode::Pmovsxbw + | SseOpcode::Pmovsxbq + | SseOpcode::Pmovsxwd + | SseOpcode::Pmovsxwq + | SseOpcode::Pmovsxdq + | SseOpcode::Pmovzxbd + | SseOpcode::Pmovzxbw + | SseOpcode::Pmovzxbq + | SseOpcode::Pmovzxwd + | SseOpcode::Pmovzxwq + | SseOpcode::Pmovzxdq + | SseOpcode::Pmuldq + | SseOpcode::Pmulld + | SseOpcode::Ptest + | SseOpcode::Roundps + | SseOpcode::Roundpd + | SseOpcode::Roundss + | SseOpcode::Roundsd + | SseOpcode::Pblendw => SSE41, + + SseOpcode::Pcmpgtq => SSE42, + } + } + + /// Returns the src operand size for an instruction. + pub(crate) fn src_size(&self) -> u8 { + match self { + SseOpcode::Movd => 4, + _ => 8, + } + } + + /// Is `src2` with this opcode a scalar, as for lane insertions? + pub(crate) fn has_scalar_src2(self) -> bool { + match self { + SseOpcode::Pinsrb | SseOpcode::Pinsrw | SseOpcode::Pinsrd => true, + SseOpcode::Pmovsxbw + | SseOpcode::Pmovsxbd + | SseOpcode::Pmovsxbq + | SseOpcode::Pmovsxwd + | SseOpcode::Pmovsxwq + | SseOpcode::Pmovsxdq => true, + SseOpcode::Pmovzxbw + | SseOpcode::Pmovzxbd + | SseOpcode::Pmovzxbq + | SseOpcode::Pmovzxwd + | SseOpcode::Pmovzxwq + | SseOpcode::Pmovzxdq => true, + _ => false, + } + } +} + +impl fmt::Debug for SseOpcode { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let name = match self { + SseOpcode::Addps => "addps", + SseOpcode::Addpd => "addpd", + SseOpcode::Addss => "addss", + SseOpcode::Addsd => "addsd", + SseOpcode::Andpd => "andpd", + SseOpcode::Andps => "andps", + SseOpcode::Andnps => "andnps", + SseOpcode::Andnpd => "andnpd", + SseOpcode::Blendvpd => "blendvpd", + SseOpcode::Blendvps => "blendvps", + SseOpcode::Cmpps => "cmpps", + SseOpcode::Cmppd => "cmppd", + SseOpcode::Cmpss => "cmpss", + SseOpcode::Cmpsd => "cmpsd", + SseOpcode::Comiss => "comiss", + SseOpcode::Comisd => "comisd", + SseOpcode::Cvtdq2ps => "cvtdq2ps", + SseOpcode::Cvtdq2pd => "cvtdq2pd", + SseOpcode::Cvtpd2ps => "cvtpd2ps", + SseOpcode::Cvtps2pd => "cvtps2pd", + SseOpcode::Cvtsd2ss => "cvtsd2ss", + SseOpcode::Cvtsd2si => "cvtsd2si", + SseOpcode::Cvtsi2ss => "cvtsi2ss", + SseOpcode::Cvtsi2sd => "cvtsi2sd", + SseOpcode::Cvtss2si => "cvtss2si", + SseOpcode::Cvtss2sd => "cvtss2sd", + SseOpcode::Cvttpd2dq => "cvttpd2dq", + SseOpcode::Cvttps2dq => "cvttps2dq", + SseOpcode::Cvttss2si => "cvttss2si", + SseOpcode::Cvttsd2si => "cvttsd2si", + SseOpcode::Divps => "divps", + SseOpcode::Divpd => "divpd", + SseOpcode::Divss => "divss", + SseOpcode::Divsd => "divsd", + SseOpcode::Insertps => "insertps", + SseOpcode::Maxps => "maxps", + SseOpcode::Maxpd => "maxpd", + SseOpcode::Maxss => "maxss", + SseOpcode::Maxsd => "maxsd", + SseOpcode::Minps => "minps", + SseOpcode::Minpd => "minpd", + SseOpcode::Minss => "minss", + SseOpcode::Minsd => "minsd", + SseOpcode::Movaps => "movaps", + SseOpcode::Movapd => "movapd", + SseOpcode::Movd => "movd", + SseOpcode::Movdqa => "movdqa", + SseOpcode::Movdqu => "movdqu", + SseOpcode::Movlhps => "movlhps", + SseOpcode::Movmskps => "movmskps", + SseOpcode::Movmskpd => "movmskpd", + SseOpcode::Movq => "movq", + SseOpcode::Movss => "movss", + SseOpcode::Movsd => "movsd", + SseOpcode::Movups => "movups", + SseOpcode::Movupd => "movupd", + SseOpcode::Mulps => "mulps", + SseOpcode::Mulpd => "mulpd", + SseOpcode::Mulss => "mulss", + SseOpcode::Mulsd => "mulsd", + SseOpcode::Orpd => "orpd", + SseOpcode::Orps => "orps", + SseOpcode::Pabsb => "pabsb", + SseOpcode::Pabsw => "pabsw", + SseOpcode::Pabsd => "pabsd", + SseOpcode::Packssdw => "packssdw", + SseOpcode::Packsswb => "packsswb", + SseOpcode::Packusdw => "packusdw", + SseOpcode::Packuswb => "packuswb", + SseOpcode::Paddb => "paddb", + SseOpcode::Paddd => "paddd", + SseOpcode::Paddq => "paddq", + SseOpcode::Paddw => "paddw", + SseOpcode::Paddsb => "paddsb", + SseOpcode::Paddsw => "paddsw", + SseOpcode::Paddusb => "paddusb", + SseOpcode::Paddusw => "paddusw", + SseOpcode::Palignr => "palignr", + SseOpcode::Pand => "pand", + SseOpcode::Pandn => "pandn", + SseOpcode::Pavgb => "pavgb", + SseOpcode::Pavgw => "pavgw", + SseOpcode::Pblendvb => "pblendvb", + SseOpcode::Pcmpeqb => "pcmpeqb", + SseOpcode::Pcmpeqw => "pcmpeqw", + SseOpcode::Pcmpeqd => "pcmpeqd", + SseOpcode::Pcmpeqq => "pcmpeqq", + SseOpcode::Pcmpgtb => "pcmpgtb", + SseOpcode::Pcmpgtw => "pcmpgtw", + SseOpcode::Pcmpgtd => "pcmpgtd", + SseOpcode::Pcmpgtq => "pcmpgtq", + SseOpcode::Pextrb => "pextrb", + SseOpcode::Pextrw => "pextrw", + SseOpcode::Pextrd => "pextrd", + SseOpcode::Pextrq => "pextrq", + SseOpcode::Pinsrb => "pinsrb", + SseOpcode::Pinsrw => "pinsrw", + SseOpcode::Pinsrd => "pinsrd", + SseOpcode::Pmaddubsw => "pmaddubsw", + SseOpcode::Pmaddwd => "pmaddwd", + SseOpcode::Pmaxsb => "pmaxsb", + SseOpcode::Pmaxsw => "pmaxsw", + SseOpcode::Pmaxsd => "pmaxsd", + SseOpcode::Pmaxub => "pmaxub", + SseOpcode::Pmaxuw => "pmaxuw", + SseOpcode::Pmaxud => "pmaxud", + SseOpcode::Pminsb => "pminsb", + SseOpcode::Pminsw => "pminsw", + SseOpcode::Pminsd => "pminsd", + SseOpcode::Pminub => "pminub", + SseOpcode::Pminuw => "pminuw", + SseOpcode::Pminud => "pminud", + SseOpcode::Pmovmskb => "pmovmskb", + SseOpcode::Pmovsxbd => "pmovsxbd", + SseOpcode::Pmovsxbw => "pmovsxbw", + SseOpcode::Pmovsxbq => "pmovsxbq", + SseOpcode::Pmovsxwd => "pmovsxwd", + SseOpcode::Pmovsxwq => "pmovsxwq", + SseOpcode::Pmovsxdq => "pmovsxdq", + SseOpcode::Pmovzxbd => "pmovzxbd", + SseOpcode::Pmovzxbw => "pmovzxbw", + SseOpcode::Pmovzxbq => "pmovzxbq", + SseOpcode::Pmovzxwd => "pmovzxwd", + SseOpcode::Pmovzxwq => "pmovzxwq", + SseOpcode::Pmovzxdq => "pmovzxdq", + SseOpcode::Pmuldq => "pmuldq", + SseOpcode::Pmulhw => "pmulhw", + SseOpcode::Pmulhuw => "pmulhuw", + SseOpcode::Pmulhrsw => "pmulhrsw", + SseOpcode::Pmulld => "pmulld", + SseOpcode::Pmullw => "pmullw", + SseOpcode::Pmuludq => "pmuludq", + SseOpcode::Por => "por", + SseOpcode::Pshufb => "pshufb", + SseOpcode::Pshufd => "pshufd", + SseOpcode::Psllw => "psllw", + SseOpcode::Pslld => "pslld", + SseOpcode::Psllq => "psllq", + SseOpcode::Psraw => "psraw", + SseOpcode::Psrad => "psrad", + SseOpcode::Psrlw => "psrlw", + SseOpcode::Psrld => "psrld", + SseOpcode::Psrlq => "psrlq", + SseOpcode::Psubb => "psubb", + SseOpcode::Psubd => "psubd", + SseOpcode::Psubq => "psubq", + SseOpcode::Psubw => "psubw", + SseOpcode::Psubsb => "psubsb", + SseOpcode::Psubsw => "psubsw", + SseOpcode::Psubusb => "psubusb", + SseOpcode::Psubusw => "psubusw", + SseOpcode::Ptest => "ptest", + SseOpcode::Punpckhbw => "punpckhbw", + SseOpcode::Punpckhwd => "punpckhwd", + SseOpcode::Punpcklbw => "punpcklbw", + SseOpcode::Punpcklwd => "punpcklwd", + SseOpcode::Pxor => "pxor", + SseOpcode::Rcpss => "rcpss", + SseOpcode::Roundps => "roundps", + SseOpcode::Roundpd => "roundpd", + SseOpcode::Roundss => "roundss", + SseOpcode::Roundsd => "roundsd", + SseOpcode::Rsqrtss => "rsqrtss", + SseOpcode::Shufps => "shufps", + SseOpcode::Sqrtps => "sqrtps", + SseOpcode::Sqrtpd => "sqrtpd", + SseOpcode::Sqrtss => "sqrtss", + SseOpcode::Sqrtsd => "sqrtsd", + SseOpcode::Subps => "subps", + SseOpcode::Subpd => "subpd", + SseOpcode::Subss => "subss", + SseOpcode::Subsd => "subsd", + SseOpcode::Ucomiss => "ucomiss", + SseOpcode::Ucomisd => "ucomisd", + SseOpcode::Unpcklps => "unpcklps", + SseOpcode::Unpckhps => "unpckhps", + SseOpcode::Xorps => "xorps", + SseOpcode::Xorpd => "xorpd", + SseOpcode::Phaddw => "phaddw", + SseOpcode::Phaddd => "phaddd", + SseOpcode::Punpckldq => "punpckldq", + SseOpcode::Punpckhdq => "punpckhdq", + SseOpcode::Punpcklqdq => "punpcklqdq", + SseOpcode::Punpckhqdq => "punpckhqdq", + SseOpcode::Pshuflw => "pshuflw", + SseOpcode::Pshufhw => "pshufhw", + SseOpcode::Pblendw => "pblendw", + SseOpcode::Movddup => "movddup", + SseOpcode::Unpcklpd => "unpcklpd", + }; + write!(fmt, "{name}") + } +} + +impl fmt::Display for SseOpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode; + +impl AvxOpcode { + /// Which `InstructionSet`s support the opcode? + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + AvxOpcode::Vfmadd213ss + | AvxOpcode::Vfmadd213sd + | AvxOpcode::Vfmadd213ps + | AvxOpcode::Vfmadd213pd + | AvxOpcode::Vfmadd132ss + | AvxOpcode::Vfmadd132sd + | AvxOpcode::Vfmadd132ps + | AvxOpcode::Vfmadd132pd + | AvxOpcode::Vfnmadd213ss + | AvxOpcode::Vfnmadd213sd + | AvxOpcode::Vfnmadd213ps + | AvxOpcode::Vfnmadd213pd + | AvxOpcode::Vfnmadd132ss + | AvxOpcode::Vfnmadd132sd + | AvxOpcode::Vfnmadd132ps + | AvxOpcode::Vfnmadd132pd + | AvxOpcode::Vfmsub213ss + | AvxOpcode::Vfmsub213sd + | AvxOpcode::Vfmsub213ps + | AvxOpcode::Vfmsub213pd + | AvxOpcode::Vfmsub132ss + | AvxOpcode::Vfmsub132sd + | AvxOpcode::Vfmsub132ps + | AvxOpcode::Vfmsub132pd + | AvxOpcode::Vfnmsub213ss + | AvxOpcode::Vfnmsub213sd + | AvxOpcode::Vfnmsub213ps + | AvxOpcode::Vfnmsub213pd + | AvxOpcode::Vfnmsub132ss + | AvxOpcode::Vfnmsub132sd + | AvxOpcode::Vfnmsub132ps + | AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA], + AvxOpcode::Vminps + | AvxOpcode::Vminpd + | AvxOpcode::Vmaxps + | AvxOpcode::Vmaxpd + | AvxOpcode::Vandnps + | AvxOpcode::Vandnpd + | AvxOpcode::Vpandn + | AvxOpcode::Vcmpps + | AvxOpcode::Vcmppd + | AvxOpcode::Vpsrlw + | AvxOpcode::Vpsrld + | AvxOpcode::Vpsrlq + | AvxOpcode::Vpaddb + | AvxOpcode::Vpaddw + | AvxOpcode::Vpaddd + | AvxOpcode::Vpaddq + | AvxOpcode::Vpaddsb + | AvxOpcode::Vpaddsw + | AvxOpcode::Vpaddusb + | AvxOpcode::Vpaddusw + | AvxOpcode::Vpsubb + | AvxOpcode::Vpsubw + | AvxOpcode::Vpsubd + | AvxOpcode::Vpsubq + | AvxOpcode::Vpsubsb + | AvxOpcode::Vpsubsw + | AvxOpcode::Vpsubusb + | AvxOpcode::Vpsubusw + | AvxOpcode::Vpavgb + | AvxOpcode::Vpavgw + | AvxOpcode::Vpand + | AvxOpcode::Vandps + | AvxOpcode::Vandpd + | AvxOpcode::Vpor + | AvxOpcode::Vorps + | AvxOpcode::Vorpd + | AvxOpcode::Vpxor + | AvxOpcode::Vxorps + | AvxOpcode::Vxorpd + | AvxOpcode::Vpmullw + | AvxOpcode::Vpmulld + | AvxOpcode::Vpmulhw + | AvxOpcode::Vpmulhd + | AvxOpcode::Vpmulhrsw + | AvxOpcode::Vpmulhuw + | AvxOpcode::Vpmuldq + | AvxOpcode::Vpmuludq + | AvxOpcode::Vpunpckhwd + | AvxOpcode::Vpunpcklwd + | AvxOpcode::Vunpcklps + | AvxOpcode::Vunpckhps + | AvxOpcode::Vaddps + | AvxOpcode::Vaddpd + | AvxOpcode::Vsubps + | AvxOpcode::Vsubpd + | AvxOpcode::Vmulps + | AvxOpcode::Vmulpd + | AvxOpcode::Vdivps + | AvxOpcode::Vdivpd + | AvxOpcode::Vpcmpeqb + | AvxOpcode::Vpcmpeqw + | AvxOpcode::Vpcmpeqd + | AvxOpcode::Vpcmpeqq + | AvxOpcode::Vpcmpgtb + | AvxOpcode::Vpcmpgtw + | AvxOpcode::Vpcmpgtd + | AvxOpcode::Vpcmpgtq + | AvxOpcode::Vblendvps + | AvxOpcode::Vblendvpd + | AvxOpcode::Vpblendvb + | AvxOpcode::Vmovlhps + | AvxOpcode::Vpminsb + | AvxOpcode::Vpminsw + | AvxOpcode::Vpminsd + | AvxOpcode::Vpminub + | AvxOpcode::Vpminuw + | AvxOpcode::Vpminud + | AvxOpcode::Vpmaxsb + | AvxOpcode::Vpmaxsw + | AvxOpcode::Vpmaxsd + | AvxOpcode::Vpmaxub + | AvxOpcode::Vpmaxuw + | AvxOpcode::Vpmaxud + | AvxOpcode::Vpunpcklbw + | AvxOpcode::Vpunpckhbw + | AvxOpcode::Vpacksswb + | AvxOpcode::Vpackssdw + | AvxOpcode::Vpackuswb + | AvxOpcode::Vpackusdw + | AvxOpcode::Vpalignr + | AvxOpcode::Vpinsrb + | AvxOpcode::Vpinsrw + | AvxOpcode::Vpinsrd + | AvxOpcode::Vpinsrq + | AvxOpcode::Vpmaddwd + | AvxOpcode::Vpmaddubsw + | AvxOpcode::Vinsertps + | AvxOpcode::Vpshufb + | AvxOpcode::Vshufps + | AvxOpcode::Vpsllw + | AvxOpcode::Vpslld + | AvxOpcode::Vpsllq + | AvxOpcode::Vpsraw + | AvxOpcode::Vpsrad + | AvxOpcode::Vpmovsxbw + | AvxOpcode::Vpmovzxbw + | AvxOpcode::Vpmovsxwd + | AvxOpcode::Vpmovzxwd + | AvxOpcode::Vpmovsxdq + | AvxOpcode::Vpmovzxdq + | AvxOpcode::Vaddss + | AvxOpcode::Vaddsd + | AvxOpcode::Vmulss + | AvxOpcode::Vmulsd + | AvxOpcode::Vsubss + | AvxOpcode::Vsubsd + | AvxOpcode::Vdivss + | AvxOpcode::Vdivsd + | AvxOpcode::Vpabsb + | AvxOpcode::Vpabsw + | AvxOpcode::Vpabsd + | AvxOpcode::Vminss + | AvxOpcode::Vminsd + | AvxOpcode::Vmaxss + | AvxOpcode::Vmaxsd + | AvxOpcode::Vsqrtps + | AvxOpcode::Vsqrtpd + | AvxOpcode::Vroundpd + | AvxOpcode::Vroundps + | AvxOpcode::Vcvtdq2pd + | AvxOpcode::Vcvtdq2ps + | AvxOpcode::Vcvtpd2ps + | AvxOpcode::Vcvtps2pd + | AvxOpcode::Vcvttpd2dq + | AvxOpcode::Vcvttps2dq + | AvxOpcode::Vphaddw + | AvxOpcode::Vphaddd + | AvxOpcode::Vpunpckldq + | AvxOpcode::Vpunpckhdq + | AvxOpcode::Vpunpcklqdq + | AvxOpcode::Vpunpckhqdq + | AvxOpcode::Vpshuflw + | AvxOpcode::Vpshufhw + | AvxOpcode::Vpshufd + | AvxOpcode::Vmovss + | AvxOpcode::Vmovsd + | AvxOpcode::Vmovups + | AvxOpcode::Vmovupd + | AvxOpcode::Vmovdqu + | AvxOpcode::Vpextrb + | AvxOpcode::Vpextrw + | AvxOpcode::Vpextrd + | AvxOpcode::Vpextrq + | AvxOpcode::Vpblendw + | AvxOpcode::Vmovddup + | AvxOpcode::Vbroadcastss + | AvxOpcode::Vmovd + | AvxOpcode::Vmovq + | AvxOpcode::Vmovmskps + | AvxOpcode::Vmovmskpd + | AvxOpcode::Vpmovmskb + | AvxOpcode::Vcvtsi2ss + | AvxOpcode::Vcvtsi2sd + | AvxOpcode::Vcvtss2sd + | AvxOpcode::Vcvtsd2ss + | AvxOpcode::Vsqrtss + | AvxOpcode::Vsqrtsd + | AvxOpcode::Vroundss + | AvxOpcode::Vroundsd + | AvxOpcode::Vunpcklpd + | AvxOpcode::Vptest + | AvxOpcode::Vucomiss + | AvxOpcode::Vucomisd => { + smallvec![InstructionSet::AVX] + } + + AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => { + smallvec![InstructionSet::AVX2] + } + } + } + + /// Is the opcode known to be commutative? + /// + /// Note that this method is not exhaustive, and there may be commutative + /// opcodes that we don't recognize as commutative. + pub(crate) fn is_commutative(&self) -> bool { + match *self { + AvxOpcode::Vpaddb + | AvxOpcode::Vpaddw + | AvxOpcode::Vpaddd + | AvxOpcode::Vpaddq + | AvxOpcode::Vpaddsb + | AvxOpcode::Vpaddsw + | AvxOpcode::Vpaddusb + | AvxOpcode::Vpaddusw + | AvxOpcode::Vpand + | AvxOpcode::Vandps + | AvxOpcode::Vandpd + | AvxOpcode::Vpor + | AvxOpcode::Vorps + | AvxOpcode::Vorpd + | AvxOpcode::Vpxor + | AvxOpcode::Vxorps + | AvxOpcode::Vxorpd + | AvxOpcode::Vpmuldq + | AvxOpcode::Vpmuludq + | AvxOpcode::Vaddps + | AvxOpcode::Vaddpd + | AvxOpcode::Vmulps + | AvxOpcode::Vmulpd + | AvxOpcode::Vpcmpeqb + | AvxOpcode::Vpcmpeqw + | AvxOpcode::Vpcmpeqd + | AvxOpcode::Vpcmpeqq + | AvxOpcode::Vaddss + | AvxOpcode::Vaddsd + | AvxOpcode::Vmulss + | AvxOpcode::Vmulsd => true, + _ => false, + } + } +} + +impl fmt::Display for AvxOpcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format!("{self:?}").to_lowercase().fmt(f) + } +} + +#[derive(Copy, Clone, PartialEq)] +#[allow(missing_docs)] +pub enum Avx512TupleType { + Full, + FullMem, + Mem128, +} + +pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode; + +impl Avx512Opcode { + /// Which `InstructionSet`s support the opcode? + pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + Avx512Opcode::Vcvtudq2ps + | Avx512Opcode::Vpabsq + | Avx512Opcode::Vpsraq + | Avx512Opcode::VpsraqImm => { + smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL] + } + Avx512Opcode::Vpermi2b => { + smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI] + } + Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ], + Avx512Opcode::Vpopcntb => { + smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG] + } + } + } + + /// What is the "TupleType" of this opcode, which affects the scaling factor + /// for 8-bit displacements when this instruction uses memory operands. + /// + /// This can be found in the encoding table for each instruction and is + /// interpreted according to Table 2-34 and 2-35 in the Intel instruction + /// manual. + pub fn tuple_type(&self) -> Avx512TupleType { + use Avx512Opcode::*; + use Avx512TupleType::*; + + match self { + Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full, + Vpermi2b | Vpopcntb => FullMem, + Vpsraq => Mem128, + } + } +} + +impl fmt::Display for Avx512Opcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = format!("{self:?}"); + f.write_str(&s.to_lowercase()) + } +} + +/// This defines the ways a value can be extended: either signed- or zero-extension, or none for +/// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which +/// values can be extended. +#[allow(dead_code)] +#[derive(Clone, PartialEq)] +pub enum ExtKind { + /// No extension. + None, + /// Sign-extend. + SignExtend, + /// Zero-extend. + ZeroExtend, +} + +/// These indicate ways of extending (widening) a value, using the Intel +/// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64 +#[derive(Clone, PartialEq)] +pub enum ExtMode { + /// Byte -> Longword. + BL, + /// Byte -> Quadword. + BQ, + /// Word -> Longword. + WL, + /// Word -> Quadword. + WQ, + /// Longword -> Quadword. + LQ, +} + +impl ExtMode { + /// Calculate the `ExtMode` from passed bit lengths of the from/to types. + pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option { + match (from_bits, to_bits) { + (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL), + (1, 64) | (8, 64) => Some(ExtMode::BQ), + (16, 32) => Some(ExtMode::WL), + (16, 64) => Some(ExtMode::WQ), + (32, 64) => Some(ExtMode::LQ), + _ => None, + } + } + + /// Return the source register size in bytes. + pub(crate) fn src_size(&self) -> u8 { + match self { + ExtMode::BL | ExtMode::BQ => 1, + ExtMode::WL | ExtMode::WQ => 2, + ExtMode::LQ => 4, + } + } + + /// Return the destination register size in bytes. + pub(crate) fn dst_size(&self) -> u8 { + match self { + ExtMode::BL | ExtMode::WL => 4, + ExtMode::BQ | ExtMode::WQ | ExtMode::LQ => 8, + } + } + + /// Source size, as an integer type. + pub(crate) fn src_type(&self) -> Type { + match self { + ExtMode::BL | ExtMode::BQ => I8, + ExtMode::WL | ExtMode::WQ => I16, + ExtMode::LQ => I32, + } + } +} + +impl fmt::Debug for ExtMode { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let name = match self { + ExtMode::BL => "bl", + ExtMode::BQ => "bq", + ExtMode::WL => "wl", + ExtMode::WQ => "wq", + ExtMode::LQ => "lq", + }; + write!(fmt, "{name}") + } +} + +impl fmt::Display for ExtMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// These indicate the form of a scalar shift/rotate: left, signed right, unsigned right. +#[derive(Clone, Copy)] +pub enum ShiftKind { + /// Left shift. + ShiftLeft, + /// Inserts zeros in the most significant bits. + ShiftRightLogical, + /// Replicates the sign bit in the most significant bits. + ShiftRightArithmetic, + /// Left rotation. + RotateLeft, + /// Right rotation. + RotateRight, +} + +impl fmt::Debug for ShiftKind { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let name = match self { + ShiftKind::ShiftLeft => "shl", + ShiftKind::ShiftRightLogical => "shr", + ShiftKind::ShiftRightArithmetic => "sar", + ShiftKind::RotateLeft => "rol", + ShiftKind::RotateRight => "ror", + }; + write!(fmt, "{name}") + } +} + +impl fmt::Display for ShiftKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// These indicate condition code tests. Not all are represented since not all are useful in +/// compiler-generated code. +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum CC { + /// overflow + O = 0, + /// no overflow + NO = 1, + + /// < unsigned + B = 2, + /// >= unsigned + NB = 3, + + /// zero + Z = 4, + /// not-zero + NZ = 5, + + /// <= unsigned + BE = 6, + /// > unsigned + NBE = 7, + + /// negative + S = 8, + /// not-negative + NS = 9, + + /// < signed + L = 12, + /// >= signed + NL = 13, + + /// <= signed + LE = 14, + /// > signed + NLE = 15, + + /// parity + P = 10, + + /// not parity + NP = 11, +} + +impl CC { + pub(crate) fn from_intcc(intcc: IntCC) -> Self { + match intcc { + IntCC::Equal => CC::Z, + IntCC::NotEqual => CC::NZ, + IntCC::SignedGreaterThanOrEqual => CC::NL, + IntCC::SignedGreaterThan => CC::NLE, + IntCC::SignedLessThanOrEqual => CC::LE, + IntCC::SignedLessThan => CC::L, + IntCC::UnsignedGreaterThanOrEqual => CC::NB, + IntCC::UnsignedGreaterThan => CC::NBE, + IntCC::UnsignedLessThanOrEqual => CC::BE, + IntCC::UnsignedLessThan => CC::B, + } + } + + pub(crate) fn invert(&self) -> Self { + match self { + CC::O => CC::NO, + CC::NO => CC::O, + + CC::B => CC::NB, + CC::NB => CC::B, + + CC::Z => CC::NZ, + CC::NZ => CC::Z, + + CC::BE => CC::NBE, + CC::NBE => CC::BE, + + CC::S => CC::NS, + CC::NS => CC::S, + + CC::L => CC::NL, + CC::NL => CC::L, + + CC::LE => CC::NLE, + CC::NLE => CC::LE, + + CC::P => CC::NP, + CC::NP => CC::P, + } + } + + pub(crate) fn get_enc(self) -> u8 { + self as u8 + } +} + +impl fmt::Debug for CC { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let name = match self { + CC::O => "o", + CC::NO => "no", + CC::B => "b", + CC::NB => "nb", + CC::Z => "z", + CC::NZ => "nz", + CC::BE => "be", + CC::NBE => "nbe", + CC::S => "s", + CC::NS => "ns", + CC::L => "l", + CC::NL => "nl", + CC::LE => "le", + CC::NLE => "nle", + CC::P => "p", + CC::NP => "np", + }; + write!(fmt, "{name}") + } +} + +impl fmt::Display for CC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`, +/// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS +/// whereas [FcmpImm] is used as an immediate. +#[derive(Clone, Copy)] +pub enum FcmpImm { + /// Equal comparison. + Equal = 0x00, + /// Less than comparison. + LessThan = 0x01, + /// Less than or equal comparison. + LessThanOrEqual = 0x02, + /// Unordered. + Unordered = 0x03, + /// Not equal comparison. + NotEqual = 0x04, + /// Unordered of greater than or equal comparison. + UnorderedOrGreaterThanOrEqual = 0x05, + /// Unordered or greater than comparison. + UnorderedOrGreaterThan = 0x06, + /// Ordered. + Ordered = 0x07, +} + +impl FcmpImm { + pub(crate) fn encode(self) -> u8 { + self as u8 + } +} + +impl From for FcmpImm { + fn from(cond: FloatCC) -> Self { + match cond { + FloatCC::Equal => FcmpImm::Equal, + FloatCC::LessThan => FcmpImm::LessThan, + FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual, + FloatCC::Unordered => FcmpImm::Unordered, + FloatCC::NotEqual => FcmpImm::NotEqual, + FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual, + FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan, + FloatCC::Ordered => FcmpImm::Ordered, + _ => panic!("unable to create comparison predicate for {cond}"), + } + } +} + +/// Encode the rounding modes used as part of the Rounding Control field. +/// Note, these rounding immediates only consider the rounding control field +/// (i.e. the rounding mode) which only take up the first two bits when encoded. +/// However the rounding immediate which this field helps make up, also includes +/// bits 3 and 4 which define the rounding select and precision mask respectively. +/// These two bits are not defined here and are implicitly set to zero when encoded. +#[derive(Clone, Copy)] +pub enum RoundImm { + /// Round to nearest mode. + RoundNearest = 0x00, + /// Round down mode. + RoundDown = 0x01, + /// Round up mode. + RoundUp = 0x02, + /// Round to zero mode. + RoundZero = 0x03, +} + +impl RoundImm { + pub(crate) fn encode(self) -> u8 { + self as u8 + } +} + +/// An operand's size in bits. +#[derive(Clone, Copy, PartialEq)] +pub enum OperandSize { + /// 8-bit. + Size8, + /// 16-bit. + Size16, + /// 32-bit. + Size32, + /// 64-bit. + Size64, +} + +impl OperandSize { + pub(crate) fn from_bytes(num_bytes: u32) -> Self { + match num_bytes { + 1 => OperandSize::Size8, + 2 => OperandSize::Size16, + 4 => OperandSize::Size32, + 8 => OperandSize::Size64, + _ => unreachable!("Invalid OperandSize: {}", num_bytes), + } + } + + // Computes the OperandSize for a given type. + // For vectors, the OperandSize of the lanes is returned. + pub(crate) fn from_ty(ty: Type) -> Self { + Self::from_bytes(ty.lane_type().bytes()) + } + + // Check that the value of self is one of the allowed sizes. + pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool { + sizes.iter().any(|val| *self == *val) + } + + pub(crate) fn to_bytes(&self) -> u8 { + match self { + Self::Size8 => 1, + Self::Size16 => 2, + Self::Size32 => 4, + Self::Size64 => 8, + } + } + + pub(crate) fn to_bits(&self) -> u8 { + self.to_bytes() * 8 + } + + pub(crate) fn to_type(&self) -> Type { + match self { + Self::Size8 => I8, + Self::Size16 => I16, + Self::Size32 => I32, + Self::Size64 => I64, + } + } +} + +/// An x64 memory fence kind. +#[derive(Clone)] +#[allow(dead_code)] +pub enum FenceKind { + /// `mfence` instruction ("Memory Fence") + MFence, + /// `lfence` instruction ("Load Fence") + LFence, + /// `sfence` instruction ("Store Fence") + SFence, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit.rs new file mode 100644 index 00000000000000..3ad94fb948c6f1 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit.rs @@ -0,0 +1,4694 @@ +use crate::ir::immediates::{Ieee32, Ieee64}; +use crate::ir::KnownSymbol; +use crate::isa::x64::encoding::evex::{EvexInstruction, EvexVectorLength, RegisterOrAmode}; +use crate::isa::x64::encoding::rex::{ + emit_simm, emit_std_enc_enc, emit_std_enc_mem, emit_std_reg_mem, emit_std_reg_reg, int_reg_enc, + low8_will_sign_extend_to_32, low8_will_sign_extend_to_64, reg_enc, LegacyPrefixes, OpcodeMap, + RexFlags, +}; +use crate::isa::x64::encoding::vex::{VexInstruction, VexVectorLength}; +use crate::isa::x64::inst::args::*; +use crate::isa::x64::inst::*; +use crate::isa::x64::lower::isle::generated_code::{Atomic128RmwSeqOp, AtomicRmwSeqOp}; + +/// A small helper to generate a signed conversion instruction. +fn emit_signed_cvt( + sink: &mut MachBuffer, + info: &EmitInfo, + state: &mut EmitState, + // Required to be RealRegs. + src: Reg, + dst: Writable, + to_f64: bool, +) { + // Handle an unsigned int, which is the "easy" case: a signed conversion will do the + // right thing. + let op = if to_f64 { + SseOpcode::Cvtsi2sd + } else { + SseOpcode::Cvtsi2ss + }; + let dst = WritableXmm::from_writable_reg(dst).unwrap(); + Inst::CvtIntToFloat { + op, + dst, + src1: dst.to_reg(), + src2: GprMem::unwrap_new(RegMem::reg(src)), + src2_size: OperandSize::Size64, + } + .emit(sink, info, state); +} + +/// Emits a one way conditional jump if CC is set (true). +fn one_way_jmp(sink: &mut MachBuffer, cc: CC, label: MachLabel) { + let cond_start = sink.cur_offset(); + let cond_disp_off = cond_start + 2; + sink.use_label_at_offset(cond_disp_off, label, LabelUse::JmpRel32); + sink.put1(0x0F); + sink.put1(0x80 + cc.get_enc()); + sink.put4(0x0); +} + +/// Emits a relocation, attaching the current source location as well. +fn emit_reloc(sink: &mut MachBuffer, kind: Reloc, name: &ExternalName, addend: Addend) { + sink.add_reloc(kind, name, addend); +} + +/// The top-level emit function. +/// +/// Important! Do not add improved (shortened) encoding cases to existing +/// instructions without also adding tests for those improved encodings. That +/// is a dangerous game that leads to hard-to-track-down errors in the emitted +/// code. +/// +/// For all instructions, make sure to have test coverage for all of the +/// following situations. Do this by creating the cross product resulting from +/// applying the following rules to each operand: +/// +/// (1) for any insn that mentions a register: one test using a register from +/// the group [rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi] and a second one +/// using a register from the group [r8, r9, r10, r11, r12, r13, r14, r15]. +/// This helps detect incorrect REX prefix construction. +/// +/// (2) for any insn that mentions a byte register: one test for each of the +/// four encoding groups [al, cl, dl, bl], [spl, bpl, sil, dil], +/// [r8b .. r11b] and [r12b .. r15b]. This checks that +/// apparently-redundant REX prefixes are retained when required. +/// +/// (3) for any insn that contains an immediate field, check the following +/// cases: field is zero, field is in simm8 range (-128 .. 127), field is +/// in simm32 range (-0x8000_0000 .. 0x7FFF_FFFF). This is because some +/// instructions that require a 32-bit immediate have a short-form encoding +/// when the imm is in simm8 range. +/// +/// Rules (1), (2) and (3) don't apply for registers within address expressions +/// (`Addr`s). Those are already pretty well tested, and the registers in them +/// don't have any effect on the containing instruction (apart from possibly +/// require REX prefix bits). +/// +/// When choosing registers for a test, avoid using registers with the same +/// offset within a given group. For example, don't use rax and r8, since they +/// both have the lowest 3 bits as 000, and so the test won't detect errors +/// where those 3-bit register sub-fields are confused by the emitter. Instead +/// use (eg) rax (lo3 = 000) and r9 (lo3 = 001). Similarly, don't use (eg) cl +/// and bpl since they have the same offset in their group; use instead (eg) cl +/// and sil. +/// +/// For all instructions, also add a test that uses only low-half registers +/// (rax .. rdi, xmm0 .. xmm7) etc, so as to check that any redundant REX +/// prefixes are correctly omitted. This low-half restriction must apply to +/// _all_ registers in the insn, even those in address expressions. +/// +/// Following these rules creates large numbers of test cases, but it's the +/// only way to make the emitter reliable. +/// +/// Known possible improvements: +/// +/// * there's a shorter encoding for shl/shr/sar by a 1-bit immediate. (Do we +/// care?) +pub(crate) fn emit( + inst: &Inst, + sink: &mut MachBuffer, + info: &EmitInfo, + state: &mut EmitState, +) { + let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool { + match iset_requirement { + // Cranelift assumes SSE2 at least. + InstructionSet::SSE | InstructionSet::SSE2 => true, + InstructionSet::CMPXCHG16b => info.isa_flags.use_cmpxchg16b(), + InstructionSet::SSSE3 => info.isa_flags.use_ssse3(), + InstructionSet::SSE41 => info.isa_flags.use_sse41(), + InstructionSet::SSE42 => info.isa_flags.use_sse42(), + InstructionSet::Popcnt => info.isa_flags.use_popcnt(), + InstructionSet::Lzcnt => info.isa_flags.use_lzcnt(), + InstructionSet::BMI1 => info.isa_flags.use_bmi1(), + InstructionSet::BMI2 => info.isa_flags.has_bmi2(), + InstructionSet::FMA => info.isa_flags.has_fma(), + InstructionSet::AVX => info.isa_flags.has_avx(), + InstructionSet::AVX2 => info.isa_flags.has_avx2(), + InstructionSet::AVX512BITALG => info.isa_flags.has_avx512bitalg(), + InstructionSet::AVX512DQ => info.isa_flags.has_avx512dq(), + InstructionSet::AVX512F => info.isa_flags.has_avx512f(), + InstructionSet::AVX512VBMI => info.isa_flags.has_avx512vbmi(), + InstructionSet::AVX512VL => info.isa_flags.has_avx512vl(), + } + }; + + // Certain instructions may be present in more than one ISA feature set; we must at least match + // one of them in the target CPU. + let isa_requirements = inst.available_in_any_isa(); + if !isa_requirements.is_empty() && !isa_requirements.iter().all(matches_isa_flags) { + panic!( + "Cannot emit inst '{inst:?}' for target; failed to match ISA requirements: {isa_requirements:?}" + ) + } + + match inst { + Inst::AluRmiR { + size, + op, + src1, + src2, + dst: reg_g, + } => { + let src1 = src1.to_reg(); + let reg_g = reg_g.to_reg().to_reg(); + debug_assert_eq!(src1, reg_g); + let src2 = src2.clone().to_reg_mem_imm().clone(); + + let prefix = if *size == OperandSize::Size16 { + LegacyPrefixes::_66 + } else { + LegacyPrefixes::None + }; + + let mut rex = RexFlags::from(*size); + let (opcode_r, opcode_m, subopcode_i) = match op { + AluRmiROpcode::Add => (0x01, 0x03, 0), + AluRmiROpcode::Adc => (0x11, 0x13, 2), + AluRmiROpcode::Sub => (0x29, 0x2B, 5), + AluRmiROpcode::Sbb => (0x19, 0x1B, 3), + AluRmiROpcode::And => (0x21, 0x23, 4), + AluRmiROpcode::Or => (0x09, 0x0B, 1), + AluRmiROpcode::Xor => (0x31, 0x33, 6), + }; + + let (opcode_r, opcode_m) = if *size == OperandSize::Size8 { + (opcode_r - 1, opcode_m - 1) + } else { + (opcode_r, opcode_m) + }; + + if *size == OperandSize::Size8 { + debug_assert!(reg_g.is_real()); + rex.always_emit_if_8bit_needed(reg_g); + } + + match src2 { + RegMemImm::Reg { reg: reg_e } => { + if *size == OperandSize::Size8 { + debug_assert!(reg_e.is_real()); + rex.always_emit_if_8bit_needed(reg_e); + } + + // GCC/llvm use the swapped operand encoding (viz., the R/RM vs RM/R + // duality). Do this too, so as to be able to compare generated machine + // code easily. + emit_std_reg_reg(sink, prefix, opcode_r, 1, reg_e, reg_g, rex); + } + + RegMemImm::Mem { addr } => { + let amode = addr.finalize(state.frame_layout(), sink); + // Here we revert to the "normal" G-E ordering. + emit_std_reg_mem(sink, prefix, opcode_m, 1, reg_g, &amode, rex, 0); + } + + RegMemImm::Imm { simm32 } => { + let imm_size = if *size == OperandSize::Size8 { + 1 + } else { + if low8_will_sign_extend_to_32(simm32) { + 1 + } else { + if *size == OperandSize::Size16 { + 2 + } else { + 4 + } + } + }; + + let opcode = if *size == OperandSize::Size8 { + 0x80 + } else if low8_will_sign_extend_to_32(simm32) { + 0x83 + } else { + 0x81 + }; + + // And also here we use the "normal" G-E ordering. + let enc_g = int_reg_enc(reg_g); + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode_i, enc_g, rex); + emit_simm(sink, imm_size, simm32); + } + } + } + + &Inst::AluConstOp { op, size, dst } => { + let dst = WritableGpr::from_writable_reg(dst.to_writable_reg()).unwrap(); + emit( + &Inst::AluRmiR { + size, + op, + dst, + src1: dst.to_reg(), + src2: dst.to_reg().into(), + }, + sink, + info, + state, + ); + } + + Inst::AluRM { + size, + src1_dst, + src2, + op, + lock, + } => { + let src2 = src2.to_reg(); + let src1_dst = src1_dst.finalize(state.frame_layout(), sink).clone(); + + let opcode = match op { + AluRmiROpcode::Add => 0x01, + AluRmiROpcode::Sub => 0x29, + AluRmiROpcode::And => 0x21, + AluRmiROpcode::Or => 0x09, + AluRmiROpcode::Xor => 0x31, + _ => panic!("Unsupported read-modify-write ALU opcode"), + }; + + let prefix = match (size, lock) { + (OperandSize::Size16, false) => LegacyPrefixes::_66, + (OperandSize::Size16, true) => LegacyPrefixes::_66F0, + (_, false) => LegacyPrefixes::None, + (_, true) => LegacyPrefixes::_F0, + }; + let opcode = if *size == OperandSize::Size8 { + opcode - 1 + } else { + opcode + }; + + let mut rex = RexFlags::from(*size); + if *size == OperandSize::Size8 { + debug_assert!(src2.is_real()); + rex.always_emit_if_8bit_needed(src2); + } + + let enc_g = int_reg_enc(src2); + emit_std_enc_mem(sink, prefix, opcode, 1, enc_g, &src1_dst, rex, 0); + } + + Inst::AluRmRVex { + size, + op, + dst, + src1, + src2, + } => { + use AluRmROpcode::*; + use LegacyPrefixes as LP; + + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let w = match size { + OperandSize::Size32 => false, + OperandSize::Size64 => true, + + // the other cases would be rejected by isle constructors + _ => unreachable!(), + }; + + let (prefix, opcode) = match op { + Andn => (LP::None, 0xf2), + Sarx => (LP::_F3, 0xf7), + Shrx => (LP::_F2, 0xf7), + Shlx => (LP::_66, 0xf7), + Bzhi => (LP::None, 0xf5), + }; + + VexInstruction::new() + .prefix(prefix) + .map(OpcodeMap::_0F38) + .w(w) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .opcode(opcode) + .encode(sink); + } + + Inst::UnaryRmR { size, op, src, dst } => { + let dst = dst.to_reg().to_reg(); + let rex_flags = RexFlags::from(*size); + use UnaryRmROpcode::*; + let prefix = match size { + OperandSize::Size16 => match op { + Bsr | Bsf => LegacyPrefixes::_66, + Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_66F3, + }, + OperandSize::Size32 | OperandSize::Size64 => match op { + Bsr | Bsf => LegacyPrefixes::None, + Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_F3, + }, + _ => unreachable!(), + }; + + let (opcode, num_opcodes) = match op { + Bsr => (0x0fbd, 2), + Bsf => (0x0fbc, 2), + Lzcnt => (0x0fbd, 2), + Tzcnt => (0x0fbc, 2), + Popcnt => (0x0fb8, 2), + }; + + match src.clone().into() { + RegMem::Reg { reg: src } => { + emit_std_reg_reg(sink, prefix, opcode, num_opcodes, dst, src, rex_flags); + } + RegMem::Mem { addr: src } => { + let amode = src.finalize(state.frame_layout(), sink).clone(); + emit_std_reg_mem(sink, prefix, opcode, num_opcodes, dst, &amode, rex_flags, 0); + } + } + } + + Inst::UnaryRmRVex { size, op, src, dst } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (opcode, opcode_ext) = match op { + UnaryRmRVexOpcode::Blsr => (0xF3, 1), + UnaryRmRVexOpcode::Blsmsk => (0xF3, 2), + UnaryRmRVexOpcode::Blsi => (0xF3, 3), + }; + + VexInstruction::new() + .map(OpcodeMap::_0F38) + .w(*size == OperandSize::Size64) + .opcode(opcode) + .reg(opcode_ext) + .vvvv(dst.to_real_reg().unwrap().hw_enc()) + .rm(src) + .encode(sink); + } + + Inst::UnaryRmRImmVex { + size, + op, + src, + dst, + imm, + } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let opcode = match op { + UnaryRmRImmVexOpcode::Rorx => 0xF0, + }; + + VexInstruction::new() + .prefix(LegacyPrefixes::_F2) + .map(OpcodeMap::_0F3A) + .w(*size == OperandSize::Size64) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src) + .imm(*imm) + .encode(sink); + } + + Inst::Not { size, src, dst } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src, dst); + let rex_flags = RexFlags::from((*size, dst)); + let (opcode, prefix) = match size { + OperandSize::Size8 => (0xF6, LegacyPrefixes::None), + OperandSize::Size16 => (0xF7, LegacyPrefixes::_66), + OperandSize::Size32 => (0xF7, LegacyPrefixes::None), + OperandSize::Size64 => (0xF7, LegacyPrefixes::None), + }; + + let subopcode = 2; + let enc_src = int_reg_enc(dst); + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_src, rex_flags) + } + + Inst::Neg { size, src, dst } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src, dst); + let rex_flags = RexFlags::from((*size, dst)); + let (opcode, prefix) = match size { + OperandSize::Size8 => (0xF6, LegacyPrefixes::None), + OperandSize::Size16 => (0xF7, LegacyPrefixes::_66), + OperandSize::Size32 => (0xF7, LegacyPrefixes::None), + OperandSize::Size64 => (0xF7, LegacyPrefixes::None), + }; + + let subopcode = 3; + let enc_src = int_reg_enc(dst); + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_src, rex_flags) + } + + Inst::Div { + sign, + trap, + divisor, + .. + } + | Inst::Div8 { + sign, + trap, + divisor, + .. + } => { + let divisor = divisor.clone().to_reg_mem().clone(); + let size = match inst { + Inst::Div { + size, + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + .. + } => { + let dividend_lo = dividend_lo.to_reg(); + let dividend_hi = dividend_hi.to_reg(); + let dst_quotient = dst_quotient.to_reg().to_reg(); + let dst_remainder = dst_remainder.to_reg().to_reg(); + debug_assert_eq!(dividend_lo, regs::rax()); + debug_assert_eq!(dividend_hi, regs::rdx()); + debug_assert_eq!(dst_quotient, regs::rax()); + debug_assert_eq!(dst_remainder, regs::rdx()); + *size + } + Inst::Div8 { dividend, dst, .. } => { + let dividend = dividend.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(dividend, regs::rax()); + debug_assert_eq!(dst, regs::rax()); + OperandSize::Size8 + } + _ => unreachable!(), + }; + + let (opcode, prefix) = match size { + OperandSize::Size8 => (0xF6, LegacyPrefixes::None), + OperandSize::Size16 => (0xF7, LegacyPrefixes::_66), + OperandSize::Size32 => (0xF7, LegacyPrefixes::None), + OperandSize::Size64 => (0xF7, LegacyPrefixes::None), + }; + + sink.add_trap(*trap); + + let subopcode = match sign { + DivSignedness::Signed => 7, + DivSignedness::Unsigned => 6, + }; + match divisor { + RegMem::Reg { reg } => { + let src = int_reg_enc(reg); + emit_std_enc_enc( + sink, + prefix, + opcode, + 1, + subopcode, + src, + RexFlags::from((size, reg)), + ) + } + RegMem::Mem { addr: src } => { + let amode = src.finalize(state.frame_layout(), sink); + emit_std_enc_mem( + sink, + prefix, + opcode, + 1, + subopcode, + &amode, + RexFlags::from(size), + 0, + ); + } + } + } + + Inst::Mul { + signed, + size, + src1, + src2, + dst_lo, + dst_hi, + } => { + let src1 = src1.to_reg(); + let dst_lo = dst_lo.to_reg().to_reg(); + let dst_hi = dst_hi.to_reg().to_reg(); + debug_assert_eq!(src1, regs::rax()); + debug_assert_eq!(dst_lo, regs::rax()); + debug_assert_eq!(dst_hi, regs::rdx()); + let src2 = src2.clone().to_reg_mem().clone(); + + let rex_flags = RexFlags::from(*size); + let prefix = match size { + OperandSize::Size16 => LegacyPrefixes::_66, + OperandSize::Size32 => LegacyPrefixes::None, + OperandSize::Size64 => LegacyPrefixes::None, + _ => unreachable!(), + }; + + let subopcode = if *signed { 5 } else { 4 }; + match src2 { + RegMem::Reg { reg } => { + let src = int_reg_enc(reg); + emit_std_enc_enc(sink, prefix, 0xF7, 1, subopcode, src, rex_flags) + } + RegMem::Mem { addr: src } => { + let amode = src.finalize(state.frame_layout(), sink); + emit_std_enc_mem(sink, prefix, 0xF7, 1, subopcode, &amode, rex_flags, 0); + } + } + } + Inst::Mul8 { + signed, + src1, + src2, + dst, + } => { + let src1 = src1.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src1, regs::rax()); + debug_assert_eq!(dst, regs::rax()); + let src2 = src2.clone().to_reg_mem().clone(); + + let mut rex_flags = RexFlags::from(OperandSize::Size8); + let prefix = LegacyPrefixes::None; + let subopcode = if *signed { 5 } else { 4 }; + match src2 { + RegMem::Reg { reg } => { + // The intel manual states: + // + // > r/m8 can not be encoded to access the following byte + // > registers if a REX prefix is used: AH, BH, CH, DH + // + // And apparently that also means that a REX prefix must be + // used if it's not one of those registers. + if !(reg == regs::rax() + || reg == regs::rbx() + || reg == regs::rcx() + || reg == regs::rdx()) + { + rex_flags.always_emit(); + } + let src = int_reg_enc(reg); + emit_std_enc_enc(sink, prefix, 0xF6, 1, subopcode, src, rex_flags) + } + RegMem::Mem { addr } => { + let amode = addr.finalize(state.frame_layout(), sink); + emit_std_enc_mem(sink, prefix, 0xF6, 1, subopcode, &amode, rex_flags, 0); + } + } + } + Inst::IMul { + size, + src1, + src2, + dst, + } => { + let src1 = src1.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src1, dst); + let src2 = src2.clone().to_reg_mem().clone(); + + let rex = RexFlags::from(*size); + let prefix = LegacyPrefixes::None; + match src2 { + RegMem::Reg { reg } => { + emit_std_reg_reg(sink, prefix, 0x0FAF, 2, dst, reg, rex); + } + + RegMem::Mem { addr } => { + let amode = addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, 0x0FAF, 2, dst, &amode, rex, 0); + } + } + } + + Inst::IMulImm { + size, + src1, + src2, + dst, + } => { + let dst = dst.to_reg().to_reg(); + let src1 = src1.clone().to_reg_mem().clone(); + + let rex = RexFlags::from(*size); + let prefix = match size { + // NB: the intel manual doesn't seem to mention this prefix as + // being required + OperandSize::Size16 => LegacyPrefixes::_66, + _ => LegacyPrefixes::None, + }; + let imm_size = if i8::try_from(*src2).is_ok() { + 1 + } else { + if *size == OperandSize::Size16 { + 2 + } else { + 4 + } + }; + let opcode = if imm_size == 1 { 0x6B } else { 0x69 }; + match src1 { + RegMem::Reg { reg } => { + emit_std_reg_reg(sink, prefix, opcode, 1, dst, reg, rex); + } + + RegMem::Mem { addr } => { + let amode = addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, 1, dst, &amode, rex, imm_size); + } + } + emit_simm(sink, imm_size, *src2 as u32); + } + + Inst::MulX { + size, + src1, + src2, + dst_lo, + dst_hi, + } => { + let src1 = src1.to_reg(); + let dst_lo = dst_lo.to_reg().to_reg(); + let dst_hi = dst_hi.to_reg().to_reg(); + debug_assert_eq!(src1, regs::rdx()); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let dst_hi = dst_hi.to_real_reg().unwrap().hw_enc(); + let dst_lo = if dst_lo.is_invalid_sentinel() { + dst_hi + } else { + dst_lo.to_real_reg().unwrap().hw_enc() + }; + + VexInstruction::new() + .prefix(LegacyPrefixes::_F2) + .map(OpcodeMap::_0F38) + .w(*size == OperandSize::Size64) + .opcode(0xf6) + .reg(dst_hi) + .vvvv(dst_lo) + .rm(src2) + .encode(sink); + } + + Inst::SignExtendData { size, src, dst } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src, regs::rax()); + if *size == OperandSize::Size8 { + debug_assert_eq!(dst, regs::rax()); + } else { + debug_assert_eq!(dst, regs::rdx()); + } + match size { + OperandSize::Size8 => { + sink.put1(0x66); + sink.put1(0x98); + } + OperandSize::Size16 => { + sink.put1(0x66); + sink.put1(0x99); + } + OperandSize::Size32 => sink.put1(0x99), + OperandSize::Size64 => { + sink.put1(0x48); + sink.put1(0x99); + } + } + } + + Inst::CheckedSRemSeq { divisor, .. } | Inst::CheckedSRemSeq8 { divisor, .. } => { + let divisor = divisor.to_reg(); + + // Validate that the register constraints of the dividend and the + // destination are all as expected. + let (dst, size) = match inst { + Inst::CheckedSRemSeq { + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + size, + .. + } => { + let dividend_lo = dividend_lo.to_reg(); + let dividend_hi = dividend_hi.to_reg(); + let dst_quotient = dst_quotient.to_reg().to_reg(); + let dst_remainder = dst_remainder.to_reg().to_reg(); + debug_assert_eq!(dividend_lo, regs::rax()); + debug_assert_eq!(dividend_hi, regs::rdx()); + debug_assert_eq!(dst_quotient, regs::rax()); + debug_assert_eq!(dst_remainder, regs::rdx()); + (regs::rdx(), *size) + } + Inst::CheckedSRemSeq8 { dividend, dst, .. } => { + let dividend = dividend.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(dividend, regs::rax()); + debug_assert_eq!(dst, regs::rax()); + (regs::rax(), OperandSize::Size8) + } + _ => unreachable!(), + }; + + // Generates the following code sequence: + // + // cmp -1 %divisor + // jnz $do_op + // + // ;; for srem, result is 0 + // mov #0, %dst + // j $done + // + // $do_op: + // idiv %divisor + // + // $done: + + let do_op = sink.get_label(); + let done_label = sink.get_label(); + + // Check if the divisor is -1, and if it isn't then immediately + // go to the `idiv`. + let inst = Inst::cmp_rmi_r(size, divisor, RegMemImm::imm(0xffffffff)); + inst.emit(sink, info, state); + one_way_jmp(sink, CC::NZ, do_op); + + // ... otherwise the divisor is -1 and the result is always 0. This + // is written to the destination register which will be %rax for + // 8-bit srem and %rdx otherwise. + // + // Note that for 16-to-64-bit srem operations this leaves the + // second destination, %rax, unchanged. This isn't semantically + // correct if a lowering actually tries to use the `dst_quotient` + // output but for srem only the `dst_remainder` output is used for + // now. + let inst = Inst::imm(OperandSize::Size64, 0, Writable::from_reg(dst)); + inst.emit(sink, info, state); + let inst = Inst::jmp_known(done_label); + inst.emit(sink, info, state); + + // Here the `idiv` is executed, which is different depending on the + // size + sink.bind_label(do_op, state.ctrl_plane_mut()); + let inst = match size { + OperandSize::Size8 => Inst::div8( + DivSignedness::Signed, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(divisor), + Gpr::unwrap_new(regs::rax()), + Writable::from_reg(Gpr::unwrap_new(regs::rax())), + ), + _ => Inst::div( + size, + DivSignedness::Signed, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(divisor), + Gpr::unwrap_new(regs::rax()), + Gpr::unwrap_new(regs::rdx()), + Writable::from_reg(Gpr::unwrap_new(regs::rax())), + Writable::from_reg(Gpr::unwrap_new(regs::rdx())), + ), + }; + inst.emit(sink, info, state); + + sink.bind_label(done_label, state.ctrl_plane_mut()); + } + + Inst::Imm { + dst_size, + simm64, + dst, + } => { + let dst = dst.to_reg().to_reg(); + let enc_dst = int_reg_enc(dst); + if *dst_size == OperandSize::Size64 { + if low32_will_sign_extend_to_64(*simm64) { + // Sign-extended move imm32. + emit_std_enc_enc( + sink, + LegacyPrefixes::None, + 0xC7, + 1, + /* subopcode */ 0, + enc_dst, + RexFlags::set_w(), + ); + sink.put4(*simm64 as u32); + } else { + sink.put1(0x48 | ((enc_dst >> 3) & 1)); + sink.put1(0xB8 | (enc_dst & 7)); + sink.put8(*simm64); + } + } else { + if ((enc_dst >> 3) & 1) == 1 { + sink.put1(0x41); + } + sink.put1(0xB8 | (enc_dst & 7)); + sink.put4(*simm64 as u32); + } + } + + Inst::MovImmM { size, simm32, dst } => { + let dst = &dst.finalize(state.frame_layout(), sink).clone(); + let default_rex = RexFlags::clear_w(); + let default_opcode = 0xC7; + let bytes = size.to_bytes(); + let prefix = LegacyPrefixes::None; + + let (opcode, rex, size, prefix) = match *size { + // In the 8-bit case, we don't need to enforce REX flags via + // `always_emit_if_8bit_needed()` since the destination + // operand is a memory operand, not a possibly 8-bit register. + OperandSize::Size8 => (0xC6, default_rex, bytes, prefix), + OperandSize::Size16 => (0xC7, default_rex, bytes, LegacyPrefixes::_66), + OperandSize::Size64 => (default_opcode, RexFlags::from(*size), bytes, prefix), + + _ => (default_opcode, default_rex, bytes, prefix), + }; + + // 8-bit C6 /0 ib + // 16-bit 0x66 C7 /0 iw + // 32-bit C7 /0 id + // 64-bit REX.W C7 /0 id + emit_std_enc_mem(sink, prefix, opcode, 1, /*subopcode*/ 0, dst, rex, 0); + emit_simm(sink, size, *simm32 as u32); + } + + Inst::MovRR { size, src, dst } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + emit_std_reg_reg( + sink, + LegacyPrefixes::None, + 0x89, + 1, + src, + dst, + RexFlags::from(*size), + ); + } + + Inst::MovFromPReg { src, dst } => { + let src: Reg = (*src).into(); + debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&src)); + let src = Gpr::unwrap_new(src); + let size = OperandSize::Size64; + let dst = WritableGpr::from_writable_reg(dst.to_writable_reg()).unwrap(); + Inst::MovRR { size, src, dst }.emit(sink, info, state); + } + + Inst::MovToPReg { src, dst } => { + let src = src.to_reg(); + let src = Gpr::unwrap_new(src); + let dst: Reg = (*dst).into(); + debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&dst)); + let dst = WritableGpr::from_writable_reg(Writable::from_reg(dst)).unwrap(); + let size = OperandSize::Size64; + Inst::MovRR { size, src, dst }.emit(sink, info, state); + } + + Inst::MovzxRmR { ext_mode, src, dst } => { + let dst = dst.to_reg().to_reg(); + let (opcodes, num_opcodes, mut rex_flags) = match ext_mode { + ExtMode::BL => { + // MOVZBL is (REX.W==0) 0F B6 /r + (0x0FB6, 2, RexFlags::clear_w()) + } + ExtMode::BQ => { + // MOVZBQ is (REX.W==1) 0F B6 /r + // I'm not sure why the Intel manual offers different + // encodings for MOVZBQ than for MOVZBL. AIUI they should + // achieve the same, since MOVZBL is just going to zero out + // the upper half of the destination anyway. + (0x0FB6, 2, RexFlags::set_w()) + } + ExtMode::WL => { + // MOVZWL is (REX.W==0) 0F B7 /r + (0x0FB7, 2, RexFlags::clear_w()) + } + ExtMode::WQ => { + // MOVZWQ is (REX.W==1) 0F B7 /r + (0x0FB7, 2, RexFlags::set_w()) + } + ExtMode::LQ => { + // This is just a standard 32 bit load, and we rely on the + // default zero-extension rule to perform the extension. + // Note that in reg/reg mode, gcc seems to use the swapped form R/RM, which we + // don't do here, since it's the same encoding size. + // MOV r/m32, r32 is (REX.W==0) 8B /r + (0x8B, 1, RexFlags::clear_w()) + } + }; + + match src.clone().to_reg_mem() { + RegMem::Reg { reg: src } => { + match ext_mode { + ExtMode::BL | ExtMode::BQ => { + // A redundant REX prefix must be emitted for certain register inputs. + rex_flags.always_emit_if_8bit_needed(src); + } + _ => {} + } + emit_std_reg_reg( + sink, + LegacyPrefixes::None, + opcodes, + num_opcodes, + dst, + src, + rex_flags, + ) + } + + RegMem::Mem { addr: src } => { + let src = &src.finalize(state.frame_layout(), sink).clone(); + + emit_std_reg_mem( + sink, + LegacyPrefixes::None, + opcodes, + num_opcodes, + dst, + src, + rex_flags, + 0, + ) + } + } + } + + Inst::Mov64MR { src, dst } => { + let dst = dst.to_reg().to_reg(); + let src = &src.finalize(state.frame_layout(), sink).clone(); + + emit_std_reg_mem( + sink, + LegacyPrefixes::None, + 0x8B, + 1, + dst, + src, + RexFlags::set_w(), + 0, + ) + } + + Inst::LoadEffectiveAddress { addr, dst, size } => { + let dst = dst.to_reg().to_reg(); + let amode = addr.finalize(state.frame_layout(), sink).clone(); + + // If this `lea` can actually get encoded as an `add` then do that + // instead. Currently all candidate `iadd`s become an `lea` + // pseudo-instruction here but maximizing the sue of `lea` is not + // necessarily optimal. The `lea` instruction goes through dedicated + // address units on cores which are finite and disjoint from the + // general ALU, so if everything uses `lea` then those units can get + // saturated while leaving the ALU idle. + // + // To help make use of more parts of a cpu, this attempts to use + // `add` when it's semantically equivalent to `lea`, or otherwise + // when the `dst` register is the same as the `base` or `index` + // register. + // + // FIXME: ideally regalloc is informed of this constraint. Register + // allocation of `lea` should "attempt" to put the `base` in the + // same register as `dst` but not at the expense of generating a + // `mov` instruction. Currently that's not possible but perhaps one + // day it may be worth it. + match amode { + // If `base == dst` then this is `add $imm, %dst`, so encode + // that instead. + Amode::ImmReg { + simm32, + base, + flags: _, + } if base == dst => { + let inst = Inst::alu_rmi_r( + *size, + AluRmiROpcode::Add, + RegMemImm::imm(simm32 as u32), + Writable::from_reg(dst), + ); + inst.emit(sink, info, state); + } + // If the offset is 0 and the shift is 0 (meaning multiplication + // by 1) then: + // + // * If `base == dst`, then this is `add %index, %base` + // * If `index == dst`, then this is `add %base, %index` + // + // Encode the appropriate instruction here in that case. + Amode::ImmRegRegShift { + simm32: 0, + base, + index, + shift: 0, + flags: _, + } if base == dst || index == dst => { + let (dst, operand) = if base == dst { + (base, index) + } else { + (index, base) + }; + let inst = Inst::alu_rmi_r( + *size, + AluRmiROpcode::Add, + RegMemImm::reg(operand.to_reg()), + Writable::from_reg(dst.to_reg()), + ); + inst.emit(sink, info, state); + } + + // If `lea`'s 3-operand mode is leveraged by regalloc, or if + // it's fancy like imm-plus-shift-plus-base, then `lea` is + // actually emitted. + _ => { + let flags = match size { + OperandSize::Size32 => RexFlags::clear_w(), + OperandSize::Size64 => RexFlags::set_w(), + _ => unreachable!(), + }; + emit_std_reg_mem(sink, LegacyPrefixes::None, 0x8D, 1, dst, &amode, flags, 0); + } + }; + } + + Inst::MovsxRmR { ext_mode, src, dst } => { + let dst = dst.to_reg().to_reg(); + let (opcodes, num_opcodes, mut rex_flags) = match ext_mode { + ExtMode::BL => { + // MOVSBL is (REX.W==0) 0F BE /r + (0x0FBE, 2, RexFlags::clear_w()) + } + ExtMode::BQ => { + // MOVSBQ is (REX.W==1) 0F BE /r + (0x0FBE, 2, RexFlags::set_w()) + } + ExtMode::WL => { + // MOVSWL is (REX.W==0) 0F BF /r + (0x0FBF, 2, RexFlags::clear_w()) + } + ExtMode::WQ => { + // MOVSWQ is (REX.W==1) 0F BF /r + (0x0FBF, 2, RexFlags::set_w()) + } + ExtMode::LQ => { + // MOVSLQ is (REX.W==1) 63 /r + (0x63, 1, RexFlags::set_w()) + } + }; + + match src.clone().to_reg_mem() { + RegMem::Reg { reg: src } => { + match ext_mode { + ExtMode::BL | ExtMode::BQ => { + // A redundant REX prefix must be emitted for certain register inputs. + rex_flags.always_emit_if_8bit_needed(src); + } + _ => {} + } + emit_std_reg_reg( + sink, + LegacyPrefixes::None, + opcodes, + num_opcodes, + dst, + src, + rex_flags, + ) + } + + RegMem::Mem { addr: src } => { + let src = &src.finalize(state.frame_layout(), sink).clone(); + + emit_std_reg_mem( + sink, + LegacyPrefixes::None, + opcodes, + num_opcodes, + dst, + src, + rex_flags, + 0, + ) + } + } + } + + Inst::MovRM { size, src, dst } => { + let src = src.to_reg(); + let dst = &dst.finalize(state.frame_layout(), sink).clone(); + + let prefix = match size { + OperandSize::Size16 => LegacyPrefixes::_66, + _ => LegacyPrefixes::None, + }; + + let opcode = match size { + OperandSize::Size8 => 0x88, + _ => 0x89, + }; + + // This is one of the few places where the presence of a + // redundant REX prefix changes the meaning of the + // instruction. + let rex = RexFlags::from((*size, src)); + + // 8-bit: MOV r8, r/m8 is (REX.W==0) 88 /r + // 16-bit: MOV r16, r/m16 is 66 (REX.W==0) 89 /r + // 32-bit: MOV r32, r/m32 is (REX.W==0) 89 /r + // 64-bit: MOV r64, r/m64 is (REX.W==1) 89 /r + emit_std_reg_mem(sink, prefix, opcode, 1, src, dst, rex, 0); + } + + Inst::ShiftR { + size, + kind, + src, + num_bits, + dst, + } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src, dst); + let subopcode = match kind { + ShiftKind::RotateLeft => 0, + ShiftKind::RotateRight => 1, + ShiftKind::ShiftLeft => 4, + ShiftKind::ShiftRightLogical => 5, + ShiftKind::ShiftRightArithmetic => 7, + }; + let enc_dst = int_reg_enc(dst); + let rex_flags = RexFlags::from((*size, dst)); + match num_bits.as_imm8_reg() { + &Imm8Reg::Reg { reg } => { + debug_assert_eq!(reg, regs::rcx()); + let (opcode, prefix) = match size { + OperandSize::Size8 => (0xD2, LegacyPrefixes::None), + OperandSize::Size16 => (0xD3, LegacyPrefixes::_66), + OperandSize::Size32 => (0xD3, LegacyPrefixes::None), + OperandSize::Size64 => (0xD3, LegacyPrefixes::None), + }; + + // SHL/SHR/SAR %cl, reg8 is (REX.W==0) D2 /subopcode + // SHL/SHR/SAR %cl, reg16 is 66 (REX.W==0) D3 /subopcode + // SHL/SHR/SAR %cl, reg32 is (REX.W==0) D3 /subopcode + // SHL/SHR/SAR %cl, reg64 is (REX.W==1) D3 /subopcode + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_dst, rex_flags); + } + + &Imm8Reg::Imm8 { imm: num_bits } => { + let (opcode, prefix) = match size { + OperandSize::Size8 => (0xC0, LegacyPrefixes::None), + OperandSize::Size16 => (0xC1, LegacyPrefixes::_66), + OperandSize::Size32 => (0xC1, LegacyPrefixes::None), + OperandSize::Size64 => (0xC1, LegacyPrefixes::None), + }; + + // SHL/SHR/SAR $ib, reg8 is (REX.W==0) C0 /subopcode + // SHL/SHR/SAR $ib, reg16 is 66 (REX.W==0) C1 /subopcode + // SHL/SHR/SAR $ib, reg32 is (REX.W==0) C1 /subopcode ib + // SHL/SHR/SAR $ib, reg64 is (REX.W==1) C1 /subopcode ib + // When the shift amount is 1, there's an even shorter encoding, but we don't + // bother with that nicety here. + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_dst, rex_flags); + sink.put1(num_bits); + } + } + } + + Inst::XmmRmiReg { + opcode, + src1, + src2, + dst, + } => { + let src1 = src1.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src1, dst); + let rex = RexFlags::clear_w(); + let prefix = LegacyPrefixes::_66; + let src2 = src2.clone().to_reg_mem_imm(); + if let RegMemImm::Imm { simm32 } = src2 { + let (opcode_bytes, reg_digit) = match opcode { + SseOpcode::Psllw => (0x0F71, 6), + SseOpcode::Pslld => (0x0F72, 6), + SseOpcode::Psllq => (0x0F73, 6), + SseOpcode::Psraw => (0x0F71, 4), + SseOpcode::Psrad => (0x0F72, 4), + SseOpcode::Psrlw => (0x0F71, 2), + SseOpcode::Psrld => (0x0F72, 2), + SseOpcode::Psrlq => (0x0F73, 2), + _ => panic!("invalid opcode: {opcode}"), + }; + let dst_enc = reg_enc(dst); + emit_std_enc_enc(sink, prefix, opcode_bytes, 2, reg_digit, dst_enc, rex); + let imm = (simm32) + .try_into() + .expect("the immediate must be convertible to a u8"); + sink.put1(imm); + } else { + let opcode_bytes = match opcode { + SseOpcode::Psllw => 0x0FF1, + SseOpcode::Pslld => 0x0FF2, + SseOpcode::Psllq => 0x0FF3, + SseOpcode::Psraw => 0x0FE1, + SseOpcode::Psrad => 0x0FE2, + SseOpcode::Psrlw => 0x0FD1, + SseOpcode::Psrld => 0x0FD2, + SseOpcode::Psrlq => 0x0FD3, + _ => panic!("invalid opcode: {opcode}"), + }; + + match src2 { + RegMemImm::Reg { reg } => { + emit_std_reg_reg(sink, prefix, opcode_bytes, 2, dst, reg, rex); + } + RegMemImm::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink).clone(); + emit_std_reg_mem(sink, prefix, opcode_bytes, 2, dst, addr, rex, 0); + } + RegMemImm::Imm { .. } => unreachable!(), + } + }; + } + + Inst::CmpRmiR { + size, + src1: reg_g, + src2: src_e, + opcode, + } => { + let reg_g = reg_g.to_reg(); + + let is_cmp = match opcode { + CmpOpcode::Cmp => true, + CmpOpcode::Test => false, + }; + + let mut prefix = LegacyPrefixes::None; + if *size == OperandSize::Size16 { + prefix = LegacyPrefixes::_66; + } + // A redundant REX prefix can change the meaning of this instruction. + let mut rex = RexFlags::from((*size, reg_g)); + + match src_e.clone().to_reg_mem_imm() { + RegMemImm::Reg { reg: reg_e } => { + if *size == OperandSize::Size8 { + // Check whether the E register forces the use of a redundant REX. + rex.always_emit_if_8bit_needed(reg_e); + } + + // Use the swapped operands encoding for CMP, to stay consistent with the output of + // gcc/llvm. + let opcode = match (*size, is_cmp) { + (OperandSize::Size8, true) => 0x38, + (_, true) => 0x39, + (OperandSize::Size8, false) => 0x84, + (_, false) => 0x85, + }; + emit_std_reg_reg(sink, prefix, opcode, 1, reg_e, reg_g, rex); + } + + RegMemImm::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink).clone(); + // Whereas here we revert to the "normal" G-E ordering for CMP. + let opcode = match (*size, is_cmp) { + (OperandSize::Size8, true) => 0x3A, + (_, true) => 0x3B, + (OperandSize::Size8, false) => 0x84, + (_, false) => 0x85, + }; + emit_std_reg_mem(sink, prefix, opcode, 1, reg_g, addr, rex, 0); + } + + RegMemImm::Imm { simm32 } => { + // FIXME JRS 2020Feb11: there are shorter encodings for + // cmp $imm, rax/eax/ax/al. + let use_imm8 = is_cmp && low8_will_sign_extend_to_32(simm32); + + // And also here we use the "normal" G-E ordering. + let opcode = if is_cmp { + if *size == OperandSize::Size8 { + 0x80 + } else if use_imm8 { + 0x83 + } else { + 0x81 + } + } else { + if *size == OperandSize::Size8 { + 0xF6 + } else { + 0xF7 + } + }; + let subopcode = if is_cmp { 7 } else { 0 }; + + let enc_g = int_reg_enc(reg_g); + emit_std_enc_enc(sink, prefix, opcode, 1, subopcode, enc_g, rex); + emit_simm(sink, if use_imm8 { 1 } else { size.to_bytes() }, simm32); + } + } + } + + Inst::Setcc { cc, dst } => { + let dst = dst.to_reg().to_reg(); + let opcode = 0x0f90 + cc.get_enc() as u32; + let mut rex_flags = RexFlags::clear_w(); + rex_flags.always_emit(); + emit_std_enc_enc( + sink, + LegacyPrefixes::None, + opcode, + 2, + 0, + reg_enc(dst), + rex_flags, + ); + } + + Inst::Bswap { size, src, dst } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src, dst); + let enc_reg = int_reg_enc(dst); + + // BSWAP reg32 is (REX.W==0) 0F C8 + // BSWAP reg64 is (REX.W==1) 0F C8 + let rex_flags = RexFlags::from(*size); + rex_flags.emit_one_op(sink, enc_reg); + + sink.put1(0x0F); + sink.put1(0xC8 | (enc_reg & 7)); + } + + Inst::Cmove { + size, + cc, + consequent, + alternative, + dst, + } => { + let alternative = alternative.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(alternative, dst); + let rex_flags = RexFlags::from(*size); + let prefix = match size { + OperandSize::Size16 => LegacyPrefixes::_66, + OperandSize::Size32 => LegacyPrefixes::None, + OperandSize::Size64 => LegacyPrefixes::None, + _ => unreachable!("invalid size spec for cmove"), + }; + let opcode = 0x0F40 + cc.get_enc() as u32; + match consequent.clone().to_reg_mem() { + RegMem::Reg { reg } => { + emit_std_reg_reg(sink, prefix, opcode, 2, dst, reg, rex_flags); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink).clone(); + emit_std_reg_mem(sink, prefix, opcode, 2, dst, addr, rex_flags, 0); + } + } + } + + Inst::XmmCmove { + ty, + cc, + consequent, + alternative, + dst, + } => { + let alternative = alternative.to_reg(); + let dst = dst.to_writable_reg(); + debug_assert_eq!(alternative, dst.to_reg()); + let consequent = consequent.to_reg(); + + // Lowering of the Select IR opcode when the input is an fcmp relies on the fact that + // this doesn't clobber flags. Make sure to not do so here. + let next = sink.get_label(); + + // Jump if cc is *not* set. + one_way_jmp(sink, cc.invert(), next); + + let op = match *ty { + types::F64 => SseOpcode::Movsd, + types::F32 => SseOpcode::Movsd, + types::F16 => SseOpcode::Movsd, + types::F32X4 => SseOpcode::Movaps, + types::F64X2 => SseOpcode::Movapd, + ty => { + debug_assert!((ty.is_float() || ty.is_vector()) && ty.bytes() == 16); + SseOpcode::Movdqa + } + }; + let inst = Inst::xmm_unary_rm_r(op, consequent.into(), dst); + inst.emit(sink, info, state); + + sink.bind_label(next, state.ctrl_plane_mut()); + } + + Inst::Push64 { src } => { + let src = src.clone().to_reg_mem_imm().clone(); + + match src { + RegMemImm::Reg { reg } => { + let enc_reg = int_reg_enc(reg); + let rex = 0x40 | ((enc_reg >> 3) & 1); + if rex != 0x40 { + sink.put1(rex); + } + sink.put1(0x50 | (enc_reg & 7)); + } + + RegMemImm::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_enc_mem( + sink, + LegacyPrefixes::None, + 0xFF, + 1, + 6, /*subopcode*/ + addr, + RexFlags::clear_w(), + 0, + ); + } + + RegMemImm::Imm { simm32 } => { + if low8_will_sign_extend_to_64(simm32) { + sink.put1(0x6A); + sink.put1(simm32 as u8); + } else { + sink.put1(0x68); + sink.put4(simm32); + } + } + } + } + + Inst::Pop64 { dst } => { + let dst = dst.to_reg().to_reg(); + let enc_dst = int_reg_enc(dst); + if enc_dst >= 8 { + // 0x41 == REX.{W=0, B=1}. It seems that REX.W is irrelevant here. + sink.put1(0x41); + } + sink.put1(0x58 + (enc_dst & 7)); + } + + Inst::StackProbeLoop { + tmp, + frame_size, + guard_size, + } => { + assert!(info.flags.enable_probestack()); + assert!(guard_size.is_power_of_two()); + + let tmp = *tmp; + + // Number of probes that we need to perform + let probe_count = align_to(*frame_size, *guard_size) / guard_size; + + // The inline stack probe loop has 3 phases: + // + // We generate the "guard area" register which is essentially the frame_size aligned to + // guard_size. We copy the stack pointer and subtract the guard area from it. This + // gets us a register that we can use to compare when looping. + // + // After that we emit the loop. Essentially we just adjust the stack pointer one guard_size'd + // distance at a time and then touch the stack by writing anything to it. We use the previously + // created "guard area" register to know when to stop looping. + // + // When we have touched all the pages that we need, we have to restore the stack pointer + // to where it was before. + // + // Generate the following code: + // mov tmp_reg, rsp + // sub tmp_reg, guard_size * probe_count + // .loop_start: + // sub rsp, guard_size + // mov [rsp], rsp + // cmp rsp, tmp_reg + // jne .loop_start + // add rsp, guard_size * probe_count + + // Create the guard bound register + // mov tmp_reg, rsp + let inst = Inst::gen_move(tmp, regs::rsp(), types::I64); + inst.emit(sink, info, state); + + // sub tmp_reg, GUARD_SIZE * probe_count + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(guard_size * probe_count), + tmp, + ); + inst.emit(sink, info, state); + + // Emit the main loop! + let loop_start = sink.get_label(); + sink.bind_label(loop_start, state.ctrl_plane_mut()); + + // sub rsp, GUARD_SIZE + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(*guard_size), + Writable::from_reg(regs::rsp()), + ); + inst.emit(sink, info, state); + + // TODO: `mov [rsp], 0` would be better, but we don't have that instruction + // Probe the stack! We don't use Inst::gen_store_stack here because we need a predictable + // instruction size. + // mov [rsp], rsp + let inst = Inst::mov_r_m( + OperandSize::Size32, // Use Size32 since it saves us one byte + regs::rsp(), + SyntheticAmode::Real(Amode::imm_reg(0, regs::rsp())), + ); + inst.emit(sink, info, state); + + // Compare and jump if we are not done yet + // cmp rsp, tmp_reg + let inst = Inst::cmp_rmi_r( + OperandSize::Size64, + tmp.to_reg(), + RegMemImm::reg(regs::rsp()), + ); + inst.emit(sink, info, state); + + // jne .loop_start + // TODO: Encoding the JmpIf as a short jump saves us 4 bytes here. + one_way_jmp(sink, CC::NZ, loop_start); + + // The regular prologue code is going to emit a `sub` after this, so we need to + // reset the stack pointer + // + // TODO: It would be better if we could avoid the `add` + `sub` that is generated here + // and in the stack adj portion of the prologue + // + // add rsp, GUARD_SIZE * probe_count + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(guard_size * probe_count), + Writable::from_reg(regs::rsp()), + ); + inst.emit(sink, info, state); + } + + Inst::CallKnown { info: call_info } => { + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset() + 5; + sink.push_user_stack_map(state, offset, s); + } + + sink.put1(0xE8); + // The addend adjusts for the difference between the end of the instruction and the + // beginning of the immediate field. + emit_reloc(sink, Reloc::X86CallPCRel4, &call_info.dest, -4); + sink.put4(0); + sink.add_call_site(); + + // Reclaim the outgoing argument area that was released by the callee, to ensure that + // StackAMode values are always computed from a consistent SP. + if call_info.callee_pop_size > 0 { + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(call_info.callee_pop_size), + Writable::from_reg(regs::rsp()), + ) + .emit(sink, info, state); + } + } + + Inst::ReturnCallKnown { info: call_info } => { + emit_return_call_common_sequence(sink, info, state, &call_info); + + // Finally, jump to the callee! + // + // Note: this is not `Inst::Jmp { .. }.emit(..)` because we have + // different metadata in this case: we don't have a label for the + // target, but rather a function relocation. + sink.put1(0xE9); + // The addend adjusts for the difference between the end of the instruction and the + // beginning of the immediate field. + emit_reloc(sink, Reloc::X86CallPCRel4, &call_info.dest, -4); + sink.put4(0); + sink.add_call_site(); + } + + Inst::ReturnCallUnknown { info: call_info } => { + let callee = call_info.dest; + + emit_return_call_common_sequence(sink, info, state, &call_info); + + Inst::JmpUnknown { + target: RegMem::reg(callee), + } + .emit(sink, info, state); + sink.add_call_site(); + } + + Inst::CallUnknown { + info: call_info, .. + } => { + let dest = call_info.dest.clone(); + + match dest { + RegMem::Reg { reg } => { + let reg_enc = int_reg_enc(reg); + emit_std_enc_enc( + sink, + LegacyPrefixes::None, + 0xFF, + 1, + 2, /*subopcode*/ + reg_enc, + RexFlags::clear_w(), + ); + } + + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_enc_mem( + sink, + LegacyPrefixes::None, + 0xFF, + 1, + 2, /*subopcode*/ + addr, + RexFlags::clear_w(), + 0, + ); + } + } + + if let Some(s) = state.take_stack_map() { + let offset = sink.cur_offset(); + sink.push_user_stack_map(state, offset, s); + } + + sink.add_call_site(); + + // Reclaim the outgoing argument area that was released by the callee, to ensure that + // StackAMode values are always computed from a consistent SP. + if call_info.callee_pop_size > 0 { + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::imm(call_info.callee_pop_size), + Writable::from_reg(regs::rsp()), + ) + .emit(sink, info, state); + } + } + + Inst::Args { .. } => {} + Inst::Rets { .. } => {} + + Inst::Ret { + stack_bytes_to_pop: 0, + } => sink.put1(0xC3), + + Inst::Ret { stack_bytes_to_pop } => { + sink.put1(0xC2); + sink.put2(u16::try_from(*stack_bytes_to_pop).unwrap()); + } + + Inst::StackSwitchBasic { + store_context_ptr, + load_context_ptr, + in_payload0, + out_payload0, + } => { + // Note that we do not emit anything for preserving and restoring + // ordinary registers here: That's taken care of by regalloc for us, + // since we marked this instruction as clobbering all registers. + // + // Also note that we do nothing about passing the single payload + // value: We've informed regalloc that it is sent and received via + // the fixed register given by [stack_switch::payload_register] + + let (tmp1, tmp2) = { + // Ideally we would just ask regalloc for two temporary registers. + // However, adding any early defs to the constraints on StackSwitch + // causes TooManyLiveRegs. Fortunately, we can manually find tmp + // registers without regalloc: Since our instruction clobbers all + // registers, we can simply pick any register that is not assigned + // to the operands. + + let all = crate::isa::x64::abi::ALL_CLOBBERS; + + let used_regs = [ + **load_context_ptr, + **store_context_ptr, + **in_payload0, + *out_payload0.to_reg(), + ]; + + let mut tmps = all.into_iter().filter_map(|preg| { + let reg: Reg = preg.into(); + if !used_regs.contains(®) { + WritableGpr::from_writable_reg(isle::WritableReg::from_reg(reg)) + } else { + None + } + }); + (tmps.next().unwrap(), tmps.next().unwrap()) + }; + + let layout = stack_switch::control_context_layout(); + let rsp_offset = layout.stack_pointer_offset as i32; + let pc_offset = layout.ip_offset as i32; + let rbp_offset = layout.frame_pointer_offset as i32; + + // Location to which someone switch-ing back to this stack will jump + // to: Right behind the `StackSwitch` instruction + let resume = sink.get_label(); + + // + // For RBP and RSP we do the following: + // - Load new value for register from `load_context_ptr` + + // corresponding offset. + // - Store previous (!) value of register at `store_context_ptr` + + // corresponding offset. + // + // Since `load_context_ptr` and `store_context_ptr` are allowed to be + // equal, we need to use a temporary register here. + // + + let mut exchange = |offset, reg| { + let inst = Inst::Mov64MR { + src: Amode::imm_reg(offset, **load_context_ptr).into(), + dst: tmp1, + }; + emit(&inst, sink, info, state); + + let inst = Inst::MovRM { + size: OperandSize::Size64, + src: Gpr::new(reg).unwrap(), + dst: Amode::imm_reg(offset, **store_context_ptr).into(), + }; + emit(&inst, sink, info, state); + + let dst = Writable::from_reg(reg.into()); + let inst = Inst::MovRR { + size: OperandSize::Size64, + src: tmp1.to_reg(), + dst: WritableGpr::from_writable_reg(dst.into()).unwrap(), + }; + emit(&inst, sink, info, state); + }; + + exchange(rsp_offset, regs::rsp()); + exchange(rbp_offset, regs::rbp()); + + // + // Load target PC, store resume PC, jump to target PC + // + + let inst = Inst::Mov64MR { + src: Amode::imm_reg(pc_offset, **load_context_ptr).into(), + dst: tmp1, + }; + emit(&inst, sink, info, state); + + let amode = Amode::RipRelative { target: resume }; + let inst = Inst::lea(amode, tmp2.map(Reg::from)); + inst.emit(sink, info, state); + + let inst = Inst::MovRM { + size: OperandSize::Size64, + src: tmp2.to_reg(), + dst: Amode::imm_reg(pc_offset, **store_context_ptr).into(), + }; + emit(&inst, sink, info, state); + + let inst = Inst::JmpUnknown { + target: RegMem::reg(tmp1.to_reg().into()), + }; + emit(&inst, sink, info, state); + + sink.bind_label(resume, state.ctrl_plane_mut()); + } + + Inst::JmpKnown { dst } => { + let br_start = sink.cur_offset(); + let br_disp_off = br_start + 1; + let br_end = br_start + 5; + + sink.use_label_at_offset(br_disp_off, *dst, LabelUse::JmpRel32); + sink.add_uncond_branch(br_start, br_end, *dst); + + sink.put1(0xE9); + // Placeholder for the label value. + sink.put4(0x0); + } + + Inst::JmpIf { cc, taken } => { + let cond_start = sink.cur_offset(); + let cond_disp_off = cond_start + 2; + + sink.use_label_at_offset(cond_disp_off, *taken, LabelUse::JmpRel32); + // Since this is not a terminator, don't enroll in the branch inversion mechanism. + + sink.put1(0x0F); + sink.put1(0x80 + cc.get_enc()); + // Placeholder for the label value. + sink.put4(0x0); + } + + Inst::JmpCond { + cc, + taken, + not_taken, + } => { + // If taken. + let cond_start = sink.cur_offset(); + let cond_disp_off = cond_start + 2; + let cond_end = cond_start + 6; + + sink.use_label_at_offset(cond_disp_off, *taken, LabelUse::JmpRel32); + let inverted: [u8; 6] = [0x0F, 0x80 + (cc.invert().get_enc()), 0x00, 0x00, 0x00, 0x00]; + sink.add_cond_branch(cond_start, cond_end, *taken, &inverted[..]); + + sink.put1(0x0F); + sink.put1(0x80 + cc.get_enc()); + // Placeholder for the label value. + sink.put4(0x0); + + // If not taken. + let uncond_start = sink.cur_offset(); + let uncond_disp_off = uncond_start + 1; + let uncond_end = uncond_start + 5; + + sink.use_label_at_offset(uncond_disp_off, *not_taken, LabelUse::JmpRel32); + sink.add_uncond_branch(uncond_start, uncond_end, *not_taken); + + sink.put1(0xE9); + // Placeholder for the label value. + sink.put4(0x0); + } + + Inst::JmpUnknown { target } => { + let target = target.clone(); + + match target { + RegMem::Reg { reg } => { + let reg_enc = int_reg_enc(reg); + emit_std_enc_enc( + sink, + LegacyPrefixes::None, + 0xFF, + 1, + 4, /*subopcode*/ + reg_enc, + RexFlags::clear_w(), + ); + } + + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_enc_mem( + sink, + LegacyPrefixes::None, + 0xFF, + 1, + 4, /*subopcode*/ + addr, + RexFlags::clear_w(), + 0, + ); + } + } + } + + &Inst::JmpTableSeq { + idx, + tmp1, + tmp2, + ref targets, + ref default_target, + .. + } => { + // This sequence is *one* instruction in the vcode, and is expanded only here at + // emission time, because we cannot allow the regalloc to insert spills/reloads in + // the middle; we depend on hardcoded PC-rel addressing below. + // + // We don't have to worry about emitting islands, because the only label-use type has a + // maximum range of 2 GB. If we later consider using shorter-range label references, + // this will need to be revisited. + + // We generate the following sequence. Note that the only read of %idx is before the + // write to %tmp2, so regalloc may use the same register for both; fix x64/inst/mod.rs + // if you change this. + // lea start_of_jump_table_offset(%rip), %tmp1 + // movslq [%tmp1, %idx, 4], %tmp2 ;; shift of 2, viz. multiply index by 4 + // addq %tmp2, %tmp1 + // j *%tmp1 + // $start_of_jump_table: + // -- jump table entries + + // Load base address of jump table. + let start_of_jumptable = sink.get_label(); + let inst = Inst::lea(Amode::rip_relative(start_of_jumptable), tmp1); + inst.emit(sink, info, state); + + // Load value out of the jump table. It's a relative offset to the target block, so it + // might be negative; use a sign-extension. + let inst = Inst::movsx_rm_r( + ExtMode::LQ, + RegMem::mem(Amode::imm_reg_reg_shift( + 0, + Gpr::unwrap_new(tmp1.to_reg()), + Gpr::unwrap_new(idx), + 2, + )), + tmp2, + ); + inst.emit(sink, info, state); + + // Add base of jump table to jump-table-sourced block offset. + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::reg(tmp2.to_reg()), + tmp1, + ); + inst.emit(sink, info, state); + + // Branch to computed address. + let inst = Inst::jmp_unknown(RegMem::reg(tmp1.to_reg())); + inst.emit(sink, info, state); + + // Emit jump table (table of 32-bit offsets). + sink.bind_label(start_of_jumptable, state.ctrl_plane_mut()); + let jt_off = sink.cur_offset(); + for &target in targets.iter().chain(std::iter::once(default_target)) { + let word_off = sink.cur_offset(); + // off_into_table is an addend here embedded in the label to be later patched at + // the end of codegen. The offset is initially relative to this jump table entry; + // with the extra addend, it'll be relative to the jump table's start, after + // patching. + let off_into_table = word_off - jt_off; + sink.use_label_at_offset(word_off, target, LabelUse::PCRel32); + sink.put4(off_into_table); + } + } + + Inst::TrapIf { cc, trap_code } => { + let trap_label = sink.defer_trap(*trap_code); + one_way_jmp(sink, *cc, trap_label); + } + + Inst::TrapIfAnd { + cc1, + cc2, + trap_code, + } => { + let trap_label = sink.defer_trap(*trap_code); + let else_label = sink.get_label(); + + // Jump to the end if the first condition isn't true, and then if + // the second condition is true go to the trap. + one_way_jmp(sink, cc1.invert(), else_label); + one_way_jmp(sink, *cc2, trap_label); + + sink.bind_label(else_label, state.ctrl_plane_mut()); + } + + Inst::TrapIfOr { + cc1, + cc2, + trap_code, + } => { + let trap_label = sink.defer_trap(*trap_code); + + // Emit two jumps to the same trap if either condition code is true. + one_way_jmp(sink, *cc1, trap_label); + one_way_jmp(sink, *cc2, trap_label); + } + + Inst::XmmUnaryRmR { op, src, dst } => { + emit( + &Inst::XmmUnaryRmRUnaligned { + op: *op, + src: XmmMem::unwrap_new(src.clone().into()), + dst: *dst, + }, + sink, + info, + state, + ); + } + + Inst::XmmUnaryRmRUnaligned { + op, + src: src_e, + dst: reg_g, + } => { + let reg_g = reg_g.to_reg().to_reg(); + let src_e = src_e.clone().to_reg_mem().clone(); + + let rex = RexFlags::clear_w(); + + let (prefix, opcode, num_opcodes) = match op { + SseOpcode::Cvtdq2pd => (LegacyPrefixes::_F3, 0x0FE6, 2), + SseOpcode::Cvtpd2ps => (LegacyPrefixes::_66, 0x0F5A, 2), + SseOpcode::Cvtps2pd => (LegacyPrefixes::None, 0x0F5A, 2), + SseOpcode::Cvtdq2ps => (LegacyPrefixes::None, 0x0F5B, 2), + SseOpcode::Cvttpd2dq => (LegacyPrefixes::_66, 0x0FE6, 2), + SseOpcode::Cvttps2dq => (LegacyPrefixes::_F3, 0x0F5B, 2), + SseOpcode::Movaps => (LegacyPrefixes::None, 0x0F28, 2), + SseOpcode::Movapd => (LegacyPrefixes::_66, 0x0F28, 2), + SseOpcode::Movdqa => (LegacyPrefixes::_66, 0x0F6F, 2), + SseOpcode::Movdqu => (LegacyPrefixes::_F3, 0x0F6F, 2), + SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F10, 2), + SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F10, 2), + SseOpcode::Movups => (LegacyPrefixes::None, 0x0F10, 2), + SseOpcode::Movupd => (LegacyPrefixes::_66, 0x0F10, 2), + SseOpcode::Pabsb => (LegacyPrefixes::_66, 0x0F381C, 3), + SseOpcode::Pabsw => (LegacyPrefixes::_66, 0x0F381D, 3), + SseOpcode::Pabsd => (LegacyPrefixes::_66, 0x0F381E, 3), + SseOpcode::Pmovsxbd => (LegacyPrefixes::_66, 0x0F3821, 3), + SseOpcode::Pmovsxbw => (LegacyPrefixes::_66, 0x0F3820, 3), + SseOpcode::Pmovsxbq => (LegacyPrefixes::_66, 0x0F3822, 3), + SseOpcode::Pmovsxwd => (LegacyPrefixes::_66, 0x0F3823, 3), + SseOpcode::Pmovsxwq => (LegacyPrefixes::_66, 0x0F3824, 3), + SseOpcode::Pmovsxdq => (LegacyPrefixes::_66, 0x0F3825, 3), + SseOpcode::Pmovzxbd => (LegacyPrefixes::_66, 0x0F3831, 3), + SseOpcode::Pmovzxbw => (LegacyPrefixes::_66, 0x0F3830, 3), + SseOpcode::Pmovzxbq => (LegacyPrefixes::_66, 0x0F3832, 3), + SseOpcode::Pmovzxwd => (LegacyPrefixes::_66, 0x0F3833, 3), + SseOpcode::Pmovzxwq => (LegacyPrefixes::_66, 0x0F3834, 3), + SseOpcode::Pmovzxdq => (LegacyPrefixes::_66, 0x0F3835, 3), + SseOpcode::Sqrtps => (LegacyPrefixes::None, 0x0F51, 2), + SseOpcode::Sqrtpd => (LegacyPrefixes::_66, 0x0F51, 2), + SseOpcode::Movddup => (LegacyPrefixes::_F2, 0x0F12, 2), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + + match src_e { + RegMem::Reg { reg: reg_e } => { + emit_std_reg_reg(sink, prefix, opcode, num_opcodes, reg_g, reg_e, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, num_opcodes, reg_g, addr, rex, 0); + } + }; + } + + Inst::XmmUnaryRmRImm { op, src, dst, imm } => { + let dst = dst.to_reg().to_reg(); + let src = src.clone().to_reg_mem().clone(); + let rex = RexFlags::clear_w(); + + let (prefix, opcode, len) = match op { + SseOpcode::Roundps => (LegacyPrefixes::_66, 0x0F3A08, 3), + SseOpcode::Roundss => (LegacyPrefixes::_66, 0x0F3A0A, 3), + SseOpcode::Roundpd => (LegacyPrefixes::_66, 0x0F3A09, 3), + SseOpcode::Roundsd => (LegacyPrefixes::_66, 0x0F3A0B, 3), + SseOpcode::Pshufd => (LegacyPrefixes::_66, 0x0F70, 2), + SseOpcode::Pshuflw => (LegacyPrefixes::_F2, 0x0F70, 2), + SseOpcode::Pshufhw => (LegacyPrefixes::_F3, 0x0F70, 2), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + match src { + RegMem::Reg { reg } => { + emit_std_reg_reg(sink, prefix, opcode, len, dst, reg, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + // N.B.: bytes_at_end == 1, because of the `imm` byte below. + emit_std_reg_mem(sink, prefix, opcode, len, dst, addr, rex, 1); + } + } + sink.put1(*imm); + } + + Inst::XmmUnaryRmREvex { op, src, dst } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, w, opcode) = match op { + Avx512Opcode::Vcvtudq2ps => (LegacyPrefixes::_F2, OpcodeMap::_0F, false, 0x7a), + Avx512Opcode::Vpabsq => (LegacyPrefixes::_66, OpcodeMap::_0F38, true, 0x1f), + Avx512Opcode::Vpopcntb => (LegacyPrefixes::_66, OpcodeMap::_0F38, false, 0x54), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + EvexInstruction::new() + .length(EvexVectorLength::V128) + .prefix(prefix) + .map(map) + .w(w) + .opcode(opcode) + .tuple_type(op.tuple_type()) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src) + .encode(sink); + } + + Inst::XmmUnaryRmRImmEvex { op, src, dst, imm } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (opcode, opcode_ext, w) = match op { + Avx512Opcode::VpsraqImm => (0x72, 4, true), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + EvexInstruction::new() + .length(EvexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F) + .w(w) + .opcode(opcode) + .reg(opcode_ext) + .vvvvv(dst.to_real_reg().unwrap().hw_enc()) + .tuple_type(op.tuple_type()) + .rm(src) + .imm(*imm) + .encode(sink); + } + + Inst::XmmRmR { + op, + src1, + src2, + dst, + } => emit( + &Inst::XmmRmRUnaligned { + op: *op, + dst: *dst, + src1: *src1, + src2: XmmMem::unwrap_new(src2.clone().to_reg_mem()), + }, + sink, + info, + state, + ), + + Inst::XmmRmRUnaligned { + op, + src1, + src2: src_e, + dst: reg_g, + } => { + let src1 = src1.to_reg(); + let reg_g = reg_g.to_reg().to_reg(); + let src_e = src_e.clone().to_reg_mem().clone(); + debug_assert_eq!(src1, reg_g); + + let rex = RexFlags::clear_w(); + let (prefix, opcode, length) = match op { + SseOpcode::Addps => (LegacyPrefixes::None, 0x0F58, 2), + SseOpcode::Addpd => (LegacyPrefixes::_66, 0x0F58, 2), + SseOpcode::Addss => (LegacyPrefixes::_F3, 0x0F58, 2), + SseOpcode::Addsd => (LegacyPrefixes::_F2, 0x0F58, 2), + SseOpcode::Andps => (LegacyPrefixes::None, 0x0F54, 2), + SseOpcode::Andpd => (LegacyPrefixes::_66, 0x0F54, 2), + SseOpcode::Andnps => (LegacyPrefixes::None, 0x0F55, 2), + SseOpcode::Andnpd => (LegacyPrefixes::_66, 0x0F55, 2), + SseOpcode::Divps => (LegacyPrefixes::None, 0x0F5E, 2), + SseOpcode::Divpd => (LegacyPrefixes::_66, 0x0F5E, 2), + SseOpcode::Divss => (LegacyPrefixes::_F3, 0x0F5E, 2), + SseOpcode::Divsd => (LegacyPrefixes::_F2, 0x0F5E, 2), + SseOpcode::Maxps => (LegacyPrefixes::None, 0x0F5F, 2), + SseOpcode::Maxpd => (LegacyPrefixes::_66, 0x0F5F, 2), + SseOpcode::Maxss => (LegacyPrefixes::_F3, 0x0F5F, 2), + SseOpcode::Maxsd => (LegacyPrefixes::_F2, 0x0F5F, 2), + SseOpcode::Minps => (LegacyPrefixes::None, 0x0F5D, 2), + SseOpcode::Minpd => (LegacyPrefixes::_66, 0x0F5D, 2), + SseOpcode::Minss => (LegacyPrefixes::_F3, 0x0F5D, 2), + SseOpcode::Minsd => (LegacyPrefixes::_F2, 0x0F5D, 2), + SseOpcode::Movlhps => (LegacyPrefixes::None, 0x0F16, 2), + SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F10, 2), + SseOpcode::Mulps => (LegacyPrefixes::None, 0x0F59, 2), + SseOpcode::Mulpd => (LegacyPrefixes::_66, 0x0F59, 2), + SseOpcode::Mulss => (LegacyPrefixes::_F3, 0x0F59, 2), + SseOpcode::Mulsd => (LegacyPrefixes::_F2, 0x0F59, 2), + SseOpcode::Orpd => (LegacyPrefixes::_66, 0x0F56, 2), + SseOpcode::Orps => (LegacyPrefixes::None, 0x0F56, 2), + SseOpcode::Packssdw => (LegacyPrefixes::_66, 0x0F6B, 2), + SseOpcode::Packsswb => (LegacyPrefixes::_66, 0x0F63, 2), + SseOpcode::Packusdw => (LegacyPrefixes::_66, 0x0F382B, 3), + SseOpcode::Packuswb => (LegacyPrefixes::_66, 0x0F67, 2), + SseOpcode::Paddb => (LegacyPrefixes::_66, 0x0FFC, 2), + SseOpcode::Paddd => (LegacyPrefixes::_66, 0x0FFE, 2), + SseOpcode::Paddq => (LegacyPrefixes::_66, 0x0FD4, 2), + SseOpcode::Paddw => (LegacyPrefixes::_66, 0x0FFD, 2), + SseOpcode::Paddsb => (LegacyPrefixes::_66, 0x0FEC, 2), + SseOpcode::Paddsw => (LegacyPrefixes::_66, 0x0FED, 2), + SseOpcode::Paddusb => (LegacyPrefixes::_66, 0x0FDC, 2), + SseOpcode::Paddusw => (LegacyPrefixes::_66, 0x0FDD, 2), + SseOpcode::Pmaddubsw => (LegacyPrefixes::_66, 0x0F3804, 3), + SseOpcode::Pand => (LegacyPrefixes::_66, 0x0FDB, 2), + SseOpcode::Pandn => (LegacyPrefixes::_66, 0x0FDF, 2), + SseOpcode::Pavgb => (LegacyPrefixes::_66, 0x0FE0, 2), + SseOpcode::Pavgw => (LegacyPrefixes::_66, 0x0FE3, 2), + SseOpcode::Pcmpeqb => (LegacyPrefixes::_66, 0x0F74, 2), + SseOpcode::Pcmpeqw => (LegacyPrefixes::_66, 0x0F75, 2), + SseOpcode::Pcmpeqd => (LegacyPrefixes::_66, 0x0F76, 2), + SseOpcode::Pcmpeqq => (LegacyPrefixes::_66, 0x0F3829, 3), + SseOpcode::Pcmpgtb => (LegacyPrefixes::_66, 0x0F64, 2), + SseOpcode::Pcmpgtw => (LegacyPrefixes::_66, 0x0F65, 2), + SseOpcode::Pcmpgtd => (LegacyPrefixes::_66, 0x0F66, 2), + SseOpcode::Pcmpgtq => (LegacyPrefixes::_66, 0x0F3837, 3), + SseOpcode::Pmaddwd => (LegacyPrefixes::_66, 0x0FF5, 2), + SseOpcode::Pmaxsb => (LegacyPrefixes::_66, 0x0F383C, 3), + SseOpcode::Pmaxsw => (LegacyPrefixes::_66, 0x0FEE, 2), + SseOpcode::Pmaxsd => (LegacyPrefixes::_66, 0x0F383D, 3), + SseOpcode::Pmaxub => (LegacyPrefixes::_66, 0x0FDE, 2), + SseOpcode::Pmaxuw => (LegacyPrefixes::_66, 0x0F383E, 3), + SseOpcode::Pmaxud => (LegacyPrefixes::_66, 0x0F383F, 3), + SseOpcode::Pminsb => (LegacyPrefixes::_66, 0x0F3838, 3), + SseOpcode::Pminsw => (LegacyPrefixes::_66, 0x0FEA, 2), + SseOpcode::Pminsd => (LegacyPrefixes::_66, 0x0F3839, 3), + SseOpcode::Pminub => (LegacyPrefixes::_66, 0x0FDA, 2), + SseOpcode::Pminuw => (LegacyPrefixes::_66, 0x0F383A, 3), + SseOpcode::Pminud => (LegacyPrefixes::_66, 0x0F383B, 3), + SseOpcode::Pmuldq => (LegacyPrefixes::_66, 0x0F3828, 3), + SseOpcode::Pmulhw => (LegacyPrefixes::_66, 0x0FE5, 2), + SseOpcode::Pmulhrsw => (LegacyPrefixes::_66, 0x0F380B, 3), + SseOpcode::Pmulhuw => (LegacyPrefixes::_66, 0x0FE4, 2), + SseOpcode::Pmulld => (LegacyPrefixes::_66, 0x0F3840, 3), + SseOpcode::Pmullw => (LegacyPrefixes::_66, 0x0FD5, 2), + SseOpcode::Pmuludq => (LegacyPrefixes::_66, 0x0FF4, 2), + SseOpcode::Por => (LegacyPrefixes::_66, 0x0FEB, 2), + SseOpcode::Pshufb => (LegacyPrefixes::_66, 0x0F3800, 3), + SseOpcode::Psubb => (LegacyPrefixes::_66, 0x0FF8, 2), + SseOpcode::Psubd => (LegacyPrefixes::_66, 0x0FFA, 2), + SseOpcode::Psubq => (LegacyPrefixes::_66, 0x0FFB, 2), + SseOpcode::Psubw => (LegacyPrefixes::_66, 0x0FF9, 2), + SseOpcode::Psubsb => (LegacyPrefixes::_66, 0x0FE8, 2), + SseOpcode::Psubsw => (LegacyPrefixes::_66, 0x0FE9, 2), + SseOpcode::Psubusb => (LegacyPrefixes::_66, 0x0FD8, 2), + SseOpcode::Psubusw => (LegacyPrefixes::_66, 0x0FD9, 2), + SseOpcode::Punpckhbw => (LegacyPrefixes::_66, 0x0F68, 2), + SseOpcode::Punpckhwd => (LegacyPrefixes::_66, 0x0F69, 2), + SseOpcode::Punpcklbw => (LegacyPrefixes::_66, 0x0F60, 2), + SseOpcode::Punpcklwd => (LegacyPrefixes::_66, 0x0F61, 2), + SseOpcode::Punpckldq => (LegacyPrefixes::_66, 0x0F62, 2), + SseOpcode::Punpcklqdq => (LegacyPrefixes::_66, 0x0F6C, 2), + SseOpcode::Punpckhdq => (LegacyPrefixes::_66, 0x0F6A, 2), + SseOpcode::Punpckhqdq => (LegacyPrefixes::_66, 0x0F6D, 2), + SseOpcode::Pxor => (LegacyPrefixes::_66, 0x0FEF, 2), + SseOpcode::Subps => (LegacyPrefixes::None, 0x0F5C, 2), + SseOpcode::Subpd => (LegacyPrefixes::_66, 0x0F5C, 2), + SseOpcode::Subss => (LegacyPrefixes::_F3, 0x0F5C, 2), + SseOpcode::Subsd => (LegacyPrefixes::_F2, 0x0F5C, 2), + SseOpcode::Unpcklps => (LegacyPrefixes::None, 0x0F14, 2), + SseOpcode::Unpckhps => (LegacyPrefixes::None, 0x0F15, 2), + SseOpcode::Xorps => (LegacyPrefixes::None, 0x0F57, 2), + SseOpcode::Xorpd => (LegacyPrefixes::_66, 0x0F57, 2), + SseOpcode::Phaddw => (LegacyPrefixes::_66, 0x0F3801, 3), + SseOpcode::Phaddd => (LegacyPrefixes::_66, 0x0F3802, 3), + SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F10, 2), + SseOpcode::Cvtss2sd => (LegacyPrefixes::_F3, 0x0F5A, 2), + SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A, 2), + SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51, 2), + SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51, 2), + SseOpcode::Unpcklpd => (LegacyPrefixes::_66, 0x0F14, 2), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + + match src_e { + RegMem::Reg { reg: reg_e } => { + emit_std_reg_reg(sink, prefix, opcode, length, reg_g, reg_e, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, length, reg_g, addr, rex, 0); + } + } + } + + Inst::XmmRmRBlend { + op, + src1, + src2, + dst, + mask, + } => { + let src1 = src1.to_reg(); + let mask = mask.to_reg(); + debug_assert_eq!(mask, regs::xmm0()); + let reg_g = dst.to_reg().to_reg(); + debug_assert_eq!(src1, reg_g); + let src_e = src2.clone().to_reg_mem().clone(); + + let rex = RexFlags::clear_w(); + let (prefix, opcode, length) = match op { + SseOpcode::Blendvps => (LegacyPrefixes::_66, 0x0F3814, 3), + SseOpcode::Blendvpd => (LegacyPrefixes::_66, 0x0F3815, 3), + SseOpcode::Pblendvb => (LegacyPrefixes::_66, 0x0F3810, 3), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + + match src_e { + RegMem::Reg { reg: reg_e } => { + emit_std_reg_reg(sink, prefix, opcode, length, reg_g, reg_e, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, length, reg_g, addr, rex, 0); + } + } + } + + Inst::XmmRmiRVex { + op, + src1, + src2, + dst, + } => { + use LegacyPrefixes as LP; + use OpcodeMap as OM; + + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = src2.clone().to_reg_mem_imm().clone(); + + // When the opcode is commutative, src1 is xmm{0..7}, and src2 is + // xmm{8..15}, then we can swap the operands to save one byte on the + // instruction's encoding. + let (src1, src2) = match (src1, src2) { + (src1, RegMemImm::Reg { reg: src2 }) + if op.is_commutative() + && src1.to_real_reg().unwrap().hw_enc() < 8 + && src2.to_real_reg().unwrap().hw_enc() >= 8 => + { + (src2, RegMemImm::Reg { reg: src1 }) + } + (src1, src2) => (src1, src2), + }; + + let src2 = match src2 { + // For opcodes where one of the operands is an immediate the + // encoding is a bit different, notably the usage of + // `opcode_ext`, so handle that specially here. + RegMemImm::Imm { simm32 } => { + let (opcode, opcode_ext, prefix) = match op { + AvxOpcode::Vpsrlw => (0x71, 2, LegacyPrefixes::_66), + AvxOpcode::Vpsrld => (0x72, 2, LegacyPrefixes::_66), + AvxOpcode::Vpsrlq => (0x73, 2, LegacyPrefixes::_66), + AvxOpcode::Vpsllw => (0x71, 6, LegacyPrefixes::_66), + AvxOpcode::Vpslld => (0x72, 6, LegacyPrefixes::_66), + AvxOpcode::Vpsllq => (0x73, 6, LegacyPrefixes::_66), + AvxOpcode::Vpsraw => (0x71, 4, LegacyPrefixes::_66), + AvxOpcode::Vpsrad => (0x72, 4, LegacyPrefixes::_66), + _ => panic!("unexpected rmi_r_vex opcode with immediate {op:?}"), + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(OpcodeMap::_0F) + .opcode(opcode) + .opcode_ext(opcode_ext) + .vvvv(dst.to_real_reg().unwrap().hw_enc()) + .prefix(LegacyPrefixes::_66) + .rm(src1.to_real_reg().unwrap().hw_enc()) + .imm(simm32.try_into().unwrap()) + .encode(sink); + return; + } + RegMemImm::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMemImm::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + AvxOpcode::Vminps => (LP::None, OM::_0F, 0x5D), + AvxOpcode::Vminpd => (LP::_66, OM::_0F, 0x5D), + AvxOpcode::Vmaxps => (LP::None, OM::_0F, 0x5F), + AvxOpcode::Vmaxpd => (LP::_66, OM::_0F, 0x5F), + AvxOpcode::Vandnps => (LP::None, OM::_0F, 0x55), + AvxOpcode::Vandnpd => (LP::_66, OM::_0F, 0x55), + AvxOpcode::Vpandn => (LP::_66, OM::_0F, 0xDF), + AvxOpcode::Vpsrlw => (LP::_66, OM::_0F, 0xD1), + AvxOpcode::Vpsrld => (LP::_66, OM::_0F, 0xD2), + AvxOpcode::Vpsrlq => (LP::_66, OM::_0F, 0xD3), + AvxOpcode::Vpaddb => (LP::_66, OM::_0F, 0xFC), + AvxOpcode::Vpaddw => (LP::_66, OM::_0F, 0xFD), + AvxOpcode::Vpaddd => (LP::_66, OM::_0F, 0xFE), + AvxOpcode::Vpaddq => (LP::_66, OM::_0F, 0xD4), + AvxOpcode::Vpaddsb => (LP::_66, OM::_0F, 0xEC), + AvxOpcode::Vpaddsw => (LP::_66, OM::_0F, 0xED), + AvxOpcode::Vpaddusb => (LP::_66, OM::_0F, 0xDC), + AvxOpcode::Vpaddusw => (LP::_66, OM::_0F, 0xDD), + AvxOpcode::Vpsubb => (LP::_66, OM::_0F, 0xF8), + AvxOpcode::Vpsubw => (LP::_66, OM::_0F, 0xF9), + AvxOpcode::Vpsubd => (LP::_66, OM::_0F, 0xFA), + AvxOpcode::Vpsubq => (LP::_66, OM::_0F, 0xFB), + AvxOpcode::Vpsubsb => (LP::_66, OM::_0F, 0xE8), + AvxOpcode::Vpsubsw => (LP::_66, OM::_0F, 0xE9), + AvxOpcode::Vpsubusb => (LP::_66, OM::_0F, 0xD8), + AvxOpcode::Vpsubusw => (LP::_66, OM::_0F, 0xD9), + AvxOpcode::Vpavgb => (LP::_66, OM::_0F, 0xE0), + AvxOpcode::Vpavgw => (LP::_66, OM::_0F, 0xE3), + AvxOpcode::Vpand => (LP::_66, OM::_0F, 0xDB), + AvxOpcode::Vandps => (LP::None, OM::_0F, 0x54), + AvxOpcode::Vandpd => (LP::_66, OM::_0F, 0x54), + AvxOpcode::Vpor => (LP::_66, OM::_0F, 0xEB), + AvxOpcode::Vorps => (LP::None, OM::_0F, 0x56), + AvxOpcode::Vorpd => (LP::_66, OM::_0F, 0x56), + AvxOpcode::Vpxor => (LP::_66, OM::_0F, 0xEF), + AvxOpcode::Vxorps => (LP::None, OM::_0F, 0x57), + AvxOpcode::Vxorpd => (LP::_66, OM::_0F, 0x57), + AvxOpcode::Vpmullw => (LP::_66, OM::_0F, 0xD5), + AvxOpcode::Vpmulld => (LP::_66, OM::_0F38, 0x40), + AvxOpcode::Vpmulhw => (LP::_66, OM::_0F, 0xE5), + AvxOpcode::Vpmulhrsw => (LP::_66, OM::_0F38, 0x0B), + AvxOpcode::Vpmulhuw => (LP::_66, OM::_0F, 0xE4), + AvxOpcode::Vpmuldq => (LP::_66, OM::_0F38, 0x28), + AvxOpcode::Vpmuludq => (LP::_66, OM::_0F, 0xF4), + AvxOpcode::Vpunpckhwd => (LP::_66, OM::_0F, 0x69), + AvxOpcode::Vpunpcklwd => (LP::_66, OM::_0F, 0x61), + AvxOpcode::Vunpcklps => (LP::None, OM::_0F, 0x14), + AvxOpcode::Vunpckhps => (LP::None, OM::_0F, 0x15), + AvxOpcode::Vaddps => (LP::None, OM::_0F, 0x58), + AvxOpcode::Vaddpd => (LP::_66, OM::_0F, 0x58), + AvxOpcode::Vsubps => (LP::None, OM::_0F, 0x5C), + AvxOpcode::Vsubpd => (LP::_66, OM::_0F, 0x5C), + AvxOpcode::Vmulps => (LP::None, OM::_0F, 0x59), + AvxOpcode::Vmulpd => (LP::_66, OM::_0F, 0x59), + AvxOpcode::Vdivps => (LP::None, OM::_0F, 0x5E), + AvxOpcode::Vdivpd => (LP::_66, OM::_0F, 0x5E), + AvxOpcode::Vpcmpeqb => (LP::_66, OM::_0F, 0x74), + AvxOpcode::Vpcmpeqw => (LP::_66, OM::_0F, 0x75), + AvxOpcode::Vpcmpeqd => (LP::_66, OM::_0F, 0x76), + AvxOpcode::Vpcmpeqq => (LP::_66, OM::_0F38, 0x29), + AvxOpcode::Vpcmpgtb => (LP::_66, OM::_0F, 0x64), + AvxOpcode::Vpcmpgtw => (LP::_66, OM::_0F, 0x65), + AvxOpcode::Vpcmpgtd => (LP::_66, OM::_0F, 0x66), + AvxOpcode::Vpcmpgtq => (LP::_66, OM::_0F38, 0x37), + AvxOpcode::Vmovlhps => (LP::None, OM::_0F, 0x16), + AvxOpcode::Vpminsb => (LP::_66, OM::_0F38, 0x38), + AvxOpcode::Vpminsw => (LP::_66, OM::_0F, 0xEA), + AvxOpcode::Vpminsd => (LP::_66, OM::_0F38, 0x39), + AvxOpcode::Vpmaxsb => (LP::_66, OM::_0F38, 0x3C), + AvxOpcode::Vpmaxsw => (LP::_66, OM::_0F, 0xEE), + AvxOpcode::Vpmaxsd => (LP::_66, OM::_0F38, 0x3D), + AvxOpcode::Vpminub => (LP::_66, OM::_0F, 0xDA), + AvxOpcode::Vpminuw => (LP::_66, OM::_0F38, 0x3A), + AvxOpcode::Vpminud => (LP::_66, OM::_0F38, 0x3B), + AvxOpcode::Vpmaxub => (LP::_66, OM::_0F, 0xDE), + AvxOpcode::Vpmaxuw => (LP::_66, OM::_0F38, 0x3E), + AvxOpcode::Vpmaxud => (LP::_66, OM::_0F38, 0x3F), + AvxOpcode::Vpunpcklbw => (LP::_66, OM::_0F, 0x60), + AvxOpcode::Vpunpckhbw => (LP::_66, OM::_0F, 0x68), + AvxOpcode::Vpacksswb => (LP::_66, OM::_0F, 0x63), + AvxOpcode::Vpackssdw => (LP::_66, OM::_0F, 0x6B), + AvxOpcode::Vpackuswb => (LP::_66, OM::_0F, 0x67), + AvxOpcode::Vpackusdw => (LP::_66, OM::_0F38, 0x2B), + AvxOpcode::Vpmaddwd => (LP::_66, OM::_0F, 0xF5), + AvxOpcode::Vpmaddubsw => (LP::_66, OM::_0F38, 0x04), + AvxOpcode::Vpshufb => (LP::_66, OM::_0F38, 0x00), + AvxOpcode::Vpsllw => (LP::_66, OM::_0F, 0xF1), + AvxOpcode::Vpslld => (LP::_66, OM::_0F, 0xF2), + AvxOpcode::Vpsllq => (LP::_66, OM::_0F, 0xF3), + AvxOpcode::Vpsraw => (LP::_66, OM::_0F, 0xE1), + AvxOpcode::Vpsrad => (LP::_66, OM::_0F, 0xE2), + AvxOpcode::Vaddss => (LP::_F3, OM::_0F, 0x58), + AvxOpcode::Vaddsd => (LP::_F2, OM::_0F, 0x58), + AvxOpcode::Vmulss => (LP::_F3, OM::_0F, 0x59), + AvxOpcode::Vmulsd => (LP::_F2, OM::_0F, 0x59), + AvxOpcode::Vsubss => (LP::_F3, OM::_0F, 0x5C), + AvxOpcode::Vsubsd => (LP::_F2, OM::_0F, 0x5C), + AvxOpcode::Vdivss => (LP::_F3, OM::_0F, 0x5E), + AvxOpcode::Vdivsd => (LP::_F2, OM::_0F, 0x5E), + AvxOpcode::Vminss => (LP::_F3, OM::_0F, 0x5D), + AvxOpcode::Vminsd => (LP::_F2, OM::_0F, 0x5D), + AvxOpcode::Vmaxss => (LP::_F3, OM::_0F, 0x5F), + AvxOpcode::Vmaxsd => (LP::_F2, OM::_0F, 0x5F), + AvxOpcode::Vphaddw => (LP::_66, OM::_0F38, 0x01), + AvxOpcode::Vphaddd => (LP::_66, OM::_0F38, 0x02), + AvxOpcode::Vpunpckldq => (LP::_66, OM::_0F, 0x62), + AvxOpcode::Vpunpckhdq => (LP::_66, OM::_0F, 0x6A), + AvxOpcode::Vpunpcklqdq => (LP::_66, OM::_0F, 0x6C), + AvxOpcode::Vpunpckhqdq => (LP::_66, OM::_0F, 0x6D), + AvxOpcode::Vmovsd => (LP::_F2, OM::_0F, 0x10), + AvxOpcode::Vmovss => (LP::_F3, OM::_0F, 0x10), + AvxOpcode::Vcvtss2sd => (LP::_F3, OM::_0F, 0x5A), + AvxOpcode::Vcvtsd2ss => (LP::_F2, OM::_0F, 0x5A), + AvxOpcode::Vsqrtss => (LP::_F3, OM::_0F, 0x51), + AvxOpcode::Vsqrtsd => (LP::_F2, OM::_0F, 0x51), + AvxOpcode::Vunpcklpd => (LP::_66, OM::_0F, 0x14), + _ => panic!("unexpected rmir vex opcode {op:?}"), + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .encode(sink); + } + + Inst::XmmRmRImmVex { + op, + src1, + src2, + dst, + imm, + } => { + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (w, prefix, map, opcode) = match op { + AvxOpcode::Vcmpps => (false, LegacyPrefixes::None, OpcodeMap::_0F, 0xC2), + AvxOpcode::Vcmppd => (false, LegacyPrefixes::_66, OpcodeMap::_0F, 0xC2), + AvxOpcode::Vpalignr => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0F), + AvxOpcode::Vinsertps => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x21), + AvxOpcode::Vshufps => (false, LegacyPrefixes::None, OpcodeMap::_0F, 0xC6), + AvxOpcode::Vpblendw => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0E), + _ => panic!("unexpected rmr_imm_vex opcode {op:?}"), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .w(w) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .imm(*imm) + .encode(sink); + } + + Inst::XmmVexPinsr { + op, + src1, + src2, + dst, + imm, + } => { + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (w, map, opcode) = match op { + AvxOpcode::Vpinsrb => (false, OpcodeMap::_0F3A, 0x20), + AvxOpcode::Vpinsrw => (false, OpcodeMap::_0F, 0xC4), + AvxOpcode::Vpinsrd => (false, OpcodeMap::_0F3A, 0x22), + AvxOpcode::Vpinsrq => (true, OpcodeMap::_0F3A, 0x22), + _ => panic!("unexpected vex_pinsr opcode {op:?}"), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(map) + .w(w) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .imm(*imm) + .encode(sink); + } + + Inst::XmmRmRVex3 { + op, + src1, + src2, + src3, + dst, + } => { + let src1 = src1.to_reg(); + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(src1, dst); + let src2 = src2.to_reg(); + let src3 = match src3.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (w, map, opcode) = match op { + AvxOpcode::Vfmadd132ss => (false, OpcodeMap::_0F38, 0x99), + AvxOpcode::Vfmadd213ss => (false, OpcodeMap::_0F38, 0xA9), + AvxOpcode::Vfnmadd132ss => (false, OpcodeMap::_0F38, 0x9D), + AvxOpcode::Vfnmadd213ss => (false, OpcodeMap::_0F38, 0xAD), + AvxOpcode::Vfmadd132sd => (true, OpcodeMap::_0F38, 0x99), + AvxOpcode::Vfmadd213sd => (true, OpcodeMap::_0F38, 0xA9), + AvxOpcode::Vfnmadd132sd => (true, OpcodeMap::_0F38, 0x9D), + AvxOpcode::Vfnmadd213sd => (true, OpcodeMap::_0F38, 0xAD), + AvxOpcode::Vfmadd132ps => (false, OpcodeMap::_0F38, 0x98), + AvxOpcode::Vfmadd213ps => (false, OpcodeMap::_0F38, 0xA8), + AvxOpcode::Vfnmadd132ps => (false, OpcodeMap::_0F38, 0x9C), + AvxOpcode::Vfnmadd213ps => (false, OpcodeMap::_0F38, 0xAC), + AvxOpcode::Vfmadd132pd => (true, OpcodeMap::_0F38, 0x98), + AvxOpcode::Vfmadd213pd => (true, OpcodeMap::_0F38, 0xA8), + AvxOpcode::Vfnmadd132pd => (true, OpcodeMap::_0F38, 0x9C), + AvxOpcode::Vfnmadd213pd => (true, OpcodeMap::_0F38, 0xAC), + AvxOpcode::Vfmsub132ss => (false, OpcodeMap::_0F38, 0x9B), + AvxOpcode::Vfmsub213ss => (false, OpcodeMap::_0F38, 0xAB), + AvxOpcode::Vfnmsub132ss => (false, OpcodeMap::_0F38, 0x9F), + AvxOpcode::Vfnmsub213ss => (false, OpcodeMap::_0F38, 0xAF), + AvxOpcode::Vfmsub132sd => (true, OpcodeMap::_0F38, 0x9B), + AvxOpcode::Vfmsub213sd => (true, OpcodeMap::_0F38, 0xAB), + AvxOpcode::Vfnmsub132sd => (true, OpcodeMap::_0F38, 0x9F), + AvxOpcode::Vfnmsub213sd => (true, OpcodeMap::_0F38, 0xAF), + AvxOpcode::Vfmsub132ps => (false, OpcodeMap::_0F38, 0x9A), + AvxOpcode::Vfmsub213ps => (false, OpcodeMap::_0F38, 0xAA), + AvxOpcode::Vfnmsub132ps => (false, OpcodeMap::_0F38, 0x9E), + AvxOpcode::Vfnmsub213ps => (false, OpcodeMap::_0F38, 0xAE), + AvxOpcode::Vfmsub132pd => (true, OpcodeMap::_0F38, 0x9A), + AvxOpcode::Vfmsub213pd => (true, OpcodeMap::_0F38, 0xAA), + AvxOpcode::Vfnmsub132pd => (true, OpcodeMap::_0F38, 0x9E), + AvxOpcode::Vfnmsub213pd => (true, OpcodeMap::_0F38, 0xAE), + AvxOpcode::Vblendvps => (false, OpcodeMap::_0F3A, 0x4A), + AvxOpcode::Vblendvpd => (false, OpcodeMap::_0F3A, 0x4B), + AvxOpcode::Vpblendvb => (false, OpcodeMap::_0F3A, 0x4C), + _ => unreachable!(), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(map) + .w(w) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src3) + .vvvv(src2.to_real_reg().unwrap().hw_enc()) + .encode(sink); + } + + Inst::XmmRmRBlendVex { + op, + src1, + src2, + mask, + dst, + } => { + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + let mask = mask.to_reg(); + + let opcode = match op { + AvxOpcode::Vblendvps => 0x4A, + AvxOpcode::Vblendvpd => 0x4B, + AvxOpcode::Vpblendvb => 0x4C, + _ => unreachable!(), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(OpcodeMap::_0F3A) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .imm(mask.to_real_reg().unwrap().hw_enc() << 4) + .encode(sink); + } + + Inst::XmmUnaryRmRVex { op, src, dst } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + AvxOpcode::Vpmovsxbw => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x20), + AvxOpcode::Vpmovzxbw => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x30), + AvxOpcode::Vpmovsxwd => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x23), + AvxOpcode::Vpmovzxwd => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x33), + AvxOpcode::Vpmovsxdq => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x25), + AvxOpcode::Vpmovzxdq => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x35), + AvxOpcode::Vpabsb => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x1C), + AvxOpcode::Vpabsw => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x1D), + AvxOpcode::Vpabsd => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x1E), + AvxOpcode::Vsqrtps => (LegacyPrefixes::None, OpcodeMap::_0F, 0x51), + AvxOpcode::Vsqrtpd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x51), + AvxOpcode::Vcvtdq2pd => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0xE6), + AvxOpcode::Vcvtdq2ps => (LegacyPrefixes::None, OpcodeMap::_0F, 0x5B), + AvxOpcode::Vcvtpd2ps => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x5A), + AvxOpcode::Vcvtps2pd => (LegacyPrefixes::None, OpcodeMap::_0F, 0x5A), + AvxOpcode::Vcvttpd2dq => (LegacyPrefixes::_66, OpcodeMap::_0F, 0xE6), + AvxOpcode::Vcvttps2dq => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x5B), + AvxOpcode::Vmovdqu => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x6F), + AvxOpcode::Vmovups => (LegacyPrefixes::None, OpcodeMap::_0F, 0x10), + AvxOpcode::Vmovupd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x10), + + // Note that for `vmov{s,d}` the `inst.isle` rules should + // statically ensure that only `Amode` operands are used here. + // Otherwise the other encodings of `vmovss` are more like + // 2-operand instructions which this unary encoding does not + // have. + AvxOpcode::Vmovss => match &src { + RegisterOrAmode::Amode(_) => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x10), + _ => unreachable!(), + }, + AvxOpcode::Vmovsd => match &src { + RegisterOrAmode::Amode(_) => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x10), + _ => unreachable!(), + }, + + AvxOpcode::Vpbroadcastb => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x78), + AvxOpcode::Vpbroadcastw => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x79), + AvxOpcode::Vpbroadcastd => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x58), + AvxOpcode::Vbroadcastss => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x18), + AvxOpcode::Vmovddup => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x12), + + _ => panic!("unexpected rmr_imm_vex opcode {op:?}"), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src) + .encode(sink); + } + + Inst::XmmUnaryRmRImmVex { op, src, dst, imm } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + AvxOpcode::Vroundps => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x08), + AvxOpcode::Vroundpd => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x09), + AvxOpcode::Vpshuflw => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x70), + AvxOpcode::Vpshufhw => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x70), + AvxOpcode::Vpshufd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x70), + AvxOpcode::Vroundss => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0A), + AvxOpcode::Vroundsd => (LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x0B), + _ => panic!("unexpected rmr_imm_vex opcode {op:?}"), + }; + + let vex = VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .opcode(opcode) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .rm(src) + .imm(*imm); + + // See comments in similar block above in `XmmUnaryRmRVex` for what + // this is doing. + let vex = match op { + AvxOpcode::Vroundss | AvxOpcode::Vroundsd => { + vex.vvvv(dst.to_real_reg().unwrap().hw_enc()) + } + _ => vex, + }; + vex.encode(sink); + } + + Inst::XmmMovRMVex { op, src, dst } => { + let src = src.to_reg(); + let dst = dst.clone().finalize(state.frame_layout(), sink); + + let (prefix, map, opcode) = match op { + AvxOpcode::Vmovdqu => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x7F), + AvxOpcode::Vmovss => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x11), + AvxOpcode::Vmovsd => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x11), + AvxOpcode::Vmovups => (LegacyPrefixes::None, OpcodeMap::_0F, 0x11), + AvxOpcode::Vmovupd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x11), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(dst) + .reg(src.to_real_reg().unwrap().hw_enc()) + .encode(sink); + } + + Inst::XmmMovRMImmVex { op, src, dst, imm } => { + let src = src.to_reg(); + let dst = dst.clone().finalize(state.frame_layout(), sink); + + let (w, prefix, map, opcode) = match op { + AvxOpcode::Vpextrb => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x14), + AvxOpcode::Vpextrw => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x15), + AvxOpcode::Vpextrd => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x16), + AvxOpcode::Vpextrq => (true, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x16), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .w(w) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(dst) + .reg(src.to_real_reg().unwrap().hw_enc()) + .imm(*imm) + .encode(sink); + } + + Inst::XmmToGprImmVex { op, src, dst, imm } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + + let (w, prefix, map, opcode) = match op { + AvxOpcode::Vpextrb => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x14), + AvxOpcode::Vpextrw => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x15), + AvxOpcode::Vpextrd => (false, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x16), + AvxOpcode::Vpextrq => (true, LegacyPrefixes::_66, OpcodeMap::_0F3A, 0x16), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .w(w) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(dst.to_real_reg().unwrap().hw_enc()) + .reg(src.to_real_reg().unwrap().hw_enc()) + .imm(*imm) + .encode(sink); + } + + Inst::XmmToGprVex { + op, + src, + dst, + dst_size, + } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + + let (prefix, map, opcode) = match op { + // vmovd/vmovq are differentiated by `w` + AvxOpcode::Vmovd | AvxOpcode::Vmovq => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x7E), + AvxOpcode::Vmovmskps => (LegacyPrefixes::None, OpcodeMap::_0F, 0x50), + AvxOpcode::Vmovmskpd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x50), + AvxOpcode::Vpmovmskb => (LegacyPrefixes::_66, OpcodeMap::_0F, 0xD7), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let w = match dst_size { + OperandSize::Size64 => true, + _ => false, + }; + let mut vex = VexInstruction::new() + .length(VexVectorLength::V128) + .w(w) + .prefix(prefix) + .map(map) + .opcode(opcode); + vex = match op { + // The `vmovq/vmovd` reverse the order of the destination/source + // relative to other opcodes using this shape of instruction. + AvxOpcode::Vmovd | AvxOpcode::Vmovq => vex + .rm(dst.to_real_reg().unwrap().hw_enc()) + .reg(src.to_real_reg().unwrap().hw_enc()), + _ => vex + .rm(src.to_real_reg().unwrap().hw_enc()) + .reg(dst.to_real_reg().unwrap().hw_enc()), + }; + vex.encode(sink); + } + + Inst::GprToXmmVex { + op, + src, + dst, + src_size, + } => { + let dst = dst.to_reg().to_reg(); + let src = match src.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + // vmovd/vmovq are differentiated by `w` + AvxOpcode::Vmovd | AvxOpcode::Vmovq => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x6E), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let w = match src_size { + OperandSize::Size64 => true, + _ => false, + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .w(w) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(src) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .encode(sink); + } + + Inst::XmmCmpRmRVex { op, src1, src2 } => { + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + AvxOpcode::Vucomiss => (LegacyPrefixes::None, OpcodeMap::_0F, 0x2E), + AvxOpcode::Vucomisd => (LegacyPrefixes::_66, OpcodeMap::_0F, 0x2E), + AvxOpcode::Vptest => (LegacyPrefixes::_66, OpcodeMap::_0F38, 0x17), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + + VexInstruction::new() + .length(VexVectorLength::V128) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(src2) + .reg(src1.to_real_reg().unwrap().hw_enc()) + .encode(sink); + } + + Inst::XmmRmREvex { + op, + src1, + src2, + dst, + } + | Inst::XmmRmREvex3 { + op, + src1: _, // `dst` reuses `src1`. + src2: src1, + src3: src2, + dst, + } => { + let reused_src = match inst { + Inst::XmmRmREvex3 { src1, .. } => Some(src1.to_reg()), + _ => None, + }; + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + let dst = dst.to_reg().to_reg(); + if let Some(src1) = reused_src { + debug_assert_eq!(src1, dst); + } + + let (w, opcode, map) = match op { + Avx512Opcode::Vpermi2b => (false, 0x75, OpcodeMap::_0F38), + Avx512Opcode::Vpmullq => (true, 0x40, OpcodeMap::_0F38), + Avx512Opcode::Vpsraq => (true, 0xE2, OpcodeMap::_0F), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + EvexInstruction::new() + .length(EvexVectorLength::V128) + .prefix(LegacyPrefixes::_66) + .map(map) + .w(w) + .opcode(opcode) + .tuple_type(op.tuple_type()) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvvv(src1.to_real_reg().unwrap().hw_enc()) + .rm(src2) + .encode(sink); + } + + Inst::XmmMinMaxSeq { + size, + is_min, + lhs, + rhs, + dst, + } => { + let rhs = rhs.to_reg(); + let lhs = lhs.to_reg(); + let dst = dst.to_writable_reg(); + debug_assert_eq!(rhs, dst.to_reg()); + + // Generates the following sequence: + // cmpss/cmpsd %lhs, %rhs_dst + // jnz do_min_max + // jp propagate_nan + // + // ;; ordered and equal: propagate the sign bit (for -0 vs 0): + // {and,or}{ss,sd} %lhs, %rhs_dst + // j done + // + // ;; to get the desired NaN behavior (signalling NaN transformed into a quiet NaN, the + // ;; NaN value is returned), we add both inputs. + // propagate_nan: + // add{ss,sd} %lhs, %rhs_dst + // j done + // + // do_min_max: + // {min,max}{ss,sd} %lhs, %rhs_dst + // + // done: + let done = sink.get_label(); + let propagate_nan = sink.get_label(); + let do_min_max = sink.get_label(); + + let (add_op, cmp_op, and_op, or_op, min_max_op) = match size { + OperandSize::Size32 => ( + SseOpcode::Addss, + SseOpcode::Ucomiss, + SseOpcode::Andps, + SseOpcode::Orps, + if *is_min { + SseOpcode::Minss + } else { + SseOpcode::Maxss + }, + ), + OperandSize::Size64 => ( + SseOpcode::Addsd, + SseOpcode::Ucomisd, + SseOpcode::Andpd, + SseOpcode::Orpd, + if *is_min { + SseOpcode::Minsd + } else { + SseOpcode::Maxsd + }, + ), + _ => unreachable!(), + }; + + let inst = Inst::xmm_cmp_rm_r(cmp_op, dst.to_reg(), RegMem::reg(lhs)); + inst.emit(sink, info, state); + + one_way_jmp(sink, CC::NZ, do_min_max); + one_way_jmp(sink, CC::P, propagate_nan); + + // Ordered and equal. The operands are bit-identical unless they are zero + // and negative zero. These instructions merge the sign bits in that + // case, and are no-ops otherwise. + let op = if *is_min { or_op } else { and_op }; + let inst = Inst::xmm_rm_r(op, RegMem::reg(lhs), dst); + inst.emit(sink, info, state); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + + // x86's min/max are not symmetric; if either operand is a NaN, they return the + // read-only operand: perform an addition between the two operands, which has the + // desired NaN propagation effects. + sink.bind_label(propagate_nan, state.ctrl_plane_mut()); + let inst = Inst::xmm_rm_r(add_op, RegMem::reg(lhs), dst); + inst.emit(sink, info, state); + + one_way_jmp(sink, CC::P, done); + + sink.bind_label(do_min_max, state.ctrl_plane_mut()); + + let inst = Inst::xmm_rm_r(min_max_op, RegMem::reg(lhs), dst); + inst.emit(sink, info, state); + + sink.bind_label(done, state.ctrl_plane_mut()); + } + + Inst::XmmRmRImm { + op, + src1, + src2, + dst, + imm, + size, + } => { + let src1 = *src1; + let dst = dst.to_reg(); + let src2 = src2.clone(); + debug_assert_eq!(src1, dst); + + let (prefix, opcode, len) = match op { + SseOpcode::Cmpps => (LegacyPrefixes::None, 0x0FC2, 2), + SseOpcode::Cmppd => (LegacyPrefixes::_66, 0x0FC2, 2), + SseOpcode::Cmpss => (LegacyPrefixes::_F3, 0x0FC2, 2), + SseOpcode::Cmpsd => (LegacyPrefixes::_F2, 0x0FC2, 2), + SseOpcode::Insertps => (LegacyPrefixes::_66, 0x0F3A21, 3), + SseOpcode::Palignr => (LegacyPrefixes::_66, 0x0F3A0F, 3), + SseOpcode::Pinsrb => (LegacyPrefixes::_66, 0x0F3A20, 3), + SseOpcode::Pinsrw => (LegacyPrefixes::_66, 0x0FC4, 2), + SseOpcode::Pinsrd => (LegacyPrefixes::_66, 0x0F3A22, 3), + SseOpcode::Shufps => (LegacyPrefixes::None, 0x0FC6, 2), + SseOpcode::Pblendw => (LegacyPrefixes::_66, 0x0F3A0E, 3), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let rex = RexFlags::from(*size); + let regs_swapped = match *op { + // These opcodes (and not the SSE2 version of PEXTRW) flip the operand + // encoding: `dst` in ModRM's r/m, `src` in ModRM's reg field. + SseOpcode::Pextrb | SseOpcode::Pextrd => true, + // The rest of the opcodes have the customary encoding: `dst` in ModRM's reg, + // `src` in ModRM's r/m field. + _ => false, + }; + match src2 { + RegMem::Reg { reg } => { + if regs_swapped { + emit_std_reg_reg(sink, prefix, opcode, len, reg, dst, rex); + } else { + emit_std_reg_reg(sink, prefix, opcode, len, dst, reg, rex); + } + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + assert!( + !regs_swapped, + "No existing way to encode a mem argument in the ModRM r/m field." + ); + // N.B.: bytes_at_end == 1, because of the `imm` byte below. + emit_std_reg_mem(sink, prefix, opcode, len, dst, addr, rex, 1); + } + } + sink.put1(*imm); + } + + Inst::XmmUninitializedValue { .. } => { + // This instruction format only exists to declare a register as a `def`; no code is + // emitted. + } + + Inst::XmmMovRM { op, src, dst } => { + let src = src.to_reg(); + let dst = dst.clone(); + + let (prefix, opcode) = match op { + SseOpcode::Movaps => (LegacyPrefixes::None, 0x0F29), + SseOpcode::Movapd => (LegacyPrefixes::_66, 0x0F29), + SseOpcode::Movdqu => (LegacyPrefixes::_F3, 0x0F7F), + SseOpcode::Movss => (LegacyPrefixes::_F3, 0x0F11), + SseOpcode::Movsd => (LegacyPrefixes::_F2, 0x0F11), + SseOpcode::Movups => (LegacyPrefixes::None, 0x0F11), + SseOpcode::Movupd => (LegacyPrefixes::_66, 0x0F11), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let dst = &dst.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, 2, src, dst, RexFlags::clear_w(), 0); + } + + Inst::XmmMovRMImm { op, src, dst, imm } => { + let src = src.to_reg(); + let dst = dst.clone(); + + let (w, prefix, opcode) = match op { + SseOpcode::Pextrb => (false, LegacyPrefixes::_66, 0x0F3A14), + SseOpcode::Pextrw => (false, LegacyPrefixes::_66, 0x0F3A15), + SseOpcode::Pextrd => (false, LegacyPrefixes::_66, 0x0F3A16), + SseOpcode::Pextrq => (true, LegacyPrefixes::_66, 0x0F3A16), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let rex = if w { + RexFlags::set_w() + } else { + RexFlags::clear_w() + }; + let dst = &dst.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, 3, src, dst, rex, 1); + sink.put1(*imm); + } + + Inst::XmmToGpr { + op, + src, + dst, + dst_size, + } => { + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + + let (prefix, opcode, dst_first) = match op { + SseOpcode::Cvttss2si => (LegacyPrefixes::_F3, 0x0F2C, true), + SseOpcode::Cvttsd2si => (LegacyPrefixes::_F2, 0x0F2C, true), + // Movd and movq use the same opcode; the presence of the REX prefix (set below) + // actually determines which is used. + SseOpcode::Movd | SseOpcode::Movq => (LegacyPrefixes::_66, 0x0F7E, false), + SseOpcode::Movmskps => (LegacyPrefixes::None, 0x0F50, true), + SseOpcode::Movmskpd => (LegacyPrefixes::_66, 0x0F50, true), + SseOpcode::Pmovmskb => (LegacyPrefixes::_66, 0x0FD7, true), + _ => panic!("unexpected opcode {op:?}"), + }; + let rex = RexFlags::from(*dst_size); + let (src, dst) = if dst_first { (dst, src) } else { (src, dst) }; + + emit_std_reg_reg(sink, prefix, opcode, 2, src, dst, rex); + } + + Inst::XmmToGprImm { op, src, dst, imm } => { + use OperandSize as OS; + + let src = src.to_reg(); + let dst = dst.to_reg().to_reg(); + + let (prefix, opcode, opcode_bytes, dst_size, dst_first) = match op { + SseOpcode::Pextrb => (LegacyPrefixes::_66, 0x0F3A14, 3, OS::Size32, false), + SseOpcode::Pextrw => (LegacyPrefixes::_66, 0x0FC5, 2, OS::Size32, true), + SseOpcode::Pextrd => (LegacyPrefixes::_66, 0x0F3A16, 3, OS::Size32, false), + SseOpcode::Pextrq => (LegacyPrefixes::_66, 0x0F3A16, 3, OS::Size64, false), + _ => panic!("unexpected opcode {op:?}"), + }; + let rex = RexFlags::from(dst_size); + let (src, dst) = if dst_first { (dst, src) } else { (src, dst) }; + + emit_std_reg_reg(sink, prefix, opcode, opcode_bytes, src, dst, rex); + sink.put1(*imm); + } + + Inst::GprToXmm { + op, + src: src_e, + dst: reg_g, + src_size, + } => { + let reg_g = reg_g.to_reg().to_reg(); + let src_e = src_e.clone().to_reg_mem().clone(); + + let (prefix, opcode) = match op { + // Movd and movq use the same opcode; the presence of the REX prefix (set below) + // actually determines which is used. + SseOpcode::Movd | SseOpcode::Movq => (LegacyPrefixes::_66, 0x0F6E), + _ => panic!("unexpected opcode {op:?}"), + }; + let rex = RexFlags::from(*src_size); + match src_e { + RegMem::Reg { reg: reg_e } => { + emit_std_reg_reg(sink, prefix, opcode, 2, reg_g, reg_e, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, 2, reg_g, addr, rex, 0); + } + } + } + + Inst::XmmCmpRmR { op, src1, src2 } => { + let src1 = src1.to_reg(); + let src2 = src2.clone().to_reg_mem().clone(); + + let rex = RexFlags::clear_w(); + let (prefix, opcode, len) = match op { + SseOpcode::Ptest => (LegacyPrefixes::_66, 0x0F3817, 3), + SseOpcode::Ucomisd => (LegacyPrefixes::_66, 0x0F2E, 2), + SseOpcode::Ucomiss => (LegacyPrefixes::None, 0x0F2E, 2), + _ => unimplemented!("Emit xmm cmp rm r"), + }; + + match src2 { + RegMem::Reg { reg } => { + emit_std_reg_reg(sink, prefix, opcode, len, src1, reg, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, len, src1, addr, rex, 0); + } + } + } + + Inst::CvtIntToFloat { + op, + src1, + src2, + dst, + src2_size, + } => { + let src1 = src1.to_reg(); + let dst = dst.to_reg().to_reg(); + assert_eq!(src1, dst); + let src2 = src2.clone().to_reg_mem().clone(); + + let (prefix, opcode) = match op { + SseOpcode::Cvtsi2ss => (LegacyPrefixes::_F3, 0x0F2A), + SseOpcode::Cvtsi2sd => (LegacyPrefixes::_F2, 0x0F2A), + _ => panic!("unexpected opcode {op:?}"), + }; + let rex = RexFlags::from(*src2_size); + match src2 { + RegMem::Reg { reg: src2 } => { + emit_std_reg_reg(sink, prefix, opcode, 2, dst, src2, rex); + } + RegMem::Mem { addr } => { + let addr = &addr.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcode, 2, dst, addr, rex, 0); + } + } + } + + Inst::CvtIntToFloatVex { + op, + src1, + src2, + dst, + src2_size, + } => { + let dst = dst.to_reg().to_reg(); + let src1 = src1.to_reg(); + let src2 = match src2.clone().to_reg_mem().clone() { + RegMem::Reg { reg } => { + RegisterOrAmode::Register(reg.to_real_reg().unwrap().hw_enc().into()) + } + RegMem::Mem { addr } => { + RegisterOrAmode::Amode(addr.finalize(state.frame_layout(), sink)) + } + }; + + let (prefix, map, opcode) = match op { + AvxOpcode::Vcvtsi2ss => (LegacyPrefixes::_F3, OpcodeMap::_0F, 0x2A), + AvxOpcode::Vcvtsi2sd => (LegacyPrefixes::_F2, OpcodeMap::_0F, 0x2A), + _ => unimplemented!("Opcode {:?} not implemented", op), + }; + let w = match src2_size { + OperandSize::Size64 => true, + _ => false, + }; + VexInstruction::new() + .length(VexVectorLength::V128) + .w(w) + .prefix(prefix) + .map(map) + .opcode(opcode) + .rm(src2) + .reg(dst.to_real_reg().unwrap().hw_enc()) + .vvvv(src1.to_real_reg().unwrap().hw_enc()) + .encode(sink); + } + + Inst::CvtUint64ToFloatSeq { + dst_size, + src, + dst, + tmp_gpr1, + tmp_gpr2, + } => { + let src = src.to_reg(); + let dst = dst.to_writable_reg(); + let tmp_gpr1 = tmp_gpr1.to_writable_reg(); + let tmp_gpr2 = tmp_gpr2.to_writable_reg(); + + // Note: this sequence is specific to 64-bit mode; a 32-bit mode would require a + // different sequence. + // + // Emit the following sequence: + // + // cmp 0, %src + // jl handle_negative + // + // ;; handle positive, which can't overflow + // cvtsi2sd/cvtsi2ss %src, %dst + // j done + // + // ;; handle negative: see below for an explanation of what it's doing. + // handle_negative: + // mov %src, %tmp_gpr1 + // shr $1, %tmp_gpr1 + // mov %src, %tmp_gpr2 + // and $1, %tmp_gpr2 + // or %tmp_gpr1, %tmp_gpr2 + // cvtsi2sd/cvtsi2ss %tmp_gpr2, %dst + // addsd/addss %dst, %dst + // + // done: + + assert_ne!(src, tmp_gpr1.to_reg()); + assert_ne!(src, tmp_gpr2.to_reg()); + + let handle_negative = sink.get_label(); + let done = sink.get_label(); + + // If x seen as a signed int64 is not negative, a signed-conversion will do the right + // thing. + // TODO use tst src, src here. + let inst = Inst::cmp_rmi_r(OperandSize::Size64, src, RegMemImm::imm(0)); + inst.emit(sink, info, state); + + one_way_jmp(sink, CC::L, handle_negative); + + // Handle a positive int64, which is the "easy" case: a signed conversion will do the + // right thing. + emit_signed_cvt( + sink, + info, + state, + src, + dst, + *dst_size == OperandSize::Size64, + ); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + + sink.bind_label(handle_negative, state.ctrl_plane_mut()); + + // Divide x by two to get it in range for the signed conversion, keep the LSB, and + // scale it back up on the FP side. + let inst = Inst::gen_move(tmp_gpr1, src, types::I64); + inst.emit(sink, info, state); + + // tmp_gpr1 := src >> 1 + let inst = Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 1 }), + tmp_gpr1.to_reg(), + tmp_gpr1, + ); + inst.emit(sink, info, state); + + let inst = Inst::gen_move(tmp_gpr2, src, types::I64); + inst.emit(sink, info, state); + + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::And, + RegMemImm::imm(1), + tmp_gpr2, + ); + inst.emit(sink, info, state); + + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Or, + RegMemImm::reg(tmp_gpr1.to_reg()), + tmp_gpr2, + ); + inst.emit(sink, info, state); + + emit_signed_cvt( + sink, + info, + state, + tmp_gpr2.to_reg(), + dst, + *dst_size == OperandSize::Size64, + ); + + let add_op = if *dst_size == OperandSize::Size64 { + SseOpcode::Addsd + } else { + SseOpcode::Addss + }; + let inst = Inst::xmm_rm_r(add_op, RegMem::reg(dst.to_reg()), dst); + inst.emit(sink, info, state); + + sink.bind_label(done, state.ctrl_plane_mut()); + } + + Inst::CvtFloatToSintSeq { + src_size, + dst_size, + is_saturating, + src, + dst, + tmp_gpr, + tmp_xmm, + } => { + let src = src.to_reg(); + let dst = dst.to_writable_reg(); + let tmp_gpr = tmp_gpr.to_writable_reg(); + let tmp_xmm = tmp_xmm.to_writable_reg(); + + // Emits the following common sequence: + // + // cvttss2si/cvttsd2si %src, %dst + // cmp %dst, 1 + // jno done + // + // Then, for saturating conversions: + // + // ;; check for NaN + // cmpss/cmpsd %src, %src + // jnp not_nan + // xor %dst, %dst + // + // ;; positive inputs get saturated to INT_MAX; negative ones to INT_MIN, which is + // ;; already in %dst. + // xorpd %tmp_xmm, %tmp_xmm + // cmpss/cmpsd %src, %tmp_xmm + // jnb done + // mov/movaps $INT_MAX, %dst + // + // done: + // + // Then, for non-saturating conversions: + // + // ;; check for NaN + // cmpss/cmpsd %src, %src + // jnp not_nan + // ud2 trap BadConversionToInteger + // + // ;; check if INT_MIN was the correct result, against a magic constant: + // not_nan: + // movaps/mov $magic, %tmp_gpr + // movq/movd %tmp_gpr, %tmp_xmm + // cmpss/cmpsd %tmp_xmm, %src + // jnb/jnbe $check_positive + // ud2 trap IntegerOverflow + // + // ;; if positive, it was a real overflow + // check_positive: + // xorpd %tmp_xmm, %tmp_xmm + // cmpss/cmpsd %src, %tmp_xmm + // jnb done + // ud2 trap IntegerOverflow + // + // done: + + let (cast_op, cmp_op, trunc_op) = match src_size { + OperandSize::Size64 => (SseOpcode::Movq, SseOpcode::Ucomisd, SseOpcode::Cvttsd2si), + OperandSize::Size32 => (SseOpcode::Movd, SseOpcode::Ucomiss, SseOpcode::Cvttss2si), + _ => unreachable!(), + }; + + let done = sink.get_label(); + + // The truncation. + let inst = Inst::xmm_to_gpr(trunc_op, src, dst, *dst_size); + inst.emit(sink, info, state); + + // Compare against 1, in case of overflow the dst operand was INT_MIN. + let inst = Inst::cmp_rmi_r(*dst_size, dst.to_reg(), RegMemImm::imm(1)); + inst.emit(sink, info, state); + + one_way_jmp(sink, CC::NO, done); // no overflow => done + + // Check for NaN. + + let inst = Inst::xmm_cmp_rm_r(cmp_op, src, RegMem::reg(src)); + inst.emit(sink, info, state); + + if *is_saturating { + let not_nan = sink.get_label(); + one_way_jmp(sink, CC::NP, not_nan); // go to not_nan if not a NaN + + // For NaN, emit 0. + let inst = Inst::alu_rmi_r( + *dst_size, + AluRmiROpcode::Xor, + RegMemImm::reg(dst.to_reg()), + dst, + ); + inst.emit(sink, info, state); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + + sink.bind_label(not_nan, state.ctrl_plane_mut()); + + // If the input was positive, saturate to INT_MAX. + + // Zero out tmp_xmm. + let inst = Inst::xmm_rm_r(SseOpcode::Xorpd, RegMem::reg(tmp_xmm.to_reg()), tmp_xmm); + inst.emit(sink, info, state); + + let inst = Inst::xmm_cmp_rm_r(cmp_op, tmp_xmm.to_reg(), RegMem::reg(src)); + inst.emit(sink, info, state); + + // Jump if >= to done. + one_way_jmp(sink, CC::NB, done); + + // Otherwise, put INT_MAX. + if *dst_size == OperandSize::Size64 { + let inst = Inst::imm(OperandSize::Size64, 0x7fffffffffffffff, dst); + inst.emit(sink, info, state); + } else { + let inst = Inst::imm(OperandSize::Size32, 0x7fffffff, dst); + inst.emit(sink, info, state); + } + } else { + let inst = Inst::trap_if(CC::P, TrapCode::BAD_CONVERSION_TO_INTEGER); + inst.emit(sink, info, state); + + // Check if INT_MIN was the correct result: determine the smallest floating point + // number that would convert to INT_MIN, put it in a temporary register, and compare + // against the src register. + // If the src register is less (or in some cases, less-or-equal) than the threshold, + // trap! + + let mut no_overflow_cc = CC::NB; // >= + let output_bits = dst_size.to_bits(); + match *src_size { + OperandSize::Size32 => { + let cst = (-Ieee32::pow2(output_bits - 1)).bits(); + let inst = Inst::imm(OperandSize::Size32, cst as u64, tmp_gpr); + inst.emit(sink, info, state); + } + OperandSize::Size64 => { + // An f64 can represent `i32::min_value() - 1` exactly with precision to spare, + // so there are values less than -2^(N-1) that convert correctly to INT_MIN. + let cst = if output_bits < 64 { + no_overflow_cc = CC::NBE; // > + Ieee64::fcvt_to_sint_negative_overflow(output_bits) + } else { + -Ieee64::pow2(output_bits - 1) + }; + let inst = Inst::imm(OperandSize::Size64, cst.bits(), tmp_gpr); + inst.emit(sink, info, state); + } + _ => unreachable!(), + } + + let inst = + Inst::gpr_to_xmm(cast_op, RegMem::reg(tmp_gpr.to_reg()), *src_size, tmp_xmm); + inst.emit(sink, info, state); + + let inst = Inst::xmm_cmp_rm_r(cmp_op, src, RegMem::reg(tmp_xmm.to_reg())); + inst.emit(sink, info, state); + + // no trap if src >= or > threshold + let inst = Inst::trap_if(no_overflow_cc.invert(), TrapCode::INTEGER_OVERFLOW); + inst.emit(sink, info, state); + + // If positive, it was a real overflow. + + // Zero out the tmp_xmm register. + let inst = Inst::xmm_rm_r(SseOpcode::Xorpd, RegMem::reg(tmp_xmm.to_reg()), tmp_xmm); + inst.emit(sink, info, state); + + let inst = Inst::xmm_cmp_rm_r(cmp_op, tmp_xmm.to_reg(), RegMem::reg(src)); + inst.emit(sink, info, state); + + // no trap if 0 >= src + let inst = Inst::trap_if(CC::B, TrapCode::INTEGER_OVERFLOW); + inst.emit(sink, info, state); + } + + sink.bind_label(done, state.ctrl_plane_mut()); + } + + Inst::CvtFloatToUintSeq { + src_size, + dst_size, + is_saturating, + src, + dst, + tmp_gpr, + tmp_xmm, + tmp_xmm2, + } => { + let src = src.to_reg(); + let dst = dst.to_writable_reg(); + let tmp_gpr = tmp_gpr.to_writable_reg(); + let tmp_xmm = tmp_xmm.to_writable_reg(); + let tmp_xmm2 = tmp_xmm2.to_writable_reg(); + + // The only difference in behavior between saturating and non-saturating is how we + // handle errors. Emits the following sequence: + // + // movaps/mov 2**(int_width - 1), %tmp_gpr + // movq/movd %tmp_gpr, %tmp_xmm + // cmpss/cmpsd %tmp_xmm, %src + // jnb is_large + // + // ;; check for NaN inputs + // jnp not_nan + // -- non-saturating: ud2 trap BadConversionToInteger + // -- saturating: xor %dst, %dst; j done + // + // not_nan: + // cvttss2si/cvttsd2si %src, %dst + // cmp 0, %dst + // jnl done + // -- non-saturating: ud2 trap IntegerOverflow + // -- saturating: xor %dst, %dst; j done + // + // is_large: + // mov %src, %tmp_xmm2 + // subss/subsd %tmp_xmm, %tmp_xmm2 + // cvttss2si/cvttss2sd %tmp_x, %dst + // cmp 0, %dst + // jnl next_is_large + // -- non-saturating: ud2 trap IntegerOverflow + // -- saturating: movaps $UINT_MAX, %dst; j done + // + // next_is_large: + // add 2**(int_width -1), %dst ;; 2 instructions for 64-bits integers + // + // done: + + assert_ne!(tmp_xmm.to_reg(), src, "tmp_xmm clobbers src!"); + + let (sub_op, cast_op, cmp_op, trunc_op) = match src_size { + OperandSize::Size32 => ( + SseOpcode::Subss, + SseOpcode::Movd, + SseOpcode::Ucomiss, + SseOpcode::Cvttss2si, + ), + OperandSize::Size64 => ( + SseOpcode::Subsd, + SseOpcode::Movq, + SseOpcode::Ucomisd, + SseOpcode::Cvttsd2si, + ), + _ => unreachable!(), + }; + + let done = sink.get_label(); + + let cst = match src_size { + OperandSize::Size32 => Ieee32::pow2(dst_size.to_bits() - 1).bits() as u64, + OperandSize::Size64 => Ieee64::pow2(dst_size.to_bits() - 1).bits(), + _ => unreachable!(), + }; + + let inst = Inst::imm(*src_size, cst, tmp_gpr); + inst.emit(sink, info, state); + + let inst = Inst::gpr_to_xmm(cast_op, RegMem::reg(tmp_gpr.to_reg()), *src_size, tmp_xmm); + inst.emit(sink, info, state); + + let inst = Inst::xmm_cmp_rm_r(cmp_op, src, RegMem::reg(tmp_xmm.to_reg())); + inst.emit(sink, info, state); + + let handle_large = sink.get_label(); + one_way_jmp(sink, CC::NB, handle_large); // jump to handle_large if src >= large_threshold + + if *is_saturating { + // If not NaN jump over this 0-return, otherwise return 0 + let not_nan = sink.get_label(); + one_way_jmp(sink, CC::NP, not_nan); + let inst = Inst::alu_rmi_r( + *dst_size, + AluRmiROpcode::Xor, + RegMemImm::reg(dst.to_reg()), + dst, + ); + inst.emit(sink, info, state); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + sink.bind_label(not_nan, state.ctrl_plane_mut()); + } else { + // Trap. + let inst = Inst::trap_if(CC::P, TrapCode::BAD_CONVERSION_TO_INTEGER); + inst.emit(sink, info, state); + } + + // Actual truncation for small inputs: if the result is not positive, then we had an + // overflow. + + let inst = Inst::xmm_to_gpr(trunc_op, src, dst, *dst_size); + inst.emit(sink, info, state); + + let inst = Inst::cmp_rmi_r(*dst_size, dst.to_reg(), RegMemImm::imm(0)); + inst.emit(sink, info, state); + + one_way_jmp(sink, CC::NL, done); // if dst >= 0, jump to done + + if *is_saturating { + // The input was "small" (< 2**(width -1)), so the only way to get an integer + // overflow is because the input was too small: saturate to the min value, i.e. 0. + let inst = Inst::alu_rmi_r( + *dst_size, + AluRmiROpcode::Xor, + RegMemImm::reg(dst.to_reg()), + dst, + ); + inst.emit(sink, info, state); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + } else { + // Trap. + let inst = Inst::trap(TrapCode::INTEGER_OVERFLOW); + inst.emit(sink, info, state); + } + + // Now handle large inputs. + + sink.bind_label(handle_large, state.ctrl_plane_mut()); + + let inst = Inst::gen_move(tmp_xmm2, src, types::F64); + inst.emit(sink, info, state); + + let inst = Inst::xmm_rm_r(sub_op, RegMem::reg(tmp_xmm.to_reg()), tmp_xmm2); + inst.emit(sink, info, state); + + let inst = Inst::xmm_to_gpr(trunc_op, tmp_xmm2.to_reg(), dst, *dst_size); + inst.emit(sink, info, state); + + let inst = Inst::cmp_rmi_r(*dst_size, dst.to_reg(), RegMemImm::imm(0)); + inst.emit(sink, info, state); + + if *is_saturating { + let next_is_large = sink.get_label(); + one_way_jmp(sink, CC::NL, next_is_large); // if dst >= 0, jump to next_is_large + + // The input was "large" (>= 2**(width -1)), so the only way to get an integer + // overflow is because the input was too large: saturate to the max value. + let inst = Inst::imm( + OperandSize::Size64, + if *dst_size == OperandSize::Size64 { + u64::max_value() + } else { + u32::max_value() as u64 + }, + dst, + ); + inst.emit(sink, info, state); + + let inst = Inst::jmp_known(done); + inst.emit(sink, info, state); + sink.bind_label(next_is_large, state.ctrl_plane_mut()); + } else { + let inst = Inst::trap_if(CC::L, TrapCode::INTEGER_OVERFLOW); + inst.emit(sink, info, state); + } + + if *dst_size == OperandSize::Size64 { + let inst = Inst::imm(OperandSize::Size64, 1 << 63, tmp_gpr); + inst.emit(sink, info, state); + + let inst = Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::reg(tmp_gpr.to_reg()), + dst, + ); + inst.emit(sink, info, state); + } else { + let inst = Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(1 << 31), + dst, + ); + inst.emit(sink, info, state); + } + + sink.bind_label(done, state.ctrl_plane_mut()); + } + + Inst::LoadExtName { + dst, + name, + offset, + distance, + } => { + let dst = dst.to_reg(); + + if info.flags.is_pic() { + // Generates: movq symbol@GOTPCREL(%rip), %dst + let enc_dst = int_reg_enc(dst); + sink.put1(0x48 | ((enc_dst >> 3) & 1) << 2); + sink.put1(0x8B); + sink.put1(0x05 | ((enc_dst & 7) << 3)); + emit_reloc(sink, Reloc::X86GOTPCRel4, name, -4); + sink.put4(0); + // Offset in the relocation above applies to the address of the *GOT entry*, not + // the loaded address; so we emit a separate add or sub instruction if needed. + if *offset < 0 { + assert!(*offset >= -i32::MAX as i64); + sink.put1(0x48 | ((enc_dst >> 3) & 1)); + sink.put1(0x81); + sink.put1(0xe8 | (enc_dst & 7)); + sink.put4((-*offset) as u32); + } else if *offset > 0 { + assert!(*offset <= i32::MAX as i64); + sink.put1(0x48 | ((enc_dst >> 3) & 1)); + sink.put1(0x81); + sink.put1(0xc0 | (enc_dst & 7)); + sink.put4(*offset as u32); + } + } else if distance == &RelocDistance::Near { + // If we know the distance to the name is within 2GB (e.g., a module-local function), + // we can generate a RIP-relative address, with a relocation. + // Generates: lea $name(%rip), $dst + let enc_dst = int_reg_enc(dst); + sink.put1(0x48 | ((enc_dst >> 3) & 1) << 2); + sink.put1(0x8D); + sink.put1(0x05 | ((enc_dst & 7) << 3)); + emit_reloc(sink, Reloc::X86CallPCRel4, name, -4); + sink.put4(0); + } else { + // The full address can be encoded in the register, with a relocation. + // Generates: movabsq $name, %dst + let enc_dst = int_reg_enc(dst); + sink.put1(0x48 | ((enc_dst >> 3) & 1)); + sink.put1(0xB8 | (enc_dst & 7)); + emit_reloc(sink, Reloc::Abs8, name, *offset); + sink.put8(0); + } + } + + Inst::LockCmpxchg { + ty, + replacement, + expected, + mem, + dst_old, + } => { + let replacement = *replacement; + let expected = *expected; + let dst_old = dst_old.to_reg(); + let mem = mem.clone(); + + debug_assert_eq!(expected, regs::rax()); + debug_assert_eq!(dst_old, regs::rax()); + + // lock cmpxchg{b,w,l,q} %replacement, (mem) + // Note that 0xF0 is the Lock prefix. + let (prefix, opcodes) = match *ty { + types::I8 => (LegacyPrefixes::_F0, 0x0FB0), + types::I16 => (LegacyPrefixes::_66F0, 0x0FB1), + types::I32 => (LegacyPrefixes::_F0, 0x0FB1), + types::I64 => (LegacyPrefixes::_F0, 0x0FB1), + _ => unreachable!(), + }; + let rex = RexFlags::from((OperandSize::from_ty(*ty), replacement)); + let amode = mem.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcodes, 2, replacement, &amode, rex, 0); + } + + Inst::LockCmpxchg16b { + replacement_low, + replacement_high, + expected_low, + expected_high, + mem, + dst_old_low, + dst_old_high, + } => { + let mem = mem.clone(); + debug_assert_eq!(*replacement_low, regs::rbx()); + debug_assert_eq!(*replacement_high, regs::rcx()); + debug_assert_eq!(*expected_low, regs::rax()); + debug_assert_eq!(*expected_high, regs::rdx()); + debug_assert_eq!(dst_old_low.to_reg(), regs::rax()); + debug_assert_eq!(dst_old_high.to_reg(), regs::rdx()); + + let amode = mem.finalize(state.frame_layout(), sink); + // lock cmpxchg16b (mem) + // Note that 0xF0 is the Lock prefix. + emit_std_enc_mem( + sink, + LegacyPrefixes::_F0, + 0x0FC7, + 2, + 1, + &amode, + RexFlags::set_w(), + 0, + ); + } + + Inst::LockXadd { + size, + operand, + mem, + dst_old, + } => { + debug_assert_eq!(dst_old.to_reg(), *operand); + // lock xadd{b,w,l,q} %operand, (mem) + // Note that 0xF0 is the Lock prefix. + let (prefix, opcodes) = match size { + OperandSize::Size8 => (LegacyPrefixes::_F0, 0x0FC0), + OperandSize::Size16 => (LegacyPrefixes::_66F0, 0x0FC1), + OperandSize::Size32 => (LegacyPrefixes::_F0, 0x0FC1), + OperandSize::Size64 => (LegacyPrefixes::_F0, 0x0FC1), + }; + let rex = RexFlags::from((*size, *operand)); + let amode = mem.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcodes, 2, *operand, &amode, rex, 0); + } + + Inst::Xchg { + size, + operand, + mem, + dst_old, + } => { + debug_assert_eq!(dst_old.to_reg(), *operand); + // xchg{b,w,l,q} %operand, (mem) + let (prefix, opcodes) = match size { + OperandSize::Size8 => (LegacyPrefixes::None, 0x86), + OperandSize::Size16 => (LegacyPrefixes::_66, 0x87), + OperandSize::Size32 => (LegacyPrefixes::None, 0x87), + OperandSize::Size64 => (LegacyPrefixes::None, 0x87), + }; + let rex = RexFlags::from((*size, *operand)); + let amode = mem.finalize(state.frame_layout(), sink); + emit_std_reg_mem(sink, prefix, opcodes, 1, *operand, &amode, rex, 0); + } + + Inst::AtomicRmwSeq { + ty, + op, + mem, + operand, + temp, + dst_old, + } => { + let operand = *operand; + let temp = *temp; + let dst_old = *dst_old; + debug_assert_eq!(dst_old.to_reg(), regs::rax()); + let mem = mem.finalize(state.frame_layout(), sink).clone(); + + // Emit this: + // mov{zbq,zwq,zlq,q} (%r_address), %rax // rax = old value + // again: + // movq %rax, %r_temp // rax = old value, r_temp = old value + // `op`q %r_operand, %r_temp // rax = old value, r_temp = new value + // lock cmpxchg{b,w,l,q} %r_temp, (%r_address) // try to store new value + // jnz again // If this is taken, rax will have a "revised" old value + // + // Operand conventions: IN: %r_address, %r_operand OUT: %rax (old + // value), %r_temp (trashed), %rflags (trashed) + let again_label = sink.get_label(); + + // mov{zbq,zwq,zlq,q} (%r_address), %rax + // No need to call `add_trap` here, since the `i1` emit will do that. + let i1 = Inst::load(*ty, mem.clone(), dst_old, ExtKind::ZeroExtend); + i1.emit(sink, info, state); + + // again: + sink.bind_label(again_label, state.ctrl_plane_mut()); + + // movq %rax, %r_temp + let i2 = Inst::mov_r_r(OperandSize::Size64, dst_old.to_reg(), temp); + i2.emit(sink, info, state); + + let operand_rmi = RegMemImm::reg(operand); + use AtomicRmwSeqOp as RmwOp; + match op { + RmwOp::Nand => { + // andq %r_operand, %r_temp + let i3 = + Inst::alu_rmi_r(OperandSize::Size64, AluRmiROpcode::And, operand_rmi, temp); + i3.emit(sink, info, state); + + // notq %r_temp + let i4 = Inst::not(OperandSize::Size64, temp); + i4.emit(sink, info, state); + } + RmwOp::Umin | RmwOp::Umax | RmwOp::Smin | RmwOp::Smax => { + // cmp %r_temp, %r_operand + let i3 = Inst::cmp_rmi_r( + OperandSize::from_ty(*ty), + operand, + RegMemImm::reg(temp.to_reg()), + ); + i3.emit(sink, info, state); + + // cmovcc %r_operand, %r_temp + let cc = match op { + RmwOp::Umin => CC::BE, + RmwOp::Umax => CC::NB, + RmwOp::Smin => CC::LE, + RmwOp::Smax => CC::NL, + _ => unreachable!(), + }; + let i4 = Inst::cmove(OperandSize::Size64, cc, RegMem::reg(operand), temp); + i4.emit(sink, info, state); + } + RmwOp::And | RmwOp::Or | RmwOp::Xor => { + // opq %r_operand, %r_temp + let alu_op = match op { + RmwOp::And => AluRmiROpcode::And, + RmwOp::Or => AluRmiROpcode::Or, + RmwOp::Xor => AluRmiROpcode::Xor, + _ => unreachable!(), + }; + let i3 = Inst::alu_rmi_r(OperandSize::Size64, alu_op, operand_rmi, temp); + i3.emit(sink, info, state); + } + } + + // lock cmpxchg{b,w,l,q} %r_temp, (%r_address) + // No need to call `add_trap` here, since the `i4` emit will do that. + let i4 = Inst::LockCmpxchg { + ty: *ty, + replacement: temp.to_reg(), + expected: dst_old.to_reg(), + mem: mem.into(), + dst_old, + }; + i4.emit(sink, info, state); + + // jnz again + one_way_jmp(sink, CC::NZ, again_label); + } + + Inst::Atomic128RmwSeq { + op, + mem, + operand_low, + operand_high, + temp_low, + temp_high, + dst_old_low, + dst_old_high, + } => { + let operand_low = *operand_low; + let operand_high = *operand_high; + let temp_low = *temp_low; + let temp_high = *temp_high; + let dst_old_low = *dst_old_low; + let dst_old_high = *dst_old_high; + debug_assert_eq!(temp_low.to_reg(), regs::rbx()); + debug_assert_eq!(temp_high.to_reg(), regs::rcx()); + debug_assert_eq!(dst_old_low.to_reg(), regs::rax()); + debug_assert_eq!(dst_old_high.to_reg(), regs::rdx()); + let mem = mem.finalize(state.frame_layout(), sink).clone(); + + let again_label = sink.get_label(); + + // Load the initial value. + Inst::load(types::I64, mem.clone(), dst_old_low, ExtKind::ZeroExtend) + .emit(sink, info, state); + Inst::load(types::I64, mem.offset(8), dst_old_high, ExtKind::ZeroExtend) + .emit(sink, info, state); + + // again: + sink.bind_label(again_label, state.ctrl_plane_mut()); + + // Move old value to temp registers. + Inst::mov_r_r(OperandSize::Size64, dst_old_low.to_reg(), temp_low) + .emit(sink, info, state); + Inst::mov_r_r(OperandSize::Size64, dst_old_high.to_reg(), temp_high) + .emit(sink, info, state); + + // Perform the operation. + let operand_low_rmi = RegMemImm::reg(operand_low); + let operand_high_rmi = RegMemImm::reg(operand_high); + use Atomic128RmwSeqOp as RmwOp; + match op { + RmwOp::Nand => { + // temp &= operand + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::And, + operand_low_rmi, + temp_low, + ) + .emit(sink, info, state); + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::And, + operand_high_rmi, + temp_high, + ) + .emit(sink, info, state); + + // temp = !temp + Inst::not(OperandSize::Size64, temp_low).emit(sink, info, state); + Inst::not(OperandSize::Size64, temp_high).emit(sink, info, state); + } + RmwOp::Umin | RmwOp::Umax | RmwOp::Smin | RmwOp::Smax => { + // Do a comparison with LHS temp and RHS operand. + // `cmp_rmi_r` and `alu_rmi_r` have opposite argument orders. + Inst::cmp_rmi_r(OperandSize::Size64, temp_low.to_reg(), operand_low_rmi) + .emit(sink, info, state); + // This will clobber `temp_high` + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sbb, + operand_high_rmi, + temp_high, + ) + .emit(sink, info, state); + // Restore the clobbered value + Inst::mov_r_r(OperandSize::Size64, dst_old_high.to_reg(), temp_high) + .emit(sink, info, state); + let cc = match op { + RmwOp::Umin => CC::NB, + RmwOp::Umax => CC::B, + RmwOp::Smin => CC::NL, + RmwOp::Smax => CC::L, + _ => unreachable!(), + }; + Inst::cmove(OperandSize::Size64, cc, operand_low.into(), temp_low) + .emit(sink, info, state); + Inst::cmove(OperandSize::Size64, cc, operand_high.into(), temp_high) + .emit(sink, info, state); + } + RmwOp::Add | RmwOp::Sub | RmwOp::And | RmwOp::Or | RmwOp::Xor => { + // temp op= operand + let (op_low, op_high) = match op { + RmwOp::Add => (AluRmiROpcode::Add, AluRmiROpcode::Adc), + RmwOp::Sub => (AluRmiROpcode::Sub, AluRmiROpcode::Sbb), + RmwOp::And => (AluRmiROpcode::And, AluRmiROpcode::And), + RmwOp::Or => (AluRmiROpcode::Or, AluRmiROpcode::Or), + RmwOp::Xor => (AluRmiROpcode::Xor, AluRmiROpcode::Xor), + _ => unreachable!(), + }; + Inst::alu_rmi_r(OperandSize::Size64, op_low, operand_low_rmi, temp_low) + .emit(sink, info, state); + Inst::alu_rmi_r(OperandSize::Size64, op_high, operand_high_rmi, temp_high) + .emit(sink, info, state); + } + } + + // cmpxchg16b (mem) + Inst::LockCmpxchg16b { + replacement_low: temp_low.to_reg(), + replacement_high: temp_high.to_reg(), + expected_low: dst_old_low.to_reg(), + expected_high: dst_old_high.to_reg(), + mem: Box::new(mem.into()), + dst_old_low, + dst_old_high, + } + .emit(sink, info, state); + + // jnz again + one_way_jmp(sink, CC::NZ, again_label); + } + + Inst::Atomic128XchgSeq { + mem, + operand_low, + operand_high, + dst_old_low, + dst_old_high, + } => { + let operand_low = *operand_low; + let operand_high = *operand_high; + let dst_old_low = *dst_old_low; + let dst_old_high = *dst_old_high; + debug_assert_eq!(operand_low, regs::rbx()); + debug_assert_eq!(operand_high, regs::rcx()); + debug_assert_eq!(dst_old_low.to_reg(), regs::rax()); + debug_assert_eq!(dst_old_high.to_reg(), regs::rdx()); + let mem = mem.finalize(state.frame_layout(), sink).clone(); + + let again_label = sink.get_label(); + + // Load the initial value. + Inst::load(types::I64, mem.clone(), dst_old_low, ExtKind::ZeroExtend) + .emit(sink, info, state); + Inst::load(types::I64, mem.offset(8), dst_old_high, ExtKind::ZeroExtend) + .emit(sink, info, state); + + // again: + sink.bind_label(again_label, state.ctrl_plane_mut()); + + // cmpxchg16b (mem) + Inst::LockCmpxchg16b { + replacement_low: operand_low, + replacement_high: operand_high, + expected_low: dst_old_low.to_reg(), + expected_high: dst_old_high.to_reg(), + mem: Box::new(mem.into()), + dst_old_low, + dst_old_high, + } + .emit(sink, info, state); + + // jnz again + one_way_jmp(sink, CC::NZ, again_label); + } + + Inst::Fence { kind } => { + sink.put1(0x0F); + sink.put1(0xAE); + match kind { + FenceKind::MFence => sink.put1(0xF0), // mfence = 0F AE F0 + FenceKind::LFence => sink.put1(0xE8), // lfence = 0F AE E8 + FenceKind::SFence => sink.put1(0xF8), // sfence = 0F AE F8 + } + } + + Inst::Hlt => { + sink.put1(0xcc); + } + + Inst::Ud2 { trap_code } => { + sink.add_trap(*trap_code); + sink.put_data(Inst::TRAP_OPCODE); + } + + Inst::Nop { len } => { + // These encodings can all be found in Intel's architecture manual, at the NOP + // instruction description. + let mut len = *len; + while len != 0 { + let emitted = u8::min(len, 9); + match emitted { + 0 => {} + 1 => sink.put1(0x90), // NOP + 2 => { + // 66 NOP + sink.put1(0x66); + sink.put1(0x90); + } + 3 => { + // NOP [EAX] + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x00); + } + 4 => { + // NOP 0(EAX), with 0 a 1-byte immediate. + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x40); + sink.put1(0x00); + } + 5 => { + // NOP [EAX, EAX, 1] + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x44); + sink.put1(0x00); + sink.put1(0x00); + } + 6 => { + // 66 NOP [EAX, EAX, 1] + sink.put1(0x66); + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x44); + sink.put1(0x00); + sink.put1(0x00); + } + 7 => { + // NOP 0[EAX], but 0 is a 4 bytes immediate. + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x80); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + } + 8 => { + // NOP 0[EAX, EAX, 1], with 0 a 4 bytes immediate. + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x84); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + } + 9 => { + // 66 NOP 0[EAX, EAX, 1], with 0 a 4 bytes immediate. + sink.put1(0x66); + sink.put1(0x0F); + sink.put1(0x1F); + sink.put1(0x84); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + sink.put1(0x00); + } + _ => unreachable!(), + } + len -= emitted; + } + } + + Inst::ElfTlsGetAddr { ref symbol, dst } => { + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(dst, regs::rax()); + + // N.B.: Must be exactly this byte sequence; the linker requires it, + // because it must know how to rewrite the bytes. + + // data16 lea gv@tlsgd(%rip),%rdi + sink.put1(0x66); // data16 + sink.put1(0b01001000); // REX.W + sink.put1(0x8d); // LEA + sink.put1(0x3d); // ModRM byte + emit_reloc(sink, Reloc::ElfX86_64TlsGd, symbol, -4); + sink.put4(0); // offset + + // data16 data16 callq __tls_get_addr-4 + sink.put1(0x66); // data16 + sink.put1(0x66); // data16 + sink.put1(0b01001000); // REX.W + sink.put1(0xe8); // CALL + emit_reloc( + sink, + Reloc::X86CallPLTRel4, + &ExternalName::LibCall(LibCall::ElfTlsGetAddr), + -4, + ); + sink.put4(0); // offset + } + + Inst::MachOTlsGetAddr { ref symbol, dst } => { + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(dst, regs::rax()); + + // movq gv@tlv(%rip), %rdi + sink.put1(0x48); // REX.w + sink.put1(0x8b); // MOV + sink.put1(0x3d); // ModRM byte + emit_reloc(sink, Reloc::MachOX86_64Tlv, symbol, -4); + sink.put4(0); // offset + + // callq *(%rdi) + sink.put1(0xff); + sink.put1(0x17); + } + + Inst::CoffTlsGetAddr { + ref symbol, + dst, + tmp, + } => { + let dst = dst.to_reg().to_reg(); + debug_assert_eq!(dst, regs::rax()); + + // tmp is used below directly as %rcx + let tmp = tmp.to_reg().to_reg(); + debug_assert_eq!(tmp, regs::rcx()); + + // See: https://gcc.godbolt.org/z/M8or9x6ss + // And: https://github.com/bjorn3/rustc_codegen_cranelift/issues/388#issuecomment-532930282 + + // Emit the following sequence + // movl (%rip), %eax ; IMAGE_REL_AMD64_REL32 _tls_index + // movq %gs:88, %rcx + // movq (%rcx,%rax,8), %rax + // leaq (%rax), %rax ; Reloc: IMAGE_REL_AMD64_SECREL symbol + + // Load TLS index for current thread + // movl (%rip), %eax + sink.put1(0x8b); // mov + sink.put1(0x05); + emit_reloc( + sink, + Reloc::X86PCRel4, + &ExternalName::KnownSymbol(KnownSymbol::CoffTlsIndex), + -4, + ); + sink.put4(0); // offset + + // movq %gs:88, %rcx + // Load the TLS Storage Array pointer + // The gs segment register refers to the base address of the TEB on x64. + // 0x58 is the offset in the TEB for the ThreadLocalStoragePointer member on x64: + sink.put_data(&[ + 0x65, 0x48, // REX.W + 0x8b, // MOV + 0x0c, 0x25, 0x58, // 0x58 - ThreadLocalStoragePointer offset + 0x00, 0x00, 0x00, + ]); + + // movq (%rcx,%rax,8), %rax + // Load the actual TLS entry for this thread. + // Computes ThreadLocalStoragePointer + _tls_index*8 + sink.put_data(&[0x48, 0x8b, 0x04, 0xc1]); + + // leaq (%rax), %rax + sink.put1(0x48); + sink.put1(0x8d); + sink.put1(0x80); + emit_reloc(sink, Reloc::X86SecRel, symbol, 0); + sink.put4(0); // offset + } + + Inst::Unwind { ref inst } => { + sink.add_unwind(inst.clone()); + } + + Inst::DummyUse { .. } => { + // Nothing. + } + } + + state.clear_post_insn(); +} + +/// Emit the common sequence used for both direct and indirect tail calls: +/// +/// * Copy the new frame's stack arguments over the top of our current frame. +/// +/// * Restore the old frame pointer. +/// +/// * Initialize the tail callee's stack pointer (simultaneously deallocating +/// the temporary stack space we allocated when creating the new frame's stack +/// arguments). +/// +/// * Move the return address into its stack slot. +fn emit_return_call_common_sequence( + sink: &mut MachBuffer, + info: &EmitInfo, + state: &mut EmitState, + call_info: &ReturnCallInfo, +) { + assert!( + info.flags.preserve_frame_pointers(), + "frame pointers aren't fundamentally required for tail calls, \ + but the current implementation relies on them being present" + ); + + let tmp = call_info.tmp.to_writable_reg(); + + for inst in + X64ABIMachineSpec::gen_clobber_restore(CallConv::Tail, &info.flags, state.frame_layout()) + { + inst.emit(sink, info, state); + } + + for inst in X64ABIMachineSpec::gen_epilogue_frame_restore( + CallConv::Tail, + &info.flags, + &info.isa_flags, + state.frame_layout(), + ) { + inst.emit(sink, info, state); + } + + let incoming_args_diff = state.frame_layout().tail_args_size - call_info.new_stack_arg_size; + if incoming_args_diff > 0 { + // Move the saved return address up by `incoming_args_diff` + Inst::mov64_m_r(Amode::imm_reg(0, regs::rsp()), tmp).emit(sink, info, state); + Inst::mov_r_m( + OperandSize::Size64, + tmp.to_reg(), + Amode::imm_reg(i32::try_from(incoming_args_diff).unwrap(), regs::rsp()), + ) + .emit(sink, info, state); + + // Increment the stack pointer to shrink the argument area for the new call. + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(incoming_args_diff), + Writable::from_reg(regs::rsp()), + ) + .emit(sink, info, state); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_state.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_state.rs new file mode 100644 index 00000000000000..c28776b9047320 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_state.rs @@ -0,0 +1,55 @@ +use super::*; +use crate::ir; +use cranelift_control::ControlPlane; + +/// State carried between emissions of a sequence of instructions. +#[derive(Default, Clone, Debug)] +pub struct EmitState { + /// The user stack map for the upcoming instruction, as provided to + /// `pre_safepoint()`. + user_stack_map: Option, + + /// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and + /// optimized away at compiletime. See [cranelift_control]. + ctrl_plane: ControlPlane, + + /// A copy of the frame layout, used during the emission of `Inst::ReturnCallKnown` and + /// `Inst::ReturnCallUnknown` instructions. + frame_layout: FrameLayout, +} + +impl MachInstEmitState for EmitState { + fn new(abi: &Callee, ctrl_plane: ControlPlane) -> Self { + EmitState { + user_stack_map: None, + ctrl_plane, + frame_layout: abi.frame_layout().clone(), + } + } + + fn pre_safepoint(&mut self, user_stack_map: Option) { + self.user_stack_map = user_stack_map; + } + + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane { + &mut self.ctrl_plane + } + + fn take_ctrl_plane(self) -> ControlPlane { + self.ctrl_plane + } + + fn frame_layout(&self) -> &FrameLayout { + &self.frame_layout + } +} + +impl EmitState { + pub(crate) fn take_stack_map(&mut self) -> Option { + self.user_stack_map.take() + } + + pub(crate) fn clear_post_insn(&mut self) { + self.user_stack_map = None; + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_tests.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_tests.rs new file mode 100644 index 00000000000000..f6f41d48c0effd --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/emit_tests.rs @@ -0,0 +1,5376 @@ +//! Tests for the emitter +//! +//! See comments at the top of `fn x64_emit` for advice on how to create reliable test cases. +//! +//! to see stdout: cargo test -- --nocapture +//! +//! for this specific case, as of 24 Aug 2020: +//! +//! cd to the top of your wasmtime tree, then: +//! +//! RUST_BACKTRACE=1 cargo test --features test-programs/test_programs \ +//! --all --exclude wasmtime-wasi-nn \ +//! -- isa::x64::inst::emit_tests::test_x64_emit + +use super::*; +use crate::ir::{MemFlags, UserExternalNameRef}; +use crate::isa::x64; +use crate::isa::x64::lower::isle::generated_code::{Atomic128RmwSeqOp, AtomicRmwSeqOp}; +use alloc::vec::Vec; +use cranelift_entity::EntityRef as _; + +impl Inst { + fn neg(size: OperandSize, src: Writable) -> Inst { + debug_assert_eq!(src.to_reg().class(), RegClass::Int); + Inst::Neg { + size, + src: Gpr::unwrap_new(src.to_reg()), + dst: WritableGpr::from_writable_reg(src).unwrap(), + } + } + + fn xmm_unary_rm_r_imm(op: SseOpcode, src: RegMem, dst: Writable, imm: u8) -> Inst { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmUnaryRmRImm { + op, + src: XmmMemAligned::unwrap_new(src), + imm, + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + fn xmm_unary_rm_r_evex(op: Avx512Opcode, src: RegMem, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmUnaryRmREvex { + op, + src: XmmMem::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + fn xmm_rmi_reg(opcode: SseOpcode, src: RegMemImm, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmRmiReg { + opcode, + src1: Xmm::unwrap_new(dst.to_reg()), + src2: XmmMemAlignedImm::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + fn xmm_rm_r_evex(op: Avx512Opcode, src1: Reg, src2: RegMem, dst: Writable) -> Self { + debug_assert_ne!(op, Avx512Opcode::Vpermi2b); + src2.assert_regclass_is(RegClass::Float); + debug_assert!(src1.class() == RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmRmREvex { + op, + src1: Xmm::unwrap_new(src1), + src2: XmmMem::unwrap_new(src2), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + fn xmm_rm_r_evex3( + op: Avx512Opcode, + src1: Reg, + src2: Reg, + src3: RegMem, + dst: Writable, + ) -> Self { + debug_assert_eq!(op, Avx512Opcode::Vpermi2b); + src3.assert_regclass_is(RegClass::Float); + debug_assert!(src1.class() == RegClass::Float); + debug_assert!(src2.class() == RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmRmREvex3 { + op, + src1: Xmm::unwrap_new(src1), + src2: Xmm::unwrap_new(src2), + src3: XmmMem::unwrap_new(src3), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + // TODO Can be replaced by `Inst::move` (high-level) and `Inst::unary_rm_r` (low-level) + fn xmm_mov(op: SseOpcode, src: RegMem, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmUnaryRmR { + op, + src: XmmMemAligned::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + fn setcc(cc: CC, dst: Writable) -> Inst { + debug_assert!(dst.to_reg().class() == RegClass::Int); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::Setcc { cc, dst } + } + + fn bswap(size: OperandSize, dst: Writable) -> Inst { + debug_assert!(dst.to_reg().class() == RegClass::Int); + let src = Gpr::unwrap_new(dst.to_reg()); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::Bswap { size, src, dst } + } + + fn xmm_rm_r_imm( + op: SseOpcode, + src: RegMem, + dst: Writable, + imm: u8, + size: OperandSize, + ) -> Inst { + debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + Inst::XmmRmRImm { + op, + src1: dst.to_reg(), + src2: src, + dst, + imm, + size, + } + } + + fn xmm_rm_r_blend(op: SseOpcode, src2: RegMem, dst: Writable) -> Inst { + Inst::XmmRmRBlend { + op, + src1: Xmm::unwrap_new(dst.to_reg()), + src2: XmmMemAligned::unwrap_new(src2), + mask: Xmm::unwrap_new(regs::xmm0()), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } +} + +#[test] +fn test_x64_emit() { + let rax = regs::rax(); + let rbx = regs::rbx(); + let rcx = regs::rcx(); + let rdx = regs::rdx(); + let rsi = regs::rsi(); + let rdi = regs::rdi(); + let rsp = regs::rsp(); + let rbp = regs::rbp(); + let r8 = regs::r8(); + let r9 = regs::r9(); + let r10 = regs::r10(); + let r11 = regs::r11(); + let r12 = regs::r12(); + let r13 = regs::r13(); + let r14 = regs::r14(); + let r15 = regs::r15(); + + let xmm0 = regs::xmm0(); + let xmm1 = regs::xmm1(); + let xmm2 = regs::xmm2(); + let xmm3 = regs::xmm3(); + let xmm4 = regs::xmm4(); + let xmm5 = regs::xmm5(); + let xmm6 = regs::xmm6(); + let xmm7 = regs::xmm7(); + let xmm8 = regs::xmm8(); + let xmm9 = regs::xmm9(); + let xmm10 = regs::xmm10(); + let xmm11 = regs::xmm11(); + let xmm12 = regs::xmm12(); + let xmm13 = regs::xmm13(); + let xmm14 = regs::xmm14(); + let xmm15 = regs::xmm15(); + + // And Writable<> versions of the same: + let w_rax = Writable::::from_reg(rax); + let w_rbx = Writable::::from_reg(rbx); + let w_rcx = Writable::::from_reg(rcx); + let w_rdx = Writable::::from_reg(rdx); + let w_rsi = Writable::::from_reg(rsi); + let w_rdi = Writable::::from_reg(rdi); + let _w_rsp = Writable::::from_reg(rsp); + let _w_rbp = Writable::::from_reg(rbp); + let w_r8 = Writable::::from_reg(r8); + let w_r9 = Writable::::from_reg(r9); + let w_r10 = Writable::::from_reg(r10); + let w_r11 = Writable::::from_reg(r11); + let w_r12 = Writable::::from_reg(r12); + let w_r13 = Writable::::from_reg(r13); + let w_r14 = Writable::::from_reg(r14); + let w_r15 = Writable::::from_reg(r15); + + let w_xmm0 = Writable::::from_reg(xmm0); + let w_xmm1 = Writable::::from_reg(xmm1); + let w_xmm2 = Writable::::from_reg(xmm2); + let w_xmm3 = Writable::::from_reg(xmm3); + let w_xmm4 = Writable::::from_reg(xmm4); + let w_xmm5 = Writable::::from_reg(xmm5); + let w_xmm6 = Writable::::from_reg(xmm6); + let w_xmm7 = Writable::::from_reg(xmm7); + let w_xmm8 = Writable::::from_reg(xmm8); + let w_xmm9 = Writable::::from_reg(xmm9); + let w_xmm10 = Writable::::from_reg(xmm10); + let w_xmm11 = Writable::::from_reg(xmm11); + let w_xmm12 = Writable::::from_reg(xmm12); + let w_xmm13 = Writable::::from_reg(xmm13); + let w_xmm14 = Writable::::from_reg(xmm14); + let w_xmm15 = Writable::::from_reg(xmm15); + + let mut insns = Vec::<(Inst, &str, &str)>::new(); + + // ======================================================== + // Cases aimed at checking Addr-esses: IR (Imm + Reg) + // + // These are just a bunch of loads with all supported (by the emitter) + // permutations of address formats. + // + // Addr_IR, offset zero + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rax), w_rdi), + "488B38", + "movq 0(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rbx), w_rdi), + "488B3B", + "movq 0(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rcx), w_rdi), + "488B39", + "movq 0(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rdx), w_rdi), + "488B3A", + "movq 0(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rbp), w_rdi), + "488B7D00", + "movq 0(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rsp), w_rdi), + "488B3C24", + "movq 0(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rsi), w_rdi), + "488B3E", + "movq 0(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, rdi), w_rdi), + "488B3F", + "movq 0(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r8), w_rdi), + "498B38", + "movq 0(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r9), w_rdi), + "498B39", + "movq 0(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r10), w_rdi), + "498B3A", + "movq 0(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r11), w_rdi), + "498B3B", + "movq 0(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r12), w_rdi), + "498B3C24", + "movq 0(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r13), w_rdi), + "498B7D00", + "movq 0(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r14), w_rdi), + "498B3E", + "movq 0(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0, r15), w_rdi), + "498B3F", + "movq 0(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset max simm8 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rax), w_rdi), + "488B787F", + "movq 127(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rbx), w_rdi), + "488B7B7F", + "movq 127(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rcx), w_rdi), + "488B797F", + "movq 127(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rdx), w_rdi), + "488B7A7F", + "movq 127(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rbp), w_rdi), + "488B7D7F", + "movq 127(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rsp), w_rdi), + "488B7C247F", + "movq 127(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rsi), w_rdi), + "488B7E7F", + "movq 127(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, rdi), w_rdi), + "488B7F7F", + "movq 127(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r8), w_rdi), + "498B787F", + "movq 127(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r9), w_rdi), + "498B797F", + "movq 127(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r10), w_rdi), + "498B7A7F", + "movq 127(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r11), w_rdi), + "498B7B7F", + "movq 127(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r12), w_rdi), + "498B7C247F", + "movq 127(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r13), w_rdi), + "498B7D7F", + "movq 127(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r14), w_rdi), + "498B7E7F", + "movq 127(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(127, r15), w_rdi), + "498B7F7F", + "movq 127(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset min simm8 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rax), w_rdi), + "488B7880", + "movq -128(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rbx), w_rdi), + "488B7B80", + "movq -128(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rcx), w_rdi), + "488B7980", + "movq -128(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rdx), w_rdi), + "488B7A80", + "movq -128(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rbp), w_rdi), + "488B7D80", + "movq -128(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rsp), w_rdi), + "488B7C2480", + "movq -128(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rsi), w_rdi), + "488B7E80", + "movq -128(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, rdi), w_rdi), + "488B7F80", + "movq -128(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r8), w_rdi), + "498B7880", + "movq -128(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r9), w_rdi), + "498B7980", + "movq -128(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r10), w_rdi), + "498B7A80", + "movq -128(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r11), w_rdi), + "498B7B80", + "movq -128(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r12), w_rdi), + "498B7C2480", + "movq -128(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r13), w_rdi), + "498B7D80", + "movq -128(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r14), w_rdi), + "498B7E80", + "movq -128(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-128, r15), w_rdi), + "498B7F80", + "movq -128(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset smallest positive simm32 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rax), w_rdi), + "488BB880000000", + "movq 128(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rbx), w_rdi), + "488BBB80000000", + "movq 128(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rcx), w_rdi), + "488BB980000000", + "movq 128(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rdx), w_rdi), + "488BBA80000000", + "movq 128(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rbp), w_rdi), + "488BBD80000000", + "movq 128(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rsp), w_rdi), + "488BBC2480000000", + "movq 128(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rsi), w_rdi), + "488BBE80000000", + "movq 128(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, rdi), w_rdi), + "488BBF80000000", + "movq 128(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r8), w_rdi), + "498BB880000000", + "movq 128(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r9), w_rdi), + "498BB980000000", + "movq 128(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r10), w_rdi), + "498BBA80000000", + "movq 128(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r11), w_rdi), + "498BBB80000000", + "movq 128(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r12), w_rdi), + "498BBC2480000000", + "movq 128(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r13), w_rdi), + "498BBD80000000", + "movq 128(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r14), w_rdi), + "498BBE80000000", + "movq 128(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(128, r15), w_rdi), + "498BBF80000000", + "movq 128(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset smallest negative simm32 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rax), w_rdi), + "488BB87FFFFFFF", + "movq -129(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rbx), w_rdi), + "488BBB7FFFFFFF", + "movq -129(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rcx), w_rdi), + "488BB97FFFFFFF", + "movq -129(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rdx), w_rdi), + "488BBA7FFFFFFF", + "movq -129(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rbp), w_rdi), + "488BBD7FFFFFFF", + "movq -129(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rsp), w_rdi), + "488BBC247FFFFFFF", + "movq -129(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rsi), w_rdi), + "488BBE7FFFFFFF", + "movq -129(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, rdi), w_rdi), + "488BBF7FFFFFFF", + "movq -129(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r8), w_rdi), + "498BB87FFFFFFF", + "movq -129(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r9), w_rdi), + "498BB97FFFFFFF", + "movq -129(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r10), w_rdi), + "498BBA7FFFFFFF", + "movq -129(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r11), w_rdi), + "498BBB7FFFFFFF", + "movq -129(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r12), w_rdi), + "498BBC247FFFFFFF", + "movq -129(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r13), w_rdi), + "498BBD7FFFFFFF", + "movq -129(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r14), w_rdi), + "498BBE7FFFFFFF", + "movq -129(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-129i32, r15), w_rdi), + "498BBF7FFFFFFF", + "movq -129(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset large positive simm32 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rax), w_rdi), + "488BB877207317", + "movq 393420919(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rbx), w_rdi), + "488BBB77207317", + "movq 393420919(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rcx), w_rdi), + "488BB977207317", + "movq 393420919(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rdx), w_rdi), + "488BBA77207317", + "movq 393420919(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rbp), w_rdi), + "488BBD77207317", + "movq 393420919(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rsp), w_rdi), + "488BBC2477207317", + "movq 393420919(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rsi), w_rdi), + "488BBE77207317", + "movq 393420919(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, rdi), w_rdi), + "488BBF77207317", + "movq 393420919(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r8), w_rdi), + "498BB877207317", + "movq 393420919(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r9), w_rdi), + "498BB977207317", + "movq 393420919(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r10), w_rdi), + "498BBA77207317", + "movq 393420919(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r11), w_rdi), + "498BBB77207317", + "movq 393420919(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r12), w_rdi), + "498BBC2477207317", + "movq 393420919(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r13), w_rdi), + "498BBD77207317", + "movq 393420919(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r14), w_rdi), + "498BBE77207317", + "movq 393420919(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(0x17732077, r15), w_rdi), + "498BBF77207317", + "movq 393420919(%r15), %rdi", + )); + + // ======================================================== + // Addr_IR, offset large negative simm32 + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rax), w_rdi), + "488BB8D9A6BECE", + "movq -826366247(%rax), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rbx), w_rdi), + "488BBBD9A6BECE", + "movq -826366247(%rbx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rcx), w_rdi), + "488BB9D9A6BECE", + "movq -826366247(%rcx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rdx), w_rdi), + "488BBAD9A6BECE", + "movq -826366247(%rdx), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rbp), w_rdi), + "488BBDD9A6BECE", + "movq -826366247(%rbp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rsp), w_rdi), + "488BBC24D9A6BECE", + "movq -826366247(%rsp), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rsi), w_rdi), + "488BBED9A6BECE", + "movq -826366247(%rsi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, rdi), w_rdi), + "488BBFD9A6BECE", + "movq -826366247(%rdi), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r8), w_rdi), + "498BB8D9A6BECE", + "movq -826366247(%r8), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r9), w_rdi), + "498BB9D9A6BECE", + "movq -826366247(%r9), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r10), w_rdi), + "498BBAD9A6BECE", + "movq -826366247(%r10), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r11), w_rdi), + "498BBBD9A6BECE", + "movq -826366247(%r11), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r12), w_rdi), + "498BBC24D9A6BECE", + "movq -826366247(%r12), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r13), w_rdi), + "498BBDD9A6BECE", + "movq -826366247(%r13), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r14), w_rdi), + "498BBED9A6BECE", + "movq -826366247(%r14), %rdi", + )); + insns.push(( + Inst::mov64_m_r(Amode::imm_reg(-0x31415927i32, r15), w_rdi), + "498BBFD9A6BECE", + "movq -826366247(%r15), %rdi", + )); + + // ======================================================== + // Cases aimed at checking Addr-esses: IRRS (Imm + Reg + (Reg << Shift)) + // Note these don't check the case where the index reg is RSP, since we + // don't encode any of those. + // + // Addr_IRRS, offset max simm8 + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(rax), Gpr::unwrap_new(rax), 0), + w_r11, + ), + "4C8B5C007F", + "movq 127(%rax,%rax,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(rdi), Gpr::unwrap_new(rax), 1), + w_r11, + ), + "4C8B5C477F", + "movq 127(%rdi,%rax,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(r8), Gpr::unwrap_new(rax), 2), + w_r11, + ), + "4D8B5C807F", + "movq 127(%r8,%rax,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(r15), Gpr::unwrap_new(rax), 3), + w_r11, + ), + "4D8B5CC77F", + "movq 127(%r15,%rax,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(rax), Gpr::unwrap_new(rdi), 3), + w_r11, + ), + "4C8B5CF87F", + "movq 127(%rax,%rdi,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(rdi), Gpr::unwrap_new(rdi), 2), + w_r11, + ), + "4C8B5CBF7F", + "movq 127(%rdi,%rdi,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(r8), Gpr::unwrap_new(rdi), 1), + w_r11, + ), + "4D8B5C787F", + "movq 127(%r8,%rdi,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(127, Gpr::unwrap_new(r15), Gpr::unwrap_new(rdi), 0), + w_r11, + ), + "4D8B5C3F7F", + "movq 127(%r15,%rdi,1), %r11", + )); + + // ======================================================== + // Addr_IRRS, offset min simm8 + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(rax), Gpr::unwrap_new(r8), 2), + w_r11, + ), + "4E8B5C8080", + "movq -128(%rax,%r8,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(rdi), Gpr::unwrap_new(r8), 3), + w_r11, + ), + "4E8B5CC780", + "movq -128(%rdi,%r8,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(r8), Gpr::unwrap_new(r8), 0), + w_r11, + ), + "4F8B5C0080", + "movq -128(%r8,%r8,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(r15), Gpr::unwrap_new(r8), 1), + w_r11, + ), + "4F8B5C4780", + "movq -128(%r15,%r8,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(rax), Gpr::unwrap_new(r15), 1), + w_r11, + ), + "4E8B5C7880", + "movq -128(%rax,%r15,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(rdi), Gpr::unwrap_new(r15), 0), + w_r11, + ), + "4E8B5C3F80", + "movq -128(%rdi,%r15,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(r8), Gpr::unwrap_new(r15), 3), + w_r11, + ), + "4F8B5CF880", + "movq -128(%r8,%r15,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-128i32, Gpr::unwrap_new(r15), Gpr::unwrap_new(r15), 2), + w_r11, + ), + "4F8B5CBF80", + "movq -128(%r15,%r15,4), %r11", + )); + + // ======================================================== + // Addr_IRRS, offset large positive simm32 + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(rax), Gpr::unwrap_new(rax), 0), + w_r11, + ), + "4C8B9C00BE25664F", + "movq 1332094398(%rax,%rax,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(rdi), Gpr::unwrap_new(rax), 1), + w_r11, + ), + "4C8B9C47BE25664F", + "movq 1332094398(%rdi,%rax,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(r8), Gpr::unwrap_new(rax), 2), + w_r11, + ), + "4D8B9C80BE25664F", + "movq 1332094398(%r8,%rax,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(r15), Gpr::unwrap_new(rax), 3), + w_r11, + ), + "4D8B9CC7BE25664F", + "movq 1332094398(%r15,%rax,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(rax), Gpr::unwrap_new(rdi), 3), + w_r11, + ), + "4C8B9CF8BE25664F", + "movq 1332094398(%rax,%rdi,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(rdi), Gpr::unwrap_new(rdi), 2), + w_r11, + ), + "4C8B9CBFBE25664F", + "movq 1332094398(%rdi,%rdi,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(r8), Gpr::unwrap_new(rdi), 1), + w_r11, + ), + "4D8B9C78BE25664F", + "movq 1332094398(%r8,%rdi,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(0x4f6625be, Gpr::unwrap_new(r15), Gpr::unwrap_new(rdi), 0), + w_r11, + ), + "4D8B9C3FBE25664F", + "movq 1332094398(%r15,%rdi,1), %r11", + )); + + // ======================================================== + // Addr_IRRS, offset large negative simm32 + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-0x264d1690i32, Gpr::unwrap_new(rax), Gpr::unwrap_new(r8), 2), + w_r11, + ), + "4E8B9C8070E9B2D9", + "movq -642586256(%rax,%r8,4), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-0x264d1690i32, Gpr::unwrap_new(rdi), Gpr::unwrap_new(r8), 3), + w_r11, + ), + "4E8B9CC770E9B2D9", + "movq -642586256(%rdi,%r8,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-0x264d1690i32, Gpr::unwrap_new(r8), Gpr::unwrap_new(r8), 0), + w_r11, + ), + "4F8B9C0070E9B2D9", + "movq -642586256(%r8,%r8,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-0x264d1690i32, Gpr::unwrap_new(r15), Gpr::unwrap_new(r8), 1), + w_r11, + ), + "4F8B9C4770E9B2D9", + "movq -642586256(%r15,%r8,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift( + -0x264d1690i32, + Gpr::unwrap_new(rax), + Gpr::unwrap_new(r15), + 1, + ), + w_r11, + ), + "4E8B9C7870E9B2D9", + "movq -642586256(%rax,%r15,2), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift( + -0x264d1690i32, + Gpr::unwrap_new(rdi), + Gpr::unwrap_new(r15), + 0, + ), + w_r11, + ), + "4E8B9C3F70E9B2D9", + "movq -642586256(%rdi,%r15,1), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(-0x264d1690i32, Gpr::unwrap_new(r8), Gpr::unwrap_new(r15), 3), + w_r11, + ), + "4F8B9CF870E9B2D9", + "movq -642586256(%r8,%r15,8), %r11", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift( + -0x264d1690i32, + Gpr::unwrap_new(r15), + Gpr::unwrap_new(r15), + 2, + ), + w_r11, + ), + "4F8B9CBF70E9B2D9", + "movq -642586256(%r15,%r15,4), %r11", + )); + + // End of test cases for Addr + // ======================================================== + + // ======================================================== + // General tests for each insn. Don't forget to follow the + // guidelines commented just prior to `fn x64_emit`. + // + // Alu_RMI_R + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::reg(r15), + w_rdx, + ), + "4C01FA", + "addq %rdx, %r15, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::reg(rcx), + w_r8, + ), + "4101C8", + "addl %r8d, %ecx, %r8d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::reg(rcx), + w_rsi, + ), + "01CE", + "addl %esi, %ecx, %esi", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + w_rdx, + ), + "48035763", + "addq %rdx, 99(%rdi), %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + w_r8, + ), + "44034763", + "addl %r8d, 99(%rdi), %r8d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + w_rsi, + ), + "037763", + "addl %esi, 99(%rdi), %esi", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(-127i32 as u32), + w_rdx, + ), + "4883C281", + "addq %rdx, $-127, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(-129i32 as u32), + w_rdx, + ), + "4881C27FFFFFFF", + "addq %rdx, $-129, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Add, + RegMemImm::imm(76543210), + w_rdx, + ), + "4881C2EAF48F04", + "addq %rdx, $76543210, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(-127i32 as u32), + w_r8, + ), + "4183C081", + "addl %r8d, $-127, %r8d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(-129i32 as u32), + w_r8, + ), + "4181C07FFFFFFF", + "addl %r8d, $-129, %r8d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(-76543210i32 as u32), + w_r8, + ), + "4181C0160B70FB", + "addl %r8d, $-76543210, %r8d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(-127i32 as u32), + w_rsi, + ), + "83C681", + "addl %esi, $-127, %esi", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(-129i32 as u32), + w_rsi, + ), + "81C67FFFFFFF", + "addl %esi, $-129, %esi", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Add, + RegMemImm::imm(76543210), + w_rsi, + ), + "81C6EAF48F04", + "addl %esi, $76543210, %esi", + )); + // This is pretty feeble + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sub, + RegMemImm::reg(r15), + w_rdx, + ), + "4C29FA", + "subq %rdx, %r15, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::And, + RegMemImm::reg(r15), + w_rdx, + ), + "4C21FA", + "andq %rdx, %r15, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Or, + RegMemImm::reg(r15), + w_rdx, + ), + "4C09FA", + "orq %rdx, %r15, %rdx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Xor, + RegMemImm::reg(r15), + w_rdx, + ), + "4C31FA", + "xorq %rdx, %r15, %rdx", + )); + + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::Add, + RegMemImm::reg(rax), + w_rdx, + ), + "6601C2", + "addw %dx, %ax, %dx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::Add, + RegMemImm::imm(10), + w_rdx, + ), + "6683C20A", + "addw %dx, $10, %dx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::Add, + RegMemImm::imm(-512i32 as u32), + w_rdx, + ), + "6681C200FE", + "addw %dx, $-512, %dx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::Sub, + RegMemImm::reg(rax), + w_r12, + ), + "664129C4", + "subw %r12w, %ax, %r12w", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::Xor, + RegMemImm::reg(r10), + w_rcx, + ), + "664431D1", + "xorw %cx, %r10w, %cx", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::And, + RegMemImm::reg(r10), + w_r14, + ), + "664521D6", + "andw %r14w, %r10w, %r14w", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::And, + RegMemImm::imm(10), + w_r14, + ), + "664183E60A", + "andw %r14w, $10, %r14w", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size16, + AluRmiROpcode::And, + RegMemImm::imm(-512i32 as u32), + w_r14, + ), + "664181E600FE", + "andw %r14w, $-512, %r14w", + )); + + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Add, + RegMemImm::imm(10), + w_rax, + ), + "80C00A", // there is theoretically 040A as a valid encoding also + "addb %al, $10, %al", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Add, + RegMemImm::reg(rcx), + w_rax, + ), + "00C8", + "addb %al, %cl, %al", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Add, + RegMemImm::reg(rsi), + w_rax, + ), + "4000F0", + "addb %al, %sil, %al", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Add, + RegMemImm::reg(r11), + w_rax, + ), + "4400D8", + "addb %al, %r11b, %al", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Add, + RegMemImm::reg(r15), + w_rax, + ), + "4400F8", + "addb %al, %r15b, %al", + )); + + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Sub, + RegMemImm::imm(10), + _w_rbp, + ), + "4080ED0A", + "subb %bpl, $10, %bpl", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Sub, + RegMemImm::reg(rcx), + _w_rbp, + ), + "4028CD", + "subb %bpl, %cl, %bpl", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Sub, + RegMemImm::reg(rsi), + _w_rbp, + ), + "4028F5", + "subb %bpl, %sil, %bpl", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Sub, + RegMemImm::reg(r11), + _w_rbp, + ), + "4428DD", + "subb %bpl, %r11b, %bpl", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Sub, + RegMemImm::reg(r15), + _w_rbp, + ), + "4428FD", + "subb %bpl, %r15b, %bpl", + )); + + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Xor, + RegMemImm::imm(10), + w_r10, + ), + "4180F20A", + "xorb %r10b, $10, %r10b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Xor, + RegMemImm::reg(rcx), + w_r10, + ), + "4130CA", + "xorb %r10b, %cl, %r10b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Xor, + RegMemImm::reg(rsi), + w_r10, + ), + "4130F2", + "xorb %r10b, %sil, %r10b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Xor, + RegMemImm::reg(r11), + w_r10, + ), + "4530DA", + "xorb %r10b, %r11b, %r10b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::Xor, + RegMemImm::reg(r15), + w_r10, + ), + "4530FA", + "xorb %r10b, %r15b, %r10b", + )); + + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::And, + RegMemImm::imm(10), + w_r15, + ), + "4180E70A", + "andb %r15b, $10, %r15b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::And, + RegMemImm::reg(rcx), + w_r15, + ), + "4120CF", + "andb %r15b, %cl, %r15b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::And, + RegMemImm::reg(rsi), + w_r15, + ), + "4120F7", + "andb %r15b, %sil, %r15b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::And, + RegMemImm::reg(r11), + w_r15, + ), + "4520DF", + "andb %r15b, %r11b, %r15b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size8, + AluRmiROpcode::And, + RegMemImm::reg(r15), + w_r15, + ), + "4520FF", + "andb %r15b, %r15b, %r15b", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size32, + AluRmiROpcode::Sbb, + RegMemImm::reg(r14), + w_r15, + ), + "4519F7", + "sbbl %r15d, %r14d, %r15d", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sbb, + RegMemImm::imm(0), + w_r15, + ), + "4983DF00", + "sbbq %r15, $0, %r15", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Adc, + RegMemImm::imm(0), + w_r15, + ), + "4983D700", + "adcq %r15, $0, %r15", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Adc, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + w_r15, + ), + "4C137F63", + "adcq %r15, 99(%rdi), %r15", + )); + insns.push(( + Inst::alu_rmi_r( + OperandSize::Size64, + AluRmiROpcode::Sbb, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + w_r15, + ), + "4C1B7F63", + "sbbq %r15, 99(%rdi), %r15", + )); + + // ======================================================== + // AluRM + + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::Add, + src1_dst: Amode::imm_reg(99, rdi).into(), + src2: Gpr::unwrap_new(r12), + lock: false, + }, + "44016763", + "addl %r12d, 99(%rdi)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::Add, + src1_dst: Amode::imm_reg_reg_shift(0, Gpr::unwrap_new(rbp), Gpr::unwrap_new(rax), 3) + .into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "480144C500", + "addq %rax, 0(%rbp,%rax,8)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::Sub, + src1_dst: Amode::imm_reg(0, rsp).into(), + src2: Gpr::unwrap_new(rcx), + lock: false, + }, + "290C24", + "subl %ecx, 0(%rsp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::Sub, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "48294500", + "subq %rax, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::And, + src1_dst: Amode::imm_reg(0, rsp).into(), + src2: Gpr::unwrap_new(rcx), + lock: false, + }, + "210C24", + "andl %ecx, 0(%rsp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::And, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "48214500", + "andq %rax, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::Or, + src1_dst: Amode::imm_reg(0, rsp).into(), + src2: Gpr::unwrap_new(rcx), + lock: false, + }, + "090C24", + "orl %ecx, 0(%rsp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::Or, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "48094500", + "orq %rax, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::Xor, + src1_dst: Amode::imm_reg(0, rsp).into(), + src2: Gpr::unwrap_new(rcx), + lock: false, + }, + "310C24", + "xorl %ecx, 0(%rsp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::Xor, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "48314500", + "xorq %rax, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size16, + op: AluRmiROpcode::Add, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "66014500", + "addw %ax, 0(%rbp)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size16, + op: AluRmiROpcode::Sub, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(r12), + lock: false, + }, + "6644296500", + "subw %r12w, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size8, + op: AluRmiROpcode::Add, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rax), + lock: false, + }, + "004500", + "addb %al, 0(%rbp)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size8, + op: AluRmiROpcode::Sub, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(rbp), + lock: false, + }, + "40286D00", + "subb %bpl, 0(%rbp)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size8, + op: AluRmiROpcode::Xor, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(r10), + lock: false, + }, + "44305500", + "xorb %r10b, 0(%rbp)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size8, + op: AluRmiROpcode::And, + src1_dst: Amode::imm_reg(0, rbp).into(), + src2: Gpr::unwrap_new(r15), + lock: false, + }, + "44207D00", + "andb %r15b, 0(%rbp)", + )); + + insns.push(( + Inst::AluRM { + size: OperandSize::Size64, + op: AluRmiROpcode::And, + src1_dst: Amode::imm_reg(0, rdx).into(), + src2: Gpr::unwrap_new(rax), + lock: true, + }, + "F0482102", + "lock andq %rax, 0(%rdx)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size32, + op: AluRmiROpcode::Or, + src1_dst: Amode::imm_reg(0, rdx).into(), + src2: Gpr::unwrap_new(rax), + lock: true, + }, + "F00902", + "lock orl %eax, 0(%rdx)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size16, + op: AluRmiROpcode::Xor, + src1_dst: Amode::imm_reg(0, rdx).into(), + src2: Gpr::unwrap_new(rax), + lock: true, + }, + "66F03102", + "lock xorw %ax, 0(%rdx)", + )); + insns.push(( + Inst::AluRM { + size: OperandSize::Size8, + op: AluRmiROpcode::Add, + src1_dst: Amode::imm_reg(0, r9).into(), + src2: Gpr::unwrap_new(rax), + lock: true, + }, + "F0410001", + "lock addb %al, 0(%r9)", + )); + + // ======================================================== + // UnaryRmR + + insns.push(( + Inst::unary_rm_r( + OperandSize::Size32, + UnaryRmROpcode::Bsr, + RegMem::reg(rsi), + w_rdi, + ), + "0FBDFE", + "bsrl %esi, %edi", + )); + insns.push(( + Inst::unary_rm_r( + OperandSize::Size64, + UnaryRmROpcode::Bsr, + RegMem::reg(r15), + w_rax, + ), + "490FBDC7", + "bsrq %r15, %rax", + )); + + // ======================================================== + // Not + insns.push(( + Inst::not(OperandSize::Size32, Writable::from_reg(regs::rsi())), + "F7D6", + "notl %esi, %esi", + )); + insns.push(( + Inst::not(OperandSize::Size64, Writable::from_reg(regs::r15())), + "49F7D7", + "notq %r15, %r15", + )); + insns.push(( + Inst::not(OperandSize::Size32, Writable::from_reg(regs::r14())), + "41F7D6", + "notl %r14d, %r14d", + )); + insns.push(( + Inst::not(OperandSize::Size16, Writable::from_reg(regs::rdi())), + "66F7D7", + "notw %di, %di", + )); + insns.push(( + Inst::not(OperandSize::Size8, Writable::from_reg(regs::rdi())), + "40F6D7", + "notb %dil, %dil", + )); + insns.push(( + Inst::not(OperandSize::Size8, Writable::from_reg(regs::rax())), + "F6D0", + "notb %al, %al", + )); + + // ======================================================== + // Neg + insns.push(( + Inst::neg(OperandSize::Size32, Writable::from_reg(regs::rsi())), + "F7DE", + "negl %esi, %esi", + )); + insns.push(( + Inst::neg(OperandSize::Size64, Writable::from_reg(regs::r15())), + "49F7DF", + "negq %r15, %r15", + )); + insns.push(( + Inst::neg(OperandSize::Size32, Writable::from_reg(regs::r14())), + "41F7DE", + "negl %r14d, %r14d", + )); + insns.push(( + Inst::neg(OperandSize::Size16, Writable::from_reg(regs::rdi())), + "66F7DF", + "negw %di, %di", + )); + insns.push(( + Inst::neg(OperandSize::Size8, Writable::from_reg(regs::rdi())), + "40F6DF", + "negb %dil, %dil", + )); + insns.push(( + Inst::neg(OperandSize::Size8, Writable::from_reg(regs::rax())), + "F6D8", + "negb %al, %al", + )); + + // ======================================================== + // Div + insns.push(( + Inst::div( + OperandSize::Size32, + DivSignedness::Signed, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::rsi()), + Gpr::unwrap_new(regs::rax()), + Gpr::unwrap_new(regs::rdx()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rdx())), + ), + "F7FE", + "idiv %eax, %edx, %esi, %eax, %edx ; trap=int_divz", + )); + insns.push(( + Inst::div( + OperandSize::Size64, + DivSignedness::Signed, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::r15()), + Gpr::unwrap_new(regs::rax()), + Gpr::unwrap_new(regs::rdx()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rdx())), + ), + "49F7FF", + "idiv %rax, %rdx, %r15, %rax, %rdx ; trap=int_divz", + )); + insns.push(( + Inst::div( + OperandSize::Size32, + DivSignedness::Unsigned, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::r14()), + Gpr::unwrap_new(regs::rax()), + Gpr::unwrap_new(regs::rdx()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rdx())), + ), + "41F7F6", + "div %eax, %edx, %r14d, %eax, %edx ; trap=int_divz", + )); + insns.push(( + Inst::div( + OperandSize::Size64, + DivSignedness::Unsigned, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::rdi()), + Gpr::unwrap_new(regs::rax()), + Gpr::unwrap_new(regs::rdx()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rdx())), + ), + "48F7F7", + "div %rax, %rdx, %rdi, %rax, %rdx ; trap=int_divz", + )); + insns.push(( + Inst::div8( + DivSignedness::Unsigned, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::rax()), + Gpr::unwrap_new(regs::rax()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + ), + "F6F0", + "div %al, %al, %al ; trap=int_divz", + )); + insns.push(( + Inst::div8( + DivSignedness::Unsigned, + TrapCode::INTEGER_DIVISION_BY_ZERO, + RegMem::reg(regs::rsi()), + Gpr::unwrap_new(regs::rax()), + WritableGpr::from_reg(Gpr::unwrap_new(regs::rax())), + ), + "40F6F6", + "div %al, %sil, %al ; trap=int_divz", + )); + + // ======================================================== + // Imm_R + // + insns.push(( + Inst::imm(OperandSize::Size32, 1234567, w_r14), + "41BE87D61200", + "movl $1234567, %r14d", + )); + insns.push(( + Inst::imm(OperandSize::Size32, -126i64 as u64, w_r14), + "41BE82FFFFFF", + "movl $-126, %r14d", + )); + insns.push(( + Inst::imm(OperandSize::Size64, 1234567898765, w_r14), + "49BE8D26FB711F010000", + "movabsq $1234567898765, %r14", + )); + insns.push(( + Inst::imm(OperandSize::Size64, -126i64 as u64, w_r14), + "49C7C682FFFFFF", + "movabsq $-126, %r14", + )); + insns.push(( + Inst::imm(OperandSize::Size32, 1234567, w_rcx), + "B987D61200", + "movl $1234567, %ecx", + )); + insns.push(( + Inst::imm(OperandSize::Size32, -126i64 as u64, w_rcx), + "B982FFFFFF", + "movl $-126, %ecx", + )); + insns.push(( + Inst::imm(OperandSize::Size64, 1234567898765, w_rsi), + "48BE8D26FB711F010000", + "movabsq $1234567898765, %rsi", + )); + insns.push(( + Inst::imm(OperandSize::Size64, -126i64 as u64, w_rbx), + "48C7C382FFFFFF", + "movabsq $-126, %rbx", + )); + + // ======================================================== + // Mov_R_R + insns.push(( + Inst::mov_r_r(OperandSize::Size32, rbx, w_rsi), + "89DE", + "movl %ebx, %esi", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size32, rbx, w_r9), + "4189D9", + "movl %ebx, %r9d", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size32, r11, w_rsi), + "4489DE", + "movl %r11d, %esi", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size32, r12, w_r9), + "4589E1", + "movl %r12d, %r9d", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size64, rbx, w_rsi), + "4889DE", + "movq %rbx, %rsi", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size64, rbx, w_r9), + "4989D9", + "movq %rbx, %r9", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size64, r11, w_rsi), + "4C89DE", + "movq %r11, %rsi", + )); + insns.push(( + Inst::mov_r_r(OperandSize::Size64, r12, w_r9), + "4D89E1", + "movq %r12, %r9", + )); + + // ======================================================== + // MovZX_RM_R + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(rdi), w_rdi), + "400FB6FF", + "movzbl %dil, %edi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(rax), w_rsi), + "0FB6F0", + "movzbl %al, %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(r15), w_rsi), + "410FB6F7", + "movzbl %r15b, %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "0FB671F9", + "movzbl -7(%rcx), %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "410FB658F9", + "movzbl -7(%r8), %ebx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "450FB64AF9", + "movzbl -7(%r10), %r9d", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "410FB653F9", + "movzbl -7(%r11), %edx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::reg(rax), w_rsi), + "480FB6F0", + "movzbq %al, %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::reg(r10), w_rsi), + "490FB6F2", + "movzbq %r10b, %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "480FB671F9", + "movzbq -7(%rcx), %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "490FB658F9", + "movzbq -7(%r8), %rbx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "4D0FB64AF9", + "movzbq -7(%r10), %r9", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "490FB653F9", + "movzbq -7(%r11), %rdx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::reg(rcx), w_rsi), + "0FB7F1", + "movzwl %cx, %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::reg(r10), w_rsi), + "410FB7F2", + "movzwl %r10w, %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "0FB771F9", + "movzwl -7(%rcx), %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "410FB758F9", + "movzwl -7(%r8), %ebx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "450FB74AF9", + "movzwl -7(%r10), %r9d", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "410FB753F9", + "movzwl -7(%r11), %edx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::reg(rcx), w_rsi), + "480FB7F1", + "movzwq %cx, %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::reg(r11), w_rsi), + "490FB7F3", + "movzwq %r11w, %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "480FB771F9", + "movzwq -7(%rcx), %rsi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "490FB758F9", + "movzwq -7(%r8), %rbx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "4D0FB74AF9", + "movzwq -7(%r10), %r9", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "490FB753F9", + "movzwq -7(%r11), %rdx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::LQ, RegMem::reg(rcx), w_rsi), + "8BF1", + "movl %ecx, %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "8B71F9", + "movl -7(%rcx), %esi", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "418B58F9", + "movl -7(%r8), %ebx", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "458B4AF9", + "movl -7(%r10), %r9d", + )); + insns.push(( + Inst::movzx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "418B53F9", + "movl -7(%r11), %edx", + )); + + // ======================================================== + // Mov64_M_R + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(rax), Gpr::unwrap_new(rbx), 0), + w_rcx, + ), + "488B8C18B3000000", + "movq 179(%rax,%rbx,1), %rcx", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(rax), Gpr::unwrap_new(rbx), 0), + w_r8, + ), + "4C8B8418B3000000", + "movq 179(%rax,%rbx,1), %r8", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(rax), Gpr::unwrap_new(r9), 0), + w_rcx, + ), + "4A8B8C08B3000000", + "movq 179(%rax,%r9,1), %rcx", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(rax), Gpr::unwrap_new(r9), 0), + w_r8, + ), + "4E8B8408B3000000", + "movq 179(%rax,%r9,1), %r8", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(r10), Gpr::unwrap_new(rbx), 0), + w_rcx, + ), + "498B8C1AB3000000", + "movq 179(%r10,%rbx,1), %rcx", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(r10), Gpr::unwrap_new(rbx), 0), + w_r8, + ), + "4D8B841AB3000000", + "movq 179(%r10,%rbx,1), %r8", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(r10), Gpr::unwrap_new(r9), 0), + w_rcx, + ), + "4B8B8C0AB3000000", + "movq 179(%r10,%r9,1), %rcx", + )); + insns.push(( + Inst::mov64_m_r( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(r10), Gpr::unwrap_new(r9), 0), + w_r8, + ), + "4F8B840AB3000000", + "movq 179(%r10,%r9,1), %r8", + )); + + // ======================================================== + // LoadEffectiveAddress + insns.push(( + Inst::lea(Amode::imm_reg(42, r10), w_r8), + "4D8D422A", + "lea 42(%r10), %r8", + )); + insns.push(( + Inst::lea(Amode::imm_reg(42, r10), w_r15), + "4D8D7A2A", + "lea 42(%r10), %r15", + )); + insns.push(( + Inst::lea( + Amode::imm_reg_reg_shift(179, Gpr::unwrap_new(r10), Gpr::unwrap_new(r9), 0), + w_r8, + ), + "4F8D840AB3000000", + "lea 179(%r10,%r9,1), %r8", + )); + insns.push(( + Inst::lea( + Amode::rip_relative(MachLabel::from_block(BlockIndex::new(0))), + w_rdi, + ), + "488D3D00000000", + "lea label0(%rip), %rdi", + )); + + // ======================================================== + // MovSX_RM_R + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(rdi), w_rdi), + "400FBEFF", + "movsbl %dil, %edi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(rcx), w_rsi), + "0FBEF1", + "movsbl %cl, %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(r14), w_rsi), + "410FBEF6", + "movsbl %r14b, %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "0FBE71F9", + "movsbl -7(%rcx), %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "410FBE58F9", + "movsbl -7(%r8), %ebx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "450FBE4AF9", + "movsbl -7(%r10), %r9d", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BL, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "410FBE53F9", + "movsbl -7(%r11), %edx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::reg(rcx), w_rsi), + "480FBEF1", + "movsbq %cl, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::reg(r15), w_rsi), + "490FBEF7", + "movsbq %r15b, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "480FBE71F9", + "movsbq -7(%rcx), %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "490FBE58F9", + "movsbq -7(%r8), %rbx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "4D0FBE4AF9", + "movsbq -7(%r10), %r9", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::BQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "490FBE53F9", + "movsbq -7(%r11), %rdx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::reg(rcx), w_rsi), + "0FBFF1", + "movswl %cx, %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::reg(r14), w_rsi), + "410FBFF6", + "movswl %r14w, %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "0FBF71F9", + "movswl -7(%rcx), %esi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "410FBF58F9", + "movswl -7(%r8), %ebx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "450FBF4AF9", + "movswl -7(%r10), %r9d", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WL, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "410FBF53F9", + "movswl -7(%r11), %edx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::reg(rcx), w_rsi), + "480FBFF1", + "movswq %cx, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::reg(r13), w_rsi), + "490FBFF5", + "movswq %r13w, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "480FBF71F9", + "movswq -7(%rcx), %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "490FBF58F9", + "movswq -7(%r8), %rbx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "4D0FBF4AF9", + "movswq -7(%r10), %r9", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::WQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "490FBF53F9", + "movswq -7(%r11), %rdx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::reg(rcx), w_rsi), + "4863F1", + "movslq %ecx, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::reg(r15), w_rsi), + "4963F7", + "movslq %r15d, %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, rcx)), w_rsi), + "486371F9", + "movslq -7(%rcx), %rsi", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r8)), w_rbx), + "496358F9", + "movslq -7(%r8), %rbx", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r10)), w_r9), + "4D634AF9", + "movslq -7(%r10), %r9", + )); + insns.push(( + Inst::movsx_rm_r(ExtMode::LQ, RegMem::mem(Amode::imm_reg(-7i32, r11)), w_rdx), + "496353F9", + "movslq -7(%r11), %rdx", + )); + + // Mov_Imm_M. + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm32: i8::MIN as i32, + dst: Amode::imm_reg(99, rax).into(), + }, + "C6406380", + "movb $-128, 99(%rax)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm32: i8::MAX as i32, + dst: Amode::imm_reg(99, r8).into(), + }, + "41C640637F", + "movb $127, 99(%r8)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm32: i16::MIN as i32, + dst: Amode::imm_reg(99, rcx).into(), + }, + "66C741630080", + "movw $-32768, 99(%rcx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm32: i16::MAX as i32, + dst: Amode::imm_reg(99, r9).into(), + }, + "6641C74163FF7F", + "movw $32767, 99(%r9)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm32: i32::MIN, + dst: Amode::imm_reg(99, rdx).into(), + }, + "C7426300000080", + "movl $-2147483648, 99(%rdx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm32: i32::MAX, + dst: Amode::imm_reg(99, r10).into(), + }, + "41C74263FFFFFF7F", + "movl $2147483647, 99(%r10)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm32: i32::MIN, + dst: Amode::imm_reg(99, rbx).into(), + }, + "48C7436300000080", + "movq $-2147483648, 99(%rbx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm32: i32::MAX, + dst: Amode::imm_reg(99, r11).into(), + }, + "49C74363FFFFFF7F", + "movq $2147483647, 99(%r11)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm32: 0i32, + dst: Amode::imm_reg(99, rsp).into(), + }, + "C644246300", + "movb $0, 99(%rsp)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm32: 0i32, + dst: Amode::imm_reg(99, r12).into(), + }, + "6641C74424630000", + "movw $0, 99(%r12)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm32: 0i32, + dst: Amode::imm_reg(99, rbp).into(), + }, + "C7456300000000", + "movl $0, 99(%rbp)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm32: 0i32, + dst: Amode::imm_reg(99, r13).into(), + }, + "49C7456300000000", + "movq $0, 99(%r13)", + )); + + // ======================================================== + // Mov_R_M. Byte stores are tricky. Check everything carefully. + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rax, Amode::imm_reg(99, rdi)), + "48894763", + "movq %rax, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rbx, Amode::imm_reg(99, r8)), + "49895863", + "movq %rbx, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rcx, Amode::imm_reg(99, rsi)), + "48894E63", + "movq %rcx, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rdx, Amode::imm_reg(99, r9)), + "49895163", + "movq %rdx, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rsi, Amode::imm_reg(99, rax)), + "48897063", + "movq %rsi, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rdi, Amode::imm_reg(99, r15)), + "49897F63", + "movq %rdi, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rsp, Amode::imm_reg(99, rcx)), + "48896163", + "movq %rsp, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, rbp, Amode::imm_reg(99, r14)), + "49896E63", + "movq %rbp, 99(%r14)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r8, Amode::imm_reg(99, rdi)), + "4C894763", + "movq %r8, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r9, Amode::imm_reg(99, r8)), + "4D894863", + "movq %r9, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r10, Amode::imm_reg(99, rsi)), + "4C895663", + "movq %r10, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r11, Amode::imm_reg(99, r9)), + "4D895963", + "movq %r11, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r12, Amode::imm_reg(99, rax)), + "4C896063", + "movq %r12, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r13, Amode::imm_reg(99, r15)), + "4D896F63", + "movq %r13, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r14, Amode::imm_reg(99, rcx)), + "4C897163", + "movq %r14, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size64, r15, Amode::imm_reg(99, r14)), + "4D897E63", + "movq %r15, 99(%r14)", + )); + // + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rax, Amode::imm_reg(99, rdi)), + "894763", + "movl %eax, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rbx, Amode::imm_reg(99, r8)), + "41895863", + "movl %ebx, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rcx, Amode::imm_reg(99, rsi)), + "894E63", + "movl %ecx, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rdx, Amode::imm_reg(99, r9)), + "41895163", + "movl %edx, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rsi, Amode::imm_reg(99, rax)), + "897063", + "movl %esi, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rdi, Amode::imm_reg(99, r15)), + "41897F63", + "movl %edi, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rsp, Amode::imm_reg(99, rcx)), + "896163", + "movl %esp, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, rbp, Amode::imm_reg(99, r14)), + "41896E63", + "movl %ebp, 99(%r14)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r8, Amode::imm_reg(99, rdi)), + "44894763", + "movl %r8d, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r9, Amode::imm_reg(99, r8)), + "45894863", + "movl %r9d, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r10, Amode::imm_reg(99, rsi)), + "44895663", + "movl %r10d, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r11, Amode::imm_reg(99, r9)), + "45895963", + "movl %r11d, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r12, Amode::imm_reg(99, rax)), + "44896063", + "movl %r12d, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r13, Amode::imm_reg(99, r15)), + "45896F63", + "movl %r13d, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r14, Amode::imm_reg(99, rcx)), + "44897163", + "movl %r14d, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size32, r15, Amode::imm_reg(99, r14)), + "45897E63", + "movl %r15d, 99(%r14)", + )); + // + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rax, Amode::imm_reg(99, rdi)), + "66894763", + "movw %ax, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rbx, Amode::imm_reg(99, r8)), + "6641895863", + "movw %bx, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rcx, Amode::imm_reg(99, rsi)), + "66894E63", + "movw %cx, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rdx, Amode::imm_reg(99, r9)), + "6641895163", + "movw %dx, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rsi, Amode::imm_reg(99, rax)), + "66897063", + "movw %si, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rdi, Amode::imm_reg(99, r15)), + "6641897F63", + "movw %di, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rsp, Amode::imm_reg(99, rcx)), + "66896163", + "movw %sp, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, rbp, Amode::imm_reg(99, r14)), + "6641896E63", + "movw %bp, 99(%r14)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r8, Amode::imm_reg(99, rdi)), + "6644894763", + "movw %r8w, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r9, Amode::imm_reg(99, r8)), + "6645894863", + "movw %r9w, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r10, Amode::imm_reg(99, rsi)), + "6644895663", + "movw %r10w, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r11, Amode::imm_reg(99, r9)), + "6645895963", + "movw %r11w, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r12, Amode::imm_reg(99, rax)), + "6644896063", + "movw %r12w, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r13, Amode::imm_reg(99, r15)), + "6645896F63", + "movw %r13w, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r14, Amode::imm_reg(99, rcx)), + "6644897163", + "movw %r14w, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size16, r15, Amode::imm_reg(99, r14)), + "6645897E63", + "movw %r15w, 99(%r14)", + )); + // + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rax, Amode::imm_reg(99, rdi)), + "884763", + "movb %al, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rbx, Amode::imm_reg(99, r8)), + "41885863", + "movb %bl, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rcx, Amode::imm_reg(99, rsi)), + "884E63", + "movb %cl, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rdx, Amode::imm_reg(99, r9)), + "41885163", + "movb %dl, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rsi, Amode::imm_reg(99, rax)), + "40887063", + "movb %sil, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rdi, Amode::imm_reg(99, r15)), + "41887F63", + "movb %dil, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rsp, Amode::imm_reg(99, rcx)), + "40886163", + "movb %spl, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, rbp, Amode::imm_reg(99, r14)), + "41886E63", + "movb %bpl, 99(%r14)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r8, Amode::imm_reg(99, rdi)), + "44884763", + "movb %r8b, 99(%rdi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r9, Amode::imm_reg(99, r8)), + "45884863", + "movb %r9b, 99(%r8)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r10, Amode::imm_reg(99, rsi)), + "44885663", + "movb %r10b, 99(%rsi)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r11, Amode::imm_reg(99, r9)), + "45885963", + "movb %r11b, 99(%r9)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r12, Amode::imm_reg(99, rax)), + "44886063", + "movb %r12b, 99(%rax)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r13, Amode::imm_reg(99, r15)), + "45886F63", + "movb %r13b, 99(%r15)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r14, Amode::imm_reg(99, rcx)), + "44887163", + "movb %r14b, 99(%rcx)", + )); + insns.push(( + Inst::mov_r_m(OperandSize::Size8, r15, Amode::imm_reg(99, r14)), + "45887E63", + "movb %r15b, 99(%r14)", + )); + + // ======================================================== + // Shift_R + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "D3E7", + "shll %cl, %edi, %edi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + r12, + w_r12, + ), + "41D3E4", + "shll %cl, %r12d, %r12d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "41C1E002", + "shll $2, %r8d, %r8d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 31 }), + r13, + w_r13, + ), + "41C1E51F", + "shll $31, %r13d, %r13d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + r13, + w_r13, + ), + "49D3E5", + "shlq %cl, %r13, %r13", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "48D3E7", + "shlq %cl, %rdi, %rdi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "49C1E002", + "shlq $2, %r8, %r8", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 3 }), + rbx, + w_rbx, + ), + "48C1E303", + "shlq $3, %rbx, %rbx", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 63 }), + r13, + w_r13, + ), + "49C1E53F", + "shlq $63, %r13, %r13", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "D3EF", + "shrl %cl, %edi, %edi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "41C1E802", + "shrl $2, %r8d, %r8d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 31 }), + r13, + w_r13, + ), + "41C1ED1F", + "shrl $31, %r13d, %r13d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "48D3EF", + "shrq %cl, %rdi, %rdi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "49C1E802", + "shrq $2, %r8, %r8", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightLogical, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 63 }), + r13, + w_r13, + ), + "49C1ED3F", + "shrq $63, %r13, %r13", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "D3FF", + "sarl %cl, %edi, %edi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "41C1F802", + "sarl $2, %r8d, %r8d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 31 }), + r13, + w_r13, + ), + "41C1FD1F", + "sarl $31, %r13d, %r13d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rdi, + w_rdi, + ), + "48D3FF", + "sarq %cl, %rdi, %rdi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 2 }), + r8, + w_r8, + ), + "49C1F802", + "sarq $2, %r8, %r8", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::ShiftRightArithmetic, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 63 }), + r13, + w_r13, + ), + "49C1FD3F", + "sarq $63, %r13, %r13", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::RotateLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + r8, + w_r8, + ), + "49D3C0", + "rolq %cl, %r8, %r8", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::RotateLeft, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 3 }), + r9, + w_r9, + ), + "41C1C103", + "roll $3, %r9d, %r9d", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size32, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rsi, + w_rsi, + ), + "D3CE", + "rorl %cl, %esi, %esi", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size64, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 5 }), + r15, + w_r15, + ), + "49C1CF05", + "rorq $5, %r15, %r15", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size8, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rsi, + w_rsi, + ), + "40D2CE", + "rorb %cl, %sil, %sil", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size8, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rax, + w_rax, + ), + "D2C8", + "rorb %cl, %al, %al", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size8, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 5 }), + r15, + w_r15, + ), + "41C0CF05", + "rorb $5, %r15b, %r15b", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size16, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Reg { reg: regs::rcx() }), + rsi, + w_rsi, + ), + "66D3CE", + "rorw %cl, %si, %si", + )); + insns.push(( + Inst::shift_r( + OperandSize::Size16, + ShiftKind::RotateRight, + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm: 5 }), + r15, + w_r15, + ), + "6641C1CF05", + "rorw $5, %r15w, %r15w", + )); + + // ======================================================== + // CmpRMIR + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, rdx, RegMemImm::reg(r15)), + "4C39FA", + "cmpq %r15, %rdx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, r8, RegMemImm::reg(rcx)), + "4939C8", + "cmpq %rcx, %r8", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, rsi, RegMemImm::reg(rcx)), + "4839CE", + "cmpq %rcx, %rsi", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size64, + rdx, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "483B5763", + "cmpq 99(%rdi), %rdx", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size64, + r8, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "4C3B4763", + "cmpq 99(%rdi), %r8", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size64, + rsi, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "483B7763", + "cmpq 99(%rdi), %rsi", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, rdx, RegMemImm::imm(76543210)), + "4881FAEAF48F04", + "cmpq $76543210, %rdx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, r8, RegMemImm::imm(-76543210i32 as u32)), + "4981F8160B70FB", + "cmpq $-76543210, %r8", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size64, rsi, RegMemImm::imm(76543210)), + "4881FEEAF48F04", + "cmpq $76543210, %rsi", + )); + // + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, rdx, RegMemImm::reg(r15)), + "4439FA", + "cmpl %r15d, %edx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, r8, RegMemImm::reg(rcx)), + "4139C8", + "cmpl %ecx, %r8d", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, rsi, RegMemImm::reg(rcx)), + "39CE", + "cmpl %ecx, %esi", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size32, + rdx, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "3B5763", + "cmpl 99(%rdi), %edx", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size32, + r8, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "443B4763", + "cmpl 99(%rdi), %r8d", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size32, + rsi, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "3B7763", + "cmpl 99(%rdi), %esi", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, rdx, RegMemImm::imm(76543210)), + "81FAEAF48F04", + "cmpl $76543210, %edx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, r8, RegMemImm::imm(-76543210i32 as u32)), + "4181F8160B70FB", + "cmpl $-76543210, %r8d", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size32, rsi, RegMemImm::imm(76543210)), + "81FEEAF48F04", + "cmpl $76543210, %esi", + )); + // + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, rdx, RegMemImm::reg(r15)), + "664439FA", + "cmpw %r15w, %dx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, r8, RegMemImm::reg(rcx)), + "664139C8", + "cmpw %cx, %r8w", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, rsi, RegMemImm::reg(rcx)), + "6639CE", + "cmpw %cx, %si", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size16, + rdx, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "663B5763", + "cmpw 99(%rdi), %dx", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size16, + r8, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "66443B4763", + "cmpw 99(%rdi), %r8w", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size16, + rsi, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "663B7763", + "cmpw 99(%rdi), %si", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, rdx, RegMemImm::imm(23210)), + "6681FAAA5A", + "cmpw $23210, %dx", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, r8, RegMemImm::imm(-7654i32 as u32)), + "664181F81AE2", + "cmpw $-7654, %r8w", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size16, rsi, RegMemImm::imm(7654)), + "6681FEE61D", + "cmpw $7654, %si", + )); + // + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::reg(r15)), + "4438FA", + "cmpb %r15b, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r8, RegMemImm::reg(rcx)), + "4138C8", + "cmpb %cl, %r8b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::reg(rcx)), + "4038CE", + "cmpb %cl, %sil", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size8, + rdx, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "3A5763", + "cmpb 99(%rdi), %dl", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size8, + r8, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "443A4763", + "cmpb 99(%rdi), %r8b", + )); + insns.push(( + Inst::cmp_rmi_r( + OperandSize::Size8, + rsi, + RegMemImm::mem(Amode::imm_reg(99, rdi)), + ), + "403A7763", + "cmpb 99(%rdi), %sil", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::imm(70)), + "80FA46", + "cmpb $70, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r8, RegMemImm::imm(-76i32 as u32)), + "4180F8B4", + "cmpb $-76, %r8b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::imm(76)), + "4080FE4C", + "cmpb $76, %sil", + )); + // Extra byte-cases (paranoia!) for cmp_rmi_r for first operand = R + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rbx, RegMemImm::reg(rax)), + "38C3", + "cmpb %al, %bl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rax, RegMemImm::reg(rbx)), + "38D8", + "cmpb %bl, %al", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::reg(rcx)), + "38CA", + "cmpb %cl, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::reg(rcx)), + "4038CE", + "cmpb %cl, %sil", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r10, RegMemImm::reg(rcx)), + "4138CA", + "cmpb %cl, %r10b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r14, RegMemImm::reg(rcx)), + "4138CE", + "cmpb %cl, %r14b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::reg(rbp)), + "4038EA", + "cmpb %bpl, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::reg(rbp)), + "4038EE", + "cmpb %bpl, %sil", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r10, RegMemImm::reg(rbp)), + "4138EA", + "cmpb %bpl, %r10b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r14, RegMemImm::reg(rbp)), + "4138EE", + "cmpb %bpl, %r14b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::reg(r9)), + "4438CA", + "cmpb %r9b, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::reg(r9)), + "4438CE", + "cmpb %r9b, %sil", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r10, RegMemImm::reg(r9)), + "4538CA", + "cmpb %r9b, %r10b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r14, RegMemImm::reg(r9)), + "4538CE", + "cmpb %r9b, %r14b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rdx, RegMemImm::reg(r13)), + "4438EA", + "cmpb %r13b, %dl", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, rsi, RegMemImm::reg(r13)), + "4438EE", + "cmpb %r13b, %sil", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r10, RegMemImm::reg(r13)), + "4538EA", + "cmpb %r13b, %r10b", + )); + insns.push(( + Inst::cmp_rmi_r(OperandSize::Size8, r14, RegMemImm::reg(r13)), + "4538EE", + "cmpb %r13b, %r14b", + )); + + // ======================================================== + // SetCC + insns.push((Inst::setcc(CC::O, w_rsi), "400F90C6", "seto %sil")); + insns.push((Inst::setcc(CC::NLE, w_rsi), "400F9FC6", "setnle %sil")); + insns.push((Inst::setcc(CC::Z, w_r14), "410F94C6", "setz %r14b")); + insns.push((Inst::setcc(CC::LE, w_r14), "410F9EC6", "setle %r14b")); + insns.push((Inst::setcc(CC::P, w_r9), "410F9AC1", "setp %r9b")); + insns.push((Inst::setcc(CC::NP, w_r8), "410F9BC0", "setnp %r8b")); + + // ======================================================== + // Bswap + insns.push(( + Inst::bswap(OperandSize::Size64, w_rax), + "480FC8", + "bswapq %rax, %rax", + )); + insns.push(( + Inst::bswap(OperandSize::Size64, w_r8), + "490FC8", + "bswapq %r8, %r8", + )); + insns.push(( + Inst::bswap(OperandSize::Size32, w_rax), + "0FC8", + "bswapl %eax, %eax", + )); + insns.push(( + Inst::bswap(OperandSize::Size64, w_rcx), + "480FC9", + "bswapq %rcx, %rcx", + )); + insns.push(( + Inst::bswap(OperandSize::Size32, w_rcx), + "0FC9", + "bswapl %ecx, %ecx", + )); + insns.push(( + Inst::bswap(OperandSize::Size64, w_r11), + "490FCB", + "bswapq %r11, %r11", + )); + insns.push(( + Inst::bswap(OperandSize::Size32, w_r11), + "410FCB", + "bswapl %r11d, %r11d", + )); + insns.push(( + Inst::bswap(OperandSize::Size64, w_r14), + "490FCE", + "bswapq %r14, %r14", + )); + insns.push(( + Inst::bswap(OperandSize::Size32, w_r14), + "410FCE", + "bswapl %r14d, %r14d", + )); + + // ======================================================== + // Cmove + insns.push(( + Inst::cmove(OperandSize::Size16, CC::O, RegMem::reg(rdi), w_rsi), + "660F40F7", + "cmovow %di, %si, %si", + )); + insns.push(( + Inst::cmove( + OperandSize::Size16, + CC::NO, + RegMem::mem(Amode::imm_reg_reg_shift( + 37, + Gpr::unwrap_new(rdi), + Gpr::unwrap_new(rsi), + 2, + )), + w_r15, + ), + "66440F417CB725", + "cmovnow 37(%rdi,%rsi,4), %r15w, %r15w", + )); + insns.push(( + Inst::cmove(OperandSize::Size32, CC::LE, RegMem::reg(rdi), w_rsi), + "0F4EF7", + "cmovlel %edi, %esi, %esi", + )); + insns.push(( + Inst::cmove( + OperandSize::Size32, + CC::NLE, + RegMem::mem(Amode::imm_reg(0, r15)), + w_rsi, + ), + "410F4F37", + "cmovnlel 0(%r15), %esi, %esi", + )); + insns.push(( + Inst::cmove(OperandSize::Size64, CC::Z, RegMem::reg(rdi), w_r14), + "4C0F44F7", + "cmovzq %rdi, %r14, %r14", + )); + insns.push(( + Inst::cmove( + OperandSize::Size64, + CC::NZ, + RegMem::mem(Amode::imm_reg(13, rdi)), + w_r14, + ), + "4C0F45770D", + "cmovnzq 13(%rdi), %r14, %r14", + )); + + // ======================================================== + // Push64 + insns.push((Inst::push64(RegMemImm::reg(rdi)), "57", "pushq %rdi")); + insns.push((Inst::push64(RegMemImm::reg(r8)), "4150", "pushq %r8")); + insns.push(( + Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(rsi), + Gpr::unwrap_new(rcx), + 3, + ))), + "FFB4CE41010000", + "pushq 321(%rsi,%rcx,8)", + )); + insns.push(( + Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(r9), + Gpr::unwrap_new(rbx), + 2, + ))), + "41FFB49941010000", + "pushq 321(%r9,%rbx,4)", + )); + insns.push((Inst::push64(RegMemImm::imm(0)), "6A00", "pushq $0")); + insns.push((Inst::push64(RegMemImm::imm(127)), "6A7F", "pushq $127")); + insns.push(( + Inst::push64(RegMemImm::imm(128)), + "6880000000", + "pushq $128", + )); + insns.push(( + Inst::push64(RegMemImm::imm(0x31415927)), + "6827594131", + "pushq $826366247", + )); + insns.push(( + Inst::push64(RegMemImm::imm(-128i32 as u32)), + "6A80", + "pushq $-128", + )); + insns.push(( + Inst::push64(RegMemImm::imm(-129i32 as u32)), + "687FFFFFFF", + "pushq $-129", + )); + insns.push(( + Inst::push64(RegMemImm::imm(-0x75c4e8a1i32 as u32)), + "685F173B8A", + "pushq $-1975838881", + )); + + // ======================================================== + // Pop64 + insns.push((Inst::pop64(w_rax), "58", "popq %rax")); + insns.push((Inst::pop64(w_rdi), "5F", "popq %rdi")); + insns.push((Inst::pop64(w_r8), "4158", "popq %r8")); + insns.push((Inst::pop64(w_r15), "415F", "popq %r15")); + + // ======================================================== + // CallKnown + insns.push(( + Inst::call_known(Box::new(CallInfo::empty( + ExternalName::User(UserExternalNameRef::new(0)), + CallConv::SystemV, + ))), + "E800000000", + "call User(userextname0)", + )); + + // ======================================================== + // CallUnknown + fn call_unknown(rm: RegMem) -> Inst { + Inst::call_unknown(Box::new(CallInfo::empty(rm, CallConv::SystemV))) + } + + insns.push((call_unknown(RegMem::reg(rbp)), "FFD5", "call *%rbp")); + insns.push((call_unknown(RegMem::reg(r11)), "41FFD3", "call *%r11")); + insns.push(( + call_unknown(RegMem::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(rsi), + Gpr::unwrap_new(rcx), + 3, + ))), + "FF94CE41010000", + "call *321(%rsi,%rcx,8)", + )); + insns.push(( + call_unknown(RegMem::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(r10), + Gpr::unwrap_new(rdx), + 2, + ))), + "41FF949241010000", + "call *321(%r10,%rdx,4)", + )); + + // ======================================================== + // LoadExtName + // N.B.: test harness below sets is_pic. + insns.push(( + Inst::LoadExtName { + dst: Writable::from_reg(r11), + name: Box::new(ExternalName::User(UserExternalNameRef::new(0))), + offset: 0, + distance: RelocDistance::Far, + }, + "4C8B1D00000000", + "load_ext_name userextname0+0, %r11", + )); + insns.push(( + Inst::LoadExtName { + dst: Writable::from_reg(r11), + name: Box::new(ExternalName::User(UserExternalNameRef::new(0))), + offset: 0x12345678, + distance: RelocDistance::Far, + }, + "4C8B1D000000004981C378563412", + "load_ext_name userextname0+305419896, %r11", + )); + insns.push(( + Inst::LoadExtName { + dst: Writable::from_reg(r11), + name: Box::new(ExternalName::User(UserExternalNameRef::new(0))), + offset: -0x12345678, + distance: RelocDistance::Far, + }, + "4C8B1D000000004981EB78563412", + "load_ext_name userextname0+-305419896, %r11", + )); + + // ======================================================== + // Ret + insns.push((Inst::ret(0), "C3", "ret")); + insns.push((Inst::ret(8), "C20800", "ret 8")); + + // ======================================================== + // JmpKnown skipped for now + + // ======================================================== + // JmpCondSymm isn't a real instruction + + // ======================================================== + // JmpCond skipped for now + + // ======================================================== + // JmpCondCompound isn't a real instruction + + // ======================================================== + // JmpUnknown + insns.push((Inst::jmp_unknown(RegMem::reg(rbp)), "FFE5", "jmp *%rbp")); + insns.push(( + Inst::jmp_unknown(RegMem::reg(r11)), + "41FFE3", + "jmp *%r11", + )); + insns.push(( + Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(rsi), + Gpr::unwrap_new(rcx), + 3, + ))), + "FFA4CE41010000", + "jmp *321(%rsi,%rcx,8)", + )); + insns.push(( + Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(r10), + Gpr::unwrap_new(rdx), + 2, + ))), + "41FFA49241010000", + "jmp *321(%r10,%rdx,4)", + )); + + // ======================================================== + // XMM FMA + + insns.push(( + Inst::xmm_rmr_vex3(AvxOpcode::Vfmadd213ss, RegMem::reg(xmm2), xmm1, w_xmm0), + "C4E271A9C2", + "vfmadd213ss %xmm0, %xmm1, %xmm2, %xmm0", + )); + + insns.push(( + Inst::xmm_rmr_vex3(AvxOpcode::Vfmadd213sd, RegMem::reg(xmm5), xmm4, w_xmm3), + "C4E2D9A9DD", + "vfmadd213sd %xmm3, %xmm4, %xmm5, %xmm3", + )); + + insns.push(( + Inst::xmm_rmr_vex3(AvxOpcode::Vfmadd213ps, RegMem::reg(xmm2), xmm1, w_xmm0), + "C4E271A8C2", + "vfmadd213ps %xmm0, %xmm1, %xmm2, %xmm0", + )); + + insns.push(( + Inst::xmm_rmr_vex3(AvxOpcode::Vfmadd213pd, RegMem::reg(xmm5), xmm4, w_xmm3), + "C4E2D9A8DD", + "vfmadd213pd %xmm3, %xmm4, %xmm5, %xmm3", + )); + + // ======================================================== + // XMM_CMP_RM_R + + insns.push(( + Inst::xmm_cmp_rm_r(SseOpcode::Ucomiss, xmm2, RegMem::reg(xmm1)), + "0F2ED1", + "ucomiss %xmm1, %xmm2", + )); + + insns.push(( + Inst::xmm_cmp_rm_r(SseOpcode::Ucomiss, xmm9, RegMem::reg(xmm0)), + "440F2EC8", + "ucomiss %xmm0, %xmm9", + )); + + insns.push(( + Inst::xmm_cmp_rm_r(SseOpcode::Ucomisd, xmm4, RegMem::reg(xmm13)), + "66410F2EE5", + "ucomisd %xmm13, %xmm4", + )); + + insns.push(( + Inst::xmm_cmp_rm_r(SseOpcode::Ucomisd, xmm12, RegMem::reg(xmm11)), + "66450F2EE3", + "ucomisd %xmm11, %xmm12", + )); + + // ======================================================== + // XMM_RM_R: float binary ops + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Addss, RegMem::reg(xmm1), w_xmm0), + "F30F58C1", + "addss %xmm0, %xmm1, %xmm0", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Addss, RegMem::reg(xmm11), w_xmm13), + "F3450F58EB", + "addss %xmm13, %xmm11, %xmm13", + )); + insns.push(( + Inst::xmm_rm_r( + SseOpcode::Addss, + RegMem::mem(Amode::imm_reg_reg_shift( + 123, + Gpr::unwrap_new(r10), + Gpr::unwrap_new(rdx), + 2, + )), + w_xmm0, + ), + "F3410F5844927B", + "addss %xmm0, 123(%r10,%rdx,4), %xmm0", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Addsd, RegMem::reg(xmm15), w_xmm4), + "F2410F58E7", + "addsd %xmm4, %xmm15, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Subss, RegMem::reg(xmm0), w_xmm1), + "F30F5CC8", + "subss %xmm1, %xmm0, %xmm1", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Subss, RegMem::reg(xmm12), w_xmm1), + "F3410F5CCC", + "subss %xmm1, %xmm12, %xmm1", + )); + insns.push(( + Inst::xmm_rm_r( + SseOpcode::Subss, + RegMem::mem(Amode::imm_reg_reg_shift( + 321, + Gpr::unwrap_new(r10), + Gpr::unwrap_new(rax), + 3, + )), + w_xmm10, + ), + "F3450F5C94C241010000", + "subss %xmm10, 321(%r10,%rax,8), %xmm10", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Subsd, RegMem::reg(xmm5), w_xmm14), + "F2440F5CF5", + "subsd %xmm14, %xmm5, %xmm14", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Mulss, RegMem::reg(xmm5), w_xmm4), + "F30F59E5", + "mulss %xmm4, %xmm5, %xmm4", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Mulsd, RegMem::reg(xmm5), w_xmm4), + "F20F59E5", + "mulsd %xmm4, %xmm5, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Divss, RegMem::reg(xmm8), w_xmm7), + "F3410F5EF8", + "divss %xmm7, %xmm8, %xmm7", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Divsd, RegMem::reg(xmm5), w_xmm4), + "F20F5EE5", + "divsd %xmm4, %xmm5, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Andps, RegMem::reg(xmm3), w_xmm12), + "440F54E3", + "andps %xmm12, %xmm3, %xmm12", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Andnps, RegMem::reg(xmm4), w_xmm11), + "440F55DC", + "andnps %xmm11, %xmm4, %xmm11", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Orps, RegMem::reg(xmm1), w_xmm15), + "440F56F9", + "orps %xmm15, %xmm1, %xmm15", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Orps, RegMem::reg(xmm5), w_xmm4), + "0F56E5", + "orps %xmm4, %xmm5, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r_blend(SseOpcode::Blendvpd, RegMem::reg(xmm15), w_xmm4), + "66410F3815E7", + "blendvpd %xmm4, %xmm15, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r_blend(SseOpcode::Blendvps, RegMem::reg(xmm2), w_xmm3), + "660F3814DA", + "blendvps %xmm3, %xmm2, %xmm3", + )); + + insns.push(( + Inst::xmm_rm_r_blend(SseOpcode::Pblendvb, RegMem::reg(xmm12), w_xmm13), + "66450F3810EC", + "pblendvb %xmm13, %xmm12, %xmm13", + )); + + // ======================================================== + // XMM_RM_R: Integer Packed + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddb, RegMem::reg(xmm9), w_xmm5), + "66410FFCE9", + "paddb %xmm5, %xmm9, %xmm5", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddw, RegMem::reg(xmm7), w_xmm6), + "660FFDF7", + "paddw %xmm6, %xmm7, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddd, RegMem::reg(xmm12), w_xmm13), + "66450FFEEC", + "paddd %xmm13, %xmm12, %xmm13", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddq, RegMem::reg(xmm1), w_xmm8), + "66440FD4C1", + "paddq %xmm8, %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddsb, RegMem::reg(xmm9), w_xmm5), + "66410FECE9", + "paddsb %xmm5, %xmm9, %xmm5", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddsw, RegMem::reg(xmm7), w_xmm6), + "660FEDF7", + "paddsw %xmm6, %xmm7, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddusb, RegMem::reg(xmm12), w_xmm13), + "66450FDCEC", + "paddusb %xmm13, %xmm12, %xmm13", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Paddusw, RegMem::reg(xmm1), w_xmm8), + "66440FDDC1", + "paddusw %xmm8, %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubsb, RegMem::reg(xmm9), w_xmm5), + "66410FE8E9", + "psubsb %xmm5, %xmm9, %xmm5", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubsw, RegMem::reg(xmm7), w_xmm6), + "660FE9F7", + "psubsw %xmm6, %xmm7, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubusb, RegMem::reg(xmm12), w_xmm13), + "66450FD8EC", + "psubusb %xmm13, %xmm12, %xmm13", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubusw, RegMem::reg(xmm1), w_xmm8), + "66440FD9C1", + "psubusw %xmm8, %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pavgb, RegMem::reg(xmm12), w_xmm13), + "66450FE0EC", + "pavgb %xmm13, %xmm12, %xmm13", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pavgw, RegMem::reg(xmm1), w_xmm8), + "66440FE3C1", + "pavgw %xmm8, %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubb, RegMem::reg(xmm5), w_xmm9), + "66440FF8CD", + "psubb %xmm9, %xmm5, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubw, RegMem::reg(xmm6), w_xmm7), + "660FF9FE", + "psubw %xmm7, %xmm6, %xmm7", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubd, RegMem::reg(xmm13), w_xmm12), + "66450FFAE5", + "psubd %xmm12, %xmm13, %xmm12", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Psubq, RegMem::reg(xmm8), w_xmm1), + "66410FFBC8", + "psubq %xmm1, %xmm8, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmuldq, RegMem::reg(xmm4), w_xmm15), + "66440F3828FC", + "pmuldq %xmm15, %xmm4, %xmm15", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmulhw, RegMem::reg(xmm9), w_xmm1), + "66410FE5C9", + "pmulhw %xmm1, %xmm9, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmulhuw, RegMem::reg(xmm7), w_xmm9), + "66440FE4CF", + "pmulhuw %xmm9, %xmm7, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmulld, RegMem::reg(xmm15), w_xmm6), + "66410F3840F7", + "pmulld %xmm6, %xmm15, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmullw, RegMem::reg(xmm14), w_xmm1), + "66410FD5CE", + "pmullw %xmm1, %xmm14, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r_evex(Avx512Opcode::Vpmullq, xmm10, RegMem::reg(xmm14), w_xmm1), + "62D2AD0840CE", + "vpmullq %xmm14, %xmm10, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r_evex(Avx512Opcode::Vpsraq, xmm10, RegMem::reg(xmm14), w_xmm1), + "62D1AD08E2CE", + "vpsraq %xmm14, %xmm10, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r_evex3( + Avx512Opcode::Vpermi2b, + xmm1, + xmm10, + RegMem::reg(xmm14), + w_xmm1, + ), + "62D22D0875CE", + "vpermi2b %xmm14, %xmm10, %xmm1, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r_evex3( + Avx512Opcode::Vpermi2b, + xmm2, + xmm0, + RegMem::reg(xmm1), + w_xmm2, + ), + "62F27D0875D1", + "vpermi2b %xmm1, %xmm0, %xmm2, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmuludq, RegMem::reg(xmm8), w_xmm9), + "66450FF4C8", + "pmuludq %xmm9, %xmm8, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaddwd, RegMem::reg(xmm8), w_xmm1), + "66410FF5C8", + "pmaddwd %xmm1, %xmm8, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxsb, RegMem::reg(xmm15), w_xmm6), + "66410F383CF7", + "pmaxsb %xmm6, %xmm15, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxsw, RegMem::reg(xmm15), w_xmm6), + "66410FEEF7", + "pmaxsw %xmm6, %xmm15, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxsd, RegMem::reg(xmm15), w_xmm6), + "66410F383DF7", + "pmaxsd %xmm6, %xmm15, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxub, RegMem::reg(xmm14), w_xmm1), + "66410FDECE", + "pmaxub %xmm1, %xmm14, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxuw, RegMem::reg(xmm14), w_xmm1), + "66410F383ECE", + "pmaxuw %xmm1, %xmm14, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pmaxud, RegMem::reg(xmm14), w_xmm1), + "66410F383FCE", + "pmaxud %xmm1, %xmm14, %xmm1", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminsb, RegMem::reg(xmm8), w_xmm9), + "66450F3838C8", + "pminsb %xmm9, %xmm8, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminsw, RegMem::reg(xmm8), w_xmm9), + "66450FEAC8", + "pminsw %xmm9, %xmm8, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminsd, RegMem::reg(xmm8), w_xmm9), + "66450F3839C8", + "pminsd %xmm9, %xmm8, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminub, RegMem::reg(xmm3), w_xmm2), + "660FDAD3", + "pminub %xmm2, %xmm3, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminuw, RegMem::reg(xmm3), w_xmm2), + "660F383AD3", + "pminuw %xmm2, %xmm3, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pminud, RegMem::reg(xmm3), w_xmm2), + "660F383BD3", + "pminud %xmm2, %xmm3, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pxor, RegMem::reg(xmm11), w_xmm2), + "66410FEFD3", + "pxor %xmm2, %xmm11, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Pshufb, RegMem::reg(xmm11), w_xmm2), + "66410F3800D3", + "pshufb %xmm2, %xmm11, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Packssdw, RegMem::reg(xmm11), w_xmm12), + "66450F6BE3", + "packssdw %xmm12, %xmm11, %xmm12", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Packsswb, RegMem::reg(xmm11), w_xmm2), + "66410F63D3", + "packsswb %xmm2, %xmm11, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Packusdw, RegMem::reg(xmm13), w_xmm6), + "66410F382BF5", + "packusdw %xmm6, %xmm13, %xmm6", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Packuswb, RegMem::reg(xmm9), w_xmm4), + "66410F67E1", + "packuswb %xmm4, %xmm9, %xmm4", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Punpckhbw, RegMem::reg(xmm3), w_xmm2), + "660F68D3", + "punpckhbw %xmm2, %xmm3, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Punpckhwd, RegMem::reg(xmm13), w_xmm2), + "66410F69D5", + "punpckhwd %xmm2, %xmm13, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Punpcklbw, RegMem::reg(xmm1), w_xmm8), + "66440F60C1", + "punpcklbw %xmm8, %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Punpcklwd, RegMem::reg(xmm11), w_xmm8), + "66450F61C3", + "punpcklwd %xmm8, %xmm11, %xmm8", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Unpcklps, RegMem::reg(xmm11), w_xmm2), + "410F14D3", + "unpcklps %xmm2, %xmm11, %xmm2", + )); + + // ======================================================== + // XMM_RM_R: Integer Conversion + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvtdq2ps, RegMem::reg(xmm1), w_xmm8), + "440F5BC1", + "cvtdq2ps %xmm1, %xmm8", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvttpd2dq, RegMem::reg(xmm15), w_xmm7), + "66410FE6FF", + "cvttpd2dq %xmm15, %xmm7", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvttps2dq, RegMem::reg(xmm9), w_xmm8), + "F3450F5BC1", + "cvttps2dq %xmm9, %xmm8", + )); + + // XMM_Mov_R_M: float stores + insns.push(( + Inst::xmm_mov_r_m(SseOpcode::Movss, xmm15, Amode::imm_reg(128, r12)), + "F3450F11BC2480000000", + "movss %xmm15, 128(%r12)", + )); + insns.push(( + Inst::xmm_mov_r_m(SseOpcode::Movsd, xmm1, Amode::imm_reg(0, rsi)), + "F20F110E", + "movsd %xmm1, 0(%rsi)", + )); + + // ======================================================== + // XMM_MOV: Packed Move + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxbd, RegMem::reg(xmm6), w_xmm8), + "66440F3821C6", + "pmovsxbd %xmm6, %xmm8", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxbw, RegMem::reg(xmm9), w_xmm10), + "66450F3820D1", + "pmovsxbw %xmm9, %xmm10", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxbq, RegMem::reg(xmm1), w_xmm1), + "660F3822C9", + "pmovsxbq %xmm1, %xmm1", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxwd, RegMem::reg(xmm13), w_xmm10), + "66450F3823D5", + "pmovsxwd %xmm13, %xmm10", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxwq, RegMem::reg(xmm12), w_xmm12), + "66450F3824E4", + "pmovsxwq %xmm12, %xmm12", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovsxdq, RegMem::reg(xmm10), w_xmm8), + "66450F3825C2", + "pmovsxdq %xmm10, %xmm8", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxbd, RegMem::reg(xmm5), w_xmm6), + "660F3831F5", + "pmovzxbd %xmm5, %xmm6", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxbw, RegMem::reg(xmm5), w_xmm13), + "66440F3830ED", + "pmovzxbw %xmm5, %xmm13", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxbq, RegMem::reg(xmm10), w_xmm11), + "66450F3832DA", + "pmovzxbq %xmm10, %xmm11", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxwd, RegMem::reg(xmm2), w_xmm10), + "66440F3833D2", + "pmovzxwd %xmm2, %xmm10", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxwq, RegMem::reg(xmm7), w_xmm4), + "660F3834E7", + "pmovzxwq %xmm7, %xmm4", + )); + + insns.push(( + Inst::xmm_mov(SseOpcode::Pmovzxdq, RegMem::reg(xmm3), w_xmm4), + "660F3835E3", + "pmovzxdq %xmm3, %xmm4", + )); + + // XmmUnary: moves and unary float ops + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Movss, RegMem::reg(xmm13), w_xmm2), + "F3410F10D5", + "movss %xmm13, %xmm2", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Movsd, RegMem::reg(xmm0), w_xmm1), + "F20F10C8", + "movsd %xmm0, %xmm1", + )); + insns.push(( + Inst::xmm_unary_rm_r( + SseOpcode::Movsd, + RegMem::mem(Amode::imm_reg(0, rsi)), + w_xmm2, + ), + "F20F1016", + "movsd 0(%rsi), %xmm2", + )); + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Movsd, RegMem::reg(xmm14), w_xmm3), + "F2410F10DE", + "movsd %xmm14, %xmm3", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Movaps, RegMem::reg(xmm5), w_xmm14), + "440F28F5", + "movaps %xmm5, %xmm14", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Sqrtss, RegMem::reg(xmm7), w_xmm8), + "F3440F51C7", + "sqrtss %xmm8, %xmm7, %xmm8", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Sqrtsd, RegMem::reg(xmm1), w_xmm2), + "F20F51D1", + "sqrtsd %xmm2, %xmm1, %xmm2", + )); + + insns.push(( + Inst::xmm_rm_r(SseOpcode::Cvtss2sd, RegMem::reg(xmm0), w_xmm1), + "F30F5AC8", + "cvtss2sd %xmm1, %xmm0, %xmm1", + )); + insns.push(( + Inst::xmm_rm_r(SseOpcode::Cvtsd2ss, RegMem::reg(xmm1), w_xmm0), + "F20F5AC1", + "cvtsd2ss %xmm0, %xmm1, %xmm0", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Pabsb, RegMem::reg(xmm2), w_xmm1), + "660F381CCA", + "pabsb %xmm2, %xmm1", + )); + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Pabsw, RegMem::reg(xmm0), w_xmm0), + "660F381DC0", + "pabsw %xmm0, %xmm0", + )); + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Pabsd, RegMem::reg(xmm10), w_xmm11), + "66450F381EDA", + "pabsd %xmm10, %xmm11", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvtdq2pd, RegMem::reg(xmm2), w_xmm8), + "F3440FE6C2", + "cvtdq2pd %xmm2, %xmm8", + )); + + insns.push(( + Inst::xmm_unary_rm_r_evex(Avx512Opcode::Vpabsq, RegMem::reg(xmm2), w_xmm8), + "6272FD081FC2", + "vpabsq %xmm2, %xmm8", + )); + + insns.push(( + Inst::xmm_unary_rm_r_evex(Avx512Opcode::Vcvtudq2ps, RegMem::reg(xmm2), w_xmm8), + "62717F087AC2", + "vcvtudq2ps %xmm2, %xmm8", + )); + + insns.push(( + Inst::xmm_unary_rm_r_evex(Avx512Opcode::Vpopcntb, RegMem::reg(xmm2), w_xmm8), + "62727D0854C2", + "vpopcntb %xmm2, %xmm8", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvtpd2ps, RegMem::reg(xmm7), w_xmm7), + "660F5AFF", + "cvtpd2ps %xmm7, %xmm7", + )); + + insns.push(( + Inst::xmm_unary_rm_r(SseOpcode::Cvtps2pd, RegMem::reg(xmm11), w_xmm9), + "450F5ACB", + "cvtps2pd %xmm11, %xmm9", + )); + + // Xmm to int conversions, and conversely. + + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Movd, xmm0, w_rsi, OperandSize::Size32), + "660F7EC6", + "movd %xmm0, %esi", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Movq, xmm2, w_rdi, OperandSize::Size64), + "66480F7ED7", + "movq %xmm2, %rdi", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Cvttss2si, xmm0, w_rsi, OperandSize::Size32), + "F30F2CF0", + "cvttss2si %xmm0, %esi", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Cvttss2si, xmm0, w_rdi, OperandSize::Size64), + "F3480F2CF8", + "cvttss2si %xmm0, %rdi", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Cvttsd2si, xmm0, w_rax, OperandSize::Size32), + "F20F2CC0", + "cvttsd2si %xmm0, %eax", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Cvttsd2si, xmm0, w_r15, OperandSize::Size64), + "F24C0F2CF8", + "cvttsd2si %xmm0, %r15", + )); + + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Pmovmskb, xmm10, w_rax, OperandSize::Size32), + "66410FD7C2", + "pmovmskb %xmm10, %eax", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Movmskps, xmm2, w_rax, OperandSize::Size32), + "0F50C2", + "movmskps %xmm2, %eax", + )); + insns.push(( + Inst::xmm_to_gpr(SseOpcode::Movmskpd, xmm0, w_rcx, OperandSize::Size32), + "660F50C8", + "movmskpd %xmm0, %ecx", + )); + + insns.push(( + Inst::gpr_to_xmm( + SseOpcode::Movd, + RegMem::reg(rax), + OperandSize::Size32, + w_xmm15, + ), + "66440F6EF8", + "movd %eax, %xmm15", + )); + insns.push(( + Inst::gpr_to_xmm( + SseOpcode::Movd, + RegMem::mem(Amode::imm_reg(2, r10)), + OperandSize::Size32, + w_xmm9, + ), + "66450F6E4A02", + "movd 2(%r10), %xmm9", + )); + insns.push(( + Inst::gpr_to_xmm( + SseOpcode::Movd, + RegMem::reg(rsi), + OperandSize::Size32, + w_xmm1, + ), + "660F6ECE", + "movd %esi, %xmm1", + )); + insns.push(( + Inst::gpr_to_xmm( + SseOpcode::Movq, + RegMem::reg(rdi), + OperandSize::Size64, + w_xmm15, + ), + "664C0F6EFF", + "movq %rdi, %xmm15", + )); + + // ======================================================== + // XmmRmi + insns.push(( + Inst::xmm_rmi_reg(SseOpcode::Psraw, RegMemImm::reg(xmm10), w_xmm1), + "66410FE1CA", + "psraw %xmm1, %xmm10, %xmm1", + )); + insns.push(( + Inst::xmm_rmi_reg(SseOpcode::Pslld, RegMemImm::imm(31), w_xmm1), + "660F72F11F", + "pslld %xmm1, $31, %xmm1", + )); + insns.push(( + Inst::xmm_rmi_reg(SseOpcode::Psrlq, RegMemImm::imm(1), w_xmm3), + "660F73D301", + "psrlq %xmm3, $1, %xmm3", + )); + + // ======================================================== + // XmmRmRImm + insns.push(( + Inst::xmm_rm_r_imm( + SseOpcode::Cmppd, + RegMem::reg(xmm5), + w_xmm1, + 2, + OperandSize::Size32, + ), + "660FC2CD02", + "cmppd $2, %xmm1, %xmm5, %xmm1", + )); + insns.push(( + Inst::xmm_rm_r_imm( + SseOpcode::Cmpps, + RegMem::reg(xmm15), + w_xmm7, + 0, + OperandSize::Size32, + ), + "410FC2FF00", + "cmpps $0, %xmm7, %xmm15, %xmm7", + )); + insns.push(( + Inst::xmm_rm_r_imm( + SseOpcode::Palignr, + RegMem::reg(xmm1), + w_xmm9, + 3, + OperandSize::Size32, + ), + "66440F3A0FC903", + "palignr $3, %xmm9, %xmm1, %xmm9", + )); + + insns.push(( + Inst::xmm_rm_r_imm( + SseOpcode::Shufps, + RegMem::reg(xmm1), + w_xmm10, + 136, + OperandSize::Size32, + ), + "440FC6D188", + "shufps $136, %xmm10, %xmm1, %xmm10", + )); + + insns.push(( + Inst::xmm_unary_rm_r_imm(SseOpcode::Roundps, RegMem::reg(xmm7), w_xmm8, 3), + "66440F3A08C703", + "roundps $3, %xmm7, %xmm8", + )); + insns.push(( + Inst::xmm_unary_rm_r_imm(SseOpcode::Roundpd, RegMem::reg(xmm10), w_xmm7, 2), + "66410F3A09FA02", + "roundpd $2, %xmm10, %xmm7", + )); + insns.push(( + Inst::xmm_unary_rm_r_imm(SseOpcode::Roundps, RegMem::reg(xmm4), w_xmm8, 1), + "66440F3A08C401", + "roundps $1, %xmm4, %xmm8", + )); + insns.push(( + Inst::xmm_unary_rm_r_imm(SseOpcode::Roundpd, RegMem::reg(xmm15), w_xmm15, 0), + "66450F3A09FF00", + "roundpd $0, %xmm15, %xmm15", + )); + + // ======================================================== + // XmmRmiRVex + + // Standard instruction w/ XmmMemImm::Reg operand. + insns.push(( + Inst::XmmRmiRVex { + op: AvxOpcode::Vpmaxub, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm1), + src2: XmmMemImm::unwrap_new(xmm12.into()), + }, + "C44171DEEC", + "vpmaxub %xmm1, %xmm12, %xmm13", + )); + + // Standard instruction w/ XmmMemImm::Mem operand. + insns.push(( + Inst::XmmRmiRVex { + op: AvxOpcode::Vpmaxub, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm1), + src2: XmmMemImm::unwrap_new(RegMemImm::Mem { + addr: Amode::ImmReg { + simm32: 10, + base: rax, + flags: MemFlags::trusted(), + } + .into(), + }), + }, + "C571DE680A", + "vpmaxub %xmm1, 10(%rax), %xmm13", + )); + + // When there's an immediate. + insns.push(( + Inst::XmmRmiRVex { + op: AvxOpcode::Vpsrlw, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm1), + src2: XmmMemImm::unwrap_new(RegMemImm::Imm { simm32: 36 }), + }, + "C59171D124", + "vpsrlw %xmm1, $36, %xmm13", + )); + + // Certain commutative ops get their operands swapped to avoid relying on an + // extra prefix byte, when possible. Note that these two instructions encode + // to the same bytes, and are 4-byte encodings rather than 5-byte encodings. + insns.push(( + Inst::XmmRmiRVex { + op: AvxOpcode::Vmulsd, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm1), + src2: XmmMemImm::unwrap_new(xmm12.into()), + }, + "C51B59E9", + "vmulsd %xmm1, %xmm12, %xmm13", + )); + insns.push(( + Inst::XmmRmiRVex { + op: AvxOpcode::Vmulsd, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm12), + src2: XmmMemImm::unwrap_new(xmm1.into()), + }, + "C51B59E9", + "vmulsd %xmm12, %xmm1, %xmm13", + )); + + // ======================================================== + // XmmRmRImmVex + insns.push(( + Inst::XmmVexPinsr { + op: AvxOpcode::Vpinsrb, + dst: Writable::from_reg(Xmm::unwrap_new(xmm13)), + src1: Xmm::unwrap_new(xmm14), + src2: GprMem::unwrap_new(RegMem::reg(r15)), + imm: 2, + }, + "C4430920EF02", + "vpinsrb $2, %xmm14, %r15, %xmm13", + )); + + // ======================================================== + // Pertaining to atomics. + let am1: SyntheticAmode = + Amode::imm_reg_reg_shift(321, Gpr::unwrap_new(r10), Gpr::unwrap_new(rdx), 2).into(); + // `am2` doesn't contribute any 1 bits to the rex prefix, so we must use it when testing + // for retention of the apparently-redundant rex prefix in the 8-bit case. + let am2: SyntheticAmode = + Amode::imm_reg_reg_shift(-12345i32, Gpr::unwrap_new(rcx), Gpr::unwrap_new(rsi), 3).into(); + // Use `r9` with a 0 offset. + let am3: SyntheticAmode = Amode::imm_reg(0, r9).into(); + + // A general 8-bit case. + insns.push(( + Inst::LockCmpxchg { + ty: types::I8, + mem: am1, + replacement: rbx, + expected: rax, + dst_old: w_rax, + }, + "F0410FB09C9241010000", + "lock cmpxchgb %bl, 321(%r10,%rdx,4), expected=%al, dst_old=%al", + )); + // Check redundant rex retention in 8-bit cases. + insns.push(( + Inst::LockCmpxchg { + ty: types::I8, + mem: am2.clone(), + replacement: rdx, + expected: rax, + dst_old: w_rax, + }, + "F00FB094F1C7CFFFFF", + "lock cmpxchgb %dl, -12345(%rcx,%rsi,8), expected=%al, dst_old=%al", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I8, + mem: am2.clone(), + replacement: rsi, + expected: rax, + dst_old: w_rax, + }, + "F0400FB0B4F1C7CFFFFF", + "lock cmpxchgb %sil, -12345(%rcx,%rsi,8), expected=%al, dst_old=%al", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I8, + mem: am2.clone(), + replacement: r10, + expected: rax, + dst_old: w_rax, + }, + "F0440FB094F1C7CFFFFF", + "lock cmpxchgb %r10b, -12345(%rcx,%rsi,8), expected=%al, dst_old=%al", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I8, + mem: am2.clone(), + replacement: r15, + expected: rax, + dst_old: w_rax, + }, + "F0440FB0BCF1C7CFFFFF", + "lock cmpxchgb %r15b, -12345(%rcx,%rsi,8), expected=%al, dst_old=%al", + )); + // 16 bit cases + insns.push(( + Inst::LockCmpxchg { + ty: types::I16, + mem: am2.clone(), + replacement: rsi, + expected: rax, + dst_old: w_rax, + }, + "66F00FB1B4F1C7CFFFFF", + "lock cmpxchgw %si, -12345(%rcx,%rsi,8), expected=%ax, dst_old=%ax", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I16, + mem: am2.clone(), + replacement: r10, + expected: rax, + dst_old: w_rax, + }, + "66F0440FB194F1C7CFFFFF", + "lock cmpxchgw %r10w, -12345(%rcx,%rsi,8), expected=%ax, dst_old=%ax", + )); + // 32 bit cases + insns.push(( + Inst::LockCmpxchg { + ty: types::I32, + mem: am2.clone(), + replacement: rsi, + expected: rax, + dst_old: w_rax, + }, + "F00FB1B4F1C7CFFFFF", + "lock cmpxchgl %esi, -12345(%rcx,%rsi,8), expected=%eax, dst_old=%eax", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I32, + mem: am2.clone(), + replacement: r10, + expected: rax, + dst_old: w_rax, + }, + "F0440FB194F1C7CFFFFF", + "lock cmpxchgl %r10d, -12345(%rcx,%rsi,8), expected=%eax, dst_old=%eax", + )); + // 64 bit cases + insns.push(( + Inst::LockCmpxchg { + ty: types::I64, + mem: am2.clone(), + replacement: rsi, + expected: rax, + dst_old: w_rax, + }, + "F0480FB1B4F1C7CFFFFF", + "lock cmpxchgq %rsi, -12345(%rcx,%rsi,8), expected=%rax, dst_old=%rax", + )); + insns.push(( + Inst::LockCmpxchg { + ty: types::I64, + mem: am2.clone(), + replacement: r10, + expected: rax, + dst_old: w_rax, + }, + "F04C0FB194F1C7CFFFFF", + "lock cmpxchgq %r10, -12345(%rcx,%rsi,8), expected=%rax, dst_old=%rax", + )); + + insns.push(( + Inst::LockCmpxchg16b { + mem: Box::new(am2.clone()), + replacement_low: rbx, + replacement_high: rcx, + expected_low: rax, + expected_high: rdx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "F0480FC78CF1C7CFFFFF", + "lock cmpxchg16b -12345(%rcx,%rsi,8), replacement=%rcx:%rbx, expected=%rdx:%rax, dst_old=%rdx:%rax", + )); + + // LockXadd + insns.push(( + Inst::LockXadd { + size: OperandSize::Size64, + operand: r10, + mem: am3.clone(), + dst_old: w_r10, + }, + "F04D0FC111", + "lock xaddq %r10, 0(%r9), dst_old=%r10", + )); + insns.push(( + Inst::LockXadd { + size: OperandSize::Size32, + operand: r11, + mem: am3.clone(), + dst_old: w_r11, + }, + "F0450FC119", + "lock xaddl %r11d, 0(%r9), dst_old=%r11d", + )); + insns.push(( + Inst::LockXadd { + size: OperandSize::Size16, + operand: r12, + mem: am3.clone(), + dst_old: w_r12, + }, + "66F0450FC121", + "lock xaddw %r12w, 0(%r9), dst_old=%r12w", + )); + insns.push(( + Inst::LockXadd { + size: OperandSize::Size8, + operand: r13, + mem: am3.clone(), + dst_old: w_r13, + }, + "F0450FC029", + "lock xaddb %r13b, 0(%r9), dst_old=%r13b", + )); + + // Xchg + insns.push(( + Inst::Xchg { + size: OperandSize::Size64, + operand: r10, + mem: am3.clone(), + dst_old: w_r10, + }, + "4D8711", + "xchgq %r10, 0(%r9), dst_old=%r10", + )); + insns.push(( + Inst::Xchg { + size: OperandSize::Size32, + operand: r11, + mem: am3.clone(), + dst_old: w_r11, + }, + "458719", + "xchgl %r11d, 0(%r9), dst_old=%r11d", + )); + insns.push(( + Inst::Xchg { + size: OperandSize::Size16, + operand: r12, + mem: am3.clone(), + dst_old: w_r12, + }, + "66458721", + "xchgw %r12w, 0(%r9), dst_old=%r12w", + )); + insns.push(( + Inst::Xchg { + size: OperandSize::Size8, + operand: r13, + mem: am3.clone(), + dst_old: w_r13, + }, + "458629", + "xchgb %r13b, 0(%r9), dst_old=%r13b", + )); + + // AtomicRmwSeq + insns.push(( + Inst::AtomicRmwSeq { + ty: types::I8, + op: AtomicRmwSeqOp::Or, + mem: am3.clone(), + operand: r10, + temp: w_r11, + dst_old: w_rax, + }, + "490FB6014989C34D09D3F0450FB0190F85EFFFFFFF", + "atomically { 8_bits_at_[%r9] Or= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }", + )); + insns.push(( + Inst::AtomicRmwSeq { + ty: types::I16, + op: AtomicRmwSeqOp::And, + mem: am3.clone(), + operand: r10, + temp: w_r11, + dst_old: w_rax + }, + "490FB7014989C34D21D366F0450FB1190F85EEFFFFFF", + "atomically { 16_bits_at_[%r9] And= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }" + )); + insns.push(( + Inst::AtomicRmwSeq { + ty: types::I32, + op: AtomicRmwSeqOp::Nand, + mem: am3.clone(), + operand: r10, + temp: w_r11, + dst_old: w_rax + }, + "418B014989C34D21D349F7D3F0450FB1190F85ECFFFFFF", + "atomically { 32_bits_at_[%r9] Nand= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }" + )); + insns.push(( + Inst::AtomicRmwSeq { + ty: types::I32, + op: AtomicRmwSeqOp::Umin, + mem: am3.clone(), + operand: r10, + temp: w_r11, + dst_old: w_rax + }, + "418B014989C34539DA4D0F46DAF0450FB1190F85EBFFFFFF", + "atomically { 32_bits_at_[%r9] Umin= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }" + )); + insns.push(( + Inst::AtomicRmwSeq { + ty: types::I64, + op: AtomicRmwSeqOp::Smax, + mem: am3.clone(), + operand: r10, + temp: w_r11, + dst_old: w_rax + }, + "498B014989C34D39DA4D0F4DDAF04D0FB1190F85EBFFFFFF", + "atomically { 64_bits_at_[%r9] Smax= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }" + )); + + // Atomic128RmwSeq + insns.push(( + Inst::Atomic128RmwSeq { + op: Atomic128RmwSeqOp::Or, + mem: Box::new(am3.clone()), + operand_low: r10, + operand_high: r11, + temp_low: w_rbx, + temp_high: w_rcx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "498B01498B51084889C34889D14C09D34C09D9F0490FC7090F85E9FFFFFF", + "atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Or %r11:%r10; 0(%r9) = %rcx:%rbx }", + )); + insns.push(( + Inst::Atomic128RmwSeq { + op: Atomic128RmwSeqOp::And, + mem: Box::new(am3.clone()), + operand_low: r10, + operand_high: r11, + temp_low: w_rbx, + temp_high: w_rcx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "498B01498B51084889C34889D14C21D34C21D9F0490FC7090F85E9FFFFFF", + "atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax And %r11:%r10; 0(%r9) = %rcx:%rbx }" + )); + insns.push(( + Inst::Atomic128RmwSeq { + op: Atomic128RmwSeqOp::Umin, + mem: Box::new(am3.clone()), + operand_low: r10, + operand_high: r11, + temp_low: w_rbx, + temp_high: w_rcx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "498B01498B51084889C34889D14C39D34C19D94889D1490F43DA490F43CBF0490FC7090F85DEFFFFFF", + "atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Umin %r11:%r10; 0(%r9) = %rcx:%rbx }" + )); + insns.push(( + Inst::Atomic128RmwSeq { + op: Atomic128RmwSeqOp::Add, + mem: Box::new(am3.clone()), + operand_low: r10, + operand_high: r11, + temp_low: w_rbx, + temp_high: w_rcx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "498B01498B51084889C34889D14C01D34C11D9F0490FC7090F85E9FFFFFF", + "atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Add %r11:%r10; 0(%r9) = %rcx:%rbx }" + )); + insns.push(( + Inst::Atomic128XchgSeq { + mem: am3.clone(), + operand_low: rbx, + operand_high: rcx, + dst_old_low: w_rax, + dst_old_high: w_rdx, + }, + "498B01498B5108F0490FC7090F85F5FFFFFF", + "atomically { %rdx:%rax = 0(%r9); 0(%r9) = %rcx:%rbx }", + )); + + // Fence + insns.push(( + Inst::Fence { + kind: FenceKind::MFence, + }, + "0FAEF0", + "mfence", + )); + insns.push(( + Inst::Fence { + kind: FenceKind::LFence, + }, + "0FAEE8", + "lfence", + )); + insns.push(( + Inst::Fence { + kind: FenceKind::SFence, + }, + "0FAEF8", + "sfence", + )); + + // ======================================================== + // Misc instructions. + + insns.push((Inst::Hlt, "CC", "hlt")); + + let trap_code = TrapCode::INTEGER_OVERFLOW; + insns.push((Inst::Ud2 { trap_code }, "0F0B", "ud2 int_ovf")); + + insns.push(( + Inst::ElfTlsGetAddr { + symbol: ExternalName::User(UserExternalNameRef::new(0)), + dst: WritableGpr::from_writable_reg(w_rax).unwrap(), + }, + "66488D3D00000000666648E800000000", + "%rax = elf_tls_get_addr User(userextname0)", + )); + + insns.push(( + Inst::MachOTlsGetAddr { + symbol: ExternalName::User(UserExternalNameRef::new(0)), + dst: WritableGpr::from_writable_reg(w_rax).unwrap(), + }, + "488B3D00000000FF17", + "%rax = macho_tls_get_addr User(userextname0)", + )); + + insns.push(( + Inst::CoffTlsGetAddr { + symbol: ExternalName::User(UserExternalNameRef::new(0)), + dst: WritableGpr::from_writable_reg(w_rax).unwrap(), + tmp: WritableGpr::from_writable_reg(w_rcx).unwrap(), + }, + "8B050000000065488B0C2558000000488B04C1488D8000000000", + "%rax = coff_tls_get_addr User(userextname0)", + )); + + // ======================================================== + // Actually run the tests! + let ctrl_plane = &mut Default::default(); + let constants = Default::default(); + let mut flag_builder = settings::builder(); + flag_builder.enable("is_pic").unwrap(); + let flags = settings::Flags::new(flag_builder); + + use crate::settings::Configurable; + let mut isa_flag_builder = x64::settings::builder(); + isa_flag_builder.enable("has_cmpxchg16b").unwrap(); + isa_flag_builder.enable("has_ssse3").unwrap(); + isa_flag_builder.enable("has_sse41").unwrap(); + isa_flag_builder.enable("has_fma").unwrap(); + isa_flag_builder.enable("has_avx").unwrap(); + isa_flag_builder.enable("has_avx512bitalg").unwrap(); + isa_flag_builder.enable("has_avx512dq").unwrap(); + isa_flag_builder.enable("has_avx512f").unwrap(); + isa_flag_builder.enable("has_avx512vbmi").unwrap(); + isa_flag_builder.enable("has_avx512vl").unwrap(); + let isa_flags = x64::settings::Flags::new(&flags, &isa_flag_builder); + + let emit_info = EmitInfo::new(flags, isa_flags); + for (insn, expected_encoding, expected_printing) in insns { + // Check the printed text is as expected. + let actual_printing = insn.pretty_print_inst(&mut Default::default()); + assert_eq!(expected_printing, actual_printing); + let mut buffer = MachBuffer::new(); + + insn.emit(&mut buffer, &emit_info, &mut Default::default()); + + // Allow one label just after the instruction (so the offset is 0). + let label = buffer.get_label(); + buffer.bind_label(label, ctrl_plane); + + let buffer = buffer.finish(&constants, ctrl_plane); + let actual_encoding = &buffer.stringify_code_bytes(); + assert_eq!(expected_encoding, actual_encoding, "{expected_printing}"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/mod.rs new file mode 100644 index 00000000000000..4cd96d4c4a7e63 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/mod.rs @@ -0,0 +1,3015 @@ +//! This module defines x86_64-specific machine instruction types. + +pub use emit_state::EmitState; + +use crate::binemit::{Addend, CodeOffset, Reloc}; +use crate::ir::{types, ExternalName, LibCall, TrapCode, Type}; +use crate::isa::x64::abi::X64ABIMachineSpec; +use crate::isa::x64::inst::regs::{pretty_print_reg, show_ireg_sized}; +use crate::isa::x64::settings as x64_settings; +use crate::isa::{CallConv, FunctionAlignment}; +use crate::{machinst::*, trace}; +use crate::{settings, CodegenError, CodegenResult}; +use alloc::boxed::Box; +use smallvec::{smallvec, SmallVec}; +use std::fmt::{self, Write}; +use std::string::{String, ToString}; + +pub mod args; +mod emit; +mod emit_state; +#[cfg(test)] +mod emit_tests; +pub mod regs; +mod stack_switch; +pub mod unwind; + +use args::*; + +//============================================================================= +// Instructions (top level): definition + +// `Inst` is defined inside ISLE as `MInst`. We publicly re-export it here. +pub use super::lower::isle::generated_code::MInst as Inst; + +/// Out-of-line data for return-calls, to keep the size of `Inst` down. +#[derive(Clone, Debug)] +pub struct ReturnCallInfo { + /// Where this call is going. + pub dest: T, + + /// The size of the argument area for this return-call, potentially smaller than that of the + /// caller, but never larger. + pub new_stack_arg_size: u32, + + /// The in-register arguments and their constraints. + pub uses: CallArgList, + + /// A temporary for use when moving the return address. + pub tmp: WritableGpr, +} + +#[test] +#[cfg(target_pointer_width = "64")] +fn inst_size_test() { + // This test will help with unintentionally growing the size + // of the Inst enum. + assert_eq!(40, std::mem::size_of::()); +} + +pub(crate) fn low32_will_sign_extend_to_64(x: u64) -> bool { + let xs = x as i64; + xs == ((xs << 32) >> 32) +} + +impl Inst { + /// Retrieve a list of ISA feature sets in which the instruction is available. An empty list + /// indicates that the instruction is available in the baseline feature set (i.e. SSE2 and + /// below); more than one `InstructionSet` in the list indicates that the instruction is present + /// *any* of the included ISA feature sets. + fn available_in_any_isa(&self) -> SmallVec<[InstructionSet; 2]> { + match self { + // These instructions are part of SSE2, which is a basic requirement in Cranelift, and + // don't have to be checked. + Inst::AluRmiR { .. } + | Inst::AluRM { .. } + | Inst::AtomicRmwSeq { .. } + | Inst::Bswap { .. } + | Inst::CallKnown { .. } + | Inst::CallUnknown { .. } + | Inst::ReturnCallKnown { .. } + | Inst::ReturnCallUnknown { .. } + | Inst::CheckedSRemSeq { .. } + | Inst::CheckedSRemSeq8 { .. } + | Inst::Cmove { .. } + | Inst::CmpRmiR { .. } + | Inst::CvtFloatToSintSeq { .. } + | Inst::CvtFloatToUintSeq { .. } + | Inst::CvtUint64ToFloatSeq { .. } + | Inst::Div { .. } + | Inst::Div8 { .. } + | Inst::Fence { .. } + | Inst::Hlt + | Inst::Imm { .. } + | Inst::JmpCond { .. } + | Inst::JmpIf { .. } + | Inst::JmpKnown { .. } + | Inst::JmpTableSeq { .. } + | Inst::JmpUnknown { .. } + | Inst::LoadEffectiveAddress { .. } + | Inst::LoadExtName { .. } + | Inst::LockCmpxchg { .. } + | Inst::LockXadd { .. } + | Inst::Xchg { .. } + | Inst::Mov64MR { .. } + | Inst::MovImmM { .. } + | Inst::MovRM { .. } + | Inst::MovRR { .. } + | Inst::MovFromPReg { .. } + | Inst::MovToPReg { .. } + | Inst::MovsxRmR { .. } + | Inst::MovzxRmR { .. } + | Inst::Mul { .. } + | Inst::Mul8 { .. } + | Inst::IMul { .. } + | Inst::IMulImm { .. } + | Inst::Neg { .. } + | Inst::Not { .. } + | Inst::Nop { .. } + | Inst::Pop64 { .. } + | Inst::Push64 { .. } + | Inst::StackProbeLoop { .. } + | Inst::Args { .. } + | Inst::Rets { .. } + | Inst::Ret { .. } + | Inst::Setcc { .. } + | Inst::ShiftR { .. } + | Inst::SignExtendData { .. } + | Inst::StackSwitchBasic { .. } + | Inst::TrapIf { .. } + | Inst::TrapIfAnd { .. } + | Inst::TrapIfOr { .. } + | Inst::Ud2 { .. } + | Inst::XmmCmove { .. } + | Inst::XmmCmpRmR { .. } + | Inst::XmmMinMaxSeq { .. } + | Inst::XmmUninitializedValue { .. } + | Inst::ElfTlsGetAddr { .. } + | Inst::MachOTlsGetAddr { .. } + | Inst::CoffTlsGetAddr { .. } + | Inst::Unwind { .. } + | Inst::DummyUse { .. } + | Inst::AluConstOp { .. } => smallvec![], + + Inst::LockCmpxchg16b { .. } + | Inst::Atomic128RmwSeq { .. } + | Inst::Atomic128XchgSeq { .. } => smallvec![InstructionSet::CMPXCHG16b], + + Inst::AluRmRVex { op, .. } => op.available_from(), + Inst::UnaryRmR { op, .. } => op.available_from(), + Inst::UnaryRmRVex { op, .. } => op.available_from(), + Inst::UnaryRmRImmVex { op, .. } => op.available_from(), + + // These use dynamic SSE opcodes. + Inst::GprToXmm { op, .. } + | Inst::XmmMovRM { op, .. } + | Inst::XmmMovRMImm { op, .. } + | Inst::XmmRmiReg { opcode: op, .. } + | Inst::XmmRmR { op, .. } + | Inst::XmmRmRUnaligned { op, .. } + | Inst::XmmRmRBlend { op, .. } + | Inst::XmmRmRImm { op, .. } + | Inst::XmmToGpr { op, .. } + | Inst::XmmToGprImm { op, .. } + | Inst::XmmUnaryRmRImm { op, .. } + | Inst::XmmUnaryRmRUnaligned { op, .. } + | Inst::XmmUnaryRmR { op, .. } + | Inst::CvtIntToFloat { op, .. } => smallvec![op.available_from()], + + Inst::XmmUnaryRmREvex { op, .. } + | Inst::XmmRmREvex { op, .. } + | Inst::XmmRmREvex3 { op, .. } + | Inst::XmmUnaryRmRImmEvex { op, .. } => op.available_from(), + + Inst::XmmRmiRVex { op, .. } + | Inst::XmmRmRVex3 { op, .. } + | Inst::XmmRmRImmVex { op, .. } + | Inst::XmmRmRBlendVex { op, .. } + | Inst::XmmVexPinsr { op, .. } + | Inst::XmmUnaryRmRVex { op, .. } + | Inst::XmmUnaryRmRImmVex { op, .. } + | Inst::XmmMovRMVex { op, .. } + | Inst::XmmMovRMImmVex { op, .. } + | Inst::XmmToGprImmVex { op, .. } + | Inst::XmmToGprVex { op, .. } + | Inst::GprToXmmVex { op, .. } + | Inst::CvtIntToFloatVex { op, .. } + | Inst::XmmCmpRmRVex { op, .. } => op.available_from(), + + Inst::MulX { .. } => smallvec![InstructionSet::BMI2], + } + } +} + +// Handy constructors for Insts. + +impl Inst { + pub(crate) fn nop(len: u8) -> Self { + debug_assert!(len <= 15); + Self::Nop { len } + } + + pub(crate) fn alu_rmi_r( + size: OperandSize, + op: AluRmiROpcode, + src: RegMemImm, + dst: Writable, + ) -> Self { + src.assert_regclass_is(RegClass::Int); + debug_assert!(dst.to_reg().class() == RegClass::Int); + Self::AluRmiR { + size, + op, + src1: Gpr::unwrap_new(dst.to_reg()), + src2: GprMemImm::unwrap_new(src), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + #[allow(dead_code)] + pub(crate) fn unary_rm_r( + size: OperandSize, + op: UnaryRmROpcode, + src: RegMem, + dst: Writable, + ) -> Self { + src.assert_regclass_is(RegClass::Int); + debug_assert!(dst.to_reg().class() == RegClass::Int); + debug_assert!(size.is_one_of(&[ + OperandSize::Size16, + OperandSize::Size32, + OperandSize::Size64 + ])); + Self::UnaryRmR { + size, + op, + src: GprMem::unwrap_new(src), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn not(size: OperandSize, src: Writable) -> Inst { + debug_assert_eq!(src.to_reg().class(), RegClass::Int); + Inst::Not { + size, + src: Gpr::unwrap_new(src.to_reg()), + dst: WritableGpr::from_writable_reg(src).unwrap(), + } + } + + pub(crate) fn div( + size: OperandSize, + sign: DivSignedness, + trap: TrapCode, + divisor: RegMem, + dividend_lo: Gpr, + dividend_hi: Gpr, + dst_quotient: WritableGpr, + dst_remainder: WritableGpr, + ) -> Inst { + divisor.assert_regclass_is(RegClass::Int); + Inst::Div { + size, + sign, + trap, + divisor: GprMem::unwrap_new(divisor), + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + } + } + + pub(crate) fn div8( + sign: DivSignedness, + trap: TrapCode, + divisor: RegMem, + dividend: Gpr, + dst: WritableGpr, + ) -> Inst { + divisor.assert_regclass_is(RegClass::Int); + Inst::Div8 { + sign, + trap, + divisor: GprMem::unwrap_new(divisor), + dividend, + dst, + } + } + + pub(crate) fn imm(dst_size: OperandSize, simm64: u64, dst: Writable) -> Inst { + debug_assert!(dst_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + debug_assert!(dst.to_reg().class() == RegClass::Int); + // Try to generate a 32-bit immediate when the upper high bits are zeroed (which matches + // the semantics of movl). + let dst_size = match dst_size { + OperandSize::Size64 if simm64 > u32::max_value() as u64 => OperandSize::Size64, + _ => OperandSize::Size32, + }; + Inst::Imm { + dst_size, + simm64, + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn mov_r_r(size: OperandSize, src: Reg, dst: Writable) -> Inst { + debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + debug_assert!(src.class() == RegClass::Int); + debug_assert!(dst.to_reg().class() == RegClass::Int); + let src = Gpr::unwrap_new(src); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::MovRR { size, src, dst } + } + + /// Convenient helper for unary float operations. + pub(crate) fn xmm_unary_rm_r(op: SseOpcode, src: RegMem, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmUnaryRmR { + op, + src: XmmMemAligned::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn xmm_rm_r(op: SseOpcode, src: RegMem, dst: Writable) -> Self { + src.assert_regclass_is(RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmRmR { + op, + src1: Xmm::unwrap_new(dst.to_reg()), + src2: XmmMemAligned::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + #[cfg(test)] + pub(crate) fn xmm_rmr_vex3(op: AvxOpcode, src3: RegMem, src2: Reg, dst: Writable) -> Self { + src3.assert_regclass_is(RegClass::Float); + debug_assert!(src2.class() == RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::XmmRmRVex3 { + op, + src3: XmmMem::unwrap_new(src3), + src2: Xmm::unwrap_new(src2), + src1: Xmm::unwrap_new(dst.to_reg()), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn xmm_mov_r_m(op: SseOpcode, src: Reg, dst: impl Into) -> Inst { + debug_assert!(src.class() == RegClass::Float); + Inst::XmmMovRM { + op, + src: Xmm::unwrap_new(src), + dst: dst.into(), + } + } + + pub(crate) fn xmm_to_gpr( + op: SseOpcode, + src: Reg, + dst: Writable, + dst_size: OperandSize, + ) -> Inst { + debug_assert!(src.class() == RegClass::Float); + debug_assert!(dst.to_reg().class() == RegClass::Int); + debug_assert!(dst_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + Inst::XmmToGpr { + op, + src: Xmm::unwrap_new(src), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + dst_size, + } + } + + pub(crate) fn gpr_to_xmm( + op: SseOpcode, + src: RegMem, + src_size: OperandSize, + dst: Writable, + ) -> Inst { + src.assert_regclass_is(RegClass::Int); + debug_assert!(src_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + debug_assert!(dst.to_reg().class() == RegClass::Float); + Inst::GprToXmm { + op, + src: GprMem::unwrap_new(src), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + src_size, + } + } + + pub(crate) fn xmm_cmp_rm_r(op: SseOpcode, src1: Reg, src2: RegMem) -> Inst { + src2.assert_regclass_is(RegClass::Float); + debug_assert!(src1.class() == RegClass::Float); + let src2 = XmmMemAligned::unwrap_new(src2); + let src1 = Xmm::unwrap_new(src1); + Inst::XmmCmpRmR { op, src1, src2 } + } + + #[allow(dead_code)] + pub(crate) fn xmm_min_max_seq( + size: OperandSize, + is_min: bool, + lhs: Reg, + rhs: Reg, + dst: Writable, + ) -> Inst { + debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64])); + debug_assert_eq!(lhs.class(), RegClass::Float); + debug_assert_eq!(rhs.class(), RegClass::Float); + debug_assert_eq!(dst.to_reg().class(), RegClass::Float); + Inst::XmmMinMaxSeq { + size, + is_min, + lhs: Xmm::unwrap_new(lhs), + rhs: Xmm::unwrap_new(rhs), + dst: WritableXmm::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn movzx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Int); + debug_assert!(dst.to_reg().class() == RegClass::Int); + let src = GprMem::unwrap_new(src); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::MovzxRmR { ext_mode, src, dst } + } + + pub(crate) fn movsx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable) -> Inst { + src.assert_regclass_is(RegClass::Int); + debug_assert!(dst.to_reg().class() == RegClass::Int); + let src = GprMem::unwrap_new(src); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::MovsxRmR { ext_mode, src, dst } + } + + pub(crate) fn mov64_m_r(src: impl Into, dst: Writable) -> Inst { + debug_assert!(dst.to_reg().class() == RegClass::Int); + Inst::Mov64MR { + src: src.into(), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn mov_r_m(size: OperandSize, src: Reg, dst: impl Into) -> Inst { + debug_assert!(src.class() == RegClass::Int); + Inst::MovRM { + size, + src: Gpr::unwrap_new(src), + dst: dst.into(), + } + } + + pub(crate) fn lea(addr: impl Into, dst: Writable) -> Inst { + debug_assert!(dst.to_reg().class() == RegClass::Int); + Inst::LoadEffectiveAddress { + addr: addr.into(), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + size: OperandSize::Size64, + } + } + + pub(crate) fn shift_r( + size: OperandSize, + kind: ShiftKind, + num_bits: Imm8Gpr, + src: Reg, + dst: Writable, + ) -> Inst { + if let &Imm8Reg::Imm8 { imm: num_bits } = num_bits.as_imm8_reg() { + debug_assert!(num_bits < size.to_bits()); + } + debug_assert!(dst.to_reg().class() == RegClass::Int); + Inst::ShiftR { + size, + kind, + src: Gpr::unwrap_new(src), + num_bits, + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + /// Does a comparison of dst - src for operands of size `size`, as stated by the machine + /// instruction semantics. Be careful with the order of parameters! + pub(crate) fn cmp_rmi_r(size: OperandSize, src1: Reg, src2: RegMemImm) -> Inst { + src2.assert_regclass_is(RegClass::Int); + debug_assert_eq!(src1.class(), RegClass::Int); + Inst::CmpRmiR { + size, + src1: Gpr::unwrap_new(src1), + src2: GprMemImm::unwrap_new(src2), + opcode: CmpOpcode::Cmp, + } + } + + pub(crate) fn trap(trap_code: TrapCode) -> Inst { + Inst::Ud2 { trap_code } + } + + pub(crate) fn trap_if(cc: CC, trap_code: TrapCode) -> Inst { + Inst::TrapIf { cc, trap_code } + } + + pub(crate) fn cmove(size: OperandSize, cc: CC, src: RegMem, dst: Writable) -> Inst { + debug_assert!(size.is_one_of(&[ + OperandSize::Size16, + OperandSize::Size32, + OperandSize::Size64 + ])); + debug_assert!(dst.to_reg().class() == RegClass::Int); + Inst::Cmove { + size, + cc, + consequent: GprMem::unwrap_new(src), + alternative: Gpr::unwrap_new(dst.to_reg()), + dst: WritableGpr::from_writable_reg(dst).unwrap(), + } + } + + pub(crate) fn push64(src: RegMemImm) -> Inst { + src.assert_regclass_is(RegClass::Int); + let src = GprMemImm::unwrap_new(src); + Inst::Push64 { src } + } + + pub(crate) fn pop64(dst: Writable) -> Inst { + debug_assert!(dst.to_reg().class() == RegClass::Int); + let dst = WritableGpr::from_writable_reg(dst).unwrap(); + Inst::Pop64 { dst } + } + + pub(crate) fn call_known(info: Box>) -> Inst { + Inst::CallKnown { info } + } + + pub(crate) fn call_unknown(info: Box>) -> Inst { + info.dest.assert_regclass_is(RegClass::Int); + Inst::CallUnknown { info } + } + + pub(crate) fn ret(stack_bytes_to_pop: u32) -> Inst { + Inst::Ret { stack_bytes_to_pop } + } + + pub(crate) fn jmp_known(dst: MachLabel) -> Inst { + Inst::JmpKnown { dst } + } + + pub(crate) fn jmp_unknown(target: RegMem) -> Inst { + target.assert_regclass_is(RegClass::Int); + Inst::JmpUnknown { target } + } + + /// Choose which instruction to use for loading a register value from memory. For loads smaller + /// than 64 bits, this method expects a way to extend the value (i.e. [ExtKind::SignExtend], + /// [ExtKind::ZeroExtend]); loads with no extension necessary will ignore this. + pub(crate) fn load( + ty: Type, + from_addr: impl Into, + to_reg: Writable, + ext_kind: ExtKind, + ) -> Inst { + let rc = to_reg.to_reg().class(); + match rc { + RegClass::Int => { + let ext_mode = match ty.bytes() { + 1 => Some(ExtMode::BQ), + 2 => Some(ExtMode::WQ), + 4 => Some(ExtMode::LQ), + 8 => None, + _ => unreachable!("the type should never use a scalar load: {}", ty), + }; + if let Some(ext_mode) = ext_mode { + // Values smaller than 64 bits must be extended in some way. + match ext_kind { + ExtKind::SignExtend => { + Inst::movsx_rm_r(ext_mode, RegMem::mem(from_addr), to_reg) + } + ExtKind::ZeroExtend => { + Inst::movzx_rm_r(ext_mode, RegMem::mem(from_addr), to_reg) + } + ExtKind::None => { + panic!("expected an extension kind for extension mode: {ext_mode:?}") + } + } + } else { + // 64-bit values can be moved directly. + Inst::mov64_m_r(from_addr, to_reg) + } + } + RegClass::Float => { + let opcode = match ty { + types::F16 => panic!("loading a f16 requires multiple instructions"), + types::F32 => SseOpcode::Movss, + types::F64 => SseOpcode::Movsd, + types::F32X4 => SseOpcode::Movups, + types::F64X2 => SseOpcode::Movupd, + _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 128 => SseOpcode::Movdqu, + _ => unimplemented!("unable to load type: {}", ty), + }; + Inst::xmm_unary_rm_r(opcode, RegMem::mem(from_addr), to_reg) + } + RegClass::Vector => unreachable!(), + } + } + + /// Choose which instruction to use for storing a register value to memory. + pub(crate) fn store(ty: Type, from_reg: Reg, to_addr: impl Into) -> Inst { + let rc = from_reg.class(); + match rc { + RegClass::Int => Inst::mov_r_m(OperandSize::from_ty(ty), from_reg, to_addr), + RegClass::Float => { + let opcode = match ty { + types::F16 => panic!("storing a f16 requires multiple instructions"), + types::F32 => SseOpcode::Movss, + types::F64 => SseOpcode::Movsd, + types::F32X4 => SseOpcode::Movups, + types::F64X2 => SseOpcode::Movupd, + _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 128 => SseOpcode::Movdqu, + _ => unimplemented!("unable to store type: {}", ty), + }; + Inst::xmm_mov_r_m(opcode, from_reg, to_addr) + } + RegClass::Vector => unreachable!(), + } + } +} + +//============================================================================= +// Instructions: printing + +impl PrettyPrint for Inst { + fn pretty_print(&self, _size: u8) -> String { + fn ljustify(s: String) -> String { + let w = 7; + if s.len() >= w { + s + } else { + let need = usize::min(w, w - s.len()); + s + &format!("{nil: String { + ljustify(s1 + &s2) + } + + fn suffix_lq(size: OperandSize) -> String { + match size { + OperandSize::Size32 => "l", + OperandSize::Size64 => "q", + _ => unreachable!(), + } + .to_string() + } + + #[allow(dead_code)] + fn suffix_lqb(size: OperandSize) -> String { + match size { + OperandSize::Size32 => "l", + OperandSize::Size64 => "q", + _ => unreachable!(), + } + .to_string() + } + + fn suffix_bwlq(size: OperandSize) -> String { + match size { + OperandSize::Size8 => "b".to_string(), + OperandSize::Size16 => "w".to_string(), + OperandSize::Size32 => "l".to_string(), + OperandSize::Size64 => "q".to_string(), + } + } + + match self { + Inst::Nop { len } => format!("{} len={}", ljustify("nop".to_string()), len), + + Inst::AluRmiR { + size, + op, + src1, + src2, + dst, + } => { + let size_bytes = size.to_bytes(); + let src1 = pretty_print_reg(src1.to_reg(), size_bytes); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size_bytes); + let src2 = src2.pretty_print(size_bytes); + let op = ljustify2(op.to_string(), suffix_bwlq(*size)); + format!("{op} {src1}, {src2}, {dst}") + } + Inst::AluConstOp { op, dst, size } => { + let size_bytes = size.to_bytes(); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size_bytes); + let op = ljustify2(op.to_string(), suffix_lqb(*size)); + format!("{op} {dst}, {dst}, {dst}") + } + Inst::AluRM { + size, + op, + src1_dst, + src2, + lock, + } => { + let size_bytes = size.to_bytes(); + let src2 = pretty_print_reg(src2.to_reg(), size_bytes); + let src1_dst = src1_dst.pretty_print(size_bytes); + let op = ljustify2(op.to_string(), suffix_bwlq(*size)); + let prefix = if *lock { "lock " } else { "" }; + format!("{prefix}{op} {src2}, {src1_dst}") + } + Inst::AluRmRVex { + size, + op, + src1, + src2, + dst, + } => { + let size_bytes = size.to_bytes(); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src1 = pretty_print_reg(src1.to_reg(), size_bytes); + let src2 = src2.pretty_print(size_bytes); + let op = ljustify2(op.to_string(), String::new()); + format!("{op} {src2}, {src1}, {dst}") + } + Inst::UnaryRmR { src, dst, op, size } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src = src.pretty_print(size.to_bytes()); + let op = ljustify2(op.to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::UnaryRmRVex { src, dst, op, size } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src = src.pretty_print(size.to_bytes()); + let op = ljustify2(op.to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::UnaryRmRImmVex { + src, + dst, + op, + size, + imm, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src = src.pretty_print(size.to_bytes()); + format!( + "{} ${imm}, {src}, {dst}", + ljustify2(op.to_string(), suffix_bwlq(*size)) + ) + } + + Inst::Not { size, src, dst } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let op = ljustify2("not".to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::Neg { size, src, dst } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let op = ljustify2("neg".to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::Div { + size, + sign, + trap, + divisor, + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + } => { + let divisor = divisor.pretty_print(size.to_bytes()); + let dividend_lo = pretty_print_reg(dividend_lo.to_reg(), size.to_bytes()); + let dividend_hi = pretty_print_reg(dividend_hi.to_reg(), size.to_bytes()); + let dst_quotient = + pretty_print_reg(dst_quotient.to_reg().to_reg(), size.to_bytes()); + let dst_remainder = + pretty_print_reg(dst_remainder.to_reg().to_reg(), size.to_bytes()); + let op = ljustify(match sign { + DivSignedness::Signed => "idiv".to_string(), + DivSignedness::Unsigned => "div".to_string(), + }); + format!( + "{op} {dividend_lo}, {dividend_hi}, {divisor}, {dst_quotient}, {dst_remainder} ; trap={trap}" + ) + } + + Inst::Div8 { + sign, + trap, + divisor, + dividend, + dst, + } => { + let divisor = divisor.pretty_print(1); + let dividend = pretty_print_reg(dividend.to_reg(), 1); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 1); + let op = ljustify(match sign { + DivSignedness::Signed => "idiv".to_string(), + DivSignedness::Unsigned => "div".to_string(), + }); + format!("{op} {dividend}, {divisor}, {dst} ; trap={trap}") + } + + Inst::Mul { + size, + signed, + src1, + src2, + dst_lo, + dst_hi, + } => { + let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes()); + let dst_lo = pretty_print_reg(dst_lo.to_reg().to_reg(), size.to_bytes()); + let dst_hi = pretty_print_reg(dst_hi.to_reg().to_reg(), size.to_bytes()); + let src2 = src2.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + let op = ljustify(if *signed { + format!("imul{suffix}") + } else { + format!("mul{suffix}") + }); + format!("{op} {src1}, {src2}, {dst_lo}, {dst_hi}") + } + + Inst::MulX { + size, + src1, + src2, + dst_lo, + dst_hi, + } => { + let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes()); + let dst_hi = pretty_print_reg(dst_hi.to_reg().to_reg(), size.to_bytes()); + let dst_lo = if dst_lo.to_reg().is_invalid_sentinel() { + dst_hi.clone() + } else { + pretty_print_reg(dst_lo.to_reg().to_reg(), size.to_bytes()) + }; + let src2 = src2.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + let op = ljustify(format!("mulx{suffix}")); + format!("{op} {src1}, {src2}, {dst_lo}, {dst_hi}") + } + + Inst::Mul8 { + signed, + src1, + src2, + dst, + } => { + let src1 = pretty_print_reg(src1.to_reg(), 1); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 1); + let src2 = src2.pretty_print(1); + let op = ljustify(if *signed { + "imulb".to_string() + } else { + "mulb".to_string() + }); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::IMul { + size, + src1, + src2, + dst, + } => { + let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src2 = src2.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + let op = ljustify(format!("imul{suffix}")); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::IMulImm { + size, + src1, + src2, + dst, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let src1 = src1.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + let op = ljustify(format!("imul{suffix}")); + format!("{op} {src1}, {src2:#x}, {dst}") + } + + Inst::CheckedSRemSeq { + size, + divisor, + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + } => { + let divisor = pretty_print_reg(divisor.to_reg(), size.to_bytes()); + let dividend_lo = pretty_print_reg(dividend_lo.to_reg(), size.to_bytes()); + let dividend_hi = pretty_print_reg(dividend_hi.to_reg(), size.to_bytes()); + let dst_quotient = + pretty_print_reg(dst_quotient.to_reg().to_reg(), size.to_bytes()); + let dst_remainder = + pretty_print_reg(dst_remainder.to_reg().to_reg(), size.to_bytes()); + format!( + "checked_srem_seq {dividend_lo}, {dividend_hi}, \ + {divisor}, {dst_quotient}, {dst_remainder}", + ) + } + + Inst::CheckedSRemSeq8 { + divisor, + dividend, + dst, + } => { + let divisor = pretty_print_reg(divisor.to_reg(), 1); + let dividend = pretty_print_reg(dividend.to_reg(), 1); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 1); + format!("checked_srem_seq {dividend}, {divisor}, {dst}") + } + + Inst::SignExtendData { size, src, dst } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let op = match size { + OperandSize::Size8 => "cbw", + OperandSize::Size16 => "cwd", + OperandSize::Size32 => "cdq", + OperandSize::Size64 => "cqo", + }; + format!("{op} {src}, {dst}") + } + + Inst::XmmUnaryRmR { op, src, dst, .. } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size()); + let src = src.pretty_print(op.src_size()); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmUnaryRmRUnaligned { op, src, dst, .. } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size()); + let src = src.pretty_print(op.src_size()); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmUnaryRmRImm { + op, src, dst, imm, .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size()); + let src = src.pretty_print(op.src_size()); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmUnaryRmRVex { op, src, dst, .. } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmUnaryRmRImmVex { + op, src, dst, imm, .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmUnaryRmREvex { op, src, dst, .. } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmUnaryRmRImmEvex { + op, src, dst, imm, .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmMovRM { op, src, dst, .. } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = dst.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmMovRMVex { op, src, dst, .. } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = dst.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmMovRMImm { + op, src, dst, imm, .. + } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = dst.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmMovRMImmVex { + op, src, dst, imm, .. + } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = dst.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmRmR { + op, + src1, + src2, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::XmmRmRUnaligned { + op, + src1, + src2, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::XmmRmRBlend { + op, + src1, + src2, + mask, + dst, + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let mask = mask.to_reg(); + let mask = if mask.is_virtual() { + format!(" <{}>", show_ireg_sized(mask, 8)) + } else { + debug_assert_eq!(mask, regs::xmm0()); + String::new() + }; + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}{mask}") + } + + Inst::XmmRmiRVex { + op, + src1, + src2, + dst, + .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::XmmRmRImmVex { + op, + src1, + src2, + dst, + imm, + .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src1}, {src2}, {dst}") + } + + Inst::XmmVexPinsr { + op, + src1, + src2, + dst, + imm, + .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src1}, {src2}, {dst}") + } + + Inst::XmmRmRVex3 { + op, + src1, + src2, + src3, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = pretty_print_reg(src2.to_reg(), 8); + let src3 = src3.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {src3}, {dst}") + } + + Inst::XmmRmRBlendVex { + op, + src1, + src2, + mask, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = src2.pretty_print(8); + let mask = pretty_print_reg(mask.to_reg(), 8); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {mask}, {dst}") + } + + Inst::XmmRmREvex { + op, + src1, + src2, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify(op.to_string()); + format!("{op} {src2}, {src1}, {dst}") + } + + Inst::XmmRmREvex3 { + op, + src1, + src2, + src3, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = pretty_print_reg(src2.to_reg(), 8); + let src3 = src3.pretty_print(8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify(op.to_string()); + format!("{op} {src3}, {src2}, {src1}, {dst}") + } + + Inst::XmmMinMaxSeq { + lhs, + rhs, + dst, + is_min, + size, + } => { + let rhs = pretty_print_reg(rhs.to_reg(), 8); + let lhs = pretty_print_reg(lhs.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify2( + if *is_min { + "xmm min seq ".to_string() + } else { + "xmm max seq ".to_string() + }, + format!("f{}", size.to_bits()), + ); + format!("{op} {lhs}, {rhs}, {dst}") + } + + Inst::XmmRmRImm { + op, + src1, + src2, + dst, + imm, + size, + .. + } => { + let src1 = pretty_print_reg(*src1, 8); + let dst = pretty_print_reg(dst.to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(format!( + "{}{}", + op.to_string(), + if *size == OperandSize::Size64 { + ".w" + } else { + "" + } + )); + format!("{op} ${imm}, {src1}, {src2}, {dst}") + } + + Inst::XmmUninitializedValue { dst } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify("uninit".into()); + format!("{op} {dst}") + } + + Inst::XmmToGpr { + op, + src, + dst, + dst_size, + } => { + let dst_size = dst_size.to_bytes(); + let src = pretty_print_reg(src.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmToGprVex { + op, + src, + dst, + dst_size, + } => { + let dst_size = dst_size.to_bytes(); + let src = pretty_print_reg(src.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmToGprImm { op, src, dst, imm } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::XmmToGprImmVex { op, src, dst, imm } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify(op.to_string()); + format!("{op} ${imm}, {src}, {dst}") + } + + Inst::GprToXmm { + op, + src, + src_size, + dst, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(src_size.to_bytes()); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::GprToXmmVex { + op, + src, + src_size, + dst, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(src_size.to_bytes()); + let op = ljustify(op.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::XmmCmpRmR { op, src1, src2 } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(op.to_string()); + format!("{op} {src2}, {src1}") + } + + Inst::CvtIntToFloat { + op, + src1, + src2, + dst, + src2_size, + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(*dst.to_reg(), 8); + let src2 = src2.pretty_print(src2_size.to_bytes()); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::CvtIntToFloatVex { + op, + src1, + src2, + dst, + src2_size, + } => { + let dst = pretty_print_reg(*dst.to_reg(), 8); + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(src2_size.to_bytes()); + let op = ljustify(op.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::XmmCmpRmRVex { op, src1, src2 } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let src2 = src2.pretty_print(8); + format!("{} {src2}, {src1}", ljustify(op.to_string())) + } + + Inst::CvtUint64ToFloatSeq { + src, + dst, + dst_size, + tmp_gpr1, + tmp_gpr2, + .. + } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes()); + let tmp_gpr1 = pretty_print_reg(tmp_gpr1.to_reg().to_reg(), 8); + let tmp_gpr2 = pretty_print_reg(tmp_gpr2.to_reg().to_reg(), 8); + let op = ljustify(format!( + "u64_to_{}_seq", + if *dst_size == OperandSize::Size64 { + "f64" + } else { + "f32" + } + )); + format!("{op} {src}, {dst}, {tmp_gpr1}, {tmp_gpr2}") + } + + Inst::CvtFloatToSintSeq { + src, + dst, + src_size, + dst_size, + tmp_xmm, + tmp_gpr, + is_saturating, + } => { + let src = pretty_print_reg(src.to_reg(), src_size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes()); + let tmp_gpr = pretty_print_reg(tmp_gpr.to_reg().to_reg(), 8); + let tmp_xmm = pretty_print_reg(tmp_xmm.to_reg().to_reg(), 8); + let op = ljustify(format!( + "cvt_float{}_to_sint{}{}_seq", + src_size.to_bits(), + dst_size.to_bits(), + if *is_saturating { "_sat" } else { "" }, + )); + format!("{op} {src}, {dst}, {tmp_gpr}, {tmp_xmm}") + } + + Inst::CvtFloatToUintSeq { + src, + dst, + src_size, + dst_size, + tmp_gpr, + tmp_xmm, + tmp_xmm2, + is_saturating, + } => { + let src = pretty_print_reg(src.to_reg(), src_size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes()); + let tmp_gpr = pretty_print_reg(tmp_gpr.to_reg().to_reg(), 8); + let tmp_xmm = pretty_print_reg(tmp_xmm.to_reg().to_reg(), 8); + let tmp_xmm2 = pretty_print_reg(tmp_xmm2.to_reg().to_reg(), 8); + let op = ljustify(format!( + "cvt_float{}_to_uint{}{}_seq", + src_size.to_bits(), + dst_size.to_bits(), + if *is_saturating { "_sat" } else { "" }, + )); + format!("{op} {src}, {dst}, {tmp_gpr}, {tmp_xmm}, {tmp_xmm2}") + } + + Inst::Imm { + dst_size, + simm64, + dst, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes()); + if *dst_size == OperandSize::Size64 { + let op = ljustify("movabsq".to_string()); + let imm = *simm64 as i64; + format!("{op} ${imm}, {dst}") + } else { + let op = ljustify("movl".to_string()); + let imm = (*simm64 as u32) as i32; + format!("{op} ${imm}, {dst}") + } + } + + Inst::MovImmM { size, simm32, dst } => { + let dst = dst.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + let imm = match *size { + OperandSize::Size8 => ((*simm32 as u8) as i8).to_string(), + OperandSize::Size16 => ((*simm32 as u16) as i16).to_string(), + OperandSize::Size32 => simm32.to_string(), + OperandSize::Size64 => (*simm32 as i64).to_string(), + }; + let op = ljustify2("mov".to_string(), suffix); + format!("{op} ${imm}, {dst}") + } + + Inst::MovRR { size, src, dst } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let op = ljustify2("mov".to_string(), suffix_lq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::MovFromPReg { src, dst } => { + let src: Reg = (*src).into(); + let src = regs::show_ireg_sized(src, 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify("movq".to_string()); + format!("{op} {src}, {dst}") + } + + Inst::MovToPReg { src, dst } => { + let src = pretty_print_reg(src.to_reg(), 8); + let dst: Reg = (*dst).into(); + let dst = regs::show_ireg_sized(dst, 8); + let op = ljustify("movq".to_string()); + format!("{op} {src}, {dst}") + } + + Inst::MovzxRmR { + ext_mode, src, dst, .. + } => { + let dst_size = if *ext_mode == ExtMode::LQ { + 4 + } else { + ext_mode.dst_size() + }; + let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size); + let src = src.pretty_print(ext_mode.src_size()); + + if *ext_mode == ExtMode::LQ { + let op = ljustify("movl".to_string()); + format!("{op} {src}, {dst}") + } else { + let op = ljustify2("movz".to_string(), ext_mode.to_string()); + format!("{op} {src}, {dst}") + } + } + + Inst::Mov64MR { src, dst, .. } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src = src.pretty_print(8); + let op = ljustify("movq".to_string()); + format!("{op} {src}, {dst}") + } + + Inst::LoadEffectiveAddress { addr, dst, size } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let addr = addr.pretty_print(8); + let op = ljustify("lea".to_string()); + format!("{op} {addr}, {dst}") + } + + Inst::MovsxRmR { + ext_mode, src, dst, .. + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), ext_mode.dst_size()); + let src = src.pretty_print(ext_mode.src_size()); + let op = ljustify2("movs".to_string(), ext_mode.to_string()); + format!("{op} {src}, {dst}") + } + + Inst::MovRM { size, src, dst, .. } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = dst.pretty_print(size.to_bytes()); + let op = ljustify2("mov".to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::ShiftR { + size, + kind, + num_bits, + src, + dst, + .. + } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + match num_bits.as_imm8_reg() { + &Imm8Reg::Reg { reg } => { + let reg = pretty_print_reg(reg, 1); + let op = ljustify2(kind.to_string(), suffix_bwlq(*size)); + format!("{op} {reg}, {src}, {dst}") + } + + &Imm8Reg::Imm8 { imm: num_bits } => { + let op = ljustify2(kind.to_string(), suffix_bwlq(*size)); + format!("{op} ${num_bits}, {src}, {dst}") + } + } + } + + Inst::XmmRmiReg { + opcode, + src1, + src2, + dst, + .. + } => { + let src1 = pretty_print_reg(src1.to_reg(), 8); + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let src2 = src2.pretty_print(8); + let op = ljustify(opcode.to_string()); + format!("{op} {src1}, {src2}, {dst}") + } + + Inst::CmpRmiR { + size, + src1, + src2, + opcode, + } => { + let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes()); + let src2 = src2.pretty_print(size.to_bytes()); + let op = match opcode { + CmpOpcode::Cmp => "cmp", + CmpOpcode::Test => "test", + }; + let op = ljustify2(op.to_string(), suffix_bwlq(*size)); + format!("{op} {src2}, {src1}") + } + + Inst::Setcc { cc, dst } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 1); + let op = ljustify2("set".to_string(), cc.to_string()); + format!("{op} {dst}") + } + + Inst::Bswap { size, src, dst } => { + let src = pretty_print_reg(src.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let op = ljustify2("bswap".to_string(), suffix_bwlq(*size)); + format!("{op} {src}, {dst}") + } + + Inst::Cmove { + size, + cc, + consequent, + alternative, + dst, + } => { + let alternative = pretty_print_reg(alternative.to_reg(), size.to_bytes()); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes()); + let consequent = consequent.pretty_print(size.to_bytes()); + let op = ljustify(format!("cmov{}{}", cc.to_string(), suffix_bwlq(*size))); + format!("{op} {consequent}, {alternative}, {dst}") + } + + Inst::XmmCmove { + ty, + cc, + consequent, + alternative, + dst, + .. + } => { + let size = u8::try_from(ty.bytes()).unwrap(); + let alternative = pretty_print_reg(alternative.to_reg(), size); + let dst = pretty_print_reg(dst.to_reg().to_reg(), size); + let consequent = pretty_print_reg(consequent.to_reg(), size); + let suffix = match *ty { + types::F64 => "sd", + types::F32 => "ss", + types::F16 => "ss", + types::F32X4 => "aps", + types::F64X2 => "apd", + _ => "dqa", + }; + let cc = cc.invert(); + format!( + "mov{suffix} {alternative}, {dst}; \ + j{cc} $next; \ + mov{suffix} {consequent}, {dst}; \ + $next:" + ) + } + + Inst::Push64 { src } => { + let src = src.pretty_print(8); + let op = ljustify("pushq".to_string()); + format!("{op} {src}") + } + + Inst::StackProbeLoop { + tmp, + frame_size, + guard_size, + } => { + let tmp = pretty_print_reg(tmp.to_reg(), 8); + let op = ljustify("stack_probe_loop".to_string()); + format!("{op} {tmp}, frame_size={frame_size}, guard_size={guard_size}") + } + + Inst::Pop64 { dst } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let op = ljustify("popq".to_string()); + format!("{op} {dst}") + } + + Inst::CallKnown { info } => { + let op = ljustify("call".to_string()); + format!("{op} {:?}", info.dest) + } + + Inst::CallUnknown { info } => { + let dest = info.dest.pretty_print(8); + let op = ljustify("call".to_string()); + format!("{op} *{dest}") + } + + Inst::ReturnCallKnown { info } => { + let ReturnCallInfo { + uses, + new_stack_arg_size, + tmp, + dest, + } = &**info; + let tmp = pretty_print_reg(tmp.to_reg().to_reg(), 8); + let mut s = format!("return_call_known {dest:?} ({new_stack_arg_size}) tmp={tmp}"); + for ret in uses { + let preg = regs::show_reg(ret.preg); + let vreg = pretty_print_reg(ret.vreg, 8); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + + Inst::ReturnCallUnknown { info } => { + let ReturnCallInfo { + uses, + new_stack_arg_size, + tmp, + dest, + } = &**info; + let callee = pretty_print_reg(*dest, 8); + let tmp = pretty_print_reg(tmp.to_reg().to_reg(), 8); + let mut s = + format!("return_call_unknown {callee} ({new_stack_arg_size}) tmp={tmp}"); + for ret in uses { + let preg = regs::show_reg(ret.preg); + let vreg = pretty_print_reg(ret.vreg, 8); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + + Inst::Args { args } => { + let mut s = "args".to_string(); + for arg in args { + let preg = regs::show_reg(arg.preg); + let def = pretty_print_reg(arg.vreg.to_reg(), 8); + write!(&mut s, " {def}={preg}").unwrap(); + } + s + } + + Inst::Rets { rets } => { + let mut s = "rets".to_string(); + for ret in rets { + let preg = regs::show_reg(ret.preg); + let vreg = pretty_print_reg(ret.vreg, 8); + write!(&mut s, " {vreg}={preg}").unwrap(); + } + s + } + + Inst::Ret { stack_bytes_to_pop } => { + let mut s = "ret".to_string(); + if *stack_bytes_to_pop != 0 { + write!(&mut s, " {stack_bytes_to_pop}").unwrap(); + } + s + } + + Inst::StackSwitchBasic { + store_context_ptr, + load_context_ptr, + in_payload0, + out_payload0, + } => { + let store_context_ptr = pretty_print_reg(**store_context_ptr, 8); + let load_context_ptr = pretty_print_reg(**load_context_ptr, 8); + let in_payload0 = pretty_print_reg(**in_payload0, 8); + let out_payload0 = pretty_print_reg(*out_payload0.to_reg(), 8); + format!("{out_payload0} = stack_switch_basic {store_context_ptr}, {load_context_ptr}, {in_payload0}") + } + + Inst::JmpKnown { dst } => { + let op = ljustify("jmp".to_string()); + let dst = dst.to_string(); + format!("{op} {dst}") + } + + Inst::JmpIf { cc, taken } => { + let taken = taken.to_string(); + let op = ljustify2("j".to_string(), cc.to_string()); + format!("{op} {taken}") + } + + Inst::JmpCond { + cc, + taken, + not_taken, + } => { + let taken = taken.to_string(); + let not_taken = not_taken.to_string(); + let op = ljustify2("j".to_string(), cc.to_string()); + format!("{op} {taken}; j {not_taken}") + } + + Inst::JmpTableSeq { + idx, tmp1, tmp2, .. + } => { + let idx = pretty_print_reg(*idx, 8); + let tmp1 = pretty_print_reg(tmp1.to_reg(), 8); + let tmp2 = pretty_print_reg(tmp2.to_reg(), 8); + let op = ljustify("br_table".into()); + format!("{op} {idx}, {tmp1}, {tmp2}") + } + + Inst::JmpUnknown { target } => { + let target = target.pretty_print(8); + let op = ljustify("jmp".to_string()); + format!("{op} *{target}") + } + + Inst::TrapIf { cc, trap_code, .. } => { + format!("j{cc} #trap={trap_code}") + } + + Inst::TrapIfAnd { + cc1, + cc2, + trap_code, + .. + } => { + let cc1 = cc1.invert(); + let cc2 = cc2.invert(); + format!("trap_if_and {cc1}, {cc2}, {trap_code}") + } + + Inst::TrapIfOr { + cc1, + cc2, + trap_code, + .. + } => { + let cc2 = cc2.invert(); + format!("trap_if_or {cc1}, {cc2}, {trap_code}") + } + + Inst::LoadExtName { + dst, name, offset, .. + } => { + let dst = pretty_print_reg(dst.to_reg(), 8); + let name = name.display(None); + let op = ljustify("load_ext_name".into()); + format!("{op} {name}+{offset}, {dst}") + } + + Inst::LockCmpxchg { + ty, + replacement, + expected, + mem, + dst_old, + .. + } => { + let size = ty.bytes() as u8; + let replacement = pretty_print_reg(*replacement, size); + let expected = pretty_print_reg(*expected, size); + let dst_old = pretty_print_reg(dst_old.to_reg(), size); + let mem = mem.pretty_print(size); + let suffix = suffix_bwlq(OperandSize::from_bytes(size as u32)); + format!( + "lock cmpxchg{suffix} {replacement}, {mem}, expected={expected}, dst_old={dst_old}" + ) + } + + Inst::LockCmpxchg16b { + replacement_low, + replacement_high, + expected_low, + expected_high, + mem, + dst_old_low, + dst_old_high, + .. + } => { + let replacement_low = pretty_print_reg(*replacement_low, 8); + let replacement_high = pretty_print_reg(*replacement_high, 8); + let expected_low = pretty_print_reg(*expected_low, 8); + let expected_high = pretty_print_reg(*expected_high, 8); + let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8); + let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8); + let mem = mem.pretty_print(16); + format!( + "lock cmpxchg16b {mem}, replacement={replacement_high}:{replacement_low}, expected={expected_high}:{expected_low}, dst_old={dst_old_high}:{dst_old_low}" + ) + } + + Inst::LockXadd { + size, + operand, + mem, + dst_old, + } => { + let operand = pretty_print_reg(*operand, size.to_bytes()); + let dst_old = pretty_print_reg(dst_old.to_reg(), size.to_bytes()); + let mem = mem.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + format!("lock xadd{suffix} {operand}, {mem}, dst_old={dst_old}") + } + + Inst::Xchg { + size, + operand, + mem, + dst_old, + } => { + let operand = pretty_print_reg(*operand, size.to_bytes()); + let dst_old = pretty_print_reg(dst_old.to_reg(), size.to_bytes()); + let mem = mem.pretty_print(size.to_bytes()); + let suffix = suffix_bwlq(*size); + format!("xchg{suffix} {operand}, {mem}, dst_old={dst_old}") + } + + Inst::AtomicRmwSeq { ty, op, .. } => { + let ty = ty.bits(); + format!( + "atomically {{ {ty}_bits_at_[%r9] {op:?}= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }}" + ) + } + + Inst::Atomic128RmwSeq { + op, + mem, + operand_low, + operand_high, + temp_low, + temp_high, + dst_old_low, + dst_old_high, + } => { + let operand_low = pretty_print_reg(*operand_low, 8); + let operand_high = pretty_print_reg(*operand_high, 8); + let temp_low = pretty_print_reg(temp_low.to_reg(), 8); + let temp_high = pretty_print_reg(temp_high.to_reg(), 8); + let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8); + let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8); + let mem = mem.pretty_print(16); + format!("atomically {{ {dst_old_high}:{dst_old_low} = {mem}; {temp_high}:{temp_low} = {dst_old_high}:{dst_old_low} {op:?} {operand_high}:{operand_low}; {mem} = {temp_high}:{temp_low} }}") + } + + Inst::Atomic128XchgSeq { + mem, + operand_low, + operand_high, + dst_old_low, + dst_old_high, + } => { + let operand_low = pretty_print_reg(*operand_low, 8); + let operand_high = pretty_print_reg(*operand_high, 8); + let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8); + let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8); + let mem = mem.pretty_print(16); + format!("atomically {{ {dst_old_high}:{dst_old_low} = {mem}; {mem} = {operand_high}:{operand_low} }}") + } + + Inst::Fence { kind } => match kind { + FenceKind::MFence => "mfence".to_string(), + FenceKind::LFence => "lfence".to_string(), + FenceKind::SFence => "sfence".to_string(), + }, + + Inst::Hlt => "hlt".into(), + + Inst::Ud2 { trap_code } => format!("ud2 {trap_code}"), + + Inst::ElfTlsGetAddr { ref symbol, dst } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + format!("{dst} = elf_tls_get_addr {symbol:?}") + } + + Inst::MachOTlsGetAddr { ref symbol, dst } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + format!("{dst} = macho_tls_get_addr {symbol:?}") + } + + Inst::CoffTlsGetAddr { + ref symbol, + dst, + tmp, + } => { + let dst = pretty_print_reg(dst.to_reg().to_reg(), 8); + let tmp = tmp.to_reg().to_reg(); + + let mut s = format!("{dst} = coff_tls_get_addr {symbol:?}"); + if tmp.is_virtual() { + let tmp = show_ireg_sized(tmp, 8); + write!(&mut s, ", {tmp}").unwrap(); + }; + + s + } + + Inst::Unwind { inst } => format!("unwind {inst:?}"), + + Inst::DummyUse { reg } => { + let reg = pretty_print_reg(*reg, 8); + format!("dummy_use {reg}") + } + } + } +} + +impl fmt::Debug for Inst { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.pretty_print_inst(&mut Default::default())) + } +} + +fn x64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { + // Note: because we need to statically know the indices of each + // reg in the operands list in order to fetch its allocation + // later, we put the variable-operand-count bits (the RegMem, + // RegMemImm, etc args) last. regalloc2 doesn't care what order + // the operands come in; they can be freely reordered. + + // N.B.: we MUST keep the below in careful sync with (i) emission, + // in `emit.rs`, and (ii) pretty-printing, in the `pretty_print` + // method above. + match inst { + Inst::AluRmiR { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::AluConstOp { dst, .. } => collector.reg_def(dst), + Inst::AluRM { src1_dst, src2, .. } => { + collector.reg_use(src2); + src1_dst.get_operands(collector); + } + Inst::AluRmRVex { + src1, src2, dst, .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::Not { src, dst, .. } => { + collector.reg_use(src); + collector.reg_reuse_def(dst, 0); + } + Inst::Neg { src, dst, .. } => { + collector.reg_use(src); + collector.reg_reuse_def(dst, 0); + } + Inst::Div { + divisor, + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + .. + } => { + divisor.get_operands(collector); + collector.reg_fixed_use(dividend_lo, regs::rax()); + collector.reg_fixed_use(dividend_hi, regs::rdx()); + collector.reg_fixed_def(dst_quotient, regs::rax()); + collector.reg_fixed_def(dst_remainder, regs::rdx()); + } + Inst::CheckedSRemSeq { + divisor, + dividend_lo, + dividend_hi, + dst_quotient, + dst_remainder, + .. + } => { + collector.reg_use(divisor); + collector.reg_fixed_use(dividend_lo, regs::rax()); + collector.reg_fixed_use(dividend_hi, regs::rdx()); + collector.reg_fixed_def(dst_quotient, regs::rax()); + collector.reg_fixed_def(dst_remainder, regs::rdx()); + } + Inst::Div8 { + divisor, + dividend, + dst, + .. + } => { + divisor.get_operands(collector); + collector.reg_fixed_use(dividend, regs::rax()); + collector.reg_fixed_def(dst, regs::rax()); + } + Inst::CheckedSRemSeq8 { + divisor, + dividend, + dst, + .. + } => { + collector.reg_use(divisor); + collector.reg_fixed_use(dividend, regs::rax()); + collector.reg_fixed_def(dst, regs::rax()); + } + Inst::Mul { + src1, + src2, + dst_lo, + dst_hi, + .. + } => { + collector.reg_fixed_use(src1, regs::rax()); + collector.reg_fixed_def(dst_lo, regs::rax()); + collector.reg_fixed_def(dst_hi, regs::rdx()); + src2.get_operands(collector); + } + Inst::Mul8 { + src1, src2, dst, .. + } => { + collector.reg_fixed_use(src1, regs::rax()); + collector.reg_fixed_def(dst, regs::rax()); + src2.get_operands(collector); + } + Inst::IMul { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::IMulImm { src1, dst, .. } => { + collector.reg_def(dst); + src1.get_operands(collector); + } + Inst::MulX { + src1, + src2, + dst_lo, + dst_hi, + .. + } => { + if !dst_lo.to_reg().is_invalid_sentinel() { + collector.reg_def(dst_lo); + } + collector.reg_def(dst_hi); + collector.reg_fixed_use(src1, regs::rdx()); + src2.get_operands(collector); + } + Inst::SignExtendData { size, src, dst } => { + match size { + OperandSize::Size8 => { + // Note `rax` on both src and dest: 8->16 extend + // does AL -> AX. + collector.reg_fixed_use(src, regs::rax()); + collector.reg_fixed_def(dst, regs::rax()); + } + _ => { + // All other widths do RAX -> RDX (AX -> DX:AX, + // EAX -> EDX:EAX). + collector.reg_fixed_use(src, regs::rax()); + collector.reg_fixed_def(dst, regs::rdx()); + } + } + } + Inst::UnaryRmR { src, dst, .. } + | Inst::UnaryRmRVex { src, dst, .. } + | Inst::UnaryRmRImmVex { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::XmmUnaryRmR { src, dst, .. } | Inst::XmmUnaryRmRImm { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::XmmUnaryRmREvex { src, dst, .. } + | Inst::XmmUnaryRmRImmEvex { src, dst, .. } + | Inst::XmmUnaryRmRUnaligned { src, dst, .. } + | Inst::XmmUnaryRmRVex { src, dst, .. } + | Inst::XmmUnaryRmRImmVex { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::XmmRmR { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::XmmRmRUnaligned { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::XmmRmRBlend { + src1, + src2, + mask, + dst, + op, + } => { + assert!(matches!( + op, + SseOpcode::Blendvpd | SseOpcode::Blendvps | SseOpcode::Pblendvb + )); + collector.reg_use(src1); + collector.reg_fixed_use(mask, regs::xmm0()); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::XmmRmiRVex { + src1, src2, dst, .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::XmmRmRImmVex { + src1, src2, dst, .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::XmmVexPinsr { + src1, src2, dst, .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::XmmRmRVex3 { + src1, + src2, + src3, + dst, + .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + collector.reg_use(src2); + src3.get_operands(collector); + } + Inst::XmmRmRBlendVex { + src1, + src2, + mask, + dst, + .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + collector.reg_use(mask); + } + Inst::XmmRmREvex { + op, + src1, + src2, + dst, + .. + } => { + assert_ne!(*op, Avx512Opcode::Vpermi2b); + collector.reg_use(src1); + src2.get_operands(collector); + collector.reg_def(dst); + } + Inst::XmmRmREvex3 { + op, + src1, + src2, + src3, + dst, + .. + } => { + assert_eq!(*op, Avx512Opcode::Vpermi2b); + collector.reg_use(src1); + collector.reg_use(src2); + src3.get_operands(collector); + collector.reg_reuse_def(dst, 0); // Reuse `src1`. + } + Inst::XmmRmRImm { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::XmmUninitializedValue { dst } => collector.reg_def(dst), + Inst::XmmMinMaxSeq { lhs, rhs, dst, .. } => { + collector.reg_use(rhs); + collector.reg_use(lhs); + collector.reg_reuse_def(dst, 0); // Reuse RHS. + } + Inst::XmmRmiReg { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); // Reuse RHS. + src2.get_operands(collector); + } + Inst::XmmMovRM { src, dst, .. } + | Inst::XmmMovRMVex { src, dst, .. } + | Inst::XmmMovRMImm { src, dst, .. } + | Inst::XmmMovRMImmVex { src, dst, .. } => { + collector.reg_use(src); + dst.get_operands(collector); + } + Inst::XmmCmpRmR { src1, src2, .. } => { + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::XmmCmpRmRVex { src1, src2, .. } => { + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::Imm { dst, .. } => { + collector.reg_def(dst); + } + Inst::MovRR { src, dst, .. } => { + collector.reg_use(src); + collector.reg_def(dst); + } + Inst::MovFromPReg { dst, src } => { + debug_assert!(dst.to_reg().to_reg().is_virtual()); + collector.reg_fixed_nonallocatable(*src); + collector.reg_def(dst); + } + Inst::MovToPReg { dst, src } => { + debug_assert!(src.to_reg().is_virtual()); + collector.reg_use(src); + collector.reg_fixed_nonallocatable(*dst); + } + Inst::XmmToGpr { src, dst, .. } + | Inst::XmmToGprVex { src, dst, .. } + | Inst::XmmToGprImm { src, dst, .. } + | Inst::XmmToGprImmVex { src, dst, .. } => { + collector.reg_use(src); + collector.reg_def(dst); + } + Inst::GprToXmm { src, dst, .. } | Inst::GprToXmmVex { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::CvtIntToFloat { + src1, src2, dst, .. + } => { + collector.reg_use(src1); + collector.reg_reuse_def(dst, 0); + src2.get_operands(collector); + } + Inst::CvtIntToFloatVex { + src1, src2, dst, .. + } => { + collector.reg_def(dst); + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::CvtUint64ToFloatSeq { + src, + dst, + tmp_gpr1, + tmp_gpr2, + .. + } => { + collector.reg_use(src); + collector.reg_early_def(dst); + collector.reg_early_def(tmp_gpr1); + collector.reg_early_def(tmp_gpr2); + } + Inst::CvtFloatToSintSeq { + src, + dst, + tmp_xmm, + tmp_gpr, + .. + } => { + collector.reg_use(src); + collector.reg_early_def(dst); + collector.reg_early_def(tmp_gpr); + collector.reg_early_def(tmp_xmm); + } + Inst::CvtFloatToUintSeq { + src, + dst, + tmp_gpr, + tmp_xmm, + tmp_xmm2, + .. + } => { + collector.reg_use(src); + collector.reg_early_def(dst); + collector.reg_early_def(tmp_gpr); + collector.reg_early_def(tmp_xmm); + collector.reg_early_def(tmp_xmm2); + } + + Inst::MovImmM { dst, .. } => { + dst.get_operands(collector); + } + + Inst::MovzxRmR { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::Mov64MR { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::LoadEffectiveAddress { addr: src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::MovsxRmR { src, dst, .. } => { + collector.reg_def(dst); + src.get_operands(collector); + } + Inst::MovRM { src, dst, .. } => { + collector.reg_use(src); + dst.get_operands(collector); + } + Inst::ShiftR { + num_bits, src, dst, .. + } => { + collector.reg_use(src); + collector.reg_reuse_def(dst, 0); + if let Imm8Reg::Reg { reg } = num_bits.as_imm8_reg_mut() { + collector.reg_fixed_use(reg, regs::rcx()); + } + } + Inst::CmpRmiR { src1, src2, .. } => { + collector.reg_use(src1); + src2.get_operands(collector); + } + Inst::Setcc { dst, .. } => { + collector.reg_def(dst); + } + Inst::Bswap { src, dst, .. } => { + collector.reg_use(src); + collector.reg_reuse_def(dst, 0); + } + Inst::Cmove { + consequent, + alternative, + dst, + .. + } => { + collector.reg_use(alternative); + collector.reg_reuse_def(dst, 0); + consequent.get_operands(collector); + } + Inst::XmmCmove { + consequent, + alternative, + dst, + .. + } => { + collector.reg_use(alternative); + collector.reg_reuse_def(dst, 0); + collector.reg_use(consequent); + } + Inst::Push64 { src } => { + src.get_operands(collector); + } + Inst::Pop64 { dst } => { + collector.reg_def(dst); + } + Inst::StackProbeLoop { tmp, .. } => { + collector.reg_early_def(tmp); + } + + Inst::CallKnown { info } => { + // Probestack is special and is only inserted after + // regalloc, so we do not need to represent its ABI to the + // register allocator. Assert that we don't alter that + // arrangement. + let CallInfo { + uses, + defs, + clobbers, + dest, + .. + } = &mut **info; + debug_assert_ne!(*dest, ExternalName::LibCall(LibCall::Probestack)); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(*clobbers); + } + + Inst::CallUnknown { info } => { + let CallInfo { + uses, + defs, + clobbers, + callee_conv, + dest, + .. + } = &mut **info; + match dest { + RegMem::Reg { reg } if *callee_conv == CallConv::Winch => { + // TODO(https://github.com/bytecodealliance/regalloc2/issues/145): + // This shouldn't be a fixed register constraint. r10 is caller-saved, so this + // should be safe to use. + collector.reg_fixed_use(reg, regs::r10()) + } + _ => dest.get_operands(collector), + } + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + for CallRetPair { vreg, preg } in defs { + collector.reg_fixed_def(vreg, *preg); + } + collector.reg_clobbers(*clobbers); + } + Inst::StackSwitchBasic { + store_context_ptr, + load_context_ptr, + in_payload0, + out_payload0, + } => { + collector.reg_use(load_context_ptr); + collector.reg_use(store_context_ptr); + collector.reg_fixed_use(in_payload0, stack_switch::payload_register()); + collector.reg_fixed_def(out_payload0, stack_switch::payload_register()); + + let mut clobbers = crate::isa::x64::abi::ALL_CLOBBERS; + // The return/payload reg must not be included in the clobber set + clobbers.remove( + stack_switch::payload_register() + .to_real_reg() + .unwrap() + .into(), + ); + collector.reg_clobbers(clobbers); + } + + Inst::ReturnCallKnown { info } => { + let ReturnCallInfo { + dest, uses, tmp, .. + } = &mut **info; + collector.reg_fixed_def(tmp, regs::r11()); + // Same as in the `Inst::CallKnown` branch. + debug_assert_ne!(*dest, ExternalName::LibCall(LibCall::Probestack)); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + } + + Inst::ReturnCallUnknown { info } => { + let ReturnCallInfo { + dest, uses, tmp, .. + } = &mut **info; + + // TODO(https://github.com/bytecodealliance/regalloc2/issues/145): + // This shouldn't be a fixed register constraint, but it's not clear how to + // pick a register that won't be clobbered by the callee-save restore code + // emitted with a return_call_indirect. r10 is caller-saved, so this should be + // safe to use. + collector.reg_fixed_use(dest, regs::r10()); + + collector.reg_fixed_def(tmp, regs::r11()); + for CallArgPair { vreg, preg } in uses { + collector.reg_fixed_use(vreg, *preg); + } + } + + Inst::JmpTableSeq { + idx, tmp1, tmp2, .. + } => { + collector.reg_use(idx); + collector.reg_early_def(tmp1); + // In the sequence emitted for this pseudoinstruction in emit.rs, + // tmp2 is only written after idx is read, so it doesn't need to be + // an early def. + collector.reg_def(tmp2); + } + + Inst::JmpUnknown { target } => { + target.get_operands(collector); + } + + Inst::LoadExtName { dst, .. } => { + collector.reg_def(dst); + } + + Inst::LockCmpxchg { + replacement, + expected, + mem, + dst_old, + .. + } => { + collector.reg_use(replacement); + collector.reg_fixed_use(expected, regs::rax()); + collector.reg_fixed_def(dst_old, regs::rax()); + mem.get_operands(collector); + } + + Inst::LockCmpxchg16b { + replacement_low, + replacement_high, + expected_low, + expected_high, + mem, + dst_old_low, + dst_old_high, + .. + } => { + collector.reg_fixed_use(replacement_low, regs::rbx()); + collector.reg_fixed_use(replacement_high, regs::rcx()); + collector.reg_fixed_use(expected_low, regs::rax()); + collector.reg_fixed_use(expected_high, regs::rdx()); + collector.reg_fixed_def(dst_old_low, regs::rax()); + collector.reg_fixed_def(dst_old_high, regs::rdx()); + mem.get_operands(collector); + } + + Inst::LockXadd { + operand, + mem, + dst_old, + .. + } => { + collector.reg_use(operand); + collector.reg_reuse_def(dst_old, 0); + mem.get_operands(collector); + } + + Inst::Xchg { + operand, + mem, + dst_old, + .. + } => { + collector.reg_use(operand); + collector.reg_reuse_def(dst_old, 0); + mem.get_operands(collector); + } + + Inst::AtomicRmwSeq { + operand, + temp, + dst_old, + mem, + .. + } => { + collector.reg_late_use(operand); + collector.reg_early_def(temp); + // This `fixed_def` is needed because `CMPXCHG` always uses this + // register implicitly. + collector.reg_fixed_def(dst_old, regs::rax()); + mem.get_operands_late(collector) + } + + Inst::Atomic128RmwSeq { + operand_low, + operand_high, + temp_low, + temp_high, + dst_old_low, + dst_old_high, + mem, + .. + } => { + // All registers are collected in the `Late` position so that they don't overlap. + collector.reg_late_use(operand_low); + collector.reg_late_use(operand_high); + collector.reg_fixed_def(temp_low, regs::rbx()); + collector.reg_fixed_def(temp_high, regs::rcx()); + collector.reg_fixed_def(dst_old_low, regs::rax()); + collector.reg_fixed_def(dst_old_high, regs::rdx()); + mem.get_operands_late(collector) + } + + Inst::Atomic128XchgSeq { + operand_low, + operand_high, + dst_old_low, + dst_old_high, + mem, + .. + } => { + // All registers are collected in the `Late` position so that they don't overlap. + collector.reg_fixed_late_use(operand_low, regs::rbx()); + collector.reg_fixed_late_use(operand_high, regs::rcx()); + collector.reg_fixed_def(dst_old_low, regs::rax()); + collector.reg_fixed_def(dst_old_high, regs::rdx()); + mem.get_operands_late(collector) + } + + Inst::Args { args } => { + for ArgPair { vreg, preg } in args { + collector.reg_fixed_def(vreg, *preg); + } + } + + Inst::Rets { rets } => { + // The return value(s) are live-out; we represent this + // with register uses on the return instruction. + for RetPair { vreg, preg } in rets { + collector.reg_fixed_use(vreg, *preg); + } + } + + Inst::JmpKnown { .. } + | Inst::JmpIf { .. } + | Inst::JmpCond { .. } + | Inst::Ret { .. } + | Inst::Nop { .. } + | Inst::TrapIf { .. } + | Inst::TrapIfAnd { .. } + | Inst::TrapIfOr { .. } + | Inst::Hlt + | Inst::Ud2 { .. } + | Inst::Fence { .. } => { + // No registers are used. + } + + Inst::ElfTlsGetAddr { dst, .. } | Inst::MachOTlsGetAddr { dst, .. } => { + collector.reg_fixed_def(dst, regs::rax()); + // All caller-saves are clobbered. + // + // We use the SysV calling convention here because the + // pseudoinstruction (and relocation that it emits) is specific to + // ELF systems; other x86-64 targets with other conventions (i.e., + // Windows) use different TLS strategies. + let mut clobbers = X64ABIMachineSpec::get_regs_clobbered_by_call(CallConv::SystemV); + clobbers.remove(regs::gpr_preg(regs::ENC_RAX)); + collector.reg_clobbers(clobbers); + } + + Inst::CoffTlsGetAddr { dst, tmp, .. } => { + // We also use the gs register. But that register is not allocatable by the + // register allocator, so we don't need to mark it as used here. + + // We use %rax to set the address + collector.reg_fixed_def(dst, regs::rax()); + + // We use %rcx as a temporary variable to load the _tls_index + collector.reg_fixed_def(tmp, regs::rcx()); + } + + Inst::Unwind { .. } => {} + + Inst::DummyUse { reg } => { + collector.reg_use(reg); + } + } +} + +//============================================================================= +// Instructions: misc functions and external interface + +impl MachInst for Inst { + type ABIMachineSpec = X64ABIMachineSpec; + + fn get_operands(&mut self, collector: &mut impl OperandVisitor) { + x64_get_operands(self, collector) + } + + fn is_move(&self) -> Option<(Writable, Reg)> { + match self { + // Note (carefully!) that a 32-bit mov *isn't* a no-op since it zeroes + // out the upper 32 bits of the destination. For example, we could + // conceivably use `movl %reg, %reg` to zero out the top 32 bits of + // %reg. + Self::MovRR { size, src, dst, .. } if *size == OperandSize::Size64 => { + Some((dst.to_writable_reg(), src.to_reg())) + } + // Note as well that MOVS[S|D] when used in the `XmmUnaryRmR` context are pure moves of + // scalar floating-point values (and annotate `dst` as `def`s to the register allocator) + // whereas the same operation in a packed context, e.g. `XMM_RM_R`, is used to merge a + // value into the lowest lane of a vector (not a move). + Self::XmmUnaryRmR { op, src, dst, .. } + if *op == SseOpcode::Movss + || *op == SseOpcode::Movsd + || *op == SseOpcode::Movaps + || *op == SseOpcode::Movapd + || *op == SseOpcode::Movups + || *op == SseOpcode::Movupd + || *op == SseOpcode::Movdqa + || *op == SseOpcode::Movdqu => + { + if let RegMem::Reg { reg } = src.clone().to_reg_mem() { + Some((dst.to_writable_reg(), reg)) + } else { + None + } + } + _ => None, + } + } + + fn is_included_in_clobbers(&self) -> bool { + match self { + &Inst::Args { .. } => false, + _ => true, + } + } + + fn is_trap(&self) -> bool { + match self { + Self::Ud2 { .. } => true, + _ => false, + } + } + + fn is_args(&self) -> bool { + match self { + Self::Args { .. } => true, + _ => false, + } + } + + fn is_term(&self) -> MachTerminator { + match self { + // Interesting cases. + &Self::Rets { .. } => MachTerminator::Ret, + &Self::ReturnCallKnown { .. } | &Self::ReturnCallUnknown { .. } => { + MachTerminator::RetCall + } + &Self::JmpKnown { .. } => MachTerminator::Uncond, + &Self::JmpCond { .. } => MachTerminator::Cond, + &Self::JmpTableSeq { .. } => MachTerminator::Indirect, + // All other cases are boring. + _ => MachTerminator::None, + } + } + + fn is_mem_access(&self) -> bool { + panic!("TODO FILL ME OUT") + } + + fn gen_move(dst_reg: Writable, src_reg: Reg, ty: Type) -> Inst { + trace!( + "Inst::gen_move {:?} -> {:?} (type: {:?})", + src_reg, + dst_reg.to_reg(), + ty + ); + let rc_dst = dst_reg.to_reg().class(); + let rc_src = src_reg.class(); + // If this isn't true, we have gone way off the rails. + debug_assert!(rc_dst == rc_src); + match rc_dst { + RegClass::Int => Inst::mov_r_r(OperandSize::Size64, src_reg, dst_reg), + RegClass::Float => { + // The Intel optimization manual, in "3.5.1.13 Zero-Latency MOV Instructions", + // doesn't include MOVSS/MOVSD as instructions with zero-latency. Use movaps for + // those, which may write more lanes that we need, but are specified to have + // zero-latency. + let opcode = match ty { + types::F16 | types::F32 | types::F64 | types::F32X4 => SseOpcode::Movaps, + types::F64X2 => SseOpcode::Movapd, + _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 128 => SseOpcode::Movdqa, + _ => unimplemented!("unable to move type: {}", ty), + }; + Inst::xmm_unary_rm_r(opcode, RegMem::reg(src_reg), dst_reg) + } + RegClass::Vector => unreachable!(), + } + } + + fn gen_nop(preferred_size: usize) -> Inst { + Inst::nop(std::cmp::min(preferred_size, 15) as u8) + } + + fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> { + match ty { + types::I8 => Ok((&[RegClass::Int], &[types::I8])), + types::I16 => Ok((&[RegClass::Int], &[types::I16])), + types::I32 => Ok((&[RegClass::Int], &[types::I32])), + types::I64 => Ok((&[RegClass::Int], &[types::I64])), + types::F16 => Ok((&[RegClass::Float], &[types::F16])), + types::F32 => Ok((&[RegClass::Float], &[types::F32])), + types::F64 => Ok((&[RegClass::Float], &[types::F64])), + types::F128 => Ok((&[RegClass::Float], &[types::F128])), + types::I128 => Ok((&[RegClass::Int, RegClass::Int], &[types::I64, types::I64])), + _ if ty.is_vector() => { + assert!(ty.bits() <= 128); + Ok((&[RegClass::Float], &[types::I8X16])) + } + _ => Err(CodegenError::Unsupported(format!( + "Unexpected SSA-value type: {ty}" + ))), + } + } + + fn canonical_type_for_rc(rc: RegClass) -> Type { + match rc { + RegClass::Float => types::I8X16, + RegClass::Int => types::I64, + RegClass::Vector => unreachable!(), + } + } + + fn gen_jump(label: MachLabel) -> Inst { + Inst::jmp_known(label) + } + + fn gen_imm_u64(value: u64, dst: Writable) -> Option { + Some(Inst::imm(OperandSize::Size64, value, dst)) + } + + fn gen_imm_f64(value: f64, tmp: Writable, dst: Writable) -> SmallVec<[Self; 2]> { + let imm_to_gpr = Inst::imm(OperandSize::Size64, value.to_bits(), tmp); + let gpr_to_xmm = Self::gpr_to_xmm( + SseOpcode::Movd, + tmp.to_reg().into(), + OperandSize::Size64, + dst, + ); + smallvec![imm_to_gpr, gpr_to_xmm] + } + + fn gen_dummy_use(reg: Reg) -> Self { + Inst::DummyUse { reg } + } + + fn worst_case_size() -> CodeOffset { + 15 + } + + fn ref_type_regclass(_: &settings::Flags) -> RegClass { + RegClass::Int + } + + fn is_safepoint(&self) -> bool { + match self { + Inst::CallKnown { .. } | Inst::CallUnknown { .. } => true, + _ => false, + } + } + + fn function_alignment() -> FunctionAlignment { + FunctionAlignment { + minimum: 1, + // Change the alignment from 16-bytes to 32-bytes for better performance. + // fix-8573: https://github.com/bytecodealliance/wasmtime/issues/8573 + preferred: 32, + } + } + + type LabelUse = LabelUse; + + const TRAP_OPCODE: &'static [u8] = &[0x0f, 0x0b]; +} + +/// Constant state used during emissions of a sequence of instructions. +pub struct EmitInfo { + pub(super) flags: settings::Flags, + isa_flags: x64_settings::Flags, +} + +impl EmitInfo { + /// Create a constant state for emission of instructions. + pub fn new(flags: settings::Flags, isa_flags: x64_settings::Flags) -> Self { + Self { flags, isa_flags } + } +} + +impl MachInstEmit for Inst { + type State = EmitState; + type Info = EmitInfo; + + fn emit(&self, sink: &mut MachBuffer, info: &Self::Info, state: &mut Self::State) { + emit::emit(self, sink, info, state); + } + + fn pretty_print_inst(&self, _: &mut Self::State) -> String { + PrettyPrint::pretty_print(self, 0) + } +} + +/// A label-use (internal relocation) in generated code. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LabelUse { + /// A 32-bit offset from location of relocation itself, added to the existing value at that + /// location. Used for control flow instructions which consider an offset from the start of the + /// next instruction (so the size of the payload -- 4 bytes -- is subtracted from the payload). + JmpRel32, + + /// A 32-bit offset from location of relocation itself, added to the existing value at that + /// location. + PCRel32, +} + +impl MachInstLabelUse for LabelUse { + const ALIGN: CodeOffset = 1; + + fn max_pos_range(self) -> CodeOffset { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => 0x7fff_ffff, + } + } + + fn max_neg_range(self) -> CodeOffset { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => 0x8000_0000, + } + } + + fn patch_size(self) -> CodeOffset { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => 4, + } + } + + fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) { + let pc_rel = (label_offset as i64) - (use_offset as i64); + debug_assert!(pc_rel <= self.max_pos_range() as i64); + debug_assert!(pc_rel >= -(self.max_neg_range() as i64)); + let pc_rel = pc_rel as u32; + match self { + LabelUse::JmpRel32 => { + let addend = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]); + let value = pc_rel.wrapping_add(addend).wrapping_sub(4); + buffer.copy_from_slice(&value.to_le_bytes()[..]); + } + LabelUse::PCRel32 => { + let addend = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]); + let value = pc_rel.wrapping_add(addend); + buffer.copy_from_slice(&value.to_le_bytes()[..]); + } + } + } + + fn supports_veneer(self) -> bool { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => false, + } + } + + fn veneer_size(self) -> CodeOffset { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => 0, + } + } + + fn worst_case_veneer_size() -> CodeOffset { + 0 + } + + fn generate_veneer(self, _: &mut [u8], _: CodeOffset) -> (CodeOffset, LabelUse) { + match self { + LabelUse::JmpRel32 | LabelUse::PCRel32 => { + panic!("Veneer not supported for JumpRel32 label-use."); + } + } + } + + fn from_reloc(reloc: Reloc, addend: Addend) -> Option { + match (reloc, addend) { + (Reloc::X86CallPCRel4, -4) => Some(LabelUse::JmpRel32), + _ => None, + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/regs.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/regs.rs new file mode 100644 index 00000000000000..d3a06da70a0310 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/regs.rs @@ -0,0 +1,275 @@ +//! Register definitions for regalloc2. +//! +//! We define 16 GPRs, with indices equal to the hardware encoding, +//! and 16 XMM registers. +//! +//! Note also that we make use of pinned VRegs to refer to PRegs. + +use crate::machinst::{RealReg, Reg}; +use alloc::string::ToString; +use regalloc2::{PReg, RegClass, VReg}; +use std::string::String; + +// Hardware encodings (note the special rax, rcx, rdx, rbx order). + +pub const ENC_RAX: u8 = 0; +pub const ENC_RCX: u8 = 1; +pub const ENC_RDX: u8 = 2; +pub const ENC_RBX: u8 = 3; +pub const ENC_RSP: u8 = 4; +pub const ENC_RBP: u8 = 5; +pub const ENC_RSI: u8 = 6; +pub const ENC_RDI: u8 = 7; +pub const ENC_R8: u8 = 8; +pub const ENC_R9: u8 = 9; +pub const ENC_R10: u8 = 10; +pub const ENC_R11: u8 = 11; +pub const ENC_R12: u8 = 12; +pub const ENC_R13: u8 = 13; +pub const ENC_R14: u8 = 14; +pub const ENC_R15: u8 = 15; + +// Constructors for Regs. + +fn gpr(enc: u8) -> Reg { + let preg = gpr_preg(enc); + Reg::from(VReg::new(preg.index(), RegClass::Int)) +} +pub(crate) const fn gpr_preg(enc: u8) -> PReg { + PReg::new(enc as usize, RegClass::Int) +} + +pub(crate) fn rsi() -> Reg { + gpr(ENC_RSI) +} +pub(crate) fn rdi() -> Reg { + gpr(ENC_RDI) +} +pub(crate) fn rax() -> Reg { + gpr(ENC_RAX) +} +pub(crate) fn rcx() -> Reg { + gpr(ENC_RCX) +} +pub(crate) fn rdx() -> Reg { + gpr(ENC_RDX) +} +pub(crate) fn r8() -> Reg { + gpr(ENC_R8) +} +pub(crate) fn r9() -> Reg { + gpr(ENC_R9) +} +pub(crate) fn r10() -> Reg { + gpr(ENC_R10) +} +pub(crate) fn r11() -> Reg { + gpr(ENC_R11) +} +pub(crate) fn r12() -> Reg { + gpr(ENC_R12) +} +pub(crate) fn r13() -> Reg { + gpr(ENC_R13) +} +pub(crate) fn r14() -> Reg { + gpr(ENC_R14) +} +pub(crate) fn rbx() -> Reg { + gpr(ENC_RBX) +} + +pub(crate) fn r15() -> Reg { + gpr(ENC_R15) +} + +pub(crate) fn rsp() -> Reg { + gpr(ENC_RSP) +} +pub(crate) fn rbp() -> Reg { + gpr(ENC_RBP) +} + +/// The pinned register on this architecture. +/// It must be the same as Spidermonkey's HeapReg, as found in this file. +/// https://searchfox.org/mozilla-central/source/js/src/jit/x64/Assembler-x64.h#99 +pub(crate) fn pinned_reg() -> Reg { + r15() +} + +fn fpr(enc: u8) -> Reg { + let preg = fpr_preg(enc); + Reg::from(VReg::new(preg.index(), RegClass::Float)) +} + +pub(crate) const fn fpr_preg(enc: u8) -> PReg { + PReg::new(enc as usize, RegClass::Float) +} + +pub(crate) fn xmm0() -> Reg { + fpr(0) +} +pub(crate) fn xmm1() -> Reg { + fpr(1) +} +pub(crate) fn xmm2() -> Reg { + fpr(2) +} +pub(crate) fn xmm3() -> Reg { + fpr(3) +} +pub(crate) fn xmm4() -> Reg { + fpr(4) +} +pub(crate) fn xmm5() -> Reg { + fpr(5) +} +pub(crate) fn xmm6() -> Reg { + fpr(6) +} +pub(crate) fn xmm7() -> Reg { + fpr(7) +} +pub(crate) fn xmm8() -> Reg { + fpr(8) +} +pub(crate) fn xmm9() -> Reg { + fpr(9) +} +pub(crate) fn xmm10() -> Reg { + fpr(10) +} +pub(crate) fn xmm11() -> Reg { + fpr(11) +} +pub(crate) fn xmm12() -> Reg { + fpr(12) +} +pub(crate) fn xmm13() -> Reg { + fpr(13) +} +pub(crate) fn xmm14() -> Reg { + fpr(14) +} +pub(crate) fn xmm15() -> Reg { + fpr(15) +} + +/// Give the name of a RealReg. +pub fn realreg_name(reg: RealReg) -> &'static str { + let preg = PReg::from(reg); + match preg.class() { + RegClass::Int => match preg.hw_enc() as u8 { + ENC_RAX => "%rax", + ENC_RBX => "%rbx", + ENC_RCX => "%rcx", + ENC_RDX => "%rdx", + ENC_RSI => "%rsi", + ENC_RDI => "%rdi", + ENC_RBP => "%rbp", + ENC_RSP => "%rsp", + ENC_R8 => "%r8", + ENC_R9 => "%r9", + ENC_R10 => "%r10", + ENC_R11 => "%r11", + ENC_R12 => "%r12", + ENC_R13 => "%r13", + ENC_R14 => "%r14", + ENC_R15 => "%r15", + _ => panic!("Invalid PReg: {preg:?}"), + }, + RegClass::Float => match preg.hw_enc() { + 0 => "%xmm0", + 1 => "%xmm1", + 2 => "%xmm2", + 3 => "%xmm3", + 4 => "%xmm4", + 5 => "%xmm5", + 6 => "%xmm6", + 7 => "%xmm7", + 8 => "%xmm8", + 9 => "%xmm9", + 10 => "%xmm10", + 11 => "%xmm11", + 12 => "%xmm12", + 13 => "%xmm13", + 14 => "%xmm14", + 15 => "%xmm15", + _ => panic!("Invalid PReg: {preg:?}"), + }, + RegClass::Vector => unreachable!(), + } +} + +pub fn show_reg(reg: Reg) -> String { + if let Some(rreg) = reg.to_real_reg() { + realreg_name(rreg).to_string() + } else { + format!("%{reg:?}") + } +} + +/// If `ireg` denotes an I64-classed reg, make a best-effort attempt to show its name at some +/// smaller size (4, 2 or 1 bytes). +pub fn show_ireg_sized(reg: Reg, size: u8) -> String { + let mut s = show_reg(reg); + + if reg.class() != RegClass::Int || size == 8 { + // We can't do any better. + return s; + } + + if reg.is_real() { + // Change (eg) "rax" into "eax", "ax" or "al" as appropriate. This is something one could + // describe diplomatically as "a kludge", but it's only debug code. + let remapper = match s.as_str() { + "%rax" => Some(["%eax", "%ax", "%al"]), + "%rbx" => Some(["%ebx", "%bx", "%bl"]), + "%rcx" => Some(["%ecx", "%cx", "%cl"]), + "%rdx" => Some(["%edx", "%dx", "%dl"]), + "%rsi" => Some(["%esi", "%si", "%sil"]), + "%rdi" => Some(["%edi", "%di", "%dil"]), + "%rbp" => Some(["%ebp", "%bp", "%bpl"]), + "%rsp" => Some(["%esp", "%sp", "%spl"]), + "%r8" => Some(["%r8d", "%r8w", "%r8b"]), + "%r9" => Some(["%r9d", "%r9w", "%r9b"]), + "%r10" => Some(["%r10d", "%r10w", "%r10b"]), + "%r11" => Some(["%r11d", "%r11w", "%r11b"]), + "%r12" => Some(["%r12d", "%r12w", "%r12b"]), + "%r13" => Some(["%r13d", "%r13w", "%r13b"]), + "%r14" => Some(["%r14d", "%r14w", "%r14b"]), + "%r15" => Some(["%r15d", "%r15w", "%r15b"]), + _ => None, + }; + if let Some(smaller_names) = remapper { + match size { + 4 => s = smaller_names[0].into(), + 2 => s = smaller_names[1].into(), + 1 => s = smaller_names[2].into(), + _ => panic!("show_ireg_sized: real"), + } + } + } else { + // Add a "l", "w" or "b" suffix to RegClass::I64 vregs used at narrower widths. + let suffix = match size { + 4 => "l", + 2 => "w", + 1 => "b", + _ => panic!("show_ireg_sized: virtual"), + }; + s = s + suffix; + } + + s +} + +// N.B.: this is not an `impl PrettyPrint for Reg` because it is +// specific to x64; other backends have analogous functions. The +// disambiguation happens statically by virtue of higher-level, +// x64-specific, types calling the right `pretty_print_reg`. (In other +// words, we can't pretty-print a `Reg` all by itself in a build that +// may have multiple backends; but we can pretty-print one as part of +// an x64 Inst or x64 RegMemImm.) +pub fn pretty_print_reg(reg: Reg, size: u8) -> String { + show_ireg_sized(reg, size) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/stack_switch.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/stack_switch.rs new file mode 100644 index 00000000000000..b96eb9362072a1 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/stack_switch.rs @@ -0,0 +1,52 @@ +use crate::{isa::x64::inst::regs, machinst::Reg}; + +/// The `stack_switch` instruction loads information about the stack to switch +/// to and stores information about the current stack by receiving pointers to +/// memory laid out as in the struct `ControlContext` below. +/// +/// The instruction is only supported on x64 Linux at the moment. +/// +/// ``` +/// #[repr(C)] +/// pub struct ControlContext { +/// pub stack_pointer: *mut u8, +/// pub frame_pointer: *mut u8, +/// pub instruction_pointer: *mut u8, +/// } +/// ``` +/// +/// Note that this layout is deliberately chosen to make frame pointer walking +/// possible, if desired: The layout enables stack layouts where a +/// `ControlContext` is part of a frame pointer chain, putting the frame pointer +/// next to the corresponding IP. +/// +/// We never actually interact with values of that type in Cranelift, but are +/// only interested in its layout for the purposes of generating code. +#[allow(dead_code)] +pub struct ControlContextLayout { + pub size: usize, + pub stack_pointer_offset: usize, + pub frame_pointer_offset: usize, + pub ip_offset: usize, +} + +pub fn control_context_layout() -> ControlContextLayout { + ControlContextLayout { + size: 24, + stack_pointer_offset: 0, + frame_pointer_offset: 8, + ip_offset: 16, + } +} + +/// The register used for handing over the payload when switching stacks. +/// +/// We must use a fixed register for sending and receiving the payload: When +/// switching from one stack to another using two matching``stack_switch`` +/// instructions, they must agree on the register where the payload is, similar +/// to a calling convention. The same holds when `stack_switch`-ing to a newly +/// initialized stack, where the entry trampoline must know which register the +/// payload is in. +pub fn payload_register() -> Reg { + regs::rdi() +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind.rs new file mode 100644 index 00000000000000..cb86c3b7ccd5a1 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind.rs @@ -0,0 +1,5 @@ +#[cfg(feature = "unwind")] +pub(crate) mod systemv; + +#[cfg(feature = "unwind")] +pub(crate) mod winx64; diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/systemv.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/systemv.rs new file mode 100644 index 00000000000000..948b9e4deb31e5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/systemv.rs @@ -0,0 +1,198 @@ +//! Unwind information for System V ABI (x86-64). + +use crate::isa::unwind::systemv::RegisterMappingError; +use crate::machinst::{Reg, RegClass}; +use gimli::{write::CommonInformationEntry, Encoding, Format, Register, X86_64}; + +/// Creates a new x86-64 common information entry (CIE). +pub fn create_cie() -> CommonInformationEntry { + use gimli::write::CallFrameInstruction; + + let mut entry = CommonInformationEntry::new( + Encoding { + address_size: 8, + format: Format::Dwarf32, + version: 1, + }, + 1, // Code alignment factor + -8, // Data alignment factor + X86_64::RA, + ); + + // Every frame will start with the call frame address (CFA) at RSP+8 + // It is +8 to account for the push of the return address by the call instruction + entry.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8)); + + // Every frame will start with the return address at RSP (CFA-8 = RSP+8-8 = RSP) + entry.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8)); + + entry +} + +/// Map Cranelift registers to their corresponding Gimli registers. +pub fn map_reg(reg: Reg) -> Result { + // Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow + const X86_GP_REG_MAP: [gimli::Register; 16] = [ + X86_64::RAX, + X86_64::RCX, + X86_64::RDX, + X86_64::RBX, + X86_64::RSP, + X86_64::RBP, + X86_64::RSI, + X86_64::RDI, + X86_64::R8, + X86_64::R9, + X86_64::R10, + X86_64::R11, + X86_64::R12, + X86_64::R13, + X86_64::R14, + X86_64::R15, + ]; + const X86_XMM_REG_MAP: [gimli::Register; 16] = [ + X86_64::XMM0, + X86_64::XMM1, + X86_64::XMM2, + X86_64::XMM3, + X86_64::XMM4, + X86_64::XMM5, + X86_64::XMM6, + X86_64::XMM7, + X86_64::XMM8, + X86_64::XMM9, + X86_64::XMM10, + X86_64::XMM11, + X86_64::XMM12, + X86_64::XMM13, + X86_64::XMM14, + X86_64::XMM15, + ]; + + match reg.class() { + RegClass::Int => { + // x86 GP registers have a weird mapping to DWARF registers, so we use a + // lookup table. + Ok(X86_GP_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]) + } + RegClass::Float => Ok(X86_XMM_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]), + RegClass::Vector => unreachable!(), + } +} + +pub(crate) struct RegisterMapper; + +impl crate::isa::unwind::systemv::RegisterMapper for RegisterMapper { + fn map(&self, reg: Reg) -> Result { + Ok(map_reg(reg)?.0) + } + fn fp(&self) -> Option { + Some(X86_64::RBP.0) + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::{ + types, AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, + }; + use crate::isa::{lookup, CallConv}; + use crate::settings::{builder, Flags}; + use crate::Context; + use gimli::write::Address; + use target_lexicon::triple; + + #[test] + fn test_simple_func() { + let isa = lookup(triple!("x86_64")) + .expect("expect x86 ISA") + .finish(Flags::new(builder())) + .expect("expect backend creation to succeed"); + + let mut context = Context::for_function(create_function( + CallConv::SystemV, + Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)), + )); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(1234)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(1234), length: 17, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"); + } + + fn create_function(call_conv: CallConv, stack_slot: Option) -> Function { + let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv)); + + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().return_(&[]); + + if let Some(stack_slot) = stack_slot { + func.sized_stack_slots.push(stack_slot); + } + + func + } + + #[test] + fn test_multi_return_func() { + let isa = lookup(triple!("x86_64")) + .expect("expect x86 ISA") + .finish(Flags::new(builder())) + .expect("expect backend creation to succeed"); + + let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV)); + + let code = context + .compile(&*isa, &mut Default::default()) + .expect("expected compilation"); + + let fde = match code + .create_unwind_info(isa.as_ref()) + .expect("can create unwind info") + { + Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => { + info.to_fde(Address::Constant(4321)) + } + _ => panic!("expected unwind information"), + }; + + assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(4321), length: 22, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"); + } + + fn create_multi_return_function(call_conv: CallConv) -> Function { + let mut sig = Signature::new(call_conv); + sig.params.push(AbiParam::new(types::I32)); + let mut func = Function::with_name_signature(Default::default(), sig); + + let block0 = func.dfg.make_block(); + let v0 = func.dfg.append_block_param(block0, types::I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + pos.ins().brif(v0, block2, &[], block1, &[]); + + pos.insert_block(block1); + pos.ins().return_(&[]); + + pos.insert_block(block2); + pos.ins().return_(&[]); + + func + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/winx64.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/winx64.rs new file mode 100644 index 00000000000000..f848a5baf76f12 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/inst/unwind/winx64.rs @@ -0,0 +1,16 @@ +//! Unwind information for Windows x64 ABI. + +use crate::machinst::{Reg, RegClass}; + +pub(crate) struct RegisterMapper; + +impl crate::isa::unwind::winx64::RegisterMapper for RegisterMapper { + fn map(reg: Reg) -> crate::isa::unwind::winx64::MappedRegister { + use crate::isa::unwind::winx64::MappedRegister; + match reg.class() { + RegClass::Int => MappedRegister::Int(reg.to_real_reg().unwrap().hw_enc()), + RegClass::Float => MappedRegister::Xmm(reg.to_real_reg().unwrap().hw_enc()), + RegClass::Vector => unreachable!(), + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.isle b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.isle new file mode 100644 index 00000000000000..ab44d23aece4aa --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.isle @@ -0,0 +1,5000 @@ +;; x86-64 instruction selection and CLIF-to-MachInst lowering. + +;; The main lowering constructor term: takes a clif `Inst` and returns the +;; register(s) within which the lowered instruction's result values live. +(spec (lower arg) + (provide (= result arg))) +(decl partial lower (Inst) InstOutput) + +;; A variant of the main lowering constructor term, used for branches. +;; The only difference is that it gets an extra argument holding a vector +;; of branch targets to be used. +(decl partial lower_branch (Inst MachLabelSlice) Unit) + +;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. +(rule (lower (has_type (fits_in_64 ty) + (iconst (u64_from_imm64 x)))) + (imm ty x)) + +;; `i128` +(rule 1 (lower (has_type $I128 + (iconst (u64_from_imm64 x)))) + (value_regs (imm $I64 x) + (imm $I64 0))) + +;;;; Rules for `f16const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f16const (u16_from_ieee16 x))) + (imm $F16 x)) + +;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f32const (u32_from_ieee32 x))) + (imm $F32 x)) + +;;;; Rules for `f64const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (f64const (u64_from_ieee64 x))) + (imm $F64 x)) + +;;;; Rules for `f128const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (f128const const)) + ;; TODO use Inst::gen_constant() instead. + (x64_xmm_load_const $F128 (const_to_vconst const))) + +(rule 1 (lower (f128const (u128_from_constant 0))) + (xmm_zero $F128)) + +;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +;; Base case for 8 and 16-bit types +(rule -6 (lower (has_type (fits_in_16 ty) + (iadd x y))) + (x64_add ty x y)) + +;; Base case for 32 and 64-bit types which might end up using the `lea` +;; instruction to fold multiple operations into one. +;; +;; Note that at this time this always generates a `lea` pseudo-instruction, +;; but the actual instruction emitted might be an `add` if it's equivalent. +;; For more details on this see the `emit.rs` logic to emit +;; `LoadEffectiveAddress`. +(rule iadd_base_case_32_or_64_lea -5 (lower (has_type (ty_32_or_64 ty) (iadd x y))) + (x64_lea ty (to_amode_add (mem_flags_trusted) x y (zero_offset)))) + +;; Higher-priority cases than the previous two where a load can be sunk into +;; the add instruction itself. Note that both operands are tested for +;; sink-ability since addition is commutative +(rule -4 (lower (has_type (fits_in_64 ty) + (iadd x (sinkable_load y)))) + (x64_add ty x y)) +(rule -3 (lower (has_type (fits_in_64 ty) + (iadd (sinkable_load x) y))) + (x64_add ty y x)) + +;; SSE. + +(rule (lower (has_type (multi_lane 8 16) + (iadd x y))) + (x64_paddb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (iadd x y))) + (x64_paddw x y)) + +(rule (lower (has_type (multi_lane 32 4) + (iadd x y))) + (x64_paddd x y)) + +(rule (lower (has_type (multi_lane 64 2) + (iadd x y))) + (x64_paddq x y)) + +;; `i128` +(rule 1 (lower (has_type $I128 (iadd x y))) + ;; Get the high/low registers for `x`. + (let ((x_regs ValueRegs x) + (y_regs ValueRegs y)) + (iadd128 + (value_regs_get_gpr x_regs 0) + (value_regs_get_gpr x_regs 1) + (value_regs_get_gpr y_regs 0) + (value_regs_get_gpr y_regs 1)))) +(rule 2 (lower (has_type $I128 (iadd x (iconcat y_lo y_hi)))) + (let ((x_regs ValueRegs x)) + (iadd128 (value_regs_get_gpr x 0) (value_regs_get_gpr x 1) y_lo y_hi))) +(rule 3 (lower (has_type $I128 (iadd x (uextend y @ (value_type $I64))))) + (let ((x_regs ValueRegs x)) + (iadd128 (value_regs_get_gpr x 0) (value_regs_get_gpr x 1) + y (RegMemImm.Imm 0)))) + +;; Helper for lowering 128-bit addition with the 64-bit halves of the lhs/rhs +;; already split. The first two arguments are lo/hi for the lhs and the second +;; two are lo/hi for the rhs. +(decl iadd128 (Gpr Gpr GprMemImm GprMemImm) ValueRegs) +(rule (iadd128 x_lo x_hi y_lo y_hi) + (with_flags (x64_add_with_flags_paired $I64 x_lo y_lo) + (x64_adc_paired $I64 x_hi y_hi))) + +;;;; Helpers for `*_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl construct_overflow_op (CC ProducesFlags) InstOutput) +(rule (construct_overflow_op cc inst) + (let ((results ValueRegs (with_flags inst + (x64_setcc_paired cc)))) + (output_pair (value_regs_get results 0) + (value_regs_get results 1)))) + +(decl construct_overflow_op_alu (Type CC AluRmiROpcode Gpr GprMemImm) InstOutput) +(rule (construct_overflow_op_alu ty cc alu_op src1 src2) + (construct_overflow_op cc (x64_alurmi_with_flags_paired alu_op ty src1 src2))) + +;; This essentially creates +;; alu_ x_lo, y_lo +;; alu_ x_hi, y_hi +;; set r8 +(decl construct_overflow_op_alu_128 (CC AluRmiROpcode AluRmiROpcode Value Value) InstOutput) +(rule (construct_overflow_op_alu_128 cc op1 op2 x y) + ;; Get the high/low registers for `x`. + (let ((x_regs ValueRegs x) + (x_lo Gpr (value_regs_get_gpr x_regs 0)) + (x_hi Gpr (value_regs_get_gpr x_regs 1))) + ;; Get the high/low registers for `y`. + (let ((y_regs ValueRegs y) + (y_lo Gpr (value_regs_get_gpr y_regs 0)) + (y_hi Gpr (value_regs_get_gpr y_regs 1))) + (let ((lo_inst ProducesFlags (x64_alurmi_with_flags_paired op1 $I64 x_lo y_lo)) + (hi_inst ConsumesAndProducesFlags (x64_alurmi_with_flags_chained op2 $I64 x_hi y_hi)) + (of_inst ConsumesFlags (x64_setcc_paired cc)) + + (result MultiReg (with_flags_chained lo_inst hi_inst of_inst))) + (multi_reg_to_pair_and_single result))))) + +;;;; Rules for `uadd_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (uadd_overflow x y @ (value_type (fits_in_64 ty)))) + (construct_overflow_op_alu ty (CC.B) (AluRmiROpcode.Add) x y)) + +;; i128 gets lowered into adc and add +(rule 0 (lower (uadd_overflow x y @ (value_type $I128))) + (construct_overflow_op_alu_128 (CC.B) (AluRmiROpcode.Add) (AluRmiROpcode.Adc) x y)) + +;;;; Rules for `sadd_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (sadd_overflow x y @ (value_type (fits_in_64 ty)))) + (construct_overflow_op_alu ty (CC.O) (AluRmiROpcode.Add) x y)) + +(rule 0 (lower (sadd_overflow x y @ (value_type $I128))) + (construct_overflow_op_alu_128 (CC.O) (AluRmiROpcode.Add) (AluRmiROpcode.Adc) x y)) + +;;;; Rules for `usub_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (usub_overflow x y @ (value_type (fits_in_64 ty)))) + (construct_overflow_op_alu ty (CC.B) (AluRmiROpcode.Sub) x y)) + +(rule 0 (lower (usub_overflow x y @ (value_type $I128))) + (construct_overflow_op_alu_128 (CC.B) (AluRmiROpcode.Sub) (AluRmiROpcode.Sbb) x y)) + +;;;; Rules for `ssub_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (ssub_overflow x y @ (value_type (fits_in_64 ty)))) + (construct_overflow_op_alu ty (CC.O) (AluRmiROpcode.Sub) x y)) + +(rule 0 (lower (ssub_overflow x y @ (value_type $I128))) + (construct_overflow_op_alu_128 (CC.O) (AluRmiROpcode.Sub) (AluRmiROpcode.Sbb) x y)) + +;;;; Rules for `umul_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower (umul_overflow x y @ (value_type $I8))) + (construct_overflow_op (CC.O) (x64_mul8_with_flags_paired false x y))) + +(rule 3 (lower (umul_overflow x y @ (value_type (ty_int_ref_16_to_64 ty)))) + (construct_overflow_op (CC.O) (x64_mul_lo_with_flags_paired ty false x y))) + +;;;; Rules for `smul_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower (smul_overflow x y @ (value_type $I8))) + (construct_overflow_op (CC.O) (x64_mul8_with_flags_paired true x y))) + +(rule 3 (lower (smul_overflow x y @ (value_type (ty_int_ref_16_to_64 ty)))) + (construct_overflow_op (CC.O) (x64_mul_lo_with_flags_paired ty true x y))) + +;;;; Rules for `sadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (multi_lane 8 16) + (sadd_sat x y))) + (x64_paddsb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (sadd_sat x y))) + (x64_paddsw x y)) + +;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (multi_lane 8 16) + (uadd_sat x y))) + (x64_paddusb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (uadd_sat x y))) + (x64_paddusw x y)) + +;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +;; Sub two registers. +(rule -3 (lower (has_type (fits_in_64 ty) + (isub x y))) + (x64_sub ty x y)) + +;; SSE. + +(rule (lower (has_type (multi_lane 8 16) + (isub x y))) + (x64_psubb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (isub x y))) + (x64_psubw x y)) + +(rule (lower (has_type (multi_lane 32 4) + (isub x y))) + (x64_psubd x y)) + +(rule (lower (has_type (multi_lane 64 2) + (isub x y))) + (x64_psubq x y)) + +;; `i128` +(rule 1 (lower (has_type $I128 (isub x y))) + ;; Get the high/low registers for `x`. + (let ((x_regs ValueRegs x) + (y_regs ValueRegs y)) + (isub128 + (value_regs_get_gpr x_regs 0) + (value_regs_get_gpr x_regs 1) + (value_regs_get_gpr y_regs 0) + (value_regs_get_gpr y_regs 1)))) +(rule 2 (lower (has_type $I128 (isub x (iconcat y_lo y_hi)))) + (let ((x_regs ValueRegs x)) + (isub128 (value_regs_get_gpr x 0) (value_regs_get_gpr x 1) y_lo y_hi))) +(rule 3 (lower (has_type $I128 (isub x (uextend y @ (value_type $I64))))) + (let ((x_regs ValueRegs x)) + (isub128 (value_regs_get_gpr x 0) (value_regs_get_gpr x 1) + y (RegMemImm.Imm 0)))) + +;; Helper for lowering 128-bit subtraction with the 64-bit halves of the lhs/rhs +;; already split. The first two arguments are lo/hi for the lhs and the second +;; two are lo/hi for the rhs. +(decl isub128 (Gpr Gpr GprMemImm GprMemImm) ValueRegs) +(rule (isub128 x_lo x_hi y_lo y_hi) + (with_flags (x64_sub_with_flags_paired $I64 x_lo y_lo) + (x64_sbb_paired $I64 x_hi y_hi))) + +;;;; Rules for `ssub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (multi_lane 8 16) + (ssub_sat x y))) + (x64_psubsb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (ssub_sat x y))) + (x64_psubsw x y)) + +;;;; Rules for `usub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (multi_lane 8 16) + (usub_sat x y))) + (x64_psubusb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (usub_sat x y))) + (x64_psubusw x y)) + +;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `{i,b}64` and smaller. + +;; And two registers. +(rule 0 (lower (has_type ty (band x y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_and ty x y)) + +;; The above case automatically handles when the rhs is an immediate or a +;; sinkable load, but additionally handle the lhs here. + +(rule 1 (lower (has_type ty (band (sinkable_load x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_and ty y x)) + +(rule 2 (lower (has_type ty (band (simm32_from_value x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_and ty y x)) + +;; f32 and f64 + +(rule 5 (lower (has_type (ty_scalar_float ty) (band x y))) + (sse_and ty x y)) + +;; SSE. + +(decl sse_and (Type Xmm XmmMem) Xmm) +(rule (sse_and $F32X4 x y) (x64_andps x y)) +(rule (sse_and $F64X2 x y) (x64_andpd x y)) +(rule (sse_and $F32 x y) (x64_andps x y)) +(rule (sse_and $F64 x y) (x64_andpd x y)) +(rule -1 (sse_and (multi_lane _bits _lanes) x y) (x64_pand x y)) + +(rule 6 (lower (has_type ty @ (multi_lane _bits _lanes) + (band x y))) + (sse_and ty x y)) + +;; `i128`. + +(decl and_i128 (ValueRegs ValueRegs) ValueRegs) +(rule (and_i128 x y) + (let ((x_regs ValueRegs x) + (x_lo Gpr (value_regs_get_gpr x_regs 0)) + (x_hi Gpr (value_regs_get_gpr x_regs 1)) + (y_regs ValueRegs y) + (y_lo Gpr (value_regs_get_gpr y_regs 0)) + (y_hi Gpr (value_regs_get_gpr y_regs 1))) + (value_gprs (x64_and $I64 x_lo y_lo) + (x64_and $I64 x_hi y_hi)))) + +(rule 7 (lower (has_type $I128 (band x y))) + (and_i128 x y)) + +;; Specialized lowerings for `(band x (bnot y))` which is additionally produced +;; by Cranelift's `band_not` instruction that is legalized into the simpler +;; forms early on. + +(decl sse_and_not (Type Xmm XmmMem) Xmm) +(rule (sse_and_not $F32X4 x y) (x64_andnps x y)) +(rule (sse_and_not $F64X2 x y) (x64_andnpd x y)) +(rule -1 (sse_and_not (multi_lane _bits _lanes) x y) (x64_pandn x y)) + +;; Note the flipping of operands below as we're match +;; +;; (band x (bnot y)) +;; +;; while x86 does +;; +;; pandn(x, y) = and(not(x), y) +(rule 8 (lower (has_type ty @ (multi_lane _bits _lane) (band x (bnot y)))) + (sse_and_not ty y x)) +(rule 9 (lower (has_type ty @ (multi_lane _bits _lane) (band (bnot y) x))) + (sse_and_not ty y x)) + +(rule 10 (lower (has_type ty (band x (bnot y)))) + (if (ty_int_ref_scalar_64 ty)) + (if-let true (use_bmi1)) + ;; the first argument is the one that gets inverted with andn + (x64_andn ty y x)) +(rule 11 (lower (has_type ty (band (bnot y) x))) + (if (ty_int_ref_scalar_64 ty)) + (if-let true (use_bmi1)) + (x64_andn ty y x)) + +;; Specialization of `blsr` for BMI1 + +(decl pure partial val_minus_one (Value) Value) +(rule 0 (val_minus_one (isub x (u64_from_iconst 1))) x) +(rule 0 (val_minus_one (iadd x (i64_from_iconst -1))) x) +(rule 1 (val_minus_one (iadd (i64_from_iconst -1) x)) x) + +(rule 12 (lower (has_type (ty_32_or_64 ty) (band x y))) + (if-let true (use_bmi1)) + (if-let x (val_minus_one y)) + (x64_blsr ty x)) +(rule 13 (lower (has_type (ty_32_or_64 ty) (band y x))) + (if-let true (use_bmi1)) + (if-let x (val_minus_one y)) + (x64_blsr ty x)) + +;; Specialization of `blsi` for BMI1 + +(rule 14 (lower (has_type (ty_32_or_64 ty) (band (ineg x) x))) + (if-let true (use_bmi1)) + (x64_blsi ty x)) +(rule 15 (lower (has_type (ty_32_or_64 ty) (band x (ineg x)))) + (if-let true (use_bmi1)) + (x64_blsi ty x)) + +;; Specialization of `bzhi` for BMI2 +;; +;; The `bzhi` instruction clears all bits indexed by the second operand of the +;; first operand. This is pattern-matched here with a `band` against a mask +;; which is generated to be N bits large. Note that if the index is larger than +;; the bit-width of the type then `bzhi` doesn't have the same semantics as +;; `ishl`, so an `and` instruction is required to mask the index to match the +;; semantics of Cranelift's `ishl`. + +(rule 16 (lower (has_type (ty_32_or_64 ty) (band x y))) + (if-let true (use_bmi2)) + (if-let (ishl (u64_from_iconst 1) index) (val_minus_one y)) + (x64_bzhi ty x (x64_and ty index (RegMemImm.Imm (u32_sub (ty_bits ty) 1))))) + +;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `{i,b}64` and smaller. + +;; Or two registers. +(rule 0 (lower (has_type ty (bor x y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_or ty x y)) + +;; Handle immediates/sinkable loads on the lhs in addition to the automatic +;; handling of the rhs above + +(rule 1 (lower (has_type ty (bor (sinkable_load x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_or ty y x)) + +(rule 2 (lower (has_type ty (bor (simm32_from_value x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_or ty y x)) + +;; f32 and f64 + +(rule 5 (lower (has_type (ty_scalar_float ty) (bor x y))) + (sse_or ty x y)) + +;; SSE. + +(decl sse_or (Type Xmm XmmMem) Xmm) +(rule (sse_or $F32X4 x y) (x64_orps x y)) +(rule (sse_or $F64X2 x y) (x64_orpd x y)) +(rule (sse_or $F32 x y) (x64_orps x y)) +(rule (sse_or $F64 x y) (x64_orpd x y)) +(rule -1 (sse_or (multi_lane _bits _lanes) x y) (x64_por x y)) + +(rule 6 (lower (has_type ty @ (multi_lane _bits _lanes) + (bor x y))) + (sse_or ty x y)) + +;; `{i,b}128`. + +(decl or_i128 (ValueRegs ValueRegs) ValueRegs) +(rule (or_i128 x y) + (let ((x_lo Gpr (value_regs_get_gpr x 0)) + (x_hi Gpr (value_regs_get_gpr x 1)) + (y_lo Gpr (value_regs_get_gpr y 0)) + (y_hi Gpr (value_regs_get_gpr y 1))) + (value_gprs (x64_or $I64 x_lo y_lo) + (x64_or $I64 x_hi y_hi)))) + +(rule 7 (lower (has_type $I128 (bor x y))) + (or_i128 x y)) + +;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `{i,b}64` and smaller. + +;; Xor two registers. +(rule 0 (lower (has_type ty (bxor x y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_xor ty x y)) + +;; Handle xor with lhs immediates/sinkable loads in addition to the automatic +;; handling of the rhs above. + +(rule 1 (lower (has_type ty (bxor (sinkable_load x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_xor ty y x)) + +(rule 4 (lower (has_type ty (bxor (simm32_from_value x) y))) + (if (ty_int_ref_scalar_64 ty)) + (x64_xor ty y x)) + +;; f32 and f64 + +(rule 5 (lower (has_type (ty_scalar_float ty) (bxor x y))) + (x64_xor_vector ty x y)) + +;; SSE. + +(rule 6 (lower (has_type ty @ (multi_lane _bits _lanes) (bxor x y))) + (x64_xor_vector ty x y)) + +;; `{i,b}128`. + +(rule 7 (lower (has_type $I128 (bxor x y))) + (let ((x_regs ValueRegs x) + (x_lo Gpr (value_regs_get_gpr x_regs 0)) + (x_hi Gpr (value_regs_get_gpr x_regs 1)) + (y_regs ValueRegs y) + (y_lo Gpr (value_regs_get_gpr y_regs 0)) + (y_hi Gpr (value_regs_get_gpr y_regs 1))) + (value_gprs (x64_xor $I64 x_lo y_lo) + (x64_xor $I64 x_hi y_hi)))) + +;; Specialization of `blsmsk` for BMI1 + +(rule 8 (lower (has_type (ty_32_or_64 ty) (bxor x y))) + (if-let true (use_bmi1)) + (if-let x (val_minus_one y)) + (x64_blsmsk ty x)) +(rule 9 (lower (has_type (ty_32_or_64 ty) (bxor y x))) + (if-let true (use_bmi1)) + (if-let x (val_minus_one y)) + (x64_blsmsk ty x)) + +;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(rule -1 (lower (has_type (fits_in_64 ty) (ishl src amt))) + (x64_shl ty src (put_masked_in_imm8_gpr amt ty))) + +;; `i128`. + +(decl shl_i128 (ValueRegs Gpr) ValueRegs) +(rule (shl_i128 src amt) + ;; Unpack the registers that make up the 128-bit value being shifted. + (let ((src_lo Gpr (value_regs_get_gpr src 0)) + (src_hi Gpr (value_regs_get_gpr src 1)) + ;; Do two 64-bit shifts. + (lo_shifted Gpr (x64_shl $I64 src_lo amt)) + (hi_shifted Gpr (x64_shl $I64 src_hi amt)) + ;; `src_lo >> (64 - amt)` are the bits to carry over from the lo + ;; into the hi. + (carry Gpr (x64_shr $I64 + src_lo + (x64_sub $I64 + (imm $I64 64) + amt))) + (zero Gpr (imm $I64 0)) + ;; Nullify the carry if we are shifting in by a multiple of 128. + (carry_ Gpr (with_flags_reg (x64_test (OperandSize.Size64) + amt + (RegMemImm.Imm 127)) + (cmove $I64 + (CC.Z) + zero + carry))) + ;; Add the carry into the high half. + (hi_shifted_ Gpr (x64_or $I64 carry_ hi_shifted))) + ;; Combine the two shifted halves. However, if we are shifting by >= 64 + ;; (modulo 128), then the low bits are zero and the high bits are our + ;; low bits. + (with_flags (x64_test (OperandSize.Size64) amt (RegMemImm.Imm 64)) + (consumes_flags_concat + (cmove $I64 (CC.Z) lo_shifted zero) + (cmove $I64 (CC.Z) hi_shifted_ lo_shifted))))) + +(rule (lower (has_type $I128 (ishl src amt))) + ;; NB: Only the low bits of `amt` matter since we logically mask the shift + ;; amount to the value's bit width. + (let ((amt_ Gpr (lo_gpr amt))) + (shl_i128 src amt_))) + +;; SSE. + +;; Since the x86 instruction set does not have any 8x16 shift instructions (even +;; in higher feature sets like AVX), we lower the `ishl.i8x16` to a sequence of +;; instructions. The basic idea, whether the amount to shift by is an immediate +;; or not, is to use a 16x8 shift and then mask off the incorrect bits to 0s. +(rule (lower (has_type ty @ $I8X16 (ishl src amt))) + (let ( + ;; Mask the amount to ensure wrapping behaviour + (masked_amt RegMemImm (mask_xmm_shift ty amt)) + ;; Shift `src` using 16x8. Unfortunately, a 16x8 shift will only be + ;; correct for half of the lanes; the others must be fixed up with + ;; the mask below. + (unmasked Xmm (x64_psllw src (mov_rmi_to_xmm masked_amt))) + (mask_addr SyntheticAmode (ishl_i8x16_mask masked_amt)) + (mask Reg (x64_load $I8X16 mask_addr (ExtKind.None)))) + (sse_and $I8X16 unmasked (RegMem.Reg mask)))) + +;; Get the address of the mask to use when fixing up the lanes that weren't +;; correctly generated by the 16x8 shift. +(decl ishl_i8x16_mask (RegMemImm) SyntheticAmode) + +;; When the shift amount is known, we can statically (i.e. at compile time) +;; determine the mask to use and only emit that. +(decl ishl_i8x16_mask_for_const (u32) SyntheticAmode) +(extern constructor ishl_i8x16_mask_for_const ishl_i8x16_mask_for_const) +(rule (ishl_i8x16_mask (RegMemImm.Imm amt)) + (ishl_i8x16_mask_for_const amt)) + +;; Otherwise, we must emit the entire mask table and dynamically (i.e. at run +;; time) find the correct mask offset in the table. We use `lea` to find the +;; base address of the mask table and then complex addressing to offset to the +;; right mask: `base_address + amt << 4` +(decl ishl_i8x16_mask_table () SyntheticAmode) +(extern constructor ishl_i8x16_mask_table ishl_i8x16_mask_table) +(rule (ishl_i8x16_mask (RegMemImm.Reg amt)) + (let ((mask_table SyntheticAmode (ishl_i8x16_mask_table)) + (base_mask_addr Gpr (x64_lea $I64 mask_table)) + (mask_offset Gpr (x64_shl $I64 amt + (imm8_to_imm8_gpr 4)))) + (Amode.ImmRegRegShift 0 + base_mask_addr + mask_offset + 0 + (mem_flags_trusted)))) + +(rule (ishl_i8x16_mask (RegMemImm.Mem amt)) + (ishl_i8x16_mask (RegMemImm.Reg (x64_load $I64 amt (ExtKind.None))))) + +;; 16x8, 32x4, and 64x2 shifts can each use a single instruction, once the shift amount is masked. + +(rule (lower (has_type ty @ $I16X8 (ishl src amt))) + (x64_psllw src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(rule (lower (has_type ty @ $I32X4 (ishl src amt))) + (x64_pslld src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(rule (lower (has_type ty @ $I64X2 (ishl src amt))) + (x64_psllq src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(rule -1 (lower (has_type (fits_in_64 ty) (ushr src amt))) + (let ((src_ Gpr (extend_to_gpr src ty (ExtendKind.Zero)))) + (x64_shr ty src_ (put_masked_in_imm8_gpr amt ty)))) + +;; `i128`. + +(decl shr_i128 (ValueRegs Gpr) ValueRegs) +(rule (shr_i128 src amt) + ;; Unpack the lo/hi halves of `src`. + (let ((src_lo Gpr (value_regs_get_gpr src 0)) + (src_hi Gpr (value_regs_get_gpr src 1)) + ;; Do a shift on each half. + (lo_shifted Gpr (x64_shr $I64 src_lo amt)) + (hi_shifted Gpr (x64_shr $I64 src_hi amt)) + ;; `src_hi << (64 - amt)` are the bits to carry over from the hi + ;; into the lo. + (carry Gpr (x64_shl $I64 + src_hi + (x64_sub $I64 + (imm $I64 64) + amt))) + ;; Share the zero value to reduce register pressure + (zero Gpr (imm $I64 0)) + + ;; Nullify the carry if we are shifting by a multiple of 128. + (carry_ Gpr (with_flags_reg (x64_test (OperandSize.Size64) amt (RegMemImm.Imm 127)) + (cmove $I64 (CC.Z) zero carry))) + ;; Add the carry bits into the lo. + (lo_shifted_ Gpr (x64_or $I64 carry_ lo_shifted))) + ;; Combine the two shifted halves. However, if we are shifting by >= 64 + ;; (modulo 128), then the hi bits are zero and the lo bits are what + ;; would otherwise be our hi bits. + (with_flags (x64_test (OperandSize.Size64) amt (RegMemImm.Imm 64)) + (consumes_flags_concat + (cmove $I64 (CC.Z) lo_shifted_ hi_shifted) + (cmove $I64 (CC.Z) hi_shifted zero))))) + +(rule (lower (has_type $I128 (ushr src amt))) + ;; NB: Only the low bits of `amt` matter since we logically mask the shift + ;; amount to the value's bit width. + (let ((amt_ Gpr (lo_gpr amt))) + (shr_i128 src amt_))) + +;; SSE. + +;; There are no 8x16 shifts in x64. Do the same 16x8-shift-and-mask thing we do +;; with 8x16 `ishl`. +(rule (lower (has_type ty @ $I8X16 (ushr src amt))) + (let ( + ;; Mask the amount to ensure wrapping behaviour + (masked_amt RegMemImm (mask_xmm_shift ty amt)) + ;; Shift `src` using 16x8. Unfortunately, a 16x8 shift will only be + ;; correct for half of the lanes; the others must be fixed up with + ;; the mask below. + (unmasked Xmm (x64_psrlw src (mov_rmi_to_xmm masked_amt)))) + (sse_and $I8X16 + unmasked + (ushr_i8x16_mask masked_amt)))) + +;; Get the address of the mask to use when fixing up the lanes that weren't +;; correctly generated by the 16x8 shift. +(decl ushr_i8x16_mask (RegMemImm) SyntheticAmode) + +;; When the shift amount is known, we can statically (i.e. at compile time) +;; determine the mask to use and only emit that. +(decl ushr_i8x16_mask_for_const (u32) SyntheticAmode) +(extern constructor ushr_i8x16_mask_for_const ushr_i8x16_mask_for_const) +(rule (ushr_i8x16_mask (RegMemImm.Imm amt)) + (ushr_i8x16_mask_for_const amt)) + +;; Otherwise, we must emit the entire mask table and dynamically (i.e. at run +;; time) find the correct mask offset in the table. We use `lea` to find the +;; base address of the mask table and then complex addressing to offset to the +;; right mask: `base_address + amt << 4` +(decl ushr_i8x16_mask_table () SyntheticAmode) +(extern constructor ushr_i8x16_mask_table ushr_i8x16_mask_table) +(rule (ushr_i8x16_mask (RegMemImm.Reg amt)) + (let ((mask_table SyntheticAmode (ushr_i8x16_mask_table)) + (base_mask_addr Gpr (x64_lea $I64 mask_table)) + (mask_offset Gpr (x64_shl $I64 + amt + (imm8_to_imm8_gpr 4)))) + (Amode.ImmRegRegShift 0 + base_mask_addr + mask_offset + 0 + (mem_flags_trusted)))) + +(rule (ushr_i8x16_mask (RegMemImm.Mem amt)) + (ushr_i8x16_mask (RegMemImm.Reg (x64_load $I64 amt (ExtKind.None))))) + +;; 16x8, 32x4, and 64x2 shifts can each use a single instruction, once the shift amount is masked. + +(rule (lower (has_type ty @ $I16X8 (ushr src amt))) + (x64_psrlw src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(rule (lower (has_type ty @ $I32X4 (ushr src amt))) + (x64_psrld src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(rule (lower (has_type ty @ $I64X2 (ushr src amt))) + (x64_psrlq src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(decl mask_xmm_shift (Type Value) RegMemImm) +(rule (mask_xmm_shift ty amt) + (gpr_to_reg (x64_and $I64 amt (RegMemImm.Imm (shift_mask ty))))) +(rule 1 (mask_xmm_shift ty (iconst n)) + (RegMemImm.Imm (shift_amount_masked ty n))) + +;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(rule -1 (lower (has_type (fits_in_64 ty) (sshr src amt))) + (let ((src_ Gpr (extend_to_gpr src ty (ExtendKind.Sign)))) + (x64_sar ty src_ (put_masked_in_imm8_gpr amt ty)))) + +;; `i128`. + +(decl sar_i128 (ValueRegs Gpr) ValueRegs) +(rule (sar_i128 src amt) + ;; Unpack the low/high halves of `src`. + (let ((src_lo Gpr (value_regs_get_gpr src 0)) + (src_hi Gpr (value_regs_get_gpr src 1)) + ;; Do a shift of each half. NB: the low half uses an unsigned shift + ;; because its MSB is not a sign bit. + (lo_shifted Gpr (x64_shr $I64 src_lo amt)) + (hi_shifted Gpr (x64_sar $I64 src_hi amt)) + ;; `src_hi << (64 - amt)` are the bits to carry over from the low + ;; half to the high half. + (carry Gpr (x64_shl $I64 + src_hi + (x64_sub $I64 + (imm $I64 64) + amt))) + ;; Nullify the carry if we are shifting by a multiple of 128. + (carry_ Gpr (with_flags_reg (x64_test (OperandSize.Size64) amt (RegMemImm.Imm 127)) + (cmove $I64 (CC.Z) (imm $I64 0) carry))) + ;; Add the carry into the low half. + (lo_shifted_ Gpr (x64_or $I64 lo_shifted carry_)) + ;; Get all sign bits. + (sign_bits Gpr (x64_sar $I64 src_hi (imm8_to_imm8_gpr 63)))) + ;; Combine the two shifted halves. However, if we are shifting by >= 64 + ;; (modulo 128), then the hi bits are all sign bits and the lo bits are + ;; what would otherwise be our hi bits. + (with_flags (x64_test (OperandSize.Size64) amt (RegMemImm.Imm 64)) + (consumes_flags_concat + (cmove $I64 (CC.Z) lo_shifted_ hi_shifted) + (cmove $I64 (CC.Z) hi_shifted sign_bits))))) + +(rule (lower (has_type $I128 (sshr src amt))) + ;; NB: Only the low bits of `amt` matter since we logically mask the shift + ;; amount to the value's bit width. + (let ((amt_ Gpr (lo_gpr amt))) + (sar_i128 src amt_))) + +;; SSE. + +;; Since the x86 instruction set does not have an 8x16 shift instruction and the +;; approach used for `ishl` and `ushr` cannot be easily used (the masks do not +;; preserve the sign), we use a different approach here: separate the low and +;; high lanes, shift them separately, and merge them into the final result. +;; +;; Visually, this looks like the following, where `src.i8x16 = [s0, s1, ..., +;; s15]: +;; +;; lo.i16x8 = [(s0, s0), (s1, s1), ..., (s7, s7)] +;; shifted_lo.i16x8 = shift each lane of `low` +;; hi.i16x8 = [(s8, s8), (s9, s9), ..., (s15, s15)] +;; shifted_hi.i16x8 = shift each lane of `high` +;; result = [s0'', s1'', ..., s15''] +(rule (lower (has_type ty @ $I8X16 (sshr src amt @ (value_type amt_ty)))) + (let ((src_ Xmm (put_in_xmm src)) + ;; Mask the amount to ensure wrapping behaviour + (masked_amt RegMemImm (mask_xmm_shift ty amt)) + ;; In order for `packsswb` later to only use the high byte of each + ;; 16x8 lane, we shift right an extra 8 bits, relying on `psraw` to + ;; fill in the upper bits appropriately. + (lo Xmm (x64_punpcklbw src_ src_)) + (hi Xmm (x64_punpckhbw src_ src_)) + (amt_ XmmMemImm (sshr_i8x16_bigger_shift amt_ty masked_amt)) + (shifted_lo Xmm (x64_psraw lo amt_)) + (shifted_hi Xmm (x64_psraw hi amt_))) + (x64_packsswb shifted_lo shifted_hi))) + +(decl sshr_i8x16_bigger_shift (Type RegMemImm) XmmMemImm) +(rule (sshr_i8x16_bigger_shift _ty (RegMemImm.Imm i)) + (xmm_mem_imm_new (RegMemImm.Imm (u32_add i 8)))) +(rule (sshr_i8x16_bigger_shift ty (RegMemImm.Reg r)) + (mov_rmi_to_xmm (RegMemImm.Reg (x64_add ty + r + (RegMemImm.Imm 8))))) +(rule (sshr_i8x16_bigger_shift ty rmi @ (RegMemImm.Mem _m)) + (mov_rmi_to_xmm (RegMemImm.Reg (x64_add ty + (imm ty 8) + rmi)))) + +;; `sshr.{i16x8,i32x4}` can be a simple `psra{w,d}`, we just have to make sure +;; that if the shift amount is in a register, it is in an XMM register. + +(rule (lower (has_type ty @ $I16X8 (sshr src amt))) + (x64_psraw src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +(rule (lower (has_type ty @ $I32X4 (sshr src amt))) + (x64_psrad src (mov_rmi_to_xmm (mask_xmm_shift ty amt)))) + +;; The `sshr.i64x2` CLIF instruction has no single x86 instruction in the older +;; feature sets. To remedy this, a small dance is done with an unsigned right +;; shift plus some extra ops. +(rule 3 (lower (has_type ty @ $I64X2 (sshr src (iconst n)))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512f)) + (x64_vpsraq_imm src (shift_amount_masked ty n))) + +(rule 2 (lower (has_type ty @ $I64X2 (sshr src amt))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512f)) + (let ((masked Gpr (x64_and $I64 amt (RegMemImm.Imm (shift_mask ty))))) + (x64_vpsraq src (x64_movd_to_xmm masked)))) + +(rule 1 (lower (has_type $I64X2 (sshr src (iconst (u64_from_imm64 (u64_as_u32 amt)))))) + (lower_i64x2_sshr_imm src (u32_and amt 63))) + +(rule (lower (has_type $I64X2 (sshr src amt))) + (lower_i64x2_sshr_gpr src (x64_and $I64 amt (RegMemImm.Imm 63)))) + +(decl lower_i64x2_sshr_imm (Xmm u32) Xmm) + +;; If the shift amount is less than 32 then do an sshr with 32-bit lanes to +;; produce the upper halves of each result, followed by a ushr of 64-bit lanes +;; to produce the lower halves of each result. Interleave results at the end. +(rule 2 (lower_i64x2_sshr_imm vec imm) + (if-let true (u64_lt imm 32)) + (let ( + (high32 Xmm (x64_psrad vec (xmi_imm imm))) + (high32 Xmm (x64_pshufd high32 0b11_10_11_01)) + (low32 Xmm (x64_psrlq vec (xmi_imm imm))) + (low32 Xmm (x64_pshufd low32 0b11_10_10_00)) + ) + (x64_punpckldq low32 high32))) + +;; If the shift amount is 32 then the `psrlq` from the above rule can be avoided +(rule 1 (lower_i64x2_sshr_imm vec 32) + (let ( + (low32 Xmm (x64_pshufd vec 0b11_10_11_01)) + (high32 Xmm (x64_psrad vec (xmi_imm 31))) + (high32 Xmm (x64_pshufd high32 0b11_10_11_01)) + ) + (x64_punpckldq low32 high32))) + +;; Shifts >= 32 use one `psrad` to generate the upper bits and second `psrad` to +;; generate the lower bits. Everything is then woven back together with +;; shuffles. +(rule (lower_i64x2_sshr_imm vec imm) + (if-let true (u64_lt 32 imm)) + (let ( + (high32 Xmm (x64_psrad vec (xmi_imm 31))) + (high32 Xmm (x64_pshufd high32 0b11_10_11_01)) + (low32 Xmm (x64_psrad vec (xmi_imm (u32_sub imm 32)))) + (low32 Xmm (x64_pshufd low32 0b11_10_11_01)) + ) + (x64_punpckldq low32 high32))) + +;; A variable shift amount is slightly more complicated than the immediate +;; shift amounts from above. The `Gpr` argument is guaranteed to be <= 63 by +;; earlier masking. A `ushr` operation is used with some xor/sub math to +;; generate the sign bits. +(decl lower_i64x2_sshr_gpr (Xmm Gpr) Xmm) +(rule (lower_i64x2_sshr_gpr vec val) + (let ( + (val Xmm (x64_movq_to_xmm val)) + (mask Xmm (flip_high_bit_mask $I64X2)) + (sign_bit_loc Xmm (x64_psrlq mask val)) + (ushr Xmm (x64_psrlq vec val)) + (ushr_sign_bit_flip Xmm (x64_pxor sign_bit_loc ushr)) + ) + (x64_psubq ushr_sign_bit_flip sign_bit_loc))) + +;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller: we can rely on x86's rotate-amount masking since +;; we operate on the whole register. For const's we mask the constant. + +(rule -1 (lower (has_type (fits_in_64 ty) (rotl src amt))) + (x64_rotl ty src (put_masked_in_imm8_gpr amt ty))) + + +;; `i128`. + +(rule (lower (has_type $I128 (rotl src amt))) + (let ((src_ ValueRegs src) + ;; NB: Only the low bits of `amt` matter since we logically mask the + ;; rotation amount to the value's bit width. + (amt_ Gpr (lo_gpr amt))) + (or_i128 (shl_i128 src_ amt_) + (shr_i128 src_ (x64_sub $I64 + (imm $I64 128) + amt_))))) + +;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller: we can rely on x86's rotate-amount masking since +;; we operate on the whole register. For const's we mask the constant. + +(rule -1 (lower (has_type (fits_in_64 ty) (rotr src amt))) + (x64_rotr ty src (put_masked_in_imm8_gpr amt ty))) + + +;; `i128`. + +(rule (lower (has_type $I128 (rotr src amt))) + (let ((src_ ValueRegs src) + ;; NB: Only the low bits of `amt` matter since we logically mask the + ;; rotation amount to the value's bit width. + (amt_ Gpr (lo_gpr amt))) + (or_i128 (shr_i128 src_ amt_) + (shl_i128 src_ (x64_sub $I64 + (imm $I64 128) + amt_))))) + +;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(rule -1 (lower (has_type (fits_in_64 ty) (ineg x))) + (x64_neg ty x)) + +(rule -2 (lower (has_type $I128 (ineg x))) + ;; Get the high/low registers for `x`. + (let ((regs ValueRegs x) + (lo Gpr (value_regs_get_gpr regs 0)) + (hi Gpr (value_regs_get_gpr regs 1))) + ;; Do a neg followed by an sub-with-borrow. + (with_flags (x64_neg_paired $I64 lo) + (x64_sbb_paired $I64 (imm $I64 0) hi)))) + +;; SSE. + +(rule (lower (has_type $I8X16 (ineg x))) + (x64_psubb (imm $I8X16 0) x)) + +(rule (lower (has_type $I16X8 (ineg x))) + (x64_psubw (imm $I16X8 0) x)) + +(rule (lower (has_type $I32X4 (ineg x))) + (x64_psubd (imm $I32X4 0) x)) + +(rule (lower (has_type $I64X2 (ineg x))) + (x64_psubq (imm $I64X2 0) x)) + +;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (multi_lane 8 16) + (avg_round x y))) + (x64_pavgb x y)) + +(rule (lower (has_type (multi_lane 16 8) + (avg_round x y))) + (x64_pavgw x y)) + +;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +;; 8-bit base case, needs a special instruction encoding and additionally +;; move sinkable loads to the right. +(rule -8 (lower (has_type $I8 (imul x y))) (x64_mul8 false x y)) +(rule -7 (lower (has_type $I8 (imul (sinkable_load x) y))) (x64_mul8 false y x)) + +;; 16-to-64-bit base cases, same as above by moving sinkable loads to the right. +(rule -6 (lower (has_type (ty_int_ref_16_to_64 ty) (imul x y))) + (x64_imul ty x y)) +(rule -5 (lower (has_type (ty_int_ref_16_to_64 ty) (imul (sinkable_load x) y))) + (x64_imul ty y x)) + +;; lift out constants to use 3-operand form +(rule -4 (lower (has_type (ty_int_ref_16_to_64 ty) (imul x (i32_from_iconst y)))) + (x64_imul_imm ty x y)) +(rule -3 (lower (has_type (ty_int_ref_16_to_64 ty) (imul (i32_from_iconst x) y))) + (x64_imul_imm ty y x)) + +;; Special case widening multiplication from 8-to-16-bits with a single +;; instruction since the 8-bit-multiply places both the high and low halves in +;; the same register +(rule -2 (lower (has_type $I16 (imul (sextend x) (sextend y)))) + (x64_mul8 true x y)) +(rule -2 (lower (has_type $I16 (imul (uextend x) (uextend y)))) + (x64_mul8 false x y)) + +;; `i128`. + +(rule 2 (lower (has_type $I128 (imul x y))) + (let ((x_regs ValueRegs x) + (y_regs ValueRegs y)) + (imul128 + (value_regs_get_gpr x_regs 0) + (value_regs_get_gpr x_regs 1) + (value_regs_get_gpr y_regs 0) + (value_regs_get_gpr y_regs 1)))) + +(rule 4 (lower (has_type $I128 (imul (iconcat x_lo x_hi) (iconcat y_lo y_hi)))) + (imul128 x_lo x_hi y_lo y_hi)) + +;; Helper for lowering 128-bit multiplication with the 64-bit halves of the +;; lhs/rhs already split. The first two arguments are lo/hi for the lhs and the +;; second two are lo/hi for the rhs. +;; +;; mul: +;; dst_lo = lhs_lo * rhs_lo +;; dst_hi = umulhi(lhs_lo, rhs_lo) + +;; lhs_lo * rhs_hi + +;; lhs_hi * rhs_lo +;; +;; so we emit: +;; lo_hi = mul x_lo, y_hi +;; hi_lo = mul x_hi, y_lo +;; hilo_hilo = add lo_hi, hi_lo +;; dst_lo:hi_lolo = mulhi_u x_lo, y_lo +;; dst_hi = add hilo_hilo, hi_lolo +;; return (dst_lo, dst_hi) +(decl imul128 (Gpr Gpr GprMem GprMem) ValueRegs) +(rule (imul128 x_lo x_hi y_lo y_hi) + ;; Put `x` into registers and unpack its hi/lo halves. + (let ( + ;; lo_hi = mul x_lo, y_hi + (lo_hi Gpr (x64_imul $I64 x_lo y_hi)) + ;; hi_lo = mul x_hi, y_lo + (hi_lo Gpr (x64_imul $I64 x_hi y_lo)) + ;; hilo_hilo = add lo_hi, hi_lo + (hilo_hilo Gpr (x64_add $I64 lo_hi hi_lo)) + ;; dst_lo:hi_lolo = x64_mul x_lo, y_lo + (mul_regs ValueRegs (x64_mul $I64 false x_lo y_lo)) + (dst_lo Gpr (value_regs_get_gpr mul_regs 0)) + (hi_lolo Gpr (value_regs_get_gpr mul_regs 1)) + ;; dst_hi = add hilo_hilo, hi_lolo + (dst_hi Gpr (x64_add $I64 hilo_hilo hi_lolo))) + (value_gprs dst_lo dst_hi))) + +;; The `mul` and `imul` instructions on x64 are defined as taking 64-bit +;; operands and producing a 128-bit result, which exactly matches the semantics +;; of widening 64-bit inputs to 128-bit and then multiplying them. That means +;; that these cases can get some some simpler codegen. +(rule 5 (lower (has_type $I128 (imul (uextend x @ (value_type $I64)) + (uextend y @ (value_type $I64))))) + (x64_mul $I64 false x y)) +(rule 5 (lower (has_type $I128 (imul (sextend x @ (value_type $I64)) + (sextend y @ (value_type $I64))))) + (x64_mul $I64 true x y)) + +;; SSE. + +;; (No i8x16 multiply.) + +(rule (lower (has_type (multi_lane 16 8) (imul x y))) + (x64_pmullw x y)) + +(rule (lower (has_type (multi_lane 32 4) (imul x y))) + (if-let true (use_sse41)) + (x64_pmulld x y)) + +;; Without `pmulld` the `pmuludq` instruction is used instead which performs +;; 32-bit multiplication storing the 64-bit result. The 64-bit result is +;; truncated to 32-bits and everything else is woven into place. +(rule -1 (lower (has_type (multi_lane 32 4) (imul x y))) + (let ( + (x Xmm x) + (y Xmm y) + (x_hi Xmm (x64_pshufd x 0b00_11_00_01)) + (y_hi Xmm (x64_pshufd y 0b00_11_00_01)) + (mul_lo Xmm (x64_pshufd (x64_pmuludq x y) 0b00_00_10_00)) + (mul_hi Xmm (x64_pshufd (x64_pmuludq x_hi y_hi) 0b00_00_10_00)) + ) + (x64_punpckldq mul_lo mul_hi))) + +;; With AVX-512 we can implement `i64x2` multiplication with a single +;; instruction. +(rule 3 (lower (has_type (multi_lane 64 2) (imul x y))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512dq)) + (x64_vpmullq x y)) + +;; Otherwise, for i64x2 multiplication we describe a lane A as being composed of +;; a 32-bit upper half "Ah" and a 32-bit lower half "Al". The 32-bit long hand +;; multiplication can then be written as: +;; +;; Ah Al +;; * Bh Bl +;; ----- +;; Al * Bl +;; + (Ah * Bl) << 32 +;; + (Al * Bh) << 32 +;; +;; So for each lane we will compute: +;; +;; A * B = (Al * Bl) + ((Ah * Bl) + (Al * Bh)) << 32 +;; +;; Note, the algorithm will use `pmuludq` which operates directly on the lower +;; 32-bit (`Al` or `Bl`) of a lane and writes the result to the full 64-bits of +;; the lane of the destination. For this reason we don't need shifts to isolate +;; the lower 32-bits, however, we will need to use shifts to isolate the high +;; 32-bits when doing calculations, i.e., `Ah == A >> 32`. +(rule (lower (has_type (multi_lane 64 2) + (imul a b))) + (let ((a0 Xmm a) + (b0 Xmm b) + ;; a_hi = A >> 32 + (a_hi Xmm (x64_psrlq a0 (xmi_imm 32))) + ;; ah_bl = Ah * Bl + (ah_bl Xmm (x64_pmuludq a_hi b0)) + ;; b_hi = B >> 32 + (b_hi Xmm (x64_psrlq b0 (xmi_imm 32))) + ;; al_bh = Al * Bh + (al_bh Xmm (x64_pmuludq a0 b_hi)) + ;; aa_bb = ah_bl + al_bh + (aa_bb Xmm (x64_paddq ah_bl al_bh)) + ;; aa_bb_shifted = aa_bb << 32 + (aa_bb_shifted Xmm (x64_psllq aa_bb (xmi_imm 32))) + ;; al_bl = Al * Bl + (al_bl Xmm (x64_pmuludq a0 b0))) + ;; al_bl + aa_bb_shifted + (x64_paddq al_bl aa_bb_shifted))) + +;; Special case for `i32x4.extmul_high_i16x8_s`. +(rule 1 (lower (has_type (multi_lane 32 4) + (imul (swiden_high (and (value_type (multi_lane 16 8)) + x)) + (swiden_high (and (value_type (multi_lane 16 8)) + y))))) + (let ((x2 Xmm x) + (y2 Xmm y) + (lo Xmm (x64_pmullw x2 y2)) + (hi Xmm (x64_pmulhw x2 y2))) + (x64_punpckhwd lo hi))) + +;; Special case for `i64x2.extmul_high_i32x4_s`. +(rule 1 (lower (has_type (multi_lane 64 2) + (imul (swiden_high (and (value_type (multi_lane 32 4)) + x)) + (swiden_high (and (value_type (multi_lane 32 4)) + y))))) + (if-let true (use_sse41)) + (let ((x2 Xmm (x64_pshufd x 0xFA)) + (y2 Xmm (x64_pshufd y 0xFA))) + (x64_pmuldq x2 y2))) + +;; Special case for `i32x4.extmul_low_i16x8_s`. +(rule 1 (lower (has_type (multi_lane 32 4) + (imul (swiden_low (and (value_type (multi_lane 16 8)) + x)) + (swiden_low (and (value_type (multi_lane 16 8)) + y))))) + (let ((x2 Xmm x) + (y2 Xmm y) + (lo Xmm (x64_pmullw x2 y2)) + (hi Xmm (x64_pmulhw x2 y2))) + (x64_punpcklwd lo hi))) + +;; Special case for `i64x2.extmul_low_i32x4_s`. +(rule 1 (lower (has_type (multi_lane 64 2) + (imul (swiden_low (and (value_type (multi_lane 32 4)) + x)) + (swiden_low (and (value_type (multi_lane 32 4)) + y))))) + (if-let true (use_sse41)) + (let ((x2 Xmm (x64_pshufd x 0x50)) + (y2 Xmm (x64_pshufd y 0x50))) + (x64_pmuldq x2 y2))) + +;; Special case for `i32x4.extmul_high_i16x8_u`. +(rule 1 (lower (has_type (multi_lane 32 4) + (imul (uwiden_high (and (value_type (multi_lane 16 8)) + x)) + (uwiden_high (and (value_type (multi_lane 16 8)) + y))))) + (let ((x2 Xmm x) + (y2 Xmm y) + (lo Xmm (x64_pmullw x2 y2)) + (hi Xmm (x64_pmulhuw x2 y2))) + (x64_punpckhwd lo hi))) + +;; Special case for `i64x2.extmul_high_i32x4_u`. +(rule 1 (lower (has_type (multi_lane 64 2) + (imul (uwiden_high (and (value_type (multi_lane 32 4)) + x)) + (uwiden_high (and (value_type (multi_lane 32 4)) + y))))) + (let ((x2 Xmm (x64_pshufd x 0xFA)) + (y2 Xmm (x64_pshufd y 0xFA))) + (x64_pmuludq x2 y2))) + +;; Special case for `i32x4.extmul_low_i16x8_u`. +(rule 1 (lower (has_type (multi_lane 32 4) + (imul (uwiden_low (and (value_type (multi_lane 16 8)) + x)) + (uwiden_low (and (value_type (multi_lane 16 8)) + y))))) + (let ((x2 Xmm x) + (y2 Xmm y) + (lo Xmm (x64_pmullw x2 y2)) + (hi Xmm (x64_pmulhuw x2 y2))) + (x64_punpcklwd lo hi))) + +;; Special case for `i64x2.extmul_low_i32x4_u`. +(rule 1 (lower (has_type (multi_lane 64 2) + (imul (uwiden_low (and (value_type (multi_lane 32 4)) + x)) + (uwiden_low (and (value_type (multi_lane 32 4)) + y))))) + (let ((x2 Xmm (x64_pshufd x 0x50)) + (y2 Xmm (x64_pshufd y 0x50))) + (x64_pmuludq x2 y2))) + +;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (has_type $I8X16 (iabs x))) + (if-let true (use_ssse3)) + (x64_pabsb x)) + +;; Note the use of `pminub` with signed inputs will produce the positive signed +;; result which is what is desired here. The `pmaxub` isn't available until +;; SSE4.1 in which case the single-instruction above lowering would apply. +(rule (lower (has_type $I8X16 (iabs x))) + (let ( + (x Xmm x) + (negated Xmm (x64_psubb (xmm_zero $I8X16) x)) + ) + (x64_pminub x negated))) + +(rule 1 (lower (has_type $I16X8 (iabs x))) + (if-let true (use_ssse3)) + (x64_pabsw x)) + +(rule (lower (has_type $I16X8 (iabs x))) + (let ( + (x Xmm x) + (negated Xmm (x64_psubw (xmm_zero $I16X8) x)) + ) + (x64_pmaxsw x negated))) + +(rule 1 (lower (has_type $I32X4 (iabs x))) + (if-let true (use_ssse3)) + (x64_pabsd x)) + +;; Generate a `negative_mask` which is either numerically -1 or 0 depending on +;; if the lane is negative. If the lane is positive then the xor operation +;; won't change the lane but otherwise it'll bit-flip everything. By then +;; subtracting the mask this subtracts 0 for positive lanes (does nothing) or +;; ends up adding one for negative lanes. This means that for a negative lane +;; `x` the result is `!x + 1` which is the result of negating it. +(rule (lower (has_type $I32X4 (iabs x))) + (let ( + (x Xmm x) + (negative_mask Xmm (x64_psrad x (xmi_imm 31))) + (flipped_if_negative Xmm (x64_pxor x negative_mask)) + ) + (x64_psubd flipped_if_negative negative_mask))) + +;; When AVX512 is available, we can use a single `vpabsq` instruction. +(rule 2 (lower (has_type $I64X2 (iabs x))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512f)) + (x64_vpabsq x)) + +;; Otherwise, we use a separate register, `neg`, to contain the results of `0 - +;; x` and then blend in those results with `blendvpd` if the MSB of `neg` was +;; set to 1 (i.e. if `neg` was negative or, conversely, if `x` was originally +;; positive). +(rule 1 (lower (has_type $I64X2 (iabs x))) + (if-let true (use_sse41)) + (let ((rx Xmm x) + (neg Xmm (x64_psubq (imm $I64X2 0) rx))) + (x64_blendvpd neg rx neg))) + +;; and if `blendvpd` isn't available then perform a shift/shuffle to generate a +;; mask of which lanes are negative, followed by flipping bits/sub to make both +;; positive. +(rule (lower (has_type $I64X2 (iabs x))) + (let ((x Xmm x) + (signs Xmm (x64_psrad x (RegMemImm.Imm 31))) + (signs Xmm (x64_pshufd signs 0b11_11_01_01)) + (xor_if_negative Xmm (x64_pxor x signs))) + (x64_psubq xor_if_negative signs))) + +;; `i64` and smaller. + +(rule -1 (lower (has_type (fits_in_64 ty) (iabs x))) + (let ((src Gpr x) + (neg ProducesFlags (x64_neg_paired ty src)) + ;; Manually extract the result from the neg, then ignore + ;; it below, since we need to pass it into the cmove + ;; before we pass the cmove to with_flags_reg. + (neg_result Gpr (produces_flags_get_reg neg)) + ;; When the neg instruction sets the sign flag, + ;; takes the original (non-negative) value. + (cmove ConsumesFlags (cmove ty (CC.S) src neg_result))) + (with_flags_reg (produces_flags_ignore neg) cmove))) + +;; `i128`. Negate the low bits, `adc` to the higher bits, then negate high bits. +(rule (lower (has_type $I128 (iabs x))) + ;; Get the high/low registers for `x`. + (let ((x_regs ValueRegs x) + (x_lo Gpr (value_regs_get_gpr x_regs 0)) + (x_hi Gpr (value_regs_get_gpr x_regs 1)) + ; negate low bits, then add 0 with carry to high bits. + (neg_lo ProducesFlags (x64_neg_paired $I64 x_lo)) + (adc_hi ConsumesFlags (x64_adc_paired $I64 x_hi (imm $I64 0))) + (neg_adc_vals ValueRegs (with_flags neg_lo adc_hi)) + ; negate high bits. + (neg_hi ProducesFlags (x64_neg_paired $I64 (value_regs_get neg_adc_vals 1))) + (neg_hi_flag_only ProducesFlags (produces_flags_ignore neg_hi)) + ; cmove based on sign flag from hi negation. + (cmove_lo ConsumesFlags (cmove $I64 (CC.S) x_lo + (value_regs_get neg_adc_vals 0))) + (cmove_hi ConsumesFlags (cmove $I64 (CC.S) x_hi + (produces_flags_get_reg neg_hi))) + (cmoves ConsumesFlags (consumes_flags_concat cmove_lo cmove_hi))) + (with_flags neg_hi_flag_only cmoves))) + +;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fabs x))) + (x64_andps x (imm $F32 0x7fffffff))) + +(rule (lower (has_type $F64 (fabs x))) + (x64_andpd x (imm $F64 0x7fffffffffffffff))) + +;; Special case for `f32x4.abs`. +(rule (lower (has_type $F32X4 (fabs x))) + (x64_andps x + (x64_psrld (vector_all_ones) (xmi_imm 1)))) + +;; Special case for `f64x2.abs`. +(rule (lower (has_type $F64X2 (fabs x))) + (x64_andpd x + (x64_psrlq (vector_all_ones) (xmi_imm 1)))) + +;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fneg x))) + (x64_xorps x (imm $F32 0x80000000))) + +(rule (lower (has_type $F64 (fneg x))) + (x64_xorpd x (imm $F64 0x8000000000000000))) + +(rule (lower (has_type $F32X4 (fneg x))) + (x64_xorps x + (x64_pslld (vector_all_ones) (xmi_imm 31)))) + +(rule (lower (has_type $F64X2 (fneg x))) + (x64_xorpd x + (x64_psllq (vector_all_ones) (xmi_imm 63)))) + +;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl lower_bmask (Type Type ValueRegs) ValueRegs) + +;; Values that fit in a register +;; +;; Use the neg instruction on the input which sets the CF (carry) flag +;; to 0 if the input is 0 or 1 otherwise. +;; We then subtract the output register with itself, which always gives a 0, +;; however use the carry flag from the previous negate to generate a -1 if it +;; was nonzero. +;; +;; neg in_reg +;; sbb out_reg, out_reg +(rule 0 + (lower_bmask (fits_in_64 out_ty) (fits_in_64 in_ty) val) + (let ((reg Gpr (value_regs_get_gpr val 0)) + (out ValueRegs (with_flags + (x64_neg_paired in_ty reg) + (x64_sbb_paired out_ty reg reg)))) + ;; Extract only the output of the sbb instruction + (value_reg (value_regs_get out 1)))) + + +;; If the input type is I128 we can `or` the registers, and recurse to the general case. +(rule 1 + (lower_bmask (fits_in_64 out_ty) $I128 val) + (let ((lo Gpr (value_regs_get_gpr val 0)) + (hi Gpr (value_regs_get_gpr val 1)) + (mixed Gpr (x64_or $I64 lo hi))) + (lower_bmask out_ty $I64 (value_reg mixed)))) + +;; If the output type is I128 we just duplicate the result of the I64 lowering +(rule 2 + (lower_bmask $I128 in_ty val) + (let ((res ValueRegs (lower_bmask $I64 in_ty val)) + (res Gpr (value_regs_get_gpr res 0))) + (value_regs res res))) + + +;; Call the lower_bmask rule that does all the procssing +(rule (lower (has_type out_ty (bmask x @ (value_type in_ty)))) + (lower_bmask out_ty in_ty x)) + +;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(rule -2 (lower (has_type ty (bnot x))) + (if (ty_int_ref_scalar_64 ty)) + (x64_not ty x)) + + +;; `i128`. + +(decl i128_not (Value) ValueRegs) +(rule (i128_not x) + (let ((x_regs ValueRegs x) + (x_lo Gpr (value_regs_get_gpr x_regs 0)) + (x_hi Gpr (value_regs_get_gpr x_regs 1))) + (value_gprs (x64_not $I64 x_lo) + (x64_not $I64 x_hi)))) + +(rule (lower (has_type $I128 (bnot x))) + (i128_not x)) + +;; f32 and f64 + +(rule -3 (lower (has_type (ty_scalar_float ty) (bnot x))) + (x64_xor_vector ty x (vector_all_ones))) + +;; Special case for vector-types where bit-negation is an xor against an +;; all-one value +(rule -1 (lower (has_type ty @ (multi_lane _bits _lanes) (bnot x))) + (x64_xor_vector ty x (vector_all_ones))) + +;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty @ (multi_lane _bits _lanes) + (bitselect condition + if_true + if_false))) + ;; a = and if_true, condition + ;; b = and_not condition, if_false + ;; or b, a + (let ((cond_xmm Xmm condition) + (a Xmm (sse_and ty if_true cond_xmm)) + (b Xmm (sse_and_not ty cond_xmm if_false))) + (sse_or ty b a))) + +;; If every byte of the condition is guaranteed to be all ones or all zeroes, +;; we can use x64_blend. +(rule 1 (lower (has_type ty @ (multi_lane _bits _lanes) + (bitselect condition + if_true + if_false))) + (if-let true (use_sse41)) + (if (all_ones_or_all_zeros condition)) + (x64_pblendvb if_false if_true condition)) + +(decl pure partial all_ones_or_all_zeros (Value) bool) +(rule (all_ones_or_all_zeros (and (icmp _ _ _) (value_type (multi_lane _ _)))) true) +(rule (all_ones_or_all_zeros (and (fcmp _ _ _) (value_type (multi_lane _ _)))) true) +(rule (all_ones_or_all_zeros (and (bitcast _ (fcmp _ _ _)) (value_type (multi_lane _ _)))) true) +(rule (all_ones_or_all_zeros (vconst (vconst_all_ones_or_all_zeros))) true) + +(decl pure vconst_all_ones_or_all_zeros () Constant) +(extern extractor vconst_all_ones_or_all_zeros vconst_all_ones_or_all_zeros) + +;; Specializations for floating-pointer compares to generate a `minp*` or a +;; `maxp*` instruction. These are equivalent to the wasm `f32x4.{pmin,pmax}` +;; instructions and how they're lowered into CLIF. Note the careful ordering +;; of all the operands here to ensure that the input CLIF matched is implemented +;; by the corresponding x64 instruction. +(rule 2 (lower (has_type $F32X4 (bitselect (bitcast _ (fcmp (FloatCC.LessThan) x y)) x y))) + (x64_minps x y)) +(rule 2 (lower (has_type $F64X2 (bitselect (bitcast _ (fcmp (FloatCC.LessThan) x y)) x y))) + (x64_minpd x y)) + +(rule 3 (lower (has_type $F32X4 (bitselect (bitcast _ (fcmp (FloatCC.LessThan) y x)) x y))) + (x64_maxps x y)) +(rule 3 (lower (has_type $F64X2 (bitselect (bitcast _ (fcmp (FloatCC.LessThan) y x)) x y))) + (x64_maxpd x y)) + +;; Scalar rules + +(rule 3 (lower (has_type $I128 (bitselect c t f))) + (let ((a ValueRegs (and_i128 c t)) + (b ValueRegs (and_i128 (i128_not c) f))) + (or_i128 a b))) + +(rule 4 (lower (has_type (ty_int_ref_scalar_64 ty) (bitselect c t f))) + (let ((a Gpr (x64_and ty c t)) + (b Gpr (x64_and ty (x64_not ty c) f))) + (x64_or ty a b))) + +(rule 5 (lower (has_type (ty_scalar_float ty) (bitselect c t f))) + (let ((a Xmm (sse_and ty c t)) + (c_neg Xmm (x64_xor_vector ty c (vector_all_ones))) + (b Xmm (sse_and ty c_neg f))) + (sse_or ty a b))) + +;;;; Rules for `x86_blendv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 + (x86_blendv condition if_true if_false))) + (if-let true (use_sse41)) + (x64_pblendvb if_false if_true condition)) + +(rule (lower (has_type $I32X4 + (x86_blendv condition if_true if_false))) + (if-let true (use_sse41)) + (x64_blendvps if_false if_true condition)) + +(rule (lower (has_type $I64X2 + (x86_blendv condition if_true if_false))) + (if-let true (use_sse41)) + (x64_blendvpd if_false if_true condition)) + +;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (insertlane vec @ (value_type $I8X16) val (u8_from_uimm8 idx))) + (if-let true (use_sse41)) + (x64_pinsrb vec val idx)) +(rule 2 (lower (insertlane vec @ (value_type $I8X16) (sinkable_load_exact val) (u8_from_uimm8 idx))) + (if-let true (use_sse41)) + (x64_pinsrb vec val idx)) + +;; This lowering is particularly unoptimized and is mostly just here to work +;; rather than here to be fast. Requiring SSE 4.1 for the above lowering isn't +;; the end of the world hopefully as that's a pretty old instruction set, so +;; this is the "simplest" version that works on SSE2 for now. +;; +;; This lowering masks the original vector with a constant with all 1s except +;; for the "hole" where this value will get placed into, meaning the desired +;; lane is guaranteed as all 0s. Next the `val` is shuffled into this hole with +;; a few operations: +;; +;; 1. The `val` is zero-extended to 32-bits to guarantee the lower 32-bits +;; are all defined. +;; 2. An arithmetic shift-left is used with the low two bits of `n`, the +;; desired lane, to move the value into the right position within the 32-bit +;; register value. +;; 3. The 32-bit register is moved with `movd` into an XMM register +;; 4. The XMM register, where all lanes are 0 except for the first lane which +;; has the shifted value, is then shuffled with `pshufd` to move the +;; shifted value to the correct and final lane. This uses the upper two +;; bits of `n` to index the i32x4 lane that we're targeting. +;; +;; This all, laboriously, gets the `val` into the desired lane so it's then +;; `por`'d with the original vec-with-a-hole to produce the final result of the +;; insertion. +(rule (lower (insertlane vec @ (value_type $I8X16) val (u8_from_uimm8 n))) + (let ((vec_with_hole Xmm (x64_pand vec (insert_i8x16_lane_hole n))) + (val Gpr (x64_movzx (ExtMode.BL) val)) + (val Gpr (x64_shl $I32 val (Imm8Reg.Imm8 (u8_shl (u8_and n 3) 3)))) + (val Xmm (x64_movd_to_xmm val)) + (val_at_hole Xmm (x64_pshufd val (insert_i8x16_lane_pshufd_imm (u8_shr n 2))))) + (x64_por vec_with_hole val_at_hole))) + +(decl insert_i8x16_lane_hole (u8) VCodeConstant) +(extern constructor insert_i8x16_lane_hole insert_i8x16_lane_hole) +(decl insert_i8x16_lane_pshufd_imm (u8) u8) +(rule (insert_i8x16_lane_pshufd_imm 0) 0b01_01_01_00) +(rule (insert_i8x16_lane_pshufd_imm 1) 0b01_01_00_01) +(rule (insert_i8x16_lane_pshufd_imm 2) 0b01_00_01_01) +(rule (insert_i8x16_lane_pshufd_imm 3) 0b00_01_01_01) + + +;; i16x8.replace_lane +(rule (lower (insertlane vec @ (value_type $I16X8) val (u8_from_uimm8 idx))) + (x64_pinsrw vec val idx)) +(rule 1 (lower (insertlane vec @ (value_type $I16X8) (sinkable_load_exact val) (u8_from_uimm8 idx))) + (x64_pinsrw vec val idx)) + +;; i32x4.replace_lane +(rule 1 (lower (insertlane vec @ (value_type $I32X4) val (u8_from_uimm8 idx))) + (if-let true (use_sse41)) + (x64_pinsrd vec val idx)) + +(rule (lower (insertlane vec @ (value_type $I32X4) val (u8_from_uimm8 0))) + (x64_movss_regmove vec (x64_movd_to_xmm val))) + +;; tmp = [ vec[1] vec[0] val[1] val[0] ] +;; result = [ vec[3] vec[2] tmp[0] tmp[2] ] +(rule (lower (insertlane vec @ (value_type $I32X4) val (u8_from_uimm8 1))) + (let ((val Xmm (x64_movd_to_xmm val)) + (vec Xmm vec)) + (x64_shufps (x64_punpcklqdq val vec) vec 0b11_10_00_10))) + +;; tmp = [ vec[0] vec[3] val[0] val[0] ] +;; result = [ tmp[2] tmp[0] vec[1] vec[0] ] +(rule (lower (insertlane vec @ (value_type $I32X4) val (u8_from_uimm8 2))) + (let ((val Xmm (x64_movd_to_xmm val)) + (vec Xmm vec)) + (x64_shufps vec (x64_shufps val vec 0b00_11_00_00) 0b10_00_01_00))) + +;; tmp = [ vec[3] vec[2] val[1] val[0] ] +;; result = [ tmp[0] tmp[2] vec[1] vec[0] ] +(rule (lower (insertlane vec @ (value_type $I32X4) val (u8_from_uimm8 3))) + (let ((val Xmm (x64_movd_to_xmm val)) + (vec Xmm vec)) + (x64_shufps vec (x64_shufps val vec 0b11_10_01_00) 0b00_10_01_00))) + +;; i64x2.replace_lane +(rule 1 (lower (insertlane vec @ (value_type $I64X2) val (u8_from_uimm8 idx))) + (if-let true (use_sse41)) + (x64_pinsrq vec val idx)) +(rule (lower (insertlane vec @ (value_type $I64X2) val (u8_from_uimm8 0))) + (x64_movsd_regmove vec (x64_movq_to_xmm val))) +(rule (lower (insertlane vec @ (value_type $I64X2) val (u8_from_uimm8 1))) + (x64_punpcklqdq vec (x64_movq_to_xmm val))) + +;; (i64x2.replace_lane 1) with a splat as source for lane 0 -- we can elide +;; the splat and just do a move. This turns out to be a common pattern when +;; constructing an i64x2 out of two i64s. +(rule 3 (lower (insertlane (has_type $I64X2 (splat lane0)) + lane1 + (u8_from_uimm8 1))) + (if-let true (use_sse41)) + (x64_pinsrq (bitcast_gpr_to_xmm 64 lane0) lane1 1)) + +(rule 1 (lower (insertlane vec @ (value_type $F32X4) (sinkable_load val) (u8_from_uimm8 idx))) + (if-let true (use_sse41)) + (x64_insertps vec val (sse_insertps_lane_imm idx))) +(rule (lower (insertlane vec @ (value_type $F32X4) val (u8_from_uimm8 idx))) + (f32x4_insertlane vec val idx)) + +;; Helper function used below for `insertlane` but also here for other +(decl f32x4_insertlane (Xmm Xmm u8) Xmm) + +;; f32x4.replace_lane +(rule 1 (f32x4_insertlane vec val idx) + (if-let true (use_sse41)) + (x64_insertps vec val (sse_insertps_lane_imm idx))) + +;; External rust code used to calculate the immediate value to `insertps`. +(decl sse_insertps_lane_imm (u8) u8) +(extern constructor sse_insertps_lane_imm sse_insertps_lane_imm) + +;; f32x4.replace_lane 0 +(rule (f32x4_insertlane vec val 0) + (x64_movss_regmove vec val)) + +;; f32x4.replace_lane 1 +;; tmp = [ vec[1] vec[0] val[1] val[0] ] +;; result = [ vec[3] vec[2] tmp[0] tmp[2] ] +(rule (f32x4_insertlane vec val 1) + (let ((tmp Xmm (x64_movlhps val vec))) + (x64_shufps tmp vec 0b11_10_00_10))) + +;; f32x4.replace_lane 2 +;; tmp = [ vec[0] vec[3] val[0] val[0] ] +;; result = [ tmp[2] tmp[0] vec[1] vec[0] ] +(rule (f32x4_insertlane vec val 2) + (let ((tmp Xmm (x64_shufps val vec 0b00_11_00_00))) + (x64_shufps vec tmp 0b10_00_01_00))) + +;; f32x4.replace_lane 3 +;; tmp = [ vec[3] vec[2] val[1] val[0] ] +;; result = [ tmp[0] tmp[2] vec[1] vec[0] ] +(rule (f32x4_insertlane vec val 3) + (let ((tmp Xmm (x64_shufps val vec 0b11_10_01_00))) + (x64_shufps vec tmp 0b00_10_01_00))) + +;; f64x2.replace_lane 0 +;; +;; Here the `movsd` instruction is used specifically to specialize moving +;; into the fist lane where unlike above cases we're not using the lane +;; immediate as an immediate to the instruction itself. +(rule (lower (insertlane vec @ (value_type $F64X2) val (u8_from_uimm8 0))) + (x64_movsd_regmove vec val)) + +;; f64x2.replace_lane 1 +;; +;; Here the `movlhps` instruction is used specifically to specialize moving +;; into the second lane where unlike above cases we're not using the lane +;; immediate as an immediate to the instruction itself. +(rule (lower (insertlane vec @ (value_type $F64X2) val (u8_from_uimm8 1))) + (x64_movlhps vec val)) + +;;;; Rules for `smin`, `smax`, `umin`, `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `i64` and smaller. + +(decl cmp_and_choose (Type CC Value Value) ValueRegs) +(rule (cmp_and_choose (fits_in_64 ty) cc x y) + (let ((size OperandSize (raw_operand_size_of_type ty)) + ;; We need to put x and y in registers explicitly because + ;; we use the values more than once. Hence, even if these + ;; are "unique uses" at the CLIF level and would otherwise + ;; allow for load-op merging, here we cannot do that. + (x_reg Reg x) + (y_reg Reg y)) + (with_flags_reg (x64_cmp size y_reg x_reg) + (cmove ty cc y_reg x_reg)))) + +(rule -1 (lower (has_type (fits_in_64 ty) (umin x y))) + (cmp_and_choose ty (CC.B) x y)) + +(rule -1 (lower (has_type (fits_in_64 ty) (umax x y))) + (cmp_and_choose ty (CC.NB) x y)) + +(rule -1 (lower (has_type (fits_in_64 ty) (smin x y))) + (cmp_and_choose ty (CC.L) x y)) + +(rule -1 (lower (has_type (fits_in_64 ty) (smax x y))) + (cmp_and_choose ty (CC.NL) x y)) + +;; SSE helpers for determining if single-instruction lowerings are available. + +(decl pure has_pmins (Type) bool) +(rule 1 (has_pmins $I16X8) true) +(rule 1 (has_pmins $I64X2) false) +(rule (has_pmins _) (use_sse41)) + +(decl pure has_pmaxs (Type) bool) +(rule 1 (has_pmaxs $I16X8) true) +(rule 1 (has_pmaxs $I64X2) false) +(rule (has_pmaxs _) (use_sse41)) + +(decl pure has_pmaxu (Type) bool) +(rule 1 (has_pmaxu $I8X16) true) +(rule 1 (has_pmaxu $I64X2) false) +(rule (has_pmaxu _) (use_sse41)) + +(decl pure has_pminu (Type) bool) +(rule 1 (has_pminu $I8X16) true) +(rule 1 (has_pminu $I64X2) false) +(rule (has_pminu _) (use_sse41)) + +;; SSE `smax`. + +(rule (lower (has_type (ty_vec128 ty) (smax x y))) + (lower_vec_smax ty x y)) + +(decl lower_vec_smax (Type Xmm Xmm) Xmm) +(rule 1 (lower_vec_smax ty x y) + (if-let true (has_pmaxs ty)) + (x64_pmaxs ty x y)) + +(rule (lower_vec_smax ty x y) + (let ( + (x Xmm x) + (y Xmm y) + (cmp Xmm (x64_pcmpgt ty x y)) + (x_is_max Xmm (x64_pand cmp x)) + (y_is_max Xmm (x64_pandn cmp y)) + ) + (x64_por x_is_max y_is_max))) + +;; SSE `smin`. + +(rule 1 (lower (has_type (ty_vec128 ty) (smin x y))) + (if-let true (has_pmins ty)) + (x64_pmins ty x y)) + +(rule (lower (has_type (ty_vec128 ty) (smin x y))) + (let ( + (x Xmm x) + (y Xmm y) + (cmp Xmm (x64_pcmpgt ty y x)) + (x_is_min Xmm (x64_pand cmp x)) + (y_is_min Xmm (x64_pandn cmp y)) + ) + (x64_por x_is_min y_is_min))) + +;; SSE `umax`. + +(rule 2 (lower (has_type (ty_vec128 ty) (umax x y))) + (if-let true (has_pmaxu ty)) + (x64_pmaxu ty x y)) + +;; If y < x then the saturating subtraction will be zero, otherwise when added +;; back to x it'll return y. +(rule 1 (lower (has_type $I16X8 (umax x y))) + (let ((x Xmm x)) + (x64_paddw x (x64_psubusw y x)))) + +;; Flip the upper bits of each lane so the signed comparison has the same +;; result as a signed comparison, and then select the results with the output +;; mask. See `pcmpgt` lowering for info on flipping the upper bit. +(rule (lower (has_type (ty_vec128 ty) (umax x y))) + (let ( + (x Xmm x) + (y Xmm y) + (mask Xmm (flip_high_bit_mask ty)) + (x_masked Xmm (x64_pxor x mask)) + (y_masked Xmm (x64_pxor y mask)) + (cmp Xmm (x64_pcmpgt ty x_masked y_masked)) + (x_is_max Xmm (x64_pand cmp x)) + (y_is_max Xmm (x64_pandn cmp y)) + ) + (x64_por x_is_max y_is_max))) + +(decl flip_high_bit_mask (Type) Xmm) +(rule (flip_high_bit_mask $I16X8) + (x64_movdqu_load (emit_u128_le_const 0x8000_8000_8000_8000_8000_8000_8000_8000))) +(rule (flip_high_bit_mask $I32X4) + (x64_movdqu_load (emit_u128_le_const 0x80000000_80000000_80000000_80000000))) +(rule (flip_high_bit_mask $I64X2) + (x64_movdqu_load (emit_u128_le_const 0x8000000000000000_8000000000000000))) + +;; SSE `umin`. + +(rule 2 (lower (has_type (ty_vec128 ty) (umin x y))) + (if-let true (has_pminu ty)) + (x64_pminu ty x y)) + +;; If x < y then the saturating subtraction will be 0. Otherwise if x > y then +;; the saturated result, when subtracted again, will go back to `y`. +(rule 1 (lower (has_type $I16X8 (umin x y))) + (let ((x Xmm x)) + (x64_psubw x (x64_psubusw x y)))) + +;; Same as `umax`, and see `pcmpgt` for docs on flipping the upper bit. +(rule (lower (has_type (ty_vec128 ty) (umin x y))) + (let ( + (x Xmm x) + (y Xmm y) + (mask Xmm (flip_high_bit_mask ty)) + (x_masked Xmm (x64_pxor x mask)) + (y_masked Xmm (x64_pxor y mask)) + (cmp Xmm (x64_pcmpgt ty y_masked x_masked)) + (x_is_max Xmm (x64_pand cmp x)) + (y_is_max Xmm (x64_pandn cmp y)) + ) + (x64_por x_is_max y_is_max))) + +;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trap code)) + (side_effect (x64_ud2 code))) + +;;;; Rules for `trapz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (trapz val code)) + (side_effect (trap_if_val (ZeroCond.Zero) val code))) + +(rule 1 (lower (trapz (icmp cc a b) code)) + (side_effect (trap_if_icmp (emit_cmp (intcc_complement cc) a b) code))) + +;;;; Rules for `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (trapnz val code)) + (side_effect (trap_if_val (ZeroCond.NonZero) val code))) + +(rule 1 (lower (trapnz (icmp cc a b) code)) + (side_effect (trap_if_icmp (emit_cmp cc a b) code))) + +;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (fits_in_64 ty) (uadd_overflow_trap a b tc))) + (with_flags + (x64_add_with_flags_paired ty a b) + (trap_if (CC.B) tc))) + +;; Handle lhs immediates/sinkable loads in addition to the automatic rhs +;; handling of above. + +(rule 1 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (simm32_from_value a) b tc))) + (with_flags + (x64_add_with_flags_paired ty b a) + (trap_if (CC.B) tc))) + +(rule 2 (lower (has_type (fits_in_64 ty) + (uadd_overflow_trap (sinkable_load a) b tc))) + (with_flags + (x64_add_with_flags_paired ty b a) + (trap_if (CC.B) tc))) + +;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; N.B.: the Ret itself is generated by the ABI. +(rule (lower (return args)) + (lower_return args)) + +;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule -2 (lower (icmp cc a @ (value_type (fits_in_64 ty)) b)) + (lower_icmp_bool (emit_cmp cc a b))) + +(rule -1 (lower (icmp cc a @ (value_type $I128) b)) + (lower_icmp_bool (emit_cmp cc a b))) + +;; Peephole optimization for `x < 0`, when x is a signed 64 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedLessThan) x @ (value_type $I64) (u64_from_iconst 0)))) + (x64_shr $I64 x (Imm8Reg.Imm8 63))) + +;; Peephole optimization for `0 > x`, when x is a signed 64 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedGreaterThan) (u64_from_iconst 0) x @ (value_type $I64)))) + (x64_shr $I64 x (Imm8Reg.Imm8 63))) + +;; Peephole optimization for `0 <= x`, when x is a signed 64 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedLessThanOrEqual) (u64_from_iconst 0) x @ (value_type $I64)))) + (x64_shr $I64 (x64_not $I64 x) (Imm8Reg.Imm8 63))) + +;; Peephole optimization for `x >= 0`, when x is a signed 64 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedGreaterThanOrEqual) x @ (value_type $I64) (u64_from_iconst 0)))) + (x64_shr $I64 (x64_not $I64 x) (Imm8Reg.Imm8 63))) + +;; Peephole optimization for `x < 0`, when x is a signed 32 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedLessThan) x @ (value_type $I32) (u64_from_iconst 0)))) + (x64_shr $I32 x (Imm8Reg.Imm8 31))) + +;; Peephole optimization for `0 > x`, when x is a signed 32 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedGreaterThan) (u64_from_iconst 0) x @ (value_type $I32)))) + (x64_shr $I32 x (Imm8Reg.Imm8 31))) + +;; Peephole optimization for `0 <= x`, when x is a signed 32 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedLessThanOrEqual) (u64_from_iconst 0) x @ (value_type $I32)))) + (x64_shr $I32 (x64_not $I64 x) (Imm8Reg.Imm8 31))) + +;; Peephole optimization for `x >= 0`, when x is a signed 32 bit value +(rule 2 (lower (has_type $I8 (icmp (IntCC.SignedGreaterThanOrEqual) x @ (value_type $I32) (u64_from_iconst 0)))) + (x64_shr $I32 (x64_not $I64 x) (Imm8Reg.Imm8 31))) + +;; For XMM-held values, we lower to `PCMP*` instructions, sometimes more than +;; one. To note: what is different here about the output values is that each +;; lane will be filled with all 1s or all 0s according to the comparison, +;; whereas for GPR-held values, the result will be simply 0 or 1 (upper bits +;; unset). +(rule (lower (icmp (IntCC.Equal) a @ (value_type (ty_vec128 ty)) b)) + (x64_pcmpeq ty a b)) + +;; To lower a not-equals comparison, we perform an equality comparison +;; (PCMPEQ*) and then invert the bits (PXOR with all 1s). +(rule (lower (icmp (IntCC.NotEqual) a @ (value_type (ty_vec128 ty)) b)) + (let ((checked Xmm (x64_pcmpeq ty a b)) + (all_ones Xmm (vector_all_ones))) + (x64_pxor checked all_ones))) + +;; SSE `sgt` + +(rule (lower (icmp (IntCC.SignedGreaterThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_pcmpgt ty a b)) + +;; SSE `slt` + +(rule (lower (icmp (IntCC.SignedLessThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_pcmpgt ty b a)) + +;; SSE `ugt` + +;; N.B.: we must manually prevent load coalescing operands; the +;; register allocator gets confused otherwise. +(rule 1 (lower (icmp (IntCC.UnsignedGreaterThan) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pmaxu ty)) + (let ((a Xmm a) + (b Xmm b) + (max Xmm (x64_pmaxu ty a b)) + (eq Xmm (x64_pcmpeq ty max b))) + (x64_pxor eq (vector_all_ones)))) + +;; Flip the upper bit of each lane so the result of a signed comparison is the +;; same as the result of an unsigned comparison (see docs on `pcmpgt` for more) +(rule (lower (icmp (IntCC.UnsignedGreaterThan) a @ (value_type (ty_vec128 ty)) b)) + (let ((mask Xmm (flip_high_bit_mask ty)) + (a_masked Xmm (x64_pxor a mask)) + (b_masked Xmm (x64_pxor b mask))) + (x64_pcmpgt ty a_masked b_masked))) + +;; SSE `ult` + +(rule 1 (lower (icmp (IntCC.UnsignedLessThan) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pminu ty)) + ;; N.B.: see note above. + (let ((a Xmm a) + (b Xmm b) + (min Xmm (x64_pminu ty a b)) + (eq Xmm (x64_pcmpeq ty min b))) + (x64_pxor eq (vector_all_ones)))) + +;; Flip the upper bit of `a` and `b` so the signed comparison result will +;; be the same as the unsigned comparison result (see docs on `pcmpgt` for more). +(rule (lower (icmp (IntCC.UnsignedLessThan) a @ (value_type (ty_vec128 ty)) b)) + (let ((mask Xmm (flip_high_bit_mask ty)) + (a_masked Xmm (x64_pxor a mask)) + (b_masked Xmm (x64_pxor b mask))) + (x64_pcmpgt ty b_masked a_masked))) + +;; SSE `sge` + +;; Use `pmaxs*` and compare the result to `a` to see if it's `>= b`. +(rule 1 (lower (icmp (IntCC.SignedGreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pmaxs ty)) + (x64_pcmpeq ty a (x64_pmaxs ty a b))) + +;; Without `pmaxs*` use a `pcmpgt*` with reversed operands and invert the +;; result. +(rule (lower (icmp (IntCC.SignedGreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_pxor (x64_pcmpgt ty b a) (vector_all_ones))) + +;; SSE `sle` + +;; With `pmins*` use that and compare the result to `a`. +(rule 1 (lower (icmp (IntCC.SignedLessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pmins ty)) + (x64_pcmpeq ty a (x64_pmins ty a b))) + +;; Without `pmins*` perform a greater-than test and invert the result. +(rule (lower (icmp (IntCC.SignedLessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_pxor (x64_pcmpgt ty a b) (vector_all_ones))) + +;; SSE `uge` + +(rule 2 (lower (icmp (IntCC.UnsignedGreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pmaxu ty)) + (x64_pcmpeq ty a (x64_pmaxu ty a b))) + +;; Perform a saturating subtract of `a` from `b` and if the result is zero then +;; `a` is greater or equal. +(rule 1 (lower (icmp (IntCC.UnsignedGreaterThanOrEqual) a @ (value_type $I16X8) b)) + (x64_pcmpeqw (x64_psubusw b a) (xmm_zero $I16X8))) + +;; Flip the upper bit of each lane so the signed comparison is the same as +;; an unsigned one and then invert the result. See docs on `pcmpgt` for why +;; flipping the upper bit works. +(rule (lower (icmp (IntCC.UnsignedGreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (let ( + (mask Xmm (flip_high_bit_mask ty)) + (a_masked Xmm (x64_pxor a mask)) + (b_masked Xmm (x64_pxor b mask)) + (cmp Xmm (x64_pcmpgt ty b_masked a_masked)) + ) + (x64_pxor cmp (vector_all_ones)))) + +;; SSE `ule` + +(rule 2 (lower (icmp (IntCC.UnsignedLessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (if-let true (has_pminu ty)) + (x64_pcmpeq ty a (x64_pminu ty a b))) + +;; A saturating subtraction will produce zeros if `a` is less than `b`, so +;; compare that result to an all-zeros result to figure out lanes of `a` that +;; are <= to the lanes in `b` +(rule 1 (lower (icmp (IntCC.UnsignedLessThanOrEqual) a @ (value_type $I16X8) b)) + (let ((zeros_if_a_is_min Xmm (x64_psubusw a b))) + (x64_pcmpeqw zeros_if_a_is_min (xmm_zero $I8X16)))) + +;; Flip the upper bit of each lane in `a` and `b` so a signed comparison +;; produces the same result as an unsigned comparison. Then test test for `gt` +;; and invert the result to get the `le` that is desired here. See docs on +;; `pcmpgt` for why flipping the upper bit works. +(rule (lower (icmp (IntCC.UnsignedLessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (let ( + (mask Xmm (flip_high_bit_mask ty)) + (a_masked Xmm (x64_pxor a mask)) + (b_masked Xmm (x64_pxor b mask)) + (cmp Xmm (x64_pcmpgt ty a_masked b_masked)) + ) + (x64_pxor cmp (vector_all_ones)))) + +;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; CLIF's `fcmp` instruction always operates on XMM registers--both scalar and +;; vector. For the scalar versions, we use the flag-setting behavior of the +;; `UCOMIS*` instruction to `SETcc` a 0 or 1 in a GPR register. Note that CLIF's +;; `select` uses the same kind of flag-setting behavior but chooses values other +;; than 0 or 1. +;; +;; Checking the result of `UCOMIS*` is unfortunately difficult in some cases +;; because we do not have `SETcc` instructions that explicitly check +;; simultaneously for the condition (i.e., `eq`, `le`, `gt`, etc.) *and* +;; orderedness. Instead, we must check the flags multiple times. The UCOMIS* +;; documentation (see Intel's Software Developer's Manual, volume 2, chapter 4) +;; is helpful: +;; - unordered assigns Z = 1, P = 1, C = 1 +;; - greater than assigns Z = 0, P = 0, C = 0 +;; - less than assigns Z = 0, P = 0, C = 1 +;; - equal assigns Z = 1, P = 0, C = 0 + +(rule -1 (lower (fcmp cc a @ (value_type (ty_scalar_float ty)) b)) + (lower_fcmp_bool (emit_fcmp cc a b))) + +;; For vector lowerings, we use `CMPP*` instructions with a 3-bit operand that +;; determines the comparison to make. Note that comparisons that succeed will +;; fill the lane with 1s; comparisons that do not will fill the lane with 0s. + +(rule (lower (fcmp (FloatCC.Equal) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.Equal))) +(rule (lower (fcmp (FloatCC.NotEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.NotEqual))) +(rule (lower (fcmp (FloatCC.LessThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.LessThan))) +(rule (lower (fcmp (FloatCC.LessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.LessThanOrEqual))) +(rule (lower (fcmp (FloatCC.Ordered) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.Ordered))) +(rule (lower (fcmp (FloatCC.Unordered) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.Unordered))) +(rule (lower (fcmp (FloatCC.UnorderedOrGreaterThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.UnorderedOrGreaterThan))) +(rule (lower (fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty a b (FcmpImm.UnorderedOrGreaterThanOrEqual))) + +;; Some vector lowerings rely on flipping the operands and using a reversed +;; comparison code. + +(rule (lower (fcmp (FloatCC.GreaterThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty b a (FcmpImm.LessThan))) +(rule (lower (fcmp (FloatCC.GreaterThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty b a (FcmpImm.LessThanOrEqual))) +(rule (lower (fcmp (FloatCC.UnorderedOrLessThan) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty b a (FcmpImm.UnorderedOrGreaterThan))) +(rule (lower (fcmp (FloatCC.UnorderedOrLessThanOrEqual) a @ (value_type (ty_vec128 ty)) b)) + (x64_cmpp ty b a (FcmpImm.UnorderedOrGreaterThanOrEqual))) + +;; Some vector lowerings are simply not supported for certain codes: +;; - FloatCC::OrderedNotEqual +;; - FloatCC::UnorderedOrEqual + +;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; When a `select` has an `fcmp` as a condition then rely on `emit_fcmp` to +;; figure out how to perform the comparison. +;; +;; Note, though, that the `FloatCC.Equal` requires an "and" to happen for two +;; condition codes which isn't the easiest thing to lower to a `cmove` +;; instruction. For this reason a `select (fcmp eq ..) ..` is instead +;; flipped around to be `select (fcmp ne ..) ..` with all operands reversed. +;; This will produce a `FcmpCondResult.OrCondition` which is easier to codegen +;; for. +(rule (lower (has_type ty (select (maybe_uextend (fcmp cc a b)) x y))) + (lower_select_fcmp ty (emit_fcmp cc a b) x y)) +(rule 1 (lower (has_type ty (select (maybe_uextend (fcmp (FloatCC.Equal) a b)) x y))) + (lower_select_fcmp ty (emit_fcmp (FloatCC.NotEqual) a b) y x)) + +(decl lower_select_fcmp (Type FcmpCondResult Value Value) InstOutput) +(rule (lower_select_fcmp ty (FcmpCondResult.Condition flags cc) x y) + (with_flags flags (cmove_from_values ty cc x y))) +(rule (lower_select_fcmp ty (FcmpCondResult.OrCondition flags cc1 cc2) x y) + (with_flags flags (cmove_or_from_values ty cc1 cc2 x y))) + +;; We also can lower `select`s that depend on an `icmp` test, but more simply +;; than the `fcmp` variants above. In these cases, we lower to a `CMP` +;; instruction plus a `CMOV`; recall that `cmove_from_values` here may emit more +;; than one instruction for certain types (e.g., XMM-held, I128). + +(rule (lower (has_type ty (select (maybe_uextend (icmp cc a b)) x y))) + (lower_select_icmp ty (emit_cmp cc a b) x y)) + +;; Finally, we lower `select` from a condition value `c`. These rules are meant +;; to be the final, default lowerings if no other patterns matched above. + +(rule -1 (lower (has_type ty (select c @ (value_type (fits_in_64 a_ty)) x y))) + (let ((size OperandSize (raw_operand_size_of_type a_ty)) + ;; N.B.: disallow load-op fusion, see above. TODO: + ;; https://github.com/bytecodealliance/wasmtime/issues/3953. + (gpr_c Gpr (put_in_gpr c))) + (with_flags (x64_test size gpr_c gpr_c) (cmove_from_values ty (CC.NZ) x y)))) + +(rule -2 (lower (has_type ty (select c @ (value_type $I128) x y))) + (let ((cond_result IcmpCondResult (cmp_zero_i128 (CC.Z) c))) + (select_icmp cond_result x y))) + +(decl lower_select_icmp (Type IcmpCondResult Value Value) InstOutput) +(rule (lower_select_icmp ty (IcmpCondResult.Condition flags cc) x y) + (with_flags flags (cmove_from_values ty cc x y))) + +;; Specializations for floating-point compares to generate a `mins*` or a +;; `maxs*` instruction. These are equivalent to the "pseudo-m{in,ax}" +;; specializations for vectors. +(rule 2 (lower (has_type $F32 (select (maybe_uextend (fcmp (FloatCC.LessThan) x y)) x y))) + (x64_minss x y)) +(rule 2 (lower (has_type $F64 (select (maybe_uextend (fcmp (FloatCC.LessThan) x y)) x y))) + (x64_minsd x y)) +(rule 3 (lower (has_type $F32 (select (maybe_uextend (fcmp (FloatCC.LessThan) y x)) x y))) + (x64_maxss x y)) +(rule 3 (lower (has_type $F64 (select (maybe_uextend (fcmp (FloatCC.LessThan) y x)) x y))) + (x64_maxsd x y)) + +;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower (has_type (ty_32_or_64 ty) (clz src))) + (do_clz ty ty src)) + +(rule 1 (lower (has_type (ty_8_or_16 ty) (clz src))) + (let ((extended Gpr (extend_to_gpr src $I64 (ExtendKind.Zero))) + (clz Gpr (do_clz $I64 $I64 extended))) + (x64_sub $I64 clz (RegMemImm.Imm (u32_sub 64 (ty_bits ty)))))) + + +(rule 0 (lower + (has_type $I128 + (clz src))) + (let ((upper Gpr (do_clz $I64 $I64 (value_regs_get_gpr src 1))) + (lower Gpr (x64_add $I64 + (do_clz $I64 $I64 (value_regs_get_gpr src 0)) + (RegMemImm.Imm 64))) + (result_lo Gpr + (with_flags_reg + (x64_cmp_imm (OperandSize.Size64) upper 64) + (cmove $I64 (CC.NZ) upper lower)))) + (value_regs result_lo (imm $I64 0)))) + +;; Implementation helper for clz; operates on 32 or 64-bit units. +(decl do_clz (Type Type Gpr) Gpr) + +;; If available, we can use a plain lzcnt instruction here. Note no +;; special handling is required for zero inputs, because the machine +;; instruction does what the CLIF expects for zero, i.e. it returns +;; zero. +(rule 1 (do_clz ty orig_ty src) + (if-let true (use_lzcnt)) + (x64_lzcnt ty src)) + +(rule 0 (do_clz ty orig_ty src) + (let ((highest_bit_index Reg (bsr_or_else ty src (imm_i64 $I64 -1))) + (bits_minus_1 Reg (imm ty (u64_sub (ty_bits_u64 orig_ty) 1)))) + (x64_sub ty bits_minus_1 highest_bit_index))) + +;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower (has_type (ty_32_or_64 ty) (ctz src))) + (do_ctz ty ty src)) + +(rule 1 (lower (has_type (ty_8_or_16 ty) (ctz src))) + (let ((extended Gpr (extend_to_gpr src $I32 (ExtendKind.Zero))) + (stopbit Gpr (x64_or $I32 extended (RegMemImm.Imm (u32_shl 1 (ty_bits ty)))))) + (do_ctz $I32 ty stopbit))) + +(rule 0 (lower + (has_type $I128 + (ctz src))) + (let ((lower Gpr (do_ctz $I64 $I64 (value_regs_get_gpr src 0))) + (upper Gpr (x64_add $I64 + (do_ctz $I64 $I64 (value_regs_get_gpr src 1)) + (RegMemImm.Imm 64))) + (result_lo Gpr + (with_flags_reg + (x64_cmp_imm (OperandSize.Size64) lower 64) + (cmove $I64 (CC.Z) upper lower)))) + (value_regs result_lo (imm $I64 0)))) + +(decl do_ctz (Type Type Gpr) Gpr) + +;; Analogous to `clz` cases above, but using mirror instructions +;; (tzcnt vs lzcnt, bsf vs bsr). +(rule 1 (do_ctz ty orig_ty src) + (if-let true (use_bmi1)) + (x64_tzcnt ty src)) + +(rule 0 (do_ctz ty orig_ty src) + (bsf_or_else ty src (imm $I64 (ty_bits_u64 orig_ty)))) + +;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 4 (lower (has_type (ty_32_or_64 ty) (popcnt src))) + (if-let true (use_popcnt)) + (x64_popcnt ty src)) + +(rule 3 (lower (has_type (ty_8_or_16 ty) (popcnt src))) + (if-let true (use_popcnt)) + (x64_popcnt $I32 (extend_to_gpr src $I32 (ExtendKind.Zero)))) + +(rule 1 (lower (has_type $I128 (popcnt src))) + (if-let true (use_popcnt)) + (let ((lo_count Gpr (x64_popcnt $I64 (value_regs_get_gpr src 0))) + (hi_count Gpr (x64_popcnt $I64 (value_regs_get_gpr src 1)))) + (value_regs (x64_add $I64 lo_count hi_count) (imm $I64 0)))) + +(rule -1 (lower + (has_type (ty_32_or_64 ty) + (popcnt src))) + (do_popcnt ty src)) + +(rule -2 (lower + (has_type (ty_8_or_16 ty) + (popcnt src))) + (do_popcnt $I32 (extend_to_gpr src $I32 (ExtendKind.Zero)))) + +(rule (lower + (has_type $I128 + (popcnt src))) + (let ((lo_count Gpr (do_popcnt $I64 (value_regs_get_gpr src 0))) + (hi_count Gpr (do_popcnt $I64 (value_regs_get_gpr src 1)))) + (value_regs (x64_add $I64 lo_count hi_count) (imm $I64 0)))) + +;; Implementation of popcount when we don't nave a native popcount +;; instruction. +(decl do_popcnt (Type Gpr) Gpr) +(rule (do_popcnt $I64 src) + (let ((shifted1 Gpr (x64_shr $I64 src (Imm8Reg.Imm8 1))) + (sevens Gpr (imm $I64 0x7777777777777777)) + (masked1 Gpr (x64_and $I64 shifted1 sevens)) + ;; diff1 := src - ((src >> 1) & 0b0111_0111_0111...) + (diff1 Gpr (x64_sub $I64 src masked1)) + (shifted2 Gpr (x64_shr $I64 masked1 (Imm8Reg.Imm8 1))) + (masked2 Gpr (x64_and $I64 shifted2 sevens)) + ;; diff2 := diff1 - ((diff1 >> 1) & 0b0111_0111_0111...) + (diff2 Gpr (x64_sub $I64 diff1 masked2)) + (shifted3 Gpr (x64_shr $I64 masked2 (Imm8Reg.Imm8 1))) + (masked3 Gpr (x64_and $I64 shifted3 sevens)) + ;; diff3 := diff2 - ((diff2 >> 1) & 0b0111_0111_0111...) + ;; + ;; At this point, each nibble of diff3 is the popcount of + ;; that nibble. This works because at each step above, we + ;; are basically subtracting floor(value / 2) from the + ;; running value; the leftover remainder is 1 if the LSB + ;; was 1. After three steps, we have (nibble / 8) -- 0 or + ;; 1 for the MSB of the nibble -- plus three possible + ;; additions for the three other bits. + (diff3 Gpr (x64_sub $I64 diff2 masked3)) + ;; Add the two nibbles of each byte together. + (sum1 Gpr (x64_add $I64 + (x64_shr $I64 diff3 (Imm8Reg.Imm8 4)) + diff3)) + ;; Mask the above sum to have the popcount for each byte + ;; in the lower nibble of that byte. + (ofof Gpr (imm $I64 0x0f0f0f0f0f0f0f0f)) + (masked4 Gpr (x64_and $I64 sum1 ofof)) + (ones Gpr (imm $I64 0x0101010101010101)) + ;; Use a multiply to sum all of the bytes' popcounts into + ;; the top byte. Consider the binomial expansion for the + ;; top byte: it is the sum of the bytes (masked4 >> 56) * + ;; 0x01 + (masked4 >> 48) * 0x01 + (masked4 >> 40) * 0x01 + ;; + ... + (masked4 >> 0). + (mul Gpr (x64_imul $I64 masked4 ones)) + ;; Now take that top byte and return it as the popcount. + (final Gpr (x64_shr $I64 mul (Imm8Reg.Imm8 56)))) + final)) + +;; This is the 32-bit version of the above; the steps for each nibble +;; are the same, we just use constants half as wide. +(rule (do_popcnt $I32 src) + (let ((shifted1 Gpr (x64_shr $I32 src (Imm8Reg.Imm8 1))) + (sevens Gpr (imm $I32 0x77777777)) + (masked1 Gpr (x64_and $I32 shifted1 sevens)) + (diff1 Gpr (x64_sub $I32 src masked1)) + (shifted2 Gpr (x64_shr $I32 masked1 (Imm8Reg.Imm8 1))) + (masked2 Gpr (x64_and $I32 shifted2 sevens)) + (diff2 Gpr (x64_sub $I32 diff1 masked2)) + (shifted3 Gpr (x64_shr $I32 masked2 (Imm8Reg.Imm8 1))) + (masked3 Gpr (x64_and $I32 shifted3 sevens)) + (diff3 Gpr (x64_sub $I32 diff2 masked3)) + (sum1 Gpr (x64_add $I32 + (x64_shr $I32 diff3 (Imm8Reg.Imm8 4)) + diff3)) + (masked4 Gpr (x64_and $I32 sum1 (RegMemImm.Imm 0x0f0f0f0f))) + (mul Gpr (x64_imul_imm $I32 masked4 0x01010101)) + (final Gpr (x64_shr $I32 mul (Imm8Reg.Imm8 24)))) + final)) + + +(rule 2 (lower (has_type $I8X16 (popcnt src))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512bitalg)) + (x64_vpopcntb src)) + + +;; For SSE 4.2 we use Mula's algorithm (https://arxiv.org/pdf/1611.07612.pdf): +;; +;; __m128i count_bytes ( __m128i v) { +;; __m128i lookup = _mm_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); +;; __m128i low_mask = _mm_set1_epi8 (0x0f); +;; __m128i lo = _mm_and_si128 (v, low_mask); +;; __m128i hi = _mm_and_si128 (_mm_srli_epi16 (v, 4), low_mask); +;; __m128i cnt1 = _mm_shuffle_epi8 (lookup, lo); +;; __m128i cnt2 = _mm_shuffle_epi8 (lookup, hi); +;; return _mm_add_epi8 (cnt1, cnt2); +;; } +;; +;; Details of the above algorithm can be found in the reference noted above, but the basics +;; are to create a lookup table that pre populates the popcnt values for each number [0,15]. +;; The algorithm uses shifts to isolate 4 bit sections of the vector, pshufb as part of the +;; lookup process, and adds together the results. +;; +;; __m128i lookup = _mm_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); + + +(rule 1 (lower (has_type $I8X16 (popcnt src))) + (if-let true (use_ssse3)) + (let ((low_mask XmmMem (emit_u128_le_const 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f)) + (low_nibbles Xmm (sse_and $I8X16 src low_mask)) + ;; Note that this is a 16x8 shift, but that's OK; we mask + ;; off anything that traverses from one byte to the next + ;; with the low_mask below. + (shifted_src Xmm (x64_psrlw src (xmi_imm 4))) + (high_nibbles Xmm (sse_and $I8X16 shifted_src low_mask)) + (lookup Xmm (x64_xmm_load_const $I8X16 + (emit_u128_le_const 0x04030302_03020201_03020201_02010100))) + (bit_counts_low Xmm (x64_pshufb lookup low_nibbles)) + (bit_counts_high Xmm (x64_pshufb lookup high_nibbles))) + (x64_paddb bit_counts_low bit_counts_high))) + +;; A modified version of the popcnt method from Hacker's Delight. +(rule (lower (has_type $I8X16 (popcnt src))) + (let ((mask1 XmmMem (emit_u128_le_const 0x77777777777777777777777777777777)) + (src Xmm src) + (shifted Xmm (x64_pand (x64_psrlq src (xmi_imm 1)) mask1)) + (src Xmm (x64_psubb src shifted)) + (shifted Xmm (x64_pand (x64_psrlq shifted (xmi_imm 1)) mask1)) + (src Xmm (x64_psubb src shifted)) + (shifted Xmm (x64_pand (x64_psrlq shifted (xmi_imm 1)) mask1)) + (src Xmm (x64_psubb src shifted)) + (src Xmm (x64_paddb src (x64_psrlw src (xmi_imm 4))))) + (x64_pand src (emit_u128_le_const 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f)))) + +;; Rules for `bitrev` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8 (bitrev src))) + (do_bitrev8 $I32 src)) + +(rule (lower (has_type $I16 (bitrev src))) + (do_bitrev16 $I32 src)) + +(rule (lower (has_type $I32 (bitrev src))) + (do_bitrev32 $I32 src)) + +(rule (lower (has_type $I64 (bitrev src))) + (do_bitrev64 $I64 src)) + +(rule (lower (has_type $I128 (bitrev src))) + (value_regs + (do_bitrev64 $I64 (value_regs_get_gpr src 1)) + (do_bitrev64 $I64 (value_regs_get_gpr src 0)))) + +(decl do_bitrev8 (Type Gpr) Gpr) +(rule (do_bitrev8 ty src) + (let ((tymask u64 (ty_mask ty)) + (mask1 Gpr (imm ty (u64_and tymask 0x5555555555555555))) + (lo1 Gpr (x64_and ty src mask1)) + (hi1 Gpr (x64_and ty (x64_shr ty src (Imm8Reg.Imm8 1)) mask1)) + (swap1 Gpr (x64_or ty + (x64_shl ty lo1 (Imm8Reg.Imm8 1)) + hi1)) + (mask2 Gpr (imm ty (u64_and tymask 0x3333333333333333))) + (lo2 Gpr (x64_and ty swap1 mask2)) + (hi2 Gpr (x64_and ty (x64_shr ty swap1 (Imm8Reg.Imm8 2)) mask2)) + (swap2 Gpr (x64_or ty + (x64_shl ty lo2 (Imm8Reg.Imm8 2)) + hi2)) + (mask4 Gpr (imm ty (u64_and tymask 0x0f0f0f0f0f0f0f0f))) + (lo4 Gpr (x64_and ty swap2 mask4)) + (hi4 Gpr (x64_and ty (x64_shr ty swap2 (Imm8Reg.Imm8 4)) mask4)) + (swap4 Gpr (x64_or ty + (x64_shl ty lo4 (Imm8Reg.Imm8 4)) + hi4))) + swap4)) + +(decl do_bitrev16 (Type Gpr) Gpr) +(rule (do_bitrev16 ty src) + (let ((src_ Gpr (do_bitrev8 ty src)) + (tymask u64 (ty_mask ty)) + (mask8 Gpr (imm ty (u64_and tymask 0x00ff00ff00ff00ff))) + (lo8 Gpr (x64_and ty src_ mask8)) + (hi8 Gpr (x64_and ty (x64_shr ty src_ (Imm8Reg.Imm8 8)) mask8)) + (swap8 Gpr (x64_or ty + (x64_shl ty lo8 (Imm8Reg.Imm8 8)) + hi8))) + swap8)) + +(decl do_bitrev32 (Type Gpr) Gpr) +(rule (do_bitrev32 ty src) + (let ((src_ Gpr (do_bitrev16 ty src)) + (tymask u64 (ty_mask ty)) + (mask16 Gpr (imm ty (u64_and tymask 0x0000ffff0000ffff))) + (lo16 Gpr (x64_and ty src_ mask16)) + (hi16 Gpr (x64_and ty (x64_shr ty src_ (Imm8Reg.Imm8 16)) mask16)) + (swap16 Gpr (x64_or ty + (x64_shl ty lo16 (Imm8Reg.Imm8 16)) + hi16))) + swap16)) + +(decl do_bitrev64 (Type Gpr) Gpr) +(rule (do_bitrev64 ty @ $I64 src) + (let ((src_ Gpr (do_bitrev32 ty src)) + (mask32 Gpr (imm ty 0xffffffff)) + (lo32 Gpr (x64_and ty src_ mask32)) + (hi32 Gpr (x64_shr ty src_ (Imm8Reg.Imm8 32))) + (swap32 Gpr (x64_or ty + (x64_shl ty lo32 (Imm8Reg.Imm8 32)) + hi32))) + swap32)) + +;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; x64 bswap instruction is only for 32- or 64-bit swaps +;; implement the 16-bit swap as a rotl by 8 +(rule (lower (has_type $I16 (bswap src))) + (x64_rotl $I16 src (Imm8Reg.Imm8 8))) + +(rule (lower (has_type $I32 (bswap src))) + (x64_bswap $I32 src)) + +(rule (lower (has_type $I64 (bswap src))) + (x64_bswap $I64 src)) + +(rule (lower (has_type $I128 (bswap src))) + (value_regs + (x64_bswap $I64 (value_regs_get_gpr src 1)) + (x64_bswap $I64 (value_regs_get_gpr src 0)))) + +;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; I{8,16,32,64} -> I128. +(rule (lower (has_type $I128 (uextend src))) + (value_regs (extend_to_gpr src $I64 (ExtendKind.Zero)) (imm $I64 0))) + +;; I{8,16,32} -> I64. +(rule (lower (has_type $I64 (uextend src))) + (extend_to_gpr src $I64 (ExtendKind.Zero))) + +;; I{8,16} -> I32 +;; I8 -> I16 +(rule -1 (lower (has_type (fits_in_32 _) (uextend src))) + (extend_to_gpr src $I32 (ExtendKind.Zero))) + +;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; I{8,16,32} -> I128. +;; +;; Produce upper 64 bits sign-extended from lower 64: shift right by +;; 63 bits to spread the sign bit across the result. +(rule (lower (has_type $I128 (sextend src))) + (let ((lo Gpr (extend_to_gpr src $I64 (ExtendKind.Sign))) + (hi Gpr (x64_sar $I64 lo (Imm8Reg.Imm8 63)))) + (value_regs lo hi))) + +;; I{8,16,32} -> I64. +(rule (lower (has_type $I64 (sextend src))) + (extend_to_gpr src $I64 (ExtendKind.Sign))) + +;; I{8,16} -> I32 +;; I8 -> I16 +(rule -1 (lower (has_type (fits_in_32 _) (sextend src))) + (extend_to_gpr src $I32 (ExtendKind.Sign))) + +;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; T -> T is always a no-op, even I128 -> I128. +(rule (lower (has_type ty (ireduce src @ (value_type ty)))) + src) + +;; T -> I{64,32,16,8}: We can simply pass through the value: values +;; are always stored with high bits undefined, so we can just leave +;; them be. +(rule 1 (lower (has_type (fits_in_64 ty) (ireduce src))) + (value_regs_get_gpr src 0)) + +;; Rules for `debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (debugtrap)) + (side_effect (x64_hlt))) + +;; Rules for `x86_pmaddubsw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I16X8 (x86_pmaddubsw x y))) + (if-let true (use_ssse3)) + (x64_pmaddubsw y x)) + +;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fadd x y))) + (x64_addss x y)) +(rule (lower (has_type $F64 (fadd x y))) + (x64_addsd x y)) +(rule (lower (has_type $F32X4 (fadd x y))) + (x64_addps x y)) +(rule (lower (has_type $F64X2 (fadd x y))) + (x64_addpd x y)) + +;; The above rules automatically sink loads for rhs operands, so additionally +;; add rules for sinking loads with lhs operands. +(rule 1 (lower (has_type $F32 (fadd (sinkable_load x) y))) + (x64_addss y x)) +(rule 1 (lower (has_type $F64 (fadd (sinkable_load x) y))) + (x64_addsd y x)) +(rule 1 (lower (has_type $F32X4 (fadd (sinkable_load x) y))) + (x64_addps y x)) +(rule 1 (lower (has_type $F64X2 (fadd (sinkable_load x) y))) + (x64_addpd y x)) + +;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fsub x y))) + (x64_subss x y)) +(rule (lower (has_type $F64 (fsub x y))) + (x64_subsd x y)) +(rule (lower (has_type $F32X4 (fsub x y))) + (x64_subps x y)) +(rule (lower (has_type $F64X2 (fsub x y))) + (x64_subpd x y)) + +;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmul x y))) + (x64_mulss x y)) +(rule (lower (has_type $F64 (fmul x y))) + (x64_mulsd x y)) +(rule (lower (has_type $F32X4 (fmul x y))) + (x64_mulps x y)) +(rule (lower (has_type $F64X2 (fmul x y))) + (x64_mulpd x y)) + +;; The above rules automatically sink loads for rhs operands, so additionally +;; add rules for sinking loads with lhs operands. +(rule 1 (lower (has_type $F32 (fmul (sinkable_load x) y))) + (x64_mulss y x)) +(rule 1 (lower (has_type $F64 (fmul (sinkable_load x) y))) + (x64_mulsd y x)) +(rule 1 (lower (has_type $F32X4 (fmul (sinkable_load x) y))) + (x64_mulps y x)) +(rule 1 (lower (has_type $F64X2 (fmul (sinkable_load x) y))) + (x64_mulpd y x)) + +;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fdiv x y))) + (x64_divss x y)) +(rule (lower (has_type $F64 (fdiv x y))) + (x64_divsd x y)) +(rule (lower (has_type $F32X4 (fdiv x y))) + (x64_divps x y)) +(rule (lower (has_type $F64X2 (fdiv x y))) + (x64_divpd x y)) + +;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type $F32 (sqrt x))) + (x64_sqrtss (xmm_zero $F32X4) x)) +(rule (lower (has_type $F64 (sqrt x))) + (x64_sqrtsd (xmm_zero $F64X2) x)) +(rule (lower (has_type $F32X4 (sqrt x))) + (x64_sqrtps x)) +(rule (lower (has_type $F64X2 (sqrt x))) + (x64_sqrtpd x)) + +;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type $F64 (fpromote x))) + (x64_cvtss2sd (xmm_zero $F64X2) x)) + +;; Rules for `fvpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type $F64X2 (fvpromote_low x))) + (x64_cvtps2pd (put_in_xmm x))) + +;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type $F32 (fdemote x))) + (x64_cvtsd2ss (xmm_zero $F32X4) x)) + +;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(rule (lower (has_type $F32X4 (fvdemote x))) + (x64_cvtpd2ps x)) + +;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmin x y))) + (xmm_min_max_seq $F32 true x y)) +(rule (lower (has_type $F64 (fmin x y))) + (xmm_min_max_seq $F64 true x y)) + +;; Vector-typed version. We don't use single pseudoinstructions as +;; above, because we don't need to generate a mini-CFG. Instead, we +;; perform a branchless series of operations. +;; +;; We cannot simply use native min instructions (minps, minpd) because +;; NaN handling is different per CLIF semantics than on +;; x86. Specifically, if an argument is NaN, or the arguments are both +;; zero but of opposite signs, then the x86 instruction always +;; produces the second argument. However, per CLIF semantics, we +;; require that fmin(NaN, _) = fmin(_, NaN) = NaN, and fmin(+0, -0) = +;; fmin(-0, +0) = -0. + +(rule (lower (has_type $F32X4 (fmin x y))) + ;; Compute min(x, y) and min(y, x) with native + ;; instructions. These will differ in one of the edge cases + ;; above that we have to handle properly. (Conversely, if they + ;; don't differ, then the native instruction's answer is the + ;; right one per CLIF semantics.) + (let ((x Xmm x) ;; force x/y into registers and disallow load sinking + (y Xmm y) + (min1 Xmm (x64_minps x y)) + (min2 Xmm (x64_minps y x)) + ;; Compute the OR of the two. Note that NaNs have an + ;; exponent field of all-ones (0xFF for F32), so if either + ;; result is a NaN, this OR will be. And if either is a + ;; zero (which has an exponent of 0 and mantissa of 0), + ;; this captures a sign-bit of 1 (negative) if either + ;; input is negative. + ;; + ;; In the case where we don't have a +/-0 mismatch or + ;; NaNs, then `min1` and `min2` are equal and `min_or` is + ;; the correct minimum. + (min_or Xmm (x64_orps min1 min2)) + ;; "compare unordered" produces a true mask (all ones) in + ;; a given lane if the min is a NaN. We use this to + ;; generate a mask to ensure quiet NaNs. + (is_nan_mask Xmm (x64_cmpps min_or min2 (FcmpImm.Unordered))) + ;; OR in the NaN mask. + (min_or_2 Xmm (x64_orps min_or is_nan_mask)) + ;; Shift the NaN mask down so that it covers just the + ;; fraction below the NaN signalling bit; we'll use this + ;; to mask off non-canonical NaN payloads. + ;; + ;; All-ones for NaN, shifted down to leave 10 top bits (1 + ;; sign, 8 exponent, 1 QNaN bit that must remain set) + ;; cleared. + (nan_fraction_mask Xmm (x64_psrld is_nan_mask (xmi_imm 10))) + ;; Do a NAND, so that we retain every bit not set in + ;; `nan_fraction_mask`. This mask will be all zeroes (so + ;; we retain every bit) in non-NaN cases, and will have + ;; ones (so we clear those bits) in NaN-payload bits + ;; otherwise. + (final Xmm (x64_andnps nan_fraction_mask min_or_2))) + final)) + +;; Likewise for F64 lanes, except that the right-shift is by 13 bits +;; (1 sign, 11 exponent, 1 QNaN bit). +(rule (lower (has_type $F64X2 (fmin x y))) + (let ((x Xmm x) ;; force x/y into registers and disallow load sinking + (y Xmm y) + (min1 Xmm (x64_minpd x y)) + (min2 Xmm (x64_minpd y x)) + (min_or Xmm (x64_orpd min1 min2)) + (is_nan_mask Xmm (x64_cmppd min1 min2 (FcmpImm.Unordered))) + (min_or_2 Xmm (x64_orpd min_or is_nan_mask)) + (nan_fraction_mask Xmm (x64_psrlq is_nan_mask (xmi_imm 13))) + (final Xmm (x64_andnpd nan_fraction_mask min_or_2))) + final)) + +;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fmax x y))) + (xmm_min_max_seq $F32 false x y)) +(rule (lower (has_type $F64 (fmax x y))) + (xmm_min_max_seq $F64 false x y)) + +;; The vector version of fmax here is a dual to the fmin sequence +;; above, almost, with a few differences. + +(rule (lower (has_type $F32X4 (fmax x y))) + ;; Compute max(x, y) and max(y, x) with native + ;; instructions. These will differ in one of the edge cases + ;; above that we have to handle properly. (Conversely, if they + ;; don't differ, then the native instruction's answer is the + ;; right one per CLIF semantics.) + (let ((x Xmm x) ;; force x/y into registers and disallow load sinking + (y Xmm y) + (max1 Xmm (x64_maxps x y)) + (max2 Xmm (x64_maxps y x)) + ;; Compute the XOR of the two maxima. In the case + ;; where we don't have a +/-0 mismatch or NaNs, then + ;; `min1` and `min2` are equal and this XOR is zero. + (max_xor Xmm (x64_xorps max1 max2)) + ;; OR the XOR into one of the original maxima. If they are + ;; equal, this does nothing. If max2 was NaN, its exponent + ;; bits were all-ones, so the xor's exponent bits were the + ;; complement of max1, and the OR of max1 and max_xor has + ;; an all-ones exponent (is a NaN). If max1 was NaN, then + ;; its exponent bits were already all-ones, so the OR will + ;; be a NaN as well. + (max_blended_nan Xmm (x64_orps max1 max_xor)) + ;; Subtract the XOR. This ensures that if we had +0 and + ;; -0, we end up with +0. + (max_blended_nan_positive Xmm (x64_subps max_blended_nan max_xor)) + ;; "compare unordered" produces a true mask (all ones) in + ;; a given lane if the min is a NaN. We use this to + ;; generate a mask to ensure quiet NaNs. + (is_nan_mask Xmm (x64_cmpps max_blended_nan max_blended_nan (FcmpImm.Unordered))) + ;; Shift the NaN mask down so that it covers just the + ;; fraction below the NaN signalling bit; we'll use this + ;; to mask off non-canonical NaN payloads. + ;; + ;; All-ones for NaN, shifted down to leave 10 top bits (1 + ;; sign, 8 exponent, 1 QNaN bit that must remain set) + ;; cleared. + (nan_fraction_mask Xmm (x64_psrld is_nan_mask (xmi_imm 10))) + ;; Do a NAND, so that we retain every bit not set in + ;; `nan_fraction_mask`. This mask will be all zeroes (so + ;; we retain every bit) in non-NaN cases, and will have + ;; ones (so we clear those bits) in NaN-payload bits + ;; otherwise. + (final Xmm (x64_andnps nan_fraction_mask max_blended_nan_positive))) + final)) + +(rule (lower (has_type $F64X2 (fmax x y))) + ;; Compute max(x, y) and max(y, x) with native + ;; instructions. These will differ in one of the edge cases + ;; above that we have to handle properly. (Conversely, if they + ;; don't differ, then the native instruction's answer is the + ;; right one per CLIF semantics.) + (let ((x Xmm x) ;; force x/y into registers and disallow load sinking + (y Xmm y) + (max1 Xmm (x64_maxpd x y)) + (max2 Xmm (x64_maxpd y x)) + ;; Compute the XOR of the two maxima. In the case + ;; where we don't have a +/-0 mismatch or NaNs, then + ;; `min1` and `min2` are equal and this XOR is zero. + (max_xor Xmm (x64_xorpd max1 max2)) + ;; OR the XOR into one of the original maxima. If they are + ;; equal, this does nothing. If max2 was NaN, its exponent + ;; bits were all-ones, so the xor's exponent bits were the + ;; complement of max1, and the OR of max1 and max_xor has + ;; an all-ones exponent (is a NaN). If max1 was NaN, then + ;; its exponent bits were already all-ones, so the OR will + ;; be a NaN as well. + (max_blended_nan Xmm (x64_orpd max1 max_xor)) + ;; Subtract the XOR. This ensures that if we had +0 and + ;; -0, we end up with +0. + (max_blended_nan_positive Xmm (x64_subpd max_blended_nan max_xor)) + ;; `cmpps` with predicate index `3` is `cmpunordps`, or + ;; "compare unordered": it produces a true mask (all ones) + ;; in a given lane if the min is a NaN. We use this to + ;; generate a mask to ensure quiet NaNs. + (is_nan_mask Xmm (x64_cmppd max_blended_nan max_blended_nan (FcmpImm.Unordered))) + ;; Shift the NaN mask down so that it covers just the + ;; fraction below the NaN signalling bit; we'll use this + ;; to mask off non-canonical NaN payloads. + ;; + ;; All-ones for NaN, shifted down to leave 13 top bits (1 + ;; sign, 11 exponent, 1 QNaN bit that must remain set) + ;; cleared. + (nan_fraction_mask Xmm (x64_psrlq is_nan_mask (xmi_imm 13))) + ;; Do a NAND, so that we retain every bit not set in + ;; `nan_fraction_mask`. This mask will be all zeroes (so + ;; we retain every bit) in non-NaN cases, and will have + ;; ones (so we clear those bits) in NaN-payload bits + ;; otherwise. + (final Xmm (x64_andnpd nan_fraction_mask max_blended_nan_positive))) + final)) + +;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Base case for fma is to call out to one of two libcalls. For vectors they +;; need to be decomposed, handle each element individually, and then recomposed. + +(rule (lower (has_type $F32 (fma x y z))) + (libcall_3 (LibCall.FmaF32) x y z)) +(rule (lower (has_type $F64 (fma x y z))) + (libcall_3 (LibCall.FmaF64) x y z)) + +(rule (lower (has_type $F32X4 (fma x y z))) + (let ( + (x Xmm (put_in_xmm x)) + (y Xmm (put_in_xmm y)) + (z Xmm (put_in_xmm z)) + (x0 Xmm (libcall_3 (LibCall.FmaF32) x y z)) + (x1 Xmm (libcall_3 (LibCall.FmaF32) + (x64_pshufd x 1) + (x64_pshufd y 1) + (x64_pshufd z 1))) + (x2 Xmm (libcall_3 (LibCall.FmaF32) + (x64_pshufd x 2) + (x64_pshufd y 2) + (x64_pshufd z 2))) + (x3 Xmm (libcall_3 (LibCall.FmaF32) + (x64_pshufd x 3) + (x64_pshufd y 3) + (x64_pshufd z 3))) + + (tmp Xmm (f32x4_insertlane x0 x1 1)) + (tmp Xmm (f32x4_insertlane tmp x2 2)) + (tmp Xmm (f32x4_insertlane tmp x3 3)) + ) + tmp)) +(rule (lower (has_type $F64X2 (fma x y z))) + (let ( + (x Xmm (put_in_xmm x)) + (y Xmm (put_in_xmm y)) + (z Xmm (put_in_xmm z)) + (x0 Xmm (libcall_3 (LibCall.FmaF64) x y z)) + (x1 Xmm (libcall_3 (LibCall.FmaF64) + (x64_pshufd x 0xee) + (x64_pshufd y 0xee) + (x64_pshufd z 0xee))) + ) + (x64_movlhps x0 x1))) + + +;; Special case for when the `fma` feature is active and a native instruction +;; can be used. +(rule 1 (lower (has_type ty (fma x y z))) + (if-let true (use_fma)) + (fmadd ty x y z)) + +(decl fmadd (Type Value Value Value) Xmm) +(decl fnmadd (Type Value Value Value) Xmm) + +;; Base case. Note that this will automatically sink a load with `z`, the value +;; to add. +(rule (fmadd ty x y z) (x64_vfmadd213 ty x y z)) + +;; Allow sinking loads with one of the two values being multiplied in addition +;; to the value being added. Note that both x and y can be sunk here due to +;; multiplication being commutative. +(rule 1 (fmadd ty (sinkable_load x) y z) (x64_vfmadd132 ty y z x)) +(rule 2 (fmadd ty x (sinkable_load y) z) (x64_vfmadd132 ty x z y)) + +;; If one of the values being multiplied is negated then use a `vfnmadd*` +;; instruction instead +(rule 3 (fmadd ty (fneg x) y z) (fnmadd ty x y z)) +(rule 4 (fmadd ty x (fneg y) z) (fnmadd ty x y z)) + +(rule (fnmadd ty x y z) (x64_vfnmadd213 ty x y z)) +(rule 1 (fnmadd ty (sinkable_load x) y z) (x64_vfnmadd132 ty y z x)) +(rule 2 (fnmadd ty x (sinkable_load y) z) (x64_vfnmadd132 ty x z y)) + +;; Like `fmadd` if one argument is negated switch which one is being codegen'd +(rule 3 (fnmadd ty (fneg x) y z) (fmadd ty x y z)) +(rule 4 (fnmadd ty x (fneg y) z) (fmadd ty x y z)) + + +(rule 2 (lower (has_type ty (fma x y (fneg z)))) + (if-let true (use_fma)) + (fmsub ty x y z)) + +;; fmsub and fnmsub +(decl fmsub (Type Value Value Value) Xmm) +(decl fnmsub (Type Value Value Value) Xmm) + +;; Base case, will sink a load of `z` automatically. +(rule (fmsub ty x y z) (x64_vfmsub213 ty x y z)) + +;; Allow sinking loads with one of the two values being multiplied in addition +;; to the value being subtracted. Note that both x and y can be sunk here due to +;; multiplication being commutative. +(rule 1 (fmsub ty (sinkable_load x) y z) (x64_vfmsub132 ty y z x)) +(rule 2 (fmsub ty x (sinkable_load y) z) (x64_vfmsub132 ty x z y)) + +;; If one of the values being multiplied is negated then use a `vfnmsub*` +;; instruction instead +(rule 3 (fmsub ty (fneg x) y z) (fnmsub ty x y z)) +(rule 4 (fmsub ty x (fneg y) z) (fnmsub ty x y z)) + +(rule (fnmsub ty x y z) (x64_vfnmsub213 ty x y z)) +(rule 1 (fnmsub ty (sinkable_load x) y z) (x64_vfnmsub132 ty y z x)) +(rule 2 (fnmsub ty x (sinkable_load y) z) (x64_vfnmsub132 ty x z y)) + +;; Like `fmsub` if one argument is negated switch which one is being codegen'd +(rule 3 (fnmsub ty (fneg x) y z) (fmsub ty x y z)) +(rule 4 (fnmsub ty x (fneg y) z) (fmsub ty x y z)) + + +;; Rules for `load*` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; In order to load a value from memory to a GPR register, we may need to extend +;; the loaded value from 8-, 16-, or 32-bits to this backend's expected GPR +;; width: 64 bits. Note that `ext_mode` will load 1-bit types (booleans) as +;; 8-bit loads. +;; +;; By default, we zero-extend all sub-64-bit loads to a GPR. +(rule load_sub64_x64_movzx -4 (lower (has_type (and (fits_in_32 ty) (is_gpr_type _)) (load flags address offset))) + (x64_movzx (ext_mode (ty_bits_u16 ty) 64) (to_amode flags address offset))) +;; But if we know that both the `from` and `to` are 64 bits, we simply load with +;; no extension. +(rule load_64_x64_movzx -1 (lower (has_type (ty_int_ref_64 ty) (load flags address offset))) + (x64_mov (to_amode flags address offset))) +;; Also, certain scalar loads have a specific `from` width and extension kind +;; (signed -> `sx`, zeroed -> `zx`). We overwrite the high bits of the 64-bit +;; GPR even if the `to` type is smaller (e.g., 16-bits). +(rule (lower (has_type (is_gpr_type ty) (uload8 flags address offset))) + (x64_movzx (ExtMode.BQ) (to_amode flags address offset))) +(rule (lower (has_type (is_gpr_type ty) (sload8 flags address offset))) + (x64_movsx (ExtMode.BQ) (to_amode flags address offset))) +(rule (lower (has_type (is_gpr_type ty) (uload16 flags address offset))) + (x64_movzx (ExtMode.WQ) (to_amode flags address offset))) +(rule (lower (has_type (is_gpr_type ty) (sload16 flags address offset))) + (x64_movsx (ExtMode.WQ) (to_amode flags address offset))) +(rule (lower (has_type (is_gpr_type ty) (uload32 flags address offset))) + (x64_movzx (ExtMode.LQ) (to_amode flags address offset))) +(rule (lower (has_type (is_gpr_type ty) (sload32 flags address offset))) + (x64_movsx (ExtMode.LQ) (to_amode flags address offset))) + +;; To load to XMM registers, we use the x64-specific instructions for each type. +;; For `$F32` and `$F64` this is important--we only want to load 32 or 64 bits. +;; But for the 128-bit types, this is not strictly necessary for performance but +;; might help with clarity during disassembly. +(rule (lower (has_type $F16 (load flags address offset))) + (x64_pinsrw (xmm_uninit_value) (to_amode flags address offset) 0)) +(rule (lower (has_type $F32 (load flags address offset))) + (x64_movss_load (to_amode flags address offset))) +(rule (lower (has_type $F64 (load flags address offset))) + (x64_movsd_load (to_amode flags address offset))) +(rule (lower (has_type $F128 (load flags address offset))) + (x64_movdqu_load (to_amode flags address offset))) +(rule (lower (has_type $F32X4 (load flags address offset))) + (x64_movups_load (to_amode flags address offset))) +(rule (lower (has_type $F64X2 (load flags address offset))) + (x64_movupd_load (to_amode flags address offset))) +(rule -2 (lower (has_type (ty_vec128 ty) (load flags address offset))) + (x64_movdqu_load (to_amode flags address offset))) + +;; We can load an I128 by doing two 64-bit loads. +(rule -3 (lower (has_type $I128 + (load flags address offset))) + (let ((addr_lo Amode (to_amode flags address offset)) + (addr_hi Amode (amode_offset addr_lo 8)) + (value_lo Reg (x64_mov addr_lo)) + (value_hi Reg (x64_mov addr_hi))) + (value_regs value_lo value_hi))) + +;; We also include widening vector loads; these sign- or zero-extend each lane +;; to the next wider width (e.g., 16x4 -> 32x4). +(rule 1 (lower (has_type $I16X8 (sload8x8 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovsxbw (to_amode flags address offset))) +(rule 1 (lower (has_type $I16X8 (uload8x8 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovzxbw (to_amode flags address offset))) +(rule 1 (lower (has_type $I32X4 (sload16x4 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovsxwd (to_amode flags address offset))) +(rule 1 (lower (has_type $I32X4 (uload16x4 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovzxwd (to_amode flags address offset))) +(rule 1 (lower (has_type $I64X2 (sload32x2 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovsxdq (to_amode flags address offset))) +(rule 1 (lower (has_type $I64X2 (uload32x2 flags address offset))) + (if-let true (use_sse41)) + (x64_pmovzxdq (to_amode flags address offset))) + +(rule (lower (has_type $I16X8 (sload8x8 flags address offset))) + (lower_swiden_low $I16X8 (x64_movq_to_xmm (to_amode flags address offset)))) +(rule (lower (has_type $I16X8 (uload8x8 flags address offset))) + (lower_uwiden_low $I16X8 (x64_movq_to_xmm (to_amode flags address offset)))) +(rule (lower (has_type $I32X4 (sload16x4 flags address offset))) + (lower_swiden_low $I32X4 (x64_movq_to_xmm (to_amode flags address offset)))) +(rule (lower (has_type $I32X4 (uload16x4 flags address offset))) + (lower_uwiden_low $I32X4 (x64_movq_to_xmm (to_amode flags address offset)))) +(rule (lower (has_type $I64X2 (sload32x2 flags address offset))) + (lower_swiden_low $I64X2 (x64_movq_to_xmm (to_amode flags address offset)))) +(rule (lower (has_type $I64X2 (uload32x2 flags address offset))) + (lower_uwiden_low $I64X2 (x64_movq_to_xmm (to_amode flags address offset)))) + +;; Rules for `store*` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 8-, 16-, 32- and 64-bit GPR stores. +(rule store_x64_movrm -2 (lower (store flags + value @ (value_type (is_gpr_type ty)) + address + offset)) + (side_effect + (x64_movrm ty (to_amode flags address offset) value))) + +;; Explicit 8/16/32-bit opcodes. +(rule (lower (istore8 flags value address offset)) + (side_effect + (x64_movrm $I8 (to_amode flags address offset) value))) +(rule (lower (istore16 flags value address offset)) + (side_effect + (x64_movrm $I16 (to_amode flags address offset) value))) +(rule (lower (istore32 flags value address offset)) + (side_effect + (x64_movrm $I32 (to_amode flags address offset) value))) + +;; IMM stores +(rule 4 (lower (store flags value @ (value_type (fits_in_64 ty)) address offset)) + (if-let (i32_from_iconst imm) value) + (side_effect + (x64_movimm_m ty (to_amode flags address offset) imm))) + +;; F16 stores of values in XMM registers. +(rule 0 (lower (store flags + value @ (value_type $F16) + address + offset)) + (side_effect + (x64_movrm $I16 (to_amode flags address offset) (bitcast_xmm_to_gpr 16 value)))) + +(rule 1 (lower (store flags + value @ (value_type $F16) + address + offset)) + (if-let true (use_sse41)) + (side_effect + (x64_pextrw_store (to_amode flags address offset) value 0))) + +;; F32 stores of values in XMM registers. +(rule 1 (lower (store flags + value @ (value_type $F32) + address + offset)) + (side_effect + (x64_movss_store (to_amode flags address offset) value))) + +;; F64 stores of values in XMM registers. +(rule 1 (lower (store flags + value @ (value_type $F64) + address + offset)) + (side_effect + (x64_movsd_store (to_amode flags address offset) value))) + +;; F128 stores of values in XMM registers. +(rule 1 (lower (store flags + value @ (value_type $F128) + address + offset)) + (side_effect + (x64_movdqu_store (to_amode flags address offset) value))) + +;; Stores of F32X4 vectors. +(rule 1 (lower (store flags + value @ (value_type $F32X4) + address + offset)) + (side_effect + (x64_movups_store (to_amode flags address offset) value))) + +;; Stores of F64X2 vectors. +(rule 1 (lower (store flags + value @ (value_type $F64X2) + address + offset)) + (side_effect + (x64_movupd_store (to_amode flags address offset) value))) + +;; Stores of all other 128-bit vector types with integer lanes. +(rule -1 (lower (store flags + value @ (value_type (ty_vec128_int _)) + address + offset)) + (side_effect + (x64_movdqu_store (to_amode flags address offset) value))) + +;; Stores of I128 values: store the two 64-bit halves separately. +(rule 0 (lower (store flags + value @ (value_type $I128) + address + offset)) + (let ((value_reg ValueRegs value) + (value_lo Gpr (value_regs_get_gpr value_reg 0)) + (value_hi Gpr (value_regs_get_gpr value_reg 1)) + (addr_lo Amode (to_amode flags address offset)) + (addr_hi Amode (amode_offset addr_lo 8))) + (side_effect + (side_effect_concat + (x64_movrm $I64 addr_lo value_lo) + (x64_movrm $I64 addr_hi value_hi))))) + +;; Slightly optimize the extraction of the first lane from a vector which is +;; stored in memory. In the case the first lane specifically is selected the +;; standard `movss` and `movsd` instructions can be used as-if we're storing a +;; f32 or f64 despite the source perhaps being an integer vector since the +;; result of the instruction is the same. +(rule 2 (lower (store flags + (has_type $F32 (extractlane value (u8_from_uimm8 0))) + address + offset)) + (side_effect + (x64_movss_store (to_amode flags address offset) value))) +(rule 2 (lower (store flags + (has_type $F64 (extractlane value (u8_from_uimm8 0))) + address + offset)) + (side_effect + (x64_movsd_store (to_amode flags address offset) value))) +(rule 2 (lower (store flags + (has_type $I8 (extractlane value (u8_from_uimm8 n))) + address + offset)) + (if-let true (use_sse41)) + (side_effect + (x64_pextrb_store (to_amode flags address offset) value n))) +(rule 2 (lower (store flags + (has_type $I16 (extractlane value (u8_from_uimm8 n))) + address + offset)) + (if-let true (use_sse41)) + (side_effect + (x64_pextrw_store (to_amode flags address offset) value n))) +(rule 2 (lower (store flags + (has_type $I32 (extractlane value (u8_from_uimm8 n))) + address + offset)) + (if-let true (use_sse41)) + (side_effect + (x64_pextrd_store (to_amode flags address offset) value n))) +(rule 2 (lower (store flags + (has_type $I64 (extractlane value (u8_from_uimm8 n))) + address + offset)) + (if-let true (use_sse41)) + (side_effect + (x64_pextrq_store (to_amode flags address offset) value n))) + +;; Rules for `load*` + ALU op + `store*` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Add mem, reg +(rule store_x64_add_mem 3 (lower + (store flags + (has_type (ty_32_or_64 ty) + (iadd (and + (sinkable_load sink) + (load flags addr offset)) + src2)) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_add_mem ty (to_amode flags addr offset) src2)))) + +;; Add mem, reg with args swapped +(rule 2 (lower + (store flags + (has_type (ty_32_or_64 ty) + (iadd src2 + (and + (sinkable_load sink) + (load flags addr offset)))) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_add_mem ty (to_amode flags addr offset) src2)))) + +;; Sub mem, reg +(rule 2 (lower + (store flags + (has_type (ty_32_or_64 ty) + (isub (and + (sinkable_load sink) + (load flags addr offset)) + src2)) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_sub_mem ty (to_amode flags addr offset) src2)))) + +;; And mem, reg +(rule 3 (lower + (store flags + (has_type (ty_32_or_64 ty) + (band (and + (sinkable_load sink) + (load flags addr offset)) + src2)) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_and_mem ty (to_amode flags addr offset) src2)))) + +;; And mem, reg with args swapped +(rule 2 (lower + (store flags + (has_type (ty_32_or_64 ty) + (band src2 + (and + (sinkable_load sink) + (load flags addr offset)))) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_and_mem ty (to_amode flags addr offset) src2)))) + +;; Or mem, reg +(rule 3 (lower + (store flags + (has_type (ty_32_or_64 ty) + (bor (and + (sinkable_load sink) + (load flags addr offset)) + src2)) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_or_mem ty (to_amode flags addr offset) src2)))) + +;; Or mem, reg with args swapped +(rule 2 (lower + (store flags + (has_type (ty_32_or_64 ty) + (bor src2 + (and + (sinkable_load sink) + (load flags addr offset)))) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_or_mem ty (to_amode flags addr offset) src2)))) + +;; Xor mem, reg +(rule 3 (lower + (store flags + (has_type (ty_32_or_64 ty) + (bxor (and + (sinkable_load sink) + (load flags addr offset)) + src2)) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_xor_mem ty (to_amode flags addr offset) src2)))) + +;; Xor mem, reg with args swapped +(rule 2 (lower + (store flags + (has_type (ty_32_or_64 ty) + (bxor src2 + (and + (sinkable_load sink) + (load flags addr offset)))) + addr + offset)) + (let ((_ RegMemImm sink)) + (side_effect + (x64_xor_mem ty (to_amode flags addr offset) src2)))) + +;; Rules for `fence` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (fence)) + (side_effect (x64_mfence))) + +;; Rules for `func_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (func_addr (func_ref_data _ extname dist))) + (load_ext_name extname 0 dist)) + +;; Rules for `symbol_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (symbol_value (symbol_value_data extname dist offset))) + (load_ext_name extname offset dist)) + +;; Rules for `atomic_load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This is a normal load. The x86-TSO memory model provides sufficient +;; sequencing to satisfy the CLIF synchronisation requirements for `AtomicLoad` +;; without the need for any fence instructions. +;; +;; This lowering is only valid for I8, I16, I32, and I64. The sub-64-bit types +;; are zero extended, as with a normal load. +(rule 1 (lower (has_type $I64 (atomic_load flags address))) + (x64_mov (to_amode flags address (zero_offset)))) +(rule (lower (has_type (and (fits_in_32 ty) (ty_int _)) (atomic_load flags address))) + (x64_movzx (ext_mode (ty_bits_u16 ty) 64) (to_amode flags address (zero_offset)))) +;; Lower 128-bit `atomic_load` using `cmpxchg16b`. +(rule 1 (lower (has_type $I128 (atomic_load flags address))) + (if-let true (use_cmpxchg16b)) + (x64_cmpxchg16b (value_regs (imm $I64 0) (imm $I64 0)) (value_regs (imm $I64 0) (imm $I64 0)) (to_amode flags address (zero_offset)))) + +;; Rules for `atomic_store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This is a normal store followed by an `mfence` instruction. This lowering is +;; only valid for I8, I16, I32, and I64. +(rule (lower (atomic_store flags + value @ (value_type (and (fits_in_64 ty) (ty_int _))) + address)) + (side_effect (side_effect_concat + (x64_movrm ty (to_amode flags address (zero_offset)) value) + (x64_mfence)))) +;; Lower 128-bit `atomic_store` using `cmpxchg16b`. +(rule 1 (lower (atomic_store flags value @ (value_type $I128) address)) + (if-let true (use_cmpxchg16b)) + (side_effect (x64_atomic_128_store_seq (to_amode flags address (zero_offset)) value))) + +;; Rules for `atomic_cas` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (and (fits_in_64 ty) (ty_int _)) + (atomic_cas flags address expected replacement))) + (x64_cmpxchg ty expected replacement (to_amode flags address (zero_offset)))) +(rule 1 (lower (has_type $I128 (atomic_cas flags address expected replacement))) + (if-let true (use_cmpxchg16b)) + (x64_cmpxchg16b expected replacement (to_amode flags address (zero_offset)))) + +;; Rules for `atomic_rmw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This is a simple, general-case atomic update, based on a loop involving +;; `cmpxchg`. +(rule (lower (has_type (and (fits_in_64 ty) (ty_int _)) + (atomic_rmw flags op address input))) + (x64_atomic_rmw_seq ty (atomic_rmw_seq_op op) (to_amode flags address (zero_offset)) input)) + +;; `Add` and `Sub` can use `lock xadd` +(rule 1 (lower (has_type (and (fits_in_64 ty) (ty_int _)) + (atomic_rmw flags (AtomicRmwOp.Add) address input))) + (x64_xadd (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) +(rule 1 (lower (has_type (and (fits_in_64 ty) (ty_int _)) + (atomic_rmw flags (AtomicRmwOp.Sub) address input))) + (x64_xadd (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) (x64_neg ty input))) +;; `Xchg` can use `xchg` +(rule 1 (lower (has_type (and (fits_in_64 ty) (ty_int _)) + (atomic_rmw flags (AtomicRmwOp.Xchg) address input))) + (x64_xchg (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) + +;; `Add`, `Sub`, `And`, `Or` and `Xor` can use `lock`-prefixed instructions if +;; the old value is not required. +(rule 2 (lower i @ (has_type (fits_in_64 (ty_int ty)) + (atomic_rmw flags (AtomicRmwOp.Add) address input))) + (if-let (first_result res) i) + (if-let true (value_is_unused res)) + (x64_lock_add (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) +(rule 2 (lower i @ (has_type (fits_in_64 (ty_int ty)) + (atomic_rmw flags (AtomicRmwOp.Sub) address input))) + (if-let (first_result res) i) + (if-let true (value_is_unused res)) + (x64_lock_sub (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) +(rule 2 (lower i @ (has_type (fits_in_64 (ty_int ty)) + (atomic_rmw flags (AtomicRmwOp.And) address input))) + (if-let (first_result res) i) + (if-let true (value_is_unused res)) + (x64_lock_and (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) +(rule 2 (lower i @ (has_type (fits_in_64 (ty_int ty)) + (atomic_rmw flags (AtomicRmwOp.Or) address input))) + (if-let (first_result res) i) + (if-let true (value_is_unused res)) + (x64_lock_or (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) +(rule 2 (lower i @ (has_type (fits_in_64 (ty_int ty)) + (atomic_rmw flags (AtomicRmwOp.Xor) address input))) + (if-let (first_result res) i) + (if-let true (value_is_unused res)) + (x64_lock_xor (raw_operand_size_of_type ty) (to_amode flags address (zero_offset)) input)) + +;; 128-bit integers always use a `lock cmpxchg16b` loop. +(rule 3 (lower (has_type $I128 (atomic_rmw flags op address input))) + (if-let true (use_cmpxchg16b)) + (x64_atomic_128_rmw_seq op (to_amode flags address (zero_offset)) input)) + +;; Rules for `call` and `call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (call (func_ref_data sig_ref extname dist) inputs)) + (gen_call sig_ref extname dist inputs)) + +(rule (lower (call_indirect sig_ref val inputs)) + (gen_call_indirect sig_ref val inputs)) + +;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (return_call (func_ref_data sig_ref extname dist) args)) + (gen_return_call sig_ref extname dist args)) + +(rule (lower (return_call_indirect sig_ref callee args)) + (gen_return_call_indirect sig_ref callee args)) + +;; Rules for `stack_switch` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; currently, only the Basic model is supported +(rule (lower (stack_switch store_context_ptr load_context_ptr in_payload0)) + (if-let (StackSwitchModel.Basic) (stack_switch_model)) + (let ((store_context_ptr Gpr (put_in_gpr store_context_ptr)) + (load_context_ptr Gpr (put_in_gpr load_context_ptr)) + (in_payload0 Gpr (put_in_gpr in_payload0))) + (x64_stack_switch_basic store_context_ptr load_context_ptr in_payload0))) + +;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;; + +(rule (lower (get_frame_pointer)) + (x64_rbp)) + +(rule (lower (get_stack_pointer)) + (x64_rsp)) + +(rule (lower (get_return_address)) + (x64_load $I64 + (Amode.ImmReg 8 (x64_rbp) (mem_flags_trusted)) + (ExtKind.None))) + +;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower_branch (jump _) (single_target target)) + (emit_side_effect (jmp_known target))) + +;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower_branch (brif (maybe_uextend (icmp cc a b)) _ _) (two_targets then else)) + (emit_side_effect (jmp_cond_icmp (emit_cmp cc a b) then else))) + +(rule 2 (lower_branch (brif (maybe_uextend (fcmp cc a b)) _ _) (two_targets then else)) + (emit_side_effect (jmp_cond_fcmp (emit_fcmp cc a b) then else))) + +(rule 2 (lower_branch (brif (maybe_uextend (vany_true a)) _ _) (two_targets then else)) + (emit_side_effect (jmp_cond_icmp (emit_vany_true a) then else))) + +(rule 2 (lower_branch (brif (maybe_uextend (vall_true a)) _ _) (two_targets then else)) + (emit_side_effect (jmp_cond_icmp (emit_vall_true a) then else))) + +(rule 1 (lower_branch (brif val @ (value_type $I128) _ _) + (two_targets then else)) + (emit_side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.Z) val) then else))) + +(rule (lower_branch (brif val @ (value_type (ty_int_bool_or_ref)) _ _) + (two_targets then else)) + (emit_side_effect (with_flags_side_effect + (cmp_zero_int_bool_ref val) + (jmp_cond (CC.NZ) then else)))) + + +;; Compare an I128 value to zero, returning a flags result suitable for making a +;; jump decision. The comparison is implemented as `(hi | low) == 0`, +;; and the result can be interpreted as follows +;; * CC.Z indicates that the value was non-zero, as one or both of the halves of +;; the value were non-zero +;; * CC.NZ indicates that both halves of the value were 0 +(decl cmp_zero_i128 (CC ValueRegs) IcmpCondResult) +(rule (cmp_zero_i128 (cc_nz_or_z cc) val) + (let ((lo Gpr (value_regs_get_gpr val 0)) + (hi Gpr (value_regs_get_gpr val 1))) + (icmp_cond_result + (x64_alurmi_flags_side_effect (AluRmiROpcode.Or) $I64 lo hi) + (cc_invert cc)))) + + +(decl cmp_zero_int_bool_ref (Value) ProducesFlags) +(rule (cmp_zero_int_bool_ref val @ (value_type ty)) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (src Gpr val)) + (x64_test size src src))) + +;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower_branch (br_table idx @ (value_type ty) _) (jump_table_targets default_target jt_targets)) + (let ((size OperandSize (raw_operand_size_of_type ty)) + (jt_size u32 (jump_table_size jt_targets)) + (size_reg Reg (imm ty (u32_as_u64 jt_size))) + (idx_reg Gpr (extend_to_gpr idx $I64 (ExtendKind.Zero))) + (clamped_idx Reg (with_flags_reg + (x64_cmp size idx_reg size_reg) + (cmove ty (CC.B) idx_reg size_reg)))) + (emit_side_effect (jmp_table_seq ty clamped_idx default_target jt_targets)))) + +;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (select_spectre_guard (icmp cc a b) x y)) + (select_icmp (emit_cmp cc a b) x y)) + +(rule -1 (lower (has_type ty (select_spectre_guard c @ (value_type (fits_in_64 a_ty)) x y))) + (let ((size OperandSize (raw_operand_size_of_type a_ty)) + (gpr_c Gpr (put_in_gpr c))) + (with_flags (x64_test size gpr_c gpr_c) (cmove_from_values ty (CC.NZ) x y)))) + +(rule -2 (lower (has_type ty (select_spectre_guard c @ (value_type $I128) x y))) + (let ((cond_result IcmpCondResult (cmp_zero_i128 (CC.Z) c))) + (select_icmp cond_result x y))) + +;; Rules for `fcvt_from_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Note that the `cvtsi2s{s,d}` instruction is not just an int-to-float +;; conversion instruction in isolation, it also takes the upper 64-bits of an +;; xmm register and places it into the destination. We don't actually want that +;; to happen as it could accidentally create a false dependency with a +;; previous instruction defining the register's upper 64-bits. See #7085 for +;; an instance of this. +;; +;; This means that the first operand to all of the int-to-float conversions here +;; are `(xmm_zero)` operands which is a guaranteed zero register that has no +;; dependencies on other instructions. +;; +;; Ideally this would be lifted out to a higher level to get deduplicated +;; between consecutive int-to-float operations but that's not easy +;; to do at this time. One possibility would be a mid-end rule which rewrites +;; `fcvt_from_sint` to an x86-specific opcode using a zero constant which would +;; be subject to normal LICM, but that's not feasible today. + +(rule 2 (lower (has_type $F32 (fcvt_from_sint a @ (value_type $I8)))) + (x64_cvtsi2ss $I32 (xmm_zero $F32X4) (extend_to_gpr a $I32 (ExtendKind.Sign)))) + +(rule 2 (lower (has_type $F32 (fcvt_from_sint a @ (value_type $I16)))) + (x64_cvtsi2ss $I32 (xmm_zero $F32X4) (extend_to_gpr a $I32 (ExtendKind.Sign)))) + +(rule 1 (lower (has_type $F32 (fcvt_from_sint a @ (value_type (ty_int (fits_in_64 ty)))))) + (x64_cvtsi2ss ty (xmm_zero $F32X4) a)) + +(rule 2 (lower (has_type $F64 (fcvt_from_sint a @ (value_type $I8)))) + (x64_cvtsi2sd $I32 (xmm_zero $F64X2) (extend_to_gpr a $I32 (ExtendKind.Sign)))) + +(rule 2 (lower (has_type $F64 (fcvt_from_sint a @ (value_type $I16)))) + (x64_cvtsi2sd $I32 (xmm_zero $F64X2) (extend_to_gpr a $I32 (ExtendKind.Sign)))) + +(rule 1 (lower (has_type $F64 (fcvt_from_sint a @ (value_type (ty_int (fits_in_64 ty)))))) + (x64_cvtsi2sd ty (xmm_zero $F64X2) a)) + +(rule 0 (lower (fcvt_from_sint a @ (value_type $I32X4))) + (x64_cvtdq2ps a)) + +;; Base case: decompose the i64x2 input into two scalar registers and convert +;; each of those into a float. Afterwards re-pack the two results into the final +;; destination. +(rule 0 (lower (fcvt_from_sint a @ (value_type $I64X2))) + (let ( + (a Xmm a) + (zero Xmm (xmm_zero $F64X2)) + (f0 Xmm (x64_cvtsi2sd $I64 zero (x64_movq_to_gpr a))) + (f1 Xmm (x64_cvtsi2sd $I64 zero (x64_movq_to_gpr (x64_pshufd a 0b11_10_11_10)))) + ) + (x64_unpcklpd f0 f1))) + +(rule 1 (lower (has_type $F64X2 (fcvt_from_sint (swiden_low a @ (value_type $I32X4))))) + (x64_cvtdq2pd a)) + +;; Rules for `fcvt_from_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (has_type $F32 (fcvt_from_uint val @ (value_type (fits_in_32 (ty_int ty)))))) + (x64_cvtsi2ss $I64 (xmm_zero $F32X4) (extend_to_gpr val $I64 (ExtendKind.Zero)))) + +(rule 1 (lower (has_type $F64 (fcvt_from_uint val @ (value_type (fits_in_32 (ty_int ty)))))) + (x64_cvtsi2sd $I64 (xmm_zero $F64X2) (extend_to_gpr val $I64 (ExtendKind.Zero)))) + +(rule (lower (has_type ty (fcvt_from_uint val @ (value_type $I64)))) + (cvt_u64_to_float_seq ty val)) + +;; Base case of u64x2 being converted to f64x2. No native instruction for this +;; is available so it's emulated through a series of instructions that exploit +;; the binary representation of 64-bit floats. This sequence of instructions is +;; copied from LLVM and my understanding of the general idea is to roughly: +;; +;; * For each bullet below operate in parallel on the left and right lanes. +;; * Move the low 32 bits of the input into one register and the upper +;; 32-bits into a different register, where both have all 0s for the upper +;; 32-bits. (e.g. split the 64-bit input into two locations) +;; * For the low bits, create `1.p52` via bit tricks. +;; * For the high bits, create `1.p84` via bit tricks. +;; * Create the constant `1.0p84 + 1.0p52` +;; * Add the two high halves and subtract the constant. +;; +;; Apply some math and this should produce the same result as the native +;; conversion. +;; +;; As for the bit tricks a float is represented where the low 53 bits are the +;; decimal of the float, basically: +;; +;; f = 1. ^ ( - 1023) +;; +;; where `` is the low 53 bits. By placing the 32-bit halves from +;; the original integer into the low 53 bits and setting the exponent right it +;; means that each 32-bit half can become part of a 64-bit floating point +;; number. The final step in combining via float arithmetic will chop off the +;; leading `1.` at the start of the float that we constructed, one for the low +;; half and one for the upper half. +(rule -1 (lower (has_type $F64X2 (fcvt_from_uint val @ (value_type $I64X2)))) + (let ((low32_mask XmmMem (emit_u128_le_const 0x00000000ffffffff_00000000ffffffff)) + (float_1p52 XmmMem (emit_u128_le_const 0x4330000000000000_4330000000000000)) + (float_1p84 XmmMem (emit_u128_le_const 0x4530000000000000_4530000000000000)) + (float_1p84_plus_1p52 XmmMem (emit_u128_le_const 0x4530000000100000_4530000000100000)) + (low32 Xmm (x64_pand val low32_mask)) + (low32_as_float Xmm (x64_por low32 float_1p52)) + (high32 Xmm (x64_psrlq val (xmi_imm 32))) + (high32_as_float Xmm (x64_por high32 float_1p84))) + (x64_addpd low32_as_float (x64_subpd high32_as_float float_1p84_plus_1p52)))) + +;; Algorithm uses unpcklps to help create a float that is equivalent +;; 0x1.0p52 + double(src). 0x1.0p52 is unique because at this exponent +;; every value of the mantissa represents a corresponding uint32 number. +;; When we subtract 0x1.0p52 we are left with double(src). +(rule 1 (lower (has_type $F64X2 (fcvt_from_uint (uwiden_low val @ (value_type $I32X4))))) + (let ((uint_mask XmmMem (emit_u128_le_const 0x43300000_43300000)) + (res Xmm (x64_unpcklps val uint_mask)) + (uint_mask_high XmmMem (emit_u128_le_const 0x4330000000000000_4330000000000000))) + (x64_subpd res uint_mask_high))) + +;; When AVX512VL and AVX512F are available, +;; `fcvt_from_uint` can be lowered to a single instruction. +(rule 2 (lower (has_type $F32X4 (fcvt_from_uint src))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512f)) + (x64_vcvtudq2ps src)) + +;; Converting packed unsigned integers to packed floats +;; requires a few steps. There is no single instruction +;; lowering for converting unsigned floats but there is for +;; converting packed signed integers to float (cvtdq2ps). In +;; the steps below we isolate the upper half (16 bits) and +;; lower half (16 bits) of each lane and then we convert +;; each half separately using cvtdq2ps meant for signed +;; integers. In order for this to work for the upper half +;; bits we must shift right by 1 (divide by 2) these bits in +;; order to ensure the most significant bit is 0 not signed, +;; and then after the conversion we double the value. +;; Finally we add the converted values where addition will +;; correctly round. +;; +;; Sequence: +;; -> A = 0xffffffff +;; -> Ah = 0xffff0000 +;; -> Al = 0x0000ffff +;; -> Convert(Al) // Convert int to float +;; -> Ah = Ah >> 1 // Shift right 1 to assure Ah conversion isn't treated as signed +;; -> Convert(Ah) // Convert .. with no loss of significant digits from previous shift +;; -> Ah = Ah + Ah // Double Ah to account for shift right before the conversion. +;; -> dst = Ah + Al // Add the two floats together +(rule 1 (lower (has_type $F32X4 (fcvt_from_uint val))) + (let ((a Xmm val) + + ;; get the low 16 bits + (a_lo Xmm (x64_pslld a (xmi_imm 16))) + (a_lo Xmm (x64_psrld a_lo (xmi_imm 16))) + + ;; get the high 16 bits + (a_hi Xmm (x64_psubd a a_lo)) + + ;; convert the low 16 bits + (a_lo Xmm (x64_cvtdq2ps a_lo)) + + ;; shift the high bits by 1, convert, and double to get the correct + ;; value + (a_hi Xmm (x64_psrld a_hi (xmi_imm 1))) + (a_hi Xmm (x64_cvtdq2ps a_hi)) + (a_hi Xmm (x64_addps a_hi a_hi))) + + ;; add together the two converted values + (x64_addps a_hi a_lo))) + +;; Rules for `fcvt_to_uint` and `fcvt_to_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type out_ty (fcvt_to_uint val @ (value_type (ty_scalar_float _))))) + (cvt_float_to_uint_seq out_ty val false)) + +(rule (lower (has_type out_ty (fcvt_to_uint_sat val @ (value_type (ty_scalar_float _))))) + (cvt_float_to_uint_seq out_ty val true)) + +(rule (lower (has_type out_ty (fcvt_to_sint val @ (value_type (ty_scalar_float _))))) + (cvt_float_to_sint_seq out_ty val false)) + +(rule (lower (has_type out_ty (fcvt_to_sint_sat val @ (value_type (ty_scalar_float _))))) + (cvt_float_to_sint_seq out_ty val true)) + +;; The x64 backend currently only supports these two type combinations. +(rule 1 (lower (has_type $I32X4 (fcvt_to_sint_sat val @ (value_type $F32X4)))) + (let ((src Xmm val) + + ;; Sets tmp to zero if float is NaN + (tmp Xmm (x64_cmpps src src (FcmpImm.Equal))) + (dst Xmm (x64_andps src tmp)) + + ;; Sets top bit of tmp if float is positive + ;; Setting up to set top bit on negative float values + (tmp Xmm (x64_pxor tmp dst)) + + ;; Convert the packed float to packed doubleword. + (dst Xmm (x64_cvttps2dq dst)) + + ;; Set top bit only if < 0 + (tmp Xmm (x64_pand dst tmp)) + (tmp Xmm (x64_psrad tmp (xmi_imm 31)))) + + ;; On overflow 0x80000000 is returned to a lane. + ;; Below sets positive overflow lanes to 0x7FFFFFFF + ;; Keeps negative overflow lanes as is. + (x64_pxor tmp dst))) + +;; The algorithm for converting floats to unsigned ints is a little tricky. The +;; complication arises because we are converting from a signed 64-bit int with a positive +;; integer range from 1..INT_MAX (0x1..0x7FFFFFFF) to an unsigned integer with an extended +;; range from (INT_MAX+1)..UINT_MAX. It's this range from (INT_MAX+1)..UINT_MAX +;; (0x80000000..0xFFFFFFFF) that needs to be accounted for as a special case since our +;; conversion instruction (cvttps2dq) only converts as high as INT_MAX (0x7FFFFFFF), but +;; which conveniently setting underflows and overflows (smaller than MIN_INT or larger than +;; MAX_INT) to be INT_MAX+1 (0x80000000). Nothing that the range (INT_MAX+1)..UINT_MAX includes +;; precisely INT_MAX values we can correctly account for and convert every value in this range +;; if we simply subtract INT_MAX+1 before doing the cvttps2dq conversion. After the subtraction +;; every value originally (INT_MAX+1)..UINT_MAX is now the range (0..INT_MAX). +;; After the conversion we add INT_MAX+1 back to this converted value, noting again that +;; values we are trying to account for were already set to INT_MAX+1 during the original conversion. +;; We simply have to create a mask and make sure we are adding together only the lanes that need +;; to be accounted for. Digesting it all the steps then are: +;; +;; Step 1 - Account for NaN and negative floats by setting these src values to zero. +;; Step 2 - Make a copy (tmp1) of the src value since we need to convert twice for +;; reasons described above. +;; Step 3 - Convert the original src values. This will convert properly all floats up to INT_MAX +;; Step 4 - Subtract INT_MAX from the copy set (tmp1). Note, all zero and negative values are those +;; values that were originally in the range (0..INT_MAX). This will come in handy during +;; step 7 when we zero negative lanes. +;; Step 5 - Create a bit mask for tmp1 that will correspond to all lanes originally less than +;; UINT_MAX that are now less than INT_MAX thanks to the subtraction. +;; Step 6 - Convert the second set of values (tmp1) +;; Step 7 - Prep the converted second set by zeroing out negative lanes (these have already been +;; converted correctly with the first set) and by setting overflow lanes to 0x7FFFFFFF +;; as this will allow us to properly saturate overflow lanes when adding to 0x80000000 +;; Step 8 - Add the original converted src and the converted tmp1 where float values originally less +;; than and equal to INT_MAX will be unchanged, float values originally between INT_MAX+1 and +;; UINT_MAX will add together (INT_MAX) + (SRC - INT_MAX), and float values originally +;; greater than UINT_MAX will be saturated to UINT_MAX (0xFFFFFFFF) after adding (0x8000000 + 0x7FFFFFFF). +;; +;; +;; The table below illustrates the result after each step where it matters for the converted set. +;; Note the original value range (original src set) is the final dst in Step 8: +;; +;; Original src set: +;; | Original Value Range | Step 1 | Step 3 | Step 8 | +;; | -FLT_MIN..FLT_MAX | 0.0..FLT_MAX | 0..INT_MAX(w/overflow) | 0..UINT_MAX(w/saturation) | +;; +;; Copied src set (tmp1): +;; | Step 2 | Step 4 | +;; | 0.0..FLT_MAX | (0.0-(INT_MAX+1))..(FLT_MAX-(INT_MAX+1)) | +;; +;; | Step 6 | Step 7 | +;; | (0-(INT_MAX+1))..(UINT_MAX-(INT_MAX+1))(w/overflow) | ((INT_MAX+1)-(INT_MAX+1))..(INT_MAX+1) | +(rule 1 (lower (has_type $I32X4 (fcvt_to_uint_sat val @ (value_type $F32X4)))) + (let ((src Xmm val) + + ;; Converting to unsigned int so if float src is negative or NaN + ;; will first set to zero. + (tmp2 Xmm (xmm_zero $F32X4)) + (dst Xmm (x64_maxps src tmp2)) + + ;; Set tmp2 to INT_MAX+1. It is important to note here that after it looks + ;; like we are only converting INT_MAX (0x7FFFFFFF) but in fact because + ;; single precision IEEE-754 floats can only accurately represent contiguous + ;; integers up to 2^23 and outside of this range it rounds to the closest + ;; integer that it can represent. In the case of INT_MAX, this value gets + ;; represented as 0x4f000000 which is the integer value (INT_MAX+1). + (tmp2 Xmm (x64_pcmpeqd tmp2 tmp2)) + (tmp2 Xmm (x64_psrld tmp2 (xmi_imm 1))) + (tmp2 Xmm (x64_cvtdq2ps tmp2)) + + ;; Make a copy of these lanes and then do the first conversion. + ;; Overflow lanes greater than the maximum allowed signed value will + ;; set to 0x80000000. Negative and NaN lanes will be 0x0 + (tmp1 Xmm dst) + (dst Xmm (x64_cvttps2dq dst)) + + ;; Set lanes to src - max_signed_int + (tmp1 Xmm (x64_subps tmp1 tmp2)) + + ;; Create mask for all positive lanes to saturate (i.e. greater than + ;; or equal to the maximum allowable unsigned int). + (tmp2 Xmm (x64_cmpps tmp2 tmp1 (FcmpImm.LessThanOrEqual))) + + ;; Convert those set of lanes that have the max_signed_int factored out. + (tmp1 Xmm (x64_cvttps2dq tmp1)) + + ;; Prepare converted lanes by zeroing negative lanes and prepping lanes + ;; that have positive overflow (based on the mask) by setting these lanes + ;; to 0x7FFFFFFF + (tmp1 Xmm (x64_pxor tmp1 tmp2)) + (tmp2 Xmm (xmm_zero $I32X4)) + (tmp1 Xmm (lower_vec_smax $I32X4 tmp1 tmp2))) + + ;; Add this second set of converted lanes to the original to properly handle + ;; values greater than max signed int. + (x64_paddd tmp1 dst))) + +;; Rules for `x86_cvtt2dq` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I32X4 (x86_cvtt2dq val @ (value_type $F32X4)))) + (x64_cvttps2dq val)) + +;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (iadd_pairwise x y))) + (let ( + ;; Shuffle all the even lanes of `x` and `y` into one register + (even_lane_mask Xmm (x64_movdqu_load (emit_u128_le_const 0x00ff_00ff_00ff_00ff_00ff_00ff_00ff_00ff))) + (x_evens Xmm (x64_pand x even_lane_mask)) + (y_evens Xmm (x64_pand y even_lane_mask)) + (evens Xmm (x64_packuswb x_evens y_evens)) + + ;; Shuffle all the odd lanes of `x` and `y` into one register + (x_odds Xmm (x64_psrlw x (xmi_imm 8))) + (y_odds Xmm (x64_psrlw y (xmi_imm 8))) + (odds Xmm (x64_packuswb x_odds y_odds)) + ) + (x64_paddb evens odds))) + + +(rule 1 (lower (has_type $I16X8 (iadd_pairwise x y))) + (if-let true (use_ssse3)) + (x64_phaddw x y)) + +(rule (lower (has_type $I16X8 (iadd_pairwise x y))) + (let ( + (x Xmm x) + (y Xmm y) + + ;; Shuffle the even-numbered 16-bit lanes into low four lanes of each + ;; vector by shuffling 16-bit lanes then shuffling 32-bit lanes. + ;; With these in place generate a new vector from the two low 64-bits + ;; of each vector (the low four 16-bit lanes). + ;; + ;; 0xe8 == 0b11_10_10_00 + (x_evens Xmm (x64_pshufd (x64_pshufhw (x64_pshuflw x 0xe8) 0xe8) 0xe8)) + (y_evens Xmm (x64_pshufd (x64_pshufhw (x64_pshuflw y 0xe8) 0xe8) 0xe8)) + (evens Xmm (x64_punpcklqdq x_evens y_evens)) + + ;; Shuffle the odd-numbered 16-bit lanes into the low 8 lanes by + ;; performing `sshr` operation on 32-bit lanes, effectively moving the + ;; odd lanes into even lanes while leaving their sign bits in the + ;; odd lanes. The `packssdw` instruction then conveniently will + ;; put everything into one vector for us. + (x_shifted Xmm (x64_psrad x (xmi_imm 16))) + (y_shifted Xmm (x64_psrad y (xmi_imm 16))) + (odds Xmm (x64_packssdw x_shifted y_shifted)) + ) + (x64_paddw evens odds))) + +(rule 1 (lower (has_type $I32X4 (iadd_pairwise x y))) + (if-let true (use_ssse3)) + (x64_phaddd x y)) + +(rule (lower (has_type $I32X4 (iadd_pairwise x y))) + (let ( + (x Xmm x) + (y Xmm y) + ;; evens = [ x[0] x[2] y[0] y[2] ] + (evens Xmm (x64_shufps x y 0b10_00_10_00)) + ;; odds = [ x[1] x[3] y[1] y[3] ] + (odds Xmm (x64_shufps x y 0b11_01_11_01)) + ) + (x64_paddd evens odds))) + +;; special case for the `i16x8.extadd_pairwise_i8x16_s` wasm instruction +(rule 2 (lower + (has_type $I16X8 (iadd_pairwise + (swiden_low val @ (value_type $I8X16)) + (swiden_high val)))) + (if-let true (use_ssse3)) + (let ((mul_const Xmm (x64_xmm_load_const $I8X16 + (emit_u128_le_const 0x01010101010101010101010101010101)))) + (x64_pmaddubsw mul_const val))) + +;; special case for the `i32x4.extadd_pairwise_i16x8_s` wasm instruction +(rule 2 (lower + (has_type $I32X4 (iadd_pairwise + (swiden_low val @ (value_type $I16X8)) + (swiden_high val)))) + (let ((mul_const XmmMem (emit_u128_le_const 0x0001_0001_0001_0001_0001_0001_0001_0001))) + (x64_pmaddwd val mul_const))) + +;; special case for the `i16x8.extadd_pairwise_i8x16_u` wasm instruction +(rule 2 (lower + (has_type $I16X8 (iadd_pairwise + (uwiden_low val @ (value_type $I8X16)) + (uwiden_high val)))) + (if-let true (use_ssse3)) + (let ((mul_const XmmMem (emit_u128_le_const 0x01010101010101010101010101010101))) + (x64_pmaddubsw val mul_const))) + +;; special case for the `i32x4.extadd_pairwise_i16x8_u` wasm instruction +(rule 2 (lower + (has_type $I32X4 (iadd_pairwise + (uwiden_low val @ (value_type $I16X8)) + (uwiden_high val)))) + (let ((xor_const XmmMem (emit_u128_le_const 0x8000_8000_8000_8000_8000_8000_8000_8000)) + (dst Xmm (x64_pxor val xor_const)) + + (madd_const XmmMem (emit_u128_le_const 0x0001_0001_0001_0001_0001_0001_0001_0001)) + (dst Xmm (x64_pmaddwd dst madd_const)) + + (addd_const XmmMem (emit_u128_le_const 0x00010000_00010000_00010000_00010000))) + (x64_paddd dst addd_const))) + +;; special case for the `i32x4.dot_i16x8_s` wasm instruction +(rule 2 (lower + (has_type $I32X4 (iadd_pairwise + (imul (swiden_low x) (swiden_low y)) + (imul (swiden_high x) (swiden_high y))))) + (x64_pmaddwd x y)) + +;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; With SSE4.1 use the `pmovsx*` instructions for this +(rule 1 (lower (has_type $I16X8 (swiden_low val @ (value_type $I8X16)))) + (if-let true (use_sse41)) + (x64_pmovsxbw val)) +(rule 1 (lower (has_type $I32X4 (swiden_low val @ (value_type $I16X8)))) + (if-let true (use_sse41)) + (x64_pmovsxwd val)) +(rule 1 (lower (has_type $I64X2 (swiden_low val @ (value_type $I32X4)))) + (if-let true (use_sse41)) + (x64_pmovsxdq val)) + +(rule (lower (has_type ty (swiden_low val))) (lower_swiden_low ty val)) + +(decl lower_swiden_low (Type Xmm) Xmm) + +;; Duplicate the low lanes next to each other, then perform a wider shift-right +;; by the low lane width to move the upper of each pair back into the lower lane +;; of each pair, achieving the widening of the lower lanes. +(rule (lower_swiden_low $I16X8 val) + (x64_psraw (x64_punpcklbw val val) (xmi_imm 8))) +(rule (lower_swiden_low $I32X4 val) + (x64_psrad (x64_punpcklwd val val) (xmi_imm 16))) + +;; Generate the sign-extended halves with a `val < 0` comparison (expressed +;; reversed here), then interleave the low 32-bit halves to create the full +;; 64-bit results. +(rule (lower_swiden_low $I64X2 val) + (let ((tmp Xmm (x64_pcmpgtd (xmm_zero $I32X4) val))) + (x64_punpckldq val tmp))) + +;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Similar to `swiden_low` with SSE4.1 except that the upper lanes are moved +;; to the lower lanes first. +(rule 1 (lower (has_type $I16X8 (swiden_high val @ (value_type $I8X16)))) + (if-let true (use_sse41)) + (if-let true (use_ssse3)) + (let ((x Xmm val)) + (x64_pmovsxbw (x64_palignr x x 8)))) +(rule 1 (lower (has_type $I32X4 (swiden_high val @ (value_type $I16X8)))) + (if-let true (use_sse41)) + (if-let true (use_ssse3)) + (let ((x Xmm val)) + (x64_pmovsxwd (x64_palignr x x 8)))) +(rule 1 (lower (has_type $I64X2 (swiden_high val @ (value_type $I32X4)))) + (if-let true (use_sse41)) + (x64_pmovsxdq (x64_pshufd val 0b11_10_11_10))) + +;; Similar to `swiden_low` versions but using `punpckh*` instructions to +;; pair the high lanes next to each other. +(rule (lower (has_type $I16X8 (swiden_high val @ (value_type $I8X16)))) + (let ((val Xmm val)) + (x64_psraw (x64_punpckhbw val val) (xmi_imm 8)))) +(rule (lower (has_type $I32X4 (swiden_high val @ (value_type $I16X8)))) + (let ((val Xmm val)) + (x64_psrad (x64_punpckhwd val val) (xmi_imm 16)))) + +;; Same as `swiden_low`, but `val` has its high lanes moved down. +(rule (lower (has_type $I64X2 (swiden_high val @ (value_type $I32X4)))) + (let ((val Xmm (x64_pshufd val 0b00_00_11_10)) + (tmp Xmm (x64_pcmpgtd (xmm_zero $I32X4) val))) + (x64_punpckldq val tmp))) + +;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; With SSE4.1 use the `pmovzx*` instructions for this +(rule 1 (lower (has_type $I16X8 (uwiden_low val @ (value_type $I8X16)))) + (if-let true (use_sse41)) + (x64_pmovzxbw val)) +(rule 1 (lower (has_type $I32X4 (uwiden_low val @ (value_type $I16X8)))) + (if-let true (use_sse41)) + (x64_pmovzxwd val)) +(rule 1 (lower (has_type $I64X2 (uwiden_low val @ (value_type $I32X4)))) + (if-let true (use_sse41)) + (x64_pmovzxdq val)) + +(rule (lower (has_type ty (uwiden_low val))) (lower_uwiden_low ty val)) + +;; Interleave an all-zero register with the low lanes to produce zero-extended +;; results. +(decl lower_uwiden_low (Type Xmm) Xmm) +(rule (lower_uwiden_low $I16X8 val) (x64_punpcklbw val (xmm_zero $I8X16))) +(rule (lower_uwiden_low $I32X4 val) (x64_punpcklwd val (xmm_zero $I8X16))) +(rule (lower_uwiden_low $I64X2 val) (x64_unpcklps val (xmm_zero $F32X4))) + +;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Same as `uwiden_high`, but interleaving high lanes instead. +;; +;; Note that according to `llvm-mca` at least these instructions are faster +;; than using `pmovzx*` in terms of cycles, even if SSE4.1 is available. +(rule (lower (has_type $I16X8 (uwiden_high val @ (value_type $I8X16)))) + (x64_punpckhbw val (xmm_zero $I8X16))) +(rule (lower (has_type $I32X4 (uwiden_high val @ (value_type $I16X8)))) + (x64_punpckhwd val (xmm_zero $I8X16))) +(rule (lower (has_type $I64X2 (uwiden_high val @ (value_type $I32X4)))) + (x64_unpckhps val (xmm_zero $F32X4))) + +;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (snarrow a @ (value_type $I16X8) b))) + (x64_packsswb a b)) + +(rule (lower (has_type $I16X8 (snarrow a @ (value_type $I32X4) b))) + (x64_packssdw a b)) + +;; We're missing a `snarrow` case for $I64X2 +;; https://github.com/bytecodealliance/wasmtime/issues/4734 + +;; This rule is a special case for handling the translation of the wasm op +;; `i32x4.trunc_sat_f64x2_s_zero`. It can be removed once we have an +;; implementation of `snarrow` for `I64X2`. +(rule (lower (has_type $I32X4 (snarrow (has_type $I64X2 (fcvt_to_sint_sat val)) + (vconst (u128_from_constant 0))))) + (let ((a Xmm val) + + ;; y = i32x4.trunc_sat_f64x2_s_zero(x) is lowered to: + ;; MOVE xmm_tmp, xmm_x + ;; CMPEQPD xmm_tmp, xmm_x + ;; MOVE xmm_y, xmm_x + ;; ANDPS xmm_tmp, [wasm_f64x2_splat(2147483647.0)] + ;; MINPD xmm_y, xmm_tmp + ;; CVTTPD2DQ xmm_y, xmm_y + + (tmp1 Xmm (x64_cmppd a a (FcmpImm.Equal))) + + ;; 2147483647.0 is equivalent to 0x41DFFFFFFFC00000 + (umax_mask XmmMem (emit_u128_le_const 0x41DFFFFFFFC00000_41DFFFFFFFC00000)) + + ;; ANDPD xmm_y, [wasm_f64x2_splat(2147483647.0)] + (tmp1 Xmm (x64_andps tmp1 umax_mask)) + (dst Xmm (x64_minpd a tmp1))) + (x64_cvttpd2dq dst))) + +;; This rule is a special case for handling the translation of the wasm op +;; `i32x4.relaxed_trunc_f64x2_s_zero`. +(rule (lower (has_type $I32X4 (snarrow (has_type $I64X2 (x86_cvtt2dq val)) + (vconst (u128_from_constant 0))))) + (x64_cvttpd2dq val)) + +;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $I8X16 (unarrow a @ (value_type $I16X8) b))) + (x64_packuswb a b)) + +(rule 1 (lower (has_type $I16X8 (unarrow a @ (value_type $I32X4) b))) + (if-let true (use_sse41)) + (x64_packusdw a b)) + +;; For each input `a` and `b` take the four 32-bit lanes and compress them to +;; the low 64-bits of the vector as four 16-bit lanes. Then these are woven +;; into one final vector with a `punpcklqdq`. +;; +;; If this is performance sensitive then it's probably best to upgrade the CPU +;; to get the above single-instruction lowering. +(rule (lower (has_type $I16X8 (unarrow a @ (value_type $I32X4) b))) + (let ( + (a Xmm (unarrow_i32x4_lanes_to_low_u16_lanes a)) + (b Xmm (unarrow_i32x4_lanes_to_low_u16_lanes b)) + ) + (x64_punpcklqdq a b))) + +(decl unarrow_i32x4_lanes_to_low_u16_lanes (Xmm) Xmm) +(rule (unarrow_i32x4_lanes_to_low_u16_lanes val) + (let ( + ;; First convert all negative values in `val` to zero lanes. + (val_gt_zero Xmm (x64_pcmpgtd val (xmm_zero $I32X4))) + (val Xmm (x64_pand val val_gt_zero)) + + ;; Next clamp all larger-than-u16-max lanes to u16::MAX. + (max Xmm (x64_movdqu_load (emit_u128_le_const 0x0000ffff_0000ffff_0000ffff_0000ffff))) + (cmp Xmm (x64_pcmpgtd max val)) + (valid_lanes Xmm (x64_pand val cmp)) + (clamped_lanes Xmm (x64_pandn cmp max)) + (val Xmm (x64_por valid_lanes clamped_lanes)) + + ;; Within each 64-bit half of the 32x4 vector move the first 16 bits + ;; and the third 16 bits to the bottom of the half. Afterwards + ;; for the 32x4 vector move the first and third lanes to the bottom + ;; lanes, which finishes up the conversion here as all the lanes + ;; are now converted to 16-bit values in the low 4 lanes. + (val Xmm (x64_pshuflw val 0b00_00_10_00)) + (val Xmm (x64_pshufhw val 0b00_00_10_00)) + ) + (x64_pshufd val 0b00_00_10_00))) + + +;; We're missing a `unarrow` case for $I64X2 +;; https://github.com/bytecodealliance/wasmtime/issues/4734 + +;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule -3 (lower (has_type (is_gpr_type (fits_in_64 ty)) (bitcast _ src @ (value_type (is_xmm_type _))))) + (bitcast_xmm_to_gpr (ty_bits ty) src)) + +(rule -2 (lower (has_type (is_xmm_type (fits_in_64 ty)) (bitcast _ src @ (value_type (is_gpr_type _))))) + (bitcast_gpr_to_xmm (ty_bits ty) src)) + +(rule -1 (lower (has_type $I128 (bitcast _ src @ (value_type (is_xmm_type _))))) + (bitcast_xmm_to_gprs src)) + +(rule 0 (lower (has_type (is_xmm_type _) (bitcast _ src @ (value_type $I128)))) + (bitcast_gprs_to_xmm src)) + +;; Bitcast between types residing in GPR registers is a no-op. +(rule 1 (lower (has_type (is_gpr_type _) + (bitcast _ x @ (value_type (is_gpr_type _))))) + x) + +;; Bitcast between types residing in XMM registers is a no-op. +(rule 3 (lower (has_type (is_xmm_type _) + (bitcast _ x @ (value_type (is_xmm_type _))))) + x) + +;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type $F32 (fcopysign a @ (value_type $F32) b))) + (let ((sign_bit Xmm (imm $F32 0x80000000))) + (x64_orps + (x64_andnps sign_bit a) + (x64_andps sign_bit b)))) + +(rule (lower (has_type $F64 (fcopysign a @ (value_type $F64) b))) + (let ((sign_bit Xmm (imm $F64 0x8000000000000000))) + (x64_orpd + (x64_andnpd sign_bit a) + (x64_andpd sign_bit b)))) + +;; Helper for the `ceil`/`floor`/`nearest`/`trunc` instructions ;;;;;;;;;;;;;;;; + +;; Emits either a `round{ss,sd,ps,pd}` instruction, as appropriate, or generates +;; the appropriate libcall and sequence to call that. +(decl x64_round (Type RegMem RoundImm) Xmm) +(rule 1 (x64_round $F32 a imm) + (if-let true (use_sse41)) + (x64_roundss a imm)) +(rule 1 (x64_round $F64 a imm) + (if-let true (use_sse41)) + (x64_roundsd a imm)) +(rule 1 (x64_round $F32X4 a imm) + (if-let true (use_sse41)) + (x64_roundps a imm)) +(rule 1 (x64_round $F64X2 a imm) + (if-let true (use_sse41)) + (x64_roundpd a imm)) + +(rule (x64_round $F32 (RegMem.Reg a) imm) (libcall_1 (round_libcall $F32 imm) a)) +(rule (x64_round $F64 (RegMem.Reg a) imm) (libcall_1 (round_libcall $F64 imm) a)) +(rule (x64_round $F32X4 (RegMem.Reg a) imm) + (let ( + (libcall LibCall (round_libcall $F32 imm)) + (result Xmm (libcall_1 libcall a)) + (a1 Xmm (libcall_1 libcall (x64_pshufd a 1))) + (result Xmm (f32x4_insertlane result a1 1)) + (a2 Xmm (libcall_1 libcall (x64_pshufd a 2))) + (result Xmm (f32x4_insertlane result a2 2)) + (a3 Xmm (libcall_1 libcall (x64_pshufd a 3))) + (result Xmm (f32x4_insertlane result a3 3)) + ) + result)) +(rule (x64_round $F64X2 (RegMem.Reg a) imm) + (let ( + (libcall LibCall (round_libcall $F64 imm)) + (result Xmm (libcall_1 libcall a)) + (a1 Xmm (libcall_1 libcall (x64_pshufd a 0b00_00_11_10))) + ) + (x64_movlhps result a1))) +(rule (x64_round ty (RegMem.Mem addr) imm) + (x64_round ty (RegMem.Reg (x64_load ty addr (ExtKind.ZeroExtend))) imm)) + +(decl round_libcall (Type RoundImm) LibCall) +(rule (round_libcall $F32 (RoundImm.RoundUp)) (LibCall.CeilF32)) +(rule (round_libcall $F64 (RoundImm.RoundUp)) (LibCall.CeilF64)) +(rule (round_libcall $F32 (RoundImm.RoundDown)) (LibCall.FloorF32)) +(rule (round_libcall $F64 (RoundImm.RoundDown)) (LibCall.FloorF64)) +(rule (round_libcall $F32 (RoundImm.RoundNearest)) (LibCall.NearestF32)) +(rule (round_libcall $F64 (RoundImm.RoundNearest)) (LibCall.NearestF64)) +(rule (round_libcall $F32 (RoundImm.RoundZero)) (LibCall.TruncF32)) +(rule (round_libcall $F64 (RoundImm.RoundZero)) (LibCall.TruncF64)) + +;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (ceil a @ (value_type ty))) + (x64_round ty a (RoundImm.RoundUp))) + +;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (floor a @ (value_type ty))) + (x64_round ty a (RoundImm.RoundDown))) + +;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (nearest a @ (value_type ty))) + (x64_round ty a (RoundImm.RoundNearest))) + +;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (trunc a @ (value_type ty))) + (x64_round ty a (RoundImm.RoundZero))) + +;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (stack_addr stack_slot offset)) + (stack_addr_impl stack_slot offset)) + +;; Rules for `udiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; NB: a `RegMem` divisor, while allowed in the instruction encoding, isn't +;; used right now to prevent a possibly-trapping load getting folded into the +;; `div` instruction. Ideally non-trapping loads would get folded, however, or +;; alternatively Wasmtime/Cranelift would grow support for multiple traps on +;; a single opcode and the signal kind would differentiate at runtime. + +;; The inputs to the `div` instruction are different for 8-bit division so +;; it needs a special case here since the instruction being crafted has a +;; different shape. +(rule 2 (lower (udiv a @ (value_type $I8) b)) + (x64_div8 (extend_to_gpr a $I32 (ExtendKind.Zero)) + (put_in_gpr b) + (DivSignedness.Unsigned) + (TrapCode.INTEGER_DIVISION_BY_ZERO))) + +;; 16-to-64-bit division is all done with a similar instruction and the only +;; tricky requirement here is that when div traps are disallowed the divisor +;; must not be zero. +(rule 1 (lower (udiv a @ (value_type (fits_in_64 ty)) b)) + (x64_div_quotient a + (imm $I64 0) + (put_in_gpr b) + (raw_operand_size_of_type ty) + (DivSignedness.Unsigned) + (TrapCode.INTEGER_DIVISION_BY_ZERO))) + +;; Rules for `sdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 2 (lower (sdiv a @ (value_type $I8) b)) + (x64_div8 (x64_sign_extend_data a (OperandSize.Size8)) + (nonzero_sdiv_divisor $I8 b) + (DivSignedness.Signed) + (TrapCode.INTEGER_OVERFLOW))) + +(rule 1 (lower (sdiv a @ (value_type (fits_in_64 ty)) b)) + (let ( + (a Gpr a) + (size OperandSize (raw_operand_size_of_type ty)) + ) + (x64_div_quotient a + (x64_sign_extend_data a size) + (nonzero_sdiv_divisor ty b) + size + (DivSignedness.Signed) + (TrapCode.INTEGER_OVERFLOW)))) + +;; Checks to make sure that the input `Value` is a non-zero value for `sdiv`. +;; +;; This is required to differentiate the divide-by-zero trap from the +;; integer-overflow trap, the two trapping conditions of signed division. +(decl nonzero_sdiv_divisor (Type Value) Reg) +(rule 1 (nonzero_sdiv_divisor ty (iconst imm)) + (if-let n (safe_divisor_from_imm64 ty imm)) + (imm ty n)) +(rule 0 (nonzero_sdiv_divisor ty val) + (let ( + (val Reg val) + (_ InstOutput (side_effect (with_flags_side_effect + (x64_test (raw_operand_size_of_type ty) val val) + (trap_if (CC.Z) (TrapCode.INTEGER_DIVISION_BY_ZERO))))) + ) + val)) + +;; Rules for `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The remainder is in AH, so take the result of the division and right-shift +;; by 8. +(rule 2 (lower (urem a @ (value_type $I8) b)) + (let ( + (result Gpr (x64_div8 (extend_to_gpr a $I32 (ExtendKind.Zero)) + (put_in_gpr b) ;; see `udiv` for why not `gpr_mem` + (DivSignedness.Unsigned) + (TrapCode.INTEGER_DIVISION_BY_ZERO))) + ) + (x64_shr $I64 result (Imm8Reg.Imm8 8)))) + +(rule 1 (lower (urem a @ (value_type (fits_in_64 ty)) b)) + (x64_div_remainder a + (imm $I64 0) + (put_in_gpr b) ;; see `udiv` for why not `gpr_mem` + (raw_operand_size_of_type ty) + (DivSignedness.Unsigned) + (TrapCode.INTEGER_DIVISION_BY_ZERO))) + +;; Rules for `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Special-cases first for constant `srem` where the checks for 0 and -1 aren't +;; applicable. +;; +;; Note that like `urem` for i8 types the result is in AH so to get the result +;; it's right-shifted down. +(rule 3 (lower (srem a @ (value_type $I8) (iconst imm))) + (if-let n (safe_divisor_from_imm64 $I8 imm)) + (let ( + (a Gpr (x64_sign_extend_data a (OperandSize.Size8))) + (result Gpr (x64_div8 a (imm $I8 n) (DivSignedness.Signed) (TrapCode.INTEGER_DIVISION_BY_ZERO))) + ) + (x64_shr $I64 result (Imm8Reg.Imm8 8)))) + +;; Same as the above rule but for 16-to-64 bit types. +(rule 2 (lower (srem a @ (value_type ty) (iconst imm))) + (if-let n (safe_divisor_from_imm64 ty imm)) + (let ( + (a Gpr a) + (size OperandSize (raw_operand_size_of_type ty)) + ) + (x64_div_remainder a + (x64_sign_extend_data a size) + (imm ty n) + size + (DivSignedness.Signed) + (TrapCode.INTEGER_DIVISION_BY_ZERO)))) + +(rule 1 (lower (srem a @ (value_type $I8) b)) + (let ( + (a Gpr (x64_sign_extend_data a (OperandSize.Size8))) + ) + (x64_shr $I64 (x64_checked_srem_seq8 a b) (Imm8Reg.Imm8 8)))) + +(rule (lower (srem a @ (value_type ty) b)) + (let ( + (a Gpr a) + (size OperandSize (raw_operand_size_of_type ty)) + (hi Gpr (x64_sign_extend_data a size)) + (tmp ValueRegs (x64_checked_srem_seq size a hi b)) + ) + (value_regs_get tmp 1))) + +;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (umulhi a @ (value_type $I8) b)) + (x64_shr $I16 (x64_mul8 false a b) (imm8_to_imm8_gpr 8))) + +(rule 1 (lower (umulhi a @ (value_type (ty_int_ref_16_to_64 ty)) b)) + (value_regs_get_gpr (x64_mul ty false a b) 1)) + +;; The BMI2 instruction set introduced `mulx` which defines two registers but +;; if the two registers are the same then it only defines the upper bits. This +;; helps slightly reduce register pressure by ensuring only one register here is +;; clobbered. +(rule 2 (lower (umulhi a @ (value_type (ty_32_or_64 ty)) b)) + (if-let true (use_bmi2)) + (x64_mulx_hi ty a b)) + +;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 0 (lower (smulhi a @ (value_type $I8) b)) + (x64_sar $I16 (x64_mul8 true a b) (imm8_to_imm8_gpr 8))) + +(rule 1 (lower (smulhi a @ (value_type (ty_int_ref_16_to_64 ty)) b)) + (value_regs_get_gpr (x64_mul ty true a b) 1)) + +;; Rules for `get_pinned_reg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_pinned_reg)) + (read_pinned_gpr)) + +;; Rules for `set_pinned_reg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (set_pinned_reg a @ (value_type ty))) + (side_effect (write_pinned_gpr a))) + +;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type ty (vconst const))) + ;; TODO use Inst::gen_constant() instead. + (x64_xmm_load_const ty (const_to_vconst const))) + +;; Special cases for known constant patterns to skip a 16-byte load. +(rule 1 (lower (has_type ty (vconst (u128_from_constant 0)))) (xmm_zero ty)) +(rule 1 (lower (has_type ty (vconst (u128_from_constant -1)))) (vector_all_ones)) + +;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Special case for `pblendw` which takes an 8-bit immediate where each bit +;; indicates which lane of the two operands is chosen for the output. A bit of +;; 0 chooses the corresponding 16-it lane from `a` and a bit of 1 chooses the +;; corresponding 16-bit lane from `b`. +(rule 14 (lower (shuffle a b (pblendw_imm n))) + (if-let true (use_sse41)) + (x64_pblendw a b n)) +(decl pblendw_imm (u8) Immediate) +(extern extractor pblendw_imm pblendw_imm) + +;; When the shuffle looks like "concatenate `a` and `b` and shift right by n*8 +;; bytes", that's a `palignr` instruction. Note that the order of operands are +;; swapped in the instruction here. The `palignr` instruction uses the second +;; operand as the low-order bytes and the first operand as high-order bytes, +;; so put `a` second. +(rule 13 (lower (shuffle a b (palignr_imm_from_immediate n))) + (if-let true (use_ssse3)) + (x64_palignr b a n)) +(decl palignr_imm_from_immediate (u8) Immediate) +(extern extractor palignr_imm_from_immediate palignr_imm_from_immediate) + +;; Special case the `pshuf{l,h}w` instruction which shuffles four 16-bit +;; integers within one value, preserving the other four 16-bit integers in that +;; value (either the high or low half). The complicated logic is in the +;; extractors here implemented in Rust and note that there's two cases for each +;; instruction here to match when either the first or second shuffle operand is +;; used. +(rule 12 (lower (shuffle x y (pshuflw_lhs_imm imm))) + (x64_pshuflw x imm)) +(rule 11 (lower (shuffle x y (pshuflw_rhs_imm imm))) + (x64_pshuflw y imm)) +(rule 10 (lower (shuffle x y (pshufhw_lhs_imm imm))) + (x64_pshufhw x imm)) +(rule 9 (lower (shuffle x y (pshufhw_rhs_imm imm))) + (x64_pshufhw y imm)) + +(decl pshuflw_lhs_imm (u8) Immediate) +(extern extractor pshuflw_lhs_imm pshuflw_lhs_imm) +(decl pshuflw_rhs_imm (u8) Immediate) +(extern extractor pshuflw_rhs_imm pshuflw_rhs_imm) +(decl pshufhw_lhs_imm (u8) Immediate) +(extern extractor pshufhw_lhs_imm pshufhw_lhs_imm) +(decl pshufhw_rhs_imm (u8) Immediate) +(extern extractor pshufhw_rhs_imm pshufhw_rhs_imm) + +;; Special case for the `pshufd` instruction which will permute 32-bit values +;; within a single register. This is only applicable if the `imm` specified +;; selects 32-bit values from either `x` or `y`, but not both. This means +;; there's one rule for selecting from `x` and another rule for selecting from +;; `y`. +(rule 8 (lower (shuffle x y (pshufd_lhs_imm imm))) + (x64_pshufd x imm)) +(rule 7 (lower (shuffle x y (pshufd_rhs_imm imm))) + (x64_pshufd y imm)) + +(decl pshufd_lhs_imm (u8) Immediate) +(extern extractor pshufd_lhs_imm pshufd_lhs_imm) +(decl pshufd_rhs_imm (u8) Immediate) +(extern extractor pshufd_rhs_imm pshufd_rhs_imm) + +;; Special case for i8-level interleaving of upper/low bytes. +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1f0f_1e0e_1d0d_1c0c_1b0b_1a0a_1909_1808))) + (x64_punpckhbw a b)) +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1707_1606_1505_1404_1303_1202_1101_1000))) + (x64_punpcklbw a b)) + +;; Special case for i16-level interleaving of upper/low bytes. +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1f1e_0f0e_1d1c_0d0c_1b1a_0b0a_1918_0908))) + (x64_punpckhwd a b)) +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1716_0706_1514_0504_1312_0302_1110_0100))) + (x64_punpcklwd a b)) + +;; Special case for i32-level interleaving of upper/low bytes. +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1f1e1d1c_0f0e0d0c_1b1a1918_0b0a0908))) + (x64_punpckhdq a b)) +(rule 6 (lower (shuffle a b (u128_from_immediate 0x17161514_07060504_13121110_03020100))) + (x64_punpckldq a b)) + +;; Special case for i64-level interleaving of upper/low bytes. +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1f1e1d1c1b1a1918_0f0e0d0c0b0a0908))) + (x64_punpckhqdq a b)) +(rule 6 (lower (shuffle a b (u128_from_immediate 0x1716151413121110_0706050403020100))) + (x64_punpcklqdq a b)) + +;; If the vector shift mask is all 0s then that means the first byte of the +;; first operand is broadcast to all bytes. Falling through would load an +;; all-zeros constant from a rip-relative location but it should be slightly +;; more efficient to execute the `pshufb` here-and-now with an xor'd-to-be-zero +;; register. +(rule 6 (lower (shuffle a _ (u128_from_immediate 0))) + (if-let true (use_ssse3)) + (x64_pshufb a (xmm_zero $I8X16))) + +;; Special case for the `shufps` instruction which will select two 32-bit values +;; from the first operand and two 32-bit values from the second operand. Note +;; that there is a second case here as well for when the operands can be +;; swapped. +;; +;; Note that the priority of this instruction is currently lower than the above +;; special cases since `shufps` handles many of them and for now it's +;; hypothesized that the dedicated instructions are better than `shufps`. +;; Someone with more knowledge about x86 timings should perhaps reorder the +;; rules here eventually though. +(rule 5 (lower (shuffle x y (shufps_imm imm))) + (x64_shufps x y imm)) +(rule 4 (lower (shuffle x y (shufps_rev_imm imm))) + (x64_shufps y x imm)) + +(decl shufps_imm(u8) Immediate) +(extern extractor shufps_imm shufps_imm) +(decl shufps_rev_imm(u8) Immediate) +(extern extractor shufps_rev_imm shufps_rev_imm) + + +;; If `lhs` and `rhs` are the same we can use a single PSHUFB to shuffle the XMM +;; register. We statically build `constructed_mask` to zero out any unknown lane +;; indices (may not be completely necessary: verification could fail incorrect +;; mask values) and fix the indexes to all point to the `dst` vector. +(rule 3 (lower (shuffle a a (vec_mask_from_immediate mask))) + (if-let true (use_ssse3)) + (x64_pshufb a (shuffle_0_31_mask mask))) + +;; For the case where the shuffle mask contains out-of-bounds values (values +;; greater than 31) we must mask off those resulting values in the result of +;; `vpermi2b`. +(rule 2 (lower (shuffle a b (vec_mask_from_immediate (perm_from_mask_with_zeros mask zeros)))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512vbmi)) + (x64_andps (x64_vpermi2b (x64_xmm_load_const $I8X16 mask) a b) zeros)) + +;; However, if the shuffle mask contains no out-of-bounds values, we can use +;; `vpermi2b` without any masking. +(rule 1 (lower (shuffle a b (vec_mask_from_immediate mask))) + (if-let true (use_avx512vl)) + (if-let true (use_avx512vbmi)) + (x64_vpermi2b (x64_xmm_load_const $I8X16 (perm_from_mask mask)) a b)) + +;; If `lhs` and `rhs` are different, we must shuffle each separately and then OR +;; them together. This is necessary due to PSHUFB semantics. As in the case +;; above, we build the `constructed_mask` for each case statically. +(rule (lower (shuffle a b (vec_mask_from_immediate mask))) + (x64_por + (lower_pshufb a (shuffle_0_15_mask mask)) + (lower_pshufb b (shuffle_16_31_mask mask)))) + +;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; SIMD swizzle; the following inefficient implementation is due to the Wasm +;; SIMD spec requiring mask indexes greater than 15 to have the same semantics +;; as a 0 index. For the spec discussion, see +;; https://github.com/WebAssembly/simd/issues/93. The CLIF semantics match the +;; Wasm SIMD semantics for this instruction. The instruction format maps to +;; variables like: %dst = swizzle %src, %mask +(rule (lower (swizzle src mask)) + (let ((mask Xmm (x64_paddusb mask (emit_u128_le_const 0x70707070707070707070707070707070)))) + (lower_pshufb src mask))) + +;; Rules for `x86_pshufb` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (x86_pshufb src mask)) + (if-let true (use_ssse3)) + (x64_pshufb src mask)) + +;; A helper function to generate either the `pshufb` instruction or a libcall to +;; the `X86Pshufb` libcall. Note that the libcall is not exactly the most +;; performant thing in the world so this is primarily here for completeness +;; of lowerings on all x86 cpus but if rules are ideally gated on the presence +;; of SSSE3 to use the `pshufb` instruction itself. +(decl lower_pshufb (Xmm RegMem) Xmm) +(rule 1 (lower_pshufb src mask) + (if-let true (use_ssse3)) + (x64_pshufb src mask)) +(rule (lower_pshufb src (RegMem.Reg mask)) + (libcall_2 (LibCall.X86Pshufb) src mask)) +(rule (lower_pshufb src (RegMem.Mem addr)) + (lower_pshufb src (x64_movdqu_load addr))) + +;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Remove the extractlane instruction, leaving the float where it is. The upper +;; bits will remain unchanged; for correctness, this relies on Cranelift type +;; checking to avoid using those bits. +(rule 3 (lower (has_type (ty_scalar_float _) (extractlane val 0))) + val) + +;; `f32x4.extract_lane N` where `N != 0` +(rule 1 (lower (extractlane val @ (value_type $F32X4) (u8_from_uimm8 lane))) + (x64_pshufd val lane)) + +;; `f64x2.extract_lane N` where `N != 0` (aka N == 1) +(rule (lower (extractlane val @ (value_type $F64X2) 1)) + (x64_pshufd val 0b11_10_11_10)) + +;; `i8x16.extract_lane N` +;; +;; Note that without SSE4.1 a 16-bit lane extraction is performed and then +;; the result is updated if the desired index is either odd or even. +(rule 2 (lower (extractlane val @ (value_type ty @ $I8X16) (u8_from_uimm8 lane))) + (if-let true (use_sse41)) + (x64_pextrb val lane)) +;; extracting an odd lane has an extra shift-right +(rule 1 (lower (extractlane val @ (value_type ty @ $I8X16) (u8_from_uimm8 lane))) + (if-let 1 (u8_and lane 1)) + (x64_shr $I16 (x64_pextrw val (u8_shr lane 1)) (Imm8Reg.Imm8 8))) +;; Extracting an even lane already has the desired lane in the lower bits. Note +;; that having arbitrary upper bits in the returned register should be ok since +;; all operators on the resulting `i8` type should work correctly regardless of +;; the bits in the rest of the register. +(rule (lower (extractlane val @ (value_type ty @ $I8X16) (u8_from_uimm8 lane))) + (if-let 0 (u8_and lane 1)) + (x64_pextrw val (u8_shr lane 1))) + +;; `i16x8.extract_lane N` +(rule (lower (extractlane val @ (value_type ty @ $I16X8) (u8_from_uimm8 lane))) + (x64_pextrw val lane)) + +;; `i32x4.extract_lane N` +(rule 2 (lower (extractlane val @ (value_type ty @ $I32X4) (u8_from_uimm8 lane))) + (if-let true (use_sse41)) + (x64_pextrd val lane)) +(rule 1 (lower (extractlane val @ (value_type $I32X4) 0)) + (x64_movd_to_gpr val)) +(rule (lower (extractlane val @ (value_type $I32X4) (u8_from_uimm8 n))) + (x64_movd_to_gpr (x64_pshufd val n))) + +;; `i64x2.extract_lane N` +(rule 1 (lower (extractlane val @ (value_type $I64X2) (u8_from_uimm8 lane))) + (if-let true (use_sse41)) + (x64_pextrq val lane)) +(rule (lower (extractlane val @ (value_type $I64X2) 0)) + (x64_movq_to_gpr val)) +(rule (lower (extractlane val @ (value_type $I64X2) 1)) + (x64_movq_to_gpr (x64_pshufd val 0b00_00_11_10))) + +;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Case 1: when moving a scalar float, we simply move from one XMM register +;; to another, expecting the register allocator to elide this. Here we +;; assume that the upper bits of a scalar float have not been munged with +;; (the same assumption the old backend makes). +(rule 1 (lower (scalar_to_vector src @ (value_type (ty_scalar_float _)))) + src) + +;; Case 2: when moving a scalar value of any other type, use MOVD to zero +;; the upper lanes. +(rule (lower (scalar_to_vector src @ (value_type ty))) + (bitcast_gpr_to_xmm (ty_bits ty) src)) + +;; Case 3: when presented with `load + scalar_to_vector`, coalesce into a single +;; MOVSS/MOVSD instruction. +(rule 2 (lower (scalar_to_vector (and (sinkable_load src) (value_type (ty_32 _))))) + (x64_movss_load src)) +(rule 3 (lower (scalar_to_vector (and (sinkable_load src) (value_type (ty_64 _))))) + (x64_movsd_load src)) + +;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; For all the splat rules below one of the goals is that splatting a value +;; doesn't end up accidentally depending on the previous value in a register. +;; This means that instructions are chosen to avoid false dependencies where +;; new values are created fresh or otherwise overwrite previous register +;; contents where possible. +;; +;; Additionally splats are specialized to special-case load-and-splat which +;; has a number of micro-optimizations available. + +;; i8x16 splats: use `vpbroadcastb` on AVX2 and otherwise `pshufb` broadcasts +;; with a mask of zero which is calculated with an xor-against-itself register. +(rule 0 (lower (has_type $I8X16 (splat src))) + (let ((src Xmm (x64_movd_to_xmm src))) + (x64_pshufd (x64_pshuflw (x64_punpcklbw src src) 0) 0))) +(rule 1 (lower (has_type $I8X16 (splat src))) + (if-let true (use_ssse3)) + (x64_pshufb (bitcast_gpr_to_xmm 32 src) (xmm_zero $I8X16))) +(rule 2 (lower (has_type $I8X16 (splat src))) + (if-let true (use_avx2)) + (x64_vpbroadcastb (bitcast_gpr_to_xmm 32 src))) +(rule 3 (lower (has_type $I8X16 (splat (sinkable_load_exact addr)))) + (if-let true (use_sse41)) + (if-let true (use_ssse3)) + (x64_pshufb (x64_pinsrb (xmm_uninit_value) addr 0) (xmm_zero $I8X16))) +(rule 4 (lower (has_type $I8X16 (splat (sinkable_load_exact addr)))) + (if-let true (use_avx2)) + (x64_vpbroadcastb addr)) + +;; i16x8 splats: use `vpbroadcastw` on AVX2 and otherwise a 16-bit value is +;; loaded into an xmm register, `pshuflw` broadcasts the low 16-bit lane +;; to the low four lanes, and `pshufd` broadcasts the low 32-bit lane (which +;; at that point is two of the 16-bit values we want to broadcast) to all the +;; lanes. +(rule 0 (lower (has_type $I16X8 (splat src))) + (x64_pshufd (x64_pshuflw (bitcast_gpr_to_xmm 32 src) 0) 0)) +(rule 1 (lower (has_type $I16X8 (splat src))) + (if-let true (use_avx2)) + (x64_vpbroadcastw (bitcast_gpr_to_xmm 32 src))) +(rule 2 (lower (has_type $I16X8 (splat (sinkable_load_exact addr)))) + (x64_pshufd (x64_pshuflw (x64_pinsrw (xmm_uninit_value) addr 0) 0) 0)) +(rule 3 (lower (has_type $I16X8 (splat (sinkable_load_exact addr)))) + (if-let true (use_avx2)) + (x64_vpbroadcastw addr)) + +;; i32x4.splat - use `vpbroadcastd` on AVX2 and otherwise `pshufd` can be +;; used to broadcast the low lane to all other lanes. +;; +;; Note that sinkable-load cases come later +(rule 0 (lower (has_type $I32X4 (splat src))) + (x64_pshufd (bitcast_gpr_to_xmm 32 src) 0)) +(rule 1 (lower (has_type $I32X4 (splat src))) + (if-let true (use_avx2)) + (x64_vpbroadcastd (bitcast_gpr_to_xmm 32 src))) + +;; f32x4.splat - the source is already in an xmm register so `shufps` is all +;; that's necessary to complete the splat. This is specialized to `vbroadcastss` +;; on AVX2 to leverage that specific instruction for this operation. +(rule 0 (lower (has_type $F32X4 (splat src))) + (let ((tmp Xmm src)) + (x64_shufps src src 0))) +(rule 1 (lower (has_type $F32X4 (splat src))) + (if-let true (use_avx2)) + (x64_vbroadcastss src)) + +;; t32x4.splat of a load - use a `movss` to load into an xmm register and then +;; `shufps` broadcasts to the other lanes. Note that this is used for both i32 +;; and f32 splats. +;; +;; With AVX the `vbroadcastss` instruction suits this purpose precisely. Note +;; that the memory-operand encoding of `vbroadcastss` is usable with AVX, but +;; the register-based encoding is only available with AVX2. With the +;; `sinkable_load` extractor this should be guaranteed to use the memory-based +;; encoding hence the `use_avx` test. +(rule 5 (lower (has_type (multi_lane 32 4) (splat (sinkable_load addr)))) + (let ((tmp Xmm (x64_movss_load addr))) + (x64_shufps tmp tmp 0))) +(rule 6 (lower (has_type (multi_lane 32 4) (splat (sinkable_load addr)))) + (if-let true (use_avx)) + (x64_vbroadcastss addr)) + +;; t64x2.splat - use `pshufd` to broadcast the lower 64-bit lane to the upper +;; lane. A minor specialization for sinkable loads to avoid going through a gpr +;; for i64 splats is used as well when `movddup` is available. +(rule 0 (lower (has_type $I64X2 (splat src))) + (x64_pshufd (bitcast_gpr_to_xmm 64 src) 0b01_00_01_00)) +(rule 0 (lower (has_type $F64X2 (splat src))) + (x64_pshufd src 0b01_00_01_00)) +(rule 6 (lower (has_type (multi_lane 64 2) (splat (sinkable_load addr)))) + (if-let true (use_ssse3)) + (x64_movddup addr)) + +;; Rules for `vany_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (vany_true val)) + (if-let true (use_sse41)) + (let ((val Xmm val)) + (with_flags (x64_ptest val val) (x64_setcc (CC.NZ))))) + +;; Any nonzero byte in `val` means that any lane is true. Compare `val` with a +;; zeroed register and extract the high bits to a gpr mask. If the mask is +;; 0xffff then every byte was equal to zero, so test if the comparison is +;; not-equal or NZ. +(rule (lower (vany_true val)) + (lower_icmp_bool (emit_vany_true val))) + +(decl emit_vany_true (Value) IcmpCondResult) +(rule (emit_vany_true val) + (let ( + (any_byte_zero Xmm (x64_pcmpeqb val (xmm_zero $I8X16))) + (mask Gpr (x64_pmovmskb (OperandSize.Size32) any_byte_zero)) + ) + (icmp_cond_result (x64_cmp_imm (OperandSize.Size32) mask 0xffff) + (CC.NZ)))) + +;; Rules for `vall_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (vall_true val)) + (lower_icmp_bool (emit_vall_true val))) + +(decl emit_vall_true (Value) IcmpCondResult) +(rule 1 (emit_vall_true val @ (value_type ty)) + (if-let true (use_sse41)) + (let ((src Xmm val) + (zeros Xmm (xmm_zero ty)) + (cmp Xmm (x64_pcmpeq (vec_int_type ty) src zeros))) + (icmp_cond_result (x64_ptest cmp cmp) (CC.Z)))) + +;; Perform an appropriately-sized lane-wise comparison with zero. If the +;; result is all 0s then all of them are true because nothing was equal to +;; zero. +(rule (emit_vall_true val @ (value_type ty)) + (let ((lanes_with_zero Xmm (x64_pcmpeq (vec_int_type ty) val (xmm_zero ty))) + (mask Gpr (x64_pmovmskb (OperandSize.Size32) lanes_with_zero))) + (icmp_cond_result (x64_test (OperandSize.Size32) mask mask) + (CC.Z)))) + +;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The Intel specification allows using both 32-bit and 64-bit GPRs as +;; destination for the "move mask" instructions. This is controlled by the REX.R +;; bit: "In 64-bit mode, the instruction can access additional registers when +;; used with a REX.R prefix. The default operand size is 64-bit in 64-bit mode" +;; (PMOVMSKB in IA Software Development Manual, vol. 2). This being the case, we +;; will always clear REX.W since its use is unnecessary (`OperandSize` is used +;; for setting/clearing REX.W) as we need at most 16 bits of output for +;; `vhigh_bits`. + +(rule (lower (vhigh_bits val @ (value_type (multi_lane 8 16)))) + (x64_pmovmskb (OperandSize.Size32) val)) + +(rule (lower (vhigh_bits val @ (value_type (multi_lane 32 4)))) + (x64_movmskps (OperandSize.Size32) val)) + +(rule (lower (vhigh_bits val @ (value_type (multi_lane 64 2)))) + (x64_movmskpd (OperandSize.Size32) val)) + +;; There is no x86 instruction for extracting the high bit of 16-bit lanes so +;; here we: +;; - duplicate the 16-bit lanes of `src` into 8-bit lanes: +;; PACKSSWB([x1, x2, ...], [x1, x2, ...]) = [x1', x2', ..., x1', x2', ...] +;; - use PMOVMSKB to gather the high bits; now we have duplicates, though +;; - shift away the bottom 8 high bits to remove the duplicates. +(rule (lower (vhigh_bits val @ (value_type (multi_lane 16 8)))) + (let ((src Xmm val) + (tmp Xmm (x64_packsswb src src)) + (tmp Gpr (x64_pmovmskb (OperandSize.Size32) tmp))) + (x64_shr $I64 tmp (Imm8Reg.Imm8 8)))) + +;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (iconcat lo @ (value_type $I64) hi)) + (value_regs lo hi)) + +;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (isplit val @ (value_type $I128))) + (let ((regs ValueRegs val) + (lo Reg (value_regs_get regs 0)) + (hi Reg (value_regs_get regs 1))) + (output_pair lo hi))) + +;; Rules for `tls_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (has_type (tls_model (TlsModel.ElfGd)) (tls_value (symbol_value_data name _ _)))) + (elf_tls_get_addr name)) + +(rule (lower (has_type (tls_model (TlsModel.Macho)) (tls_value (symbol_value_data name _ _)))) + (macho_tls_get_addr name)) + +(rule (lower (has_type (tls_model (TlsModel.Coff)) (tls_value (symbol_value_data name _ _)))) + (coff_tls_get_addr name)) + +;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule 1 (lower (sqmul_round_sat qx @ (value_type $I16X8) qy)) + (if-let true (use_ssse3)) + (let ((src1 Xmm qx) + (src2 Xmm qy) + + (mask XmmMem (emit_u128_le_const 0x8000_8000_8000_8000_8000_8000_8000_8000)) + (dst Xmm (x64_pmulhrsw src1 src2)) + (cmp Xmm (x64_pcmpeqw dst mask))) + (x64_pxor dst cmp))) + +;; This operation is defined in wasm as: +;; +;; S.SignedSaturate((x * y + 0x4000) >> 15) +;; +;; so perform all those operations here manually with a lack of the native +;; instruction. +(rule (lower (sqmul_round_sat qx @ (value_type $I16X8) qy)) + (let ( + (qx Xmm qx) + (qy Xmm qy) + ;; Multiply `qx` and `qy` generating 32-bit intermediate results. The + ;; 32-bit results have their low-halves stored in `mul_lsb` and the + ;; high halves are stored in `mul_msb`. These are then shuffled into + ;; `mul_lo` and `mul_hi` which represent the low 4 multiplications + ;; and the upper 4 multiplications. + (mul_lsb Xmm (x64_pmullw qx qy)) + (mul_msb Xmm (x64_pmulhw qx qy)) + (mul_lo Xmm (x64_punpcklwd mul_lsb mul_msb)) + (mul_hi Xmm (x64_punpckhwd mul_lsb mul_msb)) + ;; Add the 0x4000 constant to all multiplications + (val Xmm (x64_movdqu_load (emit_u128_le_const 0x00004000_00004000_00004000_00004000))) + (mul_lo Xmm (x64_paddd mul_lo val)) + (mul_hi Xmm (x64_paddd mul_hi val)) + ;; Perform the right-shift by 15 to all multiplications + (lo Xmm (x64_psrad mul_lo (xmi_imm 15))) + (hi Xmm (x64_psrad mul_hi (xmi_imm 15))) + ) + ;; And finally perform a saturating 32-to-16-bit conversion. + (x64_packssdw lo hi))) + +;; Rules for `x86_pmulhrsw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (x86_pmulhrsw qx @ (value_type $I16X8) qy)) + (if-let true (use_ssse3)) + (x64_pmulhrsw qx qy)) + +;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; TODO: currently we only lower a special case of `uunarrow` needed to support +;; the translation of wasm's i32x4.trunc_sat_f64x2_u_zero operation. +;; https://github.com/bytecodealliance/wasmtime/issues/4791 +;; +;; y = i32x4.trunc_sat_f64x2_u_zero(x) is lowered to: +;; MOVAPD xmm_y, xmm_x +;; XORPD xmm_tmp, xmm_tmp +;; MAXPD xmm_y, xmm_tmp +;; MINPD xmm_y, [wasm_f64x2_splat(4294967295.0)] +;; ROUNDPD xmm_y, xmm_y, 0x0B +;; ADDPD xmm_y, [wasm_f64x2_splat(0x1.0p+52)] +;; SHUFPS xmm_y, xmm_xmp, 0x88 +(rule (lower (uunarrow (fcvt_to_uint_sat src @ (value_type $F64X2)) + (vconst (u128_from_constant 0)))) + (let ((src Xmm src) + + ;; MOVAPD xmm_y, xmm_x + ;; XORPD xmm_tmp, xmm_tmp + (zeros Xmm (xmm_zero $F64X2)) + (dst Xmm (x64_maxpd src zeros)) + + ;; 4294967295.0 is equivalent to 0x41EFFFFFFFE00000 + (umax_mask XmmMem (emit_u128_le_const 0x41EFFFFFFFE00000_41EFFFFFFFE00000)) + + ;; MINPD xmm_y, [wasm_f64x2_splat(4294967295.0)] + (dst Xmm (x64_minpd dst umax_mask)) + + ;; ROUNDPD xmm_y, xmm_y, 0x0B + (dst Xmm (x64_round $F64X2 dst (RoundImm.RoundZero))) + + ;; ADDPD xmm_y, [wasm_f64x2_splat(0x1.0p+52)] + (uint_mask XmmMem (emit_u128_le_const 0x4330000000000000_4330000000000000)) + + (dst Xmm (x64_addpd dst uint_mask))) + + ;; SHUFPS xmm_y, xmm_xmp, 0x88 + (x64_shufps dst zeros 0x88))) + +;; Rules for `nop` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (nop)) + (invalid_reg)) diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.rs new file mode 100644 index 00000000000000..ae780089d4c5d8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower.rs @@ -0,0 +1,338 @@ +//! Lowering rules for X64. + +// ISLE integration glue. +pub(super) mod isle; + +use crate::ir::pcc::{FactContext, PccResult}; +use crate::ir::{types, ExternalName, Inst as IRInst, InstructionData, LibCall, Opcode, Type}; +use crate::isa::x64::abi::*; +use crate::isa::x64::inst::args::*; +use crate::isa::x64::inst::*; +use crate::isa::x64::pcc; +use crate::isa::{x64::X64Backend, CallConv}; +use crate::machinst::lower::*; +use crate::machinst::*; +use crate::result::CodegenResult; +use crate::settings::Flags; +use smallvec::{smallvec, SmallVec}; +use target_lexicon::Triple; + +//============================================================================= +// Helpers for instruction lowering. + +impl Lower<'_, Inst> { + #[inline] + pub fn temp_writable_gpr(&mut self) -> WritableGpr { + WritableGpr::from_writable_reg(self.alloc_tmp(types::I64).only_reg().unwrap()).unwrap() + } + + #[inline] + pub fn temp_writable_xmm(&mut self) -> WritableXmm { + WritableXmm::from_writable_reg(self.alloc_tmp(types::F64).only_reg().unwrap()).unwrap() + } +} + +fn is_int_or_ref_ty(ty: Type) -> bool { + match ty { + types::I8 | types::I16 | types::I32 | types::I64 => true, + _ => false, + } +} + +/// Returns whether the given specified `input` is a result produced by an instruction with Opcode +/// `op`. +// TODO investigate failures with checking against the result index. +fn matches_input(ctx: &mut Lower, input: InsnInput, op: Opcode) -> Option { + let inputs = ctx.get_input_as_source_or_const(input.insn, input.input); + inputs.inst.as_inst().and_then(|(src_inst, _)| { + let data = ctx.data(src_inst); + if data.opcode() == op { + return Some(src_inst); + } + None + }) +} + +/// Put the given input into possibly multiple registers, and mark it as used (side-effect). +fn put_input_in_regs(ctx: &mut Lower, spec: InsnInput) -> ValueRegs { + let ty = ctx.input_ty(spec.insn, spec.input); + let input = ctx.get_input_as_source_or_const(spec.insn, spec.input); + + if let Some(c) = input.constant { + // Generate constants fresh at each use to minimize long-range register pressure. + let size = if ty_bits(ty) < 64 { + OperandSize::Size32 + } else { + OperandSize::Size64 + }; + assert!(is_int_or_ref_ty(ty)); // Only used for addresses. + let cst_copy = ctx.alloc_tmp(ty); + ctx.emit(Inst::imm(size, c, cst_copy.only_reg().unwrap())); + non_writable_value_regs(cst_copy) + } else { + ctx.put_input_in_regs(spec.insn, spec.input) + } +} + +/// Put the given input into a register, and mark it as used (side-effect). +fn put_input_in_reg(ctx: &mut Lower, spec: InsnInput) -> Reg { + put_input_in_regs(ctx, spec) + .only_reg() + .expect("Multi-register value not expected") +} + +enum MergeableLoadSize { + /// The load size performed by a sinkable load merging operation is + /// precisely the size necessary for the type in question. + Exact, + + /// Narrower-than-32-bit values are handled by ALU insts that are at least + /// 32 bits wide, which is normally OK as we ignore upper buts; but, if we + /// generate, e.g., a direct-from-memory 32-bit add for a byte value and + /// the byte is the last byte in a page, the extra data that we load is + /// incorrectly accessed. So we only allow loads to merge for + /// 32-bit-and-above widths. + Min32, +} + +/// Determines whether a load operation (indicated by `src_insn`) can be merged +/// into the current lowering point. If so, returns the address-base source (as +/// an `InsnInput`) and an offset from that address from which to perform the +/// load. +fn is_mergeable_load( + ctx: &mut Lower, + src_insn: IRInst, + size: MergeableLoadSize, +) -> Option<(InsnInput, i32)> { + let insn_data = ctx.data(src_insn); + let inputs = ctx.num_inputs(src_insn); + if inputs != 1 { + return None; + } + + // If this type is too small to get a merged load, don't merge the load. + let load_ty = ctx.output_ty(src_insn, 0); + if ty_bits(load_ty) < 32 { + match size { + MergeableLoadSize::Exact => {} + MergeableLoadSize::Min32 => return None, + } + } + + // Just testing the opcode is enough, because the width will always match if + // the type does (and the type should match if the CLIF is properly + // constructed). + if let &InstructionData::Load { + opcode: Opcode::Load, + offset, + .. + } = insn_data + { + Some(( + InsnInput { + insn: src_insn, + input: 0, + }, + offset.into(), + )) + } else { + None + } +} + +fn input_to_imm(ctx: &mut Lower, spec: InsnInput) -> Option { + ctx.get_input_as_source_or_const(spec.insn, spec.input) + .constant +} + +fn emit_vm_call( + ctx: &mut Lower, + flags: &Flags, + triple: &Triple, + libcall: LibCall, + inputs: &[Reg], +) -> CodegenResult> { + let extname = ExternalName::LibCall(libcall); + + let dist = if flags.use_colocated_libcalls() { + RelocDistance::Near + } else { + RelocDistance::Far + }; + + // TODO avoid recreating signatures for every single Libcall function. + let call_conv = CallConv::for_libcall(flags, CallConv::triple_default(triple)); + let sig = libcall.signature(call_conv, types::I64); + let caller_conv = ctx.abi().call_conv(ctx.sigs()); + + if !ctx.sigs().have_abi_sig_for_signature(&sig) { + ctx.sigs_mut() + .make_abi_sig_from_ir_signature::(sig.clone(), flags)?; + } + + let mut abi = + X64CallSite::from_libcall(ctx.sigs(), &sig, &extname, dist, caller_conv, flags.clone()); + + assert_eq!(inputs.len(), abi.num_args(ctx.sigs())); + + for (i, input) in inputs.iter().enumerate() { + abi.gen_arg(ctx, i, ValueRegs::one(*input)); + } + + let mut retval_insts: SmallInstVec<_> = smallvec![]; + let mut outputs: SmallVec<[_; 1]> = smallvec![]; + for i in 0..ctx.sigs().num_rets(ctx.sigs().abi_sig_for_signature(&sig)) { + let (retval_inst, retval_regs) = abi.gen_retval(ctx, i); + retval_insts.extend(retval_inst.into_iter()); + outputs.push(retval_regs.only_reg().unwrap()); + } + + abi.emit_call(ctx); + + for inst in retval_insts { + ctx.emit(inst); + } + + Ok(outputs) +} + +/// Returns whether the given input is a shift by a constant value less or equal than 3. +/// The goal is to embed it within an address mode. +fn matches_small_constant_shift(ctx: &mut Lower, spec: InsnInput) -> Option<(InsnInput, u8)> { + matches_input(ctx, spec, Opcode::Ishl).and_then(|shift| { + match input_to_imm( + ctx, + InsnInput { + insn: shift, + input: 1, + }, + ) { + Some(shift_amt) if shift_amt <= 3 => Some(( + InsnInput { + insn: shift, + input: 0, + }, + shift_amt as u8, + )), + _ => None, + } + }) +} + +/// Lowers an instruction to one of the x86 addressing modes. +/// +/// Note: the 32-bit offset in Cranelift has to be sign-extended, which maps x86's behavior. +fn lower_to_amode(ctx: &mut Lower, spec: InsnInput, offset: i32) -> Amode { + let flags = ctx + .memflags(spec.insn) + .expect("Instruction with amode should have memflags"); + + // We now either have an add that we must materialize, or some other input; as well as the + // final offset. + if let Some(add) = matches_input(ctx, spec, Opcode::Iadd) { + debug_assert_eq!(ctx.output_ty(add, 0), types::I64); + let add_inputs = &[ + InsnInput { + insn: add, + input: 0, + }, + InsnInput { + insn: add, + input: 1, + }, + ]; + + // TODO heap_addr legalization generates a uext64 *after* the shift, so these optimizations + // aren't happening in the wasm case. We could do better, given some range analysis. + let (base, index, shift) = if let Some((shift_input, shift_amt)) = + matches_small_constant_shift(ctx, add_inputs[0]) + { + ( + put_input_in_reg(ctx, add_inputs[1]), + put_input_in_reg(ctx, shift_input), + shift_amt, + ) + } else if let Some((shift_input, shift_amt)) = + matches_small_constant_shift(ctx, add_inputs[1]) + { + ( + put_input_in_reg(ctx, add_inputs[0]), + put_input_in_reg(ctx, shift_input), + shift_amt, + ) + } else { + for input in 0..=1 { + // Try to pierce through uextend. + let (inst, inst_input) = if let Some(uextend) = + matches_input(ctx, InsnInput { insn: add, input }, Opcode::Uextend) + { + (uextend, 0) + } else { + (add, input) + }; + + // If it's a constant, add it directly! + if let Some(cst) = ctx.get_input_as_source_or_const(inst, inst_input).constant { + let final_offset = (offset as i64).wrapping_add(cst as i64); + if let Ok(final_offset) = i32::try_from(final_offset) { + let base = put_input_in_reg(ctx, add_inputs[1 - input]); + return Amode::imm_reg(final_offset, base).with_flags(flags); + } + } + } + + ( + put_input_in_reg(ctx, add_inputs[0]), + put_input_in_reg(ctx, add_inputs[1]), + 0, + ) + }; + + return Amode::imm_reg_reg_shift( + offset, + Gpr::unwrap_new(base), + Gpr::unwrap_new(index), + shift, + ) + .with_flags(flags); + } + + let input = put_input_in_reg(ctx, spec); + Amode::imm_reg(offset, input).with_flags(flags) +} + +//============================================================================= +// Lowering-backend trait implementation. + +impl LowerBackend for X64Backend { + type MInst = Inst; + + fn lower(&self, ctx: &mut Lower, ir_inst: IRInst) -> Option { + isle::lower(ctx, self, ir_inst) + } + + fn lower_branch( + &self, + ctx: &mut Lower, + ir_inst: IRInst, + targets: &[MachLabel], + ) -> Option<()> { + isle::lower_branch(ctx, self, ir_inst, targets) + } + + fn maybe_pinned_reg(&self) -> Option { + Some(regs::pinned_reg()) + } + + fn check_fact( + &self, + ctx: &FactContext<'_>, + vcode: &mut VCode, + inst: InsnIndex, + state: &mut pcc::FactFlowState, + ) -> PccResult<()> { + pcc::check(ctx, vcode, inst, state) + } + + type FactFlowState = pcc::FactFlowState; +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle.rs new file mode 100644 index 00000000000000..85268a90b6b8c2 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle.rs @@ -0,0 +1,997 @@ +//! ISLE integration glue code for x64 lowering. + +// Pull in the ISLE generated code. +pub(crate) mod generated_code; +use crate::{ir::types, ir::AtomicRmwOp, isa}; +use generated_code::{Context, MInst, RegisterClass}; + +// Types that the generated ISLE code uses via `use super::*`. +use super::{is_int_or_ref_ty, is_mergeable_load, lower_to_amode, MergeableLoadSize}; +use crate::ir::condcodes::{FloatCC, IntCC}; +use crate::ir::immediates::*; +use crate::ir::types::*; +use crate::ir::{ + BlockCall, Inst, InstructionData, LibCall, MemFlags, Opcode, TrapCode, Value, ValueList, +}; +use crate::isa::x64::abi::X64CallSite; +use crate::isa::x64::inst::{args::*, regs, ReturnCallInfo}; +use crate::isa::x64::lower::emit_vm_call; +use crate::isa::x64::X64Backend; +use crate::machinst::isle::*; +use crate::machinst::{ + ArgPair, CallInfo, InsnInput, InstOutput, IsTailCall, MachInst, VCodeConstant, + VCodeConstantData, +}; +use alloc::vec::Vec; +use regalloc2::PReg; +use std::boxed::Box; + +/// Type representing out-of-line data for calls. This type optional because the +/// call instruction is also used by Winch to emit calls, but the +/// `Box` field is not used, it's only used by Cranelift. By making it +/// optional, we reduce the number of heap allocations in Winch. +type BoxCallInfo = Box>; +type BoxCallIndInfo = Box>; +type BoxReturnCallInfo = Box>; +type BoxReturnCallIndInfo = Box>; +type VecArgPair = Vec; +type BoxSyntheticAmode = Box; + +pub struct SinkableLoad { + inst: Inst, + addr_input: InsnInput, + offset: i32, +} + +/// The main entry point for lowering with ISLE. +pub(crate) fn lower( + lower_ctx: &mut Lower, + backend: &X64Backend, + inst: Inst, +) -> Option { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = IsleContext { lower_ctx, backend }; + generated_code::constructor_lower(&mut isle_ctx, inst) +} + +pub(crate) fn lower_branch( + lower_ctx: &mut Lower, + backend: &X64Backend, + branch: Inst, + targets: &[MachLabel], +) -> Option<()> { + // TODO: reuse the ISLE context across lowerings so we can reuse its + // internal heap allocations. + let mut isle_ctx = IsleContext { lower_ctx, backend }; + generated_code::constructor_lower_branch(&mut isle_ctx, branch, &targets) +} + +impl Context for IsleContext<'_, '_, MInst, X64Backend> { + isle_lower_prelude_methods!(); + isle_prelude_caller_methods!(X64CallSite); + + #[inline] + fn operand_size_of_type_32_64(&mut self, ty: Type) -> OperandSize { + if ty.bits() == 64 { + OperandSize::Size64 + } else { + OperandSize::Size32 + } + } + + #[inline] + fn raw_operand_size_of_type(&mut self, ty: Type) -> OperandSize { + OperandSize::from_ty(ty) + } + + fn put_in_reg_mem_imm(&mut self, val: Value) -> RegMemImm { + let inputs = self.lower_ctx.get_value_as_source_or_const(val); + + if let Some(c) = inputs.constant { + let ty = self.lower_ctx.dfg().value_type(val); + if let Some(imm) = to_simm32(c as i64, ty) { + return imm.to_reg_mem_imm(); + } + } + + self.put_in_reg_mem(val).into() + } + + fn put_in_xmm_mem_imm(&mut self, val: Value) -> XmmMemImm { + let inputs = self.lower_ctx.get_value_as_source_or_const(val); + + if let Some(c) = inputs.constant { + let ty = self.lower_ctx.dfg().value_type(val); + if let Some(imm) = to_simm32(c as i64, ty) { + return XmmMemImm::unwrap_new(imm.to_reg_mem_imm()); + } + } + + let res = match self.put_in_xmm_mem(val).to_reg_mem() { + RegMem::Reg { reg } => RegMemImm::Reg { reg }, + RegMem::Mem { addr } => RegMemImm::Mem { addr }, + }; + + XmmMemImm::unwrap_new(res) + } + + fn put_in_xmm_mem(&mut self, val: Value) -> XmmMem { + let inputs = self.lower_ctx.get_value_as_source_or_const(val); + + if let Some(c) = inputs.constant { + // A load from the constant pool is better than a rematerialization into a register, + // because it reduces register pressure. + // + // NOTE: this is where behavior differs from `put_in_reg_mem`, as we always force + // constants to be 16 bytes when a constant will be used in place of an xmm register. + let vcode_constant = self.emit_u128_le_const(c as u128); + return XmmMem::unwrap_new(RegMem::mem(SyntheticAmode::ConstantOffset(vcode_constant))); + } + + XmmMem::unwrap_new(self.put_in_reg_mem(val)) + } + + fn put_in_reg_mem(&mut self, val: Value) -> RegMem { + let inputs = self.lower_ctx.get_value_as_source_or_const(val); + + if let Some(c) = inputs.constant { + // A load from the constant pool is better than a + // rematerialization into a register, because it reduces + // register pressure. + let vcode_constant = self.emit_u64_le_const(c); + return RegMem::mem(SyntheticAmode::ConstantOffset(vcode_constant)); + } + + if let Some(load) = self.sinkable_load(val) { + return RegMem::Mem { + addr: self.sink_load(&load), + }; + } + + RegMem::reg(self.put_in_reg(val)) + } + + #[inline] + fn encode_fcmp_imm(&mut self, imm: &FcmpImm) -> u8 { + imm.encode() + } + + #[inline] + fn encode_round_imm(&mut self, imm: &RoundImm) -> u8 { + imm.encode() + } + + #[inline] + fn use_avx(&mut self) -> bool { + self.backend.x64_flags.use_avx() + } + + #[inline] + fn use_avx2(&mut self) -> bool { + self.backend.x64_flags.use_avx2() + } + + #[inline] + fn use_avx512vl(&mut self) -> bool { + self.backend.x64_flags.use_avx512vl() + } + + #[inline] + fn use_avx512dq(&mut self) -> bool { + self.backend.x64_flags.use_avx512dq() + } + + #[inline] + fn use_avx512f(&mut self) -> bool { + self.backend.x64_flags.use_avx512f() + } + + #[inline] + fn use_avx512bitalg(&mut self) -> bool { + self.backend.x64_flags.use_avx512bitalg() + } + + #[inline] + fn use_avx512vbmi(&mut self) -> bool { + self.backend.x64_flags.use_avx512vbmi() + } + + #[inline] + fn use_lzcnt(&mut self) -> bool { + self.backend.x64_flags.use_lzcnt() + } + + #[inline] + fn use_bmi1(&mut self) -> bool { + self.backend.x64_flags.use_bmi1() + } + + #[inline] + fn use_bmi2(&mut self) -> bool { + self.backend.x64_flags.use_bmi2() + } + + #[inline] + fn use_popcnt(&mut self) -> bool { + self.backend.x64_flags.use_popcnt() + } + + #[inline] + fn use_fma(&mut self) -> bool { + self.backend.x64_flags.use_fma() + } + + #[inline] + fn use_ssse3(&mut self) -> bool { + self.backend.x64_flags.use_ssse3() + } + + #[inline] + fn use_sse41(&mut self) -> bool { + self.backend.x64_flags.use_sse41() + } + + #[inline] + fn use_sse42(&mut self) -> bool { + self.backend.x64_flags.use_sse42() + } + + #[inline] + fn use_cmpxchg16b(&mut self) -> bool { + self.backend.x64_flags.use_cmpxchg16b() + } + + #[inline] + fn imm8_from_value(&mut self, val: Value) -> Option { + let inst = self.lower_ctx.dfg().value_def(val).inst()?; + let constant = self.lower_ctx.get_constant(inst)?; + let imm = u8::try_from(constant).ok()?; + Some(Imm8Reg::Imm8 { imm }) + } + + #[inline] + fn const_to_type_masked_imm8(&mut self, c: u64, ty: Type) -> Imm8Gpr { + let mask = self.shift_mask(ty) as u64; + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { + imm: (c & mask) as u8, + }) + } + + #[inline] + fn shift_mask(&mut self, ty: Type) -> u8 { + debug_assert!(ty.lane_bits().is_power_of_two()); + + (ty.lane_bits() - 1) as u8 + } + + fn shift_amount_masked(&mut self, ty: Type, val: Imm64) -> u8 { + (val.bits() as u8) & self.shift_mask(ty) + } + + #[inline] + fn simm32_from_value(&mut self, val: Value) -> Option { + let inst = self.lower_ctx.dfg().value_def(val).inst()?; + let constant: u64 = self.lower_ctx.get_constant(inst)?; + let ty = self.lower_ctx.dfg().value_type(val); + let constant = constant as i64; + to_simm32(constant, ty) + } + + fn sinkable_load(&mut self, val: Value) -> Option { + if let Some(inst) = self.is_sinkable_inst(val) { + if let Some((addr_input, offset)) = + is_mergeable_load(self.lower_ctx, inst, MergeableLoadSize::Min32) + { + return Some(SinkableLoad { + inst, + addr_input, + offset, + }); + } + } + None + } + + fn sinkable_load_exact(&mut self, val: Value) -> Option { + if let Some(inst) = self.is_sinkable_inst(val) { + if let Some((addr_input, offset)) = + is_mergeable_load(self.lower_ctx, inst, MergeableLoadSize::Exact) + { + return Some(SinkableLoad { + inst, + addr_input, + offset, + }); + } + } + None + } + + fn sink_load(&mut self, load: &SinkableLoad) -> SyntheticAmode { + self.lower_ctx.sink_inst(load.inst); + let addr = lower_to_amode(self.lower_ctx, load.addr_input, load.offset); + SyntheticAmode::Real(addr) + } + + #[inline] + fn ext_mode(&mut self, from_bits: u16, to_bits: u16) -> ExtMode { + ExtMode::new(from_bits, to_bits).unwrap() + } + + fn emit(&mut self, inst: &MInst) -> Unit { + self.lower_ctx.emit(inst.clone()); + } + + #[inline] + fn nonzero_u64_fits_in_u32(&mut self, x: u64) -> Option { + if x != 0 && x < u64::from(u32::MAX) { + Some(x) + } else { + None + } + } + + #[inline] + fn sse_insertps_lane_imm(&mut self, lane: u8) -> u8 { + // Insert 32-bits from replacement (at index 00, bits 7:8) to vector (lane + // shifted into bits 5:6). + 0b00_00_00_00 | lane << 4 + } + + #[inline] + fn synthetic_amode_to_reg_mem(&mut self, addr: &SyntheticAmode) -> RegMem { + RegMem::mem(addr.clone()) + } + + #[inline] + fn amode_to_synthetic_amode(&mut self, amode: &Amode) -> SyntheticAmode { + amode.clone().into() + } + + #[inline] + fn const_to_synthetic_amode(&mut self, c: VCodeConstant) -> SyntheticAmode { + SyntheticAmode::ConstantOffset(c) + } + + #[inline] + fn writable_gpr_to_reg(&mut self, r: WritableGpr) -> WritableReg { + r.to_writable_reg() + } + + #[inline] + fn writable_xmm_to_reg(&mut self, r: WritableXmm) -> WritableReg { + r.to_writable_reg() + } + + fn ishl_i8x16_mask_for_const(&mut self, amt: u32) -> SyntheticAmode { + // When the shift amount is known, we can statically (i.e. at compile + // time) determine the mask to use and only emit that. + debug_assert!(amt < 8); + let mask_offset = amt as usize * 16; + let mask_constant = self.lower_ctx.use_constant(VCodeConstantData::WellKnown( + &I8X16_ISHL_MASKS[mask_offset..mask_offset + 16], + )); + SyntheticAmode::ConstantOffset(mask_constant) + } + + fn ishl_i8x16_mask_table(&mut self) -> SyntheticAmode { + let mask_table = self + .lower_ctx + .use_constant(VCodeConstantData::WellKnown(&I8X16_ISHL_MASKS)); + SyntheticAmode::ConstantOffset(mask_table) + } + + fn ushr_i8x16_mask_for_const(&mut self, amt: u32) -> SyntheticAmode { + // When the shift amount is known, we can statically (i.e. at compile + // time) determine the mask to use and only emit that. + debug_assert!(amt < 8); + let mask_offset = amt as usize * 16; + let mask_constant = self.lower_ctx.use_constant(VCodeConstantData::WellKnown( + &I8X16_USHR_MASKS[mask_offset..mask_offset + 16], + )); + SyntheticAmode::ConstantOffset(mask_constant) + } + + fn ushr_i8x16_mask_table(&mut self) -> SyntheticAmode { + let mask_table = self + .lower_ctx + .use_constant(VCodeConstantData::WellKnown(&I8X16_USHR_MASKS)); + SyntheticAmode::ConstantOffset(mask_table) + } + + #[inline] + fn writable_reg_to_xmm(&mut self, r: WritableReg) -> WritableXmm { + Writable::from_reg(Xmm::unwrap_new(r.to_reg())) + } + + #[inline] + fn writable_xmm_to_xmm(&mut self, r: WritableXmm) -> Xmm { + r.to_reg() + } + + #[inline] + fn writable_gpr_to_gpr(&mut self, r: WritableGpr) -> Gpr { + r.to_reg() + } + + #[inline] + fn gpr_to_reg(&mut self, r: Gpr) -> Reg { + r.into() + } + + #[inline] + fn xmm_to_reg(&mut self, r: Xmm) -> Reg { + r.into() + } + + #[inline] + fn xmm_to_xmm_mem_imm(&mut self, r: Xmm) -> XmmMemImm { + r.into() + } + + #[inline] + fn xmm_mem_to_xmm_mem_imm(&mut self, r: &XmmMem) -> XmmMemImm { + XmmMemImm::unwrap_new(r.clone().to_reg_mem().into()) + } + + #[inline] + fn temp_writable_gpr(&mut self) -> WritableGpr { + self.lower_ctx.temp_writable_gpr() + } + + #[inline] + fn temp_writable_xmm(&mut self) -> WritableXmm { + self.lower_ctx.temp_writable_xmm() + } + + #[inline] + fn reg_to_reg_mem_imm(&mut self, reg: Reg) -> RegMemImm { + RegMemImm::Reg { reg } + } + + #[inline] + fn reg_mem_to_xmm_mem(&mut self, rm: &RegMem) -> XmmMem { + XmmMem::unwrap_new(rm.clone()) + } + + #[inline] + fn gpr_mem_imm_new(&mut self, rmi: &RegMemImm) -> GprMemImm { + GprMemImm::unwrap_new(rmi.clone()) + } + + #[inline] + fn xmm_mem_imm_new(&mut self, rmi: &RegMemImm) -> XmmMemImm { + XmmMemImm::unwrap_new(rmi.clone()) + } + + #[inline] + fn xmm_to_xmm_mem(&mut self, r: Xmm) -> XmmMem { + r.into() + } + + #[inline] + fn xmm_mem_to_reg_mem(&mut self, xm: &XmmMem) -> RegMem { + xm.clone().into() + } + + #[inline] + fn gpr_mem_to_reg_mem(&mut self, gm: &GprMem) -> RegMem { + gm.clone().into() + } + + #[inline] + fn xmm_new(&mut self, r: Reg) -> Xmm { + Xmm::unwrap_new(r) + } + + #[inline] + fn gpr_new(&mut self, r: Reg) -> Gpr { + Gpr::unwrap_new(r) + } + + #[inline] + fn reg_mem_to_gpr_mem(&mut self, rm: &RegMem) -> GprMem { + GprMem::unwrap_new(rm.clone()) + } + + #[inline] + fn reg_to_gpr_mem(&mut self, r: Reg) -> GprMem { + GprMem::unwrap_new(RegMem::reg(r)) + } + + #[inline] + fn imm8_reg_to_imm8_gpr(&mut self, ir: &Imm8Reg) -> Imm8Gpr { + Imm8Gpr::unwrap_new(ir.clone()) + } + + #[inline] + fn gpr_to_gpr_mem(&mut self, gpr: Gpr) -> GprMem { + GprMem::from(gpr) + } + + #[inline] + fn gpr_to_gpr_mem_imm(&mut self, gpr: Gpr) -> GprMemImm { + GprMemImm::from(gpr) + } + + #[inline] + fn gpr_to_imm8_gpr(&mut self, gpr: Gpr) -> Imm8Gpr { + Imm8Gpr::from(gpr) + } + + #[inline] + fn imm8_to_imm8_gpr(&mut self, imm: u8) -> Imm8Gpr { + Imm8Gpr::unwrap_new(Imm8Reg::Imm8 { imm }) + } + + fn gpr_from_imm8_gpr(&mut self, val: &Imm8Gpr) -> Option { + match val.as_imm8_reg() { + &Imm8Reg::Reg { reg } => Some(Gpr::unwrap_new(reg)), + Imm8Reg::Imm8 { .. } => None, + } + } + + fn imm8_from_imm8_gpr(&mut self, val: &Imm8Gpr) -> Option { + match val.as_imm8_reg() { + &Imm8Reg::Imm8 { imm } => Some(imm), + Imm8Reg::Reg { .. } => None, + } + } + + #[inline] + fn type_register_class(&mut self, ty: Type) -> Option { + if is_int_or_ref_ty(ty) || ty == I128 { + Some(RegisterClass::Gpr { + single_register: ty != I128, + }) + } else if ty.is_float() || (ty.is_vector() && ty.bits() == 128) { + Some(RegisterClass::Xmm) + } else { + None + } + } + + #[inline] + fn ty_int_bool_or_ref(&mut self, ty: Type) -> Option<()> { + match ty { + types::I8 | types::I16 | types::I32 | types::I64 => Some(()), + _ => None, + } + } + + #[inline] + fn intcc_to_cc(&mut self, intcc: &IntCC) -> CC { + CC::from_intcc(*intcc) + } + + #[inline] + fn cc_invert(&mut self, cc: &CC) -> CC { + cc.invert() + } + + #[inline] + fn cc_nz_or_z(&mut self, cc: &CC) -> Option { + match cc { + CC::Z => Some(*cc), + CC::NZ => Some(*cc), + _ => None, + } + } + + #[inline] + fn sum_extend_fits_in_32_bits( + &mut self, + extend_from_ty: Type, + constant_value: Imm64, + offset: Offset32, + ) -> Option { + let offset: i64 = offset.into(); + let constant_value: u64 = constant_value.bits() as u64; + // If necessary, zero extend `constant_value` up to 64 bits. + let shift = 64 - extend_from_ty.bits(); + let zero_extended_constant_value = (constant_value << shift) >> shift; + // Sum up the two operands. + let sum = offset.wrapping_add(zero_extended_constant_value as i64); + // Check that the sum will fit in 32-bits. + if sum == ((sum << 32) >> 32) { + Some(sum as u32) + } else { + None + } + } + + #[inline] + fn amode_offset(&mut self, addr: &Amode, offset: i32) -> Amode { + addr.offset(offset) + } + + #[inline] + fn zero_offset(&mut self) -> Offset32 { + Offset32::new(0) + } + + #[inline] + fn preg_rbp(&mut self) -> PReg { + regs::rbp().to_real_reg().unwrap().into() + } + + #[inline] + fn preg_rsp(&mut self) -> PReg { + regs::rsp().to_real_reg().unwrap().into() + } + + #[inline] + fn preg_pinned(&mut self) -> PReg { + regs::pinned_reg().to_real_reg().unwrap().into() + } + + fn libcall_1(&mut self, libcall: &LibCall, a: Reg) -> Reg { + let outputs = emit_vm_call( + self.lower_ctx, + &self.backend.flags, + &self.backend.triple, + *libcall, + &[a], + ) + .expect("Failed to emit LibCall"); + + debug_assert_eq!(outputs.len(), 1); + + outputs[0] + } + + fn libcall_2(&mut self, libcall: &LibCall, a: Reg, b: Reg) -> Reg { + let outputs = emit_vm_call( + self.lower_ctx, + &self.backend.flags, + &self.backend.triple, + *libcall, + &[a, b], + ) + .expect("Failed to emit LibCall"); + + debug_assert_eq!(outputs.len(), 1); + + outputs[0] + } + + fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: Reg) -> Reg { + let outputs = emit_vm_call( + self.lower_ctx, + &self.backend.flags, + &self.backend.triple, + *libcall, + &[a, b, c], + ) + .expect("Failed to emit LibCall"); + + debug_assert_eq!(outputs.len(), 1); + + outputs[0] + } + + #[inline] + fn vconst_all_ones_or_all_zeros(&mut self, constant: Constant) -> Option<()> { + let const_data = self.lower_ctx.get_constant_data(constant); + if const_data.iter().all(|&b| b == 0 || b == 0xFF) { + return Some(()); + } + None + } + + #[inline] + fn shuffle_0_31_mask(&mut self, mask: &VecMask) -> VCodeConstant { + let mask = mask + .iter() + .map(|&b| if b > 15 { b.wrapping_sub(16) } else { b }) + .map(|b| if b > 15 { 0b10000000 } else { b }) + .collect(); + self.lower_ctx + .use_constant(VCodeConstantData::Generated(mask)) + } + + #[inline] + fn shuffle_0_15_mask(&mut self, mask: &VecMask) -> VCodeConstant { + let mask = mask + .iter() + .map(|&b| if b > 15 { 0b10000000 } else { b }) + .collect(); + self.lower_ctx + .use_constant(VCodeConstantData::Generated(mask)) + } + + #[inline] + fn shuffle_16_31_mask(&mut self, mask: &VecMask) -> VCodeConstant { + let mask = mask + .iter() + .map(|&b| b.wrapping_sub(16)) + .map(|b| if b > 15 { 0b10000000 } else { b }) + .collect(); + self.lower_ctx + .use_constant(VCodeConstantData::Generated(mask)) + } + + #[inline] + fn perm_from_mask_with_zeros( + &mut self, + mask: &VecMask, + ) -> Option<(VCodeConstant, VCodeConstant)> { + if !mask.iter().any(|&b| b > 31) { + return None; + } + + let zeros = mask + .iter() + .map(|&b| if b > 31 { 0x00 } else { 0xff }) + .collect(); + + Some(( + self.perm_from_mask(mask), + self.lower_ctx + .use_constant(VCodeConstantData::Generated(zeros)), + )) + } + + #[inline] + fn perm_from_mask(&mut self, mask: &VecMask) -> VCodeConstant { + let mask = mask.iter().cloned().collect(); + self.lower_ctx + .use_constant(VCodeConstantData::Generated(mask)) + } + + fn xmm_mem_to_xmm_mem_aligned(&mut self, arg: &XmmMem) -> XmmMemAligned { + match XmmMemAligned::new(arg.clone().into()) { + Some(aligned) => aligned, + None => match arg.clone().into() { + RegMem::Mem { addr } => self.load_xmm_unaligned(addr).into(), + _ => unreachable!(), + }, + } + } + + fn xmm_mem_imm_to_xmm_mem_aligned_imm(&mut self, arg: &XmmMemImm) -> XmmMemAlignedImm { + match XmmMemAlignedImm::new(arg.clone().into()) { + Some(aligned) => aligned, + None => match arg.clone().into() { + RegMemImm::Mem { addr } => self.load_xmm_unaligned(addr).into(), + _ => unreachable!(), + }, + } + } + + fn pshufd_lhs_imm(&mut self, imm: Immediate) -> Option { + let (a, b, c, d) = self.shuffle32_from_imm(imm)?; + if a < 4 && b < 4 && c < 4 && d < 4 { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn pshufd_rhs_imm(&mut self, imm: Immediate) -> Option { + let (a, b, c, d) = self.shuffle32_from_imm(imm)?; + // When selecting from the right-hand-side, subtract these all by 4 + // which will bail out if anything is less than 4. Afterwards the check + // is the same as `pshufd_lhs_imm` above. + let a = a.checked_sub(4)?; + let b = b.checked_sub(4)?; + let c = c.checked_sub(4)?; + let d = d.checked_sub(4)?; + if a < 4 && b < 4 && c < 4 && d < 4 { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn shufps_imm(&mut self, imm: Immediate) -> Option { + // The `shufps` instruction selects the first two elements from the + // first vector and the second two elements from the second vector, so + // offset the third/fourth selectors by 4 and then make sure everything + // fits in 32-bits. + let (a, b, c, d) = self.shuffle32_from_imm(imm)?; + let c = c.checked_sub(4)?; + let d = d.checked_sub(4)?; + if a < 4 && b < 4 && c < 4 && d < 4 { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn shufps_rev_imm(&mut self, imm: Immediate) -> Option { + // This is almost the same as `shufps_imm` except the elements that are + // subtracted are reversed. This handles the case that `shufps` + // instruction can be emitted if the order of the operands are swapped. + let (a, b, c, d) = self.shuffle32_from_imm(imm)?; + let a = a.checked_sub(4)?; + let b = b.checked_sub(4)?; + if a < 4 && b < 4 && c < 4 && d < 4 { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn pshuflw_lhs_imm(&mut self, imm: Immediate) -> Option { + // Similar to `shufps` except this operates over 16-bit values so four + // of them must be fixed and the other four must be in-range to encode + // in the immediate. + let (a, b, c, d, e, f, g, h) = self.shuffle16_from_imm(imm)?; + if a < 4 && b < 4 && c < 4 && d < 4 && [e, f, g, h] == [4, 5, 6, 7] { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn pshuflw_rhs_imm(&mut self, imm: Immediate) -> Option { + let (a, b, c, d, e, f, g, h) = self.shuffle16_from_imm(imm)?; + let a = a.checked_sub(8)?; + let b = b.checked_sub(8)?; + let c = c.checked_sub(8)?; + let d = d.checked_sub(8)?; + let e = e.checked_sub(8)?; + let f = f.checked_sub(8)?; + let g = g.checked_sub(8)?; + let h = h.checked_sub(8)?; + if a < 4 && b < 4 && c < 4 && d < 4 && [e, f, g, h] == [4, 5, 6, 7] { + Some(a | (b << 2) | (c << 4) | (d << 6)) + } else { + None + } + } + + fn pshufhw_lhs_imm(&mut self, imm: Immediate) -> Option { + // Similar to `pshuflw` except that the first four operands must be + // fixed and the second four are offset by an extra 4 and tested to + // make sure they're all in the range [4, 8). + let (a, b, c, d, e, f, g, h) = self.shuffle16_from_imm(imm)?; + let e = e.checked_sub(4)?; + let f = f.checked_sub(4)?; + let g = g.checked_sub(4)?; + let h = h.checked_sub(4)?; + if e < 4 && f < 4 && g < 4 && h < 4 && [a, b, c, d] == [0, 1, 2, 3] { + Some(e | (f << 2) | (g << 4) | (h << 6)) + } else { + None + } + } + + fn pshufhw_rhs_imm(&mut self, imm: Immediate) -> Option { + // Note that everything here is offset by at least 8 and the upper + // bits are offset by 12 to test they're in the range of [12, 16). + let (a, b, c, d, e, f, g, h) = self.shuffle16_from_imm(imm)?; + let a = a.checked_sub(8)?; + let b = b.checked_sub(8)?; + let c = c.checked_sub(8)?; + let d = d.checked_sub(8)?; + let e = e.checked_sub(12)?; + let f = f.checked_sub(12)?; + let g = g.checked_sub(12)?; + let h = h.checked_sub(12)?; + if e < 4 && f < 4 && g < 4 && h < 4 && [a, b, c, d] == [0, 1, 2, 3] { + Some(e | (f << 2) | (g << 4) | (h << 6)) + } else { + None + } + } + + fn palignr_imm_from_immediate(&mut self, imm: Immediate) -> Option { + let bytes = self.lower_ctx.get_immediate_data(imm).as_slice(); + + if bytes.windows(2).all(|a| a[0] + 1 == a[1]) { + Some(bytes[0]) + } else { + None + } + } + + fn pblendw_imm(&mut self, imm: Immediate) -> Option { + // First make sure that the shuffle immediate is selecting 16-bit lanes. + let (a, b, c, d, e, f, g, h) = self.shuffle16_from_imm(imm)?; + + // Next build up an 8-bit mask from each of the bits of the selected + // lanes above. This instruction can only be used when each lane + // selector chooses from the corresponding lane in either of the two + // operands, meaning the Nth lane selection must satisfy `lane % 8 == + // N`. + // + // This helper closure is used to calculate the value of the + // corresponding bit. + let bit = |x: u8, c: u8| { + if x % 8 == c { + if x < 8 { + Some(0) + } else { + Some(1 << c) + } + } else { + None + } + }; + Some( + bit(a, 0)? + | bit(b, 1)? + | bit(c, 2)? + | bit(d, 3)? + | bit(e, 4)? + | bit(f, 5)? + | bit(g, 6)? + | bit(h, 7)?, + ) + } + + fn xmi_imm(&mut self, imm: u32) -> XmmMemImm { + XmmMemImm::unwrap_new(RegMemImm::imm(imm)) + } + + fn insert_i8x16_lane_hole(&mut self, hole_idx: u8) -> VCodeConstant { + let mask = -1i128 as u128; + self.emit_u128_le_const(mask ^ (0xff << (hole_idx * 8))) + } + + fn writable_invalid_gpr(&mut self) -> WritableGpr { + let reg = Gpr::new(self.invalid_reg()).unwrap(); + WritableGpr::from_reg(reg) + } + + fn box_synthetic_amode(&mut self, amode: &SyntheticAmode) -> BoxSyntheticAmode { + Box::new(amode.clone()) + } +} + +impl IsleContext<'_, '_, MInst, X64Backend> { + fn load_xmm_unaligned(&mut self, addr: SyntheticAmode) -> Xmm { + let tmp = self.lower_ctx.alloc_tmp(types::F32X4).only_reg().unwrap(); + self.lower_ctx.emit(MInst::XmmUnaryRmRUnaligned { + op: SseOpcode::Movdqu, + src: XmmMem::unwrap_new(RegMem::mem(addr)), + dst: Writable::from_reg(Xmm::unwrap_new(tmp.to_reg())), + }); + Xmm::unwrap_new(tmp.to_reg()) + } +} + +// Since x64 doesn't have 8x16 shifts and we must use a 16x8 shift instead, we +// need to fix up the bits that migrate from one half of the lane to the +// other. Each 16-byte mask is indexed by the shift amount: e.g. if we shift +// right by 0 (no movement), we want to retain all the bits so we mask with +// `0xff`; if we shift right by 1, we want to retain all bits except the MSB so +// we mask with `0x7f`; etc. + +#[rustfmt::skip] // Preserve 16 bytes (i.e. one mask) per row. +const I8X16_ISHL_MASKS: [u8; 128] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +]; + +#[rustfmt::skip] // Preserve 16 bytes (i.e. one mask) per row. +const I8X16_USHR_MASKS: [u8; 128] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +]; + +#[inline] +fn to_simm32(constant: i64, ty: Type) -> Option { + if ty.bits() <= 32 || constant == ((constant << 32) >> 32) { + Some(GprMemImm::unwrap_new(RegMemImm::Imm { + simm32: constant as u32, + })) + } else { + None + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle/generated_code.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle/generated_code.rs new file mode 100644 index 00000000000000..56d19ead88e414 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/lower/isle/generated_code.rs @@ -0,0 +1,16 @@ +// See https://github.com/rust-lang/rust/issues/47995: we cannot use `#![...]` +// attributes inside of the generated ISLE source below because we include!() +// it. We must include!() it because its path depends on an environment +// variable; and also because of this, we can't do the `#[path = "..."] mod +// generated_code;` trick either. +#![allow(dead_code, unreachable_code, unreachable_patterns)] +#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)] +#![allow( + irrefutable_let_patterns, + unused_assignments, + non_camel_case_types, + missing_docs, + clippy::clone_on_copy +)] + +include!(concat!(env!("ISLE_DIR"), "/isle_x64.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/mod.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/mod.rs new file mode 100644 index 00000000000000..7545a6f1483563 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/mod.rs @@ -0,0 +1,239 @@ +//! X86_64-bit Instruction Set Architecture. + +pub use self::inst::{args, EmitInfo, EmitState, Inst}; + +use super::{OwnedTargetIsa, TargetIsa}; +use crate::dominator_tree::DominatorTree; +use crate::ir::{types, Function, Type}; +#[cfg(feature = "unwind")] +use crate::isa::unwind::systemv; +use crate::isa::x64::settings as x64_settings; +use crate::isa::{Builder as IsaBuilder, FunctionAlignment}; +use crate::machinst::{ + compile, CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, + TextSectionBuilder, VCode, +}; +use crate::result::CodegenResult; +use crate::settings::{self as shared_settings, Flags}; +use crate::{Final, MachBufferFinalized}; +use alloc::{boxed::Box, vec::Vec}; +use core::fmt; +use cranelift_control::ControlPlane; +use target_lexicon::Triple; + +mod abi; +pub mod encoding; +mod inst; +mod lower; +mod pcc; +pub mod settings; + +pub use inst::unwind::systemv::create_cie; + +/// An X64 backend. +pub(crate) struct X64Backend { + triple: Triple, + flags: Flags, + x64_flags: x64_settings::Flags, +} + +impl X64Backend { + /// Create a new X64 backend with the given (shared) flags. + fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self { + Self { + triple, + flags, + x64_flags, + } + } + + fn compile_vcode( + &self, + func: &Function, + domtree: &DominatorTree, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<(VCode, regalloc2::Output)> { + // This performs lowering to VCode, register-allocates the code, computes + // block layout and finalizes branches. The result is ready for binary emission. + let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone()); + let sigs = SigSet::new::(func, &self.flags)?; + let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?; + compile::compile::(func, domtree, self, abi, emit_info, sigs, ctrl_plane) + } +} + +impl TargetIsa for X64Backend { + fn compile_function( + &self, + func: &Function, + domtree: &DominatorTree, + want_disasm: bool, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult { + let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?; + + let emit_result = vcode.emit(®alloc_result, want_disasm, &self.flags, ctrl_plane); + let frame_size = emit_result.frame_size; + let value_labels_ranges = emit_result.value_labels_ranges; + let buffer = emit_result.buffer; + let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; + let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; + + if let Some(disasm) = emit_result.disasm.as_ref() { + crate::trace!("disassembly:\n{}", disasm); + } + + Ok(CompiledCodeStencil { + buffer, + frame_size, + vcode: emit_result.disasm, + value_labels_ranges, + sized_stackslot_offsets, + dynamic_stackslot_offsets, + bb_starts: emit_result.bb_offsets, + bb_edges: emit_result.bb_edges, + }) + } + + fn flags(&self) -> &Flags { + &self.flags + } + + fn isa_flags(&self) -> Vec { + self.x64_flags.iter().collect() + } + + fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 { + 16 + } + + fn name(&self) -> &'static str { + "x64" + } + + fn triple(&self) -> &Triple { + &self.triple + } + + #[cfg(feature = "unwind")] + fn emit_unwind_info( + &self, + result: &CompiledCode, + kind: crate::isa::unwind::UnwindInfoKind, + ) -> CodegenResult> { + emit_unwind_info(&result.buffer, kind) + } + + #[cfg(feature = "unwind")] + fn create_systemv_cie(&self) -> Option { + Some(inst::unwind::systemv::create_cie()) + } + + #[cfg(feature = "unwind")] + fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result { + inst::unwind::systemv::map_reg(reg).map(|reg| reg.0) + } + + fn text_section_builder(&self, num_funcs: usize) -> Box { + Box::new(MachTextSectionBuilder::::new(num_funcs)) + } + + fn function_alignment(&self) -> FunctionAlignment { + Inst::function_alignment() + } + + fn page_size_align_log2(&self) -> u8 { + debug_assert_eq!(1 << 12, 0x1000); + 12 + } + + #[cfg(feature = "disas")] + fn to_capstone(&self) -> Result { + use capstone::prelude::*; + Capstone::new() + .x86() + .mode(arch::x86::ArchMode::Mode64) + .syntax(arch::x86::ArchSyntax::Att) + .detail(true) + .build() + } + + fn has_native_fma(&self) -> bool { + self.x64_flags.use_fma() + } + + fn has_x86_blendv_lowering(&self, ty: Type) -> bool { + // The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only + // available from SSE 4.1 and onwards. Otherwise the i16x8 type has no + // equivalent instruction which only looks at the top bit for a select + // operation, so that always returns `false` + self.x64_flags.use_sse41() && ty != types::I16X8 + } + + fn has_x86_pshufb_lowering(&self) -> bool { + self.x64_flags.use_ssse3() + } + + fn has_x86_pmulhrsw_lowering(&self) -> bool { + self.x64_flags.use_ssse3() + } + + fn has_x86_pmaddubsw_lowering(&self) -> bool { + self.x64_flags.use_ssse3() + } +} + +/// Emit unwind info for an x86 target. +pub fn emit_unwind_info( + buffer: &MachBufferFinalized, + kind: crate::isa::unwind::UnwindInfoKind, +) -> CodegenResult> { + use crate::isa::unwind::{UnwindInfo, UnwindInfoKind}; + Ok(match kind { + UnwindInfoKind::SystemV => { + let mapper = self::inst::unwind::systemv::RegisterMapper; + Some(UnwindInfo::SystemV( + crate::isa::unwind::systemv::create_unwind_info_from_insts( + &buffer.unwind_info[..], + buffer.data().len(), + &mapper, + )?, + )) + } + UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64( + crate::isa::unwind::winx64::create_unwind_info_from_insts::< + self::inst::unwind::winx64::RegisterMapper, + >(&buffer.unwind_info[..])?, + )), + _ => None, + }) +} + +impl fmt::Display for X64Backend { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MachBackend") + .field("name", &self.name()) + .field("triple", &self.triple()) + .field("flags", &format!("{}", self.flags())) + .finish() + } +} + +/// Create a new `isa::Builder`. +pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder { + IsaBuilder { + triple, + setup: x64_settings::builder(), + constructor: isa_constructor, + } +} + +fn isa_constructor( + triple: Triple, + shared_flags: Flags, + builder: &shared_settings::Builder, +) -> CodegenResult { + let isa_flags = x64_settings::Flags::new(&shared_flags, builder); + let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags); + Ok(backend.wrapped()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/pcc.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/pcc.rs new file mode 100644 index 00000000000000..b96dce090d7c1b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/pcc.rs @@ -0,0 +1,1092 @@ +//! Proof-carrying-code validation for x64 VCode. + +use crate::ir::pcc::*; +use crate::ir::types::*; +use crate::isa::x64::args::AvxOpcode; +use crate::isa::x64::inst::args::{ + AluRmiROpcode, Amode, Gpr, Imm8Reg, RegMem, RegMemImm, ShiftKind, SseOpcode, SyntheticAmode, + ToWritableReg, CC, +}; +use crate::isa::x64::inst::Inst; +use crate::machinst::pcc::*; +use crate::machinst::{InsnIndex, VCode, VCodeConstantData}; +use crate::machinst::{Reg, Writable}; +use crate::trace; + +fn undefined_result( + ctx: &FactContext, + vcode: &mut VCode, + dst: Writable, + reg_bits: u16, + result_bits: u16, +) -> PccResult<()> { + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, reg_bits, result_bits, None) + }) +} + +fn ensure_no_fact(vcode: &VCode, reg: Reg) -> PccResult<()> { + if vcode.vreg_fact(reg.into()).is_some() { + Err(PccError::UnsupportedFact) + } else { + Ok(()) + } +} + +/// Flow-state between facts. +#[derive(Clone, Debug, Default)] +pub(crate) struct FactFlowState { + cmp_flags: Option<(Fact, Fact)>, +} + +pub(crate) fn check( + ctx: &FactContext, + vcode: &mut VCode, + inst_idx: InsnIndex, + state: &mut FactFlowState, +) -> PccResult<()> { + trace!("Checking facts on inst: {:?}", vcode[inst_idx]); + + // We only persist flag state for one instruction, because we + // can't exhaustively enumerate all flags-effecting ops; so take + // the `cmp_state` here and perhaps use it below but don't let it + // remain. + let cmp_flags = state.cmp_flags.take(); + + match vcode[inst_idx] { + Inst::Nop { .. } => Ok(()), + + Inst::Args { .. } => { + // Defs on the args have "axiomatic facts": we trust the + // ABI code to pass through the values unharmed, so the + // facts given to us in the CLIF should still be true. + Ok(()) + } + + Inst::AluRmiR { + size, + op: AluRmiROpcode::Add, + src1, + ref src2, + dst, + } => match *<&RegMemImm>::from(src2) { + RegMemImm::Reg { reg: src2 } => { + let bits = size.to_bits().into(); + check_binop( + ctx, + vcode, + 64, + dst.to_writable_reg(), + src1.to_reg(), + src2, + |src1, src2| clamp_range(ctx, 64, bits, ctx.add(src1, src2, bits)), + ) + } + RegMemImm::Imm { simm32 } => { + let bits = size.to_bits().into(); + check_unop( + ctx, + vcode, + 64, + dst.to_writable_reg(), + src1.to_reg(), + |src1| { + let simm32: i64 = simm32.into(); + clamp_range(ctx, 64, bits, ctx.offset(src1, bits, simm32)) + }, + ) + } + RegMemImm::Mem { ref addr } => { + let bits: u16 = size.to_bits().into(); + let loaded = check_load(ctx, None, addr, vcode, size.to_type(), bits)?; + check_unop(ctx, vcode, 64, dst.to_writable_reg(), src1.into(), |src1| { + let sum = loaded.and_then(|loaded| ctx.add(src1, &loaded, bits)); + clamp_range(ctx, 64, bits, sum) + }) + } + }, + + Inst::AluRmiR { + size, + op: AluRmiROpcode::Sub, + src1, + ref src2, + dst, + } => match *<&RegMemImm>::from(src2) { + RegMemImm::Imm { simm32 } => { + let bits = size.to_bits().into(); + check_unop( + ctx, + vcode, + 64, + dst.to_writable_reg(), + src1.to_reg(), + |src1| { + let simm32: i64 = simm32.into(); + clamp_range(ctx, 64, bits, ctx.offset(src1, bits, -simm32)) + }, + ) + } + RegMemImm::Reg { .. } => { + let bits: u16 = size.to_bits().into(); + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, 64, bits, None) + }) + } + RegMemImm::Mem { ref addr } => { + let loaded = check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, 64, size.to_bits().into(), loaded) + }) + } + }, + + Inst::AluRmiR { + size, + ref src2, + dst, + .. + } => match <&RegMemImm>::from(src2) { + RegMemImm::Mem { ref addr } => { + let loaded = check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, 64, size.to_bits().into(), loaded) + }) + } + RegMemImm::Reg { .. } | RegMemImm::Imm { .. } => { + undefined_result(ctx, vcode, dst, 64, size.to_bits().into()) + } + }, + + Inst::AluRM { + size, + op: _, + ref src1_dst, + src2: _, + lock: _, + } => { + check_load(ctx, None, src1_dst, vcode, size.to_type(), 64)?; + check_store(ctx, None, src1_dst, vcode, size.to_type()) + } + + Inst::AluRmRVex { + size, + ref src2, + dst, + .. + } => match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + let loaded = check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, 64, size.to_bits().into(), loaded) + }) + } + RegMem::Reg { .. } => undefined_result(ctx, vcode, dst, 64, size.to_bits().into()), + }, + + Inst::AluConstOp { + op: AluRmiROpcode::Xor, + dst, + .. + } => check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + Ok(Some(Fact::constant(64, 0))) + }), + + Inst::AluConstOp { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::UnaryRmR { + size, ref src, dst, .. + } + | Inst::UnaryRmRVex { + size, ref src, dst, .. + } + | Inst::UnaryRmRImmVex { + size, ref src, dst, .. + } => match <&RegMem>::from(src) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + clamp_range(ctx, 64, size.to_bits().into(), None) + }) + } + RegMem::Reg { .. } => undefined_result(ctx, vcode, dst, 64, size.to_bits().into()), + }, + + Inst::Not { size, dst, .. } | Inst::Neg { size, dst, .. } => { + undefined_result(ctx, vcode, dst, 64, size.to_bits().into()) + } + + Inst::Div { + size, + ref divisor, + dst_quotient, + dst_remainder, + .. + } => { + match <&RegMem>::from(divisor) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst_quotient, 64, 64)?; + undefined_result(ctx, vcode, dst_remainder, 64, 64)?; + Ok(()) + } + Inst::Div8 { + dst, ref divisor, .. + } => { + match <&RegMem>::from(divisor) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8, 64)?; + } + RegMem::Reg { .. } => {} + } + // 64-bit result width because result may be negative + // hence high bits set. + undefined_result(ctx, vcode, dst, 64, 64)?; + Ok(()) + } + Inst::Mul { + size, + dst_lo, + dst_hi, + ref src2, + .. + } + | Inst::MulX { + size, + dst_lo, + dst_hi, + ref src2, + .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst_lo, 64, size.to_bits().into())?; + undefined_result(ctx, vcode, dst_hi, 64, size.to_bits().into())?; + Ok(()) + } + Inst::Mul8 { dst, ref src2, .. } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8, 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst, 64, 16)?; + Ok(()) + } + Inst::IMul { + size, + dst, + ref src2, + .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst, 64, size.to_bits().into())?; + Ok(()) + } + Inst::IMulImm { + size, + dst, + ref src1, + .. + } => { + match <&RegMem>::from(src1) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst, 64, size.to_bits().into())?; + Ok(()) + } + Inst::CheckedSRemSeq { + dst_quotient, + dst_remainder, + .. + } => { + undefined_result(ctx, vcode, dst_quotient, 64, 64)?; + undefined_result(ctx, vcode, dst_remainder, 64, 64)?; + Ok(()) + } + + Inst::CheckedSRemSeq8 { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::SignExtendData { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::Imm { simm64, dst, .. } => { + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + Ok(Some(Fact::constant(64, simm64))) + }) + } + + Inst::MovRR { size, dst, .. } => { + undefined_result(ctx, vcode, dst, 64, size.to_bits().into()) + } + + Inst::MovFromPReg { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + Inst::MovToPReg { .. } => Ok(()), + + Inst::MovzxRmR { + ref ext_mode, + ref src, + dst, + } => { + let from_bytes: u16 = ext_mode.src_size().into(); + let to_bytes: u16 = ext_mode.dst_size().into(); + match <&RegMem>::from(src) { + RegMem::Reg { reg } => { + check_unop(ctx, vcode, 64, dst.to_writable_reg(), *reg, |src| { + clamp_range(ctx, 64, from_bytes * 8, Some(src.clone())) + }) + } + RegMem::Mem { ref addr } => { + let loaded = check_load( + ctx, + Some(dst.to_writable_reg()), + addr, + vcode, + ext_mode.src_type(), + 64, + )?; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |_vcode| { + let extended = loaded + .and_then(|loaded| ctx.uextend(&loaded, from_bytes * 8, to_bytes * 8)); + clamp_range(ctx, 64, from_bytes * 8, extended) + }) + } + } + } + + Inst::Mov64MR { ref src, dst } => { + check_load(ctx, Some(dst.to_writable_reg()), src, vcode, I64, 64)?; + Ok(()) + } + + Inst::LoadEffectiveAddress { + ref addr, + dst, + size, + } => { + let addr = addr.clone(); + let bits: u16 = size.to_bits().into(); + check_output(ctx, vcode, dst.to_writable_reg(), &[], |vcode| { + let fact = if let SyntheticAmode::Real(amode) = &addr { + compute_addr(ctx, vcode, amode, bits) + } else { + None + }; + clamp_range(ctx, 64, bits, fact) + }) + } + + Inst::MovsxRmR { + ref ext_mode, + ref src, + dst, + } => { + match <&RegMem>::from(src) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, ext_mode.src_type(), 64)?; + } + RegMem::Reg { .. } => {} + } + undefined_result(ctx, vcode, dst, 64, 64) + } + + Inst::MovImmM { size, ref dst, .. } => check_store(ctx, None, dst, vcode, size.to_type()), + + Inst::MovRM { size, src, ref dst } => { + check_store(ctx, Some(src.to_reg()), dst, vcode, size.to_type()) + } + + Inst::ShiftR { + size, + kind: ShiftKind::ShiftLeft, + src, + ref num_bits, + dst, + } => match num_bits.as_imm8_reg() { + &Imm8Reg::Imm8 { imm } => { + check_unop(ctx, vcode, 64, dst.to_writable_reg(), src.to_reg(), |src| { + clamp_range( + ctx, + 64, + size.to_bits().into(), + ctx.shl(src, size.to_bits().into(), imm.into()), + ) + }) + } + Imm8Reg::Reg { .. } => undefined_result(ctx, vcode, dst, 64, size.to_bits().into()), + }, + + Inst::ShiftR { size, dst, .. } => { + undefined_result(ctx, vcode, dst, 64, size.to_bits().into()) + } + + Inst::XmmRmiReg { dst, ref src2, .. } => { + match <&RegMemImm>::from(src2) { + RegMemImm::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + _ => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::CmpRmiR { + size, + src1, + ref src2, + .. + } => match <&RegMemImm>::from(src2) { + RegMemImm::Mem { + addr: SyntheticAmode::ConstantOffset(k), + } => { + match vcode.constants.get(*k) { + VCodeConstantData::U64(bytes) => { + let value = u64::from_le_bytes(*bytes); + let lhs = get_fact_or_default(vcode, src1.to_reg(), 64); + let rhs = Fact::constant(64, value); + state.cmp_flags = Some((lhs, rhs)); + } + _ => {} + } + Ok(()) + } + RegMemImm::Mem { ref addr } => { + if let Some(rhs) = check_load(ctx, None, addr, vcode, size.to_type(), 64)? { + let lhs = get_fact_or_default(vcode, src1.to_reg(), 64); + state.cmp_flags = Some((lhs, rhs)); + } + Ok(()) + } + RegMemImm::Reg { reg } => { + let rhs = get_fact_or_default(vcode, *reg, 64); + let lhs = get_fact_or_default(vcode, src1.to_reg(), 64); + state.cmp_flags = Some((lhs, rhs)); + Ok(()) + } + RegMemImm::Imm { simm32 } => { + let lhs = get_fact_or_default(vcode, src1.to_reg(), 64); + let rhs = Fact::constant(64, (*simm32 as i32) as i64 as u64); + state.cmp_flags = Some((lhs, rhs)); + Ok(()) + } + }, + + Inst::Setcc { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::Bswap { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::Cmove { + size, + dst, + ref consequent, + alternative, + cc, + .. + } => match <&RegMem>::from(consequent) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, size.to_type(), 64)?; + Ok(()) + } + RegMem::Reg { reg } if (cc == CC::NB || cc == CC::NBE) && cmp_flags.is_some() => { + let (cmp_lhs, cmp_rhs) = cmp_flags.unwrap(); + trace!("lhs = {:?} rhs = {:?}", cmp_lhs, cmp_rhs); + let reg = *reg; + check_output(ctx, vcode, dst.to_writable_reg(), &[], |vcode| { + // See comments in aarch64::pcc CSel for more details on this. + let in_true = get_fact_or_default(vcode, reg, 64); + let in_true_kind = match cc { + CC::NB => InequalityKind::Loose, + CC::NBE => InequalityKind::Strict, + _ => unreachable!(), + }; + let in_true = ctx.apply_inequality(&in_true, &cmp_lhs, &cmp_rhs, in_true_kind); + let in_false = get_fact_or_default(vcode, alternative.to_reg(), 64); + let in_false_kind = match cc { + CC::NB => InequalityKind::Strict, + CC::NBE => InequalityKind::Loose, + _ => unreachable!(), + }; + let in_false = + ctx.apply_inequality(&in_false, &cmp_rhs, &cmp_lhs, in_false_kind); + let union = ctx.union(&in_true, &in_false); + clamp_range(ctx, 64, 64, union) + }) + } + _ => undefined_result(ctx, vcode, dst, 64, 64), + }, + + Inst::XmmCmove { dst, .. } => ensure_no_fact(vcode, dst.to_writable_reg().to_reg()), + + Inst::Push64 { ref src } => match <&RegMemImm>::from(src) { + RegMemImm::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + Ok(()) + } + RegMemImm::Reg { .. } | RegMemImm::Imm { .. } => Ok(()), + }, + + Inst::Pop64 { dst } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::StackProbeLoop { tmp, .. } => ensure_no_fact(vcode, tmp.to_reg()), + + Inst::XmmRmR { dst, ref src2, .. } + | Inst::XmmRmRBlend { dst, ref src2, .. } + | Inst::XmmUnaryRmR { + dst, src: ref src2, .. + } + | Inst::XmmUnaryRmRImm { + dst, src: ref src2, .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmUnaryRmRUnaligned { + dst, + ref src, + op: SseOpcode::Movss, + .. + } => { + match <&RegMem>::from(src) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, F32, 32)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + Inst::XmmUnaryRmRUnaligned { + dst, + ref src, + op: SseOpcode::Movsd, + .. + } => { + match <&RegMem>::from(src) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, F64, 64)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + // NOTE: it's assumed that all of these cases perform 128-bit loads, but this hasn't been + // verified. The effect of this will be spurious PCC failures when these instructions are + // involved. + Inst::XmmRmRUnaligned { dst, ref src2, .. } + | Inst::XmmRmREvex { dst, ref src2, .. } + | Inst::XmmUnaryRmRImmEvex { + dst, src: ref src2, .. + } + | Inst::XmmUnaryRmRUnaligned { + dst, src: ref src2, .. + } + | Inst::XmmUnaryRmREvex { + dst, src: ref src2, .. + } + | Inst::XmmRmREvex3 { + dst, + src3: ref src2, + .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmRmRImmVex { + op, dst, ref src2, .. + } + | Inst::XmmRmRVex3 { + op, + dst, + src3: ref src2, + .. + } + | Inst::XmmRmRBlendVex { + op, dst, ref src2, .. + } + | Inst::XmmUnaryRmRVex { + op, + dst, + src: ref src2, + .. + } + | Inst::XmmUnaryRmRImmVex { + op, + dst, + src: ref src2, + .. + } => { + let (ty, size) = match op { + AvxOpcode::Vmovss => (F32, 32), + AvxOpcode::Vmovsd => (F64, 64), + AvxOpcode::Vpinsrb => (I8, 8), + AvxOpcode::Vpinsrw => (I16, 16), + AvxOpcode::Vpinsrd => (I32, 32), + AvxOpcode::Vpinsrq => (I64, 64), + + // We assume all other operations happen on 128-bit values. + _ => (I8X16, 128), + }; + + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, ty, size)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmRmiRVex { dst, ref src2, .. } => { + match <&RegMemImm>::from(src2) { + RegMemImm::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + RegMemImm::Reg { .. } | RegMemImm::Imm { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmVexPinsr { dst, ref src2, .. } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmMovRMVex { ref dst, .. } | Inst::XmmMovRMImmVex { ref dst, .. } => { + check_store(ctx, None, dst, vcode, I8X16) + } + + Inst::XmmToGprImmVex { dst, .. } => ensure_no_fact(vcode, dst.to_writable_reg().to_reg()), + + Inst::GprToXmmVex { dst, ref src, .. } | Inst::GprToXmm { dst, ref src, .. } => { + match <&RegMem>::from(src) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::XmmToGprVex { dst, .. } => undefined_result(ctx, vcode, dst, 64, 64), + + Inst::XmmMovRM { + ref dst, + op: SseOpcode::Movss, + .. + } => { + check_store(ctx, None, dst, vcode, F32)?; + Ok(()) + } + + Inst::XmmMovRM { + ref dst, + op: SseOpcode::Movsd, + .. + } => { + check_store(ctx, None, dst, vcode, F64)?; + Ok(()) + } + + Inst::XmmMovRM { ref dst, .. } | Inst::XmmMovRMImm { ref dst, .. } => { + check_store(ctx, None, dst, vcode, I8X16)?; + Ok(()) + } + + Inst::XmmToGpr { dst, .. } | Inst::XmmToGprImm { dst, .. } => { + undefined_result(ctx, vcode, dst, 64, 64) + } + + Inst::CvtIntToFloat { dst, ref src2, .. } + | Inst::CvtIntToFloatVex { dst, ref src2, .. } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::CvtUint64ToFloatSeq { + dst, + tmp_gpr1, + tmp_gpr2, + .. + } => { + ensure_no_fact(vcode, dst.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp_gpr1.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp_gpr2.to_writable_reg().to_reg())?; + Ok(()) + } + + Inst::CvtFloatToSintSeq { + dst, + tmp_gpr, + tmp_xmm, + .. + } => { + undefined_result(ctx, vcode, dst, 64, 64)?; + ensure_no_fact(vcode, tmp_gpr.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp_xmm.to_writable_reg().to_reg())?; + Ok(()) + } + + Inst::CvtFloatToUintSeq { + dst, + tmp_gpr, + tmp_xmm, + tmp_xmm2, + .. + } => { + undefined_result(ctx, vcode, dst, 64, 64)?; + ensure_no_fact(vcode, tmp_gpr.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp_xmm.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp_xmm2.to_writable_reg().to_reg())?; + Ok(()) + } + + Inst::XmmMinMaxSeq { dst, .. } => ensure_no_fact(vcode, dst.to_writable_reg().to_reg()), + + Inst::XmmCmpRmR { + ref src1, ref src2, .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, src1.to_reg()) + } + + Inst::XmmRmRImm { + dst, + ref src2, + size, + op, + .. + } if op.has_scalar_src2() => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load( + ctx, + None, + addr, + vcode, + size.to_type(), + size.to_bits().into(), + )?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_reg()) + } + + Inst::XmmRmRImm { dst, ref src2, .. } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I8X16, 128)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, dst.to_reg()) + } + + Inst::XmmCmpRmRVex { + ref src1, ref src2, .. + } => { + match <&RegMem>::from(src2) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, F32, 32)?; + } + RegMem::Reg { .. } => {} + } + ensure_no_fact(vcode, src1.to_reg()) + } + + Inst::CallKnown { .. } + | Inst::ReturnCallKnown { .. } + | Inst::JmpKnown { .. } + | Inst::Ret { .. } + | Inst::JmpIf { .. } + | Inst::JmpCond { .. } + | Inst::TrapIf { .. } + | Inst::TrapIfAnd { .. } + | Inst::TrapIfOr { .. } + | Inst::Hlt {} + | Inst::Ud2 { .. } => Ok(()), + Inst::Rets { .. } => Ok(()), + + Inst::ReturnCallUnknown { .. } => Ok(()), + + Inst::CallUnknown { ref info } => match <&RegMem>::from(&info.dest) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + Ok(()) + } + RegMem::Reg { .. } => Ok(()), + }, + Inst::JmpUnknown { + target: ref dest, .. + } => match <&RegMem>::from(dest) { + RegMem::Mem { ref addr } => { + check_load(ctx, None, addr, vcode, I64, 64)?; + Ok(()) + } + RegMem::Reg { .. } => Ok(()), + }, + + Inst::JmpTableSeq { tmp1, tmp2, .. } => { + ensure_no_fact(vcode, tmp1.to_reg())?; + ensure_no_fact(vcode, tmp2.to_reg())?; + Ok(()) + } + + Inst::LoadExtName { dst, .. } => { + ensure_no_fact(vcode, dst.to_reg())?; + Ok(()) + } + + Inst::LockCmpxchg { + ref mem, dst_old, .. + } => { + ensure_no_fact(vcode, dst_old.to_reg())?; + check_store(ctx, None, mem, vcode, I64)?; + Ok(()) + } + + Inst::LockCmpxchg16b { + ref mem, + dst_old_low, + dst_old_high, + .. + } => { + ensure_no_fact(vcode, dst_old_low.to_reg())?; + ensure_no_fact(vcode, dst_old_high.to_reg())?; + check_store(ctx, None, mem, vcode, I128)?; + Ok(()) + } + + Inst::LockXadd { + size, + ref mem, + dst_old, + operand: _, + } => { + ensure_no_fact(vcode, dst_old.to_reg())?; + check_store(ctx, None, mem, vcode, size.to_type())?; + Ok(()) + } + + Inst::Xchg { + size, + ref mem, + dst_old, + operand: _, + } => { + ensure_no_fact(vcode, dst_old.to_reg())?; + check_store(ctx, None, mem, vcode, size.to_type())?; + Ok(()) + } + + Inst::AtomicRmwSeq { + ref mem, + temp, + dst_old, + .. + } => { + ensure_no_fact(vcode, dst_old.to_reg())?; + ensure_no_fact(vcode, temp.to_reg())?; + check_store(ctx, None, mem, vcode, I64)?; + Ok(()) + } + + Inst::Atomic128RmwSeq { + ref mem, + temp_low, + temp_high, + dst_old_low, + dst_old_high, + .. + } => { + ensure_no_fact(vcode, dst_old_low.to_reg())?; + ensure_no_fact(vcode, dst_old_high.to_reg())?; + ensure_no_fact(vcode, temp_low.to_reg())?; + ensure_no_fact(vcode, temp_high.to_reg())?; + check_store(ctx, None, mem, vcode, I128)?; + Ok(()) + } + + Inst::Atomic128XchgSeq { + ref mem, + dst_old_low, + dst_old_high, + .. + } => { + ensure_no_fact(vcode, dst_old_low.to_reg())?; + ensure_no_fact(vcode, dst_old_high.to_reg())?; + check_store(ctx, None, mem, vcode, I128)?; + Ok(()) + } + + Inst::Fence { .. } => Ok(()), + + Inst::XmmUninitializedValue { dst } => { + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + + Inst::ElfTlsGetAddr { dst, .. } | Inst::MachOTlsGetAddr { dst, .. } => { + ensure_no_fact(vcode, dst.to_writable_reg().to_reg()) + } + Inst::CoffTlsGetAddr { dst, tmp, .. } => { + ensure_no_fact(vcode, dst.to_writable_reg().to_reg())?; + ensure_no_fact(vcode, tmp.to_writable_reg().to_reg())?; + Ok(()) + } + + Inst::Unwind { .. } | Inst::DummyUse { .. } => Ok(()), + + Inst::StackSwitchBasic { .. } => Err(PccError::UnimplementedInst), + } +} + +fn check_load( + ctx: &FactContext, + dst: Option>, + src: &SyntheticAmode, + vcode: &VCode, + ty: Type, + to_bits: u16, +) -> PccResult> { + let result_fact = dst.and_then(|dst| vcode.vreg_fact(dst.to_reg().into())); + let from_bits = u16::try_from(ty.bits()).unwrap(); + check_mem( + ctx, + src, + vcode, + ty, + LoadOrStore::Load { + result_fact, + from_bits, + to_bits, + }, + ) +} + +fn check_store( + ctx: &FactContext, + data: Option, + dst: &SyntheticAmode, + vcode: &VCode, + ty: Type, +) -> PccResult<()> { + let stored_fact = data.and_then(|data| vcode.vreg_fact(data.into())); + check_mem(ctx, dst, vcode, ty, LoadOrStore::Store { stored_fact }).map(|_| ()) +} + +fn check_mem<'a>( + ctx: &FactContext, + amode: &SyntheticAmode, + vcode: &VCode, + ty: Type, + op: LoadOrStore<'a>, +) -> PccResult> { + let addr = match amode { + SyntheticAmode::Real(amode) if amode.get_flags().checked() => { + compute_addr(ctx, vcode, amode, 64).ok_or(PccError::MissingFact)? + } + _ => return Ok(None), + }; + + match op { + LoadOrStore::Load { + result_fact, + from_bits, + to_bits, + } => { + let loaded_fact = clamp_range(ctx, to_bits, from_bits, ctx.load(&addr, ty)?.cloned())?; + trace!( + "loaded_fact = {:?} result_fact = {:?}", + loaded_fact, + result_fact + ); + if ctx.subsumes_fact_optionals(loaded_fact.as_ref(), result_fact) { + Ok(loaded_fact.clone()) + } else { + Err(PccError::UnsupportedFact) + } + } + LoadOrStore::Store { stored_fact } => { + ctx.store(&addr, ty, stored_fact)?; + Ok(None) + } + } +} + +fn compute_addr(ctx: &FactContext, vcode: &VCode, amode: &Amode, bits: u16) -> Option { + trace!("compute_addr: {:?}", amode); + match *amode { + Amode::ImmReg { simm32, base, .. } => { + let base = get_fact_or_default(vcode, base, bits); + trace!("base = {:?}", base); + let simm32: i64 = simm32.into(); + let simm32: u64 = simm32 as u64; + let offset = Fact::constant(bits, simm32); + let sum = ctx.add(&base, &offset, bits)?; + trace!("sum = {:?}", sum); + Some(sum) + } + Amode::ImmRegRegShift { + simm32, + base, + index, + shift, + .. + } => { + let base = get_fact_or_default(vcode, base.into(), bits); + let index = get_fact_or_default(vcode, index.into(), bits); + trace!("base = {:?} index = {:?}", base, index); + let shifted = ctx.shl(&index, bits, shift.into())?; + let sum = ctx.add(&base, &shifted, bits)?; + let simm32: i64 = simm32.into(); + let simm32: u64 = simm32 as u64; + let offset = Fact::constant(bits, simm32); + let sum = ctx.add(&sum, &offset, bits)?; + trace!("sum = {:?}", sum); + Some(sum) + } + Amode::RipRelative { .. } => None, + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/isa/x64/settings.rs b/deps/crates/vendor/cranelift-codegen/src/isa/x64/settings.rs new file mode 100644 index 00000000000000..501e153b46b31a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isa/x64/settings.rs @@ -0,0 +1,9 @@ +//! x86 Settings. + +use crate::settings::{self, detail, Builder, Value}; +use core::fmt; + +// Include code generated by `cranelift-codegen/meta/src/gen_settings.rs:`. This file contains a +// public `Flags` struct with an impl for all of the settings defined in +// `cranelift-codegen/meta/src/isa/x86/settings.rs`. +include!(concat!(env!("OUT_DIR"), "/settings-x86.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/isle_prelude.rs b/deps/crates/vendor/cranelift-codegen/src/isle_prelude.rs new file mode 100644 index 00000000000000..2f346309b26e69 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/isle_prelude.rs @@ -0,0 +1,1156 @@ +//! Shared ISLE prelude implementation for optimization (mid-end) and +//! lowering (backend) ISLE environments. + +/// Helper macro to define methods in `prelude.isle` within `impl Context for +/// ...` for each backend. These methods are shared amongst all backends. +#[macro_export] +#[doc(hidden)] +macro_rules! isle_common_prelude_methods { + () => { + /// We don't have a way of making a `()` value in isle directly. + #[inline] + fn unit(&mut self) -> Unit { + () + } + + #[inline] + fn u8_as_u32(&mut self, x: u8) -> u32 { + x.into() + } + + #[inline] + fn u8_as_u64(&mut self, x: u8) -> u64 { + x.into() + } + + #[inline] + fn u16_as_i16(&mut self, x: u16) -> i16 { + x as i16 + } + + #[inline] + fn u16_as_u32(&mut self, x: u16) -> u32 { + x.into() + } + + #[inline] + fn u16_as_u64(&mut self, x: u16) -> u64 { + x.into() + } + + #[inline] + fn u32_as_u64(&mut self, x: u32) -> u64 { + x.into() + } + + #[inline] + fn i64_as_u64(&mut self, x: i64) -> u64 { + x as u64 + } + + #[inline] + fn u64_as_i32(&mut self, x: u64) -> i32 { + x as i32 + } + + #[inline] + fn u64_as_i64(&mut self, x: u64) -> i64 { + x as i64 + } + + #[inline] + fn i32_as_i64(&mut self, x: i32) -> i64 { + x.into() + } + + #[inline] + fn i64_neg(&mut self, x: i64) -> i64 { + x.wrapping_neg() + } + + #[inline] + fn i8_neg(&mut self, x: i8) -> i8 { + x.wrapping_neg() + } + + #[inline] + fn u64_add(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_add(y) + } + + #[inline] + fn u64_sub(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_sub(y) + } + + #[inline] + fn u64_mul(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_mul(y) + } + + #[inline] + fn u64_sdiv(&mut self, x: u64, y: u64) -> Option { + let x = x as i64; + let y = y as i64; + x.checked_div(y).map(|d| d as u64) + } + + #[inline] + fn u64_udiv(&mut self, x: u64, y: u64) -> Option { + x.checked_div(y) + } + + #[inline] + fn u64_and(&mut self, x: u64, y: u64) -> u64 { + x & y + } + + #[inline] + fn u64_or(&mut self, x: u64, y: u64) -> u64 { + x | y + } + + #[inline] + fn u64_xor(&mut self, x: u64, y: u64) -> u64 { + x ^ y + } + + #[inline] + fn u64_shl(&mut self, x: u64, y: u64) -> u64 { + x << y + } + + #[inline] + fn imm64_shl(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 { + // Mask off any excess shift bits. + let shift_mask = (ty.bits() - 1) as u64; + let y = (y.bits() as u64) & shift_mask; + + // Mask the result to `ty` bits. + let ty_mask = self.ty_mask(ty) as i64; + Imm64::new((x.bits() << y) & ty_mask) + } + + #[inline] + fn imm64_ushr(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 { + let ty_mask = self.ty_mask(ty); + let x = (x.bits() as u64) & ty_mask; + + // Mask off any excess shift bits. + let shift_mask = (ty.bits() - 1) as u64; + let y = (y.bits() as u64) & shift_mask; + + // NB: No need to mask off high bits because they are already zero. + Imm64::new((x >> y) as i64) + } + + #[inline] + fn imm64_sshr(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 { + // Sign extend `x` from `ty.bits()`-width to the full 64 bits. + let shift = u32::checked_sub(64, ty.bits()).unwrap_or(0); + let x = (x.bits() << shift) >> shift; + + // Mask off any excess shift bits. + let shift_mask = (ty.bits() - 1) as i64; + let y = y.bits() & shift_mask; + + // Mask off sign bits that aren't part of `ty`. + let ty_mask = self.ty_mask(ty) as i64; + Imm64::new((x >> y) & ty_mask) + } + + #[inline] + fn u64_not(&mut self, x: u64) -> u64 { + !x + } + + #[inline] + fn u64_eq(&mut self, x: u64, y: u64) -> bool { + x == y + } + + #[inline] + fn u64_le(&mut self, x: u64, y: u64) -> bool { + x <= y + } + + #[inline] + fn u64_lt(&mut self, x: u64, y: u64) -> bool { + x < y + } + + #[inline] + fn u64_is_zero(&mut self, value: u64) -> bool { + 0 == value + } + + fn i64_is_zero(&mut self, value: i64) -> bool { + 0 == value + } + + #[inline] + fn u64_is_odd(&mut self, x: u64) -> bool { + x & 1 == 1 + } + + fn i64_shr(&mut self, a: i64, b: i64) -> i64 { + a >> b + } + + fn i64_ctz(&mut self, a: i64) -> i64 { + a.trailing_zeros().into() + } + + #[inline] + fn i64_sextend_u64(&mut self, ty: Type, x: u64) -> i64 { + let shift_amt = std::cmp::max(0, 64 - ty.bits()); + ((x as i64) << shift_amt) >> shift_amt + } + + #[inline] + fn i64_sextend_imm64(&mut self, ty: Type, x: Imm64) -> i64 { + x.sign_extend_from_width(ty.bits()).bits() + } + + #[inline] + fn u64_uextend_imm64(&mut self, ty: Type, x: Imm64) -> u64 { + (x.bits() as u64) & self.ty_mask(ty) + } + + #[inline] + fn imm64_icmp(&mut self, ty: Type, cc: &IntCC, x: Imm64, y: Imm64) -> Imm64 { + let ux = self.u64_uextend_imm64(ty, x); + let uy = self.u64_uextend_imm64(ty, y); + let sx = self.i64_sextend_imm64(ty, x); + let sy = self.i64_sextend_imm64(ty, y); + let result = match cc { + IntCC::Equal => ux == uy, + IntCC::NotEqual => ux != uy, + IntCC::UnsignedGreaterThanOrEqual => ux >= uy, + IntCC::UnsignedGreaterThan => ux > uy, + IntCC::UnsignedLessThanOrEqual => ux <= uy, + IntCC::UnsignedLessThan => ux < uy, + IntCC::SignedGreaterThanOrEqual => sx >= sy, + IntCC::SignedGreaterThan => sx > sy, + IntCC::SignedLessThanOrEqual => sx <= sy, + IntCC::SignedLessThan => sx < sy, + }; + Imm64::new(result.into()) + } + + #[inline] + fn ty_bits(&mut self, ty: Type) -> u8 { + use std::convert::TryInto; + ty.bits().try_into().unwrap() + } + + #[inline] + fn ty_bits_u16(&mut self, ty: Type) -> u16 { + ty.bits() as u16 + } + + #[inline] + fn ty_bits_u64(&mut self, ty: Type) -> u64 { + ty.bits() as u64 + } + + #[inline] + fn ty_bytes(&mut self, ty: Type) -> u16 { + u16::try_from(ty.bytes()).unwrap() + } + + #[inline] + fn ty_mask(&mut self, ty: Type) -> u64 { + let ty_bits = ty.bits(); + debug_assert_ne!(ty_bits, 0); + let shift = 64_u64 + .checked_sub(ty_bits.into()) + .expect("unimplemented for > 64 bits"); + u64::MAX >> shift + } + + #[inline] + fn ty_lane_mask(&mut self, ty: Type) -> u64 { + let ty_lane_count = ty.lane_count(); + debug_assert_ne!(ty_lane_count, 0); + let shift = 64_u64 + .checked_sub(ty_lane_count.into()) + .expect("unimplemented for > 64 bits"); + u64::MAX >> shift + } + + #[inline] + fn ty_lane_count(&mut self, ty: Type) -> u64 { + ty.lane_count() as u64 + } + + #[inline] + fn ty_umin(&mut self, _ty: Type) -> u64 { + 0 + } + + #[inline] + fn ty_umax(&mut self, ty: Type) -> u64 { + self.ty_mask(ty) + } + + #[inline] + fn ty_smin(&mut self, ty: Type) -> u64 { + let ty_bits = ty.bits(); + debug_assert_ne!(ty_bits, 0); + let shift = 64_u64 + .checked_sub(ty_bits.into()) + .expect("unimplemented for > 64 bits"); + (i64::MIN as u64) >> shift + } + + #[inline] + fn ty_smax(&mut self, ty: Type) -> u64 { + let ty_bits = ty.bits(); + debug_assert_ne!(ty_bits, 0); + let shift = 64_u64 + .checked_sub(ty_bits.into()) + .expect("unimplemented for > 64 bits"); + (i64::MAX as u64) >> shift + } + + fn fits_in_16(&mut self, ty: Type) -> Option { + if ty.bits() <= 16 && !ty.is_dynamic_vector() { + Some(ty) + } else { + None + } + } + + #[inline] + fn fits_in_32(&mut self, ty: Type) -> Option { + if ty.bits() <= 32 && !ty.is_dynamic_vector() { + Some(ty) + } else { + None + } + } + + #[inline] + fn lane_fits_in_32(&mut self, ty: Type) -> Option { + if !ty.is_vector() && !ty.is_dynamic_vector() { + None + } else if ty.lane_type().bits() <= 32 { + Some(ty) + } else { + None + } + } + + #[inline] + fn fits_in_64(&mut self, ty: Type) -> Option { + if ty.bits() <= 64 && !ty.is_dynamic_vector() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_int_ref_scalar_64(&mut self, ty: Type) -> Option { + if ty.bits() <= 64 && !ty.is_float() && !ty.is_vector() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_int_ref_scalar_64_extract(&mut self, ty: Type) -> Option { + self.ty_int_ref_scalar_64(ty) + } + + #[inline] + fn ty_32(&mut self, ty: Type) -> Option { + if ty.bits() == 32 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_64(&mut self, ty: Type) -> Option { + if ty.bits() == 64 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_32_or_64(&mut self, ty: Type) -> Option { + if ty.bits() == 32 || ty.bits() == 64 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_8_or_16(&mut self, ty: Type) -> Option { + if ty.bits() == 8 || ty.bits() == 16 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_16_or_32(&mut self, ty: Type) -> Option { + if ty.bits() == 16 || ty.bits() == 32 { + Some(ty) + } else { + None + } + } + + #[inline] + fn int_fits_in_32(&mut self, ty: Type) -> Option { + match ty { + I8 | I16 | I32 => Some(ty), + _ => None, + } + } + + #[inline] + fn ty_int_ref_64(&mut self, ty: Type) -> Option { + match ty { + I64 => Some(ty), + _ => None, + } + } + + #[inline] + fn ty_int_ref_16_to_64(&mut self, ty: Type) -> Option { + match ty { + I16 | I32 | I64 => Some(ty), + _ => None, + } + } + + #[inline] + fn ty_int(&mut self, ty: Type) -> Option { + ty.is_int().then(|| ty) + } + + #[inline] + fn ty_scalar(&mut self, ty: Type) -> Option { + if ty.lane_count() == 1 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_scalar_float(&mut self, ty: Type) -> Option { + if ty.is_float() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_float_or_vec(&mut self, ty: Type) -> Option { + if ty.is_float() || ty.is_vector() { + Some(ty) + } else { + None + } + } + + fn ty_vector_float(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.lane_type().is_float() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vector_not_float(&mut self, ty: Type) -> Option { + if ty.is_vector() && !ty.lane_type().is_float() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vec64_ctor(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.bits() == 64 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vec64(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.bits() == 64 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vec128(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.bits() == 128 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_dyn_vec64(&mut self, ty: Type) -> Option { + if ty.is_dynamic_vector() && dynamic_to_fixed(ty).bits() == 64 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_dyn_vec128(&mut self, ty: Type) -> Option { + if ty.is_dynamic_vector() && dynamic_to_fixed(ty).bits() == 128 { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vec64_int(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.bits() == 64 && ty.lane_type().is_int() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_vec128_int(&mut self, ty: Type) -> Option { + if ty.is_vector() && ty.bits() == 128 && ty.lane_type().is_int() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_addr64(&mut self, ty: Type) -> Option { + match ty { + I64 => Some(ty), + _ => None, + } + } + + #[inline] + fn u64_from_imm64(&mut self, imm: Imm64) -> u64 { + imm.bits() as u64 + } + + #[inline] + fn imm64_power_of_two(&mut self, x: Imm64) -> Option { + let x = i64::from(x); + let x = u64::try_from(x).ok()?; + if x.is_power_of_two() { + Some(x.trailing_zeros().into()) + } else { + None + } + } + + #[inline] + fn u64_from_bool(&mut self, b: bool) -> u64 { + if b { + u64::MAX + } else { + 0 + } + } + + #[inline] + fn multi_lane(&mut self, ty: Type) -> Option<(u32, u32)> { + if ty.lane_count() > 1 { + Some((ty.lane_bits(), ty.lane_count())) + } else { + None + } + } + + #[inline] + fn dynamic_lane(&mut self, ty: Type) -> Option<(u32, u32)> { + if ty.is_dynamic_vector() { + Some((ty.lane_bits(), ty.min_lane_count())) + } else { + None + } + } + + #[inline] + fn ty_dyn64_int(&mut self, ty: Type) -> Option { + if ty.is_dynamic_vector() && ty.min_bits() == 64 && ty.lane_type().is_int() { + Some(ty) + } else { + None + } + } + + #[inline] + fn ty_dyn128_int(&mut self, ty: Type) -> Option { + if ty.is_dynamic_vector() && ty.min_bits() == 128 && ty.lane_type().is_int() { + Some(ty) + } else { + None + } + } + + fn u16_from_ieee16(&mut self, val: Ieee16) -> u16 { + val.bits() + } + + fn u32_from_ieee32(&mut self, val: Ieee32) -> u32 { + val.bits() + } + + fn u64_from_ieee64(&mut self, val: Ieee64) -> u64 { + val.bits() + } + + fn u8_from_uimm8(&mut self, val: Uimm8) -> u8 { + val + } + + fn not_vec32x2(&mut self, ty: Type) -> Option { + if ty.lane_bits() == 32 && ty.lane_count() == 2 { + None + } else { + Some(ty) + } + } + + fn not_i64x2(&mut self, ty: Type) -> Option<()> { + if ty == I64X2 { + None + } else { + Some(()) + } + } + + fn trap_code_division_by_zero(&mut self) -> TrapCode { + TrapCode::INTEGER_DIVISION_BY_ZERO + } + + fn trap_code_integer_overflow(&mut self) -> TrapCode { + TrapCode::INTEGER_OVERFLOW + } + + fn trap_code_bad_conversion_to_integer(&mut self) -> TrapCode { + TrapCode::BAD_CONVERSION_TO_INTEGER + } + + fn nonzero_u64_from_imm64(&mut self, val: Imm64) -> Option { + match val.bits() { + 0 => None, + n => Some(n as u64), + } + } + + #[inline] + fn u32_add(&mut self, a: u32, b: u32) -> u32 { + a.wrapping_add(b) + } + + #[inline] + fn u32_sub(&mut self, a: u32, b: u32) -> u32 { + a.wrapping_sub(b) + } + + #[inline] + fn u32_and(&mut self, a: u32, b: u32) -> u32 { + a & b + } + + #[inline] + fn u32_shl(&mut self, x: u32, y: u32) -> u32 { + x << y + } + + #[inline] + fn s32_add_fallible(&mut self, a: i32, b: i32) -> Option { + a.checked_add(b) + } + + #[inline] + fn u32_nonnegative(&mut self, x: u32) -> Option { + if (x as i32) >= 0 { + Some(x) + } else { + None + } + } + + #[inline] + fn u32_lteq(&mut self, a: u32, b: u32) -> Option<()> { + if a <= b { + Some(()) + } else { + None + } + } + + #[inline] + fn u8_lteq(&mut self, a: u8, b: u8) -> Option<()> { + if a <= b { + Some(()) + } else { + None + } + } + + #[inline] + fn u8_lt(&mut self, a: u8, b: u8) -> Option<()> { + if a < b { + Some(()) + } else { + None + } + } + + #[inline] + fn imm64(&mut self, x: u64) -> Imm64 { + Imm64::new(x as i64) + } + + #[inline] + fn imm64_masked(&mut self, ty: Type, x: u64) -> Imm64 { + Imm64::new((x & self.ty_mask(ty)) as i64) + } + + #[inline] + fn offset32(&mut self, x: Offset32) -> i32 { + x.into() + } + + #[inline] + fn u8_and(&mut self, a: u8, b: u8) -> u8 { + a & b + } + + #[inline] + fn u8_shl(&mut self, a: u8, b: u8) -> u8 { + a << b + } + + #[inline] + fn u8_shr(&mut self, a: u8, b: u8) -> u8 { + a >> b + } + + #[inline] + fn u8_sub(&mut self, a: u8, b: u8) -> u8 { + a.wrapping_sub(b) + } + + #[inline] + fn lane_type(&mut self, ty: Type) -> Type { + ty.lane_type() + } + + #[inline] + fn ty_half_lanes(&mut self, ty: Type) -> Option { + if ty.lane_count() == 1 { + None + } else { + ty.lane_type().by(ty.lane_count() / 2) + } + } + + #[inline] + fn ty_half_width(&mut self, ty: Type) -> Option { + ty.half_width() + } + + #[inline] + fn ty_equal(&mut self, lhs: Type, rhs: Type) -> bool { + lhs == rhs + } + + #[inline] + fn offset32_to_i32(&mut self, offset: Offset32) -> i32 { + offset.into() + } + + #[inline] + fn i32_to_offset32(&mut self, offset: i32) -> Offset32 { + Offset32::new(offset) + } + + fn range(&mut self, start: usize, end: usize) -> Range { + (start, end) + } + + fn range_view(&mut self, (start, end): Range) -> RangeView { + if start >= end { + RangeView::Empty + } else { + RangeView::NonEmpty { + index: start, + rest: (start + 1, end), + } + } + } + + #[inline] + fn mem_flags_trusted(&mut self) -> MemFlags { + MemFlags::trusted() + } + + #[inline] + fn intcc_unsigned(&mut self, x: &IntCC) -> IntCC { + x.unsigned() + } + + #[inline] + fn signed_cond_code(&mut self, cc: &IntCC) -> Option { + match cc { + IntCC::Equal + | IntCC::UnsignedGreaterThanOrEqual + | IntCC::UnsignedGreaterThan + | IntCC::UnsignedLessThanOrEqual + | IntCC::UnsignedLessThan + | IntCC::NotEqual => None, + IntCC::SignedGreaterThanOrEqual + | IntCC::SignedGreaterThan + | IntCC::SignedLessThanOrEqual + | IntCC::SignedLessThan => Some(*cc), + } + } + + #[inline] + fn intcc_swap_args(&mut self, cc: &IntCC) -> IntCC { + cc.swap_args() + } + + #[inline] + fn intcc_complement(&mut self, cc: &IntCC) -> IntCC { + cc.complement() + } + + #[inline] + fn intcc_without_eq(&mut self, x: &IntCC) -> IntCC { + x.without_equal() + } + + #[inline] + fn floatcc_swap_args(&mut self, cc: &FloatCC) -> FloatCC { + cc.swap_args() + } + + #[inline] + fn floatcc_complement(&mut self, cc: &FloatCC) -> FloatCC { + cc.complement() + } + + fn floatcc_unordered(&mut self, cc: &FloatCC) -> bool { + match *cc { + FloatCC::Unordered + | FloatCC::UnorderedOrEqual + | FloatCC::UnorderedOrLessThan + | FloatCC::UnorderedOrLessThanOrEqual + | FloatCC::UnorderedOrGreaterThan + | FloatCC::UnorderedOrGreaterThanOrEqual => true, + _ => false, + } + } + + #[inline] + fn unpack_value_array_2(&mut self, arr: &ValueArray2) -> (Value, Value) { + let [a, b] = *arr; + (a, b) + } + + #[inline] + fn pack_value_array_2(&mut self, a: Value, b: Value) -> ValueArray2 { + [a, b] + } + + #[inline] + fn unpack_value_array_3(&mut self, arr: &ValueArray3) -> (Value, Value, Value) { + let [a, b, c] = *arr; + (a, b, c) + } + + #[inline] + fn pack_value_array_3(&mut self, a: Value, b: Value, c: Value) -> ValueArray3 { + [a, b, c] + } + + #[inline] + fn unpack_block_array_2(&mut self, arr: &BlockArray2) -> (BlockCall, BlockCall) { + let [a, b] = *arr; + (a, b) + } + + #[inline] + fn pack_block_array_2(&mut self, a: BlockCall, b: BlockCall) -> BlockArray2 { + [a, b] + } + + fn u128_as_u64(&mut self, val: u128) -> Option { + u64::try_from(val).ok() + } + + fn u64_as_u32(&mut self, val: u64) -> Option { + u32::try_from(val).ok() + } + + fn u32_as_u16(&mut self, val: u32) -> Option { + val.try_into().ok() + } + + fn i32_as_i8(&mut self, val: i32) -> Option { + val.try_into().ok() + } + + fn u8_as_i8(&mut self, val: u8) -> i8 { + val as i8 + } + + fn u64_as_u8(&mut self, val: u64) -> u8 { + val as u8 + } + + fn u64_as_u16(&mut self, val: u64) -> u16 { + val as u16 + } + + fn u8_try_from_u64(&mut self, val: u64) -> Option { + u8::try_from(val).ok() + } + + fn u64_try_from_i64(&mut self, val: i64) -> Option { + u64::try_from(val).ok() + } + + fn u16_try_from_u64(&mut self, val: u64) -> Option { + u16::try_from(val).ok() + } + + fn u32_try_from_u64(&mut self, val: u64) -> Option { + u32::try_from(val).ok() + } + + fn i8_try_from_u64(&mut self, val: u64) -> Option { + i8::try_from(val).ok() + } + + fn i16_try_from_u64(&mut self, val: u64) -> Option { + i16::try_from(val).ok() + } + + fn i32_try_from_u64(&mut self, val: u64) -> Option { + i32::try_from(val).ok() + } + + fn u128_replicated_u64(&mut self, val: u128) -> Option { + let low64 = val as u64 as u128; + if (low64 | (low64 << 64)) == val { + Some(low64 as u64) + } else { + None + } + } + + fn u64_replicated_u32(&mut self, val: u64) -> Option { + let low32 = val as u32 as u64; + if (low32 | (low32 << 32)) == val { + Some(low32) + } else { + None + } + } + + fn u32_replicated_u16(&mut self, val: u64) -> Option { + let val = val as u32; + let low16 = val as u16 as u32; + if (low16 | (low16 << 16)) == val { + Some(low16.into()) + } else { + None + } + } + + fn u16_replicated_u8(&mut self, val: u64) -> Option { + let val = val as u16; + let low8 = val as u8 as u16; + if (low8 | (low8 << 8)) == val { + Some(low8 as u8) + } else { + None + } + } + + fn f16_min(&mut self, a: Ieee16, b: Ieee16) -> Option { + a.minimum(b).non_nan() + } + + fn f16_max(&mut self, a: Ieee16, b: Ieee16) -> Option { + a.maximum(b).non_nan() + } + + fn f16_neg(&mut self, n: Ieee16) -> Ieee16 { + -n + } + + fn f16_abs(&mut self, n: Ieee16) -> Ieee16 { + n.abs() + } + + fn f16_copysign(&mut self, a: Ieee16, b: Ieee16) -> Ieee16 { + a.copysign(b) + } + + fn f32_add(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option { + (lhs + rhs).non_nan() + } + + fn f32_sub(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option { + (lhs - rhs).non_nan() + } + + fn f32_mul(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option { + (lhs * rhs).non_nan() + } + + fn f32_div(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option { + (lhs / rhs).non_nan() + } + + fn f32_sqrt(&mut self, n: Ieee32) -> Option { + n.sqrt().non_nan() + } + + fn f32_ceil(&mut self, n: Ieee32) -> Option { + n.ceil().non_nan() + } + + fn f32_floor(&mut self, n: Ieee32) -> Option { + n.floor().non_nan() + } + + fn f32_trunc(&mut self, n: Ieee32) -> Option { + n.trunc().non_nan() + } + + fn f32_nearest(&mut self, n: Ieee32) -> Option { + n.round_ties_even().non_nan() + } + + fn f32_min(&mut self, a: Ieee32, b: Ieee32) -> Option { + a.minimum(b).non_nan() + } + + fn f32_max(&mut self, a: Ieee32, b: Ieee32) -> Option { + a.maximum(b).non_nan() + } + + fn f32_neg(&mut self, n: Ieee32) -> Ieee32 { + -n + } + + fn f32_abs(&mut self, n: Ieee32) -> Ieee32 { + n.abs() + } + + fn f32_copysign(&mut self, a: Ieee32, b: Ieee32) -> Ieee32 { + a.copysign(b) + } + + fn f64_add(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option { + (lhs + rhs).non_nan() + } + + fn f64_sub(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option { + (lhs - rhs).non_nan() + } + + fn f64_mul(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option { + (lhs * rhs).non_nan() + } + + fn f64_div(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option { + (lhs / rhs).non_nan() + } + + fn f64_sqrt(&mut self, n: Ieee64) -> Option { + n.sqrt().non_nan() + } + + fn f64_ceil(&mut self, n: Ieee64) -> Option { + n.ceil().non_nan() + } + + fn f64_floor(&mut self, n: Ieee64) -> Option { + n.floor().non_nan() + } + + fn f64_trunc(&mut self, n: Ieee64) -> Option { + n.trunc().non_nan() + } + + fn f64_nearest(&mut self, n: Ieee64) -> Option { + n.round_ties_even().non_nan() + } + + fn f64_min(&mut self, a: Ieee64, b: Ieee64) -> Option { + a.minimum(b).non_nan() + } + + fn f64_max(&mut self, a: Ieee64, b: Ieee64) -> Option { + a.maximum(b).non_nan() + } + + fn f64_neg(&mut self, n: Ieee64) -> Ieee64 { + -n + } + + fn f64_abs(&mut self, n: Ieee64) -> Ieee64 { + n.abs() + } + + fn f64_copysign(&mut self, a: Ieee64, b: Ieee64) -> Ieee64 { + a.copysign(b) + } + + fn f128_min(&mut self, a: Ieee128, b: Ieee128) -> Option { + a.minimum(b).non_nan() + } + + fn f128_max(&mut self, a: Ieee128, b: Ieee128) -> Option { + a.maximum(b).non_nan() + } + + fn f128_neg(&mut self, n: Ieee128) -> Ieee128 { + -n + } + + fn f128_abs(&mut self, n: Ieee128) -> Ieee128 { + n.abs() + } + + fn f128_copysign(&mut self, a: Ieee128, b: Ieee128) -> Ieee128 { + a.copysign(b) + } + }; +} diff --git a/deps/crates/vendor/cranelift-codegen/src/iterators.rs b/deps/crates/vendor/cranelift-codegen/src/iterators.rs new file mode 100644 index 00000000000000..ca9c4ab26ba5a4 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/iterators.rs @@ -0,0 +1,93 @@ +//! Iterator utilities. + +/// Extra methods for iterators. +pub trait IteratorExtras: Iterator { + /// Create an iterator that produces adjacent pairs of elements from the iterator. + fn adjacent_pairs(mut self) -> AdjacentPairs + where + Self: Sized, + Self::Item: Clone, + { + let elem = self.next(); + AdjacentPairs { iter: self, elem } + } +} + +impl IteratorExtras for T where T: Iterator {} + +/// Adjacent pairs iterator returned by `adjacent_pairs()`. +/// +/// This wraps another iterator and produces a sequence of adjacent pairs of elements. +pub struct AdjacentPairs +where + I: Iterator, + I::Item: Clone, +{ + iter: I, + elem: Option, +} + +impl Iterator for AdjacentPairs +where + I: Iterator, + I::Item: Clone, +{ + type Item = (I::Item, I::Item); + + fn next(&mut self) -> Option { + self.elem.take().and_then(|e| { + self.elem = self.iter.next(); + self.elem.clone().map(|n| (e, n)) + }) + } +} + +#[cfg(test)] +mod tests { + use alloc::vec::Vec; + + #[test] + fn adjpairs() { + use super::IteratorExtras; + + assert_eq!( + [1, 2, 3, 4] + .iter() + .cloned() + .adjacent_pairs() + .collect::>(), + vec![(1, 2), (2, 3), (3, 4)] + ); + assert_eq!( + [2, 3, 4] + .iter() + .cloned() + .adjacent_pairs() + .collect::>(), + vec![(2, 3), (3, 4)] + ); + assert_eq!( + [2, 3, 4] + .iter() + .cloned() + .adjacent_pairs() + .collect::>(), + vec![(2, 3), (3, 4)] + ); + assert_eq!( + [3, 4].iter().cloned().adjacent_pairs().collect::>(), + vec![(3, 4)] + ); + assert_eq!( + [4].iter().cloned().adjacent_pairs().collect::>(), + vec![] + ); + assert_eq!( + [].iter() + .cloned() + .adjacent_pairs() + .collect::>(), + vec![] + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/legalizer/globalvalue.rs b/deps/crates/vendor/cranelift-codegen/src/legalizer/globalvalue.rs new file mode 100644 index 00000000000000..9837dd59278eaf --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/legalizer/globalvalue.rs @@ -0,0 +1,151 @@ +//! Legalization of global values. +//! +//! This module exports the `expand_global_value` function which transforms a `global_value` +//! instruction into code that depends on the kind of global value referenced. + +use crate::cursor::{Cursor, FuncCursor}; +use crate::ir::{self, pcc::Fact, InstBuilder}; +use crate::isa::TargetIsa; + +/// Expand a `global_value` instruction according to the definition of the global value. +pub fn expand_global_value( + inst: ir::Inst, + func: &mut ir::Function, + isa: &dyn TargetIsa, + global_value: ir::GlobalValue, +) { + crate::trace!( + "expanding global value: {:?}: {}", + inst, + func.dfg.display_inst(inst) + ); + + match func.global_values[global_value] { + ir::GlobalValueData::VMContext => vmctx_addr(global_value, inst, func), + ir::GlobalValueData::IAddImm { + base, + offset, + global_type, + } => iadd_imm_addr(inst, func, base, offset.into(), global_type), + ir::GlobalValueData::Load { + base, + offset, + global_type, + flags, + } => load_addr(inst, func, base, offset, global_type, flags, isa), + ir::GlobalValueData::Symbol { tls, .. } => symbol(inst, func, global_value, isa, tls), + ir::GlobalValueData::DynScaleTargetConst { vector_type } => { + const_vector_scale(inst, func, vector_type, isa) + } + } +} + +fn const_vector_scale(inst: ir::Inst, func: &mut ir::Function, ty: ir::Type, isa: &dyn TargetIsa) { + assert!(ty.bytes() <= 16); + + // Use a minimum of 128-bits for the base type. + let base_bytes = std::cmp::max(ty.bytes(), 16); + let scale = (isa.dynamic_vector_bytes(ty) / base_bytes) as i64; + assert!(scale > 0); + let pos = FuncCursor::new(func).at_inst(inst); + pos.func.dfg.replace(inst).iconst(isa.pointer_type(), scale); +} + +/// Expand a `global_value` instruction for a vmctx global. +fn vmctx_addr(global_value: ir::GlobalValue, inst: ir::Inst, func: &mut ir::Function) { + // Get the value representing the `vmctx` argument. + let vmctx = func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("Missing vmctx parameter"); + + // Replace the `global_value` instruction's value with an alias to the vmctx arg. + let result = func.dfg.first_result(inst); + func.dfg.clear_results(inst); + func.dfg.change_to_alias(result, vmctx); + func.layout.remove_inst(inst); + + // If there was a fact on the GV, then copy it to the vmctx arg + // blockparam def. + if let Some(fact) = &func.global_value_facts[global_value] { + if func.dfg.facts[vmctx].is_none() { + let fact = fact.clone(); + func.dfg.facts[vmctx] = Some(fact); + } + } +} + +/// Expand a `global_value` instruction for an iadd_imm global. +fn iadd_imm_addr( + inst: ir::Inst, + func: &mut ir::Function, + base: ir::GlobalValue, + offset: i64, + global_type: ir::Type, +) { + let mut pos = FuncCursor::new(func).at_inst(inst); + + // Get the value for the lhs. + let lhs = pos.ins().global_value(global_type, base); + if let Some(fact) = &pos.func.global_value_facts[base] { + pos.func.dfg.facts[lhs] = Some(fact.clone()); + } + + // Generate the constant and attach a fact to the constant if + // there is a fact on the base. + let constant = pos.ins().iconst(global_type, offset); + if pos.func.global_value_facts[base].is_some() { + let bits = u16::try_from(global_type.bits()).unwrap(); + let unsigned_offset = offset as u64; // Safety: reinterpret i64 bits as u64. + pos.func.dfg.facts[constant] = Some(Fact::constant(bits, unsigned_offset)); + } + + // Simply replace the `global_value` instruction with an `iadd_imm`, reusing the result value. + pos.func.dfg.replace(inst).iadd(lhs, constant); +} + +/// Expand a `global_value` instruction for a load global. +fn load_addr( + inst: ir::Inst, + func: &mut ir::Function, + base: ir::GlobalValue, + offset: ir::immediates::Offset32, + global_type: ir::Type, + flags: ir::MemFlags, + isa: &dyn TargetIsa, +) { + // We need to load a pointer from the `base` global value, so insert a new `global_value` + // instruction. This depends on the iterative legalization loop. Note that the IR verifier + // detects any cycles in the `load` globals. + let ptr_ty = isa.pointer_type(); + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + // Get the value for the base. + let base_addr = pos.ins().global_value(ptr_ty, base); + if let Some(fact) = &pos.func.global_value_facts[base] { + pos.func.dfg.facts[base_addr] = Some(fact.clone()); + } + + // Perform the load. + pos.func + .dfg + .replace(inst) + .load(global_type, flags, base_addr, offset); +} + +/// Expand a `global_value` instruction for a symbolic name global. +fn symbol( + inst: ir::Inst, + func: &mut ir::Function, + gv: ir::GlobalValue, + isa: &dyn TargetIsa, + tls: bool, +) { + let ptr_ty = isa.pointer_type(); + + if tls { + func.dfg.replace(inst).tls_value(ptr_ty, gv); + } else { + func.dfg.replace(inst).symbol_value(ptr_ty, gv); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/legalizer/mod.rs b/deps/crates/vendor/cranelift-codegen/src/legalizer/mod.rs new file mode 100644 index 00000000000000..5a45b45ba270a0 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/legalizer/mod.rs @@ -0,0 +1,255 @@ +//! Legalize instructions. +//! +//! A legal instruction is one that can be mapped directly to a machine code instruction for the +//! target ISA. The `legalize_function()` function takes as input any function and transforms it +//! into an equivalent function using only legal instructions. +//! +//! The characteristics of legal instructions depend on the target ISA, so any given instruction +//! can be legal for one ISA and illegal for another. +//! +//! Besides transforming instructions, the legalizer also fills out the `function.encodings` map +//! which provides a legal encoding recipe for every instruction. +//! +//! The legalizer does not deal with register allocation constraints. These constraints are derived +//! from the encoding recipes, and solved later by the register allocator. + +use crate::cursor::{Cursor, FuncCursor}; +use crate::ir::immediates::Imm64; +use crate::ir::types::{self, I128, I64}; +use crate::ir::{self, InstBuilder, InstructionData, MemFlags, Value}; +use crate::isa::TargetIsa; +use crate::trace; + +mod globalvalue; + +use self::globalvalue::expand_global_value; + +fn imm_const(pos: &mut FuncCursor, arg: Value, imm: Imm64, is_signed: bool) -> Value { + let ty = pos.func.dfg.value_type(arg); + match (ty, is_signed) { + (I128, true) => { + let imm = pos.ins().iconst(I64, imm); + pos.ins().sextend(I128, imm) + } + (I128, false) => { + let imm = pos.ins().iconst(I64, imm); + pos.ins().uextend(I128, imm) + } + _ => { + let bits = imm.bits(); + let unsigned = match ty.lane_type() { + types::I8 => bits as u8 as i64, + types::I16 => bits as u16 as i64, + types::I32 => bits as u32 as i64, + types::I64 => bits, + _ => unreachable!(), + }; + pos.ins().iconst(ty.lane_type(), unsigned) + } + } +} + +/// Perform a simple legalization by expansion of the function, without +/// platform-specific transforms. +pub fn simple_legalize(func: &mut ir::Function, isa: &dyn TargetIsa) { + trace!("Pre-legalization function:\n{}", func.display()); + + let mut pos = FuncCursor::new(func); + let func_begin = pos.position(); + pos.set_position(func_begin); + while let Some(_block) = pos.next_block() { + let mut prev_pos = pos.position(); + while let Some(inst) = pos.next_inst() { + match pos.func.dfg.insts[inst] { + // memory and constants + InstructionData::UnaryGlobalValue { + opcode: ir::Opcode::GlobalValue, + global_value, + } => expand_global_value(inst, &mut pos.func, isa, global_value), + InstructionData::StackLoad { + opcode: ir::Opcode::StackLoad, + stack_slot, + offset, + } => { + let ty = pos.func.dfg.value_type(pos.func.dfg.first_result(inst)); + let addr_ty = isa.pointer_type(); + + let mut pos = FuncCursor::new(pos.func).at_inst(inst); + pos.use_srcloc(inst); + + let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset); + + // Stack slots are required to be accessible. + // We can't currently ensure that they are aligned. + let mut mflags = MemFlags::new(); + mflags.set_notrap(); + pos.func.dfg.replace(inst).load(ty, mflags, addr, 0); + } + InstructionData::StackStore { + opcode: ir::Opcode::StackStore, + arg, + stack_slot, + offset, + } => { + let addr_ty = isa.pointer_type(); + + let mut pos = FuncCursor::new(pos.func).at_inst(inst); + pos.use_srcloc(inst); + + let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset); + + // Stack slots are required to be accessible. + // We can't currently ensure that they are aligned. + let mut mflags = MemFlags::new(); + mflags.set_notrap(); + pos.func.dfg.replace(inst).store(mflags, arg, addr, 0); + } + InstructionData::DynamicStackLoad { + opcode: ir::Opcode::DynamicStackLoad, + dynamic_stack_slot, + } => { + let ty = pos.func.dfg.value_type(pos.func.dfg.first_result(inst)); + assert!(ty.is_dynamic_vector()); + let addr_ty = isa.pointer_type(); + + let mut pos = FuncCursor::new(pos.func).at_inst(inst); + pos.use_srcloc(inst); + + let addr = pos.ins().dynamic_stack_addr(addr_ty, dynamic_stack_slot); + + // Stack slots are required to be accessible and aligned. + let mflags = MemFlags::trusted(); + pos.func.dfg.replace(inst).load(ty, mflags, addr, 0); + } + InstructionData::DynamicStackStore { + opcode: ir::Opcode::DynamicStackStore, + arg, + dynamic_stack_slot, + } => { + pos.use_srcloc(inst); + let addr_ty = isa.pointer_type(); + let vector_ty = pos.func.dfg.value_type(arg); + assert!(vector_ty.is_dynamic_vector()); + + let addr = pos.ins().dynamic_stack_addr(addr_ty, dynamic_stack_slot); + + let mut mflags = MemFlags::new(); + // Stack slots are required to be accessible and aligned. + mflags.set_notrap(); + mflags.set_aligned(); + pos.func.dfg.replace(inst).store(mflags, arg, addr, 0); + } + + InstructionData::BinaryImm64 { opcode, arg, imm } => { + let is_signed = match opcode { + ir::Opcode::IaddImm + | ir::Opcode::IrsubImm + | ir::Opcode::ImulImm + | ir::Opcode::SdivImm + | ir::Opcode::SremImm => true, + _ => false, + }; + + let imm = imm_const(&mut pos, arg, imm, is_signed); + let replace = pos.func.dfg.replace(inst); + match opcode { + // bitops + ir::Opcode::BandImm => { + replace.band(arg, imm); + } + ir::Opcode::BorImm => { + replace.bor(arg, imm); + } + ir::Opcode::BxorImm => { + replace.bxor(arg, imm); + } + // bitshifting + ir::Opcode::IshlImm => { + replace.ishl(arg, imm); + } + ir::Opcode::RotlImm => { + replace.rotl(arg, imm); + } + ir::Opcode::RotrImm => { + replace.rotr(arg, imm); + } + ir::Opcode::SshrImm => { + replace.sshr(arg, imm); + } + ir::Opcode::UshrImm => { + replace.ushr(arg, imm); + } + // math + ir::Opcode::IaddImm => { + replace.iadd(arg, imm); + } + ir::Opcode::IrsubImm => { + // note: arg order reversed + replace.isub(imm, arg); + } + ir::Opcode::ImulImm => { + replace.imul(arg, imm); + } + ir::Opcode::SdivImm => { + replace.sdiv(arg, imm); + } + ir::Opcode::SremImm => { + replace.srem(arg, imm); + } + ir::Opcode::UdivImm => { + replace.udiv(arg, imm); + } + ir::Opcode::UremImm => { + replace.urem(arg, imm); + } + _ => prev_pos = pos.position(), + }; + } + + // comparisons + InstructionData::IntCompareImm { + opcode: ir::Opcode::IcmpImm, + cond, + arg, + imm, + } => { + let imm = imm_const(&mut pos, arg, imm, true); + pos.func.dfg.replace(inst).icmp(cond, arg, imm); + } + + // Legalize the fused bitwise-plus-not instructions into simpler + // instructions to assist with optimizations. Lowering will + // pattern match this sequence regardless when architectures + // support the instruction natively. + InstructionData::Binary { opcode, args } => { + match opcode { + ir::Opcode::BandNot => { + let neg = pos.ins().bnot(args[1]); + pos.func.dfg.replace(inst).band(args[0], neg); + } + ir::Opcode::BorNot => { + let neg = pos.ins().bnot(args[1]); + pos.func.dfg.replace(inst).bor(args[0], neg); + } + ir::Opcode::BxorNot => { + let neg = pos.ins().bnot(args[1]); + pos.func.dfg.replace(inst).bxor(args[0], neg); + } + _ => prev_pos = pos.position(), + }; + } + + _ => { + prev_pos = pos.position(); + continue; + } + } + + // Legalization implementations require fixpoint loop here. + // TODO: fix this. + pos.set_position(prev_pos); + } + } + + trace!("Post-legalization function:\n{}", func.display()); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/lib.rs b/deps/crates/vendor/cranelift-codegen/src/lib.rs new file mode 100644 index 00000000000000..5291057daa771e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/lib.rs @@ -0,0 +1,109 @@ +//! Cranelift code generation library. +#![deny(missing_docs)] +// Display feature requirements in the documentation when building on docs.rs +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![no_std] +// Various bits and pieces of this crate might only be used for one platform or +// another, but it's not really too useful to learn about that all the time. On +// CI we build at least one version of this crate with `--features all-arch` +// which means we'll always detect truly dead code, otherwise if this is only +// built for one platform we don't have to worry too much about trimming +// everything down. +#![cfg_attr(not(feature = "all-arch"), allow(dead_code))] +#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] + +#[allow(unused_imports)] // #[macro_use] is required for no_std +#[macro_use] +extern crate alloc; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(not(feature = "std"))] +use hashbrown::{hash_map, HashMap}; +#[cfg(feature = "std")] +use std::collections::{hash_map, HashMap}; + +pub use crate::context::Context; +pub use crate::value_label::{LabelValueLoc, ValueLabelsRanges, ValueLocRange}; +pub use crate::verifier::verify_function; +pub use crate::write::write_function; + +pub use cranelift_bforest as bforest; +pub use cranelift_bitset as bitset; +pub use cranelift_control as control; +pub use cranelift_entity as entity; +#[cfg(feature = "unwind")] +pub use gimli; + +#[macro_use] +mod machinst; + +pub mod binemit; +pub mod cfg_printer; +pub mod cursor; +pub mod data_value; +pub mod dbg; +pub mod dominator_tree; +pub mod flowgraph; +pub mod ir; +pub mod isa; +pub mod loop_analysis; +pub mod print_errors; +pub mod settings; +pub mod timing; +pub mod traversals; +pub mod verifier; +pub mod write; + +pub use crate::entity::packed_option; +pub use crate::machinst::buffer::{ + FinalizedMachReloc, FinalizedRelocTarget, MachCallSite, MachSrcLoc, MachTextSectionBuilder, + MachTrap, OpenPatchRegion, PatchRegion, +}; +pub use crate::machinst::{ + CallInfo, CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit, + MachInstEmitState, MachLabel, RealReg, Reg, RelocDistance, TextSectionBuilder, + VCodeConstantData, VCodeConstants, Writable, +}; + +mod alias_analysis; +mod constant_hash; +mod context; +mod ctxhash; +mod egraph; +mod inst_predicates; +mod isle_prelude; +mod iterators; +mod legalizer; +mod nan_canonicalization; +mod opts; +mod ranges; +mod remove_constant_phis; +mod result; +mod scoped_hash_map; +mod unionfind; +mod unreachable_code; +mod value_label; + +#[cfg(feature = "souper-harvest")] +mod souper_harvest; + +pub use crate::result::{CodegenError, CodegenResult, CompileError}; + +#[cfg(feature = "incremental-cache")] +pub mod incremental_cache; + +/// Even when trace logging is disabled, the trace macro has a significant performance cost so we +/// disable it by default. +#[macro_export] +macro_rules! trace { + ($($tt:tt)*) => { + if cfg!(any(feature = "trace-log", debug_assertions)) { + ::log::trace!($($tt)*); + } + }; +} + +include!(concat!(env!("OUT_DIR"), "/version.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/loop_analysis.rs b/deps/crates/vendor/cranelift-codegen/src/loop_analysis.rs new file mode 100644 index 00000000000000..71f845652233d3 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/loop_analysis.rs @@ -0,0 +1,447 @@ +//! A loop analysis represented as mappings of loops to their header Block +//! and parent in the loop tree. + +use crate::dominator_tree::DominatorTree; +use crate::entity::entity_impl; +use crate::entity::SecondaryMap; +use crate::entity::{Keys, PrimaryMap}; +use crate::flowgraph::ControlFlowGraph; +use crate::ir::{Block, Function, Layout}; +use crate::packed_option::PackedOption; +use crate::timing; +use alloc::vec::Vec; +use smallvec::SmallVec; + +/// A opaque reference to a code loop. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Loop(u32); +entity_impl!(Loop, "loop"); + +/// Loop tree information for a single function. +/// +/// Loops are referenced by the Loop object, and for each loop you can access its header block, +/// its eventual parent in the loop tree and all the block belonging to the loop. +pub struct LoopAnalysis { + loops: PrimaryMap, + block_loop_map: SecondaryMap>, + valid: bool, +} + +struct LoopData { + header: Block, + parent: PackedOption, + level: LoopLevel, +} + +/// A level in a loop nest. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct LoopLevel(u8); +impl LoopLevel { + const INVALID: u8 = u8::MAX; + + /// Get the root level (no loop). + pub fn root() -> Self { + Self(0) + } + /// Get the loop level. + pub fn level(self) -> usize { + self.0 as usize + } + /// Invalid loop level. + pub fn invalid() -> Self { + Self(Self::INVALID) + } + /// One loop level deeper. + pub fn inc(self) -> Self { + if self.0 == (Self::INVALID - 1) { + self + } else { + Self(self.0 + 1) + } + } + /// A clamped loop level from a larger-width (usize) depth. + pub fn clamped(level: usize) -> Self { + Self( + u8::try_from(std::cmp::min(level, (Self::INVALID as usize) - 1)) + .expect("Clamped value must always convert"), + ) + } +} + +impl std::default::Default for LoopLevel { + fn default() -> Self { + LoopLevel::invalid() + } +} + +impl LoopData { + /// Creates a `LoopData` object with the loop header and its eventual parent in the loop tree. + pub fn new(header: Block, parent: Option) -> Self { + Self { + header, + parent: parent.into(), + level: LoopLevel::invalid(), + } + } +} + +/// Methods for querying the loop analysis. +impl LoopAnalysis { + /// Allocate a new blank loop analysis struct. Use `compute` to compute the loop analysis for + /// a function. + pub fn new() -> Self { + Self { + valid: false, + loops: PrimaryMap::new(), + block_loop_map: SecondaryMap::new(), + } + } + + /// Returns all the loops contained in a function. + pub fn loops(&self) -> Keys { + self.loops.keys() + } + + /// Returns the header block of a particular loop. + /// + /// The characteristic property of a loop header block is that it dominates some of its + /// predecessors. + pub fn loop_header(&self, lp: Loop) -> Block { + self.loops[lp].header + } + + /// Return the eventual parent of a loop in the loop tree. + pub fn loop_parent(&self, lp: Loop) -> Option { + self.loops[lp].parent.expand() + } + + /// Return the innermost loop for a given block. + pub fn innermost_loop(&self, block: Block) -> Option { + self.block_loop_map[block].expand() + } + + /// Determine if a Block is a loop header. If so, return the loop. + pub fn is_loop_header(&self, block: Block) -> Option { + self.innermost_loop(block) + .filter(|&lp| self.loop_header(lp) == block) + } + + /// Determine if a Block belongs to a loop by running a finger along the loop tree. + /// + /// Returns `true` if `block` is in loop `lp`. + pub fn is_in_loop(&self, block: Block, lp: Loop) -> bool { + let block_loop = self.block_loop_map[block]; + match block_loop.expand() { + None => false, + Some(block_loop) => self.is_child_loop(block_loop, lp), + } + } + + /// Determines if a loop is contained in another loop. + /// + /// `is_child_loop(child,parent)` returns `true` if and only if `child` is a child loop of + /// `parent` (or `child == parent`). + pub fn is_child_loop(&self, child: Loop, parent: Loop) -> bool { + let mut finger = Some(child); + while let Some(finger_loop) = finger { + if finger_loop == parent { + return true; + } + finger = self.loop_parent(finger_loop); + } + false + } + + /// Returns the loop-nest level of a given block. + pub fn loop_level(&self, block: Block) -> LoopLevel { + self.innermost_loop(block) + .map_or(LoopLevel(0), |lp| self.loops[lp].level) + } +} + +impl LoopAnalysis { + /// Detects the loops in a function. Needs the control flow graph and the dominator tree. + pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph, domtree: &DominatorTree) { + let _tt = timing::loop_analysis(); + self.loops.clear(); + self.block_loop_map.clear(); + self.block_loop_map.resize(func.dfg.num_blocks()); + self.find_loop_headers(cfg, domtree, &func.layout); + self.discover_loop_blocks(cfg, domtree, &func.layout); + self.assign_loop_levels(); + self.valid = true; + } + + /// Check if the loop analysis is in a valid state. + /// + /// Note that this doesn't perform any kind of validity checks. It simply checks if the + /// `compute()` method has been called since the last `clear()`. It does not check that the + /// loop analysis is consistent with the CFG. + pub fn is_valid(&self) -> bool { + self.valid + } + + /// Clear all the data structures contained in the loop analysis. This will leave the + /// analysis in a similar state to a context returned by `new()` except that allocated + /// memory be retained. + pub fn clear(&mut self) { + self.loops.clear(); + self.block_loop_map.clear(); + self.valid = false; + } + + // Determines if a block dominates any predecessor + // and thus is a loop header. + fn is_block_loop_header( + block: Block, + cfg: &ControlFlowGraph, + domtree: &DominatorTree, + layout: &Layout, + ) -> bool { + // A block is a loop header if it dominates any of its predecessors. + cfg.pred_iter(block) + .any(|pred| domtree.dominates(block, pred.inst, layout)) + } + + // Traverses the CFG in reverse postorder and create a loop object for every block having a + // back edge. + fn find_loop_headers( + &mut self, + cfg: &ControlFlowGraph, + domtree: &DominatorTree, + layout: &Layout, + ) { + for &block in domtree + .cfg_rpo() + .filter(|&&block| Self::is_block_loop_header(block, cfg, domtree, layout)) + { + // This block is a loop header, so we create its associated loop + let lp = self.loops.push(LoopData::new(block, None)); + self.block_loop_map[block] = lp.into(); + } + } + + // Intended to be called after `find_loop_headers`. For each detected loop header, + // discovers all the block belonging to the loop and its inner loops. After a call to this + // function, the loop tree is fully constructed. + fn discover_loop_blocks( + &mut self, + cfg: &ControlFlowGraph, + domtree: &DominatorTree, + layout: &Layout, + ) { + let mut stack: Vec = Vec::new(); + // We handle each loop header in reverse order, corresponding to a pseudo postorder + // traversal of the graph. + for lp in self.loops().rev() { + // Push all predecessors of this header that it dominates onto the stack. + stack.extend( + cfg.pred_iter(self.loops[lp].header) + .filter(|pred| { + // We follow the back edges + domtree.dominates(self.loops[lp].header, pred.inst, layout) + }) + .map(|pred| pred.block), + ); + while let Some(node) = stack.pop() { + let continue_dfs: Option; + match self.block_loop_map[node].expand() { + None => { + // The node hasn't been visited yet, we tag it as part of the loop + self.block_loop_map[node] = PackedOption::from(lp); + continue_dfs = Some(node); + } + Some(node_loop) => { + // We copy the node_loop into a mutable reference passed along the while + let mut node_loop = node_loop; + // The node is part of a loop, which can be lp or an inner loop + let mut node_loop_parent_option = self.loops[node_loop].parent; + while let Some(node_loop_parent) = node_loop_parent_option.expand() { + if node_loop_parent == lp { + // We have encountered lp so we stop (already visited) + break; + } else { + // + node_loop = node_loop_parent; + // We lookup the parent loop + node_loop_parent_option = self.loops[node_loop].parent; + } + } + // Now node_loop_parent is either: + // - None and node_loop is an new inner loop of lp + // - Some(...) and the initial node_loop was a known inner loop of lp + match node_loop_parent_option.expand() { + Some(_) => continue_dfs = None, + None => { + if node_loop != lp { + self.loops[node_loop].parent = lp.into(); + continue_dfs = Some(self.loops[node_loop].header) + } else { + // If lp is a one-block loop then we make sure we stop + continue_dfs = None + } + } + } + } + } + // Now we have handled the popped node and need to continue the DFS by adding the + // predecessors of that node + if let Some(continue_dfs) = continue_dfs { + stack.extend(cfg.pred_iter(continue_dfs).map(|pred| pred.block)); + } + } + } + } + + fn assign_loop_levels(&mut self) { + let mut stack: SmallVec<[Loop; 8]> = SmallVec::new(); + for lp in self.loops.keys() { + if self.loops[lp].level == LoopLevel::invalid() { + stack.push(lp); + while let Some(&lp) = stack.last() { + if let Some(parent) = self.loops[lp].parent.into() { + if self.loops[parent].level != LoopLevel::invalid() { + self.loops[lp].level = self.loops[parent].level.inc(); + stack.pop(); + } else { + stack.push(parent); + } + } else { + self.loops[lp].level = LoopLevel::root().inc(); + stack.pop(); + } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, FuncCursor}; + use crate::dominator_tree::DominatorTree; + use crate::flowgraph::ControlFlowGraph; + use crate::ir::{types, Function, InstBuilder}; + use crate::loop_analysis::{Loop, LoopAnalysis}; + use alloc::vec::Vec; + + #[test] + fn nested_loops_detection() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let block3 = func.dfg.make_block(); + let block4 = func.dfg.make_block(); + let cond = func.dfg.append_block_param(block0, types::I32); + + { + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + cur.ins().jump(block1, &[]); + + cur.insert_block(block1); + cur.ins().jump(block2, &[]); + + cur.insert_block(block2); + cur.ins().brif(cond, block1, &[], block3, &[]); + + cur.insert_block(block3); + cur.ins().brif(cond, block0, &[], block4, &[]); + + cur.insert_block(block4); + cur.ins().return_(&[]); + } + + let mut loop_analysis = LoopAnalysis::new(); + let mut cfg = ControlFlowGraph::new(); + let mut domtree = DominatorTree::new(); + cfg.compute(&func); + domtree.compute(&func, &cfg); + loop_analysis.compute(&func, &cfg, &domtree); + + let loops = loop_analysis.loops().collect::>(); + assert_eq!(loops.len(), 2); + assert_eq!(loop_analysis.loop_header(loops[0]), block0); + assert_eq!(loop_analysis.loop_header(loops[1]), block1); + assert_eq!(loop_analysis.loop_parent(loops[1]), Some(loops[0])); + assert_eq!(loop_analysis.loop_parent(loops[0]), None); + assert_eq!(loop_analysis.is_in_loop(block0, loops[0]), true); + assert_eq!(loop_analysis.is_in_loop(block0, loops[1]), false); + assert_eq!(loop_analysis.is_in_loop(block1, loops[1]), true); + assert_eq!(loop_analysis.is_in_loop(block1, loops[0]), true); + assert_eq!(loop_analysis.is_in_loop(block2, loops[1]), true); + assert_eq!(loop_analysis.is_in_loop(block2, loops[0]), true); + assert_eq!(loop_analysis.is_in_loop(block3, loops[0]), true); + assert_eq!(loop_analysis.is_in_loop(block0, loops[1]), false); + assert_eq!(loop_analysis.loop_level(block0).level(), 1); + assert_eq!(loop_analysis.loop_level(block1).level(), 2); + assert_eq!(loop_analysis.loop_level(block2).level(), 2); + assert_eq!(loop_analysis.loop_level(block3).level(), 1); + } + + #[test] + fn complex_loop_detection() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let block3 = func.dfg.make_block(); + let block4 = func.dfg.make_block(); + let block5 = func.dfg.make_block(); + let block6 = func.dfg.make_block(); + let cond = func.dfg.append_block_param(block0, types::I32); + + { + let mut cur = FuncCursor::new(&mut func); + + cur.insert_block(block0); + cur.ins().brif(cond, block1, &[], block3, &[]); + + cur.insert_block(block1); + cur.ins().jump(block2, &[]); + + cur.insert_block(block2); + cur.ins().brif(cond, block1, &[], block5, &[]); + + cur.insert_block(block3); + cur.ins().jump(block4, &[]); + + cur.insert_block(block4); + cur.ins().brif(cond, block3, &[], block5, &[]); + + cur.insert_block(block5); + cur.ins().brif(cond, block0, &[], block6, &[]); + + cur.insert_block(block6); + cur.ins().return_(&[]); + } + + let mut loop_analysis = LoopAnalysis::new(); + let cfg = ControlFlowGraph::with_function(&func); + let domtree = DominatorTree::with_function(&func, &cfg); + loop_analysis.compute(&func, &cfg, &domtree); + + let loops = loop_analysis.loops().collect::>(); + assert_eq!(loops.len(), 3); + assert_eq!(loop_analysis.loop_header(loops[0]), block0); + assert_eq!(loop_analysis.loop_header(loops[1]), block3); + assert_eq!(loop_analysis.loop_header(loops[2]), block1); + assert_eq!(loop_analysis.loop_parent(loops[1]), Some(loops[0])); + assert_eq!(loop_analysis.loop_parent(loops[2]), Some(loops[0])); + assert_eq!(loop_analysis.loop_parent(loops[0]), None); + assert_eq!(loop_analysis.is_in_loop(block0, loops[0]), true); + assert_eq!(loop_analysis.is_in_loop(block1, loops[2]), true); + assert_eq!(loop_analysis.is_in_loop(block2, loops[2]), true); + assert_eq!(loop_analysis.is_in_loop(block3, loops[1]), true); + assert_eq!(loop_analysis.is_in_loop(block4, loops[1]), true); + assert_eq!(loop_analysis.is_in_loop(block5, loops[0]), true); + assert_eq!(loop_analysis.loop_level(block0).level(), 1); + assert_eq!(loop_analysis.loop_level(block1).level(), 2); + assert_eq!(loop_analysis.loop_level(block2).level(), 2); + assert_eq!(loop_analysis.loop_level(block3).level(), 2); + assert_eq!(loop_analysis.loop_level(block4).level(), 2); + assert_eq!(loop_analysis.loop_level(block5).level(), 1); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/abi.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/abi.rs new file mode 100644 index 00000000000000..1849a7e2ffcc6e --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/abi.rs @@ -0,0 +1,2451 @@ +//! Implementation of a vanilla ABI, shared between several machines. The +//! implementation here assumes that arguments will be passed in registers +//! first, then additional args on the stack; that the stack grows downward, +//! contains a standard frame (return address and frame pointer), and the +//! compiler is otherwise free to allocate space below that with its choice of +//! layout; and that the machine has some notion of caller- and callee-save +//! registers. Most modern machines, e.g. x86-64 and AArch64, should fit this +//! mold and thus both of these backends use this shared implementation. +//! +//! See the documentation in specific machine backends for the "instantiation" +//! of this generic ABI, i.e., which registers are caller/callee-save, arguments +//! and return values, and any other special requirements. +//! +//! For now the implementation here assumes a 64-bit machine, but we intend to +//! make this 32/64-bit-generic shortly. +//! +//! # Vanilla ABI +//! +//! First, arguments and return values are passed in registers up to a certain +//! fixed count, after which they overflow onto the stack. Multiple return +//! values either fit in registers, or are returned in a separate return-value +//! area on the stack, given by a hidden extra parameter. +//! +//! Note that the exact stack layout is up to us. We settled on the +//! below design based on several requirements. In particular, we need +//! to be able to generate instructions (or instruction sequences) to +//! access arguments, stack slots, and spill slots before we know how +//! many spill slots or clobber-saves there will be, because of our +//! pass structure. We also prefer positive offsets to negative +//! offsets because of an asymmetry in some machines' addressing modes +//! (e.g., on AArch64, positive offsets have a larger possible range +//! without a long-form sequence to synthesize an arbitrary +//! offset). We also need clobber-save registers to be "near" the +//! frame pointer: Windows unwind information requires it to be within +//! 240 bytes of RBP. Finally, it is not allowed to access memory +//! below the current SP value. +//! +//! We assume that a prologue first pushes the frame pointer (and +//! return address above that, if the machine does not do that in +//! hardware). We set FP to point to this two-word frame record. We +//! store all other frame slots below this two-word frame record, as +//! well as enough space for arguments to the largest possible +//! function call. The stack pointer then remains at this position +//! for the duration of the function, allowing us to address all +//! frame storage at positive offsets from SP. +//! +//! Note that if we ever support dynamic stack-space allocation (for +//! `alloca`), we will need a way to reference spill slots and stack +//! slots relative to a dynamic SP, because we will no longer be able +//! to know a static offset from SP to the slots at any particular +//! program point. Probably the best solution at that point will be to +//! revert to using the frame pointer as the reference for all slots, +//! to allow generating spill/reload and stackslot accesses before we +//! know how large the clobber-saves will be. +//! +//! # Stack Layout +//! +//! The stack looks like: +//! +//! ```plain +//! (high address) +//! | ... | +//! | caller frames | +//! | ... | +//! +===========================+ +//! | ... | +//! | stack args | +//! Canonical Frame Address --> | (accessed via FP) | +//! +---------------------------+ +//! SP at function entry -----> | return address | +//! +---------------------------+ +//! FP after prologue --------> | FP (pushed by prologue) | +//! +---------------------------+ ----- +//! | ... | | +//! | clobbered callee-saves | | +//! unwind-frame base --------> | (pushed by prologue) | | +//! +---------------------------+ ----- | +//! | ... | | | +//! | spill slots | | | +//! | (accessed via SP) | fixed active +//! | ... | frame size +//! | stack slots | storage | +//! | (accessed via SP) | size | +//! | (alloc'd by prologue) | | | +//! +---------------------------+ ----- | +//! | [alignment as needed] | | +//! | ... | | +//! | args for largest call | | +//! SP -----------------------> | (alloc'd by prologue) | | +//! +===========================+ ----- +//! +//! (low address) +//! ``` +//! +//! # Multi-value Returns +//! +//! We support multi-value returns by using multiple return-value +//! registers. In some cases this is an extension of the base system +//! ABI. See each platform's `abi.rs` implementation for details. + +use crate::entity::SecondaryMap; +use crate::ir::types::*; +use crate::ir::{ArgumentExtension, ArgumentPurpose, Signature}; +use crate::isa::TargetIsa; +use crate::settings::ProbestackStrategy; +use crate::CodegenError; +use crate::{ir, isa}; +use crate::{machinst::*, trace}; +use regalloc2::{MachineEnv, PReg, PRegSet}; +use rustc_hash::FxHashMap; +use smallvec::smallvec; +use std::collections::HashMap; +use std::marker::PhantomData; +use std::mem; + +/// A small vector of instructions (with some reasonable size); appropriate for +/// a small fixed sequence implementing one operation. +pub type SmallInstVec = SmallVec<[I; 4]>; + +/// A type used by backends to track argument-binding info in the "args" +/// pseudoinst. The pseudoinst holds a vec of `ArgPair` structs. +#[derive(Clone, Debug)] +pub struct ArgPair { + /// The vreg that is defined by this args pseudoinst. + pub vreg: Writable, + /// The preg that the arg arrives in; this constrains the vreg's + /// placement at the pseudoinst. + pub preg: Reg, +} + +/// A type used by backends to track return register binding info in the "ret" +/// pseudoinst. The pseudoinst holds a vec of `RetPair` structs. +#[derive(Clone, Debug)] +pub struct RetPair { + /// The vreg that is returned by this pseudionst. + pub vreg: Reg, + /// The preg that the arg is returned through; this constrains the vreg's + /// placement at the pseudoinst. + pub preg: Reg, +} + +/// A location for (part of) an argument or return value. These "storage slots" +/// are specified for each register-sized part of an argument. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ABIArgSlot { + /// In a real register. + Reg { + /// Register that holds this arg. + reg: RealReg, + /// Value type of this arg. + ty: ir::Type, + /// Should this arg be zero- or sign-extended? + extension: ir::ArgumentExtension, + }, + /// Arguments only: on stack, at given offset from SP at entry. + Stack { + /// Offset of this arg relative to the base of stack args. + offset: i64, + /// Value type of this arg. + ty: ir::Type, + /// Should this arg be zero- or sign-extended? + extension: ir::ArgumentExtension, + }, +} + +impl ABIArgSlot { + /// The type of the value that will be stored in this slot. + pub fn get_type(&self) -> ir::Type { + match self { + ABIArgSlot::Reg { ty, .. } => *ty, + ABIArgSlot::Stack { ty, .. } => *ty, + } + } +} + +/// A vector of `ABIArgSlot`s. Inline capacity for one element because basically +/// 100% of values use one slot. Only `i128`s need multiple slots, and they are +/// super rare (and never happen with Wasm). +pub type ABIArgSlotVec = SmallVec<[ABIArgSlot; 1]>; + +/// An ABIArg is composed of one or more parts. This allows for a CLIF-level +/// Value to be passed with its parts in more than one location at the ABI +/// level. For example, a 128-bit integer may be passed in two 64-bit registers, +/// or even a 64-bit register and a 64-bit stack slot, on a 64-bit machine. The +/// number of "parts" should correspond to the number of registers used to store +/// this type according to the machine backend. +/// +/// As an invariant, the `purpose` for every part must match. As a further +/// invariant, a `StructArg` part cannot appear with any other part. +#[derive(Clone, Debug)] +pub enum ABIArg { + /// Storage slots (registers or stack locations) for each part of the + /// argument value. The number of slots must equal the number of register + /// parts used to store a value of this type. + Slots { + /// Slots, one per register part. + slots: ABIArgSlotVec, + /// Purpose of this arg. + purpose: ir::ArgumentPurpose, + }, + /// Structure argument. We reserve stack space for it, but the CLIF-level + /// semantics are a little weird: the value passed to the call instruction, + /// and received in the corresponding block param, is a *pointer*. On the + /// caller side, we memcpy the data from the passed-in pointer to the stack + /// area; on the callee side, we compute a pointer to this stack area and + /// provide that as the argument's value. + StructArg { + /// Offset of this arg relative to base of stack args. + offset: i64, + /// Size of this arg on the stack. + size: u64, + /// Purpose of this arg. + purpose: ir::ArgumentPurpose, + }, + /// Implicit argument. Similar to a StructArg, except that we have the + /// target type, not a pointer type, at the CLIF-level. This argument is + /// still being passed via reference implicitly. + ImplicitPtrArg { + /// Register or stack slot holding a pointer to the buffer. + pointer: ABIArgSlot, + /// Offset of the argument buffer. + offset: i64, + /// Type of the implicit argument. + ty: Type, + /// Purpose of this arg. + purpose: ir::ArgumentPurpose, + }, +} + +impl ABIArg { + /// Create an ABIArg from one register. + pub fn reg( + reg: RealReg, + ty: ir::Type, + extension: ir::ArgumentExtension, + purpose: ir::ArgumentPurpose, + ) -> ABIArg { + ABIArg::Slots { + slots: smallvec![ABIArgSlot::Reg { reg, ty, extension }], + purpose, + } + } + + /// Create an ABIArg from one stack slot. + pub fn stack( + offset: i64, + ty: ir::Type, + extension: ir::ArgumentExtension, + purpose: ir::ArgumentPurpose, + ) -> ABIArg { + ABIArg::Slots { + slots: smallvec![ABIArgSlot::Stack { + offset, + ty, + extension, + }], + purpose, + } + } +} + +/// Are we computing information about arguments or return values? Much of the +/// handling is factored out into common routines; this enum allows us to +/// distinguish which case we're handling. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ArgsOrRets { + /// Arguments. + Args, + /// Return values. + Rets, +} + +/// Abstract location for a machine-specific ABI impl to translate into the +/// appropriate addressing mode. +#[derive(Clone, Copy, Debug)] +pub enum StackAMode { + /// Offset into the current frame's argument area. + IncomingArg(i64, u32), + /// Offset within the stack slots in the current frame. + Slot(i64), + /// Offset into the callee frame's argument area. + OutgoingArg(i64), +} + +/// Trait implemented by machine-specific backend to represent ISA flags. +pub trait IsaFlags: Clone { + /// Get a flag indicating whether forward-edge CFI is enabled. + fn is_forward_edge_cfi_enabled(&self) -> bool { + false + } +} + +/// Used as an out-parameter to accumulate a sequence of `ABIArg`s in +/// `ABIMachineSpec::compute_arg_locs`. Wraps the shared allocation for all +/// `ABIArg`s in `SigSet` and exposes just the args for the current +/// `compute_arg_locs` call. +pub struct ArgsAccumulator<'a> { + sig_set_abi_args: &'a mut Vec, + start: usize, + non_formal_flag: bool, +} + +impl<'a> ArgsAccumulator<'a> { + fn new(sig_set_abi_args: &'a mut Vec) -> Self { + let start = sig_set_abi_args.len(); + ArgsAccumulator { + sig_set_abi_args, + start, + non_formal_flag: false, + } + } + + #[inline] + pub fn push(&mut self, arg: ABIArg) { + debug_assert!(!self.non_formal_flag); + self.sig_set_abi_args.push(arg) + } + + #[inline] + pub fn push_non_formal(&mut self, arg: ABIArg) { + self.non_formal_flag = true; + self.sig_set_abi_args.push(arg) + } + + #[inline] + pub fn args(&self) -> &[ABIArg] { + &self.sig_set_abi_args[self.start..] + } + + #[inline] + pub fn args_mut(&mut self) -> &mut [ABIArg] { + &mut self.sig_set_abi_args[self.start..] + } +} + +/// Trait implemented by machine-specific backend to provide information about +/// register assignments and to allow generating the specific instructions for +/// stack loads/saves, prologues/epilogues, etc. +pub trait ABIMachineSpec { + /// The instruction type. + type I: VCodeInst; + + /// The ISA flags type. + type F: IsaFlags; + + /// This is the limit for the size of argument and return-value areas on the + /// stack. We place a reasonable limit here to avoid integer overflow issues + /// with 32-bit arithmetic. + const STACK_ARG_RET_SIZE_LIMIT: u32; + + /// Returns the number of bits in a word, that is 32/64 for 32/64-bit architecture. + fn word_bits() -> u32; + + /// Returns the number of bytes in a word. + fn word_bytes() -> u32 { + return Self::word_bits() / 8; + } + + /// Returns word-size integer type. + fn word_type() -> Type { + match Self::word_bits() { + 32 => I32, + 64 => I64, + _ => unreachable!(), + } + } + + /// Returns word register class. + fn word_reg_class() -> RegClass { + RegClass::Int + } + + /// Returns required stack alignment in bytes. + fn stack_align(call_conv: isa::CallConv) -> u32; + + /// Process a list of parameters or return values and allocate them to registers + /// and stack slots. + /// + /// The argument locations should be pushed onto the given `ArgsAccumulator` + /// in order. Any extra arguments added (such as return area pointers) + /// should come at the end of the list so that the first N lowered + /// parameters align with the N clif parameters. + /// + /// Returns the stack-space used (rounded up to as alignment requires), and + /// if `add_ret_area_ptr` was passed, the index of the extra synthetic arg + /// that was added. + fn compute_arg_locs( + call_conv: isa::CallConv, + flags: &settings::Flags, + params: &[ir::AbiParam], + args_or_rets: ArgsOrRets, + add_ret_area_ptr: bool, + args: ArgsAccumulator, + ) -> CodegenResult<(u32, Option)>; + + /// Generate a load from the stack. + fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Self::I; + + /// Generate a store to the stack. + fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I; + + /// Generate a move. + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self::I; + + /// Generate an integer-extend operation. + fn gen_extend( + to_reg: Writable, + from_reg: Reg, + is_signed: bool, + from_bits: u8, + to_bits: u8, + ) -> Self::I; + + /// Generate an "args" pseudo-instruction to capture input args in + /// registers. + fn gen_args(args: Vec) -> Self::I; + + /// Generate a "rets" pseudo-instruction that moves vregs to return + /// registers. + fn gen_rets(rets: Vec) -> Self::I; + + /// Generate an add-with-immediate. Note that even if this uses a scratch + /// register, it must satisfy two requirements: + /// + /// - The add-imm sequence must only clobber caller-save registers that are + /// not used for arguments, because it will be placed in the prologue + /// before the clobbered callee-save registers are saved. + /// + /// - The add-imm sequence must work correctly when `from_reg` and/or + /// `into_reg` are the register returned by `get_stacklimit_reg()`. + fn gen_add_imm( + call_conv: isa::CallConv, + into_reg: Writable, + from_reg: Reg, + imm: u32, + ) -> SmallInstVec; + + /// Generate a sequence that traps with a `TrapCode::StackOverflow` code if + /// the stack pointer is less than the given limit register (assuming the + /// stack grows downward). + fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec; + + /// Generate an instruction to compute an address of a stack slot (FP- or + /// SP-based offset). + fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable) -> Self::I; + + /// Get a fixed register to use to compute a stack limit. This is needed for + /// certain sequences generated after the register allocator has already + /// run. This must satisfy two requirements: + /// + /// - It must be a caller-save register that is not used for arguments, + /// because it will be clobbered in the prologue before the clobbered + /// callee-save registers are saved. + /// + /// - It must be safe to pass as an argument and/or destination to + /// `gen_add_imm()`. This is relevant when an addition with a large + /// immediate needs its own temporary; it cannot use the same fixed + /// temporary as this one. + fn get_stacklimit_reg(call_conv: isa::CallConv) -> Reg; + + /// Generate a load to the given [base+offset] address. + fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Self::I; + + /// Generate a store from the given [base+offset] address. + fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Self::I; + + /// Adjust the stack pointer up or down. + fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec; + + /// Compute a FrameLayout structure containing a sorted list of all clobbered + /// registers that are callee-saved according to the ABI, as well as the sizes + /// of all parts of the stack frame. The result is used to emit the prologue + /// and epilogue routines. + fn compute_frame_layout( + call_conv: isa::CallConv, + flags: &settings::Flags, + sig: &Signature, + regs: &[Writable], + is_leaf: bool, + incoming_args_size: u32, + tail_args_size: u32, + fixed_frame_storage_size: u32, + outgoing_args_size: u32, + ) -> FrameLayout; + + /// Generate the usual frame-setup sequence for this architecture: e.g., + /// `push rbp / mov rbp, rsp` on x86-64, or `stp fp, lr, [sp, #-16]!` on + /// AArch64. + fn gen_prologue_frame_setup( + call_conv: isa::CallConv, + flags: &settings::Flags, + isa_flags: &Self::F, + frame_layout: &FrameLayout, + ) -> SmallInstVec; + + /// Generate the usual frame-restore sequence for this architecture. + fn gen_epilogue_frame_restore( + call_conv: isa::CallConv, + flags: &settings::Flags, + isa_flags: &Self::F, + frame_layout: &FrameLayout, + ) -> SmallInstVec; + + /// Generate a return instruction. + fn gen_return( + call_conv: isa::CallConv, + isa_flags: &Self::F, + frame_layout: &FrameLayout, + ) -> SmallInstVec; + + /// Generate a probestack call. + fn gen_probestack(insts: &mut SmallInstVec, frame_size: u32); + + /// Generate a inline stack probe. + fn gen_inline_probestack( + insts: &mut SmallInstVec, + call_conv: isa::CallConv, + frame_size: u32, + guard_size: u32, + ); + + /// Generate a clobber-save sequence. The implementation here should return + /// a sequence of instructions that "push" or otherwise save to the stack all + /// registers written/modified by the function body that are callee-saved. + /// The sequence of instructions should adjust the stack pointer downward, + /// and should align as necessary according to ABI requirements. + fn gen_clobber_save( + call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]>; + + /// Generate a clobber-restore sequence. This sequence should perform the + /// opposite of the clobber-save sequence generated above, assuming that SP + /// going into the sequence is at the same point that it was left when the + /// clobber-save sequence finished. + fn gen_clobber_restore( + call_conv: isa::CallConv, + flags: &settings::Flags, + frame_layout: &FrameLayout, + ) -> SmallVec<[Self::I; 16]>; + + /// Generate a call instruction/sequence. This method is provided one + /// temporary register to use to synthesize the called address, if needed. + fn gen_call(dest: &CallDest, tmp: Writable, info: CallInfo<()>) -> SmallVec<[Self::I; 2]>; + + /// Generate a memcpy invocation. Used to set up struct + /// args. Takes `src`, `dst` as read-only inputs and passes a temporary + /// allocator. + fn gen_memcpy Writable>( + call_conv: isa::CallConv, + dst: Reg, + src: Reg, + size: usize, + alloc_tmp: F, + ) -> SmallVec<[Self::I; 8]>; + + /// Get the number of spillslots required for the given register-class. + fn get_number_of_spillslots_for_value( + rc: RegClass, + target_vector_bytes: u32, + isa_flags: &Self::F, + ) -> u32; + + /// Get the ABI-dependent MachineEnv for managing register allocation. + fn get_machine_env(flags: &settings::Flags, call_conv: isa::CallConv) -> &MachineEnv; + + /// Get all caller-save registers, that is, registers that we expect + /// not to be saved across a call to a callee with the given ABI. + fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> PRegSet; + + /// Get the needed extension mode, given the mode attached to the argument + /// in the signature and the calling convention. The input (the attribute in + /// the signature) specifies what extension type should be done *if* the ABI + /// requires extension to the full register; this method's return value + /// indicates whether the extension actually *will* be done. + fn get_ext_mode( + call_conv: isa::CallConv, + specified: ir::ArgumentExtension, + ) -> ir::ArgumentExtension; +} + +/// Out-of-line data for calls, to keep the size of `Inst` down. +#[derive(Clone, Debug)] +pub struct CallInfo { + /// Receiver of this call + pub dest: T, + /// Register uses of this call. + pub uses: CallArgList, + /// Register defs of this call. + pub defs: CallRetList, + /// Registers clobbered by this call, as per its calling convention. + pub clobbers: PRegSet, + /// The calling convention of the callee. + pub callee_conv: isa::CallConv, + /// The calling convention of the caller. + pub caller_conv: isa::CallConv, + /// The number of bytes that the callee will pop from the stack for the + /// caller, if any. (Used for popping stack arguments with the `tail` + /// calling convention.) + pub callee_pop_size: u32, +} + +impl CallInfo { + /// Creates an empty set of info with no clobbers/uses/etc with the + /// specified ABI + pub fn empty(dest: T, call_conv: isa::CallConv) -> CallInfo { + CallInfo { + dest, + uses: smallvec![], + defs: smallvec![], + clobbers: PRegSet::empty(), + caller_conv: call_conv, + callee_conv: call_conv, + callee_pop_size: 0, + } + } + + /// Change the `T` payload on this info to `U`. + pub fn map(self, f: impl FnOnce(T) -> U) -> CallInfo { + CallInfo { + dest: f(self.dest), + uses: self.uses, + defs: self.defs, + clobbers: self.clobbers, + caller_conv: self.caller_conv, + callee_conv: self.callee_conv, + callee_pop_size: self.callee_pop_size, + } + } +} + +/// The id of an ABI signature within the `SigSet`. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Sig(u32); +cranelift_entity::entity_impl!(Sig); + +impl Sig { + fn prev(self) -> Option { + self.0.checked_sub(1).map(Sig) + } +} + +/// ABI information shared between body (callee) and caller. +#[derive(Clone, Debug)] +pub struct SigData { + /// Currently both return values and arguments are stored in a continuous space vector + /// in `SigSet::abi_args`. + /// + /// ```plain + /// +----------------------------------------------+ + /// | return values | + /// | ... | + /// rets_end --> +----------------------------------------------+ + /// | arguments | + /// | ... | + /// args_end --> +----------------------------------------------+ + /// + /// ``` + /// + /// Note we only store two offsets as rets_end == args_start, and rets_start == prev.args_end. + /// + /// Argument location ending offset (regs or stack slots). Stack offsets are relative to + /// SP on entry to function. + /// + /// This is a index into the `SigSet::abi_args`. + args_end: u32, + + /// Return-value location ending offset. Stack offsets are relative to the return-area + /// pointer. + /// + /// This is a index into the `SigSet::abi_args`. + rets_end: u32, + + /// Space on stack used to store arguments. We're storing the size in u32 to + /// reduce the size of the struct. + sized_stack_arg_space: u32, + + /// Space on stack used to store return values. We're storing the size in u32 to + /// reduce the size of the struct. + sized_stack_ret_space: u32, + + /// Index in `args` of the stack-return-value-area argument. + stack_ret_arg: Option, + + /// Calling convention used. + call_conv: isa::CallConv, +} + +impl SigData { + /// Get total stack space required for arguments. + pub fn sized_stack_arg_space(&self) -> i64 { + self.sized_stack_arg_space.into() + } + + /// Get total stack space required for return values. + pub fn sized_stack_ret_space(&self) -> i64 { + self.sized_stack_ret_space.into() + } + + /// Get calling convention used. + pub fn call_conv(&self) -> isa::CallConv { + self.call_conv + } + + /// The index of the stack-return-value-area argument, if any. + pub fn stack_ret_arg(&self) -> Option { + self.stack_ret_arg + } +} + +/// A (mostly) deduplicated set of ABI signatures. +/// +/// We say "mostly" because we do not dedupe between signatures interned via +/// `ir::SigRef` (direct and indirect calls; the vast majority of signatures in +/// this set) vs via `ir::Signature` (the callee itself and libcalls). Doing +/// this final bit of deduplication would require filling out the +/// `ir_signature_to_abi_sig`, which is a bunch of allocations (not just the +/// hash map itself but params and returns vecs in each signature) that we want +/// to avoid. +/// +/// In general, prefer using the `ir::SigRef`-taking methods to the +/// `ir::Signature`-taking methods when you can get away with it, as they don't +/// require cloning non-copy types that will trigger heap allocations. +/// +/// This type can be indexed by `Sig` to access its associated `SigData`. +pub struct SigSet { + /// Interned `ir::Signature`s that we already have an ABI signature for. + ir_signature_to_abi_sig: FxHashMap, + + /// Interned `ir::SigRef`s that we already have an ABI signature for. + ir_sig_ref_to_abi_sig: SecondaryMap>, + + /// A single, shared allocation for all `ABIArg`s used by all + /// `SigData`s. Each `SigData` references its args/rets via indices into + /// this allocation. + abi_args: Vec, + + /// The actual ABI signatures, keyed by `Sig`. + sigs: PrimaryMap, +} + +impl SigSet { + /// Construct a new `SigSet`, interning all of the signatures used by the + /// given function. + pub fn new(func: &ir::Function, flags: &settings::Flags) -> CodegenResult + where + M: ABIMachineSpec, + { + let arg_estimate = func.dfg.signatures.len() * 6; + + let mut sigs = SigSet { + ir_signature_to_abi_sig: FxHashMap::default(), + ir_sig_ref_to_abi_sig: SecondaryMap::with_capacity(func.dfg.signatures.len()), + abi_args: Vec::with_capacity(arg_estimate), + sigs: PrimaryMap::with_capacity(1 + func.dfg.signatures.len()), + }; + + sigs.make_abi_sig_from_ir_signature::(func.signature.clone(), flags)?; + for sig_ref in func.dfg.signatures.keys() { + sigs.make_abi_sig_from_ir_sig_ref::(sig_ref, &func.dfg, flags)?; + } + + Ok(sigs) + } + + /// Have we already interned an ABI signature for the given `ir::Signature`? + pub fn have_abi_sig_for_signature(&self, signature: &ir::Signature) -> bool { + self.ir_signature_to_abi_sig.contains_key(signature) + } + + /// Construct and intern an ABI signature for the given `ir::Signature`. + pub fn make_abi_sig_from_ir_signature( + &mut self, + signature: ir::Signature, + flags: &settings::Flags, + ) -> CodegenResult + where + M: ABIMachineSpec, + { + // Because the `HashMap` entry API requires taking ownership of the + // lookup key -- and we want to avoid unnecessary clones of + // `ir::Signature`s, even at the cost of duplicate lookups -- we can't + // have a single, get-or-create-style method for interning + // `ir::Signature`s into ABI signatures. So at least (debug) assert that + // we aren't creating duplicate ABI signatures for the same + // `ir::Signature`. + debug_assert!(!self.have_abi_sig_for_signature(&signature)); + + let sig_data = self.from_func_sig::(&signature, flags)?; + let sig = self.sigs.push(sig_data); + self.ir_signature_to_abi_sig.insert(signature, sig); + Ok(sig) + } + + fn make_abi_sig_from_ir_sig_ref( + &mut self, + sig_ref: ir::SigRef, + dfg: &ir::DataFlowGraph, + flags: &settings::Flags, + ) -> CodegenResult + where + M: ABIMachineSpec, + { + if let Some(sig) = self.ir_sig_ref_to_abi_sig[sig_ref] { + return Ok(sig); + } + let signature = &dfg.signatures[sig_ref]; + let sig_data = self.from_func_sig::(signature, flags)?; + let sig = self.sigs.push(sig_data); + self.ir_sig_ref_to_abi_sig[sig_ref] = Some(sig); + Ok(sig) + } + + /// Get the already-interned ABI signature id for the given `ir::SigRef`. + pub fn abi_sig_for_sig_ref(&self, sig_ref: ir::SigRef) -> Sig { + self.ir_sig_ref_to_abi_sig[sig_ref] + .expect("must call `make_abi_sig_from_ir_sig_ref` before `get_abi_sig_for_sig_ref`") + } + + /// Get the already-interned ABI signature id for the given `ir::Signature`. + pub fn abi_sig_for_signature(&self, signature: &ir::Signature) -> Sig { + self.ir_signature_to_abi_sig + .get(signature) + .copied() + .expect("must call `make_abi_sig_from_ir_signature` before `get_abi_sig_for_signature`") + } + + pub fn from_func_sig( + &mut self, + sig: &ir::Signature, + flags: &settings::Flags, + ) -> CodegenResult { + // Keep in sync with ensure_struct_return_ptr_is_returned + if sig.uses_special_return(ArgumentPurpose::StructReturn) { + panic!("Explicit StructReturn return value not allowed: {sig:?}") + } + let tmp; + let returns = if let Some(struct_ret_index) = + sig.special_param_index(ArgumentPurpose::StructReturn) + { + if !sig.returns.is_empty() { + panic!("No return values are allowed when using StructReturn: {sig:?}"); + } + tmp = [sig.params[struct_ret_index]]; + &tmp + } else { + sig.returns.as_slice() + }; + + // Compute args and retvals from signature. Handle retvals first, + // because we may need to add a return-area arg to the args. + + // NOTE: We rely on the order of the args (rets -> args) inserted to compute the offsets in + // `SigSet::args()` and `SigSet::rets()`. Therefore, we cannot change the two + // compute_arg_locs order. + let (sized_stack_ret_space, _) = M::compute_arg_locs( + sig.call_conv, + flags, + &returns, + ArgsOrRets::Rets, + /* extra ret-area ptr = */ false, + ArgsAccumulator::new(&mut self.abi_args), + )?; + if !flags.enable_multi_ret_implicit_sret() { + assert_eq!(sized_stack_ret_space, 0); + } + let rets_end = u32::try_from(self.abi_args.len()).unwrap(); + + // To avoid overflow issues, limit the return size to something reasonable. + if sized_stack_ret_space > M::STACK_ARG_RET_SIZE_LIMIT { + return Err(CodegenError::ImplLimitExceeded); + } + + let need_stack_return_area = sized_stack_ret_space > 0; + if need_stack_return_area { + assert!(!sig.uses_special_param(ir::ArgumentPurpose::StructReturn)); + } + + let (sized_stack_arg_space, stack_ret_arg) = M::compute_arg_locs( + sig.call_conv, + flags, + &sig.params, + ArgsOrRets::Args, + need_stack_return_area, + ArgsAccumulator::new(&mut self.abi_args), + )?; + let args_end = u32::try_from(self.abi_args.len()).unwrap(); + + // To avoid overflow issues, limit the arg size to something reasonable. + if sized_stack_arg_space > M::STACK_ARG_RET_SIZE_LIMIT { + return Err(CodegenError::ImplLimitExceeded); + } + + trace!( + "ABISig: sig {:?} => args end = {} rets end = {} + arg stack = {} ret stack = {} stack_ret_arg = {:?}", + sig, + args_end, + rets_end, + sized_stack_arg_space, + sized_stack_ret_space, + need_stack_return_area, + ); + + let stack_ret_arg = stack_ret_arg.map(|s| u16::try_from(s).unwrap()); + Ok(SigData { + args_end, + rets_end, + sized_stack_arg_space, + sized_stack_ret_space, + stack_ret_arg, + call_conv: sig.call_conv, + }) + } + + /// Get this signature's ABI arguments. + pub fn args(&self, sig: Sig) -> &[ABIArg] { + let sig_data = &self.sigs[sig]; + // Please see comments in `SigSet::from_func_sig` of how we store the offsets. + let start = usize::try_from(sig_data.rets_end).unwrap(); + let end = usize::try_from(sig_data.args_end).unwrap(); + &self.abi_args[start..end] + } + + /// Get information specifying how to pass the implicit pointer + /// to the return-value area on the stack, if required. + pub fn get_ret_arg(&self, sig: Sig) -> Option { + let sig_data = &self.sigs[sig]; + if let Some(i) = sig_data.stack_ret_arg { + Some(self.args(sig)[usize::from(i)].clone()) + } else { + None + } + } + + /// Get information specifying how to pass one argument. + pub fn get_arg(&self, sig: Sig, idx: usize) -> ABIArg { + self.args(sig)[idx].clone() + } + + /// Get this signature's ABI returns. + pub fn rets(&self, sig: Sig) -> &[ABIArg] { + let sig_data = &self.sigs[sig]; + // Please see comments in `SigSet::from_func_sig` of how we store the offsets. + let start = usize::try_from(sig.prev().map_or(0, |prev| self.sigs[prev].args_end)).unwrap(); + let end = usize::try_from(sig_data.rets_end).unwrap(); + &self.abi_args[start..end] + } + + /// Get information specifying how to pass one return value. + pub fn get_ret(&self, sig: Sig, idx: usize) -> ABIArg { + self.rets(sig)[idx].clone() + } + + /// Get the number of arguments expected. + pub fn num_args(&self, sig: Sig) -> usize { + let len = self.args(sig).len(); + if self.sigs[sig].stack_ret_arg.is_some() { + len - 1 + } else { + len + } + } + + /// Get the number of return values expected. + pub fn num_rets(&self, sig: Sig) -> usize { + self.rets(sig).len() + } +} + +// NB: we do _not_ implement `IndexMut` because these signatures are +// deduplicated and shared! +impl std::ops::Index for SigSet { + type Output = SigData; + + fn index(&self, sig: Sig) -> &Self::Output { + &self.sigs[sig] + } +} + +/// Structure describing the layout of a function's stack frame. +#[derive(Clone, Debug, Default)] +pub struct FrameLayout { + /// N.B. The areas whose sizes are given in this structure fully + /// cover the current function's stack frame, from high to low + /// stack addresses in the sequence below. Each size contains + /// any alignment padding that may be required by the ABI. + + /// Size of incoming arguments on the stack. This is not technically + /// part of this function's frame, but code in the function will still + /// need to access it. Depending on the ABI, we may need to set up a + /// frame pointer to do so; we also may need to pop this area from the + /// stack upon return. + pub incoming_args_size: u32, + + /// The size of the incoming argument area, taking into account any + /// potential increase in size required for tail calls present in the + /// function. In the case that no tail calls are present, this value + /// will be the same as [`Self::incoming_args_size`]. + pub tail_args_size: u32, + + /// Size of the "setup area", typically holding the return address + /// and/or the saved frame pointer. This may be written either during + /// the call itself (e.g. a pushed return address) or by code emitted + /// from gen_prologue_frame_setup. In any case, after that code has + /// completed execution, the stack pointer is expected to point to the + /// bottom of this area. The same holds at the start of code emitted + /// by gen_epilogue_frame_restore. + pub setup_area_size: u32, + + /// Size of the area used to save callee-saved clobbered registers. + /// This area is accessed by code emitted from gen_clobber_save and + /// gen_clobber_restore. + pub clobber_size: u32, + + /// Storage allocated for the fixed part of the stack frame. + /// This contains stack slots and spill slots. + pub fixed_frame_storage_size: u32, + + /// Stack size to be reserved for outgoing arguments, if used by + /// the current ABI, or 0 otherwise. After gen_clobber_save and + /// before gen_clobber_restore, the stack pointer points to the + /// bottom of this area. + pub outgoing_args_size: u32, + + /// Sorted list of callee-saved registers that are clobbered + /// according to the ABI. These registers will be saved and + /// restored by gen_clobber_save and gen_clobber_restore. + pub clobbered_callee_saves: Vec>, +} + +impl FrameLayout { + /// Split the clobbered callee-save registers into integer-class and + /// float-class groups. + /// + /// This method does not currently support vector-class callee-save + /// registers because no current backend has them. + pub fn clobbered_callee_saves_by_class(&self) -> (&[Writable], &[Writable]) { + let (ints, floats) = self.clobbered_callee_saves.split_at( + self.clobbered_callee_saves + .partition_point(|r| r.to_reg().class() == RegClass::Int), + ); + debug_assert!(floats.iter().all(|r| r.to_reg().class() == RegClass::Float)); + (ints, floats) + } + + /// The size of FP to SP while the frame is active (not during prologue + /// setup or epilogue tear down). + pub fn active_size(&self) -> u32 { + self.outgoing_args_size + self.fixed_frame_storage_size + self.clobber_size + } + + /// Get the offset from the SP to the sized stack slots area. + pub fn sp_to_sized_stack_slots(&self) -> u32 { + self.outgoing_args_size + } +} + +/// ABI object for a function body. +pub struct Callee { + /// CLIF-level signature, possibly normalized. + ir_sig: ir::Signature, + /// Signature: arg and retval regs. + sig: Sig, + /// Defined dynamic types. + dynamic_type_sizes: HashMap, + /// Offsets to each dynamic stackslot. + dynamic_stackslots: PrimaryMap, + /// Offsets to each sized stackslot. + sized_stackslots: PrimaryMap, + /// Total stack size of all stackslots + stackslots_size: u32, + /// Stack size to be reserved for outgoing arguments. + outgoing_args_size: u32, + /// Initially the number of bytes originating in the callers frame where stack arguments will + /// live. After lowering this number may be larger than the size expected by the function being + /// compiled, as tail calls potentially require more space for stack arguments. + tail_args_size: u32, + /// Register-argument defs, to be provided to the `args` + /// pseudo-inst, and pregs to constrain them to. + reg_args: Vec, + /// Finalized frame layout for this function. + frame_layout: Option, + /// The register holding the return-area pointer, if needed. + ret_area_ptr: Option, + /// Calling convention this function expects. + call_conv: isa::CallConv, + /// The settings controlling this function's compilation. + flags: settings::Flags, + /// The ISA-specific flag values controlling this function's compilation. + isa_flags: M::F, + /// Whether or not this function is a "leaf", meaning it calls no other + /// functions + is_leaf: bool, + /// If this function has a stack limit specified, then `Reg` is where the + /// stack limit will be located after the instructions specified have been + /// executed. + /// + /// Note that this is intended for insertion into the prologue, if + /// present. Also note that because the instructions here execute in the + /// prologue this happens after legalization/register allocation/etc so we + /// need to be extremely careful with each instruction. The instructions are + /// manually register-allocated and carefully only use caller-saved + /// registers and keep nothing live after this sequence of instructions. + stack_limit: Option<(Reg, SmallInstVec)>, + + _mach: PhantomData, +} + +fn get_special_purpose_param_register( + f: &ir::Function, + sigs: &SigSet, + sig: Sig, + purpose: ir::ArgumentPurpose, +) -> Option { + let idx = f.signature.special_param_index(purpose)?; + match &sigs.args(sig)[idx] { + &ABIArg::Slots { ref slots, .. } => match &slots[0] { + &ABIArgSlot::Reg { reg, .. } => Some(reg.into()), + _ => None, + }, + _ => None, + } +} + +fn checked_round_up(val: u32, mask: u32) -> Option { + Some(val.checked_add(mask)? & !mask) +} + +impl Callee { + /// Create a new body ABI instance. + pub fn new( + f: &ir::Function, + isa: &dyn TargetIsa, + isa_flags: &M::F, + sigs: &SigSet, + ) -> CodegenResult { + trace!("ABI: func signature {:?}", f.signature); + + let flags = isa.flags().clone(); + let sig = sigs.abi_sig_for_signature(&f.signature); + + let call_conv = f.signature.call_conv; + // Only these calling conventions are supported. + debug_assert!( + call_conv == isa::CallConv::SystemV + || call_conv == isa::CallConv::Tail + || call_conv == isa::CallConv::Fast + || call_conv == isa::CallConv::Cold + || call_conv == isa::CallConv::WindowsFastcall + || call_conv == isa::CallConv::AppleAarch64 + || call_conv == isa::CallConv::Winch, + "Unsupported calling convention: {call_conv:?}" + ); + + // Compute sized stackslot locations and total stackslot size. + let mut end_offset: u32 = 0; + let mut sized_stackslots = PrimaryMap::new(); + + for (stackslot, data) in f.sized_stack_slots.iter() { + // We start our computation possibly unaligned where the previous + // stackslot left off. + let unaligned_start_offset = end_offset; + + // The start of the stackslot must be aligned. + // + // We always at least machine-word-align slots, but also + // satisfy the user's requested alignment. + debug_assert!(data.align_shift < 32); + let align = std::cmp::max(M::word_bytes(), 1u32 << data.align_shift); + let mask = align - 1; + let start_offset = checked_round_up(unaligned_start_offset, mask) + .ok_or(CodegenError::ImplLimitExceeded)?; + + // The end offset is the the start offset increased by the size + end_offset = start_offset + .checked_add(data.size) + .ok_or(CodegenError::ImplLimitExceeded)?; + + debug_assert_eq!(stackslot.as_u32() as usize, sized_stackslots.len()); + sized_stackslots.push(start_offset); + } + + // Compute dynamic stackslot locations and total stackslot size. + let mut dynamic_stackslots = PrimaryMap::new(); + for (stackslot, data) in f.dynamic_stack_slots.iter() { + debug_assert_eq!(stackslot.as_u32() as usize, dynamic_stackslots.len()); + + // This computation is similar to the stackslots above + let unaligned_start_offset = end_offset; + + let mask = M::word_bytes() - 1; + let start_offset = checked_round_up(unaligned_start_offset, mask) + .ok_or(CodegenError::ImplLimitExceeded)?; + + let ty = f.get_concrete_dynamic_ty(data.dyn_ty).ok_or_else(|| { + CodegenError::Unsupported(format!("invalid dynamic vector type: {}", data.dyn_ty)) + })?; + + end_offset = start_offset + .checked_add(isa.dynamic_vector_bytes(ty)) + .ok_or(CodegenError::ImplLimitExceeded)?; + + dynamic_stackslots.push(start_offset); + } + + // The size of the stackslots needs to be word aligned + let stackslots_size = checked_round_up(end_offset, M::word_bytes() - 1) + .ok_or(CodegenError::ImplLimitExceeded)?; + + let mut dynamic_type_sizes = HashMap::with_capacity(f.dfg.dynamic_types.len()); + for (dyn_ty, _data) in f.dfg.dynamic_types.iter() { + let ty = f + .get_concrete_dynamic_ty(dyn_ty) + .unwrap_or_else(|| panic!("invalid dynamic vector type: {dyn_ty}")); + let size = isa.dynamic_vector_bytes(ty); + dynamic_type_sizes.insert(ty, size); + } + + // Figure out what instructions, if any, will be needed to check the + // stack limit. This can either be specified as a special-purpose + // argument or as a global value which often calculates the stack limit + // from the arguments. + let stack_limit = f + .stack_limit + .map(|gv| gen_stack_limit::(f, sigs, sig, gv)); + + let tail_args_size = sigs[sig].sized_stack_arg_space; + + Ok(Self { + ir_sig: ensure_struct_return_ptr_is_returned(&f.signature), + sig, + dynamic_stackslots, + dynamic_type_sizes, + sized_stackslots, + stackslots_size, + outgoing_args_size: 0, + tail_args_size, + reg_args: vec![], + frame_layout: None, + ret_area_ptr: None, + call_conv, + flags, + isa_flags: isa_flags.clone(), + is_leaf: f.is_leaf(), + stack_limit, + _mach: PhantomData, + }) + } + + /// Inserts instructions necessary for checking the stack limit into the + /// prologue. + /// + /// This function will generate instructions necessary for perform a stack + /// check at the header of a function. The stack check is intended to trap + /// if the stack pointer goes below a particular threshold, preventing stack + /// overflow in wasm or other code. The `stack_limit` argument here is the + /// register which holds the threshold below which we're supposed to trap. + /// This function is known to allocate `stack_size` bytes and we'll push + /// instructions onto `insts`. + /// + /// Note that the instructions generated here are special because this is + /// happening so late in the pipeline (e.g. after register allocation). This + /// means that we need to do manual register allocation here and also be + /// careful to not clobber any callee-saved or argument registers. For now + /// this routine makes do with the `spilltmp_reg` as one temporary + /// register, and a second register of `tmp2` which is caller-saved. This + /// should be fine for us since no spills should happen in this sequence of + /// instructions, so our register won't get accidentally clobbered. + /// + /// No values can be live after the prologue, but in this case that's ok + /// because we just need to perform a stack check before progressing with + /// the rest of the function. + fn insert_stack_check( + &self, + stack_limit: Reg, + stack_size: u32, + insts: &mut SmallInstVec, + ) { + // With no explicit stack allocated we can just emit the simple check of + // the stack registers against the stack limit register, and trap if + // it's out of bounds. + if stack_size == 0 { + insts.extend(M::gen_stack_lower_bound_trap(stack_limit)); + return; + } + + // Note that the 32k stack size here is pretty special. See the + // documentation in x86/abi.rs for why this is here. The general idea is + // that we're protecting against overflow in the addition that happens + // below. + if stack_size >= 32 * 1024 { + insts.extend(M::gen_stack_lower_bound_trap(stack_limit)); + } + + // Add the `stack_size` to `stack_limit`, placing the result in + // `scratch`. + // + // Note though that `stack_limit`'s register may be the same as + // `scratch`. If our stack size doesn't fit into an immediate this + // means we need a second scratch register for loading the stack size + // into a register. + let scratch = Writable::from_reg(M::get_stacklimit_reg(self.call_conv)); + insts.extend(M::gen_add_imm(self.call_conv, scratch, stack_limit, stack_size).into_iter()); + insts.extend(M::gen_stack_lower_bound_trap(scratch.to_reg())); + } +} + +/// Generates the instructions necessary for the `gv` to be materialized into a +/// register. +/// +/// This function will return a register that will contain the result of +/// evaluating `gv`. It will also return any instructions necessary to calculate +/// the value of the register. +/// +/// Note that global values are typically lowered to instructions via the +/// standard legalization pass. Unfortunately though prologue generation happens +/// so late in the pipeline that we can't use these legalization passes to +/// generate the instructions for `gv`. As a result we duplicate some lowering +/// of `gv` here and support only some global values. This is similar to what +/// the x86 backend does for now, and hopefully this can be somewhat cleaned up +/// in the future too! +/// +/// Also note that this function will make use of `writable_spilltmp_reg()` as a +/// temporary register to store values in if necessary. Currently after we write +/// to this register there's guaranteed to be no spilled values between where +/// it's used, because we're not participating in register allocation anyway! +fn gen_stack_limit( + f: &ir::Function, + sigs: &SigSet, + sig: Sig, + gv: ir::GlobalValue, +) -> (Reg, SmallInstVec) { + let mut insts = smallvec![]; + let reg = generate_gv::(f, sigs, sig, gv, &mut insts); + return (reg, insts); +} + +fn generate_gv( + f: &ir::Function, + sigs: &SigSet, + sig: Sig, + gv: ir::GlobalValue, + insts: &mut SmallInstVec, +) -> Reg { + match f.global_values[gv] { + // Return the direct register the vmcontext is in + ir::GlobalValueData::VMContext => { + get_special_purpose_param_register(f, sigs, sig, ir::ArgumentPurpose::VMContext) + .expect("no vmcontext parameter found") + } + // Load our base value into a register, then load from that register + // in to a temporary register. + ir::GlobalValueData::Load { + base, + offset, + global_type: _, + flags: _, + } => { + let base = generate_gv::(f, sigs, sig, base, insts); + let into_reg = Writable::from_reg(M::get_stacklimit_reg(f.stencil.signature.call_conv)); + insts.push(M::gen_load_base_offset( + into_reg, + base, + offset.into(), + M::word_type(), + )); + return into_reg.to_reg(); + } + ref other => panic!("global value for stack limit not supported: {other}"), + } +} + +/// Returns true if the signature needs to be legalized. +fn missing_struct_return(sig: &ir::Signature) -> bool { + sig.uses_special_param(ArgumentPurpose::StructReturn) + && !sig.uses_special_return(ArgumentPurpose::StructReturn) +} + +fn ensure_struct_return_ptr_is_returned(sig: &ir::Signature) -> ir::Signature { + // Keep in sync with Callee::new + let mut sig = sig.clone(); + if sig.uses_special_return(ArgumentPurpose::StructReturn) { + panic!("Explicit StructReturn return value not allowed: {sig:?}") + } + if let Some(struct_ret_index) = sig.special_param_index(ArgumentPurpose::StructReturn) { + if !sig.returns.is_empty() { + panic!("No return values are allowed when using StructReturn: {sig:?}"); + } + sig.returns.insert(0, sig.params[struct_ret_index]); + } + sig +} + +/// ### Pre-Regalloc Functions +/// +/// These methods of `Callee` may only be called before regalloc. +impl Callee { + /// Access the (possibly legalized) signature. + pub fn signature(&self) -> &ir::Signature { + debug_assert!( + !missing_struct_return(&self.ir_sig), + "`Callee::ir_sig` is always legalized" + ); + &self.ir_sig + } + + /// Initialize. This is called after the Callee is constructed because it + /// may allocate a temp vreg, which can only be allocated once the lowering + /// context exists. + pub fn init_retval_area( + &mut self, + sigs: &SigSet, + vregs: &mut VRegAllocator, + ) -> CodegenResult<()> { + if sigs[self.sig].stack_ret_arg.is_some() { + let ret_area_ptr = vregs.alloc(M::word_type())?; + self.ret_area_ptr = Some(ret_area_ptr.only_reg().unwrap()); + } + Ok(()) + } + + /// Get the return area pointer register, if any. + pub fn ret_area_ptr(&self) -> Option { + self.ret_area_ptr + } + + /// Accumulate outgoing arguments. + /// + /// This ensures that at least `size` bytes are allocated in the prologue to + /// be available for use in function calls to hold arguments and/or return + /// values. If this function is called multiple times, the maximum of all + /// `size` values will be available. + pub fn accumulate_outgoing_args_size(&mut self, size: u32) { + if size > self.outgoing_args_size { + self.outgoing_args_size = size; + } + } + + /// Accumulate the incoming argument area size requirements for a tail call, + /// as it could be larger than the incoming arguments of the function + /// currently being compiled. + pub fn accumulate_tail_args_size(&mut self, size: u32) { + if size > self.tail_args_size { + self.tail_args_size = size; + } + } + + pub fn is_forward_edge_cfi_enabled(&self) -> bool { + self.isa_flags.is_forward_edge_cfi_enabled() + } + + /// Get the calling convention implemented by this ABI object. + pub fn call_conv(&self, sigs: &SigSet) -> isa::CallConv { + sigs[self.sig].call_conv + } + + /// Get the ABI-dependent MachineEnv for managing register allocation. + pub fn machine_env(&self, sigs: &SigSet) -> &MachineEnv { + M::get_machine_env(&self.flags, self.call_conv(sigs)) + } + + /// The offsets of all sized stack slots (not spill slots) for debuginfo purposes. + pub fn sized_stackslot_offsets(&self) -> &PrimaryMap { + &self.sized_stackslots + } + + /// The offsets of all dynamic stack slots (not spill slots) for debuginfo purposes. + pub fn dynamic_stackslot_offsets(&self) -> &PrimaryMap { + &self.dynamic_stackslots + } + + /// Generate an instruction which copies an argument to a destination + /// register. + pub fn gen_copy_arg_to_regs( + &mut self, + sigs: &SigSet, + idx: usize, + into_regs: ValueRegs>, + vregs: &mut VRegAllocator, + ) -> SmallInstVec { + let mut insts = smallvec![]; + let mut copy_arg_slot_to_reg = |slot: &ABIArgSlot, into_reg: &Writable| { + match slot { + &ABIArgSlot::Reg { reg, .. } => { + // Add a preg -> def pair to the eventual `args` + // instruction. Extension mode doesn't matter + // (we're copying out, not in; we ignore high bits + // by convention). + let arg = ArgPair { + vreg: *into_reg, + preg: reg.into(), + }; + self.reg_args.push(arg); + } + &ABIArgSlot::Stack { + offset, + ty, + extension, + .. + } => { + // However, we have to respect the extension mode for stack + // slots, or else we grab the wrong bytes on big-endian. + let ext = M::get_ext_mode(sigs[self.sig].call_conv, extension); + let ty = + if ext != ArgumentExtension::None && M::word_bits() > ty_bits(ty) as u32 { + M::word_type() + } else { + ty + }; + insts.push(M::gen_load_stack( + StackAMode::IncomingArg(offset, sigs[self.sig].sized_stack_arg_space), + *into_reg, + ty, + )); + } + } + }; + + match &sigs.args(self.sig)[idx] { + &ABIArg::Slots { ref slots, .. } => { + assert_eq!(into_regs.len(), slots.len()); + for (slot, into_reg) in slots.iter().zip(into_regs.regs().iter()) { + copy_arg_slot_to_reg(&slot, &into_reg); + } + } + &ABIArg::StructArg { offset, .. } => { + let into_reg = into_regs.only_reg().unwrap(); + // Buffer address is implicitly defined by the ABI. + insts.push(M::gen_get_stack_addr( + StackAMode::IncomingArg(offset, sigs[self.sig].sized_stack_arg_space), + into_reg, + )); + } + &ABIArg::ImplicitPtrArg { pointer, ty, .. } => { + let into_reg = into_regs.only_reg().unwrap(); + // We need to dereference the pointer. + let base = match &pointer { + &ABIArgSlot::Reg { reg, ty, .. } => { + let tmp = vregs.alloc_with_deferred_error(ty).only_reg().unwrap(); + self.reg_args.push(ArgPair { + vreg: Writable::from_reg(tmp), + preg: reg.into(), + }); + tmp + } + &ABIArgSlot::Stack { offset, ty, .. } => { + let addr_reg = writable_value_regs(vregs.alloc_with_deferred_error(ty)) + .only_reg() + .unwrap(); + insts.push(M::gen_load_stack( + StackAMode::IncomingArg(offset, sigs[self.sig].sized_stack_arg_space), + addr_reg, + ty, + )); + addr_reg.to_reg() + } + }; + insts.push(M::gen_load_base_offset(into_reg, base, 0, ty)); + } + } + insts + } + + /// Generate an instruction which copies a source register to a return value slot. + pub fn gen_copy_regs_to_retval( + &self, + sigs: &SigSet, + idx: usize, + from_regs: ValueRegs, + vregs: &mut VRegAllocator, + ) -> (SmallVec<[RetPair; 2]>, SmallInstVec) { + let mut reg_pairs = smallvec![]; + let mut ret = smallvec![]; + let word_bits = M::word_bits() as u8; + match &sigs.rets(self.sig)[idx] { + &ABIArg::Slots { ref slots, .. } => { + assert_eq!(from_regs.len(), slots.len()); + for (slot, &from_reg) in slots.iter().zip(from_regs.regs().iter()) { + match slot { + &ABIArgSlot::Reg { + reg, ty, extension, .. + } => { + let from_bits = ty_bits(ty) as u8; + let ext = M::get_ext_mode(sigs[self.sig].call_conv, extension); + let vreg = match (ext, from_bits) { + (ir::ArgumentExtension::Uext, n) + | (ir::ArgumentExtension::Sext, n) + if n < word_bits => + { + let signed = ext == ir::ArgumentExtension::Sext; + let dst = + writable_value_regs(vregs.alloc_with_deferred_error(ty)) + .only_reg() + .unwrap(); + ret.push(M::gen_extend( + dst, from_reg, signed, from_bits, + /* to_bits = */ word_bits, + )); + dst.to_reg() + } + _ => { + // No move needed, regalloc2 will emit it using the constraint + // added by the RetPair. + from_reg + } + }; + reg_pairs.push(RetPair { + vreg, + preg: Reg::from(reg), + }); + } + &ABIArgSlot::Stack { + offset, + ty, + extension, + .. + } => { + let mut ty = ty; + let from_bits = ty_bits(ty) as u8; + // A machine ABI implementation should ensure that stack frames + // have "reasonable" size. All current ABIs for machinst + // backends (aarch64 and x64) enforce a 128MB limit. + let off = i32::try_from(offset).expect( + "Argument stack offset greater than 2GB; should hit impl limit first", + ); + let ext = M::get_ext_mode(sigs[self.sig].call_conv, extension); + // Trash the from_reg; it should be its last use. + match (ext, from_bits) { + (ir::ArgumentExtension::Uext, n) + | (ir::ArgumentExtension::Sext, n) + if n < word_bits => + { + assert_eq!(M::word_reg_class(), from_reg.class()); + let signed = ext == ir::ArgumentExtension::Sext; + let dst = + writable_value_regs(vregs.alloc_with_deferred_error(ty)) + .only_reg() + .unwrap(); + ret.push(M::gen_extend( + dst, from_reg, signed, from_bits, + /* to_bits = */ word_bits, + )); + // Store the extended version. + ty = M::word_type(); + } + _ => {} + }; + ret.push(M::gen_store_base_offset( + self.ret_area_ptr.unwrap(), + off, + from_reg, + ty, + )); + } + } + } + } + ABIArg::StructArg { .. } => { + panic!("StructArg in return position is unsupported"); + } + ABIArg::ImplicitPtrArg { .. } => { + panic!("ImplicitPtrArg in return position is unsupported"); + } + } + (reg_pairs, ret) + } + + /// Generate any setup instruction needed to save values to the + /// return-value area. This is usually used when were are multiple return + /// values or an otherwise large return value that must be passed on the + /// stack; typically the ABI specifies an extra hidden argument that is a + /// pointer to that memory. + pub fn gen_retval_area_setup( + &mut self, + sigs: &SigSet, + vregs: &mut VRegAllocator, + ) -> Option { + if let Some(i) = sigs[self.sig].stack_ret_arg { + let ret_area_ptr = Writable::from_reg(self.ret_area_ptr.unwrap()); + let insts = + self.gen_copy_arg_to_regs(sigs, i.into(), ValueRegs::one(ret_area_ptr), vregs); + insts.into_iter().next().map(|inst| { + trace!( + "gen_retval_area_setup: inst {:?}; ptr reg is {:?}", + inst, + ret_area_ptr.to_reg() + ); + inst + }) + } else { + trace!("gen_retval_area_setup: not needed"); + None + } + } + + /// Generate a return instruction. + pub fn gen_rets(&self, rets: Vec) -> M::I { + M::gen_rets(rets) + } + + /// Produce an instruction that computes a sized stackslot address. + pub fn sized_stackslot_addr( + &self, + slot: StackSlot, + offset: u32, + into_reg: Writable, + ) -> M::I { + // Offset from beginning of stackslot area. + let stack_off = self.sized_stackslots[slot] as i64; + let sp_off: i64 = stack_off + (offset as i64); + M::gen_get_stack_addr(StackAMode::Slot(sp_off), into_reg) + } + + /// Produce an instruction that computes a dynamic stackslot address. + pub fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable) -> M::I { + let stack_off = self.dynamic_stackslots[slot] as i64; + M::gen_get_stack_addr(StackAMode::Slot(stack_off), into_reg) + } + + /// Get an `args` pseudo-inst, if any, that should appear at the + /// very top of the function body prior to regalloc. + pub fn take_args(&mut self) -> Option { + if self.reg_args.len() > 0 { + // Very first instruction is an `args` pseudo-inst that + // establishes live-ranges for in-register arguments and + // constrains them at the start of the function to the + // locations defined by the ABI. + Some(M::gen_args(std::mem::take(&mut self.reg_args))) + } else { + None + } + } +} + +/// ### Post-Regalloc Functions +/// +/// These methods of `Callee` may only be called after +/// regalloc. +impl Callee { + /// Compute the final frame layout, post-regalloc. + /// + /// This must be called before gen_prologue or gen_epilogue. + pub fn compute_frame_layout( + &mut self, + sigs: &SigSet, + spillslots: usize, + clobbered: Vec>, + ) { + let bytes = M::word_bytes(); + let total_stacksize = self.stackslots_size + bytes * spillslots as u32; + let mask = M::stack_align(self.call_conv) - 1; + let total_stacksize = (total_stacksize + mask) & !mask; // 16-align the stack. + self.frame_layout = Some(M::compute_frame_layout( + self.call_conv, + &self.flags, + self.signature(), + &clobbered, + self.is_leaf, + self.stack_args_size(sigs), + self.tail_args_size, + total_stacksize, + self.outgoing_args_size, + )); + } + + /// Generate a prologue, post-regalloc. + /// + /// This should include any stack frame or other setup necessary to use the + /// other methods (`load_arg`, `store_retval`, and spillslot accesses.) + pub fn gen_prologue(&self) -> SmallInstVec { + let frame_layout = self.frame_layout(); + let mut insts = smallvec![]; + + // Set up frame. + insts.extend(M::gen_prologue_frame_setup( + self.call_conv, + &self.flags, + &self.isa_flags, + &frame_layout, + )); + + // The stack limit check needs to cover all the stack adjustments we + // might make, up to the next stack limit check in any function we + // call. Since this happens after frame setup, the current function's + // setup area needs to be accounted for in the caller's stack limit + // check, but we need to account for any setup area that our callees + // might need. Note that s390x may also use the outgoing args area for + // backtrace support even in leaf functions, so that should be accounted + // for unconditionally. + let total_stacksize = (frame_layout.tail_args_size - frame_layout.incoming_args_size) + + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.outgoing_args_size + + if self.is_leaf { + 0 + } else { + frame_layout.setup_area_size + }; + + // Leaf functions with zero stack don't need a stack check if one's + // specified, otherwise always insert the stack check. + if total_stacksize > 0 || !self.is_leaf { + if let Some((reg, stack_limit_load)) = &self.stack_limit { + insts.extend(stack_limit_load.clone()); + self.insert_stack_check(*reg, total_stacksize, &mut insts); + } + + if self.flags.enable_probestack() { + let guard_size = 1 << self.flags.probestack_size_log2(); + match self.flags.probestack_strategy() { + ProbestackStrategy::Inline => M::gen_inline_probestack( + &mut insts, + self.call_conv, + total_stacksize, + guard_size, + ), + ProbestackStrategy::Outline => { + if total_stacksize >= guard_size { + M::gen_probestack(&mut insts, total_stacksize); + } + } + } + } + } + + // Save clobbered registers. + insts.extend(M::gen_clobber_save( + self.call_conv, + &self.flags, + &frame_layout, + )); + + insts + } + + /// Generate an epilogue, post-regalloc. + /// + /// Note that this must generate the actual return instruction (rather than + /// emitting this in the lowering logic), because the epilogue code comes + /// before the return and the two are likely closely related. + pub fn gen_epilogue(&self) -> SmallInstVec { + let frame_layout = self.frame_layout(); + let mut insts = smallvec![]; + + // Restore clobbered registers. + insts.extend(M::gen_clobber_restore( + self.call_conv, + &self.flags, + &frame_layout, + )); + + // Tear down frame. + insts.extend(M::gen_epilogue_frame_restore( + self.call_conv, + &self.flags, + &self.isa_flags, + &frame_layout, + )); + + // And return. + insts.extend(M::gen_return( + self.call_conv, + &self.isa_flags, + &frame_layout, + )); + + trace!("Epilogue: {:?}", insts); + insts + } + + /// Return a reference to the computed frame layout information. This + /// function will panic if it's called before [`Self::compute_frame_layout`]. + pub fn frame_layout(&self) -> &FrameLayout { + self.frame_layout + .as_ref() + .expect("frame layout not computed before prologue generation") + } + + /// Returns the full frame size for the given function, after prologue + /// emission has run. This comprises the spill slots and stack-storage + /// slots as well as storage for clobbered callee-save registers, but + /// not arguments arguments pushed at callsites within this function, + /// or other ephemeral pushes. + pub fn frame_size(&self) -> u32 { + let frame_layout = self.frame_layout(); + frame_layout.clobber_size + frame_layout.fixed_frame_storage_size + } + + /// Returns offset from the slot base in the current frame to the caller's SP. + pub fn slot_base_to_caller_sp_offset(&self) -> u32 { + let frame_layout = self.frame_layout(); + frame_layout.clobber_size + + frame_layout.fixed_frame_storage_size + + frame_layout.setup_area_size + } + + /// Returns the size of arguments expected on the stack. + pub fn stack_args_size(&self, sigs: &SigSet) -> u32 { + sigs[self.sig].sized_stack_arg_space + } + + /// Get the spill-slot size. + pub fn get_spillslot_size(&self, rc: RegClass) -> u32 { + let max = if self.dynamic_type_sizes.len() == 0 { + 16 + } else { + *self + .dynamic_type_sizes + .iter() + .max_by(|x, y| x.1.cmp(&y.1)) + .map(|(_k, v)| v) + .unwrap() + }; + M::get_number_of_spillslots_for_value(rc, max, &self.isa_flags) + } + + /// Get the spill slot offset relative to the fixed allocation area start. + pub fn get_spillslot_offset(&self, slot: SpillSlot) -> i64 { + // Offset from beginning of spillslot area. + let islot = slot.index() as i64; + let spill_off = islot * M::word_bytes() as i64; + let sp_off = self.stackslots_size as i64 + spill_off; + + sp_off + } + + /// Generate a spill. + pub fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg) -> M::I { + let ty = M::I::canonical_type_for_rc(from_reg.class()); + debug_assert_eq!(::I::rc_for_type(ty).unwrap().1, &[ty]); + + let sp_off = self.get_spillslot_offset(to_slot); + trace!("gen_spill: {from_reg:?} into slot {to_slot:?} at offset {sp_off}"); + + let from = StackAMode::Slot(sp_off); + ::gen_store_stack(from, Reg::from(from_reg), ty) + } + + /// Generate a reload (fill). + pub fn gen_reload(&self, to_reg: Writable, from_slot: SpillSlot) -> M::I { + let ty = M::I::canonical_type_for_rc(to_reg.to_reg().class()); + debug_assert_eq!(::I::rc_for_type(ty).unwrap().1, &[ty]); + + let sp_off = self.get_spillslot_offset(from_slot); + trace!("gen_reload: {to_reg:?} from slot {from_slot:?} at offset {sp_off}"); + + let from = StackAMode::Slot(sp_off); + ::gen_load_stack(from, to_reg.map(Reg::from), ty) + } +} + +/// An input argument to a call instruction: the vreg that is used, +/// and the preg it is constrained to (per the ABI). +#[derive(Clone, Debug)] +pub struct CallArgPair { + /// The virtual register to use for the argument. + pub vreg: Reg, + /// The real register into which the arg goes. + pub preg: Reg, +} + +/// An output return value from a call instruction: the vreg that is +/// defined, and the preg it is constrained to (per the ABI). +#[derive(Clone, Debug)] +pub struct CallRetPair { + /// The virtual register to define from this return value. + pub vreg: Writable, + /// The real register from which the return value is read. + pub preg: Reg, +} + +pub type CallArgList = SmallVec<[CallArgPair; 8]>; +pub type CallRetList = SmallVec<[CallRetPair; 8]>; + +pub enum IsTailCall { + Yes, + No, +} + +/// ABI object for a callsite. +pub struct CallSite { + /// The called function's signature. + sig: Sig, + /// All register uses for the callsite, i.e., function args, with + /// VReg and the physical register it is constrained to. + uses: CallArgList, + /// All defs for the callsite, i.e., return values. + defs: CallRetList, + /// Call destination. + dest: CallDest, + is_tail_call: IsTailCall, + /// Caller's calling convention. + caller_conv: isa::CallConv, + /// The settings controlling this compilation. + flags: settings::Flags, + + _mach: PhantomData, +} + +/// Destination for a call. +#[derive(Debug, Clone)] +pub enum CallDest { + /// Call to an ExtName (named function symbol). + ExtName(ir::ExternalName, RelocDistance), + /// Indirect call to a function pointer in a register. + Reg(Reg), +} + +impl CallSite { + /// Create a callsite ABI object for a call directly to the specified function. + pub fn from_func( + sigs: &SigSet, + sig_ref: ir::SigRef, + extname: &ir::ExternalName, + is_tail_call: IsTailCall, + dist: RelocDistance, + caller_conv: isa::CallConv, + flags: settings::Flags, + ) -> CallSite { + let sig = sigs.abi_sig_for_sig_ref(sig_ref); + CallSite { + sig, + uses: smallvec![], + defs: smallvec![], + dest: CallDest::ExtName(extname.clone(), dist), + is_tail_call, + caller_conv, + flags, + _mach: PhantomData, + } + } + + /// Create a callsite ABI object for a call directly to the specified + /// libcall. + pub fn from_libcall( + sigs: &SigSet, + sig: &ir::Signature, + extname: &ir::ExternalName, + dist: RelocDistance, + caller_conv: isa::CallConv, + flags: settings::Flags, + ) -> CallSite { + let sig = sigs.abi_sig_for_signature(sig); + CallSite { + sig, + uses: smallvec![], + defs: smallvec![], + dest: CallDest::ExtName(extname.clone(), dist), + is_tail_call: IsTailCall::No, + caller_conv, + flags, + _mach: PhantomData, + } + } + + /// Create a callsite ABI object for a call to a function pointer with the + /// given signature. + pub fn from_ptr( + sigs: &SigSet, + sig_ref: ir::SigRef, + ptr: Reg, + is_tail_call: IsTailCall, + caller_conv: isa::CallConv, + flags: settings::Flags, + ) -> CallSite { + let sig = sigs.abi_sig_for_sig_ref(sig_ref); + CallSite { + sig, + uses: smallvec![], + defs: smallvec![], + dest: CallDest::Reg(ptr), + is_tail_call, + caller_conv, + flags, + _mach: PhantomData, + } + } + + pub(crate) fn dest(&self) -> &CallDest { + &self.dest + } + + pub(crate) fn take_uses(self) -> CallArgList { + self.uses + } + + pub(crate) fn sig<'a>(&self, sigs: &'a SigSet) -> &'a SigData { + &sigs[self.sig] + } + + pub(crate) fn is_tail_call(&self) -> bool { + matches!(self.is_tail_call, IsTailCall::Yes) + } +} + +impl CallSite { + /// Get the number of arguments expected. + pub fn num_args(&self, sigs: &SigSet) -> usize { + sigs.num_args(self.sig) + } + + /// Get the number of return values expected. + pub fn num_rets(&self, sigs: &SigSet) -> usize { + sigs.num_rets(self.sig) + } + + /// Emit a copy of a large argument into its associated stack buffer, if + /// any. We must be careful to perform all these copies (as necessary) + /// before setting up the argument registers, since we may have to invoke + /// memcpy(), which could clobber any registers already set up. The + /// back-end should call this routine for all arguments before calling + /// `gen_arg` for all arguments. + pub fn emit_copy_regs_to_buffer( + &self, + ctx: &mut Lower, + idx: usize, + from_regs: ValueRegs, + ) { + match &ctx.sigs().args(self.sig)[idx] { + &ABIArg::Slots { .. } | &ABIArg::ImplicitPtrArg { .. } => {} + &ABIArg::StructArg { offset, size, .. } => { + let src_ptr = from_regs.only_reg().unwrap(); + let dst_ptr = ctx.alloc_tmp(M::word_type()).only_reg().unwrap(); + ctx.emit(M::gen_get_stack_addr( + StackAMode::OutgoingArg(offset), + dst_ptr, + )); + // Emit a memcpy from `src_ptr` to `dst_ptr` of `size` bytes. + // N.B.: because we process StructArg params *first*, this is + // safe w.r.t. clobbers: we have not yet filled in any other + // arg regs. + let memcpy_call_conv = + isa::CallConv::for_libcall(&self.flags, ctx.sigs()[self.sig].call_conv); + for insn in M::gen_memcpy( + memcpy_call_conv, + dst_ptr.to_reg(), + src_ptr, + size as usize, + |ty| ctx.alloc_tmp(ty).only_reg().unwrap(), + ) + .into_iter() + { + ctx.emit(insn); + } + } + } + } + + /// Add a constraint for an argument value from a source register. + /// For large arguments with associated stack buffer, this may + /// load the address of the buffer into the argument register, if + /// required by the ABI. + pub fn gen_arg(&mut self, ctx: &mut Lower, idx: usize, from_regs: ValueRegs) { + let stack_arg_space = ctx.sigs()[self.sig].sized_stack_arg_space; + let stack_arg = if self.is_tail_call() { + StackAMode::IncomingArg + } else { + |offset, _| StackAMode::OutgoingArg(offset) + }; + let word_rc = M::word_reg_class(); + let word_bits = M::word_bits() as usize; + + match ctx.sigs().args(self.sig)[idx].clone() { + ABIArg::Slots { ref slots, .. } => { + assert_eq!(from_regs.len(), slots.len()); + for (slot, from_reg) in slots.iter().zip(from_regs.regs().iter()) { + match slot { + &ABIArgSlot::Reg { + reg, ty, extension, .. + } => { + let ext = M::get_ext_mode(ctx.sigs()[self.sig].call_conv, extension); + let vreg = + if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits { + assert_eq!(word_rc, reg.class()); + let signed = match ext { + ir::ArgumentExtension::Uext => false, + ir::ArgumentExtension::Sext => true, + _ => unreachable!(), + }; + let extend_result = + ctx.alloc_tmp(M::word_type()).only_reg().unwrap(); + ctx.emit(M::gen_extend( + extend_result, + *from_reg, + signed, + ty_bits(ty) as u8, + word_bits as u8, + )); + extend_result.to_reg() + } else { + *from_reg + }; + + let preg = reg.into(); + self.uses.push(CallArgPair { vreg, preg }); + } + &ABIArgSlot::Stack { + offset, + ty, + extension, + .. + } => { + let ext = M::get_ext_mode(ctx.sigs()[self.sig].call_conv, extension); + let (data, ty) = + if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits { + assert_eq!(word_rc, from_reg.class()); + let signed = match ext { + ir::ArgumentExtension::Uext => false, + ir::ArgumentExtension::Sext => true, + _ => unreachable!(), + }; + let extend_result = + ctx.alloc_tmp(M::word_type()).only_reg().unwrap(); + ctx.emit(M::gen_extend( + extend_result, + *from_reg, + signed, + ty_bits(ty) as u8, + word_bits as u8, + )); + // Store the extended version. + (extend_result.to_reg(), M::word_type()) + } else { + (*from_reg, ty) + }; + ctx.emit(M::gen_store_stack( + stack_arg(offset, stack_arg_space), + data, + ty, + )); + } + } + } + } + ABIArg::StructArg { .. } => { + // Only supported via ISLE. + } + ABIArg::ImplicitPtrArg { + offset, + pointer, + ty, + purpose: _, + } => { + assert_eq!(from_regs.len(), 1); + let vreg = from_regs.regs()[0]; + let amode = StackAMode::OutgoingArg(offset); + let tmp = ctx.alloc_tmp(M::word_type()).only_reg().unwrap(); + ctx.emit(M::gen_get_stack_addr(amode, tmp)); + let tmp = tmp.to_reg(); + ctx.emit(M::gen_store_base_offset(tmp, 0, vreg, ty)); + match pointer { + ABIArgSlot::Reg { reg, .. } => self.uses.push(CallArgPair { + vreg: tmp, + preg: reg.into(), + }), + ABIArgSlot::Stack { offset, .. } => ctx.emit(M::gen_store_stack( + stack_arg(offset, stack_arg_space), + tmp, + M::word_type(), + )), + } + } + } + } + + /// Call `gen_arg` for each non-hidden argument and emit all instructions + /// generated. + pub fn emit_args(&mut self, ctx: &mut Lower, (inputs, off): isle::ValueSlice) { + let num_args = self.num_args(ctx.sigs()); + assert_eq!(inputs.len(&ctx.dfg().value_lists) - off, num_args); + + let mut arg_value_regs: SmallVec<[_; 16]> = smallvec![]; + for i in 0..num_args { + let input = inputs.get(off + i, &ctx.dfg().value_lists).unwrap(); + arg_value_regs.push(ctx.put_value_in_regs(input)); + } + for (i, arg_regs) in arg_value_regs.iter().enumerate() { + self.emit_copy_regs_to_buffer(ctx, i, *arg_regs); + } + for (i, value_regs) in arg_value_regs.iter().enumerate() { + self.gen_arg(ctx, i, *value_regs); + } + } + + /// Emit the code to forward a stack-return pointer argument through a tail + /// call. + pub fn emit_stack_ret_arg_for_tail_call(&mut self, ctx: &mut Lower) { + if let Some(i) = ctx.sigs()[self.sig].stack_ret_arg() { + let ret_area_ptr = ctx.abi().ret_area_ptr.expect( + "if the tail callee has a return pointer, then the tail caller \ + must as well", + ); + self.gen_arg(ctx, i.into(), ValueRegs::one(ret_area_ptr)); + } + } + + /// Define a return value after the call returns. + pub fn gen_retval( + &mut self, + ctx: &mut Lower, + idx: usize, + ) -> (SmallInstVec, ValueRegs) { + let mut insts = smallvec![]; + let mut into_regs: SmallVec<[Reg; 2]> = smallvec![]; + let ret = ctx.sigs().rets(self.sig)[idx].clone(); + match ret { + ABIArg::Slots { ref slots, .. } => { + for slot in slots { + match slot { + // Extension mode doesn't matter because we're copying out, not in, + // and we ignore high bits in our own registers by convention. + &ABIArgSlot::Reg { reg, ty, .. } => { + let into_reg = ctx.alloc_tmp(ty).only_reg().unwrap(); + self.defs.push(CallRetPair { + vreg: into_reg, + preg: reg.into(), + }); + into_regs.push(into_reg.to_reg()); + } + &ABIArgSlot::Stack { offset, ty, .. } => { + let into_reg = ctx.alloc_tmp(ty).only_reg().unwrap(); + let sig_data = &ctx.sigs()[self.sig]; + // The outgoing argument area must always be restored after a call, + // ensuring that the return values will be in a consistent place after + // any call. + let ret_area_base = sig_data.sized_stack_arg_space(); + insts.push(M::gen_load_stack( + StackAMode::OutgoingArg(offset + ret_area_base), + into_reg, + ty, + )); + into_regs.push(into_reg.to_reg()); + } + } + } + } + ABIArg::StructArg { .. } => { + panic!("StructArg not supported in return position"); + } + ABIArg::ImplicitPtrArg { .. } => { + panic!("ImplicitPtrArg not supported in return position"); + } + } + + let value_regs = match *into_regs { + [a] => ValueRegs::one(a), + [a, b] => ValueRegs::two(a, b), + _ => panic!("Expected to see one or two slots only from {ret:?}"), + }; + (insts, value_regs) + } + + /// Emit the call itself. + /// + /// The returned instruction should have proper use- and def-sets according + /// to the argument registers, return-value registers, and clobbered + /// registers for this function signature in this ABI. + /// + /// (Arg registers are uses, and retval registers are defs. Clobbered + /// registers are also logically defs, but should never be read; their + /// values are "defined" (to the regalloc) but "undefined" in every other + /// sense.) + /// + /// This function should only be called once, as it is allowed to re-use + /// parts of the `CallSite` object in emitting instructions. + pub fn emit_call(&mut self, ctx: &mut Lower) { + let word_type = M::word_type(); + if let Some(i) = ctx.sigs()[self.sig].stack_ret_arg { + let rd = ctx.alloc_tmp(word_type).only_reg().unwrap(); + let ret_area_base = ctx.sigs()[self.sig].sized_stack_arg_space(); + ctx.emit(M::gen_get_stack_addr( + StackAMode::OutgoingArg(ret_area_base), + rd, + )); + self.gen_arg(ctx, i.into(), ValueRegs::one(rd.to_reg())); + } + + let uses = mem::take(&mut self.uses); + let defs = mem::take(&mut self.defs); + let clobbers = { + // Get clobbers: all caller-saves. These may include return value + // regs, which we will remove from the clobber set below. + let mut clobbers = ::get_regs_clobbered_by_call(ctx.sigs()[self.sig].call_conv); + + // Remove retval regs from clobbers. + for def in &defs { + clobbers.remove(PReg::from(def.preg.to_real_reg().unwrap())); + } + + clobbers + }; + + let sig = &ctx.sigs()[self.sig]; + let callee_pop_size = if sig.call_conv() == isa::CallConv::Tail { + // The tail calling convention has callees pop stack arguments. + sig.sized_stack_arg_space + } else { + 0 + }; + + let call_conv = sig.call_conv; + let ret_space = sig.sized_stack_ret_space; + let arg_space = sig.sized_stack_arg_space; + + ctx.abi_mut() + .accumulate_outgoing_args_size(ret_space + arg_space); + + let tmp = ctx.alloc_tmp(word_type).only_reg().unwrap(); + + // Any adjustment to SP to account for required outgoing arguments/stack return values must + // be done inside of the call pseudo-op, to ensure that SP is always in a consistent + // state for all other instructions. For example, if a tail-call abi function is called + // here, the reclamation of the outgoing argument area must be done inside of the call + // pseudo-op's emission to ensure that SP is consistent at all other points in the lowered + // function. (Except the prologue and epilogue, but those are fairly special parts of the + // function that establish the SP invariants that are relied on elsewhere and are generated + // after the register allocator has run and thus cannot have register allocator-inserted + // references to SP offsets.) + for inst in M::gen_call( + &self.dest, + tmp, + CallInfo { + dest: (), + uses, + defs, + clobbers, + callee_conv: call_conv, + caller_conv: self.caller_conv, + callee_pop_size, + }, + ) + .into_iter() + { + ctx.emit(inst); + } + } +} + +#[cfg(test)] +mod tests { + use super::SigData; + + #[test] + fn sig_data_size() { + // The size of `SigData` is performance sensitive, so make sure + // we don't regress it unintentionally. + assert_eq!(std::mem::size_of::(), 24); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/blockorder.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/blockorder.rs new file mode 100644 index 00000000000000..b23fcf4859b1c9 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/blockorder.rs @@ -0,0 +1,465 @@ +//! Computation of basic block order in emitted code. +//! +//! This module handles the translation from CLIF BBs to VCode BBs. +//! +//! The basic idea is that we compute a sequence of "lowered blocks" that +//! correspond to one or more blocks in the graph: (CLIF CFG) `union` (implicit +//! block on *every* edge). Conceptually, the lowering pipeline wants to insert +//! moves for phi-nodes on every block-to-block transfer; these blocks always +//! conceptually exist, but may be merged with an "original" CLIF block (and +//! hence not actually exist; this is equivalent to inserting the blocks only on +//! critical edges). +//! +//! In other words, starting from a CFG like this (where each "CLIF block" and +//! "(edge N->M)" is a separate basic block): +//! +//! ```plain +//! +//! CLIF block 0 +//! / \ +//! (edge 0->1) (edge 0->2) +//! | | +//! CLIF block 1 CLIF block 2 +//! \ / +//! (edge 1->3) (edge 2->3) +//! \ / +//! CLIF block 3 +//! ``` +//! +//! We can produce a CFG of lowered blocks like so: +//! +//! ```plain +//! +--------------+ +//! | CLIF block 0 | +//! +--------------+ +//! / \ +//! +--------------+ +--------------+ +//! | (edge 0->1) | | (edge 0->2) | +//! | CLIF block 1 | | CLIF block 2 | +//! | (edge 1->3) | | (edge 2->3) | +//! +--------------+ +--------------+ +//! \ / +//! \ / +//! +------------+ +//! |CLIF block 3| +//! +------------+ +//! ``` +//! +//! Each `LoweredBlock` names just an original CLIF block, or just an edge block. +//! +//! To compute this lowering, we do a DFS over the CLIF-plus-edge-block graph +//! (never actually materialized, just defined by a "successors" function), and +//! compute the reverse postorder. +//! +//! This algorithm isn't perfect w.r.t. generated code quality: we don't, for +//! example, consider any information about whether edge blocks will actually +//! have content, because this computation happens as part of lowering *before* +//! regalloc, and regalloc may or may not insert moves/spills/reloads on any +//! particular edge. But it works relatively well and is conceptually simple. +//! Furthermore, the [MachBuffer] machine-code sink performs final peephole-like +//! branch editing that in practice elides empty blocks and simplifies some of +//! the other redundancies that this scheme produces. + +use crate::dominator_tree::DominatorTree; +use crate::entity::SecondaryMap; +use crate::inst_predicates::visit_block_succs; +use crate::ir::{Block, Function, Inst, Opcode}; +use crate::{machinst::*, trace}; +use rustc_hash::{FxHashMap, FxHashSet}; + +/// Mapping from CLIF BBs to VCode BBs. +#[derive(Debug)] +pub struct BlockLoweringOrder { + /// Lowered blocks, in BlockIndex order. Each block is some combination of + /// (i) a CLIF block, and (ii) inserted crit-edge blocks before or after; + /// see [LoweredBlock] for details. + lowered_order: Vec, + /// BlockIndex values for successors for all lowered blocks, indexing `lowered_order`. + lowered_succ_indices: Vec, + /// Ranges in `lowered_succ_indices` giving the successor lists for each lowered + /// block. Indexed by lowering-order index (`BlockIndex`). + lowered_succ_ranges: Vec<(Option, std::ops::Range)>, + /// Cold blocks. These blocks are not reordered in the + /// `lowered_order` above; the lowered order must respect RPO + /// (uses after defs) in order for lowering to be + /// correct. Instead, this set is used to provide `is_cold()`, + /// which is used by VCode emission to sink the blocks at the last + /// moment (when we actually emit bytes into the MachBuffer). + cold_blocks: FxHashSet, + /// Lowered blocks that are indirect branch targets. + indirect_branch_targets: FxHashSet, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum LoweredBlock { + /// Block in original CLIF. + Orig { + /// Original CLIF block. + block: Block, + }, + + /// Critical edge between two CLIF blocks. + CriticalEdge { + /// The predecessor block. + pred: Block, + + /// The successor block. + succ: Block, + + /// The index of this branch in the successor edges from `pred`, following the same + /// indexing order as `inst_predicates::visit_block_succs`. This is used to distinguish + /// multiple edges between the same CLIF blocks. + succ_idx: u32, + }, +} + +impl LoweredBlock { + /// Unwrap an `Orig` block. + pub fn orig_block(&self) -> Option { + match self { + &LoweredBlock::Orig { block } => Some(block), + &LoweredBlock::CriticalEdge { .. } => None, + } + } + + /// The associated in-edge predecessor, if this is a critical edge. + #[cfg(test)] + pub fn in_edge(&self) -> Option { + match self { + &LoweredBlock::CriticalEdge { pred, .. } => Some(pred), + &LoweredBlock::Orig { .. } => None, + } + } + + /// The associated out-edge successor, if this is a critical edge. + #[cfg(test)] + pub fn out_edge(&self) -> Option { + match self { + &LoweredBlock::CriticalEdge { succ, .. } => Some(succ), + &LoweredBlock::Orig { .. } => None, + } + } +} + +impl BlockLoweringOrder { + /// Compute and return a lowered block order for `f`. + pub fn new( + f: &Function, + domtree: &DominatorTree, + ctrl_plane: &mut ControlPlane, + ) -> BlockLoweringOrder { + trace!("BlockLoweringOrder: function body {:?}", f); + + // Step 1: compute the in-edge and out-edge count of every block. + let mut block_in_count = SecondaryMap::with_default(0); + let mut block_out_count = SecondaryMap::with_default(0); + + // Block successors are stored as `LoweredBlocks` to simplify the construction of + // `lowered_succs` in the final result. Initially, all entries are `Orig` values, and are + // updated to be `CriticalEdge` when those cases are identified in step 2 below. + let mut block_succs: SmallVec<[LoweredBlock; 128]> = SmallVec::new(); + let mut block_succ_range = SecondaryMap::with_default(0..0); + + let mut indirect_branch_target_clif_blocks = FxHashSet::default(); + + for block in f.layout.blocks() { + let start = block_succs.len(); + visit_block_succs(f, block, |_, succ, from_table| { + block_out_count[block] += 1; + block_in_count[succ] += 1; + block_succs.push(LoweredBlock::Orig { block: succ }); + + if from_table { + indirect_branch_target_clif_blocks.insert(succ); + } + }); + + // Ensure that blocks terminated by br_table instructions with an empty jump table are + // still treated like conditional blocks from the point of view of critical edge + // splitting. + if let Some(inst) = f.layout.last_inst(block) { + if Opcode::BrTable == f.dfg.insts[inst].opcode() { + block_out_count[block] = block_out_count[block].max(2); + } + } + + let end = block_succs.len(); + block_succ_range[block] = start..end; + } + + // Step 2: walk the postorder from the domtree in reverse to produce our desired node + // lowering order, identifying critical edges to split along the way. + + let mut lowered_order = Vec::new(); + + for &block in domtree.cfg_rpo() { + lowered_order.push(LoweredBlock::Orig { block }); + + if block_out_count[block] > 1 { + let range = block_succ_range[block].clone(); + + // If chaos-mode is enabled in the control plane, iterate over + // the successors in an arbitrary order, which should have no + // impact on correctness. The order of the blocks is generally + // relevant: Uses must be seen before defs for dead-code + // elimination. + let succs = ctrl_plane.shuffled(block_succs[range].iter_mut().enumerate()); + + for (succ_ix, lb) in succs { + let succ = lb.orig_block().unwrap(); + if block_in_count[succ] > 1 { + // Mutate the successor to be a critical edge, as `block` has multiple + // edges leaving it, and `succ` has multiple edges entering it. + *lb = LoweredBlock::CriticalEdge { + pred: block, + succ, + succ_idx: succ_ix as u32, + }; + lowered_order.push(*lb); + } + } + } + } + + let lb_to_bindex = FxHashMap::from_iter( + lowered_order + .iter() + .enumerate() + .map(|(i, &lb)| (lb, BlockIndex::new(i))), + ); + + // Step 3: build the successor tables given the lowering order. We can't perform this step + // during the creation of `lowering_order`, as we need `lb_to_bindex` to be fully populated + // first. + let mut lowered_succ_indices = Vec::new(); + let mut cold_blocks = FxHashSet::default(); + let mut indirect_branch_targets = FxHashSet::default(); + let lowered_succ_ranges = + Vec::from_iter(lowered_order.iter().enumerate().map(|(ix, lb)| { + let bindex = BlockIndex::new(ix); + let start = lowered_succ_indices.len(); + let opt_inst = match lb { + // Block successors are pulled directly over, as they'll have been mutated when + // determining the block order already. + &LoweredBlock::Orig { block } => { + let range = block_succ_range[block].clone(); + lowered_succ_indices + .extend(block_succs[range].iter().map(|lb| lb_to_bindex[lb])); + + if f.layout.is_cold(block) { + cold_blocks.insert(bindex); + } + + if indirect_branch_target_clif_blocks.contains(&block) { + indirect_branch_targets.insert(bindex); + } + + let last = f.layout.last_inst(block).unwrap(); + let opcode = f.dfg.insts[last].opcode(); + + assert!(opcode.is_terminator()); + + opcode.is_branch().then_some(last) + } + + // Critical edges won't have successor information in block_succ_range, but + // they only have a single known successor to record anyway. + &LoweredBlock::CriticalEdge { succ, .. } => { + let succ_index = lb_to_bindex[&LoweredBlock::Orig { block: succ }]; + lowered_succ_indices.push(succ_index); + + // Edges inherit indirect branch and cold block metadata from their + // successor. + + if f.layout.is_cold(succ) { + cold_blocks.insert(bindex); + } + + if indirect_branch_target_clif_blocks.contains(&succ) { + indirect_branch_targets.insert(bindex); + } + + None + } + }; + let end = lowered_succ_indices.len(); + (opt_inst, start..end) + })); + + let result = BlockLoweringOrder { + lowered_order, + lowered_succ_indices, + lowered_succ_ranges, + cold_blocks, + indirect_branch_targets, + }; + + trace!("BlockLoweringOrder: {:#?}", result); + result + } + + /// Get the lowered order of blocks. + pub fn lowered_order(&self) -> &[LoweredBlock] { + &self.lowered_order[..] + } + + /// Get the successor indices for a lowered block. + pub fn succ_indices(&self, block: BlockIndex) -> (Option, &[BlockIndex]) { + let (opt_inst, range) = &self.lowered_succ_ranges[block.index()]; + (*opt_inst, &self.lowered_succ_indices[range.clone()]) + } + + /// Determine whether the given lowered-block index is cold. + pub fn is_cold(&self, block: BlockIndex) -> bool { + self.cold_blocks.contains(&block) + } + + /// Determine whether the given lowered block index is an indirect branch + /// target. + pub fn is_indirect_branch_target(&self, block: BlockIndex) -> bool { + self.indirect_branch_targets.contains(&block) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::cursor::{Cursor, FuncCursor}; + use crate::flowgraph::ControlFlowGraph; + use crate::ir::types::*; + use crate::ir::UserFuncName; + use crate::ir::{AbiParam, InstBuilder, Signature}; + use crate::isa::CallConv; + + fn build_test_func(n_blocks: usize, edges: &[(usize, usize)]) -> BlockLoweringOrder { + assert!(n_blocks > 0); + + let name = UserFuncName::testcase("test0"); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(I32)); + let mut func = Function::with_name_signature(name, sig); + let blocks = (0..n_blocks) + .map(|i| { + let bb = func.dfg.make_block(); + assert!(bb.as_u32() == i as u32); + bb + }) + .collect::>(); + + let arg0 = func.dfg.append_block_param(blocks[0], I32); + + let mut pos = FuncCursor::new(&mut func); + + let mut edge = 0; + for i in 0..n_blocks { + pos.insert_block(blocks[i]); + let mut succs = vec![]; + while edge < edges.len() && edges[edge].0 == i { + succs.push(edges[edge].1); + edge += 1; + } + if succs.len() == 0 { + pos.ins().return_(&[arg0]); + } else if succs.len() == 1 { + pos.ins().jump(blocks[succs[0]], &[]); + } else if succs.len() == 2 { + pos.ins() + .brif(arg0, blocks[succs[0]], &[], blocks[succs[1]], &[]); + } else { + panic!("Too many successors"); + } + } + + let mut cfg = ControlFlowGraph::new(); + cfg.compute(&func); + let dom_tree = DominatorTree::with_function(&func, &cfg); + + BlockLoweringOrder::new(&func, &dom_tree, &mut Default::default()) + } + + #[test] + fn test_blockorder_diamond() { + let order = build_test_func(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + + // This test case doesn't need to introduce any critical edges, as all regalloc allocations + // can sit on either the entry or exit of blocks 1 and 2. + assert_eq!(order.lowered_order.len(), 4); + } + + #[test] + fn test_blockorder_critedge() { + // 0 + // / \ + // 1 2 + // / \ \ + // 3 4 | + // |\ _|____| + // | \/ | + // | /\ | + // 5 6 + // + // (3 -> 5, and 3 -> 6 are critical edges and must be split) + // + let order = build_test_func( + 7, + &[ + (0, 1), + (0, 2), + (1, 3), + (1, 4), + (2, 5), + (3, 5), + (3, 6), + (4, 6), + ], + ); + + assert_eq!(order.lowered_order.len(), 9); + println!("ordered = {:?}", order.lowered_order); + + // block 0 + assert_eq!(order.lowered_order[0].orig_block().unwrap().as_u32(), 0); + assert!(order.lowered_order[0].in_edge().is_none()); + assert!(order.lowered_order[0].out_edge().is_none()); + + // block 2 + assert_eq!(order.lowered_order[1].orig_block().unwrap().as_u32(), 2); + assert!(order.lowered_order[1].in_edge().is_none()); + assert!(order.lowered_order[1].out_edge().is_none()); + + // block 1 + assert_eq!(order.lowered_order[2].orig_block().unwrap().as_u32(), 1); + assert!(order.lowered_order[2].in_edge().is_none()); + assert!(order.lowered_order[2].out_edge().is_none()); + + // block 4 + assert_eq!(order.lowered_order[3].orig_block().unwrap().as_u32(), 4); + assert!(order.lowered_order[3].in_edge().is_none()); + assert!(order.lowered_order[3].out_edge().is_none()); + + // block 3 + assert_eq!(order.lowered_order[4].orig_block().unwrap().as_u32(), 3); + assert!(order.lowered_order[4].in_edge().is_none()); + assert!(order.lowered_order[4].out_edge().is_none()); + + // critical edge 3 -> 5 + assert!(order.lowered_order[5].orig_block().is_none()); + assert_eq!(order.lowered_order[5].in_edge().unwrap().as_u32(), 3); + assert_eq!(order.lowered_order[5].out_edge().unwrap().as_u32(), 5); + + // critical edge 3 -> 6 + assert!(order.lowered_order[6].orig_block().is_none()); + assert_eq!(order.lowered_order[6].in_edge().unwrap().as_u32(), 3); + assert_eq!(order.lowered_order[6].out_edge().unwrap().as_u32(), 6); + + // block 6 + assert_eq!(order.lowered_order[7].orig_block().unwrap().as_u32(), 6); + assert!(order.lowered_order[7].in_edge().is_none()); + assert!(order.lowered_order[7].out_edge().is_none()); + + // block 5 + assert_eq!(order.lowered_order[8].orig_block().unwrap().as_u32(), 5); + assert!(order.lowered_order[8].in_edge().is_none()); + assert!(order.lowered_order[8].out_edge().is_none()); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/buffer.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/buffer.rs new file mode 100644 index 00000000000000..518b4cdbe389a7 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/buffer.rs @@ -0,0 +1,2496 @@ +//! In-memory representation of compiled machine code, with labels and fixups to +//! refer to those labels. Handles constant-pool island insertion and also +//! veneer insertion for out-of-range jumps. +//! +//! This code exists to solve three problems: +//! +//! - Branch targets for forward branches are not known until later, when we +//! emit code in a single pass through the instruction structs. +//! +//! - On many architectures, address references or offsets have limited range. +//! For example, on AArch64, conditional branches can only target code +/- 1MB +//! from the branch itself. +//! +//! - The lowering of control flow from the CFG-with-edges produced by +//! [BlockLoweringOrder](super::BlockLoweringOrder), combined with many empty +//! edge blocks when the register allocator does not need to insert any +//! spills/reloads/moves in edge blocks, results in many suboptimal branch +//! patterns. The lowering also pays no attention to block order, and so +//! two-target conditional forms (cond-br followed by uncond-br) can often by +//! avoided because one of the targets is the fallthrough. There are several +//! cases here where we can simplify to use fewer branches. +//! +//! This "buffer" implements a single-pass code emission strategy (with a later +//! "fixup" pass, but only through recorded fixups, not all instructions). The +//! basic idea is: +//! +//! - Emit branches as they are, including two-target (cond/uncond) compound +//! forms, but with zero offsets and optimistically assuming the target will be +//! in range. Record the "fixup" for later. Targets are denoted instead by +//! symbolic "labels" that are then bound to certain offsets in the buffer as +//! we emit code. (Nominally, there is a label at the start of every basic +//! block.) +//! +//! - As we do this, track the offset in the buffer at which the first label +//! reference "goes out of range". We call this the "deadline". If we reach the +//! deadline and we still have not bound the label to which an unresolved branch +//! refers, we have a problem! +//! +//! - To solve this problem, we emit "islands" full of "veneers". An island is +//! simply a chunk of code inserted in the middle of the code actually produced +//! by the emitter (e.g., vcode iterating over instruction structs). The emitter +//! has some awareness of this: it either asks for an island between blocks, so +//! it is not accidentally executed, or else it emits a branch around the island +//! when all other options fail (see `Inst::EmitIsland` meta-instruction). +//! +//! - A "veneer" is an instruction (or sequence of instructions) in an "island" +//! that implements a longer-range reference to a label. The idea is that, for +//! example, a branch with a limited range can branch to a "veneer" instead, +//! which is simply a branch in a form that can use a longer-range reference. On +//! AArch64, for example, conditionals have a +/- 1 MB range, but a conditional +//! can branch to an unconditional branch which has a +/- 128 MB range. Hence, a +//! conditional branch's label reference can be fixed up with a "veneer" to +//! achieve a longer range. +//! +//! - To implement all of this, we require the backend to provide a `LabelUse` +//! type that implements a trait. This is nominally an enum that records one of +//! several kinds of references to an offset in code -- basically, a relocation +//! type -- and will usually correspond to different instruction formats. The +//! `LabelUse` implementation specifies the maximum range, how to patch in the +//! actual label location when known, and how to generate a veneer to extend the +//! range. +//! +//! That satisfies label references, but we still may have suboptimal branch +//! patterns. To clean up the branches, we do a simple "peephole"-style +//! optimization on the fly. To do so, the emitter (e.g., `Inst::emit()`) +//! informs the buffer of branches in the code and, in the case of conditionals, +//! the code that would have been emitted to invert this branch's condition. We +//! track the "latest branches": these are branches that are contiguous up to +//! the current offset. (If any code is emitted after a branch, that branch or +//! run of contiguous branches is no longer "latest".) The latest branches are +//! those that we can edit by simply truncating the buffer and doing something +//! else instead. +//! +//! To optimize branches, we implement several simple rules, and try to apply +//! them to the "latest branches" when possible: +//! +//! - A branch with a label target, when that label is bound to the ending +//! offset of the branch (the fallthrough location), can be removed altogether, +//! because the branch would have no effect). +//! +//! - An unconditional branch that starts at a label location, and branches to +//! another label, results in a "label alias": all references to the label bound +//! *to* this branch instruction are instead resolved to the *target* of the +//! branch instruction. This effectively removes empty blocks that just +//! unconditionally branch to the next block. We call this "branch threading". +//! +//! - A conditional followed by an unconditional, when the conditional branches +//! to the unconditional's fallthrough, results in (i) the truncation of the +//! unconditional, (ii) the inversion of the condition's condition, and (iii) +//! replacement of the conditional's target (using the original target of the +//! unconditional). This is a fancy way of saying "we can flip a two-target +//! conditional branch's taken/not-taken targets if it works better with our +//! fallthrough". To make this work, the emitter actually gives the buffer +//! *both* forms of every conditional branch: the true form is emitted into the +//! buffer, and the "inverted" machine-code bytes are provided as part of the +//! branch-fixup metadata. +//! +//! - An unconditional B preceded by another unconditional P, when B's label(s) have +//! been redirected to target(B), can be removed entirely. This is an extension +//! of the branch-threading optimization, and is valid because if we know there +//! will be no fallthrough into this branch instruction (the prior instruction +//! is an unconditional jump), and if we know we have successfully redirected +//! all labels, then this branch instruction is unreachable. Note that this +//! works because the redirection happens before the label is ever resolved +//! (fixups happen at island emission time, at which point latest-branches are +//! cleared, or at the end of emission), so we are sure to catch and redirect +//! all possible paths to this instruction. +//! +//! # Branch-optimization Correctness +//! +//! The branch-optimization mechanism depends on a few data structures with +//! invariants, which are always held outside the scope of top-level public +//! methods: +//! +//! - The latest-branches list. Each entry describes a span of the buffer +//! (start/end offsets), the label target, the corresponding fixup-list entry +//! index, and the bytes (must be the same length) for the inverted form, if +//! conditional. The list of labels that are bound to the start-offset of this +//! branch is *complete* (if any label has a resolved offset equal to `start` +//! and is not an alias, it must appear in this list) and *precise* (no label +//! in this list can be bound to another offset). No label in this list should +//! be an alias. No two branch ranges can overlap, and branches are in +//! ascending-offset order. +//! +//! - The labels-at-tail list. This contains all MachLabels that have been bound +//! to (whose resolved offsets are equal to) the tail offset of the buffer. +//! No label in this list should be an alias. +//! +//! - The label_offsets array, containing the bound offset of a label or +//! UNKNOWN. No label can be bound at an offset greater than the current +//! buffer tail. +//! +//! - The label_aliases array, containing another label to which a label is +//! bound or UNKNOWN. A label's resolved offset is the resolved offset +//! of the label it is aliased to, if this is set. +//! +//! We argue below, at each method, how the invariants in these data structures +//! are maintained (grep for "Post-invariant"). +//! +//! Given these invariants, we argue why each optimization preserves execution +//! semantics below (grep for "Preserves execution semantics"). +//! +//! # Avoiding Quadratic Behavior +//! +//! There are two cases where we've had to take some care to avoid +//! quadratic worst-case behavior: +//! +//! - The "labels at this branch" list can grow unboundedly if the +//! code generator binds many labels at one location. If the count +//! gets too high (defined by the `LABEL_LIST_THRESHOLD` constant), we +//! simply abort an optimization early in a way that is always correct +//! but is conservative. +//! +//! - The fixup list can interact with island emission to create +//! "quadratic island behavior". In a little more detail, one can hit +//! this behavior by having some pending fixups (forward label +//! references) with long-range label-use kinds, and some others +//! with shorter-range references that nonetheless still are pending +//! long enough to trigger island generation. In such a case, we +//! process the fixup list, generate veneers to extend some forward +//! references' ranges, but leave the other (longer-range) ones +//! alone. The way this was implemented put them back on a list and +//! resulted in quadratic behavior. +//! +//! To avoid this fixups are split into two lists: one "pending" list and one +//! final list. The pending list is kept around for handling fixups related to +//! branches so it can be edited/truncated. When an island is reached, which +//! starts processing fixups, all pending fixups are flushed into the final +//! list. The final list is a `BinaryHeap` which enables fixup processing to +//! only process those which are required during island emission, deferring +//! all longer-range fixups to later. + +use crate::binemit::{Addend, CodeOffset, Reloc}; +use crate::ir::function::FunctionParameters; +use crate::ir::{ExternalName, RelSourceLoc, SourceLoc, TrapCode}; +use crate::isa::unwind::UnwindInst; +use crate::machinst::{ + BlockIndex, MachInstLabelUse, TextSectionBuilder, VCodeConstant, VCodeConstants, VCodeInst, +}; +use crate::trace; +use crate::{ir, MachInstEmitState}; +use crate::{timing, VCodeConstantData}; +use cranelift_control::ControlPlane; +use cranelift_entity::{entity_impl, PrimaryMap}; +use smallvec::SmallVec; +use std::cmp::Ordering; +use std::collections::BinaryHeap; +use std::mem; +use std::string::String; +use std::vec::Vec; + +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "enable-serde")] +pub trait CompilePhase { + type MachSrcLocType: for<'a> Deserialize<'a> + Serialize + core::fmt::Debug + PartialEq + Clone; + type SourceLocType: for<'a> Deserialize<'a> + Serialize + core::fmt::Debug + PartialEq + Clone; +} + +#[cfg(not(feature = "enable-serde"))] +pub trait CompilePhase { + type MachSrcLocType: core::fmt::Debug + PartialEq + Clone; + type SourceLocType: core::fmt::Debug + PartialEq + Clone; +} + +/// Status of a compiled artifact that needs patching before being used. +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Stencil; + +/// Status of a compiled artifact ready to use. +#[derive(Clone, Debug, PartialEq)] +pub struct Final; + +impl CompilePhase for Stencil { + type MachSrcLocType = MachSrcLoc; + type SourceLocType = RelSourceLoc; +} + +impl CompilePhase for Final { + type MachSrcLocType = MachSrcLoc; + type SourceLocType = SourceLoc; +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ForceVeneers { + Yes, + No, +} + +/// A buffer of output to be produced, fixed up, and then emitted to a CodeSink +/// in bulk. +/// +/// This struct uses `SmallVec`s to support small-ish function bodies without +/// any heap allocation. As such, it will be several kilobytes large. This is +/// likely fine as long as it is stack-allocated for function emission then +/// thrown away; but beware if many buffer objects are retained persistently. +pub struct MachBuffer { + /// The buffer contents, as raw bytes. + data: SmallVec<[u8; 1024]>, + /// Any relocations referring to this code. Note that only *external* + /// relocations are tracked here; references to labels within the buffer are + /// resolved before emission. + relocs: SmallVec<[MachReloc; 16]>, + /// Any trap records referring to this code. + traps: SmallVec<[MachTrap; 16]>, + /// Any call site records referring to this code. + call_sites: SmallVec<[MachCallSite; 16]>, + /// Any source location mappings referring to this code. + srclocs: SmallVec<[MachSrcLoc; 64]>, + /// Any user stack maps for this code. + /// + /// Each entry is an `(offset, span, stack_map)` triple. Entries are sorted + /// by code offset, and each stack map covers `span` bytes on the stack. + user_stack_maps: SmallVec<[(CodeOffset, u32, ir::UserStackMap); 8]>, + /// Any unwind info at a given location. + unwind_info: SmallVec<[(CodeOffset, UnwindInst); 8]>, + /// The current source location in progress (after `start_srcloc()` and + /// before `end_srcloc()`). This is a (start_offset, src_loc) tuple. + cur_srcloc: Option<(CodeOffset, RelSourceLoc)>, + /// Known label offsets; `UNKNOWN_LABEL_OFFSET` if unknown. + label_offsets: SmallVec<[CodeOffset; 16]>, + /// Label aliases: when one label points to an unconditional jump, and that + /// jump points to another label, we can redirect references to the first + /// label immediately to the second. + /// + /// Invariant: we don't have label-alias cycles. We ensure this by, + /// before setting label A to alias label B, resolving B's alias + /// target (iteratively until a non-aliased label); if B is already + /// aliased to A, then we cannot alias A back to B. + label_aliases: SmallVec<[MachLabel; 16]>, + /// Constants that must be emitted at some point. + pending_constants: SmallVec<[VCodeConstant; 16]>, + /// Byte size of all constants in `pending_constants`. + pending_constants_size: CodeOffset, + /// Traps that must be emitted at some point. + pending_traps: SmallVec<[MachLabelTrap; 16]>, + /// Fixups that haven't yet been flushed into `fixup_records` below and may + /// be related to branches that are chomped. These all get added to + /// `fixup_records` during island emission. + pending_fixup_records: SmallVec<[MachLabelFixup; 16]>, + /// The nearest upcoming deadline for entries in `pending_fixup_records`. + pending_fixup_deadline: CodeOffset, + /// Fixups that must be performed after all code is emitted. + fixup_records: BinaryHeap>, + /// Latest branches, to facilitate in-place editing for better fallthrough + /// behavior and empty-block removal. + latest_branches: SmallVec<[MachBranch; 4]>, + /// All labels at the current offset (emission tail). This is lazily + /// cleared: it is actually accurate as long as the current offset is + /// `labels_at_tail_off`, but if `cur_offset()` has grown larger, it should + /// be considered as empty. + /// + /// For correctness, this *must* be complete (i.e., the vector must contain + /// all labels whose offsets are resolved to the current tail), because we + /// rely on it to update labels when we truncate branches. + labels_at_tail: SmallVec<[MachLabel; 4]>, + /// The last offset at which `labels_at_tail` is valid. It is conceptually + /// always describing the tail of the buffer, but we do not clear + /// `labels_at_tail` eagerly when the tail grows, rather we lazily clear it + /// when the offset has grown past this (`labels_at_tail_off`) point. + /// Always <= `cur_offset()`. + labels_at_tail_off: CodeOffset, + /// Metadata about all constants that this function has access to. + /// + /// This records the size/alignment of all constants (not the actual data) + /// along with the last available label generated for the constant. This map + /// is consulted when constants are referred to and the label assigned to a + /// constant may change over time as well. + constants: PrimaryMap, + /// All recorded usages of constants as pairs of the constant and where the + /// constant needs to be placed within `self.data`. Note that the same + /// constant may appear in this array multiple times if it was emitted + /// multiple times. + used_constants: SmallVec<[(VCodeConstant, CodeOffset); 4]>, + /// Indicates when a patchable region is currently open, to guard that it's + /// not possible to nest patchable regions. + open_patchable: bool, +} + +impl MachBufferFinalized { + /// Get a finalized machine buffer by applying the function's base source location. + pub fn apply_base_srcloc(self, base_srcloc: SourceLoc) -> MachBufferFinalized { + MachBufferFinalized { + data: self.data, + relocs: self.relocs, + traps: self.traps, + call_sites: self.call_sites, + srclocs: self + .srclocs + .into_iter() + .map(|srcloc| srcloc.apply_base_srcloc(base_srcloc)) + .collect(), + user_stack_maps: self.user_stack_maps, + unwind_info: self.unwind_info, + alignment: self.alignment, + } + } +} + +/// A `MachBuffer` once emission is completed: holds generated code and records, +/// without fixups. This allows the type to be independent of the backend. +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct MachBufferFinalized { + /// The buffer contents, as raw bytes. + pub(crate) data: SmallVec<[u8; 1024]>, + /// Any relocations referring to this code. Note that only *external* + /// relocations are tracked here; references to labels within the buffer are + /// resolved before emission. + pub(crate) relocs: SmallVec<[FinalizedMachReloc; 16]>, + /// Any trap records referring to this code. + pub(crate) traps: SmallVec<[MachTrap; 16]>, + /// Any call site records referring to this code. + pub(crate) call_sites: SmallVec<[MachCallSite; 16]>, + /// Any source location mappings referring to this code. + pub(crate) srclocs: SmallVec<[T::MachSrcLocType; 64]>, + /// Any user stack maps for this code. + /// + /// Each entry is an `(offset, span, stack_map)` triple. Entries are sorted + /// by code offset, and each stack map covers `span` bytes on the stack. + pub(crate) user_stack_maps: SmallVec<[(CodeOffset, u32, ir::UserStackMap); 8]>, + /// Any unwind info at a given location. + pub unwind_info: SmallVec<[(CodeOffset, UnwindInst); 8]>, + /// The required alignment of this buffer. + pub alignment: u32, +} + +const UNKNOWN_LABEL_OFFSET: CodeOffset = 0xffff_ffff; +const UNKNOWN_LABEL: MachLabel = MachLabel(0xffff_ffff); + +/// Threshold on max length of `labels_at_this_branch` list to avoid +/// unbounded quadratic behavior (see comment below at use-site). +const LABEL_LIST_THRESHOLD: usize = 100; + +/// A label refers to some offset in a `MachBuffer`. It may not be resolved at +/// the point at which it is used by emitted code; the buffer records "fixups" +/// for references to the label, and will come back and patch the code +/// appropriately when the label's location is eventually known. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MachLabel(u32); +entity_impl!(MachLabel); + +impl MachLabel { + /// Get a label for a block. (The first N MachLabels are always reserved for + /// the N blocks in the vcode.) + pub fn from_block(bindex: BlockIndex) -> MachLabel { + MachLabel(bindex.index() as u32) + } + + /// Get the numeric label index. + pub fn get(self) -> u32 { + self.0 + } + + /// Creates a string representing this label, for convenience. + pub fn to_string(&self) -> String { + format!("label{}", self.0) + } +} + +impl Default for MachLabel { + fn default() -> Self { + UNKNOWN_LABEL + } +} + +/// Represents the beginning of an editable region in the [`MachBuffer`], while code emission is +/// still occurring. An [`OpenPatchRegion`] is closed by [`MachBuffer::end_patchable`], consuming +/// the [`OpenPatchRegion`] token in the process. +pub struct OpenPatchRegion(usize); + +/// A region in the [`MachBuffer`] code buffer that can be edited prior to finalization. An example +/// of where you might want to use this is for patching instructions that mention constants that +/// won't be known until later: [`MachBuffer::start_patchable`] can be used to begin the patchable +/// region, instructions can be emitted with placeholder constants, and the [`PatchRegion`] token +/// can be produced by [`MachBuffer::end_patchable`]. Once the values of those constants are known, +/// the [`PatchRegion::patch`] function can be used to get a mutable buffer to the instruction +/// bytes, and the constants uses can be updated directly. +pub struct PatchRegion { + range: std::ops::Range, +} + +impl PatchRegion { + /// Consume the patch region to yield a mutable slice of the [`MachBuffer`] data buffer. + pub fn patch(self, buffer: &mut MachBuffer) -> &mut [u8] { + &mut buffer.data[self.range] + } +} + +impl MachBuffer { + /// Create a new section, known to start at `start_offset` and with a size limited to + /// `length_limit`. + pub fn new() -> MachBuffer { + MachBuffer { + data: SmallVec::new(), + relocs: SmallVec::new(), + traps: SmallVec::new(), + call_sites: SmallVec::new(), + srclocs: SmallVec::new(), + user_stack_maps: SmallVec::new(), + unwind_info: SmallVec::new(), + cur_srcloc: None, + label_offsets: SmallVec::new(), + label_aliases: SmallVec::new(), + pending_constants: SmallVec::new(), + pending_constants_size: 0, + pending_traps: SmallVec::new(), + pending_fixup_records: SmallVec::new(), + pending_fixup_deadline: u32::MAX, + fixup_records: Default::default(), + latest_branches: SmallVec::new(), + labels_at_tail: SmallVec::new(), + labels_at_tail_off: 0, + constants: Default::default(), + used_constants: Default::default(), + open_patchable: false, + } + } + + /// Current offset from start of buffer. + pub fn cur_offset(&self) -> CodeOffset { + self.data.len() as CodeOffset + } + + /// Add a byte. + pub fn put1(&mut self, value: u8) { + self.data.push(value); + + // Post-invariant: conceptual-labels_at_tail contains a complete and + // precise list of labels bound at `cur_offset()`. We have advanced + // `cur_offset()`, hence if it had been equal to `labels_at_tail_off` + // before, it is not anymore (and it cannot become equal, because + // `labels_at_tail_off` is always <= `cur_offset()`). Thus the list is + // conceptually empty (even though it is only lazily cleared). No labels + // can be bound at this new offset (by invariant on `label_offsets`). + // Hence the invariant holds. + } + + /// Add 2 bytes. + pub fn put2(&mut self, value: u16) { + let bytes = value.to_le_bytes(); + self.data.extend_from_slice(&bytes[..]); + + // Post-invariant: as for `put1()`. + } + + /// Add 4 bytes. + pub fn put4(&mut self, value: u32) { + let bytes = value.to_le_bytes(); + self.data.extend_from_slice(&bytes[..]); + + // Post-invariant: as for `put1()`. + } + + /// Add 8 bytes. + pub fn put8(&mut self, value: u64) { + let bytes = value.to_le_bytes(); + self.data.extend_from_slice(&bytes[..]); + + // Post-invariant: as for `put1()`. + } + + /// Add a slice of bytes. + pub fn put_data(&mut self, data: &[u8]) { + self.data.extend_from_slice(data); + + // Post-invariant: as for `put1()`. + } + + /// Reserve appended space and return a mutable slice referring to it. + pub fn get_appended_space(&mut self, len: usize) -> &mut [u8] { + let off = self.data.len(); + let new_len = self.data.len() + len; + self.data.resize(new_len, 0); + &mut self.data[off..] + + // Post-invariant: as for `put1()`. + } + + /// Align up to the given alignment. + pub fn align_to(&mut self, align_to: CodeOffset) { + trace!("MachBuffer: align to {}", align_to); + assert!( + align_to.is_power_of_two(), + "{align_to} is not a power of two" + ); + while self.cur_offset() & (align_to - 1) != 0 { + self.put1(0); + } + + // Post-invariant: as for `put1()`. + } + + /// Begin a region of patchable code. There is one requirement for the + /// code that is emitted: It must not introduce any instructions that + /// could be chomped (branches are an example of this). In other words, + /// you must not call [`MachBuffer::add_cond_branch`] or + /// [`MachBuffer::add_uncond_branch`] between calls to this method and + /// [`MachBuffer::end_patchable`]. + pub fn start_patchable(&mut self) -> OpenPatchRegion { + assert!(!self.open_patchable, "Patchable regions may not be nested"); + self.open_patchable = true; + OpenPatchRegion(usize::try_from(self.cur_offset()).unwrap()) + } + + /// End a region of patchable code, yielding a [`PatchRegion`] value that + /// can be consumed later to produce a one-off mutable slice to the + /// associated region of the data buffer. + pub fn end_patchable(&mut self, open: OpenPatchRegion) -> PatchRegion { + // No need to assert the state of `open_patchable` here, as we take + // ownership of the only `OpenPatchable` value. + self.open_patchable = false; + let end = usize::try_from(self.cur_offset()).unwrap(); + PatchRegion { range: open.0..end } + } + + /// Allocate a `Label` to refer to some offset. May not be bound to a fixed + /// offset yet. + pub fn get_label(&mut self) -> MachLabel { + let l = self.label_offsets.len() as u32; + self.label_offsets.push(UNKNOWN_LABEL_OFFSET); + self.label_aliases.push(UNKNOWN_LABEL); + trace!("MachBuffer: new label -> {:?}", MachLabel(l)); + MachLabel(l) + + // Post-invariant: the only mutation is to add a new label; it has no + // bound offset yet, so it trivially satisfies all invariants. + } + + /// Reserve the first N MachLabels for blocks. + pub fn reserve_labels_for_blocks(&mut self, blocks: usize) { + trace!("MachBuffer: first {} labels are for blocks", blocks); + debug_assert!(self.label_offsets.is_empty()); + self.label_offsets.resize(blocks, UNKNOWN_LABEL_OFFSET); + self.label_aliases.resize(blocks, UNKNOWN_LABEL); + + // Post-invariant: as for `get_label()`. + } + + /// Registers metadata in this `MachBuffer` about the `constants` provided. + /// + /// This will record the size/alignment of all constants which will prepare + /// them for emission later on. + pub fn register_constants(&mut self, constants: &VCodeConstants) { + for (c, val) in constants.iter() { + self.register_constant(&c, val); + } + } + + /// Similar to [`MachBuffer::register_constants`] but registers a + /// single constant metadata. This function is useful in + /// situations where not all constants are known at the time of + /// emission. + pub fn register_constant(&mut self, constant: &VCodeConstant, data: &VCodeConstantData) { + let c2 = self.constants.push(MachBufferConstant { + upcoming_label: None, + align: data.alignment(), + size: data.as_slice().len(), + }); + assert_eq!(*constant, c2); + } + + /// Completes constant emission by iterating over `self.used_constants` and + /// filling in the "holes" with the constant values provided by `constants`. + /// + /// Returns the alignment required for this entire buffer. Alignment starts + /// at the ISA's minimum function alignment and can be increased due to + /// constant requirements. + fn finish_constants(&mut self, constants: &VCodeConstants) -> u32 { + let mut alignment = I::function_alignment().minimum; + for (constant, offset) in mem::take(&mut self.used_constants) { + let constant = constants.get(constant); + let data = constant.as_slice(); + self.data[offset as usize..][..data.len()].copy_from_slice(data); + alignment = constant.alignment().max(alignment); + } + alignment + } + + /// Returns a label that can be used to refer to the `constant` provided. + /// + /// This will automatically defer a new constant to be emitted for + /// `constant` if it has not been previously emitted. Note that this + /// function may return a different label for the same constant at + /// different points in time. The label is valid to use only from the + /// current location; the MachBuffer takes care to emit the same constant + /// multiple times if needed so the constant is always in range. + pub fn get_label_for_constant(&mut self, constant: VCodeConstant) -> MachLabel { + let MachBufferConstant { + align, + size, + upcoming_label, + } = self.constants[constant]; + if let Some(label) = upcoming_label { + return label; + } + + let label = self.get_label(); + trace!( + "defer constant: eventually emit {size} bytes aligned \ + to {align} at label {label:?}", + ); + self.pending_constants.push(constant); + self.pending_constants_size += size as u32; + self.constants[constant].upcoming_label = Some(label); + label + } + + /// Bind a label to the current offset. A label can only be bound once. + pub fn bind_label(&mut self, label: MachLabel, ctrl_plane: &mut ControlPlane) { + trace!( + "MachBuffer: bind label {:?} at offset {}", + label, + self.cur_offset() + ); + debug_assert_eq!(self.label_offsets[label.0 as usize], UNKNOWN_LABEL_OFFSET); + debug_assert_eq!(self.label_aliases[label.0 as usize], UNKNOWN_LABEL); + let offset = self.cur_offset(); + self.label_offsets[label.0 as usize] = offset; + self.lazily_clear_labels_at_tail(); + self.labels_at_tail.push(label); + + // Invariants hold: bound offset of label is <= cur_offset (in fact it + // is equal). If the `labels_at_tail` list was complete and precise + // before, it is still, because we have bound this label to the current + // offset and added it to the list (which contains all labels at the + // current offset). + + self.optimize_branches(ctrl_plane); + + // Post-invariant: by `optimize_branches()` (see argument there). + } + + /// Lazily clear `labels_at_tail` if the tail offset has moved beyond the + /// offset that it applies to. + fn lazily_clear_labels_at_tail(&mut self) { + let offset = self.cur_offset(); + if offset > self.labels_at_tail_off { + self.labels_at_tail_off = offset; + self.labels_at_tail.clear(); + } + + // Post-invariant: either labels_at_tail_off was at cur_offset, and + // state is untouched, or was less than cur_offset, in which case the + // labels_at_tail list was conceptually empty, and is now actually + // empty. + } + + /// Resolve a label to an offset, if known. May return `UNKNOWN_LABEL_OFFSET`. + pub(crate) fn resolve_label_offset(&self, mut label: MachLabel) -> CodeOffset { + let mut iters = 0; + while self.label_aliases[label.0 as usize] != UNKNOWN_LABEL { + label = self.label_aliases[label.0 as usize]; + // To protect against an infinite loop (despite our assurances to + // ourselves that the invariants make this impossible), assert out + // after 1M iterations. The number of basic blocks is limited + // in most contexts anyway so this should be impossible to hit with + // a legitimate input. + iters += 1; + assert!(iters < 1_000_000, "Unexpected cycle in label aliases"); + } + self.label_offsets[label.0 as usize] + + // Post-invariant: no mutations. + } + + /// Emit a reference to the given label with the given reference type (i.e., + /// branch-instruction format) at the current offset. This is like a + /// relocation, but handled internally. + /// + /// This can be called before the branch is actually emitted; fixups will + /// not happen until an island is emitted or the buffer is finished. + pub fn use_label_at_offset(&mut self, offset: CodeOffset, label: MachLabel, kind: I::LabelUse) { + trace!( + "MachBuffer: use_label_at_offset: offset {} label {:?} kind {:?}", + offset, + label, + kind + ); + + // Add the fixup, and update the worst-case island size based on a + // veneer for this label use. + let fixup = MachLabelFixup { + label, + offset, + kind, + }; + self.pending_fixup_deadline = self.pending_fixup_deadline.min(fixup.deadline()); + self.pending_fixup_records.push(fixup); + + // Post-invariant: no mutations to branches/labels data structures. + } + + /// Inform the buffer of an unconditional branch at the given offset, + /// targeting the given label. May be used to optimize branches. + /// The last added label-use must correspond to this branch. + /// This must be called when the current offset is equal to `start`; i.e., + /// before actually emitting the branch. This implies that for a branch that + /// uses a label and is eligible for optimizations by the MachBuffer, the + /// proper sequence is: + /// + /// - Call `use_label_at_offset()` to emit the fixup record. + /// - Call `add_uncond_branch()` to make note of the branch. + /// - Emit the bytes for the branch's machine code. + /// + /// Additional requirement: no labels may be bound between `start` and `end` + /// (exclusive on both ends). + pub fn add_uncond_branch(&mut self, start: CodeOffset, end: CodeOffset, target: MachLabel) { + debug_assert!( + !self.open_patchable, + "Branch instruction inserted within a patchable region" + ); + assert!(self.cur_offset() == start); + debug_assert!(end > start); + assert!(!self.pending_fixup_records.is_empty()); + let fixup = self.pending_fixup_records.len() - 1; + self.lazily_clear_labels_at_tail(); + self.latest_branches.push(MachBranch { + start, + end, + target, + fixup, + inverted: None, + labels_at_this_branch: self.labels_at_tail.clone(), + }); + + // Post-invariant: we asserted branch start is current tail; the list of + // labels at branch is cloned from list of labels at current tail. + } + + /// Inform the buffer of a conditional branch at the given offset, + /// targeting the given label. May be used to optimize branches. + /// The last added label-use must correspond to this branch. + /// + /// Additional requirement: no labels may be bound between `start` and `end` + /// (exclusive on both ends). + pub fn add_cond_branch( + &mut self, + start: CodeOffset, + end: CodeOffset, + target: MachLabel, + inverted: &[u8], + ) { + debug_assert!( + !self.open_patchable, + "Branch instruction inserted within a patchable region" + ); + assert!(self.cur_offset() == start); + debug_assert!(end > start); + assert!(!self.pending_fixup_records.is_empty()); + debug_assert!( + inverted.len() == (end - start) as usize, + "branch length = {}, but inverted length = {}", + end - start, + inverted.len() + ); + let fixup = self.pending_fixup_records.len() - 1; + let inverted = Some(SmallVec::from(inverted)); + self.lazily_clear_labels_at_tail(); + self.latest_branches.push(MachBranch { + start, + end, + target, + fixup, + inverted, + labels_at_this_branch: self.labels_at_tail.clone(), + }); + + // Post-invariant: we asserted branch start is current tail; labels at + // branch list is cloned from list of labels at current tail. + } + + fn truncate_last_branch(&mut self) { + debug_assert!( + !self.open_patchable, + "Branch instruction truncated within a patchable region" + ); + + self.lazily_clear_labels_at_tail(); + // Invariants hold at this point. + + let b = self.latest_branches.pop().unwrap(); + assert!(b.end == self.cur_offset()); + + // State: + // [PRE CODE] + // Offset b.start, b.labels_at_this_branch: + // [BRANCH CODE] + // cur_off, self.labels_at_tail --> + // (end of buffer) + self.data.truncate(b.start as usize); + self.pending_fixup_records.truncate(b.fixup); + while let Some(last_srcloc) = self.srclocs.last_mut() { + if last_srcloc.end <= b.start { + break; + } + if last_srcloc.start < b.start { + last_srcloc.end = b.start; + break; + } + self.srclocs.pop(); + } + // State: + // [PRE CODE] + // cur_off, Offset b.start, b.labels_at_this_branch: + // (end of buffer) + // + // self.labels_at_tail --> (past end of buffer) + let cur_off = self.cur_offset(); + self.labels_at_tail_off = cur_off; + // State: + // [PRE CODE] + // cur_off, Offset b.start, b.labels_at_this_branch, + // self.labels_at_tail: + // (end of buffer) + // + // resolve_label_offset(l) for l in labels_at_tail: + // (past end of buffer) + + trace!( + "truncate_last_branch: truncated {:?}; off now {}", + b, + cur_off + ); + + // Fix up resolved label offsets for labels at tail. + for &l in &self.labels_at_tail { + self.label_offsets[l.0 as usize] = cur_off; + } + // Old labels_at_this_branch are now at cur_off. + self.labels_at_tail + .extend(b.labels_at_this_branch.into_iter()); + + // Post-invariant: this operation is defined to truncate the buffer, + // which moves cur_off backward, and to move labels at the end of the + // buffer back to the start-of-branch offset. + // + // latest_branches satisfies all invariants: + // - it has no branches past the end of the buffer (branches are in + // order, we removed the last one, and we truncated the buffer to just + // before the start of that branch) + // - no labels were moved to lower offsets than the (new) cur_off, so + // the labels_at_this_branch list for any other branch need not change. + // + // labels_at_tail satisfies all invariants: + // - all labels that were at the tail after the truncated branch are + // moved backward to just before the branch, which becomes the new tail; + // thus every element in the list should remain (ensured by `.extend()` + // above). + // - all labels that refer to the new tail, which is the start-offset of + // the truncated branch, must be present. The `labels_at_this_branch` + // list in the truncated branch's record is a complete and precise list + // of exactly these labels; we append these to labels_at_tail. + // - labels_at_tail_off is at cur_off after truncation occurs, so the + // list is valid (not to be lazily cleared). + // + // The stated operation was performed: + // - For each label at the end of the buffer prior to this method, it + // now resolves to the new (truncated) end of the buffer: it must have + // been in `labels_at_tail` (this list is precise and complete, and + // the tail was at the end of the truncated branch on entry), and we + // iterate over this list and set `label_offsets` to the new tail. + // None of these labels could have been an alias (by invariant), so + // `label_offsets` is authoritative for each. + // - No other labels will be past the end of the buffer, because of the + // requirement that no labels be bound to the middle of branch ranges + // (see comments to `add_{cond,uncond}_branch()`). + // - The buffer is truncated to just before the last branch, and the + // fixup record referring to that last branch is removed. + } + + /// Performs various optimizations on branches pointing at the current label. + pub fn optimize_branches(&mut self, ctrl_plane: &mut ControlPlane) { + if ctrl_plane.get_decision() { + return; + } + + self.lazily_clear_labels_at_tail(); + // Invariants valid at this point. + + trace!( + "enter optimize_branches:\n b = {:?}\n l = {:?}\n f = {:?}", + self.latest_branches, + self.labels_at_tail, + self.pending_fixup_records + ); + + // We continue to munch on branches at the tail of the buffer until no + // more rules apply. Note that the loop only continues if a branch is + // actually truncated (or if labels are redirected away from a branch), + // so this always makes progress. + while let Some(b) = self.latest_branches.last() { + let cur_off = self.cur_offset(); + trace!("optimize_branches: last branch {:?} at off {}", b, cur_off); + // If there has been any code emission since the end of the last branch or + // label definition, then there's nothing we can edit (because we + // don't move code once placed, only back up and overwrite), so + // clear the records and finish. + if b.end < cur_off { + break; + } + + // If the "labels at this branch" list on this branch is + // longer than a threshold, don't do any simplification, + // and let the branch remain to separate those labels from + // the current tail. This avoids quadratic behavior (see + // #3468): otherwise, if a long string of "goto next; + // next:" patterns are emitted, all of the labels will + // coalesce into a long list of aliases for the current + // buffer tail. We must track all aliases of the current + // tail for correctness, but we are also allowed to skip + // optimization (removal) of any branch, so we take the + // escape hatch here and let it stand. In effect this + // "spreads" the many thousands of labels in the + // pathological case among an actual (harmless but + // suboptimal) instruction once per N labels. + if b.labels_at_this_branch.len() > LABEL_LIST_THRESHOLD { + break; + } + + // Invariant: we are looking at a branch that ends at the tail of + // the buffer. + + // For any branch, conditional or unconditional: + // - If the target is a label at the current offset, then remove + // the conditional branch, and reset all labels that targeted + // the current offset (end of branch) to the truncated + // end-of-code. + // + // Preserves execution semantics: a branch to its own fallthrough + // address is equivalent to a no-op; in both cases, nextPC is the + // fallthrough. + if self.resolve_label_offset(b.target) == cur_off { + trace!("branch with target == cur off; truncating"); + self.truncate_last_branch(); + continue; + } + + // If latest is an unconditional branch: + // + // - If the branch's target is not its own start address, then for + // each label at the start of branch, make the label an alias of the + // branch target, and remove the label from the "labels at this + // branch" list. + // + // - Preserves execution semantics: an unconditional branch's + // only effect is to set PC to a new PC; this change simply + // collapses one step in the step-semantics. + // + // - Post-invariant: the labels that were bound to the start of + // this branch become aliases, so they must not be present in any + // labels-at-this-branch list or the labels-at-tail list. The + // labels are removed form the latest-branch record's + // labels-at-this-branch list, and are never placed in the + // labels-at-tail list. Furthermore, it is correct that they are + // not in either list, because they are now aliases, and labels + // that are aliases remain aliases forever. + // + // - If there is a prior unconditional branch that ends just before + // this one begins, and this branch has no labels bound to its + // start, then we can truncate this branch, because it is entirely + // unreachable (we have redirected all labels that make it + // reachable otherwise). Do so and continue around the loop. + // + // - Preserves execution semantics: the branch is unreachable, + // because execution can only flow into an instruction from the + // prior instruction's fallthrough or from a branch bound to that + // instruction's start offset. Unconditional branches have no + // fallthrough, so if the prior instruction is an unconditional + // branch, no fallthrough entry can happen. The + // labels-at-this-branch list is complete (by invariant), so if it + // is empty, then the instruction is entirely unreachable. Thus, + // it can be removed. + // + // - Post-invariant: ensured by truncate_last_branch(). + // + // - If there is a prior conditional branch whose target label + // resolves to the current offset (branches around the + // unconditional branch), then remove the unconditional branch, + // and make the target of the unconditional the target of the + // conditional instead. + // + // - Preserves execution semantics: previously we had: + // + // L1: + // cond_br L2 + // br L3 + // L2: + // (end of buffer) + // + // by removing the last branch, we have: + // + // L1: + // cond_br L2 + // L2: + // (end of buffer) + // + // we then fix up the records for the conditional branch to + // have: + // + // L1: + // cond_br.inverted L3 + // L2: + // + // In the original code, control flow reaches L2 when the + // conditional branch's predicate is true, and L3 otherwise. In + // the optimized code, the same is true. + // + // - Post-invariant: all edits to latest_branches and + // labels_at_tail are performed by `truncate_last_branch()`, + // which maintains the invariants at each step. + + if b.is_uncond() { + // Set any label equal to current branch's start as an alias of + // the branch's target, if the target is not the branch itself + // (i.e., an infinite loop). + // + // We cannot perform this aliasing if the target of this branch + // ultimately aliases back here; if so, we need to keep this + // branch, so break out of this loop entirely (and clear the + // latest-branches list below). + // + // Note that this check is what prevents cycles from forming in + // `self.label_aliases`. To see why, consider an arbitrary start + // state: + // + // label_aliases[L1] = L2, label_aliases[L2] = L3, ..., up to + // Ln, which is not aliased. + // + // We would create a cycle if we assigned label_aliases[Ln] + // = L1. Note that the below assignment is the only write + // to label_aliases. + // + // By our other invariants, we have that Ln (`l` below) + // resolves to the offset `b.start`, because it is in the + // set `b.labels_at_this_branch`. + // + // If L1 were already aliased, through some arbitrarily deep + // chain, to Ln, then it must also resolve to this offset + // `b.start`. + // + // By checking the resolution of `L1` against this offset, + // and aborting this branch-simplification if they are + // equal, we prevent the below assignment from ever creating + // a cycle. + if self.resolve_label_offset(b.target) != b.start { + let redirected = b.labels_at_this_branch.len(); + for &l in &b.labels_at_this_branch { + trace!( + " -> label at start of branch {:?} redirected to target {:?}", + l, + b.target + ); + self.label_aliases[l.0 as usize] = b.target; + // NOTE: we continue to ensure the invariant that labels + // pointing to tail of buffer are in `labels_at_tail` + // because we already ensured above that the last branch + // cannot have a target of `cur_off`; so we never have + // to put the label into `labels_at_tail` when moving it + // here. + } + // Maintain invariant: all branches have been redirected + // and are no longer pointing at the start of this branch. + let mut_b = self.latest_branches.last_mut().unwrap(); + mut_b.labels_at_this_branch.clear(); + + if redirected > 0 { + trace!(" -> after label redirects, restarting loop"); + continue; + } + } else { + break; + } + + let b = self.latest_branches.last().unwrap(); + + // Examine any immediately preceding branch. + if self.latest_branches.len() > 1 { + let prev_b = &self.latest_branches[self.latest_branches.len() - 2]; + trace!(" -> more than one branch; prev_b = {:?}", prev_b); + // This uncond is immediately after another uncond; we + // should have already redirected labels to this uncond away + // (but check to be sure); so we can truncate this uncond. + if prev_b.is_uncond() + && prev_b.end == b.start + && b.labels_at_this_branch.is_empty() + { + trace!(" -> uncond follows another uncond; truncating"); + self.truncate_last_branch(); + continue; + } + + // This uncond is immediately after a conditional, and the + // conditional's target is the end of this uncond, and we've + // already redirected labels to this uncond away; so we can + // truncate this uncond, flip the sense of the conditional, and + // set the conditional's target (in `latest_branches` and in + // `fixup_records`) to the uncond's target. + if prev_b.is_cond() + && prev_b.end == b.start + && self.resolve_label_offset(prev_b.target) == cur_off + { + trace!(" -> uncond follows a conditional, and conditional's target resolves to current offset"); + // Save the target of the uncond (this becomes the + // target of the cond), and truncate the uncond. + let target = b.target; + let data = prev_b.inverted.clone().unwrap(); + self.truncate_last_branch(); + + // Mutate the code and cond branch. + let off_before_edit = self.cur_offset(); + let prev_b = self.latest_branches.last_mut().unwrap(); + let not_inverted = SmallVec::from( + &self.data[(prev_b.start as usize)..(prev_b.end as usize)], + ); + + // Low-level edit: replaces bytes of branch with + // inverted form. cur_off remains the same afterward, so + // we do not need to modify label data structures. + self.data.truncate(prev_b.start as usize); + self.data.extend_from_slice(&data[..]); + + // Save the original code as the inversion of the + // inverted branch, in case we later edit this branch + // again. + prev_b.inverted = Some(not_inverted); + self.pending_fixup_records[prev_b.fixup].label = target; + trace!(" -> reassigning target of condbr to {:?}", target); + prev_b.target = target; + debug_assert_eq!(off_before_edit, self.cur_offset()); + continue; + } + } + } + + // If we couldn't do anything with the last branch, then break. + break; + } + + self.purge_latest_branches(); + + trace!( + "leave optimize_branches:\n b = {:?}\n l = {:?}\n f = {:?}", + self.latest_branches, + self.labels_at_tail, + self.pending_fixup_records + ); + } + + fn purge_latest_branches(&mut self) { + // All of our branch simplification rules work only if a branch ends at + // the tail of the buffer, with no following code; and branches are in + // order in latest_branches; so if the last entry ends prior to + // cur_offset, then clear all entries. + let cur_off = self.cur_offset(); + if let Some(l) = self.latest_branches.last() { + if l.end < cur_off { + trace!("purge_latest_branches: removing branch {:?}", l); + self.latest_branches.clear(); + } + } + + // Post-invariant: no invariant requires any branch to appear in + // `latest_branches`; it is always optional. The list-clear above thus + // preserves all semantics. + } + + /// Emit a trap at some point in the future with the specified code and + /// stack map. + /// + /// This function returns a [`MachLabel`] which will be the future address + /// of the trap. Jumps should refer to this label, likely by using the + /// [`MachBuffer::use_label_at_offset`] method, to get a relocation + /// patched in once the address of the trap is known. + /// + /// This will batch all traps into the end of the function. + pub fn defer_trap(&mut self, code: TrapCode) -> MachLabel { + let label = self.get_label(); + self.pending_traps.push(MachLabelTrap { + label, + code, + loc: self.cur_srcloc.map(|(_start, loc)| loc), + }); + label + } + + /// Is an island needed within the next N bytes? + pub fn island_needed(&self, distance: CodeOffset) -> bool { + let deadline = match self.fixup_records.peek() { + Some(fixup) => fixup.deadline().min(self.pending_fixup_deadline), + None => self.pending_fixup_deadline, + }; + deadline < u32::MAX && self.worst_case_end_of_island(distance) > deadline + } + + /// Returns the maximal offset that islands can reach if `distance` more + /// bytes are appended. + /// + /// This is used to determine if veneers need insertions since jumps that + /// can't reach past this point must get a veneer of some form. + fn worst_case_end_of_island(&self, distance: CodeOffset) -> CodeOffset { + // Assume that all fixups will require veneers and that the veneers are + // the worst-case size for each platform. This is an over-generalization + // to avoid iterating over the `fixup_records` list or maintaining + // information about it as we go along. + let island_worst_case_size = ((self.fixup_records.len() + self.pending_fixup_records.len()) + as u32) + * (I::LabelUse::worst_case_veneer_size()) + + self.pending_constants_size + + (self.pending_traps.len() * I::TRAP_OPCODE.len()) as u32; + self.cur_offset() + .saturating_add(distance) + .saturating_add(island_worst_case_size) + } + + /// Emit all pending constants and required pending veneers. + /// + /// Should only be called if `island_needed()` returns true, i.e., if we + /// actually reach a deadline. It's not necessarily a problem to do so + /// otherwise but it may result in unnecessary work during emission. + pub fn emit_island(&mut self, distance: CodeOffset, ctrl_plane: &mut ControlPlane) { + self.emit_island_maybe_forced(ForceVeneers::No, distance, ctrl_plane); + } + + /// Same as `emit_island`, but an internal API with a `force_veneers` + /// argument to force all veneers to always get emitted for debugging. + fn emit_island_maybe_forced( + &mut self, + force_veneers: ForceVeneers, + distance: CodeOffset, + ctrl_plane: &mut ControlPlane, + ) { + // We're going to purge fixups, so no latest-branch editing can happen + // anymore. + self.latest_branches.clear(); + + // End the current location tracking since anything emitted during this + // function shouldn't be attributed to whatever the current source + // location is. + // + // Note that the current source location, if it's set right now, will be + // restored at the end of this island emission. + let cur_loc = self.cur_srcloc.map(|(_, loc)| loc); + if cur_loc.is_some() { + self.end_srcloc(); + } + + let forced_threshold = self.worst_case_end_of_island(distance); + + // First flush out all traps/constants so we have more labels in case + // fixups are applied against these labels. + // + // Note that traps are placed first since this typically happens at the + // end of the function and for disassemblers we try to keep all the code + // contiguously together. + for MachLabelTrap { label, code, loc } in mem::take(&mut self.pending_traps) { + // If this trap has source information associated with it then + // emit this information for the trap instruction going out now too. + if let Some(loc) = loc { + self.start_srcloc(loc); + } + self.align_to(I::LabelUse::ALIGN); + self.bind_label(label, ctrl_plane); + self.add_trap(code); + self.put_data(I::TRAP_OPCODE); + if loc.is_some() { + self.end_srcloc(); + } + } + + for constant in mem::take(&mut self.pending_constants) { + let MachBufferConstant { align, size, .. } = self.constants[constant]; + let label = self.constants[constant].upcoming_label.take().unwrap(); + self.align_to(align); + self.bind_label(label, ctrl_plane); + self.used_constants.push((constant, self.cur_offset())); + self.get_appended_space(size); + } + + // Either handle all pending fixups because they're ready or move them + // onto the `BinaryHeap` tracking all pending fixups if they aren't + // ready. + assert!(self.latest_branches.is_empty()); + for fixup in mem::take(&mut self.pending_fixup_records) { + if self.should_apply_fixup(&fixup, forced_threshold) { + self.handle_fixup(fixup, force_veneers, forced_threshold); + } else { + self.fixup_records.push(fixup); + } + } + self.pending_fixup_deadline = u32::MAX; + while let Some(fixup) = self.fixup_records.peek() { + trace!("emit_island: fixup {:?}", fixup); + + // If this fixup shouldn't be applied, that means its label isn't + // defined yet and there'll be remaining space to apply a veneer if + // necessary in the future after this island. In that situation + // because `fixup_records` is sorted by deadline this loop can + // exit. + if !self.should_apply_fixup(fixup, forced_threshold) { + break; + } + + let fixup = self.fixup_records.pop().unwrap(); + self.handle_fixup(fixup, force_veneers, forced_threshold); + } + + if let Some(loc) = cur_loc { + self.start_srcloc(loc); + } + } + + fn should_apply_fixup(&self, fixup: &MachLabelFixup, forced_threshold: CodeOffset) -> bool { + let label_offset = self.resolve_label_offset(fixup.label); + label_offset != UNKNOWN_LABEL_OFFSET || fixup.deadline() < forced_threshold + } + + fn handle_fixup( + &mut self, + fixup: MachLabelFixup, + force_veneers: ForceVeneers, + forced_threshold: CodeOffset, + ) { + let MachLabelFixup { + label, + offset, + kind, + } = fixup; + let start = offset as usize; + let end = (offset + kind.patch_size()) as usize; + let label_offset = self.resolve_label_offset(label); + + if label_offset != UNKNOWN_LABEL_OFFSET { + // If the offset of the label for this fixup is known then + // we're going to do something here-and-now. We're either going + // to patch the original offset because it's an in-bounds jump, + // or we're going to generate a veneer, patch the fixup to jump + // to the veneer, and then keep going. + // + // If the label comes after the original fixup, then we should + // be guaranteed that the jump is in-bounds. Otherwise there's + // a bug somewhere because this method wasn't called soon + // enough. All forward-jumps are tracked and should get veneers + // before their deadline comes and they're unable to jump + // further. + // + // Otherwise if the label is before the fixup, then that's a + // backwards jump. If it's past the maximum negative range + // then we'll emit a veneer that to jump forward to which can + // then jump backwards. + let veneer_required = if label_offset >= offset { + assert!((label_offset - offset) <= kind.max_pos_range()); + false + } else { + (offset - label_offset) > kind.max_neg_range() + }; + trace!( + " -> label_offset = {}, known, required = {} (pos {} neg {})", + label_offset, + veneer_required, + kind.max_pos_range(), + kind.max_neg_range() + ); + + if (force_veneers == ForceVeneers::Yes && kind.supports_veneer()) || veneer_required { + self.emit_veneer(label, offset, kind); + } else { + let slice = &mut self.data[start..end]; + trace!("patching in-range! slice = {slice:?}; offset = {offset:#x}; label_offset = {label_offset:#x}"); + kind.patch(slice, offset, label_offset); + } + } else { + // If the offset of this label is not known at this time then + // that means that a veneer is required because after this + // island the target can't be in range of the original target. + assert!(forced_threshold - offset > kind.max_pos_range()); + self.emit_veneer(label, offset, kind); + } + } + + /// Emits a "veneer" the `kind` code at `offset` to jump to `label`. + /// + /// This will generate extra machine code, using `kind`, to get a + /// larger-jump-kind than `kind` allows. The code at `offset` is then + /// patched to jump to our new code, and then the new code is enqueued for + /// a fixup to get processed at some later time. + fn emit_veneer(&mut self, label: MachLabel, offset: CodeOffset, kind: I::LabelUse) { + // If this `kind` doesn't support a veneer then that's a bug in the + // backend because we need to implement support for such a veneer. + assert!( + kind.supports_veneer(), + "jump beyond the range of {kind:?} but a veneer isn't supported", + ); + + // Allocate space for a veneer in the island. + self.align_to(I::LabelUse::ALIGN); + let veneer_offset = self.cur_offset(); + trace!("making a veneer at {}", veneer_offset); + let start = offset as usize; + let end = (offset + kind.patch_size()) as usize; + let slice = &mut self.data[start..end]; + // Patch the original label use to refer to the veneer. + trace!( + "patching original at offset {} to veneer offset {}", + offset, + veneer_offset + ); + kind.patch(slice, offset, veneer_offset); + // Generate the veneer. + let veneer_slice = self.get_appended_space(kind.veneer_size() as usize); + let (veneer_fixup_off, veneer_label_use) = + kind.generate_veneer(veneer_slice, veneer_offset); + trace!( + "generated veneer; fixup offset {}, label_use {:?}", + veneer_fixup_off, + veneer_label_use + ); + // Register a new use of `label` with our new veneer fixup and + // offset. This'll recalculate deadlines accordingly and + // enqueue this fixup to get processed at some later + // time. + self.use_label_at_offset(veneer_fixup_off, label, veneer_label_use); + } + + fn finish_emission_maybe_forcing_veneers( + &mut self, + force_veneers: ForceVeneers, + ctrl_plane: &mut ControlPlane, + ) { + while !self.pending_constants.is_empty() + || !self.pending_traps.is_empty() + || !self.fixup_records.is_empty() + || !self.pending_fixup_records.is_empty() + { + // `emit_island()` will emit any pending veneers and constants, and + // as a side-effect, will also take care of any fixups with resolved + // labels eagerly. + self.emit_island_maybe_forced(force_veneers, u32::MAX, ctrl_plane); + } + + // Ensure that all labels have been fixed up after the last island is emitted. This is a + // full (release-mode) assert because an unresolved label means the emitted code is + // incorrect. + assert!(self.fixup_records.is_empty()); + assert!(self.pending_fixup_records.is_empty()); + } + + /// Finish any deferred emissions and/or fixups. + pub fn finish( + mut self, + constants: &VCodeConstants, + ctrl_plane: &mut ControlPlane, + ) -> MachBufferFinalized { + let _tt = timing::vcode_emit_finish(); + + self.finish_emission_maybe_forcing_veneers(ForceVeneers::No, ctrl_plane); + + let alignment = self.finish_constants(constants); + + // Resolve all labels to their offsets. + let finalized_relocs = self + .relocs + .iter() + .map(|reloc| FinalizedMachReloc { + offset: reloc.offset, + kind: reloc.kind, + addend: reloc.addend, + target: match &reloc.target { + RelocTarget::ExternalName(name) => { + FinalizedRelocTarget::ExternalName(name.clone()) + } + RelocTarget::Label(label) => { + FinalizedRelocTarget::Func(self.resolve_label_offset(*label)) + } + }, + }) + .collect(); + + let mut srclocs = self.srclocs; + srclocs.sort_by_key(|entry| entry.start); + + MachBufferFinalized { + data: self.data, + relocs: finalized_relocs, + traps: self.traps, + call_sites: self.call_sites, + srclocs, + user_stack_maps: self.user_stack_maps, + unwind_info: self.unwind_info, + alignment, + } + } + + /// Add an external relocation at the given offset. + pub fn add_reloc_at_offset + Clone>( + &mut self, + offset: CodeOffset, + kind: Reloc, + target: &T, + addend: Addend, + ) { + let target: RelocTarget = target.clone().into(); + // FIXME(#3277): This should use `I::LabelUse::from_reloc` to optionally + // generate a label-use statement to track whether an island is possibly + // needed to escape this function to actually get to the external name. + // This is most likely to come up on AArch64 where calls between + // functions use a 26-bit signed offset which gives +/- 64MB. This means + // that if a function is 128MB in size and there's a call in the middle + // it's impossible to reach the actual target. Also, while it's + // technically possible to jump to the start of a function and then jump + // further, island insertion below always inserts islands after + // previously appended code so for Cranelift's own implementation this + // is also a problem for 64MB functions on AArch64 which start with a + // call instruction, those won't be able to escape. + // + // Ideally what needs to happen here is that a `LabelUse` is + // transparently generated (or call-sites of this function are audited + // to generate a `LabelUse` instead) and tracked internally. The actual + // relocation would then change over time if and when a veneer is + // inserted, where the relocation here would be patched by this + // `MachBuffer` to jump to the veneer. The problem, though, is that all + // this still needs to end up, in the case of a singular function, + // generating a final relocation pointing either to this particular + // relocation or to the veneer inserted. Additionally + // `MachBuffer` needs the concept of a label which will never be + // resolved, so `emit_island` doesn't trip over not actually ever + // knowning what some labels are. Currently the loop in + // `finish_emission_maybe_forcing_veneers` would otherwise infinitely + // loop. + // + // For now this means that because relocs aren't tracked at all that + // AArch64 functions have a rough size limits of 64MB. For now that's + // somewhat reasonable and the failure mode is a panic in `MachBuffer` + // when a relocation can't otherwise be resolved later, so it shouldn't + // actually result in any memory unsafety or anything like that. + self.relocs.push(MachReloc { + offset, + kind, + target, + addend, + }); + } + + /// Add an external relocation at the current offset. + pub fn add_reloc + Clone>( + &mut self, + kind: Reloc, + target: &T, + addend: Addend, + ) { + self.add_reloc_at_offset(self.data.len() as CodeOffset, kind, target, addend); + } + + /// Add a trap record at the current offset. + pub fn add_trap(&mut self, code: TrapCode) { + self.traps.push(MachTrap { + offset: self.data.len() as CodeOffset, + code, + }); + } + + /// Add a call-site record at the current offset. + pub fn add_call_site(&mut self) { + self.call_sites.push(MachCallSite { + ret_addr: self.data.len() as CodeOffset, + }); + } + + /// Add an unwind record at the current offset. + pub fn add_unwind(&mut self, unwind: UnwindInst) { + self.unwind_info.push((self.cur_offset(), unwind)); + } + + /// Set the `SourceLoc` for code from this offset until the offset at the + /// next call to `end_srcloc()`. + /// Returns the current [CodeOffset] and [RelSourceLoc]. + pub fn start_srcloc(&mut self, loc: RelSourceLoc) -> (CodeOffset, RelSourceLoc) { + let cur = (self.cur_offset(), loc); + self.cur_srcloc = Some(cur); + cur + } + + /// Mark the end of the `SourceLoc` segment started at the last + /// `start_srcloc()` call. + pub fn end_srcloc(&mut self) { + let (start, loc) = self + .cur_srcloc + .take() + .expect("end_srcloc() called without start_srcloc()"); + let end = self.cur_offset(); + // Skip zero-length extends. + debug_assert!(end >= start); + if end > start { + self.srclocs.push(MachSrcLoc { start, end, loc }); + } + } + + /// Push a user stack map onto this buffer. + /// + /// The stack map is associated with the given `return_addr` code + /// offset. This must be the PC for the instruction just *after* this stack + /// map's associated instruction. For example in the sequence `call $foo; + /// add r8, rax`, the `return_addr` must be the offset of the start of the + /// `add` instruction. + /// + /// Stack maps must be pushed in sorted `return_addr` order. + pub fn push_user_stack_map( + &mut self, + emit_state: &I::State, + return_addr: CodeOffset, + mut stack_map: ir::UserStackMap, + ) { + let span = emit_state.frame_layout().active_size(); + trace!("Adding user stack map @ {return_addr:#x} spanning {span} bytes: {stack_map:?}"); + + debug_assert!( + self.user_stack_maps + .last() + .map_or(true, |(prev_addr, _, _)| *prev_addr < return_addr), + "pushed stack maps out of order: {} is not less than {}", + self.user_stack_maps.last().unwrap().0, + return_addr, + ); + + stack_map.finalize(emit_state.frame_layout().sp_to_sized_stack_slots()); + self.user_stack_maps.push((return_addr, span, stack_map)); + } +} + +impl Extend for MachBuffer { + fn extend>(&mut self, iter: T) { + for b in iter { + self.put1(b); + } + } +} + +impl MachBufferFinalized { + /// Get a list of source location mapping tuples in sorted-by-start-offset order. + pub fn get_srclocs_sorted(&self) -> &[T::MachSrcLocType] { + &self.srclocs[..] + } + + /// Get the total required size for the code. + pub fn total_size(&self) -> CodeOffset { + self.data.len() as CodeOffset + } + + /// Return the code in this mach buffer as a hex string for testing purposes. + pub fn stringify_code_bytes(&self) -> String { + // This is pretty lame, but whatever .. + use std::fmt::Write; + let mut s = String::with_capacity(self.data.len() * 2); + for b in &self.data { + write!(&mut s, "{b:02X}").unwrap(); + } + s + } + + /// Get the code bytes. + pub fn data(&self) -> &[u8] { + // N.B.: we emit every section into the .text section as far as + // the `CodeSink` is concerned; we do not bother to segregate + // the contents into the actual program text, the jumptable and the + // rodata (constant pool). This allows us to generate code assuming + // that these will not be relocated relative to each other, and avoids + // having to designate each section as belonging in one of the three + // fixed categories defined by `CodeSink`. If this becomes a problem + // later (e.g. because of memory permissions or similar), we can + // add this designation and segregate the output; take care, however, + // to add the appropriate relocations in this case. + + &self.data[..] + } + + /// Get the list of external relocations for this code. + pub fn relocs(&self) -> &[FinalizedMachReloc] { + &self.relocs[..] + } + + /// Get the list of trap records for this code. + pub fn traps(&self) -> &[MachTrap] { + &self.traps[..] + } + + /// Get the user stack map metadata for this code. + pub fn user_stack_maps(&self) -> &[(CodeOffset, u32, ir::UserStackMap)] { + &self.user_stack_maps + } + + /// Take this buffer's user strack map metadata. + pub fn take_user_stack_maps(&mut self) -> SmallVec<[(CodeOffset, u32, ir::UserStackMap); 8]> { + mem::take(&mut self.user_stack_maps) + } + + /// Get the list of call sites for this code. + pub fn call_sites(&self) -> &[MachCallSite] { + &self.call_sites[..] + } +} + +/// Metadata about a constant. +struct MachBufferConstant { + /// A label which has not yet been bound which can be used for this + /// constant. + /// + /// This is lazily created when a label is requested for a constant and is + /// cleared when a constant is emitted. + upcoming_label: Option, + /// Required alignment. + align: CodeOffset, + /// The byte size of this constant. + size: usize, +} + +/// A trap that is deferred to the next time an island is emitted for either +/// traps, constants, or fixups. +struct MachLabelTrap { + /// This label will refer to the trap's offset. + label: MachLabel, + /// The code associated with this trap. + code: TrapCode, + /// An optional source location to assign for this trap. + loc: Option, +} + +/// A fixup to perform on the buffer once code is emitted. Fixups always refer +/// to labels and patch the code based on label offsets. Hence, they are like +/// relocations, but internal to one buffer. +#[derive(Debug)] +struct MachLabelFixup { + /// The label whose offset controls this fixup. + label: MachLabel, + /// The offset to fix up / patch to refer to this label. + offset: CodeOffset, + /// The kind of fixup. This is architecture-specific; each architecture may have, + /// e.g., several types of branch instructions, each with differently-sized + /// offset fields and different places within the instruction to place the + /// bits. + kind: I::LabelUse, +} + +impl MachLabelFixup { + fn deadline(&self) -> CodeOffset { + self.offset.saturating_add(self.kind.max_pos_range()) + } +} + +impl PartialEq for MachLabelFixup { + fn eq(&self, other: &Self) -> bool { + self.deadline() == other.deadline() + } +} + +impl Eq for MachLabelFixup {} + +impl PartialOrd for MachLabelFixup { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for MachLabelFixup { + fn cmp(&self, other: &Self) -> Ordering { + other.deadline().cmp(&self.deadline()) + } +} + +/// A relocation resulting from a compilation. +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct MachRelocBase { + /// The offset at which the relocation applies, *relative to the + /// containing section*. + pub offset: CodeOffset, + /// The kind of relocation. + pub kind: Reloc, + /// The external symbol / name to which this relocation refers. + pub target: T, + /// The addend to add to the symbol value. + pub addend: i64, +} + +type MachReloc = MachRelocBase; + +/// A relocation resulting from a compilation. +pub type FinalizedMachReloc = MachRelocBase; + +/// A Relocation target +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum RelocTarget { + /// Points to an [ExternalName] outside the current function. + ExternalName(ExternalName), + /// Points to a [MachLabel] inside this function. + /// This is different from [MachLabelFixup] in that both the relocation and the + /// label will be emitted and are only resolved at link time. + /// + /// There is no reason to prefer this over [MachLabelFixup] unless the ABI requires it. + Label(MachLabel), +} + +impl From for RelocTarget { + fn from(name: ExternalName) -> Self { + Self::ExternalName(name) + } +} + +impl From for RelocTarget { + fn from(label: MachLabel) -> Self { + Self::Label(label) + } +} + +/// A Relocation target +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub enum FinalizedRelocTarget { + /// Points to an [ExternalName] outside the current function. + ExternalName(ExternalName), + /// Points to a [CodeOffset] from the start of the current function. + Func(CodeOffset), +} + +impl FinalizedRelocTarget { + /// Returns a display for the current [FinalizedRelocTarget], with extra context to prettify the + /// output. + pub fn display<'a>(&'a self, params: Option<&'a FunctionParameters>) -> String { + match self { + FinalizedRelocTarget::ExternalName(name) => format!("{}", name.display(params)), + FinalizedRelocTarget::Func(offset) => format!("func+{offset}"), + } + } +} + +/// A trap record resulting from a compilation. +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct MachTrap { + /// The offset at which the trap instruction occurs, *relative to the + /// containing section*. + pub offset: CodeOffset, + /// The trap code. + pub code: TrapCode, +} + +/// A call site record resulting from a compilation. +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct MachCallSite { + /// The offset of the call's return address, *relative to the containing section*. + pub ret_addr: CodeOffset, +} + +/// A source-location mapping resulting from a compilation. +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr( + feature = "enable-serde", + derive(serde_derive::Serialize, serde_derive::Deserialize) +)] +pub struct MachSrcLoc { + /// The start of the region of code corresponding to a source location. + /// This is relative to the start of the function, not to the start of the + /// section. + pub start: CodeOffset, + /// The end of the region of code corresponding to a source location. + /// This is relative to the start of the section, not to the start of the + /// section. + pub end: CodeOffset, + /// The source location. + pub loc: T::SourceLocType, +} + +impl MachSrcLoc { + fn apply_base_srcloc(self, base_srcloc: SourceLoc) -> MachSrcLoc { + MachSrcLoc { + start: self.start, + end: self.end, + loc: self.loc.expand(base_srcloc), + } + } +} + +/// Record of branch instruction in the buffer, to facilitate editing. +#[derive(Clone, Debug)] +struct MachBranch { + start: CodeOffset, + end: CodeOffset, + target: MachLabel, + fixup: usize, + inverted: Option>, + /// All labels pointing to the start of this branch. For correctness, this + /// *must* be complete (i.e., must contain all labels whose resolved offsets + /// are at the start of this branch): we rely on being able to redirect all + /// labels that could jump to this branch before removing it, if it is + /// otherwise unreachable. + labels_at_this_branch: SmallVec<[MachLabel; 4]>, +} + +impl MachBranch { + fn is_cond(&self) -> bool { + self.inverted.is_some() + } + fn is_uncond(&self) -> bool { + self.inverted.is_none() + } +} + +/// Implementation of the `TextSectionBuilder` trait backed by `MachBuffer`. +/// +/// Note that `MachBuffer` was primarily written for intra-function references +/// of jumps between basic blocks, but it's also quite usable for entire text +/// sections and resolving references between functions themselves. This +/// builder interprets "blocks" as labeled functions for the purposes of +/// resolving labels internally in the buffer. +pub struct MachTextSectionBuilder { + buf: MachBuffer, + next_func: usize, + force_veneers: ForceVeneers, +} + +impl MachTextSectionBuilder { + /// Creates a new text section builder which will have `num_funcs` functions + /// pushed into it. + pub fn new(num_funcs: usize) -> MachTextSectionBuilder { + let mut buf = MachBuffer::new(); + buf.reserve_labels_for_blocks(num_funcs); + MachTextSectionBuilder { + buf, + next_func: 0, + force_veneers: ForceVeneers::No, + } + } +} + +impl TextSectionBuilder for MachTextSectionBuilder { + fn append( + &mut self, + labeled: bool, + func: &[u8], + align: u32, + ctrl_plane: &mut ControlPlane, + ) -> u64 { + // Conditionally emit an island if it's necessary to resolve jumps + // between functions which are too far away. + let size = func.len() as u32; + if self.force_veneers == ForceVeneers::Yes || self.buf.island_needed(size) { + self.buf + .emit_island_maybe_forced(self.force_veneers, size, ctrl_plane); + } + + self.buf.align_to(align); + let pos = self.buf.cur_offset(); + if labeled { + self.buf.bind_label( + MachLabel::from_block(BlockIndex::new(self.next_func)), + ctrl_plane, + ); + self.next_func += 1; + } + self.buf.put_data(func); + u64::from(pos) + } + + fn resolve_reloc(&mut self, offset: u64, reloc: Reloc, addend: Addend, target: usize) -> bool { + crate::trace!( + "Resolving relocation @ {offset:#x} + {addend:#x} to target {target} of kind {reloc:?}" + ); + let label = MachLabel::from_block(BlockIndex::new(target)); + let offset = u32::try_from(offset).unwrap(); + match I::LabelUse::from_reloc(reloc, addend) { + Some(label_use) => { + self.buf.use_label_at_offset(offset, label, label_use); + true + } + None => false, + } + } + + fn force_veneers(&mut self) { + self.force_veneers = ForceVeneers::Yes; + } + + fn write(&mut self, offset: u64, data: &[u8]) { + self.buf.data[offset.try_into().unwrap()..][..data.len()].copy_from_slice(data); + } + + fn finish(&mut self, ctrl_plane: &mut ControlPlane) -> Vec { + // Double-check all functions were pushed. + assert_eq!(self.next_func, self.buf.label_offsets.len()); + + // Finish up any veneers, if necessary. + self.buf + .finish_emission_maybe_forcing_veneers(self.force_veneers, ctrl_plane); + + // We don't need the data any more, so return it to the caller. + mem::take(&mut self.buf.data).into_vec() + } +} + +// We use an actual instruction definition to do tests, so we depend on the `arm64` feature here. +#[cfg(all(test, feature = "arm64"))] +mod test { + use cranelift_entity::EntityRef as _; + + use super::*; + use crate::ir::UserExternalNameRef; + use crate::isa::aarch64::inst::{xreg, OperandSize}; + use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst}; + use crate::machinst::{MachInstEmit, MachInstEmitState}; + use crate::settings; + + fn label(n: u32) -> MachLabel { + MachLabel::from_block(BlockIndex::new(n as usize)) + } + fn target(n: u32) -> BranchTarget { + BranchTarget::Label(label(n)) + } + + #[test] + fn test_elide_jump_to_next() { + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(2); + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(1) }; + inst.emit(&mut buf, &info, &mut state); + buf.bind_label(label(1), state.ctrl_plane_mut()); + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + assert_eq!(0, buf.total_size()); + } + + #[test] + fn test_elide_trivial_jump_blocks() { + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(4); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::CondBr { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + taken: target(1), + not_taken: target(2), + }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(3) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(2), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(3) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(3), state.ctrl_plane_mut()); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + assert_eq!(0, buf.total_size()); + } + + #[test] + fn test_flip_cond() { + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(4); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::CondBr { + kind: CondBrKind::Zero(xreg(0), OperandSize::Size64), + taken: target(1), + not_taken: target(2), + }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(2), state.ctrl_plane_mut()); + let inst = Inst::Udf { + trap_code: TrapCode::STACK_OVERFLOW, + }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(3), state.ctrl_plane_mut()); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + + let mut buf2 = MachBuffer::new(); + let mut state = Default::default(); + let inst = Inst::TrapIf { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + trap_code: TrapCode::STACK_OVERFLOW, + }; + inst.emit(&mut buf2, &info, &mut state); + let inst = Inst::Nop4; + inst.emit(&mut buf2, &info, &mut state); + + let buf2 = buf2.finish(&constants, state.ctrl_plane_mut()); + + assert_eq!(buf.data, buf2.data); + } + + #[test] + fn test_island() { + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(4); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::CondBr { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + taken: target(2), + not_taken: target(3), + }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + while buf.cur_offset() < 2000000 { + if buf.island_needed(0) { + buf.emit_island(0, state.ctrl_plane_mut()); + } + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + } + + buf.bind_label(label(2), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(3), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + + assert_eq!(2000000 + 8, buf.total_size()); + + let mut buf2 = MachBuffer::new(); + let mut state = Default::default(); + let inst = Inst::CondBr { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + + // This conditionally taken branch has a 19-bit constant, shifted + // to the left by two, giving us a 21-bit range in total. Half of + // this range positive so the we should be around 1 << 20 bytes + // away for our jump target. + // + // There are two pending fixups by the time we reach this point, + // one for this 19-bit jump and one for the unconditional 26-bit + // jump below. A 19-bit veneer is 4 bytes large and the 26-bit + // veneer is 20 bytes large, which means that pessimistically + // assuming we'll need two veneers. Currently each veneer is + // pessimistically assumed to be the maximal size which means we + // need 40 bytes of extra space, meaning that the actual island + // should come 40-bytes before the deadline. + taken: BranchTarget::ResolvedOffset((1 << 20) - 20 - 20), + + // This branch is in-range so no veneers should be needed, it should + // go directly to the target. + not_taken: BranchTarget::ResolvedOffset(2000000 + 4 - 4), + }; + inst.emit(&mut buf2, &info, &mut state); + + let buf2 = buf2.finish(&constants, state.ctrl_plane_mut()); + + assert_eq!(&buf.data[0..8], &buf2.data[..]); + } + + #[test] + fn test_island_backward() { + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(4); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(2), state.ctrl_plane_mut()); + while buf.cur_offset() < 2000000 { + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + } + + buf.bind_label(label(3), state.ctrl_plane_mut()); + let inst = Inst::CondBr { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + taken: target(0), + not_taken: target(1), + }; + inst.emit(&mut buf, &info, &mut state); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + + assert_eq!(2000000 + 12, buf.total_size()); + + let mut buf2 = MachBuffer::new(); + let mut state = Default::default(); + let inst = Inst::CondBr { + kind: CondBrKind::NotZero(xreg(0), OperandSize::Size64), + taken: BranchTarget::ResolvedOffset(8), + not_taken: BranchTarget::ResolvedOffset(4 - (2000000 + 4)), + }; + inst.emit(&mut buf2, &info, &mut state); + let inst = Inst::Jump { + dest: BranchTarget::ResolvedOffset(-(2000000 + 8)), + }; + inst.emit(&mut buf2, &info, &mut state); + + let buf2 = buf2.finish(&constants, state.ctrl_plane_mut()); + + assert_eq!(&buf.data[2000000..], &buf2.data[..]); + } + + #[test] + fn test_multiple_redirect() { + // label0: + // cbz x0, label1 + // b label2 + // label1: + // b label3 + // label2: + // nop + // nop + // b label0 + // label3: + // b label4 + // label4: + // b label5 + // label5: + // b label7 + // label6: + // nop + // label7: + // ret + // + // -- should become: + // + // label0: + // cbz x0, label7 + // label2: + // nop + // nop + // b label0 + // label6: + // nop + // label7: + // ret + + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(8); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::CondBr { + kind: CondBrKind::Zero(xreg(0), OperandSize::Size64), + taken: target(1), + not_taken: target(2), + }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(3) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(2), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + inst.emit(&mut buf, &info, &mut state); + let inst = Inst::Jump { dest: target(0) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(3), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(4) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(4), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(5) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(5), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(7) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(6), state.ctrl_plane_mut()); + let inst = Inst::Nop4; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(7), state.ctrl_plane_mut()); + let inst = Inst::Ret {}; + inst.emit(&mut buf, &info, &mut state); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + + let golden_data = vec![ + 0xa0, 0x00, 0x00, 0xb4, // cbz x0, 0x14 + 0x1f, 0x20, 0x03, 0xd5, // nop + 0x1f, 0x20, 0x03, 0xd5, // nop + 0xfd, 0xff, 0xff, 0x17, // b 0 + 0x1f, 0x20, 0x03, 0xd5, // nop + 0xc0, 0x03, 0x5f, 0xd6, // ret + ]; + + assert_eq!(&golden_data[..], &buf.data[..]); + } + + #[test] + fn test_handle_branch_cycle() { + // label0: + // b label1 + // label1: + // b label2 + // label2: + // b label3 + // label3: + // b label4 + // label4: + // b label1 // note: not label0 (to make it interesting). + // + // -- should become: + // + // label0, label1, ..., label4: + // b label0 + let info = EmitInfo::new(settings::Flags::new(settings::builder())); + let mut buf = MachBuffer::new(); + let mut state = ::State::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(5); + + buf.bind_label(label(0), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(1) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(1), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(2) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(2), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(3) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(3), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(4) }; + inst.emit(&mut buf, &info, &mut state); + + buf.bind_label(label(4), state.ctrl_plane_mut()); + let inst = Inst::Jump { dest: target(1) }; + inst.emit(&mut buf, &info, &mut state); + + let buf = buf.finish(&constants, state.ctrl_plane_mut()); + + let golden_data = vec![ + 0x00, 0x00, 0x00, 0x14, // b 0 + ]; + + assert_eq!(&golden_data[..], &buf.data[..]); + } + + #[test] + fn metadata_records() { + let mut buf = MachBuffer::::new(); + let ctrl_plane = &mut Default::default(); + let constants = Default::default(); + + buf.reserve_labels_for_blocks(1); + + buf.bind_label(label(0), ctrl_plane); + buf.put1(1); + buf.add_trap(TrapCode::HEAP_OUT_OF_BOUNDS); + buf.put1(2); + buf.add_trap(TrapCode::INTEGER_OVERFLOW); + buf.add_trap(TrapCode::INTEGER_DIVISION_BY_ZERO); + buf.add_call_site(); + buf.add_reloc( + Reloc::Abs4, + &ExternalName::User(UserExternalNameRef::new(0)), + 0, + ); + buf.put1(3); + buf.add_reloc( + Reloc::Abs8, + &ExternalName::User(UserExternalNameRef::new(1)), + 1, + ); + buf.put1(4); + + let buf = buf.finish(&constants, ctrl_plane); + + assert_eq!(buf.data(), &[1, 2, 3, 4]); + assert_eq!( + buf.traps() + .iter() + .map(|trap| (trap.offset, trap.code)) + .collect::>(), + vec![ + (1, TrapCode::HEAP_OUT_OF_BOUNDS), + (2, TrapCode::INTEGER_OVERFLOW), + (2, TrapCode::INTEGER_DIVISION_BY_ZERO) + ] + ); + assert_eq!( + buf.call_sites() + .iter() + .map(|call_site| call_site.ret_addr) + .collect::>(), + vec![2] + ); + assert_eq!( + buf.relocs() + .iter() + .map(|reloc| (reloc.offset, reloc.kind)) + .collect::>(), + vec![(2, Reloc::Abs4), (3, Reloc::Abs8)] + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/compile.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/compile.rs new file mode 100644 index 00000000000000..2324e65ce2ff1c --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/compile.rs @@ -0,0 +1,104 @@ +//! Compilation backend pipeline: optimized IR to VCode / binemit. + +use crate::dominator_tree::DominatorTree; +use crate::ir::pcc; +use crate::ir::Function; +use crate::isa::TargetIsa; +use crate::machinst::*; +use crate::settings::RegallocAlgorithm; +use crate::timing; +use crate::trace; +use crate::CodegenError; + +use regalloc2::{Algorithm, RegallocOptions}; + +/// Compile the given function down to VCode with allocated registers, ready +/// for binary emission. +pub fn compile( + f: &Function, + domtree: &DominatorTree, + b: &B, + abi: Callee<<::MInst as MachInst>::ABIMachineSpec>, + emit_info: ::Info, + sigs: SigSet, + ctrl_plane: &mut ControlPlane, +) -> CodegenResult<(VCode, regalloc2::Output)> { + // Compute lowered block order. + let block_order = BlockLoweringOrder::new(f, domtree, ctrl_plane); + + // Build the lowering context. + let lower = + crate::machinst::Lower::new(f, abi, emit_info, block_order, sigs, b.flags().clone())?; + + // Lower the IR. + let mut vcode = { + log::debug!( + "Number of CLIF instructions to lower: {}", + f.dfg.num_insts() + ); + log::debug!("Number of CLIF blocks to lower: {}", f.dfg.num_blocks()); + + let _tt = timing::vcode_lower(); + lower.lower(b, ctrl_plane)? + }; + + log::debug!( + "Number of lowered vcode instructions: {}", + vcode.num_insts() + ); + log::debug!("Number of lowered vcode blocks: {}", vcode.num_blocks()); + trace!("vcode from lowering: \n{:?}", vcode); + + // Perform validation of proof-carrying-code facts, if requested. + if b.flags().enable_pcc() { + pcc::check_vcode_facts(f, &mut vcode, b).map_err(CodegenError::Pcc)?; + } + + // Perform register allocation. + let regalloc_result = { + let _tt = timing::regalloc(); + let mut options = RegallocOptions::default(); + options.verbose_log = b.flags().regalloc_verbose_logs(); + + if cfg!(debug_assertions) { + options.validate_ssa = true; + } + + options.algorithm = match b.flags().regalloc_algorithm() { + RegallocAlgorithm::Backtracking => Algorithm::Ion, + RegallocAlgorithm::SinglePass => Algorithm::Fastalloc, + }; + + regalloc2::run(&vcode, vcode.machine_env(), &options) + .map_err(|err| { + log::error!( + "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}", + vcode, + err, + f, + ); + err + }) + .expect("register allocation") + }; + + // Run the regalloc checker, if requested. + if b.flags().regalloc_checker() { + let _tt = timing::regalloc_checker(); + let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.machine_env()); + checker.prepare(®alloc_result); + checker + .run() + .map_err(|err| { + log::error!( + "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}", + err, + vcode + ); + err + }) + .expect("register allocation checker"); + } + + Ok((vcode, regalloc_result)) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/helpers.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/helpers.rs new file mode 100644 index 00000000000000..411af0cdc7f98b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/helpers.rs @@ -0,0 +1,23 @@ +//! Miscellaneous helpers for machine backends. + +use crate::ir::Type; +use std::ops::{Add, BitAnd, Not, Sub}; + +/// Returns the size (in bits) of a given type. +pub fn ty_bits(ty: Type) -> usize { + ty.bits() as usize +} + +/// Align a size up to a power-of-two alignment. +pub(crate) fn align_to(x: N, alignment: N) -> N +where + N: Not + + BitAnd + + Add + + Sub + + From + + Copy, +{ + let alignment_mask = alignment - 1.into(); + (x + alignment_mask) & !alignment_mask +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/inst_common.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/inst_common.rs new file mode 100644 index 00000000000000..151dd4b9a107bd --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/inst_common.rs @@ -0,0 +1,24 @@ +//! A place to park MachInst::Inst fragments which are common across multiple architectures. + +use crate::ir::Inst as IRInst; + +//============================================================================ +// Instruction input "slots". +// +// We use these types to refer to operand numbers, and result numbers, together +// with the associated instruction, in a type-safe way. + +/// Identifier for a particular input of an instruction. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct InsnInput { + pub(crate) insn: IRInst, + pub(crate) input: usize, +} + +/// Identifier for a particular output of an instruction. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[allow(dead_code)] +pub(crate) struct InsnOutput { + pub(crate) insn: IRInst, + pub(crate) output: usize, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/isle.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/isle.rs new file mode 100644 index 00000000000000..8875097f1c5127 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/isle.rs @@ -0,0 +1,924 @@ +use crate::ir::{BlockCall, Value, ValueList}; +use alloc::boxed::Box; +use alloc::vec::Vec; +use smallvec::SmallVec; +use std::cell::Cell; + +pub use super::MachLabel; +use super::RetPair; +pub use crate::ir::{condcodes::CondCode, *}; +pub use crate::isa::{unwind::UnwindInst, TargetIsa}; +pub use crate::machinst::{ + ABIArg, ABIArgSlot, ABIMachineSpec, CallSite, InputSourceInst, Lower, LowerBackend, RealReg, + Reg, RelocDistance, Sig, VCodeInst, Writable, +}; +pub use crate::settings::{StackSwitchModel, TlsModel}; + +pub type Unit = (); +pub type ValueSlice = (ValueList, usize); +pub type ValueArray2 = [Value; 2]; +pub type ValueArray3 = [Value; 3]; +pub type BlockArray2 = [BlockCall; 2]; +pub type WritableReg = Writable; +pub type VecRetPair = Vec; +pub type VecMask = Vec; +pub type ValueRegs = crate::machinst::ValueRegs; +pub type WritableValueRegs = crate::machinst::ValueRegs; +pub type InstOutput = SmallVec<[ValueRegs; 2]>; +pub type InstOutputBuilder = Cell; +pub type BoxExternalName = Box; +pub type Range = (usize, usize); +pub type MachLabelSlice = [MachLabel]; +pub type BoxVecMachLabel = Box>; + +pub enum RangeView { + Empty, + NonEmpty { index: usize, rest: Range }, +} + +/// Helper macro to define methods in `prelude.isle` within `impl Context for +/// ...` for each backend. These methods are shared amongst all backends. +#[macro_export] +#[doc(hidden)] +macro_rules! isle_lower_prelude_methods { + () => { + crate::isle_lower_prelude_methods!(MInst); + }; + ($inst:ty) => { + crate::isle_common_prelude_methods!(); + + #[inline] + fn value_type(&mut self, val: Value) -> Type { + self.lower_ctx.dfg().value_type(val) + } + + #[inline] + fn value_reg(&mut self, reg: Reg) -> ValueRegs { + ValueRegs::one(reg) + } + + #[inline] + fn value_regs(&mut self, r1: Reg, r2: Reg) -> ValueRegs { + ValueRegs::two(r1, r2) + } + + #[inline] + fn writable_value_regs(&mut self, r1: WritableReg, r2: WritableReg) -> WritableValueRegs { + WritableValueRegs::two(r1, r2) + } + + #[inline] + fn writable_value_reg(&mut self, r: WritableReg) -> WritableValueRegs { + WritableValueRegs::one(r) + } + + #[inline] + fn value_regs_invalid(&mut self) -> ValueRegs { + ValueRegs::invalid() + } + + #[inline] + fn output_none(&mut self) -> InstOutput { + smallvec::smallvec![] + } + + #[inline] + fn output(&mut self, regs: ValueRegs) -> InstOutput { + smallvec::smallvec![regs] + } + + #[inline] + fn output_pair(&mut self, r1: ValueRegs, r2: ValueRegs) -> InstOutput { + smallvec::smallvec![r1, r2] + } + + #[inline] + fn output_builder_new(&mut self) -> InstOutputBuilder { + std::cell::Cell::new(InstOutput::new()) + } + + #[inline] + fn output_builder_push(&mut self, builder: &InstOutputBuilder, regs: ValueRegs) -> Unit { + let mut vec = builder.take(); + vec.push(regs); + builder.set(vec); + } + + #[inline] + fn output_builder_finish(&mut self, builder: &InstOutputBuilder) -> InstOutput { + builder.take() + } + + #[inline] + fn temp_writable_reg(&mut self, ty: Type) -> WritableReg { + let value_regs = self.lower_ctx.alloc_tmp(ty); + value_regs.only_reg().unwrap() + } + + #[inline] + fn is_valid_reg(&mut self, reg: Reg) -> bool { + use crate::machinst::valueregs::InvalidSentinel; + !reg.is_invalid_sentinel() + } + + #[inline] + fn invalid_reg(&mut self) -> Reg { + use crate::machinst::valueregs::InvalidSentinel; + Reg::invalid_sentinel() + } + + #[inline] + fn mark_value_used(&mut self, val: Value) { + self.lower_ctx.increment_lowered_uses(val); + } + + #[inline] + fn put_in_reg(&mut self, val: Value) -> Reg { + self.put_in_regs(val).only_reg().unwrap() + } + + #[inline] + fn put_in_regs(&mut self, val: Value) -> ValueRegs { + self.lower_ctx.put_value_in_regs(val) + } + + #[inline] + fn ensure_in_vreg(&mut self, reg: Reg, ty: Type) -> Reg { + self.lower_ctx.ensure_in_vreg(reg, ty) + } + + #[inline] + fn value_regs_get(&mut self, regs: ValueRegs, i: usize) -> Reg { + regs.regs()[i] + } + + #[inline] + fn value_regs_len(&mut self, regs: ValueRegs) -> usize { + regs.regs().len() + } + + #[inline] + fn value_list_slice(&mut self, list: ValueList) -> ValueSlice { + (list, 0) + } + + #[inline] + fn value_slice_empty(&mut self, slice: ValueSlice) -> Option<()> { + let (list, off) = slice; + if off >= list.len(&self.lower_ctx.dfg().value_lists) { + Some(()) + } else { + None + } + } + + #[inline] + fn value_slice_unwrap(&mut self, slice: ValueSlice) -> Option<(Value, ValueSlice)> { + let (list, off) = slice; + if let Some(val) = list.get(off, &self.lower_ctx.dfg().value_lists) { + Some((val, (list, off + 1))) + } else { + None + } + } + + #[inline] + fn value_slice_len(&mut self, slice: ValueSlice) -> usize { + let (list, off) = slice; + list.len(&self.lower_ctx.dfg().value_lists) - off + } + + #[inline] + fn value_slice_get(&mut self, slice: ValueSlice, idx: usize) -> Value { + let (list, off) = slice; + list.get(off + idx, &self.lower_ctx.dfg().value_lists) + .unwrap() + } + + #[inline] + fn writable_reg_to_reg(&mut self, r: WritableReg) -> Reg { + r.to_reg() + } + + #[inline] + fn inst_results(&mut self, inst: Inst) -> ValueSlice { + (self.lower_ctx.dfg().inst_results_list(inst), 0) + } + + #[inline] + fn first_result(&mut self, inst: Inst) -> Option { + self.lower_ctx.dfg().inst_results(inst).first().copied() + } + + #[inline] + fn inst_data(&mut self, inst: Inst) -> InstructionData { + self.lower_ctx.dfg().insts[inst] + } + + #[inline] + fn def_inst(&mut self, val: Value) -> Option { + self.lower_ctx.dfg().value_def(val).inst() + } + + #[inline] + fn i64_from_iconst(&mut self, val: Value) -> Option { + let inst = self.def_inst(val)?; + let constant = match self.lower_ctx.data(inst) { + InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm, + } => imm.bits(), + _ => return None, + }; + let ty = self.lower_ctx.output_ty(inst, 0); + let shift_amt = std::cmp::max(0, 64 - self.ty_bits(ty)); + Some((constant << shift_amt) >> shift_amt) + } + + fn i32_from_iconst(&mut self, val: Value) -> Option { + self.i64_from_iconst(val)?.try_into().ok() + } + + fn zero_value(&mut self, value: Value) -> Option { + let insn = self.def_inst(value); + if insn.is_some() { + let insn = insn.unwrap(); + let inst_data = self.lower_ctx.data(insn); + match inst_data { + InstructionData::Unary { + opcode: Opcode::Splat, + arg, + } => { + let arg = arg.clone(); + return self.zero_value(arg); + } + InstructionData::UnaryConst { + opcode: Opcode::Vconst | Opcode::F128const, + constant_handle, + } => { + let constant_data = + self.lower_ctx.get_constant_data(*constant_handle).clone(); + if constant_data.into_vec().iter().any(|&x| x != 0) { + return None; + } else { + return Some(value); + } + } + InstructionData::UnaryImm { imm, .. } => { + if imm.bits() == 0 { + return Some(value); + } else { + return None; + } + } + InstructionData::UnaryIeee16 { imm, .. } => { + if imm.bits() == 0 { + return Some(value); + } else { + return None; + } + } + InstructionData::UnaryIeee32 { imm, .. } => { + if imm.bits() == 0 { + return Some(value); + } else { + return None; + } + } + InstructionData::UnaryIeee64 { imm, .. } => { + if imm.bits() == 0 { + return Some(value); + } else { + return None; + } + } + _ => None, + } + } else { + None + } + } + + #[inline] + fn tls_model(&mut self, _: Type) -> TlsModel { + self.backend.flags().tls_model() + } + + #[inline] + fn tls_model_is_elf_gd(&mut self) -> Option<()> { + if self.backend.flags().tls_model() == TlsModel::ElfGd { + Some(()) + } else { + None + } + } + + #[inline] + fn tls_model_is_macho(&mut self) -> Option<()> { + if self.backend.flags().tls_model() == TlsModel::Macho { + Some(()) + } else { + None + } + } + + #[inline] + fn tls_model_is_coff(&mut self) -> Option<()> { + if self.backend.flags().tls_model() == TlsModel::Coff { + Some(()) + } else { + None + } + } + + #[inline] + fn preserve_frame_pointers(&mut self) -> Option<()> { + if self.backend.flags().preserve_frame_pointers() { + Some(()) + } else { + None + } + } + + #[inline] + fn stack_switch_model(&mut self) -> Option { + Some(self.backend.flags().stack_switch_model()) + } + + #[inline] + fn func_ref_data(&mut self, func_ref: FuncRef) -> (SigRef, ExternalName, RelocDistance) { + let funcdata = &self.lower_ctx.dfg().ext_funcs[func_ref]; + let reloc_distance = if funcdata.colocated { + RelocDistance::Near + } else { + RelocDistance::Far + }; + (funcdata.signature, funcdata.name.clone(), reloc_distance) + } + + #[inline] + fn box_external_name(&mut self, extname: ExternalName) -> BoxExternalName { + Box::new(extname) + } + + #[inline] + fn symbol_value_data( + &mut self, + global_value: GlobalValue, + ) -> Option<(ExternalName, RelocDistance, i64)> { + let (name, reloc, offset) = self.lower_ctx.symbol_value_data(global_value)?; + Some((name.clone(), reloc, offset)) + } + + #[inline] + fn reloc_distance_near(&mut self, dist: RelocDistance) -> Option<()> { + if dist == RelocDistance::Near { + Some(()) + } else { + None + } + } + + #[inline] + fn u128_from_immediate(&mut self, imm: Immediate) -> Option { + let bytes = self.lower_ctx.get_immediate_data(imm).as_slice(); + Some(u128::from_le_bytes(bytes.try_into().ok()?)) + } + + #[inline] + fn vconst_from_immediate(&mut self, imm: Immediate) -> Option { + Some(self.lower_ctx.use_constant(VCodeConstantData::Generated( + self.lower_ctx.get_immediate_data(imm).clone(), + ))) + } + + #[inline] + fn vec_mask_from_immediate(&mut self, imm: Immediate) -> Option { + let data = self.lower_ctx.get_immediate_data(imm); + if data.len() == 16 { + Some(Vec::from(data.as_slice())) + } else { + None + } + } + + #[inline] + fn u64_from_constant(&mut self, constant: Constant) -> Option { + let bytes = self.lower_ctx.get_constant_data(constant).as_slice(); + Some(u64::from_le_bytes(bytes.try_into().ok()?)) + } + + #[inline] + fn u128_from_constant(&mut self, constant: Constant) -> Option { + let bytes = self.lower_ctx.get_constant_data(constant).as_slice(); + Some(u128::from_le_bytes(bytes.try_into().ok()?)) + } + + #[inline] + fn emit_u64_le_const(&mut self, value: u64) -> VCodeConstant { + let data = VCodeConstantData::U64(value.to_le_bytes()); + self.lower_ctx.use_constant(data) + } + + #[inline] + fn emit_u128_le_const(&mut self, value: u128) -> VCodeConstant { + let data = VCodeConstantData::Generated(value.to_le_bytes().as_slice().into()); + self.lower_ctx.use_constant(data) + } + + #[inline] + fn const_to_vconst(&mut self, constant: Constant) -> VCodeConstant { + self.lower_ctx.use_constant(VCodeConstantData::Pool( + constant, + self.lower_ctx.get_constant_data(constant).clone(), + )) + } + + fn only_writable_reg(&mut self, regs: WritableValueRegs) -> Option { + regs.only_reg() + } + + fn writable_regs_get(&mut self, regs: WritableValueRegs, idx: usize) -> WritableReg { + regs.regs()[idx] + } + + fn abi_num_args(&mut self, abi: Sig) -> usize { + self.lower_ctx.sigs().num_args(abi) + } + + fn abi_get_arg(&mut self, abi: Sig, idx: usize) -> ABIArg { + self.lower_ctx.sigs().get_arg(abi, idx) + } + + fn abi_num_rets(&mut self, abi: Sig) -> usize { + self.lower_ctx.sigs().num_rets(abi) + } + + fn abi_get_ret(&mut self, abi: Sig, idx: usize) -> ABIArg { + self.lower_ctx.sigs().get_ret(abi, idx) + } + + fn abi_ret_arg(&mut self, abi: Sig) -> Option { + self.lower_ctx.sigs().get_ret_arg(abi) + } + + fn abi_no_ret_arg(&mut self, abi: Sig) -> Option<()> { + if let Some(_) = self.lower_ctx.sigs().get_ret_arg(abi) { + None + } else { + Some(()) + } + } + + fn abi_arg_only_slot(&mut self, arg: &ABIArg) -> Option { + match arg { + &ABIArg::Slots { ref slots, .. } => { + if slots.len() == 1 { + Some(slots[0]) + } else { + None + } + } + _ => None, + } + } + + fn abi_arg_implicit_pointer(&mut self, arg: &ABIArg) -> Option<(ABIArgSlot, i64, Type)> { + match arg { + &ABIArg::ImplicitPtrArg { + pointer, + offset, + ty, + .. + } => Some((pointer, offset, ty)), + _ => None, + } + } + + fn abi_unwrap_ret_area_ptr(&mut self) -> Reg { + self.lower_ctx.abi().ret_area_ptr().unwrap() + } + + fn abi_stackslot_addr( + &mut self, + dst: WritableReg, + stack_slot: StackSlot, + offset: Offset32, + ) -> MInst { + let offset = u32::try_from(i32::from(offset)).unwrap(); + self.lower_ctx + .abi() + .sized_stackslot_addr(stack_slot, offset, dst) + .into() + } + + fn abi_dynamic_stackslot_addr( + &mut self, + dst: WritableReg, + stack_slot: DynamicStackSlot, + ) -> MInst { + assert!(self + .lower_ctx + .abi() + .dynamic_stackslot_offsets() + .is_valid(stack_slot)); + self.lower_ctx + .abi() + .dynamic_stackslot_addr(stack_slot, dst) + .into() + } + + fn real_reg_to_reg(&mut self, reg: RealReg) -> Reg { + Reg::from(reg) + } + + fn real_reg_to_writable_reg(&mut self, reg: RealReg) -> WritableReg { + Writable::from_reg(Reg::from(reg)) + } + + fn is_sinkable_inst(&mut self, val: Value) -> Option { + let input = self.lower_ctx.get_value_as_source_or_const(val); + + if let InputSourceInst::UniqueUse(inst, _) = input.inst { + Some(inst) + } else { + None + } + } + + #[inline] + fn sink_inst(&mut self, inst: Inst) { + self.lower_ctx.sink_inst(inst); + } + + #[inline] + fn maybe_uextend(&mut self, value: Value) -> Option { + if let Some(def_inst) = self.def_inst(value) { + if let InstructionData::Unary { + opcode: Opcode::Uextend, + arg, + } = self.lower_ctx.data(def_inst) + { + return Some(*arg); + } + } + + Some(value) + } + + #[inline] + fn uimm8(&mut self, x: Imm64) -> Option { + let x64: i64 = x.into(); + let x8: u8 = x64.try_into().ok()?; + Some(x8) + } + + #[inline] + fn preg_to_reg(&mut self, preg: PReg) -> Reg { + preg.into() + } + + #[inline] + fn gen_move(&mut self, ty: Type, dst: WritableReg, src: Reg) -> MInst { + <$inst>::gen_move(dst, src, ty).into() + } + + /// Generate the return instruction. + fn gen_return(&mut self, (list, off): ValueSlice) { + let rets = (off..list.len(&self.lower_ctx.dfg().value_lists)) + .map(|ix| { + let val = list.get(ix, &self.lower_ctx.dfg().value_lists).unwrap(); + self.put_in_regs(val) + }) + .collect(); + self.lower_ctx.gen_return(rets); + } + + /// Same as `shuffle32_from_imm`, but for 64-bit lane shuffles. + fn shuffle64_from_imm(&mut self, imm: Immediate) -> Option<(u8, u8)> { + use crate::machinst::isle::shuffle_imm_as_le_lane_idx; + + let bytes = self.lower_ctx.get_immediate_data(imm).as_slice(); + Some(( + shuffle_imm_as_le_lane_idx(8, &bytes[0..8])?, + shuffle_imm_as_le_lane_idx(8, &bytes[8..16])?, + )) + } + + /// Attempts to interpret the shuffle immediate `imm` as a shuffle of + /// 32-bit lanes, returning four integers, each of which is less than 8, + /// which represents a permutation of 32-bit lanes as specified by + /// `imm`. + /// + /// For example the shuffle immediate + /// + /// `0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27` + /// + /// would return `Some((0, 2, 4, 6))`. + fn shuffle32_from_imm(&mut self, imm: Immediate) -> Option<(u8, u8, u8, u8)> { + use crate::machinst::isle::shuffle_imm_as_le_lane_idx; + + let bytes = self.lower_ctx.get_immediate_data(imm).as_slice(); + Some(( + shuffle_imm_as_le_lane_idx(4, &bytes[0..4])?, + shuffle_imm_as_le_lane_idx(4, &bytes[4..8])?, + shuffle_imm_as_le_lane_idx(4, &bytes[8..12])?, + shuffle_imm_as_le_lane_idx(4, &bytes[12..16])?, + )) + } + + /// Same as `shuffle32_from_imm`, but for 16-bit lane shuffles. + fn shuffle16_from_imm( + &mut self, + imm: Immediate, + ) -> Option<(u8, u8, u8, u8, u8, u8, u8, u8)> { + use crate::machinst::isle::shuffle_imm_as_le_lane_idx; + let bytes = self.lower_ctx.get_immediate_data(imm).as_slice(); + Some(( + shuffle_imm_as_le_lane_idx(2, &bytes[0..2])?, + shuffle_imm_as_le_lane_idx(2, &bytes[2..4])?, + shuffle_imm_as_le_lane_idx(2, &bytes[4..6])?, + shuffle_imm_as_le_lane_idx(2, &bytes[6..8])?, + shuffle_imm_as_le_lane_idx(2, &bytes[8..10])?, + shuffle_imm_as_le_lane_idx(2, &bytes[10..12])?, + shuffle_imm_as_le_lane_idx(2, &bytes[12..14])?, + shuffle_imm_as_le_lane_idx(2, &bytes[14..16])?, + )) + } + + fn safe_divisor_from_imm64(&mut self, ty: Type, val: Imm64) -> Option { + let minus_one = if ty.bytes() == 8 { + -1 + } else { + (1 << (ty.bytes() * 8)) - 1 + }; + let bits = val.bits() & minus_one; + if bits == 0 || bits == minus_one { + None + } else { + Some(bits as u64) + } + } + + fn single_target(&mut self, targets: &MachLabelSlice) -> Option { + if targets.len() == 1 { + Some(targets[0]) + } else { + None + } + } + + fn two_targets(&mut self, targets: &MachLabelSlice) -> Option<(MachLabel, MachLabel)> { + if targets.len() == 2 { + Some((targets[0], targets[1])) + } else { + None + } + } + + fn jump_table_targets( + &mut self, + targets: &MachLabelSlice, + ) -> Option<(MachLabel, BoxVecMachLabel)> { + use std::boxed::Box; + if targets.is_empty() { + return None; + } + + let default_label = targets[0]; + let jt_targets = Box::new(targets[1..].to_vec()); + Some((default_label, jt_targets)) + } + + fn jump_table_size(&mut self, targets: &BoxVecMachLabel) -> u32 { + targets.len() as u32 + } + + fn add_range_fact(&mut self, reg: Reg, bits: u16, min: u64, max: u64) -> Reg { + self.lower_ctx.add_range_fact(reg, bits, min, max); + reg + } + + fn value_is_unused(&mut self, val: Value) -> bool { + self.lower_ctx.value_is_unused(val) + } + }; +} + +/// Returns the `size`-byte lane referred to by the shuffle immediate specified +/// in `bytes`. +/// +/// This helper is used by `shuffleNN_from_imm` above and is used to interpret a +/// byte-based shuffle as a higher-level shuffle of bigger lanes. This will see +/// if the `bytes` specified, which must have `size` length, specifies a lane in +/// vectors aligned to a `size`-byte boundary. +/// +/// Returns `None` if `bytes` doesn't specify a `size`-byte lane aligned +/// appropriately, or returns `Some(n)` where `n` is the index of the lane being +/// shuffled. +pub fn shuffle_imm_as_le_lane_idx(size: u8, bytes: &[u8]) -> Option { + assert_eq!(bytes.len(), usize::from(size)); + + // The first index in `bytes` must be aligned to a `size` boundary for the + // bytes to be a valid specifier for a lane of `size` bytes. + if bytes[0] % size != 0 { + return None; + } + + // Afterwards the bytes must all be one larger than the prior to specify a + // contiguous sequence of bytes that's being shuffled. Basically `bytes` + // must refer to the entire `size`-byte lane, in little-endian order. + for i in 0..size - 1 { + let idx = usize::from(i); + if bytes[idx] + 1 != bytes[idx + 1] { + return None; + } + } + + // All of the `bytes` are in-order, meaning that this is a valid shuffle + // immediate to specify a lane of `size` bytes. The index, when viewed as + // `size`-byte immediates, will be the first byte divided by the byte size. + Some(bytes[0] / size) +} + +/// Helpers specifically for machines that use `abi::CallSite`. +#[macro_export] +#[doc(hidden)] +macro_rules! isle_prelude_caller_methods { + ($abicaller:ty) => { + fn gen_call( + &mut self, + sig_ref: SigRef, + extname: ExternalName, + dist: RelocDistance, + args @ (inputs, off): ValueSlice, + ) -> InstOutput { + let caller_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()); + let sig = &self.lower_ctx.dfg().signatures[sig_ref]; + let num_rets = sig.returns.len(); + let caller = <$abicaller>::from_func( + self.lower_ctx.sigs(), + sig_ref, + &extname, + IsTailCall::No, + dist, + caller_conv, + self.backend.flags().clone(), + ); + + assert_eq!( + inputs.len(&self.lower_ctx.dfg().value_lists) - off, + sig.params.len() + ); + + crate::machinst::isle::gen_call_common(&mut self.lower_ctx, num_rets, caller, args) + } + + fn gen_call_indirect( + &mut self, + sig_ref: SigRef, + val: Value, + args @ (inputs, off): ValueSlice, + ) -> InstOutput { + let caller_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()); + let ptr = self.put_in_reg(val); + let sig = &self.lower_ctx.dfg().signatures[sig_ref]; + let num_rets = sig.returns.len(); + let caller = <$abicaller>::from_ptr( + self.lower_ctx.sigs(), + sig_ref, + ptr, + IsTailCall::No, + caller_conv, + self.backend.flags().clone(), + ); + + assert_eq!( + inputs.len(&self.lower_ctx.dfg().value_lists) - off, + sig.params.len() + ); + + crate::machinst::isle::gen_call_common(&mut self.lower_ctx, num_rets, caller, args) + } + + fn gen_return_call( + &mut self, + callee_sig: SigRef, + callee: ExternalName, + distance: RelocDistance, + args: ValueSlice, + ) -> InstOutput { + let caller_conv = isa::CallConv::Tail; + debug_assert_eq!( + self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()), + caller_conv, + "Can only do `return_call`s from within a `tail` calling convention function" + ); + + let call_site = <$abicaller>::from_func( + self.lower_ctx.sigs(), + callee_sig, + &callee, + IsTailCall::Yes, + distance, + caller_conv, + self.backend.flags().clone(), + ); + call_site.emit_return_call(self.lower_ctx, args, self.backend); + + InstOutput::new() + } + + fn gen_return_call_indirect( + &mut self, + callee_sig: SigRef, + callee: Value, + args: ValueSlice, + ) -> InstOutput { + let caller_conv = isa::CallConv::Tail; + debug_assert_eq!( + self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()), + caller_conv, + "Can only do `return_call`s from within a `tail` calling convention function" + ); + + let callee = self.put_in_reg(callee); + + let call_site = <$abicaller>::from_ptr( + self.lower_ctx.sigs(), + callee_sig, + callee, + IsTailCall::Yes, + caller_conv, + self.backend.flags().clone(), + ); + call_site.emit_return_call(self.lower_ctx, args, self.backend); + + InstOutput::new() + } + }; +} + +fn gen_call_common_args( + ctx: &mut Lower<'_, M::I>, + call_site: &mut CallSite, + (inputs, off): ValueSlice, +) { + let num_args = call_site.num_args(ctx.sigs()); + + assert_eq!(inputs.len(&ctx.dfg().value_lists) - off, num_args); + let mut arg_regs = vec![]; + for i in 0..num_args { + let input = inputs.get(off + i, &ctx.dfg().value_lists).unwrap(); + arg_regs.push(ctx.put_value_in_regs(input)); + } + for (i, arg_regs) in arg_regs.iter().enumerate() { + call_site.emit_copy_regs_to_buffer(ctx, i, *arg_regs); + } + for (i, arg_regs) in arg_regs.iter().enumerate() { + call_site.gen_arg(ctx, i, *arg_regs); + } +} + +pub fn gen_call_common( + ctx: &mut Lower<'_, M::I>, + num_rets: usize, + mut caller: CallSite, + args: ValueSlice, +) -> InstOutput { + gen_call_common_args(ctx, &mut caller, args); + + // Handle retvals prior to emitting call, so the + // constraints are on the call instruction; but buffer the + // instructions till after the call. + let mut outputs = InstOutput::new(); + let mut retval_insts = crate::machinst::abi::SmallInstVec::new(); + // We take the *last* `num_rets` returns of the sig: + // this skips a StructReturn, if any, that is present. + let sigdata_num_rets = caller.num_rets(ctx.sigs()); + debug_assert!(num_rets <= sigdata_num_rets); + for i in (sigdata_num_rets - num_rets)..sigdata_num_rets { + let (retval_inst, retval_regs) = caller.gen_retval(ctx, i); + retval_insts.extend(retval_inst.into_iter()); + outputs.push(retval_regs); + } + + caller.emit_call(ctx); + + for inst in retval_insts { + ctx.emit(inst); + } + + outputs +} + +/// This structure is used to implement the ISLE-generated `Context` trait and +/// internally has a temporary reference to a machinst `LowerCtx`. +pub(crate) struct IsleContext<'a, 'b, I, B> +where + I: VCodeInst, + B: LowerBackend, +{ + pub lower_ctx: &'a mut Lower<'b, I>, + pub backend: &'a B, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/lower.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/lower.rs new file mode 100644 index 00000000000000..ea4fda7fc8e871 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/lower.rs @@ -0,0 +1,1603 @@ +//! This module implements lowering (instruction selection) from Cranelift IR +//! to machine instructions with virtual registers. This is *almost* the final +//! machine code, except for register allocation. + +// TODO: separate the IR-query core of `Lower` from the lowering logic built on +// top of it, e.g. the side-effect/coloring analysis and the scan support. + +use crate::entity::SecondaryMap; +use crate::inst_predicates::{has_lowering_side_effect, is_constant_64bit}; +use crate::ir::pcc::{Fact, FactContext, PccError, PccResult}; +use crate::ir::{ + ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, ExternalName, Function, + GlobalValue, GlobalValueData, Immediate, Inst, InstructionData, MemFlags, RelSourceLoc, Type, + Value, ValueDef, ValueLabelAssignments, ValueLabelStart, +}; +use crate::machinst::valueregs::InvalidSentinel; +use crate::machinst::{ + writable_value_regs, BackwardsInsnIndex, BlockIndex, BlockLoweringOrder, Callee, InsnIndex, + LoweredBlock, MachLabel, Reg, SigSet, VCode, VCodeBuilder, VCodeConstant, VCodeConstantData, + VCodeConstants, VCodeInst, ValueRegs, Writable, +}; +use crate::settings::Flags; +use crate::{trace, CodegenError, CodegenResult}; +use alloc::vec::Vec; +use cranelift_control::ControlPlane; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::{smallvec, SmallVec}; +use std::fmt::Debug; + +use super::{VCodeBuildDirection, VRegAllocator}; + +/// A vector of ValueRegs, used to represent the outputs of an instruction. +pub type InstOutput = SmallVec<[ValueRegs; 2]>; + +/// An "instruction color" partitions CLIF instructions by side-effecting ops. +/// All instructions with the same "color" are guaranteed not to be separated by +/// any side-effecting op (for this purpose, loads are also considered +/// side-effecting, to avoid subtle questions w.r.t. the memory model), and +/// furthermore, it is guaranteed that for any two instructions A and B such +/// that color(A) == color(B), either A dominates B and B postdominates A, or +/// vice-versa. (For now, in practice, only ops in the same basic block can ever +/// have the same color, trivially providing the second condition.) Intuitively, +/// this means that the ops of the same color must always execute "together", as +/// part of one atomic contiguous section of the dynamic execution trace, and +/// they can be freely permuted (modulo true dataflow dependencies) without +/// affecting program behavior. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct InstColor(u32); +impl InstColor { + fn new(n: u32) -> InstColor { + InstColor(n) + } + + /// Get an arbitrary index representing this color. The index is unique + /// *within a single function compilation*, but indices may be reused across + /// functions. + pub fn get(self) -> u32 { + self.0 + } +} + +/// A representation of all of the ways in which a value is available, aside +/// from as a direct register. +/// +/// - An instruction, if it would be allowed to occur at the current location +/// instead (see [Lower::get_input_as_source_or_const()] for more details). +/// +/// - A constant, if the value is known to be a constant. +#[derive(Clone, Copy, Debug)] +pub struct NonRegInput { + /// An instruction produces this value (as the given output), and its + /// computation (and side-effect if applicable) could occur at the + /// current instruction's location instead. + /// + /// If this instruction's operation is merged into the current instruction, + /// the backend must call [Lower::sink_inst()]. + /// + /// This enum indicates whether this use of the source instruction + /// is unique or not. + pub inst: InputSourceInst, + /// The value is a known constant. + pub constant: Option, +} + +/// When examining an input to an instruction, this enum provides one +/// of several options: there is or isn't a single instruction (that +/// we can see and merge with) that produces that input's value, and +/// we are or aren't the single user of that instruction. +#[derive(Clone, Copy, Debug)] +pub enum InputSourceInst { + /// The input in question is the single, unique use of the given + /// instruction and output index, and it can be sunk to the + /// location of this input. + UniqueUse(Inst, usize), + /// The input in question is one of multiple uses of the given + /// instruction. It can still be sunk to the location of this + /// input. + Use(Inst, usize), + /// We cannot determine which instruction produced the input, or + /// it is one of several instructions (e.g., due to a control-flow + /// merge and blockparam), or the source instruction cannot be + /// allowed to sink to the current location due to side-effects. + None, +} + +impl InputSourceInst { + /// Get the instruction and output index for this source, whether + /// we are its single or one of many users. + pub fn as_inst(&self) -> Option<(Inst, usize)> { + match self { + &InputSourceInst::UniqueUse(inst, output_idx) + | &InputSourceInst::Use(inst, output_idx) => Some((inst, output_idx)), + &InputSourceInst::None => None, + } + } +} + +/// A machine backend. +pub trait LowerBackend { + /// The machine instruction type. + type MInst: VCodeInst; + + /// Lower a single instruction. + /// + /// For a branch, this function should not generate the actual branch + /// instruction. However, it must force any values it needs for the branch + /// edge (block-param actuals) into registers, because the actual branch + /// generation (`lower_branch()`) happens *after* any possible merged + /// out-edge. + /// + /// Returns `None` if no lowering for the instruction was found. + fn lower(&self, ctx: &mut Lower, inst: Inst) -> Option; + + /// Lower a block-terminating group of branches (which together can be seen + /// as one N-way branch), given a vcode MachLabel for each target. + /// + /// Returns `None` if no lowering for the branch was found. + fn lower_branch( + &self, + ctx: &mut Lower, + inst: Inst, + targets: &[MachLabel], + ) -> Option<()>; + + /// A bit of a hack: give a fixed register that always holds the result of a + /// `get_pinned_reg` instruction, if known. This allows elision of moves + /// into the associated vreg, instead using the real reg directly. + fn maybe_pinned_reg(&self) -> Option { + None + } + + /// The type of state carried between `check_fact` invocations. + type FactFlowState: Default + Clone + Debug; + + /// Check any facts about an instruction, given VCode with facts + /// on VRegs. Takes mutable `VCode` so that it can propagate some + /// kinds of facts automatically. + fn check_fact( + &self, + _ctx: &FactContext<'_>, + _vcode: &mut VCode, + _inst: InsnIndex, + _state: &mut Self::FactFlowState, + ) -> PccResult<()> { + Err(PccError::UnimplementedBackend) + } +} + +/// Machine-independent lowering driver / machine-instruction container. Maintains a correspondence +/// from original Inst to MachInsts. +pub struct Lower<'func, I: VCodeInst> { + /// The function to lower. + f: &'func Function, + + /// Lowered machine instructions. + vcode: VCodeBuilder, + + /// VReg allocation context, given to the vcode field at build time to finalize the vcode. + vregs: VRegAllocator, + + /// Mapping from `Value` (SSA value in IR) to virtual register. + value_regs: SecondaryMap>, + + /// sret registers, if needed. + sret_reg: Option>, + + /// Instruction colors at block exits. From this map, we can recover all + /// instruction colors by scanning backward from the block end and + /// decrementing on any color-changing (side-effecting) instruction. + block_end_colors: SecondaryMap, + + /// Instruction colors at side-effecting ops. This is the *entry* color, + /// i.e., the version of global state that exists before an instruction + /// executes. For each side-effecting instruction, the *exit* color is its + /// entry color plus one. + side_effect_inst_entry_colors: FxHashMap, + + /// Current color as we scan during lowering. While we are lowering an + /// instruction, this is equal to the color *at entry to* the instruction. + cur_scan_entry_color: Option, + + /// Current instruction as we scan during lowering. + cur_inst: Option, + + /// Instruction constant values, if known. + inst_constants: FxHashMap, + + /// Use-counts per SSA value, as counted in the input IR. These + /// are "coarsened", in the abstract-interpretation sense: we only + /// care about "0, 1, many" states, as this is all we need and + /// this lets us do an efficient fixpoint analysis. + /// + /// See doc comment on `ValueUseState` for more details. + value_ir_uses: SecondaryMap, + + /// Actual uses of each SSA value so far, incremented while lowering. + value_lowered_uses: SecondaryMap, + + /// Effectful instructions that have been sunk; they are not codegen'd at + /// their original locations. + inst_sunk: FxHashSet, + + /// Instructions collected for the CLIF inst in progress, in forward order. + ir_insts: Vec, + + /// The register to use for GetPinnedReg, if any, on this architecture. + pinned_reg: Option, + + /// Compilation flags. + flags: Flags, +} + +/// How is a value used in the IR? +/// +/// This can be seen as a coarsening of an integer count. We only need +/// distinct states for zero, one, or many. +/// +/// This analysis deserves further explanation. The basic idea is that +/// we want to allow instruction lowering to know whether a value that +/// an instruction references is *only* referenced by that one use, or +/// by others as well. This is necessary to know when we might want to +/// move a side-effect: we cannot, for example, duplicate a load, so +/// we cannot let instruction lowering match a load as part of a +/// subpattern and potentially incorporate it. +/// +/// Note that a lot of subtlety comes into play once we have +/// *indirect* uses. The classical example of this in our development +/// history was the x86 compare instruction, which is incorporated +/// into flags users (e.g. `selectif`, `trueif`, branches) and can +/// subsequently incorporate loads, or at least we would like it +/// to. However, danger awaits: the compare might be the only user of +/// a load, so we might think we can just move the load (and nothing +/// is duplicated -- success!), except that the compare itself is +/// codegen'd in multiple places, where it is incorporated as a +/// subpattern itself. +/// +/// So we really want a notion of "unique all the way along the +/// matching path". Rust's `&T` and `&mut T` offer a partial analogy +/// to the semantics that we want here: we want to know when we've +/// matched a unique use of an instruction, and that instruction's +/// unique use of another instruction, etc, just as `&mut T` can only +/// be obtained by going through a chain of `&mut T`. If one has a +/// `&T` to a struct containing `&mut T` (one of several uses of an +/// instruction that itself has a unique use of an instruction), one +/// can only get a `&T` (one can only get a "I am one of several users +/// of this instruction" result). +/// +/// We could track these paths, either dynamically as one "looks up the operand +/// tree" or precomputed. But the former requires state and means that the +/// `Lower` API carries that state implicitly, which we'd like to avoid if we +/// can. And the latter implies O(n^2) storage: it is an all-pairs property (is +/// inst `i` unique from the point of view of `j`). +/// +/// To make matters even a little more complex still, a value that is +/// not uniquely used when initially viewing the IR can *become* +/// uniquely used, at least as a root allowing further unique uses of +/// e.g. loads to merge, if no other instruction actually merges +/// it. To be more concrete, if we have `v1 := load; v2 := op v1; v3 +/// := op v2; v4 := op v2` then `v2` is non-uniquely used, so from the +/// point of view of lowering `v4` or `v3`, we cannot merge the load +/// at `v1`. But if we decide just to use the assigned register for +/// `v2` at both `v3` and `v4`, then we only actually codegen `v2` +/// once, so it *is* a unique root at that point and we *can* merge +/// the load. +/// +/// Note also that the color scheme is not sufficient to give us this +/// information, for various reasons: reasoning about side-effects +/// does not tell us about potential duplication of uses through pure +/// ops. +/// +/// To keep things simple and avoid error-prone lowering APIs that +/// would extract more information about whether instruction merging +/// happens or not (we don't have that info now, and it would be +/// difficult to refactor to get it and make that refactor 100% +/// correct), we give up on the above "can become unique if not +/// actually merged" point. Instead, we compute a +/// transitive-uniqueness. That is what this enum represents. +/// +/// There is one final caveat as well to the result of this analysis. Notably, +/// we define some instructions to be "root" instructions, which means that we +/// assume they will always be codegen'd at the root of a matching tree, and not +/// matched. (This comes with the caveat that we actually enforce this property +/// by making them "opaque" to subtree matching in +/// `get_value_as_source_or_const`). Because they will always be codegen'd once, +/// they in some sense "reset" multiplicity: these root instructions can be used +/// many times, but because their result(s) are only computed once, they only +/// use their inputs once. +/// +/// We currently define all multi-result instructions to be "root" instructions, +/// because it is too complex to reason about matching through them, and they +/// cause too-coarse-grained approximation of multiplicity otherwise: the +/// analysis would have to assume (as it used to!) that they are always +/// multiply-used, simply because they have multiple outputs even if those +/// outputs are used only once. +/// +/// In the future we could define other instructions to be "root" instructions +/// as well, if we make the corresponding change to get_value_as_source_or_const +/// as well. +/// +/// To define `ValueUseState` more plainly: a value is `Unused` if no references +/// exist to it; `Once` if only one other op refers to it, *and* that other op +/// is `Unused` or `Once`; and `Multiple` otherwise. In other words, `Multiple` +/// is contagious (except through root instructions): even if an op's result +/// value is directly used only once in the CLIF, that value is `Multiple` if +/// the op that uses it is itself used multiple times (hence could be codegen'd +/// multiple times). In brief, this analysis tells us whether, if every op +/// merged all of its operand tree, a given op could be codegen'd in more than +/// one place. +/// +/// To compute this, we first consider direct uses. At this point +/// `Unused` answers are correct, `Multiple` answers are correct, but +/// some `Once`s may change to `Multiple`s. Then we propagate +/// `Multiple` transitively using a workqueue/fixpoint algorithm. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ValueUseState { + /// Not used at all. + Unused, + /// Used exactly once. + Once, + /// Used multiple times. + Multiple, +} + +impl ValueUseState { + /// Add one use. + fn inc(&mut self) { + let new = match self { + Self::Unused => Self::Once, + Self::Once | Self::Multiple => Self::Multiple, + }; + *self = new; + } +} + +/// Notion of "relocation distance". This gives an estimate of how far away a symbol will be from a +/// reference. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RelocDistance { + /// Target of relocation is "nearby". The threshold for this is fuzzy but should be interpreted + /// as approximately "within the compiled output of one module"; e.g., within AArch64's +/- + /// 128MB offset. If unsure, use `Far` instead. + Near, + /// Target of relocation could be anywhere in the address space. + Far, +} + +impl<'func, I: VCodeInst> Lower<'func, I> { + /// Prepare a new lowering context for the given IR function. + pub fn new( + f: &'func Function, + abi: Callee, + emit_info: I::Info, + block_order: BlockLoweringOrder, + sigs: SigSet, + flags: Flags, + ) -> CodegenResult { + let constants = VCodeConstants::with_capacity(f.dfg.constants.len()); + let vcode = VCodeBuilder::new( + sigs, + abi, + emit_info, + block_order, + constants, + VCodeBuildDirection::Backward, + ); + + // We usually need two VRegs per instruction result, plus extras for + // various temporaries, but two per Value is a good starting point. + let mut vregs = VRegAllocator::with_capacity(f.dfg.num_values() * 2); + + let mut value_regs = SecondaryMap::with_default(ValueRegs::invalid()); + + // Assign a vreg to each block param and each inst result. + for bb in f.layout.blocks() { + for ¶m in f.dfg.block_params(bb) { + let ty = f.dfg.value_type(param); + if value_regs[param].is_invalid() { + let regs = vregs.alloc_with_maybe_fact(ty, f.dfg.facts[param].clone())?; + value_regs[param] = regs; + trace!("bb {} param {}: regs {:?}", bb, param, regs); + } + } + for inst in f.layout.block_insts(bb) { + for &result in f.dfg.inst_results(inst) { + let ty = f.dfg.value_type(result); + if value_regs[result].is_invalid() && !ty.is_invalid() { + let regs = vregs.alloc_with_maybe_fact(ty, f.dfg.facts[result].clone())?; + value_regs[result] = regs; + trace!( + "bb {} inst {} ({:?}): result {} regs {:?}", + bb, + inst, + f.dfg.insts[inst], + result, + regs, + ); + } + } + } + } + + // Find the sret register, if it's used. + let mut sret_param = None; + for ret in vcode.abi().signature().returns.iter() { + if ret.purpose == ArgumentPurpose::StructReturn { + let entry_bb = f.stencil.layout.entry_block().unwrap(); + for (¶m, sig_param) in f + .dfg + .block_params(entry_bb) + .iter() + .zip(vcode.abi().signature().params.iter()) + { + if sig_param.purpose == ArgumentPurpose::StructReturn { + assert!(sret_param.is_none()); + sret_param = Some(param); + } + } + + assert!(sret_param.is_some()); + } + } + + let sret_reg = sret_param.map(|param| { + let regs = value_regs[param]; + assert!(regs.len() == 1); + regs + }); + + // Compute instruction colors, find constant instructions, and find instructions with + // side-effects, in one combined pass. + let mut cur_color = 0; + let mut block_end_colors = SecondaryMap::with_default(InstColor::new(0)); + let mut side_effect_inst_entry_colors = FxHashMap::default(); + let mut inst_constants = FxHashMap::default(); + for bb in f.layout.blocks() { + cur_color += 1; + for inst in f.layout.block_insts(bb) { + let side_effect = has_lowering_side_effect(f, inst); + + trace!("bb {} inst {} has color {}", bb, inst, cur_color); + if side_effect { + side_effect_inst_entry_colors.insert(inst, InstColor::new(cur_color)); + trace!(" -> side-effecting; incrementing color for next inst"); + cur_color += 1; + } + + // Determine if this is a constant; if so, add to the table. + if let Some(c) = is_constant_64bit(f, inst) { + trace!(" -> constant: {}", c); + inst_constants.insert(inst, c); + } + } + + block_end_colors[bb] = InstColor::new(cur_color); + } + + let value_ir_uses = compute_use_states(f, sret_param); + + Ok(Lower { + f, + vcode, + vregs, + value_regs, + sret_reg, + block_end_colors, + side_effect_inst_entry_colors, + inst_constants, + value_ir_uses, + value_lowered_uses: SecondaryMap::default(), + inst_sunk: FxHashSet::default(), + cur_scan_entry_color: None, + cur_inst: None, + ir_insts: vec![], + pinned_reg: None, + flags, + }) + } + + pub fn sigs(&self) -> &SigSet { + self.vcode.sigs() + } + + pub fn sigs_mut(&mut self) -> &mut SigSet { + self.vcode.sigs_mut() + } + + fn gen_arg_setup(&mut self) { + if let Some(entry_bb) = self.f.layout.entry_block() { + trace!( + "gen_arg_setup: entry BB {} args are:\n{:?}", + entry_bb, + self.f.dfg.block_params(entry_bb) + ); + + for (i, param) in self.f.dfg.block_params(entry_bb).iter().enumerate() { + if self.value_ir_uses[*param] == ValueUseState::Unused { + continue; + } + let regs = writable_value_regs(self.value_regs[*param]); + for insn in self + .vcode + .vcode + .abi + .gen_copy_arg_to_regs(&self.vcode.vcode.sigs, i, regs, &mut self.vregs) + .into_iter() + { + self.emit(insn); + } + } + if let Some(insn) = self + .vcode + .vcode + .abi + .gen_retval_area_setup(&self.vcode.vcode.sigs, &mut self.vregs) + { + self.emit(insn); + } + + // The `args` instruction below must come first. Finish + // the current "IR inst" (with a default source location, + // as for other special instructions inserted during + // lowering) and continue the scan backward. + self.finish_ir_inst(Default::default()); + + if let Some(insn) = self.vcode.vcode.abi.take_args() { + self.emit(insn); + } + } + } + + /// Generate the return instruction. + pub fn gen_return(&mut self, rets: Vec>) { + let mut out_rets = vec![]; + + let mut rets = rets.into_iter(); + for (i, ret) in self + .abi() + .signature() + .returns + .clone() + .into_iter() + .enumerate() + { + let regs = if ret.purpose == ArgumentPurpose::StructReturn { + self.sret_reg.unwrap() + } else { + rets.next().unwrap() + }; + + let (regs, insns) = self.vcode.abi().gen_copy_regs_to_retval( + self.vcode.sigs(), + i, + regs, + &mut self.vregs, + ); + out_rets.extend(regs); + for insn in insns { + self.emit(insn); + } + } + + // Hack: generate a virtual instruction that uses vmctx in + // order to keep it alive for the duration of the function, + // for the benefit of debuginfo. + if self.f.dfg.values_labels.is_some() { + if let Some(vmctx_val) = self.f.special_param(ArgumentPurpose::VMContext) { + if self.value_ir_uses[vmctx_val] != ValueUseState::Unused { + let vmctx_reg = self.value_regs[vmctx_val].only_reg().unwrap(); + self.emit(I::gen_dummy_use(vmctx_reg)); + } + } + } + + let inst = self.abi().gen_rets(out_rets); + self.emit(inst); + } + + /// Has this instruction been sunk to a use-site (i.e., away from its + /// original location)? + fn is_inst_sunk(&self, inst: Inst) -> bool { + self.inst_sunk.contains(&inst) + } + + // Is any result of this instruction needed? + fn is_any_inst_result_needed(&self, inst: Inst) -> bool { + self.f + .dfg + .inst_results(inst) + .iter() + .any(|&result| self.value_lowered_uses[result] > 0) + } + + fn lower_clif_block>( + &mut self, + backend: &B, + block: Block, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult<()> { + self.cur_scan_entry_color = Some(self.block_end_colors[block]); + // Lowering loop: + // - For each non-branch instruction, in reverse order: + // - If side-effecting (load, store, branch/call/return, + // possible trap), or if used outside of this block, or if + // demanded by another inst, then lower. + // + // That's it! Lowering of side-effecting ops will force all *needed* + // (live) non-side-effecting ops to be lowered at the right places, via + // the `use_input_reg()` callback on the `Lower` (that's us). That's + // because `use_input_reg()` sets the eager/demand bit for any insts + // whose result registers are used. + // + // We set the VCodeBuilder to "backward" mode, so we emit + // blocks in reverse order wrt the BlockIndex sequence, and + // emit instructions in reverse order within blocks. Because + // the machine backend calls `ctx.emit()` in forward order, we + // collect per-IR-inst lowered instructions in `ir_insts`, + // then reverse these and append to the VCode at the end of + // each IR instruction. + for inst in self.f.layout.block_insts(block).rev() { + let data = &self.f.dfg.insts[inst]; + let has_side_effect = has_lowering_side_effect(self.f, inst); + // If inst has been sunk to another location, skip it. + if self.is_inst_sunk(inst) { + continue; + } + // Are any outputs used at least once? + let value_needed = self.is_any_inst_result_needed(inst); + trace!( + "lower_clif_block: block {} inst {} ({:?}) is_branch {} side_effect {} value_needed {}", + block, + inst, + data, + data.opcode().is_branch(), + has_side_effect, + value_needed, + ); + + // Update scan state to color prior to this inst (as we are scanning + // backward). + self.cur_inst = Some(inst); + if has_side_effect { + let entry_color = *self + .side_effect_inst_entry_colors + .get(&inst) + .expect("every side-effecting inst should have a color-map entry"); + self.cur_scan_entry_color = Some(entry_color); + } + + // Skip lowering branches; these are handled separately + // (see `lower_clif_branches()` below). + if self.f.dfg.insts[inst].opcode().is_branch() { + continue; + } + + // Normal instruction: codegen if the instruction is side-effecting + // or any of its outputs is used. + if has_side_effect || value_needed { + trace!("lowering: inst {}: {}", inst, self.f.dfg.display_inst(inst)); + let temp_regs = match backend.lower(self, inst) { + Some(regs) => regs, + None => { + let ty = if self.num_outputs(inst) > 0 { + Some(self.output_ty(inst, 0)) + } else { + None + }; + return Err(CodegenError::Unsupported(format!( + "should be implemented in ISLE: inst = `{}`, type = `{:?}`", + self.f.dfg.display_inst(inst), + ty + ))); + } + }; + + // The ISLE generated code emits its own registers to define the + // instruction's lowered values in. However, other instructions + // that use this SSA value will be lowered assuming that the value + // is generated into a pre-assigned, different, register. + // + // To connect the two, we set up "aliases" in the VCodeBuilder + // that apply when it is building the Operand table for the + // regalloc to use. These aliases effectively rewrite any use of + // the pre-assigned register to the register that was returned by + // the ISLE lowering logic. + let results = self.f.dfg.inst_results(inst); + debug_assert_eq!(temp_regs.len(), results.len()); + for (regs, &result) in temp_regs.iter().zip(results) { + let dsts = self.value_regs[result]; + let mut regs = regs.regs().iter(); + for &dst in dsts.regs().iter() { + let temp = regs.next().copied().unwrap_or(Reg::invalid_sentinel()); + trace!("set vreg alias: {result:?} = {dst:?}, lowering = {temp:?}"); + self.vregs.set_vreg_alias(dst, temp); + } + } + } + + let start = self.vcode.vcode.num_insts(); + let loc = self.srcloc(inst); + self.finish_ir_inst(loc); + + // If the instruction had a user stack map, forward it from the CLIF + // to the vcode. + if let Some(entries) = self.f.dfg.user_stack_map_entries(inst) { + let end = self.vcode.vcode.num_insts(); + debug_assert!(end > start); + debug_assert_eq!( + (start..end) + .filter(|i| self.vcode.vcode[InsnIndex::new(*i)].is_safepoint()) + .count(), + 1 + ); + for i in start..end { + let iix = InsnIndex::new(i); + if self.vcode.vcode[iix].is_safepoint() { + trace!( + "Adding user stack map from clif\n\n\ + {inst:?} `{}`\n\n\ + to vcode\n\n\ + {iix:?} `{}`", + self.f.dfg.display_inst(inst), + &self.vcode.vcode[iix].pretty_print_inst(&mut Default::default()), + ); + self.vcode + .add_user_stack_map(BackwardsInsnIndex::new(iix.index()), entries); + break; + } + } + } + + // maybe insert random instruction + if ctrl_plane.get_decision() { + if ctrl_plane.get_decision() { + let imm: u64 = ctrl_plane.get_arbitrary(); + let reg = self.alloc_tmp(crate::ir::types::I64).regs()[0]; + I::gen_imm_u64(imm, reg).map(|inst| self.emit(inst)); + } else { + let imm: f64 = ctrl_plane.get_arbitrary(); + let tmp = self.alloc_tmp(crate::ir::types::I64).regs()[0]; + let reg = self.alloc_tmp(crate::ir::types::F64).regs()[0]; + for inst in I::gen_imm_f64(imm, tmp, reg) { + self.emit(inst); + } + } + } + + // Emit value-label markers if needed, to later recover + // debug mappings. This must happen before the instruction + // (so after we emit, in bottom-to-top pass). + self.emit_value_label_markers_for_inst(inst); + } + + // Add the block params to this block. + self.add_block_params(block)?; + + self.cur_scan_entry_color = None; + Ok(()) + } + + fn add_block_params(&mut self, block: Block) -> CodegenResult<()> { + for ¶m in self.f.dfg.block_params(block) { + for ® in self.value_regs[param].regs() { + let vreg = reg.to_virtual_reg().unwrap(); + self.vcode.add_block_param(vreg); + } + } + Ok(()) + } + + fn get_value_labels<'a>(&'a self, val: Value, depth: usize) -> Option<&'a [ValueLabelStart]> { + if let Some(ref values_labels) = self.f.dfg.values_labels { + debug_assert!(self.f.dfg.value_is_real(val)); + trace!( + "get_value_labels: val {} -> {:?}", + val, + values_labels.get(&val) + ); + match values_labels.get(&val) { + Some(&ValueLabelAssignments::Starts(ref list)) => Some(&list[..]), + Some(&ValueLabelAssignments::Alias { value, .. }) if depth < 10 => { + self.get_value_labels(value, depth + 1) + } + _ => None, + } + } else { + None + } + } + + fn emit_value_label_marks_for_value(&mut self, val: Value) { + let regs = self.value_regs[val]; + if regs.len() > 1 { + return; + } + let reg = regs.only_reg().unwrap(); + + if let Some(label_starts) = self.get_value_labels(val, 0) { + let labels = label_starts + .iter() + .map(|&ValueLabelStart { label, .. }| label) + .collect::>(); + for label in labels { + trace!( + "value labeling: defines val {:?} -> reg {:?} -> label {:?}", + val, + reg, + label, + ); + self.vcode.add_value_label(reg, label); + } + } + } + + fn emit_value_label_markers_for_inst(&mut self, inst: Inst) { + if self.f.dfg.values_labels.is_none() { + return; + } + + trace!( + "value labeling: srcloc {}: inst {}", + self.srcloc(inst), + inst + ); + for &val in self.f.dfg.inst_results(inst) { + self.emit_value_label_marks_for_value(val); + } + } + + fn emit_value_label_markers_for_block_args(&mut self, block: Block) { + if self.f.dfg.values_labels.is_none() { + return; + } + + trace!("value labeling: block {}", block); + for &arg in self.f.dfg.block_params(block) { + self.emit_value_label_marks_for_value(arg); + } + self.finish_ir_inst(Default::default()); + } + + fn finish_ir_inst(&mut self, loc: RelSourceLoc) { + // The VCodeBuilder builds in reverse order (and reverses at + // the end), but `ir_insts` is in forward order, so reverse + // it. + for inst in self.ir_insts.drain(..).rev() { + self.vcode.push(inst, loc); + } + } + + fn finish_bb(&mut self) { + self.vcode.end_bb(); + } + + fn lower_clif_branches>( + &mut self, + backend: &B, + // Lowered block index: + bindex: BlockIndex, + // Original CLIF block: + block: Block, + branch: Inst, + targets: &[MachLabel], + ) -> CodegenResult<()> { + trace!( + "lower_clif_branches: block {} branch {:?} targets {:?}", + block, + branch, + targets, + ); + // When considering code-motion opportunities, consider the current + // program point to be this branch. + self.cur_inst = Some(branch); + + // Lower the branch in ISLE. + backend + .lower_branch(self, branch, targets) + .unwrap_or_else(|| { + panic!( + "should be implemented in ISLE: branch = `{}`", + self.f.dfg.display_inst(branch), + ) + }); + let loc = self.srcloc(branch); + self.finish_ir_inst(loc); + // Add block param outputs for current block. + self.lower_branch_blockparam_args(bindex); + Ok(()) + } + + fn lower_branch_blockparam_args(&mut self, block: BlockIndex) { + // TODO: why not make `block_order` public? + for succ_idx in 0..self.vcode.block_order().succ_indices(block).1.len() { + // Avoid immutable borrow by explicitly indexing. + let (opt_inst, succs) = self.vcode.block_order().succ_indices(block); + let inst = opt_inst.expect("lower_branch_blockparam_args called on a critical edge!"); + let succ = succs[succ_idx]; + + // The use of `succ_idx` to index `branch_destination` is valid on the assumption that + // the traversal order defined in `visit_block_succs` mirrors the order returned by + // `branch_destination`. If that assumption is violated, the branch targets returned + // here will not match the clif. + let branches = self.f.dfg.insts[inst].branch_destination(&self.f.dfg.jump_tables); + let branch_args = branches[succ_idx].args_slice(&self.f.dfg.value_lists); + + let mut branch_arg_vregs: SmallVec<[Reg; 16]> = smallvec![]; + for &arg in branch_args { + debug_assert!(self.f.dfg.value_is_real(arg)); + let regs = self.put_value_in_regs(arg); + branch_arg_vregs.extend_from_slice(regs.regs()); + } + self.vcode.add_succ(succ, &branch_arg_vregs[..]); + } + } + + fn collect_branches_and_targets( + &self, + bindex: BlockIndex, + _bb: Block, + targets: &mut SmallVec<[MachLabel; 2]>, + ) -> Option { + targets.clear(); + let (opt_inst, succs) = self.vcode.block_order().succ_indices(bindex); + targets.extend(succs.iter().map(|succ| MachLabel::from_block(*succ))); + opt_inst + } + + /// Lower the function. + pub fn lower>( + mut self, + backend: &B, + ctrl_plane: &mut ControlPlane, + ) -> CodegenResult> { + trace!("about to lower function: {:?}", self.f); + + self.vcode.init_retval_area(&mut self.vregs)?; + + // Get the pinned reg here (we only parameterize this function on `B`, + // not the whole `Lower` impl). + self.pinned_reg = backend.maybe_pinned_reg(); + + self.vcode.set_entry(BlockIndex::new(0)); + + // Reused vectors for branch lowering. + let mut targets: SmallVec<[MachLabel; 2]> = SmallVec::new(); + + // get a copy of the lowered order; we hold this separately because we + // need a mut ref to the vcode to mutate it below. + let lowered_order: SmallVec<[LoweredBlock; 64]> = self + .vcode + .block_order() + .lowered_order() + .iter() + .cloned() + .collect(); + + // Main lowering loop over lowered blocks. + for (bindex, lb) in lowered_order.iter().enumerate().rev() { + let bindex = BlockIndex::new(bindex); + + // Lower the block body in reverse order (see comment in + // `lower_clif_block()` for rationale). + + // End branches. + if let Some(bb) = lb.orig_block() { + if let Some(branch) = self.collect_branches_and_targets(bindex, bb, &mut targets) { + self.lower_clif_branches(backend, bindex, bb, branch, &targets)?; + self.finish_ir_inst(self.srcloc(branch)); + } + } else { + // If no orig block, this must be a pure edge block; + // get the successor and emit a jump. Add block params + // according to the one successor, and pass them + // through; note that the successor must have an + // original block. + let (_, succs) = self.vcode.block_order().succ_indices(bindex); + let succ = succs[0]; + + let orig_succ = lowered_order[succ.index()]; + let orig_succ = orig_succ + .orig_block() + .expect("Edge block succ must be body block"); + + let mut branch_arg_vregs: SmallVec<[Reg; 16]> = smallvec![]; + for ty in self.f.dfg.block_param_types(orig_succ) { + let regs = self.vregs.alloc(ty)?; + for ® in regs.regs() { + branch_arg_vregs.push(reg); + let vreg = reg.to_virtual_reg().unwrap(); + self.vcode.add_block_param(vreg); + } + } + self.vcode.add_succ(succ, &branch_arg_vregs[..]); + + self.emit(I::gen_jump(MachLabel::from_block(succ))); + self.finish_ir_inst(Default::default()); + } + + // Original block body. + if let Some(bb) = lb.orig_block() { + self.lower_clif_block(backend, bb, ctrl_plane)?; + self.emit_value_label_markers_for_block_args(bb); + } + + if bindex.index() == 0 { + // Set up the function with arg vreg inits. + self.gen_arg_setup(); + self.finish_ir_inst(Default::default()); + } + + self.finish_bb(); + + // Check for any deferred vreg-temp allocation errors, and + // bubble one up at this time if it exists. + if let Some(e) = self.vregs.take_deferred_error() { + return Err(e); + } + } + + // Now that we've emitted all instructions into the + // VCodeBuilder, let's build the VCode. + trace!( + "built vcode:\n{:?}Backwards {:?}", + &self.vregs, + &self.vcode.vcode + ); + let vcode = self.vcode.build(self.vregs); + + Ok(vcode) + } + + pub fn value_is_unused(&self, val: Value) -> bool { + match self.value_ir_uses[val] { + ValueUseState::Unused => true, + _ => false, + } + } +} + +/// Pre-analysis: compute `value_ir_uses`. See comment on +/// `ValueUseState` for a description of what this analysis +/// computes. +fn compute_use_states( + f: &Function, + sret_param: Option, +) -> SecondaryMap { + // We perform the analysis without recursion, so we don't + // overflow the stack on long chains of ops in the input. + // + // This is sort of a hybrid of a "shallow use-count" pass and + // a DFS. We iterate over all instructions and mark their args + // as used. However when we increment a use-count to + // "Multiple" we push its args onto the stack and do a DFS, + // immediately marking the whole dependency tree as + // Multiple. Doing both (shallow use-counting over all insts, + // and deep Multiple propagation) lets us trim both + // traversals, stopping recursion when a node is already at + // the appropriate state. + // + // In particular, note that the *coarsening* into {Unused, + // Once, Multiple} is part of what makes this pass more + // efficient than a full indirect-use-counting pass. + + let mut value_ir_uses = SecondaryMap::with_default(ValueUseState::Unused); + + if let Some(sret_param) = sret_param { + // There's an implicit use of the struct-return parameter in each + // copy of the function epilogue, which we count here. + value_ir_uses[sret_param] = ValueUseState::Multiple; + } + + // Stack of iterators over Values as we do DFS to mark + // Multiple-state subtrees. The iterator type is whatever is + // returned by `uses` below. + let mut stack: SmallVec<[_; 16]> = smallvec![]; + + // Find the args for the inst corresponding to the given value. + // + // Note that "root" instructions are skipped here. This means that multiple + // uses of any result of a multi-result instruction are not considered + // multiple uses of the operands of a multi-result instruction. This + // requires tight coupling with `get_value_as_source_or_const` above which + // is the consumer of the map that this function is producing. + let uses = |value| { + trace!(" -> pushing args for {} onto stack", value); + if let ValueDef::Result(src_inst, _) = f.dfg.value_def(value) { + if is_value_use_root(f, src_inst) { + None + } else { + Some(f.dfg.inst_values(src_inst)) + } + } else { + None + } + }; + + // Do a DFS through `value_ir_uses` to mark a subtree as + // Multiple. + for inst in f + .layout + .blocks() + .flat_map(|block| f.layout.block_insts(block)) + { + // Iterate over all values used by all instructions, noting an + // additional use on each operand. + for arg in f.dfg.inst_values(inst) { + debug_assert!(f.dfg.value_is_real(arg)); + let old = value_ir_uses[arg]; + value_ir_uses[arg].inc(); + let new = value_ir_uses[arg]; + trace!("arg {} used, old state {:?}, new {:?}", arg, old, new); + + // On transition to Multiple, do DFS. + if old == ValueUseState::Multiple || new != ValueUseState::Multiple { + continue; + } + if let Some(iter) = uses(arg) { + stack.push(iter); + } + while let Some(iter) = stack.last_mut() { + if let Some(value) = iter.next() { + debug_assert!(f.dfg.value_is_real(value)); + trace!(" -> DFS reaches {}", value); + if value_ir_uses[value] == ValueUseState::Multiple { + // Truncate DFS here: no need to go further, + // as whole subtree must already be Multiple. + // With debug asserts, check one level of + // that invariant at least. + debug_assert!(uses(value).into_iter().flatten().all(|arg| { + debug_assert!(f.dfg.value_is_real(arg)); + value_ir_uses[arg] == ValueUseState::Multiple + })); + continue; + } + value_ir_uses[value] = ValueUseState::Multiple; + trace!(" -> became Multiple"); + if let Some(iter) = uses(value) { + stack.push(iter); + } + } else { + // Empty iterator, discard. + stack.pop(); + } + } + } + } + + value_ir_uses +} + +/// Definition of a "root" instruction for the calculation of `ValueUseState`. +/// +/// This function calculates whether `inst` is considered a "root" for value-use +/// information. This concept is used to forcibly prevent looking-through the +/// instruction during `get_value_as_source_or_const` as it additionally +/// prevents propagating `Multiple`-used results of the `inst` here to the +/// operands of the instruction. +/// +/// Currently this is defined as multi-result instructions. That means that +/// lowerings are never allowed to look through a multi-result instruction to +/// generate patterns. Note that this isn't possible in ISLE today anyway so +/// this isn't currently much of a loss. +/// +/// The main purpose of this function is to prevent the operands of a +/// multi-result instruction from being forcibly considered `Multiple`-used +/// regardless of circumstances. +fn is_value_use_root(f: &Function, inst: Inst) -> bool { + f.dfg.inst_results(inst).len() > 1 +} + +/// Function-level queries. +impl<'func, I: VCodeInst> Lower<'func, I> { + pub fn dfg(&self) -> &DataFlowGraph { + &self.f.dfg + } + + /// Get the `Callee`. + pub fn abi(&self) -> &Callee { + self.vcode.abi() + } + + /// Get the `Callee`. + pub fn abi_mut(&mut self) -> &mut Callee { + self.vcode.abi_mut() + } +} + +/// Instruction input/output queries. +impl<'func, I: VCodeInst> Lower<'func, I> { + /// Get the instdata for a given IR instruction. + pub fn data(&self, ir_inst: Inst) -> &InstructionData { + &self.f.dfg.insts[ir_inst] + } + + /// Likewise, but starting with a GlobalValue identifier. + pub fn symbol_value_data<'b>( + &'b self, + global_value: GlobalValue, + ) -> Option<(&'b ExternalName, RelocDistance, i64)> { + let gvdata = &self.f.global_values[global_value]; + match gvdata { + &GlobalValueData::Symbol { + ref name, + ref offset, + colocated, + .. + } => { + let offset = offset.bits(); + let dist = if colocated { + RelocDistance::Near + } else { + RelocDistance::Far + }; + Some((name, dist, offset)) + } + _ => None, + } + } + + /// Returns the memory flags of a given memory access. + pub fn memflags(&self, ir_inst: Inst) -> Option { + match &self.f.dfg.insts[ir_inst] { + &InstructionData::AtomicCas { flags, .. } => Some(flags), + &InstructionData::AtomicRmw { flags, .. } => Some(flags), + &InstructionData::Load { flags, .. } + | &InstructionData::LoadNoOffset { flags, .. } + | &InstructionData::Store { flags, .. } => Some(flags), + &InstructionData::StoreNoOffset { flags, .. } => Some(flags), + _ => None, + } + } + + /// Get the source location for a given instruction. + pub fn srcloc(&self, ir_inst: Inst) -> RelSourceLoc { + self.f.rel_srclocs()[ir_inst] + } + + /// Get the number of inputs to the given IR instruction. This is a count only of the Value + /// arguments to the instruction: block arguments will not be included in this count. + pub fn num_inputs(&self, ir_inst: Inst) -> usize { + self.f.dfg.inst_args(ir_inst).len() + } + + /// Get the number of outputs to the given IR instruction. + pub fn num_outputs(&self, ir_inst: Inst) -> usize { + self.f.dfg.inst_results(ir_inst).len() + } + + /// Get the type for an instruction's input. + pub fn input_ty(&self, ir_inst: Inst, idx: usize) -> Type { + self.value_ty(self.input_as_value(ir_inst, idx)) + } + + /// Get the type for a value. + pub fn value_ty(&self, val: Value) -> Type { + self.f.dfg.value_type(val) + } + + /// Get the type for an instruction's output. + pub fn output_ty(&self, ir_inst: Inst, idx: usize) -> Type { + self.f.dfg.value_type(self.f.dfg.inst_results(ir_inst)[idx]) + } + + /// Get the value of a constant instruction (`iconst`, etc.) as a 64-bit + /// value, if possible. + pub fn get_constant(&self, ir_inst: Inst) -> Option { + self.inst_constants.get(&ir_inst).map(|&c| { + // The upper bits must be zero, enforced during legalization and by + // the CLIF verifier. + debug_assert_eq!(c, { + let input_size = self.output_ty(ir_inst, 0).bits() as u64; + let shift = 64 - input_size; + (c << shift) >> shift + }); + c + }) + } + + /// Get the input as one of two options other than a direct register: + /// + /// - An instruction, given that it is effect-free or able to sink its + /// effect to the current instruction being lowered, and given it has only + /// one output, and if effect-ful, given that this is the only use; + /// - A constant, if the value is a constant. + /// + /// The instruction input may be available in either of these forms. It may + /// be available in neither form, if the conditions are not met; if so, use + /// `put_input_in_regs()` instead to get it in a register. + /// + /// If the backend merges the effect of a side-effecting instruction, it + /// must call `sink_inst()`. When this is called, it indicates that the + /// effect has been sunk to the current scan location. The sunk + /// instruction's result(s) must have *no* uses remaining, because it will + /// not be codegen'd (it has been integrated into the current instruction). + pub fn input_as_value(&self, ir_inst: Inst, idx: usize) -> Value { + let val = self.f.dfg.inst_args(ir_inst)[idx]; + debug_assert!(self.f.dfg.value_is_real(val)); + val + } + + /// Resolves a particular input of an instruction to the `Value` that it is + /// represented with. + /// + /// For more information see [`Lower::get_value_as_source_or_const`]. + pub fn get_input_as_source_or_const(&self, ir_inst: Inst, idx: usize) -> NonRegInput { + let val = self.input_as_value(ir_inst, idx); + self.get_value_as_source_or_const(val) + } + + /// Resolves a `Value` definition to the source instruction it came from + /// plus whether it's a unique-use of that instruction. + /// + /// This function is the workhorse of pattern-matching in ISLE which enables + /// combining multiple instructions together. This is used implicitly in + /// patterns such as `(iadd x (iconst y))` where this function is used to + /// extract the `(iconst y)` operand. + /// + /// At its core this function is a wrapper around + /// [`DataFlowGraph::value_def`]. This function applies a filter on top of + /// that, however, to determine when it is actually safe to "look through" + /// the `val` definition here and view the underlying instruction. This + /// protects against duplicating side effects, such as loads, for example. + /// + /// Internally this uses the data computed from `compute_use_states` along + /// with other instruction properties to know what to return. + pub fn get_value_as_source_or_const(&self, val: Value) -> NonRegInput { + trace!( + "get_input_for_val: val {} at cur_inst {:?} cur_scan_entry_color {:?}", + val, + self.cur_inst, + self.cur_scan_entry_color, + ); + let inst = match self.f.dfg.value_def(val) { + // OK to merge source instruction if we have a source + // instruction, and one of these two conditions hold: + // + // - It has no side-effects and this instruction is not a "value-use + // root" instruction. Instructions which are considered "roots" + // for value-use calculations do not have accurate information + // known about the `ValueUseState` of their operands. This is + // currently done for multi-result instructions to prevent a use + // of each result from forcing all operands of the multi-result + // instruction to also be `Multiple`. This in turn means that the + // `ValueUseState` for operands of a "root" instruction to be a + // lie if pattern matching were to look through the multi-result + // instruction. As a result the "look through this instruction" + // logic only succeeds if it's not a root instruction. + // + // - It has a side-effect, has one output value, that one + // output has only one use, directly or indirectly (so + // cannot be duplicated -- see comment on + // `ValueUseState`), and the instruction's color is *one + // less than* the current scan color. + // + // This latter set of conditions is testing whether a + // side-effecting instruction can sink to the current scan + // location; this is possible if the in-color of this inst is + // equal to the out-color of the producing inst, so no other + // side-effecting ops occur between them (which will only be true + // if they are in the same BB, because color increments at each BB + // start). + // + // If it is actually sunk, then in `merge_inst()`, we update the + // scan color so that as we scan over the range past which the + // instruction was sunk, we allow other instructions (that came + // prior to the sunk instruction) to sink. + ValueDef::Result(src_inst, result_idx) => { + let src_side_effect = has_lowering_side_effect(self.f, src_inst); + trace!(" -> src inst {}", src_inst); + trace!(" -> has lowering side effect: {}", src_side_effect); + if is_value_use_root(self.f, src_inst) { + // If this instruction is a "root instruction" then it's + // required that we can't look through it to see the + // definition. This means that the `ValueUseState` for the + // operands of this result assume that this instruction is + // generated exactly once which might get violated were we + // to allow looking through it. + trace!(" -> is a root instruction"); + InputSourceInst::None + } else if !src_side_effect { + // Otherwise if this instruction has no side effects and the + // value is used only once then we can look through it with + // a "unique" tag. A non-unique `Use` can be shown for other + // values ensuring consumers know how it's computed but that + // it's not available to omit. + if self.value_ir_uses[val] == ValueUseState::Once { + InputSourceInst::UniqueUse(src_inst, result_idx) + } else { + InputSourceInst::Use(src_inst, result_idx) + } + } else { + // Side-effect: test whether this is the only use of the + // only result of the instruction, and whether colors allow + // the code-motion. + trace!( + " -> side-effecting op {} for val {}: use state {:?}", + src_inst, + val, + self.value_ir_uses[val] + ); + if self.cur_scan_entry_color.is_some() + && self.value_ir_uses[val] == ValueUseState::Once + && self.num_outputs(src_inst) == 1 + && self + .side_effect_inst_entry_colors + .get(&src_inst) + .unwrap() + .get() + + 1 + == self.cur_scan_entry_color.unwrap().get() + { + InputSourceInst::UniqueUse(src_inst, 0) + } else { + InputSourceInst::None + } + } + } + _ => InputSourceInst::None, + }; + let constant = inst.as_inst().and_then(|(inst, _)| self.get_constant(inst)); + + NonRegInput { inst, constant } + } + + /// Increment the reference count for the Value, ensuring that it gets lowered. + pub fn increment_lowered_uses(&mut self, val: Value) { + self.value_lowered_uses[val] += 1 + } + + /// Put the `idx`th input into register(s) and return the assigned register. + pub fn put_input_in_regs(&mut self, ir_inst: Inst, idx: usize) -> ValueRegs { + let val = self.f.dfg.inst_args(ir_inst)[idx]; + self.put_value_in_regs(val) + } + + /// Put the given value into register(s) and return the assigned register. + pub fn put_value_in_regs(&mut self, val: Value) -> ValueRegs { + debug_assert!(self.f.dfg.value_is_real(val)); + trace!("put_value_in_regs: val {}", val); + + if let Some(inst) = self.f.dfg.value_def(val).inst() { + assert!(!self.inst_sunk.contains(&inst)); + } + + let regs = self.value_regs[val]; + trace!(" -> regs {:?}", regs); + assert!(regs.is_valid()); + + self.value_lowered_uses[val] += 1; + + regs + } +} + +/// Codegen primitives: allocate temps, emit instructions, set result registers, +/// ask for an input to be gen'd into a register. +impl<'func, I: VCodeInst> Lower<'func, I> { + /// Get a new temp. + pub fn alloc_tmp(&mut self, ty: Type) -> ValueRegs> { + writable_value_regs(self.vregs.alloc_with_deferred_error(ty)) + } + + /// Emit a machine instruction. + pub fn emit(&mut self, mach_inst: I) { + trace!("emit: {:?}", mach_inst); + self.ir_insts.push(mach_inst); + } + + /// Indicate that the side-effect of an instruction has been sunk to the + /// current scan location. This should only be done with the instruction's + /// original results are not used (i.e., `put_input_in_regs` is not invoked + /// for the input produced by the sunk instruction), otherwise the + /// side-effect will occur twice. + pub fn sink_inst(&mut self, ir_inst: Inst) { + assert!(has_lowering_side_effect(self.f, ir_inst)); + assert!(self.cur_scan_entry_color.is_some()); + + for result in self.dfg().inst_results(ir_inst) { + assert!(self.value_lowered_uses[*result] == 0); + } + + let sunk_inst_entry_color = self + .side_effect_inst_entry_colors + .get(&ir_inst) + .cloned() + .unwrap(); + let sunk_inst_exit_color = InstColor::new(sunk_inst_entry_color.get() + 1); + assert!(sunk_inst_exit_color == self.cur_scan_entry_color.unwrap()); + self.cur_scan_entry_color = Some(sunk_inst_entry_color); + self.inst_sunk.insert(ir_inst); + } + + /// Retrieve immediate data given a handle. + pub fn get_immediate_data(&self, imm: Immediate) -> &ConstantData { + self.f.dfg.immediates.get(imm).unwrap() + } + + /// Retrieve constant data given a handle. + pub fn get_constant_data(&self, constant_handle: Constant) -> &ConstantData { + self.f.dfg.constants.get(constant_handle) + } + + /// Indicate that a constant should be emitted. + pub fn use_constant(&mut self, constant: VCodeConstantData) -> VCodeConstant { + self.vcode.constants().insert(constant) + } + + /// Cause the value in `reg` to be in a virtual reg, by copying it into a + /// new virtual reg if `reg` is a real reg. `ty` describes the type of the + /// value in `reg`. + pub fn ensure_in_vreg(&mut self, reg: Reg, ty: Type) -> Reg { + if reg.to_virtual_reg().is_some() { + reg + } else { + let new_reg = self.alloc_tmp(ty).only_reg().unwrap(); + self.emit(I::gen_move(new_reg, reg, ty)); + new_reg.to_reg() + } + } + + /// Add a range fact to a register, if no other fact is present. + pub fn add_range_fact(&mut self, reg: Reg, bit_width: u16, min: u64, max: u64) { + if self.flags.enable_pcc() { + self.vregs.set_fact_if_missing( + reg.to_virtual_reg().unwrap(), + Fact::Range { + bit_width, + min, + max, + }, + ); + } + } +} + +#[cfg(test)] +mod tests { + use super::ValueUseState; + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::types; + use crate::ir::{Function, InstBuilder}; + + #[test] + fn multi_result_use_once() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + let v1 = pos.ins().iconst(types::I64, 0); + let v2 = pos.ins().iconst(types::I64, 1); + let v3 = pos.ins().iconcat(v1, v2); + let (v4, v5) = pos.ins().isplit(v3); + pos.ins().return_(&[v4, v5]); + let func = pos.func; + + let uses = super::compute_use_states(&func, None); + assert_eq!(uses[v1], ValueUseState::Once); + assert_eq!(uses[v2], ValueUseState::Once); + assert_eq!(uses[v3], ValueUseState::Once); + assert_eq!(uses[v4], ValueUseState::Once); + assert_eq!(uses[v5], ValueUseState::Once); + } + + #[test] + fn results_used_twice_but_not_operands() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + let v1 = pos.ins().iconst(types::I64, 0); + let v2 = pos.ins().iconst(types::I64, 1); + let v3 = pos.ins().iconcat(v1, v2); + let (v4, v5) = pos.ins().isplit(v3); + pos.ins().return_(&[v4, v4]); + let func = pos.func; + + let uses = super::compute_use_states(&func, None); + assert_eq!(uses[v1], ValueUseState::Once); + assert_eq!(uses[v2], ValueUseState::Once); + assert_eq!(uses[v3], ValueUseState::Once); + assert_eq!(uses[v4], ValueUseState::Multiple); + assert_eq!(uses[v5], ValueUseState::Unused); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/mod.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/mod.rs new file mode 100644 index 00000000000000..ed07b1bf0365f0 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/mod.rs @@ -0,0 +1,564 @@ +//! This module exposes the machine-specific backend definition pieces. +//! +//! The MachInst infrastructure is the compiler backend, from CLIF +//! (ir::Function) to machine code. The purpose of this infrastructure is, at a +//! high level, to do instruction selection/lowering (to machine instructions), +//! register allocation, and then perform all the fixups to branches, constant +//! data references, etc., needed to actually generate machine code. +//! +//! The container for machine instructions, at various stages of construction, +//! is the `VCode` struct. We refer to a sequence of machine instructions organized +//! into basic blocks as "vcode". This is short for "virtual-register code". +//! +//! The compilation pipeline, from an `ir::Function` (already optimized as much as +//! you like by machine-independent optimization passes) onward, is as follows. +//! +//! ```plain +//! +//! ir::Function (SSA IR, machine-independent opcodes) +//! | +//! | [lower] +//! | +//! VCode (machine instructions: +//! | - mostly virtual registers. +//! | - cond branches in two-target form. +//! | - branch targets are block indices. +//! | - in-memory constants held by insns, +//! | with unknown offsets. +//! | - critical edges (actually all edges) +//! | are split.) +//! | +//! | [regalloc --> `regalloc2::Output`; VCode is unchanged] +//! | +//! | [binary emission via MachBuffer] +//! | +//! Vec (machine code: +//! | - two-dest branches resolved via +//! | streaming branch resolution/simplification. +//! | - regalloc `Allocation` results used directly +//! | by instruction emission code. +//! | - prologue and epilogue(s) built and emitted +//! | directly during emission. +//! | - SP-relative offsets resolved by tracking +//! | EmitState.) +//! +//! ``` + +use crate::binemit::{Addend, CodeInfo, CodeOffset, Reloc}; +use crate::ir::{ + self, function::FunctionParameters, DynamicStackSlot, RelSourceLoc, StackSlot, Type, +}; +use crate::isa::FunctionAlignment; +use crate::result::CodegenResult; +use crate::settings; +use crate::settings::Flags; +use crate::value_label::ValueLabelsRanges; +use alloc::vec::Vec; +use core::fmt::Debug; +use cranelift_control::ControlPlane; +use cranelift_entity::PrimaryMap; +use regalloc2::VReg; +use smallvec::{smallvec, SmallVec}; +use std::string::String; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +#[macro_use] +pub mod isle; + +pub mod lower; +pub use lower::*; +pub mod vcode; +pub use vcode::*; +pub mod compile; +pub use compile::*; +pub mod blockorder; +pub use blockorder::*; +pub mod abi; +pub use abi::*; +pub mod buffer; +pub use buffer::*; +pub mod helpers; +pub use helpers::*; +pub mod inst_common; +#[allow(unused_imports)] // not used in all backends right now +pub use inst_common::*; +pub mod valueregs; +pub use reg::*; +pub use valueregs::*; +pub mod pcc; +pub mod reg; + +/// A machine instruction. +pub trait MachInst: Clone + Debug { + /// The ABI machine spec for this `MachInst`. + type ABIMachineSpec: ABIMachineSpec; + + /// Return the registers referenced by this machine instruction along with + /// the modes of reference (use, def, modify). + fn get_operands(&mut self, collector: &mut impl OperandVisitor); + + /// If this is a simple move, return the (source, destination) tuple of registers. + fn is_move(&self) -> Option<(Writable, Reg)>; + + /// Is this a terminator (branch or ret)? If so, return its type + /// (ret/uncond/cond) and target if applicable. + fn is_term(&self) -> MachTerminator; + + /// Is this an unconditional trap? + fn is_trap(&self) -> bool; + + /// Is this an "args" pseudoinst? + fn is_args(&self) -> bool; + + /// Should this instruction be included in the clobber-set? + fn is_included_in_clobbers(&self) -> bool; + + /// Does this instruction access memory? + fn is_mem_access(&self) -> bool; + + /// Generate a move. + fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self; + + /// Generate a dummy instruction that will keep a value alive but + /// has no other purpose. + fn gen_dummy_use(reg: Reg) -> Self; + + /// Determine register class(es) to store the given Cranelift type, and the + /// Cranelift type actually stored in the underlying register(s). May return + /// an error if the type isn't supported by this backend. + /// + /// If the type requires multiple registers, then the list of registers is + /// returned in little-endian order. + /// + /// Note that the type actually stored in the register(s) may differ in the + /// case that a value is split across registers: for example, on a 32-bit + /// target, an I64 may be stored in two registers, each of which holds an + /// I32. The actually-stored types are used only to inform the backend when + /// generating spills and reloads for individual registers. + fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])>; + + /// Get an appropriate type that can fully hold a value in a given + /// register class. This may not be the only type that maps to + /// that class, but when used with `gen_move()` or the ABI trait's + /// load/spill constructors, it should produce instruction(s) that + /// move the entire register contents. + fn canonical_type_for_rc(rc: RegClass) -> Type; + + /// Generate a jump to another target. Used during lowering of + /// control flow. + fn gen_jump(target: MachLabel) -> Self; + + /// Generate a store of an immediate 64-bit integer to a register. Used by + /// the control plane to generate random instructions. + fn gen_imm_u64(_value: u64, _dst: Writable) -> Option { + None + } + + /// Generate a store of an immediate 64-bit integer to a register. Used by + /// the control plane to generate random instructions. The tmp register may + /// be used by architectures which don't support writing immediate values to + /// floating point registers directly. + fn gen_imm_f64(_value: f64, _tmp: Writable, _dst: Writable) -> SmallVec<[Self; 2]> { + SmallVec::new() + } + + /// Generate a NOP. The `preferred_size` parameter allows the caller to + /// request a NOP of that size, or as close to it as possible. The machine + /// backend may return a NOP whose binary encoding is smaller than the + /// preferred size, but must not return a NOP that is larger. However, + /// the instruction must have a nonzero size if preferred_size is nonzero. + fn gen_nop(preferred_size: usize) -> Self; + + /// Align a basic block offset (from start of function). By default, no + /// alignment occurs. + fn align_basic_block(offset: CodeOffset) -> CodeOffset { + offset + } + + /// What is the worst-case instruction size emitted by this instruction type? + fn worst_case_size() -> CodeOffset; + + /// What is the register class used for reference types (GC-observable pointers)? Can + /// be dependent on compilation flags. + fn ref_type_regclass(_flags: &Flags) -> RegClass; + + /// Is this a safepoint? + fn is_safepoint(&self) -> bool; + + /// Generate an instruction that must appear at the beginning of a basic + /// block, if any. Note that the return value must not be subject to + /// register allocation. + fn gen_block_start( + _is_indirect_branch_target: bool, + _is_forward_edge_cfi_enabled: bool, + ) -> Option { + None + } + + /// Returns a description of the alignment required for functions for this + /// architecture. + fn function_alignment() -> FunctionAlignment; + + /// A label-use kind: a type that describes the types of label references that + /// can occur in an instruction. + type LabelUse: MachInstLabelUse; + + /// Byte representation of a trap opcode which is inserted by `MachBuffer` + /// during its `defer_trap` method. + const TRAP_OPCODE: &'static [u8]; +} + +/// A descriptor of a label reference (use) in an instruction set. +pub trait MachInstLabelUse: Clone + Copy + Debug + Eq { + /// Required alignment for any veneer. Usually the required instruction + /// alignment (e.g., 4 for a RISC with 32-bit instructions, or 1 for x86). + const ALIGN: CodeOffset; + + /// What is the maximum PC-relative range (positive)? E.g., if `1024`, a + /// label-reference fixup at offset `x` is valid if the label resolves to `x + /// + 1024`. + fn max_pos_range(self) -> CodeOffset; + /// What is the maximum PC-relative range (negative)? This is the absolute + /// value; i.e., if `1024`, then a label-reference fixup at offset `x` is + /// valid if the label resolves to `x - 1024`. + fn max_neg_range(self) -> CodeOffset; + /// What is the size of code-buffer slice this label-use needs to patch in + /// the label's value? + fn patch_size(self) -> CodeOffset; + /// Perform a code-patch, given the offset into the buffer of this label use + /// and the offset into the buffer of the label's definition. + /// It is guaranteed that, given `delta = offset - label_offset`, we will + /// have `offset >= -self.max_neg_range()` and `offset <= + /// self.max_pos_range()`. + fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset); + /// Can the label-use be patched to a veneer that supports a longer range? + /// Usually valid for jumps (a short-range jump can jump to a longer-range + /// jump), but not for e.g. constant pool references, because the constant + /// load would require different code (one more level of indirection). + fn supports_veneer(self) -> bool; + /// How many bytes are needed for a veneer? + fn veneer_size(self) -> CodeOffset; + /// What's the largest possible veneer that may be generated? + fn worst_case_veneer_size() -> CodeOffset; + /// Generate a veneer. The given code-buffer slice is `self.veneer_size()` + /// bytes long at offset `veneer_offset` in the buffer. The original + /// label-use will be patched to refer to this veneer's offset. A new + /// (offset, LabelUse) is returned that allows the veneer to use the actual + /// label. For veneers to work properly, it is expected that the new veneer + /// has a larger range; on most platforms this probably means either a + /// "long-range jump" (e.g., on ARM, the 26-bit form), or if already at that + /// stage, a jump that supports a full 32-bit range, for example. + fn generate_veneer(self, buffer: &mut [u8], veneer_offset: CodeOffset) -> (CodeOffset, Self); + + /// Returns the corresponding label-use for the relocation specified. + /// + /// This returns `None` if the relocation doesn't have a corresponding + /// representation for the target architecture. + fn from_reloc(reloc: Reloc, addend: Addend) -> Option; +} + +/// Describes a block terminator (not call) in the vcode, when its branches +/// have not yet been finalized (so a branch may have two targets). +/// +/// Actual targets are not included: the single-source-of-truth for +/// those is the VCode itself, which holds, for each block, successors +/// and outgoing branch args per successor. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum MachTerminator { + /// Not a terminator. + None, + /// A return instruction. + Ret, + /// A tail call. + RetCall, + /// An unconditional branch to another block. + Uncond, + /// A conditional branch to one of two other blocks. + Cond, + /// An indirect branch with known possible targets. + Indirect, +} + +/// A trait describing the ability to encode a MachInst into binary machine code. +pub trait MachInstEmit: MachInst { + /// Persistent state carried across `emit` invocations. + type State: MachInstEmitState; + + /// Constant information used in `emit` invocations. + type Info; + + /// Emit the instruction. + fn emit(&self, code: &mut MachBuffer, info: &Self::Info, state: &mut Self::State); + + /// Pretty-print the instruction. + fn pretty_print_inst(&self, state: &mut Self::State) -> String; +} + +/// A trait describing the emission state carried between MachInsts when +/// emitting a function body. +pub trait MachInstEmitState: Default + Clone + Debug { + /// Create a new emission state given the ABI object. + fn new(abi: &Callee, ctrl_plane: ControlPlane) -> Self; + + /// Update the emission state before emitting an instruction that is a + /// safepoint. + fn pre_safepoint(&mut self, user_stack_map: Option); + + /// The emission state holds ownership of a control plane, so it doesn't + /// have to be passed around explicitly too much. `ctrl_plane_mut` may + /// be used if temporary access to the control plane is needed by some + /// other function that doesn't have access to the emission state. + fn ctrl_plane_mut(&mut self) -> &mut ControlPlane; + + /// Used to continue using a control plane after the emission state is + /// not needed anymore. + fn take_ctrl_plane(self) -> ControlPlane; + + /// A hook that triggers when first emitting a new block. + /// It is guaranteed to be called before any instructions are emitted. + fn on_new_block(&mut self) {} + + /// The [`FrameLayout`] for the function currently being compiled. + fn frame_layout(&self) -> &FrameLayout; +} + +/// The result of a `MachBackend::compile_function()` call. Contains machine +/// code (as bytes) and a disassembly, if requested. +#[derive(PartialEq, Debug, Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct CompiledCodeBase { + /// Machine code. + pub buffer: MachBufferFinalized, + /// Size of stack frame, in bytes. + pub frame_size: u32, + /// Disassembly, if requested. + pub vcode: Option, + /// Debug info: value labels to registers/stackslots at code offsets. + pub value_labels_ranges: ValueLabelsRanges, + /// Debug info: stackslots to stack pointer offsets. + pub sized_stackslot_offsets: PrimaryMap, + /// Debug info: stackslots to stack pointer offsets. + pub dynamic_stackslot_offsets: PrimaryMap, + /// Basic-block layout info: block start offsets. + /// + /// This info is generated only if the `machine_code_cfg_info` + /// flag is set. + pub bb_starts: Vec, + /// Basic-block layout info: block edges. Each edge is `(from, + /// to)`, where `from` and `to` are basic-block start offsets of + /// the respective blocks. + /// + /// This info is generated only if the `machine_code_cfg_info` + /// flag is set. + pub bb_edges: Vec<(CodeOffset, CodeOffset)>, +} + +impl CompiledCodeStencil { + /// Apply function parameters to finalize a stencil into its final form. + pub fn apply_params(self, params: &FunctionParameters) -> CompiledCode { + CompiledCode { + buffer: self.buffer.apply_base_srcloc(params.base_srcloc()), + frame_size: self.frame_size, + vcode: self.vcode, + value_labels_ranges: self.value_labels_ranges, + sized_stackslot_offsets: self.sized_stackslot_offsets, + dynamic_stackslot_offsets: self.dynamic_stackslot_offsets, + bb_starts: self.bb_starts, + bb_edges: self.bb_edges, + } + } +} + +impl CompiledCodeBase { + /// Get a `CodeInfo` describing section sizes from this compilation result. + pub fn code_info(&self) -> CodeInfo { + CodeInfo { + total_size: self.buffer.total_size(), + } + } + + /// Returns a reference to the machine code generated for this function compilation. + pub fn code_buffer(&self) -> &[u8] { + self.buffer.data() + } + + /// Get the disassembly of the buffer, using the given capstone context. + #[cfg(feature = "disas")] + pub fn disassemble( + &self, + params: Option<&crate::ir::function::FunctionParameters>, + cs: &capstone::Capstone, + ) -> Result { + use std::fmt::Write; + + let mut buf = String::new(); + + let relocs = self.buffer.relocs(); + let traps = self.buffer.traps(); + + // Normalize the block starts to include an initial block of offset 0. + let mut block_starts = Vec::new(); + if self.bb_starts.first().copied() != Some(0) { + block_starts.push(0); + } + block_starts.extend_from_slice(&self.bb_starts); + block_starts.push(self.buffer.data().len() as u32); + + // Iterate over block regions, to ensure that we always produce block labels + for (n, (&start, &end)) in block_starts + .iter() + .zip(block_starts.iter().skip(1)) + .enumerate() + { + writeln!(buf, "block{n}: ; offset 0x{start:x}")?; + + let buffer = &self.buffer.data()[start as usize..end as usize]; + let insns = cs.disasm_all(buffer, start as u64).map_err(map_caperr)?; + for i in insns.iter() { + write!(buf, " ")?; + + let op_str = i.op_str().unwrap_or(""); + if let Some(s) = i.mnemonic() { + write!(buf, "{s}")?; + if !op_str.is_empty() { + write!(buf, " ")?; + } + } + + write!(buf, "{op_str}")?; + + let end = i.address() + i.bytes().len() as u64; + let contains = |off| i.address() <= off && off < end; + + for reloc in relocs.iter().filter(|reloc| contains(reloc.offset as u64)) { + write!( + buf, + " ; reloc_external {} {} {}", + reloc.kind, + reloc.target.display(params), + reloc.addend, + )?; + } + + if let Some(trap) = traps.iter().find(|trap| contains(trap.offset as u64)) { + write!(buf, " ; trap: {}", trap.code)?; + } + + writeln!(buf)?; + } + } + + return Ok(buf); + + fn map_caperr(err: capstone::Error) -> anyhow::Error { + anyhow::format_err!("{}", err) + } + } +} + +/// Result of compiling a `FunctionStencil`, before applying `FunctionParameters` onto it. +/// +/// Only used internally, in a transient manner, for the incremental compilation cache. +pub type CompiledCodeStencil = CompiledCodeBase; + +/// `CompiledCode` in its final form (i.e. after `FunctionParameters` have been applied), ready for +/// consumption. +pub type CompiledCode = CompiledCodeBase; + +impl CompiledCode { + /// If available, return information about the code layout in the + /// final machine code: the offsets (in bytes) of each basic-block + /// start, and all basic-block edges. + pub fn get_code_bb_layout(&self) -> (Vec, Vec<(usize, usize)>) { + ( + self.bb_starts.iter().map(|&off| off as usize).collect(), + self.bb_edges + .iter() + .map(|&(from, to)| (from as usize, to as usize)) + .collect(), + ) + } + + /// Creates unwind information for the function. + /// + /// Returns `None` if the function has no unwind information. + #[cfg(feature = "unwind")] + pub fn create_unwind_info( + &self, + isa: &dyn crate::isa::TargetIsa, + ) -> CodegenResult> { + use crate::isa::unwind::UnwindInfoKind; + let unwind_info_kind = match isa.triple().operating_system { + target_lexicon::OperatingSystem::Windows => UnwindInfoKind::Windows, + _ => UnwindInfoKind::SystemV, + }; + self.create_unwind_info_of_kind(isa, unwind_info_kind) + } + + /// Creates unwind information for the function using the supplied + /// "kind". Supports cross-OS (but not cross-arch) generation. + /// + /// Returns `None` if the function has no unwind information. + #[cfg(feature = "unwind")] + pub fn create_unwind_info_of_kind( + &self, + isa: &dyn crate::isa::TargetIsa, + unwind_info_kind: crate::isa::unwind::UnwindInfoKind, + ) -> CodegenResult> { + isa.emit_unwind_info(self, unwind_info_kind) + } +} + +/// An object that can be used to create the text section of an executable. +/// +/// This primarily handles resolving relative relocations at +/// text-section-assembly time rather than at load/link time. This +/// architecture-specific logic is sort of like a linker, but only for one +/// object file at a time. +pub trait TextSectionBuilder { + /// Appends `data` to the text section with the `align` specified. + /// + /// If `labeled` is `true` then this also binds the appended data to the + /// `n`th label for how many times this has been called with `labeled: + /// true`. The label target can be passed as the `target` argument to + /// `resolve_reloc`. + /// + /// This function returns the offset at which the data was placed in the + /// text section. + fn append( + &mut self, + labeled: bool, + data: &[u8], + align: u32, + ctrl_plane: &mut ControlPlane, + ) -> u64; + + /// Attempts to resolve a relocation for this function. + /// + /// The `offset` is the offset of the relocation, within the text section. + /// The `reloc` is the kind of relocation. + /// The `addend` is the value to add to the relocation. + /// The `target` is the labeled function that is the target of this + /// relocation. + /// + /// Labeled functions are created with the `append` function above by + /// setting the `labeled` parameter to `true`. + /// + /// If this builder does not know how to handle `reloc` then this function + /// will return `false`. Otherwise this function will return `true` and this + /// relocation will be resolved in the final bytes returned by `finish`. + fn resolve_reloc(&mut self, offset: u64, reloc: Reloc, addend: Addend, target: usize) -> bool; + + /// A debug-only option which is used to for + fn force_veneers(&mut self); + + /// Write the `data` provided at `offset`, for example when resolving a + /// relocation. + fn write(&mut self, offset: u64, data: &[u8]); + + /// Completes this text section, filling out any final details, and returns + /// the bytes of the text section. + fn finish(&mut self, ctrl_plane: &mut ControlPlane) -> Vec; +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/pcc.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/pcc.rs new file mode 100644 index 00000000000000..0c70a023838ffd --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/pcc.rs @@ -0,0 +1,169 @@ +//! Common helpers for ISA-specific proof-carrying-code implementations. + +use crate::ir::pcc::{Fact, FactContext, PccError, PccResult}; +use crate::machinst::{Reg, VCode, VCodeInst, Writable}; +use crate::trace; + +pub(crate) fn get_fact_or_default(vcode: &VCode, reg: Reg, width: u16) -> Fact { + trace!( + "get_fact_or_default: reg {reg:?} -> {:?}", + vcode.vreg_fact(reg.into()) + ); + vcode + .vreg_fact(reg.into()) + .cloned() + .unwrap_or_else(|| Fact::max_range_for_width(width)) +} + +pub(crate) fn has_fact(vcode: &VCode, reg: Reg) -> bool { + vcode.vreg_fact(reg.into()).is_some() +} + +pub(crate) fn fail_if_missing(fact: Option) -> PccResult { + fact.ok_or(PccError::UnsupportedFact) +} + +pub(crate) fn clamp_range( + ctx: &FactContext, + to_bits: u16, + from_bits: u16, + fact: Option, +) -> PccResult> { + let max = if from_bits > 64 { + return Ok(None); + } else if from_bits == 64 { + u64::MAX + } else { + (1u64 << from_bits) - 1 + }; + trace!( + "clamp_range: fact {:?} from {} to {}", + fact, + from_bits, + to_bits + ); + Ok(fact + .and_then(|f| ctx.uextend(&f, from_bits, to_bits)) + .or_else(|| { + let result = Fact::Range { + bit_width: to_bits, + min: 0, + max, + }; + trace!(" -> clamping to {:?}", result); + Some(result) + })) +} + +pub(crate) fn check_subsumes(ctx: &FactContext, subsumer: &Fact, subsumee: &Fact) -> PccResult<()> { + check_subsumes_optionals(ctx, Some(subsumer), Some(subsumee)) +} + +pub(crate) fn check_subsumes_optionals( + ctx: &FactContext, + subsumer: Option<&Fact>, + subsumee: Option<&Fact>, +) -> PccResult<()> { + trace!( + "checking if derived fact {:?} subsumes stated fact {:?}", + subsumer, + subsumee + ); + + if ctx.subsumes_fact_optionals(subsumer, subsumee) { + Ok(()) + } else { + Err(PccError::UnsupportedFact) + } +} + +pub(crate) fn check_output) -> PccResult>>( + ctx: &FactContext, + vcode: &mut VCode, + out: Writable, + ins: &[Reg], + f: F, +) -> PccResult<()> { + if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) { + let result = f(vcode)?; + check_subsumes_optionals(ctx, result.as_ref(), Some(fact)) + } else if ins.iter().any(|r| { + vcode + .vreg_fact(r.into()) + .map(|fact| fact.propagates()) + .unwrap_or(false) + }) { + if let Ok(Some(fact)) = f(vcode) { + trace!("setting vreg {:?} to {:?}", out, fact); + vcode.set_vreg_fact(out.to_reg().into(), fact); + } + Ok(()) + } else { + Ok(()) + } +} + +pub(crate) fn check_unop PccResult>>( + ctx: &FactContext, + vcode: &mut VCode, + reg_width: u16, + out: Writable, + ra: Reg, + f: F, +) -> PccResult<()> { + check_output(ctx, vcode, out, &[ra], |vcode| { + let ra = get_fact_or_default(vcode, ra, reg_width); + f(&ra) + }) +} + +pub(crate) fn check_binop PccResult>>( + ctx: &FactContext, + vcode: &mut VCode, + reg_width: u16, + out: Writable, + ra: Reg, + rb: Reg, + f: F, +) -> PccResult<()> { + check_output(ctx, vcode, out, &[ra, rb], |vcode| { + let ra = get_fact_or_default(vcode, ra, reg_width); + let rb = get_fact_or_default(vcode, rb, reg_width); + f(&ra, &rb) + }) +} + +pub(crate) fn check_constant( + ctx: &FactContext, + vcode: &mut VCode, + out: Writable, + bit_width: u16, + value: u64, +) -> PccResult<()> { + let result = Fact::constant(bit_width, value); + if let Some(fact) = vcode.vreg_fact(out.to_reg().into()) { + check_subsumes(ctx, &result, fact) + } else { + trace!("setting vreg {:?} to {:?}", out, result); + vcode.set_vreg_fact(out.to_reg().into(), result); + Ok(()) + } +} + +/// The operation we're checking against an amode: either +/// +/// - a *load*, and we need to validate that the field's fact subsumes +/// the load result's fact, OR +/// +/// - a *store*, and we need to validate that the stored data's fact +/// subsumes the field's fact. +pub(crate) enum LoadOrStore<'a> { + Load { + result_fact: Option<&'a Fact>, + from_bits: u16, + to_bits: u16, + }, + Store { + stored_fact: Option<&'a Fact>, + }, +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/reg.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/reg.rs new file mode 100644 index 00000000000000..2670e3ad12c3bf --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/reg.rs @@ -0,0 +1,486 @@ +//! Definitions for registers, operands, etc. Provides a thin +//! interface over the register allocator so that we can more easily +//! swap it out or shim it when necessary. + +use alloc::{string::String, vec::Vec}; +use core::{fmt::Debug, hash::Hash}; +use regalloc2::{Operand, OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, VReg}; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// The first 192 vregs (64 int, 64 float, 64 vec) are "pinned" to +/// physical registers: this means that they are always constrained to +/// the corresponding register at all use/mod/def sites. +/// +/// Arbitrary vregs can also be constrained to physical registers at +/// particular use/def/mod sites, and this is preferable; but pinned +/// vregs allow us to migrate code that has been written using +/// RealRegs directly. +const PINNED_VREGS: usize = 192; + +/// Convert a `VReg` to its pinned `PReg`, if any. +pub fn pinned_vreg_to_preg(vreg: VReg) -> Option { + if vreg.vreg() < PINNED_VREGS { + Some(PReg::from_index(vreg.vreg())) + } else { + None + } +} + +/// Give the first available vreg for generated code (i.e., after all +/// pinned vregs). +pub fn first_user_vreg_index() -> usize { + // This is just the constant defined above, but we keep the + // constant private and expose only this helper function with the + // specific name in order to ensure other parts of the code don't + // open-code and depend on the index-space scheme. + PINNED_VREGS +} + +/// A register named in an instruction. This register can be either a +/// virtual register or a fixed physical register. It does not have +/// any constraints applied to it: those can be added later in +/// `MachInst::get_operands()` when the `Reg`s are converted to +/// `Operand`s. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Reg(VReg); + +impl Reg { + /// Get the physical register (`RealReg`), if this register is + /// one. + pub fn to_real_reg(self) -> Option { + pinned_vreg_to_preg(self.0).map(RealReg) + } + + /// Get the virtual (non-physical) register, if this register is + /// one. + pub fn to_virtual_reg(self) -> Option { + if pinned_vreg_to_preg(self.0).is_none() { + Some(VirtualReg(self.0)) + } else { + None + } + } + + /// Get the class of this register. + pub fn class(self) -> RegClass { + self.0.class() + } + + /// Is this a real (physical) reg? + pub fn is_real(self) -> bool { + self.to_real_reg().is_some() + } + + /// Is this a virtual reg? + pub fn is_virtual(self) -> bool { + self.to_virtual_reg().is_some() + } +} + +impl std::fmt::Debug for Reg { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.0 == VReg::invalid() { + write!(f, "") + } else if let Some(rreg) = self.to_real_reg() { + let preg: PReg = rreg.into(); + write!(f, "{preg}") + } else if let Some(vreg) = self.to_virtual_reg() { + let vreg: VReg = vreg.into(); + write!(f, "{vreg}") + } else { + unreachable!() + } + } +} + +impl AsMut for Reg { + fn as_mut(&mut self) -> &mut Reg { + self + } +} + +/// A real (physical) register. This corresponds to one of the target +/// ISA's named registers and can be used as an instruction operand. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct RealReg(PReg); + +impl RealReg { + /// Get the class of this register. + pub fn class(self) -> RegClass { + self.0.class() + } + + /// The physical register number. + pub fn hw_enc(self) -> u8 { + self.0.hw_enc() as u8 + } +} + +impl std::fmt::Debug for RealReg { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + Reg::from(*self).fmt(f) + } +} + +/// A virtual register. This can be allocated into a real (physical) +/// register of the appropriate register class, but which one is not +/// specified. Virtual registers are used when generating `MachInst`s, +/// before register allocation occurs, in order to allow us to name as +/// many register-carried values as necessary. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct VirtualReg(VReg); + +impl VirtualReg { + /// Get the class of this register. + pub fn class(self) -> RegClass { + self.0.class() + } + + pub fn index(self) -> usize { + self.0.vreg() + } +} + +impl std::fmt::Debug for VirtualReg { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + Reg::from(*self).fmt(f) + } +} + +/// A type wrapper that indicates a register type is writable. The +/// underlying register can be extracted, and the type wrapper can be +/// built using an arbitrary register. Hence, this type-level wrapper +/// is not strictly a guarantee. However, "casting" to a writable +/// register is an explicit operation for which we can +/// audit. Ordinarily, internal APIs in the compiler backend should +/// take a `Writable` whenever the register is written, and the +/// usual, frictionless way to get one of these is to allocate a new +/// temporary. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct Writable { + reg: T, +} + +impl Writable { + /// Explicitly construct a `Writable` from a `T`. As noted in + /// the documentation for `Writable`, this is not hidden or + /// disallowed from the outside; anyone can perform the "cast"; + /// but it is explicit so that we can audit the use sites. + pub fn from_reg(reg: T) -> Writable { + Writable { reg } + } + + /// Get the underlying register, which can be read. + pub fn to_reg(self) -> T { + self.reg + } + + /// Get a mutable borrow of the underlying register. + pub fn reg_mut(&mut self) -> &mut T { + &mut self.reg + } + + /// Map the underlying register to another value or type. + pub fn map(self, f: impl Fn(T) -> U) -> Writable { + Writable { reg: f(self.reg) } + } +} + +// Conversions between regalloc2 types (VReg, PReg) and our types +// (VirtualReg, RealReg, Reg). + +impl std::convert::From for Reg { + fn from(vreg: regalloc2::VReg) -> Reg { + Reg(vreg) + } +} + +impl std::convert::From for VirtualReg { + fn from(vreg: regalloc2::VReg) -> VirtualReg { + debug_assert!(pinned_vreg_to_preg(vreg).is_none()); + VirtualReg(vreg) + } +} + +impl std::convert::From for regalloc2::VReg { + /// Extract the underlying `regalloc2::VReg`. Note that physical + /// registers also map to particular (special) VRegs, so this + /// method can be used either on virtual or physical `Reg`s. + fn from(reg: Reg) -> regalloc2::VReg { + reg.0 + } +} +impl std::convert::From<&Reg> for regalloc2::VReg { + fn from(reg: &Reg) -> regalloc2::VReg { + reg.0 + } +} + +impl std::convert::From for regalloc2::VReg { + fn from(reg: VirtualReg) -> regalloc2::VReg { + reg.0 + } +} + +impl std::convert::From for regalloc2::VReg { + fn from(reg: RealReg) -> regalloc2::VReg { + // This representation is redundant: the class is implied in the vreg + // index as well as being in the vreg class field. + VReg::new(reg.0.index(), reg.0.class()) + } +} + +impl std::convert::From for regalloc2::PReg { + fn from(reg: RealReg) -> regalloc2::PReg { + reg.0 + } +} + +impl std::convert::From for RealReg { + fn from(preg: regalloc2::PReg) -> RealReg { + RealReg(preg) + } +} + +impl std::convert::From for Reg { + fn from(preg: regalloc2::PReg) -> Reg { + RealReg(preg).into() + } +} + +impl std::convert::From for Reg { + fn from(reg: RealReg) -> Reg { + Reg(reg.into()) + } +} + +impl std::convert::From for Reg { + fn from(reg: VirtualReg) -> Reg { + Reg(reg.0) + } +} + +/// A spill slot. +pub type SpillSlot = regalloc2::SpillSlot; + +/// A register class. Each register in the ISA has one class, and the +/// classes are disjoint. Most modern ISAs will have just two classes: +/// the integer/general-purpose registers (GPRs), and the float/vector +/// registers (typically used for both). +/// +/// Note that unlike some other compiler backend/register allocator +/// designs, we do not allow for overlapping classes, i.e. registers +/// that belong to more than one class, because doing so makes the +/// allocation problem significantly more complex. Instead, when a +/// register can be addressed under different names for different +/// sizes (for example), the backend author should pick classes that +/// denote some fundamental allocation unit that encompasses the whole +/// register. For example, always allocate 128-bit vector registers +/// `v0`..`vN`, even though `f32` and `f64` values may use only the +/// low 32/64 bits of those registers and name them differently. +pub type RegClass = regalloc2::RegClass; + +/// An OperandCollector is a wrapper around a Vec of Operands +/// (flattened array for a whole sequence of instructions) that +/// gathers operands from a single instruction and provides the range +/// in the flattened array. +#[derive(Debug)] +pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> { + operands: &'a mut Vec, + clobbers: PRegSet, + + /// The subset of physical registers that are allocatable. + allocatable: PRegSet, + + renamer: F, +} + +impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> { + /// Start gathering operands into one flattened operand array. + pub fn new(operands: &'a mut Vec, allocatable: PRegSet, renamer: F) -> Self { + Self { + operands, + clobbers: PRegSet::default(), + allocatable, + renamer, + } + } + + /// Finish the operand collection and return the tuple giving the + /// range of indices in the flattened operand array, and the + /// clobber set. + pub fn finish(self) -> (usize, PRegSet) { + let end = self.operands.len(); + (end, self.clobbers) + } +} + +pub trait OperandVisitor { + fn add_operand( + &mut self, + reg: &mut Reg, + constraint: OperandConstraint, + kind: OperandKind, + pos: OperandPos, + ); + + fn debug_assert_is_allocatable_preg(&self, _reg: PReg, _expected: bool) {} + + /// Add a register clobber set. This is a set of registers that + /// are written by the instruction, so must be reserved (not used) + /// for the whole instruction, but are not used afterward. + fn reg_clobbers(&mut self, _regs: PRegSet) {} +} + +pub trait OperandVisitorImpl: OperandVisitor { + /// Add a use of a fixed, nonallocatable physical register. + fn reg_fixed_nonallocatable(&mut self, preg: PReg) { + self.debug_assert_is_allocatable_preg(preg, false); + // Since this operand does not participate in register allocation, + // there's nothing to do here. + } + + /// Add a register use, at the start of the instruction (`Before` + /// position). + fn reg_use(&mut self, reg: &mut impl AsMut) { + self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Early); + } + + /// Add a register use, at the end of the instruction (`After` position). + fn reg_late_use(&mut self, reg: &mut impl AsMut) { + self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Late); + } + + /// Add a register def, at the end of the instruction (`After` + /// position). Use only when this def will be written after all + /// uses are read. + fn reg_def(&mut self, reg: &mut Writable>) { + self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Late); + } + + /// Add a register "early def", which logically occurs at the + /// beginning of the instruction, alongside all uses. Use this + /// when the def may be written before all uses are read; the + /// regalloc will ensure that it does not overwrite any uses. + fn reg_early_def(&mut self, reg: &mut Writable>) { + self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Early); + } + + /// Add a register "fixed use", which ties a vreg to a particular + /// RealReg at the end of the instruction. + fn reg_fixed_late_use(&mut self, reg: &mut impl AsMut, rreg: Reg) { + self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Late); + } + + /// Add a register "fixed use", which ties a vreg to a particular + /// RealReg at this point. + fn reg_fixed_use(&mut self, reg: &mut impl AsMut, rreg: Reg) { + self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Early); + } + + /// Add a register "fixed def", which ties a vreg to a particular + /// RealReg at this point. + fn reg_fixed_def(&mut self, reg: &mut Writable>, rreg: Reg) { + self.reg_fixed(reg.reg.as_mut(), rreg, OperandKind::Def, OperandPos::Late); + } + + /// Add an operand tying a virtual register to a physical register. + fn reg_fixed(&mut self, reg: &mut Reg, rreg: Reg, kind: OperandKind, pos: OperandPos) { + debug_assert!(reg.is_virtual()); + let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg"); + self.debug_assert_is_allocatable_preg(rreg.into(), true); + let constraint = OperandConstraint::FixedReg(rreg.into()); + self.add_operand(reg, constraint, kind, pos); + } + + /// Add an operand which might already be a physical register. + fn reg_maybe_fixed(&mut self, reg: &mut Reg, kind: OperandKind, pos: OperandPos) { + if let Some(rreg) = reg.to_real_reg() { + self.reg_fixed_nonallocatable(rreg.into()); + } else { + debug_assert!(reg.is_virtual()); + self.add_operand(reg, OperandConstraint::Reg, kind, pos); + } + } + + /// Add a register def that reuses an earlier use-operand's + /// allocation. The index of that earlier operand (relative to the + /// current instruction's start of operands) must be known. + fn reg_reuse_def(&mut self, reg: &mut Writable>, idx: usize) { + let reg = reg.reg.as_mut(); + if let Some(rreg) = reg.to_real_reg() { + // In some cases we see real register arguments to a reg_reuse_def + // constraint. We assume the creator knows what they're doing + // here, though we do also require that the real register be a + // fixed-nonallocatable register. + self.reg_fixed_nonallocatable(rreg.into()); + } else { + debug_assert!(reg.is_virtual()); + // The operand we're reusing must not be fixed-nonallocatable, as + // that would imply that the register has been allocated to a + // virtual register. + let constraint = OperandConstraint::Reuse(idx); + self.add_operand(reg, constraint, OperandKind::Def, OperandPos::Late); + } + } +} + +impl OperandVisitorImpl for T {} + +impl<'a, F: Fn(VReg) -> VReg> OperandVisitor for OperandCollector<'a, F> { + fn add_operand( + &mut self, + reg: &mut Reg, + constraint: OperandConstraint, + kind: OperandKind, + pos: OperandPos, + ) { + reg.0 = (self.renamer)(reg.0); + self.operands + .push(Operand::new(reg.0, constraint, kind, pos)); + } + + fn debug_assert_is_allocatable_preg(&self, reg: PReg, expected: bool) { + debug_assert_eq!( + self.allocatable.contains(reg), + expected, + "{reg:?} should{} be allocatable", + if expected { "" } else { " not" } + ); + } + + fn reg_clobbers(&mut self, regs: PRegSet) { + self.clobbers.union_from(regs); + } +} + +impl OperandVisitor for T { + fn add_operand( + &mut self, + reg: &mut Reg, + constraint: OperandConstraint, + kind: OperandKind, + pos: OperandPos, + ) { + self(reg, constraint, kind, pos) + } +} + +/// Pretty-print part of a disassembly, with knowledge of +/// operand/instruction size, and optionally with regalloc +/// results. This can be used, for example, to print either `rax` or +/// `eax` for the register by those names on x86-64, depending on a +/// 64- or 32-bit context. +pub trait PrettyPrint { + fn pretty_print(&self, size_bytes: u8) -> String; + + fn pretty_print_default(&self) -> String { + self.pretty_print(0) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/valueregs.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/valueregs.rs new file mode 100644 index 00000000000000..cc238978a20cf8 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/valueregs.rs @@ -0,0 +1,154 @@ +//! Data structure for tracking the (possibly multiple) registers that hold one +//! SSA `Value`. + +use regalloc2::{PReg, VReg}; + +use super::{RealReg, Reg, VirtualReg, Writable}; +use std::fmt::Debug; + +const VALUE_REGS_PARTS: usize = 2; + +/// Location at which a `Value` is stored in register(s): the value is located +/// in one or more registers, depending on its width. A value may be stored in +/// more than one register if the machine has no registers wide enough +/// otherwise: for example, on a 32-bit architecture, we may store `I64` values +/// in two registers, and `I128` values in four. +/// +/// By convention, the register parts are kept in machine-endian order here. +/// +/// N.B.: we cap the capacity of this at four (when any 32-bit target is +/// enabled) or two (otherwise), and we use special in-band sentinel `Reg` +/// values (`Reg::invalid()`) to avoid the need to carry a separate length. This +/// allows the struct to be `Copy` (no heap or drop overhead) and be only 16 or +/// 8 bytes, which is important for compiler performance. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct ValueRegs { + parts: [R; VALUE_REGS_PARTS], +} + +impl Debug for ValueRegs { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut f = f.debug_tuple("ValueRegs"); + let mut last_valid = true; + for part in self.parts { + if part.is_invalid_sentinel() { + last_valid = false; + } else { + debug_assert!(last_valid); + f.field(&part); + } + } + f.finish() + } +} + +/// A type with an "invalid" sentinel value. +pub trait InvalidSentinel: Copy + Eq { + /// The invalid sentinel value. + fn invalid_sentinel() -> Self; + /// Is this the invalid sentinel? + fn is_invalid_sentinel(self) -> bool { + self == Self::invalid_sentinel() + } +} +impl InvalidSentinel for Reg { + fn invalid_sentinel() -> Self { + Reg::from(VReg::invalid()) + } +} +impl InvalidSentinel for VirtualReg { + fn invalid_sentinel() -> Self { + VirtualReg::from(VReg::invalid()) + } +} +impl InvalidSentinel for RealReg { + fn invalid_sentinel() -> Self { + RealReg::from(PReg::invalid()) + } +} +impl InvalidSentinel for Writable { + fn invalid_sentinel() -> Self { + Writable::from_reg(Reg::invalid_sentinel()) + } +} + +impl ValueRegs { + /// Create an invalid Value-in-Reg. + pub fn invalid() -> Self { + ValueRegs { + parts: [R::invalid_sentinel(); VALUE_REGS_PARTS], + } + } + + /// Is this Value-to-Reg mapping valid? + pub fn is_valid(self) -> bool { + !self.parts[0].is_invalid_sentinel() + } + /// Is this Value-to-Reg mapping invalid? + pub fn is_invalid(self) -> bool { + self.parts[0].is_invalid_sentinel() + } + + /// Return the single register used for this value, if any. + pub fn only_reg(self) -> Option { + if self.len() == 1 { + Some(self.parts[0]) + } else { + None + } + } + + /// Return a slice of the registers storing this value. + pub fn regs(&self) -> &[R] { + &self.parts[0..self.len()] + } + + /// Return a mutable slice of the registers storing this value. + pub fn regs_mut(&mut self) -> &mut [R] { + let len = self.len(); + &mut self.parts[0..len] + } +} + +impl ValueRegs { + /// Create a Value-in-R location for a value stored in one register. + pub fn one(reg: R) -> Self { + ValueRegs { + parts: [reg, R::invalid_sentinel()], + } + } + /// Create a Value-in-R location for a value stored in two registers. + pub fn two(r1: R, r2: R) -> Self { + ValueRegs { parts: [r1, r2] } + } + + /// Return the number of registers used. + pub fn len(self) -> usize { + // If rustc/LLVM is smart enough, this might even be vectorized... + (self.parts[0] != R::invalid_sentinel()) as usize + + (self.parts[1] != R::invalid_sentinel()) as usize + } + + /// Map individual registers via a map function. + pub fn map(self, f: F) -> ValueRegs + where + NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel, + F: Fn(R) -> NewR, + { + ValueRegs { + parts: [f(self.parts[0]), f(self.parts[1])], + } + } +} + +/// Create a writable ValueRegs. +#[allow(dead_code)] +pub(crate) fn writable_value_regs(regs: ValueRegs) -> ValueRegs> { + regs.map(|r| Writable::from_reg(r)) +} + +/// Strip a writable ValueRegs down to a readonly ValueRegs. +#[allow(dead_code)] +pub(crate) fn non_writable_value_regs(regs: ValueRegs>) -> ValueRegs { + regs.map(|r| r.to_reg()) +} diff --git a/deps/crates/vendor/cranelift-codegen/src/machinst/vcode.rs b/deps/crates/vendor/cranelift-codegen/src/machinst/vcode.rs new file mode 100644 index 00000000000000..12c816530f047b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/machinst/vcode.rs @@ -0,0 +1,1762 @@ +//! This implements the VCode container: a CFG of Insts that have been lowered. +//! +//! VCode is virtual-register code. An instruction in VCode is almost a machine +//! instruction; however, its register slots can refer to virtual registers in +//! addition to real machine registers. +//! +//! VCode is structured with traditional basic blocks, and +//! each block must be terminated by an unconditional branch (one target), a +//! conditional branch (two targets), or a return (no targets). Note that this +//! slightly differs from the machine code of most ISAs: in most ISAs, a +//! conditional branch has one target (and the not-taken case falls through). +//! However, we expect that machine backends will elide branches to the following +//! block (i.e., zero-offset jumps), and will be able to codegen a branch-cond / +//! branch-uncond pair if *both* targets are not fallthrough. This allows us to +//! play with layout prior to final binary emission, as well, if we want. +//! +//! See the main module comment in `mod.rs` for more details on the VCode-based +//! backend pipeline. + +use crate::ir::pcc::*; +use crate::ir::{self, types, Constant, ConstantData, ValueLabel}; +use crate::machinst::*; +use crate::ranges::Ranges; +use crate::timing; +use crate::trace; +use crate::CodegenError; +use crate::{LabelValueLoc, ValueLocRange}; +use regalloc2::{ + Edit, Function as RegallocFunction, InstOrEdit, InstRange, MachineEnv, Operand, + OperandConstraint, OperandKind, PRegSet, RegClass, +}; +use rustc_hash::FxHashMap; + +use core::mem::take; +use cranelift_entity::{entity_impl, Keys}; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::fmt; + +/// Index referring to an instruction in VCode. +pub type InsnIndex = regalloc2::Inst; + +/// Extension trait for `InsnIndex` to allow conversion to a +/// `BackwardsInsnIndex`. +trait ToBackwardsInsnIndex { + fn to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex; +} + +impl ToBackwardsInsnIndex for InsnIndex { + fn to_backwards_insn_index(&self, num_insts: usize) -> BackwardsInsnIndex { + BackwardsInsnIndex::new(num_insts - self.index() - 1) + } +} + +/// An index referring to an instruction in the VCode when it is backwards, +/// during VCode construction. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "enable-serde", + derive(::serde::Serialize, ::serde::Deserialize) +)] +pub struct BackwardsInsnIndex(InsnIndex); + +impl BackwardsInsnIndex { + pub fn new(i: usize) -> Self { + BackwardsInsnIndex(InsnIndex::new(i)) + } +} + +/// Index referring to a basic block in VCode. +pub type BlockIndex = regalloc2::Block; + +/// VCodeInst wraps all requirements for a MachInst to be in VCode: it must be +/// a `MachInst` and it must be able to emit itself at least to a `SizeCodeSink`. +pub trait VCodeInst: MachInst + MachInstEmit {} +impl VCodeInst for I {} + +/// A function in "VCode" (virtualized-register code) form, after +/// lowering. This is essentially a standard CFG of basic blocks, +/// where each basic block consists of lowered instructions produced +/// by the machine-specific backend. +/// +/// Note that the VCode is immutable once produced, and is not +/// modified by register allocation in particular. Rather, register +/// allocation on the `VCode` produces a separate `regalloc2::Output` +/// struct, and this can be passed to `emit`. `emit` in turn does not +/// modify the vcode, but produces an `EmitResult`, which contains the +/// machine code itself, and the associated disassembly and/or +/// metadata as requested. +pub struct VCode { + /// VReg IR-level types. + vreg_types: Vec, + + /// Lowered machine instructions in order corresponding to the original IR. + insts: Vec, + + /// A map from backwards instruction index to the user stack map for that + /// instruction. + /// + /// This is a sparse side table that only has entries for instructions that + /// are safepoints, and only for a subset of those that have an associated + /// user stack map. + user_stack_maps: FxHashMap, + + /// Operands: pre-regalloc references to virtual registers with + /// constraints, in one flattened array. This allows the regalloc + /// to efficiently access all operands without requiring expensive + /// matches or method invocations on insts. + operands: Vec, + + /// Operand index ranges: for each instruction in `insts`, there + /// is a tuple here providing the range in `operands` for that + /// instruction's operands. + operand_ranges: Ranges, + + /// Clobbers: a sparse map from instruction indices to clobber masks. + clobbers: FxHashMap, + + /// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is + /// reasonable to keep one of these per instruction.) + srclocs: Vec, + + /// Entry block. + entry: BlockIndex, + + /// Block instruction indices. + block_ranges: Ranges, + + /// Block successors: index range in the `block_succs` list. + block_succ_range: Ranges, + + /// Block successor lists, concatenated into one vec. The + /// `block_succ_range` list of tuples above gives (start, end) + /// ranges within this list that correspond to each basic block's + /// successors. + block_succs: Vec, + + /// Block predecessors: index range in the `block_preds` list. + block_pred_range: Ranges, + + /// Block predecessor lists, concatenated into one vec. The + /// `block_pred_range` list of tuples above gives (start, end) + /// ranges within this list that correspond to each basic block's + /// predecessors. + block_preds: Vec, + + /// Block parameters: index range in `block_params` below. + block_params_range: Ranges, + + /// Block parameter lists, concatenated into one vec. The + /// `block_params_range` list of tuples above gives (start, end) + /// ranges within this list that correspond to each basic block's + /// blockparam vregs. + block_params: Vec, + + /// Outgoing block arguments on branch instructions, concatenated + /// into one list. + /// + /// Note that this is conceptually a 3D array: we have a VReg list + /// per block, per successor. We flatten those three dimensions + /// into this 1D vec, then store index ranges in two levels of + /// indirection. + /// + /// Indexed by the indices in `branch_block_arg_succ_range`. + branch_block_args: Vec, + + /// Array of sequences of (start, end) tuples in + /// `branch_block_args`, one for each successor; these sequences + /// for each block are concatenated. + /// + /// Indexed by the indices in `branch_block_arg_succ_range`. + branch_block_arg_range: Ranges, + + /// For a given block, indices in `branch_block_arg_range` + /// corresponding to all of its successors. + branch_block_arg_succ_range: Ranges, + + /// Block-order information. + block_order: BlockLoweringOrder, + + /// ABI object. + pub(crate) abi: Callee, + + /// Constant information used during code emission. This should be + /// immutable across function compilations within the same module. + emit_info: I::Info, + + /// Constants. + pub(crate) constants: VCodeConstants, + + /// Value labels for debuginfo attached to vregs. + debug_value_labels: Vec<(VReg, InsnIndex, InsnIndex, u32)>, + + pub(crate) sigs: SigSet, + + /// Facts on VRegs, for proof-carrying code verification. + facts: Vec>, +} + +/// The result of `VCode::emit`. Contains all information computed +/// during emission: actual machine code, optionally a disassembly, +/// and optionally metadata about the code layout. +pub struct EmitResult { + /// The MachBuffer containing the machine code. + pub buffer: MachBufferFinalized, + + /// Offset of each basic block, recorded during emission. Computed + /// only if `debug_value_labels` is non-empty. + pub bb_offsets: Vec, + + /// Final basic-block edges, in terms of code offsets of + /// bb-starts. Computed only if `debug_value_labels` is non-empty. + pub bb_edges: Vec<(CodeOffset, CodeOffset)>, + + /// Final length of function body. + pub func_body_len: CodeOffset, + + /// The pretty-printed disassembly, if any. This uses the same + /// pretty-printing for MachInsts as the pre-regalloc VCode Debug + /// implementation, but additionally includes the prologue and + /// epilogue(s), and makes use of the regalloc results. + pub disasm: Option, + + /// Offsets of sized stackslots. + pub sized_stackslot_offsets: PrimaryMap, + + /// Offsets of dynamic stackslots. + pub dynamic_stackslot_offsets: PrimaryMap, + + /// Value-labels information (debug metadata). + pub value_labels_ranges: ValueLabelsRanges, + + /// Stack frame size. + pub frame_size: u32, +} + +/// A builder for a VCode function body. +/// +/// This builder has the ability to accept instructions in either +/// forward or reverse order, depending on the pass direction that +/// produces the VCode. The lowering from CLIF to VCode +/// ordinarily occurs in reverse order (in order to allow instructions +/// to be lowered only if used, and not merged) so a reversal will +/// occur at the end of lowering to ensure the VCode is in machine +/// order. +/// +/// If built in reverse, block and instruction indices used once the +/// VCode is built are relative to the final (reversed) order, not the +/// order of construction. Note that this means we do not know the +/// final block or instruction indices when building, so we do not +/// hand them out. (The user is assumed to know them when appending +/// terminator instructions with successor blocks.) +pub struct VCodeBuilder { + /// In-progress VCode. + pub(crate) vcode: VCode, + + /// In what direction is the build occurring? + direction: VCodeBuildDirection, + + /// Debug-value label in-progress map, keyed by label. For each + /// label, we keep disjoint ranges mapping to vregs. We'll flatten + /// this into (vreg, range, label) tuples when done. + debug_info: FxHashMap>, +} + +/// Direction in which a VCodeBuilder builds VCode. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum VCodeBuildDirection { + // TODO: add `Forward` once we need it and can test it adequately. + /// Backward-build pass: we expect the producer to call `emit()` + /// with instructions in reverse program order within each block. + Backward, +} + +impl VCodeBuilder { + /// Create a new VCodeBuilder. + pub fn new( + sigs: SigSet, + abi: Callee, + emit_info: I::Info, + block_order: BlockLoweringOrder, + constants: VCodeConstants, + direction: VCodeBuildDirection, + ) -> Self { + let vcode = VCode::new(sigs, abi, emit_info, block_order, constants); + + VCodeBuilder { + vcode, + direction, + debug_info: FxHashMap::default(), + } + } + + pub fn init_retval_area(&mut self, vregs: &mut VRegAllocator) -> CodegenResult<()> { + self.vcode.abi.init_retval_area(&self.vcode.sigs, vregs) + } + + /// Access the ABI object. + pub fn abi(&self) -> &Callee { + &self.vcode.abi + } + + /// Access the ABI object. + pub fn abi_mut(&mut self) -> &mut Callee { + &mut self.vcode.abi + } + + pub fn sigs(&self) -> &SigSet { + &self.vcode.sigs + } + + pub fn sigs_mut(&mut self) -> &mut SigSet { + &mut self.vcode.sigs + } + + /// Access to the BlockLoweringOrder object. + pub fn block_order(&self) -> &BlockLoweringOrder { + &self.vcode.block_order + } + + /// Set the current block as the entry block. + pub fn set_entry(&mut self, block: BlockIndex) { + self.vcode.entry = block; + } + + /// End the current basic block. Must be called after emitting vcode insts + /// for IR insts and prior to ending the function (building the VCode). + pub fn end_bb(&mut self) { + let end_idx = self.vcode.insts.len(); + // Add the instruction index range to the list of blocks. + self.vcode.block_ranges.push_end(end_idx); + // End the successors list. + let succ_end = self.vcode.block_succs.len(); + self.vcode.block_succ_range.push_end(succ_end); + // End the blockparams list. + let block_params_end = self.vcode.block_params.len(); + self.vcode.block_params_range.push_end(block_params_end); + // End the branch blockparam args list. + let branch_block_arg_succ_end = self.vcode.branch_block_arg_range.len(); + self.vcode + .branch_block_arg_succ_range + .push_end(branch_block_arg_succ_end); + } + + pub fn add_block_param(&mut self, param: VirtualReg) { + self.vcode.block_params.push(param.into()); + } + + fn add_branch_args_for_succ(&mut self, args: &[Reg]) { + self.vcode + .branch_block_args + .extend(args.iter().map(|&arg| VReg::from(arg))); + let end = self.vcode.branch_block_args.len(); + self.vcode.branch_block_arg_range.push_end(end); + } + + /// Push an instruction for the current BB and current IR inst + /// within the BB. + pub fn push(&mut self, insn: I, loc: RelSourceLoc) { + self.vcode.insts.push(insn); + self.vcode.srclocs.push(loc); + } + + /// Add a successor block with branch args. + pub fn add_succ(&mut self, block: BlockIndex, args: &[Reg]) { + self.vcode.block_succs.push(block); + self.add_branch_args_for_succ(args); + } + + /// Add a debug value label to a register. + pub fn add_value_label(&mut self, reg: Reg, label: ValueLabel) { + // We'll fix up labels in reverse(). Because we're generating + // code bottom-to-top, the liverange of the label goes *from* + // the last index at which was defined (or 0, which is the end + // of the eventual function) *to* just this instruction, and + // no further. + let inst = InsnIndex::new(self.vcode.insts.len()); + let labels = self.debug_info.entry(label).or_insert_with(|| vec![]); + let last = labels + .last() + .map(|(_start, end, _vreg)| *end) + .unwrap_or(InsnIndex::new(0)); + labels.push((last, inst, reg.into())); + } + + /// Access the constants. + pub fn constants(&mut self) -> &mut VCodeConstants { + &mut self.vcode.constants + } + + fn compute_preds_from_succs(&mut self) { + // Do a linear-time counting sort: first determine how many + // times each block appears as a successor. + let mut starts = vec![0u32; self.vcode.num_blocks()]; + for succ in &self.vcode.block_succs { + starts[succ.index()] += 1; + } + + // Determine for each block the starting index where that + // block's predecessors should go. This is equivalent to the + // ranges we need to store in block_pred_range. + self.vcode.block_pred_range.reserve(starts.len()); + let mut end = 0; + for count in starts.iter_mut() { + let start = end; + end += *count; + *count = start; + self.vcode.block_pred_range.push_end(end as usize); + } + let end = end as usize; + debug_assert_eq!(end, self.vcode.block_succs.len()); + + // Walk over the successors again, this time grouped by + // predecessor, and push the predecessor at the current + // starting position of each of its successors. We build + // each group of predecessors in whatever order Ranges::iter + // returns them; regalloc2 doesn't care. + self.vcode.block_preds.resize(end, BlockIndex::invalid()); + for (pred, range) in self.vcode.block_succ_range.iter() { + let pred = BlockIndex::new(pred); + for succ in &self.vcode.block_succs[range] { + let pos = &mut starts[succ.index()]; + self.vcode.block_preds[*pos as usize] = pred; + *pos += 1; + } + } + debug_assert!(self.vcode.block_preds.iter().all(|pred| pred.is_valid())); + } + + /// Called once, when a build in Backward order is complete, to + /// perform the overall reversal (into final forward order) and + /// finalize metadata accordingly. + fn reverse_and_finalize(&mut self, vregs: &VRegAllocator) { + let n_insts = self.vcode.insts.len(); + if n_insts == 0 { + return; + } + + // Reverse the per-block and per-inst sequences. + self.vcode.block_ranges.reverse_index(); + self.vcode.block_ranges.reverse_target(n_insts); + // block_params_range is indexed by block (and blocks were + // traversed in reverse) so we reverse it; but block-param + // sequences in the concatenated vec can remain in reverse + // order (it is effectively an arena of arbitrarily-placed + // referenced sequences). + self.vcode.block_params_range.reverse_index(); + // Likewise, we reverse block_succ_range, but the block_succ + // concatenated array can remain as-is. + self.vcode.block_succ_range.reverse_index(); + self.vcode.insts.reverse(); + self.vcode.srclocs.reverse(); + // Likewise, branch_block_arg_succ_range is indexed by block + // so must be reversed. + self.vcode.branch_block_arg_succ_range.reverse_index(); + + // To translate an instruction index *endpoint* in reversed + // order to forward order, compute `n_insts - i`. + // + // Why not `n_insts - 1 - i`? That would be correct to + // translate an individual instruction index (for ten insts 0 + // to 9 inclusive, inst 0 becomes 9, and inst 9 becomes + // 0). But for the usual inclusive-start, exclusive-end range + // idiom, inclusive starts become exclusive ends and + // vice-versa, so e.g. an (inclusive) start of 0 becomes an + // (exclusive) end of 10. + let translate = |inst: InsnIndex| InsnIndex::new(n_insts - inst.index()); + + // Generate debug-value labels based on per-label maps. + for (label, tuples) in &self.debug_info { + for &(start, end, vreg) in tuples { + let vreg = vregs.resolve_vreg_alias(vreg); + let fwd_start = translate(end); + let fwd_end = translate(start); + self.vcode + .debug_value_labels + .push((vreg, fwd_start, fwd_end, label.as_u32())); + } + } + + // Now sort debug value labels by VReg, as required + // by regalloc2. + self.vcode + .debug_value_labels + .sort_unstable_by_key(|(vreg, _, _, _)| *vreg); + } + + fn collect_operands(&mut self, vregs: &VRegAllocator) { + let allocatable = PRegSet::from(self.vcode.machine_env()); + for (i, insn) in self.vcode.insts.iter_mut().enumerate() { + // Push operands from the instruction onto the operand list. + // + // We rename through the vreg alias table as we collect + // the operands. This is better than a separate post-pass + // over operands, because it has more cache locality: + // operands only need to pass through L1 once. This is + // also better than renaming instructions' + // operands/registers while lowering, because here we only + // need to do the `match` over the instruction to visit + // its register fields (which is slow, branchy code) once. + + let mut op_collector = + OperandCollector::new(&mut self.vcode.operands, allocatable, |vreg| { + vregs.resolve_vreg_alias(vreg) + }); + insn.get_operands(&mut op_collector); + let (ops, clobbers) = op_collector.finish(); + self.vcode.operand_ranges.push_end(ops); + + if clobbers != PRegSet::default() { + self.vcode.clobbers.insert(InsnIndex::new(i), clobbers); + } + + if let Some((dst, src)) = insn.is_move() { + // We should never see non-virtual registers present in move + // instructions. + assert!( + src.is_virtual(), + "the real register {src:?} was used as the source of a move instruction" + ); + assert!( + dst.to_reg().is_virtual(), + "the real register {:?} was used as the destination of a move instruction", + dst.to_reg() + ); + } + } + + // Translate blockparam args via the vreg aliases table as well. + for arg in &mut self.vcode.branch_block_args { + let new_arg = vregs.resolve_vreg_alias(*arg); + trace!("operandcollector: block arg {:?} -> {:?}", arg, new_arg); + *arg = new_arg; + } + } + + /// Build the final VCode. + pub fn build(mut self, mut vregs: VRegAllocator) -> VCode { + self.vcode.vreg_types = take(&mut vregs.vreg_types); + self.vcode.facts = take(&mut vregs.facts); + + if self.direction == VCodeBuildDirection::Backward { + self.reverse_and_finalize(&vregs); + } + self.collect_operands(&vregs); + + self.compute_preds_from_succs(); + self.vcode.debug_value_labels.sort_unstable(); + + // At this point, nothing in the vcode should mention any + // VReg which has been aliased. All the appropriate rewriting + // should have happened above. Just to be sure, let's + // double-check each field which has vregs. + // Note: can't easily check vcode.insts, resolved in collect_operands. + // Operands are resolved in collect_operands. + vregs.debug_assert_no_vreg_aliases(self.vcode.operands.iter().map(|op| op.vreg())); + // Currently block params are never aliased to another vreg. + vregs.debug_assert_no_vreg_aliases(self.vcode.block_params.iter().copied()); + // Branch block args are resolved in collect_operands. + vregs.debug_assert_no_vreg_aliases(self.vcode.branch_block_args.iter().copied()); + // Debug value labels are resolved in reverse_and_finalize. + vregs.debug_assert_no_vreg_aliases( + self.vcode.debug_value_labels.iter().map(|&(vreg, ..)| vreg), + ); + // Facts are resolved eagerly during set_vreg_alias. + vregs.debug_assert_no_vreg_aliases( + self.vcode + .facts + .iter() + .zip(&vregs.vreg_types) + .enumerate() + .filter(|(_, (fact, _))| fact.is_some()) + .map(|(vreg, (_, &ty))| { + let (regclasses, _) = I::rc_for_type(ty).unwrap(); + VReg::new(vreg, regclasses[0]) + }), + ); + + self.vcode + } + + /// Add a user stack map for the associated instruction. + pub fn add_user_stack_map( + &mut self, + inst: BackwardsInsnIndex, + entries: &[ir::UserStackMapEntry], + ) { + let stack_map = ir::UserStackMap::new(entries, self.vcode.abi.sized_stackslot_offsets()); + let old_entry = self.vcode.user_stack_maps.insert(inst, stack_map); + debug_assert!(old_entry.is_none()); + } +} + +const NO_INST_OFFSET: CodeOffset = u32::MAX; + +impl VCode { + /// New empty VCode. + fn new( + sigs: SigSet, + abi: Callee, + emit_info: I::Info, + block_order: BlockLoweringOrder, + constants: VCodeConstants, + ) -> Self { + let n_blocks = block_order.lowered_order().len(); + VCode { + sigs, + vreg_types: vec![], + insts: Vec::with_capacity(10 * n_blocks), + user_stack_maps: FxHashMap::default(), + operands: Vec::with_capacity(30 * n_blocks), + operand_ranges: Ranges::with_capacity(10 * n_blocks), + clobbers: FxHashMap::default(), + srclocs: Vec::with_capacity(10 * n_blocks), + entry: BlockIndex::new(0), + block_ranges: Ranges::with_capacity(n_blocks), + block_succ_range: Ranges::with_capacity(n_blocks), + block_succs: Vec::with_capacity(n_blocks), + block_pred_range: Ranges::default(), + block_preds: Vec::new(), + block_params_range: Ranges::with_capacity(n_blocks), + block_params: Vec::with_capacity(5 * n_blocks), + branch_block_args: Vec::with_capacity(10 * n_blocks), + branch_block_arg_range: Ranges::with_capacity(2 * n_blocks), + branch_block_arg_succ_range: Ranges::with_capacity(n_blocks), + block_order, + abi, + emit_info, + constants, + debug_value_labels: vec![], + facts: vec![], + } + } + + /// Get the ABI-dependent MachineEnv for managing register allocation. + pub fn machine_env(&self) -> &MachineEnv { + self.abi.machine_env(&self.sigs) + } + + /// Get the number of blocks. Block indices will be in the range `0 .. + /// (self.num_blocks() - 1)`. + pub fn num_blocks(&self) -> usize { + self.block_ranges.len() + } + + /// The number of lowered instructions. + pub fn num_insts(&self) -> usize { + self.insts.len() + } + + fn compute_clobbers(&self, regalloc: ®alloc2::Output) -> Vec> { + let mut clobbered = PRegSet::default(); + + // All moves are included in clobbers. + for (_, Edit::Move { to, .. }) in ®alloc.edits { + if let Some(preg) = to.as_reg() { + clobbered.add(preg); + } + } + + for (i, range) in self.operand_ranges.iter() { + // Skip this instruction if not "included in clobbers" as + // per the MachInst. (Some backends use this to implement + // ABI specifics; e.g., excluding calls of the same ABI as + // the current function from clobbers, because by + // definition everything clobbered by the call can be + // clobbered by this function without saving as well.) + if !self.insts[i].is_included_in_clobbers() { + continue; + } + + let operands = &self.operands[range.clone()]; + let allocs = ®alloc.allocs[range]; + for (operand, alloc) in operands.iter().zip(allocs.iter()) { + if operand.kind() == OperandKind::Def { + if let Some(preg) = alloc.as_reg() { + clobbered.add(preg); + } + } + } + + // Also add explicitly-clobbered registers. + if let Some(&inst_clobbered) = self.clobbers.get(&InsnIndex::new(i)) { + clobbered.union_from(inst_clobbered); + } + } + + clobbered + .into_iter() + .map(|preg| Writable::from_reg(RealReg::from(preg))) + .collect() + } + + /// Emit the instructions to a `MachBuffer`, containing fixed-up + /// code and external reloc/trap/etc. records ready for use. Takes + /// the regalloc results as well. + /// + /// Returns the machine code itself, and optionally metadata + /// and/or a disassembly, as an `EmitResult`. The `VCode` itself + /// is consumed by the emission process. + pub fn emit( + mut self, + regalloc: ®alloc2::Output, + want_disasm: bool, + flags: &settings::Flags, + ctrl_plane: &mut ControlPlane, + ) -> EmitResult + where + I: VCodeInst, + { + // To write into disasm string. + use core::fmt::Write; + + let _tt = timing::vcode_emit(); + let mut buffer = MachBuffer::new(); + let mut bb_starts: Vec> = vec![]; + + // The first M MachLabels are reserved for block indices. + buffer.reserve_labels_for_blocks(self.num_blocks()); + + // Register all allocated constants with the `MachBuffer` to ensure that + // any references to the constants during instructions can be handled + // correctly. + buffer.register_constants(&self.constants); + + // Construct the final order we emit code in: cold blocks at the end. + let mut final_order: SmallVec<[BlockIndex; 16]> = smallvec![]; + let mut cold_blocks: SmallVec<[BlockIndex; 16]> = smallvec![]; + for block in 0..self.num_blocks() { + let block = BlockIndex::new(block); + if self.block_order.is_cold(block) { + cold_blocks.push(block); + } else { + final_order.push(block); + } + } + final_order.extend(cold_blocks.clone()); + + // Compute/save info we need for the prologue: clobbers and + // number of spillslots. + // + // We clone `abi` here because we will mutate it as we + // generate the prologue and set other info, but we can't + // mutate `VCode`. The info it usually carries prior to + // setting clobbers is fairly minimal so this should be + // relatively cheap. + let clobbers = self.compute_clobbers(regalloc); + self.abi + .compute_frame_layout(&self.sigs, regalloc.num_spillslots, clobbers); + + // Emit blocks. + let mut cur_srcloc = None; + let mut last_offset = None; + let mut inst_offsets = vec![]; + let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane)); + + let mut disasm = String::new(); + + if !self.debug_value_labels.is_empty() { + inst_offsets.resize(self.insts.len(), NO_INST_OFFSET); + } + + // Count edits per block ahead of time; this is needed for + // lookahead island emission. (We could derive it per-block + // with binary search in the edit list, but it's more + // efficient to do it in one pass here.) + let mut ra_edits_per_block: SmallVec<[u32; 64]> = smallvec![]; + let mut edit_idx = 0; + for block in 0..self.num_blocks() { + let end_inst = InsnIndex::new(self.block_ranges.get(block).end); + let start_edit_idx = edit_idx; + while edit_idx < regalloc.edits.len() && regalloc.edits[edit_idx].0.inst() < end_inst { + edit_idx += 1; + } + let end_edit_idx = edit_idx; + ra_edits_per_block.push((end_edit_idx - start_edit_idx) as u32); + } + + let is_forward_edge_cfi_enabled = self.abi.is_forward_edge_cfi_enabled(); + let mut bb_padding = match flags.bb_padding_log2_minus_one() { + 0 => Vec::new(), + n => vec![0; 1 << (n - 1)], + }; + let mut total_bb_padding = 0; + + for (block_order_idx, &block) in final_order.iter().enumerate() { + trace!("emitting block {:?}", block); + + // Call the new block hook for state + state.on_new_block(); + + // Emit NOPs to align the block. + let new_offset = I::align_basic_block(buffer.cur_offset()); + while new_offset > buffer.cur_offset() { + // Pad with NOPs up to the aligned block offset. + let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize); + nop.emit(&mut buffer, &self.emit_info, &mut Default::default()); + } + assert_eq!(buffer.cur_offset(), new_offset); + + let do_emit = |inst: &I, + disasm: &mut String, + buffer: &mut MachBuffer, + state: &mut I::State| { + if want_disasm && !inst.is_args() { + let mut s = state.clone(); + writeln!(disasm, " {}", inst.pretty_print_inst(&mut s)).unwrap(); + } + inst.emit(buffer, &self.emit_info, state); + }; + + // Is this the first block? Emit the prologue directly if so. + if block == self.entry { + trace!(" -> entry block"); + buffer.start_srcloc(Default::default()); + for inst in &self.abi.gen_prologue() { + do_emit(&inst, &mut disasm, &mut buffer, &mut state); + } + buffer.end_srcloc(); + } + + // Now emit the regular block body. + + buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut()); + + if want_disasm { + writeln!(&mut disasm, "block{}:", block.index()).unwrap(); + } + + if flags.machine_code_cfg_info() { + // Track BB starts. If we have backed up due to MachBuffer + // branch opts, note that the removed blocks were removed. + let cur_offset = buffer.cur_offset(); + if last_offset.is_some() && cur_offset <= last_offset.unwrap() { + for i in (0..bb_starts.len()).rev() { + if bb_starts[i].is_some() && cur_offset > bb_starts[i].unwrap() { + break; + } + bb_starts[i] = None; + } + } + bb_starts.push(Some(cur_offset)); + last_offset = Some(cur_offset); + } + + if let Some(block_start) = I::gen_block_start( + self.block_order.is_indirect_branch_target(block), + is_forward_edge_cfi_enabled, + ) { + do_emit(&block_start, &mut disasm, &mut buffer, &mut state); + } + + for inst_or_edit in regalloc.block_insts_and_edits(&self, block) { + match inst_or_edit { + InstOrEdit::Inst(iix) => { + if !self.debug_value_labels.is_empty() { + // If we need to produce debug info, + // record the offset of each instruction + // so that we can translate value-label + // ranges to machine-code offsets. + + // Cold blocks violate monotonicity + // assumptions elsewhere (that + // instructions in inst-index order are in + // order in machine code), so we omit + // their offsets here. Value-label range + // generation below will skip empty ranges + // and ranges with to-offsets of zero. + if !self.block_order.is_cold(block) { + inst_offsets[iix.index()] = buffer.cur_offset(); + } + } + + // Update the srcloc at this point in the buffer. + let srcloc = self.srclocs[iix.index()]; + if cur_srcloc != Some(srcloc) { + if cur_srcloc.is_some() { + buffer.end_srcloc(); + } + buffer.start_srcloc(srcloc); + cur_srcloc = Some(srcloc); + } + + // If this is a safepoint, compute a stack map + // and pass it to the emit state. + let stack_map_disasm = if self.insts[iix.index()].is_safepoint() { + let (user_stack_map, user_stack_map_disasm) = { + // The `user_stack_maps` is keyed by reverse + // instruction index, so we must flip the + // index. We can't put this into a helper method + // due to borrowck issues because parts of + // `self` are borrowed mutably elsewhere in this + // function. + let index = iix.to_backwards_insn_index(self.num_insts()); + let user_stack_map = self.user_stack_maps.remove(&index); + let user_stack_map_disasm = + user_stack_map.as_ref().map(|m| format!(" ; {m:?}")); + (user_stack_map, user_stack_map_disasm) + }; + + state.pre_safepoint(user_stack_map); + + user_stack_map_disasm + } else { + None + }; + + // If the instruction we are about to emit is + // a return, place an epilogue at this point + // (and don't emit the return; the actual + // epilogue will contain it). + if self.insts[iix.index()].is_term() == MachTerminator::Ret { + for inst in self.abi.gen_epilogue() { + do_emit(&inst, &mut disasm, &mut buffer, &mut state); + } + } else { + // Update the operands for this inst using the + // allocations from the regalloc result. + let mut allocs = regalloc.inst_allocs(iix).iter(); + self.insts[iix.index()].get_operands( + &mut |reg: &mut Reg, constraint, _kind, _pos| { + let alloc = allocs + .next() + .expect("enough allocations for all operands") + .as_reg() + .expect("only register allocations, not stack allocations") + .into(); + + if let OperandConstraint::FixedReg(rreg) = constraint { + debug_assert_eq!(Reg::from(rreg), alloc); + } + *reg = alloc; + }, + ); + debug_assert!(allocs.next().is_none()); + + // Emit the instruction! + do_emit( + &self.insts[iix.index()], + &mut disasm, + &mut buffer, + &mut state, + ); + if let Some(stack_map_disasm) = stack_map_disasm { + disasm.push_str(&stack_map_disasm); + disasm.push('\n'); + } + } + } + + InstOrEdit::Edit(Edit::Move { from, to }) => { + // Create a move/spill/reload instruction and + // immediately emit it. + match (from.as_reg(), to.as_reg()) { + (Some(from), Some(to)) => { + // Reg-to-reg move. + let from_rreg = Reg::from(from); + let to_rreg = Writable::from_reg(Reg::from(to)); + debug_assert_eq!(from.class(), to.class()); + let ty = I::canonical_type_for_rc(from.class()); + let mv = I::gen_move(to_rreg, from_rreg, ty); + do_emit(&mv, &mut disasm, &mut buffer, &mut state); + } + (Some(from), None) => { + // Spill from register to spillslot. + let to = to.as_stack().unwrap(); + let from_rreg = RealReg::from(from); + let spill = self.abi.gen_spill(to, from_rreg); + do_emit(&spill, &mut disasm, &mut buffer, &mut state); + } + (None, Some(to)) => { + // Load from spillslot to register. + let from = from.as_stack().unwrap(); + let to_rreg = Writable::from_reg(RealReg::from(to)); + let reload = self.abi.gen_reload(to_rreg, from); + do_emit(&reload, &mut disasm, &mut buffer, &mut state); + } + (None, None) => { + panic!("regalloc2 should have eliminated stack-to-stack moves!"); + } + } + } + } + } + + if cur_srcloc.is_some() { + buffer.end_srcloc(); + cur_srcloc = None; + } + + // Do we need an island? Get the worst-case size of the next BB, add + // it to the optional padding behind the block, and pass this to the + // `MachBuffer` to determine if an island is necessary. + let worst_case_next_bb = if block_order_idx < final_order.len() - 1 { + let next_block = final_order[block_order_idx + 1]; + let next_block_range = self.block_ranges.get(next_block.index()); + let next_block_size = next_block_range.len() as u32; + let next_block_ra_insertions = ra_edits_per_block[next_block.index()]; + I::worst_case_size() * (next_block_size + next_block_ra_insertions) + } else { + 0 + }; + let padding = if bb_padding.is_empty() { + 0 + } else { + bb_padding.len() as u32 + I::LabelUse::ALIGN - 1 + }; + if buffer.island_needed(padding + worst_case_next_bb) { + buffer.emit_island(padding + worst_case_next_bb, ctrl_plane); + } + + // Insert padding, if configured, to stress the `MachBuffer`'s + // relocation and island calculations. + // + // Padding can get quite large during fuzzing though so place a + // total cap on it where when a per-function threshold is exceeded + // the padding is turned back down to zero. This avoids a small-ish + // test case generating a GB+ memory footprint in Cranelift for + // example. + if !bb_padding.is_empty() { + buffer.put_data(&bb_padding); + buffer.align_to(I::LabelUse::ALIGN); + total_bb_padding += bb_padding.len(); + if total_bb_padding > (150 << 20) { + bb_padding = Vec::new(); + } + } + } + + debug_assert!( + self.user_stack_maps.is_empty(), + "any stack maps should have been consumed by instruction emission, still have: {:#?}", + self.user_stack_maps, + ); + + // Do any optimizations on branches at tail of buffer, as if we had + // bound one last label. + buffer.optimize_branches(ctrl_plane); + + // emission state is not needed anymore, move control plane back out + *ctrl_plane = state.take_ctrl_plane(); + + let func_body_len = buffer.cur_offset(); + + // Create `bb_edges` and final (filtered) `bb_starts`. + let mut bb_edges = vec![]; + let mut bb_offsets = vec![]; + if flags.machine_code_cfg_info() { + for block in 0..self.num_blocks() { + if bb_starts[block].is_none() { + // Block was deleted by MachBuffer; skip. + continue; + } + let from = bb_starts[block].unwrap(); + + bb_offsets.push(from); + // Resolve each `succ` label and add edges. + let succs = self.block_succs(BlockIndex::new(block)); + for &succ in succs.iter() { + let to = buffer.resolve_label_offset(MachLabel::from_block(succ)); + bb_edges.push((from, to)); + } + } + } + + self.monotonize_inst_offsets(&mut inst_offsets[..], func_body_len); + let value_labels_ranges = + self.compute_value_labels_ranges(regalloc, &inst_offsets[..], func_body_len); + let frame_size = self.abi.frame_size(); + + EmitResult { + buffer: buffer.finish(&self.constants, ctrl_plane), + bb_offsets, + bb_edges, + func_body_len, + disasm: if want_disasm { Some(disasm) } else { None }, + sized_stackslot_offsets: self.abi.sized_stackslot_offsets().clone(), + dynamic_stackslot_offsets: self.abi.dynamic_stackslot_offsets().clone(), + value_labels_ranges, + frame_size, + } + } + + fn monotonize_inst_offsets(&self, inst_offsets: &mut [CodeOffset], func_body_len: u32) { + if self.debug_value_labels.is_empty() { + return; + } + + // During emission, branch removal can make offsets of instructions incorrect. + // Consider the following sequence: [insi][jmp0][jmp1][jmp2][insj] + // It will be recorded as (say): [30] [34] [38] [42] [] + // When the jumps get removed we are left with (in "inst_offsets"): + // [insi][jmp0][jmp1][jmp2][insj][...] + // [30] [34] [38] [42] [34] + // Which violates the monotonicity invariant. This method sets offsets of these + // removed instructions such as to make them appear zero-sized: + // [insi][jmp0][jmp1][jmp2][insj][...] + // [30] [34] [34] [34] [34] + // + let mut next_offset = func_body_len; + for inst_index in (0..(inst_offsets.len() - 1)).rev() { + let inst_offset = inst_offsets[inst_index]; + + // Not all instructions get their offsets recorded. + if inst_offset == NO_INST_OFFSET { + continue; + } + + if inst_offset > next_offset { + trace!( + "Fixing code offset of the removed Inst {}: {} -> {}", + inst_index, + inst_offset, + next_offset + ); + inst_offsets[inst_index] = next_offset; + continue; + } + + next_offset = inst_offset; + } + } + + fn compute_value_labels_ranges( + &self, + regalloc: ®alloc2::Output, + inst_offsets: &[CodeOffset], + func_body_len: u32, + ) -> ValueLabelsRanges { + if self.debug_value_labels.is_empty() { + return ValueLabelsRanges::default(); + } + + let mut value_labels_ranges: ValueLabelsRanges = HashMap::new(); + for &(label, from, to, alloc) in ®alloc.debug_locations { + let ranges = value_labels_ranges + .entry(ValueLabel::from_u32(label)) + .or_insert_with(|| vec![]); + let from_offset = inst_offsets[from.inst().index()]; + let to_offset = if to.inst().index() == inst_offsets.len() { + func_body_len + } else { + inst_offsets[to.inst().index()] + }; + + // Empty ranges or unavailable offsets can happen + // due to cold blocks and branch removal (see above). + if from_offset == NO_INST_OFFSET + || to_offset == NO_INST_OFFSET + || from_offset == to_offset + { + continue; + } + + let loc = if let Some(preg) = alloc.as_reg() { + LabelValueLoc::Reg(Reg::from(preg)) + } else { + let slot = alloc.as_stack().unwrap(); + let slot_offset = self.abi.get_spillslot_offset(slot); + let slot_base_to_caller_sp_offset = self.abi.slot_base_to_caller_sp_offset(); + let caller_sp_to_cfa_offset = + crate::isa::unwind::systemv::caller_sp_to_cfa_offset(); + // NOTE: this is a negative offset because it's relative to the caller's SP + let cfa_to_sp_offset = + -((slot_base_to_caller_sp_offset + caller_sp_to_cfa_offset) as i64); + LabelValueLoc::CFAOffset(cfa_to_sp_offset + slot_offset) + }; + + // ValueLocRanges are recorded by *instruction-end + // offset*. `from_offset` is the *start* of the + // instruction; that is the same as the end of another + // instruction, so we only want to begin coverage once + // we are past the previous instruction's end. + let start = from_offset + 1; + + // Likewise, `end` is exclusive, but we want to + // *include* the end of the last + // instruction. `to_offset` is the start of the + // `to`-instruction, which is the exclusive end, i.e., + // the first instruction not covered. That + // instruction's start is the same as the end of the + // last instruction that is included, so we go one + // byte further to be sure to include it. + let end = to_offset + 1; + + // Coalesce adjacent ranges that for the same location + // to minimize output size here and for the consumers. + if let Some(last_loc_range) = ranges.last_mut() { + if last_loc_range.loc == loc && last_loc_range.end == start { + trace!( + "Extending debug range for VL{} in {:?} to {}", + label, + loc, + end + ); + last_loc_range.end = end; + continue; + } + } + + trace!( + "Recording debug range for VL{} in {:?}: [Inst {}..Inst {}) [{}..{})", + label, + loc, + from.inst().index(), + to.inst().index(), + start, + end + ); + + ranges.push(ValueLocRange { loc, start, end }); + } + + value_labels_ranges + } + + /// Get the IR block for a BlockIndex, if one exists. + pub fn bindex_to_bb(&self, block: BlockIndex) -> Option { + self.block_order.lowered_order()[block.index()].orig_block() + } + + /// Get the type of a VReg. + pub fn vreg_type(&self, vreg: VReg) -> Type { + self.vreg_types[vreg.vreg()] + } + + /// Get the fact, if any, for a given VReg. + pub fn vreg_fact(&self, vreg: VReg) -> Option<&Fact> { + self.facts[vreg.vreg()].as_ref() + } + + /// Set the fact for a given VReg. + pub fn set_vreg_fact(&mut self, vreg: VReg, fact: Fact) { + trace!("set fact on {}: {:?}", vreg, fact); + self.facts[vreg.vreg()] = Some(fact); + } + + /// Does a given instruction define any facts? + pub fn inst_defines_facts(&self, inst: InsnIndex) -> bool { + self.inst_operands(inst) + .iter() + .filter(|o| o.kind() == OperandKind::Def) + .map(|o| o.vreg()) + .any(|vreg| self.facts[vreg.vreg()].is_some()) + } + + /// Get the user stack map associated with the given forward instruction index. + pub fn get_user_stack_map(&self, inst: InsnIndex) -> Option<&ir::UserStackMap> { + let index = inst.to_backwards_insn_index(self.num_insts()); + self.user_stack_maps.get(&index) + } +} + +impl std::ops::Index for VCode { + type Output = I; + fn index(&self, idx: InsnIndex) -> &Self::Output { + &self.insts[idx.index()] + } +} + +impl RegallocFunction for VCode { + fn num_insts(&self) -> usize { + self.insts.len() + } + + fn num_blocks(&self) -> usize { + self.block_ranges.len() + } + + fn entry_block(&self) -> BlockIndex { + self.entry + } + + fn block_insns(&self, block: BlockIndex) -> InstRange { + let range = self.block_ranges.get(block.index()); + InstRange::new(InsnIndex::new(range.start), InsnIndex::new(range.end)) + } + + fn block_succs(&self, block: BlockIndex) -> &[BlockIndex] { + let range = self.block_succ_range.get(block.index()); + &self.block_succs[range] + } + + fn block_preds(&self, block: BlockIndex) -> &[BlockIndex] { + let range = self.block_pred_range.get(block.index()); + &self.block_preds[range] + } + + fn block_params(&self, block: BlockIndex) -> &[VReg] { + // As a special case we don't return block params for the entry block, as all the arguments + // will be defined by the `Inst::Args` instruction. + if block == self.entry { + return &[]; + } + + let range = self.block_params_range.get(block.index()); + &self.block_params[range] + } + + fn branch_blockparams(&self, block: BlockIndex, _insn: InsnIndex, succ_idx: usize) -> &[VReg] { + let succ_range = self.branch_block_arg_succ_range.get(block.index()); + debug_assert!(succ_idx < succ_range.len()); + let branch_block_args = self.branch_block_arg_range.get(succ_range.start + succ_idx); + &self.branch_block_args[branch_block_args] + } + + fn is_ret(&self, insn: InsnIndex) -> bool { + match self.insts[insn.index()].is_term() { + // We treat blocks terminated by an unconditional trap like a return for regalloc. + MachTerminator::None => self.insts[insn.index()].is_trap(), + MachTerminator::Ret | MachTerminator::RetCall => true, + MachTerminator::Uncond | MachTerminator::Cond | MachTerminator::Indirect => false, + } + } + + fn is_branch(&self, insn: InsnIndex) -> bool { + match self.insts[insn.index()].is_term() { + MachTerminator::Cond | MachTerminator::Uncond | MachTerminator::Indirect => true, + _ => false, + } + } + + fn inst_operands(&self, insn: InsnIndex) -> &[Operand] { + let range = self.operand_ranges.get(insn.index()); + &self.operands[range] + } + + fn inst_clobbers(&self, insn: InsnIndex) -> PRegSet { + self.clobbers.get(&insn).cloned().unwrap_or_default() + } + + fn num_vregs(&self) -> usize { + self.vreg_types.len() + } + + fn debug_value_labels(&self) -> &[(VReg, InsnIndex, InsnIndex, u32)] { + &self.debug_value_labels + } + + fn spillslot_size(&self, regclass: RegClass) -> usize { + self.abi.get_spillslot_size(regclass) as usize + } + + fn allow_multiple_vreg_defs(&self) -> bool { + // At least the s390x backend requires this, because the + // `Loop` pseudo-instruction aggregates all Operands so pinned + // vregs (RealRegs) may occur more than once. + true + } +} + +impl Debug for VRegAllocator { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "VRegAllocator {{")?; + + let mut alias_keys = self.vreg_aliases.keys().cloned().collect::>(); + alias_keys.sort_unstable(); + for key in alias_keys { + let dest = self.vreg_aliases.get(&key).unwrap(); + writeln!(f, " {:?} := {:?}", Reg::from(key), Reg::from(*dest))?; + } + + for (vreg, fact) in self.facts.iter().enumerate() { + if let Some(fact) = fact { + writeln!(f, " v{vreg} ! {fact}")?; + } + } + + writeln!(f, "}}") + } +} + +impl fmt::Debug for VCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "VCode {{")?; + writeln!(f, " Entry block: {}", self.entry.index())?; + + let mut state = Default::default(); + + for block in 0..self.num_blocks() { + let block = BlockIndex::new(block); + writeln!( + f, + "Block {}({:?}):", + block.index(), + self.block_params(block) + )?; + if let Some(bb) = self.bindex_to_bb(block) { + writeln!(f, " (original IR block: {bb})")?; + } + for (succ_idx, succ) in self.block_succs(block).iter().enumerate() { + writeln!( + f, + " (successor: Block {}({:?}))", + succ.index(), + self.branch_blockparams(block, InsnIndex::new(0) /* dummy */, succ_idx) + )?; + } + for inst in self.block_ranges.get(block.index()) { + writeln!( + f, + " Inst {}: {}", + inst, + self.insts[inst].pretty_print_inst(&mut state) + )?; + if !self.operands.is_empty() { + for operand in self.inst_operands(InsnIndex::new(inst)) { + if operand.kind() == OperandKind::Def { + if let Some(fact) = &self.facts[operand.vreg().vreg()] { + writeln!(f, " v{} ! {}", operand.vreg().vreg(), fact)?; + } + } + } + } + if let Some(user_stack_map) = self.get_user_stack_map(InsnIndex::new(inst)) { + writeln!(f, " {user_stack_map:?}")?; + } + } + } + + writeln!(f, "}}")?; + Ok(()) + } +} + +/// This structure manages VReg allocation during the lifetime of the VCodeBuilder. +pub struct VRegAllocator { + /// VReg IR-level types. + vreg_types: Vec, + + /// VReg aliases. When the final VCode is built we rewrite all + /// uses of the keys in this table to their replacement values. + /// + /// We use these aliases to rename an instruction's expected + /// result vregs to the returned vregs from lowering, which are + /// usually freshly-allocated temps. + vreg_aliases: FxHashMap, + + /// A deferred error, to be bubbled up to the top level of the + /// lowering algorithm. We take this approach because we cannot + /// currently propagate a `Result` upward through ISLE code (the + /// lowering rules) or some ABI code. + deferred_error: Option, + + /// Facts on VRegs, for proof-carrying code. + facts: Vec>, + + /// The type of instruction that this allocator makes registers for. + _inst: core::marker::PhantomData, +} + +impl VRegAllocator { + /// Make a new VRegAllocator. + pub fn with_capacity(capacity: usize) -> Self { + let capacity = first_user_vreg_index() + capacity; + let mut vreg_types = Vec::with_capacity(capacity); + vreg_types.resize(first_user_vreg_index(), types::INVALID); + Self { + vreg_types, + vreg_aliases: FxHashMap::with_capacity_and_hasher(capacity, Default::default()), + deferred_error: None, + facts: Vec::with_capacity(capacity), + _inst: core::marker::PhantomData::default(), + } + } + + /// Allocate a fresh ValueRegs. + pub fn alloc(&mut self, ty: Type) -> CodegenResult> { + if self.deferred_error.is_some() { + return Err(CodegenError::CodeTooLarge); + } + let v = self.vreg_types.len(); + let (regclasses, tys) = I::rc_for_type(ty)?; + if v + regclasses.len() >= VReg::MAX { + return Err(CodegenError::CodeTooLarge); + } + + let regs: ValueRegs = match regclasses { + &[rc0] => ValueRegs::one(VReg::new(v, rc0).into()), + &[rc0, rc1] => ValueRegs::two(VReg::new(v, rc0).into(), VReg::new(v + 1, rc1).into()), + // We can extend this if/when we support 32-bit targets; e.g., + // an i128 on a 32-bit machine will need up to four machine regs + // for a `Value`. + _ => panic!("Value must reside in 1 or 2 registers"), + }; + for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { + let vreg = reg.to_virtual_reg().unwrap(); + debug_assert_eq!(self.vreg_types.len(), vreg.index()); + self.vreg_types.push(reg_ty); + } + + // Create empty facts for each allocated vreg. + self.facts.resize(self.vreg_types.len(), None); + + Ok(regs) + } + + /// Allocate a fresh ValueRegs, deferring any out-of-vregs + /// errors. This is useful in places where we cannot bubble a + /// `CodegenResult` upward easily, and which are known to be + /// invoked from within the lowering loop that checks the deferred + /// error status below. + pub fn alloc_with_deferred_error(&mut self, ty: Type) -> ValueRegs { + match self.alloc(ty) { + Ok(x) => x, + Err(e) => { + self.deferred_error = Some(e); + self.bogus_for_deferred_error(ty) + } + } + } + + /// Take any deferred error that was accumulated by `alloc_with_deferred_error`. + pub fn take_deferred_error(&mut self) -> Option { + self.deferred_error.take() + } + + /// Produce an bogus VReg placeholder with the proper number of + /// registers for the given type. This is meant to be used with + /// deferred allocation errors (see `Lower::alloc_tmp()`). + fn bogus_for_deferred_error(&self, ty: Type) -> ValueRegs { + let (regclasses, _tys) = I::rc_for_type(ty).expect("must have valid type"); + match regclasses { + &[rc0] => ValueRegs::one(VReg::new(0, rc0).into()), + &[rc0, rc1] => ValueRegs::two(VReg::new(0, rc0).into(), VReg::new(1, rc1).into()), + _ => panic!("Value must reside in 1 or 2 registers"), + } + } + + /// Rewrite any mention of `from` into `to`. + pub fn set_vreg_alias(&mut self, from: Reg, to: Reg) { + let from = from.into(); + let resolved_to = self.resolve_vreg_alias(to.into()); + // Disallow cycles (see below). + assert_ne!(resolved_to, from); + + // Maintain the invariant that PCC facts only exist on vregs + // which aren't aliases. We want to preserve whatever was + // stated about the vreg before its producer was lowered. + if let Some(fact) = self.facts[from.vreg()].take() { + self.set_fact(resolved_to, fact); + } + + let old_alias = self.vreg_aliases.insert(from, resolved_to); + debug_assert_eq!(old_alias, None); + } + + fn resolve_vreg_alias(&self, mut vreg: regalloc2::VReg) -> regalloc2::VReg { + // We prevent cycles from existing by resolving targets of + // aliases eagerly before setting them. If the target resolves + // to the origin of the alias, then a cycle would be created + // and the alias is disallowed. Because of the structure of + // SSA code (one instruction can refer to another's defs but + // not vice-versa, except indirectly through + // phis/blockparams), cycles should not occur as we use + // aliases to redirect vregs to the temps that actually define + // them. + while let Some(to) = self.vreg_aliases.get(&vreg) { + vreg = *to; + } + vreg + } + + #[inline] + fn debug_assert_no_vreg_aliases(&self, mut list: impl Iterator) { + debug_assert!(list.all(|vreg| !self.vreg_aliases.contains_key(&vreg))); + } + + /// Set the proof-carrying code fact on a given virtual register. + /// + /// Returns the old fact, if any (only one fact can be stored). + fn set_fact(&mut self, vreg: regalloc2::VReg, fact: Fact) -> Option { + trace!("vreg {:?} has fact: {:?}", vreg, fact); + debug_assert!(!self.vreg_aliases.contains_key(&vreg)); + self.facts[vreg.vreg()].replace(fact) + } + + /// Set a fact only if one doesn't already exist. + pub fn set_fact_if_missing(&mut self, vreg: VirtualReg, fact: Fact) { + let vreg = self.resolve_vreg_alias(vreg.into()); + if self.facts[vreg.vreg()].is_none() { + self.set_fact(vreg, fact); + } + } + + /// Allocate a fresh ValueRegs, with a given fact to apply if + /// the value fits in one VReg. + pub fn alloc_with_maybe_fact( + &mut self, + ty: Type, + fact: Option, + ) -> CodegenResult> { + let result = self.alloc(ty)?; + + // Ensure that we don't lose a fact on a value that splits + // into multiple VRegs. + assert!(result.len() == 1 || fact.is_none()); + if let Some(fact) = fact { + self.set_fact(result.regs()[0].into(), fact); + } + + Ok(result) + } +} + +/// This structure tracks the large constants used in VCode that will be emitted separately by the +/// [MachBuffer]. +/// +/// First, during the lowering phase, constants are inserted using +/// [VCodeConstants.insert]; an intermediate handle, `VCodeConstant`, tracks what constants are +/// used in this phase. Some deduplication is performed, when possible, as constant +/// values are inserted. +/// +/// Secondly, during the emission phase, the [MachBuffer] assigns [MachLabel]s for each of the +/// constants so that instructions can refer to the value's memory location. The [MachBuffer] +/// then writes the constant values to the buffer. +#[derive(Default)] +pub struct VCodeConstants { + constants: PrimaryMap, + pool_uses: HashMap, + well_known_uses: HashMap<*const [u8], VCodeConstant>, + u64s: HashMap<[u8; 8], VCodeConstant>, +} +impl VCodeConstants { + /// Initialize the structure with the expected number of constants. + pub fn with_capacity(expected_num_constants: usize) -> Self { + Self { + constants: PrimaryMap::with_capacity(expected_num_constants), + pool_uses: HashMap::with_capacity(expected_num_constants), + well_known_uses: HashMap::new(), + u64s: HashMap::new(), + } + } + + /// Insert a constant; using this method indicates that a constant value will be used and thus + /// will be emitted to the `MachBuffer`. The current implementation can deduplicate constants + /// that are [VCodeConstantData::Pool] or [VCodeConstantData::WellKnown] but not + /// [VCodeConstantData::Generated]. + pub fn insert(&mut self, data: VCodeConstantData) -> VCodeConstant { + match data { + VCodeConstantData::Generated(_) => self.constants.push(data), + VCodeConstantData::Pool(constant, _) => match self.pool_uses.get(&constant) { + None => { + let vcode_constant = self.constants.push(data); + self.pool_uses.insert(constant, vcode_constant); + vcode_constant + } + Some(&vcode_constant) => vcode_constant, + }, + VCodeConstantData::WellKnown(data_ref) => { + match self.well_known_uses.entry(data_ref as *const [u8]) { + Entry::Vacant(v) => { + let vcode_constant = self.constants.push(data); + v.insert(vcode_constant); + vcode_constant + } + Entry::Occupied(o) => *o.get(), + } + } + VCodeConstantData::U64(value) => match self.u64s.entry(value) { + Entry::Vacant(v) => { + let vcode_constant = self.constants.push(data); + v.insert(vcode_constant); + vcode_constant + } + Entry::Occupied(o) => *o.get(), + }, + } + } + + /// Return the number of constants inserted. + pub fn len(&self) -> usize { + self.constants.len() + } + + /// Iterate over the `VCodeConstant` keys inserted in this structure. + pub fn keys(&self) -> Keys { + self.constants.keys() + } + + /// Iterate over the `VCodeConstant` keys and the data (as a byte slice) inserted in this + /// structure. + pub fn iter(&self) -> impl Iterator { + self.constants.iter() + } + + /// Returns the data associated with the specified constant. + pub fn get(&self, c: VCodeConstant) -> &VCodeConstantData { + &self.constants[c] + } + + /// Checks if the given [VCodeConstantData] is registered as + /// used by the pool. + pub fn pool_uses(&self, constant: &VCodeConstantData) -> bool { + match constant { + VCodeConstantData::Pool(c, _) => self.pool_uses.contains_key(c), + _ => false, + } + } +} + +/// A use of a constant by one or more VCode instructions; see [VCodeConstants]. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct VCodeConstant(u32); +entity_impl!(VCodeConstant); + +/// Identify the different types of constant that can be inserted into [VCodeConstants]. Tracking +/// these separately instead of as raw byte buffers allows us to avoid some duplication. +pub enum VCodeConstantData { + /// A constant already present in the Cranelift IR + /// [ConstantPool](crate::ir::constant::ConstantPool). + Pool(Constant, ConstantData), + /// A reference to a well-known constant value that is statically encoded within the compiler. + WellKnown(&'static [u8]), + /// A constant value generated during lowering; the value may depend on the instruction context + /// which makes it difficult to de-duplicate--if possible, use other variants. + Generated(ConstantData), + /// A constant of at most 64 bits. These are deduplicated as + /// well. Stored as a fixed-size array of `u8` so that we do not + /// encounter endianness problems when cross-compiling. + U64([u8; 8]), +} +impl VCodeConstantData { + /// Retrieve the constant data as a byte slice. + pub fn as_slice(&self) -> &[u8] { + match self { + VCodeConstantData::Pool(_, d) | VCodeConstantData::Generated(d) => d.as_slice(), + VCodeConstantData::WellKnown(d) => d, + VCodeConstantData::U64(value) => &value[..], + } + } + + /// Calculate the alignment of the constant data. + pub fn alignment(&self) -> u32 { + if self.as_slice().len() <= 8 { + 8 + } else { + 16 + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::mem::size_of; + + #[test] + fn size_of_constant_structs() { + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 24); + assert_eq!(size_of::(), 32); + assert_eq!( + size_of::>(), + 24 + ); + // TODO The VCodeConstants structure's memory size could be further optimized. + // With certain versions of Rust, each `HashMap` in `VCodeConstants` occupied at + // least 48 bytes, making an empty `VCodeConstants` cost 120 bytes. + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/nan_canonicalization.rs b/deps/crates/vendor/cranelift-codegen/src/nan_canonicalization.rs new file mode 100644 index 00000000000000..e6a73deaf83aa3 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/nan_canonicalization.rs @@ -0,0 +1,126 @@ +//! A NaN-canonicalizing rewriting pass. Patch floating point arithmetic +//! instructions that may return a NaN result with a sequence of operations +//! that will replace nondeterministic NaN's with a single canonical NaN value. + +use crate::cursor::{Cursor, FuncCursor}; +use crate::ir::condcodes::FloatCC; +use crate::ir::immediates::{Ieee32, Ieee64}; +use crate::ir::types::{self}; +use crate::ir::{Function, Inst, InstBuilder, InstructionData, Opcode, Value}; +use crate::opts::MemFlags; +use crate::timing; + +/// Perform the NaN canonicalization pass. +pub fn do_nan_canonicalization(func: &mut Function, has_vector_support: bool) { + let _tt = timing::canonicalize_nans(); + let mut pos = FuncCursor::new(func); + while let Some(_block) = pos.next_block() { + while let Some(inst) = pos.next_inst() { + if is_fp_arith(&mut pos, inst) { + add_nan_canon_seq(&mut pos, inst, has_vector_support); + } + } + } +} + +/// Returns true/false based on whether the instruction is a floating-point +/// arithmetic operation. This ignores operations like `fneg`, `fabs`, or +/// `fcopysign` that only operate on the sign bit of a floating point value. +fn is_fp_arith(pos: &mut FuncCursor, inst: Inst) -> bool { + match pos.func.dfg.insts[inst] { + InstructionData::Unary { opcode, .. } => { + opcode == Opcode::Ceil + || opcode == Opcode::Floor + || opcode == Opcode::Nearest + || opcode == Opcode::Sqrt + || opcode == Opcode::Trunc + || opcode == Opcode::Fdemote + || opcode == Opcode::Fpromote + || opcode == Opcode::FvpromoteLow + || opcode == Opcode::Fvdemote + } + InstructionData::Binary { opcode, .. } => { + opcode == Opcode::Fadd + || opcode == Opcode::Fdiv + || opcode == Opcode::Fmax + || opcode == Opcode::Fmin + || opcode == Opcode::Fmul + || opcode == Opcode::Fsub + } + InstructionData::Ternary { opcode, .. } => opcode == Opcode::Fma, + _ => false, + } +} + +/// Append a sequence of canonicalizing instructions after the given instruction. +fn add_nan_canon_seq(pos: &mut FuncCursor, inst: Inst, has_vector_support: bool) { + // Select the instruction result, result type. Replace the instruction + // result and step forward before inserting the canonicalization sequence. + let val = pos.func.dfg.first_result(inst); + let val_type = pos.func.dfg.value_type(val); + let new_res = pos.func.dfg.replace_result(val, val_type); + let _next_inst = pos.next_inst().expect("block missing terminator!"); + + // Insert a comparison instruction, to check if `inst_res` is NaN (comparing + // against NaN is always unordered). Select the canonical NaN value if `val` + // is NaN, assign the result to `inst`. + let comparison = FloatCC::Unordered; + + let vectorized_scalar_select = |pos: &mut FuncCursor, canon_nan: Value, ty: types::Type| { + let canon_nan = pos.ins().scalar_to_vector(ty, canon_nan); + let new_res = pos.ins().scalar_to_vector(ty, new_res); + let is_nan = pos.ins().fcmp(comparison, new_res, new_res); + let is_nan = pos.ins().bitcast(ty, MemFlags::new(), is_nan); + let simd_result = pos.ins().bitselect(is_nan, canon_nan, new_res); + pos.ins().with_result(val).extractlane(simd_result, 0); + }; + let scalar_select = |pos: &mut FuncCursor, canon_nan: Value| { + let is_nan = pos.ins().fcmp(comparison, new_res, new_res); + pos.ins() + .with_result(val) + .select(is_nan, canon_nan, new_res); + }; + + let vector_select = |pos: &mut FuncCursor, canon_nan: Value| { + let is_nan = pos.ins().fcmp(comparison, new_res, new_res); + let is_nan = pos.ins().bitcast(val_type, MemFlags::new(), is_nan); + pos.ins() + .with_result(val) + .bitselect(is_nan, canon_nan, new_res); + }; + + match val_type { + types::F32 => { + let canon_nan = pos.ins().f32const(Ieee32::NAN); + if has_vector_support { + vectorized_scalar_select(pos, canon_nan, types::F32X4); + } else { + scalar_select(pos, canon_nan); + } + } + types::F64 => { + let canon_nan = pos.ins().f64const(Ieee64::NAN); + if has_vector_support { + vectorized_scalar_select(pos, canon_nan, types::F64X2); + } else { + scalar_select(pos, canon_nan); + } + } + types::F32X4 => { + let canon_nan = pos.ins().f32const(Ieee32::NAN); + let canon_nan = pos.ins().splat(types::F32X4, canon_nan); + vector_select(pos, canon_nan); + } + types::F64X2 => { + let canon_nan = pos.ins().f64const(Ieee64::NAN); + let canon_nan = pos.ins().splat(types::F64X2, canon_nan); + vector_select(pos, canon_nan); + } + _ => { + // Panic if the type given was not an IEEE floating point type. + panic!("Could not canonicalize NaN: Unexpected result type found."); + } + } + + pos.prev_inst(); // Step backwards so the pass does not skip instructions. +} diff --git a/deps/crates/vendor/cranelift-codegen/src/opts.rs b/deps/crates/vendor/cranelift-codegen/src/opts.rs new file mode 100644 index 00000000000000..c22a0ab2e0bc1a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts.rs @@ -0,0 +1,301 @@ +//! Optimization driver using ISLE rewrite rules on an egraph. + +use crate::egraph::{NewOrExistingInst, OptimizeCtx}; +pub use crate::ir::condcodes::{FloatCC, IntCC}; +use crate::ir::dfg::ValueDef; +pub use crate::ir::immediates::{Ieee128, Ieee16, Ieee32, Ieee64, Imm64, Offset32, Uimm8, V128Imm}; +use crate::ir::instructions::InstructionFormat; +pub use crate::ir::types::*; +pub use crate::ir::{ + AtomicRmwOp, BlockCall, Constant, DynamicStackSlot, FuncRef, GlobalValue, Immediate, + InstructionData, MemFlags, Opcode, StackSlot, TrapCode, Type, Value, +}; +use crate::isle_common_prelude_methods; +use crate::machinst::isle::*; +use crate::trace; +use cranelift_entity::packed_option::ReservedValue; +use smallvec::{smallvec, SmallVec}; +use std::marker::PhantomData; + +#[allow(dead_code)] +pub type Unit = (); +pub type Range = (usize, usize); +pub type ValueArray2 = [Value; 2]; +pub type ValueArray3 = [Value; 3]; + +const MAX_ISLE_RETURNS: usize = 8; + +pub type ConstructorVec = SmallVec<[T; MAX_ISLE_RETURNS]>; + +type TypeAndInstructionData = (Type, InstructionData); + +impl generated_code::Length for SmallVec { + #[inline] + fn len(&self) -> usize { + SmallVec::len(self) + } +} + +pub(crate) mod generated_code; +use generated_code::{ContextIter, IntoContextIter}; + +pub(crate) struct IsleContext<'a, 'b, 'c> { + pub(crate) ctx: &'a mut OptimizeCtx<'b, 'c>, +} + +pub(crate) struct InstDataEtorIter<'a, 'b, 'c> { + stack: SmallVec<[Value; 8]>, + _phantom1: PhantomData<&'a ()>, + _phantom2: PhantomData<&'b ()>, + _phantom3: PhantomData<&'c ()>, +} + +impl Default for InstDataEtorIter<'_, '_, '_> { + fn default() -> Self { + InstDataEtorIter { + stack: SmallVec::default(), + _phantom1: PhantomData, + _phantom2: PhantomData, + _phantom3: PhantomData, + } + } +} + +impl<'a, 'b, 'c> InstDataEtorIter<'a, 'b, 'c> { + fn new(root: Value) -> Self { + debug_assert_ne!(root, Value::reserved_value()); + Self { + stack: smallvec![root], + _phantom1: PhantomData, + _phantom2: PhantomData, + _phantom3: PhantomData, + } + } +} + +impl<'a, 'b, 'c> ContextIter for InstDataEtorIter<'a, 'b, 'c> +where + 'b: 'a, + 'c: 'b, +{ + type Context = IsleContext<'a, 'b, 'c>; + type Output = (Type, InstructionData); + + fn next(&mut self, ctx: &mut IsleContext<'a, 'b, 'c>) -> Option { + while let Some(value) = self.stack.pop() { + debug_assert!(ctx.ctx.func.dfg.value_is_real(value)); + trace!("iter: value {:?}", value); + match ctx.ctx.func.dfg.value_def(value) { + ValueDef::Union(x, y) => { + debug_assert_ne!(x, Value::reserved_value()); + debug_assert_ne!(y, Value::reserved_value()); + trace!(" -> {}, {}", x, y); + self.stack.push(x); + self.stack.push(y); + continue; + } + ValueDef::Result(inst, _) if ctx.ctx.func.dfg.inst_results(inst).len() == 1 => { + let ty = ctx.ctx.func.dfg.value_type(value); + trace!(" -> value of type {}", ty); + return Some((ty, ctx.ctx.func.dfg.insts[inst])); + } + _ => {} + } + } + None + } +} + +impl<'a, 'b, 'c> IntoContextIter for InstDataEtorIter<'a, 'b, 'c> +where + 'b: 'a, + 'c: 'b, +{ + type Context = IsleContext<'a, 'b, 'c>; + type Output = (Type, InstructionData); + type IntoIter = Self; + + fn into_context_iter(self) -> Self { + self + } +} + +#[derive(Default)] +pub(crate) struct MaybeUnaryEtorIter<'a, 'b, 'c> { + opcode: Option, + inner: InstDataEtorIter<'a, 'b, 'c>, + fallback: Option, +} + +impl MaybeUnaryEtorIter<'_, '_, '_> { + fn new(opcode: Opcode, value: Value) -> Self { + debug_assert_eq!(opcode.format(), InstructionFormat::Unary); + Self { + opcode: Some(opcode), + inner: InstDataEtorIter::new(value), + fallback: Some(value), + } + } +} + +impl<'a, 'b, 'c> ContextIter for MaybeUnaryEtorIter<'a, 'b, 'c> +where + 'b: 'a, + 'c: 'b, +{ + type Context = IsleContext<'a, 'b, 'c>; + type Output = (Type, Value); + + fn next(&mut self, ctx: &mut IsleContext<'a, 'b, 'c>) -> Option { + debug_assert_ne!(self.opcode, None); + while let Some((ty, inst_def)) = self.inner.next(ctx) { + let InstructionData::Unary { opcode, arg } = inst_def else { + continue; + }; + if Some(opcode) == self.opcode { + self.fallback = None; + return Some((ty, arg)); + } + } + + self.fallback.take().map(|value| { + let ty = generated_code::Context::value_type(ctx, value); + (ty, value) + }) + } +} + +impl<'a, 'b, 'c> IntoContextIter for MaybeUnaryEtorIter<'a, 'b, 'c> +where + 'b: 'a, + 'c: 'b, +{ + type Context = IsleContext<'a, 'b, 'c>; + type Output = (Type, Value); + type IntoIter = Self; + + fn into_context_iter(self) -> Self { + self + } +} + +impl<'a, 'b, 'c> generated_code::Context for IsleContext<'a, 'b, 'c> { + isle_common_prelude_methods!(); + + type inst_data_etor_returns = InstDataEtorIter<'a, 'b, 'c>; + + fn inst_data_etor(&mut self, eclass: Value, returns: &mut InstDataEtorIter<'a, 'b, 'c>) { + *returns = InstDataEtorIter::new(eclass); + } + + type inst_data_tupled_etor_returns = InstDataEtorIter<'a, 'b, 'c>; + + fn inst_data_tupled_etor(&mut self, eclass: Value, returns: &mut InstDataEtorIter<'a, 'b, 'c>) { + // Literally identical to `inst_data_etor`, just a different nominal type in ISLE + self.inst_data_etor(eclass, returns); + } + + fn make_inst_ctor(&mut self, ty: Type, op: &InstructionData) -> Value { + let value = self.ctx.insert_pure_enode(NewOrExistingInst::New(*op, ty)); + trace!("make_inst_ctor: {:?} -> {}", op, value); + value + } + + fn value_array_2_ctor(&mut self, arg0: Value, arg1: Value) -> ValueArray2 { + [arg0, arg1] + } + + fn value_array_3_ctor(&mut self, arg0: Value, arg1: Value, arg2: Value) -> ValueArray3 { + [arg0, arg1, arg2] + } + + #[inline] + fn value_type(&mut self, val: Value) -> Type { + self.ctx.func.dfg.value_type(val) + } + + fn iconst_sextend_etor( + &mut self, + (ty, inst_data): (Type, InstructionData), + ) -> Option<(Type, i64)> { + if let InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm, + } = inst_data + { + Some((ty, self.i64_sextend_imm64(ty, imm))) + } else { + None + } + } + + fn remat(&mut self, value: Value) -> Value { + trace!("remat: {}", value); + self.ctx.remat_values.insert(value); + self.ctx.stats.remat += 1; + value + } + + fn subsume(&mut self, value: Value) -> Value { + trace!("subsume: {}", value); + self.ctx.subsume_values.insert(value); + self.ctx.stats.subsume += 1; + value + } + + fn splat64(&mut self, val: u64) -> Constant { + let val = u128::from(val); + let val = val | (val << 64); + let imm = V128Imm(val.to_le_bytes()); + self.ctx.func.dfg.constants.insert(imm.into()) + } + + type sextend_maybe_etor_returns = MaybeUnaryEtorIter<'a, 'b, 'c>; + fn sextend_maybe_etor(&mut self, value: Value, returns: &mut Self::sextend_maybe_etor_returns) { + *returns = MaybeUnaryEtorIter::new(Opcode::Sextend, value); + } + + type uextend_maybe_etor_returns = MaybeUnaryEtorIter<'a, 'b, 'c>; + fn uextend_maybe_etor(&mut self, value: Value, returns: &mut Self::uextend_maybe_etor_returns) { + *returns = MaybeUnaryEtorIter::new(Opcode::Uextend, value); + } + + // NB: Cranelift's defined semantics for `fcvt_from_{s,u}int` match Rust's + // own semantics for converting an integer to a float, so these are all + // implemented with `as` conversions in Rust. + fn f32_from_uint(&mut self, n: u64) -> Ieee32 { + Ieee32::with_float(n as f32) + } + + fn f64_from_uint(&mut self, n: u64) -> Ieee64 { + Ieee64::with_float(n as f64) + } + + fn f32_from_sint(&mut self, n: i64) -> Ieee32 { + Ieee32::with_float(n as f32) + } + + fn f64_from_sint(&mut self, n: i64) -> Ieee64 { + Ieee64::with_float(n as f64) + } + + fn u64_bswap16(&mut self, n: u64) -> u64 { + (n as u16).swap_bytes() as u64 + } + + fn u64_bswap32(&mut self, n: u64) -> u64 { + (n as u32).swap_bytes() as u64 + } + + fn u64_bswap64(&mut self, n: u64) -> u64 { + n.swap_bytes() + } + + fn ieee128_constant_extractor(&mut self, n: Constant) -> Option { + self.ctx.func.dfg.constants.get(n).try_into().ok() + } + + fn ieee128_constant(&mut self, n: Ieee128) -> Constant { + self.ctx.func.dfg.constants.insert(n.into()) + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/README.md b/deps/crates/vendor/cranelift-codegen/src/opts/README.md new file mode 100644 index 00000000000000..4f586a1ad491c5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/README.md @@ -0,0 +1,125 @@ +# Rules for Writing Optimization Rules + +For both correctness and compile speed, we must be careful with our rules. A lot +of it boils down to the fact that, unlike traditional e-graphs, our rules are +*directional*. + +1. Rules should not rewrite to worse code: the right-hand side should be at + least as good as the left-hand side or better. + + For example, the rule + + x => (add x 0) + + is disallowed, but swapping its left- and right-hand sides produces a rule + that is allowed. + + Any kind of canonicalizing rule that intends to help subsequent rules match + and unlock further optimizations (e.g. floating constants to the right side + for our constant-propagation rules to match) must produce canonicalized + output that is no worse than its noncanonical input. + + We assume this invariant as a heuristic to break ties between two + otherwise-equal-cost expressions in various places, making up for some + limitations of our explicit cost function. + +2. Any rule that removes value-uses in its right-hand side that previously + existed in its left-hand side MUST use `subsume`. + + For example, the rule + + (select 1 x y) => x + + MUST use `subsume`. + + This is required for correctness because, once a value-use is removed, some + e-nodes in the e-class are more equal than others. There might be uses of `x` + in a scope where `y` is not available, and so emitting `(select 1 x y)` in + place of `x` in such cases would introduce uses of `y` where it is not + defined. + + An exception to this rule is discarding constants, as they can be + rematerialized anywhere without introducing correctness issues. For example, + the (admittedly silly) rule `(select 1 x (iconst_u _)) => x` would be a good + candidate for not using `subsume`, as it does not discard any non-constant + values introduced in its LHS. + +3. Avoid overly general rewrites like commutativity and associativity. Instead, + prefer targeted instances of the rewrite (for example, canonicalizing adds + where one operand is a constant such that the constant is always the add's + second operand, rather than general commutativity for adds) or even writing + the "same" optimization rule multiple times. + + For example, the commutativity in the first rule in the following snippet is + bad because it will match even when the first operand is not an add: + + ;; Commute to allow `(foo (add ...) x)`, when we see it, to match. + (foo x y) => (foo y x) + + ;; Optimize. + (foo x (add ...)) => (bar x) + + Better is to commute only when we know that canonicalizing in this way will + all definitely allow the subsequent optimization rule to match: + + ;; Canonicalize all adds to `foo`'s second operand. + (foo (add ...) x) => (foo x (add ...)) + + ;; Optimize. + (foo x (add ...)) => (bar x) + + But even better in this case is to write the "same" optimization multiple + times: + + (foo (add ...) x) => (bar x) + (foo x (add ...)) => (bar x) + + The cost of rule-matching is amortized by the ISLE compiler, where as the + intermediate result of each rewrite allocates new e-nodes and requires + storage in the dataflow graph. Therefore, additional rules are cheaper than + additional e-nodes. + + Commutativity and associativity in particular can cause huge amounts of + e-graph bloat. + + One day we intend to extend ISLE with built-in support for commutativity, so + we don't need to author the redundant commutations ourselves: + https://github.com/bytecodealliance/wasmtime/issues/6128 + +4. Be careful with (ideally avoid) multiple matches on the same `Value`, as + they can result in surprising multi-matching behavior. Be skeptical of + helpers that can inadvertently create this behavior. + + In our mid-end ISLE environment, a `Value` corresponds to an eclass, with + multiple possible representations. A rule that matches on a `Value` will + traverse all enodes in the eclass, looking for a match. This is usually + exactly what we want: it is what allows a pattern like `(iadd (iconst k) x)` + to find the `iconst` amongst multiple possibilities for the argument. + + However, this can also result in surprising behavior. If one has a helper + and a simplify rule like + + (decl suitable_for_rewrite (Value) Value) + (rule (suitable_for_rewrite x @ (iadd ...)) x) + (rule (suitable_for_rewrite x @ (isub ...)) x) + + (rule (simplify (ireduce _ x)) + (if-let _ (suitable_for_rewrite x)) + x) + + Then this can result in the extremely surprising behavior that `(ireduce + (other_op ...))` matches, if `(other_op ...)` is in the same eclass as an + `iadd` or `isub`. This happens because the left-hand side binds `x`, which + describes the entire eclass; and `suitable_for_rewrite` matches if *any* + representation of `x` matches. + + This resulted in a real bug in #7999. The best guidance is to keep rules + simple and direct: rather than attempting to abstract out helpers and + perform multiple, separate, matches on a `Value`, write patterns directly. + This has the additional benefit that the rewrites are more clearly visible + to the casual reader. For example: + + (rule (simplify (ireduce _ (iadd ...))) + (iadd ...)) + (rule (simplify (ireduce _ (isub ...))) + (isub ...)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/arithmetic.isle b/deps/crates/vendor/cranelift-codegen/src/opts/arithmetic.isle new file mode 100644 index 00000000000000..a28ad7ef060247 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/arithmetic.isle @@ -0,0 +1,240 @@ +;; rewrites for integer and floating-point arithmetic +;; eg: `iadd`, `isub`, `ineg`, `imul`, `fadd`, `fsub`, `fmul` + +;; For commutative instructions, we depend on cprop.isle pushing immediates to +;; the right, and thus only simplify patterns like `x+0`, not `0+x`. + +;; x+0 == x. +(rule (simplify (iadd ty + x + (iconst_u ty 0))) + (subsume x)) +;; x-0 == x. +(rule (simplify (isub ty + x + (iconst_u ty 0))) + (subsume x)) +;; 0-x == (ineg x). +(rule (simplify (isub ty + (iconst_u ty 0) + x)) + (ineg ty x)) + +;; x + -y == -y + x == -(y - x) == x - y +(rule (simplify (iadd ty x (ineg ty y))) + (isub ty x y)) +(rule (simplify (iadd ty (ineg ty y) x)) + (isub ty x y)) +(rule (simplify (ineg ty (isub ty y x))) + (isub ty x y)) +;; x - -y == x + y +(rule (simplify (isub ty x (ineg ty y))) + (iadd ty x y)) + +;; ineg(ineg(x)) == x. +(rule (simplify (ineg ty (ineg ty x))) (subsume x)) + +;; ineg(x) * ineg(y) == x*y. +(rule (simplify (imul ty (ineg ty x) (ineg ty y))) + (subsume (imul ty x y))) + +;; iabs(ineg(x)) == iabs(x). +(rule (simplify (iabs ty (ineg ty x))) + (iabs ty x)) + +;; iabs(iabs(x)) == iabs(x). +(rule (simplify (iabs ty inner @ (iabs ty x))) + (subsume inner)) + +;; x-x == 0. +(rule (simplify (isub (ty_int ty) x x)) (subsume (iconst_u ty 0))) + +;; x*1 == x. +(rule (simplify (imul ty + x + (iconst_u ty 1))) + (subsume x)) + +;; x*0 == 0. +(rule (simplify (imul ty + _ + zero @ (iconst_u ty 0))) + (subsume zero)) + +;; x*-1 == ineg(x). +(rule (simplify (imul ty x (iconst_s ty -1))) + (ineg ty x)) + +;; (!x) + 1 == ineg(x) +(rule (simplify (iadd ty (bnot ty x) (iconst_u ty 1))) + (ineg ty x)) + +;; !(x - 1) == !(x + (-1)) == ineg(x) +(rule (simplify (bnot ty (isub ty x (iconst_s ty 1)))) + (ineg ty x)) +(rule (simplify (bnot ty (iadd ty x (iconst_s ty -1)))) + (ineg ty x)) + +;; x/1 == x. +(rule (simplify (sdiv ty + x + (iconst_u ty 1))) + (subsume x)) +(rule (simplify (udiv ty + x + (iconst_u ty 1))) + (subsume x)) + +;; TODO: strength reduction: div to shifts +;; TODO: div/rem by constants -> magic multiplications + +;; x*2 == x+x. +(rule (simplify (imul ty x (iconst_u _ 2))) + (iadd ty x x)) + +;; x*c == x< ((a op b) op (c op d)) +;; +;; and +;; +;; (((a op b) op c) op d) ==> ((a op b) op (c op d)) +;; +;; where `op` is an associative operation: `iadd`, `imul`, `band`, or `bxor`. +;; +;; This increases instruction-level parallelism and shrinks live ranges. It also +;; canonicalizes into the shallow-and-wide form for reassociating constants +;; together for cprop. +;; +;; NB: We subsume to avoid exponential e-node blow up due to reassociating very +;; large chains of operations. +;; +;; TODO: We should add `bor` rules for this as well. Unfortunately, they +;; conflict with our `bswap` recognizing rules when we `subsume`. + +(rule (simplify (iadd ty a (iadd ty b (iadd ty c d)))) + (subsume (iadd ty (iadd ty a b) (iadd ty c d)))) +(rule (simplify (iadd ty (iadd ty (iadd ty a b) c) d)) + (subsume (iadd ty (iadd ty a b) (iadd ty c d)))) + +(rule (simplify (imul ty a (imul ty b (imul ty c d)))) + (subsume (imul ty (imul ty a b) (imul ty c d)))) +(rule (simplify (imul ty (imul ty (imul ty a b) c) d)) + (subsume (imul ty (imul ty a b) (imul ty c d)))) + +(rule (simplify (band ty a (band ty b (band ty c d)))) + (subsume (band ty (band ty a b) (band ty c d)))) +(rule (simplify (band ty (band ty (band ty a b) c) d)) + (subsume (band ty (band ty a b) (band ty c d)))) + +(rule (simplify (bxor ty a (bxor ty b (bxor ty c d)))) + (subsume (bxor ty (bxor ty a b) (bxor ty c d)))) +(rule (simplify (bxor ty (bxor ty (bxor ty a b) c) d)) + (subsume (bxor ty (bxor ty a b) (bxor ty c d)))) + + +;; Similar rules but for associating combinations of + and - + +;; a -(b-(c-d)) = (a-b) + (c-d) +(rule (simplify (isub ty a (isub ty b (isub ty c d)))) + (subsume (iadd ty (isub ty a b) (isub ty c d)))) + +;; a -(b-(c+d)) = (a-b) + (c+d) +(rule (simplify (isub ty a (isub ty b (iadd ty c d)))) + (subsume (iadd ty (isub ty a b) (iadd ty c d)))) + +;; a -(b+(c-d)) = (a-b) - (c-d) +(rule (simplify (isub ty a (iadd ty b (isub ty c d)))) + (subsume (isub ty (isub ty a b) (isub ty c d)))) + +;; a -(b+(c+d)) = (a-b) - (c+d) +(rule (simplify (isub ty a (iadd ty b (iadd ty c d)))) + (subsume (isub ty (isub ty a b) (iadd ty c d)))) + +;; a +(b-(c-d)) = (a+b) - (c-d) +(rule (simplify (iadd ty a (isub ty b (isub ty c d)))) + (subsume (isub ty (iadd ty a b) (isub ty c d)))) + +;; a +(b-(c+d)) = (a+b) - (c+d) +(rule (simplify (iadd ty a (isub ty b (iadd ty c d)))) + (subsume (isub ty (iadd ty a b) (iadd ty c d)))) + +;; a +(b+(c-d)) = (a+b) + (c-d) +(rule (simplify (iadd ty a (iadd ty b (isub ty c d)))) + (subsume (iadd ty (iadd ty a b) (isub ty c d)))) + +;; and nested the other way + +;; ((a-b)-c)-d = (a-b) - (c+d) +(rule (simplify (isub ty (isub ty (isub ty a b) c) d)) + (subsume (isub ty (isub ty a b) (iadd ty c d)))) + +;; ((a-b)-c)+d = (a-b) - (c-d) +(rule (simplify (iadd ty (isub ty (isub ty a b) c) d)) + (subsume (isub ty (isub ty a b) (isub ty c d)))) + +;; ((a-b)+c)-d = (a-b) + (c-d) +(rule (simplify (isub ty (iadd ty (isub ty a b) c) d)) + (subsume (iadd ty (isub ty a b) (isub ty c d)))) + +;; ((a-b)+c)+d = (a-b) + (c+d) +(rule (simplify (iadd ty (iadd ty (isub ty a b) c) d)) + (subsume (iadd ty (isub ty a b) (iadd ty c d)))) + +;; ((a+b)-c)-d = (a+b) - (c+d) +(rule (simplify (isub ty (isub ty (iadd ty a b) c) d)) + (subsume (isub ty (iadd ty a b) (iadd ty c d)))) + +;; ((a+b)-c)+d = (a+b) - (c-d) +(rule (simplify (iadd ty (isub ty (iadd ty a b) c) d)) + (subsume (isub ty (iadd ty a b) (isub ty c d)))) + +;; ((a+b)+c)-d = (a+b) + (c-d) +(rule (simplify (isub ty (iadd ty (iadd ty a b) c) d)) + (subsume (iadd ty (iadd ty a b) (isub ty c d)))) + +;; Detect people open-coding `mulhi`: (x as big * y as big) >> bits +;; LLVM doesn't have an intrinsic for it, so you'll see it in code like +;; +(rule (simplify (sshr ty (imul ty (sextend _ x@(value_type half_ty)) + (sextend _ y@(value_type half_ty))) + (iconst_u _ k))) + (if-let true (ty_equal half_ty (ty_half_width ty))) + (if-let true (u64_eq k (ty_bits_u64 half_ty))) + (sextend ty (smulhi half_ty x y))) +(rule (simplify (ushr ty (imul ty (uextend _ x@(value_type half_ty)) + (uextend _ y@(value_type half_ty))) + (iconst_u _ k))) + (if-let true (ty_equal half_ty (ty_half_width ty))) + (if-let true (u64_eq k (ty_bits_u64 half_ty))) + (uextend ty (umulhi half_ty x y))) + +;; Cranelift's `fcvt_from_{u,s}int` instructions are polymorphic over the input +;; type so remove any unnecessary `uextend` or `sextend` to give backends +;; the chance to convert from the smallest integral type to the float. This +;; can help lowerings on x64 for example which has a less efficient u64-to-float +;; conversion than other bit widths. +(rule (simplify (fcvt_from_uint ty (uextend _ val))) + (fcvt_from_uint ty val)) +(rule (simplify (fcvt_from_sint ty (sextend _ val))) + (fcvt_from_sint ty val)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/bitops.isle b/deps/crates/vendor/cranelift-codegen/src/opts/bitops.isle new file mode 100644 index 00000000000000..cf1cd2dd81cda4 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/bitops.isle @@ -0,0 +1,188 @@ +;; Rewrites for `band`, `bnot`, `bor`, `bxor` + +;; x | 0 == x | x == x. +(rule (simplify (bor ty + x + (iconst_u ty 0))) + (subsume x)) +(rule (simplify (bor ty x x)) + (subsume x)) + +;; x ^ 0 == x. +(rule (simplify (bxor ty + x + (iconst_u ty 0))) + (subsume x)) + +;; x ^ x == 0. +(rule (simplify (bxor (ty_int ty) x x)) + (subsume (iconst_u ty 0))) + +;; x ^ not(x) == not(x) ^ x == x | not(x) == not(x) | x == -1. +;; This identity also holds for non-integer types, vectors, and wider types. +(rule (simplify (bxor (ty_int ty) x (bnot ty x))) (subsume (iconst_s ty -1))) +(rule (simplify (bxor (ty_int ty) (bnot ty x) x)) (subsume (iconst_s ty -1))) +(rule (simplify (bor (ty_int ty) x (bnot ty x))) (subsume (iconst_s ty -1))) +(rule (simplify (bor (ty_int ty) (bnot ty x) x)) (subsume (iconst_s ty -1))) + +;; x & x == x & -1 == x. +(rule (simplify (band ty x x)) (subsume x)) +(rule (simplify (band ty x (iconst_s ty -1))) + (subsume x)) + +;; x & 0 == x & not(x) == not(x) & x == 0. +(rule (simplify (band ty _ zero @ (iconst_u ty 0))) (subsume zero)) +(rule (simplify (band (ty_int ty) x (bnot ty x))) (subsume (iconst_u ty 0))) +(rule (simplify (band (ty_int ty) (bnot ty x) x)) (subsume (iconst_u ty 0))) + +;; not(not(x)) == x. +(rule (simplify (bnot ty (bnot ty x))) (subsume x)) + +;; DeMorgan's rule (two versions): +;; bnot(bor(x, y)) == band(bnot(x), bnot(y)) +(rule (simplify (bnot ty (bor ty x y))) + (band ty (bnot ty x) (bnot ty y))) +;; bnot(band(x, y)) == bor(bnot(x), bnot(y)) +(rule (simplify (bnot ty (band t x y))) + (bor ty (bnot ty x) (bnot ty y))) + +;; `or(and(x, y), not(y)) == or(x, not(y))` +(rule (simplify (bor ty + (band ty x y) + z @ (bnot ty y))) + (bor ty x z)) +;; Duplicate the rule but swap the `bor` operands because `bor` is +;; commutative. We could, of course, add a `simplify` rule to do the commutative +;; swap for all `bor`s but this will bloat the e-graph with many e-nodes. It is +;; cheaper to have additional rules, rather than additional e-nodes, because we +;; amortize their cost via ISLE's smart codegen. +(rule (simplify (bor ty + z @ (bnot ty y) + (band ty x y))) + (bor ty x z)) + +;; `or(and(x, y), not(y)) == or(x, not(y))` specialized for constants, since +;; otherwise we may not know that `z == not(y)` since we don't generally expand +;; constants in the e-graph. +;; +;; (No need to duplicate for commutative `bor` for this constant version because +;; we move constants to the right.) +(rule (simplify (bor ty + (band ty x (iconst_u ty y)) + z @ (iconst_u ty zk))) + (if-let true (u64_eq (u64_and (ty_mask ty) zk) + (u64_and (ty_mask ty) (u64_not y)))) + (bor ty x z)) + +;; (x ^ -1) can be replaced with the `bnot` instruction +(rule (simplify (bxor ty x (iconst_s ty -1))) + (bnot ty x)) + +;; sshr((x | -x), N) == bmask(x) where N = ty_bits(ty) - 1. +;; +;; (x | -x) sets the sign bit to 1 if x is nonzero, and 0 if x is zero. sshr propagates +;; the sign bit to the rest of the value. +(rule (simplify (sshr ty (bor ty x (ineg ty x)) (iconst_u ty shift_amt))) + (if-let true (u64_eq shift_amt (ty_shift_mask ty))) + (bmask ty x)) + +(rule (simplify (sshr ty (bor ty (ineg ty x) x) (iconst_u ty shift_amt))) + (if-let true (u64_eq shift_amt (ty_shift_mask ty))) + (bmask ty x)) + +;; Since icmp is always 0 or 1, bmask is just a negation. +;; TODO: Explore whether this makes sense for things needing extension too. +(rule (simplify (bmask $I8 cmp@(icmp $I8 _ _ _))) + (ineg $I8 cmp)) + +;; Matches any expressions that preserve "truthiness". +;; i.e. If the input is zero it remains zero, and if it is nonzero it can have +;; a different value as long as it is still nonzero. +(decl pure multi truthy (Value) Value) +(rule (truthy (sextend _ x)) x) +(rule (truthy (uextend _ x)) x) +(rule (truthy (bmask _ x)) x) +(rule (truthy (ineg _ x)) x) +(rule (truthy (bswap _ x)) x) +(rule (truthy (bitrev _ x)) x) +(rule (truthy (popcnt _ x)) x) +(rule (truthy (rotl _ x _)) x) +(rule (truthy (rotr _ x _)) x) +(rule (truthy (select _ x (iconst_u _ (u64_nonzero _)) (iconst_u _ 0))) x) +;; (ne ty (iconst 0) v) is also canonicalized into this form via another rule +(rule (truthy (ne _ x (iconst_u _ 0))) x) + +;; All of these expressions don't care about their input as long as it is truthy. +;; so we can remove expressions that preserve that property from the input. +(rule (simplify (bmask ty v)) (if-let x (truthy v)) (bmask ty x)) +(rule (simplify (select ty v t f)) (if-let c (truthy v)) (select ty c t f)) +;; (ne ty (iconst 0) v) is also canonicalized into this form via another rule +(rule (simplify (ne cty v (iconst_u _ 0))) + (if-let c (truthy v)) + (if-let (value_type (ty_int_ref_scalar_64 ty)) c) + (ne cty c (iconst_u ty 0))) + + + +;; (sextend (bmask x)) can be replaced with (bmask x) since bmask +;; supports any size of output type, regardless of input. +;; Same with `ireduce` +(rule (simplify (sextend ty (bmask _ x))) (bmask ty x)) +(rule (simplify (ireduce ty (bmask _ x))) (bmask ty x)) + +;; (bswap (bswap x)) == x +(rule (simplify (bswap ty (bswap ty x))) (subsume x)) + +;; (bitrev (bitrev x)) == x +(rule (simplify (bitrev ty (bitrev ty x))) (subsume x)) + +;; WebAssembly doesn't have a native byte-swapping instruction at this time so +;; languages which have a byte-swapping operation will compile it down to bit +;; shifting and twiddling. This attempts to pattern match what LLVM currently +;; generates today for the Rust code `a.swap_bytes()`. This might be a bit +;; brittle over time and/or with other possible LLVM backend optimizations, but +;; it's at least one way to generate a byte swap. +;; +;; Technically this could be permuted quite a few ways and currently there's no +;; easy way to match all of them, so only one is matched here. +(rule (simplify (bor ty @ $I32 + (bor ty + (ishl ty x (iconst_u ty 24)) + (ishl ty + (band ty x (iconst_u ty 0xff00)) + (iconst_u ty 8))) + (bor ty + (band ty + (ushr ty x (iconst_u ty 8)) + (iconst_u ty 0xff00)) + (ushr ty x (iconst_u ty 24))))) + (bswap ty x)) + +(rule (simplify (bor ty @ $I64 + (bor ty + (bor ty + (ishl ty x (iconst_u ty 56)) + (ishl ty + (band ty x (iconst_u ty 0xff00)) + (iconst_u ty 40))) + (bor ty + (ishl ty + (band ty x (iconst_u ty 0xff_0000)) + (iconst_u ty 24)) + (ishl ty + (band ty x (iconst_u ty 0xff00_0000)) + (iconst_u ty 8)))) + (bor ty + (bor ty + (band ty + (ushr ty x (iconst_u ty 8)) + (iconst_u ty 0xff00_0000)) + (band ty + (ushr ty x (iconst_u ty 24)) + (iconst_u ty 0xff_0000))) + (bor ty + (band ty + (ushr ty x (iconst_u ty 40)) + (iconst_u ty 0xff00)) + (ushr ty x (iconst_u ty 56)))))) + (bswap ty x)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/cprop.isle b/deps/crates/vendor/cranelift-codegen/src/opts/cprop.isle new file mode 100644 index 00000000000000..cde054d9d1e081 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/cprop.isle @@ -0,0 +1,408 @@ +;; Constant propagation. + +(rule (simplify + (iadd (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_add k1 k2))))) + +(rule (simplify + (isub (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_sub k1 k2))))) + +(rule (simplify + (imul (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_mul k1 k2))))) + +(rule (simplify + (sdiv (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (if-let d (u64_sdiv k1 k2)) + (subsume (iconst ty (imm64_masked ty d)))) + +(rule (simplify + (udiv (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (if-let d (u64_udiv k1 k2)) + (subsume (iconst ty (imm64_masked ty d)))) + +(rule (simplify + (bor (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_or k1 k2))))) + +(rule (simplify + (band (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_and k1 k2))))) + +(rule (simplify + (bxor (fits_in_64 ty) + (iconst ty (u64_from_imm64 k1)) + (iconst ty (u64_from_imm64 k2)))) + (subsume (iconst ty (imm64_masked ty (u64_xor k1 k2))))) + +(rule (simplify + (bnot (fits_in_64 ty) + (iconst ty (u64_from_imm64 k)))) + (subsume (iconst ty (imm64_masked ty (u64_not k))))) + +(rule (simplify (ishl (fits_in_64 ty) + (iconst ty k1) + (iconst _ k2))) + (subsume (iconst ty (imm64_shl ty k1 k2)))) + +(rule (simplify (ushr (fits_in_64 ty) + (iconst ty k1) + (iconst _ k2))) + (subsume (iconst ty (imm64_ushr ty k1 k2)))) + +(rule (simplify (sshr (fits_in_64 ty) + (iconst ty k1) + (iconst _ k2))) + (subsume (iconst ty (imm64_sshr ty k1 k2)))) + +(rule (simplify (ireduce narrow (iconst (fits_in_64 _) (u64_from_imm64 imm)))) + (subsume (iconst narrow (imm64_masked narrow imm)))) + +;; iconst_[su] support $I128, but do so by extending, so restricting to +;; 64-bit or smaller keeps it from just remaking essentially the same thing. +(rule (simplify (uextend (fits_in_64 wide) (iconst_u narrow k))) + (subsume (iconst_u wide k))) +(rule (simplify (sextend (fits_in_64 wide) (iconst_s narrow k))) + (subsume (iconst_s wide k))) + +(rule (simplify + (icmp result_ty + cc + (iconst ty k1) + (iconst ty k2))) + (subsume (iconst result_ty (imm64_icmp ty cc k1 k2)))) + + +;; Canonicalize via commutativity: push immediates to the right. +;; +;; (op k x) --> (op x k) + +(rule (simplify + (iadd ty k @ (iconst ty _) x)) + (iadd ty x k)) +;; sub is not commutative, but we can flip the args and negate the +;; whole thing. +(rule (simplify + (isub ty k @ (iconst ty _) x)) + (ineg ty (isub ty x k))) +(rule (simplify + (imul ty k @ (iconst ty _) x)) + (imul ty x k)) + +(rule (simplify + (bor ty k @ (iconst ty _) x)) + (bor ty x k)) +(rule (simplify + (band ty k @ (iconst ty _) x)) + (band ty x k)) +(rule (simplify + (bxor ty k @ (iconst ty _) x)) + (bxor ty x k)) + +(rule (simplify + (icmp ty cc k @ (iconst _ _) x)) + (icmp ty (intcc_swap_args cc) x k)) + +;; Canonicalize via associativity: reassociate to a right-heavy tree +;; for constants. +;; +;; (op (op x k) k) --> (op x (op k k)) + +(rule (simplify + (iadd ty (iadd ty x k1 @ (iconst ty _)) k2 @ (iconst ty _))) + (iadd ty x (iadd ty k1 k2))) +;; sub is not directly associative, but we can flip a sub to an add to +;; make it work: +;; - (sub (sub x k1) k2) -> (sub x (add k1 k2)) +;; - (sub (sub k1 x) k2) -> (sub (sub k1 k2) x) +;; - (sub (add x k1) k2) -> (sub x (sub k2 k1)) +;; - (add (sub x k1) k2) -> (add x (sub k2 k1)) +;; - (add (sub k1 x) k2) -> (sub (add k1 k2) x) +(rule (simplify (isub ty + (isub ty x (iconst ty (u64_from_imm64 k1))) + (iconst ty (u64_from_imm64 k2)))) + (isub ty x (iconst ty (imm64_masked ty (u64_add k1 k2))))) +(rule (simplify (isub ty + (isub ty (iconst ty (u64_from_imm64 k1)) x) + (iconst ty (u64_from_imm64 k2)))) + (isub ty (iconst ty (imm64_masked ty (u64_sub k1 k2))) x)) +(rule (simplify (isub ty + (iadd ty x (iconst ty (u64_from_imm64 k1))) + (iconst ty (u64_from_imm64 k2)))) + (isub ty x (iconst ty (imm64_masked ty (u64_sub k2 k1))))) +(rule (simplify (iadd ty + (isub ty x (iconst ty (u64_from_imm64 k1))) + (iconst ty (u64_from_imm64 k2)))) + (iadd ty x (iconst ty (imm64_masked ty (u64_sub k2 k1))))) +(rule (simplify (iadd ty + (isub ty (iconst ty (u64_from_imm64 k1)) x) + (iconst ty (u64_from_imm64 k2)))) + (isub ty (iconst ty (imm64_masked ty (u64_add k1 k2))) x)) + +(rule (simplify + (imul ty (imul ty x k1 @ (iconst ty _)) k2 @ (iconst ty _))) + (imul ty x (imul ty k1 k2))) +(rule (simplify + (bor ty (bor ty x k1 @ (iconst ty _)) k2 @ (iconst ty _))) + (bor ty x (bor ty k1 k2))) +(rule (simplify + (band ty (band ty x k1 @ (iconst ty _)) k2 @ (iconst ty _))) + (band ty x (band ty k1 k2))) +(rule (simplify + (bxor ty (bxor ty x k1 @ (iconst ty _)) k2 @ (iconst ty _))) + (bxor ty x (bxor ty k1 k2))) + +(rule (simplify (select ty (iconst_u _ (u64_nonzero _)) x _)) + (subsume x)) +(rule (simplify (select ty (iconst_u _ 0) _ y)) + (subsume y)) + +;; Replace subtraction by a "negative" constant with addition. +;; Notably, this gives `x - (-1) == x + 1`, so other patterns don't have to +;; match the subtract-negative-one version too. +;; TODO: it would be nice to do this for `x + (-1) == x - 1` as well, but +;; that needs work in lowering first to avoid regressing addressing modes. + +(rule (simplify (isub ty x (iconst_s ty k))) + (if-let true (u64_lt (i64_as_u64 (i64_neg k)) (i64_as_u64 k))) + (iadd ty x (iconst ty (imm64_masked ty (i64_as_u64 (i64_neg k)))))) + +;; A splat of a constant can become a direct `vconst` with the appropriate bit +;; pattern. +(rule (simplify (splat dst (iconst $I8 n))) + (vconst dst (splat8 (u64_uextend_imm64 $I8 n)))) +(rule (simplify (splat dst (iconst $I16 n))) + (vconst dst (splat16 (u64_uextend_imm64 $I16 n)))) +(rule (simplify (splat dst (iconst $I32 n))) + (vconst dst (splat32 (u64_uextend_imm64 $I32 n)))) +(rule (simplify (splat dst (iconst $I64 n))) + (vconst dst (splat64 (u64_uextend_imm64 $I64 n)))) +(rule (simplify (splat dst (f32const _ (u32_from_ieee32 n)))) + (vconst dst (splat32 n))) +(rule (simplify (splat dst (f64const _ (u64_from_ieee64 n)))) + (vconst dst (splat64 n))) + +(decl splat8 (u64) Constant) +(rule (splat8 n) (splat16 (u64_or n (u64_shl n 8)))) +(decl splat16 (u64) Constant) +(rule (splat16 n) (splat32 (u64_or n (u64_shl n 16)))) +(decl splat32 (u64) Constant) +(rule (splat32 n) (splat64 (u64_or n (u64_shl n 32)))) +(decl splat64 (u64) Constant) +(extern constructor splat64 splat64) + +;; Reassociate nested shifts of constants to put constants together for cprop. +;; +;; ((A shift b) shift C) ==> ((A shift C) shift b) +(rule (simplify (ishl ty (ishl ty a@(iconst _ _) b) c@(iconst _ _))) + (ishl ty (ishl ty a c) b)) +(rule (simplify (ushr ty (ushr ty a@(iconst _ _) b) c@(iconst _ _))) + (ushr ty (ushr ty a c) b)) +(rule (simplify (sshr ty (sshr ty a@(iconst _ _) b) c@(iconst _ _))) + (sshr ty (sshr ty a c) b)) + +;; When we operations that are both commutative and associative, reassociate +;; constants together for cprop: +;; +;; ((a op B) op (c op D)) ==> ((a op c) op (B op D)) +;; +;; Where `op` is one of: `iadd`, `imul`, `band`, `bor`, or `bxor`. +(rule (simplify (iadd ty + (iadd ty a b@(iconst _ _)) + (iadd ty c d@(iconst _ _)))) + (iadd ty (iadd ty a c) (iadd ty b d))) +(rule (simplify (imul ty + (imul ty a b@(iconst _ _)) + (imul ty c d@(iconst _ _)))) + (imul ty (imul ty a c) (imul ty b d))) +(rule (simplify (band ty + (band ty a b@(iconst _ _)) + (band ty c d@(iconst _ _)))) + (band ty (band ty a c) (band ty b d))) +(rule (simplify (bor ty + (bor ty a b@(iconst _ _)) + (bor ty c d@(iconst _ _)))) + (bor ty (bor ty a c) (bor ty b d))) +(rule (simplify (bxor ty + (bxor ty a b@(iconst _ _)) + (bxor ty c d@(iconst _ _)))) + (bxor ty (bxor ty a c) (bxor ty b d))) + + +;; Constant fold int-to-float conversions. +(rule (simplify (fcvt_from_uint $F32 (iconst_u _ n))) + (f32const $F32 (f32_from_uint n))) +(rule (simplify (fcvt_from_uint $F64 (iconst_u _ n))) + (f64const $F64 (f64_from_uint n))) +(rule (simplify (fcvt_from_sint $F32 (iconst_s _ n))) + (f32const $F32 (f32_from_sint n))) +(rule (simplify (fcvt_from_sint $F64 (iconst_s _ n))) + (f64const $F64 (f64_from_sint n))) + +(decl f32_from_uint (u64) Ieee32) +(extern constructor f32_from_uint f32_from_uint) +(decl f64_from_uint (u64) Ieee64) +(extern constructor f64_from_uint f64_from_uint) +(decl f32_from_sint (i64) Ieee32) +(extern constructor f32_from_sint f32_from_sint) +(decl f64_from_sint (i64) Ieee64) +(extern constructor f64_from_sint f64_from_sint) + +;; Constant fold bswap of a constant. +(rule (simplify (bswap $I16 (iconst ty (u64_from_imm64 n)))) + (subsume (iconst $I16 (imm64 (u64_bswap16 n))))) +(rule (simplify (bswap $I32 (iconst ty (u64_from_imm64 n)))) + (subsume (iconst $I32 (imm64 (u64_bswap32 n))))) +(rule (simplify (bswap $I64 (iconst ty (u64_from_imm64 n)))) + (subsume (iconst $I64 (imm64 (u64_bswap64 n))))) + +(decl pure u64_bswap16 (u64) u64) +(extern constructor u64_bswap16 u64_bswap16) +(decl pure u64_bswap32 (u64) u64) +(extern constructor u64_bswap32 u64_bswap32) +(decl pure u64_bswap64 (u64) u64) +(extern constructor u64_bswap64 u64_bswap64) + +;; Constant fold float operations +;; Note: With the exception of fabs, fneg and copysign, +;; constant folding is only performed when the result of +;; an instruction isn't NaN. We want the NaN bit patterns +;; produced by an instruction to be consistent, and +;; compile-time evaluation in a cross-compilation scenario +;; risks producing different NaN bit patterns than the target +;; would have at run-time. +;; TODO: fcmp, fma, demote, promote, to-int ops +(rule (simplify (fadd $F32 (f32const $F32 lhs) (f32const $F32 rhs))) + (if-let r (f32_add lhs rhs)) + (subsume (f32const $F32 r))) +(rule (simplify (fadd $F64 (f64const $F64 lhs) (f64const $F64 rhs))) + (if-let r (f64_add lhs rhs)) + (subsume (f64const $F64 r))) + +(rule (simplify (fsub $F32 (f32const $F32 lhs) (f32const $F32 rhs))) + (if-let r (f32_sub lhs rhs)) + (subsume (f32const $F32 r))) +(rule (simplify (fsub $F64 (f64const $F64 lhs) (f64const $F64 rhs))) + (if-let r (f64_sub lhs rhs)) + (subsume (f64const $F64 r))) + +(rule (simplify (fmul $F32 (f32const $F32 lhs) (f32const $F32 rhs))) + (if-let r (f32_mul lhs rhs)) + (subsume (f32const $F32 r))) +(rule (simplify (fmul $F64 (f64const $F64 lhs) (f64const $F64 rhs))) + (if-let r (f64_mul lhs rhs)) + (subsume (f64const $F64 r))) + +(rule (simplify (fdiv $F32 (f32const $F32 lhs) (f32const $F32 rhs))) + (if-let r (f32_div lhs rhs)) + (subsume (f32const $F32 r))) +(rule (simplify (fdiv $F64 (f64const $F64 lhs) (f64const $F64 rhs))) + (if-let r (f64_div lhs rhs)) + (subsume (f64const $F64 r))) + +(rule (simplify (sqrt $F32 (f32const $F32 n))) + (if-let r (f32_sqrt n)) + (subsume (f32const $F32 r))) +(rule (simplify (sqrt $F64 (f64const $F64 n))) + (if-let r (f64_sqrt n)) + (subsume (f64const $F64 r))) + +(rule (simplify (ceil $F32 (f32const $F32 n))) + (if-let r (f32_ceil n)) + (subsume (f32const $F32 r))) +(rule (simplify (ceil $F64 (f64const $F64 n))) + (if-let r (f64_ceil n)) + (subsume (f64const $F64 r))) + +(rule (simplify (floor $F32 (f32const $F32 n))) + (if-let r (f32_floor n)) + (subsume (f32const $F32 r))) +(rule (simplify (floor $F64 (f64const $F64 n))) + (if-let r (f64_floor n)) + (subsume (f64const $F64 r))) + +(rule (simplify (trunc $F32 (f32const $F32 n))) + (if-let r (f32_trunc n)) + (subsume (f32const $F32 r))) +(rule (simplify (trunc $F64 (f64const $F64 n))) + (if-let r (f64_trunc n)) + (subsume (f64const $F64 r))) + +(rule (simplify (nearest $F32 (f32const $F32 n))) + (if-let r (f32_nearest n)) + (subsume (f32const $F32 r))) +(rule (simplify (nearest $F64 (f64const $F64 n))) + (if-let r (f64_nearest n)) + (subsume (f64const $F64 r))) + +(rule (simplify (fmin $F16 (f16const $F16 n) (f16const $F16 m))) + (if-let r (f16_min n m)) + (subsume (f16const $F32 r))) +(rule (simplify (fmin $F32 (f32const $F32 n) (f32const $F32 m))) + (if-let r (f32_min n m)) + (subsume (f32const $F32 r))) +(rule (simplify (fmin $F64 (f64const $F64 n) (f64const $F64 m))) + (if-let r (f64_min n m)) + (subsume (f64const $F64 r))) +(rule (simplify (fmin $F128 (f128const $F128 (ieee128_constant n)) (f128const $F128 (ieee128_constant m)))) + (if-let r (f128_min n m)) + (subsume (f128const $F128 (ieee128_constant r)))) + +(rule (simplify (fmax $F16 (f16const $F16 n) (f16const $F16 m))) + (if-let r (f16_max n m)) + (subsume (f16const $F16 r))) +(rule (simplify (fmax $F32 (f32const $F32 n) (f32const $F32 m))) + (if-let r (f32_max n m)) + (subsume (f32const $F32 r))) +(rule (simplify (fmax $F64 (f64const $F64 n) (f64const $F64 m))) + (if-let r (f64_max n m)) + (subsume (f64const $F64 r))) +(rule (simplify (fmax $F128 (f128const $F128 (ieee128_constant n)) (f128const $F128 (ieee128_constant m)))) + (if-let r (f128_max n m)) + (subsume (f128const $F128 (ieee128_constant r)))) + +(rule (simplify (fneg $F16 (f16const $F16 n))) + (subsume (f16const $F16 (f16_neg n)))) +(rule (simplify (fneg $F32 (f32const $F32 n))) + (subsume (f32const $F32 (f32_neg n)))) +(rule (simplify (fneg $F64 (f64const $F64 n))) + (subsume (f64const $F64 (f64_neg n)))) +(rule (simplify (fneg $F128 (f128const $F128 (ieee128_constant n)))) + (subsume (f128const $F128 (ieee128_constant (f128_neg n))))) + +(rule (simplify (fabs $F16 (f16const $F16 n))) + (subsume (f16const $F16 (f16_abs n)))) +(rule (simplify (fabs $F32 (f32const $F32 n))) + (subsume (f32const $F32 (f32_abs n)))) +(rule (simplify (fabs $F64 (f64const $F64 n))) + (subsume (f64const $F64 (f64_abs n)))) +(rule (simplify (fabs $F128 (f128const $F128 (ieee128_constant n)))) + (subsume (f128const $F128 (ieee128_constant (f128_abs n))))) + +(rule (simplify (fcopysign $F16 (f16const $F16 n) (f16const $F16 m))) + (subsume (f16const $F16 (f16_copysign n m)))) +(rule (simplify (fcopysign $F32 (f32const $F32 n) (f32const $F32 m))) + (subsume (f32const $F32 (f32_copysign n m)))) +(rule (simplify (fcopysign $F64 (f64const $F64 n) (f64const $F64 m))) + (subsume (f64const $F64 (f64_copysign n m)))) +(rule (simplify (fcopysign $F128 (f128const $F128 (ieee128_constant n)) (f128const $F128 (ieee128_constant m)))) + (subsume (f128const $F128 (ieee128_constant (f128_copysign n m))))) + +(decl ieee128_constant (Ieee128) Constant) +(extern constructor ieee128_constant ieee128_constant) +(extern extractor ieee128_constant ieee128_constant_extractor) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/extends.isle b/deps/crates/vendor/cranelift-codegen/src/opts/extends.isle new file mode 100644 index 00000000000000..0cc3c48e7f5530 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/extends.isle @@ -0,0 +1,95 @@ +;; Chained `uextend` and `sextend`. +(rule (simplify (uextend ty (uextend _intermediate_ty x))) + (uextend ty x)) +(rule (simplify (sextend ty (sextend _intermediate_ty x))) + (sextend ty x)) + +;; Once something has be `uextend`ed, further `sextend`ing is the same as `uextend` +(rule (simplify (sextend ty (uextend _intermediate_ty x))) + (uextend ty x)) + +;; `icmp` is zero or one, so sign-extending is the same as zero-extending +(rule (simplify (sextend ty x@(icmp _ _ _ _))) + (uextend ty x)) + +;; Masking out any of the top bits of the result of `uextend` is a no-op. (This +;; is like a cheap version of known-bits analysis.) +(rule (simplify (band wide x @ (uextend _ (value_type narrow)) (iconst_u _ mask))) + ; Check that `narrow_mask` has a subset of the bits that `mask` does. + (if-let true (let ((narrow_mask u64 (ty_mask narrow))) (u64_eq narrow_mask (u64_and mask narrow_mask)))) + x) + +;; Masking out the sign-extended bits of an `sextend` turns it into a `uextend`. +(rule (simplify (band wide (sextend _ x @ (value_type narrow)) (iconst_u _ mask))) + (if-let true (u64_eq mask (ty_mask narrow))) + (uextend wide x)) + +;; 32-bit integers zero-extended to 64-bit integers are never negative +(rule (simplify + (slt ty + (uextend $I64 x @ (value_type $I32)) + (iconst_u _ 0))) + (subsume (iconst_u ty 0))) +(rule (simplify + (sge ty + (uextend $I64 x @ (value_type $I32)) + (iconst_u _ 0))) + (subsume (iconst_u ty 1))) + +;; Sign-extending can't change whether a number is zero nor how it signed-compares to zero +(rule (simplify (eq _ (sextend _ x@(value_type ty)) (iconst_s _ 0))) + (eq ty x (iconst_s ty 0))) +(rule (simplify (ne _ (sextend _ x@(value_type ty)) (iconst_s _ 0))) + (ne ty x (iconst_s ty 0))) +(rule (simplify (icmp _ cc (sextend _ x@(value_type ty)) (iconst_s _ 0))) + (if (signed_cond_code cc)) + (icmp ty cc x (iconst_s ty 0))) + +;; A reduction-of-an-extend back to the same original type is the same as not +;; actually doing the extend in the first place. +(rule (simplify (ireduce ty (sextend _ x @ (value_type ty)))) (subsume x)) +(rule (simplify (ireduce ty (uextend _ x @ (value_type ty)))) (subsume x)) + +;; A reduction-of-an-extend that's not just to the original type is either: +;; a reduction of the original if the final type is smaller, or +(rule (simplify (ireduce (ty_int ty_final) (sextend _ inner@(value_type ty_initial)))) + (if-let true (u64_lt (ty_bits_u64 ty_final) (ty_bits_u64 ty_initial))) + (ireduce ty_final inner)) +(rule (simplify (ireduce (ty_int ty_final) (uextend _ inner@(value_type ty_initial)))) + (if-let true (u64_lt (ty_bits_u64 ty_final) (ty_bits_u64 ty_initial))) + (ireduce ty_final inner)) +;; an extension of the original if the final type is larger. +(rule (simplify (ireduce (ty_int ty_final) (sextend _ inner@(value_type ty_initial)))) + (if-let true (u64_lt (ty_bits_u64 ty_initial) (ty_bits_u64 ty_final))) + (sextend ty_final inner)) +(rule (simplify (ireduce (ty_int ty_final) (uextend _ inner@(value_type ty_initial)))) + (if-let true (u64_lt (ty_bits_u64 ty_initial) (ty_bits_u64 ty_final))) + (uextend ty_final inner)) + +;; `band`, `bor`, and `bxor` can't affect any bits that aren't set in the one of +;; the inputs, so they can be pushed down inside `uextend`s +(rule (simplify (band bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) + (uextend bigty (band smallty x y))) +(rule (simplify (bor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) + (uextend bigty (bor smallty x y))) +(rule (simplify (bxor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) + (uextend bigty (bxor smallty x y))) + +;; Replace `(small)(x OP y)` with `(small)x OP (small)y` in cases where that's +;; legal. +;; Matches values where the high bits of the input don't affect lower bits of +;; the output, and thus the inputs can be reduced before the operation rather +;; than doing the wide operation then reducing afterwards. +(rule (simplify (ireduce ty (ineg _ x))) (ineg ty (ireduce ty x))) +(rule (simplify (ireduce ty (bnot _ x))) (bnot ty (ireduce ty x))) + +(rule (simplify (ireduce ty (iadd _ x y))) (iadd ty (ireduce ty x) (ireduce ty y))) +(rule (simplify (ireduce ty (isub _ x y))) (isub ty (ireduce ty x) (ireduce ty y))) +(rule (simplify (ireduce ty (imul _ x y))) (imul ty (ireduce ty x) (ireduce ty y))) +(rule (simplify (ireduce ty (bor _ x y))) (bor ty (ireduce ty x) (ireduce ty y))) +(rule (simplify (ireduce ty (bxor _ x y))) (bxor ty (ireduce ty x) (ireduce ty y))) +(rule (simplify (ireduce ty (band _ x y))) (band ty (ireduce ty x) (ireduce ty y))) + +;; Try to transform an `iconcat` into an i128 into either an sextend or uextend +(rule (simplify (iconcat $I128 x (iconst_u _ 0))) (uextend $I128 x)) +(rule (simplify (iconcat $I128 x (sshr _ x (iconst_u _ 63)))) (sextend $I128 x)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/generated_code.rs b/deps/crates/vendor/cranelift-codegen/src/opts/generated_code.rs new file mode 100644 index 00000000000000..cd2362988d1922 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/generated_code.rs @@ -0,0 +1,11 @@ +//! Wrapper environment for generated code from optimization rules in ISLE. + +// See https://github.com/rust-lang/rust/issues/47995: we cannot use `#![...]` attributes inside of +// the generated ISLE source below because we include!() it. We must include!() it because its path +// depends on an environment variable; and also because of this, we can't do the `#[path = "..."] +// mod generated_code;` trick either. +#![allow(dead_code, unreachable_code, unreachable_patterns)] +#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)] +#![allow(irrefutable_let_patterns, non_camel_case_types, clippy::clone_on_copy)] + +include!(concat!(env!("ISLE_DIR"), "/isle_opt.rs")); diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/icmp.isle b/deps/crates/vendor/cranelift-codegen/src/opts/icmp.isle new file mode 100644 index 00000000000000..c919525ccdec02 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/icmp.isle @@ -0,0 +1,258 @@ +;; `icmp`-related rewrites + +;; `x == x` is always true for integers; `x != x` is false. Strict +;; inequalities are false, and loose inequalities are true. +(rule (simplify (eq (ty_int ty) x x)) (subsume (iconst_u ty 1))) +(rule (simplify (ne (ty_int ty) x x)) (subsume (iconst_u ty 0))) +(rule (simplify (ugt (ty_int ty) x x)) (subsume (iconst_u ty 0))) +(rule (simplify (uge (ty_int ty) x x)) (subsume (iconst_u ty 1))) +(rule (simplify (sgt (ty_int ty) x x)) (subsume (iconst_u ty 0))) +(rule (simplify (sge (ty_int ty) x x)) (subsume (iconst_u ty 1))) +(rule (simplify (ult (ty_int ty) x x)) (subsume (iconst_u ty 0))) +(rule (simplify (ule (ty_int ty) x x)) (subsume (iconst_u ty 1))) +(rule (simplify (slt (ty_int ty) x x)) (subsume (iconst_u ty 0))) +(rule (simplify (sle (ty_int ty) x x)) (subsume (iconst_u ty 1))) + +;; Optimize icmp-of-icmp. +;; ne(icmp(ty, cc, x, y), 0) == icmp(ty, cc, x, y) +;; e.g. neq(ugt(x, y), 0) == ugt(x, y) +(rule (simplify (ne ty + (uextend_maybe _ inner @ (icmp ty _ _ _)) + (iconst_u _ 0))) + (subsume inner)) + +;; eq(icmp(ty, cc, x, y), 0) == icmp(ty, cc_complement, x, y) +;; e.g. eq(ugt(x, y), 0) == ule(x, y) +(rule (simplify (eq ty + (uextend_maybe _ (icmp ty cc x y)) + (iconst_u _ 0))) + (subsume (icmp ty (intcc_complement cc) x y))) + +;; ne(icmp(ty, cc, x, y), 1) == icmp(ty, cc_complement, x, y) +;; e.g. ne(ugt(x, y), 1) == ule(x, y) +(rule (simplify (ne ty + (uextend_maybe _ (icmp ty cc x y)) + (iconst_u _ 1))) + (subsume (icmp ty (intcc_complement cc) x y))) + +;; eq(icmp(ty, cc, x, y), 1) == icmp(ty, cc, x, y) +;; e.g. eq(ugt(x, y), 1) == ugt(x, y) +(rule (simplify (eq ty + (uextend_maybe _ inner @ (icmp _ _ _ _)) + (iconst_u _ 1))) + (subsume inner)) + +;; Optimize select-of-uextend-of-icmp to select-of-icmp, because +;; select can take an I8 condition too. +(rule (simplify + (select ty (uextend _ c @ (icmp _ _ _ _)) x y)) + (select ty c x y)) +(rule (simplify + (select ty (uextend _ c @ (icmp _ _ _ _)) x y)) + (select ty c x y)) + +;; Masking the result of a comparison with 1 always results in the comparison +;; itself. Note that comparisons in wasm may sometimes be hidden behind +;; extensions. +(rule (simplify + (band (ty_int _) + cmp @ (icmp _ _ _ _) + (iconst_u _ 1))) + cmp) +(rule (simplify + (band (ty_int _) + extend @ (uextend _ (icmp _ _ _ _)) + (iconst_u _ 1))) + extend) + +;; Comparisons against largest/smallest signed/unsigned values: +;; ult(x, 0) == false. +(rule (simplify (ult (fits_in_64 (ty_int bty)) x zero @ (iconst_u _ 0))) + (subsume (iconst_u bty 0))) + +;; ule(x, 0) == eq(x, 0) +(rule (simplify (ule (fits_in_64 (ty_int bty)) x zero @ (iconst_u _ 0))) + (eq bty x zero)) + +;; ugt(x, 0) == ne(x, 0). +(rule (simplify (ugt (fits_in_64 (ty_int bty)) x zero @ (iconst_u _ 0))) + (ne bty x zero)) + +;; uge(x, 0) == true. +(rule (simplify (uge (fits_in_64 (ty_int bty)) x zero @ (iconst_u _ 0))) + (subsume (iconst_u bty 1))) + +;; ult(x, UMAX) == ne(x, UMAX). +(rule (simplify (ult (fits_in_64 (ty_int bty)) x umax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_umax cty))) + (ne bty x umax)) + +;; ule(x, UMAX) == true. +(rule (simplify (ule (fits_in_64 (ty_int bty)) x umax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_umax cty))) + (subsume (iconst_u bty 1))) + +;; ugt(x, UMAX) == false. +(rule (simplify (ugt (fits_in_64 (ty_int bty)) x umax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_umax cty))) + (subsume (iconst_u bty 0))) + +;; uge(x, UMAX) == eq(x, UMAX). +(rule (simplify (uge (fits_in_64 (ty_int bty)) x umax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_umax cty))) + (eq bty x umax)) + +;; slt(x, SMIN) == false. +(rule (simplify (slt (fits_in_64 (ty_int bty)) x smin @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smin cty))) + (subsume (iconst_u bty 0))) + +;; sle(x, SMIN) == eq(x, SMIN). +(rule (simplify (sle (fits_in_64 (ty_int bty)) x smin @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smin cty))) + (eq bty x smin)) + +;; sgt(x, SMIN) == ne(x, SMIN). +(rule (simplify (sgt (fits_in_64 (ty_int bty)) x smin @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smin cty))) + (ne bty x smin)) + +;; sge(x, SMIN) == true. +(rule (simplify (sge (fits_in_64 (ty_int bty)) x smin @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smin cty))) + (subsume (iconst_u bty 1))) + +;; slt(x, SMAX) == ne(x, SMAX). +(rule (simplify (slt (fits_in_64 (ty_int bty)) x smax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smax cty))) + (ne bty x smax)) + +;; sle(x, SMAX) == true. +(rule (simplify (sle (fits_in_64 (ty_int bty)) x smax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smax cty))) + (subsume (iconst_u bty 1))) + +;; sgt(x, SMAX) == false. +(rule (simplify (sgt (fits_in_64 (ty_int bty)) x smax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smax cty))) + (subsume (iconst_u bty 0))) + +;; sge(x, SMAX) == eq(x, SMAX). +(rule (simplify (sge (fits_in_64 (ty_int bty)) x smax @ (iconst_u cty y))) + (if-let true (u64_eq y (ty_smax cty))) + (eq bty x smax)) + +;; `band`/`bor` of 2 comparisons: +(rule (simplify (band (fits_in_64 ty) (icmp ty cc1 x y) (icmp ty cc2 x y))) + (if-let signed (intcc_comparable cc1 cc2)) + (compose_icmp ty (u64_and (decompose_intcc cc1) (decompose_intcc cc2)) signed x y)) + +(rule (simplify (bor (fits_in_64 ty) (icmp ty cc1 x y) (icmp ty cc2 x y))) + (if-let signed (intcc_comparable cc1 cc2)) + (compose_icmp ty (u64_or (decompose_intcc cc1) (decompose_intcc cc2)) signed x y)) + +;; Prefer comparing against zero +;; uge(x, 1) == ne(x, 0) +(rule (simplify (uge ty x (iconst_u cty 1))) + (ne ty x (iconst_u cty 0))) +;; ult(x, 1) == eq(x, 0) +(rule (simplify (ult ty x (iconst_u cty 1))) + (eq ty x (iconst_u cty 0))) +;; sge(x, 1) == sgt(x, 0) +(rule (simplify (sge ty x (iconst_s cty 1))) + (sgt ty x (iconst_s cty 0))) +;; slt(x, 1) == sle(x, 0) +(rule (simplify (slt ty x (iconst_s cty 1))) + (sle ty x (iconst_s cty 0))) +;; sgt(x, -1) == sge(x, 0) +(rule (simplify (sgt ty x (iconst_s cty -1))) + (sge ty x (iconst_s cty 0))) +;; sle(x, -1) == slt(x, 0) +(rule (simplify (sle ty x (iconst_s cty -1))) + (slt ty x (iconst_s cty 0))) + +(decl pure partial intcc_comparable (IntCC IntCC) bool) +(rule (intcc_comparable x y) + (if-let (u64_nonzero class) (u64_and (intcc_class x) (intcc_class y))) + (u64_eq 2 class)) + +(decl pure decompose_intcc (IntCC) u64) +(rule (decompose_intcc (IntCC.Equal)) 1) +(rule (decompose_intcc (IntCC.UnsignedLessThan)) 2) +(rule (decompose_intcc (IntCC.SignedLessThan)) 2) +(rule (decompose_intcc (IntCC.UnsignedLessThanOrEqual)) 3) +(rule (decompose_intcc (IntCC.SignedLessThanOrEqual)) 3) +(rule (decompose_intcc (IntCC.UnsignedGreaterThan)) 4) +(rule (decompose_intcc (IntCC.SignedGreaterThan)) 4) +(rule (decompose_intcc (IntCC.UnsignedGreaterThanOrEqual)) 5) +(rule (decompose_intcc (IntCC.SignedGreaterThanOrEqual)) 5) +(rule (decompose_intcc (IntCC.NotEqual)) 6) + +(decl compose_icmp (Type u64 bool Value Value) Value) +(rule (compose_icmp ty 0 _ _ _) (subsume (iconst_u ty 0))) +(rule (compose_icmp ty 1 _ x y) (icmp ty (IntCC.Equal) x y)) +(rule (compose_icmp ty 2 false x y) (icmp ty (IntCC.UnsignedLessThan) x y)) +(rule (compose_icmp ty 2 true x y) (icmp ty (IntCC.SignedLessThan) x y)) +(rule (compose_icmp ty 3 false x y) (icmp ty (IntCC.UnsignedLessThanOrEqual) x y)) +(rule (compose_icmp ty 3 true x y) (icmp ty (IntCC.SignedLessThanOrEqual) x y)) +(rule (compose_icmp ty 4 false x y) (icmp ty (IntCC.UnsignedGreaterThan) x y)) +(rule (compose_icmp ty 4 true x y) (icmp ty (IntCC.SignedGreaterThan) x y)) +(rule (compose_icmp ty 5 false x y) (icmp ty (IntCC.UnsignedGreaterThanOrEqual) x y)) +(rule (compose_icmp ty 5 true x y) (icmp ty (IntCC.SignedGreaterThanOrEqual) x y)) +(rule (compose_icmp ty 6 _ x y) (icmp ty (IntCC.NotEqual) x y)) +(rule (compose_icmp ty 7 _ _ _) (subsume (iconst_u ty 1))) + +(decl pure intcc_class (IntCC) u64) +(rule (intcc_class (IntCC.UnsignedLessThan)) 1) +(rule (intcc_class (IntCC.UnsignedLessThanOrEqual)) 1) +(rule (intcc_class (IntCC.UnsignedGreaterThan)) 1) +(rule (intcc_class (IntCC.UnsignedGreaterThanOrEqual)) 1) +(rule (intcc_class (IntCC.SignedLessThan)) 2) +(rule (intcc_class (IntCC.SignedLessThanOrEqual)) 2) +(rule (intcc_class (IntCC.SignedGreaterThan)) 2) +(rule (intcc_class (IntCC.SignedGreaterThanOrEqual)) 2) +(rule (intcc_class (IntCC.Equal)) 3) +(rule (intcc_class (IntCC.NotEqual)) 3) + +;; Pattern-match what LLVM emits today for 128-bit comparisons into actual +;; 128-bit comparisons. Platforms like x64 and aarch64 have more optimal +;; lowerings for 128-bit arithmetic than the default structure. +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (uge ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (uge ty a_hi b_hi))) + (uge ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (uge ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sge ty a_hi b_hi))) + (sge ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ugt ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ugt ty a_hi b_hi))) + (ugt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ugt ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sgt ty a_hi b_hi))) + (sgt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ule ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ule ty a_hi b_hi))) + (ule ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ule ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sle ty a_hi b_hi))) + (sle ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ult ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ult ty a_hi b_hi))) + (ult ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ult ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (slt ty a_hi b_hi))) + (slt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/remat.isle b/deps/crates/vendor/cranelift-codegen/src/opts/remat.isle new file mode 100644 index 00000000000000..00796fc3a2533a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/remat.isle @@ -0,0 +1,31 @@ +;; Rematerialize ALU-op-with-imm and iconsts in each block where they're +;; used. This is neutral (add-with-imm) or positive (iconst) for +;; register pressure, and these ops are very cheap. +(rule (simplify x @ (iadd _ (iconst _ _) _)) + (remat x)) +(rule (simplify x @ (iadd _ _ (iconst _ _))) + (remat x)) +(rule (simplify x @ (isub _ (iconst _ _) _)) + (remat x)) +(rule (simplify x @ (isub _ _ (iconst _ _))) + (remat x)) +(rule (simplify x @ (band _ (iconst _ _) _)) + (remat x)) +(rule (simplify x @ (band _ _ (iconst _ _))) + (remat x)) +(rule (simplify x @ (bor _ (iconst _ _) _)) + (remat x)) +(rule (simplify x @ (bor _ _ (iconst _ _))) + (remat x)) +(rule (simplify x @ (bxor _ (iconst _ _) _)) + (remat x)) +(rule (simplify x @ (bxor _ _ (iconst _ _))) + (remat x)) +(rule (simplify x @ (bnot _ _)) + (remat x)) +(rule (simplify x @ (iconst _ _)) + (remat x)) +(rule (simplify x @ (f32const _ _)) + (remat x)) +(rule (simplify x @ (f64const _ _)) + (remat x)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/selects.isle b/deps/crates/vendor/cranelift-codegen/src/opts/selects.isle new file mode 100644 index 00000000000000..2968f05daba5eb --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/selects.isle @@ -0,0 +1,88 @@ +;; `select`/`bitselect`-related rewrites + +;; remove select when both choices are the same +(rule (simplify (select ty _ x x)) x) +(rule (simplify (bitselect ty _ x x)) x) + +;; Push zeroes to the right -- this makes the select `truthy`, as used elsewhere +;; if icmp { 0 } else { nonzero } => if !icmp { nonzero } else { 0 } +(rule (simplify (select sty (icmp cty cc x y) + zero@(iconst_u _ 0) + nonzero@(iconst_u _ (u64_nonzero _)))) + (select sty (icmp cty (intcc_complement cc) x y) nonzero zero)) + +;; if icmp(x, y) { 1 } else { 0 } => uextend(icmp(x, y)) +(rule (simplify (select ty cmp@(icmp _ cc x y) + (iconst_u _ 1) + (iconst_u _ 0))) + (uextend_maybe ty cmp)) +;; if icmp(x, y) { -1 } else { 0 } => uextend(icmp(x, y)) +(rule (simplify (select ty cmp@(icmp _ cc x y) + (iconst_s _ -1) + (iconst_s _ 0))) + (bmask ty cmp)) + +;; Transform select-of-icmp into {u,s}{min,max} instructions where possible. +(rule (simplify (select ty (sgt _ x y) x y)) (smax ty x y)) +(rule (simplify (select ty (sge _ x y) x y)) (smax ty x y)) +(rule (simplify (select ty (ugt _ x y) x y)) (umax ty x y)) +(rule (simplify (select ty (uge _ x y) x y)) (umax ty x y)) +(rule (simplify (select ty (slt _ x y) x y)) (smin ty x y)) +(rule (simplify (select ty (sle _ x y) x y)) (smin ty x y)) +(rule (simplify (select ty (ult _ x y) x y)) (umin ty x y)) +(rule (simplify (select ty (ule _ x y) x y)) (umin ty x y)) + +;; These are the same rules as above, but when the operands for select are swapped +(rule (simplify (select ty (slt _ x y) y x)) (smax ty x y)) +(rule (simplify (select ty (sle _ x y) y x)) (smax ty x y)) +(rule (simplify (select ty (ult _ x y) y x)) (umax ty x y)) +(rule (simplify (select ty (ule _ x y) y x)) (umax ty x y)) +(rule (simplify (select ty (sgt _ x y) y x)) (smin ty x y)) +(rule (simplify (select ty (sge _ x y) y x)) (smin ty x y)) +(rule (simplify (select ty (ugt _ x y) y x)) (umin ty x y)) +(rule (simplify (select ty (uge _ x y) y x)) (umin ty x y)) + +;; Transform bitselect-of-icmp into {u,s}{min,max} instructions where possible. +(rule (simplify (bitselect ty @ (multi_lane _ _) (sgt _ x y) x y)) (smax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (sge _ x y) x y)) (smax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ugt _ x y) x y)) (umax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (uge _ x y) x y)) (umax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (slt _ x y) x y)) (smin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (sle _ x y) x y)) (smin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ult _ x y) x y)) (umin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ule _ x y) x y)) (umin ty x y)) + +;; These are the same rules as above, but when the operands for select are swapped +(rule (simplify (bitselect ty @ (multi_lane _ _) (slt _ x y) y x)) (smax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (sle _ x y) y x)) (smax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ult _ x y) y x)) (umax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ule _ x y) y x)) (umax ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (sgt _ x y) y x)) (smin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (sge _ x y) y x)) (smin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (ugt _ x y) y x)) (umin ty x y)) +(rule (simplify (bitselect ty @ (multi_lane _ _) (uge _ x y) y x)) (umin ty x y)) + +;; (c & x) | (~c & y) -> (bitselect c x y) +;; These are all the same rule, just with different permutations of the operands +;; +;; We currently only match vectors since scalar floats and i128's are not supported +;; in some backends. +(rule (simplify (bor (ty_vec128 ty) (band ty c x) (band ty (bnot ty c) y))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty c x) (band ty y (bnot ty c) ))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty x c) (band ty (bnot ty c) y))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty x c) (band ty y (bnot ty c) ))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty (bnot ty c) y) (band ty c x))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty (bnot ty c) y) (band ty x c))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty c x))) (bitselect ty c x y)) +(rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty x c))) (bitselect ty c x y)) + +;; Lift an extend operation outside of a `select` if the extend is happening +;; on both the consequent and the alternative. +(rule (simplify (select ty cond + (uextend ty a @ (value_type small)) + (uextend ty b @ (value_type small)))) + (uextend ty (select small cond a b))) +(rule (simplify (select ty cond + (sextend ty a @ (value_type small)) + (sextend ty b @ (value_type small)))) + (sextend ty (select small cond a b))) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/shifts.isle b/deps/crates/vendor/cranelift-codegen/src/opts/shifts.isle new file mode 100644 index 00000000000000..e6aa9e58f23b53 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/shifts.isle @@ -0,0 +1,307 @@ +;; rewrites for shifts and rotates: `ishl, `ushr`, `sshr`, `rotl, `rotr` + +;; x>>0 == x<<0 == x rotr 0 == x rotl 0 == x. +(rule (simplify (ishl ty + x + (iconst_u ty 0))) + (subsume x)) +(rule (simplify (ushr ty + x + (iconst_u ty 0))) + (subsume x)) +(rule (simplify (sshr ty + x + (iconst_u ty 0))) + (subsume x)) +(rule (simplify (rotr ty + x + (iconst_u ty 0))) + (subsume x)) +(rule (simplify (rotl ty + x + (iconst_u ty 0))) + (subsume x)) + +;; `(x >> k) << k` is the same as masking off the bottom `k` bits (regardless if +;; this is a signed or unsigned shift right). +(rule (simplify (ishl (fits_in_64 ty) + (ushr ty x (iconst _ k)) + (iconst _ k))) + (let ((mask Imm64 (imm64_shl ty (imm64 0xFFFF_FFFF_FFFF_FFFF) k))) + (band ty x (iconst ty mask)))) +(rule (simplify (ishl (fits_in_64 ty) + (sshr ty x (iconst _ k)) + (iconst _ k))) + (let ((mask Imm64 (imm64_shl ty (imm64 0xFFFF_FFFF_FFFF_FFFF) k))) + (band ty x (iconst ty mask)))) + +;; For unsigned shifts, `(x << k) >> k` is the same as masking out the top +;; `k` bits. A similar rule is valid for vectors but this `iconst` mask only +;; works for scalar integers. +(rule (simplify (ushr (fits_in_64 (ty_int ty)) + (ishl ty x (iconst _ k)) + (iconst _ k))) + (band ty x (iconst ty (imm64_ushr ty (imm64 (ty_mask ty)) k)))) + +;; For signed shifts, `(x << k) >> k` does sign-extension from `n` bits to +;; `n+k` bits. In the special case where `x` is the result of either `sextend` +;; or `uextend` from `n` bits to `n+k` bits, we can implement this using +;; `sextend`. +(rule (simplify (sshr wide + (ishl wide + (uextend wide x @ (value_type narrow)) + (iconst_u _ shift_u64)) + (iconst_u _ shift_u64))) + (if-let true (u64_eq shift_u64 (u64_sub (ty_bits_u64 wide) (ty_bits_u64 narrow)))) + (sextend wide x)) + +;; If `k` is smaller than the difference in bit widths of the two types, then +;; the intermediate sign bit comes from the extend op, so the final result is +;; the same as the original extend op. +(rule (simplify (sshr wide + (ishl wide + x @ (uextend wide (value_type narrow)) + (iconst_u _ shift_u64)) + (iconst_u _ shift_u64))) + (if-let true (u64_lt shift_u64 (u64_sub (ty_bits_u64 wide) (ty_bits_u64 narrow)))) + x) + +;; If the original extend op was `sextend`, then both of the above cases say +;; the result should also be `sextend`. +(rule (simplify (sshr wide + (ishl wide + x @ (sextend wide (value_type narrow)) + (iconst_u _ shift_u64)) + (iconst_u _ shift_u64))) + (if-let true (u64_le shift_u64 (u64_sub (ty_bits_u64 wide) (ty_bits_u64 narrow)))) + x) + +;; (x << N) >> N == x as T_SMALL as T_LARGE +;; if N == bytesizeof(T_LARGE) - bytesizeof(T_SMALL) +;; +;; Note that the shift is required to be >0 to ensure this doesn't accidentally +;; try to `ireduce` a type to itself, which isn't a valid use of `ireduce`. +(rule (simplify (sshr ty (ishl ty x (iconst _ shift)) (iconst _ shift))) + (if-let (u64_from_imm64 (u64_nonzero shift_u64)) shift) + (if-let ty_small (shift_amt_to_type (u64_sub (ty_bits ty) shift_u64))) + (sextend ty (ireduce ty_small x))) +(rule (simplify (ushr ty (ishl ty x (iconst _ shift)) (iconst _ shift))) + (if-let (u64_from_imm64 (u64_nonzero shift_u64)) shift) + (if-let ty_small (shift_amt_to_type (u64_sub (ty_bits ty) shift_u64))) + (uextend ty (ireduce ty_small x))) + +(decl pure partial shift_amt_to_type (u64) Type) +(rule (shift_amt_to_type 8) $I8) +(rule (shift_amt_to_type 16) $I16) +(rule (shift_amt_to_type 32) $I32) + +;; ineg(ushr(x, k)) == sshr(x, k) when k == ty_bits - 1. +(rule (simplify (ineg ty (ushr ty x sconst @ (iconst_u ty shift_amt)))) + (if-let true (u64_eq shift_amt (ty_shift_mask ty))) + (sshr ty x sconst)) + +;; Shifts and rotates allow a different type for the shift amount, so we +;; can remove any extend/reduce operations on the shift amount. +;; +;; (op x (ireduce y)) == (op x y) +;; (op x (uextend y)) == (op x y) +;; (op x (sextend y)) == (op x y) +;; +;; where `op` is one of ishl, ushr, sshr, rotl, rotr +;; +;; TODO: This rule is restricted to <=64 bits for ireduce since the x86 +;; backend doesn't support SIMD shifts with 128-bit shift amounts. + +(rule (simplify (ishl ty x (ireduce _ y @ (value_type (fits_in_64 _))))) (ishl ty x y)) +(rule (simplify (ishl ty x (uextend _ y))) (ishl ty x y)) +(rule (simplify (ishl ty x (sextend _ y))) (ishl ty x y)) +(rule (simplify (ushr ty x (ireduce _ y @ (value_type (fits_in_64 _))))) (ushr ty x y)) +(rule (simplify (ushr ty x (uextend _ y))) (ushr ty x y)) +(rule (simplify (ushr ty x (sextend _ y))) (ushr ty x y)) +(rule (simplify (sshr ty x (ireduce _ y @ (value_type (fits_in_64 _))))) (sshr ty x y)) +(rule (simplify (sshr ty x (uextend _ y))) (sshr ty x y)) +(rule (simplify (sshr ty x (sextend _ y))) (sshr ty x y)) +(rule (simplify (rotr ty x (ireduce _ y @ (value_type (fits_in_64 _))))) (rotr ty x y)) +(rule (simplify (rotr ty x (uextend _ y))) (rotr ty x y)) +(rule (simplify (rotr ty x (sextend _ y))) (rotr ty x y)) +(rule (simplify (rotl ty x (ireduce _ y @ (value_type (fits_in_64 _))))) (rotl ty x y)) +(rule (simplify (rotl ty x (uextend _ y))) (rotl ty x y)) +(rule (simplify (rotl ty x (sextend _ y))) (rotl ty x y)) + +;; Remove iconcat from the shift amount input. This is correct even if the +;; the iconcat is i8 type, since it can represent the largest shift amount +;; for i128 types. +;; +;; (op x (iconcat y1 y2)) == (op x y1) +;; +;; where `op` is one of ishl, ushr, sshr, rotl, rotr + +(rule (simplify (ishl ty x (iconcat _ y _))) (ishl ty x y)) +(rule (simplify (ushr ty x (iconcat _ y _))) (ushr ty x y)) +(rule (simplify (sshr ty x (iconcat _ y _))) (sshr ty x y)) +(rule (simplify (rotr ty x (iconcat _ y _))) (rotr ty x y)) +(rule (simplify (rotl ty x (iconcat _ y _))) (rotl ty x y)) + +;; Try to combine the shift amount from multiple consecutive shifts +;; This only works if the shift amount remains smaller than the bit +;; width of the type. +;; +;; (ishl (ishl x k1) k2) == (ishl x (add k1 k2)) if shift_mask(k1) + shift_mask(k2) < ty_bits +;; (ushr (ushr x k1) k2) == (ushr x (add k1 k2)) if shift_mask(k1) + shift_mask(k2) < ty_bits +;; (sshr (sshr x k1) k2) == (sshr x (add k1 k2)) if shift_mask(k1) + shift_mask(k2) < ty_bits +(rule (simplify (ishl ty + (ishl ty x (iconst_u kty k1)) + (iconst_u _ k2))) + (if-let shift_amt (u64_add + (u64_and k1 (ty_shift_mask ty)) + (u64_and k2 (ty_shift_mask ty)))) + (if-let true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) + (ishl ty x (iconst_u kty shift_amt))) + +(rule (simplify (ushr ty + (ushr ty x (iconst_u kty k1)) + (iconst_u _ k2))) + (if-let shift_amt (u64_add + (u64_and k1 (ty_shift_mask ty)) + (u64_and k2 (ty_shift_mask ty)))) + (if-let true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) + (ushr ty x (iconst_u kty shift_amt))) + +(rule (simplify (sshr ty + (sshr ty x (iconst_u kty k1)) + (iconst_u _ k2))) + (if-let shift_amt (u64_add + (u64_and k1 (ty_shift_mask ty)) + (u64_and k2 (ty_shift_mask ty)))) + (if-let true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) + (sshr ty x (iconst_u kty shift_amt))) + +;; Similarly, if the shift amount overflows the type, then we can turn +;; it into a 0 +;; +;; (ishl (ishl x k1) k2) == 0 if shift_mask(k1) + shift_mask(k2) >= ty_bits +;; (ushr (ushr x k1) k2) == 0 if shift_mask(k1) + shift_mask(k2) >= ty_bits +(rule (simplify (ishl ty + (ishl ty x (iconst_u _ k1)) + (iconst_u _ k2))) + (if-let shift_amt (u64_add + (u64_and k1 (ty_shift_mask ty)) + (u64_and k2 (ty_shift_mask ty)))) + (if-let true (u64_le (ty_bits_u64 ty) shift_amt)) + (subsume (iconst_u ty 0))) + +(rule (simplify (ushr ty + (ushr ty x (iconst_u _ k1)) + (iconst_u _ k2))) + (if-let shift_amt (u64_add + (u64_and k1 (ty_shift_mask ty)) + (u64_and k2 (ty_shift_mask ty)))) + (if-let true (u64_le (ty_bits_u64 ty) shift_amt)) + (subsume (iconst_u ty 0))) + +;; (rotl (rotr x y) y) == x +;; (rotr (rotl x y) y) == x +(rule (simplify (rotl ty (rotr ty x y) y)) (subsume x)) +(rule (simplify (rotr ty (rotl ty x y) y)) (subsume x)) + +;; Emits an iadd for two values. If they have different types +;; then the smaller type is zero extended to the larger type. +(decl iadd_uextend (Value Value) Value) +(rule 1 (iadd_uextend x @ (value_type ty) y @ (value_type ty)) + (iadd ty x y)) +(rule 2 (iadd_uextend x @ (value_type x_ty) y @ (value_type y_ty)) + (if-let true (u64_lt (ty_bits_u64 x_ty) (ty_bits_u64 y_ty))) + (iadd y_ty (uextend y_ty x) y)) +(rule 3 (iadd_uextend x @ (value_type x_ty) y @ (value_type y_ty)) + (if-let true (u64_lt (ty_bits_u64 y_ty) (ty_bits_u64 x_ty))) + (iadd x_ty x (uextend x_ty y))) + +;; Emits an isub for two values. If they have different types +;; then the smaller type is zero extended to the larger type. +(decl isub_uextend (Value Value) Value) +(rule 1 (isub_uextend x @ (value_type ty) y @ (value_type ty)) + (isub ty x y)) +(rule 2 (isub_uextend x @ (value_type x_ty) y @ (value_type y_ty)) + (if-let true (u64_lt (ty_bits_u64 x_ty) (ty_bits_u64 y_ty))) + (isub y_ty (uextend y_ty x) y)) +(rule 3 (isub_uextend x @ (value_type x_ty) y @ (value_type y_ty)) + (if-let true (u64_lt (ty_bits_u64 y_ty) (ty_bits_u64 x_ty))) + (isub x_ty x (uextend x_ty y))) + +;; Try to group constants together so that other cprop rules can optimize them. +;; +;; (rotr (rotr x y) z) == (rotr x (iadd y z)) +;; (rotl (rotl x y) z) == (rotl x (iadd y z)) +;; (rotr (rotl x y) z) == (rotr x (isub y z)) +;; (rotl (rotr x y) z) == (rotl x (isub y z)) +;; +;; if x or z are constants +(rule (simplify (rotl ty (rotl ty x y @ (iconst _ _)) z)) (rotl ty x (iadd_uextend y z))) +(rule (simplify (rotl ty (rotl ty x y) z @ (iconst _ _))) (rotl ty x (iadd_uextend y z))) +(rule (simplify (rotr ty (rotr ty x y @ (iconst _ _)) z)) (rotr ty x (iadd_uextend y z))) +(rule (simplify (rotr ty (rotr ty x y) z @ (iconst _ _))) (rotr ty x (iadd_uextend y z))) + +(rule (simplify (rotr ty (rotl ty x y @ (iconst _ _)) z)) (rotl ty x (isub_uextend y z))) +(rule (simplify (rotr ty (rotl ty x y) z @ (iconst _ _))) (rotl ty x (isub_uextend y z))) +(rule (simplify (rotl ty (rotr ty x y @ (iconst _ _)) z)) (rotr ty x (isub_uextend y z))) +(rule (simplify (rotl ty (rotr ty x y) z @ (iconst _ _))) (rotr ty x (isub_uextend y z))) + +;; Similarly to the rules above, if y and z have the same type, we should emit +;; an iadd or isub instead. In some backends this is cheaper than a rotate. +;; +;; If they have different types we end up in a situation where we have to insert +;; and additional extend and that transformation is not universally beneficial. +;; +;; (rotr (rotr x y) z) == (rotr x (iadd y z)) +;; (rotl (rotl x y) z) == (rotl x (iadd y z)) +;; (rotr (rotl x y) z) == (rotl x (isub y z)) +;; (rotl (rotr x y) z) == (rotr x (isub y z)) +(rule (simplify (rotr ty (rotr ty x y @ (value_type kty)) z @ (value_type kty))) + (rotr ty x (iadd_uextend y z))) +(rule (simplify (rotl ty (rotl ty x y @ (value_type kty)) z @ (value_type kty))) + (rotl ty x (iadd_uextend y z))) + +(rule (simplify (rotr ty (rotl ty x y @ (value_type kty)) z @ (value_type kty))) + (rotl ty x (isub_uextend y z))) +(rule (simplify (rotl ty (rotr ty x y @ (value_type kty)) z @ (value_type kty))) + (rotr ty x (isub_uextend y z))) + +;; Convert shifts into rotates. We always normalize into a rotate left. +;; +;; (bor (ishl x k1) (ushr x k2)) == (rotl x k1) if k2 == ty_bits - k1 +;; (bor (ushr x k2) (ishl x k1)) == (rotl x k1) if k2 == ty_bits - k1 +;; +;; TODO: This rule is restricted to scalars since no backend currently +;; supports SIMD rotates. +(rule (simplify (bor (ty_int ty) + (ishl ty x k @ (iconst _ (u64_from_imm64 k1))) + (ushr ty x (iconst _ (u64_from_imm64 k2))))) + (if-let true (u64_eq k2 (u64_sub (ty_bits_u64 (lane_type ty)) k1))) + (rotl ty x k)) +(rule (simplify (bor (ty_int ty) + (ushr ty x (iconst _ (u64_from_imm64 k2))) + (ishl ty x k @ (iconst _ (u64_from_imm64 k1))))) + (if-let true (u64_eq k2 (u64_sub (ty_bits_u64 (lane_type ty)) k1))) + (rotl ty x k)) + +;; Normalize the shift amount. Some rules can't fire unless the shift amount +;; is normalized. This also helps us materialize fewer and smaller constants. +;; +;; (op x k) == (op x (and k (ty_shift_mask ty))) +;; +;; where `op` is one of ishl, ushr, sshr, rotl, rotr +(rule (simplify (ishl ty x (iconst_u kty k))) + (if-let false (u64_eq k (u64_and k (ty_shift_mask ty)))) + (ishl ty x (iconst_u kty (u64_and k (ty_shift_mask ty))))) +(rule (simplify (ushr ty x (iconst_u kty k))) + (if-let false (u64_eq k (u64_and k (ty_shift_mask ty)))) + (ushr ty x (iconst_u kty (u64_and k (ty_shift_mask ty))))) +(rule (simplify (sshr ty x (iconst_u kty k))) + (if-let false (u64_eq k (u64_and k (ty_shift_mask ty)))) + (sshr ty x (iconst_u kty (u64_and k (ty_shift_mask ty))))) +(rule (simplify (rotr ty x (iconst_u kty k))) + (if-let false (u64_eq k (u64_and k (ty_shift_mask ty)))) + (rotr ty x (iconst_u kty (u64_and k (ty_shift_mask ty))))) +(rule (simplify (rotl ty x (iconst_u kty k))) + (if-let false (u64_eq k (u64_and k (ty_shift_mask ty)))) + (rotl ty x (iconst_u kty (u64_and k (ty_shift_mask ty))))) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/spaceship.isle b/deps/crates/vendor/cranelift-codegen/src/opts/spaceship.isle new file mode 100644 index 00000000000000..a834aa49e4cf6f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/spaceship.isle @@ -0,0 +1,194 @@ +;; Simplifications for C++20's `<=>` "spaceship" operator, aka Rust's `Ord::cmp`. +;; +;; There's no cranelift instruction for this, nor usually a machine instruction. +;; Inspired by +;; we canonicalize the various implementations of `x <=> y` to `(x > y) - (x < y)`. + +;; Unfortunately, there's at least 3!×2 reasonable ways to write this as nested +;; selects, and no broad agreement which is the best -- notably Rust 1.74 and +;; Clang 17 use different sequences -- so we just match all of them. + +;; x < y ? -1 : x == y ? 0 : +1 +;; x < y ? -1 : x != y ? +1 : 0 +(rule (simplify (select ty (ult rty x y) + (iconst_s ty -1) + (uextend_maybe ty (ne rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) +;; x < y ? -1 : x <= y ? 0 : +1 +;; x < y ? -1 : x > y ? +1 : 0 +(rule (simplify (select ty (ult rty x y) + (iconst_s ty -1) + (uextend_maybe ty (ugt rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) + +;; x == y ? 0 : x < y ? -1 : +1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (ult rty x y) + (iconst_s ty -1) + (iconst_s ty 1)))) + (sextend_maybe ty (spaceship_u rty x y))) +;; x == y ? 0 : x <= y ? -1 : +1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (ule rty x y) + (iconst_s ty -1) + (iconst_s ty 1)))) + (sextend_maybe ty (spaceship_u rty x y))) +;; x == y ? 0 : x > y ? +1 : -1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (ugt rty x y) + (iconst_s ty 1) + (iconst_s ty -1)))) + (sextend_maybe ty (spaceship_u rty x y))) +;; x == y ? 0 : x >= y ? +1 : -1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (uge rty x y) + (iconst_s ty 1) + (iconst_s ty -1)))) + (sextend_maybe ty (spaceship_u rty x y))) + +;; x > y ? 1 : x < y ? -1 : 0 +;; x > y ? 1 : x >= y ? 0 : -1 +(rule (simplify (select ty (ugt rty x y) + (iconst_s ty 1) + (ineg rty (ult rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) +(rule (simplify (select ty (ugt rty x y) + (iconst_s ty 1) + (bmask ty (ult rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) +;; x > y ? 1 : x != y ? -1 : 0 +;; x > y ? 1 : x == y ? 0 : -1 +(rule (simplify (select ty (ugt rty x y) + (iconst_s ty 1) + (ineg rty (ne rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) +(rule (simplify (select ty (ugt rty x y) + (iconst_s ty 1) + (bmask ty (ne rty x y)))) + (sextend_maybe ty (spaceship_u rty x y))) + +;; Same, but for signed comparisons this time + +;; x < y ? -1 : x == y ? 0 : +1 +;; x < y ? -1 : x != y ? +1 : 0 +(rule (simplify (select ty (slt rty x y) + (iconst_s ty -1) + (uextend_maybe ty (ne rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) +;; x < y ? -1 : x <= y ? 0 : +1 +;; x < y ? -1 : x > y ? +1 : 0 +(rule (simplify (select ty (slt rty x y) + (iconst_s ty -1) + (uextend_maybe ty (sgt rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) + +;; x == y ? 0 : x < y ? -1 : +1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (slt rty x y) + (iconst_s ty -1) + (iconst_s ty 1)))) + (sextend_maybe ty (spaceship_s rty x y))) +;; x == y ? 0 : x <= y ? -1 : +1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (sle rty x y) + (iconst_s ty -1) + (iconst_s ty 1)))) + (sextend_maybe ty (spaceship_s rty x y))) +;; x == y ? 0 : x > y ? +1 : -1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (sgt rty x y) + (iconst_s ty 1) + (iconst_s ty -1)))) + (sextend_maybe ty (spaceship_s rty x y))) +;; x == y ? 0 : x >= y ? +1 : -1 +(rule (simplify (select ty (eq rty x y) + (iconst_s ty 0) + (select ty (sge rty x y) + (iconst_s ty 1) + (iconst_s ty -1)))) + (sextend_maybe ty (spaceship_s rty x y))) + +;; x > y ? 1 : x < y ? -1 : 0 +;; x > y ? 1 : x >= y ? 0 : -1 +(rule (simplify (select ty (sgt rty x y) + (iconst_s ty 1) + (ineg rty (slt rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) +(rule (simplify (select ty (sgt rty x y) + (iconst_s ty 1) + (bmask ty (slt rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) +;; x > y ? 1 : x != y ? -1 : 0 +;; x > y ? 1 : x == y ? 0 : -1 +(rule (simplify (select ty (sgt rty x y) + (iconst_s ty 1) + (ineg rty (ne rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) +(rule (simplify (select ty (sgt rty x y) + (iconst_s ty 1) + (bmask ty (ne rty x y)))) + (sextend_maybe ty (spaceship_s rty x y))) + +;; Then once we have it normalized, we can apply some basic simplifications. +;; For example, a derived `PartialOrd::lt` on a newtype in Rust will essentially +;; emit `(a <=> b) < 0`, and replacing that with `a < b` can really help. +;; `icmp.isle` prefers comparing against zero so we don't need to worry about +;; also matching things like `(a <=> b) < 1` or `(a <=> b) <= -1`. + +;; (a <=> b) == 0 --> a == b +(rule (simplify (eq _ (spaceship_s ty x y) (iconst_s _ 0))) + (eq ty x y)) +(rule (simplify (eq _ (spaceship_u ty x y) (iconst_s _ 0))) + (eq ty x y)) +;; (a <=> b) != 0 --> a != b +(rule (simplify (ne _ (spaceship_s ty x y) (iconst_s _ 0))) + (ne ty x y)) +(rule (simplify (ne _ (spaceship_u ty x y) (iconst_s _ 0))) + (ne ty x y)) + +;; (a <=> b) < 0 --> a < b +(rule (simplify (slt _ (spaceship_s ty x y) (iconst_s _ 0))) + (slt ty x y)) +(rule (simplify (slt _ (spaceship_u ty x y) (iconst_s _ 0))) + (ult ty x y)) +;; (a <=> b) <= 0 --> a <= b +(rule (simplify (sle _ (spaceship_s ty x y) (iconst_s _ 0))) + (sle ty x y)) +(rule (simplify (sle _ (spaceship_u ty x y) (iconst_s _ 0))) + (ule ty x y)) +;; (a <=> b) > 0 --> a > b +(rule (simplify (sgt _ (spaceship_s ty x y) (iconst_s _ 0))) + (sgt ty x y)) +(rule (simplify (sgt _ (spaceship_u ty x y) (iconst_s _ 0))) + (ugt ty x y)) +;; (a <=> b) >= 0 --> a >= b +(rule (simplify (sge _ (spaceship_s ty x y) (iconst_s _ 0))) + (sge ty x y)) +(rule (simplify (sge _ (spaceship_u ty x y) (iconst_s _ 0))) + (uge ty x y)) + +;; Rust's `sort_by` uses `compare(a, b) == Less`, which the general icmp rules +;; can't simplify to a comparison against zero, so catch things like that too. +(rule (simplify (eq _ (spaceship_s ty x y) (iconst_s _ -1))) + (slt ty x y)) +(rule (simplify (eq _ (spaceship_u ty x y) (iconst_s _ -1))) + (ult ty x y)) +(rule (simplify (ne _ (spaceship_s ty x y) (iconst_s _ -1))) + (sge ty x y)) +(rule (simplify (ne _ (spaceship_u ty x y) (iconst_s _ -1))) + (uge ty x y)) +(rule (simplify (eq _ (spaceship_s ty x y) (iconst_s _ 1))) + (sgt ty x y)) +(rule (simplify (eq _ (spaceship_u ty x y) (iconst_s _ 1))) + (ugt ty x y)) +(rule (simplify (ne _ (spaceship_s ty x y) (iconst_s _ 1))) + (sle ty x y)) +(rule (simplify (ne _ (spaceship_u ty x y) (iconst_s _ 1))) + (ule ty x y)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/spectre.isle b/deps/crates/vendor/cranelift-codegen/src/opts/spectre.isle new file mode 100644 index 00000000000000..c58e29eaa9fe39 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/spectre.isle @@ -0,0 +1,14 @@ +;; Rewrites for `select_spectre_guard`. Check these rules carefully! This +;; instruction prohibits all speculation on the controlling value when +;; determining which input to use as the result. Rewrites must respect that +;; requirement. + +;; If we statically know which value will be the result, it's safe to just use +;; that value. No speculation on the controlling value is possible if we simply +;; don't depend on that value at all. +(rule (simplify (select_spectre_guard _ _ x x)) + (subsume x)) +(rule (simplify (select_spectre_guard _ (iconst_u _ (u64_nonzero _)) x _)) + (subsume x)) +(rule (simplify (select_spectre_guard _ (iconst_u _ 0) _ y)) + (subsume y)) diff --git a/deps/crates/vendor/cranelift-codegen/src/opts/vector.isle b/deps/crates/vendor/cranelift-codegen/src/opts/vector.isle new file mode 100644 index 00000000000000..5ad57d8dc60439 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/opts/vector.isle @@ -0,0 +1,89 @@ +;; For various ops lift a splat outside of the op to try to open up +;; optimization opportunities with scalars. + +;; NB: for int-to-float conversion op this simplification is also +;; required for the x64 backend because it doesn't fully implement int-to-float +;; conversions for 64x2 vectors, for more information see #6562 +(rule (simplify (fcvt_from_uint float_vector_ty (splat _ x))) + (splat float_vector_ty (fcvt_from_uint (lane_type float_vector_ty) x))) +(rule (simplify (fcvt_from_sint float_vector_ty (splat _ x))) + (splat float_vector_ty (fcvt_from_sint (lane_type float_vector_ty) x))) + +;; Scalar bitwise ops are usually not implemented in the backends for floats, so +;; disable this transform. + +(rule (simplify (band ty (splat ty x) (splat ty y))) + (if (ty_vector_not_float ty)) + (splat ty (band (lane_type ty) x y))) + +(rule (simplify (bor ty (splat ty x) (splat ty y))) + (if (ty_vector_not_float ty)) + (splat ty (bor (lane_type ty) x y))) + +(rule (simplify (bxor ty (splat ty x) (splat ty y))) + (if (ty_vector_not_float ty)) + (splat ty (bxor (lane_type ty) x y))) + +(rule (simplify (bnot ty (splat ty x))) + (if (ty_vector_not_float ty)) + (splat ty (bnot (lane_type ty) x))) + +(rule (simplify (iadd ty (splat ty x) (splat ty y))) + (splat ty (iadd (lane_type ty) x y))) + +(rule (simplify (isub ty (splat ty x) (splat ty y))) + (splat ty (isub (lane_type ty) x y))) + +(rule (simplify (imul ty (splat ty x) (splat ty y))) + (splat ty (imul (lane_type ty) x y))) + +(rule (simplify (smulhi ty (splat ty x) (splat ty y))) + (splat ty (smulhi (lane_type ty) x y))) + +(rule (simplify (umulhi ty (splat ty x) (splat ty y))) + (splat ty (umulhi (lane_type ty) x y))) + +(rule (simplify (ineg ty (splat ty x))) + (splat ty (ineg (lane_type ty) x))) + +(rule (simplify (iabs ty (splat ty x))) + (splat ty (iabs (lane_type ty) x))) + +(rule (simplify (popcnt ty (splat ty x))) + (splat ty (popcnt (lane_type ty) x))) + +(rule (simplify (smin ty (splat ty x) (splat ty y))) + (splat ty (smin (lane_type ty) x y))) + +(rule (simplify (umin ty (splat ty x) (splat ty y))) + (splat ty (umin (lane_type ty) x y))) + +(rule (simplify (smax ty (splat ty x) (splat ty y))) + (splat ty (smax (lane_type ty) x y))) + +(rule (simplify (umax ty (splat ty x) (splat ty y))) + (splat ty (umax (lane_type ty) x y))) + +;; The second operand of shift and rotate ops is +;; scalar so splat opt applies only to the first +(rule (simplify (rotl ty (splat ty x) y)) + (splat ty (rotl (lane_type ty) x y))) + +(rule (simplify (rotr ty (splat ty x) y)) + (splat ty (rotr (lane_type ty) x y))) + +(rule (simplify (ishl ty (splat ty x) y)) + (splat ty (ishl (lane_type ty) x y))) + +(rule (simplify (ushr ty (splat ty x) y)) + (splat ty (ushr (lane_type ty) x y))) + +(rule (simplify (sshr ty (splat ty x) y)) + (splat ty (sshr (lane_type ty) x y))) + +;; {u,s}widen_{low,high}+splat is the same as splat+{u,s}extend +(rule (simplify (swiden_high wide (splat _ x))) (splat wide (sextend (lane_type wide) x))) +(rule (simplify (swiden_low wide (splat _ x))) (splat wide (sextend (lane_type wide) x))) + +(rule (simplify (uwiden_high wide (splat _ x))) (splat wide (uextend (lane_type wide) x))) +(rule (simplify (uwiden_low wide (splat _ x))) (splat wide (uextend (lane_type wide) x))) diff --git a/deps/crates/vendor/cranelift-codegen/src/prelude.isle b/deps/crates/vendor/cranelift-codegen/src/prelude.isle new file mode 100644 index 00000000000000..3f7b12b991d619 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/prelude.isle @@ -0,0 +1,836 @@ +;; This is a prelude of standard definitions for ISLE, the instruction-selector +;; DSL, as we use it bound to our interfaces. +;; +;; Note that all `extern` functions here are typically defined in the +;; `isle_prelude_methods` macro defined in `src/isa/isle.rs` + +;;;; Primitive and External Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `()` +(type Unit (primitive Unit)) +(model Unit (type Unit)) + +(decl pure unit () Unit) +(extern constructor unit unit) + +(model bool (type Bool)) + +(model u8 (type (bv 8))) +(model u16 (type (bv 16))) +(model u32 (type (bv 32))) +(model u64 (type (bv 64))) +(model usize (type (bv))) + +(model i8 (type (bv 8))) +(model i16 (type (bv 16))) +(model i32 (type (bv 32))) +(model i64 (type (bv 64))) + +;; `cranelift-entity`-based identifiers. +(model Type (type Int)) +(type Type (primitive Type)) +(model Value (type (bv))) +(type Value (primitive Value)) +(type ValueList (primitive ValueList)) +(type BlockCall (primitive BlockCall)) + +;; ISLE representation of `&[Value]`. +(type ValueSlice (primitive ValueSlice)) + +;; Extract the type of a `Value`. +(spec (value_type arg) (provide (= arg (widthof result)))) +(decl value_type (Type) Value) +(extern extractor infallible value_type value_type) + +;; Extractor that matches a `u32` only if non-negative. +(decl u32_nonnegative (u32) u32) +(extern extractor u32_nonnegative u32_nonnegative) + +;; Extractor that pulls apart an Offset32 into a i32 with the raw +;; signed-32-bit twos-complement bits. +(decl offset32 (i32) Offset32) +(extern extractor infallible offset32 offset32) + +;; Pure/fallible constructor that tests if one u32 is less than or +;; equal to another. +(spec (u32_lteq a b) + (provide (= result ())) + (require (<= a b) + (= (widthof a) 32) + (= (widthof b) 32))) +(decl pure partial u32_lteq (u32 u32) Unit) +(extern constructor u32_lteq u32_lteq) + +;; Pure/fallible constructor that tests if one u8 is less than or +;; equal to another. +(decl pure partial u8_lteq (u8 u8) Unit) +(extern constructor u8_lteq u8_lteq) + +;; Pure/fallible constructor that tests if one u8 is strictly less +;; than another. +(decl pure partial u8_lt (u8 u8) Unit) +(extern constructor u8_lt u8_lt) + +;;;; Primitive Type Conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pure u8_as_i8 (u8) i8) +(extern constructor u8_as_i8 u8_as_i8) + +(spec (u8_as_u32 arg) + (provide (= result (zero_ext 32 arg))) + (require + (= (widthof arg) 8) + (= (widthof result) 32))) +(decl pure u8_as_u32 (u8) u32) +(extern constructor u8_as_u32 u8_as_u32) +(convert u8 u32 u8_as_u32) + +(decl pure u8_as_u64 (u8) u64) +(extern constructor u8_as_u64 u8_as_u64) +(convert u8 u64 u8_as_u64) + +(decl pure u16_as_i16 (u16) i16) +(extern constructor u16_as_i16 u16_as_i16) + +(decl pure u16_as_u32 (u16) u32) +(extern constructor u16_as_u32 u16_as_u32) +(convert u16 u32 u16_as_u32) + +(decl pure u16_as_u64 (u16) u64) +(extern constructor u16_as_u64 u16_as_u64) +(convert u16 u64 u16_as_u64) + +(decl pure u64_as_u8 (u64) u8) +(extern constructor u64_as_u8 u64_as_u8) + +(decl pure u64_as_u16 (u64) u16) +(extern constructor u64_as_u16 u64_as_u16) + +(decl pure u64_as_i64 (u64) i64) +(extern constructor u64_as_i64 u64_as_i64) + +(decl pure partial u8_try_from_u64 (u64) u8) +(extern constructor u8_try_from_u64 u8_try_from_u64) + +(decl pure partial u16_try_from_u64 (u64) u16) +(extern constructor u16_try_from_u64 u16_try_from_u64) + +(decl pure partial u32_try_from_u64 (u64) u32) +(extern constructor u32_try_from_u64 u32_try_from_u64) + +(decl pure partial u64_try_from_i64 (i64) u64) +(extern constructor u64_try_from_i64 u64_try_from_i64) + +(decl pure partial i8_try_from_u64 (u64) i8) +(extern constructor i8_try_from_u64 i8_try_from_u64) + +(decl pure partial i16_try_from_u64 (u64) i16) +(extern constructor i16_try_from_u64 i16_try_from_u64) + +(decl pure partial i32_try_from_u64 (u64) i32) +(extern constructor i32_try_from_u64 i32_try_from_u64) + +(decl pure u32_as_u64 (u32) u64) +(extern constructor u32_as_u64 u32_as_u64) +(convert u32 u64 u32_as_u64) + +(decl pure i32_as_i64 (i32) i64) +(extern constructor i32_as_i64 i32_as_i64) +(convert i32 i64 i32_as_i64) + +(spec (i64_as_u64 arg) (provide (= arg result))) +(decl pure i64_as_u64 (i64) u64) +(extern constructor i64_as_u64 i64_as_u64) + +(spec (i64_neg x) (provide (= result (bvneg x)))) +(decl pure i64_neg (i64) i64) +(extern constructor i64_neg i64_neg) + +(decl pure i8_neg (i8) i8) +(extern constructor i8_neg i8_neg) + +(decl u128_as_u64 (u64) u128) +(extern extractor u128_as_u64 u128_as_u64) + +(decl u64_as_u32 (u32) u64) +(extern extractor u64_as_u32 u64_as_u32) + +(decl u32_as_u16 (u16) u32) +(extern extractor u32_as_u16 u32_as_u16) + +(decl i32_as_i8 (i8) i32) +(extern extractor i32_as_i8 i32_as_i8) + +(decl pure u64_as_i32 (u64) i32) +(extern constructor u64_as_i32 u64_as_i32) + +;;;; Primitive Arithmetic ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pure u8_and (u8 u8) u8) +(extern constructor u8_and u8_and) + +(decl pure u8_shl (u8 u8) u8) +(extern constructor u8_shl u8_shl) + +(decl pure u8_shr (u8 u8) u8) +(extern constructor u8_shr u8_shr) + +(decl pure u8_sub (u8 u8) u8) +(extern constructor u8_sub u8_sub) + +(decl pure u32_add (u32 u32) u32) +(extern constructor u32_add u32_add) + +(spec (u32_sub a b) (provide (= result (bvsub a b)))) +(decl pure u32_sub (u32 u32) u32) +(extern constructor u32_sub u32_sub) + +(decl pure u32_and (u32 u32) u32) +(extern constructor u32_and u32_and) + +(decl pure u32_shl (u32 u32) u32) +(extern constructor u32_shl u32_shl) + +;; Pure/fallible constructor that tries to add two `u32`s, interpreted +;; as signed values, and fails to match on overflow. +(spec (s32_add_fallible x y) + (provide (= result (bvadd x y))) + (require (not (bvsaddo x y)))) +(decl pure partial s32_add_fallible (i32 i32) i32) +(extern constructor s32_add_fallible s32_add_fallible) + +(decl pure u64_add (u64 u64) u64) +(extern constructor u64_add u64_add) + +(spec (u64_sub a b) + (provide (= result (bvsub a b)))) +(decl pure u64_sub (u64 u64) u64) +(extern constructor u64_sub u64_sub) + +(decl pure u64_mul (u64 u64) u64) +(extern constructor u64_mul u64_mul) + +(decl pure partial u64_sdiv (u64 u64) u64) +(extern constructor u64_sdiv u64_sdiv) + +(decl pure partial u64_udiv (u64 u64) u64) +(extern constructor u64_udiv u64_udiv) + +(decl pure u64_and (u64 u64) u64) +(extern constructor u64_and u64_and) + +(decl pure u64_or (u64 u64) u64) +(extern constructor u64_or u64_or) + +(decl pure u64_xor (u64 u64) u64) +(extern constructor u64_xor u64_xor) + +(decl pure u64_shl (u64 u64) u64) +(extern constructor u64_shl u64_shl) + +(decl pure imm64_shl (Type Imm64 Imm64) Imm64) +(extern constructor imm64_shl imm64_shl) + +(decl pure imm64_ushr (Type Imm64 Imm64) Imm64) +(extern constructor imm64_ushr imm64_ushr) + +(decl pure imm64_sshr (Type Imm64 Imm64) Imm64) +(extern constructor imm64_sshr imm64_sshr) + +(decl pure u64_not (u64) u64) +(extern constructor u64_not u64_not) + +(decl pure u64_eq (u64 u64) bool) +(extern constructor u64_eq u64_eq) + +(decl pure u64_le (u64 u64) bool) +(extern constructor u64_le u64_le) + +(decl pure u64_lt (u64 u64) bool) +(extern constructor u64_lt u64_lt) + +(decl pure i64_shr (i64 i64) i64) +(extern constructor i64_shr i64_shr) + +(decl pure i64_ctz (i64) i64) +(extern constructor i64_ctz i64_ctz) + +;; Sign extends a u64 from ty bits up to 64bits +(decl pure i64_sextend_u64 (Type u64) i64) +(extern constructor i64_sextend_u64 i64_sextend_u64) + +(spec (i64_sextend_imm64 ty a) (provide (= result (sign_ext 64 (conv_to ty a))))) +(decl pure i64_sextend_imm64 (Type Imm64) i64) +(extern constructor i64_sextend_imm64 i64_sextend_imm64) + +(decl pure u64_uextend_imm64 (Type Imm64) u64) +(extern constructor u64_uextend_imm64 u64_uextend_imm64) + +(decl pure imm64_icmp (Type IntCC Imm64 Imm64) Imm64) +(extern constructor imm64_icmp imm64_icmp) + +(decl u64_is_zero (bool) u64) +(extern extractor infallible u64_is_zero u64_is_zero) + +(decl i64_is_zero (bool) i64) +(extern extractor infallible i64_is_zero i64_is_zero) + +(decl u64_zero () u64) +(extractor (u64_zero) (u64_is_zero true)) + +(decl u64_nonzero (u64) u64) +(extractor (u64_nonzero x) (and (u64_is_zero false) x)) + +(decl i64_nonzero (i64) i64) +(extractor (i64_nonzero x) (and (i64_is_zero false) x)) + +;; x & 1 == 1 +(spec (u64_is_odd arg) (provide (= result (= #b1 (extract 0 0 arg))))) +(decl pure u64_is_odd (u64) bool) +(extern constructor u64_is_odd u64_is_odd) + +;; Each of these extractors tests whether the upper half of the input equals the +;; lower half of the input +(decl u128_replicated_u64 (u64) u128) +(extern extractor u128_replicated_u64 u128_replicated_u64) +(decl u64_replicated_u32 (u64) u64) +(extern extractor u64_replicated_u32 u64_replicated_u32) +(decl u32_replicated_u16 (u64) u64) +(extern extractor u32_replicated_u16 u32_replicated_u16) +(decl u16_replicated_u8 (u8) u64) +(extern extractor u16_replicated_u8 u16_replicated_u8) + +;; Floating point operations + +(decl pure partial f16_min (Ieee16 Ieee16) Ieee16) +(extern constructor f16_min f16_min) +(decl pure partial f16_max (Ieee16 Ieee16) Ieee16) +(extern constructor f16_max f16_max) +(decl pure f16_neg (Ieee16) Ieee16) +(extern constructor f16_neg f16_neg) +(decl pure f16_abs (Ieee16) Ieee16) +(extern constructor f16_abs f16_abs) +(decl pure f16_copysign (Ieee16 Ieee16) Ieee16) +(extern constructor f16_copysign f16_copysign) +(decl pure partial f32_add (Ieee32 Ieee32) Ieee32) +(extern constructor f32_add f32_add) +(decl pure partial f32_sub (Ieee32 Ieee32) Ieee32) +(extern constructor f32_sub f32_sub) +(decl pure partial f32_mul (Ieee32 Ieee32) Ieee32) +(extern constructor f32_mul f32_mul) +(decl pure partial f32_div (Ieee32 Ieee32) Ieee32) +(extern constructor f32_div f32_div) +(decl pure partial f32_sqrt (Ieee32) Ieee32) +(extern constructor f32_sqrt f32_sqrt) +(decl pure partial f32_ceil (Ieee32) Ieee32) +(extern constructor f32_ceil f32_ceil) +(decl pure partial f32_floor (Ieee32) Ieee32) +(extern constructor f32_floor f32_floor) +(decl pure partial f32_trunc (Ieee32) Ieee32) +(extern constructor f32_trunc f32_trunc) +(decl pure partial f32_nearest (Ieee32) Ieee32) +(extern constructor f32_nearest f32_nearest) +(decl pure partial f32_min (Ieee32 Ieee32) Ieee32) +(extern constructor f32_min f32_min) +(decl pure partial f32_max (Ieee32 Ieee32) Ieee32) +(extern constructor f32_max f32_max) +(decl pure f32_neg (Ieee32) Ieee32) +(extern constructor f32_neg f32_neg) +(decl pure f32_abs (Ieee32) Ieee32) +(extern constructor f32_abs f32_abs) +(decl pure f32_copysign (Ieee32 Ieee32) Ieee32) +(extern constructor f32_copysign f32_copysign) +(decl pure partial f64_add (Ieee64 Ieee64) Ieee64) +(extern constructor f64_add f64_add) +(decl pure partial f64_sub (Ieee64 Ieee64) Ieee64) +(extern constructor f64_sub f64_sub) +(decl pure partial f64_mul (Ieee64 Ieee64) Ieee64) +(extern constructor f64_mul f64_mul) +(decl pure partial f64_div (Ieee64 Ieee64) Ieee64) +(extern constructor f64_div f64_div) +(decl pure partial f64_sqrt (Ieee64) Ieee64) +(extern constructor f64_sqrt f64_sqrt) +(decl pure partial f64_ceil (Ieee64) Ieee64) +(extern constructor f64_ceil f64_ceil) +(decl pure partial f64_floor (Ieee64) Ieee64) +(extern constructor f64_floor f64_floor) +(decl pure partial f64_trunc (Ieee64) Ieee64) +(extern constructor f64_trunc f64_trunc) +(decl pure partial f64_nearest (Ieee64) Ieee64) +(extern constructor f64_nearest f64_nearest) +(decl pure partial f64_min (Ieee64 Ieee64) Ieee64) +(extern constructor f64_min f64_min) +(decl pure partial f64_max (Ieee64 Ieee64) Ieee64) +(extern constructor f64_max f64_max) +(decl pure f64_neg (Ieee64) Ieee64) +(extern constructor f64_neg f64_neg) +(decl pure f64_abs (Ieee64) Ieee64) +(extern constructor f64_abs f64_abs) +(decl pure f64_copysign (Ieee64 Ieee64) Ieee64) +(extern constructor f64_copysign f64_copysign) +(decl pure partial f128_min (Ieee128 Ieee128) Ieee128) +(extern constructor f128_min f128_min) +(decl pure partial f128_max (Ieee128 Ieee128) Ieee128) +(extern constructor f128_max f128_max) +(decl pure f128_neg (Ieee128) Ieee128) +(extern constructor f128_neg f128_neg) +(decl pure f128_abs (Ieee128) Ieee128) +(extern constructor f128_abs f128_abs) +(decl pure f128_copysign (Ieee128 Ieee128) Ieee128) +(extern constructor f128_copysign f128_copysign) +(type Ieee128 (primitive Ieee128)) + +;;;; `cranelift_codegen::ir::Type` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(extern const $I8 Type) +(extern const $I16 Type) +(extern const $I32 Type) +(extern const $I64 Type) +(extern const $I128 Type) + +(extern const $F16 Type) +(extern const $F32 Type) +(extern const $F64 Type) +(extern const $F128 Type) + +(extern const $I8X8 Type) +(extern const $I8X16 Type) +(extern const $I16X4 Type) +(extern const $I16X8 Type) +(extern const $I32X2 Type) +(extern const $I32X4 Type) +(extern const $I64X2 Type) + +(extern const $F32X4 Type) +(extern const $F64X2 Type) + +(extern const $I32X4XN Type) + +;; Get the unsigned minimum value for a given type. +;; This always zero, but is included for completeness. +(decl pure ty_umin (Type) u64) +(extern constructor ty_umin ty_umin) + +;; Get the unsigned maximum value for a given type. +(decl pure ty_umax (Type) u64) +(extern constructor ty_umax ty_umax) + +;; Get the signed minimum value for a given type. +(decl pure ty_smin (Type) u64) +(extern constructor ty_smin ty_smin) + +;; Get the signed maximum value for a given type. +(decl pure ty_smax (Type) u64) +(extern constructor ty_smax ty_smax) + +;; Get the bit width of a given type. +(spec (ty_bits x) (provide (= result (int2bv 8 x)))) +(decl pure ty_bits (Type) u8) +(extern constructor ty_bits ty_bits) + +;; Get the bit width of a given type. +(spec (ty_bits_u16 x) + (provide (= result (int2bv 16 x)))) +(decl pure ty_bits_u16 (Type) u16) +(extern constructor ty_bits_u16 ty_bits_u16) + +;; Get the bit width of a given type. +(decl pure ty_bits_u64 (Type) u64) +(extern constructor ty_bits_u64 ty_bits_u64) + +;; Get a mask for the width of a given type. +(decl pure ty_mask (Type) u64) +(extern constructor ty_mask ty_mask) + +;; Get a mask that is set for each lane in a given type. +(decl pure ty_lane_mask (Type) u64) +(extern constructor ty_lane_mask ty_lane_mask) + +;; Get the number of lanes for a given type. +(decl pure ty_lane_count (Type) u64) +(extern constructor ty_lane_count ty_lane_count) + +;; Get the byte width of a given type. +(decl pure ty_bytes (Type) u16) +(extern constructor ty_bytes ty_bytes) + +;; Get the type of each lane in the given type. +(decl pure lane_type (Type) Type) +(extern constructor lane_type lane_type) + +;; Get a type with the same element type, but half the number of lanes. +(decl pure partial ty_half_lanes (Type) Type) +(extern constructor ty_half_lanes ty_half_lanes) + +;; Get a type with the same number of lanes but a lane type that is half as small. +(decl pure partial ty_half_width (Type) Type) +(extern constructor ty_half_width ty_half_width) + +;; Generate a mask for the maximum shift amount for a given type. i.e 31 for I32. +(decl pure ty_shift_mask (Type) u64) +(rule (ty_shift_mask ty) (u64_sub (ty_bits (lane_type ty)) 1)) + +;; Compare two types for equality. +(decl pure ty_equal (Type Type) bool) +(extern constructor ty_equal ty_equal) + +;;;; `cranelift_codegen::ir::MemFlags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Provide model for the MemFlags type (declared in generated clif_lower.isle). +(model MemFlags (type (bv 16))) + +;; `MemFlags::trusted` +(spec (mem_flags_trusted) + (provide (= result #x0003))) +(decl pure mem_flags_trusted () MemFlags) +(extern constructor mem_flags_trusted mem_flags_trusted) + +;;;; Helpers for Working with Flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Swap args of an IntCC flag. +(decl intcc_swap_args (IntCC) IntCC) +(extern constructor intcc_swap_args intcc_swap_args) + +;; Complement an IntCC flag. +(decl intcc_complement (IntCC) IntCC) +(extern constructor intcc_complement intcc_complement) + +;; This is a direct import of `IntCC::without_equal`. +;; Get the corresponding IntCC with the equal component removed. +;; For conditions without a zero component, this is a no-op. +(decl pure intcc_without_eq (IntCC) IntCC) +(extern constructor intcc_without_eq intcc_without_eq) + +;; Swap args of a FloatCC flag. +(decl floatcc_swap_args (FloatCC) FloatCC) +(extern constructor floatcc_swap_args floatcc_swap_args) + +;; Complement a FloatCC flag. +(decl floatcc_complement (FloatCC) FloatCC) +(extern constructor floatcc_complement floatcc_complement) + +;; True when this FloatCC involves an unordered comparison. +(decl pure floatcc_unordered (FloatCC) bool) +(extern constructor floatcc_unordered floatcc_unordered) + +;;;; Helper Clif Extractors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl eq (Type Value Value) Value) +(extractor (eq ty x y) (icmp ty (IntCC.Equal) x y)) + +(decl ne (Type Value Value) Value) +(extractor (ne ty x y) (icmp ty (IntCC.NotEqual) x y)) + +(decl ult (Type Value Value) Value) +(extractor (ult ty x y) (icmp ty (IntCC.UnsignedLessThan) x y)) + +(decl ule (Type Value Value) Value) +(extractor (ule ty x y) (icmp ty (IntCC.UnsignedLessThanOrEqual) x y)) + +(decl ugt (Type Value Value) Value) +(extractor (ugt ty x y) (icmp ty (IntCC.UnsignedGreaterThan) x y)) + +(decl uge (Type Value Value) Value) +(extractor (uge ty x y) (icmp ty (IntCC.UnsignedGreaterThanOrEqual) x y)) + +(decl slt (Type Value Value) Value) +(extractor (slt ty x y) (icmp ty (IntCC.SignedLessThan) x y)) + +(decl sle (Type Value Value) Value) +(extractor (sle ty x y) (icmp ty (IntCC.SignedLessThanOrEqual) x y)) + +(decl sgt (Type Value Value) Value) +(extractor (sgt ty x y) (icmp ty (IntCC.SignedGreaterThan) x y)) + +(decl sge (Type Value Value) Value) +(extractor (sge ty x y) (icmp ty (IntCC.SignedGreaterThanOrEqual) x y)) + +;; An extractor that only matches types that can fit in 16 bits. +(spec (fits_in_16 arg) + (provide (= result arg)) + (require (<= arg 16))) +(decl fits_in_16 (Type) Type) +(extern extractor fits_in_16 fits_in_16) + +;; An extractor that only matches types that can fit in 32 bits. +(spec (fits_in_32 arg) + (provide (= result arg)) + (require (<= arg 32))) +(decl fits_in_32 (Type) Type) +(extern extractor fits_in_32 fits_in_32) + +;; An extractor that only matches types that can fit in 32 bits. +(decl lane_fits_in_32 (Type) Type) +(extern extractor lane_fits_in_32 lane_fits_in_32) + +;; An extractor that only matches types that can fit in 64 bits. +(spec (fits_in_64 arg) + (provide (= result arg)) + (require (<= arg 64))) +(decl fits_in_64 (Type) Type) +(extern extractor fits_in_64 fits_in_64) + +;; An extractor that only matches types that fit in exactly 32 bits. +(decl ty_32 (Type) Type) +(extern extractor ty_32 ty_32) + +;; An extractor that only matches types that fit in exactly 64 bits. +(decl ty_64 (Type) Type) +(extern extractor ty_64 ty_64) + +;; A pure constructor/extractor that only matches scalar integers, and +;; references that can fit in 64 bits. +(spec (ty_int_ref_scalar_64 arg) + (provide (= result arg)) + (require (<= arg 64))) +(decl pure partial ty_int_ref_scalar_64 (Type) Type) +(extern constructor ty_int_ref_scalar_64 ty_int_ref_scalar_64) +(extern extractor ty_int_ref_scalar_64 ty_int_ref_scalar_64_extract) + +;; An extractor that matches 32- and 64-bit types only. +(spec (ty_32_or_64 arg) + (provide (= result arg)) + (require (or (= arg 32) (= arg 64)))) +(decl ty_32_or_64 (Type) Type) +(extern extractor ty_32_or_64 ty_32_or_64) + +;; An extractor that matches 8- and 16-bit types only. +(decl ty_8_or_16 (Type) Type) +(extern extractor ty_8_or_16 ty_8_or_16) + +;; An extractor that matches 16- and 32-bit types only. +(decl ty_16_or_32 (Type) Type) +(extern extractor ty_16_or_32 ty_16_or_32) + +;; An extractor that matches int types that fit in 32 bits. +(decl int_fits_in_32 (Type) Type) +(extern extractor int_fits_in_32 int_fits_in_32) + +;; An extractor that matches I64. +(decl ty_int_ref_64 (Type) Type) +(extern extractor ty_int_ref_64 ty_int_ref_64) + +;; An extractor that matches int or reference types bigger than 16 bits but at most 64 bits. +(decl ty_int_ref_16_to_64 (Type) Type) +(extern extractor ty_int_ref_16_to_64 ty_int_ref_16_to_64) + +;; An extractor that only matches integers. +(spec (ty_int a) (provide (= result a))) +(decl ty_int (Type) Type) +(extern extractor ty_int ty_int) + +;; An extractor that only matches scalar types, float or int or ref's. +(decl ty_scalar (Type) Type) +(extern extractor ty_scalar ty_scalar) + +;; An extractor that only matches scalar floating-point types--F32 or F64. +(decl ty_scalar_float (Type) Type) +(extern extractor ty_scalar_float ty_scalar_float) + +;; An extractor that matches scalar floating-point types or vector types. +(decl ty_float_or_vec (Type) Type) +(extern extractor ty_float_or_vec ty_float_or_vec) + +;; A pure constructor that only matches vector floating-point types. +(decl pure partial ty_vector_float (Type) Type) +(extern constructor ty_vector_float ty_vector_float) + +;; A pure constructor that only matches vector types with lanes which +;; are not floating-point. +(decl pure partial ty_vector_not_float (Type) Type) +(extern constructor ty_vector_not_float ty_vector_not_float) + +;; A pure constructor/extractor that only matches 64-bit vector types. +(decl pure partial ty_vec64 (Type) Type) +(extern constructor ty_vec64 ty_vec64_ctor) +(extern extractor ty_vec64 ty_vec64) + +;; An extractor that only matches 128-bit vector types. +(decl ty_vec128 (Type) Type) +(extern extractor ty_vec128 ty_vec128) + +;; An extractor that only matches dynamic vector types with a 64-bit +;; base type. +(decl ty_dyn_vec64 (Type) Type) +(extern extractor ty_dyn_vec64 ty_dyn_vec64) + +;; An extractor that only matches dynamic vector types with a 128-bit +;; base type. +(decl ty_dyn_vec128 (Type) Type) +(extern extractor ty_dyn_vec128 ty_dyn_vec128) + +;; An extractor that only matches 64-bit vector types with integer +;; lanes (I8X8, I16X4, I32X2) +(decl ty_vec64_int (Type) Type) +(extern extractor ty_vec64_int ty_vec64_int) + +;; An extractor that only matches 128-bit vector types with integer +;; lanes (I8X16, I16X8, I32X4, I64X2). +(decl ty_vec128_int (Type) Type) +(extern extractor ty_vec128_int ty_vec128_int) + +;; An extractor that only matches types that can be a 64-bit address. +(decl ty_addr64 (Type) Type) +(extern extractor ty_addr64 ty_addr64) + +;; A pure constructor that matches everything except vectors with size 32X2. +(decl pure partial not_vec32x2 (Type) Type) +(extern constructor not_vec32x2 not_vec32x2) + +;; An extractor that matches everything except I64X2 +(decl not_i64x2 () Type) +(extern extractor not_i64x2 not_i64x2) + +;; Extract a `u8` from an `Uimm8`. +(decl u8_from_uimm8 (u8) Uimm8) +(extern extractor infallible u8_from_uimm8 u8_from_uimm8) + +;; Extract a `u64` from a `bool`. +(decl u64_from_bool (u64) bool) +(extern extractor infallible u64_from_bool u64_from_bool) + +;; Extract a `u64` from an `Imm64`. +(spec (u64_from_imm64 arg) (provide (= arg result))) +(decl u64_from_imm64 (u64) Imm64) +(extern extractor infallible u64_from_imm64 u64_from_imm64) + +;; Extract a `u64` from an `Imm64` which is not zero. +(decl nonzero_u64_from_imm64 (u64) Imm64) +(extern extractor nonzero_u64_from_imm64 nonzero_u64_from_imm64) + +;; If the given `Imm64` is a power-of-two, extract its log2 value. +(decl imm64_power_of_two (u64) Imm64) +(extern extractor imm64_power_of_two imm64_power_of_two) + +;; Create a new Imm64. +(decl pure imm64 (u64) Imm64) +(extern constructor imm64 imm64) + +;; Create a new Imm64, masked to the width of the given type. +(decl pure imm64_masked (Type u64) Imm64) +(extern constructor imm64_masked imm64_masked) + +;; Extract a `u16` from an `Ieee16`. +(decl u16_from_ieee16 (u16) Ieee16) +(extern extractor infallible u16_from_ieee16 u16_from_ieee16) + +;; Extract a `u32` from an `Ieee32`. +(decl u32_from_ieee32 (u32) Ieee32) +(extern extractor infallible u32_from_ieee32 u32_from_ieee32) + +;; Extract a `u64` from an `Ieee64`. +(decl u64_from_ieee64 (u64) Ieee64) +(extern extractor infallible u64_from_ieee64 u64_from_ieee64) + +;; Match a multi-lane type, extracting (# bits per lane, # lanes) from the given +;; type. Will only match when there is more than one lane. +(decl multi_lane (u32 u32) Type) +(extern extractor multi_lane multi_lane) + +;; Match a dynamic-lane type, extracting (# bits per lane) from the given +;; type. +(decl dynamic_lane (u32 u32) Type) +(extern extractor dynamic_lane dynamic_lane) + +;; An extractor that only matches 64-bit dynamic vector types with integer +;; lanes (I8X8XN, I16X4XN, I32X2XN) +(decl ty_dyn64_int (Type) Type) +(extern extractor ty_dyn64_int ty_dyn64_int) + +;; An extractor that only matches 128-bit dynamic vector types with integer +;; lanes (I8X16XN, I16X8XN, I32X4XN, I64X2XN). +(decl ty_dyn128_int (Type) Type) +(extern extractor ty_dyn128_int ty_dyn128_int) + +;; Convert an `Offset32` to a primitive number. +(spec (offset32_to_i32 offset) (provide (= result offset))) +(decl pure offset32_to_i32 (Offset32) i32) +(extern constructor offset32_to_i32 offset32_to_i32) + +;; Convert a number to an `Offset32` +(spec (i32_to_offset32 x) (provide (= result x))) +(decl pure i32_to_offset32 (i32) Offset32) +(extern constructor i32_to_offset32 i32_to_offset32) + +;; This is a direct import of `IntCC::unsigned`. +;; Get the corresponding IntCC with the signed component removed. +;; For conditions without a signed component, this is a no-op. +(decl pure intcc_unsigned (IntCC) IntCC) +(extern constructor intcc_unsigned intcc_unsigned) + +;; Pure constructor that only matches signed integer cond codes. +(spec (signed_cond_code c) + (provide (= result c)) + (require (and (bvuge c #x02) (bvule c #x05)))) +(decl pure partial signed_cond_code (IntCC) IntCC) +(extern constructor signed_cond_code signed_cond_code) + +;;;; Helpers for Working with TrapCode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl pure trap_code_division_by_zero () TrapCode) +(extern constructor trap_code_division_by_zero trap_code_division_by_zero) + +(decl pure trap_code_integer_overflow () TrapCode) +(extern constructor trap_code_integer_overflow trap_code_integer_overflow) + +(decl pure trap_code_bad_conversion_to_integer () TrapCode) +(extern constructor trap_code_bad_conversion_to_integer trap_code_bad_conversion_to_integer) + +;;;; Helpers for tail recursion loops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; A range of integers to loop through. +(type Range (primitive Range)) + +;; Create a new range from `start` through `end` (exclusive). +(decl pure range (usize usize) Range) +(extern constructor range range) + +;; A view on the current state of the range. +(type RangeView extern + (enum + (Empty) + (NonEmpty (index usize) (rest Range)))) + +;; View the current state of the range. +(decl range_view (RangeView) Range) +(extern extractor infallible range_view range_view) + +;; Extractor to test whether a range is empty. +(decl range_empty () Range) +(extractor (range_empty) (range_view (RangeView.Empty))) + +;; Extractor to return the first value in the range, and a sub-range +;; containing the remaining values. +(decl range_unwrap (usize Range) Range) +(extractor (range_unwrap index rest) (range_view (RangeView.NonEmpty index rest))) + +;;;; Automatic conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(convert Offset32 i32 offset32_to_i32) +(convert i32 Offset32 i32_to_offset32) + +;;;; Common Term Signatures ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(form + bv_unary_8_to_64 + ((args (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) +) + +(form + bv_binary_8_to_64 + ((args (bv 8) (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16) (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 32) (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) + +(form + bv_ternary_8_to_64 + ((args (bv 8) (bv 8) (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16) (bv 16) (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 32) (bv 32) (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64) (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) diff --git a/deps/crates/vendor/cranelift-codegen/src/prelude_lower.isle b/deps/crates/vendor/cranelift-codegen/src/prelude_lower.isle new file mode 100644 index 00000000000000..ddf0ee0818114d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/prelude_lower.isle @@ -0,0 +1,1128 @@ +;; Prelude definitions specific to lowering environments (backends) in +;; ISLE. + +;;;; Primitive and External Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `cranelift-entity`-based identifiers. +(type Inst (primitive Inst)) + +;; ISLE representation of `Vec` +(type VecMask extern (enum)) + +(type ValueRegs (primitive ValueRegs)) +(type WritableValueRegs (primitive WritableValueRegs)) + +;; Instruction lowering result: a vector of `ValueRegs`. +(type InstOutput (primitive InstOutput)) +;; (Mutable) builder to incrementally construct an `InstOutput`. +(type InstOutputBuilder extern (enum)) + +;; Type to hold multiple Regs +(type MultiReg + (enum + (Empty) + (One (a Reg)) + (Two (a Reg) (b Reg)) + (Three (a Reg) (b Reg) (c Reg)) + (Four (a Reg) (b Reg) (c Reg) (d Reg)) + )) + +;;;; Registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(model Reg (type (bv))) +(type Reg (primitive Reg)) +(type WritableReg (primitive WritableReg)) +(type OptionWritableReg (primitive OptionWritableReg)) +(type VecReg extern (enum)) +(type VecWritableReg extern (enum)) +(type PReg (primitive PReg)) + +;; Construct a `ValueRegs` of one register. +(spec (value_reg arg) + (provide (= result arg))) +(decl value_reg (Reg) ValueRegs) +(extern constructor value_reg value_reg) + +;; Construct a `WritableValueRegs` of one register. +(decl writable_value_reg (WritableReg) WritableValueRegs) +(extern constructor writable_value_reg writable_value_reg) + +;; Construct a `ValueRegs` of two registers. +(decl value_regs (Reg Reg) ValueRegs) +(extern constructor value_regs value_regs) + +;; Construct a `WritableValueRegs` of two registers. +(decl writable_value_regs (WritableReg WritableReg) WritableValueRegs) +(extern constructor writable_value_regs writable_value_regs) + +;; Construct an empty `ValueRegs` containing only invalid register sentinels. +(decl value_regs_invalid () ValueRegs) +(extern constructor value_regs_invalid value_regs_invalid) + +;; Construct an empty `InstOutput`. +(decl output_none () InstOutput) +(extern constructor output_none output_none) + +;; Construct a single-element `InstOutput`. +(spec (output arg) + (provide (= arg (conv_to (widthof arg) result)))) +(decl output (ValueRegs) InstOutput) +(extern constructor output output) + +;; Construct a two-element `InstOutput`. +(decl output_pair (ValueRegs ValueRegs) InstOutput) +(extern constructor output_pair output_pair) + +;; Construct a single-element `InstOutput` from a single register. +(spec (output_reg arg) + (provide (= result (conv_to (widthof result) arg)))) +(instantiate output_reg + ((args (bv 64)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 64)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 64)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(decl output_reg (Reg) InstOutput) +(rule output_reg (output_reg reg) (output (value_reg reg))) + +;; Construct a single-element `InstOutput` from a value. +(decl output_value (Value) InstOutput) +(rule (output_value val) (output (put_in_regs val))) + +;; Initially empty `InstOutput` builder. +(decl output_builder_new () InstOutputBuilder) +(extern constructor output_builder_new output_builder_new) + +;; Append a `ValueRegs` to an `InstOutput` under construction. +(decl output_builder_push (InstOutputBuilder ValueRegs) Unit) +(extern constructor output_builder_push output_builder_push) + +;; Finish building an `InstOutput` incrementally. +(decl output_builder_finish (InstOutputBuilder) InstOutput) +(extern constructor output_builder_finish output_builder_finish) + +;; Get a temporary register for writing. +(decl temp_writable_reg (Type) WritableReg) +(extern constructor temp_writable_reg temp_writable_reg) + +;; Get a temporary register for reading. +(decl temp_reg (Type) Reg) +(rule (temp_reg ty) + (writable_reg_to_reg (temp_writable_reg ty))) + +(decl is_valid_reg (bool) Reg) +(extern extractor infallible is_valid_reg is_valid_reg) + +;; Get or match the invalid register. +(decl invalid_reg () Reg) +(extern constructor invalid_reg invalid_reg) +(extractor (invalid_reg) (is_valid_reg false)) + +;; Match any register but the invalid register. +(decl valid_reg (Reg) Reg) +(extractor (valid_reg reg) (and (is_valid_reg true) reg)) + +;; Mark this value as used, to ensure that it gets lowered. +(decl mark_value_used (Value) Unit) +(extern constructor mark_value_used mark_value_used) + +;; Put the given value into a register. +;; +;; Asserts that the value fits into a single register, and doesn't require +;; multiple registers for its representation (like `i128` on x64 for example). +;; +;; As a side effect, this marks the value as used. +(spec (put_in_reg arg) + (provide (= result (conv_to 64 arg)))) +(decl put_in_reg (Value) Reg) +(extern constructor put_in_reg put_in_reg) + +;; Put the given value into one or more registers. +;; +;; As a side effect, this marks the value as used. +(spec (put_in_regs arg) (provide (= (conv_to 64 arg) result))) +(decl put_in_regs (Value) ValueRegs) +(extern constructor put_in_regs put_in_regs) + +;; If the given reg is a real register, cause the value in reg to be in a virtual +;; reg, by copying it into a new virtual reg. +(decl ensure_in_vreg (Reg Type) Reg) +(extern constructor ensure_in_vreg ensure_in_vreg) + +;; Get the `n`th register inside a `ValueRegs`. +(spec (value_regs_get arg i) + (provide (= arg result) (= (widthof i) 1))) +(decl value_regs_get (ValueRegs usize) Reg) +(extern constructor value_regs_get value_regs_get) + +;; Get the number of registers in a `ValueRegs`. +(decl pure value_regs_len (ValueRegs) usize) +(extern constructor value_regs_len value_regs_len) + +;; Get a range for the number of regs in a `ValueRegs`. +(decl value_regs_range (ValueRegs) Range) +(rule (value_regs_range regs) (range 0 (value_regs_len regs))) + +;; Put the value into one or more registers and return the first register. +;; +;; Unlike `put_in_reg`, this does not assert that the value fits in a single +;; register. This is useful for things like a `i128` shift amount, where we mask +;; the shift amount to the bit width of the value being shifted, and so the high +;; half of the `i128` won't ever be used. +;; +;; As a side effect, this marks that value as used. +(decl lo_reg (Value) Reg) +(rule (lo_reg val) + (let ((regs ValueRegs (put_in_regs val))) + (value_regs_get regs 0))) + +;; Convert a `PReg` into a `Reg`. +(decl preg_to_reg (PReg) Reg) +(extern constructor preg_to_reg preg_to_reg) + +;; Convert a MultiReg with three registers into an InstOutput containing +;; one ValueRegs containing the first two regs and one containing the third reg +(decl multi_reg_to_pair_and_single (MultiReg) InstOutput) +(rule (multi_reg_to_pair_and_single (MultiReg.Three a b c)) + (output_pair (value_regs a b) c)) + +;; Convert a MultiReg with two registers into an InstOutput containing one ValueRegs with both regs +(decl multi_reg_to_pair (MultiReg) InstOutput) +(rule (multi_reg_to_pair (MultiReg.Two a b)) + (value_regs a b)) + +;; Convert a MultiReg with one register into an InstOutput containing one ValueRegs with the register +(decl multi_reg_to_single (MultiReg) InstOutput) +(rule (multi_reg_to_single (MultiReg.One a)) + (value_reg a)) + +;; Add a range fact to a register, when compiling with +;; proof-carrying-code enabled. +(decl add_range_fact (Reg u16 u64 u64) Reg) +(extern constructor add_range_fact add_range_fact) + +;;;; Common Mach Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(type MachLabel (primitive MachLabel)) +(type ValueLabel (primitive ValueLabel)) +(type UnwindInst (primitive UnwindInst)) +(type ExternalName (primitive ExternalName)) +(type BoxExternalName (primitive BoxExternalName)) +(type RelocDistance (primitive RelocDistance)) +(type VecArgPair extern (enum)) +(type VecRetPair extern (enum)) +(type CallArgList extern (enum)) +(type MachLabelSlice extern (enum)) +(type BoxVecMachLabel extern (enum)) + +;; Extract a the target from a MachLabelSlice with exactly one target. +(decl single_target (MachLabel) MachLabelSlice) +(extern extractor single_target single_target) + +;; Extract a the targets from a MachLabelSlice with exactly two targets. +(decl two_targets (MachLabel MachLabel) MachLabelSlice) +(extern extractor two_targets two_targets) + +;; Extract the default target and jump table from a MachLabelSlice. +(decl jump_table_targets (MachLabel BoxVecMachLabel) MachLabelSlice) +(extern extractor jump_table_targets jump_table_targets) + +;; The size of the jump table. +(decl jump_table_size (BoxVecMachLabel) u32) +(extern constructor jump_table_size jump_table_size) + +;;;; Helper Clif Extractors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extractor to get a `ValueSlice` out of a `ValueList`. +(decl value_list_slice (ValueSlice) ValueList) +(extern extractor infallible value_list_slice value_list_slice) + +;; Extractor to test whether a `ValueSlice` is empty. +(decl value_slice_empty () ValueSlice) +(extern extractor value_slice_empty value_slice_empty) + +;; Extractor to split a `ValueSlice` into its first element plus a tail. +(decl value_slice_unwrap (Value ValueSlice) ValueSlice) +(extern extractor value_slice_unwrap value_slice_unwrap) + +;; Return the length of a `ValueSlice`. +(decl value_slice_len (ValueSlice) usize) +(extern constructor value_slice_len value_slice_len) + +;; Return any element of a `ValueSlice`. +(decl value_slice_get (ValueSlice usize) Value) +(extern constructor value_slice_get value_slice_get) + +;; Extractor to get the first element from a value list, along with its tail as +;; a `ValueSlice`. +(decl unwrap_head_value_list_1 (Value ValueSlice) ValueList) +(extractor (unwrap_head_value_list_1 head tail) + (value_list_slice (value_slice_unwrap head tail))) + +;; Extractor to get the first two elements from a value list, along with its +;; tail as a `ValueSlice`. +(decl unwrap_head_value_list_2 (Value Value ValueSlice) ValueList) +(extractor (unwrap_head_value_list_2 head1 head2 tail) + (value_list_slice (value_slice_unwrap head1 (value_slice_unwrap head2 tail)))) + +;; Turn a `Writable` into a `Reg` via `Writable::to_reg`. +(decl pure writable_reg_to_reg (WritableReg) Reg) +(extern constructor writable_reg_to_reg writable_reg_to_reg) + +;; Extract the result values for the given instruction. +(decl inst_results (ValueSlice) Inst) +(extern extractor infallible inst_results inst_results) + +;; Returns whether the given value is unused in this function and is a dead +;; result. +(decl pure value_is_unused (Value) bool) +(extern constructor value_is_unused value_is_unused) + +;; Extract the first result value of the given instruction. +(decl first_result (Value) Inst) +(extern extractor first_result first_result) + +;; Extract the `InstructionData` for an `Inst`. +(decl inst_data (InstructionData) Inst) +(extern extractor infallible inst_data inst_data) + +;; Extract the type of the instruction's first result. +(decl result_type (Type) Inst) +(extractor (result_type ty) + (first_result (value_type ty))) + +;; Extract the type of the instruction's first result and pass along the +;; instruction as well. +(spec (has_type ty arg) + (provide (= result arg)) + (require (= ty (widthof arg)))) +(decl has_type (Type Inst) Inst) +(extractor (has_type ty inst) + (and (result_type ty) + inst)) + +;; Match the instruction that defines the given value, if any. +(spec (def_inst arg) (provide (= result arg))) +(decl def_inst (Inst) Value) +(extern extractor def_inst def_inst) + +(decl u8_from_iconst (u8) Value) +(extractor (u8_from_iconst x) + (def_inst (iconst (uimm8 x)))) + +(decl u32_from_iconst (u32) Value) +(extractor (u32_from_iconst x) + (u64_from_iconst (u64_as_u32 x))) + +;; Extract a constant `u64` from a value defined by an `iconst`. +(spec (u64_from_iconst arg) (provide (= arg (zero_ext 64 result)))) +(decl u64_from_iconst (u64) Value) +(extractor (u64_from_iconst x) + (def_inst (iconst (u64_from_imm64 x)))) + +(decl i8_from_iconst (i8) Value) +(extractor (i8_from_iconst x) + (i32_from_iconst (i32_as_i8 x))) + +;; Extract a constant `i32` from a value defined by an `iconst`. +;; The value is sign extended to 32 bits. +(spec (i32_from_iconst arg) + (provide (= arg (extract 31 0 (sign_ext 64 result)))) + (require (= result (sign_ext (widthof result) arg)))) +(decl i32_from_iconst (i32) Value) +(extern extractor i32_from_iconst i32_from_iconst) + +;; Extract a constant `i64` from a value defined by an `iconst`. +;; The value is sign extended to 64 bits. +(decl i64_from_iconst (i64) Value) +(extern extractor i64_from_iconst i64_from_iconst) + +;; Match any zero value for iconst, fconst32, fconst64, vconst and splat. +(decl pure partial zero_value (Value) Value) +(extern constructor zero_value zero_value) + +;; Match a sinkable instruction from a value operand. +(decl pure partial is_sinkable_inst (Value) Inst) +(extern constructor is_sinkable_inst is_sinkable_inst) + +;; Match a uextend or any other instruction, "seeing through" the uextend if +;; present. +(decl maybe_uextend (Value) Value) +(extern extractor maybe_uextend maybe_uextend) + +;; Get an unsigned 8-bit immediate in a u8 from an Imm64, if possible. +(spec (uimm8 arg) + (provide (= result (zero_ext 64 arg))) + (require (bvslt result #x0000000000000100) + (= (widthof arg) 8))) +(decl uimm8 (u8) Imm64) +(extern extractor uimm8 uimm8) + +;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Emit an instruction. +;; +;; This is low-level and side-effectful; it should only be used as an +;; implementation detail by helpers that preserve the SSA facade themselves. + +(decl emit (MInst) Unit) +(extern constructor emit emit) + +;; Sink an instruction. +;; +;; This is a side-effectful operation that notifies the context that the +;; instruction has been sunk into another instruction, and no longer needs to +;; be lowered. +(decl sink_inst (Inst) Unit) +(extern constructor sink_inst sink_inst) + +;; Constant pool emission. + +(type VCodeConstant (primitive VCodeConstant)) + +;; Add a u64 little-endian constant to the in-memory constant pool and +;; return a VCodeConstant index that refers to it. This is +;; side-effecting but idempotent (constants are deduplicated). +(decl emit_u64_le_const (u64) VCodeConstant) +(extern constructor emit_u64_le_const emit_u64_le_const) + +;; Add a u128 little-endian constant to the in-memory constant pool and +;; return a VCodeConstant index that refers to it. This is +;; side-effecting but idempotent (constants are deduplicated). +(decl emit_u128_le_const (u128) VCodeConstant) +(extern constructor emit_u128_le_const emit_u128_le_const) + +;; Fetch the VCodeConstant associated with a Constant. +(decl const_to_vconst (Constant) VCodeConstant) +(extern constructor const_to_vconst const_to_vconst) + +;;;; Helpers for Side-Effectful Instructions Without Results ;;;;;;;;;;;;;;;;;;; + +(type SideEffectNoResult (enum + (Inst (inst MInst)) + (Inst2 (inst1 MInst) + (inst2 MInst)) + (Inst3 (inst1 MInst) + (inst2 MInst) + (inst3 MInst)))) + +(model SideEffectNoResult (type Unit)) + +;; Emit given side-effectful instruction. +(decl emit_side_effect (SideEffectNoResult) Unit) +(rule (emit_side_effect (SideEffectNoResult.Inst inst)) + (emit inst)) +(rule (emit_side_effect (SideEffectNoResult.Inst2 inst1 inst2)) + (let ((_ Unit (emit inst1))) + (emit inst2))) +(rule (emit_side_effect (SideEffectNoResult.Inst3 inst1 inst2 inst3)) + (let ((_ Unit (emit inst1)) + (_ Unit (emit inst2))) + (emit inst3))) + +;; Create an empty `InstOutput`, but do emit the given side-effectful +;; instruction. +(decl side_effect (SideEffectNoResult) InstOutput) +(spec (side_effect v) + (provide (= result v))) +(rule (side_effect inst) + (let ((_ Unit (emit_side_effect inst))) + (output_none))) + +(decl side_effect_concat (SideEffectNoResult SideEffectNoResult) SideEffectNoResult) +(rule (side_effect_concat (SideEffectNoResult.Inst inst1) (SideEffectNoResult.Inst inst2)) + (SideEffectNoResult.Inst2 inst1 inst2)) +(rule (side_effect_concat (SideEffectNoResult.Inst inst1) (SideEffectNoResult.Inst2 inst2 inst3)) + (SideEffectNoResult.Inst3 inst1 inst2 inst3)) +(rule (side_effect_concat (SideEffectNoResult.Inst2 inst1 inst2) (SideEffectNoResult.Inst inst3)) + (SideEffectNoResult.Inst3 inst1 inst2 inst3)) + +;;;; Helpers for Working with Flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Newtype wrapper around `MInst` for instructions that are used for their +;; effect on flags. +;; +;; Variant determines how result is given when combined with a +;; ConsumesFlags. See `with_flags` below for more. +(type ProducesFlags (enum + ;; For cases where the flags have been produced by another + ;; instruction, and we have out-of-band reasons to know + ;; that they won't be clobbered by the time we depend on + ;; them. + (AlreadyExistingFlags) + (ProducesFlagsSideEffect (inst MInst)) + (ProducesFlagsTwiceSideEffect (inst1 MInst) (inst2 MInst)) + ;; Not directly combinable with a ConsumesFlags; + ;; used in s390x and unwrapped directly by `trapif`. + (ProducesFlagsReturnsReg (inst MInst) (result Reg)) + (ProducesFlagsReturnsResultWithConsumer (inst MInst) (result Reg)))) + +;; Chain another producer to a `ProducesFlags`. +(decl produces_flags_concat (ProducesFlags ProducesFlags) ProducesFlags) +(rule (produces_flags_concat (ProducesFlags.ProducesFlagsSideEffect inst1) (ProducesFlags.ProducesFlagsSideEffect inst2)) + (ProducesFlags.ProducesFlagsTwiceSideEffect inst1 inst2)) + +;; Newtype wrapper around `MInst` for instructions that consume and produce flags +(type ConsumesAndProducesFlags (enum + (SideEffect (inst MInst)) + (ReturnsReg (inst MInst) (result Reg)))) + +;; Newtype wrapper around `MInst` for instructions that consume flags. +;; +;; Variant determines how result is given when combined with a +;; ProducesFlags. See `with_flags` below for more. +(type ConsumesFlags (enum + (ConsumesFlagsSideEffect (inst MInst)) + (ConsumesFlagsSideEffect2 (inst1 MInst) (inst2 MInst)) + (ConsumesFlagsReturnsResultWithProducer (inst MInst) (result Reg)) + (ConsumesFlagsReturnsReg (inst MInst) (result Reg)) + (ConsumesFlagsTwiceReturnsValueRegs (inst1 MInst) + (inst2 MInst) + (result ValueRegs)) + (ConsumesFlagsFourTimesReturnsValueRegs (inst1 MInst) + (inst2 MInst) + (inst3 MInst) + (inst4 MInst) + (result ValueRegs)))) + + + +;; Get the produced register out of a ProducesFlags. +(decl produces_flags_get_reg (ProducesFlags) Reg) +(rule (produces_flags_get_reg (ProducesFlags.ProducesFlagsReturnsReg _ reg)) reg) +(rule (produces_flags_get_reg (ProducesFlags.ProducesFlagsReturnsResultWithConsumer _ reg)) reg) + +;; Modify a ProducesFlags to use it only for its side-effect, ignoring +;; its result. +(decl produces_flags_ignore (ProducesFlags) ProducesFlags) +(rule (produces_flags_ignore (ProducesFlags.ProducesFlagsReturnsReg inst _)) + (ProducesFlags.ProducesFlagsSideEffect inst)) +(rule (produces_flags_ignore (ProducesFlags.ProducesFlagsReturnsResultWithConsumer inst _)) + (ProducesFlags.ProducesFlagsSideEffect inst)) + +;; Helper for combining two flags-consumer instructions that return a +;; single Reg, giving a ConsumesFlags that returns both values in a +;; ValueRegs. +(decl consumes_flags_concat (ConsumesFlags ConsumesFlags) ConsumesFlags) +(rule (consumes_flags_concat (ConsumesFlags.ConsumesFlagsReturnsReg inst1 reg1) + (ConsumesFlags.ConsumesFlagsReturnsReg inst2 reg2)) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs + inst1 + inst2 + (value_regs reg1 reg2))) +(rule (consumes_flags_concat + (ConsumesFlags.ConsumesFlagsSideEffect inst1) + (ConsumesFlags.ConsumesFlagsSideEffect inst2)) + (ConsumesFlags.ConsumesFlagsSideEffect2 inst1 inst2)) + +;; Combine flags-producing and -consuming instructions together, ensuring that +;; they are emitted back-to-back and no other instructions can be emitted +;; between them and potentially clobber the flags. +;; +;; Returns a `ValueRegs` according to the specific combination of ProducesFlags and ConsumesFlags modes: +;; - SideEffect + ReturnsReg --> ValueReg with one Reg from consumer +;; - SideEffect + ReturnsValueRegs --> ValueReg as given from consumer +;; - ReturnsResultWithProducer + ReturnsResultWithConsumer --> ValueReg with low part from producer, high part from consumer +;; +;; See `with_flags_reg` below for a variant that extracts out just the lower Reg. +(decl with_flags (ProducesFlags ConsumesFlags) ValueRegs) + +(rule (with_flags (ProducesFlags.ProducesFlagsReturnsResultWithConsumer producer_inst producer_result) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer consumer_inst consumer_result)) + (let ((_x Unit (emit producer_inst)) + (_y Unit (emit consumer_inst))) + (value_regs producer_result consumer_result))) + +;; A flag-producer that also produces a result, paired with a consumer that has +;; no results. +(rule (with_flags (ProducesFlags.ProducesFlagsReturnsResultWithConsumer producer_inst producer_result) + (ConsumesFlags.ConsumesFlagsSideEffect consumer_inst)) + (let ((_ Unit (emit producer_inst)) + (_ Unit (emit consumer_inst))) + (value_reg producer_result))) + +(rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) + (ConsumesFlags.ConsumesFlagsReturnsReg consumer_inst consumer_result)) + (let ((_x Unit (emit producer_inst)) + (_y Unit (emit consumer_inst))) + (value_reg consumer_result))) + +(rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consumer_inst_1 + consumer_inst_2 + consumer_result)) + ;; We must emit these instructions in order as the creator of + ;; the ConsumesFlags may be relying on dataflow dependencies + ;; amongst them. + (let ((_x Unit (emit producer_inst)) + (_y Unit (emit consumer_inst_1)) + (_z Unit (emit consumer_inst_2))) + consumer_result)) + +(rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consumer_inst_1 + consumer_inst_2 + consumer_inst_3 + consumer_inst_4 + consumer_result)) + ;; We must emit these instructions in order as the creator of + ;; the ConsumesFlags may be relying on dataflow dependencies + ;; amongst them. + (let ((_x Unit (emit producer_inst)) + (_y Unit (emit consumer_inst_1)) + (_z Unit (emit consumer_inst_2)) + (_w Unit (emit consumer_inst_3)) + (_v Unit (emit consumer_inst_4))) + consumer_result)) + +(rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) + (ConsumesFlags.ConsumesFlagsReturnsReg consumer_inst consumer_result)) + (let ((_ Unit (emit producer_inst1)) + (_ Unit (emit producer_inst2)) + (_ Unit (emit consumer_inst))) + (value_reg consumer_result))) + +(rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consumer_inst_1 + consumer_inst_2 + consumer_result)) + ;; We must emit these instructions in order as the creator of + ;; the ConsumesFlags may be relying on dataflow dependencies + ;; amongst them. + (let ((_ Unit (emit producer_inst1)) + (_ Unit (emit producer_inst2)) + (_ Unit (emit consumer_inst_1)) + (_ Unit (emit consumer_inst_2))) + consumer_result)) + +(rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consumer_inst_1 + consumer_inst_2 + consumer_inst_3 + consumer_inst_4 + consumer_result)) + ;; We must emit these instructions in order as the creator of + ;; the ConsumesFlags may be relying on dataflow dependencies + ;; amongst them. + (let ((_ Unit (emit producer_inst1)) + (_ Unit (emit producer_inst2)) + (_ Unit (emit consumer_inst_1)) + (_ Unit (emit consumer_inst_2)) + (_ Unit (emit consumer_inst_3)) + (_ Unit (emit consumer_inst_4))) + consumer_result)) + +(decl with_flags_reg (ProducesFlags ConsumesFlags) Reg) +(rule (with_flags_reg p c) + (let ((v ValueRegs (with_flags p c))) + (value_regs_get v 0))) + +;; Indicate that the current state of the flags register from the instruction +;; that produces this Value is relied on. +(decl flags_to_producesflags (Value) ProducesFlags) +(rule (flags_to_producesflags val) + (let ((_ Unit (mark_value_used val))) + (ProducesFlags.AlreadyExistingFlags))) + +;; Combine a flags-producing instruction and a flags-consuming instruction that +;; produces no results. +;; +;; This function handles the following case only: +;; - ProducesFlagsSideEffect + ConsumesFlagsSideEffect +(decl with_flags_side_effect (ProducesFlags ConsumesFlags) SideEffectNoResult) + +(rule (with_flags_side_effect + (ProducesFlags.AlreadyExistingFlags) + (ConsumesFlags.ConsumesFlagsSideEffect c)) + (SideEffectNoResult.Inst c)) + +(rule (with_flags_side_effect + (ProducesFlags.AlreadyExistingFlags) + (ConsumesFlags.ConsumesFlagsSideEffect2 c1 c2)) + (SideEffectNoResult.Inst2 c1 c2)) + +(rule (with_flags_side_effect + (ProducesFlags.ProducesFlagsSideEffect p) + (ConsumesFlags.ConsumesFlagsSideEffect c)) + (SideEffectNoResult.Inst2 p c)) + +(rule (with_flags_side_effect + (ProducesFlags.ProducesFlagsSideEffect p) + (ConsumesFlags.ConsumesFlagsSideEffect2 c1 c2)) + (SideEffectNoResult.Inst3 p c1 c2)) + +(rule (with_flags_side_effect + (ProducesFlags.ProducesFlagsTwiceSideEffect p1 p2) + (ConsumesFlags.ConsumesFlagsSideEffect c)) + (SideEffectNoResult.Inst3 p1 p2 c)) + +;; Combine flag-producing and -consuming instruction that allows more than two results to be returned +(decl with_flags_chained (ProducesFlags ConsumesAndProducesFlags ConsumesFlags) MultiReg) + +;; ProducesFlags.SideEffect + ConsumesAndProducesFlags.SideEffect with all possible ConsumeFlags options +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsSideEffect consume_inst)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Empty))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsSideEffect2 consume_inst1 consume_inst2)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Empty))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsReturnsReg consume_inst reg)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.One reg))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consume_inst1 consume_inst2 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Two (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consume_inst1 consume_inst2 consume_inst3 consume_inst4 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2)) + (_ Unit (emit consume_inst3)) + (_ Unit (emit consume_inst4))) + (MultiReg.Two (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + + +;; ProducesFlags.ReturnsReg + ConsumesAndProducesFlags.SideEffect with all possible ConsumeFlags options +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsSideEffect consume_inst)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.One prod_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsSideEffect2 consume_inst1 consume_inst2)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.One prod_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsReturnsReg consume_inst consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Two prod_result consume_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consume_inst1 consume_inst2 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Three prod_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.SideEffect middle_inst) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consume_inst1 consume_inst2 consume_inst3 consume_inst4 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2)) + (_ Unit (emit consume_inst3)) + (_ Unit (emit consume_inst4))) + (MultiReg.Three prod_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + + +;; ProducesFlags.SideEffect + ConsumesAndProducesFlags.ReturnsReg with all possible ConsumeFlags options +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect consume_inst)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.One middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect2 consume_inst1 consume_inst2)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.One middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsReturnsReg consume_inst consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Two middle_result consume_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consume_inst1 consume_inst2 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Three middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsSideEffect prod_inst) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consume_inst1 consume_inst2 consume_inst3 consume_inst4 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2)) + (_ Unit (emit consume_inst3)) + (_ Unit (emit consume_inst4))) + (MultiReg.Three middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + + +;; ProducesFlags.ReturnsReg + ConsumesAndProducesFlags.ReturnsReg with all possible ConsumeFlags options +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect consume_inst)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Two prod_result middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect2 consume_inst1 consume_inst2)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Two prod_result middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsReturnsReg consume_inst consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Three prod_result middle_result consume_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consume_inst1 consume_inst2 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Four prod_result middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsReg prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consume_inst1 consume_inst2 consume_inst3 consume_inst4 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2)) + (_ Unit (emit consume_inst3)) + (_ Unit (emit consume_inst4))) + (MultiReg.Four prod_result middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +;; ProducesFlags.ReturnsResultWithConsumer + ConsumesAndProducesFlags.ReturnsReg with all possible ConsumeFlags options +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect consume_inst)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Two prod_result middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsSideEffect2 consume_inst1 consume_inst2)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Two prod_result middle_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsReturnsReg consume_inst consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Three prod_result middle_result consume_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer consume_inst consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst))) + (MultiReg.Three prod_result middle_result consume_result))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consume_inst1 consume_inst2 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2))) + (MultiReg.Four prod_result middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +(rule (with_flags_chained (ProducesFlags.ProducesFlagsReturnsResultWithConsumer prod_inst prod_result) + (ConsumesAndProducesFlags.ReturnsReg middle_inst middle_result) + (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consume_inst1 consume_inst2 consume_inst3 consume_inst4 consume_result)) + (let ((_ Unit (emit prod_inst)) + (_ Unit (emit middle_inst)) + (_ Unit (emit consume_inst1)) + (_ Unit (emit consume_inst2)) + (_ Unit (emit consume_inst3)) + (_ Unit (emit consume_inst4))) + (MultiReg.Four prod_result middle_result (value_regs_get consume_result 0) (value_regs_get consume_result 1)))) + +;;;; Helpers for accessing compilation flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This definition should be kept up to date with the values defined in +;; cranelift/codegen/meta/src/shared/settings.rs +(type TlsModel extern (enum (None) (ElfGd) (Macho) (Coff))) + +(decl tls_model (TlsModel) Type) +(extern extractor infallible tls_model tls_model) + +(decl pure partial tls_model_is_elf_gd () Unit) +(extern constructor tls_model_is_elf_gd tls_model_is_elf_gd) + +(decl pure partial tls_model_is_macho () Unit) +(extern constructor tls_model_is_macho tls_model_is_macho) + +(decl pure partial tls_model_is_coff () Unit) +(extern constructor tls_model_is_coff tls_model_is_coff) + +(decl pure partial preserve_frame_pointers () Unit) +(extern constructor preserve_frame_pointers preserve_frame_pointers) + +;; This definition should be kept up to date with the values defined in +;; cranelift/codegen/meta/src/shared/settings.rs +(type StackSwitchModel extern (enum (None) (Basic) (UpdateWindowsTib))) + +(decl pure partial stack_switch_model () StackSwitchModel) +(extern constructor stack_switch_model stack_switch_model) + +;;;; Helpers for accessing instruction data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl box_external_name (ExternalName) BoxExternalName) +(extern constructor box_external_name box_external_name) + +;; Accessor for `FuncRef`. + +(decl func_ref_data (SigRef ExternalName RelocDistance) FuncRef) +(extern extractor infallible func_ref_data func_ref_data) + +;; Accessor for `GlobalValue`. + +(decl symbol_value_data (ExternalName RelocDistance i64) GlobalValue) +(extern extractor symbol_value_data symbol_value_data) + +;; Accessor for `RelocDistance`. + +(decl reloc_distance_near () RelocDistance) +(extern extractor reloc_distance_near reloc_distance_near) + +;; Accessor for `Immediate` as a vector of u8 values. + +(decl vec_mask_from_immediate (VecMask) Immediate) +(extern extractor vec_mask_from_immediate vec_mask_from_immediate) + +;; Accessor for `Immediate` as u128. + +(decl u128_from_immediate (u128) Immediate) +(extern extractor u128_from_immediate u128_from_immediate) + +;; Extracts an `Immediate` as a `VCodeConstant`. + +(decl vconst_from_immediate (VCodeConstant) Immediate) +(extern extractor vconst_from_immediate vconst_from_immediate) + +;; Accessor for `Constant` as u128. + +(decl u128_from_constant (u128) Constant) +(extern extractor u128_from_constant u128_from_constant) + +;; Accessor for `Constant` as u64. + +(decl u64_from_constant (u64) Constant) +(extern extractor u64_from_constant u64_from_constant) + +;; Extracts lane indices, represented as u8's, if the immediate for a +;; `shuffle` instruction represents shuffling N-bit values. The u8 values +;; returned will be in the range of 0 to (256/N)-1, inclusive, and index the +;; N-bit chunks of two concatenated 128-bit vectors starting from the +;; least-significant bits. +(decl shuffle64_from_imm (u8 u8) Immediate) +(extern extractor shuffle64_from_imm shuffle64_from_imm) +(decl shuffle32_from_imm (u8 u8 u8 u8) Immediate) +(extern extractor shuffle32_from_imm shuffle32_from_imm) +(decl shuffle16_from_imm (u8 u8 u8 u8 u8 u8 u8 u8) Immediate) +(extern extractor shuffle16_from_imm shuffle16_from_imm) + +;;;; Helpers for generating returns ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extractor to check for the special case that a `WritableValueRegs` +;; contains only a single register. +(decl only_writable_reg (WritableReg) WritableValueRegs) +(extern extractor only_writable_reg only_writable_reg) + +;; Get the `n`th register inside a `WritableValueRegs`. +(decl writable_regs_get (WritableValueRegs usize) WritableReg) +(extern constructor writable_regs_get writable_regs_get) + +;;;; Helpers for generating calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Type to hold information about a function call signature. +(type Sig (primitive Sig)) + +;; Information how to pass one argument or return value. +(type ABIArg extern (enum)) + +;; Information how to pass a single slot of one argument or return value. +(type ABIArgSlot extern + (enum + (Reg + (reg RealReg) + (ty Type) + (extension ArgumentExtension)) + (Stack + (offset i64) + (ty Type) + (extension ArgumentExtension)))) + +;; Physical register that may hold an argument or return value. +(type RealReg (primitive RealReg)) + +;; Instruction on whether and how to extend an argument value. +(model ArgumentExtension + (enum + (None) + (Uext) + (Sext))) +(type ArgumentExtension extern + (enum + (None) + (Uext) + (Sext))) + +;; Get the number of arguments expected. +(decl abi_num_args (Sig) usize) +(extern constructor abi_num_args abi_num_args) + +;; Get information specifying how to pass one argument. +(decl abi_get_arg (Sig usize) ABIArg) +(extern constructor abi_get_arg abi_get_arg) + +;; Get the number of return values expected. +(decl abi_num_rets (Sig) usize) +(extern constructor abi_num_rets abi_num_rets) + +;; Get information specifying how to pass one return value. +(decl abi_get_ret (Sig usize) ABIArg) +(extern constructor abi_get_ret abi_get_ret) + +;; Get information specifying how to pass the implicit pointer +;; to the return-value area on the stack, if required. +(decl abi_ret_arg (ABIArg) Sig) +(extern extractor abi_ret_arg abi_ret_arg) + +;; Succeeds if no implicit return-value area pointer is required. +(decl abi_no_ret_arg () Sig) +(extern extractor abi_no_ret_arg abi_no_ret_arg) + +;; Incoming return area pointer (must be present). +(decl abi_unwrap_ret_area_ptr () Reg) +(extern constructor abi_unwrap_ret_area_ptr abi_unwrap_ret_area_ptr) + +;; StackSlot addr +(decl abi_stackslot_addr (WritableReg StackSlot Offset32) MInst) +(extern constructor abi_stackslot_addr abi_stackslot_addr) + +;; DynamicStackSlot addr +(decl abi_dynamic_stackslot_addr (WritableReg DynamicStackSlot) MInst) +(extern constructor abi_dynamic_stackslot_addr abi_dynamic_stackslot_addr) + +;; Extractor to detect the special case where an argument or +;; return value only requires a single slot to be passed. +(decl abi_arg_only_slot (ABIArgSlot) ABIArg) +(extern extractor abi_arg_only_slot abi_arg_only_slot) + +;; Extractor to detect the special case where a non-struct argument +;; is implicitly passed by reference using a hidden pointer. +(decl abi_arg_implicit_pointer (ABIArgSlot i64 Type) ABIArg) +(extern extractor abi_arg_implicit_pointer abi_arg_implicit_pointer) + +;; Convert a real register number into a virtual register. +(decl real_reg_to_reg (RealReg) Reg) +(extern constructor real_reg_to_reg real_reg_to_reg) + +;; Convert a real register number into a writable virtual register. +(decl real_reg_to_writable_reg (RealReg) WritableReg) +(extern constructor real_reg_to_writable_reg real_reg_to_writable_reg) + +;; Generate a move between two registers. +(decl gen_move (Type WritableReg Reg) MInst) +(extern constructor gen_move gen_move) + +;; Generate a return instruction +(decl lower_return (ValueSlice) InstOutput) +(rule (lower_return vals) + (let ((_ Unit (gen_return vals))) + (output_none))) + +(decl gen_return (ValueSlice) Unit) +(extern constructor gen_return gen_return) + +(decl gen_return_call (SigRef ExternalName RelocDistance ValueSlice) InstOutput) +(extern constructor gen_return_call gen_return_call) + +(decl gen_return_call_indirect (SigRef Value ValueSlice) InstOutput) +(extern constructor gen_return_call_indirect gen_return_call_indirect) + +;; Helper for extracting an immediate that's not 0 and not -1 from an imm64. + (spec (safe_divisor_from_imm64 t x) + (provide (= (sign_ext 64 x) result)) + (require (not (= #x0000000000000000 result)) + (not (= #x1111111111111111 result)))) +(decl pure partial safe_divisor_from_imm64 (Type Imm64) u64) +(extern constructor safe_divisor_from_imm64 safe_divisor_from_imm64) + +;;;; Automatic conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(convert Inst Value def_inst) +(convert Reg ValueRegs value_reg) +(convert WritableReg WritableValueRegs writable_value_reg) +(convert Value Reg put_in_reg) +(convert Value ValueRegs put_in_regs) +(convert WritableReg Reg writable_reg_to_reg) +(convert ValueRegs InstOutput output) +(convert Reg InstOutput output_reg) +(convert Value InstOutput output_value) +(convert ExternalName BoxExternalName box_external_name) +(convert PReg Reg preg_to_reg) diff --git a/deps/crates/vendor/cranelift-codegen/src/prelude_opt.isle b/deps/crates/vendor/cranelift-codegen/src/prelude_opt.isle new file mode 100644 index 00000000000000..56c2fc244147f5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/prelude_opt.isle @@ -0,0 +1,122 @@ +;; Prelude definitions specific to the mid-end. + +;; Any `extern` definitions here are generally implemented in `src/opts.rs`. + +;;;;; eclass and enode access ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Extract any node(s) for the given eclass ID. +(decl multi inst_data (Type InstructionData) Value) +(extern extractor inst_data inst_data_etor) + +;; Identical to `inst_data`, just with a different ISLE type. +;; This is basically a manual version of `curry`/`uncurry` in Haskell: +;; to compose extractors the outer one needs to be single-parameter, +;; so this combines the two parameters of `inst_data` into one. +(type TypeAndInstructionData (primitive TypeAndInstructionData)) +(decl multi inst_data_tupled (TypeAndInstructionData) Value) +(extern extractor inst_data_tupled inst_data_tupled_etor) + +;; Construct a pure node, returning a new (or deduplicated +;; already-existing) eclass ID. +(decl make_inst (Type InstructionData) Value) +(extern constructor make_inst make_inst_ctor) + +;; Constructors for value arrays. +(decl value_array_2_ctor (Value Value) ValueArray2) +(extern constructor value_array_2_ctor value_array_2_ctor) +(decl value_array_3_ctor (Value Value Value) ValueArray3) +(extern constructor value_array_3_ctor value_array_3_ctor) + +(rule (eq ty x y) (icmp ty (IntCC.Equal) x y)) +(rule (ne ty x y) (icmp ty (IntCC.NotEqual) x y)) +(rule (ult ty x y) (icmp ty (IntCC.UnsignedLessThan) x y)) +(rule (ule ty x y) (icmp ty (IntCC.UnsignedLessThanOrEqual) x y)) +(rule (ugt ty x y) (icmp ty (IntCC.UnsignedGreaterThan) x y)) +(rule (uge ty x y) (icmp ty (IntCC.UnsignedGreaterThanOrEqual) x y)) +(rule (slt ty x y) (icmp ty (IntCC.SignedLessThan) x y)) +(rule (sle ty x y) (icmp ty (IntCC.SignedLessThanOrEqual) x y)) +(rule (sgt ty x y) (icmp ty (IntCC.SignedGreaterThan) x y)) +(rule (sge ty x y) (icmp ty (IntCC.SignedGreaterThanOrEqual) x y)) + +;; 3-way comparison, returning -1/0/+1 in I8 +(decl spaceship_s (Type Value Value) Value) +(rule (spaceship_s ty x y) (isub $I8 (sgt ty x y) (slt ty x y))) +(extractor (spaceship_s ty x y) (isub $I8 (sgt ty x y) (slt ty x y))) +(decl spaceship_u (Type Value Value) Value) +(rule (spaceship_u ty x y) (isub $I8 (ugt ty x y) (ult ty x y))) +(extractor (spaceship_u ty x y) (isub $I8 (ugt ty x y) (ult ty x y))) + +;;;;; optimization toplevel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The main matcher rule invoked by the toplevel driver. +(decl multi simplify (Value) Value) + +;; Mark a node as requiring remat when used in a different block. +(decl remat (Value) Value) +(extern constructor remat remat) + +;; Mark a node as subsuming whatever else it's rewritten from -- this +;; is definitely preferable, not just a possible option. Useful for, +;; e.g., constant propagation where we arrive at a definite "final +;; answer". +(decl subsume (Value) Value) +(extern constructor subsume subsume) + +;;;;; constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(decl iconst_sextend_etor (Type i64) TypeAndInstructionData) +(extern extractor iconst_sextend_etor iconst_sextend_etor) + +;; Construct an `iconst` from an `i64` or Extract an `i64` from an `iconst` +;; by treating the constant as signed. +;; When extracting, smaller types get their value sign-extended to 64-bits, +;; so that `iconst.i8 255` will give you a `-1_i64`. +;; When constructing, the rule will fail if the value cannot be represented in +;; the target type. If it fits, it'll be masked accordingly in the constant. +(decl iconst_s (Type i64) Value) +(extractor (iconst_s ty c) (inst_data_tupled (iconst_sextend_etor ty c))) +(rule 0 (iconst_s ty c) + (if-let c_masked (u64_and (i64_as_u64 c) (ty_umax ty))) + (if-let c_reextended (i64_sextend_u64 ty c_masked)) + (if-let true (u64_eq (i64_as_u64 c) (i64_as_u64 c_reextended))) + (iconst ty (imm64 c_masked))) +(rule 1 (iconst_s $I128 c) (sextend $I128 (iconst_s $I64 c))) + +;; Construct an `iconst` from a `u64` or Extract a `u64` from an `iconst` +;; by treating the constant as unsigned. +;; When extracting, smaller types get their value zero-extended to 64-bits, +;; so that `iconst.i8 255` will give you a `255_u64`. +;; When constructing, the rule will fail if the value cannot be represented in +;; the target type. +(decl iconst_u (Type u64) Value) +(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c))) +(rule 0 (iconst_u ty c) + (if-let true (u64_le c (ty_umax ty))) + (iconst ty (imm64 c))) +(rule 1 (iconst_u $I128 c) (uextend $I128 (iconst_u $I64 c))) + +;; These take `Value`, rather than going through `inst_data_tupled`, because +;; most of the time they want to return the original `Value`, and it would be +;; a waste to need to re-GVN the instruction data in those cases. +(decl multi sextend_maybe_etor (Type Value) Value) +(extern extractor infallible sextend_maybe_etor sextend_maybe_etor) +(decl multi uextend_maybe_etor (Type Value) Value) +(extern extractor infallible uextend_maybe_etor uextend_maybe_etor) + +;; Match or Construct a possibly-`uextend`ed value. +;; Gives the extended-to type and inner value when matching something that was +;; extended, or the input value and its type when the value isn't an extension. +;; Useful to write a single pattern that can match things that may or may not +;; have undergone C's "usual arithmetic conversions". +;; When generating values, extending to the same type is invalid CLIF, +;; so this avoids doing that where there's no extension actually needed. +(decl uextend_maybe (Type Value) Value) +(extractor (uextend_maybe ty val) (uextend_maybe_etor ty val)) +(rule 0 (uextend_maybe ty val) (uextend ty val)) +(rule 1 (uextend_maybe ty val@(value_type ty)) val) + +;; Same as `uextend_maybe` above, just for `sextend`. +(decl sextend_maybe (Type Value) Value) +(extractor (sextend_maybe ty val) (sextend_maybe_etor ty val)) +(rule 0 (sextend_maybe ty val) (sextend ty val)) +(rule 1 (sextend_maybe ty val@(value_type ty)) val) diff --git a/deps/crates/vendor/cranelift-codegen/src/print_errors.rs b/deps/crates/vendor/cranelift-codegen/src/print_errors.rs new file mode 100644 index 00000000000000..23195bf88f7a3a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/print_errors.rs @@ -0,0 +1,223 @@ +//! Utility routines for pretty-printing error messages. + +use crate::entity::SecondaryMap; +use crate::ir; +use crate::ir::entities::{AnyEntity, Block, Inst, Value}; +use crate::ir::function::Function; +use crate::ir::pcc::Fact; +use crate::result::CodegenError; +use crate::verifier::{VerifierError, VerifierErrors}; +use crate::write::{decorate_function, FuncWriter, PlainWriter}; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::fmt; +use core::fmt::Write; + +/// Pretty-print a verifier error. +pub fn pretty_verifier_error<'a>( + func: &ir::Function, + func_w: Option>, + errors: VerifierErrors, +) -> String { + let mut errors = errors.0; + let mut w = String::new(); + let num_errors = errors.len(); + + decorate_function( + &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors), + &mut w, + func, + ) + .unwrap(); + + writeln!( + w, + "\n; {} verifier error{} detected (see above). Compilation aborted.", + num_errors, + if num_errors == 1 { "" } else { "s" } + ) + .unwrap(); + + w +} + +struct PrettyVerifierError<'a>(Box, &'a mut Vec); + +impl<'a> FuncWriter for PrettyVerifierError<'a> { + fn write_block_header( + &mut self, + w: &mut dyn Write, + func: &Function, + block: Block, + indent: usize, + ) -> fmt::Result { + pretty_block_header_error(w, func, block, indent, &mut *self.0, self.1) + } + + fn write_instruction( + &mut self, + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + inst: Inst, + indent: usize, + ) -> fmt::Result { + pretty_instruction_error(w, func, aliases, inst, indent, &mut *self.0, self.1) + } + + fn write_entity_definition( + &mut self, + w: &mut dyn Write, + func: &Function, + entity: AnyEntity, + value: &dyn fmt::Display, + maybe_fact: Option<&Fact>, + ) -> fmt::Result { + pretty_preamble_error(w, func, entity, value, maybe_fact, &mut *self.0, self.1) + } +} + +/// Pretty-print a function verifier error for a given block. +fn pretty_block_header_error( + w: &mut dyn Write, + func: &Function, + cur_block: Block, + indent: usize, + func_w: &mut dyn FuncWriter, + errors: &mut Vec, +) -> fmt::Result { + let mut s = String::new(); + func_w.write_block_header(&mut s, func, cur_block, indent)?; + write!(w, "{s}")?; + + // TODO: Use drain_filter here when it gets stabilized + let mut i = 0; + let mut printed_error = false; + while i != errors.len() { + match errors[i].location { + ir::entities::AnyEntity::Block(block) if block == cur_block => { + if !printed_error { + print_arrow(w, &s)?; + printed_error = true; + } + let err = errors.remove(i); + print_error(w, err)?; + } + _ => i += 1, + } + } + + if printed_error { + w.write_char('\n')?; + } + + Ok(()) +} + +/// Pretty-print a function verifier error for a given instruction. +fn pretty_instruction_error( + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + cur_inst: Inst, + indent: usize, + func_w: &mut dyn FuncWriter, + errors: &mut Vec, +) -> fmt::Result { + let mut s = String::new(); + func_w.write_instruction(&mut s, func, aliases, cur_inst, indent)?; + write!(w, "{s}")?; + + // TODO: Use drain_filter here when it gets stabilized + let mut i = 0; + let mut printed_error = false; + while i != errors.len() { + match errors[i].location { + ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => { + if !printed_error { + print_arrow(w, &s)?; + printed_error = true; + } + let err = errors.remove(i); + print_error(w, err)?; + } + _ => i += 1, + } + } + + if printed_error { + w.write_char('\n')?; + } + + Ok(()) +} + +fn pretty_preamble_error( + w: &mut dyn Write, + func: &Function, + entity: AnyEntity, + value: &dyn fmt::Display, + maybe_fact: Option<&Fact>, + func_w: &mut dyn FuncWriter, + errors: &mut Vec, +) -> fmt::Result { + let mut s = String::new(); + func_w.write_entity_definition(&mut s, func, entity, value, maybe_fact)?; + write!(w, "{s}")?; + + // TODO: Use drain_filter here when it gets stabilized + let mut i = 0; + let mut printed_error = false; + while i != errors.len() { + if entity == errors[i].location { + if !printed_error { + print_arrow(w, &s)?; + printed_error = true; + } + let err = errors.remove(i); + print_error(w, err)?; + } else { + i += 1 + } + } + + if printed_error { + w.write_char('\n')?; + } + + Ok(()) +} + +/// Prints: +/// ; ^~~~~~ +fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result { + write!(w, ";")?; + + let indent = entity.len() - entity.trim_start().len(); + if indent != 0 { + write!(w, "{1:0$}^", indent - 1, "")?; + } + + for _ in 0..entity.trim().len() - 1 { + write!(w, "~")?; + } + + writeln!(w) +} + +/// Prints: +/// ; error: [ERROR BODY] +fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result { + writeln!(w, "; error: {}", err.to_string())?; + Ok(()) +} + +/// Pretty-print a Cranelift error. +pub fn pretty_error(func: &ir::Function, err: CodegenError) -> String { + if let CodegenError::Verifier(e) = err { + pretty_verifier_error(func, None, e) + } else { + err.to_string() + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/ranges.rs b/deps/crates/vendor/cranelift-codegen/src/ranges.rs new file mode 100644 index 00000000000000..419dee83c08f1a --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/ranges.rs @@ -0,0 +1,131 @@ +//! The [`Ranges`] type stores a list of contiguous index ranges that +//! span some other list's full length. + +use alloc::vec::Vec; +use core::ops::Range; + +/// A list of contiguous index ranges. +#[derive(Default)] +pub struct Ranges { + ranges: Vec, + reverse: bool, +} + +impl Ranges { + /// Constructs a new, empty, list of ranges with at least the + /// specified capacity. + pub fn with_capacity(capacity: usize) -> Self { + let mut new = Ranges::default(); + new.reserve(capacity); + new + } + + /// Add a new range which begins at the end of the previous range + /// and ends at the specified offset, exclusive. + pub fn push_end(&mut self, end: usize) { + debug_assert!(!self.reverse); + // To keep this implementation simple we explicitly store the + // starting index, which is always 0, so that all ranges are + // represented by adjacent pairs in the list. But we add it + // lazily so that an empty list doesn't have to allocate. + if self.ranges.is_empty() { + self.ranges.push(0); + } + self.ranges.push(u32::try_from(end).unwrap()); + } + + /// Number of ranges in this list. + pub fn len(&self) -> usize { + self.ranges.len().saturating_sub(1) + } + + /// Reserves capacity for at least `additional` more ranges to be + /// added to this list. + pub fn reserve(&mut self, mut additional: usize) { + if additional > 0 && self.ranges.is_empty() { + additional = additional.saturating_add(1); + } + self.ranges.reserve(additional); + } + + /// Get the range at the specified index. + pub fn get(&self, index: usize) -> Range { + let len = self.len(); + assert!(index < len, "index {index} is too big for length {len}"); + let index = self.map_index(index); + self.ranges[index] as usize..self.ranges[index + 1] as usize + } + + /// Visit ranges in unspecified order, paired with the index each + /// range occurs at. + pub fn iter( + &self, + ) -> impl DoubleEndedIterator)> + ExactSizeIterator + '_ { + self.ranges + .windows(2) + .enumerate() + .map(|(index, range)| (self.map_index(index), range[0] as usize..range[1] as usize)) + } + + /// Reverse this list of ranges, so that the first range is at the + /// last index and the last range is at the first index. + /// + /// ```ignore + /// use cranelift_codegen::ranges::Ranges; + /// let mut ranges = Ranges::default(); + /// ranges.push_end(4); + /// ranges.push_end(6); + /// ranges.reverse_index(); + /// assert_eq!(ranges.get(0), 4..6); + /// assert_eq!(ranges.get(1), 0..4); + /// ``` + pub fn reverse_index(&mut self) { + // We can't easily change the order of the endpoints in + // self.ranges: they need to be in ascending order or our + // compressed representation gets complicated. So instead we + // change our interpretation of indexes using map_index below, + // controlled by a simple flag. As a bonus, reversing the list + // is constant-time! + self.reverse = !self.reverse; + } + + fn map_index(&self, index: usize) -> usize { + if self.reverse { + // These subtractions can't overflow because callers + // enforce that 0 <= index < self.len() + self.len() - 1 - index + } else { + index + } + } + + /// Update these ranges to reflect that the list they refer to has + /// been reversed. Afterwards, the ranges will still be indexed + /// in the same order, but the first range will refer to the + /// same-length range at the end of the target list instead of at + /// the beginning, and subsequent ranges will proceed backwards + /// from there. + /// + /// ```ignore + /// use cranelift_codegen::ranges::Ranges; + /// let mut ranges = Ranges::default(); + /// ranges.push_end(4); + /// ranges.push_end(6); + /// ranges.reverse_target(6); + /// assert_eq!(ranges.get(0), 2..6); + /// assert_eq!(ranges.get(1), 0..2); + /// ``` + pub fn reverse_target(&mut self, target_len: usize) { + let target_len = u32::try_from(target_len).unwrap(); + // The last endpoint added should be the same as the current + // length of the target list. + debug_assert_eq!(target_len, *self.ranges.last().unwrap_or(&0)); + for end in self.ranges.iter_mut() { + *end = target_len - *end; + } + // Put the endpoints back in ascending order, but that means + // now our indexes are backwards. + self.ranges.reverse(); + self.reverse_index(); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/remove_constant_phis.rs b/deps/crates/vendor/cranelift-codegen/src/remove_constant_phis.rs new file mode 100644 index 00000000000000..bb2159c3bbeb22 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/remove_constant_phis.rs @@ -0,0 +1,419 @@ +//! A Constant-Phi-Node removal pass. + +use crate::dominator_tree::DominatorTree; +use crate::ir; +use crate::ir::Function; +use crate::ir::{Block, BlockCall, Inst, Value}; +use crate::timing; +use bumpalo::Bump; +use cranelift_entity::SecondaryMap; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::SmallVec; + +// A note on notation. For the sake of clarity, this file uses the phrase +// "formal parameters" to mean the `Value`s listed in the block head, and +// "actual parameters" to mean the `Value`s passed in a branch or a jump: +// +// block4(v16: i32, v18: i32): <-- formal parameters +// ... +// brif v27, block7(v22, v24), block6 <-- actual parameters + +// This transformation pass (conceptually) partitions all values in the +// function into two groups: +// +// * Group A: values defined by block formal parameters, except for the entry block. +// +// * Group B: All other values: that is, values defined by instructions, +// and the formals of the entry block. +// +// For each value in Group A, it attempts to establish whether it will have +// the value of exactly one member of Group B. If so, the formal parameter is +// deleted, all corresponding actual parameters (in jumps/branches to the +// defining block) are deleted, and a rename is inserted. +// +// The entry block is special-cased because (1) we don't know what values flow +// to its formals and (2) in any case we can't change its formals. +// +// Work proceeds in three phases. +// +// * Phase 1: examine all instructions. For each block, make up a useful +// grab-bag of information, `BlockSummary`, that summarises the block's +// formals and jump/branch instruction. This is used by Phases 2 and 3. +// +// * Phase 2: for each value in Group A, try to find a single Group B value +// that flows to it. This is done using a classical iterative forward +// dataflow analysis over a simple constant-propagation style lattice. It +// converges quickly in practice -- I have seen at most 4 iterations. This +// is relatively cheap because the iteration is done over the +// `BlockSummary`s, and does not visit each instruction. The resulting +// fixed point is stored in a `SolverState`. +// +// * Phase 3: using the `SolverState` and `BlockSummary`, edit the function to +// remove redundant formals and actuals, and to insert suitable renames. +// +// Note that the effectiveness of the analysis depends on on the fact that +// there are no copy instructions in Cranelift's IR. If there were, the +// computation of `actual_absval` in Phase 2 would have to be extended to +// chase through such copies. +// +// For large functions, the analysis cost using the new AArch64 backend is about +// 0.6% of the non-optimising compile time, as measured by instruction counts. +// This transformation usually pays for itself several times over, though, by +// reducing the isel/regalloc cost downstream. Gains of up to 7% have been +// seen for large functions. + +/// The `Value`s (Group B) that can flow to a formal parameter (Group A). +#[derive(Clone, Copy, Debug, PartialEq)] +enum AbstractValue { + /// Two or more values flow to this formal. + Many, + + /// Exactly one value, as stated, flows to this formal. The `Value`s that + /// can appear here are exactly: `Value`s defined by `Inst`s, plus the + /// `Value`s defined by the formals of the entry block. Note that this is + /// exactly the set of `Value`s that are *not* tracked in the solver below + /// (see `SolverState`). + One(Value /*Group B*/), + + /// No value flows to this formal. + None, +} + +impl AbstractValue { + fn join(self, other: AbstractValue) -> AbstractValue { + match (self, other) { + // Joining with `None` has no effect + (AbstractValue::None, p2) => p2, + (p1, AbstractValue::None) => p1, + // Joining with `Many` produces `Many` + (AbstractValue::Many, _p2) => AbstractValue::Many, + (_p1, AbstractValue::Many) => AbstractValue::Many, + // The only interesting case + (AbstractValue::One(v1), AbstractValue::One(v2)) => { + if v1 == v2 { + AbstractValue::One(v1) + } else { + AbstractValue::Many + } + } + } + } + + fn is_one(self) -> bool { + matches!(self, AbstractValue::One(_)) + } +} + +#[derive(Clone, Copy, Debug)] +struct OutEdge<'a> { + /// An instruction that transfers control. + inst: Inst, + /// The index into branch_destinations for this instruction that corresponds + /// to this edge. + branch_index: u32, + /// The block that control is transferred to. + block: Block, + /// The arguments to that block. + /// + /// These values can be from both groups A and B. + args: &'a [Value], +} + +impl<'a> OutEdge<'a> { + /// Construct a new `OutEdge` for the given instruction. + /// + /// Returns `None` if this is an edge without any block arguments, which + /// means we can ignore it for this analysis's purposes. + #[inline] + fn new( + bump: &'a Bump, + dfg: &ir::DataFlowGraph, + inst: Inst, + branch_index: usize, + block: BlockCall, + ) -> Option { + let inst_var_args = block.args_slice(&dfg.value_lists); + + // Skip edges without params. + if inst_var_args.is_empty() { + return None; + } + + Some(OutEdge { + inst, + branch_index: branch_index as u32, + block: block.block(&dfg.value_lists), + args: bump.alloc_slice_fill_iter( + inst_var_args + .iter() + .map(|value| dfg.resolve_aliases(*value)), + ), + }) + } +} + +/// For some block, a useful bundle of info. The `Block` itself is not stored +/// here since it will be the key in the associated `FxHashMap` -- see +/// `summaries` below. For the `SmallVec` tuning params: most blocks have +/// few parameters, hence `4`. And almost all blocks have either one or two +/// successors, hence `2`. +#[derive(Clone, Debug, Default)] +struct BlockSummary<'a> { + /// Formal parameters for this `Block`. + /// + /// These values are from group A. + formals: &'a [Value], + + /// Each outgoing edge from this block. + /// + /// We don't bother to include transfers that pass zero parameters + /// since that makes more work for the solver for no purpose. + /// + /// We optimize for the case where a branch instruction has up to two + /// outgoing edges, as unconditional jumps and conditional branches are + /// more prominent than br_table. + dests: SmallVec<[OutEdge<'a>; 2]>, +} + +impl<'a> BlockSummary<'a> { + /// Construct a new `BlockSummary`, using `values` as its backing storage. + #[inline] + fn new(bump: &'a Bump, formals: &[Value]) -> Self { + Self { + formals: bump.alloc_slice_copy(formals), + dests: Default::default(), + } + } +} + +/// Solver state. This holds a AbstractValue for each formal parameter, except +/// for those from the entry block. +struct SolverState { + absvals: FxHashMap, +} + +impl SolverState { + fn new() -> Self { + Self { + absvals: FxHashMap::default(), + } + } + + fn get(&self, actual: Value) -> AbstractValue { + *self + .absvals + .get(&actual) + .unwrap_or_else(|| panic!("SolverState::get: formal param {actual:?} is untracked?!")) + } + + fn maybe_get(&self, actual: Value) -> Option<&AbstractValue> { + self.absvals.get(&actual) + } + + fn set(&mut self, actual: Value, lp: AbstractValue) { + match self.absvals.insert(actual, lp) { + Some(_old_lp) => {} + None => panic!("SolverState::set: formal param {actual:?} is untracked?!"), + } + } +} + +/// Detect phis in `func` that will only ever produce one value, using a +/// classic forward dataflow analysis. Then remove them. +#[inline(never)] +pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree) { + let _tt = timing::remove_constant_phis(); + debug_assert!(domtree.is_valid()); + + // Phase 1 of 3: for each block, make a summary containing all relevant + // info. The solver will iterate over the summaries, rather than having + // to inspect each instruction in each block. + let bump = + Bump::with_capacity(domtree.cfg_postorder().len() * 4 * std::mem::size_of::()); + let mut summaries = + SecondaryMap::::with_capacity(domtree.cfg_postorder().len()); + + for b in domtree.cfg_rpo().copied() { + let formals = func.dfg.block_params(b); + let mut summary = BlockSummary::new(&bump, formals); + + for inst in func.layout.block_insts(b) { + for (ix, dest) in func.dfg.insts[inst] + .branch_destination(&func.dfg.jump_tables) + .iter() + .enumerate() + { + if let Some(edge) = OutEdge::new(&bump, &func.dfg, inst, ix, *dest) { + summary.dests.push(edge); + } + } + } + + // Ensure the invariant that all blocks (except for the entry) appear + // in the summary, *unless* they have neither formals nor any + // param-carrying branches/jumps. + if formals.len() > 0 || summary.dests.len() > 0 { + summaries[b] = summary; + } + } + + // Phase 2 of 3: iterate over the summaries in reverse postorder, + // computing new `AbstractValue`s for each tracked `Value`. The set of + // tracked `Value`s is exactly Group A as described above. + + let entry_block = func + .layout + .entry_block() + .expect("remove_constant_phis: entry block unknown"); + + // Set up initial solver state + let mut state = SolverState::new(); + + for b in domtree.cfg_rpo().copied() { + // For each block, get the formals + if b == entry_block { + continue; + } + let formals = func.dfg.block_params(b); + for formal in formals { + let mb_old_absval = state.absvals.insert(*formal, AbstractValue::None); + assert!(mb_old_absval.is_none()); + } + } + + // Solve: repeatedly traverse the blocks in reverse postorder, until there + // are no changes. + let mut iter_no = 0; + loop { + iter_no += 1; + let mut changed = false; + + for src in domtree.cfg_rpo().copied() { + let src_summary = &summaries[src]; + for edge in &src_summary.dests { + assert!(edge.block != entry_block); + // By contrast, the dst block must have a summary. Phase 1 + // will have only included an entry in `src_summary.dests` if + // that branch/jump carried at least one parameter. So the + // dst block does take parameters, so it must have a summary. + let dst_summary = &summaries[edge.block]; + let dst_formals = &dst_summary.formals; + assert_eq!(edge.args.len(), dst_formals.len()); + for (formal, actual) in dst_formals.iter().zip(edge.args) { + // Find the abstract value for `actual`. If it is a block + // formal parameter then the most recent abstract value is + // to be found in the solver state. If not, then it's a + // real value defining point (not a phi), in which case + // return it itself. + let actual_absval = match state.maybe_get(*actual) { + Some(pt) => *pt, + None => AbstractValue::One(*actual), + }; + + // And `join` the new value with the old. + let formal_absval_old = state.get(*formal); + let formal_absval_new = formal_absval_old.join(actual_absval); + if formal_absval_new != formal_absval_old { + changed = true; + state.set(*formal, formal_absval_new); + } + } + } + } + + if !changed { + break; + } + } + + let mut n_consts = 0; + for absval in state.absvals.values() { + if absval.is_one() { + n_consts += 1; + } + } + + // Phase 3 of 3: edit the function to remove constant formals, using the + // summaries and the final solver state as a guide. + + // Make up a set of blocks that need editing. + let mut need_editing = FxHashSet::::default(); + for (block, summary) in summaries.iter() { + if block == entry_block { + continue; + } + for formal in summary.formals { + let formal_absval = state.get(*formal); + if formal_absval.is_one() { + need_editing.insert(block); + break; + } + } + } + + // Firstly, deal with the formals. For each formal which is redundant, + // remove it, and also add a reroute from it to the constant value which + // it we know it to be. + for b in &need_editing { + let mut del_these = SmallVec::<[(Value, Value); 32]>::new(); + let formals: &[Value] = func.dfg.block_params(*b); + for formal in formals { + // The state must give an absval for `formal`. + if let AbstractValue::One(replacement_val) = state.get(*formal) { + del_these.push((*formal, replacement_val)); + } + } + // We can delete the formals in any order. However, + // `remove_block_param` works by sliding backwards all arguments to + // the right of the value it is asked to delete. Hence when removing more + // than one formal, it is significantly more efficient to ask it to + // remove the rightmost formal first, and hence this `rev()`. + for (redundant_formal, replacement_val) in del_these.into_iter().rev() { + func.dfg.remove_block_param(redundant_formal); + func.dfg.change_to_alias(redundant_formal, replacement_val); + } + } + + // Secondly, visit all branch insns. If the destination has had its + // formals changed, change the actuals accordingly. Don't scan all insns, + // rather just visit those as listed in the summaries we prepared earlier. + let mut old_actuals = alloc::vec::Vec::new(); + for summary in summaries.values() { + for edge in &summary.dests { + if !need_editing.contains(&edge.block) { + continue; + } + + let dfg = &mut func.dfg; + let dests = dfg.insts[edge.inst].branch_destination_mut(&mut dfg.jump_tables); + let block = &mut dests[edge.branch_index as usize]; + + old_actuals.extend(block.args_slice(&dfg.value_lists)); + + // Check that the numbers of arguments make sense. + let formals = &summaries[edge.block].formals; + assert_eq!(formals.len(), old_actuals.len()); + + // Filter out redundant block arguments. + let mut formals = formals.iter(); + old_actuals.retain(|_| { + let formal_i = formals.next().unwrap(); + !state.get(*formal_i).is_one() + }); + + // Replace the block with a new one that only includes the non-redundant arguments. + // This leaks the value list from the old block, + // https://github.com/bytecodealliance/wasmtime/issues/5451 for more information. + let destination = block.block(&dfg.value_lists); + *block = BlockCall::new(destination, &old_actuals, &mut dfg.value_lists); + old_actuals.clear(); + } + } + + log::debug!( + "do_remove_constant_phis: done, {} iters. {} formals, of which {} const.", + iter_no, + state.absvals.len(), + n_consts + ); +} diff --git a/deps/crates/vendor/cranelift-codegen/src/result.rs b/deps/crates/vendor/cranelift-codegen/src/result.rs new file mode 100644 index 00000000000000..5e4a490073c7f5 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/result.rs @@ -0,0 +1,111 @@ +//! Result and error types representing the outcome of compiling a function. + +use regalloc2::checker::CheckerErrors; + +use crate::ir::pcc::PccError; +use crate::{ir::Function, verifier::VerifierErrors}; +use std::string::String; + +/// A compilation error. +/// +/// When Cranelift fails to compile a function, it will return one of these error codes. +#[derive(Debug)] +pub enum CodegenError { + /// A list of IR verifier errors. + /// + /// This always represents a bug, either in the code that generated IR for Cranelift, or a bug + /// in Cranelift itself. + Verifier(VerifierErrors), + + /// An implementation limit was exceeded. + /// + /// Cranelift can compile very large and complicated functions, but the [implementation has + /// limits][limits] that cause compilation to fail when they are exceeded. + /// + /// [limits]: https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/docs/ir.md#implementation-limits + ImplLimitExceeded, + + /// The code size for the function is too large. + /// + /// Different target ISAs may impose a limit on the size of a compiled function. If that limit + /// is exceeded, compilation fails. + CodeTooLarge, + + /// Something is not supported by the code generator. This might be an indication that a + /// feature is used without explicitly enabling it, or that something is temporarily + /// unsupported by a given target backend. + Unsupported(String), + + /// A failure to map Cranelift register representation to a DWARF register representation. + #[cfg(feature = "unwind")] + RegisterMappingError(crate::isa::unwind::systemv::RegisterMappingError), + + /// Register allocator internal error discovered by the symbolic checker. + Regalloc(CheckerErrors), + + /// Proof-carrying-code validation error. + Pcc(PccError), +} + +/// A convenient alias for a `Result` that uses `CodegenError` as the error type. +pub type CodegenResult = Result; + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for CodegenError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + CodegenError::Verifier(source) => Some(source), + CodegenError::ImplLimitExceeded { .. } + | CodegenError::CodeTooLarge { .. } + | CodegenError::Unsupported { .. } => None, + #[cfg(feature = "unwind")] + CodegenError::RegisterMappingError { .. } => None, + CodegenError::Regalloc(..) => None, + CodegenError::Pcc(..) => None, + } + } +} + +impl std::fmt::Display for CodegenError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + CodegenError::Verifier(_) => write!(f, "Verifier errors"), + CodegenError::ImplLimitExceeded => write!(f, "Implementation limit exceeded"), + CodegenError::CodeTooLarge => write!(f, "Code for function is too large"), + CodegenError::Unsupported(feature) => write!(f, "Unsupported feature: {feature}"), + #[cfg(feature = "unwind")] + CodegenError::RegisterMappingError(_0) => write!(f, "Register mapping error"), + CodegenError::Regalloc(errors) => write!(f, "Regalloc validation errors: {errors:?}"), + + // NOTE: if this is changed, please update the `is_pcc_error` function defined in + // `wasmtime/crates/fuzzing/src/oracles.rs` + CodegenError::Pcc(e) => write!(f, "Proof-carrying-code validation error: {e:?}"), + } + } +} + +impl From for CodegenError { + fn from(source: VerifierErrors) -> Self { + CodegenError::Verifier { 0: source } + } +} + +/// Compilation error, with the accompanying function to help printing it. +pub struct CompileError<'a> { + /// Underlying `CodegenError` that triggered the error. + pub inner: CodegenError, + /// Function we tried to compile, for display purposes. + pub func: &'a Function, +} + +// By default, have `CompileError` be displayed as the internal error, and let consumers care if +// they want to use the func field for adding details. +impl<'a> core::fmt::Debug for CompileError<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.inner.fmt(f) + } +} + +/// A convenient alias for a `Result` that uses `CompileError` as the error type. +pub type CompileResult<'a, T> = Result>; diff --git a/deps/crates/vendor/cranelift-codegen/src/scoped_hash_map.rs b/deps/crates/vendor/cranelift-codegen/src/scoped_hash_map.rs new file mode 100644 index 00000000000000..170a6140d25981 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/scoped_hash_map.rs @@ -0,0 +1,310 @@ +//! `ScopedHashMap` +//! +//! This module defines a struct `ScopedHashMap` which defines a `FxHashMap`-like +//! container that has a concept of scopes that can be entered and exited, such that +//! values inserted while inside a scope aren't visible outside the scope. + +use core::hash::Hash; +use rustc_hash::FxHashMap; +use smallvec::{smallvec, SmallVec}; + +#[cfg(not(feature = "std"))] +use crate::fx::FxHasher; +#[cfg(not(feature = "std"))] +type Hasher = core::hash::BuildHasherDefault; + +struct Val { + value: V, + level: u32, + generation: u32, +} + +/// A view into an occupied entry in a `ScopedHashMap`. It is part of the `Entry` enum. +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + entry: super::hash_map::OccupiedEntry<'a, K, Val>, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &V { + &self.entry.get().value + } +} + +/// A view into a vacant entry in a `ScopedHashMap`. It is part of the `Entry` enum. +pub struct VacantEntry<'a, K: 'a, V: 'a> { + entry: InsertLoc<'a, K, V>, + depth: u32, + generation: u32, +} + +/// Where to insert from a `VacantEntry`. May be vacant or occupied in +/// the underlying map because of lazy (generation-based) deletion. +enum InsertLoc<'a, K: 'a, V: 'a> { + Vacant(super::hash_map::VacantEntry<'a, K, Val>), + Occupied(super::hash_map::OccupiedEntry<'a, K, Val>), +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Sets the value of the entry with the `VacantEntry`'s key. + pub fn insert(self, value: V) { + let val = Val { + value, + level: self.depth, + generation: self.generation, + }; + match self.entry { + InsertLoc::Vacant(v) => { + v.insert(val); + } + InsertLoc::Occupied(mut o) => { + o.insert(val); + } + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This enum is constructed from the `entry` method on `ScopedHashMap`. +pub enum Entry<'a, K: 'a, V: 'a> { + Occupied(OccupiedEntry<'a, K, V>), + Vacant(VacantEntry<'a, K, V>), +} + +/// A wrapper around a `FxHashMap` which adds the concept of scopes. Items inserted +/// within a scope are removed when the scope is exited. +/// +/// Shadowing, where one scope has entries with the same keys as a containing scope, +/// is not supported in this implementation. +pub struct ScopedHashMap { + map: FxHashMap>, + generation_by_depth: SmallVec<[u32; 8]>, + generation: u32, +} + +impl ScopedHashMap +where + K: PartialEq + Eq + Hash + Clone, +{ + /// Creates an empty `ScopedHashMap`. + pub fn new() -> Self { + Self { + map: FxHashMap::default(), + generation: 0, + generation_by_depth: smallvec![0], + } + } + + /// Creates an empty `ScopedHashMap` with some pre-allocated capacity. + pub fn with_capacity(cap: usize) -> Self { + let mut map = FxHashMap::default(); + map.reserve(cap); + Self { + map, + generation: 0, + generation_by_depth: smallvec![0], + } + } + + /// Similar to `FxHashMap::entry`, gets the given key's corresponding entry in the map for + /// in-place manipulation. + pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { + self.entry_with_depth(key, self.depth()) + } + + /// Get the entry, setting the scope depth at which to insert. + pub fn entry_with_depth<'a>(&'a mut self, key: K, depth: usize) -> Entry<'a, K, V> { + debug_assert!(depth <= self.generation_by_depth.len()); + let generation = self.generation_by_depth[depth]; + let depth = depth as u32; + use super::hash_map::Entry::*; + match self.map.entry(key) { + Occupied(entry) => { + let entry_generation = entry.get().generation; + let entry_depth = entry.get().level as usize; + if self.generation_by_depth.get(entry_depth).cloned() == Some(entry_generation) { + Entry::Occupied(OccupiedEntry { entry }) + } else { + Entry::Vacant(VacantEntry { + entry: InsertLoc::Occupied(entry), + depth, + generation, + }) + } + } + Vacant(entry) => Entry::Vacant(VacantEntry { + entry: InsertLoc::Vacant(entry), + depth, + generation, + }), + } + } + + /// Get a value from a key, if present. + pub fn get<'a>(&'a self, key: &K) -> Option<&'a V> { + self.map + .get(key) + .filter(|entry| { + let level = entry.level as usize; + self.generation_by_depth.get(level).cloned() == Some(entry.generation) + }) + .map(|entry| &entry.value) + } + + /// Insert a key-value pair if absent. No-op if already exists. + pub fn insert_if_absent(&mut self, key: K, value: V) { + self.insert_if_absent_with_depth(key, value, self.depth()); + } + + /// Insert a key-value pair if absent, using the given depth for + /// the insertion. No-op if already exists. + pub fn insert_if_absent_with_depth(&mut self, key: K, value: V, depth: usize) { + match self.entry_with_depth(key, depth) { + Entry::Vacant(v) => { + v.insert(value); + } + Entry::Occupied(_) => { + // Nothing. + } + } + } + + /// Enter a new scope. + pub fn increment_depth(&mut self) { + self.generation_by_depth.push(self.generation); + } + + /// Exit the current scope. + pub fn decrement_depth(&mut self) { + self.generation += 1; + self.generation_by_depth.pop(); + } + + /// Return the current scope depth. + pub fn depth(&self) -> usize { + self.generation_by_depth + .len() + .checked_sub(1) + .expect("generation_by_depth cannot be empty") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic() { + let mut map: ScopedHashMap = ScopedHashMap::new(); + + match map.entry(0) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(1), + } + match map.entry(2) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(8), + } + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + map.increment_depth(); + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(1) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(3), + } + match map.entry(1) { + Entry::Occupied(entry) => assert!(*entry.get() == 3), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(0) { + Entry::Occupied(entry) => assert!(*entry.get() == 1), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + map.decrement_depth(); + match map.entry(0) { + Entry::Occupied(entry) => assert!(*entry.get() == 1), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + map.increment_depth(); + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(1) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(4), + } + match map.entry(1) { + Entry::Occupied(entry) => assert!(*entry.get() == 4), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + map.decrement_depth(); + map.increment_depth(); + map.increment_depth(); + map.increment_depth(); + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(1) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(5), + } + match map.entry(1) { + Entry::Occupied(entry) => assert!(*entry.get() == 5), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + map.decrement_depth(); + map.decrement_depth(); + map.decrement_depth(); + match map.entry(2) { + Entry::Occupied(entry) => assert!(*entry.get() == 8), + Entry::Vacant(_entry) => panic!(), + } + match map.entry(1) { + Entry::Occupied(_entry) => panic!(), + Entry::Vacant(entry) => entry.insert(3), + } + } + + #[test] + fn insert_arbitrary_depth() { + let mut map: ScopedHashMap = ScopedHashMap::new(); + map.insert_if_absent(1, 2); + assert_eq!(map.get(&1), Some(&2)); + map.increment_depth(); + assert_eq!(map.get(&1), Some(&2)); + map.insert_if_absent(3, 4); + assert_eq!(map.get(&3), Some(&4)); + map.decrement_depth(); + assert_eq!(map.get(&3), None); + map.increment_depth(); + map.insert_if_absent_with_depth(3, 4, 0); + assert_eq!(map.get(&3), Some(&4)); + map.decrement_depth(); + assert_eq!(map.get(&3), Some(&4)); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/settings.rs b/deps/crates/vendor/cranelift-codegen/src/settings.rs new file mode 100644 index 00000000000000..a6fc9fcc6025e0 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/settings.rs @@ -0,0 +1,593 @@ +//! Shared settings module. +//! +//! This module defines data structures to access the settings defined in the meta language. +//! +//! Each settings group is translated to a `Flags` struct either in this module or in its +//! ISA-specific `settings` module. The struct provides individual getter methods for all of the +//! settings as well as computed predicate flags. +//! +//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to +//! create it. +//! +//! # Example +//! ``` +//! use cranelift_codegen::settings::{self, Configurable}; +//! +//! let mut b = settings::builder(); +//! b.set("opt_level", "speed_and_size"); +//! +//! let f = settings::Flags::new(b); +//! assert_eq!(f.opt_level(), settings::OptLevel::SpeedAndSize); +//! ``` + +use crate::constant_hash::{probe, simple_hash}; +use crate::isa::TargetIsa; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use core::fmt; +use core::str; + +/// A string-based configurator for settings groups. +/// +/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags` +/// struct is created. +pub trait Configurable { + /// Set the string value of any setting by name. + /// + /// This can set any type of setting whether it is numeric, boolean, or enumerated. + fn set(&mut self, name: &str, value: &str) -> SetResult<()>; + + /// Enable a boolean setting or apply a preset. + /// + /// If the identified setting isn't a boolean or a preset, a `BadType` error is returned. + fn enable(&mut self, name: &str) -> SetResult<()>; +} + +/// Represents the kind of setting. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SettingKind { + /// The setting is an enumeration. + Enum, + /// The setting is a number. + Num, + /// The setting is a boolean. + Bool, + /// The setting is a preset. + Preset, +} + +/// Represents an available builder setting. +/// +/// This is used for iterating settings in a builder. +#[derive(Clone, Copy, Debug)] +pub struct Setting { + /// The name of the setting. + pub name: &'static str, + /// The description of the setting. + pub description: &'static str, + /// The kind of the setting. + pub kind: SettingKind, + /// The supported values of the setting (for enum values). + pub values: Option<&'static [&'static str]>, +} + +/// Represents a setting value. +/// +/// This is used for iterating values in `Flags`. +pub struct Value { + /// The name of the setting associated with this value. + pub name: &'static str, + pub(crate) detail: detail::Detail, + pub(crate) values: Option<&'static [&'static str]>, + pub(crate) value: u8, +} + +impl Value { + /// Gets the kind of setting. + pub fn kind(&self) -> SettingKind { + match &self.detail { + detail::Detail::Enum { .. } => SettingKind::Enum, + detail::Detail::Num => SettingKind::Num, + detail::Detail::Bool { .. } => SettingKind::Bool, + detail::Detail::Preset => unreachable!(), + } + } + + /// Gets the enum value if the value is from an enum setting. + pub fn as_enum(&self) -> Option<&'static str> { + self.values.map(|v| v[self.value as usize]) + } + + /// Gets the numerical value if the value is from a num setting. + pub fn as_num(&self) -> Option { + match &self.detail { + detail::Detail::Num => Some(self.value), + _ => None, + } + } + + /// Gets the boolean value if the value is from a boolean setting. + pub fn as_bool(&self) -> Option { + match &self.detail { + detail::Detail::Bool { bit } => Some(self.value & (1 << bit) != 0), + _ => None, + } + } + + /// Builds a string from the current value + pub fn value_string(&self) -> String { + match self.kind() { + SettingKind::Enum => self.as_enum().map(|b| b.to_string()), + SettingKind::Num => self.as_num().map(|b| b.to_string()), + SettingKind::Bool => self.as_bool().map(|b| b.to_string()), + SettingKind::Preset => unreachable!(), + } + .unwrap() + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(enum_variant) = self.as_enum() { + write!(f, "{}={}", self.name, enum_variant) + } else if let Some(num) = self.as_num() { + write!(f, "{}={}", self.name, num) + } else if let Some(b) = self.as_bool() { + if b { + write!(f, "{}=1", self.name) + } else { + write!(f, "{}=0", self.name) + } + } else { + unreachable!() + } + } +} + +/// Collect settings values based on a template. +#[derive(Clone, Hash)] +pub struct Builder { + template: &'static detail::Template, + bytes: Box<[u8]>, +} + +impl Builder { + /// Create a new builder with defaults and names from the given template. + pub fn new(tmpl: &'static detail::Template) -> Self { + Self { + template: tmpl, + bytes: tmpl.defaults.into(), + } + } + + /// Extract contents of builder once everything is configured. + pub fn state_for(&self, name: &str) -> &[u8] { + assert_eq!(name, self.template.name); + &self.bytes + } + + /// Iterates the available settings in the builder. + pub fn iter(&self) -> impl Iterator { + let template = self.template; + + template.descriptors.iter().map(move |d| { + let (kind, values) = match d.detail { + detail::Detail::Enum { last, enumerators } => { + let values = template.enums(last, enumerators); + (SettingKind::Enum, Some(values)) + } + detail::Detail::Num => (SettingKind::Num, None), + detail::Detail::Bool { .. } => (SettingKind::Bool, None), + detail::Detail::Preset => (SettingKind::Preset, None), + }; + + Setting { + name: d.name, + description: d.description, + kind, + values, + } + }) + } + + /// Set the value of a single bit. + fn set_bit(&mut self, offset: usize, bit: u8, value: bool) { + let byte = &mut self.bytes[offset]; + let mask = 1 << bit; + if value { + *byte |= mask; + } else { + *byte &= !mask; + } + } + + /// Apply a preset. The argument is a slice of (mask, value) bytes. + fn apply_preset(&mut self, values: &[(u8, u8)]) { + for (byte, &(mask, value)) in self.bytes.iter_mut().zip(values) { + *byte = (*byte & !mask) | value; + } + } + + /// Look up a descriptor by name. + fn lookup(&self, name: &str) -> SetResult<(usize, detail::Detail)> { + match probe(self.template, name, simple_hash(name)) { + Err(_) => Err(SetError::BadName(name.to_string())), + Ok(entry) => { + let d = &self.template.descriptors[self.template.hash_table[entry] as usize]; + Ok((d.offset as usize, d.detail)) + } + } + } +} + +fn parse_bool_value(value: &str) -> SetResult { + match value { + "true" | "on" | "yes" | "1" => Ok(true), + "false" | "off" | "no" | "0" => Ok(false), + _ => Err(SetError::BadValue("bool".to_string())), + } +} + +fn parse_enum_value(value: &str, choices: &[&str]) -> SetResult { + match choices.iter().position(|&tag| tag == value) { + Some(idx) => Ok(idx as u8), + None => Err(SetError::BadValue(format!( + "any among {}", + choices.join(", ") + ))), + } +} + +impl Configurable for Builder { + fn enable(&mut self, name: &str) -> SetResult<()> { + use self::detail::Detail; + let (offset, detail) = self.lookup(name)?; + match detail { + Detail::Bool { bit } => { + self.set_bit(offset, bit, true); + Ok(()) + } + Detail::Preset => { + self.apply_preset(&self.template.presets[offset..]); + Ok(()) + } + _ => Err(SetError::BadType), + } + } + + fn set(&mut self, name: &str, value: &str) -> SetResult<()> { + use self::detail::Detail; + let (offset, detail) = self.lookup(name)?; + match detail { + Detail::Bool { bit } => { + self.set_bit(offset, bit, parse_bool_value(value)?); + } + Detail::Num => { + self.bytes[offset] = value + .parse() + .map_err(|_| SetError::BadValue("number".to_string()))?; + } + Detail::Enum { last, enumerators } => { + self.bytes[offset] = + parse_enum_value(value, self.template.enums(last, enumerators))?; + } + Detail::Preset => return Err(SetError::BadName(name.to_string())), + } + Ok(()) + } +} + +/// An error produced when changing a setting. +#[derive(Debug, PartialEq, Eq)] +pub enum SetError { + /// No setting by this name exists. + BadName(String), + + /// Type mismatch for setting (e.g., setting an enum setting as a bool). + BadType, + + /// This is not a valid value for this setting. + BadValue(String), +} + +impl std::error::Error for SetError {} + +impl fmt::Display for SetError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SetError::BadName(name) => write!(f, "No existing setting named '{name}'"), + SetError::BadType => { + write!(f, "Trying to set a setting with the wrong type") + } + SetError::BadValue(value) => { + write!(f, "Unexpected value for a setting, expected {value}") + } + } + } +} + +/// A result returned when changing a setting. +pub type SetResult = Result; + +/// A reference to just the boolean predicates of a settings object. +/// +/// The settings objects themselves are generated and appear in the `isa/*/settings.rs` modules. +/// Each settings object provides a `predicate_view()` method that makes it possible to query +/// ISA predicates by number. +#[derive(Clone, Copy, Hash)] +pub struct PredicateView<'a>(&'a [u8]); + +impl<'a> PredicateView<'a> { + /// Create a new view of a precomputed predicate vector. + /// + /// See the `predicate_view()` method on the various `Flags` types defined for each ISA. + pub fn new(bits: &'a [u8]) -> Self { + PredicateView(bits) + } + + /// Check a numbered predicate. + pub fn test(self, p: usize) -> bool { + self.0[p / 8] & (1 << (p % 8)) != 0 + } +} + +/// Implementation details for generated code. +/// +/// This module holds definitions that need to be public so the can be instantiated by generated +/// code in other modules. +pub mod detail { + use crate::constant_hash; + use core::fmt; + use core::hash::Hash; + + /// An instruction group template. + #[derive(Hash)] + pub struct Template { + /// Name of the instruction group. + pub name: &'static str, + /// List of setting descriptors. + pub descriptors: &'static [Descriptor], + /// Union of all enumerators. + pub enumerators: &'static [&'static str], + /// Hash table of settings. + pub hash_table: &'static [u16], + /// Default values. + pub defaults: &'static [u8], + /// Pairs of (mask, value) for presets. + pub presets: &'static [(u8, u8)], + } + + impl Template { + /// Get enumerators corresponding to a `Details::Enum`. + pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] { + let from = enumerators as usize; + let len = usize::from(last) + 1; + &self.enumerators[from..from + len] + } + + /// Format a setting value as a TOML string. This is mostly for use by the generated + /// `Display` implementation. + pub fn format_toml_value( + &self, + detail: Detail, + byte: u8, + f: &mut fmt::Formatter, + ) -> fmt::Result { + match detail { + Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0), + Detail::Num => write!(f, "{byte}"), + Detail::Enum { last, enumerators } => { + if byte <= last { + let tags = self.enums(last, enumerators); + write!(f, "\"{}\"", tags[usize::from(byte)]) + } else { + write!(f, "{byte}") + } + } + // Presets aren't printed. They are reflected in the other settings. + Detail::Preset { .. } => Ok(()), + } + } + } + + /// The template contains a hash table for by-name lookup. + impl<'a> constant_hash::Table<&'a str> for Template { + fn len(&self) -> usize { + self.hash_table.len() + } + + fn key(&self, idx: usize) -> Option<&'a str> { + let e = self.hash_table[idx] as usize; + if e < self.descriptors.len() { + Some(self.descriptors[e].name) + } else { + None + } + } + } + + /// A setting descriptor holds the information needed to generically set and print a setting. + /// + /// Each settings group will be represented as a constant DESCRIPTORS array. + #[derive(Hash)] + pub struct Descriptor { + /// Lower snake-case name of setting as defined in meta. + pub name: &'static str, + + /// The description of the setting. + pub description: &'static str, + + /// Offset of byte containing this setting. + pub offset: u32, + + /// Additional details, depending on the kind of setting. + pub detail: Detail, + } + + /// The different kind of settings along with descriptor bits that depend on the kind. + #[derive(Clone, Copy, Hash)] + pub enum Detail { + /// A boolean setting only uses one bit, numbered from LSB. + Bool { + /// 0-7. + bit: u8, + }, + + /// A numerical setting uses the whole byte. + Num, + + /// An Enum setting uses a range of enumerators. + Enum { + /// Numerical value of last enumerator, allowing for 1-256 enumerators. + last: u8, + + /// First enumerator in the ENUMERATORS table. + enumerators: u16, + }, + + /// A preset is not an individual setting, it is a collection of settings applied at once. + /// + /// The `Descriptor::offset` field refers to the `PRESETS` table. + Preset, + } + + impl Detail { + /// Check if a detail is a Detail::Preset. Useful because the Descriptor + /// offset field has a different meaning when the detail is a preset. + pub fn is_preset(self) -> bool { + match self { + Self::Preset => true, + _ => false, + } + } + } +} + +// Include code generated by `meta/gen_settings.rs`. This file contains a public `Flags` struct +// with an implementation for all of the settings defined in +// `cranelift-codegen/meta/src/shared/settings.rs`. +include!(concat!(env!("OUT_DIR"), "/settings.rs")); + +/// Wrapper containing flags and optionally a `TargetIsa` trait object. +/// +/// A few passes need to access the flags but only optionally a target ISA. The `FlagsOrIsa` +/// wrapper can be used to pass either, and extract the flags so they are always accessible. +#[derive(Clone, Copy)] +pub struct FlagsOrIsa<'a> { + /// Flags are always present. + pub flags: &'a Flags, + + /// The ISA may not be present. + pub isa: Option<&'a dyn TargetIsa>, +} + +impl<'a> From<&'a Flags> for FlagsOrIsa<'a> { + fn from(flags: &'a Flags) -> FlagsOrIsa<'a> { + FlagsOrIsa { flags, isa: None } + } +} + +impl<'a> From<&'a dyn TargetIsa> for FlagsOrIsa<'a> { + fn from(isa: &'a dyn TargetIsa) -> FlagsOrIsa<'a> { + FlagsOrIsa { + flags: isa.flags(), + isa: Some(isa), + } + } +} + +#[cfg(test)] +mod tests { + use super::Configurable; + use super::SetError::*; + use super::{builder, Flags}; + use alloc::string::ToString; + + #[test] + fn display_default() { + let b = builder(); + let f = Flags::new(b); + let actual = f.to_string(); + let expected = r#"[shared] +regalloc_algorithm = "backtracking" +opt_level = "none" +tls_model = "none" +stack_switch_model = "none" +libcall_call_conv = "isa_default" +probestack_size_log2 = 12 +probestack_strategy = "outline" +bb_padding_log2_minus_one = 0 +regalloc_checker = false +regalloc_verbose_logs = false +enable_alias_analysis = true +enable_verifier = true +enable_pcc = false +is_pic = false +use_colocated_libcalls = false +enable_float = true +enable_nan_canonicalization = false +enable_pinned_reg = false +enable_atomics = true +enable_safepoints = false +enable_llvm_abi_extensions = false +enable_multi_ret_implicit_sret = false +unwind_info = true +preserve_frame_pointers = false +machine_code_cfg_info = false +enable_probestack = false +enable_jump_tables = true +enable_heap_access_spectre_mitigation = true +enable_table_access_spectre_mitigation = true +enable_incremental_compilation_cache_checks = false +"#; + if actual != expected { + panic!( + "Default settings do not match expectations:\n\n{}", + similar::TextDiff::from_lines(expected, &actual) + .unified_diff() + .header("expected", "actual") + ); + } + assert_eq!(f.opt_level(), super::OptLevel::None); + } + + #[test] + fn modify_bool() { + let mut b = builder(); + assert_eq!(b.enable("not_there"), Err(BadName("not_there".to_string()))); + assert_eq!(b.enable("enable_atomics"), Ok(())); + assert_eq!(b.set("enable_atomics", "false"), Ok(())); + + let f = Flags::new(b); + assert_eq!(f.enable_atomics(), false); + } + + #[test] + fn modify_string() { + let mut b = builder(); + assert_eq!( + b.set("not_there", "true"), + Err(BadName("not_there".to_string())) + ); + assert_eq!( + b.set("enable_atomics", ""), + Err(BadValue("bool".to_string())) + ); + assert_eq!( + b.set("enable_atomics", "best"), + Err(BadValue("bool".to_string())) + ); + assert_eq!( + b.set("opt_level", "true"), + Err(BadValue( + "any among none, speed, speed_and_size".to_string() + )) + ); + assert_eq!(b.set("opt_level", "speed"), Ok(())); + assert_eq!(b.set("enable_atomics", "0"), Ok(())); + + let f = Flags::new(b); + assert_eq!(f.enable_atomics(), false); + assert_eq!(f.opt_level(), super::OptLevel::Speed); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/souper_harvest.rs b/deps/crates/vendor/cranelift-codegen/src/souper_harvest.rs new file mode 100644 index 00000000000000..02958ed56a712f --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/souper_harvest.rs @@ -0,0 +1,589 @@ +//! Harvest left-hand side superoptimization candidates. +//! +//! Given a clif function, harvest all its integer subexpressions, so that they +//! can be fed into [Souper](https://github.com/google/souper) as candidates for +//! superoptimization. For some of these candidates, Souper will successfully +//! synthesize a right-hand side that is equivalent but has lower cost than the +//! left-hand side. Then, we can combine these left- and right-hand sides into a +//! complete optimization, and add it to our peephole passes. +//! +//! To harvest the expression that produced a given value `x`, we do a +//! post-order traversal of the dataflow graph starting from `x`. As we do this +//! traversal, we maintain a map from clif values to their translated Souper +//! values. We stop traversing when we reach anything that can't be translated +//! into Souper IR: a memory load, a float-to-int conversion, a block parameter, +//! etc. For values produced by these instructions, we create a Souper `var`, +//! which is an input variable to the optimization. For instructions that have a +//! direct mapping into Souper IR, we get the Souper version of each of its +//! operands and then create the Souper version of the instruction itself. It +//! should now be clear why we do a post-order traversal: we need an +//! instruction's translated operands in order to translate the instruction +//! itself. Once this instruction is translated, we update the clif-to-souper +//! map with this new translation so that any other instruction that uses this +//! result as an operand has access to the translated value. When the traversal +//! is complete we return the translation of `x` as the root of left-hand side +//! candidate. + +use crate::ir; +use souper_ir::ast; +use std::collections::{HashMap, HashSet}; +use std::string::String; +use std::sync::mpsc; +use std::vec::Vec; + +/// Harvest Souper left-hand side candidates from the given function. +/// +/// Candidates are reported through the given MPSC sender. +pub fn do_souper_harvest(func: &ir::Function, out: &mut mpsc::Sender) { + let mut allocs = Allocs::default(); + + // Iterate over each instruction in each block and try and harvest a + // left-hand side from its result. + for block in func.layout.blocks() { + let mut option_inst = func.layout.first_inst(block); + while let Some(inst) = option_inst { + let results = func.dfg.inst_results(inst); + if results.len() == 1 { + let val = results[0]; + let ty = func.dfg.value_type(val); + if ty.is_int() && ty.lane_count() == 1 { + harvest_candidate_lhs(&mut allocs, func, val, out); + } + } + option_inst = func.layout.next_inst(inst); + } + } +} + +/// Allocations that we reuse across many LHS candidate harvests. +#[derive(Default)] +struct Allocs { + /// A map from cranelift IR to souper IR for values that we've already + /// translated into souper IR. + ir_to_souper_val: HashMap, + + /// Stack of to-visit and to-trace values for the post-order DFS. + dfs_stack: Vec, + + /// Set of values we've already seen in our post-order DFS. + dfs_seen: HashSet, +} + +impl Allocs { + /// Reset the collections to their empty state (without deallocating their + /// backing data). + fn reset(&mut self) { + self.ir_to_souper_val.clear(); + self.dfs_stack.clear(); + self.dfs_seen.clear(); + } +} + +/// Harvest a candidate LHS for `val` from the dataflow graph. +fn harvest_candidate_lhs( + allocs: &mut Allocs, + func: &ir::Function, + val: ir::Value, + out: &mut mpsc::Sender, +) { + allocs.reset(); + let mut lhs = ast::LeftHandSideBuilder::default(); + let mut non_var_count = 0; + + // Should we keep tracing through the given `val`? Only if it is defined + // by an instruction that we can translate to Souper IR. + let should_trace = |val| match func.dfg.value_def(val) { + ir::ValueDef::Result(inst, 0) => match func.dfg.insts[inst].opcode() { + ir::Opcode::Iadd + | ir::Opcode::IaddImm + | ir::Opcode::IrsubImm + | ir::Opcode::Imul + | ir::Opcode::ImulImm + | ir::Opcode::Udiv + | ir::Opcode::UdivImm + | ir::Opcode::Sdiv + | ir::Opcode::SdivImm + | ir::Opcode::Urem + | ir::Opcode::UremImm + | ir::Opcode::Srem + | ir::Opcode::SremImm + | ir::Opcode::Band + | ir::Opcode::BandImm + | ir::Opcode::Bor + | ir::Opcode::BorImm + | ir::Opcode::Bxor + | ir::Opcode::BxorImm + | ir::Opcode::Ishl + | ir::Opcode::IshlImm + | ir::Opcode::Sshr + | ir::Opcode::SshrImm + | ir::Opcode::Ushr + | ir::Opcode::UshrImm + | ir::Opcode::Select + | ir::Opcode::Uextend + | ir::Opcode::Sextend + | ir::Opcode::Trunc + | ir::Opcode::Icmp + | ir::Opcode::Popcnt + | ir::Opcode::Bitrev + | ir::Opcode::Clz + | ir::Opcode::Ctz + // TODO: ir::Opcode::IaddCarry + | ir::Opcode::SaddSat + | ir::Opcode::SsubSat + | ir::Opcode::UsubSat => true, + _ => false, + }, + _ => false, + }; + + post_order_dfs(allocs, &func.dfg, val, should_trace, |allocs, val| { + let souper_assignment_rhs = match func.dfg.value_def(val) { + ir::ValueDef::Result(inst, 0) => { + let args = func.dfg.inst_args(inst); + + // Get the n^th argument as a souper operand. + let arg = |allocs: &mut Allocs, n| { + let arg = args[n]; + if let Some(a) = allocs.ir_to_souper_val.get(&arg).copied() { + a.into() + } else { + // The only arguments we get that we haven't already + // converted into a souper instruction are `iconst`s. + // This is because souper only allows + // constants as operands, and it doesn't allow assigning + // constants to a variable name. So we lazily convert + // `iconst`s into souper operands here, + // when they are actually used. + match func.dfg.value_def(arg) { + ir::ValueDef::Result(inst, 0) => match func.dfg.insts[inst] { + ir::InstructionData::UnaryImm { opcode, imm } => { + debug_assert_eq!(opcode, ir::Opcode::Iconst); + let imm: i64 = imm.into(); + ast::Operand::Constant(ast::Constant { + value: imm.into(), + r#type: souper_type_of(&func.dfg, arg), + }) + } + _ => unreachable!( + "only iconst instructions \ + aren't in `ir_to_souper_val`" + ), + }, + _ => unreachable!( + "only iconst instructions \ + aren't in `ir_to_souper_val`" + ), + } + } + }; + + match (func.dfg.insts[inst].opcode(), &func.dfg.insts[inst]) { + (ir::Opcode::Iadd, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Add { a, b }.into() + } + (ir::Opcode::IaddImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Add { a, b }.into() + } + (ir::Opcode::IrsubImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let b = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let a = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Sub { a, b }.into() + } + (ir::Opcode::Imul, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Mul { a, b }.into() + } + (ir::Opcode::ImulImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Mul { a, b }.into() + } + (ir::Opcode::Udiv, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Udiv { a, b }.into() + } + (ir::Opcode::UdivImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Udiv { a, b }.into() + } + (ir::Opcode::Sdiv, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Sdiv { a, b }.into() + } + (ir::Opcode::SdivImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Sdiv { a, b }.into() + } + (ir::Opcode::Urem, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Urem { a, b }.into() + } + (ir::Opcode::UremImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Urem { a, b }.into() + } + (ir::Opcode::Srem, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Srem { a, b }.into() + } + (ir::Opcode::SremImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Srem { a, b }.into() + } + (ir::Opcode::Band, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::And { a, b }.into() + } + (ir::Opcode::BandImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::And { a, b }.into() + } + (ir::Opcode::Bor, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Or { a, b }.into() + } + (ir::Opcode::BorImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Or { a, b }.into() + } + (ir::Opcode::Bxor, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Xor { a, b }.into() + } + (ir::Opcode::BxorImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Xor { a, b }.into() + } + (ir::Opcode::Ishl, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Shl { a, b }.into() + } + (ir::Opcode::IshlImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Shl { a, b }.into() + } + (ir::Opcode::Sshr, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Ashr { a, b }.into() + } + (ir::Opcode::SshrImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Ashr { a, b }.into() + } + (ir::Opcode::Ushr, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::Lshr { a, b }.into() + } + (ir::Opcode::UshrImm, ir::InstructionData::BinaryImm64 { imm, .. }) => { + let a = arg(allocs, 0); + let value: i64 = (*imm).into(); + let value: i128 = value.into(); + let b = ast::Constant { + value, + r#type: souper_type_of(&func.dfg, val), + } + .into(); + ast::Instruction::Lshr { a, b }.into() + } + (ir::Opcode::Select, _) => { + let a = arg(allocs, 0); + + // While Cranelift allows any width condition for + // `select` and checks it against `0`, Souper requires + // an `i1`. So insert a `ne %x, 0` as needed. + let a = match a { + ast::Operand::Value(id) => match lhs.get_value(id).r#type { + Some(ast::Type { width: 1 }) => a, + _ => lhs + .assignment( + None, + Some(ast::Type { width: 1 }), + ast::Instruction::Ne { + a, + b: ast::Constant { + value: 0, + r#type: None, + } + .into(), + }, + vec![], + ) + .into(), + }, + ast::Operand::Constant(ast::Constant { value, .. }) => ast::Constant { + value: (value != 0) as _, + r#type: Some(ast::Type { width: 1 }), + } + .into(), + }; + + let b = arg(allocs, 1); + let c = arg(allocs, 2); + ast::Instruction::Select { a, b, c }.into() + } + (ir::Opcode::Uextend, _) => { + let a = arg(allocs, 0); + ast::Instruction::Zext { a }.into() + } + (ir::Opcode::Sextend, _) => { + let a = arg(allocs, 0); + ast::Instruction::Sext { a }.into() + } + (ir::Opcode::Trunc, _) => { + let a = arg(allocs, 0); + ast::Instruction::Trunc { a }.into() + } + (ir::Opcode::Icmp, ir::InstructionData::IntCompare { cond, .. }) + | (ir::Opcode::IcmpImm, ir::InstructionData::IntCompare { cond, .. }) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + match cond { + ir::condcodes::IntCC::Equal => ast::Instruction::Eq { a, b }.into(), + ir::condcodes::IntCC::NotEqual => ast::Instruction::Ne { a, b }.into(), + ir::condcodes::IntCC::UnsignedLessThan => { + ast::Instruction::Ult { a, b }.into() + } + ir::condcodes::IntCC::SignedLessThan => { + ast::Instruction::Slt { a, b }.into() + } + ir::condcodes::IntCC::UnsignedLessThanOrEqual => { + ast::Instruction::Sle { a, b }.into() + } + ir::condcodes::IntCC::SignedLessThanOrEqual => { + ast::Instruction::Sle { a, b }.into() + } + _ => ast::AssignmentRhs::Var, + } + } + (ir::Opcode::Popcnt, _) => { + let a = arg(allocs, 0); + ast::Instruction::Ctpop { a }.into() + } + (ir::Opcode::Bitrev, _) => { + let a = arg(allocs, 0); + ast::Instruction::BitReverse { a }.into() + } + (ir::Opcode::Clz, _) => { + let a = arg(allocs, 0); + ast::Instruction::Ctlz { a }.into() + } + (ir::Opcode::Ctz, _) => { + let a = arg(allocs, 0); + ast::Instruction::Cttz { a }.into() + } + // TODO: ir::Opcode::IaddCarry + (ir::Opcode::SaddSat, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::SaddSat { a, b }.into() + } + (ir::Opcode::SsubSat, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::SsubSat { a, b }.into() + } + (ir::Opcode::UsubSat, _) => { + let a = arg(allocs, 0); + let b = arg(allocs, 1); + ast::Instruction::UsubSat { a, b }.into() + } + // Because Souper doesn't allow constants to be on the right + // hand side of an assignment (i.e. `%0:i32 = 1234` is + // disallowed) we have to ignore `iconst` + // instructions until we process them as operands for some + // other instruction. See the `arg` closure above for + // details. + (ir::Opcode::Iconst, _) => return, + _ => ast::AssignmentRhs::Var, + } + } + _ => ast::AssignmentRhs::Var, + }; + + non_var_count += match souper_assignment_rhs { + ast::AssignmentRhs::Var => 0, + _ => 1, + }; + let souper_ty = souper_type_of(&func.dfg, val); + let souper_val = lhs.assignment(None, souper_ty, souper_assignment_rhs, vec![]); + let old_value = allocs.ir_to_souper_val.insert(val, souper_val); + assert!(old_value.is_none()); + }); + + // We end up harvesting a lot of candidates like: + // + // %0:i32 = var + // infer %0 + // + // and + // + // %0:i32 = var + // %1:i32 = var + // %2:i32 = add %0, %1 + // + // Both of these are useless. Only actually harvest the candidate if there + // are at least two actual operations. + if non_var_count >= 2 { + let lhs = lhs.finish(allocs.ir_to_souper_val[&val], None); + out.send(format!( + ";; Harvested from `{}` in `{}`\n{}\n", + val, func.name, lhs + )) + .unwrap(); + } +} + +fn souper_type_of(dfg: &ir::DataFlowGraph, val: ir::Value) -> Option { + let ty = dfg.value_type(val); + assert!(ty.is_int()); + assert_eq!(ty.lane_count(), 1); + let width = match dfg.value_def(val).inst() { + Some(inst) + if dfg.insts[inst].opcode() == ir::Opcode::IcmpImm + || dfg.insts[inst].opcode() == ir::Opcode::Icmp => + { + 1 + } + _ => ty.bits().try_into().unwrap(), + }; + Some(ast::Type { width }) +} + +#[derive(Debug)] +enum StackEntry { + Visit(ir::Value), + Trace(ir::Value), +} + +fn post_order_dfs( + allocs: &mut Allocs, + dfg: &ir::DataFlowGraph, + val: ir::Value, + should_trace: impl Fn(ir::Value) -> bool, + mut visit: impl FnMut(&mut Allocs, ir::Value), +) { + allocs.dfs_stack.push(StackEntry::Trace(val)); + + while let Some(entry) = allocs.dfs_stack.pop() { + match entry { + StackEntry::Visit(val) => { + let is_new = allocs.dfs_seen.insert(val); + if is_new { + visit(allocs, val); + } + } + StackEntry::Trace(val) => { + if allocs.dfs_seen.contains(&val) { + continue; + } + + allocs.dfs_stack.push(StackEntry::Visit(val)); + if should_trace(val) { + if let ir::ValueDef::Result(inst, 0) = dfg.value_def(val) { + let args = dfg.inst_args(inst); + for v in args.iter().rev().copied() { + allocs.dfs_stack.push(StackEntry::Trace(v)); + } + } + } + } + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/timing.rs b/deps/crates/vendor/cranelift-codegen/src/timing.rs new file mode 100644 index 00000000000000..c634b5d9074855 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/timing.rs @@ -0,0 +1,296 @@ +//! Pass timing. +//! +//! This modules provides facilities for timing the execution of individual compilation passes. + +use core::fmt; +use std::any::Any; +use std::boxed::Box; +use std::cell::RefCell; +use std::mem; +use std::time::Duration; + +// Each pass that can be timed is predefined with the `define_passes!` macro. Each pass has a +// snake_case name and a plain text description used when printing out the timing report. +// +// This macro defines: +// +// - A C-style enum containing all the pass names and a `None` variant. +// - A usize constant with the number of defined passes. +// - A const array of pass descriptions. +// - A public function per pass used to start the timing of that pass. +macro_rules! define_passes { + ($($pass:ident: $desc:expr,)+) => { + /// A single profiled pass. + #[allow(non_camel_case_types)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Pass { + $(#[doc=$desc] $pass,)+ + /// No active pass. + None, + } + + /// The amount of profiled passes. + pub const NUM_PASSES: usize = Pass::None as usize; + + const DESCRIPTIONS: [&str; NUM_PASSES] = [ $($desc),+ ]; + + $( + #[doc=$desc] + #[must_use] + pub fn $pass() -> Box { + start_pass(Pass::$pass) + } + )+ + } +} + +// Pass definitions. +define_passes! { + // All these are used in other crates but defined here so they appear in the unified + // `PassTimes` output. + process_file: "Processing test file", + parse_text: "Parsing textual Cranelift IR", + wasm_translate_module: "Translate WASM module", + wasm_translate_function: "Translate WASM function", + + verifier: "Verify Cranelift IR", + + compile: "Compilation passes", + try_incremental_cache: "Try loading from incremental cache", + store_incremental_cache: "Store in incremental cache", + flowgraph: "Control flow graph", + domtree: "Dominator tree", + loop_analysis: "Loop analysis", + preopt: "Pre-legalization rewriting", + egraph: "Egraph based optimizations", + gvn: "Global value numbering", + licm: "Loop invariant code motion", + unreachable_code: "Remove unreachable blocks", + remove_constant_phis: "Remove constant phi-nodes", + + vcode_lower: "VCode lowering", + vcode_emit: "VCode emission", + vcode_emit_finish: "VCode emission finalization", + + regalloc: "Register allocation", + regalloc_checker: "Register allocation symbolic verification", + layout_renumber: "Layout full renumbering", + + canonicalize_nans: "Canonicalization of NaNs", +} + +impl Pass { + fn idx(self) -> usize { + self as usize + } + + /// Description of the pass. + pub fn description(self) -> &'static str { + match DESCRIPTIONS.get(self.idx()) { + Some(s) => s, + None => "", + } + } +} + +impl fmt::Display for Pass { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.description()) + } +} + +/// A profiler. +pub trait Profiler { + /// Start a profiling pass. + /// + /// Will return a token which when dropped indicates the end of the pass. + /// + /// Multiple passes can be active at the same time, but they must be started and stopped in a + /// LIFO fashion. + fn start_pass(&self, pass: Pass) -> Box; +} + +// Information about passes in a single thread. +thread_local! { + static PROFILER: RefCell> = RefCell::new(Box::new(DefaultProfiler)); +} + +/// Set the profiler for the current thread. +/// +/// Returns the old profiler. +pub fn set_thread_profiler(new_profiler: Box) -> Box { + PROFILER.with(|profiler| std::mem::replace(&mut *profiler.borrow_mut(), new_profiler)) +} + +/// Start timing `pass` as a child of the currently running pass, if any. +/// +/// This function is called by the publicly exposed pass functions. +fn start_pass(pass: Pass) -> Box { + PROFILER.with(|profiler| profiler.borrow().start_pass(pass)) +} + +/// Accumulated timing information for a single pass. +#[derive(Default, Copy, Clone)] +struct PassTime { + /// Total time spent running this pass including children. + total: Duration, + + /// Time spent running in child passes. + child: Duration, +} + +/// Accumulated timing for all passes. +pub struct PassTimes { + pass: [PassTime; NUM_PASSES], +} + +impl PassTimes { + /// Add `other` to the timings of this `PassTimes`. + pub fn add(&mut self, other: &Self) { + for (a, b) in self.pass.iter_mut().zip(&other.pass[..]) { + a.total += b.total; + a.child += b.child; + } + } + + /// Returns the total amount of time taken by all the passes measured. + pub fn total(&self) -> Duration { + self.pass.iter().map(|p| p.total - p.child).sum() + } +} + +impl Default for PassTimes { + fn default() -> Self { + Self { + pass: [Default::default(); NUM_PASSES], + } + } +} + +impl fmt::Display for PassTimes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "======== ======== ==================================")?; + writeln!(f, " Total Self Pass")?; + writeln!(f, "-------- -------- ----------------------------------")?; + for (time, desc) in self.pass.iter().zip(&DESCRIPTIONS[..]) { + // Omit passes that haven't run. + if time.total == Duration::default() { + continue; + } + + // Write a duration as secs.millis, trailing space. + fn fmtdur(mut dur: Duration, f: &mut fmt::Formatter) -> fmt::Result { + // Round to nearest ms by adding 500us. + dur += Duration::new(0, 500_000); + let ms = dur.subsec_millis(); + write!(f, "{:4}.{:03} ", dur.as_secs(), ms) + } + + fmtdur(time.total, f)?; + if let Some(s) = time.total.checked_sub(time.child) { + fmtdur(s, f)?; + } + writeln!(f, " {desc}")?; + } + writeln!(f, "======== ======== ==================================") + } +} + +// Information about passes in a single thread. +thread_local! { + static PASS_TIME: RefCell = RefCell::new(Default::default()); +} + +/// The default profiler. You can get the results using [`take_current`]. +pub struct DefaultProfiler; + +/// Take the current accumulated pass timings and reset the timings for the current thread. +/// +/// Only applies when [`DefaultProfiler`] is used. +pub fn take_current() -> PassTimes { + PASS_TIME.with(|rc| mem::take(&mut *rc.borrow_mut())) +} + +#[cfg(feature = "timing")] +mod enabled { + use super::{DefaultProfiler, Pass, Profiler, PASS_TIME}; + use std::any::Any; + use std::boxed::Box; + use std::cell::Cell; + use std::time::Instant; + + // Information about passes in a single thread. + thread_local! { + static CURRENT_PASS: Cell = const { Cell::new(Pass::None) }; + } + + impl Profiler for DefaultProfiler { + fn start_pass(&self, pass: Pass) -> Box { + let prev = CURRENT_PASS.with(|p| p.replace(pass)); + log::debug!("timing: Starting {}, (during {})", pass, prev); + Box::new(DefaultTimingToken { + start: Instant::now(), + pass, + prev, + }) + } + } + + /// A timing token is responsible for timing the currently running pass. Timing starts when it + /// is created and ends when it is dropped. + /// + /// Multiple passes can be active at the same time, but they must be started and stopped in a + /// LIFO fashion. + struct DefaultTimingToken { + /// Start time for this pass. + start: Instant, + + // Pass being timed by this token. + pass: Pass, + + // The previously active pass which will be restored when this token is dropped. + prev: Pass, + } + + /// Dropping a timing token indicated the end of the pass. + impl Drop for DefaultTimingToken { + fn drop(&mut self) { + let duration = self.start.elapsed(); + log::debug!("timing: Ending {}: {}ms", self.pass, duration.as_millis()); + let old_cur = CURRENT_PASS.with(|p| p.replace(self.prev)); + debug_assert_eq!(self.pass, old_cur, "Timing tokens dropped out of order"); + PASS_TIME.with(|rc| { + let mut table = rc.borrow_mut(); + table.pass[self.pass.idx()].total += duration; + if let Some(parent) = table.pass.get_mut(self.prev.idx()) { + parent.child += duration; + } + }) + } + } +} + +#[cfg(not(feature = "timing"))] +mod disabled { + use super::{DefaultProfiler, Pass, Profiler}; + use std::any::Any; + use std::boxed::Box; + + impl Profiler for DefaultProfiler { + fn start_pass(&self, _pass: Pass) -> Box { + Box::new(()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn display() { + assert_eq!(Pass::None.to_string(), ""); + assert_eq!(Pass::regalloc.to_string(), "Register allocation"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/traversals.rs b/deps/crates/vendor/cranelift-codegen/src/traversals.rs new file mode 100644 index 00000000000000..b3234601bf46ee --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/traversals.rs @@ -0,0 +1,218 @@ +//! Traversals over the IR. + +use crate::ir; +use alloc::vec::Vec; +use core::fmt::Debug; +use core::hash::Hash; +use cranelift_entity::EntitySet; + +/// A low-level DFS traversal event: either entering or exiting the traversal of +/// a block. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Event { + /// Entering traversal of a block. + /// + /// Processing a block upon this event corresponds to a pre-order, + /// depth-first traversal. + Enter, + + /// Exiting traversal of a block. + /// + /// Processing a block upon this event corresponds to a post-order, + /// depth-first traversal. + Exit, +} + +/// A depth-first traversal. +/// +/// This is a fairly low-level traversal type, and is generally intended to be +/// used as a building block for making specific pre-order or post-order +/// traversals for whatever problem is at hand. +/// +/// This type may be reused multiple times across different passes or functions +/// and will internally reuse any heap allocations its already made. +/// +/// Traversal is not recursive. +#[derive(Debug, Default, Clone)] +pub struct Dfs { + stack: Vec<(Event, ir::Block)>, + seen: EntitySet, +} + +impl Dfs { + /// Construct a new depth-first traversal. + pub fn new() -> Self { + Self::default() + } + + /// Perform a depth-first traversal over the given function. + /// + /// Yields pairs of `(Event, ir::Block)`. + /// + /// This iterator can be used to perform either pre- or post-order + /// traversals, or a combination of the two. + pub fn iter<'a>(&'a mut self, func: &'a ir::Function) -> DfsIter<'a> { + self.clear(); + if let Some(e) = func.layout.entry_block() { + self.stack.push((Event::Enter, e)); + } + DfsIter { dfs: self, func } + } + + /// Perform a pre-order traversal over the given function. + /// + /// Yields `ir::Block` items. + pub fn pre_order_iter<'a>(&'a mut self, func: &'a ir::Function) -> DfsPreOrderIter<'a> { + DfsPreOrderIter(self.iter(func)) + } + + /// Perform a post-order traversal over the given function. + /// + /// Yields `ir::Block` items. + pub fn post_order_iter<'a>(&'a mut self, func: &'a ir::Function) -> DfsPostOrderIter<'a> { + DfsPostOrderIter(self.iter(func)) + } + + /// Clear this DFS, but keep its allocations for future reuse. + pub fn clear(&mut self) { + let Dfs { stack, seen } = self; + stack.clear(); + seen.clear(); + } +} + +/// An iterator that yields pairs of `(Event, ir::Block)` items as it performs a +/// depth-first traversal over its associated function. +pub struct DfsIter<'a> { + dfs: &'a mut Dfs, + func: &'a ir::Function, +} + +impl Iterator for DfsIter<'_> { + type Item = (Event, ir::Block); + + fn next(&mut self) -> Option<(Event, ir::Block)> { + let (event, block) = self.dfs.stack.pop()?; + + if event == Event::Enter && self.dfs.seen.insert(block) { + self.dfs.stack.push((Event::Exit, block)); + self.dfs.stack.extend( + self.func + .block_successors(block) + // Heuristic: chase the children in reverse. This puts + // the first successor block first in the postorder, all + // other things being equal, which tends to prioritize + // loop backedges over out-edges, putting the edge-block + // closer to the loop body and minimizing live-ranges in + // linear instruction space. This heuristic doesn't have + // any effect on the computation of dominators, and is + // purely for other consumers of the postorder we cache + // here. + .rev() + // This is purely an optimization to avoid additional + // iterations of the loop, and is not required; it's + // merely inlining the check from the outer conditional + // of this case to avoid the extra loop iteration. This + // also avoids potential excess stack growth. + .filter(|block| !self.dfs.seen.contains(*block)) + .map(|block| (Event::Enter, block)), + ); + } + + Some((event, block)) + } +} + +/// An iterator that yields `ir::Block` items during a depth-first, pre-order +/// traversal over its associated function. +pub struct DfsPreOrderIter<'a>(DfsIter<'a>); + +impl Iterator for DfsPreOrderIter<'_> { + type Item = ir::Block; + + fn next(&mut self) -> Option { + loop { + match self.0.next()? { + (Event::Enter, b) => return Some(b), + (Event::Exit, _) => continue, + } + } + } +} + +/// An iterator that yields `ir::Block` items during a depth-first, post-order +/// traversal over its associated function. +pub struct DfsPostOrderIter<'a>(DfsIter<'a>); + +impl Iterator for DfsPostOrderIter<'_> { + type Item = ir::Block; + + fn next(&mut self) -> Option { + loop { + match self.0.next()? { + (Event::Exit, b) => return Some(b), + (Event::Enter, _) => continue, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cursor::{Cursor, FuncCursor}; + use crate::ir::{types::I32, Function, InstBuilder, TrapCode}; + + #[test] + fn test_dfs_traversal() { + let _ = env_logger::try_init(); + + let mut func = Function::new(); + + let block0 = func.dfg.make_block(); + let v0 = func.dfg.append_block_param(block0, I32); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let block3 = func.dfg.make_block(); + + let mut cur = FuncCursor::new(&mut func); + + // block0(v0): + // br_if v0, block2, trap_block + cur.insert_block(block0); + cur.ins().brif(v0, block2, &[], block3, &[]); + + // block3: + // trap user0 + cur.insert_block(block3); + cur.ins().trap(TrapCode::unwrap_user(1)); + + // block1: + // v1 = iconst.i32 1 + // v2 = iadd v0, v1 + // jump block0(v2) + cur.insert_block(block1); + let v1 = cur.ins().iconst(I32, 1); + let v2 = cur.ins().iadd(v0, v1); + cur.ins().jump(block0, &[v2]); + + // block2: + // return v0 + cur.insert_block(block2); + cur.ins().return_(&[v0]); + + let mut dfs = Dfs::new(); + + assert_eq!( + dfs.iter(&func).collect::>(), + vec![ + (Event::Enter, block0), + (Event::Enter, block2), + (Event::Exit, block2), + (Event::Enter, block3), + (Event::Exit, block3), + (Event::Exit, block0) + ], + ); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/unionfind.rs b/deps/crates/vendor/cranelift-codegen/src/unionfind.rs new file mode 100644 index 00000000000000..da96611ec36669 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/unionfind.rs @@ -0,0 +1,143 @@ +//! Simple union-find data structure. + +use crate::trace; +use cranelift_entity::{packed_option::ReservedValue, EntityRef, SecondaryMap}; +use std::hash::Hash; +use std::mem::swap; + +/// A union-find data structure. The data structure can allocate +/// `Idx`s, indicating eclasses, and can merge eclasses together. +/// +/// Running `union(a, b)` will change the canonical `Idx` of `a` or `b`. +/// Usually, this is chosen based on what will minimize path lengths, +/// but it is also possible to _pin_ an eclass, such that its canonical `Idx` +/// won't change unless it gets unioned with another pinned eclass. +/// +/// In the context of the egraph pass, merging two pinned eclasses +/// is very unlikely to happen – we do not know a single concrete test case +/// where it does. The only situation where it might happen looks as follows: +/// +/// 1. We encounter terms `A` and `B`, and the optimizer does not find any +/// reason to union them together. +/// 2. We encounter a term `C`, and we rewrite `C -> A`, and separately, `C -> B`. +/// +/// Unless `C` somehow includes some crucial hint without which it is hard to +/// notice that `A = B`, there's probably a rewrite rule that we should add. +/// +/// Worst case, if we do merge two pinned eclasses, some nodes will essentially +/// disappear from the GVN map, which only affects the quality of the generated +/// code. +#[derive(Clone, Debug, PartialEq)] +pub struct UnionFind { + parent: SecondaryMap>, + /// The `rank` table is used to perform the union operations optimally, + /// without creating unnecessarily long paths. Pins are represented by + /// eclasses with a rank of `u8::MAX`. + /// + /// `rank[x]` is the upper bound on the height of the subtree rooted at `x`. + /// The subtree is guaranteed to have at least `2**rank[x]` elements, + /// unless `rank` has been artificially inflated by pinning. + rank: SecondaryMap, + + pub(crate) pinned_union_count: u64, +} + +#[derive(Clone, Debug, PartialEq)] +struct Val(Idx); + +impl Default for Val { + fn default() -> Self { + Self(Idx::reserved_value()) + } +} + +impl UnionFind { + /// Create a new `UnionFind` with the given capacity. + pub fn with_capacity(cap: usize) -> Self { + UnionFind { + parent: SecondaryMap::with_capacity(cap), + rank: SecondaryMap::with_capacity(cap), + pinned_union_count: 0, + } + } + + /// Add an `Idx` to the `UnionFind`, with its own equivalence class + /// initially. All `Idx`s must be added before being queried or + /// unioned. + pub fn add(&mut self, id: Idx) { + debug_assert!(id != Idx::reserved_value()); + self.parent[id] = Val(id); + } + + /// Find the canonical `Idx` of a given `Idx`. + pub fn find(&self, mut node: Idx) -> Idx { + while node != self.parent[node].0 { + node = self.parent[node].0; + } + node + } + + /// Find the canonical `Idx` of a given `Idx`, updating the data + /// structure in the process so that future queries for this `Idx` + /// (and others in its chain up to the root of the equivalence + /// class) will be faster. + pub fn find_and_update(&mut self, mut node: Idx) -> Idx { + // "Path halving" mutating find (Tarjan and Van Leeuwen). + debug_assert!(node != Idx::reserved_value()); + while node != self.parent[node].0 { + let next = self.parent[self.parent[node].0].0; + debug_assert!(next != Idx::reserved_value()); + self.parent[node] = Val(next); + node = next; + } + debug_assert!(node != Idx::reserved_value()); + node + } + + /// Request a stable identifier for `node`. + /// + /// After an `union` operation, the canonical representative of one + /// of the eclasses being merged together necessarily changes. If a pinned + /// eclass is merged with a non-pinned eclass, it'll be the other eclass + /// whose representative will change. + /// + /// If two pinned eclasses are unioned, one of the pins gets broken, + /// which is reported in the statistics for the pass. No concrete test case + /// which triggers this is known. + pub fn pin_index(&mut self, mut node: Idx) -> Idx { + node = self.find_and_update(node); + self.rank[node] = u8::MAX; + node + } + + /// Merge the equivalence classes of the two `Idx`s. + pub fn union(&mut self, a: Idx, b: Idx) { + let mut a = self.find_and_update(a); + let mut b = self.find_and_update(b); + + if a == b { + return; + } + + if self.rank[a] < self.rank[b] { + swap(&mut a, &mut b); + } else if self.rank[a] == self.rank[b] { + self.rank[a] = self.rank[a].checked_add(1).unwrap_or_else( + #[cold] + || { + // Both `a` and `b` are pinned. + // + // This should only occur if we rewrite X -> Y and X -> Z, + // yet neither Y -> Z nor Z -> Y can be established without + // the "hint" provided by X. This probably means we're + // missing an optimization rule. + self.pinned_union_count += 1; + u8::MAX + }, + ); + } + + self.parent[b] = Val(a); + trace!("union: {}, {}", a, b); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/unreachable_code.rs b/deps/crates/vendor/cranelift-codegen/src/unreachable_code.rs new file mode 100644 index 00000000000000..71827702201a9b --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/unreachable_code.rs @@ -0,0 +1,58 @@ +//! Unreachable code elimination. + +use cranelift_entity::EntitySet; + +use crate::cursor::{Cursor, FuncCursor}; +use crate::dominator_tree::DominatorTree; +use crate::flowgraph::ControlFlowGraph; +use crate::timing; +use crate::{ir, trace}; + +/// Eliminate unreachable code. +/// +/// This pass deletes whole blocks that can't be reached from the entry block. It does not delete +/// individual instructions whose results are unused. +/// +/// The reachability analysis is performed by the dominator tree analysis. +pub fn eliminate_unreachable_code( + func: &mut ir::Function, + cfg: &mut ControlFlowGraph, + domtree: &DominatorTree, +) { + let _tt = timing::unreachable_code(); + let mut pos = FuncCursor::new(func); + let mut used_tables = EntitySet::with_capacity(pos.func.stencil.dfg.jump_tables.len()); + while let Some(block) = pos.next_block() { + if domtree.is_reachable(block) { + let inst = pos.func.layout.last_inst(block).unwrap(); + if let ir::InstructionData::BranchTable { table, .. } = pos.func.dfg.insts[inst] { + used_tables.insert(table); + } + continue; + } + + trace!("Eliminating unreachable {}", block); + // Move the cursor out of the way and make sure the next lop iteration goes to the right + // block. + pos.prev_block(); + + // Remove all instructions from `block`. + while let Some(inst) = pos.func.layout.first_inst(block) { + trace!(" - {}", pos.func.dfg.display_inst(inst)); + pos.func.layout.remove_inst(inst); + } + + // Once the block is completely empty, we can update the CFG which removes it from any + // predecessor lists. + cfg.recompute_block(pos.func, block); + + // Finally, remove the block from the layout. + pos.func.layout.remove_block(block); + } + + for (table, jt_data) in func.stencil.dfg.jump_tables.iter_mut() { + if !used_tables.contains(table) { + jt_data.clear(); + } + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/value_label.rs b/deps/crates/vendor/cranelift-codegen/src/value_label.rs new file mode 100644 index 00000000000000..e388b8aa19480d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/value_label.rs @@ -0,0 +1,32 @@ +use crate::ir::ValueLabel; +use crate::machinst::Reg; +use crate::HashMap; +use alloc::vec::Vec; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Value location range. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ValueLocRange { + /// The ValueLoc containing a ValueLabel during this range. + pub loc: LabelValueLoc, + /// The start of the range. It is an offset in the generated code. + pub start: u32, + /// The end of the range. It is an offset in the generated code. + pub end: u32, +} + +/// The particular location for a value. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum LabelValueLoc { + /// Register. + Reg(Reg), + /// Offset from the Canonical Frame Address (aka CFA). + CFAOffset(i64), +} + +/// Resulting map of Value labels and their ranges/locations. +pub type ValueLabelsRanges = HashMap>; diff --git a/deps/crates/vendor/cranelift-codegen/src/verifier/mod.rs b/deps/crates/vendor/cranelift-codegen/src/verifier/mod.rs new file mode 100644 index 00000000000000..d0a5efced6c782 --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/verifier/mod.rs @@ -0,0 +1,1941 @@ +//! A verifier for ensuring that functions are well formed. +//! It verifies: +//! +//! block integrity +//! +//! - All instructions reached from the `block_insts` iterator must belong to +//! the block as reported by `inst_block()`. +//! - Every block must end in a terminator instruction, and no other instruction +//! can be a terminator. +//! - Every value in the `block_params` iterator belongs to the block as reported by `value_block`. +//! +//! Instruction integrity +//! +//! - The instruction format must match the opcode. +//! - All result values must be created for multi-valued instructions. +//! - All referenced entities must exist. (Values, blocks, stack slots, ...) +//! - Instructions must not reference (eg. branch to) the entry block. +//! +//! SSA form +//! +//! - Values must be defined by an instruction that exists and that is inserted in +//! a block, or be an argument of an existing block. +//! - Values used by an instruction must dominate the instruction. +//! +//! Control flow graph and dominator tree integrity: +//! +//! - All predecessors in the CFG must be branches to the block. +//! - All branches to a block must be present in the CFG. +//! - A recomputed dominator tree is identical to the existing one. +//! - The entry block must not be a cold block. +//! +//! Type checking +//! +//! - Compare input and output values against the opcode's type constraints. +//! For polymorphic opcodes, determine the controlling type variable first. +//! - Branches and jumps must pass arguments to destination blocks that match the +//! expected types exactly. The number of arguments must match. +//! - All blocks in a jump table must take no arguments. +//! - Function calls are type checked against their signature. +//! - The entry block must take arguments that match the signature of the current +//! function. +//! - All return instructions must have return value operands matching the current +//! function signature. +//! +//! Global values +//! +//! - Detect cycles in global values. +//! - Detect use of 'vmctx' global value when no corresponding parameter is defined. +//! +//! Memory types +//! +//! - Ensure that struct fields are in offset order. +//! - Ensure that struct fields are completely within the overall +//! struct size, and do not overlap. +//! +//! TODO: +//! Ad hoc checking +//! +//! - Stack slot loads and stores must be in-bounds. +//! - Immediate constraints for certain opcodes, like `udiv_imm v3, 0`. +//! - `Insertlane` and `extractlane` instructions have immediate lane numbers that must be in +//! range for their polymorphic type. +//! - Swizzle and shuffle instructions take a variable number of lane arguments. The number +//! of arguments must match the destination type, and the lane indexes must be in range. + +use crate::dbg::DisplayList; +use crate::dominator_tree::DominatorTree; +use crate::entity::SparseSet; +use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; +use crate::ir::entities::AnyEntity; +use crate::ir::instructions::{CallInfo, InstructionFormat, ResolvedConstraint}; +use crate::ir::{self, ArgumentExtension}; +use crate::ir::{ + types, ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue, + Inst, JumpTable, MemFlags, MemoryTypeData, Opcode, SigRef, StackSlot, Type, Value, ValueDef, + ValueList, +}; +use crate::isa::TargetIsa; +use crate::iterators::IteratorExtras; +use crate::print_errors::pretty_verifier_error; +use crate::settings::FlagsOrIsa; +use crate::timing; +use alloc::collections::BTreeSet; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt::{self, Display, Formatter}; + +/// A verifier error. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct VerifierError { + /// The entity causing the verifier error. + pub location: AnyEntity, + /// Optionally provide some context for the given location; e.g., for `inst42` provide + /// `Some("v3 = iconst.i32 0")` for more comprehensible errors. + pub context: Option, + /// The error message. + pub message: String, +} + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for VerifierError {} + +impl Display for VerifierError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match &self.context { + None => write!(f, "{}: {}", self.location, self.message), + Some(context) => write!(f, "{} ({}): {}", self.location, context, self.message), + } + } +} + +/// Convenience converter for making error-reporting less verbose. +/// +/// Converts a tuple of `(location, context, message)` to a `VerifierError`. +/// ``` +/// use cranelift_codegen::verifier::VerifierErrors; +/// use cranelift_codegen::ir::Inst; +/// let mut errors = VerifierErrors::new(); +/// errors.report((Inst::from_u32(42), "v3 = iadd v1, v2", "iadd cannot be used with values of this type")); +/// // note the double parenthenses to use this syntax +/// ``` +impl From<(L, C, M)> for VerifierError +where + L: Into, + C: Into, + M: Into, +{ + fn from(items: (L, C, M)) -> Self { + let (location, context, message) = items; + Self { + location: location.into(), + context: Some(context.into()), + message: message.into(), + } + } +} + +/// Convenience converter for making error-reporting less verbose. +/// +/// Same as above but without `context`. +impl From<(L, M)> for VerifierError +where + L: Into, + M: Into, +{ + fn from(items: (L, M)) -> Self { + let (location, message) = items; + Self { + location: location.into(), + context: None, + message: message.into(), + } + } +} + +/// Result of a step in the verification process. +/// +/// Functions that return `VerifierStepResult` should also take a +/// mutable reference to `VerifierErrors` as argument in order to report +/// errors. +/// +/// Here, `Ok` represents a step that **did not lead to a fatal error**, +/// meaning that the verification process may continue. However, other (non-fatal) +/// errors might have been reported through the previously mentioned `VerifierErrors` +/// argument. +pub type VerifierStepResult = Result<(), ()>; + +/// Result of a verification operation. +/// +/// Unlike `VerifierStepResult` which may be `Ok` while still having reported +/// errors, this type always returns `Err` if an error (fatal or not) was reported. +pub type VerifierResult = Result; + +/// List of verifier errors. +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct VerifierErrors(pub Vec); + +// This is manually implementing Error and Display instead of using thiserror to reduce the amount +// of dependencies used by Cranelift. +impl std::error::Error for VerifierErrors {} + +impl VerifierErrors { + /// Return a new `VerifierErrors` struct. + #[inline] + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Return whether no errors were reported. + #[inline] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Return whether one or more errors were reported. + #[inline] + pub fn has_error(&self) -> bool { + !self.0.is_empty() + } + + /// Return a `VerifierStepResult` that is fatal if at least one error was reported, + /// and non-fatal otherwise. + #[inline] + pub fn as_result(&self) -> VerifierStepResult { + if self.is_empty() { + Ok(()) + } else { + Err(()) + } + } + + /// Report an error, adding it to the list of errors. + pub fn report(&mut self, error: impl Into) { + self.0.push(error.into()); + } + + /// Report a fatal error and return `Err`. + pub fn fatal(&mut self, error: impl Into) -> VerifierStepResult { + self.report(error); + Err(()) + } + + /// Report a non-fatal error and return `Ok`. + pub fn nonfatal(&mut self, error: impl Into) -> VerifierStepResult { + self.report(error); + Ok(()) + } +} + +impl From> for VerifierErrors { + fn from(v: Vec) -> Self { + Self(v) + } +} + +impl Into> for VerifierErrors { + fn into(self) -> Vec { + self.0 + } +} + +impl Into> for VerifierErrors { + fn into(self) -> VerifierResult<()> { + if self.is_empty() { + Ok(()) + } else { + Err(self) + } + } +} + +impl Display for VerifierErrors { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + for err in &self.0 { + writeln!(f, "- {err}")?; + } + Ok(()) + } +} + +/// Verify `func`. +pub fn verify_function<'a, FOI: Into>>( + func: &Function, + fisa: FOI, +) -> VerifierResult<()> { + let _tt = timing::verifier(); + let mut errors = VerifierErrors::default(); + let verifier = Verifier::new(func, fisa.into()); + let result = verifier.run(&mut errors); + if errors.is_empty() { + result.unwrap(); + Ok(()) + } else { + Err(errors) + } +} + +/// Verify `func` after checking the integrity of associated context data structures `cfg` and +/// `domtree`. +pub fn verify_context<'a, FOI: Into>>( + func: &Function, + cfg: &ControlFlowGraph, + domtree: &DominatorTree, + fisa: FOI, + errors: &mut VerifierErrors, +) -> VerifierStepResult { + let _tt = timing::verifier(); + let verifier = Verifier::new(func, fisa.into()); + if cfg.is_valid() { + verifier.cfg_integrity(cfg, errors)?; + } + if domtree.is_valid() { + verifier.domtree_integrity(domtree, errors)?; + } + verifier.run(errors) +} + +struct Verifier<'a> { + func: &'a Function, + expected_cfg: ControlFlowGraph, + expected_domtree: DominatorTree, + isa: Option<&'a dyn TargetIsa>, +} + +impl<'a> Verifier<'a> { + pub fn new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self { + let expected_cfg = ControlFlowGraph::with_function(func); + let expected_domtree = DominatorTree::with_function(func, &expected_cfg); + Self { + func, + expected_cfg, + expected_domtree, + isa: fisa.isa, + } + } + + /// Determine a contextual error string for an instruction. + #[inline] + fn context(&self, inst: Inst) -> String { + self.func.dfg.display_inst(inst).to_string() + } + + // Check for: + // - cycles in the global value declarations. + // - use of 'vmctx' when no special parameter declares it. + fn verify_global_values(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + let mut cycle_seen = false; + let mut seen = SparseSet::new(); + + 'gvs: for gv in self.func.global_values.keys() { + seen.clear(); + seen.insert(gv); + + let mut cur = gv; + loop { + match self.func.global_values[cur] { + ir::GlobalValueData::Load { base, .. } + | ir::GlobalValueData::IAddImm { base, .. } => { + if seen.insert(base).is_some() { + if !cycle_seen { + errors.report(( + gv, + format!("global value cycle: {}", DisplayList(seen.as_slice())), + )); + // ensures we don't report the cycle multiple times + cycle_seen = true; + } + continue 'gvs; + } + + cur = base; + } + _ => break, + } + } + + match self.func.global_values[gv] { + ir::GlobalValueData::VMContext { .. } => { + if self + .func + .special_param(ir::ArgumentPurpose::VMContext) + .is_none() + { + errors.report((gv, format!("undeclared vmctx reference {gv}"))); + } + } + ir::GlobalValueData::IAddImm { + base, global_type, .. + } => { + if !global_type.is_int() { + errors.report(( + gv, + format!("iadd_imm global value with non-int type {global_type}"), + )); + } else if let Some(isa) = self.isa { + let base_type = self.func.global_values[base].global_type(isa); + if global_type != base_type { + errors.report(( + gv, + format!( + "iadd_imm type {global_type} differs from operand type {base_type}" + ), + )); + } + } + } + ir::GlobalValueData::Load { base, .. } => { + if let Some(isa) = self.isa { + let base_type = self.func.global_values[base].global_type(isa); + let pointer_type = isa.pointer_type(); + if base_type != pointer_type { + errors.report(( + gv, + format!( + "base {base} has type {base_type}, which is not the pointer type {pointer_type}" + ), + )); + } + } + } + _ => {} + } + } + + // Invalid global values shouldn't stop us from verifying the rest of the function + Ok(()) + } + + fn verify_memory_types(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + // Verify that all fields are statically-sized and lie within + // the struct, do not overlap, and are in offset order + for (mt, mt_data) in &self.func.memory_types { + match mt_data { + MemoryTypeData::Struct { size, fields } => { + let mut last_offset = 0; + for field in fields { + if field.offset < last_offset { + errors.report(( + mt, + format!( + "memory type {} has a field at offset {}, which is out-of-order", + mt, field.offset + ), + )); + } + last_offset = match field.offset.checked_add(u64::from(field.ty.bytes())) { + Some(o) => o, + None => { + errors.report(( + mt, + format!( + "memory type {} has a field at offset {} of size {}; offset plus size overflows a u64", + mt, field.offset, field.ty.bytes()), + )); + break; + } + }; + + if last_offset > *size { + errors.report(( + mt, + format!( + "memory type {} has a field at offset {} of size {} that overflows the struct size {}", + mt, field.offset, field.ty.bytes(), *size), + )); + } + } + } + _ => {} + } + } + + Ok(()) + } + + /// Check that the given block can be encoded as a BB, by checking that only + /// branching instructions are ending the block. + fn encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult { + match self.func.is_block_basic(block) { + Ok(()) => Ok(()), + Err((inst, message)) => errors.fatal((inst, self.context(inst), message)), + } + } + + fn block_integrity( + &self, + block: Block, + inst: Inst, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let is_terminator = self.func.dfg.insts[inst].opcode().is_terminator(); + let is_last_inst = self.func.layout.last_inst(block) == Some(inst); + + if is_terminator && !is_last_inst { + // Terminating instructions only occur at the end of blocks. + return errors.fatal(( + inst, + self.context(inst), + format!("a terminator instruction was encountered before the end of {block}"), + )); + } + if is_last_inst && !is_terminator { + return errors.fatal((block, "block does not end in a terminator instruction")); + } + + // Instructions belong to the correct block. + let inst_block = self.func.layout.inst_block(inst); + if inst_block != Some(block) { + return errors.fatal(( + inst, + self.context(inst), + format!("should belong to {block} not {inst_block:?}"), + )); + } + + // Parameters belong to the correct block. + for &arg in self.func.dfg.block_params(block) { + match self.func.dfg.value_def(arg) { + ValueDef::Param(arg_block, _) => { + if block != arg_block { + return errors.fatal((arg, format!("does not belong to {block}"))); + } + } + _ => { + return errors.fatal((arg, "expected an argument, found a result")); + } + } + } + + Ok(()) + } + + fn instruction_integrity(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + let inst_data = &self.func.dfg.insts[inst]; + let dfg = &self.func.dfg; + + // The instruction format matches the opcode + if inst_data.opcode().format() != InstructionFormat::from(inst_data) { + return errors.fatal(( + inst, + self.context(inst), + "instruction opcode doesn't match instruction format", + )); + } + + let expected_num_results = dfg.num_expected_results_for_verifier(inst); + + // All result values for multi-valued instructions are created + let got_results = dfg.inst_results(inst).len(); + if got_results != expected_num_results { + return errors.fatal(( + inst, + self.context(inst), + format!("expected {expected_num_results} result values, found {got_results}"), + )); + } + + self.verify_entity_references(inst, errors) + } + + fn verify_entity_references( + &self, + inst: Inst, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + use crate::ir::instructions::InstructionData::*; + + for arg in self.func.dfg.inst_values(inst) { + self.verify_inst_arg(inst, arg, errors)?; + + // All used values must be attached to something. + let original = self.func.dfg.resolve_aliases(arg); + if !self.func.dfg.value_is_attached(original) { + errors.report(( + inst, + self.context(inst), + format!("argument {arg} -> {original} is not attached"), + )); + } + } + + for &res in self.func.dfg.inst_results(inst) { + self.verify_inst_result(inst, res, errors)?; + } + + match self.func.dfg.insts[inst] { + MultiAry { ref args, .. } => { + self.verify_value_list(inst, args, errors)?; + } + Jump { destination, .. } => { + self.verify_block(inst, destination.block(&self.func.dfg.value_lists), errors)?; + } + Brif { + arg, + blocks: [block_then, block_else], + .. + } => { + self.verify_value(inst, arg, errors)?; + self.verify_block(inst, block_then.block(&self.func.dfg.value_lists), errors)?; + self.verify_block(inst, block_else.block(&self.func.dfg.value_lists), errors)?; + } + BranchTable { table, .. } => { + self.verify_jump_table(inst, table, errors)?; + } + Call { + func_ref, ref args, .. + } => { + self.verify_func_ref(inst, func_ref, errors)?; + self.verify_value_list(inst, args, errors)?; + } + CallIndirect { + sig_ref, ref args, .. + } => { + self.verify_sig_ref(inst, sig_ref, errors)?; + self.verify_value_list(inst, args, errors)?; + } + FuncAddr { func_ref, .. } => { + self.verify_func_ref(inst, func_ref, errors)?; + } + StackLoad { stack_slot, .. } | StackStore { stack_slot, .. } => { + self.verify_stack_slot(inst, stack_slot, errors)?; + } + DynamicStackLoad { + dynamic_stack_slot, .. + } + | DynamicStackStore { + dynamic_stack_slot, .. + } => { + self.verify_dynamic_stack_slot(inst, dynamic_stack_slot, errors)?; + } + UnaryGlobalValue { global_value, .. } => { + self.verify_global_value(inst, global_value, errors)?; + } + NullAry { + opcode: Opcode::GetPinnedReg, + } + | Unary { + opcode: Opcode::SetPinnedReg, + .. + } => { + if let Some(isa) = &self.isa { + if !isa.flags().enable_pinned_reg() { + return errors.fatal(( + inst, + self.context(inst), + "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg", + )); + } + } else { + return errors.fatal(( + inst, + self.context(inst), + "GetPinnedReg/SetPinnedReg need an ISA!", + )); + } + } + NullAry { + opcode: Opcode::GetFramePointer | Opcode::GetReturnAddress, + } => { + if let Some(isa) = &self.isa { + // Backends may already rely on this check implicitly, so do + // not relax it without verifying that it is safe to do so. + if !isa.flags().preserve_frame_pointers() { + return errors.fatal(( + inst, + self.context(inst), + "`get_frame_pointer`/`get_return_address` cannot be used without \ + enabling `preserve_frame_pointers`", + )); + } + } else { + return errors.fatal(( + inst, + self.context(inst), + "`get_frame_pointer`/`get_return_address` require an ISA!", + )); + } + } + LoadNoOffset { + opcode: Opcode::Bitcast, + flags, + arg, + } => { + self.verify_bitcast(inst, flags, arg, errors)?; + } + UnaryConst { + opcode: opcode @ (Opcode::Vconst | Opcode::F128const), + constant_handle, + .. + } => { + self.verify_constant_size(inst, opcode, constant_handle, errors)?; + } + + // Exhaustive list so we can't forget to add new formats + AtomicCas { .. } + | AtomicRmw { .. } + | LoadNoOffset { .. } + | StoreNoOffset { .. } + | Unary { .. } + | UnaryConst { .. } + | UnaryImm { .. } + | UnaryIeee16 { .. } + | UnaryIeee32 { .. } + | UnaryIeee64 { .. } + | Binary { .. } + | BinaryImm8 { .. } + | BinaryImm64 { .. } + | Ternary { .. } + | TernaryImm8 { .. } + | Shuffle { .. } + | IntAddTrap { .. } + | IntCompare { .. } + | IntCompareImm { .. } + | FloatCompare { .. } + | Load { .. } + | Store { .. } + | Trap { .. } + | CondTrap { .. } + | NullAry { .. } => {} + } + + Ok(()) + } + + fn verify_block( + &self, + loc: impl Into, + e: Block, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.dfg.block_is_valid(e) || !self.func.layout.is_block_inserted(e) { + return errors.fatal((loc, format!("invalid block reference {e}"))); + } + if let Some(entry_block) = self.func.layout.entry_block() { + if e == entry_block { + return errors.fatal((loc, format!("invalid reference to entry block {e}"))); + } + } + Ok(()) + } + + fn verify_sig_ref( + &self, + inst: Inst, + s: SigRef, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.dfg.signatures.is_valid(s) { + errors.fatal(( + inst, + self.context(inst), + format!("invalid signature reference {s}"), + )) + } else { + Ok(()) + } + } + + fn verify_func_ref( + &self, + inst: Inst, + f: FuncRef, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.dfg.ext_funcs.is_valid(f) { + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid function reference {f}"), + )) + } else { + Ok(()) + } + } + + fn verify_stack_slot( + &self, + inst: Inst, + ss: StackSlot, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.sized_stack_slots.is_valid(ss) { + errors.nonfatal((inst, self.context(inst), format!("invalid stack slot {ss}"))) + } else { + Ok(()) + } + } + + fn verify_dynamic_stack_slot( + &self, + inst: Inst, + ss: DynamicStackSlot, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.dynamic_stack_slots.is_valid(ss) { + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid dynamic stack slot {ss}"), + )) + } else { + Ok(()) + } + } + + fn verify_global_value( + &self, + inst: Inst, + gv: GlobalValue, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.global_values.is_valid(gv) { + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid global value {gv}"), + )) + } else { + Ok(()) + } + } + + fn verify_value_list( + &self, + inst: Inst, + l: &ValueList, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !l.is_valid(&self.func.dfg.value_lists) { + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid value list reference {l:?}"), + )) + } else { + Ok(()) + } + } + + fn verify_jump_table( + &self, + inst: Inst, + j: JumpTable, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + if !self.func.stencil.dfg.jump_tables.is_valid(j) { + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid jump table reference {j}"), + )) + } else { + let pool = &self.func.stencil.dfg.value_lists; + for block in self.func.stencil.dfg.jump_tables[j].all_branches() { + self.verify_block(inst, block.block(pool), errors)?; + } + Ok(()) + } + } + + fn verify_value( + &self, + loc_inst: Inst, + v: Value, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let dfg = &self.func.dfg; + if !dfg.value_is_valid(v) { + errors.nonfatal(( + loc_inst, + self.context(loc_inst), + format!("invalid value reference {v}"), + )) + } else { + Ok(()) + } + } + + fn verify_inst_arg( + &self, + loc_inst: Inst, + v: Value, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + self.verify_value(loc_inst, v, errors)?; + + let dfg = &self.func.dfg; + let loc_block = self + .func + .layout + .inst_block(loc_inst) + .expect("Instruction not in layout."); + let is_reachable = self.expected_domtree.is_reachable(loc_block); + + // SSA form + match dfg.value_def(v) { + ValueDef::Result(def_inst, _) => { + // Value is defined by an instruction that exists. + if !dfg.inst_is_valid(def_inst) { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("{v} is defined by invalid instruction {def_inst}"), + )); + } + // Defining instruction is inserted in a block. + if self.func.layout.inst_block(def_inst) == None { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("{v} is defined by {def_inst} which has no block"), + )); + } + // Defining instruction dominates the instruction that uses the value. + if is_reachable { + if !self + .expected_domtree + .dominates(def_inst, loc_inst, &self.func.layout) + { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("uses value {v} from non-dominating {def_inst}"), + )); + } + if def_inst == loc_inst { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("uses value {v} from itself"), + )); + } + } + } + ValueDef::Param(block, _) => { + // Value is defined by an existing block. + if !dfg.block_is_valid(block) { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("{v} is defined by invalid block {block}"), + )); + } + // Defining block is inserted in the layout + if !self.func.layout.is_block_inserted(block) { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("{v} is defined by {block} which is not in the layout"), + )); + } + // The defining block dominates the instruction using this value. + if is_reachable + && !self + .expected_domtree + .dominates(block, loc_inst, &self.func.layout) + { + return errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("uses value arg from non-dominating {block}"), + )); + } + } + ValueDef::Union(_, _) => { + // Nothing: union nodes themselves have no location, + // so we cannot check any dominance properties. + } + } + Ok(()) + } + + fn verify_inst_result( + &self, + loc_inst: Inst, + v: Value, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + self.verify_value(loc_inst, v, errors)?; + + match self.func.dfg.value_def(v) { + ValueDef::Result(def_inst, _) => { + if def_inst != loc_inst { + errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("instruction result {v} is not defined by the instruction"), + )) + } else { + Ok(()) + } + } + ValueDef::Param(_, _) => errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("instruction result {v} is not defined by the instruction"), + )), + ValueDef::Union(_, _) => errors.fatal(( + loc_inst, + self.context(loc_inst), + format!("instruction result {v} is a union node"), + )), + } + } + + fn verify_bitcast( + &self, + inst: Inst, + flags: MemFlags, + arg: Value, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let typ = self.func.dfg.ctrl_typevar(inst); + let value_type = self.func.dfg.value_type(arg); + + if typ.bits() != value_type.bits() { + errors.fatal(( + inst, + format!( + "The bitcast argument {} has a type of {} bits, which doesn't match an expected type of {} bits", + arg, + value_type.bits(), + typ.bits() + ), + )) + } else if flags != MemFlags::new() + && flags != MemFlags::new().with_endianness(ir::Endianness::Little) + && flags != MemFlags::new().with_endianness(ir::Endianness::Big) + { + errors.fatal(( + inst, + "The bitcast instruction only accepts the `big` or `little` memory flags", + )) + } else if flags == MemFlags::new() && typ.lane_count() != value_type.lane_count() { + errors.fatal(( + inst, + "Byte order specifier required for bitcast instruction changing lane count", + )) + } else { + Ok(()) + } + } + + fn verify_constant_size( + &self, + inst: Inst, + opcode: Opcode, + constant: Constant, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let type_size = match opcode { + Opcode::F128const => types::F128.bytes(), + Opcode::Vconst => self.func.dfg.ctrl_typevar(inst).bytes(), + _ => unreachable!("unexpected opcode {opcode:?}"), + } as usize; + let constant_size = self.func.dfg.constants.get(constant).len(); + if type_size != constant_size { + errors.fatal(( + inst, + format!( + "The instruction expects {constant} to have a size of {type_size} bytes but it has {constant_size}" + ), + )) + } else { + Ok(()) + } + } + + fn domtree_integrity( + &self, + domtree: &DominatorTree, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + // We consider two `DominatorTree`s to be equal if they return the same immediate + // dominator for each block. Therefore the current domtree is valid if it matches the freshly + // computed one. + for block in self.func.layout.blocks() { + let expected = self.expected_domtree.idom(block); + let got = domtree.idom(block); + if got != expected { + return errors.fatal(( + block, + format!("invalid domtree, expected idom({block}) = {expected:?}, got {got:?}"), + )); + } + } + // We also verify if the postorder defined by `DominatorTree` is sane + if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() { + return errors.fatal(( + AnyEntity::Function, + "incorrect number of Blocks in postorder traversal", + )); + } + for (index, (&test_block, &true_block)) in domtree + .cfg_postorder() + .iter() + .zip(self.expected_domtree.cfg_postorder().iter()) + .enumerate() + { + if test_block != true_block { + return errors.fatal(( + test_block, + format!( + "invalid domtree, postorder block number {index} should be {true_block}, got {test_block}" + ), + )); + } + } + // We verify rpo_cmp_block on pairs of adjacent blocks in the postorder + for (&prev_block, &next_block) in domtree.cfg_postorder().iter().adjacent_pairs() { + if self.expected_domtree.rpo_cmp_block(prev_block, next_block) != Ordering::Greater { + return errors.fatal(( + next_block, + format!( + "invalid domtree, rpo_cmp_block does not say {} is greater than {}; rpo = {:#?}", + prev_block, next_block, domtree.cfg_postorder() + ), + )); + } + } + Ok(()) + } + + fn typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + if let Some(block) = self.func.layout.entry_block() { + let expected_types = &self.func.signature.params; + let block_param_count = self.func.dfg.num_block_params(block); + + if block_param_count != expected_types.len() { + return errors.fatal(( + block, + format!( + "entry block parameters ({}) must match function signature ({})", + block_param_count, + expected_types.len() + ), + )); + } + + for (i, &arg) in self.func.dfg.block_params(block).iter().enumerate() { + let arg_type = self.func.dfg.value_type(arg); + if arg_type != expected_types[i].value_type { + errors.report(( + block, + format!( + "entry block parameter {} expected to have type {}, got {}", + i, expected_types[i], arg_type + ), + )); + } + } + } + + errors.as_result() + } + + fn check_entry_not_cold(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + if let Some(entry_block) = self.func.layout.entry_block() { + if self.func.layout.is_cold(entry_block) { + return errors + .fatal((entry_block, format!("entry block cannot be marked as cold"))); + } + } + errors.as_result() + } + + fn typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + let inst_data = &self.func.dfg.insts[inst]; + let constraints = inst_data.opcode().constraints(); + + let ctrl_type = if let Some(value_typeset) = constraints.ctrl_typeset() { + // For polymorphic opcodes, determine the controlling type variable first. + let ctrl_type = self.func.dfg.ctrl_typevar(inst); + + if !value_typeset.contains(ctrl_type) { + errors.report(( + inst, + self.context(inst), + format!( + "has an invalid controlling type {ctrl_type} (allowed set is {value_typeset:?})" + ), + )); + } + + ctrl_type + } else { + // Non-polymorphic instructions don't check the controlling type variable, so `Option` + // is unnecessary and we can just make it `INVALID`. + types::INVALID + }; + + // Typechecking instructions is never fatal + let _ = self.typecheck_results(inst, ctrl_type, errors); + let _ = self.typecheck_fixed_args(inst, ctrl_type, errors); + let _ = self.typecheck_variable_args(inst, errors); + let _ = self.typecheck_return(inst, errors); + let _ = self.typecheck_special(inst, errors); + + Ok(()) + } + + fn typecheck_results( + &self, + inst: Inst, + ctrl_type: Type, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let mut i = 0; + for &result in self.func.dfg.inst_results(inst) { + let result_type = self.func.dfg.value_type(result); + let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type); + if let Some(expected_type) = expected_type { + if result_type != expected_type { + errors.report(( + inst, + self.context(inst), + format!( + "expected result {i} ({result}) to have type {expected_type}, found {result_type}" + ), + )); + } + } else { + return errors.nonfatal(( + inst, + self.context(inst), + "has more result values than expected", + )); + } + i += 1; + } + + // There aren't any more result types left. + if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None { + return errors.nonfatal(( + inst, + self.context(inst), + "has fewer result values than expected", + )); + } + Ok(()) + } + + fn typecheck_fixed_args( + &self, + inst: Inst, + ctrl_type: Type, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let constraints = self.func.dfg.insts[inst].opcode().constraints(); + + for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() { + let arg_type = self.func.dfg.value_type(arg); + match constraints.value_argument_constraint(i, ctrl_type) { + ResolvedConstraint::Bound(expected_type) => { + if arg_type != expected_type { + errors.report(( + inst, + self.context(inst), + format!( + "arg {i} ({arg}) has type {arg_type}, expected {expected_type}" + ), + )); + } + } + ResolvedConstraint::Free(type_set) => { + if !type_set.contains(arg_type) { + errors.report(( + inst, + self.context(inst), + format!( + "arg {i} ({arg}) with type {arg_type} failed to satisfy type set {type_set:?}" + ), + )); + } + } + } + } + Ok(()) + } + + /// Typecheck both instructions that contain variable arguments like calls, and those that + /// include references to basic blocks with their arguments. + fn typecheck_variable_args( + &self, + inst: Inst, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + match &self.func.dfg.insts[inst] { + ir::InstructionData::Jump { destination, .. } => { + self.typecheck_block_call(inst, destination, errors)?; + } + ir::InstructionData::Brif { + blocks: [block_then, block_else], + .. + } => { + self.typecheck_block_call(inst, block_then, errors)?; + self.typecheck_block_call(inst, block_else, errors)?; + } + ir::InstructionData::BranchTable { table, .. } => { + for block in self.func.stencil.dfg.jump_tables[*table].all_branches() { + self.typecheck_block_call(inst, block, errors)?; + } + } + inst => debug_assert!(!inst.opcode().is_branch()), + } + + match self.func.dfg.insts[inst].analyze_call(&self.func.dfg.value_lists) { + CallInfo::Direct(func_ref, args) => { + let sig_ref = self.func.dfg.ext_funcs[func_ref].signature; + let arg_types = self.func.dfg.signatures[sig_ref] + .params + .iter() + .map(|a| a.value_type); + self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?; + } + CallInfo::Indirect(sig_ref, args) => { + let arg_types = self.func.dfg.signatures[sig_ref] + .params + .iter() + .map(|a| a.value_type); + self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?; + } + CallInfo::NotACall => {} + } + Ok(()) + } + + fn typecheck_block_call( + &self, + inst: Inst, + block: &ir::BlockCall, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let pool = &self.func.dfg.value_lists; + let iter = self + .func + .dfg + .block_params(block.block(pool)) + .iter() + .map(|&v| self.func.dfg.value_type(v)); + let args = block.args_slice(pool); + self.typecheck_variable_args_iterator(inst, iter, args, errors) + } + + fn typecheck_variable_args_iterator>( + &self, + inst: Inst, + iter: I, + variable_args: &[Value], + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let mut i = 0; + + for expected_type in iter { + if i >= variable_args.len() { + // Result count mismatch handled below, we want the full argument count first though + i += 1; + continue; + } + let arg = variable_args[i]; + let arg_type = self.func.dfg.value_type(arg); + if expected_type != arg_type { + errors.report(( + inst, + self.context(inst), + format!( + "arg {} ({}) has type {}, expected {}", + i, variable_args[i], arg_type, expected_type + ), + )); + } + i += 1; + } + if i != variable_args.len() { + return errors.nonfatal(( + inst, + self.context(inst), + format!( + "mismatched argument count for `{}`: got {}, expected {}", + self.func.dfg.display_inst(inst), + variable_args.len(), + i, + ), + )); + } + Ok(()) + } + + fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + match self.func.dfg.insts[inst] { + ir::InstructionData::MultiAry { + opcode: Opcode::Return, + args, + } => { + let types = args + .as_slice(&self.func.dfg.value_lists) + .iter() + .map(|v| self.func.dfg.value_type(*v)); + self.typecheck_return_types( + inst, + types, + errors, + "arguments of return must match function signature", + )?; + } + ir::InstructionData::Call { + opcode: Opcode::ReturnCall, + func_ref, + .. + } => { + let sig_ref = self.func.dfg.ext_funcs[func_ref].signature; + self.typecheck_tail_call(inst, sig_ref, errors)?; + } + ir::InstructionData::CallIndirect { + opcode: Opcode::ReturnCallIndirect, + sig_ref, + .. + } => { + self.typecheck_tail_call(inst, sig_ref, errors)?; + } + inst => debug_assert!(!inst.opcode().is_return()), + } + Ok(()) + } + + fn typecheck_tail_call( + &self, + inst: Inst, + sig_ref: SigRef, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let signature = &self.func.dfg.signatures[sig_ref]; + let cc = signature.call_conv; + if !cc.supports_tail_calls() { + errors.report(( + inst, + self.context(inst), + format!("calling convention `{cc}` does not support tail calls"), + )); + } + if cc != self.func.signature.call_conv { + errors.report(( + inst, + self.context(inst), + "callee's calling convention must match caller", + )); + } + let types = signature.returns.iter().map(|param| param.value_type); + self.typecheck_return_types(inst, types, errors, "results of callee must match caller")?; + Ok(()) + } + + fn typecheck_return_types( + &self, + inst: Inst, + actual_types: impl ExactSizeIterator, + errors: &mut VerifierErrors, + message: &str, + ) -> VerifierStepResult { + let expected_types = &self.func.signature.returns; + if actual_types.len() != expected_types.len() { + return errors.nonfatal((inst, self.context(inst), message)); + } + for (i, (actual_type, &expected_type)) in actual_types.zip(expected_types).enumerate() { + if actual_type != expected_type.value_type { + errors.report(( + inst, + self.context(inst), + format!( + "result {i} has type {actual_type}, must match function signature of \ + {expected_type}" + ), + )); + } + } + Ok(()) + } + + // Check special-purpose type constraints that can't be expressed in the normal opcode + // constraints. + fn typecheck_special(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + match self.func.dfg.insts[inst] { + ir::InstructionData::UnaryGlobalValue { global_value, .. } => { + if let Some(isa) = self.isa { + let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst)); + let global_type = self.func.global_values[global_value].global_type(isa); + if inst_type != global_type { + return errors.nonfatal(( + inst, self.context(inst), + format!( + "global_value instruction with type {inst_type} references global value with type {global_type}" + )), + ); + } + } + } + _ => {} + } + Ok(()) + } + + fn cfg_integrity( + &self, + cfg: &ControlFlowGraph, + errors: &mut VerifierErrors, + ) -> VerifierStepResult { + let mut expected_succs = BTreeSet::::new(); + let mut got_succs = BTreeSet::::new(); + let mut expected_preds = BTreeSet::::new(); + let mut got_preds = BTreeSet::::new(); + + for block in self.func.layout.blocks() { + expected_succs.extend(self.expected_cfg.succ_iter(block)); + got_succs.extend(cfg.succ_iter(block)); + + let missing_succs: Vec = + expected_succs.difference(&got_succs).cloned().collect(); + if !missing_succs.is_empty() { + errors.report(( + block, + format!("cfg lacked the following successor(s) {missing_succs:?}"), + )); + continue; + } + + let excess_succs: Vec = got_succs.difference(&expected_succs).cloned().collect(); + if !excess_succs.is_empty() { + errors.report(( + block, + format!("cfg had unexpected successor(s) {excess_succs:?}"), + )); + continue; + } + + expected_preds.extend( + self.expected_cfg + .pred_iter(block) + .map(|BlockPredecessor { inst, .. }| inst), + ); + got_preds.extend( + cfg.pred_iter(block) + .map(|BlockPredecessor { inst, .. }| inst), + ); + + let missing_preds: Vec = expected_preds.difference(&got_preds).cloned().collect(); + if !missing_preds.is_empty() { + errors.report(( + block, + format!("cfg lacked the following predecessor(s) {missing_preds:?}"), + )); + continue; + } + + let excess_preds: Vec = got_preds.difference(&expected_preds).cloned().collect(); + if !excess_preds.is_empty() { + errors.report(( + block, + format!("cfg had unexpected predecessor(s) {excess_preds:?}"), + )); + continue; + } + + expected_succs.clear(); + got_succs.clear(); + expected_preds.clear(); + got_preds.clear(); + } + errors.as_result() + } + + fn immediate_constraints(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + let inst_data = &self.func.dfg.insts[inst]; + + match *inst_data { + ir::InstructionData::Store { flags, .. } => { + if flags.readonly() { + errors.fatal(( + inst, + self.context(inst), + "A store instruction cannot have the `readonly` MemFlag", + )) + } else { + Ok(()) + } + } + ir::InstructionData::BinaryImm8 { + opcode: ir::instructions::Opcode::Extractlane, + imm: lane, + arg, + .. + } + | ir::InstructionData::TernaryImm8 { + opcode: ir::instructions::Opcode::Insertlane, + imm: lane, + args: [arg, _], + .. + } => { + // We must be specific about the opcodes above because other instructions are using + // the same formats. + let ty = self.func.dfg.value_type(arg); + if lane as u32 >= ty.lane_count() { + errors.fatal(( + inst, + self.context(inst), + format!("The lane {lane} does not index into the type {ty}",), + )) + } else { + Ok(()) + } + } + ir::InstructionData::Shuffle { + opcode: ir::instructions::Opcode::Shuffle, + imm, + .. + } => { + let imm = self.func.dfg.immediates.get(imm).unwrap().as_slice(); + if imm.len() != 16 { + errors.fatal(( + inst, + self.context(inst), + format!("the shuffle immediate wasn't 16-bytes long"), + )) + } else if let Some(i) = imm.iter().find(|i| **i >= 32) { + errors.fatal(( + inst, + self.context(inst), + format!("shuffle immediate index {i} is larger than the maximum 31"), + )) + } else { + Ok(()) + } + } + _ => Ok(()), + } + } + + fn iconst_bounds(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult { + use crate::ir::instructions::InstructionData::UnaryImm; + + let inst_data = &self.func.dfg.insts[inst]; + if let UnaryImm { + opcode: Opcode::Iconst, + imm, + } = inst_data + { + let ctrl_typevar = self.func.dfg.ctrl_typevar(inst); + let bounds_mask = match ctrl_typevar { + types::I8 => u8::MAX.into(), + types::I16 => u16::MAX.into(), + types::I32 => u32::MAX.into(), + types::I64 => u64::MAX, + _ => unreachable!(), + }; + + let value = imm.bits() as u64; + if value & bounds_mask != value { + errors.fatal(( + inst, + self.context(inst), + "constant immediate is out of bounds", + )) + } else { + Ok(()) + } + } else { + Ok(()) + } + } + + fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + let params = self + .func + .signature + .params + .iter() + .enumerate() + .map(|p| (true, p)); + let returns = self + .func + .signature + .returns + .iter() + .enumerate() + .map(|p| (false, p)); + + for (is_argument, (i, param)) in params.chain(returns) { + let is_return = !is_argument; + let item = if is_argument { + "Parameter" + } else { + "Return value" + }; + + if param.value_type == types::INVALID { + errors.report(( + AnyEntity::Function, + format!("{item} at position {i} has an invalid type"), + )); + } + + if let ArgumentPurpose::StructArgument(_) = param.purpose { + if is_return { + errors.report(( + AnyEntity::Function, + format!("{item} at position {i} can't be an struct argument"), + )) + } + } + + let ty_allows_extension = param.value_type.is_int(); + let has_extension = param.extension != ArgumentExtension::None; + if !ty_allows_extension && has_extension { + errors.report(( + AnyEntity::Function, + format!( + "{} at position {} has invalid extension {:?}", + item, i, param.extension + ), + )); + } + } + + if errors.has_error() { + Err(()) + } else { + Ok(()) + } + } + + pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult { + self.verify_global_values(errors)?; + self.verify_memory_types(errors)?; + self.typecheck_entry_block_params(errors)?; + self.check_entry_not_cold(errors)?; + self.typecheck_function_signature(errors)?; + + for block in self.func.layout.blocks() { + if self.func.layout.first_inst(block).is_none() { + return errors.fatal((block, format!("{block} cannot be empty"))); + } + for inst in self.func.layout.block_insts(block) { + self.block_integrity(block, inst, errors)?; + self.instruction_integrity(inst, errors)?; + self.typecheck(inst, errors)?; + self.immediate_constraints(inst, errors)?; + self.iconst_bounds(inst, errors)?; + } + + self.encodable_as_bb(block, errors)?; + } + + if !errors.is_empty() { + log::warn!( + "Found verifier errors in function:\n{}", + pretty_verifier_error(self.func, None, errors.clone()) + ); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::{Verifier, VerifierError, VerifierErrors}; + use crate::ir::instructions::{InstructionData, Opcode}; + use crate::ir::{types, AbiParam, Function, Type}; + use crate::settings; + + macro_rules! assert_err_with_msg { + ($e:expr, $msg:expr) => { + match $e.0.get(0) { + None => panic!("Expected an error"), + Some(&VerifierError { ref message, .. }) => { + if !message.contains($msg) { + #[cfg(feature = "std")] + panic!("'{}' did not contain the substring '{}'", message, $msg); + #[cfg(not(feature = "std"))] + panic!("error message did not contain the expected substring"); + } + } + } + }; + } + + #[test] + fn empty() { + let func = Function::new(); + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + let mut errors = VerifierErrors::default(); + + assert_eq!(verifier.run(&mut errors), Ok(())); + assert!(errors.0.is_empty()); + } + + #[test] + fn bad_instruction_format() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + func.layout.append_block(block0); + let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm { + opcode: Opcode::F32const, + imm: 0.into(), + }); + func.layout.append_inst(nullary_with_bad_opcode, block0); + let destination = func.dfg.block_call(block0, &[]); + func.stencil.layout.append_inst( + func.stencil.dfg.make_inst(InstructionData::Jump { + opcode: Opcode::Jump, + destination, + }), + block0, + ); + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + let mut errors = VerifierErrors::default(); + + let _ = verifier.run(&mut errors); + + assert_err_with_msg!(errors, "instruction format"); + } + + fn test_iconst_bounds(immediate: i64, ctrl_typevar: Type) -> VerifierErrors { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + func.layout.append_block(block0); + + let test_inst = func.dfg.make_inst(InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm: immediate.into(), + }); + + let end_inst = func.dfg.make_inst(InstructionData::MultiAry { + opcode: Opcode::Return, + args: Default::default(), + }); + + func.dfg.make_inst_results(test_inst, ctrl_typevar); + func.layout.append_inst(test_inst, block0); + func.layout.append_inst(end_inst, block0); + + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + let mut errors = VerifierErrors::default(); + + let _ = verifier.run(&mut errors); + errors + } + + fn test_iconst_bounds_err(immediate: i64, ctrl_typevar: Type) { + assert_err_with_msg!( + test_iconst_bounds(immediate, ctrl_typevar), + "constant immediate is out of bounds" + ); + } + + fn test_iconst_bounds_ok(immediate: i64, ctrl_typevar: Type) { + assert!(test_iconst_bounds(immediate, ctrl_typevar).is_empty()); + } + + #[test] + fn negative_iconst_8() { + test_iconst_bounds_err(-10, types::I8); + } + + #[test] + fn negative_iconst_32() { + test_iconst_bounds_err(-1, types::I32); + } + + #[test] + fn large_iconst_8() { + test_iconst_bounds_err(1 + u8::MAX as i64, types::I8); + } + + #[test] + fn large_iconst_16() { + test_iconst_bounds_err(10 + u16::MAX as i64, types::I16); + } + + #[test] + fn valid_iconst_8() { + test_iconst_bounds_ok(10, types::I8); + } + + #[test] + fn valid_iconst_32() { + test_iconst_bounds_ok(u32::MAX as i64, types::I32); + } + + #[test] + fn test_function_invalid_param() { + let mut func = Function::new(); + func.signature.params.push(AbiParam::new(types::INVALID)); + + let mut errors = VerifierErrors::default(); + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + + let _ = verifier.typecheck_function_signature(&mut errors); + assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type"); + } + + #[test] + fn test_function_invalid_return_value() { + let mut func = Function::new(); + func.signature.returns.push(AbiParam::new(types::INVALID)); + + let mut errors = VerifierErrors::default(); + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + + let _ = verifier.typecheck_function_signature(&mut errors); + assert_err_with_msg!(errors, "Return value at position 0 has an invalid type"); + } + + #[test] + fn test_printing_contextual_errors() { + // Build function. + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + func.layout.append_block(block0); + + // Build instruction "f64const 0.0" (missing one required result) + let inst = func.dfg.make_inst(InstructionData::UnaryIeee64 { + opcode: Opcode::F64const, + imm: 0.0.into(), + }); + func.layout.append_inst(inst, block0); + + // Setup verifier. + let mut errors = VerifierErrors::default(); + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + + // Now the error message, when printed, should contain the instruction sequence causing the + // error (i.e. f64const 0.0) and not only its entity value (i.e. inst0) + let _ = verifier.typecheck_results(inst, types::I32, &mut errors); + assert_eq!( + format!("{}", errors.0[0]), + "inst0 (f64const 0.0): has fewer result values than expected" + ) + } + + #[test] + fn test_empty_block() { + let mut func = Function::new(); + let block0 = func.dfg.make_block(); + func.layout.append_block(block0); + + let flags = &settings::Flags::new(settings::builder()); + let verifier = Verifier::new(&func, flags.into()); + let mut errors = VerifierErrors::default(); + let _ = verifier.run(&mut errors); + + assert_err_with_msg!(errors, "block0 cannot be empty"); + } +} diff --git a/deps/crates/vendor/cranelift-codegen/src/write.rs b/deps/crates/vendor/cranelift-codegen/src/write.rs new file mode 100644 index 00000000000000..5c77aa6792751d --- /dev/null +++ b/deps/crates/vendor/cranelift-codegen/src/write.rs @@ -0,0 +1,694 @@ +//! Converting Cranelift IR to text. +//! +//! The `write` module provides the `write_function` function which converts an IR `Function` to an +//! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate. + +use crate::entity::SecondaryMap; +use crate::ir::entities::AnyEntity; +use crate::ir::immediates::Ieee128; +use crate::ir::pcc::Fact; +use crate::ir::{Block, DataFlowGraph, Function, Inst, Opcode, SigRef, Type, Value, ValueDef}; +use crate::packed_option::ReservedValue; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::fmt::{self, Write}; + +/// A `FuncWriter` used to decorate functions during printing. +pub trait FuncWriter { + /// Write the basic block header for the current function. + fn write_block_header( + &mut self, + w: &mut dyn Write, + func: &Function, + block: Block, + indent: usize, + ) -> fmt::Result; + + /// Write the given `inst` to `w`. + fn write_instruction( + &mut self, + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + inst: Inst, + indent: usize, + ) -> fmt::Result; + + /// Write the preamble to `w`. By default, this uses `write_entity_definition`. + fn write_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result { + self.super_preamble(w, func) + } + + /// Default impl of `write_preamble` + fn super_preamble(&mut self, w: &mut dyn Write, func: &Function) -> Result { + let mut any = false; + + for (ss, slot) in func.dynamic_stack_slots.iter() { + any = true; + self.write_entity_definition(w, func, ss.into(), slot, None)?; + } + + for (ss, slot) in func.sized_stack_slots.iter() { + any = true; + self.write_entity_definition(w, func, ss.into(), slot, None)?; + } + + for (gv, gv_data) in &func.global_values { + any = true; + let maybe_fact = func.global_value_facts[gv].as_ref(); + self.write_entity_definition(w, func, gv.into(), gv_data, maybe_fact)?; + } + + for (mt, mt_data) in &func.memory_types { + any = true; + self.write_entity_definition(w, func, mt.into(), mt_data, None)?; + } + + // Write out all signatures before functions since function declarations can refer to + // signatures. + for (sig, sig_data) in &func.dfg.signatures { + any = true; + self.write_entity_definition(w, func, sig.into(), &sig_data, None)?; + } + + for (fnref, ext_func) in &func.dfg.ext_funcs { + if ext_func.signature != SigRef::reserved_value() { + any = true; + self.write_entity_definition( + w, + func, + fnref.into(), + &ext_func.display(Some(&func.params)), + None, + )?; + } + } + + for (&cref, cval) in func.dfg.constants.iter() { + any = true; + self.write_entity_definition(w, func, cref.into(), cval, None)?; + } + + if let Some(limit) = func.stack_limit { + any = true; + self.write_entity_definition(w, func, AnyEntity::StackLimit, &limit, None)?; + } + + Ok(any) + } + + /// Write an entity definition defined in the preamble to `w`. + fn write_entity_definition( + &mut self, + w: &mut dyn Write, + func: &Function, + entity: AnyEntity, + value: &dyn fmt::Display, + maybe_fact: Option<&Fact>, + ) -> fmt::Result { + self.super_entity_definition(w, func, entity, value, maybe_fact) + } + + /// Default impl of `write_entity_definition` + #[allow(unused_variables)] + fn super_entity_definition( + &mut self, + w: &mut dyn Write, + func: &Function, + entity: AnyEntity, + value: &dyn fmt::Display, + maybe_fact: Option<&Fact>, + ) -> fmt::Result { + if let Some(fact) = maybe_fact { + writeln!(w, " {entity} ! {fact} = {value}") + } else { + writeln!(w, " {entity} = {value}") + } + } +} + +/// A `PlainWriter` that doesn't decorate the function. +pub struct PlainWriter; + +impl FuncWriter for PlainWriter { + fn write_instruction( + &mut self, + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + inst: Inst, + indent: usize, + ) -> fmt::Result { + write_instruction(w, func, aliases, inst, indent) + } + + fn write_block_header( + &mut self, + w: &mut dyn Write, + func: &Function, + block: Block, + indent: usize, + ) -> fmt::Result { + write_block_header(w, func, block, indent) + } +} + +/// Write `func` to `w` as equivalent text. +/// Use `isa` to emit ISA-dependent annotations. +pub fn write_function(w: &mut dyn Write, func: &Function) -> fmt::Result { + decorate_function(&mut PlainWriter, w, func) +} + +/// Create a reverse-alias map from a value to all aliases having that value as a direct target +fn alias_map(func: &Function) -> SecondaryMap> { + let mut aliases = SecondaryMap::<_, Vec<_>>::new(); + for v in func.dfg.values() { + // VADFS returns the immediate target of an alias + if let Some(k) = func.dfg.value_alias_dest_for_serialization(v) { + aliases[k].push(v); + } + } + aliases +} + +/// Writes `func` to `w` as text. +/// write_function_plain is passed as 'closure' to print instructions as text. +/// pretty_function_error is passed as 'closure' to add error decoration. +pub fn decorate_function( + func_w: &mut FW, + w: &mut dyn Write, + func: &Function, +) -> fmt::Result { + write!(w, "function ")?; + write_spec(w, func)?; + writeln!(w, " {{")?; + let aliases = alias_map(func); + let mut any = func_w.write_preamble(w, func)?; + for block in &func.layout { + if any { + writeln!(w)?; + } + decorate_block(func_w, w, func, &aliases, block)?; + any = true; + } + writeln!(w, "}}") +} + +//---------------------------------------------------------------------- +// +// Function spec. + +fn write_spec(w: &mut dyn Write, func: &Function) -> fmt::Result { + write!(w, "{}{}", func.name, func.signature) +} + +//---------------------------------------------------------------------- +// +// Basic blocks + +fn write_arg(w: &mut dyn Write, func: &Function, arg: Value) -> fmt::Result { + let ty = func.dfg.value_type(arg); + if let Some(f) = &func.dfg.facts[arg] { + write!(w, "{arg} ! {f}: {ty}") + } else { + write!(w, "{arg}: {ty}") + } +} + +/// Write out the basic block header, outdented: +/// +/// block1: +/// block1(v1: i32): +/// block10(v4: f64, v5: i8): +/// +pub fn write_block_header( + w: &mut dyn Write, + func: &Function, + block: Block, + indent: usize, +) -> fmt::Result { + let cold = if func.layout.is_cold(block) { + " cold" + } else { + "" + }; + + // The `indent` is the instruction indentation. block headers are 4 spaces out from that. + write!(w, "{1:0$}{2}", indent - 4, "", block)?; + + let mut args = func.dfg.block_params(block).iter().cloned(); + match args.next() { + None => return writeln!(w, "{cold}:"), + Some(arg) => { + write!(w, "(")?; + write_arg(w, func, arg)?; + } + } + // Remaining arguments. + for arg in args { + write!(w, ", ")?; + write_arg(w, func, arg)?; + } + writeln!(w, "){cold}:") +} + +fn decorate_block( + func_w: &mut FW, + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + block: Block, +) -> fmt::Result { + // Indent all instructions if any srclocs are present. + let indent = if func.rel_srclocs().is_empty() { 4 } else { 36 }; + + func_w.write_block_header(w, func, block, indent)?; + for a in func.dfg.block_params(block).iter().cloned() { + write_value_aliases(w, aliases, a, indent)?; + } + + for inst in func.layout.block_insts(block) { + func_w.write_instruction(w, func, aliases, inst, indent)?; + } + + Ok(()) +} + +//---------------------------------------------------------------------- +// +// Instructions + +// Should `inst` be printed with a type suffix? +// +// Polymorphic instructions may need a suffix indicating the value of the controlling type variable +// if it can't be trivially inferred. +// +fn type_suffix(func: &Function, inst: Inst) -> Option { + let inst_data = &func.dfg.insts[inst]; + let constraints = inst_data.opcode().constraints(); + + if !constraints.is_polymorphic() { + return None; + } + + // If the controlling type variable can be inferred from the type of the designated value input + // operand, we don't need the type suffix. + if constraints.use_typevar_operand() { + let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap(); + let def_block = match func.dfg.value_def(ctrl_var) { + ValueDef::Result(instr, _) => func.layout.inst_block(instr), + ValueDef::Param(block, _) => Some(block), + ValueDef::Union(..) => None, + }; + if def_block.is_some() && def_block == func.layout.inst_block(inst) { + return None; + } + } + + let rtype = func.dfg.ctrl_typevar(inst); + assert!( + !rtype.is_invalid(), + "Polymorphic instruction must produce a result" + ); + Some(rtype) +} + +/// Write out any aliases to the given target, including indirect aliases +fn write_value_aliases( + w: &mut dyn Write, + aliases: &SecondaryMap>, + target: Value, + indent: usize, +) -> fmt::Result { + let mut todo_stack = vec![target]; + while let Some(target) = todo_stack.pop() { + for &a in &aliases[target] { + writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?; + todo_stack.push(a); + } + } + + Ok(()) +} + +fn write_instruction( + w: &mut dyn Write, + func: &Function, + aliases: &SecondaryMap>, + inst: Inst, + indent: usize, +) -> fmt::Result { + // Prefix containing source location, encoding, and value locations. + let mut s = String::with_capacity(16); + + // Source location goes first. + let srcloc = func.srcloc(inst); + if !srcloc.is_default() { + write!(s, "{srcloc} ")?; + } + + // Write out prefix and indent the instruction. + write!(w, "{s:indent$}")?; + + // Write out the result values, if any. + let mut has_results = false; + for r in func.dfg.inst_results(inst) { + if !has_results { + has_results = true; + write!(w, "{r}")?; + } else { + write!(w, ", {r}")?; + } + if let Some(f) = &func.dfg.facts[*r] { + write!(w, " ! {f}")?; + } + } + if has_results { + write!(w, " = ")?; + } + + // Then the opcode, possibly with a '.type' suffix. + let opcode = func.dfg.insts[inst].opcode(); + + match type_suffix(func, inst) { + Some(suf) => write!(w, "{opcode}.{suf}")?, + None => write!(w, "{opcode}")?, + } + + write_operands(w, &func.dfg, inst)?; + writeln!(w)?; + + // Value aliases come out on lines after the instruction defining the referent. + for r in func.dfg.inst_results(inst) { + write_value_aliases(w, aliases, *r, indent)?; + } + Ok(()) +} + +/// Write the operands of `inst` to `w` with a prepended space. +pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result { + let pool = &dfg.value_lists; + let jump_tables = &dfg.jump_tables; + use crate::ir::instructions::InstructionData::*; + let ctrl_ty = dfg.ctrl_typevar(inst); + match dfg.insts[inst] { + AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]), + AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]), + LoadNoOffset { flags, arg, .. } => write!(w, "{flags} {arg}"), + StoreNoOffset { flags, args, .. } => write!(w, "{} {}, {}", flags, args[0], args[1]), + Unary { arg, .. } => write!(w, " {arg}"), + UnaryImm { imm, .. } => write!(w, " {}", { + let mut imm = imm; + if ctrl_ty.bits() != 0 { + imm = imm.sign_extend_from_width(ctrl_ty.bits()); + } + imm + }), + UnaryIeee16 { imm, .. } => write!(w, " {imm}"), + UnaryIeee32 { imm, .. } => write!(w, " {imm}"), + UnaryIeee64 { imm, .. } => write!(w, " {imm}"), + UnaryGlobalValue { global_value, .. } => write!(w, " {global_value}"), + UnaryConst { + constant_handle, .. + } => write!(w, " {constant_handle}"), + Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]), + BinaryImm8 { arg, imm, .. } => write!(w, " {arg}, {imm}"), + BinaryImm64 { arg, imm, .. } => write!(w, " {}, {}", arg, { + let mut imm = imm; + if ctrl_ty.bits() != 0 { + imm = imm.sign_extend_from_width(ctrl_ty.bits()); + } + imm + }), + Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]), + MultiAry { ref args, .. } => { + if args.is_empty() { + write!(w, "") + } else { + write!(w, " {}", DisplayValues(args.as_slice(pool))) + } + } + NullAry { .. } => write!(w, " "), + TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm), + Shuffle { imm, args, .. } => { + let data = dfg.immediates.get(imm).expect( + "Expected the shuffle mask to already be inserted into the immediates table", + ); + write!(w, " {}, {}, {}", args[0], args[1], data) + } + IntCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]), + IntCompareImm { cond, arg, imm, .. } => write!(w, " {} {}, {}", cond, arg, { + let mut imm = imm; + if ctrl_ty.bits() != 0 { + imm = imm.sign_extend_from_width(ctrl_ty.bits()); + } + imm + }), + IntAddTrap { args, code, .. } => write!(w, " {}, {}, {}", args[0], args[1], code), + FloatCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]), + Jump { destination, .. } => { + write!(w, " {}", destination.display(pool)) + } + Brif { + arg, + blocks: [block_then, block_else], + .. + } => { + write!(w, " {}, {}", arg, block_then.display(pool))?; + write!(w, ", {}", block_else.display(pool)) + } + BranchTable { arg, table, .. } => { + write!(w, " {}, {}", arg, jump_tables[table].display(pool)) + } + Call { + func_ref, ref args, .. + } => { + write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool)))?; + write_user_stack_map_entries(w, dfg, inst) + } + CallIndirect { + sig_ref, ref args, .. + } => { + let args = args.as_slice(pool); + write!( + w, + " {}, {}({})", + sig_ref, + args[0], + DisplayValues(&args[1..]) + )?; + write_user_stack_map_entries(w, dfg, inst) + } + FuncAddr { func_ref, .. } => write!(w, " {func_ref}"), + StackLoad { + stack_slot, offset, .. + } => write!(w, " {stack_slot}{offset}"), + StackStore { + arg, + stack_slot, + offset, + .. + } => write!(w, " {arg}, {stack_slot}{offset}"), + DynamicStackLoad { + dynamic_stack_slot, .. + } => write!(w, " {dynamic_stack_slot}"), + DynamicStackStore { + arg, + dynamic_stack_slot, + .. + } => write!(w, " {arg}, {dynamic_stack_slot}"), + Load { + flags, arg, offset, .. + } => write!(w, "{flags} {arg}{offset}"), + Store { + flags, + args, + offset, + .. + } => write!(w, "{} {}, {}{}", flags, args[0], args[1], offset), + Trap { code, .. } => write!(w, " {code}"), + CondTrap { arg, code, .. } => write!(w, " {arg}, {code}"), + }?; + + let mut sep = " ; "; + for arg in dfg.inst_values(inst) { + if let ValueDef::Result(src, _) = dfg.value_def(arg) { + let imm = match dfg.insts[src] { + UnaryImm { imm, .. } => { + let mut imm = imm; + if dfg.ctrl_typevar(src).bits() != 0 { + imm = imm.sign_extend_from_width(dfg.ctrl_typevar(src).bits()); + } + imm.to_string() + } + UnaryIeee16 { imm, .. } => imm.to_string(), + UnaryIeee32 { imm, .. } => imm.to_string(), + UnaryIeee64 { imm, .. } => imm.to_string(), + UnaryConst { + constant_handle, + opcode: Opcode::F128const, + } => Ieee128::try_from(dfg.constants.get(constant_handle)) + .expect("16-byte f128 constant") + .to_string(), + UnaryConst { + constant_handle, .. + } => constant_handle.to_string(), + _ => continue, + }; + write!(w, "{sep}{arg} = {imm}")?; + sep = ", "; + } + } + Ok(()) +} + +fn write_user_stack_map_entries(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result { + let entries = match dfg.user_stack_map_entries(inst) { + None => return Ok(()), + Some(es) => es, + }; + write!(w, ", stack_map=[")?; + let mut need_comma = false; + for entry in entries { + if need_comma { + write!(w, ", ")?; + } + write!(w, "{} @ {}+{}", entry.ty, entry.slot, entry.offset)?; + need_comma = true; + } + write!(w, "]")?; + Ok(()) +} + +/// Displayable slice of values. +struct DisplayValues<'a>(&'a [Value]); + +impl<'a> fmt::Display for DisplayValues<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for (i, val) in self.0.iter().enumerate() { + if i == 0 { + write!(f, "{val}")?; + } else { + write!(f, ", {val}")?; + } + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::cursor::{Cursor, CursorPosition, FuncCursor}; + use crate::ir::types; + use crate::ir::{Function, InstBuilder, StackSlotData, StackSlotKind, UserFuncName}; + use alloc::string::ToString; + + #[test] + fn basic() { + let mut f = Function::new(); + assert_eq!(f.to_string(), "function u0:0() fast {\n}\n"); + + f.name = UserFuncName::testcase("foo"); + assert_eq!(f.to_string(), "function %foo() fast {\n}\n"); + + f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0)); + assert_eq!( + f.to_string(), + "function %foo() fast {\n ss0 = explicit_slot 4\n}\n" + ); + + let block = f.dfg.make_block(); + f.layout.append_block(block); + assert_eq!( + f.to_string(), + "function %foo() fast {\n ss0 = explicit_slot 4\n\nblock0:\n}\n" + ); + + f.dfg.append_block_param(block, types::I8); + assert_eq!( + f.to_string(), + "function %foo() fast {\n ss0 = explicit_slot 4\n\nblock0(v0: i8):\n}\n" + ); + + f.dfg.append_block_param(block, types::F32.by(4).unwrap()); + assert_eq!( + f.to_string(), + "function %foo() fast {\n ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n}\n" + ); + + { + let mut cursor = FuncCursor::new(&mut f); + cursor.set_position(CursorPosition::After(block)); + cursor.ins().return_(&[]) + }; + assert_eq!( + f.to_string(), + "function %foo() fast {\n ss0 = explicit_slot 4\n\nblock0(v0: i8, v1: f32x4):\n return\n}\n" + ); + + let mut f = Function::new(); + f.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 2)); + assert_eq!( + f.to_string(), + "function u0:0() fast {\n ss0 = explicit_slot 4, align = 4\n}\n" + ); + } + + #[test] + fn aliases() { + use crate::ir::InstBuilder; + + let mut func = Function::new(); + { + let block0 = func.dfg.make_block(); + let mut pos = FuncCursor::new(&mut func); + pos.insert_block(block0); + + // make some detached values for change_to_alias + let v0 = pos.func.dfg.append_block_param(block0, types::I32); + let v1 = pos.func.dfg.append_block_param(block0, types::I32); + let v2 = pos.func.dfg.append_block_param(block0, types::I32); + pos.func.dfg.detach_block_params(block0); + + // alias to a param--will be printed at beginning of block defining param + let v3 = pos.func.dfg.append_block_param(block0, types::I32); + pos.func.dfg.change_to_alias(v0, v3); + + // alias to an alias--should print attached to alias, not ultimate target + pos.func.dfg.make_value_alias_for_serialization(v0, v2); // v0 <- v2 + + // alias to a result--will be printed after instruction producing result + let _dummy0 = pos.ins().iconst(types::I32, 42); + let v4 = pos.ins().iadd(v0, v0); + pos.func.dfg.change_to_alias(v1, v4); + let _dummy1 = pos.ins().iconst(types::I32, 23); + let _v7 = pos.ins().iadd(v1, v1); + } + assert_eq!( + func.to_string(), + "function u0:0() fast {\nblock0(v3: i32):\n v0 -> v3\n v2 -> v0\n v4 = iconst.i32 42\n v5 = iadd v0, v0\n v1 -> v5\n v6 = iconst.i32 23\n v7 = iadd v1, v1\n}\n" + ); + } + + #[test] + fn cold_blocks() { + let mut func = Function::new(); + { + let mut pos = FuncCursor::new(&mut func); + + let block0 = pos.func.dfg.make_block(); + pos.insert_block(block0); + pos.func.layout.set_cold(block0); + + let block1 = pos.func.dfg.make_block(); + pos.insert_block(block1); + pos.func.dfg.append_block_param(block1, types::I32); + pos.func.layout.set_cold(block1); + } + + assert_eq!( + func.to_string(), + "function u0:0() fast {\nblock0 cold:\n\nblock1(v0: i32) cold:\n}\n" + ); + } +} diff --git a/deps/crates/vendor/cranelift-control/.cargo-checksum.json b/deps/crates/vendor/cranelift-control/.cargo-checksum.json new file mode 100644 index 00000000000000..fc35895578af39 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"f0e8ffb4dd8be97d712dd3ce2faada7f304ca5b7cbb2817248349578e3c30d2a","Cargo.lock":"3f2c227a77451207a779a1ea28a89bab97b574e9b2ba35d30d047286bd3a20f4","Cargo.toml":"f5d13bda76f1306ce1fe4da1762b2b6f9ba86481b10507100c499cdf07bd968d","Cargo.toml.orig":"44254969e7514939f1dbbab84eefbf9b4fc7265725058ab7065233a76c82b04c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"9266e3c8ff78a0f5948eb24292a2b51ec272d9417816ffe23de0b1ea4589acb4","src/chaos.rs":"dde1ce4e45dab264fa611734fc3190b9710e043c83e635d67c044876e8dc9d75","src/lib.rs":"c8d0ed8144b1605446d722cf530fc96e43ac83a9c32949a6b6d7a4da65f8aa92","src/zero_sized.rs":"523f2daf803a1869b6f5728a0e6f5b7b4b88455cdcfd9b47bb63ff7d3538c656"},"package":"26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-control/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-control/.cargo_vcs_info.json new file mode 100644 index 00000000000000..2918a539c4f0b0 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/control" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-control/Cargo.lock b/deps/crates/vendor/cranelift-control/Cargo.lock new file mode 100644 index 00000000000000..f96bf5d8a85eb4 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +dependencies = [ + "arbitrary", +] diff --git a/deps/crates/vendor/cranelift-control/Cargo.toml b/deps/crates/vendor/cranelift-control/Cargo.toml new file mode 100644 index 00000000000000..5b80002152f36c --- /dev/null +++ b/deps/crates/vendor/cranelift-control/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-control" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "White-box fuzz testing framework" +readme = "README.md" +keywords = [ + "fuzz", + "test", +] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_control" +path = "src/lib.rs" + +[dependencies.arbitrary] +version = "1.4.0" +optional = true + +[features] +chaos = ["fuzz"] +default = ["fuzz"] +fuzz = ["dep:arbitrary"] diff --git a/deps/crates/vendor/cranelift-control/Cargo.toml.orig b/deps/crates/vendor/cranelift-control/Cargo.toml.orig new file mode 100644 index 00000000000000..0750b01eeb49a8 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/Cargo.toml.orig @@ -0,0 +1,25 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-control" +version = "0.116.1" +description = "White-box fuzz testing framework" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +keywords = ["fuzz", "test"] +edition.workspace = true +rust-version.workspace = true + +[dependencies] +arbitrary = { workspace = true, optional = true } + +[features] +default = ["fuzz"] + +# Enable fuzzing support with `arbitrary`. Does not work on `no_std` targets. +fuzz = ["dep:arbitrary"] + +# Turn on chaos mode. +# Without this feature, a zero-sized dummy will be compiled +# for the control plane. +chaos = ["fuzz"] diff --git a/deps/crates/vendor/cranelift-control/LICENSE b/deps/crates/vendor/cranelift-control/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-control/README.md b/deps/crates/vendor/cranelift-control/README.md new file mode 100644 index 00000000000000..3eecb3d47b6b25 --- /dev/null +++ b/deps/crates/vendor/cranelift-control/README.md @@ -0,0 +1,4 @@ +This crate contains the control plane for "chaos mode". It can be used to +inject pseudo-random perturbations into specific sections in the code while +fuzzing. Its compilation is feature-gated to prevent any performance +impact on release builds. diff --git a/deps/crates/vendor/cranelift-control/src/chaos.rs b/deps/crates/vendor/cranelift-control/src/chaos.rs new file mode 100644 index 00000000000000..2db8d5f9f2679c --- /dev/null +++ b/deps/crates/vendor/cranelift-control/src/chaos.rs @@ -0,0 +1,126 @@ +use alloc::vec::Vec; +use arbitrary::{Arbitrary, Unstructured}; + +/// The control plane of chaos mode. +/// Please see the [crate-level documentation](crate). +#[derive(Debug, Clone, Default)] +pub struct ControlPlane { + data: Vec, + fuel: Option, + /// This is used as a little optimization to avoid additional heap + /// allocations when using `Unstructured` internally. See the source of + /// [`ControlPlane::shuffle`] for an example. + tmp: Vec, +} + +impl Arbitrary<'_> for ControlPlane { + fn arbitrary<'a>(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Ok(Self::new(u.arbitrary()?)) + } +} + +impl ControlPlane { + fn new(data: Vec) -> Self { + Self { + data, + fuel: None, + tmp: Vec::new(), + } + } + + /// Set the [fuel limit](crate#fuel-limit). Zero is interpreted as the + /// fuel limit being deactivated, consistent with the cranelift setting + /// `control_plane_fuel`. + pub fn set_fuel(&mut self, fuel: u8) { + self.fuel = (fuel != 0).then_some(fuel) + } + + /// Tries to consume fuel, returning `true` if successful (or if + /// fuel-limiting is disabled). + fn consume_fuel(&mut self) -> bool { + match self.fuel { + None => true, // fuel deactivated + Some(f) if f == 0 => false, // no more fuel + Some(ref mut f) => { + *f -= 1; + true + } + } + } + + /// Returns a pseudo-random boolean if the control plane was constructed + /// with `arbitrary`. + /// + /// The default value `false` will always be returned if the + /// pseudo-random data is exhausted or the control plane was constructed + /// with `default`. + pub fn get_decision(&mut self) -> bool { + self.consume_fuel() && self.data.pop().unwrap_or_default() & 1 == 1 + } + + /// Returns an arbitrary value if the control plane was constructed with + /// `arbitrary`. + /// + /// The default value will always be returned if the pseudo-random data is + /// exhausted or the control plane was constructed with `default`. + pub fn get_arbitrary Arbitrary<'a> + Default>(&mut self) -> T { + if !self.consume_fuel() || self.data.is_empty() { + return T::default(); + } + let mut u = Unstructured::new(&self.data); + let res = u.arbitrary().unwrap_or_default(); + + // take remaining bytes + let rest = u.take_rest(); + self.tmp.resize(rest.len(), 0); // allocates once per control plane + self.tmp.copy_from_slice(rest); + core::mem::swap(&mut self.data, &mut self.tmp); + + res + } + + /// Shuffles the items in the slice into a pseudo-random permutation if + /// the control plane was constructed with `arbitrary`. + /// + /// The default operation, to leave the slice unchanged, will always be + /// performed if the pseudo-random data is exhausted or the control + /// plane was constructed with `default`. + pub fn shuffle(&mut self, slice: &mut [T]) { + if !self.consume_fuel() || self.data.is_empty() { + return; + } + let mut u = Unstructured::new(&self.data); + + // adapted from: + // https://docs.rs/arbitrary/1.3.0/arbitrary/struct.Unstructured.html#examples-1 + let mut to_permute = &mut slice[..]; + + while to_permute.len() > 1 { + if let Ok(idx) = u.choose_index(to_permute.len()) { + to_permute.swap(0, idx); + to_permute = &mut to_permute[1..]; + } else { + break; + } + } + + // take remaining bytes + let rest = u.take_rest(); + self.tmp.resize(rest.len(), 0); // allocates once per control plane + self.tmp.copy_from_slice(rest); + core::mem::swap(&mut self.data, &mut self.tmp); + } + + /// Returns a new iterator over the same items as the input iterator in + /// a pseudo-random order if the control plane was constructed with + /// `arbitrary`. + /// + /// The default value, an iterator with an unchanged order, will always + /// be returned if the pseudo-random data is exhausted or the control + /// plane was constructed with `default`. + pub fn shuffled(&mut self, iter: impl Iterator) -> impl Iterator { + let mut slice: Vec<_> = iter.collect(); + self.shuffle(&mut slice); + slice.into_iter() + } +} diff --git a/deps/crates/vendor/cranelift-control/src/lib.rs b/deps/crates/vendor/cranelift-control/src/lib.rs new file mode 100644 index 00000000000000..20c33cb740a62c --- /dev/null +++ b/deps/crates/vendor/cranelift-control/src/lib.rs @@ -0,0 +1,59 @@ +//! # Cranelift Control +//! +//! This is the home of the control plane of chaos mode, a compilation feature +//! intended to be turned on for certain fuzz targets. When the feature is +//! turned off, as is normally the case, [ControlPlane] will be a zero-sized +//! type and optimized away. +//! +//! While the feature is turned on, the struct [ControlPlane] +//! provides functionality to tap into pseudo-randomness at specific locations +//! in the code. It may be used for targeted fuzzing of compiler internals, +//! e.g. manipulate heuristic optimizations, clobber undefined register bits +//! etc. +//! +//! There are two ways to acquire a [ControlPlane]: +//! - [arbitrary] for the real deal (requires the `fuzz` feature, enabled by default) +//! - [default] for an "empty" control plane which always returns default +//! values +//! +//! ## Fuel Limit +//! +//! Controls the number of mutations or optimizations that the compiler will +//! perform before stopping. +//! +//! When a perturbation introduced by chaos mode triggers a bug, it may not be +//! immediately clear which of the introduced perturbations was the trigger. The +//! fuel limit can then be used to binary-search for the trigger. It limits the +//! number of perturbations introduced by the control plane. The fuel limit will +//! typically be set with a command line argument passed to a fuzz target. For +//! example: +//! ```sh +//! cargo fuzz run --features chaos $TARGET -- --fuel=16 +//! ``` +//! +//! ## `no_std` support +//! +//! This crate compiles in `no_std` environments, although both the `fuzz` +//! or `chaos` features have a dependency on `std`. This means that on `no_std` +//! you can't use [arbitrary] to initialize [ControlPlane] and can't enable +//! chaos mode, although the rest of the usual [ControlPlane] API is available. +//! +//! [arbitrary]: ControlPlane#method.arbitrary +//! [default]: ControlPlane#method.default + +#![no_std] + +// The `alloc` crate is only needed by chaos mode, which guarantees that +// `alloc` is present because of its dependency on `std`. +#[cfg(feature = "chaos")] +extern crate alloc; + +#[cfg(not(feature = "chaos"))] +mod zero_sized; +#[cfg(not(feature = "chaos"))] +pub use zero_sized::*; + +#[cfg(feature = "chaos")] +mod chaos; +#[cfg(feature = "chaos")] +pub use chaos::*; diff --git a/deps/crates/vendor/cranelift-control/src/zero_sized.rs b/deps/crates/vendor/cranelift-control/src/zero_sized.rs new file mode 100644 index 00000000000000..8cf2fd0c9c2abd --- /dev/null +++ b/deps/crates/vendor/cranelift-control/src/zero_sized.rs @@ -0,0 +1,54 @@ +//! Shims for ControlPlane when chaos mode is disabled. Enables +//! unconditional use of the type and its methods throughout cranelift. + +/// A shim for ControlPlane when chaos mode is disabled. +/// Please see the [crate-level documentation](crate). +#[derive(Debug, Clone, Default)] +pub struct ControlPlane { + /// prevent direct instantiation (use `default` instead) + _private: (), +} + +/// A shim for ControlPlane's `Arbitrary` implementation when chaos mode is +/// disabled. It doesn't consume any bytes and always returns a default +/// control plane. +#[cfg(feature = "fuzz")] +impl arbitrary::Arbitrary<'_> for ControlPlane { + fn arbitrary(_u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { + Ok(Self::default()) + } +} + +impl ControlPlane { + /// Set the [fuel limit](crate#fuel-limit). This variant is used when + /// chaos mode is disabled. It doesn't do anything. + pub fn set_fuel(&mut self, _fuel: u8) {} + + /// Returns a pseudo-random boolean. This variant is used when chaos + /// mode is disabled. It always returns `false`. + #[inline] + pub fn get_decision(&mut self) -> bool { + false + } + + /// Returns an arbitrary value. This variant is used when chaos mode is + /// disabled. It always returns the default value. + #[inline] + pub fn get_arbitrary(&mut self) -> T { + T::default() + } + + /// Shuffles the items in the slice into a pseudo-random permutation. + /// This variant is used when chaos mode is disabled. It doesn't do + /// anything. + #[inline] + pub fn shuffle(&mut self, _slice: &mut [T]) {} + + /// Returns a new iterator over the same items as the input iterator in + /// a pseudo-random order. This variant is used when chaos mode is + /// disabled. It always returns the same order. + #[inline] + pub fn shuffled(&mut self, iter: impl Iterator) -> impl Iterator { + iter + } +} diff --git a/deps/crates/vendor/cranelift-entity/.cargo-checksum.json b/deps/crates/vendor/cranelift-entity/.cargo-checksum.json new file mode 100644 index 00000000000000..3b1e4ef017c8f8 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"947821cb6d5253703245f731b8ec165ce794d5720d221dfad7d3c43e10580989","Cargo.lock":"18812c0d96416e7d67b407140d61eef646d48d6ca5dc58b89cd5bb0b7058c8a9","Cargo.toml":"afc1cd146869f06b58fd700ec488d96a5095ff3fc7e135e15c13827478485634","Cargo.toml.orig":"a8a9d8b8209731f49208e7cb528dcd887e2086d5ab7c3a30bb69b73b5028134b","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"69d539b72460c0aba1d30e0b72efb0c29d61558574d751c784794e14abf41352","src/iter.rs":"61fefdc49cafad4cacba5f5a7ad2396a23160642c688a7f0b0734277391847cd","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"fffe1b4abe3daa415add7dc408872d2da396f8743a23ebf7939a3dd1e0ab5989","src/list.rs":"ff85aa55aa1a9388da397fbd445a14de65f71d8a62cd7f2044fa5513d6eac77f","src/map.rs":"d5e004471acf75d71cebaac0e65a45fe052781507f4a616120d264a8056a5d92","src/packed_option.rs":"50d32b9e5445c440d0e9578e37ab8db0e2df9e78f357045ab30f8366d8fafccc","src/primary.rs":"701c2e495df50179295005e21c4ab24d3e70c24c44d7c1e88f37ed51355434c6","src/set.rs":"ce4ed21026b8aa7b56a94fb91bcc42f97c4facf34a8b048a5e7d12e349c1607c","src/signed.rs":"624f0c60361f61c62876c9cedbae28ba2996954a6fcb43a470db4e2e3b24c807","src/sparse.rs":"8a76e242c97dea2d75f91fab71c8be13830457a3506992083839fe49ba6ea60a","src/unsigned.rs":"cb50cc8387466857a46dca6f0368c8be80a5c01036876fe6b10c477880202878"},"package":"4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-entity/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-entity/.cargo_vcs_info.json new file mode 100644 index 00000000000000..9b598700010331 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/entity" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-entity/Cargo.lock b/deps/crates/vendor/cranelift-entity/Cargo.lock new file mode 100644 index 00000000000000..0c73490a49813e --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/Cargo.lock @@ -0,0 +1,77 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/deps/crates/vendor/cranelift-entity/Cargo.toml b/deps/crates/vendor/cranelift-entity/Cargo.toml new file mode 100644 index 00000000000000..0a905c3b41c2db --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/Cargo.toml @@ -0,0 +1,89 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-entity" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Data structures using entity references as mapping keys" +documentation = "https://docs.rs/cranelift-entity" +readme = "README.md" +keywords = [ + "entity", + "set", + "map", +] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_entity" +path = "src/lib.rs" + +[dependencies.cranelift-bitset] +version = "0.116.1" + +[dependencies.serde] +version = "1.0.215" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde_derive] +version = "1.0.188" +optional = true + +[features] +enable-serde = [ + "serde", + "serde_derive", + "cranelift-bitset/enable-serde", +] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-entity/Cargo.toml.orig b/deps/crates/vendor/cranelift-entity/Cargo.toml.orig new file mode 100644 index 00000000000000..75496e0763d122 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/Cargo.toml.orig @@ -0,0 +1,24 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-entity" +version = "0.116.1" +description = "Data structures using entity references as mapping keys" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift-entity" +repository = "https://github.com/bytecodealliance/wasmtime" +categories = ["no-std"] +readme = "README.md" +keywords = ["entity", "set", "map"] +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +cranelift-bitset = { workspace=true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } + +[features] +enable-serde = ["serde", "serde_derive", "cranelift-bitset/enable-serde"] diff --git a/deps/crates/vendor/cranelift-entity/LICENSE b/deps/crates/vendor/cranelift-entity/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-entity/README.md b/deps/crates/vendor/cranelift-entity/README.md new file mode 100644 index 00000000000000..f840b142e687ab --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/README.md @@ -0,0 +1,40 @@ +This crate contains array-based data structures used by the core Cranelift code +generator which use densely numbered entity references as mapping keys. + +One major difference between this crate and crates like [slotmap], [slab], +and [generational-arena] is that this crate currently provides no way to delete +entities. This limits its use to situations where deleting isn't important, +however this also makes it more efficient, because it doesn't need extra +bookkeeping state to reuse the storage for deleted objects, or to ensure that +new objects always have unique keys (eg. slotmap's and generational-arena's +versioning). + +Another major difference is that this crate protects against using a key from +one map to access an element in another. Where `SlotMap`, `Slab`, and `Arena` +have a value type parameter, `PrimaryMap` has a key type parameter and a value +type parameter. The crate also provides the `entity_impl` macro which makes it +easy to declare new unique types for use as keys. Any attempt to use a key in +a map it's not intended for is diagnosed with a type error. + +Another is that this crate has two core map types, `PrimaryMap` and +`SecondaryMap`, which serve complementary purposes. A `PrimaryMap` creates its +own keys when elements are inserted, while an `SecondaryMap` reuses the keys +values of a `PrimaryMap`, conceptually storing additional data in the same +index space. `SecondaryMap`'s values must implement `Default` and all elements +in an `SecondaryMap` initially have the value of `default()`. + +A common way to implement `Default` is to wrap a type in `Option`, however +this crate also provides the `PackedOption` utility which can use less memory +in some cases. + +Additional utilities provided by this crate include: + - `EntityList`, for allocating many small arrays (such as instruction operand + lists in a compiler code generator). + - `SparseMap`: an alternative to `SecondaryMap` which can use less memory + in some situations. + - `EntitySet`: a specialized form of `SecondaryMap` using a bitvector to + record which entities are members of the set. + +[slotmap]: https://crates.io/crates/slotmap +[slab]: https://crates.io/crates/slab +[generational-arena]: https://crates.io/crates/generational-arena diff --git a/deps/crates/vendor/cranelift-entity/src/boxed_slice.rs b/deps/crates/vendor/cranelift-entity/src/boxed_slice.rs new file mode 100644 index 00000000000000..3b3b39155be591 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/boxed_slice.rs @@ -0,0 +1,316 @@ +//! Boxed slices for `PrimaryMap`. + +use crate::iter::{Iter, IterMut}; +use crate::keys::Keys; +use crate::EntityRef; +use alloc::boxed::Box; +use core::marker::PhantomData; +use core::ops::{Index, IndexMut}; +use core::slice; + +/// A slice mapping `K -> V` allocating dense entity references. +/// +/// The `BoxedSlice` data structure uses the dense index space to implement a map with a boxed +/// slice. +#[derive(Debug, Clone)] +pub struct BoxedSlice +where + K: EntityRef, +{ + elems: Box<[V]>, + unused: PhantomData, +} + +impl BoxedSlice +where + K: EntityRef, +{ + /// Create a new slice from a raw pointer. A safer way to create slices is + /// to use `PrimaryMap::into_boxed_slice()`. + /// + /// # Safety + /// + /// This relies on `raw` pointing to a valid slice of `V`s. + pub unsafe fn from_raw(raw: *mut [V]) -> Self { + Self { + elems: Box::from_raw(raw), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<&V> { + self.elems.last() + } +} + +/// Immutable indexing into a `BoxedSlice`. +/// The indexed value must be in the map. +impl Index for BoxedSlice +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into a `BoxedSlice`. +impl IndexMut for BoxedSlice +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl<'a, K, V> IntoIterator for &'a BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::primary::PrimaryMap; + use alloc::vec::Vec; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let p = PrimaryMap::::new(); + let m = p.into_boxed_slice(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn iter() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/iter.rs b/deps/crates/vendor/cranelift-entity/src/iter.rs new file mode 100644 index 00000000000000..fb0a8af9e07ce0 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/iter.rs @@ -0,0 +1,124 @@ +//! A double-ended iterator over entity references and entities. + +use crate::EntityRef; +use alloc::vec; +use core::iter::Enumerate; +use core::marker::PhantomData; +use core::slice; + +/// Iterate over all keys in order. +pub struct Iter<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> Iter<'a, K, V> { + /// Create an `Iter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::Iter<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for Iter<'a, K, V> { + type Item = (K, &'a V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for Iter<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for Iter<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IterMut<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> IterMut<'a, K, V> { + /// Create an `IterMut` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::IterMut<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for IterMut<'a, K, V> { + type Item = (K, &'a mut V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IntoIter { + enumerate: Enumerate>, + unused: PhantomData, +} + +impl IntoIter { + /// Create an `IntoIter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: vec::IntoIter) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/deps/crates/vendor/cranelift-entity/src/keys.rs b/deps/crates/vendor/cranelift-entity/src/keys.rs new file mode 100644 index 00000000000000..bfbaa0cb90b0ad --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/keys.rs @@ -0,0 +1,58 @@ +//! A double-ended iterator over entity references. +//! +//! When `core::iter::Step` is stabilized, `Keys` could be implemented as a wrapper around +//! `core::ops::Range`, but for now, we implement it manually. + +use crate::EntityRef; +use core::marker::PhantomData; + +/// Iterate over all keys in order. +pub struct Keys { + pos: usize, + rev_pos: usize, + unused: PhantomData, +} + +impl Keys { + /// Create a `Keys` iterator that visits `len` entities starting from 0. + pub fn with_len(len: usize) -> Self { + Self { + pos: 0, + rev_pos: len, + unused: PhantomData, + } + } +} + +impl Iterator for Keys { + type Item = K; + + fn next(&mut self) -> Option { + if self.pos < self.rev_pos { + let k = K::new(self.pos); + self.pos += 1; + Some(k) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.rev_pos - self.pos; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for Keys { + fn next_back(&mut self) -> Option { + if self.rev_pos > self.pos { + let k = K::new(self.rev_pos - 1); + self.rev_pos -= 1; + Some(k) + } else { + None + } + } +} + +impl ExactSizeIterator for Keys {} diff --git a/deps/crates/vendor/cranelift-entity/src/lib.rs b/deps/crates/vendor/cranelift-entity/src/lib.rs new file mode 100644 index 00000000000000..ca67cb2555ee7f --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/lib.rs @@ -0,0 +1,383 @@ +//! Array-based data structures using densely numbered entity references as mapping keys. +//! +//! This crate defines a number of data structures based on arrays. The arrays are not indexed by +//! `usize` as usual, but by *entity references* which are integers wrapped in new-types. This has +//! a couple advantages: +//! +//! - Improved type safety. The various map and set types accept a specific key type, so there is +//! no confusion about the meaning of an array index, as there is with plain arrays. +//! - Smaller indexes. The normal `usize` index is often 64 bits which is way too large for most +//! purposes. The entity reference types can be smaller, allowing for more compact data +//! structures. +//! +//! The `EntityRef` trait should be implemented by types to be used as indexed. The `entity_impl!` +//! macro provides convenient defaults for types wrapping `u32` which is common. +//! +//! - [`PrimaryMap`](struct.PrimaryMap.html) is used to keep track of a vector of entities, +//! assigning a unique entity reference to each. +//! - [`SecondaryMap`](struct.SecondaryMap.html) is used to associate secondary information to an +//! entity. The map is implemented as a simple vector, so it does not keep track of which +//! entities have been inserted. Instead, any unknown entities map to the default value. +//! - [`SparseMap`](struct.SparseMap.html) is used to associate secondary information to a small +//! number of entities. It tracks accurately which entities have been inserted. This is a +//! specialized data structure which can use a lot of memory, so read the documentation before +//! using it. +//! - [`EntitySet`](struct.EntitySet.html) is used to represent a secondary set of entities. +//! The set is implemented as a simple vector, so it does not keep track of which entities have +//! been inserted into the primary map. Instead, any unknown entities are not in the set. +//! - [`EntityList`](struct.EntityList.html) is a compact representation of lists of entity +//! references allocated from an associated memory pool. It has a much smaller footprint than +//! `Vec`. + +#![deny(missing_docs)] +#![no_std] + +extern crate alloc; + +// Re-export core so that the macros works with both std and no_std crates +#[doc(hidden)] +pub extern crate core as __core; + +use core::iter::FusedIterator; +use core::ops::Range; + +/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key +/// of an `SecondaryMap` or `SparseMap`. +pub trait EntityRef: Copy + Eq { + /// Create a new entity reference from a small integer. + /// This should crash if the requested index is not representable. + fn new(_: usize) -> Self; + + /// Get the index that was used to create this entity reference. + fn index(self) -> usize; +} + +/// Iterate over a `Range`, yielding a sequence of `E` items. +#[inline] +pub fn iter_entity_range(range: Range) -> IterEntityRange +where + E: EntityRef, +{ + IterEntityRange { + range: range.start.index()..range.end.index(), + _phantom: core::marker::PhantomData, + } +} + +/// Iterator type returned by `iter_entity_range`. +pub struct IterEntityRange { + range: Range, + _phantom: core::marker::PhantomData, +} + +impl Iterator for IterEntityRange +where + E: EntityRef, +{ + type Item = E; + + #[inline] + fn next(&mut self) -> Option { + let i = self.range.next()?; + Some(E::new(i)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } +} + +impl DoubleEndedIterator for IterEntityRange +where + E: EntityRef, +{ + #[inline] + fn next_back(&mut self) -> Option { + let i = self.range.next_back()?; + Some(E::new(i)) + } +} + +impl FusedIterator for IterEntityRange +where + E: EntityRef, + Range: FusedIterator, +{ +} + +impl ExactSizeIterator for IterEntityRange +where + E: EntityRef, + Range: ExactSizeIterator, +{ +} + +/// Macro which provides the common implementation of a 32-bit entity reference. +#[macro_export] +macro_rules! entity_impl { + // Basic traits. + ($entity:ident) => { + impl $crate::EntityRef for $entity { + #[inline] + fn new(index: usize) -> Self { + debug_assert!(index < ($crate::__core::u32::MAX as usize)); + $entity(index as u32) + } + + #[inline] + fn index(self) -> usize { + self.0 as usize + } + } + + impl $crate::packed_option::ReservedValue for $entity { + #[inline] + fn reserved_value() -> $entity { + $entity($crate::__core::u32::MAX) + } + + #[inline] + fn is_reserved_value(&self) -> bool { + self.0 == $crate::__core::u32::MAX + } + } + + impl $entity { + /// Create a new instance from a `u32`. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn from_u32(x: u32) -> Self { + debug_assert!(x < $crate::__core::u32::MAX); + $entity(x) + } + + /// Return the underlying index value as a `u32`. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn as_u32(self) -> u32 { + self.0 + } + + /// Return the raw bit encoding for this instance. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn as_bits(self) -> u32 { + self.0 + } + + /// Create a new instance from the raw bit encoding. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn from_bits(x: u32) -> Self { + $entity(x) + } + } + }; + + // Include basic `Display` impl using the given display prefix. + // Display a `Block` reference as "block12". + ($entity:ident, $display_prefix:expr) => { + entity_impl!($entity); + + impl $crate::__core::fmt::Display for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { + write!(f, concat!($display_prefix, "{}"), self.0) + } + } + + impl $crate::__core::fmt::Debug for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { + (self as &dyn $crate::__core::fmt::Display).fmt(f) + } + } + }; + + // Alternate form for tuples we can't directly construct; providing "to" and "from" expressions + // to turn an index *into* an entity, or get an index *from* an entity. + ($entity:ident, $display_prefix:expr, $arg:ident, $to_expr:expr, $from_expr:expr) => { + impl $crate::EntityRef for $entity { + #[inline] + fn new(index: usize) -> Self { + debug_assert!(index < ($crate::__core::u32::MAX as usize)); + let $arg = index as u32; + $to_expr + } + + #[inline] + fn index(self) -> usize { + let $arg = self; + $from_expr as usize + } + } + + impl $crate::packed_option::ReservedValue for $entity { + #[inline] + fn reserved_value() -> $entity { + $entity::from_u32($crate::__core::u32::MAX) + } + + #[inline] + fn is_reserved_value(&self) -> bool { + self.as_u32() == $crate::__core::u32::MAX + } + } + + impl $entity { + /// Create a new instance from a `u32`. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn from_u32(x: u32) -> Self { + debug_assert!(x < $crate::__core::u32::MAX); + let $arg = x; + $to_expr + } + + /// Return the underlying index value as a `u32`. + #[allow(dead_code, reason = "macro-generated code")] + #[inline] + pub fn as_u32(self) -> u32 { + let $arg = self; + $from_expr + } + } + + impl $crate::__core::fmt::Display for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { + write!(f, concat!($display_prefix, "{}"), self.as_u32()) + } + } + + impl $crate::__core::fmt::Debug for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { + (self as &dyn $crate::__core::fmt::Display).fmt(f) + } + } + }; +} + +pub mod packed_option; + +mod boxed_slice; +mod iter; +mod keys; +mod list; +mod map; +mod primary; +mod set; +mod signed; +mod sparse; +mod unsigned; + +pub use self::boxed_slice::BoxedSlice; +pub use self::iter::{Iter, IterMut}; +pub use self::keys::Keys; +pub use self::list::{EntityList, ListPool}; +pub use self::map::SecondaryMap; +pub use self::primary::PrimaryMap; +pub use self::set::EntitySet; +pub use self::signed::Signed; +pub use self::sparse::{SparseMap, SparseMapValue, SparseSet}; +pub use self::unsigned::Unsigned; + +/// A collection of tests to ensure that use of the different `entity_impl!` forms will generate +/// `EntityRef` implementations that behave the same way. +#[cfg(test)] +mod tests { + /// A macro used to emit some basic tests to show that entities behave as we expect. + macro_rules! entity_test { + ($entity:ident) => { + #[test] + fn from_usize_to_u32() { + let e = $entity::new(42); + assert_eq!(e.as_u32(), 42_u32); + } + + #[test] + fn from_u32_to_usize() { + let e = $entity::from_u32(42); + assert_eq!(e.index(), 42_usize); + } + + #[test] + fn comparisons_work() { + let a = $entity::from_u32(42); + let b = $entity::new(42); + assert_eq!(a, b); + } + + #[should_panic] + #[cfg(debug_assertions)] + #[test] + fn cannot_construct_from_reserved_u32() { + use crate::packed_option::ReservedValue; + let reserved = $entity::reserved_value().as_u32(); + let _ = $entity::from_u32(reserved); // panic + } + + #[should_panic] + #[cfg(debug_assertions)] + #[test] + fn cannot_construct_from_reserved_usize() { + use crate::packed_option::ReservedValue; + let reserved = $entity::reserved_value().index(); + let _ = $entity::new(reserved); // panic + } + }; + } + + /// Test cases for a plain ol' `EntityRef` implementation. + mod basic_entity { + use crate::EntityRef; + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct BasicEntity(u32); + entity_impl!(BasicEntity); + entity_test!(BasicEntity); + } + + /// Test cases for an `EntityRef` implementation that includes a display prefix. + mod prefix_entity { + use crate::EntityRef; + #[derive(Clone, Copy, PartialEq, Eq)] + struct PrefixEntity(u32); + entity_impl!(PrefixEntity, "prefix-"); + entity_test!(PrefixEntity); + + #[test] + fn display_prefix_works() { + let e = PrefixEntity::new(0); + assert_eq!(alloc::format!("{e}"), "prefix-0"); + } + } + + /// Test cases for an `EntityRef` implementation for a type we can only construct through + /// other means, such as calls to `core::convert::From`. + mod other_entity { + mod inner { + #[derive(Clone, Copy, PartialEq, Eq)] + pub struct InnerEntity(u32); + + impl From for InnerEntity { + fn from(x: u32) -> Self { + Self(x) + } + } + + impl From for u32 { + fn from(x: InnerEntity) -> Self { + x.0 + } + } + } + + use {self::inner::InnerEntity, crate::EntityRef}; + entity_impl!(InnerEntity, "inner-", i, InnerEntity::from(i), u32::from(i)); + entity_test!(InnerEntity); + + #[test] + fn display_prefix_works() { + let e = InnerEntity::new(0); + assert_eq!(alloc::format!("{e}"), "inner-0"); + } + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/list.rs b/deps/crates/vendor/cranelift-entity/src/list.rs new file mode 100644 index 00000000000000..29a6293c19bc72 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/list.rs @@ -0,0 +1,954 @@ +//! Small lists of entity references. +use crate::packed_option::ReservedValue; +use crate::EntityRef; +use alloc::vec::Vec; +use core::marker::PhantomData; +use core::mem; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A small list of entity references allocated from a pool. +/// +/// An `EntityList` type provides similar functionality to `Vec`, but with some important +/// differences in the implementation: +/// +/// 1. Memory is allocated from a `ListPool` instead of the global heap. +/// 2. The footprint of an entity list is 4 bytes, compared with the 24 bytes for `Vec`. +/// 3. An entity list doesn't implement `Drop`, leaving it to the pool to manage memory. +/// +/// The list pool is intended to be used as a LIFO allocator. After building up a larger data +/// structure with many list references, the whole thing can be discarded quickly by clearing the +/// pool. +/// +/// # Safety +/// +/// Entity lists are not as safe to use as `Vec`, but they never jeopardize Rust's memory safety +/// guarantees. These are the problems to be aware of: +/// +/// - If you lose track of an entity list, its memory won't be recycled until the pool is cleared. +/// This can cause the pool to grow very large with leaked lists. +/// - If entity lists are used after their pool is cleared, they may contain garbage data, and +/// modifying them may corrupt other lists in the pool. +/// - If an entity list is used with two different pool instances, both pools are likely to become +/// corrupted. +/// +/// Entity lists can be cloned, but that operation should only be used as part of cloning the whole +/// function they belong to. *Cloning an entity list does not allocate new memory for the clone*. +/// It creates an alias of the same memory. +/// +/// Entity lists cannot be hashed and compared for equality because it's not possible to compare the +/// contents of the list without the pool reference. +/// +/// # Implementation +/// +/// The `EntityList` itself is designed to have the smallest possible footprint. This is important +/// because it is used inside very compact data structures like `InstructionData`. The list +/// contains only a 32-bit index into the pool's memory vector, pointing to the first element of +/// the list. A zero value represents the empty list, which is returned by `EntityList::default`. +/// +/// The pool is just a single `Vec` containing all of the allocated lists. Each list is +/// represented as three contiguous parts: +/// +/// 1. The number of elements in the list. +/// 2. The list elements. +/// 3. Excess capacity elements. +/// +/// The total size of the three parts is always a power of two, and the excess capacity is always +/// as small as possible. This means that shrinking a list may cause the excess capacity to shrink +/// if a smaller power-of-two size becomes available. +/// +/// Both growing and shrinking a list may cause it to be reallocated in the pool vector. +/// +/// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is +/// reserved for the empty list which isn't allocated in the vector. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[repr(C)] +pub struct EntityList { + index: u32, + unused: PhantomData, +} + +/// Create an empty list. +impl Default for EntityList { + fn default() -> Self { + Self { + index: 0, + unused: PhantomData, + } + } +} + +/// A memory pool for storing lists of `T`. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct ListPool { + // The main array containing the lists. + data: Vec, + + // Heads of the free lists, one for each size class. + free: Vec, +} + +impl PartialEq for ListPool { + fn eq(&self, other: &Self) -> bool { + // ignore the free list + self.data == other.data + } +} + +impl core::hash::Hash for ListPool { + fn hash(&self, state: &mut H) { + // ignore the free list + self.data.hash(state); + } +} + +impl Default for ListPool { + fn default() -> Self { + Self::new() + } +} + +/// Lists are allocated in sizes that are powers of two, starting from 4. +/// Each power of two is assigned a size class number, so the size is `4 << SizeClass`. +type SizeClass = u8; + +/// Get the size of a given size class. The size includes the length field, so the maximum list +/// length is one less than the class size. +#[inline] +fn sclass_size(sclass: SizeClass) -> usize { + 4 << sclass +} + +/// Get the size class to use for a given list length. +/// This always leaves room for the length element in addition to the list elements. +#[inline] +fn sclass_for_length(len: usize) -> SizeClass { + 30 - (len as u32 | 3).leading_zeros() as SizeClass +} + +/// Is `len` the minimum length in its size class? +#[inline] +fn is_sclass_min_length(len: usize) -> bool { + len > 3 && len.is_power_of_two() +} + +impl ListPool { + /// Create a new list pool. + pub fn new() -> Self { + Self { + data: Vec::new(), + free: Vec::new(), + } + } + + /// Create a new list pool with the given capacity for data pre-allocated. + pub fn with_capacity(len: usize) -> Self { + Self { + data: Vec::with_capacity(len), + free: Vec::new(), + } + } + + /// Get the capacity of this pool. This will be somewhat higher + /// than the total length of lists that can be stored without + /// reallocating, because of internal metadata overheads. It is + /// mostly useful to allow another pool to be allocated that is + /// likely to hold data transferred from this one without the need + /// to grow. + pub fn capacity(&self) -> usize { + self.data.capacity() + } + + /// Clear the pool, forgetting about all lists that use it. + /// + /// This invalidates any existing entity lists that used this pool to allocate memory. + /// + /// The pool's memory is not released to the operating system, but kept around for faster + /// allocation in the future. + pub fn clear(&mut self) { + self.data.clear(); + self.free.clear(); + } + + /// Read the length of a list field, if it exists. + fn len_of(&self, list: &EntityList) -> Option { + let idx = list.index as usize; + // `idx` points at the list elements. The list length is encoded in the element immediately + // before the list elements. + // + // The `wrapping_sub` handles the special case 0, which is the empty list. This way, the + // cost of the bounds check that we have to pay anyway is co-opted to handle the special + // case of the empty list. + self.data.get(idx.wrapping_sub(1)).map(|len| len.index()) + } + + /// Allocate a storage block with a size given by `sclass`. + /// + /// Returns the first index of an available segment of `self.data` containing + /// `sclass_size(sclass)` elements. The allocated memory is filled with reserved + /// values. + fn alloc(&mut self, sclass: SizeClass) -> usize { + // First try the free list for this size class. + match self.free.get(sclass as usize).cloned() { + Some(head) if head > 0 => { + // The free list pointers are offset by 1, using 0 to terminate the list. + // A block on the free list has two entries: `[ 0, next ]`. + // The 0 is where the length field would be stored for a block in use. + // The free list heads and the next pointer point at the `next` field. + self.free[sclass as usize] = self.data[head].index(); + head - 1 + } + _ => { + // Nothing on the free list. Allocate more memory. + let offset = self.data.len(); + self.data + .resize(offset + sclass_size(sclass), T::reserved_value()); + offset + } + } + } + + /// Free a storage block with a size given by `sclass`. + /// + /// This must be a block that was previously allocated by `alloc()` with the same size class. + fn free(&mut self, block: usize, sclass: SizeClass) { + let sclass = sclass as usize; + + // Make sure we have a free-list head for `sclass`. + if self.free.len() <= sclass { + self.free.resize(sclass + 1, 0); + } + + // Make sure the length field is cleared. + self.data[block] = T::new(0); + // Insert the block on the free list which is a single linked list. + self.data[block + 1] = T::new(self.free[sclass]); + self.free[sclass] = block + 1 + } + + /// Returns two mutable slices representing the two requested blocks. + /// + /// The two returned slices can be longer than the blocks. Each block is located at the front + /// of the respective slice. + fn mut_slices(&mut self, block0: usize, block1: usize) -> (&mut [T], &mut [T]) { + if block0 < block1 { + let (s0, s1) = self.data.split_at_mut(block1); + (&mut s0[block0..], s1) + } else { + let (s1, s0) = self.data.split_at_mut(block0); + (s0, &mut s1[block1..]) + } + } + + /// Reallocate a block to a different size class. + /// + /// Copy `elems_to_copy` elements from the old to the new block. + fn realloc( + &mut self, + block: usize, + from_sclass: SizeClass, + to_sclass: SizeClass, + elems_to_copy: usize, + ) -> usize { + debug_assert!(elems_to_copy <= sclass_size(from_sclass)); + debug_assert!(elems_to_copy <= sclass_size(to_sclass)); + let new_block = self.alloc(to_sclass); + + if elems_to_copy > 0 { + let (old, new) = self.mut_slices(block, new_block); + (&mut new[0..elems_to_copy]).copy_from_slice(&old[0..elems_to_copy]); + } + + self.free(block, from_sclass); + new_block + } +} + +impl EntityList { + /// Create a new empty list. + pub fn new() -> Self { + Default::default() + } + + /// Create a new list with the contents initialized from a slice. + pub fn from_slice(slice: &[T], pool: &mut ListPool) -> Self { + let len = slice.len(); + if len == 0 { + return Self::new(); + } + + let block = pool.alloc(sclass_for_length(len)); + pool.data[block] = T::new(len); + pool.data[block + 1..=block + len].copy_from_slice(slice); + + Self { + index: (block + 1) as u32, + unused: PhantomData, + } + } + + /// Returns `true` if the list has a length of 0. + pub fn is_empty(&self) -> bool { + // 0 is a magic value for the empty list. Any list in the pool array must have a positive + // length. + self.index == 0 + } + + /// Get the number of elements in the list. + pub fn len(&self, pool: &ListPool) -> usize { + // Both the empty list and any invalidated old lists will return `None`. + pool.len_of(self).unwrap_or(0) + } + + /// Returns `true` if the list is valid + pub fn is_valid(&self, pool: &ListPool) -> bool { + // We consider an empty list to be valid + self.is_empty() || pool.len_of(self) != None + } + + /// Get the list as a slice. + pub fn as_slice<'a>(&self, pool: &'a ListPool) -> &'a [T] { + let idx = self.index as usize; + match pool.len_of(self) { + None => &[], + Some(len) => &pool.data[idx..idx + len], + } + } + + /// Get a single element from the list. + pub fn get(&self, index: usize, pool: &ListPool) -> Option { + self.as_slice(pool).get(index).cloned() + } + + /// Get the first element from the list. + pub fn first(&self, pool: &ListPool) -> Option { + if self.is_empty() { + None + } else { + Some(pool.data[self.index as usize]) + } + } + + /// Get the list as a mutable slice. + pub fn as_mut_slice<'a>(&'a mut self, pool: &'a mut ListPool) -> &'a mut [T] { + let idx = self.index as usize; + match pool.len_of(self) { + None => &mut [], + Some(len) => &mut pool.data[idx..idx + len], + } + } + + /// Get a mutable reference to a single element from the list. + pub fn get_mut<'a>(&'a mut self, index: usize, pool: &'a mut ListPool) -> Option<&'a mut T> { + self.as_mut_slice(pool).get_mut(index) + } + + /// Create a deep clone of the list, which does not alias the original list. + pub fn deep_clone(&self, pool: &mut ListPool) -> Self { + match pool.len_of(self) { + None => return Self::new(), + Some(len) => { + let src = self.index as usize; + let block = pool.alloc(sclass_for_length(len)); + pool.data[block] = T::new(len); + pool.data.copy_within(src..src + len, block + 1); + + Self { + index: (block + 1) as u32, + unused: PhantomData, + } + } + } + } + + /// Removes all elements from the list. + /// + /// The memory used by the list is put back in the pool. + pub fn clear(&mut self, pool: &mut ListPool) { + let idx = self.index as usize; + match pool.len_of(self) { + None => debug_assert_eq!(idx, 0, "Invalid pool"), + Some(len) => pool.free(idx - 1, sclass_for_length(len)), + } + // Switch back to the empty list representation which has no storage. + self.index = 0; + } + + /// Take all elements from this list and return them as a new list. Leave this list empty. + /// + /// This is the equivalent of `Option::take()`. + pub fn take(&mut self) -> Self { + mem::replace(self, Default::default()) + } + + /// Appends an element to the back of the list. + /// Returns the index where the element was inserted. + pub fn push(&mut self, element: T, pool: &mut ListPool) -> usize { + let idx = self.index as usize; + match pool.len_of(self) { + None => { + // This is an empty list. Allocate a block and set length=1. + debug_assert_eq!(idx, 0, "Invalid pool"); + let block = pool.alloc(sclass_for_length(1)); + pool.data[block] = T::new(1); + pool.data[block + 1] = element; + self.index = (block + 1) as u32; + 0 + } + Some(len) => { + // Do we need to reallocate? + let new_len = len + 1; + let block; + if is_sclass_min_length(new_len) { + // Reallocate, preserving length + all old elements. + let sclass = sclass_for_length(len); + block = pool.realloc(idx - 1, sclass, sclass + 1, len + 1); + self.index = (block + 1) as u32; + } else { + block = idx - 1; + } + pool.data[block + new_len] = element; + pool.data[block] = T::new(new_len); + len + } + } + } + + /// Grow list by adding `count` reserved-value elements at the end. + /// + /// Returns a mutable slice representing the whole list. + fn grow<'a>(&'a mut self, count: usize, pool: &'a mut ListPool) -> &'a mut [T] { + let idx = self.index as usize; + let new_len; + let block; + match pool.len_of(self) { + None => { + // This is an empty list. Allocate a block. + debug_assert_eq!(idx, 0, "Invalid pool"); + if count == 0 { + return &mut []; + } + new_len = count; + block = pool.alloc(sclass_for_length(new_len)); + self.index = (block + 1) as u32; + } + Some(len) => { + // Do we need to reallocate? + let sclass = sclass_for_length(len); + new_len = len + count; + let new_sclass = sclass_for_length(new_len); + if new_sclass != sclass { + block = pool.realloc(idx - 1, sclass, new_sclass, len + 1); + self.index = (block + 1) as u32; + } else { + block = idx - 1; + } + } + } + pool.data[block] = T::new(new_len); + &mut pool.data[block + 1..block + 1 + new_len] + } + + /// Constructs a list from an iterator. + pub fn from_iter(elements: I, pool: &mut ListPool) -> Self + where + I: IntoIterator, + { + let mut list = Self::new(); + list.extend(elements, pool); + list + } + + /// Appends multiple elements to the back of the list. + pub fn extend(&mut self, elements: I, pool: &mut ListPool) + where + I: IntoIterator, + { + let iterator = elements.into_iter(); + let (len, upper) = iterator.size_hint(); + // On most iterators this check is optimized down to `true`. + if upper == Some(len) { + let data = self.grow(len, pool); + let offset = data.len() - len; + for (src, dst) in iterator.zip(data[offset..].iter_mut()) { + *dst = src; + } + } else { + for x in iterator { + self.push(x, pool); + } + } + } + + /// Copies a slice from an entity list in the same pool to a position in this one. + /// + /// Will panic if `self` is the same list as `other`. + pub fn copy_from( + &mut self, + other: &Self, + slice: impl core::ops::RangeBounds, + index: usize, + pool: &mut ListPool, + ) { + assert!( + index <= self.len(pool), + "attempted to copy a slice out of bounds of `self`" + ); + assert_ne!( + self.index, other.index, + "cannot copy within one `EntityList`" + ); + + let (other_index, other_len) = (other.index, other.len(pool)); + + let start = match slice.start_bound() { + core::ops::Bound::Included(&x) => x, + core::ops::Bound::Excluded(&x) => x + 1, + core::ops::Bound::Unbounded => 0, + } + other_index as usize; + let end = match slice.end_bound() { + core::ops::Bound::Included(&x) => x + 1, + core::ops::Bound::Excluded(&x) => x, + core::ops::Bound::Unbounded => other_len, + } + other_index as usize; + let count = end - start; + assert!( + count <= other_len, + "attempted to copy a slice from out of bounds of `other`" + ); + + self.grow_at(index, count, pool); + pool.data + .copy_within(start..end, index + self.index as usize); + } + + /// Inserts an element as position `index` in the list, shifting all elements after it to the + /// right. + pub fn insert(&mut self, index: usize, element: T, pool: &mut ListPool) { + // Increase size by 1. + self.push(element, pool); + + // Move tail elements. + let seq = self.as_mut_slice(pool); + if index < seq.len() { + let tail = &mut seq[index..]; + for i in (1..tail.len()).rev() { + tail[i] = tail[i - 1]; + } + tail[0] = element; + } else { + debug_assert_eq!(index, seq.len()); + } + } + + /// Removes the last element from the list. + fn remove_last(&mut self, len: usize, pool: &mut ListPool) { + // Check if we deleted the last element. + if len == 1 { + self.clear(pool); + return; + } + + // Do we need to reallocate to a smaller size class? + let mut block = self.index as usize - 1; + if is_sclass_min_length(len) { + let sclass = sclass_for_length(len); + block = pool.realloc(block, sclass, sclass - 1, len); + self.index = (block + 1) as u32; + } + + // Finally adjust the length. + pool.data[block] = T::new(len - 1); + } + + /// Removes the element at position `index` from the list. Potentially linear complexity. + pub fn remove(&mut self, index: usize, pool: &mut ListPool) { + let len; + { + let seq = self.as_mut_slice(pool); + len = seq.len(); + debug_assert!(index < len); + + // Copy elements down. + for i in index..len - 1 { + seq[i] = seq[i + 1]; + } + } + + self.remove_last(len, pool); + } + + /// Removes the element at `index` in constant time by switching it with the last element of + /// the list. + pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool) { + let seq = self.as_mut_slice(pool); + let len = seq.len(); + debug_assert!(index < len); + if index != len - 1 { + seq.swap(index, len - 1); + } + + self.remove_last(len, pool); + } + + /// Shortens the list down to `len` elements. + /// + /// Does nothing if the list is already shorter than `len`. + pub fn truncate(&mut self, new_len: usize, pool: &mut ListPool) { + if new_len == 0 { + self.clear(pool); + return; + } + + match pool.len_of(self) { + None => return, + Some(len) => { + if len <= new_len { + return; + } + + let block; + let idx = self.index as usize; + let sclass = sclass_for_length(len); + let new_sclass = sclass_for_length(new_len); + if sclass != new_sclass { + block = pool.realloc(idx - 1, sclass, new_sclass, new_len + 1); + self.index = (block + 1) as u32; + } else { + block = idx - 1; + } + pool.data[block] = T::new(new_len); + } + } + } + + /// Grow the list by inserting `count` elements at `index`. + /// + /// The new elements are not initialized, they will contain whatever happened to be in memory. + /// Since the memory comes from the pool, this will be either zero entity references or + /// whatever where in a previously deallocated list. + pub fn grow_at(&mut self, index: usize, count: usize, pool: &mut ListPool) { + let data = self.grow(count, pool); + + // Copy elements after `index` up. + for i in (index + count..data.len()).rev() { + data[i] = data[i - count]; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// An opaque reference to an instruction in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Inst(u32); + entity_impl!(Inst, "inst"); + + #[test] + fn size_classes() { + assert_eq!(sclass_size(0), 4); + assert_eq!(sclass_for_length(0), 0); + assert_eq!(sclass_for_length(1), 0); + assert_eq!(sclass_for_length(2), 0); + assert_eq!(sclass_for_length(3), 0); + assert_eq!(sclass_for_length(4), 1); + assert_eq!(sclass_for_length(7), 1); + assert_eq!(sclass_for_length(8), 2); + assert_eq!(sclass_size(1), 8); + for l in 0..300 { + assert!(sclass_size(sclass_for_length(l)) >= l + 1); + } + } + + #[test] + fn block_allocator() { + let mut pool = ListPool::::new(); + let b1 = pool.alloc(0); + let b2 = pool.alloc(1); + let b3 = pool.alloc(0); + assert_ne!(b1, b2); + assert_ne!(b1, b3); + assert_ne!(b2, b3); + pool.free(b2, 1); + let b2a = pool.alloc(1); + let b2b = pool.alloc(1); + assert_ne!(b2a, b2b); + // One of these should reuse the freed block. + assert!(b2a == b2 || b2b == b2); + + // Check the free lists for a size class smaller than the largest seen so far. + pool.free(b1, 0); + pool.free(b3, 0); + let b1a = pool.alloc(0); + let b3a = pool.alloc(0); + assert_ne!(b1a, b3a); + assert!(b1a == b1 || b1a == b3); + assert!(b3a == b1 || b3a == b3); + } + + #[test] + fn empty_list() { + let pool = &mut ListPool::::new(); + let mut list = EntityList::::default(); + { + let ilist = &list; + assert!(ilist.is_empty()); + assert_eq!(ilist.len(pool), 0); + assert_eq!(ilist.as_slice(pool), &[]); + assert_eq!(ilist.get(0, pool), None); + assert_eq!(ilist.get(100, pool), None); + } + assert_eq!(list.as_mut_slice(pool), &[]); + assert_eq!(list.get_mut(0, pool), None); + assert_eq!(list.get_mut(100, pool), None); + + list.clear(pool); + assert!(list.is_empty()); + assert_eq!(list.len(pool), 0); + assert_eq!(list.as_slice(pool), &[]); + assert_eq!(list.first(pool), None); + } + + #[test] + fn from_slice() { + let pool = &mut ListPool::::new(); + + let list = EntityList::::from_slice(&[Inst(0), Inst(1)], pool); + assert!(!list.is_empty()); + assert_eq!(list.len(pool), 2); + assert_eq!(list.as_slice(pool), &[Inst(0), Inst(1)]); + assert_eq!(list.get(0, pool), Some(Inst(0))); + assert_eq!(list.get(100, pool), None); + + let list = EntityList::::from_slice(&[], pool); + assert!(list.is_empty()); + assert_eq!(list.len(pool), 0); + assert_eq!(list.as_slice(pool), &[]); + assert_eq!(list.get(0, pool), None); + assert_eq!(list.get(100, pool), None); + } + + #[test] + fn push() { + let pool = &mut ListPool::::new(); + let mut list = EntityList::::default(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + assert_eq!(list.push(i1, pool), 0); + assert_eq!(list.len(pool), 1); + assert!(!list.is_empty()); + assert_eq!(list.as_slice(pool), &[i1]); + assert_eq!(list.first(pool), Some(i1)); + assert_eq!(list.get(0, pool), Some(i1)); + assert_eq!(list.get(1, pool), None); + + assert_eq!(list.push(i2, pool), 1); + assert_eq!(list.len(pool), 2); + assert!(!list.is_empty()); + assert_eq!(list.as_slice(pool), &[i1, i2]); + assert_eq!(list.first(pool), Some(i1)); + assert_eq!(list.get(0, pool), Some(i1)); + assert_eq!(list.get(1, pool), Some(i2)); + assert_eq!(list.get(2, pool), None); + + assert_eq!(list.push(i3, pool), 2); + assert_eq!(list.len(pool), 3); + assert!(!list.is_empty()); + assert_eq!(list.as_slice(pool), &[i1, i2, i3]); + assert_eq!(list.first(pool), Some(i1)); + assert_eq!(list.get(0, pool), Some(i1)); + assert_eq!(list.get(1, pool), Some(i2)); + assert_eq!(list.get(2, pool), Some(i3)); + assert_eq!(list.get(3, pool), None); + + // This triggers a reallocation. + assert_eq!(list.push(i4, pool), 3); + assert_eq!(list.len(pool), 4); + assert!(!list.is_empty()); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]); + assert_eq!(list.first(pool), Some(i1)); + assert_eq!(list.get(0, pool), Some(i1)); + assert_eq!(list.get(1, pool), Some(i2)); + assert_eq!(list.get(2, pool), Some(i3)); + assert_eq!(list.get(3, pool), Some(i4)); + assert_eq!(list.get(4, pool), None); + + list.extend([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool); + assert_eq!(list.len(pool), 12); + assert_eq!( + list.as_slice(pool), + &[i1, i2, i3, i4, i1, i1, i2, i2, i3, i3, i4, i4] + ); + + let list2 = EntityList::from_iter([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool); + assert_eq!(list2.len(pool), 8); + assert_eq!(list2.as_slice(pool), &[i1, i1, i2, i2, i3, i3, i4, i4]); + } + + #[test] + fn insert_remove() { + let pool = &mut ListPool::::new(); + let mut list = EntityList::::default(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + list.insert(0, i4, pool); + assert_eq!(list.as_slice(pool), &[i4]); + + list.insert(0, i3, pool); + assert_eq!(list.as_slice(pool), &[i3, i4]); + + list.insert(2, i2, pool); + assert_eq!(list.as_slice(pool), &[i3, i4, i2]); + + list.insert(2, i1, pool); + assert_eq!(list.as_slice(pool), &[i3, i4, i1, i2]); + + list.remove(3, pool); + assert_eq!(list.as_slice(pool), &[i3, i4, i1]); + + list.remove(2, pool); + assert_eq!(list.as_slice(pool), &[i3, i4]); + + list.remove(0, pool); + assert_eq!(list.as_slice(pool), &[i4]); + + list.remove(0, pool); + assert_eq!(list.as_slice(pool), &[]); + assert!(list.is_empty()); + } + + #[test] + fn growing() { + let pool = &mut ListPool::::new(); + let mut list = EntityList::::default(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + // This is not supposed to change the list. + list.grow_at(0, 0, pool); + assert_eq!(list.len(pool), 0); + assert!(list.is_empty()); + + list.grow_at(0, 2, pool); + assert_eq!(list.len(pool), 2); + + list.as_mut_slice(pool).copy_from_slice(&[i2, i3]); + + list.grow_at(1, 0, pool); + assert_eq!(list.as_slice(pool), &[i2, i3]); + + list.grow_at(1, 1, pool); + list.as_mut_slice(pool)[1] = i1; + assert_eq!(list.as_slice(pool), &[i2, i1, i3]); + + // Append nothing at the end. + list.grow_at(3, 0, pool); + assert_eq!(list.as_slice(pool), &[i2, i1, i3]); + + // Append something at the end. + list.grow_at(3, 1, pool); + list.as_mut_slice(pool)[3] = i4; + assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]); + } + + #[test] + fn deep_clone() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list1 = EntityList::from_slice(&[i1, i2, i3], pool); + let list2 = list1.deep_clone(pool); + assert_eq!(list1.as_slice(pool), &[i1, i2, i3]); + assert_eq!(list2.as_slice(pool), &[i1, i2, i3]); + + list1.as_mut_slice(pool)[0] = i4; + assert_eq!(list1.as_slice(pool), &[i4, i2, i3]); + assert_eq!(list2.as_slice(pool), &[i1, i2, i3]); + } + + #[test] + fn truncate() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list = EntityList::from_slice(&[i1, i2, i3, i4, i1, i2, i3, i4], pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2, i3, i4]); + list.truncate(6, pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]); + list.truncate(9, pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]); + list.truncate(2, pool); + assert_eq!(list.as_slice(pool), &[i1, i2]); + list.truncate(0, pool); + assert!(list.is_empty()); + } + + #[test] + fn copy_from() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list = EntityList::from_slice(&[i1, i2, i3, i4], pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]); + let list2 = EntityList::from_slice(&[i4, i3, i2, i1], pool); + assert_eq!(list2.as_slice(pool), &[i4, i3, i2, i1]); + list.copy_from(&list2, 0..0, 0, pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]); + list.copy_from(&list2, 0..4, 0, pool); + assert_eq!(list.as_slice(pool), &[i4, i3, i2, i1, i1, i2, i3, i4]); + } + + #[test] + #[should_panic] + fn copy_from_self() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list = EntityList::from_slice(&[i4, i3, i2, i1, i1, i2, i3, i4], pool); + let list_again = list; + assert_eq!(list.as_slice(pool), &[i4, i3, i2, i1, i1, i2, i3, i4]); + // Panic should occur on the line below because `list.index == other.index` + list.copy_from(&list_again, 0..=1, 8, pool); + assert_eq!( + list.as_slice(pool), + &[i4, i3, i2, i1, i1, i2, i3, i4, i4, i3] + ); + list.copy_from(&list_again, .., 7, pool); + assert_eq!( + list.as_slice(pool), + &[i4, i3, i2, i1, i1, i2, i4, i3, i2, i1, i1, i2, i3, i4, i4, i3, i3, i4, i4, i3] + ) + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/map.rs b/deps/crates/vendor/cranelift-entity/src/map.rs new file mode 100644 index 00000000000000..332cd061b73d51 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/map.rs @@ -0,0 +1,326 @@ +//! Densely numbered entity references as mapping keys. + +use crate::iter::{Iter, IterMut}; +use crate::keys::Keys; +use crate::EntityRef; +use alloc::vec::Vec; +use core::cmp::min; +use core::marker::PhantomData; +use core::ops::{Index, IndexMut}; +use core::slice; +#[cfg(feature = "enable-serde")] +use serde::{ + de::{Deserializer, SeqAccess, Visitor}, + ser::{SerializeSeq, Serializer}, + Deserialize, Serialize, +}; + +/// A mapping `K -> V` for densely indexed entity references. +/// +/// The `SecondaryMap` data structure uses the dense index space to implement a map with a vector. +/// Unlike `PrimaryMap`, an `SecondaryMap` can't be used to allocate entity references. It is used +/// to associate secondary information with entities. +/// +/// The map does not track if an entry for a key has been inserted or not. Instead it behaves as if +/// all keys have a default entry from the beginning. +#[derive(Debug, Clone, Hash)] +pub struct SecondaryMap +where + K: EntityRef, + V: Clone, +{ + elems: Vec, + default: V, + unused: PhantomData, +} + +/// Shared `SecondaryMap` implementation for all value types. +impl SecondaryMap +where + K: EntityRef, + V: Clone, +{ + /// Create a new empty map. + pub fn new() -> Self + where + V: Default, + { + Self { + elems: Vec::new(), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new, empty map with the specified capacity. + /// + /// The map will be able to hold exactly `capacity` elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self + where + V: Default, + { + Self { + elems: Vec::with_capacity(capacity), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new empty map with a specified default value. + /// + /// This constructor does not require V to implement Default. + pub fn with_default(default: V) -> Self { + Self { + elems: Vec::new(), + default, + unused: PhantomData, + } + } + + /// Returns the number of elements the map can hold without reallocating. + pub fn capacity(&self) -> usize { + self.elems.capacity() + } + + /// Get the element at `k` if it exists. + #[inline(always)] + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Is this map completely empty? + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Remove all entries from this map. + #[inline(always)] + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Resize the map to have `n` entries by adding default entries as needed. + pub fn resize(&mut self, n: usize) { + self.elems.resize(n, self.default.clone()); + } + + /// Slow path for `index_mut` which resizes the vector. + #[cold] + fn resize_for_index_mut(&mut self, i: usize) -> &mut V { + self.elems.resize(i + 1, self.default.clone()); + &mut self.elems[i] + } +} + +impl Default for SecondaryMap +where + K: EntityRef, + V: Clone + Default, +{ + fn default() -> SecondaryMap { + SecondaryMap::new() + } +} + +/// Immutable indexing into an `SecondaryMap`. +/// +/// All keys are permitted. Untouched entries have the default value. +impl Index for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + type Output = V; + + #[inline(always)] + fn index(&self, k: K) -> &V { + self.elems.get(k.index()).unwrap_or(&self.default) + } +} + +/// Mutable indexing into an `SecondaryMap`. +/// +/// The map grows as needed to accommodate new keys. +impl IndexMut for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + #[inline(always)] + fn index_mut(&mut self, k: K) -> &mut V { + let i = k.index(); + if i >= self.elems.len() { + return self.resize_for_index_mut(i); + } + &mut self.elems[i] + } +} + +impl PartialEq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + let min_size = min(self.elems.len(), other.elems.len()); + self.default == other.default + && self.elems[..min_size] == other.elems[..min_size] + && self.elems[min_size..].iter().all(|e| *e == self.default) + && other.elems[min_size..].iter().all(|e| *e == other.default) + } +} + +impl Eq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Eq, +{ +} + +#[cfg(feature = "enable-serde")] +impl Serialize for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // TODO: bincode encodes option as "byte for Some/None" and then optionally the content + // TODO: we can actually optimize it by encoding manually bitmask, then elements + let mut elems_cnt = self.elems.len(); + while elems_cnt > 0 && self.elems[elems_cnt - 1] == self.default { + elems_cnt -= 1; + } + let mut seq = serializer.serialize_seq(Some(1 + elems_cnt))?; + seq.serialize_element(&Some(self.default.clone()))?; + for e in self.elems.iter().take(elems_cnt) { + let some_e = Some(e); + seq.serialize_element(if *e == self.default { &None } else { &some_e })?; + } + seq.end() + } +} + +#[cfg(feature = "enable-serde")] +impl<'de, K, V> Deserialize<'de> for SecondaryMap +where + K: EntityRef, + V: Clone + Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use alloc::fmt; + struct SecondaryMapVisitor { + unused: PhantomData V>, + } + + impl<'de, K, V> Visitor<'de> for SecondaryMapVisitor + where + K: EntityRef, + V: Clone + Deserialize<'de>, + { + type Value = SecondaryMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SecondaryMap") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + match seq.next_element()? { + Some(Some(default_val)) => { + let default_val: V = default_val; // compiler can't infer the type + let mut m = SecondaryMap::with_default(default_val.clone()); + let mut idx = 0; + while let Some(val) = seq.next_element()? { + let val: Option<_> = val; // compiler can't infer the type + m[K::new(idx)] = val.unwrap_or_else(|| default_val.clone()); + idx += 1; + } + Ok(m) + } + _ => Err(serde::de::Error::custom("Default value required")), + } + } + } + + deserializer.deserialize_seq(SecondaryMapVisitor { + unused: PhantomData {}, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = SecondaryMap::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + m[r2] = 3; + m[r1] = 5; + + assert_eq!(m[r1], 5); + assert_eq!(m[r2], 3); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [r0, r1, r2]); + + let shared = &m; + assert_eq!(shared[r0], 0); + assert_eq!(shared[r1], 5); + assert_eq!(shared[r2], 3); + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/packed_option.rs b/deps/crates/vendor/cranelift-entity/src/packed_option.rs new file mode 100644 index 00000000000000..e4b949f3481832 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/packed_option.rs @@ -0,0 +1,177 @@ +//! Compact representation of `Option` for types with a reserved value. +//! +//! Small Cranelift types like the 32-bit entity references are often used in tables and linked +//! lists where an `Option` is needed. Unfortunately, that would double the size of the tables +//! because `Option` is twice as big as `T`. +//! +//! This module provides a `PackedOption` for types that have a reserved value that can be used +//! to represent `None`. + +use core::fmt; +use core::mem; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Types that have a reserved value which can't be created any other way. +pub trait ReservedValue { + /// Create an instance of the reserved value. + fn reserved_value() -> Self; + /// Checks whether value is the reserved one. + fn is_reserved_value(&self) -> bool; +} + +/// Packed representation of `Option`. +/// +/// This is a wrapper around a `T`, using `T::reserved_value` to represent +/// `None`. +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[repr(transparent)] +pub struct PackedOption(T); + +impl PackedOption { + /// Returns `true` if the packed option is a `None` value. + pub fn is_none(&self) -> bool { + self.0.is_reserved_value() + } + + /// Returns `true` if the packed option is a `Some` value. + pub fn is_some(&self) -> bool { + !self.0.is_reserved_value() + } + + /// Expand the packed option into a normal `Option`. + pub fn expand(self) -> Option { + if self.is_none() { + None + } else { + Some(self.0) + } + } + + /// Maps a `PackedOption` to `Option` by applying a function to a contained value. + pub fn map(self, f: F) -> Option + where + F: FnOnce(T) -> U, + { + self.expand().map(f) + } + + /// Unwrap a packed `Some` value or panic. + #[track_caller] + pub fn unwrap(self) -> T { + self.expand().unwrap() + } + + /// Unwrap a packed `Some` value or panic. + #[track_caller] + pub fn expect(self, msg: &str) -> T { + self.expand().expect(msg) + } + + /// Takes the value out of the packed option, leaving a `None` in its place. + pub fn take(&mut self) -> Option { + mem::replace(self, None.into()).expand() + } +} + +impl Default for PackedOption { + /// Create a default packed option representing `None`. + fn default() -> Self { + Self(T::reserved_value()) + } +} + +impl From for PackedOption { + /// Convert `t` into a packed `Some(x)`. + fn from(t: T) -> Self { + debug_assert!( + !t.is_reserved_value(), + "Can't make a PackedOption from the reserved value." + ); + Self(t) + } +} + +impl From> for PackedOption { + /// Convert an option into its packed equivalent. + fn from(opt: Option) -> Self { + match opt { + None => Self::default(), + Some(t) => t.into(), + } + } +} + +impl Into> for PackedOption { + fn into(self) -> Option { + self.expand() + } +} + +impl fmt::Debug for PackedOption +where + T: ReservedValue + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_none() { + write!(f, "None") + } else { + write!(f, "Some({:?})", self.0) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Dummy entity class, with no Copy or Clone. + #[derive(Debug, PartialEq, Eq)] + struct NoC(u32); + + impl ReservedValue for NoC { + fn reserved_value() -> Self { + NoC(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn moves() { + let x = NoC(3); + let somex: PackedOption = x.into(); + assert!(!somex.is_none()); + assert_eq!(somex.expand(), Some(NoC(3))); + + let none: PackedOption = None.into(); + assert!(none.is_none()); + assert_eq!(none.expand(), None); + } + + // Dummy entity class, with Copy. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Ent(u32); + + impl ReservedValue for Ent { + fn reserved_value() -> Self { + Ent(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn copies() { + let x = Ent(2); + let some: PackedOption = x.into(); + assert_eq!(some.expand(), x.into()); + assert_eq!(some, x.into()); + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/primary.rs b/deps/crates/vendor/cranelift-entity/src/primary.rs new file mode 100644 index 00000000000000..b47e8073db9c57 --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/primary.rs @@ -0,0 +1,540 @@ +//! Densely numbered entity references as mapping keys. +use crate::boxed_slice::BoxedSlice; +use crate::iter::{IntoIter, Iter, IterMut}; +use crate::keys::Keys; +use crate::EntityRef; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::marker::PhantomData; +use core::mem; +use core::ops::{Index, IndexMut}; +use core::slice; +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// A primary mapping `K -> V` allocating dense entity references. +/// +/// The `PrimaryMap` data structure uses the dense index space to implement a map with a vector. +/// +/// A primary map contains the main definition of an entity, and it can be used to allocate new +/// entity references with the `push` method. +/// +/// There should only be a single `PrimaryMap` instance for a given `EntityRef` type, otherwise +/// conflicting references will be created. Using unknown keys for indexing will cause a panic. +/// +/// Note that `PrimaryMap` doesn't implement `Deref` or `DerefMut`, which would allow +/// `&PrimaryMap` to convert to `&[V]`. One of the main advantages of `PrimaryMap` is +/// that it only allows indexing with the distinct `EntityRef` key type, so converting to a +/// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use +/// `into_boxed_slice`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PrimaryMap +where + K: EntityRef, +{ + elems: Vec, + unused: PhantomData, +} + +impl PrimaryMap +where + K: EntityRef, +{ + /// Create a new empty map. + pub fn new() -> Self { + Self { + elems: Vec::new(), + unused: PhantomData, + } + } + + /// Create a new empty map with the given capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + elems: Vec::with_capacity(capacity), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Remove all entries from this map. + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Get the key that will be assigned to the next pushed value. + pub fn next_key(&self) -> K { + K::new(self.elems.len()) + } + + /// Append `v` to the mapping, assigning a new key which is returned. + pub fn push(&mut self, v: V) -> K { + let k = self.next_key(); + self.elems.push(v); + k + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<(K, &V)> { + let len = self.elems.len(); + let last = self.elems.last()?; + Some((K::new(len - 1), last)) + } + + /// Returns the last element that was inserted in the map. + pub fn last_mut(&mut self) -> Option<(K, &mut V)> { + let len = self.elems.len(); + let last = self.elems.last_mut()?; + Some((K::new(len - 1), last)) + } + + /// Reserves capacity for at least `additional` more elements to be inserted. + pub fn reserve(&mut self, additional: usize) { + self.elems.reserve(additional) + } + + /// Reserves the minimum capacity for exactly `additional` more elements to be inserted. + pub fn reserve_exact(&mut self, additional: usize) { + self.elems.reserve_exact(additional) + } + + /// Shrinks the capacity of the `PrimaryMap` as much as possible. + pub fn shrink_to_fit(&mut self) { + self.elems.shrink_to_fit() + } + + /// Consumes this `PrimaryMap` and produces a `BoxedSlice`. + pub fn into_boxed_slice(self) -> BoxedSlice { + unsafe { BoxedSlice::::from_raw(Box::<[V]>::into_raw(self.elems.into_boxed_slice())) } + } + + /// Returns mutable references to many elements at once. + /// + /// Returns an error if an element does not exist, or if the same key was passed more than + /// once. + // This implementation is taken from the unstable `get_many_mut`. + // + // Once it has been stabilised we can call that method directly. + pub fn get_many_mut( + &mut self, + indices: [K; N], + ) -> Result<[&mut V; N], GetManyMutError> { + for (i, &idx) in indices.iter().enumerate() { + if idx.index() >= self.len() { + return Err(GetManyMutError::DoesNotExist(idx)); + } + for &idx2 in &indices[..i] { + if idx == idx2 { + return Err(GetManyMutError::MultipleOf(idx)); + } + } + } + + let slice: *mut V = self.elems.as_mut_ptr(); + let mut arr: mem::MaybeUninit<[&mut V; N]> = mem::MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + unsafe { + for i in 0..N { + let idx = *indices.get_unchecked(i); + *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.add(idx.index()); + } + Ok(arr.assume_init()) + } + } + + /// Performs a binary search on the values with a key extraction function. + /// + /// Assumes that the values are sorted by the key extracted by the function. + /// + /// If the value is found then `Ok(K)` is returned, containing the entity key + /// of the matching value. + /// + /// If there are multiple matches, then any one of the matches could be returned. + /// + /// If the value is not found then Err(K) is returned, containing the entity key + /// where a matching element could be inserted while maintaining sorted order. + pub fn binary_search_values_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where + F: FnMut(&'a V) -> B, + B: Ord, + { + self.elems + .binary_search_by_key(b, f) + .map(|i| K::new(i)) + .map_err(|i| K::new(i)) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum GetManyMutError { + DoesNotExist(K), + MultipleOf(K), +} + +impl Default for PrimaryMap +where + K: EntityRef, +{ + fn default() -> PrimaryMap { + PrimaryMap::new() + } +} + +/// Immutable indexing into an `PrimaryMap`. +/// The indexed value must be in the map. +impl Index for PrimaryMap +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into an `PrimaryMap`. +impl IndexMut for PrimaryMap +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl IntoIterator for PrimaryMap +where + K: EntityRef, +{ + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.elems.into_iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +impl FromIterator for PrimaryMap +where + K: EntityRef, +{ + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + Self { + elems: Vec::from_iter(iter), + unused: PhantomData, + } + } +} + +impl From> for PrimaryMap +where + K: EntityRef, +{ + fn from(elems: Vec) -> Self { + Self { + elems, + unused: PhantomData, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let m = PrimaryMap::::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn push() { + let mut m = PrimaryMap::new(); + let k0: E = m.push(12); + let k1 = m.push(33); + + assert_eq!(m[k0], 12); + assert_eq!(m[k1], 33); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [k0, k1]); + } + + #[test] + fn iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } + + #[test] + fn from_iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let n = m.values().collect::>(); + assert!(m.len() == n.len()); + for (me, ne) in m.values().zip(n.values()) { + assert!(*me == **ne); + } + } + + #[test] + fn from_vec() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let n = PrimaryMap::::from(m.values().collect::>()); + assert!(m.len() == n.len()); + for (me, ne) in m.values().zip(n.values()) { + assert!(*me == **ne); + } + } + + #[test] + fn get_many_mut() { + let mut m: PrimaryMap = PrimaryMap::new(); + let _0 = m.push(0); + let _1 = m.push(1); + let _2 = m.push(2); + + assert_eq!([&mut 0, &mut 2], m.get_many_mut([_0, _2]).unwrap()); + assert_eq!( + m.get_many_mut([_0, _0]), + Err(GetManyMutError::MultipleOf(_0)) + ); + assert_eq!( + m.get_many_mut([E(4)]), + Err(GetManyMutError::DoesNotExist(E(4))) + ); + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/set.rs b/deps/crates/vendor/cranelift-entity/src/set.rs new file mode 100644 index 00000000000000..3c5925a219b89b --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/set.rs @@ -0,0 +1,207 @@ +//! Densely numbered entity references as set keys. + +use crate::keys::Keys; +use crate::EntityRef; +use core::marker::PhantomData; +use cranelift_bitset::CompoundBitSet; + +/// A set of `K` for densely indexed entity references. +/// +/// The `EntitySet` data structure uses the dense index space to implement a set with a bitvector. +/// Like `SecondaryMap`, an `EntitySet` is used to associate secondary information with entities. +#[derive(Debug, Clone)] +pub struct EntitySet +where + K: EntityRef, +{ + bitset: CompoundBitSet, + unused: PhantomData, +} + +impl Default for EntitySet { + fn default() -> Self { + Self { + bitset: CompoundBitSet::default(), + unused: PhantomData, + } + } +} + +impl Extend for EntitySet { + fn extend>(&mut self, iter: T) { + for k in iter { + self.insert(k); + } + } +} + +/// Shared `EntitySet` implementation for all value types. +impl EntitySet +where + K: EntityRef, +{ + /// Create a new empty set. + pub fn new() -> Self { + Self::default() + } + + /// Creates a new empty set with the specified capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + bitset: CompoundBitSet::with_capacity(capacity), + unused: PhantomData, + } + } + + /// Ensure that the set has enough capacity to hold `capacity` total + /// elements. + pub fn ensure_capacity(&mut self, capacity: usize) { + self.bitset.ensure_capacity(capacity); + } + + /// Get the element at `k` if it exists. + pub fn contains(&self, k: K) -> bool { + let index = k.index(); + self.bitset.contains(index) + } + + /// Is this set completely empty? + pub fn is_empty(&self) -> bool { + self.bitset.is_empty() + } + + /// Remove all entries from this set. + pub fn clear(&mut self) { + self.bitset.clear() + } + + /// Iterate over all the keys in this set. + pub fn keys(&self) -> Keys { + Keys::with_len(self.bitset.max().map_or(0, |x| x + 1)) + } + + /// Insert the element at `k`. + pub fn insert(&mut self, k: K) -> bool { + let index = k.index(); + self.bitset.insert(index) + } + + /// Removes and returns the entity from the set if it exists. + pub fn pop(&mut self) -> Option { + let index = self.bitset.pop()?; + Some(K::new(index)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec::Vec; + use core::u32; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = EntitySet::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + assert!(m.is_empty()); + + m.insert(r2); + m.insert(r1); + + assert!(!m.contains(r0)); + assert!(m.contains(r1)); + assert!(m.contains(r2)); + assert!(!m.contains(E(3))); + assert!(!m.is_empty()); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [r0, r1, r2]); + + assert!(!m.contains(E(3))); + assert!(!m.contains(E(4))); + assert!(!m.contains(E(8))); + assert!(!m.contains(E(15))); + assert!(!m.contains(E(19))); + + m.insert(E(8)); + m.insert(E(15)); + assert!(!m.contains(E(3))); + assert!(!m.contains(E(4))); + assert!(m.contains(E(8))); + assert!(!m.contains(E(9))); + assert!(!m.contains(E(14))); + assert!(m.contains(E(15))); + assert!(!m.contains(E(16))); + assert!(!m.contains(E(19))); + assert!(!m.contains(E(20))); + assert!(!m.contains(E(u32::MAX))); + + m.clear(); + assert!(m.is_empty()); + } + + #[test] + fn pop_ordered() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = EntitySet::new(); + m.insert(r0); + m.insert(r1); + m.insert(r2); + + assert_eq!(r2, m.pop().unwrap()); + assert_eq!(r1, m.pop().unwrap()); + assert_eq!(r0, m.pop().unwrap()); + assert!(m.pop().is_none()); + assert!(m.pop().is_none()); + } + + #[test] + fn pop_unordered() { + let mut blocks = [ + E(0), + E(1), + E(6), + E(7), + E(5), + E(9), + E(10), + E(2), + E(3), + E(11), + E(12), + ]; + + let mut m = EntitySet::new(); + for &block in &blocks { + m.insert(block); + } + assert_eq!(m.bitset.max(), Some(12)); + blocks.sort(); + + for &block in blocks.iter().rev() { + assert_eq!(block, m.pop().unwrap()); + } + + assert!(m.is_empty()); + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/signed.rs b/deps/crates/vendor/cranelift-entity/src/signed.rs new file mode 100644 index 00000000000000..3c136d5901572c --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/signed.rs @@ -0,0 +1,40 @@ +/// Helper trait used to add `signed()` methods to primitive unsigned integer +/// types. +/// +/// The purpose of this trait is to signal the intent that the sign bit of an +/// unsigned integer is intended to be discarded and the value is instead +/// understood to be a "bag of bits" where the conversion to a signed number +/// is intended to be lossless bit-wise. This can be used for example when +/// converting an unsigned integer into a signed integer for constrained reasons +/// outside the scope of the code in question. +pub trait Signed { + /// The signed integer for this type which has the same width. + type Signed; + + /// View this unsigned integer as a signed integer of the same width. + /// + /// All bits are preserved. + fn signed(self) -> Self::Signed; +} + +macro_rules! impls { + ($($unsigned:ident => $signed:ident)*) => {$( + impl Signed for $unsigned { + type Signed = $signed; + + #[inline] + fn signed(self) -> $signed { + self as $signed + } + } + )*} +} + +impls! { + u8 => i8 + u16 => i16 + u32 => i32 + u64 => i64 + u128 => i128 + usize => isize +} diff --git a/deps/crates/vendor/cranelift-entity/src/sparse.rs b/deps/crates/vendor/cranelift-entity/src/sparse.rs new file mode 100644 index 00000000000000..0993e070ccde6a --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/sparse.rs @@ -0,0 +1,411 @@ +//! Sparse mapping of entity references to larger value types. +//! +//! This module provides a `SparseMap` data structure which implements a sparse mapping from an +//! `EntityRef` key to a value type that may be on the larger side. This implementation is based on +//! the paper: +//! +//! > Briggs, Torczon, *An efficient representation for sparse sets*, +//! > ACM Letters on Programming Languages and Systems, Volume 2, Issue 1-4, March-Dec. 1993. + +use crate::map::SecondaryMap; +use crate::EntityRef; +use alloc::vec::Vec; +use core::fmt; +use core::mem; +use core::slice; +use core::u32; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Trait for extracting keys from values stored in a `SparseMap`. +/// +/// All values stored in a `SparseMap` must keep track of their own key in the map and implement +/// this trait to provide access to the key. +pub trait SparseMapValue { + /// Get the key of this sparse map value. This key is not allowed to change while the value + /// is a member of the map. + fn key(&self) -> K; +} + +/// A sparse mapping of entity references. +/// +/// A `SparseMap` map provides: +/// +/// - Memory usage equivalent to `SecondaryMap` + `Vec`, so much smaller than +/// `SecondaryMap` for sparse mappings of larger `V` types. +/// - Constant time lookup, slightly slower than `SecondaryMap`. +/// - A very fast, constant time `clear()` operation. +/// - Fast insert and erase operations. +/// - Stable iteration that is as fast as a `Vec`. +/// +/// # Compared to `SecondaryMap` +/// +/// When should we use a `SparseMap` instead of a secondary `SecondaryMap`? First of all, +/// `SparseMap` does not provide the functionality of a `PrimaryMap` which can allocate and assign +/// entity references to objects as they are pushed onto the map. It is only the secondary entity +/// maps that can be replaced with a `SparseMap`. +/// +/// - A secondary entity map assigns a default mapping to all keys. It doesn't distinguish between +/// an unmapped key and one that maps to the default value. `SparseMap` does not require +/// `Default` values, and it tracks accurately if a key has been mapped or not. +/// - Iterating over the contents of an `SecondaryMap` is linear in the size of the *key space*, +/// while iterating over a `SparseMap` is linear in the number of elements in the mapping. This +/// is an advantage precisely when the mapping is sparse. +/// - `SparseMap::clear()` is constant time and super-fast. `SecondaryMap::clear()` is linear in +/// the size of the key space. (Or, rather the required `resize()` call following the `clear()` +/// is). +/// - `SparseMap` requires the values to implement `SparseMapValue` which means that they must +/// contain their own key. +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct SparseMap +where + K: EntityRef, + V: SparseMapValue, +{ + sparse: SecondaryMap, + dense: Vec, +} + +impl SparseMap +where + K: EntityRef, + V: SparseMapValue, +{ + /// Create a new empty mapping. + pub fn new() -> Self { + Self { + sparse: SecondaryMap::new(), + dense: Vec::new(), + } + } + + /// Returns the number of elements in the map. + pub fn len(&self) -> usize { + self.dense.len() + } + + /// Returns true is the map contains no elements. + pub fn is_empty(&self) -> bool { + self.dense.is_empty() + } + + /// Remove all elements from the mapping. + pub fn clear(&mut self) { + self.dense.clear(); + } + + /// Returns a reference to the value corresponding to the key. + pub fn get(&self, key: K) -> Option<&V> { + if let Some(idx) = self.sparse.get(key).cloned() { + if let Some(entry) = self.dense.get(idx as usize) { + if entry.key() == key { + return Some(entry); + } + } + } + None + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// Note that the returned value must not be mutated in a way that would change its key. This + /// would invalidate the sparse set data structure. + pub fn get_mut(&mut self, key: K) -> Option<&mut V> { + if let Some(idx) = self.sparse.get(key).cloned() { + if let Some(entry) = self.dense.get_mut(idx as usize) { + if entry.key() == key { + return Some(entry); + } + } + } + None + } + + /// Return the index into `dense` of the value corresponding to `key`. + fn index(&self, key: K) -> Option { + if let Some(idx) = self.sparse.get(key).cloned() { + let idx = idx as usize; + if let Some(entry) = self.dense.get(idx) { + if entry.key() == key { + return Some(idx); + } + } + } + None + } + + /// Return `true` if the map contains a value corresponding to `key`. + pub fn contains_key(&self, key: K) -> bool { + self.get(key).is_some() + } + + /// Insert a value into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old value is returned. + /// + /// It is not necessary to provide a key since the value knows its own key already. + pub fn insert(&mut self, value: V) -> Option { + let key = value.key(); + + // Replace the existing entry for `key` if there is one. + if let Some(entry) = self.get_mut(key) { + return Some(mem::replace(entry, value)); + } + + // There was no previous entry for `key`. Add it to the end of `dense`. + let idx = self.dense.len(); + debug_assert!(idx <= u32::MAX as usize, "SparseMap overflow"); + self.dense.push(value); + self.sparse[key] = idx as u32; + None + } + + /// Remove a value from the map and return it. + pub fn remove(&mut self, key: K) -> Option { + if let Some(idx) = self.index(key) { + let back = self.dense.pop().unwrap(); + + // Are we popping the back of `dense`? + if idx == self.dense.len() { + return Some(back); + } + + // We're removing an element from the middle of `dense`. + // Replace the element at `idx` with the back of `dense`. + // Repair `sparse` first. + self.sparse[back.key()] = idx as u32; + return Some(mem::replace(&mut self.dense[idx], back)); + } + + // Nothing to remove. + None + } + + /// Remove the last value from the map. + pub fn pop(&mut self) -> Option { + self.dense.pop() + } + + /// Get an iterator over the values in the map. + /// + /// The iteration order is entirely determined by the preceding sequence of `insert` and + /// `remove` operations. In particular, if no elements were removed, this is the insertion + /// order. + pub fn values(&self) -> slice::Iter { + self.dense.iter() + } + + /// Get the values as a slice. + pub fn as_slice(&self) -> &[V] { + self.dense.as_slice() + } +} + +impl Default for SparseMap +where + K: EntityRef, + V: SparseMapValue, +{ + fn default() -> SparseMap { + SparseMap::new() + } +} + +impl fmt::Debug for SparseMap +where + K: EntityRef + fmt::Debug, + V: SparseMapValue + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map() + .entries(self.values().map(|v| (v.key(), v))) + .finish() + } +} + +/// Iterating over the elements of a set. +impl<'a, K, V> IntoIterator for &'a SparseMap +where + K: EntityRef, + V: SparseMapValue, +{ + type Item = &'a V; + type IntoIter = slice::Iter<'a, V>; + + fn into_iter(self) -> Self::IntoIter { + self.values() + } +} + +/// Any `EntityRef` can be used as a sparse map value representing itself. +impl SparseMapValue for T +where + T: EntityRef, +{ + fn key(&self) -> Self { + *self + } +} + +/// A sparse set of entity references. +/// +/// Any type that implements `EntityRef` can be used as a sparse set value too. +pub type SparseSet = SparseMap; + +#[cfg(test)] +mod tests { + use alloc::format; + + use super::*; + + /// An opaque reference to an instruction in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Inst(u32); + entity_impl!(Inst, "inst"); + + // Mock key-value object for testing. + #[derive(PartialEq, Eq, Debug)] + struct Obj(Inst, &'static str); + + impl SparseMapValue for Obj { + fn key(&self) -> Inst { + self.0 + } + } + + #[test] + fn empty_immutable_map() { + let i1 = Inst::new(1); + let map: SparseMap = SparseMap::new(); + + assert!(map.is_empty()); + assert_eq!(map.len(), 0); + assert_eq!(map.get(i1), None); + assert_eq!(map.values().count(), 0); + } + + #[test] + fn single_entry() { + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let mut map = SparseMap::new(); + + assert!(map.is_empty()); + assert_eq!(map.len(), 0); + assert_eq!(map.get(i1), None); + assert_eq!(map.get_mut(i1), None); + assert_eq!(map.remove(i1), None); + + assert_eq!(map.insert(Obj(i1, "hi")), None); + assert!(!map.is_empty()); + assert_eq!(map.len(), 1); + assert_eq!(map.get(i0), None); + assert_eq!(map.get(i1), Some(&Obj(i1, "hi"))); + assert_eq!(map.get(i2), None); + assert_eq!(map.get_mut(i0), None); + assert_eq!(map.get_mut(i1), Some(&mut Obj(i1, "hi"))); + assert_eq!(map.get_mut(i2), None); + + assert_eq!(map.remove(i0), None); + assert_eq!(map.remove(i2), None); + assert_eq!(map.remove(i1), Some(Obj(i1, "hi"))); + assert_eq!(map.len(), 0); + assert_eq!(map.get(i1), None); + assert_eq!(map.get_mut(i1), None); + assert_eq!(map.remove(i0), None); + assert_eq!(map.remove(i1), None); + assert_eq!(map.remove(i2), None); + } + + #[test] + fn multiple_entries() { + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let mut map = SparseMap::new(); + + assert_eq!(map.insert(Obj(i2, "foo")), None); + assert_eq!(map.insert(Obj(i1, "bar")), None); + assert_eq!(map.insert(Obj(i0, "baz")), None); + + // Iteration order = insertion order when nothing has been removed yet. + assert_eq!( + map.values().map(|obj| obj.1).collect::>(), + ["foo", "bar", "baz"] + ); + + assert_eq!(map.len(), 3); + assert_eq!(map.get(i0), Some(&Obj(i0, "baz"))); + assert_eq!(map.get(i1), Some(&Obj(i1, "bar"))); + assert_eq!(map.get(i2), Some(&Obj(i2, "foo"))); + assert_eq!(map.get(i3), None); + + // Remove front object, causing back to be swapped down. + assert_eq!(map.remove(i1), Some(Obj(i1, "bar"))); + assert_eq!(map.len(), 2); + assert_eq!(map.get(i0), Some(&Obj(i0, "baz"))); + assert_eq!(map.get(i1), None); + assert_eq!(map.get(i2), Some(&Obj(i2, "foo"))); + assert_eq!(map.get(i3), None); + + // Reinsert something at a previously used key. + assert_eq!(map.insert(Obj(i1, "barbar")), None); + assert_eq!(map.len(), 3); + assert_eq!(map.get(i0), Some(&Obj(i0, "baz"))); + assert_eq!(map.get(i1), Some(&Obj(i1, "barbar"))); + assert_eq!(map.get(i2), Some(&Obj(i2, "foo"))); + assert_eq!(map.get(i3), None); + + // Replace an entry. + assert_eq!(map.insert(Obj(i0, "bazbaz")), Some(Obj(i0, "baz"))); + assert_eq!(map.len(), 3); + assert_eq!(map.get(i0), Some(&Obj(i0, "bazbaz"))); + assert_eq!(map.get(i1), Some(&Obj(i1, "barbar"))); + assert_eq!(map.get(i2), Some(&Obj(i2, "foo"))); + assert_eq!(map.get(i3), None); + + // Check the reference `IntoIter` impl. + let mut v = Vec::new(); + for i in &map { + v.push(i.1); + } + assert_eq!(v.len(), map.len()); + } + + #[test] + fn entity_set() { + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let mut set = SparseSet::new(); + + assert_eq!(set.insert(i0), None); + assert_eq!(set.insert(i0), Some(i0)); + assert_eq!(set.insert(i1), None); + assert_eq!(set.get(i0), Some(&i0)); + assert_eq!(set.get(i1), Some(&i1)); + } + + #[test] + fn default_impl() { + let map: SparseMap = SparseMap::default(); + + assert!(map.is_empty()); + assert_eq!(map.len(), 0); + } + + #[test] + fn debug_impl() { + let i1 = Inst::new(1); + let mut map = SparseMap::new(); + assert_eq!(map.insert(Obj(i1, "hi")), None); + + let debug = format!("{map:?}"); + let expected = "{inst1: Obj(inst1, \"hi\")}"; + assert_eq!(debug, expected); + } +} diff --git a/deps/crates/vendor/cranelift-entity/src/unsigned.rs b/deps/crates/vendor/cranelift-entity/src/unsigned.rs new file mode 100644 index 00000000000000..2d8eb4c640ca2f --- /dev/null +++ b/deps/crates/vendor/cranelift-entity/src/unsigned.rs @@ -0,0 +1,71 @@ +/// Helper trait used to add `unsigned()` methods to primitive signed integer +/// types. +/// +/// The purpose of this trait is to signal the intent that the sign bit of a +/// signed integer is intended to be discarded and the value is instead +/// understood to be a "bag of bits" where the conversion to an unsigned number +/// is intended to be lossless. This can be used for example when converting a +/// signed integer into a larger width with zero-extension. +pub trait Unsigned { + /// The unsigned integer for this type which has the same width. + type Unsigned; + + /// View this signed integer as an unsigned integer of the same width. + /// + /// All bits are preserved. + fn unsigned(self) -> Self::Unsigned; +} + +impl Unsigned for i8 { + type Unsigned = u8; + + #[inline] + fn unsigned(self) -> u8 { + self as u8 + } +} + +impl Unsigned for i16 { + type Unsigned = u16; + + #[inline] + fn unsigned(self) -> u16 { + self as u16 + } +} + +impl Unsigned for i32 { + type Unsigned = u32; + + #[inline] + fn unsigned(self) -> u32 { + self as u32 + } +} + +impl Unsigned for i64 { + type Unsigned = u64; + + #[inline] + fn unsigned(self) -> u64 { + self as u64 + } +} + +impl Unsigned for i128 { + type Unsigned = u128; + + #[inline] + fn unsigned(self) -> u128 { + self as u128 + } +} + +impl Unsigned for isize { + type Unsigned = usize; + + #[inline] + fn unsigned(self) -> usize { + self as usize + } +} diff --git a/deps/crates/vendor/cranelift-frontend/.cargo-checksum.json b/deps/crates/vendor/cranelift-frontend/.cargo-checksum.json new file mode 100644 index 00000000000000..3edf7cfc64bc0c --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"5c118911bcd8c9a697d0052002ba7021e4ec98410bdb40c432a1d146f5b1ccfc","Cargo.lock":"fd3eab5bcfeee5b84c09de5b931716e31093c512236793c4d78a022d3bc003f7","Cargo.toml":"5bd1030c81678ef5ff4fa7c9e8c45bbc84574c850be45ffd3a555cb3d3ecb77d","Cargo.toml.orig":"9fe2f484a29a3747b6f95f0d81c668b985a1f7ed264a4f3e87bdb425a03c9fee","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"5108af8aed6c659d63b16438c43e5250e8a1c3893012d559fe3cdbecc756aefa","src/frontend/safepoints.rs":"3cd5ac872f45a2dccede7472db11bd00d39eb99a54aaaac05fe5b850ed046e76","src/lib.rs":"8a8537b6545087c64153360c567374fe627f6ea91c6e2a0b1850212fdef29448","src/ssa.rs":"a8a5d375528b46d4653825e5d6da10251a5ef6b999e6ea0b8b235cd19616478d","src/switch.rs":"dd17717bc774c2fd2e36ae960f468c1823bab29e30960cbef4f5b761d83908cd","src/variable.rs":"7df3cf5d1ace2220e909f6c7045f0018b433b5cb13d4e85e2b2bd5948a066e0c"},"package":"4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-frontend/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-frontend/.cargo_vcs_info.json new file mode 100644 index 00000000000000..3e62e91d239956 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/frontend" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-frontend/Cargo.lock b/deps/crates/vendor/cranelift-frontend/Cargo.lock new file mode 100644 index 00000000000000..a48a133cebf7ef --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/Cargo.lock @@ -0,0 +1,544 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "cranelift-bforest" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" + +[[package]] +name = "cranelift-codegen" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" + +[[package]] +name = "cranelift-control" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +dependencies = [ + "cranelift-bitset", +] + +[[package]] +name = "cranelift-frontend" +version = "0.116.1" +dependencies = [ + "cranelift-codegen", + "env_logger", + "hashbrown 0.14.3", + "log", + "similar", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regalloc2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "similar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/deps/crates/vendor/cranelift-frontend/Cargo.toml b/deps/crates/vendor/cranelift-frontend/Cargo.toml new file mode 100644 index 00000000000000..6af69c01b87f15 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/Cargo.toml @@ -0,0 +1,111 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-frontend" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Cranelift IR builder helper" +documentation = "https://docs.rs/cranelift-frontend" +readme = "README.md" +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" + +[lib] +name = "cranelift_frontend" +path = "src/lib.rs" + +[dependencies.cranelift-codegen] +version = "0.116.1" +features = [ + "std", + "unwind", +] +default-features = false + +[dependencies.hashbrown] +version = "0.14" +optional = true +default-features = false + +[dependencies.log] +version = "0.4.8" +default-features = false + +[dependencies.smallvec] +version = "1.6.1" +features = ["union"] + +[dependencies.target-lexicon] +version = "0.13.0" + +[dev-dependencies.cranelift-codegen] +version = "0.116.1" +features = [ + "std", + "unwind", + "x86", +] +default-features = false + +[dev-dependencies.env_logger] +version = "0.11.5" + +[dev-dependencies.similar] +version = "2.1.0" + +[features] +core = [ + "hashbrown", + "cranelift-codegen/core", +] +default = ["std"] +std = ["cranelift-codegen/std"] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-frontend/Cargo.toml.orig b/deps/crates/vendor/cranelift-frontend/Cargo.toml.orig new file mode 100644 index 00000000000000..ebf29a2d11007a --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/Cargo.toml.orig @@ -0,0 +1,32 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-frontend" +version = "0.116.1" +description = "Cranelift IR builder helper" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://docs.rs/cranelift-frontend" +categories = ["no-std"] +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +cranelift-codegen = { workspace = true } +target-lexicon = { workspace = true } +log = { workspace = true } +hashbrown = { workspace = true, optional = true } +smallvec = { workspace = true } + +[dev-dependencies] +env_logger = { workspace = true } +similar = { workspace = true } +cranelift-codegen = { workspace = true, features = ['x86'] } + +[features] +default = ["std"] +std = ["cranelift-codegen/std"] +core = ["hashbrown", "cranelift-codegen/core"] diff --git a/deps/crates/vendor/cranelift-frontend/LICENSE b/deps/crates/vendor/cranelift-frontend/LICENSE new file mode 100644 index 00000000000000..f9d81955f4bcb8 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/deps/crates/vendor/cranelift-frontend/README.md b/deps/crates/vendor/cranelift-frontend/README.md new file mode 100644 index 00000000000000..e43ad48f456208 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/README.md @@ -0,0 +1,5 @@ +This crate provides a straightforward way to create a +[Cranelift](https://crates.io/crates/cranelift) IR function and fill it with +instructions translated from another language. It contains an SSA construction +module that provides convenient methods for translating non-SSA variables into +SSA Cranelift IR values via `use_var` and `def_var` calls. diff --git a/deps/crates/vendor/cranelift-frontend/src/frontend.rs b/deps/crates/vendor/cranelift-frontend/src/frontend.rs new file mode 100644 index 00000000000000..125be6a773b798 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/frontend.rs @@ -0,0 +1,1963 @@ +//! A frontend for building Cranelift IR from other languages. +use crate::ssa::{SSABuilder, SideEffects}; +use crate::variable::Variable; +use alloc::vec::Vec; +use core::fmt::{self, Debug}; +use cranelift_codegen::cursor::{Cursor, CursorPosition, FuncCursor}; +use cranelift_codegen::entity::{EntityRef, EntitySet, SecondaryMap}; +use cranelift_codegen::ir; +use cranelift_codegen::ir::condcodes::IntCC; +use cranelift_codegen::ir::{ + types, AbiParam, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, ExtFuncData, + ExternalName, FuncRef, Function, GlobalValue, GlobalValueData, Inst, InstBuilder, + InstBuilderBase, InstructionData, JumpTable, JumpTableData, LibCall, MemFlags, RelSourceLoc, + SigRef, Signature, StackSlot, StackSlotData, Type, Value, ValueLabel, ValueLabelAssignments, + ValueLabelStart, +}; +use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_codegen::packed_option::PackedOption; +use cranelift_codegen::traversals::Dfs; +use smallvec::SmallVec; + +mod safepoints; + +/// Structure used for translating a series of functions into Cranelift IR. +/// +/// In order to reduce memory reallocations when compiling multiple functions, +/// [`FunctionBuilderContext`] holds various data structures which are cleared between +/// functions, rather than dropped, preserving the underlying allocations. +#[derive(Default)] +pub struct FunctionBuilderContext { + ssa: SSABuilder, + status: SecondaryMap, + types: SecondaryMap, + stack_map_vars: EntitySet, + stack_map_values: EntitySet, + safepoints: safepoints::SafepointSpiller, +} + +/// Temporary object used to build a single Cranelift IR [`Function`]. +pub struct FunctionBuilder<'a> { + /// The function currently being built. + /// This field is public so the function can be re-borrowed. + pub func: &'a mut Function, + + /// Source location to assign to all new instructions. + srcloc: ir::SourceLoc, + + func_ctx: &'a mut FunctionBuilderContext, + position: PackedOption, +} + +#[derive(Clone, Default, Eq, PartialEq)] +enum BlockStatus { + /// No instructions have been added. + #[default] + Empty, + /// Some instructions have been added, but no terminator. + Partial, + /// A terminator has been added; no further instructions may be added. + Filled, +} + +impl FunctionBuilderContext { + /// Creates a [`FunctionBuilderContext`] structure. The structure is automatically cleared after + /// each [`FunctionBuilder`] completes translating a function. + pub fn new() -> Self { + Self::default() + } + + fn clear(&mut self) { + let FunctionBuilderContext { + ssa, + status, + types, + stack_map_vars, + stack_map_values, + safepoints, + } = self; + ssa.clear(); + status.clear(); + types.clear(); + stack_map_values.clear(); + stack_map_vars.clear(); + safepoints.clear(); + } + + fn is_empty(&self) -> bool { + self.ssa.is_empty() && self.status.is_empty() && self.types.is_empty() + } +} + +/// Implementation of the [`InstBuilder`] that has +/// one convenience method per Cranelift IR instruction. +pub struct FuncInstBuilder<'short, 'long: 'short> { + builder: &'short mut FunctionBuilder<'long>, + block: Block, +} + +impl<'short, 'long> FuncInstBuilder<'short, 'long> { + fn new(builder: &'short mut FunctionBuilder<'long>, block: Block) -> Self { + Self { builder, block } + } +} + +impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { + fn data_flow_graph(&self) -> &DataFlowGraph { + &self.builder.func.dfg + } + + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { + &mut self.builder.func.dfg + } + + // This implementation is richer than `InsertBuilder` because we use the data of the + // instruction being inserted to add related info to the DFG and the SSA building system, + // and perform debug sanity checks. + fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'short mut DataFlowGraph) { + // We only insert the Block in the layout when an instruction is added to it + self.builder.ensure_inserted_block(); + + let inst = self.builder.func.dfg.make_inst(data); + self.builder.func.dfg.make_inst_results(inst, ctrl_typevar); + self.builder.func.layout.append_inst(inst, self.block); + if !self.builder.srcloc.is_default() { + self.builder.func.set_srcloc(inst, self.builder.srcloc); + } + + match &self.builder.func.dfg.insts[inst] { + ir::InstructionData::Jump { + destination: dest, .. + } => { + // If the user has supplied jump arguments we must adapt the arguments of + // the destination block + let block = dest.block(&self.builder.func.dfg.value_lists); + self.builder.declare_successor(block, inst); + } + + ir::InstructionData::Brif { + blocks: [branch_then, branch_else], + .. + } => { + let block_then = branch_then.block(&self.builder.func.dfg.value_lists); + let block_else = branch_else.block(&self.builder.func.dfg.value_lists); + + self.builder.declare_successor(block_then, inst); + if block_then != block_else { + self.builder.declare_successor(block_else, inst); + } + } + + ir::InstructionData::BranchTable { table, .. } => { + let pool = &self.builder.func.dfg.value_lists; + + // Unlike all other jumps/branches, jump tables are + // capable of having the same successor appear + // multiple times, so we must deduplicate. + let mut unique = EntitySet::::new(); + for dest_block in self + .builder + .func + .stencil + .dfg + .jump_tables + .get(*table) + .expect("you are referencing an undeclared jump table") + .all_branches() + { + let block = dest_block.block(pool); + if !unique.insert(block) { + continue; + } + + // Call `declare_block_predecessor` instead of `declare_successor` for + // avoiding the borrow checker. + self.builder + .func_ctx + .ssa + .declare_block_predecessor(block, inst); + } + } + + inst => debug_assert!(!inst.opcode().is_branch()), + } + + if data.opcode().is_terminator() { + self.builder.fill_current_block() + } + (inst, &mut self.builder.func.dfg) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +/// An error encountered when calling [`FunctionBuilder::try_use_var`]. +pub enum UseVariableError { + UsedBeforeDeclared(Variable), +} + +impl fmt::Display for UseVariableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UseVariableError::UsedBeforeDeclared(variable) => { + write!( + f, + "variable {} was used before it was defined", + variable.index() + )?; + } + } + Ok(()) + } +} + +impl std::error::Error for UseVariableError {} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +/// An error encountered when calling [`FunctionBuilder::try_declare_var`]. +pub enum DeclareVariableError { + DeclaredMultipleTimes(Variable), +} + +impl std::error::Error for DeclareVariableError {} + +impl fmt::Display for DeclareVariableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DeclareVariableError::DeclaredMultipleTimes(variable) => { + write!( + f, + "variable {} was declared multiple times", + variable.index() + )?; + } + } + Ok(()) + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +/// An error encountered when defining the initial value of a variable. +pub enum DefVariableError { + /// The variable was instantiated with a value of the wrong type. + /// + /// note: to obtain the type of the value, you can call + /// [`cranelift_codegen::ir::dfg::DataFlowGraph::value_type`] (using the + /// `FunctionBuilder.func.dfg` field) + TypeMismatch(Variable, Value), + /// The value was defined (in a call to [`FunctionBuilder::def_var`]) before + /// it was declared (in a call to [`FunctionBuilder::declare_var`]). + DefinedBeforeDeclared(Variable), +} + +impl fmt::Display for DefVariableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DefVariableError::TypeMismatch(variable, value) => { + write!( + f, + "the types of variable {} and value {} are not the same. + The `Value` supplied to `def_var` must be of the same type as + the variable was declared to be of in `declare_var`.", + variable.index(), + value.as_u32() + )?; + } + DefVariableError::DefinedBeforeDeclared(variable) => { + write!( + f, + "the value of variable {} was declared before it was defined", + variable.index() + )?; + } + } + Ok(()) + } +} + +/// This module allows you to create a function in Cranelift IR in a straightforward way, hiding +/// all the complexity of its internal representation. +/// +/// The module is parametrized by one type which is the representation of variables in your +/// origin language. It offers a way to conveniently append instruction to your program flow. +/// You are responsible to split your instruction flow into extended blocks (declared with +/// [`create_block`](Self::create_block)) whose properties are: +/// +/// - branch and jump instructions can only point at the top of extended blocks; +/// - the last instruction of each block is a terminator instruction which has no natural successor, +/// and those instructions can only appear at the end of extended blocks. +/// +/// The parameters of Cranelift IR instructions are Cranelift IR values, which can only be created +/// as results of other Cranelift IR instructions. To be able to create variables redefined multiple +/// times in your program, use the [`def_var`](Self::def_var) and [`use_var`](Self::use_var) command, +/// that will maintain the correspondence between your variables and Cranelift IR SSA values. +/// +/// The first block for which you call [`switch_to_block`](Self::switch_to_block) will be assumed to +/// be the beginning of the function. +/// +/// At creation, a [`FunctionBuilder`] instance borrows an already allocated `Function` which it +/// modifies with the information stored in the mutable borrowed +/// [`FunctionBuilderContext`]. The function passed in argument should be newly created with +/// [`Function::with_name_signature()`], whereas the [`FunctionBuilderContext`] can be kept as is +/// between two function translations. +/// +/// # Errors +/// +/// The functions below will panic in debug mode whenever you try to modify the Cranelift IR +/// function in a way that violate the coherence of the code. For instance: switching to a new +/// [`Block`] when you haven't filled the current one with a terminator instruction, inserting a +/// return instruction with arguments that don't match the function's signature. +impl<'a> FunctionBuilder<'a> { + /// Creates a new [`FunctionBuilder`] structure that will operate on a [`Function`] using a + /// [`FunctionBuilderContext`]. + pub fn new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self { + debug_assert!(func_ctx.is_empty()); + Self { + func, + srcloc: Default::default(), + func_ctx, + position: Default::default(), + } + } + + /// Get the block that this builder is currently at. + pub fn current_block(&self) -> Option { + self.position.expand() + } + + /// Set the source location that should be assigned to all new instructions. + pub fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { + self.srcloc = srcloc; + } + + /// Creates a new [`Block`] and returns its reference. + pub fn create_block(&mut self) -> Block { + let block = self.func.dfg.make_block(); + self.func_ctx.ssa.declare_block(block); + block + } + + /// Mark a block as "cold". + /// + /// This will try to move it out of the ordinary path of execution + /// when lowered to machine code. + pub fn set_cold_block(&mut self, block: Block) { + self.func.layout.set_cold(block); + } + + /// Insert `block` in the layout *after* the existing block `after`. + pub fn insert_block_after(&mut self, block: Block, after: Block) { + self.func.layout.insert_block_after(block, after); + } + + /// After the call to this function, new instructions will be inserted into the designated + /// block, in the order they are declared. You must declare the types of the [`Block`] arguments + /// you will use here. + /// + /// When inserting the terminator instruction (which doesn't have a fallthrough to its immediate + /// successor), the block will be declared filled and it will not be possible to append + /// instructions to it. + pub fn switch_to_block(&mut self, block: Block) { + // First we check that the previous block has been filled. + debug_assert!( + self.position.is_none() + || self.is_unreachable() + || self.is_pristine(self.position.unwrap()) + || self.is_filled(self.position.unwrap()), + "you have to fill your block before switching" + ); + // We cannot switch to a filled block + debug_assert!( + !self.is_filled(block), + "you cannot switch to a block which is already filled" + ); + + // Then we change the cursor position. + self.position = PackedOption::from(block); + } + + /// Declares that all the predecessors of this block are known. + /// + /// Function to call with `block` as soon as the last branch instruction to `block` has been + /// created. Forgetting to call this method on every block will cause inconsistencies in the + /// produced functions. + pub fn seal_block(&mut self, block: Block) { + let side_effects = self.func_ctx.ssa.seal_block(block, self.func); + self.handle_ssa_side_effects(side_effects); + } + + /// Effectively calls [seal_block](Self::seal_block) on all unsealed blocks in the function. + /// + /// It's more efficient to seal [`Block`]s as soon as possible, during + /// translation, but for frontends where this is impractical to do, this + /// function can be used at the end of translating all blocks to ensure + /// that everything is sealed. + pub fn seal_all_blocks(&mut self) { + let side_effects = self.func_ctx.ssa.seal_all_blocks(self.func); + self.handle_ssa_side_effects(side_effects); + } + + /// Declares the type of a variable. + /// + /// This allows the variable to be used later (by calling + /// [`FunctionBuilder::use_var`]). + /// + /// # Errors + /// + /// This function will return an error if the variable has been previously + /// declared. + pub fn try_declare_var(&mut self, var: Variable, ty: Type) -> Result<(), DeclareVariableError> { + if self.func_ctx.types[var] != types::INVALID { + return Err(DeclareVariableError::DeclaredMultipleTimes(var)); + } + self.func_ctx.types[var] = ty; + Ok(()) + } + + /// Declares the type of a variable, panicking if it is already declared. + /// + /// # Panics + /// + /// Panics if the variable has already been declared. + pub fn declare_var(&mut self, var: Variable, ty: Type) { + self.try_declare_var(var, ty) + .unwrap_or_else(|_| panic!("the variable {var:?} has been declared multiple times")) + } + + /// Declare that all uses of the given variable must be included in stack + /// map metadata. + /// + /// All values that are uses of this variable will be spilled to the stack + /// before each safepoint and their location on the stack included in stack + /// maps. Stack maps allow the garbage collector to identify the on-stack GC + /// roots. + /// + /// This does not affect any pre-existing uses of the variable. + /// + /// # Panics + /// + /// Panics if the variable's type is larger than 16 bytes or if this + /// variable has not been declared yet. + pub fn declare_var_needs_stack_map(&mut self, var: Variable) { + log::trace!("declare_var_needs_stack_map({var:?})"); + let ty = self.func_ctx.types[var]; + assert!(ty != types::INVALID); + assert!(ty.bytes() <= 16); + self.func_ctx.stack_map_vars.insert(var); + } + + /// Returns the Cranelift IR necessary to use a previously defined user + /// variable, returning an error if this is not possible. + pub fn try_use_var(&mut self, var: Variable) -> Result { + // Assert that we're about to add instructions to this block using the definition of the + // given variable. ssa.use_var is the only part of this crate which can add block parameters + // behind the caller's back. If we disallow calling append_block_param as soon as use_var is + // called, then we enforce a strict separation between user parameters and SSA parameters. + self.ensure_inserted_block(); + + let (val, side_effects) = { + let ty = *self + .func_ctx + .types + .get(var) + .ok_or(UseVariableError::UsedBeforeDeclared(var))?; + debug_assert_ne!( + ty, + types::INVALID, + "variable {var:?} is used but its type has not been declared" + ); + self.func_ctx + .ssa + .use_var(self.func, var, ty, self.position.unwrap()) + }; + self.handle_ssa_side_effects(side_effects); + + // If the variable was declared as needing stack maps, then propagate + // that requirement to all values derived from using the variable. + if self.func_ctx.stack_map_vars.contains(var) { + self.declare_value_needs_stack_map(val); + } + + Ok(val) + } + + /// Returns the Cranelift IR value corresponding to the utilization at the current program + /// position of a previously defined user variable. + pub fn use_var(&mut self, var: Variable) -> Value { + self.try_use_var(var).unwrap_or_else(|_| { + panic!("variable {var:?} is used but its type has not been declared") + }) + } + + /// Registers a new definition of a user variable. This function will return + /// an error if the value supplied does not match the type the variable was + /// declared to have. + pub fn try_def_var(&mut self, var: Variable, val: Value) -> Result<(), DefVariableError> { + let var_ty = *self + .func_ctx + .types + .get(var) + .ok_or(DefVariableError::DefinedBeforeDeclared(var))?; + if var_ty != self.func.dfg.value_type(val) { + return Err(DefVariableError::TypeMismatch(var, val)); + } + + // If `var` needs inclusion in stack maps, then `val` does too. + if self.func_ctx.stack_map_vars.contains(var) { + self.declare_value_needs_stack_map(val); + } + + self.func_ctx.ssa.def_var(var, val, self.position.unwrap()); + Ok(()) + } + + /// Register a new definition of a user variable. The type of the value must be + /// the same as the type registered for the variable. + pub fn def_var(&mut self, var: Variable, val: Value) { + self.try_def_var(var, val) + .unwrap_or_else(|error| match error { + DefVariableError::TypeMismatch(var, val) => { + panic!("declared type of variable {var:?} doesn't match type of value {val}"); + } + DefVariableError::DefinedBeforeDeclared(var) => { + panic!("variable {var:?} is used but its type has not been declared"); + } + }) + } + + /// Set label for [`Value`] + /// + /// This will not do anything unless + /// [`func.dfg.collect_debug_info`](DataFlowGraph::collect_debug_info) is called first. + pub fn set_val_label(&mut self, val: Value, label: ValueLabel) { + if let Some(values_labels) = self.func.stencil.dfg.values_labels.as_mut() { + use alloc::collections::btree_map::Entry; + + let start = ValueLabelStart { + from: RelSourceLoc::from_base_offset(self.func.params.base_srcloc(), self.srcloc), + label, + }; + + match values_labels.entry(val) { + Entry::Occupied(mut e) => match e.get_mut() { + ValueLabelAssignments::Starts(starts) => starts.push(start), + _ => panic!("Unexpected ValueLabelAssignments at this stage"), + }, + Entry::Vacant(e) => { + e.insert(ValueLabelAssignments::Starts(vec![start])); + } + } + } + } + + /// Declare that the given value is a GC reference that requires inclusion + /// in a stack map when it is live across GC safepoints. + /// + /// At the current moment, values that need inclusion in stack maps are + /// spilled before safepoints, but they are not reloaded afterwards. This + /// means that moving GCs are not yet supported, however the intention is to + /// add this support in the near future. + /// + /// # Panics + /// + /// Panics if `val` is larger than 16 bytes. + pub fn declare_value_needs_stack_map(&mut self, val: Value) { + log::trace!("declare_value_needs_stack_map({val:?})"); + + // We rely on these properties in `insert_safepoint_spills`. + let size = self.func.dfg.value_type(val).bytes(); + assert!(size <= 16); + assert!(size.is_power_of_two()); + + self.func_ctx.stack_map_values.insert(val); + } + + /// Creates a jump table in the function, to be used by [`br_table`](InstBuilder::br_table) instructions. + pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { + self.func.create_jump_table(data) + } + + /// Creates a sized stack slot in the function, to be used by [`stack_load`](InstBuilder::stack_load), + /// [`stack_store`](InstBuilder::stack_store) and [`stack_addr`](InstBuilder::stack_addr) instructions. + pub fn create_sized_stack_slot(&mut self, data: StackSlotData) -> StackSlot { + self.func.create_sized_stack_slot(data) + } + + /// Creates a dynamic stack slot in the function, to be used by + /// [`dynamic_stack_load`](InstBuilder::dynamic_stack_load), + /// [`dynamic_stack_store`](InstBuilder::dynamic_stack_store) and + /// [`dynamic_stack_addr`](InstBuilder::dynamic_stack_addr) instructions. + pub fn create_dynamic_stack_slot(&mut self, data: DynamicStackSlotData) -> DynamicStackSlot { + self.func.create_dynamic_stack_slot(data) + } + + /// Adds a signature which can later be used to declare an external function import. + pub fn import_signature(&mut self, signature: Signature) -> SigRef { + self.func.import_signature(signature) + } + + /// Declare an external function import. + pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { + self.func.import_function(data) + } + + /// Declares a global value accessible to the function. + pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { + self.func.create_global_value(data) + } + + /// Returns an object with the [`InstBuilder`] + /// trait that allows to conveniently append an instruction to the current [`Block`] being built. + pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> { + let block = self + .position + .expect("Please call switch_to_block before inserting instructions"); + FuncInstBuilder::new(self, block) + } + + /// Make sure that the current block is inserted in the layout. + pub fn ensure_inserted_block(&mut self) { + let block = self.position.unwrap(); + if self.is_pristine(block) { + if !self.func.layout.is_block_inserted(block) { + self.func.layout.append_block(block); + } + self.func_ctx.status[block] = BlockStatus::Partial; + } else { + debug_assert!( + !self.is_filled(block), + "you cannot add an instruction to a block already filled" + ); + } + } + + /// Returns a [`FuncCursor`] pointed at the current position ready for inserting instructions. + /// + /// This can be used to insert SSA code that doesn't need to access locals and that doesn't + /// need to know about [`FunctionBuilder`] at all. + pub fn cursor(&mut self) -> FuncCursor { + self.ensure_inserted_block(); + FuncCursor::new(self.func) + .with_srcloc(self.srcloc) + .at_bottom(self.position.unwrap()) + } + + /// Append parameters to the given [`Block`] corresponding to the function + /// parameters. This can be used to set up the block parameters for the + /// entry block. + pub fn append_block_params_for_function_params(&mut self, block: Block) { + debug_assert!( + !self.func_ctx.ssa.has_any_predecessors(block), + "block parameters for function parameters should only be added to the entry block" + ); + + // These parameters count as "user" parameters here because they aren't + // inserted by the SSABuilder. + debug_assert!( + self.is_pristine(block), + "You can't add block parameters after adding any instruction" + ); + + for argtyp in &self.func.stencil.signature.params { + self.func + .stencil + .dfg + .append_block_param(block, argtyp.value_type); + } + } + + /// Append parameters to the given [`Block`] corresponding to the function + /// return values. This can be used to set up the block parameters for a + /// function exit block. + pub fn append_block_params_for_function_returns(&mut self, block: Block) { + // These parameters count as "user" parameters here because they aren't + // inserted by the SSABuilder. + debug_assert!( + self.is_pristine(block), + "You can't add block parameters after adding any instruction" + ); + + for argtyp in &self.func.stencil.signature.returns { + self.func + .stencil + .dfg + .append_block_param(block, argtyp.value_type); + } + } + + /// Declare that translation of the current function is complete. + /// + /// This resets the state of the [`FunctionBuilderContext`] in preparation to + /// be used for another function. + pub fn finalize(mut self) { + // Check that all the `Block`s are filled and sealed. + #[cfg(debug_assertions)] + { + for block in self.func_ctx.status.keys() { + if !self.is_pristine(block) { + assert!( + self.func_ctx.ssa.is_sealed(block), + "FunctionBuilder finalized, but block {block} is not sealed", + ); + assert!( + self.is_filled(block), + "FunctionBuilder finalized, but block {block} is not filled", + ); + } + } + } + + // In debug mode, check that all blocks are valid basic blocks. + #[cfg(debug_assertions)] + { + // Iterate manually to provide more helpful error messages. + for block in self.func_ctx.status.keys() { + if let Err((inst, msg)) = self.func.is_block_basic(block) { + let inst_str = self.func.dfg.display_inst(inst); + panic!("{block} failed basic block invariants on {inst_str}: {msg}"); + } + } + } + + if !self.func_ctx.stack_map_values.is_empty() { + self.func_ctx + .safepoints + .run(&mut self.func, &self.func_ctx.stack_map_values); + } + + // Clear the state (but preserve the allocated buffers) in preparation + // for translation another function. + self.func_ctx.clear(); + } +} + +/// All the functions documented in the previous block are write-only and help you build a valid +/// Cranelift IR functions via multiple debug asserts. However, you might need to improve the +/// performance of your translation perform more complex transformations to your Cranelift IR +/// function. The functions below help you inspect the function you're creating and modify it +/// in ways that can be unsafe if used incorrectly. +impl<'a> FunctionBuilder<'a> { + /// Retrieves all the parameters for a [`Block`] currently inferred from the jump instructions + /// inserted that target it and the SSA construction. + pub fn block_params(&self, block: Block) -> &[Value] { + self.func.dfg.block_params(block) + } + + /// Retrieves the signature with reference `sigref` previously added with + /// [`import_signature`](Self::import_signature). + pub fn signature(&self, sigref: SigRef) -> Option<&Signature> { + self.func.dfg.signatures.get(sigref) + } + + /// Creates a parameter for a specific [`Block`] by appending it to the list of already existing + /// parameters. + /// + /// **Note:** this function has to be called at the creation of the `Block` before adding + /// instructions to it, otherwise this could interfere with SSA construction. + pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value { + debug_assert!( + self.is_pristine(block), + "You can't add block parameters after adding any instruction" + ); + self.func.dfg.append_block_param(block, ty) + } + + /// Returns the result values of an instruction. + pub fn inst_results(&self, inst: Inst) -> &[Value] { + self.func.dfg.inst_results(inst) + } + + /// Changes the destination of a jump instruction after creation. + /// + /// **Note:** You are responsible for maintaining the coherence with the arguments of + /// other jump instructions. + pub fn change_jump_destination(&mut self, inst: Inst, old_block: Block, new_block: Block) { + let dfg = &mut self.func.dfg; + for block in dfg.insts[inst].branch_destination_mut(&mut dfg.jump_tables) { + if block.block(&dfg.value_lists) == old_block { + self.func_ctx.ssa.remove_block_predecessor(old_block, inst); + block.set_block(new_block, &mut dfg.value_lists); + self.func_ctx.ssa.declare_block_predecessor(new_block, inst); + } + } + } + + /// Returns `true` if and only if the current [`Block`] is sealed and has no predecessors declared. + /// + /// The entry block of a function is never unreachable. + pub fn is_unreachable(&self) -> bool { + let is_entry = match self.func.layout.entry_block() { + None => false, + Some(entry) => self.position.unwrap() == entry, + }; + !is_entry + && self.func_ctx.ssa.is_sealed(self.position.unwrap()) + && !self + .func_ctx + .ssa + .has_any_predecessors(self.position.unwrap()) + } + + /// Returns `true` if and only if no instructions have been added since the last call to + /// [`switch_to_block`](Self::switch_to_block). + fn is_pristine(&self, block: Block) -> bool { + self.func_ctx.status[block] == BlockStatus::Empty + } + + /// Returns `true` if and only if a terminator instruction has been inserted since the + /// last call to [`switch_to_block`](Self::switch_to_block). + fn is_filled(&self, block: Block) -> bool { + self.func_ctx.status[block] == BlockStatus::Filled + } +} + +/// Helper functions +impl<'a> FunctionBuilder<'a> { + /// Calls libc.memcpy + /// + /// Copies the `size` bytes from `src` to `dest`, assumes that `src + size` + /// won't overlap onto `dest`. If `dest` and `src` overlap, the behavior is + /// undefined. Applications in which `dest` and `src` might overlap should + /// use `call_memmove` instead. + pub fn call_memcpy( + &mut self, + config: TargetFrontendConfig, + dest: Value, + src: Value, + size: Value, + ) { + let pointer_type = config.pointer_type(); + let signature = { + let mut s = Signature::new(config.default_call_conv); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.returns.push(AbiParam::new(pointer_type)); + self.import_signature(s) + }; + + let libc_memcpy = self.import_function(ExtFuncData { + name: ExternalName::LibCall(LibCall::Memcpy), + signature, + colocated: false, + }); + + self.ins().call(libc_memcpy, &[dest, src, size]); + } + + /// Optimised memcpy or memmove for small copies. + /// + /// # Codegen safety + /// + /// The following properties must hold to prevent UB: + /// + /// * `src_align` and `dest_align` are an upper-bound on the alignment of `src` respectively `dest`. + /// * If `non_overlapping` is true, then this must be correct. + pub fn emit_small_memory_copy( + &mut self, + config: TargetFrontendConfig, + dest: Value, + src: Value, + size: u64, + dest_align: u8, + src_align: u8, + non_overlapping: bool, + mut flags: MemFlags, + ) { + // Currently the result of guess work, not actual profiling. + const THRESHOLD: u64 = 4; + + if size == 0 { + return; + } + + let access_size = greatest_divisible_power_of_two(size); + assert!( + access_size.is_power_of_two(), + "`size` is not a power of two" + ); + assert!( + access_size >= u64::from(::core::cmp::min(src_align, dest_align)), + "`size` is smaller than `dest` and `src`'s alignment value." + ); + + let (access_size, int_type) = if access_size <= 8 { + (access_size, Type::int((access_size * 8) as u16).unwrap()) + } else { + (8, types::I64) + }; + + let load_and_store_amount = size / access_size; + + if load_and_store_amount > THRESHOLD { + let size_value = self.ins().iconst(config.pointer_type(), size as i64); + if non_overlapping { + self.call_memcpy(config, dest, src, size_value); + } else { + self.call_memmove(config, dest, src, size_value); + } + return; + } + + if u64::from(src_align) >= access_size && u64::from(dest_align) >= access_size { + flags.set_aligned(); + } + + // Load all of the memory first. This is necessary in case `dest` overlaps. + // It can also improve performance a bit. + let registers: smallvec::SmallVec<[_; THRESHOLD as usize]> = (0..load_and_store_amount) + .map(|i| { + let offset = (access_size * i) as i32; + (self.ins().load(int_type, flags, src, offset), offset) + }) + .collect(); + + for (value, offset) in registers { + self.ins().store(flags, value, dest, offset); + } + } + + /// Calls libc.memset + /// + /// Writes `size` bytes of i8 value `ch` to memory starting at `buffer`. + pub fn call_memset( + &mut self, + config: TargetFrontendConfig, + buffer: Value, + ch: Value, + size: Value, + ) { + let pointer_type = config.pointer_type(); + let signature = { + let mut s = Signature::new(config.default_call_conv); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(types::I32)); + s.params.push(AbiParam::new(pointer_type)); + s.returns.push(AbiParam::new(pointer_type)); + self.import_signature(s) + }; + + let libc_memset = self.import_function(ExtFuncData { + name: ExternalName::LibCall(LibCall::Memset), + signature, + colocated: false, + }); + + let ch = self.ins().uextend(types::I32, ch); + self.ins().call(libc_memset, &[buffer, ch, size]); + } + + /// Calls libc.memset + /// + /// Writes `size` bytes of value `ch` to memory starting at `buffer`. + pub fn emit_small_memset( + &mut self, + config: TargetFrontendConfig, + buffer: Value, + ch: u8, + size: u64, + buffer_align: u8, + mut flags: MemFlags, + ) { + // Currently the result of guess work, not actual profiling. + const THRESHOLD: u64 = 4; + + if size == 0 { + return; + } + + let access_size = greatest_divisible_power_of_two(size); + assert!( + access_size.is_power_of_two(), + "`size` is not a power of two" + ); + assert!( + access_size >= u64::from(buffer_align), + "`size` is smaller than `dest` and `src`'s alignment value." + ); + + let (access_size, int_type) = if access_size <= 8 { + (access_size, Type::int((access_size * 8) as u16).unwrap()) + } else { + (8, types::I64) + }; + + let load_and_store_amount = size / access_size; + + if load_and_store_amount > THRESHOLD { + let ch = self.ins().iconst(types::I8, i64::from(ch)); + let size = self.ins().iconst(config.pointer_type(), size as i64); + self.call_memset(config, buffer, ch, size); + } else { + if u64::from(buffer_align) >= access_size { + flags.set_aligned(); + } + + let ch = u64::from(ch); + let raw_value = if int_type == types::I64 { + ch * 0x0101010101010101_u64 + } else if int_type == types::I32 { + ch * 0x01010101_u64 + } else if int_type == types::I16 { + (ch << 8) | ch + } else { + assert_eq!(int_type, types::I8); + ch + }; + + let value = self.ins().iconst(int_type, raw_value as i64); + for i in 0..load_and_store_amount { + let offset = (access_size * i) as i32; + self.ins().store(flags, value, buffer, offset); + } + } + } + + /// Calls libc.memmove + /// + /// Copies `size` bytes from memory starting at `source` to memory starting + /// at `dest`. `source` is always read before writing to `dest`. + pub fn call_memmove( + &mut self, + config: TargetFrontendConfig, + dest: Value, + source: Value, + size: Value, + ) { + let pointer_type = config.pointer_type(); + let signature = { + let mut s = Signature::new(config.default_call_conv); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.returns.push(AbiParam::new(pointer_type)); + self.import_signature(s) + }; + + let libc_memmove = self.import_function(ExtFuncData { + name: ExternalName::LibCall(LibCall::Memmove), + signature, + colocated: false, + }); + + self.ins().call(libc_memmove, &[dest, source, size]); + } + + /// Calls libc.memcmp + /// + /// Compares `size` bytes from memory starting at `left` to memory starting + /// at `right`. Returns `0` if all `n` bytes are equal. If the first difference + /// is at offset `i`, returns a positive integer if `ugt(left[i], right[i])` + /// and a negative integer if `ult(left[i], right[i])`. + /// + /// Returns a C `int`, which is currently always [`types::I32`]. + pub fn call_memcmp( + &mut self, + config: TargetFrontendConfig, + left: Value, + right: Value, + size: Value, + ) -> Value { + let pointer_type = config.pointer_type(); + let signature = { + let mut s = Signature::new(config.default_call_conv); + s.params.reserve(3); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.params.push(AbiParam::new(pointer_type)); + s.returns.push(AbiParam::new(types::I32)); + self.import_signature(s) + }; + + let libc_memcmp = self.import_function(ExtFuncData { + name: ExternalName::LibCall(LibCall::Memcmp), + signature, + colocated: false, + }); + + let call = self.ins().call(libc_memcmp, &[left, right, size]); + self.func.dfg.first_result(call) + } + + /// Optimised [`Self::call_memcmp`] for small copies. + /// + /// This implements the byte slice comparison `int_cc(left[..size], right[..size])`. + /// + /// `left_align` and `right_align` are the statically-known alignments of the + /// `left` and `right` pointers respectively. These are used to know whether + /// to mark `load`s as aligned. It's always fine to pass `1` for these, but + /// passing something higher than the true alignment may trap or otherwise + /// misbehave as described in [`MemFlags::aligned`]. + /// + /// Note that `memcmp` is a *big-endian* and *unsigned* comparison. + /// As such, this panics when called with `IntCC::Signed*`. + pub fn emit_small_memory_compare( + &mut self, + config: TargetFrontendConfig, + int_cc: IntCC, + left: Value, + right: Value, + size: u64, + left_align: std::num::NonZeroU8, + right_align: std::num::NonZeroU8, + flags: MemFlags, + ) -> Value { + use IntCC::*; + let (zero_cc, empty_imm) = match int_cc { + // + Equal => (Equal, 1), + NotEqual => (NotEqual, 0), + + UnsignedLessThan => (SignedLessThan, 0), + UnsignedGreaterThanOrEqual => (SignedGreaterThanOrEqual, 1), + UnsignedGreaterThan => (SignedGreaterThan, 0), + UnsignedLessThanOrEqual => (SignedLessThanOrEqual, 1), + + SignedLessThan + | SignedGreaterThanOrEqual + | SignedGreaterThan + | SignedLessThanOrEqual => { + panic!("Signed comparison {int_cc} not supported by memcmp") + } + }; + + if size == 0 { + return self.ins().iconst(types::I8, empty_imm); + } + + // Future work could consider expanding this to handle more-complex scenarios. + if let Some(small_type) = size.try_into().ok().and_then(Type::int_with_byte_size) { + if let Equal | NotEqual = zero_cc { + let mut left_flags = flags; + if size == left_align.get() as u64 { + left_flags.set_aligned(); + } + let mut right_flags = flags; + if size == right_align.get() as u64 { + right_flags.set_aligned(); + } + let left_val = self.ins().load(small_type, left_flags, left, 0); + let right_val = self.ins().load(small_type, right_flags, right, 0); + return self.ins().icmp(int_cc, left_val, right_val); + } else if small_type == types::I8 { + // Once the big-endian loads from wasmtime#2492 are implemented in + // the backends, we could easily handle comparisons for more sizes here. + // But for now, just handle single bytes where we don't need to worry. + + let mut aligned_flags = flags; + aligned_flags.set_aligned(); + let left_val = self.ins().load(small_type, aligned_flags, left, 0); + let right_val = self.ins().load(small_type, aligned_flags, right, 0); + return self.ins().icmp(int_cc, left_val, right_val); + } + } + + let pointer_type = config.pointer_type(); + let size = self.ins().iconst(pointer_type, size as i64); + let cmp = self.call_memcmp(config, left, right, size); + self.ins().icmp_imm(zero_cc, cmp, 0) + } +} + +fn greatest_divisible_power_of_two(size: u64) -> u64 { + (size as i64 & -(size as i64)) as u64 +} + +// Helper functions +impl<'a> FunctionBuilder<'a> { + /// A Block is 'filled' when a terminator instruction is present. + fn fill_current_block(&mut self) { + self.func_ctx.status[self.position.unwrap()] = BlockStatus::Filled; + } + + fn declare_successor(&mut self, dest_block: Block, jump_inst: Inst) { + self.func_ctx + .ssa + .declare_block_predecessor(dest_block, jump_inst); + } + + fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) { + for modified_block in side_effects.instructions_added_to_blocks { + if self.is_pristine(modified_block) { + self.func_ctx.status[modified_block] = BlockStatus::Partial; + } + } + } +} + +#[cfg(test)] +mod tests { + use super::greatest_divisible_power_of_two; + use crate::frontend::{ + DeclareVariableError, DefVariableError, FunctionBuilder, FunctionBuilderContext, + UseVariableError, + }; + use crate::Variable; + use alloc::string::ToString; + use cranelift_codegen::entity::EntityRef; + use cranelift_codegen::ir::condcodes::IntCC; + use cranelift_codegen::ir::{types::*, UserFuncName}; + use cranelift_codegen::ir::{AbiParam, Function, InstBuilder, MemFlags, Signature, Value}; + use cranelift_codegen::isa::{CallConv, TargetFrontendConfig, TargetIsa}; + use cranelift_codegen::settings; + use cranelift_codegen::verifier::verify_function; + use target_lexicon::PointerWidth; + + fn sample_function(lazy_seal: bool) { + let mut sig = Signature::new(CallConv::SystemV); + sig.returns.push(AbiParam::new(I32)); + sig.params.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(1); + let z = Variable::new(2); + builder.declare_var(x, I32); + builder.declare_var(y, I32); + builder.declare_var(z, I32); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + if !lazy_seal { + builder.seal_block(block0); + } + { + let tmp = builder.block_params(block0)[0]; // the first function parameter + builder.def_var(x, tmp); + } + { + let tmp = builder.ins().iconst(I32, 2); + builder.def_var(y, tmp); + } + { + let arg1 = builder.use_var(x); + let arg2 = builder.use_var(y); + let tmp = builder.ins().iadd(arg1, arg2); + builder.def_var(z, tmp); + } + builder.ins().jump(block1, &[]); + + builder.switch_to_block(block1); + { + let arg1 = builder.use_var(y); + let arg2 = builder.use_var(z); + let tmp = builder.ins().iadd(arg1, arg2); + builder.def_var(z, tmp); + } + { + let arg = builder.use_var(y); + builder.ins().brif(arg, block3, &[], block2, &[]); + } + + builder.switch_to_block(block2); + if !lazy_seal { + builder.seal_block(block2); + } + { + let arg1 = builder.use_var(z); + let arg2 = builder.use_var(x); + let tmp = builder.ins().isub(arg1, arg2); + builder.def_var(z, tmp); + } + { + let arg = builder.use_var(y); + builder.ins().return_(&[arg]); + } + + builder.switch_to_block(block3); + if !lazy_seal { + builder.seal_block(block3); + } + + { + let arg1 = builder.use_var(y); + let arg2 = builder.use_var(x); + let tmp = builder.ins().isub(arg1, arg2); + builder.def_var(y, tmp); + } + builder.ins().jump(block1, &[]); + if !lazy_seal { + builder.seal_block(block1); + } + + if lazy_seal { + builder.seal_all_blocks(); + } + + builder.finalize(); + } + + let flags = settings::Flags::new(settings::builder()); + // println!("{}", func.display(None)); + if let Err(errors) = verify_function(&func, &flags) { + panic!("{}\n{}", func.display(), errors) + } + } + + #[test] + fn sample() { + sample_function(false) + } + + #[test] + fn sample_with_lazy_seal() { + sample_function(true) + } + + #[track_caller] + fn check(func: &Function, expected_ir: &str) { + let expected_ir = expected_ir.trim(); + let actual_ir = func.display().to_string(); + let actual_ir = actual_ir.trim(); + assert!( + expected_ir == actual_ir, + "Expected:\n{expected_ir}\nGot:\n{actual_ir}" + ); + } + + /// Helper function to construct a fixed frontend configuration. + fn systemv_frontend_config() -> TargetFrontendConfig { + TargetFrontendConfig { + default_call_conv: CallConv::SystemV, + pointer_width: PointerWidth::U64, + page_size_align_log2: 12, + } + } + + #[test] + fn memcpy() { + let frontend_config = systemv_frontend_config(); + let mut sig = Signature::new(frontend_config.default_call_conv); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(1); + let z = Variable::new(2); + builder.declare_var(x, frontend_config.pointer_type()); + builder.declare_var(y, frontend_config.pointer_type()); + builder.declare_var(z, I32); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let src = builder.use_var(x); + let dest = builder.use_var(y); + let size = builder.use_var(y); + builder.call_memcpy(frontend_config, dest, src, size); + builder.ins().return_(&[size]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { + sig0 = (i64, i64, i64) -> i64 system_v + fn0 = %Memcpy sig0 + +block0: + v4 = iconst.i64 0 + v1 -> v4 + v3 = iconst.i64 0 + v0 -> v3 + v2 = call fn0(v1, v0, v1) ; v1 = 0, v0 = 0, v1 = 0 + return v1 ; v1 = 0 +} +", + ); + } + + #[test] + fn small_memcpy() { + let frontend_config = systemv_frontend_config(); + let mut sig = Signature::new(frontend_config.default_call_conv); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(16); + builder.declare_var(x, frontend_config.pointer_type()); + builder.declare_var(y, frontend_config.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let src = builder.use_var(x); + let dest = builder.use_var(y); + let size = 8; + builder.emit_small_memory_copy( + frontend_config, + dest, + src, + size, + 8, + 8, + true, + MemFlags::new(), + ); + builder.ins().return_(&[dest]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { +block0: + v4 = iconst.i64 0 + v1 -> v4 + v3 = iconst.i64 0 + v0 -> v3 + v2 = load.i64 aligned v0 ; v0 = 0 + store aligned v2, v1 ; v1 = 0 + return v1 ; v1 = 0 +} +", + ); + } + + #[test] + fn not_so_small_memcpy() { + let frontend_config = systemv_frontend_config(); + let mut sig = Signature::new(frontend_config.default_call_conv); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(16); + builder.declare_var(x, frontend_config.pointer_type()); + builder.declare_var(y, frontend_config.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let src = builder.use_var(x); + let dest = builder.use_var(y); + let size = 8192; + builder.emit_small_memory_copy( + frontend_config, + dest, + src, + size, + 8, + 8, + true, + MemFlags::new(), + ); + builder.ins().return_(&[dest]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { + sig0 = (i64, i64, i64) -> i64 system_v + fn0 = %Memcpy sig0 + +block0: + v5 = iconst.i64 0 + v1 -> v5 + v4 = iconst.i64 0 + v0 -> v4 + v2 = iconst.i64 8192 + v3 = call fn0(v1, v0, v2) ; v1 = 0, v0 = 0, v2 = 8192 + return v1 ; v1 = 0 +} +", + ); + } + + #[test] + fn small_memset() { + let frontend_config = systemv_frontend_config(); + let mut sig = Signature::new(frontend_config.default_call_conv); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let y = Variable::new(16); + builder.declare_var(y, frontend_config.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let dest = builder.use_var(y); + let size = 8; + builder.emit_small_memset(frontend_config, dest, 1, size, 8, MemFlags::new()); + builder.ins().return_(&[dest]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { +block0: + v2 = iconst.i64 0 + v0 -> v2 + v1 = iconst.i64 0x0101_0101_0101_0101 + store aligned v1, v0 ; v1 = 0x0101_0101_0101_0101, v0 = 0 + return v0 ; v0 = 0 +} +", + ); + } + + #[test] + fn not_so_small_memset() { + let frontend_config = systemv_frontend_config(); + let mut sig = Signature::new(frontend_config.default_call_conv); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let y = Variable::new(16); + builder.declare_var(y, frontend_config.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let dest = builder.use_var(y); + let size = 8192; + builder.emit_small_memset(frontend_config, dest, 1, size, 8, MemFlags::new()); + builder.ins().return_(&[dest]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { + sig0 = (i64, i32, i64) -> i64 system_v + fn0 = %Memset sig0 + +block0: + v5 = iconst.i64 0 + v0 -> v5 + v1 = iconst.i8 1 + v2 = iconst.i64 8192 + v3 = uextend.i32 v1 ; v1 = 1 + v4 = call fn0(v0, v3, v2) ; v0 = 0, v2 = 8192 + return v0 ; v0 = 0 +} +", + ); + } + + #[test] + fn memcmp() { + use core::str::FromStr; + use cranelift_codegen::isa; + + let shared_builder = settings::builder(); + let shared_flags = settings::Flags::new(shared_builder); + + let triple = + ::target_lexicon::Triple::from_str("x86_64").expect("Couldn't create x86_64 triple"); + + let target = isa::lookup(triple) + .ok() + .map(|b| b.finish(shared_flags)) + .expect("This test requires x86_64 support.") + .expect("Should be able to create backend with default flags"); + + let mut sig = Signature::new(target.default_call_conv()); + sig.returns.push(AbiParam::new(I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(1); + let z = Variable::new(2); + builder.declare_var(x, target.pointer_type()); + builder.declare_var(y, target.pointer_type()); + builder.declare_var(z, target.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let left = builder.use_var(x); + let right = builder.use_var(y); + let size = builder.use_var(z); + let cmp = builder.call_memcmp(target.frontend_config(), left, right, size); + builder.ins().return_(&[cmp]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i32 system_v { + sig0 = (i64, i64, i64) -> i32 system_v + fn0 = %Memcmp sig0 + +block0: + v6 = iconst.i64 0 + v2 -> v6 + v5 = iconst.i64 0 + v1 -> v5 + v4 = iconst.i64 0 + v0 -> v4 + v3 = call fn0(v0, v1, v2) ; v0 = 0, v1 = 0, v2 = 0 + return v3 +} +", + ); + } + + #[test] + fn small_memcmp_zero_size() { + let align_eight = std::num::NonZeroU8::new(8).unwrap(); + small_memcmp_helper( + " +block0: + v4 = iconst.i64 0 + v1 -> v4 + v3 = iconst.i64 0 + v0 -> v3 + v2 = iconst.i8 1 + return v2 ; v2 = 1", + |builder, target, x, y| { + builder.emit_small_memory_compare( + target.frontend_config(), + IntCC::UnsignedGreaterThanOrEqual, + x, + y, + 0, + align_eight, + align_eight, + MemFlags::new(), + ) + }, + ); + } + + #[test] + fn small_memcmp_byte_ugt() { + let align_one = std::num::NonZeroU8::new(1).unwrap(); + small_memcmp_helper( + " +block0: + v6 = iconst.i64 0 + v1 -> v6 + v5 = iconst.i64 0 + v0 -> v5 + v2 = load.i8 aligned v0 ; v0 = 0 + v3 = load.i8 aligned v1 ; v1 = 0 + v4 = icmp ugt v2, v3 + return v4", + |builder, target, x, y| { + builder.emit_small_memory_compare( + target.frontend_config(), + IntCC::UnsignedGreaterThan, + x, + y, + 1, + align_one, + align_one, + MemFlags::new(), + ) + }, + ); + } + + #[test] + fn small_memcmp_aligned_eq() { + let align_four = std::num::NonZeroU8::new(4).unwrap(); + small_memcmp_helper( + " +block0: + v6 = iconst.i64 0 + v1 -> v6 + v5 = iconst.i64 0 + v0 -> v5 + v2 = load.i32 aligned v0 ; v0 = 0 + v3 = load.i32 aligned v1 ; v1 = 0 + v4 = icmp eq v2, v3 + return v4", + |builder, target, x, y| { + builder.emit_small_memory_compare( + target.frontend_config(), + IntCC::Equal, + x, + y, + 4, + align_four, + align_four, + MemFlags::new(), + ) + }, + ); + } + + #[test] + fn small_memcmp_ipv6_ne() { + let align_two = std::num::NonZeroU8::new(2).unwrap(); + small_memcmp_helper( + " +block0: + v6 = iconst.i64 0 + v1 -> v6 + v5 = iconst.i64 0 + v0 -> v5 + v2 = load.i128 v0 ; v0 = 0 + v3 = load.i128 v1 ; v1 = 0 + v4 = icmp ne v2, v3 + return v4", + |builder, target, x, y| { + builder.emit_small_memory_compare( + target.frontend_config(), + IntCC::NotEqual, + x, + y, + 16, + align_two, + align_two, + MemFlags::new(), + ) + }, + ); + } + + #[test] + fn small_memcmp_odd_size_uge() { + let one = std::num::NonZeroU8::new(1).unwrap(); + small_memcmp_helper( + " + sig0 = (i64, i64, i64) -> i32 system_v + fn0 = %Memcmp sig0 + +block0: + v6 = iconst.i64 0 + v1 -> v6 + v5 = iconst.i64 0 + v0 -> v5 + v2 = iconst.i64 3 + v3 = call fn0(v0, v1, v2) ; v0 = 0, v1 = 0, v2 = 3 + v4 = icmp_imm sge v3, 0 + return v4", + |builder, target, x, y| { + builder.emit_small_memory_compare( + target.frontend_config(), + IntCC::UnsignedGreaterThanOrEqual, + x, + y, + 3, + one, + one, + MemFlags::new(), + ) + }, + ); + } + + fn small_memcmp_helper( + expected: &str, + f: impl FnOnce(&mut FunctionBuilder, &dyn TargetIsa, Value, Value) -> Value, + ) { + use core::str::FromStr; + use cranelift_codegen::isa; + + let shared_builder = settings::builder(); + let shared_flags = settings::Flags::new(shared_builder); + + let triple = + ::target_lexicon::Triple::from_str("x86_64").expect("Couldn't create x86_64 triple"); + + let target = isa::lookup(triple) + .ok() + .map(|b| b.finish(shared_flags)) + .expect("This test requires x86_64 support.") + .expect("Should be able to create backend with default flags"); + + let mut sig = Signature::new(target.default_call_conv()); + sig.returns.push(AbiParam::new(I8)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let x = Variable::new(0); + let y = Variable::new(1); + builder.declare_var(x, target.pointer_type()); + builder.declare_var(y, target.pointer_type()); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let left = builder.use_var(x); + let right = builder.use_var(y); + let ret = f(&mut builder, &*target, left, right); + builder.ins().return_(&[ret]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + &format!("function %sample() -> i8 system_v {{{expected}\n}}\n"), + ); + } + + #[test] + fn undef_vector_vars() { + let mut sig = Signature::new(CallConv::SystemV); + sig.returns.push(AbiParam::new(I8X16)); + sig.returns.push(AbiParam::new(I8X16)); + sig.returns.push(AbiParam::new(F32X4)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + let a = Variable::new(0); + let b = Variable::new(1); + let c = Variable::new(2); + builder.declare_var(a, I8X16); + builder.declare_var(b, I8X16); + builder.declare_var(c, F32X4); + builder.switch_to_block(block0); + + let a = builder.use_var(a); + let b = builder.use_var(b); + let c = builder.use_var(c); + builder.ins().return_(&[a, b, c]); + + builder.seal_all_blocks(); + builder.finalize(); + } + + check( + &func, + "function %sample() -> i8x16, i8x16, f32x4 system_v { + const0 = 0x00000000000000000000000000000000 + +block0: + v5 = f32const 0.0 + v6 = splat.f32x4 v5 ; v5 = 0.0 + v2 -> v6 + v4 = vconst.i8x16 const0 + v1 -> v4 + v3 = vconst.i8x16 const0 + v0 -> v3 + return v0, v1, v2 ; v0 = const0, v1 = const0 +} +", + ); + } + + #[test] + fn test_greatest_divisible_power_of_two() { + assert_eq!(64, greatest_divisible_power_of_two(64)); + assert_eq!(16, greatest_divisible_power_of_two(48)); + assert_eq!(8, greatest_divisible_power_of_two(24)); + assert_eq!(1, greatest_divisible_power_of_two(25)); + } + + #[test] + fn try_use_var() { + let sig = Signature::new(CallConv::SystemV); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + assert_eq!( + builder.try_use_var(Variable::from_u32(0)), + Err(UseVariableError::UsedBeforeDeclared(Variable::from_u32(0))) + ); + + let value = builder.ins().iconst(cranelift_codegen::ir::types::I32, 0); + + assert_eq!( + builder.try_def_var(Variable::from_u32(0), value), + Err(DefVariableError::DefinedBeforeDeclared(Variable::from_u32( + 0 + ))) + ); + + builder.declare_var(Variable::from_u32(0), cranelift_codegen::ir::types::I32); + assert_eq!( + builder.try_declare_var(Variable::from_u32(0), cranelift_codegen::ir::types::I32), + Err(DeclareVariableError::DeclaredMultipleTimes( + Variable::from_u32(0) + )) + ); + } + } + + #[test] + fn test_builder_with_iconst_and_negative_constant() { + let sig = Signature::new(CallConv::SystemV); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(UserFuncName::testcase("sample"), sig); + + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let block0 = builder.create_block(); + builder.switch_to_block(block0); + builder.ins().iconst(I32, -1); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder()); + let ctx = cranelift_codegen::Context::for_function(func); + ctx.verify(&flags).expect("should be valid"); + + check( + &ctx.func, + "function %sample() system_v { +block0: + v0 = iconst.i32 -1 + return +}", + ); + } +} diff --git a/deps/crates/vendor/cranelift-frontend/src/frontend/safepoints.rs b/deps/crates/vendor/cranelift-frontend/src/frontend/safepoints.rs new file mode 100644 index 00000000000000..f4a9f8455a1d58 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/frontend/safepoints.rs @@ -0,0 +1,2409 @@ +//! Support for safepoints and stack maps. + +use super::*; +use crate::{HashMap, HashSet}; +use core::ops::{Index, IndexMut}; + +#[derive(Clone, Copy)] +#[repr(u8)] +enum SlotSize { + Size8 = 0, + Size16 = 1, + Size32 = 2, + Size64 = 3, + Size128 = 4, + // If adding support for more slot sizes, update `SLOT_SIZE_LEN` below. +} +const SLOT_SIZE_LEN: usize = 5; + +impl TryFrom for SlotSize { + type Error = &'static str; + + fn try_from(ty: ir::Type) -> Result { + Self::new(ty.bytes()).ok_or("type is not supported in stack maps") + } +} + +impl SlotSize { + fn new(bytes: u32) -> Option { + match bytes { + 1 => Some(Self::Size8), + 2 => Some(Self::Size16), + 4 => Some(Self::Size32), + 8 => Some(Self::Size64), + 16 => Some(Self::Size128), + _ => None, + } + } + + fn unwrap_new(bytes: u32) -> Self { + Self::new(bytes).unwrap_or_else(|| panic!("cannot create a `SlotSize` for {bytes} bytes")) + } +} + +/// A map from every `SlotSize` to a `T`. +struct SlotSizeMap([T; SLOT_SIZE_LEN]); + +impl Default for SlotSizeMap +where + T: Default, +{ + fn default() -> Self { + Self::new() + } +} + +impl Index for SlotSizeMap { + type Output = T; + fn index(&self, index: SlotSize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for SlotSizeMap { + fn index_mut(&mut self, index: SlotSize) -> &mut Self::Output { + self.get_mut(index) + } +} + +impl SlotSizeMap { + fn new() -> Self + where + T: Default, + { + Self([ + T::default(), + T::default(), + T::default(), + T::default(), + T::default(), + ]) + } + + fn clear(&mut self) + where + T: Default, + { + *self = Self::new(); + } + + fn get(&self, size: SlotSize) -> &T { + let index = size as u8 as usize; + &self.0[index] + } + + fn get_mut(&mut self, size: SlotSize) -> &mut T { + let index = size as u8 as usize; + &mut self.0[index] + } +} + +/// A set of live values. +/// +/// Make sure to copy to a vec and sort, or something, before iterating over the +/// values to ensure deterministic output. +type LiveSet = HashSet; + +/// A worklist of blocks' post-order indices that we need to process. +#[derive(Default)] +struct Worklist { + /// Stack of blocks to process. + stack: Vec, + + /// The set of blocks that need to be updated. + /// + /// This is a subset of the elements present in `self.stack`, *not* the + /// exact same elements. `self.stack` is allowed to have duplicates, and + /// once we pop the first occurrence of a duplicate, we remove it from this + /// set, since it no longer needs updates at that point. This potentially + /// uses more stack space than necessary, but prefers processing immediate + /// predecessors, and therefore inner loop bodies before continuing to + /// process outer loop bodies. This ultimately results in fewer iterations + /// required to reach a fixed point. + need_updates: HashSet, +} + +impl Extend for Worklist { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for block_index in iter { + self.push(block_index); + } + } +} + +impl Worklist { + fn clear(&mut self) { + let Worklist { + stack, + need_updates, + } = self; + stack.clear(); + need_updates.clear(); + } + + fn reserve(&mut self, capacity: usize) { + let Worklist { + stack, + need_updates, + } = self; + stack.reserve(capacity); + need_updates.reserve(capacity); + } + + fn push(&mut self, block_index: u32) { + // Mark this block as needing an update. If it wasn't in `self.stack`, + // now it is and it needs an update. If it was already in `self.stack`, + // then pushing this copy logically hoists it to the top of the + // stack. See the above note about processing inner-most loops first. + self.need_updates.insert(block_index); + self.stack.push(block_index); + } + + fn pop(&mut self) -> Option { + while let Some(block_index) = self.stack.pop() { + // If this block was pushed multiple times, we only need to update + // it once, so remove it from the need-updates set. In other words + // it was logically hoisted up to the top of the stack, while this + // entry was left behind, and we already popped the hoisted + // copy. See the above note about processing inner-most loops first. + if self.need_updates.remove(&block_index) { + return Some(block_index); + } + } + None + } +} + +/// A simple liveness analysis. +/// +/// This analysis is used to determine which needs-stack-map values are live +/// across safepoint instructions. +/// +/// This is a backwards analysis, from uses (which mark values live) to defs +/// (which remove values from the live set) and from successor blocks to +/// predecessor blocks. +/// +/// We compute two live sets for each block: +/// +/// 1. The live-in set, which is the set of values that are live when control +/// enters the block. +/// +/// 2. The live-out set, which is the set of values that are live when control +/// exits the block. +/// +/// A block's live-out set is the union of its successors' live-in sets. A +/// block's live-in set is the set of values that are still live after the +/// block's instructions have been processed. +/// +/// ```text +/// live_in(block) = union(live_out(s) for s in successors(block)) +/// live_out(block) = live_in(block) - defs(block) + uses(block) +/// ``` +/// +/// Whenever we update a block's live-in set, we must reprocess all of its +/// predecessors, because those predecessors' live-out sets depend on this +/// block's live-in set. Processing continues until the live sets stop changing +/// and we've reached a fixed-point. Each time we process a block, its live sets +/// can only grow monotonically, and therefore we know that the computation will +/// reach its fixed-point and terminate. This fixed-point is implemented with a +/// classic worklist algorithm. +/// +/// The worklist is seeded such that we initially process blocks in post-order, +/// which ensures that, when we have a loop-free control-flow graph, we only +/// process each block once. We pop a block off the worklist for +/// processing. Whenever a block's live-in set is updated during processing, we +/// push its predecessors onto the worklist so that their live-in sets can be +/// updated. Once the worklist is empty, there are no more blocks needing +/// updates, and we've reached the fixed-point. +/// +/// Note: For simplicity, we do not flow liveness from block parameters back to +/// branch arguments, and instead always consider branch arguments live. +/// +/// Furthermore, we do not differentiate between uses of a needs-stack-map value +/// that ultimately flow into a side-effecting operation versus uses that +/// themselves are not live. This could be tightened up in the future, but we're +/// starting with the easiest, simplest thing. It also means that we do not need +/// `O(all values)` space, only `O(needs-stack-map values)`. Finally, none of +/// our mid-end optimization passes have run at this point in time yet, so there +/// probably isn't much, if any, dead code. +/// +/// After we've computed the live-in and -out sets for each block, we pass once +/// more over each block, processing its instructions again. This time, we +/// record the precise set of needs-stack-map values that are live across each +/// safepoint instruction inside the block, which is the final output of this +/// analysis. +pub(crate) struct LivenessAnalysis { + /// Reusable depth-first search state for traversing a function's blocks. + dfs: Dfs, + + /// The cached post-order traversal of the function's blocks. + post_order: Vec, + + /// A secondary map from each block to its index in `post_order`. + block_to_index: SecondaryMap, + + /// A mapping from each block's post-order index to the post-order indices + /// of its direct (non-transitive) predecessors. + predecessors: Vec>, + + /// A worklist of blocks to process. Used to determine which blocks need + /// updates cascaded to them and when we reach a fixed-point. + worklist: Worklist, + + /// A map from a block's post-order index to its live-in set. + live_ins: Vec, + + /// A map from a block's post-order index to its live-out set. + live_outs: Vec, + + /// The set of each needs-stack-map value that is currently live while + /// processing a block. + currently_live: LiveSet, + + /// A mapping from each safepoint instruction to the set of needs-stack-map + /// values that are live across it. + safepoints: HashMap>, + + /// The set of values that are live across *any* safepoint in the function, + /// i.e. the union of all the values in the `safepoints` map. + live_across_any_safepoint: EntitySet, +} + +impl Default for LivenessAnalysis { + fn default() -> Self { + Self { + dfs: Default::default(), + post_order: Default::default(), + block_to_index: SecondaryMap::with_default(u32::MAX), + predecessors: Default::default(), + worklist: Default::default(), + live_ins: Default::default(), + live_outs: Default::default(), + currently_live: Default::default(), + safepoints: Default::default(), + live_across_any_safepoint: Default::default(), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum RecordSafepoints { + Yes, + No, +} + +impl LivenessAnalysis { + /// Clear and reset all internal state such that this analysis is ready for + /// reuse with a new function. + pub fn clear(&mut self) { + let LivenessAnalysis { + dfs, + post_order, + block_to_index, + predecessors, + worklist, + live_ins, + live_outs, + currently_live, + safepoints, + live_across_any_safepoint, + } = self; + dfs.clear(); + post_order.clear(); + block_to_index.clear(); + predecessors.clear(); + worklist.clear(); + live_ins.clear(); + live_outs.clear(); + currently_live.clear(); + safepoints.clear(); + live_across_any_safepoint.clear(); + } + + /// Given that we've initialized `self.post_order`, reserve capacity for the + /// various data structures we use during our analysis. + fn reserve_capacity(&mut self, func: &Function) { + let LivenessAnalysis { + dfs: _, + post_order, + block_to_index, + predecessors, + worklist, + live_ins, + live_outs, + currently_live: _, + safepoints: _, + live_across_any_safepoint: _, + } = self; + + block_to_index.resize(func.dfg.num_blocks()); + + let capacity = post_order.len(); + worklist.reserve(capacity); + predecessors.resize(capacity, Default::default()); + live_ins.resize(capacity, Default::default()); + live_outs.resize(capacity, Default::default()); + } + + fn initialize_block_to_index_map(&mut self) { + for (block_index, block) in self.post_order.iter().enumerate() { + self.block_to_index[*block] = u32::try_from(block_index).unwrap(); + } + } + + fn initialize_predecessors_map(&mut self, func: &Function) { + for (block_index, block) in self.post_order.iter().enumerate() { + let block_index = u32::try_from(block_index).unwrap(); + for succ in func.block_successors(*block) { + let succ_index = self.block_to_index[succ]; + debug_assert_ne!(succ_index, u32::MAX); + let succ_index = usize::try_from(succ_index).unwrap(); + self.predecessors[succ_index].push(block_index); + } + } + } + + /// Process a value's definition, removing it from the currently-live set. + fn process_def(&mut self, val: ir::Value) { + if self.currently_live.remove(&val) { + log::trace!("liveness: defining {val:?}, removing it from the live set"); + } + } + + /// Record the live set of needs-stack-map values at the given safepoint. + fn record_safepoint(&mut self, func: &Function, inst: Inst) { + log::trace!( + "liveness: found safepoint: {inst:?}: {}", + func.dfg.display_inst(inst) + ); + log::trace!("liveness: live set = {:?}", self.currently_live); + + let mut live = self.currently_live.iter().copied().collect::>(); + // Keep order deterministic since we add stack map entries in this + // order. + live.sort(); + + self.live_across_any_safepoint.extend(live.iter().copied()); + self.safepoints.insert(inst, live); + } + + /// Process a use of a needs-stack-map value, inserting it into the + /// currently-live set. + fn process_use(&mut self, func: &Function, inst: Inst, val: Value) { + if self.currently_live.insert(val) { + log::trace!( + "liveness: found use of {val:?}, marking it live: {inst:?}: {}", + func.dfg.display_inst(inst) + ); + } + } + + /// Process all the instructions in a block in reverse order. + fn process_block( + &mut self, + func: &mut Function, + stack_map_values: &EntitySet, + block_index: usize, + record_safepoints: RecordSafepoints, + ) { + let block = self.post_order[block_index]; + log::trace!("liveness: traversing {block:?}"); + + // Reset the currently-live set to this block's live-out set. + self.currently_live.clear(); + self.currently_live + .extend(self.live_outs[block_index].iter().copied()); + + // Now process this block's instructions, incrementally building its + // live-in set inside the currently-live set. + let mut option_inst = func.layout.last_inst(block); + while let Some(inst) = option_inst { + // Process any needs-stack-map values defined by this instruction. + for val in func.dfg.inst_results(inst) { + self.process_def(*val); + } + + // If this instruction is a safepoint and we've been asked to record + // safepoints, then do so. + let opcode = func.dfg.insts[inst].opcode(); + if record_safepoints == RecordSafepoints::Yes && opcode.is_safepoint() { + self.record_safepoint(func, inst); + } + + // Process any needs-stack-map values used by this instruction. + for val in func.dfg.inst_values(inst) { + let val = func.dfg.resolve_aliases(val); + if stack_map_values.contains(val) { + self.process_use(func, inst, val); + } + } + + option_inst = func.layout.prev_inst(inst); + } + + // After we've processed this block's instructions, remove its + // parameters from the live set. This is part of step (1). + for val in func.dfg.block_params(block) { + self.process_def(*val); + } + } + + /// Run the liveness analysis on the given function. + pub fn run(&mut self, func: &mut Function, stack_map_values: &EntitySet) { + self.clear(); + self.post_order.extend(self.dfs.post_order_iter(func)); + self.reserve_capacity(func); + self.initialize_block_to_index_map(); + self.initialize_predecessors_map(func); + + // Initially enqueue all blocks for processing. We push them in reverse + // post-order (which yields them in post-order when popped) because if + // there are no back-edges in the control-flow graph, post-order will + // result in only a single pass over the blocks. + self.worklist + .extend((0..u32::try_from(self.post_order.len()).unwrap()).rev()); + + // Pump the worklist until we reach a fixed-point. + while let Some(block_index) = self.worklist.pop() { + let block_index = usize::try_from(block_index).unwrap(); + + // Because our live sets grow monotonically, we just need to see if + // the size changed to determine whether the whole set changed. + let initial_live_in_len = self.live_ins[block_index].len(); + + // The live-out set for a block is the union of the live-in sets of + // its successors. + for successor in func.block_successors(self.post_order[block_index]) { + let successor_index = self.block_to_index[successor]; + debug_assert_ne!(successor_index, u32::MAX); + let successor_index = usize::try_from(successor_index).unwrap(); + self.live_outs[block_index].extend(self.live_ins[successor_index].iter().copied()); + } + + // Process the block to compute its live-in set, but do not record + // safepoints yet, as we haven't yet processed loop back edges (see + // below). + self.process_block(func, stack_map_values, block_index, RecordSafepoints::No); + + // The live-in set for a block is the set of values that are still + // live after the block's instructions have been processed. + self.live_ins[block_index].extend(self.currently_live.iter().copied()); + + // If the live-in set changed, then we need to revisit all this + // block's predecessors. + if self.live_ins[block_index].len() != initial_live_in_len { + self.worklist + .extend(self.predecessors[block_index].iter().copied()); + } + } + + // Once we've reached a fixed-point, compute the actual live set for + // each safepoint instruction in each block, backwards from the block's + // live-out set. + for block_index in 0..self.post_order.len() { + self.process_block(func, stack_map_values, block_index, RecordSafepoints::Yes); + + debug_assert_eq!( + self.currently_live, self.live_ins[block_index], + "when we recompute the live-in set for a block as part of \ + computing live sets at each safepoint, we should get the same \ + result we computed in the fixed-point" + ); + } + } +} + +/// A mapping from each needs-stack-map value to its associated stack slot. +/// +/// Internally maintains free lists for stack slots that won't be used again, so +/// that we can reuse them and minimize the number of stack slots we need to +/// allocate. +#[derive(Default)] +struct StackSlots { + /// A mapping from each needs-stack-map value that is live across some + /// safepoint to the stack slot that it resides within. Note that if a + /// needs-stack-map value is never live across a safepoint, then we won't + /// ever add it to this map, it can remain in a virtual register for the + /// duration of its lifetime, and we won't replace all its uses with reloads + /// and all that stuff. + stack_slots: HashMap, + + /// A map from slot size to free stack slots that are not being used + /// anymore. This allows us to reuse stack slots across multiple values + /// helps cut down on the ultimate size of our stack frames. + free_stack_slots: SlotSizeMap>, +} + +impl StackSlots { + fn clear(&mut self) { + let StackSlots { + stack_slots, + free_stack_slots, + } = self; + stack_slots.clear(); + free_stack_slots.clear(); + } + + fn get(&self, val: ir::Value) -> Option { + self.stack_slots.get(&val).copied() + } + + fn get_or_create_stack_slot(&mut self, func: &mut Function, val: ir::Value) -> ir::StackSlot { + *self.stack_slots.entry(val).or_insert_with(|| { + log::trace!("rewriting: {val:?} needs a stack slot"); + let ty = func.dfg.value_type(val); + let size = ty.bytes(); + match self.free_stack_slots[SlotSize::unwrap_new(size)].pop() { + Some(slot) => { + log::trace!("rewriting: reusing free stack slot {slot:?} for {val:?}"); + slot + } + None => { + debug_assert!(size.is_power_of_two()); + let log2_size = size.ilog2(); + let slot = func.create_sized_stack_slot(ir::StackSlotData::new( + ir::StackSlotKind::ExplicitSlot, + size, + log2_size.try_into().unwrap(), + )); + log::trace!("rewriting: created new stack slot {slot:?} for {val:?}"); + slot + } + } + }) + } + + fn free_stack_slot(&mut self, size: SlotSize, slot: ir::StackSlot) { + log::trace!("rewriting: returning {slot:?} to the free list"); + self.free_stack_slots[size].push(slot); + } +} + +/// A pass to rewrite a function's instructions to spill and reload values that +/// are live across safepoints. +/// +/// A single `SafepointSpiller` instance may be reused to rewrite many +/// functions, amortizing the cost of its internal allocations and avoiding +/// repeated `malloc` and `free` calls. +#[derive(Default)] +pub(super) struct SafepointSpiller { + liveness: LivenessAnalysis, + stack_slots: StackSlots, +} + +impl SafepointSpiller { + /// Clear and reset all internal state such that this pass is ready to run + /// on a new function. + pub fn clear(&mut self) { + let SafepointSpiller { + liveness, + stack_slots, + } = self; + liveness.clear(); + stack_slots.clear(); + } + + /// Identify needs-stack-map values that are live across safepoints, and + /// rewrite the function's instructions to spill and reload them as + /// necessary. + pub fn run(&mut self, func: &mut Function, stack_map_values: &EntitySet) { + log::trace!( + "values needing inclusion in stack maps: {:?}", + stack_map_values + ); + log::trace!( + "before inserting safepoint spills and reloads:\n{}", + func.display() + ); + + self.clear(); + self.liveness.run(func, stack_map_values); + self.rewrite(func); + + log::trace!( + "after inserting safepoint spills and reloads:\n{}", + func.display() + ); + } + + /// Spill this value to a stack slot if it has been declared that it must be + /// included in stack maps and is live across any safepoints. + /// + /// The given cursor must point just after this value's definition. + fn rewrite_def(&mut self, pos: &mut FuncCursor<'_>, val: ir::Value) { + if let Some(slot) = self.stack_slots.get(val) { + let i = pos.ins().stack_store(val, slot, 0); + log::trace!( + "rewriting: spilling {val:?} to {slot:?}: {}", + pos.func.dfg.display_inst(i) + ); + + // Now that we've defined this value, there cannot be any more uses + // of it, and therefore this stack slot is now available for reuse. + let ty = pos.func.dfg.value_type(val); + let size = SlotSize::try_from(ty).unwrap(); + self.stack_slots.free_stack_slot(size, slot); + } + } + + /// Add a stack map entry for each needs-stack-map value that is live across + /// the given safepoint instruction. + /// + /// This will additionally assign stack slots to needs-stack-map values, if + /// no such assignment has already been made. + fn rewrite_safepoint(&mut self, func: &mut Function, inst: ir::Inst) { + log::trace!( + "rewriting: found safepoint: {inst:?}: {}", + func.dfg.display_inst(inst) + ); + + let live = self + .liveness + .safepoints + .get(&inst) + .expect("should only call `rewrite_safepoint` on safepoint instructions"); + + for val in live { + // Get or create the stack slot for this live needs-stack-map value. + let slot = self.stack_slots.get_or_create_stack_slot(func, *val); + + log::trace!( + "rewriting: adding stack map entry for {val:?} at {slot:?}: {}", + func.dfg.display_inst(inst) + ); + let ty = func.dfg.value_type(*val); + func.dfg.append_user_stack_map_entry( + inst, + ir::UserStackMapEntry { + ty, + slot, + offset: 0, + }, + ); + } + } + + /// If `val` is a needs-stack-map value that has been spilled to a stack + /// slot, then rewrite `val` to be a load from its associated stack + /// slot. + /// + /// Returns `true` if `val` was rewritten, `false` if not. + /// + /// The given cursor must point just before the use of the value that we are + /// replacing. + fn rewrite_use(&mut self, pos: &mut FuncCursor<'_>, val: &mut ir::Value) -> bool { + if !self.liveness.live_across_any_safepoint.contains(*val) { + return false; + } + + let old_val = *val; + log::trace!("rewriting: found use of {old_val:?}"); + + let ty = pos.func.dfg.value_type(*val); + let slot = self.stack_slots.get_or_create_stack_slot(pos.func, *val); + *val = pos.ins().stack_load(ty, slot, 0); + + log::trace!( + "rewriting: reloading {old_val:?}: {}", + pos.func + .dfg + .display_inst(pos.func.dfg.value_def(*val).unwrap_inst()) + ); + + true + } + + /// Rewrite the function's instructions to spill and reload values that are + /// live across safepoints: + /// + /// 1. Definitions of needs-stack-map values that are live across some + /// safepoint need to be spilled to their assigned stack slot. + /// + /// 2. Instructions that are themselves safepoints must have stack map + /// entries added for the needs-stack-map values that are live across + /// them. + /// + /// 3. Uses of needs-stack-map values that have been spilled to a stack slot + /// need to be replaced with reloads from the slot. + fn rewrite(&mut self, func: &mut Function) { + // Shared temporary storage for operand and result lists. + let mut vals: SmallVec<[_; 8]> = Default::default(); + + // Rewrite the function's instructions in post-order. This ensures that + // we rewrite uses before defs, and therefore once we see a def we know + // its stack slot will never be used for that value again. Therefore, + // the slot can be reappropriated for a new needs-stack-map value with a + // non-overlapping live range. See `rewrite_def` and `free_stack_slots` + // for more details. + for block_index in 0..self.liveness.post_order.len() { + let block = self.liveness.post_order[block_index]; + log::trace!("rewriting: processing {block:?}"); + + let mut option_inst = func.layout.last_inst(block); + while let Some(inst) = option_inst { + // If this instruction defines a needs-stack-map value that is + // live across a safepoint, then spill the value to its stack + // slot. + let mut pos = FuncCursor::new(func).after_inst(inst); + vals.extend_from_slice(pos.func.dfg.inst_results(inst)); + for val in vals.drain(..) { + self.rewrite_def(&mut pos, val); + } + + // If this instruction is a safepoint, then we must add stack + // map entries for the needs-stack-map values that are live + // across it. + if self.liveness.safepoints.contains_key(&inst) { + self.rewrite_safepoint(func, inst); + } + + // Replace all uses of needs-stack-map values with loads from + // the value's associated stack slot. + let mut pos = FuncCursor::new(func).at_inst(inst); + vals.extend(pos.func.dfg.inst_values(inst)); + let mut replaced_any = false; + for val in &mut vals { + replaced_any |= self.rewrite_use(&mut pos, val); + } + if replaced_any { + pos.func.dfg.overwrite_inst_values(inst, vals.drain(..)); + log::trace!( + "rewriting: updated {inst:?} operands with reloaded values: {}", + pos.func.dfg.display_inst(inst) + ); + } else { + vals.clear(); + } + + option_inst = func.layout.prev_inst(inst); + } + + // Spill needs-stack-map values defined by block parameters to their + // associated stack slots. + let mut pos = FuncCursor::new(func).at_position(CursorPosition::Before(block)); + pos.next_inst(); // Advance to the first instruction in the block. + vals.clear(); + vals.extend_from_slice(pos.func.dfg.block_params(block)); + for val in vals.drain(..) { + self.rewrite_def(&mut pos, val); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + use cranelift_codegen::isa::CallConv; + + #[test] + fn needs_stack_map_and_loop() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Here the value `v1` is technically not live but our single-pass liveness + // analysis treats every branch argument to a block as live to avoid + // needing to do a fixed-point loop. + // + // block0(v0, v1): + // call $foo(v0) + // jump block0(v0, v1) + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + let a = builder.func.dfg.block_params(block0)[0]; + let b = builder.func.dfg.block_params(block0)[1]; + builder.declare_value_needs_stack_map(a); + builder.declare_value_needs_stack_map(b); + builder.switch_to_block(block0); + builder.ins().call(func_ref, &[a]); + builder.ins().jump(block0, &[a, b]); + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32, i32) system_v { + ss0 = explicit_slot 4, align = 4 + ss1 = explicit_slot 4, align = 4 + sig0 = (i32) system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32, v1: i32): + stack_store v0, ss0 + stack_store v1, ss1 + v4 = stack_load.i32 ss0 + call fn0(v4), stack_map=[i32 @ ss0+0, i32 @ ss1+0] + v2 = stack_load.i32 ss0 + v3 = stack_load.i32 ss1 + jump block0(v2, v3) +} + "# + ); + } + + #[test] + fn needs_stack_map_simple() { + let _ = env_logger::try_init(); + + let sig = Signature::new(CallConv::SystemV); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // At each `call` we are losing one more value as no longer live, so + // each stack map should be one smaller than the last. `v3` is never + // live across a safepoint, so should never appear in a stack map. Note + // that a value that is an argument to the call, but is not live after + // the call, should not appear in the stack map. This is why `v0` + // appears in the first call's stack map, but not the second call's + // stack map. + // + // block0: + // v0 = needs stack map + // v1 = needs stack map + // v2 = needs stack map + // v3 = needs stack map + // call $foo(v3) + // call $foo(v0) + // call $foo(v1) + // call $foo(v2) + // return + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + let v0 = builder.ins().iconst(ir::types::I32, 0); + builder.declare_value_needs_stack_map(v0); + let v1 = builder.ins().iconst(ir::types::I32, 1); + builder.declare_value_needs_stack_map(v1); + let v2 = builder.ins().iconst(ir::types::I32, 2); + builder.declare_value_needs_stack_map(v2); + let v3 = builder.ins().iconst(ir::types::I32, 3); + builder.declare_value_needs_stack_map(v3); + builder.ins().call(func_ref, &[v3]); + builder.ins().call(func_ref, &[v0]); + builder.ins().call(func_ref, &[v1]); + builder.ins().call(func_ref, &[v2]); + builder.ins().return_(&[]); + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample() system_v { + ss0 = explicit_slot 4, align = 4 + ss1 = explicit_slot 4, align = 4 + ss2 = explicit_slot 4, align = 4 + sig0 = (i32) system_v + fn0 = colocated u0:0 sig0 + +block0: + v0 = iconst.i32 0 + stack_store v0, ss2 ; v0 = 0 + v1 = iconst.i32 1 + stack_store v1, ss1 ; v1 = 1 + v2 = iconst.i32 2 + stack_store v2, ss0 ; v2 = 2 + v3 = iconst.i32 3 + call fn0(v3), stack_map=[i32 @ ss2+0, i32 @ ss1+0, i32 @ ss0+0] ; v3 = 3 + v6 = stack_load.i32 ss2 + call fn0(v6), stack_map=[i32 @ ss1+0, i32 @ ss0+0] + v5 = stack_load.i32 ss1 + call fn0(v5), stack_map=[i32 @ ss0+0] + v4 = stack_load.i32 ss0 + call fn0(v4) + return +} + "# + ); + } + + #[test] + fn needs_stack_map_and_post_order_early_return() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Here we rely on the post-order to make sure that we never visit block + // 4 and add `v1` to our live set, then visit block 2 and add `v1` to + // its stack map even though `v1` is not in scope. Thanksfully, that + // sequence is impossible because it would be an invalid post-order + // traversal. The only valid post-order traversals are [3, 1, 2, 0] and + // [2, 3, 1, 0]. + // + // block0(v0): + // brif v0, block1, block2 + // + // block1: + // + // v1 = get some gc ref + // jump block3 + // + // block2: + // call $needs_safepoint_accidentally + // return + // + // block3: + // stuff keeping v1 live + // return + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + let v1 = builder.ins().iconst(ir::types::I64, 0x12345678); + builder.declare_value_needs_stack_map(v1); + builder.ins().jump(block3, &[]); + + builder.switch_to_block(block2); + builder.ins().call(func_ref, &[]); + builder.ins().return_(&[]); + + builder.switch_to_block(block3); + // NB: Our simplistic liveness analysis conservatively treats any use of + // a value as keeping it live, regardless if the use has side effects or + // is otherwise itself live, so an `iadd_imm` suffices to keep `v1` live + // here. + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) system_v { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + brif v0, block1, block2 + +block1: + v1 = iconst.i64 0x1234_5678 + jump block3 + +block2: + call fn0() + return + +block3: + v2 = iadd_imm.i64 v1, 0 ; v1 = 0x1234_5678 + return +} + "# + ); + } + + #[test] + fn needs_stack_map_conditional_branches_and_liveness() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // We should not have a stack map entry for `v1` in block 1 because it + // is not live across the call. + // + // block0(v0): + // v1 = needs stack map + // brif v0, block1, block2 + // + // block1: + // call $foo() + // return + // + // block2: + // keep v1 alive + // return + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let v1 = builder.ins().iconst(ir::types::I64, 0x12345678); + builder.declare_value_needs_stack_map(v1); + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + builder.ins().call(func_ref, &[]); + builder.ins().return_(&[]); + + builder.switch_to_block(block2); + // NB: Our simplistic liveness analysis conservatively treats any use of + // a value as keeping it live, regardless if the use has side effects or + // is otherwise itself live, so an `iadd_imm` suffices to keep `v1` live + // here. + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) system_v { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + v1 = iconst.i64 0x1234_5678 + brif v0, block1, block2 + +block1: + call fn0() + return + +block2: + v2 = iadd_imm.i64 v1, 0 ; v1 = 0x1234_5678 + return +} + "# + ); + + // Now do the same test but with block 1 and 2 swapped so that we + // exercise what we are trying to exercise, regardless of which + // post-order traversal we happen to take. + func.clear(); + fn_ctx.clear(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + func.signature = sig; + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let v1 = builder.ins().iconst(ir::types::I64, 0x12345678); + builder.declare_value_needs_stack_map(v1); + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.switch_to_block(block2); + builder.ins().call(func_ref, &[]); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function u0:0(i32) system_v { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + v1 = iconst.i64 0x1234_5678 + brif v0, block1, block2 + +block1: + v2 = iadd_imm.i64 v1, 0 ; v1 = 0x1234_5678 + return + +block2: + call fn0() + return +} + "# + ); + } + + #[test] + fn needs_stack_map_and_tail_calls() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Depending on which post-order traversal we take, we might consider + // `v1` live inside `block1`. But nothing is live after a tail call so + // we shouldn't spill `v1` either way here. + // + // block0(v0): + // v1 = needs stack map + // brif v0, block1, block2 + // + // block1: + // return_call $foo() + // + // block2: + // keep v1 alive + // return + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let v1 = builder.ins().iconst(ir::types::I64, 0x12345678); + builder.declare_value_needs_stack_map(v1); + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + builder.ins().return_call(func_ref, &[]); + + builder.switch_to_block(block2); + // NB: Our simplistic liveness analysis conservatively treats any use of + // a value as keeping it live, regardless if the use has side effects or + // is otherwise itself live, so an `iadd_imm` suffices to keep `v1` live + // here. + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) system_v { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + v1 = iconst.i64 0x1234_5678 + brif v0, block1, block2 + +block1: + return_call fn0() + +block2: + v2 = iadd_imm.i64 v1, 0 ; v1 = 0x1234_5678 + return +} + "# + ); + + // Do the same test but with block 1 and 2 swapped so that we exercise + // what we are trying to exercise, regardless of which post-order + // traversal we happen to take. + func.clear(); + fn_ctx.clear(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + func.signature = sig; + + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let v1 = builder.ins().iconst(ir::types::I64, 0x12345678); + builder.declare_value_needs_stack_map(v1); + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.switch_to_block(block2); + builder.ins().return_call(func_ref, &[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function u0:0(i32) system_v { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + v1 = iconst.i64 0x1234_5678 + brif v0, block1, block2 + +block1: + v2 = iadd_imm.i64 v1, 0 ; v1 = 0x1234_5678 + return + +block2: + return_call fn0() +} + "# + ); + } + + #[test] + fn needs_stack_map_and_cfg_diamond() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Create an if/else CFG diamond that and check that various things get + // spilled as needed. + // + // block0(v0): + // brif v0, block1, block2 + // + // block1: + // v1 = needs stack map + // v2 = needs stack map + // call $foo() + // jump block3(v1, v2) + // + // block2: + // v3 = needs stack map + // v4 = needs stack map + // call $foo() + // jump block3(v3, v3) ;; Note: v4 is not live + // + // block3(v5, v6): + // call $foo() + // keep v5 alive, but not v6 + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + let v1 = builder.ins().iconst(ir::types::I64, 1); + builder.declare_value_needs_stack_map(v1); + let v2 = builder.ins().iconst(ir::types::I64, 2); + builder.declare_value_needs_stack_map(v2); + builder.ins().call(func_ref, &[]); + builder.ins().jump(block3, &[v1, v2]); + + builder.switch_to_block(block2); + let v3 = builder.ins().iconst(ir::types::I64, 3); + builder.declare_value_needs_stack_map(v3); + let v4 = builder.ins().iconst(ir::types::I64, 4); + builder.declare_value_needs_stack_map(v4); + builder.ins().call(func_ref, &[]); + builder.ins().jump(block3, &[v3, v3]); + + builder.switch_to_block(block3); + builder.append_block_param(block3, ir::types::I64); + builder.append_block_param(block3, ir::types::I64); + builder.ins().call(func_ref, &[]); + // NB: Our simplistic liveness analysis conservatively treats any use of + // a value as keeping it live, regardless if the use has side effects or + // is otherwise itself live, so an `iadd_imm` suffices to keep `v1` live + // here. + builder.ins().iadd_imm(v1, 0); + builder.ins().return_(&[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) system_v { + ss0 = explicit_slot 8, align = 8 + ss1 = explicit_slot 8, align = 8 + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + brif v0, block1, block2 + +block1: + v1 = iconst.i64 1 + stack_store v1, ss0 ; v1 = 1 + v2 = iconst.i64 2 + stack_store v2, ss1 ; v2 = 2 + call fn0(), stack_map=[i64 @ ss0+0, i64 @ ss1+0] + v9 = stack_load.i64 ss0 + v10 = stack_load.i64 ss1 + jump block3(v9, v10) + +block2: + v3 = iconst.i64 3 + stack_store v3, ss0 ; v3 = 3 + v4 = iconst.i64 4 + call fn0(), stack_map=[i64 @ ss0+0, i64 @ ss0+0] + v11 = stack_load.i64 ss0 + v12 = stack_load.i64 ss0 + jump block3(v11, v12) + +block3(v5: i64, v6: i64): + call fn0(), stack_map=[i64 @ ss0+0] + v8 = stack_load.i64 ss0 + v7 = iadd_imm v8, 0 + return +} + "# + ); + } + + #[test] + fn needs_stack_map_and_heterogeneous_types() { + let _ = env_logger::try_init(); + + let mut sig = Signature::new(CallConv::SystemV); + for ty in [ + ir::types::I8, + ir::types::I16, + ir::types::I32, + ir::types::I64, + ir::types::I128, + ir::types::F32, + ir::types::F64, + ir::types::I8X16, + ir::types::I16X8, + ] { + sig.params.push(AbiParam::new(ty)); + sig.returns.push(AbiParam::new(ty)); + } + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Test that we support stack maps of heterogeneous types and properly + // coalesce types into stack slots based on their size. + // + // block0(v0, v1, v2, v3, v4, v5, v6, v7, v8): + // call $foo() + // return v0, v1, v2, v3, v4, v5, v6, v7, v8 + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let params = builder.func.dfg.block_params(block0).to_vec(); + for val in ¶ms { + builder.declare_value_needs_stack_map(*val); + } + builder.ins().call(func_ref, &[]); + builder.ins().return_(¶ms); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i8, i16, i32, i64, i128, f32, f64, i8x16, i16x8) -> i8, i16, i32, i64, i128, f32, f64, i8x16, i16x8 system_v { + ss0 = explicit_slot 1 + ss1 = explicit_slot 2, align = 2 + ss2 = explicit_slot 4, align = 4 + ss3 = explicit_slot 8, align = 8 + ss4 = explicit_slot 16, align = 16 + ss5 = explicit_slot 4, align = 4 + ss6 = explicit_slot 8, align = 8 + ss7 = explicit_slot 16, align = 16 + ss8 = explicit_slot 16, align = 16 + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i8, v1: i16, v2: i32, v3: i64, v4: i128, v5: f32, v6: f64, v7: i8x16, v8: i16x8): + stack_store v0, ss0 + stack_store v1, ss1 + stack_store v2, ss2 + stack_store v3, ss3 + stack_store v4, ss4 + stack_store v5, ss5 + stack_store v6, ss6 + stack_store v7, ss7 + stack_store v8, ss8 + call fn0(), stack_map=[i8 @ ss0+0, i16 @ ss1+0, i32 @ ss2+0, i64 @ ss3+0, i128 @ ss4+0, f32 @ ss5+0, f64 @ ss6+0, i8x16 @ ss7+0, i16x8 @ ss8+0] + v9 = stack_load.i8 ss0 + v10 = stack_load.i16 ss1 + v11 = stack_load.i32 ss2 + v12 = stack_load.i64 ss3 + v13 = stack_load.i128 ss4 + v14 = stack_load.f32 ss5 + v15 = stack_load.f64 ss6 + v16 = stack_load.i8x16 ss7 + v17 = stack_load.i16x8 ss8 + return v9, v10, v11, v12, v13, v14, v15, v16, v17 +} + "# + ); + } + + #[test] + fn series_of_non_overlapping_live_ranges_needs_stack_map() { + let sig = Signature::new(CallConv::SystemV); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let foo_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 1, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let consume_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Create a series of needs-stack-map values that do not have + // overlapping live ranges, but which do appear in stack maps for calls + // to `$foo`: + // + // block0: + // v0 = needs stack map + // call $foo() + // call consume(v0) + // v1 = needs stack map + // call $foo() + // call consume(v1) + // v2 = needs stack map + // call $foo() + // call consume(v2) + // v3 = needs stack map + // call $foo() + // call consume(v3) + // return + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + let v0 = builder.ins().iconst(ir::types::I32, 0); + builder.declare_value_needs_stack_map(v0); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(consume_func_ref, &[v0]); + let v1 = builder.ins().iconst(ir::types::I32, 1); + builder.declare_value_needs_stack_map(v1); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(consume_func_ref, &[v1]); + let v2 = builder.ins().iconst(ir::types::I32, 2); + builder.declare_value_needs_stack_map(v2); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(consume_func_ref, &[v2]); + let v3 = builder.ins().iconst(ir::types::I32, 3); + builder.declare_value_needs_stack_map(v3); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(consume_func_ref, &[v3]); + builder.ins().return_(&[]); + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample() system_v { + ss0 = explicit_slot 4, align = 4 + sig0 = () system_v + sig1 = (i32) system_v + fn0 = colocated u0:0 sig0 + fn1 = colocated u0:1 sig1 + +block0: + v0 = iconst.i32 0 + stack_store v0, ss0 ; v0 = 0 + call fn0(), stack_map=[i32 @ ss0+0] + v7 = stack_load.i32 ss0 + call fn1(v7) + v1 = iconst.i32 1 + stack_store v1, ss0 ; v1 = 1 + call fn0(), stack_map=[i32 @ ss0+0] + v6 = stack_load.i32 ss0 + call fn1(v6) + v2 = iconst.i32 2 + stack_store v2, ss0 ; v2 = 2 + call fn0(), stack_map=[i32 @ ss0+0] + v5 = stack_load.i32 ss0 + call fn1(v5) + v3 = iconst.i32 3 + stack_store v3, ss0 ; v3 = 3 + call fn0(), stack_map=[i32 @ ss0+0] + v4 = stack_load.i32 ss0 + call fn1(v4) + return +} + "# + ); + } + + #[test] + fn vars_block_params_and_needs_stack_map() { + let _ = env_logger::try_init(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.returns.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Use a variable, create a control flow diamond so that the variable + // forces a block parameter on the control join point, and make sure + // that we get stack maps for all the appropriate uses of the variable + // in all blocks, as well as that we are reusing stack slots for each of + // the values. + // + // block0: + // x := needs stack map + // call $foo(x) + // br_if v0, block1, block2 + // + // + // block1: block2: + // call $foo(x) call $foo(x) + // call $foo(x) call $foo(x) + // x := new needs stack map x := new needs stack map + // call $foo(x) call $foo(x) + // jump block3 jump block3 + // + // + // block3: + // call $foo(x) + // return x + + let x = Variable::from_u32(0); + builder.declare_var(x, ir::types::I32); + builder.declare_var_needs_stack_map(x); + + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let val = builder.ins().iconst(ir::types::I32, 42); + builder.def_var(x, val); + { + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + } + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + { + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + builder.ins().call(func_ref, &[x]); + } + let val = builder.ins().iconst(ir::types::I32, 36); + builder.def_var(x, val); + { + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + } + builder.ins().jump(block3, &[]); + + builder.switch_to_block(block2); + { + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + builder.ins().call(func_ref, &[x]); + } + let val = builder.ins().iconst(ir::types::I32, 36); + builder.def_var(x, val); + { + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + } + builder.ins().jump(block3, &[]); + + builder.switch_to_block(block3); + let x = builder.use_var(x); + builder.ins().call(func_ref, &[x]); + builder.ins().return_(&[x]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) -> i32 system_v { + ss0 = explicit_slot 4, align = 4 + ss1 = explicit_slot 4, align = 4 + sig0 = (i32) system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + v1 = iconst.i32 42 + v2 -> v1 + v4 -> v1 + stack_store v1, ss0 ; v1 = 42 + v13 = stack_load.i32 ss0 + call fn0(v13), stack_map=[i32 @ ss0+0] + brif v0, block1, block2 + +block1: + call fn0(v2), stack_map=[i32 @ ss0+0] ; v2 = 42 + call fn0(v2) ; v2 = 42 + v3 = iconst.i32 36 + stack_store v3, ss0 ; v3 = 36 + v10 = stack_load.i32 ss0 + call fn0(v10), stack_map=[i32 @ ss0+0] + v9 = stack_load.i32 ss0 + jump block3(v9) + +block2: + call fn0(v4), stack_map=[i32 @ ss0+0] ; v4 = 42 + call fn0(v4) ; v4 = 42 + v5 = iconst.i32 36 + stack_store v5, ss1 ; v5 = 36 + v12 = stack_load.i32 ss1 + call fn0(v12), stack_map=[i32 @ ss1+0] + v11 = stack_load.i32 ss1 + jump block3(v11) + +block3(v6: i32): + stack_store v6, ss0 + v8 = stack_load.i32 ss0 + call fn0(v8), stack_map=[i32 @ ss0+0] + v7 = stack_load.i32 ss0 + return v7 +} + "# + ); + } + + #[test] + fn var_needs_stack_map() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params + .push(AbiParam::new(cranelift_codegen::ir::types::I32)); + sig.returns + .push(AbiParam::new(cranelift_codegen::ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let var = Variable::from_u32(0); + builder.declare_var(var, cranelift_codegen::ir::types::I32); + builder.declare_var_needs_stack_map(var); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let arg = builder.func.dfg.block_params(block0)[0]; + builder.def_var(var, arg); + + builder.ins().call(func_ref, &[]); + + let val = builder.use_var(var); + builder.ins().return_(&[val]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) -> i32 system_v { + ss0 = explicit_slot 4, align = 4 + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + stack_store v0, ss0 + call fn0(), stack_map=[i32 @ ss0+0] + v1 = stack_load.i32 ss0 + return v1 +} + "# + ); + } + + #[test] + fn first_inst_defines_needs_stack_map() { + let mut sig = Signature::new(CallConv::SystemV); + sig.params + .push(AbiParam::new(cranelift_codegen::ir::types::I32)); + sig.returns + .push(AbiParam::new(cranelift_codegen::ir::types::I32)); + sig.returns + .push(AbiParam::new(cranelift_codegen::ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Regression test found via fuzzing in + // https://github.com/bytecodealliance/wasmtime/pull/8941 involving the + // combination of cursor positions after we have block parameters that + // need inclusion in stack maps and when the first instruction in a + // block defines a value that needs inclusion in stack maps. + // + // block0(v0: i32): + // v1 = iconst.i32 42 + // call $foo() + // return v0, v1 + + let block0 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + builder.switch_to_block(block0); + + let arg = builder.func.dfg.block_params(block0)[0]; + builder.declare_value_needs_stack_map(arg); + + let val = builder.ins().iconst(ir::types::I32, 42); + builder.declare_value_needs_stack_map(val); + + builder.ins().call(func_ref, &[]); + + builder.ins().return_(&[arg, val]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) -> i32, i32 system_v { + ss0 = explicit_slot 4, align = 4 + ss1 = explicit_slot 4, align = 4 + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i32): + stack_store v0, ss0 + v1 = iconst.i32 42 + stack_store v1, ss1 ; v1 = 42 + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0] + v2 = stack_load.i32 ss0 + v3 = stack_load.i32 ss1 + return v2, v3 +} + "# + ); + } + + #[test] + fn needs_stack_map_and_loops_and_partially_live_values() { + let _ = env_logger::try_init(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = + Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig.clone()); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let foo_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 1, + index: 1, + }); + let signature = builder.func.import_signature(sig); + let bar_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Test that we support stack maps in loops and that we properly handle + // value that are only live for part of the loop body on each iteration, + // but are live across the whole loop because they will be used again + // the next iteration. Note that `v0` below, which is a GC value, is not + // live *within a single iteration of the loop* after the call to `bar`, + // but is actually live across the whole loop because it will be used + // again in the *next iteration of the loop*: + // + // block0(v0: i32): + // jump block1 + // + // block1: + // call $foo() + // call $bar(v0) + // call $foo() + // jump block1 + let block0 = builder.create_block(); + let block1 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + builder.ins().jump(block1, &[]); + + builder.switch_to_block(block1); + let v0 = builder.func.dfg.block_params(block0)[0]; + builder.declare_value_needs_stack_map(v0); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v0]); + builder.ins().call(foo_func_ref, &[]); + builder.ins().jump(block1, &[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32) system_v { + ss0 = explicit_slot 4, align = 4 + sig0 = () system_v + sig1 = (i32) system_v + fn0 = colocated u0:0 sig0 + fn1 = colocated u1:1 sig1 + +block0(v0: i32): + stack_store v0, ss0 + jump block1 + +block1: + call fn0(), stack_map=[i32 @ ss0+0] + v1 = stack_load.i32 ss0 + call fn1(v1), stack_map=[i32 @ ss0+0] + call fn0(), stack_map=[i32 @ ss0+0] + jump block1 +} + "#, + ); + } + + #[test] + fn needs_stack_map_and_irreducible_loops() { + let _ = env_logger::try_init(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let foo_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 1, + index: 1, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let bar_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Test an irreducible loop with multiple entry points, both block1 and + // block2, in this case: + // + // block0(v0: i32, v1: i32): + // brif v0, block1, block2 + // + // block1: + // jump block3 + // + // block2: + // jump block4 + // + // block3: + // call $foo() + // call $bar(v1) + // call $foo() + // jump block2 + // + // block4: + // call $foo() + // call $bar(v1) + // call $foo() + // jump block1 + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + let block4 = builder.create_block(); + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + let v0 = builder.func.dfg.block_params(block0)[0]; + let v1 = builder.func.dfg.block_params(block0)[1]; + builder.declare_value_needs_stack_map(v1); + builder.ins().brif(v0, block1, &[], block2, &[]); + + builder.switch_to_block(block1); + builder.ins().jump(block3, &[]); + + builder.switch_to_block(block2); + builder.ins().jump(block4, &[]); + + builder.switch_to_block(block3); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v1]); + builder.ins().call(foo_func_ref, &[]); + builder.ins().jump(block2, &[]); + + builder.switch_to_block(block4); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v1]); + builder.ins().call(foo_func_ref, &[]); + builder.ins().jump(block1, &[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32, i32) system_v { + ss0 = explicit_slot 4, align = 4 + sig0 = () system_v + sig1 = (i32) system_v + fn0 = colocated u0:0 sig0 + fn1 = colocated u1:1 sig1 + +block0(v0: i32, v1: i32): + stack_store v1, ss0 + brif v0, block1, block2 + +block1: + jump block3 + +block2: + jump block4 + +block3: + call fn0(), stack_map=[i32 @ ss0+0] + v3 = stack_load.i32 ss0 + call fn1(v3), stack_map=[i32 @ ss0+0] + call fn0(), stack_map=[i32 @ ss0+0] + jump block2 + +block4: + call fn0(), stack_map=[i32 @ ss0+0] + v2 = stack_load.i32 ss0 + call fn1(v2), stack_map=[i32 @ ss0+0] + call fn0(), stack_map=[i32 @ ss0+0] + jump block1 +} + "#, + ); + } + + #[test] + fn needs_stack_map_and_back_edge_to_back_edge() { + let _ = env_logger::try_init(); + + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.params.push(AbiParam::new(ir::types::I32)); + sig.params.push(AbiParam::new(ir::types::I32)); + + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ir::UserFuncName::testcase("sample"), sig); + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 0, + index: 0, + }); + let signature = builder + .func + .import_signature(Signature::new(CallConv::SystemV)); + let foo_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + let name = builder + .func + .declare_imported_user_function(ir::UserExternalName { + namespace: 1, + index: 1, + }); + let mut sig = Signature::new(CallConv::SystemV); + sig.params.push(AbiParam::new(ir::types::I32)); + let signature = builder.func.import_signature(sig); + let bar_func_ref = builder.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(name), + signature, + colocated: true, + }); + + // Test that we detect the `block1 -> block2 -> block3 -> block2 -> + // block1` loop in our liveness analysis and keep `v{0,1,2}` live across + // the whole loop body. + // + // block0(v0, v1, v2, v3): + // jump block1(v3) + // + // block1(v4): + // call foo_func_ref() + // call bar_func_ref(v0) + // call foo_func_ref() + // jump block2 + // + // block2: + // call foo_func_ref() + // call bar_func_ref(v1) + // call foo_func_ref() + // v5 = iadd_imm v4, -1 + // brif v4, block1(v5), block3 + // + // block3: + // call foo_func_ref() + // call bar_func_ref(v2) + // call foo_func_ref() + // jump block2 + + let block0 = builder.create_block(); + let block1 = builder.create_block(); + let block2 = builder.create_block(); + let block3 = builder.create_block(); + + builder.append_block_params_for_function_params(block0); + + builder.switch_to_block(block0); + + let v0 = builder.func.dfg.block_params(block0)[0]; + builder.declare_value_needs_stack_map(v0); + let v1 = builder.func.dfg.block_params(block0)[1]; + builder.declare_value_needs_stack_map(v1); + let v2 = builder.func.dfg.block_params(block0)[2]; + builder.declare_value_needs_stack_map(v2); + let v3 = builder.func.dfg.block_params(block0)[3]; + + builder.ins().jump(block1, &[v3]); + + builder.switch_to_block(block1); + let v4 = builder.append_block_param(block1, ir::types::I32); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v0]); + builder.ins().call(foo_func_ref, &[]); + builder.ins().jump(block2, &[]); + + builder.switch_to_block(block2); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v1]); + builder.ins().call(foo_func_ref, &[]); + let v5 = builder.ins().iadd_imm(v4, -1); + builder.ins().brif(v4, block1, &[v5], block3, &[]); + + builder.switch_to_block(block3); + builder.ins().call(foo_func_ref, &[]); + builder.ins().call(bar_func_ref, &[v2]); + builder.ins().call(foo_func_ref, &[]); + builder.ins().jump(block2, &[]); + + builder.seal_all_blocks(); + builder.finalize(); + + assert_eq_output!( + func.display().to_string(), + r#" +function %sample(i32, i32, i32, i32) system_v { + ss0 = explicit_slot 4, align = 4 + ss1 = explicit_slot 4, align = 4 + ss2 = explicit_slot 4, align = 4 + sig0 = () system_v + sig1 = (i32) system_v + fn0 = colocated u0:0 sig0 + fn1 = colocated u1:1 sig1 + +block0(v0: i32, v1: i32, v2: i32, v3: i32): + stack_store v0, ss0 + stack_store v1, ss1 + stack_store v2, ss2 + jump block1(v3) + +block1(v4: i32): + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + v8 = stack_load.i32 ss0 + call fn1(v8), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + jump block2 + +block2: + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + v7 = stack_load.i32 ss1 + call fn1(v7), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + v5 = iadd_imm.i32 v4, -1 + brif.i32 v4, block1(v5), block3 + +block3: + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + v6 = stack_load.i32 ss2 + call fn1(v6), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + call fn0(), stack_map=[i32 @ ss0+0, i32 @ ss1+0, i32 @ ss2+0] + jump block2 +} + "#, + ); + } +} diff --git a/deps/crates/vendor/cranelift-frontend/src/lib.rs b/deps/crates/vendor/cranelift-frontend/src/lib.rs new file mode 100644 index 00000000000000..7a9c8091991028 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/lib.rs @@ -0,0 +1,210 @@ +//! Cranelift IR builder library. +//! +//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions +//! corresponding to your source program written in another language. +//! +//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and +//! pass it as an argument to a [`FunctionBuilder`]. +//! +//! # Mutable variables and Cranelift IR values +//! +//! The most interesting feature of this API is that it provides a single way to deal with all your +//! variable problems. Indeed, the [`FunctionBuilder`] struct has a +//! type `Variable` that should be an index of your source language variables. Then, through +//! calling the functions +//! [`declare_var`](FunctionBuilder::declare_var), [`def_var`](FunctionBuilder::def_var) and +//! [`use_var`](FunctionBuilder::use_var), the [`FunctionBuilder`] will create for you all the +//! Cranelift IR values corresponding to your variables. +//! +//! This API has been designed to help you translate your mutable variables into +//! [`SSA`](https://en.wikipedia.org/wiki/Static_single_assignment_form) form. +//! [`use_var`](FunctionBuilder::use_var) will return the Cranelift IR value +//! that corresponds to your mutable variable at a precise point in the program. However, if you know +//! beforehand that one of your variables is defined only once, for instance if it is the result +//! of an intermediate expression in an expression-based language, then you can translate it +//! directly by the Cranelift IR value returned by the instruction builder. Using the +//! [`use_var`](FunctionBuilder::use_var) API for such an immutable variable +//! would also work but with a slight additional overhead (the SSA algorithm does not know +//! beforehand if a variable is immutable or not). +//! +//! The moral is that you should use these three functions to handle all your mutable variables, +//! even those that are not present in the source code but artifacts of the translation. It is up +//! to you to keep a mapping between the mutable variables of your language and their [`Variable`] +//! index that is used by Cranelift. Caution: as the [`Variable`] is used by Cranelift to index an +//! array containing information about your mutable variables, when you create a new [`Variable`] +//! with `Variable::new(var_index)` you should make sure that `var_index` +//! is provided by a counter incremented by 1 each time you encounter a new mutable variable. +//! +//! # Example +//! +//! Here is a pseudo-program we want to transform into Cranelift IR: +//! +//! ```clif +//! function(x) { +//! x, y, z : i32 +//! block0: +//! y = 2; +//! z = x + y; +//! jump block1 +//! block1: +//! z = z + y; +//! brif y, block3, block2 +//! block2: +//! z = z - x; +//! return y +//! block3: +//! y = y - x +//! jump block1 +//! } +//! ``` +//! +//! Here is how you build the corresponding Cranelift IR function using [`FunctionBuilderContext`]: +//! +//! ```rust +//! use cranelift_codegen::entity::EntityRef; +//! use cranelift_codegen::ir::types::*; +//! use cranelift_codegen::ir::{AbiParam, UserFuncName, Function, InstBuilder, Signature}; +//! use cranelift_codegen::isa::CallConv; +//! use cranelift_codegen::settings; +//! use cranelift_codegen::verifier::verify_function; +//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +//! +//! let mut sig = Signature::new(CallConv::SystemV); +//! sig.returns.push(AbiParam::new(I32)); +//! sig.params.push(AbiParam::new(I32)); +//! let mut fn_builder_ctx = FunctionBuilderContext::new(); +//! let mut func = Function::with_name_signature(UserFuncName::user(0, 0), sig); +//! { +//! let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); +//! +//! let block0 = builder.create_block(); +//! let block1 = builder.create_block(); +//! let block2 = builder.create_block(); +//! let block3 = builder.create_block(); +//! let x = Variable::new(0); +//! let y = Variable::new(1); +//! let z = Variable::new(2); +//! builder.declare_var(x, I32); +//! builder.declare_var(y, I32); +//! builder.declare_var(z, I32); +//! builder.append_block_params_for_function_params(block0); +//! +//! builder.switch_to_block(block0); +//! builder.seal_block(block0); +//! { +//! let tmp = builder.block_params(block0)[0]; // the first function parameter +//! builder.def_var(x, tmp); +//! } +//! { +//! let tmp = builder.ins().iconst(I32, 2); +//! builder.def_var(y, tmp); +//! } +//! { +//! let arg1 = builder.use_var(x); +//! let arg2 = builder.use_var(y); +//! let tmp = builder.ins().iadd(arg1, arg2); +//! builder.def_var(z, tmp); +//! } +//! builder.ins().jump(block1, &[]); +//! +//! builder.switch_to_block(block1); +//! { +//! let arg1 = builder.use_var(y); +//! let arg2 = builder.use_var(z); +//! let tmp = builder.ins().iadd(arg1, arg2); +//! builder.def_var(z, tmp); +//! } +//! { +//! let arg = builder.use_var(y); +//! builder.ins().brif(arg, block3, &[], block2, &[]); +//! } +//! +//! builder.switch_to_block(block2); +//! builder.seal_block(block2); +//! { +//! let arg1 = builder.use_var(z); +//! let arg2 = builder.use_var(x); +//! let tmp = builder.ins().isub(arg1, arg2); +//! builder.def_var(z, tmp); +//! } +//! { +//! let arg = builder.use_var(y); +//! builder.ins().return_(&[arg]); +//! } +//! +//! builder.switch_to_block(block3); +//! builder.seal_block(block3); +//! +//! { +//! let arg1 = builder.use_var(y); +//! let arg2 = builder.use_var(x); +//! let tmp = builder.ins().isub(arg1, arg2); +//! builder.def_var(y, tmp); +//! } +//! builder.ins().jump(block1, &[]); +//! builder.seal_block(block1); +//! +//! builder.finalize(); +//! } +//! +//! let flags = settings::Flags::new(settings::builder()); +//! let res = verify_function(&func, &flags); +//! println!("{}", func.display()); +//! if let Err(errors) = res { +//! panic!("{}", errors); +//! } +//! ``` + +#![deny(missing_docs)] +#![no_std] + +extern crate alloc; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(not(feature = "std"))] +use hashbrown::{HashMap, HashSet}; +#[cfg(feature = "std")] +use std::collections::{HashMap, HashSet}; + +pub use crate::frontend::{FuncInstBuilder, FunctionBuilder, FunctionBuilderContext}; +pub use crate::switch::Switch; +pub use crate::variable::Variable; + +#[cfg(test)] +macro_rules! assert_eq_output { + ( $left:expr, $right:expr $(,)? ) => {{ + let left = $left; + let left = left.trim(); + + let right = $right; + let right = right.trim(); + + assert_eq!( + left, + right, + "assertion failed, output not equal:\n\ + \n\ + =========== Diff ===========\n\ + {}\n\ + =========== Left ===========\n\ + {left}\n\ + =========== Right ===========\n\ + {right}\n\ + ", + similar::TextDiff::from_lines(left, right) + .unified_diff() + .header("left", "right") + ) + }}; +} + +mod frontend; +mod ssa; +mod switch; +mod variable; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/deps/crates/vendor/cranelift-frontend/src/ssa.rs b/deps/crates/vendor/cranelift-frontend/src/ssa.rs new file mode 100644 index 00000000000000..694e467b0b2051 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/ssa.rs @@ -0,0 +1,1325 @@ +//! A SSA-building API that handles incomplete CFGs. +//! +//! The algorithm is based upon Braun M., Buchwald S., Hack S., Leißa R., Mallon C., +//! Zwinkau A. (2013) Simple and Efficient Construction of Static Single Assignment Form. +//! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013. +//! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg +//! +//! + +use crate::Variable; +use alloc::vec::Vec; +use core::mem; +use cranelift_codegen::cursor::{Cursor, FuncCursor}; +use cranelift_codegen::entity::{EntityList, EntitySet, ListPool, SecondaryMap}; +use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; +use cranelift_codegen::ir::types::{F32, F64, I128, I64}; +use cranelift_codegen::ir::{Block, Function, Inst, InstBuilder, Type, Value}; +use cranelift_codegen::packed_option::PackedOption; + +/// Structure containing the data relevant the construction of SSA for a given function. +/// +/// The parameter struct [`Variable`] corresponds to the way variables are represented in the +/// non-SSA language you're translating from. +/// +/// The SSA building relies on information about the variables used and defined. +/// +/// This SSA building module allows you to def and use variables on the fly while you are +/// constructing the CFG, no need for a separate SSA pass after the CFG is completed. +/// +/// A basic block is said _filled_ if all the instruction that it contains have been translated, +/// and it is said _sealed_ if all of its predecessors have been declared. Only filled predecessors +/// can be declared. +#[derive(Default)] +pub struct SSABuilder { + // TODO: Consider a sparse representation rather than SecondaryMap-of-SecondaryMap. + /// Records for every variable and for every relevant block, the last definition of + /// the variable in the block. + variables: SecondaryMap>>, + + /// Records the position of the basic blocks and the list of values used but not defined in the + /// block. + ssa_blocks: SecondaryMap, + + /// Call stack for use in the `use_var`/`predecessors_lookup` state machine. + calls: Vec, + /// Result stack for use in the `use_var`/`predecessors_lookup` state machine. + results: Vec, + + /// Side effects accumulated in the `use_var`/`predecessors_lookup` state machine. + side_effects: SideEffects, + + /// Reused storage for cycle-detection. + visited: EntitySet, + + /// Storage for pending variable definitions. + variable_pool: ListPool, + + /// Storage for predecessor definitions. + inst_pool: ListPool, +} + +/// Side effects of a `use_var` or a `seal_block` method call. +#[derive(Default)] +pub struct SideEffects { + /// When a variable is used but has never been defined before (this happens in the case of + /// unreachable code), a placeholder `iconst` or `fconst` value is added to the right `Block`. + /// This field signals if it is the case and return the `Block` to which the initialization has + /// been added. + pub instructions_added_to_blocks: Vec, +} + +impl SideEffects { + fn is_empty(&self) -> bool { + self.instructions_added_to_blocks.is_empty() + } +} + +#[derive(Clone)] +enum Sealed { + No { + // List of current Block arguments for which an earlier def has not been found yet. + undef_variables: EntityList, + }, + Yes, +} + +impl Default for Sealed { + fn default() -> Self { + Sealed::No { + undef_variables: EntityList::new(), + } + } +} + +#[derive(Clone, Default)] +struct SSABlockData { + // The predecessors of the Block with the block and branch instruction. + predecessors: EntityList, + // A block is sealed if all of its predecessors have been declared. + sealed: Sealed, + // If this block is sealed and it has exactly one predecessor, this is that predecessor. + single_predecessor: PackedOption, +} + +impl SSABuilder { + /// Clears a `SSABuilder` from all its data, letting it in a pristine state without + /// deallocating memory. + pub fn clear(&mut self) { + self.variables.clear(); + self.ssa_blocks.clear(); + self.variable_pool.clear(); + self.inst_pool.clear(); + debug_assert!(self.calls.is_empty()); + debug_assert!(self.results.is_empty()); + debug_assert!(self.side_effects.is_empty()); + } + + /// Tests whether an `SSABuilder` is in a cleared state. + pub fn is_empty(&self) -> bool { + self.variables.is_empty() + && self.ssa_blocks.is_empty() + && self.calls.is_empty() + && self.results.is_empty() + && self.side_effects.is_empty() + } +} + +/// States for the `use_var`/`predecessors_lookup` state machine. +enum Call { + UseVar(Inst), + FinishPredecessorsLookup(Value, Block), +} + +/// Emit instructions to produce a zero value in the given type. +fn emit_zero(ty: Type, mut cur: FuncCursor) -> Value { + if ty == I128 { + let zero = cur.ins().iconst(I64, 0); + cur.ins().uextend(I128, zero) + } else if ty.is_int() { + cur.ins().iconst(ty, 0) + } else if ty == F32 { + cur.ins().f32const(Ieee32::with_bits(0)) + } else if ty == F64 { + cur.ins().f64const(Ieee64::with_bits(0)) + } else if ty.is_vector() { + let scalar_ty = ty.lane_type(); + if scalar_ty.is_int() { + let zero = cur.func.dfg.constants.insert( + core::iter::repeat(0) + .take(ty.bytes().try_into().unwrap()) + .collect(), + ); + cur.ins().vconst(ty, zero) + } else if scalar_ty == F32 { + let scalar = cur.ins().f32const(Ieee32::with_bits(0)); + cur.ins().splat(ty, scalar) + } else if scalar_ty == F64 { + let scalar = cur.ins().f64const(Ieee64::with_bits(0)); + cur.ins().splat(ty, scalar) + } else { + panic!("unimplemented scalar type: {ty:?}") + } + } else { + panic!("unimplemented type: {ty:?}") + } +} + +/// The following methods are the API of the SSA builder. Here is how it should be used when +/// translating to Cranelift IR: +/// +/// - for each basic block, create a corresponding data for SSA construction with `declare_block`; +/// +/// - while traversing a basic block and translating instruction, use `def_var` and `use_var` +/// to record definitions and uses of variables, these methods will give you the corresponding +/// SSA values; +/// +/// - when all the instructions in a basic block have translated, the block is said _filled_ and +/// only then you can add it as a predecessor to other blocks with `declare_block_predecessor`; +/// +/// - when you have constructed all the predecessor to a basic block, +/// call `seal_block` on it with the `Function` that you are building. +/// +/// This API will give you the correct SSA values to use as arguments of your instructions, +/// as well as modify the jump instruction and `Block` parameters to account for the SSA +/// Phi functions. +/// +impl SSABuilder { + /// Declares a new definition of a variable in a given basic block. + /// The SSA value is passed as an argument because it should be created with + /// `ir::DataFlowGraph::append_result`. + pub fn def_var(&mut self, var: Variable, val: Value, block: Block) { + self.variables[var][block] = PackedOption::from(val); + } + + /// Declares a use of a variable in a given basic block. Returns the SSA value corresponding + /// to the current SSA definition of this variable and a list of newly created Blocks that + /// are the results of critical edge splitting for `br_table` with arguments. + /// + /// If the variable has never been defined in this blocks or recursively in its predecessors, + /// this method will silently create an initializer with `iconst` or `fconst`. You are + /// responsible for making sure that you initialize your variables. + pub fn use_var( + &mut self, + func: &mut Function, + var: Variable, + ty: Type, + block: Block, + ) -> (Value, SideEffects) { + debug_assert!(self.calls.is_empty()); + debug_assert!(self.results.is_empty()); + debug_assert!(self.side_effects.is_empty()); + + // Prepare the 'calls' and 'results' stacks for the state machine. + self.use_var_nonlocal(func, var, ty, block); + let value = self.run_state_machine(func, var, ty); + + let side_effects = mem::take(&mut self.side_effects); + (value, side_effects) + } + + /// Resolve the minimal SSA Value of `var` in `block` by traversing predecessors. + /// + /// This function sets up state for `run_state_machine()` but does not execute it. + fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, mut block: Block) { + // First, try Local Value Numbering (Algorithm 1 in the paper). + // If the variable already has a known Value in this block, use that. + if let Some(val) = self.variables[var][block].expand() { + self.results.push(val); + return; + } + + // Otherwise, use Global Value Numbering (Algorithm 2 in the paper). + // This resolves the Value with respect to its predecessors. + // Find the most recent definition of `var`, and the block the definition comes from. + let (val, from) = self.find_var(func, var, ty, block); + + // The `from` block returned from `find_var` is guaranteed to be on the path we follow by + // traversing only single-predecessor edges. It might be equal to `block` if there is no + // such path, but in that case `find_var` ensures that the variable is defined in this block + // by a new block parameter. It also might be somewhere in a cycle, but even then this loop + // will terminate the first time it encounters that block, rather than continuing around the + // cycle forever. + // + // Why is it okay to copy the definition to all intervening blocks? For the initial block, + // this may not be the final definition of this variable within this block, but if we've + // gotten here then we know there is no earlier definition in the block already. + // + // For the remaining blocks: Recall that a block is only allowed to be set as a predecessor + // after all its instructions have already been filled in, so when we follow a predecessor + // edge to a block, we know there will never be any more local variable definitions added to + // that block. We also know that `find_var` didn't find a definition for this variable in + // any of the blocks before `from`. + // + // So in either case there is no definition in these blocks yet and we can blindly set one. + let var_defs = &mut self.variables[var]; + while block != from { + debug_assert!(var_defs[block].is_none()); + var_defs[block] = PackedOption::from(val); + block = self.ssa_blocks[block].single_predecessor.unwrap(); + } + } + + /// Find the most recent definition of this variable, returning both the definition and the + /// block in which it was found. If we can't find a definition that's provably the right one for + /// all paths to the current block, then append a block parameter to some block and use that as + /// the definition. Either way, also arrange that the definition will be on the `results` stack + /// when `run_state_machine` is done processing the current step. + /// + /// If a block has exactly one predecessor, and the block is sealed so we know its predecessors + /// will never change, then its definition for this variable is the same as the definition from + /// that one predecessor. In this case it's easy to see that no block parameter is necessary, + /// but we need to look at the predecessor to see if a block parameter might be needed there. + /// That holds transitively across any chain of sealed blocks with exactly one predecessor each. + /// + /// This runs into a problem, though, if such a chain has a cycle: Blindly following a cyclic + /// chain that never defines this variable would lead to an infinite loop in the compiler. It + /// doesn't really matter what code we generate in that case. Since each block in the cycle has + /// exactly one predecessor, there's no way to enter the cycle from the function's entry block; + /// and since all blocks in the cycle are sealed, the entire cycle is permanently dead code. But + /// we still have to prevent the possibility of an infinite loop. + /// + /// To break cycles, we can pick any block within the cycle as the one where we'll add a block + /// parameter. It's convenient to pick the block at which we entered the cycle, because that's + /// the first place where we can detect that we just followed a cycle. Adding a block parameter + /// gives us a definition we can reuse throughout the rest of the cycle. + fn find_var( + &mut self, + func: &mut Function, + var: Variable, + ty: Type, + mut block: Block, + ) -> (Value, Block) { + // Try to find an existing definition along single-predecessor edges first. + self.visited.clear(); + let var_defs = &mut self.variables[var]; + while let Some(pred) = self.ssa_blocks[block].single_predecessor.expand() { + if !self.visited.insert(block) { + break; + } + block = pred; + if let Some(val) = var_defs[block].expand() { + self.results.push(val); + return (val, block); + } + } + + // We've promised to return the most recent block where `var` was defined, but we didn't + // find a usable definition. So create one. + let val = func.dfg.append_block_param(block, ty); + var_defs[block] = PackedOption::from(val); + + // Now every predecessor needs to pass its definition of this variable to the newly added + // block parameter. To do that we have to "recursively" call `use_var`, but there are two + // problems with doing that. First, we need to keep a fixed bound on stack depth, so we + // can't actually recurse; instead we defer to `run_state_machine`. Second, if we don't + // know all our predecessors yet, we have to defer this work until the block gets sealed. + match &mut self.ssa_blocks[block].sealed { + // Once all the `calls` added here complete, this leaves either `val` or an equivalent + // definition on the `results` stack. + Sealed::Yes => self.begin_predecessors_lookup(val, block), + Sealed::No { undef_variables } => { + undef_variables.push(var, &mut self.variable_pool); + self.results.push(val); + } + } + (val, block) + } + + /// Declares a new basic block to construct corresponding data for SSA construction. + /// No predecessors are declared here and the block is not sealed. + /// Predecessors have to be added with `declare_block_predecessor`. + pub fn declare_block(&mut self, block: Block) { + // Ensure the block exists so seal_all_blocks will see it even if no predecessors or + // variables get declared for this block. But don't assign anything to it: + // SecondaryMap automatically sets all blocks to `default()`. + let _ = &mut self.ssa_blocks[block]; + } + + /// Declares a new predecessor for a `Block` and record the branch instruction + /// of the predecessor that leads to it. + /// + /// The precedent `Block` must be filled before added as predecessor. + /// Note that you must provide no jump arguments to the branch + /// instruction when you create it since `SSABuilder` will fill them for you. + /// + /// Callers are expected to avoid adding the same predecessor more than once in the case + /// of a jump table. + pub fn declare_block_predecessor(&mut self, block: Block, inst: Inst) { + debug_assert!(!self.is_sealed(block)); + self.ssa_blocks[block] + .predecessors + .push(inst, &mut self.inst_pool); + } + + /// Remove a previously declared Block predecessor by giving a reference to the jump + /// instruction. Returns the basic block containing the instruction. + /// + /// Note: use only when you know what you are doing, this might break the SSA building problem + pub fn remove_block_predecessor(&mut self, block: Block, inst: Inst) { + debug_assert!(!self.is_sealed(block)); + let data = &mut self.ssa_blocks[block]; + let pred = data + .predecessors + .as_slice(&self.inst_pool) + .iter() + .position(|&branch| branch == inst) + .expect("the predecessor you are trying to remove is not declared"); + data.predecessors.swap_remove(pred, &mut self.inst_pool); + } + + /// Completes the global value numbering for a `Block`, all of its predecessors having been + /// already sealed. + /// + /// This method modifies the function's `Layout` by adding arguments to the `Block`s to + /// take into account the Phi function placed by the SSA algorithm. + /// + /// Returns the list of newly created blocks for critical edge splitting. + pub fn seal_block(&mut self, block: Block, func: &mut Function) -> SideEffects { + debug_assert!( + !self.is_sealed(block), + "Attempting to seal {block} which is already sealed." + ); + self.seal_one_block(block, func); + mem::take(&mut self.side_effects) + } + + /// Completes the global value numbering for all unsealed `Block`s in `func`. + /// + /// It's more efficient to seal `Block`s as soon as possible, during + /// translation, but for frontends where this is impractical to do, this + /// function can be used at the end of translating all blocks to ensure + /// that everything is sealed. + pub fn seal_all_blocks(&mut self, func: &mut Function) -> SideEffects { + // Seal all `Block`s currently in the function. This can entail splitting + // and creation of new blocks, however such new blocks are sealed on + // the fly, so we don't need to account for them here. + for block in self.ssa_blocks.keys() { + self.seal_one_block(block, func); + } + mem::take(&mut self.side_effects) + } + + /// Helper function for `seal_block` and `seal_all_blocks`. + fn seal_one_block(&mut self, block: Block, func: &mut Function) { + // For each undef var we look up values in the predecessors and create a block parameter + // only if necessary. + let mut undef_variables = + match mem::replace(&mut self.ssa_blocks[block].sealed, Sealed::Yes) { + Sealed::No { undef_variables } => undef_variables, + Sealed::Yes => return, + }; + let ssa_params = undef_variables.len(&self.variable_pool); + + let predecessors = self.predecessors(block); + if predecessors.len() == 1 { + let pred = func.layout.inst_block(predecessors[0]).unwrap(); + self.ssa_blocks[block].single_predecessor = PackedOption::from(pred); + } + + // Note that begin_predecessors_lookup requires visiting these variables in the same order + // that they were defined by find_var, because it appends arguments to the jump instructions + // in all the predecessor blocks one variable at a time. + for idx in 0..ssa_params { + let var = undef_variables.get(idx, &self.variable_pool).unwrap(); + + // We need the temporary Value that was assigned to this Variable. If that Value shows + // up as a result from any of our predecessors, then it never got assigned on the loop + // through that block. We get the value from the next block param, where it was first + // allocated in find_var. + let block_params = func.dfg.block_params(block); + + // On each iteration through this loop, there are (ssa_params - idx) undefined variables + // left to process. Previous iterations through the loop may have removed earlier block + // parameters, but the last (ssa_params - idx) block parameters always correspond to the + // remaining undefined variables. So index from the end of the current block params. + let val = block_params[block_params.len() - (ssa_params - idx)]; + + debug_assert!(self.calls.is_empty()); + debug_assert!(self.results.is_empty()); + // self.side_effects may be non-empty here so that callers can + // accumulate side effects over multiple calls. + self.begin_predecessors_lookup(val, block); + self.run_state_machine(func, var, func.dfg.value_type(val)); + } + + undef_variables.clear(&mut self.variable_pool); + } + + /// Given the local SSA Value of a Variable in a Block, perform a recursive lookup on + /// predecessors to determine if it is redundant with another Value earlier in the CFG. + /// + /// If such a Value exists and is redundant, the local Value is replaced by the + /// corresponding non-local Value. If the original Value was a Block parameter, + /// the parameter may be removed if redundant. Parameters are placed eagerly by callers + /// to avoid infinite loops when looking up a Value for a Block that is in a CFG loop. + /// + /// Doing this lookup for each Value in each Block preserves SSA form during construction. + /// + /// ## Arguments + /// + /// `sentinel` is a dummy Block parameter inserted by `use_var_nonlocal()`. + /// Its purpose is to allow detection of CFG cycles while traversing predecessors. + fn begin_predecessors_lookup(&mut self, sentinel: Value, dest_block: Block) { + self.calls + .push(Call::FinishPredecessorsLookup(sentinel, dest_block)); + // Iterate over the predecessors. + self.calls.extend( + self.ssa_blocks[dest_block] + .predecessors + .as_slice(&self.inst_pool) + .iter() + .rev() + .copied() + .map(Call::UseVar), + ); + } + + /// Examine the values from the predecessors and compute a result value, creating + /// block parameters as needed. + fn finish_predecessors_lookup( + &mut self, + func: &mut Function, + sentinel: Value, + dest_block: Block, + ) -> Value { + // Determine how many predecessors are yielding unique, non-temporary Values. If a variable + // is live and unmodified across several control-flow join points, earlier blocks will + // introduce aliases for that variable's definition, so we resolve aliases eagerly here to + // ensure that we can tell when the same definition has reached this block via multiple + // paths. Doing so also detects cyclic references to the sentinel, which can occur in + // unreachable code. + let num_predecessors = self.predecessors(dest_block).len(); + // When this `Drain` is dropped, these elements will get truncated. + let results = self.results.drain(self.results.len() - num_predecessors..); + + let pred_val = { + let mut iter = results + .as_slice() + .iter() + .map(|&val| func.dfg.resolve_aliases(val)) + .filter(|&val| val != sentinel); + if let Some(val) = iter.next() { + // This variable has at least one non-temporary definition. If they're all the same + // value, we can remove the block parameter and reference that value instead. + if iter.all(|other| other == val) { + Some(val) + } else { + None + } + } else { + // The variable is used but never defined before. This is an irregularity in the + // code, but rather than throwing an error we silently initialize the variable to + // 0. This will have no effect since this situation happens in unreachable code. + if !func.layout.is_block_inserted(dest_block) { + func.layout.append_block(dest_block); + } + self.side_effects + .instructions_added_to_blocks + .push(dest_block); + let zero = emit_zero( + func.dfg.value_type(sentinel), + FuncCursor::new(func).at_first_insertion_point(dest_block), + ); + Some(zero) + } + }; + + if let Some(pred_val) = pred_val { + // Here all the predecessors use a single value to represent our variable + // so we don't need to have it as a block argument. + // We need to replace all the occurrences of val with pred_val but since + // we can't afford a re-writing pass right now we just declare an alias. + func.dfg.remove_block_param(sentinel); + func.dfg.change_to_alias(sentinel, pred_val); + pred_val + } else { + // There is disagreement in the predecessors on which value to use so we have + // to keep the block argument. + let mut preds = self.ssa_blocks[dest_block].predecessors; + let dfg = &mut func.stencil.dfg; + for (idx, &val) in results.as_slice().iter().enumerate() { + let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap(); + let branch = *pred; + + let dests = dfg.insts[branch].branch_destination_mut(&mut dfg.jump_tables); + assert!( + !dests.is_empty(), + "you have declared a non-branch instruction as a predecessor to a block!" + ); + for block in dests { + if block.block(&dfg.value_lists) == dest_block { + block.append_argument(val, &mut dfg.value_lists); + } + } + } + sentinel + } + } + + /// Returns the list of `Block`s that have been declared as predecessors of the argument. + fn predecessors(&self, block: Block) -> &[Inst] { + self.ssa_blocks[block] + .predecessors + .as_slice(&self.inst_pool) + } + + /// Returns whether the given Block has any predecessor or not. + pub fn has_any_predecessors(&self, block: Block) -> bool { + !self.predecessors(block).is_empty() + } + + /// Returns `true` if and only if `seal_block` has been called on the argument. + pub fn is_sealed(&self, block: Block) -> bool { + matches!(self.ssa_blocks[block].sealed, Sealed::Yes) + } + + /// The main algorithm is naturally recursive: when there's a `use_var` in a + /// block with no corresponding local defs, it recurses and performs a + /// `use_var` in each predecessor. To avoid risking running out of callstack + /// space, we keep an explicit stack and use a small state machine rather + /// than literal recursion. + fn run_state_machine(&mut self, func: &mut Function, var: Variable, ty: Type) -> Value { + // Process the calls scheduled in `self.calls` until it is empty. + while let Some(call) = self.calls.pop() { + match call { + Call::UseVar(branch) => { + let block = func.layout.inst_block(branch).unwrap(); + self.use_var_nonlocal(func, var, ty, block); + } + Call::FinishPredecessorsLookup(sentinel, dest_block) => { + let val = self.finish_predecessors_lookup(func, sentinel, dest_block); + self.results.push(val); + } + } + } + debug_assert_eq!(self.results.len(), 1); + self.results.pop().unwrap() + } +} + +#[cfg(test)] +mod tests { + use crate::ssa::SSABuilder; + use crate::Variable; + use cranelift_codegen::cursor::{Cursor, FuncCursor}; + use cranelift_codegen::entity::EntityRef; + use cranelift_codegen::ir; + use cranelift_codegen::ir::types::*; + use cranelift_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode}; + use cranelift_codegen::settings; + use cranelift_codegen::verify_function; + + #[test] + fn simple_block() { + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + // Here is the pseudo-program we want to translate: + // block0: + // x = 1; + // y = 2; + // z = x + y; + // z = x + z; + + ssa.declare_block(block0); + let x_var = Variable::new(0); + let x_ssa = { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.ins().iconst(I32, 1) + }; + ssa.def_var(x_var, x_ssa, block0); + let y_var = Variable::new(1); + let y_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 2) + }; + ssa.def_var(y_var, y_ssa, block0); + assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa); + assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa); + + let z_var = Variable::new(2); + let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0; + let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0; + let z1_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iadd(x_use1, y_use1) + }; + ssa.def_var(z_var, z1_ssa, block0); + assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa); + + let x_use2 = ssa.use_var(&mut func, x_var, I32, block0).0; + let z_use1 = ssa.use_var(&mut func, z_var, I32, block0).0; + let z2_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iadd(x_use2, z_use1) + }; + ssa.def_var(z_var, z2_ssa, block0); + assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z2_ssa); + } + + #[test] + fn sequence_of_blocks() { + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + // Here is the pseudo-program we want to translate: + // block0: + // x = 1; + // y = 2; + // z = x + y; + // brif y, block1, block1; + // block1: + // z = x + z; + // jump block2; + // block2: + // y = x + y; + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + cur.insert_block(block2); + } + + // block0 + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + let x_var = Variable::new(0); + let x_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 1) + }; + ssa.def_var(x_var, x_ssa, block0); + let y_var = Variable::new(1); + let y_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 2) + }; + ssa.def_var(y_var, y_ssa, block0); + let z_var = Variable::new(2); + let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0; + let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0; + let z1_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iadd(x_use1, y_use1) + }; + ssa.def_var(z_var, z1_ssa, block0); + let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0; + let brif_block0_block2_block1: Inst = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().brif(y_use2, block2, &[], block1, &[]) + }; + + assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa); + assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa); + assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa); + + // block1 + ssa.declare_block(block1); + ssa.declare_block_predecessor(block1, brif_block0_block2_block1); + ssa.seal_block(block1, &mut func); + + let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0; + let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0; + let z2_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().iadd(x_use2, z_use1) + }; + ssa.def_var(z_var, z2_ssa, block1); + let jump_block1_block2: Inst = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().jump(block2, &[]) + }; + + assert_eq!(x_use2, x_ssa); + assert_eq!(z_use1, z1_ssa); + assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa); + + // block2 + ssa.declare_block(block2); + ssa.declare_block_predecessor(block2, brif_block0_block2_block1); + ssa.declare_block_predecessor(block2, jump_block1_block2); + ssa.seal_block(block2, &mut func); + let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0; + let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0; + let y2_ssa = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().iadd(x_use3, y_use3) + }; + ssa.def_var(y_var, y2_ssa, block2); + + assert_eq!(x_ssa, x_use3); + assert_eq!(y_ssa, y_use3); + match func.dfg.insts[brif_block0_block2_block1] { + ir::InstructionData::Brif { + blocks: [block_then, block_else], + .. + } => { + assert_eq!(block_then.block(&func.dfg.value_lists), block2); + assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0); + assert_eq!(block_else.block(&func.dfg.value_lists), block1); + assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0); + } + _ => assert!(false), + }; + match func.dfg.insts[brif_block0_block2_block1] { + ir::InstructionData::Brif { + blocks: [block_then, block_else], + .. + } => { + assert_eq!(block_then.block(&func.dfg.value_lists), block2); + assert_eq!(block_then.args_slice(&func.dfg.value_lists).len(), 0); + assert_eq!(block_else.block(&func.dfg.value_lists), block1); + assert_eq!(block_else.args_slice(&func.dfg.value_lists).len(), 0); + } + _ => assert!(false), + }; + match func.dfg.insts[jump_block1_block2] { + ir::InstructionData::Jump { + destination: dest, .. + } => { + assert_eq!(dest.block(&func.dfg.value_lists), block2); + assert_eq!(dest.args_slice(&func.dfg.value_lists).len(), 0); + } + _ => assert!(false), + }; + } + + #[test] + fn program_with_loop() { + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let block3 = func.dfg.make_block(); + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + cur.insert_block(block2); + cur.insert_block(block3); + } + // Here is the pseudo-program we want to translate: + // block0: + // x = 1; + // y = 2; + // z = x + y; + // jump block1 + // block1: + // z = z + y; + // brif y, block3, block2; + // block2: + // z = z - x; + // return y + // block3: + // y = y - x + // jump block1 + + // block0 + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + let x_var = Variable::new(0); + let x1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 1) + }; + ssa.def_var(x_var, x1, block0); + let y_var = Variable::new(1); + let y1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 2) + }; + ssa.def_var(y_var, y1, block0); + let z_var = Variable::new(2); + let x2 = ssa.use_var(&mut func, x_var, I32, block0).0; + let y2 = ssa.use_var(&mut func, y_var, I32, block0).0; + let z1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iadd(x2, y2) + }; + ssa.def_var(z_var, z1, block0); + let jump_block0_block1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().jump(block1, &[]) + }; + assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1); + assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1); + assert_eq!(x2, x1); + assert_eq!(y2, y1); + + // block1 + ssa.declare_block(block1); + ssa.declare_block_predecessor(block1, jump_block0_block1); + let z2 = ssa.use_var(&mut func, z_var, I32, block1).0; + let y3 = ssa.use_var(&mut func, y_var, I32, block1).0; + let z3 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().iadd(z2, y3) + }; + ssa.def_var(z_var, z3, block1); + let y4 = ssa.use_var(&mut func, y_var, I32, block1).0; + assert_eq!(y4, y3); + let brif_block1_block3_block2 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().brif(y4, block3, &[], block2, &[]) + }; + + // block2 + ssa.declare_block(block2); + ssa.declare_block_predecessor(block2, brif_block1_block3_block2); + ssa.seal_block(block2, &mut func); + let z4 = ssa.use_var(&mut func, z_var, I32, block2).0; + assert_eq!(z4, z3); + let x3 = ssa.use_var(&mut func, x_var, I32, block2).0; + let z5 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().isub(z4, x3) + }; + ssa.def_var(z_var, z5, block2); + let y5 = ssa.use_var(&mut func, y_var, I32, block2).0; + assert_eq!(y5, y3); + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().return_(&[y5]) + }; + + // block3 + ssa.declare_block(block3); + ssa.declare_block_predecessor(block3, brif_block1_block3_block2); + ssa.seal_block(block3, &mut func); + let y6 = ssa.use_var(&mut func, y_var, I32, block3).0; + assert_eq!(y6, y3); + let x4 = ssa.use_var(&mut func, x_var, I32, block3).0; + assert_eq!(x4, x3); + let y7 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block3); + cur.ins().isub(y6, x4) + }; + ssa.def_var(y_var, y7, block3); + let jump_block3_block1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block3); + cur.ins().jump(block1, &[]) + }; + + // block1 after all predecessors have been visited. + ssa.declare_block_predecessor(block1, jump_block3_block1); + ssa.seal_block(block1, &mut func); + assert_eq!(func.dfg.block_params(block1)[0], z2); + assert_eq!(func.dfg.block_params(block1)[1], y3); + assert_eq!(func.dfg.resolve_aliases(x3), x1); + } + + #[test] + fn br_table_with_args() { + // This tests the on-demand splitting of critical edges for br_table with jump arguments + // + // Here is the pseudo-program we want to translate: + // + // function %f { + // block0: + // x = 1; + // br_table x, block2, [block2, block1] + // block1: + // x = 2 + // jump block2 + // block2: + // x = x + 1 + // return + // } + + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + cur.insert_block(block2); + } + + // block0 + let x1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 1) + }; + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + let x_var = Variable::new(0); + ssa.def_var(x_var, x1, block0); + ssa.use_var(&mut func, x_var, I32, block0).0; + let br_table = { + let jump_table = JumpTableData::new( + func.dfg.block_call(block2, &[]), + &[ + func.dfg.block_call(block2, &[]), + func.dfg.block_call(block1, &[]), + ], + ); + let jt = func.create_jump_table(jump_table); + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().br_table(x1, jt) + }; + + // block1 + ssa.declare_block(block1); + ssa.declare_block_predecessor(block1, br_table); + ssa.seal_block(block1, &mut func); + let x2 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().iconst(I32, 2) + }; + ssa.def_var(x_var, x2, block1); + let jump_block1_block2 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().jump(block2, &[]) + }; + + // block2 + ssa.declare_block(block2); + ssa.declare_block_predecessor(block2, jump_block1_block2); + ssa.declare_block_predecessor(block2, br_table); + ssa.seal_block(block2, &mut func); + let x3 = ssa.use_var(&mut func, x_var, I32, block2).0; + let x4 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().iadd_imm(x3, 1) + }; + ssa.def_var(x_var, x4, block2); + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().return_(&[]) + }; + + let flags = settings::Flags::new(settings::builder()); + match verify_function(&func, &flags) { + Ok(()) => {} + Err(_errors) => { + #[cfg(feature = "std")] + panic!("{}", _errors); + #[cfg(not(feature = "std"))] + panic!("function failed to verify"); + } + } + } + + #[test] + fn undef_values_reordering() { + // Here is the pseudo-program we want to translate: + // block0: + // x = 0; + // y = 1; + // z = 2; + // jump block1; + // block1: + // x = z + x; + // y = y - x; + // jump block1; + // + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + } + + // block0 + ssa.declare_block(block0); + let x_var = Variable::new(0); + ssa.seal_block(block0, &mut func); + let x1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 0) + }; + ssa.def_var(x_var, x1, block0); + let y_var = Variable::new(1); + let y1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 1) + }; + ssa.def_var(y_var, y1, block0); + let z_var = Variable::new(2); + let z1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().iconst(I32, 2) + }; + ssa.def_var(z_var, z1, block0); + let jump_block0_block1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().jump(block1, &[]) + }; + + // block1 + ssa.declare_block(block1); + ssa.declare_block_predecessor(block1, jump_block0_block1); + let z2 = ssa.use_var(&mut func, z_var, I32, block1).0; + assert_eq!(func.dfg.block_params(block1)[0], z2); + let x2 = ssa.use_var(&mut func, x_var, I32, block1).0; + assert_eq!(func.dfg.block_params(block1)[1], x2); + let x3 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().iadd(x2, z2) + }; + ssa.def_var(x_var, x3, block1); + let x4 = ssa.use_var(&mut func, x_var, I32, block1).0; + let y3 = ssa.use_var(&mut func, y_var, I32, block1).0; + assert_eq!(func.dfg.block_params(block1)[2], y3); + let y4 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().isub(y3, x4) + }; + ssa.def_var(y_var, y4, block1); + let jump_block1_block1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + cur.ins().jump(block1, &[]) + }; + ssa.declare_block_predecessor(block1, jump_block1_block1); + ssa.seal_block(block1, &mut func); + // At sealing the "z" argument disappear but the remaining "x" and "y" args have to be + // in the right order. + assert_eq!(func.dfg.block_params(block1)[1], y3); + assert_eq!(func.dfg.block_params(block1)[0], x2); + } + + #[test] + fn undef() { + // Use vars of various types which have not been defined. + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + let i32_var = Variable::new(0); + let f32_var = Variable::new(1); + let f64_var = Variable::new(2); + let i8_var = Variable::new(3); + let f32x4_var = Variable::new(4); + ssa.use_var(&mut func, i32_var, I32, block0); + ssa.use_var(&mut func, f32_var, F32, block0); + ssa.use_var(&mut func, f64_var, F64, block0); + ssa.use_var(&mut func, i8_var, I8, block0); + ssa.use_var(&mut func, f32x4_var, F32X4, block0); + assert_eq!(func.dfg.num_block_params(block0), 0); + } + + #[test] + fn undef_in_entry() { + // Use a var which has not been defined. The search should hit the + // top of the entry block, and then fall back to inserting an iconst. + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + let x_var = Variable::new(0); + assert_eq!(func.dfg.num_block_params(block0), 0); + ssa.use_var(&mut func, x_var, I32, block0); + assert_eq!(func.dfg.num_block_params(block0), 0); + assert_eq!( + func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(), + Opcode::Iconst + ); + } + + #[test] + fn undef_in_entry_sealed_after() { + // Use a var which has not been defined, but the block is not sealed + // until afterward. Before sealing, the SSA builder should insert an + // block param; after sealing, it should be removed. + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + ssa.declare_block(block0); + let x_var = Variable::new(0); + assert_eq!(func.dfg.num_block_params(block0), 0); + ssa.use_var(&mut func, x_var, I32, block0); + assert_eq!(func.dfg.num_block_params(block0), 1); + ssa.seal_block(block0, &mut func); + assert_eq!(func.dfg.num_block_params(block0), 0); + assert_eq!( + func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(), + Opcode::Iconst + ); + } + + #[test] + fn unreachable_use() { + // Here is the pseudo-program we want to translate: + // block0: + // return; + // block1: + // brif x, block1, block1; + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + } + + // block0 + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().return_(&[]); + } + + // block1 + ssa.declare_block(block1); + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + let x_var = Variable::new(0); + let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0; + let brif = cur.ins().brif(x_val, block1, &[], block1, &[]); + ssa.declare_block_predecessor(block1, brif); + } + ssa.seal_block(block1, &mut func); + + let flags = settings::Flags::new(settings::builder()); + match verify_function(&func, &flags) { + Ok(()) => {} + Err(_errors) => { + #[cfg(feature = "std")] + panic!("{}", _errors); + #[cfg(not(feature = "std"))] + panic!("function failed to verify"); + } + } + } + + #[test] + fn unreachable_use_with_multiple_preds() { + // Here is the pseudo-program we want to translate: + // block0: + // return; + // block1: + // brif x, block1, block2; + // block2: + // jump block1; + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + { + let mut cur = FuncCursor::new(&mut func); + cur.insert_block(block0); + cur.insert_block(block1); + cur.insert_block(block2); + } + + // block0 + ssa.declare_block(block0); + ssa.seal_block(block0, &mut func); + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + cur.ins().return_(&[]); + } + + // block1 + ssa.declare_block(block1); + let brif = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + let x_var = Variable::new(0); + let x_val = ssa.use_var(&mut cur.func, x_var, I32, block1).0; + cur.ins().brif(x_val, block2, &[], block1, &[]) + }; + + // block2 + ssa.declare_block(block2); + ssa.declare_block_predecessor(block1, brif); + ssa.declare_block_predecessor(block2, brif); + ssa.seal_block(block2, &mut func); + let jump_block2_block1 = { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + cur.ins().jump(block1, &[]) + }; + + // seal block1 + ssa.declare_block_predecessor(block1, jump_block2_block1); + ssa.seal_block(block1, &mut func); + let flags = settings::Flags::new(settings::builder()); + match verify_function(&func, &flags) { + Ok(()) => {} + Err(_errors) => { + #[cfg(feature = "std")] + panic!("{}", _errors); + #[cfg(not(feature = "std"))] + panic!("function failed to verify"); + } + } + } + + #[test] + fn reassign_with_predecessor_loop_hangs() { + // Here is the pseudo-program we want to translate: + // block0: + // var0 = iconst 0 + // return; + // block1: + // jump block2; + // block2: + // ; phantom use of var0 + // var0 = iconst 1 + // jump block1; + + let mut func = Function::new(); + let mut ssa = SSABuilder::default(); + let block0 = func.dfg.make_block(); + let block1 = func.dfg.make_block(); + let block2 = func.dfg.make_block(); + let var0 = Variable::new(0); + + { + let mut cur = FuncCursor::new(&mut func); + for block in [block0, block1, block2] { + cur.insert_block(block); + ssa.declare_block(block); + } + } + + // block0 + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block0); + + let var0_iconst = cur.ins().iconst(I32, 0); + ssa.def_var(var0, var0_iconst, block0); + + cur.ins().return_(&[]); + } + + // block1 + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block1); + + let jump = cur.ins().jump(block2, &[]); + ssa.declare_block_predecessor(block2, jump); + } + + // block2 + { + let mut cur = FuncCursor::new(&mut func).at_bottom(block2); + + let _ = ssa.use_var(&mut cur.func, var0, I32, block2).0; + let var0_iconst = cur.ins().iconst(I32, 1); + ssa.def_var(var0, var0_iconst, block2); + + let jump = cur.ins().jump(block1, &[]); + ssa.declare_block_predecessor(block1, jump); + } + + // The sealing algorithm would enter a infinite loop here + ssa.seal_all_blocks(&mut func); + } +} diff --git a/deps/crates/vendor/cranelift-frontend/src/switch.rs b/deps/crates/vendor/cranelift-frontend/src/switch.rs new file mode 100644 index 00000000000000..9605557a980a01 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/switch.rs @@ -0,0 +1,676 @@ +use super::HashMap; +use crate::frontend::FunctionBuilder; +use alloc::vec::Vec; +use cranelift_codegen::ir::condcodes::IntCC; +use cranelift_codegen::ir::*; + +type EntryIndex = u128; + +/// Unlike with `br_table`, `Switch` cases may be sparse or non-0-based. +/// They emit efficient code using branches, jump tables, or a combination of both. +/// +/// # Example +/// +/// ```rust +/// # use cranelift_codegen::ir::types::*; +/// # use cranelift_codegen::ir::{UserFuncName, Function, Signature, InstBuilder}; +/// # use cranelift_codegen::isa::CallConv; +/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch}; +/// # +/// # let mut sig = Signature::new(CallConv::SystemV); +/// # let mut fn_builder_ctx = FunctionBuilderContext::new(); +/// # let mut func = Function::with_name_signature(UserFuncName::user(0, 0), sig); +/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); +/// # +/// # let entry = builder.create_block(); +/// # builder.switch_to_block(entry); +/// # +/// let block0 = builder.create_block(); +/// let block1 = builder.create_block(); +/// let block2 = builder.create_block(); +/// let fallback = builder.create_block(); +/// +/// let val = builder.ins().iconst(I32, 1); +/// +/// let mut switch = Switch::new(); +/// switch.set_entry(0, block0); +/// switch.set_entry(1, block1); +/// switch.set_entry(7, block2); +/// switch.emit(&mut builder, val, fallback); +/// ``` +#[derive(Debug, Default)] +pub struct Switch { + cases: HashMap, +} + +impl Switch { + /// Create a new empty switch + pub fn new() -> Self { + Self { + cases: HashMap::new(), + } + } + + /// Set a switch entry + pub fn set_entry(&mut self, index: EntryIndex, block: Block) { + let prev = self.cases.insert(index, block); + assert!(prev.is_none(), "Tried to set the same entry {index} twice"); + } + + /// Get a reference to all existing entries + pub fn entries(&self) -> &HashMap { + &self.cases + } + + /// Turn the `cases` `HashMap` into a list of `ContiguousCaseRange`s. + /// + /// # Postconditions + /// + /// * Every entry will be represented. + /// * The `ContiguousCaseRange`s will not overlap. + /// * Between two `ContiguousCaseRange`s there will be at least one entry index. + /// * No `ContiguousCaseRange`s will be empty. + fn collect_contiguous_case_ranges(self) -> Vec { + log::trace!("build_contiguous_case_ranges before: {:#?}", self.cases); + let mut cases = self.cases.into_iter().collect::>(); + cases.sort_by_key(|&(index, _)| index); + + let mut contiguous_case_ranges: Vec = vec![]; + let mut last_index = None; + for (index, block) in cases { + match last_index { + None => contiguous_case_ranges.push(ContiguousCaseRange::new(index)), + Some(last_index) => { + if index > last_index + 1 { + contiguous_case_ranges.push(ContiguousCaseRange::new(index)); + } + } + } + contiguous_case_ranges + .last_mut() + .unwrap() + .blocks + .push(block); + last_index = Some(index); + } + + log::trace!( + "build_contiguous_case_ranges after: {:#?}", + contiguous_case_ranges + ); + + contiguous_case_ranges + } + + /// Binary search for the right `ContiguousCaseRange`. + fn build_search_tree<'a>( + bx: &mut FunctionBuilder, + val: Value, + otherwise: Block, + contiguous_case_ranges: &'a [ContiguousCaseRange], + ) { + // If no switch cases were added to begin with, we can just emit `jump otherwise`. + if contiguous_case_ranges.is_empty() { + bx.ins().jump(otherwise, &[]); + return; + } + + // Avoid allocation in the common case + if contiguous_case_ranges.len() <= 3 { + Self::build_search_branches(bx, val, otherwise, contiguous_case_ranges); + return; + } + + let mut stack = Vec::new(); + stack.push((None, contiguous_case_ranges)); + + while let Some((block, contiguous_case_ranges)) = stack.pop() { + if let Some(block) = block { + bx.switch_to_block(block); + } + + if contiguous_case_ranges.len() <= 3 { + Self::build_search_branches(bx, val, otherwise, contiguous_case_ranges); + } else { + let split_point = contiguous_case_ranges.len() / 2; + let (left, right) = contiguous_case_ranges.split_at(split_point); + + let left_block = bx.create_block(); + let right_block = bx.create_block(); + + let first_index = right[0].first_index; + let should_take_right_side = + icmp_imm_u128(bx, IntCC::UnsignedGreaterThanOrEqual, val, first_index); + bx.ins() + .brif(should_take_right_side, right_block, &[], left_block, &[]); + + bx.seal_block(left_block); + bx.seal_block(right_block); + + stack.push((Some(left_block), left)); + stack.push((Some(right_block), right)); + } + } + } + + /// Linear search for the right `ContiguousCaseRange`. + fn build_search_branches<'a>( + bx: &mut FunctionBuilder, + val: Value, + otherwise: Block, + contiguous_case_ranges: &'a [ContiguousCaseRange], + ) { + for (ix, range) in contiguous_case_ranges.iter().enumerate().rev() { + let alternate = if ix == 0 { + otherwise + } else { + bx.create_block() + }; + + if range.first_index == 0 { + assert_eq!(alternate, otherwise); + + if let Some(block) = range.single_block() { + bx.ins().brif(val, otherwise, &[], block, &[]); + } else { + Self::build_jump_table(bx, val, otherwise, 0, &range.blocks); + } + } else { + if let Some(block) = range.single_block() { + let is_good_val = icmp_imm_u128(bx, IntCC::Equal, val, range.first_index); + bx.ins().brif(is_good_val, block, &[], alternate, &[]); + } else { + let is_good_val = icmp_imm_u128( + bx, + IntCC::UnsignedGreaterThanOrEqual, + val, + range.first_index, + ); + let jt_block = bx.create_block(); + bx.ins().brif(is_good_val, jt_block, &[], alternate, &[]); + bx.seal_block(jt_block); + bx.switch_to_block(jt_block); + Self::build_jump_table(bx, val, otherwise, range.first_index, &range.blocks); + } + } + + if alternate != otherwise { + bx.seal_block(alternate); + bx.switch_to_block(alternate); + } + } + } + + fn build_jump_table( + bx: &mut FunctionBuilder, + val: Value, + otherwise: Block, + first_index: EntryIndex, + blocks: &[Block], + ) { + // There are currently no 128bit systems supported by rustc, but once we do ensure that + // we don't silently ignore a part of the jump table for 128bit integers on 128bit systems. + assert!( + u32::try_from(blocks.len()).is_ok(), + "Jump tables bigger than 2^32-1 are not yet supported" + ); + + let jt_data = JumpTableData::new( + bx.func.dfg.block_call(otherwise, &[]), + &blocks + .iter() + .map(|block| bx.func.dfg.block_call(*block, &[])) + .collect::>(), + ); + let jump_table = bx.create_jump_table(jt_data); + + let discr = if first_index == 0 { + val + } else { + if let Ok(first_index) = u64::try_from(first_index) { + bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg()) + } else { + let (lsb, msb) = (first_index as u64, (first_index >> 64) as u64); + let lsb = bx.ins().iconst(types::I64, lsb as i64); + let msb = bx.ins().iconst(types::I64, msb as i64); + let index = bx.ins().iconcat(lsb, msb); + bx.ins().isub(val, index) + } + }; + + let discr = match bx.func.dfg.value_type(discr).bits() { + bits if bits > 32 => { + // Check for overflow of cast to u32. This is the max supported jump table entries. + let new_block = bx.create_block(); + let bigger_than_u32 = + bx.ins() + .icmp_imm(IntCC::UnsignedGreaterThan, discr, u32::MAX as i64); + bx.ins() + .brif(bigger_than_u32, otherwise, &[], new_block, &[]); + bx.seal_block(new_block); + bx.switch_to_block(new_block); + + // Cast to i32, as br_table is not implemented for i64/i128 + bx.ins().ireduce(types::I32, discr) + } + bits if bits < 32 => bx.ins().uextend(types::I32, discr), + _ => discr, + }; + + bx.ins().br_table(discr, jump_table); + } + + /// Build the switch + /// + /// # Arguments + /// + /// * The function builder to emit to + /// * The value to switch on + /// * The default block + pub fn emit(self, bx: &mut FunctionBuilder, val: Value, otherwise: Block) { + // Validate that the type of `val` is sufficiently wide to address all cases. + let max = self.cases.keys().max().copied().unwrap_or(0); + let val_ty = bx.func.dfg.value_type(val); + let val_ty_max = val_ty.bounds(false).1; + if max > val_ty_max { + panic!("The index type {val_ty} does not fit the maximum switch entry of {max}"); + } + + let contiguous_case_ranges = self.collect_contiguous_case_ranges(); + Self::build_search_tree(bx, val, otherwise, &contiguous_case_ranges); + } +} + +fn icmp_imm_u128(bx: &mut FunctionBuilder, cond: IntCC, x: Value, y: u128) -> Value { + if bx.func.dfg.value_type(x) != types::I128 { + assert!(u64::try_from(y).is_ok()); + bx.ins().icmp_imm(cond, x, y as i64) + } else if let Ok(index) = i64::try_from(y) { + bx.ins().icmp_imm(cond, x, index) + } else { + let (lsb, msb) = (y as u64, (y >> 64) as u64); + let lsb = bx.ins().iconst(types::I64, lsb as i64); + let msb = bx.ins().iconst(types::I64, msb as i64); + let index = bx.ins().iconcat(lsb, msb); + bx.ins().icmp(cond, x, index) + } +} + +/// This represents a contiguous range of cases to switch on. +/// +/// For example 10 => block1, 11 => block2, 12 => block7 will be represented as: +/// +/// ```plain +/// ContiguousCaseRange { +/// first_index: 10, +/// blocks: vec![Block::from_u32(1), Block::from_u32(2), Block::from_u32(7)] +/// } +/// ``` +#[derive(Debug)] +struct ContiguousCaseRange { + /// The entry index of the first case. Eg. 10 when the entry indexes are 10, 11, 12 and 13. + first_index: EntryIndex, + + /// The blocks to jump to sorted in ascending order of entry index. + blocks: Vec, +} + +impl ContiguousCaseRange { + fn new(first_index: EntryIndex) -> Self { + Self { + first_index, + blocks: Vec::new(), + } + } + + /// Returns `Some` block when there is only a single block in this range. + fn single_block(&self) -> Option { + if self.blocks.len() == 1 { + Some(self.blocks[0]) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::frontend::FunctionBuilderContext; + use alloc::string::ToString; + + macro_rules! setup { + ($default:expr, [$($index:expr,)*]) => {{ + let mut func = Function::new(); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); + let block = bx.create_block(); + bx.switch_to_block(block); + let val = bx.ins().iconst(types::I8, 0); + let mut switch = Switch::new(); + let _ = &mut switch; + $( + let block = bx.create_block(); + switch.set_entry($index, block); + )* + switch.emit(&mut bx, val, Block::with_number($default).unwrap()); + } + func + .to_string() + .trim_start_matches("function u0:0() fast {\n") + .trim_end_matches("\n}\n") + .to_string() + }}; + } + + #[test] + fn switch_empty() { + let func = setup!(42, []); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + jump block42" + ); + } + + #[test] + fn switch_zero() { + let func = setup!(0, [0,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + brif v0, block0, block1 ; v0 = 0" + ); + } + + #[test] + fn switch_single() { + let func = setup!(0, [1,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm eq v0, 1 ; v0 = 0 + brif v1, block1, block0" + ); + } + + #[test] + fn switch_bool() { + let func = setup!(0, [0, 1,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = uextend.i32 v0 ; v0 = 0 + br_table v1, block0, [block1, block2]" + ); + } + + #[test] + fn switch_two_gap() { + let func = setup!(0, [0, 2,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm eq v0, 2 ; v0 = 0 + brif v1, block2, block3 + +block3: + brif.i8 v0, block0, block1 ; v0 = 0" + ); + } + + #[test] + fn switch_many() { + let func = setup!(0, [0, 1, 5, 7, 10, 11, 12,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm uge v0, 7 ; v0 = 0 + brif v1, block9, block8 + +block9: + v2 = icmp_imm.i8 uge v0, 10 ; v0 = 0 + brif v2, block11, block10 + +block11: + v3 = iadd_imm.i8 v0, -10 ; v0 = 0 + v4 = uextend.i32 v3 + br_table v4, block0, [block5, block6, block7] + +block10: + v5 = icmp_imm.i8 eq v0, 7 ; v0 = 0 + brif v5, block4, block0 + +block8: + v6 = icmp_imm.i8 eq v0, 5 ; v0 = 0 + brif v6, block3, block12 + +block12: + v7 = uextend.i32 v0 ; v0 = 0 + br_table v7, block0, [block1, block2]" + ); + } + + #[test] + fn switch_min_index_value() { + let func = setup!(0, [i8::MIN as u8 as u128, 1,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm eq v0, -128 ; v0 = 0 + brif v1, block1, block3 + +block3: + v2 = icmp_imm.i8 eq v0, 1 ; v0 = 0 + brif v2, block2, block0" + ); + } + + #[test] + fn switch_max_index_value() { + let func = setup!(0, [i8::MAX as u8 as u128, 1,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm eq v0, 127 ; v0 = 0 + brif v1, block1, block3 + +block3: + v2 = icmp_imm.i8 eq v0, 1 ; v0 = 0 + brif v2, block2, block0" + ) + } + + #[test] + fn switch_optimal_codegen() { + let func = setup!(0, [-1i8 as u8 as u128, 0, 1,]); + assert_eq_output!( + func, + "block0: + v0 = iconst.i8 0 + v1 = icmp_imm eq v0, -1 ; v0 = 0 + brif v1, block1, block4 + +block4: + v2 = uextend.i32 v0 ; v0 = 0 + br_table v2, block0, [block2, block3]" + ); + } + + #[test] + #[should_panic( + expected = "The index type i8 does not fit the maximum switch entry of 4683743612477887600" + )] + fn switch_rejects_small_inputs() { + // This is a regression test for a bug that we found where we would emit a cmp + // with a type that was not able to fully represent a large index. + // + // See: https://github.com/bytecodealliance/wasmtime/pull/4502#issuecomment-1191961677 + setup!(1, [0x4100_0000_00bf_d470,]); + } + + #[test] + fn switch_seal_generated_blocks() { + let cases = &[vec![0, 1, 2], vec![0, 1, 2, 10, 11, 12, 20, 30, 40, 50]]; + + for case in cases { + for typ in &[types::I8, types::I16, types::I32, types::I64, types::I128] { + eprintln!("Testing {typ:?} with keys: {case:?}"); + do_case(case, *typ); + } + } + + fn do_case(keys: &[u128], typ: Type) { + let mut func = Function::new(); + let mut builder_ctx = FunctionBuilderContext::new(); + let mut builder = FunctionBuilder::new(&mut func, &mut builder_ctx); + + let root_block = builder.create_block(); + let default_block = builder.create_block(); + let mut switch = Switch::new(); + + let case_blocks = keys + .iter() + .map(|key| { + let block = builder.create_block(); + switch.set_entry(*key, block); + block + }) + .collect::>(); + + builder.seal_block(root_block); + builder.switch_to_block(root_block); + + let val = builder.ins().iconst(typ, 1); + switch.emit(&mut builder, val, default_block); + + for &block in case_blocks.iter().chain(std::iter::once(&default_block)) { + builder.seal_block(block); + builder.switch_to_block(block); + builder.ins().return_(&[]); + } + + builder.finalize(); // Will panic if some blocks are not sealed + } + } + + #[test] + fn switch_64bit() { + let mut func = Function::new(); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); + let block0 = bx.create_block(); + bx.switch_to_block(block0); + let val = bx.ins().iconst(types::I64, 0); + let mut switch = Switch::new(); + let block1 = bx.create_block(); + switch.set_entry(1, block1); + let block2 = bx.create_block(); + switch.set_entry(0, block2); + let block3 = bx.create_block(); + switch.emit(&mut bx, val, block3); + } + let func = func + .to_string() + .trim_start_matches("function u0:0() fast {\n") + .trim_end_matches("\n}\n") + .to_string(); + assert_eq_output!( + func, + "block0: + v0 = iconst.i64 0 + v1 = icmp_imm ugt v0, 0xffff_ffff ; v0 = 0 + brif v1, block3, block4 + +block4: + v2 = ireduce.i32 v0 ; v0 = 0 + br_table v2, block3, [block2, block1]" + ); + } + + #[test] + fn switch_128bit() { + let mut func = Function::new(); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); + let block0 = bx.create_block(); + bx.switch_to_block(block0); + let val = bx.ins().iconst(types::I64, 0); + let val = bx.ins().uextend(types::I128, val); + let mut switch = Switch::new(); + let block1 = bx.create_block(); + switch.set_entry(1, block1); + let block2 = bx.create_block(); + switch.set_entry(0, block2); + let block3 = bx.create_block(); + switch.emit(&mut bx, val, block3); + } + let func = func + .to_string() + .trim_start_matches("function u0:0() fast {\n") + .trim_end_matches("\n}\n") + .to_string(); + assert_eq_output!( + func, + "block0: + v0 = iconst.i64 0 + v1 = uextend.i128 v0 ; v0 = 0 + v2 = icmp_imm ugt v1, 0xffff_ffff + brif v2, block3, block4 + +block4: + v3 = ireduce.i32 v1 + br_table v3, block3, [block2, block1]" + ); + } + + #[test] + fn switch_128bit_max_u64() { + let mut func = Function::new(); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); + let block0 = bx.create_block(); + bx.switch_to_block(block0); + let val = bx.ins().iconst(types::I64, 0); + let val = bx.ins().uextend(types::I128, val); + let mut switch = Switch::new(); + let block1 = bx.create_block(); + switch.set_entry(u64::MAX.into(), block1); + let block2 = bx.create_block(); + switch.set_entry(0, block2); + let block3 = bx.create_block(); + switch.emit(&mut bx, val, block3); + } + let func = func + .to_string() + .trim_start_matches("function u0:0() fast {\n") + .trim_end_matches("\n}\n") + .to_string(); + assert_eq_output!( + func, + "block0: + v0 = iconst.i64 0 + v1 = uextend.i128 v0 ; v0 = 0 + v2 = iconst.i64 -1 + v3 = iconst.i64 0 + v4 = iconcat v2, v3 ; v2 = -1, v3 = 0 + v5 = icmp eq v1, v4 + brif v5, block1, block4 + +block4: + brif.i128 v1, block3, block2" + ); + } +} diff --git a/deps/crates/vendor/cranelift-frontend/src/variable.rs b/deps/crates/vendor/cranelift-frontend/src/variable.rs new file mode 100644 index 00000000000000..60b1e7ce74e0d7 --- /dev/null +++ b/deps/crates/vendor/cranelift-frontend/src/variable.rs @@ -0,0 +1,18 @@ +//! A basic `Variable` implementation. +//! +//! Frontends can use any indexing scheme they see fit and +//! generate the appropriate `Variable` instances. +//! +//! Note: The `Variable` is used by Cranelift to index into densely allocated +//! arrays containing information about your mutable variables +//! Thus, make sure that Variable's indexes are allocated contiguously and +//! starting at `0`. + +use core::u32; +use cranelift_codegen::entity::entity_impl; + +/// An opaque reference to a variable. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Variable(u32); + +entity_impl!(Variable, "var"); diff --git a/deps/crates/vendor/cranelift-isle/.cargo-checksum.json b/deps/crates/vendor/cranelift-isle/.cargo-checksum.json new file mode 100644 index 00000000000000..b15731b3417381 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"c629718d878cb7137ad8d6f2a698542398e620f8fff1f0d9e4e7aca663f32cea","Cargo.lock":"e8ff1e658418256eac766f64fec0fbf543bb41cbbcd22d9177aafa37f5d394e5","Cargo.toml":"a2466a226f89d9b1a0d2b18a23bc48f3078fd8deee5056f2bf79823aa246ef07","Cargo.toml.orig":"d84ea2cffe6c07660e78864906c52dad649a5d2a3f28db2310b43a710b596ddb","README.md":"cde3f7281c7a6c3195784341904495770914d41414546e65e0b4e66478676121","build.rs":"1b754139bb45d23a114450d918287dd8ce6d5f942a8c0d0d8472213685da7c0a","isle_examples/fail/bad_converters.isle":"3c439432aca313302fc0bd360b48b3e0229074b7e630e8099a6f01ff7966f913","isle_examples/fail/bound_var_type_mismatch.isle":"4e00cd7b3ba3742af45cd91e6fd76099a20514d80771de8fd897c700867790ef","isle_examples/fail/converter_extractor_constructor.isle":"9603f8e41be92f30b0f2a513e4ad788b53423c61d5391ffba86d45163f36345a","isle_examples/fail/error1.isle":"05adc60252fa1c1870746c7eb8327ee6efe3b70bb7eb6c7bbdd7464c04f190e8","isle_examples/fail/extra_parens.isle":"b284bbc5fb0c26ceb6dbb2424e432427086ceec1c3d77fb3f9d84b0e33fc1635","isle_examples/fail/impure_expression.isle":"3d982a78a5a87107c14722b13d4bb7c7d327dcffa953f5601afa5c346eaeab09","isle_examples/fail/impure_rhs.isle":"5c4a4221f80defaa02cdf9c3341ea50f6390d472c7463fc0e7ce86d76069cbf5","isle_examples/fail/multi_internal_etor.isle":"1caab7220f9835b1fa655ddb187cbdc41900c2468c6854f03dbd486fc4802c4d","isle_examples/fail/multi_prio.isle":"2b6a71531965d265f093117d45e489b3f7d8427906c0c9b66cd30bc4258bb029","isle_examples/link/borrows.isle":"637fca161923fb2b72374ff50a793f194b96596b5a41c45edbd8893b6ca9cdc4","isle_examples/link/borrows_main.rs":"d14d5c191613c45a2687493ace29e8dcda532be9a09a792ee04d96b7a2994978","isle_examples/link/iflets.isle":"af1957fa1441f42d1138cacfe02207e4043f9092abc37f4a6aad74a433d26807","isle_examples/link/iflets_main.rs":"71d96686f7bea89a084fa676d87f198c630e9f8e23ad1927ea0df15af3eba19d","isle_examples/link/multi_constructor.isle":"eea23428b90cc8b7c13883507ee536dd31d368705c5ec5e633aa1c60db6c9aec","isle_examples/link/multi_constructor_main.rs":"2961d23ec3c2699ab2c5bddbc1f1c88c1c8611595afb8ef4623bf6c2a07acbe3","isle_examples/link/multi_extractor.isle":"af1153aa6b7e5227e632888d3868873d1566cc78aaeb6de6866f59997f56e968","isle_examples/link/multi_extractor_main.rs":"15899c5462790fd1508024dc52017fea1bdef65608fecbfc9baca1c478ebd7eb","isle_examples/link/test.isle":"3af6322bb18006931890fe975fa6f320fcc6760c329a66a3ed3ab6b88d6831c9","isle_examples/link/test_main.rs":"0362fa81349db33cda6b97d81da90a86509d52e8085ad499bd5be18724965878","isle_examples/pass/bound_var.isle":"5e77e2a0132c379a5dc830bdc45efa84164cbc64df4bce06cd7125e4ec838335","isle_examples/pass/construct_and_extract.isle":"42b631c41bfb5a2f877b42a8622f1b38e58707a8ea97ad898f7af5be1b362f9d","isle_examples/pass/conversions.isle":"a5705dce60a8bf6b36fd0c85f7e2a8bb064515279e8745d02bdc63b80fa49dfb","isle_examples/pass/conversions_extern.isle":"24ca717c100bf477efad53c5adb207f88bf33e7c0ea07ec4d485cb86b8da996b","isle_examples/pass/let.isle":"0f93fb307eaa4b6cfb46ac1b2393c0444b88969aecfd25a445befe47871ac55f","isle_examples/pass/nodebug.isle":"16e58d125a37fe001c03136a70c5270d2b90a719ee266a39705aaabb2aadf174","isle_examples/pass/prio_trie_bug.isle":"5347b5a8b687c4e401d93940a9e867ff8430832e6409b36c08c353417c9f6b3b","isle_examples/pass/test2.isle":"96080c11a75bb3c978e96846b769a6c46e589404e0b1e97905c34bebfa0e872e","isle_examples/pass/test3.isle":"9d88a45c122e18c5ea5eef6848c1d923f899dffcb2a7b27b595d06a23f588294","isle_examples/pass/test4.isle":"9f20d22173346a6ff65033089780b0fc8c966e8f2834ae7d5d028f8025a39c62","isle_examples/pass/tutorial.isle":"79169d350cbb62e00af4cb3dd64c7d7e0a277c1e57236f0b8a2d26d7ce710d0c","isle_examples/pass/veri_spec.isle":"ce156e4112ee66a0b121a5d901a83f9fd9cb99ad420fd8a6a99847af91917f68","isle_examples/run/iconst.isle":"adbad0f88ac2a5242c48fae313c9c71f7b70733951bbce1cbb12ec6cb03e87fd","isle_examples/run/iconst_main.rs":"f1b921b205d0f6120faaccd8138e5db8c42e9ab548eb3fbef643f3cfc8be03d0","isle_examples/run/let_shadowing.isle":"ab118b10b14e1e2121255ffe7ba39222a2526b1fbfc8f97701270bd9946d5a64","isle_examples/run/let_shadowing_main.rs":"466f9b79f06f1cfa259c4f9c05a892df99d3fd0de1e62b97a6ab372f4509f6a9","src/ast.rs":"9abff54b5fe7bb271c4d9e077df39a93f6dccdac408ce70d2f1cf9c847206c41","src/codegen.rs":"4f36c1307ace8373244a61ae5ee866cab0ed5afb94a2c946e636e5950fabe362","src/compile.rs":"d7e306c752cab46cc8fecdd038b9946892a4046f93e23eaced53cbf5ee0a78a9","src/disjointsets.rs":"19edc692db8f67fad6ee001db857b0e9875d5b6e0ad32f4c00fc346db14efa74","src/error.rs":"7b25410843d582892ff45625d09131d818fbd3d73a7304a49973c403db98c8af","src/files.rs":"fd92df6a5f887da19b9c0d3b46277f5995d572e921c7f0647dd6c616035a48d0","src/lexer.rs":"dd047a8727e2be11aef738f3799e0397921ee0efa613e7e5c6d613dc55a29779","src/lib.rs":"086325083f5daa2ec47f9869bfaa9dd0f118a2acdd144f47e5fb4742746d0811","src/log.rs":"abfe10789b25940da3a559bb7be30f928bb35574b4a8f0875bdd75350d25c0e9","src/overlap.rs":"2f31b063fd75f91136b1f6ce12635f42a13460fb81b7af8e655bbcebfb36f3b9","src/parser.rs":"2fef872991153b92af840a769fb01d8c13aa9ab8767cb26d3fb61827cdbde872","src/sema.rs":"14df1f822d179ea7ff795c9c511f9cca3c1ea87bb03c20e9baa67f2aef3eb8ad","src/serialize.rs":"6c889cb5ab18241f70849bfec4b5119417f19d48c6e82b4221f27bf721853ea3","src/stablemapset.rs":"f8d70177e5d61dc8eb309567af00094c86e7856ce2fef35c6d2dc1737e6a2ac1","src/trie_again.rs":"ac29f5e515440a532a7a4862979484f0787087a4dece7ac7b7bd97cce6902a77","tests/run_tests.rs":"a22f98ace18d39fe5d7298f2d6491c71c0a97d3d351b3d8b318f948c242aa833"},"package":"1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d"} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-isle/.cargo_vcs_info.json b/deps/crates/vendor/cranelift-isle/.cargo_vcs_info.json new file mode 100644 index 00000000000000..bc4ea27a039037 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "58282df898d79a787a726d829b166272dde155b9" + }, + "path_in_vcs": "cranelift/isle/isle" +} \ No newline at end of file diff --git a/deps/crates/vendor/cranelift-isle/Cargo.lock b/deps/crates/vendor/cranelift-isle/Cargo.lock new file mode 100644 index 00000000000000..be352379ceb96e --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/Cargo.lock @@ -0,0 +1,294 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "cranelift-isle" +version = "0.116.1" +dependencies = [ + "codespan-reporting", + "log", + "tempfile", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "rustix" +version = "0.38.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/deps/crates/vendor/cranelift-isle/Cargo.toml b/deps/crates/vendor/cranelift-isle/Cargo.toml new file mode 100644 index 00000000000000..9ed98a4cbd3c6b --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/Cargo.toml @@ -0,0 +1,83 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.81.0" +name = "cranelift-isle" +version = "0.116.1" +authors = ["The Cranelift Project Developers"] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "ISLE: Instruction Selection and Lowering Expressions. A domain-specific language for instruction selection in Cranelift." +readme = "README.md" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/isle" + +[lib] +name = "cranelift_isle" +path = "src/lib.rs" + +[[test]] +name = "run_tests" +path = "tests/run_tests.rs" + +[dependencies.codespan-reporting] +version = "0.11.1" +optional = true + +[dependencies.log] +version = "0.4.8" +optional = true +default-features = false + +[dev-dependencies.tempfile] +version = "3" + +[features] +default = [] +fancy-errors = ["codespan-reporting"] +logging = ["log"] + +[lints.clippy] +allow_attributes_without_reason = "warn" +clone_on_copy = "warn" +manual_strip = "warn" +map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" +unnecessary_to_owned = "warn" + +[lints.clippy.all] +level = "allow" +priority = -1 + +[lints.rust] +trivial_numeric_casts = "warn" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = [ + "cfg(pulley_tail_calls)", + "cfg(pulley_assume_llvm_makes_tail_calls)", +] diff --git a/deps/crates/vendor/cranelift-isle/Cargo.toml.orig b/deps/crates/vendor/cranelift-isle/Cargo.toml.orig new file mode 100644 index 00000000000000..557a5e27837004 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/Cargo.toml.orig @@ -0,0 +1,26 @@ +[package] +authors = ["The Cranelift Project Developers"] +description = "ISLE: Instruction Selection and Lowering Expressions. A domain-specific language for instruction selection in Cranelift." +edition.workspace = true +rust-version.workspace = true +license = "Apache-2.0 WITH LLVM-exception" +name = "cranelift-isle" +readme = "../README.md" +repository = "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/isle" +version = "0.116.1" + +[lints] +workspace = true + +[dependencies] +codespan-reporting = { version = "0.11.1", optional = true } +log = { workspace = true, optional = true } + +[dev-dependencies] +tempfile = "3" + +[features] +default = [] + +logging = ["log"] +fancy-errors = ["codespan-reporting"] diff --git a/deps/crates/vendor/cranelift-isle/README.md b/deps/crates/vendor/cranelift-isle/README.md new file mode 100644 index 00000000000000..fbd1d48e08aacc --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/README.md @@ -0,0 +1,9 @@ +# ISLE: Instruction Selection / Lowering Expressions + +ISLE is a domain specific language (DSL) for instruction selection and lowering +clif instructions to vcode's `MachInst`s in Cranelift. + +ISLE is a statically-typed term-rewriting language. You define rewriting rules +that map input terms (clif instructions) into output terms (`MachInst`s). These +rules get compiled down into Rust source test that uses a tree of `match` +expressions that is as good or better than what you would have written by hand. diff --git a/deps/crates/vendor/cranelift-isle/build.rs b/deps/crates/vendor/cranelift-isle/build.rs new file mode 100644 index 00000000000000..2b71758a85cbed --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/build.rs @@ -0,0 +1,35 @@ +use std::fmt::Write; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=isle_examples"); + + let out_dir = std::path::PathBuf::from( + std::env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"), + ); + + let mut out = String::new(); + + emit_tests(&mut out, "isle_examples/pass", "run_pass"); + emit_tests(&mut out, "isle_examples/fail", "run_fail"); + emit_tests(&mut out, "isle_examples/link", "run_link"); + emit_tests(&mut out, "isle_examples/run", "run_run"); + + let output = out_dir.join("isle_tests.rs"); + std::fs::write(output, out).unwrap(); +} + +fn emit_tests(out: &mut String, dir_name: &str, runner_func: &str) { + for test_file in std::fs::read_dir(dir_name).unwrap() { + let test_file = test_file.unwrap().file_name().into_string().unwrap(); + if !test_file.ends_with(".isle") { + continue; + } + let test_file_base = test_file.replace(".isle", ""); + + writeln!(out, "#[test]").unwrap(); + writeln!(out, "fn test_{runner_func}_{test_file_base}() {{").unwrap(); + writeln!(out, " {runner_func}(\"{dir_name}/{test_file}\");").unwrap(); + writeln!(out, "}}").unwrap(); + } +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/bad_converters.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/bad_converters.isle new file mode 100644 index 00000000000000..027dd088dce95f --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/bad_converters.isle @@ -0,0 +1,10 @@ +(type T (enum)) +(type U (enum)) + +(decl t_to_u_1 (T) U) +(decl t_to_u_2 (T) U) + +(convert T U t_to_u_1) +(convert T U t_to_u_2) + +(convert T Undef undefined_term) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/bound_var_type_mismatch.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/bound_var_type_mismatch.isle new file mode 100644 index 00000000000000..a58d5121514215 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/bound_var_type_mismatch.isle @@ -0,0 +1,4 @@ +(decl A (u32 u64) u32) + +(rule 1 (A x x) x) +(rule 0 (A x _) 0) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/converter_extractor_constructor.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/converter_extractor_constructor.isle new file mode 100644 index 00000000000000..b204d813e5708e --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/converter_extractor_constructor.isle @@ -0,0 +1,29 @@ +(type T (enum)) +(type U (enum)) +(type V (enum)) + +(convert T U t_to_u) +(convert U V u_to_v) + +(decl t_to_u (T) U) +(decl u_to_v (U) V) +(decl t_to_v (T) V) +(decl v_to_t (V) T) + +(extern constructor t_to_u t_to_u) +(extern extractor u_to_v u_to_v) +(extern constructor t_to_v t_to_v_ctor) +(extern extractor t_to_v t_to_v_etor) +(extern extractor v_to_t v_to_u_etor) + +;; We should fail to find a converter here. Given only the types, we +;; might expect u_to_v to be implicitly inserted in the RHS, but +;; u_to_v has only an extractor, not a constructor, associated. +(decl Test1 (U) V) +(rule (Test1 u) u) + +;; We should fail to find a converter here. Given only the types, we +;; might expect t_to_u to be implicitly inserted in the LHS, but t_to_u +;; has only a constructor, not an extractor, associated. +(decl Test2 (U) V) +(rule (Test2 (v_to_t v)) v) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/error1.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/error1.isle new file mode 100644 index 00000000000000..b24e18e54c1d9a --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/error1.isle @@ -0,0 +1,34 @@ +(type A (enum (A1 (x u32)))) + +(decl Ext1 (u32) A) +(decl Ext2 (u32) A) +(extern extractor Ext1 ext1) +(extern extractor Ext2 ext2) + +(decl C (bool) A) +(extern constructor C c) + +(decl Lower (A) A) + +(rule + (Lower + (and + a + (Ext1 x) + (Ext2 =q))) + (C y)) + +(type R (enum (A (x u32)))) + +(type Opcode (enum A B C)) +(type MachInst (enum D E F)) +(decl Lower2 (Opcode) MachInst) +(rule + (Lower2 (Opcode.A)) + (R.A (Opcode.A))) +(rule + (Lower2 (Opcode.B)) + (MachInst.E)) +(rule + (Lower2 (Opcode.C)) + (MachInst.F)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/extra_parens.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/extra_parens.isle new file mode 100644 index 00000000000000..9c37123571da98 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/extra_parens.isle @@ -0,0 +1,4 @@ +(decl f (u32) u32) +;; Should get an error about `x` not being a term, with a suggestion that it is +;; a bound var instead. +(rule (f x) (x)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_expression.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_expression.isle new file mode 100644 index 00000000000000..0adb4759708e58 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_expression.isle @@ -0,0 +1,8 @@ +(decl ctor (u32) u32) +(rule (ctor x) x) + +(decl entry (u32) u32) + +(rule (entry x) + (if-let y (ctor x)) + y) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_rhs.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_rhs.isle new file mode 100644 index 00000000000000..4bfc95e5c555dd --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/impure_rhs.isle @@ -0,0 +1,13 @@ +(decl pure ctor (u32) u32) +(decl impure (u32) u32) + +(decl entry (u32) u32) + +(rule (entry x) + (if-let y (ctor x)) + y) + +(rule (ctor x) + (impure x)) + +(rule (impure x) x) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_internal_etor.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_internal_etor.isle new file mode 100644 index 00000000000000..d876231dec752e --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_internal_etor.isle @@ -0,0 +1,2 @@ +(decl multi A (u32) u32) +(extractor (A x) x) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_prio.isle b/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_prio.isle new file mode 100644 index 00000000000000..feb766688de156 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/fail/multi_prio.isle @@ -0,0 +1,2 @@ +(decl multi A (u32) u32) +(rule 0 (A x) x) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows.isle b/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows.isle new file mode 100644 index 00000000000000..2b1ce8f6f4817c --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows.isle @@ -0,0 +1,14 @@ +(type A extern (enum (B (x u32) (y u32)))) + +(decl get_a (A) u32) +(extern extractor get_a get_a) + +(decl pure partial u32_pure (u32) u32) +(extern constructor u32_pure u32_pure) + +(decl entry (u32) u32) +(rule (entry x @ (get_a a1)) + (if-let (get_a a2) x) + (if-let (A.B p q) a1) + (if-let r (u32_pure p)) + r) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows_main.rs new file mode 100644 index 00000000000000..9de7d4ddded8e7 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/borrows_main.rs @@ -0,0 +1,21 @@ +mod borrows; + +#[derive(Clone)] +pub enum A { + B { x: u32, y: u32 }, +} + +struct Context(A); +impl borrows::Context for Context { + fn get_a(&mut self, _: u32) -> Option { + Some(self.0.clone()) + } + + fn u32_pure(&mut self, value: u32) -> Option { + Some(value + 1) + } +} + +fn main() { + borrows::constructor_entry(&mut Context(A::B { x: 1, y: 2 }), 42); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets.isle b/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets.isle new file mode 100644 index 00000000000000..cf7f324696ef8e --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets.isle @@ -0,0 +1,27 @@ +(decl pure partial A (u32 u32) u32) +(extern constructor A A) + +(decl B (u32 u32) u32) +(extern extractor B B) + +(decl partial C (u32 u32 u32 u32) u32) + +(decl pure predicate () u32) +(rule (predicate) 1) + +(rule 2 (C a b c (B d e)) + (if-let (B f g) d) + (if-let h (A a b)) + (A h a)) + +(rule (C a b c d) + (if (predicate)) + 42) + +(rule 1 (C a b a b) + (if-let x (D a b)) + x) + +(decl pure D (u32 u32) u32) +(rule (D x 0) x) +(rule 1 (D 0 x) x) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets_main.rs new file mode 100644 index 00000000000000..4c5717cbf407af --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/iflets_main.rs @@ -0,0 +1,16 @@ +mod iflets; + +struct Context; +impl iflets::Context for Context { + fn A(&mut self, a: u32, b: u32) -> Option { + Some(a + b) + } + + fn B(&mut self, value: u32) -> Option<(u32, u32)> { + Some((value, value + 1)) + } +} + +fn main() { + iflets::constructor_C(&mut Context, 1, 2, 3, 4); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor.isle b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor.isle new file mode 100644 index 00000000000000..86758c983142fa --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor.isle @@ -0,0 +1,13 @@ +(decl multi A (u32) u32) +(decl multi B (u32) u32) +(decl multi C (u32) u32) +(decl multi D (u32) u32) + +(extern constructor B ctor_B) +(extern extractor C etor_C) + +(rule (A x) + (B x)) + +(rule (D (C x)) + (B x)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor_main.rs new file mode 100644 index 00000000000000..3c05532ce077d2 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_constructor_main.rs @@ -0,0 +1,88 @@ +mod multi_constructor; +use multi_constructor::{ContextIter, IntoContextIter}; + +struct Context; + +const MAX_ISLE_RETURNS: usize = 100; + +#[derive(Default)] +struct It { + i: u32, + limit: u32, +} + +impl ContextIter for It { + type Context = Context; + type Output = u32; + fn next(&mut self, _ctx: &mut Self::Context) -> Option { + if self.i >= self.limit { + None + } else { + let i = self.i; + self.i += 1; + Some(i) + } + } +} + +impl IntoContextIter for It { + type Context = Context; + type Output = u32; + type IntoIter = It; + fn into_context_iter(self) -> It { + self + } +} + +impl multi_constructor::Context for Context { + type etor_C_returns = It; + fn etor_C(&mut self, value: u32, returns: &mut It) { + returns.i = 0; + returns.limit = value; + } + + type ctor_B_returns = multi_constructor::ContextIterWrapper, Context>; + fn ctor_B(&mut self, value: u32, returns: &mut Self::ctor_B_returns) { + returns.extend((0..value).rev()); + } +} + +struct IterWithContext< + 'a, + Item, + I: multi_constructor::ContextIter, +> { + ctx: &'a mut Context, + it: I, +} + +impl<'a, Item, I: multi_constructor::ContextIter> Iterator + for IterWithContext<'a, Item, I> +{ + type Item = Item; + fn next(&mut self) -> Option { + self.it.next(self.ctx) + } +} + +fn main() { + let mut ctx = Context; + + let mut l1 = multi_constructor::ContextIterWrapper::, _>::default(); + multi_constructor::constructor_A(&mut ctx, 10, &mut l1); + + let mut l2 = multi_constructor::ContextIterWrapper::, _>::default(); + multi_constructor::constructor_D(&mut ctx, 5, &mut l2); + + let l1 = IterWithContext { + ctx: &mut ctx, + it: l1.into_context_iter(), + } + .collect::>(); + let l2 = IterWithContext { + ctx: &mut ctx, + it: l2.into_context_iter(), + } + .collect::>(); + println!("l1 = {:?} l2 = {:?}", l1, l2); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor.isle b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor.isle new file mode 100644 index 00000000000000..f69b2a6f00454d --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor.isle @@ -0,0 +1,13 @@ +(type A extern (enum (B) (C))) + +(decl multi E1 (A u32) u32) + +(extern extractor E1 e1_etor) + +(decl multi Rule (u32) u32) + +(rule (Rule (E1 a idx)) + (if-let (A.B) a) + idx) +(rule (Rule _) + 32) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor_main.rs new file mode 100644 index 00000000000000..ebfa38e30fdf03 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/multi_extractor_main.rs @@ -0,0 +1,63 @@ +mod multi_extractor; + +use multi_extractor::{ContextIter, IntoContextIter}; + +const MAX_ISLE_RETURNS: usize = 100; + +#[derive(Clone)] +pub enum A { + B, + C, +} + +#[derive(Default)] +struct It { + i: u32, + arg: u32, +} + +impl ContextIter for It { + type Context = Context; + type Output = (A, u32); + fn next(&mut self, _ctx: &mut Self::Context) -> Option { + if self.i >= 32 { + None + } else { + let idx = self.i; + self.i += 1; + let a = if self.arg & (1u32 << idx) != 0 { + A::B + } else { + A::C + }; + Some((a, idx)) + } + } +} + +impl IntoContextIter for It { + type Context = Context; + type IntoIter = It; + type Output = (A, u32); + fn into_context_iter(self) -> It { + self + } +} + +struct Context; +impl multi_extractor::Context for Context { + type e1_etor_returns = It; + fn e1_etor(&mut self, arg0: u32, returns: &mut It) { + returns.i = 0; + returns.arg = arg0; + } +} + +fn main() { + let mut ctx = Context; + let mut x = vec![]; + multi_extractor::constructor_Rule(&mut ctx, 0xf0, &mut x); + let mut y = vec![]; + multi_extractor::constructor_Rule(&mut ctx, 0, &mut y); + println!("x = {:?} y = {:?}", x, y); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/test.isle b/deps/crates/vendor/cranelift-isle/isle_examples/link/test.isle new file mode 100644 index 00000000000000..80190e12673696 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/test.isle @@ -0,0 +1,20 @@ +(type A (enum (A1 (x u32)) (A2 (x u32)))) +(type B (enum (B1 (x u32)) (B2 (x u32)))) + +(decl Input (A) u32) +(extern extractor Input get_input) ;; fn get_input(ctx: &mut C, ret: u32) -> Option<(A,)> + +(decl Lower (A) B) + +(rule + (Lower (A.A1 sub @ (Input (A.A2 42)))) + (B.B2 sub)) + +(decl Extractor (B) A) +(extractor + (Extractor x) + (A.A2 x)) + +(rule + (Lower (Extractor b)) + (B.B1 b)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/link/test_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/link/test_main.rs new file mode 100644 index 00000000000000..733e2a20193b5b --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/link/test_main.rs @@ -0,0 +1,12 @@ +mod test; + +struct Context; +impl test::Context for Context { + fn get_input(&mut self, x: u32) -> Option { + Some(test::A::A1 { x: x + 1 }) + } +} + +fn main() { + test::constructor_Lower(&mut Context, &test::A::A1 { x: 42 }); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/bound_var.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/bound_var.isle new file mode 100644 index 00000000000000..0647330a437282 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/bound_var.isle @@ -0,0 +1,4 @@ +(decl A (u32 u32) u32) + +(rule 1 (A x x) x) +(rule 0 (A x _) 0) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/construct_and_extract.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/construct_and_extract.isle new file mode 100644 index 00000000000000..3d8becd54334d2 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/construct_and_extract.isle @@ -0,0 +1,15 @@ +(type B (enum (B (x i32) (y i32)))) + +;; `isub` has a constructor and extractor. +(decl isub (i32 i32) B) +(rule (isub x y) + (B.B x y)) +(extractor (isub x y) + (B.B x y)) + +;; `value_array_2` has both an external extractor and an external constructor. +(type Value (primitive Value)) +(type ValueArray2 extern (enum)) +(decl value_array_2 (Value Value) ValueArray2) +(extern extractor infallible value_array_2 unpack_value_array_2) +(extern constructor value_array_2 pack_value_array_2) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions.isle new file mode 100644 index 00000000000000..a1bb7ea94180d3 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions.isle @@ -0,0 +1,27 @@ +(type T (enum (A) (B))) +(type U (enum (C) (D))) +(type V (enum (E) (F))) + +(convert T U t_to_u) +(convert U T u_to_t) +(convert U V u_to_v) + +(decl t_to_u (T) U) +(decl u_to_t (U) T) +(decl u_to_v (U) V) + +(rule (t_to_u (T.A)) (U.C)) +(rule (t_to_u (T.B)) (U.D)) + +(rule (u_to_t (U.C)) (T.A)) +(rule (u_to_t (U.D)) (T.B)) + +(rule (u_to_v (U.C)) (V.E)) +(rule (u_to_v (U.D)) (V.F)) + +(extern extractor u_to_t u_to_t) + + +(decl X (T U) V) +(rule (X (U.C) (U.D)) + (U.D)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions_extern.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions_extern.isle new file mode 100644 index 00000000000000..1cddf657499f56 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/conversions_extern.isle @@ -0,0 +1,22 @@ +(type T (primitive T)) +(type U (primitive U)) +(type V (primitive V)) + +(convert T U t_to_u) + +(type Result (enum (T (u U) (v V)))) + +;; Use the implicit converter before the underlying constructor is +;; declared (below). Also use one of the conversions before it is +;; declared (below). +(decl entry (T) Result) +(rule (entry t) + (Result.T t t)) + +(convert T V t_to_v) + +(decl t_to_u (T) U) +(extern constructor t_to_u t_to_u) + +(decl t_to_v (T) V) +(rule (t_to_v _) 0) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/let.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/let.isle new file mode 100644 index 00000000000000..59670852ec12c1 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/let.isle @@ -0,0 +1,20 @@ +(type A (enum (Add (x u32) (y u32)) (Sub (x u32) (y u32)))) +(type B (enum (B (z u32)))) + +(decl Sub (u32 u32) u32) +(extern constructor Sub sub) + +(decl Add (u32 u32) u32) +(extern constructor Add add) + +(decl Lower (A) B) + +(rule + (Lower (A.Add x y)) + (let ((z u32 (Add x y))) + (B.B z))) + +(rule + (Lower (A.Sub x y)) + (let ((z u32 (Sub x y))) + (B.B z))) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/nodebug.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/nodebug.isle new file mode 100644 index 00000000000000..71accb034f85a8 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/nodebug.isle @@ -0,0 +1,4 @@ +(type DoesNotDeriveDebug nodebug + (enum A + B + C)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/prio_trie_bug.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/prio_trie_bug.isle new file mode 100644 index 00000000000000..b63de1ab152b94 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/prio_trie_bug.isle @@ -0,0 +1,106 @@ +;; Minimized bug reproducer for earlier priority-range-merging trie +;; implementation in ISLE compiler. This example, when compiled with +;; old versions of islec, would result in the bottom-most rule (at +;; priority 0) being applied before the rule involving `iconst` at +;; priority 1 below. + +(type Unit (primitive Unit)) +(type Reg (primitive Reg)) +(type MemFlags (primitive MemFlags)) +(type MachLabel (primitive MachLabel)) +(type Value (primitive Value)) + +(decl iadd (Value Value) Value) +(extern extractor iadd iadd) +(decl ishl (Value Value) Value) +(extern extractor ishl ishl) +(decl uextend (Value) Value) +(extern extractor uextend uextend) +(decl sextend (Value) Value) +(extern extractor sextend sextend) +(decl iconst (u32) Value) +(extern extractor iconst iconst) + +(decl put_in_reg (Value) Reg) +(convert Value Reg put_in_reg) +(extern constructor put_in_reg put_in_reg) + +(decl invalid_reg () Reg) +(extern extractor invalid_reg invalid_reg) +(decl valid_reg () Reg) +(extern extractor valid_reg valid_reg) + +(decl pure u32_lteq (u32 u32) Unit) +(extern constructor u32_lteq u32_lteq) + +(decl pure s32_add_fallible (u32 u32) u32) +(extern constructor s32_add_fallible s32_add_fallible) + +(decl x64_add (Reg Reg) Reg) +(extern constructor x64_add x64_add) + +;; An `Amode` represents a possible addressing mode that can be used +;; in instructions. These denote a 64-bit value only. +(type Amode (enum + ;; Immediate sign-extended and a register + (ImmReg (simm32 u32) + (base Reg) + (flags MemFlags)) + + ;; Sign-extend-32-to-64(simm32) + base + (index << shift) + (ImmRegRegShift (simm32 u32) + (base Reg) + (index Reg) + (shift u32) + (flags MemFlags)) + + ;; Sign-extend-32-to-64(immediate) + RIP (instruction + ;; pointer). The appropriate relocation is emitted so + ;; that the resulting immediate makes this Amode refer to + ;; the given MachLabel. + (RipRelative (target MachLabel)))) + +;; One step in amode processing: take an existing amode and add +;; another value to it. +(decl amode_add (Amode Value) Amode) + +;; -- Top-level driver: pull apart the addends. +;; +;; Any amode can absorb an `iadd` by absorbing first the LHS of the +;; add, then the RHS. +;; +;; Priority 2 to take this above fallbacks and ensure we traverse the +;; `iadd` tree fully. +(rule 2 (amode_add amode (iadd x y)) + (let ((amode1 Amode (amode_add amode x)) + (amode2 Amode (amode_add amode1 y))) + amode2)) + +;; -- Case 1 (adding a register to the initial Amode with invalid_reg). +;; +;; An Amode.ImmReg with invalid_reg (initial state) can absorb a +;; register as the base register. +(rule (amode_add (Amode.ImmReg off (invalid_reg) flags) value) + (Amode.ImmReg off value flags)) + +;; -- Case 4 (absorbing constant offsets). +;; +;; An Amode can absorb a constant (i64, or extended i32) as long as +;; the sum still fits in the signed-32-bit offset. +;; +;; Priority 3 in order to take this option above the fallback +;; (immediate in register). Two rules, for imm+reg and +;; imm+reg+scale*reg cases. +(rule 1 (amode_add (Amode.ImmRegRegShift off base index shift flags) + (iconst c)) + (if-let sum (s32_add_fallible off c)) + (Amode.ImmRegRegShift sum base index shift flags)) + +;; -- Case 5 (fallback to add a new value to an imm+reg+scale*reg). +;; +;; An Amode.ImmRegRegShift can absorb any other value by creating a +;; new add instruction and replacing the base with +;; (base+value). +(rule (amode_add (Amode.ImmRegRegShift off base index shift flags) value) + (let ((sum Reg (x64_add base value))) + (Amode.ImmRegRegShift off sum index shift flags))) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/test2.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test2.isle new file mode 100644 index 00000000000000..209769d39dd93f --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test2.isle @@ -0,0 +1,23 @@ +(type A (enum + (A1 (x B) (y B)))) +(type B (enum + (B1 (x u32)) + (B2 (x u32)))) + +(decl A2B (A) B) + +(rule 1 + (A2B (A.A1 _ (B.B1 x))) + (B.B1 x)) + +(rule 0 + (A2B (A.A1 (B.B1 x) _)) + (B.B1 x)) + +(rule 0 + (A2B (A.A1 (B.B2 x) _)) + (B.B1 x)) + +(rule -1 + (A2B (A.A1 _ _)) + (B.B1 42)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/test3.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test3.isle new file mode 100644 index 00000000000000..5f54a489b76416 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test3.isle @@ -0,0 +1,63 @@ +(type Opcode extern (enum + Iadd + Isub + Load + Store)) + +(type Inst (primitive Inst)) +(type InstInput (primitive InstInput)) +(type Reg (primitive Reg)) + +(decl Op (Opcode) Inst) +(extern extractor infallible Op get_opcode) + +(decl InstInputs2 (InstInput InstInput) Inst) +(extern extractor infallible InstInputs2 get_inst_inputs_2) + +(decl Producer (Inst) InstInput) +(extern extractor Producer get_input_producer) + +(decl UseInput (InstInput) Reg) +(extern constructor UseInput put_input_in_reg) + +(type MachInst (enum + (Add (a Reg) (b Reg)) + (Add3 (a Reg) (b Reg) (c Reg)) + (Sub (a Reg) (b Reg)))) + +(decl Lower (Inst) MachInst) + +;; Extractors that give syntax sugar for (Iadd ra rb), etc. +;; +;; Note that this is somewhat simplistic: it directly connects inputs to +;; MachInst regs; really we'd want to return a VReg or InstInput that we can use +;; another extractor to connect to another (producer) inst. +;; +;; Also, note that while it looks a little indirect, a verification effort could +;; define equivalences across the `rule` LHS/RHS pairs, and the types ensure that +;; we are dealing (at the semantic level) with pure value equivalences of +;; "terms", not arbitrary side-effecting calls. + +(decl Iadd (InstInput InstInput) Inst) +(decl Isub (InstInput InstInput) Inst) +(extractor + (Iadd a b) + (and + (Op (Opcode.Iadd)) + (InstInputs2 a b))) +(extractor + (Isub a b) + (and + (Op (Opcode.Isub)) + (InstInputs2 a b))) + +;; Now the nice syntax-sugar that "end-user" backend authors can write: +(rule + (Lower (Iadd ra rb)) + (MachInst.Add (UseInput ra) (UseInput rb))) +(rule 1 + (Lower (Iadd (Producer (Iadd ra rb)) rc)) + (MachInst.Add3 (UseInput ra) (UseInput rb) (UseInput rc))) +(rule + (Lower (Isub ra rb)) + (MachInst.Sub (UseInput ra) (UseInput rb))) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/test4.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test4.isle new file mode 100644 index 00000000000000..714fd7bd997da4 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/test4.isle @@ -0,0 +1,40 @@ +(type A (enum (A1 (x u32)))) + +(decl Ext1 (u32) A) +(decl Ext2 (u32) A) +(extern extractor Ext1 ext1) +(extern extractor Ext2 ext2) + +(extern const $A u32) +(extern const $B u32) + +(decl C (bool) A) +(extern constructor C c) + +(decl Lower (A) A) + +(rule + (Lower + (and + a + (Ext1 x) + (Ext2 x))) + (C true)) + +(type Opcode (enum A B C)) +(type MachInst (enum D E F)) +(decl Lower2 (Opcode) MachInst) +(rule + (Lower2 (Opcode.A)) + (MachInst.D)) +(rule + (Lower2 (Opcode.B)) + (MachInst.E)) +(rule + (Lower2 (Opcode.C)) + (MachInst.F)) + +(decl F (Opcode) u32) +(rule + (F _) + $B) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/tutorial.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/tutorial.isle new file mode 100644 index 00000000000000..871ac843b3c97f --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/tutorial.isle @@ -0,0 +1,93 @@ +;;;; Type Definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Our high-level, RISC-y input IR. +(type HighLevelInst + (enum (Add (a Value) (b Value)) + (Load (addr Value)) + (Const (c i32)))) + +;; A value in our high-level IR is a Rust `Copy` type. Values are either defined +;; by an instruction, or are a basic block argument. +(type Value (primitive Value)) + +;; Our low-level, CISC-y machine instructions. +(type LowLevelInst + (enum (Add (mode AddrMode)) + (Load (offset i32) (addr Reg)) + (Const (c i32)))) + +;; Different kinds of addressing modes for operands to our low-level machine +;; instructions. +(type AddrMode + (enum + ;; Both operands in registers. + (RegReg (a Reg) (b Reg)) + ;; The destination/first operand is a register; the second operand is in + ;; memory at `[b + offset]`. + (RegMem (a Reg) (b Reg) (offset i32)) + ;; The destination/first operand is a register, second operand is an + ;; immediate. + (RegImm (a Reg) (imm i32)))) + +;; The register type is a Rust `Copy` type. +(type Reg (primitive Reg)) + +;;;; Rules ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Declare our top-level lowering function. We will attach rules to this +;; declaration for lowering various patterns of `HighLevelInst` inputs. +(decl lower (HighLevelInst) LowLevelInst) + +;; Simple rule for lowering constants. +(rule (lower (HighLevelInst.Const c)) + (LowLevelInst.Const c)) + +;; Declare an external constructor that puts a high-level `Value` into a +;; low-level `Reg`. +(decl put_in_reg (Value) Reg) +(extern constructor put_in_reg put_in_reg) + +;; Simple rule for lowering adds. +(rule -1 (lower (HighLevelInst.Add a b)) + (LowLevelInst.Add + (AddrMode.RegReg (put_in_reg a) (put_in_reg b)))) + +;; Simple rule for lowering loads. +(rule -1 (lower (HighLevelInst.Load addr)) + (LowLevelInst.Load 0 (put_in_reg addr))) + +;; Declare an external extractor for extracting the instruction that defined a +;; given operand value. +(decl inst_result (HighLevelInst) Value) +(extern extractor inst_result inst_result) + +;; Rule to sink loads into adds. +(rule (lower (HighLevelInst.Add a (inst_result (HighLevelInst.Load addr)))) + (LowLevelInst.Add + (AddrMode.RegMem (put_in_reg a) + (put_in_reg addr) + 0))) + +;; Rule to sink a load of a base address with a static offset into a single add. +(rule 1 (lower (HighLevelInst.Add + a + (inst_result (HighLevelInst.Load + (inst_result (HighLevelInst.Add + base + (inst_result (HighLevelInst.Const offset)))))))) + (LowLevelInst.Add + (AddrMode.RegMem (put_in_reg a) + (put_in_reg base) + offset))) + +;; Rule for sinking an immediate into an add. +(rule (lower (HighLevelInst.Add a (inst_result (HighLevelInst.Const c)))) + (LowLevelInst.Add + (AddrMode.RegImm (put_in_reg a) c))) + +;; Rule for lowering loads of a base address with a static offset. +(rule (lower (HighLevelInst.Load + (inst_result (HighLevelInst.Add + base + (inst_result (HighLevelInst.Const offset)))))) + (LowLevelInst.Load offset (put_in_reg base))) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/pass/veri_spec.isle b/deps/crates/vendor/cranelift-isle/isle_examples/pass/veri_spec.isle new file mode 100644 index 00000000000000..daa0d8ead7a4c2 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/pass/veri_spec.isle @@ -0,0 +1,22 @@ +(form + bv_unary_8_to_64 + ((args (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) +) + +(spec (A i j) (provide (= (if true (= i j) (= i (bvneg j))) (=> false true)))) +(instantiate A ((args (bv 8)) (ret (bv 8)) (canon (bv 8)))) +(decl A (u8 u8) u8) + +(spec (B i) + (provide (= (bvadd i #xff) #b00000000)) + (require (= (= 1 2) false))) +(instantiate B unary_bv_8_to_64) +(decl B (u8) u8) + +(rule first 1 (A x x) x) +(rule second 0 (A x _) 0) + +(rule third 1 (B x) x) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst.isle b/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst.isle new file mode 100644 index 00000000000000..7f9614708a03ce --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst.isle @@ -0,0 +1,21 @@ +(decl partial X (i64) i64) +(rule (X -1) -2) +(rule (X -2) -3) +(rule (X 0x7fff_ffff_ffff_ffff) -0x8000_0000_0000_0000) +(rule (X -16) 1) + +(decl partial Y (i128) i128) + +(rule (Y 0x1000_0000_0000_0000_1234_5678_9abc_def0) -1) +(rule (Y 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff) 3) + +(rule (Y -0x1000_0000_0000_0000_1234_5678_9abc_def0) 1) +(rule (Y -0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff) -3) + +;; Test some various syntaxes for numbers +(decl partial Z (i32) i32) +(rule (Z 0) 0x01) +(rule (Z 0x01) 0x0_2) +(rule (Z 0b10) 3) +(rule (Z 0b1_1) 0o4) +(rule (Z 0o7654321) 0b11_00_11_00) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst_main.rs new file mode 100644 index 00000000000000..d53edea438315d --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/run/iconst_main.rs @@ -0,0 +1,51 @@ +mod iconst; + +struct Context; +impl iconst::Context for Context {} + +fn main() { + let mut ctx = Context; + + assert_eq!(iconst::constructor_X(&mut ctx, -1), Some(-2)); + assert_eq!(iconst::constructor_X(&mut ctx, -2), Some(-3)); + assert_eq!( + iconst::constructor_X(&mut ctx, 0x7fff_ffff_ffff_ffff), + Some(0x8000_0000_0000_0000u64 as i64) + ); + assert_eq!( + iconst::constructor_X(&mut ctx, 0xffff_ffff_ffff_fff0_u64 as i64), + Some(1) + ); + + assert_eq!( + iconst::constructor_Y(&mut ctx, 0x1000_0000_0000_0000_1234_5678_9abc_def0), + Some(-1) + ); + assert_eq!( + iconst::constructor_Y( + &mut ctx, + 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffffu128 as i128 + ), + Some(3) + ); + assert_eq!( + iconst::constructor_Y(&mut ctx, -0x1000_0000_0000_0000_1234_5678_9abc_def0), + Some(1) + ); + assert_eq!( + iconst::constructor_Y( + &mut ctx, + -(0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffffu128 as i128) + ), + Some(-3) + ); + + assert_eq!(iconst::constructor_Z(&mut ctx, 0), Some(1)); + assert_eq!(iconst::constructor_Z(&mut ctx, 1), Some(2)); + assert_eq!(iconst::constructor_Z(&mut ctx, 2), Some(3)); + assert_eq!(iconst::constructor_Z(&mut ctx, 3), Some(4)); + assert_eq!( + iconst::constructor_Z(&mut ctx, 0o7654321), + Some(0b11_00_11_00) + ); +} diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing.isle b/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing.isle new file mode 100644 index 00000000000000..5db327b1410357 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing.isle @@ -0,0 +1,35 @@ +(decl foo (u64) u64) +(rule (foo x) x) + +;; Shadowing of a global name +(decl test1 (u64) u64) +(rule (test1 x) + (let ((foo u64 x)) + foo)) + +;; Shadowing of a parameter +(decl test2 (u64) u64) +(rule (test2 x) + (let ((x u64 x)) + x)) + +;; Shadowing of this binding's name +(decl test3 (u64) u64) +(rule (test3 x) + (let ((test3 u64 x)) + test3)) + +;; Shadowing another let-bound name +(decl test4 (u64) u64) +(rule (test4 x) + (let ((val u64 x) + (val u64 23)) + val)) + +;; Shadowing a global with a parameter name +(decl test5 (u64) u64) +(rule (test5 foo) foo) + +;; Using a previously shadowed global +(decl test6 (u64) u64) +(rule (test6 x) (foo x)) diff --git a/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing_main.rs b/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing_main.rs new file mode 100644 index 00000000000000..37ddb0bcc50b24 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/isle_examples/run/let_shadowing_main.rs @@ -0,0 +1,27 @@ +mod let_shadowing; + +struct Context; + +impl let_shadowing::Context for Context {} + +fn main() { + let mut ctx = Context; + + assert_eq!(20, let_shadowing::constructor_test1(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test1(&mut ctx, 97)); + + assert_eq!(20, let_shadowing::constructor_test2(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test2(&mut ctx, 97)); + + assert_eq!(20, let_shadowing::constructor_test3(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test3(&mut ctx, 97)); + + assert_eq!(23, let_shadowing::constructor_test4(&mut ctx, 20)); + assert_eq!(23, let_shadowing::constructor_test4(&mut ctx, 97)); + + assert_eq!(20, let_shadowing::constructor_test5(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test5(&mut ctx, 97)); + + assert_eq!(20, let_shadowing::constructor_test6(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test6(&mut ctx, 97)); +} diff --git a/deps/crates/vendor/cranelift-isle/src/ast.rs b/deps/crates/vendor/cranelift-isle/src/ast.rs new file mode 100644 index 00000000000000..50dd9afbd6bef7 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/ast.rs @@ -0,0 +1,618 @@ +//! Abstract syntax tree (AST) created from parsed ISLE. + +#![allow(missing_docs)] + +use crate::lexer::Pos; +use crate::log; + +/// One toplevel form in an ISLE file. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Def { + Pragma(Pragma), + Type(Type), + Rule(Rule), + Extractor(Extractor), + Decl(Decl), + Spec(Spec), + Model(Model), + Form(Form), + Instantiation(Instantiation), + Extern(Extern), + Converter(Converter), +} + +/// An identifier -- a variable, term symbol, or type. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Ident(pub String, pub Pos); + +/// Pragmas parsed with the `(pragma )` syntax. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Pragma { + // currently, no pragmas are defined, but the infrastructure is useful to keep around +} + +/// A declaration of a type. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Type { + pub name: Ident, + pub is_extern: bool, + pub is_nodebug: bool, + pub ty: TypeValue, + pub pos: Pos, +} + +/// The actual type-value: a primitive or an enum with variants. +/// +/// TODO: add structs as well? +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TypeValue { + Primitive(Ident, Pos), + Enum(Vec, Pos), +} + +/// One variant of an enum type. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Variant { + pub name: Ident, + pub fields: Vec, + pub pos: Pos, +} + +/// One field of an enum variant. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Field { + pub name: Ident, + pub ty: Ident, + pub pos: Pos, +} + +/// A declaration of a term with its argument and return types. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Decl { + pub term: Ident, + pub arg_tys: Vec, + pub ret_ty: Ident, + /// Whether this term's constructor is pure. + pub pure: bool, + /// Whether this term can exist with some multiplicity: an + /// extractor or a constructor that matches multiple times, or + /// produces multiple values. + pub multi: bool, + /// Whether this term's constructor can fail to match. + pub partial: bool, + pub pos: Pos, +} + +/// An expression used to specify term semantics, similar to SMT-LIB syntax. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpecExpr { + /// An operator that matches a constant integer value. + ConstInt { + val: i128, + pos: Pos, + }, + /// An operator that matches a constant bitvector value. + ConstBitVec { + val: i128, + width: i8, + pos: Pos, + }, + /// An operator that matches a constant boolean value. + ConstBool { + val: bool, + pos: Pos, + }, + /// The Unit constant value. + ConstUnit { + pos: Pos, + }, + // A variable + Var { + var: Ident, + pos: Pos, + }, + /// An application of a type variant or term. + Op { + op: SpecOp, + args: Vec, + pos: Pos, + }, + /// Pairs, currently used for switch statements. + Pair { + l: Box, + r: Box, + }, + /// Enums variant values (enums defined by model) + Enum { + name: Ident, + }, +} + +/// An operation used to specify term semantics, similar to SMT-LIB syntax. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpecOp { + // Boolean operations + Eq, + And, + Or, + Not, + Imp, + + // Integer comparisons + Lt, + Lte, + Gt, + Gte, + + // Bitwise bitvector operations (directly SMT-LIB) + BVNot, + BVAnd, + BVOr, + BVXor, + + // Bitvector arithmetic operations (directly SMT-LIB) + BVNeg, + BVAdd, + BVSub, + BVMul, + BVUdiv, + BVUrem, + BVSdiv, + BVSrem, + BVShl, + BVLshr, + BVAshr, + + // Bitvector comparison operations (directly SMT-LIB) + BVUle, + BVUlt, + BVUgt, + BVUge, + BVSlt, + BVSle, + BVSgt, + BVSge, + + // Bitvector overflow checks (SMT-LIB pending standardization) + BVSaddo, + + // Desugared bitvector arithmetic operations + Rotr, + Rotl, + Extract, + ZeroExt, + SignExt, + Concat, + + // Custom encodings + Subs, + Popcnt, + Clz, + Cls, + Rev, + + // Conversion operations + ConvTo, + Int2BV, + BV2Int, + WidthOf, + + // Control operations + If, + Switch, + + LoadEffect, + StoreEffect, +} + +/// A specification of the semantics of a term. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Spec { + /// The term name (must match a (decl ...)) + pub term: Ident, + /// Argument names + pub args: Vec, + /// Provide statements, which give the semantics of the produces value + pub provides: Vec, + /// Require statements, which express preconditions on the term + pub requires: Vec, +} + +/// A model of an SMT-LIB type. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ModelType { + /// SMT-LIB Int + Int, + /// SMT-LIB Bool + Bool, + /// SMT-LIB bitvector, but with a potentially-polymorphic width + BitVec(Option), + /// Unit (removed before conversion to SMT-LIB) + Unit, +} + +/// A construct's value in SMT-LIB +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ModelValue { + /// Correspond to ISLE types + TypeValue(ModelType), + /// Correspond to ISLE enums, identifier is the enum variant name + EnumValues(Vec<(Ident, SpecExpr)>), +} + +/// A model of a construct into SMT-LIB (currently, types or enums) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Model { + /// The name of the type or enum + pub name: Ident, + /// The value of the type or enum (potentially multiple values) + pub val: ModelValue, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Signature { + pub args: Vec, + pub ret: ModelType, + pub canonical: ModelType, + pub pos: Pos, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Form { + pub name: Ident, + pub signatures: Vec, + pub pos: Pos, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Instantiation { + pub term: Ident, + pub form: Option, + pub signatures: Vec, + pub pos: Pos, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Rule { + pub pattern: Pattern, + pub iflets: Vec, + pub expr: Expr, + pub pos: Pos, + pub prio: Option, + pub name: Option, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct IfLet { + pub pattern: Pattern, + pub expr: Expr, + pub pos: Pos, +} + +/// An extractor macro: (A x y) becomes (B x _ y ...). Expanded during +/// ast-to-sema pass. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Extractor { + pub term: Ident, + pub args: Vec, + pub template: Pattern, + pub pos: Pos, +} + +/// A pattern: the left-hand side of a rule. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Pattern { + /// A mention of a variable. + /// + /// Equivalent either to a binding (which can be emulated with + /// `BindPattern` with a `Pattern::Wildcard` subpattern), if this + /// is the first mention of the variable, in order to capture its + /// value; or else a match of the already-captured value. This + /// disambiguation happens when we lower `ast` nodes to `sema` + /// nodes as we resolve bound variable names. + Var { var: Ident, pos: Pos }, + /// An operator that binds a variable to a subterm and matches the + /// subpattern. + BindPattern { + var: Ident, + subpat: Box, + pos: Pos, + }, + /// An operator that matches a constant boolean value. + ConstBool { val: bool, pos: Pos }, + /// An operator that matches a constant integer value. + ConstInt { val: i128, pos: Pos }, + /// An operator that matches an external constant value. + ConstPrim { val: Ident, pos: Pos }, + /// An application of a type variant or term. + Term { + sym: Ident, + args: Vec, + pos: Pos, + }, + /// An operator that matches anything. + Wildcard { pos: Pos }, + /// N sub-patterns that must all match. + And { subpats: Vec, pos: Pos }, + /// Internal use only: macro argument in a template. + MacroArg { index: usize, pos: Pos }, +} + +impl Pattern { + pub fn root_term(&self) -> Option<&Ident> { + match self { + &Pattern::Term { ref sym, .. } => Some(sym), + _ => None, + } + } + + /// Call `f` for each of the terms in this pattern. + pub fn terms(&self, f: &mut dyn FnMut(Pos, &Ident)) { + match self { + Pattern::Term { sym, args, pos } => { + f(*pos, sym); + for arg in args { + arg.terms(f); + } + } + Pattern::And { subpats, .. } => { + for p in subpats { + p.terms(f); + } + } + Pattern::BindPattern { subpat, .. } => { + subpat.terms(f); + } + Pattern::Var { .. } + | Pattern::ConstBool { .. } + | Pattern::ConstInt { .. } + | Pattern::ConstPrim { .. } + | Pattern::Wildcard { .. } + | Pattern::MacroArg { .. } => {} + } + } + + pub fn make_macro_template(&self, macro_args: &[Ident]) -> Pattern { + log!("make_macro_template: {:?} with {:?}", self, macro_args); + match self { + &Pattern::BindPattern { + ref var, + ref subpat, + pos, + .. + } if matches!(&**subpat, &Pattern::Wildcard { .. }) => { + if let Some(i) = macro_args.iter().position(|arg| arg.0 == var.0) { + Pattern::MacroArg { index: i, pos } + } else { + self.clone() + } + } + &Pattern::BindPattern { + ref var, + ref subpat, + pos, + } => Pattern::BindPattern { + var: var.clone(), + subpat: Box::new(subpat.make_macro_template(macro_args)), + pos, + }, + &Pattern::Var { ref var, pos } => { + if let Some(i) = macro_args.iter().position(|arg| arg.0 == var.0) { + Pattern::MacroArg { index: i, pos } + } else { + self.clone() + } + } + &Pattern::And { ref subpats, pos } => { + let subpats = subpats + .iter() + .map(|subpat| subpat.make_macro_template(macro_args)) + .collect::>(); + Pattern::And { subpats, pos } + } + &Pattern::Term { + ref sym, + ref args, + pos, + } => { + let args = args + .iter() + .map(|arg| arg.make_macro_template(macro_args)) + .collect::>(); + Pattern::Term { + sym: sym.clone(), + args, + pos, + } + } + + &Pattern::Wildcard { .. } + | &Pattern::ConstBool { .. } + | &Pattern::ConstInt { .. } + | &Pattern::ConstPrim { .. } => self.clone(), + &Pattern::MacroArg { .. } => unreachable!(), + } + } + + pub fn subst_macro_args(&self, macro_args: &[Pattern]) -> Option { + log!("subst_macro_args: {:?} with {:?}", self, macro_args); + match self { + &Pattern::BindPattern { + ref var, + ref subpat, + pos, + } => Some(Pattern::BindPattern { + var: var.clone(), + subpat: Box::new(subpat.subst_macro_args(macro_args)?), + pos, + }), + &Pattern::And { ref subpats, pos } => { + let subpats = subpats + .iter() + .map(|subpat| subpat.subst_macro_args(macro_args)) + .collect::>>()?; + Some(Pattern::And { subpats, pos }) + } + &Pattern::Term { + ref sym, + ref args, + pos, + } => { + let args = args + .iter() + .map(|arg| arg.subst_macro_args(macro_args)) + .collect::>>()?; + Some(Pattern::Term { + sym: sym.clone(), + args, + pos, + }) + } + + &Pattern::Var { .. } + | &Pattern::Wildcard { .. } + | &Pattern::ConstBool { .. } + | &Pattern::ConstInt { .. } + | &Pattern::ConstPrim { .. } => Some(self.clone()), + &Pattern::MacroArg { index, .. } => macro_args.get(index).cloned(), + } + } + + pub fn pos(&self) -> Pos { + match self { + &Pattern::ConstBool { pos, .. } + | &Pattern::ConstInt { pos, .. } + | &Pattern::ConstPrim { pos, .. } + | &Pattern::And { pos, .. } + | &Pattern::Term { pos, .. } + | &Pattern::BindPattern { pos, .. } + | &Pattern::Var { pos, .. } + | &Pattern::Wildcard { pos, .. } + | &Pattern::MacroArg { pos, .. } => pos, + } + } +} + +/// An expression: the right-hand side of a rule. +/// +/// Note that this *almost* looks like a core Lisp or lambda calculus, +/// except that there is no abstraction (lambda). This first-order +/// limit is what makes it analyzable. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Expr { + /// A term: `(sym args...)`. + Term { + sym: Ident, + args: Vec, + pos: Pos, + }, + /// A variable use. + Var { name: Ident, pos: Pos }, + /// A constant boolean. + ConstBool { val: bool, pos: Pos }, + /// A constant integer. + ConstInt { val: i128, pos: Pos }, + /// A constant of some other primitive type. + ConstPrim { val: Ident, pos: Pos }, + /// The `(let ((var ty val)*) body)` form. + Let { + defs: Vec, + body: Box, + pos: Pos, + }, +} + +impl Expr { + pub fn pos(&self) -> Pos { + match self { + &Expr::Term { pos, .. } + | &Expr::Var { pos, .. } + | &Expr::ConstBool { pos, .. } + | &Expr::ConstInt { pos, .. } + | &Expr::ConstPrim { pos, .. } + | &Expr::Let { pos, .. } => pos, + } + } + + /// Call `f` for each of the terms in this expression. + pub fn terms(&self, f: &mut dyn FnMut(Pos, &Ident)) { + match self { + Expr::Term { sym, args, pos } => { + f(*pos, sym); + for arg in args { + arg.terms(f); + } + } + Expr::Let { defs, body, .. } => { + for def in defs { + def.val.terms(f); + } + body.terms(f); + } + Expr::Var { .. } + | Expr::ConstBool { .. } + | Expr::ConstInt { .. } + | Expr::ConstPrim { .. } => {} + } + } +} + +/// One variable locally bound in a `(let ...)` expression. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LetDef { + pub var: Ident, + pub ty: Ident, + pub val: Box, + pub pos: Pos, +} + +/// An external binding: an extractor or constructor function attached +/// to a term. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Extern { + /// An external extractor: `(extractor Term rustfunc)` form. + Extractor { + /// The term to which this external extractor is attached. + term: Ident, + /// The Rust function name. + func: Ident, + /// The position of this decl. + pos: Pos, + /// Infallibility: if an external extractor returns `(T1, T2, + /// ...)` rather than `Option<(T1, T2, ...)>`, and hence can + /// never fail, it is declared as such and allows for slightly + /// better code to be generated. + infallible: bool, + }, + /// An external constructor: `(constructor Term rustfunc)` form. + Constructor { + /// The term to which this external constructor is attached. + term: Ident, + /// The Rust function name. + func: Ident, + /// The position of this decl. + pos: Pos, + }, + /// An external constant: `(const $IDENT type)` form. + Const { name: Ident, ty: Ident, pos: Pos }, +} + +/// An implicit converter: the given term, which must have type +/// (inner_ty) -> outer_ty, is used either in extractor or constructor +/// position as appropriate when a type mismatch with the given pair +/// of types would otherwise occur. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Converter { + /// The term name. + pub term: Ident, + /// The "inner type": the type to convert *from*, on the + /// right-hand side, or *to*, on the left-hand side. Must match + /// the singular argument type of the term. + pub inner_ty: Ident, + /// The "outer type": the type to convert *to*, on the right-hand + /// side, or *from*, on the left-hand side. Must match the ret_ty + /// of the term. + pub outer_ty: Ident, + /// The position of this converter decl. + pub pos: Pos, +} diff --git a/deps/crates/vendor/cranelift-isle/src/codegen.rs b/deps/crates/vendor/cranelift-isle/src/codegen.rs new file mode 100644 index 00000000000000..769223d383685f --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/codegen.rs @@ -0,0 +1,927 @@ +//! Generate Rust code from a series of Sequences. + +use crate::files::Files; +use crate::sema::{ + BuiltinType, ExternalSig, ReturnKind, Term, TermEnv, TermId, Type, TypeEnv, TypeId, +}; +use crate::serialize::{Block, ControlFlow, EvalStep, MatchArm}; +use crate::stablemapset::StableSet; +use crate::trie_again::{Binding, BindingId, Constraint, RuleSet}; +use std::fmt::Write; +use std::slice::Iter; +use std::sync::Arc; + +/// Options for code generation. +#[derive(Clone, Debug, Default)] +pub struct CodegenOptions { + /// Do not include the `#![allow(...)]` pragmas in the generated + /// source. Useful if it must be include!()'d elsewhere. + pub exclude_global_allow_pragmas: bool, +} + +/// Emit Rust source code for the given type and term environments. +pub fn codegen( + files: Arc, + typeenv: &TypeEnv, + termenv: &TermEnv, + terms: &[(TermId, RuleSet)], + options: &CodegenOptions, +) -> String { + Codegen::compile(files, typeenv, termenv, terms).generate_rust(options) +} + +#[derive(Clone, Debug)] +struct Codegen<'a> { + files: Arc, + typeenv: &'a TypeEnv, + termenv: &'a TermEnv, + terms: &'a [(TermId, RuleSet)], +} + +enum Nested<'a> { + Cases(Iter<'a, EvalStep>), + Arms(BindingId, Iter<'a, MatchArm>), +} + +struct BodyContext<'a, W> { + out: &'a mut W, + ruleset: &'a RuleSet, + indent: String, + is_ref: StableSet, + is_bound: StableSet, +} + +impl<'a, W: Write> BodyContext<'a, W> { + fn new(out: &'a mut W, ruleset: &'a RuleSet) -> Self { + Self { + out, + ruleset, + indent: Default::default(), + is_ref: Default::default(), + is_bound: Default::default(), + } + } + + fn enter_scope(&mut self) -> StableSet { + let new = self.is_bound.clone(); + std::mem::replace(&mut self.is_bound, new) + } + + fn begin_block(&mut self) -> std::fmt::Result { + self.indent.push_str(" "); + writeln!(self.out, " {{") + } + + fn end_block(&mut self, last_line: &str, scope: StableSet) -> std::fmt::Result { + if !last_line.is_empty() { + writeln!(self.out, "{}{}", &self.indent, last_line)?; + } + self.is_bound = scope; + self.end_block_without_newline()?; + writeln!(self.out) + } + + fn end_block_without_newline(&mut self) -> std::fmt::Result { + self.indent.truncate(self.indent.len() - 4); + write!(self.out, "{}}}", &self.indent) + } + + fn set_ref(&mut self, binding: BindingId, is_ref: bool) { + if is_ref { + self.is_ref.insert(binding); + } else { + debug_assert!(!self.is_ref.contains(&binding)); + } + } +} + +impl<'a> Codegen<'a> { + fn compile( + files: Arc, + typeenv: &'a TypeEnv, + termenv: &'a TermEnv, + terms: &'a [(TermId, RuleSet)], + ) -> Codegen<'a> { + Codegen { + files, + typeenv, + termenv, + terms, + } + } + + fn generate_rust(&self, options: &CodegenOptions) -> String { + let mut code = String::new(); + + self.generate_header(&mut code, options); + self.generate_ctx_trait(&mut code); + self.generate_internal_types(&mut code); + self.generate_internal_term_constructors(&mut code).unwrap(); + + code + } + + fn generate_header(&self, code: &mut String, options: &CodegenOptions) { + writeln!(code, "// GENERATED BY ISLE. DO NOT EDIT!").unwrap(); + writeln!(code, "//").unwrap(); + writeln!( + code, + "// Generated automatically from the instruction-selection DSL code in:", + ) + .unwrap(); + for file in &self.files.file_names { + writeln!(code, "// - {file}").unwrap(); + } + + if !options.exclude_global_allow_pragmas { + writeln!( + code, + "\n#![allow(dead_code, unreachable_code, unreachable_patterns)]" + ) + .unwrap(); + writeln!( + code, + "#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]" + ) + .unwrap(); + writeln!( + code, + "#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]" + ) + .unwrap(); + } + + writeln!(code, "\nuse super::*; // Pulls in all external types.").unwrap(); + writeln!(code, "use std::marker::PhantomData;").unwrap(); + } + + fn generate_trait_sig(&self, code: &mut String, indent: &str, sig: &ExternalSig) { + let ret_tuple = format!( + "{open_paren}{rets}{close_paren}", + open_paren = if sig.ret_tys.len() != 1 { "(" } else { "" }, + rets = sig + .ret_tys + .iter() + .map(|&ty| self.type_name(ty, /* by_ref = */ false)) + .collect::>() + .join(", "), + close_paren = if sig.ret_tys.len() != 1 { ")" } else { "" }, + ); + + if sig.ret_kind == ReturnKind::Iterator { + writeln!( + code, + "{indent}type {name}_returns: Default + IntoContextIter;", + indent = indent, + name = sig.func_name, + output = ret_tuple, + ) + .unwrap(); + } + + let ret_ty = match sig.ret_kind { + ReturnKind::Plain => ret_tuple, + ReturnKind::Option => format!("Option<{ret_tuple}>"), + ReturnKind::Iterator => format!("()"), + }; + + writeln!( + code, + "{indent}fn {name}(&mut self, {params}) -> {ret_ty};", + indent = indent, + name = sig.func_name, + params = sig + .param_tys + .iter() + .enumerate() + .map(|(i, &ty)| format!("arg{}: {}", i, self.type_name(ty, /* by_ref = */ true))) + .chain(if sig.ret_kind == ReturnKind::Iterator { + Some(format!("returns: &mut Self::{}_returns", sig.func_name)) + } else { + None + }) + .collect::>() + .join(", "), + ret_ty = ret_ty, + ) + .unwrap(); + } + + fn generate_ctx_trait(&self, code: &mut String) { + writeln!(code).unwrap(); + writeln!( + code, + "/// Context during lowering: an implementation of this trait" + ) + .unwrap(); + writeln!( + code, + "/// must be provided with all external constructors and extractors." + ) + .unwrap(); + writeln!( + code, + "/// A mutable borrow is passed along through all lowering logic." + ) + .unwrap(); + writeln!(code, "pub trait Context {{").unwrap(); + for term in &self.termenv.terms { + if term.has_external_extractor() { + let ext_sig = term.extractor_sig(self.typeenv).unwrap(); + self.generate_trait_sig(code, " ", &ext_sig); + } + if term.has_external_constructor() { + let ext_sig = term.constructor_sig(self.typeenv).unwrap(); + self.generate_trait_sig(code, " ", &ext_sig); + } + } + writeln!(code, "}}").unwrap(); + writeln!( + code, + r#" +pub trait ContextIter {{ + type Context; + type Output; + fn next(&mut self, ctx: &mut Self::Context) -> Option; + fn size_hint(&self) -> (usize, Option) {{ (0, None) }} +}} + +pub trait IntoContextIter {{ + type Context; + type Output; + type IntoIter: ContextIter; + fn into_context_iter(self) -> Self::IntoIter; +}} + +pub trait Length {{ + fn len(&self) -> usize; +}} + +impl Length for std::vec::Vec {{ + fn len(&self) -> usize {{ + std::vec::Vec::len(self) + }} +}} + +pub struct ContextIterWrapper {{ + iter: I, + _ctx: std::marker::PhantomData, +}} +impl Default for ContextIterWrapper {{ + fn default() -> Self {{ + ContextIterWrapper {{ + iter: I::default(), + _ctx: std::marker::PhantomData + }} + }} +}} +impl std::ops::Deref for ContextIterWrapper {{ + type Target = I; + fn deref(&self) -> &I {{ + &self.iter + }} +}} +impl std::ops::DerefMut for ContextIterWrapper {{ + fn deref_mut(&mut self) -> &mut I {{ + &mut self.iter + }} +}} +impl From for ContextIterWrapper {{ + fn from(iter: I) -> Self {{ + Self {{ iter, _ctx: std::marker::PhantomData }} + }} +}} +impl ContextIter for ContextIterWrapper {{ + type Context = C; + type Output = I::Item; + fn next(&mut self, _ctx: &mut Self::Context) -> Option {{ + self.iter.next() + }} + fn size_hint(&self) -> (usize, Option) {{ + self.iter.size_hint() + }} +}} +impl IntoContextIter for ContextIterWrapper {{ + type Context = C; + type Output = I::Item; + type IntoIter = ContextIterWrapper; + fn into_context_iter(self) -> Self::IntoIter {{ + ContextIterWrapper {{ + iter: self.iter.into_iter(), + _ctx: std::marker::PhantomData + }} + }} +}} +impl, C> Extend for ContextIterWrapper {{ + fn extend>(&mut self, iter: I) {{ + self.iter.extend(iter); + }} +}} +impl Length for ContextIterWrapper {{ + fn len(&self) -> usize {{ + self.iter.len() + }} +}} + "#, + ) + .unwrap(); + } + + fn generate_internal_types(&self, code: &mut String) { + for ty in &self.typeenv.types { + match ty { + &Type::Enum { + name, + is_extern, + is_nodebug, + ref variants, + pos, + .. + } if !is_extern => { + let name = &self.typeenv.syms[name.index()]; + writeln!( + code, + "\n/// Internal type {}: defined at {}.", + name, + pos.pretty_print_line(&self.files) + ) + .unwrap(); + + // Generate the `derive`s. + let debug_derive = if is_nodebug { "" } else { ", Debug" }; + if variants.iter().all(|v| v.fields.is_empty()) { + writeln!(code, "#[derive(Copy, Clone, PartialEq, Eq{debug_derive})]") + .unwrap(); + } else { + writeln!(code, "#[derive(Clone{debug_derive})]").unwrap(); + } + + writeln!(code, "pub enum {name} {{").unwrap(); + for variant in variants { + let name = &self.typeenv.syms[variant.name.index()]; + if variant.fields.is_empty() { + writeln!(code, " {name},").unwrap(); + } else { + writeln!(code, " {name} {{").unwrap(); + for field in &variant.fields { + let name = &self.typeenv.syms[field.name.index()]; + let ty_name = + self.typeenv.types[field.ty.index()].name(self.typeenv); + writeln!(code, " {name}: {ty_name},").unwrap(); + } + writeln!(code, " }},").unwrap(); + } + } + writeln!(code, "}}").unwrap(); + } + _ => {} + } + } + } + + fn type_name(&self, typeid: TypeId, by_ref: bool) -> String { + match self.typeenv.types[typeid.index()] { + Type::Builtin(bt) => String::from(bt.name()), + Type::Primitive(_, sym, _) => self.typeenv.syms[sym.index()].clone(), + Type::Enum { name, .. } => { + let r = if by_ref { "&" } else { "" }; + format!("{}{}", r, self.typeenv.syms[name.index()]) + } + } + } + + fn generate_internal_term_constructors(&self, code: &mut String) -> std::fmt::Result { + for &(termid, ref ruleset) in self.terms.iter() { + let root = crate::serialize::serialize(ruleset); + let mut ctx = BodyContext::new(code, ruleset); + + let termdata = &self.termenv.terms[termid.index()]; + let term_name = &self.typeenv.syms[termdata.name.index()]; + writeln!(ctx.out)?; + writeln!( + ctx.out, + "{}// Generated as internal constructor for term {}.", + &ctx.indent, term_name, + )?; + + let sig = termdata.constructor_sig(self.typeenv).unwrap(); + writeln!( + ctx.out, + "{}pub fn {}(", + &ctx.indent, sig.func_name + )?; + + writeln!(ctx.out, "{} ctx: &mut C,", &ctx.indent)?; + for (i, &ty) in sig.param_tys.iter().enumerate() { + let (is_ref, ty) = self.ty(ty); + write!(ctx.out, "{} arg{}: ", &ctx.indent, i)?; + write!(ctx.out, "{}{}", if is_ref { "&" } else { "" }, ty)?; + if let Some(binding) = ctx.ruleset.find_binding(&Binding::Argument { + index: i.try_into().unwrap(), + }) { + ctx.set_ref(binding, is_ref); + } + writeln!(ctx.out, ",")?; + } + + let (_, ret) = self.ty(sig.ret_tys[0]); + + if let ReturnKind::Iterator = sig.ret_kind { + writeln!( + ctx.out, + "{} returns: &mut (impl Extend<{}> + Length),", + &ctx.indent, ret + )?; + } + + write!(ctx.out, "{}) -> ", &ctx.indent)?; + match sig.ret_kind { + ReturnKind::Iterator => write!(ctx.out, "()")?, + ReturnKind::Option => write!(ctx.out, "Option<{ret}>")?, + ReturnKind::Plain => write!(ctx.out, "{ret}")?, + }; + + let last_expr = if let Some(EvalStep { + check: ControlFlow::Return { .. }, + .. + }) = root.steps.last() + { + // If there's an outermost fallback, no need for another `return` statement. + String::new() + } else { + match sig.ret_kind { + ReturnKind::Iterator => String::new(), + ReturnKind::Option => "None".to_string(), + ReturnKind::Plain => format!( + "unreachable!(\"no rule matched for term {{}} at {{}}; should it be partial?\", {:?}, {:?})", + term_name, + termdata + .decl_pos + .pretty_print_line(&self.files) + ), + } + }; + + let scope = ctx.enter_scope(); + self.emit_block(&mut ctx, &root, sig.ret_kind, &last_expr, scope)?; + } + Ok(()) + } + + fn ty(&self, typeid: TypeId) -> (bool, String) { + let ty = &self.typeenv.types[typeid.index()]; + let name = ty.name(self.typeenv); + let is_ref = match ty { + Type::Builtin(_) | Type::Primitive(..) => false, + Type::Enum { .. } => true, + }; + (is_ref, String::from(name)) + } + + fn validate_block(ret_kind: ReturnKind, block: &Block) -> Nested { + if !matches!(ret_kind, ReturnKind::Iterator) { + // Loops are only allowed if we're returning an iterator. + assert!(!block + .steps + .iter() + .any(|c| matches!(c.check, ControlFlow::Loop { .. }))); + + // Unless we're returning an iterator, a case which returns a result must be the last + // case in a block. + if let Some(result_pos) = block + .steps + .iter() + .position(|c| matches!(c.check, ControlFlow::Return { .. })) + { + assert_eq!(block.steps.len() - 1, result_pos); + } + } + + Nested::Cases(block.steps.iter()) + } + + fn emit_block( + &self, + ctx: &mut BodyContext, + block: &Block, + ret_kind: ReturnKind, + last_expr: &str, + scope: StableSet, + ) -> std::fmt::Result { + let mut stack = Vec::new(); + ctx.begin_block()?; + stack.push((Self::validate_block(ret_kind, block), last_expr, scope)); + + while let Some((mut nested, last_line, scope)) = stack.pop() { + match &mut nested { + Nested::Cases(cases) => { + let Some(case) = cases.next() else { + ctx.end_block(last_line, scope)?; + continue; + }; + // Iterator isn't done, put it back on the stack. + stack.push((nested, last_line, scope)); + + for &expr in case.bind_order.iter() { + let iter_return = match &ctx.ruleset.bindings[expr.index()] { + Binding::Extractor { term, .. } => { + let termdata = &self.termenv.terms[term.index()]; + let sig = termdata.extractor_sig(self.typeenv).unwrap(); + if sig.ret_kind == ReturnKind::Iterator { + if termdata.has_external_extractor() { + Some(format!("C::{}_returns", sig.func_name)) + } else { + Some(format!("ContextIterWrapper::, _>")) + } + } else { + None + } + } + Binding::Constructor { term, .. } => { + let termdata = &self.termenv.terms[term.index()]; + let sig = termdata.constructor_sig(self.typeenv).unwrap(); + if sig.ret_kind == ReturnKind::Iterator { + if termdata.has_external_constructor() { + Some(format!("C::{}_returns", sig.func_name)) + } else { + Some(format!("ContextIterWrapper::, _>")) + } + } else { + None + } + } + _ => None, + }; + if let Some(ty) = iter_return { + writeln!( + ctx.out, + "{}let mut v{} = {}::default();", + &ctx.indent, + expr.index(), + ty + )?; + write!(ctx.out, "{}", &ctx.indent)?; + } else { + write!(ctx.out, "{}let v{} = ", &ctx.indent, expr.index())?; + } + self.emit_expr(ctx, expr)?; + writeln!(ctx.out, ";")?; + ctx.is_bound.insert(expr); + } + + match &case.check { + // Use a shorthand notation if there's only one match arm. + ControlFlow::Match { source, arms } if arms.len() == 1 => { + let arm = &arms[0]; + let scope = ctx.enter_scope(); + match arm.constraint { + Constraint::ConstBool { .. } + | Constraint::ConstInt { .. } + | Constraint::ConstPrim { .. } => { + write!(ctx.out, "{}if ", &ctx.indent)?; + self.emit_expr(ctx, *source)?; + write!(ctx.out, " == ")?; + self.emit_constraint(ctx, *source, arm)?; + } + Constraint::Variant { .. } | Constraint::Some => { + write!(ctx.out, "{}if let ", &ctx.indent)?; + self.emit_constraint(ctx, *source, arm)?; + write!(ctx.out, " = ")?; + self.emit_source(ctx, *source, arm.constraint)?; + } + } + ctx.begin_block()?; + stack.push((Self::validate_block(ret_kind, &arm.body), "", scope)); + } + + ControlFlow::Match { source, arms } => { + let scope = ctx.enter_scope(); + write!(ctx.out, "{}match ", &ctx.indent)?; + self.emit_source(ctx, *source, arms[0].constraint)?; + ctx.begin_block()?; + + // Always add a catchall arm, because we + // don't do exhaustiveness checking on the + // match arms. + stack.push((Nested::Arms(*source, arms.iter()), "_ => {}", scope)); + } + + ControlFlow::Equal { a, b, body } => { + let scope = ctx.enter_scope(); + write!(ctx.out, "{}if ", &ctx.indent)?; + self.emit_expr(ctx, *a)?; + write!(ctx.out, " == ")?; + self.emit_expr(ctx, *b)?; + ctx.begin_block()?; + stack.push((Self::validate_block(ret_kind, body), "", scope)); + } + + ControlFlow::Loop { result, body } => { + let source = match &ctx.ruleset.bindings[result.index()] { + Binding::Iterator { source } => source, + _ => unreachable!("Loop from a non-Iterator"), + }; + let scope = ctx.enter_scope(); + + writeln!( + ctx.out, + "{}let mut v{} = v{}.into_context_iter();", + &ctx.indent, + source.index(), + source.index(), + )?; + + write!( + ctx.out, + "{}while let Some(v{}) = v{}.next(ctx)", + &ctx.indent, + result.index(), + source.index() + )?; + ctx.is_bound.insert(*result); + ctx.begin_block()?; + stack.push((Self::validate_block(ret_kind, body), "", scope)); + } + + &ControlFlow::Return { pos, result } => { + writeln!( + ctx.out, + "{}// Rule at {}.", + &ctx.indent, + pos.pretty_print_line(&self.files) + )?; + write!(ctx.out, "{}", &ctx.indent)?; + match ret_kind { + ReturnKind::Plain | ReturnKind::Option => { + write!(ctx.out, "return ")? + } + ReturnKind::Iterator => write!(ctx.out, "returns.extend(Some(")?, + } + self.emit_expr(ctx, result)?; + if ctx.is_ref.contains(&result) { + write!(ctx.out, ".clone()")?; + } + match ret_kind { + ReturnKind::Plain | ReturnKind::Option => writeln!(ctx.out, ";")?, + ReturnKind::Iterator => { + writeln!(ctx.out, "));")?; + writeln!( + ctx.out, + "{}if returns.len() >= MAX_ISLE_RETURNS {{ return; }}", + ctx.indent + )?; + } + } + } + } + } + + Nested::Arms(source, arms) => { + let Some(arm) = arms.next() else { + ctx.end_block(last_line, scope)?; + continue; + }; + let source = *source; + // Iterator isn't done, put it back on the stack. + stack.push((nested, last_line, scope)); + + let scope = ctx.enter_scope(); + write!(ctx.out, "{}", &ctx.indent)?; + self.emit_constraint(ctx, source, arm)?; + write!(ctx.out, " =>")?; + ctx.begin_block()?; + stack.push((Self::validate_block(ret_kind, &arm.body), "", scope)); + } + } + } + + Ok(()) + } + + fn emit_expr(&self, ctx: &mut BodyContext, result: BindingId) -> std::fmt::Result { + if ctx.is_bound.contains(&result) { + return write!(ctx.out, "v{}", result.index()); + } + + let binding = &ctx.ruleset.bindings[result.index()]; + + let mut call = + |term: TermId, + parameters: &[BindingId], + + get_sig: fn(&Term, &TypeEnv) -> Option| { + let termdata = &self.termenv.terms[term.index()]; + let sig = get_sig(termdata, self.typeenv).unwrap(); + if let &[ret_ty] = &sig.ret_tys[..] { + let (is_ref, _) = self.ty(ret_ty); + if is_ref { + ctx.set_ref(result, true); + write!(ctx.out, "&")?; + } + } + write!(ctx.out, "{}(ctx", sig.full_name)?; + debug_assert_eq!(parameters.len(), sig.param_tys.len()); + for (¶meter, &arg_ty) in parameters.iter().zip(sig.param_tys.iter()) { + let (is_ref, _) = self.ty(arg_ty); + write!(ctx.out, ", ")?; + let (before, after) = match (is_ref, ctx.is_ref.contains(¶meter)) { + (false, true) => ("", ".clone()"), + (true, false) => ("&", ""), + _ => ("", ""), + }; + write!(ctx.out, "{before}")?; + self.emit_expr(ctx, parameter)?; + write!(ctx.out, "{after}")?; + } + if let ReturnKind::Iterator = sig.ret_kind { + write!(ctx.out, ", &mut v{}", result.index())?; + } + write!(ctx.out, ")") + }; + + match binding { + &Binding::ConstBool { val, .. } => self.emit_bool(ctx, val), + &Binding::ConstInt { val, ty } => self.emit_int(ctx, val, ty), + Binding::ConstPrim { val } => write!(ctx.out, "{}", &self.typeenv.syms[val.index()]), + Binding::Argument { index } => write!(ctx.out, "arg{}", index.index()), + Binding::Extractor { term, parameter } => { + call(*term, std::slice::from_ref(parameter), Term::extractor_sig) + } + Binding::Constructor { + term, parameters, .. + } => call(*term, ¶meters[..], Term::constructor_sig), + + Binding::MakeVariant { + ty, + variant, + fields, + } => { + let (name, variants) = match &self.typeenv.types[ty.index()] { + Type::Enum { name, variants, .. } => (name, variants), + _ => unreachable!("MakeVariant with primitive type"), + }; + let variant = &variants[variant.index()]; + write!( + ctx.out, + "{}::{}", + &self.typeenv.syms[name.index()], + &self.typeenv.syms[variant.name.index()] + )?; + if !fields.is_empty() { + ctx.begin_block()?; + for (field, value) in variant.fields.iter().zip(fields.iter()) { + write!( + ctx.out, + "{}{}: ", + &ctx.indent, + &self.typeenv.syms[field.name.index()], + )?; + self.emit_expr(ctx, *value)?; + if ctx.is_ref.contains(value) { + write!(ctx.out, ".clone()")?; + } + writeln!(ctx.out, ",")?; + } + ctx.end_block_without_newline()?; + } + Ok(()) + } + + &Binding::MakeSome { inner } => { + write!(ctx.out, "Some(")?; + self.emit_expr(ctx, inner)?; + write!(ctx.out, ")") + } + &Binding::MatchSome { source } => { + self.emit_expr(ctx, source)?; + write!(ctx.out, "?") + } + &Binding::MatchTuple { source, field } => { + self.emit_expr(ctx, source)?; + write!(ctx.out, ".{}", field.index()) + } + + // These are not supposed to happen. If they do, make the generated code fail to compile + // so this is easier to debug than if we panic during codegen. + &Binding::MatchVariant { source, field, .. } => { + self.emit_expr(ctx, source)?; + write!(ctx.out, ".{} /*FIXME*/", field.index()) + } + &Binding::Iterator { source } => { + self.emit_expr(ctx, source)?; + write!(ctx.out, ".next() /*FIXME*/") + } + } + } + + fn emit_source( + &self, + ctx: &mut BodyContext, + source: BindingId, + constraint: Constraint, + ) -> std::fmt::Result { + if let Constraint::Variant { .. } = constraint { + if !ctx.is_ref.contains(&source) { + write!(ctx.out, "&")?; + } + } + self.emit_expr(ctx, source) + } + + fn emit_constraint( + &self, + ctx: &mut BodyContext, + source: BindingId, + arm: &MatchArm, + ) -> std::fmt::Result { + let MatchArm { + constraint, + bindings, + .. + } = arm; + for binding in bindings.iter() { + if let &Some(binding) = binding { + ctx.is_bound.insert(binding); + } + } + match *constraint { + Constraint::ConstBool { val, .. } => self.emit_bool(ctx, val), + Constraint::ConstInt { val, ty } => self.emit_int(ctx, val, ty), + Constraint::ConstPrim { val } => { + write!(ctx.out, "{}", &self.typeenv.syms[val.index()]) + } + Constraint::Variant { ty, variant, .. } => { + let (name, variants) = match &self.typeenv.types[ty.index()] { + Type::Enum { name, variants, .. } => (name, variants), + _ => unreachable!("Variant constraint on primitive type"), + }; + let variant = &variants[variant.index()]; + write!( + ctx.out, + "&{}::{}", + &self.typeenv.syms[name.index()], + &self.typeenv.syms[variant.name.index()] + )?; + if !bindings.is_empty() { + ctx.begin_block()?; + let mut skipped_some = false; + for (&binding, field) in bindings.iter().zip(variant.fields.iter()) { + if let Some(binding) = binding { + write!( + ctx.out, + "{}{}: ", + &ctx.indent, + &self.typeenv.syms[field.name.index()] + )?; + let (is_ref, _) = self.ty(field.ty); + if is_ref { + ctx.set_ref(binding, true); + write!(ctx.out, "ref ")?; + } + writeln!(ctx.out, "v{},", binding.index())?; + } else { + skipped_some = true; + } + } + if skipped_some { + writeln!(ctx.out, "{}..", &ctx.indent)?; + } + ctx.end_block_without_newline()?; + } + Ok(()) + } + Constraint::Some => { + write!(ctx.out, "Some(")?; + if let Some(binding) = bindings[0] { + ctx.set_ref(binding, ctx.is_ref.contains(&source)); + write!(ctx.out, "v{}", binding.index())?; + } else { + write!(ctx.out, "_")?; + } + write!(ctx.out, ")") + } + } + } + + fn emit_bool( + &self, + ctx: &mut BodyContext, + val: bool, + ) -> Result<(), std::fmt::Error> { + write!(ctx.out, "{val}") + } + + fn emit_int( + &self, + ctx: &mut BodyContext, + val: i128, + ty: TypeId, + ) -> Result<(), std::fmt::Error> { + let ty_data = &self.typeenv.types[ty.index()]; + match ty_data { + Type::Builtin(BuiltinType::Int(ty)) if ty.is_signed() => write!(ctx.out, "{val}_{ty}"), + Type::Builtin(BuiltinType::Int(ty)) => write!(ctx.out, "{val:#x}_{ty}"), + _ => write!(ctx.out, "{val:#x}"), + } + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/compile.rs b/deps/crates/vendor/cranelift-isle/src/compile.rs new file mode 100644 index 00000000000000..db3497fa9424e2 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/compile.rs @@ -0,0 +1,106 @@ +//! Compilation process, from AST to Sema to Sequences of Insts. + +use std::path::Path; +use std::sync::Arc; + +use crate::ast::Def; +use crate::error::Errors; +use crate::files::Files; +use crate::{ast, codegen, overlap, sema}; + +/// Compile the given AST definitions into Rust source code. +pub fn compile( + files: Arc, + defs: &[ast::Def], + options: &codegen::CodegenOptions, +) -> Result { + let mut type_env = match sema::TypeEnv::from_ast(defs) { + Ok(type_env) => type_env, + Err(errs) => return Err(Errors::new(errs, files)), + }; + let term_env = match sema::TermEnv::from_ast(&mut type_env, defs, true) { + Ok(term_env) => term_env, + Err(errs) => return Err(Errors::new(errs, files)), + }; + let terms = match overlap::check(&term_env) { + Ok(terms) => terms, + Err(errs) => return Err(Errors::new(errs, files)), + }; + + Ok(codegen::codegen( + files, &type_env, &term_env, &terms, options, + )) +} + +/// Compile the given files into Rust source code. +pub fn from_files>( + inputs: impl IntoIterator, + options: &codegen::CodegenOptions, +) -> Result { + let files = match Files::from_paths(inputs) { + Ok(files) => files, + Err((path, err)) => { + return Err(Errors::from_io( + err, + format!("cannot read file {}", path.display()), + )) + } + }; + + let files = Arc::new(files); + + let mut defs = Vec::new(); + for (file, src) in files.file_texts.iter().enumerate() { + let lexer = match crate::lexer::Lexer::new(file, src) { + Ok(lexer) => lexer, + Err(err) => return Err(Errors::new(vec![err], files)), + }; + + match crate::parser::parse(lexer) { + Ok(mut ds) => defs.append(&mut ds), + Err(err) => return Err(Errors::new(vec![err], files)), + } + } + + compile(files, &defs, options) +} + +/// Construct the ISLE type and term environments for further analysis +/// (i.e., verification), without going all the way through codegen. +pub fn create_envs( + inputs: Vec, +) -> Result<(sema::TypeEnv, sema::TermEnv, Vec), Errors> { + let files = match Files::from_paths(inputs) { + Ok(files) => files, + Err((path, err)) => { + return Err(Errors::from_io( + err, + format!("cannot read file {}", path.display()), + )) + } + }; + let files = Arc::new(files); + let mut defs = Vec::new(); + for (file, src) in files.file_texts.iter().enumerate() { + let lexer = match crate::lexer::Lexer::new(file, src) { + Ok(lexer) => lexer, + Err(err) => return Err(Errors::new(vec![err], files)), + }; + + match crate::parser::parse(lexer) { + Ok(mut ds) => defs.append(&mut ds), + Err(err) => return Err(Errors::new(vec![err], files)), + } + } + let mut type_env = match sema::TypeEnv::from_ast(&defs) { + Ok(type_env) => type_env, + Err(errs) => return Err(Errors::new(errs, files)), + }; + // We want to allow annotations on terms with internal extractors, + // so we avoid expanding them within the sema rules. + let term_env = match sema::TermEnv::from_ast(&mut type_env, &defs, false) { + Ok(term_env) => term_env, + Err(errs) => return Err(Errors::new(errs, files)), + }; + Ok((type_env, term_env, defs)) +} diff --git a/deps/crates/vendor/cranelift-isle/src/disjointsets.rs b/deps/crates/vendor/cranelift-isle/src/disjointsets.rs new file mode 100644 index 00000000000000..f8064b86cae9f4 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/disjointsets.rs @@ -0,0 +1,169 @@ +//! Implementation of [`DisjointSets`], to store disjoint sets and provide efficient operations to +//! merge sets + +use std::collections::HashMap; +use std::hash::Hash; + +/// Stores disjoint sets and provides efficient operations to merge two sets, and to find a +/// representative member of a set given any member of that set. In this implementation, sets always +/// have at least two members, and can only be formed by the `merge` operation. +#[derive(Clone, Debug, Default)] +pub struct DisjointSets { + parent: HashMap, +} + +impl DisjointSets { + /// Find a representative member of the set containing `x`. If `x` has not been merged with any + /// other items using `merge`, returns `None`. This method updates the data structure to make + /// future queries faster, and takes amortized constant time. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// sets.merge(1, 2); + /// sets.merge(1, 3); + /// sets.merge(2, 4); + /// assert_eq!(sets.find_mut(3).unwrap(), sets.find_mut(4).unwrap()); + /// assert_eq!(sets.find_mut(10), None); + /// ``` + pub fn find_mut(&mut self, mut x: T) -> Option { + while let Some(node) = self.parent.get(&x) { + if node.0 == x { + return Some(x); + } + let grandparent = self.parent[&node.0].0; + // Re-do the lookup but take a mutable borrow this time + self.parent.get_mut(&x).unwrap().0 = grandparent; + x = grandparent; + } + None + } + + /// Find a representative member of the set containing `x`. If `x` has not been merged with any + /// other items using `merge`, returns `None`. This method does not update the data structure to + /// make future queries faster, so `find_mut` should be preferred. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// sets.merge(1, 2); + /// sets.merge(1, 3); + /// sets.merge(2, 4); + /// assert_eq!(sets.find(3).unwrap(), sets.find(4).unwrap()); + /// assert_eq!(sets.find(10), None); + /// ``` + pub fn find(&self, mut x: T) -> Option { + while let Some(node) = self.parent.get(&x) { + if node.0 == x { + return Some(x); + } + x = node.0; + } + None + } + + /// Merge the set containing `x` with the set containing `y`. This method takes amortized + /// constant time. + pub fn merge(&mut self, x: T, y: T) { + assert_ne!(x, y); + let mut x = if let Some(x) = self.find_mut(x) { + self.parent[&x] + } else { + self.parent.insert(x, (x, 0)); + (x, 0) + }; + let mut y = if let Some(y) = self.find_mut(y) { + self.parent[&y] + } else { + self.parent.insert(y, (y, 0)); + (y, 0) + }; + + if x == y { + return; + } + + if x.1 < y.1 { + std::mem::swap(&mut x, &mut y); + } + + self.parent.get_mut(&y.0).unwrap().0 = x.0; + if x.1 == y.1 { + let x_rank = &mut self.parent.get_mut(&x.0).unwrap().1; + *x_rank = x_rank.saturating_add(1); + } + } + + /// Returns whether the given items have both been merged into the same set. If either is not + /// part of any set, returns `false`. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// sets.merge(1, 2); + /// sets.merge(1, 3); + /// sets.merge(2, 4); + /// sets.merge(5, 6); + /// assert!(sets.in_same_set(2, 3)); + /// assert!(sets.in_same_set(1, 4)); + /// assert!(sets.in_same_set(3, 4)); + /// assert!(!sets.in_same_set(4, 5)); + /// ``` + pub fn in_same_set(&self, x: T, y: T) -> bool { + let x = self.find(x); + let y = self.find(y); + x.zip(y).filter(|(x, y)| x == y).is_some() + } + + /// Remove the set containing the given item, and return all members of that set. The set is + /// returned in sorted order. This method takes time linear in the total size of all sets. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// sets.merge(1, 2); + /// sets.merge(1, 3); + /// sets.merge(2, 4); + /// assert_eq!(sets.remove_set_of(4), &[1, 2, 3, 4]); + /// assert_eq!(sets.remove_set_of(1), &[]); + /// assert!(sets.is_empty()); + /// ``` + pub fn remove_set_of(&mut self, x: T) -> Vec + where + T: Ord, + { + let mut set = Vec::new(); + if let Some(x) = self.find_mut(x) { + set.extend(self.parent.keys().copied()); + // It's important to use `find_mut` here to avoid quadratic worst-case time. + set.retain(|&y| self.find_mut(y).unwrap() == x); + for y in set.iter() { + self.parent.remove(y); + } + set.sort_unstable(); + } + set + } + + /// Returns true if there are no sets. This method takes constant time. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// assert!(sets.is_empty()); + /// sets.merge(1, 2); + /// assert!(!sets.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.parent.is_empty() + } + + /// Returns the total number of elements in all sets. This method takes constant time. + /// + /// ``` + /// let mut sets = cranelift_isle::disjointsets::DisjointSets::default(); + /// sets.merge(1, 2); + /// assert_eq!(sets.len(), 2); + /// sets.merge(3, 4); + /// sets.merge(3, 5); + /// assert_eq!(sets.len(), 5); + /// ``` + pub fn len(&self) -> usize { + self.parent.len() + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/error.rs b/deps/crates/vendor/cranelift-isle/src/error.rs new file mode 100644 index 00000000000000..250a6db369feef --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/error.rs @@ -0,0 +1,318 @@ +//! Error types. + +use std::sync::Arc; + +use crate::{files::Files, lexer::Pos}; + +/// A collection of errors from attempting to compile some ISLE source files. +pub struct Errors { + /// The individual errors. + pub errors: Vec, + pub(crate) files: Arc, +} + +impl std::fmt::Debug for Errors { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.errors.is_empty() { + return Ok(()); + } + let diagnostics = Vec::from_iter(self.errors.iter().map(|e| { + let message = match e { + Error::IoError { context, .. } => context.clone(), + Error::ParseError { msg, .. } => format!("parse error: {msg}"), + Error::TypeError { msg, .. } => format!("type error: {msg}"), + Error::UnreachableError { msg, .. } => format!("unreachable rule: {msg}"), + Error::OverlapError { msg, .. } => format!("overlap error: {msg}"), + Error::ShadowedError { .. } => { + "more general higher-priority rule shadows other rules".to_string() + } + }; + + let labels = match e { + Error::IoError { .. } => vec![], + + Error::ParseError { span, .. } + | Error::TypeError { span, .. } + | Error::UnreachableError { span, .. } => { + vec![Label::primary(span.from.file, span)] + } + + Error::OverlapError { rules, .. } => { + let mut labels = vec![Label::primary(rules[0].from.file, &rules[0])]; + labels.extend( + rules[1..] + .iter() + .map(|span| Label::secondary(span.from.file, span)), + ); + labels + } + + Error::ShadowedError { shadowed, mask } => { + let mut labels = vec![Label::primary(mask.from.file, mask)]; + labels.extend( + shadowed + .iter() + .map(|span| Label::secondary(span.from.file, span)), + ); + labels + } + }; + + let mut sources = Vec::new(); + let mut source = e.source(); + while let Some(e) = source { + sources.push(format!("{e:?}")); + source = std::error::Error::source(e); + } + + Diagnostic::error() + .with_message(message) + .with_labels(labels) + .with_notes(sources) + })); + self.emit(f, diagnostics)?; + if self.errors.len() > 1 { + writeln!(f, "found {} errors", self.errors.len())?; + } + Ok(()) + } +} + +/// Errors produced by ISLE. +#[derive(Debug)] +pub enum Error { + /// An I/O error. + IoError { + /// The underlying I/O error. + error: std::io::Error, + /// The context explaining what caused the I/O error. + context: String, + }, + + /// The input ISLE source has a parse error. + ParseError { + /// The error message. + msg: String, + + /// The location of the parse error. + span: Span, + }, + + /// The input ISLE source has a type error. + TypeError { + /// The error message. + msg: String, + + /// The location of the type error. + span: Span, + }, + + /// The rule can never match any input. + UnreachableError { + /// The error message. + msg: String, + + /// The location of the unreachable rule. + span: Span, + }, + + /// The rules mentioned overlap in the input they accept. + OverlapError { + /// The error message. + msg: String, + + /// The locations of all the rules that overlap. When there are more than two rules + /// present, the first rule is the one with the most overlaps (likely a fall-through + /// wildcard case). + rules: Vec, + }, + + /// The rules can never match because another rule will always match first. + ShadowedError { + /// The locations of the unmatchable rules. + shadowed: Vec, + + /// The location of the rule that shadows them. + mask: Span, + }, +} + +impl Errors { + /// Create new Errors + pub fn new(errors: Vec, files: Arc) -> Self { + Self { errors, files } + } + + /// Create `isle::Errors` from the given I/O error and context. + pub fn from_io(error: std::io::Error, context: impl Into) -> Self { + Errors { + errors: vec![Error::IoError { + error, + context: context.into(), + }], + files: Arc::new(Files::default()), + } + } + + #[cfg(feature = "fancy-errors")] + fn emit( + &self, + f: &mut std::fmt::Formatter, + diagnostics: Vec>, + ) -> std::fmt::Result { + use codespan_reporting::term::termcolor; + let w = termcolor::BufferWriter::stderr(termcolor::ColorChoice::Auto); + let mut b = w.buffer(); + let mut files = codespan_reporting::files::SimpleFiles::new(); + for (name, source) in self + .files + .file_names + .iter() + .zip(self.files.file_texts.iter()) + { + files.add(name, source); + } + for diagnostic in diagnostics { + codespan_reporting::term::emit(&mut b, &Default::default(), &files, &diagnostic) + .map_err(|_| std::fmt::Error)?; + } + let b = b.into_inner(); + let b = std::str::from_utf8(&b).map_err(|_| std::fmt::Error)?; + f.write_str(b) + } + + #[cfg(not(feature = "fancy-errors"))] + fn emit( + &self, + f: &mut std::fmt::Formatter, + diagnostics: Vec>, + ) -> std::fmt::Result { + let pos = |file_id: usize, offset| { + let ends = self.files.file_line_map(file_id).unwrap(); + let line0 = ends.line(offset); + let text = &self.files.file_texts[file_id]; + let start = line0.checked_sub(1).map_or(0, |prev| ends[prev]); + let end = ends.get(line0).copied().unwrap_or(text.len()); + let col = offset - start + 1; + format!( + "{}:{}:{}: {}", + self.files.file_names[file_id], + line0 + 1, + col, + &text[start..end] + ) + }; + for diagnostic in diagnostics { + writeln!(f, "{}", diagnostic.message)?; + for label in diagnostic.labels { + f.write_str(&pos(label.file_id, label.range.start))?; + } + for note in diagnostic.notes { + writeln!(f, "{note}")?; + } + writeln!(f)?; + } + Ok(()) + } +} + +impl Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::IoError { error, .. } => Some(error), + _ => None, + } + } +} + +/// A span in a given source. +#[derive(Clone, Debug)] +pub struct Span { + /// The byte offset of the start of the span. + pub from: Pos, + /// The byte offset of the end of the span. + pub to: Pos, +} + +impl Span { + /// Create a new span that covers one character at the given offset. + pub fn new_single(pos: Pos) -> Span { + Span { + from: pos, + // This is a slight hack (we don't actually look at the + // file to find line/col of next char); but the `to` + // position only matters for pretty-printed errors and only + // the offset is used in that case. + to: Pos { + file: pos.file, + offset: pos.offset + 1, + }, + } + } +} + +impl From<&Span> for std::ops::Range { + fn from(span: &Span) -> Self { + span.from.offset..span.to.offset + } +} + +use diagnostic::{Diagnostic, Label}; + +#[cfg(feature = "fancy-errors")] +use codespan_reporting::diagnostic; + +#[cfg(not(feature = "fancy-errors"))] +/// Minimal versions of types from codespan-reporting. +mod diagnostic { + use std::ops::Range; + + pub struct Diagnostic { + pub message: String, + pub labels: Vec>, + pub notes: Vec, + } + + impl Diagnostic { + pub fn error() -> Self { + Self { + message: String::new(), + labels: Vec::new(), + notes: Vec::new(), + } + } + + pub fn with_message(mut self, message: impl Into) -> Self { + self.message = message.into(); + self + } + + pub fn with_labels(mut self, labels: Vec>) -> Self { + self.labels = labels; + self + } + + pub fn with_notes(mut self, notes: Vec) -> Self { + self.notes = notes; + self + } + } + + pub struct Label { + pub file_id: FileId, + pub range: Range, + } + + impl Label { + pub fn primary(file_id: FileId, range: impl Into>) -> Self { + Self { + file_id, + range: range.into(), + } + } + + pub fn secondary(file_id: FileId, range: impl Into>) -> Self { + Self::primary(file_id, range) + } + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/files.rs b/deps/crates/vendor/cranelift-isle/src/files.rs new file mode 100644 index 00000000000000..703e19f04c870a --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/files.rs @@ -0,0 +1,133 @@ +#![allow(missing_docs)] + +use std::ops::Index; +use std::path::{Path, PathBuf}; + +#[derive(Default, Clone, PartialEq, Eq, Debug)] +pub struct Files { + /// Arena of filenames from the input source. + /// + /// Indexed via `Pos::file`. + pub file_names: Vec, + + /// Arena of file source texts. + /// + /// Indexed via `Pos::file`. + pub file_texts: Vec, + + /// Arena of file line maps. + /// + /// Indexed via `Pos::file`. + pub file_line_maps: Vec, +} + +#[derive(Default, Clone, PartialEq, Eq, Debug)] +pub struct LineMap { + /// Mapping from line number to starting byte position. + line_ends: Vec, +} + +impl Index for LineMap { + type Output = usize; + + fn index(&self, index: usize) -> &Self::Output { + &self.line_ends[index] + } +} + +impl LineMap { + pub fn from_str(text: &str) -> Self { + let line_ends = text.match_indices('\n').map(|(i, _)| i + 1).collect(); + Self { line_ends } + } + + /// Get the line on which `pos` occurs + pub fn line(&self, pos: usize) -> usize { + self.line_ends.partition_point(|&end| end <= pos) + } + + /// Get the starting byte position of `line`. + pub fn get(&self, line: usize) -> Option<&usize> { + self.line_ends.get(line) + } +} + +impl Files { + pub fn from_paths>( + paths: impl IntoIterator, + ) -> Result { + let mut file_names = Vec::new(); + let mut file_texts = Vec::new(); + let mut file_line_maps = Vec::new(); + + for path in paths { + let path = path.as_ref(); + let contents = + std::fs::read_to_string(path).map_err(|err| (path.to_path_buf(), err))?; + let name = path.display().to_string(); + + file_line_maps.push(LineMap::from_str(&contents)); + file_names.push(name); + file_texts.push(contents); + } + + Ok(Self { + file_names, + file_texts, + file_line_maps, + }) + } + + pub fn from_names_and_contents(files: impl IntoIterator) -> Self { + let mut file_names = Vec::new(); + let mut file_texts = Vec::new(); + let mut file_line_maps = Vec::new(); + + for (name, contents) in files { + file_line_maps.push(LineMap::from_str(&contents)); + file_names.push(name); + file_texts.push(contents); + } + + Self { + file_names, + file_texts, + file_line_maps, + } + } + + pub fn file_name(&self, file: usize) -> Option<&str> { + self.file_names.get(file).map(|x| x.as_str()) + } + + pub fn file_text(&self, file: usize) -> Option<&str> { + self.file_texts.get(file).map(|x| x.as_str()) + } + + pub fn file_line_map(&self, file: usize) -> Option<&LineMap> { + self.file_line_maps.get(file) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn line_map() { + let line_map = LineMap::from_str(""); + assert_eq!(line_map.line_ends, &[]); + assert_eq!(line_map.line(0), 0); + assert_eq!(line_map.line(100), 0); + + let line_map = LineMap::from_str("line 0"); + assert_eq!(line_map.line_ends, &[]); + assert_eq!(line_map.line(0), 0); + assert_eq!(line_map.line(100), 0); + + let line_map = LineMap::from_str("line 0\nline 1"); + assert_eq!(line_map.line_ends, &[7]); + assert_eq!(line_map.line(0), 0); + assert_eq!(line_map.line(100), 1); + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/lexer.rs b/deps/crates/vendor/cranelift-isle/src/lexer.rs new file mode 100644 index 00000000000000..2b792ab962c8db --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/lexer.rs @@ -0,0 +1,370 @@ +//! Lexer for the ISLE language. + +use std::borrow::Cow; + +use crate::error::{Error, Span}; +use crate::files::Files; + +type Result = std::result::Result; + +/// The lexer. +/// +/// Breaks source text up into a sequence of tokens (with source positions). +#[derive(Clone, Debug)] +pub struct Lexer<'src> { + src: &'src str, + pos: Pos, + lookahead: Option<(Pos, Token)>, +} + +/// A source position. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash, PartialOrd, Ord)] +pub struct Pos { + /// This source position's file. + /// + /// Indexes into `Lexer::filenames` early in the compiler pipeline, and + /// later into `TypeEnv::filenames` once we get into semantic analysis. + pub file: usize, + /// This source position's byte offset in the file. + pub offset: usize, +} + +impl Pos { + /// Create a new `Pos`. + pub fn new(file: usize, offset: usize) -> Self { + Self { file, offset } + } + + /// Print this source position as `file.isle line 12`. + pub fn pretty_print_line(&self, files: &Files) -> String { + format!( + "{} line {}", + files.file_name(self.file).unwrap(), + files.file_line_map(self.file).unwrap().line(self.offset) + ) + } +} + +/// A token of ISLE source. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Token { + /// Left paren. + LParen, + /// Right paren. + RParen, + /// A symbol, e.g. `Foo`. + Symbol(String), + /// An integer. + Int(i128), + /// `@` + At, +} + +impl<'src> Lexer<'src> { + /// Create a new lexer for the given source contents + pub fn new(file: usize, src: &'src str) -> Result> { + let mut l = Lexer { + src, + pos: Pos::new(file, 0), + lookahead: None, + }; + l.reload()?; + Ok(l) + } + + /// Get the lexer's current source position. + pub fn pos(&self) -> Pos { + self.pos + } + + fn advance_pos(&mut self) { + self.advance_by(1) + } + + fn advance_by(&mut self, n: usize) { + self.pos.offset += n; + } + + fn error(&self, pos: Pos, msg: impl Into) -> Error { + Error::ParseError { + msg: msg.into(), + span: Span::new_single(pos), + } + } + + fn next_token(&mut self) -> Result> { + fn is_sym_first_char(c: u8) -> bool { + match c { + b'-' | b'0'..=b'9' | b'(' | b')' | b';' => false, + c if c.is_ascii_whitespace() => false, + _ => true, + } + } + fn is_sym_other_char(c: u8) -> bool { + match c { + b'(' | b')' | b';' | b'@' => false, + c if c.is_ascii_whitespace() => false, + _ => true, + } + } + + // Skip any whitespace and any comments. + while let Some(c) = self.peek_byte() { + match c { + b' ' | b'\t' | b'\n' | b'\r' => self.advance_pos(), + b';' => { + while let Some(c) = self.peek_byte() { + match c { + b'\n' | b'\r' => break, + _ => self.advance_pos(), + } + } + } + b'(' if self.lookahead_byte(1) == Some(b';') => { + let pos = self.pos(); + self.advance_by(2); + let mut depth = 1usize; + loop { + match self.peek_byte() { + None => return Err(self.error(pos, "unterminated block comment")), + Some(b'(') if self.lookahead_byte(1) == Some(b';') => { + self.advance_by(2); + depth += 1; + } + Some(b';') if self.lookahead_byte(1) == Some(b')') => { + self.advance_by(2); + depth -= 1; + if depth == 0 { + break; + } + } + Some(_) => self.advance_pos(), + } + } + } + _ => break, + } + } + + let Some(c) = self.peek_byte() else { + return Ok(None); + }; + let char_pos = self.pos(); + match c { + b'(' => { + self.advance_pos(); + Ok(Some((char_pos, Token::LParen))) + } + b')' => { + self.advance_pos(); + Ok(Some((char_pos, Token::RParen))) + } + b'@' => { + self.advance_pos(); + Ok(Some((char_pos, Token::At))) + } + c if is_sym_first_char(c) => { + let start = self.pos.offset; + let start_pos = self.pos(); + while let Some(c) = self.peek_byte() { + match c { + c if is_sym_other_char(c) => self.advance_pos(), + _ => break, + } + } + let end = self.pos.offset; + let s = &self.src[start..end]; + debug_assert!(!s.is_empty()); + Ok(Some((start_pos, Token::Symbol(s.to_string())))) + } + c @ (b'0'..=b'9' | b'-') => { + let start_pos = self.pos(); + let mut neg = false; + if c == b'-' { + self.advance_pos(); + neg = true; + } + + let mut radix = 10; + + // Check for prefixed literals. + match ( + self.src.as_bytes().get(self.pos.offset), + self.src.as_bytes().get(self.pos.offset + 1), + ) { + (Some(b'0'), Some(b'x' | b'X')) => { + self.advance_by(2); + radix = 16; + } + (Some(b'0'), Some(b'o' | b'O')) => { + self.advance_by(2); + radix = 8; + } + (Some(b'0'), Some(b'b' | b'B')) => { + self.advance_by(2); + radix = 2; + } + _ => {} + } + + // Find the range in the buffer for this integer literal. We'll + // pass this range to `i64::from_str_radix` to do the actual + // string-to-integer conversion. + let start = self.pos.offset; + while let Some(c) = self.peek_byte() { + match c { + b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F' | b'_' => self.advance_pos(), + _ => break, + } + } + let end = self.pos.offset; + let s = &self.src[start..end]; + let s = if s.contains('_') { + Cow::Owned(s.replace('_', "")) + } else { + Cow::Borrowed(s) + }; + + // Support either signed range (-2^127..2^127) or + // unsigned range (0..2^128). + let num = match u128::from_str_radix(&s, radix) { + Ok(num) => num, + Err(err) => return Err(self.error(start_pos, err.to_string())), + }; + + let num = match (neg, num) { + (true, 0x80000000000000000000000000000000) => { + return Err(self.error(start_pos, "integer literal cannot fit in i128")) + } + (true, _) => -(num as i128), + (false, _) => num as i128, + }; + let tok = Token::Int(num); + + Ok(Some((start_pos, tok))) + } + c => Err(self.error(self.pos, format!("Unexpected character '{c}'"))), + } + } + + /// Get the next token from this lexer's token stream, if any. + pub fn next(&mut self) -> Result> { + let tok = self.lookahead.take(); + self.reload()?; + Ok(tok) + } + + fn reload(&mut self) -> Result<()> { + if self.lookahead.is_none() && self.pos.offset < self.src.len() { + self.lookahead = self.next_token()?; + } + Ok(()) + } + + /// Peek ahead at the next token. + pub fn peek(&self) -> Option<&(Pos, Token)> { + self.lookahead.as_ref() + } + + /// Are we at the end of the source input? + pub fn eof(&self) -> bool { + self.lookahead.is_none() + } + + fn peek_byte(&self) -> Option { + self.lookahead_byte(0) + } + + fn lookahead_byte(&self, n: usize) -> Option { + self.src.as_bytes().get(self.pos.offset + n).copied() + } +} + +impl Token { + /// Is this an `Int` token? + pub fn is_int(&self) -> bool { + matches!(self, Token::Int(_)) + } + + /// Is this a `Sym` token? + pub fn is_sym(&self) -> bool { + matches!(self, Token::Symbol(_)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[track_caller] + fn lex(src: &str) -> Vec { + let mut toks = vec![]; + let mut lexer = Lexer::new(0, src).unwrap(); + while let Some((_, tok)) = lexer.next().unwrap() { + toks.push(tok); + } + toks + } + + #[test] + fn lexer_basic() { + assert_eq!( + lex(";; comment\n; another\r\n \t(one two three (; block comment ;) 23 (; nested (; block ;) comment ;) -568 )\n"), + [ + Token::LParen, + Token::Symbol("one".to_string()), + Token::Symbol("two".to_string()), + Token::Symbol("three".to_string()), + Token::Int(23), + Token::Int(-568), + Token::RParen + ] + ); + } + + #[test] + fn ends_with_sym() { + assert_eq!(lex("asdf"), [Token::Symbol("asdf".to_string())]); + } + + #[test] + fn ends_with_num() { + assert_eq!(lex("23"), [Token::Int(23)]); + } + + #[test] + fn weird_syms() { + assert_eq!( + lex("(+ [] => !! _test!;comment\n)"), + [ + Token::LParen, + Token::Symbol("+".to_string()), + Token::Symbol("[]".to_string()), + Token::Symbol("=>".to_string()), + Token::Symbol("!!".to_string()), + Token::Symbol("_test!".to_string()), + Token::RParen, + ] + ); + } + + #[test] + fn integers() { + assert_eq!( + lex("0 1 -1"), + [Token::Int(0), Token::Int(1), Token::Int(-1)] + ); + + assert_eq!( + lex("340_282_366_920_938_463_463_374_607_431_768_211_455"), + [Token::Int(-1)] + ); + + assert_eq!( + lex("170_141_183_460_469_231_731_687_303_715_884_105_727"), + [Token::Int(i128::MAX)] + ); + + assert!(Lexer::new(0, "-170_141_183_460_469_231_731_687_303_715_884_105_728").is_err()) + } +} diff --git a/deps/crates/vendor/cranelift-isle/src/lib.rs b/deps/crates/vendor/cranelift-isle/src/lib.rs new file mode 100644 index 00000000000000..8b7724d53ed1b7 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/lib.rs @@ -0,0 +1,35 @@ +#![doc = include_str!("../README.md")] +#![deny(missing_docs)] +#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] + +macro_rules! declare_id { + ( + $(#[$attr:meta])* + $name:ident + ) => { + $(#[$attr])* + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $name(pub usize); + impl $name { + /// Get the index of this id. + pub fn index(self) -> usize { + self.0 + } + } + }; +} + +pub mod ast; +pub mod codegen; +pub mod compile; +pub mod disjointsets; +pub mod error; +pub mod files; +pub mod lexer; +mod log; +pub mod overlap; +pub mod parser; +pub mod sema; +pub mod serialize; +pub mod stablemapset; +pub mod trie_again; diff --git a/deps/crates/vendor/cranelift-isle/src/log.rs b/deps/crates/vendor/cranelift-isle/src/log.rs new file mode 100644 index 00000000000000..9cf02ef8b55290 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/log.rs @@ -0,0 +1,17 @@ +//! Debug logging from the ISLE compiler itself. + +/// Log a compiler-internal message for debugging purposes. +#[cfg(feature = "logging")] +#[macro_export] +macro_rules! log { + ($($msg:tt)*) => { + ::log::trace!($($msg)*) + }; +} + +/// Log a compiler-internal message for debugging purposes. +#[cfg(not(feature = "logging"))] +#[macro_export] +macro_rules! log { + ($($msg:tt)*) => {}; +} diff --git a/deps/crates/vendor/cranelift-isle/src/overlap.rs b/deps/crates/vendor/cranelift-isle/src/overlap.rs new file mode 100644 index 00000000000000..3ce946a3021409 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/overlap.rs @@ -0,0 +1,130 @@ +//! Overlap detection for rules in ISLE. + +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; + +use crate::error::{Error, Span}; +use crate::lexer::Pos; +use crate::sema::{TermEnv, TermId, TermKind}; +use crate::trie_again; + +/// Check for overlap. +pub fn check(termenv: &TermEnv) -> Result, Vec> { + let (terms, mut errors) = trie_again::build(termenv); + errors.append(&mut check_overlaps(&terms, termenv).report()); + + if errors.is_empty() { + Ok(terms) + } else { + Err(errors) + } +} + +/// A graph of rules that overlap in the ISLE source. The edges are undirected. +#[derive(Default)] +struct Errors { + /// Edges between rules indicating overlap. + nodes: HashMap>, + /// For each (mask, shadowed) pair, every rule in `shadowed` is unmatchable because `mask` will + /// always match first. + shadowed: HashMap>, +} + +impl Errors { + /// Condense the overlap information down into individual errors. We iteratively remove the + /// nodes from the graph with the highest degree, reporting errors for them and their direct + /// connections. The goal with reporting errors this way is to prefer reporting rules that + /// overlap with many others first, and then report other more targeted overlaps later. + fn report(mut self) -> Vec { + let mut errors = Vec::new(); + + while let Some((&pos, _)) = self + .nodes + .iter() + .max_by_key(|(pos, edges)| (edges.len(), *pos)) + { + let node = self.nodes.remove(&pos).unwrap(); + for other in node.iter() { + if let Entry::Occupied(mut entry) = self.nodes.entry(*other) { + let back_edges = entry.get_mut(); + back_edges.remove(&pos); + if back_edges.is_empty() { + entry.remove(); + } + } + } + + // build the real error + let mut rules = vec![Span::new_single(pos)]; + + rules.extend(node.into_iter().map(Span::new_single)); + + errors.push(Error::OverlapError { + msg: String::from("rules are overlapping"), + rules, + }); + } + + errors.extend( + self.shadowed + .into_iter() + .map(|(mask, shadowed)| Error::ShadowedError { + shadowed: shadowed.into_iter().map(Span::new_single).collect(), + mask: Span::new_single(mask), + }), + ); + + errors.sort_by_key(|err| match err { + Error::ShadowedError { mask, .. } => mask.from, + Error::OverlapError { rules, .. } => rules[0].from, + _ => Pos::default(), + }); + errors + } + + fn check_pair(&mut self, a: &trie_again::Rule, b: &trie_again::Rule) { + if let trie_again::Overlap::Yes { subset } = a.may_overlap(b) { + if a.prio == b.prio { + // edges are undirected + self.nodes.entry(a.pos).or_default().insert(b.pos); + self.nodes.entry(b.pos).or_default().insert(a.pos); + } else if subset { + // One rule's constraints are a subset of the other's, or they're equal. + // This is fine as long as the higher-priority rule has more constraints. + let (lo, hi) = if a.prio < b.prio { (a, b) } else { (b, a) }; + if hi.total_constraints() <= lo.total_constraints() { + // Otherwise, the lower-priority rule can never match. + self.shadowed.entry(hi.pos).or_default().push(lo.pos); + } + } + } + } +} + +/// Determine if any rules overlap in the input that they accept. This checks every unique pair of +/// rules, as checking rules in aggregate tends to suffer from exponential explosion in the +/// presence of wildcard patterns. +fn check_overlaps(terms: &[(TermId, trie_again::RuleSet)], env: &TermEnv) -> Errors { + let mut errs = Errors::default(); + for (tid, ruleset) in terms { + let is_multi_ctor = match &env.terms[tid.index()].kind { + TermKind::Decl { flags, .. } => flags.multi, + _ => false, + }; + if is_multi_ctor { + // Rules for multi-constructors are not checked for + // overlap: the ctor returns *every* match, not just + // the first or highest-priority one, so overlap does + // not actually affect the results. + continue; + } + + let mut cursor = ruleset.rules.iter(); + while let Some(left) = cursor.next() { + for right in cursor.as_slice() { + errs.check_pair(left, right); + } + } + } + errs +} diff --git a/deps/crates/vendor/cranelift-isle/src/parser.rs b/deps/crates/vendor/cranelift-isle/src/parser.rs new file mode 100644 index 00000000000000..df1c70e0e2ced8 --- /dev/null +++ b/deps/crates/vendor/cranelift-isle/src/parser.rs @@ -0,0 +1,958 @@ +//! Parser for ISLE language. + +use crate::ast::*; +use crate::error::{Error, Span}; +use crate::lexer::{Lexer, Pos, Token}; + +type Result = std::result::Result; + +/// Parse the top-level ISLE definitions and return their AST. +pub fn parse(lexer: Lexer) -> Result> { + let parser = Parser::new(lexer); + parser.parse_defs() +} + +/// The ISLE parser. +/// +/// Takes in a lexer and creates an AST. +#[derive(Clone, Debug)] +struct Parser<'a> { + lexer: Lexer<'a>, +} + +/// Used during parsing a `(rule ...)` to encapsulate some form that +/// comes after the top-level pattern: an if-let clause, or the final +/// top-level expr. +enum IfLetOrExpr { + IfLet(IfLet), + Expr(Expr), +} + +impl<'a> Parser<'a> { + /// Construct a new parser from the given lexer. + pub fn new(lexer: Lexer<'a>) -> Parser<'a> { + Parser { lexer } + } + + fn error(&self, pos: Pos, msg: String) -> Error { + Error::ParseError { + msg, + span: Span::new_single(pos), + } + } + + fn expect bool>(&mut self, f: F) -> Result { + if let Some(&(pos, ref peek)) = self.lexer.peek() { + if !f(peek) { + return Err(self.error(pos, format!("Unexpected token {peek:?}"))); + } + Ok(self.lexer.next()?.unwrap().1) + } else { + Err(self.error(self.lexer.pos(), "Unexpected EOF".to_string())) + } + } + + fn eat bool>(&mut self, f: F) -> Result> { + if let Some(&(_pos, ref peek)) = self.lexer.peek() { + if !f(peek) { + return Ok(None); + } + Ok(Some(self.lexer.next()?.unwrap().1)) + } else { + Ok(None) // EOF + } + } + + fn is bool>(&self, f: F) -> bool { + if let Some((_, peek)) = self.lexer.peek() { + f(peek) + } else { + false + } + } + + fn pos(&self) -> Pos { + self.lexer + .peek() + .map_or_else(|| self.lexer.pos(), |(pos, _)| *pos) + } + + fn is_lparen(&self) -> bool { + self.is(|tok| *tok == Token::LParen) + } + fn is_rparen(&self) -> bool { + self.is(|tok| *tok == Token::RParen) + } + fn is_at(&self) -> bool { + self.is(|tok| *tok == Token::At) + } + fn is_sym(&self) -> bool { + self.is(Token::is_sym) + } + fn is_int(&self) -> bool { + self.is(Token::is_int) + } + + fn is_const(&self) -> bool { + self.is(|tok| match tok { + Token::Symbol(tok_s) if tok_s.starts_with('$') => true, + _ => false, + }) + } + + fn is_spec_bit_vector(&self) -> bool { + self.is(|tok| match tok { + Token::Symbol(tok_s) if tok_s.starts_with("#x") || tok_s.starts_with("#b") => true, + _ => false, + }) + } + + fn is_spec_bool(&self) -> bool { + self.is(|tok| match tok { + Token::Symbol(tok_s) if tok_s == "true" || tok_s == "false" => true, + _ => false, + }) + } + + fn expect_lparen(&mut self) -> Result<()> { + self.expect(|tok| *tok == Token::LParen).map(|_| ()) + } + fn expect_rparen(&mut self) -> Result<()> { + self.expect(|tok| *tok == Token::RParen).map(|_| ()) + } + fn expect_at(&mut self) -> Result<()> { + self.expect(|tok| *tok == Token::At).map(|_| ()) + } + + fn expect_symbol(&mut self) -> Result { + match self.expect(Token::is_sym)? { + Token::Symbol(s) => Ok(s), + _ => unreachable!(), + } + } + + fn eat_sym_str(&mut self, s: &str) -> Result { + self.eat(|tok| match tok { + Token::Symbol(ref tok_s) if tok_s == s => true, + _ => false, + }) + .map(|token| token.is_some()) + } + + fn expect_int(&mut self) -> Result { + match self.expect(Token::is_int)? { + Token::Int(i) => Ok(i), + _ => unreachable!(), + } + } + + fn parse_defs(mut self) -> Result> { + let mut defs = vec![]; + while !self.lexer.eof() { + defs.push(self.parse_def()?); + } + Ok(defs) + } + + fn parse_def(&mut self) -> Result { + self.expect_lparen()?; + let pos = self.pos(); + let def = match &self.expect_symbol()?[..] { + "pragma" => Def::Pragma(self.parse_pragma()?), + "type" => Def::Type(self.parse_type()?), + "decl" => Def::Decl(self.parse_decl()?), + "spec" => Def::Spec(self.parse_spec()?), + "model" => Def::Model(self.parse_model()?), + "form" => Def::Form(self.parse_form()?), + "instantiate" => Def::Instantiation(self.parse_instantiation()?), + "rule" => Def::Rule(self.parse_rule()?), + "extractor" => Def::Extractor(self.parse_etor()?), + "extern" => Def::Extern(self.parse_extern()?), + "convert" => Def::Converter(self.parse_converter()?), + s => { + return Err(self.error(pos, format!("Unexpected identifier: {s}"))); + } + }; + self.expect_rparen()?; + Ok(def) + } + + fn str_to_ident(&self, pos: Pos, s: &str) -> Result { + let first = s + .chars() + .next() + .ok_or_else(|| self.error(pos, "empty symbol".into()))?; + if !first.is_alphabetic() && first != '_' && first != '$' { + return Err(self.error( + pos, + format!("Identifier '{s}' does not start with letter or _ or $"), + )); + } + if s.chars() + .skip(1) + .any(|c| !c.is_alphanumeric() && c != '_' && c != '.' && c != '$') + { + return Err(self.error( + pos, + format!("Identifier '{s}' contains invalid character (not a-z, A-Z, 0-9, _, ., $)"), + )); + } + Ok(Ident(s.to_string(), pos)) + } + + fn parse_ident(&mut self) -> Result { + let pos = self.pos(); + let s = self.expect_symbol()?; + self.str_to_ident(pos, &s) + } + + fn parse_const(&mut self) -> Result { + let pos = self.pos(); + let ident = self.parse_ident()?; + if let Some(s) = ident.0.strip_prefix('$') { + Ok(Ident(s.to_string(), ident.1)) + } else { + Err(self.error( + pos, + "Not a constant identifier; must start with a '$'".to_string(), + )) + } + } + + fn parse_pragma(&mut self) -> Result { + let ident = self.parse_ident()?; + // currently, no pragmas are defined, but the infrastructure is useful to keep around + let pragma = ident.0.as_str(); + Err(self.error(ident.1, format!("Unknown pragma '{pragma}'"))) + } + + fn parse_type(&mut self) -> Result { + let pos = self.pos(); + let name = self.parse_ident()?; + + let mut is_extern = false; + let mut is_nodebug = false; + + while self.lexer.peek().map_or(false, |(_pos, tok)| tok.is_sym()) { + let sym = self.expect_symbol()?; + if sym == "extern" { + is_extern = true; + } else if sym == "nodebug" { + is_nodebug = true; + } else { + return Err(self.error( + self.pos(), + format!("unknown type declaration modifier: {sym}"), + )); + } + } + + let ty = self.parse_typevalue()?; + Ok(Type { + name, + is_extern, + is_nodebug, + ty, + pos, + }) + } + + fn parse_typevalue(&mut self) -> Result { + let pos = self.pos(); + self.expect_lparen()?; + if self.eat_sym_str("primitive")? { + let primitive_ident = self.parse_ident()?; + self.expect_rparen()?; + Ok(TypeValue::Primitive(primitive_ident, pos)) + } else if self.eat_sym_str("enum")? { + let mut variants = vec![]; + while !self.is_rparen() { + let variant = self.parse_type_variant()?; + variants.push(variant); + } + self.expect_rparen()?; + Ok(TypeValue::Enum(variants, pos)) + } else { + Err(self.error(pos, "Unknown type definition".to_string())) + } + } + + fn parse_type_variant(&mut self) -> Result { + if self.is_sym() { + let pos = self.pos(); + let name = self.parse_ident()?; + Ok(Variant { + name, + fields: vec![], + pos, + }) + } else { + let pos = self.pos(); + self.expect_lparen()?; + let name = self.parse_ident()?; + let mut fields = vec![]; + while !self.is_rparen() { + fields.push(self.parse_type_field()?); + } + self.expect_rparen()?; + Ok(Variant { name, fields, pos }) + } + } + + fn parse_type_field(&mut self) -> Result { + let pos = self.pos(); + self.expect_lparen()?; + let name = self.parse_ident()?; + let ty = self.parse_ident()?; + self.expect_rparen()?; + Ok(Field { name, ty, pos }) + } + + fn parse_decl(&mut self) -> Result { + let pos = self.pos(); + + let pure = self.eat_sym_str("pure")?; + let multi = self.eat_sym_str("multi")?; + let partial = self.eat_sym_str("partial")?; + + let term = self.parse_ident()?; + + self.expect_lparen()?; + let mut arg_tys = vec![]; + while !self.is_rparen() { + arg_tys.push(self.parse_ident()?); + } + self.expect_rparen()?; + + let ret_ty = self.parse_ident()?; + + Ok(Decl { + term, + arg_tys, + ret_ty, + pure, + multi, + partial, + pos, + }) + } + + fn parse_spec(&mut self) -> Result { + let pos = self.pos(); + self.expect_lparen()?; // term with args: (spec ( ) (provide ...) ...) + let term = self.parse_ident()?; + let mut args = vec![]; + while !self.is_rparen() { + args.push(self.parse_ident()?); + } + self.expect_rparen()?; // end term with args + + self.expect_lparen()?; // provide + if !self.eat_sym_str("provide")? { + return Err(self.error( + pos, + "Invalid spec: expected (spec ( ) (provide ...) ...)".to_string(), + )); + }; + let mut provides = vec![]; + while !self.is_rparen() { + provides.push(self.parse_spec_expr()?); + } + self.expect_rparen()?; // end provide + + let requires = if self.is_lparen() { + self.expect_lparen()?; + if !self.eat_sym_str("require")? { + return Err(self.error( + pos, + "Invalid spec: expected (spec ( ) (provide ...) (require ...))" + .to_string(), + )); + } + let mut require = vec![]; + while !self.is_rparen() { + require.push(self.parse_spec_expr()?); + } + self.expect_rparen()?; // end provide + require + } else { + vec![] + }; + + Ok(Spec { + term: term, + args, + provides, + requires, + }) + } + + fn parse_spec_expr(&mut self) -> Result { + let pos = self.pos(); + if self.is_spec_bit_vector() { + let (val, width) = self.parse_spec_bit_vector()?; + return Ok(SpecExpr::ConstBitVec { val, width, pos }); + } else if self.is_int() { + return Ok(SpecExpr::ConstInt { + val: self.expect_int()?, + pos, + }); + } else if self.is_spec_bool() { + let val = self.parse_spec_bool()?; + return Ok(SpecExpr::ConstBool { val, pos }); + } else if self.is_sym() { + let var = self.parse_ident()?; + return Ok(SpecExpr::Var { var, pos }); + } else if self.is_lparen() { + self.expect_lparen()?; + if self.eat_sym_str("switch")? { + let mut args = vec![]; + args.push(self.parse_spec_expr()?); + while !(self.is_rparen()) { + self.expect_lparen()?; + let l = Box::new(self.parse_spec_expr()?); + let r = Box::new(self.parse_spec_expr()?); + self.expect_rparen()?; + args.push(SpecExpr::Pair { l, r }); + } + self.expect_rparen()?; + return Ok(SpecExpr::Op { + op: SpecOp::Switch, + args, + pos, + }); + } + if self.is_sym() && !self.is_spec_bit_vector() { + let sym = self.expect_symbol()?; + if let Ok(op) = self.parse_spec_op(sym.as_str()) { + let mut args: Vec = vec![]; + while !self.is_rparen() { + args.push(self.parse_spec_expr()?); + } + self.expect_rparen()?; + return Ok(SpecExpr::Op { op, args, pos }); + }; + let ident = self.str_to_ident(pos, &sym)?; + if self.is_rparen() { + self.expect_rparen()?; + return Ok(SpecExpr::Enum { name: ident }); + }; + } + // Unit + if self.is_rparen() { + self.expect_rparen()?; + return Ok(SpecExpr::ConstUnit { pos }); + } + } + Err(self.error(pos, "Unexpected spec expression".into())) + } + + fn parse_spec_op(&mut self, s: &str) -> Result { + let pos = self.pos(); + match s { + "=" => Ok(SpecOp::Eq), + "and" => Ok(SpecOp::And), + "not" => Ok(SpecOp::Not), + "=>" => Ok(SpecOp::Imp), + "or" => Ok(SpecOp::Or), + "<=" => Ok(SpecOp::Lte), + "<" => Ok(SpecOp::Lt), + ">=" => Ok(SpecOp::Gte), + ">" => Ok(SpecOp::Gt), + "bvnot" => Ok(SpecOp::BVNot), + "bvand" => Ok(SpecOp::BVAnd), + "bvor" => Ok(SpecOp::BVOr), + "bvxor" => Ok(SpecOp::BVXor), + "bvneg" => Ok(SpecOp::BVNeg), + "bvadd" => Ok(SpecOp::BVAdd), + "bvsub" => Ok(SpecOp::BVSub), + "bvmul" => Ok(SpecOp::BVMul), + "bvudiv" => Ok(SpecOp::BVUdiv), + "bvurem" => Ok(SpecOp::BVUrem), + "bvsdiv" => Ok(SpecOp::BVSdiv), + "bvsrem" => Ok(SpecOp::BVSrem), + "bvshl" => Ok(SpecOp::BVShl), + "bvlshr" => Ok(SpecOp::BVLshr), + "bvashr" => Ok(SpecOp::BVAshr), + "bvsaddo" => Ok(SpecOp::BVSaddo), + "bvule" => Ok(SpecOp::BVUle), + "bvult" => Ok(SpecOp::BVUlt), + "bvugt" => Ok(SpecOp::BVUgt), + "bvuge" => Ok(SpecOp::BVUge), + "bvslt" => Ok(SpecOp::BVSlt), + "bvsle" => Ok(SpecOp::BVSle), + "bvsgt" => Ok(SpecOp::BVSgt), + "bvsge" => Ok(SpecOp::BVSge), + "rotr" => Ok(SpecOp::Rotr), + "rotl" => Ok(SpecOp::Rotl), + "extract" => Ok(SpecOp::Extract), + "zero_ext" => Ok(SpecOp::ZeroExt), + "sign_ext" => Ok(SpecOp::SignExt), + "concat" => Ok(SpecOp::Concat), + "conv_to" => Ok(SpecOp::ConvTo), + "int2bv" => Ok(SpecOp::Int2BV), + "bv2int" => Ok(SpecOp::BV2Int), + "widthof" => Ok(SpecOp::WidthOf), + "if" => Ok(SpecOp::If), + "switch" => Ok(SpecOp::Switch), + "subs" => Ok(SpecOp::Subs), + "popcnt" => Ok(SpecOp::Popcnt), + "rev" => Ok(SpecOp::Rev), + "cls" => Ok(SpecOp::Cls), + "clz" => Ok(SpecOp::Clz), + "load_effect" => Ok(SpecOp::LoadEffect), + "store_effect" => Ok(SpecOp::StoreEffect), + x => Err(self.error(pos, format!("Not a valid spec operator: {x}"))), + } + } + + fn parse_spec_bit_vector(&mut self) -> Result<(i128, i8)> { + let pos = self.pos(); + let s = self.expect_symbol()?; + if let Some(s) = s.strip_prefix("#b") { + match i128::from_str_radix(s, 2) { + Ok(i) => Ok((i, s.len() as i8)), + Err(_) => Err(self.error(pos, "Not a constant binary bit vector".to_string())), + } + } else if let Some(s) = s.strip_prefix("#x") { + match i128::from_str_radix(s, 16) { + Ok(i) => Ok((i, (s.len() as i8) * 4)), + Err(_) => Err(self.error(pos, "Not a constant hex bit vector".to_string())), + } + } else { + Err(self.error( + pos, + "Not a constant bit vector; must start with `#x` (hex) or `#b` (binary)" + .to_string(), + )) + } + } + + fn parse_spec_bool(&mut self) -> Result { + let pos = self.pos(); + let s = self.expect_symbol()?; + match s.as_str() { + "true" => Ok(true), + "false" => Ok(false), + x => Err(self.error(pos, format!("Not a valid spec boolean: {x}"))), + } + } + + fn parse_model(&mut self) -> Result { + let pos = self.pos(); + let name = self.parse_ident()?; + self.expect_lparen()?; // body + let val = if self.eat_sym_str("type")? { + let ty = self.parse_model_type(); + ModelValue::TypeValue(ty?) + } else if self.eat_sym_str("enum")? { + let mut variants = vec![]; + let mut has_explicit_value = false; + let mut implicit_idx = None; + + while !self.is_rparen() { + self.expect_lparen()?; // enum value + let name = self.parse_ident()?; + let val = if self.is_rparen() { + // has implicit enum value + if has_explicit_value { + return Err(self.error( + pos, + format!( + "Spec enum has unexpected implicit value after implicit value." + ), + )); + } + implicit_idx = Some(if let Some(idx) = implicit_idx { + idx + 1 + } else { + 0 + }); + SpecExpr::ConstInt { + val: implicit_idx.unwrap(), + pos, + } + } else { + if implicit_idx.is_some() { + return Err(self.error( + pos, + format!( + "Spec enum has unexpected explicit value after implicit value." + ), + )); + } + has_explicit_value = true; + self.parse_spec_expr()? + }; + self.expect_rparen()?; + variants.push((name, val)); + } + ModelValue::EnumValues(variants) + } else { + return Err(self.error(pos, "Model must be a type or enum".to_string())); + }; + + self.expect_rparen()?; // end body + Ok(Model { name, val }) + } + + fn parse_model_type(&mut self) -> Result { + let pos = self.pos(); + if self.eat_sym_str("Bool")? { + Ok(ModelType::Bool) + } else if self.eat_sym_str("Int")? { + Ok(ModelType::Int) + } else if self.eat_sym_str("Unit")? { + Ok(ModelType::Unit) + } else if self.is_lparen() { + self.expect_lparen()?; + let width = if self.eat_sym_str("bv")? { + if self.is_rparen() { + None + } else if self.is_int() { + Some(usize::try_from(self.expect_int()?).map_err(|err| { + self.error(pos, format!("Invalid BitVector width: {err}")) + })?) + } else { + return Err(self.error(pos, "Badly formed BitVector (bv ...)".to_string())); + } + } else { + return Err(self.error(pos, "Badly formed BitVector (bv ...)".to_string())); + }; + self.expect_rparen()?; + Ok(ModelType::BitVec(width)) + } else { + Err(self.error( + pos, + "Model type be a Bool, Int, or BitVector (bv ...)".to_string(), + )) + } + } + + fn parse_form(&mut self) -> Result